Cast sentinel for execl*() to (char *) to quiet gcc4 warnings.
[games.git] / games / phantasia / io.c
CommitLineData
984263bc
MD
1/*
2 * io.c - input/output routines for Phantasia
3 *
4 * $FreeBSD: src/games/phantasia/io.c,v 1.6 1999/11/16 02:57:33 billf Exp $
313fa7d1 5 * $DragonFly: src/games/phantasia/io.c,v 1.3 2005/05/31 00:06:26 swildner Exp $
984263bc
MD
6 */
7
8#include <string.h>
9#include "include.h"
10
313fa7d1
SW
11/* functions which we need to know about */
12/* misc.c */
13extern void death(const char *);
14extern void leavegame(void);
15/* phantglobs.c */
16extern double drandom(void);
17
18void getstring(char *, int);
19void more(int);
20double infloat(void);
21int inputoption(void);
22void interrupt(void);
23int getanswer(const char *, bool);
24void catchalarm(void);
25
984263bc
MD
26/************************************************************************
27/
28/ FUNCTION NAME: getstring()
29/
30/ FUNCTION: read a string from operator
31/
32/ AUTHOR: E. A. Estes, 12/4/85
33/
34/ ARGUMENTS:
35/ char *cp - pointer to buffer area to fill
36/ int mx - maximum number of characters to put in buffer
37/
38/ RETURN VALUE: none
39/
40/ MODULES CALLED: wmove(), _filbuf(), clearok(), waddstr(), wrefresh(),
41/ wclrtoeol()
42/
43/ GLOBAL INPUTS: Echo, _iob[], Wizard, *stdscr
44/
45/ GLOBAL OUTPUTS: _iob[]
46/
47/ DESCRIPTION:
48/ Read a string from the keyboard.
49/ This routine is specially designed to:
50/
51/ - strip non-printing characters (unless Wizard)
52/ - echo, if desired
53/ - redraw the screen if CH_REDRAW is entered
54/ - read in only 'mx - 1' characters or less characters
55/ - nul-terminate string, and throw away newline
56/
57/ 'mx' is assumed to be at least 2.
58/
59*************************************************************************/
60
313fa7d1
SW
61void
62getstring(char *cp, int mx)
984263bc
MD
63{
64char *inptr; /* pointer into string for next string */
65int x, y; /* original x, y coordinates on screen */
66int ch; /* input */
67
68 getyx(stdscr, y, x); /* get coordinates on screen */
69 inptr = cp;
70 *inptr = '\0'; /* clear string to start */
71 --mx; /* reserve room in string for nul terminator */
72
73 do
74 /* get characters and process */
75 {
76 if (Echo)
77 mvaddstr(y, x, cp); /* print string on screen */
78 clrtoeol(); /* clear any data after string */
79 refresh(); /* update screen */
80
81 ch = getchar(); /* get character */
82
83 switch (ch)
84 {
85 case CH_ERASE: /* back up one character */
86 if (inptr > cp)
87 --inptr;
88 break;
89
90 case CH_KILL: /* back up to original location */
91 inptr = cp;
92 break;
93
94 case CH_NEWLINE: /* terminate string */
95 break;
96
97 case CH_REDRAW: /* redraw screen */
98 clearok(stdscr, TRUE);
99 continue;
100
101 default: /* put data in string */
102 if (ch >= ' ' || Wizard)
103 /* printing char; put in string */
104 *inptr++ = ch;
105 }
106
107 *inptr = '\0'; /* terminate string */
108 }
109 while (ch != CH_NEWLINE && inptr < cp + mx);
110}
111/*\f*/
112/************************************************************************
113/
114/ FUNCTION NAME: more()
115/
116/ FUNCTION: pause and prompt player
117/
118/ AUTHOR: E. A. Estes, 12/4/85
119/
120/ ARGUMENTS:
121/ int where - line on screen on which to pause
122/
123/ RETURN VALUE: none
124/
125/ MODULES CALLED: wmove(), waddstr(), getanswer()
126/
127/ GLOBAL INPUTS: *stdscr
128/
129/ GLOBAL OUTPUTS: none
130/
131/ DESCRIPTION:
132/ Print a message, and wait for a space character.
133/
134*************************************************************************/
135
313fa7d1
SW
136void
137more(int where)
984263bc
MD
138{
139 mvaddstr(where, 0, "-- more --");
140 getanswer(" ", FALSE);
141}
142/*\f*/
143/************************************************************************
144/
145/ FUNCTION NAME: infloat()
146/
147/ FUNCTION: input a floating point number from operator
148/
149/ AUTHOR: E. A. Estes, 12/4/85
150/
151/ ARGUMENTS: none
152/
153/ RETURN VALUE: floating point number from operator
154/
155/ MODULES CALLED: sscanf(), getstring()
156/
157/ GLOBAL INPUTS: Databuf[]
158/
159/ GLOBAL OUTPUTS: none
160/
161/ DESCRIPTION:
162/ Read a string from player, and scan for a floating point
163/ number.
164/ If no valid number is found, return 0.0.
165/
166*************************************************************************/
167
168double
313fa7d1 169infloat(void)
984263bc
MD
170{
171double result; /* return value */
172
173 getstring(Databuf, SZ_DATABUF);
174 if (sscanf(Databuf, "%lf", &result) < 1)
175 /* no valid number entered */
176 result = 0.0;
177
178 return(result);
179}
180/*\f*/
181/************************************************************************
182/
183/ FUNCTION NAME: inputoption()
184/
185/ FUNCTION: input an option value from player
186/
187/ AUTHOR: E. A. Estes, 12/4/85
188/
189/ ARGUMENTS: none
190/
191/ RETURN VALUE: none
192/
193/ MODULES CALLED: floor(), drandom(), getanswer()
194/
195/ GLOBAL INPUTS: Player
196/
197/ GLOBAL OUTPUTS: Player
198/
199/ DESCRIPTION:
200/ Age increases with every move.
201/ Refresh screen, and get a single character option from player.
202/ Return a random value if player's ring has gone bad.
203/
204*************************************************************************/
205
313fa7d1
SW
206int
207inputoption(void)
984263bc
MD
208{
209 ++Player.p_age; /* increase age */
210
211 if (Player.p_ring.ring_type != R_SPOILED)
212 /* ring ok */
213 return(getanswer("T ", TRUE));
214 else
215 /* bad ring */
216 {
217 getanswer(" ", TRUE);
218 return((int) ROLL(0.0, 5.0) + '0');
219 }
220}
221/*\f*/
222/************************************************************************
223/
224/ FUNCTION NAME: interrupt()
225/
226/ FUNCTION: handle interrupt from operator
227/
228/ AUTHOR: E. A. Estes, 12/4/85
229/
230/ ARGUMENTS: none
231/
232/ RETURN VALUE: none
233/
234/ MODULES CALLED: fork(), exit(), wait(), death(), alarm(), execl(), wmove(),
235/ getgid(), signal(), getenv(), wclear(), setuid(), getuid(), setgid(),
236/ crmode(), clearok(), waddstr(), cleanup(), wrefresh(), leavegame(),
237/ getanswer()
238/
239/ GLOBAL INPUTS: Player, *stdscr
240/
241/ GLOBAL OUTPUTS: none
242/
243/ DESCRIPTION:
244/ Allow player to quit upon hitting the interrupt key.
245/ If the player wants to quit while in battle, he/she automatically
246/ dies.
247/
248*************************************************************************/
249
313fa7d1
SW
250void
251interrupt(void)
984263bc
MD
252{
253char line[81]; /* a place to store data already on screen */
254int loop; /* counter */
255int x, y; /* coordinates on screen */
256int ch; /* input */
257unsigned savealarm; /* to save alarm value */
258
259#ifdef SYS3
260 signal(SIGINT, SIG_IGN);
261#endif
262#ifdef SYS5
263 signal(SIGINT, SIG_IGN);
264#endif
265
266 savealarm = alarm(0); /* turn off any alarms */
267
268 getyx(stdscr, y, x); /* save cursor location */
269
270 for (loop = 0; loop < 80; ++loop) /* save line on screen */
271 {
272 move(4, loop);
273 line[loop] = inch();
274 }
275 line[80] = '\0'; /* nul terminate */
276
277 if (Player.p_status == S_INBATTLE || Player.p_status == S_MONSTER)
278 /* in midst of fighting */
279 {
280 mvaddstr(4, 0, "Quitting now will automatically kill your character. Still want to ? ");
281 ch = getanswer("NY", FALSE);
282 if (ch == 'Y')
283 death("Bailing out");
284 /*NOTREACHED*/
285 }
286 else
287 {
288 mvaddstr(4, 0, "Do you really want to quit ? ");
289 ch = getanswer("NY", FALSE);
290 if (ch == 'Y')
291 leavegame();
292 /*NOTREACHED*/
293 }
294
295 mvaddstr(4, 0, line); /* restore data on screen */
296 move(y, x); /* restore cursor */
297 refresh();
298
299#ifdef SYS3
300 signal(SIGINT, interrupt);
301#endif
302#ifdef SYS5
303 signal(SIGINT, interrupt);
304#endif
305
306 alarm(savealarm); /* restore alarm */
307}
308/*\f*/
309/************************************************************************
310/
311/ FUNCTION NAME: getanswer()
312/
313/ FUNCTION: get an answer from operator
314/
315/ AUTHOR: E. A. Estes, 12/4/85
316/
317/ ARGUMENTS:
318/ char *choices - string of (upper case) valid choices
319/ bool def - set if default answer
320/
321/ RETURN VALUE: none
322/
323/ MODULES CALLED: alarm(), wmove(), waddch(), signal(), setjmp(), strchr(),
324/ _filbuf(), clearok(), toupper(), wrefresh(), mvprintw(), wclrtoeol()
325/
326/ GLOBAL INPUTS: catchalarm(), Echo, _iob[], _ctype[], *stdscr, Timeout,
327/ Timeoenv[]
328/
329/ GLOBAL OUTPUTS: _iob[]
330/
331/ DESCRIPTION:
332/ Get a single character answer from operator.
333/ Timeout waiting for response. If we timeout, or the
334/ answer in not in the list of valid choices, print choices,
335/ and wait again, otherwise return the first character in ths
336/ list of choices.
337/ Give up after 3 tries.
338/
339*************************************************************************/
340
313fa7d1
SW
341int
342getanswer(const char *choices, bool def)
984263bc
MD
343{
344int ch; /* input */
313fa7d1
SW
345volatile int loop; /* counter */
346volatile int oldx, oldy; /* original coordinates on screen */
984263bc
MD
347
348 getyx(stdscr, oldy, oldx);
349 alarm(0); /* make sure alarm is off */
350
351 for (loop = 3; loop; --loop)
352 /* try for 3 times */
353 {
354 if (setjmp(Timeoenv) != 0)
355 /* timed out waiting for response */
356 {
357 if (def || loop <= 1)
358 /* return default answer */
359 break;
360 else
361 /* prompt, and try again */
362 goto YELL;
363 }
364 else
365 /* wait for response */
366 {
367 clrtoeol();
368 refresh();
369#ifdef BSD41
370 sigset(SIGALRM, catchalarm);
371#else
313fa7d1 372 signal(SIGALRM, (sig_t)catchalarm);
984263bc
MD
373#endif
374 /* set timeout */
375 if (Timeout)
376 alarm(7); /* short */
377 else
378 alarm(600); /* long */
379
380 ch = getchar();
381
382 alarm(0); /* turn off timeout */
383
384 if (ch < 0)
385 /* caught some signal */
386 {
387 ++loop;
388 continue;
389 }
390 else if (ch == CH_REDRAW)
391 /* redraw screen */
392 {
393 clearok(stdscr, TRUE); /* force clear screen */
394 ++loop; /* don't count this input */
395 continue;
396 }
397 else if (Echo)
398 {
399 addch(ch); /* echo character */
400 refresh();
401 }
402
403 if (islower(ch))
404 /* convert to upper case */
405 ch = toupper(ch);
406
407 if (def || strchr(choices, ch) != NULL)
408 /* valid choice */
409 return(ch);
410 else if (!def && loop > 1)
411 /* bad choice; prompt, and try again */
412 {
413YELL: mvprintw(oldy + 1, 0, "Please choose one of : [%s]\n", choices);
414 move(oldy, oldx);
415 clrtoeol();
416 continue;
417 }
418 else
419 /* return default answer */
420 break;
421 }
422 }
423
424 return(*choices);
425}
426/*\f*/
427/************************************************************************
428/
429/ FUNCTION NAME: catchalarm()
430/
431/ FUNCTION: catch timer when waiting for input
432/
433/ AUTHOR: E. A. Estes, 12/4/85
434/
435/ ARGUMENTS: none
436/
437/ RETURN VALUE: none
438/
439/ MODULES CALLED: longjmp()
440/
441/ GLOBAL INPUTS: Timeoenv[]
442/
443/ GLOBAL OUTPUTS: none
444/
445/ DESCRIPTION:
446/ Come here when the alarm expires while waiting for input.
447/ Simply longjmp() into getanswer().
448/
449*************************************************************************/
450
451void
313fa7d1 452catchalarm(void)
984263bc
MD
453{
454 longjmp(Timeoenv, 1);
455}