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