1 /*        $NetBSD: io.c,v 1.14 2009/08/31 08:27:16 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 
26 static void catchalarm(int) __dead;
27 
28 void
getstring(char * cp,int mx)29 getstring(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 
78 void
more(int where)79 more(int where)
80 {
81           mvaddstr(where, 0, "-- more --");
82           getanswer(" ", FALSE);
83 }
84 
85 double
infloat(void)86 infloat(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 
98 int
inputoption(void)99 inputoption(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 
114 void
interrupt(void)115 interrupt(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 
170 int
getanswer(const char * choices,phbool def)171 getanswer(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 
253 static void
catchalarm(int dummy __unused)254 catchalarm(int dummy __unused)
255 {
256           longjmp(Timeoenv, 1);
257 }
258