1 /* pcterm.c -- How to handle the PC terminal for Info under MS-DOS/MS-Windows. 2 $Id: pcterm.c,v 1.1.1.3 2006/07/17 16:03:45 espie Exp $ 3 4 Copyright (C) 1998, 1999, 2003, 2004 Free Software Foundation, Inc. 5 6 This program is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 2, or (at your option) 9 any later version. 10 11 This program is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License along 17 with this program; if not, write to the Free Software Foundation, Inc., 18 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ 19 20 21 /* WARNING WARNING WARNING!!! 22 This probably won't work as is with anything but DJGPP! However, Borland 23 should come close, and other PC compilers will need minor modifications. */ 24 25 /* intl/libintl.h defines a macro `gettext' which 26 conflicts with conio.h header. */ 27 #ifdef gettext 28 # undef gettext 29 # define gettext _gettext 30 #endif 31 32 #include <pc.h> 33 #include <keys.h> 34 #include <conio.h> 35 36 #include "variables.h" 37 38 extern int speech_friendly; /* defined in info.c */ 39 40 /* **************************************************************** */ 41 /* */ 42 /* PC Terminal Output Functions */ 43 /* */ 44 /* **************************************************************** */ 45 46 static struct text_info outside_info; /* holds screen params outside Info */ 47 static unsigned char norm_attr, inv_attr; 48 49 static unsigned const char * find_sequence (int); 50 51 /* Turn on reverse video. */ 52 static void 53 pc_begin_inverse (void) 54 { 55 textattr (inv_attr); 56 } 57 58 /* Turn off reverse video. */ 59 static void 60 pc_end_inverse (void) 61 { 62 textattr (norm_attr); 63 } 64 65 /* Move the cursor up one line. */ 66 static void 67 pc_up_line (void) 68 { 69 int x, y; 70 ScreenGetCursor (&y, &x); 71 ScreenSetCursor (MAX (y-1, 0), x); 72 } 73 74 /* Move the cursor down one line. */ 75 static void 76 pc_down_line (void) 77 { 78 int x, y; 79 ScreenGetCursor (&y, &x); 80 ScreenSetCursor (MIN (screenheight-1, y+1), x); 81 } 82 83 /* Clear the entire terminal screen. */ 84 static void 85 pc_clear_screen (void) 86 { 87 ScreenClear (); 88 } 89 90 /* Clear from the current position of the cursor to the end of the line. */ 91 static void 92 pc_clear_to_eol (void) 93 { 94 clreol (); /* perhaps to be replaced by a loop */ 95 } 96 97 /* Set the global variables SCREENWIDTH and SCREENHEIGHT. */ 98 static void 99 pc_get_screen_size(void) 100 { 101 /* Current screen dimensions are the default. */ 102 if (!outside_info.screenheight) /* paranoia */ 103 gettextinfo (&outside_info); 104 screenwidth = outside_info.screenwidth; 105 screenheight = outside_info.screenheight; 106 107 /* Environment variable "LINES" overrides the default. */ 108 if (getenv ("LINES") != NULL) 109 screenheight = atoi (getenv ("LINES")); 110 111 /* Environment variable "INFO_LINES" overrides "LINES". */ 112 if (getenv ("INFO_LINES") != NULL) 113 screenheight = atoi (getenv ("INFO_LINES")); 114 } 115 116 /* Move the cursor to the terminal location of X and Y. */ 117 static void 118 pc_goto_xy (x, y) 119 int x, y; 120 { 121 ScreenSetCursor (y, x); /* yes, pc.h says ScreenSetCursor (row, column) !! */ 122 } 123 124 /* Print STRING to the terminal at the current position. */ 125 static void 126 pc_put_text (string) 127 char *string; 128 { 129 if (speech_friendly) 130 fputs (string, stdout); 131 else 132 cputs (string); 133 } 134 135 /* Ring the terminal bell. The bell is rung visibly if the terminal is 136 capable of doing that, and if terminal_use_visible_bell_p is non-zero. */ 137 static void 138 pc_ring_bell(void) 139 { 140 if (terminal_has_visible_bell_p && terminal_use_visible_bell_p) 141 ScreenVisualBell (); 142 else 143 { 144 printf ("%c",'\a'); 145 fflush (stdout); 146 } 147 } 148 149 /* Print NCHARS from STRING to the terminal at the current position. */ 150 static void 151 pc_write_chars (string, nchars) 152 char *string; 153 int nchars; 154 { 155 if (!nchars) 156 return; 157 158 if (speech_friendly) 159 printf ("%.*s",nchars, string); 160 else 161 cprintf ("%..*s",nchars, string); 162 } 163 164 /* Scroll an area of the terminal from START to (and excluding) END, 165 AMOUNT lines. If AMOUNT is negative, the lines are scrolled 166 towards the top of the screen, else they are scrolled towards the 167 bottom of the screen. The lines of the old region which do not 168 overlap the new region are cleared, to mimic terminal operation. */ 169 static void 170 pc_scroll_terminal (start, end, amount) 171 int start, end, amount; 172 { 173 int line_to_clear = amount > 0 ? start : end + amount; 174 175 /* Move the text. Note that `movetext' expects 1-based coordinates. */ 176 movetext (1, start + 1, ScreenCols (), end, 1, start + amount + 1); 177 178 /* Now clear the lines which were left unoccupied. */ 179 if (amount < 0) 180 amount = -amount; 181 while (amount--) 182 { 183 ScreenSetCursor (line_to_clear++, 0); 184 clreol (); 185 } 186 } 187 188 /* Put the screen in the video mode and colors which Info will use. 189 Prepare to start using the terminal to read characters singly. */ 190 static void 191 pc_prep_terminal (void) 192 { 193 int tty; 194 195 /* Do not set screen height if we already have it, because 196 doing so erases the screen. */ 197 if (screenheight != ScreenRows ()) 198 _set_screen_lines (screenheight); 199 200 /* Don't fail if they asked for screen dimensions that their 201 hardware cannot support. */ 202 screenheight = ScreenRows (); 203 screenwidth = ScreenCols (); 204 205 /* Try setting the colors user asked for. */ 206 textattr (norm_attr); 207 ScreenClear (); 208 209 /* Switch console reads to binary mode. */ 210 tty = fileno (stdin); 211 #ifdef __DJGPP__ 212 setmode (tty, O_BINARY); 213 __djgpp_set_ctrl_c (1); /* re-enable SIGINT generation by Ctrl-C */ 214 #endif 215 } 216 217 /* Restore the tty settings back to what they were before we started using 218 this terminal. */ 219 static void 220 pc_unprep_terminal (void) 221 { 222 int tty; 223 224 textattr (outside_info.normattr); 225 226 /* Do not set screen height if we already have it, because 227 doing so erases the screen. */ 228 if (outside_info.screenheight != ScreenRows ()) 229 { 230 _set_screen_lines (outside_info.screenheight); 231 textmode (LASTMODE); 232 } 233 else 234 pc_clear_to_eol (); /* for text attributes to really take effect */ 235 236 /* Switch back to text mode on stdin. */ 237 tty = fileno (stdin); 238 #ifdef __DJGPP__ 239 setmode (tty, O_TEXT); 240 #endif 241 } 242 243 /* Initialize the terminal which is known as TERMINAL_NAME. If this 244 terminal doesn't have cursor addressability, `terminal_is_dumb_p' 245 becomes nonzero. The variables SCREENHEIGHT and SCREENWIDTH are set 246 to the dimensions that this terminal actually has. The variable 247 TERMINAL_HAS_META_P becomes nonzero if this terminal supports a Meta 248 key. Finally, the terminal screen is cleared. */ 249 static void 250 pc_initialize_terminal (term_name) 251 char *term_name; 252 { 253 char *info_colors; 254 255 if (!term_name) 256 { 257 term_name = getenv ("TERM"); 258 if (!term_name) 259 term_name = "pc-dos"; /* ``what's in a name?'' */ 260 } 261 262 /* Get current video information, to be restored later. */ 263 if (outside_info.screenwidth == 0) 264 gettextinfo (&outside_info); 265 266 /* Current screen colors are the default. */ 267 norm_attr = outside_info.normattr; 268 inv_attr = (((outside_info.normattr & 7) << 4) | 269 ((outside_info.normattr & 0x7f) >> 4)); 270 271 /* Does the user want non-default colors? */ 272 info_colors = getenv ("INFO_COLORS"); 273 if ((info_colors != (char *)0) && !speech_friendly) 274 { 275 /* Decode a color from a string descriptor. 276 The descriptor string is a sequence of color specifiers separated 277 by a non-numeric character. Each color specifier should represent 278 a small integer which fits into an unsigned char, and can be given 279 in any base supported by strtoul. Examples of valid descriptors: 280 281 "10 31" 282 "0x13/0x45" 283 "007.077" 284 285 The separator between two color specifiers can be any character which 286 cannot be used in a printed representation of an integer number. */ 287 char *endp; 288 unsigned long color_desc = strtoul (info_colors, &endp, 0); 289 290 if (color_desc <= UCHAR_MAX) 291 { 292 norm_attr = (unsigned char)color_desc; 293 color_desc = strtoul (endp + 1, &endp, 0); 294 if (color_desc <= UCHAR_MAX) 295 inv_attr = (unsigned char)color_desc; 296 } 297 } 298 299 /* We can scroll. */ 300 terminal_can_scroll = 1; 301 302 /* We know how to produce a visible bell, if somebody's looking... */ 303 if (!speech_friendly) 304 terminal_has_visible_bell_p = 1; 305 306 /* We have a Meta key. */ 307 terminal_has_meta_p = 1; 308 309 /* We are *certainly* NOT dumb! */ 310 terminal_is_dumb_p = 0; 311 312 pc_get_screen_size (); 313 314 /* Store the arrow keys. */ 315 term_ku = (char *)find_sequence (K_Up); 316 term_kd = (char *)find_sequence (K_Down); 317 term_kr = (char *)find_sequence (K_Right); 318 term_kl = (char *)find_sequence (K_Left); 319 320 term_kP = (char *)find_sequence (K_PageUp); 321 term_kN = (char *)find_sequence (K_PageDown); 322 323 #if defined(INFOKEY) 324 term_kh = (char *)find_sequence (K_Home); 325 term_ke = (char *)find_sequence (K_End); 326 term_ki = (char *)find_sequence (K_Insert); 327 term_kx = (char *)find_sequence (K_Delete); 328 #endif 329 330 /* Set all the hooks to our PC-specific functions. */ 331 terminal_begin_inverse_hook = pc_begin_inverse; 332 terminal_end_inverse_hook = pc_end_inverse; 333 terminal_prep_terminal_hook = pc_prep_terminal; 334 terminal_unprep_terminal_hook = pc_unprep_terminal; 335 terminal_up_line_hook = pc_up_line; 336 terminal_down_line_hook = pc_down_line; 337 terminal_clear_screen_hook = pc_clear_screen; 338 terminal_clear_to_eol_hook = pc_clear_to_eol; 339 terminal_get_screen_size_hook = pc_get_screen_size; 340 terminal_goto_xy_hook = pc_goto_xy; 341 terminal_put_text_hook = pc_put_text; 342 terminal_ring_bell_hook = pc_ring_bell; 343 terminal_write_chars_hook = pc_write_chars; 344 terminal_scroll_terminal_hook = pc_scroll_terminal; 345 } 346 347 /* **************************************************************** */ 348 /* */ 349 /* How to Read Characters From the PC Terminal */ 350 /* */ 351 /* **************************************************************** */ 352 353 /* This will most certainly work ONLY with DJGPP. */ 354 #ifdef __DJGPP__ 355 356 #include <errno.h> 357 #include <sys/fsext.h> 358 #include <dpmi.h> 359 360 /* Translation table for some special keys. 361 Arrow keys which are standard on other keyboards are translated into 362 standard ESC-sequences, in case somebody rebinds the simple keys 363 (like C-f, C-b, C-n, etc.). 364 365 The strange "\033\061" prefix in some keys is a numeric argument of 366 one, which means ``do the next command once''. It is here so that 367 when the according PC key is pressed in the middle of an incremental 368 search, Info doesn't see just an ASCII character like `n' or `B', 369 and doesn't add it to the search string; instead, it will exit the 370 incremental search and then perform the command. */ 371 static struct 372 { 373 int inkey; 374 unsigned char const * const sequence; 375 } DJGPP_keytab[] = { /* these are for moving between nodes... */ 376 {K_Control_PageDown, "\033\061n"}, 377 {K_Control_PageUp, "\033\061p"}, 378 {K_Control_Up, "\033\061u"}, 379 {K_Control_Down, "\033\061m"}, 380 {K_Control_Center, "\033\061l"}, 381 382 #if defined(INFOKEY) 383 {K_Home, "\033[H"}, /* ...and these are for moving IN a node */ 384 {K_End, "\033[F"}, /* they're Numeric-Keypad-Keys, so */ 385 #else 386 {K_Home, "\001"}, 387 {K_End, "\005"}, 388 #endif 389 {K_Left, "\033[D"}, /* NUMLOCK should be off !! */ 390 {K_Right, "\033[C"}, 391 {K_Down, "\033[B"}, 392 {K_Up, "\033[A"}, 393 {K_PageDown, "\033[G"}, 394 {K_PageUp, "\033[I"}, 395 {K_Control_Left, "\033b"}, 396 {K_Control_Right, "\033f"}, 397 {K_Control_Home, "\033<"}, 398 {K_Control_End, "\033>"}, 399 400 #if defined(INFOKEY) 401 {K_EHome, "\033[H"}, /* these are also for moving IN a node */ 402 {K_EEnd, "\033[F"}, /* they're the "extended" (Grey) keys */ 403 #else 404 {K_EHome, "\001"}, 405 {K_EEnd, "\005"}, 406 #endif 407 {K_ELeft, "\033[D"}, 408 {K_ERight, "\033[C"}, 409 {K_EDown, "\033[B"}, 410 {K_EUp, "\033[A"}, 411 {K_EPageDown, "\033[G"}, 412 {K_EPageUp, "\033[I"}, 413 {K_Control_ELeft, "\033b"}, 414 {K_Control_ERight, "\033f"}, 415 {K_Control_EHome, "\033<"}, 416 {K_Control_EEnd, "\033>"}, 417 418 {K_BackTab, "\033\011"}, 419 {K_F1, "\10"}, /* YEAH, gimme that good old F-one-thing */ 420 {K_Delete, "\177"}, /* to make Kp-Del be DEL (0x7f) */ 421 {K_EDelete, "\177"}, /* to make Delete be DEL (0x7f) */ 422 #if defined(INFOKEY) 423 {K_Insert, "\033[L"}, 424 {K_EInsert, "\033[L"}, 425 #endif 426 427 /* These are here to map more Alt-X keys to ESC X sequences. */ 428 {K_Alt_Q, "\033q"}, 429 {K_Alt_W, "\033w"}, 430 {K_Alt_E, "\033e"}, 431 {K_Alt_R, "\033r"}, 432 {K_Alt_T, "\033t"}, 433 {K_Alt_Y, "\033y"}, 434 {K_Alt_U, "\033u"}, 435 {K_Alt_I, "\033i"}, 436 {K_Alt_O, "\033o"}, 437 {K_Alt_P, "\033p"}, 438 {K_Alt_LBracket, "\033["}, 439 {K_Alt_RBracket, "\033]"}, 440 {K_Alt_Return, "\033\015"}, 441 {K_Alt_A, "\033a"}, 442 {K_Alt_S, "\033s"}, 443 {K_Alt_D, "\033d"}, 444 {K_Alt_F, "\033f"}, 445 {K_Alt_G, "\033g"}, 446 {K_Alt_H, "\033h"}, 447 {K_Alt_J, "\033j"}, 448 {K_Alt_K, "\033k"}, 449 {K_Alt_L, "\033l"}, 450 {K_Alt_Semicolon, "\033;"}, 451 {K_Alt_Quote, "\033'"}, 452 {K_Alt_Backquote, "\033`"}, 453 {K_Alt_Backslash, "\033\\"}, 454 {K_Alt_Z, "\033z"}, 455 {K_Alt_X, "\033x"}, 456 {K_Alt_C, "\033c"}, 457 {K_Alt_V, "\033v"}, 458 {K_Alt_B, "\033b"}, 459 {K_Alt_N, "\033n"}, 460 {K_Alt_M, "\033m"}, 461 {K_Alt_Comma, "\033<"}, /* our reader cannot distinguish between */ 462 {K_Alt_Period, "\033>"}, /* Alt-. and Alt->, so we cheat a little */ 463 {K_Alt_Slash, "\033?"}, /* ditto, to get Alt-? */ 464 {K_Alt_Backspace, "\033\177"}, /* M-DEL, to delete word backwards */ 465 {K_Alt_1, "\033\061"}, 466 {K_Alt_2, "\033\062"}, 467 {K_Alt_3, "\033\063"}, 468 {K_Alt_4, "\033\064"}, 469 {K_Alt_5, "\033\065"}, 470 {K_Alt_6, "\033\066"}, 471 {K_Alt_7, "\033\067"}, 472 {K_Alt_8, "\033\070"}, 473 {K_Alt_9, "\033\071"}, 474 {K_Alt_0, "\033\060"}, 475 {K_Alt_Dash, "\033\055"}, 476 {K_Alt_EPageUp, "\033\033[I"}, 477 {K_Alt_EPageDown, "\033\033[G"}, 478 {K_Alt_Equals, "\033\075"}, 479 {K_Alt_EDelete, "\033\177"}, 480 {K_Alt_Tab, "\033\011"}, 481 {0, 0} 482 }; 483 484 /* Given a key, return the sequence of characters which 485 our keyboard driver generates. */ 486 static unsigned const char * 487 find_sequence (int key) 488 { 489 int i; 490 491 for (i = 0; DJGPP_keytab[i].inkey; i++) 492 if (key == DJGPP_keytab[i].inkey) 493 return DJGPP_keytab[i].sequence; 494 495 return (unsigned const char *)NULL; 496 } 497 498 /* Return zero if a key is pending in the 499 keyboard buffer, non-zero otherwise. */ 500 static int 501 kbd_buffer_empty (void) 502 { 503 __dpmi_regs r; 504 int retval; 505 506 r.h.ah = 0x11; /* Get enhanced keyboard status */ 507 __dpmi_int (0x16, &r); 508 509 /* If the keyboard buffer is empty, the Zero Flag will be set. */ 510 return (r.x.flags & 0x40) == 0x40; 511 } 512 513 /* The buffered characters pending to be read. 514 Actually, Info usually reads a single character, but when we 515 translate a key into a sequence of characters, we keep them here. */ 516 static unsigned char buffered[512]; 517 518 /* Index of the next buffered character to be returned. */ 519 static int buf_idx; 520 521 /* Return the number of characters waiting to be read. */ 522 long 523 pc_term_chars_avail (void) 524 { 525 if (buf_idx >= sizeof (buffered)) /* paranoia */ 526 { 527 buf_idx = 0; 528 buffered[buf_idx] = '\0'; 529 return 0; 530 } 531 else 532 return (long)strlen (buffered + buf_idx); 533 } 534 535 /* Our special terminal keyboard reader. It will be called by 536 low-level libc functions when the application calls `read' or 537 the ANSI-standard stream-oriented read functions. If the 538 caller wants to read the terminal, we redirect the call to 539 the BIOS keyboard functions, since that lets us recognize more 540 keys than DOS does. */ 541 static int 542 keyboard_read (__FSEXT_Fnumber func, int *retval, va_list rest_args) 543 { 544 /* When we are called, REST_ARGS are: file_descriptor, buf, nbytes. */ 545 unsigned char *buf; 546 size_t nbytes, nread = 0; 547 int fd = va_arg (rest_args, int); 548 549 /* Is this call for us? */ 550 if (func != __FSEXT_read || !isatty (fd)) 551 return 0; /* and the usual DOS call will be issued */ 552 553 buf = va_arg (rest_args, unsigned char *); 554 nbytes = va_arg (rest_args, size_t); 555 556 if (!buf) 557 { 558 errno = EINVAL; 559 *retval = -1; 560 return 1; 561 } 562 if (!nbytes) 563 { 564 *retval = 0; 565 return 1; 566 } 567 568 /* Loop here until enough bytes has been read. */ 569 do 570 { 571 int key; 572 573 /* If any ``buffered characters'' are left, return as much 574 of them as the caller wanted. */ 575 while (buffered[buf_idx] && nbytes) 576 { 577 *buf++ = buffered[buf_idx++]; 578 nread++; 579 nbytes--; 580 } 581 582 if (nbytes <= 0) 583 break; 584 585 /* Wait for another key. 586 We do that in a busy-waiting loop so we don't get parked 587 inside a BIOS call, which will effectively disable signals. 588 While we wait for them to type something, we repeatedly 589 release the rest of our time slice, so that other programs 590 in a multitasking environment, such as Windows, get more cycles. */ 591 while (kbd_buffer_empty ()) 592 __dpmi_yield (); 593 594 key = getxkey (); 595 596 /* Translate the key if necessary. 597 Untranslated non-ASCII keys are silently ignored. */ 598 if ((key & 0x300) != 0) 599 { 600 unsigned char const * key_sequence = find_sequence (key); 601 602 if (key_sequence != NULL) 603 { 604 strcpy (buffered, key_sequence); 605 buf_idx = 0; 606 } 607 } 608 else if (key == K_Control_Z) 609 raise (SIGUSR1); /* we don't have SIGTSTP, so simulate it */ 610 else if (key <= 0xff) 611 { 612 *buf++ = key; 613 nbytes--; 614 nread++; 615 } 616 } 617 while (nbytes > 0); 618 619 *retval = nread; 620 return 1; /* meaning that we handled the call */ 621 } 622 623 /* Install our keyboard handler. 624 This is called by the startup code before `main'. */ 625 static void __attribute__((constructor)) 626 install_keyboard_handler (void) 627 { 628 __FSEXT_set_function (fileno (stdin), keyboard_read); 629 630 /* We need to set this single hook here; the rest 631 will be set by pc_initialize_terminal when it is called. */ 632 terminal_initialize_terminal_hook = pc_initialize_terminal; 633 } 634 635 #endif /* __DJGPP__ */ 636 637 /* **************************************************************** */ 638 /* */ 639 /* Emulation of SIGTSTP on Ctrl-Z */ 640 /* */ 641 /* **************************************************************** */ 642 643 #include <limits.h> 644 #include "signals.h" 645 #include "session.h" 646 647 #ifndef PATH_MAX 648 # define PATH_MAX 512 649 #endif 650 651 /* Effectively disable signals which aren't defined 652 (assuming no signal can ever be zero). 653 SIGINT is ANSI, so we expect it to be always defined. */ 654 #ifndef SIGUSR1 655 # define SIGUSR1 0 656 #endif 657 #ifndef SIGQUIT 658 # define SIGQUIT 0 659 #endif 660 661 int 662 kill (pid_t pid, int sig) 663 { 664 static char interrupted_msg[] = "Interrupted\r\n"; 665 static char stopped_msg[] = "Stopped. Type `exit RET' to return.\r\n"; 666 char cwd[PATH_MAX + 1]; 667 668 if (pid == getpid () 669 || pid == 0 670 || pid == -1 671 || pid == -getpid ()) 672 { 673 switch (sig) 674 { 675 RETSIGTYPE (*old_INT)(int), (*old_QUIT)(int); 676 677 case SIGINT: 678 #ifdef __DJGPP__ 679 /* If SIGINT was generated by a readable key, we want to remove 680 it from the PC keyboard buffer, so that DOS and other 681 programs never see it. DJGPP signal-handling mechanism 682 doesn't remove the INT key from the keyboard buffer. */ 683 if (!kbd_buffer_empty ()) 684 getxkey (); 685 #endif 686 pc_write_chars (interrupted_msg, sizeof (interrupted_msg) - 1); 687 xexit (1); 688 case SIGUSR1: 689 /* Simulate SIGTSTP by invoking a subsidiary shell. */ 690 pc_goto_xy (0, outside_info.screenheight - 1); 691 pc_clear_to_eol (); 692 pc_write_chars (stopped_msg, sizeof (stopped_msg) - 1); 693 694 /* The child shell can change the working directory, so 695 we need to save and restore it, since it is global. */ 696 if (!getcwd (cwd, PATH_MAX)) /* should never happen */ 697 cwd[0] = '\0'; 698 699 /* We don't want to get fatal signals while the subshell runs. */ 700 old_INT = signal (SIGINT, SIG_IGN); 701 old_QUIT = signal (SIGQUIT, SIG_IGN); 702 system (""); 703 if (*cwd) 704 chdir (cwd); 705 signal (SIGINT, old_INT); 706 signal (SIGQUIT, old_QUIT); 707 break; 708 default: 709 if (sig) 710 raise (sig); 711 break; 712 } 713 return 0; 714 } 715 else 716 return -1; 717 } 718 719 /* These should never be called, but they make the linker happy. */ 720 721 void tputs (char *a, int b, int (*c)()) 722 { 723 perror ("tputs"); 724 } 725 726 char* tgoto (char*a, int b, int c) 727 { 728 perror ("tgoto"); return 0; /* here and below, added dummy retvals */ 729 } 730 731 int tgetnum (char*a) 732 { 733 perror ("tgetnum"); return 0; 734 } 735 736 int tgetflag (char*a) 737 { 738 perror ("tgetflag"); return 0; 739 } 740 741 char* tgetstr (char *a, char **b) 742 { 743 perror ("tgetstr"); return 0; 744 } 745 746 int tgetent (char*a, char*b) 747 { 748 perror ("tgetent"); return 0; 749 } 750 751 int tcgetattr(int fildes, struct termios *termios_p) 752 { 753 perror ("tcgetattr"); return 0; 754 } 755 756 int tcsetattr(int fd, int opt_actions, const struct termios *termios_p) 757 { 758 perror ("tcsetattr"); return 0; 759 } 760