ex_vget.c revision f6db9f272f0061301cfaa1c0001b7d636eae31f4
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
/* Copyright (c) 1981 Regents of the University of California */
#pragma ident "%Z%%M% %I% %E% SMI"
#include "ex.h"
#include "ex_tty.h"
#include "ex_vis.h"
/*
* We handle upper case only terminals in visual and reading from the
* echo area here as well as notification on large changes
* which appears in the echo area.
*/
/*
* Return the key.
*/
void
ungetkey(int c)
{
Peekkey = c;
}
/*
* Return a keystroke, but never a ^@.
*/
int
getkey(void)
{
int c; /* char --> int */
do {
c = getbr();
if (c==0)
(void) beep();
} while (c == 0);
return (c);
}
/*
* Tell whether next keystroke would be a ^@.
*/
int
peekbr(void)
{
return (Peekkey == 0);
}
short precbksl;
/*
* Get a keystroke, including a ^@.
* If an key was returned with ungetkey, that
* comes back first. Next comes unread input (e.g.
* from repeating commands with .), and finally new
* keystrokes.
*
* The hard work here is in mapping of \ escaped
* characters on upper case only terminals.
*/
int
getbr(void)
{
unsigned char ch;
int c, d;
unsigned char *colp;
int cnt;
static unsigned char Peek2key;
if (Peekkey) {
c = Peekkey;
Peekkey = 0;
return (c);
}
if (Peek2key) {
c = Peek2key;
Peek2key = 0;
return (c);
}
if (vglobp) {
if (*vglobp)
lastvgk = 0;
return (ESCAPE);
}
if (vmacp) {
if (*vmacp)
return(*vmacp++);
/* End of a macro or set of nested macros */
vmacp = 0;
}
flusho();
goto getATTN;
}
c = ch;
goto getATTN;
switch (Peek2key) {
case 'C': /* SPOW mode sometimes sends \EC for space */
c = ' ';
Peek2key = 0;
break;
case 'q': /* f2 -> ^C */
c = CTRL('c');
Peek2key = 0;
break;
case 'p': /* f1 -> esc */
Peek2key = 0;
break;
}
}
/*
* The algorithm here is that of the UNIX kernel.
* See the description in the programmers manual.
*/
if (UPPERCASE) {
if (isupper(c))
c = tolower(c);
if (c == '\\') {
if (precbksl < 2)
precbksl++;
if (precbksl == 1)
goto again;
} else if (precbksl) {
d = 0;
if (islower(c))
d = toupper(c);
else {
colp = (unsigned char *)"({)}!|^~'~";
while (d = *colp++)
if (d == c) {
d = *colp++;
break;
} else
colp++;
}
if (precbksl == 2) {
if (!d) {
Peekkey = c;
precbksl = 0;
c = '\\';
}
} else if (d)
c = d;
else {
Peekkey = c;
precbksl = 0;
c = '\\';
}
}
if (c != '\\')
precbksl = 0;
}
#ifdef TRACE
if (trace) {
if (!techoin) {
tfixnl();
techoin = 1;
}
tracec(c);
}
#endif
lastvgk = 0;
return (c);
}
/*
* Get a key, but if a delete, quit or attention
* is typed return 0 so we will abort a partial command.
*/
int
getesc(void)
{
int c;
c = getkey();
switch (c) {
case CTRL('v'):
case CTRL('q'):
c = getkey();
return (c);
case ATTN:
case QUIT:
ungetkey(c);
return (0);
case ESCAPE:
return (0);
}
return (c);
}
/*
* Peek at the next keystroke.
*/
int
peekkey(void)
{
return (Peekkey);
}
/*
* Read a line from the echo area, with single character prompt c.
* A return value of 1 means the user blewit or blewit away.
*/
int
readecho(c)
unsigned char c;
{
int (*OP)();
bool waste;
int OPeek;
vclean();
else
vclrech(0);
splitw++;
putchar(c);
vclreol();
ixlatctl(1);
if (peekbr()) {
INS[128] = 0;
goto blewit;
}
}
doomed = 0; /* don't care about doomed characters in echo line */
ixlatctl(0);
putchar('\n');
vscrap();
vclreol();
return (0);
}
splitw = 0;
vclean();
return (1);
}
/*
* A complete command has been defined for
* the purposes of repeat, so copy it from
* the working to the previous command buffer.
*/
void
setLAST(void)
{
return;
*lastcp = 0;
}
/*
* Gather up some more text from an insert.
* If the insertion buffer oveflows, then destroy
* the repeatability of the insert.
*/
void
{
if (vglobp)
return;
lastcmd[0] = 0;
}
void
setDEL(void)
{
}
/*
* Put text from cursor upto wcursor in BUF.
*/
void
{
int c;
c = *wp;
*wp = 0;
BUF[0] = 0;
BUF[128] = 0;
*wp = c;
}
void
{
return;
return;
}
buf[128] = 0;
}
/*
* Verbalize command name and embed it in message.
*/
char *
int cnt;
{
if (cmdstr[0] == '\0')
if (sgn[0] == '\0') {
switch (cmdstr[0]) {
case 'c':
gettext("1 line changed") :
break;
goto Default;
}
case 't':
goto Default;
break;
case 'd':
break;
case 'j':
break;
case 'm':
break;
case 'p':
break;
case 'y':
break;
case '>':
break;
case '=':
break;
case '<':
break;
default:
break;
}
} else if (sgn[0] == 'm') {
} else {
}
return (NULL);
}
/*
* Note a change affecting a lot of lines, or non-visible
* lines. If the parameter must is set, then we only want
* to do this for open modes now; return and save for later
* notification in visual.
*/
int
bool must;
{
return (0);
splitw++;
vclreol();
notecnt = 0;
splitw = 0;
vup1();
return (1);
}
/*
* Ring or beep.
* If possible, flash screen.
*/
int
beep(void)
{
vputp(flash_screen, 0);
else if (bell)
return (0);
}
/*
* Map the command input character c,
* for keypads and labelled keys which do cursor
* motions. I.e. on an adm3a we might map ^K to ^P.
* DM1520 for example has a lot of mappable characters.
*/
int
int c;
{
int d;
unsigned char *p, *q;
unsigned char b[10]; /* Assumption: no keypad sends string longer than 10 */
unsigned char *st;
/*
* Mapping for special keys on the terminal only.
* BUG: if there's a long sequence and it matches
* some chars and then misses, we lose some chars.
*
* For this to work, some conditions must be met.
* 1) Keypad sends SHORT (2 or 3 char) strings
* 2) All strings sent are same length & similar
* 3) The user is unlikely to type the first few chars of
* one of these strings very fast.
* Note: some code has been fixed up since the above was laid out,
* so conditions 1 & 2 are probably not required anymore.
* However, this hasn't been tested with any first char
* that means anything else except escape.
*/
#ifdef MDEBUG
if (trace)
#endif
/*
* If c==0, the char came from getesc typing escape. Pass it through
* unchanged. 0 messes up the following code anyway.
*/
if (c==0)
return(0);
b[0] = c;
b[1] = 0;
#ifdef MDEBUG
if (trace)
#endif
for (q=b; *p; p++, q++) {
#ifdef MDEBUG
if (trace)
#endif
if (*q==0) {
/*
* Is there another char waiting?
*
* This test is oversimplified, but
* should work mostly. It handles the
* case where we get an ESCAPE that
* wasn't part of a keypad string.
*/
#ifdef MDEBUG
if (trace)
#endif
/*
* Nothing waiting. Push back
* what we peeked at & return
* failure (c).
*
* We want to be able to undo
* commands, but it's nonsense
* to undo part of an insertion
* so if in input mode don't.
*/
#ifdef MDEBUG
if (trace)
#endif
#ifdef MDEBUG
if (trace)
#endif
return(c);
}
*q = getkey();
q[1] = 0;
}
if (*p != *q)
goto contin;
}
/*
* For all macros performed within insert,
* append, or replacement mode, we must end
* up returning back to that mode when we
* return (except that append will become
* insert for <home> key, so cursor is not
* in second column).
*
* In order to preserve backward movement
* when leaving insert mode, an 'l' must be
* done to compensate for the left done by
* the <esc> (except when cursor is already
* in the first column: i.e., outcol = 0).
*/
switch (commch) {
case 'R':
st = (unsigned char *)"R";
else
if (outcol == 0)
st = (unsigned char *)"R";
else
st = (unsigned char *)"lR";
break;
case 'i':
st = (unsigned char *)"i";
else
if (outcol == 0)
st = (unsigned char *)"i";
else
st = (unsigned char *)"li";
break;
case 'a':
st = (unsigned char *)"i";
else
st = (unsigned char *)"a";
break;
default:
st = (unsigned char *)"i";
}
else
/*
* Macros such as function keys are
* performed by leaving the insert,
* replace, or append mode, executing
* the proper cursor movement commands
* and returning to the mode we are
* currently in (commch).
*/
}
c = getkey();
#ifdef MDEBUG
if (trace)
#endif
return(c); /* first char of map string */
contin:;
}
}
#ifdef MDEBUG
if (trace)
#endif
macpush(&b[1],0);
return(c);
}
/*
* Push st onto the front of vmacp. This is tricky because we have to
* worry about where vmacp was previously pointing. We also have to
* check for overflow (which is typically from a recursive macro)
* Finally we have to set a flag so the whole thing can be undone.
* canundo is 1 iff we want to be able to undo the macro. This
* is false for, for example, pushing back lookahead from fastpeekkey(),
* since otherwise two fast escapes can clobber our undo.
*/
void
{
return;
#ifdef MDEBUG
if (trace)
#endif
gettext("Macro too long - maybe recursive?"));
if (vmacp) {
if (!FIXUNDO)
canundo = 0; /* can't undo inside a macro anyway */
}
if (vmacp)
/* arrange to be able to undo the whole macro */
if (canundo) {
#ifdef notdef
vsave();
saveall();
#endif
}
}
#ifdef UNDOTRACE
visdump(s)
unsigned char *s;
{
int i;
if (!trace) return;
for (i=0; i<TUBELINES; i++)
tvliny();
}
vudump(s)
unsigned char *s;
{
line *p;
unsigned char savelb[1024];
if (!trace) return;
getline(*p);
}
}
#endif
/*
* Get a count from the keyed input stream.
* A zero count is indistinguishable from no count.
*/
int
vgetcnt(void)
{
int c, cnt;
cnt = 0;
for (;;) {
c = getkey();
if (!isdigit(c))
break;
}
ungetkey(c);
Xhadcnt = 1;
return(cnt);
}
/*
* fastpeekkey is just like peekkey but insists the character come in
* fast (within 1 second). This will succeed if it is the 2nd char of
* a machine generated sequence (such as a function pad from an escape
* flavor terminal) but fail for a human hitting escape then waiting.
*/
int
fastpeekkey(void)
{
void trapalarm();
int c;
/*
* If the user has set notimeout, we wait forever for a key.
* If we are in a macro we do too, but since it's already
* buffered internally it will return immediately.
* In other cases we force this to die in 1 second.
* This is pretty reliable (VMUNIX rounds it to .5 - 1.5 secs,
* but UNIX truncates it to 0 - 1 secs) but due to system delays
* there are times when arrow keys or very fast typing get counted
* as separate. notimeout is provided for people who dislike such
* nondeterminism.
*/
setalarm();
}
c = peekkey();
cancelalarm();
c = 0;
/* Should have an alternative method based on select for 4.2BSD */
return(c);
}
static int ftfd;
struct requestbuf {
short time;
short signo;
};
/*
* Arrange for SIGALRM to come in shortly, so we don't
* hang very long if the user didn't type anything. There are
* various ways to do this on different systems.
*/
void
setalarm(void)
{
unsigned char ftname[20];
struct requestbuf rb;
#ifdef FTIOCSET
/*
* Use nonstandard "fast timer" to get better than
* one second resolution. We must wait at least
* 1/15th of a second because some keypads don't
* transmit faster than this.
*/
/* Open ft psuedo-device - we need our own copy. */
if (ftfd == 0) {
if (ftfd <= 0)
ftname[7] ++;
}
}
alarm(1);
} else {
}
#else
/*
* No special capabilities, so we use alarm, with 1 sec. resolution.
*/
alarm(1);
#endif
}
/*
* Get rid of any impending incoming SIGALRM.
*/
void
cancelalarm(void)
{
struct requestbuf rb;
#ifdef FTIOCSET
if (ftfd > 0) {
}
#endif
alarm(0); /* Have to do this whether or not FTIOCSET */
}
void trapalarm() {
alarm(0);
}