1 | /* SCCS Id: @(#)topl.c 3.3 96/10/24 */
2 | /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 | /* NetHack may be freely redistributed. See license for details. */
4 |
5 | #include "hack.h"
6 |
7 | #ifdef TTY_GRAPHICS
8 |
9 | #include "tcap.h"
10 | #include "wintty.h"
11 | #include <ctype.h>
12 |
13 | #ifndef C /* this matches src/cmd.c */
14 | #define C(c) (0x1f & (c))
15 | #endif
16 |
17 | STATIC_DCL void FDECL(redotoplin, (const char*));
18 | STATIC_DCL void FDECL(topl_putsym, (CHAR_P));
19 | STATIC_DCL void NDECL(remember_topl);
20 | STATIC_DCL void FDECL(removetopl, (int));
21 |
22 | #ifdef OVLB
23 |
24 | int
25 | tty_doprev_message()
26 | {
27 | register struct WinDesc *cw = wins[WIN_MESSAGE];
28 |
29 | ttyDisplay->dismiss_more = C('p'); /* <ctrl/P> allowed at --More-- */
30 | do {
31 | morc = 0;
32 | if (cw->maxcol == cw->maxrow)
33 | redotoplin(toplines);
34 | else if (cw->data[cw->maxcol])
35 | redotoplin(cw->data[cw->maxcol]);
36 | cw->maxcol--;
37 | if (cw->maxcol < 0) cw->maxcol = cw->rows-1;
38 | if (!cw->data[cw->maxcol])
39 | cw->maxcol = cw->maxrow;
40 | } while (morc == C('p'));
41 | ttyDisplay->dismiss_more = 0;
42 | return 0;
43 | }
44 |
45 | #endif /* OVLB */
46 | #ifdef OVL1
47 |
48 | STATIC_OVL void
49 | redotoplin(str)
50 | const char *str;
51 | {
52 | int otoplin = ttyDisplay->toplin;
53 | home();
54 | if(*str & 0x80) {
55 | /* kludge for the / command, the only time we ever want a */
56 | /* graphics character on the top line */
57 | g_putch((int)*str++);
58 | ttyDisplay->curx++;
59 | }
60 | end_glyphout(); /* in case message printed during graphics output */
61 | putsyms(str);
62 | cl_end();
63 | ttyDisplay->toplin = 1;
64 | if(ttyDisplay->cury && otoplin != 3)
65 | more();
66 | }
67 |
68 | STATIC_OVL void
69 | remember_topl()
70 | {
71 | register struct WinDesc *cw = wins[WIN_MESSAGE];
72 | int idx = cw->maxrow;
73 | unsigned len = strlen(toplines) + 1;
74 |
75 | if (len > (unsigned)cw->datlen[idx]) {
76 | if (cw->data[idx]) free(cw->data[idx]);
77 | len += (8 - (len & 7)); /* pad up to next multiple of 8 */
78 | cw->data[idx] = (char *)alloc(len);
79 | cw->datlen[idx] = (short)len;
80 | }
81 | Strcpy(cw->data[idx], toplines);
82 | cw->maxcol = cw->maxrow = (idx + 1) % cw->rows;
83 | }
84 |
85 | void
86 | addtopl(s)
87 | const char *s;
88 | {
89 | register struct WinDesc *cw = wins[WIN_MESSAGE];
90 |
91 | tty_curs(BASE_WINDOW,cw->curx+1,cw->cury);
92 | putsyms(s);
93 | cl_end();
94 | ttyDisplay->toplin = 1;
95 | }
96 |
97 | #endif /* OVL1 */
98 | #ifdef OVL2
99 |
100 | void
101 | more()
102 | {
103 | struct WinDesc *cw = wins[WIN_MESSAGE];
104 |
105 | /* avoid recursion -- only happens from interrupts */
106 | if(ttyDisplay->inmore++)
107 | return;
108 |
109 | if(ttyDisplay->toplin) {
110 | tty_curs(BASE_WINDOW, cw->curx+1, cw->cury);
111 | if(cw->curx >= CO - 8) topl_putsym('\n');
112 | }
113 |
114 | if(flags.standout)
115 | standoutbeg();
116 | putsyms(defmorestr);
117 | if(flags.standout)
118 | standoutend();
119 |
120 | xwaitforspace("\033 ");
121 |
122 | if(morc == '\033')
123 | cw->flags |= WIN_STOP;
124 |
125 | if(ttyDisplay->toplin && cw->cury) {
126 | docorner(1, cw->cury+1);
127 | cw->curx = cw->cury = 0;
128 | home();
129 | } else if(morc == '\033') {
130 | cw->curx = cw->cury = 0;
131 | home();
132 | cl_end();
133 | }
134 | ttyDisplay->toplin = 0;
135 | ttyDisplay->inmore = 0;
136 | }
137 |
138 | void
139 | update_topl(bp)
140 | register const char *bp;
141 | {
142 | register char *tl, *otl;
143 | register int n0;
144 | int notdied = 1;
145 | struct WinDesc *cw = wins[WIN_MESSAGE];
146 |
147 | /* If there is room on the line, print message on same line */
148 | /* But messages like "You die..." deserve their own line */
149 | n0 = strlen(bp);
150 | if(ttyDisplay->toplin == 1 && cw->cury == 0 &&
151 | n0 + (int)strlen(toplines) + 3 < CO-8 && /* room for --More-- */
152 | (notdied = strncmp(bp, "You die", 7))) {
153 | Strcat(toplines, " ");
154 | Strcat(toplines, bp);
155 | cw->curx += 2;
156 | if(!(cw->flags & WIN_STOP))
157 | addtopl(bp);
158 | return;
159 | } else if(!(cw->flags & WIN_STOP)) {
160 | if(ttyDisplay->toplin == 1) more();
161 | else if(cw->cury) { /* for when flags.toplin == 2 && cury > 1 */
162 | docorner(1, cw->cury+1); /* reset cury = 0 if redraw screen */
163 | cw->curx = cw->cury = 0;/* from home--cls() & docorner(1,n) */
164 | }
165 | }
166 | remember_topl();
167 | (void) strncpy(toplines, bp, TBUFSZ);
168 | toplines[TBUFSZ - 1] = 0;
169 |
170 | for(tl = toplines; n0 >= CO; ){
171 | otl = tl;
172 | for(tl+=CO-1; tl != otl && !isspace(*tl); --tl) ;
173 | if(tl == otl) {
174 | /* Eek! A huge token. Try splitting after it. */
175 | tl = index(otl, ' ');
176 | if (!tl) break; /* No choice but to spit it out whole. */
177 | }
178 | *tl++ = '\n';
179 | n0 = strlen(tl);
180 | }
181 | if(!notdied) cw->flags &= ~WIN_STOP;
182 | if(!(cw->flags & WIN_STOP)) redotoplin(toplines);
183 | }
184 |
185 | STATIC_OVL
186 | void
187 | topl_putsym(c)
188 | char c;
189 | {
190 | register struct WinDesc *cw = wins[WIN_MESSAGE];
191 |
192 | if(cw == (struct WinDesc *) 0) panic("Putsym window MESSAGE nonexistant");
193 |
194 | switch(c) {
195 | case '\b':
196 | if(ttyDisplay->curx == 0 && ttyDisplay->cury > 0)
197 | tty_curs(BASE_WINDOW, CO, (int)ttyDisplay->cury-1);
198 | backsp();
199 | ttyDisplay->curx--;
200 | cw->curx = ttyDisplay->curx;
201 | return;
202 | case '\n':
203 | cl_end();
204 | ttyDisplay->curx = 0;
205 | ttyDisplay->cury++;
206 | cw->cury = ttyDisplay->cury;
207 | break;
208 | default:
209 | if(ttyDisplay->curx == CO-1)
210 | topl_putsym('\n'); /* 1 <= curx <= CO; avoid CO */
211 | ttyDisplay->curx++;
212 | }
213 | cw->curx = ttyDisplay->curx;
214 | if(cw->curx == 0) cl_end();
215 | (void) putchar(c);
216 | }
217 |
218 | void
219 | putsyms(str)
220 | const char *str;
221 | {
222 | while(*str)
223 | topl_putsym(*str++);
224 | }
225 |
226 | STATIC_OVL void
227 | removetopl(n)
228 | register int n;
229 | {
230 | /* assume addtopl() has been done, so ttyDisplay->toplin is already set */
231 | while (n-- > 0) putsyms("\b \b");
232 | }
233 |
234 | extern char erase_char; /* from xxxtty.c; don't need kill_char */
235 |
236 | char
237 | tty_yn_function(query,resp, def)
238 | const char *query,*resp;
239 | char def;
240 | /*
241 | * Generic yes/no function. 'def' is the default (returned by space or
242 | * return; 'esc' returns 'q', or 'n', or the default, depending on
243 | * what's in the string. The 'query' string is printed before the user
244 | * is asked about the string.
245 | * If resp is NULL, any single character is accepted and returned.
246 | * If not-NULL, only characters in it are allowed (exceptions: the
247 | * quitchars are always allowed, and if it contains '#' then digits
248 | * are allowed); if it includes an <esc>, anything beyond that won't
249 | * be shown in the prompt to the user but will be acceptable as input.
250 | */
251 | {
252 | register char q;
253 | char rtmp[40];
254 | boolean digit_ok, allow_num;
255 | struct WinDesc *cw = wins[WIN_MESSAGE];
256 | boolean doprev = 0;
257 | char prompt[QBUFSZ];
258 |
259 | if(ttyDisplay->toplin == 1 && !(cw->flags & WIN_STOP)) more();
260 | cw->flags &= ~WIN_STOP;
261 | ttyDisplay->toplin = 3; /* special prompt state */
262 | ttyDisplay->inread++;
263 | if (resp) {
264 | char *rb, respbuf[QBUFSZ];
265 |
266 | allow_num = (index(resp, '#') != 0);
267 | Strcpy(respbuf, resp);
268 | /* any acceptable responses that follow <esc> aren't displayed */
269 | if ((rb = index(respbuf, '\033')) != 0) *rb = '\0';
270 | Sprintf(prompt, "%s [%s] ", query, respbuf);
271 | if (def) Sprintf(eos(prompt), "(%c) ", def);
272 | pline("%s", prompt);
273 | } else {
274 | pline("%s ", query);
275 | q = readchar();
276 | goto clean_up;
277 | }
278 |
279 | do { /* loop until we get valid input */
280 | q = lowc(readchar());
281 | if (q == '\020') { /* ctrl-P */
282 | if(!doprev) (void) tty_doprev_message(); /* need two initially */
283 | (void) tty_doprev_message();
284 | doprev = 1;
285 | q = '\0'; /* force another loop iteration */
286 | continue;
287 | } else if (doprev) {
288 | /* BUG[?]: this probably ought to check whether the
289 | character which has just been read is an acceptable
290 | response; if so, skip the reprompt and use it. */
291 | tty_clear_nhwindow(WIN_MESSAGE);
292 | cw->maxcol = cw->maxrow;
293 | doprev = 0;
294 | addtopl(prompt);
295 | q = '\0'; /* force another loop iteration */
296 | continue;
297 | }
298 | digit_ok = allow_num && digit(q);
299 | if (q == '\033') {
300 | if (index(resp, 'q'))
301 | q = 'q';
302 | else if (index(resp, 'n'))
303 | q = 'n';
304 | else
305 | q = def;
306 | break;
307 | } else if (index(quitchars, q)) {
308 | q = def;
309 | break;
310 | }
311 | if (!index(resp, q) && !digit_ok) {
312 | tty_nhbell();
313 | q = (char)0;
314 | } else if (q == '#' || digit_ok) {
315 | char z, digit_string[2];
316 | int n_len = 0;
317 | long value = 0;
318 | addtopl("#"), n_len++;
319 | digit_string[1] = '\0';
320 | if (q != '#') {
321 | digit_string[0] = q;
322 | addtopl(digit_string), n_len++;
323 | value = q - '0';
324 | q = '#';
325 | }
326 | do { /* loop until we get a non-digit */
327 | z = lowc(readchar());
328 | if (digit(z)) {
329 | value = (10 * value) + (z - '0');
330 | if (value < 0) break; /* overflow: try again */
331 | digit_string[0] = z;
332 | addtopl(digit_string), n_len++;
333 | } else if (z == 'y' || index(quitchars, z)) {
334 | if (z == '\033') value = -1; /* abort */
335 | z = '\n'; /* break */
336 | } else if (z == erase_char || z == '\b') {
337 | if (n_len <= 1) { value = -1; break; }
338 | else { value /= 10; removetopl(1), n_len--; }
339 | } else {
340 | value = -1; /* abort */
341 | tty_nhbell();
342 | break;
343 | }
344 | } while (z != '\n');
345 | if (value > 0) yn_number = value;
346 | else if (value == 0) q = 'n'; /* 0 => "no" */
347 | else { /* remove number from top line, then try again */
348 | removetopl(n_len), n_len = 0;
349 | q = '\0';
350 | }
351 | }
352 | } while(!q);
353 |
354 | if (q != '#') {
355 | Sprintf(rtmp, "%c", q);
356 | addtopl(rtmp);
357 | }
358 | clean_up:
359 | ttyDisplay->inread--;
360 | ttyDisplay->toplin = 2;
361 | if (ttyDisplay->intr) ttyDisplay->intr--;
362 | if(wins[WIN_MESSAGE]->cury)
363 | tty_clear_nhwindow(WIN_MESSAGE);
364 |
365 | return q;
366 | }
367 |
368 | #endif /* OVL2 */
369 |
370 | #endif /* TTY_GRAPHICS */
371 |
372 | /*topl.c*/