1 /* NetHack 3.6	getline.c	$NHDT-Date: 1543830347 2018/12/03 09:45:47 $  $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.37 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /*-Copyright (c) Michael Allison, 2006. */
4 /* NetHack may be freely redistributed.  See license for details. */
5 
6 #include "hack.h"
7 
8 #ifdef TTY_GRAPHICS
9 
10 #if !defined(MAC)
11 #define NEWAUTOCOMP
12 #endif
13 
14 #include "wintty.h"
15 #include "func_tab.h"
16 
17 char morc = 0; /* tell the outside world what char you chose */
18 STATIC_VAR boolean suppress_history;
19 STATIC_DCL boolean FDECL(ext_cmd_getlin_hook, (char *));
20 
21 typedef boolean FDECL((*getlin_hook_proc), (char *));
22 
23 STATIC_DCL void FDECL(hooked_tty_getlin,
24                       (const char *, char *, getlin_hook_proc));
25 extern int NDECL(extcmd_via_menu); /* cmd.c */
26 
27 extern char erase_char, kill_char; /* from appropriate tty.c file */
28 
29 /*
30  * Read a line closed with '\n' into the array char bufp[BUFSZ].
31  * (The '\n' is not stored. The string is closed with a '\0'.)
32  * Reading can be interrupted by an escape ('\033') - now the
33  * resulting string is "\033".
34  */
35 void
tty_getlin(query,bufp)36 tty_getlin(query, bufp)
37 const char *query;
38 register char *bufp;
39 {
40     suppress_history = FALSE;
41     hooked_tty_getlin(query, bufp, (getlin_hook_proc) 0);
42 }
43 
44 STATIC_OVL void
hooked_tty_getlin(query,bufp,hook)45 hooked_tty_getlin(query, bufp, hook)
46 const char *query;
47 register char *bufp;
48 getlin_hook_proc hook;
49 {
50     register char *obufp = bufp;
51     register int c;
52     struct WinDesc *cw = wins[WIN_MESSAGE];
53     boolean doprev = 0;
54 
55     if (ttyDisplay->toplin == 1 && !(cw->flags & WIN_STOP))
56         more();
57     cw->flags &= ~WIN_STOP;
58     ttyDisplay->toplin = 3; /* special prompt state */
59     ttyDisplay->inread++;
60 
61     /* issue the prompt */
62     custompline(OVERRIDE_MSGTYPE | SUPPRESS_HISTORY, "%s ", query);
63 #ifdef EDIT_GETLIN
64     /* bufp is input/output; treat current contents (presumed to be from
65        previous getlin()) as default input */
66     addtopl(obufp);
67     bufp = eos(obufp);
68 #else
69     /* !EDIT_GETLIN: bufp is output only; init it to empty */
70     *bufp = '\0';
71 #endif
72 
73     for (;;) {
74         (void) fflush(stdout);
75         Strcat(strcat(strcpy(toplines, query), " "), obufp);
76         c = pgetchar();
77         if (c == '\033' || c == EOF) {
78             if (c == '\033' && obufp[0] != '\0') {
79                 obufp[0] = '\0';
80                 bufp = obufp;
81                 tty_clear_nhwindow(WIN_MESSAGE);
82                 cw->maxcol = cw->maxrow;
83                 addtopl(query);
84                 addtopl(" ");
85                 addtopl(obufp);
86             } else {
87                 obufp[0] = '\033';
88                 obufp[1] = '\0';
89                 break;
90             }
91         }
92         if (ttyDisplay->intr) {
93             ttyDisplay->intr--;
94             *bufp = 0;
95         }
96         if (c == '\020') { /* ctrl-P */
97             if (iflags.prevmsg_window != 's') {
98                 int sav = ttyDisplay->inread;
99 
100                 ttyDisplay->inread = 0;
101                 (void) tty_doprev_message();
102                 ttyDisplay->inread = sav;
103                 tty_clear_nhwindow(WIN_MESSAGE);
104                 cw->maxcol = cw->maxrow;
105                 addtopl(query);
106                 addtopl(" ");
107                 *bufp = 0;
108                 addtopl(obufp);
109             } else {
110                 if (!doprev)
111                     (void) tty_doprev_message(); /* need two initially */
112                 (void) tty_doprev_message();
113                 doprev = 1;
114                 continue;
115             }
116         } else if (doprev && iflags.prevmsg_window == 's') {
117             tty_clear_nhwindow(WIN_MESSAGE);
118             cw->maxcol = cw->maxrow;
119             doprev = 0;
120             addtopl(query);
121             addtopl(" ");
122             *bufp = 0;
123             addtopl(obufp);
124         }
125         if (c == erase_char || c == '\b') {
126             if (bufp != obufp) {
127 #ifdef NEWAUTOCOMP
128                 char *i;
129 
130 #endif /* NEWAUTOCOMP */
131                 bufp--;
132 #ifndef NEWAUTOCOMP
133                 putsyms("\b \b"); /* putsym converts \b */
134 #else                             /* NEWAUTOCOMP */
135                 putsyms("\b");
136                 for (i = bufp; *i; ++i)
137                     putsyms(" ");
138                 for (; i > bufp; --i)
139                     putsyms("\b");
140                 *bufp = 0;
141 #endif                            /* NEWAUTOCOMP */
142             } else
143                 tty_nhbell();
144         } else if (c == '\n' || c == '\r') {
145 #ifndef NEWAUTOCOMP
146             *bufp = 0;
147 #endif /* not NEWAUTOCOMP */
148             break;
149         } else if (' ' <= (unsigned char) c && c != '\177'
150                    /* avoid isprint() - some people don't have it
151                       ' ' is not always a printing char */
152                    && (bufp - obufp < BUFSZ - 1 && bufp - obufp < COLNO)) {
153 #ifdef NEWAUTOCOMP
154             char *i = eos(bufp);
155 
156 #endif /* NEWAUTOCOMP */
157             *bufp = c;
158             bufp[1] = 0;
159             putsyms(bufp);
160             bufp++;
161             if (hook && (*hook)(obufp)) {
162                 putsyms(bufp);
163 #ifndef NEWAUTOCOMP
164                 bufp = eos(bufp);
165 #else  /* NEWAUTOCOMP */
166                 /* pointer and cursor left where they were */
167                 for (i = bufp; *i; ++i)
168                     putsyms("\b");
169             } else if (i > bufp) {
170                 char *s = i;
171 
172                 /* erase rest of prior guess */
173                 for (; i > bufp; --i)
174                     putsyms(" ");
175                 for (; s > bufp; --s)
176                     putsyms("\b");
177 #endif /* NEWAUTOCOMP */
178             }
179         } else if (c == kill_char || c == '\177') { /* Robert Viduya */
180             /* this test last - @ might be the kill_char */
181 #ifndef NEWAUTOCOMP
182             while (bufp != obufp) {
183                 bufp--;
184                 putsyms("\b \b");
185             }
186 #else  /* NEWAUTOCOMP */
187             for (; *bufp; ++bufp)
188                 putsyms(" ");
189             for (; bufp != obufp; --bufp)
190                 putsyms("\b \b");
191             *bufp = 0;
192 #endif /* NEWAUTOCOMP */
193         } else
194             tty_nhbell();
195     }
196     ttyDisplay->toplin = 2; /* nonempty, no --More-- required */
197     ttyDisplay->inread--;
198     clear_nhwindow(WIN_MESSAGE); /* clean up after ourselves */
199 
200     if (suppress_history) {
201         /* prevent next message from pushing current query+answer into
202            tty message history */
203         *toplines = '\0';
204 #ifdef DUMPLOG
205     } else {
206         /* needed because we've bypassed pline() */
207         dumplogmsg(toplines);
208 #endif
209     }
210 }
211 
212 void
xwaitforspace(s)213 xwaitforspace(s)
214 register const char *s; /* chars allowed besides return */
215 {
216     register int c, x = ttyDisplay ? (int) ttyDisplay->dismiss_more : '\n';
217 
218     morc = 0;
219     while (
220 #ifdef HANGUPHANDLING
221         !program_state.done_hup &&
222 #endif
223         (c = tty_nhgetch()) != EOF) {
224         if (c == '\n' || c == '\r')
225             break;
226 
227         if (iflags.cbreak) {
228             if (c == '\033') {
229                 if (ttyDisplay)
230                     ttyDisplay->dismiss_more = 1;
231                 morc = '\033';
232                 break;
233             }
234             if ((s && index(s, c)) || c == x || (x == '\n' && c == '\r')) {
235                 morc = (char) c;
236                 break;
237             }
238             tty_nhbell();
239         }
240     }
241 }
242 
243 /*
244  * Implement extended command completion by using this hook into
245  * tty_getlin.  Check the characters already typed, if they uniquely
246  * identify an extended command, expand the string to the whole
247  * command.
248  *
249  * Return TRUE if we've extended the string at base.  Otherwise return FALSE.
250  * Assumptions:
251  *
252  *	+ we don't change the characters that are already in base
253  *	+ base has enough room to hold our string
254  */
255 STATIC_OVL boolean
ext_cmd_getlin_hook(base)256 ext_cmd_getlin_hook(base)
257 char *base;
258 {
259     int oindex, com_index;
260 
261     com_index = -1;
262     for (oindex = 0; extcmdlist[oindex].ef_txt != (char *) 0; oindex++) {
263         if (extcmdlist[oindex].flags & CMD_NOT_AVAILABLE)
264             continue;
265         if ((extcmdlist[oindex].flags & AUTOCOMPLETE)
266             && !(!wizard && (extcmdlist[oindex].flags & WIZMODECMD))
267             && !strncmpi(base, extcmdlist[oindex].ef_txt, strlen(base))) {
268             if (com_index == -1) /* no matches yet */
269                 com_index = oindex;
270             else /* more than 1 match */
271                 return FALSE;
272         }
273     }
274     if (com_index >= 0) {
275         Strcpy(base, extcmdlist[com_index].ef_txt);
276         return TRUE;
277     }
278 
279     return FALSE; /* didn't match anything */
280 }
281 
282 /*
283  * Read in an extended command, doing command line completion.  We
284  * stop when we have found enough characters to make a unique command.
285  */
286 int
tty_get_ext_cmd()287 tty_get_ext_cmd()
288 {
289     int i;
290     char buf[BUFSZ];
291 
292     if (iflags.extmenu)
293         return extcmd_via_menu();
294 
295     suppress_history = TRUE;
296     /* maybe a runtime option?
297      * hooked_tty_getlin("#", buf,
298      *                   (flags.cmd_comp && !in_doagain)
299      *                      ? ext_cmd_getlin_hook
300      *                      : (getlin_hook_proc) 0);
301      */
302     buf[0] = '\0';
303     hooked_tty_getlin("#", buf, in_doagain ? (getlin_hook_proc) 0
304                                            : ext_cmd_getlin_hook);
305     (void) mungspaces(buf);
306     if (buf[0] == 0 || buf[0] == '\033')
307         return -1;
308 
309     for (i = 0; extcmdlist[i].ef_txt != (char *) 0; i++)
310         if (!strcmpi(buf, extcmdlist[i].ef_txt))
311             break;
312 
313     if (!in_doagain) {
314         int j;
315         for (j = 0; buf[j]; j++)
316             savech(buf[j]);
317         savech('\n');
318     }
319 
320     if (extcmdlist[i].ef_txt == (char *) 0) {
321         pline("%s: unknown extended command.", buf);
322         i = -1;
323     }
324 
325     return i;
326 }
327 
328 #endif /* TTY_GRAPHICS */
329 
330 /*getline.c*/
331