xref: /onnv-gate/usr/src/cmd/vi/port/ex_vget.c (revision 802:73b56fb6544b)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
50Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
60Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
70Sstevel@tonic-gate  * with the License.
80Sstevel@tonic-gate  *
90Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
100Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
110Sstevel@tonic-gate  * See the License for the specific language governing permissions
120Sstevel@tonic-gate  * and limitations under the License.
130Sstevel@tonic-gate  *
140Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
150Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
160Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
170Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
180Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
190Sstevel@tonic-gate  *
200Sstevel@tonic-gate  * CDDL HEADER END
210Sstevel@tonic-gate  */
22*802Scf46844 /*
23*802Scf46844  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*802Scf46844  * Use is subject to license terms.
25*802Scf46844  */
26*802Scf46844 
270Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
280Sstevel@tonic-gate /*	  All Rights Reserved  	*/
290Sstevel@tonic-gate 
300Sstevel@tonic-gate 
310Sstevel@tonic-gate /* Copyright (c) 1981 Regents of the University of California */
320Sstevel@tonic-gate 
330Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
340Sstevel@tonic-gate 
350Sstevel@tonic-gate #include "ex.h"
360Sstevel@tonic-gate #include "ex_tty.h"
370Sstevel@tonic-gate #include "ex_vis.h"
380Sstevel@tonic-gate 
390Sstevel@tonic-gate /*
400Sstevel@tonic-gate  * Input routines for open/visual.
410Sstevel@tonic-gate  * We handle upper case only terminals in visual and reading from the
420Sstevel@tonic-gate  * echo area here as well as notification on large changes
430Sstevel@tonic-gate  * which appears in the echo area.
440Sstevel@tonic-gate  */
450Sstevel@tonic-gate 
460Sstevel@tonic-gate /*
470Sstevel@tonic-gate  * Return the key.
480Sstevel@tonic-gate  */
49*802Scf46844 void
50*802Scf46844 ungetkey(int c)
510Sstevel@tonic-gate {
520Sstevel@tonic-gate 
530Sstevel@tonic-gate 	if (Peekkey != ATTN)
540Sstevel@tonic-gate 		Peekkey = c;
550Sstevel@tonic-gate }
560Sstevel@tonic-gate 
570Sstevel@tonic-gate /*
580Sstevel@tonic-gate  * Return a keystroke, but never a ^@.
590Sstevel@tonic-gate  */
60*802Scf46844 int
61*802Scf46844 getkey(void)
620Sstevel@tonic-gate {
63*802Scf46844 	int c;		/* char --> int */
640Sstevel@tonic-gate 
650Sstevel@tonic-gate 	do {
660Sstevel@tonic-gate 		c = getbr();
670Sstevel@tonic-gate 		if (c==0)
68*802Scf46844 			(void) beep();
690Sstevel@tonic-gate 	} while (c == 0);
700Sstevel@tonic-gate 	return (c);
710Sstevel@tonic-gate }
720Sstevel@tonic-gate 
730Sstevel@tonic-gate /*
740Sstevel@tonic-gate  * Tell whether next keystroke would be a ^@.
750Sstevel@tonic-gate  */
76*802Scf46844 int
77*802Scf46844 peekbr(void)
780Sstevel@tonic-gate {
790Sstevel@tonic-gate 
800Sstevel@tonic-gate 	Peekkey = getbr();
810Sstevel@tonic-gate 	return (Peekkey == 0);
820Sstevel@tonic-gate }
830Sstevel@tonic-gate 
840Sstevel@tonic-gate short	precbksl;
850Sstevel@tonic-gate 
860Sstevel@tonic-gate /*
870Sstevel@tonic-gate  * Get a keystroke, including a ^@.
880Sstevel@tonic-gate  * If an key was returned with ungetkey, that
890Sstevel@tonic-gate  * comes back first.  Next comes unread input (e.g.
900Sstevel@tonic-gate  * from repeating commands with .), and finally new
910Sstevel@tonic-gate  * keystrokes.
920Sstevel@tonic-gate  *
930Sstevel@tonic-gate  * The hard work here is in mapping of \ escaped
940Sstevel@tonic-gate  * characters on upper case only terminals.
950Sstevel@tonic-gate  */
96*802Scf46844 int
97*802Scf46844 getbr(void)
980Sstevel@tonic-gate {
990Sstevel@tonic-gate 	unsigned char ch;
100*802Scf46844 	int c, d;
101*802Scf46844 	unsigned char *colp;
1020Sstevel@tonic-gate 	int cnt;
1030Sstevel@tonic-gate 	static unsigned char Peek2key;
1040Sstevel@tonic-gate 	extern short slevel, ttyindes;
1050Sstevel@tonic-gate 
1060Sstevel@tonic-gate getATTN:
1070Sstevel@tonic-gate 	if (Peekkey) {
1080Sstevel@tonic-gate 		c = Peekkey;
1090Sstevel@tonic-gate 		Peekkey = 0;
1100Sstevel@tonic-gate 		return (c);
1110Sstevel@tonic-gate 	}
1120Sstevel@tonic-gate 	if (Peek2key) {
1130Sstevel@tonic-gate 		c = Peek2key;
1140Sstevel@tonic-gate 		Peek2key = 0;
1150Sstevel@tonic-gate 		return (c);
1160Sstevel@tonic-gate 	}
1170Sstevel@tonic-gate 	if (vglobp) {
1180Sstevel@tonic-gate 		if (*vglobp)
1190Sstevel@tonic-gate 			return (lastvgk = *vglobp++);
1200Sstevel@tonic-gate 		lastvgk = 0;
1210Sstevel@tonic-gate 		return (ESCAPE);
1220Sstevel@tonic-gate 	}
1230Sstevel@tonic-gate 	if (vmacp) {
1240Sstevel@tonic-gate 		if (*vmacp)
1250Sstevel@tonic-gate 			return(*vmacp++);
1260Sstevel@tonic-gate 		/* End of a macro or set of nested macros */
1270Sstevel@tonic-gate 		vmacp = 0;
1280Sstevel@tonic-gate 		if (inopen == -1)	/* don't mess up undo for esc esc */
1290Sstevel@tonic-gate 			vundkind = VMANY;
1300Sstevel@tonic-gate 		inopen = 1;	/* restore old setting now that macro done */
1310Sstevel@tonic-gate 		vch_mac = VC_NOTINMAC;
1320Sstevel@tonic-gate 	}
1330Sstevel@tonic-gate 	flusho();
1340Sstevel@tonic-gate again:
1350Sstevel@tonic-gate 	if ((c=read(slevel == 0 ? 0 : ttyindes, &ch, 1)) != 1) {
1360Sstevel@tonic-gate 		if (errno == EINTR)
1370Sstevel@tonic-gate 			goto getATTN;
1380Sstevel@tonic-gate 		else if (errno == EIO)
1390Sstevel@tonic-gate 		  kill(getpid(), SIGHUP);
1400Sstevel@tonic-gate 
1410Sstevel@tonic-gate 		error(gettext("Input read error"));
1420Sstevel@tonic-gate 	}
1430Sstevel@tonic-gate 	c = ch;
1440Sstevel@tonic-gate 	if (beehive_glitch && slevel==0 && c == ESCAPE) {
1450Sstevel@tonic-gate 		if (read(0, &Peek2key, 1) != 1)
1460Sstevel@tonic-gate 			goto getATTN;
1470Sstevel@tonic-gate 		switch (Peek2key) {
1480Sstevel@tonic-gate 		case 'C':	/* SPOW mode sometimes sends \EC for space */
1490Sstevel@tonic-gate 			c = ' ';
1500Sstevel@tonic-gate 			Peek2key = 0;
1510Sstevel@tonic-gate 			break;
1520Sstevel@tonic-gate 		case 'q':	/* f2 -> ^C */
1530Sstevel@tonic-gate 			c = CTRL('c');
1540Sstevel@tonic-gate 			Peek2key = 0;
1550Sstevel@tonic-gate 			break;
1560Sstevel@tonic-gate 		case 'p':	/* f1 -> esc */
1570Sstevel@tonic-gate 			Peek2key = 0;
1580Sstevel@tonic-gate 			break;
1590Sstevel@tonic-gate 		}
1600Sstevel@tonic-gate 	}
1610Sstevel@tonic-gate 
1620Sstevel@tonic-gate 	/*
1630Sstevel@tonic-gate 	 * The algorithm here is that of the UNIX kernel.
1640Sstevel@tonic-gate 	 * See the description in the programmers manual.
1650Sstevel@tonic-gate 	 */
1660Sstevel@tonic-gate 	if (UPPERCASE) {
1670Sstevel@tonic-gate 		if (isupper(c))
1680Sstevel@tonic-gate 			c = tolower(c);
1690Sstevel@tonic-gate 		if (c == '\\') {
1700Sstevel@tonic-gate 			if (precbksl < 2)
1710Sstevel@tonic-gate 				precbksl++;
1720Sstevel@tonic-gate 			if (precbksl == 1)
1730Sstevel@tonic-gate 				goto again;
1740Sstevel@tonic-gate 		} else if (precbksl) {
1750Sstevel@tonic-gate 			d = 0;
1760Sstevel@tonic-gate 			if (islower(c))
1770Sstevel@tonic-gate 				d = toupper(c);
1780Sstevel@tonic-gate 			else {
1790Sstevel@tonic-gate 				colp = (unsigned char *)"({)}!|^~'~";
1800Sstevel@tonic-gate 				while (d = *colp++)
1810Sstevel@tonic-gate 					if (d == c) {
1820Sstevel@tonic-gate 						d = *colp++;
1830Sstevel@tonic-gate 						break;
1840Sstevel@tonic-gate 					} else
1850Sstevel@tonic-gate 						colp++;
1860Sstevel@tonic-gate 			}
1870Sstevel@tonic-gate 			if (precbksl == 2) {
1880Sstevel@tonic-gate 				if (!d) {
1890Sstevel@tonic-gate 					Peekkey = c;
1900Sstevel@tonic-gate 					precbksl = 0;
1910Sstevel@tonic-gate 					c = '\\';
1920Sstevel@tonic-gate 				}
1930Sstevel@tonic-gate 			} else if (d)
1940Sstevel@tonic-gate 				c = d;
1950Sstevel@tonic-gate 			else {
1960Sstevel@tonic-gate 				Peekkey = c;
1970Sstevel@tonic-gate 				precbksl = 0;
1980Sstevel@tonic-gate 				c = '\\';
1990Sstevel@tonic-gate 			}
2000Sstevel@tonic-gate 		}
2010Sstevel@tonic-gate 		if (c != '\\')
2020Sstevel@tonic-gate 			precbksl = 0;
2030Sstevel@tonic-gate 	}
2040Sstevel@tonic-gate #ifdef TRACE
2050Sstevel@tonic-gate 	if (trace) {
2060Sstevel@tonic-gate 		if (!techoin) {
2070Sstevel@tonic-gate 			tfixnl();
2080Sstevel@tonic-gate 			techoin = 1;
2090Sstevel@tonic-gate 			fprintf(trace, "*** Input: ");
2100Sstevel@tonic-gate 		}
2110Sstevel@tonic-gate 		tracec(c);
2120Sstevel@tonic-gate 	}
2130Sstevel@tonic-gate #endif
2140Sstevel@tonic-gate 	lastvgk = 0;
2150Sstevel@tonic-gate 	return (c);
2160Sstevel@tonic-gate }
2170Sstevel@tonic-gate 
2180Sstevel@tonic-gate /*
2190Sstevel@tonic-gate  * Get a key, but if a delete, quit or attention
2200Sstevel@tonic-gate  * is typed return 0 so we will abort a partial command.
2210Sstevel@tonic-gate  */
222*802Scf46844 int
223*802Scf46844 getesc(void)
2240Sstevel@tonic-gate {
225*802Scf46844 	int c;
2260Sstevel@tonic-gate 
2270Sstevel@tonic-gate 	c = getkey();
2280Sstevel@tonic-gate 	switch (c) {
2290Sstevel@tonic-gate 
2300Sstevel@tonic-gate 	case CTRL('v'):
2310Sstevel@tonic-gate 	case CTRL('q'):
2320Sstevel@tonic-gate 		c = getkey();
2330Sstevel@tonic-gate 		return (c);
2340Sstevel@tonic-gate 
2350Sstevel@tonic-gate 	case ATTN:
2360Sstevel@tonic-gate 	case QUIT:
2370Sstevel@tonic-gate 		ungetkey(c);
2380Sstevel@tonic-gate 		return (0);
2390Sstevel@tonic-gate 
2400Sstevel@tonic-gate 	case ESCAPE:
2410Sstevel@tonic-gate 		return (0);
2420Sstevel@tonic-gate 	}
2430Sstevel@tonic-gate 	return (c);
2440Sstevel@tonic-gate }
2450Sstevel@tonic-gate 
2460Sstevel@tonic-gate /*
2470Sstevel@tonic-gate  * Peek at the next keystroke.
2480Sstevel@tonic-gate  */
249*802Scf46844 int
250*802Scf46844 peekkey(void)
2510Sstevel@tonic-gate {
2520Sstevel@tonic-gate 
2530Sstevel@tonic-gate 	Peekkey = getkey();
2540Sstevel@tonic-gate 	return (Peekkey);
2550Sstevel@tonic-gate }
2560Sstevel@tonic-gate 
2570Sstevel@tonic-gate /*
2580Sstevel@tonic-gate  * Read a line from the echo area, with single character prompt c.
2590Sstevel@tonic-gate  * A return value of 1 means the user blewit or blewit away.
2600Sstevel@tonic-gate  */
261*802Scf46844 int
2620Sstevel@tonic-gate readecho(c)
2630Sstevel@tonic-gate 	unsigned char c;
2640Sstevel@tonic-gate {
265*802Scf46844 	unsigned char *sc = cursor;
266*802Scf46844 	int (*OP)();
2670Sstevel@tonic-gate 	bool waste;
268*802Scf46844 	int OPeek;
2690Sstevel@tonic-gate 
2700Sstevel@tonic-gate 	if (WBOT == WECHO)
2710Sstevel@tonic-gate 		vclean();
2720Sstevel@tonic-gate 	else
2730Sstevel@tonic-gate 		vclrech(0);
2740Sstevel@tonic-gate 	splitw++;
2750Sstevel@tonic-gate 	vgoto(WECHO, 0);
2760Sstevel@tonic-gate 	putchar(c);
2770Sstevel@tonic-gate 	vclreol();
2780Sstevel@tonic-gate 	vgoto(WECHO, 1);
2790Sstevel@tonic-gate 	cursor = linebuf; linebuf[0] = 0; genbuf[0] = c;
2800Sstevel@tonic-gate 	ixlatctl(1);
2810Sstevel@tonic-gate 	if (peekbr()) {
2820Sstevel@tonic-gate 		if (!INS[0] || (unsigned char)INS[128] == 0200) {
2830Sstevel@tonic-gate 			INS[128] = 0;
2840Sstevel@tonic-gate 			goto blewit;
2850Sstevel@tonic-gate 		}
2860Sstevel@tonic-gate 		vglobp = INS;
2870Sstevel@tonic-gate 	}
2880Sstevel@tonic-gate 	OP = Pline; Pline = normline;
2890Sstevel@tonic-gate 	(void)vgetline(0, genbuf + 1, &waste, c);
2900Sstevel@tonic-gate 	doomed = 0;	/* don't care about doomed characters in echo line */
2910Sstevel@tonic-gate 	ixlatctl(0);
2920Sstevel@tonic-gate 	if (Outchar == termchar)
2930Sstevel@tonic-gate 		putchar('\n');
2940Sstevel@tonic-gate 	vscrap();
2950Sstevel@tonic-gate 	Pline = OP;
2960Sstevel@tonic-gate 	if (Peekkey != ATTN && Peekkey != QUIT && Peekkey != CTRL('h')) {
2970Sstevel@tonic-gate 		cursor = sc;
2980Sstevel@tonic-gate 		vclreol();
2990Sstevel@tonic-gate 		return (0);
3000Sstevel@tonic-gate 	}
3010Sstevel@tonic-gate blewit:
3020Sstevel@tonic-gate 	OPeek = Peekkey==CTRL('h') ? 0 : Peekkey; Peekkey = 0;
3030Sstevel@tonic-gate 	splitw = 0;
3040Sstevel@tonic-gate 	vclean();
3050Sstevel@tonic-gate 	vshow(dot, NOLINE);
3060Sstevel@tonic-gate 	vnline(sc);
3070Sstevel@tonic-gate 	Peekkey = OPeek;
3080Sstevel@tonic-gate 	return (1);
3090Sstevel@tonic-gate }
3100Sstevel@tonic-gate 
3110Sstevel@tonic-gate /*
3120Sstevel@tonic-gate  * A complete command has been defined for
3130Sstevel@tonic-gate  * the purposes of repeat, so copy it from
3140Sstevel@tonic-gate  * the working to the previous command buffer.
3150Sstevel@tonic-gate  */
316*802Scf46844 void
317*802Scf46844 setLAST(void)
3180Sstevel@tonic-gate {
3190Sstevel@tonic-gate 
3200Sstevel@tonic-gate 	if (vglobp || vmacp)
3210Sstevel@tonic-gate 		return;
3220Sstevel@tonic-gate 	lastreg = vreg;
3230Sstevel@tonic-gate 	lasthad = Xhadcnt;
3240Sstevel@tonic-gate 	lastcnt = Xcnt;
3250Sstevel@tonic-gate 	*lastcp = 0;
3260Sstevel@tonic-gate 	CP(lastcmd, workcmd);
3270Sstevel@tonic-gate }
3280Sstevel@tonic-gate 
3290Sstevel@tonic-gate /*
3300Sstevel@tonic-gate  * Gather up some more text from an insert.
3310Sstevel@tonic-gate  * If the insertion buffer oveflows, then destroy
3320Sstevel@tonic-gate  * the repeatability of the insert.
3330Sstevel@tonic-gate  */
334*802Scf46844 void
335*802Scf46844 addtext(unsigned char *cp)
3360Sstevel@tonic-gate {
3370Sstevel@tonic-gate 
3380Sstevel@tonic-gate 	if (vglobp)
3390Sstevel@tonic-gate 		return;
3400Sstevel@tonic-gate 	addto(INS, cp);
3410Sstevel@tonic-gate 	if ((unsigned char)INS[128] == 0200)
3420Sstevel@tonic-gate 		lastcmd[0] = 0;
3430Sstevel@tonic-gate }
3440Sstevel@tonic-gate 
345*802Scf46844 void
346*802Scf46844 setDEL(void)
3470Sstevel@tonic-gate {
3480Sstevel@tonic-gate 
3490Sstevel@tonic-gate 	setBUF(DEL);
3500Sstevel@tonic-gate }
3510Sstevel@tonic-gate 
3520Sstevel@tonic-gate /*
3530Sstevel@tonic-gate  * Put text from cursor upto wcursor in BUF.
3540Sstevel@tonic-gate  */
355*802Scf46844 void
356*802Scf46844 setBUF(unsigned char *BUF)
3570Sstevel@tonic-gate {
358*802Scf46844 	int c;
359*802Scf46844 	unsigned char *wp = wcursor;
3600Sstevel@tonic-gate 
3610Sstevel@tonic-gate 	c = *wp;
3620Sstevel@tonic-gate 	*wp = 0;
3630Sstevel@tonic-gate 	BUF[0] = 0;
3640Sstevel@tonic-gate 	BUF[128] = 0;
3650Sstevel@tonic-gate 	addto(BUF, cursor);
3660Sstevel@tonic-gate 	*wp = c;
3670Sstevel@tonic-gate }
3680Sstevel@tonic-gate 
369*802Scf46844 void
370*802Scf46844 addto(unsigned char *buf, unsigned char *str)
3710Sstevel@tonic-gate {
3720Sstevel@tonic-gate 
3730Sstevel@tonic-gate 	if ((unsigned char)buf[128] == 0200)
3740Sstevel@tonic-gate 		return;
3750Sstevel@tonic-gate 	if (strlen(buf) + strlen(str) + 1 >= VBSIZE) {
3760Sstevel@tonic-gate 		buf[128] = 0200;
3770Sstevel@tonic-gate 		return;
3780Sstevel@tonic-gate 	}
3790Sstevel@tonic-gate 	(void)strcat(buf, str);
3800Sstevel@tonic-gate 	buf[128] = 0;
3810Sstevel@tonic-gate }
3820Sstevel@tonic-gate 
3830Sstevel@tonic-gate /*
3840Sstevel@tonic-gate  * Verbalize command name and embed it in message.
3850Sstevel@tonic-gate  */
3860Sstevel@tonic-gate char *
3870Sstevel@tonic-gate verbalize(cnt, cmdstr, sgn)
3880Sstevel@tonic-gate int cnt;
3890Sstevel@tonic-gate char *cmdstr, *sgn;
3900Sstevel@tonic-gate {
3910Sstevel@tonic-gate 	if (cmdstr[0] == '\0')
3920Sstevel@tonic-gate 		cmdstr = (char *)Command;
3930Sstevel@tonic-gate 	if (sgn[0] == '\0') {
3940Sstevel@tonic-gate 		switch (cmdstr[0]) {
3950Sstevel@tonic-gate 		    case 'c':
3960Sstevel@tonic-gate 			if (cmdstr[1] == 'h') {
397*802Scf46844 				viprintf((cnt == 1) ?
398*802Scf46844 				    gettext("1 line changed") :
399*802Scf46844 				    gettext("%d lines changed"), cnt);
4000Sstevel@tonic-gate 				break;
4010Sstevel@tonic-gate 			} else if (cmdstr[1] != 'o') {
4020Sstevel@tonic-gate 				goto Default;
4030Sstevel@tonic-gate 			}
4040Sstevel@tonic-gate 		    case 't':
4050Sstevel@tonic-gate 			if (cmdstr[1] != '\0')
4060Sstevel@tonic-gate 				goto Default;
407*802Scf46844 			viprintf((cnt == 1) ? gettext("1 line copied") :
4080Sstevel@tonic-gate 			       gettext("%d lines copied"), cnt);
4090Sstevel@tonic-gate 			break;
4100Sstevel@tonic-gate 		    case 'd':
411*802Scf46844 			viprintf((cnt == 1) ? gettext("1 line deleted") :
4120Sstevel@tonic-gate 			       gettext("%d lines deleted"), cnt);
4130Sstevel@tonic-gate 			break;
4140Sstevel@tonic-gate 		    case 'j':
415*802Scf46844 			viprintf((cnt == 1) ? gettext("1 line joined") :
4160Sstevel@tonic-gate 			       gettext("%d lines joined"), cnt);
4170Sstevel@tonic-gate 			break;
4180Sstevel@tonic-gate 		    case 'm':
419*802Scf46844 			viprintf((cnt == 1) ? gettext("1 line moved") :
4200Sstevel@tonic-gate 			       gettext("%d lines moved"), cnt);
4210Sstevel@tonic-gate 			break;
4220Sstevel@tonic-gate 		    case 'p':
423*802Scf46844 			viprintf((cnt == 1) ? gettext("1 line put") :
4240Sstevel@tonic-gate 			       gettext("%d lines put"), cnt);
4250Sstevel@tonic-gate 			break;
4260Sstevel@tonic-gate 		    case 'y':
427*802Scf46844 			viprintf((cnt == 1) ? gettext("1 line yanked") :
4280Sstevel@tonic-gate 			       gettext("%d lines yanked"), cnt);
4290Sstevel@tonic-gate 			break;
4300Sstevel@tonic-gate 		    case '>':
431*802Scf46844 			viprintf((cnt == 1) ? gettext("1 line >>ed") :
4320Sstevel@tonic-gate 			       gettext("%d lines >>ed"), cnt);
4330Sstevel@tonic-gate 			break;
4340Sstevel@tonic-gate 		    case '=':
435*802Scf46844 			viprintf((cnt == 1) ? gettext("1 line =ed") :
4360Sstevel@tonic-gate 			       gettext("%d lines =ed"), cnt);
4370Sstevel@tonic-gate 			break;
4380Sstevel@tonic-gate 		    case '<':
439*802Scf46844 			viprintf((cnt == 1) ? gettext("1 line <<ed") :
4400Sstevel@tonic-gate 			       gettext("%d lines <<ed"), cnt);
4410Sstevel@tonic-gate 			break;
4420Sstevel@tonic-gate 		    default:
4430Sstevel@tonic-gate Default:
444*802Scf46844 			viprintf((cnt == 1) ? gettext("1 line") :
4450Sstevel@tonic-gate 			       gettext("%d lines"), cnt);
4460Sstevel@tonic-gate 			break;
4470Sstevel@tonic-gate 		}
4480Sstevel@tonic-gate 	} else if (sgn[0] == 'm') {
449*802Scf46844 		viprintf((cnt == 1) ? gettext("1 more line") :
4500Sstevel@tonic-gate 			gettext("%d more lines"), cnt);
4510Sstevel@tonic-gate 	} else {
452*802Scf46844 		viprintf((cnt == 1) ? gettext("1 fewer line") :
4530Sstevel@tonic-gate 			gettext("%d fewer lines"), cnt);
4540Sstevel@tonic-gate 	}
4550Sstevel@tonic-gate 	return (NULL);
4560Sstevel@tonic-gate }
4570Sstevel@tonic-gate 
4580Sstevel@tonic-gate /*
4590Sstevel@tonic-gate  * Note a change affecting a lot of lines, or non-visible
4600Sstevel@tonic-gate  * lines.  If the parameter must is set, then we only want
4610Sstevel@tonic-gate  * to do this for open modes now; return and save for later
4620Sstevel@tonic-gate  * notification in visual.
4630Sstevel@tonic-gate  */
464*802Scf46844 int
4650Sstevel@tonic-gate noteit(must)
4660Sstevel@tonic-gate 	bool must;
4670Sstevel@tonic-gate {
468*802Scf46844 	int sdl = destline, sdc = destcol;
4690Sstevel@tonic-gate 
4700Sstevel@tonic-gate 	if (notecnt < 1 || !must && state == VISUAL)
4710Sstevel@tonic-gate 		return (0);
4720Sstevel@tonic-gate 	splitw++;
4730Sstevel@tonic-gate 	if (WBOT == WECHO)
4740Sstevel@tonic-gate 		vmoveitup(1, 1);
4750Sstevel@tonic-gate 	vigoto(WECHO, 0);
4760Sstevel@tonic-gate 
4770Sstevel@tonic-gate 	verbalize(notecnt, notenam, notesgn);
4780Sstevel@tonic-gate 	vclreol();
4790Sstevel@tonic-gate 	notecnt = 0;
4800Sstevel@tonic-gate 	if (state != VISUAL)
4810Sstevel@tonic-gate 		vcnt = vcline = 0;
4820Sstevel@tonic-gate 	splitw = 0;
4830Sstevel@tonic-gate 	if (state == ONEOPEN || state == CRTOPEN)
4840Sstevel@tonic-gate 		vup1();
4850Sstevel@tonic-gate 	destline = sdl; destcol = sdc;
4860Sstevel@tonic-gate 	return (1);
4870Sstevel@tonic-gate }
4880Sstevel@tonic-gate 
4890Sstevel@tonic-gate /*
4900Sstevel@tonic-gate  * Ring or beep.
4910Sstevel@tonic-gate  * If possible, flash screen.
4920Sstevel@tonic-gate  */
493*802Scf46844 int
494*802Scf46844 beep(void)
4950Sstevel@tonic-gate {
4960Sstevel@tonic-gate 
4970Sstevel@tonic-gate 	if (flash_screen && value(vi_FLASH))
4980Sstevel@tonic-gate 		vputp(flash_screen, 0);
4990Sstevel@tonic-gate 	else if (bell)
5000Sstevel@tonic-gate 		vputp(bell, 0);
501*802Scf46844 	return (0);
5020Sstevel@tonic-gate }
5030Sstevel@tonic-gate 
5040Sstevel@tonic-gate /*
5050Sstevel@tonic-gate  * Map the command input character c,
5060Sstevel@tonic-gate  * for keypads and labelled keys which do cursor
5070Sstevel@tonic-gate  * motions.  I.e. on an adm3a we might map ^K to ^P.
5080Sstevel@tonic-gate  * DM1520 for example has a lot of mappable characters.
5090Sstevel@tonic-gate  */
5100Sstevel@tonic-gate 
511*802Scf46844 int
512*802Scf46844 map(c, maps, commch)
513*802Scf46844 	int c;
514*802Scf46844 	struct maps *maps;
515*802Scf46844 	unsigned char commch; /* indicate if in append/insert/replace mode */
5160Sstevel@tonic-gate {
517*802Scf46844 	int d;
518*802Scf46844 	unsigned char *p, *q;
5190Sstevel@tonic-gate 	unsigned char b[10];	/* Assumption: no keypad sends string longer than 10 */
5200Sstevel@tonic-gate 	unsigned char *st;
5210Sstevel@tonic-gate 
5220Sstevel@tonic-gate 	/*
5230Sstevel@tonic-gate 	 * Mapping for special keys on the terminal only.
5240Sstevel@tonic-gate 	 * BUG: if there's a long sequence and it matches
5250Sstevel@tonic-gate 	 * some chars and then misses, we lose some chars.
5260Sstevel@tonic-gate 	 *
5270Sstevel@tonic-gate 	 * For this to work, some conditions must be met.
5280Sstevel@tonic-gate 	 * 1) Keypad sends SHORT (2 or 3 char) strings
5290Sstevel@tonic-gate 	 * 2) All strings sent are same length & similar
5300Sstevel@tonic-gate 	 * 3) The user is unlikely to type the first few chars of
5310Sstevel@tonic-gate 	 *    one of these strings very fast.
5320Sstevel@tonic-gate 	 * Note: some code has been fixed up since the above was laid out,
5330Sstevel@tonic-gate 	 * so conditions 1 & 2 are probably not required anymore.
5340Sstevel@tonic-gate 	 * However, this hasn't been tested with any first char
5350Sstevel@tonic-gate 	 * that means anything else except escape.
5360Sstevel@tonic-gate 	 */
5370Sstevel@tonic-gate #ifdef MDEBUG
5380Sstevel@tonic-gate 	if (trace)
5390Sstevel@tonic-gate 		fprintf(trace,"map(%c): ",c);
5400Sstevel@tonic-gate #endif
5410Sstevel@tonic-gate 	/*
5420Sstevel@tonic-gate 	 * If c==0, the char came from getesc typing escape.  Pass it through
5430Sstevel@tonic-gate 	 * unchanged.  0 messes up the following code anyway.
5440Sstevel@tonic-gate 	 */
5450Sstevel@tonic-gate 	if (c==0)
5460Sstevel@tonic-gate 		return(0);
5470Sstevel@tonic-gate 
5480Sstevel@tonic-gate 	b[0] = c;
5490Sstevel@tonic-gate 	b[1] = 0;
5500Sstevel@tonic-gate 	for (d=0; d < MAXNOMACS && maps[d].mapto; d++) {
5510Sstevel@tonic-gate #ifdef MDEBUG
5520Sstevel@tonic-gate 		if (trace)
5530Sstevel@tonic-gate 			fprintf(trace,"\ntry '%s', ",maps[d].cap);
5540Sstevel@tonic-gate #endif
5550Sstevel@tonic-gate 		if (p = maps[d].cap) {
5560Sstevel@tonic-gate 			for (q=b; *p; p++, q++) {
5570Sstevel@tonic-gate #ifdef MDEBUG
5580Sstevel@tonic-gate 				if (trace)
5590Sstevel@tonic-gate 					fprintf(trace,"q->b[%d], ",q-b);
5600Sstevel@tonic-gate #endif
5610Sstevel@tonic-gate 				if (*q==0) {
5620Sstevel@tonic-gate 					/*
5630Sstevel@tonic-gate 					 * Is there another char waiting?
5640Sstevel@tonic-gate 					 *
5650Sstevel@tonic-gate 					 * This test is oversimplified, but
5660Sstevel@tonic-gate 					 * should work mostly. It handles the
5670Sstevel@tonic-gate 					 * case where we get an ESCAPE that
5680Sstevel@tonic-gate 					 * wasn't part of a keypad string.
5690Sstevel@tonic-gate 					 */
5700Sstevel@tonic-gate 					if ((c=='#' ? peekkey() : fastpeekkey()) == 0) {
5710Sstevel@tonic-gate #ifdef MDEBUG
5720Sstevel@tonic-gate 						if (trace)
5730Sstevel@tonic-gate 							fprintf(trace,"fpk=0: will return '%c'",c);
5740Sstevel@tonic-gate #endif
5750Sstevel@tonic-gate 						/*
5760Sstevel@tonic-gate 						 * Nothing waiting.  Push back
5770Sstevel@tonic-gate 						 * what we peeked at & return
5780Sstevel@tonic-gate 						 * failure (c).
5790Sstevel@tonic-gate 						 *
5800Sstevel@tonic-gate 						 * We want to be able to undo
5810Sstevel@tonic-gate 						 * commands, but it's nonsense
5820Sstevel@tonic-gate 						 * to undo part of an insertion
5830Sstevel@tonic-gate 						 * so if in input mode don't.
5840Sstevel@tonic-gate 						 */
5850Sstevel@tonic-gate #ifdef MDEBUG
5860Sstevel@tonic-gate 						if (trace)
5870Sstevel@tonic-gate 							fprintf(trace, "Call macpush, b %d %d %d\n", b[0], b[1], b[2]);
5880Sstevel@tonic-gate #endif
5890Sstevel@tonic-gate 						macpush(&b[1],maps == arrows);
5900Sstevel@tonic-gate #ifdef MDEBUG
5910Sstevel@tonic-gate 						if (trace)
5920Sstevel@tonic-gate 							fprintf(trace, "return %d\n", c);
5930Sstevel@tonic-gate #endif
5940Sstevel@tonic-gate 						return(c);
5950Sstevel@tonic-gate 					}
5960Sstevel@tonic-gate 					*q = getkey();
5970Sstevel@tonic-gate 					q[1] = 0;
5980Sstevel@tonic-gate 				}
5990Sstevel@tonic-gate 				if (*p != *q)
6000Sstevel@tonic-gate 					goto contin;
6010Sstevel@tonic-gate 			}
6020Sstevel@tonic-gate 			macpush(maps[d].mapto,maps == arrows);
6030Sstevel@tonic-gate 			/*
6040Sstevel@tonic-gate 			 * For all macros performed within insert,
6050Sstevel@tonic-gate 			 * append, or replacement mode, we must end
6060Sstevel@tonic-gate 			 * up returning back to that mode when we
6070Sstevel@tonic-gate 			 * return (except that append will become
6080Sstevel@tonic-gate 			 * insert for <home> key, so cursor is not
6090Sstevel@tonic-gate 			 * in second column).
6100Sstevel@tonic-gate 			 *
6110Sstevel@tonic-gate 			 * In order to preserve backward movement
6120Sstevel@tonic-gate 			 * when leaving insert mode, an 'l' must be
6130Sstevel@tonic-gate 			 * done to compensate for the left done by
6140Sstevel@tonic-gate 			 * the <esc> (except when cursor is already
6150Sstevel@tonic-gate 			 * in the first column: i.e., outcol = 0).
6160Sstevel@tonic-gate 			 */
6170Sstevel@tonic-gate 			 if ((maps == immacs)
6180Sstevel@tonic-gate 			 && strcmp(maps[d].descr, maps[d].cap)) {
6190Sstevel@tonic-gate 				switch (commch) {
6200Sstevel@tonic-gate 				  case 'R':
6210Sstevel@tonic-gate 					if (!strcmp(maps[d].descr, "home"))
6220Sstevel@tonic-gate 						st = (unsigned char *)"R";
6230Sstevel@tonic-gate 					else
6240Sstevel@tonic-gate 						if (outcol == 0)
6250Sstevel@tonic-gate 							st = (unsigned char *)"R";
6260Sstevel@tonic-gate 						else
6270Sstevel@tonic-gate 							st = (unsigned char *)"lR";
6280Sstevel@tonic-gate 					break;
6290Sstevel@tonic-gate 				  case 'i':
6300Sstevel@tonic-gate 					if (!strcmp(maps[d].descr, "home"))
6310Sstevel@tonic-gate 						st = (unsigned char *)"i";
6320Sstevel@tonic-gate 					else
6330Sstevel@tonic-gate 						if (outcol == 0)
6340Sstevel@tonic-gate 							st = (unsigned char *)"i";
6350Sstevel@tonic-gate 						else
6360Sstevel@tonic-gate 							st = (unsigned char *)"li";
6370Sstevel@tonic-gate 					break;
6380Sstevel@tonic-gate 				  case 'a':
6390Sstevel@tonic-gate 					if (!strcmp(maps[d].descr, "home"))
6400Sstevel@tonic-gate 						st = (unsigned char *)"i";
6410Sstevel@tonic-gate 					else
6420Sstevel@tonic-gate 						st = (unsigned char *)"a";
6430Sstevel@tonic-gate 					break;
6440Sstevel@tonic-gate 				  default:
6450Sstevel@tonic-gate 					st = (unsigned char *)"i";
6460Sstevel@tonic-gate 				}
6470Sstevel@tonic-gate 				if(strlen(vmacbuf)  + strlen(st) > BUFSIZE)
6480Sstevel@tonic-gate 					error(value(vi_TERSE) ?
6490Sstevel@tonic-gate gettext("Macro too long") : gettext("Macro too long  - maybe recursive?"));
6500Sstevel@tonic-gate 				else
6510Sstevel@tonic-gate 					/*
6520Sstevel@tonic-gate 					 * Macros such as function keys are
6530Sstevel@tonic-gate 					 * performed by leaving the insert,
6540Sstevel@tonic-gate 					 * replace, or append mode, executing
6550Sstevel@tonic-gate 					 * the proper cursor movement commands
6560Sstevel@tonic-gate 					 * and returning to the mode we are
6570Sstevel@tonic-gate 					 * currently in (commch).
6580Sstevel@tonic-gate 					 */
6590Sstevel@tonic-gate 					strcat(vmacbuf, st);
6600Sstevel@tonic-gate 			}
6610Sstevel@tonic-gate 			c = getkey();
6620Sstevel@tonic-gate #ifdef MDEBUG
6630Sstevel@tonic-gate 			if (trace)
6640Sstevel@tonic-gate 				fprintf(trace,"Success: push(%s), return %c",maps[d].mapto, c);
6650Sstevel@tonic-gate #endif
6660Sstevel@tonic-gate 			return(c);	/* first char of map string */
6670Sstevel@tonic-gate 			contin:;
6680Sstevel@tonic-gate 		}
6690Sstevel@tonic-gate 	}
6700Sstevel@tonic-gate #ifdef MDEBUG
6710Sstevel@tonic-gate 	if (trace)
6720Sstevel@tonic-gate 		fprintf(trace,"Fail: push(%s), return %c", &b[1], c);
6730Sstevel@tonic-gate #endif
6740Sstevel@tonic-gate 	macpush(&b[1],0);
6750Sstevel@tonic-gate 	return(c);
6760Sstevel@tonic-gate }
6770Sstevel@tonic-gate 
6780Sstevel@tonic-gate /*
6790Sstevel@tonic-gate  * Push st onto the front of vmacp. This is tricky because we have to
6800Sstevel@tonic-gate  * worry about where vmacp was previously pointing. We also have to
6810Sstevel@tonic-gate  * check for overflow (which is typically from a recursive macro)
6820Sstevel@tonic-gate  * Finally we have to set a flag so the whole thing can be undone.
6830Sstevel@tonic-gate  * canundo is 1 iff we want to be able to undo the macro.  This
6840Sstevel@tonic-gate  * is false for, for example, pushing back lookahead from fastpeekkey(),
6850Sstevel@tonic-gate  * since otherwise two fast escapes can clobber our undo.
6860Sstevel@tonic-gate  */
687*802Scf46844 void
688*802Scf46844 macpush(unsigned char *st, int canundo)
6890Sstevel@tonic-gate {
6900Sstevel@tonic-gate 	unsigned char tmpbuf[BUFSIZE];
6910Sstevel@tonic-gate 
6920Sstevel@tonic-gate 	if (st==0 || *st==0)
6930Sstevel@tonic-gate 		return;
6940Sstevel@tonic-gate #ifdef MDEBUG
6950Sstevel@tonic-gate 	if (trace)
6960Sstevel@tonic-gate 		fprintf(trace, "macpush(%s), canundo=%d\n",st,canundo);
6970Sstevel@tonic-gate #endif
6980Sstevel@tonic-gate 	if ((vmacp ? strlen(vmacp) : 0) + strlen(st) > BUFSIZE)
6990Sstevel@tonic-gate 		error(value(vi_TERSE) ? gettext("Macro too long") :
7000Sstevel@tonic-gate gettext("Macro too long  - maybe recursive?"));
7010Sstevel@tonic-gate 	if (vmacp) {
7020Sstevel@tonic-gate 		strcpy(tmpbuf, vmacp);
7030Sstevel@tonic-gate 		if (!FIXUNDO)
7040Sstevel@tonic-gate 			canundo = 0;	/* can't undo inside a macro anyway */
7050Sstevel@tonic-gate 	}
7060Sstevel@tonic-gate 	strcpy(vmacbuf, st);
7070Sstevel@tonic-gate 	if (vmacp)
7080Sstevel@tonic-gate 		strcat(vmacbuf, tmpbuf);
7090Sstevel@tonic-gate 	vmacp = vmacbuf;
7100Sstevel@tonic-gate 	/* arrange to be able to undo the whole macro */
7110Sstevel@tonic-gate 	if (canundo) {
7120Sstevel@tonic-gate #ifdef notdef
7130Sstevel@tonic-gate 		otchng = tchng;
7140Sstevel@tonic-gate 		vsave();
7150Sstevel@tonic-gate 		saveall();
7160Sstevel@tonic-gate 		inopen = -1;	/* no need to save since it had to be 1 or -1 before */
7170Sstevel@tonic-gate 		vundkind = VMANY;
7180Sstevel@tonic-gate #endif
7190Sstevel@tonic-gate 		vch_mac = VC_NOCHANGE;
7200Sstevel@tonic-gate 	}
7210Sstevel@tonic-gate }
7220Sstevel@tonic-gate 
7230Sstevel@tonic-gate #ifdef UNDOTRACE
7240Sstevel@tonic-gate visdump(s)
7250Sstevel@tonic-gate unsigned char *s;
7260Sstevel@tonic-gate {
727*802Scf46844 	int i;
7280Sstevel@tonic-gate 
7290Sstevel@tonic-gate 	if (!trace) return;
7300Sstevel@tonic-gate 
7310Sstevel@tonic-gate 	fprintf(trace, "\n%s: basWTOP=%d, basWLINES=%d, WTOP=%d, WBOT=%d, WLINES=%d, WCOLS=%d, WECHO=%d\n",
7320Sstevel@tonic-gate 		s, basWTOP, basWLINES, WTOP, WBOT, WLINES, WCOLS, WECHO);
7330Sstevel@tonic-gate 	fprintf(trace, "   vcnt=%d, vcline=%d, cursor=%d, wcursor=%d, wdot=%d\n",
7340Sstevel@tonic-gate 		vcnt, vcline, cursor-linebuf, wcursor-linebuf, wdot-zero);
7350Sstevel@tonic-gate 	for (i=0; i<TUBELINES; i++)
7360Sstevel@tonic-gate 		if (vtube[i] && *vtube[i])
7370Sstevel@tonic-gate 			fprintf(trace, "%d: '%s'\n", i, vtube[i]);
7380Sstevel@tonic-gate 	tvliny();
7390Sstevel@tonic-gate }
7400Sstevel@tonic-gate 
7410Sstevel@tonic-gate vudump(s)
7420Sstevel@tonic-gate unsigned char *s;
7430Sstevel@tonic-gate {
744*802Scf46844 	line *p;
7450Sstevel@tonic-gate 	unsigned char savelb[1024];
7460Sstevel@tonic-gate 
7470Sstevel@tonic-gate 	if (!trace) return;
7480Sstevel@tonic-gate 
7490Sstevel@tonic-gate 	fprintf(trace, "\n%s: undkind=%d, vundkind=%d, unddel=%d, undap1=%d, undap2=%d,\n",
7500Sstevel@tonic-gate 		s, undkind, vundkind, lineno(unddel), lineno(undap1), lineno(undap2));
7510Sstevel@tonic-gate 	fprintf(trace, "  undadot=%d, dot=%d, dol=%d, unddol=%d, truedol=%d\n",
7520Sstevel@tonic-gate 		lineno(undadot), lineno(dot), lineno(dol), lineno(unddol), lineno(truedol));
7530Sstevel@tonic-gate 	fprintf(trace, "  [\n");
7540Sstevel@tonic-gate 	CP(savelb, linebuf);
7550Sstevel@tonic-gate 	fprintf(trace, "linebuf = '%s'\n", linebuf);
7560Sstevel@tonic-gate 	for (p=zero+1; p<=truedol; p++) {
7570Sstevel@tonic-gate 		fprintf(trace, "%o ", *p);
7580Sstevel@tonic-gate 		getline(*p);
7590Sstevel@tonic-gate 		fprintf(trace, "'%s'\n", linebuf);
7600Sstevel@tonic-gate 	}
7610Sstevel@tonic-gate 	fprintf(trace, "]\n");
7620Sstevel@tonic-gate 	CP(linebuf, savelb);
7630Sstevel@tonic-gate }
7640Sstevel@tonic-gate #endif
7650Sstevel@tonic-gate 
7660Sstevel@tonic-gate /*
7670Sstevel@tonic-gate  * Get a count from the keyed input stream.
7680Sstevel@tonic-gate  * A zero count is indistinguishable from no count.
7690Sstevel@tonic-gate  */
770*802Scf46844 int
771*802Scf46844 vgetcnt(void)
7720Sstevel@tonic-gate {
773*802Scf46844 	int c, cnt;
7740Sstevel@tonic-gate 
7750Sstevel@tonic-gate 	cnt = 0;
7760Sstevel@tonic-gate 	for (;;) {
7770Sstevel@tonic-gate 		c = getkey();
7780Sstevel@tonic-gate 		if (!isdigit(c))
7790Sstevel@tonic-gate 			break;
7800Sstevel@tonic-gate 		cnt *= 10, cnt += c - '0';
7810Sstevel@tonic-gate 	}
7820Sstevel@tonic-gate 	ungetkey(c);
7830Sstevel@tonic-gate 	Xhadcnt = 1;
7840Sstevel@tonic-gate 	Xcnt = cnt;
7850Sstevel@tonic-gate 	return(cnt);
7860Sstevel@tonic-gate }
7870Sstevel@tonic-gate 
7880Sstevel@tonic-gate /*
7890Sstevel@tonic-gate  * fastpeekkey is just like peekkey but insists the character come in
7900Sstevel@tonic-gate  * fast (within 1 second). This will succeed if it is the 2nd char of
7910Sstevel@tonic-gate  * a machine generated sequence (such as a function pad from an escape
7920Sstevel@tonic-gate  * flavor terminal) but fail for a human hitting escape then waiting.
7930Sstevel@tonic-gate  */
794*802Scf46844 int
795*802Scf46844 fastpeekkey(void)
7960Sstevel@tonic-gate {
7970Sstevel@tonic-gate 	void trapalarm();
798*802Scf46844 	int c;
7990Sstevel@tonic-gate 
8000Sstevel@tonic-gate 	/*
8010Sstevel@tonic-gate 	 * If the user has set notimeout, we wait forever for a key.
8020Sstevel@tonic-gate 	 * If we are in a macro we do too, but since it's already
8030Sstevel@tonic-gate 	 * buffered internally it will return immediately.
8040Sstevel@tonic-gate 	 * In other cases we force this to die in 1 second.
8050Sstevel@tonic-gate 	 * This is pretty reliable (VMUNIX rounds it to .5 - 1.5 secs,
8060Sstevel@tonic-gate 	 * but UNIX truncates it to 0 - 1 secs) but due to system delays
8070Sstevel@tonic-gate 	 * there are times when arrow keys or very fast typing get counted
8080Sstevel@tonic-gate 	 * as separate.  notimeout is provided for people who dislike such
8090Sstevel@tonic-gate 	 * nondeterminism.
8100Sstevel@tonic-gate 	 */
8110Sstevel@tonic-gate 	CATCH
8120Sstevel@tonic-gate 		if (value(vi_TIMEOUT) && inopen >= 0) {
8130Sstevel@tonic-gate 			signal(SIGALRM, trapalarm);
8140Sstevel@tonic-gate 			setalarm();
8150Sstevel@tonic-gate 		}
8160Sstevel@tonic-gate 		c = peekkey();
8170Sstevel@tonic-gate 		cancelalarm();
8180Sstevel@tonic-gate 	ONERR
8190Sstevel@tonic-gate 		c = 0;
8200Sstevel@tonic-gate 	ENDCATCH
8210Sstevel@tonic-gate 	/* Should have an alternative method based on select for 4.2BSD */
8220Sstevel@tonic-gate 	return(c);
8230Sstevel@tonic-gate }
8240Sstevel@tonic-gate 
8250Sstevel@tonic-gate static int ftfd;
8260Sstevel@tonic-gate struct requestbuf {
8270Sstevel@tonic-gate 	short time;
8280Sstevel@tonic-gate 	short signo;
8290Sstevel@tonic-gate };
8300Sstevel@tonic-gate 
8310Sstevel@tonic-gate /*
8320Sstevel@tonic-gate  * Arrange for SIGALRM to come in shortly, so we don't
8330Sstevel@tonic-gate  * hang very long if the user didn't type anything.  There are
8340Sstevel@tonic-gate  * various ways to do this on different systems.
8350Sstevel@tonic-gate  */
836*802Scf46844 void
837*802Scf46844 setalarm(void)
8380Sstevel@tonic-gate {
8390Sstevel@tonic-gate 	unsigned char ftname[20];
8400Sstevel@tonic-gate 	struct requestbuf rb;
8410Sstevel@tonic-gate 
8420Sstevel@tonic-gate #ifdef FTIOCSET
8430Sstevel@tonic-gate 	/*
8440Sstevel@tonic-gate 	 * Use nonstandard "fast timer" to get better than
8450Sstevel@tonic-gate 	 * one second resolution.  We must wait at least
8460Sstevel@tonic-gate 	 * 1/15th of a second because some keypads don't
8470Sstevel@tonic-gate 	 * transmit faster than this.
8480Sstevel@tonic-gate 	 */
8490Sstevel@tonic-gate 
8500Sstevel@tonic-gate 	/* Open ft psuedo-device - we need our own copy. */
8510Sstevel@tonic-gate 	if (ftfd == 0) {
8520Sstevel@tonic-gate 		strcpy(ftname, "/dev/ft0");
8530Sstevel@tonic-gate 		while (ftfd <= 0 && ftname[7] <= '~') {
8540Sstevel@tonic-gate 			ftfd = open(ftname, 0);
8550Sstevel@tonic-gate 			if (ftfd <= 0)
8560Sstevel@tonic-gate 				ftname[7] ++;
8570Sstevel@tonic-gate 		}
8580Sstevel@tonic-gate 	}
8590Sstevel@tonic-gate 	if (ftfd <= 0) {	/* Couldn't open a /dev/ft? */
8600Sstevel@tonic-gate 		alarm(1);
8610Sstevel@tonic-gate 	} else {
8620Sstevel@tonic-gate 		rb.time = 6;	/* 6 ticks = 100 ms > 67 ms. */
8630Sstevel@tonic-gate 		rb.signo = SIGALRM;
8640Sstevel@tonic-gate 		ioctl(ftfd, FTIOCSET, &rb);
8650Sstevel@tonic-gate 	}
8660Sstevel@tonic-gate #else
8670Sstevel@tonic-gate 	/*
8680Sstevel@tonic-gate 	 * No special capabilities, so we use alarm, with 1 sec. resolution.
8690Sstevel@tonic-gate 	 */
8700Sstevel@tonic-gate 	alarm(1);
8710Sstevel@tonic-gate #endif
8720Sstevel@tonic-gate }
8730Sstevel@tonic-gate 
8740Sstevel@tonic-gate /*
8750Sstevel@tonic-gate  * Get rid of any impending incoming SIGALRM.
8760Sstevel@tonic-gate  */
877*802Scf46844 void
878*802Scf46844 cancelalarm(void)
8790Sstevel@tonic-gate {
8800Sstevel@tonic-gate 	struct requestbuf rb;
8810Sstevel@tonic-gate #ifdef FTIOCSET
8820Sstevel@tonic-gate 	if (ftfd > 0) {
8830Sstevel@tonic-gate 		rb.time = 0;
8840Sstevel@tonic-gate 		rb.signo = SIGALRM;
8850Sstevel@tonic-gate 		ioctl(ftfd, FTIOCCANCEL, &rb);
8860Sstevel@tonic-gate 	}
8870Sstevel@tonic-gate #endif
8880Sstevel@tonic-gate 	alarm(0);	/* Have to do this whether or not FTIOCSET */
8890Sstevel@tonic-gate }
8900Sstevel@tonic-gate 
8910Sstevel@tonic-gate void trapalarm() {
8920Sstevel@tonic-gate 	alarm(0);
8930Sstevel@tonic-gate 	longjmp(vreslab,1);
8940Sstevel@tonic-gate }
895