xref: /onnv-gate/usr/src/cmd/vi/port/ex_voper.c (revision 13093:48f2dbca79a2)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
59694SScott.Rotondo@Sun.COM  * Common Development and Distribution License (the "License").
69694SScott.Rotondo@Sun.COM  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
21*13093SRoger.Faulkner@Oracle.COM 
22802Scf46844 /*
23*13093SRoger.Faulkner@Oracle.COM  * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
24802Scf46844  */
25802Scf46844 
260Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
270Sstevel@tonic-gate /*	  All Rights Reserved  	*/
280Sstevel@tonic-gate 
290Sstevel@tonic-gate 
300Sstevel@tonic-gate /*
310Sstevel@tonic-gate  * Copyright (c) 1981 Regents of the University of California
320Sstevel@tonic-gate  */
330Sstevel@tonic-gate 
340Sstevel@tonic-gate #include "ex.h"
350Sstevel@tonic-gate #include "ex_tty.h"
360Sstevel@tonic-gate #include "ex_vis.h"
370Sstevel@tonic-gate #include <regexpr.h>
380Sstevel@tonic-gate #ifndef PRESUNEUC
390Sstevel@tonic-gate #include <wctype.h>
400Sstevel@tonic-gate /* Undef putchar/getchar if they're defined. */
410Sstevel@tonic-gate #ifdef putchar
420Sstevel@tonic-gate #undef putchar
430Sstevel@tonic-gate #endif
440Sstevel@tonic-gate #ifdef getchar
450Sstevel@tonic-gate #undef getchar
460Sstevel@tonic-gate #endif
470Sstevel@tonic-gate #endif /* PRESUNEUC */
480Sstevel@tonic-gate 
490Sstevel@tonic-gate #ifdef PRESUNEUC
500Sstevel@tonic-gate #define	blank()		isspace(wcursor[0])
510Sstevel@tonic-gate #endif /* PRESUNEUC */
520Sstevel@tonic-gate #define	forbid(a)	if (a) goto errlab;
530Sstevel@tonic-gate 
540Sstevel@tonic-gate unsigned char	vscandir[2] =	{ '/', 0 };
550Sstevel@tonic-gate 
569694SScott.Rotondo@Sun.COM static int get_addr();
579694SScott.Rotondo@Sun.COM 
580Sstevel@tonic-gate /*
590Sstevel@tonic-gate  * Decode an operator/operand type command.
600Sstevel@tonic-gate  * Eventually we switch to an operator subroutine in ex_vops.c.
610Sstevel@tonic-gate  * The work here is setting up a function variable to point
620Sstevel@tonic-gate  * to the routine we want, and manipulation of the variables
630Sstevel@tonic-gate  * wcursor and wdot, which mark the other end of the affected
640Sstevel@tonic-gate  * area.  If wdot is zero, then the current line is the other end,
650Sstevel@tonic-gate  * and if wcursor is zero, then the first non-blank location of the
660Sstevel@tonic-gate  * other line is implied.
670Sstevel@tonic-gate  */
68802Scf46844 void
operate(int c,int cnt)69802Scf46844 operate(int c, int cnt)
700Sstevel@tonic-gate {
71802Scf46844 	wchar_t i;
720Sstevel@tonic-gate 	int (*moveop)(), (*deleteop)();
73802Scf46844 	int (*opf)();
740Sstevel@tonic-gate 	bool subop = 0;
750Sstevel@tonic-gate 	unsigned char *oglobp, *ocurs;
76802Scf46844 	line *addr;
770Sstevel@tonic-gate 	line *odot;
780Sstevel@tonic-gate 	int oc;
790Sstevel@tonic-gate 	static unsigned char lastFKND;
800Sstevel@tonic-gate 	static wchar_t lastFCHR;
810Sstevel@tonic-gate 	short d;
820Sstevel@tonic-gate /* #ifdef PTR_ADDRESSES */
830Sstevel@tonic-gate 	int mouse_x;
840Sstevel@tonic-gate 	int mouse_y;
850Sstevel@tonic-gate 	int oline;
860Sstevel@tonic-gate /* #endif PTR_ADDRESSES */
870Sstevel@tonic-gate 
88802Scf46844 	moveop = vmove, deleteop = (int (*)())vdelete;
890Sstevel@tonic-gate 	wcursor = cursor;
900Sstevel@tonic-gate 	wdot = NOLINE;
910Sstevel@tonic-gate 	notecnt = 0;
920Sstevel@tonic-gate 	dir = 1;
930Sstevel@tonic-gate 	switch (c) {
940Sstevel@tonic-gate 
950Sstevel@tonic-gate 	/*
960Sstevel@tonic-gate 	 * d		delete operator.
970Sstevel@tonic-gate 	 */
980Sstevel@tonic-gate 	case 'd':
99802Scf46844 		moveop = (int (*)())vdelete;
1000Sstevel@tonic-gate 		deleteop = beep;
1010Sstevel@tonic-gate 		break;
1020Sstevel@tonic-gate 
1030Sstevel@tonic-gate 	/*
1040Sstevel@tonic-gate 	 * s		substitute characters, like c\040, i.e. change space.
1050Sstevel@tonic-gate 	 */
1060Sstevel@tonic-gate 	case 's':
1070Sstevel@tonic-gate 		ungetkey(' ');
1080Sstevel@tonic-gate 		subop++;
1090Sstevel@tonic-gate 		/* fall into ... */
1100Sstevel@tonic-gate 
1110Sstevel@tonic-gate 	/*
1120Sstevel@tonic-gate 	 * c		Change operator.
1130Sstevel@tonic-gate 	 */
1140Sstevel@tonic-gate 	case 'c':
1150Sstevel@tonic-gate 		if (c == 'c' && workcmd[0] == 'C' || workcmd[0] == 'S')
1160Sstevel@tonic-gate 			subop++;
117802Scf46844 		moveop = (int (*)())vchange;
1180Sstevel@tonic-gate 		deleteop = beep;
1190Sstevel@tonic-gate 		break;
1200Sstevel@tonic-gate 
1210Sstevel@tonic-gate 	/*
1220Sstevel@tonic-gate 	 * !		Filter through a UNIX command.
1230Sstevel@tonic-gate 	 */
1240Sstevel@tonic-gate 	case '!':
1250Sstevel@tonic-gate 		moveop = vfilter;
1260Sstevel@tonic-gate 		deleteop = beep;
1270Sstevel@tonic-gate 		break;
1280Sstevel@tonic-gate 
1290Sstevel@tonic-gate 	/*
1300Sstevel@tonic-gate 	 * y		Yank operator.  Place specified text so that it
1310Sstevel@tonic-gate 	 *		can be put back with p/P.  Also yanks to named buffers.
1320Sstevel@tonic-gate 	 */
1330Sstevel@tonic-gate 	case 'y':
1340Sstevel@tonic-gate 		moveop = vyankit;
1350Sstevel@tonic-gate 		deleteop = beep;
1360Sstevel@tonic-gate 		break;
1370Sstevel@tonic-gate 
1380Sstevel@tonic-gate 	/*
1390Sstevel@tonic-gate 	 * =		Reformat operator (for LISP).
1400Sstevel@tonic-gate 	 */
1410Sstevel@tonic-gate 	case '=':
1420Sstevel@tonic-gate 		forbid(!value(vi_LISP));
1430Sstevel@tonic-gate 		/* fall into ... */
1440Sstevel@tonic-gate 
1450Sstevel@tonic-gate 	/*
1460Sstevel@tonic-gate 	 * >		Right shift operator.
1470Sstevel@tonic-gate 	 * <		Left shift operator.
1480Sstevel@tonic-gate 	 */
1490Sstevel@tonic-gate 	case '<':
1500Sstevel@tonic-gate 	case '>':
1510Sstevel@tonic-gate 		moveop = vshftop;
1520Sstevel@tonic-gate 		deleteop = beep;
1530Sstevel@tonic-gate 		break;
1540Sstevel@tonic-gate 
1550Sstevel@tonic-gate 	/*
1560Sstevel@tonic-gate 	 * r		Replace character under cursor with single following
1570Sstevel@tonic-gate 	 *		character.
1580Sstevel@tonic-gate 	 */
1590Sstevel@tonic-gate 	case 'r':
1600Sstevel@tonic-gate 		vmacchng(1);
1610Sstevel@tonic-gate 		vrep(cnt);
1620Sstevel@tonic-gate 		return;
1630Sstevel@tonic-gate 
1640Sstevel@tonic-gate 	default:
1650Sstevel@tonic-gate 		goto nocount;
1660Sstevel@tonic-gate 	}
1670Sstevel@tonic-gate 	vmacchng(1);
1680Sstevel@tonic-gate 	/*
1690Sstevel@tonic-gate 	 * Had an operator, so accept another count.
1700Sstevel@tonic-gate 	 * Multiply counts together.
1710Sstevel@tonic-gate 	 */
1720Sstevel@tonic-gate 	if (isdigit(peekkey()) && peekkey() != '0') {
1730Sstevel@tonic-gate 		cnt *= vgetcnt();
1740Sstevel@tonic-gate 		Xcnt = cnt;
1750Sstevel@tonic-gate 		forbid(cnt <= 0);
1760Sstevel@tonic-gate 	}
1770Sstevel@tonic-gate 
1780Sstevel@tonic-gate 	/*
1790Sstevel@tonic-gate 	 * Get next character, mapping it and saving as
1800Sstevel@tonic-gate 	 * part of command for repeat.
1810Sstevel@tonic-gate 	 */
1820Sstevel@tonic-gate 	c = map(getesc(), arrows, 0);
1830Sstevel@tonic-gate 	if (c == 0)
1840Sstevel@tonic-gate 		return;
1850Sstevel@tonic-gate 	if (!subop)
1860Sstevel@tonic-gate 		*lastcp++ = c;
1870Sstevel@tonic-gate nocount:
1880Sstevel@tonic-gate 	opf = moveop;
1890Sstevel@tonic-gate 	switch (c) {
1900Sstevel@tonic-gate 
1910Sstevel@tonic-gate /* #ifdef PTR_ADDRESSES */
1920Sstevel@tonic-gate 	/*
1930Sstevel@tonic-gate 	 * ^X^_		Netty Mouse positioning hack
1940Sstevel@tonic-gate 	 * ^X^]
1950Sstevel@tonic-gate 	 */
1960Sstevel@tonic-gate 	case CTRL('X'):
1970Sstevel@tonic-gate /*
1980Sstevel@tonic-gate  *	Read in mouse stuff
1990Sstevel@tonic-gate  */
2000Sstevel@tonic-gate 		c = getkey();			/* ^_ or ^] */
2010Sstevel@tonic-gate 		if ((c != CTRL('_')) && (c != (CTRL(']'))))
2020Sstevel@tonic-gate 			break;
2030Sstevel@tonic-gate 		getkey();			/* mouse button */
2040Sstevel@tonic-gate 		mouse_x = get_addr() + 1;
2050Sstevel@tonic-gate 		mouse_y = get_addr() + 1;
2060Sstevel@tonic-gate 		if (mouse_y < WTOP)
2070Sstevel@tonic-gate 			break;
2080Sstevel@tonic-gate 		if (Pline == numbline)
2090Sstevel@tonic-gate 			mouse_x -= 8;
2100Sstevel@tonic-gate 		if (mouse_x < 0)
2110Sstevel@tonic-gate 			mouse_x = 0;
2120Sstevel@tonic-gate 		if (mouse_x > WCOLS)
2130Sstevel@tonic-gate 			break;
2140Sstevel@tonic-gate /*
2150Sstevel@tonic-gate  *	Find the line on the screen
2160Sstevel@tonic-gate  */
217804Scf46844 		for (i = 0; i <= WECHO; i++) {
2180Sstevel@tonic-gate 			if (vlinfo[i].vliny >= mouse_y)
2190Sstevel@tonic-gate 				break;
2200Sstevel@tonic-gate 		}
2210Sstevel@tonic-gate 		if (i > WECHO)
2220Sstevel@tonic-gate 			break;
2230Sstevel@tonic-gate /*
2240Sstevel@tonic-gate  *	Look for lines longer than one line - note  odd case at zero
2250Sstevel@tonic-gate  */
226804Scf46844 		if (i) {
227804Scf46844 			if (vlinfo[i - 1].vdepth > 1) {
2280Sstevel@tonic-gate 				mouse_x += WCOLS * (mouse_y -
2299694SScott.Rotondo@Sun.COM 				    (vlinfo[i].vliny -
2309694SScott.Rotondo@Sun.COM 				    (vlinfo[i - 1].vdepth - 1)));
2310Sstevel@tonic-gate 			}
2320Sstevel@tonic-gate 		}
2330Sstevel@tonic-gate 		else
2340Sstevel@tonic-gate 		{
2350Sstevel@tonic-gate 			mouse_x += WCOLS * (mouse_y - 1);
2360Sstevel@tonic-gate 		}
2370Sstevel@tonic-gate /*
2380Sstevel@tonic-gate  *	Set the line
2390Sstevel@tonic-gate  */
2400Sstevel@tonic-gate 		vsave();
2410Sstevel@tonic-gate 		ocurs = cursor;
2420Sstevel@tonic-gate 		odot = dot;
2430Sstevel@tonic-gate 		oline = vcline;
2440Sstevel@tonic-gate 		operate('H', i);
2450Sstevel@tonic-gate /*
2460Sstevel@tonic-gate  *	Set the column
2470Sstevel@tonic-gate  */
2480Sstevel@tonic-gate 		getDOT();
2490Sstevel@tonic-gate 		if (Pline == numbline)
2500Sstevel@tonic-gate 			mouse_x += 8;
2510Sstevel@tonic-gate 		vmovcol = mouse_x;
2520Sstevel@tonic-gate 		vmoving = 1;
2530Sstevel@tonic-gate 		wcursor = vfindcol(mouse_x);
2540Sstevel@tonic-gate /*
2550Sstevel@tonic-gate  *	Reset everything so that stuff like delete and change work
2560Sstevel@tonic-gate  */
2570Sstevel@tonic-gate 		wdot = (odot - oline) + i - 1;
2580Sstevel@tonic-gate 		cursor = ocurs;
2590Sstevel@tonic-gate 		vcline = oline;
2600Sstevel@tonic-gate 		dot = odot;
2610Sstevel@tonic-gate 		getDOT();
2620Sstevel@tonic-gate 		break;
2630Sstevel@tonic-gate /* #endif PTR_ADDRESSES */
2640Sstevel@tonic-gate 
2650Sstevel@tonic-gate 	/*
2660Sstevel@tonic-gate 	 * b		Back up a word.
2670Sstevel@tonic-gate 	 * B		Back up a word, liberal definition.
2680Sstevel@tonic-gate 	 */
2690Sstevel@tonic-gate 	case 'b':
2700Sstevel@tonic-gate 	case 'B':
2710Sstevel@tonic-gate 		dir = -1;
2720Sstevel@tonic-gate 		/* fall into ... */
2730Sstevel@tonic-gate 
2740Sstevel@tonic-gate 	/*
2750Sstevel@tonic-gate 	 * w		Forward a word.
2760Sstevel@tonic-gate 	 * W		Forward a word, liberal definition.
2770Sstevel@tonic-gate 	 */
2780Sstevel@tonic-gate 	case 'W':
2790Sstevel@tonic-gate 	case 'w':
2800Sstevel@tonic-gate 		wdkind = c & ' ';
2810Sstevel@tonic-gate 		forbid(lfind(2, cnt, opf, (line *)0) < 0);
2820Sstevel@tonic-gate 		vmoving = 0;
2830Sstevel@tonic-gate 		break;
2840Sstevel@tonic-gate 
2850Sstevel@tonic-gate 	/*
2860Sstevel@tonic-gate 	 * E		to end of following blank/nonblank word
2870Sstevel@tonic-gate 	 */
2880Sstevel@tonic-gate 	case 'E':
2890Sstevel@tonic-gate 		wdkind = 0;
2900Sstevel@tonic-gate 		goto ein;
2910Sstevel@tonic-gate 
2920Sstevel@tonic-gate 	/*
2930Sstevel@tonic-gate 	 * e		To end of following word.
2940Sstevel@tonic-gate 	 */
2950Sstevel@tonic-gate 	case 'e':
2960Sstevel@tonic-gate 		wdkind = 1;
2970Sstevel@tonic-gate ein:
2980Sstevel@tonic-gate 		forbid(lfind(3, cnt - 1, opf, (line *)0) < 0);
2990Sstevel@tonic-gate 		vmoving = 0;
3000Sstevel@tonic-gate 		break;
3010Sstevel@tonic-gate 
3020Sstevel@tonic-gate 	/*
3030Sstevel@tonic-gate 	 * (		Back an s-expression.
3040Sstevel@tonic-gate 	 */
3050Sstevel@tonic-gate 	case '(':
3060Sstevel@tonic-gate 		dir = -1;
3070Sstevel@tonic-gate 		/* fall into... */
3080Sstevel@tonic-gate 
3090Sstevel@tonic-gate 	/*
3100Sstevel@tonic-gate 	 * )		Forward an s-expression.
3110Sstevel@tonic-gate 	 */
3120Sstevel@tonic-gate 	case ')':
3130Sstevel@tonic-gate 		forbid(lfind(0, cnt, opf, (line *) 0) < 0);
3140Sstevel@tonic-gate 		markDOT();
3150Sstevel@tonic-gate 		break;
3160Sstevel@tonic-gate 
3170Sstevel@tonic-gate 	/*
3180Sstevel@tonic-gate 	 * {		Back an s-expression, but don't stop on atoms.
3190Sstevel@tonic-gate 	 *		In text mode, a paragraph.  For C, a balanced set
3200Sstevel@tonic-gate 	 *		of {}'s.
3210Sstevel@tonic-gate 	 */
3220Sstevel@tonic-gate 	case '{':
3230Sstevel@tonic-gate 		dir = -1;
3240Sstevel@tonic-gate 		/* fall into... */
3250Sstevel@tonic-gate 
3260Sstevel@tonic-gate 	/*
3270Sstevel@tonic-gate 	 * }		Forward an s-expression, but don't stop on atoms.
3280Sstevel@tonic-gate 	 *		In text mode, back paragraph.  For C, back a balanced
3290Sstevel@tonic-gate 	 *		set of {}'s.
3300Sstevel@tonic-gate 	 */
3310Sstevel@tonic-gate 	case '}':
3320Sstevel@tonic-gate 		forbid(lfind(1, cnt, opf, (line *) 0) < 0);
3330Sstevel@tonic-gate 		markDOT();
3340Sstevel@tonic-gate 		break;
3350Sstevel@tonic-gate 
3360Sstevel@tonic-gate 	/*
3370Sstevel@tonic-gate 	 * %		To matching () or {}.  If not at ( or { scan for
3380Sstevel@tonic-gate 	 *		first such after cursor on this line.
3390Sstevel@tonic-gate 	 */
3400Sstevel@tonic-gate 	case '%':
3410Sstevel@tonic-gate 		vsave();
3420Sstevel@tonic-gate 		ocurs = cursor;
3430Sstevel@tonic-gate 		odot = wdot = dot;
3440Sstevel@tonic-gate 		oglobp = globp;
3450Sstevel@tonic-gate 		CATCH
3460Sstevel@tonic-gate 			i = lmatchp((line *) 0);
3470Sstevel@tonic-gate 		ONERR
3480Sstevel@tonic-gate 			globp = oglobp;
3490Sstevel@tonic-gate 			dot = wdot = odot;
3500Sstevel@tonic-gate 			cursor = ocurs;
3510Sstevel@tonic-gate 			splitw = 0;
3520Sstevel@tonic-gate 			vclean();
3530Sstevel@tonic-gate 			vjumpto(dot, ocurs, 0);
3540Sstevel@tonic-gate 			return;
3550Sstevel@tonic-gate 		ENDCATCH
3560Sstevel@tonic-gate #ifdef TRACE
3570Sstevel@tonic-gate 		if (trace)
3580Sstevel@tonic-gate 			fprintf(trace, "after lmatchp in %, dot=%d, wdot=%d, "
3590Sstevel@tonic-gate 			    "dol=%d\n", lineno(dot), lineno(wdot), lineno(dol));
3600Sstevel@tonic-gate #endif
3610Sstevel@tonic-gate 		getDOT();
3620Sstevel@tonic-gate 		forbid(!i);
3630Sstevel@tonic-gate 		if (opf != vmove)
3640Sstevel@tonic-gate 			if (dir > 0)
3650Sstevel@tonic-gate 				wcursor++;
3660Sstevel@tonic-gate 			else
3670Sstevel@tonic-gate 				cursor++;
3680Sstevel@tonic-gate 		else
3690Sstevel@tonic-gate 			markDOT();
3700Sstevel@tonic-gate 		vmoving = 0;
3710Sstevel@tonic-gate 		break;
3720Sstevel@tonic-gate 
3730Sstevel@tonic-gate 	/*
3740Sstevel@tonic-gate 	 * [		Back to beginning of defun, i.e. an ( in column 1.
3750Sstevel@tonic-gate 	 *		For text, back to a section macro.
3760Sstevel@tonic-gate 	 *		For C, back to a { in column 1 (~~ beg of function.)
3770Sstevel@tonic-gate 	 */
3780Sstevel@tonic-gate 	case '[':
3790Sstevel@tonic-gate 		dir = -1;
3800Sstevel@tonic-gate 		/* fall into ... */
3810Sstevel@tonic-gate 
3820Sstevel@tonic-gate 	/*
3830Sstevel@tonic-gate 	 * ]		Forward to next defun, i.e. a ( in column 1.
3840Sstevel@tonic-gate 	 *		For text, forward section.
3850Sstevel@tonic-gate 	 *		For C, forward to a } in column 1 (if delete or such)
3860Sstevel@tonic-gate 	 *		or if a move to a { in column 1.
3870Sstevel@tonic-gate 	 */
3880Sstevel@tonic-gate 	case ']':
3890Sstevel@tonic-gate 		if (!vglobp)
3900Sstevel@tonic-gate 			forbid(getkey() != c);
3910Sstevel@tonic-gate #ifndef XPG4
3920Sstevel@tonic-gate 		forbid(Xhadcnt);
3930Sstevel@tonic-gate #endif
3940Sstevel@tonic-gate 		vsave();
3950Sstevel@tonic-gate #ifdef XPG4
3960Sstevel@tonic-gate 		if (cnt > 1) {
3970Sstevel@tonic-gate 			while (cnt-- > 1) {
3980Sstevel@tonic-gate 				i = lbrack(c, opf);
3990Sstevel@tonic-gate 				getDOT();
4000Sstevel@tonic-gate 				forbid(!i);
4010Sstevel@tonic-gate 				markDOT();
4020Sstevel@tonic-gate 				if (ospeed > B300)
4030Sstevel@tonic-gate 					hold |= HOLDWIG;
4040Sstevel@tonic-gate 				(*opf)(c);
4050Sstevel@tonic-gate 			}
4060Sstevel@tonic-gate 		}
4070Sstevel@tonic-gate #endif /* XPG4 */
4080Sstevel@tonic-gate 		i = lbrack(c, opf);
4090Sstevel@tonic-gate 		getDOT();
4100Sstevel@tonic-gate 		forbid(!i);
4110Sstevel@tonic-gate 		markDOT();
4120Sstevel@tonic-gate 		if (ospeed > B300)
4130Sstevel@tonic-gate 			hold |= HOLDWIG;
4140Sstevel@tonic-gate 		break;
4150Sstevel@tonic-gate 
4160Sstevel@tonic-gate 	/*
4170Sstevel@tonic-gate 	 * ,		Invert last find with f F t or T, like inverse
4180Sstevel@tonic-gate 	 *		of ;.
4190Sstevel@tonic-gate 	 */
4200Sstevel@tonic-gate 	case ',':
4210Sstevel@tonic-gate 		forbid(lastFKND == 0);
4220Sstevel@tonic-gate 		c = isupper(lastFKND) ? tolower(lastFKND) : toupper(lastFKND);
4230Sstevel@tonic-gate 		i = lastFCHR;
4240Sstevel@tonic-gate 		if (vglobp == 0)
4250Sstevel@tonic-gate 			vglobp = (unsigned char *)"";
4260Sstevel@tonic-gate 		subop++;
4270Sstevel@tonic-gate 		goto nocount;
4280Sstevel@tonic-gate 
4290Sstevel@tonic-gate 	/*
4300Sstevel@tonic-gate 	 * 0		To beginning of real line.
4310Sstevel@tonic-gate 	 */
4320Sstevel@tonic-gate 	case '0':
4330Sstevel@tonic-gate 		wcursor = linebuf;
4340Sstevel@tonic-gate 		vmoving = 0;
4350Sstevel@tonic-gate 		break;
4360Sstevel@tonic-gate 
4370Sstevel@tonic-gate 	/*
4380Sstevel@tonic-gate 	 * ;		Repeat last find with f F t or T.
4390Sstevel@tonic-gate 	 */
4400Sstevel@tonic-gate 	case ';':
4410Sstevel@tonic-gate 		forbid(lastFKND == 0);
4420Sstevel@tonic-gate 		c = lastFKND;
4430Sstevel@tonic-gate 		i = lastFCHR;
4440Sstevel@tonic-gate 		subop++;
4450Sstevel@tonic-gate 		goto nocount;
4460Sstevel@tonic-gate 
4470Sstevel@tonic-gate 	/*
4480Sstevel@tonic-gate 	 * F		Find single character before cursor in current line.
4490Sstevel@tonic-gate 	 * T		Like F, but stops before character.
4500Sstevel@tonic-gate 	 */
4510Sstevel@tonic-gate 	case 'F':	/* inverted find */
4520Sstevel@tonic-gate 	case 'T':
4530Sstevel@tonic-gate 		dir = -1;
4540Sstevel@tonic-gate 		/* fall into ... */
4550Sstevel@tonic-gate 
4560Sstevel@tonic-gate 	/*
4570Sstevel@tonic-gate 	 * f		Find single character following cursor in current line.
4580Sstevel@tonic-gate 	 * t		Like f, but stope before character.
4590Sstevel@tonic-gate 	 */
4600Sstevel@tonic-gate 	case 'f':	/* find */
4610Sstevel@tonic-gate 	case 't':
4620Sstevel@tonic-gate 		if (!subop) {
4630Sstevel@tonic-gate 			int length;
4640Sstevel@tonic-gate 			wchar_t wchar;
4650Sstevel@tonic-gate 			length = _mbftowc(lastcp, &wchar, getesc, &Peekkey);
4660Sstevel@tonic-gate 			if (length <= 0 || wchar == 0) {
467802Scf46844 				(void) beep();
4680Sstevel@tonic-gate 				return;
4690Sstevel@tonic-gate 			}
4700Sstevel@tonic-gate 			i = wchar;
4710Sstevel@tonic-gate 			lastcp += length;
4720Sstevel@tonic-gate 		}
4730Sstevel@tonic-gate 		if (vglobp == 0)
4740Sstevel@tonic-gate 			lastFKND = c, lastFCHR = i;
4750Sstevel@tonic-gate 		for (; cnt > 0; cnt--)
4760Sstevel@tonic-gate 			forbid(find(i) == 0);
4770Sstevel@tonic-gate 		vmoving = 0;
4780Sstevel@tonic-gate 		switch (c) {
4790Sstevel@tonic-gate 
4800Sstevel@tonic-gate 		case 'T':
4810Sstevel@tonic-gate 			wcursor = nextchr(wcursor);
4820Sstevel@tonic-gate 			break;
4830Sstevel@tonic-gate 
4840Sstevel@tonic-gate 		case 't':
4850Sstevel@tonic-gate 			wcursor = lastchr(linebuf, wcursor);
4860Sstevel@tonic-gate 		case 'f':
4870Sstevel@tonic-gate fixup:
4880Sstevel@tonic-gate 			if (moveop != vmove)
4890Sstevel@tonic-gate 				wcursor = nextchr(wcursor);
4900Sstevel@tonic-gate 			break;
4910Sstevel@tonic-gate 		}
4920Sstevel@tonic-gate 		break;
4930Sstevel@tonic-gate 
4940Sstevel@tonic-gate 	/*
4950Sstevel@tonic-gate 	 * |		Find specified print column in current line.
4960Sstevel@tonic-gate 	 */
4970Sstevel@tonic-gate 	case '|':
4980Sstevel@tonic-gate 		if (Pline == numbline)
4990Sstevel@tonic-gate 			cnt += 8;
5000Sstevel@tonic-gate 		vmovcol = cnt;
5010Sstevel@tonic-gate 		vmoving = 1;
5020Sstevel@tonic-gate 		wcursor = vfindcol(cnt);
5030Sstevel@tonic-gate 		break;
5040Sstevel@tonic-gate 
5050Sstevel@tonic-gate 	/*
5060Sstevel@tonic-gate 	 * ^		To beginning of non-white space on line.
5070Sstevel@tonic-gate 	 */
5080Sstevel@tonic-gate 	case '^':
5090Sstevel@tonic-gate 		wcursor = vskipwh(linebuf);
5100Sstevel@tonic-gate 		vmoving = 0;
5110Sstevel@tonic-gate 		break;
5120Sstevel@tonic-gate 
5130Sstevel@tonic-gate 	/*
5140Sstevel@tonic-gate 	 * $		To end of line.
5150Sstevel@tonic-gate 	 */
5160Sstevel@tonic-gate 	case '$':
5170Sstevel@tonic-gate 		if (opf == vmove) {
5180Sstevel@tonic-gate 			vmoving = 1;
5190Sstevel@tonic-gate 			vmovcol = 20000;
5200Sstevel@tonic-gate 		} else
5210Sstevel@tonic-gate 			vmoving = 0;
5220Sstevel@tonic-gate 		if (cnt > 1) {
5230Sstevel@tonic-gate 			if (opf == vmove) {
5240Sstevel@tonic-gate 				wcursor = 0;
5250Sstevel@tonic-gate 				cnt--;
5260Sstevel@tonic-gate 			} else
5270Sstevel@tonic-gate 				wcursor = linebuf;
5280Sstevel@tonic-gate 			/* This is wrong at EOF */
5290Sstevel@tonic-gate 			wdot = dot + cnt;
5300Sstevel@tonic-gate 			break;
5310Sstevel@tonic-gate 		}
5320Sstevel@tonic-gate 		if (linebuf[0]) {
5330Sstevel@tonic-gate 			wcursor = strend(linebuf);
5340Sstevel@tonic-gate 			wcursor = lastchr(linebuf, wcursor);
5350Sstevel@tonic-gate 			goto fixup;
5360Sstevel@tonic-gate 		}
5370Sstevel@tonic-gate 		wcursor = linebuf;
5380Sstevel@tonic-gate 		break;
5390Sstevel@tonic-gate 
5400Sstevel@tonic-gate 	/*
5410Sstevel@tonic-gate 	 * h		Back a character.
5420Sstevel@tonic-gate 	 * ^H		Back a character.
5430Sstevel@tonic-gate 	 */
5440Sstevel@tonic-gate 	case 'h':
5450Sstevel@tonic-gate 	case CTRL('h'):
5460Sstevel@tonic-gate 		dir = -1;
5470Sstevel@tonic-gate 		/* fall into ... */
5480Sstevel@tonic-gate 
5490Sstevel@tonic-gate 	/*
5500Sstevel@tonic-gate 	 * space	Forward a character.
5510Sstevel@tonic-gate 	 */
5520Sstevel@tonic-gate 	case 'l':
5530Sstevel@tonic-gate 	case ' ':
5540Sstevel@tonic-gate 		forbid(margin() || opf == vmove && edge());
5550Sstevel@tonic-gate 		while (cnt > 0 && !margin()) {
5560Sstevel@tonic-gate 			if (dir == 1)
5570Sstevel@tonic-gate 				wcursor = nextchr(wcursor);
5580Sstevel@tonic-gate 			else
5590Sstevel@tonic-gate 				wcursor = lastchr(linebuf, wcursor);
5600Sstevel@tonic-gate 			cnt--;
5610Sstevel@tonic-gate 		}
5620Sstevel@tonic-gate 		if (margin() && opf == vmove || wcursor < linebuf) {
5630Sstevel@tonic-gate 			if (dir == 1)
5640Sstevel@tonic-gate 				wcursor = lastchr(linebuf, wcursor);
5650Sstevel@tonic-gate 			else
5660Sstevel@tonic-gate 				wcursor = linebuf;
5670Sstevel@tonic-gate 		}
5680Sstevel@tonic-gate 		vmoving = 0;
5690Sstevel@tonic-gate 		break;
5700Sstevel@tonic-gate 
5710Sstevel@tonic-gate 	/*
5720Sstevel@tonic-gate 	 * D		Delete to end of line, short for d$.
5730Sstevel@tonic-gate 	 */
5740Sstevel@tonic-gate 	case 'D':
5750Sstevel@tonic-gate 		cnt = INF;
5760Sstevel@tonic-gate 		goto deleteit;
5770Sstevel@tonic-gate 
5780Sstevel@tonic-gate 	/*
5790Sstevel@tonic-gate 	 * X		Delete character before cursor.
5800Sstevel@tonic-gate 	 */
5810Sstevel@tonic-gate 	case 'X':
5820Sstevel@tonic-gate 		dir = -1;
5830Sstevel@tonic-gate 		/* fall into ... */
5840Sstevel@tonic-gate deleteit:
5850Sstevel@tonic-gate 	/*
5860Sstevel@tonic-gate 	 * x		Delete character at cursor, leaving cursor where it is.
5870Sstevel@tonic-gate 	 */
5880Sstevel@tonic-gate 	case 'x':
5890Sstevel@tonic-gate 		if (margin())
5900Sstevel@tonic-gate 			goto errlab;
5910Sstevel@tonic-gate 		vmacchng(1);
5920Sstevel@tonic-gate 		while (cnt > 0 && !margin()) {
5930Sstevel@tonic-gate 			if (dir == 1)
5940Sstevel@tonic-gate 				wcursor = nextchr(wcursor);
5950Sstevel@tonic-gate 			else
5960Sstevel@tonic-gate 				wcursor = lastchr(linebuf, wcursor);
5970Sstevel@tonic-gate 			cnt--;
5980Sstevel@tonic-gate 		}
5990Sstevel@tonic-gate 		opf = deleteop;
6000Sstevel@tonic-gate 		vmoving = 0;
6010Sstevel@tonic-gate 		break;
6020Sstevel@tonic-gate 
6030Sstevel@tonic-gate 	default:
6040Sstevel@tonic-gate 		/*
6050Sstevel@tonic-gate 		 * Stuttered operators are equivalent to the operator on
6060Sstevel@tonic-gate 		 * a line, thus turn dd into d_.
6070Sstevel@tonic-gate 		 */
6080Sstevel@tonic-gate 		if (opf == vmove || c != workcmd[0]) {
6090Sstevel@tonic-gate errlab:
610802Scf46844 			(void) beep();
6110Sstevel@tonic-gate 			vmacp = 0;
6120Sstevel@tonic-gate 			return;
6130Sstevel@tonic-gate 		}
6140Sstevel@tonic-gate 		/* fall into ... */
6150Sstevel@tonic-gate 
6160Sstevel@tonic-gate 	/*
6170Sstevel@tonic-gate 	 * _		Target for a line or group of lines.
6180Sstevel@tonic-gate 	 *		Stuttering is more convenient; this is mostly
6190Sstevel@tonic-gate 	 *		for aesthetics.
6200Sstevel@tonic-gate 	 */
6210Sstevel@tonic-gate 	case '_':
6220Sstevel@tonic-gate 		wdot = dot + cnt - 1;
6230Sstevel@tonic-gate 		vmoving = 0;
6240Sstevel@tonic-gate 		wcursor = 0;
6250Sstevel@tonic-gate 		break;
6260Sstevel@tonic-gate 
6270Sstevel@tonic-gate 	/*
6280Sstevel@tonic-gate 	 * H		To first, home line on screen.
6290Sstevel@tonic-gate 	 *		Count is for count'th line rather than first.
6300Sstevel@tonic-gate 	 */
6310Sstevel@tonic-gate 	case 'H':
6320Sstevel@tonic-gate 		wdot = (dot - vcline) + cnt - 1;
6330Sstevel@tonic-gate 		if (opf == vmove)
6340Sstevel@tonic-gate 			markit(wdot);
6350Sstevel@tonic-gate 		vmoving = 0;
6360Sstevel@tonic-gate 		wcursor = 0;
6370Sstevel@tonic-gate 		break;
6380Sstevel@tonic-gate 
6390Sstevel@tonic-gate 	/*
6400Sstevel@tonic-gate 	 * -		Backwards lines, to first non-white character.
6410Sstevel@tonic-gate 	 */
6420Sstevel@tonic-gate 	case '-':
6430Sstevel@tonic-gate 		wdot = dot - cnt;
6440Sstevel@tonic-gate 		vmoving = 0;
6450Sstevel@tonic-gate 		wcursor = 0;
6460Sstevel@tonic-gate 		break;
6470Sstevel@tonic-gate 
6480Sstevel@tonic-gate 	/*
6490Sstevel@tonic-gate 	 * ^P		To previous line same column.  Ridiculous on the
6500Sstevel@tonic-gate 	 *		console of the VAX since it puts console in LSI mode.
6510Sstevel@tonic-gate 	 */
6520Sstevel@tonic-gate 	case 'k':
6530Sstevel@tonic-gate 	case CTRL('p'):
6540Sstevel@tonic-gate 		wdot = dot - cnt;
6550Sstevel@tonic-gate 		if (vmoving == 0)
6560Sstevel@tonic-gate 			vmoving = 1, vmovcol = column(cursor);
6570Sstevel@tonic-gate 		wcursor = 0;
6580Sstevel@tonic-gate 		break;
6590Sstevel@tonic-gate 
6600Sstevel@tonic-gate 	/*
6610Sstevel@tonic-gate 	 * L		To last line on screen, or count'th line from the
6620Sstevel@tonic-gate 	 *		bottom.
6630Sstevel@tonic-gate 	 */
6640Sstevel@tonic-gate 	case 'L':
6650Sstevel@tonic-gate 		wdot = dot + vcnt - vcline - cnt;
6660Sstevel@tonic-gate 		if (opf == vmove)
6670Sstevel@tonic-gate 			markit(wdot);
6680Sstevel@tonic-gate 		vmoving = 0;
6690Sstevel@tonic-gate 		wcursor = 0;
6700Sstevel@tonic-gate 		break;
6710Sstevel@tonic-gate 
6720Sstevel@tonic-gate 	/*
6730Sstevel@tonic-gate 	 * M		To the middle of the screen.
6740Sstevel@tonic-gate 	 */
6750Sstevel@tonic-gate 	case 'M':
6760Sstevel@tonic-gate 		wdot = dot + ((vcnt + 1) / 2) - vcline - 1;
6770Sstevel@tonic-gate 		if (opf == vmove)
6780Sstevel@tonic-gate 			markit(wdot);
6790Sstevel@tonic-gate 		vmoving = 0;
6800Sstevel@tonic-gate 		wcursor = 0;
6810Sstevel@tonic-gate 		break;
6820Sstevel@tonic-gate 
6830Sstevel@tonic-gate 	/*
6840Sstevel@tonic-gate 	 * +		Forward line, to first non-white.
6850Sstevel@tonic-gate 	 *
6860Sstevel@tonic-gate 	 * CR		Convenient synonym for +.
6870Sstevel@tonic-gate 	 */
6880Sstevel@tonic-gate 	case '+':
6890Sstevel@tonic-gate 	case CR:
6900Sstevel@tonic-gate 		wdot = dot + cnt;
6910Sstevel@tonic-gate 		vmoving = 0;
6920Sstevel@tonic-gate 		wcursor = 0;
6930Sstevel@tonic-gate 		break;
6940Sstevel@tonic-gate 
6950Sstevel@tonic-gate 	/*
6960Sstevel@tonic-gate 	 * ^N		To next line, same column if possible.
6970Sstevel@tonic-gate 	 *
6980Sstevel@tonic-gate 	 * LF		Linefeed is a convenient synonym for ^N.
6990Sstevel@tonic-gate 	 */
7000Sstevel@tonic-gate 	case CTRL('n'):
7010Sstevel@tonic-gate 	case 'j':
7020Sstevel@tonic-gate 	case NL:
7030Sstevel@tonic-gate 		wdot = dot + cnt;
7040Sstevel@tonic-gate 		if (vmoving == 0)
7050Sstevel@tonic-gate 			vmoving = 1, vmovcol = column(cursor);
7060Sstevel@tonic-gate 		wcursor = 0;
7070Sstevel@tonic-gate 		break;
7080Sstevel@tonic-gate 
7090Sstevel@tonic-gate 	/*
7100Sstevel@tonic-gate 	 * n		Search to next match of current pattern.
7110Sstevel@tonic-gate 	 */
7120Sstevel@tonic-gate 	case 'n':
7130Sstevel@tonic-gate 		vglobp = vscandir;
7140Sstevel@tonic-gate 		c = *vglobp++;
7150Sstevel@tonic-gate 		goto nocount;
7160Sstevel@tonic-gate 
7170Sstevel@tonic-gate 	/*
7180Sstevel@tonic-gate 	 * N		Like n but in reverse direction.
7190Sstevel@tonic-gate 	 */
7200Sstevel@tonic-gate 	case 'N':
7210Sstevel@tonic-gate 		vglobp = vscandir[0] == '/' ? (unsigned char *)"?" :
7220Sstevel@tonic-gate 		    (unsigned char *)"/";
7230Sstevel@tonic-gate 		c = *vglobp++;
7240Sstevel@tonic-gate 		goto nocount;
7250Sstevel@tonic-gate 
7260Sstevel@tonic-gate 	/*
7270Sstevel@tonic-gate 	 * '		Return to line specified by following mark,
7280Sstevel@tonic-gate 	 *		first white position on line.
7290Sstevel@tonic-gate 	 *
7300Sstevel@tonic-gate 	 * `		Return to marked line at remembered column.
7310Sstevel@tonic-gate 	 */
7320Sstevel@tonic-gate 	case '\'':
7330Sstevel@tonic-gate 	case '`':
7340Sstevel@tonic-gate 		d = c;
7350Sstevel@tonic-gate 		c = getesc();
7360Sstevel@tonic-gate 		if (c == 0)
7370Sstevel@tonic-gate 			return;
7380Sstevel@tonic-gate 		c = markreg(c);
7390Sstevel@tonic-gate 		forbid(c == 0);
7400Sstevel@tonic-gate 		wdot = getmark(c);
7410Sstevel@tonic-gate 		forbid(wdot == NOLINE);
7420Sstevel@tonic-gate 		forbid(Xhadcnt);
7430Sstevel@tonic-gate 		vmoving = 0;
7440Sstevel@tonic-gate 		wcursor = d == '`' ? ncols[c - 'a'] : 0;
7450Sstevel@tonic-gate 		if (opf == vmove && (wdot != dot ||
7469694SScott.Rotondo@Sun.COM 		    (d == '`' && wcursor != cursor)))
7470Sstevel@tonic-gate 			markDOT();
7480Sstevel@tonic-gate 		if (wcursor) {
7490Sstevel@tonic-gate 			vsave();
750*13093SRoger.Faulkner@Oracle.COM 			getaline(*wdot);
7510Sstevel@tonic-gate 			if (wcursor > strend(linebuf))
7520Sstevel@tonic-gate 				wcursor = 0;
7530Sstevel@tonic-gate 			else {
7540Sstevel@tonic-gate 				cnt = wcursor - linebuf;
7550Sstevel@tonic-gate 				/*CSTYLED*/
7560Sstevel@tonic-gate 				for (wcursor = linebuf; wcursor - linebuf < cnt; )
7570Sstevel@tonic-gate 					wcursor = nextchr(wcursor);
7580Sstevel@tonic-gate 				if (wcursor - linebuf > cnt)
7590Sstevel@tonic-gate 					wcursor = lastchr(linebuf, wcursor);
7600Sstevel@tonic-gate 			}
7610Sstevel@tonic-gate 			getDOT();
7620Sstevel@tonic-gate 		}
7630Sstevel@tonic-gate 		if (ospeed > B300)
7640Sstevel@tonic-gate 			hold |= HOLDWIG;
7650Sstevel@tonic-gate 		break;
7660Sstevel@tonic-gate 
7670Sstevel@tonic-gate 	/*
7680Sstevel@tonic-gate 	 * G		Goto count'th line, or last line if no count
7690Sstevel@tonic-gate 	 *		given.
7700Sstevel@tonic-gate 	 */
7710Sstevel@tonic-gate 	case 'G':
7720Sstevel@tonic-gate 		if (!Xhadcnt)
7730Sstevel@tonic-gate 			cnt = lineDOL();
7740Sstevel@tonic-gate 		wdot = zero + cnt;
7750Sstevel@tonic-gate 		forbid(wdot < one || wdot > dol);
7760Sstevel@tonic-gate 		if (opf == vmove)
7770Sstevel@tonic-gate 			markit(wdot);
7780Sstevel@tonic-gate 		vmoving = 0;
7790Sstevel@tonic-gate 		wcursor = 0;
7800Sstevel@tonic-gate 		break;
7810Sstevel@tonic-gate 
7820Sstevel@tonic-gate 	/*
7830Sstevel@tonic-gate 	 * /		Scan forward for following re.
7840Sstevel@tonic-gate 	 * ?		Scan backward for following re.
7850Sstevel@tonic-gate 	 */
7860Sstevel@tonic-gate 	case '/':
7870Sstevel@tonic-gate 	case '?':
7880Sstevel@tonic-gate 		forbid(Xhadcnt);
7890Sstevel@tonic-gate 		vsave();
7900Sstevel@tonic-gate 		oc = c;
7910Sstevel@tonic-gate 		ocurs = cursor;
7920Sstevel@tonic-gate 		odot = dot;
7930Sstevel@tonic-gate 		wcursor = 0;
7940Sstevel@tonic-gate 		if (readecho(c))
7950Sstevel@tonic-gate 			return;
7960Sstevel@tonic-gate 		if (!vglobp)
7970Sstevel@tonic-gate 			vscandir[0] = genbuf[0];
7980Sstevel@tonic-gate 		oglobp = globp; CP(vutmp, genbuf); globp = vutmp;
7990Sstevel@tonic-gate 		d = peekc;
8000Sstevel@tonic-gate fromsemi:
8010Sstevel@tonic-gate 		ungetchar(0);
8020Sstevel@tonic-gate 		fixech();
8030Sstevel@tonic-gate 		CATCH
8040Sstevel@tonic-gate #ifndef CBREAK
8050Sstevel@tonic-gate 			/*
8060Sstevel@tonic-gate 			 * Lose typeahead (ick).
8070Sstevel@tonic-gate 			 */
8080Sstevel@tonic-gate 			vcook();
8090Sstevel@tonic-gate #endif
8100Sstevel@tonic-gate 			addr = address(cursor);
8110Sstevel@tonic-gate #ifndef CBREAK
8120Sstevel@tonic-gate 			vraw();
8130Sstevel@tonic-gate #endif
8140Sstevel@tonic-gate 		ONERR
8150Sstevel@tonic-gate #ifndef CBREAK
8160Sstevel@tonic-gate 			vraw();
8170Sstevel@tonic-gate #endif
8180Sstevel@tonic-gate slerr:
8190Sstevel@tonic-gate 			globp = oglobp;
8200Sstevel@tonic-gate 			dot = odot;
8210Sstevel@tonic-gate 			cursor = ocurs;
8220Sstevel@tonic-gate 			ungetchar(d);
8230Sstevel@tonic-gate 			splitw = 0;
8240Sstevel@tonic-gate 			vclean();
8250Sstevel@tonic-gate 			vjumpto(dot, ocurs, 0);
8260Sstevel@tonic-gate 			return;
8270Sstevel@tonic-gate 		ENDCATCH
8280Sstevel@tonic-gate 		if (globp == 0)
8290Sstevel@tonic-gate 			globp = (unsigned char *)"";
8300Sstevel@tonic-gate 		else if (peekc)
8310Sstevel@tonic-gate 			--globp;
8320Sstevel@tonic-gate 		if (*globp == ';') {
8330Sstevel@tonic-gate 			/* /foo/;/bar/ */
8340Sstevel@tonic-gate 			globp++;
8350Sstevel@tonic-gate 			dot = addr;
8360Sstevel@tonic-gate 			cursor = (unsigned char *)loc1;
8370Sstevel@tonic-gate 			goto fromsemi;
8380Sstevel@tonic-gate 		}
8390Sstevel@tonic-gate 		dot = odot;
8400Sstevel@tonic-gate 		ungetchar(d);
8410Sstevel@tonic-gate 		c = 0;
8420Sstevel@tonic-gate 		if (*globp == 'z')
8430Sstevel@tonic-gate 			globp++, c = '\n';
8440Sstevel@tonic-gate 		if (any(*globp, "^+-."))
8450Sstevel@tonic-gate 			c = *globp++;
8460Sstevel@tonic-gate 		i = 0;
8470Sstevel@tonic-gate 		while (isdigit(*globp))
8480Sstevel@tonic-gate 			i = i * 10 + *globp++ - '0';
8490Sstevel@tonic-gate 		if (any(*globp, "^+-."))
8500Sstevel@tonic-gate 			c = *globp++;
8510Sstevel@tonic-gate 		if (*globp) {
8520Sstevel@tonic-gate 			/* random junk after the pattern */
853802Scf46844 			(void) beep();
8540Sstevel@tonic-gate 			goto slerr;
8550Sstevel@tonic-gate 		}
8560Sstevel@tonic-gate 		globp = oglobp;
8570Sstevel@tonic-gate 		splitw = 0;
8580Sstevel@tonic-gate 		vmoving = 0;
8590Sstevel@tonic-gate 		wcursor = (unsigned char *)loc1;
8600Sstevel@tonic-gate 		if (i != 0)
8610Sstevel@tonic-gate 			vsetsiz(i);
8620Sstevel@tonic-gate 		if (opf == vmove) {
8630Sstevel@tonic-gate 			if (state == ONEOPEN || state == HARDOPEN)
8640Sstevel@tonic-gate 				outline = destline = WBOT;
8650Sstevel@tonic-gate 			if (addr != dot || (unsigned char *)loc1 != cursor)
8660Sstevel@tonic-gate 				markDOT();
8670Sstevel@tonic-gate 			if (loc1 > (char *)linebuf && *loc1 == 0)
8680Sstevel@tonic-gate 				loc1 = (char *)lastchr(linebuf, loc1);
8690Sstevel@tonic-gate 			if (c)
870802Scf46844 				vjumpto(addr, (unsigned char *)loc1, c);
8710Sstevel@tonic-gate 			else {
8720Sstevel@tonic-gate 				vmoving = 0;
8730Sstevel@tonic-gate 				if (loc1) {
8740Sstevel@tonic-gate 					vmoving++;
8750Sstevel@tonic-gate 					vmovcol = column(loc1);
8760Sstevel@tonic-gate 				}
8770Sstevel@tonic-gate 				getDOT();
8780Sstevel@tonic-gate 				if (state == CRTOPEN && addr != dot)
8790Sstevel@tonic-gate 					vup1();
8800Sstevel@tonic-gate 				vupdown(addr - dot, NOSTR);
8810Sstevel@tonic-gate 			}
8820Sstevel@tonic-gate 			if (oc == '/') {	/* forward search */
8830Sstevel@tonic-gate 				if (dot < odot ||
8840Sstevel@tonic-gate 				    (dot == odot && cursor <= ocurs))
8850Sstevel@tonic-gate 					warnf(value(vi_TERSE) ?
8860Sstevel@tonic-gate 			gettext("Search wrapped BOTTOM") :
8870Sstevel@tonic-gate 			gettext("Search wrapped around BOTTOM of buffer"));
8880Sstevel@tonic-gate 			} else {		/* backward search */
8890Sstevel@tonic-gate 				if (dot > odot ||
8900Sstevel@tonic-gate 				    (dot == odot && cursor >= ocurs))
8910Sstevel@tonic-gate 					warnf(value(vi_TERSE) ?
8920Sstevel@tonic-gate 			gettext("Search wrapped TOP") :
8930Sstevel@tonic-gate 			gettext("Search wrapped around TOP of buffer"));
8940Sstevel@tonic-gate 			}
8950Sstevel@tonic-gate 			return;
8960Sstevel@tonic-gate 		}
8970Sstevel@tonic-gate 		lastcp[-1] = 'n';
8980Sstevel@tonic-gate 		getDOT();
8990Sstevel@tonic-gate 		wdot = addr;
9000Sstevel@tonic-gate 		break;
9010Sstevel@tonic-gate 	}
9020Sstevel@tonic-gate 	/*
9030Sstevel@tonic-gate 	 * Apply.
9040Sstevel@tonic-gate 	 */
9050Sstevel@tonic-gate 	if (vreg && wdot == 0)
9060Sstevel@tonic-gate 		wdot = dot;
9070Sstevel@tonic-gate 	(*opf)(c);
9080Sstevel@tonic-gate 	wdot = NOLINE;
9090Sstevel@tonic-gate }
9100Sstevel@tonic-gate 
9110Sstevel@tonic-gate static void
lfixol()9120Sstevel@tonic-gate lfixol()
9130Sstevel@tonic-gate {
9140Sstevel@tonic-gate 	unsigned char *savevglobp;
9150Sstevel@tonic-gate 	int savesplit;
9160Sstevel@tonic-gate 
9170Sstevel@tonic-gate 	if (Outchar == vputchar)
9180Sstevel@tonic-gate 		return;
9190Sstevel@tonic-gate 
9200Sstevel@tonic-gate 	/* Show messages */
9210Sstevel@tonic-gate 	putnl();
9220Sstevel@tonic-gate 	if (inopen > 0 && clr_eol)
9230Sstevel@tonic-gate 		vclreol();
9240Sstevel@tonic-gate 	if (enter_standout_mode && exit_bold)
925802Scf46844 		putpad((unsigned char *)enter_standout_mode);
9260Sstevel@tonic-gate 	lprintf(gettext("[Hit return to continue] "), 0);
9270Sstevel@tonic-gate 	if (enter_standout_mode && exit_bold)
928802Scf46844 		putpad((unsigned char *)exit_bold);
9290Sstevel@tonic-gate 
9300Sstevel@tonic-gate 	/* Get key input for confirmation */
9310Sstevel@tonic-gate 	savevglobp = vglobp;
9320Sstevel@tonic-gate 	vglobp = 0; /* force typed input */
9330Sstevel@tonic-gate 	getkey();
9340Sstevel@tonic-gate 	vglobp = savevglobp;
9350Sstevel@tonic-gate 
9360Sstevel@tonic-gate 	/* reset output function */
9370Sstevel@tonic-gate 	Outchar = vputchar;
9380Sstevel@tonic-gate 
9390Sstevel@tonic-gate 	/* Clean up screen */
9400Sstevel@tonic-gate 	savesplit = splitw;
9410Sstevel@tonic-gate 	splitw = 0;
9420Sstevel@tonic-gate 	vclear();
9430Sstevel@tonic-gate 	vdirty(0, WLINES);
9440Sstevel@tonic-gate 	vredraw(WTOP);
9450Sstevel@tonic-gate 	splitw = savesplit;
9460Sstevel@tonic-gate }
9470Sstevel@tonic-gate 
948802Scf46844 void
warnf(char * str,char * cp)949802Scf46844 warnf(char *str, char *cp)
9500Sstevel@tonic-gate {
9510Sstevel@tonic-gate 	int saveline, savecol, savesplit;
9520Sstevel@tonic-gate 
9530Sstevel@tonic-gate 	saveline = outline;
9540Sstevel@tonic-gate 	savecol = outcol;
9550Sstevel@tonic-gate 	savesplit = splitw;
9560Sstevel@tonic-gate 	splitw = 1;
9570Sstevel@tonic-gate 	vgoto(WECHO, 0);
9580Sstevel@tonic-gate 	if (!enter_standout_mode || !exit_bold)
9590Sstevel@tonic-gate 		dingdong();
9600Sstevel@tonic-gate 	if (clr_eol)
9610Sstevel@tonic-gate 		vclreol();
9620Sstevel@tonic-gate 	if (enter_standout_mode && exit_bold)
963802Scf46844 		putpad((unsigned char *)enter_standout_mode);
9640Sstevel@tonic-gate 	lprintf(str, cp);
9650Sstevel@tonic-gate 	if (enter_standout_mode && exit_bold)
966802Scf46844 		putpad((unsigned char *)exit_bold);
9670Sstevel@tonic-gate 	lfixol();
9680Sstevel@tonic-gate 	vgoto(saveline, savecol);
9690Sstevel@tonic-gate 	splitw = savesplit;
9700Sstevel@tonic-gate }
9710Sstevel@tonic-gate 
9720Sstevel@tonic-gate /* #ifdef PTR_ADDRESSES */
9730Sstevel@tonic-gate /*
9740Sstevel@tonic-gate  *	read in a row or column address
9750Sstevel@tonic-gate  *
9760Sstevel@tonic-gate  */
9770Sstevel@tonic-gate static int
get_addr()9780Sstevel@tonic-gate get_addr()
9790Sstevel@tonic-gate {
980802Scf46844 	short  c;
981802Scf46844 	short  next;
9820Sstevel@tonic-gate 
9830Sstevel@tonic-gate 	c = getkey();
9840Sstevel@tonic-gate 	next = 0;
9850Sstevel@tonic-gate 	switch (c) {
9860Sstevel@tonic-gate 	case CTRL('A'):
9870Sstevel@tonic-gate 		next = 96;
9880Sstevel@tonic-gate 		c = getkey();
9890Sstevel@tonic-gate 		break;
9900Sstevel@tonic-gate 
9910Sstevel@tonic-gate 	case CTRL('B'):
9920Sstevel@tonic-gate 		next = 192;
9930Sstevel@tonic-gate 		c = getkey();
9940Sstevel@tonic-gate 		break;
9950Sstevel@tonic-gate 	}
9960Sstevel@tonic-gate 	if (c < ' ')
9970Sstevel@tonic-gate 		return (-1);
9980Sstevel@tonic-gate 	return (next + c - ' ');
9990Sstevel@tonic-gate }
10000Sstevel@tonic-gate /* #endif PTR_ADDRESSES */
10010Sstevel@tonic-gate 
10020Sstevel@tonic-gate /*
10030Sstevel@tonic-gate  * Find single character c, in direction dir from cursor.
10040Sstevel@tonic-gate  */
1005802Scf46844 int
find(wchar_t c)1006802Scf46844 find(wchar_t c)
10070Sstevel@tonic-gate {
10080Sstevel@tonic-gate 
10090Sstevel@tonic-gate 	wchar_t wchar;
10100Sstevel@tonic-gate 	int length;
10110Sstevel@tonic-gate 	for (;;) {
10120Sstevel@tonic-gate 		if (edge())
10130Sstevel@tonic-gate 			return (0);
10140Sstevel@tonic-gate 		if (dir == 1)
10150Sstevel@tonic-gate 			wcursor = nextchr(wcursor);
10160Sstevel@tonic-gate 		else
10170Sstevel@tonic-gate 			wcursor = lastchr(linebuf, wcursor);
10180Sstevel@tonic-gate 		if ((length = mbtowc(&wchar, (char *)wcursor,
10190Sstevel@tonic-gate 		    MULTI_BYTE_MAX)) > 0 && wchar == c)
10200Sstevel@tonic-gate 			return (1);
10210Sstevel@tonic-gate 	}
10220Sstevel@tonic-gate }
10230Sstevel@tonic-gate 
10240Sstevel@tonic-gate /*
10250Sstevel@tonic-gate  * Do a word motion with operator op, and cnt more words
10260Sstevel@tonic-gate  * to go after this.
10270Sstevel@tonic-gate  */
1028802Scf46844 int
word(int (* op)(),int cnt)1029802Scf46844 word(int (*op)(), int cnt)
10300Sstevel@tonic-gate {
1031802Scf46844 	int which;
1032802Scf46844 	unsigned char *iwc;
1033802Scf46844 	line *iwdot = wdot;
10340Sstevel@tonic-gate 	wchar_t wchar;
10350Sstevel@tonic-gate 	int length;
10360Sstevel@tonic-gate 
10370Sstevel@tonic-gate 	if (dir == 1) {
10380Sstevel@tonic-gate 		iwc = wcursor;
10390Sstevel@tonic-gate 		which = wordch(wcursor);
10400Sstevel@tonic-gate 		while (wordof(which, wcursor)) {
10410Sstevel@tonic-gate 			length = mbtowc(&wchar, (char *)wcursor,
10420Sstevel@tonic-gate 			    MULTI_BYTE_MAX);
10430Sstevel@tonic-gate 			if (length <= 0)
10440Sstevel@tonic-gate 				length = 1;
10450Sstevel@tonic-gate 			if (cnt == 1 && op != vmove && wcursor[length] == 0) {
10460Sstevel@tonic-gate 				wcursor += length;
10470Sstevel@tonic-gate 				break;
10480Sstevel@tonic-gate 			}
10490Sstevel@tonic-gate 			if (!lnext())
10500Sstevel@tonic-gate 				return (0);
10510Sstevel@tonic-gate 			if (wcursor == linebuf)
10520Sstevel@tonic-gate 				break;
10530Sstevel@tonic-gate 		}
10540Sstevel@tonic-gate 		/* Unless last segment of a change skip blanks */
1055802Scf46844 		if (op != (int (*)())vchange || cnt > 1)
10560Sstevel@tonic-gate 			while (!margin() && blank()) {
10570Sstevel@tonic-gate 				if (!lnext())
10580Sstevel@tonic-gate 					return (0);
10590Sstevel@tonic-gate 			}
10600Sstevel@tonic-gate 		else
10610Sstevel@tonic-gate 			if (wcursor == iwc && iwdot == wdot && *iwc)
10620Sstevel@tonic-gate 				wcursor = nextchr(wcursor);
10630Sstevel@tonic-gate 		if (op == vmove && margin()) {
10640Sstevel@tonic-gate 			wcursor = lastchr(linebuf, wcursor);
10650Sstevel@tonic-gate #ifdef XPG4
10660Sstevel@tonic-gate 			if (wcursor < linebuf) {
10670Sstevel@tonic-gate 				wcursor = linebuf;
10680Sstevel@tonic-gate 			}
10690Sstevel@tonic-gate #endif /* XPG4 */
10700Sstevel@tonic-gate 		}
10710Sstevel@tonic-gate 	} else {
10720Sstevel@tonic-gate 		if (!lnext())
10730Sstevel@tonic-gate 			return (0);
10740Sstevel@tonic-gate 		while (blank())
10750Sstevel@tonic-gate 			if (!lnext())
10760Sstevel@tonic-gate 				return (0);
10770Sstevel@tonic-gate 		if (!margin()) {
10780Sstevel@tonic-gate 			which = wordch(wcursor);
10790Sstevel@tonic-gate 			while (!margin() && wordof(which, wcursor))
10800Sstevel@tonic-gate 				wcursor = lastchr(linebuf, wcursor);
10810Sstevel@tonic-gate 		}
10820Sstevel@tonic-gate #ifdef PRESUNEUC
10830Sstevel@tonic-gate 		if (wcursor < linebuf || !wordof(which, wcursor))
10840Sstevel@tonic-gate 			wcursor = nextchr(wcursor);
10850Sstevel@tonic-gate #else
10860Sstevel@tonic-gate 		if (wcursor < linebuf)
10870Sstevel@tonic-gate 			wcursor++;
10880Sstevel@tonic-gate 		else if (!wordof(which, wcursor))
10890Sstevel@tonic-gate 			wcursor = nextchr(wcursor);
10900Sstevel@tonic-gate #endif /* PRESUNEUC */
10910Sstevel@tonic-gate 	}
10920Sstevel@tonic-gate 	return (1);
10930Sstevel@tonic-gate }
10940Sstevel@tonic-gate 
10950Sstevel@tonic-gate /*
10960Sstevel@tonic-gate  * To end of word, with operator op and cnt more motions
10970Sstevel@tonic-gate  * remaining after this.
10980Sstevel@tonic-gate  */
1099802Scf46844 int
eend(int (* op)())1100802Scf46844 eend(int (*op)())
11010Sstevel@tonic-gate {
1102802Scf46844 	int which;
11030Sstevel@tonic-gate 
11040Sstevel@tonic-gate 	if (!lnext())
11050Sstevel@tonic-gate 		return (0);
11060Sstevel@tonic-gate 	while (blank())
11070Sstevel@tonic-gate 		if (!lnext())
11080Sstevel@tonic-gate 			return (0);
11090Sstevel@tonic-gate 	which = wordch(wcursor);
11100Sstevel@tonic-gate 	while (wordof(which, wcursor)) {
11110Sstevel@tonic-gate 		if (wcursor[1] == 0) {
11120Sstevel@tonic-gate 			wcursor = nextchr(wcursor);
11130Sstevel@tonic-gate 			break;
11140Sstevel@tonic-gate 		}
11150Sstevel@tonic-gate 		if (!lnext())
11160Sstevel@tonic-gate 			return (0);
11170Sstevel@tonic-gate 	}
11180Sstevel@tonic-gate 	if (op == vyankit)
11190Sstevel@tonic-gate 		wcursor = lastchr(linebuf, wcursor) + 1;
1120802Scf46844 	else if (op != (int (*)())vchange && op != (int (*)())vdelete &&
1121802Scf46844 	    wcursor > linebuf)
11220Sstevel@tonic-gate 		wcursor = lastchr(linebuf, wcursor);
11230Sstevel@tonic-gate 	return (1);
11240Sstevel@tonic-gate }
11250Sstevel@tonic-gate 
11260Sstevel@tonic-gate /*
11270Sstevel@tonic-gate  * Wordof tells whether the character at *wc is in a word of
11280Sstevel@tonic-gate  * kind which (blank/nonblank words are 0, conservative words 1).
11290Sstevel@tonic-gate  */
1130802Scf46844 int
wordof(unsigned char which,unsigned char * wc)1131802Scf46844 wordof(unsigned char which, unsigned char *wc)
11320Sstevel@tonic-gate {
11330Sstevel@tonic-gate #ifdef PRESUNEUC
11340Sstevel@tonic-gate 
11350Sstevel@tonic-gate 	if (isspace(*wc))
11360Sstevel@tonic-gate #else
11370Sstevel@tonic-gate 	wchar_t z;
11380Sstevel@tonic-gate 
11390Sstevel@tonic-gate 	(void) mbtowc(&z, (char *)wc, MB_LEN_MAX);
11400Sstevel@tonic-gate 	if (iswspace(z))
11410Sstevel@tonic-gate #endif /* PRESUNEUC */
11420Sstevel@tonic-gate 		return (0);
11430Sstevel@tonic-gate 	return (!wdkind || wordch(wc) == which);
11440Sstevel@tonic-gate }
11450Sstevel@tonic-gate 
11460Sstevel@tonic-gate /*
11470Sstevel@tonic-gate  * Wordch tells whether character at *wc is a word character
11480Sstevel@tonic-gate  * i.e. an alfa, digit, or underscore.
11490Sstevel@tonic-gate  */
11500Sstevel@tonic-gate #ifdef PRESUNEUC
11510Sstevel@tonic-gate #define	SS2 0216
11520Sstevel@tonic-gate #define	SS3 0217
11530Sstevel@tonic-gate #endif /* PRESUNEUC */
11540Sstevel@tonic-gate 
1155802Scf46844 int
wordch(unsigned char * wc)1156802Scf46844 wordch(unsigned char *wc)
11570Sstevel@tonic-gate {
1158802Scf46844 	int length;
11590Sstevel@tonic-gate 	wchar_t c;
11600Sstevel@tonic-gate 
11610Sstevel@tonic-gate 	length = mbtowc(&c, (char *)wc, MULTI_BYTE_MAX);
11620Sstevel@tonic-gate 	if (length <= 0)
11630Sstevel@tonic-gate 		return (0);
11640Sstevel@tonic-gate 	if (length > 1)
11650Sstevel@tonic-gate #ifndef PRESUNEUC
11660Sstevel@tonic-gate 		if (wdwc)
11670Sstevel@tonic-gate 			return (*wdwc)(c);
11680Sstevel@tonic-gate 		else
11690Sstevel@tonic-gate #endif /* PRESUNEUC */
11700Sstevel@tonic-gate 		return (length);
11710Sstevel@tonic-gate #ifndef PRESUNEUC
11720Sstevel@tonic-gate 	return (isalpha(*wc) || isdigit(*wc) || *wc == '_');
11730Sstevel@tonic-gate #else
11740Sstevel@tonic-gate 	return (isalpha(c) || isdigit(c) || c == '_');
11750Sstevel@tonic-gate #endif /* PRESUNEUC */
11760Sstevel@tonic-gate }
11770Sstevel@tonic-gate 
11780Sstevel@tonic-gate /*
11790Sstevel@tonic-gate  * Edge tells when we hit the last character in the current line.
11800Sstevel@tonic-gate  */
1181802Scf46844 int
edge(void)1182802Scf46844 edge(void)
11830Sstevel@tonic-gate {
11840Sstevel@tonic-gate 
11850Sstevel@tonic-gate 	if (linebuf[0] == 0)
11860Sstevel@tonic-gate 		return (1);
11870Sstevel@tonic-gate 	if (dir == 1)
11880Sstevel@tonic-gate 		return (*(nextchr(wcursor)) == 0);
11890Sstevel@tonic-gate 	else
11900Sstevel@tonic-gate 		return (wcursor == linebuf);
11910Sstevel@tonic-gate }
11920Sstevel@tonic-gate 
11930Sstevel@tonic-gate /*
11940Sstevel@tonic-gate  * Margin tells us when we have fallen off the end of the line.
11950Sstevel@tonic-gate  */
1196802Scf46844 int
margin(void)1197802Scf46844 margin(void)
11980Sstevel@tonic-gate {
11990Sstevel@tonic-gate 
12000Sstevel@tonic-gate 	return (wcursor < linebuf || wcursor[0] == 0);
12010Sstevel@tonic-gate }
12020Sstevel@tonic-gate #ifndef PRESUNEUC
12030Sstevel@tonic-gate 
12040Sstevel@tonic-gate /*
12050Sstevel@tonic-gate  * Blank tells if the cursor is currently on a TAB, RETURN,
12060Sstevel@tonic-gate  * NEWLINE, FORMFEED, bertical tab, or SPACE character from EUC
12070Sstevel@tonic-gate  * primary and supplementary codesets.
12080Sstevel@tonic-gate  */
1209802Scf46844 int
blank(void)1210802Scf46844 blank(void)
12110Sstevel@tonic-gate {
12120Sstevel@tonic-gate 	wchar_t z;
12130Sstevel@tonic-gate 
12140Sstevel@tonic-gate 	(void) mbtowc(&z, (char *)wcursor, MB_CUR_MAX);
12150Sstevel@tonic-gate 	return (iswspace((int)z));
12160Sstevel@tonic-gate }
12170Sstevel@tonic-gate #endif /* PRESUNEUC */
1218