usr/src/cmd/vi/port/ex_voper.c
changeset 0 68f95e015346
child 802 73b56fb6544b
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/vi/port/ex_voper.c	Tue Jun 14 00:00:00 2005 -0700
@@ -0,0 +1,1216 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
+/*	  All Rights Reserved  	*/
+
+
+/*
+ * Copyright (c) 1981 Regents of the University of California
+ * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+#include "ex.h"
+#include "ex_tty.h"
+#include "ex_vis.h"
+#include <regexpr.h>
+#ifndef PRESUNEUC
+#include <wctype.h>
+/* Undef putchar/getchar if they're defined. */
+#ifdef putchar
+#undef putchar
+#endif
+#ifdef getchar
+#undef getchar
+#endif
+#endif /* PRESUNEUC */
+
+#ifdef PRESUNEUC
+#define	blank()		isspace(wcursor[0])
+#endif /* PRESUNEUC */
+#define	forbid(a)	if (a) goto errlab;
+
+unsigned char	vscandir[2] =	{ '/', 0 };
+
+/*
+ * Decode an operator/operand type command.
+ * Eventually we switch to an operator subroutine in ex_vops.c.
+ * The work here is setting up a function variable to point
+ * to the routine we want, and manipulation of the variables
+ * wcursor and wdot, which mark the other end of the affected
+ * area.  If wdot is zero, then the current line is the other end,
+ * and if wcursor is zero, then the first non-blank location of the
+ * other line is implied.
+ */
+operate(c, cnt)
+	register int c, cnt;
+{
+	register wchar_t i;
+	int (*moveop)(), (*deleteop)();
+	register int (*opf)();
+	bool subop = 0;
+	unsigned char *oglobp, *ocurs;
+	register line *addr;
+	line *odot;
+	int oc;
+	static unsigned char lastFKND;
+	static wchar_t lastFCHR;
+	short d;
+/* #ifdef PTR_ADDRESSES */
+	int mouse_x;
+	int mouse_y;
+	int oline;
+	static int get_addr();
+/* #endif PTR_ADDRESSES */
+
+	moveop = vmove, deleteop = vdelete;
+	wcursor = cursor;
+	wdot = NOLINE;
+	notecnt = 0;
+	dir = 1;
+	switch (c) {
+
+	/*
+	 * d		delete operator.
+	 */
+	case 'd':
+		moveop = vdelete;
+		deleteop = beep;
+		break;
+
+	/*
+	 * s		substitute characters, like c\040, i.e. change space.
+	 */
+	case 's':
+		ungetkey(' ');
+		subop++;
+		/* fall into ... */
+
+	/*
+	 * c		Change operator.
+	 */
+	case 'c':
+		if (c == 'c' && workcmd[0] == 'C' || workcmd[0] == 'S')
+			subop++;
+		moveop = vchange;
+		deleteop = beep;
+		break;
+
+	/*
+	 * !		Filter through a UNIX command.
+	 */
+	case '!':
+		moveop = vfilter;
+		deleteop = beep;
+		break;
+
+	/*
+	 * y		Yank operator.  Place specified text so that it
+	 *		can be put back with p/P.  Also yanks to named buffers.
+	 */
+	case 'y':
+		moveop = vyankit;
+		deleteop = beep;
+		break;
+
+	/*
+	 * =		Reformat operator (for LISP).
+	 */
+	case '=':
+		forbid(!value(vi_LISP));
+		/* fall into ... */
+
+	/*
+	 * >		Right shift operator.
+	 * <		Left shift operator.
+	 */
+	case '<':
+	case '>':
+		moveop = vshftop;
+		deleteop = beep;
+		break;
+
+	/*
+	 * r		Replace character under cursor with single following
+	 *		character.
+	 */
+	case 'r':
+		vmacchng(1);
+		vrep(cnt);
+		return;
+
+	default:
+		goto nocount;
+	}
+	vmacchng(1);
+	/*
+	 * Had an operator, so accept another count.
+	 * Multiply counts together.
+	 */
+	if (isdigit(peekkey()) && peekkey() != '0') {
+		cnt *= vgetcnt();
+		Xcnt = cnt;
+		forbid(cnt <= 0);
+	}
+
+	/*
+	 * Get next character, mapping it and saving as
+	 * part of command for repeat.
+	 */
+	c = map(getesc(), arrows, 0);
+	if (c == 0)
+		return;
+	if (!subop)
+		*lastcp++ = c;
+nocount:
+	opf = moveop;
+	switch (c) {
+
+/* #ifdef PTR_ADDRESSES */
+	/*
+	 * ^X^_		Netty Mouse positioning hack
+	 * ^X^]
+	 */
+	case CTRL('X'):
+/*
+ *	Read in mouse stuff
+ */
+		c = getkey();			/* ^_ or ^] */
+		if ((c != CTRL('_')) && (c != (CTRL(']'))))
+			break;
+		getkey();			/* mouse button */
+		mouse_x = get_addr() + 1;
+		mouse_y = get_addr() + 1;
+		if (mouse_y < WTOP)
+			break;
+		if (Pline == numbline)
+			mouse_x -= 8;
+		if (mouse_x < 0)
+			mouse_x = 0;
+		if (mouse_x > WCOLS)
+			break;
+/*
+ *	Find the line on the screen
+ */
+		for (i = 0; i <= WECHO; i++)
+		{
+			if (vlinfo[i].vliny >= mouse_y)
+				break;
+		}
+		if (i > WECHO)
+			break;
+/*
+ *	Look for lines longer than one line - note  odd case at zero
+ */
+		if (i)
+		{
+			if (vlinfo[i - 1].vdepth > 1)
+			{
+				mouse_x += WCOLS * (mouse_y -
+					(vlinfo[i].vliny -
+					(vlinfo[i - 1].vdepth - 1)));
+			}
+		}
+		else
+		{
+			mouse_x += WCOLS * (mouse_y - 1);
+		}
+/*
+ *	Set the line
+ */
+		vsave();
+		ocurs = cursor;
+		odot = dot;
+		oline = vcline;
+		operate('H', i);
+/*
+ *	Set the column
+ */
+		getDOT();
+		if (Pline == numbline)
+			mouse_x += 8;
+		vmovcol = mouse_x;
+		vmoving = 1;
+		wcursor = vfindcol(mouse_x);
+/*
+ *	Reset everything so that stuff like delete and change work
+ */
+		wdot = (odot - oline) + i - 1;
+		cursor = ocurs;
+		vcline = oline;
+		dot = odot;
+		getDOT();
+		break;
+/* #endif PTR_ADDRESSES */
+
+	/*
+	 * b		Back up a word.
+	 * B		Back up a word, liberal definition.
+	 */
+	case 'b':
+	case 'B':
+		dir = -1;
+		/* fall into ... */
+
+	/*
+	 * w		Forward a word.
+	 * W		Forward a word, liberal definition.
+	 */
+	case 'W':
+	case 'w':
+		wdkind = c & ' ';
+		forbid(lfind(2, cnt, opf, (line *)0) < 0);
+		vmoving = 0;
+		break;
+
+	/*
+	 * E		to end of following blank/nonblank word
+	 */
+	case 'E':
+		wdkind = 0;
+		goto ein;
+
+	/*
+	 * e		To end of following word.
+	 */
+	case 'e':
+		wdkind = 1;
+ein:
+		forbid(lfind(3, cnt - 1, opf, (line *)0) < 0);
+		vmoving = 0;
+		break;
+
+	/*
+	 * (		Back an s-expression.
+	 */
+	case '(':
+		dir = -1;
+		/* fall into... */
+
+	/*
+	 * )		Forward an s-expression.
+	 */
+	case ')':
+		forbid(lfind(0, cnt, opf, (line *) 0) < 0);
+		markDOT();
+		break;
+
+	/*
+	 * {		Back an s-expression, but don't stop on atoms.
+	 *		In text mode, a paragraph.  For C, a balanced set
+	 *		of {}'s.
+	 */
+	case '{':
+		dir = -1;
+		/* fall into... */
+
+	/*
+	 * }		Forward an s-expression, but don't stop on atoms.
+	 *		In text mode, back paragraph.  For C, back a balanced
+	 *		set of {}'s.
+	 */
+	case '}':
+		forbid(lfind(1, cnt, opf, (line *) 0) < 0);
+		markDOT();
+		break;
+
+	/*
+	 * %		To matching () or {}.  If not at ( or { scan for
+	 *		first such after cursor on this line.
+	 */
+	case '%':
+		vsave();
+		ocurs = cursor;
+		odot = wdot = dot;
+		oglobp = globp;
+		CATCH
+			i = lmatchp((line *) 0);
+		ONERR
+			globp = oglobp;
+			dot = wdot = odot;
+			cursor = ocurs;
+			splitw = 0;
+			vclean();
+			vjumpto(dot, ocurs, 0);
+			return;
+		ENDCATCH
+#ifdef TRACE
+		if (trace)
+			fprintf(trace, "after lmatchp in %, dot=%d, wdot=%d, "
+			    "dol=%d\n", lineno(dot), lineno(wdot), lineno(dol));
+#endif
+		getDOT();
+		forbid(!i);
+		if (opf != vmove)
+			if (dir > 0)
+				wcursor++;
+			else
+				cursor++;
+		else
+			markDOT();
+		vmoving = 0;
+		break;
+
+	/*
+	 * [		Back to beginning of defun, i.e. an ( in column 1.
+	 *		For text, back to a section macro.
+	 *		For C, back to a { in column 1 (~~ beg of function.)
+	 */
+	case '[':
+		dir = -1;
+		/* fall into ... */
+
+	/*
+	 * ]		Forward to next defun, i.e. a ( in column 1.
+	 *		For text, forward section.
+	 *		For C, forward to a } in column 1 (if delete or such)
+	 *		or if a move to a { in column 1.
+	 */
+	case ']':
+		if (!vglobp)
+			forbid(getkey() != c);
+#ifndef XPG4
+		forbid(Xhadcnt);
+#endif
+		vsave();
+#ifdef XPG4
+		if (cnt > 1) {
+			while (cnt-- > 1) {
+				i = lbrack(c, opf);
+				getDOT();
+				forbid(!i);
+				markDOT();
+				if (ospeed > B300)
+					hold |= HOLDWIG;
+				(*opf)(c);
+			}
+		}
+#endif /* XPG4 */
+		i = lbrack(c, opf);
+		getDOT();
+		forbid(!i);
+		markDOT();
+		if (ospeed > B300)
+			hold |= HOLDWIG;
+		break;
+
+	/*
+	 * ,		Invert last find with f F t or T, like inverse
+	 *		of ;.
+	 */
+	case ',':
+		forbid(lastFKND == 0);
+		c = isupper(lastFKND) ? tolower(lastFKND) : toupper(lastFKND);
+		i = lastFCHR;
+		if (vglobp == 0)
+			vglobp = (unsigned char *)"";
+		subop++;
+		goto nocount;
+
+	/*
+	 * 0		To beginning of real line.
+	 */
+	case '0':
+		wcursor = linebuf;
+		vmoving = 0;
+		break;
+
+	/*
+	 * ;		Repeat last find with f F t or T.
+	 */
+	case ';':
+		forbid(lastFKND == 0);
+		c = lastFKND;
+		i = lastFCHR;
+		subop++;
+		goto nocount;
+
+	/*
+	 * F		Find single character before cursor in current line.
+	 * T		Like F, but stops before character.
+	 */
+	case 'F':	/* inverted find */
+	case 'T':
+		dir = -1;
+		/* fall into ... */
+
+	/*
+	 * f		Find single character following cursor in current line.
+	 * t		Like f, but stope before character.
+	 */
+	case 'f':	/* find */
+	case 't':
+		if (!subop) {
+			int length;
+			wchar_t wchar;
+			length = _mbftowc(lastcp, &wchar, getesc, &Peekkey);
+			if (length <= 0 || wchar == 0) {
+				beep();
+				return;
+			}
+			i = wchar;
+			lastcp += length;
+		}
+		if (vglobp == 0)
+			lastFKND = c, lastFCHR = i;
+		for (; cnt > 0; cnt--)
+			forbid(find(i) == 0);
+		vmoving = 0;
+		switch (c) {
+
+		case 'T':
+			wcursor = nextchr(wcursor);
+			break;
+
+		case 't':
+			wcursor = lastchr(linebuf, wcursor);
+		case 'f':
+fixup:
+			if (moveop != vmove)
+				wcursor = nextchr(wcursor);
+			break;
+		}
+		break;
+
+	/*
+	 * |		Find specified print column in current line.
+	 */
+	case '|':
+		if (Pline == numbline)
+			cnt += 8;
+		vmovcol = cnt;
+		vmoving = 1;
+		wcursor = vfindcol(cnt);
+		break;
+
+	/*
+	 * ^		To beginning of non-white space on line.
+	 */
+	case '^':
+		wcursor = vskipwh(linebuf);
+		vmoving = 0;
+		break;
+
+	/*
+	 * $		To end of line.
+	 */
+	case '$':
+		if (opf == vmove) {
+			vmoving = 1;
+			vmovcol = 20000;
+		} else
+			vmoving = 0;
+		if (cnt > 1) {
+			if (opf == vmove) {
+				wcursor = 0;
+				cnt--;
+			} else
+				wcursor = linebuf;
+			/* This is wrong at EOF */
+			wdot = dot + cnt;
+			break;
+		}
+		if (linebuf[0]) {
+			wcursor = strend(linebuf);
+			wcursor = lastchr(linebuf, wcursor);
+			goto fixup;
+		}
+		wcursor = linebuf;
+		break;
+
+	/*
+	 * h		Back a character.
+	 * ^H		Back a character.
+	 */
+	case 'h':
+	case CTRL('h'):
+		dir = -1;
+		/* fall into ... */
+
+	/*
+	 * space	Forward a character.
+	 */
+	case 'l':
+	case ' ':
+		forbid(margin() || opf == vmove && edge());
+		while (cnt > 0 && !margin()) {
+			if (dir == 1)
+				wcursor = nextchr(wcursor);
+			else
+				wcursor = lastchr(linebuf, wcursor);
+			cnt--;
+		}
+		if (margin() && opf == vmove || wcursor < linebuf) {
+			if (dir == 1)
+				wcursor = lastchr(linebuf, wcursor);
+			else
+				wcursor = linebuf;
+		}
+		vmoving = 0;
+		break;
+
+	/*
+	 * D		Delete to end of line, short for d$.
+	 */
+	case 'D':
+		cnt = INF;
+		goto deleteit;
+
+	/*
+	 * X		Delete character before cursor.
+	 */
+	case 'X':
+		dir = -1;
+		/* fall into ... */
+deleteit:
+	/*
+	 * x		Delete character at cursor, leaving cursor where it is.
+	 */
+	case 'x':
+		if (margin())
+			goto errlab;
+		vmacchng(1);
+		while (cnt > 0 && !margin()) {
+			if (dir == 1)
+				wcursor = nextchr(wcursor);
+			else
+				wcursor = lastchr(linebuf, wcursor);
+			cnt--;
+		}
+		opf = deleteop;
+		vmoving = 0;
+		break;
+
+	default:
+		/*
+		 * Stuttered operators are equivalent to the operator on
+		 * a line, thus turn dd into d_.
+		 */
+		if (opf == vmove || c != workcmd[0]) {
+errlab:
+			beep();
+			vmacp = 0;
+			return;
+		}
+		/* fall into ... */
+
+	/*
+	 * _		Target for a line or group of lines.
+	 *		Stuttering is more convenient; this is mostly
+	 *		for aesthetics.
+	 */
+	case '_':
+		wdot = dot + cnt - 1;
+		vmoving = 0;
+		wcursor = 0;
+		break;
+
+	/*
+	 * H		To first, home line on screen.
+	 *		Count is for count'th line rather than first.
+	 */
+	case 'H':
+		wdot = (dot - vcline) + cnt - 1;
+		if (opf == vmove)
+			markit(wdot);
+		vmoving = 0;
+		wcursor = 0;
+		break;
+
+	/*
+	 * -		Backwards lines, to first non-white character.
+	 */
+	case '-':
+		wdot = dot - cnt;
+		vmoving = 0;
+		wcursor = 0;
+		break;
+
+	/*
+	 * ^P		To previous line same column.  Ridiculous on the
+	 *		console of the VAX since it puts console in LSI mode.
+	 */
+	case 'k':
+	case CTRL('p'):
+		wdot = dot - cnt;
+		if (vmoving == 0)
+			vmoving = 1, vmovcol = column(cursor);
+		wcursor = 0;
+		break;
+
+	/*
+	 * L		To last line on screen, or count'th line from the
+	 *		bottom.
+	 */
+	case 'L':
+		wdot = dot + vcnt - vcline - cnt;
+		if (opf == vmove)
+			markit(wdot);
+		vmoving = 0;
+		wcursor = 0;
+		break;
+
+	/*
+	 * M		To the middle of the screen.
+	 */
+	case 'M':
+		wdot = dot + ((vcnt + 1) / 2) - vcline - 1;
+		if (opf == vmove)
+			markit(wdot);
+		vmoving = 0;
+		wcursor = 0;
+		break;
+
+	/*
+	 * +		Forward line, to first non-white.
+	 *
+	 * CR		Convenient synonym for +.
+	 */
+	case '+':
+	case CR:
+		wdot = dot + cnt;
+		vmoving = 0;
+		wcursor = 0;
+		break;
+
+	/*
+	 * ^N		To next line, same column if possible.
+	 *
+	 * LF		Linefeed is a convenient synonym for ^N.
+	 */
+	case CTRL('n'):
+	case 'j':
+	case NL:
+		wdot = dot + cnt;
+		if (vmoving == 0)
+			vmoving = 1, vmovcol = column(cursor);
+		wcursor = 0;
+		break;
+
+	/*
+	 * n		Search to next match of current pattern.
+	 */
+	case 'n':
+		vglobp = vscandir;
+		c = *vglobp++;
+		goto nocount;
+
+	/*
+	 * N		Like n but in reverse direction.
+	 */
+	case 'N':
+		vglobp = vscandir[0] == '/' ? (unsigned char *)"?" :
+		    (unsigned char *)"/";
+		c = *vglobp++;
+		goto nocount;
+
+	/*
+	 * '		Return to line specified by following mark,
+	 *		first white position on line.
+	 *
+	 * `		Return to marked line at remembered column.
+	 */
+	case '\'':
+	case '`':
+		d = c;
+		c = getesc();
+		if (c == 0)
+			return;
+		c = markreg(c);
+		forbid(c == 0);
+		wdot = getmark(c);
+		forbid(wdot == NOLINE);
+		forbid(Xhadcnt);
+		vmoving = 0;
+		wcursor = d == '`' ? ncols[c - 'a'] : 0;
+		if (opf == vmove && (wdot != dot ||
+			(d == '`' && wcursor != cursor)))
+			markDOT();
+		if (wcursor) {
+			vsave();
+			getline(*wdot);
+			if (wcursor > strend(linebuf))
+				wcursor = 0;
+			else {
+				cnt = wcursor - linebuf;
+				/*CSTYLED*/
+				for (wcursor = linebuf; wcursor - linebuf < cnt; ) 
+					wcursor = nextchr(wcursor);
+				if (wcursor - linebuf > cnt)
+					wcursor = lastchr(linebuf, wcursor);
+			}
+			getDOT();
+		}
+		if (ospeed > B300)
+			hold |= HOLDWIG;
+		break;
+
+	/*
+	 * G		Goto count'th line, or last line if no count
+	 *		given.
+	 */
+	case 'G':
+		if (!Xhadcnt)
+			cnt = lineDOL();
+		wdot = zero + cnt;
+		forbid(wdot < one || wdot > dol);
+		if (opf == vmove)
+			markit(wdot);
+		vmoving = 0;
+		wcursor = 0;
+		break;
+
+	/*
+	 * /		Scan forward for following re.
+	 * ?		Scan backward for following re.
+	 */
+	case '/':
+	case '?':
+		forbid(Xhadcnt);
+		vsave();
+		oc = c;
+		ocurs = cursor;
+		odot = dot;
+		wcursor = 0;
+		if (readecho(c))
+			return;
+		if (!vglobp)
+			vscandir[0] = genbuf[0];
+		oglobp = globp; CP(vutmp, genbuf); globp = vutmp;
+		d = peekc;
+fromsemi:
+		ungetchar(0);
+		fixech();
+		CATCH
+#ifndef CBREAK
+			/*
+			 * Lose typeahead (ick).
+			 */
+			vcook();
+#endif
+			addr = address(cursor);
+#ifndef CBREAK
+			vraw();
+#endif
+		ONERR
+#ifndef CBREAK
+			vraw();
+#endif
+slerr:
+			globp = oglobp;
+			dot = odot;
+			cursor = ocurs;
+			ungetchar(d);
+			splitw = 0;
+			vclean();
+			vjumpto(dot, ocurs, 0);
+			return;
+		ENDCATCH
+		if (globp == 0)
+			globp = (unsigned char *)"";
+		else if (peekc)
+			--globp;
+		if (*globp == ';') {
+			/* /foo/;/bar/ */
+			globp++;
+			dot = addr;
+			cursor = (unsigned char *)loc1;
+			goto fromsemi;
+		}
+		dot = odot;
+		ungetchar(d);
+		c = 0;
+		if (*globp == 'z')
+			globp++, c = '\n';
+		if (any(*globp, "^+-."))
+			c = *globp++;
+		i = 0;
+		while (isdigit(*globp))
+			i = i * 10 + *globp++ - '0';
+		if (any(*globp, "^+-."))
+			c = *globp++;
+		if (*globp) {
+			/* random junk after the pattern */
+			beep();
+			goto slerr;
+		}
+		globp = oglobp;
+		splitw = 0;
+		vmoving = 0;
+		wcursor = (unsigned char *)loc1;
+		if (i != 0)
+			vsetsiz(i);
+		if (opf == vmove) {
+			if (state == ONEOPEN || state == HARDOPEN)
+				outline = destline = WBOT;
+			if (addr != dot || (unsigned char *)loc1 != cursor)
+				markDOT();
+			if (loc1 > (char *)linebuf && *loc1 == 0)
+				loc1 = (char *)lastchr(linebuf, loc1);
+			if (c)
+				vjumpto(addr, loc1, c);
+			else {
+				vmoving = 0;
+				if (loc1) {
+					vmoving++;
+					vmovcol = column(loc1);
+				}
+				getDOT();
+				if (state == CRTOPEN && addr != dot)
+					vup1();
+				vupdown(addr - dot, NOSTR);
+			}
+			if (oc == '/') {	/* forward search */
+				if (dot < odot ||
+				    (dot == odot && cursor <= ocurs))
+					warnf(value(vi_TERSE) ?
+			gettext("Search wrapped BOTTOM") :
+			gettext("Search wrapped around BOTTOM of buffer"));
+			} else {		/* backward search */
+				if (dot > odot ||
+				    (dot == odot && cursor >= ocurs))
+					warnf(value(vi_TERSE) ?
+			gettext("Search wrapped TOP") :
+			gettext("Search wrapped around TOP of buffer"));
+			}
+			return;
+		}
+		lastcp[-1] = 'n';
+		getDOT();
+		wdot = addr;
+		break;
+	}
+	/*
+	 * Apply.
+	 */
+	if (vreg && wdot == 0)
+		wdot = dot;
+	(*opf)(c);
+	wdot = NOLINE;
+}
+
+static void
+lfixol()
+{
+	unsigned char *savevglobp;
+	int savesplit;
+
+	if (Outchar == vputchar)
+		return;
+
+	/* Show messages */
+	putnl();
+	if (inopen > 0 && clr_eol)
+		vclreol();
+	if (enter_standout_mode && exit_bold)
+		putpad(enter_standout_mode);
+	lprintf(gettext("[Hit return to continue] "), 0);
+	if (enter_standout_mode && exit_bold)
+		putpad(exit_bold);
+
+	/* Get key input for confirmation */
+	savevglobp = vglobp;
+	vglobp = 0; /* force typed input */
+	getkey();
+	vglobp = savevglobp;
+
+	/* reset output function */
+	Outchar = vputchar;
+
+	/* Clean up screen */
+	savesplit = splitw;
+	splitw = 0;
+	vclear();
+	vdirty(0, WLINES);
+	vredraw(WTOP);
+	splitw = savesplit;
+}
+
+warnf(str, cp)
+	char *str, *cp;
+{
+	int saveline, savecol, savesplit;
+
+	saveline = outline;
+	savecol = outcol;
+	savesplit = splitw;
+	splitw = 1;
+	vgoto(WECHO, 0);
+	if (!enter_standout_mode || !exit_bold)
+		dingdong();
+	if (clr_eol)
+		vclreol();
+	if (enter_standout_mode && exit_bold)
+		putpad(enter_standout_mode);
+	lprintf(str, cp);
+	if (enter_standout_mode && exit_bold)
+		putpad(exit_bold);
+	lfixol();
+	vgoto(saveline, savecol);
+	splitw = savesplit;
+}
+
+/* #ifdef PTR_ADDRESSES */
+/*
+ *	read in a row or column address
+ *
+ */
+static int
+get_addr()
+{
+	register short  c;
+	register short  next;
+
+	c = getkey();
+	next = 0;
+	switch (c) {
+	case CTRL('A'):
+		next = 96;
+		c = getkey();
+		break;
+
+	case CTRL('B'):
+		next = 192;
+		c = getkey();
+		break;
+	}
+	if (c < ' ')
+		return (-1);
+	return (next + c - ' ');
+}
+/* #endif PTR_ADDRESSES */
+
+/*
+ * Find single character c, in direction dir from cursor.
+ */
+find(c)
+	wchar_t c;
+{
+
+	wchar_t wchar;
+	int length;
+	for (;;) {
+		if (edge())
+			return (0);
+		if (dir == 1)
+			wcursor = nextchr(wcursor);
+		else
+			wcursor = lastchr(linebuf, wcursor);
+		if ((length = mbtowc(&wchar, (char *)wcursor,
+		    MULTI_BYTE_MAX)) > 0 && wchar == c)
+			return (1);
+	}
+}
+
+/*
+ * Do a word motion with operator op, and cnt more words
+ * to go after this.
+ */
+word(op, cnt)
+	register int (*op)();
+	int cnt;
+{
+	register int which;
+	register unsigned char *iwc;
+	register line *iwdot = wdot;
+	wchar_t wchar;
+	int length;
+
+	if (dir == 1) {
+		iwc = wcursor;
+		which = wordch(wcursor);
+		while (wordof(which, wcursor)) {
+			length = mbtowc(&wchar, (char *)wcursor,
+			    MULTI_BYTE_MAX);
+			if (length <= 0)
+				length = 1;
+			if (cnt == 1 && op != vmove && wcursor[length] == 0) {
+				wcursor += length;
+				break;
+			}
+			if (!lnext())
+				return (0);
+			if (wcursor == linebuf)
+				break;
+		}
+		/* Unless last segment of a change skip blanks */
+		if (op != vchange || cnt > 1)
+			while (!margin() && blank()) {
+				if (!lnext())
+					return (0);
+			}
+		else
+			if (wcursor == iwc && iwdot == wdot && *iwc)
+				wcursor = nextchr(wcursor);
+		if (op == vmove && margin()) {
+			wcursor = lastchr(linebuf, wcursor);
+#ifdef XPG4
+			if (wcursor < linebuf) {
+				wcursor = linebuf;
+			}
+#endif /* XPG4 */
+		}
+	} else {
+		if (!lnext())
+			return (0);
+		while (blank())
+			if (!lnext())
+				return (0);
+		if (!margin()) {
+			which = wordch(wcursor);
+			while (!margin() && wordof(which, wcursor))
+				wcursor = lastchr(linebuf, wcursor);
+		}
+#ifdef PRESUNEUC
+		if (wcursor < linebuf || !wordof(which, wcursor))
+			wcursor = nextchr(wcursor);
+#else
+		if (wcursor < linebuf)
+			wcursor++;
+		else if (!wordof(which, wcursor))
+			wcursor = nextchr(wcursor);
+#endif /* PRESUNEUC */
+	}
+	return (1);
+}
+
+/*
+ * To end of word, with operator op and cnt more motions
+ * remaining after this.
+ */
+eend(op)
+	register int (*op)();
+{
+	register int which;
+
+	if (!lnext())
+		return (0);
+	while (blank())
+		if (!lnext())
+			return (0);
+	which = wordch(wcursor);
+	while (wordof(which, wcursor)) {
+		if (wcursor[1] == 0) {
+			wcursor = nextchr(wcursor);
+			break;
+		}
+		if (!lnext())
+			return (0);
+	}
+	if (op == vyankit)
+		wcursor = lastchr(linebuf, wcursor) + 1;
+	else if (op != vchange && op != vdelete && wcursor > linebuf)
+		wcursor = lastchr(linebuf, wcursor);
+	return (1);
+}
+
+/*
+ * Wordof tells whether the character at *wc is in a word of
+ * kind which (blank/nonblank words are 0, conservative words 1).
+ */
+wordof(which, wc)
+	unsigned char which;
+	register unsigned char *wc;
+{
+#ifdef PRESUNEUC
+
+	if (isspace(*wc))
+#else
+	wchar_t z;
+
+	(void) mbtowc(&z, (char *)wc, MB_LEN_MAX);
+	if (iswspace(z))
+#endif /* PRESUNEUC */
+		return (0);
+	return (!wdkind || wordch(wc) == which);
+}
+
+/*
+ * Wordch tells whether character at *wc is a word character
+ * i.e. an alfa, digit, or underscore.
+ */
+#ifdef PRESUNEUC
+#define	SS2 0216
+#define	SS3 0217
+#endif /* PRESUNEUC */
+
+wordch(wc)
+	unsigned char *wc;
+{
+	register int length;
+	wchar_t c;
+
+	length = mbtowc(&c, (char *)wc, MULTI_BYTE_MAX);
+	if (length <= 0)
+		return (0);
+	if (length > 1)
+#ifndef PRESUNEUC
+		if (wdwc)
+			return (*wdwc)(c);
+		else
+#endif /* PRESUNEUC */
+		return (length);
+#ifndef PRESUNEUC
+	return (isalpha(*wc) || isdigit(*wc) || *wc == '_');
+#else
+	return (isalpha(c) || isdigit(c) || c == '_');
+#endif /* PRESUNEUC */
+}
+
+/*
+ * Edge tells when we hit the last character in the current line.
+ */
+edge()
+{
+
+	if (linebuf[0] == 0)
+		return (1);
+	if (dir == 1)
+		return (*(nextchr(wcursor)) == 0);
+	else
+		return (wcursor == linebuf);
+}
+
+/*
+ * Margin tells us when we have fallen off the end of the line.
+ */
+margin()
+{
+
+	return (wcursor < linebuf || wcursor[0] == 0);
+}
+#ifndef PRESUNEUC
+
+/*
+ * Blank tells if the cursor is currently on a TAB, RETURN,
+ * NEWLINE, FORMFEED, bertical tab, or SPACE character from EUC
+ * primary and supplementary codesets.
+ */
+blank()
+{
+	wchar_t z;
+
+	(void) mbtowc(&z, (char *)wcursor, MB_CUR_MAX);
+	return (iswspace((int)z));
+}
+#endif /* PRESUNEUC */