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