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