xref: /titanic_51/usr/src/cmd/vi/port/ex_cmdsub.c (revision 6a3e8e8695d5c7d1d18c6800d676990d7f61a2a4)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
523a1cceaSRoger A. Faulkner  * Common Development and Distribution License (the "License").
623a1cceaSRoger A. Faulkner  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
2123a1cceaSRoger A. Faulkner 
22f6db9f27Scf46844 /*
2323a1cceaSRoger A. Faulkner  * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
24f6db9f27Scf46844  */
25f6db9f27Scf46844 
267c478bd9Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
277c478bd9Sstevel@tonic-gate /*	  All Rights Reserved  	*/
287c478bd9Sstevel@tonic-gate 
297c478bd9Sstevel@tonic-gate 
307c478bd9Sstevel@tonic-gate /* Copyright (c) 1981 Regents of the University of California */
317c478bd9Sstevel@tonic-gate 
327c478bd9Sstevel@tonic-gate #include "ex.h"
337c478bd9Sstevel@tonic-gate #include "ex_argv.h"
347c478bd9Sstevel@tonic-gate #include "ex_temp.h"
357c478bd9Sstevel@tonic-gate #include "ex_tty.h"
367c478bd9Sstevel@tonic-gate #include "ex_vis.h"
377c478bd9Sstevel@tonic-gate #ifdef	STDIO
387c478bd9Sstevel@tonic-gate #include	<stdio.h>
397c478bd9Sstevel@tonic-gate #undef getchar
407c478bd9Sstevel@tonic-gate #undef putchar
417c478bd9Sstevel@tonic-gate #endif
42*6a3e8e86SRichard Lowe 
43*6a3e8e86SRichard Lowe 
447c478bd9Sstevel@tonic-gate /*
457c478bd9Sstevel@tonic-gate  * Command mode subroutines implementing
467c478bd9Sstevel@tonic-gate  *	append, args, copy, delete, join, move, put,
477c478bd9Sstevel@tonic-gate  *	shift, tag, yank, z and undo
487c478bd9Sstevel@tonic-gate  */
497c478bd9Sstevel@tonic-gate 
507c478bd9Sstevel@tonic-gate bool	endline = 1;
517c478bd9Sstevel@tonic-gate line	*tad1;
52f6db9f27Scf46844 static int jnoop(void);
53f6db9f27Scf46844 static void splitit(void);
547c478bd9Sstevel@tonic-gate int putchar(), getchar();
557c478bd9Sstevel@tonic-gate int tags_flag;
567c478bd9Sstevel@tonic-gate 
577c478bd9Sstevel@tonic-gate /*
587c478bd9Sstevel@tonic-gate  * Append after line a lines returned by function f.
597c478bd9Sstevel@tonic-gate  * Be careful about intermediate states to avoid scramble
607c478bd9Sstevel@tonic-gate  * if an interrupt comes in.
617c478bd9Sstevel@tonic-gate  */
62f6db9f27Scf46844 int
63f6db9f27Scf46844 append(int (*f)(), line *a)
647c478bd9Sstevel@tonic-gate {
65f6db9f27Scf46844 	line *a1, *a2, *rdot;
667c478bd9Sstevel@tonic-gate 	int nline;
677c478bd9Sstevel@tonic-gate 
687c478bd9Sstevel@tonic-gate 	nline = 0;
697c478bd9Sstevel@tonic-gate 	dot = a;
707c478bd9Sstevel@tonic-gate 	if(FIXUNDO && !inopen && f!=getsub) {
717c478bd9Sstevel@tonic-gate 		undap1 = undap2 = dot + 1;
727c478bd9Sstevel@tonic-gate 		undkind = UNDCHANGE;
737c478bd9Sstevel@tonic-gate 	}
747c478bd9Sstevel@tonic-gate 	while ((*f)() == 0) {
757c478bd9Sstevel@tonic-gate 		if (truedol >= endcore) {
767c478bd9Sstevel@tonic-gate 			if (morelines() < 0) {
777c478bd9Sstevel@tonic-gate 				if (FIXUNDO && f == getsub) {
787c478bd9Sstevel@tonic-gate 					undap1 = addr1;
797c478bd9Sstevel@tonic-gate 					undap2 = addr2 + 1;
807c478bd9Sstevel@tonic-gate 				}
817c478bd9Sstevel@tonic-gate 				error(value(vi_TERSE) ? gettext("Out of memory") :
827c478bd9Sstevel@tonic-gate gettext("Out of memory- too many lines in file"));
837c478bd9Sstevel@tonic-gate 			}
847c478bd9Sstevel@tonic-gate 		}
857c478bd9Sstevel@tonic-gate 		nline++;
867c478bd9Sstevel@tonic-gate 		a1 = truedol + 1;
877c478bd9Sstevel@tonic-gate 		a2 = a1 + 1;
887c478bd9Sstevel@tonic-gate 		dot++;
897c478bd9Sstevel@tonic-gate 		undap2++;
907c478bd9Sstevel@tonic-gate 		dol++;
917c478bd9Sstevel@tonic-gate 		unddol++;
927c478bd9Sstevel@tonic-gate 		truedol++;
937c478bd9Sstevel@tonic-gate 		for (rdot = dot; a1 > rdot;)
947c478bd9Sstevel@tonic-gate 			*--a2 = *--a1;
957c478bd9Sstevel@tonic-gate 		*rdot = 0;
967c478bd9Sstevel@tonic-gate 		putmark(rdot);
977c478bd9Sstevel@tonic-gate 		if (f == gettty) {
987c478bd9Sstevel@tonic-gate 			dirtcnt++;
997c478bd9Sstevel@tonic-gate 			TSYNC();
1007c478bd9Sstevel@tonic-gate 		}
1017c478bd9Sstevel@tonic-gate 	}
1027c478bd9Sstevel@tonic-gate 	return (nline);
1037c478bd9Sstevel@tonic-gate }
1047c478bd9Sstevel@tonic-gate 
105f6db9f27Scf46844 void
106f6db9f27Scf46844 appendnone(void)
1077c478bd9Sstevel@tonic-gate {
1087c478bd9Sstevel@tonic-gate 
1097c478bd9Sstevel@tonic-gate 	if(FIXUNDO) {
1107c478bd9Sstevel@tonic-gate 		undkind = UNDCHANGE;
1117c478bd9Sstevel@tonic-gate 		undap1 = undap2 = addr1;
1127c478bd9Sstevel@tonic-gate 	}
1137c478bd9Sstevel@tonic-gate }
1147c478bd9Sstevel@tonic-gate 
1157c478bd9Sstevel@tonic-gate /*
1167c478bd9Sstevel@tonic-gate  * Print out the argument list, with []'s around the current name.
1177c478bd9Sstevel@tonic-gate  */
118f6db9f27Scf46844 void
119f6db9f27Scf46844 pargs(void)
1207c478bd9Sstevel@tonic-gate {
121f6db9f27Scf46844 	unsigned char **av = argv0, *as = args0;
122f6db9f27Scf46844 	int ac;
1237c478bd9Sstevel@tonic-gate 
1247c478bd9Sstevel@tonic-gate 	for (ac = 0; ac < argc0; ac++) {
1257c478bd9Sstevel@tonic-gate 		if (ac != 0)
1267c478bd9Sstevel@tonic-gate 			putchar(' ');
1277c478bd9Sstevel@tonic-gate 		if (ac + argc == argc0 - 1)
128f6db9f27Scf46844 			viprintf("[");
1297c478bd9Sstevel@tonic-gate 		lprintf("%s", as);
1307c478bd9Sstevel@tonic-gate 		if (ac + argc == argc0 - 1)
131f6db9f27Scf46844 			viprintf("]");
1327c478bd9Sstevel@tonic-gate 		as = av ? *++av : strend(as) + 1;
1337c478bd9Sstevel@tonic-gate 	}
1347c478bd9Sstevel@tonic-gate 	noonl();
1357c478bd9Sstevel@tonic-gate }
1367c478bd9Sstevel@tonic-gate 
1377c478bd9Sstevel@tonic-gate /*
1387c478bd9Sstevel@tonic-gate  * Delete lines; two cases are if we are really deleting,
1397c478bd9Sstevel@tonic-gate  * more commonly we are just moving lines to the undo save area.
1407c478bd9Sstevel@tonic-gate  */
141f6db9f27Scf46844 int
142f6db9f27Scf46844 delete(bool hush)
1437c478bd9Sstevel@tonic-gate {
144f6db9f27Scf46844 	line *a1, *a2;
1457c478bd9Sstevel@tonic-gate 
1467c478bd9Sstevel@tonic-gate 	nonzero();
1477c478bd9Sstevel@tonic-gate 	if(FIXUNDO) {
1487c478bd9Sstevel@tonic-gate 		void (*dsavint)();
1497c478bd9Sstevel@tonic-gate 
1507c478bd9Sstevel@tonic-gate #ifdef UNDOTRACE
1517c478bd9Sstevel@tonic-gate 		if (trace)
1527c478bd9Sstevel@tonic-gate 			vudump("before delete");
1537c478bd9Sstevel@tonic-gate #endif
1547c478bd9Sstevel@tonic-gate 		change();
1557c478bd9Sstevel@tonic-gate 		dsavint = signal(SIGINT, SIG_IGN);
1567c478bd9Sstevel@tonic-gate 		undkind = UNDCHANGE;
1577c478bd9Sstevel@tonic-gate 		a1 = addr1;
1587c478bd9Sstevel@tonic-gate 		squish();
1597c478bd9Sstevel@tonic-gate 		a2 = addr2;
1607c478bd9Sstevel@tonic-gate 		if (a2++ != dol) {
1617c478bd9Sstevel@tonic-gate 			reverse(a1, a2);
1627c478bd9Sstevel@tonic-gate 			reverse(a2, dol + 1);
1637c478bd9Sstevel@tonic-gate 			reverse(a1, dol + 1);
1647c478bd9Sstevel@tonic-gate 		}
1657c478bd9Sstevel@tonic-gate 		dol -= a2 - a1;
1667c478bd9Sstevel@tonic-gate 		unddel = a1 - 1;
1677c478bd9Sstevel@tonic-gate 		if (a1 > dol)
1687c478bd9Sstevel@tonic-gate 			a1 = dol;
1697c478bd9Sstevel@tonic-gate 		dot = a1;
1707c478bd9Sstevel@tonic-gate 		pkill[0] = pkill[1] = 0;
1717c478bd9Sstevel@tonic-gate 		signal(SIGINT, dsavint);
1727c478bd9Sstevel@tonic-gate #ifdef UNDOTRACE
1737c478bd9Sstevel@tonic-gate 		if (trace)
1747c478bd9Sstevel@tonic-gate 			vudump("after delete");
1757c478bd9Sstevel@tonic-gate #endif
1767c478bd9Sstevel@tonic-gate 	} else {
177f6db9f27Scf46844 		line *a3;
178f6db9f27Scf46844 		int i;
1797c478bd9Sstevel@tonic-gate 
1807c478bd9Sstevel@tonic-gate 		change();
1817c478bd9Sstevel@tonic-gate 		a1 = addr1;
1827c478bd9Sstevel@tonic-gate 		a2 = addr2 + 1;
1837c478bd9Sstevel@tonic-gate 		a3 = truedol;
1847c478bd9Sstevel@tonic-gate 		i = a2 - a1;
1857c478bd9Sstevel@tonic-gate 		unddol -= i;
1867c478bd9Sstevel@tonic-gate 		undap2 -= i;
1877c478bd9Sstevel@tonic-gate 		dol -= i;
1887c478bd9Sstevel@tonic-gate 		truedol -= i;
1897c478bd9Sstevel@tonic-gate 		do
1907c478bd9Sstevel@tonic-gate 			*a1++ = *a2++;
1917c478bd9Sstevel@tonic-gate 		while (a2 <= a3);
1927c478bd9Sstevel@tonic-gate 		a1 = addr1;
1937c478bd9Sstevel@tonic-gate 		if (a1 > dol)
1947c478bd9Sstevel@tonic-gate 			a1 = dol;
1957c478bd9Sstevel@tonic-gate 		dot = a1;
1967c478bd9Sstevel@tonic-gate 	}
1977c478bd9Sstevel@tonic-gate 	if (!hush)
1987c478bd9Sstevel@tonic-gate 		killed();
199f6db9f27Scf46844 	return (0);
2007c478bd9Sstevel@tonic-gate }
2017c478bd9Sstevel@tonic-gate 
202f6db9f27Scf46844 void
203f6db9f27Scf46844 deletenone(void)
2047c478bd9Sstevel@tonic-gate {
2057c478bd9Sstevel@tonic-gate 
2067c478bd9Sstevel@tonic-gate 	if(FIXUNDO) {
2077c478bd9Sstevel@tonic-gate 		undkind = UNDCHANGE;
2087c478bd9Sstevel@tonic-gate 		squish();
2097c478bd9Sstevel@tonic-gate 		unddel = addr1;
2107c478bd9Sstevel@tonic-gate 	}
2117c478bd9Sstevel@tonic-gate }
2127c478bd9Sstevel@tonic-gate 
2137c478bd9Sstevel@tonic-gate /*
2147c478bd9Sstevel@tonic-gate  * Crush out the undo save area, moving the open/visual
2157c478bd9Sstevel@tonic-gate  * save area down in its place.
2167c478bd9Sstevel@tonic-gate  */
217f6db9f27Scf46844 void
218f6db9f27Scf46844 squish(void)
2197c478bd9Sstevel@tonic-gate {
220f6db9f27Scf46844 	line *a1 = dol + 1, *a2 = unddol + 1, *a3 = truedol + 1;
2217c478bd9Sstevel@tonic-gate 
2227c478bd9Sstevel@tonic-gate 	if(FIXUNDO) {
2237c478bd9Sstevel@tonic-gate 		if (inopen == -1)
2247c478bd9Sstevel@tonic-gate 			return;
2257c478bd9Sstevel@tonic-gate 		if (a1 < a2 && a2 < a3)
2267c478bd9Sstevel@tonic-gate 			do
2277c478bd9Sstevel@tonic-gate 				*a1++ = *a2++;
2287c478bd9Sstevel@tonic-gate 			while (a2 < a3);
2297c478bd9Sstevel@tonic-gate 		truedol -= unddol - dol;
2307c478bd9Sstevel@tonic-gate 		unddol = dol;
2317c478bd9Sstevel@tonic-gate 	}
2327c478bd9Sstevel@tonic-gate }
2337c478bd9Sstevel@tonic-gate 
2347c478bd9Sstevel@tonic-gate /*
2357c478bd9Sstevel@tonic-gate  * Join lines.  Special hacks put in spaces, two spaces if
2367c478bd9Sstevel@tonic-gate  * preceding line ends with '.', or no spaces if next line starts with ).
2377c478bd9Sstevel@tonic-gate  */
238f6db9f27Scf46844 static	int jcount;
2397c478bd9Sstevel@tonic-gate 
240f6db9f27Scf46844 int
241f6db9f27Scf46844 join(int c)
2427c478bd9Sstevel@tonic-gate {
243f6db9f27Scf46844 	line *a1;
244f6db9f27Scf46844 	unsigned char *cp, *cp1;
2457c478bd9Sstevel@tonic-gate #ifndef PRESUNEUC
246f6db9f27Scf46844 	unsigned char *pcp;
247f6db9f27Scf46844 	wchar_t *delim;
2487c478bd9Sstevel@tonic-gate 	wchar_t wc1, wc2;
2497c478bd9Sstevel@tonic-gate 	int n;
2507c478bd9Sstevel@tonic-gate #endif /* PRESUNEUC */
2517c478bd9Sstevel@tonic-gate 
2527c478bd9Sstevel@tonic-gate 	cp = genbuf;
2537c478bd9Sstevel@tonic-gate 	*cp = 0;
2547c478bd9Sstevel@tonic-gate 	for (a1 = addr1; a1 <= addr2; a1++) {
25523a1cceaSRoger A. Faulkner 		getaline(*a1);
2567c478bd9Sstevel@tonic-gate 		cp1 = linebuf;
2577c478bd9Sstevel@tonic-gate 		if (a1 != addr1 && c == 0) {
2587c478bd9Sstevel@tonic-gate 			while (*cp1 == ' ' || *cp1 == '\t')
2597c478bd9Sstevel@tonic-gate 				cp1++;
2607c478bd9Sstevel@tonic-gate 			if (*cp1 && cp > genbuf && cp[-1] != ' ' && cp[-1] != '\t') {
2617c478bd9Sstevel@tonic-gate #ifndef PRESUNEUC
2627c478bd9Sstevel@tonic-gate 				/*
2637c478bd9Sstevel@tonic-gate 				 * insert locale-specific word delimiter if
2647c478bd9Sstevel@tonic-gate 				 * either of end-of-former-line or
2657c478bd9Sstevel@tonic-gate 				 * top-of-latter-line is non-ASCII.
2667c478bd9Sstevel@tonic-gate 				 */
2677c478bd9Sstevel@tonic-gate 				if (wddlm && *cp1 != ')' && cp[-1] != '.') {
2687c478bd9Sstevel@tonic-gate 					if ((pcp = cp - MB_CUR_MAX) < genbuf)
2697c478bd9Sstevel@tonic-gate 						pcp = genbuf;;
2707c478bd9Sstevel@tonic-gate 					for ( ; pcp <= cp-1; pcp++) {
2717c478bd9Sstevel@tonic-gate 						if ((n = mbtowc(&wc1,
2727c478bd9Sstevel@tonic-gate 						    (char *)pcp, cp - pcp)) ==
2737c478bd9Sstevel@tonic-gate 						    cp - pcp)
2747c478bd9Sstevel@tonic-gate 							goto gotprev;
2757c478bd9Sstevel@tonic-gate 					}
2767c478bd9Sstevel@tonic-gate 					goto mberror;
2777c478bd9Sstevel@tonic-gate gotprev:
2787c478bd9Sstevel@tonic-gate 					if (!isascii(wc2 = *cp1)) {
2797c478bd9Sstevel@tonic-gate 						if (mbtowc(&wc2, (char *) cp1,
2807c478bd9Sstevel@tonic-gate 					    		   MB_CUR_MAX) <= 0)
2817c478bd9Sstevel@tonic-gate 							goto mberror;
2827c478bd9Sstevel@tonic-gate 					}
2837c478bd9Sstevel@tonic-gate 					delim = (*wddlm)(wc1,wc2,2);
2847c478bd9Sstevel@tonic-gate 					while (*delim)
2857c478bd9Sstevel@tonic-gate 						cp += wctomb((char *)cp,
2867c478bd9Sstevel@tonic-gate 						      *delim++);
2877c478bd9Sstevel@tonic-gate 					*cp = 0;
2887c478bd9Sstevel@tonic-gate 				} else
2897c478bd9Sstevel@tonic-gate mberror:
2907c478bd9Sstevel@tonic-gate #endif /* PRESUNEUC */
2917c478bd9Sstevel@tonic-gate 				if (*cp1 != ')') {
2927c478bd9Sstevel@tonic-gate 					*cp++ = ' ';
2937c478bd9Sstevel@tonic-gate 					if (cp[-2] == '.')
2947c478bd9Sstevel@tonic-gate 						*cp++ = ' ';
2957c478bd9Sstevel@tonic-gate 				}
2967c478bd9Sstevel@tonic-gate 			}
2977c478bd9Sstevel@tonic-gate 		}
2987c478bd9Sstevel@tonic-gate 		while (*cp++ = *cp1++)
2997c478bd9Sstevel@tonic-gate 			if (cp > &genbuf[LBSIZE-2])
3007c478bd9Sstevel@tonic-gate 				error(value(vi_TERSE) ? gettext("Line overflow") :
3017c478bd9Sstevel@tonic-gate gettext("Result line of join would be too long"));
3027c478bd9Sstevel@tonic-gate 		cp--;
3037c478bd9Sstevel@tonic-gate 	}
3047c478bd9Sstevel@tonic-gate 	strcLIN(genbuf);
305f6db9f27Scf46844 	(void) delete(0);
3067c478bd9Sstevel@tonic-gate 	jcount = 1;
3077c478bd9Sstevel@tonic-gate 	if (FIXUNDO)
3087c478bd9Sstevel@tonic-gate 		undap1 = undap2 = addr1;
3097c478bd9Sstevel@tonic-gate 	(void)append(jnoop, --addr1);
3107c478bd9Sstevel@tonic-gate 	if (FIXUNDO)
3117c478bd9Sstevel@tonic-gate 		vundkind = VMANY;
312f6db9f27Scf46844 	return (0);
3137c478bd9Sstevel@tonic-gate }
3147c478bd9Sstevel@tonic-gate 
315f6db9f27Scf46844 static int
316f6db9f27Scf46844 jnoop(void)
3177c478bd9Sstevel@tonic-gate {
3187c478bd9Sstevel@tonic-gate 
3197c478bd9Sstevel@tonic-gate 	return(--jcount);
3207c478bd9Sstevel@tonic-gate }
3217c478bd9Sstevel@tonic-gate 
3227c478bd9Sstevel@tonic-gate /*
3237c478bd9Sstevel@tonic-gate  * Move and copy lines.  Hard work is done by move1 which
3247c478bd9Sstevel@tonic-gate  * is also called by undo.
3257c478bd9Sstevel@tonic-gate  */
3267c478bd9Sstevel@tonic-gate int	getcopy();
3277c478bd9Sstevel@tonic-gate 
328f6db9f27Scf46844 void
329f6db9f27Scf46844 vi_move(void)
3307c478bd9Sstevel@tonic-gate {
331f6db9f27Scf46844 	line *adt;
3327c478bd9Sstevel@tonic-gate 	bool iscopy = 0;
3337c478bd9Sstevel@tonic-gate 
3347c478bd9Sstevel@tonic-gate 	if (Command[0] == 'm') {
3357c478bd9Sstevel@tonic-gate 		setdot1();
3367c478bd9Sstevel@tonic-gate 		markpr(addr2 == dot ? addr1 - 1 : addr2 + 1);
3377c478bd9Sstevel@tonic-gate 	} else {
3387c478bd9Sstevel@tonic-gate 		iscopy++;
3397c478bd9Sstevel@tonic-gate 		setdot();
3407c478bd9Sstevel@tonic-gate 	}
3417c478bd9Sstevel@tonic-gate 	nonzero();
3427c478bd9Sstevel@tonic-gate 	adt = address((char*)0);
3437c478bd9Sstevel@tonic-gate 	if (adt == 0)
344f6db9f27Scf46844 		serror(value(vi_TERSE) ?
345f6db9f27Scf46844 		    (unsigned char *)gettext("%s where?") :
346f6db9f27Scf46844 		    (unsigned char *)gettext("%s requires a trailing address"),
347f6db9f27Scf46844 		    Command);
3487c478bd9Sstevel@tonic-gate 	donewline();
3497c478bd9Sstevel@tonic-gate 	move1(iscopy, adt);
3507c478bd9Sstevel@tonic-gate 	killed();
3517c478bd9Sstevel@tonic-gate }
3527c478bd9Sstevel@tonic-gate 
353f6db9f27Scf46844 void
354f6db9f27Scf46844 move1(int cflag, line *addrt)
3557c478bd9Sstevel@tonic-gate {
356f6db9f27Scf46844 	line *adt, *ad1, *ad2;
3577c478bd9Sstevel@tonic-gate 	int nlines;
3587c478bd9Sstevel@tonic-gate 
3597c478bd9Sstevel@tonic-gate 	adt = addrt;
3607c478bd9Sstevel@tonic-gate 	nlines = (addr2 - addr1) + 1;
3617c478bd9Sstevel@tonic-gate 	if (cflag) {
3627c478bd9Sstevel@tonic-gate 		tad1 = addr1;
3637c478bd9Sstevel@tonic-gate 		ad1 = dol;
3647c478bd9Sstevel@tonic-gate 		(void)append(getcopy, ad1++);
3657c478bd9Sstevel@tonic-gate 		ad2 = dol;
3667c478bd9Sstevel@tonic-gate 	} else {
3677c478bd9Sstevel@tonic-gate 		ad2 = addr2;
3687c478bd9Sstevel@tonic-gate 		for (ad1 = addr1; ad1 <= ad2;)
3697c478bd9Sstevel@tonic-gate 			*ad1++ &= ~01;
3707c478bd9Sstevel@tonic-gate 		ad1 = addr1;
3717c478bd9Sstevel@tonic-gate 	}
3727c478bd9Sstevel@tonic-gate 	ad2++;
3737c478bd9Sstevel@tonic-gate 	if (adt < ad1) {
3747c478bd9Sstevel@tonic-gate 		if (adt + 1 == ad1 && !cflag && !inglobal)
3757c478bd9Sstevel@tonic-gate 			error(gettext("That move would do nothing!"));
3767c478bd9Sstevel@tonic-gate 		dot = adt + (ad2 - ad1);
3777c478bd9Sstevel@tonic-gate 		if (++adt != ad1) {
3787c478bd9Sstevel@tonic-gate 			reverse(adt, ad1);
3797c478bd9Sstevel@tonic-gate 			reverse(ad1, ad2);
3807c478bd9Sstevel@tonic-gate 			reverse(adt, ad2);
3817c478bd9Sstevel@tonic-gate 		}
3827c478bd9Sstevel@tonic-gate 	} else if (adt >= ad2) {
3837c478bd9Sstevel@tonic-gate 		dot = adt++;
3847c478bd9Sstevel@tonic-gate 		reverse(ad1, ad2);
3857c478bd9Sstevel@tonic-gate 		reverse(ad2, adt);
3867c478bd9Sstevel@tonic-gate 		reverse(ad1, adt);
3877c478bd9Sstevel@tonic-gate 	} else
3887c478bd9Sstevel@tonic-gate 		error(gettext("Move to a moved line"));
3897c478bd9Sstevel@tonic-gate 	change();
3907c478bd9Sstevel@tonic-gate 	if (!inglobal)
3917c478bd9Sstevel@tonic-gate 		if(FIXUNDO) {
3927c478bd9Sstevel@tonic-gate 			if (cflag) {
3937c478bd9Sstevel@tonic-gate 				undap1 = addrt + 1;
3947c478bd9Sstevel@tonic-gate 				undap2 = undap1 + nlines;
3957c478bd9Sstevel@tonic-gate 				deletenone();
3967c478bd9Sstevel@tonic-gate 			} else {
3977c478bd9Sstevel@tonic-gate 				undkind = UNDMOVE;
3987c478bd9Sstevel@tonic-gate 				undap1 = addr1;
3997c478bd9Sstevel@tonic-gate 				undap2 = addr2;
4007c478bd9Sstevel@tonic-gate 				unddel = addrt;
4017c478bd9Sstevel@tonic-gate 				squish();
4027c478bd9Sstevel@tonic-gate 			}
4037c478bd9Sstevel@tonic-gate 		}
4047c478bd9Sstevel@tonic-gate }
4057c478bd9Sstevel@tonic-gate 
406f6db9f27Scf46844 int
407f6db9f27Scf46844 getcopy(void)
4087c478bd9Sstevel@tonic-gate {
4097c478bd9Sstevel@tonic-gate 
4107c478bd9Sstevel@tonic-gate 	if (tad1 > addr2)
4117c478bd9Sstevel@tonic-gate 		return (EOF);
41223a1cceaSRoger A. Faulkner 	getaline(*tad1++);
4137c478bd9Sstevel@tonic-gate 	return (0);
4147c478bd9Sstevel@tonic-gate }
4157c478bd9Sstevel@tonic-gate 
4167c478bd9Sstevel@tonic-gate /*
4177c478bd9Sstevel@tonic-gate  * Put lines in the buffer from the undo save area.
4187c478bd9Sstevel@tonic-gate  */
419f6db9f27Scf46844 int
420f6db9f27Scf46844 getput(void)
4217c478bd9Sstevel@tonic-gate {
4227c478bd9Sstevel@tonic-gate 
4237c478bd9Sstevel@tonic-gate 	if (tad1 > unddol)
4247c478bd9Sstevel@tonic-gate 		return (EOF);
42523a1cceaSRoger A. Faulkner 	getaline(*tad1++);
4267c478bd9Sstevel@tonic-gate 	tad1++;
4277c478bd9Sstevel@tonic-gate 	return (0);
4287c478bd9Sstevel@tonic-gate }
4297c478bd9Sstevel@tonic-gate 
430f6db9f27Scf46844 int
431f6db9f27Scf46844 put(void)
4327c478bd9Sstevel@tonic-gate {
433f6db9f27Scf46844 	int cnt;
4347c478bd9Sstevel@tonic-gate 
4357c478bd9Sstevel@tonic-gate 	if (!FIXUNDO)
4367c478bd9Sstevel@tonic-gate 		error(gettext("Cannot put inside global/macro"));
4377c478bd9Sstevel@tonic-gate 	cnt = unddol - dol;
4387c478bd9Sstevel@tonic-gate 	if (cnt && inopen && pkill[0] && pkill[1]) {
4397c478bd9Sstevel@tonic-gate 		pragged(1);
440f6db9f27Scf46844 		return (0);
4417c478bd9Sstevel@tonic-gate 	}
4427c478bd9Sstevel@tonic-gate 	tad1 = dol + 1;
4437c478bd9Sstevel@tonic-gate 	(void)append(getput, addr2);
4447c478bd9Sstevel@tonic-gate 	undkind = UNDPUT;
4457c478bd9Sstevel@tonic-gate 	notecnt = cnt;
4467c478bd9Sstevel@tonic-gate 	netchange(cnt);
447f6db9f27Scf46844 	return (0);
4487c478bd9Sstevel@tonic-gate }
4497c478bd9Sstevel@tonic-gate 
4507c478bd9Sstevel@tonic-gate /*
4517c478bd9Sstevel@tonic-gate  * A tricky put, of a group of lines in the middle
4527c478bd9Sstevel@tonic-gate  * of an existing line.  Only from open/visual.
4537c478bd9Sstevel@tonic-gate  * Argument says pkills have meaning, e.g. called from
4547c478bd9Sstevel@tonic-gate  * put; it is 0 on calls from putreg.
4557c478bd9Sstevel@tonic-gate  */
456f6db9f27Scf46844 void
457f6db9f27Scf46844 pragged(bool kill)
4587c478bd9Sstevel@tonic-gate {
4597c478bd9Sstevel@tonic-gate 	extern unsigned char *cursor;
4607c478bd9Sstevel@tonic-gate #ifdef XPG4
4617c478bd9Sstevel@tonic-gate 	extern int P_cursor_offset;
4627c478bd9Sstevel@tonic-gate #endif
463f6db9f27Scf46844 	unsigned char *gp = &genbuf[cursor - linebuf];
4647c478bd9Sstevel@tonic-gate 
4657c478bd9Sstevel@tonic-gate 	/*
4667c478bd9Sstevel@tonic-gate 	 * Assume the editor has:
4677c478bd9Sstevel@tonic-gate 	 *
4687c478bd9Sstevel@tonic-gate 	 *	cursor is on 'c'
4697c478bd9Sstevel@tonic-gate 	 *
4707c478bd9Sstevel@tonic-gate 	 *	file is:	1) abcd
4717c478bd9Sstevel@tonic-gate 	 *			2) efgh
4727c478bd9Sstevel@tonic-gate 	 *
4737c478bd9Sstevel@tonic-gate 	 *	undo area:	3) 1
4747c478bd9Sstevel@tonic-gate 	 *			4) 2
4757c478bd9Sstevel@tonic-gate 	 *			5) 3
4767c478bd9Sstevel@tonic-gate 	 */
4777c478bd9Sstevel@tonic-gate 
4787c478bd9Sstevel@tonic-gate 	if (!kill)
4797c478bd9Sstevel@tonic-gate 		getDOT();
4807c478bd9Sstevel@tonic-gate 
4817c478bd9Sstevel@tonic-gate 	/*
4827c478bd9Sstevel@tonic-gate 	 * Copy "abcd" into genbuf.
4837c478bd9Sstevel@tonic-gate 	 * Note that gp points to 'c'.
4847c478bd9Sstevel@tonic-gate 	 */
4857c478bd9Sstevel@tonic-gate 
4867c478bd9Sstevel@tonic-gate 	strcpy(genbuf, linebuf);
4877c478bd9Sstevel@tonic-gate 
4887c478bd9Sstevel@tonic-gate 	/*
4897c478bd9Sstevel@tonic-gate 	 * Get last line of undo area ("3") into linebuf.
4907c478bd9Sstevel@tonic-gate 	 */
4917c478bd9Sstevel@tonic-gate 
49223a1cceaSRoger A. Faulkner 	getaline(*unddol);
4937c478bd9Sstevel@tonic-gate 	if (kill)
4947c478bd9Sstevel@tonic-gate 		*pkill[1] = 0;
4957c478bd9Sstevel@tonic-gate 
4967c478bd9Sstevel@tonic-gate 
4977c478bd9Sstevel@tonic-gate 	/*
4987c478bd9Sstevel@tonic-gate 	 * Concatenate trailing end of current line
4997c478bd9Sstevel@tonic-gate 	 * into the last line of undo area:
5007c478bd9Sstevel@tonic-gate 	 *	linebuf = "3cd"
5017c478bd9Sstevel@tonic-gate 	 */
5027c478bd9Sstevel@tonic-gate 
5037c478bd9Sstevel@tonic-gate 	strcat(linebuf, gp);
5047c478bd9Sstevel@tonic-gate #ifdef XPG4
5057c478bd9Sstevel@tonic-gate 	P_cursor_offset = strlen(linebuf) - strlen(gp) - 1;
5067c478bd9Sstevel@tonic-gate #endif
5077c478bd9Sstevel@tonic-gate 
5087c478bd9Sstevel@tonic-gate 	/*
5097c478bd9Sstevel@tonic-gate 	 * Replace the last line with what is now in linebuf.
5107c478bd9Sstevel@tonic-gate 	 * So unddol = "3cd"
5117c478bd9Sstevel@tonic-gate 	 */
5127c478bd9Sstevel@tonic-gate 
5137c478bd9Sstevel@tonic-gate 	putmark(unddol);
5147c478bd9Sstevel@tonic-gate 
5157c478bd9Sstevel@tonic-gate 	/*
5167c478bd9Sstevel@tonic-gate 	 * Get the first line of the undo save area into linebuf.
5177c478bd9Sstevel@tonic-gate 	 * So linebuf = "1"
5187c478bd9Sstevel@tonic-gate 	 */
5197c478bd9Sstevel@tonic-gate 
52023a1cceaSRoger A. Faulkner 	getaline(dol[1]);
5217c478bd9Sstevel@tonic-gate 	if (kill)
5227c478bd9Sstevel@tonic-gate 		strcLIN(pkill[0]);
5237c478bd9Sstevel@tonic-gate 
5247c478bd9Sstevel@tonic-gate 	/*
5257c478bd9Sstevel@tonic-gate 	 * Copy the first line of the undo save area
5267c478bd9Sstevel@tonic-gate 	 * over what is pointed to by sp.
5277c478bd9Sstevel@tonic-gate 	 *	genbuf = "ab1"
5287c478bd9Sstevel@tonic-gate 	 */
5297c478bd9Sstevel@tonic-gate 
5307c478bd9Sstevel@tonic-gate 	strcpy(gp, linebuf);
5317c478bd9Sstevel@tonic-gate 
5327c478bd9Sstevel@tonic-gate 	/*
5337c478bd9Sstevel@tonic-gate 	 * Now copy genbuf back into linebuf.
5347c478bd9Sstevel@tonic-gate 	 *	linebuf = "ab1"
5357c478bd9Sstevel@tonic-gate 	 */
5367c478bd9Sstevel@tonic-gate 
5377c478bd9Sstevel@tonic-gate 	strcLIN(genbuf);
5387c478bd9Sstevel@tonic-gate 
5397c478bd9Sstevel@tonic-gate 	/*
5407c478bd9Sstevel@tonic-gate 	 * Now put linebuf back into the first line
5417c478bd9Sstevel@tonic-gate 	 * of the undo save area.
5427c478bd9Sstevel@tonic-gate 	 */
5437c478bd9Sstevel@tonic-gate 
5447c478bd9Sstevel@tonic-gate 	putmark(dol+1);
5457c478bd9Sstevel@tonic-gate 
5467c478bd9Sstevel@tonic-gate 	/*
5477c478bd9Sstevel@tonic-gate 	 * Prepare to perform an undo which will actually
5487c478bd9Sstevel@tonic-gate 	 * do a put of multiple lines in the middle of
5497c478bd9Sstevel@tonic-gate 	 * the current line.
5507c478bd9Sstevel@tonic-gate 	 */
5517c478bd9Sstevel@tonic-gate 
5527c478bd9Sstevel@tonic-gate 	undkind = UNDCHANGE;
5537c478bd9Sstevel@tonic-gate 	undap1 = dot;
5547c478bd9Sstevel@tonic-gate 	undap2 = dot + 1;
5557c478bd9Sstevel@tonic-gate 	unddel = dot - 1;
5567c478bd9Sstevel@tonic-gate 	undo(1);
5577c478bd9Sstevel@tonic-gate }
5587c478bd9Sstevel@tonic-gate 
5597c478bd9Sstevel@tonic-gate /*
5607c478bd9Sstevel@tonic-gate  * Shift lines, based on c.
5617c478bd9Sstevel@tonic-gate  * If c is neither < nor >, then this is a lisp aligning =.
5627c478bd9Sstevel@tonic-gate  */
563f6db9f27Scf46844 void
564f6db9f27Scf46844 shift(int c, int cnt)
5657c478bd9Sstevel@tonic-gate {
566f6db9f27Scf46844 	line *addr;
567f6db9f27Scf46844 	unsigned char *cp;
5687c478bd9Sstevel@tonic-gate 	unsigned char *dp;
569f6db9f27Scf46844 	int i;
5707c478bd9Sstevel@tonic-gate 
5717c478bd9Sstevel@tonic-gate 	if(FIXUNDO)
5727c478bd9Sstevel@tonic-gate 		save12(), undkind = UNDCHANGE;
5737c478bd9Sstevel@tonic-gate 	cnt *= value(vi_SHIFTWIDTH);
5747c478bd9Sstevel@tonic-gate 	for (addr = addr1; addr <= addr2; addr++) {
5757c478bd9Sstevel@tonic-gate 		dot = addr;
5767c478bd9Sstevel@tonic-gate 		if (c == '=' && addr == addr1 && addr != addr2)
5777c478bd9Sstevel@tonic-gate 			continue;
5787c478bd9Sstevel@tonic-gate 		getDOT();
5797c478bd9Sstevel@tonic-gate 		i = whitecnt(linebuf);
5807c478bd9Sstevel@tonic-gate 		switch (c) {
5817c478bd9Sstevel@tonic-gate 
5827c478bd9Sstevel@tonic-gate 		case '>':
5837c478bd9Sstevel@tonic-gate 			if (linebuf[0] == 0)
5847c478bd9Sstevel@tonic-gate 				continue;
5857c478bd9Sstevel@tonic-gate 			cp = genindent(i + cnt);
5867c478bd9Sstevel@tonic-gate 			break;
5877c478bd9Sstevel@tonic-gate 
5887c478bd9Sstevel@tonic-gate 		case '<':
5897c478bd9Sstevel@tonic-gate 			if (i == 0)
5907c478bd9Sstevel@tonic-gate 				continue;
5917c478bd9Sstevel@tonic-gate 			i -= cnt;
5927c478bd9Sstevel@tonic-gate 			cp = i > 0 ? genindent(i) : genbuf;
5937c478bd9Sstevel@tonic-gate 			break;
5947c478bd9Sstevel@tonic-gate 
5957c478bd9Sstevel@tonic-gate 		default:
5967c478bd9Sstevel@tonic-gate 			i = lindent(addr);
5977c478bd9Sstevel@tonic-gate 			getDOT();
5987c478bd9Sstevel@tonic-gate 			cp = genindent(i);
5997c478bd9Sstevel@tonic-gate 			break;
6007c478bd9Sstevel@tonic-gate 		}
6017c478bd9Sstevel@tonic-gate 		if (cp + strlen(dp = vpastwh(linebuf)) >= &genbuf[LBSIZE - 2])
6027c478bd9Sstevel@tonic-gate 			error(value(vi_TERSE) ? gettext("Line too long") :
6037c478bd9Sstevel@tonic-gate gettext("Result line after shift would be too long"));
6047c478bd9Sstevel@tonic-gate 		CP(cp, dp);
6057c478bd9Sstevel@tonic-gate 		strcLIN(genbuf);
6067c478bd9Sstevel@tonic-gate 		putmark(addr);
6077c478bd9Sstevel@tonic-gate 	}
6087c478bd9Sstevel@tonic-gate 	killed();
6097c478bd9Sstevel@tonic-gate }
6107c478bd9Sstevel@tonic-gate 
6117c478bd9Sstevel@tonic-gate /*
6127c478bd9Sstevel@tonic-gate  * Find a tag in the tags file.
6137c478bd9Sstevel@tonic-gate  * Most work here is in parsing the tags file itself.
6147c478bd9Sstevel@tonic-gate  */
615f6db9f27Scf46844 void
6167c478bd9Sstevel@tonic-gate tagfind(quick)
6177c478bd9Sstevel@tonic-gate 	bool quick;
6187c478bd9Sstevel@tonic-gate {
6197c478bd9Sstevel@tonic-gate 	unsigned char cmdbuf[BUFSIZE];
6207c478bd9Sstevel@tonic-gate 	unsigned char filebuf[FNSIZE];
6217c478bd9Sstevel@tonic-gate 	unsigned char tagfbuf[BUFSIZE];
622f6db9f27Scf46844 	int c, d;
6237c478bd9Sstevel@tonic-gate 	bool samef = 1;
6247c478bd9Sstevel@tonic-gate 	int tfcount = 0;
6257c478bd9Sstevel@tonic-gate 	int omagic, tl;
6267c478bd9Sstevel@tonic-gate 	unsigned char *fn, *fne;
6277c478bd9Sstevel@tonic-gate #ifdef STDIO		/* was VMUNIX */
6287c478bd9Sstevel@tonic-gate 	/*
6297c478bd9Sstevel@tonic-gate 	 * We have lots of room so we bring in stdio and do
6307c478bd9Sstevel@tonic-gate 	 * a binary search on the tags file.
6317c478bd9Sstevel@tonic-gate 	 */
6327c478bd9Sstevel@tonic-gate 	FILE *iof;
6337c478bd9Sstevel@tonic-gate 	unsigned char iofbuf[BUFSIZE];
6347c478bd9Sstevel@tonic-gate 	off64_t mid;	/* assumed byte offset */
6357c478bd9Sstevel@tonic-gate 	off64_t top, bot;	/* length of tag file */
6367c478bd9Sstevel@tonic-gate 	struct stat64 sbuf;
6377c478bd9Sstevel@tonic-gate #endif
6387c478bd9Sstevel@tonic-gate 
6397c478bd9Sstevel@tonic-gate 	omagic = value(vi_MAGIC);
6407c478bd9Sstevel@tonic-gate 	tl = value(vi_TAGLENGTH);
6417c478bd9Sstevel@tonic-gate 	if (!skipend()) {
642f6db9f27Scf46844 		unsigned char *lp = lasttag;
6437c478bd9Sstevel@tonic-gate 
6447c478bd9Sstevel@tonic-gate 		while (!iswhite(peekchar()) && !endcmd(peekchar()))
6457c478bd9Sstevel@tonic-gate 			if (lp < &lasttag[sizeof lasttag - 2])
6467c478bd9Sstevel@tonic-gate 				*lp++ = getchar();
6477c478bd9Sstevel@tonic-gate 			else
6487c478bd9Sstevel@tonic-gate 				ignchar();
6497c478bd9Sstevel@tonic-gate 		*lp++ = 0;
6507c478bd9Sstevel@tonic-gate 		if (!endcmd(peekchar()))
6517c478bd9Sstevel@tonic-gate badtag:
6527c478bd9Sstevel@tonic-gate 			error(value(vi_TERSE) ? gettext("Bad tag") :
6537c478bd9Sstevel@tonic-gate 				gettext("Give one tag per line"));
6547c478bd9Sstevel@tonic-gate 	} else if (lasttag[0] == 0)
6557c478bd9Sstevel@tonic-gate 		error(gettext("No previous tag"));
6567c478bd9Sstevel@tonic-gate 	c = getchar();
6577c478bd9Sstevel@tonic-gate 	if (!endcmd(c))
6587c478bd9Sstevel@tonic-gate 		goto badtag;
6597c478bd9Sstevel@tonic-gate 	if (c == EOF)
6607c478bd9Sstevel@tonic-gate 		ungetchar(c);
6617c478bd9Sstevel@tonic-gate 	clrstats();
6627c478bd9Sstevel@tonic-gate 
6637c478bd9Sstevel@tonic-gate 	/*
6647c478bd9Sstevel@tonic-gate 	 * Loop once for each file in tags "path".
6657c478bd9Sstevel@tonic-gate 	 *
6667c478bd9Sstevel@tonic-gate 	 * System tags array limits to 4k (tags[ONMSZ]) long,
6677c478bd9Sstevel@tonic-gate 	 * therefore, tagfbuf should be able to hold all tags.
6687c478bd9Sstevel@tonic-gate 	 */
6697c478bd9Sstevel@tonic-gate 
6707c478bd9Sstevel@tonic-gate 	CP(tagfbuf, svalue(vi_TAGS));
6717c478bd9Sstevel@tonic-gate 	fne = tagfbuf - 1;
6727c478bd9Sstevel@tonic-gate 	while (fne) {
6737c478bd9Sstevel@tonic-gate 		fn = ++fne;
6747c478bd9Sstevel@tonic-gate 		while (*fne && *fne != ' ')
6757c478bd9Sstevel@tonic-gate 			fne++;
6767c478bd9Sstevel@tonic-gate 		if (*fne == 0)
6777c478bd9Sstevel@tonic-gate 			fne = 0;	/* done, quit after this time */
6787c478bd9Sstevel@tonic-gate 		else
6797c478bd9Sstevel@tonic-gate 			*fne = 0;	/* null terminate filename */
6807c478bd9Sstevel@tonic-gate #ifdef STDIO		/* was VMUNIX */
6817c478bd9Sstevel@tonic-gate 		iof = fopen((char *)fn, "r");
6827c478bd9Sstevel@tonic-gate 		if (iof == NULL)
6837c478bd9Sstevel@tonic-gate 			continue;
6847c478bd9Sstevel@tonic-gate 		tfcount++;
6857c478bd9Sstevel@tonic-gate 		setbuf(iof, (char *)iofbuf);
6867c478bd9Sstevel@tonic-gate 		fstat64(fileno(iof), &sbuf);
6877c478bd9Sstevel@tonic-gate 		top = sbuf.st_size;
6887c478bd9Sstevel@tonic-gate 		if (top == 0L || iof == NULL)
6897c478bd9Sstevel@tonic-gate 			top = -1L;
6907c478bd9Sstevel@tonic-gate 		bot = 0L;
6917c478bd9Sstevel@tonic-gate 		while (top >= bot) {
6927c478bd9Sstevel@tonic-gate 			/* loop for each tags file entry */
693f6db9f27Scf46844 			unsigned char *cp = linebuf;
694f6db9f27Scf46844 			unsigned char *lp = lasttag;
6957c478bd9Sstevel@tonic-gate 			unsigned char *oglobp;
6967c478bd9Sstevel@tonic-gate 
6977c478bd9Sstevel@tonic-gate 			mid = (top + bot) / 2;
6987c478bd9Sstevel@tonic-gate 			fseeko64(iof, mid, 0);
6997c478bd9Sstevel@tonic-gate 			if (mid > 0)	/* to get first tag in file to work */
7007c478bd9Sstevel@tonic-gate 				/* scan to next \n */
7017c478bd9Sstevel@tonic-gate 				if(fgets((char *)linebuf, sizeof linebuf, iof)==NULL)
7027c478bd9Sstevel@tonic-gate 					goto goleft;
7037c478bd9Sstevel@tonic-gate 			/* get the line itself */
7047c478bd9Sstevel@tonic-gate 			if(fgets((char *)linebuf, sizeof linebuf, iof)==NULL)
7057c478bd9Sstevel@tonic-gate 				goto goleft;
7067c478bd9Sstevel@tonic-gate 			linebuf[strlen(linebuf)-1] = 0;	/* was '\n' */
7077c478bd9Sstevel@tonic-gate 			while (*cp && *lp == *cp)
7087c478bd9Sstevel@tonic-gate 				cp++, lp++;
7097c478bd9Sstevel@tonic-gate 			/*
7107c478bd9Sstevel@tonic-gate 			 * This if decides whether there is a tag match.
7117c478bd9Sstevel@tonic-gate 			 *  A positive taglength means that a
7127c478bd9Sstevel@tonic-gate 			 *  match is found if the tag given matches at least
7137c478bd9Sstevel@tonic-gate 			 *  taglength chars of the tag found.
7147c478bd9Sstevel@tonic-gate 			 *  A taglength of greater than 511 means that a
7157c478bd9Sstevel@tonic-gate 			 *  match is found even if the tag given is a proper
7167c478bd9Sstevel@tonic-gate 			 *  prefix of the tag found.  i.e. "ab" matches "abcd"
7177c478bd9Sstevel@tonic-gate 			 */
7187c478bd9Sstevel@tonic-gate 			if ( *lp == 0 && (iswhite(*cp) || tl > 511 || tl > 0 && lp-lasttag >= tl) ) {
7197c478bd9Sstevel@tonic-gate 				/*
7207c478bd9Sstevel@tonic-gate 				 * Found a match.  Force selection to be
7217c478bd9Sstevel@tonic-gate 				 *  the first possible.
7227c478bd9Sstevel@tonic-gate 				 */
7237c478bd9Sstevel@tonic-gate 				if ( mid == bot  &&  mid == top ) {
7247c478bd9Sstevel@tonic-gate 					; /* found first possible match */
7257c478bd9Sstevel@tonic-gate 				}
7267c478bd9Sstevel@tonic-gate 				else {
7277c478bd9Sstevel@tonic-gate 					/* postpone final decision. */
7287c478bd9Sstevel@tonic-gate 					top = mid;
7297c478bd9Sstevel@tonic-gate 					continue;
7307c478bd9Sstevel@tonic-gate 				}
7317c478bd9Sstevel@tonic-gate 			}
7327c478bd9Sstevel@tonic-gate 			else {
7337c478bd9Sstevel@tonic-gate 				if ((int)*lp > (int)*cp)
7347c478bd9Sstevel@tonic-gate 					bot = mid + 1;
7357c478bd9Sstevel@tonic-gate 				else
7367c478bd9Sstevel@tonic-gate goleft:
7377c478bd9Sstevel@tonic-gate 					top = mid - 1;
7387c478bd9Sstevel@tonic-gate 				continue;
7397c478bd9Sstevel@tonic-gate 			}
7407c478bd9Sstevel@tonic-gate 			/*
7417c478bd9Sstevel@tonic-gate 			 * We found the tag.  Decode the line in the file.
7427c478bd9Sstevel@tonic-gate 			 */
7437c478bd9Sstevel@tonic-gate 			fclose(iof);
7447c478bd9Sstevel@tonic-gate 
7457c478bd9Sstevel@tonic-gate 			/* Rest of tag if abbreviated */
7467c478bd9Sstevel@tonic-gate 			while (!iswhite(*cp))
7477c478bd9Sstevel@tonic-gate 				cp++;
7487c478bd9Sstevel@tonic-gate 
7497c478bd9Sstevel@tonic-gate 			/* name of file */
7507c478bd9Sstevel@tonic-gate 			while (*cp && iswhite(*cp))
7517c478bd9Sstevel@tonic-gate 				cp++;
7527c478bd9Sstevel@tonic-gate 			if (!*cp)
7537c478bd9Sstevel@tonic-gate badtags:
754f6db9f27Scf46844 				serror((unsigned char *)
755f6db9f27Scf46844 				    gettext("%s: Bad tags file entry"),
756f6db9f27Scf46844 				    lasttag);
7577c478bd9Sstevel@tonic-gate 			lp = filebuf;
7587c478bd9Sstevel@tonic-gate 			while (*cp && *cp != ' ' && *cp != '\t') {
7597c478bd9Sstevel@tonic-gate 				if (lp < &filebuf[sizeof filebuf - 2])
7607c478bd9Sstevel@tonic-gate 					*lp++ = *cp;
7617c478bd9Sstevel@tonic-gate 				cp++;
7627c478bd9Sstevel@tonic-gate 			}
7637c478bd9Sstevel@tonic-gate 			*lp++ = 0;
7647c478bd9Sstevel@tonic-gate 
7657c478bd9Sstevel@tonic-gate 			if (*cp == 0)
7667c478bd9Sstevel@tonic-gate 				goto badtags;
7677c478bd9Sstevel@tonic-gate 			if (dol != zero) {
7687c478bd9Sstevel@tonic-gate 				/*
7697c478bd9Sstevel@tonic-gate 				 * Save current position in 't for ^^ in visual.
7707c478bd9Sstevel@tonic-gate 				 */
7717c478bd9Sstevel@tonic-gate 				names['t'-'a'] = *dot &~ 01;
7727c478bd9Sstevel@tonic-gate 				if (inopen) {
7737c478bd9Sstevel@tonic-gate 					extern unsigned char *ncols['z'-'a'+2];
7747c478bd9Sstevel@tonic-gate 					extern unsigned char *cursor;
7757c478bd9Sstevel@tonic-gate 
7767c478bd9Sstevel@tonic-gate 					ncols['t'-'a'] = cursor;
7777c478bd9Sstevel@tonic-gate 				}
7787c478bd9Sstevel@tonic-gate 			}
7797c478bd9Sstevel@tonic-gate #ifdef TAG_STACK
7807c478bd9Sstevel@tonic-gate                         if (*savedfile) {
781f6db9f27Scf46844 				savetag((char *)savedfile);
7827c478bd9Sstevel@tonic-gate                         }
7837c478bd9Sstevel@tonic-gate #endif
7847c478bd9Sstevel@tonic-gate 			strcpy(cmdbuf, cp);
7857c478bd9Sstevel@tonic-gate 			if (strcmp(filebuf, savedfile) || !edited) {
7867c478bd9Sstevel@tonic-gate 				unsigned char cmdbuf2[sizeof filebuf + 10];
7877c478bd9Sstevel@tonic-gate 
7887c478bd9Sstevel@tonic-gate 				/* Different file.  Do autowrite & get it. */
7897c478bd9Sstevel@tonic-gate 				if (!quick) {
7907c478bd9Sstevel@tonic-gate 					ckaw();
7917c478bd9Sstevel@tonic-gate 					if (chng && dol > zero) {
7927c478bd9Sstevel@tonic-gate #ifdef TAG_STACK
7937c478bd9Sstevel@tonic-gate                                                 unsavetag();
7947c478bd9Sstevel@tonic-gate #endif
7957c478bd9Sstevel@tonic-gate 						error(value(vi_TERSE) ?
7967c478bd9Sstevel@tonic-gate gettext("No write") : gettext("No write since last change (:tag! overrides)"));
7977c478bd9Sstevel@tonic-gate 					}
7987c478bd9Sstevel@tonic-gate 				}
7997c478bd9Sstevel@tonic-gate 				oglobp = globp;
8007c478bd9Sstevel@tonic-gate 				strcpy(cmdbuf2, "e! ");
8017c478bd9Sstevel@tonic-gate 				strcat(cmdbuf2, filebuf);
8027c478bd9Sstevel@tonic-gate 				globp = cmdbuf2;
8037c478bd9Sstevel@tonic-gate 				d = peekc; ungetchar(0);
8047c478bd9Sstevel@tonic-gate 				commands(1, 1);
8057c478bd9Sstevel@tonic-gate 				peekc = d;
8067c478bd9Sstevel@tonic-gate 				globp = oglobp;
8077c478bd9Sstevel@tonic-gate 				value(vi_MAGIC) = omagic;
8087c478bd9Sstevel@tonic-gate 				samef = 0;
8097c478bd9Sstevel@tonic-gate 			}
8107c478bd9Sstevel@tonic-gate 
8117c478bd9Sstevel@tonic-gate 			/*
8127c478bd9Sstevel@tonic-gate 			 * Look for pattern in the current file.
8137c478bd9Sstevel@tonic-gate 			 */
8147c478bd9Sstevel@tonic-gate 			oglobp = globp;
8157c478bd9Sstevel@tonic-gate 			globp = cmdbuf;
8167c478bd9Sstevel@tonic-gate 			d = peekc; ungetchar(0);
8177c478bd9Sstevel@tonic-gate 			if (samef)
8187c478bd9Sstevel@tonic-gate 				markpr(dot);
8197c478bd9Sstevel@tonic-gate 			/*
8207c478bd9Sstevel@tonic-gate 			 * BUG: if it isn't found (user edited header
8217c478bd9Sstevel@tonic-gate 			 * line) we get left in nomagic mode.
8227c478bd9Sstevel@tonic-gate 			 */
8237c478bd9Sstevel@tonic-gate 			value(vi_MAGIC) = 0;
8247c478bd9Sstevel@tonic-gate 			commands(1, 1);
8257c478bd9Sstevel@tonic-gate 			peekc = d;
8267c478bd9Sstevel@tonic-gate 			globp = oglobp;
8277c478bd9Sstevel@tonic-gate 			value(vi_MAGIC) = omagic;
8287c478bd9Sstevel@tonic-gate 			return;
8297c478bd9Sstevel@tonic-gate 		}	/* end of "for each tag in file" */
8307c478bd9Sstevel@tonic-gate #endif	/* STDIO */
8317c478bd9Sstevel@tonic-gate 		/*
8327c478bd9Sstevel@tonic-gate 		 * Binary search failed, so try linear search if -S is on.
8337c478bd9Sstevel@tonic-gate 		 * -S is needed for tags files that are not sorted.
8347c478bd9Sstevel@tonic-gate 		 */
8357c478bd9Sstevel@tonic-gate 
8367c478bd9Sstevel@tonic-gate 		/*
8377c478bd9Sstevel@tonic-gate 		 * Avoid stdio and scan tag file linearly.
8387c478bd9Sstevel@tonic-gate 		 */
8397c478bd9Sstevel@tonic-gate 		if (tags_flag == 0)
8407c478bd9Sstevel@tonic-gate 			continue;
8417c478bd9Sstevel@tonic-gate 		io = open(fn, 0);
8427c478bd9Sstevel@tonic-gate 		if (io < 0)
8437c478bd9Sstevel@tonic-gate 			continue;
8447c478bd9Sstevel@tonic-gate 		/* tfcount++; */
8457c478bd9Sstevel@tonic-gate 		while (getfile() == 0) {
8467c478bd9Sstevel@tonic-gate 			/* loop for each tags file entry */
847f6db9f27Scf46844 			unsigned char *cp = linebuf;
848f6db9f27Scf46844 			unsigned char *lp = lasttag;
8497c478bd9Sstevel@tonic-gate 			unsigned char *oglobp;
8507c478bd9Sstevel@tonic-gate 
8517c478bd9Sstevel@tonic-gate 			while (*cp && *lp == *cp)
8527c478bd9Sstevel@tonic-gate 				cp++, lp++;
8537c478bd9Sstevel@tonic-gate 			/*
8547c478bd9Sstevel@tonic-gate 			 * This if decides whether there is a tag match.
8557c478bd9Sstevel@tonic-gate 			 *  A positive taglength means that a
8567c478bd9Sstevel@tonic-gate 			 *  match is found if the tag given matches at least
8577c478bd9Sstevel@tonic-gate 			 *  taglength chars of the tag found.
8587c478bd9Sstevel@tonic-gate 			 *  A taglength of greater than 511 means that a
8597c478bd9Sstevel@tonic-gate 			 *  match is found even if the tag given is a proper
8607c478bd9Sstevel@tonic-gate 			 *  prefix of the tag found.  i.e. "ab" matches "abcd"
8617c478bd9Sstevel@tonic-gate 			 */
8627c478bd9Sstevel@tonic-gate 			if ( *lp == 0 && (iswhite(*cp) || tl > 511 || tl > 0 && lp-lasttag >= tl) ) {
8637c478bd9Sstevel@tonic-gate 				; /* Found it. */
8647c478bd9Sstevel@tonic-gate 			}
8657c478bd9Sstevel@tonic-gate 			else {
8667c478bd9Sstevel@tonic-gate 				/* Not this tag.  Try the next */
8677c478bd9Sstevel@tonic-gate 				continue;
8687c478bd9Sstevel@tonic-gate 			}
8697c478bd9Sstevel@tonic-gate 			/*
8707c478bd9Sstevel@tonic-gate 			 * We found the tag.  Decode the line in the file.
8717c478bd9Sstevel@tonic-gate 			 */
8727c478bd9Sstevel@tonic-gate 			close(io);
8737c478bd9Sstevel@tonic-gate 			/* Rest of tag if abbreviated */
8747c478bd9Sstevel@tonic-gate 			while (!iswhite(*cp))
8757c478bd9Sstevel@tonic-gate 				cp++;
8767c478bd9Sstevel@tonic-gate 
8777c478bd9Sstevel@tonic-gate 			/* name of file */
8787c478bd9Sstevel@tonic-gate 			while (*cp && iswhite(*cp))
8797c478bd9Sstevel@tonic-gate 				cp++;
8807c478bd9Sstevel@tonic-gate 			if (!*cp)
8817c478bd9Sstevel@tonic-gate badtags2:
882f6db9f27Scf46844 				serror((unsigned char *)
883f6db9f27Scf46844 				    gettext("%s: Bad tags file entry"),
884f6db9f27Scf46844 				    lasttag);
8857c478bd9Sstevel@tonic-gate 			lp = filebuf;
8867c478bd9Sstevel@tonic-gate 			while (*cp && *cp != ' ' && *cp != '\t') {
8877c478bd9Sstevel@tonic-gate 				if (lp < &filebuf[sizeof filebuf - 2])
8887c478bd9Sstevel@tonic-gate 					*lp++ = *cp;
8897c478bd9Sstevel@tonic-gate 				cp++;
8907c478bd9Sstevel@tonic-gate 			}
8917c478bd9Sstevel@tonic-gate 			*lp++ = 0;
8927c478bd9Sstevel@tonic-gate 
8937c478bd9Sstevel@tonic-gate 			if (*cp == 0)
8947c478bd9Sstevel@tonic-gate 				goto badtags2;
8957c478bd9Sstevel@tonic-gate 			if (dol != zero) {
8967c478bd9Sstevel@tonic-gate 				/*
8977c478bd9Sstevel@tonic-gate 				 * Save current position in 't for ^^ in visual.
8987c478bd9Sstevel@tonic-gate 				 */
8997c478bd9Sstevel@tonic-gate 				names['t'-'a'] = *dot &~ 01;
9007c478bd9Sstevel@tonic-gate 				if (inopen) {
9017c478bd9Sstevel@tonic-gate 					extern unsigned char *ncols['z'-'a'+2];
9027c478bd9Sstevel@tonic-gate 					extern unsigned char *cursor;
9037c478bd9Sstevel@tonic-gate 
9047c478bd9Sstevel@tonic-gate 					ncols['t'-'a'] = cursor;
9057c478bd9Sstevel@tonic-gate 				}
9067c478bd9Sstevel@tonic-gate 			}
9077c478bd9Sstevel@tonic-gate #ifdef TAG_STACK
9087c478bd9Sstevel@tonic-gate                         if (*savedfile) {
909f6db9f27Scf46844 				savetag((char *)savedfile);
9107c478bd9Sstevel@tonic-gate                         }
9117c478bd9Sstevel@tonic-gate #endif
9127c478bd9Sstevel@tonic-gate 			strcpy(cmdbuf, cp);
9137c478bd9Sstevel@tonic-gate 			if (strcmp(filebuf, savedfile) || !edited) {
9147c478bd9Sstevel@tonic-gate 				unsigned char cmdbuf2[sizeof filebuf + 10];
9157c478bd9Sstevel@tonic-gate 
9167c478bd9Sstevel@tonic-gate 				/* Different file.  Do autowrite & get it. */
9177c478bd9Sstevel@tonic-gate 				if (!quick) {
9187c478bd9Sstevel@tonic-gate 					ckaw();
9197c478bd9Sstevel@tonic-gate 					if (chng && dol > zero) {
9207c478bd9Sstevel@tonic-gate #ifdef TAG_STACK
9217c478bd9Sstevel@tonic-gate                                                 unsavetag();
9227c478bd9Sstevel@tonic-gate #endif
9237c478bd9Sstevel@tonic-gate 						error(value(vi_TERSE) ?
9247c478bd9Sstevel@tonic-gate gettext("No write") : gettext("No write since last change (:tag! overrides)"));
9257c478bd9Sstevel@tonic-gate 					}
9267c478bd9Sstevel@tonic-gate 				}
9277c478bd9Sstevel@tonic-gate 				oglobp = globp;
9287c478bd9Sstevel@tonic-gate 				strcpy(cmdbuf2, "e! ");
9297c478bd9Sstevel@tonic-gate 				strcat(cmdbuf2, filebuf);
9307c478bd9Sstevel@tonic-gate 				globp = cmdbuf2;
9317c478bd9Sstevel@tonic-gate 				d = peekc; ungetchar(0);
9327c478bd9Sstevel@tonic-gate 				commands(1, 1);
9337c478bd9Sstevel@tonic-gate 				peekc = d;
9347c478bd9Sstevel@tonic-gate 				globp = oglobp;
9357c478bd9Sstevel@tonic-gate 				value(vi_MAGIC) = omagic;
9367c478bd9Sstevel@tonic-gate 				samef = 0;
9377c478bd9Sstevel@tonic-gate 			}
9387c478bd9Sstevel@tonic-gate 
9397c478bd9Sstevel@tonic-gate 			/*
9407c478bd9Sstevel@tonic-gate 			 * Look for pattern in the current file.
9417c478bd9Sstevel@tonic-gate 			 */
9427c478bd9Sstevel@tonic-gate 			oglobp = globp;
9437c478bd9Sstevel@tonic-gate 			globp = cmdbuf;
9447c478bd9Sstevel@tonic-gate 			d = peekc; ungetchar(0);
9457c478bd9Sstevel@tonic-gate 			if (samef)
9467c478bd9Sstevel@tonic-gate 				markpr(dot);
9477c478bd9Sstevel@tonic-gate 			/*
9487c478bd9Sstevel@tonic-gate 			 * BUG: if it isn't found (user edited header
9497c478bd9Sstevel@tonic-gate 			 * line) we get left in nomagic mode.
9507c478bd9Sstevel@tonic-gate 			 */
9517c478bd9Sstevel@tonic-gate 			value(vi_MAGIC) = 0;
9527c478bd9Sstevel@tonic-gate 			commands(1, 1);
9537c478bd9Sstevel@tonic-gate 			peekc = d;
9547c478bd9Sstevel@tonic-gate 			globp = oglobp;
9557c478bd9Sstevel@tonic-gate 			value(vi_MAGIC) = omagic;
9567c478bd9Sstevel@tonic-gate 			return;
9577c478bd9Sstevel@tonic-gate 		}	/* end of "for each tag in file" */
9587c478bd9Sstevel@tonic-gate 
9597c478bd9Sstevel@tonic-gate 		/*
9607c478bd9Sstevel@tonic-gate 		 * No such tag in this file.  Close it and try the next.
9617c478bd9Sstevel@tonic-gate 		 */
9627c478bd9Sstevel@tonic-gate #ifdef STDIO		/* was VMUNIX */
9637c478bd9Sstevel@tonic-gate 		fclose(iof);
9647c478bd9Sstevel@tonic-gate #else
9657c478bd9Sstevel@tonic-gate 		close(io);
9667c478bd9Sstevel@tonic-gate #endif
9677c478bd9Sstevel@tonic-gate 	}	/* end of "for each file in path" */
9687c478bd9Sstevel@tonic-gate 	if (tfcount <= 0)
9697c478bd9Sstevel@tonic-gate 		error(gettext("No tags file"));
9707c478bd9Sstevel@tonic-gate 	else
971f6db9f27Scf46844 		serror(value(vi_TERSE) ?
972f6db9f27Scf46844 		    (unsigned char *)gettext("%s: No such tag") :
973f6db9f27Scf46844 		    (unsigned char *)gettext("%s: No such tag in tags file"),
974f6db9f27Scf46844 		    lasttag);
9757c478bd9Sstevel@tonic-gate }
9767c478bd9Sstevel@tonic-gate 
9777c478bd9Sstevel@tonic-gate /*
9787c478bd9Sstevel@tonic-gate  * Save lines from addr1 thru addr2 as though
9797c478bd9Sstevel@tonic-gate  * they had been deleted.
9807c478bd9Sstevel@tonic-gate  */
981f6db9f27Scf46844 int
982f6db9f27Scf46844 yank(void)
9837c478bd9Sstevel@tonic-gate {
9847c478bd9Sstevel@tonic-gate 
9857c478bd9Sstevel@tonic-gate 	if (!FIXUNDO)
9867c478bd9Sstevel@tonic-gate 		error(gettext("Can't yank inside global/macro"));
9877c478bd9Sstevel@tonic-gate 	save12();
9887c478bd9Sstevel@tonic-gate 	undkind = UNDNONE;
9897c478bd9Sstevel@tonic-gate 	killcnt(addr2 - addr1 + 1);
990f6db9f27Scf46844 	return (0);
9917c478bd9Sstevel@tonic-gate }
9927c478bd9Sstevel@tonic-gate 
9937c478bd9Sstevel@tonic-gate /*
9947c478bd9Sstevel@tonic-gate  * z command; print windows of text in the file.
9957c478bd9Sstevel@tonic-gate  *
9967c478bd9Sstevel@tonic-gate  * If this seems unreasonably arcane, the reasons
9977c478bd9Sstevel@tonic-gate  * are historical.  This is one of the first commands
9987c478bd9Sstevel@tonic-gate  * added to the first ex (then called en) and the
9997c478bd9Sstevel@tonic-gate  * number of facilities here were the major advantage
10007c478bd9Sstevel@tonic-gate  * of en over ed since they allowed more use to be
10017c478bd9Sstevel@tonic-gate  * made of fast terminals w/o typing .,.22p all the time.
10027c478bd9Sstevel@tonic-gate  */
10037c478bd9Sstevel@tonic-gate bool	zhadpr;
10047c478bd9Sstevel@tonic-gate bool	znoclear;
10057c478bd9Sstevel@tonic-gate short	zweight;
10067c478bd9Sstevel@tonic-gate 
1007f6db9f27Scf46844 void
1008f6db9f27Scf46844 zop(int hadpr)
10097c478bd9Sstevel@tonic-gate {
1010f6db9f27Scf46844 	int c, nlines, op;
10117c478bd9Sstevel@tonic-gate 	bool excl;
10127c478bd9Sstevel@tonic-gate 
10137c478bd9Sstevel@tonic-gate 	zhadpr = hadpr;
10147c478bd9Sstevel@tonic-gate 	notempty();
10157c478bd9Sstevel@tonic-gate 	znoclear = 0;
10167c478bd9Sstevel@tonic-gate 	zweight = 0;
10177c478bd9Sstevel@tonic-gate 	excl = exclam();
10187c478bd9Sstevel@tonic-gate 	switch (c = op = getchar()) {
10197c478bd9Sstevel@tonic-gate 
10207c478bd9Sstevel@tonic-gate 	case '^':
10217c478bd9Sstevel@tonic-gate 		zweight = 1;
10227c478bd9Sstevel@tonic-gate 	case '-':
10237c478bd9Sstevel@tonic-gate 	case '+':
10247c478bd9Sstevel@tonic-gate 		while (peekchar() == op) {
10257c478bd9Sstevel@tonic-gate 			ignchar();
10267c478bd9Sstevel@tonic-gate 			zweight++;
10277c478bd9Sstevel@tonic-gate 		}
10287c478bd9Sstevel@tonic-gate 	case '=':
10297c478bd9Sstevel@tonic-gate 	case '.':
10307c478bd9Sstevel@tonic-gate 		c = getchar();
10317c478bd9Sstevel@tonic-gate 		break;
10327c478bd9Sstevel@tonic-gate 
10337c478bd9Sstevel@tonic-gate 	case EOF:
10347c478bd9Sstevel@tonic-gate 		znoclear++;
10357c478bd9Sstevel@tonic-gate 		break;
10367c478bd9Sstevel@tonic-gate 
10377c478bd9Sstevel@tonic-gate 	default:
10387c478bd9Sstevel@tonic-gate 		op = 0;
10397c478bd9Sstevel@tonic-gate 		break;
10407c478bd9Sstevel@tonic-gate 	}
10417c478bd9Sstevel@tonic-gate 	if (isdigit(c)) {
10427c478bd9Sstevel@tonic-gate 		nlines = c - '0';
10437c478bd9Sstevel@tonic-gate 		for(;;) {
10447c478bd9Sstevel@tonic-gate 			c = getchar();
10457c478bd9Sstevel@tonic-gate 			if (!isdigit(c))
10467c478bd9Sstevel@tonic-gate 				break;
10477c478bd9Sstevel@tonic-gate 			nlines *= 10;
10487c478bd9Sstevel@tonic-gate 			nlines += c - '0';
10497c478bd9Sstevel@tonic-gate 		}
10507c478bd9Sstevel@tonic-gate 		if (nlines < lines)
10517c478bd9Sstevel@tonic-gate 			znoclear++;
10527c478bd9Sstevel@tonic-gate 		value(vi_WINDOW) = nlines;
10537c478bd9Sstevel@tonic-gate 		if (op == '=')
10547c478bd9Sstevel@tonic-gate 			nlines += 2;
10557c478bd9Sstevel@tonic-gate 	}
10567c478bd9Sstevel@tonic-gate 	else {
10577c478bd9Sstevel@tonic-gate 		nlines = op == EOF ? value(vi_SCROLL) :
10587c478bd9Sstevel@tonic-gate 			excl ? lines - 1 : value(vi_WINDOW);
10597c478bd9Sstevel@tonic-gate 	}
10607c478bd9Sstevel@tonic-gate 	if (inopen || c != EOF) {
10617c478bd9Sstevel@tonic-gate 		ungetchar(c);
10627c478bd9Sstevel@tonic-gate 		donewline();
10637c478bd9Sstevel@tonic-gate 	}
10647c478bd9Sstevel@tonic-gate 	addr1 = addr2;
10657c478bd9Sstevel@tonic-gate 	if (addr2 == 0 && dot < dol && op == 0)
10667c478bd9Sstevel@tonic-gate 		addr1 = addr2 = dot+1;
10677c478bd9Sstevel@tonic-gate 	setdot();
10687c478bd9Sstevel@tonic-gate 	zop2(nlines, op);
10697c478bd9Sstevel@tonic-gate }
10707c478bd9Sstevel@tonic-gate 
1071f6db9f27Scf46844 void
1072f6db9f27Scf46844 zop2(int nlines, int op)
10737c478bd9Sstevel@tonic-gate {
1074f6db9f27Scf46844 	line *split;
10757c478bd9Sstevel@tonic-gate 
10767c478bd9Sstevel@tonic-gate 	split = NULL;
10777c478bd9Sstevel@tonic-gate 	switch (op) {
10787c478bd9Sstevel@tonic-gate 
10797c478bd9Sstevel@tonic-gate 	case EOF:
10807c478bd9Sstevel@tonic-gate 		if (addr2 == dol)
10817c478bd9Sstevel@tonic-gate 			error(gettext("\nAt EOF"));
10827c478bd9Sstevel@tonic-gate 	case '+':
10837c478bd9Sstevel@tonic-gate 		if (addr2 == dol)
10847c478bd9Sstevel@tonic-gate 			error(gettext("At EOF"));
10857c478bd9Sstevel@tonic-gate 		addr2 += nlines * zweight;
10867c478bd9Sstevel@tonic-gate 		if (addr2 > dol)
10877c478bd9Sstevel@tonic-gate 			error(gettext("Hit BOTTOM"));
10887c478bd9Sstevel@tonic-gate 		addr2++;
10897c478bd9Sstevel@tonic-gate 	default:
10907c478bd9Sstevel@tonic-gate 		addr1 = addr2;
10917c478bd9Sstevel@tonic-gate 		addr2 += nlines-1;
10927c478bd9Sstevel@tonic-gate 		dot = addr2;
10937c478bd9Sstevel@tonic-gate 		break;
10947c478bd9Sstevel@tonic-gate 
10957c478bd9Sstevel@tonic-gate 	case '=':
10967c478bd9Sstevel@tonic-gate 	case '.':
10977c478bd9Sstevel@tonic-gate 		znoclear = 0;
10987c478bd9Sstevel@tonic-gate 		nlines--;
10997c478bd9Sstevel@tonic-gate 		nlines >>= 1;
11007c478bd9Sstevel@tonic-gate 		if (op == '=')
11017c478bd9Sstevel@tonic-gate 			nlines--;
11027c478bd9Sstevel@tonic-gate 		addr1 = addr2 - nlines;
11037c478bd9Sstevel@tonic-gate 		if (op == '=')
11047c478bd9Sstevel@tonic-gate 			dot = split = addr2;
11057c478bd9Sstevel@tonic-gate 		addr2 += nlines;
11067c478bd9Sstevel@tonic-gate 		if (op == '.') {
11077c478bd9Sstevel@tonic-gate 			markDOT();
11087c478bd9Sstevel@tonic-gate 			dot = addr2;
11097c478bd9Sstevel@tonic-gate 		}
11107c478bd9Sstevel@tonic-gate 		break;
11117c478bd9Sstevel@tonic-gate 
11127c478bd9Sstevel@tonic-gate 	case '^':
11137c478bd9Sstevel@tonic-gate 	case '-':
11147c478bd9Sstevel@tonic-gate 		addr2 -= nlines * zweight;
11157c478bd9Sstevel@tonic-gate 		if (addr2 < one)
11167c478bd9Sstevel@tonic-gate 			error(gettext("Hit TOP"));
11177c478bd9Sstevel@tonic-gate 		nlines--;
11187c478bd9Sstevel@tonic-gate 		addr1 = addr2 - nlines;
11197c478bd9Sstevel@tonic-gate 		dot = addr2;
11207c478bd9Sstevel@tonic-gate 		break;
11217c478bd9Sstevel@tonic-gate 	}
11227c478bd9Sstevel@tonic-gate 	if (addr1 <= zero)
11237c478bd9Sstevel@tonic-gate 		addr1 = one;
11247c478bd9Sstevel@tonic-gate 	if (addr2 > dol)
11257c478bd9Sstevel@tonic-gate 		addr2 = dol;
11267c478bd9Sstevel@tonic-gate 	if (dot > dol)
11277c478bd9Sstevel@tonic-gate 		dot = dol;
11287c478bd9Sstevel@tonic-gate 	if (addr1 > addr2)
11297c478bd9Sstevel@tonic-gate 		return;
11307c478bd9Sstevel@tonic-gate 	if (op == EOF && zhadpr) {
113123a1cceaSRoger A. Faulkner 		getaline(*addr1);
11327c478bd9Sstevel@tonic-gate 		putchar((int)('\r' | QUOTE));
11337c478bd9Sstevel@tonic-gate 		shudclob = 1;
11347c478bd9Sstevel@tonic-gate 	} else if (znoclear == 0 && clear_screen != NOSTR && !inopen) {
11357c478bd9Sstevel@tonic-gate 		flush1();
11367c478bd9Sstevel@tonic-gate 		vclear();
11377c478bd9Sstevel@tonic-gate 	}
11387c478bd9Sstevel@tonic-gate 	if (addr2 - addr1 > 1)
11397c478bd9Sstevel@tonic-gate 		pstart();
11407c478bd9Sstevel@tonic-gate 	if (split) {
11417c478bd9Sstevel@tonic-gate 		plines(addr1, split - 1, 0);
11427c478bd9Sstevel@tonic-gate 		splitit();
11437c478bd9Sstevel@tonic-gate 		plines(split, split, 0);
11447c478bd9Sstevel@tonic-gate 		splitit();
11457c478bd9Sstevel@tonic-gate 		addr1 = split + 1;
11467c478bd9Sstevel@tonic-gate 	}
11477c478bd9Sstevel@tonic-gate 	plines(addr1, addr2, 0);
11487c478bd9Sstevel@tonic-gate }
11497c478bd9Sstevel@tonic-gate 
1150f6db9f27Scf46844 static void
1151f6db9f27Scf46844 splitit(void)
11527c478bd9Sstevel@tonic-gate {
1153f6db9f27Scf46844 	int l;
11547c478bd9Sstevel@tonic-gate 
11557c478bd9Sstevel@tonic-gate 	for (l = columns > 80 ? 40 : columns / 2; l > 0; l--)
11567c478bd9Sstevel@tonic-gate 		putchar('-');
11577c478bd9Sstevel@tonic-gate 	putnl();
11587c478bd9Sstevel@tonic-gate }
11597c478bd9Sstevel@tonic-gate 
1160f6db9f27Scf46844 void
1161f6db9f27Scf46844 plines(line *adr1, line *adr2, bool movedot)
11627c478bd9Sstevel@tonic-gate {
1163f6db9f27Scf46844 	line *addr;
11647c478bd9Sstevel@tonic-gate 
11657c478bd9Sstevel@tonic-gate 	pofix();
11667c478bd9Sstevel@tonic-gate 	for (addr = adr1; addr <= adr2; addr++) {
116723a1cceaSRoger A. Faulkner 		getaline(*addr);
11687c478bd9Sstevel@tonic-gate 		pline(lineno(addr));
11697c478bd9Sstevel@tonic-gate 		if (inopen)
11707c478bd9Sstevel@tonic-gate 			putchar((int)('\n' | QUOTE));
11717c478bd9Sstevel@tonic-gate 		if (movedot)
11727c478bd9Sstevel@tonic-gate 			dot = addr;
11737c478bd9Sstevel@tonic-gate 	}
11747c478bd9Sstevel@tonic-gate }
11757c478bd9Sstevel@tonic-gate 
1176f6db9f27Scf46844 void
1177f6db9f27Scf46844 pofix(void)
11787c478bd9Sstevel@tonic-gate {
11797c478bd9Sstevel@tonic-gate 
11807c478bd9Sstevel@tonic-gate 	if (inopen && Outchar != termchar) {
11817c478bd9Sstevel@tonic-gate 		vnfl();
11827c478bd9Sstevel@tonic-gate 		setoutt();
11837c478bd9Sstevel@tonic-gate 	}
11847c478bd9Sstevel@tonic-gate }
11857c478bd9Sstevel@tonic-gate 
11867c478bd9Sstevel@tonic-gate /*
11877c478bd9Sstevel@tonic-gate  * Command level undo works easily because
11887c478bd9Sstevel@tonic-gate  * the editor has a unique temporary file
11897c478bd9Sstevel@tonic-gate  * index for every line which ever existed.
11907c478bd9Sstevel@tonic-gate  * We don't have to save large blocks of text,
11917c478bd9Sstevel@tonic-gate  * only the indices which are small.  We do this
11927c478bd9Sstevel@tonic-gate  * by moving them to after the last line in the
11937c478bd9Sstevel@tonic-gate  * line buffer array, and marking down info
11947c478bd9Sstevel@tonic-gate  * about whence they came.
11957c478bd9Sstevel@tonic-gate  *
11967c478bd9Sstevel@tonic-gate  * Undo is its own inverse.
11977c478bd9Sstevel@tonic-gate  */
1198f6db9f27Scf46844 void
1199f6db9f27Scf46844 undo(bool c)
12007c478bd9Sstevel@tonic-gate {
1201f6db9f27Scf46844 	int i, k;
1202f6db9f27Scf46844 	line *jp, *kp, *j;
12037c478bd9Sstevel@tonic-gate 	line *dolp1, *newdol, *newadot;
12047c478bd9Sstevel@tonic-gate 
12057c478bd9Sstevel@tonic-gate #ifdef UNDOTRACE
12067c478bd9Sstevel@tonic-gate 	if (trace)
12077c478bd9Sstevel@tonic-gate 		vudump("before undo");
12087c478bd9Sstevel@tonic-gate #endif
12097c478bd9Sstevel@tonic-gate 	if (inglobal && inopen <= 0)
12107c478bd9Sstevel@tonic-gate 		error(value(vi_TERSE) ? gettext("Can't undo in global") :
12117c478bd9Sstevel@tonic-gate 			gettext("Can't undo in global commands"));
12127c478bd9Sstevel@tonic-gate 
12137c478bd9Sstevel@tonic-gate 	/*
12147c478bd9Sstevel@tonic-gate 	 * Unless flag indicates a forced undo, make sure
12157c478bd9Sstevel@tonic-gate 	 * there really was a change before trying to undo it.
12167c478bd9Sstevel@tonic-gate 	 */
12177c478bd9Sstevel@tonic-gate 
12187c478bd9Sstevel@tonic-gate 	if (!c)
12197c478bd9Sstevel@tonic-gate 		somechange();
12207c478bd9Sstevel@tonic-gate 
12217c478bd9Sstevel@tonic-gate 	/*
12227c478bd9Sstevel@tonic-gate 	 * Update change flags.
12237c478bd9Sstevel@tonic-gate 	 */
12247c478bd9Sstevel@tonic-gate 
12257c478bd9Sstevel@tonic-gate 	pkill[0] = pkill[1] = 0;
12267c478bd9Sstevel@tonic-gate 	change();
12277c478bd9Sstevel@tonic-gate 	if (undkind == UNDMOVE) {
12287c478bd9Sstevel@tonic-gate  		/*
12297c478bd9Sstevel@tonic-gate 		 * Command to be undone is a move command.
12307c478bd9Sstevel@tonic-gate 		 * This is handled as a special case by noting that
12317c478bd9Sstevel@tonic-gate 		 * a move "a,b m c" can be inverted by another move.
12327c478bd9Sstevel@tonic-gate 		 */
12337c478bd9Sstevel@tonic-gate 		if ((i = (jp = unddel) - undap2) > 0) {
12347c478bd9Sstevel@tonic-gate 			/*
12357c478bd9Sstevel@tonic-gate 			 * when c > b inverse is a+(c-b),c m a-1
12367c478bd9Sstevel@tonic-gate 			 */
12377c478bd9Sstevel@tonic-gate 			addr2 = jp;
12387c478bd9Sstevel@tonic-gate 			addr1 = (jp = undap1) + i;
12397c478bd9Sstevel@tonic-gate 			unddel = jp-1;
12407c478bd9Sstevel@tonic-gate 		} else {
12417c478bd9Sstevel@tonic-gate 			/*
12427c478bd9Sstevel@tonic-gate 			 * when b > c inverse is  c+1,c+1+(b-a) m b
12437c478bd9Sstevel@tonic-gate 			 */
12447c478bd9Sstevel@tonic-gate 			addr1 = ++jp;
12457c478bd9Sstevel@tonic-gate 			addr2 = jp + ((unddel = undap2) - undap1);
12467c478bd9Sstevel@tonic-gate 		}
12477c478bd9Sstevel@tonic-gate 		kp = undap1;
12487c478bd9Sstevel@tonic-gate 		move1(0, unddel);
12497c478bd9Sstevel@tonic-gate 		dot = kp;
12507c478bd9Sstevel@tonic-gate 		Command = (unsigned char *)"move";
12517c478bd9Sstevel@tonic-gate 		killed();
12527c478bd9Sstevel@tonic-gate 	} else {
12537c478bd9Sstevel@tonic-gate 		int cnt;
12547c478bd9Sstevel@tonic-gate 
12557c478bd9Sstevel@tonic-gate 		newadot = dot;
12567c478bd9Sstevel@tonic-gate 		cnt = lineDOL();
12577c478bd9Sstevel@tonic-gate 		newdol = dol;
12587c478bd9Sstevel@tonic-gate 		dolp1 = dol + 1;
12597c478bd9Sstevel@tonic-gate 		/*
12607c478bd9Sstevel@tonic-gate 		 * Command to be undone is a non-move.
12617c478bd9Sstevel@tonic-gate 		 * All such commands are treated as a combination of
12627c478bd9Sstevel@tonic-gate 		 * a delete command and a append command.
12637c478bd9Sstevel@tonic-gate 		 * We first move the lines appended by the last command
12647c478bd9Sstevel@tonic-gate 		 * from undap1 to undap2-1 so that they are just before the
12657c478bd9Sstevel@tonic-gate 		 * saved deleted lines.
12667c478bd9Sstevel@tonic-gate 		 *
12677c478bd9Sstevel@tonic-gate 		 * Assume the editor has:
12687c478bd9Sstevel@tonic-gate 		 *
12697c478bd9Sstevel@tonic-gate 		 * 	cursor is on 'c'
12707c478bd9Sstevel@tonic-gate 		 *
12717c478bd9Sstevel@tonic-gate 		 *	(just change lines 5-8)
12727c478bd9Sstevel@tonic-gate 		 *
12737c478bd9Sstevel@tonic-gate 		 *	file is:	1) ab
12747c478bd9Sstevel@tonic-gate 		 *			2) cd
12757c478bd9Sstevel@tonic-gate 		 *			3) ef
12767c478bd9Sstevel@tonic-gate 		 *			4) gh
12777c478bd9Sstevel@tonic-gate 		 *	undap1:		5) 12
12787c478bd9Sstevel@tonic-gate 		 *			6) 34
12797c478bd9Sstevel@tonic-gate 		 *			7) 56
12807c478bd9Sstevel@tonic-gate 		 *			8) 78
12817c478bd9Sstevel@tonic-gate 		 *	undap2:		9) qr
12827c478bd9Sstevel@tonic-gate 		 *		       10) st
12837c478bd9Sstevel@tonic-gate 		 *		       11) uv
12847c478bd9Sstevel@tonic-gate 		 *		       12) wx
12857c478bd9Sstevel@tonic-gate 		 *	dol:	       13) yz
12867c478bd9Sstevel@tonic-gate 		 *
12877c478bd9Sstevel@tonic-gate 		 *	    UNDO AREA:
12887c478bd9Sstevel@tonic-gate 		 *	dol+1:		5) ij
12897c478bd9Sstevel@tonic-gate 		 *			6) kl
12907c478bd9Sstevel@tonic-gate 		 *			7) mn
12917c478bd9Sstevel@tonic-gate 		 *	unddol:		8) op
12927c478bd9Sstevel@tonic-gate 		 */
12937c478bd9Sstevel@tonic-gate 
12947c478bd9Sstevel@tonic-gate 		/*
12957c478bd9Sstevel@tonic-gate 		 * If this is a change (not a delete/put),
12967c478bd9Sstevel@tonic-gate 		 * then we must move the text between undap1 and undap2
12977c478bd9Sstevel@tonic-gate 		 * and it must not be at the bottom of the file
12987c478bd9Sstevel@tonic-gate 		 */
12997c478bd9Sstevel@tonic-gate 
13007c478bd9Sstevel@tonic-gate 		if ((i = (kp = undap2) - (jp = undap1)) > 0) {
13017c478bd9Sstevel@tonic-gate 			if (kp != dolp1) {
13027c478bd9Sstevel@tonic-gate 
13037c478bd9Sstevel@tonic-gate 		/*
13047c478bd9Sstevel@tonic-gate 		 * FILE:     LINE    INITIAL   REV1   REV2   REV3
13057c478bd9Sstevel@tonic-gate 		 *
13067c478bd9Sstevel@tonic-gate 		 *	      1)       ab	ab     ab     ab
13077c478bd9Sstevel@tonic-gate 		 *	      2)       cd       cd     cd     cd
13087c478bd9Sstevel@tonic-gate 		 *            3)       ef       ef     ef     ef
13097c478bd9Sstevel@tonic-gate 		 * unddel:    4)       gh       gh     gh     gh
13107c478bd9Sstevel@tonic-gate 		 * undap1:    5)       12       78     78     qr
13117c478bd9Sstevel@tonic-gate 		 *            6)       34       56     56     st
13127c478bd9Sstevel@tonic-gate 		 *            7)       56       34     34     uv
13137c478bd9Sstevel@tonic-gate 		 *            8)       78       12     12     wx
13147c478bd9Sstevel@tonic-gate 		 * undap2:    9)       qr       qr     yz     yz
13157c478bd9Sstevel@tonic-gate 		 *           10)       st       st     wx     12
13167c478bd9Sstevel@tonic-gate 		 *           11)       uv       uv     uv     34
13177c478bd9Sstevel@tonic-gate 		 *           12)       wx       wx     st     56
13187c478bd9Sstevel@tonic-gate 		 * dol:      13)       yz       yz     qr     78
13197c478bd9Sstevel@tonic-gate 		 *
13207c478bd9Sstevel@tonic-gate 		 *	UNDO AREA:
13217c478bd9Sstevel@tonic-gate 		 * dol+1:     5)       ij       ij     ij     ij
13227c478bd9Sstevel@tonic-gate 		 *            6)       kl       kl     kl     kl
13237c478bd9Sstevel@tonic-gate 		 *	      7)       mn       mn     mn     mn
13247c478bd9Sstevel@tonic-gate 		 * unddol:    8)       op       op     op     op
13257c478bd9Sstevel@tonic-gate 		 */
13267c478bd9Sstevel@tonic-gate 
13277c478bd9Sstevel@tonic-gate 				reverse(jp, kp);
13287c478bd9Sstevel@tonic-gate 				reverse(kp, dolp1);
13297c478bd9Sstevel@tonic-gate 				reverse(jp, dolp1);
13307c478bd9Sstevel@tonic-gate 			}
13317c478bd9Sstevel@tonic-gate 			/*
13327c478bd9Sstevel@tonic-gate 			 * Unddel, the line just before the spot where this
13337c478bd9Sstevel@tonic-gate 			 * test was deleted, may have moved. Account for
13347c478bd9Sstevel@tonic-gate 			 * this in restoration of saved deleted lines.
13357c478bd9Sstevel@tonic-gate 			 */
13367c478bd9Sstevel@tonic-gate 			if (unddel >= jp)
13377c478bd9Sstevel@tonic-gate 				unddel -= i;
13387c478bd9Sstevel@tonic-gate 
13397c478bd9Sstevel@tonic-gate 			/*
13407c478bd9Sstevel@tonic-gate 			 * The last line (dol) may have changed,
13417c478bd9Sstevel@tonic-gate 			 * account for this.
13427c478bd9Sstevel@tonic-gate 			 */
13437c478bd9Sstevel@tonic-gate 			 newdol -= i;
13447c478bd9Sstevel@tonic-gate 
13457c478bd9Sstevel@tonic-gate 			/*
13467c478bd9Sstevel@tonic-gate 			 * For the case where no lines are restored, dot
13477c478bd9Sstevel@tonic-gate 			 * is the line before the first line deleted.
13487c478bd9Sstevel@tonic-gate 			 */
13497c478bd9Sstevel@tonic-gate 			dot = jp-1;
13507c478bd9Sstevel@tonic-gate 		}
13517c478bd9Sstevel@tonic-gate 		/*
13527c478bd9Sstevel@tonic-gate 		 * Now put the deleted lines, if any, back where they were.
13537c478bd9Sstevel@tonic-gate 		 * Basic operation is: dol+1,unddol m unddel
13547c478bd9Sstevel@tonic-gate 		 */
13557c478bd9Sstevel@tonic-gate 		if (undkind == UNDPUT) {
13567c478bd9Sstevel@tonic-gate 			unddel = undap1 - 1;
13577c478bd9Sstevel@tonic-gate 			squish();
13587c478bd9Sstevel@tonic-gate 		}
13597c478bd9Sstevel@tonic-gate 
13607c478bd9Sstevel@tonic-gate 		/*
13617c478bd9Sstevel@tonic-gate 		 * Set jp to the line where deleted text is to be added.
13627c478bd9Sstevel@tonic-gate 		 */
13637c478bd9Sstevel@tonic-gate 		jp = unddel + 1;
13647c478bd9Sstevel@tonic-gate 
13657c478bd9Sstevel@tonic-gate 		/*
13667c478bd9Sstevel@tonic-gate 		 * Set kp to end of undo save area.
13677c478bd9Sstevel@tonic-gate 		 *
13687c478bd9Sstevel@tonic-gate 		 * If there is any deleted text to be added, do reverses.
13697c478bd9Sstevel@tonic-gate 		 */
13707c478bd9Sstevel@tonic-gate 
13717c478bd9Sstevel@tonic-gate 		if ((i = (kp = unddol) - dol) > 0) {
13727c478bd9Sstevel@tonic-gate 
13737c478bd9Sstevel@tonic-gate 			/*
13747c478bd9Sstevel@tonic-gate 			 * If deleted lines are not to be appended
13757c478bd9Sstevel@tonic-gate 			 * to the bottom of the file...
13767c478bd9Sstevel@tonic-gate 			 */
13777c478bd9Sstevel@tonic-gate 
13787c478bd9Sstevel@tonic-gate 			 if (jp != dolp1) {
13797c478bd9Sstevel@tonic-gate 				/*
13807c478bd9Sstevel@tonic-gate 				 * FILE:   LINE   START   REV1   REV2   REV3
13817c478bd9Sstevel@tonic-gate 				 *          1)     ab      ab     ab     ab
13827c478bd9Sstevel@tonic-gate 				 *          2)     cd      cd     cd     cd
13837c478bd9Sstevel@tonic-gate 				 *          3)     ef      ef     ef     ef
13847c478bd9Sstevel@tonic-gate 				 * unddel:  4)     gh      gh     gh     gh
13857c478bd9Sstevel@tonic-gate 				 * undap1:  5)     qr      78     78     ij
13867c478bd9Sstevel@tonic-gate 				 *          6)     st      56     56     kl
13877c478bd9Sstevel@tonic-gate 				 *          7)     uv      34     34     mn
13887c478bd9Sstevel@tonic-gate 				 *          8)     wx      12     12     op
13897c478bd9Sstevel@tonic-gate 				 * undap2:  9)     yz      yz     yz     qr
13907c478bd9Sstevel@tonic-gate 				 *         10)     12      wx     wx     st
13917c478bd9Sstevel@tonic-gate 				 *         11)     34      uv     uv     uv
13927c478bd9Sstevel@tonic-gate 				 *         12)     56      st     st     wx
13937c478bd9Sstevel@tonic-gate 				 * dol:    13)     78      qr     qr     yz
13947c478bd9Sstevel@tonic-gate 				 *
13957c478bd9Sstevel@tonic-gate 				 * UNDO AREA:
13967c478bd9Sstevel@tonic-gate 				 * dol+1:  5)      ij      ij     op     12
13977c478bd9Sstevel@tonic-gate 				 *         6)      kl      kl     mn     34
13987c478bd9Sstevel@tonic-gate 				 *         7)      mn      mn     kl     56
13997c478bd9Sstevel@tonic-gate 				 * unddol: 8)      op      op     ij     78
14007c478bd9Sstevel@tonic-gate 				 */
14017c478bd9Sstevel@tonic-gate 
14027c478bd9Sstevel@tonic-gate 				 reverse(jp, dolp1);
14037c478bd9Sstevel@tonic-gate 				reverse(dolp1, ++kp);
14047c478bd9Sstevel@tonic-gate 				reverse(jp, kp);
14057c478bd9Sstevel@tonic-gate 			}
14067c478bd9Sstevel@tonic-gate 			/*
14077c478bd9Sstevel@tonic-gate 			 * Account for possible forward motion of the target
14087c478bd9Sstevel@tonic-gate 			 * (where the deleted lines were restored) for after
14097c478bd9Sstevel@tonic-gate 			 * restoration of the deleted lines.
14107c478bd9Sstevel@tonic-gate 			 */
14117c478bd9Sstevel@tonic-gate 			if (undap1 >= jp)
14127c478bd9Sstevel@tonic-gate 				undap1 += i;
14137c478bd9Sstevel@tonic-gate 			/*
14147c478bd9Sstevel@tonic-gate 			 * Dot is the first resurrected line.
14157c478bd9Sstevel@tonic-gate 			 */
14167c478bd9Sstevel@tonic-gate 			dot = jp;
14177c478bd9Sstevel@tonic-gate 
14187c478bd9Sstevel@tonic-gate 			/*
14197c478bd9Sstevel@tonic-gate 			 * Account for a shift in the last line (dol).
14207c478bd9Sstevel@tonic-gate 			 */
14217c478bd9Sstevel@tonic-gate 
14227c478bd9Sstevel@tonic-gate 			 newdol += i;
14237c478bd9Sstevel@tonic-gate 		}
14247c478bd9Sstevel@tonic-gate 		/*
14257c478bd9Sstevel@tonic-gate 		 * Clean up so we are invertible
14267c478bd9Sstevel@tonic-gate 		 */
14277c478bd9Sstevel@tonic-gate 		unddel = undap1 - 1;
14287c478bd9Sstevel@tonic-gate 		undap1 = jp;
14297c478bd9Sstevel@tonic-gate 		undap2 = jp + i;
14307c478bd9Sstevel@tonic-gate 		dol = newdol;
14317c478bd9Sstevel@tonic-gate 		netchHAD(cnt);
14327c478bd9Sstevel@tonic-gate 		if (undkind == UNDALL) {
14337c478bd9Sstevel@tonic-gate 			dot = undadot;
14347c478bd9Sstevel@tonic-gate 			undadot = newadot;
14357c478bd9Sstevel@tonic-gate 		} else
14367c478bd9Sstevel@tonic-gate 			undkind = UNDCHANGE;
14377c478bd9Sstevel@tonic-gate  		/*
14387c478bd9Sstevel@tonic-gate  		 * Now relocate all marks for lines that were modified,
14397c478bd9Sstevel@tonic-gate  		 * since the marks point to lines whose address has
14407c478bd9Sstevel@tonic-gate  		 * been modified from the save area to the current
14417c478bd9Sstevel@tonic-gate  		 * area
14427c478bd9Sstevel@tonic-gate  		 */
14437c478bd9Sstevel@tonic-gate 
14447c478bd9Sstevel@tonic-gate  		for (j=unddol; j> dol; j--)
14457c478bd9Sstevel@tonic-gate  			for (k=0; k<=25; k++)
14467c478bd9Sstevel@tonic-gate  				if (names[k] == *(j))
14477c478bd9Sstevel@tonic-gate  					names[k]= *((undap1+(j-dolp1)) );
14487c478bd9Sstevel@tonic-gate 	}
14497c478bd9Sstevel@tonic-gate 	/*
14507c478bd9Sstevel@tonic-gate 	 * Defensive programming - after a munged undadot.
14517c478bd9Sstevel@tonic-gate 	 * Also handle empty buffer case.
14527c478bd9Sstevel@tonic-gate 	 */
14537c478bd9Sstevel@tonic-gate 	if ((dot <= zero || dot > dol) && dot != dol)
14547c478bd9Sstevel@tonic-gate 		dot = one;
14557c478bd9Sstevel@tonic-gate #ifdef UNDOTRACE
14567c478bd9Sstevel@tonic-gate 	if (trace)
14577c478bd9Sstevel@tonic-gate 		vudump("after undo");
14587c478bd9Sstevel@tonic-gate #endif
14597c478bd9Sstevel@tonic-gate }
14607c478bd9Sstevel@tonic-gate 
14617c478bd9Sstevel@tonic-gate /*
14627c478bd9Sstevel@tonic-gate  * Be (almost completely) sure there really
14637c478bd9Sstevel@tonic-gate  * was a change, before claiming to undo.
14647c478bd9Sstevel@tonic-gate  */
1465f6db9f27Scf46844 void
1466f6db9f27Scf46844 somechange(void)
14677c478bd9Sstevel@tonic-gate {
1468f6db9f27Scf46844 	line *ip, *jp;
14697c478bd9Sstevel@tonic-gate 
14707c478bd9Sstevel@tonic-gate 	switch (undkind) {
14717c478bd9Sstevel@tonic-gate 
14727c478bd9Sstevel@tonic-gate 	case UNDMOVE:
14737c478bd9Sstevel@tonic-gate 		return;
14747c478bd9Sstevel@tonic-gate 
14757c478bd9Sstevel@tonic-gate 	case UNDCHANGE:
14767c478bd9Sstevel@tonic-gate 		if (undap1 == undap2 && dol == unddol)
14777c478bd9Sstevel@tonic-gate 			break;
14787c478bd9Sstevel@tonic-gate 		return;
14797c478bd9Sstevel@tonic-gate 
14807c478bd9Sstevel@tonic-gate 	case UNDPUT:
14817c478bd9Sstevel@tonic-gate 		if (undap1 != undap2)
14827c478bd9Sstevel@tonic-gate 			return;
14837c478bd9Sstevel@tonic-gate 		break;
14847c478bd9Sstevel@tonic-gate 
14857c478bd9Sstevel@tonic-gate 	case UNDALL:
14867c478bd9Sstevel@tonic-gate 		if (unddol - dol != lineDOL())
14877c478bd9Sstevel@tonic-gate 			return;
14887c478bd9Sstevel@tonic-gate 		for (ip = one, jp = dol + 1; ip <= dol; ip++, jp++)
14897c478bd9Sstevel@tonic-gate 			if ((*ip &~ 01) != (*jp &~ 01))
14907c478bd9Sstevel@tonic-gate 				return;
14917c478bd9Sstevel@tonic-gate 		break;
14927c478bd9Sstevel@tonic-gate 
14937c478bd9Sstevel@tonic-gate 	case UNDNONE:
14947c478bd9Sstevel@tonic-gate 		error(gettext("Nothing to undo"));
14957c478bd9Sstevel@tonic-gate 	}
14967c478bd9Sstevel@tonic-gate 	error(value(vi_TERSE) ? gettext("Nothing changed") :
14977c478bd9Sstevel@tonic-gate 		gettext("Last undoable command didn't change anything"));
14987c478bd9Sstevel@tonic-gate }
14997c478bd9Sstevel@tonic-gate 
15007c478bd9Sstevel@tonic-gate /*
15017c478bd9Sstevel@tonic-gate  * Map command:
15027c478bd9Sstevel@tonic-gate  * map src dest
1503f6db9f27Scf46844  *
1504f6db9f27Scf46844  * un is true if this is unmap command
1505f6db9f27Scf46844  * ab is true if this is abbr command
15067c478bd9Sstevel@tonic-gate  */
1507f6db9f27Scf46844 void
1508f6db9f27Scf46844 mapcmd(int un, int ab)
15097c478bd9Sstevel@tonic-gate {
15107c478bd9Sstevel@tonic-gate 	unsigned char lhs[100], rhs[100];	/* max sizes resp. */
1511f6db9f27Scf46844 	unsigned char *p;
1512f6db9f27Scf46844 	int c;		/* char --> int */
15137c478bd9Sstevel@tonic-gate 	unsigned char *dname;
15147c478bd9Sstevel@tonic-gate 	struct maps *mp;	/* the map structure we are working on */
15157c478bd9Sstevel@tonic-gate 
15167c478bd9Sstevel@tonic-gate 	mp = ab ? abbrevs : exclam() ? immacs : arrows;
15177c478bd9Sstevel@tonic-gate 	if (skipend()) {
15187c478bd9Sstevel@tonic-gate 		int i;
15197c478bd9Sstevel@tonic-gate 
15207c478bd9Sstevel@tonic-gate 		/* print current mapping values */
15217c478bd9Sstevel@tonic-gate 		if (peekchar() != EOF)
15227c478bd9Sstevel@tonic-gate 			ignchar();
15237c478bd9Sstevel@tonic-gate 		if (un)
15247c478bd9Sstevel@tonic-gate 			error(gettext("Missing lhs"));
15257c478bd9Sstevel@tonic-gate 		if (inopen)
15267c478bd9Sstevel@tonic-gate 			pofix();
15277c478bd9Sstevel@tonic-gate 		for (i=0; i< MAXNOMACS && mp[i].mapto; i++)
15287c478bd9Sstevel@tonic-gate 			if (mp[i].cap) {
15297c478bd9Sstevel@tonic-gate 				lprintf("%s", mp[i].descr);
15307c478bd9Sstevel@tonic-gate 				putchar('\t');
15317c478bd9Sstevel@tonic-gate 				lprintf("%s", mp[i].cap);
15327c478bd9Sstevel@tonic-gate 				putchar('\t');
15337c478bd9Sstevel@tonic-gate 				lprintf("%s", mp[i].mapto);
15347c478bd9Sstevel@tonic-gate 				putNFL();
15357c478bd9Sstevel@tonic-gate 			}
15367c478bd9Sstevel@tonic-gate 		return;
15377c478bd9Sstevel@tonic-gate 	}
15387c478bd9Sstevel@tonic-gate 
15397c478bd9Sstevel@tonic-gate 	(void)skipwh();
15407c478bd9Sstevel@tonic-gate 	for (p=lhs; ; ) {
15417c478bd9Sstevel@tonic-gate 		c = getchar();
15427c478bd9Sstevel@tonic-gate 		if (c == CTRL('v')) {
15437c478bd9Sstevel@tonic-gate 			c = getchar();
15447c478bd9Sstevel@tonic-gate 		} else if (!un && any(c, " \t")) {
15457c478bd9Sstevel@tonic-gate 			/* End of lhs */
15467c478bd9Sstevel@tonic-gate 			break;
15477c478bd9Sstevel@tonic-gate 		} else if (endcmd(c) && c!='"') {
15487c478bd9Sstevel@tonic-gate 			ungetchar(c);
15497c478bd9Sstevel@tonic-gate 			if (un) {
15507c478bd9Sstevel@tonic-gate 				donewline();
15517c478bd9Sstevel@tonic-gate 				*p = 0;
1552f6db9f27Scf46844 				addmac(lhs, (unsigned char *)NOSTR,
1553f6db9f27Scf46844 				    (unsigned char *)NOSTR, mp);
15547c478bd9Sstevel@tonic-gate 				return;
15557c478bd9Sstevel@tonic-gate 			} else
15567c478bd9Sstevel@tonic-gate 				error(gettext("Missing rhs"));
15577c478bd9Sstevel@tonic-gate 		}
15587c478bd9Sstevel@tonic-gate 		*p++ = c;
15597c478bd9Sstevel@tonic-gate 	}
15607c478bd9Sstevel@tonic-gate 	*p = 0;
15617c478bd9Sstevel@tonic-gate 
15627c478bd9Sstevel@tonic-gate 	if (skipend())
15637c478bd9Sstevel@tonic-gate 		error(gettext("Missing rhs"));
15647c478bd9Sstevel@tonic-gate 	for (p=rhs; ; ) {
15657c478bd9Sstevel@tonic-gate 		c = getchar();
15667c478bd9Sstevel@tonic-gate 		if (c == CTRL('v')) {
15677c478bd9Sstevel@tonic-gate 			c = getchar();
15687c478bd9Sstevel@tonic-gate 		} else if (endcmd(c) && c!='"') {
15697c478bd9Sstevel@tonic-gate 			ungetchar(c);
15707c478bd9Sstevel@tonic-gate 			break;
15717c478bd9Sstevel@tonic-gate 		}
15727c478bd9Sstevel@tonic-gate 		*p++ = c;
15737c478bd9Sstevel@tonic-gate 	}
15747c478bd9Sstevel@tonic-gate 	*p = 0;
15757c478bd9Sstevel@tonic-gate 	donewline();
15767c478bd9Sstevel@tonic-gate 	/*
15777c478bd9Sstevel@tonic-gate 	 * Special hack for function keys: #1 means key f1, etc.
15787c478bd9Sstevel@tonic-gate 	 * If the terminal doesn't have function keys, we just use #1.
15797c478bd9Sstevel@tonic-gate 	 */
15807c478bd9Sstevel@tonic-gate 	if (lhs[0] == '#') {
15817c478bd9Sstevel@tonic-gate 		unsigned char *fnkey;
15827c478bd9Sstevel@tonic-gate 		unsigned char *fkey();
15837c478bd9Sstevel@tonic-gate 		unsigned char funkey[3];
15847c478bd9Sstevel@tonic-gate 
15857c478bd9Sstevel@tonic-gate 		fnkey = fkey(lhs[1] - '0');
15867c478bd9Sstevel@tonic-gate 		funkey[0] = 'f'; funkey[1] = lhs[1]; funkey[2] = 0;
15877c478bd9Sstevel@tonic-gate 		if (fnkey)
15887c478bd9Sstevel@tonic-gate 			strcpy(lhs, fnkey);
15897c478bd9Sstevel@tonic-gate 		dname = funkey;
15907c478bd9Sstevel@tonic-gate 	} else {
15917c478bd9Sstevel@tonic-gate 		dname = lhs;
15927c478bd9Sstevel@tonic-gate 	}
15937c478bd9Sstevel@tonic-gate 	addmac(lhs,rhs,dname,mp);
15947c478bd9Sstevel@tonic-gate }
15957c478bd9Sstevel@tonic-gate 
15967c478bd9Sstevel@tonic-gate /*
15977c478bd9Sstevel@tonic-gate  * Add a macro definition to those that already exist. The sequence of
15987c478bd9Sstevel@tonic-gate  * chars "src" is mapped into "dest". If src is already mapped into something
15997c478bd9Sstevel@tonic-gate  * this overrides the mapping. There is no recursion. Unmap is done by
16007c478bd9Sstevel@tonic-gate  * using NOSTR for dest.  Dname is what to show in listings.  mp is
16017c478bd9Sstevel@tonic-gate  * the structure to affect (arrows, etc).
16027c478bd9Sstevel@tonic-gate  */
1603f6db9f27Scf46844 void
1604f6db9f27Scf46844 addmac(unsigned char *src, unsigned char *dest, unsigned char *dname,
1605f6db9f27Scf46844     struct maps *mp)
16067c478bd9Sstevel@tonic-gate {
1607f6db9f27Scf46844 	int slot, zer;
16087c478bd9Sstevel@tonic-gate 
16097c478bd9Sstevel@tonic-gate #ifdef UNDOTRACE
16107c478bd9Sstevel@tonic-gate 	if (trace)
16117c478bd9Sstevel@tonic-gate 		fprintf(trace, "addmac(src='%s', dest='%s', dname='%s', mp=%x\n", src, dest, dname, mp);
16127c478bd9Sstevel@tonic-gate #endif
16137c478bd9Sstevel@tonic-gate 	if (dest && mp==arrows) {
16147c478bd9Sstevel@tonic-gate 		/*
16157c478bd9Sstevel@tonic-gate 		 * Prevent tail recursion. We really should be
16167c478bd9Sstevel@tonic-gate 		 * checking to see if src is a suffix of dest
16177c478bd9Sstevel@tonic-gate 		 * but this makes mapping involving escapes that
16187c478bd9Sstevel@tonic-gate 		 * is reasonable mess up.
16197c478bd9Sstevel@tonic-gate 		 */
16207c478bd9Sstevel@tonic-gate 		if (src[1] == 0 && src[0] == dest[strlen(dest)-1])
16217c478bd9Sstevel@tonic-gate 			error(gettext("No tail recursion"));
16227c478bd9Sstevel@tonic-gate 		/*
16237c478bd9Sstevel@tonic-gate 		 * We don't let the user rob himself of ":", and making
16247c478bd9Sstevel@tonic-gate 		 * multi char words is a bad idea so we don't allow it.
16257c478bd9Sstevel@tonic-gate 		 * Note that if user sets mapinput and maps all of return,
16267c478bd9Sstevel@tonic-gate 		 * linefeed, and escape, he can hurt himself. This is
16277c478bd9Sstevel@tonic-gate 		 * so weird I don't bother to check for it.
16287c478bd9Sstevel@tonic-gate 		 */
16297c478bd9Sstevel@tonic-gate 		if (isalpha(src[0])  && isascii(src[0]) && src[1] || any(src[0],":"))
16307c478bd9Sstevel@tonic-gate 			error(gettext("Too dangerous to map that"));
16317c478bd9Sstevel@tonic-gate 	}
16327c478bd9Sstevel@tonic-gate 	else if (dest) {
16337c478bd9Sstevel@tonic-gate 		/* check for tail recursion in input mode: fussier */
16347c478bd9Sstevel@tonic-gate 		if (eq(src, dest+strlen(dest)-strlen(src)))
16357c478bd9Sstevel@tonic-gate 			error(gettext("No tail recursion"));
16367c478bd9Sstevel@tonic-gate 	}
16377c478bd9Sstevel@tonic-gate 	/*
16387c478bd9Sstevel@tonic-gate 	 * If the src were null it would cause the dest to
16397c478bd9Sstevel@tonic-gate 	 * be mapped always forever. This is not good.
16407c478bd9Sstevel@tonic-gate 	 */
16417c478bd9Sstevel@tonic-gate 	if (src == (unsigned char *)NOSTR || src[0] == 0)
16427c478bd9Sstevel@tonic-gate 		error(gettext("Missing lhs"));
16437c478bd9Sstevel@tonic-gate 
16447c478bd9Sstevel@tonic-gate 	/* see if we already have a def for src */
16457c478bd9Sstevel@tonic-gate 	zer = -1;
16467c478bd9Sstevel@tonic-gate 	for (slot=0; slot < MAXNOMACS && mp[slot].mapto; slot++) {
16477c478bd9Sstevel@tonic-gate 		if (mp[slot].cap) {
16487c478bd9Sstevel@tonic-gate 			if (eq(src, mp[slot].cap) || eq(src, mp[slot].mapto))
16497c478bd9Sstevel@tonic-gate 				break;	/* if so, reuse slot */
16507c478bd9Sstevel@tonic-gate 		} else {
16517c478bd9Sstevel@tonic-gate 			zer = slot;	/* remember an empty slot */
16527c478bd9Sstevel@tonic-gate 		}
16537c478bd9Sstevel@tonic-gate 	}
16547c478bd9Sstevel@tonic-gate 
16557c478bd9Sstevel@tonic-gate 	if (slot >= MAXNOMACS)
16567c478bd9Sstevel@tonic-gate 		error(gettext("Too many macros"));
16577c478bd9Sstevel@tonic-gate 
16587c478bd9Sstevel@tonic-gate 	if (dest == (unsigned char *)NOSTR) {
16597c478bd9Sstevel@tonic-gate 		/* unmap */
16607c478bd9Sstevel@tonic-gate 		if (mp[slot].cap) {
16617c478bd9Sstevel@tonic-gate 			mp[slot].cap = (unsigned char *)NOSTR;
16627c478bd9Sstevel@tonic-gate 			mp[slot].descr = (unsigned char *)NOSTR;
16637c478bd9Sstevel@tonic-gate 		} else {
16647c478bd9Sstevel@tonic-gate 			error(value(vi_TERSE) ? gettext("Not mapped") :
16657c478bd9Sstevel@tonic-gate 				gettext("That macro wasn't mapped"));
16667c478bd9Sstevel@tonic-gate 		}
16677c478bd9Sstevel@tonic-gate 		return;
16687c478bd9Sstevel@tonic-gate 	}
16697c478bd9Sstevel@tonic-gate 
16707c478bd9Sstevel@tonic-gate 	/* reuse empty slot, if we found one and src isn't already defined */
16717c478bd9Sstevel@tonic-gate 	if (zer >= 0 && mp[slot].mapto == 0)
16727c478bd9Sstevel@tonic-gate 		slot = zer;
16737c478bd9Sstevel@tonic-gate 
16747c478bd9Sstevel@tonic-gate 	/* if not, append to end */
16757c478bd9Sstevel@tonic-gate 	if (msnext == 0)	/* first time */
16767c478bd9Sstevel@tonic-gate 		msnext = mapspace;
16777c478bd9Sstevel@tonic-gate 	/* Check is a bit conservative, we charge for dname even if reusing src */
16787c478bd9Sstevel@tonic-gate 	if (msnext - mapspace + strlen(dest) + strlen(src) + strlen(dname) + 3 > MAXCHARMACS)
16797c478bd9Sstevel@tonic-gate 		error(gettext("Too much macro text"));
16807c478bd9Sstevel@tonic-gate 	CP(msnext, src);
16817c478bd9Sstevel@tonic-gate 	mp[slot].cap = msnext;
16827c478bd9Sstevel@tonic-gate 	msnext += strlen(src) + 1;	/* plus 1 for null on the end */
16837c478bd9Sstevel@tonic-gate 	CP(msnext, dest);
16847c478bd9Sstevel@tonic-gate 	mp[slot].mapto = msnext;
16857c478bd9Sstevel@tonic-gate 	msnext += strlen(dest) + 1;
16867c478bd9Sstevel@tonic-gate 	if (dname) {
16877c478bd9Sstevel@tonic-gate 		CP(msnext, dname);
16887c478bd9Sstevel@tonic-gate 		mp[slot].descr = msnext;
16897c478bd9Sstevel@tonic-gate 		msnext += strlen(dname) + 1;
16907c478bd9Sstevel@tonic-gate 	} else {
16917c478bd9Sstevel@tonic-gate 		/* default descr to string user enters */
16927c478bd9Sstevel@tonic-gate 		mp[slot].descr = src;
16937c478bd9Sstevel@tonic-gate 	}
16947c478bd9Sstevel@tonic-gate }
16957c478bd9Sstevel@tonic-gate 
16967c478bd9Sstevel@tonic-gate /*
16977c478bd9Sstevel@tonic-gate  * Implements macros from command mode. c is the buffer to
16987c478bd9Sstevel@tonic-gate  * get the macro from.
16997c478bd9Sstevel@tonic-gate  */
1700f6db9f27Scf46844 void
17017c478bd9Sstevel@tonic-gate cmdmac(c)
17027c478bd9Sstevel@tonic-gate unsigned char c;
17037c478bd9Sstevel@tonic-gate {
17047c478bd9Sstevel@tonic-gate 	unsigned char macbuf[BUFSIZE];
17057c478bd9Sstevel@tonic-gate 	line *ad, *a1, *a2;
17067c478bd9Sstevel@tonic-gate 	unsigned char *oglobp;
17077c478bd9Sstevel@tonic-gate 	short pk;
17087c478bd9Sstevel@tonic-gate 	bool oinglobal;
17097c478bd9Sstevel@tonic-gate 
17107c478bd9Sstevel@tonic-gate 	lastmac = c;
17117c478bd9Sstevel@tonic-gate 	oglobp = globp;
17127c478bd9Sstevel@tonic-gate 	oinglobal = inglobal;
17137c478bd9Sstevel@tonic-gate 	pk = peekc; peekc = 0;
17147c478bd9Sstevel@tonic-gate 	if (inglobal < 2)
17157c478bd9Sstevel@tonic-gate 		inglobal = 1;
17167c478bd9Sstevel@tonic-gate 	regbuf(c, macbuf, sizeof(macbuf));
17177c478bd9Sstevel@tonic-gate 	a1 = addr1; a2 = addr2;
17187c478bd9Sstevel@tonic-gate 	for (ad=a1; ad<=a2; ad++) {
17197c478bd9Sstevel@tonic-gate 		globp = macbuf;
17207c478bd9Sstevel@tonic-gate 		dot = ad;
17217c478bd9Sstevel@tonic-gate 		commands(1,1);
17227c478bd9Sstevel@tonic-gate 	}
17237c478bd9Sstevel@tonic-gate 	globp = oglobp;
17247c478bd9Sstevel@tonic-gate 	inglobal = oinglobal;
17257c478bd9Sstevel@tonic-gate 	peekc = pk;
17267c478bd9Sstevel@tonic-gate }
17277c478bd9Sstevel@tonic-gate 
17287c478bd9Sstevel@tonic-gate unsigned char *
17297c478bd9Sstevel@tonic-gate vgetpass(prompt)
1730*6a3e8e86SRichard Lowe char *prompt;
17317c478bd9Sstevel@tonic-gate {
1732f6db9f27Scf46844 	unsigned char *p;
1733f6db9f27Scf46844 	int c;
17347c478bd9Sstevel@tonic-gate 	static unsigned char pbuf[9];
17357c478bd9Sstevel@tonic-gate 
17367c478bd9Sstevel@tonic-gate 	/* In ex mode, let the system hassle with setting no echo */
17377c478bd9Sstevel@tonic-gate 	if (!inopen)
17387c478bd9Sstevel@tonic-gate 		return (unsigned char *)getpass(prompt);
1739f6db9f27Scf46844 	viprintf("%s", prompt); flush();
17407c478bd9Sstevel@tonic-gate 	for (p=pbuf; (c = getkey())!='\n' && c!=EOF && c!='\r';) {
17417c478bd9Sstevel@tonic-gate 		if (p < &pbuf[8])
17427c478bd9Sstevel@tonic-gate 			*p++ = c;
17437c478bd9Sstevel@tonic-gate 	}
17447c478bd9Sstevel@tonic-gate 	*p = '\0';
17457c478bd9Sstevel@tonic-gate 	return(pbuf);
17467c478bd9Sstevel@tonic-gate }
17477c478bd9Sstevel@tonic-gate 
17487c478bd9Sstevel@tonic-gate 
17497c478bd9Sstevel@tonic-gate #ifdef TAG_STACK
17507c478bd9Sstevel@tonic-gate #define TSTACKSIZE 20
17517c478bd9Sstevel@tonic-gate struct tagstack {
17527c478bd9Sstevel@tonic-gate 	line *tag_line;
17537c478bd9Sstevel@tonic-gate 	char *tag_file;
17547c478bd9Sstevel@tonic-gate } tagstack[TSTACKSIZE];
17557c478bd9Sstevel@tonic-gate static int tag_depth = 0;
17567c478bd9Sstevel@tonic-gate 
17577c478bd9Sstevel@tonic-gate static char tag_buf[ 1024 ];
17587c478bd9Sstevel@tonic-gate static char *tag_end = tag_buf;
17597c478bd9Sstevel@tonic-gate 
1760f6db9f27Scf46844 void
1761f6db9f27Scf46844 savetag(char *name)	/* saves location where we are */
17627c478bd9Sstevel@tonic-gate {
17637c478bd9Sstevel@tonic-gate 	if( !value(vi_TAGSTACK) )
17647c478bd9Sstevel@tonic-gate 		return;
17657c478bd9Sstevel@tonic-gate 	if(tag_depth >= TSTACKSIZE) {
17667c478bd9Sstevel@tonic-gate 		error(gettext("Tagstack too deep."));
17677c478bd9Sstevel@tonic-gate 	}
17687c478bd9Sstevel@tonic-gate 	if( strlen( name ) + 1 + tag_end >= &tag_buf[1024]) {
17697c478bd9Sstevel@tonic-gate 		error(gettext("Too many tags."));
17707c478bd9Sstevel@tonic-gate 	}
17717c478bd9Sstevel@tonic-gate 	tagstack[tag_depth].tag_line = dot;
17727c478bd9Sstevel@tonic-gate 	tagstack[tag_depth++].tag_file = tag_end;
17737c478bd9Sstevel@tonic-gate 	while(*tag_end++ = *name++)
17747c478bd9Sstevel@tonic-gate 		;
17757c478bd9Sstevel@tonic-gate }
17767c478bd9Sstevel@tonic-gate 
17777c478bd9Sstevel@tonic-gate /*
17787c478bd9Sstevel@tonic-gate  * Undo a "savetag".
17797c478bd9Sstevel@tonic-gate  */
1780f6db9f27Scf46844 void
1781f6db9f27Scf46844 unsavetag(void)
17827c478bd9Sstevel@tonic-gate {
17837c478bd9Sstevel@tonic-gate 	if (!value(vi_TAGSTACK))
17847c478bd9Sstevel@tonic-gate 		return;
17857c478bd9Sstevel@tonic-gate 	if (tag_depth > 0)
17867c478bd9Sstevel@tonic-gate 		tag_end = tagstack[--tag_depth].tag_file;
17877c478bd9Sstevel@tonic-gate }
17887c478bd9Sstevel@tonic-gate 
1789f6db9f27Scf46844 void
17907c478bd9Sstevel@tonic-gate poptag(quick)	/* puts us back where we came from */
17917c478bd9Sstevel@tonic-gate bool quick;
17927c478bd9Sstevel@tonic-gate {
17937c478bd9Sstevel@tonic-gate 	unsigned char cmdbuf[100];
17947c478bd9Sstevel@tonic-gate 	unsigned char *oglobp;
17957c478bd9Sstevel@tonic-gate 	int d;
17967c478bd9Sstevel@tonic-gate 
17977c478bd9Sstevel@tonic-gate 	if (!value(vi_TAGSTACK)) {	/* reset the stack */
17987c478bd9Sstevel@tonic-gate 		tag_end = tag_buf;
17997c478bd9Sstevel@tonic-gate 		d = tag_depth;
18007c478bd9Sstevel@tonic-gate 		tag_depth = 0;
18017c478bd9Sstevel@tonic-gate 		if (d == 0)
18027c478bd9Sstevel@tonic-gate 			error(gettext("Tagstack not enabled."));
18037c478bd9Sstevel@tonic-gate 		else
18047c478bd9Sstevel@tonic-gate 			return;
18057c478bd9Sstevel@tonic-gate 	}
18067c478bd9Sstevel@tonic-gate 	if (!tag_depth)
18077c478bd9Sstevel@tonic-gate 		error(gettext("Tagstack empty."));
18087c478bd9Sstevel@tonic-gate 
18097c478bd9Sstevel@tonic-gate 	/* change to old file */
18107c478bd9Sstevel@tonic-gate 	if (strcmp(tagstack[tag_depth-1].tag_file, savedfile) ) {
18117c478bd9Sstevel@tonic-gate 		if (!quick) {
18127c478bd9Sstevel@tonic-gate 			ckaw();
18137c478bd9Sstevel@tonic-gate 			if (chng && dol > zero)
18147c478bd9Sstevel@tonic-gate 				error(value(vi_TERSE) ?
18157c478bd9Sstevel@tonic-gate gettext("No write") : gettext("No write since last change (:pop! overrides)"));
18167c478bd9Sstevel@tonic-gate 		}
18177c478bd9Sstevel@tonic-gate 		oglobp = globp;
18187c478bd9Sstevel@tonic-gate 		strcpy(cmdbuf, "e! ");
18197c478bd9Sstevel@tonic-gate 		strcat(cmdbuf, tagstack[tag_depth-1].tag_file);
18207c478bd9Sstevel@tonic-gate 		globp = cmdbuf;
18217c478bd9Sstevel@tonic-gate 		d = peekc; ungetchar(0);
18227c478bd9Sstevel@tonic-gate 		commands(1, 1);
18237c478bd9Sstevel@tonic-gate 		peekc = d;
18247c478bd9Sstevel@tonic-gate 		globp = oglobp;
18257c478bd9Sstevel@tonic-gate 	}
18267c478bd9Sstevel@tonic-gate 		markpr(dot);
18277c478bd9Sstevel@tonic-gate 	/* set line number */
18287c478bd9Sstevel@tonic-gate 	dot = tagstack[--tag_depth].tag_line;
18297c478bd9Sstevel@tonic-gate 	tag_end = tagstack[tag_depth].tag_file;
18307c478bd9Sstevel@tonic-gate }
18317c478bd9Sstevel@tonic-gate #endif
1832