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