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 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 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 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 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 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 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 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 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 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 343 setDEL(void) 344 { 345 346 setBUF(DEL); 347 } 348 349 /* 350 * Put text from cursor upto wcursor in BUF. 351 */ 352 void 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 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 * 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 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 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 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 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 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 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 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 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 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 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 889 void trapalarm() { 890 alarm(0); 891 longjmp(vreslab,1); 892 } 893