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