[Midnightbsd-cvs] src [10823] trunk/contrib/nvi: update nvi

laffer1 at midnightbsd.org laffer1 at midnightbsd.org
Sun Jun 10 16:23:49 EDT 2018


Revision: 10823
          http://svnweb.midnightbsd.org/src/?rev=10823
Author:   laffer1
Date:     2018-06-10 16:23:48 -0400 (Sun, 10 Jun 2018)
Log Message:
-----------
update nvi

Modified Paths:
--------------
    trunk/contrib/nvi/LICENSE
    trunk/contrib/nvi/README
    trunk/contrib/nvi/catalog/Makefile
    trunk/contrib/nvi/catalog/README
    trunk/contrib/nvi/catalog/dump.c
    trunk/contrib/nvi/catalog/dutch.base
    trunk/contrib/nvi/catalog/french.base
    trunk/contrib/nvi/catalog/german.base
    trunk/contrib/nvi/catalog/german.owner
    trunk/contrib/nvi/catalog/polish.base
    trunk/contrib/nvi/catalog/ru_RU.KOI8-R.base
    trunk/contrib/nvi/catalog/ru_RU.KOI8-R.owner
    trunk/contrib/nvi/catalog/spanish.base
    trunk/contrib/nvi/catalog/swedish.base
    trunk/contrib/nvi/catalog/uk_UA.KOI8-U.base
    trunk/contrib/nvi/cl/README.signal
    trunk/contrib/nvi/cl/cl.h
    trunk/contrib/nvi/cl/cl_funcs.c
    trunk/contrib/nvi/cl/cl_main.c
    trunk/contrib/nvi/cl/cl_read.c
    trunk/contrib/nvi/cl/cl_screen.c
    trunk/contrib/nvi/cl/cl_term.c
    trunk/contrib/nvi/common/args.h
    trunk/contrib/nvi/common/common.h
    trunk/contrib/nvi/common/cut.c
    trunk/contrib/nvi/common/cut.h
    trunk/contrib/nvi/common/delete.c
    trunk/contrib/nvi/common/exf.c
    trunk/contrib/nvi/common/exf.h
    trunk/contrib/nvi/common/gs.h
    trunk/contrib/nvi/common/key.c
    trunk/contrib/nvi/common/key.h
    trunk/contrib/nvi/common/line.c
    trunk/contrib/nvi/common/log.c
    trunk/contrib/nvi/common/main.c
    trunk/contrib/nvi/common/mark.c
    trunk/contrib/nvi/common/mark.h
    trunk/contrib/nvi/common/mem.h
    trunk/contrib/nvi/common/msg.c
    trunk/contrib/nvi/common/msg.h
    trunk/contrib/nvi/common/options.c
    trunk/contrib/nvi/common/options.h
    trunk/contrib/nvi/common/options_f.c
    trunk/contrib/nvi/common/put.c
    trunk/contrib/nvi/common/recover.c
    trunk/contrib/nvi/common/screen.c
    trunk/contrib/nvi/common/screen.h
    trunk/contrib/nvi/common/search.c
    trunk/contrib/nvi/common/seq.c
    trunk/contrib/nvi/common/seq.h
    trunk/contrib/nvi/common/util.c
    trunk/contrib/nvi/common/util.h
    trunk/contrib/nvi/docs/USD.doc/vi.man/vi.1
    trunk/contrib/nvi/docs/USD.doc/vi.ref/vi.ref
    trunk/contrib/nvi/ex/ex.c
    trunk/contrib/nvi/ex/ex.h
    trunk/contrib/nvi/ex/ex_abbrev.c
    trunk/contrib/nvi/ex/ex_append.c
    trunk/contrib/nvi/ex/ex_args.c
    trunk/contrib/nvi/ex/ex_argv.c
    trunk/contrib/nvi/ex/ex_at.c
    trunk/contrib/nvi/ex/ex_bang.c
    trunk/contrib/nvi/ex/ex_cd.c
    trunk/contrib/nvi/ex/ex_cmd.c
    trunk/contrib/nvi/ex/ex_cscope.c
    trunk/contrib/nvi/ex/ex_delete.c
    trunk/contrib/nvi/ex/ex_display.c
    trunk/contrib/nvi/ex/ex_edit.c
    trunk/contrib/nvi/ex/ex_equal.c
    trunk/contrib/nvi/ex/ex_file.c
    trunk/contrib/nvi/ex/ex_filter.c
    trunk/contrib/nvi/ex/ex_global.c
    trunk/contrib/nvi/ex/ex_init.c
    trunk/contrib/nvi/ex/ex_join.c
    trunk/contrib/nvi/ex/ex_map.c
    trunk/contrib/nvi/ex/ex_mark.c
    trunk/contrib/nvi/ex/ex_mkexrc.c
    trunk/contrib/nvi/ex/ex_move.c
    trunk/contrib/nvi/ex/ex_open.c
    trunk/contrib/nvi/ex/ex_preserve.c
    trunk/contrib/nvi/ex/ex_print.c
    trunk/contrib/nvi/ex/ex_put.c
    trunk/contrib/nvi/ex/ex_quit.c
    trunk/contrib/nvi/ex/ex_read.c
    trunk/contrib/nvi/ex/ex_screen.c
    trunk/contrib/nvi/ex/ex_script.c
    trunk/contrib/nvi/ex/ex_set.c
    trunk/contrib/nvi/ex/ex_shell.c
    trunk/contrib/nvi/ex/ex_shift.c
    trunk/contrib/nvi/ex/ex_source.c
    trunk/contrib/nvi/ex/ex_stop.c
    trunk/contrib/nvi/ex/ex_subst.c
    trunk/contrib/nvi/ex/ex_tag.c
    trunk/contrib/nvi/ex/ex_txt.c
    trunk/contrib/nvi/ex/ex_undo.c
    trunk/contrib/nvi/ex/ex_usage.c
    trunk/contrib/nvi/ex/ex_util.c
    trunk/contrib/nvi/ex/ex_version.c
    trunk/contrib/nvi/ex/ex_visual.c
    trunk/contrib/nvi/ex/ex_write.c
    trunk/contrib/nvi/ex/ex_yank.c
    trunk/contrib/nvi/ex/ex_z.c
    trunk/contrib/nvi/ex/script.h
    trunk/contrib/nvi/ex/tag.h
    trunk/contrib/nvi/ex/version.h
    trunk/contrib/nvi/vi/getc.c
    trunk/contrib/nvi/vi/v_at.c
    trunk/contrib/nvi/vi/v_ch.c
    trunk/contrib/nvi/vi/v_cmd.c
    trunk/contrib/nvi/vi/v_delete.c
    trunk/contrib/nvi/vi/v_ex.c
    trunk/contrib/nvi/vi/v_increment.c
    trunk/contrib/nvi/vi/v_init.c
    trunk/contrib/nvi/vi/v_itxt.c
    trunk/contrib/nvi/vi/v_left.c
    trunk/contrib/nvi/vi/v_mark.c
    trunk/contrib/nvi/vi/v_match.c
    trunk/contrib/nvi/vi/v_paragraph.c
    trunk/contrib/nvi/vi/v_put.c
    trunk/contrib/nvi/vi/v_redraw.c
    trunk/contrib/nvi/vi/v_replace.c
    trunk/contrib/nvi/vi/v_right.c
    trunk/contrib/nvi/vi/v_screen.c
    trunk/contrib/nvi/vi/v_scroll.c
    trunk/contrib/nvi/vi/v_search.c
    trunk/contrib/nvi/vi/v_section.c
    trunk/contrib/nvi/vi/v_sentence.c
    trunk/contrib/nvi/vi/v_status.c
    trunk/contrib/nvi/vi/v_txt.c
    trunk/contrib/nvi/vi/v_ulcase.c
    trunk/contrib/nvi/vi/v_undo.c
    trunk/contrib/nvi/vi/v_util.c
    trunk/contrib/nvi/vi/v_word.c
    trunk/contrib/nvi/vi/v_xchar.c
    trunk/contrib/nvi/vi/v_yank.c
    trunk/contrib/nvi/vi/v_z.c
    trunk/contrib/nvi/vi/v_zexit.c
    trunk/contrib/nvi/vi/vi.c
    trunk/contrib/nvi/vi/vi.h
    trunk/contrib/nvi/vi/vs_line.c
    trunk/contrib/nvi/vi/vs_msg.c
    trunk/contrib/nvi/vi/vs_refresh.c
    trunk/contrib/nvi/vi/vs_relative.c
    trunk/contrib/nvi/vi/vs_smap.c
    trunk/contrib/nvi/vi/vs_split.c

Added Paths:
-----------
    trunk/contrib/nvi/catalog/zh_CN.GB2312.base
    trunk/contrib/nvi/catalog/zh_CN.GB2312.owner
    trunk/contrib/nvi/cl/extern.h
    trunk/contrib/nvi/common/conv.c
    trunk/contrib/nvi/common/conv.h
    trunk/contrib/nvi/common/encoding.c
    trunk/contrib/nvi/common/extern.h
    trunk/contrib/nvi/common/multibyte.h
    trunk/contrib/nvi/common/options_def.h
    trunk/contrib/nvi/ex/ex_def.h
    trunk/contrib/nvi/ex/extern.h
    trunk/contrib/nvi/regex/
    trunk/contrib/nvi/regex/COPYRIGHT
    trunk/contrib/nvi/regex/WHATSNEW
    trunk/contrib/nvi/regex/cclass.h
    trunk/contrib/nvi/regex/cname.h
    trunk/contrib/nvi/regex/engine.c
    trunk/contrib/nvi/regex/re_format.7
    trunk/contrib/nvi/regex/regcomp.c
    trunk/contrib/nvi/regex/regerror.c
    trunk/contrib/nvi/regex/regex.3
    trunk/contrib/nvi/regex/regex.h
    trunk/contrib/nvi/regex/regex2.h
    trunk/contrib/nvi/regex/regexec.c
    trunk/contrib/nvi/regex/regfree.c
    trunk/contrib/nvi/regex/utils.h
    trunk/contrib/nvi/vi/extern.h

Property Changed:
----------------
    trunk/contrib/nvi/catalog/ru_RU.KOI8-R.base
    trunk/contrib/nvi/catalog/uk_UA.KOI8-U.base

Modified: trunk/contrib/nvi/LICENSE
===================================================================
--- trunk/contrib/nvi/LICENSE	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/LICENSE	2018-06-10 20:23:48 UTC (rev 10823)
@@ -1,14 +1,19 @@
-The vi program is freely redistributable.  You are welcome to copy, modify
-and share it with others under the conditions listed in this file.  If any
-company (not any individual!) finds vi sufficiently useful that you would
-have purchased it, or if any company wishes to redistribute it, contributions
-to the authors would be appreciated.
+/*-
+ * $Id: LICENSE,v 8.18 2011/07/10 11:58:35 zy Exp $
+ */
 
-/*-
+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
+ *  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.
+ *  Copyright (c) 2011
+ *	Zhihao Yuan.  All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -18,11 +23,7 @@
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *	This product includes software developed by the University of
- *	California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
+ * 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.
  *

Modified: trunk/contrib/nvi/README
===================================================================
--- trunk/contrib/nvi/README	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/README	2018-06-10 20:23:48 UTC (rev 10823)
@@ -1,32 +1,33 @@
-#	@(#)README	8.147 (Berkeley) 10/19/96
+#	$Id: README,v 9.1 2013/11/02 02:50:23 zy Exp $
 
-This is the README for nex/nvi, a freely redistributable implementation
-of the ex/vi text editors originally distributed as part of the Fourth
-Berkeley Software Distribution (4BSD), by the University of California,
-Berkeley.
+This is version 2.1.2 (2012-11-02) 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 source code for nex/nvi can be retrieved by using anonymous ftp to
-ftp.cs.berkeley.edu.  The file ucb/4bsd/nvi.tar.gz is the gzip'd archive,
-of version 1.71 of nex/nvi.  This version is believed to be stable and
-problem free.  The file ucb/4bsd/nvi-###.ALPHA.tar.gz is a gzip'd archive
-of the current alpha-test release of nex/nvi.  This version reflects the
-current development tree, and will be more likely to have problems.
+The directory layout is as follows:
 
-See the file:
-	build/README	for information on building nvi.
-	LAYOUT		for a description of where everything is.
-	LICENSE		for the copyright and redistribution terms.
+    LICENSE ....... Copyright, use and redistribution information.
+    README ........ This file.
+    build ......... Build directory.
+    catalog ....... Message catalogs; see catalog/README.
+    cl ............ Vi interface to the curses(3) library.
+    common ........ Code shared by ex and vi.
+    docs .......... Ex/vi documentation, both current and historic.
+    ex ............ Ex source code.
+    regex ......... Modified regex library with wide character support.
+    vi ............ Vi source code.
 
-If you have any questions about nex/nvi, problems with it, or concerns
-about the conditions for redistribution, please contact me:
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
 
-	Keith Bostic		+1-508-287-4781
-	394 E. Riding Dr.	bostic at bostic.com
-	Carlisle, MA 01741
-	USA
+o Nvi was written by Keith Bostic, and the last version is 1.79.  After that,
 
-Keith Bostic
+	Sven Verdoolaege added the iconv support and the DB3 locking.
 
+	Jun-ichiro itojun Hagino developed the file encoding detection
+	techniques in his nvi-m17n.
+
+The following acknowledgments were written by Keith Bostic:
+
 =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
 o This software is several years old and is the product of many folks' work.  
 
@@ -63,51 +64,3 @@
 o And...
 	The financial support of UUNET Communications Services is gratefully
 	acknowledged.
-
-=-=-=-=-=-=-=-=-=-=-=
-o Status:
-
-This software is in beta test, and it's pretty stable.  Almost all of the
-historic functionality in ex/vi is there, the only major missing pieces
-are open mode and the lisp edit option.
-
-Nvi is largely 8-bit clean.  This isn't difficult to fix, and was left in
-during initial development to keep things simple.  Wide character support
-will be integrated at the same time that it is made fully 8-bit clean.
-
-There aren't a lot of new features in nex/nvi, but there are a few things
-you might like.  The "Additional Features" section of the reference work
-(docs/USD.doc/vi.ref/vi.ref.txt, docs/USD.doc/vi.ref/vi.ref.ps) has more
-information.
-
-=-=-=-=-=-=-=-=-=-=-=
-o Debugging:
-
-Code fixes are greatly appreciated, of course, but if you can't provide
-them, please email me as much information as you can as to how I might
-reproduce the bug, and I'll try to fix it locally.  Stack traces of core
-dumps are only rarely helpful -- an example file with a set of keystrokes
-that causes the problem is almost invariably necessary.  I know it's
-annoying, but simply playing with the bug until you can reproduce it at
-will, with minimal keystrokes, is immensely helpful to me.
-
-Please include the following in the bug report;
-
-	o The version of nvi you're running (use :version to get it).
-	o The row/column dimensions of the screen (80 x 32).
-	o Unless you're confident that they're not part of the problem,
-	  your startup files (.exrc, .nexrc) and the environment variable
-	  (EXINIT, NEXINIT) values.  (Cutting and pasting the output
-	  of ":set all" is usually sufficient.)
-
-If you want to do your own debugging, recompile the program with DEBUG
-defined.  (Configuring with --enable-debug will do this for you.)  This
-turns on the additional command-line option -D, that takes either s or w
-as an argument.  The option -Ds causes nvi to ignore the EXINIT and
-.exrc files on startup, and -Dw causes nvi to print out the process id
-and wait for you to enter a <carriage-return> to continue.
-
-If you're running a memory checker (e.g. Purify) on nvi, you will first
-want to  recompile everything with "-DPURIFY" set in the CFLAGS.  This
-initializes allocated pages in the DB code, and free's allocated memory
-at the end of the nvi execution.

Modified: trunk/contrib/nvi/catalog/Makefile
===================================================================
--- trunk/contrib/nvi/catalog/Makefile	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/catalog/Makefile	2018-06-10 20:23:48 UTC (rev 10823)
@@ -1,7 +1,8 @@
-#	@(#)Makefile	8.29 (Berkeley) 10/19/96
+#	$Id: Makefile,v 9.0 2012/10/19 15:13:11 zy Exp $
 
-CAT=	dutch english french german polish ru_SU.KOI8-R spanish swedish
-FILES=	../cl/*.c ../common/*.c ../ex/*.c ../tk/*.c ../vi/*.c
+CAT=	dutch english french german polish ru_RU.KOI8-R spanish swedish \
+	uk_UA.KOI8-U zh_CN.GB2312
+FILES=	../cl/*.c ../common/*.c ../ex/*.c ../vi/*.c
 
 all: dump ${CAT}
 
@@ -18,13 +19,10 @@
 			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/' > $@;					\
+	sed -e '1s/^/$$set 1~$$quote "~/; 1y/~/\n/' |			\
+	gencat $@ /dev/stdin;						\
 	chmod 444 $@;							\
 	if grep DUPLICATE $@ > /dev/null; then				\
 		grep DUPLICATE $@;					\
@@ -34,7 +32,8 @@
 	fi
 
 CHK=	dutch.check english.check french.check german.check \
-	polish.check ru_SU.KOI8-R.check spanish.check swedish.check
+	polish.check ru_RU.KOI8-R.check spanish.check swedish.check \
+	uk_UA.KOI8-U.check zh_CN.GB2312.check
 check: ${CHK}
 ${CHK}: ${CAT}
 	@echo "... $@";							\
@@ -63,10 +62,6 @@
 	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
@@ -73,9 +68,8 @@
 	./dump ${FILES} |\
 	sed -e '/|/!d' \
 	    -e 's/|/ "/' \
-	    -e 's/^"//' \
-	    -e 's/\\"/"/g' |\
-	sort -n > $@
+	    -e 's/^"//' |\
+	sort -nu > $@
 
 dump: dump.c
 	${CC} -O -o dump dump.c

Modified: trunk/contrib/nvi/catalog/README
===================================================================
--- trunk/contrib/nvi/catalog/README	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/catalog/README	2018-06-10 20:23:48 UTC (rev 10823)
@@ -1,16 +1,10 @@
-#	@(#)README	8.4 (Berkeley) 11/22/94
+#	$Id: README,v 9.0 2012/10/19 17:06:15 zy Exp $
 
 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.
+Command strings, usage strings, system errors and other 'known text'
+are not.
 
-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:
@@ -33,20 +27,8 @@
 
 	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:
+is a format string that displays two arguments.
 
-	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:
@@ -54,14 +36,16 @@
 	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:
+msg_print() returns a printable version of a string; the third argument
+indicates whether the string needs to be freed.  For example:
 
 	char *p;
+	int nf;
 
-	p = msg_print(sp, file_name);
-	msgq(sp, M_ERR, M("003", "File: %s"), p);
-	FREE_SPACE(sp, p, 0);
+	p = msg_print(sp, file_name, &nf);
+	msgq(sp, M_ERR, "003|File: %s", p);
+	if (nf)
+		FREE_SPACE(sp, p, 0);
 
 makes sure that "file_name" is printable before calling the msgq
 routine.
@@ -71,64 +55,41 @@
 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
+"<language>.base", e.g. the English one is "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"
+	002 "Line length overflow"
+	003 "unable to delete line %lu"
+	004 "unable to append to line %lu"
+	005 "unable to insert at line %lu"
+	006 "unable to store line %lu"
+	007 "unable to get last line"
 
-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.
+are the first few lines of the current english.base file.
 
-The second file is the file used by nvi to access messages, and is a list
-of the messages, one per line:
+Before this file being converted to the second file, the POSIX formatted
+message catalog file, by gencat(1), two lines:
 
-	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
+	$set 1
+	$quote "
 
-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.
+will be inserted before the base text to setup the set_id and the quote
+character.  So the double-quote needs to be escaped by a backslash to be
+included in a message; same as the backslash itself.
 
-These files are named for their language, e.g. "vi_english".  The second
-files are automatically created from the first files.
+These files are named for their language, e.g. "english".  However, a
+locale(1) name is also recommended.
 
 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:
+Copy the file english.base to a file that you can modify , e.g.  "cp
+english.base german.base".  For each of the messages in the file,
+replace the message with the string that you want to use.  If you have
+doubts about the meaning of a message, just email me.
 
-	cd ..; egrep '123\|' */*.[chys]
+A latest english.base can be created from source by running the command
+"make english" in the catalog/ directory.
 
-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
@@ -156,11 +117,11 @@
 =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
 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.
+directory that contains a message catalog "$LC_MESSAGES", which is set
+through the LC_MESSAGES environment variable but returned by setlocale(3).
+Check the output of locale(1) to validate such a value.  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.

Modified: trunk/contrib/nvi/catalog/dump.c
===================================================================
--- trunk/contrib/nvi/catalog/dump.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/catalog/dump.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -105,10 +105,10 @@
 	for (; *argv != NULL; ++argv) {
 		if ((fp = fopen(*argv, "r")) == NULL) {
 			perror(*argv);
-			exit (1);
+			return (1);
 		}
 		parse(fp);
 		(void)fclose(fp);
 	}
-	exit (0);
+	return (0);
 }

Modified: trunk/contrib/nvi/catalog/dutch.base
===================================================================
--- trunk/contrib/nvi/catalog/dutch.base	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/catalog/dutch.base	2018-06-10 20:23:48 UTC (rev 10823)
@@ -43,8 +43,7 @@
 044 "De lisp optie is niet ondersteund"
 045 "messages niet uitgeschakeld: %s"
 046 "messages niet geactiveerd: %s"
-048 "De paragraph optie moet karakter paren bevatten"
-049 "De section optie moet karakter paren bevatten"
+047 "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"
@@ -97,16 +96,16 @@
 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"
+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"
+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"
+115 "Geen voorgaand commando om \"!\" te vervangen"
 116 "Geen bestandsnaam voor %%"
 117 "Geen bestandsnaam voor #"
 118 "Fout: execl: %s"
@@ -119,7 +118,7 @@
 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""
+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"
@@ -126,7 +125,7 @@
 132 "Geen input map entries"
 133 "Geen command map entries"
 134 "Het %s karakter kan niet ge-remapped worden"
-135 ""%s" is niet gemapped"
+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. "
@@ -296,7 +295,7 @@
 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"
+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"

Modified: trunk/contrib/nvi/catalog/french.base
===================================================================
--- trunk/contrib/nvi/catalog/french.base	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/catalog/french.base	2018-06-10 20:23:48 UTC (rev 10823)
@@ -43,8 +43,7 @@
 044 "L'option lisp n'est pas impl\xE9ment\xE9e"
 045 "Les messages ne sont pas d\xE9sactiv\xE9s : %s"
 046 "Les messages ne sont pas activ\xE9s : %s"
-048 "L'option de paragraphe doit \xEAtre en groupe de deux caract\xE8res"
-049 "L'option de section doit \xEAtre en groupe de deux caract\xE8res"
+047 "L'option de %s doit \xEAtre en groupe de deux caract\xE8res"
 053 "Le tampon par d\xE9faut est vide"
 054 "Le tampon %s est vide"
 055 "Les fichiers dont le nom contient des caract\xE8res de saut de ligne sont irr\xE9cup\xE9rables"
@@ -97,16 +96,16 @@
 103 "Adresse non valide : le fichier est vide"
 104 "La commande %s ne permet pas une adresse de 0"
 105 "Pas d'abr\xE9viations \xE0 afficher"
-106 "Les abr\xE9viations doivent finir par un caract\xE8re"mot"
+106 "Les abr\xE9viations doivent finir par un caract\xE8re \"mot\""
 107 "Les abr\xE9viations ne peuvent pas contenir de tabulations ni d'espaces"
 108 "Les abr\xE9viations ne peuvent pas contenir un m\xE9lange de caract\xE8res mot/non-mot, sauf \xE0 la fin"
-109 ""%s" n'est pas une abr\xE9viation"
+109 "\"%s\" n'est pas une abr\xE9viation"
 110 "La commande Vi a \xE9chou\xE9 : Les touches affect\xE9es ont \xE9t\xE9 abandonn\xE9es"
 111 "Plus de fichiers \xE0 \xE9diter"
 112 "Pas de fichiers pr\xE9c\xE9dents \xE0 \xE9diter"
 113 "Pas de fichiers pr\xE9c\xE9dents \xE0 rembobiner"
 114 "Pas de liste de fichiers \xE0 afficher"
-115 "Pas de commande pr\xE9c\xE9dente \xE0 remplacer"!""
+115 "Pas de commande pr\xE9c\xE9dente \xE0 remplacer \"!\""
 116 "Pas de nom de fichier \xE0 substituer \xE0 %%"
 117 "Pas de nom de fichier \xE0 substituer \xE0 #"
 118 "Erreur : execl : %s"
@@ -126,7 +125,7 @@
 132 "Pas d'entr\xE9es de mappage d'entr\xE9e"
 133 "Pas d'entr\xE9es de mappage de commandes"
 134 "Le caract\xE8re %s ne peut pas \xEAtre remapp\xE9"
-135 ""%s" n'est pas actuellement mapp\xE9"
+135 "\"%s\" n'est pas actuellement mapp\xE9"
 136 "Les noms de marque ne doivent avoir qu'un caract\xE8re"
 137 "%s existe, non enregistr\xE9; utiliser ! pour outrepasser"
 138 "Nouveau fichier exrc : %s"
@@ -200,7 +199,6 @@
 207 "La commande Q n\xE9cessite une interface terminal ex"
 208 "Pas de commande \xE0 r\xE9p\xE9ter"
 209 "Le fichier est vide"
-209 "Le fichier est vide"
 210 "Vous ne pouvez pas utiliser %s comme commande de d\xE9placement"
 211 "D\xE9j\xE0 en mode commande"
 212 "Le curseur n'est pas dans un mot"
@@ -293,12 +291,11 @@
 302 "Vi n'a pas \xE9t\xE9 charg\xE9 avec un interpr\xE9tateur Tcl"
 303 "Ficher modifi\xE9 depuis le dernier enregistrement."
 304 "L'expansion du shell a \xE9chou\xE9"
-304 "L'expansion du shell a \xE9chou\xE9"
 305 "Pas d'option d'\xE9dition %s sp\xE9cifi\xE9e"
 306 "Vi n'a pas \xE9t\xE9 charg\xE9 avec un interpr\xE9tateur Perl"
 307 "Pas de commande ex \xE0 ex\xE9cuter"
 308 "Entrez <CR> pour ex\xE9cuter une commande, :q pour quitter"
-309 "Utiliser "cscope help" pour obtenir de l'aide"
+309 "Utiliser \"cscope help\" pour obtenir de l'aide"
 310 "Aucune connexion cscope n'est lanc\xE9e"
 311 "%s : type de recherche inconnu : utiliser un des %s"
 312 "%d : Il n'existe pas de telle session cscope"

Modified: trunk/contrib/nvi/catalog/german.base
===================================================================
--- trunk/contrib/nvi/catalog/german.base	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/catalog/german.base	2018-06-10 20:23:48 UTC (rev 10823)
@@ -1,67 +1,66 @@
-002 "Zeilenlaengen Ueberlauf"
-003 "kann Zeile %lu nicht loeschen"
-004 "kann an Zeile %lu nicht anfuegen"
-005 "kann in Zeile %lu nicht einfuegen"
+002 "Zeilenl\xE4ngen-\xDCberlauf"
+003 "kann Zeile %lu nicht l\xF6schen"
+004 "kann an Zeile %lu nicht anf\xFCgen"
+005 "kann in Zeile %lu nicht einf\xFCgen"
 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, rueckgaengig machen nicht moeglich"
-011 "Keine Aenderungen rueckgaengig zu machen"
-012 "Keine Protokollierung aktiv, rueckgaengig machen nicht moeglich"
-013 "Keine Protokollierung aktiv, Wiederholung von Aenderungen nicht moeglich"
-014 "Keine Aenderungen zu wiederholen"
+010 "Keine Protokollierung aktiv, R\xFCckg\xE4ngigmachen nicht m\xF6glich"
+011 "Keine \xC4nderungen r\xFCckg\xE4ngig zu machen"
+012 "Keine Protokollierung aktiv, R\xFCckg\xE4ngigmachen nicht m\xF6glich"
+013 "Keine Protokollierung aktiv, Wiederholung von \xC4nderungen nicht m\xF6glich"
+014 "Keine \xC4nderungen zu wiederholen"
 015 "%s/%d: Protokollschreibfehler"
-016 "Vi's Standardein- und ausgabe muss ein Terminal sein"
+016 "Vi's Standardein- und -ausgabe mu\xDF ein Terminal sein"
 017 "Marke %s: nicht gesetzt"
-018 "Marke %s: die Zeile wurde geloescht"
+018 "Marke %s: die Zeile wurde gel\xF6scht"
 019 "Marke %s: Cursorposition existiert nicht mehr"
 020 "Fehler: "
 021 "neue Datei"
-022 "Name geaendert"
-023 "geaendert"
-024 "nicht geaendert"
-025 "NICHT GELOCKED"
+022 "Name ge\xE4ndert"
+023 "ge\xE4ndert"
+024 "nicht ge\xE4ndert"
+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 fuer %s Option nicht moeglich"
+031 "Setzen der Voreinstellung f\xFCr %s Option nicht m\xF6glich"
 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"
+035 "set: %s ist keine Boolsche Option"
 036 "set: %s Option: %s"
-037 "set: %s Option: %s: Wert Ueberlauf"
-038 "set: %s Option: %s ist eine ungueltige Zahl"
-039 "set: %s ist keine boolsche Option"
-040 "Anzeige hat zu wenig Spalten, weniger als %d"
-041 "Anzeige hat zu viele Spalten, mehr als %d"
-042 "Anzeige hat zu wenig Zeilen, weniger als %d"
-043 "Anzeige hat zu viele Zeilen, mehr als %d"
-044 "Die lisp Option ist nicht implementiert"
-045 "Messages nicht abgeschalten: %s"
-046 "Messages nicht eingeschalten: %s"
-048 "Die paragraph Option muss Gruppen zu zwei Zeichen enthalten"
-049 "Die section Option muss Gruppen zu zwei Zeichen enthalten"
+037 "set: %s Option: %s: Werte-\xDCberlauf"
+038 "set: %s Option: %s ist eine ung\xFCltige 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 "Die %s-Option mu\xDF 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 "Aenderungen nicht wiederherstellbar falls die Editorsitzung schief geht"
-057 "kopiere Datei fuer Wiederherstellung ..."
+056 "\xC4nderungen nicht wiederherstellbar, falls die Editorsitzung schiefgeht"
+057 "kopiere Datei f\xFCr Wiederherstellung ..."
 058 "Rettungsmechanismus funktioniert nicht: %s"
-059 "Aenderungen nicht wiederherstellbar falls die Editorsitzung schief geht"
+059 "\xC4nderungen nicht wiederherstellbar, falls die Editorsitzung schiefgeht"
 060 "Sicherung der Datei gescheitert: %s"
-061 "kopiere Datei fuer Wiederherstellung ..."
-062 "Informationen ueber den Benutzer mit id %u nicht gefunden"
-063 "Wiederherstellungsdatei kann nicht gesperrt werden"
-064 "Puffer der Wiederherstellungsdatei uebergelaufen"
+061 "kopiere Datei f\xFCr Wiederherstellung ..."
+062 "Informationen \xFCber den Benutzer mit id %u nicht gefunden"
+063 "Wiederherstellungsdatei kann nicht gelockt werden"
+064 "Puffer der Wiederherstellungsdatei \xFCbergelaufen"
 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 aeltere Versionen dieser Datei von Ihnen zum Wiederherstellen"
+069 "Es gibt \xE4ltere 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"
@@ -69,110 +68,110 @@
 074 "Kein altes Suchmuster"
 075 "Suchmuster nicht gefunden"
 076 "Dateianfang erreicht, ohne das Suchmuster zu finden"
-077 "Suche umgeschlagen"
+077 "Suche beginnt von vorn"
 078 "suche ..."
 079 "Keine nichtdruckbaren Zeichen gefunden"
 080 "Unbekannter Kommandoname"
-082 "%s: Kommando im ex Modus nicht verfuegbar"
-083 "Count darf nicht Null sein"
+082 "%s: Kommando im ex-Modus nicht verf\xFCgbar"
+083 "Anzahl darf nicht Null sein"
 084 "%s: falsche Zeilenangabe"
 085 "Interner Syntaxtabellenfehler (%s: %s)"
 086 "Benutzung: %s"
-087 "%s: temporaerer Puffer nicht freigegeben"
+087 "%s: tempor\xE4rer Puffer nicht freigegeben"
 088 "Flagoffset vor Zeile 1"
 089 "Flagoffset hinter dem Dateiende"
-090 "@ mit Bereich lief als Datei/Anzeige geaendert wurde"
-091 "globales oder v-Kommando lief als Datei/Anzeige geaendert wurde"
-092 "Ex Kommando misslungen: restliche Kommandoeingabe ignoriert"
-093 "Ex Kommando misslungen: umdefinierte Tasten ungueltig"
+090 "@ mit Bereich lief, als Datei/Anzeige ge\xE4ndert wurde"
+091 "globales oder v-Kommando lief, als Datei/Anzeige ge\xE4ndert wurde"
+092 "Ex-Kommando mi\xDFlungen: restliche Kommandoeingabe ignoriert"
+093 "Ex-Kommando mi\xDFlungen: umdefinierte Tasten ung\xFCltig"
 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 "Adresswert zu gross"
-100 "Adresswert zu klein"
-101 "Ungueltige Adresskombination"
-102 "Ungueltige Adresse: nur %lu Zeilen in der Datei"
-103 "Ungueltige Adresse: die Datei ist leer"
+099 "Adre\xDFwert zu gro\xDF"
+100 "Adre\xDFwert zu klein"
+101 "Ung\xFCltige Adre\xDFkombination"
+102 "Ung\xFCltige Adresse: nur %lu Zeilen in der Datei"
+103 "Ung\xFCltige Adresse: die Datei ist leer"
 104 "Das Kommando %s erlaubt keine Adresse 0"
-105 "Keine Abkuerzungen zum Anzeigen"
-106 "Abkuerzungen muessen mit einem "Wort"-Zeichen enden"
-107 "Abkuerzungen duerfen keine Tabulator- oder Leerzeichen enthalten"
-108 "In Abkuerzungen duerfen ausser am Ende Wort- und Nicht-Wort-Zeichen nicht gemischt werden"
-109 ""%s" ist keine Abkuerzung"
-110 "Vi Kommando misslungen: umdefinierte Tasten ungueltig"
-111 "Keine weiteren Dateien zu edieren"
-112 "Keine vorhergehenden Dateien zu edieren"
-113 "Keine vorhergehenden Dateien fuer rewind"
+105 "Keine Abk\xFCrzungen zum Anzeigen"
+106 "Abk\xFCrzungen m\xFCssen mit einem \"Wort\"-Zeichen enden"
+107 "Abk\xFCrzungen d\xFCrfen keine Tabulator- oder Leerzeichen enthalten"
+108 "In Abk\xFCrzungen d\xFCrfen au\xDFer am Ende Wort- und Nicht-Wort-Zeichen nicht gemischt werden"
+109 "\"%s\" ist keine Abk\xFCrzung"
+110 "Vi Kommando mi\xDFlungen: umdefinierte Tasten ung\xFCltig"
+111 "Keine weiteren Dateien zu editieren"
+112 "Keine vorhergehenden Dateien zu editieren"
+113 "Keine vorhergehenden Dateien f\xFCr rewind"
 114 "Keine Dateiliste zum Anzeigen"
-115 "Kein vorhergehendes Kommando um "!" zu ersetzen"
-116 "Kein Dateiname fuer %%"
-117 "Kein Dateiname fuer #"
+115 "Kein vorhergehendes Kommando, um \"!\" zu ersetzen"
+116 "Kein Dateiname f\xFCr %%"
+117 "Kein Dateiname f\xFCr #"
 118 "Fehler: execl: %s"
-119 "I/O Fehler: %s"
-120 "Datei wurde seit dem letzten vollstaendigen Schreiben geaendert; schreibe oder verwende ! zum ignorieren"
+119 "E/A-Fehler: %s"
+120 "Datei wurde seit dem letzten vollst\xE4ndigen Schreiben ge\xE4ndert; 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: gehoehrt weder Ihnen noch root"
-126 "%s/%s: nicht gelesen: gehoehrt nicht Ihnen"
-127 "%s/%s: nicht gelesen: anderer Benutzer als Eigentuemer hat Schreibrecht"
-128 "%s: nicht gelesen: gehoehrt weder Ihnen noch root"
-129 "%s: nicht gelesen: gehoehrt nicht Ihnen"
-130 "%s: nicht gelesen: anderer Benutzer als Eigentuemer hat Schreibrecht"
+125 "%s/%s: nicht gelesen: geh\xF6rt weder Ihnen noch root"
+126 "%s/%s: nicht gelesen: geh\xF6rt nicht Ihnen"
+127 "%s/%s: nicht gelesen: anderer Benutzer als Eigent\xFCmer hat Schreibrecht"
+128 "%s: nicht gelesen: geh\xF6rt weder Ihnen noch root"
+129 "%s: nicht gelesen: geh\xF6rt nicht Ihnen"
+130 "%s: nicht gelesen: anderer Benutzer als Eigent\xFCmer hat Schreibrecht"
 131 "Keine folgenden Zeilen zum Verbinden"
-132 "Kein Eingabe-Map Eintrag"
-133 "Kein Kommando-Map Eintrag"
+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 muessen einzelne Buchstaben sein"
-137 "%s existiert, nicht geschrieben; verwende ! zum Ueberschreiben"
+135 "\"%s\" ist momentan nicht gemappt"
+136 "Markennamen m\xFCssen einzelne Buchstaben sein"
+137 "%s existiert, nicht geschrieben; verwende ! zum \xDCberschreiben"
 138 "Neue .exrc Datei: %s. "
 139 "Zielzeile ist innerhalb des Verschiebebereichs"
-140 "Das open Kommando verlangt, dass die open Option gesetzt ist"
+140 "Das open Kommando verlangt, da\xDF die open Option gesetzt ist"
 141 "Das open Kommando ist nocht nicht implementiert"
-142 "Rettung dieser Datei nicht moeglich"
+142 "Rettung dieser Datei nicht m\xF6glich"
 143 "Datei gerettet"
 144 "%s wurde in zu viele Dateinamen expandiert"
-145 "Nur regulaere Dateien und named pipes koennen gelesen werden"
-146 "%s: Lesesperrung war nicht moeglich"
+145 "Nur regul\xE4re Dateien und named pipes k\xF6nnen gelesen werden"
+146 "%s: Locken zum Lesen war nicht m\xF6glich"
 147 "lese ..."
 148 "%s: %lu Zeilen, %lu Zeichen"
-149 "Keine Hintegrundanzeigen vorhanden"
-150 "Das script Kommando ist nur im vi Modus verfuegbar"
-151 "Kein Kommando auszufuehren"
+149 "Keine Hintergrundanzeigen vorhanden"
+150 "Das script Kommando ist nur im vi Modus verf\xFCgbar"
+151 "Kein Kommando auszuf\xFChren"
 152 "shiftwidth Option auf 0 gesetzt"
-153 "Count ueberlauf"
-154 "Count unterlauf"
-155 "Regulaerer Ausdruck angegeben; r Flag bedeutungslos"
-156 "Die #, l und p Flags koennen im vi Modus nicht mit dem c Flag kombiniert werden"
-157 "Keine Uebereinstimmung gefunden"
+153 "Anzahl-\xDCberlauf"
+154 "Anzahl-Unterlauf"
+155 "Regul\xE4rer Ausdruck angegeben; r Flag bedeutungslos"
+156 "Die #, l und p Flags k\xF6nnen im vi Modus nicht mit dem c Flag kombiniert werden"
+157 "Keine \xDCbereinstimmung gefunden"
 158 "Kein vorhergehender 'tag' angegeben"
-159 "Weniger als %s Eintraege auf dem 'tag'-Stack; verwende :display t[ags]"
+159 "Weniger als %s Eintr\xE4ge auf dem 'tag'-Stack; verwende :display t[ags]"
 160 "Keine Datei namens %s auf dem 'tag'-Stack; verwende :display t[ags]"
-161 "Druecke Enter um fortzufahren: "
+161 "Dr\xFCcke 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 edieren"
+167 "%d weitere Dateien zu editieren"
 168 "Puffer %s ist leer"
-169 "Bestaetige Aenderung [n]"
+169 "Best\xE4tige \xC4nderung [n]"
 170 "Unterbrochen."
-171 "Kein vorhergehender Puffer zum Ausfuehren"
-172 "Kein vorhergehender regulaerer Ausdruck"
-173 "Das Kommando %s verlangt, dass bereits eine Datei eingelesen wurde"
+171 "Kein vorhergehender Puffer zum Ausf\xFChren"
+172 "Kein vorhergehender regul\xE4rer Ausdruck"
+173 "Das Kommando %s verlangt, da\xDF bereits eine Datei eingelesen wurde"
 174 "Benutzung: %s"
-175 "Das visual Kommando verlangt dass die open Option gesetzt ist"
+175 "Das visual Kommando verlangt da\xDF 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 edieren"
+180 "Keine vorhergehende Datei zu editieren"
 181 "Cursor nicht auf einer Zahl"
-182 "Sich ergebende Zahl ist zu gross"
+182 "Sich ergebende Zahl ist zu gro\xDF"
 183 "Sich ergebende Zahl ist zu klein"
 184 "Kein korrespondierendes Zeichen in dieser Zeile"
 185 "Korrespondierendes Zeichen nicht gefunden"
@@ -180,11 +179,11 @@
 187 "Keine andere Anzeige zum Hinschalten"
 188 "Zeichen nach Suchmuster, Zeilenoffset und/oder z Kommando"
 189 "Kein altes Suchmuster"
-190 "Suche zur urspruenglichen Position umgeschlagen"
-191 "Abkuerzung ueberschreitet Expansionsgrenze: Zeichen weggelassen"
+190 "Suche zur urspr\xFCnglichen Position zur\xFCckgekehrt"
+191 "Abk\xFCrzung \xFCberschreitet Expansionsgrenze: Zeichen weggelassen"
 192 "Nicht erlaubtes Zeichen; maskiere zum Eingeben"
 193 "Bereits am Anfang der Eingabe"
-194 "Keine weiteren Zeichen zu loeschen"
+194 "Keine weiteren Zeichen zu l\xF6schen"
 195 "Bewegung hinter das Dateiende"
 196 "Bewegung hinter das Zeilenende"
 197 "Keine Cursorbewegung gemacht"
@@ -196,51 +195,51 @@
 203 "Bereits am Zeilenende"
 204 "%s ist kein vi Kommando"
 205 "Benutzung: %s"
-206 "Keine Zeichen zu loeschen"
-207 "Das Q Kommando benoetigt das ex Terminal Interface"
+206 "Keine Zeichen zu l\xF6schen"
+207 "Das Q Kommando ben\xF6tigt 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 gross, max ist %u"
-215 "Anfuegen"
-216 "Aendern"
+214 "Wert der Window Option ist zu gro\xDF, max ist %u"
+215 "Anh\xE4ngen"
+216 "\xC4ndern"
 217 "Kommando"
-218 "Einfuegen"
+218 "Einf\xFCgen"
 219 "Ersetzen"
 220 "Bewegung hinter das Anzeigenende"
 221 "Bewegung vor den Anzeigenanfang"
-222 "Anzeige muss zum Zerlegen groesser als %d sein"
+222 "Anzeige mu\xDF f\xFCr Bildschirmteilung gr\xF6\xDFer als %d sein"
 223 "Keine Hintergrundanzeigen vorhanden"
-224 "Es gibt keine Hintergrundanzeige die eine Datei namens %s ediert"
+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 vergroessert werden"
-230 "Diese Anzeige kann nicht gestopped werden"
-231 "Unterbrochen: umdefinierte Tasten ungueltig"
-232 "vi: temporaerer Puffer nicht freigegeben"
+228 "Die Anzeige kann nicht vergr\xF6\xDFert werden"
+230 "Diese Anzeige kann nicht gestopt werden"
+231 "Unterbrochen: umdefinierte Tasten ung\xFCltig"
+232 "vi: tempor\xE4rer Puffer nicht freigegeben"
 233 "Dieses Terminal hat keine %s Taste"
 234 "es kann nur ein Puffer angegeben werden"
-235 "Zahl groesser als %lu"
+235 "Zahl gr\xF6\xDFer als %lu"
 236 "Unterbrochen"
-237 "Nicht moeglich temporaere Datei anzulegen"
-238 "Warnung: %s ist keine regulaere Datei"
-239 "%s ist bereits gesperrt, nur-lese Editorsitzung"
-240 "%s: loeschen"
-241 "%s: schliessen"
-242 "%s: loeschen"
-243 "%s: loeschen"
-244 "Nur-lese Datei, nicht geschrieben; verwende ! zum Ueberschreiben"
-245 "Nur-lese Datei, nicht geschrieben"
-246 "%s existiert, nicht geschrieben; verwende ! zum Ueberschreiben"
+237 "Nicht m\xF6glich, tempor\xE4re Datei anzulegen"
+238 "Warnung: %s ist keine regul\xE4re Datei"
+239 "%s ist bereits gelockt, Editorsitzung schreibgesch\xFCtzt"
+240 "%s: l\xF6schen"
+241 "%s: schlie\xDFen"
+242 "%s: l\xF6schen"
+243 "%s: l\xF6schen"
+244 "Datei nicht schreibbar, nicht geschrieben; verwende ! zum \xDCberschreiben"
+245 "Datei nicht schreibbar, nicht geschrieben"
+246 "%s existiert, nicht geschrieben; verwende ! zum \xDCberschreiben"
 247 "%s existiert, nicht geschrieben"
-248 "Teil der Datei, nicht geschrieben; verwende ! zum Ueberschreiben"
+248 "Teil der Datei, nicht geschrieben; verwende ! zum \xDCberschreiben"
 249 "Teil der Datei, nicht geschrieben"
-250 "%s: Datei wurde spaeter als diese Kopie veraendert; verwende ! zum Ueberschreiben"
-251 "%s: Datei wurde spaeter als diese Kopie veraendert"
-252 "%s: Schreibsperrung war nicht moeglich"
+250 "%s: Datei wurde sp\xE4ter als diese Kopie ver\xE4ndert; verwende ! zum \xDCberschreiben"
+251 "%s: Datei wurde sp\xE4ter als diese Kopie ver\xE4ndert"
+252 "%s: Locken zum Schreiben war nicht m\xF6glich"
 253 "schreibe ..."
 254 "%s: WARNUNG: DATEI ABGESCHNITTEN"
 255 "Bereits am ersten 'tag' dieser Gruppe"
@@ -247,22 +246,22 @@
 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 regulaere Datei"
-260 "%s: gehoehrt nicht Ihnen"
-261 "%s: anderer Benutzer als Eigentuemer hat Zugriff"
-262 "Datei wurde seit dem letzten vollstaendigen Schreiben geaendert; schreibe oder verwende ! zum ignorieren"
-263 "Datei wurde seit dem letzten vollstaendigen Schreiben geaendert; schreibe oder verwende :edit! zum ignorieren"
-264 "Datei wurde seit dem letzten vollstaendigen Schreiben geaendert; schreibe oder verwende ! zum ignorieren"
-265 "Datei ist temporaer; beim Verlassen gehen die Aenderungen verloren"
-266 "Nur-lese Datei, Aenderungen werden nicht automatisch geschrieben"
+259 "%s: keine regul\xE4re Datei"
+260 "%s: geh\xF6rt nicht Ihnen"
+261 "%s: anderer Benutzer als Eigent\xFCmer hat Zugriff"
+262 "Datei wurde seit dem letzten vollst\xE4ndigen Schreiben ge\xE4ndert; schreibe oder verwende ! zum ignorieren"
+263 "Datei wurde seit dem letzten vollst\xE4ndigen Schreiben ge\xE4ndert; schreibe oder verwende :edit! zum ignorieren"
+264 "Datei wurde seit dem letzten vollst\xE4ndigen Schreiben ge\xE4ndert; schreibe oder verwende ! zum ignorieren"
+265 "Datei ist tempor\xE4r; beim Verlassen gehen die \xC4nderungen verloren"
+266 "Datei ist schreibgesch\xFCtzt, \xC4nderungen werden nicht automatisch geschrieben"
 267 "Portokollierung neu begonnen"
-268 "bestaetigen [ynq]"
-269 "Druecke beliebige Taste um fortzufahren"
-270 "Druecke beliebige Taste um fortzufahren [: um weitere Kommandos einzugeben]: "
-271 "Druecke beliebige Taste um fortzufahren [q zum Verlassen]: "
-272 "Diese Form von %s benoetigt das ex Terminal-Interface"
+268 "best\xE4tigen [ynq]"
+269 "Dr\xFCcke beliebige Taste um fortzufahren"
+270 "Dr\xFCcke beliebige Taste um fortzufahren [: um weitere Kommandos einzugeben]: "
+271 "Dr\xFCcke beliebige Taste um fortzufahren [q zum Verlassen]: "
+272 "Diese Form von %s ben\xF6tigt das ex Terminal-Interface"
 273 "Gehe in ex Eingabe-Modus.\n"
-274 "Kommando schief gelaufen, noch keine Datei eingelesen"
+274 "Kommando schiefgelaufen, noch keine Datei eingelesen"
 275 " weiter?"
 276 "unerwartetes Zeichen - Ereignis"
 277 "unerwartetes Dateiende - Ereignis"
@@ -271,18 +270,18 @@
 280 "unerwartetes Verlassen - Ereignis"
 281 "unerwartetes Wiederherstellungs - Ereignis"
 282 "Bereits am letzten 'tag' dieser Gruppe"
-283 "Das %s Kommando benoetigt das ex Terminal-Interface"
-284 "Diese Form von %s wird nicht unterstuetzt wenn die 'secure edit' - Option gesetzt ist"
+283 "Das %s Kommando ben\xF6tigt das ex Terminal-Interface"
+284 "Diese Form von %s wird nicht unterst\xFCtzt wenn die 'secure edit' - Option gesetzt ist"
 285 "unerwartetes Zeichenketten - Ereignis"
 286 "unerwartetes timeout - Ereignis"
 287 "unerwartetes Schreibe - Ereignis"
-289 "Shell Expandierungen nicht unterstuetzt wenn die 'secure edit' - Option gesetzt ist"
-290 "Das %s Kommando wird nicht unterstuetzt wenn die 'secure edit' - Option gesetzt ist"
+289 "Shell Expandierungen nicht unterst\xFCtzt wenn die 'secure edit' - Option gesetzt ist"
+290 "Das %s Kommando wird nicht unterst\xFCtzt wenn die 'secure edit' - Option gesetzt ist"
 291 "set: %s kann nicht ausgeschaltet werden"
 292 "Anzeige zu klein."
-293 "angefuegt"
-294 "geaendert"
-295 "geloescht"
+293 "angef\xFCgt"
+294 "ge\xE4ndert"
+295 "gel\xF6scht"
 296 "verbunden"
 297 "verschoben"
 298 "geschoben"
@@ -290,18 +289,18 @@
 300 "Zeile"
 301 "Zeilen"
 302 "Vi wurde nicht mit dem Tcl Interpreter gelinkt"
-303 "Datei wurde seit dem letzten Schreiben veraendert."
-304 "Shell Expansion nicht geklappt"
-305 "Es ist keine %s Edieroption angegeben"
+303 "Datei wurde seit dem letzten Schreiben ver\xE4ndert."
+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 auszufuehren"
-308 "Druecke <CR> um ein Kommando auszufuehren, :q zum verlassen"
-309 "Verwende "cscope help" fuer Hilestellung"
+307 "Kein ex Kommando auszuf\xFChren"
+308 "Dr\xFCcke <CR> um ein Kommando auszuf\xFChren, :q zum verlassen"
+309 "Verwende \"cscope help\" f\xFCr 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: angefuegt: %lu Zeilen, %lu Zeichen"
-316 "unerwartetes Groessenveraenderungs - Ereignis"
+315 "%s: angef\xFCgt: %lu Zeilen, %lu Zeichen"
+316 "unerwartetes Gr\xF6\xDFenver\xE4nderungs - Ereignis"
 317 "%d Dateien zu edieren"

Modified: trunk/contrib/nvi/catalog/german.owner
===================================================================
--- trunk/contrib/nvi/catalog/german.owner	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/catalog/german.owner	2018-06-10 20:23:48 UTC (rev 10823)
@@ -1 +1,2 @@
-Bernhard Daeubler <daeb at physik.uni-ulm.de>
+Bernhard Daeubler	<daeb at physik.uni-ulm.de>
+Joerg Wunsch		<joerg_wunsch at uriah.heep.sax.de>

Modified: trunk/contrib/nvi/catalog/polish.base
===================================================================
--- trunk/contrib/nvi/catalog/polish.base	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/catalog/polish.base	2018-06-10 20:23:48 UTC (rev 10823)
@@ -43,8 +43,7 @@
 044 "Opcja lisp nie jest zaimplementowana"
 045 "komunikaty nie wy\xB3\xB1czone: %s"
 046 "komunikaty nie w\xB3\xB1czone: %s"
-048 "Opcja paragraph musi sk\xB3ada\xE6 si\xEA z dw\xF3ch grup symboli"
-049 "Opcja section musi sk\xB3ada\xE6 si\xEA z dw\xF3ch grup symboli"
+047 "Opcja %s musi sk\xB3ada\xE6 si\xEA z dw\xF3ch grup symboli"
 053 "Domy\xB6lny bufor jest pusty"
 054 "Bufor %s jest pusty"
 055 "Pliki z symbolem nowego wiersza w nazwie nie mog\xB1 by\xE6 odtworzone"
@@ -97,16 +96,16 @@
 103 "Niedozwolony adres: plik jest pusty"
 104 "Polecenie %s nie zezwala na u\xBFycie adresu 0"
 105 "Brak skr\xF3t\xF3w do wy\xB6wietlenia"
-106 "Skr\xF3ty musz\xB1 si\xEA ko\xF1czy\xE6 symbolem "s\xB3owo""
+106 "Skr\xF3ty musz\xB1 si\xEA ko\xF1czy\xE6 symbolem \"s\xB3owo\""
 107 "Skr\xF3ty nie mog\xB1 zawiera\xE6 spacji lub tabulacji"
 108 "Skr\xF3ty nie mog\xB1 przeplata\xE6 symboli s\xB3owo/nie-s\xB3owo, z wyj\xB1tkiem na ko\xF1cu linii"
-109 ""%s" nie jest skr\xF3tem"
+109 "\"%s\" nie jest skr\xF3tem"
 110 "B\xB3\xB1d polecenia vi: mapowanie klawiszy odrzucone"
 111 "Nie ma wi\xEAcej plik\xF3w do edycji"
 112 "Nie ma poprzednich plik\xF3w do edycji"
 113 "Nie ma poprzednich plik\xF3w do przewini\xEAcia wstecz"
 114 "Nie ma listy plik\xF3w do wy\xB6wietlenia"
-115 "Nie ma poprzedniego polecenia do zast\xB1pienia "!""
+115 "Nie ma poprzedniego polecenia do zast\xB1pienia \"!\""
 116 "Nie ma nazwy pliku do zast\xB1pienia %%"
 117 "Nie ma nazwy pliku do zast\xB1pienia #"
 118 "B\xB3\xB1d: execl: %s"
@@ -126,7 +125,7 @@
 132 "Brak pozycji map wej\xB6ciowych"
 133 "Brak pozycji map polece\xF1"
 134 "Znak %s nie mo\xBFe by\xE6 przemapowany"
-135 ""%s" obecnie nie jest mapowany"
+135 "\"%s\" obecnie nie jest mapowany"
 136 "Nazwa znacznika musi by\xE6 pojedy\xF1cz\xB1 liter\xB1"
 137 "%s istnieje, nie zapisany; u\xBFyj ! \xBFeby wymusi\xE6"
 138 "Nowy plik exrc: %s"
@@ -296,7 +295,7 @@
 306 "Vi nie zosta\xB3 uruchomiony z interpreterem Perl"
 307 "Brak polecenia ex do wykonania"
 308 "Naci\xB6nij <CR> \xBFeby wykonac polecenie, :q \xBFeby wyj\xB6\xE6"
-309 "U\xBFyj "cscope help" w celu uzyskania pomocy"
+309 "U\xBFyj \"cscope help\" w celu uzyskania pomocy"
 310 "Brak aktywnych po\xB3\xB1cze\xF1 cscope"
 311 "%s: nieznany typ poszukiwa\xF1: u\xBFyj jednego z %s"
 312 "%d: brak takiej sesji cscope"

Modified: trunk/contrib/nvi/catalog/ru_RU.KOI8-R.base
===================================================================
(Binary files differ)

Index: trunk/contrib/nvi/catalog/ru_RU.KOI8-R.base
===================================================================
--- trunk/contrib/nvi/catalog/ru_RU.KOI8-R.base	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/catalog/ru_RU.KOI8-R.base	2018-06-10 20:23:48 UTC (rev 10823)

Property changes on: trunk/contrib/nvi/catalog/ru_RU.KOI8-R.base
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Modified: trunk/contrib/nvi/catalog/ru_RU.KOI8-R.owner
===================================================================
--- trunk/contrib/nvi/catalog/ru_RU.KOI8-R.owner	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/catalog/ru_RU.KOI8-R.owner	2018-06-10 20:23:48 UTC (rev 10823)
@@ -1 +1,3 @@
-Dima Ruban <dima at rdy.com>, "Andrey A. Chernov" <ache at nagual.pp.ru>
+Andrey A. Chernov <ache at nagual.ru>
+Dima Ruban <dima at rdy.com>
+Pavel Timofeev <timp87 at gmail.com>

Modified: trunk/contrib/nvi/catalog/spanish.base
===================================================================
--- trunk/contrib/nvi/catalog/spanish.base	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/catalog/spanish.base	2018-06-10 20:23:48 UTC (rev 10823)
@@ -43,8 +43,7 @@
 044 "La opci\xF3n lisp no est\xE1 implementada"
 045 "mensajes no desconectados: %s"
 046 "mensajes no conectados: %s"
-048 "La opci\xF3n de p\xE1rrafo debe estar en dos grupos de caracteres"
-049 "La opci\xF3n de secci\xF3n debe estar en dos grupos de caracteres"
+047 "La opci\xF3n de %s debe estar en dos grupos de caracteres"
 053 "El buffer por omisi\xF3n est\xE1 vac\xEDo"
 054 "El buffer %s est\xE1 vac\xEDo"
 055 "Los archivos con nuevas l\xEDneas en el nombre son irrecuperables"
@@ -200,7 +199,6 @@
 207 "El comando Q requiere la interfase de terminal ex"
 208 "No hay comando para repetir"
 209 "El archivo est\xE1 vac\xEDo"
-209 "El archivo est\xE1 vac\xEDo"
 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"
@@ -293,7 +291,6 @@
 302 "Vi no se carg\xF3 con un int\xE9rprete Tcl"
 303 "Archivo modificado desde la \xFAltima escritura."
 304 "Expansi\xF3n de shell fracasada"
-304 "Expansi\xF3n de shell fracasada"
 305 "No hay opci\xF3n de edici\xF3n %s especificada"
 306 "Vi no se carg\xF3 con un int\xE9rprete Perl"
 307 "No hay comando ex para ejecutar"

Modified: trunk/contrib/nvi/catalog/swedish.base
===================================================================
--- trunk/contrib/nvi/catalog/swedish.base	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/catalog/swedish.base	2018-06-10 20:23:48 UTC (rev 10823)
@@ -29,7 +29,7 @@
 030 "Filen %s \xE4r ingen meddelandekatalog"
 031 "Kan inte s\xE4tta standardv\xE4rde f\xF6r %s flaggan"
 032 "Anv\xE4ndning: %s"
-033 "set: %s \xE4r en ok\xE4nd flagga: "set all" visar alla flaggor"
+033 "set: %s \xE4r en ok\xE4nd flagga: \"set all\" visar alla flaggor"
 034 "set: [no]%s flaggan kan inte ges ett v\xE4rde"
 035 "set: %s flaggan \xE4r inte boleansk"
 036 "set: %s flaggan: %s"
@@ -43,8 +43,7 @@
 044 "Lisp flaggan \xE4r inte implementerad"
 045 "meddelanden \xE4r inte avslagna: %s"
 046 "meddelanden \xE4r inte p\xE5slagna: %s"
-048 "Paragraph flaggan m\xE5ste ges i teckengrupper om tv\xE5"
-049 "Section flaggan m\xE5ste ges i teckengrupper om tv\xE5"
+047 "%s flaggan m\xE5ste ges i teckengrupper om tv\xE5"
 053 "Standardbufferten \xE4r tom"
 054 "Buffer %s \xE4r tom"
 055 "Filer med radmatning i namnet kan inte \xE5terskapas"
@@ -73,7 +72,7 @@
 078 "S\xF6ker..."
 079 "Inga icke skrivbara tecken funna"
 080 "Ok\xE4nt kommandonamn"
-082 "%s: kommandot \xE4r inte tillg\xE4ngligt i "ex" l\xE4ge"
+082 "%s: kommandot \xE4r inte tillg\xE4ngligt i \"ex\" l\xE4ge"
 083 "Talet f\xE5r inte vara noll"
 084 "%s: Ogiltig radspecifikation"
 085 "Fel i intern syntaxtabell (%s: %s)"
@@ -97,16 +96,16 @@
 103 "Otill\xE5ten adress: filen \xE4r tom"
 104 "%s kommandot till\xE5ter inte en adress som \xE4r 0"
 105 "Inga f\xF6rkortningar att visa"
-106 "F\xF6rkortningar m\xE5ste sluta med ett "ord" tecken"
+106 "F\xF6rkortningar m\xE5ste sluta med ett \"ord\" tecken"
 107 "F\xF6rkortningar kan inte inneh\xE5lla mellanslag eller tab"
-108 "F\xF6rkortningar kan inte blanda "ord"/"icke ord" tecken, utom i slutet"
-109 ""%s" \xE4r ingen f\xF6rkortning"
+108 "F\xF6rkortningar kan inte blanda \"ord\"/\"icke ord\" tecken, utom i slutet"
+109 "\"%s\" \xE4r ingen f\xF6rkortning"
 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\xE4tta "!" med"
+115 "Inget tidigare kommando att ers\xE4tta \"!\" med"
 116 "Inget filnamn att ers\xE4tta %% med"
 117 "Inget filnamn att ers\xE4tta # med"
 118 "Fel: execl: %s"
@@ -114,8 +113,8 @@
 120 "Filen \xE4ndrad efter sista skrivning; spara eller anv\xE4nd !"
 121 "Kan inte hitta hemkatalog"
 122 "Ny nuvarande katalog: %s"
-123 "Inga "cut buffers" att visa"
-124 "%s kommandot kan inte anv\xE4nds som del i ett "global" eller v kommando"
+123 "Inga \"cut buffers\" att visa"
+124 "%s kommandot kan inte anv\xE4nds som del i ett \"global\" eller v kommando"
 125 "%s/%s: inte l\xE4st: varken du eller root \xE4r \xE4gare"
 126 "%s/%s: inte l\xE4st: du \xE4r inte \xE4gare"
 127 "%s/%s: inte l\xE4st: skrivbar av annan \xE4n \xE4garen"
@@ -126,7 +125,7 @@
 132 "Det finns inget i inmatningsmappningen"
 133 "Det finns inget i kommandomappningen"
 134 "%s tecknet kan inte mappas om"
-135 ""%s" \xE4r inte ommappat just nu"
+135 "\"%s\" \xE4r inte ommappat just nu"
 136 "Namn p\xE5 markeringar m\xE5ste vara ett tecken l\xE5nga"
 137 "%s finns, inget sparat; anv\xE4nd ! f\xF6r att spara"
 138 "Ny exrc fil: %s"
@@ -141,13 +140,13 @@
 147 "L\xE4ser..."
 148 "%s: %lu rader, %lu tecken"
 149 "Inga bakgrundsf\xF6nster att visa"
-150 "Script kommandot finns bara i "vi" l\xE4ge"
+150 "Script kommandot finns bara i \"vi\" l\xE4ge"
 151 "Inget kommando att exekvera"
 152 "shiftwidth flaggan satt till 0"
 153 "Talet har f\xF6r stort v\xE4rde"
 154 "Talet har f\xF6r litet v\xE4rde"
 155 "Regulj\xE4rt uttryck \xE4r givet; r flaggan \xE4r meningsl\xF6s"
-156 "#, l och p flaggorna kan inte kombineras med c flaggan i "vi" l\xE4ge"
+156 "#, l och p flaggorna kan inte kombineras med c flaggan i \"vi\" l\xE4ge"
 157 "Ingen matchande text funnen"
 158 "Inget tidigare m\xE4rke har givits"
 159 "Det \xE4r f\xE4rre \xE4n %s m\xE4rken i stacken; anv\xE4nd :display t[ags]"
@@ -182,7 +181,7 @@
 189 "Ingen tidigare s\xF6kstr\xE4ng"
 190 "S\xF6kningen slog runt till ursprungliga positionen"
 191 "F\xF6rkortning \xF6verskred expanderingsgr\xE4nsen: tecken har tagits bort"
-192 "Ogiltigt tecken; anv\xE4nd "quote" f\xF6r att s\xE4tta in"
+192 "Ogiltigt tecken; anv\xE4nd \"quote\" f\xF6r att s\xE4tta in"
 193 "Redan i b\xF6rjan p\xE5 ins\xE4ttningen"
 194 "Inga fler tecken att ta bort"
 195 "F\xF6rs\xF6k att g\xE5 bortom slutet p\xE5 filen"
@@ -194,10 +193,10 @@
 201 "Buffertar m\xE5ste anges f\xF6re kommandot"
 202 "Redan i slutet av filen"
 203 "Redan p\xE5 slutet av raden"
-204 "%s \xE4r inte ett "vi" kommando"
+204 "%s \xE4r inte ett \"vi\" kommando"
 205 "Anv\xE4ndning: %s"
 206 "Inga tecken att ta bort"
-207 "Q kommandot kr\xE4ver "ex" i terminall\xE4ge"
+207 "Q kommandot kr\xE4ver \"ex\" i terminall\xE4ge"
 208 "Inget kommando att repetera"
 209 "Filen \xE4r tom"
 210 "%s kan inte anv\xE4ndas som ett f\xF6rflyttningskommando"
@@ -260,8 +259,8 @@
 269 "Tryck p\xE5 en tangent f\xF6r att forts\xE4tta: "
 270 "Tryck p\xE5 en tangent f\xF6r att forts\xE4tta [: f\xF6r att ge fler kommandon]: "
 271 "Tryck p\xE5 en tangent f\xF6r att forts\xE4tta [q f\xF6r att avsluta]: "
-272 "Den formen av %s kr\xE4ver "ex" i terminall\xE4ge"
-273 "G\xE5r till "ex" inmatningsl\xE4ge."
+272 "Den formen av %s kr\xE4ver \"ex\" i terminall\xE4ge"
+273 "G\xE5r till \"ex\" inmatningsl\xE4ge."
 274 "Kommandot misslyckades, ingen fil inl\xE4st \xE4nnu."
 275 " forts?"
 276 "Ov\xE4ntad teckenh\xE4ndelse"
@@ -271,7 +270,7 @@
 280 "Ov\xE4ntad avslutningsh\xE4ndelse"
 281 "Ov\xE4ntad omritningsh\xE4ndelse"
 282 "Redan vid sista m\xE4rket i denna grupp"
-283 "%s kommandot kr\xE4ver "ex" i terminall\xE4ge"
+283 "%s kommandot kr\xE4ver \"ex\" i terminall\xE4ge"
 284 "Den formen av %s \xE4r inte tillg\xE4nglig n\xE4r secure edit flaggan \xE4r satt"
 285 "Ov\xE4ntad str\xE4ngh\xE4ndelse"
 286 "Ov\xE4ntad tidsh\xE4ndelse"
@@ -294,9 +293,9 @@
 304 "Skalexpansion misslyckades"
 305 "Ingen %s edit flagga given"
 306 "Vi har inte l\xE4nkats med en Perl tolk"
-307 "Inga "ex" kommandon att exekvera"
+307 "Inga \"ex\" kommandon att exekvera"
 308 "Tryck <CR> f\xF6r att exekvera kommando, :q f\xF6r att avsluta"
-309 "G\xF6r "cscope help" f\xF6r hj\xE4lp"
+309 "G\xF6r \"cscope help\" f\xF6r hj\xE4lp"
 310 "Inga cscope kopplingar k\xF6rs"
 311 "%s: ok\xE4nd s\xF6ktyp: anv\xE4nd en av %s"
 312 "%d: ingen s\xE5dan cscope session"

Modified: trunk/contrib/nvi/catalog/uk_UA.KOI8-U.base
===================================================================
(Binary files differ)

Index: trunk/contrib/nvi/catalog/uk_UA.KOI8-U.base
===================================================================
--- trunk/contrib/nvi/catalog/uk_UA.KOI8-U.base	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/catalog/uk_UA.KOI8-U.base	2018-06-10 20:23:48 UTC (rev 10823)

Property changes on: trunk/contrib/nvi/catalog/uk_UA.KOI8-U.base
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Added: trunk/contrib/nvi/catalog/zh_CN.GB2312.base
===================================================================
(Binary files differ)

Index: trunk/contrib/nvi/catalog/zh_CN.GB2312.base
===================================================================
--- trunk/contrib/nvi/catalog/zh_CN.GB2312.base	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/catalog/zh_CN.GB2312.base	2018-06-10 20:23:48 UTC (rev 10823)

Property changes on: trunk/contrib/nvi/catalog/zh_CN.GB2312.base
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Added: trunk/contrib/nvi/catalog/zh_CN.GB2312.owner
===================================================================
--- trunk/contrib/nvi/catalog/zh_CN.GB2312.owner	                        (rev 0)
+++ trunk/contrib/nvi/catalog/zh_CN.GB2312.owner	2018-06-10 20:23:48 UTC (rev 10823)
@@ -0,0 +1 @@
+Zhihao Yuan <lichray at gmail.com>

Modified: trunk/contrib/nvi/cl/README.signal
===================================================================
--- trunk/contrib/nvi/cl/README.signal	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/cl/README.signal	2018-06-10 20:23:48 UTC (rev 10823)
@@ -1,4 +1,4 @@
-#	@(#)README.signal	10.1 (Berkeley) 6/23/95
+#	$Id: README.signal,v 10.1 1995/06/23 10:28:17 bostic Exp $
 
 There are six (normally) asynchronous actions about which vi cares:
 SIGHUP, SIGINT, SIGQUIT, SIGTERM, SIGTSTP and SIGWINCH.

Modified: trunk/contrib/nvi/cl/cl.h
===================================================================
--- trunk/contrib/nvi/cl/cl.h	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/cl/cl.h	2018-06-10 20:23:48 UTC (rev 10823)
@@ -6,12 +6,25 @@
  *
  * See the LICENSE file for redistribution information.
  *
- *	@(#)cl.h	10.19 (Berkeley) 9/24/96
+ *	$Id: cl.h,v 10.34 2011/08/15 20:07:32 zy Exp $
  */
 
+#ifdef USE_WIDECHAR
+#define _XOPEN_SOURCE_EXTENDED
+#endif
+#ifdef HAVE_NCURSES_H
+#include <ncurses.h>
+#else
+#include <curses.h>
+#endif
+
 typedef struct _cl_private {
-	CHAR_T	 ibuf[256];	/* Input keys. */
+	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. */
@@ -24,6 +37,10 @@
 	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
@@ -39,30 +56,30 @@
 	    TE_SENT=0, TI_SENT } ti_te;
 
 #define	CL_IN_EX	0x0001	/* Currently running ex. */
-#define	CL_RENAME	0x0002	/* X11 xterm icon/window renamed. */
-#define	CL_RENAME_OK	0x0004	/* User wants the windows renamed. */
-#define	CL_SCR_EX_INIT	0x0008	/* Ex screen initialized. */
-#define	CL_SCR_VI_INIT	0x0010	/* Vi screen initialized. */
-#define	CL_SIGHUP	0x0020	/* SIGHUP arrived. */
-#define	CL_SIGINT	0x0040	/* SIGINT arrived. */
-#define	CL_SIGTERM	0x0080	/* SIGTERM arrived. */
-#define	CL_SIGWINCH	0x0100	/* SIGWINCH arrived. */
-#define	CL_STDIN_TTY	0x0200	/* Talking to a terminal. */
+#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 line relative to a specific window. */
-#define	RLNO(sp, lno)	(sp)->woff + (lno)
+/* The screen position relative to a specific window. */
+#define	RCNO(sp, cno)	(cno)
+#define	RLNO(sp, lno)	(lno)
 
-/* X11 xterm escape sequence to rename the icon/window. */
-#define	XTERM_RENAME	"\033]0;%s\007"
-
 /*
  * XXX
  * Some implementations of curses.h don't define these for us.  Used for
@@ -75,4 +92,4 @@
 #define	FALSE	0
 #endif
 
-#include "cl_extern.h"
+#include "extern.h"

Modified: trunk/contrib/nvi/cl/cl_funcs.c
===================================================================
--- trunk/contrib/nvi/cl/cl_funcs.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/cl/cl_funcs.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -10,7 +10,7 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)cl_funcs.c	10.50 (Berkeley) 9/24/96";
+static const char sccsid[] = "$Id: cl_funcs.c,v 10.74 2012/10/11 10:30:16 zy Exp $";
 #endif /* not lint */
 
 #include <sys/types.h>
@@ -19,11 +19,13 @@
 
 #include <bitstring.h>
 #include <ctype.h>
-#include <curses.h>
 #include <signal.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#ifdef HAVE_TERM_H
+#include <term.h>
+#endif
 #include <termios.h>
 #include <unistd.h>
 
@@ -31,23 +33,18 @@
 #include "../vi/vi.h"
 #include "cl.h"
 
-/*
- * 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(sp, str, len)
-	SCR *sp;
-	const char *str;
-	size_t len;
+static void cl_rdiv __P((SCR *));
+
+static int 
+addstr4(SCR *sp, void *str, size_t len, int wide)
 {
 	CL_PRIVATE *clp;
-	size_t oldy, oldx;
+	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
@@ -54,22 +51,52 @@
 	 * it's a split screen, use inverse video.
 	 */
 	iv = 0;
-	getyx(stdscr, oldy, oldx);
+	getyx(win, y, x);
 	if (!F_ISSET(sp, SC_SCR_EXWROTE) &&
-	    oldy == RLNO(sp, LASTLINE(sp)) && IS_SPLIT(sp)) {
+	    y == RLNO(sp, LASTLINE(sp)) && IS_SPLIT(sp)) {
 		iv = 1;
-		(void)standout();
+		(void)wstandout(win);
 	}
 
-	if (addnstr(str, len) == ERR)
+#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)standend();
+		(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, (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, (void *)str, len, 0);
+}
+
+/*
  * cl_attr --
  *	Toggle a screen attribute on/off.
  *
@@ -76,14 +103,13 @@
  * PUBLIC: int cl_attr __P((SCR *, scr_attr_t, int));
  */
 int
-cl_attr(sp, attribute, on)
-	SCR *sp;
-	scr_attr_t attribute;
-	int on;
+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:
@@ -146,9 +172,9 @@
 			(void)fflush(stdout);
 		} else {
 			if (on)
-				(void)standout();
+				(void)wstandout(win);
 			else
-				(void)standend();
+				(void)wstandend(win);
 		}
 		break;
 	default:
@@ -164,9 +190,7 @@
  * PUBLIC: int cl_baud __P((SCR *, u_long *));
  */
 int
-cl_baud(sp, ratep)
-	SCR *sp;
-	u_long *ratep;
+cl_baud(SCR *sp, u_long *ratep)
 {
 	CL_PRIVATE *clp;
 
@@ -207,10 +231,9 @@
  * PUBLIC: int cl_bell __P((SCR *));
  */
 int
-cl_bell(sp)
-	SCR *sp;
+cl_bell(SCR *sp)
 {
-	if (F_ISSET(sp, SC_EX | SC_SCR_EXWROTE))
+	if (F_ISSET(sp, SC_EX | SC_SCR_EXWROTE | SC_SCR_EX))
 		(void)write(STDOUT_FILENO, "\07", 1);		/* \a */
 	else {
 		/*
@@ -232,10 +255,26 @@
  * PUBLIC: int cl_clrtoeol __P((SCR *));
  */
 int
-cl_clrtoeol(sp)
-	SCR *sp;
+cl_clrtoeol(SCR *sp)
 {
-	return (clrtoeol() == ERR);
+	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);
 }
 
 /*
@@ -245,10 +284,10 @@
  * PUBLIC: int cl_cursor __P((SCR *, size_t *, size_t *));
  */
 int
-cl_cursor(sp, yp, xp)
-	SCR *sp;
-	size_t *yp, *xp;
+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
@@ -256,8 +295,11 @@
 	 * current screen, and not absolute.  Screens that implement the split
 	 * using physically distinct screens won't need this hack.
 	 */
-	getyx(stdscr, *yp, *xp);
-	*yp -= sp->woff;
+	getyx(win, *yp, *xp);
+	/*
+	*yp -= sp->roff;
+	*xp -= sp->coff;
+	*/
 	return (0);
 }
 
@@ -268,14 +310,14 @@
  * PUBLIC: int cl_deleteln __P((SCR *));
  */
 int
-cl_deleteln(sp)
-	SCR *sp;
+cl_deleteln(SCR *sp)
 {
-	CHAR_T ch;
 	CL_PRIVATE *clp;
-	size_t col, lno, spcnt, oldy, oldx;
+	WINDOW *win;
+	size_t y, x;
 
 	clp = CLP(sp);
+	win = CLSP(sp) ? CLSP(sp) : stdscr;
 
 	/*
 	 * This clause is required because the curses screen uses reverse
@@ -284,38 +326,11 @@
 	 *
 	 * 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(stdscr, oldy, oldx);
-#ifdef mvchgat
-		mvchgat(RLNO(sp, LASTLINE(sp)), 0, -1, A_NORMAL, 0, NULL);
-#else
-		for (lno = RLNO(sp, LASTLINE(sp)), col = spcnt = 0;;) {
-			(void)move(lno, col);
-			ch = winch(stdscr);
-			if (isblank(ch))
-				++spcnt;
-			else {
-				(void)move(lno, col - spcnt);
-				for (; spcnt > 0; --spcnt)
-					(void)addch(' ');
-				(void)addch(ch);
-			}
-			if (++col >= sp->cols)
-				break;
-		}
-#endif
-		(void)move(oldy, oldx);
+		getyx(win, y, x);
+		mvwchgat(win, RLNO(sp, LASTLINE(sp)), 0, -1, A_NORMAL, 0, NULL);
+		(void)wmove(win, y, x);
 	}
 
 	/*
@@ -322,10 +337,50 @@
 	 * The bottom line is expected to be blank after this operation,
 	 * and other screens must support that semantic.
 	 */
-	return (deleteln() == ERR);
+	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.
@@ -333,9 +388,7 @@
  * PUBLIC: int cl_ex_adjust __P((SCR *, exadj_t));
  */
 int
-cl_ex_adjust(sp, action)
-	SCR *sp;
-	exadj_t action;
+cl_ex_adjust(SCR *sp, exadj_t action)
 {
 	CL_PRIVATE *clp;
 	int cnt;
@@ -390,14 +443,15 @@
  * PUBLIC: int cl_insertln __P((SCR *));
  */
 int
-cl_insertln(sp)
-	SCR *sp;
+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 (insertln() == ERR);
+	return (winsertln(win) == ERR);
 }
 
 /*
@@ -407,11 +461,7 @@
  * PUBLIC: int cl_keyval __P((SCR *, scr_keyval_t, CHAR_T *, int *));
  */
 int
-cl_keyval(sp, val, chp, dnep)
-	SCR *sp;
-	scr_keyval_t val;
-	CHAR_T *chp;
-	int *dnep;
+cl_keyval(SCR *sp, scr_keyval_t val, CHAR_T *chp, int *dnep)
 {
 	CL_PRIVATE *clp;
 
@@ -449,14 +499,14 @@
  * PUBLIC: int cl_move __P((SCR *, size_t, size_t));
  */
 int
-cl_move(sp, lno, cno)
-	SCR *sp;
-	size_t lno, cno;
+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 (move(RLNO(sp, lno), cno) == ERR) {
-		msgq(sp, M_ERR,
-		    "Error: move: l(%u) c(%u) o(%u)", lno, cno, sp->woff);
+	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);
@@ -469,13 +519,17 @@
  * PUBLIC: int cl_refresh __P((SCR *, int));
  */
 int
-cl_refresh(sp, repaint)
-	SCR *sp;
-	int repaint;
+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
@@ -488,6 +542,28 @@
 	 * 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 != NULL; psp = TAILQ_NEXT(psp, q))
+			for (tsp = TAILQ_NEXT(psp, q); tsp != NULL;
+			    tsp = TAILQ_NEXT(tsp, q))
+				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().
@@ -494,10 +570,32 @@
 	 */
 	if (repaint)
 		clearok(curscr, 1);
-	return (refresh() == ERR);
+	/*
+	 * 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)
+{
+#ifdef __NetBSD__
+	mvvline(sp->roff, sp->cols + sp->coff, '|', sp->rows);
+#else
+	mvvline(sp->roff, sp->cols + sp->coff, ACS_VLINE, sp->rows);
+#endif
+}
+
+/*
  * cl_rename --
  *	Rename the file.
  *
@@ -504,41 +602,98 @@
  * PUBLIC: int cl_rename __P((SCR *, char *, int));
  */
 int
-cl_rename(sp, name, on)
-	SCR *sp;
-	char *name;
-	int on;
+cl_rename(SCR *sp, char *name, int on)
 {
 	GS *gp;
 	CL_PRIVATE *clp;
-	char *ttype;
+	FILE *pfp;
+	char buf[256], *s, *e;
+	char * wid;
+	char cmd[64];
 
 	gp = sp->gp;
 	clp = CLP(sp);
 
-	ttype = OG_STR(gp, GO_TERM);
-
 	/*
 	 * XXX
 	 * We can only rename windows for xterm.
 	 */
 	if (on) {
-		if (F_ISSET(clp, CL_RENAME_OK) &&
-		    !strncmp(ttype, "xterm", sizeof("xterm") - 1)) {
-			F_SET(clp, CL_RENAME);
-			(void)printf(XTERM_RENAME, name);
-			(void)fflush(stdout);
+		clp->focus = sp;
+		if (!F_ISSET(clp, CL_RENAME_OK) ||
+				strncmp(OG_STR(gp, GO_TERM), "xterm", 5))
+			return (0);
+
+		if (clp->oname == NULL && (wid = getenv("WINDOWID"))) {
+			snprintf(cmd, sizeof(cmd), "xprop -id %s WM_NAME", wid);
+			if ((pfp = popen(cmd, "r")) == NULL)
+				goto rename;
+			if (fgets(buf, sizeof(buf), pfp) == NULL) {
+				pclose(pfp);
+				goto rename;
+			}
+			pclose(pfp);
+			if ((s = strchr(buf, '"')) != NULL &&
+			    (e = strrchr(buf, '"')) != NULL)
+				clp->oname = strndup(s + 1, e - s - 1);
 		}
+
+rename:		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);
-			(void)printf(XTERM_RENAME, ttype);
-			(void)fflush(stdout);
 		}
 	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);
+#undef XTERM_RENAME
+}
+
+/* 
+ * 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.
  *
@@ -545,18 +700,18 @@
  * PUBLIC: int cl_suspend __P((SCR *, int *));
  */
 int
-cl_suspend(sp, allowedp)
-	SCR *sp;
-	int *allowedp;
+cl_suspend(SCR *sp, int *allowedp)
 {
 	struct termios t;
 	CL_PRIVATE *clp;
+	WINDOW *win;
 	GS *gp;
-	size_t oldy, oldx;
+	size_t y, x;
 	int changed;
 
 	gp = sp->gp;
 	clp = CLP(sp);
+	win = CLSP(sp) ? CLSP(sp) : stdscr;
 	*allowedp = 1;
 
 	/*
@@ -596,9 +751,9 @@
 	 * Not sure this is necessary in System V implementations, but it
 	 * shouldn't hurt.
 	 */
-	getyx(stdscr, oldy, oldx);
-	(void)move(LINES - 1, 0);
-	(void)refresh();
+	getyx(win, y, x);
+	(void)wmove(win, LINES - 1, 0);
+	(void)wrefresh(win);
 
 	/*
 	 * Temporarily end the screen.  System V introduced a semantic where
@@ -607,10 +762,8 @@
 	 * restarting after endwin(), so we have to do what clean up we can
 	 * without calling it.
 	 */
-#ifdef HAVE_BSD_CURSES
 	/* Save the terminal settings. */
 	(void)tcgetattr(STDIN_FILENO, &t);
-#endif
 
 	/* Restore the cursor keys to normal mode. */
 	(void)keypad(stdscr, FALSE);
@@ -618,11 +771,8 @@
 	/* 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
@@ -647,14 +797,11 @@
 		return (0);
 	}
 
-#ifdef HAVE_BSD_CURSES
 	/* Restore terminal settings. */
+	wrefresh(win);			    /* Needed on SunOs/Solaris ? */
 	if (F_ISSET(clp, CL_STDIN_TTY))
 		(void)tcsetattr(STDIN_FILENO, TCSASOFT | TCSADRAIN, &t);
 
-	(void)cl_attr(sp, SA_ALTERNATE, 1);
-#endif
-
 	/* Set the window name. */
 	(void)cl_rename(sp, sp->frp->name, 1);
 
@@ -662,7 +809,7 @@
 	(void)keypad(stdscr, TRUE);
 
 	/* Refresh and repaint the screen. */
-	(void)move(oldy, oldx);
+	(void)wmove(win, y, x);
 	(void)cl_refresh(sp, 1);
 
 	/* If the screen changed size, set the SIGWINCH bit. */
@@ -681,7 +828,7 @@
  * PUBLIC: void cl_usage __P((void));
  */
 void
-cl_usage()
+cl_usage(void)
 {
 #define	USAGE "\
 usage: ex [-eFRrSsv] [-c command] [-t tag] [-w size] [file ...]\n\
@@ -695,8 +842,9 @@
  * gdbrefresh --
  *	Stub routine so can flush out curses screen changes using gdb.
  */
-int
-gdbrefresh()
+static int
+	__attribute__((unused))
+gdbrefresh(void)
 {
 	refresh();
 	return (0);		/* XXX Convince gdb to run it. */

Modified: trunk/contrib/nvi/cl/cl_main.c
===================================================================
--- trunk/contrib/nvi/cl/cl_main.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/cl/cl_main.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -10,7 +10,7 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)cl_main.c	10.36 (Berkeley) 10/14/96";
+static const char sccsid[] = "$Id: cl_main.c,v 10.55 2011/08/15 19:52:28 zy Exp $";
 #endif /* not lint */
 
 #include <sys/types.h>
@@ -17,7 +17,6 @@
 #include <sys/queue.h>
 
 #include <bitstring.h>
-#include <curses.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <signal.h>
@@ -24,13 +23,13 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#ifdef HAVE_TERM_H
+#include <term.h>
+#endif
 #include <termios.h>
 #include <unistd.h>
 
 #include "../common/common.h"
-#ifdef RUNNING_IP
-#include "../ip/ip.h"
-#endif
 #include "cl.h"
 #include "pathnames.h"
 
@@ -50,9 +49,7 @@
  *	This is the main loop for the standalone curses editor.
  */
 int
-main(argc, argv)
-	int argc;
-	char *argv[];
+main(int argc, char **argv)
 {
 	static int reenter;
 	CL_PRIVATE *clp;
@@ -59,7 +56,7 @@
 	GS *gp;
 	size_t rows, cols;
 	int rval;
-	char *ip_arg, **p_av, **t_av, *ttype;
+	char **p_av, **t_av, *ttype;
 
 	/* If loaded at 0 and jumping through a NULL pointer, stop. */
 	if (reenter++)
@@ -73,8 +70,6 @@
 	 * no way to portably call getopt twice, so arguments parsed here must
 	 * be removed from the argument list.
 	 */
-#ifdef RUNNING_IP
-	ip_arg = NULL;
 	for (p_av = t_av = argv;;) {
 		if (*t_av == NULL) {
 			*p_av = NULL;
@@ -84,33 +79,9 @@
 			while ((*p_av++ = *t_av++) != NULL);
 			break;
 		}
-		if (!memcmp(*t_av, "-I", sizeof("-I") - 1)) {
-			if (t_av[0][2] != '\0') {
-				ip_arg = t_av[0] + 2;
-				++t_av;
-				--argc;
-				continue;
-			}
-			if (t_av[1] != NULL) {
-				ip_arg = t_av[1];
-				t_av += 2;
-				argc -= 2;
-				continue;
-			}
-		}
 		*p_av++ = *t_av++;
 	}
 
-	/*
-	 * If we're being called as an editor library, we're done here, we
-	 * get loaded with the curses screen, we don't share much code.
-	 */
-	if (ip_arg != NULL)
-		exit (ip_main(argc, argv, gp, ip_arg));
-#else
-	ip_arg = argv[0];
-#endif
-		
 	/* Create and initialize the CL_PRIVATE structure. */
 	clp = cl_init(gp);
 
@@ -164,10 +135,8 @@
 	 * XXX
 	 * Reset the X11 xterm icon/window name.
 	 */
-	if (F_ISSET(clp, CL_RENAME)) {
-		(void)printf(XTERM_RENAME, ttype);
-		(void)fflush(stdout);
-	}
+	if (F_ISSET(clp, CL_RENAME))
+		cl_setname(gp, clp->oname);
 
 	/* If a killer signal arrived, pretend we just got it. */
 	if (clp->killersig) {
@@ -178,7 +147,10 @@
 
 	/* Free the global and CL private areas. */
 #if defined(DEBUG) || defined(PURIFY) || defined(LIBRARY)
+	if (clp->oname != NULL)
+		free(clp->oname);
 	free(clp);
+	free(OG_STR(gp, GO_TERM));
 	free(gp);
 #endif
 
@@ -190,10 +162,8 @@
  *	Create and partially initialize the GS structure.
  */
 static GS *
-gs_init(name)
-	char *name;
+gs_init(char *name)
 {
-	CL_PRIVATE *clp;
 	GS *gp;
 	char *p;
 
@@ -206,7 +176,6 @@
 	if (gp == NULL)
 		perr(name, NULL);
 
-
 	gp->progname = name;
 	return (gp);
 }
@@ -216,8 +185,7 @@
  *	Create and partially initialize the CL structure.
  */
 static CL_PRIVATE *
-cl_init(gp)
-	GS *gp;
+cl_init(GS *gp)
 {
 	CL_PRIVATE *clp;
 	int fd;
@@ -265,8 +233,7 @@
  *	Initialize terminal information.
  */
 static void
-term_init(name, ttype)
-	char *name, *ttype;
+term_init(char *name, char *ttype)
 {
 	int err;
 
@@ -287,8 +254,7 @@
 #define	GLOBAL_CLP \
 	CL_PRIVATE *clp = GCLP(__global_list);
 static void
-h_hup(signo)
-	int signo;
+h_hup(int signo)
 {
 	GLOBAL_CLP;
 
@@ -297,8 +263,7 @@
 }
 
 static void
-h_int(signo)
-	int signo;
+h_int(int signo)
 {
 	GLOBAL_CLP;
 
@@ -306,8 +271,7 @@
 }
 
 static void
-h_term(signo)
-	int signo;
+h_term(int signo)
 {
 	GLOBAL_CLP;
 
@@ -316,8 +280,7 @@
 }
 
 static void
-h_winch(signo)
-	int signo;
+h_winch(int signo)
 {
 	GLOBAL_CLP;
 
@@ -332,9 +295,7 @@
  * PUBLIC: int sig_init __P((GS *, SCR *));
  */
 int
-sig_init(gp, sp)
-	GS *gp;
-	SCR *sp;
+sig_init(GS *gp, SCR *sp)
 {
 	CL_PRIVATE *clp;
 
@@ -376,10 +337,7 @@
  *	Set a signal handler.
  */
 static int
-setsig(signo, oactp, handler)
-	int signo;
-	struct sigaction *oactp;
-	void (*handler) __P((int));
+setsig(int signo, struct sigaction *oactp, void (*handler) (int))
 {
 	struct sigaction act;
 
@@ -410,8 +368,7 @@
  *	End signal setup.
  */
 static void
-sig_end(gp)
-	GS *gp;
+sig_end(GS *gp)
 {
 	CL_PRIVATE *clp;
 
@@ -429,17 +386,20 @@
  *	Initialize the standard curses functions.
  */
 static void
-cl_func_std(gp)
-	GS *gp;
+cl_func_std(GS *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;
@@ -451,6 +411,7 @@
 	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;
 }
@@ -460,8 +421,7 @@
  *	Print system error.
  */
 static void
-perr(name, msg)
-	char *name, *msg;
+perr(char *name, char *msg)
 {
 	(void)fprintf(stderr, "%s:", name);
 	if (msg != NULL)

Modified: trunk/contrib/nvi/cl/cl_read.c
===================================================================
--- trunk/contrib/nvi/cl/cl_read.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/cl/cl_read.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -10,18 +10,14 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)cl_read.c	10.15 (Berkeley) 9/24/96";
+static const char sccsid[] = "$Id: cl_read.c,v 10.30 2012/07/12 18:28:58 zy Exp $";
 #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 <curses.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <signal.h>
@@ -35,8 +31,12 @@
 #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_T *, size_t, int *, struct timeval *));
+    u_int32_t, char *, size_t, int *, struct timeval *));
 static int	cl_resize __P((SCR *, size_t, size_t));
 
 /*
@@ -46,16 +46,15 @@
  * PUBLIC: int cl_event __P((SCR *, EVENT *, u_int32_t, int));
  */
 int
-cl_event(sp, evp, flags, ms)
-	SCR *sp;
-	EVENT *evp;
-	u_int32_t flags;
-	int ms;
+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;
+	int changed, nr = 0;
+	CHAR_T *wp;
+	size_t wlen;
+	int rc;
 
 	/*
 	 * Queue signal based events.  We never clear SIGHUP or SIGTERM events,
@@ -102,12 +101,25 @@
 	}
 
 	/* Read input characters. */
+read:
 	switch (cl_read(sp, LF_ISSET(EC_QUOTED | EC_RAW),
-	    clp->ibuf, sizeof(clp->ibuf), &nr, tp)) {
+	    clp->ibuf + clp->skip, SIZE(clp->ibuf) - clp->skip, &nr, tp)) {
 	case INP_OK:
-		evp->e_csp = clp->ibuf;
-		evp->e_len = nr;
+		rc = INPUT2INT5(sp, clp->cw, clp->ibuf, nr + clp->skip, 
+				wp, wlen);
+		evp->e_csp = 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_EOF:
 		evp->e_event = E_EOF;
@@ -131,19 +143,11 @@
  *	Read characters from the input.
  */
 static input_t
-cl_read(sp, flags, bp, blen, nrp, tp)
-	SCR *sp;
-	u_int32_t flags;
-	CHAR_T *bp;
-	size_t blen;
-	int *nrp;
-	struct timeval *tp;
+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;
-	SCR *tsp;
 	fd_set rdfd;
 	input_t rval;
 	int maxfd, nr, term_reset;
@@ -175,13 +179,10 @@
 	 * 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_ZERO(&rdfd);
 		FD_SET(STDIN_FILENO, &rdfd);
-		switch (select(STDIN_FILENO + 1,
-		    &rdfd, NULL, NULL, tp == NULL ? &poll : tp)) {
+		switch (select(STDIN_FILENO + 1, &rdfd, NULL, NULL, tp)) {
 		case 0:
 			return (INP_TIMEOUT);
 		case -1:
@@ -225,13 +226,11 @@
 loop:		FD_ZERO(&rdfd);
 		FD_SET(STDIN_FILENO, &rdfd);
 		maxfd = STDIN_FILENO;
-		for (tsp = gp->dq.cqh_first;
-		    tsp != (void *)&gp->dq; tsp = tsp->q.cqe_next)
-			if (F_ISSET(sp, SC_SCRIPT)) {
-				FD_SET(sp->script->sh_master, &rdfd);
-				if (sp->script->sh_master > maxfd)
-					maxfd = sp->script->sh_master;
-			}
+		if (F_ISSET(sp, SC_SCRIPT)) {
+			FD_SET(sp->script->sh_master, &rdfd);
+			if (sp->script->sh_master > maxfd)
+				maxfd = sp->script->sh_master;
+		}
 		switch (select(maxfd + 1, &rdfd, NULL, NULL, NULL)) {
 		case 0:
 			abort();
@@ -309,12 +308,10 @@
  *	Reset the options for a resize event.
  */
 static int
-cl_resize(sp, lines, columns)
-	SCR *sp;
-	size_t lines, columns;
+cl_resize(SCR *sp, size_t lines, size_t columns)
 {
 	ARGS *argv[2], a, b;
-	char b1[1024];
+	CHAR_T b1[1024];
 
 	a.bp = b1;
 	b.bp = NULL;
@@ -322,12 +319,10 @@
 	argv[0] = &a;
 	argv[1] = &b;
 
-	(void)snprintf(b1, sizeof(b1), "lines=%lu", (u_long)lines);
-	a.len = strlen(b1);
+	a.len = SPRINTF(b1, sizeof(b1), L("lines=%lu"), (u_long)lines);
 	if (opts_set(sp, argv, NULL))
 		return (1);
-	(void)snprintf(b1, sizeof(b1), "columns=%lu", (u_long)columns);
-	a.len = strlen(b1);
+	a.len = SPRINTF(b1, sizeof(b1), L("columns=%lu"), (u_long)columns);
 	if (opts_set(sp, argv, NULL))
 		return (1);
 	return (0);

Modified: trunk/contrib/nvi/cl/cl_screen.c
===================================================================
--- trunk/contrib/nvi/cl/cl_screen.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/cl/cl_screen.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -5,27 +5,27 @@
  *	Keith Bostic.  All rights reserved.
  *
  * See the LICENSE file for redistribution information.
- *
- * $MidnightBSD$
  */
 
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)cl_screen.c	10.49 (Berkeley) 9/24/96";
+static const char sccsid[] = "$Id: cl_screen.c,v 10.56 2002/05/03 19:59:44 skimo Exp $";
 #endif /* not lint */
 
 #include <sys/types.h>
 #include <sys/queue.h>
+#include <sys/time.h>
 
 #include <bitstring.h>
-#include <curses.h>
 #include <errno.h>
 #include <signal.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#ifdef HAVE_TERM_H
 #include <term.h>
+#endif
 #include <termios.h>
 #include <unistd.h>
 
@@ -46,18 +46,22 @@
  * PUBLIC: int cl_screen __P((SCR *, u_int32_t));
  */
 int
-cl_screen(sp, flags)
-	SCR *sp;
-	u_int32_t flags;
+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);
@@ -64,8 +68,8 @@
 	}
 	
 	/* 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))
+	if ((LF_ISSET(SC_EX) && F_ISSET(sp, SC_SCR_EX)) ||
+	    (LF_ISSET(SC_VI) && F_ISSET(sp, SC_SCR_VI)))
 		return (0);
 
 	/*
@@ -93,12 +97,12 @@
 	if (F_ISSET(sp, SC_SCR_VI)) {
 		F_CLR(sp, SC_SCR_VI);
 
-		if (sp->q.cqe_next != (void *)&gp->dq) {
-			(void)move(RLNO(sp, sp->rows), 0);
-			clrtobot();
+		if (TAILQ_NEXT(sp, q) != NULL) {
+			(void)wmove(win, RLNO(sp, sp->rows), 0);
+			wclrtobot(win);
 		}
-		(void)move(RLNO(sp, sp->rows) - 1, 0);
-		refresh();
+		(void)wmove(win, RLNO(sp, sp->rows) - 1, 0);
+		wrefresh(win);
 	}
 
 	/* Enter the requested mode. */
@@ -130,8 +134,7 @@
  * PUBLIC: int cl_quit __P((GS *));
  */
 int
-cl_quit(gp)
-	GS *gp;
+cl_quit(GS *gp)
 {
 	CL_PRIVATE *clp;
 	int rval;
@@ -181,8 +184,7 @@
  *	Initialize the curses vi screen.
  */
 static int
-cl_vi_init(sp)
-	SCR *sp;
+cl_vi_init(SCR *sp)
 {
 	CL_PRIVATE *clp;
 	GS *gp;
@@ -245,6 +247,7 @@
 	 * The HP/UX newterm doesn't support the NULL first argument, so we
 	 * have to specify the terminal type.
 	 */
+	(void)del_curterm(cur_term);
 	errno = 0;
 	if (newterm(ttype, stdout, stdin) == NULL) {
 		if (errno)
@@ -385,8 +388,7 @@
  *	Shutdown the vi screen.
  */
 static int
-cl_vi_end(gp)
-	GS *gp;
+cl_vi_end(GS *gp)
 {
 	CL_PRIVATE *clp;
 
@@ -429,8 +431,7 @@
  *	Initialize the ex screen.
  */
 static int
-cl_ex_init(sp)
-	SCR *sp;
+cl_ex_init(SCR *sp)
 {
 	CL_PRIVATE *clp;
 
@@ -504,8 +505,7 @@
  *	Shutdown the ex screen.
  */
 static int
-cl_ex_end(gp)
-	GS *gp;
+cl_ex_end(GS *gp)
 {
 	CL_PRIVATE *clp;
 
@@ -523,9 +523,7 @@
  * PUBLIC: int cl_getcap __P((SCR *, char *, char **));
  */
 int
-cl_getcap(sp, name, elementp)
-	SCR *sp;
-	char *name, **elementp;
+cl_getcap(SCR *sp, char *name, char **elementp)
 {
 	size_t len;
 	char *t;
@@ -543,8 +541,7 @@
  *	Free any allocated termcap/terminfo strings.
  */
 static void
-cl_freecap(clp)
-	CL_PRIVATE *clp;
+cl_freecap(CL_PRIVATE *clp)
 {
 	if (clp->el != NULL) {
 		free(clp->el);
@@ -566,6 +563,12 @@
 		free(clp->smso);
 		clp->smso = NULL;
 	}
+	/* Required by libcursesw :) */
+	if (clp->cw.bp1.c != NULL) {
+		free(clp->cw.bp1.c);
+		clp->cw.bp1.c = NULL;
+		clp->cw.blen1 = 0;
+	}
 }
 
 /*
@@ -573,10 +576,7 @@
  *	Put a value into the environment.
  */
 static int
-cl_putenv(name, str, value)
-	char *name, *str;
-	u_long value;
-
+cl_putenv(char *name, char *str, u_long value)
 {
 	char buf[40];
 

Modified: trunk/contrib/nvi/cl/cl_term.c
===================================================================
--- trunk/contrib/nvi/cl/cl_term.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/cl/cl_term.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -10,7 +10,7 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)cl_term.c	10.22 (Berkeley) 9/15/96";
+static const char sccsid[] = "$Id: cl_term.c,v 10.34 2013/12/07 16:21:14 wjenkner Exp $";
 #endif /* not lint */
 
 #include <sys/types.h>
@@ -19,7 +19,6 @@
 #include <sys/stat.h>
 
 #include <bitstring.h>
-#include <curses.h>
 #include <errno.h>
 #include <limits.h>
 #include <signal.h>
@@ -26,6 +25,9 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#ifdef HAVE_TERM_H
+#include <term.h>
+#endif
 #include <termios.h>
 #include <unistd.h>
 
@@ -82,20 +84,30 @@
  * PUBLIC: int cl_term_init __P((SCR *));
  */
 int
-cl_term_init(sp)
-	SCR *sp;
+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];
+	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;
-		if (seq_set(sp, tkp->name, strlen(tkp->name), t, strlen(t),
-		    tkp->output, strlen(tkp->output), SEQ_COMMAND,
+		CHAR2INT(sp, tkp->name, strlen(tkp->name), wp, wlen);
+		MEMCPY(name, wp, wlen);
+		CHAR2INT(sp, t, strlen(t), wp, wlen);
+		MEMCPY(ts, wp, wlen);
+		CHAR2INT(sp, tkp->output, strlen(tkp->output), wp, wlen);
+		MEMCPY(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);
 	}
@@ -109,8 +121,13 @@
 				break;
 		if (kp == NULL)
 			continue;
-		if (seq_set(sp, tkp->name, strlen(tkp->name), t, strlen(t),
-		    &kp->ch, 1, SEQ_INPUT, SEQ_NOOVERWRITE | SEQ_SCREEN))
+		CHAR2INT(sp, tkp->name, strlen(tkp->name), wp, wlen);
+		MEMCPY(name, wp, wlen);
+		CHAR2INT(sp, t, strlen(t), wp, wlen);
+		MEMCPY(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);
 	}
 
@@ -128,15 +145,26 @@
 		if (!strcmp(t, "\b"))
 			continue;
 		if (tkp->output == NULL) {
-			if (seq_set(sp, tkp->name, strlen(tkp->name),
-			    t, strlen(t), NULL, 0,
+			CHAR2INT(sp, tkp->name, strlen(tkp->name), wp, wlen);
+			MEMCPY(name, wp, wlen);
+			CHAR2INT(sp, t, strlen(t), wp, wlen);
+			MEMCPY(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
-			if (seq_set(sp, tkp->name, strlen(tkp->name),
-			    t, strlen(t), tkp->output, strlen(tkp->output),
+		} else {
+			CHAR2INT(sp, tkp->name, strlen(tkp->name), wp, wlen);
+			MEMCPY(name, wp, wlen);
+			CHAR2INT(sp, t, strlen(t), wp, wlen);
+			MEMCPY(ts, wp, wlen);
+			CHAR2INT(sp, tkp->output, strlen(tkp->output), wp, wlen);
+			MEMCPY(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);
+		}
 	}
 
 	/*
@@ -143,7 +171,7 @@
 	 * 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)
+	SLIST_FOREACH(qp, sp->gp->seqq, q)
 		if (F_ISSET(qp, SEQ_FUNCMAP))
 			(void)cl_pfmap(sp, qp->stype,
 			    qp->input, qp->ilen, qp->output, qp->olen);
@@ -157,17 +185,20 @@
  * PUBLIC: int cl_term_end __P((GS *));
  */
 int
-cl_term_end(gp)
-	GS *gp;
+cl_term_end(GS *gp)
 {
-	SEQ *qp, *nqp;
+	SEQ *qp, *nqp, *pre_qp = NULL;
 
 	/* 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);
-	}
+	SLIST_FOREACH_SAFE(qp, gp->seqq, q, nqp)
+		if (F_ISSET(qp, SEQ_SCREEN)) {
+			if (qp == SLIST_FIRST(gp->seqq))
+				SLIST_REMOVE_HEAD(gp->seqq, q);
+			else
+				SLIST_REMOVE_AFTER(pre_qp, q);
+			(void)seq_free(qp);
+		} else
+			pre_qp = qp;
 	return (0);
 }
 
@@ -178,11 +209,7 @@
  * PUBLIC: int cl_fmap __P((SCR *, seq_t, CHAR_T *, size_t, CHAR_T *, size_t));
  */
 int
-cl_fmap(sp, stype, from, flen, to, tlen)
-	SCR *sp;
-	seq_t stype;
-	CHAR_T *from, *to;
-	size_t flen, tlen;
+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))
@@ -198,28 +225,33 @@
  *	Map a function key (private version).
  */
 static int
-cl_pfmap(sp, stype, from, flen, to, tlen)
-	SCR *sp;
-	seq_t stype;
-	CHAR_T *from, *to;
-	size_t flen, tlen;
+cl_pfmap(SCR *sp, seq_t stype, CHAR_T *from, size_t flen, CHAR_T *to, size_t tlen)
 {
 	size_t nlen;
-	char *p, keyname[64];
+	char *p;
+	char name[64];
+	CHAR_T keyname[64];
+	CHAR_T ts[20];
+	CHAR_T *wp;
+	size_t wlen;
 
-	(void)snprintf(keyname, sizeof(keyname), "kf%d", atoi(from + 1));
-	if ((p = tigetstr(keyname)) == NULL ||
+	(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_str(sp, M_ERR, from, "233|This terminal has no %s key");
+		msgq_wstr(sp, M_ERR, from, "233|This terminal has no %s key");
 		return (1);
 	}
 
-	nlen = snprintf(keyname,
-	    sizeof(keyname), "function key %d", atoi(from + 1));
+	nlen = SPRINTF(keyname,
+	    SIZE(keyname), L("function key %d"), 
+			(int)STRTOL(from+1,NULL,10));
+	CHAR2INT(sp, p, strlen(p), wp, wlen);
+	MEMCPY(ts, wp, wlen);
 	return (seq_set(sp, keyname, nlen,
-	    p, strlen(p), to, tlen, stype, SEQ_NOOVERWRITE | SEQ_SCREEN));
+	    ts, strlen(p), to, tlen, stype, SEQ_NOOVERWRITE | SEQ_SCREEN));
 }
 
 /*
@@ -229,11 +261,7 @@
  * PUBLIC: int cl_optchange __P((SCR *, int, char *, u_long *));
  */
 int
-cl_optchange(sp, opt, str, valp)
-	SCR *sp;
-	int opt;
-	char *str;
-	u_long *valp;
+cl_optchange(SCR *sp, int opt, char *str, u_long *valp)
 {
 	CL_PRIVATE *clp;
 
@@ -251,14 +279,10 @@
 		F_CLR(sp, SC_SCR_EX | SC_SCR_VI);
 		break;
 	case O_MESG:
-		(void)cl_omesg(sp, clp, !*valp);
+		(void)cl_omesg(sp, clp, *valp);
 		break;
 	case O_WINDOWNAME:
 		if (*valp) {
-			F_CLR(clp, CL_RENAME_OK);
-
-			(void)cl_rename(sp, NULL, 0);
-		} else {
 			F_SET(clp, CL_RENAME_OK);
 
 			/*
@@ -267,6 +291,10 @@
 			 */
 			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;
 	}
@@ -280,10 +308,7 @@
  * PUBLIC: int cl_omesg __P((SCR *, CL_PRIVATE *, int));
  */
 int
-cl_omesg(sp, clp, on)
-	SCR *sp;
-	CL_PRIVATE *clp;
-	int on;
+cl_omesg(SCR *sp, CL_PRIVATE *clp, int on)
 {
 	struct stat sb;
 	char *tty;
@@ -329,15 +354,9 @@
  * PUBLIC: int cl_ssize __P((SCR *, int, size_t *, size_t *, int *));
  */
 int
-cl_ssize(sp, sigwinch, rowp, colp, changedp)
-	SCR *sp;
-	int sigwinch;
-	size_t *rowp, *colp;
-	int *changedp;
+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;
@@ -358,12 +377,10 @@
 	 * 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) {
 		/*
@@ -453,8 +470,7 @@
  * PUBLIC: int cl_putchar __P((int));
  */
 int
-cl_putchar(ch)
-	int ch;
+cl_putchar(int ch)
 {
 	return (putchar(ch));
 }

Added: trunk/contrib/nvi/cl/extern.h
===================================================================
--- trunk/contrib/nvi/cl/extern.h	                        (rev 0)
+++ trunk/contrib/nvi/cl/extern.h	2018-06-10 20:23:48 UTC (rev 10823)
@@ -0,0 +1,31 @@
+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 *, 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, 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));


Property changes on: trunk/contrib/nvi/cl/extern.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Modified: trunk/contrib/nvi/common/args.h
===================================================================
--- trunk/contrib/nvi/common/args.h	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/common/args.h	2018-06-10 20:23:48 UTC (rev 10823)
@@ -6,7 +6,7 @@
  *
  * See the LICENSE file for redistribution information.
  *
- *	@(#)args.h	10.2 (Berkeley) 3/6/96
+ *	$Id: args.h,v 10.2 1996/03/06 19:50:07 bostic Exp $
  */
 
 /*

Modified: trunk/contrib/nvi/common/common.h
===================================================================
--- trunk/contrib/nvi/common/common.h	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/common/common.h	2018-06-10 20:23:48 UTC (rev 10823)
@@ -6,16 +6,10 @@
  *
  * See the LICENSE file for redistribution information.
  *
- *	@(#)common.h	10.13 (Berkeley) 9/25/96
+ *	$Id: common.h,v 10.22 2012/04/13 05:21:50 zy Exp $
  */
 
 /*
- * 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.
@@ -29,6 +23,8 @@
  */
 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;
@@ -48,7 +44,7 @@
 typedef struct _text		TEXT;
 
 /* Autoindent state. */
-typedef enum { C_NOTSET, C_CARATSET, C_NOCHANGE, C_ZEROSET } carat_t;
+typedef enum { C_NOTSET, C_CARATSET, C_ZEROSET } carat_t;
 
 /* Busy message types. */
 typedef enum { BUSY_ON = 1, BUSY_OFF, BUSY_UPDATE } busy_t;
@@ -86,6 +82,7 @@
 #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 "screen.h"		/* Required by exf.h. */
@@ -93,4 +90,4 @@
 #include "log.h"
 #include "mem.h"
 
-#include "com_extern.h"
+#include "extern.h"

Added: trunk/contrib/nvi/common/conv.c
===================================================================
--- trunk/contrib/nvi/common/conv.c	                        (rev 0)
+++ trunk/contrib/nvi/common/conv.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -0,0 +1,446 @@
+/*-
+ * 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.
+ * Copyright (c) 2011, 2012
+ *	Zhihao Yuan.  All rights reserved.
+ *
+ * See the LICENSE file for redistribution information.
+ */
+
+#include "config.h"
+
+#ifndef lint
+static const char sccsid[] = "$Id: conv.c,v 2.39 2013/07/01 23:28:13 zy Exp $";
+#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 <langinfo.h>
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <unistd.h>
+
+#include "common.h"
+
+/*
+ * codeset --
+ *	Get the locale encoding.
+ *
+ * PUBLIC: char * codeset __P((void));
+ */
+char *
+codeset(void) {
+    static char *cs;
+
+    if (cs == NULL)
+	cs = nl_langinfo(CODESET);
+    return cs;
+}
+
+#ifdef USE_WIDECHAR
+static int 
+raw2int(SCR *sp, const char * str, ssize_t len, CONVWIN *cw,
+	size_t *tolen, CHAR_T **dst)
+{
+    int i;
+    CHAR_T **tostr = &cw->bp1.wc;
+    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.wc;
+
+    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, (iconv_src_t)&str, &left, &bp, &outleft) == -1 &&	\
+		errno != E2BIG)						\
+	    goto err;							\
+	if ((len = CONV_BUFFER_SIZE - outleft) == 0) {			\
+	    error = -left;						\
+	    goto err;							\
+	}				    				\
+	src = buffer;							\
+    } while (0)
+
+#define IC_RESET()							\
+    do {								\
+	if (id != (iconv_t)-1)						\
+	    iconv(id, NULL, NULL, NULL, NULL);				\
+    } while(0)
+#else
+#define CONVERT(str, left, src, len)
+#define IC_RESET()
+#endif
+
+static int 
+default_char2int(SCR *sp, const char * str, ssize_t len, CONVWIN *cw, 
+		size_t *tolen, CHAR_T **dst, iconv_t id)
+{
+    size_t i = 0, j;
+    CHAR_T **tostr = &cw->bp1.wc;
+    size_t  *blen = &cw->blen1;
+    mbstate_t mbs;
+    size_t   n;
+    ssize_t  nlen = len;
+    char *src = (char *)str;
+#ifdef USE_ICONV
+    char	buffer[CONV_BUFFER_SIZE];
+#endif
+    size_t	left = len;
+    int		error = 1;
+
+    BZERO(&mbs, 1);
+    BINC_RETW(NULL, *tostr, *blen, nlen);
+
+#ifdef USE_ICONV
+    if (id != (iconv_t)-1)
+	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 == -2) error = -(len-j);
+	if (n == -1 || n == -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;
+	}
+    }
+
+    error = 0;
+err:
+    *tolen = i;
+    *dst = cw->bp1.wc;
+    IC_RESET();
+
+    return error;
+}
+
+static int 
+fe_char2int(SCR *sp, const char * str, ssize_t len, CONVWIN *cw, 
+	    size_t *tolen, CHAR_T **dst)
+{
+    return default_char2int(sp, str, len, cw, tolen, dst,
+	sp->conv.id[IC_FE_CHAR2INT]);
+}
+
+static int 
+ie_char2int(SCR *sp, const char * str, ssize_t len, CONVWIN *cw, 
+	    size_t *tolen, CHAR_T **dst)
+{
+    return default_char2int(sp, str, len, cw, tolen, dst,
+	sp->conv.id[IC_IE_CHAR2INT]);
+}
+
+static int 
+cs_char2int(SCR *sp, const char * str, ssize_t len, CONVWIN *cw, 
+	    size_t *tolen, CHAR_T **dst)
+{
+    return default_char2int(sp, str, len, cw, tolen, dst,
+	(iconv_t)-1);
+}
+
+static int 
+int2raw(SCR *sp, const CHAR_T * str, ssize_t len, CONVWIN *cw,
+	size_t *tolen, char **dst)
+{
+    int i;
+    char **tostr = &cw->bp1.c;
+    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.c;
+
+    return 0;
+}
+
+static int 
+default_int2char(SCR *sp, const CHAR_T * str, ssize_t len, CONVWIN *cw, 
+		size_t *tolen, char **pdst, iconv_t id)
+{
+    size_t i, j, offset = 0;
+    char **tostr = &cw->bp1.c;
+    size_t  *blen = &cw->blen1;
+    mbstate_t mbs;
+    size_t n;
+    ssize_t  nlen = len + MB_CUR_MAX;
+    char *dst;
+    size_t buflen;
+#ifdef USE_ICONV
+    char	buffer[CONV_BUFFER_SIZE];
+#endif
+    int		error = 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(_buffer, lenp, cw, offset)				\
+    do {								\
+	char *bp = _buffer;						\
+	int ret;							\
+	do {								\
+	    size_t outleft = cw->blen1 - offset;			\
+	    char *obp = cw->bp1.c + offset;				\
+	    if (cw->blen1 < offset + MB_CUR_MAX) {		    	\
+		nlen += 256;						\
+		BINC_RETC(NULL, cw->bp1.c, cw->blen1, nlen);		\
+	    }						    		\
+	    errno = 0;						    	\
+	    ret = iconv(id, (iconv_src_t)&bp, lenp, &obp, &outleft);	\
+	    if (ret == -1 && errno != E2BIG)				\
+		goto err;						\
+	    offset = cw->blen1 - outleft;			        \
+	} while (ret != 0); 					        \
+    } while (0)
+#else
+#define CONVERT2(_buffer, lenp, cw, offset)
+#endif
+
+
+    BZERO(&mbs, 1);
+    BINC_RETC(NULL, *tostr, *blen, nlen);
+    dst = *tostr; buflen = *blen;
+
+#ifdef USE_ICONV
+    if (id != (iconv_t)-1) {
+	dst = buffer; buflen = CONV_BUFFER_SIZE;
+    }
+#endif
+
+    for (i = 0, j = 0; i < len; ++i) {
+	n = wcrtomb(dst+j, str[i], &mbs);
+	if (n == -1) goto err;
+	j += n;
+	if (buflen < j + MB_CUR_MAX) {
+	    if (id != (iconv_t)-1) {
+		CONVERT2(buffer, &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(buffer, &j, cw, offset);
+	CONVERT2(NULL, NULL, cw, offset);  /* back to the initial state */
+	*tolen = offset;
+    }
+
+    error = 0;
+err:
+    if (error)
+	*tolen = j;
+    *pdst = cw->bp1.c;
+    IC_RESET();
+
+    return error;
+}
+
+static int 
+fe_int2char(SCR *sp, const CHAR_T * str, ssize_t len, CONVWIN *cw, 
+	    size_t *tolen, char **dst)
+{
+    return default_int2char(sp, str, len, cw, tolen, dst,
+	sp->conv.id[IC_FE_INT2CHAR]);
+}
+
+static int 
+cs_int2char(SCR *sp, const CHAR_T * str, ssize_t len, CONVWIN *cw, 
+	    size_t *tolen, char **dst)
+{
+    return default_int2char(sp, str, len, cw, tolen, dst,
+	(iconv_t)-1);
+}
+
+#endif
+
+/*
+ * conv_init --
+ *	Initialize the iconv environment.
+ *
+ * PUBLIC: void conv_init __P((SCR *, SCR *));
+ */
+void
+conv_init(SCR *orig, SCR *sp)
+{
+    int i;
+
+    if (orig == NULL)
+	setlocale(LC_ALL, "");
+    if (orig != NULL)
+	BCOPY(&orig->conv, &sp->conv, 1);
+#ifdef USE_WIDECHAR
+    else {
+	char *ctype = setlocale(LC_CTYPE, NULL);
+
+	/*
+	 * XXX
+	 * This hack fixes the libncursesw issue on FreeBSD.
+	 */
+	if (!strcmp(ctype, "ko_KR.CP949"))
+	    setlocale(LC_CTYPE, "ko_KR.eucKR");
+	else if (!strcmp(ctype, "zh_CN.GB2312"))
+	    setlocale(LC_CTYPE, "zh_CN.eucCN");
+	else if (!strcmp(ctype, "zh_CN.GBK"))
+	    setlocale(LC_CTYPE, "zh_CN.GB18030");
+
+	/*
+	 * Switch to 8bit mode if locale is C;
+	 * LC_CTYPE should be reseted to C if unmatched.
+	 */
+	if (!strcmp(ctype, "C") || !strcmp(ctype, "POSIX")) {
+	    sp->conv.sys2int = sp->conv.file2int = raw2int;
+	    sp->conv.int2sys = sp->conv.int2file = int2raw;
+	    sp->conv.input2int = raw2int;
+	} else {
+	    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;
+	}
+#ifdef USE_ICONV
+	o_set(sp, O_INPUTENCODING, OS_STRDUP, codeset(), 0);
+#endif
+    }
+#endif
+
+    /* iconv descriptors must be distinct to screens. */
+    for (i = 0; i <= IC_IE_TO_UTF16; ++i)
+	sp->conv.id[i] = (iconv_t)-1;
+#ifdef USE_ICONV
+    conv_enc(sp, O_INPUTENCODING, 0);
+#endif
+}
+
+/*
+ * conv_enc --
+ *	Convert file/input encoding.
+ *
+ * PUBLIC: int conv_enc __P((SCR *, int, char *));
+ */
+int
+conv_enc(SCR *sp, int option, char *enc)
+{
+#if defined(USE_WIDECHAR) && defined(USE_ICONV)
+    iconv_t *c2w, *w2c;
+
+    switch (option) {
+    case O_FILEENCODING:
+	c2w = sp->conv.id + IC_FE_CHAR2INT;
+	w2c = sp->conv.id + IC_FE_INT2CHAR;
+	if (!enc) enc = O_STR(sp, O_FILEENCODING);
+	if (*c2w != (iconv_t)-1)
+	    iconv_close(*c2w);
+	if (*w2c != (iconv_t)-1)
+	    iconv_close(*w2c);
+	if (strcasecmp(codeset(), enc)) {
+	    if ((*c2w = iconv_open(codeset(), enc)) == (iconv_t)-1)
+		goto err;
+	    if ((*w2c = iconv_open(enc, codeset())) == (iconv_t)-1)
+		goto err;
+	} else *c2w = *w2c = (iconv_t)-1;
+	break;
+    case O_INPUTENCODING:
+	c2w = sp->conv.id + IC_IE_CHAR2INT;
+	w2c = sp->conv.id + IC_IE_TO_UTF16;
+	if (!enc) enc = O_STR(sp, O_INPUTENCODING);
+	if (*c2w != (iconv_t)-1)
+	    iconv_close(*c2w);
+	if (*w2c != (iconv_t)-1)
+	    iconv_close(*w2c);
+	if (strcasecmp(codeset(), enc)) {
+	    if ((*c2w = iconv_open(codeset(), enc)) == (iconv_t)-1)
+		goto err;
+	} else *c2w = (iconv_t)-1;
+	/* UTF-16 can not be locale and can not be inputed. */
+	if ((*w2c = iconv_open("utf-16be", enc)) == (iconv_t)-1)
+	    goto err;
+	break;
+    }
+
+    F_CLR(sp, SC_CONV_ERROR);
+    F_SET(sp, SC_SCR_REFORMAT);
+
+    return 0;
+err:
+#endif
+    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;
+    }
+    return 1;
+}
+
+/*
+ * conv_end --
+ *	Close the iconv descriptors, release the buffer.
+ *
+ * PUBLIC: void conv_end __P((SCR *));
+ */
+void
+conv_end(SCR *sp)
+{
+#if defined(USE_WIDECHAR) && defined(USE_ICONV)
+    int i;
+    for (i = 0; i <= IC_IE_TO_UTF16; ++i)
+	if (sp->conv.id[i] != (iconv_t)-1)
+	    iconv_close(sp->conv.id[i]);
+	if (sp->cw.bp1.c != NULL)
+	    free(sp->cw.bp1.c);
+#endif
+}


Property changes on: trunk/contrib/nvi/common/conv.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/contrib/nvi/common/conv.h
===================================================================
--- trunk/contrib/nvi/common/conv.h	                        (rev 0)
+++ trunk/contrib/nvi/common/conv.h	2018-06-10 20:23:48 UTC (rev 10823)
@@ -0,0 +1,57 @@
+/*-
+ * 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) 2011, 2012
+ *	Zhihao Yuan.  All rights reserved.
+ *
+ * See the LICENSE file for redistribution information.
+ *
+ *	$Id: conv.h,v 2.32 2013/03/11 01:20:53 zy Exp $
+ */
+
+#ifdef USE_ICONV
+#include <iconv.h>
+#ifdef ICONV_TRADITIONAL
+typedef char **		iconv_src_t;
+#else
+typedef char const **	iconv_src_t;
+#endif
+#else
+typedef int	iconv_t;
+#endif
+
+/*
+ * XXX
+ * We can not use MB_CUR_MAX here, since UTF-8 may report it as 6, but
+ * a sequence longer than 4 is deprecated by RFC 3629.
+ */
+#define KEY_NEEDSWIDE(sp, ch)						\
+	(INTISWIDE(ch) && KEY_LEN(sp, ch) <= 4)
+#define KEY_COL(sp, ch)							\
+	(KEY_NEEDSWIDE(sp, ch) ? CHAR_WIDTH(sp, ch) : KEY_LEN(sp, ch))
+
+enum { IC_FE_CHAR2INT, IC_FE_INT2CHAR, IC_IE_CHAR2INT, IC_IE_TO_UTF16 };
+
+struct _conv_win {
+	union {
+		char 	*c;
+		CHAR_T	*wc;
+	}	bp1;
+	size_t	blen1;
+};
+
+typedef int (*char2wchar_t) 
+    (SCR *, const char *, ssize_t, struct _conv_win *, size_t *, CHAR_T **);
+typedef int (*wchar2char_t) 
+    (SCR *, const CHAR_T *, ssize_t, struct _conv_win *, size_t *, char **);
+
+struct _conv {
+	char2wchar_t	sys2int;
+	wchar2char_t	int2sys;
+	char2wchar_t	file2int;
+	wchar2char_t	int2file;
+	char2wchar_t	input2int;
+	iconv_t		id[IC_IE_TO_UTF16 + 1];
+};


Property changes on: trunk/contrib/nvi/common/conv.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Modified: trunk/contrib/nvi/common/cut.c
===================================================================
--- trunk/contrib/nvi/common/cut.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/common/cut.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -10,7 +10,7 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)cut.c	10.10 (Berkeley) 9/15/96";
+static const char sccsid[] = "$Id: cut.c,v 10.12 2012/02/11 15:52:33 zy Exp $";
 #endif /* not lint */
 
 #include <sys/types.h>
@@ -64,14 +64,15 @@
  * PUBLIC: int cut __P((SCR *, CHAR_T *, MARK *, MARK *, int));
  */
 int
-cut(sp, namep, fm, tm, flags)
-	SCR *sp;
-	CHAR_T *namep;
-	MARK *fm, *tm;
-	int flags;
+cut(
+	SCR *sp,
+	CHAR_T *namep,
+	MARK *fm,
+	MARK *tm,
+	int flags)
 {
 	CB *cbp;
-	CHAR_T name;
+	CHAR_T name = '\0';
 	recno_t lno;
 	int append, copy_one, copy_def;
 
@@ -100,19 +101,19 @@
 	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)) {
+		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 ((append = isupper(name))) {
 			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)) {
+	} 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;
@@ -127,26 +128,25 @@
 	if (cbp == NULL) {
 		CALLOC_RET(sp, cbp, CB *, 1, sizeof(CB));
 		cbp->name = name;
-		CIRCLEQ_INIT(&cbp->textq);
-		LIST_INSERT_HEAD(&sp->gp->cutq, cbp, q);
+		TAILQ_INIT(cbp->textq);
+		SLIST_INSERT_HEAD(sp->gp->cutq, cbp, q);
 	} else if (!append) {
-		text_lfree(&cbp->textq);
+		text_lfree(cbp->textq);
 		cbp->len = 0;
 		cbp->flags = 0;
 	}
 
 
-#define	ENTIRE_LINE	0
 	/* In line mode, it's pretty easy, just cut the lines. */
 	if (LF_ISSET(CUT_LINEMODE)) {
 		cbp->flags |= CB_LMODE;
 		for (lno = fm->lno; lno <= tm->lno; ++lno)
-			if (cut_line(sp, lno, 0, 0, cbp))
+			if (cut_line(sp, lno, 0, ENTIRE_LINE, cbp))
 				goto cut_line_err;
 	} else {
 		/*
-		 * Get the first line.  A length of 0 causes cut_line
-		 * to cut from the MARK to the end of the line.
+		 * 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))
@@ -180,7 +180,7 @@
 	return (0);
 
 cut_line_err:	
-	text_lfree(&cbp->textq);
+	text_lfree(cbp->textq);
 	cbp->len = 0;
 	cbp->flags = 0;
 	return (1);
@@ -191,45 +191,29 @@
  *	Rotate the numbered buffers up one.
  */
 static void
-cb_rotate(sp)
-	SCR *sp;
+cb_rotate(SCR *sp)
 {
-	CB *cbp, *del_cbp;
+	CB *cbp, *del_cbp = NULL, *pre_cbp = NULL;
 
-	del_cbp = NULL;
-	for (cbp = sp->gp->cutq.lh_first; cbp != NULL; cbp = cbp->q.le_next)
+	SLIST_FOREACH(cbp, sp->gp->cutq, q) {
 		switch(cbp->name) {
-		case '1':
-			cbp->name = '2';
+		case '1': case '2': case '3':
+		case '4': case '5': case '6':
+		case '7': case '8':
+			cbp->name += 1;
 			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':
+			if (cbp == SLIST_FIRST(sp->gp->cutq))
+				SLIST_REMOVE_HEAD(sp->gp->cutq, q);
+			else
+				SLIST_REMOVE_AFTER(pre_cbp, q);
 			del_cbp = cbp;
 			break;
 		}
+		pre_cbp = cbp;
+	}
 	if (del_cbp != NULL) {
-		LIST_REMOVE(del_cbp, q);
-		text_lfree(&del_cbp->textq);
+		text_lfree(del_cbp->textq);
 		free(del_cbp);
 	}
 }
@@ -241,15 +225,16 @@
  * PUBLIC: int cut_line __P((SCR *, recno_t, size_t, size_t, CB *));
  */
 int
-cut_line(sp, lno, fcno, clen, cbp)
-	SCR *sp;
-	recno_t lno;
-	size_t fcno, clen;
-	CB *cbp;
+cut_line(
+	SCR *sp,
+	recno_t lno,
+	size_t fcno,
+	size_t clen,
+	CB *cbp)
 {
 	TEXT *tp;
 	size_t len;
-	char *p;
+	CHAR_T *p;
 
 	/* Get the line. */
 	if (db_get(sp, lno, DBG_FATAL, &p, &len))
@@ -264,14 +249,14 @@
 	 * copy the portion we want, and reset the TEXT length.
 	 */
 	if (len != 0) {
-		if (clen == 0)
+		if (clen == ENTIRE_LINE)
 			clen = len - fcno;
-		memcpy(tp->lb, p + fcno, clen);
+		MEMCPY(tp->lb, p + fcno, clen);
 		tp->len = clen;
 	}
 
 	/* Append to the end of the cut buffer. */
-	CIRCLEQ_INSERT_TAIL(&cbp->textq, tp, q);
+	TAILQ_INSERT_TAIL(cbp->textq, tp, q);
 	cbp->len += tp->len;
 
 	return (0);
@@ -284,23 +269,22 @@
  * PUBLIC: void cut_close __P((GS *));
  */
 void
-cut_close(gp)
-	GS *gp;
+cut_close(GS *gp)
 {
 	CB *cbp;
 
 	/* Free cut buffer list. */
-	while ((cbp = gp->cutq.lh_first) != NULL) {
-		if (cbp->textq.cqh_first != (void *)&cbp->textq)
-			text_lfree(&cbp->textq);
-		LIST_REMOVE(cbp, q);
+	while ((cbp = SLIST_FIRST(gp->cutq)) != NULL) {
+		if (!TAILQ_EMPTY(cbp->textq))
+			text_lfree(cbp->textq);
+		SLIST_REMOVE_HEAD(gp->cutq, q);
 		free(cbp);
 	}
 
 	/* Free default cut storage. */
 	cbp = &gp->dcb_store;
-	if (cbp->textq.cqh_first != (void *)&cbp->textq)
-		text_lfree(&cbp->textq);
+	if (!TAILQ_EMPTY(cbp->textq))
+		text_lfree(cbp->textq);
 }
 
 /*
@@ -307,13 +291,14 @@
  * text_init --
  *	Allocate a new TEXT structure.
  *
- * PUBLIC: TEXT *text_init __P((SCR *, const char *, size_t, size_t));
+ * PUBLIC: TEXT *text_init __P((SCR *, const CHAR_T *, size_t, size_t));
  */
 TEXT *
-text_init(sp, p, len, total_len)
-	SCR *sp;
-	const char *p;
-	size_t len, total_len;
+text_init(
+	SCR *sp,
+	const CHAR_T *p,
+	size_t len,
+	size_t total_len)
 {
 	TEXT *tp;
 
@@ -321,7 +306,7 @@
 	if (tp == NULL)
 		return (NULL);
 	/* ANSI C doesn't define a call to malloc(3) for 0 bytes. */
-	if ((tp->lb_len = total_len) != 0) {
+	if ((tp->lb_len = total_len * sizeof(CHAR_T)) != 0) {
 		MALLOC(sp, tp->lb, CHAR_T *, tp->lb_len);
 		if (tp->lb == NULL) {
 			free(tp);
@@ -328,7 +313,7 @@
 			return (NULL);
 		}
 		if (p != NULL && len != 0)
-			memcpy(tp->lb, p, len);
+			MEMCPY(tp->lb, p, len);
 	}
 	tp->len = len;
 	return (tp);
@@ -341,13 +326,12 @@
  * PUBLIC: void text_lfree __P((TEXTH *));
  */
 void
-text_lfree(headp)
-	TEXTH *headp;
+text_lfree(TEXTH *headp)
 {
 	TEXT *tp;
 
-	while ((tp = headp->cqh_first) != (void *)headp) {
-		CIRCLEQ_REMOVE(headp, tp, q);
+	while ((tp = TAILQ_FIRST(headp)) != NULL) {
+		TAILQ_REMOVE(headp, tp, q);
 		text_free(tp);
 	}
 }
@@ -359,8 +343,7 @@
  * PUBLIC: void text_free __P((TEXT *));
  */
 void
-text_free(tp)
-	TEXT *tp;
+text_free(TEXT *tp)
 {
 	if (tp->lb != NULL)
 		free(tp->lb);

Modified: trunk/contrib/nvi/common/cut.h
===================================================================
--- trunk/contrib/nvi/common/cut.h	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/common/cut.h	2018-06-10 20:23:48 UTC (rev 10823)
@@ -6,16 +6,17 @@
  *
  * See the LICENSE file for redistribution information.
  *
- *	@(#)cut.h	10.5 (Berkeley) 4/3/96
+ *	$Id: cut.h,v 10.10 2012/02/11 15:52:33 zy Exp $
  */
 
 typedef struct _texth TEXTH;		/* TEXT list head structure. */
-CIRCLEQ_HEAD(_texth, _text);
+TAILQ_HEAD(_texth, _text);
 
 /* Cut buffers. */
 struct _cb {
-	LIST_ENTRY(_cb) q;		/* Linked list of cut buffers. */
-	TEXTH	 textq;			/* Linked list of TEXT structures. */
+	SLIST_ENTRY(_cb) q;		/* Linked list of cut buffers. */
+	TEXTH	 textq[1];		/* Linked list of TEXT structures. */
+	/* XXXX Needed ? Can non ascii-chars be cut buffer names ? */
 	CHAR_T	 name;			/* Cut buffer name. */
 	size_t	 len;			/* Total length of cut text. */
 
@@ -25,13 +26,15 @@
 
 /* Lines/blocks of text. */
 struct _text {				/* Text: a linked list of lines. */
-	CIRCLEQ_ENTRY(_text) q;		/* Linked list of text structures. */
-	char	*lb;			/* Line buffer. */
+	TAILQ_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. */
 	recno_t	 lno;			/* 1-N: file line. */
+
+#define	ENTIRE_LINE	((size_t)-1)	/* cno: end of the 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). */
@@ -65,8 +68,7 @@
 #define	CBNAME(sp, cbp, nch) {						\
 	CHAR_T L__name;							\
 	L__name = isupper(nch) ? tolower(nch) : (nch);			\
-	for (cbp = sp->gp->cutq.lh_first;				\
-	    cbp != NULL; cbp = cbp->q.le_next)				\
+	SLIST_FOREACH(cbp, sp->gp->cutq, q)				\
 		if (cbp->name == L__name)				\
 			break;						\
 }

Modified: trunk/contrib/nvi/common/delete.c
===================================================================
--- trunk/contrib/nvi/common/delete.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/common/delete.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -10,11 +10,12 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)delete.c	10.12 (Berkeley) 10/23/96";
+static const char sccsid[] = "$Id: delete.c,v 10.18 2012/02/11 15:52:33 zy Exp $";
 #endif /* not lint */
 
 #include <sys/types.h>
 #include <sys/queue.h>
+#include <sys/time.h>
 
 #include <bitstring.h>
 #include <errno.h>
@@ -32,14 +33,15 @@
  * PUBLIC: int del __P((SCR *, MARK *, MARK *, int));
  */
 int
-del(sp, fm, tm, lmode)
-	SCR *sp;
-	MARK *fm, *tm;
-	int lmode;
+del(
+	SCR *sp,
+	MARK *fm,
+	MARK *tm,
+	int lmode)
 {
 	recno_t lno;
 	size_t blen, len, nlen, tlen;
-	char *bp, *p;
+	CHAR_T *bp, *p;
 	int eof, rval;
 
 	bp = NULL;
@@ -66,7 +68,7 @@
 		if (tm->lno == lno) {
 			if (db_get(sp, lno, DBG_FATAL, &p, &len))
 				return (1);
-			eof = tm->cno >= len ? 1 : 0;
+			eof = tm->cno != ENTIRE_LINE && tm->cno >= len ? 1 : 0;
 		} else
 			eof = 1;
 		if (eof) {
@@ -80,8 +82,8 @@
 			}
 			if (db_get(sp, fm->lno, DBG_FATAL, &p, &len))
 				return (1);
-			GET_SPACE_RET(sp, bp, blen, fm->cno);
-			memcpy(bp, p, fm->cno);
+			GET_SPACE_RETW(sp, bp, blen, fm->cno);
+			MEMCPY(bp, p, fm->cno);
 			if (db_set(sp, fm->lno, bp, fm->cno))
 				return (1);
 			goto done;
@@ -92,10 +94,11 @@
 	if (tm->lno == fm->lno) {
 		if (db_get(sp, fm->lno, DBG_FATAL, &p, &len))
 			return (1);
-		GET_SPACE_RET(sp, bp, blen, len);
+		GET_SPACE_RETW(sp, bp, blen, len);
 		if (fm->cno != 0)
-			memcpy(bp, p, fm->cno);
-		memcpy(bp + fm->cno, p + (tm->cno + 1), len - (tm->cno + 1));
+			MEMCPY(bp, p, fm->cno);
+		MEMCPY(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;
@@ -110,8 +113,8 @@
 	if ((tlen = fm->cno) != 0) {
 		if (db_get(sp, fm->lno, DBG_FATAL, &p, NULL))
 			return (1);
-		GET_SPACE_RET(sp, bp, blen, tlen + 256);
-		memcpy(bp, p, tlen);
+		GET_SPACE_RETW(sp, bp, blen, tlen + 256);
+		MEMCPY(bp, p, tlen);
 	}
 
 	/* Copy the end partial line into place. */
@@ -130,11 +133,11 @@
 			goto err;
 		}
 		if (tlen == 0) {
-			GET_SPACE_RET(sp, bp, blen, nlen);
+			GET_SPACE_RETW(sp, bp, blen, nlen);
 		} else
-			ADD_SPACE_RET(sp, bp, blen, nlen);
+			ADD_SPACE_RETW(sp, bp, blen, nlen);
 
-		memcpy(bp + tlen, p + (tm->cno + 1), len - (tm->cno + 1));
+		MEMCPY(bp + tlen, p + (tm->cno + 1), len - (tm->cno + 1));
 		tlen += len - (tm->cno + 1);
 	}
 
@@ -155,6 +158,6 @@
 	if (0)
 err:		rval = 1;
 	if (bp != NULL)
-		FREE_SPACE(sp, bp, blen);
+		FREE_SPACEW(sp, bp, blen);
 	return (rval);
 }

Added: trunk/contrib/nvi/common/encoding.c
===================================================================
--- trunk/contrib/nvi/common/encoding.c	                        (rev 0)
+++ trunk/contrib/nvi/common/encoding.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -0,0 +1,230 @@
+/*-
+ * Copyright (c) 2011, 2012
+ *	Zhihao Yuan.  All rights reserved.
+ *
+ * See the LICENSE file for redistribution information.
+ */
+
+#ifndef lint
+static const char sccsid[] = "$Id: encoding.c,v 1.4 2011/12/13 19:40:52 zy Exp $";
+#endif /* not lint */
+
+#include <sys/types.h>
+
+int looks_utf8 __P((const char *, size_t));
+int looks_utf16 __P((const char *, size_t));
+int decode_utf8 __P((const char *));
+int decode_utf16 __P((const char *, int));
+
+#define F 0   /* character never appears in text */
+#define T 1   /* character appears in plain ASCII text */
+#define I 2   /* character appears in ISO-8859 text */
+#define X 3   /* character appears in non-ISO extended ASCII (Mac, IBM PC) */
+
+static char text_chars[256] = {
+	/*                  BEL BS HT LF    FF CR    */
+	F, F, F, F, F, F, F, T, T, T, T, F, T, T, F, F,  /* 0x0X */
+	/*                              ESC          */
+	F, F, F, F, F, F, F, F, F, F, F, T, F, F, F, F,  /* 0x1X */
+	T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,  /* 0x2X */
+	T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,  /* 0x3X */
+	T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,  /* 0x4X */
+	T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,  /* 0x5X */
+	T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,  /* 0x6X */
+	T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, F,  /* 0x7X */
+	/*            NEL                            */
+	X, X, X, X, X, T, X, X, X, X, X, X, X, X, X, X,  /* 0x8X */
+	X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,  /* 0x9X */
+	I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I,  /* 0xaX */
+	I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I,  /* 0xbX */
+	I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I,  /* 0xcX */
+	I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I,  /* 0xdX */
+	I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I,  /* 0xeX */
+	I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I   /* 0xfX */
+};
+
+/*
+ * looks_utf8 --
+ *  Decide whether some text looks like UTF-8. Returns:
+ *
+ *     -1: invalid UTF-8
+ *      0: uses odd control characters, so doesn't look like text
+ *      1: 7-bit text
+ *      2: definitely UTF-8 text (valid high-bit set bytes)
+ *
+ *  Based on RFC 3629. UTF-8 with BOM is not accepted.
+ *
+ * PUBLIC: int looks_utf8 __P((const char *, size_t));
+ */
+int
+looks_utf8(const char *ibuf, size_t nbytes)
+{
+	const u_char *buf = (u_char *)ibuf;
+	size_t i;
+	int n;
+	int gotone = 0, ctrl = 0;
+
+	for (i = 0; i < nbytes; i++) {
+		if ((buf[i] & 0x80) == 0) {	   /* 0xxxxxxx is plain ASCII */
+			/*
+			 * Even if the whole file is valid UTF-8 sequences,
+			 * still reject it if it uses weird control characters.
+			 */
+
+			if (text_chars[buf[i]] != T)
+				ctrl = 1;
+		} else if ((buf[i] & 0x40) == 0) { /* 10xxxxxx never 1st byte */
+			return -1;
+		} else {			   /* 11xxxxxx begins UTF-8 */
+			int following;
+
+			if ((buf[i] & 0x20) == 0)	/* 110xxxxx */
+				if (buf[i] > 0xC1)	/* C0, C1 */
+					following = 1;
+				else return -1;
+			else if ((buf[i] & 0x10) == 0)	/* 1110xxxx */
+				following = 2;
+			else if ((buf[i] & 0x08) == 0)	/* 11110xxx */
+				if (buf[i] < 0xF5)
+					following = 3;
+				else return -1;		/* F5, F6, F7 */
+			else
+				return -1;		/* F8~FF */
+
+			for (n = 0; n < following; n++) {
+				i++;
+				if (i >= nbytes)
+					goto done;
+
+				if (buf[i] & 0x40)	/* 10xxxxxx */
+					return -1;
+			}
+
+			gotone = 1;
+		}
+	}
+done:
+	return ctrl ? 0 : (gotone ? 2 : 1);
+}
+
+/*
+ * looks_utf16 --
+ *  Decide whether some text looks like UTF-16. Returns:
+ *
+ *      0: invalid UTF-16
+ *      1: Little-endian UTF-16
+ *      2: Big-endian UTF-16
+ *
+ * PUBLIC: int looks_utf16 __P((const char *, size_t));
+ */
+int
+looks_utf16(const char *ibuf, size_t nbytes)
+{
+	const u_char *buf = (u_char *)ibuf;
+	int bigend;
+	size_t i;
+	unsigned int c;
+	int bom;
+	int following = 0;
+
+	if (nbytes < 2)
+		return 0;
+
+	bom = buf[0] << 8 ^ buf[1];
+	if (bom == 0xFFFE)
+		bigend = 0;
+	else if (bom == 0xFEFF)
+		bigend = 1;
+	else
+		return 0;
+
+	for (i = 2; i + 1 < nbytes; i += 2) {
+		if (bigend)
+			c = buf[i] << 8 ^ buf[i + 1];
+		else
+			c = buf[i] ^ buf[i + 1] << 8;
+
+		if (!following)
+			if (c < 0xD800 || c > 0xDFFF)
+				if (c < 128 && text_chars[c] != T)
+					return 0;
+				else
+					following = 0;
+			else if (c > 0xDBFF)
+				return 0;
+			else {
+				following = 1;
+				continue;
+			}
+		else if (c < 0xDC00 || c > 0xDFFF)
+			return 0;
+	}
+
+	return 1 + bigend;
+}
+
+#undef F
+#undef T
+#undef I
+#undef X
+
+/*
+ * decode_utf8 --
+ *  Decode a UTF-8 character from byte string to Unicode.
+ *  Returns -1 if the first byte is a not UTF-8 leader.
+ *
+ *  Based on RFC 3629, but without error detection.
+ *
+ * PUBLIC: int decode_utf8 __P((const char *));
+ */
+int decode_utf8(const char *ibuf) {
+	const u_char *buf = (u_char *)ibuf;
+	int u = -1;
+
+	if ((buf[0] & 0x80) == 0)
+		u = buf[0];
+	else if ((buf[0] & 0x40) == 0);
+	else {
+		if ((buf[0] & 0x20) == 0)
+			u = (buf[0] ^ 0xC0) <<  6 ^ (buf[1] ^ 0x80);
+		else if ((buf[0] & 0x10) == 0)
+			u = (buf[0] ^ 0xE0) << 12 ^ (buf[1] ^ 0x80) <<  6
+			  ^ (buf[2] ^ 0x80);
+		else if (((buf[0] & 0x08) == 0))
+			u = (buf[0] ^ 0xF0) << 18 ^ (buf[1] ^ 0x80) << 12
+			  ^ (buf[2] ^ 0x80) <<  6 ^ (buf[3] ^ 0x80);
+	}
+	return u;
+}
+
+/*
+ * decode_utf16 --
+ *  Decode a UTF-16 character from byte string to Unicode.
+ *  Returns -1 if the first unsigned integer is invalid.
+ *
+ *  No error detection on supplementary bytes.
+ *
+ * PUBLIC: int decode_utf16 __P((const char *, int));
+ */
+int decode_utf16(const char* ibuf, int bigend) {
+	const u_char *buf = (u_char *)ibuf;
+	int u = -1;
+	unsigned int w1, w2;
+
+	if (bigend)
+		w1 = buf[0] << 8 ^ buf[1];
+	else
+		w1 = buf[0] ^ buf[1] << 8;
+
+	if (w1 < 0xD800 || w1 > 0xDFFF)
+		u = w1;
+	else if (w1 > 0xDBFF);
+	else {
+		if (bigend)
+			w2 = buf[2] << 8 ^ buf[3];
+		else
+			w2 = buf[2] ^ buf[3] << 8;
+		u = ((w1 ^ 0xD800) << 10 ^ (w2 ^ 0xDC00)) + 0x10000;
+	}
+	return u;
+}


Property changes on: trunk/contrib/nvi/common/encoding.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Modified: trunk/contrib/nvi/common/exf.c
===================================================================
--- trunk/contrib/nvi/common/exf.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/common/exf.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -5,23 +5,18 @@
  *	Keith Bostic.  All rights reserved.
  *
  * See the LICENSE file for redistribution information.
- *
  */
 
 #include "config.h"
 
 #ifndef lint
-#if 0
-static const char sccsid[] = "@(#)exf.c	10.49 (Berkeley) 10/10/96";
-#endif
-static const char rcsid[] = 
-  "$FreeBSD: src/contrib/nvi/common/exf.c,v 1.5 2001/10/26 08:25:32 jkh Exp $";
+static const char sccsid[] = "$Id: exf.c,v 10.62 2013/07/01 23:28:13 zy Exp $";
 #endif /* not lint */
 
-#include <sys/param.h>
-#include <sys/types.h>		/* XXX: param.h may not have included types.h */
+#include <sys/types.h>
 #include <sys/queue.h>
 #include <sys/stat.h>
+#include <sys/time.h>
 
 /*
  * We include <sys/file.h>, because the flock(2) and open(2) #defines
@@ -44,6 +39,7 @@
 
 static int	file_backup __P((SCR *, char *, char *));
 static void	file_cinit __P((SCR *));
+static void	file_encinit __P((SCR *));
 static void	file_comment __P((SCR *));
 static int	file_spath __P((SCR *, FREF *, struct stat *, int *));
 
@@ -60,12 +56,12 @@
  * vi now remembers the last location in any file that it has ever edited,
  * not just the previously edited file.
  *
- * PUBLIC: FREF *file_add __P((SCR *, CHAR_T *));
+ * PUBLIC: FREF *file_add __P((SCR *, char *));
  */
 FREF *
-file_add(sp, name)
-	SCR *sp;
-	CHAR_T *name;
+file_add(
+	SCR *sp,
+	char *name)
 {
 	GS *gp;
 	FREF *frp, *tfrp;
@@ -81,15 +77,12 @@
 	 */
 	gp = sp->gp;
 	if (name != NULL)
-		for (frp = gp->frefq.cqh_first;
-		    frp != (FREF *)&gp->frefq; frp = frp->q.cqe_next) {
+		TAILQ_FOREACH_SAFE(frp, gp->frefq, q, tfrp) {
 			if (frp->name == NULL) {
-				tfrp = frp->q.cqe_next;
-				CIRCLEQ_REMOVE(&gp->frefq, frp, q);
+				TAILQ_REMOVE(gp->frefq, frp, q);
 				if (frp->name != NULL)
 					free(frp->name);
 				free(frp);
-				frp = tfrp;
 				continue;
 			}
 			if (!strcmp(frp->name, name))
@@ -114,7 +107,7 @@
 	}
 
 	/* Append into the chain of file names. */
-	CIRCLEQ_INSERT_TAIL(&gp->frefq, frp, q);
+	TAILQ_INSERT_TAIL(gp->frefq, frp, q);
 
 	return (frp);
 }
@@ -128,18 +121,18 @@
  * PUBLIC: int file_init __P((SCR *, FREF *, char *, int));
  */
 int
-file_init(sp, frp, rcv_name, flags)
-	SCR *sp;
-	FREF *frp;
-	char *rcv_name;
-	int flags;
+file_init(
+	SCR *sp,
+	FREF *frp,
+	char *rcv_name,
+	int flags)
 {
 	EXF *ep;
-	RECNOINFO oinfo;
+	RECNOINFO oinfo = { 0 };
 	struct stat sb;
 	size_t psize;
 	int fd, exists, open_err, readonly;
-	char *oname, tname[MAXPATHLEN];
+	char *oname, *tname;
 
 	open_err = readonly = 0;
 
@@ -169,7 +162,7 @@
 	 */
 	CALLOC_RET(sp, ep, EXF *, 1, sizeof(EXF));
 	ep->c_lno = ep->c_nlines = OOBLNO;
-	ep->rcv_fd = ep->fcntl_fd = -1;
+	ep->rcv_fd = -1;
 	F_SET(ep, F_FIRSTMODIFY);
 
 	/*
@@ -187,11 +180,17 @@
 	 */
 	oname = frp->name;
 	if (LF_ISSET(FS_OPENERR) || oname == NULL || !exists) {
-		if (opts_empty(sp, O_DIRECTORY, 0))
+		struct stat sb;
+
+		if (opts_empty(sp, O_TMPDIR, 0))
 			goto err;
-		(void)snprintf(tname, sizeof(tname),
-		    "%s/vi.XXXXXXXXXX", O_STR(sp, O_DIRECTORY));
-		if ((fd = mkstemp(tname)) == -1) {
+		if ((tname =
+		    join(O_STR(sp, O_TMPDIR), "vi.XXXXXXXXXX")) == NULL) {
+			msgq(sp, M_SYSERR, NULL);
+			goto err;
+		}
+		if ((fd = mkstemp(tname)) == -1 || fstat(fd, &sb)) {
+			free(tname);
 			msgq(sp, M_SYSERR,
 			    "237|Unable to create temporary file");
 			goto err;
@@ -198,15 +197,13 @@
 		}
 		(void)close(fd);
 
-		if (frp->name == NULL)
+		frp->tname = tname;
+		if (frp->name == NULL) {
 			F_SET(frp, FR_TMPFILE);
-		if ((frp->tname = strdup(tname)) == NULL ||
-		    frp->name == NULL && (frp->name = strdup(tname)) == NULL) {
-			if (frp->tname != NULL)
-				free(frp->tname);
-			msgq(sp, M_SYSERR, NULL);
-			(void)unlink(tname);
-			goto err;
+			if ((frp->name = strdup(tname)) == NULL) {
+				msgq(sp, M_SYSERR, NULL);
+				goto err;
+			}
 		}
 		oname = frp->tname;
 		psize = 1024;
@@ -213,26 +210,26 @@
 		if (!LF_ISSET(FS_OPENERR))
 			F_SET(frp, FR_NEWFILE);
 
-		time(&ep->mtime);
+		ep->mtim = sb.st_mtimespec;
 	} else {
 		/*
 		 * XXX
 		 * A seat of the pants calculation: try to keep the file in
-		 * 15 pages or less.  Don't use a page size larger than 10K
+		 * 15 pages or less.  Don't use a page size larger than 16K
 		 * (vi should have good locality) or smaller than 1K.
 		 */
 		psize = ((sb.st_size / 15) + 1023) / 1024;
-		if (psize > 10)
-			psize = 10;
+		if (psize > 16)
+			psize = 16;
 		if (psize == 0)
 			psize = 1;
-		psize *= 1024;
+		psize = p2roundup(psize) << 10;
 
 		F_SET(ep, F_DEVSET);
 		ep->mdev = sb.st_dev;
 		ep->minode = sb.st_ino;
 
-		ep->mtime = sb.st_mtime;
+		ep->mtim = sb.st_mtimespec;
 
 		if (!S_ISREG(sb.st_mode))
 			msgq_str(sp, M_ERR, oname,
@@ -240,7 +237,6 @@
 	}
 
 	/* Set up recovery. */
-	memset(&oinfo, 0, sizeof(RECNOINFO));
 	oinfo.bval = '\n';			/* Always set. */
 	oinfo.psize = psize;
 	oinfo.flags = F_ISSET(sp->gp, G_SNAPSHOT) ? R_SNAPSHOT : 0;
@@ -338,8 +334,7 @@
 	 * an error.
 	 */
 	if (rcv_name == NULL)
-		switch (file_lock(sp, oname,
-		    &ep->fcntl_fd, ep->db->fd(ep->db), 0)) {
+		switch (file_lock(sp, oname, ep->db->fd(ep->db), 0)) {
 		case LOCK_FAILED:
 			F_SET(frp, FR_UNLOCKED);
 			break;
@@ -396,9 +391,9 @@
 	 * probably isn't a problem for vi when it's running standalone.
 	 */
 	if (readonly || F_ISSET(sp, SC_READONLY) ||
-	    !F_ISSET(frp, FR_NEWFILE) &&
+	    (!F_ISSET(frp, FR_NEWFILE) &&
 	    (!(sb.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)) ||
-	    access(frp->name, W_OK)))
+	    access(frp->name, W_OK))))
 		O_SET(sp, O_READONLY);
 	else
 		O_CLR(sp, O_READONLY);
@@ -408,6 +403,9 @@
 	sp->ep = ep;
 	sp->frp = frp;
 
+	/* Detect and set the file encoding */
+	file_encinit(sp);
+
 	/* Set the initial cursor position, queue initial command. */
 	file_cinit(sp);
 
@@ -446,16 +444,16 @@
  *	try and open.
  */
 static int
-file_spath(sp, frp, sbp, existsp)
-	SCR *sp;
-	FREF *frp;
-	struct stat *sbp;
-	int *existsp;
+file_spath(
+	SCR *sp,
+	FREF *frp,
+	struct stat *sbp,
+	int *existsp)
 {
-	CHAR_T savech;
+	int savech;
 	size_t len;
 	int found;
-	char *name, *p, *t, path[MAXPATHLEN];
+	char *name, *p, *t, *path;
 
 	/*
 	 * If the name is NULL or an explicit reference (i.e., the first
@@ -466,8 +464,8 @@
 		*existsp = 0;
 		return (0);
 	}
-	if (name[0] == '/' || name[0] == '.' &&
-	    (name[1] == '/' || name[1] == '.' && name[2] == '/')) {
+	if (name[0] == '/' || (name[0] == '.' &&
+	    (name[1] == '/' || (name[1] == '.' && name[2] == '/')))) {
 		*existsp = !stat(name, sbp);
 		return (0);
 	}
@@ -481,16 +479,24 @@
 	/* Try the O_PATH option values. */
 	for (found = 0, p = t = O_STR(sp, O_PATH);; ++p)
 		if (*p == ':' || *p == '\0') {
-			if (t < p - 1) {
+			/*
+			 * Ignore the empty strings and ".", since we've already
+			 * tried the current directory.
+			 */
+			if (t < p && (p - t != 1 || *t != '.')) {
 				savech = *p;
 				*p = '\0';
-				len = snprintf(path,
-				    sizeof(path), "%s/%s", t, name);
+				if ((path = join(t, name)) == NULL) {
+					msgq(sp, M_SYSERR, NULL);
+					break;
+				}
+				len = strlen(path);
 				*p = savech;
 				if (!stat(path, sbp)) {
 					found = 1;
 					break;
 				}
+				free(path);
 			}
 			t = p + 1;
 			if (*p == '\0')
@@ -499,10 +505,8 @@
 
 	/* If we found it, build a new pathname and discard the old one. */
 	if (found) {
-		MALLOC_RET(sp, p, char *, len + 1);
-		memcpy(p, path, len + 1);
 		free(frp->name);
-		frp->name = p;
+		frp->name = path;
 	}
 	*existsp = found;
 	return (0);
@@ -513,13 +517,14 @@
  *	Set up the initial cursor position.
  */
 static void
-file_cinit(sp)
-	SCR *sp;
+file_cinit(SCR *sp)
 {
 	GS *gp;
 	MARK m;
 	size_t len;
 	int nb;
+	CHAR_T *wp;
+	size_t wlen;
 
 	/* Set some basic defaults. */
 	sp->lno = 1;
@@ -553,8 +558,9 @@
 			sp->lno = 1;
 			sp->cno = 0;
 		}
-		if (ex_run_str(sp,
-		    "-c option", gp->c_option, strlen(gp->c_option), 1, 1))
+		CHAR2INT(sp, gp->c_option, strlen(gp->c_option) + 1,
+			 wp, wlen);
+		if (ex_run_str(sp, "-c option", wp, wlen - 1, 1, 1))
 			return;
 		gp->c_option = NULL;
 	} else if (F_ISSET(sp, SC_EX)) {
@@ -622,10 +628,10 @@
  * PUBLIC: int file_end __P((SCR *, EXF *, int));
  */
 int
-file_end(sp, ep, force)
-	SCR *sp;
-	EXF *ep;
-	int force;
+file_end(
+	SCR *sp,
+	EXF *ep,
+	int force)
 {
 	FREF *frp;
 
@@ -670,7 +676,7 @@
 		free(frp->tname);
 		frp->tname = NULL;
 		if (F_ISSET(frp, FR_TMPFILE)) {
-			CIRCLEQ_REMOVE(&sp->gp->frefq, frp, q);
+			TAILQ_REMOVE(sp->gp->frefq, frp, q);
 			if (frp->name != NULL)
 				free(frp->name);
 			free(frp);
@@ -712,8 +718,6 @@
 		if (ep->rcv_mpath != NULL && unlink(ep->rcv_mpath))
 			msgq_str(sp, M_SYSERR, ep->rcv_mpath, "243|%s: remove");
 	}
-	if (ep->fcntl_fd != -1)
-		(void)close(ep->fcntl_fd);
 	if (ep->rcv_fd != -1)
 		(void)close(ep->rcv_fd);
 	if (ep->rcv_path != NULL)
@@ -720,6 +724,8 @@
 		free(ep->rcv_path);
 	if (ep->rcv_mpath != NULL)
 		free(ep->rcv_mpath);
+	if (ep->c_blen > 0)
+		free(ep->c_lp);
 
 	free(ep);
 	return (0);
@@ -734,11 +740,12 @@
  * PUBLIC: int file_write __P((SCR *, MARK *, MARK *, char *, int));
  */
 int
-file_write(sp, fm, tm, name, flags)
-	SCR *sp;
-	MARK *fm, *tm;
-	char *name;
-	int flags;
+file_write(
+	SCR *sp,
+	MARK *fm,
+	MARK *tm,
+	char *name,
+	int flags)
 {
 	enum { NEWFILE, OLDFILE } mtype;
 	struct stat sb;
@@ -749,7 +756,7 @@
 	size_t len;
 	u_long nlno, nch;
 	int fd, nf, noname, oflags, rval;
-	char *p, *s, *t, buf[MAXPATHLEN + 64];
+	char *p, *s, *t, buf[1024];
 	const char *msgstr;
 
 	ep = sp->ep;
@@ -812,9 +819,9 @@
 		mtype = NEWFILE;
 	else {
 		if (noname && !LF_ISSET(FS_FORCE | FS_APPEND) &&
-		    (F_ISSET(ep, F_DEVSET) &&
-		    (sb.st_dev != ep->mdev || sb.st_ino != ep->minode) ||
-		    sb.st_mtime != ep->mtime)) {
+		    ((F_ISSET(ep, F_DEVSET) &&
+		    (sb.st_dev != ep->mdev || sb.st_ino != ep->minode)) ||
+		    timespeccmp(&sb.st_mtimespec, &ep->mtim, !=))) {
 			msgq_str(sp, M_ERR, name, LF_ISSET(FS_POSSIBLE) ?
 "250|%s: file modified more recently than this copy; use ! to override" :
 "251|%s: file modified more recently than this copy");
@@ -873,26 +880,11 @@
 	SIGUNBLOCK;
 
 	/* Try and get a lock. */
-	if (!noname && file_lock(sp, NULL, NULL, fd, 0) == LOCK_UNAVAIL)
+	if (!noname && file_lock(sp, NULL, fd, 0) == LOCK_UNAVAIL)
 		msgq_str(sp, M_ERR, name,
 		    "252|%s: write lock was unavailable");
 
-#if __linux__
 	/*
-	 * XXX
-	 * In libc 4.5.x, fdopen(fd, "w") clears the O_APPEND flag (if set).
-	 * 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.
-	 */
-	if (LF_ISSET(FS_APPEND) && lseek(fd, (off_t)0, SEEK_END) < 0) {
-		msgq(sp, M_SYSERR, name);
-		return (1);
-	}
-#endif
-
-	/*
 	 * Use stdio for buffering.
 	 *
 	 * XXX
@@ -925,13 +917,13 @@
 	 */
 	if (noname)
 		if (stat(name, &sb))
-			time(&ep->mtime);
+			timepoint_system(&ep->mtim);
 		else {
 			F_SET(ep, F_DEVSET);
 			ep->mdev = sb.st_dev;
 			ep->minode = sb.st_ino;
 
-			ep->mtime = sb.st_mtime;
+			ep->mtim = sb.st_mtimespec;
 		}
 
 	/*
@@ -1023,9 +1015,10 @@
  * recreate the file.  So, let's not risk it.
  */
 static int
-file_backup(sp, name, bname)
-	SCR *sp;
-	char *name, *bname;
+file_backup(
+	SCR *sp,
+	char *name,
+	char *bname)
 {
 	struct dirent *dp;
 	struct stat sb;
@@ -1035,6 +1028,10 @@
 	size_t blen;
 	int flags, maxnum, nr, num, nw, rfd, wfd, version;
 	char *bp, *estr, *p, *pct, *slash, *t, *wfname, buf[8192];
+	CHAR_T *wp;
+	size_t wlen;
+	size_t nlen;
+	char *d = NULL;
 
 	rfd = wfd = -1;
 	bp = estr = wfname = NULL;
@@ -1064,15 +1061,20 @@
 	 *
 	 * Shell and file name expand the option's value.
 	 */
-	argv_init(sp, &cmd);
-	ex_cinit(&cmd, 0, 0, 0, 0, 0, NULL);
+	ex_cinit(sp, &cmd, 0, 0, 0, 0, 0);
 	if (bname[0] == 'N') {
 		version = 1;
 		++bname;
 	} else
 		version = 0;
-	if (argv_exp2(sp, &cmd, bname, strlen(bname)))
+	CHAR2INT(sp, bname, strlen(bname), wp, wlen);
+	if ((wp = v_wstrdup(sp, wp, wlen)) == NULL)
 		return (1);
+	if (argv_exp2(sp, &cmd, wp, wlen)) {
+		free(wp);
+		return (1);
+	}
+	free(wp);
 
 	/*
 	 *  0 args: impossible.
@@ -1095,9 +1097,13 @@
 	 * by one.
 	 */
 	if (version) {
-		GET_SPACE_GOTO(sp, bp, blen, cmd.argv[0]->len * 2 + 50);
-		for (t = bp, slash = NULL,
-		    p = cmd.argv[0]->bp; p[0] != '\0'; *t++ = *p++)
+		GET_SPACE_GOTOC(sp, bp, blen, cmd.argv[0]->len * 2 + 50);
+		INT2CHAR(sp, cmd.argv[0]->bp, cmd.argv[0]->len + 1,
+			 p, nlen); 
+		d = strdup(p);
+		p = d;
+		for (t = bp, slash = NULL;
+		     p[0] != '\0'; *t++ = *p++)
 			if (p[0] == '%') {
 				if (p[1] != '%')
 					*t++ = '%';
@@ -1118,7 +1124,8 @@
 			p = slash + 1;
 		}
 		if (dirp == NULL) {
-			estr = cmd.argv[0]->bp;
+			INT2CHAR(sp, cmd.argv[0]->bp, cmd.argv[0]->len + 1,
+				estr, nlen);
 			goto err;
 		}
 
@@ -1132,7 +1139,8 @@
 		wfname = bp;
 	} else {
 		bp = NULL;
-		wfname = cmd.argv[0]->bp;
+		INT2CHAR(sp, cmd.argv[0]->bp, cmd.argv[0]->len + 1,
+			wfname, nlen);
 	}
 	
 	/* Open the backup file, avoiding lurkers. */
@@ -1192,6 +1200,8 @@
 	}
 	if (estr)
 		msgq_str(sp, M_SYSERR, estr, "%s");
+	if (d != NULL)
+		free(d);
 	if (bp != NULL)
 		FREE_SPACE(sp, bp, blen);
 	return (1);
@@ -1198,16 +1208,61 @@
 }
 
 /*
+ * file_encinit --
+ *	Read the first line and set the O_FILEENCODING.
+ */
+static void
+file_encinit(SCR *sp)
+{
+#if defined(USE_WIDECHAR) && defined(USE_ICONV)
+	size_t len;
+	char *p;
+	size_t blen = 0;
+	char buf[4096];	/* not need to be '\0'-terminated */
+	recno_t ln = 1;
+	EXF *ep;
+
+	ep = sp->ep;
+
+	while (!db_rget(sp, ln++, &p, &len)) {
+		if (blen + len > sizeof(buf))
+			len = sizeof(buf) - blen;
+		memcpy(buf + blen, p, len);
+		blen += len;
+		if (blen == sizeof(buf))
+			break;
+		else
+			buf[blen++] = '\n';
+	}
+
+	/*
+	 * Detect UTF-8 and fallback to the locale/preset encoding.
+	 *
+	 * XXX
+	 * A manually set O_FILEENCODING indicates the "fallback
+	 * encoding", but UTF-8, which can be safely detected, is not
+	 * inherited from the old screen.
+	 */
+	if (looks_utf8(buf, blen) > 1)
+		o_set(sp, O_FILEENCODING, OS_STRDUP, "utf-8", 0);
+	else if (!O_ISSET(sp, O_FILEENCODING) ||
+	    !strncasecmp(O_STR(sp, O_FILEENCODING), "utf-8", 5))
+		o_set(sp, O_FILEENCODING, OS_STRDUP, codeset(), 0);
+
+	conv_enc(sp, O_FILEENCODING, 0);
+#endif
+}
+
+/*
  * file_comment --
  *	Skip the first comment.
  */
 static void
-file_comment(sp)
-	SCR *sp;
+file_comment(SCR *sp)
 {
 	recno_t lno;
 	size_t len;
-	char *p;
+	CHAR_T *p;
 
 	for (lno = 1; !db_get(sp, lno, 0, &p, &len) && len == 0; ++lno);
 	if (p == NULL)
@@ -1250,9 +1305,10 @@
  * PUBLIC: int file_m1 __P((SCR *, int, int));
  */
 int
-file_m1(sp, force, flags)
-	SCR *sp;
-	int force, flags;
+file_m1(
+	SCR *sp,
+	int force,
+	int flags)
 {
 	EXF *ep;
 
@@ -1290,9 +1346,9 @@
  * PUBLIC: int file_m2 __P((SCR *, int));
  */
 int
-file_m2(sp, force)
-	SCR *sp;
-	int force;
+file_m2(
+	SCR *sp,
+	int force)
 {
 	EXF *ep;
 
@@ -1322,9 +1378,9 @@
  * PUBLIC: int file_m3 __P((SCR *, int));
  */
 int
-file_m3(sp, force)
-	SCR *sp;
-	int force;
+file_m3(
+	SCR *sp,
+	int force)
 {
 	EXF *ep;
 
@@ -1358,9 +1414,9 @@
  * PUBLIC: int file_aw __P((SCR *, int));
  */
 int
-file_aw(sp, flags)
-	SCR *sp;
-	int flags;
+file_aw(
+	SCR *sp,
+	int flags)
 {
 	if (!F_ISSET(sp->ep, F_MODIFIED))
 		return (0);
@@ -1419,9 +1475,9 @@
  * PUBLIC: void set_alt_name __P((SCR *, char *));
  */
 void
-set_alt_name(sp, name)
-	SCR *sp;
-	char *name;
+set_alt_name(
+	SCR *sp,
+	char *name)
 {
 	if (sp->alt_name != NULL)
 		free(sp->alt_name);
@@ -1435,35 +1491,18 @@
  * file_lock --
  *	Get an exclusive lock on a file.
  *
- * XXX
- * The default locking is flock(2) style, not fcntl(2).  The latter is
- * known to fail badly on some systems, and its only advantage is that
- * it occasionally works over NFS.
- *
- * Furthermore, the semantics of fcntl(2) are wrong.  The problems are
- * two-fold: you can't close any file descriptor associated with the file
- * without losing all of the locks, and you can't get an exclusive lock
- * unless you have the file open for writing.  Someone ought to be shot,
- * but it's probably too late, they may already have reproduced.  To get
- * around these problems, nvi opens the files for writing when it can and
- * acquires a second file descriptor when it can't.  The recovery files
- * are examples of the former, they're always opened for writing.  The DB
- * files can't be opened for writing because the semantics of DB are that
- * files opened for writing are flushed back to disk when the DB session
- * is ended. So, in that case we have to acquire an extra file descriptor.
- *
- * PUBLIC: lockr_t file_lock __P((SCR *, char *, int *, int, int));
+ * PUBLIC: lockr_t file_lock __P((SCR *, char *, int, int));
  */
 lockr_t
-file_lock(sp, name, fdp, fd, iswrite)
-	SCR *sp;
-	char *name;
-	int *fdp, fd, iswrite;
+file_lock(
+	SCR *sp,
+	char *name,
+	int fd,
+	int iswrite)
 {
 	if (!O_ISSET(sp, O_LOCKFILES))
 		return (LOCK_SUCCESS);
 	
-#ifdef HAVE_LOCK_FLOCK			/* Hurrah!  We've got flock(2). */
 	/*
 	 * !!!
 	 * We need to distinguish a lock not being available for the file
@@ -1481,59 +1520,4 @@
 	    || errno == EWOULDBLOCK
 #endif
 	    ? LOCK_UNAVAIL : LOCK_FAILED);
-#endif
-#ifdef HAVE_LOCK_FCNTL			/* Gag me.  We've got fcntl(2). */
-{
-	struct flock arg;
-	int didopen, sverrno;
-
-	arg.l_type = F_WRLCK;
-	arg.l_whence = 0;		/* SEEK_SET */
-	arg.l_start = arg.l_len = 0;
-	arg.l_pid = 0;
-
-	/*
-	 * If the file descriptor isn't opened for writing, it must fail.
-	 * If we fail because we can't get a read/write file descriptor,
-	 * we return LOCK_SUCCESS, believing that the file is readonly
-	 * and that will be sufficient to warn the user.
-	 */
-	if (!iswrite) {
-		if (name == NULL || fdp == NULL)
-			return (LOCK_FAILED);
-		if ((fd = open(name, O_RDWR, 0)) == -1)
-			return (LOCK_SUCCESS);
-		*fdp = fd;
-		didopen = 1;
-	}
-
-	errno = 0;
-	if (!fcntl(fd, F_SETLK, &arg)) {
-		fcntl(fd, F_SETFD, 1);
-		return (LOCK_SUCCESS);
-	}
-
-	if (didopen) {
-		sverrno = errno;
-		(void)close(fd);
-		errno = sverrno;
-	}
-
-	/*
-	 * !!!
-	 * We need to distinguish a lock not being available for the file
-	 * from the file system not supporting locking.  Fcntl is documented
-	 * as returning EACCESS and EAGAIN; add EWOULDBLOCK for good measure,
-	 * and assume they are the former.  There's no portable way to do this.
-	 */
-	return (errno == EACCES || errno == EAGAIN
-#ifdef EWOULDBLOCK
-	|| errno == EWOULDBLOCK
-#endif
-	?  LOCK_UNAVAIL : LOCK_FAILED);
 }
-#endif
-#if !defined(HAVE_LOCK_FLOCK) && !defined(HAVE_LOCK_FCNTL)
-	return (LOCK_SUCCESS);
-#endif
-}

Modified: trunk/contrib/nvi/common/exf.h
===================================================================
--- trunk/contrib/nvi/common/exf.h	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/common/exf.h	2018-06-10 20:23:48 UTC (rev 10823)
@@ -6,7 +6,7 @@
  *
  * See the LICENSE file for redistribution information.
  *
- *	@(#)exf.h	10.7 (Berkeley) 7/9/96
+ *	$Id: exf.h,v 10.10 2012/07/06 16:03:37 zy Exp $
  */
 					/* Undo direction. */
 /*
@@ -18,8 +18,9 @@
 
 					/* Underlying database state. */
 	DB	*db;			/* File db structure. */
-	char	*c_lp;			/* Cached line. */
+	CHAR_T	*c_lp;			/* Cached line. */
 	size_t	 c_len;			/* Cached line length. */
+	size_t	 c_blen;		/* Cached line buffer length. */
 	recno_t	 c_lno;			/* Cached line number. */
 	recno_t	 c_nlines;		/* Cached lines in the file. */
 
@@ -31,18 +32,13 @@
 	MARK	 l_cursor;		/* Log cursor position. */
 	dir_t	 lundo;			/* Last undo direction. */
 
-	LIST_HEAD(_markh, _lmark) marks;/* Linked list of file MARK's. */
+					/* Linked list of file MARK's. */
+	SLIST_HEAD(_markh, _lmark) marks[1];
 
-	/*
-	 * 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. */
+	dev_t		 mdev;		/* Device. */
+	ino_t		 minode;	/* Inode. */
+	struct timespec	 mtim;		/* Last modification time. */
 
-	int	 fcntl_fd;		/* Fcntl locking fd; see exf.c. */
-
 	/*
 	 * Recovery in general, and these fields specifically, are described
 	 * in recover.c.

Added: trunk/contrib/nvi/common/extern.h
===================================================================
--- trunk/contrib/nvi/common/extern.h	                        (rev 0)
+++ trunk/contrib/nvi/common/extern.h	2018-06-10 20:23:48 UTC (rev 10823)
@@ -0,0 +1,132 @@
+char * codeset __P((void));
+void conv_init __P((SCR *, SCR *));
+int conv_enc __P((SCR *, int, char *));
+void conv_end __P((SCR *));
+int cut __P((SCR *, CHAR_T *, MARK *, MARK *, int));
+int cut_line __P((SCR *, recno_t, size_t, size_t, CB *));
+void cut_close __P((GS *));
+TEXT *text_init __P((SCR *, const CHAR_T *, size_t, size_t));
+void text_lfree __P((TEXTH *));
+void text_free __P((TEXT *));
+int del __P((SCR *, MARK *, MARK *, int));
+int looks_utf8 __P((const char *, size_t));
+int looks_utf16 __P((const char *, size_t));
+int decode_utf8 __P((const char *));
+int decode_utf16 __P((const char *, int));
+FREF *file_add __P((SCR *, 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 *, char *));
+lockr_t file_lock __P((SCR *, char *, int, int));
+int v_key_init __P((SCR *));
+void v_key_ilookup __P((SCR *));
+size_t v_key_len __P((SCR *, ARG_CHAR_T));
+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 *, 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 db_eget __P((SCR *, recno_t, CHAR_T **, size_t *, int *));
+int db_get __P((SCR *, recno_t, u_int32_t, CHAR_T **, size_t *));
+int db_delete __P((SCR *, recno_t));
+int db_append __P((SCR *, int, recno_t, CHAR_T *, size_t));
+int db_insert __P((SCR *, recno_t, CHAR_T *, size_t));
+int db_set __P((SCR *, recno_t, CHAR_T *, size_t));
+int db_exist __P((SCR *, recno_t));
+int db_last __P((SCR *, recno_t *));
+int db_rget __P((SCR *, recno_t, char **, size_t *));
+int db_rset __P((SCR *, recno_t, char *, size_t));
+void db_err __P((SCR *, recno_t));
+int log_init __P((SCR *, EXF *));
+int log_end __P((SCR *, EXF *));
+int log_cursor __P((SCR *));
+int log_line __P((SCR *, 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((GS *, int, char *[]));
+void v_end __P((GS *));
+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, recno_t));
+void msgq __P((SCR *, mtype_t, const char *, ...));
+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 *, recno_t, u_int));
+int msg_open __P((SCR *, 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 *));
+int opts_init __P((SCR *, int *));
+int opts_set __P((SCR *, ARGS *[], char *));
+int o_set __P((SCR *, int, u_int, 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((CHAR_T *));
+void opts_nomatch __P((SCR *, CHAR_T *));
+int opts_copy __P((SCR *, SCR *));
+void opts_free __P((SCR *));
+int f_altwerase __P((SCR *, OPTION *, char *, u_long *));
+int f_columns __P((SCR *, OPTION *, char *, u_long *));
+int f_lines __P((SCR *, OPTION *, char *, u_long *));
+int f_lisp __P((SCR *, OPTION *, char *, u_long *));
+int f_msgcat __P((SCR *, OPTION *, char *, u_long *));
+int f_print __P((SCR *, OPTION *, char *, u_long *));
+int f_readonly __P((SCR *, OPTION *, char *, u_long *));
+int f_recompile __P((SCR *, OPTION *, char *, u_long *));
+int f_reformat __P((SCR *, OPTION *, char *, u_long *));
+int f_ttywerase __P((SCR *, OPTION *, char *, u_long *));
+int f_w300 __P((SCR *, OPTION *, char *, u_long *));
+int f_w1200 __P((SCR *, OPTION *, char *, u_long *));
+int f_w9600 __P((SCR *, OPTION *, char *, u_long *));
+int f_window __P((SCR *, OPTION *, char *, u_long *));
+int f_encoding __P((SCR *, OPTION *, char *, u_long *));
+int put __P((SCR *, CB *, 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_free __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 *, char *, seq_t));
+int e_memcmp __P((CHAR_T *, EVENT *, size_t));
+void *binc __P((SCR *, void *, size_t *, size_t));
+int nonblank __P((SCR *, recno_t, size_t *));
+char *tail __P((char *));
+char *join __P((char *, char *));
+char *expanduser __P((char *));
+char *quote __P((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((u_long *, const CHAR_T *, CHAR_T **, int));
+enum nresult nget_slong __P((long *, const CHAR_T *, CHAR_T **, int));
+void timepoint_steady __P((struct timespec *));
+void timepoint_system __P((struct timespec *));
+void TRACE __P((SCR *, const char *, ...));


Property changes on: trunk/contrib/nvi/common/extern.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Modified: trunk/contrib/nvi/common/gs.h
===================================================================
--- trunk/contrib/nvi/common/gs.h	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/common/gs.h	2018-06-10 20:23:48 UTC (rev 10823)
@@ -6,11 +6,13 @@
  *
  * See the LICENSE file for redistribution information.
  *
- *	@(#)gs.h	10.34 (Berkeley) 9/24/96
+ *	$Id: gs.h,v 11.0 2012/10/17 06:34:37 zy Exp $
  */
 
 #define	TEMPORARY_FILE_STRING	"/tmp"	/* Default temporary file name. */
 
+#include <nl_types.h>
+
 /*
  * File reference structure (FREF).  The structure contains the name of the
  * file, along with the information that follows the name.
@@ -19,7 +21,7 @@
  * The read-only bit follows the file name, not the file itself.
  */
 struct _fref {
-	CIRCLEQ_ENTRY(_fref) q;		/* Linked list of file references. */
+	TAILQ_ENTRY(_fref) q;		/* Linked list of file references. */
 	char	*name;			/* File name. */
 	char	*tname;			/* Backing temporary file name. */
 
@@ -56,20 +58,15 @@
 	char	*progname;		/* Programe name. */
 
 	int	 id;			/* Last allocated screen id. */
-	CIRCLEQ_HEAD(_dqh, _scr) dq;	/* Displayed screens. */
-	CIRCLEQ_HEAD(_hqh, _scr) hq;	/* Hidden screens. */
+	TAILQ_HEAD(_dqh, _scr) dq[1];	/* Displayed screens. */
+	TAILQ_HEAD(_hqh, _scr) hq[1];	/* Hidden screens. */
 
 	SCR	*ccl_sp;		/* Colon command-line screen. */
 
-	void	*perl_interp;		/* Perl interpreter. */
-	void	*tcl_interp;		/* Tcl_Interp *: Tcl interpreter. */
-
 	void	*cl_private;		/* Curses support private area. */
-	void	*ip_private;		/* IP support private area. */
-	void	*tk_private;		/* Tk/Tcl support private area. */
 
 					/* File references. */
-	CIRCLEQ_HEAD(_frefh, _fref) frefq;
+	TAILQ_HEAD(_frefh, _fref) frefq[1];
 
 #define	GO_COLUMNS	0		/* Global options: columns. */
 #define	GO_LINES	1		/* Global options: lines. */
@@ -77,10 +74,10 @@
 #define	GO_TERM		3		/* Global options: terminal type. */
 	OPTION	 opts[GO_TERM + 1];
 
-	DB	*msg;			/* Message catalog DB. */
-	MSGH	 msgq;			/* User message list. */
+	nl_catd	 catd;			/* Message catalog descriptor. */
+	MSGH	 msgq[1];		/* User message list. */
 #define	DEFAULT_NOPRINT	'\1'		/* Emergency non-printable character. */
-	CHAR_T	 noprint;		/* Cached, unprintable character. */
+	int	 noprint;		/* Cached, unprintable character. */
 
 	char	*tmp_bp;		/* Temporary buffer. */
 	size_t	 tmp_blen;		/* Temporary buffer size. */
@@ -89,8 +86,9 @@
 	 * Ex command structures (EXCMD).  Defined here because ex commands
 	 * exist outside of any particular screen or file.
 	 */
-#define	EXCMD_RUNNING(gp)	((gp)->ecq.lh_first->clen != 0)
-	LIST_HEAD(_excmdh, _excmd) ecq;	/* Ex command linked list. */
+#define	EXCMD_RUNNING(gp)	(SLIST_FIRST((gp)->ecq)->clen != 0)
+					/* Ex command linked list. */
+	SLIST_HEAD(_excmdh, _excmd) ecq[1];
 	EXCMD	 excmd;			/* Default ex command structure. */
 	char	 *if_name;		/* Current associated file. */
 	recno_t	  if_lno;		/* Current associated line number. */
@@ -108,30 +106,28 @@
 
 	CB	*dcbp;			/* Default cut buffer pointer. */
 	CB	 dcb_store;		/* Default cut buffer storage. */
-	LIST_HEAD(_cuth, _cb) cutq;	/* Linked list of cut buffers. */
+	SLIST_HEAD(_cuth, _cb) cutq[1];	/* Linked list of cut buffers. */
 
-#define	MAX_BIT_SEQ	128		/* Max + 1 fast check character. */
-	LIST_HEAD(_seqh, _seq) seqq;	/* Linked list of maps, abbrevs. */
-	bitstr_t bit_decl(seqb, MAX_BIT_SEQ);
+#define	MAX_BIT_SEQ	0x7f		/* Max + 1 fast check character. */
+	SLIST_HEAD(_seqh, _seq) seqq[1];/* Linked list of maps, abbrevs. */
+	bitstr_t bit_decl(seqb, MAX_BIT_SEQ + 1);
 
-#define	MAX_FAST_KEY	254		/* Max fast check character.*/
+#define	MAX_FAST_KEY	0xff		/* Max fast check character.*/
 #define	KEY_LEN(sp, ch)							\
-	((unsigned char)(ch) <= MAX_FAST_KEY ?				\
+	(((ch) & ~MAX_FAST_KEY) == 0 ?					\
 	    sp->gp->cname[(unsigned char)ch].len : v_key_len(sp, ch))
 #define	KEY_NAME(sp, ch)						\
-	((unsigned char)(ch) <= MAX_FAST_KEY ?				\
+	(((ch) & ~MAX_FAST_KEY) == 0 ?					\
 	    sp->gp->cname[(unsigned char)ch].name : v_key_name(sp, ch))
 	struct {
-		CHAR_T	 name[MAX_CHARACTER_COLUMNS + 1];
+		char	 name[MAX_CHARACTER_COLUMNS + 1];
 		u_int8_t len;
 	} cname[MAX_FAST_KEY + 1];	/* Fast lookup table. */
 
 #define	KEY_VAL(sp, ch)							\
-	((unsigned char)(ch) <= MAX_FAST_KEY ? 				\
-	    sp->gp->special_key[(unsigned char)ch] :			\
-	    (unsigned char)(ch) > sp->gp->max_special ? 0 : v_key_val(sp,ch))
-	CHAR_T	 max_special;		/* Max special character. */
-	u_char				/* Fast lookup table. */
+	(((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. */
@@ -149,6 +145,8 @@
 	/* 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. */
@@ -157,6 +155,8 @@
 	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. */
@@ -163,6 +163,8 @@
 	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. */
@@ -183,8 +185,12 @@
 	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. */

Modified: trunk/contrib/nvi/common/key.c
===================================================================
--- trunk/contrib/nvi/common/key.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/common/key.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -10,7 +10,7 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)key.c	10.33 (Berkeley) 9/24/96";
+static const char sccsid[] = "$Id: key.c,v 10.54 2013/11/13 12:15:27 zy Exp $";
 #endif /* not lint */
 
 #include <sys/types.h>
@@ -21,10 +21,10 @@
 #include <ctype.h>
 #include <errno.h>
 #include <limits.h>
-#include <locale.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <strings.h>
 #include <unistd.h>
 
 #include "common.h"
@@ -100,10 +100,9 @@
  * PUBLIC: int v_key_init __P((SCR *));
  */
 int
-v_key_init(sp)
-	SCR *sp;
+v_key_init(SCR *sp)
 {
-	CHAR_T ch;
+	int ch;
 	GS *gp;
 	KEYLIST *kp;
 	int cnt;
@@ -110,22 +109,6 @@
 
 	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);
@@ -137,15 +120,11 @@
 	qsort(keylist, nkeylist, sizeof(keylist[0]), v_key_cmp);
 
 	/* Initialize the fast lookup table. */
-	for (gp->max_special = 0, kp = keylist, cnt = nkeylist; cnt--; ++kp) {
-		if (gp->max_special < kp->value)
-			gp->max_special = kp->value;
-		if (kp->ch <= MAX_FAST_KEY)
-			gp->special_key[kp->ch] = kp->value;
-	}
+	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 <= MAX_CHAR_T; ++ch)
+	for (ch = 1; ch <= UCHAR_MAX; ++ch)
 		if (!isprint(ch)) {
 			gp->noprint = ch;
 			break;
@@ -166,10 +145,10 @@
  * in the table, so we check for that first.
  */
 static void
-v_keyval(sp, val, name)
-	SCR *sp;
-	int val;
-	scr_keyval_t name;
+v_keyval(
+	SCR *sp,
+	int val,
+	scr_keyval_t name)
 {
 	KEYLIST *kp;
 	CHAR_T ch;
@@ -203,17 +182,20 @@
  * PUBLIC: void v_key_ilookup __P((SCR *));
  */
 void
-v_key_ilookup(sp)
-	SCR *sp;
+v_key_ilookup(SCR *sp)
 {
-	CHAR_T ch, *p, *t;
+	UCHAR_T ch;
+	char *p, *t;
 	GS *gp;
 	size_t len;
 
-	for (gp = sp->gp, ch = 0; ch <= MAX_FAST_KEY; ++ch)
+	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;
+	}
 }
 
 /*
@@ -224,9 +206,9 @@
  * PUBLIC: size_t v_key_len __P((SCR *, ARG_CHAR_T));
  */
 size_t
-v_key_len(sp, ch)
-	SCR *sp;
-	ARG_CHAR_T ch;
+v_key_len(
+	SCR *sp,
+	ARG_CHAR_T ch)
 {
 	(void)v_key_name(sp, ch);
 	return (sp->clen);
@@ -237,30 +219,43 @@
  *	Return the string that will display the key.  This routine
  *	is the backup for the KEY_NAME() macro.
  *
- * PUBLIC: CHAR_T *v_key_name __P((SCR *, ARG_CHAR_T));
+ * PUBLIC: char *v_key_name __P((SCR *, ARG_CHAR_T));
  */
-CHAR_T *
-v_key_name(sp, ach)
-	SCR *sp;
-	ARG_CHAR_T ach;
+char *
+v_key_name(
+	SCR *sp,
+	ARG_CHAR_T ach)
 {
-	static const CHAR_T hexdigit[] = "0123456789abcdef";
-	static const CHAR_T octdigit[] = "01234567";
-	CHAR_T ch, *chp, mask;
+	static const char hexdigit[] = "0123456789abcdef";
+	static const char octdigit[] = "01234567";
+	int ch;
 	size_t len;
-	int cnt, shift;
+	char *chp;
 
-	ch = ach;
+	/*
+	 * Cache the last checked character.  It won't be a problem
+	 * since nvi will rescan the mapping when settings changed.
+	 */
+	if (ach && sp->lastc == ach)
+		return (sp->cname);
+	sp->lastc = ach;
 
+#ifdef USE_WIDECHAR
+	len = wctomb(sp->cname, ach);
+	if (len > MB_CUR_MAX)
+#endif
+		sp->cname[(len = 1)-1] = (u_char)ach;
+
+	ch = (u_char)sp->cname[0];
+	sp->cname[len] = '\0';
+
 	/* 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 (strstr(chp, sp->cname) != NULL)
+			goto done;
 	if ((chp = O_STR(sp, O_NOPRINT)) != NULL)
-		for (; *chp != '\0'; ++chp)
-			if (*chp == ch)
-				goto nopr;
+		if (strstr(chp, sp->cname) != NULL)
+			goto nopr;
 
 	/*
 	 * Historical (ARPA standard) mappings.  Printable characters are left
@@ -274,41 +269,55 @@
 	 * 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.
+	 * The code prints non-printable wide characters in 4 or 5 digits
+	 * Unicode escape sequences, so only supports plane 0 to 15.
 	 */
-	if (isprint(ch)) {
-pr:		sp->cname[0] = ch;
-		len = 1;
+	if (CAN_PRINT(sp, ach))
 		goto done;
-	}
 nopr:	if (iscntrl(ch) && (ch < 0x20 || ch == 0x7f)) {
 		sp->cname[0] = '^';
 		sp->cname[1] = ch == 0x7f ? '?' : '@' + ch;
 		len = 2;
-	} else if (O_ISSET(sp, O_OCTAL)) {
-#define	BITS	(sizeof(CHAR_T) * 8)
-#define	SHIFT	(BITS - BITS % 3)
-#define	TOPMASK	(BITS % 3 == 2 ? 3 : 1) << (BITS - BITS % 3)
+		goto done;
+	}
+#ifdef USE_WIDECHAR
+	if (INTISWIDE(ach)) {
+		int uc = -1;
+
+		if (!strcmp(codeset(), "UTF-8"))
+			uc = decode_utf8(sp->cname);
+#ifdef USE_ICONV
+		else {
+			char buf[sizeof(sp->cname)] = "";
+			size_t left = sizeof(sp->cname);
+			char *in = sp->cname;
+			char *out = buf;
+			iconv(sp->conv.id[IC_IE_TO_UTF16],
+			    (iconv_src_t)&in, &len, &out, &left);
+			iconv(sp->conv.id[IC_IE_TO_UTF16],
+			    NULL, NULL, NULL, NULL);
+			uc = decode_utf16(buf, 1);
+		}
+#endif
+		if (uc >= 0) {
+			len = snprintf(sp->cname, sizeof(sp->cname),
+			    uc < 0x10000 ? "\\u%04x" : "\\U%05X", uc);
+			goto done;
+		}
+	}
+#endif
+	if (O_ISSET(sp, O_OCTAL)) {
 		sp->cname[0] = '\\';
-		sp->cname[1] = octdigit[(ch & TOPMASK) >> SHIFT];
-		shift = SHIFT - 3;
-		for (len = 2, mask = 7 << (SHIFT - 3),
-		    cnt = BITS / 3; cnt-- > 0; mask >>= 3, shift -= 3)
-			sp->cname[len++] = octdigit[(ch & mask) >> shift];
+		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';
-		for (len = 2, chp = (u_int8_t *)&ch,
-		    cnt = sizeof(CHAR_T); cnt-- > 0; ++chp) {
-			sp->cname[len++] = hexdigit[(*chp & 0xf0) >> 4];
-			sp->cname[len++] = hexdigit[*chp & 0x0f];
-		}
+		sp->cname[2] = hexdigit[(ch & 0xf0) >> 4];
+		sp->cname[3] = hexdigit[ ch & 0x0f      ];
 	}
+	len = 4;
 done:	sp->cname[sp->clen = len] = '\0';
 	return (sp->cname);
 }
@@ -318,12 +327,12 @@
  *	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));
+ * PUBLIC: e_key_t v_key_val __P((SCR *, ARG_CHAR_T));
  */
-int
-v_key_val(sp, ch)
-	SCR *sp;
-	ARG_CHAR_T ch;
+e_key_t
+v_key_val(
+	SCR *sp,
+	ARG_CHAR_T ch)
 {
 	KEYLIST k, *kp;
 
@@ -345,12 +354,12 @@
  * PUBLIC: int v_event_push __P((SCR *, EVENT *, CHAR_T *, size_t, u_int));
  */
 int
-v_event_push(sp, p_evp, p_s, nitems, flags)
-	SCR *sp;
-	EVENT *p_evp;			/* Push event. */
-	CHAR_T *p_s;			/* Push characters. */
-	size_t nitems;			/* Number of items to push. */
-	u_int flags;			/* CH_* flags. */
+v_event_push(
+	SCR *sp,
+	EVENT *p_evp,			/* Push event. */
+	CHAR_T *p_s,			/* Push characters. */
+	size_t nitems,			/* Number of items to push. */
+	u_int flags)			/* CH_* flags. */
 {
 	EVENT *evp;
 	GS *gp;
@@ -375,8 +384,8 @@
 	if (total >= gp->i_nelem && v_event_grow(sp, MAX(total, 64)))
 		return (1);
 	if (gp->i_cnt)
-		MEMMOVE(gp->i_event + TERM_PUSH_SHIFT + nitems,
-		    gp->i_event + gp->i_next, gp->i_cnt);
+		BCOPY(gp->i_event + gp->i_next,
+		    gp->i_event + TERM_PUSH_SHIFT + nitems, gp->i_cnt);
 	gp->i_next = TERM_PUSH_SHIFT;
 
 	/* Put the new items into the queue. */
@@ -399,9 +408,9 @@
  *	Append events onto the tail of the buffer.
  */
 static int
-v_event_append(sp, argp)
-	SCR *sp;
-	EVENT *argp;
+v_event_append(
+	SCR *sp,
+	EVENT *argp)
 {
 	CHAR_T *s;			/* Characters. */
 	EVENT *evp;
@@ -526,11 +535,11 @@
  * PUBLIC: int v_event_get __P((SCR *, EVENT *, int, u_int32_t));
  */
 int
-v_event_get(sp, argp, timeout, flags)
-	SCR *sp;
-	EVENT *argp;
-	int timeout;
-	u_int32_t flags;
+v_event_get(
+	SCR *sp,
+	EVENT *argp,
+	int timeout,
+	u_int32_t flags)
 {
 	EVENT *evp, ev;
 	GS *gp;
@@ -630,7 +639,8 @@
 	 */
 	if (istimeout || F_ISSET(&evp->e_ch, CH_NOMAP) ||
 	    !LF_ISSET(EC_MAPCOMMAND | EC_MAPINPUT) ||
-	    evp->e_c < MAX_BIT_SEQ && !bit_test(gp->seqb, evp->e_c))
+	    ((evp->e_c & ~MAX_BIT_SEQ) == 0 &&
+	    !bit_test(gp->seqb, evp->e_c)))
 		goto nomap;
 
 	/* Search the map. */
@@ -664,7 +674,7 @@
 
 	/* If no map, return the character. */
 	if (qp == NULL) {
-nomap:		if (!isdigit(evp->e_c) && LF_ISSET(EC_MAPNODIGIT))
+nomap:		if (!ISDIGIT(evp->e_c) && LF_ISSET(EC_MAPNODIGIT))
 			goto not_digit;
 		*argp = *evp;
 		QREM(1);
@@ -676,7 +686,7 @@
 	 * of the map is it, pretend we haven't seen the character.
 	 */
 	if (LF_ISSET(EC_MAPNODIGIT) &&
-	    qp->output != NULL && !isdigit(qp->output[0])) {
+	    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;
@@ -744,16 +754,16 @@
  *	Walk the screen lists, sync'ing files to their backup copies.
  */
 static void
-v_sync(sp, flags)
-	SCR *sp;
-	int flags;
+v_sync(
+	SCR *sp,
+	int flags)
 {
 	GS *gp;
 
 	gp = sp->gp;
-	for (sp = gp->dq.cqh_first; sp != (void *)&gp->dq; sp = sp->q.cqe_next)
+	TAILQ_FOREACH(sp, gp->dq, q)
 		rcv_sync(sp, flags);
-	for (sp = gp->hq.cqh_first; sp != (void *)&gp->hq; sp = sp->q.cqe_next)
+	TAILQ_FOREACH(sp, gp->hq, q)
 		rcv_sync(sp, flags);
 }
 
@@ -764,9 +774,9 @@
  * PUBLIC: void v_event_err __P((SCR *, EVENT *));
  */
 void
-v_event_err(sp, evp)
-	SCR *sp;
-	EVENT *evp;
+v_event_err(
+	SCR *sp,
+	EVENT *evp)
 {
 	switch (evp->e_event) {
 	case E_CHARACTER:
@@ -778,9 +788,6 @@
 	case E_INTERRUPT:
 		msgq(sp, M_ERR, "279|Unexpected interrupt event");
 		break;
-	case E_QUIT:
-		msgq(sp, M_ERR, "280|Unexpected quit event");
-		break;
 	case E_REPAINT:
 		msgq(sp, M_ERR, "281|Unexpected repaint event");
 		break;
@@ -793,9 +800,6 @@
 	case E_WRESIZE:
 		msgq(sp, M_ERR, "316|Unexpected resize event");
 		break;
-	case E_WRITE:
-		msgq(sp, M_ERR, "287|Unexpected write event");
-		break;
 
 	/*
 	 * Theoretically, none of these can occur, as they're handled at the
@@ -820,9 +824,9 @@
  * PUBLIC: int v_event_flush __P((SCR *, u_int));
  */
 int
-v_event_flush(sp, flags)
-	SCR *sp;
-	u_int flags;
+v_event_flush(
+	SCR *sp,
+	u_int flags)
 {
 	GS *gp;
 	int rval;
@@ -838,9 +842,9 @@
  *	Grow the terminal queue.
  */
 static int
-v_event_grow(sp, add)
-	SCR *sp;
-	int add;
+v_event_grow(
+	SCR *sp,
+	int add)
 {
 	GS *gp;
 	size_t new_nelem, olen;
@@ -848,7 +852,7 @@
 	gp = sp->gp;
 	new_nelem = gp->i_nelem + add;
 	olen = gp->i_nelem * sizeof(gp->i_event[0]);
-	BINC_RET(sp, gp->i_event, olen, new_nelem * sizeof(gp->i_event[0]));
+	BINC_RET(sp, EVENT, gp->i_event, olen, new_nelem * sizeof(gp->i_event[0]));
 	gp->i_nelem = olen / sizeof(gp->i_event[0]);
 	return (0);
 }
@@ -858,8 +862,9 @@
  *	Compare two keys for sorting.
  */
 static int
-v_key_cmp(ap, bp)
-	const void *ap, *bp;
+v_key_cmp(
+	const void *ap,
+	const void *bp)
 {
 	return (((KEYLIST *)ap)->ch - ((KEYLIST *)bp)->ch);
 }

Modified: trunk/contrib/nvi/common/key.h
===================================================================
--- trunk/contrib/nvi/common/key.h	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/common/key.h	2018-06-10 20:23:48 UTC (rev 10823)
@@ -6,27 +6,49 @@
  *
  * See the LICENSE file for redistribution information.
  *
- *	@(#)key.h	10.18 (Berkeley) 6/30/96
+ *	$Id: key.h,v 10.56 2013/11/13 12:15:27 zy Exp $
  */
 
-/*
- * Fundamental character types.
- *
- * CHAR_T	An integral type that can hold any character.
- * ARG_CHAR_T	The type of a CHAR_T when passed as an argument using
- *		traditional promotion rules.  It should also be able
- *		to be compared against any CHAR_T for equality without
- *		problems.
- * MAX_CHAR_T	The maximum value of any character.
- *
- * If no integral type can hold a character, don't even try the port.
- */
-typedef	u_char		CHAR_T;
-typedef	u_int		ARG_CHAR_T;
-#define	MAX_CHAR_T	0xff
+#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->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->cw, &nlen, &n)
+#define INPUT2INT5(sp,cw,n,nlen,w,wlen)					    \
+    sp->conv.input2int(sp, n, nlen, &(cw), &wlen, &w)
+#define CONST
+#define INTISWIDE(c)        (wctob(c) == EOF)
+#define CHAR_WIDTH(sp, ch)  wcwidth(ch)
+#define CAN_PRINT(sp, ch)   (CHAR_WIDTH(sp, ch) > 0)
+#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 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
+#define CAN_PRINT(sp, ch)   isprint(ch)
+#endif
+#define FILE2INT(sp,n,nlen,w,wlen)					    \
+    FILE2INT5(sp,sp->cw,n,nlen,w,wlen)
+#define CHAR2INT(sp,n,nlen,w,wlen)					    \
+    CHAR2INT5(sp,sp->cw,n,nlen,w,wlen)
+
 /* The maximum number of columns any character can take up on a screen. */
-#define	MAX_CHARACTER_COLUMNS	4
+#define	MAX_CHARACTER_COLUMNS	7
 
 /*
  * Event types.
@@ -42,7 +64,6 @@
 	E_EOF,				/* End of input (NOT ^D). */
 	E_ERR,				/* Input error. */
 	E_INTERRUPT,			/* Interrupt. */
-	E_QUIT,				/* Quit. */
 	E_REPAINT,			/* Repaint: e_flno, e_tlno set. */
 	E_SIGHUP,			/* SIGHUP. */
 	E_SIGTERM,			/* SIGTERM. */
@@ -49,7 +70,6 @@
 	E_STRING,			/* Input string: e_csp, e_len set. */
 	E_TIMEOUT,			/* Timeout. */
 	E_WRESIZE,			/* Window resize. */
-	E_WRITE				/* Write. */
 } e_event_t;
 
 /*
@@ -124,7 +144,7 @@
 
 typedef struct _keylist {
 	e_key_t value;			/* Special value. */
-	CHAR_T ch;			/* Key. */
+	int	ch;			/* Key. */
 } KEYLIST;
 extern KEYLIST keylist[];
 
@@ -137,15 +157,13 @@
 /*
  * 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.
+ * characters like ^K in the ASCII character set.  The POSIX isblank(3)
+ * has the same problem for non-ASCII locale, so we need a standalone one.
  *
  * XXX
  * Note side effect, ch is evaluated multiple times.
  */
-#ifndef isblank
-#define	isblank(ch)	((ch) == ' ' || (ch) == '\t')
-#endif
+#define	cmdskip(ch)	((ch) == ' ' || (ch) == '\t')
 
 /* The "standard" tab width, for displaying things to users. */
 #define	STANDARD_TAB	6

Modified: trunk/contrib/nvi/common/line.c
===================================================================
--- trunk/contrib/nvi/common/line.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/common/line.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -10,7 +10,7 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)line.c	10.21 (Berkeley) 9/15/96";
+static const char sccsid[] = "$Id: line.c,v 10.26 2011/08/12 12:36:41 zy Exp $";
 #endif /* not lint */
 
 #include <sys/types.h>
@@ -32,15 +32,15 @@
  * db_eget --
  *	Front-end to db_get, special case handling for empty files.
  *
- * PUBLIC: int db_eget __P((SCR *, recno_t, char **, size_t *, int *));
+ * PUBLIC: int db_eget __P((SCR *, recno_t, CHAR_T **, size_t *, int *));
  */
 int
-db_eget(sp, lno, pp, lenp, isemptyp)
-	SCR *sp;
-	recno_t lno;				/* Line number. */
-	char **pp;				/* Pointer store. */
-	size_t *lenp;				/* Length store. */
-	int *isemptyp;
+db_eget(
+	SCR *sp,
+	recno_t lno,				/* Line number. */
+	CHAR_T **pp,				/* Pointer store. */
+	size_t *lenp,				/* Length store. */
+	int *isemptyp)
 {
 	recno_t l1;
 
@@ -60,7 +60,7 @@
 		return (1);
 
 	/* If the file isn't empty, fail loudly. */
-	if (lno != 0 && lno != 1 || l1 != 0) {
+	if ((lno != 0 && lno != 1) || l1 != 0) {
 		db_err(sp, lno);
 		return (1);
 	}
@@ -76,20 +76,23 @@
  *	Look in the text buffers for a line, followed by the cache, followed
  *	by the database.
  *
- * PUBLIC: int db_get __P((SCR *, recno_t, u_int32_t, char **, size_t *));
+ * PUBLIC: int db_get __P((SCR *, recno_t, u_int32_t, CHAR_T **, size_t *));
  */
 int
-db_get(sp, lno, flags, pp, lenp)
-	SCR *sp;
-	recno_t lno;				/* Line number. */
-	u_int32_t flags;
-	char **pp;				/* Pointer store. */
-	size_t *lenp;				/* Length store. */
+db_get(
+	SCR *sp,
+	recno_t lno,				/* Line number. */
+	u_int32_t flags,
+	CHAR_T **pp,				/* Pointer store. */
+	size_t *lenp)				/* Length store. */
 {
 	DBT data, key;
 	EXF *ep;
 	TEXT *tp;
 	recno_t l1, l2;
+	CHAR_T *wp;
+	size_t wlen;
+	size_t nlen;
 
 	/*
 	 * The underlying recno stuff handles zero by returning NULL, but
@@ -113,14 +116,14 @@
 	 * is there.
 	 */
 	if (F_ISSET(sp, SC_TINPUT)) {
-		l1 = ((TEXT *)sp->tiq.cqh_first)->lno;
-		l2 = ((TEXT *)sp->tiq.cqh_last)->lno;
+		l1 = ((TEXT *)TAILQ_FIRST(sp->tiq))->lno;
+		l2 = ((TEXT *)TAILQ_LAST(sp->tiq, _texth))->lno;
 		if (l1 <= lno && l2 >= lno) {
 #if defined(DEBUG) && 0
 	TRACE(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);
+			for (tp = TAILQ_FIRST(sp->tiq);
+			    tp->lno != lno; tp = TAILQ_NEXT(tp, q));
 			if (lenp != NULL)
 				*lenp = tp->len;
 			if (pp != NULL)
@@ -149,32 +152,52 @@
 	ep->c_lno = OOBLNO;
 
 nocache:
+	nlen = 1024;
+retry:
 	/* Get the line from the underlying database. */
 	key.data = &lno;
 	key.size = sizeof(lno);
 	switch (ep->db->get(ep->db, &key, &data, 0)) {
-        case -1:
+	case -1:
 		goto err2;
 	case 1:
 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 (data.size > nlen) {
+			nlen = data.size;
+			goto retry;
+		}
 	}
 
+	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, ep->c_lp, ep->c_blen, wlen);
+		MEMCPY(ep->c_lp, wp, wlen);
+	} else
+		ep->c_lp = data.data;
 	ep->c_lno = lno;
-	ep->c_len = data.size;
-	ep->c_lp = data.data;
+	ep->c_len = wlen;
 
 #if defined(DEBUG) && 0
 	TRACE(sp, "retrieve DB line %lu\n", (u_long)lno);
 #endif
 	if (lenp != NULL)
-		*lenp = data.size;
+		*lenp = wlen;
 	if (pp != NULL)
 		*pp = ep->c_lp;
 	return (0);
@@ -187,9 +210,9 @@
  * PUBLIC: int db_delete __P((SCR *, recno_t));
  */
 int
-db_delete(sp, lno)
-	SCR *sp;
-	recno_t lno;
+db_delete(
+	SCR *sp,
+	recno_t lno)
 {
 	DBT key;
 	EXF *ep;
@@ -242,18 +265,20 @@
  * db_append --
  *	Append a line into the file.
  *
- * PUBLIC: int db_append __P((SCR *, int, recno_t, char *, size_t));
+ * PUBLIC: int db_append __P((SCR *, int, recno_t, CHAR_T *, size_t));
  */
 int
-db_append(sp, update, lno, p, len)
-	SCR *sp;
-	int update;
-	recno_t lno;
-	char *p;
-	size_t len;
+db_append(
+	SCR *sp,
+	int update,
+	recno_t lno,
+	CHAR_T *p,
+	size_t len)
 {
 	DBT data, key;
 	EXF *ep;
+	char *fp;
+	size_t flen;
 	int rval;
 
 #if defined(DEBUG) && 0
@@ -265,11 +290,13 @@
 		return (1);
 	}
 		
+	INT2FILE(sp, p, len, fp, flen);
+
 	/* Update file. */
 	key.data = &lno;
 	key.size = sizeof(lno);
-	data.data = p;
-	data.size = len;
+	data.data = fp;
+	data.size = flen;
 	SIGBLOCK;
 	if (ep->db->put(ep->db, &key, &data, R_IAFTER) == -1) {
 		msgq(sp, M_SYSERR,
@@ -316,17 +343,19 @@
  * db_insert --
  *	Insert a line into the file.
  *
- * PUBLIC: int db_insert __P((SCR *, recno_t, char *, size_t));
+ * PUBLIC: int db_insert __P((SCR *, recno_t, CHAR_T *, size_t));
  */
 int
-db_insert(sp, lno, p, len)
-	SCR *sp;
-	recno_t lno;
-	char *p;
-	size_t len;
+db_insert(
+	SCR *sp,
+	recno_t lno,
+	CHAR_T *p,
+	size_t len)
 {
 	DBT data, key;
 	EXF *ep;
+	char *fp;
+	size_t flen;
 	int rval;
 
 #if defined(DEBUG) && 0
@@ -339,11 +368,13 @@
 		return (1);
 	}
 		
+	INT2FILE(sp, p, len, fp, flen);
+		
 	/* Update file. */
 	key.data = &lno;
 	key.size = sizeof(lno);
-	data.data = p;
-	data.size = len;
+	data.data = fp;
+	data.size = flen;
 	SIGBLOCK;
 	if (ep->db->put(ep->db, &key, &data, R_IBEFORE) == -1) {
 		msgq(sp, M_SYSERR,
@@ -381,23 +412,24 @@
  * db_set --
  *	Store a line in the file.
  *
- * PUBLIC: int db_set __P((SCR *, recno_t, char *, size_t));
+ * PUBLIC: int db_set __P((SCR *, recno_t, CHAR_T *, size_t));
  */
 int
-db_set(sp, lno, p, len)
-	SCR *sp;
-	recno_t lno;
-	char *p;
-	size_t len;
+db_set(
+	SCR *sp,
+	recno_t lno,
+	CHAR_T *p,
+	size_t len)
 {
 	DBT data, key;
 	EXF *ep;
+	char *fp;
+	size_t flen;
 
 #if defined(DEBUG) && 0
 	TRACE(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);
@@ -407,11 +439,13 @@
 	/* Log before change. */
 	log_line(sp, lno, LOG_LINE_RESET_B);
 
+	INT2FILE(sp, p, len, fp, flen);
+
 	/* Update file. */
 	key.data = &lno;
 	key.size = sizeof(lno);
-	data.data = p;
-	data.size = len;
+	data.data = fp;
+	data.size = flen;
 	SIGBLOCK;
 	if (ep->db->put(ep->db, &key, &data, 0) == -1) {
 		msgq(sp, M_SYSERR,
@@ -443,9 +477,9 @@
  * PUBLIC: int db_exist __P((SCR *, recno_t));
  */
 int
-db_exist(sp, lno)
-	SCR *sp;
-	recno_t lno;
+db_exist(
+	SCR *sp,
+	recno_t lno)
 {
 	EXF *ep;
 
@@ -464,8 +498,8 @@
 	 */
 	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));
+		    ep->c_nlines + (((TEXT *)TAILQ_LAST(sp->tiq, _texth))->lno -
+		    ((TEXT *)TAILQ_FIRST(sp->tiq))->lno) : ep->c_nlines));
 
 	/* Go get the line. */
 	return (!db_get(sp, lno, 0, NULL, NULL));
@@ -478,13 +512,15 @@
  * PUBLIC: int db_last __P((SCR *, recno_t *));
  */
 int
-db_last(sp, lnop)
-	SCR *sp;
-	recno_t *lnop;
+db_last(
+	SCR *sp,
+	recno_t *lnop)
 {
 	DBT data, key;
 	EXF *ep;
 	recno_t lno;
+	CHAR_T *wp;
+	size_t wlen;
 
 	/* Check for no underlying file. */
 	if ((ep = sp->ep) == NULL) {
@@ -499,8 +535,8 @@
 	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;
+			*lnop += ((TEXT *)TAILQ_LAST(sp->tiq, _texth))->lno -
+			    ((TEXT *)TAILQ_FIRST(sp->tiq))->lno;
 		return (0);
 	}
 
@@ -508,31 +544,108 @@
 	key.size = sizeof(lno);
 
 	switch (ep->db->seq(ep->db, &key, &data, R_LAST)) {
-        case -1:
+	case -1:
+alloc_err:
 		msgq(sp, M_SYSERR, "007|unable to get last line");
 		*lnop = 0;
 		return (1);
-        case 1:
+	case 1:
 		*lnop = 0;
 		return (0);
-	default:
-		break;
+	case 0:
+		;
 	}
 
-	/* Fill the cache. */
 	memcpy(&lno, key.data, sizeof(lno));
-	ep->c_nlines = ep->c_lno = lno;
-	ep->c_len = data.size;
-	ep->c_lp = data.data;
 
+	if (lno != ep->c_lno) {
+		FILE2INT(sp, data.data, data.size, wp, wlen);
+
+		/* Fill the cache. */
+		if (wp != data.data) {
+			BINC_GOTOW(sp, ep->c_lp, ep->c_blen, wlen);
+			MEMCPY(ep->c_lp, wp, wlen);
+		} else
+			ep->c_lp = data.data;
+		ep->c_lno = lno;
+		ep->c_len = wlen;
+	}
+	ep->c_nlines = lno;
+
 	/* Return the value. */
 	*lnop = (F_ISSET(sp, SC_TINPUT) &&
-	    ((TEXT *)sp->tiq.cqh_last)->lno > lno ?
-	    ((TEXT *)sp->tiq.cqh_last)->lno : lno);
+	    ((TEXT *)TAILQ_LAST(sp->tiq, _texth))->lno > lno ?
+	    ((TEXT *)TAILQ_LAST(sp->tiq, _texth))->lno : lno);
 	return (0);
 }
 
 /*
+ * db_rget --
+ *	Retrieve a raw line from database. No cache, no conversion.
+ *
+ * PUBLIC: int db_rget __P((SCR *, recno_t, char **, size_t *));
+ */
+int
+db_rget(
+	SCR *sp,
+	recno_t lno,				/* Line number. */
+	char **pp,				/* Pointer store. */
+	size_t *lenp)				/* Length store. */
+{
+	DBT data, key;
+	EXF *ep;
+
+	/* Check for no underlying file. */
+	if ((ep = sp->ep) == NULL)
+		return (1);
+
+	/* Get the line from the underlying database. */
+	key.data = &lno;
+	key.size = sizeof(lno);
+	if (ep->db->get(ep->db, &key, &data, 0))
+	/* We do not report error, and do not ensure the size! */
+		return (1);
+
+	if (lenp != NULL)
+		*lenp = data.size;
+	if (pp != NULL)
+		*pp = data.data;
+	return (0);
+}
+
+/*
+ * db_rset --
+ *	Store a line in the file. No log, no conversion.
+ *
+ * PUBLIC: int db_rset __P((SCR *, recno_t, char *, size_t));
+ */
+int
+db_rset(
+	SCR *sp,
+	recno_t lno,
+	char *p,
+	size_t len)
+{
+	DBT data, key;
+	EXF *ep;
+
+	/* Check for no underlying file. */
+	if ((ep = sp->ep) == NULL)
+		return (1);
+		
+	/* Update file. */
+	key.data = &lno;
+	key.size = sizeof(lno);
+	data.data = p;
+	data.size = len;
+	if (ep->db->put(ep->db, &key, &data, 0) == -1)
+	/* We do not report error, and do not ensure the size! */
+		return (1);
+
+	return (0);
+}
+
+/*
  * db_err --
  *	Report a line error.
  *
@@ -539,9 +652,9 @@
  * PUBLIC: void db_err __P((SCR *, recno_t));
  */
 void
-db_err(sp, lno)
-	SCR *sp;
-	recno_t lno;
+db_err(
+	SCR *sp,
+	recno_t lno)
 {
 	msgq(sp, M_ERR,
 	    "008|Error: unable to retrieve line %lu", (u_long)lno);
@@ -553,11 +666,11 @@
  *	just changed.
  */
 static int
-scr_update(sp, lno, op, current)
-	SCR *sp;
-	recno_t lno;
-	lnop_t op;
-	int current;
+scr_update(
+	SCR *sp,
+	recno_t lno,
+	lnop_t op,
+	int current)
 {
 	EXF *ep;
 	SCR *tsp;
@@ -567,8 +680,7 @@
 
 	ep = sp->ep;
 	if (ep->refcnt != 1)
-		for (tsp = sp->gp->dq.cqh_first;
-		    tsp != (void *)&sp->gp->dq; tsp = tsp->q.cqe_next)
+		TAILQ_FOREACH(tsp, sp->gp->dq, q)
 			if (sp != tsp && tsp->ep == ep)
 				if (vs_change(tsp, lno, op))
 					return (1);

Modified: trunk/contrib/nvi/common/log.c
===================================================================
--- trunk/contrib/nvi/common/log.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/common/log.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -10,7 +10,7 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)log.c	10.8 (Berkeley) 3/6/96";
+static const char sccsid[] = "$Id: log.c,v 10.27 2011/07/13 06:25:50 zy Exp $";
 #endif /* not lint */
 
 #include <sys/types.h>
@@ -21,6 +21,7 @@
 #include <errno.h>
 #include <fcntl.h>
 #include <limits.h>
+#include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -67,6 +68,8 @@
 #if defined(DEBUG) && 0
 static void	log_trace __P((SCR *, char *, recno_t, u_char *));
 #endif
+static int	apply_with __P((int (*)(SCR *, recno_t, CHAR_T *, size_t),
+					SCR *, recno_t, u_char *, size_t));
 
 /* Try and restart the log on failure, i.e. if we run out of memory. */
 #define	LOG_ERR {							\
@@ -74,6 +77,15 @@
 	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(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.
@@ -81,9 +93,9 @@
  * PUBLIC: int log_init __P((SCR *, EXF *));
  */
 int
-log_init(sp, ep)
-	SCR *sp;
-	EXF *ep;
+log_init(
+	SCR *sp,
+	EXF *ep)
 {
 	/*
 	 * !!!
@@ -117,9 +129,9 @@
  * PUBLIC: int log_end __P((SCR *, EXF *));
  */
 int
-log_end(sp, ep)
-	SCR *sp;
-	EXF *ep;
+log_end(
+	SCR *sp,
+	EXF *ep)
 {
 	/*
 	 * !!!
@@ -147,8 +159,7 @@
  * PUBLIC: int log_cursor __P((SCR *));
  */
 int
-log_cursor(sp)
-	SCR *sp;
+log_cursor(SCR *sp)
 {
 	EXF *ep;
 
@@ -175,15 +186,16 @@
  *	Actually push a cursor record out.
  */
 static int
-log_cursor1(sp, type)
-	SCR *sp;
-	int type;
+log_cursor1(
+	SCR *sp,
+	int type)
 {
 	DBT data, key;
 	EXF *ep;
 
 	ep = sp->ep;
-	BINC_RET(sp, ep->l_lp, ep->l_len, sizeof(u_char) + sizeof(MARK));
+
+	BINC_RETC(sp, ep->l_lp, ep->l_len, sizeof(u_char) + sizeof(MARK));
 	ep->l_lp[0] = type;
 	memmove(ep->l_lp + sizeof(u_char), &ep->l_cursor, sizeof(MARK));
 
@@ -212,15 +224,16 @@
  * PUBLIC: int log_line __P((SCR *, recno_t, u_int));
  */
 int
-log_line(sp, lno, action)
-	SCR *sp;
-	recno_t lno;
-	u_int action;
+log_line(
+	SCR *sp,
+	recno_t lno,
+	u_int action)
 {
 	DBT data, key;
 	EXF *ep;
 	size_t len;
-	char *lp;
+	CHAR_T *lp;
+	recno_t lcur;
 
 	ep = sp->ep;
 	if (F_ISSET(ep, F_NOLOG))
@@ -254,21 +267,23 @@
 				return (1);
 			}
 			len = 0;
-			lp = "";
+			lp = L("");
 		}
 	} else
 		if (db_get(sp, lno, DBG_FATAL, &lp, &len))
 			return (1);
-	BINC_RET(sp,
-	    ep->l_lp, ep->l_len, len + sizeof(u_char) + sizeof(recno_t));
+	BINC_RETC(sp,
+	    ep->l_lp, ep->l_len,
+	    len * sizeof(CHAR_T) + CHAR_T_OFFSET);
 	ep->l_lp[0] = action;
 	memmove(ep->l_lp + sizeof(u_char), &lno, sizeof(recno_t));
-	memmove(ep->l_lp + sizeof(u_char) + sizeof(recno_t), lp, len);
+	memmove(ep->l_lp + CHAR_T_OFFSET, lp, len * sizeof(CHAR_T));
 
-	key.data = &ep->l_cur;
+	lcur = ep->l_cur;
+	key.data = &lcur;
 	key.size = sizeof(recno_t);
 	data.data = ep->l_lp;
-	data.size = len + sizeof(u_char) + sizeof(recno_t);
+	data.size = len * sizeof(CHAR_T) + CHAR_T_OFFSET;
 	if (ep->log->put(ep->log, &key, &data, 0) == -1)
 		LOG_ERR;
 
@@ -275,7 +290,7 @@
 #if defined(DEBUG) && 0
 	switch (action) {
 	case LOG_LINE_APPEND:
-		TRACE(sp, "%u: log_line: append: %lu {%u}\n",
+		TRACE(sp, "%lu: log_line: append: %lu {%u}\n",
 		    ep->l_cur, lno, len);
 		break;
 	case LOG_LINE_DELETE:
@@ -312,9 +327,9 @@
  * PUBLIC: int log_mark __P((SCR *, LMARK *));
  */
 int
-log_mark(sp, lmp)
-	SCR *sp;
-	LMARK *lmp;
+log_mark(
+	SCR *sp,
+	LMARK *lmp)
 {
 	DBT data, key;
 	EXF *ep;
@@ -330,7 +345,7 @@
 		ep->l_cursor.lno = OOBLNO;
 	}
 
-	BINC_RET(sp, ep->l_lp,
+	BINC_RETC(sp, ep->l_lp,
 	    ep->l_len, sizeof(u_char) + sizeof(LMARK));
 	ep->l_lp[0] = LOG_MARK;
 	memmove(ep->l_lp + sizeof(u_char), lmp, sizeof(LMARK));
@@ -358,9 +373,9 @@
  * PUBLIC: int log_backward __P((SCR *, MARK *));
  */
 int
-log_backward(sp, rp)
-	SCR *sp;
-	MARK *rp;
+log_backward(
+	SCR *sp,
+	MARK *rp)
 {
 	DBT key, data;
 	EXF *ep;
@@ -414,9 +429,8 @@
 		case LOG_LINE_DELETE:
 			didop = 1;
 			memmove(&lno, p + sizeof(u_char), sizeof(recno_t));
-			if (db_insert(sp, lno, p + sizeof(u_char) +
-			    sizeof(recno_t), data.size - sizeof(u_char) -
-			    sizeof(recno_t)))
+			if (apply_with(db_insert, sp, lno,
+				p + CHAR_T_OFFSET, data.size - CHAR_T_OFFSET))
 				goto err;
 			++sp->rptlines[L_ADDED];
 			break;
@@ -425,9 +439,8 @@
 		case LOG_LINE_RESET_B:
 			didop = 1;
 			memmove(&lno, p + sizeof(u_char), sizeof(recno_t));
-			if (db_set(sp, lno, p + sizeof(u_char) +
-			    sizeof(recno_t), data.size - sizeof(u_char) -
-			    sizeof(recno_t)))
+			if (apply_with(db_set, sp, lno,
+				p + CHAR_T_OFFSET, data.size - CHAR_T_OFFSET))
 				goto err;
 			if (sp->rptlchange != lno) {
 				sp->rptlchange = lno;
@@ -464,8 +477,7 @@
  * PUBLIC: int log_setline __P((SCR *));
  */
 int
-log_setline(sp)
-	SCR *sp;
+log_setline(SCR *sp)
 {
 	DBT key, data;
 	EXF *ep;
@@ -488,7 +500,6 @@
 
 	key.data = &ep->l_cur;		/* Initialize db request. */
 	key.size = sizeof(recno_t);
-
 	for (;;) {
 		--ep->l_cur;
 		if (ep->log->get(ep->log, &key, &data, 0))
@@ -520,9 +531,8 @@
 		case LOG_LINE_RESET_B:
 			memmove(&lno, p + sizeof(u_char), sizeof(recno_t));
 			if (lno == sp->lno &&
-			    db_set(sp, lno, p + sizeof(u_char) +
-			    sizeof(recno_t), data.size - sizeof(u_char) -
-			    sizeof(recno_t)))
+				apply_with(db_set, sp, lno,
+				p + CHAR_T_OFFSET, data.size - CHAR_T_OFFSET))
 				goto err;
 			if (sp->rptlchange != lno) {
 				sp->rptlchange = lno;
@@ -551,9 +561,9 @@
  * PUBLIC: int log_forward __P((SCR *, MARK *));
  */
 int
-log_forward(sp, rp)
-	SCR *sp;
-	MARK *rp;
+log_forward(
+	SCR *sp,
+	MARK *rp)
 {
 	DBT key, data;
 	EXF *ep;
@@ -601,9 +611,8 @@
 		case LOG_LINE_INSERT:
 			didop = 1;
 			memmove(&lno, p + sizeof(u_char), sizeof(recno_t));
-			if (db_insert(sp, lno, p + sizeof(u_char) +
-			    sizeof(recno_t), data.size - sizeof(u_char) -
-			    sizeof(recno_t)))
+			if (apply_with(db_insert, sp, lno,
+				p + CHAR_T_OFFSET, data.size - CHAR_T_OFFSET))
 				goto err;
 			++sp->rptlines[L_ADDED];
 			break;
@@ -619,9 +628,8 @@
 		case LOG_LINE_RESET_F:
 			didop = 1;
 			memmove(&lno, p + sizeof(u_char), sizeof(recno_t));
-			if (db_set(sp, lno, p + sizeof(u_char) +
-			    sizeof(recno_t), data.size - sizeof(u_char) -
-			    sizeof(recno_t)))
+			if (apply_with(db_set, sp, lno,
+				p + CHAR_T_OFFSET, data.size - CHAR_T_OFFSET))
 				goto err;
 			if (sp->rptlchange != lno) {
 				sp->rptlchange = lno;
@@ -650,10 +658,10 @@
  *	Try and restart the log on failure, i.e. if we run out of memory.
  */
 static void
-log_err(sp, file, line)
-	SCR *sp;
-	char *file;
-	int line;
+log_err(
+	SCR *sp,
+	char *file,
+	int line)
 {
 	EXF *ep;
 
@@ -666,11 +674,11 @@
 
 #if defined(DEBUG) && 0
 static void
-log_trace(sp, msg, rno, p)
-	SCR *sp;
-	char *msg;
-	recno_t rno;
-	u_char *p;
+log_trace(
+	SCR *sp,
+	char *msg,
+	recno_t rno,
+	u_char *p)
 {
 	LMARK lm;
 	MARK m;
@@ -715,3 +723,45 @@
 	}
 }
 #endif
+
+/*
+ * apply_with --
+ *	Apply a realigned line from the log db to the file db.
+ */
+static int
+apply_with(
+	int (*db_func)(SCR *, recno_t, CHAR_T *, size_t),
+	SCR *sp,
+	recno_t lno,
+	u_char *p,
+	size_t len)
+{
+#ifdef USE_WIDECHAR
+	typedef unsigned long nword;
+
+	static size_t blen;
+	static nword *bp;
+	nword *lp = (nword *)((uintptr_t)p / sizeof(nword) * sizeof(nword));
+
+	if (lp != (nword *)p) {
+		int offl = ((uintptr_t)p - (uintptr_t)lp) << 3;
+		int offr = (sizeof(nword) << 3) - offl;
+		size_t i, cnt = (len + sizeof(nword) / 2) / sizeof(nword);
+
+		if (len > blen) {
+			blen = p2roundup(MAX(len, 512));
+			REALLOC(sp, bp, nword *, blen);
+			if (bp == NULL)
+				return (1);
+		}
+		for (i = 0; i < cnt; ++i)
+#if BYTE_ORDER == BIG_ENDIAN
+			bp[i] = (lp[i] << offl) ^ (lp[i+1] >> offr);
+#else
+			bp[i] = (lp[i] >> offl) ^ (lp[i+1] << offr);
+#endif
+		p = (u_char *)bp;
+	}
+#endif
+	return db_func(sp, lno, (CHAR_T *)p, len / sizeof(CHAR_T));
+}

Modified: trunk/contrib/nvi/common/main.c
===================================================================
--- trunk/contrib/nvi/common/main.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/common/main.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -18,13 +18,12 @@
 #endif /* not lint */
 
 #ifndef lint
-static const char sccsid[] = "@(#)main.c	10.48 (Berkeley) 10/11/96";
+static const char sccsid[] = "$Id: main.c,v 11.0 2012/10/17 06:34:37 zy Exp $";
 #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>
@@ -50,10 +49,10 @@
  * PUBLIC: int editor __P((GS *, int, char *[]));
  */
 int
-editor(gp, argc, argv)
-	GS *gp;
-	int argc;
-	char *argv[];
+editor(
+	GS *gp,
+	int argc,
+	char *argv[])
 {
 	extern int optind;
 	extern char *optarg;
@@ -64,10 +63,9 @@
 	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];
+	CHAR_T *w;
+	size_t wlen;
 
 	/* Initialize the busy routine, if not defined by the screen. */
 	if (gp->scr_busy == NULL)
@@ -75,19 +73,20 @@
 	/* Initialize the message routine, if not defined by the screen. */
 	if (gp->scr_msg == NULL)
 		gp->scr_msg = vs_msg;
+	gp->catd = (nl_catd)-1;
 
 	/* Common global structure initialization. */
-	CIRCLEQ_INIT(&gp->dq);
-	CIRCLEQ_INIT(&gp->hq);
-	LIST_INIT(&gp->ecq);
-	LIST_INSERT_HEAD(&gp->ecq, &gp->excmd, q);
+	TAILQ_INIT(gp->dq);
+	TAILQ_INIT(gp->hq);
+	SLIST_INIT(gp->ecq);
+	SLIST_INSERT_HEAD(gp->ecq, &gp->excmd, q);
 	gp->noprint = DEFAULT_NOPRINT;
 
 	/* Structures shared by screens so stored in the GS structure. */
-	CIRCLEQ_INIT(&gp->frefq);
-	CIRCLEQ_INIT(&gp->dcb_store.textq);
-	LIST_INIT(&gp->cutq);
-	LIST_INIT(&gp->seqq);
+	TAILQ_INIT(gp->frefq);
+	TAILQ_INIT(gp->dcb_store.textq);
+	SLIST_INIT(gp->cutq);
+	SLIST_INIT(gp->seqq);
 
 	/* Set initial screen type and mode based on the program name. */
 	readonly = 0;
@@ -116,19 +115,11 @@
 	/* Set the file snapshot flag. */
 	F_SET(gp, G_SNAPSHOT);
 
-#ifdef GTAGS
 #ifdef DEBUG
-	while ((ch = getopt(argc, argv, "c:D:eFGlRrSsT:t:vw:")) != EOF)
-#else
-	while ((ch = getopt(argc, argv, "c:eFGlRrSst:vw:")) != EOF)
-#endif
-#else
-#ifdef DEBUG
 	while ((ch = getopt(argc, argv, "c:D:eFlRrSsT:t:vw:")) != EOF)
 #else
 	while ((ch = getopt(argc, argv, "c:eFlRrSst:vw:")) != EOF)
 #endif
-#endif
 		switch (ch) {
 		case 'c':		/* Run the command. */
 			/*
@@ -165,11 +156,6 @@
 		case 'F':		/* No snapshot. */
 			F_CLR(gp, G_SNAPSHOT);
 			break;
-#ifdef GTAGS
-		case 'G':		/* gtags mode. */
-			gtags = 1;
-			break;
-#endif
 		case 'l':		/* Set lisp, showmatch options. */
 			lflag = 1;
 			break;
@@ -252,11 +238,11 @@
 	 */
 	if (screen_init(gp, NULL, &sp)) {
 		if (sp != NULL)
-			CIRCLEQ_INSERT_HEAD(&gp->dq, sp, q);
+			TAILQ_INSERT_HEAD(gp->dq, sp, q);
 		goto err;
 	}
 	F_SET(sp, SC_EX);
-	CIRCLEQ_INSERT_HEAD(&gp->dq, sp, q);
+	TAILQ_INSERT_HEAD(gp->dq, sp, q);
 
 	if (v_key_init(sp))		/* Special key initialization. */
 		goto err;
@@ -268,10 +254,6 @@
 	}
 	if (readonly)
 		*oargp++ = O_READONLY;
-#ifdef GTAGS
-	if (gtags)
-		*oargp++ = O_GTAGSMODE;
-#endif
 	if (secure)
 		*oargp++ = O_SECURE;
 	*oargp = -1;			/* Options initialization. */
@@ -351,8 +333,11 @@
 	}
 
 	/* Open a tag file if specified. */
-	if (tag_f != NULL && ex_tag_first(sp, tag_f))
-		goto err;
+	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
@@ -362,13 +347,11 @@
 	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);
+			*--argv = strdup(sp->frp->name);
 			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);
@@ -386,7 +369,7 @@
 			if ((frp = file_add(sp, NULL)) == NULL)
 				goto err;
 		} else  {
-			if ((frp = file_add(sp, (CHAR_T *)sp->argv[0])) == NULL)
+			if ((frp = file_add(sp, sp->argv[0])) == NULL)
 				goto err;
 			if (F_ISSET(sp, SC_ARGRECOVER))
 				F_SET(frp, FR_RECOVER);
@@ -420,8 +403,8 @@
 			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))
+			    (ev.e_event == E_CHARACTER &&
+			     (ev.e_value == K_CR || ev.e_value == K_NL)))
 				break;
 			(void)gp->scr_bell(sp);
 		}
@@ -467,20 +450,16 @@
 		(void)file_end(gp->ccl_sp, NULL, 1);
 		(void)screen_end(gp->ccl_sp);
 	}
-	while ((sp = gp->dq.cqh_first) != (void *)&gp->dq)
+	while ((sp = TAILQ_FIRST(gp->dq)) != NULL)
 		(void)screen_end(sp);
-	while ((sp = gp->hq.cqh_first) != (void *)&gp->hq)
+	while ((sp = TAILQ_FIRST(gp->hq)) != NULL)
 		(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);
+		while ((frp = TAILQ_FIRST(gp->frefq)) != NULL) {
+			TAILQ_REMOVE(gp->frefq, frp, q);
 			if (frp->name != NULL)
 				free(frp->name);
 			if (frp->tname != NULL)
@@ -500,7 +479,7 @@
 	seq_close(gp);
 
 	/* Free default buffer storage. */
-	(void)text_lfree(&gp->dcb_store.textq);
+	(void)text_lfree(gp->dcb_store.textq);
 
 	/* Close message catalogs. */
 	msg_close(gp);
@@ -516,10 +495,10 @@
 	 * it's possible that the user is sourcing a file that exits from the
 	 * editor).
 	 */
-	while ((mp = gp->msgq.lh_first) != NULL) {
+	while ((mp = SLIST_FIRST(gp->msgq)) != NULL) {
 		(void)fprintf(stderr, "%s%.*s",
 		    mp->mtype == M_ERR ? "ex/vi: " : "", (int)mp->len, mp->buf);
-		LIST_REMOVE(mp, q);
+		SLIST_REMOVE_HEAD(gp->msgq, q);
 #if defined(DEBUG) || defined(PURIFY) || defined(LIBRARY)
 		free(mp->buf);
 		free(mp);
@@ -544,8 +523,9 @@
  *	Convert historic arguments into something getopt(3) will like.
  */
 static int
-v_obsolete(name, argv)
-	char *name, *argv[];
+v_obsolete(
+	char *name,
+	char *argv[])
 {
 	size_t len;
 	char *p;
@@ -566,28 +546,26 @@
 	while (*++argv && strcmp(argv[0], "--"))
 		if (argv[0][0] == '+') {
 			if (argv[0][1] == '\0') {
-				MALLOC_NOMSG(NULL, argv[0], char *, 4);
+				argv[0] = strdup("-c$");
 				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);
+				argv[0] = malloc(len + 2);
 				if (argv[0] == NULL)
 					goto nomem;
 				argv[0][0] = '-';
 				argv[0][1] = 'c';
-				(void)strcpy(argv[0] + 2, p + 1);
+				(void)strlcpy(argv[0] + 2, p + 1, len);
 			}
 		} else if (argv[0][0] == '-')
 			if (argv[0][1] == '\0') {
-				MALLOC_NOMSG(NULL, argv[0], char *, 3);
+				argv[0] = strdup("-s");
 				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') &&
@@ -598,8 +576,7 @@
 
 #ifdef DEBUG
 static void
-attach(gp)
-	GS *gp;
+attach(GS *gp)
 {
 	int fd;
 	char ch;
@@ -624,9 +601,10 @@
 #endif
 
 static void
-v_estr(name, eno, msg)
-	char *name, *msg;
-	int eno;
+v_estr(
+	char *name,
+	int eno,
+	char *msg)
 {
 	(void)fprintf(stderr, "%s", name);
 	if (msg != NULL)

Modified: trunk/contrib/nvi/common/mark.c
===================================================================
--- trunk/contrib/nvi/common/mark.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/common/mark.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -10,11 +10,12 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)mark.c	10.13 (Berkeley) 7/19/96";
+static const char sccsid[] = "$Id: mark.c,v 10.14 2011/07/04 14:42:58 zy Exp $";
 #endif /* not lint */
 
 #include <sys/types.h>
 #include <sys/queue.h>
+#include <sys/time.h>
 
 #include <bitstring.h>
 #include <errno.h>
@@ -28,7 +29,7 @@
 static LMARK *mark_find __P((SCR *, ARG_CHAR_T));
 
 /*
- * Marks are maintained in a key sorted doubly linked list.  We can't
+ * Marks are maintained in a key sorted singly 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.
@@ -65,9 +66,9 @@
  * PUBLIC: int mark_init __P((SCR *, EXF *));
  */
 int
-mark_init(sp, ep)
-	SCR *sp;
-	EXF *ep;
+mark_init(
+	SCR *sp,
+	EXF *ep)
 {
 	/*
 	 * !!!
@@ -75,7 +76,7 @@
 	 *
 	 * Set up the marks.
 	 */
-	LIST_INIT(&ep->marks);
+	SLIST_INIT(ep->marks);
 	return (0);
 }
 
@@ -86,9 +87,9 @@
  * PUBLIC: int mark_end __P((SCR *, EXF *));
  */
 int
-mark_end(sp, ep)
-	SCR *sp;
-	EXF *ep;
+mark_end(
+	SCR *sp,
+	EXF *ep)
 {
 	LMARK *lmp;
 
@@ -96,8 +97,8 @@
 	 * !!!
 	 * 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);
+	while ((lmp = SLIST_FIRST(ep->marks)) != NULL) {
+		SLIST_REMOVE_HEAD(ep->marks, q);
 		free(lmp);
 	}
 	return (0);
@@ -110,11 +111,11 @@
  * PUBLIC: int mark_get __P((SCR *, ARG_CHAR_T, MARK *, mtype_t));
  */
 int
-mark_get(sp, key, mp, mtype)
-	SCR *sp;
-	ARG_CHAR_T key;
-	MARK *mp;
-	mtype_t mtype;
+mark_get(
+	SCR *sp,
+	ARG_CHAR_T key,
+	MARK *mp,
+	mtype_t mtype)
 {
 	LMARK *lmp;
 
@@ -155,11 +156,11 @@
  * PUBLIC: int mark_set __P((SCR *, ARG_CHAR_T, MARK *, int));
  */
 int
-mark_set(sp, key, value, userset)
-	SCR *sp;
-	ARG_CHAR_T key;
-	MARK *value;
-	int userset;
+mark_set(
+	SCR *sp,
+	ARG_CHAR_T key,
+	MARK *value,
+	int userset)
 {
 	LMARK *lmp, *lmt;
 
@@ -176,9 +177,9 @@
 	if (lmp == NULL || lmp->name != key) {
 		MALLOC_RET(sp, lmt, LMARK *, sizeof(LMARK));
 		if (lmp == NULL) {
-			LIST_INSERT_HEAD(&sp->ep->marks, lmt, q);
+			SLIST_INSERT_HEAD(sp->ep->marks, lmt, q);
 		} else
-			LIST_INSERT_AFTER(lmp, lmt, q);
+			SLIST_INSERT_AFTER(lmp, lmt, q);
 		lmp = lmt;
 	} else if (!userset &&
 	    !F_ISSET(lmp, MARK_DELETED) && F_ISSET(lmp, MARK_USERSET))
@@ -197,20 +198,21 @@
  *	where it would go.
  */
 static LMARK *
-mark_find(sp, key)
-	SCR *sp;
-	ARG_CHAR_T key;
+mark_find(
+	SCR *sp,
+	ARG_CHAR_T key)
 {
-	LMARK *lmp, *lastlmp;
+	LMARK *lmp, *lastlmp = NULL;
 
 	/*
 	 * 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)
+	SLIST_FOREACH(lmp, sp->ep->marks, q) {
 		if (lmp->name >= key)
 			return (lmp->name == key ? lmp : lastlmp);
+		lastlmp = lmp;
+	}
 	return (lastlmp);
 }
 
@@ -221,10 +223,10 @@
  * PUBLIC: int mark_insdel __P((SCR *, lnop_t, recno_t));
  */
 int
-mark_insdel(sp, op, lno)
-	SCR *sp;
-	lnop_t op;
-	recno_t lno;
+mark_insdel(
+	SCR *sp,
+	lnop_t op,
+	recno_t lno)
 {
 	LMARK *lmp;
 	recno_t lline;
@@ -234,8 +236,7 @@
 		/* 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)
+		SLIST_FOREACH(lmp, sp->ep->marks, q)
 			if (lmp->lno >= lno)
 				if (lmp->lno == lno) {
 					F_SET(lmp, MARK_DELETED);
@@ -265,8 +266,7 @@
 				return (0);
 		}
 
-		for (lmp = sp->ep->marks.lh_first;
-		    lmp != NULL; lmp = lmp->q.le_next)
+		SLIST_FOREACH(lmp, sp->ep->marks, q)
 			if (lmp->lno >= lno)
 				++lmp->lno;
 		break;

Modified: trunk/contrib/nvi/common/mark.h
===================================================================
--- trunk/contrib/nvi/common/mark.h	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/common/mark.h	2018-06-10 20:23:48 UTC (rev 10823)
@@ -6,7 +6,7 @@
  *
  * See the LICENSE file for redistribution information.
  *
- *	@(#)mark.h	10.3 (Berkeley) 3/6/96
+ *	$Id: mark.h,v 10.6 2011/07/04 14:41:51 zy Exp $
  */
 
 /*
@@ -28,9 +28,10 @@
 };
 
 struct _lmark {
-	LIST_ENTRY(_lmark) q;		/* Linked list of marks. */
+	SLIST_ENTRY(_lmark) q;		/* Linked list of marks. */
 	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. */

Modified: trunk/contrib/nvi/common/mem.h
===================================================================
--- trunk/contrib/nvi/common/mem.h	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/common/mem.h	2018-06-10 20:23:48 UTC (rev 10823)
@@ -6,13 +6,21 @@
  *
  * See the LICENSE file for redistribution information.
  *
- *	@(#)mem.h	10.7 (Berkeley) 3/30/96
+ *	$Id: mem.h,v 10.17 2012/10/07 00:40:29 zy Exp $
  */
 
+#ifdef DEBUG
+#define CHECK_TYPE(type, var)						\
+	type L__lp __attribute__((unused)) = var;
+#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, lp, llen, nlen) {					\
+#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)	\
@@ -24,7 +32,12 @@
 		lp = L__bincp;						\
 	}								\
 }
-#define	BINC_RET(sp, lp, llen, nlen) {					\
+#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 ((nlen) > llen) {						\
 		if ((L__bincp = binc(sp, lp, &(llen), nlen)) == NULL)	\
@@ -36,6 +49,10 @@
 		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,
@@ -42,59 +59,79 @@
  * from a malloc'd buffer otherwise.  Two versions, one that returns, one
  * that jumps to an error label.
  */
-#define	GET_SPACE_GOTO(sp, bp, blen, nlen) {				\
+#define	GET_SPACE_GOTO(sp, type, bp, blen, nlen) {			\
+	CHECK_TYPE(type *, bp)						\
 	GS *L__gp = (sp) == NULL ? NULL : (sp)->gp;			\
 	if (L__gp == NULL || F_ISSET(L__gp, G_TMP_INUSE)) {		\
 		bp = NULL;						\
 		blen = 0;						\
-		BINC_GOTO(sp, bp, blen, nlen); 				\
+		BINC_GOTO(sp, type, bp, blen, nlen); 			\
 	} else {							\
-		BINC_GOTO(sp, L__gp->tmp_bp, L__gp->tmp_blen, nlen);	\
-		bp = L__gp->tmp_bp;					\
+		BINC_GOTOC(sp, L__gp->tmp_bp, L__gp->tmp_blen, nlen);	\
+		bp = (type *) L__gp->tmp_bp;				\
 		blen = L__gp->tmp_blen;					\
 		F_SET(L__gp, G_TMP_INUSE);				\
 	}								\
 }
-#define	GET_SPACE_RET(sp, bp, blen, nlen) {				\
+#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)						\
 	GS *L__gp = (sp) == NULL ? NULL : (sp)->gp;			\
 	if (L__gp == NULL || F_ISSET(L__gp, G_TMP_INUSE)) {		\
 		bp = NULL;						\
 		blen = 0;						\
-		BINC_RET(sp, bp, blen, nlen);				\
+		BINC_RET(sp, type, bp, blen, nlen);			\
 	} else {							\
-		BINC_RET(sp, L__gp->tmp_bp, L__gp->tmp_blen, nlen);	\
-		bp = L__gp->tmp_bp;					\
+		BINC_RETC(sp, L__gp->tmp_bp, L__gp->tmp_blen, nlen);	\
+		bp = (type *) L__gp->tmp_bp;				\
 		blen = L__gp->tmp_blen;					\
 		F_SET(L__gp, G_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, bp, blen, nlen) {				\
+#define	ADD_SPACE_GOTO(sp, type, bp, blen, nlen) {			\
+	CHECK_TYPE(type *, bp)						\
 	GS *L__gp = (sp) == NULL ? NULL : (sp)->gp;			\
-	if (L__gp == NULL || bp == L__gp->tmp_bp) {			\
+	if (L__gp == NULL || bp == (type *)L__gp->tmp_bp) {		\
 		F_CLR(L__gp, G_TMP_INUSE);				\
-		BINC_GOTO(sp, L__gp->tmp_bp, L__gp->tmp_blen, nlen);	\
-		bp = L__gp->tmp_bp;					\
+		BINC_GOTOC(sp, L__gp->tmp_bp, L__gp->tmp_blen, nlen);	\
+		bp = (type *) L__gp->tmp_bp;				\
 		blen = L__gp->tmp_blen;					\
 		F_SET(L__gp, G_TMP_INUSE);				\
 	} else								\
-		BINC_GOTO(sp, bp, blen, nlen);				\
+		BINC_GOTO(sp, type, bp, blen, nlen);			\
 }
-#define	ADD_SPACE_RET(sp, bp, blen, nlen) {				\
+#define	ADD_SPACE_GOTOC(sp, bp, blen, nlen)				\
+	ADD_SPACE_GOTO(sp, char, 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)						\
 	GS *L__gp = (sp) == NULL ? NULL : (sp)->gp;			\
-	if (L__gp == NULL || bp == L__gp->tmp_bp) {			\
+	if (L__gp == NULL || bp == (type *)L__gp->tmp_bp) {		\
 		F_CLR(L__gp, G_TMP_INUSE);				\
-		BINC_RET(sp, L__gp->tmp_bp, L__gp->tmp_blen, nlen);	\
-		bp = L__gp->tmp_bp;					\
+		BINC_RETC(sp, L__gp->tmp_bp, L__gp->tmp_blen, nlen);	\
+		bp = (type *) L__gp->tmp_bp;				\
 		blen = L__gp->tmp_blen;					\
 		F_SET(L__gp, G_TMP_INUSE);				\
 	} else								\
-		BINC_RET(sp, bp, blen, nlen);				\
+		BINC_RET(sp, type, bp, blen, nlen);			\
 }
+#define	ADD_SPACE_RETC(sp, bp, blen, nlen)				\
+	ADD_SPACE_RET(sp, char, 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) {					\
@@ -104,6 +141,10 @@
 	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.
@@ -150,19 +191,50 @@
 		return (1);						\
 	}								\
 }
+
 /*
- * XXX
- * Don't depend on realloc(NULL, size) working.
+ * Resize a buffer, free any already held memory if we can't get more.
+ * FreeBSD's reallocf(3) does the same thing, but it's not portable yet.
  */
 #define	REALLOC(sp, p, cast, size) {					\
-	if ((p = (cast)(p == NULL ?					\
-	    malloc(size) : realloc(p, size))) == NULL)			\
+	cast newp;							\
+	if ((newp = (cast)realloc(p, size)) == NULL) {			\
+		if (p != NULL)						\
+			free(p);					\
 		msgq(sp, M_SYSERR, NULL);				\
+	}								\
+	p = newp;							\
 }
 
 /*
- * Versions of memmove(3) and memset(3) that use the size of the
+ * Versions of bcopy(3) and bzero(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)))
+#define	BCOPY(p, t, len)	bcopy(p, t, (len) * sizeof(*(p)))
+#define	BZERO(p, len)		bzero(p, (len) * sizeof(*(p)))
+
+/* 
+ * p2roundup --
+ *	Get next power of 2; convenient for realloc.
+ *
+ * Reference: FreeBSD /usr/src/lib/libc/stdio/getdelim.c
+ */
+static __inline size_t
+p2roundup(size_t n)
+{
+	n--;
+	n |= n >> 1;
+	n |= n >> 2;
+	n |= n >> 4;
+	n |= n >> 8;
+	n |= n >> 16;
+#if SIZE_T_MAX > 0xffffffffU
+	n |= n >> 32;
+#endif
+	n++;
+	return (n);
+}
+
+/* Additional TAILQ helper. */
+#define TAILQ_ENTRY_ISVALID(elm, field)					\
+	((elm)->field.tqe_prev != NULL)

Modified: trunk/contrib/nvi/common/msg.c
===================================================================
--- trunk/contrib/nvi/common/msg.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/common/msg.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -10,14 +10,12 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)msg.c	10.48 (Berkeley) 9/15/96";
+static const char sccsid[] = "$Id: msg.c,v 11.0 2012/10/17 06:34:37 zy Exp $";
 #endif /* not lint */
 
-#include <sys/param.h>
-#include <sys/types.h>		/* XXX: param.h may not have included types.h */
+#include <sys/types.h>
 #include <sys/queue.h>
 #include <sys/stat.h>
-#include <sys/time.h>
 
 #include <bitstring.h>
 #include <ctype.h>
@@ -24,17 +22,13 @@
 #include <errno.h>
 #include <fcntl.h>
 #include <limits.h>
+#include <locale.h>
+#include <stdarg.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 "../vi/vi.h"
 
@@ -45,15 +39,11 @@
  * 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
+msgq(
+	SCR *sp,
+	mtype_t mt,
+	const char *fmt,
+	...)
 {
 #ifndef NL_ARGMAX
 #define	__NL_ARGMAX	20		/* Set to 9 by System V. */
@@ -66,12 +56,17 @@
 	} str[__NL_ARGMAX];
 #endif
 	static int reenter;		/* STATIC: Re-entrancy check. */
-	CHAR_T ch;
 	GS *gp;
-	size_t blen, cnt1, cnt2, len, mlen, nlen, soff;
-	const char *p, *t, *u;
-	char *bp, *mp, *rbp, *s_rbp;
+	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
 
 	/*
 	 * !!!
@@ -130,7 +125,7 @@
 	}
 	bp = NULL;
 	blen = 0;
-	GET_SPACE_GOTO(sp, bp, blen, nlen);
+	GET_SPACE_GOTOC(sp, bp, blen, nlen);
 
 	/*
 	 * Error prefix.
@@ -157,8 +152,12 @@
 	 */
 	if ((mt == M_ERR || mt == M_SYSERR) &&
 	    sp != NULL && gp != NULL && gp->if_name != NULL) {
-		for (p = gp->if_name; *p != '\0'; ++p) {
-			len = snprintf(mp, REM, "%s", KEY_NAME(sp, *p));
+		CHAR_T *wp;
+		size_t wlen;
+
+		CHAR2INT(sp, gp->if_name, strlen(gp->if_name) + 1, wp, wlen);
+		for (; *wp != '\0'; ++wp) {
+			len = snprintf(mp, REM, "%s", KEY_NAME(sp, *wp));
 			mp += len;
 			if ((mlen += len) > blen)
 				goto retry;
@@ -272,12 +271,10 @@
 	fmt = rbp;
 #endif
 
+#ifndef NL_ARGMAX
 format:	/* Format the arguments into the string. */
-#ifdef __STDC__
+#endif
         va_start(ap, fmt);
-#else
-        va_start(ap);
-#endif
 	len = vsnprintf(mp, REM, fmt, ap);
 	va_end(ap);
 	if (len >= nlen)
@@ -347,28 +344,56 @@
 		(void)fprintf(stderr, "%.*s", (int)mlen, bp);
 
 	/* Cleanup. */
-ret:	FREE_SPACE(sp, bp, blen);
+#ifndef NL_ARGMAX
+ret:
+#endif
+	FREE_SPACE(sp, bp, blen);
 alloc_err:
 	reenter = 0;
 }
 
 /*
+ * msgq_wstr --
+ *	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 *));
+ * PUBLIC: void msgq_str __P((SCR *, mtype_t, const char *, const char *));
  */
 void
-msgq_str(sp, mtype, str, fmt)
-	SCR *sp;
-	mtype_t mtype;
-	char *str, *fmt;
+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, fmt);
+		msgq(sp, mtype, "%s", fmt);
 		return;
 	}
 
@@ -401,8 +426,7 @@
  * PUBLIC: void mod_rpt __P((SCR *));
  */
 void
-mod_rpt(sp)
-	SCR *sp;
+mod_rpt(SCR *sp)
 {
 	static char * const action[] = {
 		"293|added",
@@ -461,7 +485,7 @@
 	}
 
 	/* Build and display the message. */
-	GET_SPACE_GOTO(sp, bp, blen, sizeof(action) * MAXNUM + 1);
+	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) {
@@ -512,27 +536,32 @@
  * PUBLIC: void msgq_status __P((SCR *, recno_t, u_int));
  */
 void
-msgq_status(sp, lno, flags)
-	SCR *sp;
-	recno_t lno;
-	u_int flags;
+msgq_status(
+	SCR *sp,
+	recno_t lno,
+	u_int flags)
 {
-	static int poisoned;
 	recno_t last;
 	size_t blen, len;
 	int cnt, needsep;
 	const char *t;
-	char **ap, *bp, *np, *p, *s;
+	char **ap, *bp, *np, *p, *s, *ep;
+	CHAR_T *wp;
+	size_t wlen;
 
 	/* Get sufficient memory. */
 	len = strlen(sp->frp->name);
-	GET_SPACE_GOTO(sp, bp, blen, len * MAX_CHARACTER_COLUMNS + 128);
+	GET_SPACE_GOTOC(sp, bp, blen, len * MAX_CHARACTER_COLUMNS + 128);
 	p = bp;
+	ep = bp + blen;
 
+	/* Convert the filename. */
+	CHAR2INT(sp, sp->frp->name, len + 1, wp, wlen);
+
 	/* 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);
+	for (; *wp != '\0'; ++wp) {
+		len = KEY_LEN(sp, *wp);
+		memcpy(p, KEY_NAME(sp, *wp), len);
 		p += len;
 	}
 	np = p;
@@ -543,7 +572,7 @@
 	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,
+			(void)snprintf(p, ep - p,
 			    msg_cat(sp, "317|%d files to edit", NULL), cnt);
 			p += strlen(p);
 			*p++ = ':';
@@ -617,18 +646,18 @@
 			memcpy(p, t, len);
 			p += len;
 		} else {
-			t = msg_cat(sp, "027|line %lu of %lu [%lu%%]", &len);
-			(void)sprintf(p, t, (u_long)lno, (u_long)last,
-			    (u_long)(lno * 100) / last);
+			t = msg_cat(sp, "027|line %lu of %lu [%ld%%]", &len);
+			(void)snprintf(p, ep - p, t, lno, last,
+			    ((u_long)lno * 100) / last);
 			p += strlen(p);
 		}
 	} else {
 		t = msg_cat(sp, "029|line %lu", &len);
-		(void)sprintf(p, t, (u_long)lno);
+		(void)snprintf(p, ep - p, t, (u_long)lno);
 		p += strlen(p);
 	}
 #ifdef DEBUG
-	(void)sprintf(p, " (pid %lu)", (u_long)getpid());
+	(void)snprintf(p, ep - p, " (pid %lu)", (u_long)getpid());
 	p += strlen(p);
 #endif
 	*p++ = '\n';
@@ -679,9 +708,9 @@
  * PUBLIC: int msg_open __P((SCR *, char *));
  */
 int
-msg_open(sp, file)
-	SCR *sp;
-	char *file;
+msg_open(
+	SCR *sp,
+	char *file)
 {
 	/*
 	 * !!!
@@ -693,54 +722,50 @@
 	 * message will be repeated every time nvi is started up.
 	 */
 	static int first = 1;
-	DB *db;
-	DBT data, key;
-	recno_t msgno;
-	char *p, *t, buf[MAXPATHLEN];
+	nl_catd catd;
+	char *p;
+	int rval = 0;
 
-	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 ((db = dbopen(p,
-	    O_NONBLOCK | O_RDONLY, 0, DB_RECNO, NULL)) == NULL) {
-		if (first) {
-			first = 0;
+	if ((p = strrchr(file, '/')) != NULL && p[1] == '\0') {
+		/* Confirms to XPG4. */
+		if ((p = join(file, setlocale(LC_MESSAGES, NULL))) == NULL) {
+			msgq(sp, M_SYSERR, NULL);
 			return (1);
 		}
-		msgq_str(sp, M_SYSERR, p, "%s");
-		return (1);
+	} else {
+		/* Make sure it's recognized as a path by catopen(3). */
+		if ((p = join(".", file)) == NULL) {
+			msgq(sp, M_SYSERR, NULL);
+			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"
-	key.data = &msgno;
-	key.size = sizeof(recno_t);
-	msgno = 1;
-	if (db->get(db, &key, &data, 0) != 0 ||
-	    data.size != sizeof(VMC) - 1 ||
-	    memcmp(data.data, VMC, sizeof(VMC) - 1)) {
-		(void)db->close(db);
+	errno = 0;
+	if ((catd = catopen(p, NL_CAT_LOCALE)) == (nl_catd)-1) {
 		if (first) {
 			first = 0;
-			return (1);
+			rval = 1;
+			goto ret;
 		}
-		msgq_str(sp, M_ERR, p,
-		    "030|The file %s is not a message catalog");
-		return (1);
+
+		/*
+		 * POSIX.1-2008 gives no instruction on how to report a
+		 * corrupt catalog file.  Errno == 0 is not rare; add
+		 * EFTYPE, which is seen on FreeBSD, for a good measure.
+		 */
+		if (errno == 0 || errno == EFTYPE)
+			msgq_str(sp, M_ERR, p,
+			    "030|The file %s is not a message catalog");
+		else
+			msgq_str(sp, M_SYSERR, p, "%s");
+		rval = 1;
+		goto ret;
 	}
 	first = 0;
 
-	if (sp->gp->msg != NULL)
-		(void)sp->gp->msg->close(sp->gp->msg);
-	sp->gp->msg = db;
-	return (0);
+	msg_close(sp->gp);
+	sp->gp->catd = catd;
+ret:	free(p);
+	return (rval);
 }
 
 /*
@@ -750,11 +775,10 @@
  * PUBLIC: void msg_close __P((GS *));
  */
 void
-msg_close(gp)
-	GS *gp;
+msg_close(GS *gp)
 {
-	if (gp->msg != NULL)
-		(void)gp->msg->close(gp->msg);
+	if (gp->catd != (nl_catd)-1)
+		(void)catclose(gp->catd);
 }
 
 /*
@@ -764,10 +788,10 @@
  * PUBLIC: const char *msg_cmsg __P((SCR *, cmsg_t, size_t *));
  */
 const char *
-msg_cmsg(sp, which, lenp)
-	SCR *sp;
-	cmsg_t which;
-	size_t *lenp;
+msg_cmsg(
+	SCR *sp,
+	cmsg_t which,
+	size_t *lenp)
 {
 	switch (which) {
 	case CMSG_CONF:
@@ -802,14 +826,14 @@
  * PUBLIC: const char *msg_cat __P((SCR *, const char *, size_t *));
  */
 const char *
-msg_cat(sp, str, lenp)
-	SCR *sp;
-	const char *str;
-	size_t *lenp;
+msg_cat(
+	SCR *sp,
+	const char *str,
+	size_t *lenp)
 {
 	GS *gp;
-	DBT data, key;
-	recno_t msgno;
+	char *p;
+	int msgno;
 
 	/*
 	 * If it's not a catalog message, i.e. has doesn't have a leading
@@ -817,28 +841,16 @@
 	 */
 	if (isdigit(str[0]) &&
 	    isdigit(str[1]) && isdigit(str[2]) && str[3] == '|') {
-		key.data = &msgno;
-		key.size = sizeof(recno_t);
 		msgno = atoi(str);
+		str = &str[4];
 
-		/*
-		 * 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, &key, &data, 0) == 0 &&
-		    data.size != 0) {
+		if (gp != NULL && gp->catd != (nl_catd)-1 &&
+		    (p = catgets(gp->catd, 1, msgno, str)) != NULL) {
 			if (lenp != NULL)
-				*lenp = data.size - 1;
-			((char *)data.data)[data.size - 1] = '\0';
-			return (data.data);
+				*lenp = strlen(p);
+			return (p);
 		}
-		str = &str[4];
 	}
 	if (lenp != NULL)
 		*lenp = strlen(str);
@@ -852,19 +864,22 @@
  * PUBLIC: char *msg_print __P((SCR *, const char *, int *));
  */
 char *
-msg_print(sp, s, needfree)
-	SCR *sp;
-	const char *s;
-	int *needfree;
+msg_print(
+	SCR *sp,
+	const char *s,
+	int *needfree)
 {
 	size_t blen, nlen;
-	const char *cp;
 	char *bp, *ep, *p, *t;
+	CHAR_T *wp, *cp;
+	size_t wlen;
 
 	*needfree = 0;
 
-	for (cp = s; *cp != '\0'; ++cp)
-		if (!isprint(*cp))
+	/* XXX Not good for debugging ex_read & ex_filter.*/
+	CHAR2INT5(sp, EXP(sp)->ibcw, (char *)s, strlen(s) + 1, wp, wlen);
+	for (cp = wp; *cp != '\0'; ++cp)
+		if (!ISPRINT(*cp))
 			break;
 	if (*cp == '\0')
 		return ((char *)s);	/* SAFE: needfree set to 0. */
@@ -875,7 +890,7 @@
 			free(bp);
 		else
 			FREE_SPACE(sp, bp, blen);
-		needfree = 0;
+		*needfree = 0;
 	}
 	nlen += 256;
 	if (sp == NULL) {
@@ -882,14 +897,14 @@
 		if ((bp = malloc(nlen)) == NULL)
 			goto alloc_err;
 	} else
-		GET_SPACE_GOTO(sp, bp, blen, nlen);
+		GET_SPACE_GOTOC(sp, bp, blen, nlen);
 	if (0) {
 alloc_err:	return ("");
 	}
 	*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++);
+	for (p = bp, ep = (bp + blen) - 1; *wp != '\0' && p < ep; ++wp)
+		for (t = KEY_NAME(sp, *wp); *t != '\0' && p < ep; *p++ = *t++);
 	if (p == ep)
 		goto retry;
 	*p = '\0';

Modified: trunk/contrib/nvi/common/msg.h
===================================================================
--- trunk/contrib/nvi/common/msg.h	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/common/msg.h	2018-06-10 20:23:48 UTC (rev 10823)
@@ -52,9 +52,9 @@
  * messages.
  */
 typedef struct _msgh MSGH;	/* MSGS list head structure. */
-LIST_HEAD(_msgh, _msg);
+SLIST_HEAD(_msgh, _msg);
 struct _msg {
-	LIST_ENTRY(_msg) q;	/* Linked list of messages. */
+	SLIST_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. */

Added: trunk/contrib/nvi/common/multibyte.h
===================================================================
--- trunk/contrib/nvi/common/multibyte.h	                        (rev 0)
+++ trunk/contrib/nvi/common/multibyte.h	2018-06-10 20:23:48 UTC (rev 10823)
@@ -0,0 +1,115 @@
+/*-
+ * 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: multibyte.h,v 1.32 2012/10/07 01:35:58 zy Exp $
+ */
+
+#ifndef MULTIBYTE_H
+#define MULTIBYTE_H
+
+/*
+ * 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.
+ * UCHAR_T	The shortest unified character type (8-bit clean).
+ * RCHAR_T	The character type used by the internal regex engine.
+ *
+ * If no integral type can hold a character, don't even try the port.
+ */
+typedef	int		ARG_CHAR_T;
+
+#ifdef USE_WIDECHAR
+#include <wchar.h>
+#include <wctype.h>
+
+typedef	wchar_t		CHAR_T;
+typedef	wint_t		UCHAR_T;
+typedef wchar_t 	RCHAR_T;
+#define REOF		WEOF
+
+#define STRLEN		wcslen
+#define STRTOL		wcstol
+#define STRTOUL		wcstoul
+#define SPRINTF		swprintf
+#define STRCMP		wcscmp
+#define STRPBRK		wcspbrk
+#define ISBLANK		iswblank
+#define ISCNTRL		iswcntrl
+#define ISDIGIT		iswdigit
+#define ISXDIGIT	iswxdigit
+#define ISGRAPH		iswgraph
+#define ISLOWER		iswlower
+#define ISPRINT		iswprint
+#define ISPUNCT		iswpunct
+#define ISSPACE		iswspace
+#define ISUPPER		iswupper
+#define TOLOWER		towlower
+#define TOUPPER		towupper
+#define STRSET		wmemset
+#define STRCHR		wcschr
+#define STRRCHR		wcsrchr
+#define GETC		getwc
+
+#define L(ch)		L ## ch
+#define WS		"%ls"
+#define WVS		"%*ls"
+#define WC		"%lc"
+
+#else
+typedef	u_char		CHAR_T;
+typedef	u_char		UCHAR_T;
+typedef	char		RCHAR_T;
+#define REOF		EOF
+
+#define STRLEN		strlen
+#define STRTOL(a,b,c)	(strtol(a,(char**)b,c))
+#define STRTOUL(a,b,c)	(strtoul(a,(char**)b,c))
+#define SPRINTF		snprintf
+#define STRCMP		strcmp
+#define STRPBRK		strpbrk
+#define ISBLANK		isblank
+#define ISCNTRL		iscntrl
+#define ISDIGIT		isdigit
+#define ISXDIGIT	isxdigit
+#define ISGRAPH		isgraph
+#define ISLOWER		islower
+#define ISPRINT		isprint
+#define ISPUNCT		ispunct
+#define ISSPACE		isspace
+#define ISUPPER		isupper
+#define TOLOWER		tolower
+#define TOUPPER		toupper
+#define STRSET		memset
+#define STRCHR		strchr
+#define STRRCHR		strrchr
+#define GETC		getc
+
+#define L(ch)		ch
+#define WS		"%s"
+#define WVS		"%*s"
+#define WC		"%c"
+
+#endif
+
+#if defined(USE_WIDECHAR) && defined(DEBUG)
+#define MEMCPY			wmemcpy
+#define MEMMOVE			wmemmove
+#define MEMCMP			wmemcmp
+#else
+#define MEMCPY(p, t, len)	memcpy(p, t, (len) * sizeof(CHAR_T))
+#define MEMMOVE(p, t, len)	memmove(p, t, (len) * sizeof(CHAR_T))
+#define MEMCMP(p, t, len)	memcmp(p, t, (len) * sizeof(CHAR_T))
+#endif
+
+#define SIZE(w)			(sizeof(w) / sizeof(*w))
+
+#endif


Property changes on: trunk/contrib/nvi/common/multibyte.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Modified: trunk/contrib/nvi/common/options.c
===================================================================
--- trunk/contrib/nvi/common/options.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/common/options.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -10,13 +10,12 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)options.c	10.51 (Berkeley) 10/14/96";
+static const char sccsid[] = "$Id: options.c,v 10.73 2012/10/09 06:14:07 zy Exp $";
 #endif /* not lint */
 
 #include <sys/types.h>
 #include <sys/queue.h>
 #include <sys/stat.h>
-#include <sys/time.h>
 
 #include <bitstring.h>
 #include <ctype.h>
@@ -35,6 +34,12 @@
 static int	 	 opts_cmp __P((const void *, const void *));
 static int	 	 opts_print __P((SCR *, OPTLIST const *));
 
+#ifdef USE_WIDECHAR
+#define OPT_WC	    0
+#else
+#define OPT_WC	    (OPT_NOSAVE | OPT_NDISP)
+#endif
+
 /*
  * O'Reilly noted options and abbreviations are from "Learning the VI Editor",
  * Fifth Edition, May 1992.  There's no way of knowing what systems they are
@@ -45,77 +50,81 @@
  */
 OPTLIST const optlist[] = {
 /* O_ALTWERASE	  4.4BSD */
-	{"altwerase",	f_altwerase,	OPT_0BOOL,	0},
+	{L("altwerase"),	f_altwerase,	OPT_0BOOL,	0},
 /* O_AUTOINDENT	    4BSD */
-	{"autoindent",	NULL,		OPT_0BOOL,	0},
+	{L("autoindent"),	NULL,		OPT_0BOOL,	0},
 /* O_AUTOPRINT	    4BSD */
-	{"autoprint",	NULL,		OPT_1BOOL,	0},
+	{L("autoprint"),	NULL,		OPT_1BOOL,	0},
 /* O_AUTOWRITE	    4BSD */
-	{"autowrite",	NULL,		OPT_0BOOL,	0},
+	{L("autowrite"),	NULL,		OPT_0BOOL,	0},
 /* O_BACKUP	  4.4BSD */
-	{"backup",	NULL,		OPT_STR,	0},
+	{L("backup"),	NULL,		OPT_STR,	0},
 /* O_BEAUTIFY	    4BSD */
-	{"beautify",	NULL,		OPT_0BOOL,	0},
+	{L("beautify"),	NULL,		OPT_0BOOL,	0},
 /* O_CDPATH	  4.4BSD */
-	{"cdpath",	NULL,		OPT_STR,	0},
+	{L("cdpath"),	NULL,		OPT_STR,	0},
 /* O_CEDIT	  4.4BSD */
-	{"cedit",	NULL,		OPT_STR,	0},
+	{L("cedit"),	NULL,		OPT_STR,	0},
 /* O_COLUMNS	  4.4BSD */
-	{"columns",	f_columns,	OPT_NUM,	OPT_NOSAVE},
+	{L("columns"),	f_columns,	OPT_NUM,	OPT_NOSAVE},
+/* O_COMBINED */
+	{L("combined"),	NULL,		OPT_0BOOL,	OPT_NOSET|OPT_WC},
 /* O_COMMENT	  4.4BSD */
-	{"comment",	NULL,		OPT_0BOOL,	0},
-/* O_DIRECTORY	    4BSD */
-	{"directory",	NULL,		OPT_STR,	0},
+	{L("comment"),	NULL,		OPT_0BOOL,	0},
+/* O_TMPDIR	    4BSD */
+	{L("directory"),	NULL,		OPT_STR,	0},
 /* O_EDCOMPATIBLE   4BSD */
-	{"edcompatible",NULL,		OPT_0BOOL,	0},
+	{L("edcompatible"),NULL,		OPT_0BOOL,	0},
+/* O_ERRORBELLS	    4BSD */
+	{L("errorbells"),	NULL,		OPT_0BOOL,	0},
 /* O_ESCAPETIME	  4.4BSD */
-	{"escapetime",	NULL,		OPT_NUM,	0},
-/* O_ERRORBELLS	    4BSD */
-	{"errorbells",	NULL,		OPT_0BOOL,	0},
+	{L("escapetime"),	NULL,		OPT_NUM,	0},
 /* O_EXRC	System V (undocumented) */
-	{"exrc",	NULL,		OPT_0BOOL,	0},
+	{L("exrc"),	NULL,		OPT_0BOOL,	0},
 /* O_EXTENDED	  4.4BSD */
-	{"extended",	f_recompile,	OPT_0BOOL,	0},
+	{L("extended"),	f_recompile,	OPT_0BOOL,	0},
 /* O_FILEC	  4.4BSD */
-	{"filec",	NULL,		OPT_STR,	0},
+	{L("filec"),	NULL,		OPT_STR,	0},
+/* O_FILEENCODING */
+	{L("fileencoding"),f_encoding,	OPT_STR,	OPT_WC},
 /* O_FLASH	    HPUX */
-	{"flash",	NULL,		OPT_1BOOL,	0},
-#ifdef GTAGS
-/* O_GTAGSMODE      FreeBSD2.2 */
-	{"gtagsmode",	NULL,		OPT_0BOOL,	0},
-#endif
+	{L("flash"),	NULL,		OPT_1BOOL,	0},
 /* O_HARDTABS	    4BSD */
-	{"hardtabs",	NULL,		OPT_NUM,	0},
+	{L("hardtabs"),	NULL,		OPT_NUM,	0},
 /* O_ICLOWER	  4.4BSD */
-	{"iclower",	f_recompile,	OPT_0BOOL,	0},
+	{L("iclower"),	f_recompile,	OPT_0BOOL,	0},
 /* O_IGNORECASE	    4BSD */
-	{"ignorecase",	f_recompile,	OPT_0BOOL,	0},
+	{L("ignorecase"),	f_recompile,	OPT_0BOOL,	0},
+/* O_INPUTENCODING */
+	{L("inputencoding"),f_encoding,	OPT_STR,	OPT_WC},
 /* O_KEYTIME	  4.4BSD */
-	{"keytime",	NULL,		OPT_NUM,	0},
+	{L("keytime"),	NULL,		OPT_NUM,	0},
 /* O_LEFTRIGHT	  4.4BSD */
-	{"leftright",	f_reformat,	OPT_0BOOL,	0},
+	{L("leftright"),	f_reformat,	OPT_0BOOL,	0},
 /* O_LINES	  4.4BSD */
-	{"lines",	f_lines,	OPT_NUM,	OPT_NOSAVE},
+	{L("lines"),	f_lines,	OPT_NUM,	OPT_NOSAVE},
 /* O_LISP	    4BSD
  *	XXX
  *	When the lisp option is implemented, delete the OPT_NOSAVE flag,
  *	so that :mkexrc dumps it.
  */
-	{"lisp",	f_lisp,		OPT_0BOOL,	OPT_NOSAVE},
+	{L("lisp"),	f_lisp,		OPT_0BOOL,	OPT_NOSAVE},
 /* O_LIST	    4BSD */
-	{"list",	f_reformat,	OPT_0BOOL,	0},
+	{L("list"),	f_reformat,	OPT_0BOOL,	0},
 /* O_LOCKFILES	  4.4BSD
  *	XXX
  *	Locking isn't reliable enough over NFS to require it, in addition,
  *	it's a serious startup performance problem over some remote links.
  */
-	{"lock",	NULL,		OPT_1BOOL,	0},
+	{L("lock"),	NULL,		OPT_1BOOL,	0},
 /* O_MAGIC	    4BSD */
-	{"magic",	NULL,		OPT_1BOOL,	0},
+	{L("magic"),	NULL,		OPT_1BOOL,	0},
+/* O_MATCHCHARS	  NetBSD 2.0 */
+	{L("matchchars"),	NULL,		OPT_STR,	OPT_PAIRS},
 /* O_MATCHTIME	  4.4BSD */
-	{"matchtime",	NULL,		OPT_NUM,	0},
+	{L("matchtime"),	NULL,		OPT_NUM,	0},
 /* O_MESG	    4BSD */
-	{"mesg",	NULL,		OPT_1BOOL,	0},
+	{L("mesg"),	NULL,		OPT_1BOOL,	0},
 /* O_MODELINE	    4BSD
  *	!!!
  *	This has been documented in historical systems as both "modeline"
@@ -124,61 +133,61 @@
  *	example of what your intro CS professor referred to as the perils of
  *	mixing code and data.  Don't add it, or I will kill you.
  */
-	{"modeline",	NULL,		OPT_0BOOL,	OPT_NOSET},
+	{L("modeline"),	NULL,		OPT_0BOOL,	OPT_NOSET},
 /* O_MSGCAT	  4.4BSD */
-	{"msgcat",	f_msgcat,	OPT_STR,	0},
+	{L("msgcat"),	f_msgcat,	OPT_STR,	0},
 /* O_NOPRINT	  4.4BSD */
-	{"noprint",	f_print,	OPT_STR,	0},
+	{L("noprint"),	f_print,	OPT_STR,	0},
 /* O_NUMBER	    4BSD */
-	{"number",	f_reformat,	OPT_0BOOL,	0},
+	{L("number"),	f_reformat,	OPT_0BOOL,	0},
 /* O_OCTAL	  4.4BSD */
-	{"octal",	f_print,	OPT_0BOOL,	0},
+	{L("octal"),	f_print,	OPT_0BOOL,	0},
 /* O_OPEN	    4BSD */
-	{"open",	NULL,		OPT_1BOOL,	0},
+	{L("open"),	NULL,		OPT_1BOOL,	0},
 /* O_OPTIMIZE	    4BSD */
-	{"optimize",	NULL,		OPT_1BOOL,	0},
+	{L("optimize"),	NULL,		OPT_1BOOL,	0},
 /* O_PARAGRAPHS	    4BSD */
-	{"paragraphs",	f_paragraph,	OPT_STR,	0},
+	{L("paragraphs"),	NULL,		OPT_STR,	OPT_PAIRS},
 /* O_PATH	  4.4BSD */
-	{"path",	NULL,		OPT_STR,	0},
+	{L("path"),	NULL,		OPT_STR,	0},
 /* O_PRINT	  4.4BSD */
-	{"print",	f_print,	OPT_STR,	0},
+	{L("print"),	f_print,	OPT_STR,	0},
 /* O_PROMPT	    4BSD */
-	{"prompt",	NULL,		OPT_1BOOL,	0},
+	{L("prompt"),	NULL,		OPT_1BOOL,	0},
 /* O_READONLY	    4BSD (undocumented) */
-	{"readonly",	f_readonly,	OPT_0BOOL,	OPT_ALWAYS},
+	{L("readonly"),	f_readonly,	OPT_0BOOL,	OPT_ALWAYS},
 /* O_RECDIR	  4.4BSD */
-	{"recdir",	NULL,		OPT_STR,	0},
+	{L("recdir"),	NULL,		OPT_STR,	0},
 /* O_REDRAW	    4BSD */
-	{"redraw",	NULL,		OPT_0BOOL,	0},
+	{L("redraw"),	NULL,		OPT_0BOOL,	0},
 /* O_REMAP	    4BSD */
-	{"remap",	NULL,		OPT_1BOOL,	0},
+	{L("remap"),	NULL,		OPT_1BOOL,	0},
 /* O_REPORT	    4BSD */
-	{"report",	NULL,		OPT_NUM,	0},
+	{L("report"),	NULL,		OPT_NUM,	0},
 /* O_RULER	  4.4BSD */
-	{"ruler",	NULL,		OPT_0BOOL,	0},
+	{L("ruler"),	NULL,		OPT_0BOOL,	0},
 /* O_SCROLL	    4BSD */
-	{"scroll",	NULL,		OPT_NUM,	0},
+	{L("scroll"),	NULL,		OPT_NUM,	0},
 /* O_SEARCHINCR	  4.4BSD */
-	{"searchincr",	NULL,		OPT_0BOOL,	0},
+	{L("searchincr"),	NULL,		OPT_0BOOL,	0},
 /* O_SECTIONS	    4BSD */
-	{"sections",	f_section,	OPT_STR,	0},
+	{L("sections"),	NULL,		OPT_STR,	OPT_PAIRS},
 /* O_SECURE	  4.4BSD */
-	{"secure",	NULL,		OPT_0BOOL,	OPT_NOUNSET},
+	{L("secure"),	NULL,		OPT_0BOOL,	OPT_NOUNSET},
 /* O_SHELL	    4BSD */
-	{"shell",	NULL,		OPT_STR,	0},
+	{L("shell"),	NULL,		OPT_STR,	0},
 /* O_SHELLMETA	  4.4BSD */
-	{"shellmeta",	NULL,		OPT_STR,	0},
+	{L("shellmeta"),	NULL,		OPT_STR,	0},
 /* O_SHIFTWIDTH	    4BSD */
-	{"shiftwidth",	NULL,		OPT_NUM,	OPT_NOZERO},
+	{L("shiftwidth"),	NULL,		OPT_NUM,	OPT_NOZERO},
 /* O_SHOWMATCH	    4BSD */
-	{"showmatch",	NULL,		OPT_0BOOL,	0},
+	{L("showmatch"),	NULL,		OPT_0BOOL,	0},
 /* O_SHOWMODE	  4.4BSD */
-	{"showmode",	NULL,		OPT_0BOOL,	0},
+	{L("showmode"),	NULL,		OPT_0BOOL,	0},
 /* O_SIDESCROLL	  4.4BSD */
-	{"sidescroll",	NULL,		OPT_NUM,	OPT_NOZERO},
+	{L("sidescroll"),	NULL,		OPT_NUM,	OPT_NOZERO},
 /* O_SLOWOPEN	    4BSD  */
-	{"slowopen",	NULL,		OPT_0BOOL,	0},
+	{L("slowopen"),	NULL,		OPT_0BOOL,	0},
 /* O_SOURCEANY	    4BSD (undocumented)
  *	!!!
  *	Historic vi, on startup, source'd $HOME/.exrc and ./.exrc, if they
@@ -187,98 +196,97 @@
  *	.exrc files the user didn't own.  This is an obvious security problem,
  *	and we ignore the option.
  */
-	{"sourceany",	NULL,		OPT_0BOOL,	OPT_NOSET},
+	{L("sourceany"),	NULL,		OPT_0BOOL,	OPT_NOSET},
 /* O_TABSTOP	    4BSD */
-	{"tabstop",	f_reformat,	OPT_NUM,	OPT_NOZERO},
+	{L("tabstop"),	f_reformat,	OPT_NUM,	OPT_NOZERO},
 /* O_TAGLENGTH	    4BSD */
-	{"taglength",	NULL,		OPT_NUM,	0},
+	{L("taglength"),	NULL,		OPT_NUM,	0},
 /* O_TAGS	    4BSD */
-	{"tags",	NULL,		OPT_STR,	0},
+	{L("tags"),	NULL,		OPT_STR,	0},
 /* O_TERM	    4BSD
  *	!!!
  *	By default, the historic vi always displayed information about two
  *	options, redraw and term.  Term seems sufficient.
  */
-	{"term",	NULL,		OPT_STR,	OPT_ADISP|OPT_NOSAVE},
+	{L("term"),	NULL,		OPT_STR,	OPT_ADISP|OPT_NOSAVE},
 /* O_TERSE	    4BSD */
-	{"terse",	NULL,		OPT_0BOOL,	0},
+	{L("terse"),	NULL,		OPT_0BOOL,	0},
 /* O_TILDEOP      4.4BSD */
-	{"tildeop",	NULL,		OPT_0BOOL,	0},
+	{L("tildeop"),	NULL,		OPT_0BOOL,	0},
 /* O_TIMEOUT	    4BSD (undocumented) */
-	{"timeout",	NULL,		OPT_1BOOL,	0},
+	{L("timeout"),	NULL,		OPT_1BOOL,	0},
 /* O_TTYWERASE	  4.4BSD */
-	{"ttywerase",	f_ttywerase,	OPT_0BOOL,	0},
+	{L("ttywerase"),	f_ttywerase,	OPT_0BOOL,	0},
 /* O_VERBOSE	  4.4BSD */
-	{"verbose",	NULL,		OPT_0BOOL,	0},
+	{L("verbose"),	NULL,		OPT_0BOOL,	0},
 /* O_W1200	    4BSD */
-	{"w1200",	f_w1200,	OPT_NUM,	OPT_NDISP|OPT_NOSAVE},
+	{L("w1200"),	f_w1200,	OPT_NUM,	OPT_NDISP|OPT_NOSAVE},
 /* O_W300	    4BSD */
-	{"w300",	f_w300,		OPT_NUM,	OPT_NDISP|OPT_NOSAVE},
+	{L("w300"),	f_w300,		OPT_NUM,	OPT_NDISP|OPT_NOSAVE},
 /* O_W9600	    4BSD */
-	{"w9600",	f_w9600,	OPT_NUM,	OPT_NDISP|OPT_NOSAVE},
+	{L("w9600"),	f_w9600,	OPT_NUM,	OPT_NDISP|OPT_NOSAVE},
 /* O_WARN	    4BSD */
-	{"warn",	NULL,		OPT_1BOOL,	0},
+	{L("warn"),	NULL,		OPT_1BOOL,	0},
 /* O_WINDOW	    4BSD */
-	{"window",	f_window,	OPT_NUM,	0},
+	{L("window"),	f_window,	OPT_NUM,	0},
 /* O_WINDOWNAME	    4BSD */
-	{"windowname",	NULL,		OPT_0BOOL,	0},
+	{L("windowname"),	NULL,		OPT_0BOOL,	0},
 /* O_WRAPLEN	  4.4BSD */
-	{"wraplen",	NULL,		OPT_NUM,	0},
+	{L("wraplen"),	NULL,		OPT_NUM,	0},
 /* O_WRAPMARGIN	    4BSD */
-	{"wrapmargin",	NULL,		OPT_NUM,	0},
+	{L("wrapmargin"),	NULL,		OPT_NUM,	0},
 /* O_WRAPSCAN	    4BSD */
-	{"wrapscan",	NULL,		OPT_1BOOL,	0},
+	{L("wrapscan"),	NULL,		OPT_1BOOL,	0},
 /* O_WRITEANY	    4BSD */
-	{"writeany",	NULL,		OPT_0BOOL,	0},
+	{L("writeany"),	NULL,		OPT_0BOOL,	0},
 	{NULL},
 };
 
 typedef struct abbrev {
-        char *name;
+        CHAR_T *name;
         int offset;
 } OABBREV;
 
 static OABBREV const abbrev[] = {
-	{"ai",		O_AUTOINDENT},		/*     4BSD */
-	{"ap",		O_AUTOPRINT},		/*     4BSD */
-	{"aw",		O_AUTOWRITE},		/*     4BSD */
-	{"bf",		O_BEAUTIFY},		/*     4BSD */
-	{"co",		O_COLUMNS},		/*   4.4BSD */
-	{"dir",		O_DIRECTORY},		/*     4BSD */
-	{"eb",		O_ERRORBELLS},		/*     4BSD */
-	{"ed",		O_EDCOMPATIBLE},	/*     4BSD */
-	{"ex",		O_EXRC},		/* System V (undocumented) */
-#ifdef GTAGS
-	{"gt",		O_GTAGSMODE},		/* FreeBSD2.2 */
-#endif
-	{"ht",		O_HARDTABS},		/*     4BSD */
-	{"ic",		O_IGNORECASE},		/*     4BSD */
-	{"li",		O_LINES},		/*   4.4BSD */
-	{"modelines",	O_MODELINE},		/*     HPUX */
-	{"nu",		O_NUMBER},		/*     4BSD */
-	{"opt",		O_OPTIMIZE},		/*     4BSD */
-	{"para",	O_PARAGRAPHS},		/*     4BSD */
-	{"re",		O_REDRAW},		/* O'Reilly */
-	{"ro",		O_READONLY},		/*     4BSD (undocumented) */
-	{"scr",		O_SCROLL},		/*     4BSD (undocumented) */
-	{"sect",	O_SECTIONS},		/* O'Reilly */
-	{"sh",		O_SHELL},		/*     4BSD */
-	{"slow",	O_SLOWOPEN},		/*     4BSD */
-	{"sm",		O_SHOWMATCH},		/*     4BSD */
-	{"smd",		O_SHOWMODE},		/*     4BSD */
-	{"sw",		O_SHIFTWIDTH},		/*     4BSD */
-	{"tag",		O_TAGS},		/*     4BSD (undocumented) */
-	{"tl",		O_TAGLENGTH},		/*     4BSD */
-	{"to",		O_TIMEOUT},		/*     4BSD (undocumented) */
-	{"ts",		O_TABSTOP},		/*     4BSD */
-	{"tty",		O_TERM},		/*     4BSD (undocumented) */
-	{"ttytype",	O_TERM},		/*     4BSD (undocumented) */
-	{"w",		O_WINDOW},		/* O'Reilly */
-	{"wa",		O_WRITEANY},		/*     4BSD */
-	{"wi",		O_WINDOW},		/*     4BSD (undocumented) */
-	{"wl",		O_WRAPLEN},		/*   4.4BSD */
-	{"wm",		O_WRAPMARGIN},		/*     4BSD */
-	{"ws",		O_WRAPSCAN},		/*     4BSD */
+	{L("ai"),	O_AUTOINDENT},		/*     4BSD */
+	{L("ap"),	O_AUTOPRINT},		/*     4BSD */
+	{L("aw"),	O_AUTOWRITE},		/*     4BSD */
+	{L("bf"),	O_BEAUTIFY},		/*     4BSD */
+	{L("co"),	O_COLUMNS},		/*   4.4BSD */
+	{L("dir"),	O_TMPDIR},		/*     4BSD */
+	{L("eb"),	O_ERRORBELLS},		/*     4BSD */
+	{L("ed"),	O_EDCOMPATIBLE},	/*     4BSD */
+	{L("ex"),	O_EXRC},		/* System V (undocumented) */
+	{L("fe"),	O_FILEENCODING},
+	{L("ht"),	O_HARDTABS},		/*     4BSD */
+	{L("ic"),	O_IGNORECASE},		/*     4BSD */
+	{L("ie"),	O_INPUTENCODING},
+	{L("li"),	O_LINES},		/*   4.4BSD */
+	{L("modelines"),	O_MODELINE},		/*     HPUX */
+	{L("nu"),	O_NUMBER},		/*     4BSD */
+	{L("opt"),	O_OPTIMIZE},		/*     4BSD */
+	{L("para"),	O_PARAGRAPHS},		/*     4BSD */
+	{L("re"),	O_REDRAW},		/* O'Reilly */
+	{L("ro"),	O_READONLY},		/*     4BSD (undocumented) */
+	{L("scr"),	O_SCROLL},		/*     4BSD (undocumented) */
+	{L("sect"),	O_SECTIONS},		/* O'Reilly */
+	{L("sh"),	O_SHELL},		/*     4BSD */
+	{L("slow"),	O_SLOWOPEN},		/*     4BSD */
+	{L("sm"),	O_SHOWMATCH},		/*     4BSD */
+	{L("smd"),	O_SHOWMODE},		/*     4BSD */
+	{L("sw"),	O_SHIFTWIDTH},		/*     4BSD */
+	{L("tag"),	O_TAGS},		/*     4BSD (undocumented) */
+	{L("tl"),	O_TAGLENGTH},		/*     4BSD */
+	{L("to"),	O_TIMEOUT},		/*     4BSD (undocumented) */
+	{L("ts"),	O_TABSTOP},		/*     4BSD */
+	{L("tty"),	O_TERM},		/*     4BSD (undocumented) */
+	{L("ttytype"),	O_TERM},		/*     4BSD (undocumented) */
+	{L("w"),	O_WINDOW},		/* O'Reilly */
+	{L("wa"),	O_WRITEANY},		/*     4BSD */
+	{L("wi"),	O_WINDOW},		/*     4BSD (undocumented) */
+	{L("wl"),	O_WRAPLEN},		/*   4.4BSD */
+	{L("wm"),	O_WRAPMARGIN},		/*     4BSD */
+	{L("ws"),	O_WRAPSCAN},		/*     4BSD */
 	{NULL},
 };
 
@@ -289,17 +297,18 @@
  * PUBLIC: int opts_init __P((SCR *, int *));
  */
 int
-opts_init(sp, oargs)
-	SCR *sp;
-	int *oargs;
+opts_init(
+	SCR *sp,
+	int *oargs)
 {
 	ARGS *argv[2], a, b;
 	OPTLIST const *op;
 	u_long v;
-	int cnt, optindx;
-	char *s, b1[1024];
+	int cnt, optindx = 0;
+	char *s;
+	CHAR_T b2[1024];
 
-	a.bp = b1;
+	a.bp = b2;
 	b.bp = NULL;
 	a.len = b.len = 0;
 	argv[0] = &a;
@@ -307,9 +316,9 @@
 
 	/* Set numeric and string default values. */
 #define	OI(indx, str) {							\
-	if (str != b1)		/* GCC puts strings in text-space. */	\
-		(void)strcpy(b1, str);					\
-	a.len = strlen(b1);						\
+	a.len = STRLEN(str);						\
+	if ((CHAR_T*)str != b2)	  /* GCC puts strings in text-space. */	\
+		(void)MEMCPY(b2, str, a.len+1);				\
 	if (opts_set(sp, argv, NULL)) {					\
 		 optindx = indx;					\
 		goto err;						\
@@ -334,9 +343,10 @@
 	F_SET(&sp->opts[O_SECURE], OPT_GLOBAL);
 
 	/* Initialize string values. */
-	(void)snprintf(b1, sizeof(b1),
-	    "cdpath=%s", (s = getenv("CDPATH")) == NULL ? ":" : s);
-	OI(O_CDPATH, b1);
+	(void)SPRINTF(b2, SIZE(b2),
+	    L("cdpath=%s"), (s = getenv("CDPATH")) == NULL ? ":" : s);
+	OI(O_CDPATH, b2);
+	OI(O_CEDIT, L("cedit=\033"));
 
 	/*
 	 * !!!
@@ -345,30 +355,32 @@
 	 * are two ways to change this -- the user can set either the directory
 	 * option or the TMPDIR environmental variable.
 	 */
-	(void)snprintf(b1, sizeof(b1),
-	    "directory=%s", (s = getenv("TMPDIR")) == NULL ? _PATH_TMP : s);
-	OI(O_DIRECTORY, b1);
-	OI(O_ESCAPETIME, "escapetime=6");
-	OI(O_KEYTIME, "keytime=6");
-	OI(O_MATCHTIME, "matchtime=7");
-	(void)snprintf(b1, sizeof(b1), "msgcat=%s", _PATH_MSGCAT);
-	OI(O_MSGCAT, b1);
-	OI(O_REPORT, "report=5");
-	OI(O_PARAGRAPHS, "paragraphs=IPLPPPQPP LIpplpipbp");
-	(void)snprintf(b1, sizeof(b1), "path=%s", "");
-	OI(O_PATH, b1);
-	(void)snprintf(b1, sizeof(b1), "recdir=%s", _PATH_PRESERVE);
-	OI(O_RECDIR, b1);
-	OI(O_SECTIONS, "sections=NHSHH HUnhsh");
-	(void)snprintf(b1, sizeof(b1),
-	    "shell=%s", (s = getenv("SHELL")) == NULL ? _PATH_BSHELL : s);
-	OI(O_SHELL, b1);
-	OI(O_SHELLMETA, "shellmeta=~{[*?$`'\"\\");
-	OI(O_SHIFTWIDTH, "shiftwidth=8");
-	OI(O_SIDESCROLL, "sidescroll=16");
-	OI(O_TABSTOP, "tabstop=8");
-	(void)snprintf(b1, sizeof(b1), "tags=%s", _PATH_TAGS);
-	OI(O_TAGS, b1);
+	(void)SPRINTF(b2, SIZE(b2),
+	    L("directory=%s"), (s = getenv("TMPDIR")) == NULL ? _PATH_TMP : s);
+	OI(O_TMPDIR, b2);
+	OI(O_ESCAPETIME, L("escapetime=6"));
+	OI(O_FILEC, L("filec=\t"));
+	OI(O_KEYTIME, L("keytime=6"));
+	OI(O_MATCHCHARS, L("matchchars=()[]{}"));
+	OI(O_MATCHTIME, L("matchtime=7"));
+	(void)SPRINTF(b2, SIZE(b2), L("msgcat=%s"), _PATH_MSGCAT);
+	OI(O_MSGCAT, b2);
+	OI(O_REPORT, L("report=5"));
+	OI(O_PARAGRAPHS, L("paragraphs=IPLPPPQPP LIpplpipbp"));
+	(void)SPRINTF(b2, SIZE(b2), L("path=%s"), "");
+	OI(O_PATH, b2);
+	(void)SPRINTF(b2, SIZE(b2), L("recdir=%s"), _PATH_PRESERVE);
+	OI(O_RECDIR, b2);
+	OI(O_SECTIONS, L("sections=NHSHH HUnhsh"));
+	(void)SPRINTF(b2, SIZE(b2),
+	    L("shell=%s"), (s = getenv("SHELL")) == NULL ? _PATH_BSHELL : s);
+	OI(O_SHELL, b2);
+	OI(O_SHELLMETA, L("shellmeta=~{[*?$`'\"\\"));
+	OI(O_SHIFTWIDTH, L("shiftwidth=8"));
+	OI(O_SIDESCROLL, L("sidescroll=16"));
+	OI(O_TABSTOP, L("tabstop=8"));
+	(void)SPRINTF(b2, SIZE(b2), L("tags=%s"), _PATH_TAGS);
+	OI(O_TAGS, b2);
 
 	/*
 	 * XXX
@@ -377,8 +389,8 @@
 	 */
 	if ((v = (O_VAL(sp, O_LINES) - 1) / 2) == 0)
 		v = 1;
-	(void)snprintf(b1, sizeof(b1), "scroll=%ld", v);
-	OI(O_SCROLL, b1);
+	(void)SPRINTF(b2, SIZE(b2), L("scroll=%ld"), v);
+	OI(O_SCROLL, b2);
 
 	/*
 	 * The default window option values are:
@@ -395,16 +407,19 @@
 		v = 8;
 	else if (v <= 1200)
 		v = 16;
-	else
-		v = O_VAL(sp, O_LINES) - 1;
-	(void)snprintf(b1, sizeof(b1), "window=%lu", v);
-	OI(O_WINDOW, b1);
+	else if ((v = O_VAL(sp, O_LINES) - 1) == 0)
+		v = 1;
 
+	(void)SPRINTF(b2, SIZE(b2), L("window=%lu"), v);
+	OI(O_WINDOW, b2);
+
 	/*
 	 * Set boolean default values, and copy all settings into the default
 	 * information.  OS_NOFREE is set, we're copying, not replacing.
 	 */
-	for (op = optlist, cnt = 0; op->name != NULL; ++op, ++cnt)
+	for (op = optlist, cnt = 0; op->name != NULL; ++op, ++cnt) {
+		if (F_ISSET(op, OPT_GLOBAL))
+			continue;
 		switch (op->type) {
 		case OPT_0BOOL:
 			break;
@@ -423,6 +438,7 @@
 		default:
 			abort();
 		}
+	}
 
 	/*
 	 * !!!
@@ -432,11 +448,11 @@
 	 */
 	for (; *oargs != -1; ++oargs)
 		OI(*oargs, optlist[*oargs].name);
+#undef OI
 	return (0);
-#undef OI
 
-err:	msgq(sp, M_ERR,
-	    "031|Unable to set default %s option", optlist[optindx].name);
+err:	msgq_wstr(sp, M_ERR, optlist[optindx].name,
+	    "031|Unable to set default %s option");
 	return (1);
 }
 
@@ -447,18 +463,21 @@
  * PUBLIC: int opts_set __P((SCR *, ARGS *[], char *));
  */
 int
-opts_set(sp, argv, usage)
-	SCR *sp;
-	ARGS *argv[];
-	char *usage;
+opts_set(
+	SCR *sp,
+	ARGS *argv[],
+	char *usage)
 {
 	enum optdisp disp;
 	enum nresult nret;
 	OPTLIST const *op;
 	OPTION *spo;
-	u_long value, turnoff;
+	u_long isset, turnoff, value;
 	int ch, equals, nf, nf2, offset, qmark, rval;
-	char *endp, *name, *p, *sep, *t;
+	CHAR_T *endp, *name, *p, *sep;
+	char *p2, *t2;
+	char *np;
+	size_t nlen;
 
 	disp = NO_DISPLAY;
 	for (rval = 0; argv[0]->len != 0; ++argv) {
@@ -466,7 +485,7 @@
 		 * The historic vi dumped the options for each occurrence of
 		 * "all" in the set list.  Puhleeze.
 		 */
-		if (!strcmp(argv[0]->bp, "all")) {
+		if (!STRCMP(argv[0]->bp, L("all"))) {
 			disp = ALL_DISPLAY;
 			continue;
 		}
@@ -528,7 +547,7 @@
 		case OPT_1BOOL:
 			/* Some options may not be reset. */
 			if (F_ISSET(op, OPT_NOUNSET) && turnoff) {
-				msgq_str(sp, M_ERR, name,
+				msgq_wstr(sp, M_ERR, name,
 			    "291|set: the %s option may not be turned off");
 				rval = 1;
 				break;
@@ -536,7 +555,7 @@
 
 			/* Some options may not be set. */
 			if (F_ISSET(op, OPT_NOSET) && !turnoff) {
-				msgq_str(sp, M_ERR, name,
+				msgq_wstr(sp, M_ERR, name,
 			    "313|set: the %s option may never be turned on");
 				rval = 1;
 				break;
@@ -543,7 +562,7 @@
 			}
 
 			if (equals) {
-				msgq_str(sp, M_ERR, name,
+				msgq_wstr(sp, M_ERR, name,
 			    "034|set: [no]%s option doesn't take a value");
 				rval = 1;
 				break;
@@ -559,34 +578,34 @@
 			 * Do nothing if the value is unchanged, the underlying
 			 * functions can be expensive.
 			 */
+			isset = !turnoff;
 			if (!F_ISSET(op, OPT_ALWAYS))
-				if (turnoff) {
+				if (isset) {
+					if (O_ISSET(sp, offset))
+						break;
+				} else
 					if (!O_ISSET(sp, offset))
 						break;
-				} else {
-					if (O_ISSET(sp, offset))
-						break;
-				}
 
 			/* Report to subsystems. */
-			if (op->func != NULL &&
-			    op->func(sp, spo, NULL, &turnoff) ||
-			    ex_optchange(sp, offset, NULL, &turnoff) ||
-			    v_optchange(sp, offset, NULL, &turnoff) ||
-			    sp->gp->scr_optchange(sp, offset, NULL, &turnoff)) {
+			if ((op->func != NULL &&
+			    op->func(sp, spo, NULL, &isset)) ||
+			    ex_optchange(sp, offset, NULL, &isset) ||
+			    v_optchange(sp, offset, NULL, &isset) ||
+			    sp->gp->scr_optchange(sp, offset, NULL, &isset)) {
 				rval = 1;
 				break;
 			}
 
 			/* Set the value. */
-			if (turnoff)
+			if (isset)
+				O_SET(sp, offset);
+			else
 				O_CLR(sp, offset);
-			else
-				O_SET(sp, offset);
 			break;
 		case OPT_NUM:
 			if (turnoff) {
-				msgq_str(sp, M_ERR, name,
+				msgq_wstr(sp, M_ERR, name,
 				    "035|set: %s option isn't a boolean");
 				rval = 1;
 				break;
@@ -598,20 +617,24 @@
 				break;
 			}
 
-			if (!isdigit(sep[0]))
+			if (!ISDIGIT(sep[0]))
 				goto badnum;
 			if ((nret =
 			    nget_uslong(&value, sep, &endp, 10)) != NUM_OK) {
-				p = msg_print(sp, name, &nf);
-				t = msg_print(sp, sep, &nf2);
+				INT2CHAR(sp, name, STRLEN(name) + 1, 
+					     np, nlen);
+				p2 = msg_print(sp, np, &nf);
+				INT2CHAR(sp, sep, STRLEN(sep) + 1, 
+					     np, nlen);
+				t2 = msg_print(sp, np, &nf2);
 				switch (nret) {
 				case NUM_ERR:
 					msgq(sp, M_SYSERR,
-					    "036|set: %s option: %s", p, t);
+					    "036|set: %s option: %s", p2, t2);
 					break;
 				case NUM_OVER:
 					msgq(sp, M_ERR,
-			    "037|set: %s option: %s: value overflow", p, t);
+			    "037|set: %s option: %s: value overflow", p2, t2);
 					break;
 				case NUM_OK:
 				case NUM_UNDER:
@@ -618,21 +641,25 @@
 					abort();
 				}
 				if (nf)
-					FREE_SPACE(sp, p, 0);
+					FREE_SPACE(sp, p2, 0);
 				if (nf2)
-					FREE_SPACE(sp, t, 0);
+					FREE_SPACE(sp, t2, 0);
 				rval = 1;
 				break;
 			}
-			if (*endp && !isblank(*endp)) {
-badnum:				p = msg_print(sp, name, &nf);
-				t = msg_print(sp, sep, &nf2);
+			if (*endp && !cmdskip(*endp)) {
+badnum:				INT2CHAR(sp, name, STRLEN(name) + 1, 
+					     np, nlen);
+				p2 = msg_print(sp, np, &nf);
+				INT2CHAR(sp, sep, STRLEN(sep) + 1, 
+					     np, nlen);
+				t2 = msg_print(sp, np, &nf2);
 				msgq(sp, M_ERR,
-		    "038|set: %s option: %s is an illegal number", p, t);
+		    "038|set: %s option: %s is an illegal number", p2, t2);
 				if (nf)
-					FREE_SPACE(sp, p, 0);
+					FREE_SPACE(sp, p2, 0);
 				if (nf2)
-					FREE_SPACE(sp, t, 0);
+					FREE_SPACE(sp, t2, 0);
 				rval = 1;
 				break;
 			}
@@ -639,7 +666,7 @@
 
 			/* Some options may never be set to zero. */
 			if (F_ISSET(op, OPT_NOZERO) && value == 0) {
-				msgq_str(sp, M_ERR, name,
+				msgq_wstr(sp, M_ERR, name,
 			    "314|set: the %s option may never be set to 0");
 				rval = 1;
 				break;
@@ -654,11 +681,12 @@
 				break;
 
 			/* Report to subsystems. */
-			if (op->func != NULL &&
-			    op->func(sp, spo, sep, &value) ||
-			    ex_optchange(sp, offset, sep, &value) ||
-			    v_optchange(sp, offset, sep, &value) ||
-			    sp->gp->scr_optchange(sp, offset, sep, &value)) {
+			INT2CHAR(sp, sep, STRLEN(sep) + 1, np, nlen);
+			if ((op->func != NULL &&
+			    op->func(sp, spo, np, &value)) ||
+			    ex_optchange(sp, offset, np, &value) ||
+			    v_optchange(sp, offset, np, &value) ||
+			    sp->gp->scr_optchange(sp, offset, np, &value)) {
 				rval = 1;
 				break;
 			}
@@ -669,7 +697,7 @@
 			break;
 		case OPT_STR:
 			if (turnoff) {
-				msgq_str(sp, M_ERR, name,
+				msgq_wstr(sp, M_ERR, name,
 				    "039|set: %s option isn't a boolean");
 				rval = 1;
 				break;
@@ -681,27 +709,36 @@
 				break;
 			}
 
+			/* Check for strings that must have even length. */
+			if (F_ISSET(op, OPT_PAIRS) && STRLEN(sep) & 1) {
+				msgq_wstr(sp, M_ERR, name,
+				    "047|The %s option must be in two character groups");
+				rval = 1;
+				break;
+			}
+
 			/*
 			 * Do nothing if the value is unchanged, the underlying
 			 * functions can be expensive.
 			 */
+			INT2CHAR(sp, sep, STRLEN(sep) + 1, np, nlen);
 			if (!F_ISSET(op, OPT_ALWAYS) &&
 			    O_STR(sp, offset) != NULL &&
-			    !strcmp(O_STR(sp, offset), sep))
+			    !strcmp(O_STR(sp, offset), np))
 				break;
 
 			/* Report to subsystems. */
-			if (op->func != NULL &&
-			    op->func(sp, spo, sep, NULL) ||
-			    ex_optchange(sp, offset, sep, NULL) ||
-			    v_optchange(sp, offset, sep, NULL) ||
-			    sp->gp->scr_optchange(sp, offset, sep, NULL)) {
+			if ((op->func != NULL &&
+			    op->func(sp, spo, np, NULL)) ||
+			    ex_optchange(sp, offset, np, NULL) ||
+			    v_optchange(sp, offset, np, NULL) ||
+			    sp->gp->scr_optchange(sp, offset, np, NULL)) {
 				rval = 1;
 				break;
 			}
 
 			/* Set the value. */
-			if (o_set(sp, offset, OS_STRDUP, sep, 0))
+			if (o_set(sp, offset, OS_STRDUP, np, 0))
 				rval = 1;
 			break;
 		default:
@@ -720,12 +757,12 @@
  * PUBLIC: int o_set __P((SCR *, int, u_int, char *, u_long));
  */
 int
-o_set(sp, opt, flags, str, val)
-	SCR *sp;
-	int opt;
-	u_int flags;
-	char *str;
-	u_long val;
+o_set(
+	SCR *sp,
+	int opt,
+	u_int flags,
+	char *str,
+	u_long val)
 {
 	OPTION *op;
 
@@ -764,15 +801,16 @@
  * PUBLIC: int opts_empty __P((SCR *, int, int));
  */
 int
-opts_empty(sp, off, silent)
-	SCR *sp;
-	int off, silent;
+opts_empty(
+	SCR *sp,
+	int off,
+	int silent)
 {
 	char *p;
 
 	if ((p = O_STR(sp, off)) == NULL || p[0] == '\0') {
 		if (!silent)
-			msgq_str(sp, M_ERR, optlist[off].name,
+			msgq_wstr(sp, M_ERR, optlist[off].name,
 			    "305|No %s edit option specified");
 		return (1);
 	}
@@ -786,9 +824,9 @@
  * PUBLIC: void opts_dump __P((SCR *, enum optdisp));
  */
 void
-opts_dump(sp, type)
-	SCR *sp;
-	enum optdisp type;
+opts_dump(
+	SCR *sp,
+	enum optdisp type)
 {
 	OPTLIST const *op;
 	int base, b_num, cnt, col, colwidth, curlen, s_num;
@@ -843,8 +881,8 @@
 				break;
 			case OPT_STR:
 				if (O_STR(sp, cnt) == O_D_STR(sp, cnt) ||
-				    O_D_STR(sp, cnt) != NULL &&
-				    !strcmp(O_STR(sp, cnt), O_D_STR(sp, cnt)))
+				    (O_D_STR(sp, cnt) != NULL &&
+				    !strcmp(O_STR(sp, cnt), O_D_STR(sp, cnt))))
 					continue;
 				break;
 			}
@@ -859,7 +897,7 @@
 		}
 		F_CLR(&sp->opts[cnt], OPT_SELECTED);
 
-		curlen = strlen(op->name);
+		curlen = STRLEN(op->name);
 		switch (op->type) {
 		case OPT_0BOOL:
 		case OPT_1BOOL:
@@ -920,9 +958,9 @@
  *	Print out an option.
  */
 static int
-opts_print(sp, op)
-	SCR *sp;
-	OPTLIST const *op;
+opts_print(
+	SCR *sp,
+	OPTLIST const *op)
 {
 	int curlen, offset;
 
@@ -932,13 +970,13 @@
 	case OPT_0BOOL:
 	case OPT_1BOOL:
 		curlen += ex_printf(sp,
-		    "%s%s", O_ISSET(sp, offset) ? "" : "no", op->name);
+		    "%s"WS, O_ISSET(sp, offset) ? "" : "no", op->name);
 		break;
 	case OPT_NUM:
-		curlen += ex_printf(sp, "%s=%ld", op->name, O_VAL(sp, offset));
+		curlen += ex_printf(sp, WS"=%ld", op->name, O_VAL(sp, offset));
 		break;
 	case OPT_STR:
-		curlen += ex_printf(sp, "%s=\"%s\"", op->name,
+		curlen += ex_printf(sp, WS"=\"%s\"", op->name,
 		    O_STR(sp, offset) == NULL ? "" : O_STR(sp, offset));
 		break;
 	}
@@ -952,13 +990,14 @@
  * PUBLIC: int opts_save __P((SCR *, FILE *));
  */
 int
-opts_save(sp, fp)
-	SCR *sp;
-	FILE *fp;
+opts_save(
+	SCR *sp,
+	FILE *fp)
 {
 	OPTLIST const *op;
-	int ch, cnt;
-	char *p;
+	CHAR_T ch, *p;
+	char nch, *np;
+	int cnt;
 
 	for (op = optlist; op->name != NULL; ++op) {
 		if (F_ISSET(op, OPT_NOSAVE))
@@ -968,13 +1007,13 @@
 		case OPT_0BOOL:
 		case OPT_1BOOL:
 			if (O_ISSET(sp, cnt))
-				(void)fprintf(fp, "set %s\n", op->name);
+				(void)fprintf(fp, "set "WS"\n", op->name);
 			else
-				(void)fprintf(fp, "set no%s\n", op->name);
+				(void)fprintf(fp, "set no"WS"\n", op->name);
 			break;
 		case OPT_NUM:
 			(void)fprintf(fp,
-			    "set %s=%-3ld\n", op->name, O_VAL(sp, cnt));
+			    "set "WS"=%-3ld\n", op->name, O_VAL(sp, cnt));
 			break;
 		case OPT_STR:
 			if (O_STR(sp, cnt) == NULL)
@@ -981,15 +1020,15 @@
 				break;
 			(void)fprintf(fp, "set ");
 			for (p = op->name; (ch = *p) != '\0'; ++p) {
-				if (isblank(ch) || ch == '\\')
+				if (cmdskip(ch) || ch == '\\')
 					(void)putc('\\', fp);
-				(void)putc(ch, fp);
+				fprintf(fp, WC, ch);
 			}
 			(void)putc('=', fp);
-			for (p = O_STR(sp, cnt); (ch = *p) != '\0'; ++p) {
-				if (isblank(ch) || ch == '\\')
+			for (np = O_STR(sp, cnt); (nch = *np) != '\0'; ++np) {
+				if (cmdskip(nch) || nch == '\\')
 					(void)putc('\\', fp);
-				(void)putc(ch, fp);
+				(void)putc(nch, fp);
 			}
 			(void)putc('\n', fp);
 			break;
@@ -1006,11 +1045,10 @@
  * opts_search --
  *	Search for an option.
  *
- * PUBLIC: OPTLIST const *opts_search __P((char *));
+ * PUBLIC: OPTLIST const *opts_search __P((CHAR_T *));
  */
 OPTLIST const *
-opts_search(name)
-	char *name;
+opts_search(CHAR_T *name)
 {
 	OPTLIST const *op, *found;
 	OABBREV atmp, *ap;
@@ -1033,13 +1071,13 @@
 	 * Check to see if the name is the prefix of one (and only one)
 	 * option.  If so, return the option.
 	 */
-	len = strlen(name);
+	len = STRLEN(name);
 	for (found = NULL, op = optlist; op->name != NULL; ++op) {
 		if (op->name[0] < name[0])
 			continue;
 		if (op->name[0] > name[0])
 			break;
-		if (!memcmp(op->name, name, len)) {
+		if (!MEMCMP(op->name, name, len)) {
 			if (found != NULL)
 				return (NULL);
 			found = op;
@@ -1052,29 +1090,31 @@
  * opts_nomatch --
  *	Standard nomatch error message for options.
  *
- * PUBLIC: void opts_nomatch __P((SCR *, char *));
+ * PUBLIC: void opts_nomatch __P((SCR *, CHAR_T *));
  */
 void
-opts_nomatch(sp, name)
-	SCR *sp;
-	char *name;
+opts_nomatch(
+	SCR *sp,
+	CHAR_T *name)
 {
-	msgq_str(sp, M_ERR, name,
+	msgq_wstr(sp, M_ERR, name,
 	    "033|set: no %s option: 'set all' gives all option values");
 }
 
 static int
-opts_abbcmp(a, b)
-        const void *a, *b;
+opts_abbcmp(
+        const void *a,
+		const void *b)
 {
-        return(strcmp(((OABBREV *)a)->name, ((OABBREV *)b)->name));
+        return(STRCMP(((OABBREV *)a)->name, ((OABBREV *)b)->name));
 }
 
 static int
-opts_cmp(a, b)
-        const void *a, *b;
+opts_cmp(
+        const void *a,
+		const void *b)
 {
-        return(strcmp(((OPTLIST *)a)->name, ((OPTLIST *)b)->name));
+        return(STRCMP(((OPTLIST *)a)->name, ((OPTLIST *)b)->name));
 }
 
 /*
@@ -1084,8 +1124,9 @@
  * PUBLIC: int opts_copy __P((SCR *, SCR *));
  */
 int
-opts_copy(orig, sp)
-	SCR *orig, *sp;
+opts_copy(
+	SCR *orig,
+	SCR *sp)
 {
 	int cnt, rval;
 
@@ -1095,7 +1136,7 @@
 	/* Copy the string edit options. */
 	for (cnt = rval = 0; cnt < O_OPTIONCOUNT; ++cnt) {
 		if (optlist[cnt].type != OPT_STR ||
-		    F_ISSET(&optlist[cnt], OPT_GLOBAL))
+		    F_ISSET(&sp->opts[cnt], OPT_GLOBAL))
 			continue;
 		/*
 		 * If never set, or already failed, NULL out the entries --
@@ -1131,14 +1172,13 @@
  * PUBLIC: void opts_free __P((SCR *));
  */
 void
-opts_free(sp)
-	SCR *sp;
+opts_free(SCR *sp)
 {
 	int cnt;
 
 	for (cnt = 0; cnt < O_OPTIONCOUNT; ++cnt) {
 		if (optlist[cnt].type != OPT_STR ||
-		    F_ISSET(&optlist[cnt], OPT_GLOBAL))
+		    F_ISSET(&sp->opts[cnt], OPT_GLOBAL))
 			continue;
 		if (O_STR(sp, cnt) != NULL)
 			free(O_STR(sp, cnt));

Modified: trunk/contrib/nvi/common/options.h
===================================================================
--- trunk/contrib/nvi/common/options.h	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/common/options.h	2018-06-10 20:23:48 UTC (rev 10823)
@@ -6,7 +6,7 @@
  *
  * See the LICENSE file for redistribution information.
  *
- *	@(#)options.h	10.19 (Berkeley) 10/10/96
+ *	$Id: options.h,v 10.21 2012/02/10 20:24:58 zy Exp $
  */
 
 /*
@@ -76,7 +76,7 @@
 
 /* List of option names, associated update functions and information. */
 struct _optlist {
-	char	*name;			/* Name. */
+	CHAR_T	*name;			/* Name. */
 					/* Change function. */
 	int	(*func) __P((SCR *, OPTION *, char *, u_long *));
 					/* Type of object. */
@@ -89,6 +89,7 @@
 #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;
 };
 

Added: trunk/contrib/nvi/common/options_def.h
===================================================================
--- trunk/contrib/nvi/common/options_def.h	                        (rev 0)
+++ trunk/contrib/nvi/common/options_def.h	2018-06-10 20:23:48 UTC (rev 10823)
@@ -0,0 +1,83 @@
+#define O_ALTWERASE 0
+#define O_AUTOINDENT 1
+#define O_AUTOPRINT 2
+#define O_AUTOWRITE 3
+#define O_BACKUP 4
+#define O_BEAUTIFY 5
+#define O_CDPATH 6
+#define O_CEDIT 7
+#define O_COLUMNS 8
+#define O_COMBINED 9
+#define O_COMMENT 10
+#define O_TMPDIR 11
+#define O_EDCOMPATIBLE 12
+#define O_ERRORBELLS 13
+#define O_ESCAPETIME 14
+#define O_EXRC 15
+#define O_EXTENDED 16
+#define O_FILEC 17
+#define O_FILEENCODING 18
+#define O_FLASH 19
+#define O_HARDTABS 20
+#define O_ICLOWER 21
+#define O_IGNORECASE 22
+#define O_INPUTENCODING 23
+#define O_KEYTIME 24
+#define O_LEFTRIGHT 25
+#define O_LINES 26
+#define O_LISP 27
+#define O_LIST 28
+#define O_LOCKFILES 29
+#define O_MAGIC 30
+#define O_MATCHCHARS 31
+#define O_MATCHTIME 32
+#define O_MESG 33
+#define O_MODELINE 34
+#define O_MSGCAT 35
+#define O_NOPRINT 36
+#define O_NUMBER 37
+#define O_OCTAL 38
+#define O_OPEN 39
+#define O_OPTIMIZE 40
+#define O_PARAGRAPHS 41
+#define O_PATH 42
+#define O_PRINT 43
+#define O_PROMPT 44
+#define O_READONLY 45
+#define O_RECDIR 46
+#define O_REDRAW 47
+#define O_REMAP 48
+#define O_REPORT 49
+#define O_RULER 50
+#define O_SCROLL 51
+#define O_SEARCHINCR 52
+#define O_SECTIONS 53
+#define O_SECURE 54
+#define O_SHELL 55
+#define O_SHELLMETA 56
+#define O_SHIFTWIDTH 57
+#define O_SHOWMATCH 58
+#define O_SHOWMODE 59
+#define O_SIDESCROLL 60
+#define O_SLOWOPEN 61
+#define O_SOURCEANY 62
+#define O_TABSTOP 63
+#define O_TAGLENGTH 64
+#define O_TAGS 65
+#define O_TERM 66
+#define O_TERSE 67
+#define O_TILDEOP 68
+#define O_TIMEOUT 69
+#define O_TTYWERASE 70
+#define O_VERBOSE 71
+#define O_W1200 72
+#define O_W300 73
+#define O_W9600 74
+#define O_WARN 75
+#define O_WINDOW 76
+#define O_WINDOWNAME 77
+#define O_WRAPLEN 78
+#define O_WRAPMARGIN 79
+#define O_WRAPSCAN 80
+#define O_WRITEANY 81
+#define O_OPTIONCOUNT 82


Property changes on: trunk/contrib/nvi/common/options_def.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Modified: trunk/contrib/nvi/common/options_f.c
===================================================================
--- trunk/contrib/nvi/common/options_f.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/common/options_f.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -10,7 +10,7 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)options_f.c	10.25 (Berkeley) 7/12/96";
+static const char sccsid[] = "$Id: options_f.c,v 10.34 04/07/11 16:06:29 zy Exp $";
 #endif /* not lint */
 
 #include <sys/types.h>
@@ -32,13 +32,13 @@
  * PUBLIC: int f_altwerase __P((SCR *, OPTION *, char *, u_long *));
  */
 int
-f_altwerase(sp, op, str, valp)
-	SCR *sp;
-	OPTION *op;
-	char *str;
-	u_long *valp;
+f_altwerase(
+	SCR *sp,
+	OPTION *op,
+	char *str,
+	u_long *valp)
 {
-	if (!*valp)
+	if (*valp)
 		O_CLR(sp, O_TTYWERASE);
 	return (0);
 }
@@ -47,11 +47,11 @@
  * PUBLIC: int f_columns __P((SCR *, OPTION *, char *, u_long *));
  */
 int
-f_columns(sp, op, str, valp)
-	SCR *sp;
-	OPTION *op;
-	char *str;
-	u_long *valp;
+f_columns(
+	SCR *sp,
+	OPTION *op,
+	char *str,
+	u_long *valp)
 {
 	/* Validate the number. */
 	if (*valp < MINIMUM_SCREEN_COLS) {
@@ -81,11 +81,11 @@
  * PUBLIC: int f_lines __P((SCR *, OPTION *, char *, u_long *));
  */
 int
-f_lines(sp, op, str, valp)
-	SCR *sp;
-	OPTION *op;
-	char *str;
-	u_long *valp;
+f_lines(
+	SCR *sp,
+	OPTION *op,
+	char *str,
+	u_long *valp)
 {
 	/* Validate the number. */
 	if (*valp < MINIMUM_SCREEN_ROWS) {
@@ -138,11 +138,11 @@
  * PUBLIC: int f_lisp __P((SCR *, OPTION *, char *, u_long *));
  */
 int
-f_lisp(sp, op, str, valp)
-	SCR *sp;
-	OPTION *op;
-	char *str;
-	u_long *valp;
+f_lisp(
+	SCR *sp,
+	OPTION *op,
+	char *str,
+	u_long *valp)
 {
 	msgq(sp, M_ERR, "044|The lisp option is not implemented");
 	return (0);
@@ -152,11 +152,11 @@
  * PUBLIC: int f_msgcat __P((SCR *, OPTION *, char *, u_long *));
  */
 int
-f_msgcat(sp, op, str, valp)
-	SCR *sp;
-	OPTION *op;
-	char *str;
-	u_long *valp;
+f_msgcat(
+	SCR *sp,
+	OPTION *op,
+	char *str,
+	u_long *valp)
 {
 	(void)msg_open(sp, str);
 	return (0);
@@ -163,33 +163,26 @@
 }
 
 /*
- * PUBLIC: int f_paragraph __P((SCR *, OPTION *, char *, u_long *));
+ * PUBLIC: int f_print __P((SCR *, OPTION *, char *, u_long *));
  */
 int
-f_paragraph(sp, op, str, valp)
-	SCR *sp;
-	OPTION *op;
-	char *str;
-	u_long *valp;
+f_print(
+	SCR *sp,
+	OPTION *op,
+	char *str,
+	u_long *valp)
 {
-	if (strlen(str) & 1) {
-		msgq(sp, M_ERR,
-		    "048|The paragraph option must be in two character groups");
-		return (1);
-	}
-	return (0);
-}
+	int offset = op - sp->opts;
 
-/*
- * PUBLIC: int f_print __P((SCR *, OPTION *, char *, u_long *));
- */
-int
-f_print(sp, op, str, valp)
-	SCR *sp;
-	OPTION *op;
-	char *str;
-	u_long *valp;
-{
+	/* 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);
 
@@ -202,11 +195,11 @@
  * PUBLIC: int f_readonly __P((SCR *, OPTION *, char *, u_long *));
  */
 int
-f_readonly(sp, op, str, valp)
-	SCR *sp;
-	OPTION *op;
-	char *str;
-	u_long *valp;
+f_readonly(
+	SCR *sp,
+	OPTION *op,
+	char *str,
+	u_long *valp)
 {
 	/*
 	 * !!!
@@ -213,9 +206,9 @@
 	 * See the comment in exf.c.
 	 */
 	if (*valp)
+		F_SET(sp, SC_READONLY);
+	else
 		F_CLR(sp, SC_READONLY);
-	else
-		F_SET(sp, SC_READONLY);
 	return (0);
 }
 
@@ -223,11 +216,11 @@
  * PUBLIC: int f_recompile __P((SCR *, OPTION *, char *, u_long *));
  */
 int
-f_recompile(sp, op, str, valp)
-	SCR *sp;
-	OPTION *op;
-	char *str;
-	u_long *valp;
+f_recompile(
+	SCR *sp,
+	OPTION *op,
+	char *str,
+	u_long *valp)
 {
 	if (F_ISSET(sp, SC_RE_SEARCH)) {
 		regfree(&sp->re_c);
@@ -244,11 +237,11 @@
  * PUBLIC: int f_reformat __P((SCR *, OPTION *, char *, u_long *));
  */
 int
-f_reformat(sp, op, str, valp)
-	SCR *sp;
-	OPTION *op;
-	char *str;
-	u_long *valp;
+f_reformat(
+	SCR *sp,
+	OPTION *op,
+	char *str,
+	u_long *valp)
 {
 	F_SET(sp, SC_SCR_REFORMAT);
 	return (0);
@@ -255,34 +248,16 @@
 }
 
 /*
- * PUBLIC: int f_section __P((SCR *, OPTION *, char *, u_long *));
- */
-int
-f_section(sp, op, str, valp)
-	SCR *sp;
-	OPTION *op;
-	char *str;
-	u_long *valp;
-{
-	if (strlen(str) & 1) {
-		msgq(sp, M_ERR,
-		    "049|The section option must be in two character groups");
-		return (1);
-	}
-	return (0);
-}
-
-/*
  * PUBLIC: int f_ttywerase __P((SCR *, OPTION *, char *, u_long *));
  */
 int
-f_ttywerase(sp, op, str, valp)
-	SCR *sp;
-	OPTION *op;
-	char *str;
-	u_long *valp;
+f_ttywerase(
+	SCR *sp,
+	OPTION *op,
+	char *str,
+	u_long *valp)
 {
-	if (!*valp)
+	if (*valp)
 		O_CLR(sp, O_ALTWERASE);
 	return (0);
 }
@@ -291,11 +266,11 @@
  * PUBLIC: int f_w300 __P((SCR *, OPTION *, char *, u_long *));
  */
 int
-f_w300(sp, op, str, valp)
-	SCR *sp;
-	OPTION *op;
-	char *str;
-	u_long *valp;
+f_w300(
+	SCR *sp,
+	OPTION *op,
+	char *str,
+	u_long *valp)
 {
 	u_long v;
 
@@ -312,11 +287,11 @@
  * PUBLIC: int f_w1200 __P((SCR *, OPTION *, char *, u_long *));
  */
 int
-f_w1200(sp, op, str, valp)
-	SCR *sp;
-	OPTION *op;
-	char *str;
-	u_long *valp;
+f_w1200(
+	SCR *sp,
+	OPTION *op,
+	char *str,
+	u_long *valp)
 {
 	u_long v;
 
@@ -333,11 +308,11 @@
  * PUBLIC: int f_w9600 __P((SCR *, OPTION *, char *, u_long *));
  */
 int
-f_w9600(sp, op, str, valp)
-	SCR *sp;
-	OPTION *op;
-	char *str;
-	u_long *valp;
+f_w9600(
+	SCR *sp,
+	OPTION *op,
+	char *str,
+	u_long *valp)
 {
 	u_long v;
 
@@ -354,11 +329,11 @@
  * PUBLIC: int f_window __P((SCR *, OPTION *, char *, u_long *));
  */
 int
-f_window(sp, op, str, valp)
-	SCR *sp;
-	OPTION *op;
-	char *str;
-	u_long *valp;
+f_window(
+	SCR *sp,
+	OPTION *op,
+	char *str,
+	u_long *valp)
 {
 	if (*valp >= O_VAL(sp, O_LINES) - 1 &&
 	    (*valp = O_VAL(sp, O_LINES) - 1) == 0)
@@ -365,3 +340,18 @@
 		*valp = 1;
 	return (0);
 }
+
+/*
+ * PUBLIC: int f_encoding __P((SCR *, OPTION *, char *, u_long *));
+ */
+int
+f_encoding(
+	SCR *sp,
+	OPTION *op,
+	char *str,
+	u_long *valp)
+{
+	int offset = op - sp->opts;
+
+	return conv_enc(sp, offset, str);
+}

Modified: trunk/contrib/nvi/common/put.c
===================================================================
--- trunk/contrib/nvi/common/put.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/common/put.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -10,11 +10,12 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)put.c	10.11 (Berkeley) 9/23/96";
+static const char sccsid[] = "$Id: put.c,v 10.19 04/07/11 17:00:24 zy Exp $";
 #endif /* not lint */
 
 #include <sys/types.h>
 #include <sys/queue.h>
+#include <sys/time.h>
 
 #include <bitstring.h>
 #include <ctype.h>
@@ -32,12 +33,13 @@
  * PUBLIC: int put __P((SCR *, CB *, CHAR_T *, MARK *, MARK *, int));
  */
 int
-put(sp, cbp, namep, cp, rp, append)
-	SCR *sp;
-	CB *cbp;
-	CHAR_T *namep;
-	MARK *cp, *rp;
-	int append;
+put(
+	SCR *sp,
+	CB *cbp,
+	CHAR_T *namep,
+	MARK *cp,
+	MARK *rp,
+	int append)
 {
 	CHAR_T name;
 	TEXT *ltp, *tp;
@@ -44,7 +46,8 @@
 	recno_t lno;
 	size_t blen, clen, len;
 	int rval;
-	char *bp, *p, *t;
+	CHAR_T *bp, *t;
+	CHAR_T *p;
 
 	if (cbp == NULL)
 		if (namep == NULL) {
@@ -63,7 +66,7 @@
 				return (1);
 			}
 		}
-	tp = cbp->textq.cqh_first;
+	tp = TAILQ_FIRST(cbp->textq);
 
 	/*
 	 * It's possible to do a put into an empty file, meaning that the cut
@@ -84,8 +87,8 @@
 		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)
+			for (; tp != NULL;
+			    ++lno, ++sp->rptlines[L_ADDED], tp = TAILQ_NEXT(tp, q))
 				if (db_append(sp, 1, lno, tp->lb, tp->len))
 					return (1);
 			rp->lno = 1;
@@ -98,8 +101,8 @@
 	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)
+		for (; tp != NULL;
+		    ++lno, ++sp->rptlines[L_ADDED], tp = TAILQ_NEXT(tp, q))
 			if (db_append(sp, 1, lno, tp->lb, tp->len))
 				return (1);
 		rp->cno = 0;
@@ -120,12 +123,12 @@
 	if (db_get(sp, lno, DBG_FATAL, &p, &len))
 		return (1);
 
-	GET_SPACE_RET(sp, bp, blen, tp->len + len + 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) {
-		memcpy(bp, p, clen);
+		MEMCPY(bp, p, clen);
 		p += clen;
 		t += clen;
 	}
@@ -132,7 +135,7 @@
 
 	/* First line from the CB. */
 	if (tp->len != 0) {
-		memcpy(t, tp->lb, tp->len);
+		MEMCPY(t, tp->lb, tp->len);
 		t += tp->len;
 	}
 
@@ -161,9 +164,9 @@
 	 * the intermediate lines, because the line changes will lose
 	 * the cached line.
 	 */
-	if (tp->q.cqe_next == (void *)&cbp->textq) {
+	if (TAILQ_NEXT(tp, q) == NULL) {
 		if (clen > 0) {
-			memcpy(t, p, clen);
+			MEMCPY(t, p, clen);
 			t += clen;
 		}
 		if (db_set(sp, lno, bp, t - bp))
@@ -183,15 +186,15 @@
 		 * Last part of original line; check for space, reset
 		 * the pointer into the buffer.
 		 */
-		ltp = cbp->textq.cqh_last;
+		ltp = TAILQ_LAST(cbp->textq, _texth);
 		len = t - bp;
-		ADD_SPACE_RET(sp, bp, blen, ltp->len + clen);
+		ADD_SPACE_RETW(sp, bp, blen, ltp->len + clen);
 		t = bp + len;
 
 		/* Add in last part of the CB. */
-		memcpy(t, ltp->lb, ltp->len);
+		MEMCPY(t, ltp->lb, ltp->len);
 		if (clen)
-			memcpy(t + ltp->len, p, clen);
+			MEMCPY(t + ltp->len, p, clen);
 		clen += ltp->len;
 
 		/*
@@ -211,9 +214,8 @@
 		}
 
 		/* 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)
+		for (tp = TAILQ_NEXT(tp, q); TAILQ_NEXT(tp, q) != NULL;
+		    ++lno, ++sp->rptlines[L_ADDED], tp = TAILQ_NEXT(tp, q))
 			if (db_append(sp, 1, lno, tp->lb, tp->len))
 				goto err;
 
@@ -226,6 +228,6 @@
 	if (0)
 err:		rval = 1;
 
-	FREE_SPACE(sp, bp, blen);
+	FREE_SPACEW(sp, bp, blen);
 	return (rval);
 }

Modified: trunk/contrib/nvi/common/recover.c
===================================================================
--- trunk/contrib/nvi/common/recover.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/common/recover.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -10,11 +10,10 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)recover.c	10.21 (Berkeley) 9/15/96";
+static const char sccsid[] = "$Id: recover.c,v 11.2 2012/10/09 08:06:58 zy Exp $";
 #endif /* not lint */
 
-#include <sys/param.h>
-#include <sys/types.h>		/* XXX: param.h may not have included types.h */
+#include <sys/types.h>
 #include <sys/queue.h>
 #include <sys/stat.h>
 
@@ -31,6 +30,8 @@
 #include <fcntl.h>
 #include <limits.h>
 #include <pwd.h>
+#include <netinet/in.h>		/* Required by resolv.h. */
+#include <resolv.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -37,6 +38,7 @@
 #include <time.h>
 #include <unistd.h>
 
+#include "../ex/version.h"
 #include "common.h"
 #include "pathnames.h"
 
@@ -57,12 +59,7 @@
  *		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.)
+ * file descriptor for the mail recovery file.
  *
  * To find out if a recovery file/backing file pair are in use, try to get
  * a lock on the recovery file.
@@ -93,27 +90,24 @@
  * 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:
+ * The recovery mail file contains normal mail headers, with two additional
  *
- *	X-vi-recover-file: file_name
- *	X-vi-recover-path: recover_path
+ *	X-vi-data: <file|path>;<base64 encoded 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.
+ * MIME headers; the folding character is limited to ' '.
  *
- * Btree files are named "vi.XXXX" and recovery files are named "recover.XXXX".
+ * Btree files are named "vi.XXXXXX" and recovery files are named
+ * "recover.XXXXXX".
  */
 
-#define	VI_FHEADER	"X-vi-recover-file: "
-#define	VI_PHEADER	"X-vi-recover-path: "
+#define	VI_DHEADER	"X-vi-data:"
 
 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 *, char *, int));
+static int	 rcv_mktemp __P((SCR *, char *, char *));
+static int	 rcv_dlnwrite __P((SCR *, const char *, const char *, FILE *));
+static int	 rcv_dlnread __P((SCR *, char **, char **, FILE *));
 
 /*
  * rcv_tmp --
@@ -122,14 +116,14 @@
  * PUBLIC: int rcv_tmp __P((SCR *, EXF *, char *));
  */
 int
-rcv_tmp(sp, ep, name)
-	SCR *sp;
-	EXF *ep;
-	char *name;
+rcv_tmp(
+	SCR *sp,
+	EXF *ep,
+	char *name)
 {
 	struct stat sb;
 	int fd;
-	char *dp, *p, path[MAXPATHLEN];
+	char *dp, *path;
 
 	/*
 	 * !!!
@@ -153,22 +147,17 @@
 		(void)chmod(dp, S_IRWXU | S_IRWXG | S_IRWXO | S_ISVTX);
 	}
 
-	/* Newlines delimit the mail messages. */
-	for (p = name; *p; ++p)
-		if (*p == '\n') {
-			msgq(sp, M_ERR,
-		    "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)
+	if ((path = join(dp, "vi.XXXXXX")) == NULL)
 		goto err;
+	if ((fd = rcv_mktemp(sp, path, dp)) == -1) {
+		free(path);
+		goto err;
+	}
+	(void)fchmod(fd, S_IRWXU);
 	(void)close(fd);
 
-	if ((ep->rcv_path = strdup(path)) == NULL) {
-		msgq(sp, M_SYSERR, NULL);
-		(void)unlink(path);
+	ep->rcv_path = path;
+	if (0) {
 err:		msgq(sp, M_ERR,
 		    "056|Modifications not recoverable if the session fails");
 		return (1);
@@ -186,8 +175,7 @@
  * PUBLIC: int rcv_init __P((SCR *));
  */
 int
-rcv_init(sp)
-	SCR *sp;
+rcv_init(SCR *sp)
 {
 	EXF *ep;
 	recno_t lno;
@@ -249,13 +237,13 @@
  * PUBLIC: int rcv_sync __P((SCR *, u_int));
  */
 int
-rcv_sync(sp, flags)
-	SCR *sp;
-	u_int flags;
+rcv_sync(
+	SCR *sp,
+	u_int flags)
 {
 	EXF *ep;
 	int fd, rval;
-	char *dp, buf[1024];
+	char *dp, *buf;
 
 	/* Make sure that there's something to recover/sync. */
 	ep = sp->ep;
@@ -298,9 +286,14 @@
 		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)
+		if ((buf = join(dp, "vi.XXXXXX")) == NULL) {
+			msgq(sp, M_SYSERR, NULL);
 			goto err;
+		}
+		if ((fd = rcv_mktemp(sp, buf, dp)) == -1) {
+			free(buf);
+			goto err;
+		}
 		sp->gp->scr_busy(sp,
 		    "061|Copying file for recovery...", BUSY_ON);
 		if (rcv_copy(sp, fd, ep->rcv_path) ||
@@ -309,6 +302,7 @@
 			(void)close(fd);
 			rval = 1;
 		}
+		free(buf);
 		sp->gp->scr_busy(sp, NULL, BUSY_OFF);
 	}
 	if (0) {
@@ -327,30 +321,32 @@
  *	Build the file to mail to the user.
  */
 static int
-rcv_mailfile(sp, issync, cp_path)
-	SCR *sp;
-	int issync;
-	char *cp_path;
+rcv_mailfile(
+	SCR *sp,
+	int issync,
+	char *cp_path)
 {
 	EXF *ep;
 	GS *gp;
 	struct passwd *pw;
-	size_t len;
+	int len;
 	time_t now;
 	uid_t uid;
 	int fd;
-	char *dp, *p, *t, buf[4096], mpath[MAXPATHLEN];
+	FILE *fp;
+	char *dp, *p, *t, *qt, *buf, *mpath;
 	char *t1, *t2, *t3;
+	int st;
 
 	/*
 	 * XXX
-	 * MAXHOSTNAMELEN is in various places on various systems, including
-	 * <netdb.h> and <sys/socket.h>.  If not found, use a large default.
+	 * MAXHOSTNAMELEN/HOST_NAME_MAX are deprecated. We try sysconf(3)
+	 * first, then fallback to _POSIX_HOST_NAME_MAX.
 	 */
-#ifndef MAXHOSTNAMELEN
-#define	MAXHOSTNAMELEN	1024
-#endif
-	char host[MAXHOSTNAMELEN];
+	char *host;
+	long hostmax = sysconf(_SC_HOST_NAME_MAX);
+	if (hostmax < 0)
+		hostmax = _POSIX_HOST_NAME_MAX;
 
 	gp = sp->gp;
 	if ((pw = getpwuid(uid = getuid())) == NULL) {
@@ -362,9 +358,19 @@
 	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)
+	if ((mpath = join(dp, "recover.XXXXXX")) == NULL) {
+		msgq(sp, M_SYSERR, NULL);
 		return (1);
+	}
+	if ((fd = rcv_mktemp(sp, mpath, dp)) == -1) {
+		free(mpath);
+		return (1);
+	}
+	if ((fp = fdopen(fd, "w")) == NULL) {
+		free(mpath);
+		close(fd);
+		return (1);
+	}
 
 	/*
 	 * XXX
@@ -374,25 +380,15 @@
 	 * and the lock, but it's pretty small.
 	 */
 	ep = sp->ep;
-	if (file_lock(sp, NULL, NULL, fd, 1) != LOCK_SUCCESS)
+	if (file_lock(sp, 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;
-		}
+		ep->rcv_fd = dup(fd);
+		ep->rcv_mpath = mpath;
 		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;
@@ -399,31 +395,49 @@
 	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,
+
+	if ((st = rcv_dlnwrite(sp, "file", t, fp))) {
+		if (st == 1)
+			goto werr;
+		goto err;
+	}
+	if ((st = rcv_dlnwrite(sp, "path", cp_path, fp))) {
+		if (st == 1)
+			goto werr;
+		goto err;
+	}
+
+	MALLOC(sp, host, char *, hostmax + 1);
+	if (host == NULL)
+		goto err;
+	(void)gethostname(host, hostmax + 1);
+
+	len = fprintf(fp, "%s%s%s\n%s%s%s%s\n%s%.40s\n%s\n\n",
+	    "From: root@", host, " (Nvi recovery program)",
+	    "To: ", pw->pw_name, "@", host,
 	    "Subject: Nvi saved the file ", p,
 	    "Precedence: bulk");		/* For vacation(1). */
-	if (len > sizeof(buf) - 1)
-		goto lerr;
-	if (write(fd, buf, len) != len)
+	if (len < 0) {
+		free(host);
 		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",
+	if ((qt = quote(t)) == NULL) {
+		free(host);
+		msgq(sp, M_SYSERR, NULL);
+		goto err;
+	}
+	len = asprintf(&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");
+	    gp->progname, " -r ", qt);
+	free(qt);
+	free(host);
+	if (buf == NULL) {
+		msgq(sp, M_SYSERR, NULL);
 		goto err;
 	}
 
@@ -457,23 +471,29 @@
 wout:		*t2++ = '\n';
 
 		/* t2 points one after the last character to display. */
-		if (write(fd, t1, t2 - t1) != t2 - t1)
+		if (fwrite(t1, 1, t2 - t1, fp) != t2 - t1) {
+			free(buf);
 			goto werr;
+		}
 	}
 
 	if (issync) {
+		fflush(fp);
 		rcv_email(sp, mpath);
-		if (close(fd)) {
-werr:			msgq(sp, M_SYSERR, "065|Recovery file");
-			goto err;
-		}
+		free(mpath);
 	}
+	if (fclose(fp)) {
+		free(buf);
+werr:		msgq(sp, M_SYSERR, "065|Recovery file");
+		goto err;
+	}
+	free(buf);
 	return (0);
 
 err:	if (!issync)
 		ep->rcv_fd = -1;
-	if (fd != -1)
-		(void)close(fd);
+	if (fp != NULL)
+		(void)fclose(fp);
 	return (1);
 }
 
@@ -488,8 +508,7 @@
  * PUBLIC: int rcv_list __P((SCR *));
  */
 int
-rcv_list(sp)
-	SCR *sp;
+rcv_list(SCR *sp)
 {
 	struct dirent *dp;
 	struct stat sb;
@@ -496,7 +515,9 @@
 	DIR *dirp;
 	FILE *fp;
 	int found;
-	char *p, *t, file[MAXPATHLEN], path[MAXPATHLEN];
+	char *p, *file, *path;
+	char *dtype, *data;
+	int st;
 
 	/* Open the recovery directory for reading. */
 	if (opts_empty(sp, O_RECDIR, 0))
@@ -512,18 +533,11 @@
 		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)
+		/* If it's readable, it's recoverable. */
+		if ((fp = fopen(dp->d_name, "r")) == NULL)
 			continue;
 
-		switch (file_lock(sp, NULL, NULL, fileno(fp), 1)) {
+		switch (file_lock(sp, NULL, fileno(fp), 1)) {
 		case LOCK_FAILED:
 			/*
 			 * XXX
@@ -542,17 +556,23 @@
 		}
 
 		/* 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;
+		for (file = NULL, path = NULL;
+		    file == NULL || path == NULL;) {
+			if ((st = rcv_dlnread(sp, &dtype, &data, fp))) {
+				if (st == 1)
+					msgq_str(sp, M_ERR, dp->d_name,
+					    "066|%s: malformed recovery file");
+				goto next;
+			}
+			if (dtype == NULL)
+				continue;
+			if (!strcmp(dtype, "file"))
+				file = data;
+			else if (!strcmp(dtype, "path"))
+				path = data;
+			else
+				free(data);
 		}
-		*p = *t = '\0';
 
 		/*
 		 * If the file doesn't exist, it's an orphaned recovery file,
@@ -563,7 +583,7 @@
 		 * before deleting the email file.
 		 */
 		errno = 0;
-		if (stat(path + sizeof(VI_PHEADER) - 1, &sb) &&
+		if (stat(path, &sb) &&
 		    errno == ENOENT) {
 			(void)unlink(dp->d_name);
 			goto next;
@@ -572,14 +592,18 @@
 		/* 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);
+		    ctime(&sb.st_mtime), file);
 		found = 1;
 
 		/* Close, discarding lock. */
 next:		(void)fclose(fp);
+		if (file != NULL)
+			free(file);
+		if (path != NULL)
+			free(path);
 	}
 	if (found == 0)
-		(void)printf("vi: no files to recover.\n");
+		(void)printf("%s: No files to recover\n", sp->gp->progname);
 	(void)closedir(dirp);
 	return (0);
 }
@@ -591,18 +615,21 @@
  * PUBLIC: int rcv_read __P((SCR *, FREF *));
  */
 int
-rcv_read(sp, frp)
-	SCR *sp;
-	FREF *frp;
+rcv_read(
+	SCR *sp,
+	FREF *frp)
 {
 	struct dirent *dp;
 	struct stat sb;
 	DIR *dirp;
+	FILE *fp;
 	EXF *ep;
-	time_t rec_mtime;
-	int fd, found, locked, requested, sv_fd;
+	struct timespec rec_mtim = { 0, 0 };
+	int found, locked = 0, requested, sv_fd;
 	char *name, *p, *t, *rp, *recp, *pathp;
-	char file[MAXPATHLEN], path[MAXPATHLEN], recpath[MAXPATHLEN];
+	char *file, *path, *recpath;
+	char *dtype, *data;
+	int st;
 
 	if (opts_empty(sp, O_RECDIR, 0))
 		return (1);
@@ -614,30 +641,22 @@
 
 	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 ((recpath = join(rp, dp->d_name)) == NULL) {
+			msgq(sp, M_SYSERR, NULL);
+			continue;
+		}
 
-		/*
-		 * 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)
+		/* If it's readable, it's recoverable. */
+		if ((fp = fopen(recpath, "r")) == NULL) {
+			free(recpath);
 			continue;
+		}
 
-		switch (file_lock(sp, NULL, NULL, fd, 1)) {
+		switch (file_lock(sp, NULL, fileno(fp), 1)) {
 		case LOCK_FAILED:
 			/*
 			 * XXX
@@ -653,22 +672,28 @@
 			break;
 		case LOCK_UNAVAIL:
 			/* If it's locked, it's live. */
-			(void)close(fd);
+			(void)fclose(fp);
 			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;
+		for (file = NULL, path = NULL;
+		    file == NULL || path == NULL;) {
+			if ((st = rcv_dlnread(sp, &dtype, &data, fp))) {
+				if (st == 1)
+					msgq_str(sp, M_ERR, dp->d_name,
+					    "067|%s: malformed recovery file");
+				goto next;
+			}
+			if (dtype == NULL)
+				continue;
+			if (!strcmp(dtype, "file"))
+				file = data;
+			else if (!strcmp(dtype, "path"))
+				path = data;
+			else
+				free(data);
 		}
-		*p = *t = '\0';
 		++found;
 
 		/*
@@ -680,7 +705,7 @@
 		 * before deleting the email file.
 		 */
 		errno = 0;
-		if (stat(path + sizeof(VI_PHEADER) - 1, &sb) &&
+		if (stat(path, &sb) &&
 		    errno == ENOENT) {
 			(void)unlink(dp->d_name);
 			goto next;
@@ -687,45 +712,35 @@
 		}
 
 		/* Check the file name. */
-		if (strcmp(file + sizeof(VI_FHEADER) - 1, name))
+		if (strcmp(file, 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) {
+		/* If we've found more than one, take the most recent. */
+		(void)fstat(fileno(fp), &sb);
+		if (recp == NULL ||
+		    timespeccmp(&rec_mtim, &sb.st_mtimespec, <)) {
 			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;
-			}
+			recp = recpath;
+			pathp = path;
 			if (p != NULL) {
 				free(p);
 				free(t);
 			}
-			rec_mtime = sb.st_mtime;
+			rec_mtim = sb.st_mtimespec;
 			if (sv_fd != -1)
 				(void)close(sv_fd);
-			sv_fd = fd;
-		} else
-next:			(void)close(fd);
+			sv_fd = dup(fileno(fp));
+		} else {
+next:			free(recpath);
+			if (path != NULL)
+				free(path);
+		}
+		(void)fclose(fp);
+		if (file != NULL)
+			free(file);
 	}
 	(void)closedir(dirp);
 
@@ -749,12 +764,13 @@
 	 * XXX
 	 * file_init() is going to set ep->rcv_path.
 	 */
-	if (file_init(sp, frp, pathp + sizeof(VI_PHEADER) - 1, 0)) {
+	if (file_init(sp, frp, pathp, 0)) {
 		free(recp);
 		free(pathp);
 		(void)close(sv_fd);
 		return (1);
 	}
+	free(pathp);
 
 	/*
 	 * We keep an open lock on the file so that the recover option can
@@ -777,10 +793,10 @@
  *	Copy a recovery file.
  */
 static int
-rcv_copy(sp, wfd, fname)
-	SCR *sp;
-	int wfd;
-	char *fname;
+rcv_copy(
+	SCR *sp,
+	int wfd,
+	char *fname)
 {
 	int nr, nw, off, rfd;
 	char buf[8 * 1024];
@@ -799,52 +815,19 @@
 }
 
 /*
- * rcv_gets --
- *	Fgets(3) for a file descriptor.
- */
-static char *
-rcv_gets(buf, len, fd)
-	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(sp, path, dname, perms)
-	SCR *sp;
-	char *path, *dname;
-	int perms;
+rcv_mktemp(
+	SCR *sp,
+	char *path,
+	char *dname)
 {
 	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);
 }
 
@@ -853,26 +836,141 @@
  *	Send email.
  */
 static void
-rcv_email(sp, fname)
-	SCR *sp;
-	char *fname;
+rcv_email(
+	SCR *sp,
+	char *fname)
 {
-	struct stat sb;
-	char buf[MAXPATHLEN * 2 + 20];
+	char *buf;
 
-	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);
+	(void)asprintf(&buf, _PATH_SENDMAIL " -odb -t < %s", fname);
+	if (buf == NULL) {
+		msgq_str(sp, M_ERR, strerror(errno),
+		    "071|not sending email: %s");
+		return;
 	}
+	(void)system(buf);
+	free(buf);
 }
+
+/*
+ * rcv_dlnwrite --
+ *	Encode a string into an X-vi-data line and write it.
+ */
+static int
+rcv_dlnwrite(
+	SCR *sp,
+	const char *dtype,
+	const char *src,
+	FILE *fp)
+{
+	char *bp = NULL, *p;
+	size_t blen = 0;
+	size_t dlen, len;
+	int plen, xlen;
+
+	len = strlen(src);
+	dlen = strlen(dtype);
+	GET_SPACE_GOTOC(sp, bp, blen, (len + 2) / 3 * 4 + dlen + 2);
+	(void)memcpy(bp, dtype, dlen);
+	bp[dlen] = ';';
+	if ((xlen = b64_ntop((u_char *)src,
+	    len, bp + dlen + 1, blen)) == -1)
+		goto err;
+	xlen += dlen + 1;
+
+	/* Output as an MIME folding header. */
+	if ((plen = fprintf(fp, VI_DHEADER " %.*s\n",
+	    FMTCOLS - (int)sizeof(VI_DHEADER), bp)) < 0)
+		goto err;
+	plen -= (int)sizeof(VI_DHEADER) + 1;
+	for (p = bp, xlen -= plen; xlen > 0; xlen -= plen) {
+		p += plen;
+		if ((plen = fprintf(fp, " %.*s\n", FMTCOLS - 1, p)) < 0)
+			goto err;
+		plen -= 2;
+	}
+	FREE_SPACE(sp, bp, blen);
+	return (0);
+
+err:	FREE_SPACE(sp, bp, blen);
+	return (1);
+alloc_err:
+	msgq(sp, M_SYSERR, NULL);
+	return (-1);
+}
+
+/*
+ * rcv_dlnread --
+ *	Read an X-vi-data line and decode it.
+ */
+static int
+rcv_dlnread(
+	SCR *sp,
+	char **dtypep,
+	char **datap,		/* free *datap if != NULL after use. */
+	FILE *fp)
+{
+	int ch;
+	char buf[1024];
+	char *bp = NULL, *p, *src;
+	size_t blen = 0;
+	size_t len, off, dlen;
+	char *dtype, *data;
+	int xlen;
+
+	if (fgets(buf, sizeof(buf), fp) == NULL)
+		return (1);
+	if (strncmp(buf, VI_DHEADER, sizeof(VI_DHEADER) - 1)) {
+		*dtypep = NULL;
+		*datap = NULL;
+		return (0);
+	}
+
+	/* Fetch an MIME folding header. */
+	len = strlen(buf) - sizeof(VI_DHEADER) + 1;
+	GET_SPACE_GOTOC(sp, bp, blen, len);
+	(void)memcpy(bp, buf + sizeof(VI_DHEADER) - 1, len);
+	p = bp + len;
+	while ((ch = fgetc(fp)) == ' ') {
+		if (fgets(buf, sizeof(buf), fp) == NULL)
+			goto err;
+		off = strlen(buf);
+		len += off;
+		ADD_SPACE_GOTOC(sp, bp, blen, len);
+		p = bp + len - off;
+		(void)memcpy(p, buf, off);
+	}
+	bp[len] = '\0';
+	(void)ungetc(ch, fp);
+
+	for (p = bp; *p == ' ' || *p == '\n'; p++);
+	if ((src = strchr(p, ';')) == NULL)
+		goto err;
+	dlen = src - p;
+	src += 1;
+	len -= src - bp;
+
+	/* Memory looks like: "<data>\0<dtype>\0". */
+	MALLOC(sp, data, char *, dlen + len / 4 * 3 + 2);
+	if (data == NULL)
+		goto err;
+	if ((xlen = (b64_pton(p + dlen + 1,
+	    (u_char *)data, len / 4 * 3 + 1))) == -1) {
+		free(data);
+		goto err;
+	}
+	data[xlen] = '\0';
+	dtype = data + xlen + 1;
+	(void)memcpy(dtype, p, dlen);
+	dtype[dlen] = '\0';
+	FREE_SPACE(sp, bp, blen);
+	*dtypep = dtype;
+	*datap = data;
+	return (0);
+
+err: 	FREE_SPACE(sp, bp, blen);
+	return (1);
+alloc_err:
+	msgq(sp, M_SYSERR, NULL);
+	return (-1);
+}

Modified: trunk/contrib/nvi/common/screen.c
===================================================================
--- trunk/contrib/nvi/common/screen.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/common/screen.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -10,7 +10,7 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)screen.c	10.15 (Berkeley) 9/15/96";
+static const char sccsid[] = "$Id: screen.c,v 10.25 2011/12/04 04:06:45 zy Exp $";
 #endif /* not lint */
 
 #include <sys/types.h>
@@ -35,9 +35,10 @@
  * PUBLIC: int screen_init __P((GS *, SCR *, SCR **));
  */
 int
-screen_init(gp, orig, spp)
-	GS *gp;
-	SCR *orig, **spp;
+screen_init(
+	GS *gp,
+	SCR *orig,
+	SCR **spp)
 {
 	SCR *sp;
 	size_t len;
@@ -50,9 +51,9 @@
 	sp->id = ++gp->id;
 	sp->refcnt = 1;
 
-	sp->gp = gp;				/* All ref the GS structure. */
+	sp->gp = gp;			/* All ref the GS structure. */
 
-	sp->ccnt = 2;				/* Anything > 1 */
+	sp->ccnt = 2;			/* Anything > 1 */
 
 	/*
 	 * XXX
@@ -60,7 +61,7 @@
 	 * we don't have the option information yet.
 	 */
 
-	CIRCLEQ_INIT(&sp->tiq);
+	TAILQ_INIT(sp->tiq);
 
 /* PARTIALLY OR COMPLETELY COPIED FROM PREVIOUS SCREEN. */
 	if (orig == NULL) {
@@ -80,15 +81,15 @@
 		/* Retain searching/substitution information. */
 		sp->searchdir = orig->searchdir == NOTSET ? NOTSET : FORWARD;
 		if (orig->re != NULL && (sp->re =
-		    v_strdup(sp, orig->re, orig->re_len)) == NULL)
+		    v_wstrdup(sp, orig->re, orig->re_len)) == NULL)
 			goto mem;
 		sp->re_len = orig->re_len;
 		if (orig->subre != NULL && (sp->subre =
-		    v_strdup(sp, orig->subre, orig->subre_len)) == NULL)
+		    v_wstrdup(sp, orig->subre, orig->subre_len)) == NULL)
 			goto mem;
 		sp->subre_len = orig->subre_len;
 		if (orig->repl != NULL && (sp->repl =
-		    v_strdup(sp, orig->repl, orig->repl_len)) == NULL)
+		    v_wstrdup(sp, orig->repl, orig->repl_len)) == NULL)
 			goto mem;
 		sp->repl_len = orig->repl_len;
 		if (orig->newl_len) {
@@ -113,6 +114,8 @@
 		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);
@@ -129,8 +132,7 @@
  * PUBLIC: int screen_end __P((SCR *));
  */
 int
-screen_end(sp)
-	SCR *sp;
+screen_end(SCR *sp)
 {
 	int rval;
 
@@ -144,17 +146,13 @@
 	 * If a created screen failed during initialization, it may not
 	 * be linked into the chain.
 	 */
-	if (sp->q.cqe_next != NULL)
-		CIRCLEQ_REMOVE(&sp->gp->dq, sp, q);
+	if (TAILQ_ENTRY_ISVALID(sp, q))
+		TAILQ_REMOVE(sp->gp->dq, 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. */
@@ -170,8 +168,8 @@
 	}
 
 	/* Free any text input. */
-	if (sp->tiq.cqh_first != NULL)
-		text_lfree(&sp->tiq);
+	if (!TAILQ_EMPTY(sp->tiq))
+		text_lfree(sp->tiq);
 
 	/* Free alternate file name. */
 	if (sp->alt_name != NULL)
@@ -191,6 +189,9 @@
 	if (sp->newl != NULL)
 		free(sp->newl);
 
+	/* Free the iconv environment */
+	conv_end(sp);
+
 	/* Free all the options */
 	opts_free(sp);
 
@@ -207,8 +208,7 @@
  * PUBLIC: SCR *screen_next __P((SCR *));
  */
 SCR *
-screen_next(sp)
-	SCR *sp;
+screen_next(SCR *sp)
 {
 	GS *gp;
 	SCR *next;
@@ -215,18 +215,17 @@
 
 	/* Try the display queue, without returning the current screen. */
 	gp = sp->gp;
-	for (next = gp->dq.cqh_first;
-	    next != (void *)&gp->dq; next = next->q.cqe_next)
+	TAILQ_FOREACH(next, gp->dq, q)
 		if (next != sp)
 			break;
-	if (next != (void *)&gp->dq)
+	if (next != NULL)
 		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(&gp->dq, next, q);
+	if (!TAILQ_EMPTY(gp->hq)) {
+		next = TAILQ_FIRST(gp->hq);
+		TAILQ_REMOVE(gp->hq, next, q);
+		TAILQ_INSERT_HEAD(gp->dq, next, q);
 		return (next);
 	}
 	return (NULL);

Modified: trunk/contrib/nvi/common/screen.h
===================================================================
--- trunk/contrib/nvi/common/screen.h	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/common/screen.h	2018-06-10 20:23:48 UTC (rev 10823)
@@ -6,7 +6,7 @@
  *
  * See the LICENSE file for redistribution information.
  *
- *	@(#)screen.h	10.24 (Berkeley) 7/19/96
+ *	$Id: screen.h,v 10.26 2011/12/12 22:31:36 zy Exp $
  */
 
 /*
@@ -32,7 +32,7 @@
  */
 struct _scr {
 /* INITIALIZED AT SCREEN CREATE. */
-	CIRCLEQ_ENTRY(_scr) q;		/* Screens. */
+	TAILQ_ENTRY(_scr) q;		/* Screens. */
 
 	int	 id;			/* Screen id #. */
 	int	 refcnt;		/* Reference count. */
@@ -55,7 +55,8 @@
 	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	 woff;			/* 0-N: screen offset in frame. */
+	size_t	 coff;			/* 0-N: screen col offset in display. */
+	size_t	 roff;			/* 0-N: screen row offset in display. */
 
 					/* Cursor's: */
 	recno_t	 lno;			/* 1-N: file line. */
@@ -73,7 +74,7 @@
 	recno_t	 rptlchange;		/* Ex/vi: last L_CHANGED lno. */
 	recno_t	 rptlines[L_YANKED + 1];/* Ex/vi: lines changed by last op. */
 
-	TEXTH	 tiq;			/* Ex/vi: text input queue. */
+	TEXTH	 tiq[1];		/* Ex/vi: text input queue. */
 
 	SCRIPT	*script;		/* Vi: script mode information .*/
 
@@ -80,8 +81,9 @@
 	recno_t	 defscroll;		/* Vi: ^D, ^U scroll information. */
 
 					/* Display character. */
-	CHAR_T	 cname[MAX_CHARACTER_COLUMNS + 1];
+	char	 cname[MAX_CHARACTER_COLUMNS + 1];
 	size_t	 clen;			/* Length of display character. */
+	ARG_CHAR_T lastc;		/* The last display character. */
 
 	enum {				/* Vi editor mode. */
 	    SM_APPEND = 0, SM_CHANGE, SM_COMMAND, SM_INSERT,
@@ -89,8 +91,11 @@
 
 	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;			/* Conversion functions. */
+	CONVWIN	 cw;			/* Conversion buffer. */
+
 /* PARTIALLY OR COMPLETELY COPIED FROM PREVIOUS SCREEN. */
 	char	*alt_name;		/* Ex/vi: alternate file name. */
 
@@ -103,8 +108,10 @@
 #define	RE_C_SUBST	0x0008		/* Compile substitute replacement. */
 #define	RE_C_TAG	0x0010		/* Compile ctag pattern. */
 
-#define	RE_WSTART	"[[:<:]]"	/* Ex/vi: not-in-word search pattern. */
-#define	RE_WSTOP	"[[:>:]]"
+#define	RE_WSTART	L("[[:<:]]")	/* Ex/vi: not-in-word search pattern. */
+#define	RE_WSTOP	L("[[:>:]]")
+#define RE_WSTART_LEN	(SIZE(RE_WSTART) - 1)
+#define RE_WSTOP_LEN	(SIZE(RE_WSTOP) - 1)
 					/* Ex/vi: flags to search routines. */
 #define	SEARCH_CSCOPE	0x0001		/* Search for a cscope pattern. */
 #define	SEARCH_EOL	0x0002		/* Offset past EOL is okay. */
@@ -119,12 +126,12 @@
 					/* Ex/vi: RE information. */
 	dir_t	 searchdir;		/* Last file search direction. */
 	regex_t	 re_c;			/* Search RE: compiled form. */
-	char	*re;			/* Search RE: uncompiled 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	*subre;			/* Substitute RE: uncompiled form. */
+	CHAR_T	*subre;			/* Substitute RE: uncompiled form. */
 	size_t	 subre_len;		/* Substitute RE: uncompiled length). */
-	char	*repl;			/* Substitute replacement. */
+	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. */
@@ -199,5 +206,6 @@
 #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;
 };

Modified: trunk/contrib/nvi/common/search.c
===================================================================
--- trunk/contrib/nvi/common/search.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/common/search.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -10,11 +10,12 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)search.c	10.25 (Berkeley) 6/30/96";
+static const char sccsid[] = "$Id: search.c,v 10.26 2011/07/04 20:16:26 zy Exp $";
 #endif /* not lint */
 
 #include <sys/types.h>
 #include <sys/queue.h>
+#include <sys/time.h>
 
 #include <bitstring.h>
 #include <ctype.h>
@@ -30,7 +31,7 @@
 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 *, size_t, char **, u_int));
+static int	search_init __P((SCR *, dir_t, CHAR_T *, size_t, CHAR_T **, u_int));
 
 /*
  * search_init --
@@ -37,16 +38,17 @@
  *	Set up a search.
  */
 static int
-search_init(sp, dir, ptrn, plen, epp, flags)
-	SCR *sp;
-	dir_t dir;
-	char *ptrn, **epp;
-	size_t plen;
-	u_int flags;
+search_init(
+	SCR *sp,
+	dir_t dir,
+	CHAR_T *ptrn,
+	size_t plen,
+	CHAR_T **epp,
+	u_int flags)
 {
 	recno_t lno;
 	int delim;
-	char *p, *t;
+	CHAR_T *p, *t;
 
 	/* If the file is empty, it's a fast search. */
 	if (sp->lno <= 1) {
@@ -141,15 +143,17 @@
  *	Do a forward search.
  *
  * PUBLIC: int f_search __P((SCR *,
- * PUBLIC:    MARK *, MARK *, char *, size_t, char **, u_int));
+ * PUBLIC:    MARK *, MARK *, CHAR_T *, size_t, CHAR_T **, u_int));
  */
 int
-f_search(sp, fm, rm, ptrn, plen, eptrn, flags)
-	SCR *sp;
-	MARK *fm, *rm;
-	char *ptrn, **eptrn;
-	size_t plen;
-	u_int flags;
+f_search(
+	SCR *sp,
+	MARK *fm,
+	MARK *rm,
+	CHAR_T *ptrn,
+	size_t plen,
+	CHAR_T **eptrn,
+	u_int flags)
 {
 	busy_t btype;
 	recno_t lno;
@@ -156,7 +160,7 @@
 	regmatch_t match[1];
 	size_t coff, len;
 	int cnt, eval, rval, wrapped;
-	char *l;
+	CHAR_T *l;
 
 	if (search_init(sp, FORWARD, ptrn, plen, eptrn, flags))
 		return (1);
@@ -210,7 +214,7 @@
 			}
 			cnt = INTERRUPT_CHECK;
 		}
-		if (wrapped && lno > fm->lno || db_get(sp, lno, 0, &l, &len)) {
+		if ((wrapped && lno > fm->lno) || db_get(sp, lno, 0, &l, &len)) {
 			if (wrapped) {
 				if (LF_ISSET(SEARCH_MSG))
 					search_msg(sp, S_NOTFOUND);
@@ -285,15 +289,17 @@
  *	Do a backward search.
  *
  * PUBLIC: int b_search __P((SCR *,
- * PUBLIC:    MARK *, MARK *, char *, size_t, char **, u_int));
+ * PUBLIC:    MARK *, MARK *, CHAR_T *, size_t, CHAR_T **, u_int));
  */
 int
-b_search(sp, fm, rm, ptrn, plen, eptrn, flags)
-	SCR *sp;
-	MARK *fm, *rm;
-	char *ptrn, **eptrn;
-	size_t plen;
-	u_int flags;
+b_search(
+	SCR *sp,
+	MARK *fm,
+	MARK *rm,
+	CHAR_T *ptrn,
+	size_t plen,
+	CHAR_T **eptrn,
+	u_int flags)
 {
 	busy_t btype;
 	recno_t lno;
@@ -300,7 +306,7 @@
 	regmatch_t match[1];
 	size_t coff, last, len;
 	int cnt, eval, rval, wrapped;
-	char *l;
+	CHAR_T *l;
 
 	if (search_init(sp, BACKWARD, ptrn, plen, eptrn, flags))
 		return (1);
@@ -342,7 +348,7 @@
 			}
 			cnt = INTERRUPT_CHECK;
 		}
-		if (wrapped && lno < fm->lno || lno == 0) {
+		if ((wrapped && lno < fm->lno) || lno == 0) {
 			if (wrapped) {
 				if (LF_ISSET(SEARCH_MSG))
 					search_msg(sp, S_NOTFOUND);
@@ -447,9 +453,9 @@
  *	Display one of the search messages.
  */
 static void
-search_msg(sp, msg)
-	SCR *sp;
-	smsg_t msg;
+search_msg(
+	SCR *sp,
+	smsg_t msg)
 {
 	switch (msg) {
 	case S_EMPTY:
@@ -484,9 +490,9 @@
  * PUBLIC: void search_busy __P((SCR *, busy_t));
  */
 void
-search_busy(sp, btype)
-	SCR *sp;
-	busy_t btype;
+search_busy(
+	SCR *sp,
+	busy_t btype)
 {
 	sp->gp->scr_busy(sp, "078|Searching...", btype);
 }

Modified: trunk/contrib/nvi/common/seq.c
===================================================================
--- trunk/contrib/nvi/common/seq.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/common/seq.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -10,11 +10,12 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)seq.c	10.10 (Berkeley) 3/30/96";
+static const char sccsid[] = "$Id: seq.c,v 10.18 2011/12/11 23:13:00 zy Exp $";
 #endif /* not lint */
 
 #include <sys/types.h>
 #include <sys/queue.h>
+#include <sys/time.h>
 
 #include <bitstring.h>
 #include <ctype.h>
@@ -34,12 +35,16 @@
  * PUBLIC:    size_t, CHAR_T *, size_t, CHAR_T *, size_t, seq_t, int));
  */
 int
-seq_set(sp, name, nlen, input, ilen, output, olen, stype, flags)
-	SCR *sp;
-	CHAR_T *name, *input, *output;
-	size_t nlen, ilen, olen;
-	seq_t stype;
-	int flags;
+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;
@@ -59,7 +64,7 @@
 		if (output == NULL || olen == 0) {
 			p = NULL;
 			olen = 0;
-		} else if ((p = v_strdup(sp, output, olen)) == NULL) {
+		} else if ((p = v_wstrdup(sp, output, olen)) == NULL) {
 			sv_errno = errno;
 			goto mem1;
 		}
@@ -80,7 +85,7 @@
 	/* Name. */
 	if (name == NULL || nlen == 0)
 		qp->name = NULL;
-	else if ((qp->name = v_strdup(sp, name, nlen)) == NULL) {
+	else if ((qp->name = v_wstrdup(sp, name, nlen)) == NULL) {
 		sv_errno = errno;
 		goto mem2;
 	}
@@ -87,7 +92,7 @@
 	qp->nlen = nlen;
 
 	/* Input. */
-	if ((qp->input = v_strdup(sp, input, ilen)) == NULL) {
+	if ((qp->input = v_wstrdup(sp, input, ilen)) == NULL) {
 		sv_errno = errno;
 		goto mem3;
 	}
@@ -97,7 +102,7 @@
 	if (output == NULL) {
 		qp->output = NULL;
 		olen = 0;
-	} else if ((qp->output = v_strdup(sp, output, olen)) == NULL) {
+	} else if ((qp->output = v_wstrdup(sp, output, olen)) == NULL) {
 		sv_errno = errno;
 		free(qp->input);
 mem3:		if (qp->name != NULL)
@@ -115,13 +120,13 @@
 
 	/* Link into the chain. */
 	if (lastqp == NULL) {
-		LIST_INSERT_HEAD(&sp->gp->seqq, qp, q);
+		SLIST_INSERT_HEAD(sp->gp->seqq, qp, q);
 	} else {
-		LIST_INSERT_AFTER(lastqp, qp, q);
+		SLIST_INSERT_AFTER(lastqp, qp, q);
 	}
 
 	/* Set the fast lookup bit. */
-	if (qp->input[0] < MAX_BIT_SEQ)
+	if ((qp->input[0] & ~MAX_BIT_SEQ) == 0)
 		bit_set(sp->gp->seqb, qp->input[0]);
 
 	return (0);
@@ -134,33 +139,48 @@
  * PUBLIC: int seq_delete __P((SCR *, CHAR_T *, size_t, seq_t));
  */
 int
-seq_delete(sp, input, ilen, stype)
-	SCR *sp;
-	CHAR_T *input;
-	size_t ilen;
-	seq_t stype;
+seq_delete(
+	SCR *sp,
+	CHAR_T *input,
+	size_t ilen,
+	seq_t stype)
 {
-	SEQ *qp;
+	SEQ *qp, *pre_qp = NULL;
+	int diff;
 
-	if ((qp = seq_find(sp, NULL, NULL, input, ilen, stype, NULL)) == NULL)
-		return (1);
-	return (seq_mdel(qp));
+	SLIST_FOREACH(qp, sp->gp->seqq, q) {
+		if (qp->stype == stype && qp->ilen == ilen) {
+			diff = MEMCMP(qp->input, input, ilen);
+			if (!diff) {
+				if (F_ISSET(qp, SEQ_FUNCMAP))
+					break;
+				if (qp == SLIST_FIRST(sp->gp->seqq))
+					SLIST_REMOVE_HEAD(sp->gp->seqq, q);
+				else
+					SLIST_REMOVE_AFTER(pre_qp, q);
+				return (seq_free(qp));
+			}
+			if (diff > 0)
+				break;
+		}
+		pre_qp = qp;
+	}
+	return (1);
 }
 
 /*
- * seq_mdel --
- *	Delete a map entry, without lookup.
+ * seq_free --
+ *	Free a map entry.
  *
- * PUBLIC: int seq_mdel __P((SEQ *));
+ * PUBLIC: int seq_free __P((SEQ *));
  */
 int
-seq_mdel(qp)
-	SEQ *qp;
+seq_free(SEQ *qp)
 {
-	LIST_REMOVE(qp, q);
 	if (qp->name != NULL)
 		free(qp->name);
-	free(qp->input);
+	if (qp->input != NULL)
+		free(qp->input);
 	if (qp->output != NULL)
 		free(qp->output);
 	free(qp);
@@ -176,16 +196,16 @@
  * PUBLIC:    __P((SCR *, SEQ **, EVENT *, CHAR_T *, size_t, seq_t, int *));
  */
 SEQ *
-seq_find(sp, lastqp, e_input, c_input, ilen, stype, ispartialp)
-	SCR *sp;
-	SEQ **lastqp;
-	EVENT *e_input;
-	CHAR_T *c_input;
-	size_t ilen;
-	seq_t stype;
-	int *ispartialp;
+seq_find(
+	SCR *sp,
+	SEQ **lastqp,
+	EVENT *e_input,
+	CHAR_T *c_input,
+	size_t ilen,
+	seq_t stype,
+	int *ispartialp)
 {
-	SEQ *lqp, *qp;
+	SEQ *lqp = NULL, *qp;
 	int diff;
 
 	/*
@@ -200,8 +220,8 @@
 	 */
 	if (ispartialp != NULL)
 		*ispartialp = 0;
-	for (lqp = NULL, qp = sp->gp->seqq.lh_first;
-	    qp != NULL; lqp = qp, qp = qp->q.le_next) {
+	for (qp = SLIST_FIRST(sp->gp->seqq); qp != NULL;
+	    lqp = qp, qp = SLIST_NEXT(qp, q)) {
 		/*
 		 * Fast checks on the first character and type, and then
 		 * a real comparison.
@@ -212,7 +232,7 @@
 			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));
+			diff = MEMCMP(qp->input, c_input, MIN(qp->ilen, ilen));
 		} else {
 			if (qp->input[0] > e_input->e_c)
 				break;
@@ -261,20 +281,13 @@
  * PUBLIC: void seq_close __P((GS *));
  */
 void
-seq_close(gp)
-	GS *gp;
+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);
+	while ((qp = SLIST_FIRST(gp->seqq)) != NULL) {
+		SLIST_REMOVE_HEAD(gp->seqq, q);
+		(void)seq_free(qp);
 	}
 }
 
@@ -285,10 +298,10 @@
  * PUBLIC: int seq_dump __P((SCR *, seq_t, int));
  */
 int
-seq_dump(sp, stype, isname)
-	SCR *sp;
-	seq_t stype;
-	int isname;
+seq_dump(
+	SCR *sp,
+	seq_t stype,
+	int isname)
 {
 	CHAR_T *p;
 	GS *gp;
@@ -297,7 +310,7 @@
 
 	cnt = 0;
 	gp = sp->gp;
-	for (qp = gp->seqq.lh_first; qp != NULL; qp = qp->q.le_next) {
+	SLIST_FOREACH(qp, sp->gp->seqq, q) {
 		if (stype != qp->stype || F_ISSET(qp, SEQ_FUNCMAP))
 			continue;
 		++cnt;
@@ -333,11 +346,11 @@
  * PUBLIC: int seq_save __P((SCR *, FILE *, char *, seq_t));
  */
 int
-seq_save(sp, fp, prefix, stype)
-	SCR *sp;
-	FILE *fp;
-	char *prefix;
-	seq_t stype;
+seq_save(
+	SCR *sp,
+	FILE *fp,
+	char *prefix,
+	seq_t stype)
 {
 	CHAR_T *p;
 	SEQ *qp;
@@ -345,7 +358,7 @@
 	int ch;
 
 	/* Write a sequence command for all keys the user defined. */
-	for (qp = sp->gp->seqq.lh_first; qp != NULL; qp = qp->q.le_next) {
+	SLIST_FOREACH(qp, sp->gp->seqq, q) {
 		if (stype != qp->stype || !F_ISSET(qp, SEQ_USERDEF))
 			continue;
 		if (prefix)
@@ -353,7 +366,7 @@
 		for (p = qp->input, olen = qp->ilen; olen > 0; --olen) {
 			ch = *p++;
 			if (ch == CH_LITERAL || ch == '|' ||
-			    isblank(ch) || KEY_VAL(sp, ch) == K_NL)
+			    cmdskip(ch) || KEY_VAL(sp, ch) == K_NL)
 				(void)putc(CH_LITERAL, fp);
 			(void)putc(ch, fp);
 		}
@@ -379,10 +392,10 @@
  * PUBLIC: int e_memcmp __P((CHAR_T *, EVENT *, size_t));
  */
 int
-e_memcmp(p1, ep, n)
-	CHAR_T *p1;
-	EVENT *ep;
-	size_t n;
+e_memcmp(
+	CHAR_T *p1,
+	EVENT *ep,
+	size_t n)
 {
 	if (n != 0) {
                 do {

Modified: trunk/contrib/nvi/common/seq.h
===================================================================
--- trunk/contrib/nvi/common/seq.h	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/common/seq.h	2018-06-10 20:23:48 UTC (rev 10823)
@@ -6,13 +6,13 @@
  *
  * See the LICENSE file for redistribution information.
  *
- *	@(#)seq.h	10.3 (Berkeley) 3/6/96
+ *	$Id: seq.h,v 10.4 2011/12/11 21:43:39 zy Exp $
  */
 
 /*
  * Map and abbreviation structures.
  *
- * The map structure is doubly linked list, sorted by input string and by
+ * The map structure is singly 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
@@ -27,7 +27,7 @@
  * things, though, so it's probably not a big deal.
  */
 struct _seq {
-	LIST_ENTRY(_seq) q;		/* Linked list of all sequences. */
+	SLIST_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. */

Modified: trunk/contrib/nvi/common/util.c
===================================================================
--- trunk/contrib/nvi/common/util.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/common/util.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -10,18 +10,27 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)util.c	10.11 (Berkeley) 9/15/96";
+static const char sccsid[] = "$Id: util.c,v 10.30 2013/03/19 10:00:27 yamt Exp $";
 #endif /* not lint */
 
 #include <sys/types.h>
 #include <sys/queue.h>
 
+#ifdef __APPLE__
+#include <mach/clock.h>
+#include <mach/mach.h>
+#include <mach/mach_time.h>
+#endif
+
 #include <bitstring.h>
+#include <ctype.h>
 #include <errno.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"
@@ -33,10 +42,11 @@
  * PUBLIC: void *binc __P((SCR *, void *, size_t *, size_t));
  */
 void *
-binc(sp, bp, bsizep, min)
-	SCR *sp;			/* sp MAY BE NULL!!! */
-	void *bp;
-	size_t *bsizep, min;
+binc(
+	SCR *sp,			/* sp MAY BE NULL!!! */
+	void *bp,
+	size_t *bsizep,
+	size_t min)
 {
 	size_t csize;
 
@@ -44,14 +54,10 @@
 	if (min && *bsizep >= min)
 		return (bp);
 
-	csize = *bsizep + MAX(min, 256);
+	csize = p2roundup(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);
 	}
@@ -73,12 +79,12 @@
  * PUBLIC: int nonblank __P((SCR *, recno_t, size_t *));
  */
 int
-nonblank(sp, lno, cnop)
-	SCR *sp;
-	recno_t lno;
-	size_t *cnop;
+nonblank(
+	SCR *sp,
+	recno_t lno,
+	size_t *cnop)
 {
-	char *p;
+	CHAR_T *p;
 	size_t cnt, len, off;
 	int isempty;
 
@@ -95,7 +101,7 @@
 		return (0);
 
 	for (cnt = off, p = &p[off],
-	    len -= off; len && isblank(*p); ++cnt, ++p, --len);
+	    len -= off; len && ISBLANK(*p); ++cnt, ++p, --len);
 
 	/* Set the return. */
 	*cnop = len ? cnt : cnt - 1;
@@ -109,8 +115,7 @@
  * PUBLIC: char *tail __P((char *));
  */
 char *
-tail(path)
-	char *path;
+tail(char *path)
 {
 	char *p;
 
@@ -120,23 +125,161 @@
 }
 
 /*
+ * join --
+ *	Join two paths; need free.
+ *
+ * PUBLIC: char *join __P((char *, char *));
+ */
+char *
+join(
+    char *path1,
+    char *path2)
+{
+	char *p;
+
+	if (path1[0] == '\0' || path2[0] == '/')
+		return strdup(path2);
+	(void)asprintf(&p, path1[strlen(path1)-1] == '/' ?
+	    "%s%s" : "%s/%s", path1, path2);
+	return p;
+}
+
+/*
+ * expanduser --
+ *	Return a "~" or "~user" expanded path; need free.
+ *
+ * PUBLIC: char *expanduser __P((char *));
+ */
+char *
+expanduser(char *str)
+{
+	struct passwd *pwd;
+	char *p, *t, *u, *h;
+
+	/*
+	 * This function always expands the content between the
+	 * leading '~' and the first '/' or '\0' from the input.
+	 * Return NULL whenever we fail to do so.
+	 */
+	if (*str != '~')
+		return (NULL);
+	p = str + 1;
+	for (t = p; *t != '/' && *t != '\0'; ++t)
+		continue;
+	if (t == p) {
+		/* ~ */
+		if (issetugid() != 0 ||
+		    (h = getenv("HOME")) == NULL) {
+			if (((h = getlogin()) != NULL &&
+			     (pwd = getpwnam(h)) != NULL) ||
+			    (pwd = getpwuid(getuid())) != NULL)
+				h = pwd->pw_dir;
+			else
+				return (NULL);
+		}
+	} else {
+		/* ~user */
+		if ((u = strndup(p, t - p)) == NULL)
+			return (NULL);
+		if ((pwd = getpwnam(u)) == NULL) {
+			free(u);
+			return (NULL);
+		} else
+			h = pwd->pw_dir;
+		free(u);
+	}
+
+	for (; *t == '/' && *t != '\0'; ++t)
+		continue;
+	return (join(h, t));
+}
+
+/*
+ * quote --
+ *	Return a escaped string for /bin/sh; need free.
+ *
+ * PUBLIC: char *quote __P((char *));
+ */
+char *
+quote(char *str)
+{
+	char *p, *t;
+	size_t i = 0, n = 0;
+	int unsafe = 0;
+
+	for (p = str; *p != '\0'; p++, i++) {
+		if (*p == '\'')
+			n++;
+		if (unsafe)
+			continue;
+		if (isascii(*p)) {
+			if (isalnum(*p))
+				continue;
+			switch (*p) {
+			case '%': case '+': case ',': case '-': case '.':
+			case '/': case ':': case '=': case '@': case '_':
+				continue;
+			}
+		}
+		unsafe = 1;
+	}
+	if (!unsafe)
+		t = strdup(str);
+#define SQT "'\\''"
+	else if ((p = t = malloc(i + n * (sizeof(SQT) - 2) + 3)) != NULL) {
+		*p++ = '\'';
+		for (; *str != '\0'; str++) {
+			if (*str == '\'') {
+				(void)memcpy(p, SQT, sizeof(SQT) - 1);
+				p += sizeof(SQT) - 1;
+			} else
+				*p++ = *str;
+		}
+		*p++ = '\'';
+		*p = '\0';
+	}
+	return t;
+}
+
+/*
  * v_strdup --
+ *	Strdup for 8-bit 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_wstrdup --
  *	Strdup for wide character strings with an associated length.
  *
- * PUBLIC: CHAR_T *v_strdup __P((SCR *, const CHAR_T *, size_t));
+ * PUBLIC: CHAR_T *v_wstrdup __P((SCR *, const CHAR_T *, size_t));
  */
 CHAR_T *
-v_strdup(sp, str, len)
-	SCR *sp;
-	const CHAR_T *str;
-	size_t len;
+v_wstrdup(SCR *sp,
+	const CHAR_T *str,
+	size_t len)
 {
 	CHAR_T *copy;
 
-	MALLOC(sp, copy, CHAR_T *, len + 1);
+	MALLOC(sp, copy, CHAR_T *, (len + 1) * sizeof(CHAR_T));
 	if (copy == NULL)
 		return (NULL);
-	memcpy(copy, str, len * sizeof(CHAR_T));
+	MEMCPY(copy, str, len);
 	copy[len] = '\0';
 	return (copy);
 }
@@ -145,17 +288,17 @@
  * nget_uslong --
  *      Get an unsigned long, checking for overflow.
  *
- * PUBLIC: enum nresult nget_uslong __P((u_long *, const char *, char **, int));
+ * PUBLIC: enum nresult nget_uslong __P((u_long *, const CHAR_T *, CHAR_T **, int));
  */
 enum nresult
-nget_uslong(valp, p, endp, base)
-	u_long *valp;
-	const char *p;
-	char **endp;
-	int base;
+nget_uslong(
+	u_long *valp,
+	const CHAR_T *p,
+	CHAR_T **endp,
+	int base)
 {
 	errno = 0;
-	*valp = strtoul(p, endp, base);
+	*valp = STRTOUL(p, endp, base);
 	if (errno == 0)
 		return (NUM_OK);
 	if (errno == ERANGE && *valp == ULONG_MAX)
@@ -167,17 +310,17 @@
  * nget_slong --
  *      Convert a signed long, checking for overflow and underflow.
  *
- * PUBLIC: enum nresult nget_slong __P((long *, const char *, char **, int));
+ * PUBLIC: enum nresult nget_slong __P((long *, const CHAR_T *, CHAR_T **, int));
  */
 enum nresult
-nget_slong(valp, p, endp, base)
-	long *valp;
-	const char *p;
-	char **endp;
-	int base;
+nget_slong(
+	long *valp,
+	const CHAR_T *p,
+	CHAR_T **endp,
+	int base)
 {
 	errno = 0;
-	*valp = strtol(p, endp, base);
+	*valp = STRTOL(p, endp, base);
 	if (errno == 0)
 		return (NUM_OK);
 	if (errno == ERANGE) {
@@ -189,14 +332,72 @@
 	return (NUM_ERR);
 }
 
-#ifdef DEBUG
-#ifdef __STDC__
-#include <stdarg.h>
+/*
+ * timepoint_steady --
+ *      Get a timestamp from a monotonic clock.
+ *
+ * PUBLIC: void timepoint_steady __P((struct timespec *));
+ */
+void
+timepoint_steady(
+	struct timespec *ts)
+{
+#ifdef __APPLE__
+	static mach_timebase_info_data_t base = { 0 };
+	uint64_t val;
+	uint64_t ns;
+
+	if (base.denom == 0)
+		(void)mach_timebase_info(&base);
+
+	val = mach_absolute_time();
+	ns = val * base.numer / base.denom;
+	ts->tv_sec = ns / 1000000000;
+	ts->tv_nsec = ns % 1000000000;
 #else
-#include <varargs.h>
+#ifdef CLOCK_MONOTONIC_FAST
+	(void)clock_gettime(CLOCK_MONOTONIC_FAST, ts);
+#else
+	(void)clock_gettime(CLOCK_MONOTONIC, ts);
 #endif
+#endif
+}
 
 /*
+ * timepoint_system --
+ *      Get the current calendar time.
+ *
+ * PUBLIC: void timepoint_system __P((struct timespec *));
+ */
+void
+timepoint_system(
+	struct timespec *ts)
+{
+#ifdef __APPLE__
+	clock_serv_t clk;
+	mach_timespec_t mts;
+	kern_return_t kr;
+
+	kr = host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &clk);
+	if (kr != KERN_SUCCESS)
+		return;
+	(void)clock_get_time(clk, &mts);
+	(void)mach_port_deallocate(mach_task_self(), clk);
+	ts->tv_sec = mts.tv_sec;
+	ts->tv_nsec = mts.tv_nsec;
+#else
+#ifdef CLOCK_REALTIME_FAST
+	(void)clock_gettime(CLOCK_REALTIME_FAST, ts);
+#else
+	(void)clock_gettime(CLOCK_REALTIME, ts);
+#endif
+#endif
+}
+
+#ifdef DEBUG
+#include <stdarg.h>
+
+/*
  * TRACE --
  *	debugging trace routine.
  *
@@ -203,14 +404,10 @@
  * PUBLIC: void TRACE __P((SCR *, const char *, ...));
  */
 void
-#ifdef __STDC__
-TRACE(SCR *sp, const char *fmt, ...)
-#else
-TRACE(sp, fmt, va_alist)
-	SCR *sp;
-	char *fmt;
-	va_dcl
-#endif
+TRACE(
+	SCR *sp,
+	const char *fmt,
+	...)
 {
 	FILE *tfp;
 	va_list ap;
@@ -217,11 +414,7 @@
 
 	if ((tfp = sp->gp->tracefp) == NULL)
 		return;
-#ifdef __STDC__
 	va_start(ap, fmt);
-#else
-	va_start(ap);
-#endif
 	(void)vfprintf(tfp, fmt, ap);
 	va_end(ap);
 

Modified: trunk/contrib/nvi/common/util.h
===================================================================
--- trunk/contrib/nvi/common/util.h	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/common/util.h	2018-06-10 20:23:48 UTC (rev 10823)
@@ -6,7 +6,7 @@
  *
  * See the LICENSE file for redistribution information.
  *
- *	@(#)util.h	10.5 (Berkeley) 3/16/96
+ *	$Id: util.h,v 10.7 2013/02/24 21:00:10 zy Exp $
  */
 
 /* Macros to init/set/clear/test flags. */
@@ -54,3 +54,40 @@
 	 NUM_OK)
 #define	NADD_USLONG(sp, v1, v2)						\
 	(NPFITS(ULONG_MAX, (v1), (v2)) ? NUM_OK : NUM_OVER)
+
+/* Macros for min/max. */
+#undef	MIN
+#undef	MAX
+#define	MIN(_a,_b)	((_a)<(_b)?(_a):(_b))
+#define	MAX(_a,_b)	((_a)<(_b)?(_b):(_a))
+
+/* Operations on timespecs */
+#undef timespecclear
+#undef timespecisset
+#undef timespeccmp
+#undef timespecadd
+#undef timespecsub
+#define	timespecclear(tvp)	((tvp)->tv_sec = (tvp)->tv_nsec = 0)
+#define	timespecisset(tvp)	((tvp)->tv_sec || (tvp)->tv_nsec)
+#define	timespeccmp(tvp, uvp, cmp)					\
+	(((tvp)->tv_sec == (uvp)->tv_sec) ?				\
+	    ((tvp)->tv_nsec cmp (uvp)->tv_nsec) :			\
+	    ((tvp)->tv_sec cmp (uvp)->tv_sec))
+#define timespecadd(vvp, uvp)						\
+	do {								\
+		(vvp)->tv_sec += (uvp)->tv_sec;				\
+		(vvp)->tv_nsec += (uvp)->tv_nsec;			\
+		if ((vvp)->tv_nsec >= 1000000000) {			\
+			(vvp)->tv_sec++;				\
+			(vvp)->tv_nsec -= 1000000000;			\
+		}							\
+	} while (0)
+#define timespecsub(vvp, uvp)						\
+	do {								\
+		(vvp)->tv_sec -= (uvp)->tv_sec;				\
+		(vvp)->tv_nsec -= (uvp)->tv_nsec;			\
+		if ((vvp)->tv_nsec < 0) {				\
+			(vvp)->tv_sec--;				\
+			(vvp)->tv_nsec += 1000000000;			\
+		}							\
+	} while (0)

Modified: trunk/contrib/nvi/docs/USD.doc/vi.man/vi.1
===================================================================
--- trunk/contrib/nvi/docs/USD.doc/vi.man/vi.1	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/docs/USD.doc/vi.man/vi.1	2018-06-10 20:23:48 UTC (rev 10823)
@@ -2,1619 +2,2745 @@
 .\"     The Regents of the University of California.  All rights reserved.
 .\" Copyright (c) 1994, 1995, 1996
 .\"	Keith Bostic.  All rights reserved.
+.\" Copyright (c) 2011
+.\"	Zhihao Yuan.  All rights reserved.
 .\"
-.\" This document may not be republished without written permission from
-.\" Keith Bostic. 
+.\" The vi program is freely redistributable.
+.\" You are welcome to copy, modify and share it with others
+.\" under the conditions listed in the LICENSE file.
+.\" If any company (not individual!) finds vi sufficiently useful
+.\" that you would have purchased it, or if any company wishes to
+.\" redistribute it, contributions to the authors would be appreciated.
 .\"
-.\" See the LICENSE file for redistribution information.
+.\"     $Id: vi.1,v 9.0 2013/11/02 12:11:56 zy Exp $
+.\"     $FreeBSD: stable/10/contrib/nvi/docs/USD.doc/vi.man/vi.1 258231 2013-11-16 19:22:13Z gjb $
 .\"
-.\"     @(#)vi.1	8.51 (Berkeley) 10/10/96
-.\"	$FreeBSD: src/contrib/nvi/docs/USD.doc/vi.man/vi.1,v 1.5 2001/01/03 18:32:10 ben Exp $
-.\"
-.TH VI 1 "October 10, 1996"
-.UC
-.SH NAME
-ex, vi, view \- text editors
-.SH SYNOPSIS
-.B ex
-[\c
-.B -eFGRrSsv\c
-] [\c
-.BI -c " cmd"\c
-] [\c
-.BI -t " tag"\c
-] [\c
-.BI -w " size"\c
-] [file ...]
-.br
-.B vi
-[\c
-.B -eFGlRrSv\c
-] [\c
-.BI -c " cmd"\c
-] [\c
-.BI -t " tag"\c
-] [\c
-.BI -w " size"\c
-] [file ...]
-.br
-.B view
-[\c
-.B -eFGRrSv\c
-] [\c
-.BI -c " cmd"\c
-] [\c
-.BI -t " tag"\c
-] [\c
-.BI -w " size"\c
-] [file ...]
-.SH LICENSE
-The vi program is freely redistributable.  You are welcome to copy,
-modify and share it with others under the conditions listed in the
-LICENSE file.  If any company (not individual!) finds vi sufficiently
-useful that you would have purchased it, or if any company wishes to
-redistribute it, contributions to the authors would be appreciated.
-.SH DESCRIPTION
-.I \&Vi
-is a screen oriented text editor.
-.I \&Ex
+.Dd November 2, 2013
+.Dt VI 1
+.Os
+.Sh NAME
+.Nm ex , vi , view
+.Nd text editors
+.Sh SYNOPSIS
+.Nm ex
+.Op Fl FRrSsv
+.Op Fl c Ar cmd
+.Op Fl t Ar tag
+.Op Fl w Ar size
+.Op Ar
+.Nm vi\ \&
+.Op Fl eFRrS
+.Op Fl c Ar cmd
+.Op Fl t Ar tag
+.Op Fl w Ar size
+.Op Ar
+.Nm view
+.Op Fl eFrS
+.Op Fl c Ar cmd
+.Op Fl t Ar tag
+.Op Fl w Ar size
+.Op Ar
+.Sh DESCRIPTION
+.Nm vi
+is a screen-oriented text editor.
+.Nm ex
 is a line-oriented text editor.
-.I \&Ex
+.Nm ex
 and
-.I \&vi
+.Nm vi
 are different interfaces to the same program,
 and it is possible to switch back and forth during an edit session.
-.I View
+.Nm view
 is the equivalent of using the
-.B \-R
-(read-only) option of
-.IR \&vi .
-.PP
+.Fl R
+.Pq read-only
+option of
+.Nm vi .
+.Pp
 This manual page is the one provided with the
-.I nex/nvi
+.Nm nex Ns / Ns Nm nvi
 versions of the
-.I ex/vi
+.Nm ex Ns / Ns Nm vi
 text editors.
-.I Nex/nvi
+.Nm nex Ns / Ns Nm nvi
 are intended as bug-for-bug compatible replacements for the original
-Fourth Berkeley Software Distribution (4BSD)
-.I \&ex
+Fourth Berkeley Software Distribution
+.Pq 4BSD
+.Nm ex
 and
-.I \&vi
+.Nm vi
 programs.
 For the rest of this manual page,
-.I nex/nvi
+.Nm nex Ns / Ns Nm nvi
 is used only when it's necessary to distinguish it from the historic
 implementations of
-.IR ex/vi .
-.PP
+.Nm ex Ns / Ns Nm vi .
+.Pp
 This manual page is intended for users already familiar with
-.IR ex/vi .
+.Nm ex Ns / Ns Nm vi .
 Anyone else should almost certainly read a good tutorial on the
 editor before this manual page.
-If you're in an unfamiliar environment, and you absolutely have to
-get work done immediately, read the section after the options
-description, entitled ``Fast Startup''.
+If you're in an unfamiliar environment,
+and you absolutely have to get work done immediately,
+read the section after the options description, entitled
+.Sx FAST STARTUP .
 It's probably enough to get you going.
-.PP
+.Pp
 The following options are available:
-.TP
-.B \-c
+.Bl -tag -width "-w size "
+.It Fl c Ar cmd
 Execute
-.B cmd
-immediately after starting the edit session.
-Particularly useful for initial positioning in the file, however
-.B cmd
+.Ar cmd
+on the first file loaded.
+Particularly useful for initial positioning in the file, although
+.Ar cmd
 is not limited to positioning commands.
-This is the POSIX 1003.2 interface for the historic ``+cmd'' syntax.
-.I Nex/nvi
+This is the POSIX 1003.2 interface for the historic
+.Dq +cmd
+syntax.
+.Nm nex Ns / Ns Nm nvi
 supports both the old and new syntax.
-.TP
-.B \-e
+.It Fl e
 Start editing in ex mode, as if the command name were
-.IR \&ex .
-.TP
-.B \-F
+.Nm ex .
+.It Fl F
 Don't copy the entire file when first starting to edit.
 (The default is to make a copy in case someone else modifies
 the file during your edit session.)
-.TP
-.B \-l
-Start editing with the lisp and showmatch options set.
-.TP
-.B \-G
-Start editing in gtags mode, as if the gtagsmode option was set.
-.TP
-.B \-R
+.\" .It Fl l
+.\" Start editing with the lisp and showmatch options set.
+.It Fl R
 Start editing in read-only mode, as if the command name was
-.IR view ,
+.Nm view ,
 or the
-.B readonly
+.Cm readonly
 option was set.
-.TP
-.B \-r
+.It Fl r
 Recover the specified files, or, if no files are specified,
 list the files that could be recovered.
 If no recoverable files by the specified name exist,
 the file is edited as if the
-.B \-r
+.Fl r
 option had not been specified.
-.TP
-.B \-S
+.It Fl S
 Run with the
-.B secure
+.Cm secure
 edit option set, disallowing all access to external programs.
-.TP
-.B \-s
+.It Fl s
 Enter batch mode; applicable only to
-.I \&ex
+.Nm ex
 edit sessions.
 Batch mode is useful when running
-.I \&ex
+.Nm ex
 scripts.
-Prompts, informative messages and other user oriented message
-are turned off,
+Prompts, informative messages and other user oriented messages are turned off,
 and no startup files or environment variables are read.
-This is the POSIX 1003.2 interface for the historic ``\-'' argument.
-.I \&Nex/nvi
+This is the POSIX 1003.2 interface for the historic
+.Dq -
+argument.
+.Nm nex Ns / Ns Nm nvi
 supports both the old and new syntax.
-.TP
-.B \-t
-Start editing at the specified tag.
-(See
-.IR ctags (1)).
-.TP
-.B \-w
+.It Fl t Ar tag
+Start editing at the specified
+.Ar tag
+.Pq see Xr ctags 1 .
+.It Fl v
+Start editing in vi mode, as if the command name was
+.Nm vi .
+.It Fl w Ar size
 Set the initial window size to the specified number of lines.
-.TP
-.B \-v
-Start editing in vi mode, as if the command name was
-.I \&vi
-or
-.IR view .
-.PP
+.El
+.Pp
 Command input for
-.I ex/vi
+.Nm ex Ns / Ns Nm vi
 is read from the standard input.
 In the
-.I \&vi
+.Nm vi
 interface, it is an error if standard input is not a terminal.
 In the
-.I \&ex
+.Nm ex
 interface, if standard input is not a terminal,
-.I \&ex
-will read commands from it regardless, however, the session will be a
+.Nm ex
+will read commands from it regardless; however, the session will be a
 batch mode session, exactly as if the
-.B \-s
+.Fl s
 option had been specified.
-.PP
-.I Ex/vi
-exits 0 on success, and greater than 0 if an error occurs.
-.SH FAST STARTUP
+.Sh FAST STARTUP
 This section will tell you the minimum amount that you need to
 do simple editing tasks using
-.IR \&vi .
-If you've never used any screen editor before, you're likely to have
-problems even with this simple introduction.
+.Nm vi .
+If you've never used any screen editor before,
+you're likely to have problems even with this simple introduction.
 In that case you should find someone that already knows
-.I \&vi
+.Nm vi
 and have them walk you through this section.
-.PP
-.I \&Vi
+.Pp
+.Nm vi
 is a screen editor.
-This means that it takes up almost the entire screen, displaying part
-of the file on each screen line, except for the last line of the screen.
+This means that it takes up almost the entire screen,
+displaying part of the file on each screen line,
+except for the last line of the screen.
 The last line of the screen is used for you to give commands to
-.IR \&vi ,
+.Nm vi ,
 and for
-.I \&vi
+.Nm vi
 to give information to you.
-.PP
+.Pp
 The other fact that you need to understand is that
-.I \&vi
-is a modeful editor, i.e. you are either entering text or you
-are executing commands, and you have to be in the right mode
-to do one or the other.
+.Nm vi
+is a modeful editor,
+i.e., you are either entering text or you are executing commands,
+and you have to be in the right mode to do one or the other.
 You will be in command mode when you first start editing a file.
 There are commands that switch you into input mode.
 There is only one key that takes you out of input mode,
-and that is the <escape> key.
-(Key names are written using less-than and greater-than signs, e.g.
-<escape> means the ``escape'' key, usually labeled ``esc'' on your
-terminal's keyboard.)
+and that is the
+.Aq escape
+key.
+.Pp
+Key names are written using less-than and greater-than signs, e.g.,
+.Aq escape
+means the
+.Dq escape
+key, usually labeled
+.Dq Esc
+on your terminal's keyboard.
 If you're ever confused as to which mode you're in,
-keep entering the <escape> key until
-.I \&vi
+keep entering the
+.Aq escape
+key until
+.Nm vi
 beeps at you.
-(Generally,
-.I \&vi
+Generally,
+.Nm vi
 will beep at you if you try and do something that's not allowed.
-It will also display error messages.)
-.PP
-To start editing a file, enter the command ``vi file_name<carriage-return>''.
-The command you should enter as soon as you start editing is
-``:set verbose showmode<carriage-return>''.
+It will also display error messages.
+.Pp
+To start editing a file, enter the following command:
+.Pp
+.Dl $ vi file
+.Pp
+The command you should enter as soon as you start editing is:
+.Pp
+.Dl :set verbose showmode
+.Pp
 This will make the editor give you verbose error messages and display
 the current mode at the bottom of the screen.
-.PP
+.Pp
 The commands to move around the file are:
-.TP
-.B h
+.Bl -tag -width Ds
+.It Cm h
 Move the cursor left one character.
-.TP
-.B j
+.It Cm j
 Move the cursor down one line.
-.TP
-.B k
+.It Cm k
 Move the cursor up one line.
-.TP
-.B l
+.It Cm l
 Move the cursor right one character.
-.TP
-.B <cursor-arrows>
+.It Aq Cm cursor-arrows
 The cursor arrow keys should work, too.
-.TP
-.B /text<carriage-return>
-Search for the string ``text'' in the file,
+.It Cm / Ns text
+Search for the string
+.Dq text
+in the file,
 and move the cursor to its first character.
-.PP
+.El
+.Pp
 The commands to enter new text are:
-.TP
-.B a
-Append new text,
-.I after
-the cursor.
-.TP
-.B i
-Insert new text,
-.I before
-the cursor.
-.TP
-.B o
-Open a new line below the line the cursor is on, and start
-entering text.
-.TP
-.B O
-Open a new line above the line the cursor is on, and start
-entering text.
-.TP
-.B <escape>
-Once you've entered input mode using the one of the
-.BR \&a ,
-.BR \&i ,
-.BR \&O
-or 
-.B \&o
+.Bl -tag -width "<escape>"
+.It Cm a
+Append new text, after the cursor.
+.It Cm i
+Insert new text, before the cursor.
+.It Cm o
+Open a new line below the line the cursor is on, and start entering text.
+.It Cm O
+Open a new line above the line the cursor is on, and start entering text.
+.It Aq Cm escape
+Once you've entered input mode using one of the
+.Cm a ,
+.Cm i ,
+.Cm o
+or
+.Cm O
 commands, use
-.B <escape>
+.Aq Cm escape
 to quit entering text and return to command mode.
-.PP
+.El
+.Pp
 The commands to copy text are:
-.TP
-.B yy
+.Bl -tag -width Ds
+.It Cm yy
 Copy the line the cursor is on.
-.TP
-.B p
+.It Cm p
 Append the copied line after the line the cursor is on.
-.PP
+.El
+.Pp
 The commands to delete text are:
-.TP
-.B dd
+.Bl -tag -width Ds
+.It Cm dd
 Delete the line the cursor is on.
-.TP
-.B x
+.It Cm x
 Delete the character the cursor is on.
-.PP
+.El
+.Pp
 The commands to write the file are:
-.TP
-.B :w<carriage-return>
+.Bl -tag -width Ds
+.It Cm :w
 Write the file back to the file with the name that you originally used
 as an argument on the
-.I \&vi
+.Nm vi
 command line.
-.TP
-.B ":w file_name<carriage-return>"
-Write the file back to the file with the name ``file_name''.
-.PP
+.It Cm :w Ar file_name
+Write the file back to the file with the name
+.Ar file_name .
+.El
+.Pp
 The commands to quit editing and exit the editor are:
-.TP
-.B :q<carriage-return>
-Quit editing and leave vi (if you've modified the file, but not
-saved your changes,
-.I \&vi
+.Bl -tag -width Ds
+.It Cm :q
+Quit editing and leave
+.Nm vi
+(if you've modified the file, but not saved your changes,
+.Nm vi
 will refuse to quit).
-.TP
-.B :q!<carriage-return>
+.It Cm :q!
 Quit, discarding any modifications that you may have made.
-.PP
-One final caution.
+.El
+.Pp
+One final caution:
 Unusual characters can take up more than one column on the screen,
 and long lines can take up more than a single screen line.
-The above commands work on ``physical'' characters and lines,
-i.e. they affect the entire line no matter how many screen lines it
-takes up and the entire character no matter how many screen columns
-it takes up.
-.SH VI COMMANDS
+The above commands work on
+.Dq physical
+characters and lines,
+i.e., they affect the entire line no matter how many screen lines it takes up
+and the entire character no matter how many screen columns it takes up.
+.Sh REGULAR EXPRESSIONS
+.Nm ex Ns / Ns Nm vi
+supports regular expressions
+.Pq REs ,
+as documented in
+.Xr re_format 7 ,
+for line addresses, as the first part of the
+.Nm ex Cm substitute ,
+.Cm global
+and
+.Cm v
+commands, and in search patterns.
+Basic regular expressions
+.Pq BREs
+are enabled by default;
+extended regular expressions
+.Pq EREs
+are used if the
+.Cm extended
+option is enabled.
+The use of regular expressions can be largely disabled using the
+.Cm magic
+option.
+.Pp
+The following strings have special meanings in the
+.Nm ex Ns / Ns Nm vi
+version of regular expressions:
+.Bl -bullet -offset 6u
+.It
+An empty regular expression is equivalent to the last regular expression used.
+.It
+.Sq \e\(la
+matches the beginning of the word.
+.It
+.Sq \e\(ra
+matches the end of the word.
+.It
+.Sq \(a~
+matches the replacement part of the last
+.Cm substitute
+command.
+.El
+.Sh BUFFERS
+A buffer is an area where commands can save changed or deleted text
+for later use.
+.Nm vi
+buffers are named with a single character preceded by a double quote,
+for example
+.Pf \&" Ns Aq c ;
+.Nm ex
+buffers are the same,
+but without the double quote.
+.Nm nex Ns / Ns Nm nvi
+permits the use of any character without another meaning in the position where
+a buffer name is expected.
+.Pp
+All buffers are either in
+.Em line mode
+or
+.Em character mode .
+Inserting a buffer in line mode into the text creates new lines for each of the
+lines it contains, while a buffer in character mode creates new lines for any
+lines
+.Em other
+than the first and last lines it contains.
+The first and last lines are inserted at the current cursor position, becoming
+part of the current line.
+If there is more than one line in the buffer,
+the current line itself will be split.
+All
+.Nm ex
+commands which store text into buffers do so in line mode.
+The behaviour of
+.Nm vi
+commands depend on their associated motion command:
+.Bl -bullet -offset 6u
+.It
+.Aq Cm control-A ,
+.Cm h ,
+.Cm l ,
+.Cm ,\& ,
+.Cm 0 ,
+.Cm B ,
+.Cm E ,
+.Cm F ,
+.Cm T ,
+.Cm W ,
+.Cm ^ ,
+.Cm b ,
+.Cm e ,
+.Cm f
+and
+.Cm t
+make the destination buffer character-oriented.
+.It
+.Cm j ,
+.Aq Cm control-M ,
+.Cm k ,
+.Cm ' ,
+.Cm - ,
+.Cm G ,
+.Cm H ,
+.Cm L ,
+.Cm M ,
+.Cm _
+and
+.Cm |\&
+make the destination buffer line-oriented.
+.It
+.Cm $ ,
+.Cm % ,
+.Cm ` ,
+.Cm (\& ,
+.Cm )\& ,
+.Cm / ,
+.Cm ?\& ,
+.Cm [[ ,
+.Cm ]] ,
+.Cm {
+and
+.Cm }
+make the destination buffer character-oriented, unless the starting and
+end positions are the first and last characters on a line.
+In that case, the buffer is line-oriented.
+.El
+.Pp
+The
+.Nm ex
+command
+.Cm display buffers
+displays the current mode for each buffer.
+.Pp
+Buffers named
+.Sq a
+through
+.Sq z
+may be referred to using their uppercase equivalent, in which case new content
+will be appended to the buffer, instead of replacing it.
+.Pp
+Buffers named
+.Sq 1
+through
+.Sq 9
+are special.
+A region of text modified using the
+.Cm c
+.Pq change
+or
+.Cm d
+.Pq delete
+commands is placed into the numeric buffer
+.Sq 1
+if no other buffer is specified and if it meets one of the following conditions:
+.Bl -bullet -offset 6u
+.It
+It includes characters from more than one line.
+.It
+It is specified using a line-oriented motion.
+.It
+It is specified using one of the following motion commands:
+.Aq Cm control-A ,
+.Cm ` Ns Aq Cm character ,
+.Cm n ,
+.Cm N ,
+.Cm % ,
+.Cm / ,
+.Cm { ,
+.Cm } ,
+.Cm \&( ,
+.Cm \&) ,
+and
+.Cm \&? .
+.El
+.Pp
+Before this copy is done, the previous contents of buffer
+.Sq 1
+are moved into buffer
+.Sq 2 ,
+.Sq 2
+into buffer
+.Sq 3 ,
+and so on.
+The contents of buffer
+.Sq 9
+are discarded.
+Note that this rotation occurs
+.Em regardless
+of the user specifying another buffer.
+In
+.Nm vi ,
+text may be explicitly stored into the numeric buffers.
+In this case, the buffer rotation occurs before the replacement of the buffer's
+contents.
+The numeric buffers are only available in
+.Nm vi
+mode.
+.Sh VI COMMANDS
 The following section describes the commands available in the command
 mode of the
-.I \&vi
+.Nm vi
 editor.
-In each entry below, the tag line is a usage synopsis for the command
-character.
-.PP
-.TP
-.B "[count] <control-A>"
+The following words have a special meaning in the commands description:
+.Pp
+.Bl -tag -width bigword -compact -offset 3u
+.It Ar bigword
+A set of non-whitespace characters.
+.It Ar buffer
+Temporary area where commands may place text.
+If not specified, the default buffer is used.
+See also
+.Sx BUFFERS ,
+above.
+.It Ar count
+A positive number used to specify the desired number of iterations
+of a command.
+It defaults to 1 if not specified.
+.It Ar motion
+A cursor movement command which indicates the other end of the affected region
+of text, the first being the current cursor position.
+Repeating the command character makes it affect the whole current line.
+.It Ar word
+A sequence of letters, digits or underscores.
+.El
+.Pp
+.Ar buffer
+and
+.Ar count ,
+if both present, may be specified in any order.
+.Ar motion
+and
+.Ar count ,
+if both present, are effectively multiplied together
+and considered part of the motion.
+.Pp
+.Bl -tag -width Ds -compact
+.It Xo
+.Aq Cm control-A
+.Xc
 Search forward
-.I count
-times for the current word.
-.TP
-.B "[count] <control-B>"
+for the word starting at the cursor position.
+.Pp
+.It Xo
+.Op Ar count
+.Aq Cm control-B
+.Xc
 Page backwards
-.I count
+.Ar count
 screens.
-.TP
-.B "[count] <control-D>"
+Two lines of overlap are maintained, if possible.
+.Pp
+.It Xo
+.Op Ar count
+.Aq Cm control-D
+.Xc
 Scroll forward
-.I count
+.Ar count
 lines.
-.TP
-.B "[count] <control-E>"
+If
+.Ar count
+is not given, scroll forward the number of lines specified by the last
+.Aq Cm control-D
+or
+.Aq Cm control-U
+command.
+If this is the first
+.Aq Cm control-D
+command, scroll half the number of lines in the current screen.
+.Pp
+.It Xo
+.Op Ar count
+.Aq Cm control-E
+.Xc
 Scroll forward
-.I count
+.Ar count
 lines, leaving the current line and column as is, if possible.
-.TP
-.B "[count] <control-F>"
+.Pp
+.It Xo
+.Op Ar count
+.Aq Cm control-F
+.Xc
 Page forward
-.I count
+.Ar count
 screens.
-.TP
-.B "<control-G>"
-Display the file information.
-.TP
-.B "<control-H>"
-.TP
-.B "[count] h"
+Two lines of overlap are maintained, if possible.
+.Pp
+.It Aq Cm control-G
+Display the following file information:
+the file name
+.Pq as given to Nm vi ;
+whether the file has been modified since it was last written;
+if the file is read-only;
+the current line number;
+the total number of lines in the file;
+and the current line number as a percentage of the total lines in the file.
+.Pp
+.It Xo
+.Op Ar count
+.Aq Cm control-H
+.Xc
+.It Xo
+.Op Ar count
+.Cm h
+.Xc
 Move the cursor back
-.I count
+.Ar count
 characters in the current line.
-.TP
-.B "[count] <control-J>"
-.TP
-.B "[count] <control-N>"
-.TP
-.B "[count] j"
+.Pp
+.It Xo
+.Op Ar count
+.Aq Cm control-J
+.Xc
+.It Xo
+.Op Ar count
+.Aq Cm control-N
+.Xc
+.It Xo
+.Op Ar count
+.Cm j
+.Xc
 Move the cursor down
-.I count
+.Ar count
 lines without changing the current column.
-.TP
-.B "<control-L>"
-.TP
-.B "<control-R>"
+.Pp
+.It Aq Cm control-L
+.It Aq Cm control-R
 Repaint the screen.
-.TP
-.B "[count] <control-M>"
-.TP
-.B "[count] +"
+.Pp
+.It Xo
+.Op Ar count
+.Aq Cm control-M
+.Xc
+.It Xo
+.Op Ar count
+.Cm +
+.Xc
 Move the cursor down
-.I count
-lines to the first nonblank character of that line.
-.TP
-.B "[count] <control-P>"
-.TP
-.B "[count] k"
+.Ar count
+lines to the first non-blank character of that line.
+.Pp
+.It Xo
+.Op Ar count
+.Aq Cm control-P
+.Xc
+.It Xo
+.Op Ar count
+.Cm k
+.Xc
 Move the cursor up
-.I count
+.Ar count
 lines, without changing the current column.
-.TP
-.B "<control-T>"
+.Pp
+.It Aq Cm control-T
 Return to the most recent tag context.
-.TP
-.B "<control-U>"
+.Pp
+.It Xo
+.Op Ar count
+.Aq Cm control-U
+.Xc
 Scroll backwards
-.I count
+.Ar count
 lines.
-.TP
-.B "<control-W>"
-Switch to the next lower screen in the window, or, to the first
-screen if there are no lower screens in the window.
-.TP
-.B "<control-Y>"
+If
+.Ar count
+is not given, scroll backwards the number of lines specified by the last
+.Aq Cm control-D
+or
+.Aq Cm control-U
+command.
+If this is the first
+.Aq Cm control-U
+command, scroll half the number of lines in the current screen.
+.Pp
+.It Aq Cm control-W
+Switch to the next lower screen in the window,
+or to the first screen if there are no lower screens in the window.
+.Pp
+.It Xo
+.Op Ar count
+.Aq Cm control-Y
+.Xc
 Scroll backwards
-.I count
+.Ar count
 lines, leaving the current line and column as is, if possible.
-.TP
-.B "<control-Z>"
+.Pp
+.It Aq Cm control-Z
 Suspend the current editor session.
-.TP
-.B "<escape>"
-Execute
-.I \&ex
-commands or cancel partial commands.
-.TP
-.B "<control-]>"
+.Pp
+.It Aq Cm escape
+Execute the
+.Nm ex
+command being entered, or cancel it if it is only partial.
+.Pp
+.It Aq Cm control-]
 Push a tag reference onto the tag stack.
-In gtagsmode, if at the first column of line,
-locate function references otherwise function definitions.
-.TP
-.B "<control-^>"
+.Pp
+.It Aq Cm control-^
 Switch to the most recently edited file.
-.TP
-.B "[count] <space>"
-.TP
-.B "[count] l"
+.Pp
+.It Xo
+.Op Ar count
+.Aq Cm space
+.Xc
+.It Xo
+.Op Ar count
+.Cm l
+.Xc
 Move the cursor forward
-.I count
+.Ar count
 characters without changing the current line.
-.TP
-.B "[count] ! motion shell-argument(s)"
-Replace text with results from a shell command.
-.TP
-.B "[count] # #|+|-"
-Increment or decrement the cursor number.
-.TP
-.B "[count] $"
+.Pp
+.It Xo
+.Op Ar count
+.Cm !\&
+.Ar motion shell-argument(s)
+.Aq Li carriage-return
+.Xc
+Replace the lines spanned by
+.Ar count
+and
+.Ar motion
+with the output
+.Pq standard output and standard error
+of the program named by the
+.Cm shell
+option, called with a
+.Fl c
+flag followed by the
+.Ar shell-argument(s)
+.Pq bundled into a single argument .
+Within
+.Ar shell-argument(s) ,
+the
+.Sq % ,
+.Sq #
+and
+.Sq !\&
+characters are expanded to the current file name,
+the previous current file name,
+and the command text of the previous
+.Cm !\&
+or
+.Cm :!
+commands, respectively.
+The special meaning of
+.Sq % ,
+.Sq #
+and
+.Sq !\&
+can be overridden by escaping them with a backslash.
+.Pp
+.It Xo
+.Op Ar count
+.Cm #
+.Sm off
+.Cm # | + | -
+.Sm on
+.Xc
+Increment
+.Pq trailing So # Sc or So + Sc
+or decrement
+.Pq trailing Sq -
+the number under the cursor by
+.Ar count ,
+starting at the cursor position or at the first non-blank
+character following it.
+Numbers with a leading
+.Sq 0x
+or
+.Sq 0X
+are interpreted as hexadecimal numbers.
+Numbers with a leading
+.Sq 0
+are interpreted as octal numbers unless they contain a non-octal digit.
+Other numbers may be prefixed with a
+.Sq +
+or
+.Sq -
+sign.
+.Pp
+.It Xo
+.Op Ar count
+.Cm $
+.Xc
 Move the cursor to the end of a line.
-.TP
-.B "%"
-Move to the matching character.
-.TP
-.B "&"
+If
+.Ar count
+is specified, additionally move the cursor down
+.Ar count
+\- 1 lines.
+.Pp
+.It Cm %
+Move to the
+.Cm matchchars
+character matching
+the one found at the cursor position or the closest to the right of it.
+.Pp
+.It Cm &
 Repeat the previous substitution command on the current line.
-.TP
-.B "'<character>"
-.TP
-.B "`<character>"
-Return to a context marked by the character
-.IR <character> .
-.TP
-.B "[count] ("
-Back up
-.I count
-sentences.
-.TP
-.B "[count] )"
-Move forward
-.I count
-sentences.
-.TP
-.B "[count] ,"
+.Pp
+.It Xo
+.Cm ' Ns Aq Ar character
+.Xc
+.It Xo
+.Cm ` Ns Aq Ar character
+.Xc
+Return to the cursor position marked by the character
+.Ar character ,
+or, if
+.Ar character
+is
+.Sq '
+or
+.Sq ` ,
+to the position of the cursor before the last of the following commands:
+.Aq Cm control-A ,
+.Aq Cm control-T ,
+.Aq Cm control-] ,
+.Cm % ,
+.Cm ' ,
+.Cm ` ,
+.Cm (\& ,
+.Cm )\& ,
+.Cm / ,
+.Cm ?\& ,
+.Cm G ,
+.Cm H ,
+.Cm L ,
+.Cm [[ ,
+.Cm ]] ,
+.Cm { ,
+.Cm } .
+The first form returns to the first non-blank character of the line marked by
+.Ar character .
+The second form returns to the line and column marked by
+.Ar character .
+.Pp
+.It Xo
+.Op Ar count
+.Cm \&(
+.Xc
+.It Xo
+.Op Ar count
+.Cm \&)
+.Xc
+Move
+.Ar count
+sentences backward or forward, respectively.
+A sentence is an area of text that begins with the first nonblank character
+following the previous sentence, paragraph, or section
+boundary and continues until the next period, exclamation point,
+or question mark character, followed by any number of closing parentheses,
+brackets, double or single quote characters, followed by
+either an end-of-line or two whitespace characters.
+Groups of empty lines
+.Pq or lines containing only whitespace characters
+are treated as a single sentence.
+.Pp
+.It Xo
+.Op Ar count
+.Cm ,\&
+.Xc
 Reverse find character
-.I count
+.Pq i.e., the last Cm F , f , T No or Cm t No command
+.Ar count
 times.
-.TP
-.B "[count] -"
-Move to first nonblank of the previous line,
-.I count
+.Pp
+.It Xo
+.Op Ar count
+.Cm -
+.Xc
+Move to the first non-blank character of the previous line,
+.Ar count
 times.
-.TP
-.B "[count] ."
+.Pp
+.It Xo
+.Op Ar count
+.Cm .\&
+.Xc
 Repeat the last
-.I \&vi
+.Nm vi
 command that modified text.
-.TP
-.B "/RE<carriage-return>"
-.TP
-.B "/RE/ [offset]<carriage-return>"
-.TP
-.B "?RE<carriage-return>"
-.TP
-.B "?RE? [offset]<carriage-return>"
-.TP
-.B "N"
-.TP
-.B "n"
-Search forward or backward for a regular expression.
-.TP
-.B "0"
+.Ar count
+replaces both the
+.Ar count
+argument of the repeated command and that of the associated
+.Ar motion .
+If the
+.Cm .\&
+command repeats the
+.Cm u
+command, the change log is rolled forward or backward, depending on the action
+of the
+.Cm u
+command.
+.Pp
+.It Xo
+.Pf / Ns Ar RE
+.Aq Li carriage-return
+.Xc
+.It Xo
+.Pf / Ns Ar RE Ns /
+.Op Ar offset
+.Op Cm z
+.Aq Li carriage-return
+.Xc
+.It Xo
+.Pf ?\& Ns Ar RE
+.Aq Li carriage-return
+.Xc
+.It Xo
+.Pf ?\& Ns Ar RE Ns ?\&
+.Op Ar offset
+.Op Cm z
+.Aq Li carriage-return
+.Xc
+.It Cm N
+.It Cm n
+Search forward
+.Pq Sq /
+or backward
+.Pq Sq ?\&
+for a regular expression.
+.Cm n
+and
+.Cm N
+repeat the last search in the same or opposite directions, respectively.
+If
+.Ar RE
+is empty, the last search regular expression is used.
+If
+.Ar offset
+is specified, the cursor is placed
+.Ar offset
+lines before or after the matched regular expression.
+If either
+.Cm n
+or
+.Cm N
+commands are used as motion components for the
+.Cm !\&
+command, there will be no prompt for the text of the command and the previous
+.Cm !\&
+will be executed.
+Multiple search patterns may be grouped together by delimiting them with
+semicolons and zero or more whitespace characters.
+These patterns are evaluated from left to right with the final cursor position
+determined by the last search pattern.
+A
+.Cm z
+command may be appended to the closed search expressions to reposition the
+result line.
+.Pp
+.It Cm 0
 Move to the first character in the current line.
-.TP
-.B ":"
-Execute an ex command.
-.TP
-.B "[count] ;"
+.Pp
+.It Cm :\&
+Execute an
+.Nm ex
+command.
+.Pp
+.It Xo
+.Op Ar count
+.Cm ;\&
+.Xc
 Repeat the last character find
-.I count
+.Pq i.e., the last .Cm F , f , T No or Cm t No command
+.Ar count
 times.
-.TP
-.B "[count] < motion"
-.TP
-.B "[count] > motion"
-Shift lines left or right.
-.TP
-.B "@ buffer"
-Execute a named buffer.
-.TP
-.B "[count] A"
+.Pp
+.It Xo
+.Op Ar count
+.Cm <
+.Ar motion
+.Xc
+.It Xo
+.Op Ar count
+.Cm >
+.Ar motion
+.Xc
+Shift
+.Ar count
+lines left or right, respectively, by an amount of
+.Cm shiftwidth .
+.Pp
+.It Cm @ Ar buffer
+Execute a named
+.Ar buffer
+as
+.Nm vi
+commands.
+The buffer may include
+.Nm ex
+commands too, but they must be expressed as a
+.Cm \&:
+command.
+If
+.Ar buffer
+is
+.Sq @
+or
+.Sq * ,
+then the last buffer executed shall be used.
+.Pp
+.It Xo
+.Op Ar count
+.Cm A
+.Xc
 Enter input mode, appending the text after the end of the line.
-.TP
-.B "[count] B"
+If a
+.Ar count
+argument is given, the characters input are repeated
+.Ar count
+\- 1 times after input mode is exited.
+.Pp
+.It Xo
+.Op Ar count
+.Cm B
+.Xc
 Move backwards
-.I count
+.Ar count
 bigwords.
-.TP
-.B "[buffer] [count] C"
+.Pp
+.It Xo
+.Op Ar buffer
+.Cm C
+.Xc
 Change text from the current position to the end-of-line.
-.TP
-.B "[buffer] D"
+If
+.Ar buffer
+is specified,
+.Dq yank
+the deleted text into
+.Ar buffer .
+.Pp
+.It Xo
+.Op Ar buffer
+.Cm D
+.Xc
 Delete text from the current position to the end-of-line.
-.TP
-.B "[count] E"
+If
+.Ar buffer
+is specified,
+.Dq yank
+the deleted text into
+.Ar buffer .
+.Pp
+.It Xo
+.Op Ar count
+.Cm E
+.Xc
 Move forward
-.I count
+.Ar count
 end-of-bigwords.
-.TP
-.B "[count] F <character>"
+.Pp
+.It Xo
+.Op Ar count
+.Cm F Aq Ar character
+.Xc
 Search
-.I count
+.Ar count
 times backward through the current line for
-.IR <character> .
-.TP
-.B "[count] G"
+.Aq Ar character .
+.Pp
+.It Xo
+.Op Ar count
+.Cm G
+.Xc
 Move to line
-.IR count ,
+.Ar count ,
 or the last line of the file if
-.I count
-not specified.
-.TP
-.B "[count] H"
+.Ar count
+is not specified.
+.Pp
+.It Xo
+.Op Ar count
+.Cm H
+.Xc
 Move to the screen line
-.I "count - 1"
-lines below the top of the screen.
-.TP
-.B "[count] I"
+.Ar count
+\- 1 lines below the top of the screen.
+.Pp
+.It Xo
+.Op Ar count
+.Cm I
+.Xc
 Enter input mode, inserting the text at the beginning of the line.
-.TP
-.B "[count] J"
-Join lines.
-.TP
-.B "[count] L"
+If a
+.Ar count
+argument is given,
+the characters input are repeated
+.Ar count
+\- 1 more times.
+.Pp
+.It Xo
+.Op Ar count
+.Cm J
+.Xc
+Join
+.Ar count
+lines with the current line.
+The spacing between two joined lines is set to two whitespace characters if the
+former ends with a question mark, a period or an exclamation point.
+It is set to one whitespace character otherwise.
+.Pp
+.It Xo
+.Op Ar count
+.Cm L
+.Xc
 Move to the screen line
-.I "count - 1"
-lines above the bottom of the screen.
-.TP
-.B " M"
+.Ar count
+\- 1 lines above the bottom of the screen.
+.Pp
+.It Cm M
 Move to the screen line in the middle of the screen.
-.TP
-.B "[count] O"
+.Pp
+.It Xo
+.Op Ar count
+.Cm O
+.Xc
 Enter input mode, appending text in a new line above the current line.
-.TP
-.B "[buffer] P"
-Insert text from a buffer.
-.TP
-.B "Q"
+If a
+.Ar count
+argument is given,
+the characters input are repeated
+.Ar count
+\- 1 more times.
+.Pp
+.It Xo
+.Op Ar buffer
+.Cm P
+.Xc
+Insert text from
+.Ar buffer
+before the current column if
+.Ar buffer
+is character-oriented or before the current line if it is line-oriented.
+.Pp
+.It Cm Q
 Exit
-.I \&vi
-(or visual) mode and switch to
-.I \&ex
+.Nm vi
+.Pq or visual
+mode and switch to
+.Nm ex
 mode.
-.TP
-.B "[count] R"
+.Pp
+.It Xo
+.Op Ar count
+.Cm R
+.Xc
 Enter input mode, replacing the characters in the current line.
-.TP
-.B "[buffer] [count] S"
+If a
+.Ar count
+argument is given,
+the characters input are repeated
+.Ar count
+\- 1 more times upon exit from insert mode.
+.Pp
+.It Xo
+.Op Ar buffer
+.Op Ar count
+.Cm S
+.Xc
 Substitute
-.I count
+.Ar count
 lines.
-.TP
-.B "[count] T <character>"
+If
+.Ar buffer
+is specified,
+.Dq yank
+the deleted text into
+.Ar buffer .
+.Pp
+.It Xo
+.Op Ar count
+.Cm T
+.Aq Ar character
+.Xc
 Search backwards,
-.I count
-times,
-through the current line for the character
-.I after
-the specified
-.IR <character> .
-.TP
-.B "U"
-Restore the current line to its state before the cursor last
-moved to it.
-.TP
-.B "[count] W"
+.Ar count
+times, through the current line for the character after the specified
+.Aq Ar character .
+.Pp
+.It Cm U
+Restore the current line to its state before the cursor last moved to it.
+.Pp
+.It Xo
+.Op Ar count
+.Cm W
+.Xc
 Move forward
-.I count
+.Ar count
 bigwords.
-.TP
-.B "[buffer] [count] X"
+.Pp
+.It Xo
+.Op Ar buffer
+.Op Ar count
+.Cm X
+.Xc
 Delete
-.I count
-characters before the cursor.
-.TP
-.B "[buffer] [count] Y"
-Copy (or ``yank'')
-.I count
-lines into the specified buffer.
-.TP
-.B "ZZ"
+.Ar count
+characters before the cursor, on the current line.
+If
+.Ar buffer
+is specified,
+.Dq yank
+the deleted text into
+.Ar buffer .
+.Pp
+.It Xo
+.Op Ar buffer
+.Op Ar count
+.Cm Y
+.Xc
+Copy
+.Pq or Dq yank
+.Ar count
+lines into
+.Ar buffer .
+.Pp
+.It Cm ZZ
 Write the file and exit
-.IR \&vi .
-.TP
-.B "[count] [["
+.Nm vi
+if there are no more files to edit.
+Entering two
+.Dq quit
+commands in a row ignores any remaining file to edit.
+.Pp
+.It Xo
+.Op Ar count
+.Cm [[
+.Xc
 Back up
-.I count
+.Ar count
 section boundaries.
-.TP
-.B "[count] ]]"
+.Pp
+.It Xo
+.Op Ar count
+.Cm ]]
+.Xc
 Move forward
-.I count
+.Ar count
 section boundaries.
-.TP
-.B "\&^"
-Move to first nonblank character on the current line.
-.TP
-.B "[count] _"
+.Pp
+.It Cm ^
+Move to the first non-blank character on the current line.
+.Pp
+.It Xo
+.Op Ar count
+.Cm _
+.Xc
 Move down
-.I "count - 1"
-lines, to the first nonblank character.
-.TP
-.B "[count] a"
+.Ar count
+\- 1 lines, to the first non-blank character.
+.Pp
+.It Xo
+.Op Ar count
+.Cm a
+.Xc
 Enter input mode, appending the text after the cursor.
-.TP
-.B "[count] b"
+If a
+.Ar count
+argument is given,
+the characters input are repeated
+.Ar count
+number of times.
+.Pp
+.It Xo
+.Op Ar count
+.Cm b
+.Xc
 Move backwards
-.I count
+.Ar count
 words.
-.TP
-.B "[buffer] [count] c motion"
-Change a region of text.
-.TP
-.B "[buffer] [count] d motion"
-Delete a region of text.
-.TP
-.B "[count] e"
+.Pp
+.It Xo
+.Op Ar buffer
+.Op Ar count
+.Cm c
+.Ar motion
+.Xc
+Change the region of text described by
+.Ar count
+and
+.Ar motion .
+If
+.Ar buffer
+is specified,
+.Dq yank
+the changed text into
+.Ar buffer .
+.Pp
+.It Xo
+.Op Ar buffer
+.Op Ar count
+.Cm d
+.Ar motion
+.Xc
+Delete the region of text described by
+.Ar count
+and
+.Ar motion .
+If
+.Ar buffer
+is specified,
+.Dq yank
+the deleted text into
+.Ar buffer .
+.Pp
+.It Xo
+.Op Ar count
+.Cm e
+.Xc
 Move forward
-.I count
+.Ar count
 end-of-words.
-.TP
-.B "[count] f<character>"
+.Pp
+.It Xo
+.Op Ar count
+.Cm f Aq Ar character
+.Xc
 Search forward,
-.I count
+.Ar count
 times, through the rest of the current line for
-.IR <character> .
-.TP
-.B "[count] i"
+.Aq Ar character .
+.Pp
+.It Xo
+.Op Ar count
+.Cm i
+.Xc
 Enter input mode, inserting the text before the cursor.
-.TP
-.B "m <character>"
-Save the current context (line and column) as
-.IR <character> .
-.TP
-.B "[count] o"
+If a
+.Ar count
+argument is given,
+the characters input are repeated
+.Ar count
+number of times.
+.Pp
+.It Xo
+.Cm m
+.Aq Ar character
+.Xc
+Save the current context
+.Pq line and column
+as
+.Aq Ar character .
+.Pp
+.It Xo
+.Op Ar count
+.Cm o
+.Xc
 Enter input mode, appending text in a new line under the current line.
-.TP
-.B "[buffer] p"
-Append text from a buffer.
-.TP
-.B "[count] r <character>"
+If a
+.Ar count
+argument is given,
+the characters input are repeated
+.Ar count
+\- 1 more times.
+.Pp
+.It Xo
+.Op Ar buffer
+.Cm p
+.Xc
+Append text from
+.Ar buffer .
+Text is appended after the current column if
+.Ar buffer
+is character oriented, or after the current line otherwise.
+.Pp
+.It Xo
+.Op Ar count
+.Cm r
+.Aq Ar character
+.Xc
 Replace
-.I count
-characters.
-.TP
-.B "[buffer] [count] s"
+.Ar count
+characters with
+.Ar character .
+.Pp
+.It Xo
+.Op Ar buffer
+.Op Ar count
+.Cm s
+.Xc
 Substitute
-.I count
+.Ar count
 characters in the current line starting with the current character.
-.TP
-.B "[count] t <character>"
+If
+.Ar buffer
+is specified,
+.Dq yank
+the substituted text into
+.Ar buffer .
+.Pp
+.It Xo
+.Op Ar count
+.Cm t
+.Aq Ar character
+.Xc
 Search forward,
-.I count
-times, through the current line for the character immediately
-.I before
-.IR <character> .
-.TP
-.B "u"
+.Ar count
+times, through the current line for the character immediately before
+.Aq Ar character .
+.Pp
+.It Cm u
 Undo the last change made to the file.
-.TP
-.B "[count] w"
+If repeated, the
+.Cm u
+command alternates between these two states.
+The
+.Cm .\&
+command, when used immediately after
+.Cm u ,
+causes the change log to be rolled forward or backward, depending on the action
+of the
+.Cm u
+command.
+.Pp
+.It Xo
+.Op Ar count
+.Cm w
+.Xc
 Move forward
-.I count
+.Ar count
 words.
-.TP
-.B "[buffer] [count] x"
+.Pp
+.It Xo
+.Op Ar buffer
+.Op Ar count
+.Cm x
+.Xc
 Delete
-.I count
-characters.
-.TP
-.B "[buffer] [count] y motion"
-Copy (or ``yank'')
-a text region specified by the
-.I count
-and motion into a buffer.
-.TP
-.B "[count1] z [count2] -|.|+|^|<carriage-return>"
+.Ar count
+characters at the current cursor position, but no more than there are till the
+end of the line.
+.Pp
+.It Xo
+.Op Ar buffer
+.Op Ar count
+.Cm y
+.Ar motion
+.Xc
+Copy
+.Pq or Dq yank
+a text region specified by
+.Ar count
+and
+.Ar motion
+into a buffer.
+.Pp
+.It Xo
+.Op Ar count1
+.Cm z
+.Op Ar count2
+.Cm type
+.Xc
 Redraw, optionally repositioning and resizing the screen.
-.TP
-.B "[count] {"
+If
+.Ar count2
+is specified, limit the screen size to
+.Ar count2
+lines.
+The following
+.Cm type
+characters may be used:
+.Bl -tag -width Ds
+.It Cm +
+If
+.Ar count1
+is specified, place the line
+.Ar count1
+at the top of the screen.
+Otherwise, display the screen after the current screen.
+.It Aq Cm carriage-return
+Place the line
+.Ar count1
+at the top of the screen.
+.It Cm .\&
+Place the line
+.Ar count1
+in the center of the screen.
+.It Cm -
+Place the line
+.Ar count1
+at the bottom of the screen.
+.It Cm ^
+If
+.Ar count1
+is given,
+display the screen before the screen before
+.Ar count1
+.Pq i.e., 2 screens before .
+Otherwise, display the screen before the current screen.
+.El
+.Pp
+.It Xo
+.Op Ar count
+.Cm {\&
+.Xc
 Move backward
-.I count
+.Ar count
 paragraphs.
-.TP
-.B "[count] |"
+.Pp
+.It Xo
+.Op Ar column
+.Cm |\&
+.Xc
 Move to a specific
-.I column
+.Ar column
 position on the current line.
-.TP
-.B "[count] }"
+If
+.Ar column
+is omitted,
+move to the start of the current line.
+.Pp
+.It Xo
+.Op Ar count
+.Cm }\&
+.Xc
 Move forward
-.I count
+.Ar count
 paragraphs.
-.TP
-.B "[count] ~"
-Reverse the case of the next
-.I count
-character(s).
-.TP
-.B "[count] ~ motion"
-Reverse the case of the characters in a text region specified by the
-.I count
+.Pp
+.It Xo
+.Op Ar count
+.Cm ~
+.Ar motion
+.Xc
+If the
+.Cm tildeop
+option is not set, reverse the case of the next
+.Ar count
+character(s) and no
+.Ar motion
+can be specified.
+Otherwise
+.Ar motion
+is mandatory and
+.Cm ~
+reverses the case of the characters in a text region specified by the
+.Ar count
 and
-.IR motion .
-.TP
-.B "<interrupt>"
+.Ar motion .
+.Pp
+.It Aq Cm interrupt
 Interrupt the current operation.
-.SH VI TEXT INPUT COMMANDS
-The following section describes the commands available in the text
-input mode of the
-.I \&vi
+The
+.Aq interrupt
+character is usually
+.Aq control-C .
+.El
+.Sh VI TEXT INPUT COMMANDS
+The following section describes the commands available in the text input mode
+of the
+.Nm vi
 editor.
-.PP
-.TP
-.B "<nul>"
+.Pp
+.Bl -tag -width Ds -compact
+.It Aq Cm nul
 Replay the previous input.
-.TP
-.B "<control-D>"
+.Pp
+.It Aq Cm control-D
 Erase to the previous
-.B shiftwidth
+.Ar shiftwidth
 column boundary.
-.TP
-.B "^<control-D>"
+.Pp
+.It Cm ^ Ns Aq Cm control-D
 Erase all of the autoindent characters, and reset the autoindent level.
-.TP
-.B "0<control-D>"
+.Pp
+.It Cm 0 Ns Aq Cm control-D
 Erase all of the autoindent characters.
-.TP
-.B "<control-T>"
+.Pp
+.It Aq Cm control-T
 Insert sufficient
-.I <tab>
+.Aq tab
 and
-.I <space>
+.Aq space
 characters to move forward to the next
-.B shiftwidth
+.Ar shiftwidth
 column boundary.
-.TP
-.B "<erase>
-.TP
-.B "<control-H>"
+.Pp
+.It Aq Cm erase
+.It Aq Cm control-H
 Erase the last character.
-.TP
-.B "<literal next>"
-Quote the next character.
-.TP
-.B "<escape>
+.Pp
+.It Aq Cm literal next
+Escape the next character from any special meaning.
+The
+.Aq literal\ \&next
+character is usually
+.Aq control-V .
+.Pp
+.It Aq Cm escape
 Resolve all text input into the file, and return to command mode.
-.TP
-.B "<line erase>"
+.Pp
+.It Aq Cm line erase
 Erase the current line.
-.TP
-.B "<control-W>"
-.TP
-.B "<word erase>"
+.Pp
+.It Aq Cm control-W
+.It Aq Cm word erase
 Erase the last word.
 The definition of word is dependent on the
-.B altwerase
+.Cm altwerase
 and
-.B ttywerase
+.Cm ttywerase
 options.
-.TP
-.B "<control-X>[0-9A-Fa-f]+"
+.Pp
+.Sm off
+.It Xo
+.Aq Cm control-X
+.Bq Cm 0-9A-Fa-f
+.Cm +
+.Xc
+.Sm on
 Insert a character with the specified hexadecimal value into the text.
-.TP
-.B "<interrupt>"
+.Pp
+.It Aq Cm interrupt
 Interrupt text input mode, returning to command mode.
-.SH EX COMMANDS
+The
+.Aq interrupt
+character is usually
+.Aq control-C .
+.El
+.Sh EX COMMANDS
 The following section describes the commands available in the
-.I \&ex
+.Nm ex
 editor.
 In each entry below, the tag line is a usage synopsis for the command.
-.PP
-.TP
-.B "<end-of-file>"
+.Pp
+.Bl -tag -width Ds -compact
+.It Aq Cm end-of-file
 Scroll the screen.
-.TP
-.B "! argument(s)"
-.TP
-.B "[range]! argument(s)"
+.Pp
+.It Cm !\& Ar argument(s)
+.It Xo
+.Op Ar range
+.Cm !\&
+.Ar argument(s)
+.Xc
 Execute a shell command, or filter lines through a shell command.
-.TP
-.B \&"
+.Pp
+.It Cm \&"
 A comment.
-.TP
-.B "[range] nu[mber] [count] [flags]"
-.TP
-.B "[range] # [count] [flags]"
+.Pp
+.It Xo
+.Op Ar range
+.Cm nu Ns Op Cm mber
+.Op Ar count
+.Op Ar flags
+.Xc
+.It Xo
+.Op Ar range
+.Cm #
+.Op Ar count
+.Op Ar flags
+.Xc
 Display the selected lines, each preceded with its line number.
-.TP
-.B "@ buffer"
-.TP
-.B "* buffer"
+.Pp
+.It Cm @ Ar buffer
+.It Cm * Ar buffer
 Execute a buffer.
-.TP
-.B "[line] a[ppend][!]"
+.Pp
+.It Xo
+.Op Ar range
+.Cm < Ns Op Cm < ...
+.Op Ar count
+.Op Ar flags
+.Xc
+Shift lines left.
+.Pp
+.It Xo
+.Op Ar line
+.Cm =
+.Op Ar flags
+.Xc
+Display the line number of
+.Ar line .
+If
+.Ar line
+is not specified, display the line number of the last line in the file.
+.Pp
+.It Xo
+.Op Ar range
+.Cm > Ns Op Cm > ...
+.Op Ar count
+.Op Ar flags
+.Xc
+Shift lines right.
+.Pp
+.It Xo
+.Cm ab Ns Op Cm breviate
+.Ar lhs rhs
+.Xc
+.Nm vi
+only.
+Add
+.Ar lhs
+as an abbreviation for
+.Ar rhs
+to the abbreviation list.
+.Pp
+.It Xo
+.Op Ar line
+.Cm a Ns Op Cm ppend Ns
+.Op Cm !\&
+.Xc
 The input text is appended after the specified line.
-.TP
-.B "[range] c[hange][!] [count]"
+.Pp
+.It Cm ar Ns Op Cm gs
+Display the argument list.
+.Pp
+.It Cm bg
+.Nm vi
+only.
+Background the current screen.
+.Pp
+.It Xo
+.Op Ar range
+.Cm c Ns Op Cm hange Ns
+.Op Cm !\&
+.Op Ar count
+.Xc
 The input text replaces the specified range.
-.TP
-.B "cs[cope] add | find | help | kill | reset"
+.Pp
+.It Xo
+.Cm chd Ns Op Cm ir Ns
+.Op Cm !\&
+.Op Ar directory
+.Xc
+.It Xo
+.Cm cd Ns Op Cm !\&
+.Op Ar directory
+.Xc
+Change the current working directory.
+.Pp
+.It Xo
+.Op Ar range
+.Cm co Ns Op Cm py
+.Ar line
+.Op Ar flags
+.Xc
+.It Xo
+.Op Ar range
+.Cm t
+.Ar line
+.Op Ar flags
+.Xc
+Copy the specified lines after the destination
+.Ar line .
+.Pp
+.It Xo
+.Cm cs Ns Op Cm cope
+.Cm add | find | help | kill | reset
+.Xc
 Execute a Cscope command.
-.TP
-.B "[range] d[elete] [buffer] [count] [flags]"
+.Pp
+.It Xo
+.Op Ar range
+.Cm d Ns Op Cm elete
+.Op Ar buffer
+.Op Ar count
+.Op Ar flags
+.Xc
 Delete the lines from the file.
-.TP
-.B "di[splay] b[uffers] | c[onnections] | s[creens] | t[ags]"
+.Pp
+.It Xo
+.Cm di Ns Op Cm splay
+.Cm b Ns Oo Cm uffers Oc |
+.Cm c Ns Oo Cm onnections Oc |
+.Cm s Ns Oo Cm creens Oc |
+.Cm t Ns Op Cm ags
+.Xc
 Display buffers, Cscope connections, screens or tags.
-.TP
-.B "[Ee][dit][!] [+cmd] [file]"
-.TP
-.B "[Ee]x[!] [+cmd] [file]"
+.Pp
+.It Xo
+.Op Cm Ee Ns
+.Op Cm dit Ns
+.Op Cm !\&
+.Op Ar +cmd
+.Op Ar file
+.Xc
+.It Xo
+.Op Cm Ee Ns
+.Cm x Ns Op Cm !\&
+.Op Ar +cmd
+.Op Ar file
+.Xc
 Edit a different file.
-.TP
-.B "exu[sage] [command]"
+.Pp
+.It Xo
+.Cm exu Ns Op Cm sage
+.Op Ar command
+.Xc
 Display usage for an
-.I \&ex
+.Nm ex
 command.
-.TP
-.B "f[ile] [file]"
+.Pp
+.It Xo
+.Cm f Ns Op Cm ile
+.Op Ar file
+.Xc
 Display and optionally change the file name.
-.TP
-.B "[Ff]g [name]"
-.I \&Vi
+.Pp
+.It Xo
+.Op Cm Ff Ns
+.Cm g
+.Op Ar name
+.Xc
+.Nm vi
 mode only.
 Foreground the specified screen.
-.TP
-.B "[range] g[lobal] /pattern/ [commands]"
-.TP
-.B "[range] v /pattern/ [commands]"
-Apply commands to lines matching (or not matching) a pattern.
-.TP
-.B "he[lp]"
+.Pp
+.It Xo
+.Op Ar range
+.Cm g Ns Op Cm lobal
+.No / Ns Ar pattern Ns /
+.Op Ar commands
+.Xc
+.It Xo
+.Op Ar range
+.Cm v
+.No / Ns Ar pattern Ns /
+.Op Ar commands
+.Xc
+Apply commands to lines matching
+.Pq Sq global
+or not matching
+.Pq Sq v
+a pattern.
+.Pp
+.It Cm he Ns Op Cm lp
 Display a help message.
-.TP
-.B "[line] i[nsert][!]"
+.Pp
+.It Xo
+.Op Ar line
+.Cm i Ns Op Cm nsert Ns
+.Op Cm !\&
+.Xc
 The input text is inserted before the specified line.
-.TP
-.B "[range] j[oin][!] [count] [flags]"
+.Pp
+.It Xo
+.Op Ar range
+.Cm j Ns Op Cm oin Ns
+.Op Cm !\&
+.Op Ar count
+.Op Ar flags
+.Xc
 Join lines of text together.
-.TP
-.B "[range] l[ist] [count] [flags]"
+.Pp
+.It Xo
+.Op Ar range
+.Cm l Ns Op Cm ist
+.Op Ar count
+.Op Ar flags
+.Xc
 Display the lines unambiguously.
-.TP
-.B "map[!] [lhs rhs]"
-Define or display maps (for
-.I \&vi
-only).
-.TP
-.B "[line] ma[rk] <character>"
-.TP
-.B "[line] k <character>"
+.Pp
+.It Xo
+.Cm map Ns Op Cm !\&
+.Op Ar lhs rhs
+.Xc
+Define or display maps
+.Pq for Nm vi No only .
+.Pp
+.It Xo
+.Op Ar line
+.Cm ma Ns Op Cm rk
+.Aq Ar character
+.Xc
+.It Xo
+.Op Ar line
+.Cm k Aq Ar character
+.Xc
 Mark the line with the mark
-.IR <character> .
-.TP
-.B "[range] m[ove] line"
+.Aq Ar character .
+.Pp
+.It Xo
+.Op Ar range
+.Cm m Ns Op Cm ove
+.Ar line
+.Xc
 Move the specified lines after the target line.
-.TP
-.B "mk[exrc][!] file"
+.Pp
+.It Xo
+.Cm mk Ns Op Cm exrc Ns
+.Op Cm !\&
+.Ar file
+.Xc
 Write the abbreviations, editor options and maps to the specified
-file.
-.TP
-.B "[Nn][ext][!] [file ...]"
+.Ar file .
+.Pp
+.It Xo
+.Op Cm Nn Ns
+.Op Cm ext Ns
+.Op Cm !\&
+.Op Ar
+.Xc
 Edit the next file from the argument list.
-.TP
-.B "[line] o[pen] /pattern/ [flags]"
-Enter open mode.
-.TP
-.B "pre[serve]"
+.\" .Pp
+.\" .It Xo
+.\" .Op Ar line
+.\" .Cm o Ns Op Cm pen
+.\" .No / Ns Ar pattern Ns /
+.\" .Op Ar flags
+.\" .Xc
+.\" Enter open mode.
+.Pp
+.It Cm pre Ns Op Cm serve
 Save the file in a form that can later be recovered using the
-.I \&ex
-.B \-r
+.Nm ex
+.Fl r
 option.
-.TP
-.B "[Pp]rev[ious][!]"
+.Pp
+.It Xo
+.Op Cm \&Pp Ns
+.Cm rev Ns Op Cm ious Ns
+.Op Cm !\&
+.Xc
 Edit the previous file from the argument list.
-.TP
-.B "[range] p[rint] [count] [flags]"
+.Pp
+.It Xo
+.Op Ar range
+.Cm p Ns Op Cm rint
+.Op Ar count
+.Op Ar flags
+.Xc
 Display the specified lines.
-.TP
-.B "[line] pu[t] [buffer]"
+.Pp
+.It Xo
+.Op Ar line
+.Cm pu Ns Op Cm t
+.Op Ar buffer
+.Xc
 Append buffer contents to the current line.
-.TP
-.B "q[uit][!]"
+.Pp
+.It Xo
+.Cm q Ns Op Cm uit Ns
+.Op Cm !\&
+.Xc
 End the editing session.
-.TP
-.B "[line] r[ead][!] [file]"
+.Pp
+.It Xo
+.Op Ar line
+.Cm r Ns Op Cm ead Ns
+.Op Cm !\&
+.Op Ar file
+.Xc
 Read a file.
-.TP
-.B "rec[over] file"
+.Pp
+.It Xo
+.Cm rec Ns Op Cm over
+.Ar file
+.Xc
 Recover
-.I file
+.Ar file
 if it was previously saved.
-.TP
-.B "res[ize] [+|-]size"
-.I \&Vi
+.Pp
+.It Xo
+.Cm res Ns Op Cm ize
+.Op Cm + Ns | Ns Cm - Ns
+.Ar size
+.Xc
+.Nm vi
 mode only.
 Grow or shrink the current screen.
-.TP
-.B "rew[ind][!]"
+.Pp
+.It Xo
+.Cm rew Ns Op Cm ind Ns
+.Op Cm !\&
+.Xc
 Rewind the argument list.
-.TP
-.B "rta[g][!] tagstring"
-Edit the file referring the specified tag. (Only in gtagsmode)
-.TP
-.B "se[t] [option[=[value]] ...] [nooption ...] [option? ...] [all]"
+.Pp
+.It Xo
+.Cm se Ns Op Cm t
+.Sm off
+.Op option Oo = Oo value Oc Oc \ \&...
+.Sm on
+.Pf \ \& Op nooption ...
+.Op option? ...
+.Op Ar all
+.Xc
 Display or set editor options.
-.TP
-.B "sh[ell]"
+.Pp
+.It Cm sh Ns Op Cm ell
 Run a shell program.
-.TP
-.B "so[urce] file"
+.Pp
+.It Xo
+.Cm so Ns Op Cm urce
+.Ar file
+.Xc
 Read and execute
-.I \&ex
+.Nm ex
 commands from a file.
-.TP
-.B "[range] s[ubstitute] [/pattern/replace/] [options] [count] [flags]"
-.TP
-.B "[range] & [options] [count] [flags]"
-.TP
-.B "[range] ~ [options] [count] [flags]"
+.Pp
+.It Xo
+.Op Ar range
+.Cm s Ns Op Cm ubstitute
+.Sm off
+.Op / Ar pattern No / Ar replace No /
+.Sm on
+.Pf \ \& Op Ar options
+.Op Ar count
+.Op Ar flags
+.Xc
+.It Xo
+.Op Ar range
+.Cm &
+.Op Ar options
+.Op Ar count
+.Op Ar flags
+.Xc
+.It Xo
+.Op Ar range
+.Cm ~
+.Op Ar options
+.Op Ar count
+.Op Ar flags
+.Xc
 Make substitutions.
-.TP
-.B "su[spend][!]"
-.TP
-.B "st[op][!]"
-.TP
-.B <suspend>
+The
+.Ar replace
+field may contain any of the following sequences:
+.Bl -tag -width Ds
+.It Sq \*(Am
+The text matched by
+.Ar pattern .
+.It Sq \(a~
+The replacement part of the previous
+.Cm substitute
+command.
+.It Sq %
+If this is the entire
+.Ar replace
+pattern, the replacement part of the previous
+.Cm substitute
+command.
+.It Sq \e\(sh
+Where
+.Sq \(sh
+is an integer from 1 to 9, the text matched by the #'th subexpression in
+.Ar pattern .
+.It Sq \eL
+Causes the characters up to the end of the line of the next occurrence of
+.Sq \eE
+or
+.Sq \ee
+to be converted to lowercase.
+.It Sq \el
+Causes the next character to be converted to lowercase.
+.It Sq \eU
+Causes the characters up to the end of the line of the next occurrence of
+.Sq \eE
+or
+.Sq \ee
+to be converted to uppercase.
+.It Sq \eu
+Causes the next character to be converted to uppercase.
+.El
+.Pp
+.It Xo
+.Cm su Ns Op Cm spend Ns
+.Op Cm !\&
+.Xc
+.It Xo
+.Cm st Ns Op Cm op Ns
+.Op Cm !\&
+.Xc
+.It Aq Cm suspend
 Suspend the edit session.
-.TP
-.B "[Tt]a[g][!] tagstring"
+The
+.Aq suspend
+character is usually
+.Aq control-Z .
+.Pp
+.It Xo
+.Op Cm Tt Ns
+.Cm a Ns Op Cm g Ns
+.Op Cm !\&
+.Ar tagstring
+.Xc
 Edit the file containing the specified tag.
-.TP
-.B "tagn[ext][!]"
+.Pp
+.It Xo
+.Cm tagn Ns Op Cm ext Ns
+.Op Cm !\&
+.Xc
 Edit the file containing the next context for the current tag.
-.TP
-.B "tagp[op][!] [file | number]"
+.Pp
+.It Xo
+.Cm tagp Ns Op Cm op Ns
+.Op Cm !\&
+.Op Ar file | number
+.Xc
 Pop to the specified tag in the tags stack.
-.TP
-.B "tagp[rev][!]"
+.Pp
+.It Xo
+.Cm tagpr Ns Op Cm ev Ns
+.Op Cm !\&
+.Xc
 Edit the file containing the previous context for the current tag.
-.TP
-.B "unm[ap][!] lhs"
+.Pp
+.It Xo
+.Cm tagt Ns Op Cm op Ns
+.Op Cm !\&
+.Xc
+Pop to the least recent tag on the tags stack, clearing the stack.
+.Pp
+.It Xo
+.Cm una Ns Op Cm bbreviate
+.Ar lhs
+.Xc
+.Nm vi
+only.
+Delete an abbreviation.
+.Pp
+.It Cm u Ns Op Cm ndo
+Undo the last change made to the file.
+.Pp
+.It Xo
+.Cm unm Ns Op Cm ap Ns
+.Op Cm !\&
+.Ar lhs
+.Xc
 Unmap a mapped string.
-.TP
-.B "ve[rsion]"
+.Pp
+.It Cm ve Ns Op Cm rsion
 Display the version of the
-.I \&ex/vi
+.Nm ex Ns / Ns Nm vi
 editor.
-.TP
-.B "[line] vi[sual] [type] [count] [flags]"
-.I \&Ex
+.Pp
+.It Xo
+.Op Ar line
+.Cm vi Ns Op Cm sual
+.Op Ar type
+.Op Ar count
+.Op Ar flags
+.Xc
+.Nm ex
 mode only.
 Enter
-.IR \&vi .
-.TP
-.B "[Vi]i[sual][!] [+cmd] [file]"
-.I \&Vi
+.Nm vi .
+.Pp
+.It Xo
+.Op Cm Vi Ns
+.Cm i Ns Op Cm sual Ns
+.Op Cm !\&
+.Op Ar +cmd
+.Op Ar file
+.Xc
+.Nm vi
 mode only.
 Edit a new file.
-.TP
-.B "viu[sage] [command]"
+.Pp
+.It Xo
+.Cm viu Ns Op Cm sage
+.Op Ar command
+.Xc
 Display usage for a
-.I \&vi
+.Nm vi
 command.
-.TP
-.B "[range] w[rite][!] [>>] [file]"
-.TP
-.B "[range] w[rite] [!] [file]"
-.TP
-.B "[range] wn[!] [>>] [file]"
-.TP
-.B "[range] wq[!] [>>] [file]"
+.Pp
+.It Xo
+.Op Ar range
+.Cm w Ns Op Cm rite Ns
+.Op Cm !\&
+.Op >>
+.Op Ar file
+.Xc
+.It Xo
+.Op Ar range
+.Cm w Ns Op Cm rite
+.Op Cm !\&
+.Op Ar file
+.Xc
+.It Xo
+.Op Ar range
+.Cm wn Ns Op Cm !\&
+.Op >>
+.Op Ar file
+.Xc
+.It Xo
+.Op Ar range
+.Cm wq Ns Op Cm !\&
+.Op >>
+.Op Ar file
+.Xc
 Write the file.
-.TP
-.B "[range] x[it][!] [file]"
-Write the file if it has been modified.
-.TP
-.B "[range] ya[nk] [buffer] [count]"
+.Pp
+.It Xo
+.Op Ar range
+.Cm x Ns Op Cm it Ns
+.Op Cm !\&
+.Op Ar file
+.Xc
+Exit the editor,
+writing the file if it has been modified.
+.Pp
+.It Xo
+.Op Ar range
+.Cm ya Ns Op Cm nk
+.Op Ar buffer
+.Op Ar count
+.Xc
 Copy the specified lines to a buffer.
-.TP
-.B "[line] z [type] [count] [flags]"
+.Pp
+.It Xo
+.Op Ar line
+.Cm z
+.Op Ar type
+.Op Ar count
+.Op Ar flags
+.Xc
 Adjust the window.
-.SH SET OPTIONS
-There are a large number of options that may be set (or unset) to
-change the editor's behavior.
+.El
+.Sh SET OPTIONS
+There are a large number of options that may be set
+.Pq or unset
+to change the editor's behavior.
 This section describes the options, their abbreviations and their
 default values.
-.PP
+.Pp
 In each entry below, the first part of the tag line is the full name
 of the option, followed by any equivalent abbreviations.
 The part in square brackets is the default value of the option.
-Most of the options are boolean, i.e. they are either on or off,
+Most of the options are boolean, i.e., they are either on or off,
 and do not have an associated value.
-.PP
+.Pp
 Options apply to both
-.I \&ex
+.Nm ex
 and
-.I \&vi
+.Nm vi
 modes, unless otherwise specified.
-.PP
-.TP
-.B "altwerase [off]"
-.I \&Vi
+.Bl -tag -width Ds
+.It Cm altwerase Bq off
+.Nm vi
 only.
 Select an alternate word erase algorithm.
-.TP
-.B "autoindent, ai [off]"
+.It Cm autoindent , ai Bq off
 Automatically indent new lines.
-.TP
-.B "autoprint, ap [off]"
-.I \&Ex
+.It Cm autoprint , ap Bq on
+.Nm ex
 only.
 Display the current line automatically.
-.TP
-.B "autowrite, aw [off]"
-Write modified files automatically when changing files.
-.\" I cannot get a double quote to print between the square brackets
-.\" to save my life.  The ONLY way I've been able to get this to work
-.\" is with the .tr command.
-.tr Q"
-.ds ms backup [QQ]
-.TP
-.B "\*(ms"
-.tr QQ
-Backup files before they are overwritten.
-.TP
-.B "beautify, bf [off]"
+.It Cm autowrite , aw Bq off
+Write modified files automatically when changing files or suspending the editor
+session.
+.It Cm backup Bq \&"\&"
+Back up files before they are overwritten.
+.It Cm beautify , bf Bq off
 Discard control characters.
-.TP
-.B "cdpath [environment variable CDPATH, or current directory]"
+.It Cm cdpath Bq "environment variable CDPATH, or current directory"
 The directory paths used as path prefixes for the
-.B cd
+.Cm cd
 command.
-.TP
-.B "cedit [no default]"
+.It Cm cedit Bq no default
 Set the character to edit the colon command-line history.
-.TP
-.B "columns, co [80]"
+.It Cm columns , co Bq 80
 Set the number of columns in the screen.
-.TP
-.B "comment [off]"
-.I \&Vi
+.It Cm comment Bq off
+.Nm vi
 only.
 Skip leading comments in shell, C and C++ language files.
-.TP
-.B "directory, dir [environment variable TMPDIR, or /tmp]"
+.It Cm directory , dir Bq "environment variable TMPDIR, or /tmp"
 The directory where temporary files are created.
-.TP
-.B "edcompatible, ed [off]"
-Remember the values of the ``c'' and ``g'' suffices to the
-.B substitute
-commands, instead of initializing them as unset for each new
-command.
-.TP
-.B "errorbells, eb [off]"
-.I \&Ex
+.It Cm edcompatible , ed Bq off
+Remember the values of the
+.Sq c
+and
+.Sq g
+suffixes to the
+.Cm substitute
+commands, instead of initializing them as unset for each new command.
+.It Cm errorbells , eb Bq off
+.Nm ex
 only.
 Announce error messages with a bell.
-.TP
-.B "exrc, ex [off]"
+.It Cm escapetime Bq 1
+The tenths of a second
+.Nm ex Ns / Ns Nm vi
+waits for a subsequent key to complete an
+.Aq escape
+key mapping.
+.It Cm exrc , ex Bq off
 Read the startup files in the local directory.
-.TP
-.B "extended [off]"
-Regular expressions are extended (i.e.
-.IR egrep (1)\-\c
-style) expressions.
-.TP
-.B "filec [no default]"
-Set the character to perform file path completion on the colon
-command line.
-.TP
-.B "flash [on]"
+.It Cm extended Bq off
+Use extended regular expressions
+.Pq EREs
+rather than basic regular expressions
+.Pq BREs .
+See
+.Xr re_format 7
+for more information on regular expressions.
+.It Cm filec Bq Aq tab
+Set the character to perform file path completion on the colon command line.
+.It Cm fileencoding , fe Bq auto detect
+Set the encoding of the current file.
+.It Cm flash Bq on
 Flash the screen instead of beeping the keyboard on error.
-.TP
-.B "gtagsmode, gt [off]"
-Use GTAGS and GRTAGS instead of tags.
-.TP
-.B "hardtabs, ht [8]"
+.It Cm hardtabs, ht Bq 0
 Set the spacing between hardware tab settings.
-.TP
-.B "iclower [off]"
-Makes all Regular Expressions case-insensitive,
+This option currently has no effect.
+.It Cm iclower Bq off
+Makes all regular expressions case-insensitive,
 as long as an upper-case letter does not appear in the search string.
-.TP
-.B "ignorecase, ic [off]"
+.It Cm ignorecase , ic Bq off
 Ignore case differences in regular expressions.
-.TP
-.B "keytime [6]"
-The 10th's of a second
-.I ex/vi
+.It Cm inputencoding , ie Bq locale
+Set the encoding of your input characters.
+.It Cm keytime Bq 6
+The tenths of a second
+.Nm ex Ns / Ns Nm vi
 waits for a subsequent key to complete a key mapping.
-.TP
-.B "leftright [off]"
-.I \&Vi
+.It Cm leftright Bq off
+.Nm vi
 only.
 Do left-right scrolling.
-.TP
-.B "lines, li [24]"
-.I \&Vi
+.It Cm lines , li Bq 24
+.Nm vi
 only.
 Set the number of lines in the screen.
-.TP
-.B "lisp [off]"
-.I \&Vi
+.It Cm lisp Bq off
+.Nm vi
 only.
 Modify various search commands and options to work with Lisp.
-.I "This option is not yet implemented."
-.TP
-.B "list [off]"
+This option is not yet implemented.
+.It Cm list Bq off
 Display lines in an unambiguous fashion.
-.TP
-.B "lock [on]"
-Attempt to get an exclusive lock on any file being edited,
-read or written.
-.TP
-.B "magic [on]"
-Treat certain characters specially in regular expressions.
-.TP
-.B "matchtime [7]"
-.I \&Vi
+.It Cm lock Bq on
+Attempt to get an exclusive lock on any file being edited, read or written.
+.It Cm magic Bq on
+When turned off, all regular expression characters except for
+.Sq \(ha
+and
+.Sq \(Do
+are treated as ordinary characters.
+Preceding individual characters by
+.Sq \e
+re-enables them.
+.It Cm matchchars Bq []{}()
+Character pairs looked for by the
+.Cm %
+command.
+.It Cm matchtime Bq 7
+.Nm vi
 only.
-The 10th's of a second
-.I ex/vi
+The tenths of a second
+.Nm ex Ns / Ns Nm vi
 pauses on the matching character when the
-.B showmatch
+.Cm showmatch
 option is set.
-.TP
-.B "mesg [on]"
+.It Cm mesg Bq on
 Permit messages from other users.
-.TP
-.B "modelines, modeline [off]"
+.It Cm msgcat Bq /usr/share/vi/catalog/
+Selects a message catalog to be used to display error and informational
+messages in a specified language.
+.It Cm modelines , modeline Bq off
 Read the first and last few lines of each file for
-.I ex
+.Nm ex
 commands.
-.I "This option will never be implemented."
-.\" I cannot get a double quote to print between the square brackets
-.\" to save my life.  The ONLY way I've been able to get this to work
-.\" is with the .tr command.
-.tr Q"
-.ds ms noprint [QQ]
-.TP
-.B "\*(ms"
-.tr QQ
+This option will never be implemented.
+.It Cm noprint Bq \&"\&"
 Characters that are never handled as printable characters.
-.TP
-.B "number, nu [off]"
+.It Cm number , nu Bq off
 Precede each line displayed with its current line number.
-.TP
-.B "octal [off]"
+.It Cm octal Bq off
 Display unknown characters as octal numbers, instead of the default
 hexadecimal.
-.TP
-.B "open [on]"
-.I \&Ex
+.It Cm open Bq on
+.Nm ex
 only.
 If this option is not set, the
-.B open
+.Cm open
 and
-.B visual
+.Cm visual
 commands are disallowed.
-.TP
-.B "optimize, opt [on]"
-.I \&Vi
+.It Cm optimize , opt Bq on
+.Nm vi
 only.
 Optimize text throughput to dumb terminals.
-.I "This option is not yet implemented."
-.TP
-.B "paragraphs, para [IPLPPPQPP LIpplpipbp]"
-.I \&Vi
+This option is not yet implemented.
+.It Cm paragraphs , para Bq "IPLPPPQPP LIpplpipbp"
+.Nm vi
 only.
 Define additional paragraph boundaries for the
-.B \&{
+.Cm {\&
 and
-.B \&}
+.Cm }\&
 commands.
-.TP
-.B "path []"
+.It Cm path Bq \&"\&"
 Define additional directories to search for files being edited.
-.\" I cannot get a double quote to print between the square brackets
-.\" to save my life.  The ONLY way I've been able to get this to work
-.\" is with the .tr command.
-.tr Q"
-.ds ms print [QQ]
-.TP
-.B "\*(ms"
-.tr QQ
+.It Cm print Bq \&"\&"
 Characters that are always handled as printable characters.
-.TP
-.B "prompt [on]"
-.I \&Ex
+.It Cm prompt Bq on
+.Nm ex
 only.
 Display a command prompt.
-.TP
-.B "readonly, ro [off]"
+.It Cm readonly , ro Bq off
 Mark the file and session as read-only.
-.TP
-.B "recdir [/var/tmp/vi.recover]"
+.It Cm recdir Bq /var/tmp/vi.recover
 The directory where recovery files are stored.
-.TP
-.B "redraw, re [off]"
-.I \&Vi
+.It Cm redraw , re Bq off
+.Nm vi
 only.
 Simulate an intelligent terminal on a dumb one.
-.I "This option is not yet implemented."
-.TP
-.B "remap [on]"
+This option is not yet implemented.
+.It Cm remap Bq on
 Remap keys until resolved.
-.TP
-.B "report [5]"
-Set the number of lines about which the editor reports changes
-or yanks.
-.TP
-.B "ruler [off]"
-.I \&Vi
+.It Cm report Bq 5
+Set the number of lines about which the editor reports changes or yanks.
+.It Cm ruler Bq off
+.Nm vi
 only.
 Display a row/column ruler on the colon command line.
-.TP
-.B "scroll, scr [window / 2]"
+.It Cm scroll , scr Bq "window size / 2"
 Set the number of lines scrolled.
-.TP
-.B "searchincr [off]"
+.It Cm searchincr Bq off
 Makes the
-.B \&/
+.Cm /
 and
-.B \&?
+.Cm ?\&
 commands incremental.
-.TP
-.B "sections, sect [NHSHH HUnhsh]"
-.I \&Vi
+.It Cm sections , sect Bq "NHSHH HUnhsh"
+.Nm vi
 only.
 Define additional section boundaries for the
-.B \&[[
+.Cm [[
 and
-.B \&]]
+.Cm ]]
 commands.
-.TP
-.B "secure [off]"
+.It Cm secure Bq off
 Turns off all access to external programs.
-.TP
-.B "shell, sh [environment variable SHELL, or /bin/sh]"
+.It Cm shell , sh Bq "environment variable SHELL, or /bin/sh"
 Select the shell used by the editor.
-.\" I cannot get a double quote to print between the square brackets
-.\" to save my life.  The ONLY way I've been able to get this to work
-.\" is with the .tr command.
-.tr Q"
-.ds ms shellmeta [~{[*?$`'Q\e]
-.TP
-.B "\*(ms"
-.tr QQ
+.It Cm shellmeta Bq ~{[*?$`'\&"\e
 Set the meta characters checked to determine if file name expansion
 is necessary.
-.TP
-.B "shiftwidth, sw [8]"
+.It Cm shiftwidth , sw Bq 8
 Set the autoindent and shift command indentation width.
-.TP
-.B "showmatch, sm [off]"
-.I \&Vi
+.It Cm showmatch , sm Bq off
+.Nm vi
 only.
-Note matching ``{'' and ``('' for ``}'' and ``)'' characters.
-.TP
-.B "showmode, smd [off]"
-.I \&Vi
+Note the left matching characters when the right ones are inserted.
+.It Cm showmode , smd Bq off
+.Nm vi
 only.
-Display the current editor mode and a ``modified'' flag.
-.TP
-.B "sidescroll [16]"
-.I \&Vi
+Display the current editor mode and a
+.Dq modified
+flag.
+.It Cm sidescroll Bq 16
+.Nm vi
 only.
 Set the amount a left-right scroll will shift.
-.TP
-.B "slowopen, slow [off]"
+.It Cm slowopen , slow Bq off
 Delay display updating during text input.
-.I "This option is not yet implemented."
-.TP
-.B "sourceany [off]"
+This option is not yet implemented.
+.It Cm sourceany Bq off
 Read startup files not owned by the current user.
-.I "This option will never be implemented."
-.TP
-.B "tabstop, ts [8]"
+This option will never be implemented.
+.It Cm tabstop , ts Bq 8
 This option sets tab widths for the editor display.
-.TP
-.B "taglength, tl [0]"
+.It Cm taglength , tl Bq 0
 Set the number of significant characters in tag names.
-.TP
-.B "tags, tag [tags /var/db/libc.tags /sys/kern/tags]"
+.It Cm tags , tag Bq tags
 Set the list of tags files.
-.TP
-.B "term, ttytype, tty [environment variable TERM]"
+.It Xo
+.Cm term , ttytype , tty
+.Bq "environment variable TERM"
+.Xc
 Set the terminal type.
-.TP
-.B "terse [off]"
+.It Cm terse Bq off
 This option has historically made editor messages less verbose.
 It has no effect in this implementation.
-.TP
-.B "tildeop [off]"
+.It Cm tildeop Bq off
 Modify the
-.B \&~
+.Cm ~
 command to take an associated motion.
-.TP
-.B "timeout, to [on]"
+.It Cm timeout , to Bq on
 Time out on keys which may be mapped.
-.TP
-.B "ttywerase [off]"
-.I \&Vi
+.It Cm ttywerase Bq off
+.Nm vi
 only.
 Select an alternate erase algorithm.
-.TP
-.B "verbose [off]"
-.I \&Vi
+.It Cm verbose Bq off
+.Nm vi
 only.
 Display an error message for every error.
-.TP
-.B "w300 [no default]"
-.I \&Vi
+.It Cm w300 Bq no default
+.Nm vi
 only.
 Set the window size if the baud rate is less than 1200 baud.
-.TP
-.B "w1200 [no default]"
-.I \&Vi
+.It Cm w1200 Bq no default
+.Nm vi
 only.
 Set the window size if the baud rate is equal to 1200 baud.
-.TP
-.B "w9600 [no default]"
-.I \&Vi
+.It Cm w9600 Bq no default
+.Nm vi
 only.
 Set the window size if the baud rate is greater than 1200 baud.
-.TP
-.B "warn [on]"
-.I \&Ex
+.It Cm warn Bq on
+.Nm ex
 only.
-This option causes a warning message to the terminal if the file has
-been modified, since it was last written, before a
-.B \&!
+This option causes a warning message to be printed on the terminal
+if the file has been modified since it was last written, before a
+.Cm !\&
 command.
-.TP
-.B "window, w, wi [environment variable LINES]"
+.It Xo
+.Cm window , w , wi
+.Bq "environment variable LINES \- 1"
+.Xc
 Set the window size for the screen.
-.TP
-.B "windowname [off]"
-Change the icon/window name to the current file name even if it can't
-be restored on editor exit.
-.TP
-.B "wraplen, wl [0]"
-.I \&Vi
+.It Cm windowname Bq off
+Change the icon/window name to the current file name.
+.It Cm wraplen , wl Bq 0
+.Nm vi
 only.
-Break lines automatically, the specified number of columns from the
-left-hand margin.
+Break lines automatically,
+the specified number of columns from the left-hand margin.
 If both the
-.B wraplen
+.Cm wraplen
 and
-.B wrapmargin
+.Cm wrapmargin
 edit options are set, the
-.B wrapmargin
+.Cm wrapmargin
 value is used.
-.TP
-.B "wrapmargin, wm [0]"
-.I \&Vi
+.It Cm wrapmargin , wm Bq 0
+.Nm vi
 only.
-Break lines automatically, the specified number of columns from the
-right-hand margin.
+Break lines automatically,
+the specified number of columns from the right-hand margin.
 If both the
-.B wraplen
+.Cm wraplen
 and
-.B wrapmargin
+.Cm wrapmargin
 edit options are set, the
-.B wrapmargin
+.Cm wrapmargin
 value is used.
-.TP
-.B "wrapscan, ws [on]"
+.It Cm wrapscan , ws Bq on
 Set searches to wrap around the end or beginning of the file.
-.TP
-.B "writeany, wa [off]"
+.It Cm writeany , wa Bq off
 Turn off file-overwriting checks.
-.SH ENVIRONMENT VARIABLES
-.TP
-.I COLUMNS
+.El
+.Sh ENVIRONMENT
+.Bl -tag -width "COLUMNS"
+.It Ev COLUMNS
 The number of columns on the screen.
 This value overrides any system or terminal specific values.
 If the
-.I COLUMNS
+.Ev COLUMNS
 environment variable is not set when
-.I ex/vi
+.Nm ex Ns / Ns Nm vi
 runs, or the
-.B columns
+.Cm columns
 option is explicitly reset by the user,
-.I ex/vi
+.Nm ex Ns / Ns Nm vi
 enters the value into the environment.
-.TP
-.I EXINIT
+.It Ev EXINIT
 A list of
-.I \&ex
-startup commands, read if the variable
-.I NEXINIT
-is not set.
-.TP
-.I HOME
-The user's home directory, used as the initial directory path
-for the startup ``$\fIHOME\fP/.nexrc'' and ``$\fIHOME\fP/.exrc''
+.Nm ex
+startup commands, read after
+.Pa /etc/vi.exrc
+unless the variable
+.Ev NEXINIT
+is also set.
+.It Ev HOME
+The user's home directory, used as the initial directory path for the startup
+.Pa $HOME/.nexrc
+and
+.Pa $HOME/.exrc
 files.
 This value is also used as the default directory for the
-.I \&vi
-.B \&cd
+.Cm cd
 command.
-.TP
-.I LINES
+.It Ev LINES
 The number of rows on the screen.
 This value overrides any system or terminal specific values.
 If the
-.I LINES
+.Ev LINES
 environment variable is not set when
-.I ex/vi
+.Nm ex Ns / Ns Nm vi
 runs, or the
-.B lines
+.Cm lines
 option is explicitly reset by the user,
-.I ex/vi
+.Nm ex Ns / Ns Nm vi
 enters the value into the environment.
-.TP
-.I NEXINIT
+.It Ev NEXINIT
 A list of
-.I \&ex
-startup commands.
-.TP
-.I SHELL
-The user's shell of choice (see also the
-.B shell
-option).
-.TP
-.I TERM
+.Nm ex
+startup commands, read after
+.Pa /etc/vi.exrc .
+.It Ev SHELL
+The user's shell of choice
+.Pq see also the Cm shell No option .
+.It Ev TERM
 The user's terminal type.
-The default is the type ``unknown''.
+The default is the type
+.Dq unknown .
 If the
-.I TERM
+.Ev TERM
 environment variable is not set when
-.I ex/vi
+.Nm ex Ns / Ns Nm vi
 runs, or the
-.B term
+.Cm term
 option is explicitly reset by the user,
-.I ex/vi
+.Nm ex Ns / Ns Nm vi
 enters the value into the environment.
-.TP
-.I TMPDIR
-The location used to stored temporary files (see also the
-.B directory
-edit option).
-.SH ASYNCHRONOUS EVENTS
-.TP
-SIGALRM
-.I \&Vi/ex
-uses this signal for periodic backups of file modifications and to
-display ``busy'' messages when operations are likely to take a long time.
-.TP
-SIGHUP
-.TP
-SIGTERM
-If the current buffer has changed since it was last written in its
-entirety, the editor attempts to save the modified file so it can
-be later recovered.
+.It Ev TMPDIR
+The location used to store temporary files
+.Pq see also the Cm directory No edit option .
+.El
+.Sh ASYNCHRONOUS EVENTS
+.Bl -tag -width "SIGWINCH" -compact
+.It Dv SIGALRM
+.Nm vi Ns / Ns Nm ex
+uses this signal for periodic backups of file modifications and to display
+.Dq busy
+messages when operations are likely to take a long time.
+.Pp
+.It Dv SIGHUP
+.It Dv SIGTERM
+If the current buffer has changed since it was last written in its entirety,
+the editor attempts to save the modified file so it can be later recovered.
 See the
-.I \&vi/ex
-Reference manual section entitled ``Recovery'' for more information.
-.TP
-SIGINT
-When an interrupt occurs,
-the current operation is halted,
+.Nm vi Ns / Ns Nm ex
+reference manual section
+.Sx Recovery
+for more information.
+.Pp
+.It Dv SIGINT
+When an interrupt occurs, the current operation is halted
 and the editor returns to the command level.
 If interrupted during text input,
 the text already input is resolved into the file as if the text
 input had been normally terminated.
-.TP
-SIGWINCH
+.Pp
+.It Dv SIGWINCH
 The screen is resized.
 See the
-.I \&vi/ex
-Reference manual section entitled ``Sizing the Screen'' for more information.
-.TP
-SIGCONT
-.TP
-SIGQUIT
-.TP
-SIGTSTP
-.I \&Vi/ex
-ignores these signals.
-.SH FILES
-.TP
-/bin/sh
+.Nm vi Ns / Ns Nm ex
+reference manual section
+.Sx Sizing the Screen
+for more information.
+.\" .Pp
+.\" .It Dv SIGCONT
+.\" .It Dv SIGTSTP
+.\" .Nm vi Ns / Ns Nm ex
+.\" ignores these signals.
+.El
+.Sh FILES
+.Bl -tag -width "/var/tmp/vi.recover"
+.It Pa /bin/sh
 The default user shell.
-.TP
-/etc/vi.exrc
-System-wide vi startup file.
-.TP
-/tmp
+.It Pa /etc/vi.exrc
+System-wide
+.Nm vi
+startup file.
+It is read for
+.Nm ex
+commands first in the startup sequence.
+Must be owned by root or the user,
+and writable only by the owner.
+.It Pa /tmp
 Temporary file directory.
-.TP
-/var/tmp/vi.recover
+.It Pa /var/tmp/vi.recover
 The default recovery file directory.
-.TP
-$HOME/.nexrc
-1st choice for user's home directory startup file.
-.TP
-$HOME/.exrc
-2nd choice for user's home directory startup file.
-.TP
-\&.nexrc
-1st choice for local directory startup file.
-.TP
-\&.exrc
-2nd choice for local directory startup file.
-.SH SEE ALSO
-.IR ctags (1),
-.IR more (1),
-.IR curses (3),
-.IR dbopen (3)
-.sp
-The ``Vi Quick Reference'' card.
-.sp
-``An Introduction to Display Editing with Vi'', found in the
-``UNIX User's Manual Supplementary Documents''
-section of both the 4.3BSD and 4.4BSD manual sets.
-This document is the closest thing available to an introduction to the
-.I \&vi
-screen editor.
-.sp
-``Ex Reference Manual (Version 3.7)'',
-found in the
-``UNIX User's Manual Supplementary Documents''
-section of both the 4.3BSD and 4.4BSD manual sets.
-This document is the final reference for the
-.I \&ex
-editor, as distributed in most historic 4BSD and System V systems.
-.sp
-``Edit: A tutorial'',
-found in the
-``UNIX User's Manual Supplementary Documents''
-section of the 4.3BSD manual set.
-This document is an introduction to a simple version of the
-.I \&ex
-screen editor.
-.sp
-``Ex/Vi Reference Manual'',
-found in the
-``UNIX User's Manual Supplementary Documents''
-section of the 4.4BSD manual set.
-This document is the final reference for the
-.I \&nex/nvi
-text editors, as distributed in 4.4BSD and 4.4BSD-Lite.
-.PP
-.I Roff
-source for all of these documents is distributed with
-.I nex/nvi
-in the
-.I nvi/USD.doc
-directory of the
-.I nex/nvi
-source code.
-.sp
-The files ``autowrite'', ``input'', ``quoting'' and ``structures''
-found in the
-.I nvi/docs/internals
-directory of the
-.I nex/nvi
-source code.
-.SH HISTORY
+.It Pa $HOME/.nexrc
+First choice for user's home directory startup file, read for
+.Nm ex
+commands right after
+.Pa /etc/vi.exrc
+unless either
+.Ev NEXINIT
+or
+.Ev EXINIT
+are set.
+Must be owned by root or the user,
+and writable only by the owner.
+.It Pa $HOME/.exrc
+Second choice for user's home directory startup file, read for
+.Nm ex
+commands under the same conditions as
+.Pa $HOME/.nexrc .
+.It Pa .nexrc
+First choice for local directory startup file, read for
+.Nm ex
+commands at the end of the startup sequence if the
+.Cm exrc
+option was turned on earlier.
+Must be owned by the user
+and writable only by the owner.
+.It Pa .exrc
+Second choice for local directory startup file, read for
+.Nm ex
+commands under the same conditions as
+.Pa .nexrc .
+.El
+.Sh EXIT STATUS
 The
-.I nex/nvi
-replacements for the
-.I ex/vi
-editor first appeared in 4.4BSD.
-.SH STANDARDS
-.I \&Nex/nvi
-is close to IEEE Std1003.2 (``POSIX'').
+.Nm ex
+and
+.Nm vi
+utilities exit 0 on success,
+and \*(Gt0 if an error occurs.
+.Sh SEE ALSO
+.Xr ctags 1 ,
+.Xr iconv 1 ,
+.Xr re_format 7
+.Sh STANDARDS
+.Nm nex Ns / Ns Nm nvi
+is close to
+.St -p1003.1-2008 .
 That document differs from historical
-.I ex/vi
+.Nm ex Ns / Ns Nm vi
 practice in several places; there are changes to be made on both sides.
+.Sh HISTORY
+The
+.Nm ex
+editor first appeared in
+.Bx 1 .
+The
+.Nm nex Ns / Ns Nm nvi
+replacements for the
+.Nm ex Ns / Ns Nm vi
+editor first appeared in
+.Bx 4.4 .
+.Sh AUTHORS
+.An Bill Joy
+wrote the original version of
+.Nm ex
+in 1977.

Modified: trunk/contrib/nvi/docs/USD.doc/vi.ref/vi.ref
===================================================================
--- trunk/contrib/nvi/docs/USD.doc/vi.ref/vi.ref	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/docs/USD.doc/vi.ref/vi.ref	2018-06-10 20:23:48 UTC (rev 10823)
@@ -10,7 +10,7 @@
 .\"
 .\"     @(#)vi.ref	8.88 (Berkeley) 10/19/96
 .\"
-.\" $FreeBSD$
+.\" $FreeBSD: stable/10/contrib/nvi/docs/USD.doc/vi.ref/vi.ref 149196 2005-08-17 15:56:04Z cperciva $
 .\"
 .so ref.so
 .tp

Modified: trunk/contrib/nvi/ex/ex.c
===================================================================
--- trunk/contrib/nvi/ex/ex.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/ex/ex.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -7,18 +7,15 @@
  * See the LICENSE file for redistribution information.
  */
 
-/* $MidnightBSD$ */
-
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)ex.c	10.57 (Berkeley) 10/10/96";
+static const char sccsid[] = "$Id: ex.c,v 10.80 2012/10/03 16:24:40 zy Exp $";
 #endif /* not lint */
 
 #include <sys/types.h>
 #include <sys/queue.h>
 #include <sys/stat.h>
-#include <sys/time.h>
 
 #include <bitstring.h>
 #include <ctype.h>
@@ -37,11 +34,11 @@
 static void	ex_comlog __P((SCR *, EXCMD *));
 #endif
 static EXCMDLIST const *
-		ex_comm_search __P((char *, size_t));
+		ex_comm_search __P((CHAR_T *, size_t));
 static int	ex_discard __P((SCR *));
 static int	ex_line __P((SCR *, EXCMD *, MARK *, int *, int *));
 static int	ex_load __P((SCR *));
-static void	ex_unknown __P((SCR *, char *, size_t));
+static void	ex_unknown __P((SCR *, CHAR_T *, size_t));
 
 /*
  * ex --
@@ -50,8 +47,7 @@
  * PUBLIC: int ex __P((SCR **));
  */
 int
-ex(spp)
-	SCR **spp;
+ex(SCR **spp)
 {
 	EX_PRIVATE *exp;
 	GS *gp;
@@ -69,9 +65,9 @@
 		return (1);
 
 	/* Flush any saved messages. */
-	while ((mp = gp->msgq.lh_first) != NULL) {
+	while ((mp = SLIST_FIRST(gp->msgq)) != NULL) {
 		gp->scr_msg(sp, mp->mtype, mp->buf, mp->len);
-		LIST_REMOVE(mp, q);
+		SLIST_REMOVE_HEAD(gp->msgq, q);
 		free(mp->buf);
 		free(mp);
 	}
@@ -107,7 +103,7 @@
 
 		/* Clear any current interrupts, and get a command. */
 		CLR_INTERRUPT(sp);
-		if (ex_txt(sp, &sp->tiq, ':', flags))
+		if (ex_txt(sp, sp->tiq, ':', flags))
 			return (1);
 		if (INTERRUPTED(sp)) {
 			(void)ex_puts(sp, "\n");
@@ -122,9 +118,9 @@
 		 * If the user entered a single carriage return, send
 		 * ex_cmd() a separator -- it discards single newlines.
 		 */
-		tp = sp->tiq.cqh_first;
+		tp = TAILQ_FIRST(sp->tiq);
 		if (tp->len == 0) {
-			gp->excmd.cp = " ";	/* __TK__ why not |? */
+			gp->excmd.cp = L(" ");	/* __TK__ why not |? */
 			gp->excmd.clen = 1;
 		} else {
 			gp->excmd.cp = tp->lb;
@@ -194,8 +190,7 @@
  * PUBLIC: int ex_cmd __P((SCR *));
  */
 int
-ex_cmd(sp)
-	SCR *sp;
+ex_cmd(SCR *sp)
 {
 	enum nresult nret;
 	EX_PRIVATE *exp;
@@ -207,9 +202,12 @@
 	u_int32_t flags;
 	long ltmp;
 	int at_found, gv_found;
-	int ch, cnt, delim, isaddr, namelen;
+	int cnt, delim, isaddr, namelen;
 	int newscreen, notempty, tmp, vi_address;
-	char *arg1, *p, *s, *t;
+	CHAR_T *arg1, *s, *p, *t;
+	CHAR_T ch = '\0';
+	CHAR_T *n;
+	char *np;
 
 	gp = sp->gp;
 	exp = EXP(sp);
@@ -219,7 +217,7 @@
 	 * This means that *everything* must be resolved when we leave
 	 * this function for any reason.
 	 */
-loop:	ecp = gp->ecq.lh_first;
+loop:	ecp = SLIST_FIRST(gp->ecq);
 
 	/* If we're reading a command from a file, set up error information. */
 	if (ecp->if_name != NULL) {
@@ -261,7 +259,7 @@
 		if ((ch = *ecp->cp) == '\n') {
 			++gp->if_lno;
 			++ecp->if_lno;
-		} else if (isblank(ch))
+		} else if (cmdskip(ch))
 			notempty = 1;
 		else
 			break;
@@ -300,7 +298,7 @@
 	/* Skip whitespace. */
 	for (; ecp->clen > 0; ++ecp->cp, --ecp->clen) {
 		ch = *ecp->cp;
-		if (!isblank(ch))
+		if (!cmdskip(ch))
 			break;
 	}
 
@@ -323,7 +321,7 @@
 	    (!notempty || F_ISSET(sp, SC_VI) || F_ISSET(ecp, E_BLIGNORE))) {
 		if (ex_load(sp))
 			goto rfail;
-		ecp = gp->ecq.lh_first;
+		ecp = SLIST_FIRST(gp->ecq);
 		if (ecp->clen == 0)
 			goto rsuccess;
 		goto loop;
@@ -355,7 +353,7 @@
 	 */
 	for (; ecp->clen > 0; ++ecp->cp, --ecp->clen) {
 		ch = *ecp->cp;
-		if (!isblank(ch) && ch != ':')
+		if (!cmdskip(ch) && ch != ':')
 			break;
 	}
 
@@ -379,10 +377,10 @@
 	 * from vi mode, and displayed lines 2, 3, and 4, so we do a default
 	 * command for each separator.
 	 */
-#define	SINGLE_CHAR_COMMANDS	"\004!#&*<=>@~"
+#define	SINGLE_CHAR_COMMANDS	L("\004!#&*<=>@~")
 	newscreen = 0;
 	if (ecp->clen != 0 && ecp->cp[0] != '|' && ecp->cp[0] != '\n') {
-		if (strchr(SINGLE_CHAR_COMMANDS, *ecp->cp)) {
+		if (STRCHR(SINGLE_CHAR_COMMANDS, *ecp->cp)) {
 			p = ecp->cp;
 			++ecp->cp;
 			--ecp->clen;
@@ -390,7 +388,7 @@
 		} else {
 			for (p = ecp->cp;
 			    ecp->clen > 0; --ecp->clen, ++ecp->cp)
-				if (!isalpha(*ecp->cp))
+				if (!isascii(*ecp->cp) || !isalpha(*ecp->cp))
 					break;
 			if ((namelen = ecp->cp - p) == 0) {
 				msgq(sp, M_ERR, "080|Unknown command name");
@@ -417,7 +415,7 @@
 		switch (p[0]) {
 		case 'd':
 			for (s = p,
-			    t = cmds[C_DELETE].name; *s == *t; ++s, ++t);
+			    n = cmds[C_DELETE].name; *s == *n; ++s, ++n);
 			if (s[0] == 'l' || s[0] == 'p' || s[0] == '+' ||
 			    s[0] == '-' || s[0] == '^' || s[0] == '#') {
 				len = (ecp->cp - p) - (s - p);
@@ -512,7 +510,7 @@
 
 		/* Secure means no shell access. */
 		if (F_ISSET(ecp->cmd, E_SECURE) && O_ISSET(sp, O_SECURE)) {
-			ex_emsg(sp, ecp->cmd->name, EXM_SECURE);
+			ex_wemsg(sp, ecp->cmd->name, EXM_SECURE);
 			goto err;
 		}
 
@@ -576,8 +574,8 @@
 
 	/* Check for ex mode legality. */
 	if (F_ISSET(sp, SC_EX) && (F_ISSET(ecp->cmd, E_VIONLY) || newscreen)) {
-		msgq(sp, M_ERR,
-		    "082|%s: command not available in ex mode", ecp->cmd->name);
+		msgq_wstr(sp, M_ERR, ecp->cmd->name,
+		    "082|%s: command not available in ex mode");
 		goto err;
 	}
 
@@ -631,7 +629,8 @@
 	arg1_len = 0;
 	ecp->save_cmd = ecp->cp;
 	if (ecp->cmd == &cmds[C_EDIT] || ecp->cmd == &cmds[C_EX] ||
-	    ecp->cmd == &cmds[C_NEXT] || ecp->cmd == &cmds[C_VISUAL_VI]) {
+	    ecp->cmd == &cmds[C_NEXT] || ecp->cmd == &cmds[C_VISUAL_VI] ||
+	    ecp->cmd == &cmds[C_VSPLIT]) {
 		/*
 		 * Move to the next non-whitespace character.  A '!'
 		 * immediately following the command is eaten as a
@@ -646,7 +645,7 @@
 			ecp->save_cmd = ecp->cp;
 		}
 		for (; ecp->clen > 0; --ecp->clen, ++ecp->cp)
-			if (!isblank(*ecp->cp))
+			if (!cmdskip(*ecp->cp))
 				break;
 		/*
 		 * QUOTING NOTE:
@@ -668,7 +667,7 @@
 					++discard;
 					--ecp->clen;
 					ch = *++ecp->cp;
-				} else if (isblank(ch))
+				} else if (cmdskip(ch))
 					break;
 				*p++ = ch;
 			}
@@ -712,7 +711,7 @@
 		 */
 		for (tmp = 0; ecp->clen > 0; --ecp->clen, ++ecp->cp) {
 			ch = *ecp->cp;
-			if (isblank(ch))
+			if (cmdskip(ch))
 				tmp = 1;
 			else
 				break;
@@ -730,10 +729,11 @@
 		 * into something like ":s g", so use the special s command.
 		 */
 		for (; ecp->clen > 0; --ecp->clen, ++ecp->cp)
-			if (!isblank(ecp->cp[0]))
+			if (!cmdskip(ecp->cp[0]))
 				break;
 
-		if (isalnum(ecp->cp[0]) || ecp->cp[0] == '|') {
+		if (!isascii(ecp->cp[0]) ||
+		    isalnum(ecp->cp[0]) || ecp->cp[0] == '|') {
 			ecp->rcmd = cmds[C_SUBSTITUTE];
 			ecp->rcmd.fn = ex_subagain;
 			ecp->cmd = &ecp->rcmd;
@@ -777,7 +777,7 @@
 	for (p = ecp->cp; ecp->clen > 0; --ecp->clen, ++ecp->cp) {
 		ch = ecp->cp[0];
 		if (IS_ESCAPE(sp, ecp, ch) && ecp->clen > 1) {
-			tmp = ecp->cp[1];
+			CHAR_T tmp = ecp->cp[1];
 			if (tmp == '\n' || tmp == '|') {
 				if (tmp == '\n') {
 					++gp->if_lno;
@@ -818,7 +818,10 @@
 	 */
 	if (ecp->cmd == &cmds[C_SET])
 		for (p = ecp->cp, len = ecp->clen; len > 0; --len, ++p)
-			if (*p == '\\')
+			if (IS_ESCAPE(sp, ecp, *p) && len > 1) {
+				--len;
+				++p;
+			} else if (*p == '\\')
 				*p = CH_LITERAL;
 
 	/*
@@ -937,13 +940,13 @@
 	}
 
 	ecp->flagoff = 0;
-	for (p = ecp->cmd->syntax; *p != '\0'; ++p) {
+	for (np = ecp->cmd->syntax; *np != '\0'; ++np) {
 		/*
 		 * The force flag is sensitive to leading whitespace, i.e.
 		 * "next !" is different from "next!".  Handle it before
 		 * skipping leading <blank>s.
 		 */
-		if (*p == '!') {
+		if (*np == '!') {
 			if (ecp->clen > 0 && *ecp->cp == '!') {
 				++ecp->cp;
 				--ecp->clen;
@@ -954,12 +957,12 @@
 
 		/* Skip leading <blank>s. */
 		for (; ecp->clen > 0; --ecp->clen, ++ecp->cp)
-			if (!isblank(*ecp->cp))
+			if (!cmdskip(*ecp->cp))
 				break;
 		if (ecp->clen == 0)
 			break;
 
-		switch (*p) {
+		switch (*np) {
 		case '1':				/* +, -, #, l, p */
 			/*
 			 * !!!
@@ -1014,7 +1017,7 @@
 					FL_SET(ecp->iflags, E_C_CARAT);
 					break;
 				case '=':
-					if (*p == '3') {
+					if (*np == '3') {
 						FL_SET(ecp->iflags, E_C_EQUAL);
 						break;
 					}
@@ -1034,7 +1037,7 @@
 			 */
 			if ((ecp->cp[0] == '+' || ecp->cp[0] == '-' ||
 			    ecp->cp[0] == '^' || ecp->cp[0] == '#') &&
-			    strchr(p, '1') != NULL)
+			    strchr(np, '1') != NULL)
 				break;
 			/*
 			 * !!!
@@ -1042,7 +1045,7 @@
 			 * command "d2" would be a delete into buffer '2', and
 			 * not a two-line deletion.
 			 */
-			if (!isdigit(ecp->cp[0])) {
+			if (!ISDIGIT(ecp->cp[0])) {
 				ecp->buffer = *ecp->cp;
 				++ecp->cp;
 				--ecp->clen;
@@ -1050,9 +1053,9 @@
 			}
 			break;
 		case 'c':				/* count [01+a] */
-			++p;
+			++np;
 			/* Validate any signed value. */
-			if (!isdigit(*ecp->cp) && (*p != '+' ||
+			if (!ISDIGIT(*ecp->cp) && (*np != '+' ||
 			    (*ecp->cp != '+' && *ecp->cp != '-')))
 				break;
 			/* If a signed value, set appropriate flags. */
@@ -1065,7 +1068,7 @@
 				ex_badaddr(sp, NULL, A_NOTSET, nret);
 				goto err;
 			}
-			if (ltmp == 0 && *p != '0') {
+			if (ltmp == 0 && *np != '0') {
 				msgq(sp, M_ERR, "083|Count may not be zero");
 				goto err;
 			}
@@ -1081,7 +1084,7 @@
 			 * join) do different things with counts than with
 			 * line addresses.
 			 */
-			if (*p == 'a') {
+			if (*np == 'a') {
 				ecp->addr1 = ecp->addr2;
 				ecp->addr2.lno = ecp->addr1.lno + ltmp - 1;
 			} else
@@ -1108,7 +1111,7 @@
 
 			/* Line specifications are always required. */
 			if (!isaddr) {
-				msgq_str(sp, M_ERR, ecp->cp,
+				msgq_wstr(sp, M_ERR, ecp->cp,
 				     "084|%s: bad line specification");
 				goto err;
 			}
@@ -1151,7 +1154,7 @@
 				    ecp, ch) && ecp->clen > 1) {
 					--ecp->clen;
 					*p++ = *++ecp->cp;
-				} else if (isblank(ch)) {
+				} else if (cmdskip(ch)) {
 					++ecp->cp;
 					--ecp->clen;
 					break;
@@ -1165,7 +1168,7 @@
 			for (; ecp->clen > 0;
 			    --ecp->clen, ++ecp->cp) {
 				ch = *ecp->cp;
-				if (!isblank(ch))
+				if (!cmdskip(ch))
 					break;
 			}
 			if (ecp->clen == 0)
@@ -1188,29 +1191,35 @@
 		case 'w':				/* word */
 			if (argv_exp3(sp, ecp, ecp->cp, ecp->clen))
 				goto err;
-arg_cnt_chk:		if (*++p != 'N') {		/* N */
+arg_cnt_chk:		if (*++np != 'N') {		/* N */
 				/*
 				 * If a number is specified, must either be
 				 * 0 or that number, if optional, and that
 				 * number, if required.
 				 */
-				tmp = *p - '0';
-				if ((*++p != 'o' || exp->argsoff != 0) &&
+				tmp = *np - '0';
+				if ((*++np != 'o' || exp->argsoff != 0) &&
 				    exp->argsoff != tmp)
 					goto usage;
 			}
 			goto addr_verify;
-		default:
+		default: {
+			size_t nlen;
+			char *nstr;
+
+			INT2CHAR(sp, ecp->cmd->name, STRLEN(ecp->cmd->name) + 1,
+			    nstr, nlen);
 			msgq(sp, M_ERR,
 			    "085|Internal syntax table error (%s: %s)",
-			    ecp->cmd->name, KEY_NAME(sp, *p));
+			    nstr, KEY_NAME(sp, *np));
 		}
+		}
 	}
 
 	/* Skip trailing whitespace. */
 	for (; ecp->clen > 0; --ecp->clen) {
 		ch = *ecp->cp++;
-		if (!isblank(ch))
+		if (!cmdskip(ch))
 			break;
 	}
 
@@ -1218,7 +1227,7 @@
 	 * There shouldn't be anything left, and no more required fields,
 	 * i.e neither 'l' or 'r' in the syntax string.
 	 */
-	if (ecp->clen != 0 || strpbrk(p, "lr")) {
+	if (ecp->clen != 0 || strpbrk(np, "lr")) {
 usage:		msgq(sp, M_ERR, "086|Usage: %s", ecp->cmd->usage);
 		goto err;
 	}
@@ -1381,8 +1390,8 @@
 	/* Make sure no function left global temporary space locked. */
 	if (F_ISSET(gp, G_TMP_INUSE)) {
 		F_CLR(gp, G_TMP_INUSE);
-		msgq(sp, M_ERR, "087|%s: temporary buffer not released",
-		    ecp->cmd->name);
+		msgq_wstr(sp, M_ERR, ecp->cmd->name,
+		    "087|%s: temporary buffer not released");
 	}
 #endif
 	/*
@@ -1495,7 +1504,7 @@
 
 		ecp->save_cmd -= arg1_len;
 		ecp->save_cmdlen += arg1_len;
-		memcpy(ecp->save_cmd, arg1, arg1_len);
+		MEMCPY(ecp->save_cmd, arg1, arg1_len);
 
 		/*
 		 * Any commands executed from a +cmd are executed starting at
@@ -1529,8 +1538,7 @@
 	 */
 	if (F_ISSET(sp, SC_EXIT | SC_EXIT_FORCE | SC_FSWITCH | SC_SSWITCH)) {
 		at_found = gv_found = 0;
-		for (ecp = sp->gp->ecq.lh_first;
-		    ecp != NULL; ecp = ecp->q.le_next)
+		SLIST_FOREACH(ecp, sp->gp->ecq, q)
 			switch (ecp->agv_flags) {
 			case 0:
 			case AGV_AT_NORANGE:
@@ -1582,7 +1590,7 @@
 				break;
 			}
 		}
-	if (ecp->save_cmdlen != 0 || gp->ecq.lh_first != &gp->excmd) {
+	if (ecp->save_cmdlen != 0 || SLIST_FIRST(gp->ecq) != &gp->excmd) {
 discard:	msgq(sp, M_BERR,
 		    "092|Ex command failed: pending commands discarded");
 		ex_discard(sp);
@@ -1611,10 +1619,7 @@
  * PUBLIC: int ex_range __P((SCR *, EXCMD *, int *));
  */
 int
-ex_range(sp, ecp, errp)
-	SCR *sp;
-	EXCMD *ecp;
-	int *errp;
+ex_range(SCR *sp, EXCMD *ecp, int *errp)
 {
 	enum { ADDR_FOUND, ADDR_NEED, ADDR_NONE } addr;
 	GS *gp;
@@ -1813,11 +1818,7 @@
  * it's fairly close.
  */
 static int
-ex_line(sp, ecp, mp, isaddrp, errp)
-	SCR *sp;
-	EXCMD *ecp;
-	MARK *mp;
-	int *isaddrp, *errp;
+ex_line(SCR *sp, EXCMD *ecp, MARK *mp, int *isaddrp, int *errp)
 {
 	enum nresult nret;
 	EX_PRIVATE *exp;
@@ -1824,8 +1825,8 @@
 	GS *gp;
 	long total, val;
 	int isneg;
-	int (*sf) __P((SCR *, MARK *, MARK *, char *, size_t, char **, u_int));
-	char *endp;
+	int (*sf) __P((SCR *, MARK *, MARK *, CHAR_T *, size_t, CHAR_T **, u_int));
+	CHAR_T *endp;
 
 	gp = sp->gp;
 	exp = EXP(sp);
@@ -1834,7 +1835,7 @@
 	F_CLR(ecp, E_DELTA);
 
 	/* No addresses permitted until a file has been read in. */
-	if (sp->ep == NULL && strchr("$0123456789'\\/?.+-^", *ecp->cp)) {
+	if (sp->ep == NULL && STRCHR(L("$0123456789'\\/?.+-^"), *ecp->cp)) {
 		ex_badaddr(sp, NULL, A_EMPTY, NUM_OK);
 		*errp = 1;
 		return (0);
@@ -1895,7 +1896,7 @@
 		 * difference.  C'est la vie.
 		 */
 		if (ecp->clen < 2 ||
-		    ecp->cp[1] != '/' && ecp->cp[1] != '?') {
+		    (ecp->cp[1] != '/' && ecp->cp[1] != '?')) {
 			msgq(sp, M_ERR, "096|\\ not followed by / or ?");
 			*errp = 1;
 			return (0);
@@ -1945,7 +1946,7 @@
 		 * the '+' could be omitted.  (This feature is found in ed
 		 * as well.)
 		 */
-		if (ecp->clen > 1 && isdigit(ecp->cp[1]))
+		if (ecp->clen > 1 && ISDIGIT(ecp->cp[1]))
 			*ecp->cp = '+';
 		else {
 			++ecp->cp;
@@ -1956,7 +1957,7 @@
 
 	/* Skip trailing <blank>s. */
 	for (; ecp->clen > 0 &&
-	    isblank(ecp->cp[0]); ++ecp->cp, --ecp->clen);
+	    cmdskip(ecp->cp[0]); ++ecp->cp, --ecp->clen);
 
 	/*
 	 * Evaluate any offset.  If no address yet found, the offset
@@ -1963,7 +1964,7 @@
 	 * is relative to ".".
 	 */
 	total = 0;
-	if (ecp->clen != 0 && (isdigit(ecp->cp[0]) ||
+	if (ecp->clen != 0 && (ISDIGIT(ecp->cp[0]) ||
 	    ecp->cp[0] == '+' || ecp->cp[0] == '-' ||
 	    ecp->cp[0] == '^')) {
 		if (!*isaddrp) {
@@ -1999,14 +2000,14 @@
 		 */
 		F_SET(ecp, E_DELTA);
 		for (;;) {
-			for (; ecp->clen > 0 && isblank(ecp->cp[0]);
+			for (; ecp->clen > 0 && cmdskip(ecp->cp[0]);
 			    ++ecp->cp, --ecp->clen);
-			if (ecp->clen == 0 || !isdigit(ecp->cp[0]) &&
+			if (ecp->clen == 0 || (!ISDIGIT(ecp->cp[0]) &&
 			    ecp->cp[0] != '+' && ecp->cp[0] != '-' &&
-			    ecp->cp[0] != '^')
+			    ecp->cp[0] != '^'))
 				break;
-			if (!isdigit(ecp->cp[0]) &&
-			    !isdigit(ecp->cp[1])) {
+			if (!ISDIGIT(ecp->cp[0]) &&
+			    !ISDIGIT(ecp->cp[1])) {
 				total += ecp->cp[0] == '+' ? 1 : -1;
 				--ecp->clen;
 				++ecp->cp;
@@ -2064,8 +2065,7 @@
  *	Load up the next command, which may be an @ buffer or global command.
  */
 static int
-ex_load(sp)
-	SCR *sp;
+ex_load(SCR *sp)
 {
 	GS *gp;
 	EXCMD *ecp;
@@ -2078,16 +2078,18 @@
 	 * can't be an AGV command, which makes things a bit easier.
 	 */
 	for (gp = sp->gp;;) {
+		ecp = SLIST_FIRST(gp->ecq);
+
+		/* Discard the allocated source name as requested. */
+		if (F_ISSET(ecp, E_NAMEDISCARD))
+			free(ecp->if_name);
+
 		/*
 		 * If we're back to the original structure, leave it around,
-		 * but discard any allocated source name, we've returned to
-		 * the beginning of the command stack.
+		 * since we've returned to the beginning of the command stack.
 		 */
-		if ((ecp = gp->ecq.lh_first) == &gp->excmd) {
-			if (F_ISSET(ecp, E_NAMEDISCARD)) {
-				free(ecp->if_name);
-				ecp->if_name = NULL;
-			}
+		if (ecp == &gp->excmd) {
+			ecp->if_name = NULL;
 			return (0);
 		}
 
@@ -2107,15 +2109,15 @@
 		 */
 		if (FL_ISSET(ecp->agv_flags, AGV_ALL)) {
 			/* Discard any exhausted ranges. */
-			while ((rp = ecp->rq.cqh_first) != (void *)&ecp->rq)
+			while ((rp = TAILQ_FIRST(ecp->rq)) != NULL)
 				if (rp->start > rp->stop) {
-					CIRCLEQ_REMOVE(&ecp->rq, rp, q);
+					TAILQ_REMOVE(ecp->rq, rp, q);
 					free(rp);
 				} else
 					break;
 
 			/* If there's another range, continue with it. */
-			if (rp != (void *)&ecp->rq)
+			if (rp != NULL)
 				break;
 
 			/* If it's a global/v command, fix up the last line. */
@@ -2133,7 +2135,7 @@
 		}
 
 		/* Discard the EXCMD. */
-		LIST_REMOVE(ecp, q);
+		SLIST_REMOVE_HEAD(gp->ecq, q);
 		free(ecp);
 	}
 
@@ -2144,7 +2146,7 @@
 	 * so we have play games.
 	 */
 	ecp->cp = ecp->o_cp;
-	memcpy(ecp->cp, ecp->cp + ecp->o_clen, ecp->o_clen);
+	MEMCPY(ecp->cp, ecp->cp + ecp->o_clen, ecp->o_clen);
 	ecp->clen = ecp->o_clen;
 	ecp->range_lno = sp->lno = rp->start++;
 
@@ -2158,8 +2160,7 @@
  *	Discard any pending ex commands.
  */
 static int
-ex_discard(sp)
-	SCR *sp;
+ex_discard(SCR *sp)
 {
 	GS *gp;
 	EXCMD *ecp;
@@ -2169,18 +2170,26 @@
 	 * We know the first command can't be an AGV command, so we don't
 	 * process it specially.  We do, however, nail the command itself.
 	 */
-	for (gp = sp->gp; (ecp = gp->ecq.lh_first) != &gp->excmd;) {
+	for (gp = sp->gp;;) {
+		ecp = SLIST_FIRST(gp->ecq);
+		if (F_ISSET(ecp, E_NAMEDISCARD))
+			free(ecp->if_name);
+		/* Reset the last command without dropping it. */
+		if (ecp == &gp->excmd)
+			break;
 		if (FL_ISSET(ecp->agv_flags, AGV_ALL)) {
-			while ((rp = ecp->rq.cqh_first) != (void *)&ecp->rq) {
-				CIRCLEQ_REMOVE(&ecp->rq, rp, q);
+			while ((rp = TAILQ_FIRST(ecp->rq)) != NULL) {
+				TAILQ_REMOVE(ecp->rq, rp, q);
 				free(rp);
 			}
 			free(ecp->o_cp);
 		}
-		LIST_REMOVE(ecp, q);
+		SLIST_REMOVE_HEAD(gp->ecq, q);
 		free(ecp);
 	}
-	gp->ecq.lh_first->clen = 0;
+
+	ecp->if_name = NULL;
+	ecp->clen = 0;
 	return (0);
 }
 
@@ -2189,19 +2198,16 @@
  *	Display an unknown command name.
  */
 static void
-ex_unknown(sp, cmd, len)
-	SCR *sp;
-	char *cmd;
-	size_t len;
+ex_unknown(SCR *sp, CHAR_T *cmd, size_t len)
 {
 	size_t blen;
-	char *bp;
+	CHAR_T *bp;
 
-	GET_SPACE_GOTO(sp, bp, blen, len + 1);
+	GET_SPACE_GOTOW(sp, bp, blen, len + 1);
 	bp[len] = '\0';
-	memcpy(bp, cmd, len);
-	msgq_str(sp, M_ERR, bp, "098|The %s command is unknown");
-	FREE_SPACE(sp, bp, blen);
+	MEMCPY(bp, cmd, len);
+	msgq_wstr(sp, M_ERR, bp, "098|The %s command is unknown");
+	FREE_SPACEW(sp, bp, blen);
 
 alloc_err:
 	return;
@@ -2213,12 +2219,10 @@
  *	[un]abbreviate command, so it can turn off abbreviations.  See
  *	the usual ranting in the vi/v_txt_ev.c:txt_abbrev() routine.
  *
- * PUBLIC: int ex_is_abbrev __P((char *, size_t));
+ * PUBLIC: int ex_is_abbrev __P((CHAR_T *, size_t));
  */
 int
-ex_is_abbrev(name, len)
-	char *name;
-	size_t len;
+ex_is_abbrev(CHAR_T *name, size_t len)
 {
 	EXCMDLIST const *cp;
 
@@ -2232,12 +2236,10 @@
  *	unmap command, so it can turn off input mapping.  See the usual
  *	ranting in the vi/v_txt_ev.c:txt_unmap() routine.
  *
- * PUBLIC: int ex_is_unmap __P((char *, size_t));
+ * PUBLIC: int ex_is_unmap __P((CHAR_T *, size_t));
  */
 int
-ex_is_unmap(name, len)
-	char *name;
-	size_t len;
+ex_is_unmap(CHAR_T *name, size_t len)
 {
 	EXCMDLIST const *cp;
 
@@ -2257,9 +2259,7 @@
  *	Search for a command name.
  */
 static EXCMDLIST const *
-ex_comm_search(name, len)
-	char *name;
-	size_t len;
+ex_comm_search(CHAR_T *name, size_t len)
 {
 	EXCMDLIST const *cp;
 
@@ -2268,7 +2268,7 @@
 			return (NULL);
 		if (cp->name[0] != name[0])
 			continue;
-		if (!memcmp(name, cp->name, len))
+		if (!MEMCMP(name, cp->name, len))
 			return (cp);
 	}
 	return (NULL);
@@ -2282,11 +2282,7 @@
  * PUBLIC:    __P((SCR *, EXCMDLIST const *, enum badaddr, enum nresult));
  */
 void
-ex_badaddr(sp, cp, ba, nret)
-	SCR *sp;
-	EXCMDLIST const *cp;
-	enum badaddr ba;
-	enum nresult nret;
+ex_badaddr(SCR *sp, const EXCMDLIST *cp, enum badaddr ba, enum nresult nret)
 {
 	recno_t lno;
 
@@ -2309,7 +2305,7 @@
 	 * underlying file, that's the real problem.
 	 */
 	if (sp->ep == NULL) {
-		ex_emsg(sp, cp ? cp->name : NULL, EXM_NOFILEYET);
+		ex_wemsg(sp, cp ? cp->name : NULL, EXM_NOFILEYET);
 		return;
 	}
 
@@ -2323,7 +2319,7 @@
 		if (lno != 0) {
 			msgq(sp, M_ERR,
 			    "102|Illegal address: only %lu lines in the file",
-			    lno);
+			    (u_long)lno);
 			break;
 		}
 		/* FALLTHROUGH */
@@ -2334,9 +2330,8 @@
 		abort();
 		/* NOTREACHED */
 	case A_ZERO:
-		msgq(sp, M_ERR,
-		    "104|The %s command doesn't permit an address of 0",
-		    cp->name);
+		msgq_wstr(sp, M_ERR, cp->name,
+		    "104|The %s command doesn't permit an address of 0");
 		break;
 	}
 	return;
@@ -2352,7 +2347,7 @@
 	SCR *sp;
 	EXCMD *ecp;
 {
-	TRACE(sp, "ecmd: %s", ecp->cmd->name);
+	TRACE(sp, "ecmd: "WS, ecp->cmd->name);
 	if (ecp->addrcnt > 0) {
 		TRACE(sp, " a1 %d", ecp->addr1.lno);
 		if (ecp->addrcnt > 1)
@@ -2362,11 +2357,13 @@
 		TRACE(sp, " line %d", ecp->lineno);
 	if (ecp->flags)
 		TRACE(sp, " flags 0x%x", ecp->flags);
-	if (F_ISSET(&exc, E_BUFFER))
-		TRACE(sp, " buffer %c", ecp->buffer);
-	if (ecp->argc)
+	if (FL_ISSET(ecp->iflags, E_C_BUFFER))
+		TRACE(sp, " buffer "WC, ecp->buffer);
+	if (ecp->argc) {
+		int cnt;
 		for (cnt = 0; cnt < ecp->argc; ++cnt)
-			TRACE(sp, " arg %d: {%s}", cnt, ecp->argv[cnt]->bp);
+			TRACE(sp, " arg %d: {"WS"}", cnt, ecp->argv[cnt]->bp);
+	}
 	TRACE(sp, "\n");
 }
 #endif

Modified: trunk/contrib/nvi/ex/ex.h
===================================================================
--- trunk/contrib/nvi/ex/ex.h	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/ex/ex.h	2018-06-10 20:23:48 UTC (rev 10823)
@@ -6,13 +6,13 @@
  *
  * See the LICENSE file for redistribution information.
  *
- *	@(#)ex.h	10.24 (Berkeley) 8/12/96
+ *	$Id: ex.h,v 10.31 2012/10/03 02:33:24 zy Exp $
  */
 
 #define	PROMPTCHAR	':'		/* Prompt using a colon. */
 
 typedef struct _excmdlist {		/* Ex command table structure. */
-	char *name;			/* Command name, underlying function. */
+	CHAR_T *name;			/* Command name, underlying function. */
 	int (*fn) __P((SCR *, EXCMD *));
 
 #define	E_ADDR1		0x00000001	/* One address. */
@@ -49,6 +49,9 @@
 	(F_ISSET(cmdp, E_VLITONLY) ?					\
 	    (ch) == CH_LITERAL : KEY_VAL(sp, ch) == K_VLNEXT)
 
+#define	IS_SHELLMETA(sp, ch)						\
+	((ch) <= CHAR_MAX && strchr(O_STR(sp, O_SHELLMETA), ch) != NULL)
+
 /*
  * File state must be checked for each command -- any ex command may be entered
  * at any time, and most of them won't work well if a file hasn't yet been read
@@ -56,7 +59,7 @@
  */
 #define	NEEDFILE(sp, cmdp) {						\
 	if ((sp)->ep == NULL) {						\
-		ex_emsg(sp, (cmdp)->cmd->name, EXM_NOFILEYET);		\
+		ex_wemsg(sp, (cmdp)->cmd->name, EXM_NOFILEYET);		\
 		return (1);						\
 	}								\
 }
@@ -64,13 +67,13 @@
 /* Range structures for global and @ commands. */
 typedef struct _range RANGE;
 struct _range {				/* Global command range. */
-	CIRCLEQ_ENTRY(_range) q;	/* Linked list of ranges. */
+	TAILQ_ENTRY(_range) q;		/* Linked list of ranges. */
 	recno_t start, stop;		/* Start/stop of the range. */
 };
 
 /* Ex command structure. */
 struct _excmd {
-	LIST_ENTRY(_excmd) q;		/* Linked list of commands. */
+	SLIST_ENTRY(_excmd) q;		/* Linked list of commands. */
 
 	char	 *if_name;		/* Associated file. */
 	recno_t	  if_lno;		/* Associated line number. */
@@ -80,18 +83,18 @@
 	memset(&((cmdp)->cp), 0, ((char *)&(cmdp)->flags -		\
 	    (char *)&((cmdp)->cp)) + sizeof((cmdp)->flags))
 
-	char	 *cp;			/* Current command text. */
+	CHAR_T	 *cp;			/* Current command text. */
 	size_t	  clen;			/* Current command length. */
 
-	char	 *save_cmd;		/* Remaining command. */
+	CHAR_T	 *save_cmd;		/* Remaining command. */
 	size_t	  save_cmdlen;		/* Remaining command length. */
 
 	EXCMDLIST const *cmd;		/* Command: entry in command table. */
 	EXCMDLIST rcmd;			/* Command: table entry/replacement. */
 
-	CIRCLEQ_HEAD(_rh, _range) rq;	/* @/global range: linked list. */
+	TAILQ_HEAD(_rh, _range) rq[1];	/* @/global range: linked list. */
 	recno_t   range_lno;		/* @/global range: set line number. */
-	char	 *o_cp;			/* Original @/global command. */
+	CHAR_T	 *o_cp;			/* Original @/global command. */
 	size_t	  o_clen;		/* Original @/global command length. */
 #define	AGV_AT		0x01		/* @ buffer execution. */
 #define	AGV_AT_NORANGE	0x02		/* @ buffer execution without range. */
@@ -133,7 +136,7 @@
 #define	E_C_PRINT	0x01000		/*  p flag. */
 	u_int16_t iflags;		/* User input information. */
 
-#define	__INUSE2	0x000004ff	/* Same name space as EXCMDLIST. */
+#define	__INUSE2	0x000007ff	/* Same name space as EXCMDLIST. */
 #define	E_BLIGNORE	0x00000800	/* Ignore blank lines. */
 #define	E_NAMEDISCARD	0x00001000	/* Free/discard the name. */
 #define	E_NOAUTO	0x00002000	/* Don't do autoprint output. */
@@ -152,18 +155,16 @@
 #define	E_SEARCH_WMSG	0x01000000	/* Display search-wrapped message. */
 #define	E_USELASTCMD	0x02000000	/* Use the last command. */
 #define	E_VISEARCH	0x04000000	/* It's really a vi search command. */
-#ifdef GTAGS
-#define	E_REFERENCE	0x08000000	/* locate function references */
-#endif
 	u_int32_t flags;		/* Current flags. */
 };
 
 /* Ex private, per-screen memory. */
 typedef struct _ex_private {
-	CIRCLEQ_HEAD(_tqh, _tagq) tq;	/* Tag queue. */
-	TAILQ_HEAD(_tagfh, _tagf) tagfq;/* Tag file list. */
-	LIST_HEAD(_csch, _csc) cscq;    /* Cscope connection list. */
-	char	*tag_last;		/* Saved last tag string. */
+					/* Tag file list. */
+	TAILQ_HEAD(_tagfh, _tagf) tagfq[1];
+	TAILQ_HEAD(_tqh, _tagq) tq[1];	/* Tag queue. */
+	SLIST_HEAD(_csch, _csc) cscq[1];/* Cscope connection list. */
+	CHAR_T	*tag_last;		/* Saved last tag string. */
 
 	CHAR_T	*lastbcomm;		/* Last bang command. */
 
@@ -175,6 +176,7 @@
 
 	char	*ibp;			/* File line input buffer. */
 	size_t	 ibp_len;		/* File line input buffer length. */
+	CONVWIN	 ibcw;			/* File line input conversion buffer. */
 
 	/*
 	 * Buffers for the ex output.  The screen/vi support doesn't do any
@@ -228,4 +230,4 @@
 } tagmsg_t;
 
 #include "ex_def.h"
-#include "ex_extern.h"
+#include "extern.h"

Modified: trunk/contrib/nvi/ex/ex_abbrev.c
===================================================================
--- trunk/contrib/nvi/ex/ex_abbrev.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/ex/ex_abbrev.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -10,7 +10,7 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)ex_abbrev.c	10.7 (Berkeley) 3/6/96";
+static const char sccsid[] = "$Id: ex_abbrev.c,v 10.10 2001/12/16 18:18:54 skimo Exp $";
 #endif /* not lint */
 
 #include <sys/types.h>
@@ -34,9 +34,7 @@
  * PUBLIC: int ex_abbr __P((SCR *, EXCMD *));
  */
 int
-ex_abbr(sp, cmdp)
-	SCR *sp;
-	EXCMD *cmdp;
+ex_abbr(SCR *sp, EXCMD *cmdp)
 {
 	CHAR_T *p;
 	size_t len;
@@ -71,7 +69,7 @@
 			return (1);
 	}
 	for (p = cmdp->argv[0]->bp; *p != '\0'; ++p)
-		if (isblank(p[0])) {
+		if (ISBLANK(p[0])) {
 			msgq(sp, M_ERR,
 			    "107|Abbreviations may not contain tabs or spaces");
 			return (1);
@@ -100,9 +98,7 @@
  * PUBLIC: int ex_unabbr __P((SCR *, EXCMD *));
  */
 int
-ex_unabbr(sp, cmdp)
-	SCR *sp;
-        EXCMD *cmdp;
+ex_unabbr(SCR *sp, EXCMD *cmdp)
 {
 	ARGS *ap;
 
@@ -109,7 +105,7 @@
 	ap = cmdp->argv[0];
 	if (!F_ISSET(sp->gp, G_ABBREV) ||
 	    seq_delete(sp, ap->bp, ap->len, SEQ_ABBREV)) {
-		msgq_str(sp, M_ERR, ap->bp,
+		msgq_wstr(sp, M_ERR, ap->bp,
 		    "109|\"%s\" is not an abbreviation");
 		return (1);
 	}

Modified: trunk/contrib/nvi/ex/ex_append.c
===================================================================
--- trunk/contrib/nvi/ex/ex_append.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/ex/ex_append.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -10,11 +10,12 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)ex_append.c	10.30 (Berkeley) 10/23/96";
+static const char sccsid[] = "$Id: ex_append.c,v 10.34 2001/06/25 15:19:14 skimo Exp $";
 #endif /* not lint */
 
 #include <sys/types.h>
 #include <sys/queue.h>
+#include <sys/time.h>
 
 #include <bitstring.h>
 #include <limits.h>
@@ -36,9 +37,7 @@
  * PUBLIC: int ex_append __P((SCR *, EXCMD *));
  */
 int
-ex_append(sp, cmdp)
-	SCR *sp;
-	EXCMD *cmdp;
+ex_append(SCR *sp, EXCMD *cmdp)
 {
 	return (ex_aci(sp, cmdp, APPEND));
 }
@@ -50,9 +49,7 @@
  * PUBLIC: int ex_change __P((SCR *, EXCMD *));
  */
 int
-ex_change(sp, cmdp)
-	SCR *sp;
-	EXCMD *cmdp;
+ex_change(SCR *sp, EXCMD *cmdp)
 {
 	return (ex_aci(sp, cmdp, CHANGE));
 }
@@ -65,9 +62,7 @@
  * PUBLIC: int ex_insert __P((SCR *, EXCMD *));
  */
 int
-ex_insert(sp, cmdp)
-	SCR *sp;
-	EXCMD *cmdp;
+ex_insert(SCR *sp, EXCMD *cmdp)
 {
 	return (ex_aci(sp, cmdp, INSERT));
 }
@@ -77,16 +72,13 @@
  *	Append, change, insert in ex.
  */
 static int
-ex_aci(sp, cmdp, cmd)
-	SCR *sp;
-	EXCMD *cmdp;
-	enum which cmd;
+ex_aci(SCR *sp, EXCMD *cmdp, enum which cmd)
 {
 	CHAR_T *p, *t;
 	GS *gp;
 	TEXT *tp;
-	TEXTH tiq;
-	recno_t cnt, lno;
+	TEXTH tiq[] = {{ 0 }};
+	recno_t cnt = 0, lno;
 	size_t len;
 	u_int32_t flags;
 	int need_newline;
@@ -175,7 +167,7 @@
 			if (len != 0) {
 				++t;
 				if (--len == 0 &&
-				    db_append(sp, 1, lno++, "", 0))
+				    db_append(sp, 1, lno++, NULL, 0))
 					return (1);
 			}
 		}
@@ -213,7 +205,7 @@
 	 */
 	if (F_ISSET(sp, SC_VI)) {
 		if (gp->scr_screen(sp, SC_EX)) {
-			ex_emsg(sp, cmdp->cmd->name, EXM_NOCANON);
+			ex_wemsg(sp, cmdp->cmd->name, EXM_NOCANON);
 			return (1);
 		}
 
@@ -254,16 +246,16 @@
 	 * characters in the common TEXTH structure when they were inserted
 	 * into the file, above.)
 	 */
-	memset(&tiq, 0, sizeof(TEXTH));
-	CIRCLEQ_INIT(&tiq);
+	TAILQ_INIT(tiq);
 
-	if (ex_txt(sp, &tiq, 0, flags))
+	if (ex_txt(sp, tiq, 0, flags))
 		return (1);
 
-	for (cnt = 0, tp = tiq.cqh_first;
-	    tp != (TEXT *)&tiq; ++cnt, tp = tp->q.cqe_next)
+	TAILQ_FOREACH(tp, tiq, q) {
 		if (db_append(sp, 1, lno++, tp->lb, tp->len))
 			return (1);
+		++cnt;
+	}
 
 	/*
 	 * Set sp->lno to the final line number value (correcting for a

Modified: trunk/contrib/nvi/ex/ex_args.c
===================================================================
--- trunk/contrib/nvi/ex/ex_args.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/ex/ex_args.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -10,7 +10,7 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)ex_args.c	10.16 (Berkeley) 7/13/96";
+static const char sccsid[] = "$Id: ex_args.c,v 10.19 2011/12/16 16:18:10 zy Exp $";
 #endif /* not lint */
 
 #include <sys/types.h>
@@ -42,14 +42,16 @@
  * PUBLIC: int ex_next __P((SCR *, EXCMD *));
  */
 int
-ex_next(sp, cmdp)
-	SCR *sp;
-	EXCMD *cmdp;
+ex_next(SCR *sp, EXCMD *cmdp)
 {
 	ARGS **argv;
 	FREF *frp;
 	int noargs;
 	char **ap;
+	CHAR_T *wp;
+	size_t wlen;
+	char *np;
+	size_t nlen;
 
 	/* Check for file to move to. */
 	if (cmdp->argc == 0 && (sp->cargv == NULL || sp->cargv[1] == NULL)) {
@@ -60,8 +62,9 @@
 	if (F_ISSET(cmdp, E_NEWSCREEN)) {
 		/* By default, edit the next file in the old argument list. */
 		if (cmdp->argc == 0) {
-			if (argv_exp0(sp,
-			    cmdp, sp->cargv[1], strlen(sp->cargv[1])))
+			CHAR2INT(sp, sp->cargv[1], strlen(sp->cargv[1]) + 1,
+					   wp, wlen);
+			if (argv_exp0(sp, cmdp, wp, wlen - 1))
 				return (1);
 			return (ex_edit(sp, cmdp));
 		}
@@ -88,10 +91,11 @@
 		CALLOC_RET(sp,
 		    sp->argv, char **, cmdp->argc + 1, sizeof(char *));
 		for (ap = sp->argv,
-		    argv = cmdp->argv; argv[0]->len != 0; ++ap, ++argv)
-			if ((*ap =
-			    v_strdup(sp, argv[0]->bp, argv[0]->len)) == NULL)
+		    argv = cmdp->argv; argv[0]->len != 0; ++ap, ++argv) {
+			INT2CHAR(sp, argv[0]->bp, argv[0]->len, np, nlen);
+			if ((*ap = v_strdup(sp, np, nlen)) == NULL)
 				return (1);
+		}
 		*ap = NULL;
 
 		/* Switch to the first file. */
@@ -125,12 +129,12 @@
  *	New screen version of ex_next.
  */
 static int
-ex_N_next(sp, cmdp)
-	SCR *sp;
-	EXCMD *cmdp;
+ex_N_next(SCR *sp, EXCMD *cmdp)
 {
 	SCR *new;
 	FREF *frp;
+	char *np;
+	size_t nlen;
 
 	/* Get a new screen. */
 	if (screen_init(sp->gp, sp, &new))
@@ -141,7 +145,8 @@
 	}
 
 	/* Get a backing file. */
-	if ((frp = file_add(new, cmdp->argv[0]->bp)) == NULL ||
+	INT2CHAR(sp, cmdp->argv[0]->bp, cmdp->argv[0]->len + 1, np, nlen);
+	if ((frp = file_add(new, np)) == NULL ||
 	    file_init(new, frp, NULL,
 	    (FL_ISSET(cmdp->iflags, E_C_FORCE) ? FS_FORCE : 0))) {
 		(void)vs_discard(new, NULL);
@@ -169,11 +174,11 @@
  * PUBLIC: int ex_prev __P((SCR *, EXCMD *));
  */
 int
-ex_prev(sp, cmdp)
-	SCR *sp;
-	EXCMD *cmdp;
+ex_prev(SCR *sp, EXCMD *cmdp)
 {
 	FREF *frp;
+	size_t wlen;
+	CHAR_T *wp;
 
 	if (sp->cargv == sp->argv) {
 		msgq(sp, M_ERR, "112|No previous files to edit");
@@ -181,7 +186,9 @@
 	}
 
 	if (F_ISSET(cmdp, E_NEWSCREEN)) {
-		if (argv_exp0(sp, cmdp, sp->cargv[-1], strlen(sp->cargv[-1])))
+		CHAR2INT(sp, sp->cargv[-1], strlen(sp->cargv[-1]) + 1,
+				   wp, wlen);
+		if (argv_exp0(sp, cmdp, wp, wlen - 1))
 			return (1);
 		return (ex_edit(sp, cmdp));
 	}
@@ -216,9 +223,7 @@
  * PUBLIC: int ex_rew __P((SCR *, EXCMD *));
  */
 int
-ex_rew(sp, cmdp)
-	SCR *sp;
-	EXCMD *cmdp;
+ex_rew(SCR *sp, EXCMD *cmdp)
 {
 	FREF *frp;
 
@@ -256,9 +261,7 @@
  * PUBLIC: int ex_args __P((SCR *, EXCMD *));
  */
 int
-ex_args(sp, cmdp)
-	SCR *sp;
-	EXCMD *cmdp;
+ex_args(SCR *sp, EXCMD *cmdp)
 {
 	GS *gp;
 	int cnt, col, len, sep;
@@ -299,14 +302,13 @@
  * PUBLIC: char **ex_buildargv __P((SCR *, EXCMD *, char *));
  */
 char **
-ex_buildargv(sp, cmdp, name)
-	SCR *sp;
-	EXCMD *cmdp;
-	char *name;
+ex_buildargv(SCR *sp, EXCMD *cmdp, char *name)
 {
 	ARGS **argv;
 	int argc;
 	char **ap, **s_argv;
+	char *np;
+	size_t nlen;
 
 	argc = cmdp == NULL ? 1 : cmdp->argc;
 	CALLOC(sp, s_argv, char **, argc + 1, sizeof(char *));
@@ -318,10 +320,11 @@
 			return (NULL);
 		++ap;
 	} else
-		for (argv = cmdp->argv; argv[0]->len != 0; ++ap, ++argv)
-			if ((*ap =
-			    v_strdup(sp, argv[0]->bp, argv[0]->len)) == NULL)
+		for (argv = cmdp->argv; argv[0]->len != 0; ++ap, ++argv) {
+			INT2CHAR(sp, argv[0]->bp, argv[0]->len, np, nlen);
+			if ((*ap = v_strdup(sp, np, nlen)) == NULL)
 				return (NULL);
+		}
 	*ap = NULL;
 	return (s_argv);
 }

Modified: trunk/contrib/nvi/ex/ex_argv.c
===================================================================
--- trunk/contrib/nvi/ex/ex_argv.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/ex/ex_argv.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -10,11 +10,12 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)ex_argv.c	10.26 (Berkeley) 9/20/96";
+static const char sccsid[] = "$Id: ex_argv.c,v 11.2 2012/10/09 23:00:29 zy Exp $";
 #endif /* not lint */
 
 #include <sys/types.h>
 #include <sys/queue.h>
+#include <sys/time.h>
 
 #include <bitstring.h>
 #include <ctype.h>
@@ -21,6 +22,7 @@
 #include <dirent.h>
 #include <errno.h>
 #include <limits.h>
+#include <pwd.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -31,9 +33,9 @@
 static int argv_alloc __P((SCR *, size_t));
 static int argv_comp __P((const void *, const void *));
 static int argv_fexp __P((SCR *, EXCMD *,
-	char *, size_t, char *, size_t *, char **, size_t *, int));
-static int argv_lexp __P((SCR *, EXCMD *, char *));
-static int argv_sexp __P((SCR *, char **, size_t *, size_t *));
+	CHAR_T *, size_t, CHAR_T *, size_t *, CHAR_T **, size_t *, int));
+static int argv_sexp __P((SCR *, CHAR_T **, size_t *, size_t *));
+static int argv_flt_user __P((SCR *, EXCMD *, CHAR_T *, size_t));
 
 /*
  * argv_init --
@@ -42,9 +44,7 @@
  * PUBLIC: int argv_init __P((SCR *, EXCMD *));
  */
 int
-argv_init(sp, excp)
-	SCR *sp;
-	EXCMD *excp;
+argv_init(SCR *sp, EXCMD *excp)
 {
 	EX_PRIVATE *exp;
 
@@ -61,20 +61,16 @@
  * argv_exp0 --
  *	Append a string to the argument list.
  *
- * PUBLIC: int argv_exp0 __P((SCR *, EXCMD *, char *, size_t));
+ * PUBLIC: int argv_exp0 __P((SCR *, EXCMD *, CHAR_T *, size_t));
  */
 int
-argv_exp0(sp, excp, cmd, cmdlen)
-	SCR *sp;
-	EXCMD *excp;
-	char *cmd;
-	size_t cmdlen;
+argv_exp0(SCR *sp, EXCMD *excp, CHAR_T *cmd, size_t cmdlen)
 {
 	EX_PRIVATE *exp;
 
 	exp = EXP(sp);
 	argv_alloc(sp, cmdlen);
-	memcpy(exp->args[exp->argsoff]->bp, cmd, cmdlen);
+	MEMCPY(exp->args[exp->argsoff]->bp, cmd, cmdlen);
 	exp->args[exp->argsoff]->bp[cmdlen] = '\0';
 	exp->args[exp->argsoff]->len = cmdlen;
 	++exp->argsoff;
@@ -88,26 +84,21 @@
  *	Do file name expansion on a string, and append it to the
  *	argument list.
  *
- * PUBLIC: int argv_exp1 __P((SCR *, EXCMD *, char *, size_t, int));
+ * PUBLIC: int argv_exp1 __P((SCR *, EXCMD *, CHAR_T *, size_t, int));
  */
 int
-argv_exp1(sp, excp, cmd, cmdlen, is_bang)
-	SCR *sp;
-	EXCMD *excp;
-	char *cmd;
-	size_t cmdlen;
-	int is_bang;
+argv_exp1(SCR *sp, EXCMD *excp, CHAR_T *cmd, size_t cmdlen, int is_bang)
 {
 	EX_PRIVATE *exp;
 	size_t blen, len;
-	char *bp, *p, *t;
+	CHAR_T *p, *t, *bp;
 
-	GET_SPACE_RET(sp, bp, blen, 512);
+	GET_SPACE_RETW(sp, bp, blen, 512);
 
 	len = 0;
 	exp = EXP(sp);
 	if (argv_fexp(sp, excp, cmd, cmdlen, bp, &len, &bp, &blen, is_bang)) {
-		FREE_SPACE(sp, bp, blen);
+		FREE_SPACEW(sp, bp, blen);
 		return (1);
 	}
 
@@ -114,7 +105,7 @@
 	/* If it's empty, we're done. */
 	if (len != 0) {
 		for (p = bp, t = bp + len; p < t; ++p)
-			if (!isblank(*p))
+			if (!cmdskip(*p))
 				break;
 		if (p == t)
 			goto ret;
@@ -123,7 +114,7 @@
 
 	(void)argv_exp0(sp, excp, bp, len);
 
-ret:	FREE_SPACE(sp, bp, blen);
+ret:	FREE_SPACEW(sp, bp, blen);
 	return (0);
 }
 
@@ -132,24 +123,20 @@
  *	Do file name and shell expansion on a string, and append it to
  *	the argument list.
  *
- * PUBLIC: int argv_exp2 __P((SCR *, EXCMD *, char *, size_t));
+ * PUBLIC: int argv_exp2 __P((SCR *, EXCMD *, CHAR_T *, size_t));
  */
 int
-argv_exp2(sp, excp, cmd, cmdlen)
-	SCR *sp;
-	EXCMD *excp;
-	char *cmd;
-	size_t cmdlen;
+argv_exp2(SCR *sp, EXCMD *excp, CHAR_T *cmd, size_t cmdlen)
 {
 	size_t blen, len, n;
 	int rval;
-	char *bp, *mp, *p;
+	CHAR_T *bp, *p;
 
-	GET_SPACE_RET(sp, bp, blen, 512);
+	GET_SPACE_RETW(sp, bp, blen, 512);
 
-#define	SHELLECHO	"echo "
-#define	SHELLOFFSET	(sizeof(SHELLECHO) - 1)
-	memcpy(bp, SHELLECHO, SHELLOFFSET);
+#define	SHELLECHO	L("echo ")
+#define	SHELLOFFSET	(SIZE(SHELLECHO) - 1)
+	MEMCPY(bp, SHELLECHO, SHELLOFFSET);
 	p = bp + SHELLOFFSET;
 	len = SHELLOFFSET;
 
@@ -175,28 +162,15 @@
 	 * but then, if your shell was csh, the above example will behave
 	 * differently in nvi than in vi.  If you want to get other characters
 	 * passed through to your shell, change the "meta" option.
-	 *
-	 * To avoid a function call per character, we do a first pass through
-	 * the meta characters looking for characters that aren't expected
-	 * to be there, and then we can ignore them in the user's argument.
 	 */
 	if (opts_empty(sp, O_SHELL, 1) || opts_empty(sp, O_SHELLMETA, 1))
 		n = 0;
 	else {
-		for (p = mp = O_STR(sp, O_SHELLMETA); *p != '\0'; ++p)
-			if (isblank(*p) || isalnum(*p))
-				break;
 		p = bp + SHELLOFFSET;
 		n = len - SHELLOFFSET;
-		if (*p != '\0') {
-			for (; n > 0; --n, ++p)
-				if (strchr(mp, *p) != NULL)
-					break;
-		} else
-			for (; n > 0; --n, ++p)
-				if (!isblank(*p) &&
-				    !isalnum(*p) && strchr(mp, *p) != NULL)
-					break;
+		for (; n > 0; --n, ++p)
+			if (IS_SHELLMETA(sp, *p))
+				break;
 	}
 
 	/*
@@ -204,13 +178,11 @@
 	 * it.  Unfortunately, this is comparatively slow.  Historically, it
 	 * didn't matter much, since users don't enter meta characters as part
 	 * of pathnames that frequently.  The addition of filename completion
-	 * broke that assumption because it's easy to use.  As a result, lots
-	 * folks have complained that the expansion code is too slow.  So, we
-	 * detect filename completion as a special case, and do it internally.
-	 * Note that this code assumes that the <asterisk> character is the
-	 * match-anything meta character.  That feels safe -- if anyone writes
-	 * a shell that doesn't follow that convention, I'd suggest giving them
-	 * a festive hot-lead enema.
+	 * broke that assumption because it's easy to use.  To increase the
+	 * completion performance, nvi used to have an internal routine to
+	 * handle "filename*".  However, the shell special characters does not
+	 * limit to "shellmeta", so such a hack breaks historic practice.
+	 * After it all, we split the completion logic out from here.
 	 */
 	switch (n) {
 	case 0:
@@ -218,13 +190,6 @@
 		len -= SHELLOFFSET;
 		rval = argv_exp3(sp, excp, p, len);
 		break;
-	case 1:
-		if (*p == '*') {
-			*p = '\0';
-			rval = argv_lexp(sp, excp, bp + SHELLOFFSET);
-			break;
-		}
-		/* FALLTHROUGH */
 	default:
 		if (argv_sexp(sp, &bp, &blen, &len)) {
 			rval = 1;
@@ -235,7 +200,7 @@
 		break;
 	}
 
-err:	FREE_SPACE(sp, bp, blen);
+err:	FREE_SPACEW(sp, bp, blen);
 	return (rval);
 }
 
@@ -244,25 +209,21 @@
  *	Take a string and break it up into an argv, which is appended
  *	to the argument list.
  *
- * PUBLIC: int argv_exp3 __P((SCR *, EXCMD *, char *, size_t));
+ * PUBLIC: int argv_exp3 __P((SCR *, EXCMD *, CHAR_T *, size_t));
  */
 int
-argv_exp3(sp, excp, cmd, cmdlen)
-	SCR *sp;
-	EXCMD *excp;
-	char *cmd;
-	size_t cmdlen;
+argv_exp3(SCR *sp, EXCMD *excp, CHAR_T *cmd, size_t cmdlen)
 {
 	EX_PRIVATE *exp;
 	size_t len;
 	int ch, off;
-	char *ap, *p;
+	CHAR_T *ap, *p;
 
 	for (exp = EXP(sp); cmdlen > 0; ++exp->argsoff) {
 		/* Skip any leading whitespace. */
 		for (; cmdlen > 0; --cmdlen, ++cmd) {
 			ch = *cmd;
-			if (!isblank(ch))
+			if (!cmdskip(ch))
 				break;
 		}
 		if (cmdlen == 0)
@@ -282,7 +243,7 @@
 			if (IS_ESCAPE(sp, excp, ch) && cmdlen > 1) {
 				++cmd;
 				--cmdlen;
-			} else if (isblank(ch))
+			} else if (cmdskip(ch))
 				break;
 		}
 
@@ -312,20 +273,99 @@
 }
 
 /*
+ * argv_flt_ex --
+ *	Filter the ex commands with a prefix, and append the results to
+ *	the argument list.
+ *
+ * PUBLIC: int argv_flt_ex __P((SCR *, EXCMD *, CHAR_T *, size_t));
+ */
+int
+argv_flt_ex(SCR *sp, EXCMD *excp, CHAR_T *cmd, size_t cmdlen)
+{
+	EX_PRIVATE *exp;
+	EXCMDLIST const *cp;
+	int off;
+	size_t len;
+
+	exp = EXP(sp);
+
+	for (off = exp->argsoff, cp = cmds; cp->name != NULL; ++cp) {
+		len = STRLEN(cp->name);
+		if (cmdlen > 0 &&
+		    (cmdlen > len || MEMCMP(cmd, cp->name, cmdlen)))
+			continue;
+
+		/* Copy the matched ex command name. */
+		argv_alloc(sp, len + 1);
+		MEMCPY(exp->args[exp->argsoff]->bp, cp->name, len + 1);
+		exp->args[exp->argsoff]->len = len;
+		++exp->argsoff;
+		excp->argv = exp->args;
+		excp->argc = exp->argsoff;
+	}
+
+	return (0);
+}
+
+/*
+ * argv_flt_user --
+ *	Filter the ~user list on the system with a prefix, and append
+ *	the results to the argument list.
+ */
+static int
+argv_flt_user(SCR *sp, EXCMD *excp, CHAR_T *uname, size_t ulen)
+{
+	EX_PRIVATE *exp;
+	struct passwd *pw;
+	int off;
+	char *np;
+	size_t len, nlen;
+
+	exp = EXP(sp);
+	off = exp->argsoff;
+
+	/* The input must come with a leading '~'. */
+	INT2CHAR(sp, uname + 1, ulen - 1, np, nlen);
+	if ((np = v_strdup(sp, np, nlen)) == NULL)
+		return (1);
+
+	setpwent();
+	while ((pw = getpwent()) != NULL) {
+		len = strlen(pw->pw_name);
+		if (nlen > 0 &&
+		    (nlen > len || memcmp(np, pw->pw_name, nlen)))
+			continue;
+
+		/* Copy '~' + the matched user name. */
+		CHAR2INT(sp, pw->pw_name, len + 1, uname, ulen);
+		argv_alloc(sp, ulen + 1);
+		exp->args[exp->argsoff]->bp[0] = '~';
+		MEMCPY(exp->args[exp->argsoff]->bp + 1, uname, ulen);
+		exp->args[exp->argsoff]->len = ulen;
+		++exp->argsoff;
+		excp->argv = exp->args;
+		excp->argc = exp->argsoff;
+	}
+	endpwent();
+	free(np);
+
+	qsort(exp->args + off, exp->argsoff - off, sizeof(ARGS *), argv_comp);
+	return (0);
+}
+
+/*
  * argv_fexp --
  *	Do file name and bang command expansion.
  */
 static int
-argv_fexp(sp, excp, cmd, cmdlen, p, lenp, bpp, blenp, is_bang)
-	SCR *sp;
-	EXCMD *excp;
-	char *cmd, *p, **bpp;
-	size_t cmdlen, *lenp, *blenp;
-	int is_bang;
+argv_fexp(SCR *sp, EXCMD *excp, CHAR_T *cmd, size_t cmdlen, CHAR_T *p, size_t *lenp, CHAR_T **bpp, size_t *blenp, int is_bang)
 {
 	EX_PRIVATE *exp;
-	char *bp, *t;
+	char *t;
 	size_t blen, len, off, tlen;
+	CHAR_T *bp;
+	CHAR_T *wp;
+	size_t wlen;
 
 	/* Replace file name characters. */
 	for (bp = *bpp, blen = *blenp, len = *lenp; cmdlen > 0; --cmdlen, ++cmd)
@@ -339,11 +379,11 @@
 				    "115|No previous command to replace \"!\"");
 				return (1);
 			}
-			len += tlen = strlen(exp->lastbcomm);
+			len += tlen = STRLEN(exp->lastbcomm);
 			off = p - bp;
-			ADD_SPACE_RET(sp, bp, blen, len);
+			ADD_SPACE_RETW(sp, bp, blen, len);
 			p = bp + off;
-			memcpy(p, exp->lastbcomm, tlen);
+			MEMCPY(p, exp->lastbcomm, tlen);
 			p += tlen;
 			F_SET(excp, E_MODIFY);
 			break;
@@ -356,10 +396,11 @@
 			tlen = strlen(t);
 			len += tlen;
 			off = p - bp;
-			ADD_SPACE_RET(sp, bp, blen, len);
+			ADD_SPACE_RETW(sp, bp, blen, len);
 			p = bp + off;
-			memcpy(p, t, tlen);
-			p += tlen;
+			CHAR2INT(sp, t, tlen, wp, wlen);
+			MEMCPY(p, wp, wlen);
+			p += wlen;
 			F_SET(excp, E_MODIFY);
 			break;
 		case '#':
@@ -370,10 +411,11 @@
 			}
 			len += tlen = strlen(t);
 			off = p - bp;
-			ADD_SPACE_RET(sp, bp, blen, len);
+			ADD_SPACE_RETW(sp, bp, blen, len);
 			p = bp + off;
-			memcpy(p, t, tlen);
-			p += tlen;
+			CHAR2INT(sp, t, tlen, wp, wlen);
+			MEMCPY(p, wp, wlen);
+			p += wlen;
 			F_SET(excp, E_MODIFY);
 			break;
 		case '\\':
@@ -392,7 +434,7 @@
 		default:
 ins_ch:			++len;
 			off = p - bp;
-			ADD_SPACE_RET(sp, bp, blen, len);
+			ADD_SPACE_RETW(sp, bp, blen, len);
 			p = bp + off;
 			*p++ = *cmd;
 		}
@@ -400,7 +442,7 @@
 	/* Nul termination. */
 	++len;
 	off = p - bp;
-	ADD_SPACE_RET(sp, bp, blen, len);
+	ADD_SPACE_RETW(sp, bp, blen, len);
 	p = bp + off;
 	*p = '\0';
 
@@ -416,9 +458,7 @@
  *	Make more space for arguments.
  */
 static int
-argv_alloc(sp, len)
-	SCR *sp;
-	size_t len;
+argv_alloc(SCR *sp, size_t len)
 {
 	ARGS *ap;
 	EX_PRIVATE *exp;
@@ -483,8 +523,7 @@
  * PUBLIC: int argv_free __P((SCR *));
  */
 int
-argv_free(sp)
-	SCR *sp;
+argv_free(SCR *sp)
 {
 	EX_PRIVATE *exp;
 	int off;
@@ -507,15 +546,14 @@
 }
 
 /*
- * argv_lexp --
+ * argv_flt_path --
  *	Find all file names matching the prefix and append them to the
- *	buffer.
+ *	argument list.
+ *
+ * PUBLIC: int argv_flt_path __P((SCR *, EXCMD *, CHAR_T *, size_t));
  */
-static int
-argv_lexp(sp, excp, path)
-	SCR *sp;
-	EXCMD *excp;
-	char *path;
+int
+argv_flt_path(SCR *sp, EXCMD *excp, CHAR_T *path, size_t plen)
 {
 	struct dirent *dp;
 	DIR *dirp;
@@ -522,74 +560,89 @@
 	EX_PRIVATE *exp;
 	int off;
 	size_t dlen, len, nlen;
-	char *dname, *name, *p;
+	CHAR_T *dname;
+	CHAR_T *p, *np, *n;
+	char *name, *tp, *epd = NULL;
+	CHAR_T *wp;
+	size_t wlen;
 
 	exp = EXP(sp);
 
 	/* Set up the name and length for comparison. */
-	if ((p = strrchr(path, '/')) == NULL) {
-		dname = ".";
+	if ((path = v_wstrdup(sp, path, plen)) == NULL)
+		return (1);
+	if ((p = STRRCHR(path, '/')) == NULL) {
+		if (*path == '~') {
+			int rc;
+			
+			/* Filter ~user list instead. */
+			rc = argv_flt_user(sp, excp, path, plen);
+			free(path);
+			return (rc);
+		}
+		dname = L(".");
 		dlen = 0;
-		name = path;
-	} else { 
+		np = path;
+	} else {
 		if (p == path) {
-			dname = "/";
+			dname = L("/");
 			dlen = 1;
 		} else {
 			*p = '\0';
 			dname = path;
-			dlen = strlen(path);
+			dlen = p - path;
 		}
-		name = p + 1;
+		np = p + 1;
 	}
-	nlen = strlen(name);
 
-	/*
-	 * XXX
-	 * We don't use the d_namlen field, it's not portable enough; we
-	 * assume that d_name is nul terminated, instead.
-	 */
-	if ((dirp = opendir(dname)) == NULL) {
-		msgq_str(sp, M_SYSERR, dname, "%s");
+	INT2CHAR(sp, dname, dlen + 1, tp, nlen);
+	if ((epd = expanduser(tp)) != NULL)
+		tp = epd;
+	if ((dirp = opendir(tp)) == NULL) {
+		free(epd);
+		free(path);
 		return (1);
 	}
+	free(epd);
+
+	INT2CHAR(sp, np, STRLEN(np), tp, nlen);
+	if ((name = v_strdup(sp, tp, nlen)) == NULL) {
+		free(path);
+		return (1);
+	}
+
 	for (off = exp->argsoff; (dp = readdir(dirp)) != NULL;) {
 		if (nlen == 0) {
 			if (dp->d_name[0] == '.')
 				continue;
-			len = strlen(dp->d_name);
+			len = dp->d_namlen;
 		} else {
-			len = strlen(dp->d_name);
+			len = dp->d_namlen;
 			if (len < nlen || memcmp(dp->d_name, name, nlen))
 				continue;
 		}
 
 		/* Directory + name + slash + null. */
-		argv_alloc(sp, dlen + len + 2);
-		p = exp->args[exp->argsoff]->bp;
+		CHAR2INT(sp, dp->d_name, len + 1, wp, wlen);
+		argv_alloc(sp, dlen + wlen + 1);
+		n = exp->args[exp->argsoff]->bp;
 		if (dlen != 0) {
-			memcpy(p, dname, dlen);
-			p += dlen;
+			MEMCPY(n, dname, dlen);
+			n += dlen;
 			if (dlen > 1 || dname[0] != '/')
-				*p++ = '/';
+				*n++ = '/';
+			exp->args[exp->argsoff]->len = dlen + 1;
 		}
-		memcpy(p, dp->d_name, len + 1);
-		exp->args[exp->argsoff]->len = dlen + len + 1;
+		MEMCPY(n, wp, wlen);
+		exp->args[exp->argsoff]->len += wlen - 1;
 		++exp->argsoff;
 		excp->argv = exp->args;
 		excp->argc = exp->argsoff;
 	}
 	closedir(dirp);
+	free(name);
+	free(path);
 
-	if (off == exp->argsoff) {
-		/*
-		 * If we didn't find a match, complain that the expansion
-		 * failed.  We can't know for certain that's the error, but
-		 * it's a good guess, and it matches historic practice. 
-		 */
-		msgq(sp, M_ERR, "304|Shell expansion failed");
-		return (1);
-	}
 	qsort(exp->args + off, exp->argsoff - off, sizeof(ARGS *), argv_comp);
 	return (0);
 }
@@ -599,10 +652,9 @@
  *	Alphabetic comparison.
  */
 static int
-argv_comp(a, b)
-	const void *a, *b;
+argv_comp(const void *a, const void *b)
 {
-	return (strcmp((char *)(*(ARGS **)a)->bp, (char *)(*(ARGS **)b)->bp));
+	return (STRCMP((*(ARGS **)a)->bp, (*(ARGS **)b)->bp));
 }
 
 /*
@@ -611,10 +663,7 @@
  *	a buffer.
  */
 static int
-argv_sexp(sp, bpp, blenp, lenp)
-	SCR *sp;
-	char **bpp;
-	size_t *blenp, *lenp;
+argv_sexp(SCR *sp, CHAR_T **bpp, size_t *blenp, size_t *lenp)
 {
 	enum { SEXP_ERR, SEXP_EXPANSION_ERR, SEXP_OK } rval;
 	FILE *ifp;
@@ -621,7 +670,10 @@
 	pid_t pid;
 	size_t blen, len;
 	int ch, std_output[2];
-	char *bp, *p, *sh, *sh_path;
+	CHAR_T *bp, *p;
+	char *sh, *sh_path;
+	char *np;
+	size_t nlen;
 
 	/* Secure means no shell access. */
 	if (O_ISSET(sp, O_SECURE)) {
@@ -689,7 +741,8 @@
 		 * XXX
 		 * Assume that all shells have -c.
 		 */
-		execl(sh_path, sh, "-c", bp, NULL);
+		INT2CHAR(sp, bp, STRLEN(bp)+1, np, nlen);
+		execl(sh_path, sh, "-c", np, (char *)NULL);
 		msgq_str(sp, M_SYSERR, sh_path, "118|Error: execl: %s");
 		_exit(127);
 	default:			/* Parent. */
@@ -707,9 +760,9 @@
 	 * shell that does that is broken.
 	 */
 	for (p = bp, len = 0, ch = EOF;
-	    (ch = getc(ifp)) != EOF; *p++ = ch, --blen, ++len)
+	    (ch = GETC(ifp)) != EOF; *p++ = ch, blen-=sizeof(CHAR_T), ++len)
 		if (blen < 5) {
-			ADD_SPACE_GOTO(sp, bp, *blenp, *blenp * 2);
+			ADD_SPACE_GOTOW(sp, bp, *blenp, *blenp * 2);
 			p = bp + len;
 			blen = *blenp - len;
 		}
@@ -744,7 +797,7 @@
 		rval = SEXP_EXPANSION_ERR;
 
 	for (p = bp; len; ++p, --len)
-		if (!isblank(*p))
+		if (!cmdskip(*p))
 			break;
 	if (len == 0)
 		rval = SEXP_EXPANSION_ERR;
@@ -754,3 +807,108 @@
 
 	return (rval == SEXP_OK ? 0 : 1);
 }
+
+/*
+ * argv_esc --
+ *	Escape a string into an ex and shell argument.
+ *
+ * PUBLIC: CHAR_T *argv_esc __P((SCR *, EXCMD *, CHAR_T *, size_t));
+ */
+CHAR_T *
+argv_esc(SCR *sp, EXCMD *excp, CHAR_T *str, size_t len)
+{
+	size_t blen, off;
+	CHAR_T *bp, *p;
+	int ch;
+
+	GET_SPACE_GOTOW(sp, bp, blen, len + 1);
+
+	/*
+	 * Leaving the first '~' unescaped causes the user to need a
+	 * "./" prefix to edit a file which really starts with a '~'.
+	 * However, the file completion happens to not work for these
+	 * files without the prefix.
+	 * 
+	 * All ex expansion characters, "!%#", are double escaped.
+	 */
+	for (p = bp; len > 0; ++str, --len) {
+		ch = *str;
+		off = p - bp;
+		if (blen / sizeof(CHAR_T) - off < 3) {
+			ADD_SPACE_GOTOW(sp, bp, blen, off + 3);
+			p = bp + off;
+		}
+		if (cmdskip(ch) || ch == '\n' ||
+		    IS_ESCAPE(sp, excp, ch))			/* Ex. */
+			*p++ = CH_LITERAL;
+		else switch (ch) {
+		case '~':					/* ~user. */
+			if (p != bp)
+				*p++ = '\\';
+			break;
+		case '+':					/* Ex +cmd. */
+			if (p == bp)
+				*p++ = '\\';
+			break;
+		case '!': case '%': case '#':			/* Ex exp. */
+			*p++ = '\\';
+			*p++ = '\\';
+			break;
+		case ',': case '-': case '.': case '/':		/* Safe. */
+		case ':': case '=': case '@': case '_':
+			break;
+		default:					/* Unsafe. */
+			if (isascii(ch) && !isalnum(ch))
+				*p++ = '\\';
+		}
+		*p++ = ch;
+	}
+	*p = '\0';
+
+	return bp;
+
+alloc_err:
+	return NULL;
+}
+
+/*
+ * argv_uesc --
+ *	Unescape an escaped ex and shell argument.
+ *
+ * PUBLIC: CHAR_T *argv_uesc __P((SCR *, EXCMD *, CHAR_T *, size_t));
+ */
+CHAR_T *
+argv_uesc(SCR *sp, EXCMD *excp, CHAR_T *str, size_t len)
+{
+	size_t blen;
+	CHAR_T *bp, *p;
+
+	GET_SPACE_GOTOW(sp, bp, blen, len + 1);
+
+	for (p = bp; len > 0; ++str, --len) {
+		if (IS_ESCAPE(sp, excp, *str)) {
+			if (--len < 1)
+				break;
+			++str;
+		} else if (*str == '\\') {
+			if (--len < 1)
+				break;
+			++str;
+
+			/* Check for double escaping. */
+			if (*str == '\\' && len > 1)
+				switch (str[1]) {
+				case '!': case '%': case '#':
+					++str;
+					--len;
+				}
+		}
+		*p++ = *str;
+	}
+	*p = '\0';
+
+	return bp;
+
+alloc_err:
+	return NULL;
+}

Modified: trunk/contrib/nvi/ex/ex_at.c
===================================================================
--- trunk/contrib/nvi/ex/ex_at.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/ex/ex_at.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -10,11 +10,12 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)ex_at.c	10.12 (Berkeley) 9/15/96";
+static const char sccsid[] = "$Id: ex_at.c,v 10.16 2001/06/25 15:19:14 skimo Exp $";
 #endif /* not lint */
 
 #include <sys/types.h>
 #include <sys/queue.h>
+#include <sys/time.h>
 
 #include <bitstring.h>
 #include <ctype.h>
@@ -34,9 +35,7 @@
  * PUBLIC: int ex_at __P((SCR *, EXCMD *));
  */
 int
-ex_at(sp, cmdp)
-	SCR *sp;
-	EXCMD *cmdp;
+ex_at(SCR *sp, EXCMD *cmdp)
 {
 	CB *cbp;
 	CHAR_T name;
@@ -43,8 +42,8 @@
 	EXCMD *ecp;
 	RANGE *rp;
 	TEXT *tp;
-	size_t len;
-	char *p;
+	size_t len = 0;
+	CHAR_T *p;
 
 	/*
 	 * !!!
@@ -84,7 +83,7 @@
 	 * means @ buffers are still useful in a multi-screen environment.
 	 */
 	CALLOC_RET(sp, ecp, EXCMD *, 1, sizeof(EXCMD));
-	CIRCLEQ_INIT(&ecp->rq);
+	TAILQ_INIT(ecp->rq);
 	CALLOC_RET(sp, rp, RANGE *, 1, sizeof(RANGE));
 	rp->start = cmdp->addr1.lno;
 	if (F_ISSET(cmdp, E_ADDR_DEF)) {
@@ -94,7 +93,7 @@
 		rp->stop = cmdp->addr2.lno;
 		FL_SET(ecp->agv_flags, AGV_AT);
 	}
-	CIRCLEQ_INSERT_HEAD(&ecp->rq, rp, q);
+	TAILQ_INSERT_HEAD(ecp->rq, rp, q);
 
 	/*
 	 * Buffers executed in ex mode or from the colon command line in vi
@@ -104,23 +103,22 @@
 	 * Build two copies of the command.  We need two copies because the
 	 * ex parser may step on the command string when it's parsing it.
 	 */
-	for (len = 0, tp = cbp->textq.cqh_last;
-	    tp != (void *)&cbp->textq; tp = tp->q.cqe_prev)
+	TAILQ_FOREACH_REVERSE(tp, cbp->textq, _texth, q)
 		len += tp->len + 1;
 
-	MALLOC_RET(sp, ecp->cp, char *, len * 2);
+	MALLOC_RET(sp, ecp->cp, CHAR_T *, len * 2 * sizeof(CHAR_T));
 	ecp->o_cp = ecp->cp;
 	ecp->o_clen = len;
 	ecp->cp[len] = '\0';
 
 	/* Copy the buffer into the command space. */
-	for (p = ecp->cp + len, tp = cbp->textq.cqh_last;
-	    tp != (void *)&cbp->textq; tp = tp->q.cqe_prev) {
-		memcpy(p, tp->lb, tp->len);
+	p = ecp->cp + len;
+	TAILQ_FOREACH_REVERSE(tp, cbp->textq, _texth, q) {
+		MEMCPY(p, tp->lb, tp->len);
 		p += tp->len;
 		*p++ = '\n';
 	}
 
-	LIST_INSERT_HEAD(&sp->gp->ecq, ecp, q);
+	SLIST_INSERT_HEAD(sp->gp->ecq, ecp, q);
 	return (0);
 }

Modified: trunk/contrib/nvi/ex/ex_bang.c
===================================================================
--- trunk/contrib/nvi/ex/ex_bang.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/ex/ex_bang.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -10,7 +10,7 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)ex_bang.c	10.33 (Berkeley) 9/23/96";
+static const char sccsid[] = "$Id: ex_bang.c,v 10.36 2001/06/25 15:19:14 skimo Exp $";
 #endif /* not lint */
 
 #include <sys/types.h>
@@ -47,9 +47,7 @@
  * PUBLIC: int ex_bang __P((SCR *, EXCMD *));
  */
 int
-ex_bang(sp, cmdp)
-	SCR *sp;
-	EXCMD *cmdp;
+ex_bang(SCR *sp, EXCMD *cmdp)
 {
 	enum filtertype ftype;
 	ARGS *ap;
@@ -58,6 +56,8 @@
 	recno_t lno;
 	int rval;
 	const char *msg;
+	char *np;
+	size_t nlen;
 
 	ap = cmdp->argv[0];
 	if (ap->len == 0) {
@@ -69,7 +69,7 @@
 	exp = EXP(sp);
 	if (exp->lastbcomm != NULL)
 		free(exp->lastbcomm);
-	if ((exp->lastbcomm = strdup(ap->bp)) == NULL) {
+	if ((exp->lastbcomm = v_wstrdup(sp, ap->bp, ap->len)) == NULL) {
 		msgq(sp, M_SYSERR, NULL);
 		return (1);
 	}
@@ -88,7 +88,7 @@
 		if (F_ISSET(sp, SC_VI))
 			vs_update(sp, "!", ap->bp);
 		else {
-			(void)ex_printf(sp, "!%s\n", ap->bp);
+			(void)ex_printf(sp, "!"WS"\n", ap->bp);
 			(void)ex_fflush(sp);
 		}
 	}
@@ -112,8 +112,9 @@
 				    NULL);
 
 		/* If we're still in a vi screen, move out explicitly. */
+		INT2CHAR(sp, ap->bp, ap->len+1, np, nlen);
 		(void)ex_exec_proc(sp,
-		    cmdp, ap->bp, msg, !F_ISSET(sp, SC_EX | SC_SCR_EXWROTE));
+		    cmdp, np, msg, !F_ISSET(sp, SC_EX | SC_SCR_EXWROTE));
 	}
 
 	/*

Modified: trunk/contrib/nvi/ex/ex_cd.c
===================================================================
--- trunk/contrib/nvi/ex/ex_cd.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/ex/ex_cd.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -10,11 +10,11 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)ex_cd.c	10.10 (Berkeley) 8/12/96";
+static const char sccsid[] = "$Id: ex_cd.c,v 10.13 2012/04/12 06:28:27 zy Exp $";
 #endif /* not lint */
 
-#include <sys/param.h>
 #include <sys/queue.h>
+#include <sys/time.h>
 
 #include <bitstring.h>
 #include <errno.h>
@@ -34,15 +34,14 @@
  * PUBLIC: int ex_cd __P((SCR *, EXCMD *));
  */
 int
-ex_cd(sp, cmdp)
-	SCR *sp;
-	EXCMD *cmdp;
+ex_cd(SCR *sp, EXCMD *cmdp)
 {
 	struct passwd *pw;
 	ARGS *ap;
-	CHAR_T savech;
-	char *dir, *p, *t;	/* XXX: END OF THE STACK, DON'T TRUST GETCWD. */
-	char buf[MAXPATHLEN * 2];
+	int savech;
+	char *dir, *p, *t;
+	char *buf;
+	size_t dlen;
 
 	/*
 	 * !!!
@@ -71,7 +70,8 @@
 		}
 		break;
 	case 1:
-		dir = cmdp->argv[0]->bp;
+		INT2CHAR(sp, cmdp->argv[0]->bp, cmdp->argv[0]->len + 1, 
+			 dir, dlen);
 		break;
 	default:
 		abort();
@@ -91,9 +91,9 @@
 	 */
 	if (cmdp->argc == 0 ||
 	    (ap = cmdp->argv[0])->bp[0] == '/' ||
-	    ap->len == 1 && ap->bp[0] == '.' ||
-	    ap->len >= 2 && ap->bp[0] == '.' && ap->bp[1] == '.' &&
-	    (ap->bp[2] == '/' || ap->bp[2] == '\0'))
+	    (ap->len == 1 && ap->bp[0] == '.') ||
+	    (ap->len >= 2 && ap->bp[0] == '.' && ap->bp[1] == '.' &&
+	    (ap->bp[2] == '/' || ap->bp[2] == '\0')))
 		goto err;
 
 	/* Try the O_CDPATH option values. */
@@ -100,24 +100,26 @@
 	for (p = t = O_STR(sp, O_CDPATH);; ++p)
 		if (*p == '\0' || *p == ':') {
 			/*
-			 * Empty strings specify ".".  The only way to get an
-			 * empty string is a leading colon, colons in a row,
-			 * or a trailing colon.  Or, to put it the other way,
-			 * if the length is 1 or less, then we're dealing with
-			 * ":XXX", "XXX::XXXX" , "XXX:", or "".  Since we've
-			 * already tried dot, we ignore tham all.
+			 * Ignore the empty strings and ".", since we've already
+			 * tried the current directory.
 			 */
-			if (t < p - 1) {
+			if (t < p && (p - t != 1 || *t != '.')) {
 				savech = *p;
 				*p = '\0';
-				(void)snprintf(buf,
-				    sizeof(buf), "%s/%s", t, dir);
+				if ((buf = join(t, dir)) == NULL) {
+					msgq(sp, M_SYSERR, NULL);
+					return (1);
+				}
 				*p = savech;
 				if (!chdir(buf)) {
-					if (getcwd(buf, sizeof(buf)) != NULL)
+					free(buf);
+					if ((buf = getcwd(NULL, 0)) != NULL) {
 		msgq_str(sp, M_INFO, buf, "122|New current directory: %s");
+						free(buf);
+					}
 					return (0);
 				}
+				free(buf);
 			}
 			t = p + 1;
 			if (*p == '\0')

Modified: trunk/contrib/nvi/ex/ex_cmd.c
===================================================================
--- trunk/contrib/nvi/ex/ex_cmd.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/ex/ex_cmd.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -10,11 +10,12 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)ex_cmd.c	10.20 (Berkeley) 10/10/96";
+static const char sccsid[] = "$Id: ex_cmd.c,v 10.26 2011/07/14 15:11:16 zy Exp $";
 #endif /* not lint */
 
 #include <sys/types.h>
 #include <sys/queue.h>
+#include <sys/time.h>
 
 #include <bitstring.h>
 #include <limits.h>
@@ -50,92 +51,92 @@
  */
 EXCMDLIST const cmds[] = {
 /* C_SCROLL */
-	{"\004",	ex_pr,		E_ADDR2,
+	{L("\004"),	ex_pr,		E_ADDR2,
 	    "",
 	    "^D",
 	    "scroll lines"},
 /* C_BANG */
-	{"!",		ex_bang,	E_ADDR2_NONE | E_SECURE,
+	{L("!"),		ex_bang,	E_ADDR2_NONE|E_SECURE,
 	    "S",
 	    "[line [,line]] ! command",
 	    "filter lines through commands or run commands"},
 /* C_HASH */
-	{"#",		ex_number,	E_ADDR2|E_CLRFLAG,
+	{L("#"),		ex_number,	E_ADDR2|E_CLRFLAG,
 	    "ca1",
 	    "[line [,line]] # [count] [l]",
 	    "display numbered lines"},
 /* C_SUBAGAIN */
-	{"&",		ex_subagain,	E_ADDR2,
+	{L("&"),		ex_subagain,	E_ADDR2|E_ADDR_ZERO,
 	    "s",
 	    "[line [,line]] & [cgr] [count] [#lp]",
-	    "repeat the last substitution"},
+	    "repeat the last subsitution"},
 /* C_STAR */
-	{"*",		ex_at,		0,
+	{L("*"),		ex_at,		0,
 	    "b",
 	    "* [buffer]",
 	    "execute a buffer"},
 /* C_SHIFTL */
-	{"<",		ex_shiftl,	E_ADDR2|E_AUTOPRINT,
+	{L("<"),		ex_shiftl,	E_ADDR2|E_AUTOPRINT,
 	    "ca1",
 	    "[line [,line]] <[<...] [count] [flags]",
 	    "shift lines left"},
 /* C_EQUAL */
-	{"=",		ex_equal,	E_ADDR1|E_ADDR_ZERO|E_ADDR_ZERODEF,
+	{L("="),		ex_equal,	E_ADDR1|E_ADDR_ZERO|E_ADDR_ZERODEF,
 	    "1",
 	    "[line] = [flags]",
 	    "display line number"},
 /* C_SHIFTR */
-	{">",		ex_shiftr,	E_ADDR2|E_AUTOPRINT,
+	{L(">"),		ex_shiftr,	E_ADDR2|E_AUTOPRINT,
 	    "ca1",
 	    "[line [,line]] >[>...] [count] [flags]",
 	    "shift lines right"},
 /* C_AT */
-	{"@",		ex_at,		E_ADDR2,
+	{L("@"),		ex_at,		E_ADDR2,
 	    "b",
 	    "@ [buffer]",
 	    "execute a buffer"},
 /* C_APPEND */
-	{"append",	ex_append,	E_ADDR1|E_ADDR_ZERO|E_ADDR_ZERODEF,
+	{L("append"),	ex_append,	E_ADDR1|E_ADDR_ZERO|E_ADDR_ZERODEF,
 	    "!",
 	    "[line] a[ppend][!]",
 	    "append input to a line"},
 /* C_ABBR */
-	{"abbreviate", 	ex_abbr,	0,
+	{L("abbreviate"), 	ex_abbr,	0,
 	    "W",
 	    "ab[brev] [word replace]",
 	    "specify an input abbreviation"},
 /* C_ARGS */
-	{"args",	ex_args,	0,
+	{L("args"),	ex_args,	0,
 	    "",
 	    "ar[gs]",
 	    "display file argument list"},
 /* C_BG */
-	{"bg",		ex_bg,		E_VIONLY,
+	{L("bg"),		ex_bg,		E_VIONLY,
 	    "",
 	    "bg",
 	    "put a foreground screen into the background"},
 /* C_CHANGE */
-	{"change",	ex_change,	E_ADDR2|E_ADDR_ZERODEF,
+	{L("change"),	ex_change,	E_ADDR2|E_ADDR_ZERODEF,
 	    "!ca",
 	    "[line [,line]] c[hange][!] [count]",
 	    "change lines to input"},
 /* C_CD */
-	{"cd",		ex_cd,		0,
+	{L("cd"),		ex_cd,		0,
 	    "!f1o",
 	    "cd[!] [directory]",
 	    "change the current directory"},
 /* C_CHDIR */
-	{"chdir",	ex_cd,		0,
+	{L("chdir"),	ex_cd,		0,
 	    "!f1o",
 	    "chd[ir][!] [directory]",
 	    "change the current directory"},
 /* C_COPY */
-	{"copy",	ex_copy,	E_ADDR2|E_AUTOPRINT,
+	{L("copy"),	ex_copy,	E_ADDR2|E_AUTOPRINT,
 	    "l1",
 	    "[line [,line]] co[py] line [flags]",
 	    "copy lines elsewhere in the file"},
 /* C_CSCOPE */
-	{"cscope",      ex_cscope,      0,
+	{L("cscope"),      ex_cscope,      0,
 	    "!s",
 	    "cs[cope] command [args]",
 	    "create a set of tags using a cscope command"},
@@ -145,170 +146,151 @@
  * in ex_cmd() (the ex parser).  Read through the comments there, first.
  */
 /* C_DELETE */
-	{"delete",	ex_delete,	E_ADDR2|E_AUTOPRINT,
+	{L("delete"),	ex_delete,	E_ADDR2|E_AUTOPRINT,
 	    "bca1",
 	    "[line [,line]] d[elete][flags] [buffer] [count] [flags]",
 	    "delete lines from the file"},
 /* C_DISPLAY */
-	{"display",	ex_display,	0,
+	{L("display"),	ex_display,	0,
 	    "w1r",
 	    "display b[uffers] | c[onnections] | s[creens] | t[ags]",
 	    "display buffers, connections, screens or tags"},
 /* C_EDIT */
-	{"edit",	ex_edit,	E_NEWSCREEN,
+	{L("edit"),	ex_edit,	E_NEWSCREEN,
 	    "f1o",
 	    "[Ee][dit][!] [+cmd] [file]",
 	    "begin editing another file"},
 /* C_EX */
-	{"ex",		ex_edit,	E_NEWSCREEN,
+	{L("ex"),		ex_edit,	E_NEWSCREEN,
 	    "f1o",
 	    "[Ee]x[!] [+cmd] [file]",
 	    "begin editing another file"},
 /* C_EXUSAGE */
-	{"exusage",	ex_usage,	0,
+	{L("exusage"),	ex_usage,	0,
 	    "w1o",
 	    "[exu]sage [command]",
 	    "display ex command usage statement"},
 /* C_FILE */
-	{"file",	ex_file,	0,
+	{L("file"),	ex_file,	0,
 	    "f1o",
 	    "f[ile] [name]",
 	    "display (and optionally set) file name"},
 /* C_FG */
-	{"fg",		ex_fg,		E_NEWSCREEN|E_VIONLY,
+	{L("fg"),		ex_fg,		E_NEWSCREEN|E_VIONLY,
 	    "f1o",
 	    "[Ff]g [file]",
 	    "bring a backgrounded screen into the foreground"},
 /* C_GLOBAL */
-	{"global",	ex_global,	E_ADDR2_ALL,
+	{L("global"),	ex_global,	E_ADDR2_ALL,
 	    "!s",
 	    "[line [,line]] g[lobal][!] [;/]RE[;/] [commands]",
 	    "execute a global command on lines matching an RE"},
 /* C_HELP */
-	{"help",	ex_help,	0,
+	{L("help"),	ex_help,	0,
 	    "",
 	    "he[lp]",
 	    "display help statement"},
 /* C_INSERT */
-	{"insert",	ex_insert,	E_ADDR1|E_ADDR_ZERO|E_ADDR_ZERODEF,
+	{L("insert"),	ex_insert,	E_ADDR1|E_ADDR_ZERO|E_ADDR_ZERODEF,
 	    "!",
 	    "[line] i[nsert][!]",
 	    "insert input before a line"},
 /* C_JOIN */
-	{"join",	ex_join,	E_ADDR2|E_AUTOPRINT,
+	{L("join"),	ex_join,	E_ADDR2|E_AUTOPRINT,
 	    "!ca1",
 	    "[line [,line]] j[oin][!] [count] [flags]",
 	    "join lines into a single line"},
 /* C_K */
-	{"k",		ex_mark,	E_ADDR1,
+	{L("k"),		ex_mark,	E_ADDR1,
 	    "w1r",
 	    "[line] k key",
 	    "mark a line position"},
 /* C_LIST */
-	{"list",	ex_list,	E_ADDR2|E_CLRFLAG,
+	{L("list"),	ex_list,	E_ADDR2|E_CLRFLAG,
 	    "ca1",
 	    "[line [,line]] l[ist] [count] [#]",
 	    "display lines in an unambiguous form"},
 /* C_MOVE */
-	{"move",	ex_move,	E_ADDR2|E_AUTOPRINT,
+	{L("move"),	ex_move,	E_ADDR2|E_AUTOPRINT,
 	    "l",
 	    "[line [,line]] m[ove] line",
 	    "move lines elsewhere in the file"},
 /* C_MARK */
-	{"mark",	ex_mark,	E_ADDR1,
+	{L("mark"),	ex_mark,	E_ADDR1,
 	    "w1r",
 	    "[line] ma[rk] key",
 	    "mark a line position"},
 /* C_MAP */
-	{"map",		ex_map,		0,
+	{L("map"),		ex_map,		0,
 	    "!W",
 	    "map[!] [keys replace]",
 	    "map input or commands to one or more keys"},
 /* C_MKEXRC */
-	{"mkexrc",	ex_mkexrc,	0,
+	{L("mkexrc"),	ex_mkexrc,	0,
 	    "!f1r",
 	    "mkexrc[!] file",
 	    "write a .exrc file"},
 /* C_NEXT */
-	{"next",	ex_next,	E_NEWSCREEN,
+	{L("next"),	ex_next,	E_NEWSCREEN,
 	    "!fN",
 	    "[Nn][ext][!] [+cmd] [file ...]",
 	    "edit (and optionally specify) the next file"},
 /* C_NUMBER */
-	{"number",	ex_number,	E_ADDR2|E_CLRFLAG,
+	{L("number"),	ex_number,	E_ADDR2|E_CLRFLAG,
 	    "ca1",
 	    "[line [,line]] nu[mber] [count] [l]",
 	    "change display to number lines"},
 /* C_OPEN */
-	{"open",	ex_open,	E_ADDR1,
+	{L("open"),	ex_open,	E_ADDR1,
 	    "s",
 	    "[line] o[pen] [/RE/] [flags]",
 	    "enter \"open\" mode (not implemented)"},
 /* C_PRINT */
-	{"print",	ex_pr,		E_ADDR2|E_CLRFLAG,
+	{L("print"),	ex_pr,		E_ADDR2|E_CLRFLAG,
 	    "ca1",
 	    "[line [,line]] p[rint] [count] [#l]",
 	    "display lines"},
-/* C_PERLCMD */
-	{"perl",	ex_perl,	E_ADDR2_ALL|E_ADDR_ZERO|
-					    E_ADDR_ZERODEF|E_SECURE,
-	    "s",
-	    "pe[rl] cmd",
-	    "run the perl interpreter with the command"},
-/* C_PERLDOCMD */
-	{"perldo",	ex_perl,	E_ADDR2_ALL|E_ADDR_ZERO|
-					    E_ADDR_ZERODEF|E_SECURE,
-	    "s",
-	    "perld[o] cmd",
-	    "run the perl interpreter with the command, on each line"},
 /* C_PRESERVE */
-	{"preserve",	ex_preserve,	0,
+	{L("preserve"),	ex_preserve,	0,
 	    "",
 	    "pre[serve]",
 	    "preserve an edit session for recovery"},
 /* C_PREVIOUS */
-	{"previous",	ex_prev,	E_NEWSCREEN,
+	{L("previous"),	ex_prev,	E_NEWSCREEN,
 	    "!",
 	    "[Pp]rev[ious][!]",
 	    "edit the previous file in the file argument list"},
 /* C_PUT */
-	{"put",		ex_put,	
+	{L("put"),		ex_put,	
 	    E_ADDR1|E_AUTOPRINT|E_ADDR_ZERO|E_ADDR_ZERODEF,
 	    "b",
 	    "[line] pu[t] [buffer]",
 	    "append a cut buffer to the line"},
 /* C_QUIT */
-	{"quit",	ex_quit,	0,
+	{L("quit"),	ex_quit,	0,
 	    "!",
 	    "q[uit][!]",
 	    "exit ex/vi"},
 /* C_READ */
-	{"read",	ex_read,	E_ADDR1|E_ADDR_ZERO|E_ADDR_ZERODEF,
+	{L("read"),	ex_read,	E_ADDR1|E_ADDR_ZERO|E_ADDR_ZERODEF,
 	    "s",
 	    "[line] r[ead] [!cmd | [file]]",
 	    "append input from a command or file to the line"},
 /* C_RECOVER */
-	{"recover",	ex_recover,	0,
+	{L("recover"),	ex_recover,	0,
 	    "!f1r",
 	    "recover[!] file",
 	    "recover a saved file"},
 /* C_RESIZE */
-	{"resize",	ex_resize,	E_VIONLY,
+	{L("resize"),	ex_resize,	E_VIONLY,
 	    "c+",
 	    "resize [+-]rows",
 	    "grow or shrink the current screen"},
 /* C_REWIND */
-	{"rewind",	ex_rew,		0,
+	{L("rewind"),	ex_rew,		0,
 	    "!",
 	    "rew[ind][!]",
 	    "re-edit all the files in the file argument list"},
-#ifdef GTAGS
-/* C_RTAG */
-	{"rtag",	ex_rtag_push,	E_NEWSCREEN,
-	    "!w1o",
-	    "[Rr]ta[g][!] [string]",
-	    "edit the file containing the tag"},
-#endif
 /*
  * !!!
  * Adding new commands starting with 's' may break the substitute command code
@@ -315,148 +297,147 @@
  * in ex_cmd() (the ex parser).  Read through the comments there, first.
  */
 /* C_SUBSTITUTE */
-	{"s",		ex_s,		E_ADDR2,
+	{L("s"),		ex_s,		E_ADDR2|E_ADDR_ZERO,
 	    "s",
 	    "[line [,line]] s [[/;]RE[/;]repl[/;] [cgr] [count] [#lp]]",
 	    "substitute on lines matching an RE"},
 /* C_SCRIPT */
-	{"script",	ex_script,	E_SECURE,
+	{L("script"),	ex_script,	E_SECURE,
 	    "!f1o",
 	    "sc[ript][!] [file]",
 	    "run a shell in a screen"},
 /* C_SET */
-	{"set",		ex_set,		0,
+	{L("set"),		ex_set,		0,
 	    "wN",
 	    "se[t] [option[=[value]]...] [nooption ...] [option? ...] [all]",
 	    "set options (use \":set all\" to see all options)"},
 /* C_SHELL */
-	{"shell",	ex_shell,	E_SECURE,
+	{L("shell"),	ex_shell,	E_SECURE,
 	    "",
 	    "sh[ell]",
 	    "suspend editing and run a shell"},
 /* C_SOURCE */
-	{"source",	ex_source,	0,
+	{L("source"),	ex_source,	0,
 	    "f1r",
 	    "so[urce] file",
 	    "read a file of ex commands"},
 /* C_STOP */
-	{"stop",	ex_stop,	E_SECURE,
+	{L("stop"),	ex_stop,	E_SECURE,
 	    "!",
 	    "st[op][!]",
 	    "suspend the edit session"},
 /* C_SUSPEND */
-	{"suspend",	ex_stop,	E_SECURE,
+	{L("suspend"),	ex_stop,	E_SECURE,
 	    "!",
 	    "su[spend][!]",
 	    "suspend the edit session"},
 /* C_T */
-	{"t",		ex_copy,	E_ADDR2|E_AUTOPRINT,
+	{L("t"),		ex_copy,	E_ADDR2|E_AUTOPRINT,
 	    "l1",
 	    "[line [,line]] t line [flags]",
 	    "copy lines elsewhere in the file"},
 /* C_TAG */
-	{"tag",		ex_tag_push,	E_NEWSCREEN,
+	{L("tag"),		ex_tag_push,	E_NEWSCREEN,
 	    "!w1o",
 	    "[Tt]a[g][!] [string]",
 	    "edit the file containing the tag"},
 /* C_TAGNEXT */
-	{"tagnext",	ex_tag_next,	0,
+	{L("tagnext"),	ex_tag_next,	0,
 	    "!",
 	    "tagn[ext][!]",
 	    "move to the next tag"},
 /* C_TAGPOP */
-	{"tagpop",	ex_tag_pop,	0,
+	{L("tagpop"),	ex_tag_pop,	0,
 	    "!w1o",
 	    "tagp[op][!] [number | file]",
 	    "return to the previous group of tags"},
 /* C_TAGPREV */
-	{"tagprev",	ex_tag_prev,	0,
+	{L("tagprev"),	ex_tag_prev,	0,
 	    "!",
 	    "tagpr[ev][!]",
 	    "move to the previous tag"},
 /* C_TAGTOP */
-	{"tagtop",	ex_tag_top,	0,
+	{L("tagtop"),	ex_tag_top,	0,
 	    "!",
 	    "tagt[op][!]",
 	    "discard all tags"},
-/* C_TCLCMD */
-	{"tcl",		ex_tcl,		E_ADDR2_ALL|E_ADDR_ZERO|
-					    E_ADDR_ZERODEF|E_SECURE,
-	    "s",
-	    "tc[l] cmd",
-	    "run the tcl interpreter with the command"},
 /* C_UNDO */
-	{"undo",	ex_undo,	E_AUTOPRINT,
+	{L("undo"),	ex_undo,	E_AUTOPRINT,
 	    "",
 	    "u[ndo]",
 	    "undo the most recent change"},
 /* C_UNABBREVIATE */
-	{"unabbreviate",ex_unabbr,	0,
+	{L("unabbreviate"),ex_unabbr,	0,
 	    "w1r",
 	    "una[bbrev] word",
 	    "delete an abbreviation"},
 /* C_UNMAP */
-	{"unmap",	ex_unmap,	0,
+	{L("unmap"),	ex_unmap,	0,
 	    "!w1r",
 	    "unm[ap][!] word",
 	    "delete an input or command map"},
 /* C_V */
-	{"v",		ex_v,		E_ADDR2_ALL,
+	{L("v"),		ex_v,		E_ADDR2_ALL,
 	    "s",
 	    "[line [,line]] v [;/]RE[;/] [commands]",
 	    "execute a global command on lines NOT matching an RE"},
 /* C_VERSION */
-	{"version",	ex_version,	0,
+	{L("version"),	ex_version,	0,
 	    "",
 	    "version",
 	    "display the program version information"},
 /* C_VISUAL_EX */
-	{"visual",	ex_visual,	E_ADDR1|E_ADDR_ZERODEF,
+	{L("visual"),	ex_visual,	E_ADDR1|E_ADDR_ZERODEF,
 	    "2c11",
 	    "[line] vi[sual] [-|.|+|^] [window_size] [flags]",
 	    "enter visual (vi) mode from ex mode"},
 /* C_VISUAL_VI */
-	{"visual",	ex_edit,	E_NEWSCREEN,
+	{L("visual"),	ex_edit,	E_NEWSCREEN,
 	    "f1o",
 	    "[Vv]i[sual][!] [+cmd] [file]",
 	    "edit another file (from vi mode only)"},
 /* C_VIUSAGE */
-	{"viusage",	ex_viusage,	0,
+	{L("viusage"),	ex_viusage,	0,
 	    "w1o",
 	    "[viu]sage [key]",
 	    "display vi key usage statement"},
+/* C_VSPLIT */
+	{L("vsplit"),	ex_edit,	E_VIONLY,
+	    "f1o",
+	    "vs[plit] [+cmd] [file]",
+	    "split the current screen vertically"},
 /* C_WRITE */
-	{"write",	ex_write,	E_ADDR2_ALL|E_ADDR_ZERODEF,
+	{L("write"),	ex_write,	E_ADDR2_ALL|E_ADDR_ZERODEF,
 	    "!s",
 	    "[line [,line]] w[rite][!] [ !cmd | [>>] [file]]",
 	    "write the file"},
 /* C_WN */
-	{"wn",		ex_wn,		E_ADDR2_ALL|E_ADDR_ZERODEF,
+	{L("wn"),		ex_wn,		E_ADDR2_ALL|E_ADDR_ZERODEF,
 	    "!s",
 	    "[line [,line]] wn[!] [>>] [file]",
 	    "write the file and switch to the next file"},
 /* C_WQ */
-	{"wq",		ex_wq,		E_ADDR2_ALL|E_ADDR_ZERODEF,
+	{L("wq"),		ex_wq,		E_ADDR2_ALL|E_ADDR_ZERODEF,
 	    "!s",
 	    "[line [,line]] wq[!] [>>] [file]",
 	    "write the file and exit"},
 /* C_XIT */
-	{"xit",		ex_xit,		E_ADDR2_ALL|E_ADDR_ZERODEF,
+	{L("xit"),		ex_xit,		E_ADDR2_ALL|E_ADDR_ZERODEF,
 	    "!f1o",
 	    "[line [,line]] x[it][!] [file]",
 	    "exit"},
 /* C_YANK */
-	{"yank",	ex_yank,	E_ADDR2,
+	{L("yank"),	ex_yank,	E_ADDR2,
 	    "bca",
 	    "[line [,line]] ya[nk] [buffer] [count]",
 	    "copy lines to a cut buffer"},
 /* C_Z */
-	{"z",		ex_z,		E_ADDR1,
+	{L("z"),		ex_z,		E_ADDR1,
 	    "3c01",
 	    "[line] z [-|.|+|^|=] [count] [flags]",
 	    "display different screens of the file"},
 /* C_SUBTILDE */
-	{"~",		ex_subtilde,	E_ADDR2,
+	{L("~"),		ex_subtilde,	E_ADDR2|E_ADDR_ZERO,
 	    "s",
 	    "[line [,line]] ~ [cgr] [count] [#lp]",
 	    "replace previous RE with previous replacement string,"},

Modified: trunk/contrib/nvi/ex/ex_cscope.c
===================================================================
--- trunk/contrib/nvi/ex/ex_cscope.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/ex/ex_cscope.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -10,14 +10,12 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)ex_cscope.c	10.13 (Berkeley) 9/15/96";
+static const char sccsid[] = "$Id: ex_cscope.c,v 10.25 2012/10/04 09:23:03 zy Exp $";
 #endif /* not lint */
 
-#include <sys/param.h>
-#include <sys/types.h>		/* XXX: param.h may not have included types.h */
+#include <sys/types.h>
 #include <sys/queue.h>
 #include <sys/stat.h>
-#include <sys/time.h>
 #include <sys/wait.h>
 
 #include <bitstring.h>
@@ -25,6 +23,7 @@
 #include <errno.h>
 #include <fcntl.h>
 #include <limits.h>
+#include <signal.h>
 #include <stddef.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -62,15 +61,15 @@
       s: find all uses of name\n\
       t: find assignments to name"
 
-static int cscope_add __P((SCR *, EXCMD *, char *));
-static int cscope_find __P((SCR *, EXCMD*, char *));
-static int cscope_help __P((SCR *, EXCMD *, char *));
-static int cscope_kill __P((SCR *, EXCMD *, char *));
-static int cscope_reset __P((SCR *, EXCMD *, char *));
+static int cscope_add __P((SCR *, EXCMD *, CHAR_T *));
+static int cscope_find __P((SCR *, EXCMD*, CHAR_T *));
+static int cscope_help __P((SCR *, EXCMD *, CHAR_T *));
+static int cscope_kill __P((SCR *, EXCMD *, CHAR_T *));
+static int cscope_reset __P((SCR *, EXCMD *, CHAR_T *));
 
 typedef struct _cc {
 	char	 *name;
-	int	(*function) __P((SCR *, EXCMD *, char *));
+	int	(*function) __P((SCR *, EXCMD *, CHAR_T *));
 	char	 *help_msg;
 	char	 *usage_msg;
 } CC;
@@ -108,14 +107,15 @@
  * PUBLIC: int ex_cscope __P((SCR *, EXCMD *));
  */
 int
-ex_cscope(sp, cmdp)
-	SCR *sp;
-	EXCMD *cmdp;
+ex_cscope(SCR *sp, EXCMD *cmdp)
 {
 	CC const *ccp;
 	EX_PRIVATE *exp;
 	int i;
-	char *cmd, *p;
+	CHAR_T *cmd;
+	CHAR_T *p;
+	char *np;
+	size_t nlen;
 
 	/* Initialize the default cscope directories. */
 	exp = EXP(sp);
@@ -139,7 +139,8 @@
 		for (; *p && isspace(*p); ++p);
 	}
 
-	if ((ccp = lookup_ccmd(cmd)) == NULL) {
+	INT2CHAR(sp, cmd, STRLEN(cmd) + 1, np, nlen);
+	if ((ccp = lookup_ccmd(np)) == NULL) {
 usage:		msgq(sp, M_ERR, "309|Use \"cscope help\" for help");
 		return (1);
 	}
@@ -153,12 +154,12 @@
  *	Initialize the cscope package.
  */
 static int
-start_cscopes(sp, cmdp)
-	SCR *sp;
-	EXCMD *cmdp;
+start_cscopes(SCR *sp, EXCMD *cmdp)
 {
 	size_t blen, len;
 	char *bp, *cscopes, *p, *t;
+	CHAR_T *wp;
+	size_t wlen;
 
 	/*
 	 * EXTENSION #1:
@@ -175,12 +176,14 @@
 	if ((cscopes = getenv("CSCOPE_DIRS")) == NULL)
 		return (0);
 	len = strlen(cscopes);
-	GET_SPACE_RET(sp, bp, blen, len);
+	GET_SPACE_RETC(sp, bp, blen, len);
 	memcpy(bp, cscopes, len + 1);
 
 	for (cscopes = t = bp; (p = strsep(&t, "\t :")) != NULL;)
-		if (*p != '\0')
-			(void)cscope_add(sp, cmdp, p);
+		if (*p != '\0') {
+			CHAR2INT(sp, p, strlen(p) + 1, wp, wlen);
+			(void)cscope_add(sp, cmdp, wp);
+		}
 
 	FREE_SPACE(sp, bp, blen);
 	return (0);
@@ -191,10 +194,7 @@
  *	The cscope add command.
  */
 static int
-cscope_add(sp, cmdp, dname)
-	SCR *sp;
-	EXCMD *cmdp;
-	char *dname;
+cscope_add(SCR *sp, EXCMD *cmdp, CHAR_T *dname)
 {
 	struct stat sb;
 	EX_PRIVATE *exp;
@@ -201,7 +201,9 @@
 	CSC *csc;
 	size_t len;
 	int cur_argc;
-	char *dbname, path[MAXPATHLEN];
+	char *dbname, *path;
+	char *np = NULL;
+	size_t nlen;
 
 	exp = EXP(sp);
 
@@ -211,8 +213,9 @@
 	 * >1 additional args: object, too many args.
 	 */
 	cur_argc = cmdp->argc;
-	if (argv_exp2(sp, cmdp, dname, strlen(dname)))
+	if (argv_exp2(sp, cmdp, dname, STRLEN(dname))) {
 		return (1);
+	}
 	if (cmdp->argc == cur_argc) {
 		(void)csc_help(sp, "add");
 		return (1);
@@ -220,10 +223,12 @@
 	if (cmdp->argc == cur_argc + 1)
 		dname = cmdp->argv[cur_argc]->bp;
 	else {
-		ex_emsg(sp, dname, EXM_FILECOUNT);
+		ex_emsg(sp, np, EXM_FILECOUNT);
 		return (1);
 	}
 
+	INT2CHAR(sp, dname, STRLEN(dname)+1, np, nlen);
+
 	/*
 	 * The user can specify a specific file (so they can have multiple
 	 * Cscope databases in a single directory) or a directory.  If the
@@ -231,28 +236,36 @@
 	 * standard database file name and try again.  Store the directory
 	 * name regardless so that we can use it as a base for searches.
 	 */
-	if (stat(dname, &sb)) {
-		msgq(sp, M_SYSERR, dname);
+	if (stat(np, &sb)) {
+		msgq(sp, M_SYSERR, "%s", np);
 		return (1);
 	}
 	if (S_ISDIR(sb.st_mode)) {
-		(void)snprintf(path, sizeof(path),
-		    "%s/%s", dname, CSCOPE_DBFILE);
+		if ((path = join(np, CSCOPE_DBFILE)) == NULL) {
+			msgq(sp, M_SYSERR, NULL);
+			return (1);
+		}
 		if (stat(path, &sb)) {
-			msgq(sp, M_SYSERR, path);
+			msgq(sp, M_SYSERR, "%s", path);
+			free(path);
 			return (1);
 		}
+		free(path);
 		dbname = CSCOPE_DBFILE;
-	} else if ((dbname = strrchr(dname, '/')) != NULL)
+	} else if ((dbname = strrchr(np, '/')) != NULL)
 		*dbname++ = '\0';
+	else {
+		dbname = np;
+		np = ".";
+	}
 
 	/* Allocate a cscope connection structure and initialize its fields. */
-	len = strlen(dname);
+	len = strlen(np);
 	CALLOC_RET(sp, csc, CSC *, 1, sizeof(CSC) + len);
 	csc->dname = csc->buf;
 	csc->dlen = len;
-	memcpy(csc->dname, dname, len);
-	csc->mtime = sb.st_mtime;
+	memcpy(csc->dname, np, len);
+	csc->mtim = sb.st_mtimespec;
 
 	/* Get the search paths for the cscope. */
 	if (get_paths(sp, csc))
@@ -267,16 +280,11 @@
 	 * on error, we have to call terminate, which expects the csc to
 	 * be on the chain.
 	 */
-	LIST_INSERT_HEAD(&exp->cscq, csc, q);
+	SLIST_INSERT_HEAD(exp->cscq, csc, q);
 
 	/* Read the initial prompt from the cscope to make sure it's okay. */
-	if (read_prompt(sp, csc)) {
-		terminate(sp, csc, 0);
-		return (1);
-	}
+	return read_prompt(sp, csc);
 
-	return (0);
-
 err:	free(csc);
 	return (1);
 }
@@ -287,14 +295,12 @@
  *	cscope database.
  */
 static int
-get_paths(sp, csc)
-	SCR *sp;
-	CSC *csc;
+get_paths(SCR *sp, CSC *csc)
 {
 	struct stat sb;
 	int fd, nentries;
 	size_t len;
-	char *p, **pathp, buf[MAXPATHLEN * 2];
+	char *p, **pathp, *buf;
 
 	/*
 	 * EXTENSION #2:
@@ -308,7 +314,10 @@
 	 * directory.  To fix this, rewrite the each path using the cscope
 	 * directory as a prefix.
 	 */
-	(void)snprintf(buf, sizeof(buf), "%s/%s", csc->dname, CSCOPE_PATHS);
+	if ((buf = join(csc->dname, CSCOPE_PATHS)) == NULL) {
+		msgq(sp, M_SYSERR, NULL);
+		return (1);
+	}
 	if (stat(buf, &sb) == 0) {
 		/* Read in the CSCOPE_PATHS file. */
 		len = sb.st_size;
@@ -318,9 +327,11 @@
 			 msgq_str(sp, M_SYSERR, buf, "%s");
 			 if (fd >= 0)
 				(void)close(fd);
+			 free(buf);
 			 return (1);
 		}
 		(void)close(fd);
+		free(buf);
 		csc->pbuf[len] = '\0';
 
 		/* Count up the entries. */
@@ -336,6 +347,7 @@
 			*pathp++ = p;
 		return (0);
 	}
+	free(buf);
 
 	/*
 	 * If the CSCOPE_PATHS file doesn't exist, we look for files
@@ -362,24 +374,22 @@
  *	Fork off the cscope process.
  */
 static int
-run_cscope(sp, csc, dbname)
-	SCR *sp;
-	CSC *csc;
-	char *dbname;
+run_cscope(SCR *sp, CSC *csc, char *dbname)
 {
 	int to_cs[2], from_cs[2];
-	char cmd[MAXPATHLEN * 2];
+	char *cmd;
 
 	/*
 	 * Cscope reads from to_cs[0] and writes to from_cs[1]; vi reads from
 	 * from_cs[0] and writes to to_cs[1].
 	 */
-	to_cs[0] = to_cs[1] = from_cs[0] = from_cs[0] = -1;
+	to_cs[0] = to_cs[1] = from_cs[0] = from_cs[1] = -1;
 	if (pipe(to_cs) < 0 || pipe(from_cs) < 0) {
 		msgq(sp, M_SYSERR, "pipe");
 		goto err;
 	}
 	switch (csc->pid = vfork()) {
+		char *dn, *dbn;
 	case -1:
 		msgq(sp, M_SYSERR, "vfork");
 err:		if (to_cs[0] != -1)
@@ -401,11 +411,23 @@
 		(void)close(from_cs[0]);
 
 		/* Run the cscope command. */
-#define	CSCOPE_CMD_FMT		"cd '%s' && exec cscope -dl -f %s"
-		(void)snprintf(cmd, sizeof(cmd),
-		    CSCOPE_CMD_FMT, csc->dname, dbname);
-		(void)execl(_PATH_BSHELL, "sh", "-c", cmd, NULL);
+#define	CSCOPE_CMD_FMT		"cd %s && exec cscope -dl -f %s"
+		if ((dn = quote(csc->dname)) == NULL)
+			goto nomem;
+		if ((dbn = quote(dbname)) == NULL) {
+			free(dn);
+			goto nomem;
+		}
+		(void)asprintf(&cmd, CSCOPE_CMD_FMT, dn, dbn);
+		free(dbn);
+		free(dn);
+		if (cmd == NULL) {
+nomem:			msgq(sp, M_SYSERR, NULL);
+			_exit (1);
+		}
+		(void)execl(_PATH_BSHELL, "sh", "-c", cmd, (char *)NULL);
 		msgq_str(sp, M_SYSERR, cmd, "execl: %s");
+		free(cmd);
 		_exit (127);
 		/* NOTREACHED */
 	default:			/* parent. */
@@ -431,10 +453,7 @@
  *	The cscope find command.
  */
 static int
-cscope_find(sp, cmdp, pattern)
-	SCR *sp;
-	EXCMD *cmdp;
-	char *pattern;
+cscope_find(SCR *sp, EXCMD *cmdp, CHAR_T *pattern)
 {
 	CSC *csc, *csc_next;
 	EX_PRIVATE *exp;
@@ -444,11 +463,13 @@
 	recno_t lno;
 	size_t cno, search;
 	int force, istmp, matches;
+	char *np = NULL;
+	size_t nlen;
 
 	exp = EXP(sp);
 
 	/* Check for connections. */
-	if (exp->cscq.lh_first == NULL) {
+	if (SLIST_EMPTY(exp->cscq)) {
 		msgq(sp, M_ERR, "310|No cscope connections running");
 		return (1);
 	}
@@ -460,20 +481,24 @@
 	 */
 	rtp = NULL;
 	rtqp = NULL;
-	if (exp->tq.cqh_first == (void *)&exp->tq) {
+	if (TAILQ_EMPTY(exp->tq)) {
 		/* Initialize the `local context' tag queue structure. */
 		CALLOC_GOTO(sp, rtqp, TAGQ *, 1, sizeof(TAGQ));
-		CIRCLEQ_INIT(&rtqp->tagq);
+		TAILQ_INIT(rtqp->tagq);
 
 		/* Initialize and link in its tag structure. */
 		CALLOC_GOTO(sp, rtp, TAG *, 1, sizeof(TAG));
-		CIRCLEQ_INSERT_HEAD(&rtqp->tagq, rtp, q);
-		rtqp->current = rtp; 
+		TAILQ_INSERT_HEAD(rtqp->tagq, rtp, q);
+		rtqp->current = rtp;
 	}
 
 	/* Create the cscope command. */
-	if ((tqp = create_cs_cmd(sp, pattern, &search)) == NULL)
+	INT2CHAR(sp, pattern, STRLEN(pattern) + 1, np, nlen);
+	np = strdup(np);
+	if ((tqp = create_cs_cmd(sp, np, &search)) == NULL)
 		goto err;
+	if (np != NULL)
+		free(np);
 
 	/*
 	 * Stick the current context in a convenient place, we'll lose it
@@ -486,10 +511,8 @@
 
 	/* Search all open connections for a match. */
 	matches = 0;
-	for (csc = exp->cscq.lh_first; csc != NULL; csc = csc_next) {
-		/* Copy csc->q.lh_next here in case csc is killed. */
-		csc_next = csc->q.le_next;
-
+	/* Copy next connect here in case csc is killed. */
+	SLIST_FOREACH_SAFE(csc, exp->cscq, q, csc_next) {
 		/*
 		 * Send the command to the cscope program.  (We skip the
 		 * first two bytes of the command, because we stored the
@@ -496,25 +519,24 @@
 		 * search cscope command character and a leading space
 		 * there.)
 		 */
-		(void)fprintf(csc->to_fp, "%d%s\n", search, tqp->tag + 2);
+		(void)fprintf(csc->to_fp, "%lu%s\n", search, tqp->tag + 2);
 		(void)fflush(csc->to_fp);
 
 		/* Read the output. */
-		if (parse(sp, csc, tqp, &matches)) {
-			if (rtqp != NULL)
-				free(rtqp);
-			tagq_free(sp, tqp);
-			return (1);
-		}
+		if (parse(sp, csc, tqp, &matches))
+			goto nomatch;
 	}
 
 	if (matches == 0) {
 		msgq(sp, M_INFO, "278|No matches for query");
-		return (0);
+nomatch:	if (rtp != NULL)
+			free(rtp);
+		if (rtqp != NULL)
+			free(rtqp);
+		tagq_free(sp, tqp);
+		return (1);
 	}
 
-	tqp->current = tqp->tagq.cqh_first;
-
 	/* Try to switch to the first tag. */
 	force = FL_ISSET(cmdp->iflags, E_C_FORCE);
 	if (F_ISSET(cmdp, E_NEWSCREEN)) {
@@ -533,13 +555,13 @@
 	 * in place, so we can pop all the way back to the current mark.
 	 * Note, it doesn't point to much of anything, it's a placeholder.
 	 */
-	if (exp->tq.cqh_first == (void *)&exp->tq) {
-		CIRCLEQ_INSERT_HEAD(&exp->tq, rtqp, q);
+	if (TAILQ_EMPTY(exp->tq)) {
+		TAILQ_INSERT_HEAD(exp->tq, rtqp, q);
 	} else
-		rtqp = exp->tq.cqh_first;
+		rtqp = TAILQ_FIRST(exp->tq);
 
 	/* Link the current TAGQ structure into place. */
-	CIRCLEQ_INSERT_HEAD(&exp->tq, tqp, q);
+	TAILQ_INSERT_HEAD(exp->tq, tqp, q);
 
 	(void)cscope_search(sp, tqp, tqp->current);
 
@@ -570,6 +592,8 @@
 		free(rtqp);
 	if (rtp != NULL)
 		free(rtp);
+	if (np != NULL)
+		free(np);
 	return (1);
 }
 
@@ -578,10 +602,7 @@
  *	Build a cscope command, creating and initializing the base TAGQ.
  */
 static TAGQ *
-create_cs_cmd(sp, pattern, searchp)
-	SCR *sp;
-	char *pattern;
-	size_t *searchp;
+create_cs_cmd(SCR *sp, char *pattern, size_t *searchp)
 {
 	CB *cbp;
 	TAGQ *tqp;
@@ -601,8 +622,8 @@
 		goto usage;
 
 	/* Skip leading blanks, check for command character. */
-	for (; isblank(pattern[0]); ++pattern);
-	if (pattern[0] == '\0' || !isblank(pattern[1]))
+	for (; cmdskip(pattern[0]); ++pattern);
+	if (pattern[0] == '\0' || !cmdskip(pattern[1]))
 		goto usage;
 	for (*searchp = 0, p = CSCOPE_QUERIES;
 	    *p != '\0' && *p != pattern[0]; ++*searchp, ++p);
@@ -614,7 +635,7 @@
 	}
 
 	/* Skip <blank> characters to the pattern. */
-	for (p = pattern + 1; *p != '\0' && isblank(*p); ++p);
+	for (p = pattern + 1; *p != '\0' && cmdskip(*p); ++p);
 	if (*p == '\0') {
 usage:		(void)csc_help(sp, "find");
 		return (NULL);
@@ -625,8 +646,8 @@
 	if (p[0] == '"' && p[1] != '\0' && p[2] == '\0')
 		CBNAME(sp, cbp, p[1]);
 	if (cbp != NULL) {
-		p = cbp->textq.cqh_first->lb;
-		tlen = cbp->textq.cqh_first->len;
+		INT2CHAR(sp, TAILQ_FIRST(cbp->textq)->lb,
+			TAILQ_FIRST(cbp->textq)->len, p, tlen);
 	} else
 		tlen = strlen(p);
 
@@ -634,7 +655,7 @@
 	CALLOC(sp, tqp, TAGQ *, 1, sizeof(TAGQ) + tlen + 3);
 	if (tqp == NULL)
 		return (NULL);
-	CIRCLEQ_INIT(&tqp->tagq);
+	TAILQ_INIT(tqp->tagq);
 	tqp->tag = tqp->buf;
 	tqp->tag[0] = pattern[0];
 	tqp->tag[1] = ' ';
@@ -651,17 +672,15 @@
  *	Parse the cscope output.
  */
 static int
-parse(sp, csc, tqp, matchesp)
-	SCR *sp;
-	CSC *csc;
-	TAGQ *tqp;
-	int *matchesp;
+parse(SCR *sp, CSC *csc, TAGQ *tqp, int *matchesp)
 {
 	TAG *tp;
-	recno_t slno;
-	size_t dlen, nlen, slen;
-	int ch, i, isolder, nlines;
-	char *dname, *name, *search, *p, *t, dummy[2], buf[2048];
+	recno_t slno = 0;
+	size_t dlen, nlen = 0, slen = 0;
+	int ch, i, isolder = 0, nlines;
+	char *dname = NULL, *name = NULL, *search, *p, *t, dummy[2], buf[2048];
+	CHAR_T *wp;
+	size_t wlen;
 
 	for (;;) {
 		if (!fgets(buf, sizeof(buf), csc->from_fp))
@@ -738,9 +757,12 @@
 		 * length cscope information that follows it.
 		 */
 		CALLOC_RET(sp, tp,
-		    TAG *, 1, sizeof(TAG) + dlen + 2 + nlen + 1 + slen + 1);
-		tp->fname = tp->buf;
-		if (dlen != 0) {
+		    TAG *, 1, sizeof(TAG) + dlen + 2 + nlen + 1 +
+		    (slen + 1) * sizeof(CHAR_T));
+		tp->fname = (char *)tp->buf;
+		if (dlen == 1 && *dname == '.')
+			--dlen;
+		else if (dlen != 0) {
 			memcpy(tp->fname, dname, dlen);
 			tp->fname[dlen] = '/';
 			++dlen;
@@ -748,18 +770,24 @@
 		memcpy(tp->fname + dlen, name, nlen + 1);
 		tp->fnlen = dlen + nlen;
 		tp->slno = slno;
-		if (slen != 0) {
-			tp->search = tp->fname + tp->fnlen + 1;
-			memcpy(tp->search, search, (tp->slen = slen) + 1);
-		}
-		CIRCLEQ_INSERT_TAIL(&tqp->tagq, tp, q);
+		tp->search = (CHAR_T*)(tp->fname + tp->fnlen + 1);
+		CHAR2INT(sp, search, slen + 1, wp, wlen);
+		MEMCPY(tp->search, wp, (tp->slen = slen) + 1);
+		TAILQ_INSERT_TAIL(tqp->tagq, tp, q);
 
+		/* Try to preset the tag within the current file. */
+		if (sp->frp != NULL && sp->frp->name != NULL &&
+		    tqp->current == NULL && !strcmp(tp->fname, sp->frp->name))
+			tqp->current = tp;
+
 		++*matchesp;
 	}
 
-	(void)read_prompt(sp, csc);
-	return (0);
+	if (tqp->current == NULL)
+		tqp->current = TAILQ_FIRST(tqp->tagq);
 
+	return read_prompt(sp, csc);
+
 io_err:	if (feof(csc->from_fp))
 		errno = EIO;
 	msgq_str(sp, M_SYSERR, "%s", csc->dname);
@@ -772,15 +800,10 @@
  *	Search for the right path to this file.
  */
 static void
-csc_file(sp, csc, name, dirp, dlenp, isolderp)
-	SCR *sp;
-	CSC *csc;
-	char *name, **dirp;
-	size_t *dlenp;
-	int *isolderp;
+csc_file(SCR *sp, CSC *csc, char *name, char **dirp, size_t *dlenp, int *isolderp)
 {
 	struct stat sb;
-	char **pp, buf[MAXPATHLEN];
+	char **pp, *buf;
 
 	/*
 	 * Check for the file in all of the listed paths.  If we don't
@@ -790,13 +813,20 @@
 	 * lives.
 	 */
 	for (pp = csc->paths; *pp != NULL; ++pp) {
-		(void)snprintf(buf, sizeof(buf), "%s/%s", *pp, name);
+		if ((buf = join(*pp, name)) == NULL) {
+			msgq(sp, M_SYSERR, NULL);
+			*dlenp = 0;
+			return;
+		}
 		if (stat(buf, &sb) == 0) {
+			free(buf);
 			*dirp = *pp;
 			*dlenp = strlen(*pp);
-			*isolderp = sb.st_mtime < csc->mtime;
+			*isolderp = timespeccmp(
+			    &sb.st_mtimespec, &csc->mtim, <);
 			return;
 		}
+		free(buf);
 	}
 	*dlenp = 0;
 }
@@ -806,12 +836,13 @@
  *	The cscope help command.
  */
 static int
-cscope_help(sp, cmdp, subcmd)
-	SCR *sp;
-	EXCMD *cmdp;
-	char *subcmd;
+cscope_help(SCR *sp, EXCMD *cmdp, CHAR_T *subcmd)
 {
-	return (csc_help(sp, subcmd));
+	char *np;
+	size_t nlen;
+
+	INT2CHAR(sp, subcmd, STRLEN(subcmd) + 1, np, nlen);
+	return (csc_help(sp, np));
 }
 
 /*
@@ -819,9 +850,7 @@
  *	Display help/usage messages.
  */
 static int
-csc_help(sp, cmd)
-	SCR *sp;
-	char *cmd;
+csc_help(SCR *sp, char *cmd)
 {
 	CC const *ccp;
 
@@ -848,12 +877,17 @@
  *	The cscope kill command.
  */
 static int
-cscope_kill(sp, cmdp, cn)
-	SCR *sp;
-	EXCMD *cmdp;
-	char *cn;
+cscope_kill(SCR *sp, EXCMD *cmdp, CHAR_T *cn)
 {
-	return (terminate(sp, NULL, atoi(cn)));
+	char *np;
+	size_t nlen;
+	int n = 1;
+
+	if (*cn) {
+		INT2CHAR(sp, cn, STRLEN(cn) + 1, np, nlen);
+		n = atoi(np);
+	}
+	return (terminate(sp, NULL, n));
 }
 
 /*
@@ -861,49 +895,54 @@
  *	Detach from a cscope process.
  */
 static int
-terminate(sp, csc, n)
-	SCR *sp;
-	CSC *csc;
-	int n;
+terminate(SCR *sp, CSC *csc, int n)
 {
 	EX_PRIVATE *exp;
-	int i, pstat;
+	int i = 0, pstat;
+	CSC *cp, *pre_cp = NULL;
 
 	exp = EXP(sp);
 
 	/*
-	 * We either get a csc structure or a number.  If not provided a
-	 * csc structure, find the right one.
+	 * We either get a csc structure or a number.  Locate and remove
+	 * the candidate which matches the structure or the number.
 	 */
-	if (csc == NULL) {
-		if (n < 1)
-			goto badno;
-		for (i = 1, csc = exp->cscq.lh_first;
-		    csc != NULL; csc = csc->q.le_next, i++)
-			if (i == n)
-				break;
-		if (csc == NULL) {
-badno:			msgq(sp, M_ERR, "312|%d: no such cscope session", n);
-			return (1);
+	if (csc == NULL && n < 1)
+		goto badno;
+	SLIST_FOREACH(cp, exp->cscq, q) {
+		++i;
+		if (csc == NULL ? i != n : cp != csc) {
+			pre_cp = cp;
+			continue;
 		}
+		if (cp == SLIST_FIRST(exp->cscq))
+			SLIST_REMOVE_HEAD(exp->cscq, q);
+		else
+			SLIST_REMOVE_AFTER(pre_cp, q);
+		csc = cp;
+		break;
 	}
+	if (csc == NULL) {
+badno:		msgq(sp, M_ERR, "312|%d: no such cscope session", n);
+		return (1);
+	}
 
 	/*
 	 * XXX
 	 * Theoretically, we have the only file descriptors to the process,
 	 * so closing them should let it exit gracefully, deleting temporary
-	 * files, etc.  The original vi cscope integration sent the cscope
-	 * connection a SIGTERM signal, so I'm not sure if closing the file
-	 * descriptors is sufficient.
+	 * files, etc.  However, the earlier created cscope processes seems
+	 * to refuse to quit unless we send a SIGTERM signal.
 	 */
 	if (csc->from_fp != NULL)
 		(void)fclose(csc->from_fp);
 	if (csc->to_fp != NULL)
 		(void)fclose(csc->to_fp);
+	if (i > 1)
+		(void)kill(csc->pid, SIGTERM);
 	(void)waitpid(csc->pid, &pstat, 0);
 
 	/* Discard cscope connection information. */
-	LIST_REMOVE(csc, q);
 	if (csc->pbuf != NULL)
 		free(csc->pbuf);
 	if (csc->paths != NULL)
@@ -917,15 +956,24 @@
  *	The cscope reset command.
  */
 static int
-cscope_reset(sp, cmdp, notusedp)
-	SCR *sp;
-	EXCMD *cmdp;
-	char *notusedp;
+cscope_reset(SCR *sp, EXCMD *cmdp, CHAR_T *notusedp)
 {
+	return cscope_end(sp);
+}
+
+/*
+ * cscope_end --
+ *	End all cscope connections.
+ *
+ * PUBLIC: int cscope_end __P((SCR *));
+ */
+int
+cscope_end(SCR *sp)
+{
 	EX_PRIVATE *exp;
 
-	for (exp = EXP(sp); exp->cscq.lh_first != NULL;)
-		if (cscope_kill(sp, cmdp, "1"))
+	for (exp = EXP(sp); !SLIST_EMPTY(exp->cscq);)
+		if (terminate(sp, NULL, 1))
 			return (1);
 	return (0);
 }
@@ -937,22 +985,20 @@
  * PUBLIC: int cscope_display __P((SCR *));
  */
 int
-cscope_display(sp)
-	SCR *sp;
+cscope_display(SCR *sp)
 {
 	EX_PRIVATE *exp;
 	CSC *csc;
-	int i;
+	int i = 0;
 
 	exp = EXP(sp);
-	if (exp->cscq.lh_first == NULL) {
+	if (SLIST_EMPTY(exp->cscq)) {
 		ex_printf(sp, "No cscope connections.\n");
 		return (0);
 	}
-	for (i = 1,
-	    csc = exp->cscq.lh_first; csc != NULL; ++i, csc = csc->q.le_next)
-		ex_printf(sp,
-		    "%2d %s (process %lu)\n", i, csc->dname, (u_long)csc->pid);
+	SLIST_FOREACH(csc, exp->cscq, q)
+		ex_printf(sp, "%2d %s (process %lu)\n",
+		    ++i, csc->dname, (u_long)csc->pid);
 	return (0);
 }
 
@@ -963,10 +1009,7 @@
  * PUBLIC: int cscope_search __P((SCR *, TAGQ *, TAG *));
  */
 int
-cscope_search(sp, tqp, tp)
-	SCR *sp;
-	TAGQ *tqp;
-	TAG *tp;
+cscope_search(SCR *sp, TAGQ *tqp, TAG *tp)
 {
 	MARK m;
 
@@ -1015,8 +1058,7 @@
  *	Return a pointer to the command structure.
  */
 static CC const *
-lookup_ccmd(name)
-	char *name;
+lookup_ccmd(char *name)
 {
 	CC const *ccp;
 	size_t len;
@@ -1033,9 +1075,7 @@
  *	Read a prompt from cscope.
  */
 static int
-read_prompt(sp, csc)
-	SCR *sp;
-	CSC *csc;
+read_prompt(SCR *sp, CSC *csc)
 {
 	int ch;
 

Added: trunk/contrib/nvi/ex/ex_def.h
===================================================================
--- trunk/contrib/nvi/ex/ex_def.h	                        (rev 0)
+++ trunk/contrib/nvi/ex/ex_def.h	2018-06-10 20:23:48 UTC (rev 10823)
@@ -0,0 +1,76 @@
+#define C_SCROLL 0
+#define C_BANG 1
+#define C_HASH 2
+#define C_SUBAGAIN 3
+#define C_STAR 4
+#define C_SHIFTL 5
+#define C_EQUAL 6
+#define C_SHIFTR 7
+#define C_AT 8
+#define C_APPEND 9
+#define C_ABBR 10
+#define C_ARGS 11
+#define C_BG 12
+#define C_CHANGE 13
+#define C_CD 14
+#define C_CHDIR 15
+#define C_COPY 16
+#define C_CSCOPE 17
+#define C_DELETE 18
+#define C_DISPLAY 19
+#define C_EDIT 20
+#define C_EX 21
+#define C_EXUSAGE 22
+#define C_FILE 23
+#define C_FG 24
+#define C_GLOBAL 25
+#define C_HELP 26
+#define C_INSERT 27
+#define C_JOIN 28
+#define C_K 29
+#define C_LIST 30
+#define C_MOVE 31
+#define C_MARK 32
+#define C_MAP 33
+#define C_MKEXRC 34
+#define C_NEXT 35
+#define C_NUMBER 36
+#define C_OPEN 37
+#define C_PRINT 38
+#define C_PRESERVE 39
+#define C_PREVIOUS 40
+#define C_PUT 41
+#define C_QUIT 42
+#define C_READ 43
+#define C_RECOVER 44
+#define C_RESIZE 45
+#define C_REWIND 46
+#define C_SUBSTITUTE 47
+#define C_SCRIPT 48
+#define C_SET 49
+#define C_SHELL 50
+#define C_SOURCE 51
+#define C_STOP 52
+#define C_SUSPEND 53
+#define C_T 54
+#define C_TAG 55
+#define C_TAGNEXT 56
+#define C_TAGPOP 57
+#define C_TAGPREV 58
+#define C_TAGTOP 59
+#define C_UNDO 60
+#define C_UNABBREVIATE 61
+#define C_UNMAP 62
+#define C_V 63
+#define C_VERSION 64
+#define C_VISUAL_EX 65
+#define C_VISUAL_VI 66
+#define C_VIUSAGE 67
+#define C_VSPLIT 68
+#define C_WRITE 69
+#define C_WN 70
+#define C_WQ 71
+#define C_XIT 72
+#define C_YANK 73
+#define C_Z 74
+#define C_SUBTILDE 75


Property changes on: trunk/contrib/nvi/ex/ex_def.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Modified: trunk/contrib/nvi/ex/ex_delete.c
===================================================================
--- trunk/contrib/nvi/ex/ex_delete.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/ex/ex_delete.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -10,11 +10,12 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)ex_delete.c	10.9 (Berkeley) 10/23/96";
+static const char sccsid[] = "$Id: ex_delete.c,v 10.11 2001/06/25 15:19:15 skimo Exp $";
 #endif /* not lint */
 
 #include <sys/types.h>
 #include <sys/queue.h>
+#include <sys/time.h>
 
 #include <bitstring.h>
 #include <limits.h>
@@ -30,9 +31,7 @@
  * PUBLIC: int ex_delete __P((SCR *, EXCMD *));
  */
 int
-ex_delete(sp, cmdp)
-	SCR *sp;
-	EXCMD *cmdp;
+ex_delete(SCR *sp, EXCMD *cmdp)
 {
 	recno_t lno;
 

Modified: trunk/contrib/nvi/ex/ex_display.c
===================================================================
--- trunk/contrib/nvi/ex/ex_display.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/ex/ex_display.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -10,11 +10,12 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)ex_display.c	10.12 (Berkeley) 4/10/96";
+static const char sccsid[] = "$Id: ex_display.c,v 10.15 2001/06/25 15:19:15 skimo Exp $";
 #endif /* not lint */
 
 #include <sys/types.h>
 #include <sys/queue.h>
+#include <sys/time.h>
 
 #include <bitstring.h>
 #include <ctype.h>
@@ -25,8 +26,9 @@
 #include "../common/common.h"
 #include "tag.h"
 
+static int	is_prefix __P((ARGS *, CHAR_T *));
 static int	bdisplay __P((SCR *));
-static void	db __P((SCR *, CB *, CHAR_T *));
+static void	db __P((SCR *, CB *, const char *));
 
 /*
  * ex_display -- :display b[uffers] | c[onnections] | s[creens] | t[ags]
@@ -36,37 +38,27 @@
  * PUBLIC: int ex_display __P((SCR *, EXCMD *));
  */
 int
-ex_display(sp, cmdp)
-	SCR *sp;
-	EXCMD *cmdp;
+ex_display(SCR *sp, EXCMD *cmdp)
 {
-	switch (cmdp->argv[0]->bp[0]) {
+	ARGS *arg;
+
+	arg = cmdp->argv[0];
+
+	switch (arg->bp[0]) {
 	case 'b':
-#undef	ARG
-#define	ARG	"buffers"
-		if (cmdp->argv[0]->len >= sizeof(ARG) ||
-		    memcmp(cmdp->argv[0]->bp, ARG, cmdp->argv[0]->len))
+		if (!is_prefix(arg, L("buffers")))
 			break;
 		return (bdisplay(sp));
 	case 'c':
-#undef	ARG
-#define	ARG	"connections"
-		if (cmdp->argv[0]->len >= sizeof(ARG) ||
-		    memcmp(cmdp->argv[0]->bp, ARG, cmdp->argv[0]->len))
+		if (!is_prefix(arg, L("connections")))
 			break;
 		return (cscope_display(sp));
 	case 's':
-#undef	ARG
-#define	ARG	"screens"
-		if (cmdp->argv[0]->len >= sizeof(ARG) ||
-		    memcmp(cmdp->argv[0]->bp, ARG, cmdp->argv[0]->len))
+		if (!is_prefix(arg, L("screens")))
 			break;
 		return (ex_sdisplay(sp));
 	case 't':
-#undef	ARG
-#define	ARG	"tags"
-		if (cmdp->argv[0]->len >= sizeof(ARG) ||
-		    memcmp(cmdp->argv[0]->bp, ARG, cmdp->argv[0]->len))
+		if (!is_prefix(arg, L("tags")))
 			break;
 		return (ex_tag_display(sp));
 	}
@@ -75,35 +67,45 @@
 }
 
 /*
+ * is_prefix --
+ *
+ *	Check that a command argument matches a prefix of a given string.
+ */
+static int
+is_prefix(ARGS *arg, CHAR_T *str)
+{
+	return arg->len <= STRLEN(str) && !MEMCMP(arg->bp, str, arg->len);
+}
+
+/*
  * bdisplay --
  *
  *	Display buffers.
  */
 static int
-bdisplay(sp)
-	SCR *sp;
+bdisplay(SCR *sp)
 {
 	CB *cbp;
 
-	if (sp->gp->cutq.lh_first == NULL && sp->gp->dcbp == NULL) {
+	if (SLIST_EMPTY(sp->gp->cutq) && sp->gp->dcbp == NULL) {
 		msgq(sp, M_INFO, "123|No cut buffers to display");
 		return (0);
 	}
 
 	/* Display regular cut buffers. */
-	for (cbp = sp->gp->cutq.lh_first; cbp != NULL; cbp = cbp->q.le_next) {
+	SLIST_FOREACH(cbp, sp->gp->cutq, q) {
 		if (isdigit(cbp->name))
 			continue;
-		if (cbp->textq.cqh_first != (void *)&cbp->textq)
+		if (!TAILQ_EMPTY(cbp->textq))
 			db(sp, cbp, NULL);
 		if (INTERRUPTED(sp))
 			return (0);
 	}
 	/* Display numbered buffers. */
-	for (cbp = sp->gp->cutq.lh_first; cbp != NULL; cbp = cbp->q.le_next) {
+	SLIST_FOREACH(cbp, sp->gp->cutq, q) {
 		if (!isdigit(cbp->name))
 			continue;
-		if (cbp->textq.cqh_first != (void *)&cbp->textq)
+		if (!TAILQ_EMPTY(cbp->textq))
 			db(sp, cbp, NULL);
 		if (INTERRUPTED(sp))
 			return (0);
@@ -119,10 +121,7 @@
  *	Display a buffer.
  */
 static void
-db(sp, cbp, name)
-	SCR *sp;
-	CB *cbp;
-	CHAR_T *name;
+db(SCR *sp, CB *cbp, const char *name)
 {
 	CHAR_T *p;
 	GS *gp;
@@ -133,8 +132,7 @@
 	(void)ex_printf(sp, "********** %s%s\n",
 	    name == NULL ? KEY_NAME(sp, cbp->name) : name,
 	    F_ISSET(cbp, CB_LMODE) ? " (line mode)" : " (character mode)");
-	for (tp = cbp->textq.cqh_first;
-	    tp != (void *)&cbp->textq; tp = tp->q.cqe_next) {
+	TAILQ_FOREACH(tp, cbp->textq, q) {
 		for (len = tp->len, p = tp->lb; len--; ++p) {
 			(void)ex_puts(sp, KEY_NAME(sp, *p));
 			if (INTERRUPTED(sp))

Modified: trunk/contrib/nvi/ex/ex_edit.c
===================================================================
--- trunk/contrib/nvi/ex/ex_edit.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/ex/ex_edit.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -10,7 +10,7 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)ex_edit.c	10.10 (Berkeley) 4/27/96";
+static const char sccsid[] = "$Id: ex_edit.c,v 10.15 2011/12/22 23:26:50 zy Exp $";
 #endif /* not lint */
 
 #include <sys/types.h>
@@ -46,12 +46,12 @@
  * PUBLIC: int ex_edit __P((SCR *, EXCMD *));
  */
 int
-ex_edit(sp, cmdp)
-	SCR *sp;
-	EXCMD *cmdp;
+ex_edit(SCR *sp, EXCMD *cmdp)
 {
 	FREF *frp;
 	int attach, setalt;
+	char *np;
+	size_t nlen;
 
 	switch (cmdp->argc) {
 	case 0:
@@ -72,17 +72,19 @@
 		setalt = 0;
 		break;
 	case 1:
-		if ((frp = file_add(sp, cmdp->argv[0]->bp)) == NULL)
+		INT2CHAR(sp, cmdp->argv[0]->bp, cmdp->argv[0]->len + 1, 
+			 np, nlen);
+		if ((frp = file_add(sp, np)) == NULL)
 			return (1);
 		attach = 0;
 		setalt = 1;
-		set_alt_name(sp, cmdp->argv[0]->bp);
+		set_alt_name(sp, np);
 		break;
 	default:
 		abort();
 	}
 
-	if (F_ISSET(cmdp, E_NEWSCREEN))
+	if (F_ISSET(cmdp, E_NEWSCREEN) || cmdp->cmd == &cmds[C_VSPLIT])
 		return (ex_N_edit(sp, cmdp, frp, attach));
 
 	/*
@@ -108,11 +110,7 @@
  *	New screen version of ex_edit.
  */
 static int
-ex_N_edit(sp, cmdp, frp, attach)
-	SCR *sp;
-	EXCMD *cmdp;
-	FREF *frp;
-	int attach;
+ex_N_edit(SCR *sp, EXCMD *cmdp, FREF *frp, int attach)
 {
 	SCR *new;
 
@@ -119,7 +117,8 @@
 	/* Get a new screen. */
 	if (screen_init(sp->gp, sp, &new))
 		return (1);
-	if (vs_split(sp, new, 0)) {
+	if ((cmdp->cmd == &cmds[C_VSPLIT] && vs_vsplit(sp, new)) ||
+	    (cmdp->cmd != &cmds[C_VSPLIT] && vs_split(sp, new, 0))) {
 		(void)screen_end(new);
 		return (1);
 	}
@@ -135,6 +134,13 @@
 
 		new->lno = sp->lno;
 		new->cno = sp->cno;
+
+#if defined(USE_WIDECHAR) && defined(USE_ICONV)
+		/* Synchronize the iconv environments. */
+		o_set(new, O_FILEENCODING, OS_STRDUP,
+		    O_STR(sp, O_FILEENCODING), 0);
+		conv_enc(new, O_FILEENCODING, 0);
+#endif
 	} else if (file_init(new, frp, NULL,
 	    (FL_ISSET(cmdp->iflags, E_C_FORCE) ? FS_FORCE : 0))) {
 		(void)vs_discard(new, NULL);

Modified: trunk/contrib/nvi/ex/ex_equal.c
===================================================================
--- trunk/contrib/nvi/ex/ex_equal.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/ex/ex_equal.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -10,11 +10,12 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)ex_equal.c	10.10 (Berkeley) 3/6/96";
+static const char sccsid[] = "$Id: ex_equal.c,v 10.12 2001/06/25 15:19:15 skimo Exp $";
 #endif /* not lint */
 
 #include <sys/types.h>
 #include <sys/queue.h>
+#include <sys/time.h>
 
 #include <bitstring.h>
 #include <limits.h>
@@ -28,9 +29,7 @@
  * PUBLIC: int ex_equal __P((SCR *, EXCMD *));
  */
 int
-ex_equal(sp, cmdp)
-	SCR *sp;
-	EXCMD *cmdp;
+ex_equal(SCR *sp, EXCMD *cmdp)
 {
 	recno_t lno;
 

Modified: trunk/contrib/nvi/ex/ex_file.c
===================================================================
--- trunk/contrib/nvi/ex/ex_file.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/ex/ex_file.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -10,11 +10,12 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)ex_file.c	10.12 (Berkeley) 7/12/96";
+static const char sccsid[] = "$Id: ex_file.c,v 10.14 2001/06/25 15:19:16 skimo Exp $";
 #endif /* not lint */
 
 #include <sys/types.h>
 #include <sys/queue.h>
+#include <sys/time.h>
 
 #include <bitstring.h>
 #include <errno.h>
@@ -32,12 +33,12 @@
  * PUBLIC: int ex_file __P((SCR *, EXCMD *));
  */
 int
-ex_file(sp, cmdp)
-	SCR *sp;
-	EXCMD *cmdp;
+ex_file(SCR *sp, EXCMD *cmdp)
 {
-	CHAR_T *p;
+	char *p;
 	FREF *frp;
+	char *np;
+	size_t nlen;
 
 	NEEDFILE(sp, cmdp);
 
@@ -48,8 +49,9 @@
 		frp = sp->frp;
 
 		/* Make sure can allocate enough space. */
-		if ((p = v_strdup(sp,
-		    cmdp->argv[0]->bp, cmdp->argv[0]->len)) == NULL)
+		INT2CHAR(sp, cmdp->argv[0]->bp, cmdp->argv[0]->len + 1, 
+			    np, nlen);
+		if ((p = v_strdup(sp, np, nlen - 1)) == NULL)
 			return (1);
 
 		/* If already have a file name, it becomes the alternate. */

Modified: trunk/contrib/nvi/ex/ex_filter.c
===================================================================
--- trunk/contrib/nvi/ex/ex_filter.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/ex/ex_filter.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -10,7 +10,7 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)ex_filter.c	10.34 (Berkeley) 10/23/96";
+static const char sccsid[] = "$Id: ex_filter.c,v 10.44 2003/11/05 17:11:54 skimo Exp $";
 #endif /* not lint */
 
 #include <sys/types.h>
@@ -36,15 +36,10 @@
  *	the utility.
  *
  * PUBLIC: int ex_filter __P((SCR *, 
- * PUBLIC:    EXCMD *, MARK *, MARK *, MARK *, char *, enum filtertype));
+ * PUBLIC:    EXCMD *, MARK *, MARK *, MARK *, CHAR_T *, enum filtertype));
  */
 int
-ex_filter(sp, cmdp, fm, tm, rp, cmd, ftype)
-	SCR *sp;
-	EXCMD *cmdp;
-	MARK *fm, *tm, *rp;
-	char *cmd;
-	enum filtertype ftype;
+ex_filter(SCR *sp, EXCMD *cmdp, MARK *fm, MARK *tm, MARK *rp, CHAR_T *cmd, enum filtertype ftype)
 {
 	FILE *ifp, *ofp;
 	pid_t parent_writer_pid, utility_pid;
@@ -51,6 +46,8 @@
 	recno_t nread;
 	int input[2], output[2], rval;
 	char *name;
+	char *np;
+	size_t nlen;
 
 	rval = 0;
 
@@ -141,7 +138,8 @@
 		else
 			++name;
 
-		execl(O_STR(sp, O_SHELL), name, "-c", cmd, NULL);
+		INT2CHAR(sp, cmd, STRLEN(cmd)+1, np, nlen);
+		execl(O_STR(sp, O_SHELL), name, "-c", np, (char *)NULL);
 		msgq_str(sp, M_SYSERR, O_STR(sp, O_SHELL), "execl: %s");
 		_exit (127);
 		/* NOTREACHED */
@@ -285,7 +283,8 @@
 	 * Ignore errors on vi file reads, to make reads prettier.  It's
 	 * completely inconsistent, and historic practice.
 	 */
-uwait:	return (proc_wait(sp, (long)utility_pid, cmd,
+uwait:	INT2CHAR(sp, cmd, STRLEN(cmd) + 1, np, nlen);
+	return (proc_wait(sp, (long)utility_pid, np,
 	    ftype == FILTER_READ && F_ISSET(sp, SC_VI) ? 1 : 0, 0) || rval);
 }
 
@@ -298,17 +297,19 @@
  * We use the ex print routines to make sure they're printable.
  */
 static int
-filter_ldisplay(sp, fp)
-	SCR *sp;
-	FILE *fp;
+filter_ldisplay(SCR *sp, FILE *fp)
 {
 	size_t len;
+	size_t wlen;
+	CHAR_T *wp;
 
 	EX_PRIVATE *exp;
 
-	for (exp = EXP(sp); !ex_getline(sp, fp, &len) && !INTERRUPTED(sp);)
-		if (ex_ldisplay(sp, exp->ibp, len, 0, 0))
+	for (exp = EXP(sp); !ex_getline(sp, fp, &len) && !INTERRUPTED(sp);) {
+		FILE2INT5(sp, exp->ibcw, exp->ibp, len, wp, wlen);
+		if (ex_ldisplay(sp, wp, wlen, 0, 0))
 			break;
+	}
 	if (ferror(fp))
 		msgq(sp, M_SYSERR, "filter read");
 	(void)fclose(fp);

Modified: trunk/contrib/nvi/ex/ex_global.c
===================================================================
--- trunk/contrib/nvi/ex/ex_global.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/ex/ex_global.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -10,11 +10,12 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)ex_global.c	10.22 (Berkeley) 10/10/96";
+static const char sccsid[] = "$Id: ex_global.c,v 10.32 2011/12/26 23:37:01 zy Exp $";
 #endif /* not lint */
 
 #include <sys/types.h>
 #include <sys/queue.h>
+#include <sys/time.h>
 
 #include <bitstring.h>
 #include <ctype.h>
@@ -38,9 +39,7 @@
  * PUBLIC: int ex_global __P((SCR *, EXCMD *));
  */
 int
-ex_global(sp, cmdp)
-	SCR *sp;
-	EXCMD *cmdp;
+ex_global(SCR *sp, EXCMD *cmdp)
 {
 	return (ex_g_setup(sp,
 	    cmdp, FL_ISSET(cmdp->iflags, E_C_FORCE) ? V : GLOBAL));
@@ -53,9 +52,7 @@
  * PUBLIC: int ex_v __P((SCR *, EXCMD *));
  */
 int
-ex_v(sp, cmdp)
-	SCR *sp;
-	EXCMD *cmdp;
+ex_v(SCR *sp, EXCMD *cmdp)
 {
 	return (ex_g_setup(sp, cmdp, V));
 }
@@ -65,10 +62,7 @@
  *	Ex global and v commands.
  */
 static int
-ex_g_setup(sp, cmdp, cmd)
-	SCR *sp;
-	EXCMD *cmdp;
-	enum which cmd;
+ex_g_setup(SCR *sp, EXCMD *cmdp, enum which cmd)
 {
 	CHAR_T *ptrn, *p, *t;
 	EXCMD *ecp;
@@ -80,14 +74,13 @@
 	regmatch_t match[1];
 	size_t len;
 	int cnt, delim, eval;
-	char *dbp;
+	CHAR_T *dbp;
 
 	NEEDFILE(sp, cmdp);
 
 	if (F_ISSET(sp, SC_EX_GLOBAL)) {
-		msgq(sp, M_ERR,
-	"124|The %s command can't be used as part of a global or v command",
-		    cmdp->cmd->name);
+		msgq_wstr(sp, M_ERR, cmdp->cmd->name,
+	"124|The %s command can't be used as part of a global or v command");
 		return (1);
 	}
 
@@ -97,8 +90,8 @@
 	 */
 	if (cmdp->argc == 0)
 		goto usage;
-	for (p = cmdp->argv[0]->bp; isblank(*p); ++p);
-	if (*p == '\0' || isalnum(*p) ||
+	for (p = cmdp->argv[0]->bp; cmdskip(*p); ++p);
+	if (!isascii(*p) || *p == '\0' || isalnum(*p) ||
 	    *p == '\\' || *p == '|' || *p == '\n') {
 usage:		ex_emsg(sp, cmdp->cmd->usage, EXM_USAGE);
 		return (1);
@@ -139,13 +132,14 @@
 		}
 
 		/* Re-compile the RE if necessary. */
-		if (!F_ISSET(sp, SC_RE_SEARCH) && re_compile(sp,
-		    sp->re, sp->re_len, NULL, NULL, &sp->re_c, RE_C_SEARCH))
+		if (!F_ISSET(sp, SC_RE_SEARCH) &&
+		    re_compile(sp, sp->re, sp->re_len,
+		    NULL, NULL, &sp->re_c, RE_C_SEARCH))
 			return (1);
 	} else {
 		/* Compile the RE. */
-		if (re_compile(sp, ptrn, t - ptrn,
-		    &sp->re, &sp->re_len, &sp->re_c, RE_C_SEARCH))
+		if (re_compile(sp, ptrn, t - ptrn, &sp->re,
+		    &sp->re_len, &sp->re_c, RE_C_SEARCH))
 			return (1);
 
 		/*
@@ -164,7 +158,7 @@
 
 	/* Get an EXCMD structure. */
 	CALLOC_RET(sp, ecp, EXCMD *, 1, sizeof(EXCMD));
-	CIRCLEQ_INIT(&ecp->rq);
+	TAILQ_INIT(ecp->rq);
 
 	/*
 	 * Get a copy of the command string; the default command is print.
@@ -174,17 +168,17 @@
 	 * parsing it.
 	 */
 	if ((len = cmdp->argv[0]->len - (p - cmdp->argv[0]->bp)) == 0) {
-		p = "pp";
+		p = L("p");
 		len = 1;
 	}
 
-	MALLOC_RET(sp, ecp->cp, char *, len * 2);
+	MALLOC_RET(sp, ecp->cp, CHAR_T *, (len * 2) * sizeof(CHAR_T));
 	ecp->o_cp = ecp->cp;
 	ecp->o_clen = len;
-	memcpy(ecp->cp + len, p, len);
+	MEMCPY(ecp->cp + len, p, len);
 	ecp->range_lno = OOBLNO;
 	FL_SET(ecp->agv_flags, cmd == GLOBAL ? AGV_GLOBAL : AGV_V);
-	LIST_INSERT_HEAD(&sp->gp->ecq, ecp, q);
+	SLIST_INSERT_HEAD(sp->gp->ecq, ecp, q);
 
 	/*
 	 * For each line...  The semantics of global matching are that we first
@@ -204,7 +198,7 @@
 	    end = cmdp->addr2.lno; start <= end; ++start) {
 		if (cnt-- == 0) {
 			if (INTERRUPTED(sp)) {
-				LIST_REMOVE(ecp, q);
+				SLIST_REMOVE_HEAD(sp->gp->ecq, q);
 				free(ecp->cp);
 				free(ecp);
 				break;
@@ -233,7 +227,7 @@
 		}
 
 		/* If follows the last entry, extend the last entry's range. */
-		if ((rp = ecp->rq.cqh_last) != (void *)&ecp->rq &&
+		if ((rp = TAILQ_LAST(ecp->rq, _rh)) != NULL &&
 		    rp->stop == start - 1) {
 			++rp->stop;
 			continue;
@@ -244,7 +238,7 @@
 		if (rp == NULL)
 			return (1);
 		rp->start = rp->stop = start;
-		CIRCLEQ_INSERT_TAIL(&ecp->rq, rp, q);
+		TAILQ_INSERT_TAIL(ecp->rq, rp, q);
 	}
 	search_busy(sp, BUSY_OFF);
 	return (0);
@@ -257,10 +251,7 @@
  * PUBLIC: int ex_g_insdel __P((SCR *, lnop_t, recno_t));
  */
 int
-ex_g_insdel(sp, op, lno)
-	SCR *sp;
-	lnop_t op;
-	recno_t lno;
+ex_g_insdel(SCR *sp, lnop_t op, recno_t lno)
 {
 	EXCMD *ecp;
 	RANGE *nrp, *rp;
@@ -272,12 +263,10 @@
 	if (op == LINE_RESET)
 		return (0);
 
-	for (ecp = sp->gp->ecq.lh_first; ecp != NULL; ecp = ecp->q.le_next) {
+	SLIST_FOREACH(ecp, sp->gp->ecq, q) {
 		if (!FL_ISSET(ecp->agv_flags, AGV_AT | AGV_GLOBAL | AGV_V))
 			continue;
-		for (rp = ecp->rq.cqh_first; rp != (void *)&ecp->rq; rp = nrp) {
-			nrp = rp->q.cqe_next;
-
+		TAILQ_FOREACH_SAFE(rp, ecp->rq, q, nrp) {
 			/* If range less than the line, ignore it. */
 			if (rp->stop < lno)
 				continue;
@@ -305,7 +294,7 @@
 			 */
 			if (op == LINE_DELETE) {
 				if (rp->start > --rp->stop) {
-					CIRCLEQ_REMOVE(&ecp->rq, rp, q);
+					TAILQ_REMOVE(ecp->rq, rp, q);
 					free(rp);
 				}
 			} else {
@@ -313,8 +302,7 @@
 				nrp->start = lno + 1;
 				nrp->stop = rp->stop + 1;
 				rp->stop = lno - 1;
-				CIRCLEQ_INSERT_AFTER(&ecp->rq, rp, nrp, q);
-				rp = nrp;
+				TAILQ_INSERT_AFTER(ecp->rq, rp, nrp, q);
 			}
 		}
 

Modified: trunk/contrib/nvi/ex/ex_init.c
===================================================================
--- trunk/contrib/nvi/ex/ex_init.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/ex/ex_init.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -10,11 +10,10 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)ex_init.c	10.26 (Berkeley) 8/12/96";
+static const char sccsid[] = "$Id: ex_init.c,v 10.33 2012/04/11 19:12:34 zy Exp $";
 #endif /* not lint */
 
-#include <sys/param.h>
-#include <sys/types.h>		/* XXX: param.h may not have included types.h */
+#include <sys/types.h>
 #include <sys/queue.h>
 #include <sys/stat.h>
 
@@ -42,8 +41,7 @@
  * PUBLIC: int ex_screen_copy __P((SCR *, SCR *));
  */
 int
-ex_screen_copy(orig, sp)
-	SCR *orig, *sp;
+ex_screen_copy(SCR *orig, SCR *sp)
 {
 	EX_PRIVATE *oexp, *nexp;
 
@@ -52,9 +50,9 @@
 	sp->ex_private = nexp;
 
 	/* Initialize queues. */
-	CIRCLEQ_INIT(&nexp->tq);
-	TAILQ_INIT(&nexp->tagfq);
-	LIST_INIT(&nexp->cscq);
+	TAILQ_INIT(nexp->tq);
+	TAILQ_INIT(nexp->tagfq);
+	SLIST_INIT(nexp->cscq);
 
 	if (orig == NULL) {
 	} else {
@@ -61,7 +59,8 @@
 		oexp = EXP(orig);
 
 		if (oexp->lastbcomm != NULL &&
-		    (nexp->lastbcomm = strdup(oexp->lastbcomm)) == NULL) {
+		    (nexp->lastbcomm = v_wstrdup(sp, oexp->lastbcomm, 
+				     STRLEN(oexp->lastbcomm))) == NULL) {
 			msgq(sp, M_SYSERR, NULL);
 			return(1);
 		}
@@ -78,8 +77,7 @@
  * PUBLIC: int ex_screen_end __P((SCR *));
  */
 int
-ex_screen_end(sp)
-	SCR *sp;
+ex_screen_end(SCR *sp)
 {
 	EX_PRIVATE *exp;
 	int rval;
@@ -102,9 +100,15 @@
 	if (exp->lastbcomm != NULL)
 		free(exp->lastbcomm);
 
+	if (exp->ibcw.bp1.c != NULL)
+		free(exp->ibcw.bp1.c);
+
 	if (ex_tag_free(sp))
 		rval = 1;
 
+	if (cscope_end(sp))
+		rval = 1;
+
 	/* Free private memory. */
 	free(exp);
 	sp->ex_private = NULL;
@@ -119,11 +123,7 @@
  * PUBLIC: int ex_optchange __P((SCR *, int, char *, u_long *));
  */
 int
-ex_optchange(sp, offset, str, valp)
-	SCR *sp;
-	int offset;
-	char *str;
-	u_long *valp;
+ex_optchange(SCR *sp, int offset, char *str, u_long *valp)
 {
 	switch (offset) {
 	case O_TAGS:
@@ -140,11 +140,12 @@
  * PUBLIC: int ex_exrc __P((SCR *));
  */
 int
-ex_exrc(sp)
-	SCR *sp;
+ex_exrc(SCR *sp)
 {
 	struct stat hsb, lsb;
-	char *p, path[MAXPATHLEN];
+	char *p, *path;
+	CHAR_T *wp;
+	size_t wlen;
 
 	/*
 	 * Source the system, environment, $HOME and local .exrc values.
@@ -187,28 +188,41 @@
 		return (0);
 
 	if ((p = getenv("NEXINIT")) != NULL) {
-		if (ex_run_str(sp, "NEXINIT", p, strlen(p), 1, 0))
+		CHAR2INT(sp, p, strlen(p) + 1, wp, wlen);
+		if (ex_run_str(sp, "NEXINIT", wp, wlen - 1, 1, 0))
 			return (1);
 	} else if ((p = getenv("EXINIT")) != NULL) {
-		if (ex_run_str(sp, "EXINIT", p, strlen(p), 1, 0))
+		CHAR2INT(sp, p, strlen(p) + 1, wp, wlen);
+		if (ex_run_str(sp, "EXINIT", wp, wlen - 1, 1, 0))
 			return (1);
 	} else if ((p = getenv("HOME")) != NULL && *p) {
-		(void)snprintf(path, sizeof(path), "%s/%s", p, _PATH_NEXRC);
+		int st = 0;
+
+		if ((path = join(p, _PATH_NEXRC)) == NULL) {
+			msgq(sp, M_SYSERR, NULL);
+			return (1);
+		}
 		switch (exrc_isok(sp, &hsb, path, 0, 1)) {
 		case NOEXIST:
-			(void)snprintf(path,
-			    sizeof(path), "%s/%s", p, _PATH_EXRC);
+			free(path);
+			if ((path = join(p, _PATH_EXRC)) == NULL) {
+				msgq(sp, M_SYSERR, NULL);
+				return (1);
+			}
 			if (exrc_isok(sp,
 			    &hsb, path, 0, 1) == RCOK && ex_run_file(sp, path))
-				return (1);
+				st = 1;
 			break;
 		case NOPERM:
 			break;
 		case RCOK:
 			if (ex_run_file(sp, path))
-				return (1);
+				st = 1;
 			break;
 		}
+		free(path);
+		if (st)
+			return st;
 	}
 
 	/* Run the commands. */
@@ -251,15 +265,15 @@
  *	Set up a file of ex commands to run.
  */
 static int
-ex_run_file(sp, name)
-	SCR *sp;
-	char *name;
+ex_run_file(SCR *sp, char *name)
 {
-	ARGS *ap[2], a;
 	EXCMD cmd;
+	CHAR_T *wp;
+	size_t wlen;
 
-	ex_cinit(&cmd, C_SOURCE, 0, OOBLNO, OOBLNO, 0, ap);
-	ex_cadd(&cmd, &a, name, strlen(name));
+	ex_cinit(sp, &cmd, C_SOURCE, 0, OOBLNO, OOBLNO, 0);
+	CHAR2INT(sp, name, strlen(name)+1, wp, wlen);
+	argv_exp0(sp, &cmd, wp, wlen - 1);
 	return (ex_source(sp, &cmd));
 }
 
@@ -267,14 +281,10 @@
  * ex_run_str --
  *	Set up a string of ex commands to run.
  *
- * PUBLIC: int ex_run_str __P((SCR *, char *, char *, size_t, int, int));
+ * PUBLIC: int ex_run_str __P((SCR *, char *, CHAR_T *, size_t, int, int));
  */
 int
-ex_run_str(sp, name, str, len, ex_flags, nocopy)
-	SCR *sp;
-	char *name, *str;
-	size_t len;
-	int ex_flags, nocopy;
+ex_run_str(SCR *sp, char *name, CHAR_T *str, size_t len, int ex_flags, int nocopy)
 {
 	GS *gp;
 	EXCMD *ecp;
@@ -282,7 +292,7 @@
 	gp = sp->gp;
 	if (EXCMD_RUNNING(gp)) {
 		CALLOC_RET(sp, ecp, EXCMD *, 1, sizeof(EXCMD));
-		LIST_INSERT_HEAD(&gp->ecq, ecp, q);
+		SLIST_INSERT_HEAD(gp->ecq, ecp, q);
 	} else
 		ecp = &gp->excmd;
 
@@ -292,7 +302,7 @@
 	if (nocopy)
 		ecp->cp = str;
 	else
-		if ((ecp->cp = v_strdup(sp, str, len)) == NULL)
+		if ((ecp->cp = v_wstrdup(sp, str, len)) == NULL)
 			return (1);
 	ecp->clen = len;
 
@@ -345,16 +355,12 @@
  * files.
  */
 static enum rc
-exrc_isok(sp, sbp, path, rootown, rootid)
-	SCR *sp;
-	struct stat *sbp;
-	char *path;
-	int rootown, rootid;
+exrc_isok(SCR *sp, struct stat *sbp, char *path, int rootown, int rootid)
 {
 	enum { ROOTOWN, OWN, WRITER } etype;
 	uid_t euid;
 	int nf1, nf2;
-	char *a, *b, buf[MAXPATHLEN];
+	char *a, *b, *buf;
 
 	/* Check for the file's existence. */
 	if (stat(path, sbp))
@@ -376,23 +382,30 @@
 	return (RCOK);
 
 denied:	a = msg_print(sp, path, &nf1);
-	if (strchr(path, '/') == NULL && getcwd(buf, sizeof(buf)) != NULL) {
+	if (strchr(path, '/') == NULL && (buf = getcwd(NULL, 0)) != NULL) {
+		char *p;
+
 		b = msg_print(sp, buf, &nf2);
+		if ((p = join(b, a)) == NULL) {
+			msgq(sp, M_SYSERR, NULL);
+			goto err;
+		}
 		switch (etype) {
 		case ROOTOWN:
 			msgq(sp, M_ERR,
-			    "125|%s/%s: not sourced: not owned by you or root",
-			    b, a);
+			    "128|%s: not sourced: not owned by you or root", p);
 			break;
 		case OWN:
 			msgq(sp, M_ERR,
-			    "126|%s/%s: not sourced: not owned by you", b, a);
+			    "129|%s: not sourced: not owned by you", p);
 			break;
 		case WRITER:
 			msgq(sp, M_ERR,
-    "127|%s/%s: not sourced: writeable by a user other than the owner", b, a);
+    "130|%s: not sourced: writeable by a user other than the owner", p);
 			break;
 		}
+		free(p);
+err:		free(buf);
 		if (nf2)
 			FREE_SPACE(sp, b, 0);
 	} else

Modified: trunk/contrib/nvi/ex/ex_join.c
===================================================================
--- trunk/contrib/nvi/ex/ex_join.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/ex/ex_join.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -10,11 +10,12 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)ex_join.c	10.10 (Berkeley) 9/15/96";
+static const char sccsid[] = "$Id: ex_join.c,v 10.17 2004/03/16 14:14:04 skimo Exp $";
 #endif /* not lint */
 
 #include <sys/types.h>
 #include <sys/queue.h>
+#include <sys/time.h>
 
 #include <bitstring.h>
 #include <ctype.h>
@@ -32,14 +33,13 @@
  * PUBLIC: int ex_join __P((SCR *, EXCMD *));
  */
 int
-ex_join(sp, cmdp)
-	SCR *sp;
-	EXCMD *cmdp;
+ex_join(SCR *sp, EXCMD *cmdp)
 {
 	recno_t from, to;
 	size_t blen, clen, len, tlen;
-	int echar, extra, first;
-	char *bp, *p, *tbp;
+	int echar = 0, extra, first;
+	CHAR_T *bp, *tbp = NULL;
+	CHAR_T *p;
 
 	NEEDFILE(sp, cmdp);
 
@@ -52,22 +52,15 @@
 		return (1);
 	}
 
-	GET_SPACE_RET(sp, bp, blen, 256);
+	GET_SPACE_RETW(sp, bp, blen, 256);
 
 	/*
 	 * The count for the join command was off-by-one,
 	 * historically, to other counts for other commands.
 	 */
-	if (FL_ISSET(cmdp->iflags, E_C_COUNT))
+	if (F_ISSET(cmdp, E_ADDR_DEF) || cmdp->addrcnt == 1)
 		++cmdp->addr2.lno;
 
-	/*
-	 * If only a single address specified, or, the same address
-	 * specified twice, the from/two addresses will be the same.
-	 */
-	if (cmdp->addr1.lno == cmdp->addr2.lno)
-		++cmdp->addr2.lno;
-
 	clen = tlen = 0;
         for (first = 1,
 	    from = cmdp->addr1.lno, to = cmdp->addr2.lno; from <= to; ++from) {
@@ -90,7 +83,7 @@
 		 * tbp - bp is the length of the new line.
 		 */
 		tlen += len + 2;
-		ADD_SPACE_RET(sp, bp, blen, tlen);
+		ADD_SPACE_RETW(sp, bp, blen, tlen);
 		tbp = bp + clen;
 
 		/*
@@ -114,7 +107,7 @@
 			if (isblank(echar))
 				for (; len && isblank(*p); --len, ++p);
 			else if (p[0] != ')') {
-				if (strchr(".?!", echar)) {
+				if (STRCHR(L(".?!"), echar)) {
 					*tbp++ = ' ';
 					++clen;
 					extra = 1;
@@ -126,7 +119,7 @@
 		}
 
 		if (len != 0) {
-			memcpy(tbp, p, len);
+			MEMCPY(tbp, p, len);
 			tbp += len;
 			clen += len;
 			echar = p[len - 1];
@@ -167,10 +160,10 @@
 
 	/* If the original line changed, reset it. */
 	if (!first && db_set(sp, from, bp, tbp - bp)) {
-err:		FREE_SPACE(sp, bp, blen);
+err:		FREE_SPACEW(sp, bp, blen);
 		return (1);
 	}
-	FREE_SPACE(sp, bp, blen);
+	FREE_SPACEW(sp, bp, blen);
 
 	sp->rptlines[L_JOINED] += (cmdp->addr2.lno - cmdp->addr1.lno) + 1;
 	return (0);

Modified: trunk/contrib/nvi/ex/ex_map.c
===================================================================
--- trunk/contrib/nvi/ex/ex_map.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/ex/ex_map.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -10,11 +10,12 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)ex_map.c	10.9 (Berkeley) 3/6/96";
+static const char sccsid[] = "$Id: ex_map.c,v 10.11 2001/06/25 15:19:17 skimo Exp $";
 #endif /* not lint */
 
 #include <sys/types.h>
 #include <sys/queue.h>
+#include <sys/time.h>
 
 #include <bitstring.h>
 #include <ctype.h>
@@ -42,9 +43,7 @@
  * PUBLIC: int ex_map __P((SCR *, EXCMD *));
  */
 int
-ex_map(sp, cmdp)
-	SCR *sp;
-	EXCMD *cmdp;
+ex_map(SCR *sp, EXCMD *cmdp)
 {
 	seq_t stype;
 	CHAR_T *input, *p;
@@ -107,13 +106,11 @@
  * PUBLIC: int ex_unmap __P((SCR *, EXCMD *));
  */
 int
-ex_unmap(sp, cmdp)
-	SCR *sp;
-	EXCMD *cmdp;
+ex_unmap(SCR *sp, EXCMD *cmdp)
 {
 	if (seq_delete(sp, cmdp->argv[0]->bp, cmdp->argv[0]->len,
 	    FL_ISSET(cmdp->iflags, E_C_FORCE) ? SEQ_INPUT : SEQ_COMMAND)) {
-		msgq_str(sp, M_INFO,
+		msgq_wstr(sp, M_INFO,
 		    cmdp->argv[0]->bp, "135|\"%s\" isn't currently mapped");
 		return (1);
 	}

Modified: trunk/contrib/nvi/ex/ex_mark.c
===================================================================
--- trunk/contrib/nvi/ex/ex_mark.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/ex/ex_mark.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -10,11 +10,12 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)ex_mark.c	10.8 (Berkeley) 3/6/96";
+static const char sccsid[] = "$Id: ex_mark.c,v 10.9 2001/06/25 15:19:17 skimo Exp $";
 #endif /* not lint */
 
 #include <sys/types.h>
 #include <sys/queue.h>
+#include <sys/time.h>
 
 #include <bitstring.h>
 #include <limits.h>
@@ -31,9 +32,7 @@
  * PUBLIC: int ex_mark __P((SCR *, EXCMD *));
  */
 int
-ex_mark(sp, cmdp)
-	SCR *sp;
-	EXCMD *cmdp;
+ex_mark(SCR *sp, EXCMD *cmdp)
 {
 	NEEDFILE(sp, cmdp);
 

Modified: trunk/contrib/nvi/ex/ex_mkexrc.c
===================================================================
--- trunk/contrib/nvi/ex/ex_mkexrc.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/ex/ex_mkexrc.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -10,7 +10,7 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)ex_mkexrc.c	10.11 (Berkeley) 3/6/96";
+static const char sccsid[] = "$Id: ex_mkexrc.c,v 10.13 2001/06/25 15:19:17 skimo Exp $";
 #endif /* not lint */
 
 #include <sys/types.h>
@@ -37,14 +37,13 @@
  * PUBLIC: int ex_mkexrc __P((SCR *, EXCMD *));
  */
 int
-ex_mkexrc(sp, cmdp)
-	SCR *sp;
-	EXCMD *cmdp;
+ex_mkexrc(SCR *sp, EXCMD *cmdp)
 {
 	struct stat sb;
 	FILE *fp;
 	int fd, sverrno;
 	char *fname;
+	size_t flen;
 
 	switch (cmdp->argc) {
 	case 0:
@@ -51,7 +50,8 @@
 		fname = _PATH_EXRC;
 		break;
 	case 1:
-		fname = cmdp->argv[0]->bp;
+		INT2CHAR(sp, cmdp->argv[0]->bp, cmdp->argv[0]->len + 1, 
+			    fname, flen);
 		set_alt_name(sp, fname);
 		break;
 	default:

Modified: trunk/contrib/nvi/ex/ex_move.c
===================================================================
--- trunk/contrib/nvi/ex/ex_move.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/ex/ex_move.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -10,11 +10,12 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)ex_move.c	10.10 (Berkeley) 9/15/96";
+static const char sccsid[] = "$Id: ex_move.c,v 10.16 2012/02/11 15:52:33 zy Exp $";
 #endif /* not lint */
 
 #include <sys/types.h>
 #include <sys/queue.h>
+#include <sys/time.h>
 
 #include <bitstring.h>
 #include <limits.h>
@@ -31,11 +32,9 @@
  * PUBLIC: int ex_copy __P((SCR *, EXCMD *));
  */
 int
-ex_copy(sp, cmdp)
-	SCR *sp;
-	EXCMD *cmdp;
+ex_copy(SCR *sp, EXCMD *cmdp)
 {
-	CB cb;
+	CB cb = {{ 0 }};
 	MARK fm1, fm2, m, tm;
 	recno_t cnt;
 	int rval;
@@ -51,10 +50,9 @@
 	 */
 	fm1 = cmdp->addr1;
 	fm2 = cmdp->addr2;
-	memset(&cb, 0, sizeof(cb));
-	CIRCLEQ_INIT(&cb.textq);
+	TAILQ_INIT(cb.textq);
 	for (cnt = fm1.lno; cnt <= fm2.lno; ++cnt)
-		if (cut_line(sp, cnt, 0, 0, &cb)) {
+		if (cut_line(sp, cnt, 0, ENTIRE_LINE, &cb)) {
 			rval = 1;
 			goto err;
 		}
@@ -75,7 +73,7 @@
 		sp->lno = m.lno + (cnt - 1);
 		sp->cno = 0;
 	}
-err:	text_lfree(&cb.textq);
+err:	text_lfree(cb.textq);
 	return (rval);
 }
 
@@ -86,9 +84,7 @@
  * PUBLIC: int ex_move __P((SCR *, EXCMD *));
  */
 int
-ex_move(sp, cmdp)
-	SCR *sp;
-	EXCMD *cmdp;
+ex_move(SCR *sp, EXCMD *cmdp)
 {
 	LMARK *lmp;
 	MARK fm1, fm2;
@@ -95,7 +91,8 @@
 	recno_t cnt, diff, fl, tl, mfl, mtl;
 	size_t blen, len;
 	int mark_reset;
-	char *bp, *p;
+	CHAR_T *bp;
+	CHAR_T *p;
 
 	NEEDFILE(sp, cmdp);
 
@@ -126,7 +123,7 @@
 
 	/* Log the old positions of the marks. */
 	mark_reset = 0;
-	for (lmp = sp->ep->marks.lh_first; lmp != NULL; lmp = lmp->q.le_next)
+	SLIST_FOREACH(lmp, sp->ep->marks, q)
 		if (lmp->name != ABSMARK1 &&
 		    lmp->lno >= fl && lmp->lno <= tl) {
 			mark_reset = 1;
@@ -135,7 +132,7 @@
 		}
 
 	/* Get memory for the copy. */
-	GET_SPACE_RET(sp, bp, blen, 256);
+	GET_SPACE_RETW(sp, bp, blen, 256);
 
 	/* Move the lines. */
 	diff = (fm2.lno - fm1.lno) + 1;
@@ -145,13 +142,12 @@
 		for (cnt = diff; cnt--;) {
 			if (db_get(sp, fl, DBG_FATAL, &p, &len))
 				return (1);
-			BINC_RET(sp, bp, blen, len);
-			memcpy(bp, p, len);
+			BINC_RETW(sp, bp, blen, len);
+			MEMCPY(bp, p, len);
 			if (db_append(sp, 1, tl, bp, len))
 				return (1);
 			if (mark_reset)
-				for (lmp = sp->ep->marks.lh_first;
-				    lmp != NULL; lmp = lmp->q.le_next)
+				SLIST_FOREACH(lmp, sp->ep->marks, q)
 					if (lmp->name != ABSMARK1 &&
 					    lmp->lno == fl)
 						lmp->lno = tl + 1;
@@ -164,13 +160,12 @@
 		for (cnt = diff; cnt--;) {
 			if (db_get(sp, fl, DBG_FATAL, &p, &len))
 				return (1);
-			BINC_RET(sp, bp, blen, len);
-			memcpy(bp, p, len);
+			BINC_RETW(sp, bp, blen, len);
+			MEMCPY(bp, p, len);
 			if (db_append(sp, 1, tl++, bp, len))
 				return (1);
 			if (mark_reset)
-				for (lmp = sp->ep->marks.lh_first;
-				    lmp != NULL; lmp = lmp->q.le_next)
+				SLIST_FOREACH(lmp, sp->ep->marks, q)
 					if (lmp->name != ABSMARK1 &&
 					    lmp->lno == fl)
 						lmp->lno = tl;
@@ -179,7 +174,7 @@
 				return (1);
 		}
 	}
-	FREE_SPACE(sp, bp, blen);
+	FREE_SPACEW(sp, bp, blen);
 
 	sp->lno = tl;				/* Last line moved. */
 	sp->cno = 0;
@@ -186,8 +181,7 @@
 
 	/* Log the new positions of the marks. */
 	if (mark_reset)
-		for (lmp = sp->ep->marks.lh_first;
-		    lmp != NULL; lmp = lmp->q.le_next)
+		SLIST_FOREACH(lmp, sp->ep->marks, q)
 			if (lmp->name != ABSMARK1 &&
 			    lmp->lno >= mfl && lmp->lno <= mtl)
 				(void)log_mark(sp, lmp);

Modified: trunk/contrib/nvi/ex/ex_open.c
===================================================================
--- trunk/contrib/nvi/ex/ex_open.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/ex/ex_open.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -10,11 +10,12 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)ex_open.c	10.7 (Berkeley) 3/6/96";
+static const char sccsid[] = "$Id: ex_open.c,v 10.8 2001/06/25 15:19:17 skimo Exp $";
 #endif /* not lint */
 
 #include <sys/types.h>
 #include <sys/queue.h>
+#include <sys/time.h>
 
 #include <bitstring.h>
 #include <limits.h>
@@ -30,9 +31,7 @@
  * PUBLIC: int ex_open __P((SCR *, EXCMD *));
  */
 int
-ex_open(sp, cmdp)
-	SCR *sp;
-	EXCMD *cmdp;
+ex_open(SCR *sp, EXCMD *cmdp)
 {
 	/* If open option off, disallow open command. */
 	if (!O_ISSET(sp, O_OPEN)) {

Modified: trunk/contrib/nvi/ex/ex_preserve.c
===================================================================
--- trunk/contrib/nvi/ex/ex_preserve.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/ex/ex_preserve.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -10,11 +10,12 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)ex_preserve.c	10.12 (Berkeley) 4/27/96";
+static const char sccsid[] = "$Id: ex_preserve.c,v 10.15 2001/06/25 15:19:18 skimo Exp $";
 #endif /* not lint */
 
 #include <sys/types.h>
 #include <sys/queue.h>
+#include <sys/time.h>
 
 #include <bitstring.h>
 #include <errno.h>
@@ -31,9 +32,7 @@
  * PUBLIC: int ex_preserve __P((SCR *, EXCMD *));
  */
 int
-ex_preserve(sp, cmdp)
-	SCR *sp;
-	EXCMD *cmdp;
+ex_preserve(SCR *sp, EXCMD *cmdp)
 {
 	recno_t lno;
 
@@ -67,17 +66,18 @@
  * PUBLIC: int ex_recover __P((SCR *, EXCMD *));
  */
 int
-ex_recover(sp, cmdp)
-	SCR *sp;
-	EXCMD *cmdp;
+ex_recover(SCR *sp, EXCMD *cmdp)
 {
 	ARGS *ap;
 	FREF *frp;
+	char *np;
+	size_t nlen;
 
 	ap = cmdp->argv[0];
 
 	/* Set the alternate file name. */
-	set_alt_name(sp, ap->bp);
+	INT2CHAR(sp, ap->bp, ap->len+1, np, nlen);
+	set_alt_name(sp, np);
 
 	/*
 	 * Check for modifications.  Autowrite did not historically
@@ -87,7 +87,8 @@
 		return (1);
 
 	/* Get a file structure for the file. */
-	if ((frp = file_add(sp, ap->bp)) == NULL)
+	INT2CHAR(sp, ap->bp, ap->len+1, np, nlen);
+	if ((frp = file_add(sp, np)) == NULL)
 		return (1);
 
 	/* Set the recover bit. */

Modified: trunk/contrib/nvi/ex/ex_print.c
===================================================================
--- trunk/contrib/nvi/ex/ex_print.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/ex/ex_print.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -10,27 +10,24 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)ex_print.c	10.18 (Berkeley) 5/12/96";
+static const char sccsid[] = "$Id: ex_print.c,v 10.26 2013/11/02 02:11:07 zy Exp $";
 #endif /* not lint */
 
 #include <sys/types.h>
 #include <sys/queue.h>
+#include <sys/time.h>
 
 #include <bitstring.h>
 #include <ctype.h>
 #include <limits.h>
+#include <stdarg.h>
 #include <stdio.h>
 #include <string.h>
 
-#ifdef __STDC__
-#include <stdarg.h>
-#else
-#include <varargs.h>
-#endif
-
 #include "../common/common.h"
 
-static int ex_prchars __P((SCR *, const char *, size_t *, size_t, u_int, int));
+static int ex_prchars __P((SCR *, const CHAR_T *, size_t *, size_t, 
+                           u_int, int));
 
 /*
  * ex_list -- :[line [,line]] l[ist] [count] [flags]
@@ -40,9 +37,7 @@
  * PUBLIC: int ex_list __P((SCR *, EXCMD *));
  */
 int
-ex_list(sp, cmdp)
-	SCR *sp;
-	EXCMD *cmdp;
+ex_list(SCR *sp, EXCMD *cmdp)
 {
 	if (ex_print(sp, cmdp,
 	    &cmdp->addr1, &cmdp->addr2, cmdp->iflags | E_C_LIST))
@@ -60,9 +55,7 @@
  * PUBLIC: int ex_number __P((SCR *, EXCMD *));
  */
 int
-ex_number(sp, cmdp)
-	SCR *sp;
-	EXCMD *cmdp;
+ex_number(SCR *sp, EXCMD *cmdp)
 {
 	if (ex_print(sp, cmdp,
 	    &cmdp->addr1, &cmdp->addr2, cmdp->iflags | E_C_HASH))
@@ -80,9 +73,7 @@
  * PUBLIC: int ex_pr __P((SCR *, EXCMD *));
  */
 int
-ex_pr(sp, cmdp)
-	SCR *sp;
-	EXCMD *cmdp;
+ex_pr(SCR *sp, EXCMD *cmdp)
 {
 	if (ex_print(sp, cmdp, &cmdp->addr1, &cmdp->addr2, cmdp->iflags))
 		return (1);
@@ -98,16 +89,13 @@
  * PUBLIC: int ex_print __P((SCR *, EXCMD *, MARK *, MARK *, u_int32_t));
  */
 int
-ex_print(sp, cmdp, fp, tp, flags)
-	SCR *sp;
-	EXCMD *cmdp;
-	MARK *fp, *tp;
-	u_int32_t flags;
+ex_print(SCR *sp, EXCMD *cmdp, MARK *fp, MARK *tp, u_int32_t flags)
 {
 	GS *gp;
 	recno_t from, to;
 	size_t col, len;
-	char *p, buf[10];
+	CHAR_T *p;
+	CHAR_T buf[10];
 
 	NEEDFILE(sp, cmdp);
 
@@ -122,11 +110,10 @@
 		 */
 		if (LF_ISSET(E_C_HASH)) {
 			if (from <= 999999) {
-				snprintf(buf, sizeof(buf), "%6lu  ",
-				    (u_long)from);
+				SPRINTF(buf, SIZE(buf), L("%6u  "), from);
 				p = buf;
 			} else
-				p = "TOOBIG  ";
+				p = L("TOOBIG  ");
 			if (ex_prchars(sp, p, &col, 8, 0, 0))
 				return (1);
 		}
@@ -154,19 +141,15 @@
  * ex_ldisplay --
  *	Display a line without any preceding number.
  *
- * PUBLIC: int ex_ldisplay __P((SCR *, const char *, size_t, size_t, u_int));
+ * PUBLIC: int ex_ldisplay __P((SCR *, const CHAR_T *, size_t, size_t, u_int));
  */
 int
-ex_ldisplay(sp, p, len, col, flags)
-	SCR *sp;
-	const char *p;
-	size_t len, col;
-	u_int flags;
+ex_ldisplay(SCR *sp, const CHAR_T *p, size_t len, size_t col, u_int flags)
 {
 	if (len > 0 && ex_prchars(sp, p, &col, len, LF_ISSET(E_C_LIST), 0))
 		return (1);
 	if (!INTERRUPTED(sp) && LF_ISSET(E_C_LIST)) {
-		p = "$";
+		p = L("$");
 		if (ex_prchars(sp, p, &col, 1, LF_ISSET(E_C_LIST), 0))
 			return (1);
 	}
@@ -182,21 +165,19 @@
  * PUBLIC: int ex_scprint __P((SCR *, MARK *, MARK *));
  */
 int
-ex_scprint(sp, fp, tp)
-	SCR *sp;
-	MARK *fp, *tp;
+ex_scprint(SCR *sp, MARK *fp, MARK *tp)
 {
-	const char *p;
+	CHAR_T *p;
 	size_t col, len;
 
 	col = 0;
 	if (O_ISSET(sp, O_NUMBER)) {
-		p = "        ";
+		p = L("        ");
 		if (ex_prchars(sp, p, &col, 8, 0, 0))
 			return (1);
 	}
 
-	if (db_get(sp, fp->lno, DBG_FATAL, (char **)&p, &len))
+	if (db_get(sp, fp->lno, DBG_FATAL, &p, &len))
 		return (1);
 
 	if (ex_prchars(sp, p, &col, fp->cno, 0, ' '))
@@ -207,7 +188,7 @@
 		return (1);
 	if (INTERRUPTED(sp))
 		return (1);
-	p = "[ynq]";		/* XXX: should be msg_cat. */
+	p = L("[ynq]");		/* XXX: should be msg_cat. */
 	if (ex_prchars(sp, p, &col, 5, 0, 0))
 		return (1);
 	(void)ex_fflush(sp);
@@ -219,14 +200,11 @@
  *	Local routine to dump characters to the screen.
  */
 static int
-ex_prchars(sp, p, colp, len, flags, repeatc)
-	SCR *sp;
-	const char *p;
-	size_t *colp, len;
-	u_int flags;
-	int repeatc;
+ex_prchars(SCR *sp, const CHAR_T *p, size_t *colp, size_t len, 
+	    u_int flags, int repeatc)
 {
-	CHAR_T ch, *kp;
+	CHAR_T ch;
+	char *kp;
 	GS *gp;
 	size_t col, tlen, ts;
 
@@ -235,7 +213,7 @@
 	gp = sp->gp;
 	ts = O_VAL(sp, O_TABSTOP);
 	for (col = *colp; len--;)
-		if ((ch = *p++) == '\t' && !LF_ISSET(E_C_LIST))
+		if ((ch = *p++) == L('\t') && !LF_ISSET(E_C_LIST))
 			for (tlen = ts - col % ts;
 			    col < sp->cols && tlen--; ++col) {
 				(void)ex_printf(sp,
@@ -245,21 +223,32 @@
 			}
 		else {
 			kp = KEY_NAME(sp, ch);
-			tlen = KEY_LEN(sp, ch);
-			if (!repeatc  && col + tlen < sp->cols) {
+			tlen = KEY_COL(sp, ch);
+
+			/*
+			 * Start a new line if the last character does not fit
+			 * into the current line.  The implicit new lines are
+			 * not interruptible.
+			 */
+			if (col + tlen > sp->cols) {
+				col = 0;
+				(void)ex_puts(sp, "\n");
+			}
+
+			col += tlen;
+			if (!repeatc) {
 				(void)ex_puts(sp, kp);
-				col += tlen;
-			} else
-				for (; tlen--; ++kp, ++col) {
-					if (col == sp->cols) {
-						col = 0;
-						(void)ex_puts(sp, "\n");
-					}
-					(void)ex_printf(sp,
-					    "%c", repeatc ? repeatc : *kp);
-					if (INTERRUPTED(sp))
-						goto intr;
-				}
+				if (INTERRUPTED(sp))
+					goto intr;
+			} else while (tlen--) {
+				(void)ex_printf(sp, "%c", repeatc);
+				if (INTERRUPTED(sp))
+					goto intr;
+			}
+			if (col == sp->cols) {
+				col = 0;
+				(void)ex_puts(sp, "\n");
+			}
 		}
 intr:	*colp = col;
 	return (0);
@@ -272,14 +261,10 @@
  * PUBLIC: int ex_printf __P((SCR *, const char *, ...));
  */
 int
-#ifdef __STDC__
-ex_printf(SCR *sp, const char *fmt, ...)
-#else
-ex_printf(sp, fmt, va_alist)
-	SCR *sp;
-	const char *fmt;
-	va_dcl
-#endif
+ex_printf(
+	SCR *sp,
+	const char *fmt,
+	...)
 {
 	EX_PRIVATE *exp;
 	va_list ap;
@@ -287,11 +272,7 @@
 
 	exp = EXP(sp);
 
-#ifdef __STDC__
 	va_start(ap, fmt);
-#else
-	va_start(ap);
-#endif
 	exp->obp_len += n = vsnprintf(exp->obp + exp->obp_len,
 	    sizeof(exp->obp) - exp->obp_len, fmt, ap);
 	va_end(ap);
@@ -310,9 +291,7 @@
  * PUBLIC: int ex_puts __P((SCR *, const char *));
  */
 int
-ex_puts(sp, str)
-	SCR *sp;
-	const char *str;
+ex_puts(SCR *sp, const char *str)
 {
 	EX_PRIVATE *exp;
 	int doflush, n;
@@ -338,8 +317,7 @@
  * PUBLIC: int ex_fflush __P((SCR *sp));
  */
 int
-ex_fflush(sp)
-	SCR *sp;
+ex_fflush(SCR *sp)
 {
 	EX_PRIVATE *exp;
 

Modified: trunk/contrib/nvi/ex/ex_put.c
===================================================================
--- trunk/contrib/nvi/ex/ex_put.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/ex/ex_put.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -10,11 +10,12 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)ex_put.c	10.7 (Berkeley) 3/6/96";
+static const char sccsid[] = "$Id: ex_put.c,v 10.8 2001/06/25 15:19:18 skimo Exp $";
 #endif /* not lint */
 
 #include <sys/types.h>
 #include <sys/queue.h>
+#include <sys/time.h>
 
 #include <bitstring.h>
 #include <ctype.h>
@@ -31,9 +32,7 @@
  * PUBLIC: int ex_put __P((SCR *, EXCMD *));
  */
 int
-ex_put(sp, cmdp)
-	SCR *sp;
-	EXCMD *cmdp;
+ex_put(SCR *sp, EXCMD *cmdp)
 {
 	MARK m;
 

Modified: trunk/contrib/nvi/ex/ex_quit.c
===================================================================
--- trunk/contrib/nvi/ex/ex_quit.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/ex/ex_quit.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -10,11 +10,12 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)ex_quit.c	10.7 (Berkeley) 4/27/96";
+static const char sccsid[] = "$Id: ex_quit.c,v 10.8 2001/06/25 15:19:18 skimo Exp $";
 #endif /* not lint */
 
 #include <sys/types.h>
 #include <sys/queue.h>
+#include <sys/time.h>
 
 #include <bitstring.h>
 #include <limits.h>
@@ -29,9 +30,7 @@
  * PUBLIC: int ex_quit __P((SCR *, EXCMD *));
  */
 int
-ex_quit(sp, cmdp)
-	SCR *sp;
-	EXCMD *cmdp;
+ex_quit(SCR *sp, EXCMD *cmdp)
 {
 	int force;
 

Modified: trunk/contrib/nvi/ex/ex_read.c
===================================================================
--- trunk/contrib/nvi/ex/ex_read.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/ex/ex_read.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -10,13 +10,12 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)ex_read.c	10.38 (Berkeley) 8/12/96";
+static const char sccsid[] = "$Id: ex_read.c,v 10.44 2001/06/25 15:19:19 skimo Exp $";
 #endif /* not lint */
 
 #include <sys/types.h>
 #include <sys/queue.h>
 #include <sys/stat.h>
-#include <sys/time.h>
 
 #include <bitstring.h>
 #include <ctype.h>
@@ -40,13 +39,13 @@
  * PUBLIC: int ex_read __P((SCR *, EXCMD *));
  */
 int
-ex_read(sp, cmdp)
-	SCR *sp;
-	EXCMD *cmdp;
+ex_read(SCR *sp, EXCMD *cmdp)
 {
 	enum { R_ARG, R_EXPANDARG, R_FILTER } which;
 	struct stat sb;
-	CHAR_T *arg, *name;
+	CHAR_T *arg = NULL;
+	char *name = NULL;
+	size_t nlen;
 	EX_PRIVATE *exp;
 	FILE *fp;
 	FREF *frp;
@@ -53,7 +52,7 @@
 	GS *gp;
 	MARK rm;
 	recno_t nlines;
-	size_t arglen;
+	size_t arglen = 0;
 	int argc, rval;
 	char *p;
 
@@ -77,7 +76,7 @@
 
 			/* Secure means no shell access. */
 			if (O_ISSET(sp, O_SECURE)) {
-				ex_emsg(sp, cmdp->cmd->name, EXM_SECURE_F);
+				ex_wemsg(sp, cmdp->cmd->name, EXM_SECURE_F);
 				return (1);
 			}
 		} else
@@ -116,7 +115,8 @@
 		if (exp->lastbcomm != NULL)
 			free(exp->lastbcomm);
 		if ((exp->lastbcomm =
-		    strdup(cmdp->argv[argc]->bp)) == NULL) {
+		    v_wstrdup(sp, cmdp->argv[argc]->bp,
+				cmdp->argv[argc]->len)) == NULL) {
 			msgq(sp, M_SYSERR, NULL);
 			return (1);
 		}
@@ -132,7 +132,7 @@
 		} else {
 			if (F_ISSET(cmdp, E_MODIFY))
 				(void)ex_printf(sp,
-				    "!%s\n", cmdp->argv[argc]->bp);
+				    "!"WS"\n", cmdp->argv[argc]->bp);
 			else
 				(void)ex_puts(sp, "!\n");
 			(void)ex_fflush(sp);
@@ -157,7 +157,7 @@
 		 */
 		if (F_ISSET(sp, SC_VI)) {
 			if (gp->scr_screen(sp, SC_EX)) {
-				ex_emsg(sp, cmdp->cmd->name, EXM_NOCANON_F);
+				ex_wemsg(sp, cmdp->cmd->name, EXM_NOCANON_F);
 				return (1);
 			}
 			/*
@@ -207,7 +207,8 @@
 			abort();
 			/* NOTREACHED */
 		case 2:
-			name = cmdp->argv[1]->bp;
+			INT2CHAR(sp, cmdp->argv[1]->bp, cmdp->argv[1]->len + 1, 
+				 name, nlen);
 			/*
 			 * !!!
 			 * Historically, the read and write commands renamed
@@ -216,8 +217,7 @@
 			 */
 			if (F_ISSET(sp->frp, FR_TMPFILE) &&
 			    !F_ISSET(sp->frp, FR_EXNAMED)) {
-				if ((p = v_strdup(sp, cmdp->argv[1]->bp,
-				    cmdp->argv[1]->len)) != NULL) {
+				if ((p = strdup(name)) != NULL) {
 					free(sp->frp->name);
 					sp->frp->name = p;
 				}
@@ -230,11 +230,14 @@
 
 				/* Notify the screen. */
 				(void)sp->gp->scr_rename(sp, sp->frp->name, 1);
-			} else
+				name = sp->frp->name;
+			} else {
 				set_alt_name(sp, name);
+				name = sp->alt_name;
+			}
 			break;
 		default:
-			ex_emsg(sp, cmdp->argv[0]->bp, EXM_FILECOUNT);
+			ex_wemsg(sp, cmdp->argv[0]->bp, EXM_FILECOUNT);
 			return (1);
 		
 		}
@@ -261,7 +264,7 @@
 	}
 
 	/* Try and get a lock. */
-	if (file_lock(sp, NULL, NULL, fileno(fp), 0) == LOCK_UNAVAIL)
+	if (file_lock(sp, NULL, fileno(fp), 0) == LOCK_UNAVAIL)
 		msgq(sp, M_ERR, "146|%s: read lock was unavailable", name);
 
 	rval = ex_readfp(sp, name, fp, &cmdp->addr1, &nlines, 0);
@@ -291,13 +294,7 @@
  * PUBLIC: int ex_readfp __P((SCR *, char *, FILE *, MARK *, recno_t *, int));
  */
 int
-ex_readfp(sp, name, fp, fm, nlinesp, silent)
-	SCR *sp;
-	char *name;
-	FILE *fp;
-	MARK *fm;
-	recno_t *nlinesp;
-	int silent;
+ex_readfp(SCR *sp, char *name, FILE *fp, MARK *fm, recno_t *nlinesp, int silent)
 {
 	EX_PRIVATE *exp;
 	GS *gp;
@@ -306,6 +303,8 @@
 	u_long ccnt;			/* XXX: can't print off_t portably. */
 	int nf, rval;
 	char *p;
+	size_t wlen;
+	CHAR_T *wp;
 
 	gp = sp->gp;
 	exp = EXP(sp);
@@ -327,7 +326,8 @@
 				p = NULL;
 			}
 		}
-		if (db_append(sp, 1, lno, exp->ibp, len))
+		FILE2INT5(sp, exp->ibcw, exp->ibp, len, wp, wlen);
+		if (db_append(sp, 1, lno, wp, wlen))
 			goto err;
 		ccnt += len;
 	}
@@ -342,7 +342,8 @@
 	if (!silent) {
 		p = msg_print(sp, name, &nf);
 		msgq(sp, M_INFO,
-		    "148|%s: %lu lines, %lu characters", p, lcnt, ccnt);
+		    "148|%s: %lu lines, %lu characters", p,
+		    (u_long)lcnt, ccnt);
 		if (nf)
 			FREE_SPACE(sp, p, 0);
 	}

Modified: trunk/contrib/nvi/ex/ex_screen.c
===================================================================
--- trunk/contrib/nvi/ex/ex_screen.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/ex/ex_screen.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -10,7 +10,7 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)ex_screen.c	10.11 (Berkeley) 6/29/96";
+static const char sccsid[] = "$Id: ex_screen.c,v 10.12 2001/06/25 15:19:19 skimo Exp $";
 #endif /* not lint */
 
 #include <sys/types.h>
@@ -33,9 +33,7 @@
  * PUBLIC: int ex_bg __P((SCR *, EXCMD *));
  */
 int
-ex_bg(sp, cmdp)
-	SCR *sp;
-	EXCMD *cmdp;
+ex_bg(SCR *sp, EXCMD *cmdp)
 {
 	return (vs_bg(sp));
 }
@@ -47,9 +45,7 @@
  * PUBLIC: int ex_fg __P((SCR *, EXCMD *));
  */
 int
-ex_fg(sp, cmdp)
-	SCR *sp;
-	EXCMD *cmdp;
+ex_fg(SCR *sp, EXCMD *cmdp)
 {
 	SCR *nsp;
 	int newscreen;
@@ -73,9 +69,7 @@
  * PUBLIC: int ex_resize __P((SCR *, EXCMD *));
  */
 int
-ex_resize(sp, cmdp)
-	SCR *sp;
-	EXCMD *cmdp;
+ex_resize(SCR *sp, EXCMD *cmdp)
 {
 	adj_t adj;
 
@@ -104,8 +98,7 @@
  * PUBLIC: int ex_sdisplay __P((SCR *));
  */
 int
-ex_sdisplay(sp)
-	SCR *sp;
+ex_sdisplay(SCR *sp)
 {
 	GS *gp;
 	SCR *tsp;
@@ -112,14 +105,14 @@
 	int cnt, col, len, sep;
 
 	gp = sp->gp;
-	if ((tsp = gp->hq.cqh_first) == (void *)&gp->hq) {
+	if ((tsp = TAILQ_FIRST(gp->hq)) == NULL) {
 		msgq(sp, M_INFO, "149|No background screens to display");
 		return (0);
 	}
 
 	col = len = sep = 0;
-	for (cnt = 1; tsp != (void *)&gp->hq && !INTERRUPTED(sp);
-	    tsp = tsp->q.cqe_next) {
+	for (cnt = 1; tsp != NULL && !INTERRUPTED(sp);
+	    tsp = TAILQ_NEXT(tsp, q)) {
 		col += len = strlen(tsp->frp->name) + sep;
 		if (col >= sp->cols - 1) {
 			col = len;

Modified: trunk/contrib/nvi/ex/ex_script.c
===================================================================
--- trunk/contrib/nvi/ex/ex_script.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/ex/ex_script.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -13,32 +13,32 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)ex_script.c	10.30 (Berkeley) 9/24/96";
+static const char sccsid[] = "$Id: ex_script.c,v 10.44 2012/10/05 10:17:47 zy Exp $";
 #endif /* not lint */
 
 #include <sys/types.h>
 #include <sys/ioctl.h>
 #include <sys/queue.h>
-#ifdef HAVE_SYS_SELECT_H
 #include <sys/select.h>
-#endif
 #include <sys/stat.h>
-#ifdef HAVE_SYS5_PTY
-#include <sys/stropts.h>
-#endif
-#include <sys/time.h>
 #include <sys/wait.h>
 
 #include <bitstring.h>
 #include <errno.h>
 #include <fcntl.h>
-#include <stdio.h>		/* XXX: OSF/1 bug: include before <grp.h> */
 #include <grp.h>
 #include <limits.h>
+#include <signal.h>
+#include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <termios.h>
 #include <unistd.h>
+#ifdef HAVE_LIBUTIL_H
+#include <libutil.h>
+#else
+#include <util.h>
+#endif
 
 #include "../common/common.h"
 #include "../vi/vi.h"
@@ -50,7 +50,6 @@
 static int	sscr_init __P((SCR *));
 static int	sscr_insert __P((SCR *));
 static int	sscr_matchprompt __P((SCR *, char *, size_t, size_t *));
-static int	sscr_pty __P((int *, int *, char *, struct termios *, void *));
 static int	sscr_setprompt __P((SCR *, char *, size_t));
 
 /*
@@ -60,9 +59,7 @@
  * PUBLIC: int ex_script __P((SCR *, EXCMD *));
  */
 int
-ex_script(sp, cmdp)
-	SCR *sp;
-	EXCMD *cmdp;
+ex_script(SCR *sp, EXCMD *cmdp)
 {
 	/* Vi only command. */
 	if (!F_ISSET(sp, SC_VI)) {
@@ -87,8 +84,7 @@
  *	Create a pty setup for a shell.
  */
 static int
-sscr_init(sp)
-	SCR *sp;
+sscr_init(SCR *sp)
 {
 	SCRIPT *sc;
 	char *sh, *sh_path;
@@ -119,24 +115,16 @@
 	sc->sh_term.c_oflag &= ~OPOST;
 	sc->sh_term.c_cflag &= ~(ECHO|ECHOE|ECHONL|ECHOK);
 
-#ifdef TIOCGWINSZ
 	if (ioctl(STDIN_FILENO, TIOCGWINSZ, &sc->sh_win) == -1) {
 		msgq(sp, M_SYSERR, "tcgetattr");
 		goto err;
 	}
 
-	if (sscr_pty(&sc->sh_master,
+	if (openpty(&sc->sh_master,
 	    &sc->sh_slave, sc->sh_name, &sc->sh_term, &sc->sh_win) == -1) {
-		msgq(sp, M_SYSERR, "pty");
+		msgq(sp, M_SYSERR, "openpty");
 		goto err;
 	}
-#else
-	if (sscr_pty(&sc->sh_master,
-	    &sc->sh_slave, sc->sh_name, &sc->sh_term, NULL) == -1) {
-		msgq(sp, M_SYSERR, "pty");
-		goto err;
-	}
-#endif
 
 	/*
 	 * __TK__ huh?
@@ -203,18 +191,21 @@
  *	carriage return comes; set the prompt from that line.
  */
 static int
-sscr_getprompt(sp)
-	SCR *sp;
+sscr_getprompt(SCR *sp)
 {
+	EX_PRIVATE *exp;
 	struct timeval tv;
-	CHAR_T *endp, *p, *t, buf[1024];
+	char *endp, *p, *t, buf[1024];
 	SCRIPT *sc;
 	fd_set fdset;
 	recno_t lline;
 	size_t llen, len;
-	u_int value;
 	int nr;
+	CHAR_T *wp;
+	size_t wlen;
 
+	exp = EXP(sp);
+
 	FD_ZERO(&fdset);
 	endp = buf;
 	len = sizeof(buf);
@@ -251,10 +242,11 @@
 
 	/* If any complete lines, push them into the file. */
 	for (p = t = buf; p < endp; ++p) {
-		value = KEY_VAL(sp, *p);
-		if (value == K_CR || value == K_NL) {
+		if (*p == '\r' || *p == '\n') {
+			if (CHAR2INT5(sp, exp->ibcw, t, p - t, wp, wlen))
+				goto conv_err;
 			if (db_last(sp, &lline) ||
-			    db_append(sp, 0, lline, t, p - t))
+			    db_append(sp, 0, lline, wp, wlen))
 				goto prompterr;
 			t = p + 1;
 		}
@@ -284,7 +276,11 @@
 	endp = buf;
 
 	/* Append the line into the file. */
-	if (db_last(sp, &lline) || db_append(sp, 0, lline, buf, llen)) {
+	if (CHAR2INT5(sp, exp->ibcw, buf, llen, wp, wlen))
+		goto conv_err;
+	if (db_last(sp, &lline) || db_append(sp, 0, lline, wp, wlen)) {
+		if (0)
+conv_err:		msgq(sp, M_ERR, "323|Invalid input. Truncated.");
 prompterr:	sscr_end(sp);
 		return (1);
 	}
@@ -299,30 +295,31 @@
  * PUBLIC: int sscr_exec __P((SCR *, recno_t));
  */
 int
-sscr_exec(sp, lno)
-	SCR *sp;
-	recno_t lno;
+sscr_exec(SCR *sp, recno_t lno)
 {
 	SCRIPT *sc;
 	recno_t last_lno;
 	size_t blen, len, last_len, tlen;
 	int isempty, matchprompt, nw, rval;
-	char *bp, *p;
+	char *bp = NULL, *p;
+	CHAR_T *wp;
+	size_t wlen;
 
 	/* If there's a prompt on the last line, append the command. */
 	if (db_last(sp, &last_lno))
 		return (1);
-	if (db_get(sp, last_lno, DBG_FATAL, &p, &last_len))
+	if (db_get(sp, last_lno, DBG_FATAL, &wp, &wlen))
 		return (1);
+	INT2CHAR(sp, wp, wlen, p, last_len);
 	if (sscr_matchprompt(sp, p, last_len, &tlen) && tlen == 0) {
 		matchprompt = 1;
-		GET_SPACE_RET(sp, bp, blen, last_len + 128);
+		GET_SPACE_RETC(sp, bp, blen, last_len + 128);
 		memmove(bp, p, last_len);
 	} else
 		matchprompt = 0;
 
 	/* Get something to execute. */
-	if (db_eget(sp, lno, &p, &len, &isempty)) {
+	if (db_eget(sp, lno, &wp, &wlen, &isempty)) {
 		if (isempty)
 			goto empty;
 		goto err1;
@@ -329,8 +326,9 @@
 	}
 
 	/* Empty lines aren't interesting. */
-	if (len == 0)
+	if (wlen == 0)
 		goto empty;
+	INT2CHAR(sp, wp, wlen, p, len);
 
 	/* Delete any prompt. */
 	if (sscr_matchprompt(sp, p, len, &tlen)) {
@@ -355,9 +353,10 @@
 	}
 
 	if (matchprompt) {
-		ADD_SPACE_RET(sp, bp, blen, last_len + len);
+		ADD_SPACE_RETC(sp, bp, blen, last_len + len);
 		memmove(bp + last_len, p, len);
-		if (db_set(sp, last_lno, bp, last_len + len))
+		CHAR2INT(sp, bp, last_len + len, wp, wlen);
+		if (db_set(sp, last_lno, wp, wlen))
 err1:			rval = 1;
 	}
 	if (matchprompt)
@@ -372,8 +371,7 @@
  * PUBLIC: int sscr_input __P((SCR *));
  */
 int
-sscr_input(sp)
-	SCR *sp;
+sscr_input(SCR *sp)
 {
 	GS *gp;
 	struct timeval poll;
@@ -388,7 +386,7 @@
 	poll.tv_usec = 0;
 
 	/* Set up the input mask. */
-	for (sp = gp->dq.cqh_first; sp != (void *)&gp->dq; sp = sp->q.cqe_next)
+	TAILQ_FOREACH(sp, gp->dq, q)
 		if (F_ISSET(sp, SC_SCRIPT)) {
 			FD_SET(sp->script->sh_master, &rdfd);
 			if (sp->script->sh_master > maxfd)
@@ -407,9 +405,10 @@
 	}
 
 	/* Read the input. */
-	for (sp = gp->dq.cqh_first; sp != (void *)&gp->dq; sp = sp->q.cqe_next)
+	TAILQ_FOREACH(sp, gp->dq, q)
 		if (F_ISSET(sp, SC_SCRIPT) &&
-		    FD_ISSET(sp->script->sh_master, &rdfd) && sscr_insert(sp))
+		    FD_ISSET(sp->script->sh_master, &rdfd) &&
+		    sscr_insert(sp))
 			return (1);
 	goto loop;
 }
@@ -419,25 +418,29 @@
  *	Take a line from the shell and insert it into the file.
  */
 static int
-sscr_insert(sp)
-	SCR *sp;
+sscr_insert(SCR *sp)
 {
+	EX_PRIVATE *exp;
 	struct timeval tv;
-	CHAR_T *endp, *p, *t;
+	char *endp, *p, *t;
 	SCRIPT *sc;
 	fd_set rdfd;
 	recno_t lno;
 	size_t blen, len, tlen;
-	u_int value;
 	int nr, rval;
 	char *bp;
+	CHAR_T *wp;
+	size_t wlen = 0;
 
+	exp = EXP(sp);
+
+
 	/* Find out where the end of the file is. */
 	if (db_last(sp, &lno))
 		return (1);
 
 #define	MINREAD	1024
-	GET_SPACE_RET(sp, bp, blen, MINREAD);
+	GET_SPACE_RETC(sp, bp, blen, MINREAD);
 	endp = bp;
 
 	/* Read the characters. */
@@ -458,10 +461,11 @@
 
 	/* Append the lines into the file. */
 	for (p = t = bp; p < endp; ++p) {
-		value = KEY_VAL(sp, *p);
-		if (value == K_CR || value == K_NL) {
+		if (*p == '\r' || *p == '\n') {
 			len = p - t;
-			if (db_append(sp, 1, lno++, t, len))
+			if (CHAR2INT5(sp, exp->ibcw, t, len, wp, wlen))
+				goto conv_err;
+			if (db_append(sp, 1, lno++, wp, wlen))
 				goto ret;
 			t = p + 1;
 		}
@@ -489,15 +493,20 @@
 		}
 		if (sscr_setprompt(sp, t, len))
 			return (1);
-		if (db_append(sp, 1, lno++, t, len))
+		if (CHAR2INT5(sp, exp->ibcw, t, len, wp, wlen))
+			goto conv_err;
+		if (db_append(sp, 1, lno++, wp, wlen))
 			goto ret;
 	}
 
 	/* The cursor moves to EOF. */
 	sp->lno = lno;
-	sp->cno = len ? len - 1 : 0;
+	sp->cno = wlen ? wlen - 1 : 0;
 	rval = vs_refresh(sp, 1);
 
+	if (0)
+conv_err:	msgq(sp, M_ERR, "323|Invalid input. Truncated.");
+
 ret:	FREE_SPACE(sp, bp, blen);
 	return (rval);
 }
@@ -509,10 +518,7 @@
  *
  */
 static int
-sscr_setprompt(sp, buf, len)
-	SCR *sp;
-	char *buf;
-	size_t len;
+sscr_setprompt(SCR *sp, char *buf, size_t len)
 {
 	SCRIPT *sc;
 
@@ -536,10 +542,7 @@
  *	parts that can change, in both content and size.
  */
 static int
-sscr_matchprompt(sp, lp, line_len, lenp)
-	SCR *sp;
-	char *lp;
-	size_t line_len, *lenp;
+sscr_matchprompt(SCR *sp, char *lp, size_t line_len, size_t *lenp)
 {
 	SCRIPT *sc;
 	size_t prompt_len;
@@ -577,8 +580,7 @@
  * PUBLIC: int sscr_end __P((SCR *));
  */
 int
-sscr_end(sp)
-	SCR *sp;
+sscr_end(SCR *sp)
 {
 	SCRIPT *sc;
 
@@ -611,13 +613,12 @@
  *	Set/clear the global scripting bit.
  */
 static void
-sscr_check(sp)
-	SCR *sp;
+sscr_check(SCR *sp)
 {
 	GS *gp;
 
 	gp = sp->gp;
-	for (sp = gp->dq.cqh_first; sp != (void *)&gp->dq; sp = sp->q.cqe_next)
+	TAILQ_FOREACH(sp, gp->dq, q)
 		if (F_ISSET(sp, SC_SCRIPT)) {
 			F_SET(gp, G_SCRWIN);
 			return;
@@ -624,175 +625,3 @@
 		}
 	F_CLR(gp, G_SCRWIN);
 }
-
-#ifdef HAVE_SYS5_PTY
-static int ptys_open __P((int, char *));
-static int ptym_open __P((char *));
-
-static int
-sscr_pty(amaster, aslave, name, termp, winp)
-	int *amaster, *aslave;
-	char *name;
-	struct termios *termp;
-	void *winp;
-{
-	int master, slave, ttygid;
-
-	/* open master terminal */
-	if ((master = ptym_open(name)) < 0)  {
-		errno = ENOENT;	/* out of ptys */
-		return (-1);
-	}
-
-	/* open slave terminal */
-	if ((slave = ptys_open(master, name)) >= 0) {
-		*amaster = master;
-		*aslave = slave;
-	} else {
-		errno = ENOENT;	/* out of ptys */
-		return (-1);
-	}
-
-	if (termp)
-		(void) tcsetattr(slave, TCSAFLUSH, termp);
-#ifdef TIOCSWINSZ
-	if (winp != NULL)
-		(void) ioctl(slave, TIOCSWINSZ, (struct winsize *)winp);
-#endif
-	return (0);
-}
-
-/*
- * ptym_open --
- *	This function opens a master pty and returns the file descriptor
- *	to it.  pts_name is also returned which is the name of the slave.
- */
-static int
-ptym_open(pts_name)
-	char *pts_name;
-{
-	int fdm;
-	char *ptr, *ptsname();
-
-	strcpy(pts_name, _PATH_SYSV_PTY);
-	if ((fdm = open(pts_name, O_RDWR)) < 0 )
-		return (-1);
-
-	if (grantpt(fdm) < 0) {
-		close(fdm);
-		return (-2);
-	}
-
-	if (unlockpt(fdm) < 0) {
-		close(fdm);
-		return (-3);
-	}
-
-	if (unlockpt(fdm) < 0) {
-		close(fdm);
-		return (-3);
-	}
-
-	/* get slave's name */
-	if ((ptr = ptsname(fdm)) == NULL) {
-		close(fdm);
-		return (-3);
-	}
-	strcpy(pts_name, ptr);
-	return (fdm);
-}
-
-/*
- * ptys_open --
- *	This function opens the slave pty.
- */
-static int
-ptys_open(fdm, pts_name)
-	int fdm;
-	char *pts_name;
-{
-	int fds;
-
-	if ((fds = open(pts_name, O_RDWR)) < 0) {
-		close(fdm);
-		return (-5);
-	}
-
-	if (ioctl(fds, I_PUSH, "ptem") < 0) {
-		close(fds);
-		close(fdm);
-		return (-6);
-	}
-
-	if (ioctl(fds, I_PUSH, "ldterm") < 0) {
-		close(fds);
-		close(fdm);
-		return (-7);
-	}
-
-	if (ioctl(fds, I_PUSH, "ttcompat") < 0) {
-		close(fds);
-		close(fdm);
-		return (-8);
-	}
-
-	return (fds);
-}
-
-#else /* !HAVE_SYS5_PTY */
-
-static int
-sscr_pty(amaster, aslave, name, termp, winp)
-	int *amaster, *aslave;
-	char *name;
-	struct termios *termp;
-	void *winp;
-{
-	static char line[] = "/dev/ptyXX";
-	register char *cp1, *cp2;
-	register int master, slave, ttygid;
-	struct group *gr;
-
-	if ((gr = getgrnam("tty")) != NULL)
-		ttygid = gr->gr_gid;
-	else
-		ttygid = -1;
-
-	for (cp1 = "pqrs"; *cp1; cp1++) {
-		line[8] = *cp1;
-		for (cp2 = "0123456789abcdef"; *cp2; cp2++) {
-			line[5] = 'p';
-			line[9] = *cp2;
-			if ((master = open(line, O_RDWR, 0)) == -1) {
-				if (errno == ENOENT)
-					return (-1);	/* out of ptys */
-			} else {
-				line[5] = 't';
-				(void) chown(line, getuid(), ttygid);
-				(void) chmod(line, S_IRUSR|S_IWUSR|S_IWGRP);
-#ifdef HAVE_REVOKE
-				(void) revoke(line);
-#endif
-				if ((slave = open(line, O_RDWR, 0)) != -1) {
-					*amaster = master;
-					*aslave = slave;
-					if (name)
-						strcpy(name, line);
-					if (termp)
-						(void) tcsetattr(slave, 
-							TCSAFLUSH, termp);
-#ifdef TIOCSWINSZ
-					if (winp)
-						(void) ioctl(slave, TIOCSWINSZ, 
-							(char *)winp);
-#endif
-					return (0);
-				}
-				(void) close(master);
-			}
-		}
-	}
-	errno = ENOENT;	/* out of ptys */
-	return (-1);
-}
-#endif /* HAVE_SYS5_PTY */

Modified: trunk/contrib/nvi/ex/ex_set.c
===================================================================
--- trunk/contrib/nvi/ex/ex_set.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/ex/ex_set.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -10,11 +10,12 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)ex_set.c	10.7 (Berkeley) 3/6/96";
+static const char sccsid[] = "$Id: ex_set.c,v 10.8 2001/06/25 15:19:19 skimo Exp $";
 #endif /* not lint */
 
 #include <sys/types.h>
 #include <sys/queue.h>
+#include <sys/time.h>
 
 #include <bitstring.h>
 #include <limits.h>
@@ -29,9 +30,7 @@
  * PUBLIC: int ex_set __P((SCR *, EXCMD *));
  */
 int
-ex_set(sp, cmdp)
-	SCR *sp;
-	EXCMD *cmdp;
+ex_set(SCR *sp, EXCMD *cmdp)
 {
 	switch(cmdp->argc) {
 	case 0:

Modified: trunk/contrib/nvi/ex/ex_shell.c
===================================================================
--- trunk/contrib/nvi/ex/ex_shell.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/ex/ex_shell.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -10,14 +10,15 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)ex_shell.c	10.38 (Berkeley) 8/19/96";
+static const char sccsid[] = "$Id: ex_shell.c,v 10.44 2012/07/06 06:51:26 zy Exp $";
 #endif /* not lint */
 
-#include <sys/param.h>
 #include <sys/queue.h>
+#include <sys/time.h>
 #include <sys/wait.h>
 
 #include <bitstring.h>
+#include <ctype.h>
 #include <errno.h>
 #include <limits.h>
 #include <signal.h>
@@ -38,12 +39,10 @@
  * PUBLIC: int ex_shell __P((SCR *, EXCMD *));
  */
 int
-ex_shell(sp, cmdp)
-	SCR *sp;
-	EXCMD *cmdp;
+ex_shell(SCR *sp, EXCMD *cmdp)
 {
 	int rval;
-	char buf[MAXPATHLEN];
+	char *buf;
 
 	/* We'll need a shell. */
 	if (opts_empty(sp, O_SHELL, 0))
@@ -53,7 +52,11 @@
 	 * XXX
 	 * Assumes all shells use -i.
 	 */
-	(void)snprintf(buf, sizeof(buf), "%s -i", O_STR(sp, O_SHELL));
+	(void)asprintf(&buf, "%s -i", O_STR(sp, O_SHELL));
+	if (buf == NULL) {
+		msgq(sp, M_SYSERR, NULL);
+		return (1);
+	}
 
 	/* Restore the window name. */
 	(void)sp->gp->scr_rename(sp, NULL, 0);
@@ -60,6 +63,7 @@
 
 	/* If we're still in a vi screen, move out explicitly. */
 	rval = ex_exec_proc(sp, cmdp, buf, NULL, !F_ISSET(sp, SC_SCR_EXWROTE));
+	free(buf);
 
 	/* Set the window name. */
 	(void)sp->gp->scr_rename(sp, sp->frp->name, 1);
@@ -81,12 +85,7 @@
  * PUBLIC: int ex_exec_proc __P((SCR *, EXCMD *, char *, const char *, int));
  */
 int
-ex_exec_proc(sp, cmdp, cmd, msg, need_newline)
-	SCR *sp;
-	EXCMD *cmdp;
-	char *cmd;
-	const char *msg;
-	int need_newline;
+ex_exec_proc(SCR *sp, EXCMD *cmdp, char *cmd, const char *msg, int need_newline)
 {
 	GS *gp;
 	const char *name;
@@ -101,7 +100,7 @@
 	/* Enter ex mode. */
 	if (F_ISSET(sp, SC_VI)) {
 		if (gp->scr_screen(sp, SC_EX)) {
-			ex_emsg(sp, cmdp->cmd->name, EXM_NOCANON);
+			ex_wemsg(sp, cmdp->cmd->name, EXM_NOCANON);
 			return (1);
 		}
 		(void)gp->scr_attr(sp, SA_ALTERNATE, 0);
@@ -122,11 +121,13 @@
 		msgq(sp, M_SYSERR, "vfork");
 		return (1);
 	case 0:				/* Utility. */
+		if (gp->scr_child)
+			gp->scr_child(sp);
 		if ((name = strrchr(O_STR(sp, O_SHELL), '/')) == NULL)
 			name = O_STR(sp, O_SHELL);
 		else
 			++name;
-		execl(O_STR(sp, O_SHELL), name, "-c", cmd, NULL);
+		execl(O_STR(sp, O_SHELL), name, "-c", cmd, (char *)NULL);
 		msgq_str(sp, M_SYSERR, O_STR(sp, O_SHELL), "execl: %s");
 		_exit(127);
 		/* NOTREACHED */
@@ -149,11 +150,7 @@
  * PUBLIC: int proc_wait __P((SCR *, long, const char *, int, int));
  */
 int
-proc_wait(sp, pid, cmd, silent, okpipe)
-	SCR *sp;
-	long pid;
-	const char *cmd;
-	int silent, okpipe;
+proc_wait(SCR *sp, long int pid, const char *cmd, int silent, int okpipe)
 {
 	size_t len;
 	int nf, pstat;
@@ -176,11 +173,11 @@
 	 * exit before reading all of its input.
 	 */
 	if (WIFSIGNALED(pstat) && (!okpipe || WTERMSIG(pstat) != SIGPIPE)) {
-		for (; isblank(*cmd); ++cmd);
+		for (; cmdskip(*cmd); ++cmd);
 		p = msg_print(sp, cmd, &nf);
 		len = strlen(p);
 		msgq(sp, M_ERR, "%.*s%s: received signal: %s%s",
-		    MIN(len, 20), p, len > 20 ? " ..." : "",
+		    (int)MIN(len, 20), p, len > 20 ? " ..." : "",
 		    sigmsg(WTERMSIG(pstat)),
 		    WCOREDUMP(pstat) ? "; core dumped" : "");
 		if (nf)
@@ -198,11 +195,11 @@
 		 * practice.
 		 */
 		if (!silent) {
-			for (; isblank(*cmd); ++cmd);
+			for (; cmdskip(*cmd); ++cmd);
 			p = msg_print(sp, cmd, &nf);
 			len = strlen(p);
 			msgq(sp, M_ERR, "%.*s%s: exited with status %d",
-			    MIN(len, 20), p, len > 20 ? " ..." : "",
+			    (int)MIN(len, 20), p, len > 20 ? " ..." : "",
 			    WEXITSTATUS(pstat));
 			if (nf)
 				FREE_SPACE(sp, p, 0);
@@ -213,166 +210,18 @@
 }
 
 /*
- * XXX
- * The sys_siglist[] table in the C library has this information, but there's
- * no portable way to get to it.  (Believe me, I tried.)
- */
-typedef struct _sigs {
-	int	 number;		/* signal number */
-	char	*message;		/* related message */
-} SIGS;
-
-SIGS const sigs[] = {
-#ifdef SIGABRT
-	SIGABRT,	"Abort trap",
-#endif
-#ifdef SIGALRM
-	SIGALRM,	"Alarm clock",
-#endif
-#ifdef SIGBUS
-	SIGBUS,		"Bus error",
-#endif
-#ifdef SIGCLD
-	SIGCLD,		"Child exited or stopped",
-#endif
-#ifdef SIGCHLD
-	SIGCHLD,	"Child exited",
-#endif
-#ifdef SIGCONT
-	SIGCONT,	"Continued",
-#endif
-#ifdef SIGDANGER
-	SIGDANGER,	"System crash imminent",
-#endif
-#ifdef SIGEMT
-	SIGEMT,		"EMT trap",
-#endif
-#ifdef SIGFPE
-	SIGFPE,		"Floating point exception",
-#endif
-#ifdef SIGGRANT
-	SIGGRANT,	"HFT monitor mode granted",
-#endif
-#ifdef SIGHUP
-	SIGHUP,		"Hangup",
-#endif
-#ifdef SIGILL
-	SIGILL,		"Illegal instruction",
-#endif
-#ifdef SIGINFO
-	SIGINFO,	"Information request",
-#endif
-#ifdef SIGINT
-	SIGINT,		"Interrupt",
-#endif
-#ifdef SIGIO
-	SIGIO,		"I/O possible",
-#endif
-#ifdef SIGIOT
-	SIGIOT,		"IOT trap",
-#endif
-#ifdef SIGKILL
-	SIGKILL,	"Killed",
-#endif
-#ifdef SIGLOST
-	SIGLOST,	"Record lock",
-#endif
-#ifdef SIGMIGRATE
-	SIGMIGRATE,	"Migrate process to another CPU",
-#endif
-#ifdef SIGMSG
-	SIGMSG,		"HFT input data pending",
-#endif
-#ifdef SIGPIPE
-	SIGPIPE,	"Broken pipe",
-#endif
-#ifdef SIGPOLL
-	SIGPOLL,	"I/O possible",
-#endif
-#ifdef SIGPRE
-	SIGPRE,		"Programming error",
-#endif
-#ifdef SIGPROF
-	SIGPROF,	"Profiling timer expired",
-#endif
-#ifdef SIGPWR
-	SIGPWR,		"Power failure imminent",
-#endif
-#ifdef SIGRETRACT
-	SIGRETRACT,	"HFT monitor mode retracted",
-#endif
-#ifdef SIGQUIT
-	SIGQUIT,	"Quit",
-#endif
-#ifdef SIGSAK
-	SIGSAK,		"Secure Attention Key",
-#endif
-#ifdef SIGSEGV
-	SIGSEGV,	"Segmentation fault",
-#endif
-#ifdef SIGSOUND
-	SIGSOUND,	"HFT sound sequence completed",
-#endif
-#ifdef SIGSTOP
-	SIGSTOP,	"Suspended (signal)",
-#endif
-#ifdef SIGSYS
-	SIGSYS,		"Bad system call",
-#endif
-#ifdef SIGTERM
-	SIGTERM,	"Terminated",
-#endif
-#ifdef SIGTRAP
-	SIGTRAP,	"Trace/BPT trap",
-#endif
-#ifdef SIGTSTP
-	SIGTSTP,	"Suspended",
-#endif
-#ifdef SIGTTIN
-	SIGTTIN,	"Stopped (tty input)",
-#endif
-#ifdef SIGTTOU
-	SIGTTOU,	"Stopped (tty output)",
-#endif
-#ifdef SIGURG
-	SIGURG,		"Urgent I/O condition",
-#endif
-#ifdef SIGUSR1
-	SIGUSR1,	"User defined signal 1",
-#endif
-#ifdef SIGUSR2
-	SIGUSR2,	"User defined signal 2",
-#endif
-#ifdef SIGVTALRM
-	SIGVTALRM,	"Virtual timer expired",
-#endif
-#ifdef SIGWINCH
-	SIGWINCH,	"Window size changes",
-#endif
-#ifdef SIGXCPU
-	SIGXCPU,	"Cputime limit exceeded",
-#endif
-#ifdef SIGXFSZ
-	SIGXFSZ,	"Filesize limit exceeded",
-#endif
-};
-
-/*
  * sigmsg --
  * 	Return a pointer to a message describing a signal.
  */
 static const char *
-sigmsg(signo)
-	int signo;
+sigmsg(int signo)
 {
 	static char buf[40];
-	const SIGS *sigp;
-	int n;
+	char *message;
 
-	for (n = 0,
-	    sigp = &sigs[0]; n < sizeof(sigs) / sizeof(sigs[0]); ++n, ++sigp)
-		if (sigp->number == signo)
-			return (sigp->message);
+	/* POSIX.1-2008 leaves strsignal(3)'s return value unspecified. */
+	if ((message = strsignal(signo)) != NULL)
+		return message;
 	(void)snprintf(buf, sizeof(buf), "Unknown signal: %d", signo);
 	return (buf);
 }

Modified: trunk/contrib/nvi/ex/ex_shift.c
===================================================================
--- trunk/contrib/nvi/ex/ex_shift.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/ex/ex_shift.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -10,11 +10,12 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)ex_shift.c	10.11 (Berkeley) 9/15/96";
+static const char sccsid[] = "$Id: ex_shift.c,v 10.17 2001/06/25 15:19:20 skimo Exp $";
 #endif /* not lint */
 
 #include <sys/types.h>
 #include <sys/queue.h>
+#include <sys/time.h>
 
 #include <bitstring.h>
 #include <limits.h>
@@ -34,9 +35,7 @@
  * PUBLIC: int ex_shiftl __P((SCR *, EXCMD *));
  */
 int
-ex_shiftl(sp, cmdp)
-	SCR *sp;
-	EXCMD *cmdp;
+ex_shiftl(SCR *sp, EXCMD *cmdp)
 {
 	return (shift(sp, cmdp, LEFT));
 }
@@ -47,9 +46,7 @@
  * PUBLIC: int ex_shiftr __P((SCR *, EXCMD *));
  */
 int
-ex_shiftr(sp, cmdp)
-	SCR *sp;
-	EXCMD *cmdp;
+ex_shiftr(SCR *sp, EXCMD *cmdp)
 {
 	return (shift(sp, cmdp, RIGHT));
 }
@@ -59,15 +56,13 @@
  *	Ex shift support.
  */
 static int
-shift(sp, cmdp, rl)
-	SCR *sp;
-	EXCMD *cmdp;
-	enum which rl;
+shift(SCR *sp, EXCMD *cmdp, enum which rl)
 {
 	recno_t from, to;
 	size_t blen, len, newcol, newidx, oldcol, oldidx, sw;
 	int curset;
-	char *p, *bp, *tbp;
+	CHAR_T *p;
+	CHAR_T *bp, *tbp;
 
 	NEEDFILE(sp, cmdp);
 
@@ -93,7 +88,7 @@
 	for (p = cmdp->argv[0]->bp, sw = 0; *p == '>' || *p == '<'; ++p)
 		sw += O_VAL(sp, O_SHIFTWIDTH);
 
-	GET_SPACE_RET(sp, bp, blen, 256);
+	GET_SPACE_RETW(sp, bp, blen, 256);
 
 	curset = 0;
 	for (from = cmdp->addr1.lno, to = cmdp->addr2.lno; from <= to; ++from) {
@@ -131,7 +126,7 @@
 		}
 
 		/* Get a buffer that will hold the new line. */
-		ADD_SPACE_RET(sp, bp, blen, newcol + len);
+		ADD_SPACE_RETW(sp, bp, blen, newcol + len);
 
 		/*
 		 * Build a new indent string and count the number of
@@ -146,11 +141,11 @@
 			*tbp++ = ' ';
 
 		/* Add the original line. */
-		memcpy(tbp, p + oldidx, len - oldidx);
+		MEMCPY(tbp, p + oldidx, len - oldidx);
 
 		/* Set the replacement line. */
 		if (db_set(sp, from, bp, (tbp + (len - oldidx)) - bp)) {
-err:			FREE_SPACE(sp, bp, blen);
+err:			FREE_SPACEW(sp, bp, blen);
 			return (1);
 		}
 
@@ -184,7 +179,7 @@
 		(void)nonblank(sp, to, &sp->cno);
 	}
 
-	FREE_SPACE(sp, bp, blen);
+	FREE_SPACEW(sp, bp, blen);
 
 	sp->rptlines[L_SHIFT] += cmdp->addr2.lno - cmdp->addr1.lno + 1;
 	return (0);

Modified: trunk/contrib/nvi/ex/ex_source.c
===================================================================
--- trunk/contrib/nvi/ex/ex_source.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/ex/ex_source.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -10,7 +10,7 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)ex_source.c	10.12 (Berkeley) 8/10/96";
+static const char sccsid[] = "$Id: ex_source.c,v 10.17 2011/12/19 16:17:06 zy Exp $";
 #endif /* not lint */
 
 #include <sys/types.h>
@@ -35,15 +35,18 @@
  * PUBLIC: int ex_source __P((SCR *, EXCMD *));
  */
 int
-ex_source(sp, cmdp)
-	SCR *sp;
-	EXCMD *cmdp;
+ex_source(SCR *sp, EXCMD *cmdp)
 {
 	struct stat sb;
 	int fd, len;
-	char *bp, *name;
+	char *bp;
+	char *name, *np;
+	size_t nlen;
+	CHAR_T *wp;
+	size_t wlen;
+	int rc;
 
-	name = cmdp->argv[0]->bp;
+	INT2CHAR(sp, cmdp->argv[0]->bp, cmdp->argv[0]->len + 1, name, nlen);
 	if ((fd = open(name, O_RDONLY, 0)) < 0 || fstat(fd, &sb))
 		goto err;
 
@@ -80,6 +83,13 @@
 		return (1);
 	}
 
+	np = strdup(name);
+	if (CHAR2INT(sp, bp, (size_t)sb.st_size + 1, wp, wlen))
+		msgq(sp, M_ERR, "323|Invalid input. Truncated.");
 	/* Put it on the ex queue. */
-	return (ex_run_str(sp, name, bp, (size_t)sb.st_size, 1, 1));
+	rc = ex_run_str(sp, np, wp, wlen - 1, 1, 0);
+	if (np != NULL)
+		free(np);
+	free(bp);
+	return (rc);
 }

Modified: trunk/contrib/nvi/ex/ex_stop.c
===================================================================
--- trunk/contrib/nvi/ex/ex_stop.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/ex/ex_stop.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -10,11 +10,12 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)ex_stop.c	10.10 (Berkeley) 3/6/96";
+static const char sccsid[] = "$Id: ex_stop.c,v 10.11 2001/06/25 15:19:20 skimo Exp $";
 #endif /* not lint */
 
 #include <sys/types.h>
 #include <sys/queue.h>
+#include <sys/time.h>
 
 #include <bitstring.h>
 #include <errno.h>
@@ -33,9 +34,7 @@
  * PUBLIC: int ex_stop __P((SCR *, EXCMD *));
  */
 int
-ex_stop(sp, cmdp)
-	SCR *sp;
-	EXCMD *cmdp;
+ex_stop(SCR *sp, EXCMD *cmdp)
 {
 	int allowed;
 

Modified: trunk/contrib/nvi/ex/ex_subst.c
===================================================================
--- trunk/contrib/nvi/ex/ex_subst.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/ex/ex_subst.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -10,7 +10,7 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)ex_subst.c	10.37 (Berkeley) 9/15/96";
+static const char sccsid[] = "$Id: ex_subst.c,v 10.53 2011/12/21 20:40:35 zy Exp $";
 #endif /* not lint */
 
 #include <sys/types.h>
@@ -32,12 +32,12 @@
 #define	SUB_FIRST	0x01		/* The 'r' flag isn't reasonable. */
 #define	SUB_MUSTSETR	0x02		/* The 'r' flag is required. */
 
-static int re_conv __P((SCR *, char **, size_t *, int *));
-static int re_cscope_conv __P((SCR *, char **, size_t *, int *));
+static int re_conv __P((SCR *, CHAR_T **, size_t *, int *));
+static int re_cscope_conv __P((SCR *, CHAR_T **, size_t *, int *));
 static int re_sub __P((SCR *,
-		char *, char **, size_t *, size_t *, regmatch_t [10]));
-static int re_tag_conv __P((SCR *, char **, size_t *, int *));
-static int s __P((SCR *, EXCMD *, char *, regex_t *, u_int));
+		CHAR_T *, CHAR_T **, size_t *, size_t *, regmatch_t [10]));
+static int re_tag_conv __P((SCR *, CHAR_T **, size_t *, int *));
+static int s __P((SCR *, EXCMD *, CHAR_T *, regex_t *, u_int));
 
 /*
  * ex_s --
@@ -48,15 +48,13 @@
  * PUBLIC: int ex_s __P((SCR *, EXCMD *));
  */
 int
-ex_s(sp, cmdp)
-	SCR *sp;
-	EXCMD *cmdp;
+ex_s(SCR *sp, EXCMD *cmdp)
 {
 	regex_t *re;
 	size_t blen, len;
 	u_int flags;
 	int delim;
-	char *bp, *ptrn, *rep, *p, *t;
+	CHAR_T *bp, *p, *ptrn, *rep, *t;
 
 	/*
 	 * Skip leading white space.
@@ -73,7 +71,7 @@
 		goto subagain;
 	for (p = cmdp->argv[0]->bp,
 	    len = cmdp->argv[0]->len; len > 0; --len, ++p) {
-		if (!isblank(*p))
+		if (!cmdskip(*p))
 			break;
 	}
 	if (len == 0)
@@ -80,7 +78,7 @@
 subagain:	return (ex_subagain(sp, cmdp));
 
 	delim = *p++;
-	if (isalnum(delim) || delim == '\\')
+	if (!isascii(delim) || isalnum(delim) || delim == '\\')
 		return (s(sp, cmdp, p, &sp->subre_c, SUB_MUSTSETR));
 
 	/*
@@ -140,8 +138,9 @@
 		}
 
 		/* Re-compile the RE if necessary. */
-		if (!F_ISSET(sp, SC_RE_SEARCH) && re_compile(sp,
-		    sp->re, sp->re_len, NULL, NULL, &sp->re_c, RE_C_SEARCH))
+		if (!F_ISSET(sp, SC_RE_SEARCH) &&
+		    re_compile(sp, sp->re, sp->re_len,
+		    NULL, NULL, &sp->re_c, RE_C_SEARCH))
 			return (1);
 		flags = 0;
 	} else {
@@ -152,11 +151,11 @@
 		 * RE's.  We compile the RE twice, as we don't want to bother
 		 * ref counting the pattern string and (opaque) structure.
 		 */
-		if (re_compile(sp, ptrn, t - ptrn,
-		    &sp->re, &sp->re_len, &sp->re_c, RE_C_SEARCH))
+		if (re_compile(sp, ptrn, t - ptrn, &sp->re,
+		    &sp->re_len, &sp->re_c, RE_C_SEARCH))
 			return (1);
-		if (re_compile(sp, ptrn, t - ptrn,
-		    &sp->subre, &sp->subre_len, &sp->subre_c, RE_C_SUBST))
+		if (re_compile(sp, ptrn, t - ptrn, &sp->subre,
+		    &sp->subre_len, &sp->subre_c, RE_C_SUBST))
 			return (1);
 		
 		flags = SUB_FIRST;
@@ -202,7 +201,7 @@
 		    p[0] != '\0' && p[0] != delim; ++p, ++len)
 			if (p[0] == '~')
 				len += sp->repl_len;
-		GET_SPACE_RET(sp, bp, blen, len);
+		GET_SPACE_RETW(sp, bp, blen, len);
 		for (t = bp, len = 0, p = rep;;) {
 			if (p[0] == '\0' || p[0] == delim) {
 				if (p[0] == delim)
@@ -222,7 +221,7 @@
 				}
 			} else if (p[0] == '~' && O_ISSET(sp, O_MAGIC)) {
 tilde:				++p;
-				memcpy(t, sp->repl, sp->repl_len);
+				MEMCPY(t, sp->repl, sp->repl_len);
 				t += sp->repl_len;
 				len += sp->repl_len;
 				continue;
@@ -233,14 +232,14 @@
 		if ((sp->repl_len = len) != 0) {
 			if (sp->repl != NULL)
 				free(sp->repl);
-			if ((sp->repl = malloc(len)) == NULL) {
-				msgq(sp, M_SYSERR, NULL);
-				FREE_SPACE(sp, bp, blen);
+			MALLOC(sp, sp->repl, CHAR_T *, len * sizeof(CHAR_T));
+			if (sp->repl == NULL) {
+				FREE_SPACEW(sp, bp, blen);
 				return (1);
 			}
-			memcpy(sp->repl, bp, len);
+			MEMCPY(sp->repl, bp, len);
 		}
-		FREE_SPACE(sp, bp, blen);
+		FREE_SPACEW(sp, bp, blen);
 	}
 	return (s(sp, cmdp, p, re, flags));
 }
@@ -254,16 +253,15 @@
  * PUBLIC: int ex_subagain __P((SCR *, EXCMD *));
  */
 int
-ex_subagain(sp, cmdp)
-	SCR *sp;
-	EXCMD *cmdp;
+ex_subagain(SCR *sp, EXCMD *cmdp)
 {
 	if (sp->subre == NULL) {
 		ex_emsg(sp, NULL, EXM_NOPREVRE);
 		return (1);
 	}
-	if (!F_ISSET(sp, SC_RE_SUBST) && re_compile(sp,
-	    sp->subre, sp->subre_len, NULL, NULL, &sp->subre_c, RE_C_SUBST))
+	if (!F_ISSET(sp, SC_RE_SUBST) &&
+	    re_compile(sp, sp->subre, sp->subre_len,
+	    NULL, NULL, &sp->subre_c, RE_C_SUBST))
 		return (1);
 	return (s(sp,
 	    cmdp, cmdp->argc ? cmdp->argv[0]->bp : NULL, &sp->subre_c, 0));
@@ -278,16 +276,14 @@
  * PUBLIC: int ex_subtilde __P((SCR *, EXCMD *));
  */
 int
-ex_subtilde(sp, cmdp)
-	SCR *sp;
-	EXCMD *cmdp;
+ex_subtilde(SCR *sp, EXCMD *cmdp)
 {
 	if (sp->re == NULL) {
 		ex_emsg(sp, NULL, EXM_NOPREVRE);
 		return (1);
 	}
-	if (!F_ISSET(sp, SC_RE_SEARCH) && re_compile(sp,
-	    sp->re, sp->re_len, NULL, NULL, &sp->re_c, RE_C_SEARCH))
+	if (!F_ISSET(sp, SC_RE_SEARCH) && re_compile(sp, sp->re,
+	    sp->re_len, NULL, NULL, &sp->re_c, RE_C_SEARCH))
 		return (1);
 	return (s(sp,
 	    cmdp, cmdp->argc ? cmdp->argv[0]->bp : NULL, &sp->re_c, 0));
@@ -320,21 +316,21 @@
 
 #define	BUILD(sp, l, len) {						\
 	if (lbclen + (len) > lblen) {					\
-		lblen += MAX(lbclen + (len), 256);			\
-		REALLOC(sp, lb, char *, lblen);				\
+		lblen = p2roundup(MAX(lbclen + (len), 256));		\
+		REALLOC(sp, lb, CHAR_T *, lblen * sizeof(CHAR_T));	\
 		if (lb == NULL) {					\
 			lbclen = 0;					\
 			return (1);					\
 		}							\
 	}								\
-	memcpy(lb + lbclen, l, len);					\
+	MEMCPY(lb + lbclen, l, len);					\
 	lbclen += len;							\
 }
 
 #define	NEEDSP(sp, len, pnt) {						\
 	if (lbclen + (len) > lblen) {					\
-		lblen += MAX(lbclen + (len), 256);			\
-		REALLOC(sp, lb, char *, lblen);				\
+		lblen = p2roundup(MAX(lbclen + (len), 256));		\
+		REALLOC(sp, lb, CHAR_T *, lblen * sizeof(CHAR_T));	\
 		if (lb == NULL) {					\
 			lbclen = 0;					\
 			return (1);					\
@@ -344,17 +340,13 @@
 }
 
 static int
-s(sp, cmdp, s, re, flags)
-	SCR *sp;
-	EXCMD *cmdp;
-	char *s;
-	regex_t *re;
-	u_int flags;
+s(SCR *sp, EXCMD *cmdp, CHAR_T *s, regex_t *re, u_int flags)
 {
 	EVENT ev;
 	MARK from, to;
-	TEXTH tiq;
+	TEXTH tiq[] = {{ 0 }};
 	recno_t elno, lno, slno;
+	u_long ul;
 	regmatch_t match[10];
 	size_t blen, cnt, last, lbclen, lblen, len, llen;
 	size_t offset, saved_offset, scno;
@@ -361,7 +353,8 @@
 	int cflag, lflag, nflag, pflag, rflag;
 	int didsub, do_eol_match, eflags, empty_ok, eval;
 	int linechanged, matched, quit, rval;
-	char *bp, *lb;
+	CHAR_T *bp, *lb;
+	enum nresult nret;
 
 	NEEDFILE(sp, cmdp);
 
@@ -414,13 +407,14 @@
 			if (lno != OOBLNO)
 				goto usage;
 			errno = 0;
-			lno = strtoul(s, &s, 10);
+			nret = nget_uslong(&ul, s, &s, 10);
+			lno = ul;
 			if (*s == '\0')		/* Loop increment correction. */
 				--s;
-			if (errno == ERANGE) {
-				if (lno == LONG_MAX)
+			if (nret != NUM_OK) {
+				if (nret == NUM_OVER)
 					msgq(sp, M_ERR, "153|Count overflow");
-				else if (lno == LONG_MIN)
+				else if (nret == NUM_UNDER)
 					msgq(sp, M_ERR, "154|Count underflow");
 				else
 					msgq(sp, M_SYSERR, NULL);
@@ -443,10 +437,8 @@
 			sp->c_suffix = !sp->c_suffix;
 
 			/* Ex text structure initialization. */
-			if (F_ISSET(sp, SC_EX)) {
-				memset(&tiq, 0, sizeof(TEXTH));
-				CIRCLEQ_INIT(&tiq);
-			}
+			if (F_ISSET(sp, SC_EX))
+				TAILQ_INIT(tiq);
 			break;
 		case 'g':
 			sp->g_suffix = !sp->g_suffix;
@@ -474,7 +466,7 @@
 			goto usage;
 		}
 
-	if (*s != '\0' || !rflag && LF_ISSET(SUB_MUSTSETR)) {
+	if (*s != '\0' || (!rflag && LF_ISSET(SUB_MUSTSETR))) {
 usage:		ex_emsg(sp, cmdp->cmd->usage, EXM_USAGE);
 		return (1);
 	}
@@ -496,7 +488,8 @@
 	blen = lbclen = lblen = 0;
 
 	/* For each line... */
-	for (matched = quit = 0, lno = cmdp->addr1.lno,
+	lno = cmdp->addr1.lno == 0 ? 1 : cmdp->addr1.lno;
+	for (matched = quit = 0,
 	    elno = cmdp->addr2.lno; !quit && lno <= elno; ++lno) {
 
 		/* Someone's unhappy, time to stop. */
@@ -513,10 +506,10 @@
 		 */
 		if (sp->c_suffix) {
 			if (bp == NULL) {
-				GET_SPACE_RET(sp, bp, blen, llen);
+				GET_SPACE_RETW(sp, bp, blen, llen);
 			} else
-				ADD_SPACE_RET(sp, bp, blen, llen);
-			memcpy(bp, s, llen);
+				ADD_SPACE_RETW(sp, bp, blen, llen);
+			MEMCPY(bp, s, llen);
 			s = bp;
 		}
 
@@ -555,7 +548,7 @@
 		match[0].rm_eo = len;
 
 		/* Get the next match. */
-		eval = regexec(re, (char *)s + offset, 10, match, eflags);
+		eval = regexec(re, s + offset, 10, match, eflags);
 
 		/*
 		 * There wasn't a match or if there was an error, deal with
@@ -658,9 +651,9 @@
 				if (ex_print(sp, cmdp, &from, &to, 0) ||
 				    ex_scprint(sp, &from, &to))
 					goto lquit;
-				if (ex_txt(sp, &tiq, 0, TXT_CR))
+				if (ex_txt(sp, tiq, 0, TXT_CR))
 					goto err;
-				ev.e_c = tiq.cqh_first->lb[0];
+				ev.e_c = TAILQ_FIRST(tiq)->lb[0];
 			}
 
 			switch (ev.e_c) {
@@ -749,8 +742,8 @@
 				goto err;
 			if (db_get(sp, lno, DBG_FATAL, &s, &llen))
 				goto err;
-			ADD_SPACE_RET(sp, bp, blen, llen)
-			memcpy(bp, s, llen);
+			ADD_SPACE_RETW(sp, bp, blen, llen)
+			MEMCPY(bp, s, llen);
 			s = bp;
 			len = llen - offset;
 
@@ -876,7 +869,7 @@
 	}
 
 	if (bp != NULL)
-		FREE_SPACE(sp, bp, blen);
+		FREE_SPACEW(sp, bp, blen);
 	if (lb != NULL)
 		free(lb);
 	return (rval);
@@ -887,19 +880,14 @@
  *	Compile the RE.
  *
  * PUBLIC: int re_compile __P((SCR *,
- * PUBLIC:     char *, size_t, char **, size_t *, regex_t *, u_int));
+ * PUBLIC:     CHAR_T *, size_t, CHAR_T **, size_t *, regex_t *, u_int));
  */
 int
-re_compile(sp, ptrn, plen, ptrnp, lenp, rep, flags)
-	SCR *sp;
-	char *ptrn, **ptrnp;
-	size_t plen, *lenp;
-	regex_t *rep;
-	u_int flags;
+re_compile(SCR *sp, CHAR_T *ptrn, size_t plen, CHAR_T **ptrnp, size_t *lenp, regex_t *rep, u_int flags)
 {
 	size_t len;
 	int reflags, replaced, rval;
-	char *p;
+	CHAR_T *p;
 
 	/* Set RE flags. */
 	reflags = 0;
@@ -910,7 +898,7 @@
 			reflags |= REG_ICASE;
 		if (O_ISSET(sp, O_ICLOWER)) {
 			for (p = ptrn, len = plen; len > 0; ++p, --len)
-				if (isupper(*p))
+				if (ISUPPER(*p))
 					break;
 			if (len == 0)
 				reflags |= REG_ICASE;
@@ -933,6 +921,7 @@
 	 * later recompilation.   Free any previously saved value.
 	 */
 	if (ptrnp != NULL) {
+		replaced = 0;
 		if (LF_ISSET(RE_C_CSCOPE)) {
 			if (re_cscope_conv(sp, &ptrn, &plen, &replaced))
 				return (1);
@@ -965,15 +954,15 @@
 		 * Regcomp isn't 8-bit clean, so the pattern is nul-terminated
 		 * for now.  There's just no other solution.  
 		 */
-		MALLOC(sp, *ptrnp, char *, plen + 1);
+		MALLOC(sp, *ptrnp, CHAR_T *, (plen + 1) * sizeof(CHAR_T));
 		if (*ptrnp != NULL) {
-			memcpy(*ptrnp, ptrn, plen);
+			MEMCPY(*ptrnp, ptrn, plen);
 			(*ptrnp)[plen] = '\0';
 		}
 
 		/* Free up conversion-routine-allocated memory. */
 		if (replaced)
-			FREE_SPACE(sp, ptrn, 0);
+			FREE_SPACEW(sp, ptrn, 0);
 
 		if (*ptrnp == NULL)
 			return (1);
@@ -1023,15 +1012,11 @@
  * weren't historically.  It's a bug.
  */
 static int
-re_conv(sp, ptrnp, plenp, replacedp)
-	SCR *sp;
-	char **ptrnp;
-	size_t *plenp;
-	int *replacedp;
+re_conv(SCR *sp, CHAR_T **ptrnp, size_t *plenp, int *replacedp)
 {
 	size_t blen, len, needlen;
 	int magic;
-	char *bp, *p, *t;
+	CHAR_T *bp, *p, *t;
 
 	/*
 	 * First pass through, we figure out how much space we'll need.
@@ -1048,11 +1033,11 @@
 				switch (*++p) {
 				case '<':
 					magic = 1;
-					needlen += sizeof(RE_WSTART);
+					needlen += RE_WSTART_LEN + 1;
 					break;
 				case '>':
 					magic = 1;
-					needlen += sizeof(RE_WSTOP);
+					needlen += RE_WSTOP_LEN + 1;
 					break;
 				case '~':
 					if (!O_ISSET(sp, O_MAGIC)) {
@@ -1100,7 +1085,7 @@
 
 	/* Get enough memory to hold the final pattern. */
 	*replacedp = 1;
-	GET_SPACE_RET(sp, bp, blen, needlen);
+	GET_SPACE_RETW(sp, bp, blen, needlen);
 
 	for (p = *ptrnp, len = *plenp, t = bp; len > 0; ++p, --len)
 		switch (*p) {
@@ -1109,20 +1094,20 @@
 				--len;
 				switch (*++p) {
 				case '<':
-					memcpy(t,
-					    RE_WSTART, sizeof(RE_WSTART) - 1);
-					t += sizeof(RE_WSTART) - 1;
+					MEMCPY(t,
+					    RE_WSTART, RE_WSTART_LEN);
+					t += RE_WSTART_LEN;
 					break;
 				case '>':
-					memcpy(t,
-					    RE_WSTOP, sizeof(RE_WSTOP) - 1);
-					t += sizeof(RE_WSTOP) - 1;
+					MEMCPY(t,
+					    RE_WSTOP, RE_WSTOP_LEN);
+					t += RE_WSTOP_LEN;
 					break;
 				case '~':
 					if (O_ISSET(sp, O_MAGIC))
 						*t++ = '~';
 					else {
-						memcpy(t,
+						MEMCPY(t,
 						    sp->repl, sp->repl_len);
 						t += sp->repl_len;
 					}
@@ -1143,7 +1128,7 @@
 			break;
 		case '~':
 			if (O_ISSET(sp, O_MAGIC)) {
-				memcpy(t, sp->repl, sp->repl_len);
+				MEMCPY(t, sp->repl, sp->repl_len);
 				t += sp->repl_len;
 			} else
 				*t++ = '~';
@@ -1171,21 +1156,17 @@
  *	1003.2 RE functions can handle.
  */
 static int
-re_tag_conv(sp, ptrnp, plenp, replacedp)
-	SCR *sp;
-	char **ptrnp;
-	size_t *plenp;
-	int *replacedp;
+re_tag_conv(SCR *sp, CHAR_T **ptrnp, size_t *plenp, int *replacedp)
 {
 	size_t blen, len;
 	int lastdollar;
-	char *bp, *p, *t;
+	CHAR_T *bp, *p, *t;
 
 	len = *plenp;
 
 	/* Max memory usage is 2 times the length of the string. */
 	*replacedp = 1;
-	GET_SPACE_RET(sp, bp, blen, len * 2);
+	GET_SPACE_RETW(sp, bp, blen, len * 2);
 
 	p = *ptrnp;
 	t = bp;
@@ -1222,7 +1203,7 @@
 		if (p[0] == '\\' && (p[1] == '/' || p[1] == '?')) {
 			++p;
 			--len;
-		} else if (strchr("^.[]$*", p[0]))
+		} else if (STRCHR(L("^.[]$*"), p[0]))
 			*t++ = '\\';
 		*t++ = *p++;
 	}
@@ -1240,14 +1221,13 @@
  *      1003.2 RE functions can handle.
  */
 static int
-re_cscope_conv(sp, ptrnp, plenp, replacedp)
-	SCR *sp;
-	char **ptrnp;
-	size_t *plenp;
-	int *replacedp;
+re_cscope_conv(SCR *sp, CHAR_T **ptrnp, size_t *plenp, int *replacedp)
 {
 	size_t blen, len, nspaces;
-	char *bp, *p, *t;
+	CHAR_T *bp, *t;
+	CHAR_T *p;
+	CHAR_T *wp;
+	size_t wlen;
 
 	/*
 	 * Each space in the source line printed by cscope represents an
@@ -1254,6 +1234,8 @@
 	 * arbitrary sequence of spaces, tabs, and comments.
 	 */
 #define	CSCOPE_RE_SPACE		"([ \t]|/\\*([^*]|\\*/)*\\*/)*"
+#define CSCOPE_LEN	sizeof(CSCOPE_RE_SPACE) - 1
+	CHAR2INT(sp, CSCOPE_RE_SPACE, CSCOPE_LEN, wp, wlen);
 	for (nspaces = 0, p = *ptrnp, len = *plenp; len > 0; ++p, --len)
 		if (*p == ' ')
 			++nspaces;
@@ -1266,27 +1248,27 @@
 	 */
 	*replacedp = 1;
 	len = (p - *ptrnp) * 2 + (nspaces + 2) * sizeof(CSCOPE_RE_SPACE) + 3;
-	GET_SPACE_RET(sp, bp, blen, len);
+	GET_SPACE_RETW(sp, bp, blen, len);
 
 	p = *ptrnp;
 	t = bp;
 
 	*t++ = '^';
-	memcpy(t, CSCOPE_RE_SPACE, sizeof(CSCOPE_RE_SPACE) - 1);
-	t += sizeof(CSCOPE_RE_SPACE) - 1;
+	MEMCPY(t, wp, wlen);
+	t += wlen;
 
 	for (len = *plenp; len > 0; ++p, --len)
 		if (*p == ' ') {
-			memcpy(t, CSCOPE_RE_SPACE, sizeof(CSCOPE_RE_SPACE) - 1);
-			t += sizeof(CSCOPE_RE_SPACE) - 1;
+			MEMCPY(t, wp, wlen);
+			t += wlen;
 		} else {
-			if (strchr("\\^.[]$*+?()|{}", *p))
+			if (STRCHR(L("\\^.[]$*+?()|{}"), *p))
 				*t++ = '\\';
 			*t++ = *p;
 		}
 
-	memcpy(t, CSCOPE_RE_SPACE, sizeof(CSCOPE_RE_SPACE) - 1);
-	t += sizeof(CSCOPE_RE_SPACE) - 1;
+	MEMCPY(t, wp, wlen);
+	t += wlen;
 	*t++ = '$';
 
 	*ptrnp = bp;
@@ -1301,18 +1283,14 @@
  * PUBLIC: void re_error __P((SCR *, int, regex_t *));
  */
 void
-re_error(sp, errcode, preg)
-	SCR *sp;
-	int errcode;
-	regex_t *preg;
+re_error(SCR *sp, int errcode, regex_t *preg)
 {
 	size_t s;
 	char *oe;
 
 	s = regerror(errcode, preg, "", 0);
-	if ((oe = malloc(s)) == NULL)
-		msgq(sp, M_SYSERR, NULL);
-	else {
+	MALLOC(sp, oe, char *, s);
+	if (oe != NULL) {
 		(void)regerror(errcode, preg, oe, s);
 		msgq(sp, M_ERR, "RE error: %s", oe);
 		free(oe);
@@ -1324,22 +1302,23 @@
  * 	Do the substitution for a regular expression.
  */
 static int
-re_sub(sp, ip, lbp, lbclenp, lblenp, match)
-	SCR *sp;
-	char *ip;			/* Input line. */
-	char **lbp;
-	size_t *lbclenp, *lblenp;
-	regmatch_t match[10];
+re_sub(
+	SCR *sp,
+	CHAR_T *ip,			/* Input line. */
+	CHAR_T **lbp,
+	size_t *lbclenp,
+	size_t *lblenp,
+	regmatch_t match[10])
 {
 	enum { C_NOTSET, C_LOWER, C_ONELOWER, C_ONEUPPER, C_UPPER } conv;
 	size_t lbclen, lblen;		/* Local copies. */
 	size_t mlen;			/* Match length. */
 	size_t rpl;			/* Remaining replacement length. */
-	char *rp;			/* Replacement pointer. */
+	CHAR_T *rp;			/* Replacement pointer. */
 	int ch;
 	int no;				/* Match replacement offset. */
-	char *p, *t;			/* Buffer pointers. */
-	char *lb;			/* Local copies. */
+	CHAR_T *p, *t;			/* Buffer pointers. */
+	CHAR_T *lb;			/* Local copies. */
 
 	lb = *lbp;			/* Get local copies. */
 	lbclen = *lbclenp;
@@ -1363,8 +1342,8 @@
 	 * all escaping characters.  This (hopefully) matches historic practice.
 	 */
 #define	OUTCH(ch, nltrans) {						\
-	CHAR_T __ch = (ch);						\
-	u_int __value = KEY_VAL(sp, __ch);				\
+	ARG_CHAR_T __ch = (ch);						\
+	e_key_t __value = KEY_VAL(sp, __ch);				\
 	if (nltrans && (__value == K_CR || __value == K_NL)) {		\
 		NEEDNEWLINE(sp);					\
 		sp->newl[sp->newl_cnt++] = lbclen;			\
@@ -1374,15 +1353,15 @@
 			conv = C_NOTSET;				\
 			/* FALLTHROUGH */				\
 		case C_LOWER:						\
-			if (isupper(__ch))				\
-				__ch = tolower(__ch);			\
+			if (ISUPPER(__ch))				\
+				__ch = TOLOWER(__ch);			\
 			break;						\
 		case C_ONEUPPER:					\
 			conv = C_NOTSET;				\
 			/* FALLTHROUGH */				\
 		case C_UPPER:						\
-			if (islower(__ch))				\
-				__ch = toupper(__ch);			\
+			if (ISLOWER(__ch))				\
+				__ch = TOUPPER(__ch);			\
 			break;						\
 		default:						\
 			abort();					\
@@ -1444,6 +1423,9 @@
 				++rp;
 				conv = C_UPPER;
 				continue;
+			case '\r':
+				OUTCH(ch, 0);
+				continue;
 			default:
 				++rp;
 				break;

Modified: trunk/contrib/nvi/ex/ex_tag.c
===================================================================
--- trunk/contrib/nvi/ex/ex_tag.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/ex/ex_tag.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -13,19 +13,13 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)ex_tag.c	10.36 (Berkeley) 9/15/96";
+static const char sccsid[] = "$Id: ex_tag.c,v 10.54 2012/04/12 07:17:30 zy Exp $";
 #endif /* not lint */
 
-#include <sys/param.h>
-#include <sys/types.h>		/* XXX: param.h may not have included types.h */
-
-#ifdef HAVE_SYS_MMAN_H
+#include <sys/types.h>
 #include <sys/mman.h>
-#endif
-
 #include <sys/queue.h>
 #include <sys/stat.h>
-#include <sys/time.h>
 
 #include <bitstring.h>
 #include <ctype.h>
@@ -45,14 +39,10 @@
 static char	*binary_search __P((char *, char *, char *));
 static int	 compare __P((char *, char *, char *));
 static void	 ctag_file __P((SCR *, TAGF *, char *, char **, size_t *));
-static int	 ctag_search __P((SCR *, char *, size_t, char *));
-#ifdef GTAGS
-static int	 getentry __P((char *, char **, char **, char **));
-static TAGQ	*gtag_slist __P((SCR *, char *, int));
-#endif
+static int	 ctag_search __P((SCR *, CHAR_T *, size_t, char *));
 static int	 ctag_sfile __P((SCR *, TAGF *, TAGQ *, char *));
-static TAGQ	*ctag_slist __P((SCR *, char *));
-static char	*linear_search __P((char *, char *, char *));
+static TAGQ	*ctag_slist __P((SCR *, CHAR_T *));
+static char	*linear_search __P((char *, char *, char *, long));
 static int	 tag_copy __P((SCR *, TAG *, TAG **));
 static int	 tag_pop __P((SCR *, TAGQ *, int));
 static int	 tagf_copy __P((SCR *, TAGF *, TAGF **));
@@ -63,19 +53,16 @@
  * ex_tag_first --
  *	The tag code can be entered from main, e.g., "vi -t tag".
  *
- * PUBLIC: int ex_tag_first __P((SCR *, char *));
+ * PUBLIC: int ex_tag_first __P((SCR *, CHAR_T *));
  */
 int
-ex_tag_first(sp, tagarg)
-	SCR *sp;
-	char *tagarg;
+ex_tag_first(SCR *sp, CHAR_T *tagarg)
 {
-	ARGS *ap[2], a;
 	EXCMD cmd;
 
 	/* Build an argument for the ex :tag command. */
-	ex_cinit(&cmd, C_TAG, 0, OOBLNO, OOBLNO, 0, ap);
-	ex_cadd(&cmd, &a, tagarg, strlen(tagarg));
+	ex_cinit(sp, &cmd, C_TAG, 0, OOBLNO, OOBLNO, 0);
+	argv_exp0(sp, &cmd, tagarg, STRLEN(tagarg));
 
 	/*
 	 * XXX
@@ -93,26 +80,7 @@
 	return (0);
 }
 
-#ifdef GTAGS
 /*
- * ex_rtag_push -- ^]
- *		  :rtag[!] [string]
- *
- * Enter a new TAGQ context based on a ctag string.
- *
- * PUBLIC: int ex_rtag_push __P((SCR *, EXCMD *));
- */
-int
-ex_rtag_push(sp, cmdp)
-	SCR *sp;
-	EXCMD *cmdp;
-{
-	F_SET(cmdp, E_REFERENCE);
-	return ex_tag_push(sp, cmdp);
-}
-#endif
-
-/*
  * ex_tag_push -- ^]
  *		  :tag[!] [string]
  *
@@ -121,18 +89,11 @@
  * PUBLIC: int ex_tag_push __P((SCR *, EXCMD *));
  */
 int
-ex_tag_push(sp, cmdp)
-	SCR *sp;
-	EXCMD *cmdp;
+ex_tag_push(SCR *sp, EXCMD *cmdp)
 {
 	EX_PRIVATE *exp;
-	FREF *frp;
-	TAG *rtp;
-	TAGQ *rtqp, *tqp;
-	recno_t lno;
-	size_t cno;
+	TAGQ *tqp;
 	long tl;
-	int force, istmp;
 
 	exp = EXP(sp);
 	switch (cmdp->argc) {
@@ -140,7 +101,8 @@
 		if (exp->tag_last != NULL)
 			free(exp->tag_last);
 
-		if ((exp->tag_last = strdup(cmdp->argv[0]->bp)) == NULL) {
+		if ((exp->tag_last = v_wstrdup(sp, cmdp->argv[0]->bp,
+		    cmdp->argv[0]->len)) == NULL) {
 			msgq(sp, M_SYSERR, NULL);
 			return (1);
 		}
@@ -147,7 +109,7 @@
 
 		/* Taglength may limit the number of characters. */
 		if ((tl =
-		    O_VAL(sp, O_TAGLENGTH)) != 0 && strlen(exp->tag_last) > tl)
+		    O_VAL(sp, O_TAGLENGTH)) != 0 && STRLEN(exp->tag_last) > tl)
 			exp->tag_last[tl] = '\0';
 		break;
 	case 0:
@@ -161,100 +123,14 @@
 	}
 
 	/* Get the tag information. */
-#ifdef GTAGS
-	if (O_ISSET(sp, O_GTAGSMODE)) {
-		if ((tqp = gtag_slist(sp, exp->tag_last, F_ISSET(cmdp, E_REFERENCE))) == NULL)
-			return (1);
-	} else
-#endif
 	if ((tqp = ctag_slist(sp, exp->tag_last)) == NULL)
 		return (1);
 
-	/*
-	 * Allocate all necessary memory before swapping screens.  Initialize
-	 * flags so we know what to free.
-	 */
-	rtp = NULL;
-	rtqp = NULL;
-	if (exp->tq.cqh_first == (void *)&exp->tq) {
-		/* Initialize the `local context' tag queue structure. */
-		CALLOC_GOTO(sp, rtqp, TAGQ *, 1, sizeof(TAGQ));
-		CIRCLEQ_INIT(&rtqp->tagq);
+	if (tagq_push(sp, tqp, F_ISSET(cmdp, E_NEWSCREEN), 
+			       FL_ISSET(cmdp->iflags, E_C_FORCE)))
+		return 1;
 
-		/* Initialize and link in its tag structure. */
-		CALLOC_GOTO(sp, rtp, TAG *, 1, sizeof(TAG));
-		CIRCLEQ_INSERT_HEAD(&rtqp->tagq, rtp, q);
-		rtqp->current = rtp;
-	}
-
-	/*
-	 * Stick the current context information in a convenient place, we're
-	 * about to lose it.  Note, if we're called on editor startup, there
-	 * will be no FREF structure.
-	 */
-	frp = sp->frp;
-	lno = sp->lno;
-	cno = sp->cno;
-	istmp = frp == NULL ||
-	    F_ISSET(frp, FR_TMPFILE) && !F_ISSET(cmdp, E_NEWSCREEN);
-
-	/* Try to switch to the tag. */
-	force = FL_ISSET(cmdp->iflags, E_C_FORCE);
-	if (F_ISSET(cmdp, E_NEWSCREEN)) {
-		if (ex_tag_Nswitch(sp, tqp->tagq.cqh_first, force))
-			goto err;
-
-		/* Everything else gets done in the new screen. */
-		sp = sp->nextdisp;
-		exp = EXP(sp);
-	} else
-		if (ex_tag_nswitch(sp, tqp->tagq.cqh_first, force))
-			goto err;
-
-	/*
-	 * If this is the first tag, put a `current location' queue entry
-	 * in place, so we can pop all the way back to the current mark.
-	 * Note, it doesn't point to much of anything, it's a placeholder.
-	 */
-	if (exp->tq.cqh_first == (void *)&exp->tq) {
-		CIRCLEQ_INSERT_HEAD(&exp->tq, rtqp, q);
-	} else
-		rtqp = exp->tq.cqh_first;
-
-	/* Link the new TAGQ structure into place. */
-	CIRCLEQ_INSERT_HEAD(&exp->tq, tqp, q);
-
-	(void)ctag_search(sp,
-	    tqp->current->search, tqp->current->slen, tqp->tag);
-
-	/*
-	 * Move the current context from the temporary save area into the
-	 * right structure.
-	 *
-	 * If we were in a temporary file, we don't have a context to which
-	 * we can return, so just make it be the same as what we're moving
-	 * to.  It will be a little odd that ^T doesn't change anything, but
-	 * I don't think it's a big deal.
-	 */
-	if (istmp) {
-		rtqp->current->frp = sp->frp;
-		rtqp->current->lno = sp->lno;
-		rtqp->current->cno = sp->cno;
-	} else {
-		rtqp->current->frp = frp;
-		rtqp->current->lno = lno;
-		rtqp->current->cno = cno;
-	}
-	return (0);
-
-err:
-alloc_err:
-	if (rtqp != NULL)
-		free(rtqp);
-	if (rtp != NULL)
-		free(rtp);
-	tagq_free(sp, tqp);
-	return (1);
+	return 0;
 }
 
 /* 
@@ -264,20 +140,20 @@
  * PUBLIC: int ex_tag_next __P((SCR *, EXCMD *));
  */
 int
-ex_tag_next(sp, cmdp)
-	SCR *sp;
-	EXCMD *cmdp;
+ex_tag_next(SCR *sp, EXCMD *cmdp)
 {
 	EX_PRIVATE *exp;
 	TAG *tp;
 	TAGQ *tqp;
+	char *np;
+	size_t nlen;
 
 	exp = EXP(sp);
-	if ((tqp = exp->tq.cqh_first) == (void *)&exp->tq) {
+	if ((tqp = TAILQ_FIRST(exp->tq)) == NULL) {
 		tag_msg(sp, TAG_EMPTY, NULL);
 		return (1);
 	}
-	if ((tp = tqp->current->q.cqe_next) == (void *)&tqp->tagq) {
+	if ((tp = TAILQ_NEXT(tqp->current, q)) == NULL) {
 		msgq(sp, M_ERR, "282|Already at the last tag of this group");
 		return (1);
 	}
@@ -289,6 +165,11 @@
 		(void)cscope_search(sp, tqp, tp);
 	else
 		(void)ctag_search(sp, tp->search, tp->slen, tqp->tag);
+	if (tqp->current->msg) {
+	    INT2CHAR(sp, tqp->current->msg, tqp->current->mlen + 1,
+		     np, nlen);
+	    msgq(sp, M_INFO, "%s", np);
+	}
 	return (0);
 }
 
@@ -299,20 +180,20 @@
  * PUBLIC: int ex_tag_prev __P((SCR *, EXCMD *));
  */
 int
-ex_tag_prev(sp, cmdp)
-	SCR *sp;
-	EXCMD *cmdp;
+ex_tag_prev(SCR *sp, EXCMD *cmdp)
 {
 	EX_PRIVATE *exp;
 	TAG *tp;
 	TAGQ *tqp;
+	char *np;
+	size_t nlen;
 
 	exp = EXP(sp);
-	if ((tqp = exp->tq.cqh_first) == (void *)&exp->tq) {
+	if ((tqp = TAILQ_FIRST(exp->tq)) == NULL) {
 		tag_msg(sp, TAG_EMPTY, NULL);
 		return (0);
 	}
-	if ((tp = tqp->current->q.cqe_prev) == (void *)&tqp->tagq) {
+	if ((tp = TAILQ_PREV(tqp->current, _tagqh, q)) == NULL) {
 		msgq(sp, M_ERR, "255|Already at the first tag of this group");
 		return (1);
 	}
@@ -324,6 +205,11 @@
 		(void)cscope_search(sp, tqp, tp);
 	else
 		(void)ctag_search(sp, tp->search, tp->slen, tqp->tag);
+	if (tqp->current->msg) {
+	    INT2CHAR(sp, tqp->current->msg, tqp->current->mlen + 1,
+		     np, nlen);
+	    msgq(sp, M_INFO, "%s", np);
+	}
 	return (0);
 }
 
@@ -334,10 +220,7 @@
  * PUBLIC: int ex_tag_nswitch __P((SCR *, TAG *, int));
  */
 int
-ex_tag_nswitch(sp, tp, force)
-	SCR *sp;
-	TAG *tp;
-	int force;
+ex_tag_nswitch(SCR *sp, TAG *tp, int force)
 {
 	/* Get a file structure. */
 	if (tp->frp == NULL && (tp->frp = file_add(sp, tp->fname)) == NULL)
@@ -371,10 +254,7 @@
  * PUBLIC: int ex_tag_Nswitch __P((SCR *, TAG *, int));
  */
 int
-ex_tag_Nswitch(sp, tp, force)
-	SCR *sp;
-	TAG *tp;
-	int force;
+ex_tag_Nswitch(SCR *sp, TAG *tp, int force)
 {
 	SCR *new;
 
@@ -428,9 +308,7 @@
  * PUBLIC: int ex_tag_pop __P((SCR *, EXCMD *));
  */
 int
-ex_tag_pop(sp, cmdp)
-	SCR *sp;
-	EXCMD *cmdp;
+ex_tag_pop(SCR *sp, EXCMD *cmdp)
 {
 	EX_PRIVATE *exp;
 	TAGQ *tqp, *dtqp;
@@ -437,10 +315,11 @@
 	size_t arglen;
 	long off;
 	char *arg, *p, *t;
+	size_t nlen;
 
 	/* Check for an empty stack. */
 	exp = EXP(sp);
-	if (exp->tq.cqh_first == (void *)&exp->tq) {
+	if (TAILQ_EMPTY(exp->tq)) {
 		tag_msg(sp, TAG_EMPTY, NULL);
 		return (1);
 	}
@@ -448,10 +327,11 @@
 	/* Find the last TAG structure that we're going to DISCARD! */
 	switch (cmdp->argc) {
 	case 0:				/* Pop one tag. */
-		dtqp = exp->tq.cqh_first;
+		dtqp = TAILQ_FIRST(exp->tq);
 		break;
 	case 1:				/* Name or number. */
-		arg = cmdp->argv[0]->bp;
+		INT2CHAR(sp, cmdp->argv[0]->bp, cmdp->argv[0]->len+1, 
+			 arg, nlen);
 		off = strtol(arg, &p, 10);
 		if (*p != '\0')
 			goto filearg;
@@ -459,10 +339,9 @@
 		/* Number: pop that many queue entries. */
 		if (off < 1)
 			return (0);
-		for (tqp = exp->tq.cqh_first;
-		    tqp != (void *)&exp->tq && --off > 1;
-		    tqp = tqp->q.cqe_next);
-		if (tqp == (void *)&exp->tq) {
+		TAILQ_FOREACH(tqp, exp->tq, q)
+			if (--off <= 1) break;
+		if (tqp == NULL) {
 			msgq(sp, M_ERR,
 	"159|Less than %s entries on the tags stack; use :display t[ags]",
 			    arg);
@@ -473,11 +352,10 @@
 
 		/* File argument: pop to that queue entry. */
 filearg:	arglen = strlen(arg);
-		for (tqp = exp->tq.cqh_first;
-		    tqp != (void *)&exp->tq;
-		    dtqp = tqp, tqp = tqp->q.cqe_next) {
+		for (tqp = TAILQ_FIRST(exp->tq); tqp;
+		    dtqp = tqp, tqp = TAILQ_NEXT(tqp, q)) {
 			/* Don't pop to the current file. */
-			if (tqp == exp->tq.cqh_first)
+			if (tqp == TAILQ_FIRST(exp->tq))
 				continue;
 			p = tqp->current->frp->name;
 			if ((t = strrchr(p, '/')) == NULL)
@@ -487,12 +365,12 @@
 			if (!strncmp(arg, t, arglen))
 				break;
 		}
-		if (tqp == (void *)&exp->tq) {
+		if (tqp == NULL) {
 			msgq_str(sp, M_ERR, arg,
 	"160|No file %s on the tags stack to return to; use :display t[ags]");
 			return (1);
 		}
-		if (tqp == exp->tq.cqh_first)
+		if (tqp == TAILQ_FIRST(exp->tq))
 			return (0);
 		break;
 	default:
@@ -509,9 +387,7 @@
  * PUBLIC: int ex_tag_top __P((SCR *, EXCMD *));
  */
 int
-ex_tag_top(sp, cmdp)
-	SCR *sp;
-	EXCMD *cmdp;
+ex_tag_top(SCR *sp, EXCMD *cmdp)
 {
 	EX_PRIVATE *exp;
 
@@ -518,14 +394,14 @@
 	exp = EXP(sp);
 
 	/* Check for an empty stack. */
-	if (exp->tq.cqh_first == (void *)&exp->tq) {
+	if (TAILQ_EMPTY(exp->tq)) {
 		tag_msg(sp, TAG_EMPTY, NULL);
 		return (1);
 	}
 
 	/* Return to the oldest information. */
-	return (tag_pop(sp,
-	    exp->tq.cqh_last->q.cqe_prev, FL_ISSET(cmdp->iflags, E_C_FORCE)));
+	return (tag_pop(sp, TAILQ_PREV(TAILQ_LAST(exp->tq, _tqh), _tqh, q),
+	    FL_ISSET(cmdp->iflags, E_C_FORCE)));
 }
 
 /*
@@ -533,10 +409,7 @@
  *	Pop up to and including the specified TAGQ context.
  */
 static int
-tag_pop(sp, dtqp, force)
-	SCR *sp;
-	TAGQ *dtqp;
-	int force;
+tag_pop(SCR *sp, TAGQ *dtqp, int force)
 {
 	EX_PRIVATE *exp;
 	TAG *tp;
@@ -548,7 +421,7 @@
 	 * Update the cursor from the saved TAG information of the TAG
 	 * structure we're moving to.
 	 */
-	tp = dtqp->q.cqe_next->current;
+	tp = TAILQ_NEXT(dtqp, q)->current;
 	if (tp->frp == sp->frp) {
 		sp->lno = tp->lno;
 		sp->cno = tp->cno;
@@ -567,7 +440,7 @@
 
 	/* Pop entries off the queue up to and including dtqp. */
 	do {
-		tqp = exp->tq.cqh_first;
+		tqp = TAILQ_FIRST(exp->tq);
 		if (tagq_free(sp, tqp))
 			return (0);
 	} while (tqp != dtqp);
@@ -576,8 +449,8 @@
 	 * If only a single tag left, we've returned to the first tag point,
 	 * and the stack is now empty.
 	 */
-	if (exp->tq.cqh_first->q.cqe_next == (void *)&exp->tq)
-		tagq_free(sp, exp->tq.cqh_first);
+	if (TAILQ_NEXT(TAILQ_FIRST(exp->tq), q) == NULL)
+		tagq_free(sp, TAILQ_FIRST(exp->tq));
 
 	return (0);
 }
@@ -589,8 +462,7 @@
  * PUBLIC: int ex_tag_display __P((SCR *));
  */
 int
-ex_tag_display(sp)
-	SCR *sp;
+ex_tag_display(SCR *sp)
 {
 	EX_PRIVATE *exp;
 	TAG *tp;
@@ -597,10 +469,10 @@
 	TAGQ *tqp;
 	int cnt;
 	size_t len;
-	char *p, *sep;
+	char *p;
 
 	exp = EXP(sp);
-	if ((tqp = exp->tq.cqh_first) == (void *)&exp->tq) {
+	if (TAILQ_EMPTY(exp->tq)) {
 		tag_msg(sp, TAG_EMPTY, NULL);
 		return (0);
 	}
@@ -628,11 +500,10 @@
 	 * Display the list of tags for each queue entry.  The first entry
 	 * is numbered, and the current tag entry has an asterisk appended.
 	 */
-	for (cnt = 1, tqp = exp->tq.cqh_first; !INTERRUPTED(sp) &&
-	    tqp != (void *)&exp->tq; ++cnt, tqp = tqp->q.cqe_next)
-		for (tp = tqp->tagq.cqh_first;
-		    tp != (void *)&tqp->tagq; tp = tp->q.cqe_next) {
-			if (tp == tqp->tagq.cqh_first)
+	for (cnt = 1, tqp = TAILQ_FIRST(exp->tq); !INTERRUPTED(sp) &&
+	    tqp != NULL; ++cnt, tqp = TAILQ_NEXT(tqp, q))
+		TAILQ_FOREACH(tp, tqp->tagq, q) {
+			if (tp == TAILQ_FIRST(tqp->tagq))
 				(void)ex_printf(sp, "%2d ", cnt);
 			else
 				(void)ex_printf(sp, "   ");
@@ -647,7 +518,7 @@
 			if (tqp->current == tp)
 				(void)ex_printf(sp, "*");
 
-			if (tp == tqp->tagq.cqh_first && tqp->tag != NULL &&
+			if (tp == TAILQ_FIRST(tqp->tagq) && tqp->tag != NULL &&
 			    (sp->cols - L_NAME) >= L_TAG + L_SPACE) {
 				len = strlen(tqp->tag);
 				if (len > sp->cols - (L_NAME + L_SPACE))
@@ -668,8 +539,7 @@
  * PUBLIC: int ex_tag_copy __P((SCR *, SCR *));
  */
 int
-ex_tag_copy(orig, sp)
-	SCR *orig, *sp;
+ex_tag_copy(SCR *orig, SCR *sp)
 {
 	EX_PRIVATE *oexp, *nexp;
 	TAGQ *aqp, *tqp;
@@ -680,33 +550,31 @@
 	nexp = EXP(sp);
 
 	/* Copy tag queue and tags stack. */
-	for (aqp = oexp->tq.cqh_first;
-	    aqp != (void *)&oexp->tq; aqp = aqp->q.cqe_next) {
+	TAILQ_FOREACH(aqp, oexp->tq, q) {
 		if (tagq_copy(sp, aqp, &tqp))
 			return (1);
-		for (ap = aqp->tagq.cqh_first;
-		    ap != (void *)&aqp->tagq; ap = ap->q.cqe_next) {
+		TAILQ_FOREACH(ap, aqp->tagq, q) {
 			if (tag_copy(sp, ap, &tp))
 				return (1);
 			/* Set the current pointer. */
 			if (aqp->current == ap)
 				tqp->current = tp;
-			CIRCLEQ_INSERT_TAIL(&tqp->tagq, tp, q);
+			TAILQ_INSERT_TAIL(tqp->tagq, tp, q);
 		}
-		CIRCLEQ_INSERT_TAIL(&nexp->tq, tqp, q);
+		TAILQ_INSERT_TAIL(nexp->tq, tqp, q);
 	}
 
 	/* Copy list of tag files. */
-	for (atfp = oexp->tagfq.tqh_first;
-	    atfp != NULL; atfp = atfp->q.tqe_next) {
+	TAILQ_FOREACH(atfp, oexp->tagfq, q) {
 		if (tagf_copy(sp, atfp, &tfp))
 			return (1);
-		TAILQ_INSERT_TAIL(&nexp->tagfq, tfp, q);
+		TAILQ_INSERT_TAIL(nexp->tagfq, tfp, q);
 	}
 
 	/* Copy the last tag. */
 	if (oexp->tag_last != NULL &&
-	    (nexp->tag_last = strdup(oexp->tag_last)) == NULL) {
+	    (nexp->tag_last = v_wstrdup(sp, oexp->tag_last, 
+					STRLEN(oexp->tag_last))) == NULL) {
 		msgq(sp, M_SYSERR, NULL);
 		return (1);
 	}
@@ -718,9 +586,7 @@
  *	Copy a TAGF structure and return it in new memory.
  */
 static int
-tagf_copy(sp, otfp, tfpp)
-	SCR *sp;
-	TAGF *otfp, **tfpp;
+tagf_copy(SCR *sp, TAGF *otfp, TAGF **tfpp)
 {
 	TAGF *tfp;
 
@@ -740,9 +606,7 @@
  *	Copy a TAGQ structure and return it in new memory.
  */
 static int
-tagq_copy(sp, otqp, tqpp)
-	SCR *sp;
-	TAGQ *otqp, **tqpp;
+tagq_copy(SCR *sp, TAGQ *otqp, TAGQ **tqpp)
 {
 	TAGQ *tqp;
 	size_t len;
@@ -753,7 +617,7 @@
 	MALLOC_RET(sp, tqp, TAGQ *, len);
 	memcpy(tqp, otqp, len);
 
-	CIRCLEQ_INIT(&tqp->tagq);
+	TAILQ_INIT(tqp->tagq);
 	tqp->current = NULL;
 	if (otqp->tag != NULL)
 		tqp->tag = tqp->buf;
@@ -767,9 +631,7 @@
  *	Copy a TAG structure and return it in new memory.
  */
 static int
-tag_copy(sp, otp, tpp)
-	SCR *sp;
-	TAG *otp, **tpp;
+tag_copy(SCR *sp, TAG *otp, TAG **tpp)
 {
 	TAG *tp;
 	size_t len;
@@ -779,13 +641,17 @@
 		len += otp->fnlen + 1;
 	if (otp->search != NULL)
 		len += otp->slen + 1;
+	if (otp->msg != NULL)
+		len += otp->mlen + 1;
 	MALLOC_RET(sp, tp, TAG *, len);
 	memcpy(tp, otp, len);
 
 	if (otp->fname != NULL)
-		tp->fname = tp->buf;
+		tp->fname = (char *)tp->buf;
 	if (otp->search != NULL)
-		tp->search = tp->fname + otp->fnlen + 1;
+		tp->search = tp->buf + (otp->search - otp->buf);
+	if (otp->msg != NULL)
+		tp->msg = tp->buf + (otp->msg - otp->buf);
 
 	*tpp = tp;
 	return (0);
@@ -796,14 +662,12 @@
  *	Free a TAGF structure.
  */
 static int
-tagf_free(sp, tfp)
-	SCR *sp;
-	TAGF *tfp;
+tagf_free(SCR *sp, TAGF *tfp)
 {
 	EX_PRIVATE *exp;
 
 	exp = EXP(sp);
-	TAILQ_REMOVE(&exp->tagfq, tfp, q);
+	TAILQ_REMOVE(exp->tagfq, tfp, q);
 	free(tfp->name);
 	free(tfp);
 	return (0);
@@ -816,16 +680,14 @@
  * PUBLIC: int tagq_free __P((SCR *, TAGQ *));
  */
 int
-tagq_free(sp, tqp)
-	SCR *sp;
-	TAGQ *tqp;
+tagq_free(SCR *sp, TAGQ *tqp)
 {
 	EX_PRIVATE *exp;
 	TAG *tp;
 
 	exp = EXP(sp);
-	while ((tp = tqp->tagq.cqh_first) != (void *)&tqp->tagq) {
-		CIRCLEQ_REMOVE(&tqp->tagq, tp, q);
+	while ((tp = TAILQ_FIRST(tqp->tagq)) != NULL) {
+		TAILQ_REMOVE(tqp->tagq, tp, q);
 		free(tp);
 	}
 	/*
@@ -833,13 +695,122 @@
 	 * If allocated and then the user failed to switch files, the TAGQ
 	 * structure was never attached to any list.
 	 */
-	if (tqp->q.cqe_next != NULL)
-		CIRCLEQ_REMOVE(&exp->tq, tqp, q);
+	if (TAILQ_ENTRY_ISVALID(tqp, q))
+		TAILQ_REMOVE(exp->tq, tqp, q);
 	free(tqp);
 	return (0);
 }
 
 /*
+ * PUBLIC: int tagq_push __P((SCR*, TAGQ*, int, int ));
+ */
+int
+tagq_push(SCR *sp, TAGQ *tqp, int new_screen, int force)
+{
+	EX_PRIVATE *exp;
+	FREF *frp;
+	TAG *rtp;
+	TAGQ *rtqp;
+	recno_t lno;
+	size_t cno;
+	int istmp;
+	char *np;
+	size_t nlen;
+
+	exp = EXP(sp);
+
+	/*
+	 * Allocate all necessary memory before swapping screens.  Initialize
+	 * flags so we know what to free.
+	 */
+	rtp = NULL;
+	rtqp = NULL;
+	if (TAILQ_EMPTY(exp->tq)) {
+		/* Initialize the `local context' tag queue structure. */
+		CALLOC_GOTO(sp, rtqp, TAGQ *, 1, sizeof(TAGQ));
+		TAILQ_INIT(rtqp->tagq);
+
+		/* Initialize and link in its tag structure. */
+		CALLOC_GOTO(sp, rtp, TAG *, 1, sizeof(TAG));
+		TAILQ_INSERT_HEAD(rtqp->tagq, rtp, q);
+		rtqp->current = rtp;
+	}
+
+	/*
+	 * Stick the current context information in a convenient place, we're
+	 * about to lose it.  Note, if we're called on editor startup, there
+	 * will be no FREF structure.
+	 */
+	frp = sp->frp;
+	lno = sp->lno;
+	cno = sp->cno;
+	istmp = frp == NULL ||
+	    (F_ISSET(frp, FR_TMPFILE) && !new_screen);
+
+	/* Try to switch to the preset tag. */
+	if (new_screen) {
+		if (ex_tag_Nswitch(sp, tqp->current, force))
+			goto err;
+
+		/* Everything else gets done in the new screen. */
+		sp = sp->nextdisp;
+		exp = EXP(sp);
+	} else
+		if (ex_tag_nswitch(sp, tqp->current, force))
+			goto err;
+
+	/*
+	 * If this is the first tag, put a `current location' queue entry
+	 * in place, so we can pop all the way back to the current mark.
+	 * Note, it doesn't point to much of anything, it's a placeholder.
+	 */
+	if (TAILQ_EMPTY(exp->tq)) {
+		TAILQ_INSERT_HEAD(exp->tq, rtqp, q);
+	} else
+		rtqp = TAILQ_FIRST(exp->tq);
+
+	/* Link the new TAGQ structure into place. */
+	TAILQ_INSERT_HEAD(exp->tq, tqp, q);
+
+	(void)ctag_search(sp,
+	    tqp->current->search, tqp->current->slen, tqp->tag);
+	if (tqp->current->msg) {
+	    INT2CHAR(sp, tqp->current->msg, tqp->current->mlen + 1,
+		     np, nlen);
+	    msgq(sp, M_INFO, "%s", np);
+	}
+
+	/*
+	 * Move the current context from the temporary save area into the
+	 * right structure.
+	 *
+	 * If we were in a temporary file, we don't have a context to which
+	 * we can return, so just make it be the same as what we're moving
+	 * to.  It will be a little odd that ^T doesn't change anything, but
+	 * I don't think it's a big deal.
+	 */
+	if (istmp) {
+		rtqp->current->frp = sp->frp;
+		rtqp->current->lno = sp->lno;
+		rtqp->current->cno = sp->cno;
+	} else {
+		rtqp->current->frp = frp;
+		rtqp->current->lno = lno;
+		rtqp->current->cno = cno;
+	}
+	return (0);
+
+err:
+alloc_err:
+	if (rtqp != NULL)
+		free(rtqp);
+	if (rtp != NULL)
+		free(rtp);
+	tagq_free(sp, tqp);
+	return (1);
+}
+
+/*
  * tag_msg
  *	A few common messages.
  *
@@ -846,10 +817,7 @@
  * PUBLIC: void tag_msg __P((SCR *, tagmsg_t, char *));
  */
 void
-tag_msg(sp, msg, tag)
-	SCR *sp;
-	tagmsg_t msg;
-	char *tag;
+tag_msg(SCR *sp, tagmsg_t msg, char *tag)
 {
 	switch (msg) {
 	case TAG_BADLNO:
@@ -874,9 +842,7 @@
  * PUBLIC: int ex_tagf_alloc __P((SCR *, char *));
  */
 int
-ex_tagf_alloc(sp, str)
-	SCR *sp;
-	char *str;
+ex_tagf_alloc(SCR *sp, char *str)
 {
 	EX_PRIVATE *exp;
 	TAGF *tfp;
@@ -885,13 +851,13 @@
 
 	/* Free current queue. */
 	exp = EXP(sp);
-	while ((tfp = exp->tagfq.tqh_first) != NULL)
+	while ((tfp = TAILQ_FIRST(exp->tagfq)) != NULL)
 		tagf_free(sp, tfp);
 
 	/* Create new queue. */
 	for (p = t = str;; ++p) {
-		if (*p == '\0' || isblank(*p)) {
-			if ((len = p - t) > 1) {
+		if (*p == '\0' || cmdskip(*p)) {
+			if ((len = p - t)) {
 				MALLOC_RET(sp, tfp, TAGF *, sizeof(TAGF));
 				MALLOC(sp, tfp->name, char *, len + 1);
 				if (tfp->name == NULL) {
@@ -901,7 +867,7 @@
 				memcpy(tfp->name, t, len);
 				tfp->name[len] = '\0';
 				tfp->flags = 0;
-				TAILQ_INSERT_TAIL(&exp->tagfq, tfp, q);
+				TAILQ_INSERT_TAIL(exp->tagfq, tfp, q);
 			}
 			t = p + 1;
 		}
@@ -918,8 +884,7 @@
  * PUBLIC: int ex_tag_free __P((SCR *));
  */
 int
-ex_tag_free(sp)
-	SCR *sp;
+ex_tag_free(SCR *sp)
 {
 	EX_PRIVATE *exp;
 	TAGF *tfp;
@@ -927,9 +892,9 @@
 
 	/* Free up tag information. */
 	exp = EXP(sp);
-	while ((tqp = exp->tq.cqh_first) != (void *)&exp->tq)
+	while ((tqp = TAILQ_FIRST(exp->tq)) != NULL)
 		tagq_free(sp, tqp);
-	while ((tfp = exp->tagfq.tqh_first) != NULL)
+	while ((tfp = TAILQ_FIRST(exp->tagfq)) != NULL)
 		tagf_free(sp, tfp);
 	if (exp->tag_last != NULL)
 		free(exp->tag_last);
@@ -941,13 +906,12 @@
  *	Search a file for a tag.
  */
 static int
-ctag_search(sp, search, slen, tag)
-	SCR *sp;
-	char *search, *tag;
-	size_t slen;
+ctag_search(SCR *sp, CHAR_T *search, size_t slen, char *tag)
 {
 	MARK m;
 	char *p;
+	char *np;
+	size_t nlen;
 
 	/*
 	 * !!!
@@ -955,8 +919,9 @@
 	 * used a line number, not a search string.  I got complaints, so
 	 * people are still using the format.  POSIX 1003.2 permits it.
 	 */
-	if (isdigit(search[0])) {
-		m.lno = atoi(search);
+	if (ISDIGIT(search[0])) {
+		INT2CHAR(sp, search, slen+1, np, nlen);
+		m.lno = atoi(np);
 		if (!db_exist(sp, m.lno)) {
 			tag_msg(sp, TAG_BADLNO, tag);
 			return (1);
@@ -969,9 +934,10 @@
 		m.lno = 1;
 		m.cno = 0;
 		if (f_search(sp, &m, &m,
-		    search, slen, NULL, SEARCH_FILE | SEARCH_TAG))
-			if ((p = strrchr(search, '(')) != NULL) {
-				slen = p - search;
+		    search, slen, NULL, SEARCH_FILE | SEARCH_TAG)) {
+			INT2CHAR(sp, search, slen, np, nlen);
+			if ((p = strrchr(np, '(')) != NULL) {
+				slen = p - np;
 				if (f_search(sp, &m, &m, search, slen,
 				    NULL, SEARCH_FILE | SEARCH_TAG))
 					goto notfound;
@@ -979,6 +945,7 @@
 notfound:			tag_msg(sp, TAG_SEARCH, tag);
 				return (1);
 			}
+		}
 		/*
 		 * !!!
 		 * Historically, tags set the search direction if it wasn't
@@ -998,160 +965,37 @@
 	return (0);
 }
 
-#ifdef GTAGS
 /*
- * getentry --
- *	get tag information from current line.
- *
- * gtags temporary file format.
- * <tag>   <lineno>  <file>         <image>
- *
- * sample.
- * +------------------------------------------------
- * |main     30      main.c         main(argc, argv)
- * |func     21      subr.c         func(arg)
- */
-static int
-getentry(buf, tag, file, line)
-	char *buf, **tag, **file, **line;
-{
-	char *p = buf;
-
-	for (*tag = p; *p && !isspace(*p); p++)		/* tag name */
-		;
-	if (*p == 0)
-		goto err;
-	*p++ = 0;
-	for (; *p && isspace(*p); p++)			/* (skip blanks) */
-		;
-	if (*p == 0)
-		goto err;
-	*line = p;					/* line no */
-	for (*line = p; *p && !isspace(*p); p++)
-		;
-	if (*p == 0)
-		goto err;
-	*p++ = 0;
-	for (; *p && isspace(*p); p++)			/* (skip blanks) */
-		;
-	if (*p == 0)
-		goto err;
-	*file = p;					/* file name */
-	for (*file = p; *p && !isspace(*p); p++)
-		;
-	if (*p == 0)
-		goto err;
-	*p = 0;
-
-	/* value check */
-	if (strlen(*tag) && strlen(*line) && strlen(*file) && atoi(*line) > 0)
-		return 1;	/* OK */
-err:
-	return 0;		/* ERROR */
-}
-
-/*
- * gtag_slist --
- *	Search the list of tags files for a tag, and return tag queue.
- */
-static TAGQ *
-gtag_slist(sp, tag, ref)
-	SCR *sp;
-	char *tag;
-	int ref;
-{
-	EX_PRIVATE *exp;
-	TAGF *tfp;
-	TAGQ *tqp;
-	size_t len;
-	int echk;
-	TAG *tp;
-	char *name, *file, *line;
-	char command[BUFSIZ];
-	char buf[BUFSIZ];
-	FILE *fp;
-
-	/* 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);
-
-	/*
-	 * Find the tag, only display missing file messages once, and
-	 * then only if we didn't find the tag.
-	 */
-	snprintf(command, sizeof(command), "global -%s '%s'", ref ? "rx" : "x", tag);
-	if (fp = popen(command, "r")) {
-		while (fgets(buf, sizeof(buf), fp)) {
-			if (buf[strlen(buf)-1] == '\n')		/* chop(buf) */
-				buf[strlen(buf)-1] = 0;
-			else
-				while (fgetc(fp) != '\n')
-					;
-			if (getentry(buf, &name, &file, &line) == 0) {
-				echk = 1;
-				F_SET(tfp, TAGF_ERR);
-				break;
-			}
-			CALLOC_GOTO(sp, tp,
-			    TAG *, 1, sizeof(TAG) + strlen(file) + 1 + strlen(line) + 1);
-			tp->fname = tp->buf;
-			strcpy(tp->fname, file);
-			tp->fnlen = strlen(file);
-			tp->search = tp->fname + tp->fnlen + 1;
-			strcpy(tp->search, line);
-			CIRCLEQ_INSERT_TAIL(&tqp->tagq, tp, q);
-		}
-		pclose(fp);
-	}
-
-	/* Check to see if we found anything. */
-	if (tqp->tagq.cqh_first == (void *)&tqp->tagq) {
-		msgq_str(sp, M_ERR, tag, "162|%s: tag not found");
-		free(tqp);
-		return (NULL);
-	}
-
-	tqp->current = tqp->tagq.cqh_first;
-	return (tqp);
-
-alloc_err:
-	return (NULL);
-}
-#endif
-/*
  * ctag_slist --
  *	Search the list of tags files for a tag, and return tag queue.
  */
 static TAGQ *
-ctag_slist(sp, tag)
-	SCR *sp;
-	char *tag;
+ctag_slist(SCR *sp, CHAR_T *tag)
 {
 	EX_PRIVATE *exp;
 	TAGF *tfp;
 	TAGQ *tqp;
 	size_t len;
-	int echk;
+	int echk = 0;
+	char *np;
+	size_t nlen;
 
 	exp = EXP(sp);
 
 	/* Allocate and initialize the tag queue structure. */
-	len = strlen(tag);
+	INT2CHAR(sp, tag, STRLEN(tag) + 1, np, nlen);
+	len = nlen - 1;
 	CALLOC_GOTO(sp, tqp, TAGQ *, 1, sizeof(TAGQ) + len + 1);
-	CIRCLEQ_INIT(&tqp->tagq);
+	TAILQ_INIT(tqp->tagq);
 	tqp->tag = tqp->buf;
-	memcpy(tqp->tag, tag, (tqp->tlen = len) + 1);
+	memcpy(tqp->tag, np, (tqp->tlen = len) + 1);
 
 	/*
 	 * Find the tag, only display missing file messages once, and
 	 * then only if we didn't find the tag.
 	 */
-	for (echk = 0,
-	    tfp = exp->tagfq.tqh_first; tfp != NULL; tfp = tfp->q.tqe_next)
-		if (ctag_sfile(sp, tfp, tqp, tag)) {
+	TAILQ_FOREACH(tfp, exp->tagfq, q)
+		if (ctag_sfile(sp, tfp, tqp, tqp->tag)) {
 			echk = 1;
 			F_SET(tfp, TAGF_ERR);
 		} else
@@ -1158,11 +1002,10 @@
 			F_CLR(tfp, TAGF_ERR | TAGF_ERR_WARN);
 
 	/* Check to see if we found anything. */
-	if (tqp->tagq.cqh_first == (void *)&tqp->tagq) {
-		msgq_str(sp, M_ERR, tag, "162|%s: tag not found");
+	if (TAILQ_EMPTY(tqp->tagq)) {
+		msgq_str(sp, M_ERR, tqp->tag, "162|%s: tag not found");
 		if (echk)
-			for (tfp = exp->tagfq.tqh_first;
-			    tfp != NULL; tfp = tfp->q.tqe_next)
+			TAILQ_FOREACH(tfp, exp->tagfq, q)
 				if (F_ISSET(tfp, TAGF_ERR) &&
 				    !F_ISSET(tfp, TAGF_ERR_WARN)) {
 					errno = tfp->errnum;
@@ -1173,7 +1016,6 @@
 		return (NULL);
 	}
 
-	tqp->current = tqp->tagq.cqh_first;
 	return (tqp);
 
 alloc_err:
@@ -1185,17 +1027,17 @@
  *	Search a tags file for a tag, adding any found to the tag queue.
  */
 static int
-ctag_sfile(sp, tfp, tqp, tname)
-	SCR *sp;
-	TAGF *tfp;
-	TAGQ *tqp;
-	char *tname;
+ctag_sfile(SCR *sp, TAGF *tfp, TAGQ *tqp, char *tname)
 {
 	struct stat sb;
 	TAG *tp;
-	size_t dlen, nlen, slen;
+	size_t dlen, nlen = 0, slen;
 	int fd, i, nf1, nf2;
-	char *back, *cname, *dname, *front, *map, *name, *p, *search, *t;
+	char *back, *front, *map, *p, *search, *t;
+	char *cname = NULL, *dname = NULL, *name = NULL;
+	CHAR_T *wp;
+	size_t wlen;
+	long tl;
 
 	if ((fd = open(tfp->name, O_RDONLY, 0)) < 0) {
 		tfp->errnum = errno;
@@ -1202,34 +1044,19 @@
 		return (1);
 	}
 
-	/*
-	 * XXX
-	 * Some old BSD systems require MAP_FILE as an argument when mapping
-	 * regular files.
-	 */
-#ifndef MAP_FILE
-#define	MAP_FILE	0
-#endif
-	/*
-	 * XXX
-	 * We'd like to test if the file is too big to mmap.  Since we don't
-	 * know what size or type off_t's or size_t's are, what the largest
-	 * unsigned integral type is, or what random insanity the local C
-	 * compiler will perpetrate, doing the comparison in a portable way
-	 * is flatly impossible.  Hope mmap fails if the file is too large.
-	 */
 	if (fstat(fd, &sb) != 0 ||
-	    (map = mmap(NULL, (size_t)sb.st_size, PROT_READ | PROT_WRITE,
-	    MAP_FILE | MAP_PRIVATE, fd, (off_t)0)) == (caddr_t)-1) {
+	    (map = mmap(NULL, sb.st_size, PROT_READ | PROT_WRITE,
+	    MAP_PRIVATE, fd, 0)) == MAP_FAILED) {
 		tfp->errnum = errno;
 		(void)close(fd);
 		return (1);
 	}
 
+	tl = O_VAL(sp, O_TAGLENGTH);
 	front = map;
 	back = front + sb.st_size;
 	front = binary_search(tname, front, back);
-	front = linear_search(tname, front, back);
+	front = linear_search(tname, front, back, tl);
 	if (front == NULL)
 		goto done;
 
@@ -1292,7 +1119,7 @@
 		}
 
 		/* Check for passing the last entry. */
-		if (strcmp(tname, cname))
+		if (tl ? strncmp(tname, cname, tl) : strcmp(tname, cname))
 			break;
 
 		/* Resolve the file name. */
@@ -1299,9 +1126,12 @@
 		ctag_file(sp, tfp, name, &dname, &dlen);
 
 		CALLOC_GOTO(sp, tp,
-		    TAG *, 1, sizeof(TAG) + dlen + 2 + nlen + 1 + slen + 1);
-		tp->fname = tp->buf;
-		if (dlen != 0) {
+		    TAG *, 1, sizeof(TAG) + dlen + 2 + nlen + 1 + 
+		    (slen + 1) * sizeof(CHAR_T));
+		tp->fname = (char *)tp->buf;
+		if (dlen == 1 && *dname == '.')
+			--dlen;
+		else if (dlen != 0) {
 			memcpy(tp->fname, dname, dlen);
 			tp->fname[dlen] = '/';
 			++dlen;
@@ -1308,13 +1138,22 @@
 		}
 		memcpy(tp->fname + dlen, name, nlen + 1);
 		tp->fnlen = dlen + nlen;
-		tp->search = tp->fname + tp->fnlen + 1;
-		memcpy(tp->search, search, (tp->slen = slen) + 1);
-		CIRCLEQ_INSERT_TAIL(&tqp->tagq, tp, q);
+		tp->search = (CHAR_T*)(tp->fname + tp->fnlen + 1);
+		CHAR2INT(sp, search, slen + 1, wp, wlen);
+		MEMCPY(tp->search, wp, (tp->slen = slen) + 1);
+		TAILQ_INSERT_TAIL(tqp->tagq, tp, q);
+
+		/* Try to preset the tag within the current file. */
+		if (sp->frp != NULL && sp->frp->name != NULL &&
+		    tqp->current == NULL && !strcmp(tp->fname, sp->frp->name))
+			tqp->current = tp;
 	}
 
+	if (tqp->current == NULL)
+		tqp->current = TAILQ_FIRST(tqp->tagq);
+
 alloc_err:
-done:	if (munmap(map, (size_t)sb.st_size))
+done:	if (munmap(map, sb.st_size))
 		msgq(sp, M_SYSERR, "munmap");
 	if (close(fd))
 		msgq(sp, M_SYSERR, "close");
@@ -1326,15 +1165,10 @@
  *	Search for the right path to this file.
  */
 static void
-ctag_file(sp, tfp, name, dirp, dlenp)
-	SCR *sp;
-	TAGF *tfp;
-	char *name, **dirp;
-	size_t *dlenp;
+ctag_file(SCR *sp, TAGF *tfp, char *name, char **dirp, size_t *dlenp)
 {
 	struct stat sb;
-	size_t len;
-	char *p, buf[MAXPATHLEN];
+	char *p, *buf;
 
 	/*
 	 * !!!
@@ -1348,12 +1182,16 @@
 	if (name[0] != '/' &&
 	    stat(name, &sb) && (p = strrchr(tfp->name, '/')) != NULL) {
 		*p = '\0';
-		len = snprintf(buf, sizeof(buf), "%s/%s", tfp->name, name);
-		*p = '/';
+		if ((buf = join(tfp->name, name)) == NULL) {
+			msgq(sp, M_SYSERR, NULL);
+			return;
+		}
 		if (stat(buf, &sb) == 0) {
 			*dirp = tfp->name;
 			*dlenp = strlen(*dirp);
 		}
+		free(buf);
+		*p = '/';
 	}
 }
 
@@ -1399,11 +1237,11 @@
 #define	GREATER		1
 #define	LESS		(-1)
 
-#define	SKIP_PAST_NEWLINE(p, back)	while (p < back && *p++ != '\n');
+#define	SKIP_PAST_NEWLINE(p, back)					\
+	while (p < back && *p++ != '\n') continue;
 
 static char *
-binary_search(string, front, back)
-	register char *string, *front, *back;
+binary_search(register char *string, register char *front, register char *back)
 {
 	register char *p;
 
@@ -1433,11 +1271,12 @@
  *	o front is before or at the first line to be printed.
  */
 static char *
-linear_search(string, front, back)
-	char *string, *front, *back;
+linear_search(char *string, char *front, char *back, long tl)
 {
+	char *end;
 	while (front < back) {
-		switch (compare(string, front, back)) {
+		end = tl && back-front > tl ? front+tl : back;
+		switch (compare(string, front, end)) {
 		case EQUAL:		/* Found it. */
 			return (front);
 		case LESS:		/* No such string. */
@@ -1465,8 +1304,7 @@
  * However, historic programs did use spaces, and, I got complaints.
  */
 static int
-compare(s1, s2, back)
-	register char *s1, *s2, *back;
+compare(register char *s1, register char *s2, register char *back)
 {
 	for (; *s1 && s2 < back && (*s2 != '\t' && *s2 != ' '); ++s1, ++s2)
 		if (*s1 != *s2)

Modified: trunk/contrib/nvi/ex/ex_txt.c
===================================================================
--- trunk/contrib/nvi/ex/ex_txt.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/ex/ex_txt.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -10,11 +10,12 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)ex_txt.c	10.17 (Berkeley) 10/10/96";
+static const char sccsid[] = "$Id: ex_txt.c,v 10.23 2001/06/25 15:19:21 skimo Exp $";
 #endif /* not lint */
 
 #include <sys/types.h>
 #include <sys/queue.h>
+#include <sys/time.h>
 
 #include <bitstring.h>
 #include <ctype.h>
@@ -24,6 +25,7 @@
 #include <string.h>
 
 #include "../common/common.h"
+#include "../vi/vi.h"
 
 /*
  * !!!
@@ -52,11 +54,7 @@
  * PUBLIC: int ex_txt __P((SCR *, TEXTH *, ARG_CHAR_T, u_int32_t));
  */
 int
-ex_txt(sp, tiqh, prompt, flags)
-	SCR *sp;
-	TEXTH *tiqh;
-	ARG_CHAR_T prompt;
-	u_int32_t flags;
+ex_txt(SCR *sp, TEXTH *tiqh, ARG_CHAR_T prompt, u_int32_t flags)
 {
 	EVENT ev;
 	GS *gp;
@@ -64,6 +62,7 @@
 	carat_t carat_st;
 	size_t cnt;
 	int rval;
+	int nochange;
 
 	rval = 0;
 
@@ -72,9 +71,9 @@
 	 * last one if it's big enough.  (All TEXT bookkeeping fields default
 	 * to 0 -- text_init() handles this.)
 	 */
-	if (tiqh->cqh_first != (void *)tiqh) {
-		tp = tiqh->cqh_first;
-		if (tp->q.cqe_next != (void *)tiqh || tp->lb_len < 32) {
+	if (!TAILQ_EMPTY(tiqh)) {
+		tp = TAILQ_FIRST(tiqh);
+		if (TAILQ_NEXT(tp, q) != NULL || tp->lb_len < 32) {
 			text_lfree(tiqh);
 			goto newtp;
 		}
@@ -82,7 +81,7 @@
 	} else {
 newtp:		if ((tp = text_init(sp, NULL, 0, 32)) == NULL)
 			goto err;
-		CIRCLEQ_INSERT_HEAD(tiqh, tp, q);
+		TAILQ_INSERT_HEAD(tiqh, tp, q);
 	}
 
 	/* Set the starting line number. */
@@ -112,7 +111,7 @@
 		txt_prompt(sp, tp, prompt, flags);
 	}
 
-	for (carat_st = C_NOTSET;;) {
+	for (carat_st = C_NOTSET, nochange = 0;;) {
 		if (v_event_get(sp, &ev, 0, 0))
 			goto err;
 
@@ -146,7 +145,7 @@
 		 * Check to see if the character fits into the input buffer.
 		 * (Use tp->len, ignore overwrite and non-printable chars.)
 		 */
-		BINC_GOTO(sp, tp->lb, tp->lb_len, tp->len + 1);
+		BINC_GOTOW(sp, tp->lb, tp->lb_len, tp->len + 1);
 
 		switch (ev.e_value) {
 		case K_CR:
@@ -189,7 +188,7 @@
 			 */
 			if (LF_ISSET(TXT_DOTTERM) && tp->len == tp->ai + 1 &&
 			    tp->lb[tp->len - 1] == '.') {
-notlast:			CIRCLEQ_REMOVE(tiqh, tp, q);
+notlast:			TAILQ_REMOVE(tiqh, tp, q);
 				text_free(tp);
 				goto done;
 			}
@@ -208,7 +207,8 @@
 			 * erased.
 			 */
 			if (LF_ISSET(TXT_AUTOINDENT)) {
-				if (carat_st == C_NOCHANGE) {
+				if (nochange) {
+					nochange = 0;
 					if (v_txt_auto(sp,
 					    OOBLNO, &ait, ait.ai, ntp))
 						goto err;
@@ -226,7 +226,7 @@
 			 * into the queue.
 			 */
 			tp = ntp;
-			CIRCLEQ_INSERT_TAIL(tiqh, tp, q);
+			TAILQ_INSERT_TAIL(tiqh, tp, q);
 			break;
 		case K_CARAT:			/* Delete autoindent chars. */
 			if (tp->len <= tp->ai && LF_ISSET(TXT_AUTOINDENT))
@@ -291,11 +291,12 @@
 				/* Save the ai string for later. */
 				ait.lb = NULL;
 				ait.lb_len = 0;
-				BINC_GOTO(sp, ait.lb, ait.lb_len, tp->ai);
-				memcpy(ait.lb, tp->lb, tp->ai);
+				BINC_GOTOW(sp, ait.lb, ait.lb_len, tp->ai);
+				MEMCPY(ait.lb, tp->lb, tp->ai);
 				ait.ai = ait.len = tp->ai;
 
-				carat_st = C_NOCHANGE;
+				carat_st = C_NOTSET;
+				nochange = 1;
 				goto leftmargin;
 			case C_ZEROSET:			/* 0^D */
 				if (tp->len > tp->ai + 1)
@@ -328,7 +329,7 @@
 			 * not already handled specially, except for <tab> and
 			 * <ff>.
 			 */
-ins_ch:			if (LF_ISSET(TXT_BEAUTIFY) && iscntrl(ev.e_c) &&
+ins_ch:			if (LF_ISSET(TXT_BEAUTIFY) && ISCNTRL(ev.e_c) &&
 			    ev.e_value != K_FORMFEED && ev.e_value != K_TAB)
 				break;
 
@@ -352,24 +353,20 @@
  *	not ours.
  */
 static void
-txt_prompt(sp, tp, prompt, flags)
-	SCR *sp;
-	TEXT *tp;
-	ARG_CHAR_T prompt;
-	u_int32_t flags;
+txt_prompt(SCR *sp, TEXT *tp, ARG_CHAR_T prompt, u_int32_t flags)
 {
 	/* Display the prompt. */
 	if (LF_ISSET(TXT_PROMPT))
-		(void)printf("%c", prompt);
+		(void)ex_printf(sp, "%c", prompt);
 
 	/* Display the line number. */
 	if (LF_ISSET(TXT_NUMBER) && O_ISSET(sp, O_NUMBER))
-		(void)printf("%6lu  ", (u_long)tp->lno);
+		(void)ex_printf(sp, "%6lu  ", (u_long)tp->lno);
 
 	/* Print out autoindent string. */
 	if (LF_ISSET(TXT_AUTOINDENT))
-		(void)printf("%.*s", (int)tp->ai, tp->lb);
-	(void)fflush(stdout);
+		(void)ex_printf(sp, WVS, (int)tp->ai, tp->lb);
+	(void)ex_fflush(sp);
 }
 
 /*
@@ -380,9 +377,7 @@
  * ranting and raving.  This is a fair bit simpler as ^T isn't special.
  */
 static int
-txt_dent(sp, tp)
-	SCR *sp;
-	TEXT *tp;
+txt_dent(SCR *sp, TEXT *tp)
 {
 	u_long sw, ts;
 	size_t cno, off, scno, spaces, tabs;
@@ -416,7 +411,7 @@
 	spaces = scno - cno;
 
 	/* Make sure there's enough room. */
-	BINC_RET(sp, tp->lb, tp->lb_len, tabs + spaces + 1);
+	BINC_RETW(sp, tp->lb, tp->lb_len, tabs + spaces + 1);
 
 	/* Adjust the final ai character count. */
 	tp->ai = tabs + spaces;

Modified: trunk/contrib/nvi/ex/ex_undo.c
===================================================================
--- trunk/contrib/nvi/ex/ex_undo.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/ex/ex_undo.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -10,11 +10,12 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)ex_undo.c	10.6 (Berkeley) 3/6/96";
+static const char sccsid[] = "$Id: ex_undo.c,v 10.7 2001/06/25 15:19:21 skimo Exp $";
 #endif /* not lint */
 
 #include <sys/types.h>
 #include <sys/queue.h>
+#include <sys/time.h>
 
 #include <bitstring.h>
 #include <limits.h>
@@ -30,9 +31,7 @@
  * PUBLIC: int ex_undo __P((SCR *, EXCMD *));
  */
 int
-ex_undo(sp, cmdp)
-	SCR *sp;
-	EXCMD *cmdp;
+ex_undo(SCR *sp, EXCMD *cmdp)
 {
 	EXF *ep;
 	MARK m;

Modified: trunk/contrib/nvi/ex/ex_usage.c
===================================================================
--- trunk/contrib/nvi/ex/ex_usage.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/ex/ex_usage.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -10,7 +10,7 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)ex_usage.c	10.13 (Berkeley) 5/3/96";
+static const char sccsid[] = "$Id: ex_usage.c,v 10.16 2011/12/21 19:26:48 zy Exp $";
 #endif /* not lint */
 
 #include <sys/types.h>
@@ -34,9 +34,7 @@
  * PUBLIC: int ex_help __P((SCR *, EXCMD *));
  */
 int
-ex_help(sp, cmdp)
-	SCR *sp;
-	EXCMD *cmdp;
+ex_help(SCR *sp, EXCMD *cmdp)
 {
 	(void)ex_puts(sp,
 	    "To see the list of vi commands, enter \":viusage<CR>\"\n");
@@ -57,30 +55,28 @@
  * PUBLIC: int ex_usage __P((SCR *, EXCMD *));
  */
 int
-ex_usage(sp, cmdp)
-	SCR *sp;
-	EXCMD *cmdp;
+ex_usage(SCR *sp, EXCMD *cmdp)
 {
 	ARGS *ap;
 	EXCMDLIST const *cp;
 	int newscreen;
-	char *name, *p, nb[MAXCMDNAMELEN + 5];
+	CHAR_T *name, *p, nb[MAXCMDNAMELEN + 5];
 
 	switch (cmdp->argc) {
 	case 1:
 		ap = cmdp->argv[0];
-		if (isupper(ap->bp[0])) {
+		if (ISUPPER(ap->bp[0])) {
 			newscreen = 1;
-			ap->bp[0] = tolower(ap->bp[0]);
+			ap->bp[0] = TOLOWER(ap->bp[0]);
 		} else
 			newscreen = 0;
 		for (cp = cmds; cp->name != NULL &&
-		    memcmp(ap->bp, cp->name, ap->len); ++cp);
+		    MEMCMP(ap->bp, cp->name, ap->len); ++cp);
 		if (cp->name == NULL ||
-		    newscreen && !F_ISSET(cp, E_NEWSCREEN)) {
+		    (newscreen && !F_ISSET(cp, E_NEWSCREEN))) {
 			if (newscreen)
-				ap->bp[0] = toupper(ap->bp[0]);
-			(void)ex_printf(sp, "The %.*s command is unknown\n",
+				ap->bp[0] = TOUPPER(ap->bp[0]);
+			(void)ex_printf(sp, "The "WVS" command is unknown\n",
 			    (int)ap->len, ap->bp);
 		} else {
 			(void)ex_printf(sp,
@@ -112,10 +108,10 @@
 			 * room, they're all short names.
 			 */
 			if (cp == &cmds[C_SCROLL])
-				name = "^D";
+				name = L("^D");
 			else if (F_ISSET(cp, E_NEWSCREEN)) {
 				nb[0] = '[';
-				nb[1] = toupper(cp->name[0]);
+				nb[1] = TOUPPER(cp->name[0]);
 				nb[2] = cp->name[0];
 				nb[3] = ']';
 				for (name = cp->name + 1,
@@ -124,7 +120,7 @@
 			} else
 				name = cp->name;
 			(void)ex_printf(sp,
-			    "%*s: %s\n", MAXCMDNAMELEN, name, cp->help);
+			    WVS": %s\n", MAXCMDNAMELEN, name, cp->help);
 		}
 		break;
 	default:
@@ -140,9 +136,7 @@
  * PUBLIC: int ex_viusage __P((SCR *, EXCMD *));
  */
 int
-ex_viusage(sp, cmdp)
-	SCR *sp;
-	EXCMD *cmdp;
+ex_viusage(SCR *sp, EXCMD *cmdp)
 {
 	GS *gp;
 	VIKEYS const *kp;

Modified: trunk/contrib/nvi/ex/ex_util.c
===================================================================
--- trunk/contrib/nvi/ex/ex_util.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/ex/ex_util.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -10,7 +10,7 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)ex_util.c	10.23 (Berkeley) 6/19/96";
+static const char sccsid[] = "$Id: ex_util.c,v 10.32 2001/06/25 15:19:21 skimo Exp $";
 #endif /* not lint */
 
 #include <sys/types.h>
@@ -31,15 +31,10 @@
  * ex_cinit --
  *	Create an EX command structure.
  *
- * PUBLIC: void ex_cinit __P((EXCMD *,
- * PUBLIC:    int, int, recno_t, recno_t, int, ARGS **));
+ * PUBLIC: void ex_cinit __P((SCR *, EXCMD *, int, int, recno_t, recno_t, int));
  */
 void
-ex_cinit(cmdp, cmd_id, naddr, lno1, lno2, force, ap)
-	EXCMD *cmdp;
-	int cmd_id, force, naddr;
-	recno_t lno1, lno2;
-	ARGS **ap;
+ex_cinit(SCR *sp, EXCMD *cmdp, int cmd_id, int naddr, recno_t lno1, recno_t lno2, int force)
 {
 	memset(cmdp, 0, sizeof(EXCMD));
 	cmdp->cmd = &cmds[cmd_id];
@@ -49,31 +44,10 @@
 	cmdp->addr1.cno = cmdp->addr2.cno = 1;
 	if (force)
 		cmdp->iflags |= E_C_FORCE;
-	cmdp->argc = 0;
-	if ((cmdp->argv = ap) != NULL)
-		cmdp->argv[0] = NULL;
+	(void)argv_init(sp, cmdp);
 }
 
 /*
- * ex_cadd --
- *	Add an argument to an EX command structure.
- *
- * PUBLIC: void ex_cadd __P((EXCMD *, ARGS *, char *, size_t));
- */
-void
-ex_cadd(cmdp, ap, arg, len)
-	EXCMD *cmdp;
-	ARGS *ap;
-	char *arg;
-	size_t len;
-{
-	cmdp->argv[cmdp->argc] = ap;
-	ap->bp = arg;
-	ap->len = len;
-	cmdp->argv[++cmdp->argc] = NULL;
-}
-
-/*
  * ex_getline --
  *	Return a line from the file.
  *
@@ -80,10 +54,7 @@
  * PUBLIC: int ex_getline __P((SCR *, FILE *, size_t *));
  */
 int
-ex_getline(sp, fp, lenp)
-	SCR *sp;
-	FILE *fp;
-	size_t *lenp;
+ex_getline(SCR *sp, FILE *fp, size_t *lenp)
 {
 	EX_PRIVATE *exp;
 	size_t off;
@@ -93,7 +64,7 @@
 	exp = EXP(sp);
 	for (errno = 0, off = 0, p = exp->ibp;;) {
 		if (off >= exp->ibp_len) {
-			BINC_RET(sp, exp->ibp, exp->ibp_len, off + 1);
+			BINC_RETC(sp, exp->ibp, exp->ibp_len, off + 1);
 			p = exp->ibp + off;
 		}
 		if ((ch = getc(fp)) == EOF && !feof(fp)) {
@@ -123,9 +94,7 @@
  * PUBLIC: int ex_ncheck __P((SCR *, int));
  */
 int
-ex_ncheck(sp, force)
-	SCR *sp;
-	int force;
+ex_ncheck(SCR *sp, int force)
 {
 	char **ap;
 
@@ -140,7 +109,7 @@
 
 		for (ap = sp->cargv + 1; *ap != NULL; ++ap);
 		msgq(sp, M_ERR,
-		    "167|%d more files to edit", (ap - sp->cargv) - 1);
+		    "167|%d more files to edit", (int)(ap - sp->cargv) - 1);
 
 		return (1);
 	}
@@ -154,8 +123,7 @@
  * PUBLIC: int ex_init __P((SCR *));
  */
 int
-ex_init(sp)
-	SCR *sp;
+ex_init(SCR *sp)
 {
 	GS *gp;
 
@@ -177,13 +145,27 @@
  * ex_emsg --
  *	Display a few common ex and vi error messages.
  *
+ * PUBLIC: void ex_wemsg __P((SCR *, CHAR_T *, exm_t));
+ */
+void
+ex_wemsg(SCR* sp, CHAR_T *p, exm_t which)
+{
+	char *np;
+	size_t nlen;
+
+	if (p) INT2CHAR(sp, p, STRLEN(p), np, nlen);
+	else np = NULL;
+	ex_emsg(sp, np, which);
+}
+
+/*
+ * ex_emsg --
+ *	Display a few common ex and vi error messages.
+ *
  * PUBLIC: void ex_emsg __P((SCR *, char *, exm_t));
  */
 void
-ex_emsg(sp, p, which)
-	SCR *sp;
-	char *p;
-	exm_t which;
+ex_emsg(SCR *sp, char *p, exm_t which)
 {
 	switch (which) {
 	case EXM_EMPTYBUF:

Modified: trunk/contrib/nvi/ex/ex_version.c
===================================================================
--- trunk/contrib/nvi/ex/ex_version.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/ex/ex_version.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -10,11 +10,12 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)ex_version.c	10.31 (Berkeley) 8/22/96";
+static const char sccsid[] = "$Id: ex_version.c,v 10.32 2001/06/25 15:19:22 skimo Exp $";
 #endif /* not lint */
 
 #include <sys/types.h>
 #include <sys/queue.h>
+#include <sys/time.h>
 
 #include <bitstring.h>
 #include <limits.h>
@@ -30,10 +31,9 @@
  * PUBLIC: int ex_version __P((SCR *, EXCMD *));
  */
 int
-ex_version(sp, cmdp)
-	SCR *sp;
-	EXCMD *cmdp;
+ex_version(SCR *sp, EXCMD *cmdp)
 {
-	msgq(sp, M_INFO, VI_VERSION);
+	msgq(sp, M_INFO, "Version "VI_VERSION
+			 " The CSRG, University of California, Berkeley.");
 	return (0);
 }

Modified: trunk/contrib/nvi/ex/ex_visual.c
===================================================================
--- trunk/contrib/nvi/ex/ex_visual.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/ex/ex_visual.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -10,7 +10,7 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)ex_visual.c	10.13 (Berkeley) 6/28/96";
+static const char sccsid[] = "$Id: ex_visual.c,v 10.16 2001/08/29 11:04:13 skimo Exp $";
 #endif /* not lint */
 
 #include <sys/types.h>
@@ -34,14 +34,14 @@
  * PUBLIC: int ex_visual __P((SCR *, EXCMD *));
  */
 int
-ex_visual(sp, cmdp)
-	SCR *sp;
-	EXCMD *cmdp;
+ex_visual(SCR *sp, EXCMD *cmdp)
 {
 	SCR *tsp;
 	size_t len;
 	int pos;
 	char buf[256];
+	size_t wlen;
+	CHAR_T *wp;
 
 	/* If open option off, disallow visual command. */
 	if (!O_ISSET(sp, O_OPEN)) {
@@ -83,9 +83,9 @@
 		len = snprintf(buf, sizeof(buf),
 		     "%luz%c%lu", (u_long)sp->lno, pos, cmdp->count);
 	else
-		len = snprintf(buf, sizeof(buf), "%luz%c",
-		    (u_long)sp->lno, pos);
-	(void)v_event_push(sp, NULL, buf, len, CH_NOMAP | CH_QUOTED);
+		len = snprintf(buf, sizeof(buf), "%luz%c", (u_long)sp->lno, pos);
+	CHAR2INT(sp, buf, len, wp, wlen);
+	(void)v_event_push(sp, NULL, wp, wlen, CH_NOMAP | CH_QUOTED);
 
 	/*
 	 * !!!
@@ -130,6 +130,7 @@
 		 */
 		++sp->refcnt;
 		++sp->ep->refcnt;
+		/* XXXX where is this decremented ? */
 
 		/*
 		 * Fake up a screen pointer -- vi doesn't get to change our

Modified: trunk/contrib/nvi/ex/ex_write.c
===================================================================
--- trunk/contrib/nvi/ex/ex_write.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/ex/ex_write.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -10,7 +10,7 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)ex_write.c	10.30 (Berkeley) 7/12/96";
+static const char sccsid[] = "$Id: ex_write.c,v 10.41 2011/12/02 01:07:06 zy Exp $";
 #endif /* not lint */
 
 #include <sys/types.h>
@@ -25,6 +25,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <strings.h>
 #include <unistd.h>
 
 #include "../common/common.h"
@@ -39,9 +40,7 @@
  * PUBLIC: int ex_wn __P((SCR *, EXCMD *));
  */
 int
-ex_wn(sp, cmdp)
-	SCR *sp;
-	EXCMD *cmdp;
+ex_wn(SCR *sp, EXCMD *cmdp)
 {
 	if (exwr(sp, cmdp, WN))
 		return (1);
@@ -61,9 +60,7 @@
  * PUBLIC: int ex_wq __P((SCR *, EXCMD *));
  */
 int
-ex_wq(sp, cmdp)
-	SCR *sp;
-	EXCMD *cmdp;
+ex_wq(SCR *sp, EXCMD *cmdp)
 {
 	int force;
 
@@ -89,9 +86,7 @@
  * PUBLIC: int ex_write __P((SCR *, EXCMD *));
  */
 int
-ex_write(sp, cmdp)
-	SCR *sp;
-	EXCMD *cmdp;
+ex_write(SCR *sp, EXCMD *cmdp)
 {
 	return (exwr(sp, cmdp, WRITE));
 }
@@ -104,9 +99,7 @@
  * PUBLIC: int ex_xit __P((SCR *, EXCMD *));
  */
 int
-ex_xit(sp, cmdp)
-	SCR *sp;
-	EXCMD *cmdp;
+ex_xit(SCR *sp, EXCMD *cmdp)
 {
 	int force;
 
@@ -131,14 +124,16 @@
  *	The guts of the ex write commands.
  */
 static int
-exwr(sp, cmdp, cmd)
-	SCR *sp;
-	EXCMD *cmdp;
-	enum which cmd;
+exwr(SCR *sp, EXCMD *cmdp, enum which cmd)
 {
 	MARK rm;
 	int flags;
-	char *name, *p;
+	char *name;
+	CHAR_T *p = NULL;
+	size_t nlen;
+	char *n;
+	int rc;
+	EX_PRIVATE *exp;
 
 	NEEDFILE(sp, cmdp);
 
@@ -149,25 +144,31 @@
 
 	/* Skip any leading whitespace. */
 	if (cmdp->argc != 0)
-		for (p = cmdp->argv[0]->bp; *p != '\0' && isblank(*p); ++p);
+		for (p = cmdp->argv[0]->bp; *p != '\0' && cmdskip(*p); ++p);
 
 	/* If "write !" it's a pipe to a utility. */
 	if (cmdp->argc != 0 && cmd == WRITE && *p == '!') {
 		/* Secure means no shell access. */
 		if (O_ISSET(sp, O_SECURE)) {
-			ex_emsg(sp, cmdp->cmd->name, EXM_SECURE_F);
+			ex_wemsg(sp, cmdp->cmd->name, EXM_SECURE_F);
 			return (1);
 		}
 
 		/* Expand the argument. */
-		for (++p; *p && isblank(*p); ++p);
+		for (++p; *p && cmdskip(*p); ++p);
 		if (*p == '\0') {
 			ex_emsg(sp, cmdp->cmd->usage, EXM_USAGE);
 			return (1);
 		}
-		if (argv_exp1(sp, cmdp, p, strlen(p), 1))
+		if (argv_exp1(sp, cmdp, p, STRLEN(p), 1))
 			return (1);
 
+		/* Set the last bang command */
+		exp = EXP(sp);
+		free(exp->lastbcomm);
+		exp->lastbcomm = v_wstrdup(sp, cmdp->argv[1]->bp,
+		    cmdp->argv[1]->len);
+
 		/*
 		 * Historically, vi waited after a write filter even if there
 		 * wasn't any output from the command.  People complained when
@@ -201,7 +202,7 @@
 		LF_SET(FS_APPEND);
 
 		/* Skip ">>" and whitespace. */
-		for (p += 2; *p && isblank(*p); ++p);
+		for (p += 2; *p && cmdskip(*p); ++p);
 	}
 
 	/* If no other arguments, just write the file back. */
@@ -210,7 +211,7 @@
 		    &cmdp->addr1, &cmdp->addr2, NULL, flags));
 
 	/* Build an argv so we get an argument count and file expansion. */
-	if (argv_exp2(sp, cmdp, p, strlen(p)))
+	if (argv_exp2(sp, cmdp, p, STRLEN(p)))
 		return (1);
 
 	/*
@@ -228,7 +229,9 @@
 		abort();
 		/* NOTREACHED */
 	case 2:
-		name = cmdp->argv[1]->bp;
+		INT2CHAR(sp, cmdp->argv[1]->bp, cmdp->argv[1]->len+1,
+			 n, nlen);
+		name = v_strdup(sp, n, nlen - 1);
 
 		/*
 		 * !!!
@@ -238,10 +241,9 @@
 		 */
 		if (F_ISSET(sp->frp, FR_TMPFILE) &&
 		    !F_ISSET(sp->frp, FR_EXNAMED)) {
-			if ((p = v_strdup(sp,
-			    cmdp->argv[1]->bp, cmdp->argv[1]->len)) != NULL) {
+			if ((n = v_strdup(sp, name, nlen - 1)) != NULL) {
 				free(sp->frp->name);
-				sp->frp->name = p;
+				sp->frp->name = n;
 			}
 			/*
 			 * The file has a real name, it's no longer a
@@ -261,11 +263,16 @@
 			set_alt_name(sp, name);
 		break;
 	default:
-		ex_emsg(sp, p, EXM_FILECOUNT);
+		INT2CHAR(sp, p, STRLEN(p) + 1, n, nlen);
+		ex_emsg(sp, n, EXM_FILECOUNT);
 		return (1);
 	}
 
-	return (file_write(sp, &cmdp->addr1, &cmdp->addr2, name, flags));
+	rc = file_write(sp, &cmdp->addr1, &cmdp->addr2, name, flags);
+
+	free(name);
+
+	return rc;
 }
 
 /*
@@ -276,13 +283,7 @@
  * PUBLIC:    char *, FILE *, MARK *, MARK *, u_long *, u_long *, int));
  */
 int
-ex_writefp(sp, name, fp, fm, tm, nlno, nch, silent)
-	SCR *sp;
-	char *name;
-	FILE *fp;
-	MARK *fm, *tm;
-	u_long *nlno, *nch;
-	int silent;
+ex_writefp(SCR *sp, char *name, FILE *fp, MARK *fm, MARK *tm, u_long *nlno, u_long *nch, int silent)
 {
 	struct stat sb;
 	GS *gp;
@@ -290,7 +291,11 @@
 	recno_t fline, tline, lcnt;
 	size_t len;
 	int rval;
-	char *msg, *p;
+	char *msg;
+	CHAR_T *p;
+	char *f;
+	size_t flen;
+	int isutf16;
 
 	gp = sp->gp;
 	fline = fm->lno;
@@ -319,7 +324,17 @@
 	ccnt = 0;
 	lcnt = 0;
 	msg = "253|Writing...";
-	if (tline != 0)
+
+	if (O_ISSET(sp, O_FILEENCODING)) {
+		isutf16 = !strncasecmp(O_STR(sp, O_FILEENCODING), "utf-16", 6);
+		isutf16 += !strncasecmp(O_STR(sp, O_FILEENCODING), "utf-16le", 8);
+	} else isutf16 = 0;
+
+	if (tline != 0) {
+		if (isutf16 == 1 && fwrite("\xfe\xff", 1, 2, fp) != 2)
+			goto err;
+		if (isutf16 == 2 && fwrite("\xff\xfe", 1, 2, fp) != 2)
+			goto err;
 		for (; fline <= tline; ++fline, ++lcnt) {
 			/* Caller has to provide any interrupt message. */
 			if ((lcnt + 1) % INTERRUPT_CHECK == 0) {
@@ -333,15 +348,29 @@
 			}
 			if (db_get(sp, fline, DBG_FATAL, &p, &len))
 				goto err;
-			if (fwrite(p, 1, len, fp) != len)
+			INT2FILE(sp, p, len, f, flen);
+			if (fwrite(f, 1, flen, fp) != flen)
 				goto err;
 			ccnt += len;
-			if (putc('\n', fp) != '\n')
+			/* UTF-16 w/o BOM is big-endian */
+			switch (isutf16) {
+			case 1:		/* UTF-16BE */
+				if (fwrite("\0\x0a", 1, 2, fp) != 2)
+					goto done;
 				break;
+			case 2:		/* UTF-16LE */
+				if (fwrite("\x0a\0", 1, 2, fp) != 2)
+					goto done;
+				break;
+			default:
+				if (putc('\n', fp) != '\n')
+					goto done;
+			}
 			++ccnt;
 		}
+	}
 
-	if (fflush(fp))
+done:	if (fflush(fp))
 		goto err;
 	/*
 	 * XXX

Modified: trunk/contrib/nvi/ex/ex_yank.c
===================================================================
--- trunk/contrib/nvi/ex/ex_yank.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/ex/ex_yank.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -10,11 +10,12 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)ex_yank.c	10.7 (Berkeley) 3/6/96";
+static const char sccsid[] = "$Id: ex_yank.c,v 10.8 2001/06/25 15:19:22 skimo Exp $";
 #endif /* not lint */
 
 #include <sys/types.h>
 #include <sys/queue.h>
+#include <sys/time.h>
 
 #include <bitstring.h>
 #include <limits.h>
@@ -29,9 +30,7 @@
  * PUBLIC: int ex_yank __P((SCR *, EXCMD *));
  */
 int
-ex_yank(sp, cmdp)
-	SCR *sp;
-	EXCMD *cmdp;
+ex_yank(SCR *sp, EXCMD *cmdp)
 {
 	NEEDFILE(sp, cmdp);
 

Modified: trunk/contrib/nvi/ex/ex_z.c
===================================================================
--- trunk/contrib/nvi/ex/ex_z.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/ex/ex_z.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -10,11 +10,12 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)ex_z.c	10.10 (Berkeley) 3/6/96";
+static const char sccsid[] = "$Id: ex_z.c,v 10.12 2001/06/25 15:19:22 skimo Exp $";
 #endif /* not lint */
 
 #include <sys/types.h>
 #include <sys/queue.h>
+#include <sys/time.h>
 
 #include <bitstring.h>
 #include <limits.h>
@@ -31,9 +32,7 @@
  * PUBLIC: int ex_z __P((SCR *, EXCMD *));
  */
 int
-ex_z(sp, cmdp)
-	SCR *sp;
-	EXCMD *cmdp;
+ex_z(SCR *sp, EXCMD *cmdp)
 {
 	MARK abs;
 	recno_t cnt, equals, lno;
@@ -55,7 +54,7 @@
 	if (FL_ISSET(cmdp->iflags, E_C_COUNT))
 		cnt = cmdp->count;
 	else
-#ifdef HISTORIC_PRACTICE
+#ifdef HISTORICAL_PRACTICE
 		cnt = O_VAL(sp, O_SCROLL) * 2;
 #else
 		cnt = O_VAL(sp, O_WINDOW) - 1;

Added: trunk/contrib/nvi/ex/extern.h
===================================================================
--- trunk/contrib/nvi/ex/extern.h	                        (rev 0)
+++ trunk/contrib/nvi/ex/extern.h	2018-06-10 20:23:48 UTC (rev 10823)
@@ -0,0 +1,130 @@
+int ex __P((SCR **));
+int ex_cmd __P((SCR *));
+int ex_range __P((SCR *, EXCMD *, int *));
+int ex_is_abbrev __P((CHAR_T *, size_t));
+int ex_is_unmap __P((CHAR_T *, size_t));
+void ex_badaddr
+   __P((SCR *, EXCMDLIST const *, enum badaddr, enum nresult));
+int ex_abbr __P((SCR *, EXCMD *));
+int ex_unabbr __P((SCR *, EXCMD *));
+int ex_append __P((SCR *, EXCMD *));
+int ex_change __P((SCR *, EXCMD *));
+int ex_insert __P((SCR *, EXCMD *));
+int ex_next __P((SCR *, EXCMD *));
+int ex_prev __P((SCR *, EXCMD *));
+int ex_rew __P((SCR *, EXCMD *));
+int ex_args __P((SCR *, EXCMD *));
+char **ex_buildargv __P((SCR *, EXCMD *, char *));
+int argv_init __P((SCR *, EXCMD *));
+int argv_exp0 __P((SCR *, EXCMD *, CHAR_T *, size_t));
+int argv_exp1 __P((SCR *, EXCMD *, CHAR_T *, size_t, int));
+int argv_exp2 __P((SCR *, EXCMD *, CHAR_T *, size_t));
+int argv_exp3 __P((SCR *, EXCMD *, CHAR_T *, size_t));
+int argv_flt_ex __P((SCR *, EXCMD *, CHAR_T *, size_t));
+int argv_free __P((SCR *));
+int argv_flt_path __P((SCR *, EXCMD *, CHAR_T *, size_t));
+CHAR_T *argv_esc __P((SCR *, EXCMD *, CHAR_T *, size_t));
+CHAR_T *argv_uesc __P((SCR *, EXCMD *, CHAR_T *, size_t));
+int ex_at __P((SCR *, EXCMD *));
+int ex_bang __P((SCR *, EXCMD *));
+int ex_cd __P((SCR *, EXCMD *));
+int ex_cscope __P((SCR *, EXCMD *));
+int cscope_end __P((SCR *));
+int cscope_display __P((SCR *));
+int cscope_search __P((SCR *, TAGQ *, TAG *));
+int ex_delete __P((SCR *, EXCMD *));
+int ex_display __P((SCR *, EXCMD *));
+int ex_edit __P((SCR *, EXCMD *));
+int ex_equal __P((SCR *, EXCMD *));
+int ex_file __P((SCR *, EXCMD *));
+int ex_filter __P((SCR *, 
+   EXCMD *, MARK *, MARK *, MARK *, CHAR_T *, enum filtertype));
+int ex_global __P((SCR *, EXCMD *));
+int ex_v __P((SCR *, EXCMD *));
+int ex_g_insdel __P((SCR *, lnop_t, recno_t));
+int ex_screen_copy __P((SCR *, SCR *));
+int ex_screen_end __P((SCR *));
+int ex_optchange __P((SCR *, int, char *, u_long *));
+int ex_exrc __P((SCR *));
+int ex_run_str __P((SCR *, char *, CHAR_T *, size_t, int, int));
+int ex_join __P((SCR *, EXCMD *));
+int ex_map __P((SCR *, EXCMD *));
+int ex_unmap __P((SCR *, EXCMD *));
+int ex_mark __P((SCR *, EXCMD *));
+int ex_mkexrc __P((SCR *, EXCMD *));
+int ex_copy __P((SCR *, EXCMD *));
+int ex_move __P((SCR *, EXCMD *));
+int ex_open __P((SCR *, EXCMD *));
+int ex_preserve __P((SCR *, EXCMD *));
+int ex_recover __P((SCR *, EXCMD *));
+int ex_list __P((SCR *, EXCMD *));
+int ex_number __P((SCR *, EXCMD *));
+int ex_pr __P((SCR *, EXCMD *));
+int ex_print __P((SCR *, EXCMD *, MARK *, MARK *, u_int32_t));
+int ex_ldisplay __P((SCR *, const CHAR_T *, size_t, size_t, u_int));
+int ex_scprint __P((SCR *, MARK *, MARK *));
+int ex_printf __P((SCR *, const char *, ...));
+int ex_puts __P((SCR *, const char *));
+int ex_fflush __P((SCR *sp));
+int ex_put __P((SCR *, EXCMD *));
+int ex_quit __P((SCR *, EXCMD *));
+int ex_read __P((SCR *, EXCMD *));
+int ex_readfp __P((SCR *, char *, FILE *, MARK *, recno_t *, int));
+int ex_bg __P((SCR *, EXCMD *));
+int ex_fg __P((SCR *, EXCMD *));
+int ex_resize __P((SCR *, EXCMD *));
+int ex_sdisplay __P((SCR *));
+int ex_script __P((SCR *, EXCMD *));
+int sscr_exec __P((SCR *, recno_t));
+int sscr_input __P((SCR *));
+int sscr_end __P((SCR *));
+int ex_set __P((SCR *, EXCMD *));
+int ex_shell __P((SCR *, EXCMD *));
+int ex_exec_proc __P((SCR *, EXCMD *, char *, const char *, int));
+int proc_wait __P((SCR *, long, const char *, int, int));
+int ex_shiftl __P((SCR *, EXCMD *));
+int ex_shiftr __P((SCR *, EXCMD *));
+int ex_source __P((SCR *, EXCMD *));
+int ex_stop __P((SCR *, EXCMD *));
+int ex_s __P((SCR *, EXCMD *));
+int ex_subagain __P((SCR *, EXCMD *));
+int ex_subtilde __P((SCR *, EXCMD *));
+int re_compile __P((SCR *,
+    CHAR_T *, size_t, CHAR_T **, size_t *, regex_t *, u_int));
+void re_error __P((SCR *, int, regex_t *));
+int ex_tag_first __P((SCR *, CHAR_T *));
+int ex_tag_push __P((SCR *, EXCMD *));
+int ex_tag_next __P((SCR *, EXCMD *));
+int ex_tag_prev __P((SCR *, EXCMD *));
+int ex_tag_nswitch __P((SCR *, TAG *, int));
+int ex_tag_Nswitch __P((SCR *, TAG *, int));
+int ex_tag_pop __P((SCR *, EXCMD *));
+int ex_tag_top __P((SCR *, EXCMD *));
+int ex_tag_display __P((SCR *));
+int ex_tag_copy __P((SCR *, SCR *));
+int tagq_free __P((SCR *, TAGQ *));
+int tagq_push __P((SCR*, TAGQ*, int, int ));
+void tag_msg __P((SCR *, tagmsg_t, char *));
+int ex_tagf_alloc __P((SCR *, char *));
+int ex_tag_free __P((SCR *));
+int ex_txt __P((SCR *, TEXTH *, ARG_CHAR_T, u_int32_t));
+int ex_undo __P((SCR *, EXCMD *));
+int ex_help __P((SCR *, EXCMD *));
+int ex_usage __P((SCR *, EXCMD *));
+int ex_viusage __P((SCR *, EXCMD *));
+void ex_cinit __P((SCR *, EXCMD *, int, int, recno_t, recno_t, int));
+int ex_getline __P((SCR *, FILE *, size_t *));
+int ex_ncheck __P((SCR *, int));
+int ex_init __P((SCR *));
+void ex_wemsg __P((SCR *, CHAR_T *, exm_t));
+void ex_emsg __P((SCR *, char *, exm_t));
+int ex_version __P((SCR *, EXCMD *));
+int ex_visual __P((SCR *, EXCMD *));
+int ex_wn __P((SCR *, EXCMD *));
+int ex_wq __P((SCR *, EXCMD *));
+int ex_write __P((SCR *, EXCMD *));
+int ex_xit __P((SCR *, EXCMD *));
+int ex_writefp __P((SCR *,
+   char *, FILE *, MARK *, MARK *, u_long *, u_long *, int));
+int ex_yank __P((SCR *, EXCMD *));
+int ex_z __P((SCR *, EXCMD *));


Property changes on: trunk/contrib/nvi/ex/extern.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Modified: trunk/contrib/nvi/ex/script.h
===================================================================
--- trunk/contrib/nvi/ex/script.h	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/ex/script.h	2018-06-10 20:23:48 UTC (rev 10823)
@@ -6,7 +6,7 @@
  *
  * See the LICENSE file for redistribution information.
  *
- *	@(#)script.h	10.2 (Berkeley) 3/6/96
+ *	$Id: script.h,v 10.3 2012/04/21 23:51:46 zy Exp $
  */
 
 struct _script {
@@ -16,8 +16,6 @@
 	char	*sh_prompt;		/* Prompt. */
 	size_t	 sh_prompt_len;		/* Prompt length. */
 	char	 sh_name[64];		/* Pty name */
-#ifdef TIOCGWINSZ
 	struct winsize sh_win;		/* Window size. */
-#endif
 	struct termios sh_term;		/* Terminal information. */
 };

Modified: trunk/contrib/nvi/ex/tag.h
===================================================================
--- trunk/contrib/nvi/ex/tag.h	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/ex/tag.h	2018-06-10 20:23:48 UTC (rev 10823)
@@ -8,7 +8,7 @@
  *
  * See the LICENSE file for redistribution information.
  *
- *	@(#)tag.h	10.5 (Berkeley) 5/15/96
+ *	$Id: tag.h,v 10.9 2012/07/06 16:38:36 zy Exp $
  */
 
 /*
@@ -16,12 +16,12 @@
  * connection, linked from the EX_PRIVATE structure.
  */
 struct _csc {
-	LIST_ENTRY(_csc) q;	/* Linked list of cscope connections. */
+	SLIST_ENTRY(_csc) q;	/* Linked list of cscope connections. */
 
-	char	*dname;		/* Base directory of this cscope connection. */
-	size_t	 dlen;		/* Length of base directory. */
-	pid_t	 pid;		/* PID of the connected cscope process. */
-	time_t	 mtime;		/* Last modification time of cscope database. */
+	char		*dname;	/* Base directory of this cscope connection. */
+	size_t		 dlen;	/* Length of base directory. */
+	pid_t		 pid;	/* PID of the connected cscope process. */
+	struct timespec	 mtim;	/* Last modification time of cscope database. */
 
 	FILE	*from_fp;	/* from cscope: FILE. */
 	int	 from_fd;	/* from cscope: file descriptor. */
@@ -74,7 +74,7 @@
  * tagtop:	discard all Q
  */
 struct _tag {			/* Tag list. */
-	CIRCLEQ_ENTRY(_tag) q;	/* Linked list of tags. */
+	TAILQ_ENTRY(_tag) q;	/* Linked list of tags. */
 
 				/* Tag pop/return information. */
 	FREF	*frp;		/* Saved file. */
@@ -84,16 +84,18 @@
 	char	*fname;		/* Filename. */
 	size_t	 fnlen;		/* Filename length. */
 	recno_t	 slno;		/* Search line number. */
-	char	*search;	/* Search string. */
+	CHAR_T	*search;	/* Search string. */
 	size_t	 slen;		/* Search string length. */
+	CHAR_T	*msg;		/* Message string. */
+	size_t	 mlen;		/* Message string length. */
 
-	char	 buf[1];	/* Variable length buffer. */
+	CHAR_T	 buf[1];	/* Variable length buffer. */
 };
 
 struct _tagq {			/* Tag queue. */
-	CIRCLEQ_ENTRY(_tagq) q;	/* Linked list of tag queues. */
+	TAILQ_ENTRY(_tagq) q;	/* Linked list of tag queues. */
 				/* This queue's tag list. */
-	CIRCLEQ_HEAD(_tagqh, _tag) tagq;
+	TAILQ_HEAD(_tagqh, _tag) tagq[1];
 
 	TAG	*current;	/* Current TAG within the queue. */
 

Modified: trunk/contrib/nvi/ex/version.h
===================================================================
--- trunk/contrib/nvi/ex/version.h	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/ex/version.h	2018-06-10 20:23:48 UTC (rev 10823)
@@ -1,2 +1 @@
-#define	VI_VERSION \
-	"Version 1.79 (10/23/96) The CSRG, University of California, Berkeley."
+#define VI_VERSION "2.1.2 (2012-11-02)"

Added: trunk/contrib/nvi/regex/COPYRIGHT
===================================================================
--- trunk/contrib/nvi/regex/COPYRIGHT	                        (rev 0)
+++ trunk/contrib/nvi/regex/COPYRIGHT	2018-06-10 20:23:48 UTC (rev 10823)
@@ -0,0 +1,56 @@
+Copyright 1992, 1993, 1994 Henry Spencer.  All rights reserved.
+This software is not subject to any license of the American Telephone
+and Telegraph Company or of the Regents of the University of California.
+
+Permission is granted to anyone to use this software for any purpose on
+any computer system, and to alter it and redistribute it, subject
+to the following restrictions:
+
+1. The author is not responsible for the consequences of use of this
+   software, no matter how awful, even if they arise from flaws in it.
+
+2. The origin of this software must not be misrepresented, either by
+   explicit claim or by omission.  Since few users ever read sources,
+   credits must appear in the documentation.
+
+3. Altered versions must be plainly marked as such, and must not be
+   misrepresented as being the original software.  Since few users
+   ever read sources, credits must appear in the documentation.
+
+4. This notice may not be removed or altered.
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+/*-
+ * Copyright (c) 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)COPYRIGHT	8.1 (Berkeley) 3/16/94
+ */

Added: trunk/contrib/nvi/regex/WHATSNEW
===================================================================
--- trunk/contrib/nvi/regex/WHATSNEW	                        (rev 0)
+++ trunk/contrib/nvi/regex/WHATSNEW	2018-06-10 20:23:48 UTC (rev 10823)
@@ -0,0 +1,94 @@
+# @(#)WHATSNEW	8.3 (Berkeley) 3/18/94
+
+New in alpha3.4:  The complex bug alluded to below has been fixed (in a
+slightly kludgey temporary way that may hurt efficiency a bit; this is
+another "get it out the door for 4.4" release).  The tests at the end of
+the tests file have accordingly been uncommented.  The primary sign of
+the bug was that something like a?b matching ab matched b rather than ab.
+(The bug was essentially specific to this exact situation, else it would
+have shown up earlier.)
+
+New in alpha3.3:  The definition of word boundaries has been altered
+slightly, to more closely match the usual programming notion that "_"
+is an alphabetic.  Stuff used for pre-ANSI systems is now in a subdir,
+and the makefile no longer alludes to it in mysterious ways.  The
+makefile has generally been cleaned up some.  Fixes have been made
+(again!) so that the regression test will run without -DREDEBUG, at
+the cost of weaker checking.  A workaround for a bug in some folks'
+<assert.h> has been added.  And some more things have been added to
+tests, including a couple right at the end which are commented out
+because the code currently flunks them (complex bug; fix coming).
+Plus the usual minor cleanup.
+
+New in alpha3.2:  Assorted bits of cleanup and portability improvement
+(the development base is now a BSDI system using GCC instead of an ancient
+Sun system, and the newer compiler exposed some glitches).  Fix for a
+serious bug that affected REs using many [] (including REG_ICASE REs
+because of the way they are implemented), *sometimes*, depending on
+memory-allocation patterns.  The header-file prototypes no longer name
+the parameters, avoiding possible name conflicts.  The possibility that
+some clot has defined CHAR_MIN as (say) `-128' instead of `(-128)' is
+now handled gracefully.  "uchar" is no longer used as an internal type
+name (too many people have the same idea).  Still the same old lousy
+performance, alas.
+
+New in alpha3.1:  Basically nothing, this release is just a bookkeeping
+convenience.  Stay tuned.
+
+New in alpha3.0:  Performance is no better, alas, but some fixes have been
+made and some functionality has been added.  (This is basically the "get
+it out the door in time for 4.4" release.)  One bug fix:  regfree() didn't
+free the main internal structure (how embarrassing).  It is now possible
+to put NULs in either the RE or the target string, using (resp.) a new
+REG_PEND flag and the old REG_STARTEND flag.  The REG_NOSPEC flag to
+regcomp() makes all characters ordinary, so you can match a literal
+string easily (this will become more useful when performance improves!).
+There are now primitives to match beginnings and ends of words, although
+the syntax is disgusting and so is the implementation.  The REG_ATOI
+debugging interface has changed a bit.  And there has been considerable
+internal cleanup of various kinds.
+
+New in alpha2.3:  Split change list out of README, and moved flags notes
+into Makefile.  Macro-ized the name of regex(7) in regex(3), since it has
+to change for 4.4BSD.  Cleanup work in engine.c, and some new regression
+tests to catch tricky cases thereof.
+
+New in alpha2.2:  Out-of-date manpages updated.  Regerror() acquires two
+small extensions -- REG_ITOA and REG_ATOI -- which avoid debugging kludges
+in my own test program and might be useful to others for similar purposes.
+The regression test will now compile (and run) without REDEBUG.  The
+BRE \$ bug is fixed.  Most uses of "uchar" are gone; it's all chars now.
+Char/uchar parameters are now written int/unsigned, to avoid possible
+portability problems with unpromoted parameters.  Some unsigned casts have
+been introduced to minimize portability problems with shifting into sign
+bits.
+
+New in alpha2.1:  Lots of little stuff, cleanup and fixes.  The one big
+thing is that regex.h is now generated, using mkh, rather than being
+supplied in the distribution; due to circularities in dependencies,
+you have to build regex.h explicitly by "make h".  The two known bugs
+have been fixed (and the regression test now checks for them), as has a
+problem with assertions not being suppressed in the absence of REDEBUG.
+No performance work yet.
+
+New in alpha2:  Backslash-anything is an ordinary character, not an
+error (except, of course, for the handful of backslashed metacharacters
+in BREs), which should reduce script breakage.  The regression test
+checks *where* null strings are supposed to match, and has generally
+been tightened up somewhat.  Small bug fixes in parameter passing (not
+harmful, but technically errors) and some other areas.  Debugging
+invoked by defining REDEBUG rather than not defining NDEBUG.
+
+New in alpha+3:  full prototyping for internal routines, using a little
+helper program, mkh, which extracts prototypes given in stylized comments.
+More minor cleanup.  Buglet fix:  it's CHAR_BIT, not CHAR_BITS.  Simple
+pre-screening of input when a literal string is known to be part of the
+RE; this does wonders for performance.
+
+New in alpha+2:  minor bits of cleanup.  Notably, the number "32" for the
+word width isn't hardwired into regexec.c any more, the public header
+file prototypes the functions if __STDC__ is defined, and some small typos
+in the manpages have been fixed.
+
+New in alpha+1:  improvements to the manual pages, and an important
+extension, the REG_STARTEND option to regexec().

Added: trunk/contrib/nvi/regex/cclass.h
===================================================================
--- trunk/contrib/nvi/regex/cclass.h	                        (rev 0)
+++ trunk/contrib/nvi/regex/cclass.h	2018-06-10 20:23:48 UTC (rev 10823)
@@ -0,0 +1,85 @@
+/*	$NetBSD: cclass.h,v 1.2 2008/12/05 22:51:42 christos Exp $ */
+
+/*-
+ * Copyright (c) 1992, 1993, 1994 Henry Spencer.
+ * Copyright (c) 1992, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Henry Spencer of the University of Toronto.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)cclass.h	8.2 (Berkeley) 3/16/94
+ */
+
+RCHAR_T ALNUM[] = {'a','l','n','u','m',0};
+RCHAR_T ALPHA[] = {'a','l','p','h','a',0};
+RCHAR_T BLANK[] = {'b','l','a','n','k',0};
+RCHAR_T CNTRL[] = {'c','n','t','r','l',0};
+RCHAR_T DIGIT[] = {'d','i','g','i','t',0};
+RCHAR_T GRAPH[] = {'g','r','a','p','h',0};
+RCHAR_T LOWER[] = {'l','o','w','e','r',0};
+RCHAR_T PRINT[] = {'p','r','i','n','t',0};
+RCHAR_T PUNCT[] = {'p','u','n','c','t',0};
+RCHAR_T SPACE[] = {'s','p','a','c','e',0};
+RCHAR_T UPPER[] = {'u','p','p','e','r',0};
+RCHAR_T XDIGIT[] = {'x','d','i','g','i','t',0};
+
+/* character-class table */
+static struct cclass {
+	RCHAR_T *name;
+	const char *chars;
+	const char *multis;
+} cclasses[] = {
+	{ ALNUM,	"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\
+0123456789",				"" },
+	{ ALPHA,	"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
+					"" },
+	{ BLANK,	" \t",		"" },
+	{ CNTRL,	"\007\b\t\n\v\f\r\1\2\3\4\5\6\16\17\20\21\22\23\24\
+\25\26\27\30\31\32\33\34\35\36\37\177",	"" },
+	{ DIGIT,	"0123456789",	"" },
+	{ GRAPH,	"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\
+0123456789!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~",
+					"" },
+	{ LOWER,	"abcdefghijklmnopqrstuvwxyz",
+					"" },
+	{ PRINT,	"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\
+0123456789!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~ ",
+					"" },
+	{ PUNCT,	"!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~",
+					"" },
+	{ SPACE,	"\t\n\v\f\r ",	"" },
+	{ UPPER,	"ABCDEFGHIJKLMNOPQRSTUVWXYZ",
+					"" },
+	{ XDIGIT,	"0123456789ABCDEFabcdef",
+					"" },
+	{ NULL,		0,		"" },
+};


Property changes on: trunk/contrib/nvi/regex/cclass.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/contrib/nvi/regex/cname.h
===================================================================
--- trunk/contrib/nvi/regex/cname.h	                        (rev 0)
+++ trunk/contrib/nvi/regex/cname.h	2018-06-10 20:23:48 UTC (rev 10823)
@@ -0,0 +1,143 @@
+/*	$NetBSD: cname.h,v 1.2 2008/12/05 22:51:42 christos Exp $ */
+
+/*-
+ * Copyright (c) 1992, 1993, 1994 Henry Spencer.
+ * Copyright (c) 1992, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Henry Spencer of the University of Toronto.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)cname.h	8.2 (Berkeley) 3/16/94
+ */
+
+/* character-name table */
+static struct cname {
+	const RCHAR_T *name;
+	char code;
+} cnames[] = {
+	{ L("NUL"),		'\0' },
+	{ L("SOH"),		'\001' },
+	{ L("STX"),		'\002' },
+	{ L("ETX"),		'\003' },
+	{ L("EOT"),		'\004' },
+	{ L("ENQ"),		'\005' },
+	{ L("ACK"),		'\006' },
+	{ L("BEL"),		'\007' },
+	{ L("alert"),		'\007' },
+	{ L("BS"),		'\010' },
+	{ L("backspace"),	'\b' },
+	{ L("HT"),		'\011' },
+	{ L("tab"),		'\t' },
+	{ L("LF"),		'\012' },
+	{ L("newline"),		'\n' },
+	{ L("VT"),		'\013' },
+	{ L("vertical-tab"),	'\v' },
+	{ L("FF"),		'\014' },
+	{ L("form-feed"),	'\f' },
+	{ L("CR"),		'\015' },
+	{ L("carriage-return"),	'\r' },
+	{ L("SO"),		'\016' },
+	{ L("SI"),		'\017' },
+	{ L("DLE"),		'\020' },
+	{ L("DC1"),		'\021' },
+	{ L("DC2"),		'\022' },
+	{ L("DC3"),		'\023' },
+	{ L("DC4"),		'\024' },
+	{ L("NAK"),		'\025' },
+	{ L("SYN"),		'\026' },
+	{ L("ETB"),		'\027' },
+	{ L("CAN"),		'\030' },
+	{ L("EM"),		'\031' },
+	{ L("SUB"),		'\032' },
+	{ L("ESC"),		'\033' },
+	{ L("IS4"),		'\034' },
+	{ L("FS"),		'\034' },
+	{ L("IS3"),		'\035' },
+	{ L("GS"),		'\035' },
+	{ L("IS2"),		'\036' },
+	{ L("RS"),		'\036' },
+	{ L("IS1"),		'\037' },
+	{ L("US"),		'\037' },
+	{ L("space"),		' ' },
+	{ L("exclamation-mark"),'!' },
+	{ L("quotation-mark"),	'"' },
+	{ L("number-sign"),	'#' },
+	{ L("dollar-sign"),	'$' },
+	{ L("percent-sign"),	'%' },
+	{ L("ampersand"),	'&' },
+	{ L("apostrophe"),	'\'' },
+	{ L("left-parenthesis"),'(' },
+	{ L("right-parenthesis"),')' },
+	{ L("asterisk"),	'*' },
+	{ L("plus-sign"),	'+' },
+	{ L("comma"),		',' },
+	{ L("hyphen"),		'-' },
+	{ L("hyphen-minus"),	'-' },
+	{ L("period"),		'.' },
+	{ L("full-stop"),	'.' },
+	{ L("slash"),		'/' },
+	{ L("solidus"),		'/' },
+	{ L("zero"),		'0' },
+	{ L("one"),		'1' },
+	{ L("two"),		'2' },
+	{ L("three"),		'3' },
+	{ L("four"),		'4' },
+	{ L("five"),		'5' },
+	{ L("six"),		'6' },
+	{ L("seven"),		'7' },
+	{ L("eight"),		'8' },
+	{ L("nine"),		'9' },
+	{ L("colon"),		':' },
+	{ L("semicolon"),	';' },
+	{ L("less-than-sign"),	'<' },
+	{ L("equals-sign"),	'=' },
+	{ L("greater-than-sign"),'>' },
+	{ L("question-mark"),	'?' },
+	{ L("commercial-at"),	'@' },
+	{ L("left-square-bracket"),'[' },
+	{ L("backslash"),	'\\' },
+	{ L("reverse-solidus"),	'\\' },
+	{ L("right-square-bracket"),']' },
+	{ L("circumflex"),	'^' },
+	{ L("circumflex-accent"),'^' },
+	{ L("underscore"),	'_' },
+	{ L("low-line"),	'_' },
+	{ L("grave-accent"),	'`' },
+	{ L("left-brace"),	'{' },
+	{ L("left-curly-bracket"),'{' },
+	{ L("vertical-line"),	'|' },
+	{ L("right-brace"),	'}' },
+	{ L("right-curly-bracket"),'}' },
+	{ L("tilde"),		'~' },
+	{ L("DEL"),		'\177' },
+	{ NULL,			0 },
+};


Property changes on: trunk/contrib/nvi/regex/cname.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/contrib/nvi/regex/engine.c
===================================================================
--- trunk/contrib/nvi/regex/engine.c	                        (rev 0)
+++ trunk/contrib/nvi/regex/engine.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -0,0 +1,1102 @@
+/*	$NetBSD: engine.c,v 1.7 2011/11/19 17:45:11 tnozaki Exp $ */
+
+/*-
+ * Copyright (c) 1992, 1993, 1994 Henry Spencer.
+ * Copyright (c) 1992, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Henry Spencer of the University of Toronto.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)engine.c	8.4 (Berkeley) 3/19/94
+ */
+
+/*
+ * The matching engine and friends.  This file is #included by regexec.c
+ * after suitable #defines of a variety of macros used herein, so that
+ * different state representations can be used without duplicating masses
+ * of code.
+ */
+
+#ifdef SNAMES
+#define	matcher	smatcher
+#define	fast	sfast
+#define	slow	sslow
+#define	dissect	sdissect
+#define	backref	sbackref
+#define	step	sstep
+#define	print	sprint
+#define	at	sat
+#define	match	smat
+#endif
+#ifdef LNAMES
+#define	matcher	lmatcher
+#define	fast	lfast
+#define	slow	lslow
+#define	dissect	ldissect
+#define	backref	lbackref
+#define	step	lstep
+#define	print	lprint
+#define	at	lat
+#define	match	lmat
+#endif
+
+/* another structure passed up and down to avoid zillions of parameters */
+struct match {
+	struct re_guts *g;
+	int eflags;
+	regmatch_t *pmatch;	/* [nsub+1] (0 element unused) */
+	const RCHAR_T *offp;		/* offsets work from here */
+	const RCHAR_T *beginp;		/* start of string -- virtual NUL precedes */
+	const RCHAR_T *endp;		/* end of string -- virtual NUL here */
+	const RCHAR_T *coldp;		/* can be no match starting before here */
+	const RCHAR_T **lastpos;	/* [nplus+1] */
+	STATEVARS;
+	states st;		/* current states */
+	states fresh;		/* states for a fresh start */
+	states tmp;		/* temporary */
+	states empty;		/* empty set of states */
+};
+
+/* ========= begin header generated by ./mkh ========= */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* === engine.c === */
+static int matcher __P((struct re_guts *g, const RCHAR_T *string, size_t nmatch, regmatch_t pmatch[], int eflags));
+static const RCHAR_T *dissect __P((struct match *m, const RCHAR_T *start, const RCHAR_T *stop, sopno startst, sopno stopst));
+static const RCHAR_T *backref __P((struct match *m, const RCHAR_T *start, const RCHAR_T *stop, sopno startst, sopno stopst, sopno lev));
+static const RCHAR_T *fast __P((struct match *m, const RCHAR_T *start, const RCHAR_T *stop, sopno startst, sopno stopst));
+static const RCHAR_T *slow __P((struct match *m, const RCHAR_T *start, const RCHAR_T *stop, sopno startst, sopno stopst));
+static states step __P((struct re_guts *g, sopno start, sopno stop, states bef, int flag, RCHAR_T ch, states aft));
+#define	BOL	(1)
+#define	EOL	(BOL+1)
+#define	BOLEOL	(BOL+2)
+#define	NOTHING	(BOL+3)
+#define	BOW	(BOL+4)
+#define	EOW	(BOL+5)
+#ifdef REDEBUG
+static void print __P((struct match *m, char *caption, states st, int ch, FILE *d));
+#endif
+#ifdef REDEBUG
+static void at __P((struct match *m, char *title, char *start, char *stop, sopno startst, sopno stopst));
+#endif
+#ifdef REDEBUG
+static char *pchar __P((int ch));
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+/* ========= end header generated by ./mkh ========= */
+
+#ifdef REDEBUG
+#define	SP(t, s, c)	print(m, t, s, c, stdout)
+#define	AT(t, p1, p2, s1, s2)	at(m, t, p1, p2, s1, s2)
+#define	NOTE(str)	{ if (m->eflags&REG_TRACE) printf("=%s\n", (str)); }
+#else
+#define	SP(t, s, c)	/* nothing */
+#define	AT(t, p1, p2, s1, s2)	/* nothing */
+#define	NOTE(s)	/* nothing */
+#endif
+
+/*
+ - matcher - the actual matching engine
+ == static int matcher(register struct re_guts *g, const RCHAR_T *string, \
+ ==	size_t nmatch, regmatch_t pmatch[], int eflags);
+ */
+static int			/* 0 success, REG_NOMATCH failure */
+matcher(g, string, nmatch, pmatch, eflags)
+register struct re_guts *g;
+const RCHAR_T *string;
+size_t nmatch;
+regmatch_t pmatch[];
+int eflags;
+{
+	register const RCHAR_T *endp;
+	register size_t i;
+	struct match mv;
+	register struct match *m = &mv;
+	register const RCHAR_T *dp;
+	register const sopno gf = g->firststate+1;	/* +1 for OEND */
+	register const sopno gl = g->laststate;
+	const RCHAR_T *start;
+	const RCHAR_T *stop;
+
+	/* simplify the situation where possible */
+	if (g->cflags&REG_NOSUB)
+		nmatch = 0;
+	if (eflags&REG_STARTEND) {
+		start = string + pmatch[0].rm_so;
+		stop = string + pmatch[0].rm_eo;
+	} else {
+		start = string;
+		stop = start + STRLEN(start);
+	}
+	if (stop < start)
+		return(REG_INVARG);
+
+	/* prescreening; this does wonders for this rather slow code */
+	if (g->must != NULL) {
+		for (dp = start; dp < stop; dp++)
+			if (*dp == g->must[0] && (size_t)(stop - dp) >= g->mlen &&
+				MEMCMP(dp, g->must, g->mlen) == 0)
+				break;
+		if (dp == stop)		/* we didn't find g->must */
+			return(REG_NOMATCH);
+	}
+
+	/* match struct setup */
+	m->g = g;
+	m->eflags = eflags;
+	m->pmatch = NULL;
+	m->lastpos = NULL;
+	m->offp = string;
+	m->beginp = start;
+	m->endp = stop;
+	STATESETUP(m, 4);
+	SETUP(m->st);
+	SETUP(m->fresh);
+	SETUP(m->tmp);
+	SETUP(m->empty);
+	CLEAR(m->empty);
+
+	/* this loop does only one repetition except for backrefs */
+	for (;;) {
+		endp = fast(m, start, stop, gf, gl);
+		if (endp == NULL) {		/* a miss */
+			STATETEARDOWN(m);
+			return(REG_NOMATCH);
+		}
+		if (nmatch == 0 && !g->backrefs)
+			break;		/* no further info needed */
+
+		/* where? */
+		assert(m->coldp != NULL);
+		for (;;) {
+			NOTE("finding start");
+			endp = slow(m, m->coldp, stop, gf, gl);
+			if (endp != NULL)
+				break;
+			assert(m->coldp < m->endp);
+			m->coldp++;
+		}
+		if (nmatch == 1 && !g->backrefs)
+			break;		/* no further info needed */
+
+		/* oh my, he wants the subexpressions... */
+		if (m->pmatch == NULL)
+			m->pmatch = (regmatch_t *)malloc((m->g->nsub + 1) *
+							sizeof(regmatch_t));
+		if (m->pmatch == NULL) {
+			STATETEARDOWN(m);
+			return(REG_ESPACE);
+		}
+		for (i = 1; i <= m->g->nsub; i++)
+			m->pmatch[i].rm_so = m->pmatch[i].rm_eo = -1;
+		if (!g->backrefs && !(m->eflags&REG_BACKR)) {
+			NOTE("dissecting");
+			dp = dissect(m, m->coldp, endp, gf, gl);
+		} else {
+			if (g->nplus > 0 && m->lastpos == NULL)
+				m->lastpos = (const RCHAR_T **)malloc((g->nplus+1) *
+							sizeof(const RCHAR_T *));
+			if (g->nplus > 0 && m->lastpos == NULL) {
+				free(m->pmatch);
+				STATETEARDOWN(m);
+				return(REG_ESPACE);
+			}
+			NOTE("backref dissect");
+			dp = backref(m, m->coldp, endp, gf, gl, (sopno)0);
+		}
+		if (dp != NULL)
+			break;
+
+		/* uh-oh... we couldn't find a subexpression-level match */
+		assert(g->backrefs);	/* must be back references doing it */
+		assert(g->nplus == 0 || m->lastpos != NULL);
+		for (;;) {
+			if (dp != NULL || endp <= m->coldp)
+				break;		/* defeat */
+			NOTE("backoff");
+			endp = slow(m, m->coldp, endp-1, gf, gl);
+			if (endp == NULL)
+				break;		/* defeat */
+			/* try it on a shorter possibility */
+#ifndef NDEBUG
+			for (i = 1; i <= m->g->nsub; i++) {
+				assert(m->pmatch[i].rm_so == -1);
+				assert(m->pmatch[i].rm_eo == -1);
+			}
+#endif
+			NOTE("backoff dissect");
+			dp = backref(m, m->coldp, endp, gf, gl, (sopno)0);
+		}
+		assert(dp == NULL || dp == endp);
+		if (dp != NULL)		/* found a shorter one */
+			break;
+
+		/* despite initial appearances, there is no match here */
+		NOTE("false alarm");
+		start = m->coldp + 1;	/* recycle starting later */
+		assert(start <= stop);
+	}
+
+	/* fill in the details if requested */
+	if (nmatch > 0) {
+		pmatch[0].rm_so = m->coldp - m->offp;
+		pmatch[0].rm_eo = endp - m->offp;
+	}
+	if (nmatch > 1) {
+		assert(m->pmatch != NULL);
+		for (i = 1; i < nmatch; i++)
+			if (i <= m->g->nsub)
+				pmatch[i] = m->pmatch[i];
+			else {
+				pmatch[i].rm_so = -1;
+				pmatch[i].rm_eo = -1;
+			}
+	}
+
+	if (m->pmatch != NULL)
+		free((char *)m->pmatch);
+	if (m->lastpos != NULL)
+		free((char *)m->lastpos);
+	STATETEARDOWN(m);
+	return(0);
+}
+
+/*
+ - dissect - figure out what matched what, no back references
+ == static const RCHAR_T *dissect(register struct match *m, const RCHAR_T *start, \
+ ==	const RCHAR_T *stop, sopno startst, sopno stopst);
+ */
+static const RCHAR_T *			/* == stop (success) always */
+dissect(m, start, stop, startst, stopst)
+register struct match *m;
+const RCHAR_T *start;
+const RCHAR_T *stop;
+sopno startst;
+sopno stopst;
+{
+	register int i;
+	register sopno ss;	/* start sop of current subRE */
+	register sopno es;	/* end sop of current subRE */
+	register const RCHAR_T *sp;	/* start of string matched by it */
+	register const RCHAR_T *stp;	/* string matched by it cannot pass here */
+	register const RCHAR_T *rest;	/* start of rest of string */
+	register const RCHAR_T *tail;	/* string unmatched by rest of RE */
+	register sopno ssub;	/* start sop of subsubRE */
+	register sopno esub;	/* end sop of subsubRE */
+	register const RCHAR_T *ssp;	/* start of string matched by subsubRE */
+	register const RCHAR_T *sep;	/* end of string matched by subsubRE */
+	register const RCHAR_T *oldssp;	/* previous ssp */
+	register const RCHAR_T *dp;
+
+	AT("diss", start, stop, startst, stopst);
+	sp = start;
+	for (ss = startst; ss < stopst; ss = es) {
+		/* identify end of subRE */
+		es = ss;
+		switch (m->g->strip[es]) {
+		case OPLUS_:
+		case OQUEST_:
+			es += m->g->stripdata[es];
+			break;
+		case OCH_:
+			while (m->g->strip[es] != O_CH)
+				es += m->g->stripdata[es];
+			break;
+		}
+		es++;
+
+		/* figure out what it matched */
+		switch (m->g->strip[ss]) {
+		case OEND:
+			assert(nope);
+			break;
+		case OCHAR:
+			sp++;
+			break;
+		case OBOL:
+		case OEOL:
+		case OBOW:
+		case OEOW:
+			break;
+		case OANY:
+		case OANYOF:
+			sp++;
+			break;
+		case OBACK_:
+		case O_BACK:
+			assert(nope);
+			break;
+		/* cases where length of match is hard to find */
+		case OQUEST_:
+			stp = stop;
+			for (;;) {
+				/* how long could this one be? */
+				rest = slow(m, sp, stp, ss, es);
+				assert(rest != NULL);	/* it did match */
+				/* could the rest match the rest? */
+				tail = slow(m, rest, stop, es, stopst);
+				if (tail == stop)
+					break;		/* yes! */
+				/* no -- try a shorter match for this one */
+				stp = rest - 1;
+				assert(stp >= sp);	/* it did work */
+			}
+			ssub = ss + 1;
+			esub = es - 1;
+			/* did innards match? */
+			if (slow(m, sp, rest, ssub, esub) != NULL) {
+				dp = dissect(m, sp, rest, ssub, esub);
+				assert(dp == rest);
+			} else		/* no */
+				assert(sp == rest);
+			sp = rest;
+			break;
+		case OPLUS_:
+			stp = stop;
+			for (;;) {
+				/* how long could this one be? */
+				rest = slow(m, sp, stp, ss, es);
+				assert(rest != NULL);	/* it did match */
+				/* could the rest match the rest? */
+				tail = slow(m, rest, stop, es, stopst);
+				if (tail == stop)
+					break;		/* yes! */
+				/* no -- try a shorter match for this one */
+				stp = rest - 1;
+				assert(stp >= sp);	/* it did work */
+			}
+			ssub = ss + 1;
+			esub = es - 1;
+			ssp = sp;
+			oldssp = ssp;
+			for (;;) {	/* find last match of innards */
+				sep = slow(m, ssp, rest, ssub, esub);
+				if (sep == NULL || sep == ssp)
+					break;	/* failed or matched null */
+				oldssp = ssp;	/* on to next try */
+				ssp = sep;
+			}
+			if (sep == NULL) {
+				/* last successful match */
+				sep = ssp;
+				ssp = oldssp;
+			}
+			assert(sep == rest);	/* must exhaust substring */
+			assert(slow(m, ssp, sep, ssub, esub) == rest);
+			dp = dissect(m, ssp, sep, ssub, esub);
+			assert(dp == sep);
+			sp = rest;
+			break;
+		case OCH_:
+			stp = stop;
+			for (;;) {
+				/* how long could this one be? */
+				rest = slow(m, sp, stp, ss, es);
+				assert(rest != NULL);	/* it did match */
+				/* could the rest match the rest? */
+				tail = slow(m, rest, stop, es, stopst);
+				if (tail == stop)
+					break;		/* yes! */
+				/* no -- try a shorter match for this one */
+				stp = rest - 1;
+				assert(stp >= sp);	/* it did work */
+			}
+			ssub = ss + 1;
+			esub = ss + m->g->stripdata[ss] - 1;
+			assert(m->g->strip[esub] == OOR1);
+			for (;;) {	/* find first matching branch */
+				if (slow(m, sp, rest, ssub, esub) == rest)
+					break;	/* it matched all of it */
+				/* that one missed, try next one */
+				assert(m->g->strip[esub] == OOR1);
+				esub++;
+				assert(m->g->strip[esub] == OOR2);
+				ssub = esub + 1;
+				esub += m->g->stripdata[esub];
+				if (m->g->strip[esub] == OOR2)
+					esub--;
+				else
+					assert(m->g->strip[esub] == O_CH);
+			}
+			dp = dissect(m, sp, rest, ssub, esub);
+			assert(dp == rest);
+			sp = rest;
+			break;
+		case O_PLUS:
+		case O_QUEST:
+		case OOR1:
+		case OOR2:
+		case O_CH:
+			assert(nope);
+			break;
+		case OLPAREN:
+			i = m->g->stripdata[ss];
+			assert(0 < i && i <= m->g->nsub);
+			m->pmatch[i].rm_so = sp - m->offp;
+			break;
+		case ORPAREN:
+			i = m->g->stripdata[ss];
+			assert(0 < i && i <= m->g->nsub);
+			m->pmatch[i].rm_eo = sp - m->offp;
+			break;
+		default:		/* uh oh */
+			assert(nope);
+			break;
+		}
+	}
+
+	assert(sp == stop);
+	return(sp);
+}
+
+/*
+ - backref - figure out what matched what, figuring in back references
+ == static const RCHAR_T *backref(register struct match *m, const RCHAR_T *start, \
+ ==	const RCHAR_T *stop, sopno startst, sopno stopst, sopno lev);
+ */
+static const RCHAR_T *			/* == stop (success) or NULL (failure) */
+backref(m, start, stop, startst, stopst, lev)
+register struct match *m;
+const RCHAR_T *start;
+const RCHAR_T *stop;
+sopno startst;
+sopno stopst;
+sopno lev;			/* PLUS nesting level */
+{
+	register int i;
+	register sopno ss;	/* start sop of current subRE */
+	register const RCHAR_T *sp;	/* start of string matched by it */
+	register sopno ssub;	/* start sop of subsubRE */
+	register sopno esub;	/* end sop of subsubRE */
+	register const RCHAR_T *ssp;	/* start of string matched by subsubRE */
+	register const RCHAR_T *dp;
+	register size_t len;
+	register int hard;
+	register sop s;
+	register RCHAR_T d;
+	register regoff_t offsave;
+	register cset *cs;
+
+	AT("back", start, stop, startst, stopst);
+	sp = start;
+
+	/* get as far as we can with easy stuff */
+	hard = 0;
+	for (ss = startst; !hard && ss < stopst; ss++) {
+		s = m->g->strip[ss];
+		d = m->g->stripdata[ss];
+		switch (s) {
+		case OCHAR:
+			if (sp == stop || *sp++ != d)
+				return(NULL);
+			break;
+		case OANY:
+			if (sp == stop)
+				return(NULL);
+			sp++;
+			break;
+		case OANYOF:
+			cs = &m->g->sets[d];
+			if (sp == stop || !CHIN(cs, *sp++))
+				return(NULL);
+			break;
+		case OBOL:
+			if ( (sp == m->beginp && !(m->eflags&REG_NOTBOL)) ||
+					(sp < m->endp && *(sp-1) == '\n' &&
+						(m->g->cflags&REG_NEWLINE)) )
+				{ /* yes */ }
+			else
+				return(NULL);
+			break;
+		case OEOL:
+			if ( (sp == m->endp && !(m->eflags&REG_NOTEOL)) ||
+					(sp < m->endp && *sp == '\n' &&
+						(m->g->cflags&REG_NEWLINE)) )
+				{ /* yes */ }
+			else
+				return(NULL);
+			break;
+		case OBOW:
+			if (( (sp == m->beginp && !(m->eflags&REG_NOTBOL)) ||
+					(sp < m->endp && *(sp-1) == '\n' &&
+						(m->g->cflags&REG_NEWLINE)) ||
+					(sp > m->beginp &&
+							!ISWORD(*(sp-1))) ) &&
+					(sp < m->endp && ISWORD(*sp)) )
+				{ /* yes */ }
+			else
+				return(NULL);
+			break;
+		case OEOW:
+			if (( (sp == m->endp && !(m->eflags&REG_NOTEOL)) ||
+					(sp < m->endp && *sp == '\n' &&
+						(m->g->cflags&REG_NEWLINE)) ||
+					(sp < m->endp && !ISWORD(*sp)) ) &&
+					(sp > m->beginp && ISWORD(*(sp-1))) )
+				{ /* yes */ }
+			else
+				return(NULL);
+			break;
+		case O_QUEST:
+			break;
+		case OOR1:	/* matches null but needs to skip */
+			ss++;
+			s = m->g->strip[ss];
+			d = m->g->stripdata[ss];
+			do {
+				assert(s == OOR2);
+				ss += d;
+				s = m->g->strip[ss];
+				d = m->g->stripdata[ss];
+			} while (s != O_CH);
+			/* note that the ss++ gets us past the O_CH */
+			break;
+		default:	/* have to make a choice */
+			hard = 1;
+			break;
+		}
+	}
+	if (!hard) {		/* that was it! */
+		if (sp != stop)
+			return(NULL);
+		return(sp);
+	}
+	ss--;			/* adjust for the for's final increment */
+
+	/* the hard stuff */
+	AT("hard", sp, stop, ss, stopst);
+	s = m->g->strip[ss];
+	d = m->g->stripdata[ss];
+	switch (s) {
+	case OBACK_:		/* the vilest depths */
+		i = d;
+		assert(0 < i && i <= m->g->nsub);
+		if (m->pmatch[i].rm_eo == -1)
+			return(NULL);
+		assert(m->pmatch[i].rm_so != -1);
+		len = m->pmatch[i].rm_eo - m->pmatch[i].rm_so;
+		assert(stop - m->beginp >= len);
+		if (sp > stop - len)
+			return(NULL);	/* not enough left to match */
+		ssp = m->offp + m->pmatch[i].rm_so;
+		if (memcmp(sp, ssp, len) != 0)
+			return(NULL);
+		while (m->g->strip[ss] != O_BACK || m->g->stripdata[ss] != i)
+			ss++;
+		return(backref(m, sp+len, stop, ss+1, stopst, lev));
+		break;
+	case OQUEST_:		/* to null or not */
+		dp = backref(m, sp, stop, ss+1, stopst, lev);
+		if (dp != NULL)
+			return(dp);	/* not */
+		return(backref(m, sp, stop, ss+d+1, stopst, lev));
+		break;
+	case OPLUS_:
+		assert(m->lastpos != NULL);
+		assert(lev+1 <= m->g->nplus);
+		m->lastpos[lev+1] = sp;
+		return(backref(m, sp, stop, ss+1, stopst, lev+1));
+		break;
+	case O_PLUS:
+		if (sp == m->lastpos[lev])	/* last pass matched null */
+			return(backref(m, sp, stop, ss+1, stopst, lev-1));
+		/* try another pass */
+		m->lastpos[lev] = sp;
+		dp = backref(m, sp, stop, ss-d+1, stopst, lev);
+		if (dp == NULL)
+			return(backref(m, sp, stop, ss+1, stopst, lev-1));
+		else
+			return(dp);
+		break;
+	case OCH_:		/* find the right one, if any */
+		ssub = ss + 1;
+		esub = ss + d - 1;
+		assert(m->g->strip[esub] == OOR1);
+		for (;;) {	/* find first matching branch */
+			dp = backref(m, sp, stop, ssub, esub, lev);
+			if (dp != NULL)
+				return(dp);
+			/* that one missed, try next one */
+			if (m->g->strip[esub] == O_CH)
+				return(NULL);	/* there is none */
+			esub++;
+			assert(m->g->strip[esub] == OOR2);
+			ssub = esub + 1;
+			esub += m->g->stripdata[esub];
+			if (m->g->strip[esub] == OOR2)
+				esub--;
+			else
+				assert(m->g->strip[esub] == O_CH);
+		}
+		break;
+	case OLPAREN:		/* must undo assignment if rest fails */
+		i = d;
+		assert(0 < i && i <= m->g->nsub);
+		offsave = m->pmatch[i].rm_so;
+		m->pmatch[i].rm_so = sp - m->offp;
+		dp = backref(m, sp, stop, ss+1, stopst, lev);
+		if (dp != NULL)
+			return(dp);
+		m->pmatch[i].rm_so = offsave;
+		return(NULL);
+		break;
+	case ORPAREN:		/* must undo assignment if rest fails */
+		i = d;
+		assert(0 < i && i <= m->g->nsub);
+		offsave = m->pmatch[i].rm_eo;
+		m->pmatch[i].rm_eo = sp - m->offp;
+		dp = backref(m, sp, stop, ss+1, stopst, lev);
+		if (dp != NULL)
+			return(dp);
+		m->pmatch[i].rm_eo = offsave;
+		return(NULL);
+		break;
+	default:		/* uh oh */
+		assert(nope);
+		break;
+	}
+
+	/* "can't happen" */
+	assert(nope);
+	/* NOTREACHED */
+	return NULL;
+}
+
+/*
+ - fast - step through the string at top speed
+ == static const RCHAR_T *fast(register struct match *m, const RCHAR_T *start, \
+ ==	const RCHAR_T *stop, sopno startst, sopno stopst);
+ */
+static const RCHAR_T *			/* where tentative match ended, or NULL */
+fast(m, start, stop, startst, stopst)
+register struct match *m;
+const RCHAR_T *start;
+const RCHAR_T *stop;
+sopno startst;
+sopno stopst;
+{
+	register states st = m->st;
+	register states fresh = m->fresh;
+	register states tmp = m->tmp;
+	register const RCHAR_T *p = start;
+	register RCHAR_T c = (start == m->beginp) ? OUT : *(start-1);
+	register RCHAR_T lastc;	/* previous c */
+	register int flag;
+	register int i;
+	register const RCHAR_T *coldp;	/* last p after which no match was underway */
+
+	CLEAR(st);
+	SET1(st, startst);
+	st = step(m->g, startst, stopst, st, NOTHING, OUT, st);
+	ASSIGN(fresh, st);
+	SP("start", st, *p);
+	coldp = NULL;
+	for (;;) {
+		/* next character */
+		lastc = c;
+		c = (p == m->endp) ? OUT : *p;
+		if (EQ(st, fresh))
+			coldp = p;
+
+		/* is there an EOL and/or BOL between lastc and c? */
+		flag = 0;
+		i = 0;
+		if ( (lastc == '\n' && m->g->cflags&REG_NEWLINE) ||
+				(lastc == OUT && !(m->eflags&REG_NOTBOL)) ) {
+			flag = BOL;
+			i = m->g->nbol;
+		}
+		if ( (c == '\n' && m->g->cflags&REG_NEWLINE) ||
+				(c == OUT && !(m->eflags&REG_NOTEOL)) ) {
+			flag = (flag == BOL) ? BOLEOL : EOL;
+			i += m->g->neol;
+		}
+		if (i != 0) {
+			for (; i > 0; i--)
+				st = step(m->g, startst, stopst, st, flag, OUT, st);
+			SP("boleol", st, c);
+		}
+
+		/* how about a word boundary? */
+		if ( (flag == BOL || (lastc != OUT && !ISWORD(lastc))) &&
+					(c != OUT && ISWORD(c)) ) {
+			flag = BOW;
+		}
+		if ( (lastc != OUT && ISWORD(lastc)) &&
+				(flag == EOL || (c != OUT && !ISWORD(c))) ) {
+			flag = EOW;
+		}
+		if (flag == BOW || flag == EOW) {
+			st = step(m->g, startst, stopst, st, flag, OUT, st);
+			SP("boweow", st, c);
+		}
+
+		/* are we done? */
+		if (ISSET(st, stopst) || p == stop)
+			break;		/* NOTE BREAK OUT */
+
+		/* no, we must deal with this character */
+		ASSIGN(tmp, st);
+		ASSIGN(st, fresh);
+		assert(c != OUT);
+		st = step(m->g, startst, stopst, tmp, 0, c, st);
+		SP("aft", st, c);
+		assert(EQ(step(m->g, startst, stopst, st, NOTHING, OUT, st), st));
+		p++;
+	}
+
+	assert(coldp != NULL);
+	m->coldp = coldp;
+	if (ISSET(st, stopst))
+		return(p+1);
+	else
+		return(NULL);
+}
+
+/*
+ - slow - step through the string more deliberately
+ == static const RCHAR_T *slow(register struct match *m, const RCHAR_T *start, \
+ ==	const RCHAR_T *stop, sopno startst, sopno stopst);
+ */
+static const RCHAR_T *			/* where it ended */
+slow(m, start, stop, startst, stopst)
+register struct match *m;
+const RCHAR_T *start;
+const RCHAR_T *stop;
+sopno startst;
+sopno stopst;
+{
+	register states st = m->st;
+	register states empty = m->empty;
+	register states tmp = m->tmp;
+	register const RCHAR_T *p = start;
+	register RCHAR_T c = (start == m->beginp) ? OUT : *(start-1);
+	register RCHAR_T lastc;	/* previous c */
+	register int flag;
+	register int i;
+	register const RCHAR_T *matchp;	/* last p at which a match ended */
+
+	AT("slow", start, stop, startst, stopst);
+	CLEAR(st);
+	SET1(st, startst);
+	SP("sstart", st, *p);
+	st = step(m->g, startst, stopst, st, NOTHING, OUT, st);
+	matchp = NULL;
+	for (;;) {
+		/* next character */
+		lastc = c;
+		c = (p == m->endp) ? OUT : *p;
+
+		/* is there an EOL and/or BOL between lastc and c? */
+		flag = 0;
+		i = 0;
+		if ( (lastc == '\n' && m->g->cflags&REG_NEWLINE) ||
+				(lastc == OUT && !(m->eflags&REG_NOTBOL)) ) {
+			flag = BOL;
+			i = m->g->nbol;
+		}
+		if ( (c == '\n' && m->g->cflags&REG_NEWLINE) ||
+				(c == OUT && !(m->eflags&REG_NOTEOL)) ) {
+			flag = (flag == BOL) ? BOLEOL : EOL;
+			i += m->g->neol;
+		}
+		if (i != 0) {
+			for (; i > 0; i--)
+				st = step(m->g, startst, stopst, st, flag, OUT, st);
+			SP("sboleol", st, c);
+		}
+
+		/* how about a word boundary? */
+		if ( (flag == BOL || (lastc != OUT && !ISWORD(lastc))) &&
+					(c != OUT && ISWORD(c)) ) {
+			flag = BOW;
+		}
+		if ( (lastc != OUT && ISWORD(lastc)) &&
+				(flag == EOL || (c != OUT && !ISWORD(c))) ) {
+			flag = EOW;
+		}
+		if (flag == BOW || flag == EOW) {
+			st = step(m->g, startst, stopst, st, flag, OUT, st);
+			SP("sboweow", st, c);
+		}
+
+		/* are we done? */
+		if (ISSET(st, stopst))
+			matchp = p;
+		if (EQ(st, empty) || p == stop)
+			break;		/* NOTE BREAK OUT */
+
+		/* no, we must deal with this character */
+		ASSIGN(tmp, st);
+		ASSIGN(st, empty);
+		assert(c != OUT);
+		st = step(m->g, startst, stopst, tmp, 0, c, st);
+		SP("saft", st, c);
+		assert(EQ(step(m->g, startst, stopst, st, NOTHING, OUT, st), st));
+		p++;
+	}
+
+	return(matchp);
+}
+
+
+/*
+ - step - map set of states reachable before char to set reachable after
+ == static states step(register struct re_guts *g, sopno start, sopno stop, \
+ ==	register states bef, int flag, RCHAR_T ch, register states aft);
+ == #define	BOL	(1)
+ == #define	EOL	(BOL+1)
+ == #define	BOLEOL	(BOL+2)
+ == #define	NOTHING	(BOL+3)
+ == #define	BOW	(BOL+4)
+ == #define	EOW	(BOL+5)
+ */
+static states
+step(g, start, stop, bef, flag, ch, aft)
+register struct re_guts *g;
+sopno start;			/* start state within strip */
+sopno stop;			/* state after stop state within strip */
+register states bef;		/* states reachable before */
+int flag;			/* NONCHAR flag */
+RCHAR_T ch;			/* character code */
+register states aft;		/* states already known reachable after */
+{
+	register cset *cs;
+	register sop s;
+	register RCHAR_T d;
+	register sopno pc;
+	register onestate here;		/* note, macros know this name */
+	register sopno look;
+	register int i;
+
+	for (pc = start, INIT(here, pc); pc != stop; pc++, INC(here)) {
+		s = g->strip[pc];
+		d = g->stripdata[pc];
+		switch (s) {
+		case OEND:
+			assert(pc == stop-1);
+			break;
+		case OCHAR:
+			/* only characters can match */
+			assert(!flag || ch != d);
+			if (ch == d)
+				FWD(aft, bef, 1);
+			break;
+		case OBOL:
+			if (flag == BOL || flag == BOLEOL)
+				FWD(aft, bef, 1);
+			break;
+		case OEOL:
+			if (flag == EOL || flag == BOLEOL)
+				FWD(aft, bef, 1);
+			break;
+		case OBOW:
+			if (flag == BOW)
+				FWD(aft, bef, 1);
+			break;
+		case OEOW:
+			if (flag == EOW)
+				FWD(aft, bef, 1);
+			break;
+		case OANY:
+			if (!flag)
+				FWD(aft, bef, 1);
+			break;
+		case OANYOF:
+			cs = &g->sets[d];
+			if (!flag && CHIN(cs, ch))
+				FWD(aft, bef, 1);
+			break;
+		case OBACK_:		/* ignored here */
+		case O_BACK:
+			FWD(aft, aft, 1);
+			break;
+		case OPLUS_:		/* forward, this is just an empty */
+			FWD(aft, aft, 1);
+			break;
+		case O_PLUS:		/* both forward and back */
+			FWD(aft, aft, 1);
+			i = ISSETBACK(aft, d);
+			BACK(aft, aft, d);
+			if (!i && ISSETBACK(aft, d)) {
+				/* oho, must reconsider loop body */
+				pc -= d + 1;
+				INIT(here, pc);
+			}
+			break;
+		case OQUEST_:		/* two branches, both forward */
+			FWD(aft, aft, 1);
+			FWD(aft, aft, d);
+			break;
+		case O_QUEST:		/* just an empty */
+			FWD(aft, aft, 1);
+			break;
+		case OLPAREN:		/* not significant here */
+		case ORPAREN:
+			FWD(aft, aft, 1);
+			break;
+		case OCH_:		/* mark the first two branches */
+			FWD(aft, aft, 1);
+			assert(OP(g->strip[pc+d]) == OOR2);
+			FWD(aft, aft, d);
+			break;
+		case OOR1:		/* done a branch, find the O_CH */
+			if (ISSTATEIN(aft, here)) {
+				for (look = 1; /**/; look += d) {
+					s = g->strip[pc+look];
+					d = g->stripdata[pc+look];
+					if (s == O_CH)
+						break;
+					assert(s == OOR2);
+				}
+				FWD(aft, aft, look);
+			}
+			break;
+		case OOR2:		/* propagate OCH_'s marking */
+			FWD(aft, aft, 1);
+			if (g->strip[pc+d] != O_CH) {
+				assert(g->strip[pc+d] == OOR2);
+				FWD(aft, aft, d);
+			}
+			break;
+		case O_CH:		/* just empty */
+			FWD(aft, aft, 1);
+			break;
+		default:		/* ooooops... */
+			assert(nope);
+			break;
+		}
+	}
+
+	return(aft);
+}
+
+#ifdef REDEBUG
+/*
+ - print - print a set of states
+ == #ifdef REDEBUG
+ == static void print(struct match *m, char *caption, states st, \
+ ==	int ch, FILE *d);
+ == #endif
+ */
+static void
+print(m, caption, st, ch, d)
+struct match *m;
+char *caption;
+states st;
+int ch;
+FILE *d;
+{
+	register struct re_guts *g = m->g;
+	register int i;
+	register int first = 1;
+
+	if (!(m->eflags&REG_TRACE))
+		return;
+
+	fprintf(d, "%s", caption);
+	if (ch != '\0')
+		fprintf(d, " %s", pchar(ch));
+	for (i = 0; i < g->nstates; i++)
+		if (ISSET(st, i)) {
+			fprintf(d, "%s%d", (first) ? "\t" : ", ", i);
+			first = 0;
+		}
+	fprintf(d, "\n");
+}
+
+/* 
+ - at - print current situation
+ == #ifdef REDEBUG
+ == static void at(struct match *m, char *title, char *start, char *stop, \
+ ==						sopno startst, sopno stopst);
+ == #endif
+ */
+static void
+at(m, title, start, stop, startst, stopst)
+struct match *m;
+char *title;
+char *start;
+char *stop;
+sopno startst;
+sopno stopst;
+{
+	if (!(m->eflags&REG_TRACE))
+		return;
+
+	printf("%s %s-", title, pchar(*start));
+	printf("%s ", pchar(*stop));
+	printf("%ld-%ld\n", (long)startst, (long)stopst);
+}
+
+#ifndef PCHARDONE
+#define	PCHARDONE	/* never again */
+/*
+ - pchar - make a character printable
+ == #ifdef REDEBUG
+ == static char *pchar(int ch);
+ == #endif
+ *
+ * Is this identical to regchar() over in debug.c?  Well, yes.  But a
+ * duplicate here avoids having a debugging-capable regexec.o tied to
+ * a matching debug.o, and this is convenient.  It all disappears in
+ * the non-debug compilation anyway, so it doesn't matter much.
+ */
+static char *			/* -> representation */
+pchar(ch)
+int ch;
+{
+	static char pbuf[10];
+
+	if (isprint(ch) || ch == ' ')
+		snprintf(pbuf, sizeof(pbuf), "%c", ch);
+	else
+		snprintf(pbuf, sizeof(pbuf), "\\%o", ch);
+	return(pbuf);
+}
+#endif
+#endif
+
+#undef	matcher
+#undef	fast
+#undef	slow
+#undef	dissect
+#undef	backref
+#undef	step
+#undef	print
+#undef	at
+#undef	match


Property changes on: trunk/contrib/nvi/regex/engine.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/contrib/nvi/regex/re_format.7
===================================================================
--- trunk/contrib/nvi/regex/re_format.7	                        (rev 0)
+++ trunk/contrib/nvi/regex/re_format.7	2018-06-10 20:23:48 UTC (rev 10823)
@@ -0,0 +1,271 @@
+.\"	$NetBSD: re_format.7,v 1.1.1.2 2008/05/18 14:31:37 aymeric Exp $
+.\"
+.\" Copyright (c) 1992, 1993, 1994 Henry Spencer.
+.\" Copyright (c) 1992, 1993, 1994
+.\"	The Regents of the University of California.  All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Henry Spencer of the University of Toronto.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\"    must display the following acknowledgement:
+.\"	This product includes software developed by the University of
+.\"	California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"	@(#)re_format.7	8.2 (Berkeley) 3/16/94
+.\"
+.TH RE_FORMAT 7 "March 16, 1994"
+.SH NAME
+re_format \- POSIX 1003.2 regular expressions
+.SH DESCRIPTION
+Regular expressions (``RE''s),
+as defined in POSIX 1003.2, come in two forms:
+modern REs (roughly those of
+.IR egrep ;
+1003.2 calls these ``extended'' REs)
+and obsolete REs (roughly those of
+.IR ed ;
+1003.2 ``basic'' REs).
+Obsolete REs mostly exist for backward compatibility in some old programs;
+they will be discussed at the end.
+1003.2 leaves some aspects of RE syntax and semantics open;
+`\(dg' marks decisions on these aspects that
+may not be fully portable to other 1003.2 implementations.
+.PP
+A (modern) RE is one\(dg or more non-empty\(dg \fIbranches\fR,
+separated by `|'.
+It matches anything that matches one of the branches.
+.PP
+A branch is one\(dg or more \fIpieces\fR, concatenated.
+It matches a match for the first, followed by a match for the second, etc.
+.PP
+A piece is an \fIatom\fR possibly followed
+by a single\(dg `*', `+', `?', or \fIbound\fR.
+An atom followed by `*' matches a sequence of 0 or more matches of the atom.
+An atom followed by `+' matches a sequence of 1 or more matches of the atom.
+An atom followed by `?' matches a sequence of 0 or 1 matches of the atom.
+.PP
+A \fIbound\fR is `{' followed by an unsigned decimal integer,
+possibly followed by `,'
+possibly followed by another unsigned decimal integer,
+always followed by `}'.
+The integers must lie between 0 and RE_DUP_MAX (255\(dg) inclusive,
+and if there are two of them, the first may not exceed the second.
+An atom followed by a bound containing one integer \fIi\fR
+and no comma matches
+a sequence of exactly \fIi\fR matches of the atom.
+An atom followed by a bound
+containing one integer \fIi\fR and a comma matches
+a sequence of \fIi\fR or more matches of the atom.
+An atom followed by a bound
+containing two integers \fIi\fR and \fIj\fR matches
+a sequence of \fIi\fR through \fIj\fR (inclusive) matches of the atom.
+.PP
+An atom is a regular expression enclosed in `()' (matching a match for the
+regular expression),
+an empty set of `()' (matching the null string)\(dg,
+a \fIbracket expression\fR (see below), `.'
+(matching any single character), `^' (matching the null string at the
+beginning of a line), `$' (matching the null string at the
+end of a line), a `\e' followed by one of the characters
+`^.[$()|*+?{\e'
+(matching that character taken as an ordinary character),
+a `\e' followed by any other character\(dg
+(matching that character taken as an ordinary character,
+as if the `\e' had not been present\(dg),
+or a single character with no other significance (matching that character).
+A `{' followed by a character other than a digit is an ordinary
+character, not the beginning of a bound\(dg.
+It is illegal to end an RE with `\e'.
+.PP
+A \fIbracket expression\fR is a list of characters enclosed in `[]'.
+It normally matches any single character from the list (but see below).
+If the list begins with `^',
+it matches any single character
+(but see below) \fInot\fR from the rest of the list.
+If two characters in the list are separated by `\-', this is shorthand
+for the full \fIrange\fR of characters between those two (inclusive) in the
+collating sequence,
+e.g. `[0-9]' in ASCII matches any decimal digit.
+It is illegal\(dg for two ranges to share an
+endpoint, e.g. `a-c-e'.
+Ranges are very collating-sequence-dependent,
+and portable programs should avoid relying on them.
+.PP
+To include a literal `]' in the list, make it the first character
+(following a possible `^').
+To include a literal `\-', make it the first or last character,
+or the second endpoint of a range.
+To use a literal `\-' as the first endpoint of a range,
+enclose it in `[.' and `.]' to make it a collating element (see below).
+With the exception of these and some combinations using `[' (see next
+paragraphs), all other special characters, including `\e', lose their
+special significance within a bracket expression.
+.PP
+Within a bracket expression, a collating element (a character,
+a multi-character sequence that collates as if it were a single character,
+or a collating-sequence name for either)
+enclosed in `[.' and `.]' stands for the
+sequence of characters of that collating element.
+The sequence is a single element of the bracket expression's list.
+A bracket expression containing a multi-character collating element 
+can thus match more than one character,
+e.g. if the collating sequence includes a `ch' collating element,
+then the RE `[[.ch.]]*c' matches the first five characters
+of `chchcc'.
+.PP
+Within a bracket expression, a collating element enclosed in `[=' and
+`=]' is an equivalence class, standing for the sequences of characters
+of all collating elements equivalent to that one, including itself.
+(If there are no other equivalent collating elements,
+the treatment is as if the enclosing delimiters were `[.' and `.]'.)
+For example, if o and \o'o^' are the members of an equivalence class,
+then `[[=o=]]', `[[=\o'o^'=]]', and `[o\o'o^']' are all synonymous.
+An equivalence class may not\(dg be an endpoint
+of a range.
+.PP
+Within a bracket expression, the name of a \fIcharacter class\fR enclosed
+in `[:' and `:]' stands for the list of all characters belonging to that
+class.
+Standard character class names are:
+.PP
+.RS
+.nf
+.ta 3c 6c 9c
+alnum	digit	punct
+alpha	graph	space
+blank	lower	upper
+cntrl	print	xdigit
+.fi
+.RE
+.PP
+These stand for the character classes defined in
+.IR ctype (3).
+A locale may provide others.
+A character class may not be used as an endpoint of a range.
+.PP
+There are two special cases\(dg of bracket expressions:
+the bracket expressions `[[:<:]]' and `[[:>:]]' match the null string at
+the beginning and end of a word respectively.
+A word is defined as a sequence of
+word characters
+which is neither preceded nor followed by
+word characters.
+A word character is an
+.I alnum
+character (as defined by
+.IR ctype (3))
+or an underscore.
+This is an extension,
+compatible with but not specified by POSIX 1003.2,
+and should be used with
+caution in software intended to be portable to other systems.
+.PP
+In the event that an RE could match more than one substring of a given
+string,
+the RE matches the one starting earliest in the string.
+If the RE could match more than one substring starting at that point,
+it matches the longest.
+Subexpressions also match the longest possible substrings, subject to
+the constraint that the whole match be as long as possible,
+with subexpressions starting earlier in the RE taking priority over
+ones starting later.
+Note that higher-level subexpressions thus take priority over
+their lower-level component subexpressions.
+.PP
+Match lengths are measured in characters, not collating elements.
+A null string is considered longer than no match at all.
+For example,
+`bb*' matches the three middle characters of `abbbc',
+`(wee|week)(knights|nights)' matches all ten characters of `weeknights',
+when `(.*).*' is matched against `abc' the parenthesized subexpression
+matches all three characters, and
+when `(a*)*' is matched against `bc' both the whole RE and the parenthesized
+subexpression match the null string.
+.PP
+If case-independent matching is specified,
+the effect is much as if all case distinctions had vanished from the
+alphabet.
+When an alphabetic that exists in multiple cases appears as an
+ordinary character outside a bracket expression, it is effectively
+transformed into a bracket expression containing both cases,
+e.g. `x' becomes `[xX]'.
+When it appears inside a bracket expression, all case counterparts
+of it are added to the bracket expression, so that (e.g.) `[x]'
+becomes `[xX]' and `[^x]' becomes `[^xX]'.
+.PP
+No particular limit is imposed on the length of REs\(dg.
+Programs intended to be portable should not employ REs longer
+than 256 bytes,
+as an implementation can refuse to accept such REs and remain
+POSIX-compliant.
+.PP
+Obsolete (``basic'') regular expressions differ in several respects.
+`|', `+', and `?' are ordinary characters and there is no equivalent
+for their functionality.
+The delimiters for bounds are `\e{' and `\e}',
+with `{' and `}' by themselves ordinary characters.
+The parentheses for nested subexpressions are `\e(' and `\e)',
+with `(' and `)' by themselves ordinary characters.
+`^' is an ordinary character except at the beginning of the
+RE or\(dg the beginning of a parenthesized subexpression,
+`$' is an ordinary character except at the end of the
+RE or\(dg the end of a parenthesized subexpression,
+and `*' is an ordinary character if it appears at the beginning of the
+RE or the beginning of a parenthesized subexpression
+(after a possible leading `^').
+Finally, there is one new type of atom, a \fIback reference\fR:
+`\e' followed by a non-zero decimal digit \fId\fR
+matches the same sequence of characters
+matched by the \fId\fRth parenthesized subexpression
+(numbering subexpressions by the positions of their opening parentheses,
+left to right),
+so that (e.g.) `\e([bc]\e)\e1' matches `bb' or `cc' but not `bc'.
+.SH SEE ALSO
+regex(3)
+.PP
+POSIX 1003.2, section 2.8 (Regular Expression Notation).
+.SH BUGS
+Having two kinds of REs is a botch.
+.PP
+The current 1003.2 spec says that `)' is an ordinary character in
+the absence of an unmatched `(';
+this was an unintentional result of a wording error,
+and change is likely.
+Avoid relying on it.
+.PP
+Back references are a dreadful botch,
+posing major problems for efficient implementations.
+They are also somewhat vaguely defined
+(does
+`a\e(\e(b\e)*\e2\e)*d' match `abbbd'?).
+Avoid using them.
+.PP
+1003.2's specification of case-independent matching is vague.
+The ``one case implies all cases'' definition given above
+is current consensus among implementors as to the right interpretation.
+.PP
+The syntax for word boundaries is incredibly ugly.


Property changes on: trunk/contrib/nvi/regex/re_format.7
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/contrib/nvi/regex/regcomp.c
===================================================================
--- trunk/contrib/nvi/regex/regcomp.c	                        (rev 0)
+++ trunk/contrib/nvi/regex/regcomp.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -0,0 +1,1737 @@
+/*	$NetBSD: regcomp.c,v 1.7 2011/11/19 17:45:11 tnozaki Exp $ */
+
+/*-
+ * Copyright (c) 1992, 1993, 1994 Henry Spencer.
+ * Copyright (c) 1992, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Henry Spencer of the University of Toronto.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)regcomp.c	8.4 (Berkeley) 3/19/94
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)regcomp.c	8.4 (Berkeley) 3/19/94";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <regex.h>
+
+#include "utils.h"
+#include "regex2.h"
+
+#include "cclass.h"
+#include "cname.h"
+
+/*
+ * parse structure, passed up and down to avoid global variables and
+ * other clumsinesses
+ */
+struct parse {
+	RCHAR_T *next;		/* next character in RE */
+	RCHAR_T *end;		/* end of string (-> NUL normally) */
+	int error;		/* has an error been seen? */
+	sop *strip;		/* malloced strip */
+	RCHAR_T *stripdata;	/* malloced stripdata */
+	sopno ssize;		/* malloced strip size (allocated) */
+	sopno slen;		/* malloced strip length (used) */
+	int ncsalloc;		/* number of csets allocated */
+	struct re_guts *g;
+#	define	NPAREN	10	/* we need to remember () 1-9 for back refs */
+	sopno pbegin[NPAREN];	/* -> ( ([0] unused) */
+	sopno pend[NPAREN];	/* -> ) ([0] unused) */
+};
+
+/* ========= begin header generated by ./mkh ========= */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* === regcomp.c === */
+static void p_ere __P((struct parse *p, int stop, size_t reclimit));
+static void p_ere_exp __P((struct parse *p, size_t reclimit));
+static void p_str __P((struct parse *p));
+static void p_bre __P((struct parse *p, int end1, int end2, size_t reclimit));
+static int p_simp_re __P((struct parse *p, int starordinary, size_t reclimit));
+static int p_count __P((struct parse *p));
+static void p_bracket __P((struct parse *p));
+static void p_b_term __P((struct parse *p, cset *cs));
+static void p_b_cclass __P((struct parse *p, cset *cs));
+static void p_b_eclass __P((struct parse *p, cset *cs));
+static char p_b_symbol __P((struct parse *p));
+static char p_b_coll_elem __P((struct parse *p, int endc));
+static char othercase __P((int ch));
+static void bothcases __P((struct parse *p, int ch));
+static void ordinary __P((struct parse *p, int ch));
+static void nonnewline __P((struct parse *p));
+static void repeat __P((struct parse *p, sopno start, int from, int to, size_t reclimit));
+static int seterr __P((struct parse *p, int e));
+static cset *allocset __P((struct parse *p));
+static void freeset __P((struct parse *p, cset *cs));
+static int freezeset __P((struct parse *p, cset *cs));
+static int firstch __P((struct parse *p, cset *cs));
+static int nch __P((struct parse *p, cset *cs));
+static void mcadd __P((struct parse *p, cset *cs, const char *cp));
+#ifdef notdef
+static void mcsub __P((cset *cs, char *cp));
+static int mcin __P((cset *cs, char *cp));
+static char *mcfind __P((cset *cs, char *cp));
+#endif
+static void mcinvert __P((struct parse *p, cset *cs));
+static void mccase __P((struct parse *p, cset *cs));
+#ifdef notdef
+static int isinsets __P((struct re_guts *g, int c));
+static int samesets __P((struct re_guts *g, int c1, int c2));
+#endif
+static void categorize __P((struct parse *p, struct re_guts *g));
+static sopno dupl __P((struct parse *p, sopno start, sopno finish));
+static void doemit __P((struct parse *p, sop op, size_t opnd));
+static void doinsert __P((struct parse *p, sop op, size_t opnd, sopno pos));
+static void dofwd __P((struct parse *p, sopno pos, sop value));
+static int enlarge __P((struct parse *p, sopno size));
+static void stripsnug __P((struct parse *p, struct re_guts *g));
+static void findmust __P((struct parse *p, struct re_guts *g));
+static sopno pluscount __P((struct parse *p, struct re_guts *g));
+
+#ifdef __cplusplus
+}
+#endif
+/* ========= end header generated by ./mkh ========= */
+
+static RCHAR_T nuls[10];		/* place to point scanner in event of error */
+
+/*
+ * macros for use with parse structure
+ * BEWARE:  these know that the parse structure is named `p' !!!
+ */
+#define	PEEK()	(*p->next)
+#define	PEEK2()	(*(p->next+1))
+#define	MORE()	(p->next < p->end)
+#define	MORE2()	(p->next+1 < p->end)
+#define	SEE(c)	(MORE() && PEEK() == (c))
+#define	SEETWO(a, b)	(MORE() && MORE2() && PEEK() == (a) && PEEK2() == (b))
+#define	EAT(c)	((SEE(c)) ? (NEXT(), 1) : 0)
+#define	EATTWO(a, b)	((SEETWO(a, b)) ? (NEXT2(), 1) : 0)
+#define	NEXT()	(p->next++)
+#define	NEXT2()	(p->next += 2)
+#define	NEXTn(n)	(p->next += (n))
+#define	GETNEXT()	(*p->next++)
+#define	SETERROR(e)	seterr(p, (e))
+#define	REQUIRE(co, e)	((co) || SETERROR(e))
+#define	MUSTSEE(c, e)	(REQUIRE(MORE() && PEEK() == (c), e))
+#define	MUSTEAT(c, e)	(REQUIRE(MORE() && GETNEXT() == (c), e))
+#define	MUSTNOTSEE(c, e)	(REQUIRE(!MORE() || PEEK() != (c), e))
+#define	EMIT(op, sopnd)	doemit(p, (sop)(op), (size_t)(sopnd))
+#define	INSERT(op, pos)	doinsert(p, (sop)(op), HERE()-(pos)+1, pos)
+#define	AHEAD(pos)		dofwd(p, pos, HERE()-(pos))
+#define	ASTERN(sop, pos)	EMIT(sop, HERE()-pos)
+#define	HERE()		(p->slen)
+#define	THERE()		(p->slen - 1)
+#define	THERETHERE()	(p->slen - 2)
+#define	DROP(n)	(p->slen -= (n))
+
+#ifndef NDEBUG
+static int never = 0;		/* for use in asserts; shuts lint up */
+#else
+#define	never	0		/* some <assert.h>s have bugs too */
+#endif
+
+#define	MEMLIMIT	0x8000000
+#define MEMSIZE(p) \
+	((p)->ncsalloc / CHAR_BIT * (p)->g->csetsize + \
+	(p)->ncsalloc * sizeof(cset) + \
+	(p)->ssize * sizeof(sop))
+#define	RECLIMIT	256
+
+/*
+ - regcomp - interface for parser and compilation
+ = extern int regcomp(regex_t *, const RCHAR_T *, int);
+ = #define	REG_BASIC	0000
+ = #define	REG_EXTENDED	0001
+ = #define	REG_ICASE	0002
+ = #define	REG_NOSUB	0004
+ = #define	REG_NEWLINE	0010
+ = #define	REG_NOSPEC	0020
+ = #define	REG_PEND	0040
+ = #define	REG_DUMP	0200
+ */
+int				/* 0 success, otherwise REG_something */
+regcomp(regex_t *preg, const RCHAR_T *pattern, int cflags)
+{
+	struct parse pa;
+	register struct re_guts *g;
+	register struct parse *p = &pa;
+	register int i;
+	register size_t len;
+#ifdef REDEBUG
+#	define	GOODFLAGS(f)	(f)
+#else
+#	define	GOODFLAGS(f)	((f)&~REG_DUMP)
+#endif
+
+	cflags = GOODFLAGS(cflags);
+	if ((cflags&REG_EXTENDED) && (cflags&REG_NOSPEC))
+		return(REG_INVARG);
+
+	if (cflags&REG_PEND) {
+		if (preg->re_endp < pattern)
+			return(REG_INVARG);
+		len = preg->re_endp - pattern;
+	} else
+		len = STRLEN(pattern);
+
+	/* do the mallocs early so failure handling is easy */
+	g = (struct re_guts *)malloc(sizeof(struct re_guts) +
+							(NC-1)*sizeof(cat_t));
+	if (g == NULL)
+		return(REG_ESPACE);
+	p->ssize = len/(size_t)2*(size_t)3 + (size_t)1;	/* ugh */
+	p->strip = (sop *)malloc(p->ssize * sizeof(sop));
+	if (p->strip == NULL) {
+		free((char *)g);
+		return(REG_ESPACE);
+	}
+	p->stripdata = (RCHAR_T *)malloc(p->ssize * sizeof(RCHAR_T));
+	if (p->stripdata == NULL) {
+		free((char *)p->strip);
+		free((char *)g);
+		return(REG_ESPACE);
+	}
+	p->slen = 0;
+
+	/* set things up */
+	p->g = g;
+	p->next = (RCHAR_T *)pattern;	/* convenience; we do not modify it */
+	p->end = p->next + len;
+	p->error = 0;
+	p->ncsalloc = 0;
+	for (i = 0; i < NPAREN; i++) {
+		p->pbegin[i] = 0;
+		p->pend[i] = 0;
+	}
+	g->csetsize = NC;
+	g->sets = NULL;
+	g->setbits = NULL;
+	g->ncsets = 0;
+	g->cflags = cflags;
+	g->iflags = 0;
+	g->nbol = 0;
+	g->neol = 0;
+	g->must = NULL;
+	g->mlen = 0;
+	g->nsub = 0;
+#if 0
+	g->ncategories = 1;	/* category 0 is "everything else" */
+	g->categories = &g->catspace[-(CHAR_MIN)];
+	(void) memset((char *)g->catspace, 0, NC*sizeof(cat_t));
+#endif
+	g->backrefs = 0;
+
+	/* do it */
+	EMIT(OEND, 0);
+	g->firststate = THERE();
+	if (cflags&REG_EXTENDED)
+		p_ere(p, OUT, 0);
+	else if (cflags&REG_NOSPEC)
+		p_str(p);
+	else
+		p_bre(p, OUT, OUT, 0);
+	EMIT(OEND, 0);
+	g->laststate = THERE();
+
+	/* tidy up loose ends and fill things in */
+	categorize(p, g);
+	stripsnug(p, g);
+	findmust(p, g);
+	g->nplus = pluscount(p, g);
+	g->magic = MAGIC2;
+	preg->re_nsub = g->nsub;
+	preg->re_g = g;
+	preg->re_magic = MAGIC1;
+#ifndef REDEBUG
+	/* not debugging, so can't rely on the assert() in regexec() */
+	if (g->iflags&BAD)
+		SETERROR(REG_ASSERT);
+#endif
+
+	/* win or lose, we're done */
+	if (p->error != 0)	/* lose */
+		regfree(preg);
+	return(p->error);
+}
+
+/*
+ - p_ere - ERE parser top level, concatenation and alternation
+ == static void p_ere(register struct parse *p, int stop, size_t reclimit);
+ */
+static void
+p_ere(register struct parse *p, int stop, size_t reclimit)
+                         
+         			/* character this ERE should end at */
+{
+	register char c;
+	register sopno prevback = 0;
+	register sopno prevfwd = 0;
+	register sopno conc;
+	register int first = 1;		/* is this the first alternative? */
+
+	if (reclimit++ > RECLIMIT || p->error == REG_ESPACE) {
+		p->error = REG_ESPACE;
+		return;
+	}
+
+	for (;;) {
+		/* do a bunch of concatenated expressions */
+		conc = HERE();
+		while (MORE() && (c = PEEK()) != '|' && c != stop)
+			p_ere_exp(p, reclimit);
+		(void)REQUIRE(HERE() != conc, REG_EMPTY);	/* require nonempty */
+
+		if (!EAT('|'))
+			break;		/* NOTE BREAK OUT */
+
+		if (first) {
+			INSERT(OCH_, conc);	/* offset is wrong */
+			prevfwd = conc;
+			prevback = conc;
+			first = 0;
+		}
+		ASTERN(OOR1, prevback);
+		prevback = THERE();
+		AHEAD(prevfwd);			/* fix previous offset */
+		prevfwd = HERE();
+		EMIT(OOR2, 0);			/* offset is very wrong */
+	}
+
+	if (!first) {		/* tail-end fixups */
+		AHEAD(prevfwd);
+		ASTERN(O_CH, prevback);
+	}
+
+	assert(!MORE() || SEE(stop));
+}
+
+/*
+ - p_ere_exp - parse one subERE, an atom possibly followed by a repetition op
+ == static void p_ere_exp(register struct parse *p);
+ */
+static void
+p_ere_exp(register struct parse *p, size_t reclimit)
+{
+	register char c;
+	register sopno pos;
+	register int count;
+	register int count2;
+	register sopno subno;
+	int wascaret = 0;
+
+	assert(MORE());		/* caller should have ensured this */
+	c = GETNEXT();
+
+	pos = HERE();
+	switch (c) {
+	case '(':
+		(void)REQUIRE(MORE(), REG_EPAREN);
+		p->g->nsub++;
+		subno = p->g->nsub;
+		if (subno < NPAREN)
+			p->pbegin[subno] = HERE();
+		EMIT(OLPAREN, subno);
+		if (!SEE(')'))
+			p_ere(p, ')', reclimit);
+		if (subno < NPAREN) {
+			p->pend[subno] = HERE();
+			assert(p->pend[subno] != 0);
+		}
+		EMIT(ORPAREN, subno);
+		(void)MUSTEAT(')', REG_EPAREN);
+		break;
+#ifndef POSIX_MISTAKE
+	case ')':		/* happens only if no current unmatched ( */
+		/*
+		 * You may ask, why the ifndef?  Because I didn't notice
+		 * this until slightly too late for 1003.2, and none of the
+		 * other 1003.2 regular-expression reviewers noticed it at
+		 * all.  So an unmatched ) is legal POSIX, at least until
+		 * we can get it fixed.
+		 */
+		SETERROR(REG_EPAREN);
+		break;
+#endif
+	case '^':
+		EMIT(OBOL, 0);
+		p->g->iflags |= USEBOL;
+		p->g->nbol++;
+		wascaret = 1;
+		break;
+	case '$':
+		EMIT(OEOL, 0);
+		p->g->iflags |= USEEOL;
+		p->g->neol++;
+		break;
+	case '|':
+		SETERROR(REG_EMPTY);
+		break;
+	case '*':
+	case '+':
+	case '?':
+		SETERROR(REG_BADRPT);
+		break;
+	case '.':
+		if (p->g->cflags&REG_NEWLINE)
+			nonnewline(p);
+		else
+			EMIT(OANY, 0);
+		break;
+	case '[':
+		p_bracket(p);
+		break;
+	case '\\':
+		(void)REQUIRE(MORE(), REG_EESCAPE);
+		c = GETNEXT();
+		ordinary(p, c);
+		break;
+	case '{':		/* okay as ordinary except if digit follows */
+		(void)REQUIRE(!MORE() || !ISDIGIT((UCHAR_T)PEEK()), REG_BADRPT);
+		/* FALLTHROUGH */
+	default:
+		ordinary(p, c);
+		break;
+	}
+
+	if (!MORE())
+		return;
+	c = PEEK();
+	/* we call { a repetition if followed by a digit */
+	if (!( c == '*' || c == '+' || c == '?' ||
+				(c == '{' && MORE2() && ISDIGIT((UCHAR_T)PEEK2())) ))
+		return;		/* no repetition, we're done */
+	NEXT();
+
+	(void)REQUIRE(!wascaret, REG_BADRPT);
+	switch (c) {
+	case '*':	/* implemented as +? */
+		/* this case does not require the (y|) trick, noKLUDGE */
+		INSERT(OPLUS_, pos);
+		ASTERN(O_PLUS, pos);
+		INSERT(OQUEST_, pos);
+		ASTERN(O_QUEST, pos);
+		break;
+	case '+':
+		INSERT(OPLUS_, pos);
+		ASTERN(O_PLUS, pos);
+		break;
+	case '?':
+		/* KLUDGE: emit y? as (y|) until subtle bug gets fixed */
+		INSERT(OCH_, pos);		/* offset slightly wrong */
+		ASTERN(OOR1, pos);		/* this one's right */
+		AHEAD(pos);			/* fix the OCH_ */
+		EMIT(OOR2, 0);			/* offset very wrong... */
+		AHEAD(THERE());			/* ...so fix it */
+		ASTERN(O_CH, THERETHERE());
+		break;
+	case '{':
+		count = p_count(p);
+		if (EAT(',')) {
+			if (ISDIGIT((UCHAR_T)PEEK())) {
+				count2 = p_count(p);
+				(void)REQUIRE(count <= count2, REG_BADBR);
+			} else		/* single number with comma */
+				count2 = INFINITY;
+		} else		/* just a single number */
+			count2 = count;
+		repeat(p, pos, count, count2, 0);
+		if (!EAT('}')) {	/* error heuristics */
+			while (MORE() && PEEK() != '}')
+				NEXT();
+			(void)REQUIRE(MORE(), REG_EBRACE);
+			SETERROR(REG_BADBR);
+		}
+		break;
+	}
+
+	if (!MORE())
+		return;
+	c = PEEK();
+	if (!( c == '*' || c == '+' || c == '?' ||
+				(c == '{' && MORE2() && ISDIGIT((UCHAR_T)PEEK2())) ) )
+		return;
+	SETERROR(REG_BADRPT);
+}
+
+/*
+ - p_str - string (no metacharacters) "parser"
+ == static void p_str(register struct parse *p);
+ */
+static void
+p_str(register struct parse *p)
+{
+	(void)REQUIRE(MORE(), REG_EMPTY);
+	while (MORE())
+		ordinary(p, GETNEXT());
+}
+
+/*
+ - p_bre - BRE parser top level, anchoring and concatenation
+ == static void p_bre(register struct parse *p, register int end1, \
+ ==	register int end2, size_t reclimit);
+ * Giving end1 as OUT essentially eliminates the end1/end2 check.
+ *
+ * This implementation is a bit of a kludge, in that a trailing $ is first
+ * taken as an ordinary character and then revised to be an anchor.  The
+ * only undesirable side effect is that '$' gets included as a character
+ * category in such cases.  This is fairly harmless; not worth fixing.
+ * The amount of lookahead needed to avoid this kludge is excessive.
+ */
+static void
+p_bre(register struct parse *p, register int end1, register int end2, size_t reclimit)
+                         
+                  		/* first terminating character */
+                  		/* second terminating character */
+{
+	register sopno start;
+	register int first = 1;			/* first subexpression? */
+	register int wasdollar = 0;
+
+	if (reclimit++ > RECLIMIT || p->error == REG_ESPACE) {
+		p->error = REG_ESPACE;
+		return;
+	}
+
+	start = HERE();
+
+	if (EAT('^')) {
+		EMIT(OBOL, 0);
+		p->g->iflags |= USEBOL;
+		p->g->nbol++;
+	}
+	while (MORE() && !SEETWO(end1, end2)) {
+		wasdollar = p_simp_re(p, first, reclimit);
+		first = 0;
+	}
+	if (wasdollar) {	/* oops, that was a trailing anchor */
+		DROP(1);
+		EMIT(OEOL, 0);
+		p->g->iflags |= USEEOL;
+		p->g->neol++;
+	}
+
+	(void)REQUIRE(HERE() != start, REG_EMPTY);	/* require nonempty */
+}
+
+/*
+ - p_simp_re - parse a simple RE, an atom possibly followed by a repetition
+ == static int p_simp_re(register struct parse *p, int starordinary, size_t reclimit);
+ */
+static int			/* was the simple RE an unbackslashed $? */
+p_simp_re(register struct parse *p, int starordinary, size_t reclimit)
+                         
+                 		/* is a leading * an ordinary character? */
+{
+	register int c;
+	register int count;
+	register int count2;
+	register sopno pos;
+	register int i;
+	register sopno subno;
+	int backsl;
+
+	pos = HERE();		/* repetion op, if any, covers from here */
+
+	assert(MORE());		/* caller should have ensured this */
+	c = GETNEXT();
+	backsl = c == '\\';
+	if (backsl) {
+		(void)REQUIRE(MORE(), REG_EESCAPE);
+		c = (unsigned char)GETNEXT();
+		switch (c) {
+		case '{':
+			SETERROR(REG_BADRPT);
+			break;
+		case '(':
+			p->g->nsub++;
+			subno = p->g->nsub;
+			if (subno < NPAREN)
+				p->pbegin[subno] = HERE();
+			EMIT(OLPAREN, subno);
+			/* the MORE here is an error heuristic */
+			if (MORE() && !SEETWO('\\', ')'))
+				p_bre(p, '\\', ')', reclimit);
+			if (subno < NPAREN) {
+				p->pend[subno] = HERE();
+				assert(p->pend[subno] != 0);
+			}
+			EMIT(ORPAREN, subno);
+			(void)REQUIRE(EATTWO('\\', ')'), REG_EPAREN);
+			break;
+		case ')':	/* should not get here -- must be user */
+		case '}':
+			SETERROR(REG_EPAREN);
+			break;
+		case '1':
+		case '2':
+		case '3':
+		case '4':
+		case '5':
+		case '6':
+		case '7':
+		case '8':
+		case '9':
+			i = c - '0';
+			assert(i < NPAREN);
+			if (p->pend[i] != 0) {
+				assert(i <= p->g->nsub);
+				EMIT(OBACK_, i);
+				assert(p->pbegin[i] != 0);
+				assert(p->strip[p->pbegin[i]] == OLPAREN);
+				assert(p->strip[p->pend[i]] == ORPAREN);
+				(void) dupl(p, p->pbegin[i]+1, p->pend[i]);
+				EMIT(O_BACK, i);
+			} else
+				SETERROR(REG_ESUBREG);
+			p->g->backrefs = 1;
+			break;
+		default:
+			ordinary(p, c);
+			break;
+		}
+	} else {
+		switch (c) {
+		case '.':
+			if (p->g->cflags&REG_NEWLINE)
+				nonnewline(p);
+			else
+				EMIT(OANY, 0);
+			break;
+		case '[':
+			p_bracket(p);
+			break;
+		case '*':
+			(void)REQUIRE(starordinary, REG_BADRPT);
+			/* FALLTHROUGH */
+		default:
+			ordinary(p, c);
+			break;
+		}
+	}
+
+	if (EAT('*')) {		/* implemented as +? */
+		/* this case does not require the (y|) trick, noKLUDGE */
+		INSERT(OPLUS_, pos);
+		ASTERN(O_PLUS, pos);
+		INSERT(OQUEST_, pos);
+		ASTERN(O_QUEST, pos);
+	} else if (EATTWO('\\', '{')) {
+		count = p_count(p);
+		if (EAT(',')) {
+			if (MORE() && ISDIGIT((UCHAR_T)PEEK())) {
+				count2 = p_count(p);
+				(void)REQUIRE(count <= count2, REG_BADBR);
+			} else		/* single number with comma */
+				count2 = INFINITY;
+		} else		/* just a single number */
+			count2 = count;
+		repeat(p, pos, count, count2, reclimit);
+		if (!EATTWO('\\', '}')) {	/* error heuristics */
+			while (MORE() && !SEETWO('\\', '}'))
+				NEXT();
+			(void)REQUIRE(MORE(), REG_EBRACE);
+			SETERROR(REG_BADBR);
+		}
+	} else if (!backsl && c == (unsigned char)'$')	/* $ (but not \$) ends it */
+		return(1);
+
+	return(0);
+}
+
+/*
+ - p_count - parse a repetition count
+ == static int p_count(register struct parse *p);
+ */
+static int			/* the value */
+p_count(register struct parse *p)
+{
+	register int count = 0;
+	register int ndigits = 0;
+
+	while (MORE() && ISDIGIT((UCHAR_T)PEEK()) && count <= DUPMAX) {
+		count = count*10 + (GETNEXT() - '0');
+		ndigits++;
+	}
+
+	(void)REQUIRE(ndigits > 0 && count <= DUPMAX, REG_BADBR);
+	return(count);
+}
+
+/*
+ - p_bracket - parse a bracketed character list
+ == static void p_bracket(register struct parse *p);
+ *
+ * Note a significant property of this code:  if the allocset() did SETERROR,
+ * no set operations are done.
+ */
+static void
+p_bracket(register struct parse *p)
+{
+	register cset *cs;
+	register int invert = 0;
+	static RCHAR_T bow[] = { '[', ':', '<', ':', ']', ']' };
+	static RCHAR_T eow[] = { '[', ':', '>', ':', ']', ']' };
+
+	cs = allocset(p);
+	if (cs == NULL)
+		return;
+
+	/* Dept of Truly Sickening Special-Case Kludges */
+	if (p->next + 5 < p->end && MEMCMP(p->next, bow, 6) == 0) {
+		EMIT(OBOW, 0);
+		NEXTn(6);
+		return;
+	}
+	if (p->next + 5 < p->end && MEMCMP(p->next, eow, 6) == 0) {
+		EMIT(OEOW, 0);
+		NEXTn(6);
+		return;
+	}
+
+	if (EAT('^'))
+		invert++;	/* make note to invert set at end */
+	if (EAT(']'))
+		CHadd(cs, ']');
+	else if (EAT('-'))
+		CHadd(cs, '-');
+	while (MORE() && PEEK() != ']' && !SEETWO('-', ']'))
+		p_b_term(p, cs);
+	if (EAT('-'))
+		CHadd(cs, '-');
+	(void)MUSTEAT(']', REG_EBRACK);
+
+	if (p->error != 0)	/* don't mess things up further */
+		return;
+
+	if (p->g->cflags&REG_ICASE) {
+		register int i;
+		register int ci;
+
+		for (i = p->g->csetsize - 1; i >= 0; i--)
+			if (CHIN(cs, i) && isalpha(i)) {
+				ci = othercase(i);
+				if (ci != i)
+					CHadd(cs, ci);
+			}
+		if (cs->multis != NULL)
+			mccase(p, cs);
+	}
+	if (invert) {
+		register int i;
+
+		for (i = p->g->csetsize - 1; i >= 0; i--)
+			if (CHIN(cs, i))
+				CHsub(cs, i);
+			else
+				CHadd(cs, i);
+		if (p->g->cflags&REG_NEWLINE)
+			CHsub(cs, '\n');
+		if (cs->multis != NULL)
+			mcinvert(p, cs);
+	}
+
+	assert(cs->multis == NULL);		/* xxx */
+
+	if (nch(p, cs) == 1) {		/* optimize singleton sets */
+		ordinary(p, firstch(p, cs));
+		freeset(p, cs);
+	} else
+		EMIT(OANYOF, freezeset(p, cs));
+}
+
+/*
+ - p_b_term - parse one term of a bracketed character list
+ == static void p_b_term(register struct parse *p, register cset *cs);
+ */
+static void
+p_b_term(register struct parse *p, register cset *cs)
+{
+	register char c;
+	register char start, finish;
+	register int i;
+
+	/* classify what we've got */
+	switch ((MORE()) ? PEEK() : '\0') {
+	case '[':
+		c = (MORE2()) ? PEEK2() : '\0';
+		break;
+	case '-':
+		SETERROR(REG_ERANGE);
+		return;			/* NOTE RETURN */
+		break;
+	default:
+		c = '\0';
+		break;
+	}
+
+	switch (c) {
+	case ':':		/* character class */
+		NEXT2();
+		(void)REQUIRE(MORE(), REG_EBRACK);
+		c = PEEK();
+		(void)REQUIRE(c != '-' && c != ']', REG_ECTYPE);
+		p_b_cclass(p, cs);
+		(void)REQUIRE(MORE(), REG_EBRACK);
+		(void)REQUIRE(EATTWO(':', ']'), REG_ECTYPE);
+		break;
+	case '=':		/* equivalence class */
+		NEXT2();
+		(void)REQUIRE(MORE(), REG_EBRACK);
+		c = PEEK();
+		(void)REQUIRE(c != '-' && c != ']', REG_ECOLLATE);
+		p_b_eclass(p, cs);
+		(void)REQUIRE(MORE(), REG_EBRACK);
+		(void)REQUIRE(EATTWO('=', ']'), REG_ECOLLATE);
+		break;
+	default:		/* symbol, ordinary character, or range */
+/* xxx revision needed for multichar stuff */
+		start = p_b_symbol(p);
+		if (SEE('-') && MORE2() && PEEK2() != ']') {
+			/* range */
+			NEXT();
+			if (EAT('-'))
+				finish = '-';
+			else
+				finish = p_b_symbol(p);
+		} else
+			finish = start;
+/* xxx what about signed chars here... */
+		(void)REQUIRE(start <= finish, REG_ERANGE);
+		for (i = start; i <= finish; i++)
+			CHadd(cs, i);
+		break;
+	}
+}
+
+/*
+ - p_b_cclass - parse a character-class name and deal with it
+ == static void p_b_cclass(register struct parse *p, register cset *cs);
+ */
+static void
+p_b_cclass(register struct parse *p, register cset *cs)
+{
+	register RCHAR_T *sp = p->next;
+	register struct cclass *cp;
+	register size_t len;
+	register const char *u;
+	register char c;
+
+	while (MORE() && isalpha(PEEK()))
+		NEXT();
+	len = p->next - sp;
+	for (cp = cclasses; cp->name != NULL; cp++)
+		if (STRLEN(cp->name) == len && !MEMCMP(cp->name, sp, len))
+			break;
+	if (cp->name == NULL) {
+		/* oops, didn't find it */
+		SETERROR(REG_ECTYPE);
+		return;
+	}
+
+	u = cp->chars;
+	while ((c = *u++) != '\0')
+		CHadd(cs, c);
+	for (u = cp->multis; *u != '\0'; u += strlen(u) + 1)
+		MCadd(p, cs, u);
+}
+
+/*
+ - p_b_eclass - parse an equivalence-class name and deal with it
+ == static void p_b_eclass(register struct parse *p, register cset *cs);
+ *
+ * This implementation is incomplete. xxx
+ */
+static void
+p_b_eclass(register struct parse *p, register cset *cs)
+{
+	register char c;
+
+	c = p_b_coll_elem(p, '=');
+	CHadd(cs, c);
+}
+
+/*
+ - p_b_symbol - parse a character or [..]ed multicharacter collating symbol
+ == static char p_b_symbol(register struct parse *p);
+ */
+static char			/* value of symbol */
+p_b_symbol(register struct parse *p)
+{
+	register char value;
+
+	(void)REQUIRE(MORE(), REG_EBRACK);
+	if (!EATTWO('[', '.'))
+		return(GETNEXT());
+
+	/* collating symbol */
+	value = p_b_coll_elem(p, '.');
+	(void)REQUIRE(EATTWO('.', ']'), REG_ECOLLATE);
+	return(value);
+}
+
+/*
+ - p_b_coll_elem - parse a collating-element name and look it up
+ == static char p_b_coll_elem(register struct parse *p, int endc);
+ */
+static char			/* value of collating element */
+p_b_coll_elem(register struct parse *p, int endc)
+                         
+         			/* name ended by endc,']' */
+{
+	register RCHAR_T *sp = p->next;
+	register struct cname *cp;
+	register size_t len;
+
+	while (MORE() && !SEETWO(endc, ']'))
+		NEXT();
+	if (!MORE()) {
+		SETERROR(REG_EBRACK);
+		return(0);
+	}
+	len = p->next - sp;
+	for (cp = cnames; cp->name != NULL; cp++)
+		if (STRLEN(cp->name) == len && MEMCMP(cp->name, sp, len))
+			return(cp->code);	/* known name */
+	if (len == 1)
+		return(*sp);	/* single character */
+	SETERROR(REG_ECOLLATE);			/* neither */
+	return(0);
+}
+
+/*
+ - othercase - return the case counterpart of an alphabetic
+ == static char othercase(int ch);
+ */
+static char			/* if no counterpart, return ch */
+othercase(int ch)
+{
+	assert(isalpha(ch));
+	if (isupper(ch))
+		return(tolower(ch));
+	else if (islower(ch))
+		return(toupper(ch));
+	else			/* peculiar, but could happen */
+		return(ch);
+}
+
+/*
+ - bothcases - emit a dualcase version of a two-case character
+ == static void bothcases(register struct parse *p, int ch);
+ *
+ * Boy, is this implementation ever a kludge...
+ */
+static void
+bothcases(register struct parse *p, int ch)
+{
+	register RCHAR_T *oldnext = p->next;
+	register RCHAR_T *oldend = p->end;
+	RCHAR_T bracket[3];
+
+	assert(othercase(ch) != ch);	/* p_bracket() would recurse */
+	p->next = bracket;
+	p->end = bracket+2;
+	bracket[0] = ch;
+	bracket[1] = ']';
+	bracket[2] = '\0';
+	p_bracket(p);
+	assert(p->next == bracket+2);
+	p->next = oldnext;
+	p->end = oldend;
+}
+
+/*
+ - ordinary - emit an ordinary character
+ == static void ordinary(register struct parse *p, register int ch);
+ */
+static void
+ordinary(register struct parse *p, register int ch)
+{
+/*
+	register cat_t *cap = p->g->categories;
+*/
+
+	if ((p->g->cflags&REG_ICASE) && isalpha(ch) && othercase(ch) != ch)
+		bothcases(p, ch);
+	else {
+		EMIT(OCHAR, (UCHAR_T)ch);
+/*
+		if (cap[ch] == 0)
+			cap[ch] = p->g->ncategories++;
+*/
+	}
+}
+
+/*
+ - nonnewline - emit REG_NEWLINE version of OANY
+ == static void nonnewline(register struct parse *p);
+ *
+ * Boy, is this implementation ever a kludge...
+ */
+static void
+nonnewline(register struct parse *p)
+{
+	register RCHAR_T *oldnext = p->next;
+	register RCHAR_T *oldend = p->end;
+	RCHAR_T bracket[4];
+
+	p->next = bracket;
+	p->end = bracket+3;
+	bracket[0] = '^';
+	bracket[1] = '\n';
+	bracket[2] = ']';
+	bracket[3] = '\0';
+	p_bracket(p);
+	assert(p->next == bracket+3);
+	p->next = oldnext;
+	p->end = oldend;
+}
+
+/*
+ - repeat - generate code for a bounded repetition, recursively if needed
+ == static void repeat(register struct parse *p, sopno start, int from, int to, size_t reclimit);
+ */
+static void
+repeat(register struct parse *p, sopno start, int from, int to, size_t reclimit)
+                         
+            			/* operand from here to end of strip */
+         			/* repeated from this number */
+       				/* to this number of times (maybe INFINITY) */
+{
+	register sopno finish;
+#	define	N	2
+#	define	INF	3
+#	define	REP(f, t)	((f)*8 + (t))
+#	define	MAP(n)	(((n) <= 1) ? (n) : ((n) == INFINITY) ? INF : N)
+	register sopno copy;
+
+	if (reclimit++ > RECLIMIT) 
+		p->error = REG_ESPACE;
+	if (p->error)
+		return;
+
+	finish = HERE();
+
+	assert(from <= to);
+
+	switch (REP(MAP(from), MAP(to))) {
+	case REP(0, 0):			/* must be user doing this */
+		DROP(finish-start);	/* drop the operand */
+		break;
+	case REP(0, 1):			/* as x{1,1}? */
+	case REP(0, N):			/* as x{1,n}? */
+	case REP(0, INF):		/* as x{1,}? */
+		/* KLUDGE: emit y? as (y|) until subtle bug gets fixed */
+		INSERT(OCH_, start);		/* offset is wrong... */
+		repeat(p, start+1, 1, to, reclimit);
+		ASTERN(OOR1, start);
+		AHEAD(start);			/* ... fix it */
+		EMIT(OOR2, 0);
+		AHEAD(THERE());
+		ASTERN(O_CH, THERETHERE());
+		break;
+	case REP(1, 1):			/* trivial case */
+		/* done */
+		break;
+	case REP(1, N):			/* as x?x{1,n-1} */
+		/* KLUDGE: emit y? as (y|) until subtle bug gets fixed */
+		INSERT(OCH_, start);
+		ASTERN(OOR1, start);
+		AHEAD(start);
+		EMIT(OOR2, 0);			/* offset very wrong... */
+		AHEAD(THERE());			/* ...so fix it */
+		ASTERN(O_CH, THERETHERE());
+		copy = dupl(p, start+1, finish+1);
+		assert(copy == finish+4);
+		repeat(p, copy, 1, to-1, reclimit);
+		break;
+	case REP(1, INF):		/* as x+ */
+		INSERT(OPLUS_, start);
+		ASTERN(O_PLUS, start);
+		break;
+	case REP(N, N):			/* as xx{m-1,n-1} */
+		copy = dupl(p, start, finish);
+		repeat(p, copy, from-1, to-1, reclimit);
+		break;
+	case REP(N, INF):		/* as xx{n-1,INF} */
+		copy = dupl(p, start, finish);
+		repeat(p, copy, from-1, to, reclimit);
+		break;
+	default:			/* "can't happen" */
+		SETERROR(REG_ASSERT);	/* just in case */
+		break;
+	}
+}
+
+/*
+ - seterr - set an error condition
+ == static int seterr(register struct parse *p, int e);
+ */
+static int			/* useless but makes type checking happy */
+seterr(register struct parse *p, int e)
+{
+	if (p->error == 0)	/* keep earliest error condition */
+		p->error = e;
+	p->next = nuls;		/* try to bring things to a halt */
+	p->end = nuls;
+	return(0);		/* make the return value well-defined */
+}
+
+/*
+ - allocset - allocate a set of characters for []
+ == static cset *allocset(register struct parse *p);
+ */
+static cset *
+allocset(register struct parse *p)
+{
+	register int no = p->g->ncsets++;
+	register size_t nc;
+	register size_t nbytes;
+	register cset *cs;
+	register size_t css = (size_t)p->g->csetsize;
+	register int i;
+
+	if (no >= p->ncsalloc) {	/* need another column of space */
+		p->ncsalloc += CHAR_BIT;
+		nc = p->ncsalloc;
+		assert(nc % CHAR_BIT == 0);
+		nbytes = nc / CHAR_BIT * css;
+		if (MEMSIZE(p) > MEMLIMIT)
+			goto oomem;
+		if (p->g->sets == NULL)
+			p->g->sets = (cset *)malloc(nc * sizeof(cset));
+		else
+			p->g->sets = (cset *)realloc((char *)p->g->sets,
+							nc * sizeof(cset));
+		if (p->g->setbits == NULL)
+			p->g->setbits = (uch *)malloc(nbytes);
+		else {
+			p->g->setbits = (uch *)realloc((char *)p->g->setbits,
+								nbytes);
+			/* xxx this isn't right if setbits is now NULL */
+			for (i = 0; i < no; i++)
+				p->g->sets[i].ptr = p->g->setbits + css*(i/CHAR_BIT);
+		}
+		if (p->g->sets != NULL && p->g->setbits != NULL)
+			(void) memset((char *)p->g->setbits + (nbytes - css),
+								0, css);
+		else {
+oomem:
+			no = 0;
+			SETERROR(REG_ESPACE);
+			/* caller's responsibility not to do set ops */
+			return NULL;
+		}
+	}
+
+	cs = &p->g->sets[no];
+	cs->ptr = p->g->setbits + css*((no)/CHAR_BIT);
+	cs->mask = 1 << ((no) % CHAR_BIT);
+	cs->hash = 0;
+	cs->smultis = 0;
+	cs->multis = NULL;
+
+	return(cs);
+}
+
+/*
+ - freeset - free a now-unused set
+ == static void freeset(register struct parse *p, register cset *cs);
+ */
+static void
+freeset(register struct parse *p, register cset *cs)
+{
+	register size_t i;
+	register cset *top = &p->g->sets[p->g->ncsets];
+	register size_t css = (size_t)p->g->csetsize;
+
+	for (i = 0; i < css; i++)
+		CHsub(cs, i);
+	if (cs == top-1)	/* recover only the easy case */
+		p->g->ncsets--;
+}
+
+/*
+ - freezeset - final processing on a set of characters
+ == static int freezeset(register struct parse *p, register cset *cs);
+ *
+ * The main task here is merging identical sets.  This is usually a waste
+ * of time (although the hash code minimizes the overhead), but can win
+ * big if REG_ICASE is being used.  REG_ICASE, by the way, is why the hash
+ * is done using addition rather than xor -- all ASCII [aA] sets xor to
+ * the same value!
+ */
+static int			/* set number */
+freezeset(register struct parse *p, register cset *cs)
+{
+	register uch h = cs->hash;
+	register size_t i;
+	register cset *top = &p->g->sets[p->g->ncsets];
+	register cset *cs2;
+	register size_t css = (size_t)p->g->csetsize;
+
+	/* look for an earlier one which is the same */
+	for (cs2 = &p->g->sets[0]; cs2 < top; cs2++)
+		if (cs2->hash == h && cs2 != cs) {
+			/* maybe */
+			for (i = 0; i < css; i++)
+				if (!!CHIN(cs2, i) != !!CHIN(cs, i))
+					break;		/* no */
+			if (i == css)
+				break;			/* yes */
+		}
+
+	if (cs2 < top) {	/* found one */
+		freeset(p, cs);
+		cs = cs2;
+	}
+
+	return((int)(cs - p->g->sets));
+}
+
+/*
+ - firstch - return first character in a set (which must have at least one)
+ == static int firstch(register struct parse *p, register cset *cs);
+ */
+static int			/* character; there is no "none" value */
+firstch(register struct parse *p, register cset *cs)
+{
+	register size_t i;
+	register size_t css = (size_t)p->g->csetsize;
+
+	for (i = 0; i < css; i++)
+		if (CHIN(cs, i))
+			return((char)i);
+	assert(never);
+	return(0);		/* arbitrary */
+}
+
+/*
+ - nch - number of characters in a set
+ == static int nch(register struct parse *p, register cset *cs);
+ */
+static int
+nch(register struct parse *p, register cset *cs)
+{
+	register size_t i;
+	register size_t css = (size_t)p->g->csetsize;
+	register int n = 0;
+
+	for (i = 0; i < css; i++)
+		if (CHIN(cs, i))
+			n++;
+	return(n);
+}
+
+/*
+ - mcadd - add a collating element to a cset
+ == static void mcadd(register struct parse *p, register cset *cs, \
+ ==	register char *cp);
+ */
+static void
+mcadd(register struct parse *p, register cset *cs, register const char *cp)
+{
+	register size_t oldend = cs->smultis;
+	void *np;
+
+	cs->smultis += strlen(cp) + 1;
+	np = realloc(cs->multis, cs->smultis);
+	if (np == NULL) {
+		if (cs->multis)
+			free(cs->multis);
+		cs->multis = NULL;
+		SETERROR(REG_ESPACE);
+		return;
+	}
+	cs->multis = np;
+
+	(void) strlcpy(cs->multis + oldend - 1, cp, cs->smultis - oldend + 1);
+}
+
+#ifdef notdef
+/*
+ - mcsub - subtract a collating element from a cset
+ == static void mcsub(register cset *cs, register char *cp);
+ */
+static void
+mcsub(register cset *cs, register char *cp)
+{
+	register char *fp = mcfind(cs, cp);
+	register size_t len = strlen(fp);
+
+	assert(fp != NULL);
+	(void) memmove(fp, fp + len + 1,
+				cs->smultis - (fp + len + 1 - cs->multis));
+	cs->smultis -= len;
+
+	if (cs->smultis == 0) {
+		free(cs->multis);
+		cs->multis = NULL;
+		return;
+	}
+
+	cs->multis = realloc(cs->multis, cs->smultis);
+	assert(cs->multis != NULL);
+}
+
+/*
+ - mcin - is a collating element in a cset?
+ == static int mcin(register cset *cs, register char *cp);
+ */
+static int
+mcin(register cset *cs, register char *cp)
+{
+	return(mcfind(cs, cp) != NULL);
+}
+
+/*
+ - mcfind - find a collating element in a cset
+ == static char *mcfind(register cset *cs, register char *cp);
+ */
+static char *
+mcfind(register cset *cs, register char *cp)
+{
+	register char *p;
+
+	if (cs->multis == NULL)
+		return(NULL);
+	for (p = cs->multis; *p != '\0'; p += strlen(p) + 1)
+		if (strcmp(cp, p) == 0)
+			return(p);
+	return(NULL);
+}
+#endif
+
+/*
+ - mcinvert - invert the list of collating elements in a cset
+ == static void mcinvert(register struct parse *p, register cset *cs);
+ *
+ * This would have to know the set of possibilities.  Implementation
+ * is deferred.
+ */
+static void
+mcinvert(register struct parse *p, register cset *cs)
+{
+	assert(cs->multis == NULL);	/* xxx */
+}
+
+/*
+ - mccase - add case counterparts of the list of collating elements in a cset
+ == static void mccase(register struct parse *p, register cset *cs);
+ *
+ * This would have to know the set of possibilities.  Implementation
+ * is deferred.
+ */
+static void
+mccase(register struct parse *p, register cset *cs)
+{
+	assert(cs->multis == NULL);	/* xxx */
+}
+
+#ifdef notdef
+/*
+ - isinsets - is this character in any sets?
+ == static int isinsets(register struct re_guts *g, int c);
+ */
+static int			/* predicate */
+isinsets(register struct re_guts *g, int c)
+{
+	register uch *col;
+	register int i;
+	register int ncols = (g->ncsets+(CHAR_BIT-1)) / CHAR_BIT;
+	register unsigned uc = (unsigned char)c;
+
+	for (i = 0, col = g->setbits; i < ncols; i++, col += g->csetsize)
+		if (col[uc] != 0)
+			return(1);
+	return(0);
+}
+
+/*
+ - samesets - are these two characters in exactly the same sets?
+ == static int samesets(register struct re_guts *g, int c1, int c2);
+ */
+static int			/* predicate */
+samesets(register struct re_guts *g, int c1, int c2)
+{
+	register uch *col;
+	register int i;
+	register int ncols = (g->ncsets+(CHAR_BIT-1)) / CHAR_BIT;
+	register unsigned uc1 = (unsigned char)c1;
+	register unsigned uc2 = (unsigned char)c2;
+
+	for (i = 0, col = g->setbits; i < ncols; i++, col += g->csetsize)
+		if (col[uc1] != col[uc2])
+			return(0);
+	return(1);
+}
+#endif
+
+/*
+ - categorize - sort out character categories
+ == static void categorize(struct parse *p, register struct re_guts *g);
+ */
+static void
+categorize(struct parse *p, register struct re_guts *g)
+{
+#ifdef notdef
+	register cat_t *cats = g->categories;
+	register int c;
+	register int c2;
+	register cat_t cat;
+
+	/* avoid making error situations worse */
+	if (p->error != 0)
+		return;
+
+	for (c = CHAR_MIN; c <= CHAR_MAX; c++)
+		if (cats[c] == 0 && isinsets(g, c)) {
+			cat = g->ncategories++;
+			cats[c] = cat;
+			for (c2 = c+1; c2 <= CHAR_MAX; c2++)
+				if (cats[c2] == 0 && samesets(g, c, c2))
+					cats[c2] = cat;
+		}
+#endif
+}
+
+/*
+ - dupl - emit a duplicate of a bunch of sops
+ == static sopno dupl(register struct parse *p, sopno start, sopno finish);
+ */
+static sopno			/* start of duplicate */
+dupl(register struct parse *p, sopno start, sopno finish)
+                         
+            			/* from here */
+             			/* to this less one */
+{
+	register sopno ret = HERE();
+	register sopno len = finish - start;
+
+	assert(finish >= start);
+	if (len == 0)
+		return(ret);
+	if (!enlarge(p, p->ssize + len))	/* this many unexpected additions */
+		return ret;
+	assert(p->ssize >= p->slen + len);
+	(void) memcpy((char *)(p->strip + p->slen),
+		(char *)(p->strip + start), (size_t)len*sizeof(sop));
+	(void) memcpy((char *)(p->stripdata + p->slen),
+		(char *)(p->stripdata + start), (size_t)len*sizeof(RCHAR_T));
+	p->slen += len;
+	return(ret);
+}
+
+/*
+ - doemit - emit a strip operator
+ == static void doemit(register struct parse *p, sop op, size_t opnd);
+ *
+ * It might seem better to implement this as a macro with a function as
+ * hard-case backup, but it's just too big and messy unless there are
+ * some changes to the data structures.  Maybe later.
+ */
+static void
+doemit(register struct parse *p, sop op, size_t opnd)
+{
+	/* avoid making error situations worse */
+	if (p->error != 0)
+		return;
+
+	/* deal with oversize operands ("can't happen", more or less) */
+	assert(opnd < 1);
+
+	/* deal with undersized strip */
+	if (p->slen >= p->ssize)
+		if (!enlarge(p, (p->ssize+1) / 2 * 3))	/* +50% */
+			return;
+
+	/* finally, it's all reduced to the easy case */
+	p->strip[p->slen] = op;
+	p->stripdata[p->slen] = opnd;
+	p->slen++;
+}
+
+/*
+ - doinsert - insert a sop into the strip
+ == static void doinsert(register struct parse *p, sop op, size_t opnd, sopno pos);
+ */
+static void
+doinsert(register struct parse *p, sop op, size_t opnd, sopno pos)
+{
+	register sopno sn;
+	register sop s;
+	register RCHAR_T d;
+	register int i;
+
+	/* avoid making error situations worse */
+	if (p->error != 0)
+		return;
+
+	sn = HERE();
+	EMIT(op, opnd);		/* do checks, ensure space */
+	assert(HERE() == sn+1);
+	s = p->strip[sn];
+	d = p->stripdata[sn];
+
+	/* adjust paren pointers */
+	assert(pos > 0);
+	for (i = 1; i < NPAREN; i++) {
+		if (p->pbegin[i] >= pos) {
+			p->pbegin[i]++;
+		}
+		if (p->pend[i] >= pos) {
+			p->pend[i]++;
+		}
+	}
+
+	memmove((char *)&p->strip[pos+1], (char *)&p->strip[pos],
+						(HERE()-pos-1)*sizeof(sop));
+	memmove((char *)&p->stripdata[pos+1], (char *)&p->stripdata[pos],
+						(HERE()-pos-1)*sizeof(RCHAR_T));
+	p->strip[pos] = s;
+	p->stripdata[pos] = d;
+}
+
+/*
+ - dofwd - complete a forward reference
+ == static void dofwd(register struct parse *p, sopno pos, sop value);
+ */
+static void
+dofwd(register struct parse *p, register sopno pos, sop value)
+{
+	/* avoid making error situations worse */
+	if (p->error != 0)
+		return;
+
+	assert(value < 1);
+	p->stripdata[pos] = value;
+}
+
+/*
+ - enlarge - enlarge the strip
+ == static int enlarge(register struct parse *p, sopno size);
+ */
+static int
+enlarge(register struct parse *p, register sopno size)
+{
+	register sop *sp;
+	register RCHAR_T *dp;
+	sopno osize;
+
+	if (p->ssize >= size)
+		return 1;
+
+	osize = p->ssize;
+	p->ssize = size;
+	if (MEMSIZE(p) > MEMLIMIT)
+		goto oomem;
+	sp = realloc(p->strip, p->ssize * sizeof(sop));
+	if (sp == NULL)
+		goto oomem;
+	p->strip = sp;
+	dp = realloc(p->stripdata, p->ssize * sizeof(RCHAR_T));
+	if (dp == NULL) {
+oomem:
+		p->ssize = osize;
+		SETERROR(REG_ESPACE);
+		return 0;
+	}
+	p->stripdata = dp;
+	return 1;
+}
+
+/*
+ - stripsnug - compact the strip
+ == static void stripsnug(register struct parse *p, register struct re_guts *g);
+ */
+static void
+stripsnug(register struct parse *p, register struct re_guts *g)
+{
+	g->nstates = p->slen;
+	g->strip = (sop *)realloc((char *)p->strip,
+	    p->slen * sizeof(sop));
+	if (g->strip == NULL) {
+		SETERROR(REG_ESPACE);
+		g->strip = p->strip;
+	}
+	g->stripdata = (RCHAR_T *)realloc((char *)p->stripdata,
+	    p->slen * sizeof(RCHAR_T));
+	if (g->stripdata == NULL) {
+		SETERROR(REG_ESPACE);
+		g->stripdata = p->stripdata;
+	}
+}
+
+/*
+ - findmust - fill in must and mlen with longest mandatory literal string
+ == static void findmust(register struct parse *p, register struct re_guts *g);
+ *
+ * This algorithm could do fancy things like analyzing the operands of |
+ * for common subsequences.  Someday.  This code is simple and finds most
+ * of the interesting cases.
+ *
+ * Note that must and mlen got initialized during setup.
+ */
+static void
+findmust(struct parse *p, register struct re_guts *g)
+{
+	register sop *scans;
+	register RCHAR_T *scand;
+	sop *starts = 0;
+	RCHAR_T *startd = NULL;
+	register sop *newstarts = 0;
+	register RCHAR_T *newstartd = NULL;
+	register sopno newlen;
+	register sop s;
+	register RCHAR_T d;
+	register RCHAR_T *cp;
+	register sopno i;
+
+	/* avoid making error situations worse */
+	if (p->error != 0)
+		return;
+
+	/* find the longest OCHAR sequence in strip */
+	newlen = 0;
+	scans = g->strip + 1;
+	scand = g->stripdata + 1;
+	do {
+		s = *scans++;
+		d = *scand++;
+		switch (s) {
+		case OCHAR:		/* sequence member */
+			if (newlen == 0) {		/* new sequence */
+				newstarts = scans - 1;
+				newstartd = scand - 1;
+			}
+			newlen++;
+			break;
+		case OPLUS_:		/* things that don't break one */
+		case OLPAREN:
+		case ORPAREN:
+			break;
+		case OQUEST_:		/* things that must be skipped */
+		case OCH_:
+			scans--;
+			scand--;
+			do {
+				scans += d;
+				scand += d;
+				s = *scans;
+				d = *scand;
+				/* assert() interferes w debug printouts */
+				if (s != O_QUEST && s != O_CH && s != OOR2) {
+					g->iflags |= BAD;
+					return;
+				}
+			} while (s != O_QUEST && s != O_CH);
+			/* fallthrough */
+		default:		/* things that break a sequence */
+			if (newlen > g->mlen) {		/* ends one */
+				starts = newstarts;
+				startd = newstartd;
+				g->mlen = newlen;
+			}
+			newlen = 0;
+			break;
+		}
+	} while (s != OEND);
+
+	if (g->mlen == 0)		/* there isn't one */
+		return;
+
+	/* turn it into a character string */
+	g->must = malloc(((size_t)g->mlen + 1) * sizeof(RCHAR_T));
+	if (g->must == NULL) {		/* argh; just forget it */
+		g->mlen = 0;
+		return;
+	}
+	cp = g->must;
+	scans = starts;
+	scand = startd;
+	for (i = g->mlen; i > 0; i--) {
+		for (;;) {
+			s = *scans++;
+			d = *scand++;
+			if (s == OCHAR)
+				break;
+		}
+		assert(cp < g->must + g->mlen);
+		*cp++ = d;
+	}
+	assert(cp == g->must + g->mlen);
+	*cp++ = '\0';		/* just on general principles */
+}
+
+/*
+ - pluscount - count + nesting
+ == static sopno pluscount(register struct parse *p, register struct re_guts *g);
+ */
+static sopno			/* nesting depth */
+pluscount(struct parse *p, register struct re_guts *g)
+{
+	register sop *scan;
+	register sop s;
+	register sopno plusnest = 0;
+	register sopno maxnest = 0;
+
+	if (p->error != 0)
+		return(0);	/* there may not be an OEND */
+
+	scan = g->strip + 1;
+	do {
+		s = *scan++;
+		switch (s) {
+		case OPLUS_:
+			plusnest++;
+			break;
+		case O_PLUS:
+			if (plusnest > maxnest)
+				maxnest = plusnest;
+			plusnest--;
+			break;
+		}
+	} while (s != OEND);
+	if (plusnest != 0)
+		g->iflags |= BAD;
+	return(maxnest);
+}


Property changes on: trunk/contrib/nvi/regex/regcomp.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/contrib/nvi/regex/regerror.c
===================================================================
--- trunk/contrib/nvi/regex/regerror.c	                        (rev 0)
+++ trunk/contrib/nvi/regex/regerror.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -0,0 +1,176 @@
+/*	$NetBSD: regerror.c,v 1.2 2008/12/05 22:51:43 christos Exp $ */
+
+/*-
+ * Copyright (c) 1992, 1993, 1994 Henry Spencer.
+ * Copyright (c) 1992, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Henry Spencer of the University of Toronto.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)regerror.c	8.3 (Berkeley) 3/19/94
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)regerror.c	8.3 (Berkeley) 3/19/94";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <regex.h>
+
+#include "utils.h"
+
+/* ========= begin header generated by ./mkh ========= */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* === regerror.c === */
+static char *regatoi __P((const regex_t *preg, char *localbuf));
+
+#ifdef __cplusplus
+}
+#endif
+/* ========= end header generated by ./mkh ========= */
+/*
+ = #define	REG_NOMATCH	 1
+ = #define	REG_BADPAT	 2
+ = #define	REG_ECOLLATE	 3
+ = #define	REG_ECTYPE	 4
+ = #define	REG_EESCAPE	 5
+ = #define	REG_ESUBREG	 6
+ = #define	REG_EBRACK	 7
+ = #define	REG_EPAREN	 8
+ = #define	REG_EBRACE	 9
+ = #define	REG_BADBR	10
+ = #define	REG_ERANGE	11
+ = #define	REG_ESPACE	12
+ = #define	REG_BADRPT	13
+ = #define	REG_EMPTY	14
+ = #define	REG_ASSERT	15
+ = #define	REG_INVARG	16
+ = #define	REG_ATOI	255	// convert name to number (!)
+ = #define	REG_ITOA	0400	// convert number to name (!)
+ */
+static struct rerr {
+	int code;
+	const char *name;
+	const char *explain;
+} rerrs[] = {
+	{ REG_NOMATCH,	"REG_NOMATCH",	"regexec() failed to match" },
+	{ REG_BADPAT,	"REG_BADPAT",	"invalid regular expression" },
+	{ REG_ECOLLATE,	"REG_ECOLLATE",	"invalid collating element" },
+	{ REG_ECTYPE,	"REG_ECTYPE",	"invalid character class" },
+	{ REG_EESCAPE,	"REG_EESCAPE",	"trailing backslash (\\)" },
+	{ REG_ESUBREG,	"REG_ESUBREG",	"invalid backreference number" },
+	{ REG_EBRACK,	"REG_EBRACK",	"brackets ([ ]) not balanced" },
+	{ REG_EPAREN,	"REG_EPAREN",	"parentheses not balanced" },
+	{ REG_EBRACE,	"REG_EBRACE",	"braces not balanced" },
+	{ REG_BADBR,	"REG_BADBR",	"invalid repetition count(s)" },
+	{ REG_ERANGE,	"REG_ERANGE",	"invalid character range" },
+	{ REG_ESPACE,	"REG_ESPACE",	"out of memory" },
+	{ REG_BADRPT,	"REG_BADRPT",	"repetition-operator operand invalid" },
+	{ REG_EMPTY,	"REG_EMPTY",	"empty (sub)expression" },
+	{ REG_ASSERT,	"REG_ASSERT",	"\"can't happen\" -- you found a bug" },
+	{ REG_INVARG,	"REG_INVARG",	"invalid argument to regex routine" },
+	{ 0,		"",		"*** unknown regexp error code ***" },
+};
+
+/*
+ - regerror - the interface to error numbers
+ = extern size_t regerror(int, const regex_t *, char *, size_t);
+ */
+/* ARGSUSED */
+size_t
+regerror(int errcode, const regex_t *preg, char *errbuf, size_t errbuf_size)
+{
+	register struct rerr *r;
+	register size_t len;
+	register int target = errcode &~ REG_ITOA;
+	register const char *s;
+	char convbuf[50];
+
+	if (errcode == REG_ATOI)
+		s = regatoi(preg, convbuf);
+	else {
+		for (r = rerrs; r->code != 0; r++)
+			if (r->code == target)
+				break;
+	
+		if (errcode&REG_ITOA) {
+			if (r->code != 0) {
+				assert(strlen(r->name) < sizeof(convbuf));
+				(void) strlcpy(convbuf, r->name, sizeof(convbuf));
+			} else
+				(void) snprintf(convbuf, sizeof(convbuf),
+				    "REG_0x%x", target);
+			s = convbuf;
+		} else
+			s = r->explain;
+	}
+
+	len = strlen(s) + 1;
+	if (errbuf_size > 0) {
+		(void) strlcpy(errbuf, s, errbuf_size);
+	}
+
+	return(len);
+}
+
+/*
+ - regatoi - internal routine to implement REG_ATOI
+ == static char *regatoi(const regex_t *preg, char *localbuf);
+ */
+static char *
+regatoi(const regex_t *preg, char *localbuf)
+{
+#if 0 /* we don't seem to use this and it gives a warning. */
+	register struct rerr *r;
+	register size_t siz;
+	register char *p;
+
+	for (r = rerrs; r->code != 0; r++)
+		if (strcmp(r->name, preg->re_endp) == 0)
+			break;
+	if (r->code == 0)
+		return("0");
+
+	sprintf(localbuf, "%d", r->code);
+#else
+	*localbuf = '\0';
+#endif
+	return(localbuf);
+}


Property changes on: trunk/contrib/nvi/regex/regerror.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/contrib/nvi/regex/regex.3
===================================================================
--- trunk/contrib/nvi/regex/regex.3	                        (rev 0)
+++ trunk/contrib/nvi/regex/regex.3	2018-06-10 20:23:48 UTC (rev 10823)
@@ -0,0 +1,540 @@
+.\"	$NetBSD: regex.3,v 1.1.1.2 2008/05/18 14:31:38 aymeric Exp $
+.\"
+.\" Copyright (c) 1992, 1993, 1994 Henry Spencer.
+.\" Copyright (c) 1992, 1993, 1994
+.\"	The Regents of the University of California.  All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Henry Spencer of the University of Toronto.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\"    must display the following acknowledgement:
+.\"	This product includes software developed by the University of
+.\"	California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"	@(#)regex.3	8.2 (Berkeley) 3/16/94
+.\"
+.TH REGEX 3 "March 16, 1994"
+.de ZR
+.\" one other place knows this name:  the SEE ALSO section
+.IR re_format (7) \\$1
+..
+.SH NAME
+regcomp, regexec, regerror, regfree \- regular-expression library
+.SH SYNOPSIS
+.ft B
+.\".na
+#include <sys/types.h>
+.br
+#include <regex.h>
+.HP 10
+int regcomp(regex_t\ *preg, const\ char\ *pattern, int\ cflags);
+.HP
+int\ regexec(const\ regex_t\ *preg, const\ char\ *string,
+size_t\ nmatch, regmatch_t\ pmatch[], int\ eflags);
+.HP
+size_t\ regerror(int\ errcode, const\ regex_t\ *preg,
+char\ *errbuf, size_t\ errbuf_size);
+.HP
+void\ regfree(regex_t\ *preg);
+.\".ad
+.ft
+.SH DESCRIPTION
+These routines implement POSIX 1003.2 regular expressions (``RE''s);
+see
+.ZR .
+.I Regcomp
+compiles an RE written as a string into an internal form,
+.I regexec
+matches that internal form against a string and reports results,
+.I regerror
+transforms error codes from either into human-readable messages,
+and
+.I regfree
+frees any dynamically-allocated storage used by the internal form
+of an RE.
+.PP
+The header
+.I <regex.h>
+declares two structure types,
+.I regex_t
+and
+.IR regmatch_t ,
+the former for compiled internal forms and the latter for match reporting.
+It also declares the four functions,
+a type
+.IR regoff_t ,
+and a number of constants with names starting with ``REG_''.
+.PP
+.I Regcomp
+compiles the regular expression contained in the
+.I pattern
+string,
+subject to the flags in
+.IR cflags ,
+and places the results in the
+.I regex_t
+structure pointed to by
+.IR preg .
+.I Cflags
+is the bitwise OR of zero or more of the following flags:
+.IP REG_EXTENDED \w'REG_EXTENDED'u+2n
+Compile modern (``extended'') REs,
+rather than the obsolete (``basic'') REs that
+are the default.
+.IP REG_BASIC
+This is a synonym for 0,
+provided as a counterpart to REG_EXTENDED to improve readability.
+.IP REG_NOSPEC
+Compile with recognition of all special characters turned off.
+All characters are thus considered ordinary,
+so the ``RE'' is a literal string.
+This is an extension,
+compatible with but not specified by POSIX 1003.2,
+and should be used with
+caution in software intended to be portable to other systems.
+REG_EXTENDED and REG_NOSPEC may not be used
+in the same call to
+.IR regcomp .
+.IP REG_ICASE
+Compile for matching that ignores upper/lower case distinctions.
+See
+.ZR .
+.IP REG_NOSUB
+Compile for matching that need only report success or failure,
+not what was matched.
+.IP REG_NEWLINE
+Compile for newline-sensitive matching.
+By default, newline is a completely ordinary character with no special
+meaning in either REs or strings.
+With this flag,
+`[^' bracket expressions and `.' never match newline,
+a `^' anchor matches the null string after any newline in the string
+in addition to its normal function,
+and the `$' anchor matches the null string before any newline in the
+string in addition to its normal function.
+.IP REG_PEND
+The regular expression ends,
+not at the first NUL,
+but just before the character pointed to by the
+.I re_endp
+member of the structure pointed to by
+.IR preg .
+The
+.I re_endp
+member is of type
+.IR const\ char\ * .
+This flag permits inclusion of NULs in the RE;
+they are considered ordinary characters.
+This is an extension,
+compatible with but not specified by POSIX 1003.2,
+and should be used with
+caution in software intended to be portable to other systems.
+.PP
+When successful,
+.I regcomp
+returns 0 and fills in the structure pointed to by
+.IR preg .
+One member of that structure
+(other than
+.IR re_endp )
+is publicized:
+.IR re_nsub ,
+of type
+.IR size_t ,
+contains the number of parenthesized subexpressions within the RE
+(except that the value of this member is undefined if the
+REG_NOSUB flag was used).
+If
+.I regcomp
+fails, it returns a non-zero error code;
+see DIAGNOSTICS.
+.PP
+.I Regexec
+matches the compiled RE pointed to by
+.I preg
+against the
+.IR string ,
+subject to the flags in
+.IR eflags ,
+and reports results using
+.IR nmatch ,
+.IR pmatch ,
+and the returned value.
+The RE must have been compiled by a previous invocation of
+.IR regcomp .
+The compiled form is not altered during execution of
+.IR regexec ,
+so a single compiled RE can be used simultaneously by multiple threads.
+.PP
+By default,
+the NUL-terminated string pointed to by
+.I string
+is considered to be the text of an entire line, minus any terminating
+newline.
+The
+.I eflags
+argument is the bitwise OR of zero or more of the following flags:
+.IP REG_NOTBOL \w'REG_STARTEND'u+2n
+The first character of
+the string
+is not the beginning of a line, so the `^' anchor should not match before it.
+This does not affect the behavior of newlines under REG_NEWLINE.
+.IP REG_NOTEOL
+The NUL terminating
+the string
+does not end a line, so the `$' anchor should not match before it.
+This does not affect the behavior of newlines under REG_NEWLINE.
+.IP REG_STARTEND
+The string is considered to start at
+\fIstring\fR\ + \fIpmatch\fR[0].\fIrm_so\fR
+and to have a terminating NUL located at
+\fIstring\fR\ + \fIpmatch\fR[0].\fIrm_eo\fR
+(there need not actually be a NUL at that location),
+regardless of the value of
+.IR nmatch .
+See below for the definition of
+.IR pmatch
+and
+.IR nmatch .
+This is an extension,
+compatible with but not specified by POSIX 1003.2,
+and should be used with
+caution in software intended to be portable to other systems.
+Note that a non-zero \fIrm_so\fR does not imply REG_NOTBOL;
+REG_STARTEND affects only the location of the string,
+not how it is matched.
+.PP
+See
+.ZR
+for a discussion of what is matched in situations where an RE or a
+portion thereof could match any of several substrings of
+.IR string .
+.PP
+Normally,
+.I regexec
+returns 0 for success and the non-zero code REG_NOMATCH for failure.
+Other non-zero error codes may be returned in exceptional situations;
+see DIAGNOSTICS.
+.PP
+If REG_NOSUB was specified in the compilation of the RE,
+or if
+.I nmatch
+is 0,
+.I regexec
+ignores the
+.I pmatch
+argument (but see below for the case where REG_STARTEND is specified).
+Otherwise,
+.I pmatch
+points to an array of
+.I nmatch
+structures of type
+.IR regmatch_t .
+Such a structure has at least the members
+.I rm_so
+and
+.IR rm_eo ,
+both of type
+.I regoff_t
+(a signed arithmetic type at least as large as an
+.I off_t
+and a
+.IR ssize_t ),
+containing respectively the offset of the first character of a substring
+and the offset of the first character after the end of the substring.
+Offsets are measured from the beginning of the
+.I string
+argument given to
+.IR regexec .
+An empty substring is denoted by equal offsets,
+both indicating the character following the empty substring.
+.PP
+The 0th member of the
+.I pmatch
+array is filled in to indicate what substring of
+.I string
+was matched by the entire RE.
+Remaining members report what substring was matched by parenthesized
+subexpressions within the RE;
+member
+.I i
+reports subexpression
+.IR i ,
+with subexpressions counted (starting at 1) by the order of their opening
+parentheses in the RE, left to right.
+Unused entries in the array\(emcorresponding either to subexpressions that
+did not participate in the match at all, or to subexpressions that do not
+exist in the RE (that is, \fIi\fR\ > \fIpreg\fR\->\fIre_nsub\fR)\(emhave both
+.I rm_so
+and
+.I rm_eo
+set to \-1.
+If a subexpression participated in the match several times,
+the reported substring is the last one it matched.
+(Note, as an example in particular, that when the RE `(b*)+' matches `bbb',
+the parenthesized subexpression matches each of the three `b's and then
+an infinite number of empty strings following the last `b',
+so the reported substring is one of the empties.)
+.PP
+If REG_STARTEND is specified,
+.I pmatch
+must point to at least one
+.I regmatch_t
+(even if
+.I nmatch
+is 0 or REG_NOSUB was specified),
+to hold the input offsets for REG_STARTEND.
+Use for output is still entirely controlled by
+.IR nmatch ;
+if
+.I nmatch
+is 0 or REG_NOSUB was specified,
+the value of
+.IR pmatch [0]
+will not be changed by a successful
+.IR regexec .
+.PP
+.I Regerror
+maps a non-zero
+.I errcode
+from either
+.I regcomp
+or
+.I regexec
+to a human-readable, printable message.
+If
+.I preg
+is non-NULL,
+the error code should have arisen from use of
+the
+.I regex_t
+pointed to by
+.IR preg ,
+and if the error code came from
+.IR regcomp ,
+it should have been the result from the most recent
+.I regcomp
+using that
+.IR regex_t .
+.RI ( Regerror
+may be able to supply a more detailed message using information
+from the
+.IR regex_t .)
+.I Regerror
+places the NUL-terminated message into the buffer pointed to by
+.IR errbuf ,
+limiting the length (including the NUL) to at most
+.I errbuf_size
+bytes.
+If the whole message won't fit,
+as much of it as will fit before the terminating NUL is supplied.
+In any case,
+the returned value is the size of buffer needed to hold the whole
+message (including terminating NUL).
+If
+.I errbuf_size
+is 0,
+.I errbuf
+is ignored but the return value is still correct.
+.PP
+If the
+.I errcode
+given to
+.I regerror
+is first ORed with REG_ITOA,
+the ``message'' that results is the printable name of the error code,
+e.g. ``REG_NOMATCH'',
+rather than an explanation thereof.
+If
+.I errcode
+is REG_ATOI,
+then
+.I preg
+shall be non-NULL and the
+.I re_endp
+member of the structure it points to
+must point to the printable name of an error code;
+in this case, the result in
+.I errbuf
+is the decimal digits of
+the numeric value of the error code
+(0 if the name is not recognized).
+REG_ITOA and REG_ATOI are intended primarily as debugging facilities;
+they are extensions,
+compatible with but not specified by POSIX 1003.2,
+and should be used with
+caution in software intended to be portable to other systems.
+Be warned also that they are considered experimental and changes are possible.
+.PP
+.I Regfree
+frees any dynamically-allocated storage associated with the compiled RE
+pointed to by
+.IR preg .
+The remaining
+.I regex_t
+is no longer a valid compiled RE
+and the effect of supplying it to
+.I regexec
+or
+.I regerror
+is undefined.
+.PP
+None of these functions references global variables except for tables
+of constants;
+all are safe for use from multiple threads if the arguments are safe.
+.SH IMPLEMENTATION CHOICES
+There are a number of decisions that 1003.2 leaves up to the implementor,
+either by explicitly saying ``undefined'' or by virtue of them being
+forbidden by the RE grammar.
+This implementation treats them as follows.
+.PP
+See
+.ZR
+for a discussion of the definition of case-independent matching.
+.PP
+There is no particular limit on the length of REs,
+except insofar as memory is limited.
+Memory usage is approximately linear in RE size, and largely insensitive
+to RE complexity, except for bounded repetitions.
+See BUGS for one short RE using them
+that will run almost any system out of memory.
+.PP
+A backslashed character other than one specifically given a magic meaning
+by 1003.2 (such magic meanings occur only in obsolete [``basic''] REs)
+is taken as an ordinary character.
+.PP
+Any unmatched [ is a REG_EBRACK error.
+.PP
+Equivalence classes cannot begin or end bracket-expression ranges.
+The endpoint of one range cannot begin another.
+.PP
+RE_DUP_MAX, the limit on repetition counts in bounded repetitions, is 255.
+.PP
+A repetition operator (?, *, +, or bounds) cannot follow another
+repetition operator.
+A repetition operator cannot begin an expression or subexpression
+or follow `^' or `|'.
+.PP
+`|' cannot appear first or last in a (sub)expression or after another `|',
+i.e. an operand of `|' cannot be an empty subexpression.
+An empty parenthesized subexpression, `()', is legal and matches an
+empty (sub)string.
+An empty string is not a legal RE.
+.PP
+A `{' followed by a digit is considered the beginning of bounds for a
+bounded repetition, which must then follow the syntax for bounds.
+A `{' \fInot\fR followed by a digit is considered an ordinary character.
+.PP
+`^' and `$' beginning and ending subexpressions in obsolete (``basic'')
+REs are anchors, not ordinary characters.
+.SH SEE ALSO
+grep(1), re_format(7)
+.PP
+POSIX 1003.2, sections 2.8 (Regular Expression Notation)
+and
+B.5 (C Binding for Regular Expression Matching).
+.SH DIAGNOSTICS
+Non-zero error codes from
+.I regcomp
+and
+.I regexec
+include the following:
+.PP
+.nf
+.ta \w'REG_ECOLLATE'u+3n
+REG_NOMATCH	regexec() failed to match
+REG_BADPAT	invalid regular expression
+REG_ECOLLATE	invalid collating element
+REG_ECTYPE	invalid character class
+REG_EESCAPE	\e applied to unescapable character
+REG_ESUBREG	invalid backreference number
+REG_EBRACK	brackets [ ] not balanced
+REG_EPAREN	parentheses ( ) not balanced
+REG_EBRACE	braces { } not balanced
+REG_BADBR	invalid repetition count(s) in { }
+REG_ERANGE	invalid character range in [ ]
+REG_ESPACE	ran out of memory
+REG_BADRPT	?, *, or + operand invalid
+REG_EMPTY	empty (sub)expression
+REG_ASSERT	``can't happen''\(emyou found a bug
+REG_INVARG	invalid argument, e.g. negative-length string
+.fi
+.SH HISTORY
+Originally written by Henry Spencer at University of Toronto.
+Altered for inclusion in the 4.4BSD distribution.
+.SH BUGS
+This is an alpha release with known defects.
+Please report problems.
+.PP
+There is one known functionality bug.
+The implementation of internationalization is incomplete:
+the locale is always assumed to be the default one of 1003.2,
+and only the collating elements etc. of that locale are available.
+.PP
+The back-reference code is subtle and doubts linger about its correctness
+in complex cases.
+.PP
+.I Regexec
+performance is poor.
+This will improve with later releases.
+.I Nmatch
+exceeding 0 is expensive;
+.I nmatch
+exceeding 1 is worse.
+.I Regexec
+is largely insensitive to RE complexity \fIexcept\fR that back
+references are massively expensive.
+RE length does matter; in particular, there is a strong speed bonus
+for keeping RE length under about 30 characters,
+with most special characters counting roughly double.
+.PP
+.I Regcomp
+implements bounded repetitions by macro expansion,
+which is costly in time and space if counts are large
+or bounded repetitions are nested.
+An RE like, say,
+`((((a{1,100}){1,100}){1,100}){1,100}){1,100}'
+will (eventually) run almost any existing machine out of swap space.
+.PP
+There are suspected problems with response to obscure error conditions.
+Notably,
+certain kinds of internal overflow,
+produced only by truly enormous REs or by multiply nested bounded repetitions,
+are probably not handled well.
+.PP
+Due to a mistake in 1003.2, things like `a)b' are legal REs because `)' is
+a special character only in the presence of a previous unmatched `('.
+This can't be fixed until the spec is fixed.
+.PP
+The standard's definition of back references is vague.
+For example, does
+`a\e(\e(b\e)*\e2\e)*d' match `abbbd'?
+Until the standard is clarified,
+behavior in such cases should not be relied on.
+.PP
+The implementation of word-boundary matching is a bit of a kludge,
+and bugs may lurk in combinations of word-boundary matching and anchoring.


Property changes on: trunk/contrib/nvi/regex/regex.3
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/contrib/nvi/regex/regex.h
===================================================================
--- trunk/contrib/nvi/regex/regex.h	                        (rev 0)
+++ trunk/contrib/nvi/regex/regex.h	2018-06-10 20:23:48 UTC (rev 10823)
@@ -0,0 +1,109 @@
+/*	$NetBSD: regex.h,v 1.1.1.2 2008/05/18 14:31:38 aymeric Exp $ */
+
+/*-
+ * Copyright (c) 1992 Henry Spencer.
+ * Copyright (c) 1992, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Henry Spencer of the University of Toronto.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)regex.h	8.1 (Berkeley) 6/2/93
+ */
+
+#ifndef _REGEX_H_
+#define	_REGEX_H_
+
+#ifdef __REGEX_PRIVATE
+#include "config.h"
+#include "../common/multibyte.h"
+#endif
+
+/* types */
+typedef off_t regoff_t;
+
+typedef struct {
+	int re_magic;
+	size_t re_nsub;		/* number of parenthesized subexpressions */
+	const RCHAR_T *re_endp;	/* end pointer for REG_PEND */
+	struct re_guts *re_g;	/* none of your business :-) */
+} regex_t;
+
+typedef struct {
+	regoff_t rm_so;		/* start of match */
+	regoff_t rm_eo;		/* end of match */
+} regmatch_t;
+
+/* regcomp() flags */
+#define	REG_BASIC	0000
+#define	REG_EXTENDED	0001
+#define	REG_ICASE	0002
+#define	REG_NOSUB	0004
+#define	REG_NEWLINE	0010
+#define	REG_NOSPEC	0020
+#define	REG_PEND	0040
+#define	REG_DUMP	0200
+
+/* regerror() flags */
+#define	REG_NOMATCH	 1
+#define	REG_BADPAT	 2
+#define	REG_ECOLLATE	 3
+#define	REG_ECTYPE	 4
+#define	REG_EESCAPE	 5
+#define	REG_ESUBREG	 6
+#define	REG_EBRACK	 7
+#define	REG_EPAREN	 8
+#define	REG_EBRACE	 9
+#define	REG_BADBR	10
+#define	REG_ERANGE	11
+#define	REG_ESPACE	12
+#define	REG_BADRPT	13
+#define	REG_EMPTY	14
+#define	REG_ASSERT	15
+#define	REG_INVARG	16
+#define	REG_ATOI	255	/* convert name to number (!) */
+#define	REG_ITOA	0400	/* convert number to name (!) */
+
+/* regexec() flags */
+#define	REG_NOTBOL	00001
+#define	REG_NOTEOL	00002
+#define	REG_STARTEND	00004
+#define	REG_TRACE	00400	/* tracing of execution */
+#define	REG_LARGE	01000	/* force large representation */
+#define	REG_BACKR	02000	/* force use of backref code */
+
+int	regcomp __P((regex_t *, const RCHAR_T *, int));
+size_t	regerror __P((int, const regex_t *, char *, size_t));
+int	regexec __P((const regex_t *,
+	    const RCHAR_T *, size_t, regmatch_t [], int));
+void	regfree __P((regex_t *));
+
+#endif /* !_REGEX_H_ */


Property changes on: trunk/contrib/nvi/regex/regex.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/contrib/nvi/regex/regex2.h
===================================================================
--- trunk/contrib/nvi/regex/regex2.h	                        (rev 0)
+++ trunk/contrib/nvi/regex/regex2.h	2018-06-10 20:23:48 UTC (rev 10823)
@@ -0,0 +1,174 @@
+/*	$NetBSD: regex2.h,v 1.5 2011/11/23 15:43:39 tnozaki Exp $ */
+
+/*-
+ * Copyright (c) 1992, 1993, 1994 Henry Spencer.
+ * Copyright (c) 1992, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Henry Spencer of the University of Toronto.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)regex2.h	8.3 (Berkeley) 3/16/94
+ */
+
+/*
+ * First, the stuff that ends up in the outside-world include file
+ = typedef off_t regoff_t;
+ = typedef struct {
+ = 	int re_magic;
+ = 	size_t re_nsub;		// number of parenthesized subexpressions
+ = 	const char *re_endp;	// end pointer for REG_PEND
+ = 	struct re_guts *re_g;	// none of your business :-)
+ = } regex_t;
+ = typedef struct {
+ = 	regoff_t rm_so;		// start of match
+ = 	regoff_t rm_eo;		// end of match
+ = } regmatch_t;
+ */
+/*
+ * internals of regex_t
+ */
+#define	MAGIC1	((('r'^0200)<<8) | 'e')
+
+/*
+ * The internal representation is a *strip*, a sequence of
+ * operators ending with an endmarker.  (Some terminology etc. is a
+ * historical relic of earlier versions which used multiple strips.)
+ * Certain oddities in the representation are there to permit running
+ * the machinery backwards; in particular, any deviation from sequential
+ * flow must be marked at both its source and its destination.  Some
+ * fine points:
+ *
+ * - OPLUS_ and O_PLUS are *inside* the loop they create.
+ * - OQUEST_ and O_QUEST are *outside* the bypass they create.
+ * - OCH_ and O_CH are *outside* the multi-way branch they create, while
+ *   OOR1 and OOR2 are respectively the end and the beginning of one of
+ *   the branches.  Note that there is an implicit OOR2 following OCH_
+ *   and an implicit OOR1 preceding O_CH.
+ *
+ * In state representations, an operator's bit is on to signify a state
+ * immediately *preceding* "execution" of that operator.
+ */
+typedef char sop;	/* strip operator */
+typedef size_t sopno;
+/* operators			   meaning	operand			*/
+/*						(back, fwd are offsets)	*/
+#define	OEND	(1)		/* endmarker	-			*/
+#define	OCHAR	(2)		/* character	unsigned char		*/
+#define	OBOL	(3)		/* left anchor	-			*/
+#define	OEOL	(4)		/* right anchor	-			*/
+#define	OANY	(5)		/* .		-			*/
+#define	OANYOF	(6)		/* [...]	set number		*/
+#define	OBACK_	(7)		/* begin \d	paren number		*/
+#define	O_BACK	(8)		/* end \d	paren number		*/
+#define	OPLUS_	(9)		/* + prefix	fwd to suffix		*/
+#define	O_PLUS	(10)		/* + suffix	back to prefix		*/
+#define	OQUEST_	(11)		/* ? prefix	fwd to suffix		*/
+#define	O_QUEST	(12)		/* ? suffix	back to prefix		*/
+#define	OLPAREN	(13)		/* (		fwd to )		*/
+#define	ORPAREN	(14)		/* )		back to (		*/
+#define	OCH_	(15)		/* begin choice	fwd to OOR2		*/
+#define	OOR1	(16)		/* | pt. 1	back to OOR1 or OCH_	*/
+#define	OOR2	(17)		/* | pt. 2	fwd to OOR2 or O_CH	*/
+#define	O_CH	(18)		/* end choice	back to OOR1		*/
+#define	OBOW	(19)		/* begin word	-			*/
+#define	OEOW	(20)		/* end word	-			*/
+
+/*
+ * Structure for [] character-set representation.  Character sets are
+ * done as bit vectors, grouped 8 to a byte vector for compactness.
+ * The individual set therefore has both a pointer to the byte vector
+ * and a mask to pick out the relevant bit of each byte.  A hash code
+ * simplifies testing whether two sets could be identical.
+ *
+ * This will get trickier for multicharacter collating elements.  As
+ * preliminary hooks for dealing with such things, we also carry along
+ * a string of multi-character elements, and decide the size of the
+ * vectors at run time.
+ */
+typedef struct {
+	uch *ptr;		/* -> uch [csetsize] */
+	uch mask;		/* bit within array */
+	uch hash;		/* hash code */
+	size_t smultis;
+	char *multis;		/* -> char[smulti]  ab\0cd\0ef\0\0 */
+} cset;
+/* note that CHadd and CHsub are unsafe, and CHIN doesn't yield 0/1 */
+#define	CHadd(cs, c)	((cs)->ptr[(uch)(c)] |= (cs)->mask, (cs)->hash += (c))
+#define	CHsub(cs, c)	((cs)->ptr[(uch)(c)] &= ~(cs)->mask, (cs)->hash -= (c))
+#define	CHIN(cs, c)	((cs)->ptr[(uch)(c)] & (cs)->mask)
+#define	MCadd(p, cs, cp)	mcadd(p, cs, cp)	/* regcomp() internal fns */
+#define	MCsub(p, cs, cp)	mcsub(p, cs, cp)
+#define	MCin(p, cs, cp)	mcin(p, cs, cp)
+
+/* stuff for character categories */
+typedef RCHAR_T cat_t;
+
+/*
+ * main compiled-expression structure
+ */
+struct re_guts {
+	int magic;
+#		define	MAGIC2	((('R'^0200)<<8)|'E')
+	sop *strip;		/* malloced area for strip */
+	RCHAR_T *stripdata;	/* malloced area for stripdata */
+	size_t csetsize;	/* number of bits in a cset vector */
+	size_t ncsets;		/* number of csets in use */
+	cset *sets;		/* -> cset [ncsets] */
+	uch *setbits;		/* -> uch[csetsize][ncsets/CHAR_BIT] */
+	int cflags;		/* copy of regcomp() cflags argument */
+	sopno nstates;		/* = number of sops */
+	sopno firststate;	/* the initial OEND (normally 0) */
+	sopno laststate;	/* the final OEND */
+	int iflags;		/* internal flags */
+#		define	USEBOL	01	/* used ^ */
+#		define	USEEOL	02	/* used $ */
+#		define	BAD	04	/* something wrong */
+	size_t nbol;		/* number of ^ used */
+	size_t neol;		/* number of $ used */
+#if 0
+	size_t ncategories;	/* how many character categories */
+	cat_t *categories;	/* ->catspace[-CHAR_MIN] */
+#endif
+	RCHAR_T *must;		/* match must contain this string */
+	size_t mlen;		/* length of must */
+	size_t nsub;		/* copy of re_nsub */
+	int backrefs;		/* does it use back references? */
+	sopno nplus;		/* how deep does it nest +s? */
+	/* catspace must be last */
+#if 0
+	cat_t catspace[1];	/* actually [NC] */
+#endif
+};
+
+/* misc utilities */
+#define OUT	REOF	/* a non-character value */
+#define	ISWORD(c) ((c) == '_' || (ISGRAPH((UCHAR_T)c) && !ISPUNCT((UCHAR_T)c)))


Property changes on: trunk/contrib/nvi/regex/regex2.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/contrib/nvi/regex/regexec.c
===================================================================
--- trunk/contrib/nvi/regex/regexec.c	                        (rev 0)
+++ trunk/contrib/nvi/regex/regexec.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -0,0 +1,180 @@
+/*	$NetBSD: regexec.c,v 1.4 2009/10/31 20:11:53 dsl Exp $ */
+
+/*-
+ * Copyright (c) 1992, 1993, 1994 Henry Spencer.
+ * Copyright (c) 1992, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Henry Spencer of the University of Toronto.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)regexec.c	8.2 (Berkeley) 3/16/94
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)regexec.c	8.2 (Berkeley) 3/16/94";
+#endif /* LIBC_SCCS and not lint */
+
+/*
+ * the outer shell of regexec()
+ *
+ * This file includes engine.c *twice*, after muchos fiddling with the
+ * macros that code uses.  This lets the same code operate on two different
+ * representations for state sets.
+ */
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <ctype.h>
+#include <regex.h>
+
+#include "utils.h"
+#include "regex2.h"
+
+#ifdef notdef
+static int nope = 0;		/* for use in asserts; shuts lint up */
+#endif
+
+/* macros for manipulating states, small version */
+#define	states	int
+#define	states1	int		/* for later use in regexec() decision */
+#define	CLEAR(v)	((v) = 0)
+#define	SET0(v, n)	((v) &= ~(1 << (n)))
+#define	SET1(v, n)	((v) |= 1 << (n))
+#define	ISSET(v, n)	((v) & (1 << (n)))
+#define	ASSIGN(d, s)	((d) = (s))
+#define	EQ(a, b)	((a) == (b))
+#define	STATEVARS	int dummy	/* dummy version */
+#define	STATESETUP(m, n)	/* nothing */
+#define	STATETEARDOWN(m)	/* nothing */
+#define	SETUP(v)	((v) = 0)
+#define	onestate	int
+#define	INIT(o, n)	((o) = (unsigned)1 << (n))
+#define	INC(o)	((o) <<= 1)
+#define	ISSTATEIN(v, o)	((v) & (o))
+/* some abbreviations; note that some of these know variable names! */
+/* do "if I'm here, I can also be there" etc without branches */
+#define	FWD(dst, src, n)	((dst) |= ((unsigned)(src)&(here)) << (n))
+#define	BACK(dst, src, n)	((dst) |= ((unsigned)(src)&(here)) >> (n))
+#define	ISSETBACK(v, n)	((v) & ((unsigned)here >> (n)))
+/* function names */
+#define SNAMES			/* engine.c looks after details */
+
+#include "engine.c"
+
+/* now undo things */
+#undef	states
+#undef	CLEAR
+#undef	SET0
+#undef	SET1
+#undef	ISSET
+#undef	ASSIGN
+#undef	EQ
+#undef	STATEVARS
+#undef	STATESETUP
+#undef	STATETEARDOWN
+#undef	SETUP
+#undef	onestate
+#undef	INIT
+#undef	INC
+#undef	ISSTATEIN
+#undef	FWD
+#undef	BACK
+#undef	ISSETBACK
+#undef	SNAMES
+
+/* macros for manipulating states, large version */
+#define	states	char *
+#define	CLEAR(v)	memset(v, 0, m->g->nstates)
+#define	SET0(v, n)	((v)[n] = 0)
+#define	SET1(v, n)	((v)[n] = 1)
+#define	ISSET(v, n)	((v)[n])
+#define	ASSIGN(d, s)	memcpy(d, s, m->g->nstates)
+#define	EQ(a, b)	(memcmp(a, b, m->g->nstates) == 0)
+#define	STATEVARS	int vn; char *space
+#define	STATESETUP(m, nv)	{ (m)->space = malloc((nv)*(m)->g->nstates); \
+				if ((m)->space == NULL) return(REG_ESPACE); \
+				(m)->vn = 0; }
+#define	STATETEARDOWN(m)	{ free((m)->space); }
+#define	SETUP(v)	((v) = &m->space[m->vn++ * m->g->nstates])
+#define	onestate	int
+#define	INIT(o, n)	((o) = (n))
+#define	INC(o)	((o)++)
+#define	ISSTATEIN(v, o)	((v)[o])
+/* some abbreviations; note that some of these know variable names! */
+/* do "if I'm here, I can also be there" etc without branches */
+#define	FWD(dst, src, n)	((dst)[here+(n)] |= (src)[here])
+#define	BACK(dst, src, n)	((dst)[here-(n)] |= (src)[here])
+#define	ISSETBACK(v, n)	((v)[here - (n)])
+/* function names */
+#define	LNAMES			/* flag */
+
+#include "engine.c"
+
+/*
+ - regexec - interface for matching
+ = extern int regexec(const regex_t *, const char *, size_t, \
+ =					regmatch_t [], int);
+ = #define	REG_NOTBOL	00001
+ = #define	REG_NOTEOL	00002
+ = #define	REG_STARTEND	00004
+ = #define	REG_TRACE	00400	// tracing of execution
+ = #define	REG_LARGE	01000	// force large representation
+ = #define	REG_BACKR	02000	// force use of backref code
+ *
+ * We put this here so we can exploit knowledge of the state representation
+ * when choosing which matcher to call.  Also, by this point the matchers
+ * have been prototyped.
+ */
+int				/* 0 success, REG_NOMATCH failure */
+regexec(const regex_t *preg, const RCHAR_T *string, size_t nmatch, regmatch_t *pmatch, int eflags)
+{
+	register struct re_guts *g = preg->re_g;
+#ifdef REDEBUG
+#	define	GOODFLAGS(f)	(f)
+#else
+#	define	GOODFLAGS(f)	((f)&(REG_NOTBOL|REG_NOTEOL|REG_STARTEND))
+#endif
+
+	if (preg->re_magic != MAGIC1 || g->magic != MAGIC2)
+		return(REG_BADPAT);
+	assert(!(g->iflags&BAD));
+	if (g->iflags&BAD)		/* backstop for no-debug case */
+		return(REG_BADPAT);
+	eflags = GOODFLAGS(eflags);
+
+	if (g->nstates <= (int)(CHAR_BIT*sizeof(states1)) && !(eflags&REG_LARGE))
+		return(smatcher(g, string, nmatch, pmatch, eflags));
+	else
+		return(lmatcher(g, string, nmatch, pmatch, eflags));
+}


Property changes on: trunk/contrib/nvi/regex/regexec.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/contrib/nvi/regex/regfree.c
===================================================================
--- trunk/contrib/nvi/regex/regfree.c	                        (rev 0)
+++ trunk/contrib/nvi/regex/regfree.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -0,0 +1,83 @@
+/*	$NetBSD: regfree.c,v 1.2 2009/01/02 00:32:11 tnozaki Exp $ */
+
+/*-
+ * Copyright (c) 1992, 1993, 1994 Henry Spencer.
+ * Copyright (c) 1992, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Henry Spencer of the University of Toronto.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)regfree.c	8.2 (Berkeley) 3/16/94
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)regfree.c	8.2 (Berkeley) 3/16/94";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <regex.h>
+
+#include "utils.h"
+#include "regex2.h"
+
+/*
+ - regfree - free everything
+ = extern void regfree(regex_t *);
+ */
+void
+regfree(regex_t *preg)
+{
+	register struct re_guts *g;
+
+	if (preg->re_magic != MAGIC1)	/* oops */
+		return;			/* nice to complain, but hard */
+
+	g = preg->re_g;
+	if (g == NULL || g->magic != MAGIC2)	/* oops again */
+		return;
+	preg->re_magic = 0;		/* mark it invalid */
+	g->magic = 0;			/* mark it invalid */
+
+	if (g->strip != NULL)
+		free((char *)g->strip);
+	if (g->stripdata != NULL)
+		free((char *)g->stripdata);
+	if (g->sets != NULL)
+		free((char *)g->sets);
+	if (g->setbits != NULL)
+		free((char *)g->setbits);
+	if (g->must != NULL)
+		free(g->must);
+	free((char *)g);
+}


Property changes on: trunk/contrib/nvi/regex/regfree.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/contrib/nvi/regex/utils.h
===================================================================
--- trunk/contrib/nvi/regex/utils.h	                        (rev 0)
+++ trunk/contrib/nvi/regex/utils.h	2018-06-10 20:23:48 UTC (rev 10823)
@@ -0,0 +1,59 @@
+/*	$NetBSD: utils.h,v 1.1.1.2 2008/05/18 14:31:39 aymeric Exp $ */
+
+/*-
+ * Copyright (c) 1992, 1993, 1994 Henry Spencer.
+ * Copyright (c) 1992, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Henry Spencer of the University of Toronto.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)utils.h	8.2 (Berkeley) 3/16/94
+ */
+
+/* utility definitions */
+#define	DUPMAX		_POSIX2_RE_DUP_MAX	/* xxx is this right? */
+#define	INFINITY	(DUPMAX + 1)
+#define	NC		(CHAR_MAX - CHAR_MIN + 1)
+typedef unsigned char uch;
+
+/* switch off assertions (if not already off) if no REDEBUG */
+#ifndef REDEBUG
+#ifndef NDEBUG
+#define	NDEBUG	/* no assertions please */
+#endif
+#endif
+#include <assert.h>
+
+/* for old systems with bcopy() but no memmove() */
+#ifdef USEBCOPY
+#define	memmove(d, s, c)	bcopy(s, d, c)
+#endif


Property changes on: trunk/contrib/nvi/regex/utils.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/contrib/nvi/vi/extern.h
===================================================================
--- trunk/contrib/nvi/vi/extern.h	                        (rev 0)
+++ trunk/contrib/nvi/vi/extern.h	2018-06-10 20:23:48 UTC (rev 10823)
@@ -0,0 +1,145 @@
+int cs_init __P((SCR *, VCS *));
+int cs_next __P((SCR *, VCS *));
+int cs_fspace __P((SCR *, VCS *));
+int cs_fblank __P((SCR *, VCS *));
+int cs_prev __P((SCR *, VCS *));
+int cs_bblank __P((SCR *, VCS *));
+int v_at __P((SCR *, VICMD *));
+int v_chrepeat __P((SCR *, VICMD *));
+int v_chrrepeat __P((SCR *, VICMD *));
+int v_cht __P((SCR *, VICMD *));
+int v_chf __P((SCR *, VICMD *));
+int v_chT __P((SCR *, VICMD *));
+int v_chF __P((SCR *, VICMD *));
+int v_delete __P((SCR *, VICMD *));
+int v_again __P((SCR *, VICMD *));
+int v_exmode __P((SCR *, VICMD *));
+int v_join __P((SCR *, VICMD *));
+int v_shiftl __P((SCR *, VICMD *));
+int v_shiftr __P((SCR *, VICMD *));
+int v_suspend __P((SCR *, VICMD *));
+int v_switch __P((SCR *, VICMD *));
+int v_tagpush __P((SCR *, VICMD *));
+int v_tagpop __P((SCR *, VICMD *));
+int v_filter __P((SCR *, VICMD *));
+int v_ex __P((SCR *, VICMD *));
+int v_ecl_exec __P((SCR *));
+int v_increment __P((SCR *, VICMD *));
+int v_screen_copy __P((SCR *, SCR *));
+int v_screen_end __P((SCR *));
+int v_optchange __P((SCR *, int, char *, u_long *));
+int v_iA __P((SCR *, VICMD *));
+int v_ia __P((SCR *, VICMD *));
+int v_iI __P((SCR *, VICMD *));
+int v_ii __P((SCR *, VICMD *));
+int v_iO __P((SCR *, VICMD *));
+int v_io __P((SCR *, VICMD *));
+int v_change __P((SCR *, VICMD *));
+int v_Replace __P((SCR *, VICMD *));
+int v_subst __P((SCR *, VICMD *));
+int v_left __P((SCR *, VICMD *));
+int v_cfirst __P((SCR *, VICMD *));
+int v_first __P((SCR *, VICMD *));
+int v_ncol __P((SCR *, VICMD *));
+int v_zero __P((SCR *, VICMD *));
+int v_mark __P((SCR *, VICMD *));
+int v_bmark __P((SCR *, VICMD *));
+int v_fmark __P((SCR *, VICMD *));
+int v_emark __P((SCR *, VICMD *));
+int v_match __P((SCR *, VICMD *));
+int v_buildmcs __P((SCR *, char *));
+int v_paragraphf __P((SCR *, VICMD *));
+int v_paragraphb __P((SCR *, VICMD *));
+int v_buildps __P((SCR *, char *, char *));
+int v_Put __P((SCR *, VICMD *));
+int v_put __P((SCR *, VICMD *));
+int v_redraw __P((SCR *, VICMD *));
+int v_replace __P((SCR *, VICMD *));
+int v_right __P((SCR *, VICMD *));
+int v_dollar __P((SCR *, VICMD *));
+int v_screen __P((SCR *, VICMD *));
+int v_lgoto __P((SCR *, VICMD *));
+int v_home __P((SCR *, VICMD *));
+int v_middle __P((SCR *, VICMD *));
+int v_bottom __P((SCR *, VICMD *));
+int v_up __P((SCR *, VICMD *));
+int v_cr __P((SCR *, VICMD *));
+int v_down __P((SCR *, VICMD *));
+int v_hpageup __P((SCR *, VICMD *));
+int v_hpagedown __P((SCR *, VICMD *));
+int v_pagedown __P((SCR *, VICMD *));
+int v_pageup __P((SCR *, VICMD *));
+int v_lineup __P((SCR *, VICMD *));
+int v_linedown __P((SCR *, VICMD *));
+int v_searchb __P((SCR *, VICMD *));
+int v_searchf __P((SCR *, VICMD *));
+int v_searchN __P((SCR *, VICMD *));
+int v_searchn __P((SCR *, VICMD *));
+int v_searchw __P((SCR *, VICMD *));
+int v_correct __P((SCR *, VICMD *, int));
+int v_sectionf __P((SCR *, VICMD *));
+int v_sectionb __P((SCR *, VICMD *));
+int v_sentencef __P((SCR *, VICMD *));
+int v_sentenceb __P((SCR *, VICMD *));
+int v_status __P((SCR *, VICMD *));
+int v_tcmd __P((SCR *, VICMD *, ARG_CHAR_T, u_int));
+int v_txt __P((SCR *, VICMD *, MARK *,
+   const CHAR_T *, size_t, ARG_CHAR_T, recno_t, u_long, u_int32_t));
+int v_txt_auto __P((SCR *, recno_t, TEXT *, size_t, TEXT *));
+int v_ulcase __P((SCR *, VICMD *));
+int v_mulcase __P((SCR *, VICMD *));
+int v_Undo __P((SCR *, VICMD *));
+int v_undo __P((SCR *, VICMD *));
+void v_eof __P((SCR *, MARK *));
+void v_eol __P((SCR *, MARK *));
+void v_nomove __P((SCR *));
+void v_sof __P((SCR *, MARK *));
+void v_sol __P((SCR *));
+int v_isempty __P((CHAR_T *, size_t));
+void v_emsg __P((SCR *, char *, vim_t));
+int v_wordW __P((SCR *, VICMD *));
+int v_wordw __P((SCR *, VICMD *));
+int v_wordE __P((SCR *, VICMD *));
+int v_worde __P((SCR *, VICMD *));
+int v_wordB __P((SCR *, VICMD *));
+int v_wordb __P((SCR *, VICMD *));
+int v_xchar __P((SCR *, VICMD *));
+int v_Xchar __P((SCR *, VICMD *));
+int v_yank __P((SCR *, VICMD *));
+int v_z __P((SCR *, VICMD *));
+int vs_crel __P((SCR *, long));
+int v_zexit __P((SCR *, VICMD *));
+int vi __P((SCR **));
+int v_curword __P((SCR *));
+int vs_line __P((SCR *, SMAP *, size_t *, size_t *));
+int vs_number __P((SCR *));
+void vs_busy __P((SCR *, const char *, busy_t));
+void vs_home __P((SCR *));
+void vs_update __P((SCR *, const char *, const CHAR_T *));
+void vs_msg __P((SCR *, mtype_t, char *, size_t));
+int vs_ex_resolve __P((SCR *, int *));
+int vs_resolve __P((SCR *, SCR *, int));
+int vs_repaint __P((SCR *, EVENT *));
+int vs_refresh __P((SCR *, int));
+int vs_column __P((SCR *, size_t *));
+size_t vs_screens __P((SCR *, recno_t, size_t *));
+size_t vs_columns __P((SCR *, CHAR_T *, recno_t, size_t *, size_t *));
+size_t vs_rcm __P((SCR *, recno_t, int));
+size_t vs_colpos __P((SCR *, recno_t, size_t));
+int vs_change __P((SCR *, recno_t, lnop_t));
+int vs_sm_fill __P((SCR *, recno_t, pos_t));
+int vs_sm_scroll __P((SCR *, MARK *, recno_t, scroll_t));
+int vs_sm_1up __P((SCR *));
+int vs_sm_1down __P((SCR *));
+int vs_sm_next __P((SCR *, SMAP *, SMAP *));
+int vs_sm_prev __P((SCR *, SMAP *, SMAP *));
+int vs_sm_cursor __P((SCR *, SMAP **));
+int vs_sm_position __P((SCR *, MARK *, u_long, pos_t));
+recno_t vs_sm_nlines __P((SCR *, SMAP *, recno_t, size_t));
+int vs_split __P((SCR *, SCR *, int));
+int vs_vsplit __P((SCR *, SCR *));
+int vs_discard __P((SCR *, SCR **));
+int vs_fg __P((SCR *, SCR **, CHAR_T *, int));
+int vs_bg __P((SCR *));
+int vs_swap __P((SCR *, SCR **, char *));
+int vs_resize __P((SCR *, long, adj_t));


Property changes on: trunk/contrib/nvi/vi/extern.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Modified: trunk/contrib/nvi/vi/getc.c
===================================================================
--- trunk/contrib/nvi/vi/getc.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/vi/getc.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -10,7 +10,7 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)getc.c	10.10 (Berkeley) 3/6/96";
+static const char sccsid[] = "$Id: getc.c,v 10.13 2011/12/27 00:49:31 zy Exp $";
 #endif /* not lint */
 
 #include <sys/types.h>
@@ -43,9 +43,7 @@
  * PUBLIC: int cs_init __P((SCR *, VCS *));
  */
 int
-cs_init(sp, csp)
-	SCR *sp;
-	VCS *csp;
+cs_init(SCR *sp, VCS *csp)
 {
 	int isempty;
 
@@ -71,11 +69,9 @@
  * PUBLIC: int cs_next __P((SCR *, VCS *));
  */
 int
-cs_next(sp, csp)
-	SCR *sp;
-	VCS *csp;
+cs_next(SCR *sp, VCS *csp)
 {
-	char *p;
+	CHAR_T *p;
 
 	switch (csp->cs_flags) {
 	case CS_EMP:				/* EMP; get next line. */
@@ -123,16 +119,14 @@
  * PUBLIC: int cs_fspace __P((SCR *, VCS *));
  */
 int
-cs_fspace(sp, csp)
-	SCR *sp;
-	VCS *csp;
+cs_fspace(SCR *sp, VCS *csp)
 {
-	if (csp->cs_flags != 0 || !isblank(csp->cs_ch))
+	if (csp->cs_flags != 0 || !ISBLANK(csp->cs_ch))
 		return (0);
 	for (;;) {
 		if (cs_next(sp, csp))
 			return (1);
-		if (csp->cs_flags != 0 || !isblank(csp->cs_ch))
+		if (csp->cs_flags != 0 || !ISBLANK(csp->cs_ch))
 			break;
 	}
 	return (0);
@@ -145,15 +139,13 @@
  * PUBLIC: int cs_fblank __P((SCR *, VCS *));
  */
 int
-cs_fblank(sp, csp)
-	SCR *sp;
-	VCS *csp;
+cs_fblank(SCR *sp, VCS *csp)
 {
 	for (;;) {
 		if (cs_next(sp, csp))
 			return (1);
 		if (csp->cs_flags == CS_EOL || csp->cs_flags == CS_EMP ||
-		    csp->cs_flags == 0 && isblank(csp->cs_ch))
+		    (csp->cs_flags == 0 && ISBLANK(csp->cs_ch)))
 			continue;
 		break;
 	}
@@ -167,9 +159,7 @@
  * PUBLIC: int cs_prev __P((SCR *, VCS *));
  */
 int
-cs_prev(sp, csp)
-	SCR *sp;
-	VCS *csp;
+cs_prev(SCR *sp, VCS *csp)
 {
 	switch (csp->cs_flags) {
 	case CS_EMP:				/* EMP; get previous line. */
@@ -218,15 +208,13 @@
  * PUBLIC: int cs_bblank __P((SCR *, VCS *));
  */
 int
-cs_bblank(sp, csp)
-	SCR *sp;
-	VCS *csp;
+cs_bblank(SCR *sp, VCS *csp)
 {
 	for (;;) {
 		if (cs_prev(sp, csp))
 			return (1);
 		if (csp->cs_flags == CS_EOL || csp->cs_flags == CS_EMP ||
-		    csp->cs_flags == 0 && isblank(csp->cs_ch))
+		    (csp->cs_flags == 0 && ISBLANK(csp->cs_ch)))
 			continue;
 		break;
 	}

Modified: trunk/contrib/nvi/vi/v_at.c
===================================================================
--- trunk/contrib/nvi/vi/v_at.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/vi/v_at.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -10,7 +10,7 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)v_at.c	10.8 (Berkeley) 4/27/96";
+static const char sccsid[] = "$Id: v_at.c,v 10.11 2001/06/25 15:19:30 skimo Exp $";
 #endif /* not lint */
 
 #include <sys/types.h>
@@ -21,6 +21,7 @@
 #include <ctype.h>
 #include <limits.h>
 #include <stdio.h>
+#include <string.h>
 
 #include "../common/common.h"
 #include "vi.h"
@@ -32,9 +33,7 @@
  * PUBLIC: int v_at __P((SCR *, VICMD *));
  */
 int
-v_at(sp, vp)
-	SCR *sp;
-	VICMD *vp;
+v_at(SCR *sp, VICMD *vp)
 {
 	CB *cbp;
 	CHAR_T name;
@@ -41,6 +40,9 @@
 	TEXT *tp;
 	size_t len;
 	char nbuf[20];
+	CHAR_T wbuf[20];
+	CHAR_T *wp;
+	size_t wlen;
 
 	/*
 	 * !!!
@@ -87,13 +89,13 @@
 	 * together.  We don't get this right; I'm waiting for the new DB
 	 * logging code to be available.
 	 */
-	for (tp = cbp->textq.cqh_last;
-	    tp != (void *)&cbp->textq; tp = tp->q.cqe_prev)
-		if ((F_ISSET(cbp, CB_LMODE) ||
-		    tp->q.cqe_next != (void *)&cbp->textq) &&
-		    v_event_push(sp, NULL, "\n", 1, 0) ||
+	TAILQ_FOREACH_REVERSE(tp, cbp->textq, _texth, q) {
+		if (((F_ISSET(cbp, CB_LMODE) ||
+		    TAILQ_NEXT(tp, q) != NULL) &&
+		    v_event_push(sp, NULL, L("\n"), 1, 0)) ||
 		    v_event_push(sp, NULL, tp->lb, tp->len, 0))
 			return (1);
+	}
 
 	/*
 	 * !!!
@@ -102,7 +104,9 @@
 	 */
 	if (F_ISSET(vp, VC_C1SET)) {
 		len = snprintf(nbuf, sizeof(nbuf), "%lu", vp->count);
-		if (v_event_push(sp, NULL, nbuf, len, 0))
+		CHAR2INT(sp, nbuf, len, wp, wlen);
+		MEMCPY(wbuf, wp, wlen);
+		if (v_event_push(sp, NULL, wp, wlen, 0))
 			return (1);
 	}
 	return (0);

Modified: trunk/contrib/nvi/vi/v_ch.c
===================================================================
--- trunk/contrib/nvi/vi/v_ch.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/vi/v_ch.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -10,7 +10,7 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)v_ch.c	10.8 (Berkeley) 3/6/96";
+static const char sccsid[] = "$Id: v_ch.c,v 10.11 2011/12/02 19:49:50 zy Exp $";
 #endif /* not lint */
 
 #include <sys/types.h>
@@ -35,9 +35,7 @@
  * PUBLIC: int v_chrepeat __P((SCR *, VICMD *));
  */
 int
-v_chrepeat(sp, vp)
-	SCR *sp;
-	VICMD *vp;
+v_chrepeat(SCR *sp, VICMD *vp)
 {
 	vp->character = VIP(sp)->lastckey;
 
@@ -66,9 +64,7 @@
  * PUBLIC: int v_chrrepeat __P((SCR *, VICMD *));
  */
 int
-v_chrrepeat(sp, vp)
-	SCR *sp;
-	VICMD *vp;
+v_chrrepeat(SCR *sp, VICMD *vp)
 {
 	cdir_t savedir;
 	int rval;
@@ -107,9 +103,7 @@
  * PUBLIC: int v_cht __P((SCR *, VICMD *));
  */
 int
-v_cht(sp, vp)
-	SCR *sp;
-	VICMD *vp;
+v_cht(SCR *sp, VICMD *vp)
 {
 	if (v_chf(sp, vp))
 		return (1);
@@ -140,14 +134,13 @@
  * PUBLIC: int v_chf __P((SCR *, VICMD *));
  */
 int
-v_chf(sp, vp)
-	SCR *sp;
-	VICMD *vp;
+v_chf(SCR *sp, VICMD *vp)
 {
 	size_t len;
 	u_long cnt;
-	int isempty, key;
-	char *endp, *p, *startp;
+	int isempty;
+	ARG_CHAR_T key;
+	CHAR_T *endp, *p, *startp;
 
 	/*
 	 * !!!
@@ -198,9 +191,7 @@
  * PUBLIC: int v_chT __P((SCR *, VICMD *));
  */
 int
-v_chT(sp, vp)
-	SCR *sp;
-	VICMD *vp;
+v_chT(SCR *sp, VICMD *vp)
 {
 	if (v_chF(sp, vp))
 		return (1);
@@ -225,14 +216,13 @@
  * PUBLIC: int v_chF __P((SCR *, VICMD *));
  */
 int
-v_chF(sp, vp)
-	SCR *sp;
-	VICMD *vp;
+v_chF(SCR *sp, VICMD *vp)
 {
 	size_t len;
 	u_long cnt;
-	int isempty, key;
-	char *endp, *p;
+	int isempty;
+	ARG_CHAR_T key;
+	CHAR_T *endp, *p;
 
 	/*
 	 * !!!
@@ -280,16 +270,13 @@
 }
 
 static void
-noprev(sp)
-	SCR *sp;
+noprev(SCR *sp)
 {
 	msgq(sp, M_BERR, "178|No previous F, f, T or t search");
 }
 
 static void
-notfound(sp, ch)
-	SCR *sp;
-	ARG_CHAR_T ch;
+notfound(SCR *sp, ARG_CHAR_T ch)
 {
 	msgq(sp, M_BERR, "179|%s not found", KEY_NAME(sp, ch));
 }

Modified: trunk/contrib/nvi/vi/v_cmd.c
===================================================================
--- trunk/contrib/nvi/vi/v_cmd.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/vi/v_cmd.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -10,7 +10,7 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)v_cmd.c	10.9 (Berkeley) 3/28/96";
+static const char sccsid[] = "$Id: v_cmd.c,v 10.9 1996/03/28 15:18:39 bostic Exp $";
 #endif /* not lint */
 
 #include <sys/types.h>

Modified: trunk/contrib/nvi/vi/v_delete.c
===================================================================
--- trunk/contrib/nvi/vi/v_delete.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/vi/v_delete.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -10,7 +10,7 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)v_delete.c	10.9 (Berkeley) 10/23/96";
+static const char sccsid[] = "$Id: v_delete.c,v 10.11 2001/06/25 15:19:31 skimo Exp $";
 #endif /* not lint */
 
 #include <sys/types.h>
@@ -32,9 +32,7 @@
  * PUBLIC: int v_delete __P((SCR *, VICMD *));
  */
 int
-v_delete(sp, vp)
-	SCR *sp;
-	VICMD *vp;
+v_delete(SCR *sp, VICMD *vp)
 {
 	recno_t nlines;
 	size_t len;

Modified: trunk/contrib/nvi/vi/v_ex.c
===================================================================
--- trunk/contrib/nvi/vi/v_ex.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/vi/v_ex.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -10,7 +10,7 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)v_ex.c	10.42 (Berkeley) 6/28/96";
+static const char sccsid[] = "$Id: v_ex.c,v 10.61 2011/12/22 18:41:53 zy Exp $";
 #endif /* not lint */
 
 #include <sys/types.h>
@@ -40,16 +40,12 @@
  * PUBLIC: int v_again __P((SCR *, VICMD *));
  */
 int
-v_again(sp, vp)
-	SCR *sp;
-	VICMD *vp;
+v_again(SCR *sp, VICMD *vp)
 {
-	ARGS *ap[2], a;
 	EXCMD cmd;
 
-	ex_cinit(&cmd, C_SUBAGAIN, 2, vp->m_start.lno, vp->m_start.lno, 1, ap);
-	ex_cadd(&cmd, &a, "", 1);
-
+	ex_cinit(sp, &cmd, C_SUBAGAIN, 2, vp->m_start.lno, vp->m_start.lno, 1);
+	argv_exp0(sp, &cmd, L(""), 1);
 	return (v_exec_ex(sp, vp, &cmd));
 }
 
@@ -60,9 +56,7 @@
  * PUBLIC: int v_exmode __P((SCR *, VICMD *));
  */
 int
-v_exmode(sp, vp)
-	SCR *sp;
-	VICMD *vp;
+v_exmode(SCR *sp, VICMD *vp)
 {
 	GS *gp;
 
@@ -98,9 +92,7 @@
  * PUBLIC: int v_join __P((SCR *, VICMD *));
  */
 int
-v_join(sp, vp)
-	SCR *sp;
-	VICMD *vp;
+v_join(SCR *sp, VICMD *vp)
 {
 	EXCMD cmd;
 	int lno;
@@ -118,7 +110,7 @@
 	if (F_ISSET(vp, VC_C1SET) && vp->count > 2)
 		lno = vp->m_start.lno + (vp->count - 1);
 
-	ex_cinit(&cmd, C_JOIN, 2, vp->m_start.lno, lno, 0, NULL);
+	ex_cinit(sp, &cmd, C_JOIN, 2, vp->m_start.lno, lno, 0);
 	return (v_exec_ex(sp, vp, &cmd));
 }
 
@@ -129,15 +121,12 @@
  * PUBLIC: int v_shiftl __P((SCR *, VICMD *));
  */
 int
-v_shiftl(sp, vp)
-	SCR *sp;
-	VICMD *vp;
+v_shiftl(SCR *sp, VICMD *vp)
 {
-	ARGS *ap[2], a;
 	EXCMD cmd;
 
-	ex_cinit(&cmd, C_SHIFTL, 2, vp->m_start.lno, vp->m_stop.lno, 0, ap);
-	ex_cadd(&cmd, &a, "<", 1);
+	ex_cinit(sp, &cmd, C_SHIFTL, 2, vp->m_start.lno, vp->m_stop.lno, 0);
+	argv_exp0(sp, &cmd, L("<"), 2);
 	return (v_exec_ex(sp, vp, &cmd));
 }
 
@@ -148,15 +137,12 @@
  * PUBLIC: int v_shiftr __P((SCR *, VICMD *));
  */
 int
-v_shiftr(sp, vp)
-	SCR *sp;
-	VICMD *vp;
+v_shiftr(SCR *sp, VICMD *vp)
 {
-	ARGS *ap[2], a;
 	EXCMD cmd;
 
-	ex_cinit(&cmd, C_SHIFTR, 2, vp->m_start.lno, vp->m_stop.lno, 0, ap);
-	ex_cadd(&cmd, &a, ">", 1);
+	ex_cinit(sp, &cmd, C_SHIFTR, 2, vp->m_start.lno, vp->m_stop.lno, 0);
+	argv_exp0(sp, &cmd, L(">"), 2);
 	return (v_exec_ex(sp, vp, &cmd));
 }
 
@@ -167,15 +153,12 @@
  * PUBLIC: int v_suspend __P((SCR *, VICMD *));
  */
 int
-v_suspend(sp, vp)
-	SCR *sp;
-	VICMD *vp;
+v_suspend(SCR *sp, VICMD *vp)
 {
-	ARGS *ap[2], a;
 	EXCMD cmd;
 
-	ex_cinit(&cmd, C_STOP, 0, OOBLNO, OOBLNO, 0, ap);
-	ex_cadd(&cmd, &a, "suspend", sizeof("suspend") - 1);
+	ex_cinit(sp, &cmd, C_STOP, 0, OOBLNO, OOBLNO, 0);
+	argv_exp0(sp, &cmd, L("suspend"), SIZE(L("suspend")));
 	return (v_exec_ex(sp, vp, &cmd));
 }
 
@@ -186,13 +169,12 @@
  * PUBLIC: int v_switch __P((SCR *, VICMD *));
  */
 int
-v_switch(sp, vp)
-	SCR *sp;
-	VICMD *vp;
+v_switch(SCR *sp, VICMD *vp)
 {
-	ARGS *ap[2], a;
 	EXCMD cmd;
 	char *name;
+	CHAR_T *wp;
+	size_t wlen;
 
 	/*
 	 * Try the alternate file name, then the previous file
@@ -207,8 +189,9 @@
 	if (file_m1(sp, 0, FS_ALL))
 		return (1);
 
-	ex_cinit(&cmd, C_EDIT, 0, OOBLNO, OOBLNO, 0, ap);
-	ex_cadd(&cmd, &a, name, strlen(name));
+	ex_cinit(sp, &cmd, C_EDIT, 0, OOBLNO, OOBLNO, 0);
+	CHAR2INT(sp, name, strlen(name) + 1, wp, wlen);
+	argv_exp0(sp, &cmd, wp, wlen);
 	return (v_exec_ex(sp, vp, &cmd));
 }
 
@@ -219,20 +202,12 @@
  * PUBLIC: int v_tagpush __P((SCR *, VICMD *));
  */
 int
-v_tagpush(sp, vp)
-	SCR *sp;
-	VICMD *vp;
+v_tagpush(SCR *sp, VICMD *vp)
 {
-	ARGS *ap[2], a;
 	EXCMD cmd;
 
-#ifdef GTAGS
-	if (O_ISSET(sp, O_GTAGSMODE) && vp->m_start.cno == 0)
-		ex_cinit(&cmd, C_RTAG, 0, OOBLNO, 0, 0, ap);
-	else
-#endif
-	ex_cinit(&cmd, C_TAG, 0, OOBLNO, 0, 0, ap);
-	ex_cadd(&cmd, &a, VIP(sp)->keyw, strlen(VIP(sp)->keyw));
+	ex_cinit(sp, &cmd, C_TAG, 0, OOBLNO, 0, 0);
+	argv_exp0(sp, &cmd, VIP(sp)->keyw, STRLEN(VIP(sp)->keyw) + 1);
 	return (v_exec_ex(sp, vp, &cmd));
 }
 
@@ -243,13 +218,11 @@
  * PUBLIC: int v_tagpop __P((SCR *, VICMD *));
  */
 int
-v_tagpop(sp, vp)
-	SCR *sp;
-	VICMD *vp;
+v_tagpop(SCR *sp, VICMD *vp)
 {
 	EXCMD cmd;
 
-	ex_cinit(&cmd, C_TAGPOP, 0, OOBLNO, 0, 0, NULL);
+	ex_cinit(sp, &cmd, C_TAGPOP, 0, OOBLNO, 0, 0);
 	return (v_exec_ex(sp, vp, &cmd));
 }
 
@@ -260,9 +233,7 @@
  * PUBLIC: int v_filter __P((SCR *, VICMD *));
  */
 int
-v_filter(sp, vp)
-	SCR *sp;
-	VICMD *vp;
+v_filter(SCR *sp, VICMD *vp)
 {
 	EXCMD cmd;
 	TEXT *tp;
@@ -288,11 +259,11 @@
 	 */
 	if (F_ISSET(vp, VC_ISDOT) ||
 	    ISCMD(vp->rkp, 'N') || ISCMD(vp->rkp, 'n')) {
-		ex_cinit(&cmd, C_BANG,
-		    2, vp->m_start.lno, vp->m_stop.lno, 0, NULL);
+		ex_cinit(sp,
+		    &cmd, C_BANG, 2, vp->m_start.lno, vp->m_stop.lno, 0);
 		EXP(sp)->argsoff = 0;			/* XXX */
 
-		if (argv_exp1(sp, &cmd, "!", 1, 1))
+		if (argv_exp1(sp, &cmd, L("!"), 1, 1))
 			return (1);
 		cmd.argc = EXP(sp)->argsoff;		/* XXX */
 		cmd.argv = EXP(sp)->args;		/* XXX */
@@ -311,7 +282,7 @@
 	 * Entering <escape> on an empty line was historically an error,
 	 * this implementation doesn't bother.
 	 */
-	tp = sp->tiq.cqh_first;
+	tp = TAILQ_FIRST(sp->tiq);
 	if (tp->term != TERM_OK) {
 		vp->m_final.lno = sp->lno;
 		vp->m_final.cno = sp->cno;
@@ -321,7 +292,7 @@
 	/* Home the cursor. */
 	vs_home(sp);
 
-	ex_cinit(&cmd, C_BANG, 2, vp->m_start.lno, vp->m_stop.lno, 0, NULL);
+	ex_cinit(sp, &cmd, C_BANG, 2, vp->m_start.lno, vp->m_stop.lno, 0);
 	EXP(sp)->argsoff = 0;			/* XXX */
 
 	if (argv_exp1(sp, &cmd, tp->lb + 1, tp->len - 1, 1))
@@ -332,40 +303,11 @@
 }
 
 /*
- * v_event_exec --
- *	Execute some command(s) based on an event.
- *
- * PUBLIC: int v_event_exec __P((SCR *, VICMD *));
- */
-int
-v_event_exec(sp, vp)
-	SCR *sp;
-	VICMD *vp;
-{
-	EXCMD cmd;
-
-	switch (vp->ev.e_event) {
-	case E_QUIT:
-		ex_cinit(&cmd, C_QUIT, 0, OOBLNO, OOBLNO, 0, NULL);
-		break;
-	case E_WRITE:
-		ex_cinit(&cmd, C_WRITE, 0, OOBLNO, OOBLNO, 0, NULL);
-		break;
-	default:
-		abort();
-	}
-	return (v_exec_ex(sp, vp, &cmd));
-}
-
-/*
  * v_exec_ex --
  *	Execute an ex command.
  */
 static int
-v_exec_ex(sp, vp, exp)
-	SCR *sp;
-	VICMD *vp;
-	EXCMD *exp;
+v_exec_ex(SCR *sp, VICMD *vp, EXCMD *exp)
 {
 	int rval;
 
@@ -380,9 +322,7 @@
  * PUBLIC: int v_ex __P((SCR *, VICMD *));
  */
 int
-v_ex(sp, vp)
-	SCR *sp;
-	VICMD *vp;
+v_ex(SCR *sp, VICMD *vp)
 {
 	GS *gp;
 	TEXT *tp;
@@ -410,7 +350,7 @@
 			if (v_tcmd(sp, vp, ':',
 			    TXT_BS | TXT_CEDIT | TXT_FILEC | TXT_PROMPT))
 				return (1);
-			tp = sp->tiq.cqh_first;
+			tp = TAILQ_FIRST(sp->tiq);
 
 			/*
 			 * If the user entered a single <esc>, they want to
@@ -510,9 +450,7 @@
  *	Cleanup from an ex command.
  */
 static int
-v_ex_done(sp, vp)
-	SCR *sp;
-	VICMD *vp;
+v_ex_done(SCR *sp, VICMD *vp)
 {
 	size_t len;
 
@@ -554,8 +492,7 @@
  *	Start an edit window on the colon command-line commands.
  */
 static int
-v_ecl(sp)
-	SCR *sp;
+v_ecl(SCR *sp)
 {
 	GS *gp;
 	SCR *new;
@@ -591,6 +528,11 @@
 	/* It's a special window. */
 	F_SET(new, SC_COMEDIT);
 
+#if defined(USE_WIDECHAR) && defined(USE_ICONV)
+	/* Bypass iconv on writing to DB. */
+	o_set(new, O_FILEENCODING, OS_STRDUP, codeset(), 0);
+#endif
+
 	/* Set up the switch. */
 	sp->nextdisp = new;
 	F_SET(sp, SC_SSWITCH);
@@ -604,11 +546,10 @@
  * PUBLIC: int v_ecl_exec __P((SCR *));
  */
 int
-v_ecl_exec(sp)
-	SCR *sp;
+v_ecl_exec(SCR *sp)
 {
 	size_t len;
-	char *p;
+	CHAR_T *p;
 
 	if (db_get(sp, sp->lno, 0, &p, &len) && sp->lno == 1) {
 		v_emsg(sp, NULL, VIM_EMPTY);
@@ -634,39 +575,43 @@
  *	Log a command into the colon command-line log file.
  */
 static int
-v_ecl_log(sp, tp)
-	SCR *sp;
-	TEXT *tp;
+v_ecl_log(SCR *sp, TEXT *tp)
 {
-	EXF *save_ep;
 	recno_t lno;
 	int rval;
+	CHAR_T *p;
+	size_t len;
+	SCR *ccl_sp;
 
 	/* Initialize the screen, if necessary. */
 	if (sp->gp->ccl_sp == NULL && v_ecl_init(sp))
 		return (1);
 
+	ccl_sp = sp->gp->ccl_sp;
+
 	/*
 	 * Don't log colon command window commands into the colon command
 	 * window...
 	 */
-	if (sp->ep == sp->gp->ccl_sp->ep)
+	if (sp->ep == ccl_sp->ep)
 		return (0);
 
-	/*
-	 * XXX
-	 * Swap the current EXF with the colon command file EXF.  This
-	 * isn't pretty, but too many routines "know" that sp->ep points
-	 * to the current EXF.
-	 */
-	save_ep = sp->ep;
-	sp->ep = sp->gp->ccl_sp->ep;
-	if (db_last(sp, &lno)) {
-		sp->ep = save_ep;
+	if (db_last(ccl_sp, &lno)) {
 		return (1);
 	}
-	rval = db_append(sp, 0, lno, tp->lb, tp->len);
-	sp->ep = save_ep;
+	/* Don't log line that is identical to previous one */
+	if (lno > 0 &&
+	    !db_get(ccl_sp, lno, 0, &p, &len) &&
+	    len == tp->len &&
+	    !MEMCMP(tp->lb, p, len))
+		rval = 0;
+	else {
+		rval = db_append(ccl_sp, 0, lno, tp->lb, tp->len);
+		/* XXXX end "transaction" on ccl */
+		/* Is this still necessary now that we no longer hijack sp ? */
+		log_cursor(ccl_sp);
+	}
+
 	return (rval);
 }
 
@@ -675,8 +620,7 @@
  *	Initialize the colon command-line log file.
  */
 static int
-v_ecl_init(sp)
-	SCR *sp;
+v_ecl_init(SCR *sp)
 {
 	FREF *frp;
 	GS *gp;
@@ -695,6 +639,7 @@
 		return (1);
 	if (file_init(gp->ccl_sp, frp, NULL, 0)) {
 		(void)screen_end(gp->ccl_sp);
+		gp->ccl_sp = NULL;
 		return (1);
 	}
 

Modified: trunk/contrib/nvi/vi/v_increment.c
===================================================================
--- trunk/contrib/nvi/vi/v_increment.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/vi/v_increment.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -10,7 +10,7 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)v_increment.c	10.12 (Berkeley) 3/19/96";
+static const char sccsid[] = "$Id: v_increment.c,v 10.17 2011/12/02 01:17:53 zy Exp $";
 #endif /* not lint */
 
 #include <sys/types.h>
@@ -28,17 +28,17 @@
 #include "../common/common.h"
 #include "vi.h"
 
-static char * const fmt[] = {
+static CHAR_T * const fmt[] = {
 #define	DEC	0
-	"%ld",
+	L("%ld"),
 #define	SDEC	1
-	"%+ld",
+	L("%+ld"),
 #define	HEXC	2
-	"0X%0*lX",
+	L("0X%0*lX"),
 #define	HEXL	3
-	"0x%0*lx",
+	L("0x%0*lx"),
 #define	OCTAL	4
-	"%#0*lo",
+	L("%#0*lo"),
 };
 
 static void inc_err __P((SCR *, enum nresult));
@@ -50,9 +50,7 @@
  * PUBLIC: int v_increment __P((SCR *, VICMD *));
  */
 int
-v_increment(sp, vp)
-	SCR *sp;
-	VICMD *vp;
+v_increment(SCR *sp, VICMD *vp)
 {
 	enum nresult nret;
 	u_long ulval;
@@ -59,7 +57,8 @@
 	long change, ltmp, lval;
 	size_t beg, blen, end, len, nlen, wlen;
 	int base, isempty, rval;
-	char *bp, *ntype, *p, *t, nbuf[100];
+	CHAR_T *ntype, nbuf[100];
+	CHAR_T *bp, *p, *t;
 
 	/* Validate the operator. */
 	if (vp->character == '#')
@@ -91,7 +90,7 @@
 	 * implies moving the cursor to its beginning, if we moved, refresh
 	 * now.
 	 */
-	for (beg = vp->m_start.cno; beg < len && isspace(p[beg]); ++beg);
+	for (beg = vp->m_start.cno; beg < len && ISSPACE(p[beg]); ++beg);
 	if (beg >= len)
 		goto nonum;
 	if (beg != vp->m_start.cno) {
@@ -100,9 +99,9 @@
 	}
 
 #undef	ishex
-#define	ishex(c)	(isdigit(c) || strchr("abcdefABCDEF", c))
+#define	ishex(c)	(ISXDIGIT(c))
 #undef	isoctal
-#define	isoctal(c)	(isdigit(c) && (c) != '8' && (c) != '9')
+#define	isoctal(c)	((c) >= '0' && (c) <= '7')
 
 	/*
 	 * Look for 0[Xx], or leading + or - signs, guess at the base.
@@ -175,9 +174,9 @@
 	 * buffer big enough to fit the line changes as well, and only
 	 * allocate once.
 	 */
-	GET_SPACE_RET(sp, bp, blen, len + 50);
+	GET_SPACE_RETW(sp, bp, blen, len + 50);
 	if (end == len) {
-		memmove(bp, &p[beg], wlen);
+		MEMMOVE(bp, &p[beg], wlen);
 		bp[wlen] = '\0';
 		t = bp;
 	} else
@@ -203,7 +202,7 @@
 		/* If we cross 0, signed numbers lose their sign. */
 		if (lval == 0 && ntype == fmt[SDEC])
 			ntype = fmt[DEC];
-		nlen = snprintf(nbuf, sizeof(nbuf), ntype, lval);
+		nlen = SPRINTF(nbuf, sizeof(nbuf), ntype, lval);
 	} else {
 		if ((nret = nget_uslong(&ulval, t, NULL, base)) != NUM_OK)
 			goto err;
@@ -225,13 +224,13 @@
 		if (base == 16)
 			wlen -= 2;
 
-		nlen = snprintf(nbuf, sizeof(nbuf), ntype, wlen, ulval);
+		nlen = SPRINTF(nbuf, sizeof(nbuf), ntype, wlen, ulval);
 	}
 
 	/* Build the new line. */
-	memmove(bp, p, beg);
-	memmove(bp + beg, nbuf, nlen);
-	memmove(bp + beg + nlen, p + end, len - beg - (end - beg));
+	MEMMOVE(bp, p, beg);
+	MEMMOVE(bp + beg, nbuf, nlen);
+	MEMMOVE(bp + beg + nlen, p + end, len - beg - (end - beg));
 	len = beg + nlen + (len - beg - (end - beg));
 
 	nret = NUM_OK;
@@ -242,14 +241,12 @@
 		inc_err(sp, nret);
 	}
 	if (bp != NULL)
-		FREE_SPACE(sp, bp, blen);
+		FREE_SPACEW(sp, bp, blen);
 	return (rval);
 }
 
 static void
-inc_err(sp, nret)
-	SCR *sp;
-	enum nresult nret;
+inc_err(SCR *sp, enum nresult nret)
 {
 	switch (nret) {
 	case NUM_ERR:

Modified: trunk/contrib/nvi/vi/v_init.c
===================================================================
--- trunk/contrib/nvi/vi/v_init.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/vi/v_init.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -10,7 +10,7 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)v_init.c	10.8 (Berkeley) 3/30/96";
+static const char sccsid[] = "$Id: v_init.c,v 10.10 2012/02/11 00:33:46 zy Exp $";
 #endif /* not lint */
 
 #include <sys/types.h>
@@ -34,8 +34,7 @@
  * PUBLIC: int v_screen_copy __P((SCR *, SCR *));
  */
 int
-v_screen_copy(orig, sp)
-	SCR *orig, *sp;
+v_screen_copy(SCR *orig, SCR *sp)
 {
 	VI_PRIVATE *ovip, *nvip;
 
@@ -58,6 +57,11 @@
 			nvip->rep_len = ovip->rep_len;
 		}
 
+		/* Copy the match characters information. */
+		if (ovip->mcs != NULL && (nvip->mcs =
+		    v_wstrdup(sp, ovip->mcs, STRLEN(ovip->mcs))) == NULL)
+			return (1);
+
 		/* Copy the paragraph/section information. */
 		if (ovip->ps != NULL && (nvip->ps =
 		    v_strdup(sp, ovip->ps, strlen(ovip->ps))) == NULL)
@@ -78,8 +82,7 @@
  * PUBLIC: int v_screen_end __P((SCR *));
  */
 int
-v_screen_end(sp)
-	SCR *sp;
+v_screen_end(SCR *sp)
 {
 	VI_PRIVATE *vip;
 
@@ -89,6 +92,8 @@
 		free(vip->keyw);
 	if (vip->rep != NULL)
 		free(vip->rep);
+	if (vip->mcs != NULL)
+		free(vip->mcs);
 	if (vip->ps != NULL)
 		free(vip->ps);
 
@@ -108,13 +113,11 @@
  * PUBLIC: int v_optchange __P((SCR *, int, char *, u_long *));
  */
 int
-v_optchange(sp, offset, str, valp)
-	SCR *sp;
-	int offset;
-	char *str;
-	u_long *valp;
+v_optchange(SCR *sp, int offset, char *str, u_long *valp)
 {
 	switch (offset) {
+	case O_MATCHCHARS:
+		return (v_buildmcs(sp, str));
 	case O_PARAGRAPHS:
 		return (v_buildps(sp, str, O_STR(sp, O_SECTIONS)));
 	case O_SECTIONS:

Modified: trunk/contrib/nvi/vi/v_itxt.c
===================================================================
--- trunk/contrib/nvi/vi/v_itxt.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/vi/v_itxt.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -10,7 +10,7 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)v_itxt.c	10.16 (Berkeley) 10/23/96";
+static const char sccsid[] = "$Id: v_itxt.c,v 10.21 2001/06/25 15:19:32 skimo Exp $";
 #endif /* not lint */
 
 #include <sys/types.h>
@@ -66,9 +66,7 @@
  * PUBLIC: int v_iA __P((SCR *, VICMD *));
  */
 int
-v_iA(sp, vp)
-	SCR *sp;
-	VICMD *vp;
+v_iA(SCR *sp, VICMD *vp)
 {
 	size_t len;
 
@@ -88,14 +86,12 @@
  * PUBLIC: int v_ia __P((SCR *, VICMD *));
  */
 int
-v_ia(sp, vp)
-	SCR *sp;
-	VICMD *vp;
+v_ia(SCR *sp, VICMD *vp)
 {
 	size_t len;
 	u_int32_t flags;
 	int isempty;
-	char *p;
+	CHAR_T *p;
 
 	flags = set_txt_std(sp, vp, 0);
 	sp->showmode = SM_APPEND;
@@ -127,9 +123,7 @@
  * PUBLIC: int v_iI __P((SCR *, VICMD *));
  */
 int
-v_iI(sp, vp)
-	SCR *sp;
-	VICMD *vp;
+v_iI(SCR *sp, VICMD *vp)
 {
 	sp->cno = 0;
 	if (nonblank(sp, vp->m_start.lno, &sp->cno))
@@ -148,14 +142,12 @@
  * PUBLIC: int v_ii __P((SCR *, VICMD *));
  */
 int
-v_ii(sp, vp)
-	SCR *sp;
-	VICMD *vp;
+v_ii(SCR *sp, VICMD *vp)
 {
 	size_t len;
 	u_int32_t flags;
 	int isempty;
-	char *p;
+	CHAR_T *p;
 
 	flags = set_txt_std(sp, vp, 0);
 	sp->showmode = SM_INSERT;
@@ -183,9 +175,7 @@
  * PUBLIC: int v_iO __P((SCR *, VICMD *));
  */
 int
-v_iO(sp, vp)
-	SCR *sp;
-	VICMD *vp;
+v_iO(SCR *sp, VICMD *vp)
 {
 	return (io(sp, vp, O_cmd));
 }
@@ -197,23 +187,18 @@
  * PUBLIC: int v_io __P((SCR *, VICMD *));
  */
 int
-v_io(sp, vp)
-	SCR *sp;
-	VICMD *vp;
+v_io(SCR *sp, VICMD *vp)
 {
 	return (io(sp, vp, o_cmd));
 }
 
 static int
-io(sp, vp, cmd)
-	SCR *sp;
-	VICMD *vp;
-	enum which cmd;
+io(SCR *sp, VICMD *vp, enum which cmd)
 {
 	recno_t ai_line, lno;
 	size_t len;
 	u_int32_t flags;
-	char *p;
+	CHAR_T *p;
 
 	flags = set_txt_std(sp, vp, TXT_ADDNEWLINE | TXT_APPENDEOL);
 	sp->showmode = SM_INSERT;
@@ -227,7 +212,7 @@
 		len = 0;
 		ai_line = OOBLNO;
 	} else {
-insert:		p = "";
+insert:		p = L("");
 		sp->cno = 0;
 		LOG_CORRECT;
 
@@ -258,14 +243,13 @@
  * PUBLIC: int v_change __P((SCR *, VICMD *));
  */
 int
-v_change(sp, vp)
-	SCR *sp;
-	VICMD *vp;
+v_change(SCR *sp, VICMD *vp)
 {
 	size_t blen, len;
 	u_int32_t flags;
 	int isempty, lmode, rval;
-	char *bp, *p;
+	CHAR_T *bp;
+	CHAR_T *p;
 
 	/*
 	 * 'c' can be combined with motion commands that set the resulting
@@ -356,8 +340,8 @@
 		 */
 		if (db_get(sp, vp->m_start.lno, DBG_FATAL, &p, &len))
 			return (1);
-		GET_SPACE_RET(sp, bp, blen, vp->m_start.cno);
-		memmove(bp, p, vp->m_start.cno);
+		GET_SPACE_RETW(sp, bp, blen, vp->m_start.cno);
+		MEMMOVE(bp, p, vp->m_start.cno);
 	} else
 		bp = NULL;
 
@@ -388,7 +372,7 @@
 	    0, OOBLNO, F_ISSET(vp, VC_C1SET) ? vp->count : 1, flags);
 
 	if (bp != NULL)
-		FREE_SPACE(sp, bp, blen);
+		FREE_SPACEW(sp, bp, blen);
 	return (rval);
 }
 
@@ -399,14 +383,12 @@
  * PUBLIC: int v_Replace __P((SCR *, VICMD *));
  */
 int
-v_Replace(sp, vp)
-	SCR *sp;
-	VICMD *vp;
+v_Replace(SCR *sp, VICMD *vp)
 {
 	size_t len;
 	u_int32_t flags;
 	int isempty;
-	char *p;
+	CHAR_T *p;
 
 	flags = set_txt_std(sp, vp, 0);
 	sp->showmode = SM_REPLACE;
@@ -435,14 +417,12 @@
  * PUBLIC: int v_subst __P((SCR *, VICMD *));
  */
 int
-v_subst(sp, vp)
-	SCR *sp;
-	VICMD *vp;
+v_subst(SCR *sp, VICMD *vp)
 {
 	size_t len;
 	u_int32_t flags;
 	int isempty;
-	char *p;
+	CHAR_T *p;
 
 	flags = set_txt_std(sp, vp, 0);
 	sp->showmode = SM_CHANGE;
@@ -477,10 +457,7 @@
  *	Initialize text processing flags.
  */
 static u_int32_t
-set_txt_std(sp, vp, flags)
-	SCR *sp;
-	VICMD *vp;
-	u_int32_t flags;
+set_txt_std(SCR *sp, VICMD *vp, u_int32_t flags)
 {
 	LF_SET(TXT_CNTRLT |
 	    TXT_ESCAPE | TXT_MAPINPUT | TXT_RECORD | TXT_RESOLVE);

Modified: trunk/contrib/nvi/vi/v_left.c
===================================================================
--- trunk/contrib/nvi/vi/v_left.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/vi/v_left.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -10,7 +10,7 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)v_left.c	10.7 (Berkeley) 3/6/96";
+static const char sccsid[] = "$Id: v_left.c,v 10.9 2001/06/25 15:19:32 skimo Exp $";
 #endif /* not lint */
 
 #include <sys/types.h>
@@ -31,9 +31,7 @@
  * PUBLIC: int v_left __P((SCR *, VICMD *));
  */
 int
-v_left(sp, vp)
-	SCR *sp;
-	VICMD *vp;
+v_left(SCR *sp, VICMD *vp)
 {
 	recno_t cnt;
 
@@ -71,9 +69,7 @@
  * PUBLIC: int v_cfirst __P((SCR *, VICMD *));
  */
 int
-v_cfirst(sp, vp)
-	SCR *sp;
-	VICMD *vp;
+v_cfirst(SCR *sp, VICMD *vp)
 {
 	recno_t cnt, lno;
 
@@ -140,9 +136,7 @@
  * PUBLIC: int v_first __P((SCR *, VICMD *));
  */
 int
-v_first(sp, vp)
-	SCR *sp;
-	VICMD *vp;
+v_first(SCR *sp, VICMD *vp)
 {
 	/*
 	 * !!!
@@ -204,9 +198,7 @@
  * PUBLIC: int v_ncol __P((SCR *, VICMD *));
  */
 int
-v_ncol(sp, vp)
-	SCR *sp;
-	VICMD *vp;
+v_ncol(SCR *sp, VICMD *vp)
 {
 	if (F_ISSET(vp, VC_C1SET) && vp->count > 1) {
 		--vp->count;
@@ -266,9 +258,7 @@
  * PUBLIC: int v_zero __P((SCR *, VICMD *));
  */
 int
-v_zero(sp, vp)
-	SCR *sp;
-	VICMD *vp;
+v_zero(SCR *sp, VICMD *vp)
 {
 	/*
 	 * !!!

Modified: trunk/contrib/nvi/vi/v_mark.c
===================================================================
--- trunk/contrib/nvi/vi/v_mark.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/vi/v_mark.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -10,7 +10,7 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)v_mark.c	10.8 (Berkeley) 9/20/96";
+static const char sccsid[] = "$Id: v_mark.c,v 10.12 2001/06/25 15:19:32 skimo Exp $";
 #endif /* not lint */
 
 #include <sys/types.h>
@@ -25,6 +25,9 @@
 #include "../common/common.h"
 #include "vi.h"
 
+enum which {BQMARK, FQMARK};
+static int mark __P((SCR *, VICMD *, int, enum which));
+
 /*
  * v_mark -- m[a-z]
  *	Set a mark.
@@ -32,17 +35,11 @@
  * PUBLIC: int v_mark __P((SCR *, VICMD *));
  */
 int
-v_mark(sp, vp)
-	SCR *sp;
-	VICMD *vp;
+v_mark(SCR *sp, VICMD *vp)
 {
 	return (mark_set(sp, vp->character, &vp->m_start, 1));
 }
 
-enum which {BQMARK, FQMARK};
-static int mark __P((SCR *, VICMD *, enum which));
-
-
 /*
  * v_bmark -- `['`a-z]
  *	Move to a mark.
@@ -59,11 +56,9 @@
  * PUBLIC: int v_bmark __P((SCR *, VICMD *));
  */
 int
-v_bmark(sp, vp)
-	SCR *sp;
-	VICMD *vp;
+v_bmark(SCR *sp, VICMD *vp)
 {
-	return (mark(sp, vp, BQMARK));
+	return (mark(sp, vp, 1, BQMARK));
 }
 
 /*
@@ -75,28 +70,45 @@
  * PUBLIC: int v_fmark __P((SCR *, VICMD *));
  */
 int
-v_fmark(sp, vp)
-	SCR *sp;
-	VICMD *vp;
+v_fmark(SCR *sp, VICMD *vp)
 {
-	return (mark(sp, vp, FQMARK));
+	return (mark(sp, vp, 1, FQMARK));
 }
 
 /*
+ * v_emark -- <mouse click>
+ *	Mouse mark.
+ *
+ * PUBLIC: int v_emark __P((SCR *, VICMD *));
+ */
+int
+v_emark(SCR *sp, VICMD *vp)
+{
+	SMAP *smp;
+
+	smp = HMAP + vp->ev.e_lno;
+	if (smp > TMAP) {
+		msgq(sp, M_BERR, "320|Unknown cursor position.");
+		return (1);
+	}
+	vp->m_stop.lno = smp->lno;
+	vp->m_stop.cno =
+	    vs_colpos(sp, smp->lno, vp->ev.e_cno + (smp->soff - 1) * sp->cols);
+	return (mark(sp, vp, 0, BQMARK));
+}
+
+/*
  * mark --
  *	Mark commands.
  */
 static int
-mark(sp, vp, cmd)
-	SCR *sp;
-	VICMD *vp;
-	enum which cmd;
+mark(SCR *sp, VICMD *vp, int getmark, enum which cmd)
 {
 	dir_t dir;
 	MARK m;
 	size_t len;
 
-	if (mark_get(sp, vp->character, &vp->m_stop, M_BERR))
+	if (getmark && mark_get(sp, vp->character, &vp->m_stop, M_BERR))
 		return (1);
 
 	/*
@@ -111,7 +123,7 @@
 		if (db_get(sp, vp->m_stop.lno, DBG_FATAL, NULL, &len))
 			return (1);
 		if (vp->m_stop.cno < len ||
-		    vp->m_stop.cno == len && len == 0)
+		    (vp->m_stop.cno == len && len == 0))
 			break;
 
 		if (ISMOTION(vp))
@@ -152,8 +164,8 @@
 	 * and backward motions can happen for any kind of search command.
 	 */
 	if (vp->m_start.lno > vp->m_stop.lno ||
-	    vp->m_start.lno == vp->m_stop.lno &&
-	    vp->m_start.cno > vp->m_stop.cno) {
+	    (vp->m_start.lno == vp->m_stop.lno &&
+	    vp->m_start.cno > vp->m_stop.cno)) {
 		m = vp->m_start;
 		vp->m_start = vp->m_stop;
 		vp->m_stop = m;
@@ -187,15 +199,15 @@
 #ifdef HISTORICAL_PRACTICE
 	if (ISCMD(vp->rkp, 'y')) {
 		if ((cmd == BQMARK ||
-		    cmd == FQMARK && vp->m_start.lno != vp->m_stop.lno) &&
+		    (cmd == FQMARK && vp->m_start.lno != vp->m_stop.lno)) &&
 		    (vp->m_start.lno > vp->m_stop.lno ||
-		    vp->m_start.lno == vp->m_stop.lno &&
-		    vp->m_start.cno > vp->m_stop.cno))
+		    (vp->m_start.lno == vp->m_stop.lno &&
+		    vp->m_start.cno > vp->m_stop.cno)))
 			vp->m_final = vp->m_stop;
 	} else if (ISCMD(vp->rkp, 'd'))
 		if (vp->m_start.lno > vp->m_stop.lno ||
-		    vp->m_start.lno == vp->m_stop.lno &&
-		    vp->m_start.cno > vp->m_stop.cno)
+		    (vp->m_start.lno == vp->m_stop.lno &&
+		    vp->m_start.cno > vp->m_stop.cno))
 			vp->m_final = vp->m_stop;
 #else
 	vp->m_final = vp->m_start;

Modified: trunk/contrib/nvi/vi/v_match.c
===================================================================
--- trunk/contrib/nvi/vi/v_match.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/vi/v_match.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -10,7 +10,7 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)v_match.c	10.8 (Berkeley) 3/6/96";
+static const char sccsid[] = "$Id: v_match.c,v 10.11 2012/02/11 00:33:46 zy Exp $";
 #endif /* not lint */
 
 #include <sys/types.h>
@@ -18,8 +18,10 @@
 #include <sys/time.h>
 
 #include <bitstring.h>
+#include <ctype.h>
 #include <limits.h>
 #include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
 
 #include "../common/common.h"
@@ -32,17 +34,25 @@
  * PUBLIC: int v_match __P((SCR *, VICMD *));
  */
 int
-v_match(sp, vp)
-	SCR *sp;
-	VICMD *vp;
+v_match(SCR *sp, VICMD *vp)
 {
 	VCS cs;
 	MARK *mp;
 	size_t cno, len, off;
 	int cnt, isempty, matchc, startc, (*gc)__P((SCR *, VCS *));
-	char *p;
+	CHAR_T *p;
+	CHAR_T *cp;
+	const CHAR_T *match_chars;
 
 	/*
+	 * Historically vi would match (), {} and [] however
+	 * an update included <>.  This is ok for editing HTML
+	 * but a pain in the butt for C source.
+	 * Making it an option lets the user decide what is 'right'.
+	 */
+	match_chars = VIP(sp)->mcs;
+
+	/*
 	 * !!!
 	 * Historic practice; ignore the count.
 	 *
@@ -60,43 +70,14 @@
 nomatch:		msgq(sp, M_BERR, "184|No match character on this line");
 			return (1);
 		}
-		switch (startc = p[off]) {
-		case '(':
-			matchc = ')';
-			gc = cs_next;
+		startc = p[off];
+		cp = STRCHR(match_chars, startc);
+		if (cp != NULL) {
+			cnt = cp - match_chars;
+			matchc = match_chars[cnt ^ 1];
+			gc = cnt & 1 ? cs_prev : cs_next;
 			break;
-		case ')':
-			matchc = '(';
-			gc = cs_prev;
-			break;
-		case '[':
-			matchc = ']';
-			gc = cs_next;
-			break;
-		case ']':
-			matchc = '[';
-			gc = cs_prev;
-			break;
-		case '{':
-			matchc = '}';
-			gc = cs_next;
-			break;
-		case '}':
-			matchc = '{';
-			gc = cs_prev;
-			break;
-		case '<':
-			matchc = '>';
-			gc = cs_next;
-			break;
-		case '>':
-			matchc = '<';
-			gc = cs_prev;
-			break;
-		default:
-			continue;
 		}
-		break;
 	}
 
 	cs.cs_lno = vp->m_start.lno;
@@ -135,8 +116,8 @@
 	 * starting cursor position when deleting to a match.
 	 */
 	if (vp->m_start.lno < vp->m_stop.lno ||
-	    vp->m_start.lno == vp->m_stop.lno &&
-	    vp->m_start.cno < vp->m_stop.cno)
+	    (vp->m_start.lno == vp->m_stop.lno &&
+	    vp->m_start.cno < vp->m_stop.cno))
 		vp->m_final = ISMOTION(vp) ? vp->m_start : vp->m_stop;
 	else
 		vp->m_final = vp->m_stop;
@@ -168,3 +149,29 @@
 	F_SET(vp, VM_LMODE);
 	return (0);
 }
+
+/*
+ * v_buildmcs --
+ *	Build the match character list.
+ *
+ * PUBLIC: int v_buildmcs __P((SCR *, char *));
+ */
+int
+v_buildmcs(SCR *sp, char *str)
+{
+	CHAR_T **mp = &VIP(sp)->mcs;
+	size_t len = strlen(str) + 1;
+
+	if (*mp != NULL)
+		free(*mp);
+	MALLOC(sp, *mp, CHAR_T *, len * sizeof(CHAR_T));
+	if (*mp == NULL)
+		return (1);
+#ifdef USE_WIDECHAR
+	if (mbstowcs(*mp, str, len) == (size_t)-1)
+		return (1);
+#else
+	memcpy(*mp, str, len);
+#endif
+	return (0);
+}

Modified: trunk/contrib/nvi/vi/v_paragraph.c
===================================================================
--- trunk/contrib/nvi/vi/v_paragraph.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/vi/v_paragraph.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -10,7 +10,7 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)v_paragraph.c	10.7 (Berkeley) 3/6/96";
+static const char sccsid[] = "$Id: v_paragraph.c,v 10.10 2001/06/25 15:19:32 skimo Exp $";
 #endif /* not lint */
 
 #include <sys/types.h>
@@ -64,15 +64,14 @@
  * PUBLIC: int v_paragraphf __P((SCR *, VICMD *));
  */
 int
-v_paragraphf(sp, vp)
-	SCR *sp;
-	VICMD *vp;
+v_paragraphf(SCR *sp, VICMD *vp)
 {
 	enum { P_INTEXT, P_INBLANK } pstate;
 	size_t lastlen, len;
 	recno_t cnt, lastlno, lno;
 	int isempty;
-	char *p, *lp;
+	CHAR_T *p;
+	char *lp;
 
 	/*
 	 * !!!
@@ -203,14 +202,13 @@
  * PUBLIC: int v_paragraphb __P((SCR *, VICMD *));
  */
 int
-v_paragraphb(sp, vp)
-	SCR *sp;
-	VICMD *vp;
+v_paragraphb(SCR *sp, VICMD *vp)
 {
 	enum { P_INTEXT, P_INBLANK } pstate;
 	size_t len;
 	recno_t cnt, lno;
-	char *p, *lp;
+	CHAR_T *p;
+	char *lp;
 
 	/*
 	 * !!!
@@ -311,9 +309,7 @@
  * PUBLIC: int v_buildps __P((SCR *, char *, char *));
  */
 int
-v_buildps(sp, p_p, s_p)
-	SCR *sp;
-	char *p_p, *s_p;
+v_buildps(SCR *sp, char *p_p, char *s_p)
 {
 	VI_PRIVATE *vip;
 	size_t p_len, s_len;

Modified: trunk/contrib/nvi/vi/v_put.c
===================================================================
--- trunk/contrib/nvi/vi/v_put.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/vi/v_put.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -10,7 +10,7 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)v_put.c	10.5 (Berkeley) 3/6/96";
+static const char sccsid[] = "$Id: v_put.c,v 10.6 2001/06/25 15:19:34 skimo Exp $";
 #endif /* not lint */
 
 #include <sys/types.h>
@@ -33,9 +33,7 @@
  * PUBLIC: int v_Put __P((SCR *, VICMD *));
  */
 int
-v_Put(sp, vp)
-	SCR *sp;
-	VICMD *vp;
+v_Put(SCR *sp, VICMD *vp)
 {
 	u_long cnt;
 
@@ -66,9 +64,7 @@
  * PUBLIC: int v_put __P((SCR *, VICMD *));
  */
 int
-v_put(sp, vp)
-	SCR *sp;
-	VICMD *vp;
+v_put(SCR *sp, VICMD *vp)
 {
 	u_long cnt;
 
@@ -108,9 +104,7 @@
  * the buffer increment gets done regardless of the success of the put.
  */
 static void
-inc_buf(sp, vp)
-	SCR *sp;
-	VICMD *vp;
+inc_buf(SCR *sp, VICMD *vp)
 {
 	CHAR_T v;
 

Modified: trunk/contrib/nvi/vi/v_redraw.c
===================================================================
--- trunk/contrib/nvi/vi/v_redraw.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/vi/v_redraw.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -10,7 +10,7 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)v_redraw.c	10.6 (Berkeley) 3/6/96";
+static const char sccsid[] = "$Id: v_redraw.c,v 10.7 2001/06/25 15:19:34 skimo Exp $";
 #endif /* not lint */
 
 #include <sys/types.h>
@@ -31,9 +31,7 @@
  * PUBLIC: int v_redraw __P((SCR *, VICMD *));
  */
 int
-v_redraw(sp, vp)
-	SCR *sp;
-	VICMD *vp;
+v_redraw(SCR *sp, VICMD *vp)
 {
 	return (sp->gp->scr_refresh(sp, 1));
 }

Modified: trunk/contrib/nvi/vi/v_replace.c
===================================================================
--- trunk/contrib/nvi/vi/v_replace.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/vi/v_replace.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -10,7 +10,7 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)v_replace.c	10.17 (Berkeley) 6/30/96";
+static const char sccsid[] = "$Id: v_replace.c,v 10.24 2001/06/25 15:19:34 skimo Exp $";
 #endif /* not lint */
 
 #include <sys/types.h>
@@ -43,9 +43,7 @@
  * PUBLIC: int v_replace __P((SCR *, VICMD *));
  */
 int
-v_replace(sp, vp)
-	SCR *sp;
-	VICMD *vp;
+v_replace(SCR *sp, VICMD *vp)
 {
 	EVENT ev;
 	VI_PRIVATE *vip;
@@ -53,7 +51,8 @@
 	size_t blen, len;
 	u_long cnt;
 	int quote, rval;
-	char *bp, *p;
+	CHAR_T *bp;
+	CHAR_T *p;
 
 	vip = VIP(sp);
 
@@ -144,8 +143,8 @@
 	}
 
 	/* Copy the line. */
-	GET_SPACE_RET(sp, bp, blen, len);
-	memmove(bp, p, len);
+	GET_SPACE_RETW(sp, bp, blen, len);
+	MEMMOVE(bp, p, len);
 	p = bp;
 
 	/*
@@ -154,7 +153,7 @@
 	 * is different from the historic vi, which replaced N characters with
 	 * a single new line.  Users complained, so we match historic practice.
 	 */
-	if (!quote && vip->rvalue == K_CR || vip->rvalue == K_NL) {
+	if ((!quote && vip->rvalue == K_CR) || vip->rvalue == K_NL) {
 		/* Set return line. */
 		vp->m_stop.lno = vp->m_start.lno + 1;
 		vp->m_stop.cno = 0;
@@ -193,10 +192,10 @@
 			rval = 0;
 		}
 	} else {
-		memset(bp + vp->m_start.cno, vip->rlast, cnt);
+		STRSET(bp + vp->m_start.cno, vip->rlast, cnt);
 		rval = db_set(sp, vp->m_start.lno, bp, len);
 	}
-	FREE_SPACE(sp, bp, blen);
+	FREE_SPACEW(sp, bp, blen);
 
 	vp->m_final = vp->m_stop;
 	return (rval);

Modified: trunk/contrib/nvi/vi/v_right.c
===================================================================
--- trunk/contrib/nvi/vi/v_right.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/vi/v_right.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -10,7 +10,7 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)v_right.c	10.7 (Berkeley) 3/6/96";
+static const char sccsid[] = "$Id: v_right.c,v 10.8 2001/06/25 15:19:34 skimo Exp $";
 #endif /* not lint */
 
 #include <sys/types.h>
@@ -31,9 +31,7 @@
  * PUBLIC: int v_right __P((SCR *, VICMD *));
  */
 int
-v_right(sp, vp)
-	SCR *sp;
-	VICMD *vp;
+v_right(SCR *sp, VICMD *vp)
 {
 	size_t len;
 	int isempty;
@@ -83,9 +81,7 @@
  * PUBLIC: int v_dollar __P((SCR *, VICMD *));
  */
 int
-v_dollar(sp, vp)
-	SCR *sp;
-	VICMD *vp;
+v_dollar(SCR *sp, VICMD *vp)
 {
 	size_t len;
 	int isempty;

Modified: trunk/contrib/nvi/vi/v_screen.c
===================================================================
--- trunk/contrib/nvi/vi/v_screen.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/vi/v_screen.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -10,7 +10,7 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)v_screen.c	10.10 (Berkeley) 4/27/96";
+static const char sccsid[] = "$Id: v_screen.c,v 10.12 2001/06/25 15:19:34 skimo Exp $";
 #endif /* not lint */
 
 #include <sys/types.h>
@@ -31,9 +31,7 @@
  * PUBLIC: int v_screen __P((SCR *, VICMD *));
  */
 int
-v_screen(sp, vp)
-	SCR *sp;
-	VICMD *vp;
+v_screen(SCR *sp, VICMD *vp)
 {
 	/*
 	 * You can't leave a colon command-line edit window -- it's not that
@@ -51,13 +49,13 @@
 	 * Try for the next lower screen, or, go back to the first
 	 * screen on the stack.
 	 */
-	if (sp->q.cqe_next != (void *)&sp->gp->dq)
-		sp->nextdisp = sp->q.cqe_next;
-	else if (sp->gp->dq.cqh_first == sp) {
+	if (TAILQ_NEXT(sp, q) != NULL)
+		sp->nextdisp = TAILQ_NEXT(sp, q);
+	else if (TAILQ_FIRST(sp->gp->dq) == sp) {
 		msgq(sp, M_ERR, "187|No other screen to switch to");
 		return (1);
 	} else
-		sp->nextdisp = sp->gp->dq.cqh_first;
+		sp->nextdisp = TAILQ_FIRST(sp->gp->dq);
 
 	F_SET(sp->nextdisp, SC_STATUS);
 	F_SET(sp, SC_SSWITCH | SC_STATUS);

Modified: trunk/contrib/nvi/vi/v_scroll.c
===================================================================
--- trunk/contrib/nvi/vi/v_scroll.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/vi/v_scroll.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -10,7 +10,7 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)v_scroll.c	10.9 (Berkeley) 4/27/96";
+static const char sccsid[] = "$Id: v_scroll.c,v 10.12 2001/06/25 15:19:34 skimo Exp $";
 #endif /* not lint */
 
 #include <sys/types.h>
@@ -67,9 +67,7 @@
  * PUBLIC: int v_lgoto __P((SCR *, VICMD *));
  */
 int
-v_lgoto(sp, vp)
-	SCR *sp;
-	VICMD *vp;
+v_lgoto(SCR *sp, VICMD *vp)
 {
 	recno_t nlines;
 
@@ -106,9 +104,7 @@
  * PUBLIC: int v_home __P((SCR *, VICMD *));
  */
 int
-v_home(sp, vp)
-	SCR *sp;
-	VICMD *vp;
+v_home(SCR *sp, VICMD *vp)
 {
 	if (vs_sm_position(sp, &vp->m_stop,
 	    F_ISSET(vp, VC_C1SET) ? vp->count - 1 : 0, P_TOP))
@@ -125,9 +121,7 @@
  * PUBLIC: int v_middle __P((SCR *, VICMD *));
  */
 int
-v_middle(sp, vp)
-	SCR *sp;
-	VICMD *vp;
+v_middle(SCR *sp, VICMD *vp)
 {
 	/*
 	 * Yielding to none in our quest for compatibility with every
@@ -148,9 +142,7 @@
  * PUBLIC: int v_bottom __P((SCR *, VICMD *));
  */
 int
-v_bottom(sp, vp)
-	SCR *sp;
-	VICMD *vp;
+v_bottom(SCR *sp, VICMD *vp)
 {
 	if (vs_sm_position(sp, &vp->m_stop,
 	    F_ISSET(vp, VC_C1SET) ? vp->count - 1 : 0, P_BOTTOM))
@@ -160,8 +152,7 @@
 }
 
 static void
-goto_adjust(vp)
-	VICMD *vp;
+goto_adjust(VICMD *vp)
 {
 	/* Guess that it's the end of the range. */
 	vp->m_final = vp->m_stop;
@@ -199,8 +190,8 @@
 	 * stay at the start of the range.  Ignore others.
 	 */
 	if (vp->m_stop.lno < vp->m_start.lno ||
-	    vp->m_stop.lno == vp->m_start.lno &&
-	    vp->m_stop.cno < vp->m_start.cno) {
+	    (vp->m_stop.lno == vp->m_start.lno &&
+	    vp->m_stop.cno < vp->m_start.cno)) {
 		if (ISCMD(vp->rkp, 'y') && vp->m_stop.lno == vp->m_start.lno)
 			vp->m_final = vp->m_start;
 	} else
@@ -214,9 +205,7 @@
  * PUBLIC: int v_up __P((SCR *, VICMD *));
  */
 int
-v_up(sp, vp)
-	SCR *sp;
-	VICMD *vp;
+v_up(SCR *sp, VICMD *vp)
 {
 	recno_t lno;
 
@@ -238,9 +227,7 @@
  * PUBLIC: int v_cr __P((SCR *, VICMD *));
  */
 int
-v_cr(sp, vp)
-	SCR *sp;
-	VICMD *vp;
+v_cr(SCR *sp, VICMD *vp)
 {
 	/* If it's a colon command-line edit window, it's an ex command. */
 	if (F_ISSET(sp, SC_COMEDIT))
@@ -261,9 +248,7 @@
  * PUBLIC: int v_down __P((SCR *, VICMD *));
  */
 int
-v_down(sp, vp)
-	SCR *sp;
-	VICMD *vp;
+v_down(SCR *sp, VICMD *vp)
 {
 	recno_t lno;
 
@@ -284,9 +269,7 @@
  * PUBLIC: int v_hpageup __P((SCR *, VICMD *));
  */
 int
-v_hpageup(sp, vp)
-	SCR *sp;
-	VICMD *vp;
+v_hpageup(SCR *sp, VICMD *vp)
 {
 	/*
 	 * Half screens always succeed unless already at SOF.
@@ -310,9 +293,7 @@
  * PUBLIC: int v_hpagedown __P((SCR *, VICMD *));
  */
 int
-v_hpagedown(sp, vp)
-	SCR *sp;
-	VICMD *vp;
+v_hpagedown(SCR *sp, VICMD *vp)
 {
 	/*
 	 * Half screens always succeed unless already at EOF.
@@ -340,9 +321,7 @@
  * PUBLIC: int v_pagedown __P((SCR *, VICMD *));
  */
 int
-v_pagedown(sp, vp)
-	SCR *sp;
-	VICMD *vp;
+v_pagedown(SCR *sp, VICMD *vp)
 {
 	recno_t offset;
 
@@ -361,8 +340,8 @@
 	 * any screen but the "next" one anyway.  We do it the historical
 	 * way as there's no good reason to change it.
 	 *
-	 * If the screen has been split, use the smaller of the current
-	 * window size and the window option value.
+	 * If the screen has been split horizontally, use the smaller of
+	 * the current window size and the window option value.
 	 *
 	 * It possible for this calculation to be less than 1; move at
 	 * least one line.
@@ -388,9 +367,7 @@
  * PUBLIC: int v_pageup __P((SCR *, VICMD *));
  */
 int
-v_pageup(sp, vp)
-	SCR *sp;
-	VICMD *vp;
+v_pageup(SCR *sp, VICMD *vp)
 {
 	recno_t offset;
 
@@ -414,8 +391,8 @@
 	 * but the first screen.  We do it the historical way as there's
 	 * no good reason to change it.
 	 *
-	 * If the screen has been split, use the smaller of the current
-	 * window size and the window option value.
+	 * If the screen has been split horizontally, use the smaller of
+	 * the current window size and the window option value.
 	 *
 	 * It possible for this calculation to be less than 1; move at
 	 * least one line.
@@ -436,9 +413,7 @@
  * PUBLIC: int v_lineup __P((SCR *, VICMD *));
  */
 int
-v_lineup(sp, vp)
-	SCR *sp;
-	VICMD *vp;
+v_lineup(SCR *sp, VICMD *vp)
 {
 	/*
 	 * The cursor moves down, staying with its original line, unless it
@@ -458,9 +433,7 @@
  * PUBLIC: int v_linedown __P((SCR *, VICMD *));
  */
 int
-v_linedown(sp, vp)
-	SCR *sp;
-	VICMD *vp;
+v_linedown(SCR *sp, VICMD *vp)
 {
 	/*
 	 * The cursor moves up, staying with its original line, unless it

Modified: trunk/contrib/nvi/vi/v_search.c
===================================================================
--- trunk/contrib/nvi/vi/v_search.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/vi/v_search.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -10,7 +10,7 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)v_search.c	10.18 (Berkeley) 9/19/96";
+static const char sccsid[] = "$Id: v_search.c,v 10.31 2012/02/08 07:26:59 zy Exp $";
 #endif /* not lint */
 
 #include <sys/types.h>
@@ -29,7 +29,7 @@
 #include "vi.h"
 
 static int v_exaddr __P((SCR *, VICMD *, dir_t));
-static int v_search __P((SCR *, VICMD *, char *, size_t, u_int, dir_t));
+static int v_search __P((SCR *, VICMD *, CHAR_T *, size_t, u_int, dir_t));
 
 /*
  * v_srch -- [count]?RE[? offset]
@@ -38,9 +38,7 @@
  * PUBLIC: int v_searchb __P((SCR *, VICMD *));
  */
 int
-v_searchb(sp, vp)
-	SCR *sp;
-	VICMD *vp;
+v_searchb(SCR *sp, VICMD *vp)
 {
 	return (v_exaddr(sp, vp, BACKWARD));
 }
@@ -52,9 +50,7 @@
  * PUBLIC: int v_searchf __P((SCR *, VICMD *));
  */
 int
-v_searchf(sp, vp)
-	SCR *sp;
-	VICMD *vp;
+v_searchf(SCR *sp, VICMD *vp)
 {
 	return (v_exaddr(sp, vp, FORWARD));
 }
@@ -64,12 +60,9 @@
  *	Do a vi search (which is really an ex address).
  */
 static int
-v_exaddr(sp, vp, dir)
-	SCR *sp;
-	VICMD *vp;
-	dir_t dir;
+v_exaddr(SCR *sp, VICMD *vp, dir_t dir)
 {
-	static EXCMDLIST fake = { "search" };
+	static EXCMDLIST fake = { L("search") };
 	EXCMD *cmdp;
 	GS *gp;
 	TEXT *tp;
@@ -76,7 +69,10 @@
 	recno_t s_lno;
 	size_t len, s_cno, tlen;
 	int err, nb, type;
-	char *cmd, *t, buf[20];
+	char buf[20];
+	CHAR_T *cmd, *t;
+	CHAR_T *w;
+	size_t wlen;
 
 	/*
 	 * !!!
@@ -93,7 +89,7 @@
 	    (O_ISSET(sp, O_SEARCHINCR) ? TXT_SEARCHINCR : 0)))
 		return (1);
 
-	tp = sp->tiq.cqh_first;
+	tp = TAILQ_FIRST(sp->tiq);
 
 	/* If the user backspaced over the prompt, do nothing. */
 	if (tp->term == TERM_BS)
@@ -245,7 +241,7 @@
 
 		/* Default to z+. */
 		if (!type &&
-		    v_event_push(sp, NULL, "+", 1, CH_NOMAP | CH_QUOTED))
+		    v_event_push(sp, NULL, L("+"), 1, CH_NOMAP | CH_QUOTED))
 			return (1);
 
 		/* Push the user's command. */
@@ -255,7 +251,8 @@
 		/* Push line number so get correct z display. */
 		tlen = snprintf(buf,
 		    sizeof(buf), "%lu", (u_long)vp->m_stop.lno);
-		if (v_event_push(sp, NULL, buf, tlen, CH_NOMAP | CH_QUOTED))
+		CHAR2INT(sp, buf, tlen, w, wlen);
+		if (v_event_push(sp, NULL, w, wlen, CH_NOMAP | CH_QUOTED))
 			return (1);
 		 
 		/* Don't refresh until after 'z' happens. */
@@ -284,9 +281,7 @@
  * PUBLIC: int v_searchN __P((SCR *, VICMD *));
  */
 int
-v_searchN(sp, vp)
-	SCR *sp;
-	VICMD *vp;
+v_searchN(SCR *sp, VICMD *vp)
 {
 	dir_t dir;
 
@@ -311,14 +306,35 @@
  * PUBLIC: int v_searchn __P((SCR *, VICMD *));
  */
 int
-v_searchn(sp, vp)
-	SCR *sp;
-	VICMD *vp;
+v_searchn(SCR *sp, VICMD *vp)
 {
 	return (v_search(sp, vp, NULL, 0, SEARCH_PARSE, sp->searchdir));
 }
 
 /*
+ * is_special --
+ *	Test if the character is special in a basic RE.
+ */
+static int
+is_special(CHAR_T c)
+{
+	/*
+	 * !!!
+	 * `*' and `$' are ordinary when appear at the beginning of a RE,
+	 * but it's safe to distinguish them from the ordinary characters.
+	 * The tilde is vi-specific, of course.
+	 */
+	return (STRCHR(L(".[*\\^$~"), c) && c);
+}
+
+/*
+ * Rear delimiter for word search when the keyword ends in
+ * (i.e., consists of) a non-word character.  See v_searchw below.
+ */
+#define RE_NWSTOP	L("([^[:alnum:]_]|$)")
+#define RE_NWSTOP_LEN	(SIZE(RE_NWSTOP) - 1)
+
+/*
  * v_searchw -- [count]^A
  *	Search for the word under the cursor.
  *
@@ -325,21 +341,47 @@
  * PUBLIC: int v_searchw __P((SCR *, VICMD *));
  */
 int
-v_searchw(sp, vp)
-	SCR *sp;
-	VICMD *vp;
+v_searchw(SCR *sp, VICMD *vp)
 {
 	size_t blen, len;
 	int rval;
-	char *bp;
+	CHAR_T *bp, *p;
 
-	len = VIP(sp)->klen + sizeof(RE_WSTART) + sizeof(RE_WSTOP);
-	GET_SPACE_RET(sp, bp, blen, len);
-	len = snprintf(bp, blen, "%s%s%s", RE_WSTART, VIP(sp)->keyw, RE_WSTOP);
+	/* An upper bound for the SIZE of the RE under construction. */
+	len = VIP(sp)->klen + MAX(RE_WSTART_LEN, 1)
+	    + MAX(RE_WSTOP_LEN, RE_NWSTOP_LEN);
+	GET_SPACE_RETW(sp, bp, blen, len);
+	p = bp;
 
+	/* Only the first character can be non-word, see v_curword. */
+	if (inword(VIP(sp)->keyw[0])) {
+		MEMCPY(p, RE_WSTART, RE_WSTART_LEN);
+		p += RE_WSTART_LEN;
+	} else if (is_special(VIP(sp)->keyw[0])) {
+		MEMCPY(p, L("\\"), 1);
+		p += 1;
+	}
+
+	MEMCPY(p, VIP(sp)->keyw, VIP(sp)->klen);
+	p += VIP(sp)->klen;
+
+	if (inword(p[-1])) {
+		MEMCPY(p, RE_WSTOP, RE_WSTOP_LEN);
+		p += RE_WSTOP_LEN;
+	} else {
+		/*
+		 * The keyword is a single non-word character.
+		 * We want it to stay the same when typing ^A several times
+		 * in a row, just the way the other cases behave.
+		 */
+		MEMCPY(p, RE_NWSTOP, RE_NWSTOP_LEN);
+		p += RE_NWSTOP_LEN;
+	}
+
+	len = p - bp;
 	rval = v_search(sp, vp, bp, len, SEARCH_SET, FORWARD);
 
-	FREE_SPACE(sp, bp, blen);
+	FREE_SPACEW(sp, bp, blen);
 	return (rval);
 }
 
@@ -348,13 +390,7 @@
  *	The search commands.
  */
 static int
-v_search(sp, vp, ptrn, plen, flags, dir)
-	SCR *sp;
-	VICMD *vp;
-	u_int flags;
-	char *ptrn;
-	size_t plen;
-	dir_t dir;
+v_search(SCR *sp, VICMD *vp, CHAR_T *ptrn, size_t plen, u_int flags, dir_t dir)
 {
 	/* Display messages. */
 	LF_SET(SEARCH_MSG);
@@ -417,10 +453,7 @@
  * PUBLIC: int v_correct __P((SCR *, VICMD *, int));
  */
 int
-v_correct(sp, vp, isdelta)
-	SCR *sp;
-	VICMD *vp;
-	int isdelta;
+v_correct(SCR *sp, VICMD *vp, int isdelta)
 {
 	dir_t dir;
 	MARK m;
@@ -462,8 +495,8 @@
 	 * because of the wrapscan option.
 	 */
 	if (vp->m_start.lno > vp->m_stop.lno ||
-	    vp->m_start.lno == vp->m_stop.lno &&
-	    vp->m_start.cno > vp->m_stop.cno) {
+	    (vp->m_start.lno == vp->m_stop.lno &&
+	    vp->m_start.cno > vp->m_stop.cno)) {
 		m = vp->m_start;
 		vp->m_start = vp->m_stop;
 		vp->m_stop = m;

Modified: trunk/contrib/nvi/vi/v_section.c
===================================================================
--- trunk/contrib/nvi/vi/v_section.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/vi/v_section.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -10,7 +10,7 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)v_section.c	10.7 (Berkeley) 3/6/96";
+static const char sccsid[] = "$Id: v_section.c,v 10.10 2001/06/25 15:19:35 skimo Exp $";
 #endif /* not lint */
 
 #include <sys/types.h>
@@ -62,13 +62,12 @@
  * PUBLIC: int v_sectionf __P((SCR *, VICMD *));
  */
 int
-v_sectionf(sp, vp)
-	SCR *sp;
-	VICMD *vp;
+v_sectionf(SCR *sp, VICMD *vp)
 {
 	recno_t cnt, lno;
 	size_t len;
-	char *p, *list, *lp;
+	CHAR_T *p;
+	char *list, *lp;
 
 	/* Get the macro list. */
 	if ((list = O_STR(sp, O_SECTIONS)) == NULL)
@@ -98,7 +97,7 @@
 	for (lno = vp->m_start.lno; !db_get(sp, ++lno, 0, &p, &len);) {
 		if (len == 0)
 			continue;
-		if (p[0] == '{' || ISMOTION(vp) && p[0] == '}') {
+		if (p[0] == '{' || (ISMOTION(vp) && p[0] == '}')) {
 			if (!--cnt) {
 				if (p[0] == '{')
 					goto adjust1;
@@ -122,7 +121,7 @@
 			continue;
 		for (lp = list; *lp != '\0'; lp += 2 * sizeof(*lp))
 			if (lp[0] == p[1] &&
-			    (lp[1] == ' ' && len == 2 || lp[1] == p[2]) &&
+			    ((lp[1] == ' ' && len == 2) || lp[1] == p[2]) &&
 			    !--cnt) {
 				/*
 				 * !!!
@@ -170,13 +169,12 @@
  * PUBLIC: int v_sectionb __P((SCR *, VICMD *));
  */
 int
-v_sectionb(sp, vp)
-	SCR *sp;
-	VICMD *vp;
+v_sectionb(SCR *sp, VICMD *vp)
 {
 	size_t len;
 	recno_t cnt, lno;
-	char *p, *list, *lp;
+	CHAR_T *p;
+	char *list, *lp;
 
 	/* An empty file or starting from line 1 is always illegal. */
 	if (vp->m_start.lno <= 1) {
@@ -213,7 +211,7 @@
 			continue;
 		for (lp = list; *lp != '\0'; lp += 2 * sizeof(*lp))
 			if (lp[0] == p[1] &&
-			    (lp[1] == ' ' && len == 2 || lp[1] == p[2]) &&
+			    ((lp[1] == ' ' && len == 2) || lp[1] == p[2]) &&
 			    !--cnt) {
 adjust1:			vp->m_stop.lno = lno;
 				vp->m_stop.cno = 0;

Modified: trunk/contrib/nvi/vi/v_sentence.c
===================================================================
--- trunk/contrib/nvi/vi/v_sentence.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/vi/v_sentence.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -10,7 +10,7 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)v_sentence.c	10.7 (Berkeley) 3/6/96";
+static const char sccsid[] = "$Id: v_sentence.c,v 10.9 2001/06/25 15:19:35 skimo Exp $";
 #endif /* not lint */
 
 #include <sys/types.h>
@@ -52,9 +52,7 @@
  * PUBLIC: int v_sentencef __P((SCR *, VICMD *));
  */
 int
-v_sentencef(sp, vp)
-	SCR *sp;
-	VICMD *vp;
+v_sentencef(SCR *sp, VICMD *vp)
 {
 	enum { BLANK, NONE, PERIOD } state;
 	VCS cs;
@@ -74,7 +72,7 @@
 	 * This may not handle "  .  " correctly, but it's real unclear
 	 * what correctly means in that case.
 	 */
-	if (cs.cs_flags == CS_EMP || cs.cs_flags == 0 && isblank(cs.cs_ch)) {
+	if (cs.cs_flags == CS_EMP || (cs.cs_flags == 0 && isblank(cs.cs_ch))) {
 		if (cs_fblank(sp, &cs))
 			return (1);
 		if (--cnt == 0) {
@@ -193,9 +191,7 @@
  * PUBLIC: int v_sentenceb __P((SCR *, VICMD *));
  */
 int
-v_sentenceb(sp, vp)
-	SCR *sp;
-	VICMD *vp;
+v_sentenceb(SCR *sp, VICMD *vp)
 {
 	VCS cs;
 	recno_t slno;

Modified: trunk/contrib/nvi/vi/v_status.c
===================================================================
--- trunk/contrib/nvi/vi/v_status.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/vi/v_status.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -10,13 +10,12 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)v_status.c	10.9 (Berkeley) 5/15/96";
+static const char sccsid[] = "$Id: v_status.c,v 10.10 2001/06/25 15:19:35 skimo Exp $";
 #endif /* not lint */
 
 #include <sys/types.h>
 #include <sys/queue.h>
 #include <sys/stat.h>
-#include <sys/time.h>
 
 #include <bitstring.h>
 #include <limits.h>
@@ -32,9 +31,7 @@
  * PUBLIC: int v_status __P((SCR *, VICMD *));
  */
 int
-v_status(sp, vp)
-	SCR *sp;
-	VICMD *vp;
+v_status(SCR *sp, VICMD *vp)
 {
 	(void)msgq_status(sp, vp->m_start.lno, MSTAT_SHOWLAST);
 	return (0);

Modified: trunk/contrib/nvi/vi/v_txt.c
===================================================================
--- trunk/contrib/nvi/vi/v_txt.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/vi/v_txt.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -10,13 +10,12 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)v_txt.c	10.87 (Berkeley) 10/13/96";
+static const char sccsid[] = "$Id: v_txt.c,v 11.5 2013/05/19 20:37:45 bentley Exp $";
 #endif /* not lint */
 
 #include <sys/types.h>
 #include <sys/queue.h>
 #include <sys/stat.h>
-#include <sys/time.h>
 
 #include <bitstring.h>
 #include <ctype.h>
@@ -63,11 +62,7 @@
  * PUBLIC: int v_tcmd __P((SCR *, VICMD *, ARG_CHAR_T, u_int));
  */
 int
-v_tcmd(sp, vp, prompt, flags)
-	SCR *sp;
-	VICMD *vp;
-	ARG_CHAR_T prompt;
-	u_int flags;
+v_tcmd(SCR *sp, VICMD *vp, ARG_CHAR_T prompt, u_int flags)
 {
 	/* Normally, we end up where we started. */
 	vp->m_final.lno = sp->lno;
@@ -118,8 +113,7 @@
  *	Initialize the screen map for colon command-line input.
  */
 static int
-txt_map_init(sp)
-	SCR *sp;
+txt_map_init(SCR *sp)
 {
 	SMAP *esmp;
 	VI_PRIVATE *vip;
@@ -171,8 +165,7 @@
  *	Reset the screen map for colon command-line input.
  */
 static int
-txt_map_end(sp)
-	SCR *sp;
+txt_map_end(SCR *sp)
 {
 	VI_PRIVATE *vip;
 	size_t cnt;
@@ -242,26 +235,26 @@
  *	Vi text input.
  *
  * PUBLIC: int v_txt __P((SCR *, VICMD *, MARK *,
- * PUBLIC:    const char *, size_t, ARG_CHAR_T, recno_t, u_long, u_int32_t));
+ * PUBLIC:    const CHAR_T *, size_t, ARG_CHAR_T, recno_t, u_long, u_int32_t));
  */
 int
-v_txt(sp, vp, tm, lp, len, prompt, ai_line, rcount, flags)
-	SCR *sp;
-	VICMD *vp;
-	MARK *tm;		/* To MARK. */
-	const char *lp;		/* Input line. */
-	size_t len;		/* Input line length. */
-	ARG_CHAR_T prompt;	/* Prompt to display. */
-	recno_t ai_line;	/* Line number to use for autoindent count. */
-	u_long rcount;		/* Replay count. */
-	u_int32_t flags;	/* TXT_* flags. */
+v_txt(
+	SCR *sp,
+	VICMD *vp,
+	MARK *tm,		/* To MARK. */
+	const CHAR_T *lp,	/* Input line. */
+	size_t len,		/* Input line length. */
+	ARG_CHAR_T prompt,	/* Prompt to display. */
+	recno_t ai_line,	/* Line number to use for autoindent count. */
+	u_long rcount,		/* Replay count. */
+	u_int32_t flags)	/* TXT_* flags. */
 {
-	EVENT ev, *evp;		/* Current event. */
+	EVENT ev, *evp = NULL;	/* Current event. */
 	EVENT fc;		/* File name completion event. */
 	GS *gp;
 	TEXT *ntp, *tp;		/* Input text structures. */
 	TEXT ait;		/* Autoindent text structure. */
-	TEXT wmt;		/* Wrapmargin text structure. */
+	TEXT wmt = {{ 0 }};	/* Wrapmargin text structure. */
 	TEXTH *tiqh;
 	VI_PRIVATE *vip;
 	abb_t abb;		/* State of abbreviation checks. */
@@ -281,7 +274,8 @@
 	int showmatch;		/* Showmatch set on this character. */
 	int wm_set, wm_skip;	/* Wrapmargin happened, blank skip flags. */
 	int max, tmp;
-	char *p;
+	int nochange;
+	CHAR_T *p;
 
 	gp = sp->gp;
 	vip = VIP(sp);
@@ -298,10 +292,11 @@
 	 * default to 0 -- text_init() handles this.)  If changing a line,
 	 * copy it into the TEXT buffer.
 	 */
-	tiqh = &sp->tiq;
-	if (tiqh->cqh_first != (void *)tiqh) {
-		tp = tiqh->cqh_first;
-		if (tp->q.cqe_next != (void *)tiqh || tp->lb_len < len + 32) {
+	tiqh = sp->tiq;
+	if (!TAILQ_EMPTY(tiqh)) {
+		tp = TAILQ_FIRST(tiqh);
+		if (TAILQ_NEXT(tp, q) != NULL ||
+		    tp->lb_len < (len + 32) * sizeof(CHAR_T)) {
 			text_lfree(tiqh);
 			goto newtp;
 		}
@@ -308,13 +303,14 @@
 		tp->ai = tp->insert = tp->offset = tp->owrite = 0;
 		if (lp != NULL) {
 			tp->len = len;
-			memmove(tp->lb, lp, len);
+			BINC_RETW(sp, tp->lb, tp->lb_len, len);
+			MEMMOVE(tp->lb, lp, len);
 		} else
 			tp->len = 0;
 	} else {
 newtp:		if ((tp = text_init(sp, lp, len, len + 32)) == NULL)
 			return (1);
-		CIRCLEQ_INSERT_HEAD(tiqh, tp, q);
+		TAILQ_INSERT_HEAD(tiqh, tp, q);
 	}
 
 	/* Set default termination condition. */
@@ -463,6 +459,7 @@
 	/* Other text input mode setup. */
 	quote = Q_NOTSET;
 	carat = C_NOTSET;
+	nochange = 0;
 	FL_INIT(is_flags,
 	    LF_ISSET(TXT_SEARCHINCR) ? IS_RESTART | IS_RUNNING : 0);
 	filec_redraw = hexcnt = showmatch = 0;
@@ -510,6 +507,15 @@
 	case E_EOF:
 		F_SET(sp, SC_EXIT_FORCE);
 		return (1);
+	case E_INTERRUPT:
+		/*
+		 * !!!
+		 * Historically, <interrupt> exited the user from text input
+		 * mode or cancelled a colon command, and returned to command
+		 * mode.  It also beeped the terminal, but that seems a bit
+		 * excessive.
+		 */
+		goto k_escape;
 	case E_REPAINT:
 		if (vs_repaint(sp, &ev))
 			return (1);
@@ -517,37 +523,10 @@
 	case E_WRESIZE:
 		/* <resize> interrupts the input mode. */
 		v_emsg(sp, NULL, VIM_WRESIZE);
-		/* FALLTHROUGH */
+		goto k_escape;
 	default:
-		if (evp->e_event != E_INTERRUPT && evp->e_event != E_WRESIZE)
-			v_event_err(sp, evp);
-		/*
-		 * !!!
-		 * Historically, <interrupt> exited the user from text input
-		 * mode or cancelled a colon command, and returned to command
-		 * mode.  It also beeped the terminal, but that seems a bit
-		 * excessive.
-		 */
-		/*
-		 * If we are recording, morph into <escape> key so that
-		 * we can repeat the command safely: there is no way to
-		 * invalidate the repetition of an instance of a command,
-		 * which would be the alternative possibility.
-		 * If we are not recording (most likely on the command line),
-		 * simply discard the input and return to command mode
-		 * so that an INTERRUPT doesn't become for example a file
-		 * completion request. -aymeric
-		 */
-		if (LF_ISSET(TXT_RECORD)) {
-			evp->e_event = E_CHARACTER;
-			evp->e_c = 033;
-			evp->e_flags = 0;
-			evp->e_value = K_ESCAPE;
-			break;
-		} else {
-			tp->term = TERM_ESC;
-			goto k_escape;
-		}
+		v_event_err(sp, evp);
+		goto k_escape;
 	}
 
 	/*
@@ -612,13 +591,16 @@
 
 	/* Check to see if the character fits into the replay buffers. */
 	if (LF_ISSET(TXT_RECORD)) {
-		BINC_GOTO(sp, vip->rep,
+		BINC_GOTO(sp, EVENT, vip->rep,
 		    vip->rep_len, (rcol + 1) * sizeof(EVENT));
 		vip->rep[rcol++] = *evp;
 	}
 
-replay:	if (LF_ISSET(TXT_REPLAY))
+replay:	if (LF_ISSET(TXT_REPLAY)) {
+		if (rcol == vip->rep_cnt)
+			goto k_escape;
 		evp = vip->rep + rcol++;
+	}
 
 	/* Wrapmargin check for leading space. */
 	if (wm_skip) {
@@ -669,7 +651,7 @@
 	 * this test delimits the value by any non-hex character.  Offset by
 	 * one, we use 0 to mean that we've found <CH_HEX>.
 	 */
-	if (hexcnt > 1 && !isxdigit(evp->e_c)) {
+	if (hexcnt > 1 && !ISXDIGIT(evp->e_c)) {
 		hexcnt = 0;
 		if (txt_hex(sp, tp))
 			goto err;
@@ -691,7 +673,7 @@
 				if (vs_change(sp, tp->lno, LINE_RESET))
 					goto err;
 			} else if (F_ISSET(sp, SC_SCRIPT))
-				(void)v_event_push(sp, NULL, "\r", 1, CH_NOMAP);
+				(void)v_event_push(sp, NULL, L("\r"), 1, CH_NOMAP);
 
 			/* Set term condition: if empty. */
 			if (tp->cno <= tp->offset)
@@ -789,7 +771,7 @@
 		if ((ntp = text_init(sp, p,
 		    insert + owrite, insert + owrite + 32)) == NULL)
 			goto err;
-		CIRCLEQ_INSERT_TAIL(&sp->tiq, ntp, q);
+		TAILQ_INSERT_TAIL(sp->tiq, ntp, q);
 
 		/* Set up bookkeeping for the new line. */
 		ntp->insert = insert;
@@ -804,10 +786,11 @@
 		 * characters may have been erased.
 		 */
 		if (LF_ISSET(TXT_AUTOINDENT)) {
-			if (carat == C_NOCHANGE) {
+			if (nochange) {
+				nochange = 0;
 				if (v_txt_auto(sp, OOBLNO, &ait, ait.ai, ntp))
 					goto err;
-				FREE_SPACE(sp, ait.lb, ait.lb_len);
+				FREE_SPACEW(sp, ait.lb, ait.lb_len);
 			} else
 				if (v_txt_auto(sp, OOBLNO, tp, tp->cno, ntp))
 					goto err;
@@ -826,9 +809,9 @@
 			if (wmt.offset != 0 ||
 			    wmt.owrite != 0 || wmt.insert != 0) {
 #define	WMTSPACE	wmt.offset + wmt.owrite + wmt.insert
-				BINC_GOTO(sp, ntp->lb,
+				BINC_GOTOW(sp, ntp->lb,
 				    ntp->lb_len, ntp->len + WMTSPACE + 32);
-				memmove(ntp->lb + ntp->cno, wmt.lb, WMTSPACE);
+				MEMMOVE(ntp->lb + ntp->cno, wmt.lb, WMTSPACE);
 				ntp->len += WMTSPACE;
 				ntp->cno += wmt.offset;
 				ntp->owrite = wmt.owrite;
@@ -839,7 +822,7 @@
 
 		/* New lines are TXT_APPENDEOL. */
 		if (ntp->owrite == 0 && ntp->insert == 0) {
-			BINC_GOTO(sp, ntp->lb, ntp->lb_len, ntp->len + 1);
+			BINC_GOTOW(sp, ntp->lb, ntp->lb_len, ntp->len + 1);
 			LF_SET(TXT_APPENDEOL);
 			ntp->lb[ntp->cno] = CH_CURSOR;
 			++ntp->insert;
@@ -860,6 +843,7 @@
 		if (rcount > 1) {
 			--rcount;
 
+			vip->rep_cnt = rcol;
 			rcol = 0;
 			abb = AB_NOTSET;
 			LF_CLR(TXT_RECORD);
@@ -902,7 +886,7 @@
 		 * characters, and making them into insert characters.
 		 */
 		if (LF_ISSET(TXT_REPLACE))
-			txt_Rresolve(sp, &sp->tiq, tp, len);
+			txt_Rresolve(sp, sp->tiq, tp, len);
 
 		/*
 		 * If there are any overwrite characters, copy down
@@ -910,7 +894,7 @@
 		 */
 		if (tp->owrite) {
 			if (tp->insert)
-				memmove(tp->lb + tp->cno,
+				MEMMOVE(tp->lb + tp->cno,
 				    tp->lb + tp->cno + tp->owrite, tp->insert);
 			tp->len -= tp->owrite;
 		}
@@ -925,10 +909,10 @@
 		 * This is wrong, should pass back a length.
 		 */
 		if (LF_ISSET(TXT_RESOLVE)) {
-			if (txt_resolve(sp, &sp->tiq, flags))
+			if (txt_resolve(sp, sp->tiq, flags))
 				goto err;
 		} else {
-			BINC_GOTO(sp, tp->lb, tp->lb_len, tp->len + 1);
+			BINC_GOTOW(sp, tp->lb, tp->lb_len, tp->len + 1);
 			tp->lb[tp->len] = '\0';
 		}
 
@@ -972,11 +956,12 @@
 			/* Save the ai string for later. */
 			ait.lb = NULL;
 			ait.lb_len = 0;
-			BINC_GOTO(sp, ait.lb, ait.lb_len, tp->ai);
-			memmove(ait.lb, tp->lb, tp->ai);
+			BINC_GOTOW(sp, ait.lb, ait.lb_len, tp->ai);
+			MEMMOVE(ait.lb, tp->lb, tp->ai);
 			ait.ai = ait.len = tp->ai;
 
-			carat = C_NOCHANGE;
+			carat = C_NOTSET;
+			nochange = 1;
 			goto leftmargin;
 		case C_ZEROSET:		/* 0^D */
 			if (tp->ai == 0 || tp->cno > tp->ai + tp->offset + 1)
@@ -1011,7 +996,7 @@
 		 */
 		if (tp->cno == 0) {
 			if ((ntp =
-			    txt_backup(sp, &sp->tiq, tp, &flags)) == NULL)
+			    txt_backup(sp, sp->tiq, tp, &flags)) == NULL)
 				goto err;
 			tp = ntp;
 			break;
@@ -1063,7 +1048,7 @@
 		 */
 		if (tp->cno == 0) {
 			if ((ntp =
-			    txt_backup(sp, &sp->tiq, tp, &flags)) == NULL)
+			    txt_backup(sp, sp->tiq, tp, &flags)) == NULL)
 				goto err;
 			tp = ntp;
 		}
@@ -1093,7 +1078,7 @@
 		}
 
 		/* Skip over trailing space characters. */
-		while (tp->cno > max && isblank(tp->lb[tp->cno - 1])) {
+		while (tp->cno > max && ISBLANK(tp->lb[tp->cno - 1])) {
 			--tp->cno;
 			++tp->owrite;
 		}
@@ -1122,12 +1107,12 @@
 		 */
 		if (LF_ISSET(TXT_TTYWERASE))
 			while (tp->cno > max) {
+				if (ISBLANK(tp->lb[tp->cno - 1]))
+					break;
 				--tp->cno;
 				++tp->owrite;
 				if (FL_ISSET(is_flags, IS_RUNNING))
 					tp->lb[tp->cno] = ' ';
-				if (isblank(tp->lb[tp->cno - 1]))
-					break;
 			}
 		else {
 			if (LF_ISSET(TXT_ALTWERASE)) {
@@ -1135,19 +1120,17 @@
 				++tp->owrite;
 				if (FL_ISSET(is_flags, IS_RUNNING))
 					tp->lb[tp->cno] = ' ';
-				if (isblank(tp->lb[tp->cno - 1]))
-					break;
 			}
 			if (tp->cno > max)
 				tmp = inword(tp->lb[tp->cno - 1]);
 			while (tp->cno > max) {
+				if (tmp != inword(tp->lb[tp->cno - 1])
+				    || ISBLANK(tp->lb[tp->cno - 1]))
+					break;
 				--tp->cno;
 				++tp->owrite;
 				if (FL_ISSET(is_flags, IS_RUNNING))
 					tp->lb[tp->cno] = ' ';
-				if (tmp != inword(tp->lb[tp->cno - 1])
-				    || isblank(tp->lb[tp->cno - 1]))
-					break;
 			}
 		}
 
@@ -1164,7 +1147,7 @@
 		 */
 		if (tp->cno == 0) {
 			if ((ntp =
-			    txt_backup(sp, &sp->tiq, tp, &flags)) == NULL)
+			    txt_backup(sp, sp->tiq, tp, &flags)) == NULL)
 				goto err;
 			tp = ntp;
 		}
@@ -1213,11 +1196,6 @@
 		if (txt_dent(sp, tp, 1))
 			goto err;
 		goto ebuf_chk;
-	case K_RIGHTBRACE:
-	case K_RIGHTPAREN:
-		if (LF_ISSET(TXT_SHOWMATCH))
-			showmatch = 1;
-		goto ins_ch;
 	case K_BACKSLASH:		/* Quote next erase/kill. */
 		/*
 		 * !!!
@@ -1265,6 +1243,14 @@
 		hexcnt = 1;
 		goto insq_ch;
 	default:			/* Insert the character. */
+		if (LF_ISSET(TXT_SHOWMATCH)) {
+			CHAR_T *match_chars, *cp;
+
+			match_chars = VIP(sp)->mcs;
+			cp = STRCHR(match_chars, evp->e_c);
+			if (cp != NULL && (cp - match_chars) & 1)
+				showmatch = 1;
+		}
 ins_ch:		/*
 		 * Historically, vi eliminated nul's out of hand.  If the
 		 * beautify option was set, it also deleted any unknown
@@ -1278,7 +1264,7 @@
 		 * wasn't a replay and wasn't handled specially, except
 		 * <tab> or <ff>.
 		 */
-		if (LF_ISSET(TXT_BEAUTIFY) && iscntrl(evp->e_c) &&
+		if (LF_ISSET(TXT_BEAUTIFY) && ISCNTRL(evp->e_c) &&
 		    evp->e_value != K_FORMFEED && evp->e_value != K_TAB) {
 			msgq(sp, M_BERR,
 			    "192|Illegal character; quote to enter");
@@ -1331,7 +1317,7 @@
 		 * number of hex bytes.  Offset by one, we use 0 to mean
 		 * that we've found <CH_HEX>.
 		 */
-		if (hexcnt != 0 && hexcnt++ == sizeof(CHAR_T) * 2 + 1) {
+		if (hexcnt != 0 && hexcnt++ == 3) {
 			hexcnt = 0;
 			if (txt_hex(sp, tp))
 				goto err;
@@ -1370,7 +1356,7 @@
 		 * the length of the motion.
 		 */
 ebuf_chk:	if (tp->cno >= tp->len) {
-			BINC_GOTO(sp, tp->lb, tp->lb_len, tp->len + 1);
+			BINC_GOTOW(sp, tp->lb, tp->lb_len, tp->len + 1);
 			LF_SET(TXT_APPENDEOL);
 
 			tp->lb[tp->cno] = CH_CURSOR;
@@ -1391,7 +1377,7 @@
 #ifdef DEBUG
 	if (tp->cno + tp->insert + tp->owrite != tp->len) {
 		msgq(sp, M_ERR,
-		    "len %u != cno: %u ai: %u insert %u overwrite %u",
+		    "len %zu != cno: %zu ai: %zu insert %zu overwrite %zu",
 		    tp->len, tp->cno, tp->ai, tp->insert, tp->owrite);
 		if (LF_ISSET(TXT_REPLAY))
 			goto done;
@@ -1475,7 +1461,7 @@
 err:
 alloc_err:
 	F_CLR(sp, SC_TINPUT);
-	txt_err(sp, &sp->tiq);
+	txt_err(sp, sp->tiq);
 	return (1);
 }
 
@@ -1484,11 +1470,7 @@
  *	Handle abbreviations.
  */
 static int
-txt_abbrev(sp, tp, pushcp, isinfoline, didsubp, turnoffp)
-	SCR *sp;
-	TEXT *tp;
-	CHAR_T *pushcp;
-	int isinfoline, *didsubp, *turnoffp;
+txt_abbrev(SCR *sp, TEXT *tp, CHAR_T *pushcp, int isinfoline, int *didsubp, int *turnoffp)
 {
 	VI_PRIVATE *vip;
 	CHAR_T ch, *p;
@@ -1632,7 +1614,7 @@
 		tp->owrite += len;
 	else {
 		if (tp->insert)
-			memmove(tp->lb + tp->cno + qp->olen,
+			MEMMOVE(tp->lb + tp->cno + qp->olen,
 			    tp->lb + tp->cno + tp->owrite + len, tp->insert);
 		tp->owrite += qp->olen;
 		tp->len -= len - qp->olen;
@@ -1654,13 +1636,10 @@
  *	Handle the unmap command.
  */
 static void
-txt_unmap(sp, tp, ec_flagsp)
-	SCR *sp;
-	TEXT *tp;
-	u_int32_t *ec_flagsp;
+txt_unmap(SCR *sp, TEXT *tp, u_int32_t *ec_flagsp)
 {
 	size_t len, off;
-	char *p;
+	CHAR_T *p;
 
 	/* Find the beginning of this "word". */
 	for (off = tp->cno - 1, p = tp->lb + off, len = 0;; --p, --off) {
@@ -1697,15 +1676,12 @@
  *	When a line is resolved by <esc>, review autoindent characters.
  */
 static void
-txt_ai_resolve(sp, tp, changedp)
-	SCR *sp;
-	TEXT *tp;
-	int *changedp;
+txt_ai_resolve(SCR *sp, TEXT *tp, int *changedp)
 {
 	u_long ts;
 	int del;
 	size_t cno, len, new, old, scno, spaces, tab_after_sp, tabs;
-	char *p;
+	CHAR_T *p;
 
 	*changedp = 0;
 
@@ -1748,7 +1724,7 @@
 	 * If there are no spaces, or no tabs after spaces and less than
 	 * ts spaces, it's already minimal.
 	 */
-	if (!spaces || !tab_after_sp && spaces < ts)
+	if (!spaces || (!tab_after_sp && spaces < ts))
 		return;
 
 	/* Count up spaces/tabs needed to get to the target. */
@@ -1767,7 +1743,7 @@
 
 	/* Shift the rest of the characters down, adjust the counts. */
 	del = old - new;
-	memmove(p - del, p, tp->len - old);
+	MEMMOVE(p - del, p, tp->len - old);
 	tp->len -= del;
 	tp->cno -= del;
 
@@ -1787,14 +1763,10 @@
  * PUBLIC: int v_txt_auto __P((SCR *, recno_t, TEXT *, size_t, TEXT *));
  */
 int
-v_txt_auto(sp, lno, aitp, len, tp)
-	SCR *sp;
-	recno_t lno;
-	TEXT *aitp, *tp;
-	size_t len;
+v_txt_auto(SCR *sp, recno_t lno, TEXT *aitp, size_t len, TEXT *tp)
 {
 	size_t nlen;
-	char *p, *t;
+	CHAR_T *p, *t;
 
 	if (aitp == NULL) {
 		/*
@@ -1821,15 +1793,15 @@
 		return (0);
 
 	/* Make sure the buffer's big enough. */
-	BINC_RET(sp, tp->lb, tp->lb_len, tp->len + nlen);
+	BINC_RETW(sp, tp->lb, tp->lb_len, tp->len + nlen);
 
 	/* Copy the buffer's current contents up. */
 	if (tp->len != 0)
-		memmove(tp->lb + nlen, tp->lb, tp->len);
+		MEMMOVE(tp->lb + nlen, tp->lb, tp->len);
 	tp->len += nlen;
 
 	/* Copy the indentation into the new buffer. */
-	memmove(tp->lb, t, nlen);
+	MEMMOVE(tp->lb, t, nlen);
 
 	/* Set the autoindent count. */
 	tp->ai = nlen;
@@ -1841,17 +1813,13 @@
  *	Back up to the previously edited line.
  */
 static TEXT *
-txt_backup(sp, tiqh, tp, flagsp)
-	SCR *sp;
-	TEXTH *tiqh;
-	TEXT *tp;
-	u_int32_t *flagsp;
+txt_backup(SCR *sp, TEXTH *tiqh, TEXT *tp, u_int32_t *flagsp)
 {
 	VI_PRIVATE *vip;
 	TEXT *ntp;
 
 	/* Get a handle on the previous TEXT structure. */
-	if ((ntp = tp->q.cqe_prev) == (void *)tiqh) {
+	if ((ntp = TAILQ_PREV(tp, _texth, q)) == NULL) {
 		if (!FL_ISSET(*flagsp, TXT_REPLAY))
 			msgq(sp, M_BERR,
 			    "193|Already at the beginning of the insert");
@@ -1872,7 +1840,7 @@
 		FL_CLR(*flagsp, TXT_APPENDEOL);
 
 	/* Release the current TEXT. */
-	CIRCLEQ_REMOVE(tiqh, tp, q);
+	TAILQ_REMOVE(tiqh, tp, q);
 	text_free(tp);
 
 	/* Update the old line on the screen. */
@@ -1910,7 +1878,7 @@
  * Technically, txt_dent should be part of the screen interface, as it requires
  * knowledge of character sizes, including <space>s, on the screen.  It's here
  * because it's a complicated little beast, and I didn't want to shove it down
- * into the screen.  It's probable that KEY_LEN will call into the screen once
+ * into the screen.  It's probable that KEY_COL will call into the screen once
  * there are screens with different character representations.
  *
  * txt_dent --
@@ -1920,14 +1888,11 @@
  * changes.
  */
 static int
-txt_dent(sp, tp, isindent)
-	SCR *sp;
-	TEXT *tp;
-	int isindent;
+txt_dent(SCR *sp, TEXT *tp, int isindent)
 {
 	CHAR_T ch;
 	u_long sw, ts;
-	size_t cno, current, spaces, target, tabs, off;
+	size_t cno, current, spaces, target, tabs;
 	int ai_reset;
 
 	ts = O_VAL(sp, O_TABSTOP);
@@ -1951,7 +1916,7 @@
 	 */
 	for (current = cno = 0; cno < tp->cno; ++cno)
 		current += tp->lb[cno] == '\t' ?
-		    COL_OFF(current, ts) : KEY_LEN(sp, tp->lb[cno]);
+		    COL_OFF(current, ts) : KEY_COL(sp, tp->lb[cno]);
 
 	target = current;
 	if (isindent)
@@ -1981,7 +1946,7 @@
 	    --tp->cno, ++tp->owrite);
 	for (current = cno = 0; cno < tp->cno; ++cno)
 		current += tp->lb[cno] == '\t' ?
-		    COL_OFF(current, ts) : KEY_LEN(sp, tp->lb[cno]);
+		    COL_OFF(current, ts) : KEY_COL(sp, tp->lb[cno]);
 
 	/*
 	 * If we didn't move up to or past the target, it's because there
@@ -2021,24 +1986,23 @@
 
 /*
  * txt_fc --
- *	File name completion.
+ *	File name and ex command completion.
  */
 static int
-txt_fc(sp, tp, redrawp)
-	SCR *sp;
-	TEXT *tp;
-	int *redrawp;
+txt_fc(SCR *sp, TEXT *tp, int *redrawp)
 {
 	struct stat sb;
 	ARGS **argv;
-	CHAR_T s_ch;
 	EXCMD cmd;
 	size_t indx, len, nlen, off;
-	int argc, trydir;
-	char *p, *t;
+	int argc;
+	CHAR_T *p, *t, *bp;
+	char *np, *epd = NULL;
+	size_t nplen;
+	int fstwd = 1;
 
-	trydir = 0;
 	*redrawp = 0;
+	ex_cinit(sp, &cmd, 0, 0, OOBLNO, OOBLNO, 0);
 
 	/*
 	 * Find the beginning of this "word" -- if we're at the beginning
@@ -2047,67 +2011,53 @@
 	if (tp->cno == 1) {
 		len = 0;
 		p = tp->lb;
-	} else
-retry:		for (len = 0,
-		    off = tp->cno - 1, p = tp->lb + off;; --off, --p) {
-			if (isblank(*p)) {
-				++p;
-				break;
-			}
-			++len;
-			if (off == tp->ai || off == tp->offset)
-				break;
+	} else {
+		CHAR_T *ap;
+
+		for (len = 0,
+		    off = MAX(tp->ai, tp->offset), ap = tp->lb + off, p = ap;
+		    off < tp->cno; ++off, ++ap) {
+			if (IS_ESCAPE(sp, &cmd, *ap)) {
+				if (++off == tp->cno)
+					break;
+				++ap;
+				len += 2;
+			} else if (cmdskip(*ap)) {
+				p = ap + 1;
+				if (len > 0)
+					fstwd = 0;
+				len = 0;
+			} else
+				++len;
 		}
+	}
 
 	/*
-	 * Get enough space for a wildcard character.
-	 *
-	 * XXX
-	 * This won't work for "foo\", since the \ will escape the expansion
-	 * character.  I'm not sure if that's a bug or not...
+	 * If we are at the first word, do ex command completion instead of
+	 * file name completion.
 	 */
-	off = p - tp->lb;
-	BINC_RET(sp, tp->lb, tp->lb_len, tp->len + 1);
-	p = tp->lb + off;
-
-	s_ch = p[len];
-	p[len] = '*';
-
-	/* Build an ex command, and call the ex expansion routines. */
-	ex_cinit(&cmd, 0, 0, OOBLNO, OOBLNO, 0, NULL);
-	if (argv_init(sp, &cmd))
-		return (1);
-	if (argv_exp2(sp, &cmd, p, len + 1)) {
-		p[len] = s_ch;
-		return (0);
+	if (fstwd)
+		(void)argv_flt_ex(sp, &cmd, p, len);
+	else {
+		if ((bp = argv_uesc(sp, &cmd, p, len)) == NULL)
+			return (1);
+		if (argv_flt_path(sp, &cmd, bp, STRLEN(bp))) {
+			FREE_SPACEW(sp, bp, 0);
+			return (0);
+		}
+		FREE_SPACEW(sp, bp, 0);
 	}
 	argc = cmd.argc;
 	argv = cmd.argv;
 
-	p[len] = s_ch;
-
 	switch (argc) {
 	case 0:				/* No matches. */
-		if (!trydir)
-			(void)sp->gp->scr_bell(sp);
+		(void)sp->gp->scr_bell(sp);
 		return (0);
 	case 1:				/* One match. */
-		/* If something changed, do the exchange. */
-		nlen = strlen(cmd.argv[0]->bp);
-		if (len != nlen || memcmp(cmd.argv[0]->bp, p, len))
-			break;
-
-		/* If haven't done a directory test, do it now. */
-		if (!trydir &&
-		    !stat(cmd.argv[0]->bp, &sb) && S_ISDIR(sb.st_mode)) {
-			p += len;
-			goto isdir;
-		}
-
-		/* If nothing changed, period, ring the bell. */
-		if (!trydir)
-			(void)sp->gp->scr_bell(sp);
-		return (0);
+		/* Always overwrite the old text. */
+		nlen = STRLEN(cmd.argv[0]->bp);
+		break;
 	default:			/* Multiple matches. */
 		*redrawp = 1;
 		if (txt_fc_col(sp, argc, argv))
@@ -2125,8 +2075,17 @@
 		break;
 	}
 
+	/* Escape the matched part of the path. */
+	if (fstwd)
+		bp = cmd.argv[0]->bp;
+	else {
+		if ((bp = argv_esc(sp, &cmd, cmd.argv[0]->bp, nlen)) == NULL)
+			return (1);
+		nlen = STRLEN(bp);
+	}
+
 	/* Overwrite the expanded text first. */
-	for (t = cmd.argv[0]->bp; len > 0 && nlen > 0; --len, --nlen)
+	for (t = bp; len > 0 && nlen > 0; --len, --nlen)
 		*p++ = *t++;
 
 	/* If lost text, make the remaining old text overwrite characters. */
@@ -2142,7 +2101,7 @@
 	/* Shift remaining text up, and move the cursor to the end. */
 	if (nlen) {
 		off = p - tp->lb;
-		BINC_RET(sp, tp->lb, tp->lb_len, tp->len + nlen);
+		BINC_RETW(sp, tp->lb, tp->lb_len, tp->len + nlen);
 		p = tp->lb + off;
 
 		tp->cno += nlen;
@@ -2149,19 +2108,29 @@
 		tp->len += nlen;
 
 		if (tp->insert != 0)
-			(void)memmove(p + nlen, p, tp->insert);
+			(void)MEMMOVE(p + nlen, p, tp->insert);
 		while (nlen--)
 			*p++ = *t++;
 	}
 
-	/* If a single match and it's a directory, retry it. */
-	if (argc == 1 && !stat(cmd.argv[0]->bp, &sb) && S_ISDIR(sb.st_mode)) {
-isdir:		if (tp->owrite == 0) {
+	if (!fstwd)
+		FREE_SPACEW(sp, bp, 0);
+
+	/* If not a single match of path, we've done. */
+	if (argc != 1 || fstwd)
+		return (0);
+
+	/* If a single match and it's a directory, append a '/'. */
+	INT2CHAR(sp, cmd.argv[0]->bp, cmd.argv[0]->len + 1, np, nplen);
+	if ((epd = expanduser(np)) != NULL)
+		np = epd;
+	if (!stat(np, &sb) && S_ISDIR(sb.st_mode)) {
+		if (tp->owrite == 0) {
 			off = p - tp->lb;
-			BINC_RET(sp, tp->lb, tp->lb_len, tp->len + 1);
+			BINC_RETW(sp, tp->lb, tp->lb_len, tp->len + 1);
 			p = tp->lb + off;
 			if (tp->insert != 0)
-				(void)memmove(p + 1, p, tp->insert);
+				(void)MEMMOVE(p + 1, p, tp->insert);
 			++tp->len;
 		} else
 			--tp->owrite;
@@ -2168,10 +2137,8 @@
 
 		++tp->cno;
 		*p++ = '/';
-
-		trydir = 1;
-		goto retry;
 	}
+	free(epd);
 	return (0);
 }
 
@@ -2180,10 +2147,7 @@
  *	Display file names for file name completion.
  */
 static int
-txt_fc_col(sp, argc, argv)
-	SCR *sp;
-	int argc;
-	ARGS **argv;
+txt_fc_col(SCR *sp, int argc, ARGS **argv)
 {
 	ARGS **av;
 	CHAR_T *p;
@@ -2190,17 +2154,21 @@
 	GS *gp;
 	size_t base, cnt, col, colwidth, numrows, numcols, prefix, row;
 	int ac, nf, reset;
+	char *np, *pp;
+	size_t nlen;
 
 	gp = sp->gp;
 
 	/* Trim any directory prefix common to all of the files. */
-	if ((p = strrchr(argv[0]->bp, '/')) == NULL)
+	INT2CHAR(sp, argv[0]->bp, argv[0]->len + 1, np, nlen);
+	if ((pp = strrchr(np, '/')) == NULL)
 		prefix = 0;
 	else {
-		prefix = (p - argv[0]->bp) + 1;
+		prefix = (pp - np) + 1;
 		for (ac = argc - 1, av = argv + 1; ac > 0; --ac, ++av)
 			if (av[0]->len < prefix ||
-			    memcmp(av[0]->bp, argv[0]->bp, prefix)) {
+			    MEMCMP(av[0]->bp, argv[0]->bp, 
+				   prefix)) {
 				prefix = 0;
 				break;
 			}
@@ -2215,7 +2183,7 @@
 	 */
 	for (ac = argc, av = argv, colwidth = 0; ac > 0; --ac, ++av) {
 		for (col = 0, p = av[0]->bp + prefix; *p != '\0'; ++p)
-			col += KEY_LEN(sp, *p);
+			col += KEY_COL(sp, *p);
 		if (col > colwidth)
 			colwidth = col;
 	}
@@ -2236,15 +2204,17 @@
 		goto intr;
 
 	/* If the largest file name is too large, just print them. */
-	if (colwidth > sp->cols) {
+	if (colwidth >= sp->cols) {
 		for (ac = argc, av = argv; ac > 0; --ac, ++av) {
-			p = msg_print(sp, av[0]->bp + prefix, &nf);
-			(void)ex_printf(sp, "%s\n", p);
+			INT2CHAR(sp, av[0]->bp+prefix, av[0]->len+1-prefix,
+				 np, nlen);
+			pp = msg_print(sp, np, &nf);
+			(void)ex_printf(sp, "%s\n", pp);
+			if (nf)
+				FREE_SPACE(sp, pp, 0);
 			if (F_ISSET(gp, G_INTERRUPTED))
 				break;
 		}
-		if (nf)
-			FREE_SPACE(sp, p, 0);
 		CHK_INTR;
 	} else {
 		/* Figure out the number of columns. */
@@ -2259,10 +2229,12 @@
 		/* Display the files in sorted order. */
 		for (row = 0; row < numrows; ++row) {
 			for (base = row, col = 0; col < numcols; ++col) {
-				p = msg_print(sp, argv[base]->bp + prefix, &nf);
-				cnt = ex_printf(sp, "%s", p);
+				INT2CHAR(sp, argv[base]->bp+prefix, 
+					argv[base]->len+1-prefix, np, nlen);
+				pp = msg_print(sp, np, &nf);
+				cnt = ex_printf(sp, "%s", pp);
 				if (nf)
-					FREE_SPACE(sp, p, 0);
+					FREE_SPACE(sp, pp, 0);
 				CHK_INTR;
 				if ((base += numrows) >= argc)
 					break;
@@ -2292,14 +2264,12 @@
  *	Set the end mark on the line.
  */
 static int
-txt_emark(sp, tp, cno)
-	SCR *sp;
-	TEXT *tp;
-	size_t cno;
+txt_emark(SCR *sp, TEXT *tp, size_t cno)
 {
-	CHAR_T ch, *kp;
+	CHAR_T ch;
+	u_char *kp;
 	size_t chlen, nlen, olen;
-	char *p;
+	CHAR_T *p;
 
 	ch = CH_ENDMARK;
 
@@ -2307,11 +2277,11 @@
 	 * The end mark may not be the same size as the current character.
 	 * Don't let the line shift.
 	 */
-	nlen = KEY_LEN(sp, ch);
+	nlen = KEY_COL(sp, ch);
 	if (tp->lb[cno] == '\t')
 		(void)vs_columns(sp, tp->lb, tp->lno, &cno, &olen);
 	else
-		olen = KEY_LEN(sp, tp->lb[cno]);
+		olen = KEY_COL(sp, tp->lb[cno]);
 
 	/*
 	 * If the line got longer, well, it's weird, but it's easy.  If
@@ -2319,20 +2289,22 @@
 	 * to fix it up.
 	 */
 	if (olen > nlen) {
-		BINC_RET(sp, tp->lb, tp->lb_len, tp->len + olen);
+		BINC_RETW(sp, tp->lb, tp->lb_len, tp->len + olen);
 		chlen = olen - nlen;
 		if (tp->insert != 0)
-			memmove(tp->lb + cno + 1 + chlen,
+			MEMMOVE(tp->lb + cno + 1 + chlen,
 			    tp->lb + cno + 1, tp->insert);
 
 		tp->len += chlen;
 		tp->owrite += chlen;
 		p = tp->lb + cno;
-		if (tp->lb[cno] == '\t')
+		if (tp->lb[cno] == '\t' ||
+		    KEY_NEEDSWIDE(sp, tp->lb[cno]))
 			for (cno += chlen; chlen--;)
 				*p++ = ' ';
 		else
-			for (kp = KEY_NAME(sp, tp->lb[cno]),
+			for (kp = (u_char *)
+			    KEY_NAME(sp, tp->lb[cno]),
 			    cno += chlen; chlen--;)
 				*p++ = *kp++;
 	}
@@ -2345,9 +2317,7 @@
  *	Handle an error during input processing.
  */
 static void
-txt_err(sp, tiqh)
-	SCR *sp;
-	TEXTH *tiqh;
+txt_err(SCR *sp, TEXTH *tiqh)
 {
 	recno_t lno;
 
@@ -2360,7 +2330,7 @@
 	 * We depend on at least one line number being set in the text
 	 * chain.
 	 */
-	for (lno = tiqh->cqh_first->lno;
+	for (lno = TAILQ_FIRST(tiqh)->lno;
 	    !db_exist(sp, lno) && lno > 0; --lno);
 
 	sp->lno = lno == 0 ? 1 : lno;
@@ -2380,14 +2350,12 @@
  * may not be able to enter.
  */
 static int
-txt_hex(sp, tp)
-	SCR *sp;
-	TEXT *tp;
+txt_hex(SCR *sp, TEXT *tp)
 {
 	CHAR_T savec;
 	size_t len, off;
 	u_long value;
-	char *p, *wp;
+	CHAR_T *p, *wp;
 
 	/*
 	 * Null-terminate the string.  Since nul isn't a legal hex value,
@@ -2414,8 +2382,8 @@
 
 	/* Get the value. */
 	errno = 0;
-	value = strtol(wp, NULL, 16);
-	if (errno || value > MAX_CHAR_T) {
+	value = STRTOL(wp, NULL, 16);
+	if (errno || value > UCHAR_MAX) {
 nothex:		tp->lb[tp->cno] = savec;
 		return (0);
 	}
@@ -2430,12 +2398,14 @@
 
 	/* Copy down any overwrite characters. */
 	if (tp->owrite)
-		memmove(tp->lb + tp->cno, tp->lb + tp->cno + len, tp->owrite);
+		MEMMOVE(tp->lb + tp->cno, tp->lb + tp->cno + len, 
+		    tp->owrite);
 
 	/* Copy down any insert characters. */
 	if (tp->insert)
-		memmove(tp->lb + tp->cno + tp->owrite,
-		    tp->lb + tp->cno + tp->owrite + len, tp->insert);
+		MEMMOVE(tp->lb + tp->cno + tp->owrite,
+		    tp->lb + tp->cno + tp->owrite + len, 
+		    tp->insert);
 
 	return (0);
 }
@@ -2460,15 +2430,12 @@
  * of the screen space they require, but that it not overwrite other characters.
  */
 static int
-txt_insch(sp, tp, chp, flags)
-	SCR *sp;
-	TEXT *tp;
-	CHAR_T *chp;
-	u_int flags;
+txt_insch(SCR *sp, TEXT *tp, CHAR_T *chp, u_int flags)
 {
-	CHAR_T *kp, savech;
+	u_char *kp;
+	CHAR_T savech;
 	size_t chlen, cno, copydown, olen, nlen;
-	char *p;
+	CHAR_T *p;
 
 	/*
 	 * The 'R' command does one-for-one replacement, because there's
@@ -2494,7 +2461,7 @@
 			(void)vs_columns(sp, tp->lb, tp->lno, &cno, &nlen);
 			tp->lb[cno] = savech;
 		} else
-			nlen = KEY_LEN(sp, *chp);
+			nlen = KEY_COL(sp, *chp);
 
 		/*
 		 * Eat overwrite characters until we run out of them or we've
@@ -2509,7 +2476,7 @@
 				(void)vs_columns(sp,
 				    tp->lb, tp->lno, &cno, &olen);
 			else
-				olen = KEY_LEN(sp, tp->lb[cno]);
+				olen = KEY_COL(sp, tp->lb[cno]);
 
 			if (olen == nlen) {
 				nlen = 0;
@@ -2519,19 +2486,21 @@
 				++copydown;
 				nlen -= olen;
 			} else {
-				BINC_RET(sp,
+				BINC_RETW(sp,
 				    tp->lb, tp->lb_len, tp->len + olen);
 				chlen = olen - nlen;
-				memmove(tp->lb + cno + 1 + chlen,
-				    tp->lb + cno + 1, tp->owrite + tp->insert);
+				MEMMOVE(tp->lb + cno + 1 + chlen,
+				    tp->lb + cno + 1, 
+				    tp->owrite + tp->insert);
 
 				tp->len += chlen;
 				tp->owrite += chlen;
-				if (tp->lb[cno] == '\t')
+				if (tp->lb[cno] == '\t' ||
+				   KEY_NEEDSWIDE(sp, tp->lb[cno]))
 					for (p = tp->lb + cno + 1; chlen--;)
 						*p++ = ' ';
 				else
-					for (kp =
+					for (kp = (u_char *)
 					    KEY_NAME(sp, tp->lb[cno]) + nlen,
 					    p = tp->lb + cno + 1; chlen--;)
 						*p++ = *kp++;
@@ -2546,7 +2515,7 @@
 		 * into position.
 		 */
 		if (copydown != 0 && (tp->len -= copydown) != 0)
-			memmove(tp->lb + cno, tp->lb + cno + copydown,
+			MEMMOVE(tp->lb + cno, tp->lb + cno + copydown,
 			    tp->owrite + tp->insert + copydown);
 
 		/* If we had enough overwrite characters, we're done. */
@@ -2557,7 +2526,7 @@
 	}
 
 	/* Check to see if the character fits into the input buffer. */
-	BINC_RET(sp, tp->lb, tp->lb_len, tp->len + 1);
+	BINC_RETW(sp, tp->lb, tp->lb_len, tp->len + 1);
 
 	++tp->len;
 	if (tp->insert) {			/* Insert a character. */
@@ -2564,7 +2533,7 @@
 		if (tp->insert == 1)
 			tp->lb[tp->cno + 1] = tp->lb[tp->cno];
 		else
-			memmove(tp->lb + tp->cno + 1,
+			MEMMOVE(tp->lb + tp->cno + 1,
 			    tp->lb + tp->cno, tp->owrite + tp->insert);
 	}
 	tp->lb[tp->cno++] = *chp;
@@ -2576,11 +2545,7 @@
  *	Do an incremental search.
  */
 static int
-txt_isrch(sp, vp, tp, is_flagsp)
-	SCR *sp;
-	VICMD *vp;
-	TEXT *tp;
-	u_int8_t *is_flagsp;
+txt_isrch(SCR *sp, VICMD *vp, TEXT *tp, u_int8_t *is_flagsp)
 {
 	MARK start;
 	recno_t lno;
@@ -2613,7 +2578,7 @@
 	 * If it's a magic shell character, and not quoted, reset the cursor
 	 * to the starting point.
 	 */
-	if (strchr(O_STR(sp, O_SHELLMETA), tp->lb[tp->cno - 1]) != NULL &&
+	if (IS_SHELLMETA(sp, tp->lb[tp->cno - 1]) &&
 	    (tp->cno == 2 || tp->lb[tp->cno - 2] != '\\'))
 		vp->m_final = vp->m_start;
 
@@ -2700,10 +2665,7 @@
  *	Resolve the input text chain into the file.
  */
 static int
-txt_resolve(sp, tiqh, flags)
-	SCR *sp;
-	TEXTH *tiqh;
-	u_int32_t flags;
+txt_resolve(SCR *sp, TEXTH *tiqh, u_int32_t flags)
 {
 	VI_PRIVATE *vip;
 	TEXT *tp;
@@ -2718,7 +2680,7 @@
 	 * about the line will be wrong.
 	 */
 	vip = VIP(sp);
-	tp = tiqh->cqh_first;
+	tp = TAILQ_FIRST(tiqh);
 
 	if (LF_ISSET(TXT_AUTOINDENT))
 		txt_ai_resolve(sp, tp, &changed);
@@ -2725,16 +2687,16 @@
 	else
 		changed = 0;
 	if (db_set(sp, tp->lno, tp->lb, tp->len) ||
-	    changed && vs_change(sp, tp->lno, LINE_RESET))
+	    (changed && vs_change(sp, tp->lno, LINE_RESET)))
 		return (1);
 
-	for (lno = tp->lno; (tp = tp->q.cqe_next) != (void *)&sp->tiq; ++lno) {
+	for (lno = tp->lno; (tp = TAILQ_NEXT(tp, q)) != NULL; ++lno) {
 		if (LF_ISSET(TXT_AUTOINDENT))
 			txt_ai_resolve(sp, tp, &changed);
 		else
 			changed = 0;
 		if (db_append(sp, 0, lno, tp->lb, tp->len) ||
-		    changed && vs_change(sp, tp->lno, LINE_RESET))
+		    (changed && vs_change(sp, tp->lno, LINE_RESET)))
 			return (1);
 	}
 
@@ -2757,9 +2719,7 @@
  * I think not.
  */
 static int
-txt_showmatch(sp, tp)
-	SCR *sp;
-	TEXT *tp;
+txt_showmatch(SCR *sp, TEXT *tp)
 {
 	GS *gp;
 	VCS cs;
@@ -2788,7 +2748,7 @@
 	cs.cs_cno = tp->cno - 1;
 	if (cs_init(sp, &cs))
 		return (1);
-	startc = (endc = cs.cs_ch)  == ')' ? '(' : '{';
+	startc = STRCHR(VIP(sp)->mcs, endc = cs.cs_ch)[-1];
 
 	/* Search for the match. */
 	for (cnt = 1;;) {
@@ -2809,7 +2769,7 @@
 	}
 
 	/* If the match is on the screen, move to it. */
-	if (cs.cs_lno < m.lno || cs.cs_lno == m.lno && cs.cs_cno < m.cno)
+	if (cs.cs_lno < m.lno || (cs.cs_lno == m.lno && cs.cs_cno < m.cno))
 		return (0);
 	sp->lno = cs.cs_lno;
 	sp->cno = cs.cs_cno;
@@ -2826,15 +2786,11 @@
  *	Handle margin wrap.
  */
 static int
-txt_margin(sp, tp, wmtp, didbreak, flags)
-	SCR *sp;
-	TEXT *tp, *wmtp;
-	int *didbreak;
-	u_int32_t flags;
+txt_margin(SCR *sp, TEXT *tp, TEXT *wmtp, int *didbreak, u_int32_t flags)
 {
 	VI_PRIVATE *vip;
 	size_t len, off;
-	char *p, *wp;
+	CHAR_T *p, *wp;
 
 	/* Find the nearest previous blank. */
 	for (off = tp->cno - 1, p = tp->lb + off, len = 0;; --off, --p, ++len) {
@@ -2906,15 +2862,11 @@
  *	Resolve the input line for the 'R' command.
  */
 static void
-txt_Rresolve(sp, tiqh, tp, orig_len)
-	SCR *sp;
-	TEXTH *tiqh;
-	TEXT *tp;
-	const size_t orig_len;
+txt_Rresolve(SCR *sp, TEXTH *tiqh, TEXT *tp, const size_t orig_len)
 {
 	TEXT *ttp;
 	size_t input_len, retain;
-	char *p;
+	CHAR_T *p;
 
 	/*
 	 * Check to make sure that the cursor hasn't moved beyond
@@ -2927,9 +2879,9 @@
 	 * Calculate how many characters the user has entered,
 	 * plus the blanks erased by <carriage-return>/<newline>s.
 	 */
-	for (ttp = tiqh->cqh_first, input_len = 0;;) {
+	for (ttp = TAILQ_FIRST(tiqh), input_len = 0;;) {
 		input_len += ttp == tp ? tp->cno : ttp->len + ttp->R_erase;
-		if ((ttp = ttp->q.cqe_next) == (void *)&sp->tiq)
+		if ((ttp = TAILQ_NEXT(ttp, q)) == NULL)
 			break;
 	}
 
@@ -2950,9 +2902,9 @@
 	if (input_len < orig_len) {
 		retain = MIN(tp->owrite, orig_len - input_len);
 		if (db_get(sp,
-		    tiqh->cqh_first->lno, DBG_FATAL | DBG_NOCACHE, &p, NULL))
+		    TAILQ_FIRST(tiqh)->lno, DBG_FATAL | DBG_NOCACHE, &p, NULL))
 			return;
-		memcpy(tp->lb + tp->cno, p + input_len, retain);
+		MEMCPY(tp->lb + tp->cno, p + input_len, retain);
 		tp->len -= tp->owrite - retain;
 		tp->owrite = 0;
 		tp->insert += retain;
@@ -2964,8 +2916,7 @@
  *	No more characters message.
  */
 static void
-txt_nomorech(sp)
-	SCR *sp;
+txt_nomorech(SCR *sp)
 {
 	msgq(sp, M_BERR, "194|No more characters to erase");
 }

Modified: trunk/contrib/nvi/vi/v_ulcase.c
===================================================================
--- trunk/contrib/nvi/vi/v_ulcase.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/vi/v_ulcase.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -10,7 +10,7 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)v_ulcase.c	10.7 (Berkeley) 3/6/96";
+static const char sccsid[] = "$Id: v_ulcase.c,v 10.12 2011/12/02 19:58:32 zy Exp $";
 #endif /* not lint */
 
 #include <sys/types.h>
@@ -47,14 +47,12 @@
  * PUBLIC: int v_ulcase __P((SCR *, VICMD *));
  */
 int
-v_ulcase(sp, vp)
-	SCR *sp;
-	VICMD *vp;
+v_ulcase(SCR *sp, VICMD *vp)
 {
 	recno_t lno;
 	size_t cno, lcnt, len;
 	u_long cnt;
-	char *p;
+	CHAR_T *p;
 
 	lno = vp->m_start.lno;
 	cno = vp->m_start.cno;
@@ -107,9 +105,7 @@
  * PUBLIC: int v_mulcase __P((SCR *, VICMD *));
  */
 int
-v_mulcase(sp, vp)
-	SCR *sp;
-	VICMD *vp;
+v_mulcase(SCR *sp, VICMD *vp)
 {
 	CHAR_T *p;
 	size_t len;
@@ -145,28 +141,24 @@
  *	Change part of a line's case.
  */
 static int
-ulcase(sp, lno, lp, len, scno, ecno)
-	SCR *sp;
-	recno_t lno;
-	CHAR_T *lp;
-	size_t len, scno, ecno;
+ulcase(SCR *sp, recno_t lno, CHAR_T *lp, size_t len, size_t scno, size_t ecno)
 {
 	size_t blen;
 	int change, rval;
-	CHAR_T ch, *p, *t;
-	char *bp;
+	ARG_CHAR_T ch;
+	CHAR_T *p, *t, *bp;
 
-	GET_SPACE_RET(sp, bp, blen, len);
-	memmove(bp, lp, len);
+	GET_SPACE_RETW(sp, bp, blen, len);
+	MEMMOVE(bp, lp, len);
 
 	change = rval = 0;
 	for (p = bp + scno, t = bp + ecno + 1; p < t; ++p) {
-		ch = *(u_char *)p;
-		if (islower(ch)) {
-			*p = toupper(ch);
+		ch = (UCHAR_T)*p;
+		if (ISLOWER(ch)) {
+			*p = TOUPPER(ch);
 			change = 1;
-		} else if (isupper(ch)) {
-			*p = tolower(ch);
+		} else if (ISUPPER(ch)) {
+			*p = TOLOWER(ch);
 			change = 1;
 		}
 	}
@@ -174,6 +166,6 @@
 	if (change && db_set(sp, lno, bp, len))
 		rval = 1;
 
-	FREE_SPACE(sp, bp, blen);
+	FREE_SPACEW(sp, bp, blen);
 	return (rval);
 }

Modified: trunk/contrib/nvi/vi/v_undo.c
===================================================================
--- trunk/contrib/nvi/vi/v_undo.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/vi/v_undo.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -10,7 +10,7 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)v_undo.c	10.5 (Berkeley) 3/6/96";
+static const char sccsid[] = "$Id: v_undo.c,v 10.6 2001/06/25 15:19:36 skimo Exp $";
 #endif /* not lint */
 
 #include <sys/types.h>
@@ -34,9 +34,7 @@
  * PUBLIC: int v_Undo __P((SCR *, VICMD *));
  */
 int
-v_Undo(sp, vp)
-	SCR *sp;
-	VICMD *vp;
+v_Undo(SCR *sp, VICMD *vp)
 {
 	/*
 	 * Historically, U reset the cursor to the first column in the line
@@ -70,9 +68,7 @@
  * PUBLIC: int v_undo __P((SCR *, VICMD *));
  */
 int
-v_undo(sp, vp)
-	SCR *sp;
-	VICMD *vp;
+v_undo(SCR *sp, VICMD *vp)
 {
 	EXF *ep;
 

Modified: trunk/contrib/nvi/vi/v_util.c
===================================================================
--- trunk/contrib/nvi/vi/v_util.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/vi/v_util.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -10,7 +10,7 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)v_util.c	10.11 (Berkeley) 6/30/96";
+static const char sccsid[] = "$Id: v_util.c,v 10.14 2001/06/25 15:19:36 skimo Exp $";
 #endif /* not lint */
 
 #include <sys/types.h>
@@ -35,9 +35,7 @@
  * PUBLIC: void v_eof __P((SCR *, MARK *));
  */
 void
-v_eof(sp, mp)
-	SCR *sp;
-	MARK *mp;
+v_eof(SCR *sp, MARK *mp)
 {
 	recno_t lno;
 
@@ -60,9 +58,7 @@
  * PUBLIC: void v_eol __P((SCR *, MARK *));
  */
 void
-v_eol(sp, mp)
-	SCR *sp;
-	MARK *mp;
+v_eol(SCR *sp, MARK *mp)
 {
 	size_t len;
 
@@ -85,8 +81,7 @@
  * PUBLIC: void v_nomove __P((SCR *));
  */
 void
-v_nomove(sp)
-	SCR *sp;
+v_nomove(SCR *sp)
 {
 	msgq(sp, M_BERR, "197|No cursor movement made");
 }
@@ -98,9 +93,7 @@
  * PUBLIC: void v_sof __P((SCR *, MARK *));
  */
 void
-v_sof(sp, mp)
-	SCR *sp;
-	MARK *mp;
+v_sof(SCR *sp, MARK *mp)
 {
 	if (mp == NULL || mp->lno == 1)
 		msgq(sp, M_BERR, "198|Already at the beginning of the file");
@@ -115,8 +108,7 @@
  * PUBLIC: void v_sol __P((SCR *));
  */
 void
-v_sol(sp)
-	SCR *sp;
+v_sol(SCR *sp)
 {
 	msgq(sp, M_BERR, "200|Already in the first column");
 }
@@ -125,12 +117,10 @@
  * v_isempty --
  *	Return if the line contains nothing but white-space characters.
  *
- * PUBLIC: int v_isempty __P((char *, size_t));
+ * PUBLIC: int v_isempty __P((CHAR_T *, size_t));
  */
 int
-v_isempty(p, len)
-	char *p;
-	size_t len;
+v_isempty(CHAR_T *p, size_t len)
 {
 	for (; len--; ++p)
 		if (!isblank(*p))
@@ -145,10 +135,7 @@
  * PUBLIC: void v_emsg __P((SCR *, char *, vim_t));
  */
 void
-v_emsg(sp, p, which)
-	SCR *sp;
-	char *p;
-	vim_t which;
+v_emsg(SCR *sp, char *p, vim_t which)
 {
 	switch (which) {
 	case VIM_COMBUF:

Modified: trunk/contrib/nvi/vi/v_word.c
===================================================================
--- trunk/contrib/nvi/vi/v_word.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/vi/v_word.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -10,7 +10,7 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)v_word.c	10.5 (Berkeley) 3/6/96";
+static const char sccsid[] = "$Id: v_word.c,v 10.7 2011/12/27 00:49:31 zy Exp $";
 #endif /* not lint */
 
 #include <sys/types.h>
@@ -77,9 +77,7 @@
  * PUBLIC: int v_wordW __P((SCR *, VICMD *));
  */
 int
-v_wordW(sp, vp)
-	SCR *sp;
-	VICMD *vp;
+v_wordW(SCR *sp, VICMD *vp)
 {
 	return (fword(sp, vp, BIGWORD));
 }
@@ -91,9 +89,7 @@
  * PUBLIC: int v_wordw __P((SCR *, VICMD *));
  */
 int
-v_wordw(sp, vp)
-	SCR *sp;
-	VICMD *vp;
+v_wordw(SCR *sp, VICMD *vp)
 {
 	return (fword(sp, vp, LITTLEWORD));
 }
@@ -103,10 +99,7 @@
  *	Move forward by words.
  */
 static int
-fword(sp, vp, type)
-	SCR *sp;
-	VICMD *vp;
-	enum which type;
+fword(SCR *sp, VICMD *vp, enum which type)
 {
 	enum { INWORD, NOTWORD } state;
 	VCS cs;
@@ -125,7 +118,7 @@
 	 *	counts as a single word move.  If it's a motion command,
 	 *	don't move off the end of the line.
 	 */
-	if (cs.cs_flags == CS_EMP || cs.cs_flags == 0 && isblank(cs.cs_ch)) {
+	if (cs.cs_flags == CS_EMP || (cs.cs_flags == 0 && ISBLANK(cs.cs_ch))) {
 		if (ISMOTION(vp) && cs.cs_flags != CS_EMP && cnt == 1) {
 			if (ISCMD(vp->rkp, 'c'))
 				return (0);
@@ -153,7 +146,7 @@
 					return (1);
 				if (cs.cs_flags == CS_EOF)
 					goto ret;
-				if (cs.cs_flags != 0 || isblank(cs.cs_ch))
+				if (cs.cs_flags != 0 || ISBLANK(cs.cs_ch))
 					break;
 			}
 			/*
@@ -185,7 +178,7 @@
 					return (1);
 				if (cs.cs_flags == CS_EOF)
 					goto ret;
-				if (cs.cs_flags != 0 || isblank(cs.cs_ch))
+				if (cs.cs_flags != 0 || ISBLANK(cs.cs_ch))
 					break;
 				if (state == INWORD) {
 					if (!inword(cs.cs_ch))
@@ -204,7 +197,7 @@
 			}
 
 			/* Eat whitespace characters. */
-			if (cs.cs_flags != 0 || isblank(cs.cs_ch))
+			if (cs.cs_flags != 0 || ISBLANK(cs.cs_ch))
 				if (cs_fblank(sp, &cs))
 					return (1);
 			if (cs.cs_flags == CS_EOF)
@@ -244,9 +237,7 @@
  * PUBLIC: int v_wordE __P((SCR *, VICMD *));
  */
 int
-v_wordE(sp, vp)
-	SCR *sp;
-	VICMD *vp;
+v_wordE(SCR *sp, VICMD *vp)
 {
 	return (eword(sp, vp, BIGWORD));
 }
@@ -258,9 +249,7 @@
  * PUBLIC: int v_worde __P((SCR *, VICMD *));
  */
 int
-v_worde(sp, vp)
-	SCR *sp;
-	VICMD *vp;
+v_worde(SCR *sp, VICMD *vp)
 {
 	return (eword(sp, vp, LITTLEWORD));
 }
@@ -270,10 +259,7 @@
  *	Move forward to the end of the word.
  */
 static int
-eword(sp, vp, type)
-	SCR *sp;
-	VICMD *vp;
-	enum which type;
+eword(SCR *sp, VICMD *vp, enum which type)
 {
 	enum { INWORD, NOTWORD } state;
 	VCS cs;
@@ -291,10 +277,10 @@
 	 * it.  (This doesn't count as a word move.)  Stay at the character
 	 * past the current one, it sets word "state" for the 'e' command.
 	 */
-	if (cs.cs_flags == 0 && !isblank(cs.cs_ch)) {
+	if (cs.cs_flags == 0 && !ISBLANK(cs.cs_ch)) {
 		if (cs_next(sp, &cs))
 			return (1);
-		if (cs.cs_flags == 0 && !isblank(cs.cs_ch))
+		if (cs.cs_flags == 0 && !ISBLANK(cs.cs_ch))
 			goto start;
 	}
 	if (cs_fblank(sp, &cs))
@@ -313,7 +299,7 @@
 					return (1);
 				if (cs.cs_flags == CS_EOF)
 					goto ret;
-				if (cs.cs_flags != 0 || isblank(cs.cs_ch))
+				if (cs.cs_flags != 0 || ISBLANK(cs.cs_ch))
 					break;
 			}
 			/*
@@ -342,7 +328,7 @@
 					return (1);
 				if (cs.cs_flags == CS_EOF)
 					goto ret;
-				if (cs.cs_flags != 0 || isblank(cs.cs_ch))
+				if (cs.cs_flags != 0 || ISBLANK(cs.cs_ch))
 					break;
 				if (state == INWORD) {
 					if (!inword(cs.cs_ch))
@@ -359,7 +345,7 @@
 			}
 
 			/* Eat whitespace characters. */
-			if (cs.cs_flags != 0 || isblank(cs.cs_ch))
+			if (cs.cs_flags != 0 || ISBLANK(cs.cs_ch))
 				if (cs_fblank(sp, &cs))
 					return (1);
 			if (cs.cs_flags == CS_EOF)
@@ -397,9 +383,7 @@
  * PUBLIC: int v_wordB __P((SCR *, VICMD *));
  */
 int
-v_wordB(sp, vp)
-	SCR *sp;
-	VICMD *vp;
+v_wordB(SCR *sp, VICMD *vp)
 {
 	return (bword(sp, vp, BIGWORD));
 }
@@ -411,9 +395,7 @@
  * PUBLIC: int v_wordb __P((SCR *, VICMD *));
  */
 int
-v_wordb(sp, vp)
-	SCR *sp;
-	VICMD *vp;
+v_wordb(SCR *sp, VICMD *vp)
 {
 	return (bword(sp, vp, LITTLEWORD));
 }
@@ -423,10 +405,7 @@
  *	Move backward by words.
  */
 static int
-bword(sp, vp, type)
-	SCR *sp;
-	VICMD *vp;
-	enum which type;
+bword(SCR *sp, VICMD *vp, enum which type)
 {
 	enum { INWORD, NOTWORD } state;
 	VCS cs;
@@ -445,10 +424,10 @@
 	 * character before the current one, it sets word "state" for the
 	 * 'b' command.
 	 */
-	if (cs.cs_flags == 0 && !isblank(cs.cs_ch)) {
+	if (cs.cs_flags == 0 && !ISBLANK(cs.cs_ch)) {
 		if (cs_prev(sp, &cs))
 			return (1);
-		if (cs.cs_flags == 0 && !isblank(cs.cs_ch))
+		if (cs.cs_flags == 0 && !ISBLANK(cs.cs_ch))
 			goto start;
 	}
 	if (cs_bblank(sp, &cs))
@@ -467,7 +446,7 @@
 					return (1);
 				if (cs.cs_flags == CS_SOF)
 					goto ret;
-				if (cs.cs_flags != 0 || isblank(cs.cs_ch))
+				if (cs.cs_flags != 0 || ISBLANK(cs.cs_ch))
 					break;
 			}
 			/*
@@ -496,7 +475,7 @@
 					return (1);
 				if (cs.cs_flags == CS_SOF)
 					goto ret;
-				if (cs.cs_flags != 0 || isblank(cs.cs_ch))
+				if (cs.cs_flags != 0 || ISBLANK(cs.cs_ch))
 					break;
 				if (state == INWORD) {
 					if (!inword(cs.cs_ch))
@@ -513,7 +492,7 @@
 			}
 
 			/* Eat whitespace characters. */
-			if (cs.cs_flags != 0 || isblank(cs.cs_ch))
+			if (cs.cs_flags != 0 || ISBLANK(cs.cs_ch))
 				if (cs_bblank(sp, &cs))
 					return (1);
 			if (cs.cs_flags == CS_SOF)

Modified: trunk/contrib/nvi/vi/v_xchar.c
===================================================================
--- trunk/contrib/nvi/vi/v_xchar.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/vi/v_xchar.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -10,7 +10,7 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)v_xchar.c	10.9 (Berkeley) 10/23/96";
+static const char sccsid[] = "$Id: v_xchar.c,v 10.10 2001/06/25 15:19:36 skimo Exp $";
 #endif /* not lint */
 
 #include <sys/types.h>
@@ -31,9 +31,7 @@
  * PUBLIC: int v_xchar __P((SCR *, VICMD *));
  */
 int
-v_xchar(sp, vp)
-	SCR *sp;
-	VICMD *vp;
+v_xchar(SCR *sp, VICMD *vp)
 {
 	size_t len;
 	int isempty;
@@ -80,9 +78,7 @@
  * PUBLIC: int v_Xchar __P((SCR *, VICMD *));
  */
 int
-v_Xchar(sp, vp)
-	SCR *sp;
-	VICMD *vp;
+v_Xchar(SCR *sp, VICMD *vp)
 {
 	u_long cnt;
 

Modified: trunk/contrib/nvi/vi/v_yank.c
===================================================================
--- trunk/contrib/nvi/vi/v_yank.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/vi/v_yank.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -10,7 +10,7 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)v_yank.c	10.9 (Berkeley) 5/19/96";
+static const char sccsid[] = "$Id: v_yank.c,v 10.10 2001/06/25 15:19:36 skimo Exp $";
 #endif /* not lint */
 
 #include <sys/types.h>
@@ -42,9 +42,7 @@
  * PUBLIC: int v_yank __P((SCR *, VICMD *));
  */
 int
-v_yank(sp, vp)
-	SCR *sp;
-	VICMD *vp;
+v_yank(SCR *sp, VICMD *vp)
 {
 	size_t len;
 

Modified: trunk/contrib/nvi/vi/v_z.c
===================================================================
--- trunk/contrib/nvi/vi/v_z.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/vi/v_z.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -10,7 +10,7 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)v_z.c	10.10 (Berkeley) 5/16/96";
+static const char sccsid[] = "$Id: v_z.c,v 10.13 2011/12/02 17:26:59 zy Exp $";
 #endif /* not lint */
 
 #include <sys/types.h>
@@ -31,12 +31,10 @@
  * PUBLIC: int v_z __P((SCR *, VICMD *));
  */
 int
-v_z(sp, vp)
-	SCR *sp;
-	VICMD *vp;
+v_z(SCR *sp, VICMD *vp)
 {
 	recno_t lno;
-	u_int value;
+	e_key_t value;
 
 	/*
 	 * The first count is the line to use.  If the value doesn't
@@ -136,9 +134,7 @@
  * PUBLIC: int vs_crel __P((SCR *, long));
  */
 int
-vs_crel(sp, count)
-	SCR *sp;
-	long count;
+vs_crel(SCR *sp, long int count)
 {
 	sp->t_minrows = sp->t_rows = count;
 	if (sp->t_rows > sp->rows - 1)

Modified: trunk/contrib/nvi/vi/v_zexit.c
===================================================================
--- trunk/contrib/nvi/vi/v_zexit.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/vi/v_zexit.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -10,7 +10,7 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)v_zexit.c	10.6 (Berkeley) 4/27/96";
+static const char sccsid[] = "$Id: v_zexit.c,v 10.7 2001/06/25 15:19:37 skimo Exp $";
 #endif /* not lint */
 
 #include <sys/types.h>
@@ -32,9 +32,7 @@
  * PUBLIC: int v_zexit __P((SCR *, VICMD *));
  */
 int
-v_zexit(sp, vp)
-	SCR *sp;
-	VICMD *vp;
+v_zexit(SCR *sp, VICMD *vp)
 {
 	/* Write back any modifications. */
 	if (F_ISSET(sp->ep, F_MODIFIED) &&

Modified: trunk/contrib/nvi/vi/vi.c
===================================================================
--- trunk/contrib/nvi/vi/vi.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/vi/vi.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -10,7 +10,7 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)vi.c	10.57 (Berkeley) 10/13/96";
+static const char sccsid[] = "$Id: vi.c,v 10.61 2011/12/21 13:08:30 zy Exp $";
 #endif /* not lint */
 
 #include <sys/types.h>
@@ -40,7 +40,6 @@
 static void	v_dtoh __P((SCR *));
 static int	v_init __P((SCR *));
 static gcret_t	v_key __P((SCR *, int, EVENT *, u_int32_t));
-static int	v_keyword __P((SCR *));
 static int	v_motion __P((SCR *, VICMD *, VICMD *, int *));
 
 #if defined(DEBUG) && defined(COMLOG)
@@ -62,13 +61,12 @@
  * PUBLIC: int vi __P((SCR **));
  */
 int
-vi(spp)
-	SCR **spp;
+vi(SCR **spp)
 {
 	GS *gp;
 	MARK abs;
 	SCR *next, *sp;
-	VICMD cmd, *vp;
+	VICMD cmd = { 0 }, *vp;
 	VI_PRIVATE *vip;
 	int comcount, mapped, rval;
 
@@ -76,9 +74,8 @@
 	sp = *spp;
 	gp = sp->gp;
 
-	/* Initialize the command structure. */
+	/* Point to the command structure. */
 	vp = &cmd;
-	memset(vp, 0, sizeof(VICMD));
 
 	/* Reset strange attraction. */
 	F_SET(vp, VM_RCM_SET);
@@ -158,8 +155,6 @@
 		case GC_ERR_NOFLUSH:
 			goto gc_err_noflush;
 		case GC_EVENT:
-			if (v_event_exec(sp, vp))
-				goto err;
 			goto gc_event;
 		case GC_FATAL:
 			goto ret;
@@ -347,9 +342,9 @@
 		 * command, since the tag may be moving to the same file.
 		 */
 		if ((F_ISSET(vp, V_ABS) ||
-		    F_ISSET(vp, V_ABS_L) && sp->lno != abs.lno ||
-		    F_ISSET(vp, V_ABS_C) &&
-		    (sp->lno != abs.lno || sp->cno != abs.cno)) &&
+		    (F_ISSET(vp, V_ABS_L) && sp->lno != abs.lno) ||
+		    (F_ISSET(vp, V_ABS_C) &&
+		    (sp->lno != abs.lno || sp->cno != abs.cno))) &&
 		    mark_set(sp, ABSMARK1, &abs, 1))
 			goto err;
 
@@ -405,6 +400,7 @@
 		if (F_ISSET(gp, G_SRESTART) || F_ISSET(sp, SC_EX)) {
 			*spp = sp;
 			v_dtoh(sp);
+			gp->scr_discard(sp, NULL);
 			break;
 		}
 	}
@@ -452,11 +448,13 @@
  *	[count] key [character]
  */
 static gcret_t
-v_cmd(sp, dp, vp, ismotion, comcountp, mappedp)
-	SCR *sp;
-	VICMD *dp, *vp;
-	VICMD *ismotion;	/* Previous key if getting motion component. */
-	int *comcountp, *mappedp;
+v_cmd(
+	SCR *sp,
+	VICMD *dp,
+	VICMD *vp,
+	VICMD *ismotion,	/* Previous key if getting motion component. */
+	int *comcountp,
+	int *mappedp)
 {
 	enum { COMMANDMODE, ISPARTIAL, NOTPARTIAL } cpart;
 	EVENT ev;
@@ -494,7 +492,7 @@
 	if (ismotion == NULL)
 		cpart = NOTPARTIAL;
 
-	/* Pick up optional buffer. */
+	/* Pick up an optional buffer. */
 	if (key == '"') {
 		cpart = ISPARTIAL;
 		if (ismotion != NULL) {
@@ -508,10 +506,10 @@
 	}
 
 	/*
-	 * Pick up optional count, where a leading 0 is not a count,
+	 * Pick up an optional count, where a leading 0 is not a count,
 	 * it's a command.
 	 */
-	if (isdigit(key) && key != '0') {
+	if (ISDIGIT(key) && key != '0') {
 		if (v_count(sp, key, &vp->count))
 			return (GC_ERR);
 		F_SET(vp, VC_C1SET);
@@ -650,7 +648,7 @@
 		 * Don't set the EC_MAPCOMMAND flag, apparently ] is a popular
 		 * vi meta-character, and we don't want the user to wait while
 		 * we time out a possible mapping.  This *appears* to match
-		 * historic vi practice, but with mapping characters, you Just
+		 * historic vi practice, but with mapping characters, You Just
 		 * Never Know.
 		 */
 		KEY(key, 0);
@@ -669,7 +667,7 @@
 	/* Special case: 'z' command. */
 	if (vp->key == 'z') {
 		KEY(vp->character, 0);
-		if (isdigit(vp->character)) {
+		if (ISDIGIT(vp->character)) {
 			if (v_count(sp, vp->character, &vp->count2))
 				return (GC_ERR);
 			F_SET(vp, VC_C2SET);
@@ -678,8 +676,8 @@
 	}
 
 	/*
-	 * Commands that have motion components can be doubled to
-	 * imply the current line.
+	 * Commands that have motion components can be doubled to imply the
+	 * current line.
 	 */
 	if (ismotion != NULL && ismotion->key != key && !LF_ISSET(V_MOVE)) {
 		msgq(sp, M_ERR, "210|%s may not be used as a motion command",
@@ -687,12 +685,12 @@
 		return (GC_ERR);
 	}
 
-	/* Required character. */
+	/* Pick up required trailing character. */
 	if (LF_ISSET(V_CHAR))
 		KEY(vp->character, 0);
 
 	/* Get any associated cursor word. */
-	if (F_ISSET(kp, V_KEYW) && v_keyword(sp))
+	if (F_ISSET(kp, V_KEYW) && v_curword(sp))
 		return (GC_ERR);
 
 	return (GC_OK);
@@ -716,10 +714,11 @@
  * Get resulting motion mark.
  */
 static int
-v_motion(sp, dm, vp, mappedp)
-	SCR *sp;
-	VICMD *dm, *vp;
-	int *mappedp;
+v_motion(
+	SCR *sp,
+	VICMD *dm,
+	VICMD *vp,
+	int *mappedp)
 {
 	VICMD motion;
 	size_t len;
@@ -785,7 +784,7 @@
 		vp->m_stop.lno = sp->lno + motion.count - 1;
 		if (db_get(sp, vp->m_stop.lno, 0, NULL, &len)) {
 			if (vp->m_stop.lno != 1 ||
-			   vp->key != 'c' && vp->key != '!') {
+			   (vp->key != 'c' && vp->key != '!')) {
 				v_emsg(sp, NULL, VIM_EMPTY);
 				return (1);
 			}
@@ -857,7 +856,7 @@
 		 */
 		if (!db_exist(sp, vp->m_stop.lno)) {
 			if (vp->m_stop.lno != 1 ||
-			   vp->key != 'c' && vp->key != '!') {
+			   (vp->key != 'c' && vp->key != '!')) {
 				v_emsg(sp, NULL, VIM_EMPTY);
 				return (1);
 			}
@@ -901,8 +900,8 @@
 		 * Motions are from the from MARK to the to MARK (inclusive).
 		 */
 		if (motion.m_start.lno > motion.m_stop.lno ||
-		    motion.m_start.lno == motion.m_stop.lno &&
-		    motion.m_start.cno > motion.m_stop.cno) {
+		    (motion.m_start.lno == motion.m_stop.lno &&
+		    motion.m_start.cno > motion.m_stop.cno)) {
 			vp->m_start = motion.m_stop;
 			vp->m_stop = motion.m_start;
 		} else {
@@ -929,8 +928,7 @@
  *	Initialize the vi screen.
  */
 static int
-v_init(sp)
-	SCR *sp;
+v_init(SCR *sp)
 {
 	GS *gp;
 	VI_PRIVATE *vip;
@@ -964,12 +962,12 @@
 			sp->t_minrows = sp->t_rows = sp->rows - 1;
 			msgq(sp, M_INFO,
 			    "214|Windows option value is too large, max is %u",
-			    sp->t_rows);
+			    (u_int)sp->t_rows);
 		}
 		sp->t_maxrows = sp->rows - 1;
 	} else
 		sp->t_maxrows = 1;
-	sp->woff = 0;
+	sp->roff = sp->coff = 0;
 
 	/* Create a screen map. */
 	CALLOC_RET(sp, HMAP, SMAP *, SIZE_HMAP(sp), sizeof(SMAP));
@@ -1000,8 +998,7 @@
  *	Move all but the current screen to the hidden queue.
  */
 static void
-v_dtoh(sp)
-	SCR *sp;
+v_dtoh(SCR *sp)
 {
 	GS *gp;
 	SCR *tsp;
@@ -1009,42 +1006,40 @@
 
 	/* Move all screens to the hidden queue, tossing screen maps. */
 	for (hidden = 0, gp = sp->gp;
-	    (tsp = gp->dq.cqh_first) != (void *)&gp->dq; ++hidden) {
+	    (tsp = TAILQ_FIRST(gp->dq)) != NULL; ++hidden) {
 		if (_HMAP(tsp) != NULL) {
 			free(_HMAP(tsp));
 			_HMAP(tsp) = NULL;
 		}
-		CIRCLEQ_REMOVE(&gp->dq, tsp, q);
-		CIRCLEQ_INSERT_TAIL(&gp->hq, tsp, q);
+		TAILQ_REMOVE(gp->dq, tsp, q);
+		TAILQ_INSERT_TAIL(gp->hq, tsp, q);
+		/* XXXX Change if hidden screens per window */
+		gp->scr_discard(tsp, NULL);
 	}
 
 	/* Move current screen back to the display queue. */
-	CIRCLEQ_REMOVE(&gp->hq, sp, q);
-	CIRCLEQ_INSERT_TAIL(&gp->dq, sp, q);
+	TAILQ_REMOVE(gp->hq, sp, q);
+	TAILQ_INSERT_TAIL(gp->dq, sp, q);
 
-	/*
-	 * XXX
-	 * Don't bother internationalizing this message, it's going to
-	 * go away as soon as we have one-line screens.  --TK
-	 */
 	if (hidden > 1)
 		msgq(sp, M_INFO,
-		    "%d screens backgrounded; use :display to list them",
+		    "319|%d screens backgrounded; use :display to list them",
 		    hidden - 1);
 }
 
 /*
- * v_keyword --
- *	Get the word (or non-word) the cursor is on.
+ * v_curword --
+ *	Get the word (tagstring, actually) the cursor is on.
+ *
+ * PUBLIC: int v_curword __P((SCR *));
  */
-static int
-v_keyword(sp)
-	SCR *sp;
+int
+v_curword(SCR *sp)
 {
 	VI_PRIVATE *vip;
 	size_t beg, end, len;
-	int moved, state;
-	char *p;
+	int moved;
+	CHAR_T *p;
 
 	if (db_get(sp, sp->lno, DBG_FATAL, &p, &len))
 		return (1);
@@ -1065,7 +1060,7 @@
 	 * follow the same rule.
 	 */
 	for (moved = 0,
-	    beg = sp->cno; beg < len && isspace(p[beg]); moved = 1, ++beg);
+	    beg = sp->cno; beg < len && ISSPACE(p[beg]); moved = 1, ++beg);
 	if (beg >= len) {
 		msgq(sp, M_BERR, "212|Cursor not in a word");
 		return (1);
@@ -1075,14 +1070,19 @@
 		(void)vs_refresh(sp, 0);
 	}
 
-	/* Find the end of the word. */
-	for (state = inword(p[beg]),
-	    end = beg; ++end < len && state == inword(p[end]););
+	/*
+	 * Find the end of the word.
+	 *
+	 * !!!
+	 * Historically, vi accepted any non-blank as initial character
+	 * when building up a tagstring.  Required by IEEE 1003.1-2001.
+	 */
+	for (end = beg; ++end < len && inword(p[end]););
 
 	vip = VIP(sp);
-	len = (end - beg);
-	BINC_RET(sp, vip->keyw, vip->klen, len);
-	memmove(vip->keyw, p + beg, len);
+	vip->klen = len = (end - beg);
+	BINC_RETW(sp, vip->keyw, vip->keywlen, len+1);
+	MEMMOVE(vip->keyw, p + beg, len);
 	vip->keyw[len] = '\0';				/* XXX */
 	return (0);
 }
@@ -1092,10 +1092,10 @@
  *	Check for a command alias.
  */
 static VIKEYS const *
-v_alias(sp, vp, kp)
-	SCR *sp;
-	VICMD *vp;
-	VIKEYS const *kp;
+v_alias(
+	SCR *sp,
+	VICMD *vp,
+	VIKEYS const *kp)
 {
 	CHAR_T push;
 
@@ -1128,10 +1128,10 @@
  *	Return the next count.
  */
 static int
-v_count(sp, fkey, countp)
-	SCR *sp;
-	ARG_CHAR_T fkey;
-	u_long *countp;
+v_count(
+	SCR *sp,
+	ARG_CHAR_T fkey,
+	u_long *countp)
 {
 	EVENT ev;
 	u_long count, tc;
@@ -1150,7 +1150,7 @@
 				if (v_key(sp, 0, &ev,
 				    EC_MAPCOMMAND | EC_MAPNODIGIT) != GC_OK)
 					return (1);
-			} while (isdigit(ev.e_c));
+			} while (ISDIGIT(ev.e_c));
 			msgq(sp, M_ERR,
 			    "235|Number larger than %lu", ULONG_MAX);
 			return (1);
@@ -1158,7 +1158,7 @@
 		count = tc;
 		if (v_key(sp, 0, &ev, EC_MAPCOMMAND | EC_MAPNODIGIT) != GC_OK)
 			return (1);
-	} while (isdigit(ev.e_c));
+	} while (ISDIGIT(ev.e_c));
 	*countp = count;
 	return (0);
 }
@@ -1168,11 +1168,11 @@
  *	Return the next event.
  */
 static gcret_t
-v_key(sp, command_events, evp, ec_flags)
-	SCR *sp;
-	int command_events;
-	EVENT *evp;
-	u_int32_t ec_flags;
+v_key(
+	SCR *sp,
+	int command_events,
+	EVENT *evp,
+	u_int32_t ec_flags)
 {
 	u_int32_t quote;
 
@@ -1216,10 +1216,6 @@
 			break;
 		case E_WRESIZE:
 			return (GC_ERR);
-		case E_QUIT:
-		case E_WRITE:
-			if (command_events)
-				return (GC_EVENT);
 			/* FALLTHROUGH */
 		default:
 			v_event_err(sp, evp);
@@ -1235,13 +1231,13 @@
  *	Log the contents of the command structure.
  */
 static void
-v_comlog(sp, vp)
-	SCR *sp;
-	VICMD *vp;
+v_comlog(
+	SCR *sp,
+	VICMD *vp)
 {
-	TRACE(sp, "vcmd: %c", vp->key);
+	TRACE(sp, "vcmd: "WC, vp->key);
 	if (F_ISSET(vp, VC_BUFFER))
-		TRACE(sp, " buffer: %c", vp->buffer);
+		TRACE(sp, " buffer: "WC, vp->buffer);
 	if (F_ISSET(vp, VC_C1SET))
 		TRACE(sp, " c1: %lu", vp->count);
 	if (F_ISSET(vp, VC_C2SET))

Modified: trunk/contrib/nvi/vi/vi.h
===================================================================
--- trunk/contrib/nvi/vi/vi.h	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/vi/vi.h	2018-06-10 20:23:48 UTC (rev 10823)
@@ -6,11 +6,11 @@
  *
  * See the LICENSE file for redistribution information.
  *
- *	@(#)vi.h	10.19 (Berkeley) 6/30/96
+ *	$Id: vi.h,v 10.29 2012/02/11 00:33:46 zy Exp $
  */
 
 /* Definition of a vi "word". */
-#define	inword(ch)	(isalnum(ch) || (ch) == '_')
+#define	inword(ch)	((ch) == '_' || (ISGRAPH(ch) && !ISPUNCT(ch)))
 
 typedef struct _vikeys VIKEYS;
 
@@ -188,23 +188,24 @@
  * slot for the colon command line, so there is room to add any screen into
  * another one at screen exit.
  *
- * Lno is the line number.  If doing the historic vi long line folding, off
+ * Lno is the line number.  If doing the historic vi long line folding, soff
  * is the screen offset into the line.  For example, the pair 2:1 would be
  * the first screen of line 2, and 2:2 would be the second.  In the case of
  * long lines, the screen map will tend to be staggered, e.g., 1:1, 1:2, 1:3,
- * 2:1, 3:1, etc.  If doing left-right scrolling, the off field is the screen
+ * 2:1, 3:1, etc.  If doing left-right scrolling, the coff field is the screen
  * column offset into the lines, and can take on any value, as it's adjusted
  * by the user set value O_SIDESCROLL.
  */
 typedef struct _smap {
-	recno_t  lno;		/* 1-N: Physical file line number. */
+	recno_t  lno;	/* 1-N: Physical file line number. */
 	size_t	 coff;		/* 0-N: Column offset in the line. */
 	size_t	 soff;		/* 1-N: Screen offset in the line. */
 
 				/* vs_line() cache information. */
-	size_t	 c_sboff;	/* 0-N: offset of first character byte. */
-	size_t	 c_eboff;	/* 0-N: offset of  last character byte. */
+	size_t	 c_sboff;	/* 0-N: offset of first character on screen. */
+	size_t	 c_eboff;	/* 0-N: offset of  last character on screen. */
 	u_int8_t c_scoff;	/* 0-N: offset into the first character. */
+				/* 255: no character of line visible. */
 	u_int8_t c_eclen;	/* 1-N: columns from the last character. */
 	u_int8_t c_ecsize;	/* 1-N: size of the last character. */
 } SMAP;
@@ -253,8 +254,11 @@
 	size_t	busy_fx;	/* Busy character x coordinate. */
 	size_t	busy_oldy;	/* Saved y coordinate. */
 	size_t	busy_oldx;	/* Saved x coordinate. */
-	struct timeval busy_tv;	/* Busy timer. */
+	struct timespec busy_ts;/* Busy timer. */
 
+	MARK	sel;		/* Select start position. */
+
+	CHAR_T *mcs;		/* Match character list. */
 	char   *ps;		/* Paragraph plus section list. */
 
 	u_long	u_ccnt;		/* Undo command count. */
@@ -351,10 +355,15 @@
  */
 #define	TAB_OFF(c)	COL_OFF((c), O_VAL(sp, O_TABSTOP))
 
+/* If more than one horizontal screen being shown. */
+#define	IS_HSPLIT(sp)							\
+	((sp)->rows != O_VAL(sp, O_LINES))
+/* If more than one vertical screen being shown. */
+#define	IS_VSPLIT(sp)							\
+	((sp)->cols != O_VAL(sp, O_COLUMNS))
 /* If more than one screen being shown. */
 #define	IS_SPLIT(sp)							\
-	((sp)->q.cqe_next != (void *)&(sp)->gp->dq ||			\
-	(sp)->q.cqe_prev != (void *)&(sp)->gp->dq)
+	(IS_HSPLIT(sp) || IS_VSPLIT(sp))
 
 /* Screen adjustment operations. */
 typedef enum { A_DECREASE, A_INCREASE, A_SET } adj_t;
@@ -374,4 +383,4 @@
 	VIM_NOCOM, VIM_NOCOM_B, VIM_USAGE, VIM_WRESIZE
 } vim_t;
 
-#include "vi_extern.h"
+#include "extern.h"

Modified: trunk/contrib/nvi/vi/vs_line.c
===================================================================
--- trunk/contrib/nvi/vi/vs_line.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/vi/vs_line.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -10,11 +10,7 @@
 #include "config.h"
 
 #ifndef lint
-#if 0
-static const char sccsid[] = "@(#)vs_line.c	10.19 (Berkeley) 9/26/96";
-#endif
-static const char rcsid[] =
-  "$MidnightBSD$";
+static const char sccsid[] = "$Id: vs_line.c,v 10.40 2012/02/13 19:22:25 zy Exp $";
 #endif /* not lint */
 
 #include <sys/types.h>
@@ -42,20 +38,19 @@
  * PUBLIC: int vs_line __P((SCR *, SMAP *, size_t *, size_t *));
  */
 int
-vs_line(sp, smp, yp, xp)
-	SCR *sp;
-	SMAP *smp;
-	size_t *xp, *yp;
+vs_line(SCR *sp, SMAP *smp, size_t *yp, size_t *xp)
 {
-	CHAR_T *kp;
+	u_char *kp;
 	GS *gp;
 	SMAP *tsmp;
-	size_t chlen, cno_cnt, cols_per_screen, len, nlen;
+	size_t chlen = 0, cno_cnt, cols_per_screen, len, nlen;
 	size_t offset_in_char, offset_in_line, oldx, oldy;
 	size_t scno, skip_cols, skip_screens;
-	int ch, dne, is_cached, is_partial, is_tab, no_draw;
+	int dne, is_cached, is_partial, is_tab, no_draw;
 	int list_tab, list_dollar;
-	char *p, *cbp, *ecbp, cbuf[128];
+	CHAR_T *p;
+	CHAR_T *cbp, *ecbp, cbuf[128];
+	ARG_CHAR_T ch = '\0';
 
 #if defined(DEBUG) && 0
 	TRACE(sp, "vs_line: row %u: line: %u off: %u\n",
@@ -143,9 +138,9 @@
 		if (O_ISSET(sp, O_NUMBER)) {
 			cols_per_screen -= O_NUMBER_LENGTH;
 			if ((!dne || smp->lno == 1) && skip_cols == 0) {
-				nlen = snprintf(cbuf, sizeof(cbuf),
-				    O_NUMBER_FMT, (u_long)smp->lno);
-				(void)gp->scr_addstr(sp, cbuf, nlen);
+				nlen = snprintf((char*)cbuf,
+				    sizeof(cbuf), O_NUMBER_FMT, (u_long)smp->lno);
+				(void)gp->scr_addstr(sp, (char*)cbuf, nlen);
 			}
 		}
 	}
@@ -197,6 +192,12 @@
 		return (0);
 	}
 
+	/* If we shortened this line in another screen, the cursor
+	 * position may have fallen off.
+	 */
+	if (sp->lno == smp->lno && sp->cno >= len)
+	    sp->cno = len - 1;
+
 	/*
 	 * If we just wrote this or a previous line, we cached the starting
 	 * and ending positions of that line.  The way it works is we keep
@@ -262,8 +263,8 @@
 	/* Do it the hard way, for leftright scrolling screens. */
 	if (O_ISSET(sp, O_LEFTRIGHT)) {
 		for (; offset_in_line < len; ++offset_in_line) {
-			chlen = (ch = *(u_char *)p++) == '\t' && !list_tab ?
-			    TAB_OFF(scno) : KEY_LEN(sp, ch);
+			chlen = (ch = *p++) == '\t' && !list_tab ?
+			    TAB_OFF(scno) : KEY_COL(sp, ch);
 			if ((scno += chlen) >= skip_cols)
 				break;
 		}
@@ -289,8 +290,8 @@
 	/* Do it the hard way, for historic line-folding screens. */
 	else {
 		for (; offset_in_line < len; ++offset_in_line) {
-			chlen = (ch = *(u_char *)p++) == '\t' && !list_tab ?
-			    TAB_OFF(scno) : KEY_LEN(sp, ch);
+			chlen = (ch = *p++) == '\t' && !list_tab ?
+			    TAB_OFF(scno) : KEY_COL(sp, ch);
 			if ((scno += chlen) < cols_per_screen)
 				continue;
 			scno -= cols_per_screen;
@@ -336,14 +337,14 @@
 		cno_cnt = (sp->cno - offset_in_line) + 1;
 
 	/* This is the loop that actually displays characters. */
-	ecbp = (cbp = cbuf) + sizeof(cbuf) - 1;
+	ecbp = (cbp = cbuf) + SIZE(cbuf) - 1;
 	for (is_partial = 0, scno = 0;
 	    offset_in_line < len; ++offset_in_line, offset_in_char = 0) {
-		if ((ch = *(u_char *)p++) == '\t' && !list_tab) {
+		if ((ch = *p++) == '\t' && !list_tab) {
 			scno += chlen = TAB_OFF(scno) - offset_in_char;
 			is_tab = 1;
 		} else {
-			scno += chlen = KEY_LEN(sp, ch) - offset_in_char;
+			scno += chlen = KEY_COL(sp, ch) - offset_in_char;
 			is_tab = 0;
 		}
 
@@ -386,7 +387,10 @@
 		    --cno_cnt == 0 && (F_ISSET(sp, SC_TINPUT) || !is_partial)) {
 			*yp = smp - HMAP;
 			if (F_ISSET(sp, SC_TINPUT))
-				*xp = scno - chlen;
+				if (is_partial)
+					*xp = scno - smp->c_ecsize;
+				else
+					*xp = scno - chlen;
 			else
 				*xp = scno - 1;
 			if (O_ISSET(sp, O_NUMBER) &&
@@ -404,7 +408,7 @@
 
 #define	FLUSH {								\
 	*cbp = '\0';							\
-	(void)gp->scr_addstr(sp, cbuf, cbp - cbuf);			\
+	(void)gp->scr_waddstr(sp, cbuf, cbp - cbuf);			\
 	cbp = cbuf;							\
 }
 		/*
@@ -423,14 +427,26 @@
 		else {
 			if (cbp + chlen >= ecbp)
 				FLUSH;
-			for (kp = KEY_NAME(sp, ch) + offset_in_char; chlen--;)
-				*cbp++ = *kp++;
+
+			/* don't display half a wide character */
+			if (is_partial && CHAR_WIDTH(sp, ch) > 1) {
+				*cbp++ = ' ';
+				break;
+			}
+
+			if (KEY_NEEDSWIDE(sp, ch))
+				*cbp++ = ch;
+			else
+				for (kp = (u_char *)
+				    KEY_NAME(sp, ch) + offset_in_char;
+				    chlen--;)
+					*cbp++ = *kp++;
 		}
 	}
 
 	if (scno < cols_per_screen) {
 		/* If didn't paint the whole line, update the cache. */
-		smp->c_ecsize = smp->c_eclen = KEY_LEN(sp, ch);
+		smp->c_ecsize = smp->c_eclen = KEY_COL(sp, ch);
 		smp->c_eboff = len - 1;
 
 		/*
@@ -444,7 +460,8 @@
 			chlen = KEY_LEN(sp, '$');
 			if (cbp + chlen >= ecbp)
 				FLUSH;
-			for (kp = KEY_NAME(sp, '$'); chlen--;)
+			for (kp = (u_char *)
+			    KEY_NAME(sp, '$'); chlen--;)
 				*cbp++ = *kp++;
 		}
 
@@ -468,8 +485,7 @@
  * PUBLIC: int vs_number __P((SCR *));
  */
 int
-vs_number(sp)
-	SCR *sp;
+vs_number(SCR *sp)
 {
 	GS *gp;
 	SMAP *smp;
@@ -514,8 +530,7 @@
 			break;
 
 		(void)gp->scr_move(sp, smp - HMAP, 0);
-		len = snprintf(nbuf, sizeof(nbuf),
-		    O_NUMBER_FMT, (u_long)smp->lno);
+		len = snprintf(nbuf, sizeof(nbuf), O_NUMBER_FMT, (u_long)smp->lno);
 		(void)gp->scr_addstr(sp, nbuf, len);
 	}
 	(void)gp->scr_move(sp, oldy, oldx);

Modified: trunk/contrib/nvi/vi/vs_msg.c
===================================================================
--- trunk/contrib/nvi/vi/vs_msg.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/vi/vs_msg.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -10,7 +10,7 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)vs_msg.c	10.77 (Berkeley) 10/13/96";
+static const char sccsid[] = "$Id: vs_msg.c,v 10.88 2013/03/19 09:59:03 zy Exp $";
 #endif /* not lint */
 
 #include <sys/types.h>
@@ -56,15 +56,13 @@
  * PUBLIC: void vs_busy __P((SCR *, const char *, busy_t));
  */
 void
-vs_busy(sp, msg, btype)
-	SCR *sp;
-	const char *msg;
-	busy_t btype;
+vs_busy(SCR *sp, const char *msg, busy_t btype)
 {
 	GS *gp;
 	VI_PRIVATE *vip;
 	static const char flagc[] = "|/-\\";
-	struct timeval tv;
+	struct timespec ts, ts_diff;
+	const struct timespec ts_min = { 0, 125000000 };
 	size_t len, notused;
 	const char *p;
 
@@ -89,7 +87,7 @@
 
 		/* Initialize state for updates. */
 		vip->busy_ch = 0;
-		(void)gettimeofday(&vip->busy_tv, NULL);
+		timepoint_steady(&vip->busy_ts);
 
 		/* Save the current cursor. */
 		(void)gp->scr_cursor(sp, &vip->busy_oldy, &vip->busy_oldx);
@@ -122,11 +120,12 @@
 			break;
 
 		/* Update no more than every 1/8 of a second. */
-		(void)gettimeofday(&tv, NULL);
-		if (((tv.tv_sec - vip->busy_tv.tv_sec) * 1000000 +
-		    (tv.tv_usec - vip->busy_tv.tv_usec)) < 125000)
+		timepoint_steady(&ts);
+		ts_diff = ts;
+		timespecsub(&ts_diff, &vip->busy_ts);
+		if (timespeccmp(&ts_diff, &ts_min, <))
 			return;
-		vip->busy_tv = tv;
+		vip->busy_ts = ts;
 
 		/* Display the update. */
 		if (vip->busy_ch == sizeof(flagc) - 1)
@@ -146,8 +145,7 @@
  * PUBLIC: void vs_home __P((SCR *));
  */
 void
-vs_home(sp)
-	SCR *sp;
+vs_home(SCR *sp)
 {
 	(void)sp->gp->scr_move(sp, LASTLINE(sp), 0);
 	(void)sp->gp->scr_refresh(sp, 0);
@@ -157,15 +155,15 @@
  * vs_update --
  *	Update a command.
  *
- * PUBLIC: void vs_update __P((SCR *, const char *, const char *));
+ * PUBLIC: void vs_update __P((SCR *, const char *, const CHAR_T *));
  */
 void
-vs_update(sp, m1, m2)
-	SCR *sp;
-	const char *m1, *m2;
+vs_update(SCR *sp, const char *m1, const CHAR_T *m2)
 {
 	GS *gp;
 	size_t len, mlen, oldx, oldy;
+	CONST char *np;
+	size_t nlen;
 
 	gp = sp->gp;
 
@@ -178,8 +176,10 @@
 	 * expanded, and by the ex substitution confirmation prompt.
 	 */
 	if (F_ISSET(sp, SC_SCR_EXWROTE)) {
+		if (m2 != NULL)
+			INT2CHAR(sp, m2, STRLEN(m2) + 1, np, nlen);
 		(void)ex_printf(sp,
-		    "%s\n", m1 == NULL? "" : m1, m2 == NULL ? "" : m2);
+		    "%s\n", m1 == NULL? "" : m1, m2 == NULL ? "" : np);
 		(void)ex_fflush(sp);
 	}
 
@@ -205,10 +205,10 @@
 	} else
 		len = 0;
 	if (m2 != NULL) {
-		mlen = strlen(m2);
+		mlen = STRLEN(m2);
 		if (len + mlen > sp->cols - 2)
 			mlen = (sp->cols - 2) - len;
-		(void)gp->scr_addstr(sp, m2, mlen);
+		(void)gp->scr_waddstr(sp, m2, mlen);
 	}
 
 	(void)gp->scr_move(sp, oldy, oldx);
@@ -228,11 +228,7 @@
  * PUBLIC: void vs_msg __P((SCR *, mtype_t, char *, size_t));
  */
 void
-vs_msg(sp, mtype, line, len)
-	SCR *sp;
-	mtype_t mtype;
-	char *line;
-	size_t len;
+vs_msg(SCR *sp, mtype_t mtype, char *line, size_t len)
 {
 	GS *gp;
 	VI_PRIVATE *vip;
@@ -394,17 +390,12 @@
  *	Output the text to the screen.
  */
 static void
-vs_output(sp, mtype, line, llen)
-	SCR *sp;
-	mtype_t mtype;
-	const char *line;
-	int llen;
+vs_output(SCR *sp, mtype_t mtype, const char *line, int llen)
 {
-	CHAR_T *kp;
 	GS *gp;
 	VI_PRIVATE *vip;
-	size_t chlen, notused;
-	int ch, len, rlen, tlen;
+	size_t notused;
+	int len, rlen, tlen;
 	const char *p, *t;
 	char *cbp, *ecbp, cbuf[128];
 
@@ -472,7 +463,6 @@
 }
 		ecbp = (cbp = cbuf) + sizeof(cbuf) - 1;
 		for (t = line, tlen = len; tlen--; ++t) {
-			ch = *t;
 			/*
 			 * Replace tabs with spaces, there are places in
 			 * ex that do column calculations without looking
@@ -480,13 +470,9 @@
 			 * <tabs> do their own expansions.  This catches
 			 * <tabs> in things like tag search strings.
 			 */
-			if (ch == '\t')
-				ch = ' ';
-			chlen = KEY_LEN(sp, ch);
-			if (cbp + chlen >= ecbp)
+			if (cbp + 1 >= ecbp)
 				FLUSH;
-			for (kp = KEY_NAME(sp, ch); chlen--;)
-				*cbp++ = *kp++;
+			*cbp++ = *t == '\t' ? ' ' : *t;
 		}
 		if (cbp > cbuf)
 			FLUSH;
@@ -523,9 +509,7 @@
  * PUBLIC: int vs_ex_resolve __P((SCR *, int *));
  */
 int
-vs_ex_resolve(sp, continuep)
-	SCR *sp;
-	int *continuep;
+vs_ex_resolve(SCR *sp, int *continuep)
 {
 	EVENT ev;
 	GS *gp;
@@ -598,7 +582,7 @@
 	 * If we're not the bottom of the split screen stack, the screen
 	 * image itself is wrong, so redraw everything.
 	 */
-	if (sp->q.cqe_next != (void *)&sp->gp->dq)
+	if (TAILQ_NEXT(sp, q) != NULL)
 		F_SET(sp, SC_SCR_REDRAW);
 
 	/* If ex changed the underlying file, the map itself is wrong. */
@@ -649,9 +633,7 @@
  * PUBLIC: int vs_resolve __P((SCR *, SCR *, int));
  */
 int
-vs_resolve(sp, csp, forcewait)
-	SCR *sp, *csp;
-	int forcewait;
+vs_resolve(SCR *sp, SCR *csp, int forcewait)
 {
 	EVENT ev;
 	GS *gp;
@@ -696,12 +678,12 @@
 	 * messages.)  Once this is done, don't trust the cursor.  That
 	 * extra refresh screwed the pooch.
 	 */
-	if (gp->msgq.lh_first != NULL) {
+	if (!SLIST_EMPTY(gp->msgq)) {
 		if (!F_ISSET(sp, SC_SCR_VI) && vs_refresh(sp, 1))
 			return (1);
-		while ((mp = gp->msgq.lh_first) != NULL) {
+		while ((mp = SLIST_FIRST(gp->msgq)) != NULL) {
 			gp->scr_msg(sp, mp->mtype, mp->buf, mp->len);
-			LIST_REMOVE(mp, q);
+			SLIST_REMOVE_HEAD(gp->msgq, q);
 			free(mp->buf);
 			free(mp);
 		}
@@ -758,10 +740,7 @@
  *	Scroll the screen for output.
  */
 static void
-vs_scroll(sp, continuep, wtype)
-	SCR *sp;
-	int *continuep;
-	sw_t wtype;
+vs_scroll(SCR *sp, int *continuep, sw_t wtype)
 {
 	GS *gp;
 	VI_PRIVATE *vip;
@@ -779,7 +758,7 @@
 		(void)gp->scr_deleteln(sp);
 
 		/* If there are screens below us, push them back into place. */
-		if (sp->q.cqe_next != (void *)&sp->gp->dq) {
+		if (TAILQ_NEXT(sp, q) != NULL) {
 			(void)gp->scr_move(sp, LASTLINE(sp), 0);
 			(void)gp->scr_insertln(sp);
 		}
@@ -794,10 +773,7 @@
  *	Prompt the user to continue.
  */
 static void
-vs_wait(sp, continuep, wtype)
-	SCR *sp;
-	int *continuep;
-	sw_t wtype;
+vs_wait(SCR *sp, int *continuep, sw_t wtype)
 {
 	EVENT ev;
 	VI_PRIVATE *vip;
@@ -868,8 +844,7 @@
  *	Draw a dividing line between the screen and the output.
  */
 static void
-vs_divider(sp)
-	SCR *sp;
+vs_divider(SCR *sp)
 {
 	GS *gp;
 	size_t len;
@@ -888,11 +863,7 @@
  *	Save a message for later display.
  */
 static void
-vs_msgsave(sp, mt, p, len)
-	SCR *sp;
-	mtype_t mt;
-	char *p;
-	size_t len;
+vs_msgsave(SCR *sp, mtype_t mt, char *p, size_t len)
 {
 	GS *gp;
 	MSGS *mp_c, *mp_n;
@@ -912,11 +883,13 @@
 	mp_n->mtype = mt;
 
 	gp = sp->gp;
-	if ((mp_c = gp->msgq.lh_first) == NULL) {
-		LIST_INSERT_HEAD(&gp->msgq, mp_n, q);
+	if (SLIST_EMPTY(gp->msgq)) {
+		SLIST_INSERT_HEAD(gp->msgq, mp_n, q);
 	} else {
-		for (; mp_c->q.le_next != NULL; mp_c = mp_c->q.le_next);
-		LIST_INSERT_AFTER(mp_c, mp_n, q);
+		SLIST_FOREACH(mp_c, gp->msgq, q)
+			if (SLIST_NEXT(mp_c, q) == NULL)
+				break;
+		SLIST_INSERT_AFTER(mp_c, mp_n, q);
 	}
 	return;
 

Modified: trunk/contrib/nvi/vi/vs_refresh.c
===================================================================
--- trunk/contrib/nvi/vi/vs_refresh.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/vi/vs_refresh.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -10,11 +10,7 @@
 #include "config.h"
 
 #ifndef lint
-#if 0
-static const char sccsid[] = "@(#)vs_refresh.c	10.44 (Berkeley) 10/13/96";
-#endif
-static const char rcsid[] =
-  "$MidnightBSD$";
+static const char sccsid[] = "$Id: vs_refresh.c,v 10.53 2013/11/01 11:57:36 zy Exp $";
 #endif /* not lint */
 
 #include <sys/types.h>
@@ -44,9 +40,9 @@
  * PUBLIC: int vs_repaint __P((SCR *, EVENT *));
  */
 int
-vs_repaint(sp, evp)
-	SCR *sp;
-	EVENT *evp;
+vs_repaint(
+	SCR *sp,
+	EVENT *evp)
 {
 	SMAP *smp;
 
@@ -66,13 +62,13 @@
  * PUBLIC: int vs_refresh __P((SCR *, int));
  */
 int
-vs_refresh(sp, forcepaint)
-	SCR *sp;
-	int forcepaint;
+vs_refresh(
+	SCR *sp,
+	int forcepaint)
 {
 	GS *gp;
 	SCR *tsp;
-	int need_refresh;
+	int need_refresh = 0;
 	u_int priv_paint, pub_paint;
 
 	gp = sp->gp;
@@ -84,8 +80,7 @@
 	 * that we can find, including status lines.
 	 */
 	if (F_ISSET(sp, SC_SCR_REDRAW))
-		for (tsp = gp->dq.cqh_first;
-		    tsp != (void *)&gp->dq; tsp = tsp->q.cqe_next)
+		TAILQ_FOREACH(tsp, gp->dq, q)
 			if (tsp != sp)
 				F_SET(tsp, SC_SCR_REDRAW | SC_STATUS);
 
@@ -102,8 +97,7 @@
 	priv_paint = VIP_CUR_INVALID | VIP_N_REFRESH;
 	if (O_ISSET(sp, O_NUMBER))
 		priv_paint |= VIP_N_RENUMBER;
-	for (tsp = gp->dq.cqh_first;
-	    tsp != (void *)&gp->dq; tsp = tsp->q.cqe_next)
+	TAILQ_FOREACH(tsp, gp->dq, q)
 		if (tsp != sp && !F_ISSET(tsp, SC_EXIT | SC_EXIT_FORCE) &&
 		    (F_ISSET(tsp, pub_paint) ||
 		    F_ISSET(VIP(tsp), priv_paint))) {
@@ -138,8 +132,7 @@
 	 * And, finally, if we updated any status lines, make sure the cursor
 	 * gets back to where it belongs.
 	 */
-	for (need_refresh = 0, tsp = gp->dq.cqh_first;
-	    tsp != (void *)&gp->dq; tsp = tsp->q.cqe_next)
+	TAILQ_FOREACH(tsp, gp->dq, q)
 		if (F_ISSET(tsp, SC_STATUS)) {
 			need_refresh = 1;
 			vs_resolve(tsp, sp, 0);
@@ -166,9 +159,9 @@
  *	what you're doing.  It's subtle and quick to anger.
  */
 static int
-vs_paint(sp, flags)
-	SCR *sp;
-	u_int flags;
+vs_paint(
+	SCR *sp,
+	u_int flags)
 {
 	GS *gp;
 	SMAP *smp, tmp;
@@ -175,8 +168,8 @@
 	VI_PRIVATE *vip;
 	recno_t lastline, lcnt;
 	size_t cwtotal, cnt, len, notused, off, y;
-	int ch, didpaint, isempty, leftright_warp;
-	char *p;
+	int ch = 0, didpaint, isempty, leftright_warp;
+	CHAR_T *p;
 
 #define	 LNO	sp->lno			/* Current file line. */
 #define	OLNO	vip->olno		/* Remembered file line. */
@@ -338,7 +331,8 @@
 				if (vs_sm_1down(sp))
 					return (1);
 			goto adjust;
-		}
+		} else
+			goto top;	/* XXX No such line. */
 
 		/*
 		 * If less than a half screen from the bottom of the file,
@@ -474,7 +468,7 @@
 #ifdef DEBUG
 	/* Sanity checking. */
 	if (CNO >= len && len != 0) {
-		msgq(sp, M_ERR, "Error: %s/%d: cno (%u) >= len (%u)",
+		msgq(sp, M_ERR, "Error: %s/%d: cno (%zu) >= len (%zu)",
 		     tail(__FILE__), __LINE__, CNO, len);
 		return (1);
 	}
@@ -511,8 +505,8 @@
 		 * Count up the widths of the characters.  If it's a tab
 		 * character, go do it the the slow way.
 		 */
-		for (cwtotal = 0; cnt--; cwtotal += KEY_LEN(sp, ch))
-			if ((ch = *(u_char *)p--) == '\t')
+		for (cwtotal = 0; cnt--; cwtotal += KEY_COL(sp, ch))
+			if ((ch = *(UCHAR_T *)p--) == '\t')
 				goto slow;
 
 		/*
@@ -525,8 +519,8 @@
 		 * If we're moving left, and there's a wide character in the
 		 * current position, go to the end of the character.
 		 */
-		if (KEY_LEN(sp, ch) > 1)
-			cwtotal -= KEY_LEN(sp, ch) - 1;
+		if (KEY_COL(sp, ch) > 1)
+			cwtotal -= KEY_COL(sp, ch) - 1;
 
 		/*
 		 * If the new column moved us off of the current logical line,
@@ -551,9 +545,9 @@
 		 * screen boundary, we can quit.
 		 */
 		for (cwtotal = SCNO; cnt--;) {
-			if ((ch = *(u_char *)p++) == '\t')
+			if ((ch = *(UCHAR_T *)p++) == '\t')
 				goto slow;
-			if ((cwtotal += KEY_LEN(sp, ch)) >= SCREEN_COLS(sp))
+			if ((cwtotal += KEY_COL(sp, ch)) >= SCREEN_COLS(sp))
 				break;
 		}
 
@@ -617,8 +611,8 @@
 		}
 
 		/* Adjust the window towards the end of the line. */
-		if (off == 0 && off + SCREEN_COLS(sp) < cnt ||
-		    off != 0 && off + sp->cols < cnt) {
+		if ((off == 0 && off + SCREEN_COLS(sp) < cnt) ||
+		    (off != 0 && off + sp->cols < cnt)) {
 			do {
 				off += O_VAL(sp, O_SIDESCROLL);
 			} while (off + sp->cols < cnt);
@@ -767,8 +761,7 @@
  *	Update the mode line.
  */
 static void
-vs_modeline(sp)
-	SCR *sp;
+vs_modeline(SCR *sp)
 {
 	static char * const modes[] = {
 		"215|Append",			/* SM_APPEND */
@@ -779,9 +772,9 @@
 	};
 	GS *gp;
 	size_t cols, curcol, curlen, endpoint, len, midpoint;
-	const char *t;
+	const char *t = NULL;
 	int ellipsis;
-	char *p, buf[20];
+	char buf[20];
 
 	gp = sp->gp;
 
@@ -803,19 +796,23 @@
 	/* If more than one screen in the display, show the file name. */
 	curlen = 0;
 	if (IS_SPLIT(sp)) {
-		for (p = sp->frp->name; *p != '\0'; ++p);
-		for (ellipsis = 0, cols = sp->cols / 2; --p > sp->frp->name;) {
+		CHAR_T *wp, *p;
+		size_t l;
+
+		CHAR2INT(sp, sp->frp->name, strlen(sp->frp->name) + 1, wp, l);
+		p = wp + l;
+		for (ellipsis = 0, cols = sp->cols / 2; --p > wp;) {
 			if (*p == '/') {
 				++p;
 				break;
 			}
-			if ((curlen += KEY_LEN(sp, *p)) > cols) {
+			if ((curlen += KEY_COL(sp, *p)) > cols) {
 				ellipsis = 3;
 				curlen +=
 				    KEY_LEN(sp, '.') * 3 + KEY_LEN(sp, ' ');
 				while (curlen > cols) {
 					++p;
-					curlen -= KEY_LEN(sp, *p);
+					curlen -= KEY_COL(sp, *p);
 				}
 				break;
 			}
@@ -829,7 +826,7 @@
 		}
 		for (; *p != '\0'; ++p)
 			(void)gp->scr_addstr(sp,
-			    KEY_NAME(sp, *p), KEY_LEN(sp, *p));
+			    KEY_NAME(sp, *p), KEY_COL(sp, *p));
 	}
 
 	/* Clear the rest of the line. */

Modified: trunk/contrib/nvi/vi/vs_relative.c
===================================================================
--- trunk/contrib/nvi/vi/vs_relative.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/vi/vs_relative.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -10,7 +10,7 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)vs_relative.c	10.11 (Berkeley) 5/13/96";
+static const char sccsid[] = "$Id: vs_relative.c,v 10.19 2011/12/01 15:22:59 zy Exp $";
 #endif /* not lint */
 
 #include <sys/types.h>
@@ -32,9 +32,7 @@
  * PUBLIC: int vs_column __P((SCR *, size_t *));
  */
 int
-vs_column(sp, colp)
-	SCR *sp;
-	size_t *colp;
+vs_column(SCR *sp, size_t *colp)
 {
 	VI_PRIVATE *vip;
 
@@ -55,10 +53,7 @@
  * PUBLIC: size_t vs_screens __P((SCR *, recno_t, size_t *));
  */
 size_t
-vs_screens(sp, lno, cnop)
-	SCR *sp;
-	recno_t lno;
-	size_t *cnop;
+vs_screens(SCR *sp, recno_t lno, size_t *cnop)
 {
 	size_t cols, screens;
 
@@ -98,18 +93,14 @@
  *	Return the screen columns necessary to display the line, or,
  *	if specified, the physical character column within the line.
  *
- * PUBLIC: size_t vs_columns __P((SCR *, char *, recno_t, size_t *, size_t *));
+ * PUBLIC: size_t vs_columns __P((SCR *, CHAR_T *, recno_t, size_t *, size_t *));
  */
 size_t
-vs_columns(sp, lp, lno, cnop, diffp)
-	SCR *sp;
-	char *lp;
-	recno_t lno;
-	size_t *cnop, *diffp;
+vs_columns(SCR *sp, CHAR_T *lp, recno_t lno, size_t *cnop, size_t *diffp)
 {
-	size_t chlen, cno, curoff, last, len, scno;
+	size_t chlen, cno, curoff, last = 0, len, scno;
 	int ch, leftright, listset;
-	char *p;
+	CHAR_T *p;
 
 	/*
 	 * Initialize the screen offset.
@@ -142,11 +133,11 @@
 	 * Initialize the pointer into the buffer and current offset.
 	 */
 	p = lp;
-	curoff = 0;
+	curoff = scno;
 
 	/* Macro to return the display length of any signal character. */
-#define	CHLEN(val) (ch = *(u_char *)p++) == '\t' &&			\
-	    !listset ? TAB_OFF(val) : KEY_LEN(sp, ch);
+#define	CHLEN(val) (ch = *(UCHAR_T *)p++) == '\t' &&			\
+	    !listset ? TAB_OFF(val) : KEY_COL(sp, ch);
 
 	/*
 	 * If folding screens (the historic vi screen format), past the end
@@ -204,10 +195,7 @@
  * PUBLIC: size_t vs_rcm __P((SCR *, recno_t, int));
  */
 size_t
-vs_rcm(sp, lno, islast)
-	SCR *sp;
-	recno_t lno;
-	int islast;
+vs_rcm(SCR *sp, recno_t lno, int islast)
 {
 	size_t len;
 
@@ -233,14 +221,11 @@
  * PUBLIC: size_t vs_colpos __P((SCR *, recno_t, size_t));
  */
 size_t
-vs_colpos(sp, lno, cno)
-	SCR *sp;
-	recno_t lno;
-	size_t cno;
+vs_colpos(SCR *sp, recno_t lno, size_t cno)
 {
 	size_t chlen, curoff, len, llen, off, scno;
-	int ch, leftright, listset;
-	char *lp, *p;
+	int ch = 0, leftright, listset;
+	CHAR_T *lp, *p;
 
 	/* Need the line to go any further. */
 	(void)db_get(sp, lno, 0, &lp, &llen);

Modified: trunk/contrib/nvi/vi/vs_smap.c
===================================================================
--- trunk/contrib/nvi/vi/vs_smap.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/vi/vs_smap.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -10,7 +10,7 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)vs_smap.c	10.25 (Berkeley) 7/12/96";
+static const char sccsid[] = "$Id: vs_smap.c,v 10.31 2011/02/26 13:56:21 skimo Exp $";
 #endif /* not lint */
 
 #include <sys/types.h>
@@ -42,10 +42,7 @@
  * PUBLIC: int vs_change __P((SCR *, recno_t, lnop_t));
  */
 int
-vs_change(sp, lno, op)
-	SCR *sp;
-	recno_t lno;
-	lnop_t op;
+vs_change(SCR *sp, recno_t lno, lnop_t op)
 {
 	VI_PRIVATE *vip;
 	SMAP *p;
@@ -64,7 +61,8 @@
 	 *
 	 * Check for line #2 before going to the end of the file.
 	 */
-	if ((op == LINE_APPEND && lno == 0 || op == LINE_INSERT && lno == 1) &&
+	if (((op == LINE_APPEND && lno == 0) || 
+	    (op == LINE_INSERT && lno == 1)) &&
 	    !db_exist(sp, 2)) {
 		lno = 1;
 		op = LINE_RESET;
@@ -138,11 +136,15 @@
 	case LINE_DELETE:
 		if (vs_sm_delete(sp, lno))
 			return (1);
+		if (sp->lno > lno)
+			--sp->lno;
 		F_SET(vip, VIP_N_RENUMBER);
 		break;
 	case LINE_INSERT:
 		if (vs_sm_insert(sp, lno))
 			return (1);
+		if (sp->lno > lno)
+			++sp->lno;
 		F_SET(vip, VIP_N_RENUMBER);
 		break;
 	case LINE_RESET:
@@ -172,10 +174,7 @@
  * PUBLIC: int vs_sm_fill __P((SCR *, recno_t, pos_t));
  */
 int
-vs_sm_fill(sp, lno, pos)
-	SCR *sp;
-	recno_t lno;
-	pos_t pos;
+vs_sm_fill(SCR *sp, recno_t lno, pos_t pos)
 {
 	SMAP *p, tmp;
 	size_t cnt;
@@ -225,6 +224,16 @@
 top:			HMAP->lno = lno;
 			HMAP->coff = 0;
 			HMAP->soff = 1;
+		} else {
+			/*
+			 * If number of lines HMAP->lno (top line) spans
+			 * changed due to, say reformatting, and now is
+			 * fewer than HMAP->soff, reset so the line is
+			 * redrawn at the top of the screen.
+			 */
+			cnt = vs_screens(sp, HMAP->lno, NULL);
+			if (cnt < HMAP->soff)
+				HMAP->soff = 1;
 		}
 		/* If we fail, just punt. */
 		for (p = HMAP, cnt = sp->t_rows; --cnt; ++p)
@@ -299,9 +308,7 @@
  *	Delete a line out of the SMAP.
  */
 static int
-vs_sm_delete(sp, lno)
-	SCR *sp;
-	recno_t lno;
+vs_sm_delete(SCR *sp, recno_t lno)
 {
 	SMAP *p, *t;
 	size_t cnt_orig;
@@ -349,9 +356,7 @@
  *	Insert a line into the SMAP.
  */
 static int
-vs_sm_insert(sp, lno)
-	SCR *sp;
-	recno_t lno;
+vs_sm_insert(SCR *sp, recno_t lno)
 {
 	SMAP *p, *t;
 	size_t cnt_orig, cnt, coff;
@@ -405,9 +410,7 @@
  *	Reset a line in the SMAP.
  */
 static int
-vs_sm_reset(sp, lno)
-	SCR *sp;
-	recno_t lno;
+vs_sm_reset(SCR *sp, recno_t lno)
 {
 	SMAP *p, *t;
 	size_t cnt_orig, cnt_new, cnt, diff;
@@ -512,11 +515,7 @@
  * PUBLIC: int vs_sm_scroll __P((SCR *, MARK *, recno_t, scroll_t));
  */
 int
-vs_sm_scroll(sp, rp, count, scmd)
-	SCR *sp;
-	MARK *rp;
-	recno_t count;
-	scroll_t scmd;
+vs_sm_scroll(SCR *sp, MARK *rp, recno_t count, scroll_t scmd)
 {
 	SMAP *smp;
 
@@ -573,12 +572,7 @@
  *	Scroll the SMAP up count logical lines.
  */
 static int
-vs_sm_up(sp, rp, count, scmd, smp)
-	SCR *sp;
-	MARK *rp;
-	scroll_t scmd;
-	recno_t count;
-	SMAP *smp;
+vs_sm_up(SCR *sp, MARK *rp, recno_t count, scroll_t scmd, SMAP *smp)
 {
 	int cursor_set, echanged, zset;
 	SMAP *ssmp, s1, s2;
@@ -754,8 +748,7 @@
  * PUBLIC: int vs_sm_1up __P((SCR *));
  */
 int
-vs_sm_1up(sp)
-	SCR *sp;
+vs_sm_1up(SCR *sp)
 {
 	/*
 	 * Delete the top line of the screen.  Shift the screen map
@@ -784,14 +777,19 @@
  *	line and other screens back.
  */
 static int
-vs_deleteln(sp, cnt)
-	SCR *sp;
-	int cnt;
+vs_deleteln(SCR *sp, int cnt)
 {
 	GS *gp;
 	size_t oldy, oldx;
 
 	gp = sp->gp;
+
+	/* If the screen is vertically split, we can't scroll it. */
+	if (IS_VSPLIT(sp)) {
+		F_SET(sp, SC_SCR_REDRAW);
+		return (0);
+	}
+		
 	if (IS_ONELINE(sp))
 		(void)gp->scr_clrtoeol(sp);
 	else {
@@ -811,12 +809,7 @@
  *	Scroll the SMAP down count logical lines.
  */
 static int
-vs_sm_down(sp, rp, count, scmd, smp)
-	SCR *sp;
-	MARK *rp;
-	recno_t count;
-	SMAP *smp;
-	scroll_t scmd;
+vs_sm_down(SCR *sp, MARK *rp, recno_t count, scroll_t scmd, SMAP *smp)
 {
 	SMAP *ssmp, s1, s2;
 	int cursor_set, ychanged, zset;
@@ -967,8 +960,7 @@
  *	Erase the small screen area for the scrolling functions.
  */
 static int
-vs_sm_erase(sp)
-	SCR *sp;
+vs_sm_erase(SCR *sp)
 {
 	GS *gp;
 
@@ -989,8 +981,7 @@
  * PUBLIC: int vs_sm_1down __P((SCR *));
  */
 int
-vs_sm_1down(sp)
-	SCR *sp;
+vs_sm_1down(SCR *sp)
 {
 	/*
 	 * Insert a line at the top of the screen.  Shift the screen map
@@ -1019,14 +1010,19 @@
  *	line and other screens back.
  */
 static int
-vs_insertln(sp, cnt)
-	SCR *sp;
-	int cnt;
+vs_insertln(SCR *sp, int cnt)
 {
 	GS *gp;
 	size_t oldy, oldx;
 
 	gp = sp->gp;
+
+	/* If the screen is vertically split, we can't scroll it. */
+	if (IS_VSPLIT(sp)) {
+		F_SET(sp, SC_SCR_REDRAW);
+		return (0);
+	}
+
 	if (IS_ONELINE(sp)) {
 		(void)gp->scr_move(sp, LASTLINE(sp), 0);
 		(void)gp->scr_clrtoeol(sp);
@@ -1049,9 +1045,7 @@
  * PUBLIC: int vs_sm_next __P((SCR *, SMAP *, SMAP *));
  */
 int
-vs_sm_next(sp, p, t)
-	SCR *sp;
-	SMAP *p, *t;
+vs_sm_next(SCR *sp, SMAP *p, SMAP *t)
 {
 	size_t lcnt;
 
@@ -1079,9 +1073,7 @@
  * PUBLIC: int vs_sm_prev __P((SCR *, SMAP *, SMAP *));
  */
 int
-vs_sm_prev(sp, p, t)
-	SCR *sp;
-	SMAP *p, *t;
+vs_sm_prev(SCR *sp, SMAP *p, SMAP *t)
 {
 	SMAP_FLUSH(t);
 	if (O_ISSET(sp, O_LEFTRIGHT)) {
@@ -1106,9 +1098,7 @@
  * PUBLIC: int vs_sm_cursor __P((SCR *, SMAP **));
  */
 int
-vs_sm_cursor(sp, smpp)
-	SCR *sp;
-	SMAP **smpp;
+vs_sm_cursor(SCR *sp, SMAP **smpp)
 {
 	SMAP *p;
 
@@ -1147,11 +1137,7 @@
  * PUBLIC: int vs_sm_position __P((SCR *, MARK *, u_long, pos_t));
  */
 int
-vs_sm_position(sp, rp, cnt, pos)
-	SCR *sp;
-	MARK *rp;
-	u_long cnt;
-	pos_t pos;
+vs_sm_position(SCR *sp, MARK *rp, u_long cnt, pos_t pos)
 {
 	SMAP *smp;
 	recno_t last;
@@ -1231,11 +1217,7 @@
  * PUBLIC: recno_t vs_sm_nlines __P((SCR *, SMAP *, recno_t, size_t));
  */
 recno_t
-vs_sm_nlines(sp, from_sp, to_lno, max)
-	SCR *sp;
-	SMAP *from_sp;
-	recno_t to_lno;
-	size_t max;
+vs_sm_nlines(SCR *sp, SMAP *from_sp, recno_t to_lno, size_t max)
 {
 	recno_t lno, lcnt;
 

Modified: trunk/contrib/nvi/vi/vs_split.c
===================================================================
--- trunk/contrib/nvi/vi/vs_split.c	2018-06-10 20:21:25 UTC (rev 10822)
+++ trunk/contrib/nvi/vi/vs_split.c	2018-06-10 20:23:48 UTC (rev 10823)
@@ -10,7 +10,7 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)vs_split.c	10.31 (Berkeley) 10/13/96";
+static const char sccsid[] = "$Id: vs_split.c,v 10.42 2001/06/25 15:19:38 skimo Exp $";
 #endif /* not lint */
 
 #include <sys/types.h>
@@ -27,18 +27,23 @@
 #include "../common/common.h"
 #include "vi.h"
 
-static SCR *vs_getbg __P((SCR *, char *));
+typedef enum { HORIZ_FOLLOW, HORIZ_PRECEDE, VERT_FOLLOW, VERT_PRECEDE } jdir_t;
 
+static SCR	*vs_getbg __P((SCR *, char *));
+static void      vs_insert __P((SCR *sp, GS *gp));
+static int	 vs_join __P((SCR *, SCR **, jdir_t *));
+
 /*
  * vs_split --
- *	Create a new screen.
+ *	Create a new screen, horizontally.
  *
  * PUBLIC: int vs_split __P((SCR *, SCR *, int));
  */
 int
-vs_split(sp, new, ccl)
-	SCR *sp, *new;
-	int ccl;		/* Colon-command line split. */
+vs_split(
+	SCR *sp,
+	SCR *new,
+	int ccl)		/* Colon-command line split. */
 {
 	GS *gp;
 	SMAP *smp;
@@ -58,10 +63,6 @@
 	/* Wait for any messages in the screen. */
 	vs_resolve(sp, NULL, 1);
 
-	half = sp->rows / 2;
-	if (ccl && half > 6)
-		half = 6;
-
 	/* Get a new screen map. */
 	CALLOC(sp, _HMAP(new), SMAP *, SIZE_HMAP(sp), sizeof(SMAP));
 	if (_HMAP(new) == NULL)
@@ -70,6 +71,11 @@
 	_HMAP(new)->coff = 0;
 	_HMAP(new)->soff = 1;
 
+	/* Split the screen in half. */
+	half = sp->rows / 2;
+	if (ccl && half > 6)
+		half = 6;
+
 	/*
 	 * Small screens: see vs_refresh.c section 6a.  Set a flag so
 	 * we know to fix the screen up later.
@@ -77,6 +83,7 @@
 	issmallscreen = IS_SMALL(sp);
 
 	/* The columns in the screen don't change. */
+	new->coff = sp->coff;
 	new->cols = sp->cols;
 
 	/*
@@ -93,24 +100,20 @@
 	    !ccl && (vs_sm_cursor(sp, &smp) ? 0 : (smp - HMAP) + 1) >= half;
 	if (splitup) {				/* Old is bottom half. */
 		new->rows = sp->rows - half;	/* New. */
-		new->woff = sp->woff;
+		new->roff = sp->roff;
 		sp->rows = half;		/* Old. */
-		sp->woff += new->rows;
-						/* Link in before old. */
-		CIRCLEQ_INSERT_BEFORE(&gp->dq, sp, new, q);
+		sp->roff += new->rows;
 
 		/*
 		 * If the parent is the bottom half of the screen, shift
 		 * the map down to match on-screen text.
 		 */
-		memmove(_HMAP(sp), _HMAP(sp) + new->rows,
+		memcpy(_HMAP(sp), _HMAP(sp) + new->rows,
 		    (sp->t_maxrows - new->rows) * sizeof(SMAP));
 	} else {				/* Old is top half. */
 		new->rows = half;		/* New. */
 		sp->rows -= half;		/* Old. */
-		new->woff = sp->woff + sp->rows;
-						/* Link in after old. */
-		CIRCLEQ_INSERT_AFTER(&gp->dq, sp, new, q);
+		new->roff = sp->roff + sp->rows;
 	}
 
 	/* Adjust maximum text count. */
@@ -168,6 +171,12 @@
 	if ((new->defscroll = new->t_maxrows / 2) == 0)
 		new->defscroll = 1;
 
+	/* Fit the screen into the logical chain. */
+	vs_insert(new, sp->gp);
+
+	/* Tell the display that we're splitting. */
+	(void)gp->scr_split(sp, new);
+
 	/*
 	 * Initialize the screen flags:
 	 *
@@ -190,6 +199,134 @@
 }
 
 /*
+ * vs_vsplit --
+ *	Create a new screen, vertically.
+ *
+ * PUBLIC: int vs_vsplit __P((SCR *, SCR *));
+ */
+int
+vs_vsplit(SCR *sp, SCR *new)
+{
+	GS *gp;
+	size_t cols;
+
+	gp = sp->gp;
+
+	/* Check to see if it's possible. */
+	if (sp->cols / 2 <= MINIMUM_SCREEN_COLS) {
+		msgq(sp, M_ERR,
+		    "288|Screen must be larger than %d columns to split",
+		    MINIMUM_SCREEN_COLS * 2);
+		return (1);
+	}
+
+	/* Wait for any messages in the screen. */
+	vs_resolve(sp, NULL, 1);
+
+	/* Get a new screen map. */
+	CALLOC(sp, _HMAP(new), SMAP *, SIZE_HMAP(sp), sizeof(SMAP));
+	if (_HMAP(new) == NULL)
+		return (1);
+	_HMAP(new)->lno = sp->lno;
+	_HMAP(new)->coff = 0;
+	_HMAP(new)->soff = 1;
+
+	/*
+	 * Split the screen in half; we have to sacrifice a column to delimit
+	 * the screens.
+	 *
+	 * XXX
+	 * We always split to the right... that makes more sense to me, and
+	 * I don't want to play the stupid games that I play when splitting
+	 * horizontally.
+	 *
+	 * XXX
+	 * We reserve a column for the screen, "knowing" that curses needs
+	 * one.  This should be worked out with the display interface.
+	 */
+	cols = sp->cols / 2;
+	new->cols = sp->cols - cols - 1;
+	sp->cols = cols;
+	new->coff = sp->coff + cols + 1;
+	sp->cno = 0;
+
+	/* Nothing else changes. */
+	new->rows = sp->rows;
+	new->t_rows = sp->t_rows;
+	new->t_maxrows = sp->t_maxrows;
+	new->t_minrows = sp->t_minrows;
+	new->roff = sp->roff;
+	new->defscroll = sp->defscroll;
+	_TMAP(new) = _HMAP(new) + (new->t_rows - 1);
+
+	/* Fit the screen into the logical chain. */
+	vs_insert(new, sp->gp);
+
+	/* Tell the display that we're splitting. */
+	(void)gp->scr_split(sp, new);
+
+	/* Redraw the old screen from scratch. */
+	F_SET(sp, SC_SCR_REFORMAT | SC_STATUS);
+
+	/*
+	 * Initialize the screen flags:
+	 *
+	 * If we're in vi mode in one screen, we don't have to reinitialize.
+	 * This isn't just a cosmetic fix.  The path goes like this:
+	 *
+	 *	return into vi(), SC_SSWITCH set
+	 *	call vs_refresh() with SC_STATUS set
+	 *	call vs_resolve to display the status message
+	 *	call vs_refresh() because the SC_SCR_VI bit isn't set
+	 *
+	 * Things go downhill at this point.
+	 *
+	 * Draw the new screen from scratch, and add a status line.
+	 */
+	F_SET(new,
+	    SC_SCR_REFORMAT | SC_STATUS |
+	    F_ISSET(sp, SC_EX | SC_VI | SC_SCR_VI | SC_SCR_EX));
+	return (0);
+}
+
+/*
+ * vs_insert --
+ *	Insert the new screen into the correct place in the logical
+ *	chain.
+ */
+static void
+vs_insert(SCR *sp, GS *gp)
+{
+	SCR *tsp;
+
+	gp = sp->gp;
+
+	/* Move past all screens with lower row numbers. */
+	TAILQ_FOREACH(tsp, gp->dq, q)
+		if (tsp->roff >= sp->roff)
+			break;
+	/*
+	 * Move past all screens with the same row number and lower
+	 * column numbers.
+	 */
+	for (; tsp != NULL; tsp = TAILQ_NEXT(tsp, q))
+		if (tsp->roff != sp->roff || tsp->coff > sp->coff)
+			break;
+
+	/*
+	 * If we reached the end, this screen goes there.  Otherwise,
+	 * put it before or after the screen where we stopped.
+	 */
+	if (tsp == NULL) {
+		TAILQ_INSERT_TAIL(gp->dq, sp, q);
+	} else if (tsp->roff < sp->roff ||
+	    (tsp->roff == sp->roff && tsp->coff < sp->coff)) {
+		TAILQ_INSERT_AFTER(gp->dq, tsp, sp, q);
+	} else
+		TAILQ_INSERT_BEFORE(tsp, sp, q);
+}
+
+/*
  * vs_discard --
  *	Discard the screen, folding the real-estate into a related screen,
  *	if one exists, and return that screen.
@@ -197,12 +334,14 @@
  * PUBLIC: int vs_discard __P((SCR *, SCR **));
  */
 int
-vs_discard(sp, spp)
-	SCR *sp, **spp;
+vs_discard(SCR *sp, SCR **spp)
 {
-	SCR *nsp;
-	dir_t dir;
+	GS *gp;
+	SCR *tsp, **lp, *list[100];
+	jdir_t jdir;
 
+	gp = sp->gp;
+
 	/*
 	 * Save the old screen's cursor information.
 	 *
@@ -216,68 +355,256 @@
 		F_SET(sp->frp, FR_CURSORSET);
 	}
 
-	/*
-	 * Add into a previous screen and then into a subsequent screen, as
-	 * they're the closest to the current screen.  If that doesn't work,
-	 * there was no screen to join.
-	 */
-	if ((nsp = sp->q.cqe_prev) != (void *)&sp->gp->dq) {
-		nsp->rows += sp->rows;
-		sp = nsp;
-		dir = FORWARD;
-	} else if ((nsp = sp->q.cqe_next) != (void *)&sp->gp->dq) {
-		nsp->woff = sp->woff;
-		nsp->rows += sp->rows;
-		sp = nsp;
-		dir = BACKWARD;
-	} else
-		sp = NULL;
+	/* If no other screens to join, we're done. */
+	if (!IS_SPLIT(sp)) {
+		(void)gp->scr_discard(sp, NULL);
 
-	if (spp != NULL)
-		*spp = sp;
-	if (sp == NULL)
+		if (spp != NULL)
+			*spp = NULL;
 		return (0);
-		
+	}
+
 	/*
-	 * Make no effort to clean up the discarded screen's information.  If
-	 * it's not exiting, we'll do the work when the user redisplays it.
+	 * Find a set of screens that cover one of the screen's borders.
+	 * Check the vertical axis first, for no particular reason.
 	 *
-	 * Small screens: see vs_refresh.c section 6a.  Adjust text line info,
-	 * unless it's a small screen.
-	 *
-	 * Reset the length of the default scroll.
+	 * XXX
+	 * It's possible (I think?), to create a screen that shares no full
+	 * border with any other set of screens, so we can't discard it.  We
+	 * just complain at the user until they clean it up.
 	 */
-	if (!IS_SMALL(sp))
-		sp->t_rows = sp->t_minrows = sp->rows - 1;
-	sp->t_maxrows = sp->rows - 1;
-	sp->defscroll = sp->t_maxrows / 2;
-	*(HMAP + (sp->t_rows - 1)) = *TMAP;
-	TMAP = HMAP + (sp->t_rows - 1);
+	if (vs_join(sp, list, &jdir))
+		return (1);
 
 	/*
-	 * Draw the new screen from scratch, and add a status line.
+	 * Modify the affected screens.  Redraw the modified screen(s) from
+	 * scratch, setting a status line.  If this is ever a performance
+	 * problem we could play games with the map, but I wrote that code
+	 * before and it was never clean or easy.
 	 *
-	 * XXX
-	 * We could play games with the map, if this were ever to be a
-	 * performance problem, but I wrote the code a few times and it
-	 * was never clean or easy.
+	 * Don't clean up the discarded screen's information.  If the screen
+	 * isn't exiting, we'll do the work when the user redisplays it.
 	 */
-	switch (dir) {
-	case FORWARD:
-		vs_sm_fill(sp, OOBLNO, P_TOP);
+	switch (jdir) {
+	case HORIZ_FOLLOW:
+	case HORIZ_PRECEDE:
+		for (lp = &list[0]; (tsp = *lp) != NULL; ++lp) {
+			/*
+			 * Small screens: see vs_refresh.c section 6a.  Adjust
+			 * text line info, unless it's a small screen.
+			 *
+			 * Reset the length of the default scroll.
+			 *
+			 * Reset the map references.
+			 */
+			tsp->rows += sp->rows;
+			if (!IS_SMALL(tsp))
+				tsp->t_rows = tsp->t_minrows = tsp->rows - 1;
+			tsp->t_maxrows = tsp->rows - 1;
+
+			tsp->defscroll = tsp->t_maxrows / 2;
+
+			*(_HMAP(tsp) + (tsp->t_rows - 1)) = *_TMAP(tsp);
+			_TMAP(tsp) = _HMAP(tsp) + (tsp->t_rows - 1);
+
+			switch (jdir) {
+			case HORIZ_FOLLOW:
+				tsp->roff = sp->roff;
+				vs_sm_fill(tsp, OOBLNO, P_TOP);
+				break;
+			case HORIZ_PRECEDE:
+				vs_sm_fill(tsp, OOBLNO, P_BOTTOM);
+				break;
+			default:
+				abort();
+			}
+			F_SET(tsp, SC_STATUS);
+		}
 		break;
-	case BACKWARD:
-		vs_sm_fill(sp, OOBLNO, P_BOTTOM);
+	case VERT_FOLLOW:
+	case VERT_PRECEDE:
+		for (lp = &list[0]; (tsp = *lp) != NULL; ++lp) {
+			if (jdir == VERT_FOLLOW)
+				tsp->coff = sp->coff;
+			tsp->cols += sp->cols + 1;	/* XXX: DIVIDER */
+			vs_sm_fill(tsp, OOBLNO, P_TOP);
+			F_SET(tsp, SC_STATUS);
+		}
 		break;
 	default:
 		abort();
 	}
 
-	F_SET(sp, SC_STATUS);
+	/* Find the closest screen that changed and move to it. */
+	tsp = list[0];
+	if (spp != NULL)
+		*spp = tsp;
+
+	/* Tell the display that we're discarding a screen. */
+	(void)gp->scr_discard(sp, list);
+
 	return (0);
 }
 
 /*
+ * vs_join --
+ *	Find a set of screens that covers a screen's border.
+ */
+static int
+vs_join(SCR *sp, SCR **listp, jdir_t *jdirp)
+{
+	GS *gp;
+	SCR **lp, *tsp;
+	int first;
+	size_t tlen;
+
+	gp = sp->gp;
+
+	/* Check preceding vertical. */
+	for (lp = listp, tlen = sp->rows,
+	    tsp = TAILQ_FIRST(gp->dq);
+	    tsp != NULL; tsp = TAILQ_NEXT(tsp, q)) {
+		if (sp == tsp)
+			continue;
+		/* Test if precedes the screen vertically. */
+		if (tsp->coff + tsp->cols + 1 != sp->coff)
+			continue;
+		/*
+		 * Test if a subset on the vertical axis.  If overlaps the
+		 * beginning or end, we can't join on this axis at all.
+		 */
+		if (tsp->roff > sp->roff + sp->rows)
+			continue;
+		if (tsp->roff < sp->roff) {
+			if (tsp->roff + tsp->rows >= sp->roff)
+				break;
+			continue;
+		}
+		if (tsp->roff + tsp->rows > sp->roff + sp->rows)
+			break;
+#ifdef DEBUG
+		if (tlen < tsp->rows)
+			abort();
+#endif
+		tlen -= tsp->rows;
+		*lp++ = tsp;
+	}
+	if (tlen == 0) {
+		*lp = NULL;
+		*jdirp = VERT_PRECEDE;
+		return (0);
+	}
+
+	/* Check following vertical. */
+	for (lp = listp, tlen = sp->rows,
+	    tsp = TAILQ_FIRST(gp->dq);
+	    tsp != NULL; tsp = TAILQ_NEXT(tsp, q)) {
+		if (sp == tsp)
+			continue;
+		/* Test if follows the screen vertically. */
+		if (tsp->coff != sp->coff + sp->cols + 1)
+			continue;
+		/*
+		 * Test if a subset on the vertical axis.  If overlaps the
+		 * beginning or end, we can't join on this axis at all.
+		 */
+		if (tsp->roff > sp->roff + sp->rows)
+			continue;
+		if (tsp->roff < sp->roff) {
+			if (tsp->roff + tsp->rows >= sp->roff)
+				break;
+			continue;
+		}
+		if (tsp->roff + tsp->rows > sp->roff + sp->rows)
+			break;
+#ifdef DEBUG
+		if (tlen < tsp->rows)
+			abort();
+#endif
+		tlen -= tsp->rows;
+		*lp++ = tsp;
+	}
+	if (tlen == 0) {
+		*lp = NULL;
+		*jdirp = VERT_FOLLOW;
+		return (0);
+	}
+
+	/* Check preceding horizontal. */
+	for (first = 0, lp = listp, tlen = sp->cols,
+	    tsp = TAILQ_FIRST(gp->dq);
+	    tsp != NULL; tsp = TAILQ_NEXT(tsp, q)) {
+		if (sp == tsp)
+			continue;
+		/* Test if precedes the screen horizontally. */
+		if (tsp->roff + tsp->rows != sp->roff)
+			continue;
+		/*
+		 * Test if a subset on the horizontal axis.  If overlaps the
+		 * beginning or end, we can't join on this axis at all.
+		 */
+		if (tsp->coff > sp->coff + sp->cols)
+			continue;
+		if (tsp->coff < sp->coff) {
+			if (tsp->coff + tsp->cols >= sp->coff)
+				break;
+			continue;
+		}
+		if (tsp->coff + tsp->cols > sp->coff + sp->cols)
+			break;
+#ifdef DEBUG
+		if (tlen < tsp->cols)
+			abort();
+#endif
+		tlen -= tsp->cols + first;
+		first = 1;
+		*lp++ = tsp;
+	}
+	if (tlen == 0) {
+		*lp = NULL;
+		*jdirp = HORIZ_PRECEDE;
+		return (0);
+	}
+
+	/* Check following horizontal. */
+	for (first = 0, lp = listp, tlen = sp->cols,
+	    tsp = TAILQ_FIRST(gp->dq);
+	    tsp != NULL; tsp = TAILQ_NEXT(tsp, q)) {
+		if (sp == tsp)
+			continue;
+		/* Test if precedes the screen horizontally. */
+		if (tsp->roff != sp->roff + sp->rows)
+			continue;
+		/*
+		 * Test if a subset on the horizontal axis.  If overlaps the
+		 * beginning or end, we can't join on this axis at all.
+		 */
+		if (tsp->coff > sp->coff + sp->cols)
+			continue;
+		if (tsp->coff < sp->coff) {
+			if (tsp->coff + tsp->cols >= sp->coff)
+				break;
+			continue;
+		}
+		if (tsp->coff + tsp->cols > sp->coff + sp->cols)
+			break;
+#ifdef DEBUG
+		if (tlen < tsp->cols)
+			abort();
+#endif
+		tlen -= tsp->cols + first;
+		first = 1;
+		*lp++ = tsp;
+	}
+	if (tlen == 0) {
+		*lp = NULL;
+		*jdirp = HORIZ_FOLLOW;
+		return (0);
+	}
+	return (1);
+}
+
+/*
  * vs_fg --
  *	Background the current screen, and foreground a new one.
  *
@@ -284,26 +611,29 @@
  * PUBLIC: int vs_fg __P((SCR *, SCR **, CHAR_T *, int));
  */
 int
-vs_fg(sp, nspp, name, newscreen)
-	SCR *sp, **nspp;
-	CHAR_T *name;
-	int newscreen;
+vs_fg(SCR *sp, SCR **nspp, CHAR_T *name, int newscreen)
 {
 	GS *gp;
 	SCR *nsp;
+	char *np;
+	size_t nlen;
 
 	gp = sp->gp;
 
+	if (name)
+	    INT2CHAR(sp, name, STRLEN(name) + 1, np, nlen);
+	else
+	    np = NULL;
 	if (newscreen)
 		/* Get the specified background screen. */
-		nsp = vs_getbg(sp, name);
+		nsp = vs_getbg(sp, np);
 	else
 		/* Swap screens. */
-		if (vs_swap(sp, &nsp, name))
+		if (vs_swap(sp, &nsp, np))
 			return (1);
 
 	if ((*nspp = nsp) == NULL) {
-		msgq_str(sp, M_ERR, name,
+		msgq_wstr(sp, M_ERR, name,
 		    name == NULL ?
 		    "223|There are no background screens" :
 		    "224|There's no background screen editing a file named %s");
@@ -312,17 +642,17 @@
 
 	if (newscreen) {
 		/* Remove the new screen from the background queue. */
-		CIRCLEQ_REMOVE(&gp->hq, nsp, q);
+		TAILQ_REMOVE(gp->hq, nsp, q);
 
 		/* Split the screen; if we fail, hook the screen back in. */
 		if (vs_split(sp, nsp, 0)) {
-			CIRCLEQ_INSERT_TAIL(&gp->hq, nsp, q);
+			TAILQ_INSERT_TAIL(gp->hq, nsp, q);
 			return (1);
 		}
 	} else {
 		/* Move the old screen to the background queue. */
-		CIRCLEQ_REMOVE(&gp->dq, sp, q);
-		CIRCLEQ_INSERT_TAIL(&gp->hq, sp, q);
+		TAILQ_REMOVE(gp->dq, sp, q);
+		TAILQ_INSERT_TAIL(gp->hq, sp, q);
 	}
 	return (0);
 }
@@ -334,8 +664,7 @@
  * PUBLIC: int vs_bg __P((SCR *));
  */
 int
-vs_bg(sp)
-	SCR *sp;
+vs_bg(SCR *sp)
 {
 	GS *gp;
 	SCR *nsp;
@@ -352,8 +681,8 @@
 	}
 
 	/* Move the old screen to the background queue. */
-	CIRCLEQ_REMOVE(&gp->dq, sp, q);
-	CIRCLEQ_INSERT_TAIL(&gp->hq, sp, q);
+	TAILQ_REMOVE(gp->dq, sp, q);
+	TAILQ_INSERT_TAIL(gp->hq, sp, q);
 
 	/* Toss the screen map. */
 	free(_HMAP(sp));
@@ -373,12 +702,10 @@
  * PUBLIC: int vs_swap __P((SCR *, SCR **, char *));
  */
 int
-vs_swap(sp, nspp, name)
-	SCR *sp, **nspp;
-	char *name;
+vs_swap(SCR *sp, SCR **nspp, char *name)
 {
 	GS *gp;
-	SCR *nsp;
+	SCR *nsp, *list[2];
 
 	gp = sp->gp;
 
@@ -409,7 +736,7 @@
 	/* Initialize screen information. */
 	nsp->cols = sp->cols;
 	nsp->rows = sp->rows;	/* XXX: Only place in vi that sets rows. */
-	nsp->woff = sp->woff;
+	nsp->roff = sp->roff;
 
 	/*
 	 * Small screens: see vs_refresh.c, section 6a.
@@ -435,6 +762,7 @@
 	_TMAP(nsp) = _HMAP(nsp) + (nsp->t_rows - 1);
 
 	/* Fill the map. */
+	nsp->gp = sp->gp;
 	if (vs_sm_fill(nsp, nsp->lno, P_FILL))
 		return (1);
 
@@ -444,8 +772,8 @@
 	 * the exit will delete the old one, if we're foregrounding, the fg
 	 * code will move the old one to the background queue.
 	 */
-	CIRCLEQ_REMOVE(&gp->hq, nsp, q);
-	CIRCLEQ_INSERT_AFTER(&gp->dq, sp, nsp, q);
+	TAILQ_REMOVE(gp->hq, nsp, q);
+	TAILQ_INSERT_AFTER(gp->dq, sp, nsp, q);
 
 	/*
 	 * Don't change the screen's cursor information other than to
@@ -455,6 +783,10 @@
 
 	/* Draw the new screen from scratch, and add a status line. */
 	F_SET(nsp, SC_SCR_REDRAW | SC_STATUS);
+
+	list[0] = nsp; list[1] = NULL;
+	(void)gp->scr_discard(sp, list);
+
 	return (0);
 }
 
@@ -465,13 +797,10 @@
  * PUBLIC: int vs_resize __P((SCR *, long, adj_t));
  */
 int
-vs_resize(sp, count, adj)
-	SCR *sp;
-	long count;
-	adj_t adj;
+vs_resize(SCR *sp, long int count, adj_t adj)
 {
 	GS *gp;
-	SCR *g, *s;
+	SCR *g, *s, *prev, *next, *list[3] = {NULL, NULL, NULL};
 	size_t g_off, s_off;
 
 	gp = sp->gp;
@@ -494,6 +823,23 @@
 		}
 	}
 
+	/* Find first overlapping screen */
+	for (next = TAILQ_NEXT(sp, q); next != NULL &&
+	     (next->coff >= sp->coff + sp->cols ||
+	      next->coff + next->cols <= sp->coff);
+	     next = TAILQ_NEXT(next, q));
+	/* See if we can use it */
+	if (next != NULL &&
+	    (sp->coff != next->coff || sp->cols != next->cols))
+		next = NULL;
+	for (prev = TAILQ_PREV(sp, _dqh, q); prev != NULL &&
+	     (prev->coff >= sp->coff + sp->cols ||
+	      prev->coff + prev->cols <= sp->coff);
+	     prev = TAILQ_PREV(prev, _dqh, q));
+	if (prev != NULL &&
+	    (sp->coff != prev->coff || sp->cols != prev->cols))
+		prev = NULL;
+
 	g_off = s_off = 0;
 	if (adj == A_DECREASE) {
 		if (count < 0)
@@ -501,8 +847,8 @@
 		s = sp;
 		if (s->t_maxrows < MINIMUM_SCREEN_ROWS + count)
 			goto toosmall;
-		if ((g = sp->q.cqe_prev) == (void *)&gp->dq) {
-			if ((g = sp->q.cqe_next) == (void *)&gp->dq)
+		if ((g = prev) == NULL) {
+			if ((g = next) == NULL)
 				goto toobig;
 			g_off = -count;
 		} else
@@ -509,15 +855,13 @@
 			s_off = count;
 	} else {
 		g = sp;
-		if ((s = sp->q.cqe_next) != (void *)&gp->dq)
-			if (s->t_maxrows < MINIMUM_SCREEN_ROWS + count)
-				s = NULL;
-			else
+		if ((s = next) != NULL &&
+		    s->t_maxrows >= MINIMUM_SCREEN_ROWS + count)
 				s_off = count;
 		else
 			s = NULL;
 		if (s == NULL) {
-			if ((s = sp->q.cqe_prev) == (void *)&gp->dq) {
+			if ((s = prev) == NULL) {
 toobig:				msgq(sp, M_BERR, adj == A_DECREASE ?
 				    "227|The screen cannot shrink" :
 				    "228|The screen cannot grow");
@@ -539,9 +883,9 @@
 	 * to make it worthwhile.
 	 */
 	s->rows += -count;
-	s->woff += s_off;
+	s->roff += s_off;
 	g->rows += count;
-	g->woff += g_off;
+	g->roff += g_off;
 
 	g->t_rows += count;
 	if (g->t_minrows == g->t_maxrows)
@@ -557,6 +901,10 @@
 	_TMAP(s) -= count;
 	F_SET(s, SC_SCR_REFORMAT | SC_STATUS);
 
+	/* XXXX */
+	list[0] = g; list[1] = s;
+	gp->scr_discard(0, list);
+
 	return (0);
 }
 
@@ -566,9 +914,7 @@
  *	background screen.
  */
 static SCR *
-vs_getbg(sp, name)
-	SCR *sp;
-	char *name;
+vs_getbg(SCR *sp, char *name)
 {
 	GS *gp;
 	SCR *nsp;
@@ -577,22 +923,18 @@
 	gp = sp->gp;
 
 	/* If name is NULL, return the first background screen on the list. */
-	if (name == NULL) {
-		nsp = gp->hq.cqh_first;
-		return (nsp == (void *)&gp->hq ? NULL : nsp);
-	}
+	if (name == NULL)
+		return (TAILQ_FIRST(gp->hq));
 
 	/* Search for a full match. */
-	for (nsp = gp->hq.cqh_first;
-	    nsp != (void *)&gp->hq; nsp = nsp->q.cqe_next)
+	TAILQ_FOREACH(nsp, gp->hq, q)
 		if (!strcmp(nsp->frp->name, name))
 			break;
-	if (nsp != (void *)&gp->hq)
+	if (nsp != NULL)
 		return (nsp);
 
 	/* Search for a last-component match. */
-	for (nsp = gp->hq.cqh_first;
-	    nsp != (void *)&gp->hq; nsp = nsp->q.cqe_next) {
+	TAILQ_FOREACH(nsp, gp->hq, q) {
 		if ((p = strrchr(nsp->frp->name, '/')) == NULL)
 			p = nsp->frp->name;
 		else
@@ -600,7 +942,7 @@
 		if (!strcmp(p, name))
 			break;
 	}
-	if (nsp != (void *)&gp->hq)
+	if (nsp != NULL)
 		return (nsp);
 
 	return (NULL);



More information about the Midnightbsd-cvs mailing list