xref: /illumos-gate/usr/src/cmd/vi/port/ex_vget.c (revision f6db9f27)
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
57c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
67c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
77c478bd9Sstevel@tonic-gate  * with the License.
87c478bd9Sstevel@tonic-gate  *
97c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate  * and limitations under the License.
137c478bd9Sstevel@tonic-gate  *
147c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate  *
207c478bd9Sstevel@tonic-gate  * CDDL HEADER END
217c478bd9Sstevel@tonic-gate  */
22*f6db9f27Scf /*
23*f6db9f27Scf  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*f6db9f27Scf  * Use is subject to license terms.
25*f6db9f27Scf  */
26*f6db9f27Scf 
277c478bd9Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
287c478bd9Sstevel@tonic-gate /*	  All Rights Reserved  	*/
297c478bd9Sstevel@tonic-gate 
307c478bd9Sstevel@tonic-gate 
317c478bd9Sstevel@tonic-gate /* Copyright (c) 1981 Regents of the University of California */
327c478bd9Sstevel@tonic-gate 
337c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
347c478bd9Sstevel@tonic-gate 
357c478bd9Sstevel@tonic-gate #include "ex.h"
367c478bd9Sstevel@tonic-gate #include "ex_tty.h"
377c478bd9Sstevel@tonic-gate #include "ex_vis.h"
387c478bd9Sstevel@tonic-gate 
397c478bd9Sstevel@tonic-gate /*
407c478bd9Sstevel@tonic-gate  * Input routines for open/visual.
417c478bd9Sstevel@tonic-gate  * We handle upper case only terminals in visual and reading from the
427c478bd9Sstevel@tonic-gate  * echo area here as well as notification on large changes
437c478bd9Sstevel@tonic-gate  * which appears in the echo area.
447c478bd9Sstevel@tonic-gate  */
457c478bd9Sstevel@tonic-gate 
467c478bd9Sstevel@tonic-gate /*
477c478bd9Sstevel@tonic-gate  * Return the key.
487c478bd9Sstevel@tonic-gate  */
49*f6db9f27Scf void
50*f6db9f27Scf ungetkey(int c)
517c478bd9Sstevel@tonic-gate {
527c478bd9Sstevel@tonic-gate 
537c478bd9Sstevel@tonic-gate 	if (Peekkey != ATTN)
547c478bd9Sstevel@tonic-gate 		Peekkey = c;
557c478bd9Sstevel@tonic-gate }
567c478bd9Sstevel@tonic-gate 
577c478bd9Sstevel@tonic-gate /*
587c478bd9Sstevel@tonic-gate  * Return a keystroke, but never a ^@.
597c478bd9Sstevel@tonic-gate  */
60*f6db9f27Scf int
61*f6db9f27Scf getkey(void)
627c478bd9Sstevel@tonic-gate {
63*f6db9f27Scf 	int c;		/* char --> int */
647c478bd9Sstevel@tonic-gate 
657c478bd9Sstevel@tonic-gate 	do {
667c478bd9Sstevel@tonic-gate 		c = getbr();
677c478bd9Sstevel@tonic-gate 		if (c==0)
68*f6db9f27Scf 			(void) beep();
697c478bd9Sstevel@tonic-gate 	} while (c == 0);
707c478bd9Sstevel@tonic-gate 	return (c);
717c478bd9Sstevel@tonic-gate }
727c478bd9Sstevel@tonic-gate 
737c478bd9Sstevel@tonic-gate /*
747c478bd9Sstevel@tonic-gate  * Tell whether next keystroke would be a ^@.
757c478bd9Sstevel@tonic-gate  */
76*f6db9f27Scf int
77*f6db9f27Scf peekbr(void)
787c478bd9Sstevel@tonic-gate {
797c478bd9Sstevel@tonic-gate 
807c478bd9Sstevel@tonic-gate 	Peekkey = getbr();
817c478bd9Sstevel@tonic-gate 	return (Peekkey == 0);
827c478bd9Sstevel@tonic-gate }
837c478bd9Sstevel@tonic-gate 
847c478bd9Sstevel@tonic-gate short	precbksl;
857c478bd9Sstevel@tonic-gate 
867c478bd9Sstevel@tonic-gate /*
877c478bd9Sstevel@tonic-gate  * Get a keystroke, including a ^@.
887c478bd9Sstevel@tonic-gate  * If an key was returned with ungetkey, that
897c478bd9Sstevel@tonic-gate  * comes back first.  Next comes unread input (e.g.
907c478bd9Sstevel@tonic-gate  * from repeating commands with .), and finally new
917c478bd9Sstevel@tonic-gate  * keystrokes.
927c478bd9Sstevel@tonic-gate  *
937c478bd9Sstevel@tonic-gate  * The hard work here is in mapping of \ escaped
947c478bd9Sstevel@tonic-gate  * characters on upper case only terminals.
957c478bd9Sstevel@tonic-gate  */
96*f6db9f27Scf int
97*f6db9f27Scf getbr(void)
987c478bd9Sstevel@tonic-gate {
997c478bd9Sstevel@tonic-gate 	unsigned char ch;
100*f6db9f27Scf 	int c, d;
101*f6db9f27Scf 	unsigned char *colp;
1027c478bd9Sstevel@tonic-gate 	int cnt;
1037c478bd9Sstevel@tonic-gate 	static unsigned char Peek2key;
1047c478bd9Sstevel@tonic-gate 	extern short slevel, ttyindes;
1057c478bd9Sstevel@tonic-gate 
1067c478bd9Sstevel@tonic-gate getATTN:
1077c478bd9Sstevel@tonic-gate 	if (Peekkey) {
1087c478bd9Sstevel@tonic-gate 		c = Peekkey;
1097c478bd9Sstevel@tonic-gate 		Peekkey = 0;
1107c478bd9Sstevel@tonic-gate 		return (c);
1117c478bd9Sstevel@tonic-gate 	}
1127c478bd9Sstevel@tonic-gate 	if (Peek2key) {
1137c478bd9Sstevel@tonic-gate 		c = Peek2key;
1147c478bd9Sstevel@tonic-gate 		Peek2key = 0;
1157c478bd9Sstevel@tonic-gate 		return (c);
1167c478bd9Sstevel@tonic-gate 	}
1177c478bd9Sstevel@tonic-gate 	if (vglobp) {
1187c478bd9Sstevel@tonic-gate 		if (*vglobp)
1197c478bd9Sstevel@tonic-gate 			return (lastvgk = *vglobp++);
1207c478bd9Sstevel@tonic-gate 		lastvgk = 0;
1217c478bd9Sstevel@tonic-gate 		return (ESCAPE);
1227c478bd9Sstevel@tonic-gate 	}
1237c478bd9Sstevel@tonic-gate 	if (vmacp) {
1247c478bd9Sstevel@tonic-gate 		if (*vmacp)
1257c478bd9Sstevel@tonic-gate 			return(*vmacp++);
1267c478bd9Sstevel@tonic-gate 		/* End of a macro or set of nested macros */
1277c478bd9Sstevel@tonic-gate 		vmacp = 0;
1287c478bd9Sstevel@tonic-gate 		if (inopen == -1)	/* don't mess up undo for esc esc */
1297c478bd9Sstevel@tonic-gate 			vundkind = VMANY;
1307c478bd9Sstevel@tonic-gate 		inopen = 1;	/* restore old setting now that macro done */
1317c478bd9Sstevel@tonic-gate 		vch_mac = VC_NOTINMAC;
1327c478bd9Sstevel@tonic-gate 	}
1337c478bd9Sstevel@tonic-gate 	flusho();
1347c478bd9Sstevel@tonic-gate again:
1357c478bd9Sstevel@tonic-gate 	if ((c=read(slevel == 0 ? 0 : ttyindes, &ch, 1)) != 1) {
1367c478bd9Sstevel@tonic-gate 		if (errno == EINTR)
1377c478bd9Sstevel@tonic-gate 			goto getATTN;
1387c478bd9Sstevel@tonic-gate 		else if (errno == EIO)
1397c478bd9Sstevel@tonic-gate 		  kill(getpid(), SIGHUP);
1407c478bd9Sstevel@tonic-gate 
1417c478bd9Sstevel@tonic-gate 		error(gettext("Input read error"));
1427c478bd9Sstevel@tonic-gate 	}
1437c478bd9Sstevel@tonic-gate 	c = ch;
1447c478bd9Sstevel@tonic-gate 	if (beehive_glitch && slevel==0 && c == ESCAPE) {
1457c478bd9Sstevel@tonic-gate 		if (read(0, &Peek2key, 1) != 1)
1467c478bd9Sstevel@tonic-gate 			goto getATTN;
1477c478bd9Sstevel@tonic-gate 		switch (Peek2key) {
1487c478bd9Sstevel@tonic-gate 		case 'C':	/* SPOW mode sometimes sends \EC for space */
1497c478bd9Sstevel@tonic-gate 			c = ' ';
1507c478bd9Sstevel@tonic-gate 			Peek2key = 0;
1517c478bd9Sstevel@tonic-gate 			break;
1527c478bd9Sstevel@tonic-gate 		case 'q':	/* f2 -> ^C */
1537c478bd9Sstevel@tonic-gate 			c = CTRL('c');
1547c478bd9Sstevel@tonic-gate 			Peek2key = 0;
1557c478bd9Sstevel@tonic-gate 			break;
1567c478bd9Sstevel@tonic-gate 		case 'p':	/* f1 -> esc */
1577c478bd9Sstevel@tonic-gate 			Peek2key = 0;
1587c478bd9Sstevel@tonic-gate 			break;
1597c478bd9Sstevel@tonic-gate 		}
1607c478bd9Sstevel@tonic-gate 	}
1617c478bd9Sstevel@tonic-gate 
1627c478bd9Sstevel@tonic-gate 	/*
1637c478bd9Sstevel@tonic-gate 	 * The algorithm here is that of the UNIX kernel.
1647c478bd9Sstevel@tonic-gate 	 * See the description in the programmers manual.
1657c478bd9Sstevel@tonic-gate 	 */
1667c478bd9Sstevel@tonic-gate 	if (UPPERCASE) {
1677c478bd9Sstevel@tonic-gate 		if (isupper(c))
1687c478bd9Sstevel@tonic-gate 			c = tolower(c);
1697c478bd9Sstevel@tonic-gate 		if (c == '\\') {
1707c478bd9Sstevel@tonic-gate 			if (precbksl < 2)
1717c478bd9Sstevel@tonic-gate 				precbksl++;
1727c478bd9Sstevel@tonic-gate 			if (precbksl == 1)
1737c478bd9Sstevel@tonic-gate 				goto again;
1747c478bd9Sstevel@tonic-gate 		} else if (precbksl) {
1757c478bd9Sstevel@tonic-gate 			d = 0;
1767c478bd9Sstevel@tonic-gate 			if (islower(c))
1777c478bd9Sstevel@tonic-gate 				d = toupper(c);
1787c478bd9Sstevel@tonic-gate 			else {
1797c478bd9Sstevel@tonic-gate 				colp = (unsigned char *)"({)}!|^~'~";
1807c478bd9Sstevel@tonic-gate 				while (d = *colp++)
1817c478bd9Sstevel@tonic-gate 					if (d == c) {
1827c478bd9Sstevel@tonic-gate 						d = *colp++;
1837c478bd9Sstevel@tonic-gate 						break;
1847c478bd9Sstevel@tonic-gate 					} else
1857c478bd9Sstevel@tonic-gate 						colp++;
1867c478bd9Sstevel@tonic-gate 			}
1877c478bd9Sstevel@tonic-gate 			if (precbksl == 2) {
1887c478bd9Sstevel@tonic-gate 				if (!d) {
1897c478bd9Sstevel@tonic-gate 					Peekkey = c;
1907c478bd9Sstevel@tonic-gate 					precbksl = 0;
1917c478bd9Sstevel@tonic-gate 					c = '\\';
1927c478bd9Sstevel@tonic-gate 				}
1937c478bd9Sstevel@tonic-gate 			} else if (d)
1947c478bd9Sstevel@tonic-gate 				c = d;
1957c478bd9Sstevel@tonic-gate 			else {
1967c478bd9Sstevel@tonic-gate 				Peekkey = c;
1977c478bd9Sstevel@tonic-gate 				precbksl = 0;
1987c478bd9Sstevel@tonic-gate 				c = '\\';
1997c478bd9Sstevel@tonic-gate 			}
2007c478bd9Sstevel@tonic-gate 		}
2017c478bd9Sstevel@tonic-gate 		if (c != '\\')
2027c478bd9Sstevel@tonic-gate 			precbksl = 0;
2037c478bd9Sstevel@tonic-gate 	}
2047c478bd9Sstevel@tonic-gate #ifdef TRACE
2057c478bd9Sstevel@tonic-gate 	if (trace) {
2067c478bd9Sstevel@tonic-gate 		if (!techoin) {
2077c478bd9Sstevel@tonic-gate 			tfixnl();
2087c478bd9Sstevel@tonic-gate 			techoin = 1;
2097c478bd9Sstevel@tonic-gate 			fprintf(trace, "*** Input: ");
2107c478bd9Sstevel@tonic-gate 		}
2117c478bd9Sstevel@tonic-gate 		tracec(c);
2127c478bd9Sstevel@tonic-gate 	}
2137c478bd9Sstevel@tonic-gate #endif
2147c478bd9Sstevel@tonic-gate 	lastvgk = 0;
2157c478bd9Sstevel@tonic-gate 	return (c);
2167c478bd9Sstevel@tonic-gate }
2177c478bd9Sstevel@tonic-gate 
2187c478bd9Sstevel@tonic-gate /*
2197c478bd9Sstevel@tonic-gate  * Get a key, but if a delete, quit or attention
2207c478bd9Sstevel@tonic-gate  * is typed return 0 so we will abort a partial command.
2217c478bd9Sstevel@tonic-gate  */
222*f6db9f27Scf int
223*f6db9f27Scf getesc(void)
2247c478bd9Sstevel@tonic-gate {
225*f6db9f27Scf 	int c;
2267c478bd9Sstevel@tonic-gate 
2277c478bd9Sstevel@tonic-gate 	c = getkey();
2287c478bd9Sstevel@tonic-gate 	switch (c) {
2297c478bd9Sstevel@tonic-gate 
2307c478bd9Sstevel@tonic-gate 	case CTRL('v'):
2317c478bd9Sstevel@tonic-gate 	case CTRL('q'):
2327c478bd9Sstevel@tonic-gate 		c = getkey();
2337c478bd9Sstevel@tonic-gate 		return (c);
2347c478bd9Sstevel@tonic-gate 
2357c478bd9Sstevel@tonic-gate 	case ATTN:
2367c478bd9Sstevel@tonic-gate 	case QUIT:
2377c478bd9Sstevel@tonic-gate 		ungetkey(c);
2387c478bd9Sstevel@tonic-gate 		return (0);
2397c478bd9Sstevel@tonic-gate 
2407c478bd9Sstevel@tonic-gate 	case ESCAPE:
2417c478bd9Sstevel@tonic-gate 		return (0);
2427c478bd9Sstevel@tonic-gate 	}
2437c478bd9Sstevel@tonic-gate 	return (c);
2447c478bd9Sstevel@tonic-gate }
2457c478bd9Sstevel@tonic-gate 
2467c478bd9Sstevel@tonic-gate /*
2477c478bd9Sstevel@tonic-gate  * Peek at the next keystroke.
2487c478bd9Sstevel@tonic-gate  */
249*f6db9f27Scf int
250*f6db9f27Scf peekkey(void)
2517c478bd9Sstevel@tonic-gate {
2527c478bd9Sstevel@tonic-gate 
2537c478bd9Sstevel@tonic-gate 	Peekkey = getkey();
2547c478bd9Sstevel@tonic-gate 	return (Peekkey);
2557c478bd9Sstevel@tonic-gate }
2567c478bd9Sstevel@tonic-gate 
2577c478bd9Sstevel@tonic-gate /*
2587c478bd9Sstevel@tonic-gate  * Read a line from the echo area, with single character prompt c.
2597c478bd9Sstevel@tonic-gate  * A return value of 1 means the user blewit or blewit away.
2607c478bd9Sstevel@tonic-gate  */
261*f6db9f27Scf int
2627c478bd9Sstevel@tonic-gate readecho(c)
2637c478bd9Sstevel@tonic-gate 	unsigned char c;
2647c478bd9Sstevel@tonic-gate {
265*f6db9f27Scf 	unsigned char *sc = cursor;
266*f6db9f27Scf 	int (*OP)();
2677c478bd9Sstevel@tonic-gate 	bool waste;
268*f6db9f27Scf 	int OPeek;
2697c478bd9Sstevel@tonic-gate 
2707c478bd9Sstevel@tonic-gate 	if (WBOT == WECHO)
2717c478bd9Sstevel@tonic-gate 		vclean();
2727c478bd9Sstevel@tonic-gate 	else
2737c478bd9Sstevel@tonic-gate 		vclrech(0);
2747c478bd9Sstevel@tonic-gate 	splitw++;
2757c478bd9Sstevel@tonic-gate 	vgoto(WECHO, 0);
2767c478bd9Sstevel@tonic-gate 	putchar(c);
2777c478bd9Sstevel@tonic-gate 	vclreol();
2787c478bd9Sstevel@tonic-gate 	vgoto(WECHO, 1);
2797c478bd9Sstevel@tonic-gate 	cursor = linebuf; linebuf[0] = 0; genbuf[0] = c;
2807c478bd9Sstevel@tonic-gate 	ixlatctl(1);
2817c478bd9Sstevel@tonic-gate 	if (peekbr()) {
2827c478bd9Sstevel@tonic-gate 		if (!INS[0] || (unsigned char)INS[128] == 0200) {
2837c478bd9Sstevel@tonic-gate 			INS[128] = 0;
2847c478bd9Sstevel@tonic-gate 			goto blewit;
2857c478bd9Sstevel@tonic-gate 		}
2867c478bd9Sstevel@tonic-gate 		vglobp = INS;
2877c478bd9Sstevel@tonic-gate 	}
2887c478bd9Sstevel@tonic-gate 	OP = Pline; Pline = normline;
2897c478bd9Sstevel@tonic-gate 	(void)vgetline(0, genbuf + 1, &waste, c);
2907c478bd9Sstevel@tonic-gate 	doomed = 0;	/* don't care about doomed characters in echo line */
2917c478bd9Sstevel@tonic-gate 	ixlatctl(0);
2927c478bd9Sstevel@tonic-gate 	if (Outchar == termchar)
2937c478bd9Sstevel@tonic-gate 		putchar('\n');
2947c478bd9Sstevel@tonic-gate 	vscrap();
2957c478bd9Sstevel@tonic-gate 	Pline = OP;
2967c478bd9Sstevel@tonic-gate 	if (Peekkey != ATTN && Peekkey != QUIT && Peekkey != CTRL('h')) {
2977c478bd9Sstevel@tonic-gate 		cursor = sc;
2987c478bd9Sstevel@tonic-gate 		vclreol();
2997c478bd9Sstevel@tonic-gate 		return (0);
3007c478bd9Sstevel@tonic-gate 	}
3017c478bd9Sstevel@tonic-gate blewit:
3027c478bd9Sstevel@tonic-gate 	OPeek = Peekkey==CTRL('h') ? 0 : Peekkey; Peekkey = 0;
3037c478bd9Sstevel@tonic-gate 	splitw = 0;
3047c478bd9Sstevel@tonic-gate 	vclean();
3057c478bd9Sstevel@tonic-gate 	vshow(dot, NOLINE);
3067c478bd9Sstevel@tonic-gate 	vnline(sc);
3077c478bd9Sstevel@tonic-gate 	Peekkey = OPeek;
3087c478bd9Sstevel@tonic-gate 	return (1);
3097c478bd9Sstevel@tonic-gate }
3107c478bd9Sstevel@tonic-gate 
3117c478bd9Sstevel@tonic-gate /*
3127c478bd9Sstevel@tonic-gate  * A complete command has been defined for
3137c478bd9Sstevel@tonic-gate  * the purposes of repeat, so copy it from
3147c478bd9Sstevel@tonic-gate  * the working to the previous command buffer.
3157c478bd9Sstevel@tonic-gate  */
316*f6db9f27Scf void
317*f6db9f27Scf setLAST(void)
3187c478bd9Sstevel@tonic-gate {
3197c478bd9Sstevel@tonic-gate 
3207c478bd9Sstevel@tonic-gate 	if (vglobp || vmacp)
3217c478bd9Sstevel@tonic-gate 		return;
3227c478bd9Sstevel@tonic-gate 	lastreg = vreg;
3237c478bd9Sstevel@tonic-gate 	lasthad = Xhadcnt;
3247c478bd9Sstevel@tonic-gate 	lastcnt = Xcnt;
3257c478bd9Sstevel@tonic-gate 	*lastcp = 0;
3267c478bd9Sstevel@tonic-gate 	CP(lastcmd, workcmd);
3277c478bd9Sstevel@tonic-gate }
3287c478bd9Sstevel@tonic-gate 
3297c478bd9Sstevel@tonic-gate /*
3307c478bd9Sstevel@tonic-gate  * Gather up some more text from an insert.
3317c478bd9Sstevel@tonic-gate  * If the insertion buffer oveflows, then destroy
3327c478bd9Sstevel@tonic-gate  * the repeatability of the insert.
3337c478bd9Sstevel@tonic-gate  */
334*f6db9f27Scf void
335*f6db9f27Scf addtext(unsigned char *cp)
3367c478bd9Sstevel@tonic-gate {
3377c478bd9Sstevel@tonic-gate 
3387c478bd9Sstevel@tonic-gate 	if (vglobp)
3397c478bd9Sstevel@tonic-gate 		return;
3407c478bd9Sstevel@tonic-gate 	addto(INS, cp);
3417c478bd9Sstevel@tonic-gate 	if ((unsigned char)INS[128] == 0200)
3427c478bd9Sstevel@tonic-gate 		lastcmd[0] = 0;
3437c478bd9Sstevel@tonic-gate }
3447c478bd9Sstevel@tonic-gate 
345*f6db9f27Scf void
346*f6db9f27Scf setDEL(void)
3477c478bd9Sstevel@tonic-gate {
3487c478bd9Sstevel@tonic-gate 
3497c478bd9Sstevel@tonic-gate 	setBUF(DEL);
3507c478bd9Sstevel@tonic-gate }
3517c478bd9Sstevel@tonic-gate 
3527c478bd9Sstevel@tonic-gate /*
3537c478bd9Sstevel@tonic-gate  * Put text from cursor upto wcursor in BUF.
3547c478bd9Sstevel@tonic-gate  */
355*f6db9f27Scf void
356*f6db9f27Scf setBUF(unsigned char *BUF)
3577c478bd9Sstevel@tonic-gate {
358*f6db9f27Scf 	int c;
359*f6db9f27Scf 	unsigned char *wp = wcursor;
3607c478bd9Sstevel@tonic-gate 
3617c478bd9Sstevel@tonic-gate 	c = *wp;
3627c478bd9Sstevel@tonic-gate 	*wp = 0;
3637c478bd9Sstevel@tonic-gate 	BUF[0] = 0;
3647c478bd9Sstevel@tonic-gate 	BUF[128] = 0;
3657c478bd9Sstevel@tonic-gate 	addto(BUF, cursor);
3667c478bd9Sstevel@tonic-gate 	*wp = c;
3677c478bd9Sstevel@tonic-gate }
3687c478bd9Sstevel@tonic-gate 
369*f6db9f27Scf void
370*f6db9f27Scf addto(unsigned char *buf, unsigned char *str)
3717c478bd9Sstevel@tonic-gate {
3727c478bd9Sstevel@tonic-gate 
3737c478bd9Sstevel@tonic-gate 	if ((unsigned char)buf[128] == 0200)
3747c478bd9Sstevel@tonic-gate 		return;
3757c478bd9Sstevel@tonic-gate 	if (strlen(buf) + strlen(str) + 1 >= VBSIZE) {
3767c478bd9Sstevel@tonic-gate 		buf[128] = 0200;
3777c478bd9Sstevel@tonic-gate 		return;
3787c478bd9Sstevel@tonic-gate 	}
3797c478bd9Sstevel@tonic-gate 	(void)strcat(buf, str);
3807c478bd9Sstevel@tonic-gate 	buf[128] = 0;
3817c478bd9Sstevel@tonic-gate }
3827c478bd9Sstevel@tonic-gate 
3837c478bd9Sstevel@tonic-gate /*
3847c478bd9Sstevel@tonic-gate  * Verbalize command name and embed it in message.
3857c478bd9Sstevel@tonic-gate  */
3867c478bd9Sstevel@tonic-gate char *
3877c478bd9Sstevel@tonic-gate verbalize(cnt, cmdstr, sgn)
3887c478bd9Sstevel@tonic-gate int cnt;
3897c478bd9Sstevel@tonic-gate char *cmdstr, *sgn;
3907c478bd9Sstevel@tonic-gate {
3917c478bd9Sstevel@tonic-gate 	if (cmdstr[0] == '\0')
3927c478bd9Sstevel@tonic-gate 		cmdstr = (char *)Command;
3937c478bd9Sstevel@tonic-gate 	if (sgn[0] == '\0') {
3947c478bd9Sstevel@tonic-gate 		switch (cmdstr[0]) {
3957c478bd9Sstevel@tonic-gate 		    case 'c':
3967c478bd9Sstevel@tonic-gate 			if (cmdstr[1] == 'h') {
397*f6db9f27Scf 				viprintf((cnt == 1) ?
398*f6db9f27Scf 				    gettext("1 line changed") :
399*f6db9f27Scf 				    gettext("%d lines changed"), cnt);
4007c478bd9Sstevel@tonic-gate 				break;
4017c478bd9Sstevel@tonic-gate 			} else if (cmdstr[1] != 'o') {
4027c478bd9Sstevel@tonic-gate 				goto Default;
4037c478bd9Sstevel@tonic-gate 			}
4047c478bd9Sstevel@tonic-gate 		    case 't':
4057c478bd9Sstevel@tonic-gate 			if (cmdstr[1] != '\0')
4067c478bd9Sstevel@tonic-gate 				goto Default;
407*f6db9f27Scf 			viprintf((cnt == 1) ? gettext("1 line copied") :
4087c478bd9Sstevel@tonic-gate 			       gettext("%d lines copied"), cnt);
4097c478bd9Sstevel@tonic-gate 			break;
4107c478bd9Sstevel@tonic-gate 		    case 'd':
411*f6db9f27Scf 			viprintf((cnt == 1) ? gettext("1 line deleted") :
4127c478bd9Sstevel@tonic-gate 			       gettext("%d lines deleted"), cnt);
4137c478bd9Sstevel@tonic-gate 			break;
4147c478bd9Sstevel@tonic-gate 		    case 'j':
415*f6db9f27Scf 			viprintf((cnt == 1) ? gettext("1 line joined") :
4167c478bd9Sstevel@tonic-gate 			       gettext("%d lines joined"), cnt);
4177c478bd9Sstevel@tonic-gate 			break;
4187c478bd9Sstevel@tonic-gate 		    case 'm':
419*f6db9f27Scf 			viprintf((cnt == 1) ? gettext("1 line moved") :
4207c478bd9Sstevel@tonic-gate 			       gettext("%d lines moved"), cnt);
4217c478bd9Sstevel@tonic-gate 			break;
4227c478bd9Sstevel@tonic-gate 		    case 'p':
423*f6db9f27Scf 			viprintf((cnt == 1) ? gettext("1 line put") :
4247c478bd9Sstevel@tonic-gate 			       gettext("%d lines put"), cnt);
4257c478bd9Sstevel@tonic-gate 			break;
4267c478bd9Sstevel@tonic-gate 		    case 'y':
427*f6db9f27Scf 			viprintf((cnt == 1) ? gettext("1 line yanked") :
4287c478bd9Sstevel@tonic-gate 			       gettext("%d lines yanked"), cnt);
4297c478bd9Sstevel@tonic-gate 			break;
4307c478bd9Sstevel@tonic-gate 		    case '>':
431*f6db9f27Scf 			viprintf((cnt == 1) ? gettext("1 line >>ed") :
4327c478bd9Sstevel@tonic-gate 			       gettext("%d lines >>ed"), cnt);
4337c478bd9Sstevel@tonic-gate 			break;
4347c478bd9Sstevel@tonic-gate 		    case '=':
435*f6db9f27Scf 			viprintf((cnt == 1) ? gettext("1 line =ed") :
4367c478bd9Sstevel@tonic-gate 			       gettext("%d lines =ed"), cnt);
4377c478bd9Sstevel@tonic-gate 			break;
4387c478bd9Sstevel@tonic-gate 		    case '<':
439*f6db9f27Scf 			viprintf((cnt == 1) ? gettext("1 line <<ed") :
4407c478bd9Sstevel@tonic-gate 			       gettext("%d lines <<ed"), cnt);
4417c478bd9Sstevel@tonic-gate 			break;
4427c478bd9Sstevel@tonic-gate 		    default:
4437c478bd9Sstevel@tonic-gate Default:
444*f6db9f27Scf 			viprintf((cnt == 1) ? gettext("1 line") :
4457c478bd9Sstevel@tonic-gate 			       gettext("%d lines"), cnt);
4467c478bd9Sstevel@tonic-gate 			break;
4477c478bd9Sstevel@tonic-gate 		}
4487c478bd9Sstevel@tonic-gate 	} else if (sgn[0] == 'm') {
449*f6db9f27Scf 		viprintf((cnt == 1) ? gettext("1 more line") :
4507c478bd9Sstevel@tonic-gate 			gettext("%d more lines"), cnt);
4517c478bd9Sstevel@tonic-gate 	} else {
452*f6db9f27Scf 		viprintf((cnt == 1) ? gettext("1 fewer line") :
4537c478bd9Sstevel@tonic-gate 			gettext("%d fewer lines"), cnt);
4547c478bd9Sstevel@tonic-gate 	}
4557c478bd9Sstevel@tonic-gate 	return (NULL);
4567c478bd9Sstevel@tonic-gate }
4577c478bd9Sstevel@tonic-gate 
4587c478bd9Sstevel@tonic-gate /*
4597c478bd9Sstevel@tonic-gate  * Note a change affecting a lot of lines, or non-visible
4607c478bd9Sstevel@tonic-gate  * lines.  If the parameter must is set, then we only want
4617c478bd9Sstevel@tonic-gate  * to do this for open modes now; return and save for later
4627c478bd9Sstevel@tonic-gate  * notification in visual.
4637c478bd9Sstevel@tonic-gate  */
464*f6db9f27Scf int
4657c478bd9Sstevel@tonic-gate noteit(must)
4667c478bd9Sstevel@tonic-gate 	bool must;
4677c478bd9Sstevel@tonic-gate {
468*f6db9f27Scf 	int sdl = destline, sdc = destcol;
4697c478bd9Sstevel@tonic-gate 
4707c478bd9Sstevel@tonic-gate 	if (notecnt < 1 || !must && state == VISUAL)
4717c478bd9Sstevel@tonic-gate 		return (0);
4727c478bd9Sstevel@tonic-gate 	splitw++;
4737c478bd9Sstevel@tonic-gate 	if (WBOT == WECHO)
4747c478bd9Sstevel@tonic-gate 		vmoveitup(1, 1);
4757c478bd9Sstevel@tonic-gate 	vigoto(WECHO, 0);
4767c478bd9Sstevel@tonic-gate 
4777c478bd9Sstevel@tonic-gate 	verbalize(notecnt, notenam, notesgn);
4787c478bd9Sstevel@tonic-gate 	vclreol();
4797c478bd9Sstevel@tonic-gate 	notecnt = 0;
4807c478bd9Sstevel@tonic-gate 	if (state != VISUAL)
4817c478bd9Sstevel@tonic-gate 		vcnt = vcline = 0;
4827c478bd9Sstevel@tonic-gate 	splitw = 0;
4837c478bd9Sstevel@tonic-gate 	if (state == ONEOPEN || state == CRTOPEN)
4847c478bd9Sstevel@tonic-gate 		vup1();
4857c478bd9Sstevel@tonic-gate 	destline = sdl; destcol = sdc;
4867c478bd9Sstevel@tonic-gate 	return (1);
4877c478bd9Sstevel@tonic-gate }
4887c478bd9Sstevel@tonic-gate 
4897c478bd9Sstevel@tonic-gate /*
4907c478bd9Sstevel@tonic-gate  * Ring or beep.
4917c478bd9Sstevel@tonic-gate  * If possible, flash screen.
4927c478bd9Sstevel@tonic-gate  */
493*f6db9f27Scf int
494*f6db9f27Scf beep(void)
4957c478bd9Sstevel@tonic-gate {
4967c478bd9Sstevel@tonic-gate 
4977c478bd9Sstevel@tonic-gate 	if (flash_screen && value(vi_FLASH))
4987c478bd9Sstevel@tonic-gate 		vputp(flash_screen, 0);
4997c478bd9Sstevel@tonic-gate 	else if (bell)
5007c478bd9Sstevel@tonic-gate 		vputp(bell, 0);
501*f6db9f27Scf 	return (0);
5027c478bd9Sstevel@tonic-gate }
5037c478bd9Sstevel@tonic-gate 
5047c478bd9Sstevel@tonic-gate /*
5057c478bd9Sstevel@tonic-gate  * Map the command input character c,
5067c478bd9Sstevel@tonic-gate  * for keypads and labelled keys which do cursor
5077c478bd9Sstevel@tonic-gate  * motions.  I.e. on an adm3a we might map ^K to ^P.
5087c478bd9Sstevel@tonic-gate  * DM1520 for example has a lot of mappable characters.
5097c478bd9Sstevel@tonic-gate  */
5107c478bd9Sstevel@tonic-gate 
511*f6db9f27Scf int
512*f6db9f27Scf map(c, maps, commch)
513*f6db9f27Scf 	int c;
514*f6db9f27Scf 	struct maps *maps;
515*f6db9f27Scf 	unsigned char commch; /* indicate if in append/insert/replace mode */
5167c478bd9Sstevel@tonic-gate {
517*f6db9f27Scf 	int d;
518*f6db9f27Scf 	unsigned char *p, *q;
5197c478bd9Sstevel@tonic-gate 	unsigned char b[10];	/* Assumption: no keypad sends string longer than 10 */
5207c478bd9Sstevel@tonic-gate 	unsigned char *st;
5217c478bd9Sstevel@tonic-gate 
5227c478bd9Sstevel@tonic-gate 	/*
5237c478bd9Sstevel@tonic-gate 	 * Mapping for special keys on the terminal only.
5247c478bd9Sstevel@tonic-gate 	 * BUG: if there's a long sequence and it matches
5257c478bd9Sstevel@tonic-gate 	 * some chars and then misses, we lose some chars.
5267c478bd9Sstevel@tonic-gate 	 *
5277c478bd9Sstevel@tonic-gate 	 * For this to work, some conditions must be met.
5287c478bd9Sstevel@tonic-gate 	 * 1) Keypad sends SHORT (2 or 3 char) strings
5297c478bd9Sstevel@tonic-gate 	 * 2) All strings sent are same length & similar
5307c478bd9Sstevel@tonic-gate 	 * 3) The user is unlikely to type the first few chars of
5317c478bd9Sstevel@tonic-gate 	 *    one of these strings very fast.
5327c478bd9Sstevel@tonic-gate 	 * Note: some code has been fixed up since the above was laid out,
5337c478bd9Sstevel@tonic-gate 	 * so conditions 1 & 2 are probably not required anymore.
5347c478bd9Sstevel@tonic-gate 	 * However, this hasn't been tested with any first char
5357c478bd9Sstevel@tonic-gate 	 * that means anything else except escape.
5367c478bd9Sstevel@tonic-gate 	 */
5377c478bd9Sstevel@tonic-gate #ifdef MDEBUG
5387c478bd9Sstevel@tonic-gate 	if (trace)
5397c478bd9Sstevel@tonic-gate 		fprintf(trace,"map(%c): ",c);
5407c478bd9Sstevel@tonic-gate #endif
5417c478bd9Sstevel@tonic-gate 	/*
5427c478bd9Sstevel@tonic-gate 	 * If c==0, the char came from getesc typing escape.  Pass it through
5437c478bd9Sstevel@tonic-gate 	 * unchanged.  0 messes up the following code anyway.
5447c478bd9Sstevel@tonic-gate 	 */
5457c478bd9Sstevel@tonic-gate 	if (c==0)
5467c478bd9Sstevel@tonic-gate 		return(0);
5477c478bd9Sstevel@tonic-gate 
5487c478bd9Sstevel@tonic-gate 	b[0] = c;
5497c478bd9Sstevel@tonic-gate 	b[1] = 0;
5507c478bd9Sstevel@tonic-gate 	for (d=0; d < MAXNOMACS && maps[d].mapto; d++) {
5517c478bd9Sstevel@tonic-gate #ifdef MDEBUG
5527c478bd9Sstevel@tonic-gate 		if (trace)
5537c478bd9Sstevel@tonic-gate 			fprintf(trace,"\ntry '%s', ",maps[d].cap);
5547c478bd9Sstevel@tonic-gate #endif
5557c478bd9Sstevel@tonic-gate 		if (p = maps[d].cap) {
5567c478bd9Sstevel@tonic-gate 			for (q=b; *p; p++, q++) {
5577c478bd9Sstevel@tonic-gate #ifdef MDEBUG
5587c478bd9Sstevel@tonic-gate 				if (trace)
5597c478bd9Sstevel@tonic-gate 					fprintf(trace,"q->b[%d], ",q-b);
5607c478bd9Sstevel@tonic-gate #endif
5617c478bd9Sstevel@tonic-gate 				if (*q==0) {
5627c478bd9Sstevel@tonic-gate 					/*
5637c478bd9Sstevel@tonic-gate 					 * Is there another char waiting?
5647c478bd9Sstevel@tonic-gate 					 *
5657c478bd9Sstevel@tonic-gate 					 * This test is oversimplified, but
5667c478bd9Sstevel@tonic-gate 					 * should work mostly. It handles the
5677c478bd9Sstevel@tonic-gate 					 * case where we get an ESCAPE that
5687c478bd9Sstevel@tonic-gate 					 * wasn't part of a keypad string.
5697c478bd9Sstevel@tonic-gate 					 */
5707c478bd9Sstevel@tonic-gate 					if ((c=='#' ? peekkey() : fastpeekkey()) == 0) {
5717c478bd9Sstevel@tonic-gate #ifdef MDEBUG
5727c478bd9Sstevel@tonic-gate 						if (trace)
5737c478bd9Sstevel@tonic-gate 							fprintf(trace,"fpk=0: will return '%c'",c);
5747c478bd9Sstevel@tonic-gate #endif
5757c478bd9Sstevel@tonic-gate 						/*
5767c478bd9Sstevel@tonic-gate 						 * Nothing waiting.  Push back
5777c478bd9Sstevel@tonic-gate 						 * what we peeked at & return
5787c478bd9Sstevel@tonic-gate 						 * failure (c).
5797c478bd9Sstevel@tonic-gate 						 *
5807c478bd9Sstevel@tonic-gate 						 * We want to be able to undo
5817c478bd9Sstevel@tonic-gate 						 * commands, but it's nonsense
5827c478bd9Sstevel@tonic-gate 						 * to undo part of an insertion
5837c478bd9Sstevel@tonic-gate 						 * so if in input mode don't.
5847c478bd9Sstevel@tonic-gate 						 */
5857c478bd9Sstevel@tonic-gate #ifdef MDEBUG
5867c478bd9Sstevel@tonic-gate 						if (trace)
5877c478bd9Sstevel@tonic-gate 							fprintf(trace, "Call macpush, b %d %d %d\n", b[0], b[1], b[2]);
5887c478bd9Sstevel@tonic-gate #endif
5897c478bd9Sstevel@tonic-gate 						macpush(&b[1],maps == arrows);
5907c478bd9Sstevel@tonic-gate #ifdef MDEBUG
5917c478bd9Sstevel@tonic-gate 						if (trace)
5927c478bd9Sstevel@tonic-gate 							fprintf(trace, "return %d\n", c);
5937c478bd9Sstevel@tonic-gate #endif
5947c478bd9Sstevel@tonic-gate 						return(c);
5957c478bd9Sstevel@tonic-gate 					}
5967c478bd9Sstevel@tonic-gate 					*q = getkey();
5977c478bd9Sstevel@tonic-gate 					q[1] = 0;
5987c478bd9Sstevel@tonic-gate 				}
5997c478bd9Sstevel@tonic-gate 				if (*p != *q)
6007c478bd9Sstevel@tonic-gate 					goto contin;
6017c478bd9Sstevel@tonic-gate 			}
6027c478bd9Sstevel@tonic-gate 			macpush(maps[d].mapto,maps == arrows);
6037c478bd9Sstevel@tonic-gate 			/*
6047c478bd9Sstevel@tonic-gate 			 * For all macros performed within insert,
6057c478bd9Sstevel@tonic-gate 			 * append, or replacement mode, we must end
6067c478bd9Sstevel@tonic-gate 			 * up returning back to that mode when we
6077c478bd9Sstevel@tonic-gate 			 * return (except that append will become
6087c478bd9Sstevel@tonic-gate 			 * insert for <home> key, so cursor is not
6097c478bd9Sstevel@tonic-gate 			 * in second column).
6107c478bd9Sstevel@tonic-gate 			 *
6117c478bd9Sstevel@tonic-gate 			 * In order to preserve backward movement
6127c478bd9Sstevel@tonic-gate 			 * when leaving insert mode, an 'l' must be
6137c478bd9Sstevel@tonic-gate 			 * done to compensate for the left done by
6147c478bd9Sstevel@tonic-gate 			 * the <esc> (except when cursor is already
6157c478bd9Sstevel@tonic-gate 			 * in the first column: i.e., outcol = 0).
6167c478bd9Sstevel@tonic-gate 			 */
6177c478bd9Sstevel@tonic-gate 			 if ((maps == immacs)
6187c478bd9Sstevel@tonic-gate 			 && strcmp(maps[d].descr, maps[d].cap)) {
6197c478bd9Sstevel@tonic-gate 				switch (commch) {
6207c478bd9Sstevel@tonic-gate 				  case 'R':
6217c478bd9Sstevel@tonic-gate 					if (!strcmp(maps[d].descr, "home"))
6227c478bd9Sstevel@tonic-gate 						st = (unsigned char *)"R";
6237c478bd9Sstevel@tonic-gate 					else
6247c478bd9Sstevel@tonic-gate 						if (outcol == 0)
6257c478bd9Sstevel@tonic-gate 							st = (unsigned char *)"R";
6267c478bd9Sstevel@tonic-gate 						else
6277c478bd9Sstevel@tonic-gate 							st = (unsigned char *)"lR";
6287c478bd9Sstevel@tonic-gate 					break;
6297c478bd9Sstevel@tonic-gate 				  case 'i':
6307c478bd9Sstevel@tonic-gate 					if (!strcmp(maps[d].descr, "home"))
6317c478bd9Sstevel@tonic-gate 						st = (unsigned char *)"i";
6327c478bd9Sstevel@tonic-gate 					else
6337c478bd9Sstevel@tonic-gate 						if (outcol == 0)
6347c478bd9Sstevel@tonic-gate 							st = (unsigned char *)"i";
6357c478bd9Sstevel@tonic-gate 						else
6367c478bd9Sstevel@tonic-gate 							st = (unsigned char *)"li";
6377c478bd9Sstevel@tonic-gate 					break;
6387c478bd9Sstevel@tonic-gate 				  case 'a':
6397c478bd9Sstevel@tonic-gate 					if (!strcmp(maps[d].descr, "home"))
6407c478bd9Sstevel@tonic-gate 						st = (unsigned char *)"i";
6417c478bd9Sstevel@tonic-gate 					else
6427c478bd9Sstevel@tonic-gate 						st = (unsigned char *)"a";
6437c478bd9Sstevel@tonic-gate 					break;
6447c478bd9Sstevel@tonic-gate 				  default:
6457c478bd9Sstevel@tonic-gate 					st = (unsigned char *)"i";
6467c478bd9Sstevel@tonic-gate 				}
6477c478bd9Sstevel@tonic-gate 				if(strlen(vmacbuf)  + strlen(st) > BUFSIZE)
6487c478bd9Sstevel@tonic-gate 					error(value(vi_TERSE) ?
6497c478bd9Sstevel@tonic-gate gettext("Macro too long") : gettext("Macro too long  - maybe recursive?"));
6507c478bd9Sstevel@tonic-gate 				else
6517c478bd9Sstevel@tonic-gate 					/*
6527c478bd9Sstevel@tonic-gate 					 * Macros such as function keys are
6537c478bd9Sstevel@tonic-gate 					 * performed by leaving the insert,
6547c478bd9Sstevel@tonic-gate 					 * replace, or append mode, executing
6557c478bd9Sstevel@tonic-gate 					 * the proper cursor movement commands
6567c478bd9Sstevel@tonic-gate 					 * and returning to the mode we are
6577c478bd9Sstevel@tonic-gate 					 * currently in (commch).
6587c478bd9Sstevel@tonic-gate 					 */
6597c478bd9Sstevel@tonic-gate 					strcat(vmacbuf, st);
6607c478bd9Sstevel@tonic-gate 			}
6617c478bd9Sstevel@tonic-gate 			c = getkey();
6627c478bd9Sstevel@tonic-gate #ifdef MDEBUG
6637c478bd9Sstevel@tonic-gate 			if (trace)
6647c478bd9Sstevel@tonic-gate 				fprintf(trace,"Success: push(%s), return %c",maps[d].mapto, c);
6657c478bd9Sstevel@tonic-gate #endif
6667c478bd9Sstevel@tonic-gate 			return(c);	/* first char of map string */
6677c478bd9Sstevel@tonic-gate 			contin:;
6687c478bd9Sstevel@tonic-gate 		}
6697c478bd9Sstevel@tonic-gate 	}
6707c478bd9Sstevel@tonic-gate #ifdef MDEBUG
6717c478bd9Sstevel@tonic-gate 	if (trace)
6727c478bd9Sstevel@tonic-gate 		fprintf(trace,"Fail: push(%s), return %c", &b[1], c);
6737c478bd9Sstevel@tonic-gate #endif
6747c478bd9Sstevel@tonic-gate 	macpush(&b[1],0);
6757c478bd9Sstevel@tonic-gate 	return(c);
6767c478bd9Sstevel@tonic-gate }
6777c478bd9Sstevel@tonic-gate 
6787c478bd9Sstevel@tonic-gate /*
6797c478bd9Sstevel@tonic-gate  * Push st onto the front of vmacp. This is tricky because we have to
6807c478bd9Sstevel@tonic-gate  * worry about where vmacp was previously pointing. We also have to
6817c478bd9Sstevel@tonic-gate  * check for overflow (which is typically from a recursive macro)
6827c478bd9Sstevel@tonic-gate  * Finally we have to set a flag so the whole thing can be undone.
6837c478bd9Sstevel@tonic-gate  * canundo is 1 iff we want to be able to undo the macro.  This
6847c478bd9Sstevel@tonic-gate  * is false for, for example, pushing back lookahead from fastpeekkey(),
6857c478bd9Sstevel@tonic-gate  * since otherwise two fast escapes can clobber our undo.
6867c478bd9Sstevel@tonic-gate  */
687*f6db9f27Scf void
688*f6db9f27Scf macpush(unsigned char *st, int canundo)
6897c478bd9Sstevel@tonic-gate {
6907c478bd9Sstevel@tonic-gate 	unsigned char tmpbuf[BUFSIZE];
6917c478bd9Sstevel@tonic-gate 
6927c478bd9Sstevel@tonic-gate 	if (st==0 || *st==0)
6937c478bd9Sstevel@tonic-gate 		return;
6947c478bd9Sstevel@tonic-gate #ifdef MDEBUG
6957c478bd9Sstevel@tonic-gate 	if (trace)
6967c478bd9Sstevel@tonic-gate 		fprintf(trace, "macpush(%s), canundo=%d\n",st,canundo);
6977c478bd9Sstevel@tonic-gate #endif
6987c478bd9Sstevel@tonic-gate 	if ((vmacp ? strlen(vmacp) : 0) + strlen(st) > BUFSIZE)
6997c478bd9Sstevel@tonic-gate 		error(value(vi_TERSE) ? gettext("Macro too long") :
7007c478bd9Sstevel@tonic-gate gettext("Macro too long  - maybe recursive?"));
7017c478bd9Sstevel@tonic-gate 	if (vmacp) {
7027c478bd9Sstevel@tonic-gate 		strcpy(tmpbuf, vmacp);
7037c478bd9Sstevel@tonic-gate 		if (!FIXUNDO)
7047c478bd9Sstevel@tonic-gate 			canundo = 0;	/* can't undo inside a macro anyway */
7057c478bd9Sstevel@tonic-gate 	}
7067c478bd9Sstevel@tonic-gate 	strcpy(vmacbuf, st);
7077c478bd9Sstevel@tonic-gate 	if (vmacp)
7087c478bd9Sstevel@tonic-gate 		strcat(vmacbuf, tmpbuf);
7097c478bd9Sstevel@tonic-gate 	vmacp = vmacbuf;
7107c478bd9Sstevel@tonic-gate 	/* arrange to be able to undo the whole macro */
7117c478bd9Sstevel@tonic-gate 	if (canundo) {
7127c478bd9Sstevel@tonic-gate #ifdef notdef
7137c478bd9Sstevel@tonic-gate 		otchng = tchng;
7147c478bd9Sstevel@tonic-gate 		vsave();
7157c478bd9Sstevel@tonic-gate 		saveall();
7167c478bd9Sstevel@tonic-gate 		inopen = -1;	/* no need to save since it had to be 1 or -1 before */
7177c478bd9Sstevel@tonic-gate 		vundkind = VMANY;
7187c478bd9Sstevel@tonic-gate #endif
7197c478bd9Sstevel@tonic-gate 		vch_mac = VC_NOCHANGE;
7207c478bd9Sstevel@tonic-gate 	}
7217c478bd9Sstevel@tonic-gate }
7227c478bd9Sstevel@tonic-gate 
7237c478bd9Sstevel@tonic-gate #ifdef UNDOTRACE
7247c478bd9Sstevel@tonic-gate visdump(s)
7257c478bd9Sstevel@tonic-gate unsigned char *s;
7267c478bd9Sstevel@tonic-gate {
727*f6db9f27Scf 	int i;
7287c478bd9Sstevel@tonic-gate 
7297c478bd9Sstevel@tonic-gate 	if (!trace) return;
7307c478bd9Sstevel@tonic-gate 
7317c478bd9Sstevel@tonic-gate 	fprintf(trace, "\n%s: basWTOP=%d, basWLINES=%d, WTOP=%d, WBOT=%d, WLINES=%d, WCOLS=%d, WECHO=%d\n",
7327c478bd9Sstevel@tonic-gate 		s, basWTOP, basWLINES, WTOP, WBOT, WLINES, WCOLS, WECHO);
7337c478bd9Sstevel@tonic-gate 	fprintf(trace, "   vcnt=%d, vcline=%d, cursor=%d, wcursor=%d, wdot=%d\n",
7347c478bd9Sstevel@tonic-gate 		vcnt, vcline, cursor-linebuf, wcursor-linebuf, wdot-zero);
7357c478bd9Sstevel@tonic-gate 	for (i=0; i<TUBELINES; i++)
7367c478bd9Sstevel@tonic-gate 		if (vtube[i] && *vtube[i])
7377c478bd9Sstevel@tonic-gate 			fprintf(trace, "%d: '%s'\n", i, vtube[i]);
7387c478bd9Sstevel@tonic-gate 	tvliny();
7397c478bd9Sstevel@tonic-gate }
7407c478bd9Sstevel@tonic-gate 
7417c478bd9Sstevel@tonic-gate vudump(s)
7427c478bd9Sstevel@tonic-gate unsigned char *s;
7437c478bd9Sstevel@tonic-gate {
744*f6db9f27Scf 	line *p;
7457c478bd9Sstevel@tonic-gate 	unsigned char savelb[1024];
7467c478bd9Sstevel@tonic-gate 
7477c478bd9Sstevel@tonic-gate 	if (!trace) return;
7487c478bd9Sstevel@tonic-gate 
7497c478bd9Sstevel@tonic-gate 	fprintf(trace, "\n%s: undkind=%d, vundkind=%d, unddel=%d, undap1=%d, undap2=%d,\n",
7507c478bd9Sstevel@tonic-gate 		s, undkind, vundkind, lineno(unddel), lineno(undap1), lineno(undap2));
7517c478bd9Sstevel@tonic-gate 	fprintf(trace, "  undadot=%d, dot=%d, dol=%d, unddol=%d, truedol=%d\n",
7527c478bd9Sstevel@tonic-gate 		lineno(undadot), lineno(dot), lineno(dol), lineno(unddol), lineno(truedol));
7537c478bd9Sstevel@tonic-gate 	fprintf(trace, "  [\n");
7547c478bd9Sstevel@tonic-gate 	CP(savelb, linebuf);
7557c478bd9Sstevel@tonic-gate 	fprintf(trace, "linebuf = '%s'\n", linebuf);
7567c478bd9Sstevel@tonic-gate 	for (p=zero+1; p<=truedol; p++) {
7577c478bd9Sstevel@tonic-gate 		fprintf(trace, "%o ", *p);
7587c478bd9Sstevel@tonic-gate 		getline(*p);
7597c478bd9Sstevel@tonic-gate 		fprintf(trace, "'%s'\n", linebuf);
7607c478bd9Sstevel@tonic-gate 	}
7617c478bd9Sstevel@tonic-gate 	fprintf(trace, "]\n");
7627c478bd9Sstevel@tonic-gate 	CP(linebuf, savelb);
7637c478bd9Sstevel@tonic-gate }
7647c478bd9Sstevel@tonic-gate #endif
7657c478bd9Sstevel@tonic-gate 
7667c478bd9Sstevel@tonic-gate /*
7677c478bd9Sstevel@tonic-gate  * Get a count from the keyed input stream.
7687c478bd9Sstevel@tonic-gate  * A zero count is indistinguishable from no count.
7697c478bd9Sstevel@tonic-gate  */
770*f6db9f27Scf int
771*f6db9f27Scf vgetcnt(void)
7727c478bd9Sstevel@tonic-gate {
773*f6db9f27Scf 	int c, cnt;
7747c478bd9Sstevel@tonic-gate 
7757c478bd9Sstevel@tonic-gate 	cnt = 0;
7767c478bd9Sstevel@tonic-gate 	for (;;) {
7777c478bd9Sstevel@tonic-gate 		c = getkey();
7787c478bd9Sstevel@tonic-gate 		if (!isdigit(c))
7797c478bd9Sstevel@tonic-gate 			break;
7807c478bd9Sstevel@tonic-gate 		cnt *= 10, cnt += c - '0';
7817c478bd9Sstevel@tonic-gate 	}
7827c478bd9Sstevel@tonic-gate 	ungetkey(c);
7837c478bd9Sstevel@tonic-gate 	Xhadcnt = 1;
7847c478bd9Sstevel@tonic-gate 	Xcnt = cnt;
7857c478bd9Sstevel@tonic-gate 	return(cnt);
7867c478bd9Sstevel@tonic-gate }
7877c478bd9Sstevel@tonic-gate 
7887c478bd9Sstevel@tonic-gate /*
7897c478bd9Sstevel@tonic-gate  * fastpeekkey is just like peekkey but insists the character come in
7907c478bd9Sstevel@tonic-gate  * fast (within 1 second). This will succeed if it is the 2nd char of
7917c478bd9Sstevel@tonic-gate  * a machine generated sequence (such as a function pad from an escape
7927c478bd9Sstevel@tonic-gate  * flavor terminal) but fail for a human hitting escape then waiting.
7937c478bd9Sstevel@tonic-gate  */
794*f6db9f27Scf int
795*f6db9f27Scf fastpeekkey(void)
7967c478bd9Sstevel@tonic-gate {
7977c478bd9Sstevel@tonic-gate 	void trapalarm();
798*f6db9f27Scf 	int c;
7997c478bd9Sstevel@tonic-gate 
8007c478bd9Sstevel@tonic-gate 	/*
8017c478bd9Sstevel@tonic-gate 	 * If the user has set notimeout, we wait forever for a key.
8027c478bd9Sstevel@tonic-gate 	 * If we are in a macro we do too, but since it's already
8037c478bd9Sstevel@tonic-gate 	 * buffered internally it will return immediately.
8047c478bd9Sstevel@tonic-gate 	 * In other cases we force this to die in 1 second.
8057c478bd9Sstevel@tonic-gate 	 * This is pretty reliable (VMUNIX rounds it to .5 - 1.5 secs,
8067c478bd9Sstevel@tonic-gate 	 * but UNIX truncates it to 0 - 1 secs) but due to system delays
8077c478bd9Sstevel@tonic-gate 	 * there are times when arrow keys or very fast typing get counted
8087c478bd9Sstevel@tonic-gate 	 * as separate.  notimeout is provided for people who dislike such
8097c478bd9Sstevel@tonic-gate 	 * nondeterminism.
8107c478bd9Sstevel@tonic-gate 	 */
8117c478bd9Sstevel@tonic-gate 	CATCH
8127c478bd9Sstevel@tonic-gate 		if (value(vi_TIMEOUT) && inopen >= 0) {
8137c478bd9Sstevel@tonic-gate 			signal(SIGALRM, trapalarm);
8147c478bd9Sstevel@tonic-gate 			setalarm();
8157c478bd9Sstevel@tonic-gate 		}
8167c478bd9Sstevel@tonic-gate 		c = peekkey();
8177c478bd9Sstevel@tonic-gate 		cancelalarm();
8187c478bd9Sstevel@tonic-gate 	ONERR
8197c478bd9Sstevel@tonic-gate 		c = 0;
8207c478bd9Sstevel@tonic-gate 	ENDCATCH
8217c478bd9Sstevel@tonic-gate 	/* Should have an alternative method based on select for 4.2BSD */
8227c478bd9Sstevel@tonic-gate 	return(c);
8237c478bd9Sstevel@tonic-gate }
8247c478bd9Sstevel@tonic-gate 
8257c478bd9Sstevel@tonic-gate static int ftfd;
8267c478bd9Sstevel@tonic-gate struct requestbuf {
8277c478bd9Sstevel@tonic-gate 	short time;
8287c478bd9Sstevel@tonic-gate 	short signo;
8297c478bd9Sstevel@tonic-gate };
8307c478bd9Sstevel@tonic-gate 
8317c478bd9Sstevel@tonic-gate /*
8327c478bd9Sstevel@tonic-gate  * Arrange for SIGALRM to come in shortly, so we don't
8337c478bd9Sstevel@tonic-gate  * hang very long if the user didn't type anything.  There are
8347c478bd9Sstevel@tonic-gate  * various ways to do this on different systems.
8357c478bd9Sstevel@tonic-gate  */
836*f6db9f27Scf void
837*f6db9f27Scf setalarm(void)
8387c478bd9Sstevel@tonic-gate {
8397c478bd9Sstevel@tonic-gate 	unsigned char ftname[20];
8407c478bd9Sstevel@tonic-gate 	struct requestbuf rb;
8417c478bd9Sstevel@tonic-gate 
8427c478bd9Sstevel@tonic-gate #ifdef FTIOCSET
8437c478bd9Sstevel@tonic-gate 	/*
8447c478bd9Sstevel@tonic-gate 	 * Use nonstandard "fast timer" to get better than
8457c478bd9Sstevel@tonic-gate 	 * one second resolution.  We must wait at least
8467c478bd9Sstevel@tonic-gate 	 * 1/15th of a second because some keypads don't
8477c478bd9Sstevel@tonic-gate 	 * transmit faster than this.
8487c478bd9Sstevel@tonic-gate 	 */
8497c478bd9Sstevel@tonic-gate 
8507c478bd9Sstevel@tonic-gate 	/* Open ft psuedo-device - we need our own copy. */
8517c478bd9Sstevel@tonic-gate 	if (ftfd == 0) {
8527c478bd9Sstevel@tonic-gate 		strcpy(ftname, "/dev/ft0");
8537c478bd9Sstevel@tonic-gate 		while (ftfd <= 0 && ftname[7] <= '~') {
8547c478bd9Sstevel@tonic-gate 			ftfd = open(ftname, 0);
8557c478bd9Sstevel@tonic-gate 			if (ftfd <= 0)
8567c478bd9Sstevel@tonic-gate 				ftname[7] ++;
8577c478bd9Sstevel@tonic-gate 		}
8587c478bd9Sstevel@tonic-gate 	}
8597c478bd9Sstevel@tonic-gate 	if (ftfd <= 0) {	/* Couldn't open a /dev/ft? */
8607c478bd9Sstevel@tonic-gate 		alarm(1);
8617c478bd9Sstevel@tonic-gate 	} else {
8627c478bd9Sstevel@tonic-gate 		rb.time = 6;	/* 6 ticks = 100 ms > 67 ms. */
8637c478bd9Sstevel@tonic-gate 		rb.signo = SIGALRM;
8647c478bd9Sstevel@tonic-gate 		ioctl(ftfd, FTIOCSET, &rb);
8657c478bd9Sstevel@tonic-gate 	}
8667c478bd9Sstevel@tonic-gate #else
8677c478bd9Sstevel@tonic-gate 	/*
8687c478bd9Sstevel@tonic-gate 	 * No special capabilities, so we use alarm, with 1 sec. resolution.
8697c478bd9Sstevel@tonic-gate 	 */
8707c478bd9Sstevel@tonic-gate 	alarm(1);
8717c478bd9Sstevel@tonic-gate #endif
8727c478bd9Sstevel@tonic-gate }
8737c478bd9Sstevel@tonic-gate 
8747c478bd9Sstevel@tonic-gate /*
8757c478bd9Sstevel@tonic-gate  * Get rid of any impending incoming SIGALRM.
8767c478bd9Sstevel@tonic-gate  */
877*f6db9f27Scf void
878*f6db9f27Scf cancelalarm(void)
8797c478bd9Sstevel@tonic-gate {
8807c478bd9Sstevel@tonic-gate 	struct requestbuf rb;
8817c478bd9Sstevel@tonic-gate #ifdef FTIOCSET
8827c478bd9Sstevel@tonic-gate 	if (ftfd > 0) {
8837c478bd9Sstevel@tonic-gate 		rb.time = 0;
8847c478bd9Sstevel@tonic-gate 		rb.signo = SIGALRM;
8857c478bd9Sstevel@tonic-gate 		ioctl(ftfd, FTIOCCANCEL, &rb);
8867c478bd9Sstevel@tonic-gate 	}
8877c478bd9Sstevel@tonic-gate #endif
8887c478bd9Sstevel@tonic-gate 	alarm(0);	/* Have to do this whether or not FTIOCSET */
8897c478bd9Sstevel@tonic-gate }
8907c478bd9Sstevel@tonic-gate 
8917c478bd9Sstevel@tonic-gate void trapalarm() {
8927c478bd9Sstevel@tonic-gate 	alarm(0);
8937c478bd9Sstevel@tonic-gate 	longjmp(vreslab,1);
8947c478bd9Sstevel@tonic-gate }
895