Mercurial > hg > early-roguelike
diff rogue3/mdport.c @ 0:527e2150eaf0
Import Rogue 3.6 from the Roguelike Restoration Project (r1490)
author | edwarj4 |
---|---|
date | Tue, 13 Oct 2009 13:33:34 +0000 |
parents | |
children | 9a2c0c60c386 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rogue3/mdport.c Tue Oct 13 13:33:34 2009 +0000 @@ -0,0 +1,1603 @@ +/* + mdport.c - Machine Dependent Code for Porting Unix/Curses games + + Copyright (C) 2005 Nicholas J. Kisseberth + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name(s) of the author(s) nor the names of other contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) AND CONTRIBUTORS ``AS IS'' AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. +*/ + +#include <stdlib.h> +#include <string.h> + +#if defined(_WIN32) +#include <Windows.h> +#include <io.h> +#include <sys/locking.h> +#include <Lmcons.h> +#include <conio.h> +#pragma warning( disable: 4201 ) +#include <shlobj.h> +#pragma warning( default: 4201 ) +#include <Shlwapi.h> +#undef MOUSE_MOVED +#endif + +#include <curses.h> + +#include "mdport.h" + +#if defined(HAVE_SYS_TYPES) +#include <sys/types.h> +#endif + +#if defined(HAVE_PROCESS_H) +#include <process.h> +#endif + +#if defined(HAVE_PWD_H) +#include <pwd.h> +#endif + +#if defined(HAVE_SYS_UTSNAME) +#include <sys/utsname.h> +#endif + +#if defined(HAVE_ARPA_INET_H) +#include <arpa/inet.h> /* Solaris 2.8 required this for htonl() and ntohl() */ +#endif + +#if defined(HAVE_TERMIOS_H) +#include <termios.h> +#endif + +#if defined(HAVE_UNISTD_H) +#ifndef __USE_GNU +#define __USE_GNU +#include <unistd.h> +#undef __USE_GNU +#else +#include <unistd.h> +#endif +#endif + +#if defined(HAVE_TERM_H) +#include <term.h> +#elif defined(HAVE_NCURSES_TERM_H) +#include <ncurses/term.h> +#endif + +#if defined(HAVE_WORKING_FORK) +#include <sys/wait.h> +#endif + +#ifdef HAVE_UTMPX_H +#include <utmpx.h> +#endif + +#ifdef HAVE_ERRNO_H +#include <errno.h> +#endif + +#include <ctype.h> +#include <fcntl.h> +#include <limits.h> +#include <sys/stat.h> +#include <signal.h> + +#define NOOP(x) (x += 0) + +static int pass_ctrl_keypad = 1; + +void +md_init(int options) +{ +#if defined(__INTERIX) + char *term; + + term = getenv("TERM"); + + if (term == NULL) + setenv("TERM","interix"); +#elif defined(__DJGPP__) + _fmode = _O_BINARY; +#elif defined(_WIN32) + _fmode = _O_BINARY; +#endif + +#if defined(HAVE_ESCDELAY) || defined(NCURSES_VERSION) + ESCDELAY=64; +#endif + +#if defined(DUMP) + md_onsignal_default(); +#else + md_onsignal_exit(); +#endif + + if (options & MD_STRIP_CTRL_KEYPAD) + pass_ctrl_keypad = 0; + else + pass_ctrl_keypad = 1; +} + +void +md_onsignal_default(void) +{ +#ifdef SIGHUP + signal(SIGHUP, SIG_DFL); +#endif +#ifdef SIGQUIT + signal(SIGQUIT, SIG_DFL); +#endif +#ifdef SIGILL + signal(SIGILL, SIG_DFL); +#endif +#ifdef SIGTRAP + signal(SIGTRAP, SIG_DFL); +#endif +#ifdef SIGIOT + signal(SIGIOT, SIG_DFL); +#endif +#ifdef SIGEMT + signal(SIGEMT, SIG_DFL); +#endif +#ifdef SIGFPE + signal(SIGFPE, SIG_DFL); +#endif +#ifdef SIGBUS + signal(SIGBUS, SIG_DFL); +#endif +#ifdef SIGSEGV + signal(SIGSEGV, SIG_DFL); +#endif +#ifdef SIGSYS + signal(SIGSYS, SIG_DFL); +#endif +#ifdef SIGTERM + signal(SIGTERM, SIG_DFL); +#endif +} + +void +md_onsignal_exit(void) +{ +#ifdef SIGHUP + signal(SIGHUP, SIG_DFL); +#endif +#ifdef SIGQUIT + signal(SIGQUIT, exit); +#endif +#ifdef SIGILL + signal(SIGILL, exit); +#endif +#ifdef SIGTRAP + signal(SIGTRAP, exit); +#endif +#ifdef SIGIOT + signal(SIGIOT, exit); +#endif +#ifdef SIGEMT + signal(SIGEMT, exit); +#endif +#ifdef SIGFPE + signal(SIGFPE, exit); +#endif +#ifdef SIGBUS + signal(SIGBUS, exit); +#endif +#ifdef SIGSEGV + signal(SIGSEGV, exit); +#endif +#ifdef SIGSYS + signal(SIGSYS, exit); +#endif +#ifdef SIGTERM + signal(SIGTERM, exit); +#endif +} + +extern void auto_save(int sig); +extern void endit(int sig); +extern void quit(int sig); + +void +md_onsignal_autosave(void) +{ + +#ifdef SIGHUP + signal(SIGHUP, auto_save); +#endif +#ifdef SIGQUIT + signal(SIGQUIT, endit); +#endif +#ifdef SIGILL + signal(SIGILL, auto_save); +#endif +#ifdef SIGTRAP + signal(SIGTRAP, auto_save); +#endif +#ifdef SIGIOT + signal(SIGIOT, auto_save); +#endif +#ifdef SIGEMT + signal(SIGEMT, auto_save); +#endif +#ifdef SIGFPE + signal(SIGFPE, auto_save); +#endif +#ifdef SIGBUS + signal(SIGBUS, auto_save); +#endif +#ifdef SIGSEGV + signal(SIGSEGV, auto_save); +#endif +#ifdef SIGSYS + signal(SIGSYS, auto_save); +#endif +#ifdef SIGTERM + signal(SIGTERM, auto_save); +#endif +#ifdef SIGINT + signal(SIGINT, quit); +#endif +} + +int +md_hasclreol(void) +{ +#if defined(clr_eol) +#ifdef NCURSES_VERSION + if (cur_term == NULL) + return(0); + if (cur_term->type.Strings == NULL) + return(0); +#endif + return((clr_eol != NULL) && (*clr_eol != 0)); +#elif defined(__PDCURSES__) + return(TRUE); +#else + return((CE != NULL) && (*CE != 0)); +#endif +} + +void +md_putchar(int c) +{ + putchar(c); +} + +#ifdef _WIN32 +static int md_standout_mode = 0; +#endif + +void +md_raw_standout(void) +{ +#ifdef _WIN32 + CONSOLE_SCREEN_BUFFER_INFO csbiInfo; + HANDLE hStdout; + WORD fgattr,bgattr; + + if (md_standout_mode == 0) + { + hStdout = GetStdHandle(STD_OUTPUT_HANDLE); + GetConsoleScreenBufferInfo(hStdout, &csbiInfo); + fgattr = (csbiInfo.wAttributes & 0xF); + bgattr = (csbiInfo.wAttributes & 0xF0); + SetConsoleTextAttribute(hStdout,(fgattr << 4) | (bgattr >> 4)); + md_standout_mode = 1; + } +#elif defined(SO) + tputs(SO,0,md_putchar); + fflush(stdout); +#endif +} + +void +md_raw_standend(void) +{ +#ifdef _WIN32 + CONSOLE_SCREEN_BUFFER_INFO csbiInfo; + HANDLE hStdout; + WORD fgattr,bgattr; + + if (md_standout_mode == 1) + { + hStdout = GetStdHandle(STD_OUTPUT_HANDLE); + GetConsoleScreenBufferInfo(hStdout, &csbiInfo); + fgattr = (csbiInfo.wAttributes & 0xF); + bgattr = (csbiInfo.wAttributes & 0xF0); + SetConsoleTextAttribute(hStdout,(fgattr << 4) | (bgattr >> 4)); + md_standout_mode = 0; + } +#elif defined(SE) + tputs(SE,0,md_putchar); + fflush(stdout); +#endif +} + +int +md_unlink_open_file(const char *file, FILE *inf) +{ +#ifdef _WIN32 + fclose(inf); + (void) _chmod(file, 0600); + return( _unlink(file) ); +#else + return(unlink(file)); +#endif +} + +int +md_unlink(char *file) +{ +#ifdef _WIN32 + (void) _chmod(file, 0600); + return( _unlink(file) ); +#else + return(unlink(file)); +#endif +} + +int +md_chmod(const char *filename, int mode) +{ +#ifdef _WIN32 + return( _chmod(filename, mode) ); +#else + return( chmod(filename, mode) ); +#endif +} + +void +md_normaluser(void) +{ +#if defined(HAVE_GETGID) && defined(HAVE_GETUID) + gid_t realgid = getgid(); + uid_t realuid = getuid(); + +#if defined(HAVE_SETRESGID) + if (setresgid(-1, realgid, realgid) != 0) { +#elif defined (HAVE_SETREGID) + if (setregid(realgid, realgid) != 0) { +#elif defined (HAVE_SETGID) + if (setgid(realgid) != 0) { +#else + if (0) { +#endif + perror("Could not drop setgid privileges. Aborting."); + exit(1); + } + +#if defined(HAVE_SETRESUID) + if (setresuid(-1, realuid, realuid) != 0) { +#elif defined(HAVE_SETREUID) + if (setreuid(realuid, realuid) != 0) { +#elif defined(HAVE_SETUID) + if (setuid(realuid) != 0) { +#else + if (0) { +#endif + perror("Could not drop setuid privileges. Aborting."); + exit(1); + } +#endif +} + +uid_t +md_getuid(void) +{ +#ifdef HAVE_GETUID + return( getuid() ); +#else + return(42); +#endif +} + +pid_t +md_getpid(void) +{ +#ifdef _WIN32 + return( _getpid() ); +#else + return( getpid() ); +#endif +} + +char * +md_getusername(void) +{ + static char login[80]; + char *l = NULL; +#ifdef _WIN32 + LPSTR mybuffer; + DWORD size = UNLEN + 1; + TCHAR buffer[UNLEN + 1]; + + mybuffer = buffer; + GetUserName(mybuffer,&size); + l = mybuffer; +#elif defined(HAVE_GETPWUID)&& !defined(__DJGPP__) + struct passwd *pw; + + pw = getpwuid(getuid()); + + l = pw->pw_name; +#endif + + if ((l == NULL) || (*l == '\0')) + if ( (l = getenv("USERNAME")) == NULL ) + if ( (l = getenv("LOGNAME")) == NULL ) + if ( (l = getenv("USER")) == NULL ) + l = "nobody"; + + strncpy(login,l,80); + login[79] = 0; + + return(login); +} + +char * +md_gethomedir(void) +{ + static char homedir[PATH_MAX]; + char *h = NULL; + size_t len; +#if defined(_WIN32) + TCHAR szPath[PATH_MAX]; +#endif +#if defined(_WIN32) || defined(DJGPP) + char slash = '\\'; +#else + char slash = '/'; + struct passwd *pw; + pw = getpwuid(getuid()); + + h = pw->pw_dir; + + if (strcmp(h,"/") == 0) + h = NULL; +#endif + homedir[0] = 0; +#ifdef _WIN32 + if(SUCCEEDED(SHGetFolderPath(NULL, CSIDL_PERSONAL, NULL, 0, szPath))) + h = szPath; +#endif + + if ( (h == NULL) || (*h == '\0') ) + { + if ( (h = getenv("HOME")) == NULL ) + { + if ( (h = getenv("HOMEDRIVE")) == NULL) + h = ""; + else + { + strncpy(homedir,h,PATH_MAX-1); + homedir[PATH_MAX-1] = 0; + + if ( (h = getenv("HOMEPATH")) == NULL) + h = ""; + } + } + } + + + len = strlen(homedir); + strncat(homedir,h,PATH_MAX-len-1); + len = strlen(homedir); + + if ((len > 0) && (homedir[len-1] != slash)) { + homedir[len] = slash; + homedir[len+1] = 0; + } + + return(homedir); +} + +void +md_sleep(int s) +{ +#ifdef _WIN32 + Sleep(s); +#else + sleep(s); +#endif +} + +char * +md_getshell(void) +{ + static char shell[PATH_MAX]; + char *s = NULL; +#ifdef _WIN32 + char *def = "C:\\WINDOWS\\SYSTEM32\\CMD.EXE"; +#elif defined(__DJGPP__) + char *def = "C:\\COMMAND.COM"; +#else + char *def = "/bin/sh"; + struct passwd *pw; + pw = getpwuid(getuid()); + s = pw->pw_shell; +#endif + if ((s == NULL) || (*s == '\0')) + if ( (s = getenv("COMSPEC")) == NULL) + if ( (s = getenv("SHELL")) == NULL) + if ( (s = getenv("SystemRoot")) == NULL) + s = def; + + strncpy(shell,s,PATH_MAX); + shell[PATH_MAX-1] = 0; + + return(shell); +} + +int +md_shellescape(void) +{ +#if defined(HAVE_WORKING_FORK) + int ret_status; + int pid; + void (*myquit)(int); + void (*myend)(int); + char *sh; + + sh = md_getshell(); + + while((pid = fork()) < 0) + sleep(1); + + if (pid == 0) /* Shell Process */ + { + /* + * Set back to original user, just in case + */ + md_normaluser(); + execl(sh == NULL ? "/bin/sh" : sh, "shell", "-i", NULL); + perror("No shelly"); + _exit(-1); + } + else /* Application */ + { + myend = signal(SIGINT, SIG_IGN); +#ifdef SIGQUIT + myquit = signal(SIGQUIT, SIG_IGN); +#endif + while (wait(&ret_status) != pid) + continue; + + signal(SIGINT, myquit); +#ifdef SIGQUIT + signal(SIGQUIT, myend); +#endif + } + return(ret_status); +#elif defined(HAVE__SPAWNL) + return((int)_spawnl(_P_WAIT,md_getshell(),"shell",NULL,0)); +#elif defined(HAVE_SPAWNL) + return ( spawnl(P_WAIT,md_getshell(),"shell",NULL,0) ); +#else + return(0); +#endif +} + +int +directory_exists(char *dirname) +{ + struct stat sb; + + if (stat(dirname, &sb) == 0) /* path exists */ + return (sb.st_mode & S_IFDIR); + + return(0); +} + +char * +md_getrealname(uid_t uid) +{ + static char uidstr[20]; +#if !defined(_WIN32) && !defined(DJGPP) + struct passwd *pp; + + if ((pp = getpwuid(uid)) == NULL) + { + sprintf(uidstr,"%d", uid); + return(uidstr); + } + else + return(pp->pw_name); +#else + sprintf(uidstr,"%d", uid); + return(uidstr); +#endif +} + +char * +md_getpass(char *prompt) +{ +#ifndef HAVE_GETPASS + static char password_buffer[9]; + char *p = password_buffer; + int c, count = 0; + int max_length = 9; + + fflush(stdout); + /* If we can't prompt, abort */ + if (fputs(prompt, stderr) < 0) + { + *p = '\0'; + return NULL; + } + + for(;;) + { + /* Get a character with no echo */ + c = _getch(); + + /* Exit on interrupt (^c or ^break) */ + if (c == '\003' || c == 0x100) + exit(1); + + /* Terminate on end of line or file (^j, ^m, ^d, ^z) */ + if (c == '\r' || c == '\n' || c == '\004' || c == '\032') + break; + + /* Back up on backspace */ + if (c == '\b') + { + if (count) + count--; + else if (p > password_buffer) + p--; + continue; + } + + /* Ignore DOS extended characters */ + if ((c & 0xff) != c) + continue; + + /* Add to password if it isn't full */ + if (p < password_buffer + max_length - 1) + *p++ = (char) c; + else + count++; + } + *p = '\0'; + + fputc('\n', stderr); + + return password_buffer; +#else + return( getpass(prompt) ); +#endif +} + +int +md_erasechar(void) +{ +#ifdef HAVE_ERASECHAR + return( erasechar() ); /* process erase character */ +#elif defined(VERASE) + return(_tty.c_cc[VERASE]); /* process erase character */ +#else + return(_tty.sg_erase); /* process erase character */ +#endif +} + +int +md_killchar(void) +{ +#ifdef HAVE_KILLCHAR + return( killchar() ); +#elif defined(VKILL) + return(_tty.c_cc[VKILL]); +#else + return(_tty.sg_kill); +#endif +} + +int +md_dsuspchar(void) +{ +#if defined(VDSUSP) /* POSIX has priority */ + struct termios attr; + tcgetattr(STDIN_FILENO, &attr); + return( attr.c_cc[VDSUSP] ); +#elif defined(TIOCGLTC) + struct ltchars ltc; + ioctl(1, TIOCGLTC, <c); + return(ltc.t_dsuspc); +#elif defined(_POSIX_VDISABLE) + return(_POSIX_VDISABLE); +#else + return(0); +#endif +} + +int +md_setdsuspchar(int c) +{ +#if defined(VDSUSP) /* POSIX has priority */ + struct termios attr; + tcgetattr(STDIN_FILENO, &attr); + attr.c_cc[VDSUSP] = c; + tcgetattr(STDIN_FILENO, &attr); +#elif defined(TIOCSLTC) + struct ltchars ltc; + ioctl(1, TIOCGLTC, <c); + ltc.t_dsuspc = c; + ioctl(1, TIOCSLTC, <c); +#else + NOOP(c); +#endif + return(0); +} + +int +md_suspchar(void) +{ +#if defined(VSUSP) /* POSIX has priority */ + struct termios attr; + tcgetattr(STDIN_FILENO, &attr); + return( attr.c_cc[VSUSP] ); +#elif defined(TIOCGLTC) + struct ltchars ltc; + ioctl(1, TIOCGLTC, <c); + return(ltc.t_suspc); +#elif defined(_POSIX_VDISABLE) + return(_POSIX_VDISABLE); +#else + return(0); +#endif +} + +int +md_setsuspchar(int c) +{ +#if defined(VSUSP) /* POSIX has priority */ + struct termios attr; + tcgetattr(STDIN_FILENO, &attr); + attr.c_cc[VSUSP] = c; + tcgetattr(STDIN_FILENO, &attr); +#elif defined(TIOCSLTC) + struct ltchars ltc; + ioctl(1, TIOCGLTC, <c); + ltc.t_suspc = c; + ioctl(1, TIOCSLTC, <c); +#else + NOOP(c); +#endif + + return(0); +} + +/* + Cursor/Keypad Support + + Sadly Cursor/Keypad support is less straightforward than it should be. + + The various terminal emulators/consoles choose to differentiate the + cursor and keypad keys (with modifiers) in different ways (if at all!). + Furthermore they use different code set sequences for each key only + a subset of which the various curses libraries recognize. Partly due + to incomplete termcap/terminfo entries and partly due to inherent + limitations of those terminal capability databases. + + I give curses first crack at decoding the sequences. If it fails to decode + it we check for common ESC-prefixed sequences. + + All cursor/keypad results are translated into standard rogue movement + commands. + + Unmodified keys are translated to walk commands: hjklyubn + Modified (shift,control,alt) are translated to run commands: HJKLYUBN + + Console and supported (differentiated) keys + Interix: Cursor Keys, Keypad, Ctl-Keypad + Cygwin: Cursor Keys, Keypad, Alt-Cursor Keys + MSYS: Cursor Keys, Keypad, Ctl-Cursor Keys, Ctl-Keypad + Win32: Cursor Keys, Keypad, Ctl/Shift/Alt-Cursor Keys, Ctl/Alt-Keypad + DJGPP: Cursor Keys, Keypad, Ctl/Shift/Alt-Cursor Keys, Ctl/Alt-Keypad + + Interix Console (raw, ncurses) + ============================== + normal shift ctrl alt + ESC [D, ESC F^, ESC [D, ESC [D /# Left #/ + ESC [C, ESC F$, ESC [C, ESC [C /# Right #/ + ESC [A, ESC F-, local win, ESC [A /# Up #/ + ESC [B, ESC F+, local win, ESC [B /# Down #/ + ESC [H, ESC [H, ESC [H, ESC [H /# Home #/ + ESC [S, local win, ESC [S, ESC [S /# Page Up #/ + ESC [T, local win, ESC [T, ESC [T /# Page Down #/ + ESC [U, ESC [U, ESC [U, ESC [U /# End #/ + ESC [D, ESC F^, ESC [D, O /# Keypad Left #/ + ESC [C, ESC F$, ESC [C, O /# Keypad Right #/ + ESC [A, ESC [A, ESC [-1, O /# Keypad Up #/ + ESC [B, ESC [B, ESC [-2, O /# Keypad Down #/ + ESC [H, ESC [H, ESC [-263, O /# Keypad Home #/ + ESC [S, ESC [S, ESC [-19, O /# Keypad PgUp #/ + ESC [T, ESC [T, ESC [-20, O /# Keypad PgDn #/ + ESC [U, ESC [U, ESC [-21, O /# Keypad End #/ + nothing, nothing, nothing, O /# Kaypad 5 #/ + + Interix Console (term=interix, ncurses) + ============================== + KEY_LEFT, ESC F^, KEY_LEFT, KEY_LEFT /# Left #/ + KEY_RIGHT, ESC F$, KEY_RIGHT, KEY_RIGHT /# Right #/ + KEY_UP, 0x146, local win, KEY_UP /# Up #/ + KEY_DOWN, 0x145, local win, KEY_DOWN /# Down #/ + ESC [H, ESC [H, ESC [H, ESC [H /# Home #/ + KEY_PPAGE, local win, KEY_PPAGE, KEY_PPAGE /# Page Up #/ + KEY_NPAGE, local win, KEY_NPAGE, KEY_NPAGE /# Page Down #/ + KEY_LL, KEY_LL, KEY_LL, KEY_LL /# End #/ + KEY_LEFT, ESC F^, ESC [-4, O /# Keypad Left #/ + KEY_RIGHT, ESC F$, ESC [-3, O /# Keypad Right #/ + KEY_UP, KEY_UP, ESC [-1, O /# Keypad Up #/ + KEY_DOWN, KEY_DOWN, ESC [-2, O /# Keypad Down #/ + ESC [H, ESC [H, ESC [-263, O /# Keypad Home #/ + KEY_PPAGE, KEY_PPAGE, ESC [-19, O /# Keypad PgUp #/ + KEY_NPAGE, KEY_NPAGE, ESC [-20, O /# Keypad PgDn #/ + KEY_LL, KEY_LL, ESC [-21, O /# Keypad End #/ + nothing, nothing, nothing, O /# Keypad 5 #/ + + Cygwin Console (raw, ncurses) + ============================== + normal shift ctrl alt + ESC [D, ESC [D, ESC [D, ESC ESC [D /# Left #/ + ESC [C, ESC [C, ESC [C, ESC ESC [C /# Rght #/ + ESC [A, ESC [A, ESC [A, ESC ESC [A /# Up #/ + ESC [B, ESC [B, ESC [B, ESC ESC [B /# Down #/ + ESC [1~, ESC [1~, ESC [1~, ESC ESC [1~ /# Home #/ + ESC [5~, ESC [5~, ESC [5~, ESC ESC [5~ /# Page Up #/ + ESC [6~, ESC [6~, ESC [6~, ESC ESC [6~ /# Page Down #/ + ESC [4~, ESC [4~, ESC [4~, ESC ESC [4~ /# End #/ + ESC [D, ESC [D, ESC [D, ESC ESC [D,O /# Keypad Left #/ + ESC [C, ESC [C, ESC [C, ESC ESC [C,O /# Keypad Right #/ + ESC [A, ESC [A, ESC [A, ESC ESC [A,O /# Keypad Up #/ + ESC [B, ESC [B, ESC [B, ESC ESC [B,O /# Keypad Down #/ + ESC [1~, ESC [1~, ESC [1~, ESC ESC [1~,O /# Keypad Home #/ + ESC [5~, ESC [5~, ESC [5~, ESC ESC [5~,O /# Keypad PgUp #/ + ESC [6~, ESC [6~, ESC [6~, ESC ESC [6~,O /# Keypad PgDn #/ + ESC [4~, ESC [4~, ESC [4~, ESC ESC [4~,O /# Keypad End #/ + ESC [-71, nothing, nothing, O /# Keypad 5 #/ + + Cygwin Console (term=cygwin, ncurses) + ============================== + KEY_LEFT, KEY_LEFT, KEY_LEFT, ESC-260 /# Left #/ + KEY_RIGHT, KEY_RIGHT, KEY_RIGHT, ESC-261 /# Rght #/ + KEY_UP, KEY_UP, KEY_UP, ESC-259 /# Up #/ + KEY_DOWN, KEY_DOWN, KEY_DOWN, ESC-258 /# Down #/ + KEY_HOME, KEY_HOME, KEY_HOME, ESC-262 /# Home #/ + KEY_PPAGE, KEY_PPAGE, KEY_PPAGE, ESC-339 /# Page Up #/ + KEY_NPAGE, KEY_NPAGE, KEY_NPAGE, ESC-338 /# Page Down #/ + KEY_END, KEY_END, KEY_END, ESC-360 /# End #/ + KEY_LEFT, KEY_LEFT, KEY_LEFT, ESC-260,O /# Keypad Left #/ + KEY_RIGHT, KEY_RIGHT, KEY_RIGHT, ESC-261,O /# Keypad Right #/ + KEY_UP, KEY_UP, KEY_UP, ESC-259,O /# Keypad Up #/ + KEY_DOWN, KEY_DOWN, KEY_DOWN, ESC-258,O /# Keypad Down #/ + KEY_HOME, KEY_HOME, KEY_HOME, ESC-262,O /# Keypad Home #/ + KEY_PPAGE, KEY_PPAGE, KEY_PPAGE, ESC-339,O /# Keypad PgUp #/ + KEY_NPAGE, KEY_NPAGE, KEY_NPAGE, ESC-338,O /# Keypad PgDn #/ + KEY_END, KEY_END, KEY_END, ESC-360,O /# Keypad End #/ + ESC [G, nothing, nothing, O /# Keypad 5 #/ + + MSYS Console (raw, ncurses) + ============================== + normal shift ctrl alt + ESC OD, ESC [d, ESC Od nothing /# Left #/ + ESC OE, ESC [e, ESC Oe, nothing /# Right #/ + ESC OA, ESC [a, ESC Oa, nothing /# Up #/ + ESC OB, ESC [b, ESC Ob, nothing /# Down #/ + ESC [7~, ESC [7$, ESC [7^, nothing /# Home #/ + ESC [5~, local window, ESC [5^, nothing /# Page Up #/ + ESC [6~, local window, ESC [6^, nothing /# Page Down #/ + ESC [8~, ESC [8$, ESC [8^, nothing /# End #/ + ESC OD, ESC [d, ESC Od O /# Keypad Left #/ + ESC OE, ESC [c, ESC Oc, O /# Keypad Right #/ + ESC OA, ESC [a, ESC Oa, O /# Keypad Up #/ + ESC OB, ESC [b, ESC Ob, O /# Keypad Down #/ + ESC [7~, ESC [7$, ESC [7^, O /# Keypad Home #/ + ESC [5~, local window, ESC [5^, O /# Keypad PgUp #/ + ESC [6~, local window, ESC [6^, O /# Keypad PgDn #/ + ESC [8~, ESC [8$, ESC [8^, O /# Keypad End #/ + 11, 11, 11, O /# Keypad 5 #/ + + MSYS Console (term=rxvt, ncurses) + ============================== + normal shift ctrl alt + KEY_LEFT, KEY_SLEFT, 514 nothing /# Left #/ + KEY_RIGHT, KEY_SRIGHT, 516, nothing /# Right #/ + KEY_UP, 518, 519, nothing /# Up #/ + KEY_DOWN, 511, 512, nothing /# Down #/ + KEY_HOME, KEY_SHOME, ESC [7^, nothing /# Home #/ + KEY_PPAGE, local window, ESC [5^, nothing /# Page Up #/ + KEY_NPAGE, local window, ESC [6^, nothing /# Page Down #/ + KEY_END, KEY_SEND, KEY_EOL, nothing /# End #/ + KEY_LEFT, KEY_SLEFT, 514 O /# Keypad Left #/ + KEY_RIGHT, KEY_SRIGHT, 516, O /# Keypad Right #/ + KEY_UP, 518, 519, O /# Keypad Up #/ + KEY_DOWN, 511, 512, O /# Keypad Down #/ + KEY_HOME, KEY_SHOME, ESC [7^, O /# Keypad Home #/ + KEY_PPAGE, local window, ESC [5^, O /# Keypad PgUp #/ + KEY_NPAGE, local window, ESC [6^, O /# Keypad PgDn #/ + KEY_END, KEY_SEND, KEY_EOL, O /# Keypad End #/ + 11, 11, 11, O /# Keypad 5 #/ + + Win32 Console (raw, pdcurses) + DJGPP Console (raw, pdcurses) + ============================== + normal shift ctrl alt + 260, 391, 443, 493 /# Left #/ + 261, 400, 444, 492 /# Right #/ + 259, 547, 480, 490 /# Up #/ + 258, 548, 481, 491 /# Down #/ + 262, 388, 447, 524 /# Home #/ + 339, 396, 445, 526 /# Page Up #/ + 338, 394, 446, 520 /# Page Down #/ + 358, 384, 448, 518 /# End #/ + 452, 52('4'), 511, 521 /# Keypad Left #/ + 454, 54('6'), 513, 523 /# Keypad Right #/ + 450, 56('8'), 515, 525 /# Keypad Up #/ + 456, 50('2'), 509, 519 /# Keypad Down #/ + 449, 55('7'), 514, 524 /# Keypad Home #/ + 451, 57('9'), 516, 526 /# Keypad PgUp #/ + 457, 51('3'), 510, 520 /# Keypad PgDn #/ + 455, 49('1'), 508, 518 /# Keypad End #/ + 453, 53('5'), 512, 522 /# Keypad 5 #/ + + Win32 Console (pdcurses, MSVC/MingW32) + DJGPP Console (pdcurses) + ============================== + normal shift ctrl alt + KEY_LEFT, KEY_SLEFT, CTL_LEFT, ALT_LEFT /# Left #/ + KEY_RIGHT, KEY_SRIGHT, CTL_RIGHT, ALT_RIGHT /# Right #/ + KEY_UP, KEY_SUP, CTL_UP, ALT_UP /# Up #/ + KEY_DOWN, KEY_SDOWN, CTL_DOWN, ALT_DOWN /# Down #/ + KEY_HOME, KEY_SHOME, CTL_HOME, ALT_HOME /# Home #/ + KEY_PPAGE, KEY_SPREVIOUS, CTL_PGUP, ALT_PGUP /# Page Up #/ + KEY_NPAGE, KEY_SNEXTE, CTL_PGDN, ALT_PGDN /# Page Down #/ + KEY_END, KEY_SEND, CTL_END, ALT_END /# End #/ + KEY_B1, 52('4'), CTL_PAD4, ALT_PAD4 /# Keypad Left #/ + KEY_B3, 54('6'), CTL_PAD6, ALT_PAD6 /# Keypad Right #/ + KEY_A2, 56('8'), CTL_PAD8, ALT_PAD8 /# Keypad Up #/ + KEY_C2, 50('2'), CTL_PAD2, ALT_PAD2 /# Keypad Down #/ + KEY_A1, 55('7'), CTL_PAD7, ALT_PAD7 /# Keypad Home #/ + KEY_A3, 57('9'), CTL_PAD9, ALT_PAD9 /# Keypad PgUp #/ + KEY_C3, 51('3'), CTL_PAD3, ALT_PAD3 /# Keypad PgDn #/ + KEY_C1, 49('1'), CTL_PAD1, ALT_PAD1 /# Keypad End #/ + KEY_B2, 53('5'), CTL_PAD5, ALT_PAD5 /# Keypad 5 #/ + + Windows Telnet (raw) + ============================== + normal shift ctrl alt + ESC [D, ESC [D, ESC [D, ESC [D /# Left #/ + ESC [C, ESC [C, ESC [C, ESC [C /# Right #/ + ESC [A, ESC [A, ESC [A, ESC [A /# Up #/ + ESC [B, ESC [B, ESC [B, ESC [B /# Down #/ + ESC [1~, ESC [1~, ESC [1~, ESC [1~ /# Home #/ + ESC [5~, ESC [5~, ESC [5~, ESC [5~ /# Page Up #/ + ESC [6~, ESC [6~, ESC [6~, ESC [6~ /# Page Down #/ + ESC [4~, ESC [4~, ESC [4~, ESC [4~ /# End #/ + ESC [D, ESC [D, ESC [D, ESC [D /# Keypad Left #/ + ESC [C, ESC [C, ESC [C, ESC [C /# Keypad Right #/ + ESC [A, ESC [A, ESC [A, ESC [A /# Keypad Up #/ + ESC [B, ESC [B, ESC [B, ESC [B /# Keypad Down #/ + ESC [1~, ESC [1~, ESC [1~, ESC [1~ /# Keypad Home #/ + ESC [5~, ESC [5~, ESC [5~, ESC [5~ /# Keypad PgUp #/ + ESC [6~, ESC [6~, ESC [6~, ESC [6~ /# Keypad PgDn #/ + ESC [4~, ESC [4~, ESC [4~, ESC [4~ /# Keypad End #/ + nothing, nothing, nothing, nothing /# Keypad 5 #/ + + Windows Telnet (term=xterm) + ============================== + normal shift ctrl alt + KEY_LEFT, KEY_LEFT, KEY_LEFT, KEY_LEFT /# Left #/ + KEY_RIGHT, KEY_RIGHT, KEY_RIGHT, KEY_RIGHT /# Right #/ + KEY_UP, KEY_UP, KEY_UP, KEY_UP /# Up #/ + KEY_DOWN, KEY_DOWN, KEY_DOWN, KEY_DOWN /# Down #/ + ESC [1~, ESC [1~, ESC [1~, ESC [1~ /# Home #/ + KEY_PPAGE, KEY_PPAGE, KEY_PPAGE, KEY_PPAGE /# Page Up #/ + KEY_NPAGE, KEY_NPAGE, KEY_NPAGE, KEY_NPAGE /# Page Down #/ + ESC [4~, ESC [4~, ESC [4~, ESC [4~ /# End #/ + KEY_LEFT, KEY_LEFT, KEY_LEFT, O /# Keypad Left #/ + KEY_RIGHT, KEY_RIGHT, KEY_RIGHT, O /# Keypad Right #/ + KEY_UP, KEY_UP, KEY_UP, O /# Keypad Up #/ + KEY_DOWN, KEY_DOWN, KEY_DOWN, O /# Keypad Down #/ + ESC [1~, ESC [1~, ESC [1~, ESC [1~ /# Keypad Home #/ + KEY_PPAGE, KEY_PPAGE, KEY_PPAGE, KEY_PPAGE /# Keypad PgUp #/ + KEY_NPAGE, KEY_NPAGE, KEY_NPAGE, KEY_NPAGE /# Keypad PgDn #/ + ESC [4~, ESC [4~, ESC [4~, O /# Keypad End #/ + ESC [-71, nothing, nothing, O /# Keypad 5 #/ + + PuTTY + ============================== + normal shift ctrl alt + ESC [D, ESC [D, ESC OD, ESC [D /# Left #/ + ESC [C, ESC [C, ESC OC, ESC [C /# Right #/ + ESC [A, ESC [A, ESC OA, ESC [A /# Up #/ + ESC [B, ESC [B, ESC OB, ESC [B /# Down #/ + ESC [1~, ESC [1~, local win, ESC [1~ /# Home #/ + ESC [5~, local win, local win, ESC [5~ /# Page Up #/ + ESC [6~, local win, local win, ESC [6~ /# Page Down #/ + ESC [4~, ESC [4~, local win, ESC [4~ /# End #/ + ESC [D, ESC [D, ESC [D, O /# Keypad Left #/ + ESC [C, ESC [C, ESC [C, O /# Keypad Right #/ + ESC [A, ESC [A, ESC [A, O /# Keypad Up #/ + ESC [B, ESC [B, ESC [B, O /# Keypad Down #/ + ESC [1~, ESC [1~, ESC [1~, O /# Keypad Home #/ + ESC [5~, ESC [5~, ESC [5~, O /# Keypad PgUp #/ + ESC [6~, ESC [6~, ESC [6~, O /# Keypad PgDn #/ + ESC [4~, ESC [4~, ESC [4~, O /# Keypad End #/ + nothing, nothing, nothing, O /# Keypad 5 #/ + + PuTTY + ============================== + normal shift ctrl alt + KEY_LEFT, KEY_LEFT, ESC OD, ESC KEY_LEFT /# Left #/ + KEY_RIGHT KEY_RIGHT, ESC OC, ESC KEY_RIGHT /# Right #/ + KEY_UP, KEY_UP, ESC OA, ESC KEY_UP /# Up #/ + KEY_DOWN, KEY_DOWN, ESC OB, ESC KEY_DOWN /# Down #/ + ESC [1~, ESC [1~, local win, ESC ESC [1~ /# Home #/ + KEY_PPAGE local win, local win, ESC KEY_PPAGE /# Page Up #/ + KEY_NPAGE local win, local win, ESC KEY_NPAGE /# Page Down #/ + ESC [4~, ESC [4~, local win, ESC ESC [4~ /# End #/ + ESC Ot, ESC Ot, ESC Ot, O /# Keypad Left #/ + ESC Ov, ESC Ov, ESC Ov, O /# Keypad Right #/ + ESC Ox, ESC Ox, ESC Ox, O /# Keypad Up #/ + ESC Or, ESC Or, ESC Or, O /# Keypad Down #/ + ESC Ow, ESC Ow, ESC Ow, O /# Keypad Home #/ + ESC Oy, ESC Oy, ESC Oy, O /# Keypad PgUp #/ + ESC Os, ESC Os, ESC Os, O /# Keypad PgDn #/ + ESC Oq, ESC Oq, ESC Oq, O /# Keypad End #/ + ESC Ou, ESC Ou, ESC Ou, O /# Keypad 5 #/ +*/ + +#define M_NORMAL 0 +#define M_ESC 1 +#define M_KEYPAD 2 +#define M_TRAIL 3 + +#ifndef CTRL +#define CTRL(ch) (ch & 0x1F) +#endif + +int undo[5]; +int uindex = -1; + +int +reread() +{ + int redo; + + if (uindex < 0) + return 0; + + redo = undo[0]; + undo[0] = undo[1]; + undo[1] = undo[2]; + undo[2] = undo[3]; + undo[3] = undo[4]; + uindex--; + return redo; +} + +void +unread(int c) +{ + if (uindex >= 4) + abort(); + + undo[++uindex] = c; +} + +int +md_readchar(WINDOW *win) +{ + int ch = 0; + int lastch = 0; + int wch = 0; + int mode = M_NORMAL; + int mode2 = M_NORMAL; + int nodelayf = 0; + int count = 0; + + for(;;) + { + if (mode == M_NORMAL && uindex >= 0) + { + wch = ch = reread(); + break; + } + + wch = ch = wgetch(win); + + if (ch == ERR) /* timed out or error */ + { + if (nodelayf) /* likely timed out, switch to */ + { /* normal mode and block on */ + mode = M_NORMAL; /* next read */ + nodelayf = 0; + nodelay(win,0); + } + else if (count > 10) /* after 10 errors assume */ + auto_save(0); /* input stream is broken and */ + else /* auto save and exit */ + count++; + + continue; + } + + count = 0; /* reset input error count */ + + if (mode == M_TRAIL) + { + if (ch == '^') /* msys console : 7,5,6,8: modified*/ + ch = CTRL( toupper(lastch) ); + else if (ch == '~') /* cygwin console: 1,5,6,4: normal */ + ch = tolower(lastch); /* windows telnet: 1,5,6,4: normal */ + /* msys console : 7,5,6,8: normal */ + else if (mode2 == M_ESC) /* cygwin console: 1,5,6,4: modified*/ + ch = CTRL( toupper(ch) ); + else + { + mode = M_NORMAL; + unread(ch); + continue; + } + + break; + } + + if (mode == M_ESC) + { + if (ch == 27) + { + mode2 = M_ESC; + unread(ch); + continue; + } + + if ((ch == 'F') || (ch == 'O') || (ch == '[')) + { + mode = M_KEYPAD; + unread(ch); + continue; + } + + + switch(ch) + { + /* Cygwin Console */ + /* PuTTY */ + case KEY_LEFT : ch = CTRL('H'); break; + case KEY_RIGHT: ch = CTRL('L'); break; + case KEY_UP : ch = CTRL('K'); break; + case KEY_DOWN : ch = CTRL('J'); break; + case KEY_HOME : ch = CTRL('Y'); break; + case KEY_PPAGE: ch = CTRL('U'); break; + case KEY_NPAGE: ch = CTRL('N'); break; + case KEY_END : ch = CTRL('B'); break; + + default: mode = M_NORMAL; + mode2 = M_NORMAL; + unread(ch); + continue;} + + break; + } + + if (mode == M_KEYPAD) + { + switch(ch) + { + /* ESC F - Interix Console codes */ + case '^': ch = CTRL('H'); break; /* Shift-Left */ + case '$': ch = CTRL('L'); break; /* Shift-Right */ + + /* ESC [ - Interix Console codes */ + case 'H': ch = 'y'; break; /* Home */ + case 1: ch = CTRL('K'); break; /* Ctl-Keypad Up */ + case 2: ch = CTRL('J'); break; /* Ctl-Keypad Down */ + case 3: ch = CTRL('L'); break; /* Ctl-Keypad Right */ + case 4: ch = CTRL('H'); break; /* Ctl-Keypad Left */ + case 263: ch = CTRL('Y'); break; /* Ctl-Keypad Home */ + case 19: ch = CTRL('U'); break; /* Ctl-Keypad PgUp */ + case 20: ch = CTRL('N'); break; /* Ctl-Keypad PgDn */ + case 21: ch = CTRL('B'); break; /* Ctl-Keypad End */ + + /* ESC [ - Cygwin Console codes */ + case 'G': ch = '.'; break; /* Keypad 5 */ + case '7': lastch = 'Y'; mode=M_TRAIL; break; /* Ctl-Home */ + case '5': lastch = 'U'; mode=M_TRAIL; break; /* Ctl-PgUp */ + case '6': lastch = 'N'; mode=M_TRAIL; break; /* Ctl-PgDn */ + + /* ESC [ - Win32 Telnet, PuTTY */ + case '1': lastch = 'y'; mode=M_TRAIL; break; /* Home */ + case '4': lastch = 'b'; mode=M_TRAIL; break; /* End */ + + /* ESC O - PuTTY */ + case 'D': ch = CTRL('H'); break; + case 'C': ch = CTRL('L'); break; + case 'A': ch = CTRL('K'); break; + case 'B': ch = CTRL('J'); break; + case 't': ch = 'h'; break; + case 'v': ch = 'l'; break; + case 'x': ch = 'k'; break; + case 'r': ch = 'j'; break; + case 'w': ch = 'y'; break; + case 'y': ch = 'u'; break; + case 's': ch = 'n'; break; + case 'q': ch = 'b'; break; + case 'u': ch = '.'; break; + } + + if (mode != M_KEYPAD) + { + unread(ch); + continue; + } + } + + if (ch == 27) + { + nodelay(win,1); + mode = M_ESC; + nodelayf = 1; + unread(ch); + continue; + } + + switch(ch) + { + case KEY_LEFT : ch = 'h'; break; + case KEY_DOWN : ch = 'j'; break; + case KEY_UP : ch = 'k'; break; + case KEY_RIGHT : ch = 'l'; break; + case KEY_HOME : ch = 'y'; break; + case KEY_PPAGE : ch = 'u'; break; + case KEY_END : ch = 'b'; break; +#ifdef KEY_LL + case KEY_LL : ch = 'b'; break; +#endif + case KEY_NPAGE : ch = 'n'; break; + +#ifdef KEY_B1 + case KEY_B1 : ch = 'h'; break; + case KEY_C2 : ch = 'j'; break; + case KEY_A2 : ch = 'k'; break; + case KEY_B3 : ch = 'l'; break; +#endif + case KEY_A1 : ch = 'y'; break; + case KEY_A3 : ch = 'u'; break; + case KEY_C1 : ch = 'b'; break; + case KEY_C3 : ch = 'n'; break; + /* next should be '.', but for problem with putty/linux */ + case KEY_B2 : ch = 'u'; break; + +#ifdef KEY_SLEFT + case KEY_SRIGHT : ch = CTRL('L'); break; + case KEY_SLEFT : ch = CTRL('H'); break; +#ifdef KEY_SUP + case KEY_SUP : ch = CTRL('K'); break; + case KEY_SDOWN : ch = CTRL('J'); break; +#endif + case KEY_SHOME : ch = CTRL('Y'); break; + case KEY_SPREVIOUS:ch = CTRL('U'); break; + case KEY_SEND : ch = CTRL('B'); break; + case KEY_SNEXT : ch = CTRL('N'); break; +#endif + case 0x146 : ch = CTRL('K'); break; /* Shift-Up */ + case 0x145 : ch = CTRL('J'); break; /* Shift-Down */ + +#ifdef CTL_RIGHT + case CTL_RIGHT : ch = CTRL('L'); break; + case CTL_LEFT : ch = CTRL('H'); break; + case CTL_UP : ch = CTRL('K'); break; + case CTL_DOWN : ch = CTRL('J'); break; + case CTL_HOME : ch = CTRL('Y'); break; + case CTL_PGUP : ch = CTRL('U'); break; + case CTL_END : ch = CTRL('B'); break; + case CTL_PGDN : ch = CTRL('N'); break; +#endif +#ifdef KEY_EOL + case KEY_EOL : ch = CTRL('B'); break; +#endif + +#ifndef CTL_PAD1 + /* MSYS rxvt console */ + case 511 : ch = CTRL('J'); break; /* Shift Dn */ + case 512 : ch = CTRL('J'); break; /* Ctl Down */ + case 514 : ch = CTRL('H'); break; /* Ctl Left */ + case 516 : ch = CTRL('L'); break; /* Ctl Right*/ + case 518 : ch = CTRL('K'); break; /* Shift Up */ + case 519 : ch = CTRL('K'); break; /* Ctl Up */ +#endif + +#ifdef CTL_PAD1 + case CTL_PAD1 : ch = CTRL('B'); break; + case CTL_PAD2 : ch = CTRL('J'); break; + case CTL_PAD3 : ch = CTRL('N'); break; + case CTL_PAD4 : ch = CTRL('H'); break; + case CTL_PAD5 : ch = '.'; break; + case CTL_PAD6 : ch = CTRL('L'); break; + case CTL_PAD7 : ch = CTRL('Y'); break; + case CTL_PAD8 : ch = CTRL('K'); break; + case CTL_PAD9 : ch = CTRL('U'); break; +#endif + +#ifdef ALT_RIGHT + case ALT_RIGHT : ch = CTRL('L'); break; + case ALT_LEFT : ch = CTRL('H'); break; + case ALT_DOWN : ch = CTRL('J'); break; + case ALT_HOME : ch = CTRL('Y'); break; + case ALT_PGUP : ch = CTRL('U'); break; + case ALT_END : ch = CTRL('B'); break; + case ALT_PGDN : ch = CTRL('N'); break; +#endif + +#ifdef ALT_PAD1 + case ALT_PAD1 : ch = CTRL('B'); break; + case ALT_PAD2 : ch = CTRL('J'); break; + case ALT_PAD3 : ch = CTRL('N'); break; + case ALT_PAD4 : ch = CTRL('H'); break; + case ALT_PAD5 : ch = '.'; break; + case ALT_PAD6 : ch = CTRL('L'); break; + case ALT_PAD7 : ch = CTRL('Y'); break; + case ALT_PAD8 : ch = CTRL('K'); break; + case ALT_PAD9 : ch = CTRL('U'); break; +#endif +#ifdef KEY_BACKSPACE /* NCURSES in Keypad mode sends this for Ctrl-H */ + case KEY_BACKSPACE: ch = CTRL('H'); break; +#endif + } + + break; + } + + + if (nodelayf) + nodelay(win,0); + + uindex = -1; + + if (!pass_ctrl_keypad && (ch != wch)) + switch(ch) + { + case CTRL('H'): + case CTRL('L'): + case CTRL('K'): + case CTRL('J'): + case CTRL('Y'): + case CTRL('U'): + case CTRL('N'): + case CTRL('B'): + return(ch + 0x40); + } + + return(ch & 0x7F); +} + +#if defined(LOADAV) && defined(HAVE_NLIST_H) && defined(HAVE_NLIST) +/* + * loadav: + * Looking up load average in core (for system where the loadav() + * system call isn't defined + */ + +#include <nlist.h> + +struct nlist avenrun = { + "_avenrun" +}; + +int +md_loadav(double *avg) +{ + int kmem; + + if ((kmem = open("/dev/kmem", 0)) < 0) + goto bad; + nlist(NAMELIST, &avenrun); + if (avenrun.n_type == 0) + { + close(kmem); +bad: + avg[0] = 0.0; + avg[1] = 0.0; + avg[2] = 0.0; + return -1; + } + + lseek(kmem, avenrun.n_value, 0); + read(kmem, (char *) avg, 3 * sizeof (double)); + close(kmem); + return 0; +} +#else +int +md_loadav(double *avg) +{ +#if defined(HAVE_LOADAV) + loadav(avg); + return(0); +#elif defined(HAVE_GETLOADAVG) + int ret; + ret = getloadavg(avg,3); + return (ret == 3) ? 0 : -1; +#else + avg[0] = avg[1] = avg[2] = 0; + return(-1); +#endif +} +#endif + +#ifndef NSIG +#define NSIG 32 +#endif + +void +md_ignoreallsignals(void) +{ + int i; + + for (i = 0; i < NSIG; i++) + signal(i, SIG_IGN); +} + +void +md_tstphold(void) +{ +#ifdef SIGTSTP + /* + * If a process can be suspended, this code wouldn't work + */ +# ifdef SIG_HOLD + signal(SIGTSTP, SIG_HOLD); +# else + signal(SIGTSTP, SIG_IGN); +# endif +#endif +} + +void +md_tstpresume(void (*tstp)(int)) +{ +#ifdef SIGTSTP + signal(SIGTSTP, tstp); +#endif +} + +void +md_tstpsignal(void) +{ +#ifdef SIGTSTP + kill(0, SIGTSTP); /* send actual signal and suspend process */ +#endif +} + +#if defined(CHECKTIME) +void +md_start_checkout_timer(int time) +{ + int checkout(); + +#if defined(HAVE_ALARM) && defined(SIGALRM) + signal(SIGALRM, checkout); + alarm(time); +#endif +} + +void +md_stop_checkout_timer(void) +{ +#if defined(SIGALRM) + signal(SIGALRM, SIG_IGN); +#endif +} +#endif + +long +md_memused() +{ +#ifdef _WIN32 + MEMORYSTATUS stat; + + GlobalMemoryStatus(&stat); + + return((long)stat.dwTotalPageFile); +#else + return( (long)sbrk(0) ); +#endif +} + +int +md_ucount() +{ +#if defined(HAVE_UTMPX_H) + struct utmpx *up=NULL; + int count=0; + + setutxent(); + do + { + up = getutxent(); + if (up && up->ut_type == USER_PROCESS) + count++; + } while(up != NULL); + + endutxent(); + + return(count); +#else + return(1) +#endif +} + +int +md_lockfile(FILE *fp) +{ + int fd; + int ret; + + fflush(fp); + rewind(fp); + +#ifdef _WIN32 + fd = _fileno(fp); + ret = _locking(fd,_LK_LOCK,1); +#else + fd = fileno(fp); + + while((ret = lockf(fd, F_LOCK, 1)) == -1) + if (errno != EINTR) + break; +#endif + + return ret; +} + +int +md_unlockfile(FILE *fp) +{ + int fd; + int ret; + + fflush(fp); + rewind(fp); + + +#ifdef _WIN32 + fd = _fileno(fp); + ret = _locking(fd,_LK_UNLCK,1); +#else + fd = fileno(fp); + + while( (ret = lockf(fd, F_ULOCK, 1)) == -1) + if (errno != EINTR) + break; +#endif + + return ret; +}