1/*	$NetBSD: io.c,v 1.13 2009/08/12 08:21:41 dholland Exp $	*/
2
3/*
4 * io.c - input/output routines for Phantasia
5 */
6
7#include <sys/cdefs.h>
8
9#include <ctype.h>
10#include <math.h>
11#include <setjmp.h>
12#include <signal.h>
13#include <stdio.h>
14#include <string.h>
15#include <unistd.h>
16
17#include "macros.h"
18#include "phantdefs.h"
19#include "phantstruct.h"
20#include "phantglobs.h"
21//#include "pathnames.h"
22
23#undef bool
24#include <curses.h>
25
26static void catchalarm(int) __dead;
27
28void
29getstring(char *cp, int mx)
30{
31	char   *inptr;		/* pointer into string for next string */
32	int     x, y;		/* original x, y coordinates on screen */
33	int     ch;		/* input */
34
35	getyx(stdscr, y, x);	/* get coordinates on screen */
36	inptr = cp;
37	*inptr = '\0';		/* clear string to start */
38	--mx;			/* reserve room in string for nul terminator */
39
40	do
41		/* get characters and process */
42	{
43		if (Echo)
44			mvaddstr(y, x, cp);	/* print string on screen */
45		clrtoeol();	/* clear any data after string */
46		refresh();	/* update screen */
47
48		ch = getchar();	/* get character */
49
50		switch (ch) {
51		case CH_ERASE:	/* back up one character */
52			if (inptr > cp)
53				--inptr;
54			break;
55
56		case CH_KILL:	/* back up to original location */
57			inptr = cp;
58			break;
59
60		case CH_NEWLINE:	/* terminate string */
61			break;
62
63		case CH_REDRAW:/* redraw screen */
64			clearok(stdscr, TRUE);
65			continue;
66
67		default:	/* put data in string */
68			if (ch >= ' ' || Wizard)
69				/* printing char; put in string */
70				*inptr++ = ch;
71		}
72
73		*inptr = '\0';	/* terminate string */
74	}
75	while (ch != CH_NEWLINE && inptr < cp + mx);
76}
77
78void
79more(int where)
80{
81	mvaddstr(where, 0, "-- more --");
82	getanswer(" ", FALSE);
83}
84
85double
86infloat(void)
87{
88	double  result;		/* return value */
89
90	getstring(Databuf, SZ_DATABUF);
91	if (sscanf(Databuf, "%lf", &result) < 1)
92		/* no valid number entered */
93		result = 0.0;
94
95	return (result);
96}
97
98int
99inputoption(void)
100{
101	++Player.p_age;		/* increase age */
102
103	if (Player.p_ring.ring_type != R_SPOILED)
104		/* ring ok */
105		return (getanswer("T ", TRUE));
106	else
107		/* bad ring */
108	{
109		getanswer(" ", TRUE);
110		return ((int) ROLL(0.0, 5.0) + '0');
111	}
112}
113
114void
115interrupt(void)
116{
117	char    line[81];	/* a place to store data already on screen */
118	int     loop;		/* counter */
119	int     x, y;		/* coordinates on screen */
120	int     ch;		/* input */
121	unsigned savealarm;	/* to save alarm value */
122
123#ifdef SYS3
124	signal(SIGINT, SIG_IGN);
125#endif
126#ifdef SYS5
127	signal(SIGINT, SIG_IGN);
128#endif
129
130	savealarm = alarm(0);	/* turn off any alarms */
131
132	getyx(stdscr, y, x);	/* save cursor location */
133
134	for (loop = 0; loop < 80; ++loop) {	/* save line on screen */
135		move(4, loop);
136		line[loop] = inch();
137	}
138	line[80] = '\0';	/* nul terminate */
139
140	if (Player.p_status == S_INBATTLE || Player.p_status == S_MONSTER)
141		/* in midst of fighting */
142	{
143		mvaddstr(4, 0, "Quitting now will automatically kill your character.  Still want to ? ");
144		ch = getanswer("NY", FALSE);
145		if (ch == 'Y')
146			death("Bailing out");
147		/* NOTREACHED */
148	} else {
149		mvaddstr(4, 0, "Do you really want to quit ? ");
150		ch = getanswer("NY", FALSE);
151		if (ch == 'Y')
152			leavegame();
153		/* NOTREACHED */
154	}
155
156	mvaddstr(4, 0, line);	/* restore data on screen */
157	move(y, x);		/* restore cursor */
158	refresh();
159
160#ifdef SYS3
161	signal(SIGINT, interrupt);
162#endif
163#ifdef SYS5
164	signal(SIGINT, interrupt);
165#endif
166
167	alarm(savealarm);	/* restore alarm */
168}
169
170int
171getanswer(const char *choices, phbool def)
172{
173	int     ch;		/* input */
174	volatile int	loop;	/* counter */
175	volatile int	oldx, oldy;	/* original coordinates on screen */
176
177	getyx(stdscr, oldy, oldx);
178	alarm(0);		/* make sure alarm is off */
179
180	for (loop = 3; loop; --loop)
181		/* try for 3 times */
182	{
183		if (setjmp(Timeoenv) != 0)
184			/* timed out waiting for response */
185		{
186			if (def || loop <= 1)
187				/* return default answer */
188				break;
189			else
190				/* prompt, and try again */
191				goto YELL;
192		} else
193			/* wait for response */
194		{
195			clrtoeol();
196			refresh();
197#ifdef BSD41
198			sigset(SIGALRM, catchalarm);
199#else
200			signal(SIGALRM, catchalarm);
201#endif
202			/* set timeout */
203			if (Timeout)
204				alarm(7);	/* short */
205			else
206				alarm(600);	/* long */
207
208			ch = getchar();
209
210			alarm(0);	/* turn off timeout */
211
212			if (ch < 0)
213				/* caught some signal */
214			{
215				++loop;
216				continue;
217			} else
218				if (ch == CH_REDRAW)
219					/* redraw screen */
220				{
221					clearok(stdscr, TRUE);	/* force clear screen */
222					++loop;	/* don't count this input */
223					continue;
224				} else
225					if (Echo) {
226						addch(ch);	/* echo character */
227						refresh();
228					}
229			if (islower(ch))
230				/* convert to upper case */
231				ch = toupper(ch);
232
233			if (def || strchr(choices, ch) != NULL)
234				/* valid choice */
235				return (ch);
236			else
237				if (!def && loop > 1)
238					/* bad choice; prompt, and try again */
239				{
240			YELL:		mvprintw(oldy + 1, 0, "Please choose one of : [%s]\n", choices);
241					move(oldy, oldx);
242					clrtoeol();
243					continue;
244				} else
245					/* return default answer */
246					break;
247		}
248	}
249
250	return (*choices);
251}
252
253static void
254catchalarm(int dummy __unused)
255{
256	longjmp(Timeoenv, 1);
257}
258