Mercurial > hg > early-roguelike
diff rogue4/mdport.c @ 12:9535a08ddc39
Import Rogue 5.2 from the Roguelike Restoration Project (r1490)
author | edwarj4 |
---|---|
date | Sat, 24 Oct 2009 16:52:52 +0000 |
parents | |
children | 107a467612fb |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rogue4/mdport.c Sat Oct 24 16:52:52 2009 +0000 @@ -0,0 +1,1309 @@ +/* + mdport.c - Machine Dependent + + Copyright (C) 2005-2008 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. +*/ + +#if defined(_WIN32) +#include <Windows.h> +#include <Lmcons.h> +#include <process.h> +#include <shlobj.h> +#include <sys/types.h> +#include <io.h> +#include <conio.h> +#undef MOUSE_MOVED +#elif defined(__DJGPP__) +#include <process.h> +#else +#include <pwd.h> +#include <sys/utsname.h> +#include <unistd.h> +#include <utmpx.h> +#endif + +#ifdef __INTERIX +char *strdup(const char *s); +#endif + +#include <stdlib.h> +#include <string.h> + +#if defined(_WIN32) && !defined(__MINGW32__) +#define PATH_MAX MAX_PATH +#endif + +#include <curses.h> +#if !defined(DJGPP) +#include <term.h> +#endif + +#include <stdio.h> +#include <fcntl.h> +#include <limits.h> +#include <sys/stat.h> +#include <signal.h> + +#define MOD_MOVE(c) (toupper(c) ) + +void +md_init() +{ +#ifdef __INTERIX + char *term; + + term = getenv("TERM"); + + if (term == NULL) + setenv("TERM","interix",1); +#endif +#if defined(__DJGPP__) || defined(_WIN32) + _fmode = _O_BINARY; +#endif +#if defined(__CYGWIN__) || defined(__MSYS__) + ESCDELAY=250; +#endif +} + +int +md_hasclreol() +{ +#ifdef CE + return((CE != NULL) && (*CE != 0)); +#elif defined (clr_eol) + return((clr_eol != NULL) && (*clr_eol != 0)); +#elif !defined(__PDCURSES__) + return(clr_eol != NULL); +#else + return(TRUE); +#endif +} + +void +md_putchar(int c) +{ + putchar(c); +} + +static int md_standout_mode = 0; + +void +md_raw_standout() +{ +#ifdef _WIN32 + CONSOLE_SCREEN_BUFFER_INFO csbiInfo; + HANDLE hStdout; + int 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() +{ +#ifdef _WIN32 + CONSOLE_SCREEN_BUFFER_INFO csbiInfo; + HANDLE hStdout; + int 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(char *file, int inf) +{ +#ifdef _WIN32 + _close(inf); + _chmod(file, 0600); + return( _unlink(file) ); +#else + return(unlink(file)); +#endif +} + +int +md_unlink(char *file) +{ +#ifdef _WIN32 + _chmod(file, 0600); + return( _unlink(file) ); +#else + return(unlink(file)); +#endif +} + +FILE * +md_fdopen(int fd, char *mode) +{ +#ifdef _WIN32 + return( _fdopen(fd, mode) ); +#else + return( fdopen(fd, mode) ); +#endif +} + +int +md_fileno(FILE *fp) +{ +#ifdef _WIN32 + return( _fileno(fp) ); +#else + return( fileno(fp) ); +#endif +} + +int +md_creat(char *file, int mode) +{ + int fd; +#ifdef _WIN32 + mode = _S_IREAD | _S_IWRITE; + fd = _open(file,O_CREAT | O_EXCL | O_WRONLY, mode); +#else + fd = open(file,O_CREAT | O_EXCL | O_WRONLY, mode); +#endif + + return(fd); +} + + +void +md_normaluser() +{ +#ifndef _WIN32 + setuid(getuid()); + setgid(getgid()); +#endif +} + +int +md_getuid() +{ +#ifndef _WIN32 + return( getuid() ); +#else + return(42); +#endif +} + +char * +md_getusername(int uid) +{ + static char login[80]; + char *l = NULL; + + /* POSIX Shell has priority, then O/S specific methods */ + if ( (uid == md_getuid()) && ((l = getenv("LOGNAME")) != NULL) ) + { + strncpy(login,l,80); + login[79] = 0; + return(login); + } + +#ifdef _WIN32 + LPSTR mybuffer; + DWORD size = UNLEN + 1; + TCHAR buffer[UNLEN + 1]; + + mybuffer = buffer; + if (uid != md_getuid()) + strcpy(mybuffer, "someone"); + else + GetUserName(mybuffer,&size); + l = mybuffer; +#endif +#if !defined(_WIN32) && !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("USER")) == NULL ) + l = "nobody"; + + strncpy(login,l,80); + login[79] = 0; + + return(login); +} + +char * +md_gethomedir() +{ + 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 ) + h = ""; + + strncpy(homedir,h,PATH_MAX-1); + len = strlen(homedir); + + if ((len > 0) && (homedir[len-1] == slash)) + homedir[len-1] = 0; + + return(homedir); +} + +void +md_sleep(int s) +{ +#ifdef _WIN32 + Sleep(s); +#else + sleep(s); +#endif +} + +char * +md_getshell() +{ + 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); +} + +void +md_ignore_signals() +{ +#ifndef _WIN32 + int i; + for (i = 0; i < NSIG; i++) + signal(i, SIG_IGN); +#else + signal(SIGABRT, SIG_IGN); + signal(SIGFPE, SIG_IGN); + signal(SIGILL, SIG_IGN); + signal(SIGINT, SIG_IGN); + signal(SIGSEGV, SIG_IGN); + signal(SIGTERM, SIG_IGN); +#endif +} + +int +md_shellescape() +{ +#if (!defined(_WIN32) && !defined(__DJGPP__)) + int ret_status; + int pid; + void (*myquit)(int); + void (*myend)(int); +#endif + char *sh; + + sh = md_getshell(); + +#if defined(_WIN32) + return((int)_spawnl(_P_WAIT,sh,"shell",NULL,0)); +#elif defined(__DJGPP__) + return ( spawnl(P_WAIT,sh,"shell",NULL,0) ); +#else + while((pid = fork()) < 0) + sleep(1); + + if (pid == 0) /* Shell Process */ + { + /* + * Set back to original user, just in case + */ + setuid(getuid()); + setgid(getgid()); + execl(sh == NULL ? "/bin/sh" : sh, "shell", "-i", 0); + 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); +#endif +} + +char * +md_getrealname(int 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 +} + +extern char *xcrypt(char *key, char *salt); + +char * +md_crypt(char *key, char *salt) +{ + return( xcrypt(key,salt) ); +} + +char * +md_getpass(char *prompt) +{ +#ifdef _WIN32 + 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++ = c; + else + count++; + } + *p = '\0'; + + fputc('\n', stderr); + + return password_buffer; +#else + return( (char *) getpass(prompt) ); +#endif +} + + +int md_endian = 0x01020304; + +unsigned long int +md_ntohl(unsigned long int x) +{ +#ifdef _WIN32 + if ( *((char *)&md_endian) == 0x01 ) + return(x); + else + return( ((x & 0x000000ffU) << 24) | + ((x & 0x0000ff00U) << 8) | + ((x & 0x00ff0000U) >> 8) | + ((x & 0xff000000U) >> 24) ); +#else + return( ntohl(x) ); +#endif +} + +unsigned long int +md_htonl(unsigned long int x) +{ +#ifdef _WIN32 + if ( *((char *)&md_endian) == 0x01 ) + return(x); + else + return( ((x & 0x000000ffU) << 24) | + ((x & 0x0000ff00U) << 8) | + ((x & 0x00ff0000U) >> 8) | + ((x & 0xff000000U) >> 24) ); +#else + return( htonl(x) ); +#endif +} + +int +md_ucount() +{ +#ifdef __DJGPP__ + return(1); +#elif defined(_WIN32) + return(1); +#else + 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); +#endif +} + +int +md_getloadavg(double *avg) +{ +#if defined(__GLIBC__) || defined(_BSD) + if (getloadavg(avg, 3) == -1) +#endif + { + avg[0] = avg[1] = avg[2] = 0.0; + return -1; + } +} + +long +md_random() +{ +#ifdef _WIN32 + return(rand()); +#else + return( random() ); +#endif +} + +void +md_srandom(unsigned x) +{ +#ifdef _WIN32 + srand(x); +#else + srandom(x); +#endif +} + +int +md_rand() +{ +#ifdef _WIN32 + return(rand()); +#else + return(lrand48() & 0x7fffffff); +#endif +} + +void +md_srand(int seed) +{ +#ifdef _WIN32 + srand(seed); +#else + srand48(seed); +#endif +} + +char * +md_strdup(const char *s) +{ +#ifdef _WIN32 + return( _strdup(s) ); +#else + return(strdup(s)); +#endif +} + +long +md_memused() +{ +#ifdef _WIN32 + MEMORYSTATUS stat; + + GlobalMemoryStatus(&stat); + + return((long)stat.dwTotalPageFile); +#else + return( (long)sbrk(0) ); +#endif +} + +char * +md_gethostname() +{ + static char nodename[80]; + char *n = NULL; +#if !defined(_WIN32) && !defined(__DJGPP__) + struct utsname ourname; + + if (uname(&ourname) == 0) + n = ourname.nodename; +#endif + if ((n == NULL) || (*n == '\0')) + if ( (n = getenv("COMPUTERNAME")) == NULL) + if ( (n = getenv("HOSTNAME")) == NULL) + n = "localhost"; + + strncpy(nodename, n, 80); + nodename[79] = 0; + + return(nodename); +} + +int +md_erasechar() +{ +#ifdef BSD + return(_tty.sg_erase); /* process erase character */ +#elif defined(USG5_0) + return(_tty.c_cc[VERASE]); /* process erase character */ +#else /* USG5_2 .... curses */ + return( erasechar() ); /* process erase character */ +#endif +} + +int +md_killchar() +{ +#ifdef BSD + return(_tty.sg_kill); +#elif defined(USG5_0) + return(_tty.c_cc[VKILL]); +#else /* USG5_2 ..... curses */ + return( killchar() ); +#endif +} + +/* + * unctrl: + * Print a readable version of a certain character + */ + +char * +md_unctrl(char ch) +{ +#if USG5_0 + extern char *_unctrl[]; /* Defined in curses library */ + + return _unctrl[ch&0177]; +#else + return( (char *) unctrl(ch) ); +#endif +} + +void +md_flushinp() +{ +#ifdef BSD + ioctl(0, TIOCFLUSH); +#elif defined(USG5_0) + ioctl(_tty_ch,TCFLSH,0) +#else /* USG5_2.... curses */ + flushinp(); +#endif +} + +/* + 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 + +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 mode = M_NORMAL; + int mode2 = M_NORMAL; + int nodelayf = 0; + int count = 0; + + for(;;) + { + if (mode == M_NORMAL && uindex >= 0) + { + ch = reread(); + break; + } + + 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 = MOD_MOVE( 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 = MOD_MOVE( 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 = MOD_MOVE('H'); break; + case KEY_RIGHT: ch = MOD_MOVE('L'); break; + case KEY_UP : ch = MOD_MOVE('K'); break; + case KEY_DOWN : ch = MOD_MOVE('J'); break; + case KEY_HOME : ch = MOD_MOVE('Y'); break; + case KEY_PPAGE: ch = MOD_MOVE('U'); break; + case KEY_NPAGE: ch = MOD_MOVE('N'); break; + case KEY_END : ch = MOD_MOVE('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 = MOD_MOVE('H'); break; /* Shift-Left */ + case '$': ch = MOD_MOVE('L'); break; /* Shift-Right */ + + /* ESC [ - Interix Console codes */ + case 'H': ch = 'y'; break; /* Home */ + case 1: ch = MOD_MOVE('K'); break; /* Ctl-Keypad Up */ + case 2: ch = MOD_MOVE('J'); break; /* Ctl-Keypad Down */ + case 3: ch = MOD_MOVE('L'); break; /* Ctl-Keypad Right */ + case 4: ch = MOD_MOVE('H'); break; /* Ctl-Keypad Left */ + case 263: ch = MOD_MOVE('Y'); break; /* Ctl-Keypad Home */ + case 19: ch = MOD_MOVE('U'); break; /* Ctl-Keypad PgUp */ + case 20: ch = MOD_MOVE('N'); break; /* Ctl-Keypad PgDn */ + case 21: ch = MOD_MOVE('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 = MOD_MOVE('H'); break; + case 'C': ch = MOD_MOVE('L'); break; + case 'A': ch = MOD_MOVE('K'); break; + case 'B': ch = MOD_MOVE('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 = MOD_MOVE('L'); break; + case KEY_SLEFT : ch = MOD_MOVE('H'); break; +#ifdef KEY_SUP + case KEY_SUP : ch = MOD_MOVE('K'); break; + case KEY_SDOWN : ch = MOD_MOVE('J'); break; +#endif + case KEY_SHOME : ch = MOD_MOVE('Y'); break; + case KEY_SPREVIOUS:ch = MOD_MOVE('U'); break; + case KEY_SEND : ch = MOD_MOVE('B'); break; + case KEY_SNEXT : ch = MOD_MOVE('N'); break; +#endif + case 0x146 : ch = MOD_MOVE('K'); break; /* Shift-Up */ + case 0x145 : ch = MOD_MOVE('J'); break; /* Shift-Down */ + +#ifdef CTL_RIGHT + case CTL_RIGHT : ch = MOD_MOVE('L'); break; + case CTL_LEFT : ch = MOD_MOVE('H'); break; + case CTL_UP : ch = MOD_MOVE('K'); break; + case CTL_DOWN : ch = MOD_MOVE('J'); break; + case CTL_HOME : ch = MOD_MOVE('Y'); break; + case CTL_PGUP : ch = MOD_MOVE('U'); break; + case CTL_END : ch = MOD_MOVE('B'); break; + case CTL_PGDN : ch = MOD_MOVE('N'); break; +#endif +#ifdef KEY_EOL + case KEY_EOL : ch = MOD_MOVE('B'); break; +#endif + +#ifndef CTL_PAD1 + /* MSYS rxvt console */ + case 511 : ch = MOD_MOVE('J'); break; /* Shift Dn */ + case 512 : ch = MOD_MOVE('J'); break; /* Ctl Down */ + case 514 : ch = MOD_MOVE('H'); break; /* Ctl Left */ + case 516 : ch = MOD_MOVE('L'); break; /* Ctl Right*/ + case 518 : ch = MOD_MOVE('K'); break; /* Shift Up */ + case 519 : ch = MOD_MOVE('K'); break; /* Ctl Up */ +#endif + +#ifdef CTL_PAD1 + case CTL_PAD1 : ch = MOD_MOVE('B'); break; + case CTL_PAD2 : ch = MOD_MOVE('J'); break; + case CTL_PAD3 : ch = MOD_MOVE('N'); break; + case CTL_PAD4 : ch = MOD_MOVE('H'); break; + case CTL_PAD5 : ch = '.'; break; + case CTL_PAD6 : ch = MOD_MOVE('L'); break; + case CTL_PAD7 : ch = MOD_MOVE('Y'); break; + case CTL_PAD8 : ch = MOD_MOVE('K'); break; + case CTL_PAD9 : ch = MOD_MOVE('U'); break; +#endif + +#ifdef ALT_RIGHT + case ALT_RIGHT : ch = MOD_MOVE('L'); break; + case ALT_LEFT : ch = MOD_MOVE('H'); break; + case ALT_DOWN : ch = MOD_MOVE('J'); break; + case ALT_HOME : ch = MOD_MOVE('Y'); break; + case ALT_PGUP : ch = MOD_MOVE('U'); break; + case ALT_END : ch = MOD_MOVE('B'); break; + case ALT_PGDN : ch = MOD_MOVE('N'); break; +#endif + +#ifdef ALT_PAD1 + case ALT_PAD1 : ch = MOD_MOVE('B'); break; + case ALT_PAD2 : ch = MOD_MOVE('J'); break; + case ALT_PAD3 : ch = MOD_MOVE('N'); break; + case ALT_PAD4 : ch = MOD_MOVE('H'); break; + case ALT_PAD5 : ch = '.'; break; + case ALT_PAD6 : ch = MOD_MOVE('L'); break; + case ALT_PAD7 : ch = MOD_MOVE('Y'); break; + case ALT_PAD8 : ch = MOD_MOVE('K'); break; + case ALT_PAD9 : ch = MOD_MOVE('U'); break; +#endif + } + + break; + } + + if (nodelayf) + nodelay(win,0); + + uindex = -1; + + return(ch & 0x7F); +}