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