1cd8169f0Sbostic /*-
2*e049d966Sbostic * Copyright (c) 1980, 1993
3*e049d966Sbostic * The Regents of the University of California. All rights reserved.
4cd8169f0Sbostic *
5cd8169f0Sbostic * %sccs.include.proprietary.c%
6767d0bbbSdist */
7767d0bbbSdist
8767d0bbbSdist #ifndef lint
9*e049d966Sbostic static char sccsid[] = "@(#)ex_vget.c 8.1 (Berkeley) 06/09/93";
10cd8169f0Sbostic #endif /* not lint */
11767d0bbbSdist
124e1fedf7Smark #include "ex.h"
134e1fedf7Smark #include "ex_tty.h"
144e1fedf7Smark #include "ex_vis.h"
154e1fedf7Smark
164e1fedf7Smark /*
174e1fedf7Smark * Input routines for open/visual.
184e1fedf7Smark * We handle upper case only terminals in visual and reading from the
194e1fedf7Smark * echo area here as well as notification on large changes
204e1fedf7Smark * which appears in the echo area.
214e1fedf7Smark */
224e1fedf7Smark
234e1fedf7Smark /*
244e1fedf7Smark * Return the key.
254e1fedf7Smark */
ungetkey(c)264e1fedf7Smark ungetkey(c)
27c93a6a15Sdist int c; /* mjm: char --> int */
284e1fedf7Smark {
294e1fedf7Smark
30c0a5300eSconrad if (Peek_key != ATTN)
31c0a5300eSconrad Peek_key = c;
324e1fedf7Smark }
334e1fedf7Smark
344e1fedf7Smark /*
354e1fedf7Smark * Return a keystroke, but never a ^@.
364e1fedf7Smark */
getkey()374e1fedf7Smark getkey()
384e1fedf7Smark {
39c93a6a15Sdist register int c; /* mjm: char --> int */
404e1fedf7Smark
414e1fedf7Smark do {
424e1fedf7Smark c = getbr();
434e1fedf7Smark if (c==0)
444e1fedf7Smark beep();
454e1fedf7Smark } while (c == 0);
464e1fedf7Smark return (c);
474e1fedf7Smark }
484e1fedf7Smark
494e1fedf7Smark /*
504e1fedf7Smark * Tell whether next keystroke would be a ^@.
514e1fedf7Smark */
peekbr()524e1fedf7Smark peekbr()
534e1fedf7Smark {
544e1fedf7Smark
55c0a5300eSconrad Peek_key = getbr();
56c0a5300eSconrad return (Peek_key == 0);
574e1fedf7Smark }
584e1fedf7Smark
594e1fedf7Smark short precbksl;
60c93a6a15Sdist jmp_buf readbuf;
61c93a6a15Sdist int doingread = 0;
624e1fedf7Smark
634e1fedf7Smark /*
644e1fedf7Smark * Get a keystroke, including a ^@.
654e1fedf7Smark * If an key was returned with ungetkey, that
664e1fedf7Smark * comes back first. Next comes unread input (e.g.
674e1fedf7Smark * from repeating commands with .), and finally new
684e1fedf7Smark * keystrokes.
694e1fedf7Smark *
704e1fedf7Smark * The hard work here is in mapping of \ escaped
714e1fedf7Smark * characters on upper case only terminals.
724e1fedf7Smark */
getbr()734e1fedf7Smark getbr()
744e1fedf7Smark {
754e1fedf7Smark char ch;
764e1fedf7Smark register int c, d;
774e1fedf7Smark register char *colp;
782f4283ecSmark #define BEEHIVE
792f4283ecSmark #ifdef BEEHIVE
802f4283ecSmark static char Peek2key;
812f4283ecSmark #endif
822f4283ecSmark extern short slevel, ttyindes;
834e1fedf7Smark
844e1fedf7Smark getATTN:
85c0a5300eSconrad if (Peek_key) {
86c0a5300eSconrad c = Peek_key;
87c0a5300eSconrad Peek_key = 0;
884e1fedf7Smark return (c);
894e1fedf7Smark }
902f4283ecSmark #ifdef BEEHIVE
912f4283ecSmark if (Peek2key) {
922f4283ecSmark c = Peek2key;
932f4283ecSmark Peek2key = 0;
942f4283ecSmark return (c);
952f4283ecSmark }
962f4283ecSmark #endif
974e1fedf7Smark if (vglobp) {
984e1fedf7Smark if (*vglobp)
994e1fedf7Smark return (lastvgk = *vglobp++);
1004e1fedf7Smark lastvgk = 0;
1014e1fedf7Smark return (ESCAPE);
1024e1fedf7Smark }
1034e1fedf7Smark if (vmacp) {
1044e1fedf7Smark if (*vmacp)
1054e1fedf7Smark return(*vmacp++);
1064e1fedf7Smark /* End of a macro or set of nested macros */
1074e1fedf7Smark vmacp = 0;
108933430aaSmark if (inopen == -1) /* don't screw up undo for esc esc */
1094e1fedf7Smark vundkind = VMANY;
110933430aaSmark inopen = 1; /* restore old setting now that macro done */
1112f4283ecSmark vch_mac = VC_NOTINMAC;
1124e1fedf7Smark }
1134e1fedf7Smark flusho();
1144e1fedf7Smark again:
115c93a6a15Sdist if (setjmp(readbuf))
116c93a6a15Sdist goto getATTN;
117c93a6a15Sdist doingread = 1;
118c0a5300eSconrad #ifndef vms
119c93a6a15Sdist c = read(slevel == 0 ? 0 : ttyindes, &ch, 1);
120c0a5300eSconrad #else
121c0a5300eSconrad c = vms_read(slevel == 0 ? 0 : ttyindes, &ch, 1);
122c0a5300eSconrad #endif
123c93a6a15Sdist doingread = 0;
124c93a6a15Sdist if (c != 1) {
1254e1fedf7Smark if (errno == EINTR)
1264e1fedf7Smark goto getATTN;
1274e1fedf7Smark error("Input read error");
1284e1fedf7Smark }
1294e1fedf7Smark c = ch & TRIM;
1302f4283ecSmark #ifdef BEEHIVE
1312f4283ecSmark if (XB && slevel==0 && c == ESCAPE) {
1322f4283ecSmark if (read(0, &Peek2key, 1) != 1)
1332f4283ecSmark goto getATTN;
1342f4283ecSmark Peek2key &= TRIM;
1352f4283ecSmark switch (Peek2key) {
1362f4283ecSmark case 'C': /* SPOW mode sometimes sends \EC for space */
1372f4283ecSmark c = ' ';
1382f4283ecSmark Peek2key = 0;
1392f4283ecSmark break;
1402f4283ecSmark case 'q': /* f2 -> ^C */
1412949201cSbostic c = CTRL('c');
1422f4283ecSmark Peek2key = 0;
1432f4283ecSmark break;
1442f4283ecSmark case 'p': /* f1 -> esc */
1452f4283ecSmark Peek2key = 0;
1462f4283ecSmark break;
1472f4283ecSmark }
1482f4283ecSmark }
1492f4283ecSmark #endif
1504e1fedf7Smark
1514e1fedf7Smark #ifdef UCVISUAL
1524e1fedf7Smark /*
1534e1fedf7Smark * The algorithm here is that of the UNIX kernel.
1544e1fedf7Smark * See the description in the programmers manual.
1554e1fedf7Smark */
1564e1fedf7Smark if (UPPERCASE) {
1574e1fedf7Smark if (isupper(c))
1584e1fedf7Smark c = tolower(c);
1594e1fedf7Smark if (c == '\\') {
1604e1fedf7Smark if (precbksl < 2)
1614e1fedf7Smark precbksl++;
1624e1fedf7Smark if (precbksl == 1)
1634e1fedf7Smark goto again;
1644e1fedf7Smark } else if (precbksl) {
1654e1fedf7Smark d = 0;
1664e1fedf7Smark if (islower(c))
1674e1fedf7Smark d = toupper(c);
1684e1fedf7Smark else {
1694e1fedf7Smark colp = "({)}!|^~'~";
1704e1fedf7Smark while (d = *colp++)
1714e1fedf7Smark if (d == c) {
1724e1fedf7Smark d = *colp++;
1734e1fedf7Smark break;
1744e1fedf7Smark } else
1754e1fedf7Smark colp++;
1764e1fedf7Smark }
1774e1fedf7Smark if (precbksl == 2) {
1784e1fedf7Smark if (!d) {
179c0a5300eSconrad Peek_key = c;
1804e1fedf7Smark precbksl = 0;
1814e1fedf7Smark c = '\\';
1824e1fedf7Smark }
1834e1fedf7Smark } else if (d)
1844e1fedf7Smark c = d;
1854e1fedf7Smark else {
186c0a5300eSconrad Peek_key = c;
1874e1fedf7Smark precbksl = 0;
1884e1fedf7Smark c = '\\';
1894e1fedf7Smark }
1904e1fedf7Smark }
1914e1fedf7Smark if (c != '\\')
1924e1fedf7Smark precbksl = 0;
1934e1fedf7Smark }
1944e1fedf7Smark #endif
1954e1fedf7Smark #ifdef TRACE
1964e1fedf7Smark if (trace) {
1974e1fedf7Smark if (!techoin) {
1984e1fedf7Smark tfixnl();
1994e1fedf7Smark techoin = 1;
2004e1fedf7Smark fprintf(trace, "*** Input: ");
2014e1fedf7Smark }
2024e1fedf7Smark tracec(c);
2034e1fedf7Smark }
2044e1fedf7Smark #endif
2054e1fedf7Smark lastvgk = 0;
2064e1fedf7Smark return (c);
2074e1fedf7Smark }
2084e1fedf7Smark
2094e1fedf7Smark /*
2104e1fedf7Smark * Get a key, but if a delete, quit or attention
2114e1fedf7Smark * is typed return 0 so we will abort a partial command.
2124e1fedf7Smark */
getesc()2134e1fedf7Smark getesc()
2144e1fedf7Smark {
2154e1fedf7Smark register int c;
2164e1fedf7Smark
2174e1fedf7Smark c = getkey();
2184e1fedf7Smark switch (c) {
2194e1fedf7Smark
2202949201cSbostic case CTRL('v'):
2212949201cSbostic case CTRL('q'):
22214b70d95Smark c = getkey();
22314b70d95Smark return (c);
22414b70d95Smark
2254e1fedf7Smark case ATTN:
2264e1fedf7Smark case QUIT:
2274e1fedf7Smark ungetkey(c);
2284e1fedf7Smark return (0);
2294e1fedf7Smark
2304e1fedf7Smark case ESCAPE:
2314e1fedf7Smark return (0);
2324e1fedf7Smark }
2334e1fedf7Smark return (c);
2344e1fedf7Smark }
2354e1fedf7Smark
2364e1fedf7Smark /*
2374e1fedf7Smark * Peek at the next keystroke.
2384e1fedf7Smark */
peekkey()2394e1fedf7Smark peekkey()
2404e1fedf7Smark {
2414e1fedf7Smark
242c0a5300eSconrad Peek_key = getkey();
243c0a5300eSconrad return (Peek_key);
2444e1fedf7Smark }
2454e1fedf7Smark
2464e1fedf7Smark /*
2474e1fedf7Smark * Read a line from the echo area, with single character prompt c.
2484e1fedf7Smark * A return value of 1 means the user blewit or blewit away.
2494e1fedf7Smark */
readecho(c)2504e1fedf7Smark readecho(c)
2514e1fedf7Smark char c;
2524e1fedf7Smark {
2534e1fedf7Smark register char *sc = cursor;
2544e1fedf7Smark register int (*OP)();
2554e1fedf7Smark bool waste;
2564e1fedf7Smark register int OPeek;
2574e1fedf7Smark
2584e1fedf7Smark if (WBOT == WECHO)
2594e1fedf7Smark vclean();
2604e1fedf7Smark else
2614e1fedf7Smark vclrech(0);
2624e1fedf7Smark splitw++;
2634e1fedf7Smark vgoto(WECHO, 0);
264c0a5300eSconrad ex_putchar(c);
2654e1fedf7Smark vclreol();
2664e1fedf7Smark vgoto(WECHO, 1);
2674e1fedf7Smark cursor = linebuf; linebuf[0] = 0; genbuf[0] = c;
2684e1fedf7Smark if (peekbr()) {
2694e1fedf7Smark if (!INS[0] || (INS[0] & (QUOTE|TRIM)) == OVERBUF)
2704e1fedf7Smark goto blewit;
2714e1fedf7Smark vglobp = INS;
2724e1fedf7Smark }
2734e1fedf7Smark OP = Pline; Pline = normline;
274c93a6a15Sdist ignore(vgetline(0, genbuf + 1, &waste, c));
2752f4283ecSmark if (Outchar == termchar)
276c0a5300eSconrad ex_putchar('\n');
2774e1fedf7Smark vscrap();
2784e1fedf7Smark Pline = OP;
2792949201cSbostic if (Peek_key != ATTN && Peek_key != QUIT && Peek_key != CTRL('h')) {
2804e1fedf7Smark cursor = sc;
2814e1fedf7Smark vclreol();
2824e1fedf7Smark return (0);
2834e1fedf7Smark }
2844e1fedf7Smark blewit:
2852949201cSbostic OPeek = Peek_key==CTRL('h') ? 0 : Peek_key; Peek_key = 0;
2864e1fedf7Smark splitw = 0;
2874e1fedf7Smark vclean();
2884e1fedf7Smark vshow(dot, NOLINE);
2894e1fedf7Smark vnline(sc);
290c0a5300eSconrad Peek_key = OPeek;
2914e1fedf7Smark return (1);
2924e1fedf7Smark }
2934e1fedf7Smark
2944e1fedf7Smark /*
2954e1fedf7Smark * A complete command has been defined for
2964e1fedf7Smark * the purposes of repeat, so copy it from
2974e1fedf7Smark * the working to the previous command buffer.
2984e1fedf7Smark */
setLAST()2994e1fedf7Smark setLAST()
3004e1fedf7Smark {
3014e1fedf7Smark
3022f4283ecSmark if (vglobp || vmacp)
3034e1fedf7Smark return;
3044e1fedf7Smark lastreg = vreg;
3054e1fedf7Smark lasthad = Xhadcnt;
3064e1fedf7Smark lastcnt = Xcnt;
3074e1fedf7Smark *lastcp = 0;
3084e1fedf7Smark CP(lastcmd, workcmd);
3094e1fedf7Smark }
3104e1fedf7Smark
3114e1fedf7Smark /*
3124e1fedf7Smark * Gather up some more text from an insert.
3134e1fedf7Smark * If the insertion buffer oveflows, then destroy
3144e1fedf7Smark * the repeatability of the insert.
3154e1fedf7Smark */
addtext(cp)3164e1fedf7Smark addtext(cp)
3174e1fedf7Smark char *cp;
3184e1fedf7Smark {
3194e1fedf7Smark
3204e1fedf7Smark if (vglobp)
3214e1fedf7Smark return;
3224e1fedf7Smark addto(INS, cp);
3234e1fedf7Smark if ((INS[0] & (QUOTE|TRIM)) == OVERBUF)
3244e1fedf7Smark lastcmd[0] = 0;
3254e1fedf7Smark }
3264e1fedf7Smark
setDEL()3274e1fedf7Smark setDEL()
3284e1fedf7Smark {
3294e1fedf7Smark
330c0a5300eSconrad ex_setBUF(DEL);
3314e1fedf7Smark }
3324e1fedf7Smark
3334e1fedf7Smark /*
3344e1fedf7Smark * Put text from cursor upto wcursor in BUF.
3354e1fedf7Smark */
ex_setBUF(BUF)336c0a5300eSconrad ex_setBUF(BUF)
3374e1fedf7Smark register char *BUF;
3384e1fedf7Smark {
3394e1fedf7Smark register int c;
3404e1fedf7Smark register char *wp = wcursor;
3414e1fedf7Smark
3424e1fedf7Smark c = *wp;
3434e1fedf7Smark *wp = 0;
3444e1fedf7Smark BUF[0] = 0;
3454e1fedf7Smark addto(BUF, cursor);
3464e1fedf7Smark *wp = c;
3474e1fedf7Smark }
3484e1fedf7Smark
addto(buf,str)3494e1fedf7Smark addto(buf, str)
3504e1fedf7Smark register char *buf, *str;
3514e1fedf7Smark {
3524e1fedf7Smark
3534e1fedf7Smark if ((buf[0] & (QUOTE|TRIM)) == OVERBUF)
3544e1fedf7Smark return;
3554e1fedf7Smark if (strlen(buf) + strlen(str) + 1 >= VBSIZE) {
3564e1fedf7Smark buf[0] = OVERBUF;
3574e1fedf7Smark return;
3584e1fedf7Smark }
3594e1fedf7Smark ignore(strcat(buf, str));
3604e1fedf7Smark }
3614e1fedf7Smark
3624e1fedf7Smark /*
3634e1fedf7Smark * Note a change affecting a lot of lines, or non-visible
3644e1fedf7Smark * lines. If the parameter must is set, then we only want
3654e1fedf7Smark * to do this for open modes now; return and save for later
3664e1fedf7Smark * notification in visual.
3674e1fedf7Smark */
noteit(must)3684e1fedf7Smark noteit(must)
3694e1fedf7Smark bool must;
3704e1fedf7Smark {
3714e1fedf7Smark register int sdl = destline, sdc = destcol;
3724e1fedf7Smark
3734e1fedf7Smark if (notecnt < 2 || !must && state == VISUAL)
3744e1fedf7Smark return (0);
3754e1fedf7Smark splitw++;
3764e1fedf7Smark if (WBOT == WECHO)
3774e1fedf7Smark vmoveitup(1, 1);
3784e1fedf7Smark vigoto(WECHO, 0);
379c0a5300eSconrad ex_printf("%d %sline", notecnt, notesgn);
3804e1fedf7Smark if (notecnt > 1)
381c0a5300eSconrad ex_putchar('s');
3824e1fedf7Smark if (*notenam) {
383c0a5300eSconrad ex_printf(" %s", notenam);
3844e1fedf7Smark if (*(strend(notenam) - 1) != 'e')
385c0a5300eSconrad ex_putchar('e');
386c0a5300eSconrad ex_putchar('d');
3874e1fedf7Smark }
3884e1fedf7Smark vclreol();
3894e1fedf7Smark notecnt = 0;
3904e1fedf7Smark if (state != VISUAL)
3914e1fedf7Smark vcnt = vcline = 0;
3924e1fedf7Smark splitw = 0;
3934e1fedf7Smark if (state == ONEOPEN || state == CRTOPEN)
3944e1fedf7Smark vup1();
3954e1fedf7Smark destline = sdl; destcol = sdc;
3964e1fedf7Smark return (1);
3974e1fedf7Smark }
3984e1fedf7Smark
3994e1fedf7Smark /*
4004e1fedf7Smark * Rrrrringgggggg.
4014e1fedf7Smark * If possible, use flash (VB).
4024e1fedf7Smark */
beep()4034e1fedf7Smark beep()
4044e1fedf7Smark {
4054e1fedf7Smark
4064e1fedf7Smark if (VB)
4074e1fedf7Smark vputp(VB, 0);
4084e1fedf7Smark else
4092949201cSbostic vputc(CTRL('g'));
4104e1fedf7Smark }
4114e1fedf7Smark
4124e1fedf7Smark /*
4134e1fedf7Smark * Map the command input character c,
4144e1fedf7Smark * for keypads and labelled keys which do cursor
4154e1fedf7Smark * motions. I.e. on an adm3a we might map ^K to ^P.
4164e1fedf7Smark * DM1520 for example has a lot of mappable characters.
4174e1fedf7Smark */
4184e1fedf7Smark
map(c,maps)4194e1fedf7Smark map(c,maps)
4204e1fedf7Smark register int c;
4214e1fedf7Smark register struct maps *maps;
4224e1fedf7Smark {
4234e1fedf7Smark register int d;
4244e1fedf7Smark register char *p, *q;
4254e1fedf7Smark char b[10]; /* Assumption: no keypad sends string longer than 10 */
4264e1fedf7Smark
4274e1fedf7Smark /*
4284e1fedf7Smark * Mapping for special keys on the terminal only.
4294e1fedf7Smark * BUG: if there's a long sequence and it matches
4304e1fedf7Smark * some chars and then misses, we lose some chars.
4314e1fedf7Smark *
4324e1fedf7Smark * For this to work, some conditions must be met.
4334e1fedf7Smark * 1) Keypad sends SHORT (2 or 3 char) strings
4344e1fedf7Smark * 2) All strings sent are same length & similar
4354e1fedf7Smark * 3) The user is unlikely to type the first few chars of
4364e1fedf7Smark * one of these strings very fast.
4374e1fedf7Smark * Note: some code has been fixed up since the above was laid out,
4384e1fedf7Smark * so conditions 1 & 2 are probably not required anymore.
4394e1fedf7Smark * However, this hasn't been tested with any first char
4404e1fedf7Smark * that means anything else except escape.
4414e1fedf7Smark */
4424e1fedf7Smark #ifdef MDEBUG
4434e1fedf7Smark if (trace)
4444e1fedf7Smark fprintf(trace,"map(%c): ",c);
4454e1fedf7Smark #endif
4462f4283ecSmark /*
4472f4283ecSmark * If c==0, the char came from getesc typing escape. Pass it through
4482f4283ecSmark * unchanged. 0 messes up the following code anyway.
4492f4283ecSmark */
4502f4283ecSmark if (c==0)
4512f4283ecSmark return(0);
4522f4283ecSmark
4534e1fedf7Smark b[0] = c;
4544e1fedf7Smark b[1] = 0;
4554e1fedf7Smark for (d=0; maps[d].mapto; d++) {
4564e1fedf7Smark #ifdef MDEBUG
4574e1fedf7Smark if (trace)
4582f4283ecSmark fprintf(trace,"\ntry '%s', ",maps[d].cap);
4594e1fedf7Smark #endif
4604e1fedf7Smark if (p = maps[d].cap) {
4614e1fedf7Smark for (q=b; *p; p++, q++) {
4624e1fedf7Smark #ifdef MDEBUG
4634e1fedf7Smark if (trace)
4644e1fedf7Smark fprintf(trace,"q->b[%d], ",q-b);
4654e1fedf7Smark #endif
4664e1fedf7Smark if (*q==0) {
4674e1fedf7Smark /*
4682f4283ecSmark * Is there another char waiting?
4692f4283ecSmark *
4704e1fedf7Smark * This test is oversimplified, but
4714e1fedf7Smark * should work mostly. It handles the
4724e1fedf7Smark * case where we get an ESCAPE that
4734e1fedf7Smark * wasn't part of a keypad string.
4744e1fedf7Smark */
4754e1fedf7Smark if ((c=='#' ? peekkey() : fastpeekkey()) == 0) {
4764e1fedf7Smark #ifdef MDEBUG
4774e1fedf7Smark if (trace)
478c93a6a15Sdist fprintf(trace,"fpk=0: will return '%c'",c);
4794e1fedf7Smark #endif
48014b70d95Smark /*
4812f4283ecSmark * Nothing waiting. Push back
4822f4283ecSmark * what we peeked at & return
4832f4283ecSmark * failure (c).
4842f4283ecSmark *
48514b70d95Smark * We want to be able to undo
48614b70d95Smark * commands, but it's nonsense
48714b70d95Smark * to undo part of an insertion
48814b70d95Smark * so if in input mode don't.
48914b70d95Smark */
490c93a6a15Sdist #ifdef MDEBUG
491c93a6a15Sdist if (trace)
492c93a6a15Sdist fprintf(trace, "Call macpush, b %d %d %d\n", b[0], b[1], b[2]);
493c93a6a15Sdist #endif
49414b70d95Smark macpush(&b[1],maps == arrows);
495c93a6a15Sdist #ifdef MDEBUG
496c93a6a15Sdist if (trace)
497c93a6a15Sdist fprintf(trace, "return %d\n", c);
498c93a6a15Sdist #endif
4994e1fedf7Smark return(c);
5004e1fedf7Smark }
5014e1fedf7Smark *q = getkey();
5024e1fedf7Smark q[1] = 0;
5034e1fedf7Smark }
5044e1fedf7Smark if (*p != *q)
5054e1fedf7Smark goto contin;
5064e1fedf7Smark }
5072f4283ecSmark macpush(maps[d].mapto,maps == arrows);
5084e1fedf7Smark c = getkey();
5094e1fedf7Smark #ifdef MDEBUG
5104e1fedf7Smark if (trace)
5112f4283ecSmark fprintf(trace,"Success: push(%s), return %c",maps[d].mapto, c);
5124e1fedf7Smark #endif
5134e1fedf7Smark return(c); /* first char of map string */
5144e1fedf7Smark contin:;
5154e1fedf7Smark }
5164e1fedf7Smark }
5174e1fedf7Smark #ifdef MDEBUG
5184e1fedf7Smark if (trace)
5192f4283ecSmark fprintf(trace,"Fail: push(%s), return %c", &b[1], c);
5204e1fedf7Smark #endif
521933430aaSmark macpush(&b[1],0);
5224e1fedf7Smark return(c);
5234e1fedf7Smark }
5244e1fedf7Smark
5254e1fedf7Smark /*
5264e1fedf7Smark * Push st onto the front of vmacp. This is tricky because we have to
5274e1fedf7Smark * worry about where vmacp was previously pointing. We also have to
5284e1fedf7Smark * check for overflow (which is typically from a recursive macro)
5294e1fedf7Smark * Finally we have to set a flag so the whole thing can be undone.
530933430aaSmark * canundo is 1 iff we want to be able to undo the macro. This
531933430aaSmark * is false for, for example, pushing back lookahead from fastpeekkey(),
532933430aaSmark * since otherwise two fast escapes can clobber our undo.
5334e1fedf7Smark */
macpush(st,canundo)534933430aaSmark macpush(st, canundo)
5354e1fedf7Smark char *st;
536933430aaSmark int canundo;
5374e1fedf7Smark {
5384e1fedf7Smark char tmpbuf[BUFSIZ];
5394e1fedf7Smark
5404e1fedf7Smark if (st==0 || *st==0)
5414e1fedf7Smark return;
542c93a6a15Sdist #ifdef MDEBUG
5434e1fedf7Smark if (trace)
5442f4283ecSmark fprintf(trace, "macpush(%s), canundo=%d\n",st,canundo);
5454e1fedf7Smark #endif
54614b70d95Smark if ((vmacp ? strlen(vmacp) : 0) + strlen(st) > BUFSIZ)
5474e1fedf7Smark error("Macro too long@ - maybe recursive?");
548933430aaSmark if (vmacp) {
5494e1fedf7Smark strcpy(tmpbuf, vmacp);
55014b70d95Smark if (!FIXUNDO)
551933430aaSmark canundo = 0; /* can't undo inside a macro anyway */
552933430aaSmark }
5534e1fedf7Smark strcpy(vmacbuf, st);
5544e1fedf7Smark if (vmacp)
5554e1fedf7Smark strcat(vmacbuf, tmpbuf);
5564e1fedf7Smark vmacp = vmacbuf;
5574e1fedf7Smark /* arrange to be able to undo the whole macro */
558933430aaSmark if (canundo) {
5592f4283ecSmark #ifdef notdef
5604e1fedf7Smark otchng = tchng;
561933430aaSmark vsave();
5624e1fedf7Smark saveall();
56314b70d95Smark inopen = -1; /* no need to save since it had to be 1 or -1 before */
5644e1fedf7Smark vundkind = VMANY;
5652f4283ecSmark #endif
5662f4283ecSmark vch_mac = VC_NOCHANGE;
567933430aaSmark }
5684e1fedf7Smark }
5694e1fedf7Smark
57014b70d95Smark #ifdef TRACE
visdump(s)5712f4283ecSmark visdump(s)
5722f4283ecSmark char *s;
5732f4283ecSmark {
5742f4283ecSmark register int i;
5752f4283ecSmark
5762f4283ecSmark if (!trace) return;
5772f4283ecSmark
5782f4283ecSmark fprintf(trace, "\n%s: basWTOP=%d, basWLINES=%d, WTOP=%d, WBOT=%d, WLINES=%d, WCOLS=%d, WECHO=%d\n",
5792f4283ecSmark s, basWTOP, basWLINES, WTOP, WBOT, WLINES, WCOLS, WECHO);
5802f4283ecSmark fprintf(trace, " vcnt=%d, vcline=%d, cursor=%d, wcursor=%d, wdot=%d\n",
5812f4283ecSmark vcnt, vcline, cursor-linebuf, wcursor-linebuf, wdot-zero);
5822f4283ecSmark for (i=0; i<TUBELINES; i++)
5832f4283ecSmark if (vtube[i] && *vtube[i])
5842f4283ecSmark fprintf(trace, "%d: '%s'\n", i, vtube[i]);
5852f4283ecSmark tvliny();
5862f4283ecSmark }
5872f4283ecSmark
vudump(s)58814b70d95Smark vudump(s)
58914b70d95Smark char *s;
59014b70d95Smark {
5912f4283ecSmark register line *p;
592c93a6a15Sdist char savelb[1024];
5932f4283ecSmark
5942f4283ecSmark if (!trace) return;
5952f4283ecSmark
5962f4283ecSmark fprintf(trace, "\n%s: undkind=%d, vundkind=%d, unddel=%d, undap1=%d, undap2=%d,\n",
5972f4283ecSmark s, undkind, vundkind, lineno(unddel), lineno(undap1), lineno(undap2));
5982f4283ecSmark fprintf(trace, " undadot=%d, dot=%d, dol=%d, unddol=%d, truedol=%d\n",
5992f4283ecSmark lineno(undadot), lineno(dot), lineno(dol), lineno(unddol), lineno(truedol));
600c93a6a15Sdist fprintf(trace, " [\n");
601c93a6a15Sdist CP(savelb, linebuf);
602c93a6a15Sdist fprintf(trace, "linebuf = '%s'\n", linebuf);
603c93a6a15Sdist for (p=zero+1; p<=truedol; p++) {
6042f4283ecSmark fprintf(trace, "%o ", *p);
605c93a6a15Sdist getline(*p);
606c93a6a15Sdist fprintf(trace, "'%s'\n", linebuf);
607c93a6a15Sdist }
6082f4283ecSmark fprintf(trace, "]\n");
609c93a6a15Sdist CP(linebuf, savelb);
61014b70d95Smark }
61114b70d95Smark #endif
61214b70d95Smark
6134e1fedf7Smark /*
6144e1fedf7Smark * Get a count from the keyed input stream.
6154e1fedf7Smark * A zero count is indistinguishable from no count.
6164e1fedf7Smark */
vgetcnt()6174e1fedf7Smark vgetcnt()
6184e1fedf7Smark {
6194e1fedf7Smark register int c, cnt;
6204e1fedf7Smark
6214e1fedf7Smark cnt = 0;
6224e1fedf7Smark for (;;) {
6234e1fedf7Smark c = getkey();
6244e1fedf7Smark if (!isdigit(c))
6254e1fedf7Smark break;
6264e1fedf7Smark cnt *= 10, cnt += c - '0';
6274e1fedf7Smark }
6284e1fedf7Smark ungetkey(c);
6294e1fedf7Smark Xhadcnt = 1;
6304e1fedf7Smark Xcnt = cnt;
6314e1fedf7Smark return(cnt);
6324e1fedf7Smark }
6334e1fedf7Smark
6344e1fedf7Smark /*
6354e1fedf7Smark * fastpeekkey is just like peekkey but insists the character come in
6364e1fedf7Smark * fast (within 1 second). This will succeed if it is the 2nd char of
6374e1fedf7Smark * a machine generated sequence (such as a function pad from an escape
6384e1fedf7Smark * flavor terminal) but fail for a human hitting escape then waiting.
6394e1fedf7Smark */
fastpeekkey()6404e1fedf7Smark fastpeekkey()
6414e1fedf7Smark {
642b085448bSbostic void trapalarm();
643b085448bSbostic sig_t Oint;
6444e1fedf7Smark register int c;
6454e1fedf7Smark
64614b70d95Smark /*
64714b70d95Smark * If the user has set notimeout, we wait forever for a key.
64814b70d95Smark * If we are in a macro we do too, but since it's already
64914b70d95Smark * buffered internally it will return immediately.
65014b70d95Smark * In other cases we force this to die in 1 second.
65114b70d95Smark * This is pretty reliable (VMUNIX rounds it to .5 - 1.5 secs,
65214b70d95Smark * but UNIX truncates it to 0 - 1 secs) but due to system delays
65314b70d95Smark * there are times when arrow keys or very fast typing get counted
65414b70d95Smark * as separate. notimeout is provided for people who dislike such
65514b70d95Smark * nondeterminism.
65614b70d95Smark */
657c93a6a15Sdist #ifdef MDEBUG
658c93a6a15Sdist if (trace)
659dff40de8Sbostic fprintf(trace,"\nfastpeekkey: ");
660c93a6a15Sdist #endif
661c93a6a15Sdist Oint = signal(SIGINT, trapalarm);
662dff40de8Sbostic CATCH
66314b70d95Smark if (value(TIMEOUT) && inopen >= 0) {
6644e1fedf7Smark signal(SIGALRM, trapalarm);
665c93a6a15Sdist #ifdef MDEBUG
666c93a6a15Sdist alarm(10);
667c93a6a15Sdist if (trace)
668c93a6a15Sdist fprintf(trace, "set alarm ");
669c93a6a15Sdist #else
6704e1fedf7Smark alarm(1);
671c93a6a15Sdist #endif
67214b70d95Smark }
6734e1fedf7Smark c = peekkey();
674dff40de8Sbostic alarm(0);
6754e1fedf7Smark #ifdef MDEBUG
6764e1fedf7Smark if (trace)
677c8368a91Sbostic fprintf(trace,"[OK]");
6784e1fedf7Smark #endif
6794e1fedf7Smark ONERR
6804e1fedf7Smark c = 0;
6814e1fedf7Smark #ifdef MDEBUG
6824e1fedf7Smark if (trace)
683c8368a91Sbostic fprintf(trace,"[TIMEOUT]");
6844e1fedf7Smark #endif
6854e1fedf7Smark ENDCATCH
6864e1fedf7Smark #ifdef MDEBUG
6874e1fedf7Smark if (trace)
6884e1fedf7Smark fprintf(trace,"[fpk:%o]",c);
6894e1fedf7Smark #endif
690c93a6a15Sdist signal(SIGINT,Oint);
6914e1fedf7Smark return(c);
6924e1fedf7Smark }
6934e1fedf7Smark
694b085448bSbostic void
trapalarm()6954e1fedf7Smark trapalarm() {
6964e1fedf7Smark alarm(0);
697c93a6a15Sdist if (vcatch)
6984e1fedf7Smark longjmp(vreslab,1);
6994e1fedf7Smark }
700