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