|
|
1.1 root 1: /* Copyright (c) 1981 Regents of the University of California */
2: static char *sccsid = "@(#)ex_vget.c 6.5 6/18/83";
3: #include "ex.h"
4: #include "ex_tty.h"
5: #include "ex_vis.h"
6:
7: /*
8: * Input routines for open/visual.
9: * We handle upper case only terminals in visual and reading from the
10: * echo area here as well as notification on large changes
11: * which appears in the echo area.
12: */
13:
14: /*
15: * Return the key.
16: */
17: ungetkey(c)
18: int c; /* mjm: char --> int */
19: {
20:
21: if (Peekkey != ATTN)
22: Peekkey = c;
23: }
24:
25: /*
26: * Return a keystroke, but never a ^@.
27: */
28: getkey()
29: {
30: register int c; /* mjm: char --> int */
31:
32: do {
33: c = getbr();
34: if (c==0)
35: beep();
36: } while (c == 0);
37: return (c);
38: }
39:
40: /*
41: * Tell whether next keystroke would be a ^@.
42: */
43: peekbr()
44: {
45:
46: Peekkey = getbr();
47: return (Peekkey == 0);
48: }
49:
50: short precbksl;
51: jmp_buf readbuf;
52: int doingread = 0;
53:
54: /*
55: * Get a keystroke, including a ^@.
56: * If an key was returned with ungetkey, that
57: * comes back first. Next comes unread input (e.g.
58: * from repeating commands with .), and finally new
59: * keystrokes.
60: *
61: * The hard work here is in mapping of \ escaped
62: * characters on upper case only terminals.
63: */
64: getbr()
65: {
66: char ch;
67: register int c, d;
68: register char *colp;
69: int cnt;
70: #define BEEHIVE
71: #ifdef BEEHIVE
72: static char Peek2key;
73: #endif
74: extern short slevel, ttyindes;
75:
76: getATTN:
77: if (Peekkey) {
78: c = Peekkey;
79: Peekkey = 0;
80: return (c);
81: }
82: #ifdef BEEHIVE
83: if (Peek2key) {
84: c = Peek2key;
85: Peek2key = 0;
86: return (c);
87: }
88: #endif
89: if (vglobp) {
90: if (*vglobp)
91: return (lastvgk = *vglobp++);
92: lastvgk = 0;
93: return (ESCAPE);
94: }
95: if (vmacp) {
96: if (*vmacp)
97: return(*vmacp++);
98: /* End of a macro or set of nested macros */
99: vmacp = 0;
100: if (inopen == -1) /* don't screw up undo for esc esc */
101: vundkind = VMANY;
102: inopen = 1; /* restore old setting now that macro done */
103: vch_mac = VC_NOTINMAC;
104: }
105: flusho();
106: again:
107: if (setjmp(readbuf))
108: goto getATTN;
109: doingread = 1;
110: c = read(slevel == 0 ? 0 : ttyindes, &ch, 1);
111: doingread = 0;
112: if (c != 1) {
113: if (errno == EINTR)
114: goto getATTN;
115: error("Input read error");
116: }
117: c = ch & TRIM;
118: #ifdef BEEHIVE
119: if (XB && slevel==0 && c == ESCAPE) {
120: if (read(0, &Peek2key, 1) != 1)
121: goto getATTN;
122: Peek2key &= TRIM;
123: switch (Peek2key) {
124: case 'C': /* SPOW mode sometimes sends \EC for space */
125: c = ' ';
126: Peek2key = 0;
127: break;
128: case 'q': /* f2 -> ^C */
129: c = CTRL(c);
130: Peek2key = 0;
131: break;
132: case 'p': /* f1 -> esc */
133: Peek2key = 0;
134: break;
135: }
136: }
137: #endif
138:
139: #ifdef UCVISUAL
140: /*
141: * The algorithm here is that of the UNIX kernel.
142: * See the description in the programmers manual.
143: */
144: if (UPPERCASE) {
145: if (isupper(c))
146: c = tolower(c);
147: if (c == '\\') {
148: if (precbksl < 2)
149: precbksl++;
150: if (precbksl == 1)
151: goto again;
152: } else if (precbksl) {
153: d = 0;
154: if (islower(c))
155: d = toupper(c);
156: else {
157: colp = "({)}!|^~'~";
158: while (d = *colp++)
159: if (d == c) {
160: d = *colp++;
161: break;
162: } else
163: colp++;
164: }
165: if (precbksl == 2) {
166: if (!d) {
167: Peekkey = c;
168: precbksl = 0;
169: c = '\\';
170: }
171: } else if (d)
172: c = d;
173: else {
174: Peekkey = c;
175: precbksl = 0;
176: c = '\\';
177: }
178: }
179: if (c != '\\')
180: precbksl = 0;
181: }
182: #endif
183: #ifdef TRACE
184: if (trace) {
185: if (!techoin) {
186: tfixnl();
187: techoin = 1;
188: fprintf(trace, "*** Input: ");
189: }
190: tracec(c);
191: }
192: #endif
193: lastvgk = 0;
194: return (c);
195: }
196:
197: /*
198: * Get a key, but if a delete, quit or attention
199: * is typed return 0 so we will abort a partial command.
200: */
201: getesc()
202: {
203: register int c;
204:
205: c = getkey();
206: switch (c) {
207:
208: case CTRL(v):
209: case CTRL(q):
210: c = getkey();
211: return (c);
212:
213: case ATTN:
214: case QUIT:
215: ungetkey(c);
216: return (0);
217:
218: case ESCAPE:
219: return (0);
220: }
221: return (c);
222: }
223:
224: /*
225: * Peek at the next keystroke.
226: */
227: peekkey()
228: {
229:
230: Peekkey = getkey();
231: return (Peekkey);
232: }
233:
234: /*
235: * Read a line from the echo area, with single character prompt c.
236: * A return value of 1 means the user blewit or blewit away.
237: */
238: readecho(c)
239: char c;
240: {
241: register char *sc = cursor;
242: register int (*OP)();
243: bool waste;
244: register int OPeek;
245:
246: if (WBOT == WECHO)
247: vclean();
248: else
249: vclrech(0);
250: splitw++;
251: vgoto(WECHO, 0);
252: putchar(c);
253: vclreol();
254: vgoto(WECHO, 1);
255: cursor = linebuf; linebuf[0] = 0; genbuf[0] = c;
256: if (peekbr()) {
257: if (!INS[0] || (INS[0] & (QUOTE|TRIM)) == OVERBUF)
258: goto blewit;
259: vglobp = INS;
260: }
261: OP = Pline; Pline = normline;
262: ignore(vgetline(0, genbuf + 1, &waste, c));
263: if (Outchar == termchar)
264: putchar('\n');
265: vscrap();
266: Pline = OP;
267: if (Peekkey != ATTN && Peekkey != QUIT && Peekkey != CTRL(h)) {
268: cursor = sc;
269: vclreol();
270: return (0);
271: }
272: blewit:
273: OPeek = Peekkey==CTRL(h) ? 0 : Peekkey; Peekkey = 0;
274: splitw = 0;
275: vclean();
276: vshow(dot, NOLINE);
277: vnline(sc);
278: Peekkey = OPeek;
279: return (1);
280: }
281:
282: /*
283: * A complete command has been defined for
284: * the purposes of repeat, so copy it from
285: * the working to the previous command buffer.
286: */
287: setLAST()
288: {
289:
290: if (vglobp || vmacp)
291: return;
292: lastreg = vreg;
293: lasthad = Xhadcnt;
294: lastcnt = Xcnt;
295: *lastcp = 0;
296: CP(lastcmd, workcmd);
297: }
298:
299: /*
300: * Gather up some more text from an insert.
301: * If the insertion buffer oveflows, then destroy
302: * the repeatability of the insert.
303: */
304: addtext(cp)
305: char *cp;
306: {
307:
308: if (vglobp)
309: return;
310: addto(INS, cp);
311: if ((INS[0] & (QUOTE|TRIM)) == OVERBUF)
312: lastcmd[0] = 0;
313: }
314:
315: setDEL()
316: {
317:
318: setBUF(DEL);
319: }
320:
321: /*
322: * Put text from cursor upto wcursor in BUF.
323: */
324: setBUF(BUF)
325: register char *BUF;
326: {
327: register int c;
328: register char *wp = wcursor;
329:
330: c = *wp;
331: *wp = 0;
332: BUF[0] = 0;
333: addto(BUF, cursor);
334: *wp = c;
335: }
336:
337: addto(buf, str)
338: register char *buf, *str;
339: {
340:
341: if ((buf[0] & (QUOTE|TRIM)) == OVERBUF)
342: return;
343: if (strlen(buf) + strlen(str) + 1 >= VBSIZE) {
344: buf[0] = OVERBUF;
345: return;
346: }
347: ignore(strcat(buf, str));
348: }
349:
350: /*
351: * Note a change affecting a lot of lines, or non-visible
352: * lines. If the parameter must is set, then we only want
353: * to do this for open modes now; return and save for later
354: * notification in visual.
355: */
356: noteit(must)
357: bool must;
358: {
359: register int sdl = destline, sdc = destcol;
360:
361: if (notecnt < 2 || !must && state == VISUAL)
362: return (0);
363: splitw++;
364: if (WBOT == WECHO)
365: vmoveitup(1, 1);
366: vigoto(WECHO, 0);
367: printf("%d %sline", notecnt, notesgn);
368: if (notecnt > 1)
369: putchar('s');
370: if (*notenam) {
371: printf(" %s", notenam);
372: if (*(strend(notenam) - 1) != 'e')
373: putchar('e');
374: putchar('d');
375: }
376: vclreol();
377: notecnt = 0;
378: if (state != VISUAL)
379: vcnt = vcline = 0;
380: splitw = 0;
381: if (state == ONEOPEN || state == CRTOPEN)
382: vup1();
383: destline = sdl; destcol = sdc;
384: return (1);
385: }
386:
387: /*
388: * Rrrrringgggggg.
389: * If possible, use flash (VB).
390: */
391: beep()
392: {
393:
394: if (VB)
395: vputp(VB, 0);
396: else
397: vputc(CTRL(g));
398: }
399:
400: /*
401: * Map the command input character c,
402: * for keypads and labelled keys which do cursor
403: * motions. I.e. on an adm3a we might map ^K to ^P.
404: * DM1520 for example has a lot of mappable characters.
405: */
406:
407: map(c,maps)
408: register int c;
409: register struct maps *maps;
410: {
411: register int d;
412: register char *p, *q;
413: char b[10]; /* Assumption: no keypad sends string longer than 10 */
414:
415: /*
416: * Mapping for special keys on the terminal only.
417: * BUG: if there's a long sequence and it matches
418: * some chars and then misses, we lose some chars.
419: *
420: * For this to work, some conditions must be met.
421: * 1) Keypad sends SHORT (2 or 3 char) strings
422: * 2) All strings sent are same length & similar
423: * 3) The user is unlikely to type the first few chars of
424: * one of these strings very fast.
425: * Note: some code has been fixed up since the above was laid out,
426: * so conditions 1 & 2 are probably not required anymore.
427: * However, this hasn't been tested with any first char
428: * that means anything else except escape.
429: */
430: #ifdef MDEBUG
431: if (trace)
432: fprintf(trace,"map(%c): ",c);
433: #endif
434: /*
435: * If c==0, the char came from getesc typing escape. Pass it through
436: * unchanged. 0 messes up the following code anyway.
437: */
438: if (c==0)
439: return(0);
440:
441: b[0] = c;
442: b[1] = 0;
443: for (d=0; maps[d].mapto; d++) {
444: #ifdef MDEBUG
445: if (trace)
446: fprintf(trace,"\ntry '%s', ",maps[d].cap);
447: #endif
448: if (p = maps[d].cap) {
449: for (q=b; *p; p++, q++) {
450: #ifdef MDEBUG
451: if (trace)
452: fprintf(trace,"q->b[%d], ",q-b);
453: #endif
454: if (*q==0) {
455: /*
456: * Is there another char waiting?
457: *
458: * This test is oversimplified, but
459: * should work mostly. It handles the
460: * case where we get an ESCAPE that
461: * wasn't part of a keypad string.
462: */
463: if ((c=='#' ? peekkey() : fastpeekkey()) == 0) {
464: #ifdef MDEBUG
465: if (trace)
466: fprintf(trace,"fpk=0: will return '%c'",c);
467: #endif
468: /*
469: * Nothing waiting. Push back
470: * what we peeked at & return
471: * failure (c).
472: *
473: * We want to be able to undo
474: * commands, but it's nonsense
475: * to undo part of an insertion
476: * so if in input mode don't.
477: */
478: #ifdef MDEBUG
479: if (trace)
480: fprintf(trace, "Call macpush, b %d %d %d\n", b[0], b[1], b[2]);
481: #endif
482: macpush(&b[1],maps == arrows);
483: #ifdef MDEBUG
484: if (trace)
485: fprintf(trace, "return %d\n", c);
486: #endif
487: return(c);
488: }
489: *q = getkey();
490: q[1] = 0;
491: }
492: if (*p != *q)
493: goto contin;
494: }
495: macpush(maps[d].mapto,maps == arrows);
496: c = getkey();
497: #ifdef MDEBUG
498: if (trace)
499: fprintf(trace,"Success: push(%s), return %c",maps[d].mapto, c);
500: #endif
501: return(c); /* first char of map string */
502: contin:;
503: }
504: }
505: #ifdef MDEBUG
506: if (trace)
507: fprintf(trace,"Fail: push(%s), return %c", &b[1], c);
508: #endif
509: macpush(&b[1],0);
510: return(c);
511: }
512:
513: /*
514: * Push st onto the front of vmacp. This is tricky because we have to
515: * worry about where vmacp was previously pointing. We also have to
516: * check for overflow (which is typically from a recursive macro)
517: * Finally we have to set a flag so the whole thing can be undone.
518: * canundo is 1 iff we want to be able to undo the macro. This
519: * is false for, for example, pushing back lookahead from fastpeekkey(),
520: * since otherwise two fast escapes can clobber our undo.
521: */
522: macpush(st, canundo)
523: char *st;
524: int canundo;
525: {
526: char tmpbuf[BUFSIZ];
527:
528: if (st==0 || *st==0)
529: return;
530: #ifdef MDEBUG
531: if (trace)
532: fprintf(trace, "macpush(%s), canundo=%d\n",st,canundo);
533: #endif
534: if ((vmacp ? strlen(vmacp) : 0) + strlen(st) > BUFSIZ)
535: error("Macro too long@ - maybe recursive?");
536: if (vmacp) {
537: strcpy(tmpbuf, vmacp);
538: if (!FIXUNDO)
539: canundo = 0; /* can't undo inside a macro anyway */
540: }
541: strcpy(vmacbuf, st);
542: if (vmacp)
543: strcat(vmacbuf, tmpbuf);
544: vmacp = vmacbuf;
545: /* arrange to be able to undo the whole macro */
546: if (canundo) {
547: #ifdef notdef
548: otchng = tchng;
549: vsave();
550: saveall();
551: inopen = -1; /* no need to save since it had to be 1 or -1 before */
552: vundkind = VMANY;
553: #endif
554: vch_mac = VC_NOCHANGE;
555: }
556: }
557:
558: #ifdef TRACE
559: visdump(s)
560: char *s;
561: {
562: register int i;
563:
564: if (!trace) return;
565:
566: fprintf(trace, "\n%s: basWTOP=%d, basWLINES=%d, WTOP=%d, WBOT=%d, WLINES=%d, WCOLS=%d, WECHO=%d\n",
567: s, basWTOP, basWLINES, WTOP, WBOT, WLINES, WCOLS, WECHO);
568: fprintf(trace, " vcnt=%d, vcline=%d, cursor=%d, wcursor=%d, wdot=%d\n",
569: vcnt, vcline, cursor-linebuf, wcursor-linebuf, wdot-zero);
570: for (i=0; i<TUBELINES; i++)
571: if (vtube[i] && *vtube[i])
572: fprintf(trace, "%d: '%s'\n", i, vtube[i]);
573: tvliny();
574: }
575:
576: vudump(s)
577: char *s;
578: {
579: register line *p;
580: char savelb[1024];
581:
582: if (!trace) return;
583:
584: fprintf(trace, "\n%s: undkind=%d, vundkind=%d, unddel=%d, undap1=%d, undap2=%d,\n",
585: s, undkind, vundkind, lineno(unddel), lineno(undap1), lineno(undap2));
586: fprintf(trace, " undadot=%d, dot=%d, dol=%d, unddol=%d, truedol=%d\n",
587: lineno(undadot), lineno(dot), lineno(dol), lineno(unddol), lineno(truedol));
588: fprintf(trace, " [\n");
589: CP(savelb, linebuf);
590: fprintf(trace, "linebuf = '%s'\n", linebuf);
591: for (p=zero+1; p<=truedol; p++) {
592: fprintf(trace, "%o ", *p);
593: getline(*p);
594: fprintf(trace, "'%s'\n", linebuf);
595: }
596: fprintf(trace, "]\n");
597: CP(linebuf, savelb);
598: }
599: #endif
600:
601: /*
602: * Get a count from the keyed input stream.
603: * A zero count is indistinguishable from no count.
604: */
605: vgetcnt()
606: {
607: register int c, cnt;
608:
609: cnt = 0;
610: for (;;) {
611: c = getkey();
612: if (!isdigit(c))
613: break;
614: cnt *= 10, cnt += c - '0';
615: }
616: ungetkey(c);
617: Xhadcnt = 1;
618: Xcnt = cnt;
619: return(cnt);
620: }
621:
622: /*
623: * fastpeekkey is just like peekkey but insists the character come in
624: * fast (within 1 second). This will succeed if it is the 2nd char of
625: * a machine generated sequence (such as a function pad from an escape
626: * flavor terminal) but fail for a human hitting escape then waiting.
627: */
628: fastpeekkey()
629: {
630: int trapalarm();
631: register int c;
632:
633: /*
634: * If the user has set notimeout, we wait forever for a key.
635: * If we are in a macro we do too, but since it's already
636: * buffered internally it will return immediately.
637: * In other cases we force this to die in 1 second.
638: * This is pretty reliable (VMUNIX rounds it to .5 - 1.5 secs,
639: * but UNIX truncates it to 0 - 1 secs) but due to system delays
640: * there are times when arrow keys or very fast typing get counted
641: * as separate. notimeout is provided for people who dislike such
642: * nondeterminism.
643: */
644: #ifdef MDEBUG
645: if (trace)
646: fprintf(trace,"\nfastpeekkey: ",c);
647: #endif
648: if (value(TIMEOUT) && inopen >= 0) {
649: signal(SIGALRM, trapalarm);
650: #ifdef MDEBUG
651: alarm(10);
652: if (trace)
653: fprintf(trace, "set alarm ");
654: #else
655: alarm(1);
656: #endif
657: }
658: CATCH
659: c = peekkey();
660: #ifdef MDEBUG
661: if (trace)
662: fprintf(trace,"[OK]",c);
663: #endif
664: alarm(0);
665: ONERR
666: c = 0;
667: #ifdef MDEBUG
668: if (trace)
669: fprintf(trace,"[TIMEOUT]",c);
670: #endif
671: ENDCATCH
672: #ifdef MDEBUG
673: if (trace)
674: fprintf(trace,"[fpk:%o]",c);
675: #endif
676: return(c);
677: }
678:
679: trapalarm() {
680: alarm(0);
681: longjmp(vreslab,1);
682: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.