diff options
Diffstat (limited to 'ex_vget.c')
-rw-r--r-- | ex_vget.c | 879 |
1 files changed, 879 insertions, 0 deletions
diff --git a/ex_vget.c b/ex_vget.c new file mode 100644 index 0000000..e3a50d0 --- /dev/null +++ b/ex_vget.c @@ -0,0 +1,879 @@ +/* + * This code contains changes by + * Gunnar Ritter, Freiburg i. Br., Germany, 2002. All rights reserved. + * + * Conditions 1, 2, and 4 and the no-warranty notice below apply + * to these changes. + * + * + * Copyright (c) 1980, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * + * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * Redistributions of source code and documentation must retain the + * above copyright notice, this list of conditions and the following + * disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed or owned by Caldera + * International, Inc. + * Neither the name of Caldera International, Inc. nor the names of + * other contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA + * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE + * LIABLE FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef lint +#ifdef DOSCCS +static char sccsid[] = "@(#)ex_vget.c 1.29 (gritter) 2/15/05"; +#endif +#endif + +/* from ex_vget.c 6.8.1 (2.11BSD GTE) 12/9/94 */ + +#include "ex.h" +#include "ex_tty.h" +#include "ex_vis.h" + +/* + * Input routines for open/visual. + * We handle 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 /* mjm: char --> int */ +) +{ + + if (Peekkey != ATTN) + Peekkey = c; +} + +/* + * Return a keystroke, but never a ^@. + */ +int +getkey(void) +{ + register int c; /* mjm: char --> int */ + + do { + c = getbr(); + if (c==0) + beep(); + } while (c == 0); + return (c); +} + +/* + * Tell whether next keystroke would be a ^@. + */ +int +peekbr(void) +{ + + Peekkey = getbr(); + return (Peekkey == 0); +} + +short precbksl; +JMP_BUF readbuf; +int doingread = 0; + +static int +readwc(int fd, int *cp) +{ + int c; + char b; + +#ifdef MB + if (mb_cur_max > 1) { + static char pbuf[2][MB_LEN_MAX], *pend[2], *pcur[2]; + static mbstate_t state[2]; + static int incompl[2]; + int i, rest; + int idx = fd ? 1 : 0; + wchar_t wc; + size_t sz; + + i = 0; + rest = pend[idx] - pcur[idx]; + if (rest && pcur[idx] > pbuf[idx]) { + do + pbuf[idx][i] = pcur[idx][i]; + while (i++, --rest); + } else if (incompl[idx]) { + pend[idx] = pcur[idx] = NULL; + return -1; + } + if (i == 0) { + if ((c = read(fd, &b, 1)) <= 0) { + pend[idx] = pcur[idx] = NULL; + return c; + } + pbuf[idx][i++] = b; + } + if (pbuf[idx][0] & 0200) { + sz = 1; + while ((sz = mbrtowc(&wc, pbuf[idx], i, &state[idx])) + == (size_t)-2 && i < mb_cur_max) { + if ((c = read(fd, &b, 1)) <= 0) { + incompl[idx] = 1; + break; + } else + pbuf[idx][i++] = b; + memset(&state[idx], 0, sizeof state[idx]); + } + if (sz == (size_t)-2 || sz == (size_t)-1 || + !widthok(wc)) { + memset(&state[idx], 0, sizeof state[idx]); + c = 1; + *cp = pbuf[idx][0] | INVBIT; + } else if (sz == 0) { + c = 1; + *cp = wc; + } else { + c = sz; + *cp = wc; + } + } else { + c = 1; + *cp = pbuf[idx][0]; + } + pcur[idx] = &pbuf[idx][c]; + pend[idx] = &pcur[idx][i-c]; + return c; + } else +#endif /* MB */ + { + c = read(fd, &b, 1); + *cp = b; + return c; + } +} + +/* + * 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. + */ +int +getbr(void) +{ + int ch; + register int c; +#ifdef UCVISUAL + register int d; + register char *colp; +#endif +#ifdef BEEHIVE + int cnt; + static char Peek2key; +#endif + extern short slevel, ttyindes; + +getATTN: + if (Peekkey) { + c = Peekkey; + Peekkey = 0; + return (c); + } +#ifdef BEEHIVE + if (Peek2key) { + c = Peek2key; + Peek2key = 0; + return (c); + } +#endif + if (vglobp) { + if (*vglobp) + return (lastvgk = *vglobp++); + lastvgk = 0; + return (ESCAPE); + } + if (vmacp) { + if (*vmacp) { + int n; + nextc(ch, vmacp, n); + vmacp += n; + return (ch); + } + /* End of a macro or set of nested macros */ + vmacp = 0; + if (inopen == -1) /* don't screw up undo for esc esc */ + vundkind = VMANY; + inopen = 1; /* restore old setting now that macro done */ + vch_mac = VC_NOTINMAC; + } + flusho(); + for (c =0; abbrevs[c].mapto; c++) + abbrevs[c].hadthis = 0; +#ifdef UCVISUAL +again: +#endif + if (SETJMP(readbuf)) + goto getATTN; + doingread = 1; + c = readwc(slevel == 0 ? 0 : ttyindes, &ch); + doingread = 0; + if (c < 1) { + if (errno == EINTR) + goto getATTN; + error(catgets(catd, 1, 222, "Input read error")); + } + c = ch & TRIM; +#ifdef BEEHIVE + if (XB && slevel==0 && c == ESCAPE) { + if (readwc(0, &Peek2key) < 1) + goto getATTN; + Peek2key &= TRIM; + 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; + } + } +#endif + +#ifdef UCVISUAL + /* + * The algorithm here is that of the UNIX kernel. + * See the description in the programmers manual. + */ + if (UPPERCASE) { + if (xisupper(c)) + c = xtolower(c); + if (c == '\\') { + if (precbksl < 2) + precbksl++; + if (precbksl == 1) + goto again; + } else if (precbksl) { + d = 0; + if (xislower(c)) + d = xtoupper(c); + else { + colp = "({)}!|^~'~"; + 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; + } +#endif + +#ifdef TRACE + if (trace) { + if (!techoin) { + tfixnl(); + techoin = 1; + fprintf(trace, "*** Input: "); + } + 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) +{ + register int c; + + c = getkey(); + if (c == ATTN) + goto case_ATTN; + switch (c) { + + case CTRL('v'): + case CTRL('q'): + c = getkey(); + return (c); + + case QUIT: +case_ATTN: + ungetkey(c); + return (0); + + case ESCAPE: + return (0); + } + return (c); +} + +/* + * Peek at the next keystroke. + */ +int +peekkey(void) +{ + + Peekkey = getkey(); + 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(int c) +{ + register char *sc = cursor; + register void (*OP)(int); + bool waste; + register int OPeek; + + if (WBOT == WECHO) + vclean(); + else + vclrech(0); + splitw++; + vgoto(WECHO, 0); + putchar(c); + vclreol(); + vgoto(WECHO, 1); + cursor = linebuf; linebuf[0] = 0; genbuf[0] = c; + if (peekbr()) { + if (!INS[0] || (INS[0] & (QUOTE|TRIM)) == OVERBUF) + goto blewit; + vglobp = INS; + } + OP = Pline; Pline = normline; + ignore(vgetline(0, genbuf + 1, &waste, c)); + if (Outchar == termchar) + putchar('\n'); + vscrap(); + Pline = OP; + if (Peekkey != ATTN && Peekkey != QUIT && Peekkey != CTRL('h')) { + cursor = sc; + vclreol(); + return (0); + } +blewit: + OPeek = Peekkey==CTRL('h') ? 0 : Peekkey; Peekkey = 0; + splitw = 0; + vclean(); + vshow(dot, NOLINE); + vnline(sc); + Peekkey = OPeek; + 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) +{ + + if (vglobp || vmacp) + return; + lastreg = vreg; + lasthad = Xhadcnt; + lastcnt = Xcnt; + *lastcp = 0; + cellcpy(lastcmd, workcmd); +} + +/* + * Gather up some more text from an insert. + * If the insertion buffer oveflows, then destroy + * the repeatability of the insert. + */ +void +addtext(char *cp) +{ + + if (vglobp) + return; + addto(INS, cp); + if ((INS[0] & (QUOTE|TRIM)) == OVERBUF) + lastcmd[0] = 0; +} + +void +setDEL(void) +{ + + setBUF(DEL); +} + +/* + * Put text from cursor upto wcursor in BUF. + */ +void +setBUF(register cell *BUF) +{ + register int c; + register char *wp = wcursor; + + c = *wp; + *wp = 0; + BUF[0] = 0; + addto(BUF, cursor); + *wp = c; +} + +void +addto(register cell *buf, register char *str) +{ + + if ((buf[0] & (QUOTE|TRIM)) == OVERBUF) + return; + if (cellen(buf) + strlen(str) + 1 >= VBSIZE) { + buf[0] = OVERBUF; + return; + } + while (*buf) + buf++; + str2cell(buf, str); +} + +/* + * 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 +noteit(int must) +{ + register int sdl = destline, sdc = destcol; + + if (notecnt < 2 || !must && state == VISUAL) + return (0); + splitw++; + if (WBOT == WECHO) + vmoveitup(1, 1); + vigoto(WECHO, 0); + printf(catgets(catd, 1, 223, "%d %sline"), notecnt, notesgn); + if (notecnt > 1) + putchar('s'); + if (*notenam) { + printf(" %s", notenam); + if (*(strend(notenam) - 1) != 'e') + putchar('e'); + putchar('d'); + } + vclreol(); + notecnt = 0; + if (state != VISUAL) + vcnt = vcline = 0; + splitw = 0; + if (state == ONEOPEN || state == CRTOPEN) + vup1(); + destline = sdl; destcol = sdc; + return (1); +} + +/* + * Rrrrringgggggg. + * If possible, use flash (VB). + */ +void +beep(void) +{ + + if (VB && value(FLASH)) + vputp(VB, 0); + else + vputc(CTRL('g')); +} + +/* + * Push an integer string as a macro. + */ +static void +imacpush(int *ip, int canundo) +{ + char buf[BUFSIZ], *bp = buf; + +#ifdef MB + do { + int n; + n = wctomb(bp, *ip&TRIM); + bp += n; + } while (*ip++); +#else /* !MB */ + while (*bp++ = *ip++); +#endif /* !MB */ + macpush(buf, canundo); +} + +/* + * 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 +map(register int c, register struct maps *maps) +{ + register int d; + register int *p, *q; + int b[10+MB_LEN_MAX]; /* Assumption: no keypad sends string longer than 10 */ + + /* + * 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) + fprintf(trace,"map(%c): ",c); +#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; + for (d=0; maps[d].mapto; d++) { +#ifdef MDEBUG + if (trace) + fprintf(trace,"\ntry '%s', ",maps[d].cap); +#endif + if (p = maps[d].icap) { + for (q=b; *p; p++, q++) { +#ifdef MDEBUG + if (trace) + fprintf(trace,"q->b[%d], ",q-b); +#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. + */ + if ((c=='#' ? peekkey() : fastpeekkey()) == 0) { +#ifdef MDEBUG + if (trace) + fprintf(trace,"fpk=0: will return '%c'",c); +#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) + fprintf(trace, "Call macpush, b %d %d %d\n", b[0], b[1], b[2]); +#endif + imacpush(&b[1],maps == arrows); +#ifdef MDEBUG + if (trace) + fprintf(trace, "return %d\n", c); +#endif + return(c); + } + *q = getkey(); + q[1] = 0; + } + if (*p != *q) + goto contin; + } + macpush(maps[d].mapto,maps == arrows); + c = getkey(); +#ifdef MDEBUG + if (trace) + fprintf(trace,"Success: push(%s), return %c",maps[d].mapto, c); +#endif + return(c); /* first char of map string */ + contin:; + } + } +#ifdef MDEBUG + if (trace) + fprintf(trace,"Fail: push(%s), return %c", &b[1], c); +#endif + imacpush(&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 +macpush(char *st, int canundo) +{ + char tmpbuf[BUFSIZ]; + + if (st==0 || *st==0) + return; +#ifdef MDEBUG + if (trace) + fprintf(trace, "macpush(%s), canundo=%d\n",st,canundo); +#endif + if ((vmacp ? strlen(vmacp) : 0) + strlen(st) > BUFSIZ) + error(catgets(catd, 1, 224, + "Macro too long@ - maybe recursive?")); + if (vmacp) { + strcpy(tmpbuf, vmacp); + if (!FIXUNDO) + canundo = 0; /* can't undo inside a macro anyway */ + } + strcpy(vmacbuf, st); + if (vmacp) + strcat(vmacbuf, tmpbuf); + vmacp = vmacbuf; + /* arrange to be able to undo the whole macro */ + if (canundo) { +#ifdef notdef + otchng = tchng; + vsave(); + saveall(); + inopen = -1; /* no need to save since it had to be 1 or -1 before */ + vundkind = VMANY; +#endif + vch_mac = VC_NOCHANGE; + } +} + +#ifdef TRACE +void +visdump(char *s) +{ + register int i; + + if (!trace) return; + + fprintf(trace, "\n%s: basWTOP=%d, basWLINES=%d, WTOP=%d, WBOT=%d, WLINES=%d, WCOLS=%d, WECHO=%d\n", + s, basWTOP, basWLINES, WTOP, WBOT, WLINES, WCOLS, WECHO); + fprintf(trace, " vcnt=%d, vcline=%d, cursor=%d, wcursor=%d, wdot=%d\n", + vcnt, vcline, cursor-linebuf, wcursor-linebuf, wdot-zero); + for (i=0; i<TUBELINES; i++) + if (vtube[i] && *vtube[i]) + fprintf(trace, "%d: '%s'\n", i, vtube[i]); + tvliny(); +} + +void +vudump(char *s) +{ + register line *p; + char savelb[1024]; + + if (!trace) return; + + fprintf(trace, "\n%s: undkind=%d, vundkind=%d, unddel=%d, undap1=%d, undap2=%d,\n", + s, undkind, vundkind, lineno(unddel), lineno(undap1), lineno(undap2)); + fprintf(trace, " undadot=%d, dot=%d, dol=%d, unddol=%d, truedol=%d\n", + lineno(undadot), lineno(dot), lineno(dol), lineno(unddol), lineno(truedol)); + fprintf(trace, " [\n"); + CP(savelb, linebuf); + fprintf(trace, "linebuf = '%s'\n", linebuf); + for (p=zero+1; p<=truedol; p++) { + fprintf(trace, "%o ", *p); + getline(*p); + fprintf(trace, "'%s'\n", linebuf); + } + fprintf(trace, "]\n"); + CP(linebuf, savelb); +} +#endif + +/* + * Get a count from the keyed input stream. + * A zero count is indistinguishable from no count. + */ +int +vgetcnt(void) +{ + register int c, cnt; + + cnt = 0; + for (;;) { + c = getkey(); + if (!xisdigit(c)) + break; + cnt *= 10, cnt += c - '0'; + } + ungetkey(c); + Xhadcnt = 1; + Xcnt = cnt; + return(cnt); +} + +void +trapalarm(int signum) { + alarm(0); + if (vcatch) + LONGJMP(vreslab,1); +} + +/* + * 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) +{ + shand Oint; + register 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. + */ +#ifdef MDEBUG + if (trace) + fprintf(trace,"\nfastpeekkey: ",c); +#endif + Oint = signal(SIGINT, trapalarm); + if (value(TIMEOUT) && inopen >= 0) { + signal(SIGALRM, trapalarm); +#ifdef MDEBUG + alarm(10); + if (trace) + fprintf(trace, "set alarm "); +#else + alarm(1); +#endif + } + CATCH + c = peekkey(); +#ifdef MDEBUG + if (trace) + fprintf(trace,"[OK]",c); +#endif + alarm(0); + ONERR + c = 0; +#ifdef MDEBUG + if (trace) + fprintf(trace,"[TIMEOUT]",c); +#endif + ENDCATCH +#ifdef MDEBUG + if (trace) + fprintf(trace,"[fpk:%o]",c); +#endif + signal(SIGINT,Oint); + return(c); +} |