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