1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
24 */
25
26 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
27 /* All Rights Reserved */
28
29
30 /* Copyright (c) 1981 Regents of the University of California */
31
32 #include "ex.h"
33 #include "ex_tty.h"
34 #include "ex_vis.h"
35
36 /*
37 * Input routines for open/visual.
38 * We handle upper case only terminals in visual and reading from the
39 * echo area here as well as notification on large changes
40 * which appears in the echo area.
41 */
42
43 /*
44 * Return the key.
45 */
46 void
ungetkey(int c)47 ungetkey(int c)
48 {
49
50 if (Peekkey != ATTN)
51 Peekkey = c;
52 }
53
54 /*
55 * Return a keystroke, but never a ^@.
56 */
57 int
getkey(void)58 getkey(void)
59 {
60 int c; /* char --> int */
61
62 do {
63 c = getbr();
64 if (c==0)
65 (void) beep();
66 } while (c == 0);
67 return (c);
68 }
69
70 /*
71 * Tell whether next keystroke would be a ^@.
72 */
73 int
peekbr(void)74 peekbr(void)
75 {
76
77 Peekkey = getbr();
78 return (Peekkey == 0);
79 }
80
81 short precbksl;
82
83 /*
84 * Get a keystroke, including a ^@.
85 * If an key was returned with ungetkey, that
86 * comes back first. Next comes unread input (e.g.
87 * from repeating commands with .), and finally new
88 * keystrokes.
89 *
90 * The hard work here is in mapping of \ escaped
91 * characters on upper case only terminals.
92 */
93 int
getbr(void)94 getbr(void)
95 {
96 unsigned char ch;
97 int c, d;
98 unsigned char *colp;
99 int cnt;
100 static unsigned char Peek2key;
101 extern short slevel, ttyindes;
102
103 getATTN:
104 if (Peekkey) {
105 c = Peekkey;
106 Peekkey = 0;
107 return (c);
108 }
109 if (Peek2key) {
110 c = Peek2key;
111 Peek2key = 0;
112 return (c);
113 }
114 if (vglobp) {
115 if (*vglobp)
116 return (lastvgk = *vglobp++);
117 lastvgk = 0;
118 return (ESCAPE);
119 }
120 if (vmacp) {
121 if (*vmacp)
122 return(*vmacp++);
123 /* End of a macro or set of nested macros */
124 vmacp = 0;
125 if (inopen == -1) /* don't mess up undo for esc esc */
126 vundkind = VMANY;
127 inopen = 1; /* restore old setting now that macro done */
128 vch_mac = VC_NOTINMAC;
129 }
130 flusho();
131 again:
132 if ((c=read(slevel == 0 ? 0 : ttyindes, &ch, 1)) != 1) {
133 if (errno == EINTR)
134 goto getATTN;
135 else if (errno == EIO)
136 kill(getpid(), SIGHUP);
137
138 error(gettext("Input read error"));
139 }
140 c = ch;
141 if (beehive_glitch && slevel==0 && c == ESCAPE) {
142 if (read(0, &Peek2key, 1) != 1)
143 goto getATTN;
144 switch (Peek2key) {
145 case 'C': /* SPOW mode sometimes sends \EC for space */
146 c = ' ';
147 Peek2key = 0;
148 break;
149 case 'q': /* f2 -> ^C */
150 c = CTRL('c');
151 Peek2key = 0;
152 break;
153 case 'p': /* f1 -> esc */
154 Peek2key = 0;
155 break;
156 }
157 }
158
159 /*
160 * The algorithm here is that of the UNIX kernel.
161 * See the description in the programmers manual.
162 */
163 if (UPPERCASE) {
164 if (isupper(c))
165 c = tolower(c);
166 if (c == '\\') {
167 if (precbksl < 2)
168 precbksl++;
169 if (precbksl == 1)
170 goto again;
171 } else if (precbksl) {
172 d = 0;
173 if (islower(c))
174 d = toupper(c);
175 else {
176 colp = (unsigned char *)"({)}!|^~'~";
177 while (d = *colp++)
178 if (d == c) {
179 d = *colp++;
180 break;
181 } else
182 colp++;
183 }
184 if (precbksl == 2) {
185 if (!d) {
186 Peekkey = c;
187 precbksl = 0;
188 c = '\\';
189 }
190 } else if (d)
191 c = d;
192 else {
193 Peekkey = c;
194 precbksl = 0;
195 c = '\\';
196 }
197 }
198 if (c != '\\')
199 precbksl = 0;
200 }
201 #ifdef TRACE
202 if (trace) {
203 if (!techoin) {
204 tfixnl();
205 techoin = 1;
206 fprintf(trace, "*** Input: ");
207 }
208 tracec(c);
209 }
210 #endif
211 lastvgk = 0;
212 return (c);
213 }
214
215 /*
216 * Get a key, but if a delete, quit or attention
217 * is typed return 0 so we will abort a partial command.
218 */
219 int
getesc(void)220 getesc(void)
221 {
222 int c;
223
224 c = getkey();
225 switch (c) {
226
227 case CTRL('v'):
228 case CTRL('q'):
229 c = getkey();
230 return (c);
231
232 case ATTN:
233 case QUIT:
234 ungetkey(c);
235 return (0);
236
237 case ESCAPE:
238 return (0);
239 }
240 return (c);
241 }
242
243 /*
244 * Peek at the next keystroke.
245 */
246 int
peekkey(void)247 peekkey(void)
248 {
249
250 Peekkey = getkey();
251 return (Peekkey);
252 }
253
254 /*
255 * Read a line from the echo area, with single character prompt c.
256 * A return value of 1 means the user blewit or blewit away.
257 */
258 int
readecho(c)259 readecho(c)
260 unsigned char c;
261 {
262 unsigned char *sc = cursor;
263 int (*OP)();
264 bool waste;
265 int OPeek;
266
267 if (WBOT == WECHO)
268 vclean();
269 else
270 vclrech(0);
271 splitw++;
272 vgoto(WECHO, 0);
273 putchar(c);
274 vclreol();
275 vgoto(WECHO, 1);
276 cursor = linebuf; linebuf[0] = 0; genbuf[0] = c;
277 ixlatctl(1);
278 if (peekbr()) {
279 if (!INS[0] || (unsigned char)INS[128] == 0200) {
280 INS[128] = 0;
281 goto blewit;
282 }
283 vglobp = INS;
284 }
285 OP = Pline; Pline = normline;
286 (void)vgetline(0, genbuf + 1, &waste, c);
287 doomed = 0; /* don't care about doomed characters in echo line */
288 ixlatctl(0);
289 if (Outchar == termchar)
290 putchar('\n');
291 vscrap();
292 Pline = OP;
293 if (Peekkey != ATTN && Peekkey != QUIT && Peekkey != CTRL('h')) {
294 cursor = sc;
295 vclreol();
296 return (0);
297 }
298 blewit:
299 OPeek = Peekkey==CTRL('h') ? 0 : Peekkey; Peekkey = 0;
300 splitw = 0;
301 vclean();
302 vshow(dot, NOLINE);
303 vnline(sc);
304 Peekkey = OPeek;
305 return (1);
306 }
307
308 /*
309 * A complete command has been defined for
310 * the purposes of repeat, so copy it from
311 * the working to the previous command buffer.
312 */
313 void
setLAST(void)314 setLAST(void)
315 {
316
317 if (vglobp || vmacp)
318 return;
319 lastreg = vreg;
320 lasthad = Xhadcnt;
321 lastcnt = Xcnt;
322 *lastcp = 0;
323 CP(lastcmd, workcmd);
324 }
325
326 /*
327 * Gather up some more text from an insert.
328 * If the insertion buffer oveflows, then destroy
329 * the repeatability of the insert.
330 */
331 void
addtext(unsigned char * cp)332 addtext(unsigned char *cp)
333 {
334
335 if (vglobp)
336 return;
337 addto(INS, cp);
338 if ((unsigned char)INS[128] == 0200)
339 lastcmd[0] = 0;
340 }
341
342 void
setDEL(void)343 setDEL(void)
344 {
345
346 setBUF(DEL);
347 }
348
349 /*
350 * Put text from cursor upto wcursor in BUF.
351 */
352 void
setBUF(unsigned char * BUF)353 setBUF(unsigned char *BUF)
354 {
355 int c;
356 unsigned char *wp = wcursor;
357
358 c = *wp;
359 *wp = 0;
360 BUF[0] = 0;
361 BUF[128] = 0;
362 addto(BUF, cursor);
363 *wp = c;
364 }
365
366 void
addto(unsigned char * buf,unsigned char * str)367 addto(unsigned char *buf, unsigned char *str)
368 {
369
370 if ((unsigned char)buf[128] == 0200)
371 return;
372 if (strlen(buf) + strlen(str) + 1 >= VBSIZE) {
373 buf[128] = 0200;
374 return;
375 }
376 (void)strcat(buf, str);
377 buf[128] = 0;
378 }
379
380 /*
381 * Verbalize command name and embed it in message.
382 */
383 char *
verbalize(cnt,cmdstr,sgn)384 verbalize(cnt, cmdstr, sgn)
385 int cnt;
386 char *cmdstr, *sgn;
387 {
388 if (cmdstr[0] == '\0')
389 cmdstr = (char *)Command;
390 if (sgn[0] == '\0') {
391 switch (cmdstr[0]) {
392 case 'c':
393 if (cmdstr[1] == 'h') {
394 viprintf((cnt == 1) ?
395 gettext("1 line changed") :
396 gettext("%d lines changed"), cnt);
397 break;
398 } else if (cmdstr[1] != 'o') {
399 goto Default;
400 }
401 /* FALLTHROUGH */
402 case 't':
403 if (cmdstr[1] != '\0')
404 goto Default;
405 viprintf((cnt == 1) ? gettext("1 line copied") :
406 gettext("%d lines copied"), cnt);
407 break;
408 case 'd':
409 viprintf((cnt == 1) ? gettext("1 line deleted") :
410 gettext("%d lines deleted"), cnt);
411 break;
412 case 'j':
413 viprintf((cnt == 1) ? gettext("1 line joined") :
414 gettext("%d lines joined"), cnt);
415 break;
416 case 'm':
417 viprintf((cnt == 1) ? gettext("1 line moved") :
418 gettext("%d lines moved"), cnt);
419 break;
420 case 'p':
421 viprintf((cnt == 1) ? gettext("1 line put") :
422 gettext("%d lines put"), cnt);
423 break;
424 case 'y':
425 viprintf((cnt == 1) ? gettext("1 line yanked") :
426 gettext("%d lines yanked"), cnt);
427 break;
428 case '>':
429 viprintf((cnt == 1) ? gettext("1 line >>ed") :
430 gettext("%d lines >>ed"), cnt);
431 break;
432 case '=':
433 viprintf((cnt == 1) ? gettext("1 line =ed") :
434 gettext("%d lines =ed"), cnt);
435 break;
436 case '<':
437 viprintf((cnt == 1) ? gettext("1 line <<ed") :
438 gettext("%d lines <<ed"), cnt);
439 break;
440 default:
441 Default:
442 viprintf((cnt == 1) ? gettext("1 line") :
443 gettext("%d lines"), cnt);
444 break;
445 }
446 } else if (sgn[0] == 'm') {
447 viprintf((cnt == 1) ? gettext("1 more line") :
448 gettext("%d more lines"), cnt);
449 } else {
450 viprintf((cnt == 1) ? gettext("1 fewer line") :
451 gettext("%d fewer lines"), cnt);
452 }
453 return (NULL);
454 }
455
456 /*
457 * Note a change affecting a lot of lines, or non-visible
458 * lines. If the parameter must is set, then we only want
459 * to do this for open modes now; return and save for later
460 * notification in visual.
461 */
462 int
noteit(must)463 noteit(must)
464 bool must;
465 {
466 int sdl = destline, sdc = destcol;
467
468 if (notecnt < 1 || !must && state == VISUAL)
469 return (0);
470 splitw++;
471 if (WBOT == WECHO)
472 vmoveitup(1, 1);
473 vigoto(WECHO, 0);
474
475 verbalize(notecnt, notenam, notesgn);
476 vclreol();
477 notecnt = 0;
478 if (state != VISUAL)
479 vcnt = vcline = 0;
480 splitw = 0;
481 if (state == ONEOPEN || state == CRTOPEN)
482 vup1();
483 destline = sdl; destcol = sdc;
484 return (1);
485 }
486
487 /*
488 * Ring or beep.
489 * If possible, flash screen.
490 */
491 int
beep(void)492 beep(void)
493 {
494
495 if (flash_screen && value(vi_FLASH))
496 vputp(flash_screen, 0);
497 else if (bell)
498 vputp(bell, 0);
499 return (0);
500 }
501
502 /*
503 * Map the command input character c,
504 * for keypads and labelled keys which do cursor
505 * motions. I.e. on an adm3a we might map ^K to ^P.
506 * DM1520 for example has a lot of mappable characters.
507 */
508
509 int
map(c,maps,commch)510 map(c, maps, commch)
511 int c;
512 struct maps *maps;
513 unsigned char commch; /* indicate if in append/insert/replace mode */
514 {
515 int d;
516 unsigned char *p, *q;
517 unsigned char b[10]; /* Assumption: no keypad sends string longer than 10 */
518 unsigned char *st;
519
520 /*
521 * Mapping for special keys on the terminal only.
522 * BUG: if there's a long sequence and it matches
523 * some chars and then misses, we lose some chars.
524 *
525 * For this to work, some conditions must be met.
526 * 1) Keypad sends SHORT (2 or 3 char) strings
527 * 2) All strings sent are same length & similar
528 * 3) The user is unlikely to type the first few chars of
529 * one of these strings very fast.
530 * Note: some code has been fixed up since the above was laid out,
531 * so conditions 1 & 2 are probably not required anymore.
532 * However, this hasn't been tested with any first char
533 * that means anything else except escape.
534 */
535 #ifdef MDEBUG
536 if (trace)
537 fprintf(trace,"map(%c): ",c);
538 #endif
539 /*
540 * If c==0, the char came from getesc typing escape. Pass it through
541 * unchanged. 0 messes up the following code anyway.
542 */
543 if (c==0)
544 return(0);
545
546 b[0] = c;
547 b[1] = 0;
548 for (d=0; d < MAXNOMACS && maps[d].mapto; d++) {
549 #ifdef MDEBUG
550 if (trace)
551 fprintf(trace,"\ntry '%s', ",maps[d].cap);
552 #endif
553 if (p = maps[d].cap) {
554 for (q=b; *p; p++, q++) {
555 #ifdef MDEBUG
556 if (trace)
557 fprintf(trace,"q->b[%d], ",q-b);
558 #endif
559 if (*q==0) {
560 /*
561 * Is there another char waiting?
562 *
563 * This test is oversimplified, but
564 * should work mostly. It handles the
565 * case where we get an ESCAPE that
566 * wasn't part of a keypad string.
567 */
568 if ((c=='#' ? peekkey() : fastpeekkey()) == 0) {
569 #ifdef MDEBUG
570 if (trace)
571 fprintf(trace,"fpk=0: will return '%c'",c);
572 #endif
573 /*
574 * Nothing waiting. Push back
575 * what we peeked at & return
576 * failure (c).
577 *
578 * We want to be able to undo
579 * commands, but it's nonsense
580 * to undo part of an insertion
581 * so if in input mode don't.
582 */
583 #ifdef MDEBUG
584 if (trace)
585 fprintf(trace, "Call macpush, b %d %d %d\n", b[0], b[1], b[2]);
586 #endif
587 macpush(&b[1],maps == arrows);
588 #ifdef MDEBUG
589 if (trace)
590 fprintf(trace, "return %d\n", c);
591 #endif
592 return(c);
593 }
594 *q = getkey();
595 q[1] = 0;
596 }
597 if (*p != *q)
598 goto contin;
599 }
600 macpush(maps[d].mapto,maps == arrows);
601 /*
602 * For all macros performed within insert,
603 * append, or replacement mode, we must end
604 * up returning back to that mode when we
605 * return (except that append will become
606 * insert for <home> key, so cursor is not
607 * in second column).
608 *
609 * In order to preserve backward movement
610 * when leaving insert mode, an 'l' must be
611 * done to compensate for the left done by
612 * the <esc> (except when cursor is already
613 * in the first column: i.e., outcol = 0).
614 */
615 if ((maps == immacs)
616 && strcmp(maps[d].descr, maps[d].cap)) {
617 switch (commch) {
618 case 'R':
619 if (!strcmp(maps[d].descr, "home"))
620 st = (unsigned char *)"R";
621 else
622 if (outcol == 0)
623 st = (unsigned char *)"R";
624 else
625 st = (unsigned char *)"lR";
626 break;
627 case 'i':
628 if (!strcmp(maps[d].descr, "home"))
629 st = (unsigned char *)"i";
630 else
631 if (outcol == 0)
632 st = (unsigned char *)"i";
633 else
634 st = (unsigned char *)"li";
635 break;
636 case 'a':
637 if (!strcmp(maps[d].descr, "home"))
638 st = (unsigned char *)"i";
639 else
640 st = (unsigned char *)"a";
641 break;
642 default:
643 st = (unsigned char *)"i";
644 }
645 if(strlen(vmacbuf) + strlen(st) > BUFSIZE)
646 error(value(vi_TERSE) ?
647 gettext("Macro too long") : gettext("Macro too long - maybe recursive?"));
648 else
649 /*
650 * Macros such as function keys are
651 * performed by leaving the insert,
652 * replace, or append mode, executing
653 * the proper cursor movement commands
654 * and returning to the mode we are
655 * currently in (commch).
656 */
657 strcat(vmacbuf, st);
658 }
659 c = getkey();
660 #ifdef MDEBUG
661 if (trace)
662 fprintf(trace,"Success: push(%s), return %c",maps[d].mapto, c);
663 #endif
664 return(c); /* first char of map string */
665 contin:;
666 }
667 }
668 #ifdef MDEBUG
669 if (trace)
670 fprintf(trace,"Fail: push(%s), return %c", &b[1], c);
671 #endif
672 macpush(&b[1],0);
673 return(c);
674 }
675
676 /*
677 * Push st onto the front of vmacp. This is tricky because we have to
678 * worry about where vmacp was previously pointing. We also have to
679 * check for overflow (which is typically from a recursive macro)
680 * Finally we have to set a flag so the whole thing can be undone.
681 * canundo is 1 iff we want to be able to undo the macro. This
682 * is false for, for example, pushing back lookahead from fastpeekkey(),
683 * since otherwise two fast escapes can clobber our undo.
684 */
685 void
macpush(unsigned char * st,int canundo)686 macpush(unsigned char *st, int canundo)
687 {
688 unsigned char tmpbuf[BUFSIZE];
689
690 if (st==0 || *st==0)
691 return;
692 #ifdef MDEBUG
693 if (trace)
694 fprintf(trace, "macpush(%s), canundo=%d\n",st,canundo);
695 #endif
696 if ((vmacp ? strlen(vmacp) : 0) + strlen(st) > BUFSIZE)
697 error(value(vi_TERSE) ? gettext("Macro too long") :
698 gettext("Macro too long - maybe recursive?"));
699 if (vmacp) {
700 strcpy(tmpbuf, vmacp);
701 if (!FIXUNDO)
702 canundo = 0; /* can't undo inside a macro anyway */
703 }
704 strcpy(vmacbuf, st);
705 if (vmacp)
706 strcat(vmacbuf, tmpbuf);
707 vmacp = vmacbuf;
708 /* arrange to be able to undo the whole macro */
709 if (canundo) {
710 #ifdef notdef
711 otchng = tchng;
712 vsave();
713 saveall();
714 inopen = -1; /* no need to save since it had to be 1 or -1 before */
715 vundkind = VMANY;
716 #endif
717 vch_mac = VC_NOCHANGE;
718 }
719 }
720
721 #ifdef UNDOTRACE
visdump(s)722 visdump(s)
723 unsigned char *s;
724 {
725 int i;
726
727 if (!trace) return;
728
729 fprintf(trace, "\n%s: basWTOP=%d, basWLINES=%d, WTOP=%d, WBOT=%d, WLINES=%d, WCOLS=%d, WECHO=%d\n",
730 s, basWTOP, basWLINES, WTOP, WBOT, WLINES, WCOLS, WECHO);
731 fprintf(trace, " vcnt=%d, vcline=%d, cursor=%d, wcursor=%d, wdot=%d\n",
732 vcnt, vcline, cursor-linebuf, wcursor-linebuf, wdot-zero);
733 for (i=0; i<TUBELINES; i++)
734 if (vtube[i] && *vtube[i])
735 fprintf(trace, "%d: '%s'\n", i, vtube[i]);
736 tvliny();
737 }
738
vudump(s)739 vudump(s)
740 unsigned char *s;
741 {
742 line *p;
743 unsigned char savelb[1024];
744
745 if (!trace) return;
746
747 fprintf(trace, "\n%s: undkind=%d, vundkind=%d, unddel=%d, undap1=%d, undap2=%d,\n",
748 s, undkind, vundkind, lineno(unddel), lineno(undap1), lineno(undap2));
749 fprintf(trace, " undadot=%d, dot=%d, dol=%d, unddol=%d, truedol=%d\n",
750 lineno(undadot), lineno(dot), lineno(dol), lineno(unddol), lineno(truedol));
751 fprintf(trace, " [\n");
752 CP(savelb, linebuf);
753 fprintf(trace, "linebuf = '%s'\n", linebuf);
754 for (p=zero+1; p<=truedol; p++) {
755 fprintf(trace, "%o ", *p);
756 getaline(*p);
757 fprintf(trace, "'%s'\n", linebuf);
758 }
759 fprintf(trace, "]\n");
760 CP(linebuf, savelb);
761 }
762 #endif
763
764 /*
765 * Get a count from the keyed input stream.
766 * A zero count is indistinguishable from no count.
767 */
768 int
vgetcnt(void)769 vgetcnt(void)
770 {
771 int c, cnt;
772
773 cnt = 0;
774 for (;;) {
775 c = getkey();
776 if (!isdigit(c))
777 break;
778 cnt *= 10, cnt += c - '0';
779 }
780 ungetkey(c);
781 Xhadcnt = 1;
782 Xcnt = cnt;
783 return(cnt);
784 }
785
786 /*
787 * fastpeekkey is just like peekkey but insists the character come in
788 * fast (within 1 second). This will succeed if it is the 2nd char of
789 * a machine generated sequence (such as a function pad from an escape
790 * flavor terminal) but fail for a human hitting escape then waiting.
791 */
792 int
fastpeekkey(void)793 fastpeekkey(void)
794 {
795 void trapalarm();
796 int c;
797
798 /*
799 * If the user has set notimeout, we wait forever for a key.
800 * If we are in a macro we do too, but since it's already
801 * buffered internally it will return immediately.
802 * In other cases we force this to die in 1 second.
803 * This is pretty reliable (VMUNIX rounds it to .5 - 1.5 secs,
804 * but UNIX truncates it to 0 - 1 secs) but due to system delays
805 * there are times when arrow keys or very fast typing get counted
806 * as separate. notimeout is provided for people who dislike such
807 * nondeterminism.
808 */
809 CATCH
810 if (value(vi_TIMEOUT) && inopen >= 0) {
811 signal(SIGALRM, trapalarm);
812 setalarm();
813 }
814 c = peekkey();
815 cancelalarm();
816 ONERR
817 c = 0;
818 ENDCATCH
819 /* Should have an alternative method based on select for 4.2BSD */
820 return(c);
821 }
822
823 static int ftfd;
824 struct requestbuf {
825 short time;
826 short signo;
827 };
828
829 /*
830 * Arrange for SIGALRM to come in shortly, so we don't
831 * hang very long if the user didn't type anything. There are
832 * various ways to do this on different systems.
833 */
834 void
setalarm(void)835 setalarm(void)
836 {
837 unsigned char ftname[20];
838 struct requestbuf rb;
839
840 #ifdef FTIOCSET
841 /*
842 * Use nonstandard "fast timer" to get better than
843 * one second resolution. We must wait at least
844 * 1/15th of a second because some keypads don't
845 * transmit faster than this.
846 */
847
848 /* Open ft psuedo-device - we need our own copy. */
849 if (ftfd == 0) {
850 strcpy(ftname, "/dev/ft0");
851 while (ftfd <= 0 && ftname[7] <= '~') {
852 ftfd = open(ftname, 0);
853 if (ftfd <= 0)
854 ftname[7] ++;
855 }
856 }
857 if (ftfd <= 0) { /* Couldn't open a /dev/ft? */
858 alarm(1);
859 } else {
860 rb.time = 6; /* 6 ticks = 100 ms > 67 ms. */
861 rb.signo = SIGALRM;
862 ioctl(ftfd, FTIOCSET, &rb);
863 }
864 #else
865 /*
866 * No special capabilities, so we use alarm, with 1 sec. resolution.
867 */
868 alarm(1);
869 #endif
870 }
871
872 /*
873 * Get rid of any impending incoming SIGALRM.
874 */
875 void
cancelalarm(void)876 cancelalarm(void)
877 {
878 struct requestbuf rb;
879 #ifdef FTIOCSET
880 if (ftfd > 0) {
881 rb.time = 0;
882 rb.signo = SIGALRM;
883 ioctl(ftfd, FTIOCCANCEL, &rb);
884 }
885 #endif
886 alarm(0); /* Have to do this whether or not FTIOCSET */
887 }
888
trapalarm()889 void trapalarm() {
890 alarm(0);
891 longjmp(vreslab,1);
892 }
893