OSDN Git Service

9affd7ba8ebee7e08dd832d4f92990bf1a85e23b
[jnethack/source.git] / sys / share / unixtty.c
1 /* NetHack 3.6  unixtty.c       $NHDT-Date: 1450916700 2015/12/24 00:25:00 $  $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.21 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /*-Copyright (c) Michael Allison, 2006. */
4 /* NetHack may be freely redistributed.  See license for details. */
5
6 /* tty.c - (Unix) version */
7
8 /* With thanks to the people who sent code for SYSV - hpscdi!jon,
9  * arnold@ucsf-cgl, wcs@bo95b, cbcephus!pds and others.
10  */
11
12 #define NEED_VARARGS
13 #include "hack.h"
14
15 /*
16  * The distinctions here are not BSD - rest but rather USG - rest, as
17  * BSD still has the old sgttyb structure, but SYSV has termio. Thus:
18  */
19 #if (defined(BSD) || defined(ULTRIX)) && !defined(POSIX_TYPES)
20 #define V7
21 #else
22 #define USG
23 #endif
24
25 #ifdef USG
26
27 #ifdef POSIX_TYPES
28 #include <termios.h>
29 #include <unistd.h>
30 #define termstruct termios
31 #else
32 #include <termio.h>
33 #if defined(TCSETS) && !defined(AIX_31)
34 #define termstruct termios
35 #else
36 #define termstruct termio
37 #endif
38 #endif /* POSIX_TYPES */
39 #ifdef LINUX
40 #include <sys/ioctl.h>
41 #undef delay_output /* curses redefines this */
42 #include <curses.h>
43 #endif
44 #define kill_sym c_cc[VKILL]
45 #define erase_sym c_cc[VERASE]
46 #define intr_sym c_cc[VINTR]
47 #ifdef TAB3 /* not a POSIX flag, but some have it anyway */
48 #define EXTABS TAB3
49 #else
50 #define EXTABS 0
51 #endif
52 #define tabflgs c_oflag
53 #define echoflgs c_lflag
54 #define cbrkflgs c_lflag
55 #define CBRKMASK ICANON
56 #define CBRKON !/* reverse condition */
57 #ifdef POSIX_TYPES
58 #define OSPEED(x) (speednum(cfgetospeed(&x)))
59 #else
60 #ifndef CBAUD
61 #define CBAUD _CBAUD /* for POSIX nitpickers (like RS/6000 cc) */
62 #endif
63 #define OSPEED(x) ((x).c_cflag & CBAUD)
64 #endif
65 #define IS_7BIT(x) ((x).c_cflag & CS7)
66 #define inputflags c_iflag
67 #define STRIPHI ISTRIP
68 #ifdef POSIX_TYPES
69 #define GTTY(x) (tcgetattr(0, x))
70 #define STTY(x) (tcsetattr(0, TCSADRAIN, x))
71 #else
72 #if defined(TCSETS) && !defined(AIX_31)
73 #define GTTY(x) (ioctl(0, TCGETS, x))
74 #define STTY(x) (ioctl(0, TCSETSW, x))
75 #else
76 #define GTTY(x) (ioctl(0, TCGETA, x))
77 #define STTY(x) (ioctl(0, TCSETAW, x))
78 #endif
79 #endif /* POSIX_TYPES */
80 #define GTTY2(x) 1
81 #define STTY2(x) 1
82 #ifdef POSIX_TYPES
83 #if defined(BSD) && !defined(__DGUX__)
84 #define nonesuch _POSIX_VDISABLE
85 #else
86 #define nonesuch (fpathconf(0, _PC_VDISABLE))
87 #endif
88 #else
89 #define nonesuch 0
90 #endif
91 #define inittyb2 inittyb
92 #define curttyb2 curttyb
93
94 #else /* V7 */
95
96 #include <sgtty.h>
97 #define termstruct sgttyb
98 #define kill_sym sg_kill
99 #define erase_sym sg_erase
100 #define intr_sym t_intrc
101 #define EXTABS XTABS
102 #define tabflgs sg_flags
103 #define echoflgs sg_flags
104 #define cbrkflgs sg_flags
105 #define CBRKMASK CBREAK
106 #define CBRKON              /* empty */
107 #define inputflags sg_flags /* don't know how enabling meta bits */
108 #define IS_7BIT(x) (FALSE)
109 #define STRIPHI 0 /* should actually be done on BSD */
110 #define OSPEED(x) (x).sg_ospeed
111 #if defined(bsdi) || defined(__386BSD) || defined(SUNOS4)
112 #define GTTY(x) (ioctl(0, TIOCGETP, (char *) x))
113 #define STTY(x) (ioctl(0, TIOCSETP, (char *) x))
114 #else
115 #define GTTY(x) (gtty(0, x))
116 #define STTY(x) (stty(0, x))
117 #endif
118 #define GTTY2(x) (ioctl(0, TIOCGETC, (char *) x))
119 #define STTY2(x) (ioctl(0, TIOCSETC, (char *) x))
120 #define nonesuch -1
121 struct tchars inittyb2, curttyb2;
122
123 #endif /* V7 */
124
125 #if defined(TTY_GRAPHICS) && ((!defined(SYSV) && !defined(HPUX)) \
126                               || defined(UNIXPC) || defined(SVR4))
127 #ifndef LINT
128 extern /* it is defined in libtermlib (libtermcap) */
129 #endif
130     short ospeed; /* terminal baudrate; set by gettty */
131 #else
132 short ospeed = 0; /* gets around "not defined" error message */
133 #endif
134
135 #if defined(POSIX_TYPES) && defined(BSD)
136 unsigned
137 #endif
138     char erase_char,
139     intr_char, kill_char;
140 static boolean settty_needed = FALSE;
141 struct termstruct inittyb, curttyb;
142
143 #ifdef POSIX_TYPES
144 static int
145 speednum(speed)
146 speed_t speed;
147 {
148     switch (speed) {
149     case B0:
150         return 0;
151     case B50:
152         return 1;
153     case B75:
154         return 2;
155     case B110:
156         return 3;
157     case B134:
158         return 4;
159     case B150:
160         return 5;
161     case B200:
162         return 6;
163     case B300:
164         return 7;
165     case B600:
166         return 8;
167     case B1200:
168         return 9;
169     case B1800:
170         return 10;
171     case B2400:
172         return 11;
173     case B4800:
174         return 12;
175     case B9600:
176         return 13;
177     case B19200:
178         return 14;
179     case B38400:
180         return 15;
181     }
182
183     return 0;
184 }
185 #endif
186
187 static void
188 setctty()
189 {
190     if (STTY(&curttyb) < 0 || STTY2(&curttyb2) < 0)
191         perror("NetHack (setctty)");
192 }
193
194 /*
195  * Get initial state of terminal, set ospeed (for termcap routines)
196  * and switch off tab expansion if necessary.
197  * Called by startup() in termcap.c and after returning from ! or ^Z
198  */
199 void
200 gettty()
201 {
202     if (GTTY(&inittyb) < 0 || GTTY2(&inittyb2) < 0)
203         perror("NetHack (gettty)");
204     curttyb = inittyb;
205     curttyb2 = inittyb2;
206     ospeed = OSPEED(inittyb);
207     erase_char = inittyb.erase_sym;
208     kill_char = inittyb.kill_sym;
209     intr_char = inittyb2.intr_sym;
210     getioctls();
211
212     /* do not expand tabs - they might be needed inside a cm sequence */
213     if (curttyb.tabflgs & EXTABS) {
214         curttyb.tabflgs &= ~EXTABS;
215         setctty();
216     }
217     settty_needed = TRUE;
218 }
219
220 /* reset terminal to original state */
221 void
222 settty(s)
223 const char *s;
224 {
225     end_screen();
226     if (s)
227         raw_print(s);
228     if (STTY(&inittyb) < 0 || STTY2(&inittyb2) < 0)
229         perror("NetHack (settty)");
230     iflags.echo = (inittyb.echoflgs & ECHO) ? ON : OFF;
231     iflags.cbreak = (CBRKON(inittyb.cbrkflgs & CBRKMASK)) ? ON : OFF;
232     curttyb.inputflags |= STRIPHI;
233     setioctls();
234 }
235
236 void
237 setftty()
238 {
239     unsigned ef, cf;
240     int change = 0;
241
242     ef = 0;                /* desired value of flags & ECHO */
243     cf = CBRKON(CBRKMASK); /* desired value of flags & CBREAK */
244     iflags.cbreak = ON;
245     iflags.echo = OFF;
246     /* Should use (ECHO|CRMOD) here instead of ECHO */
247     if ((unsigned) (curttyb.echoflgs & ECHO) != ef) {
248         curttyb.echoflgs &= ~ECHO;
249         /*              curttyb.echoflgs |= ef; */
250         change++;
251     }
252     if ((unsigned) (curttyb.cbrkflgs & CBRKMASK) != cf) {
253         curttyb.cbrkflgs &= ~CBRKMASK;
254         curttyb.cbrkflgs |= cf;
255 #ifdef USG
256         /* be satisfied with one character; no timeout */
257         curttyb.c_cc[VMIN] = 1;  /* was VEOF */
258         curttyb.c_cc[VTIME] = 0; /* was VEOL */
259 #ifdef POSIX_JOB_CONTROL
260 /* turn off system suspend character
261  * due to differences in structure layout, this has to be
262  * here instead of in ioctl.c:getioctls() with the BSD
263  * equivalent
264  */
265 #ifdef VSUSP /* real POSIX */
266         curttyb.c_cc[VSUSP] = nonesuch;
267 #else /* other later SYSV */
268         curttyb.c_cc[VSWTCH] = nonesuch;
269 #endif
270 #endif
271 #ifdef VDSUSP /* SunOS Posix extensions */
272         curttyb.c_cc[VDSUSP] = nonesuch;
273 #endif
274 #ifdef VREPRINT
275         curttyb.c_cc[VREPRINT] = nonesuch;
276 #endif
277 #ifdef VDISCARD
278         curttyb.c_cc[VDISCARD] = nonesuch;
279 #endif
280 #ifdef VWERASE
281         curttyb.c_cc[VWERASE] = nonesuch;
282 #endif
283 #ifdef VLNEXT
284         curttyb.c_cc[VLNEXT] = nonesuch;
285 #endif
286 #endif
287         change++;
288     }
289     if (!IS_7BIT(inittyb))
290         curttyb.inputflags &= ~STRIPHI;
291     /* If an interrupt character is used, it will be overridden and
292      * set to ^C.
293      */
294     if (intr_char != nonesuch && curttyb2.intr_sym != '\003') {
295         curttyb2.intr_sym = '\003';
296         change++;
297     }
298
299     if (change)
300         setctty();
301     start_screen();
302 }
303
304 void intron() /* enable kbd interupts if enabled when game started */
305 {
306 #ifdef TTY_GRAPHICS
307     /* Ugly hack to keep from changing tty modes for non-tty games -dlc */
308     if (!strcmp(windowprocs.name, "tty") && intr_char != nonesuch
309         && curttyb2.intr_sym != '\003') {
310         curttyb2.intr_sym = '\003';
311         setctty();
312     }
313 #endif
314 }
315
316 void introff() /* disable kbd interrupts if required*/
317 {
318 #ifdef TTY_GRAPHICS
319     /* Ugly hack to keep from changing tty modes for non-tty games -dlc */
320     if (!strcmp(windowprocs.name, "tty") && curttyb2.intr_sym != nonesuch) {
321         curttyb2.intr_sym = nonesuch;
322         setctty();
323     }
324 #endif
325 }
326
327 #ifdef _M_UNIX /* SCO UNIX (3.2.4), from Andreas Arens */
328 #include <sys/console.h>
329
330 #define BSIZE (E_TABSZ * 2)
331 #define LDIOC ('D' << 8) /* POSIX prevents definition */
332
333 #include <sys/emap.h>
334
335 int sco_flag_console = 0;
336 int sco_map_valid = -1;
337 unsigned char sco_chanmap_buf[BSIZE];
338
339 void NDECL(sco_mapon);
340 void NDECL(sco_mapoff);
341 void NDECL(check_sco_console);
342 void NDECL(init_sco_cons);
343
344 void
345 sco_mapon()
346 {
347 #ifdef TTY_GRAPHICS
348     if (!strcmp(windowprocs.name, "tty") && sco_flag_console) {
349         if (sco_map_valid != -1) {
350             ioctl(0, LDSMAP, sco_chanmap_buf);
351         }
352         sco_map_valid = -1;
353     }
354 #endif
355 }
356
357 void
358 sco_mapoff()
359 {
360 #ifdef TTY_GRAPHICS
361     if (!strcmp(windowprocs.name, "tty") && sco_flag_console) {
362         sco_map_valid = ioctl(0, LDGMAP, sco_chanmap_buf);
363         if (sco_map_valid != -1) {
364             ioctl(0, LDNMAP, (char *) 0);
365         }
366     }
367 #endif
368 }
369
370 void
371 check_sco_console()
372 {
373     if (isatty(0) && ioctl(0, CONS_GET, 0) != -1) {
374         sco_flag_console = 1;
375     }
376 }
377
378 void
379 init_sco_cons()
380 {
381 #ifdef TTY_GRAPHICS
382     if (!strcmp(windowprocs.name, "tty") && sco_flag_console) {
383         atexit(sco_mapon);
384         sco_mapoff();
385         load_symset("IBMGraphics", PRIMARY);
386         load_symset("RogueIBM", ROGUESET);
387         switch_symbols(TRUE);
388 #ifdef TEXTCOLOR
389         if (has_colors())
390             iflags.use_color = TRUE;
391 #endif
392     }
393 #endif
394 }
395 #endif /* _M_UNIX */
396
397 #ifdef __linux__ /* via Jesse Thilo and Ben Gertzfield */
398 #include <sys/vt.h>
399 #include <sys/ioctl.h>
400
401 int linux_flag_console = 0;
402
403 void NDECL(linux_mapon);
404 void NDECL(linux_mapoff);
405 void NDECL(check_linux_console);
406 void NDECL(init_linux_cons);
407
408 void
409 linux_mapon()
410 {
411 #ifdef TTY_GRAPHICS
412     if (!strcmp(windowprocs.name, "tty") && linux_flag_console) {
413 _pragma_ignore(-Wunused-result)
414         write(1, "\033(B", 3);
415 _pragma_pop
416     }
417 #endif
418 }
419
420 void
421 linux_mapoff()
422 {
423 #ifdef TTY_GRAPHICS
424     if (!strcmp(windowprocs.name, "tty") && linux_flag_console) {
425 _pragma_ignore(-Wunused-result)
426         write(1, "\033(U", 3);
427 _pragma_pop
428     }
429 #endif
430 }
431
432 void
433 check_linux_console()
434 {
435     struct vt_mode vtm;
436
437     if (isatty(0) && ioctl(0, VT_GETMODE, &vtm) >= 0) {
438         linux_flag_console = 1;
439     }
440 }
441
442 void
443 init_linux_cons()
444 {
445 #ifdef TTY_GRAPHICS
446     if (!strcmp(windowprocs.name, "tty") && linux_flag_console) {
447         atexit(linux_mapon);
448         linux_mapoff();
449 #ifdef TEXTCOLOR
450         if (has_colors())
451             iflags.use_color = TRUE;
452 #endif
453     }
454 #endif
455 }
456 #endif /* __linux__ */
457
458 #ifndef __begui__ /* the Be GUI will define its own error proc */
459 /* fatal error */
460 /*VARARGS1*/
461 void error
462 VA_DECL(const char *, s)
463 {
464     VA_START(s);
465     VA_INIT(s, const char *);
466     if (settty_needed)
467         settty((char *) 0);
468     Vprintf(s, VA_ARGS);
469     (void) putchar('\n');
470     VA_END();
471     exit(EXIT_FAILURE);
472 }
473 #endif /* !__begui__ */