xref: /onnv-gate/usr/src/cmd/vi/port/ex_cmdsub.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
5*13093SRoger.Faulkner@Oracle.COM  * Common Development and Distribution License (the "License").
6*13093SRoger.Faulkner@Oracle.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 /* Copyright (c) 1981 Regents of the University of California */
310Sstevel@tonic-gate 
320Sstevel@tonic-gate #include "ex.h"
330Sstevel@tonic-gate #include "ex_argv.h"
340Sstevel@tonic-gate #include "ex_temp.h"
350Sstevel@tonic-gate #include "ex_tty.h"
360Sstevel@tonic-gate #include "ex_vis.h"
370Sstevel@tonic-gate #ifdef	STDIO
380Sstevel@tonic-gate #include	<stdio.h>
390Sstevel@tonic-gate #undef getchar
400Sstevel@tonic-gate #undef putchar
410Sstevel@tonic-gate #endif
420Sstevel@tonic-gate /*
430Sstevel@tonic-gate  * Command mode subroutines implementing
440Sstevel@tonic-gate  *	append, args, copy, delete, join, move, put,
450Sstevel@tonic-gate  *	shift, tag, yank, z and undo
460Sstevel@tonic-gate  */
470Sstevel@tonic-gate 
480Sstevel@tonic-gate bool	endline = 1;
490Sstevel@tonic-gate line	*tad1;
50802Scf46844 static int jnoop(void);
51802Scf46844 static void splitit(void);
52802Scf46844 int putchar(), getchar();
530Sstevel@tonic-gate int tags_flag;
540Sstevel@tonic-gate 
550Sstevel@tonic-gate /*
560Sstevel@tonic-gate  * Append after line a lines returned by function f.
570Sstevel@tonic-gate  * Be careful about intermediate states to avoid scramble
580Sstevel@tonic-gate  * if an interrupt comes in.
590Sstevel@tonic-gate  */
60802Scf46844 int
append(int (* f)(),line * a)61802Scf46844 append(int (*f)(), line *a)
620Sstevel@tonic-gate {
63802Scf46844 	line *a1, *a2, *rdot;
640Sstevel@tonic-gate 	int nline;
650Sstevel@tonic-gate 
660Sstevel@tonic-gate 	nline = 0;
670Sstevel@tonic-gate 	dot = a;
680Sstevel@tonic-gate 	if(FIXUNDO && !inopen && f!=getsub) {
690Sstevel@tonic-gate 		undap1 = undap2 = dot + 1;
700Sstevel@tonic-gate 		undkind = UNDCHANGE;
710Sstevel@tonic-gate 	}
720Sstevel@tonic-gate 	while ((*f)() == 0) {
730Sstevel@tonic-gate 		if (truedol >= endcore) {
740Sstevel@tonic-gate 			if (morelines() < 0) {
750Sstevel@tonic-gate 				if (FIXUNDO && f == getsub) {
760Sstevel@tonic-gate 					undap1 = addr1;
770Sstevel@tonic-gate 					undap2 = addr2 + 1;
780Sstevel@tonic-gate 				}
790Sstevel@tonic-gate 				error(value(vi_TERSE) ? gettext("Out of memory") :
800Sstevel@tonic-gate gettext("Out of memory- too many lines in file"));
810Sstevel@tonic-gate 			}
820Sstevel@tonic-gate 		}
830Sstevel@tonic-gate 		nline++;
840Sstevel@tonic-gate 		a1 = truedol + 1;
850Sstevel@tonic-gate 		a2 = a1 + 1;
860Sstevel@tonic-gate 		dot++;
870Sstevel@tonic-gate 		undap2++;
880Sstevel@tonic-gate 		dol++;
890Sstevel@tonic-gate 		unddol++;
900Sstevel@tonic-gate 		truedol++;
910Sstevel@tonic-gate 		for (rdot = dot; a1 > rdot;)
920Sstevel@tonic-gate 			*--a2 = *--a1;
930Sstevel@tonic-gate 		*rdot = 0;
940Sstevel@tonic-gate 		putmark(rdot);
950Sstevel@tonic-gate 		if (f == gettty) {
960Sstevel@tonic-gate 			dirtcnt++;
970Sstevel@tonic-gate 			TSYNC();
980Sstevel@tonic-gate 		}
990Sstevel@tonic-gate 	}
1000Sstevel@tonic-gate 	return (nline);
1010Sstevel@tonic-gate }
1020Sstevel@tonic-gate 
103802Scf46844 void
appendnone(void)104802Scf46844 appendnone(void)
1050Sstevel@tonic-gate {
1060Sstevel@tonic-gate 
1070Sstevel@tonic-gate 	if(FIXUNDO) {
1080Sstevel@tonic-gate 		undkind = UNDCHANGE;
1090Sstevel@tonic-gate 		undap1 = undap2 = addr1;
1100Sstevel@tonic-gate 	}
1110Sstevel@tonic-gate }
1120Sstevel@tonic-gate 
1130Sstevel@tonic-gate /*
1140Sstevel@tonic-gate  * Print out the argument list, with []'s around the current name.
1150Sstevel@tonic-gate  */
116802Scf46844 void
pargs(void)117802Scf46844 pargs(void)
1180Sstevel@tonic-gate {
119802Scf46844 	unsigned char **av = argv0, *as = args0;
120802Scf46844 	int ac;
1210Sstevel@tonic-gate 
1220Sstevel@tonic-gate 	for (ac = 0; ac < argc0; ac++) {
1230Sstevel@tonic-gate 		if (ac != 0)
1240Sstevel@tonic-gate 			putchar(' ');
1250Sstevel@tonic-gate 		if (ac + argc == argc0 - 1)
126802Scf46844 			viprintf("[");
1270Sstevel@tonic-gate 		lprintf("%s", as);
1280Sstevel@tonic-gate 		if (ac + argc == argc0 - 1)
129802Scf46844 			viprintf("]");
1300Sstevel@tonic-gate 		as = av ? *++av : strend(as) + 1;
1310Sstevel@tonic-gate 	}
1320Sstevel@tonic-gate 	noonl();
1330Sstevel@tonic-gate }
1340Sstevel@tonic-gate 
1350Sstevel@tonic-gate /*
1360Sstevel@tonic-gate  * Delete lines; two cases are if we are really deleting,
1370Sstevel@tonic-gate  * more commonly we are just moving lines to the undo save area.
1380Sstevel@tonic-gate  */
139802Scf46844 int
delete(bool hush)140802Scf46844 delete(bool hush)
1410Sstevel@tonic-gate {
142802Scf46844 	line *a1, *a2;
1430Sstevel@tonic-gate 
1440Sstevel@tonic-gate 	nonzero();
1450Sstevel@tonic-gate 	if(FIXUNDO) {
1460Sstevel@tonic-gate 		void (*dsavint)();
1470Sstevel@tonic-gate 
1480Sstevel@tonic-gate #ifdef UNDOTRACE
1490Sstevel@tonic-gate 		if (trace)
1500Sstevel@tonic-gate 			vudump("before delete");
1510Sstevel@tonic-gate #endif
1520Sstevel@tonic-gate 		change();
1530Sstevel@tonic-gate 		dsavint = signal(SIGINT, SIG_IGN);
1540Sstevel@tonic-gate 		undkind = UNDCHANGE;
1550Sstevel@tonic-gate 		a1 = addr1;
1560Sstevel@tonic-gate 		squish();
1570Sstevel@tonic-gate 		a2 = addr2;
1580Sstevel@tonic-gate 		if (a2++ != dol) {
1590Sstevel@tonic-gate 			reverse(a1, a2);
1600Sstevel@tonic-gate 			reverse(a2, dol + 1);
1610Sstevel@tonic-gate 			reverse(a1, dol + 1);
1620Sstevel@tonic-gate 		}
1630Sstevel@tonic-gate 		dol -= a2 - a1;
1640Sstevel@tonic-gate 		unddel = a1 - 1;
1650Sstevel@tonic-gate 		if (a1 > dol)
1660Sstevel@tonic-gate 			a1 = dol;
1670Sstevel@tonic-gate 		dot = a1;
1680Sstevel@tonic-gate 		pkill[0] = pkill[1] = 0;
1690Sstevel@tonic-gate 		signal(SIGINT, dsavint);
1700Sstevel@tonic-gate #ifdef UNDOTRACE
1710Sstevel@tonic-gate 		if (trace)
1720Sstevel@tonic-gate 			vudump("after delete");
1730Sstevel@tonic-gate #endif
1740Sstevel@tonic-gate 	} else {
175802Scf46844 		line *a3;
176802Scf46844 		int i;
1770Sstevel@tonic-gate 
1780Sstevel@tonic-gate 		change();
1790Sstevel@tonic-gate 		a1 = addr1;
1800Sstevel@tonic-gate 		a2 = addr2 + 1;
1810Sstevel@tonic-gate 		a3 = truedol;
1820Sstevel@tonic-gate 		i = a2 - a1;
1830Sstevel@tonic-gate 		unddol -= i;
1840Sstevel@tonic-gate 		undap2 -= i;
1850Sstevel@tonic-gate 		dol -= i;
1860Sstevel@tonic-gate 		truedol -= i;
1870Sstevel@tonic-gate 		do
1880Sstevel@tonic-gate 			*a1++ = *a2++;
1890Sstevel@tonic-gate 		while (a2 <= a3);
1900Sstevel@tonic-gate 		a1 = addr1;
1910Sstevel@tonic-gate 		if (a1 > dol)
1920Sstevel@tonic-gate 			a1 = dol;
1930Sstevel@tonic-gate 		dot = a1;
1940Sstevel@tonic-gate 	}
1950Sstevel@tonic-gate 	if (!hush)
1960Sstevel@tonic-gate 		killed();
197802Scf46844 	return (0);
1980Sstevel@tonic-gate }
1990Sstevel@tonic-gate 
200802Scf46844 void
deletenone(void)201802Scf46844 deletenone(void)
2020Sstevel@tonic-gate {
2030Sstevel@tonic-gate 
2040Sstevel@tonic-gate 	if(FIXUNDO) {
2050Sstevel@tonic-gate 		undkind = UNDCHANGE;
2060Sstevel@tonic-gate 		squish();
2070Sstevel@tonic-gate 		unddel = addr1;
2080Sstevel@tonic-gate 	}
2090Sstevel@tonic-gate }
2100Sstevel@tonic-gate 
2110Sstevel@tonic-gate /*
2120Sstevel@tonic-gate  * Crush out the undo save area, moving the open/visual
2130Sstevel@tonic-gate  * save area down in its place.
2140Sstevel@tonic-gate  */
215802Scf46844 void
squish(void)216802Scf46844 squish(void)
2170Sstevel@tonic-gate {
218802Scf46844 	line *a1 = dol + 1, *a2 = unddol + 1, *a3 = truedol + 1;
2190Sstevel@tonic-gate 
2200Sstevel@tonic-gate 	if(FIXUNDO) {
2210Sstevel@tonic-gate 		if (inopen == -1)
2220Sstevel@tonic-gate 			return;
2230Sstevel@tonic-gate 		if (a1 < a2 && a2 < a3)
2240Sstevel@tonic-gate 			do
2250Sstevel@tonic-gate 				*a1++ = *a2++;
2260Sstevel@tonic-gate 			while (a2 < a3);
2270Sstevel@tonic-gate 		truedol -= unddol - dol;
2280Sstevel@tonic-gate 		unddol = dol;
2290Sstevel@tonic-gate 	}
2300Sstevel@tonic-gate }
2310Sstevel@tonic-gate 
2320Sstevel@tonic-gate /*
2330Sstevel@tonic-gate  * Join lines.  Special hacks put in spaces, two spaces if
2340Sstevel@tonic-gate  * preceding line ends with '.', or no spaces if next line starts with ).
2350Sstevel@tonic-gate  */
236802Scf46844 static	int jcount;
2370Sstevel@tonic-gate 
238802Scf46844 int
join(int c)239802Scf46844 join(int c)
2400Sstevel@tonic-gate {
241802Scf46844 	line *a1;
242802Scf46844 	unsigned char *cp, *cp1;
2430Sstevel@tonic-gate #ifndef PRESUNEUC
244802Scf46844 	unsigned char *pcp;
245802Scf46844 	wchar_t *delim;
2460Sstevel@tonic-gate 	wchar_t wc1, wc2;
2470Sstevel@tonic-gate 	int n;
2480Sstevel@tonic-gate #endif /* PRESUNEUC */
2490Sstevel@tonic-gate 
2500Sstevel@tonic-gate 	cp = genbuf;
2510Sstevel@tonic-gate 	*cp = 0;
2520Sstevel@tonic-gate 	for (a1 = addr1; a1 <= addr2; a1++) {
253*13093SRoger.Faulkner@Oracle.COM 		getaline(*a1);
2540Sstevel@tonic-gate 		cp1 = linebuf;
2550Sstevel@tonic-gate 		if (a1 != addr1 && c == 0) {
2560Sstevel@tonic-gate 			while (*cp1 == ' ' || *cp1 == '\t')
2570Sstevel@tonic-gate 				cp1++;
2580Sstevel@tonic-gate 			if (*cp1 && cp > genbuf && cp[-1] != ' ' && cp[-1] != '\t') {
2590Sstevel@tonic-gate #ifndef PRESUNEUC
2600Sstevel@tonic-gate 				/*
2610Sstevel@tonic-gate 				 * insert locale-specific word delimiter if
2620Sstevel@tonic-gate 				 * either of end-of-former-line or
2630Sstevel@tonic-gate 				 * top-of-latter-line is non-ASCII.
2640Sstevel@tonic-gate 				 */
2650Sstevel@tonic-gate 				if (wddlm && *cp1 != ')' && cp[-1] != '.') {
2660Sstevel@tonic-gate 					if ((pcp = cp - MB_CUR_MAX) < genbuf)
2670Sstevel@tonic-gate 						pcp = genbuf;;
2680Sstevel@tonic-gate 					for ( ; pcp <= cp-1; pcp++) {
2690Sstevel@tonic-gate 						if ((n = mbtowc(&wc1,
2700Sstevel@tonic-gate 						    (char *)pcp, cp - pcp)) ==
2710Sstevel@tonic-gate 						    cp - pcp)
2720Sstevel@tonic-gate 							goto gotprev;
2730Sstevel@tonic-gate 					}
2740Sstevel@tonic-gate 					goto mberror;
2750Sstevel@tonic-gate gotprev:
2760Sstevel@tonic-gate 					if (!isascii(wc2 = *cp1)) {
2770Sstevel@tonic-gate 						if (mbtowc(&wc2, (char *) cp1,
2780Sstevel@tonic-gate 					    		   MB_CUR_MAX) <= 0)
2790Sstevel@tonic-gate 							goto mberror;
2800Sstevel@tonic-gate 					}
2810Sstevel@tonic-gate 					delim = (*wddlm)(wc1,wc2,2);
2820Sstevel@tonic-gate 					while (*delim)
2830Sstevel@tonic-gate 						cp += wctomb((char *)cp,
2840Sstevel@tonic-gate 						      *delim++);
2850Sstevel@tonic-gate 					*cp = 0;
2860Sstevel@tonic-gate 				} else
2870Sstevel@tonic-gate mberror:
2880Sstevel@tonic-gate #endif /* PRESUNEUC */
2890Sstevel@tonic-gate 				if (*cp1 != ')') {
2900Sstevel@tonic-gate 					*cp++ = ' ';
2910Sstevel@tonic-gate 					if (cp[-2] == '.')
2920Sstevel@tonic-gate 						*cp++ = ' ';
2930Sstevel@tonic-gate 				}
2940Sstevel@tonic-gate 			}
2950Sstevel@tonic-gate 		}
2960Sstevel@tonic-gate 		while (*cp++ = *cp1++)
2970Sstevel@tonic-gate 			if (cp > &genbuf[LBSIZE-2])
2980Sstevel@tonic-gate 				error(value(vi_TERSE) ? gettext("Line overflow") :
2990Sstevel@tonic-gate gettext("Result line of join would be too long"));
3000Sstevel@tonic-gate 		cp--;
3010Sstevel@tonic-gate 	}
3020Sstevel@tonic-gate 	strcLIN(genbuf);
303802Scf46844 	(void) delete(0);
3040Sstevel@tonic-gate 	jcount = 1;
3050Sstevel@tonic-gate 	if (FIXUNDO)
3060Sstevel@tonic-gate 		undap1 = undap2 = addr1;
3070Sstevel@tonic-gate 	(void)append(jnoop, --addr1);
3080Sstevel@tonic-gate 	if (FIXUNDO)
3090Sstevel@tonic-gate 		vundkind = VMANY;
310802Scf46844 	return (0);
3110Sstevel@tonic-gate }
3120Sstevel@tonic-gate 
313802Scf46844 static int
jnoop(void)314802Scf46844 jnoop(void)
3150Sstevel@tonic-gate {
3160Sstevel@tonic-gate 
3170Sstevel@tonic-gate 	return(--jcount);
3180Sstevel@tonic-gate }
3190Sstevel@tonic-gate 
3200Sstevel@tonic-gate /*
3210Sstevel@tonic-gate  * Move and copy lines.  Hard work is done by move1 which
3220Sstevel@tonic-gate  * is also called by undo.
3230Sstevel@tonic-gate  */
3240Sstevel@tonic-gate int	getcopy();
3250Sstevel@tonic-gate 
326802Scf46844 void
vi_move(void)327802Scf46844 vi_move(void)
3280Sstevel@tonic-gate {
329802Scf46844 	line *adt;
3300Sstevel@tonic-gate 	bool iscopy = 0;
3310Sstevel@tonic-gate 
3320Sstevel@tonic-gate 	if (Command[0] == 'm') {
3330Sstevel@tonic-gate 		setdot1();
3340Sstevel@tonic-gate 		markpr(addr2 == dot ? addr1 - 1 : addr2 + 1);
3350Sstevel@tonic-gate 	} else {
3360Sstevel@tonic-gate 		iscopy++;
3370Sstevel@tonic-gate 		setdot();
3380Sstevel@tonic-gate 	}
3390Sstevel@tonic-gate 	nonzero();
3400Sstevel@tonic-gate 	adt = address((char*)0);
3410Sstevel@tonic-gate 	if (adt == 0)
342802Scf46844 		serror(value(vi_TERSE) ?
343802Scf46844 		    (unsigned char *)gettext("%s where?") :
344802Scf46844 		    (unsigned char *)gettext("%s requires a trailing address"),
345802Scf46844 		    Command);
3460Sstevel@tonic-gate 	donewline();
3470Sstevel@tonic-gate 	move1(iscopy, adt);
3480Sstevel@tonic-gate 	killed();
3490Sstevel@tonic-gate }
3500Sstevel@tonic-gate 
351802Scf46844 void
move1(int cflag,line * addrt)352802Scf46844 move1(int cflag, line *addrt)
3530Sstevel@tonic-gate {
354802Scf46844 	line *adt, *ad1, *ad2;
3550Sstevel@tonic-gate 	int nlines;
3560Sstevel@tonic-gate 
3570Sstevel@tonic-gate 	adt = addrt;
3580Sstevel@tonic-gate 	nlines = (addr2 - addr1) + 1;
3590Sstevel@tonic-gate 	if (cflag) {
3600Sstevel@tonic-gate 		tad1 = addr1;
3610Sstevel@tonic-gate 		ad1 = dol;
3620Sstevel@tonic-gate 		(void)append(getcopy, ad1++);
3630Sstevel@tonic-gate 		ad2 = dol;
3640Sstevel@tonic-gate 	} else {
3650Sstevel@tonic-gate 		ad2 = addr2;
3660Sstevel@tonic-gate 		for (ad1 = addr1; ad1 <= ad2;)
3670Sstevel@tonic-gate 			*ad1++ &= ~01;
3680Sstevel@tonic-gate 		ad1 = addr1;
3690Sstevel@tonic-gate 	}
3700Sstevel@tonic-gate 	ad2++;
3710Sstevel@tonic-gate 	if (adt < ad1) {
3720Sstevel@tonic-gate 		if (adt + 1 == ad1 && !cflag && !inglobal)
3730Sstevel@tonic-gate 			error(gettext("That move would do nothing!"));
3740Sstevel@tonic-gate 		dot = adt + (ad2 - ad1);
3750Sstevel@tonic-gate 		if (++adt != ad1) {
3760Sstevel@tonic-gate 			reverse(adt, ad1);
3770Sstevel@tonic-gate 			reverse(ad1, ad2);
3780Sstevel@tonic-gate 			reverse(adt, ad2);
3790Sstevel@tonic-gate 		}
3800Sstevel@tonic-gate 	} else if (adt >= ad2) {
3810Sstevel@tonic-gate 		dot = adt++;
3820Sstevel@tonic-gate 		reverse(ad1, ad2);
3830Sstevel@tonic-gate 		reverse(ad2, adt);
3840Sstevel@tonic-gate 		reverse(ad1, adt);
3850Sstevel@tonic-gate 	} else
3860Sstevel@tonic-gate 		error(gettext("Move to a moved line"));
3870Sstevel@tonic-gate 	change();
3880Sstevel@tonic-gate 	if (!inglobal)
3890Sstevel@tonic-gate 		if(FIXUNDO) {
3900Sstevel@tonic-gate 			if (cflag) {
3910Sstevel@tonic-gate 				undap1 = addrt + 1;
3920Sstevel@tonic-gate 				undap2 = undap1 + nlines;
3930Sstevel@tonic-gate 				deletenone();
3940Sstevel@tonic-gate 			} else {
3950Sstevel@tonic-gate 				undkind = UNDMOVE;
3960Sstevel@tonic-gate 				undap1 = addr1;
3970Sstevel@tonic-gate 				undap2 = addr2;
3980Sstevel@tonic-gate 				unddel = addrt;
3990Sstevel@tonic-gate 				squish();
4000Sstevel@tonic-gate 			}
4010Sstevel@tonic-gate 		}
4020Sstevel@tonic-gate }
4030Sstevel@tonic-gate 
404802Scf46844 int
getcopy(void)405802Scf46844 getcopy(void)
4060Sstevel@tonic-gate {
4070Sstevel@tonic-gate 
4080Sstevel@tonic-gate 	if (tad1 > addr2)
4090Sstevel@tonic-gate 		return (EOF);
410*13093SRoger.Faulkner@Oracle.COM 	getaline(*tad1++);
4110Sstevel@tonic-gate 	return (0);
4120Sstevel@tonic-gate }
4130Sstevel@tonic-gate 
4140Sstevel@tonic-gate /*
4150Sstevel@tonic-gate  * Put lines in the buffer from the undo save area.
4160Sstevel@tonic-gate  */
417802Scf46844 int
getput(void)418802Scf46844 getput(void)
4190Sstevel@tonic-gate {
4200Sstevel@tonic-gate 
4210Sstevel@tonic-gate 	if (tad1 > unddol)
4220Sstevel@tonic-gate 		return (EOF);
423*13093SRoger.Faulkner@Oracle.COM 	getaline(*tad1++);
4240Sstevel@tonic-gate 	tad1++;
4250Sstevel@tonic-gate 	return (0);
4260Sstevel@tonic-gate }
4270Sstevel@tonic-gate 
428802Scf46844 int
put(void)429802Scf46844 put(void)
4300Sstevel@tonic-gate {
431802Scf46844 	int cnt;
4320Sstevel@tonic-gate 
4330Sstevel@tonic-gate 	if (!FIXUNDO)
4340Sstevel@tonic-gate 		error(gettext("Cannot put inside global/macro"));
4350Sstevel@tonic-gate 	cnt = unddol - dol;
4360Sstevel@tonic-gate 	if (cnt && inopen && pkill[0] && pkill[1]) {
4370Sstevel@tonic-gate 		pragged(1);
438802Scf46844 		return (0);
4390Sstevel@tonic-gate 	}
4400Sstevel@tonic-gate 	tad1 = dol + 1;
4410Sstevel@tonic-gate 	(void)append(getput, addr2);
4420Sstevel@tonic-gate 	undkind = UNDPUT;
4430Sstevel@tonic-gate 	notecnt = cnt;
4440Sstevel@tonic-gate 	netchange(cnt);
445802Scf46844 	return (0);
4460Sstevel@tonic-gate }
4470Sstevel@tonic-gate 
4480Sstevel@tonic-gate /*
4490Sstevel@tonic-gate  * A tricky put, of a group of lines in the middle
4500Sstevel@tonic-gate  * of an existing line.  Only from open/visual.
4510Sstevel@tonic-gate  * Argument says pkills have meaning, e.g. called from
4520Sstevel@tonic-gate  * put; it is 0 on calls from putreg.
4530Sstevel@tonic-gate  */
454802Scf46844 void
pragged(bool kill)455802Scf46844 pragged(bool kill)
4560Sstevel@tonic-gate {
4570Sstevel@tonic-gate 	extern unsigned char *cursor;
4580Sstevel@tonic-gate #ifdef XPG4
4590Sstevel@tonic-gate 	extern int P_cursor_offset;
4600Sstevel@tonic-gate #endif
461802Scf46844 	unsigned char *gp = &genbuf[cursor - linebuf];
4620Sstevel@tonic-gate 
4630Sstevel@tonic-gate 	/*
4640Sstevel@tonic-gate 	 * Assume the editor has:
4650Sstevel@tonic-gate 	 *
4660Sstevel@tonic-gate 	 *	cursor is on 'c'
4670Sstevel@tonic-gate 	 *
4680Sstevel@tonic-gate 	 *	file is:	1) abcd
4690Sstevel@tonic-gate 	 *			2) efgh
4700Sstevel@tonic-gate 	 *
4710Sstevel@tonic-gate 	 *	undo area:	3) 1
4720Sstevel@tonic-gate 	 *			4) 2
4730Sstevel@tonic-gate 	 *			5) 3
4740Sstevel@tonic-gate 	 */
4750Sstevel@tonic-gate 
4760Sstevel@tonic-gate 	if (!kill)
4770Sstevel@tonic-gate 		getDOT();
4780Sstevel@tonic-gate 
4790Sstevel@tonic-gate 	/*
4800Sstevel@tonic-gate 	 * Copy "abcd" into genbuf.
4810Sstevel@tonic-gate 	 * Note that gp points to 'c'.
4820Sstevel@tonic-gate 	 */
4830Sstevel@tonic-gate 
4840Sstevel@tonic-gate 	strcpy(genbuf, linebuf);
4850Sstevel@tonic-gate 
4860Sstevel@tonic-gate 	/*
4870Sstevel@tonic-gate 	 * Get last line of undo area ("3") into linebuf.
4880Sstevel@tonic-gate 	 */
4890Sstevel@tonic-gate 
490*13093SRoger.Faulkner@Oracle.COM 	getaline(*unddol);
4910Sstevel@tonic-gate 	if (kill)
4920Sstevel@tonic-gate 		*pkill[1] = 0;
4930Sstevel@tonic-gate 
4940Sstevel@tonic-gate 
4950Sstevel@tonic-gate 	/*
4960Sstevel@tonic-gate 	 * Concatenate trailing end of current line
4970Sstevel@tonic-gate 	 * into the last line of undo area:
4980Sstevel@tonic-gate 	 *	linebuf = "3cd"
4990Sstevel@tonic-gate 	 */
5000Sstevel@tonic-gate 
5010Sstevel@tonic-gate 	strcat(linebuf, gp);
5020Sstevel@tonic-gate #ifdef XPG4
5030Sstevel@tonic-gate 	P_cursor_offset = strlen(linebuf) - strlen(gp) - 1;
5040Sstevel@tonic-gate #endif
5050Sstevel@tonic-gate 
5060Sstevel@tonic-gate 	/*
5070Sstevel@tonic-gate 	 * Replace the last line with what is now in linebuf.
5080Sstevel@tonic-gate 	 * So unddol = "3cd"
5090Sstevel@tonic-gate 	 */
5100Sstevel@tonic-gate 
5110Sstevel@tonic-gate 	putmark(unddol);
5120Sstevel@tonic-gate 
5130Sstevel@tonic-gate 	/*
5140Sstevel@tonic-gate 	 * Get the first line of the undo save area into linebuf.
5150Sstevel@tonic-gate 	 * So linebuf = "1"
5160Sstevel@tonic-gate 	 */
5170Sstevel@tonic-gate 
518*13093SRoger.Faulkner@Oracle.COM 	getaline(dol[1]);
5190Sstevel@tonic-gate 	if (kill)
5200Sstevel@tonic-gate 		strcLIN(pkill[0]);
5210Sstevel@tonic-gate 
5220Sstevel@tonic-gate 	/*
5230Sstevel@tonic-gate 	 * Copy the first line of the undo save area
5240Sstevel@tonic-gate 	 * over what is pointed to by sp.
5250Sstevel@tonic-gate 	 *	genbuf = "ab1"
5260Sstevel@tonic-gate 	 */
5270Sstevel@tonic-gate 
5280Sstevel@tonic-gate 	strcpy(gp, linebuf);
5290Sstevel@tonic-gate 
5300Sstevel@tonic-gate 	/*
5310Sstevel@tonic-gate 	 * Now copy genbuf back into linebuf.
5320Sstevel@tonic-gate 	 *	linebuf = "ab1"
5330Sstevel@tonic-gate 	 */
5340Sstevel@tonic-gate 
5350Sstevel@tonic-gate 	strcLIN(genbuf);
5360Sstevel@tonic-gate 
5370Sstevel@tonic-gate 	/*
5380Sstevel@tonic-gate 	 * Now put linebuf back into the first line
5390Sstevel@tonic-gate 	 * of the undo save area.
5400Sstevel@tonic-gate 	 */
5410Sstevel@tonic-gate 
5420Sstevel@tonic-gate 	putmark(dol+1);
5430Sstevel@tonic-gate 
5440Sstevel@tonic-gate 	/*
5450Sstevel@tonic-gate 	 * Prepare to perform an undo which will actually
5460Sstevel@tonic-gate 	 * do a put of multiple lines in the middle of
5470Sstevel@tonic-gate 	 * the current line.
5480Sstevel@tonic-gate 	 */
5490Sstevel@tonic-gate 
5500Sstevel@tonic-gate 	undkind = UNDCHANGE;
5510Sstevel@tonic-gate 	undap1 = dot;
5520Sstevel@tonic-gate 	undap2 = dot + 1;
5530Sstevel@tonic-gate 	unddel = dot - 1;
5540Sstevel@tonic-gate 	undo(1);
5550Sstevel@tonic-gate }
5560Sstevel@tonic-gate 
5570Sstevel@tonic-gate /*
5580Sstevel@tonic-gate  * Shift lines, based on c.
5590Sstevel@tonic-gate  * If c is neither < nor >, then this is a lisp aligning =.
5600Sstevel@tonic-gate  */
561802Scf46844 void
shift(int c,int cnt)562802Scf46844 shift(int c, int cnt)
5630Sstevel@tonic-gate {
564802Scf46844 	line *addr;
565802Scf46844 	unsigned char *cp;
5660Sstevel@tonic-gate 	unsigned char *dp;
567802Scf46844 	int i;
5680Sstevel@tonic-gate 
5690Sstevel@tonic-gate 	if(FIXUNDO)
5700Sstevel@tonic-gate 		save12(), undkind = UNDCHANGE;
5710Sstevel@tonic-gate 	cnt *= value(vi_SHIFTWIDTH);
5720Sstevel@tonic-gate 	for (addr = addr1; addr <= addr2; addr++) {
5730Sstevel@tonic-gate 		dot = addr;
5740Sstevel@tonic-gate 		if (c == '=' && addr == addr1 && addr != addr2)
5750Sstevel@tonic-gate 			continue;
5760Sstevel@tonic-gate 		getDOT();
5770Sstevel@tonic-gate 		i = whitecnt(linebuf);
5780Sstevel@tonic-gate 		switch (c) {
5790Sstevel@tonic-gate 
5800Sstevel@tonic-gate 		case '>':
5810Sstevel@tonic-gate 			if (linebuf[0] == 0)
5820Sstevel@tonic-gate 				continue;
5830Sstevel@tonic-gate 			cp = genindent(i + cnt);
5840Sstevel@tonic-gate 			break;
5850Sstevel@tonic-gate 
5860Sstevel@tonic-gate 		case '<':
5870Sstevel@tonic-gate 			if (i == 0)
5880Sstevel@tonic-gate 				continue;
5890Sstevel@tonic-gate 			i -= cnt;
5900Sstevel@tonic-gate 			cp = i > 0 ? genindent(i) : genbuf;
5910Sstevel@tonic-gate 			break;
5920Sstevel@tonic-gate 
5930Sstevel@tonic-gate 		default:
5940Sstevel@tonic-gate 			i = lindent(addr);
5950Sstevel@tonic-gate 			getDOT();
5960Sstevel@tonic-gate 			cp = genindent(i);
5970Sstevel@tonic-gate 			break;
5980Sstevel@tonic-gate 		}
5990Sstevel@tonic-gate 		if (cp + strlen(dp = vpastwh(linebuf)) >= &genbuf[LBSIZE - 2])
6000Sstevel@tonic-gate 			error(value(vi_TERSE) ? gettext("Line too long") :
6010Sstevel@tonic-gate gettext("Result line after shift would be too long"));
6020Sstevel@tonic-gate 		CP(cp, dp);
6030Sstevel@tonic-gate 		strcLIN(genbuf);
6040Sstevel@tonic-gate 		putmark(addr);
6050Sstevel@tonic-gate 	}
6060Sstevel@tonic-gate 	killed();
6070Sstevel@tonic-gate }
6080Sstevel@tonic-gate 
6090Sstevel@tonic-gate /*
6100Sstevel@tonic-gate  * Find a tag in the tags file.
6110Sstevel@tonic-gate  * Most work here is in parsing the tags file itself.
6120Sstevel@tonic-gate  */
613802Scf46844 void
tagfind(quick)6140Sstevel@tonic-gate tagfind(quick)
6150Sstevel@tonic-gate 	bool quick;
6160Sstevel@tonic-gate {
6170Sstevel@tonic-gate 	unsigned char cmdbuf[BUFSIZE];
6180Sstevel@tonic-gate 	unsigned char filebuf[FNSIZE];
6190Sstevel@tonic-gate 	unsigned char tagfbuf[BUFSIZE];
620802Scf46844 	int c, d;
6210Sstevel@tonic-gate 	bool samef = 1;
6220Sstevel@tonic-gate 	int tfcount = 0;
6230Sstevel@tonic-gate 	int omagic, tl;
6240Sstevel@tonic-gate 	unsigned char *fn, *fne;
6250Sstevel@tonic-gate #ifdef STDIO		/* was VMUNIX */
6260Sstevel@tonic-gate 	/*
6270Sstevel@tonic-gate 	 * We have lots of room so we bring in stdio and do
6280Sstevel@tonic-gate 	 * a binary search on the tags file.
6290Sstevel@tonic-gate 	 */
6300Sstevel@tonic-gate 	FILE *iof;
6310Sstevel@tonic-gate 	unsigned char iofbuf[BUFSIZE];
6320Sstevel@tonic-gate 	off64_t mid;	/* assumed byte offset */
6330Sstevel@tonic-gate 	off64_t top, bot;	/* length of tag file */
6340Sstevel@tonic-gate 	struct stat64 sbuf;
6350Sstevel@tonic-gate #endif
6360Sstevel@tonic-gate 
6370Sstevel@tonic-gate 	omagic = value(vi_MAGIC);
6380Sstevel@tonic-gate 	tl = value(vi_TAGLENGTH);
6390Sstevel@tonic-gate 	if (!skipend()) {
640802Scf46844 		unsigned char *lp = lasttag;
6410Sstevel@tonic-gate 
6420Sstevel@tonic-gate 		while (!iswhite(peekchar()) && !endcmd(peekchar()))
6430Sstevel@tonic-gate 			if (lp < &lasttag[sizeof lasttag - 2])
6440Sstevel@tonic-gate 				*lp++ = getchar();
6450Sstevel@tonic-gate 			else
6460Sstevel@tonic-gate 				ignchar();
6470Sstevel@tonic-gate 		*lp++ = 0;
6480Sstevel@tonic-gate 		if (!endcmd(peekchar()))
6490Sstevel@tonic-gate badtag:
6500Sstevel@tonic-gate 			error(value(vi_TERSE) ? gettext("Bad tag") :
6510Sstevel@tonic-gate 				gettext("Give one tag per line"));
6520Sstevel@tonic-gate 	} else if (lasttag[0] == 0)
6530Sstevel@tonic-gate 		error(gettext("No previous tag"));
6540Sstevel@tonic-gate 	c = getchar();
6550Sstevel@tonic-gate 	if (!endcmd(c))
6560Sstevel@tonic-gate 		goto badtag;
6570Sstevel@tonic-gate 	if (c == EOF)
6580Sstevel@tonic-gate 		ungetchar(c);
6590Sstevel@tonic-gate 	clrstats();
6600Sstevel@tonic-gate 
6610Sstevel@tonic-gate 	/*
6620Sstevel@tonic-gate 	 * Loop once for each file in tags "path".
6630Sstevel@tonic-gate 	 *
6640Sstevel@tonic-gate 	 * System tags array limits to 4k (tags[ONMSZ]) long,
6650Sstevel@tonic-gate 	 * therefore, tagfbuf should be able to hold all tags.
6660Sstevel@tonic-gate 	 */
6670Sstevel@tonic-gate 
6680Sstevel@tonic-gate 	CP(tagfbuf, svalue(vi_TAGS));
6690Sstevel@tonic-gate 	fne = tagfbuf - 1;
6700Sstevel@tonic-gate 	while (fne) {
6710Sstevel@tonic-gate 		fn = ++fne;
6720Sstevel@tonic-gate 		while (*fne && *fne != ' ')
6730Sstevel@tonic-gate 			fne++;
6740Sstevel@tonic-gate 		if (*fne == 0)
6750Sstevel@tonic-gate 			fne = 0;	/* done, quit after this time */
6760Sstevel@tonic-gate 		else
6770Sstevel@tonic-gate 			*fne = 0;	/* null terminate filename */
6780Sstevel@tonic-gate #ifdef STDIO		/* was VMUNIX */
6790Sstevel@tonic-gate 		iof = fopen((char *)fn, "r");
6800Sstevel@tonic-gate 		if (iof == NULL)
6810Sstevel@tonic-gate 			continue;
6820Sstevel@tonic-gate 		tfcount++;
6830Sstevel@tonic-gate 		setbuf(iof, (char *)iofbuf);
6840Sstevel@tonic-gate 		fstat64(fileno(iof), &sbuf);
6850Sstevel@tonic-gate 		top = sbuf.st_size;
6860Sstevel@tonic-gate 		if (top == 0L || iof == NULL)
6870Sstevel@tonic-gate 			top = -1L;
6880Sstevel@tonic-gate 		bot = 0L;
6890Sstevel@tonic-gate 		while (top >= bot) {
6900Sstevel@tonic-gate 			/* loop for each tags file entry */
691802Scf46844 			unsigned char *cp = linebuf;
692802Scf46844 			unsigned char *lp = lasttag;
6930Sstevel@tonic-gate 			unsigned char *oglobp;
6940Sstevel@tonic-gate 
6950Sstevel@tonic-gate 			mid = (top + bot) / 2;
6960Sstevel@tonic-gate 			fseeko64(iof, mid, 0);
6970Sstevel@tonic-gate 			if (mid > 0)	/* to get first tag in file to work */
6980Sstevel@tonic-gate 				/* scan to next \n */
6990Sstevel@tonic-gate 				if(fgets((char *)linebuf, sizeof linebuf, iof)==NULL)
7000Sstevel@tonic-gate 					goto goleft;
7010Sstevel@tonic-gate 			/* get the line itself */
7020Sstevel@tonic-gate 			if(fgets((char *)linebuf, sizeof linebuf, iof)==NULL)
7030Sstevel@tonic-gate 				goto goleft;
7040Sstevel@tonic-gate 			linebuf[strlen(linebuf)-1] = 0;	/* was '\n' */
7050Sstevel@tonic-gate 			while (*cp && *lp == *cp)
7060Sstevel@tonic-gate 				cp++, lp++;
7070Sstevel@tonic-gate 			/*
7080Sstevel@tonic-gate 			 * This if decides whether there is a tag match.
7090Sstevel@tonic-gate 			 *  A positive taglength means that a
7100Sstevel@tonic-gate 			 *  match is found if the tag given matches at least
7110Sstevel@tonic-gate 			 *  taglength chars of the tag found.
7120Sstevel@tonic-gate 			 *  A taglength of greater than 511 means that a
7130Sstevel@tonic-gate 			 *  match is found even if the tag given is a proper
7140Sstevel@tonic-gate 			 *  prefix of the tag found.  i.e. "ab" matches "abcd"
7150Sstevel@tonic-gate 			 */
7160Sstevel@tonic-gate 			if ( *lp == 0 && (iswhite(*cp) || tl > 511 || tl > 0 && lp-lasttag >= tl) ) {
7170Sstevel@tonic-gate 				/*
7180Sstevel@tonic-gate 				 * Found a match.  Force selection to be
7190Sstevel@tonic-gate 				 *  the first possible.
7200Sstevel@tonic-gate 				 */
7210Sstevel@tonic-gate 				if ( mid == bot  &&  mid == top ) {
7220Sstevel@tonic-gate 					; /* found first possible match */
7230Sstevel@tonic-gate 				}
7240Sstevel@tonic-gate 				else {
7250Sstevel@tonic-gate 					/* postpone final decision. */
7260Sstevel@tonic-gate 					top = mid;
7270Sstevel@tonic-gate 					continue;
7280Sstevel@tonic-gate 				}
7290Sstevel@tonic-gate 			}
7300Sstevel@tonic-gate 			else {
7310Sstevel@tonic-gate 				if ((int)*lp > (int)*cp)
7320Sstevel@tonic-gate 					bot = mid + 1;
7330Sstevel@tonic-gate 				else
7340Sstevel@tonic-gate goleft:
7350Sstevel@tonic-gate 					top = mid - 1;
7360Sstevel@tonic-gate 				continue;
7370Sstevel@tonic-gate 			}
7380Sstevel@tonic-gate 			/*
7390Sstevel@tonic-gate 			 * We found the tag.  Decode the line in the file.
7400Sstevel@tonic-gate 			 */
7410Sstevel@tonic-gate 			fclose(iof);
7420Sstevel@tonic-gate 
7430Sstevel@tonic-gate 			/* Rest of tag if abbreviated */
7440Sstevel@tonic-gate 			while (!iswhite(*cp))
7450Sstevel@tonic-gate 				cp++;
7460Sstevel@tonic-gate 
7470Sstevel@tonic-gate 			/* name of file */
7480Sstevel@tonic-gate 			while (*cp && iswhite(*cp))
7490Sstevel@tonic-gate 				cp++;
7500Sstevel@tonic-gate 			if (!*cp)
7510Sstevel@tonic-gate badtags:
752802Scf46844 				serror((unsigned char *)
753802Scf46844 				    gettext("%s: Bad tags file entry"),
754802Scf46844 				    lasttag);
7550Sstevel@tonic-gate 			lp = filebuf;
7560Sstevel@tonic-gate 			while (*cp && *cp != ' ' && *cp != '\t') {
7570Sstevel@tonic-gate 				if (lp < &filebuf[sizeof filebuf - 2])
7580Sstevel@tonic-gate 					*lp++ = *cp;
7590Sstevel@tonic-gate 				cp++;
7600Sstevel@tonic-gate 			}
7610Sstevel@tonic-gate 			*lp++ = 0;
7620Sstevel@tonic-gate 
7630Sstevel@tonic-gate 			if (*cp == 0)
7640Sstevel@tonic-gate 				goto badtags;
7650Sstevel@tonic-gate 			if (dol != zero) {
7660Sstevel@tonic-gate 				/*
7670Sstevel@tonic-gate 				 * Save current position in 't for ^^ in visual.
7680Sstevel@tonic-gate 				 */
7690Sstevel@tonic-gate 				names['t'-'a'] = *dot &~ 01;
7700Sstevel@tonic-gate 				if (inopen) {
7710Sstevel@tonic-gate 					extern unsigned char *ncols['z'-'a'+2];
7720Sstevel@tonic-gate 					extern unsigned char *cursor;
7730Sstevel@tonic-gate 
7740Sstevel@tonic-gate 					ncols['t'-'a'] = cursor;
7750Sstevel@tonic-gate 				}
7760Sstevel@tonic-gate 			}
7770Sstevel@tonic-gate #ifdef TAG_STACK
7780Sstevel@tonic-gate                         if (*savedfile) {
779802Scf46844 				savetag((char *)savedfile);
7800Sstevel@tonic-gate                         }
7810Sstevel@tonic-gate #endif
7820Sstevel@tonic-gate 			strcpy(cmdbuf, cp);
7830Sstevel@tonic-gate 			if (strcmp(filebuf, savedfile) || !edited) {
7840Sstevel@tonic-gate 				unsigned char cmdbuf2[sizeof filebuf + 10];
7850Sstevel@tonic-gate 
7860Sstevel@tonic-gate 				/* Different file.  Do autowrite & get it. */
7870Sstevel@tonic-gate 				if (!quick) {
7880Sstevel@tonic-gate 					ckaw();
7890Sstevel@tonic-gate 					if (chng && dol > zero) {
7900Sstevel@tonic-gate #ifdef TAG_STACK
7910Sstevel@tonic-gate                                                 unsavetag();
7920Sstevel@tonic-gate #endif
7930Sstevel@tonic-gate 						error(value(vi_TERSE) ?
7940Sstevel@tonic-gate gettext("No write") : gettext("No write since last change (:tag! overrides)"));
7950Sstevel@tonic-gate 					}
7960Sstevel@tonic-gate 				}
7970Sstevel@tonic-gate 				oglobp = globp;
7980Sstevel@tonic-gate 				strcpy(cmdbuf2, "e! ");
7990Sstevel@tonic-gate 				strcat(cmdbuf2, filebuf);
8000Sstevel@tonic-gate 				globp = cmdbuf2;
8010Sstevel@tonic-gate 				d = peekc; ungetchar(0);
8020Sstevel@tonic-gate 				commands(1, 1);
8030Sstevel@tonic-gate 				peekc = d;
8040Sstevel@tonic-gate 				globp = oglobp;
8050Sstevel@tonic-gate 				value(vi_MAGIC) = omagic;
8060Sstevel@tonic-gate 				samef = 0;
8070Sstevel@tonic-gate 			}
8080Sstevel@tonic-gate 
8090Sstevel@tonic-gate 			/*
8100Sstevel@tonic-gate 			 * Look for pattern in the current file.
8110Sstevel@tonic-gate 			 */
8120Sstevel@tonic-gate 			oglobp = globp;
8130Sstevel@tonic-gate 			globp = cmdbuf;
8140Sstevel@tonic-gate 			d = peekc; ungetchar(0);
8150Sstevel@tonic-gate 			if (samef)
8160Sstevel@tonic-gate 				markpr(dot);
8170Sstevel@tonic-gate 			/*
8180Sstevel@tonic-gate 			 * BUG: if it isn't found (user edited header
8190Sstevel@tonic-gate 			 * line) we get left in nomagic mode.
8200Sstevel@tonic-gate 			 */
8210Sstevel@tonic-gate 			value(vi_MAGIC) = 0;
8220Sstevel@tonic-gate 			commands(1, 1);
8230Sstevel@tonic-gate 			peekc = d;
8240Sstevel@tonic-gate 			globp = oglobp;
8250Sstevel@tonic-gate 			value(vi_MAGIC) = omagic;
8260Sstevel@tonic-gate 			return;
8270Sstevel@tonic-gate 		}	/* end of "for each tag in file" */
8280Sstevel@tonic-gate #endif	/* STDIO */
8290Sstevel@tonic-gate 		/*
8300Sstevel@tonic-gate 		 * Binary search failed, so try linear search if -S is on.
8310Sstevel@tonic-gate 		 * -S is needed for tags files that are not sorted.
8320Sstevel@tonic-gate 		 */
8330Sstevel@tonic-gate 
8340Sstevel@tonic-gate 		/*
8350Sstevel@tonic-gate 		 * Avoid stdio and scan tag file linearly.
8360Sstevel@tonic-gate 		 */
8370Sstevel@tonic-gate 		if (tags_flag == 0)
8380Sstevel@tonic-gate 			continue;
8390Sstevel@tonic-gate 		io = open(fn, 0);
8400Sstevel@tonic-gate 		if (io < 0)
8410Sstevel@tonic-gate 			continue;
8420Sstevel@tonic-gate 		/* tfcount++; */
8430Sstevel@tonic-gate 		while (getfile() == 0) {
8440Sstevel@tonic-gate 			/* loop for each tags file entry */
845802Scf46844 			unsigned char *cp = linebuf;
846802Scf46844 			unsigned char *lp = lasttag;
8470Sstevel@tonic-gate 			unsigned char *oglobp;
8480Sstevel@tonic-gate 
8490Sstevel@tonic-gate 			while (*cp && *lp == *cp)
8500Sstevel@tonic-gate 				cp++, lp++;
8510Sstevel@tonic-gate 			/*
8520Sstevel@tonic-gate 			 * This if decides whether there is a tag match.
8530Sstevel@tonic-gate 			 *  A positive taglength means that a
8540Sstevel@tonic-gate 			 *  match is found if the tag given matches at least
8550Sstevel@tonic-gate 			 *  taglength chars of the tag found.
8560Sstevel@tonic-gate 			 *  A taglength of greater than 511 means that a
8570Sstevel@tonic-gate 			 *  match is found even if the tag given is a proper
8580Sstevel@tonic-gate 			 *  prefix of the tag found.  i.e. "ab" matches "abcd"
8590Sstevel@tonic-gate 			 */
8600Sstevel@tonic-gate 			if ( *lp == 0 && (iswhite(*cp) || tl > 511 || tl > 0 && lp-lasttag >= tl) ) {
8610Sstevel@tonic-gate 				; /* Found it. */
8620Sstevel@tonic-gate 			}
8630Sstevel@tonic-gate 			else {
8640Sstevel@tonic-gate 				/* Not this tag.  Try the next */
8650Sstevel@tonic-gate 				continue;
8660Sstevel@tonic-gate 			}
8670Sstevel@tonic-gate 			/*
8680Sstevel@tonic-gate 			 * We found the tag.  Decode the line in the file.
8690Sstevel@tonic-gate 			 */
8700Sstevel@tonic-gate 			close(io);
8710Sstevel@tonic-gate 			/* Rest of tag if abbreviated */
8720Sstevel@tonic-gate 			while (!iswhite(*cp))
8730Sstevel@tonic-gate 				cp++;
8740Sstevel@tonic-gate 
8750Sstevel@tonic-gate 			/* name of file */
8760Sstevel@tonic-gate 			while (*cp && iswhite(*cp))
8770Sstevel@tonic-gate 				cp++;
8780Sstevel@tonic-gate 			if (!*cp)
8790Sstevel@tonic-gate badtags2:
880802Scf46844 				serror((unsigned char *)
881802Scf46844 				    gettext("%s: Bad tags file entry"),
882802Scf46844 				    lasttag);
8830Sstevel@tonic-gate 			lp = filebuf;
8840Sstevel@tonic-gate 			while (*cp && *cp != ' ' && *cp != '\t') {
8850Sstevel@tonic-gate 				if (lp < &filebuf[sizeof filebuf - 2])
8860Sstevel@tonic-gate 					*lp++ = *cp;
8870Sstevel@tonic-gate 				cp++;
8880Sstevel@tonic-gate 			}
8890Sstevel@tonic-gate 			*lp++ = 0;
8900Sstevel@tonic-gate 
8910Sstevel@tonic-gate 			if (*cp == 0)
8920Sstevel@tonic-gate 				goto badtags2;
8930Sstevel@tonic-gate 			if (dol != zero) {
8940Sstevel@tonic-gate 				/*
8950Sstevel@tonic-gate 				 * Save current position in 't for ^^ in visual.
8960Sstevel@tonic-gate 				 */
8970Sstevel@tonic-gate 				names['t'-'a'] = *dot &~ 01;
8980Sstevel@tonic-gate 				if (inopen) {
8990Sstevel@tonic-gate 					extern unsigned char *ncols['z'-'a'+2];
9000Sstevel@tonic-gate 					extern unsigned char *cursor;
9010Sstevel@tonic-gate 
9020Sstevel@tonic-gate 					ncols['t'-'a'] = cursor;
9030Sstevel@tonic-gate 				}
9040Sstevel@tonic-gate 			}
9050Sstevel@tonic-gate #ifdef TAG_STACK
9060Sstevel@tonic-gate                         if (*savedfile) {
907802Scf46844 				savetag((char *)savedfile);
9080Sstevel@tonic-gate                         }
9090Sstevel@tonic-gate #endif
9100Sstevel@tonic-gate 			strcpy(cmdbuf, cp);
9110Sstevel@tonic-gate 			if (strcmp(filebuf, savedfile) || !edited) {
9120Sstevel@tonic-gate 				unsigned char cmdbuf2[sizeof filebuf + 10];
9130Sstevel@tonic-gate 
9140Sstevel@tonic-gate 				/* Different file.  Do autowrite & get it. */
9150Sstevel@tonic-gate 				if (!quick) {
9160Sstevel@tonic-gate 					ckaw();
9170Sstevel@tonic-gate 					if (chng && dol > zero) {
9180Sstevel@tonic-gate #ifdef TAG_STACK
9190Sstevel@tonic-gate                                                 unsavetag();
9200Sstevel@tonic-gate #endif
9210Sstevel@tonic-gate 						error(value(vi_TERSE) ?
9220Sstevel@tonic-gate gettext("No write") : gettext("No write since last change (:tag! overrides)"));
9230Sstevel@tonic-gate 					}
9240Sstevel@tonic-gate 				}
9250Sstevel@tonic-gate 				oglobp = globp;
9260Sstevel@tonic-gate 				strcpy(cmdbuf2, "e! ");
9270Sstevel@tonic-gate 				strcat(cmdbuf2, filebuf);
9280Sstevel@tonic-gate 				globp = cmdbuf2;
9290Sstevel@tonic-gate 				d = peekc; ungetchar(0);
9300Sstevel@tonic-gate 				commands(1, 1);
9310Sstevel@tonic-gate 				peekc = d;
9320Sstevel@tonic-gate 				globp = oglobp;
9330Sstevel@tonic-gate 				value(vi_MAGIC) = omagic;
9340Sstevel@tonic-gate 				samef = 0;
9350Sstevel@tonic-gate 			}
9360Sstevel@tonic-gate 
9370Sstevel@tonic-gate 			/*
9380Sstevel@tonic-gate 			 * Look for pattern in the current file.
9390Sstevel@tonic-gate 			 */
9400Sstevel@tonic-gate 			oglobp = globp;
9410Sstevel@tonic-gate 			globp = cmdbuf;
9420Sstevel@tonic-gate 			d = peekc; ungetchar(0);
9430Sstevel@tonic-gate 			if (samef)
9440Sstevel@tonic-gate 				markpr(dot);
9450Sstevel@tonic-gate 			/*
9460Sstevel@tonic-gate 			 * BUG: if it isn't found (user edited header
9470Sstevel@tonic-gate 			 * line) we get left in nomagic mode.
9480Sstevel@tonic-gate 			 */
9490Sstevel@tonic-gate 			value(vi_MAGIC) = 0;
9500Sstevel@tonic-gate 			commands(1, 1);
9510Sstevel@tonic-gate 			peekc = d;
9520Sstevel@tonic-gate 			globp = oglobp;
9530Sstevel@tonic-gate 			value(vi_MAGIC) = omagic;
9540Sstevel@tonic-gate 			return;
9550Sstevel@tonic-gate 		}	/* end of "for each tag in file" */
9560Sstevel@tonic-gate 
9570Sstevel@tonic-gate 		/*
9580Sstevel@tonic-gate 		 * No such tag in this file.  Close it and try the next.
9590Sstevel@tonic-gate 		 */
9600Sstevel@tonic-gate #ifdef STDIO		/* was VMUNIX */
9610Sstevel@tonic-gate 		fclose(iof);
9620Sstevel@tonic-gate #else
9630Sstevel@tonic-gate 		close(io);
9640Sstevel@tonic-gate #endif
9650Sstevel@tonic-gate 	}	/* end of "for each file in path" */
9660Sstevel@tonic-gate 	if (tfcount <= 0)
9670Sstevel@tonic-gate 		error(gettext("No tags file"));
9680Sstevel@tonic-gate 	else
969802Scf46844 		serror(value(vi_TERSE) ?
970802Scf46844 		    (unsigned char *)gettext("%s: No such tag") :
971802Scf46844 		    (unsigned char *)gettext("%s: No such tag in tags file"),
972802Scf46844 		    lasttag);
9730Sstevel@tonic-gate }
9740Sstevel@tonic-gate 
9750Sstevel@tonic-gate /*
9760Sstevel@tonic-gate  * Save lines from addr1 thru addr2 as though
9770Sstevel@tonic-gate  * they had been deleted.
9780Sstevel@tonic-gate  */
979802Scf46844 int
yank(void)980802Scf46844 yank(void)
9810Sstevel@tonic-gate {
9820Sstevel@tonic-gate 
9830Sstevel@tonic-gate 	if (!FIXUNDO)
9840Sstevel@tonic-gate 		error(gettext("Can't yank inside global/macro"));
9850Sstevel@tonic-gate 	save12();
9860Sstevel@tonic-gate 	undkind = UNDNONE;
9870Sstevel@tonic-gate 	killcnt(addr2 - addr1 + 1);
988802Scf46844 	return (0);
9890Sstevel@tonic-gate }
9900Sstevel@tonic-gate 
9910Sstevel@tonic-gate /*
9920Sstevel@tonic-gate  * z command; print windows of text in the file.
9930Sstevel@tonic-gate  *
9940Sstevel@tonic-gate  * If this seems unreasonably arcane, the reasons
9950Sstevel@tonic-gate  * are historical.  This is one of the first commands
9960Sstevel@tonic-gate  * added to the first ex (then called en) and the
9970Sstevel@tonic-gate  * number of facilities here were the major advantage
9980Sstevel@tonic-gate  * of en over ed since they allowed more use to be
9990Sstevel@tonic-gate  * made of fast terminals w/o typing .,.22p all the time.
10000Sstevel@tonic-gate  */
10010Sstevel@tonic-gate bool	zhadpr;
10020Sstevel@tonic-gate bool	znoclear;
10030Sstevel@tonic-gate short	zweight;
10040Sstevel@tonic-gate 
1005802Scf46844 void
zop(int hadpr)1006802Scf46844 zop(int hadpr)
10070Sstevel@tonic-gate {
1008802Scf46844 	int c, nlines, op;
10090Sstevel@tonic-gate 	bool excl;
10100Sstevel@tonic-gate 
10110Sstevel@tonic-gate 	zhadpr = hadpr;
10120Sstevel@tonic-gate 	notempty();
10130Sstevel@tonic-gate 	znoclear = 0;
10140Sstevel@tonic-gate 	zweight = 0;
10150Sstevel@tonic-gate 	excl = exclam();
10160Sstevel@tonic-gate 	switch (c = op = getchar()) {
10170Sstevel@tonic-gate 
10180Sstevel@tonic-gate 	case '^':
10190Sstevel@tonic-gate 		zweight = 1;
10200Sstevel@tonic-gate 	case '-':
10210Sstevel@tonic-gate 	case '+':
10220Sstevel@tonic-gate 		while (peekchar() == op) {
10230Sstevel@tonic-gate 			ignchar();
10240Sstevel@tonic-gate 			zweight++;
10250Sstevel@tonic-gate 		}
10260Sstevel@tonic-gate 	case '=':
10270Sstevel@tonic-gate 	case '.':
10280Sstevel@tonic-gate 		c = getchar();
10290Sstevel@tonic-gate 		break;
10300Sstevel@tonic-gate 
10310Sstevel@tonic-gate 	case EOF:
10320Sstevel@tonic-gate 		znoclear++;
10330Sstevel@tonic-gate 		break;
10340Sstevel@tonic-gate 
10350Sstevel@tonic-gate 	default:
10360Sstevel@tonic-gate 		op = 0;
10370Sstevel@tonic-gate 		break;
10380Sstevel@tonic-gate 	}
10390Sstevel@tonic-gate 	if (isdigit(c)) {
10400Sstevel@tonic-gate 		nlines = c - '0';
10410Sstevel@tonic-gate 		for(;;) {
10420Sstevel@tonic-gate 			c = getchar();
10430Sstevel@tonic-gate 			if (!isdigit(c))
10440Sstevel@tonic-gate 				break;
10450Sstevel@tonic-gate 			nlines *= 10;
10460Sstevel@tonic-gate 			nlines += c - '0';
10470Sstevel@tonic-gate 		}
10480Sstevel@tonic-gate 		if (nlines < lines)
10490Sstevel@tonic-gate 			znoclear++;
10500Sstevel@tonic-gate 		value(vi_WINDOW) = nlines;
10510Sstevel@tonic-gate 		if (op == '=')
10520Sstevel@tonic-gate 			nlines += 2;
10530Sstevel@tonic-gate 	}
10540Sstevel@tonic-gate 	else {
10550Sstevel@tonic-gate 		nlines = op == EOF ? value(vi_SCROLL) :
10560Sstevel@tonic-gate 			excl ? lines - 1 : value(vi_WINDOW);
10570Sstevel@tonic-gate 	}
10580Sstevel@tonic-gate 	if (inopen || c != EOF) {
10590Sstevel@tonic-gate 		ungetchar(c);
10600Sstevel@tonic-gate 		donewline();
10610Sstevel@tonic-gate 	}
10620Sstevel@tonic-gate 	addr1 = addr2;
10630Sstevel@tonic-gate 	if (addr2 == 0 && dot < dol && op == 0)
10640Sstevel@tonic-gate 		addr1 = addr2 = dot+1;
10650Sstevel@tonic-gate 	setdot();
10660Sstevel@tonic-gate 	zop2(nlines, op);
10670Sstevel@tonic-gate }
10680Sstevel@tonic-gate 
1069802Scf46844 void
zop2(int nlines,int op)1070802Scf46844 zop2(int nlines, int op)
10710Sstevel@tonic-gate {
1072802Scf46844 	line *split;
10730Sstevel@tonic-gate 
10740Sstevel@tonic-gate 	split = NULL;
10750Sstevel@tonic-gate 	switch (op) {
10760Sstevel@tonic-gate 
10770Sstevel@tonic-gate 	case EOF:
10780Sstevel@tonic-gate 		if (addr2 == dol)
10790Sstevel@tonic-gate 			error(gettext("\nAt EOF"));
10800Sstevel@tonic-gate 	case '+':
10810Sstevel@tonic-gate 		if (addr2 == dol)
10820Sstevel@tonic-gate 			error(gettext("At EOF"));
10830Sstevel@tonic-gate 		addr2 += nlines * zweight;
10840Sstevel@tonic-gate 		if (addr2 > dol)
10850Sstevel@tonic-gate 			error(gettext("Hit BOTTOM"));
10860Sstevel@tonic-gate 		addr2++;
10870Sstevel@tonic-gate 	default:
10880Sstevel@tonic-gate 		addr1 = addr2;
10890Sstevel@tonic-gate 		addr2 += nlines-1;
10900Sstevel@tonic-gate 		dot = addr2;
10910Sstevel@tonic-gate 		break;
10920Sstevel@tonic-gate 
10930Sstevel@tonic-gate 	case '=':
10940Sstevel@tonic-gate 	case '.':
10950Sstevel@tonic-gate 		znoclear = 0;
10960Sstevel@tonic-gate 		nlines--;
10970Sstevel@tonic-gate 		nlines >>= 1;
10980Sstevel@tonic-gate 		if (op == '=')
10990Sstevel@tonic-gate 			nlines--;
11000Sstevel@tonic-gate 		addr1 = addr2 - nlines;
11010Sstevel@tonic-gate 		if (op == '=')
11020Sstevel@tonic-gate 			dot = split = addr2;
11030Sstevel@tonic-gate 		addr2 += nlines;
11040Sstevel@tonic-gate 		if (op == '.') {
11050Sstevel@tonic-gate 			markDOT();
11060Sstevel@tonic-gate 			dot = addr2;
11070Sstevel@tonic-gate 		}
11080Sstevel@tonic-gate 		break;
11090Sstevel@tonic-gate 
11100Sstevel@tonic-gate 	case '^':
11110Sstevel@tonic-gate 	case '-':
11120Sstevel@tonic-gate 		addr2 -= nlines * zweight;
11130Sstevel@tonic-gate 		if (addr2 < one)
11140Sstevel@tonic-gate 			error(gettext("Hit TOP"));
11150Sstevel@tonic-gate 		nlines--;
11160Sstevel@tonic-gate 		addr1 = addr2 - nlines;
11170Sstevel@tonic-gate 		dot = addr2;
11180Sstevel@tonic-gate 		break;
11190Sstevel@tonic-gate 	}
11200Sstevel@tonic-gate 	if (addr1 <= zero)
11210Sstevel@tonic-gate 		addr1 = one;
11220Sstevel@tonic-gate 	if (addr2 > dol)
11230Sstevel@tonic-gate 		addr2 = dol;
11240Sstevel@tonic-gate 	if (dot > dol)
11250Sstevel@tonic-gate 		dot = dol;
11260Sstevel@tonic-gate 	if (addr1 > addr2)
11270Sstevel@tonic-gate 		return;
11280Sstevel@tonic-gate 	if (op == EOF && zhadpr) {
1129*13093SRoger.Faulkner@Oracle.COM 		getaline(*addr1);
11300Sstevel@tonic-gate 		putchar((int)('\r' | QUOTE));
11310Sstevel@tonic-gate 		shudclob = 1;
11320Sstevel@tonic-gate 	} else if (znoclear == 0 && clear_screen != NOSTR && !inopen) {
11330Sstevel@tonic-gate 		flush1();
11340Sstevel@tonic-gate 		vclear();
11350Sstevel@tonic-gate 	}
11360Sstevel@tonic-gate 	if (addr2 - addr1 > 1)
11370Sstevel@tonic-gate 		pstart();
11380Sstevel@tonic-gate 	if (split) {
11390Sstevel@tonic-gate 		plines(addr1, split - 1, 0);
11400Sstevel@tonic-gate 		splitit();
11410Sstevel@tonic-gate 		plines(split, split, 0);
11420Sstevel@tonic-gate 		splitit();
11430Sstevel@tonic-gate 		addr1 = split + 1;
11440Sstevel@tonic-gate 	}
11450Sstevel@tonic-gate 	plines(addr1, addr2, 0);
11460Sstevel@tonic-gate }
11470Sstevel@tonic-gate 
1148802Scf46844 static void
splitit(void)1149802Scf46844 splitit(void)
11500Sstevel@tonic-gate {
1151802Scf46844 	int l;
11520Sstevel@tonic-gate 
11530Sstevel@tonic-gate 	for (l = columns > 80 ? 40 : columns / 2; l > 0; l--)
11540Sstevel@tonic-gate 		putchar('-');
11550Sstevel@tonic-gate 	putnl();
11560Sstevel@tonic-gate }
11570Sstevel@tonic-gate 
1158802Scf46844 void
plines(line * adr1,line * adr2,bool movedot)1159802Scf46844 plines(line *adr1, line *adr2, bool movedot)
11600Sstevel@tonic-gate {
1161802Scf46844 	line *addr;
11620Sstevel@tonic-gate 
11630Sstevel@tonic-gate 	pofix();
11640Sstevel@tonic-gate 	for (addr = adr1; addr <= adr2; addr++) {
1165*13093SRoger.Faulkner@Oracle.COM 		getaline(*addr);
11660Sstevel@tonic-gate 		pline(lineno(addr));
11670Sstevel@tonic-gate 		if (inopen)
11680Sstevel@tonic-gate 			putchar((int)('\n' | QUOTE));
11690Sstevel@tonic-gate 		if (movedot)
11700Sstevel@tonic-gate 			dot = addr;
11710Sstevel@tonic-gate 	}
11720Sstevel@tonic-gate }
11730Sstevel@tonic-gate 
1174802Scf46844 void
pofix(void)1175802Scf46844 pofix(void)
11760Sstevel@tonic-gate {
11770Sstevel@tonic-gate 
11780Sstevel@tonic-gate 	if (inopen && Outchar != termchar) {
11790Sstevel@tonic-gate 		vnfl();
11800Sstevel@tonic-gate 		setoutt();
11810Sstevel@tonic-gate 	}
11820Sstevel@tonic-gate }
11830Sstevel@tonic-gate 
11840Sstevel@tonic-gate /*
11850Sstevel@tonic-gate  * Command level undo works easily because
11860Sstevel@tonic-gate  * the editor has a unique temporary file
11870Sstevel@tonic-gate  * index for every line which ever existed.
11880Sstevel@tonic-gate  * We don't have to save large blocks of text,
11890Sstevel@tonic-gate  * only the indices which are small.  We do this
11900Sstevel@tonic-gate  * by moving them to after the last line in the
11910Sstevel@tonic-gate  * line buffer array, and marking down info
11920Sstevel@tonic-gate  * about whence they came.
11930Sstevel@tonic-gate  *
11940Sstevel@tonic-gate  * Undo is its own inverse.
11950Sstevel@tonic-gate  */
1196802Scf46844 void
undo(bool c)1197802Scf46844 undo(bool c)
11980Sstevel@tonic-gate {
1199802Scf46844 	int i, k;
1200802Scf46844 	line *jp, *kp, *j;
12010Sstevel@tonic-gate 	line *dolp1, *newdol, *newadot;
12020Sstevel@tonic-gate 
12030Sstevel@tonic-gate #ifdef UNDOTRACE
12040Sstevel@tonic-gate 	if (trace)
12050Sstevel@tonic-gate 		vudump("before undo");
12060Sstevel@tonic-gate #endif
12070Sstevel@tonic-gate 	if (inglobal && inopen <= 0)
12080Sstevel@tonic-gate 		error(value(vi_TERSE) ? gettext("Can't undo in global") :
12090Sstevel@tonic-gate 			gettext("Can't undo in global commands"));
12100Sstevel@tonic-gate 
12110Sstevel@tonic-gate 	/*
12120Sstevel@tonic-gate 	 * Unless flag indicates a forced undo, make sure
12130Sstevel@tonic-gate 	 * there really was a change before trying to undo it.
12140Sstevel@tonic-gate 	 */
12150Sstevel@tonic-gate 
12160Sstevel@tonic-gate 	if (!c)
12170Sstevel@tonic-gate 		somechange();
12180Sstevel@tonic-gate 
12190Sstevel@tonic-gate 	/*
12200Sstevel@tonic-gate 	 * Update change flags.
12210Sstevel@tonic-gate 	 */
12220Sstevel@tonic-gate 
12230Sstevel@tonic-gate 	pkill[0] = pkill[1] = 0;
12240Sstevel@tonic-gate 	change();
12250Sstevel@tonic-gate 	if (undkind == UNDMOVE) {
12260Sstevel@tonic-gate  		/*
12270Sstevel@tonic-gate 		 * Command to be undone is a move command.
12280Sstevel@tonic-gate 		 * This is handled as a special case by noting that
12290Sstevel@tonic-gate 		 * a move "a,b m c" can be inverted by another move.
12300Sstevel@tonic-gate 		 */
12310Sstevel@tonic-gate 		if ((i = (jp = unddel) - undap2) > 0) {
12320Sstevel@tonic-gate 			/*
12330Sstevel@tonic-gate 			 * when c > b inverse is a+(c-b),c m a-1
12340Sstevel@tonic-gate 			 */
12350Sstevel@tonic-gate 			addr2 = jp;
12360Sstevel@tonic-gate 			addr1 = (jp = undap1) + i;
12370Sstevel@tonic-gate 			unddel = jp-1;
12380Sstevel@tonic-gate 		} else {
12390Sstevel@tonic-gate 			/*
12400Sstevel@tonic-gate 			 * when b > c inverse is  c+1,c+1+(b-a) m b
12410Sstevel@tonic-gate 			 */
12420Sstevel@tonic-gate 			addr1 = ++jp;
12430Sstevel@tonic-gate 			addr2 = jp + ((unddel = undap2) - undap1);
12440Sstevel@tonic-gate 		}
12450Sstevel@tonic-gate 		kp = undap1;
12460Sstevel@tonic-gate 		move1(0, unddel);
12470Sstevel@tonic-gate 		dot = kp;
12480Sstevel@tonic-gate 		Command = (unsigned char *)"move";
12490Sstevel@tonic-gate 		killed();
12500Sstevel@tonic-gate 	} else {
12510Sstevel@tonic-gate 		int cnt;
12520Sstevel@tonic-gate 
12530Sstevel@tonic-gate 		newadot = dot;
12540Sstevel@tonic-gate 		cnt = lineDOL();
12550Sstevel@tonic-gate 		newdol = dol;
12560Sstevel@tonic-gate 		dolp1 = dol + 1;
12570Sstevel@tonic-gate 		/*
12580Sstevel@tonic-gate 		 * Command to be undone is a non-move.
12590Sstevel@tonic-gate 		 * All such commands are treated as a combination of
12600Sstevel@tonic-gate 		 * a delete command and a append command.
12610Sstevel@tonic-gate 		 * We first move the lines appended by the last command
12620Sstevel@tonic-gate 		 * from undap1 to undap2-1 so that they are just before the
12630Sstevel@tonic-gate 		 * saved deleted lines.
12640Sstevel@tonic-gate 		 *
12650Sstevel@tonic-gate 		 * Assume the editor has:
12660Sstevel@tonic-gate 		 *
12670Sstevel@tonic-gate 		 * 	cursor is on 'c'
12680Sstevel@tonic-gate 		 *
12690Sstevel@tonic-gate 		 *	(just change lines 5-8)
12700Sstevel@tonic-gate 		 *
12710Sstevel@tonic-gate 		 *	file is:	1) ab
12720Sstevel@tonic-gate 		 *			2) cd
12730Sstevel@tonic-gate 		 *			3) ef
12740Sstevel@tonic-gate 		 *			4) gh
12750Sstevel@tonic-gate 		 *	undap1:		5) 12
12760Sstevel@tonic-gate 		 *			6) 34
12770Sstevel@tonic-gate 		 *			7) 56
12780Sstevel@tonic-gate 		 *			8) 78
12790Sstevel@tonic-gate 		 *	undap2:		9) qr
12800Sstevel@tonic-gate 		 *		       10) st
12810Sstevel@tonic-gate 		 *		       11) uv
12820Sstevel@tonic-gate 		 *		       12) wx
12830Sstevel@tonic-gate 		 *	dol:	       13) yz
12840Sstevel@tonic-gate 		 *
12850Sstevel@tonic-gate 		 *	    UNDO AREA:
12860Sstevel@tonic-gate 		 *	dol+1:		5) ij
12870Sstevel@tonic-gate 		 *			6) kl
12880Sstevel@tonic-gate 		 *			7) mn
12890Sstevel@tonic-gate 		 *	unddol:		8) op
12900Sstevel@tonic-gate 		 */
12910Sstevel@tonic-gate 
12920Sstevel@tonic-gate 		/*
12930Sstevel@tonic-gate 		 * If this is a change (not a delete/put),
12940Sstevel@tonic-gate 		 * then we must move the text between undap1 and undap2
12950Sstevel@tonic-gate 		 * and it must not be at the bottom of the file
12960Sstevel@tonic-gate 		 */
12970Sstevel@tonic-gate 
12980Sstevel@tonic-gate 		if ((i = (kp = undap2) - (jp = undap1)) > 0) {
12990Sstevel@tonic-gate 			if (kp != dolp1) {
13000Sstevel@tonic-gate 
13010Sstevel@tonic-gate 		/*
13020Sstevel@tonic-gate 		 * FILE:     LINE    INITIAL   REV1   REV2   REV3
13030Sstevel@tonic-gate 		 *
13040Sstevel@tonic-gate 		 *	      1)       ab	ab     ab     ab
13050Sstevel@tonic-gate 		 *	      2)       cd       cd     cd     cd
13060Sstevel@tonic-gate 		 *            3)       ef       ef     ef     ef
13070Sstevel@tonic-gate 		 * unddel:    4)       gh       gh     gh     gh
13080Sstevel@tonic-gate 		 * undap1:    5)       12       78     78     qr
13090Sstevel@tonic-gate 		 *            6)       34       56     56     st
13100Sstevel@tonic-gate 		 *            7)       56       34     34     uv
13110Sstevel@tonic-gate 		 *            8)       78       12     12     wx
13120Sstevel@tonic-gate 		 * undap2:    9)       qr       qr     yz     yz
13130Sstevel@tonic-gate 		 *           10)       st       st     wx     12
13140Sstevel@tonic-gate 		 *           11)       uv       uv     uv     34
13150Sstevel@tonic-gate 		 *           12)       wx       wx     st     56
13160Sstevel@tonic-gate 		 * dol:      13)       yz       yz     qr     78
13170Sstevel@tonic-gate 		 *
13180Sstevel@tonic-gate 		 *	UNDO AREA:
13190Sstevel@tonic-gate 		 * dol+1:     5)       ij       ij     ij     ij
13200Sstevel@tonic-gate 		 *            6)       kl       kl     kl     kl
13210Sstevel@tonic-gate 		 *	      7)       mn       mn     mn     mn
13220Sstevel@tonic-gate 		 * unddol:    8)       op       op     op     op
13230Sstevel@tonic-gate 		 */
13240Sstevel@tonic-gate 
13250Sstevel@tonic-gate 				reverse(jp, kp);
13260Sstevel@tonic-gate 				reverse(kp, dolp1);
13270Sstevel@tonic-gate 				reverse(jp, dolp1);
13280Sstevel@tonic-gate 			}
13290Sstevel@tonic-gate 			/*
13300Sstevel@tonic-gate 			 * Unddel, the line just before the spot where this
13310Sstevel@tonic-gate 			 * test was deleted, may have moved. Account for
13320Sstevel@tonic-gate 			 * this in restoration of saved deleted lines.
13330Sstevel@tonic-gate 			 */
13340Sstevel@tonic-gate 			if (unddel >= jp)
13350Sstevel@tonic-gate 				unddel -= i;
13360Sstevel@tonic-gate 
13370Sstevel@tonic-gate 			/*
13380Sstevel@tonic-gate 			 * The last line (dol) may have changed,
13390Sstevel@tonic-gate 			 * account for this.
13400Sstevel@tonic-gate 			 */
13410Sstevel@tonic-gate 			 newdol -= i;
13420Sstevel@tonic-gate 
13430Sstevel@tonic-gate 			/*
13440Sstevel@tonic-gate 			 * For the case where no lines are restored, dot
13450Sstevel@tonic-gate 			 * is the line before the first line deleted.
13460Sstevel@tonic-gate 			 */
13470Sstevel@tonic-gate 			dot = jp-1;
13480Sstevel@tonic-gate 		}
13490Sstevel@tonic-gate 		/*
13500Sstevel@tonic-gate 		 * Now put the deleted lines, if any, back where they were.
13510Sstevel@tonic-gate 		 * Basic operation is: dol+1,unddol m unddel
13520Sstevel@tonic-gate 		 */
13530Sstevel@tonic-gate 		if (undkind == UNDPUT) {
13540Sstevel@tonic-gate 			unddel = undap1 - 1;
13550Sstevel@tonic-gate 			squish();
13560Sstevel@tonic-gate 		}
13570Sstevel@tonic-gate 
13580Sstevel@tonic-gate 		/*
13590Sstevel@tonic-gate 		 * Set jp to the line where deleted text is to be added.
13600Sstevel@tonic-gate 		 */
13610Sstevel@tonic-gate 		jp = unddel + 1;
13620Sstevel@tonic-gate 
13630Sstevel@tonic-gate 		/*
13640Sstevel@tonic-gate 		 * Set kp to end of undo save area.
13650Sstevel@tonic-gate 		 *
13660Sstevel@tonic-gate 		 * If there is any deleted text to be added, do reverses.
13670Sstevel@tonic-gate 		 */
13680Sstevel@tonic-gate 
13690Sstevel@tonic-gate 		if ((i = (kp = unddol) - dol) > 0) {
13700Sstevel@tonic-gate 
13710Sstevel@tonic-gate 			/*
13720Sstevel@tonic-gate 			 * If deleted lines are not to be appended
13730Sstevel@tonic-gate 			 * to the bottom of the file...
13740Sstevel@tonic-gate 			 */
13750Sstevel@tonic-gate 
13760Sstevel@tonic-gate 			 if (jp != dolp1) {
13770Sstevel@tonic-gate 				/*
13780Sstevel@tonic-gate 				 * FILE:   LINE   START   REV1   REV2   REV3
13790Sstevel@tonic-gate 				 *          1)     ab      ab     ab     ab
13800Sstevel@tonic-gate 				 *          2)     cd      cd     cd     cd
13810Sstevel@tonic-gate 				 *          3)     ef      ef     ef     ef
13820Sstevel@tonic-gate 				 * unddel:  4)     gh      gh     gh     gh
13830Sstevel@tonic-gate 				 * undap1:  5)     qr      78     78     ij
13840Sstevel@tonic-gate 				 *          6)     st      56     56     kl
13850Sstevel@tonic-gate 				 *          7)     uv      34     34     mn
13860Sstevel@tonic-gate 				 *          8)     wx      12     12     op
13870Sstevel@tonic-gate 				 * undap2:  9)     yz      yz     yz     qr
13880Sstevel@tonic-gate 				 *         10)     12      wx     wx     st
13890Sstevel@tonic-gate 				 *         11)     34      uv     uv     uv
13900Sstevel@tonic-gate 				 *         12)     56      st     st     wx
13910Sstevel@tonic-gate 				 * dol:    13)     78      qr     qr     yz
13920Sstevel@tonic-gate 				 *
13930Sstevel@tonic-gate 				 * UNDO AREA:
13940Sstevel@tonic-gate 				 * dol+1:  5)      ij      ij     op     12
13950Sstevel@tonic-gate 				 *         6)      kl      kl     mn     34
13960Sstevel@tonic-gate 				 *         7)      mn      mn     kl     56
13970Sstevel@tonic-gate 				 * unddol: 8)      op      op     ij     78
13980Sstevel@tonic-gate 				 */
13990Sstevel@tonic-gate 
14000Sstevel@tonic-gate 				 reverse(jp, dolp1);
14010Sstevel@tonic-gate 				reverse(dolp1, ++kp);
14020Sstevel@tonic-gate 				reverse(jp, kp);
14030Sstevel@tonic-gate 			}
14040Sstevel@tonic-gate 			/*
14050Sstevel@tonic-gate 			 * Account for possible forward motion of the target
14060Sstevel@tonic-gate 			 * (where the deleted lines were restored) for after
14070Sstevel@tonic-gate 			 * restoration of the deleted lines.
14080Sstevel@tonic-gate 			 */
14090Sstevel@tonic-gate 			if (undap1 >= jp)
14100Sstevel@tonic-gate 				undap1 += i;
14110Sstevel@tonic-gate 			/*
14120Sstevel@tonic-gate 			 * Dot is the first resurrected line.
14130Sstevel@tonic-gate 			 */
14140Sstevel@tonic-gate 			dot = jp;
14150Sstevel@tonic-gate 
14160Sstevel@tonic-gate 			/*
14170Sstevel@tonic-gate 			 * Account for a shift in the last line (dol).
14180Sstevel@tonic-gate 			 */
14190Sstevel@tonic-gate 
14200Sstevel@tonic-gate 			 newdol += i;
14210Sstevel@tonic-gate 		}
14220Sstevel@tonic-gate 		/*
14230Sstevel@tonic-gate 		 * Clean up so we are invertible
14240Sstevel@tonic-gate 		 */
14250Sstevel@tonic-gate 		unddel = undap1 - 1;
14260Sstevel@tonic-gate 		undap1 = jp;
14270Sstevel@tonic-gate 		undap2 = jp + i;
14280Sstevel@tonic-gate 		dol = newdol;
14290Sstevel@tonic-gate 		netchHAD(cnt);
14300Sstevel@tonic-gate 		if (undkind == UNDALL) {
14310Sstevel@tonic-gate 			dot = undadot;
14320Sstevel@tonic-gate 			undadot = newadot;
14330Sstevel@tonic-gate 		} else
14340Sstevel@tonic-gate 			undkind = UNDCHANGE;
14350Sstevel@tonic-gate  		/*
14360Sstevel@tonic-gate  		 * Now relocate all marks for lines that were modified,
14370Sstevel@tonic-gate  		 * since the marks point to lines whose address has
14380Sstevel@tonic-gate  		 * been modified from the save area to the current
14390Sstevel@tonic-gate  		 * area
14400Sstevel@tonic-gate  		 */
14410Sstevel@tonic-gate 
14420Sstevel@tonic-gate  		for (j=unddol; j> dol; j--)
14430Sstevel@tonic-gate  			for (k=0; k<=25; k++)
14440Sstevel@tonic-gate  				if (names[k] == *(j))
14450Sstevel@tonic-gate  					names[k]= *((undap1+(j-dolp1)) );
14460Sstevel@tonic-gate 	}
14470Sstevel@tonic-gate 	/*
14480Sstevel@tonic-gate 	 * Defensive programming - after a munged undadot.
14490Sstevel@tonic-gate 	 * Also handle empty buffer case.
14500Sstevel@tonic-gate 	 */
14510Sstevel@tonic-gate 	if ((dot <= zero || dot > dol) && dot != dol)
14520Sstevel@tonic-gate 		dot = one;
14530Sstevel@tonic-gate #ifdef UNDOTRACE
14540Sstevel@tonic-gate 	if (trace)
14550Sstevel@tonic-gate 		vudump("after undo");
14560Sstevel@tonic-gate #endif
14570Sstevel@tonic-gate }
14580Sstevel@tonic-gate 
14590Sstevel@tonic-gate /*
14600Sstevel@tonic-gate  * Be (almost completely) sure there really
14610Sstevel@tonic-gate  * was a change, before claiming to undo.
14620Sstevel@tonic-gate  */
1463802Scf46844 void
somechange(void)1464802Scf46844 somechange(void)
14650Sstevel@tonic-gate {
1466802Scf46844 	line *ip, *jp;
14670Sstevel@tonic-gate 
14680Sstevel@tonic-gate 	switch (undkind) {
14690Sstevel@tonic-gate 
14700Sstevel@tonic-gate 	case UNDMOVE:
14710Sstevel@tonic-gate 		return;
14720Sstevel@tonic-gate 
14730Sstevel@tonic-gate 	case UNDCHANGE:
14740Sstevel@tonic-gate 		if (undap1 == undap2 && dol == unddol)
14750Sstevel@tonic-gate 			break;
14760Sstevel@tonic-gate 		return;
14770Sstevel@tonic-gate 
14780Sstevel@tonic-gate 	case UNDPUT:
14790Sstevel@tonic-gate 		if (undap1 != undap2)
14800Sstevel@tonic-gate 			return;
14810Sstevel@tonic-gate 		break;
14820Sstevel@tonic-gate 
14830Sstevel@tonic-gate 	case UNDALL:
14840Sstevel@tonic-gate 		if (unddol - dol != lineDOL())
14850Sstevel@tonic-gate 			return;
14860Sstevel@tonic-gate 		for (ip = one, jp = dol + 1; ip <= dol; ip++, jp++)
14870Sstevel@tonic-gate 			if ((*ip &~ 01) != (*jp &~ 01))
14880Sstevel@tonic-gate 				return;
14890Sstevel@tonic-gate 		break;
14900Sstevel@tonic-gate 
14910Sstevel@tonic-gate 	case UNDNONE:
14920Sstevel@tonic-gate 		error(gettext("Nothing to undo"));
14930Sstevel@tonic-gate 	}
14940Sstevel@tonic-gate 	error(value(vi_TERSE) ? gettext("Nothing changed") :
14950Sstevel@tonic-gate 		gettext("Last undoable command didn't change anything"));
14960Sstevel@tonic-gate }
14970Sstevel@tonic-gate 
14980Sstevel@tonic-gate /*
14990Sstevel@tonic-gate  * Map command:
15000Sstevel@tonic-gate  * map src dest
1501802Scf46844  *
1502802Scf46844  * un is true if this is unmap command
1503802Scf46844  * ab is true if this is abbr command
15040Sstevel@tonic-gate  */
1505802Scf46844 void
mapcmd(int un,int ab)1506802Scf46844 mapcmd(int un, int ab)
15070Sstevel@tonic-gate {
15080Sstevel@tonic-gate 	unsigned char lhs[100], rhs[100];	/* max sizes resp. */
1509802Scf46844 	unsigned char *p;
1510802Scf46844 	int c;		/* char --> int */
15110Sstevel@tonic-gate 	unsigned char *dname;
15120Sstevel@tonic-gate 	struct maps *mp;	/* the map structure we are working on */
15130Sstevel@tonic-gate 
15140Sstevel@tonic-gate 	mp = ab ? abbrevs : exclam() ? immacs : arrows;
15150Sstevel@tonic-gate 	if (skipend()) {
15160Sstevel@tonic-gate 		int i;
15170Sstevel@tonic-gate 
15180Sstevel@tonic-gate 		/* print current mapping values */
15190Sstevel@tonic-gate 		if (peekchar() != EOF)
15200Sstevel@tonic-gate 			ignchar();
15210Sstevel@tonic-gate 		if (un)
15220Sstevel@tonic-gate 			error(gettext("Missing lhs"));
15230Sstevel@tonic-gate 		if (inopen)
15240Sstevel@tonic-gate 			pofix();
15250Sstevel@tonic-gate 		for (i=0; i< MAXNOMACS && mp[i].mapto; i++)
15260Sstevel@tonic-gate 			if (mp[i].cap) {
15270Sstevel@tonic-gate 				lprintf("%s", mp[i].descr);
15280Sstevel@tonic-gate 				putchar('\t');
15290Sstevel@tonic-gate 				lprintf("%s", mp[i].cap);
15300Sstevel@tonic-gate 				putchar('\t');
15310Sstevel@tonic-gate 				lprintf("%s", mp[i].mapto);
15320Sstevel@tonic-gate 				putNFL();
15330Sstevel@tonic-gate 			}
15340Sstevel@tonic-gate 		return;
15350Sstevel@tonic-gate 	}
15360Sstevel@tonic-gate 
15370Sstevel@tonic-gate 	(void)skipwh();
15380Sstevel@tonic-gate 	for (p=lhs; ; ) {
15390Sstevel@tonic-gate 		c = getchar();
15400Sstevel@tonic-gate 		if (c == CTRL('v')) {
15410Sstevel@tonic-gate 			c = getchar();
15420Sstevel@tonic-gate 		} else if (!un && any(c, " \t")) {
15430Sstevel@tonic-gate 			/* End of lhs */
15440Sstevel@tonic-gate 			break;
15450Sstevel@tonic-gate 		} else if (endcmd(c) && c!='"') {
15460Sstevel@tonic-gate 			ungetchar(c);
15470Sstevel@tonic-gate 			if (un) {
15480Sstevel@tonic-gate 				donewline();
15490Sstevel@tonic-gate 				*p = 0;
1550802Scf46844 				addmac(lhs, (unsigned char *)NOSTR,
1551802Scf46844 				    (unsigned char *)NOSTR, mp);
15520Sstevel@tonic-gate 				return;
15530Sstevel@tonic-gate 			} else
15540Sstevel@tonic-gate 				error(gettext("Missing rhs"));
15550Sstevel@tonic-gate 		}
15560Sstevel@tonic-gate 		*p++ = c;
15570Sstevel@tonic-gate 	}
15580Sstevel@tonic-gate 	*p = 0;
15590Sstevel@tonic-gate 
15600Sstevel@tonic-gate 	if (skipend())
15610Sstevel@tonic-gate 		error(gettext("Missing rhs"));
15620Sstevel@tonic-gate 	for (p=rhs; ; ) {
15630Sstevel@tonic-gate 		c = getchar();
15640Sstevel@tonic-gate 		if (c == CTRL('v')) {
15650Sstevel@tonic-gate 			c = getchar();
15660Sstevel@tonic-gate 		} else if (endcmd(c) && c!='"') {
15670Sstevel@tonic-gate 			ungetchar(c);
15680Sstevel@tonic-gate 			break;
15690Sstevel@tonic-gate 		}
15700Sstevel@tonic-gate 		*p++ = c;
15710Sstevel@tonic-gate 	}
15720Sstevel@tonic-gate 	*p = 0;
15730Sstevel@tonic-gate 	donewline();
15740Sstevel@tonic-gate 	/*
15750Sstevel@tonic-gate 	 * Special hack for function keys: #1 means key f1, etc.
15760Sstevel@tonic-gate 	 * If the terminal doesn't have function keys, we just use #1.
15770Sstevel@tonic-gate 	 */
15780Sstevel@tonic-gate 	if (lhs[0] == '#') {
15790Sstevel@tonic-gate 		unsigned char *fnkey;
15800Sstevel@tonic-gate 		unsigned char *fkey();
15810Sstevel@tonic-gate 		unsigned char funkey[3];
15820Sstevel@tonic-gate 
15830Sstevel@tonic-gate 		fnkey = fkey(lhs[1] - '0');
15840Sstevel@tonic-gate 		funkey[0] = 'f'; funkey[1] = lhs[1]; funkey[2] = 0;
15850Sstevel@tonic-gate 		if (fnkey)
15860Sstevel@tonic-gate 			strcpy(lhs, fnkey);
15870Sstevel@tonic-gate 		dname = funkey;
15880Sstevel@tonic-gate 	} else {
15890Sstevel@tonic-gate 		dname = lhs;
15900Sstevel@tonic-gate 	}
15910Sstevel@tonic-gate 	addmac(lhs,rhs,dname,mp);
15920Sstevel@tonic-gate }
15930Sstevel@tonic-gate 
15940Sstevel@tonic-gate /*
15950Sstevel@tonic-gate  * Add a macro definition to those that already exist. The sequence of
15960Sstevel@tonic-gate  * chars "src" is mapped into "dest". If src is already mapped into something
15970Sstevel@tonic-gate  * this overrides the mapping. There is no recursion. Unmap is done by
15980Sstevel@tonic-gate  * using NOSTR for dest.  Dname is what to show in listings.  mp is
15990Sstevel@tonic-gate  * the structure to affect (arrows, etc).
16000Sstevel@tonic-gate  */
1601802Scf46844 void
addmac(unsigned char * src,unsigned char * dest,unsigned char * dname,struct maps * mp)1602802Scf46844 addmac(unsigned char *src, unsigned char *dest, unsigned char *dname,
1603802Scf46844     struct maps *mp)
16040Sstevel@tonic-gate {
1605802Scf46844 	int slot, zer;
16060Sstevel@tonic-gate 
16070Sstevel@tonic-gate #ifdef UNDOTRACE
16080Sstevel@tonic-gate 	if (trace)
16090Sstevel@tonic-gate 		fprintf(trace, "addmac(src='%s', dest='%s', dname='%s', mp=%x\n", src, dest, dname, mp);
16100Sstevel@tonic-gate #endif
16110Sstevel@tonic-gate 	if (dest && mp==arrows) {
16120Sstevel@tonic-gate 		/*
16130Sstevel@tonic-gate 		 * Prevent tail recursion. We really should be
16140Sstevel@tonic-gate 		 * checking to see if src is a suffix of dest
16150Sstevel@tonic-gate 		 * but this makes mapping involving escapes that
16160Sstevel@tonic-gate 		 * is reasonable mess up.
16170Sstevel@tonic-gate 		 */
16180Sstevel@tonic-gate 		if (src[1] == 0 && src[0] == dest[strlen(dest)-1])
16190Sstevel@tonic-gate 			error(gettext("No tail recursion"));
16200Sstevel@tonic-gate 		/*
16210Sstevel@tonic-gate 		 * We don't let the user rob himself of ":", and making
16220Sstevel@tonic-gate 		 * multi char words is a bad idea so we don't allow it.
16230Sstevel@tonic-gate 		 * Note that if user sets mapinput and maps all of return,
16240Sstevel@tonic-gate 		 * linefeed, and escape, he can hurt himself. This is
16250Sstevel@tonic-gate 		 * so weird I don't bother to check for it.
16260Sstevel@tonic-gate 		 */
16270Sstevel@tonic-gate 		if (isalpha(src[0])  && isascii(src[0]) && src[1] || any(src[0],":"))
16280Sstevel@tonic-gate 			error(gettext("Too dangerous to map that"));
16290Sstevel@tonic-gate 	}
16300Sstevel@tonic-gate 	else if (dest) {
16310Sstevel@tonic-gate 		/* check for tail recursion in input mode: fussier */
16320Sstevel@tonic-gate 		if (eq(src, dest+strlen(dest)-strlen(src)))
16330Sstevel@tonic-gate 			error(gettext("No tail recursion"));
16340Sstevel@tonic-gate 	}
16350Sstevel@tonic-gate 	/*
16360Sstevel@tonic-gate 	 * If the src were null it would cause the dest to
16370Sstevel@tonic-gate 	 * be mapped always forever. This is not good.
16380Sstevel@tonic-gate 	 */
16390Sstevel@tonic-gate 	if (src == (unsigned char *)NOSTR || src[0] == 0)
16400Sstevel@tonic-gate 		error(gettext("Missing lhs"));
16410Sstevel@tonic-gate 
16420Sstevel@tonic-gate 	/* see if we already have a def for src */
16430Sstevel@tonic-gate 	zer = -1;
16440Sstevel@tonic-gate 	for (slot=0; slot < MAXNOMACS && mp[slot].mapto; slot++) {
16450Sstevel@tonic-gate 		if (mp[slot].cap) {
16460Sstevel@tonic-gate 			if (eq(src, mp[slot].cap) || eq(src, mp[slot].mapto))
16470Sstevel@tonic-gate 				break;	/* if so, reuse slot */
16480Sstevel@tonic-gate 		} else {
16490Sstevel@tonic-gate 			zer = slot;	/* remember an empty slot */
16500Sstevel@tonic-gate 		}
16510Sstevel@tonic-gate 	}
16520Sstevel@tonic-gate 
16530Sstevel@tonic-gate 	if (slot >= MAXNOMACS)
16540Sstevel@tonic-gate 		error(gettext("Too many macros"));
16550Sstevel@tonic-gate 
16560Sstevel@tonic-gate 	if (dest == (unsigned char *)NOSTR) {
16570Sstevel@tonic-gate 		/* unmap */
16580Sstevel@tonic-gate 		if (mp[slot].cap) {
16590Sstevel@tonic-gate 			mp[slot].cap = (unsigned char *)NOSTR;
16600Sstevel@tonic-gate 			mp[slot].descr = (unsigned char *)NOSTR;
16610Sstevel@tonic-gate 		} else {
16620Sstevel@tonic-gate 			error(value(vi_TERSE) ? gettext("Not mapped") :
16630Sstevel@tonic-gate 				gettext("That macro wasn't mapped"));
16640Sstevel@tonic-gate 		}
16650Sstevel@tonic-gate 		return;
16660Sstevel@tonic-gate 	}
16670Sstevel@tonic-gate 
16680Sstevel@tonic-gate 	/* reuse empty slot, if we found one and src isn't already defined */
16690Sstevel@tonic-gate 	if (zer >= 0 && mp[slot].mapto == 0)
16700Sstevel@tonic-gate 		slot = zer;
16710Sstevel@tonic-gate 
16720Sstevel@tonic-gate 	/* if not, append to end */
16730Sstevel@tonic-gate 	if (msnext == 0)	/* first time */
16740Sstevel@tonic-gate 		msnext = mapspace;
16750Sstevel@tonic-gate 	/* Check is a bit conservative, we charge for dname even if reusing src */
16760Sstevel@tonic-gate 	if (msnext - mapspace + strlen(dest) + strlen(src) + strlen(dname) + 3 > MAXCHARMACS)
16770Sstevel@tonic-gate 		error(gettext("Too much macro text"));
16780Sstevel@tonic-gate 	CP(msnext, src);
16790Sstevel@tonic-gate 	mp[slot].cap = msnext;
16800Sstevel@tonic-gate 	msnext += strlen(src) + 1;	/* plus 1 for null on the end */
16810Sstevel@tonic-gate 	CP(msnext, dest);
16820Sstevel@tonic-gate 	mp[slot].mapto = msnext;
16830Sstevel@tonic-gate 	msnext += strlen(dest) + 1;
16840Sstevel@tonic-gate 	if (dname) {
16850Sstevel@tonic-gate 		CP(msnext, dname);
16860Sstevel@tonic-gate 		mp[slot].descr = msnext;
16870Sstevel@tonic-gate 		msnext += strlen(dname) + 1;
16880Sstevel@tonic-gate 	} else {
16890Sstevel@tonic-gate 		/* default descr to string user enters */
16900Sstevel@tonic-gate 		mp[slot].descr = src;
16910Sstevel@tonic-gate 	}
16920Sstevel@tonic-gate }
16930Sstevel@tonic-gate 
16940Sstevel@tonic-gate /*
16950Sstevel@tonic-gate  * Implements macros from command mode. c is the buffer to
16960Sstevel@tonic-gate  * get the macro from.
16970Sstevel@tonic-gate  */
1698802Scf46844 void
cmdmac(c)16990Sstevel@tonic-gate cmdmac(c)
17000Sstevel@tonic-gate unsigned char c;
17010Sstevel@tonic-gate {
17020Sstevel@tonic-gate 	unsigned char macbuf[BUFSIZE];
17030Sstevel@tonic-gate 	line *ad, *a1, *a2;
17040Sstevel@tonic-gate 	unsigned char *oglobp;
17050Sstevel@tonic-gate 	short pk;
17060Sstevel@tonic-gate 	bool oinglobal;
17070Sstevel@tonic-gate 
17080Sstevel@tonic-gate 	lastmac = c;
17090Sstevel@tonic-gate 	oglobp = globp;
17100Sstevel@tonic-gate 	oinglobal = inglobal;
17110Sstevel@tonic-gate 	pk = peekc; peekc = 0;
17120Sstevel@tonic-gate 	if (inglobal < 2)
17130Sstevel@tonic-gate 		inglobal = 1;
17140Sstevel@tonic-gate 	regbuf(c, macbuf, sizeof(macbuf));
17150Sstevel@tonic-gate 	a1 = addr1; a2 = addr2;
17160Sstevel@tonic-gate 	for (ad=a1; ad<=a2; ad++) {
17170Sstevel@tonic-gate 		globp = macbuf;
17180Sstevel@tonic-gate 		dot = ad;
17190Sstevel@tonic-gate 		commands(1,1);
17200Sstevel@tonic-gate 	}
17210Sstevel@tonic-gate 	globp = oglobp;
17220Sstevel@tonic-gate 	inglobal = oinglobal;
17230Sstevel@tonic-gate 	peekc = pk;
17240Sstevel@tonic-gate }
17250Sstevel@tonic-gate 
17260Sstevel@tonic-gate unsigned char *
vgetpass(prompt)17270Sstevel@tonic-gate vgetpass(prompt)
17280Sstevel@tonic-gate unsigned char *prompt;
17290Sstevel@tonic-gate {
1730802Scf46844 	unsigned char *p;
1731802Scf46844 	int c;
17320Sstevel@tonic-gate 	static unsigned char pbuf[9];
17330Sstevel@tonic-gate 	char *getpass();
17340Sstevel@tonic-gate 
17350Sstevel@tonic-gate 	/* In ex mode, let the system hassle with setting no echo */
17360Sstevel@tonic-gate 	if (!inopen)
17370Sstevel@tonic-gate 		return (unsigned char *)getpass(prompt);
1738802Scf46844 	viprintf("%s", prompt); flush();
17390Sstevel@tonic-gate 	for (p=pbuf; (c = getkey())!='\n' && c!=EOF && c!='\r';) {
17400Sstevel@tonic-gate 		if (p < &pbuf[8])
17410Sstevel@tonic-gate 			*p++ = c;
17420Sstevel@tonic-gate 	}
17430Sstevel@tonic-gate 	*p = '\0';
17440Sstevel@tonic-gate 	return(pbuf);
17450Sstevel@tonic-gate }
17460Sstevel@tonic-gate 
17470Sstevel@tonic-gate 
17480Sstevel@tonic-gate #ifdef TAG_STACK
17490Sstevel@tonic-gate #define TSTACKSIZE 20
17500Sstevel@tonic-gate struct tagstack {
17510Sstevel@tonic-gate 	line *tag_line;
17520Sstevel@tonic-gate 	char *tag_file;
17530Sstevel@tonic-gate } tagstack[TSTACKSIZE];
17540Sstevel@tonic-gate static int tag_depth = 0;
17550Sstevel@tonic-gate 
17560Sstevel@tonic-gate static char tag_buf[ 1024 ];
17570Sstevel@tonic-gate static char *tag_end = tag_buf;
17580Sstevel@tonic-gate 
1759802Scf46844 void
savetag(char * name)1760802Scf46844 savetag(char *name)	/* saves location where we are */
17610Sstevel@tonic-gate {
17620Sstevel@tonic-gate 	if( !value(vi_TAGSTACK) )
17630Sstevel@tonic-gate 		return;
17640Sstevel@tonic-gate 	if(tag_depth >= TSTACKSIZE) {
17650Sstevel@tonic-gate 		error(gettext("Tagstack too deep."));
17660Sstevel@tonic-gate 	}
17670Sstevel@tonic-gate 	if( strlen( name ) + 1 + tag_end >= &tag_buf[1024]) {
17680Sstevel@tonic-gate 		error(gettext("Too many tags."));
17690Sstevel@tonic-gate 	}
17700Sstevel@tonic-gate 	tagstack[tag_depth].tag_line = dot;
17710Sstevel@tonic-gate 	tagstack[tag_depth++].tag_file = tag_end;
17720Sstevel@tonic-gate 	while(*tag_end++ = *name++)
17730Sstevel@tonic-gate 		;
17740Sstevel@tonic-gate }
17750Sstevel@tonic-gate 
17760Sstevel@tonic-gate /*
17770Sstevel@tonic-gate  * Undo a "savetag".
17780Sstevel@tonic-gate  */
1779802Scf46844 void
unsavetag(void)1780802Scf46844 unsavetag(void)
17810Sstevel@tonic-gate {
17820Sstevel@tonic-gate 	if (!value(vi_TAGSTACK))
17830Sstevel@tonic-gate 		return;
17840Sstevel@tonic-gate 	if (tag_depth > 0)
17850Sstevel@tonic-gate 		tag_end = tagstack[--tag_depth].tag_file;
17860Sstevel@tonic-gate }
17870Sstevel@tonic-gate 
1788802Scf46844 void
poptag(quick)17890Sstevel@tonic-gate poptag(quick)	/* puts us back where we came from */
17900Sstevel@tonic-gate bool quick;
17910Sstevel@tonic-gate {
17920Sstevel@tonic-gate 	unsigned char cmdbuf[100];
17930Sstevel@tonic-gate 	unsigned char *oglobp;
17940Sstevel@tonic-gate 	int d;
17950Sstevel@tonic-gate 
17960Sstevel@tonic-gate 	if (!value(vi_TAGSTACK)) {	/* reset the stack */
17970Sstevel@tonic-gate 		tag_end = tag_buf;
17980Sstevel@tonic-gate 		d = tag_depth;
17990Sstevel@tonic-gate 		tag_depth = 0;
18000Sstevel@tonic-gate 		if (d == 0)
18010Sstevel@tonic-gate 			error(gettext("Tagstack not enabled."));
18020Sstevel@tonic-gate 		else
18030Sstevel@tonic-gate 			return;
18040Sstevel@tonic-gate 	}
18050Sstevel@tonic-gate 	if (!tag_depth)
18060Sstevel@tonic-gate 		error(gettext("Tagstack empty."));
18070Sstevel@tonic-gate 
18080Sstevel@tonic-gate 	/* change to old file */
18090Sstevel@tonic-gate 	if (strcmp(tagstack[tag_depth-1].tag_file, savedfile) ) {
18100Sstevel@tonic-gate 		if (!quick) {
18110Sstevel@tonic-gate 			ckaw();
18120Sstevel@tonic-gate 			if (chng && dol > zero)
18130Sstevel@tonic-gate 				error(value(vi_TERSE) ?
18140Sstevel@tonic-gate gettext("No write") : gettext("No write since last change (:pop! overrides)"));
18150Sstevel@tonic-gate 		}
18160Sstevel@tonic-gate 		oglobp = globp;
18170Sstevel@tonic-gate 		strcpy(cmdbuf, "e! ");
18180Sstevel@tonic-gate 		strcat(cmdbuf, tagstack[tag_depth-1].tag_file);
18190Sstevel@tonic-gate 		globp = cmdbuf;
18200Sstevel@tonic-gate 		d = peekc; ungetchar(0);
18210Sstevel@tonic-gate 		commands(1, 1);
18220Sstevel@tonic-gate 		peekc = d;
18230Sstevel@tonic-gate 		globp = oglobp;
18240Sstevel@tonic-gate 	}
18250Sstevel@tonic-gate 		markpr(dot);
18260Sstevel@tonic-gate 	/* set line number */
18270Sstevel@tonic-gate 	dot = tagstack[--tag_depth].tag_line;
18280Sstevel@tonic-gate 	tag_end = tagstack[tag_depth].tag_file;
18290Sstevel@tonic-gate }
18300Sstevel@tonic-gate #endif
1831