Annotation of early-roguelike/rogue3/mdport.c, Revision 1.1
1.1 ! rubenllo 1: /*
! 2: mdport.c - Machine Dependent Code for Porting Unix/Curses games
! 3:
! 4: Copyright (C) 2005 Nicholas J. Kisseberth
! 5: All rights reserved.
! 6:
! 7: Redistribution and use in source and binary forms, with or without
! 8: modification, are permitted provided that the following conditions
! 9: are met:
! 10: 1. Redistributions of source code must retain the above copyright
! 11: notice, this list of conditions and the following disclaimer.
! 12: 2. Redistributions in binary form must reproduce the above copyright
! 13: notice, this list of conditions and the following disclaimer in the
! 14: documentation and/or other materials provided with the distribution.
! 15: 3. Neither the name(s) of the author(s) nor the names of other contributors
! 16: may be used to endorse or promote products derived from this software
! 17: without specific prior written permission.
! 18:
! 19: THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) AND CONTRIBUTORS ``AS IS'' AND
! 20: ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 21: IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 22: ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTORS BE LIABLE
! 23: FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 24: DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 25: OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 26: HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 27: LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 28: OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 29: SUCH DAMAGE.
! 30: */
! 31:
! 32: #include <stdlib.h>
! 33: #include <string.h>
! 34:
! 35: #if defined(_WIN32)
! 36: #include <Windows.h>
! 37: #include <io.h>
! 38: #include <sys/locking.h>
! 39: #include <Lmcons.h>
! 40: #include <conio.h>
! 41: #pragma warning( disable: 4201 )
! 42: #include <shlobj.h>
! 43: #pragma warning( default: 4201 )
! 44: #include <Shlwapi.h>
! 45: #undef MOUSE_MOVED
! 46: #endif
! 47:
! 48: #include <curses.h>
! 49:
! 50: #include "mdport.h"
! 51:
! 52: #if defined(HAVE_SYS_TYPES)
! 53: #include <sys/types.h>
! 54: #endif
! 55:
! 56: #if defined(HAVE_PROCESS_H)
! 57: #include <process.h>
! 58: #endif
! 59:
! 60: #if defined(HAVE_PWD_H)
! 61: #include <pwd.h>
! 62: #endif
! 63:
! 64: #if defined(HAVE_ARPA_INET_H)
! 65: #include <arpa/inet.h> /* Solaris 2.8 required this for htonl() and ntohl() */
! 66: #endif
! 67:
! 68: #if defined(HAVE_TERMIOS_H)
! 69: #include <termios.h>
! 70: #endif
! 71:
! 72: #if defined(HAVE_UNISTD_H)
! 73: #ifndef __USE_GNU
! 74: #define __USE_GNU
! 75: #include <unistd.h>
! 76: #undef __USE_GNU
! 77: #else
! 78: #include <unistd.h>
! 79: #endif
! 80: #endif
! 81:
! 82: #if defined(HAVE_TERM_H)
! 83: #include <term.h>
! 84: #elif defined(HAVE_NCURSES_TERM_H)
! 85: #include <ncurses/term.h>
! 86: #endif
! 87:
! 88: #if defined(HAVE_WORKING_FORK)
! 89: #include <sys/wait.h>
! 90: #endif
! 91:
! 92: #ifdef HAVE_UTMPX_H
! 93: #include <utmpx.h>
! 94: #endif
! 95:
! 96: #ifdef HAVE_ERRNO_H
! 97: #include <errno.h>
! 98: #endif
! 99:
! 100: #include <ctype.h>
! 101: #include <fcntl.h>
! 102: #include <limits.h>
! 103: #include <sys/stat.h>
! 104: #include <signal.h>
! 105: #include <time.h>
! 106:
! 107: #define NOOP(x) (x += 0)
! 108:
! 109: static int pass_ctrl_keypad = 1;
! 110:
! 111: void
! 112: md_init(int options)
! 113: {
! 114: #if defined(__INTERIX)
! 115: char *term;
! 116:
! 117: term = getenv("TERM");
! 118:
! 119: if (term == NULL)
! 120: setenv("TERM","interix");
! 121: #elif defined(__DJGPP__)
! 122: _fmode = _O_BINARY;
! 123: #elif defined(_WIN32)
! 124: _fmode = _O_BINARY;
! 125: #endif
! 126:
! 127: #if defined(HAVE_ESCDELAY) || defined(NCURSES_VERSION)
! 128: ESCDELAY=64;
! 129: #endif
! 130:
! 131: #if defined(DUMP)
! 132: md_onsignal_default();
! 133: #else
! 134: md_onsignal_exit();
! 135: #endif
! 136:
! 137: if (options & MD_STRIP_CTRL_KEYPAD)
! 138: pass_ctrl_keypad = 0;
! 139: else
! 140: pass_ctrl_keypad = 1;
! 141: }
! 142:
! 143: void
! 144: md_onsignal_default(void)
! 145: {
! 146: #ifdef SIGHUP
! 147: signal(SIGHUP, SIG_DFL);
! 148: #endif
! 149: #ifdef SIGQUIT
! 150: signal(SIGQUIT, SIG_DFL);
! 151: #endif
! 152: #ifdef SIGILL
! 153: signal(SIGILL, SIG_DFL);
! 154: #endif
! 155: #ifdef SIGTRAP
! 156: signal(SIGTRAP, SIG_DFL);
! 157: #endif
! 158: #ifdef SIGIOT
! 159: signal(SIGIOT, SIG_DFL);
! 160: #endif
! 161: #ifdef SIGEMT
! 162: signal(SIGEMT, SIG_DFL);
! 163: #endif
! 164: #ifdef SIGFPE
! 165: signal(SIGFPE, SIG_DFL);
! 166: #endif
! 167: #ifdef SIGBUS
! 168: signal(SIGBUS, SIG_DFL);
! 169: #endif
! 170: #ifdef SIGSEGV
! 171: signal(SIGSEGV, SIG_DFL);
! 172: #endif
! 173: #ifdef SIGSYS
! 174: signal(SIGSYS, SIG_DFL);
! 175: #endif
! 176: #ifdef SIGTERM
! 177: signal(SIGTERM, SIG_DFL);
! 178: #endif
! 179: }
! 180:
! 181: void
! 182: md_onsignal_exit(void)
! 183: {
! 184: #ifdef SIGHUP
! 185: signal(SIGHUP, SIG_DFL);
! 186: #endif
! 187: #ifdef SIGQUIT
! 188: signal(SIGQUIT, exit);
! 189: #endif
! 190: #ifdef SIGILL
! 191: signal(SIGILL, exit);
! 192: #endif
! 193: #ifdef SIGTRAP
! 194: signal(SIGTRAP, exit);
! 195: #endif
! 196: #ifdef SIGIOT
! 197: signal(SIGIOT, exit);
! 198: #endif
! 199: #ifdef SIGEMT
! 200: signal(SIGEMT, exit);
! 201: #endif
! 202: #ifdef SIGFPE
! 203: signal(SIGFPE, exit);
! 204: #endif
! 205: #ifdef SIGBUS
! 206: signal(SIGBUS, exit);
! 207: #endif
! 208: #ifdef SIGSEGV
! 209: signal(SIGSEGV, exit);
! 210: #endif
! 211: #ifdef SIGSYS
! 212: signal(SIGSYS, exit);
! 213: #endif
! 214: #ifdef SIGTERM
! 215: signal(SIGTERM, exit);
! 216: #endif
! 217: }
! 218:
! 219: extern void auto_save(int sig);
! 220: extern void endit(int sig);
! 221: extern void quit(int sig);
! 222:
! 223: void
! 224: md_onsignal_autosave(void)
! 225: {
! 226:
! 227: #ifdef SIGHUP
! 228: signal(SIGHUP, auto_save);
! 229: #endif
! 230: #ifdef SIGQUIT
! 231: signal(SIGQUIT, endit);
! 232: #endif
! 233: #ifdef SIGILL
! 234: signal(SIGILL, auto_save);
! 235: #endif
! 236: #ifdef SIGTRAP
! 237: signal(SIGTRAP, auto_save);
! 238: #endif
! 239: #ifdef SIGIOT
! 240: signal(SIGIOT, auto_save);
! 241: #endif
! 242: #ifdef SIGEMT
! 243: signal(SIGEMT, auto_save);
! 244: #endif
! 245: #ifdef SIGFPE
! 246: signal(SIGFPE, auto_save);
! 247: #endif
! 248: #ifdef SIGBUS
! 249: signal(SIGBUS, auto_save);
! 250: #endif
! 251: #ifdef SIGSEGV
! 252: /* If there's a segfault, the game state is probably trashed
! 253: and there's no point saving it. */
! 254: signal(SIGSEGV, SIG_DFL);
! 255: #endif
! 256: #ifdef SIGSYS
! 257: signal(SIGSYS, auto_save);
! 258: #endif
! 259: #ifdef SIGTERM
! 260: signal(SIGTERM, auto_save);
! 261: #endif
! 262: #ifdef SIGINT
! 263: signal(SIGINT, quit);
! 264: #endif
! 265: }
! 266:
! 267: #ifdef _WIN32
! 268: static int md_standout_mode = 0;
! 269: #endif
! 270:
! 271: void
! 272: md_raw_standout(void)
! 273: {
! 274: #ifdef _WIN32
! 275: CONSOLE_SCREEN_BUFFER_INFO csbiInfo;
! 276: HANDLE hStdout;
! 277: WORD fgattr,bgattr;
! 278:
! 279: if (md_standout_mode == 0)
! 280: {
! 281: hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
! 282: GetConsoleScreenBufferInfo(hStdout, &csbiInfo);
! 283: fgattr = (csbiInfo.wAttributes & 0xF);
! 284: bgattr = (csbiInfo.wAttributes & 0xF0);
! 285: SetConsoleTextAttribute(hStdout,(fgattr << 4) | (bgattr >> 4));
! 286: md_standout_mode = 1;
! 287: }
! 288: #elif defined(SO)
! 289: tputs(SO,0,putchar);
! 290: fflush(stdout);
! 291: #endif
! 292: }
! 293:
! 294: void
! 295: md_raw_standend(void)
! 296: {
! 297: #ifdef _WIN32
! 298: CONSOLE_SCREEN_BUFFER_INFO csbiInfo;
! 299: HANDLE hStdout;
! 300: WORD fgattr,bgattr;
! 301:
! 302: if (md_standout_mode == 1)
! 303: {
! 304: hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
! 305: GetConsoleScreenBufferInfo(hStdout, &csbiInfo);
! 306: fgattr = (csbiInfo.wAttributes & 0xF);
! 307: bgattr = (csbiInfo.wAttributes & 0xF0);
! 308: SetConsoleTextAttribute(hStdout,(fgattr << 4) | (bgattr >> 4));
! 309: md_standout_mode = 0;
! 310: }
! 311: #elif defined(SE)
! 312: tputs(SE,0,putchar);
! 313: fflush(stdout);
! 314: #endif
! 315: }
! 316:
! 317: int
! 318: md_unlink_open_file(const char *file, FILE *inf)
! 319: {
! 320: #ifdef _WIN32
! 321: fclose(inf);
! 322: (void) _chmod(file, 0600);
! 323: return( _unlink(file) );
! 324: #else
! 325: return(unlink(file));
! 326: #endif
! 327: }
! 328:
! 329: int
! 330: md_unlink(char *file)
! 331: {
! 332: #ifdef _WIN32
! 333: (void) _chmod(file, 0600);
! 334: return( _unlink(file) );
! 335: #else
! 336: return(unlink(file));
! 337: #endif
! 338: }
! 339:
! 340: int
! 341: md_chmod(const char *filename, int mode)
! 342: {
! 343: #ifdef _WIN32
! 344: return( _chmod(filename, mode) );
! 345: #else
! 346: return( chmod(filename, mode) );
! 347: #endif
! 348: }
! 349:
! 350: void
! 351: md_normaluser(void)
! 352: {
! 353: #if defined(HAVE_GETGID) && defined(HAVE_GETUID)
! 354: gid_t realgid = getgid();
! 355: uid_t realuid = getuid();
! 356:
! 357: #if defined(HAVE_SETRESGID)
! 358: if (setresgid(-1, realgid, realgid) != 0) {
! 359: #elif defined (HAVE_SETREGID)
! 360: if (setregid(realgid, realgid) != 0) {
! 361: #elif defined (HAVE_SETGID)
! 362: if (setgid(realgid) != 0) {
! 363: #else
! 364: if (0) {
! 365: #endif
! 366: perror("Could not drop setgid privileges. Aborting.");
! 367: exit(1);
! 368: }
! 369:
! 370: #if defined(HAVE_SETRESUID)
! 371: if (setresuid(-1, realuid, realuid) != 0) {
! 372: #elif defined(HAVE_SETREUID)
! 373: if (setreuid(realuid, realuid) != 0) {
! 374: #elif defined(HAVE_SETUID)
! 375: if (setuid(realuid) != 0) {
! 376: #else
! 377: if (0) {
! 378: #endif
! 379: perror("Could not drop setuid privileges. Aborting.");
! 380: exit(1);
! 381: }
! 382: #endif
! 383: }
! 384:
! 385: uid_t
! 386: md_getuid(void)
! 387: {
! 388: #ifdef HAVE_GETUID
! 389: return( getuid() );
! 390: #else
! 391: return(42);
! 392: #endif
! 393: }
! 394:
! 395: char *
! 396: md_getusername(void)
! 397: {
! 398: static char login[80];
! 399: char *l = NULL;
! 400: #ifdef _WIN32
! 401: LPSTR mybuffer;
! 402: DWORD size = UNLEN + 1;
! 403: TCHAR buffer[UNLEN + 1];
! 404:
! 405: mybuffer = buffer;
! 406: GetUserName(mybuffer,&size);
! 407: l = mybuffer;
! 408: #elif defined(HAVE_GETPWUID)&& !defined(__DJGPP__)
! 409: struct passwd *pw;
! 410:
! 411: pw = getpwuid(getuid());
! 412: /* Don't segfault if getpwuid fails (and the thing is wildly possible) */
! 413: if (pw != NULL)
! 414: l = pw->pw_name;
! 415: else
! 416: l = NULL;
! 417: #endif
! 418:
! 419: if ((l == NULL) || (*l == '\0'))
! 420: if ( (l = getenv("USERNAME")) == NULL )
! 421: if ( (l = getenv("LOGNAME")) == NULL )
! 422: if ( (l = getenv("USER")) == NULL )
! 423: l = "nobody";
! 424:
! 425: strncpy(login,l,80);
! 426: login[79] = 0;
! 427:
! 428: return(login);
! 429: }
! 430:
! 431: char *
! 432: md_gethomedir(void)
! 433: {
! 434: static char homedir[PATH_MAX];
! 435: char *h = NULL;
! 436: size_t len;
! 437: #if defined(_WIN32)
! 438: TCHAR szPath[PATH_MAX];
! 439: #endif
! 440: #if defined(_WIN32) || defined(DJGPP)
! 441: char slash = '\\';
! 442: #else
! 443: char slash = '/';
! 444: struct passwd *pw;
! 445: pw = getpwuid(getuid());
! 446: /* Don't segfault if getpwuid fails */
! 447: if (pw != NULL)
! 448: h = pw->pw_dir;
! 449: else
! 450: h = NULL;
! 451:
! 452: if (strcmp(h,"/") == 0)
! 453: h = NULL;
! 454: #endif
! 455: homedir[0] = 0;
! 456: #ifdef _WIN32
! 457: if(SUCCEEDED(SHGetFolderPath(NULL, CSIDL_PERSONAL, NULL, 0, szPath)))
! 458: h = szPath;
! 459: #endif
! 460:
! 461: if ( (h == NULL) || (*h == '\0') )
! 462: {
! 463: if ( (h = getenv("HOME")) == NULL )
! 464: {
! 465: if ( (h = getenv("HOMEDRIVE")) == NULL)
! 466: h = "";
! 467: else
! 468: {
! 469: strncpy(homedir,h,PATH_MAX-1);
! 470: homedir[PATH_MAX-1] = 0;
! 471:
! 472: if ( (h = getenv("HOMEPATH")) == NULL)
! 473: h = "";
! 474: }
! 475: }
! 476: }
! 477:
! 478:
! 479: len = strlen(homedir);
! 480: strncat(homedir,h,PATH_MAX-len-1);
! 481: len = strlen(homedir);
! 482:
! 483: if ((len > 0) && (homedir[len-1] != slash)) {
! 484: homedir[len] = slash;
! 485: homedir[len+1] = 0;
! 486: }
! 487:
! 488: return(homedir);
! 489: }
! 490:
! 491: void
! 492: md_sleep(int s)
! 493: {
! 494: #ifdef _WIN32
! 495: Sleep(s);
! 496: #else
! 497: sleep(s);
! 498: #endif
! 499: }
! 500:
! 501: char *
! 502: md_getshell(void)
! 503: {
! 504: static char shell[PATH_MAX];
! 505: char *s = NULL;
! 506: #ifdef _WIN32
! 507: char *def = "C:\\WINDOWS\\SYSTEM32\\CMD.EXE";
! 508: #elif defined(__DJGPP__)
! 509: char *def = "C:\\COMMAND.COM";
! 510: #else
! 511: char *def = "/bin/sh";
! 512: struct passwd *pw;
! 513: pw = getpwuid(getuid());
! 514: /* don't segfault if getpwuid fails */
! 515: if (pw != NULL)
! 516: s = pw->pw_shell;
! 517: else
! 518: s = NULL;
! 519: #endif
! 520: if ((s == NULL) || (*s == '\0'))
! 521: if ( (s = getenv("COMSPEC")) == NULL)
! 522: if ( (s = getenv("SHELL")) == NULL)
! 523: if ( (s = getenv("SystemRoot")) == NULL)
! 524: s = def;
! 525:
! 526: strncpy(shell,s,PATH_MAX);
! 527: shell[PATH_MAX-1] = 0;
! 528:
! 529: return(shell);
! 530: }
! 531:
! 532: int
! 533: md_shellescape(void)
! 534: {
! 535: #if defined(HAVE_WORKING_FORK)
! 536: int ret_status;
! 537: int pid;
! 538: void (*myquit)(int);
! 539: void (*myend)(int);
! 540: char *sh;
! 541:
! 542: sh = md_getshell();
! 543:
! 544: while((pid = fork()) < 0)
! 545: sleep(1);
! 546:
! 547: if (pid == 0) /* Shell Process */
! 548: {
! 549: /*
! 550: * Set back to original user, just in case
! 551: */
! 552: md_normaluser();
! 553: execl(sh == NULL ? "/bin/sh" : sh, "shell", "-i", NULL);
! 554: perror("No shelly");
! 555: _exit(-1);
! 556: }
! 557: else /* Application */
! 558: {
! 559: myend = signal(SIGINT, SIG_IGN);
! 560: #ifdef SIGQUIT
! 561: myquit = signal(SIGQUIT, SIG_IGN);
! 562: #endif
! 563: while (wait(&ret_status) != pid)
! 564: continue;
! 565:
! 566: signal(SIGINT, myend);
! 567: #ifdef SIGQUIT
! 568: signal(SIGQUIT, myquit);
! 569: #endif
! 570: }
! 571: return(ret_status);
! 572: #elif defined(HAVE__SPAWNL)
! 573: return((int)_spawnl(_P_WAIT,md_getshell(),"shell",NULL,0));
! 574: #elif defined(HAVE_SPAWNL)
! 575: return ( spawnl(P_WAIT,md_getshell(),"shell",NULL,0) );
! 576: #else
! 577: return(0);
! 578: #endif
! 579: }
! 580:
! 581: int
! 582: directory_exists(char *dirname)
! 583: {
! 584: struct stat sb;
! 585:
! 586: if (stat(dirname, &sb) == 0) /* path exists */
! 587: return (sb.st_mode & S_IFDIR);
! 588:
! 589: return(0);
! 590: }
! 591:
! 592: char *
! 593: md_getrealname(uid_t uid)
! 594: {
! 595: static char uidstr[20];
! 596: #if !defined(_WIN32) && !defined(DJGPP)
! 597: struct passwd *pp;
! 598:
! 599: if ((pp = getpwuid(uid)) == NULL)
! 600: {
! 601: sprintf(uidstr,"%d", uid);
! 602: return(uidstr);
! 603: }
! 604: else
! 605: return(pp->pw_name);
! 606: #else
! 607: sprintf(uidstr,"%d", uid);
! 608: return(uidstr);
! 609: #endif
! 610: }
! 611:
! 612: char *
! 613: md_getpass(char *prompt)
! 614: {
! 615: #ifndef HAVE_GETPASS
! 616: static char password_buffer[9];
! 617: char *p = password_buffer;
! 618: int c, count = 0;
! 619: int max_length = 9;
! 620:
! 621: fflush(stdout);
! 622: /* If we can't prompt, abort */
! 623: if (fputs(prompt, stderr) < 0)
! 624: {
! 625: *p = '\0';
! 626: return NULL;
! 627: }
! 628:
! 629: for(;;)
! 630: {
! 631: /* Get a character with no echo */
! 632: c = _getch();
! 633:
! 634: /* Exit on interrupt (^c or ^break) */
! 635: if (c == '\003' || c == 0x100)
! 636: exit(1);
! 637:
! 638: /* Terminate on end of line or file (^j, ^m, ^d, ^z) */
! 639: if (c == '\r' || c == '\n' || c == '\004' || c == '\032')
! 640: break;
! 641:
! 642: /* Back up on backspace */
! 643: if (c == '\b')
! 644: {
! 645: if (count)
! 646: count--;
! 647: else if (p > password_buffer)
! 648: p--;
! 649: continue;
! 650: }
! 651:
! 652: /* Ignore DOS extended characters */
! 653: if ((c & 0xff) != c)
! 654: continue;
! 655:
! 656: /* Add to password if it isn't full */
! 657: if (p < password_buffer + max_length - 1)
! 658: *p++ = (char) c;
! 659: else
! 660: count++;
! 661: }
! 662: *p = '\0';
! 663:
! 664: fputc('\n', stderr);
! 665:
! 666: return password_buffer;
! 667: #else
! 668: return( getpass(prompt) );
! 669: #endif
! 670: }
! 671:
! 672: int
! 673: md_erasechar(void)
! 674: {
! 675: #ifdef HAVE_ERASECHAR
! 676: return( erasechar() ); /* process erase character */
! 677: #elif defined(VERASE)
! 678: return(_tty.c_cc[VERASE]); /* process erase character */
! 679: #else
! 680: return(_tty.sg_erase); /* process erase character */
! 681: #endif
! 682: }
! 683:
! 684: int
! 685: md_killchar(void)
! 686: {
! 687: #ifdef HAVE_KILLCHAR
! 688: return( killchar() );
! 689: #elif defined(VKILL)
! 690: return(_tty.c_cc[VKILL]);
! 691: #else
! 692: return(_tty.sg_kill);
! 693: #endif
! 694: }
! 695:
! 696: int
! 697: md_dsuspchar(void)
! 698: {
! 699: #if defined(VDSUSP) /* POSIX has priority */
! 700: struct termios attr;
! 701: tcgetattr(STDIN_FILENO, &attr);
! 702: return( attr.c_cc[VDSUSP] );
! 703: #elif defined(TIOCGLTC)
! 704: struct ltchars ltc;
! 705: ioctl(1, TIOCGLTC, <c);
! 706: return(ltc.t_dsuspc);
! 707: #elif defined(_POSIX_VDISABLE)
! 708: return(_POSIX_VDISABLE);
! 709: #else
! 710: return(0);
! 711: #endif
! 712: }
! 713:
! 714: int
! 715: md_setdsuspchar(int c)
! 716: {
! 717: #if defined(VDSUSP) /* POSIX has priority */
! 718: struct termios attr;
! 719: tcgetattr(STDIN_FILENO, &attr);
! 720: attr.c_cc[VDSUSP] = c;
! 721: tcgetattr(STDIN_FILENO, &attr);
! 722: #elif defined(TIOCSLTC)
! 723: struct ltchars ltc;
! 724: ioctl(1, TIOCGLTC, <c);
! 725: ltc.t_dsuspc = c;
! 726: ioctl(1, TIOCSLTC, <c);
! 727: #else
! 728: NOOP(c);
! 729: #endif
! 730: return(0);
! 731: }
! 732:
! 733: int
! 734: md_suspchar(void)
! 735: {
! 736: #if defined(VSUSP) /* POSIX has priority */
! 737: struct termios attr;
! 738: tcgetattr(STDIN_FILENO, &attr);
! 739: return( attr.c_cc[VSUSP] );
! 740: #elif defined(TIOCGLTC)
! 741: struct ltchars ltc;
! 742: ioctl(1, TIOCGLTC, <c);
! 743: return(ltc.t_suspc);
! 744: #elif defined(_POSIX_VDISABLE)
! 745: return(_POSIX_VDISABLE);
! 746: #else
! 747: return(0);
! 748: #endif
! 749: }
! 750:
! 751: int
! 752: md_setsuspchar(int c)
! 753: {
! 754: #if defined(VSUSP) /* POSIX has priority */
! 755: struct termios attr;
! 756: tcgetattr(STDIN_FILENO, &attr);
! 757: attr.c_cc[VSUSP] = c;
! 758: tcgetattr(STDIN_FILENO, &attr);
! 759: #elif defined(TIOCSLTC)
! 760: struct ltchars ltc;
! 761: ioctl(1, TIOCGLTC, <c);
! 762: ltc.t_suspc = c;
! 763: ioctl(1, TIOCSLTC, <c);
! 764: #else
! 765: NOOP(c);
! 766: #endif
! 767:
! 768: return(0);
! 769: }
! 770:
! 771: /*
! 772: Cursor/Keypad Support
! 773:
! 774: Sadly Cursor/Keypad support is less straightforward than it should be.
! 775:
! 776: The various terminal emulators/consoles choose to differentiate the
! 777: cursor and keypad keys (with modifiers) in different ways (if at all!).
! 778: Furthermore they use different code set sequences for each key only
! 779: a subset of which the various curses libraries recognize. Partly due
! 780: to incomplete termcap/terminfo entries and partly due to inherent
! 781: limitations of those terminal capability databases.
! 782:
! 783: I give curses first crack at decoding the sequences. If it fails to decode
! 784: it we check for common ESC-prefixed sequences.
! 785:
! 786: All cursor/keypad results are translated into standard rogue movement
! 787: commands.
! 788:
! 789: Unmodified keys are translated to walk commands: hjklyubn
! 790: Modified (shift,control,alt) are translated to run commands: HJKLYUBN
! 791:
! 792: Console and supported (differentiated) keys
! 793: Interix: Cursor Keys, Keypad, Ctl-Keypad
! 794: Cygwin: Cursor Keys, Keypad, Alt-Cursor Keys
! 795: MSYS: Cursor Keys, Keypad, Ctl-Cursor Keys, Ctl-Keypad
! 796: Win32: Cursor Keys, Keypad, Ctl/Shift/Alt-Cursor Keys, Ctl/Alt-Keypad
! 797: DJGPP: Cursor Keys, Keypad, Ctl/Shift/Alt-Cursor Keys, Ctl/Alt-Keypad
! 798:
! 799: Interix Console (raw, ncurses)
! 800: ==============================
! 801: normal shift ctrl alt
! 802: ESC [D, ESC F^, ESC [D, ESC [D /# Left #/
! 803: ESC [C, ESC F$, ESC [C, ESC [C /# Right #/
! 804: ESC [A, ESC F-, local win, ESC [A /# Up #/
! 805: ESC [B, ESC F+, local win, ESC [B /# Down #/
! 806: ESC [H, ESC [H, ESC [H, ESC [H /# Home #/
! 807: ESC [S, local win, ESC [S, ESC [S /# Page Up #/
! 808: ESC [T, local win, ESC [T, ESC [T /# Page Down #/
! 809: ESC [U, ESC [U, ESC [U, ESC [U /# End #/
! 810: ESC [D, ESC F^, ESC [D, O /# Keypad Left #/
! 811: ESC [C, ESC F$, ESC [C, O /# Keypad Right #/
! 812: ESC [A, ESC [A, ESC [-1, O /# Keypad Up #/
! 813: ESC [B, ESC [B, ESC [-2, O /# Keypad Down #/
! 814: ESC [H, ESC [H, ESC [-263, O /# Keypad Home #/
! 815: ESC [S, ESC [S, ESC [-19, O /# Keypad PgUp #/
! 816: ESC [T, ESC [T, ESC [-20, O /# Keypad PgDn #/
! 817: ESC [U, ESC [U, ESC [-21, O /# Keypad End #/
! 818: nothing, nothing, nothing, O /# Kaypad 5 #/
! 819:
! 820: Interix Console (term=interix, ncurses)
! 821: ==============================
! 822: KEY_LEFT, ESC F^, KEY_LEFT, KEY_LEFT /# Left #/
! 823: KEY_RIGHT, ESC F$, KEY_RIGHT, KEY_RIGHT /# Right #/
! 824: KEY_UP, 0x146, local win, KEY_UP /# Up #/
! 825: KEY_DOWN, 0x145, local win, KEY_DOWN /# Down #/
! 826: ESC [H, ESC [H, ESC [H, ESC [H /# Home #/
! 827: KEY_PPAGE, local win, KEY_PPAGE, KEY_PPAGE /# Page Up #/
! 828: KEY_NPAGE, local win, KEY_NPAGE, KEY_NPAGE /# Page Down #/
! 829: KEY_LL, KEY_LL, KEY_LL, KEY_LL /# End #/
! 830: KEY_LEFT, ESC F^, ESC [-4, O /# Keypad Left #/
! 831: KEY_RIGHT, ESC F$, ESC [-3, O /# Keypad Right #/
! 832: KEY_UP, KEY_UP, ESC [-1, O /# Keypad Up #/
! 833: KEY_DOWN, KEY_DOWN, ESC [-2, O /# Keypad Down #/
! 834: ESC [H, ESC [H, ESC [-263, O /# Keypad Home #/
! 835: KEY_PPAGE, KEY_PPAGE, ESC [-19, O /# Keypad PgUp #/
! 836: KEY_NPAGE, KEY_NPAGE, ESC [-20, O /# Keypad PgDn #/
! 837: KEY_LL, KEY_LL, ESC [-21, O /# Keypad End #/
! 838: nothing, nothing, nothing, O /# Keypad 5 #/
! 839:
! 840: Cygwin Console (raw, ncurses)
! 841: ==============================
! 842: normal shift ctrl alt
! 843: ESC [D, ESC [D, ESC [D, ESC ESC [D /# Left #/
! 844: ESC [C, ESC [C, ESC [C, ESC ESC [C /# Rght #/
! 845: ESC [A, ESC [A, ESC [A, ESC ESC [A /# Up #/
! 846: ESC [B, ESC [B, ESC [B, ESC ESC [B /# Down #/
! 847: ESC [1~, ESC [1~, ESC [1~, ESC ESC [1~ /# Home #/
! 848: ESC [5~, ESC [5~, ESC [5~, ESC ESC [5~ /# Page Up #/
! 849: ESC [6~, ESC [6~, ESC [6~, ESC ESC [6~ /# Page Down #/
! 850: ESC [4~, ESC [4~, ESC [4~, ESC ESC [4~ /# End #/
! 851: ESC [D, ESC [D, ESC [D, ESC ESC [D,O /# Keypad Left #/
! 852: ESC [C, ESC [C, ESC [C, ESC ESC [C,O /# Keypad Right #/
! 853: ESC [A, ESC [A, ESC [A, ESC ESC [A,O /# Keypad Up #/
! 854: ESC [B, ESC [B, ESC [B, ESC ESC [B,O /# Keypad Down #/
! 855: ESC [1~, ESC [1~, ESC [1~, ESC ESC [1~,O /# Keypad Home #/
! 856: ESC [5~, ESC [5~, ESC [5~, ESC ESC [5~,O /# Keypad PgUp #/
! 857: ESC [6~, ESC [6~, ESC [6~, ESC ESC [6~,O /# Keypad PgDn #/
! 858: ESC [4~, ESC [4~, ESC [4~, ESC ESC [4~,O /# Keypad End #/
! 859: ESC [-71, nothing, nothing, O /# Keypad 5 #/
! 860:
! 861: Cygwin Console (term=cygwin, ncurses)
! 862: ==============================
! 863: KEY_LEFT, KEY_LEFT, KEY_LEFT, ESC-260 /# Left #/
! 864: KEY_RIGHT, KEY_RIGHT, KEY_RIGHT, ESC-261 /# Rght #/
! 865: KEY_UP, KEY_UP, KEY_UP, ESC-259 /# Up #/
! 866: KEY_DOWN, KEY_DOWN, KEY_DOWN, ESC-258 /# Down #/
! 867: KEY_HOME, KEY_HOME, KEY_HOME, ESC-262 /# Home #/
! 868: KEY_PPAGE, KEY_PPAGE, KEY_PPAGE, ESC-339 /# Page Up #/
! 869: KEY_NPAGE, KEY_NPAGE, KEY_NPAGE, ESC-338 /# Page Down #/
! 870: KEY_END, KEY_END, KEY_END, ESC-360 /# End #/
! 871: KEY_LEFT, KEY_LEFT, KEY_LEFT, ESC-260,O /# Keypad Left #/
! 872: KEY_RIGHT, KEY_RIGHT, KEY_RIGHT, ESC-261,O /# Keypad Right #/
! 873: KEY_UP, KEY_UP, KEY_UP, ESC-259,O /# Keypad Up #/
! 874: KEY_DOWN, KEY_DOWN, KEY_DOWN, ESC-258,O /# Keypad Down #/
! 875: KEY_HOME, KEY_HOME, KEY_HOME, ESC-262,O /# Keypad Home #/
! 876: KEY_PPAGE, KEY_PPAGE, KEY_PPAGE, ESC-339,O /# Keypad PgUp #/
! 877: KEY_NPAGE, KEY_NPAGE, KEY_NPAGE, ESC-338,O /# Keypad PgDn #/
! 878: KEY_END, KEY_END, KEY_END, ESC-360,O /# Keypad End #/
! 879: ESC [G, nothing, nothing, O /# Keypad 5 #/
! 880:
! 881: MSYS Console (raw, ncurses)
! 882: ==============================
! 883: normal shift ctrl alt
! 884: ESC OD, ESC [d, ESC Od nothing /# Left #/
! 885: ESC OE, ESC [e, ESC Oe, nothing /# Right #/
! 886: ESC OA, ESC [a, ESC Oa, nothing /# Up #/
! 887: ESC OB, ESC [b, ESC Ob, nothing /# Down #/
! 888: ESC [7~, ESC [7$, ESC [7^, nothing /# Home #/
! 889: ESC [5~, local window, ESC [5^, nothing /# Page Up #/
! 890: ESC [6~, local window, ESC [6^, nothing /# Page Down #/
! 891: ESC [8~, ESC [8$, ESC [8^, nothing /# End #/
! 892: ESC OD, ESC [d, ESC Od O /# Keypad Left #/
! 893: ESC OE, ESC [c, ESC Oc, O /# Keypad Right #/
! 894: ESC OA, ESC [a, ESC Oa, O /# Keypad Up #/
! 895: ESC OB, ESC [b, ESC Ob, O /# Keypad Down #/
! 896: ESC [7~, ESC [7$, ESC [7^, O /# Keypad Home #/
! 897: ESC [5~, local window, ESC [5^, O /# Keypad PgUp #/
! 898: ESC [6~, local window, ESC [6^, O /# Keypad PgDn #/
! 899: ESC [8~, ESC [8$, ESC [8^, O /# Keypad End #/
! 900: 11, 11, 11, O /# Keypad 5 #/
! 901:
! 902: MSYS Console (term=rxvt, ncurses)
! 903: ==============================
! 904: normal shift ctrl alt
! 905: KEY_LEFT, KEY_SLEFT, 514 nothing /# Left #/
! 906: KEY_RIGHT, KEY_SRIGHT, 516, nothing /# Right #/
! 907: KEY_UP, 518, 519, nothing /# Up #/
! 908: KEY_DOWN, 511, 512, nothing /# Down #/
! 909: KEY_HOME, KEY_SHOME, ESC [7^, nothing /# Home #/
! 910: KEY_PPAGE, local window, ESC [5^, nothing /# Page Up #/
! 911: KEY_NPAGE, local window, ESC [6^, nothing /# Page Down #/
! 912: KEY_END, KEY_SEND, KEY_EOL, nothing /# End #/
! 913: KEY_LEFT, KEY_SLEFT, 514 O /# Keypad Left #/
! 914: KEY_RIGHT, KEY_SRIGHT, 516, O /# Keypad Right #/
! 915: KEY_UP, 518, 519, O /# Keypad Up #/
! 916: KEY_DOWN, 511, 512, O /# Keypad Down #/
! 917: KEY_HOME, KEY_SHOME, ESC [7^, O /# Keypad Home #/
! 918: KEY_PPAGE, local window, ESC [5^, O /# Keypad PgUp #/
! 919: KEY_NPAGE, local window, ESC [6^, O /# Keypad PgDn #/
! 920: KEY_END, KEY_SEND, KEY_EOL, O /# Keypad End #/
! 921: 11, 11, 11, O /# Keypad 5 #/
! 922:
! 923: Win32 Console (raw, pdcurses)
! 924: DJGPP Console (raw, pdcurses)
! 925: ==============================
! 926: normal shift ctrl alt
! 927: 260, 391, 443, 493 /# Left #/
! 928: 261, 400, 444, 492 /# Right #/
! 929: 259, 547, 480, 490 /# Up #/
! 930: 258, 548, 481, 491 /# Down #/
! 931: 262, 388, 447, 524 /# Home #/
! 932: 339, 396, 445, 526 /# Page Up #/
! 933: 338, 394, 446, 520 /# Page Down #/
! 934: 358, 384, 448, 518 /# End #/
! 935: 452, 52('4'), 511, 521 /# Keypad Left #/
! 936: 454, 54('6'), 513, 523 /# Keypad Right #/
! 937: 450, 56('8'), 515, 525 /# Keypad Up #/
! 938: 456, 50('2'), 509, 519 /# Keypad Down #/
! 939: 449, 55('7'), 514, 524 /# Keypad Home #/
! 940: 451, 57('9'), 516, 526 /# Keypad PgUp #/
! 941: 457, 51('3'), 510, 520 /# Keypad PgDn #/
! 942: 455, 49('1'), 508, 518 /# Keypad End #/
! 943: 453, 53('5'), 512, 522 /# Keypad 5 #/
! 944:
! 945: Win32 Console (pdcurses, MSVC/MingW32)
! 946: DJGPP Console (pdcurses)
! 947: ==============================
! 948: normal shift ctrl alt
! 949: KEY_LEFT, KEY_SLEFT, CTL_LEFT, ALT_LEFT /# Left #/
! 950: KEY_RIGHT, KEY_SRIGHT, CTL_RIGHT, ALT_RIGHT /# Right #/
! 951: KEY_UP, KEY_SUP, CTL_UP, ALT_UP /# Up #/
! 952: KEY_DOWN, KEY_SDOWN, CTL_DOWN, ALT_DOWN /# Down #/
! 953: KEY_HOME, KEY_SHOME, CTL_HOME, ALT_HOME /# Home #/
! 954: KEY_PPAGE, KEY_SPREVIOUS, CTL_PGUP, ALT_PGUP /# Page Up #/
! 955: KEY_NPAGE, KEY_SNEXTE, CTL_PGDN, ALT_PGDN /# Page Down #/
! 956: KEY_END, KEY_SEND, CTL_END, ALT_END /# End #/
! 957: KEY_B1, 52('4'), CTL_PAD4, ALT_PAD4 /# Keypad Left #/
! 958: KEY_B3, 54('6'), CTL_PAD6, ALT_PAD6 /# Keypad Right #/
! 959: KEY_A2, 56('8'), CTL_PAD8, ALT_PAD8 /# Keypad Up #/
! 960: KEY_C2, 50('2'), CTL_PAD2, ALT_PAD2 /# Keypad Down #/
! 961: KEY_A1, 55('7'), CTL_PAD7, ALT_PAD7 /# Keypad Home #/
! 962: KEY_A3, 57('9'), CTL_PAD9, ALT_PAD9 /# Keypad PgUp #/
! 963: KEY_C3, 51('3'), CTL_PAD3, ALT_PAD3 /# Keypad PgDn #/
! 964: KEY_C1, 49('1'), CTL_PAD1, ALT_PAD1 /# Keypad End #/
! 965: KEY_B2, 53('5'), CTL_PAD5, ALT_PAD5 /# Keypad 5 #/
! 966:
! 967: Windows Telnet (raw)
! 968: ==============================
! 969: normal shift ctrl alt
! 970: ESC [D, ESC [D, ESC [D, ESC [D /# Left #/
! 971: ESC [C, ESC [C, ESC [C, ESC [C /# Right #/
! 972: ESC [A, ESC [A, ESC [A, ESC [A /# Up #/
! 973: ESC [B, ESC [B, ESC [B, ESC [B /# Down #/
! 974: ESC [1~, ESC [1~, ESC [1~, ESC [1~ /# Home #/
! 975: ESC [5~, ESC [5~, ESC [5~, ESC [5~ /# Page Up #/
! 976: ESC [6~, ESC [6~, ESC [6~, ESC [6~ /# Page Down #/
! 977: ESC [4~, ESC [4~, ESC [4~, ESC [4~ /# End #/
! 978: ESC [D, ESC [D, ESC [D, ESC [D /# Keypad Left #/
! 979: ESC [C, ESC [C, ESC [C, ESC [C /# Keypad Right #/
! 980: ESC [A, ESC [A, ESC [A, ESC [A /# Keypad Up #/
! 981: ESC [B, ESC [B, ESC [B, ESC [B /# Keypad Down #/
! 982: ESC [1~, ESC [1~, ESC [1~, ESC [1~ /# Keypad Home #/
! 983: ESC [5~, ESC [5~, ESC [5~, ESC [5~ /# Keypad PgUp #/
! 984: ESC [6~, ESC [6~, ESC [6~, ESC [6~ /# Keypad PgDn #/
! 985: ESC [4~, ESC [4~, ESC [4~, ESC [4~ /# Keypad End #/
! 986: nothing, nothing, nothing, nothing /# Keypad 5 #/
! 987:
! 988: Windows Telnet (term=xterm)
! 989: ==============================
! 990: normal shift ctrl alt
! 991: KEY_LEFT, KEY_LEFT, KEY_LEFT, KEY_LEFT /# Left #/
! 992: KEY_RIGHT, KEY_RIGHT, KEY_RIGHT, KEY_RIGHT /# Right #/
! 993: KEY_UP, KEY_UP, KEY_UP, KEY_UP /# Up #/
! 994: KEY_DOWN, KEY_DOWN, KEY_DOWN, KEY_DOWN /# Down #/
! 995: ESC [1~, ESC [1~, ESC [1~, ESC [1~ /# Home #/
! 996: KEY_PPAGE, KEY_PPAGE, KEY_PPAGE, KEY_PPAGE /# Page Up #/
! 997: KEY_NPAGE, KEY_NPAGE, KEY_NPAGE, KEY_NPAGE /# Page Down #/
! 998: ESC [4~, ESC [4~, ESC [4~, ESC [4~ /# End #/
! 999: KEY_LEFT, KEY_LEFT, KEY_LEFT, O /# Keypad Left #/
! 1000: KEY_RIGHT, KEY_RIGHT, KEY_RIGHT, O /# Keypad Right #/
! 1001: KEY_UP, KEY_UP, KEY_UP, O /# Keypad Up #/
! 1002: KEY_DOWN, KEY_DOWN, KEY_DOWN, O /# Keypad Down #/
! 1003: ESC [1~, ESC [1~, ESC [1~, ESC [1~ /# Keypad Home #/
! 1004: KEY_PPAGE, KEY_PPAGE, KEY_PPAGE, KEY_PPAGE /# Keypad PgUp #/
! 1005: KEY_NPAGE, KEY_NPAGE, KEY_NPAGE, KEY_NPAGE /# Keypad PgDn #/
! 1006: ESC [4~, ESC [4~, ESC [4~, O /# Keypad End #/
! 1007: ESC [-71, nothing, nothing, O /# Keypad 5 #/
! 1008:
! 1009: PuTTY
! 1010: ==============================
! 1011: normal shift ctrl alt
! 1012: ESC [D, ESC [D, ESC OD, ESC [D /# Left #/
! 1013: ESC [C, ESC [C, ESC OC, ESC [C /# Right #/
! 1014: ESC [A, ESC [A, ESC OA, ESC [A /# Up #/
! 1015: ESC [B, ESC [B, ESC OB, ESC [B /# Down #/
! 1016: ESC [1~, ESC [1~, local win, ESC [1~ /# Home #/
! 1017: ESC [5~, local win, local win, ESC [5~ /# Page Up #/
! 1018: ESC [6~, local win, local win, ESC [6~ /# Page Down #/
! 1019: ESC [4~, ESC [4~, local win, ESC [4~ /# End #/
! 1020: ESC [D, ESC [D, ESC [D, O /# Keypad Left #/
! 1021: ESC [C, ESC [C, ESC [C, O /# Keypad Right #/
! 1022: ESC [A, ESC [A, ESC [A, O /# Keypad Up #/
! 1023: ESC [B, ESC [B, ESC [B, O /# Keypad Down #/
! 1024: ESC [1~, ESC [1~, ESC [1~, O /# Keypad Home #/
! 1025: ESC [5~, ESC [5~, ESC [5~, O /# Keypad PgUp #/
! 1026: ESC [6~, ESC [6~, ESC [6~, O /# Keypad PgDn #/
! 1027: ESC [4~, ESC [4~, ESC [4~, O /# Keypad End #/
! 1028: nothing, nothing, nothing, O /# Keypad 5 #/
! 1029:
! 1030: PuTTY
! 1031: ==============================
! 1032: normal shift ctrl alt
! 1033: KEY_LEFT, KEY_LEFT, ESC OD, ESC KEY_LEFT /# Left #/
! 1034: KEY_RIGHT KEY_RIGHT, ESC OC, ESC KEY_RIGHT /# Right #/
! 1035: KEY_UP, KEY_UP, ESC OA, ESC KEY_UP /# Up #/
! 1036: KEY_DOWN, KEY_DOWN, ESC OB, ESC KEY_DOWN /# Down #/
! 1037: ESC [1~, ESC [1~, local win, ESC ESC [1~ /# Home #/
! 1038: KEY_PPAGE local win, local win, ESC KEY_PPAGE /# Page Up #/
! 1039: KEY_NPAGE local win, local win, ESC KEY_NPAGE /# Page Down #/
! 1040: ESC [4~, ESC [4~, local win, ESC ESC [4~ /# End #/
! 1041: ESC Ot, ESC Ot, ESC Ot, O /# Keypad Left #/
! 1042: ESC Ov, ESC Ov, ESC Ov, O /# Keypad Right #/
! 1043: ESC Ox, ESC Ox, ESC Ox, O /# Keypad Up #/
! 1044: ESC Or, ESC Or, ESC Or, O /# Keypad Down #/
! 1045: ESC Ow, ESC Ow, ESC Ow, O /# Keypad Home #/
! 1046: ESC Oy, ESC Oy, ESC Oy, O /# Keypad PgUp #/
! 1047: ESC Os, ESC Os, ESC Os, O /# Keypad PgDn #/
! 1048: ESC Oq, ESC Oq, ESC Oq, O /# Keypad End #/
! 1049: ESC Ou, ESC Ou, ESC Ou, O /# Keypad 5 #/
! 1050: */
! 1051:
! 1052: #define M_NORMAL 0
! 1053: #define M_ESC 1
! 1054: #define M_KEYPAD 2
! 1055: #define M_TRAIL 3
! 1056:
! 1057: #ifndef CTRL
! 1058: #define CTRL(ch) (ch & 0x1F)
! 1059: #endif
! 1060:
! 1061: int undo[5];
! 1062: int uindex = -1;
! 1063:
! 1064: int
! 1065: reread()
! 1066: {
! 1067: int redo;
! 1068:
! 1069: if (uindex < 0)
! 1070: return 0;
! 1071:
! 1072: redo = undo[0];
! 1073: undo[0] = undo[1];
! 1074: undo[1] = undo[2];
! 1075: undo[2] = undo[3];
! 1076: undo[3] = undo[4];
! 1077: uindex--;
! 1078: return redo;
! 1079: }
! 1080:
! 1081: void
! 1082: unread(int c)
! 1083: {
! 1084: if (uindex >= 4)
! 1085: abort();
! 1086:
! 1087: undo[++uindex] = c;
! 1088: }
! 1089:
! 1090: int
! 1091: md_readchar(WINDOW *win)
! 1092: {
! 1093: int ch = 0;
! 1094: int lastch = 0;
! 1095: int wch = 0;
! 1096: int mode = M_NORMAL;
! 1097: int mode2 = M_NORMAL;
! 1098: int nodelayf = 0;
! 1099: int count = 0;
! 1100:
! 1101: for(;;)
! 1102: {
! 1103: if (mode == M_NORMAL && uindex >= 0)
! 1104: {
! 1105: wch = ch = reread();
! 1106: break;
! 1107: }
! 1108:
! 1109: wch = ch = wgetch(win);
! 1110:
! 1111: if (ch == ERR) /* timed out or error */
! 1112: {
! 1113: if (nodelayf) /* likely timed out, switch to */
! 1114: { /* normal mode and block on */
! 1115: mode = M_NORMAL; /* next read */
! 1116: nodelayf = 0;
! 1117: nodelay(win,0);
! 1118: }
! 1119: else if (count > 10) /* after 10 errors assume */
! 1120: auto_save(0); /* input stream is broken and */
! 1121: else /* auto save and exit */
! 1122: count++;
! 1123:
! 1124: continue;
! 1125: }
! 1126:
! 1127: count = 0; /* reset input error count */
! 1128:
! 1129: if (mode == M_TRAIL)
! 1130: {
! 1131: if (ch == '^') /* msys console : 7,5,6,8: modified*/
! 1132: ch = CTRL( toupper(lastch) );
! 1133: else if (ch == '~') /* cygwin console: 1,5,6,4: normal */
! 1134: ch = tolower(lastch); /* windows telnet: 1,5,6,4: normal */
! 1135: /* msys console : 7,5,6,8: normal */
! 1136: else if (mode2 == M_ESC) /* cygwin console: 1,5,6,4: modified*/
! 1137: ch = CTRL( toupper(ch) );
! 1138: else
! 1139: {
! 1140: mode = M_NORMAL;
! 1141: unread(ch);
! 1142: continue;
! 1143: }
! 1144:
! 1145: break;
! 1146: }
! 1147:
! 1148: if (mode == M_ESC)
! 1149: {
! 1150: if (ch == 27)
! 1151: {
! 1152: mode2 = M_ESC;
! 1153: unread(ch);
! 1154: continue;
! 1155: }
! 1156:
! 1157: if ((ch == 'F') || (ch == 'O') || (ch == '['))
! 1158: {
! 1159: mode = M_KEYPAD;
! 1160: unread(ch);
! 1161: continue;
! 1162: }
! 1163:
! 1164:
! 1165: switch(ch)
! 1166: {
! 1167: /* Cygwin Console */
! 1168: /* PuTTY */
! 1169: case KEY_LEFT : ch = CTRL('H'); break;
! 1170: case KEY_RIGHT: ch = CTRL('L'); break;
! 1171: case KEY_UP : ch = CTRL('K'); break;
! 1172: case KEY_DOWN : ch = CTRL('J'); break;
! 1173: case KEY_HOME : ch = CTRL('Y'); break;
! 1174: case KEY_PPAGE: ch = CTRL('U'); break;
! 1175: case KEY_NPAGE: ch = CTRL('N'); break;
! 1176: case KEY_END : ch = CTRL('B'); break;
! 1177:
! 1178: default: mode = M_NORMAL;
! 1179: mode2 = M_NORMAL;
! 1180: unread(ch);
! 1181: continue;}
! 1182:
! 1183: break;
! 1184: }
! 1185:
! 1186: if (mode == M_KEYPAD)
! 1187: {
! 1188: switch(ch)
! 1189: {
! 1190: /* ESC F - Interix Console codes */
! 1191: case '^': ch = CTRL('H'); break; /* Shift-Left */
! 1192: case '$': ch = CTRL('L'); break; /* Shift-Right */
! 1193:
! 1194: /* ESC [ - Interix Console codes */
! 1195: case 'H': ch = 'y'; break; /* Home */
! 1196: case 1: ch = CTRL('K'); break; /* Ctl-Keypad Up */
! 1197: case 2: ch = CTRL('J'); break; /* Ctl-Keypad Down */
! 1198: case 3: ch = CTRL('L'); break; /* Ctl-Keypad Right */
! 1199: case 4: ch = CTRL('H'); break; /* Ctl-Keypad Left */
! 1200: case 263: ch = CTRL('Y'); break; /* Ctl-Keypad Home */
! 1201: case 19: ch = CTRL('U'); break; /* Ctl-Keypad PgUp */
! 1202: case 20: ch = CTRL('N'); break; /* Ctl-Keypad PgDn */
! 1203: case 21: ch = CTRL('B'); break; /* Ctl-Keypad End */
! 1204:
! 1205: /* ESC [ - Cygwin Console codes */
! 1206: case 'G': ch = '.'; break; /* Keypad 5 */
! 1207: case '7': lastch = 'Y'; mode=M_TRAIL; break; /* Ctl-Home */
! 1208: case '5': lastch = 'U'; mode=M_TRAIL; break; /* Ctl-PgUp */
! 1209: case '6': lastch = 'N'; mode=M_TRAIL; break; /* Ctl-PgDn */
! 1210:
! 1211: /* ESC [ - Win32 Telnet, PuTTY */
! 1212: case '1': lastch = 'y'; mode=M_TRAIL; break; /* Home */
! 1213: case '4': lastch = 'b'; mode=M_TRAIL; break; /* End */
! 1214:
! 1215: /* ESC [ - tmux calling itself screen */
! 1216: case 'E': ch = '.'; break; /* Keypad 5 */
! 1217:
! 1218: /* ESC O - PuTTY */
! 1219: case 'D': ch = CTRL('H'); break;
! 1220: case 'C': ch = CTRL('L'); break;
! 1221: case 'A': ch = CTRL('K'); break;
! 1222: case 'B': ch = CTRL('J'); break;
! 1223: case 't': ch = 'h'; break;
! 1224: case 'v': ch = 'l'; break;
! 1225: case 'x': ch = 'k'; break;
! 1226: case 'r': ch = 'j'; break;
! 1227: case 'w': ch = 'y'; break;
! 1228: case 'y': ch = 'u'; break;
! 1229: case 's': ch = 'n'; break;
! 1230: case 'q': ch = 'b'; break;
! 1231: case 'u': ch = '.'; break;
! 1232: }
! 1233:
! 1234: if (mode != M_KEYPAD)
! 1235: {
! 1236: unread(ch);
! 1237: continue;
! 1238: }
! 1239: }
! 1240:
! 1241: if (ch == 27)
! 1242: {
! 1243: nodelay(win,1);
! 1244: mode = M_ESC;
! 1245: nodelayf = 1;
! 1246: unread(ch);
! 1247: continue;
! 1248: }
! 1249:
! 1250: switch(ch)
! 1251: {
! 1252: case KEY_LEFT : ch = 'h'; break;
! 1253: case KEY_DOWN : ch = 'j'; break;
! 1254: case KEY_UP : ch = 'k'; break;
! 1255: case KEY_RIGHT : ch = 'l'; break;
! 1256: case KEY_HOME : ch = 'y'; break;
! 1257: case KEY_PPAGE : ch = 'u'; break;
! 1258: case KEY_END : ch = 'b'; break;
! 1259: #ifdef KEY_LL
! 1260: case KEY_LL : ch = 'b'; break;
! 1261: #endif
! 1262: case KEY_NPAGE : ch = 'n'; break;
! 1263: case KEY_BEG : ch = '.'; break;
! 1264:
! 1265: #ifdef KEY_B1
! 1266: case KEY_B1 : ch = 'h'; break;
! 1267: case KEY_C2 : ch = 'j'; break;
! 1268: case KEY_A2 : ch = 'k'; break;
! 1269: case KEY_B3 : ch = 'l'; break;
! 1270: #endif
! 1271: case KEY_A1 : ch = 'y'; break;
! 1272: case KEY_A3 : ch = 'u'; break;
! 1273: case KEY_C1 : ch = 'b'; break;
! 1274: case KEY_C3 : ch = 'n'; break;
! 1275: /* next should be '.', but for problem with putty/linux */
! 1276: /* Can't reproduce this "problem", changing it. -elwin */
! 1277: case KEY_B2 : ch = '.'; break;
! 1278:
! 1279: #ifdef KEY_SLEFT
! 1280: case KEY_SRIGHT : ch = CTRL('L'); break;
! 1281: case KEY_SLEFT : ch = CTRL('H'); break;
! 1282: #ifdef KEY_SUP
! 1283: case KEY_SUP : ch = CTRL('K'); break;
! 1284: case KEY_SDOWN : ch = CTRL('J'); break;
! 1285: #endif
! 1286: case KEY_SHOME : ch = CTRL('Y'); break;
! 1287: case KEY_SPREVIOUS:ch = CTRL('U'); break;
! 1288: case KEY_SEND : ch = CTRL('B'); break;
! 1289: case KEY_SNEXT : ch = CTRL('N'); break;
! 1290: #endif
! 1291: case 0x146 : ch = CTRL('K'); break; /* Shift-Up */
! 1292: case 0x145 : ch = CTRL('J'); break; /* Shift-Down */
! 1293:
! 1294: #ifdef CTL_RIGHT
! 1295: case CTL_RIGHT : ch = CTRL('L'); break;
! 1296: case CTL_LEFT : ch = CTRL('H'); break;
! 1297: case CTL_UP : ch = CTRL('K'); break;
! 1298: case CTL_DOWN : ch = CTRL('J'); break;
! 1299: case CTL_HOME : ch = CTRL('Y'); break;
! 1300: case CTL_PGUP : ch = CTRL('U'); break;
! 1301: case CTL_END : ch = CTRL('B'); break;
! 1302: case CTL_PGDN : ch = CTRL('N'); break;
! 1303: #endif
! 1304: #ifdef KEY_EOL
! 1305: case KEY_EOL : ch = CTRL('B'); break;
! 1306: #endif
! 1307:
! 1308: #ifndef CTL_PAD1
! 1309: /* MSYS rxvt console */
! 1310: case 511 : ch = CTRL('J'); break; /* Shift Dn */
! 1311: case 512 : ch = CTRL('J'); break; /* Ctl Down */
! 1312: case 514 : ch = CTRL('H'); break; /* Ctl Left */
! 1313: case 516 : ch = CTRL('L'); break; /* Ctl Right*/
! 1314: case 518 : ch = CTRL('K'); break; /* Shift Up */
! 1315: case 519 : ch = CTRL('K'); break; /* Ctl Up */
! 1316: #endif
! 1317:
! 1318: #ifdef CTL_PAD1
! 1319: case CTL_PAD1 : ch = CTRL('B'); break;
! 1320: case CTL_PAD2 : ch = CTRL('J'); break;
! 1321: case CTL_PAD3 : ch = CTRL('N'); break;
! 1322: case CTL_PAD4 : ch = CTRL('H'); break;
! 1323: case CTL_PAD5 : ch = '.'; break;
! 1324: case CTL_PAD6 : ch = CTRL('L'); break;
! 1325: case CTL_PAD7 : ch = CTRL('Y'); break;
! 1326: case CTL_PAD8 : ch = CTRL('K'); break;
! 1327: case CTL_PAD9 : ch = CTRL('U'); break;
! 1328: #endif
! 1329:
! 1330: #ifdef ALT_RIGHT
! 1331: case ALT_RIGHT : ch = CTRL('L'); break;
! 1332: case ALT_LEFT : ch = CTRL('H'); break;
! 1333: case ALT_DOWN : ch = CTRL('J'); break;
! 1334: case ALT_HOME : ch = CTRL('Y'); break;
! 1335: case ALT_PGUP : ch = CTRL('U'); break;
! 1336: case ALT_END : ch = CTRL('B'); break;
! 1337: case ALT_PGDN : ch = CTRL('N'); break;
! 1338: #endif
! 1339:
! 1340: #ifdef ALT_PAD1
! 1341: case ALT_PAD1 : ch = CTRL('B'); break;
! 1342: case ALT_PAD2 : ch = CTRL('J'); break;
! 1343: case ALT_PAD3 : ch = CTRL('N'); break;
! 1344: case ALT_PAD4 : ch = CTRL('H'); break;
! 1345: case ALT_PAD5 : ch = '.'; break;
! 1346: case ALT_PAD6 : ch = CTRL('L'); break;
! 1347: case ALT_PAD7 : ch = CTRL('Y'); break;
! 1348: case ALT_PAD8 : ch = CTRL('K'); break;
! 1349: case ALT_PAD9 : ch = CTRL('U'); break;
! 1350: #endif
! 1351: #ifdef KEY_BACKSPACE
! 1352: case KEY_BACKSPACE: ch = md_erasechar(); break;
! 1353: #endif
! 1354: }
! 1355:
! 1356: break;
! 1357: }
! 1358:
! 1359:
! 1360: if (nodelayf)
! 1361: nodelay(win,0);
! 1362:
! 1363: uindex = -1;
! 1364:
! 1365: if (!pass_ctrl_keypad && (ch != wch))
! 1366: switch(ch)
! 1367: {
! 1368: case CTRL('H'):
! 1369: case CTRL('L'):
! 1370: case CTRL('K'):
! 1371: case CTRL('J'):
! 1372: case CTRL('Y'):
! 1373: case CTRL('U'):
! 1374: case CTRL('N'):
! 1375: case CTRL('B'):
! 1376: return(ch + 0x40);
! 1377: }
! 1378:
! 1379: return(ch & 0x7F);
! 1380: }
! 1381:
! 1382: #if defined(LOADAV) && defined(HAVE_NLIST_H) && defined(HAVE_NLIST)
! 1383: /*
! 1384: * loadav:
! 1385: * Looking up load average in core (for system where the loadav()
! 1386: * system call isn't defined
! 1387: */
! 1388:
! 1389: #include <nlist.h>
! 1390:
! 1391: struct nlist avenrun = {
! 1392: "_avenrun"
! 1393: };
! 1394:
! 1395: int
! 1396: md_loadav(double *avg)
! 1397: {
! 1398: int kmem;
! 1399:
! 1400: if ((kmem = open("/dev/kmem", 0)) < 0)
! 1401: goto bad;
! 1402: nlist(NAMELIST, &avenrun);
! 1403: if (avenrun.n_type == 0)
! 1404: {
! 1405: close(kmem);
! 1406: bad:
! 1407: avg[0] = 0.0;
! 1408: avg[1] = 0.0;
! 1409: avg[2] = 0.0;
! 1410: return -1;
! 1411: }
! 1412:
! 1413: lseek(kmem, avenrun.n_value, 0);
! 1414: read(kmem, (char *) avg, 3 * sizeof (double));
! 1415: close(kmem);
! 1416: return 0;
! 1417: }
! 1418: #else
! 1419: int
! 1420: md_loadav(double *avg)
! 1421: {
! 1422: #if defined(HAVE_LOADAV)
! 1423: loadav(avg);
! 1424: return(0);
! 1425: #elif defined(HAVE_GETLOADAVG)
! 1426: int ret;
! 1427: ret = getloadavg(avg,3);
! 1428: return (ret == 3) ? 0 : -1;
! 1429: #else
! 1430: avg[0] = avg[1] = avg[2] = 0;
! 1431: return(-1);
! 1432: #endif
! 1433: }
! 1434: #endif
! 1435:
! 1436: #ifndef NSIG
! 1437: #define NSIG 32
! 1438: #endif
! 1439:
! 1440: void
! 1441: md_ignoreallsignals(void)
! 1442: {
! 1443: int i;
! 1444:
! 1445: for (i = 0; i < NSIG; i++)
! 1446: signal(i, SIG_IGN);
! 1447: }
! 1448:
! 1449: void
! 1450: md_tstphold(void)
! 1451: {
! 1452: #ifdef SIGTSTP
! 1453: /*
! 1454: * If a process can be suspended, this code wouldn't work
! 1455: */
! 1456: # ifdef SIG_HOLD
! 1457: signal(SIGTSTP, SIG_HOLD);
! 1458: # else
! 1459: signal(SIGTSTP, SIG_IGN);
! 1460: # endif
! 1461: #endif
! 1462: }
! 1463:
! 1464: void
! 1465: md_tstpresume(void (*tstp)(int))
! 1466: {
! 1467: #ifdef SIGTSTP
! 1468: signal(SIGTSTP, tstp);
! 1469: #endif
! 1470: }
! 1471:
! 1472: void
! 1473: md_tstpsignal(void)
! 1474: {
! 1475: #ifdef SIGTSTP
! 1476: kill(0, SIGTSTP); /* send actual signal and suspend process */
! 1477: #endif
! 1478: }
! 1479:
! 1480: void
! 1481: md_start_checkout_timer(int time)
! 1482: {
! 1483: void checkout();
! 1484:
! 1485: #if defined(HAVE_ALARM) && defined(SIGALRM)
! 1486: signal(SIGALRM, checkout);
! 1487: alarm(time);
! 1488: #endif
! 1489: }
! 1490:
! 1491: void
! 1492: md_stop_checkout_timer(void)
! 1493: {
! 1494: #if defined(SIGALRM)
! 1495: signal(SIGALRM, SIG_IGN);
! 1496: #endif
! 1497: }
! 1498:
! 1499: long
! 1500: md_memused()
! 1501: {
! 1502: #ifdef _WIN32
! 1503: MEMORYSTATUS stat;
! 1504:
! 1505: GlobalMemoryStatus(&stat);
! 1506:
! 1507: return((long)stat.dwTotalPageFile);
! 1508: #else
! 1509: return( (long)sbrk(0) );
! 1510: #endif
! 1511: }
! 1512:
! 1513: int
! 1514: md_ucount()
! 1515: {
! 1516: #if defined(HAVE_UTMPX_H)
! 1517: struct utmpx *up=NULL;
! 1518: int count=0;
! 1519:
! 1520: setutxent();
! 1521: do
! 1522: {
! 1523: up = getutxent();
! 1524: if (up && up->ut_type == USER_PROCESS)
! 1525: count++;
! 1526: } while(up != NULL);
! 1527:
! 1528: endutxent();
! 1529:
! 1530: return(count);
! 1531: #else
! 1532: return(1);
! 1533: #endif
! 1534: }
! 1535:
! 1536: int
! 1537: md_lockfile(FILE *fp)
! 1538: {
! 1539: int fd;
! 1540: int ret;
! 1541:
! 1542: fflush(fp);
! 1543: rewind(fp);
! 1544:
! 1545: #ifdef _WIN32
! 1546: fd = _fileno(fp);
! 1547: ret = _locking(fd,_LK_LOCK,1);
! 1548: #else
! 1549: fd = fileno(fp);
! 1550:
! 1551: while((ret = lockf(fd, F_LOCK, 1)) == -1)
! 1552: if (errno != EINTR)
! 1553: break;
! 1554: #endif
! 1555:
! 1556: return ret;
! 1557: }
! 1558:
! 1559: int
! 1560: md_unlockfile(FILE *fp)
! 1561: {
! 1562: int fd;
! 1563: int ret;
! 1564:
! 1565: fflush(fp);
! 1566: rewind(fp);
! 1567:
! 1568:
! 1569: #ifdef _WIN32
! 1570: fd = _fileno(fp);
! 1571: ret = _locking(fd,_LK_UNLCK,1);
! 1572: #else
! 1573: fd = fileno(fp);
! 1574:
! 1575: while( (ret = lockf(fd, F_ULOCK, 1)) == -1)
! 1576: if (errno != EINTR)
! 1577: break;
! 1578: #endif
! 1579:
! 1580: return ret;
! 1581: }
! 1582:
! 1583: unsigned int
! 1584: md_random_seed(void)
! 1585: {
! 1586: unsigned int seed;
! 1587: seed = (unsigned int) time((time_t *) NULL);
! 1588: #ifdef _WIN32
! 1589: seed += _getpid();
! 1590: #else
! 1591: seed += getpid();
! 1592: #endif
! 1593: return seed;
! 1594: }
CVSweb