ncurses 6.2 - patch 20211018
[ncurses.git] / test / test_getstr.c
1 /****************************************************************************
2  * Copyright 2020 Thomas E. Dickey                                          *
3  * Copyright 2007-2012,2017 Free Software Foundation, Inc.                  *
4  *                                                                          *
5  * Permission is hereby granted, free of charge, to any person obtaining a  *
6  * copy of this software and associated documentation files (the            *
7  * "Software"), to deal in the Software without restriction, including      *
8  * without limitation the rights to use, copy, modify, merge, publish,      *
9  * distribute, distribute with modifications, sublicense, and/or sell       *
10  * copies of the Software, and to permit persons to whom the Software is    *
11  * furnished to do so, subject to the following conditions:                 *
12  *                                                                          *
13  * The above copyright notice and this permission notice shall be included  *
14  * in all copies or substantial portions of the Software.                   *
15  *                                                                          *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
17  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
18  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
19  * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
20  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
21  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
22  * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
23  *                                                                          *
24  * Except as contained in this notice, the name(s) of the above copyright   *
25  * holders shall not be used in advertising or otherwise to promote the     *
26  * sale, use or other dealings in this Software without prior written       *
27  * authorization.                                                           *
28  ****************************************************************************/
29 /*
30  * $Id: test_getstr.c,v 1.14 2020/02/02 23:34:34 tom Exp $
31  *
32  * Author: Thomas E Dickey
33  *
34  * Demonstrate the getstr functions from the curses library.
35
36        int getstr(char *str);
37        int getnstr(char *str, int n);
38        int wgetstr(WINDOW *win, char *str);
39        int wgetnstr(WINDOW *win, char *str, int n);
40        int mvgetstr(int y, int x, char *str);
41        int mvwgetstr(WINDOW *win, int y, int x, char *str);
42        int mvgetnstr(int y, int x, char *str, int n);
43        int mvwgetnstr(WINDOW *, int y, int x, char *str, int n);
44  */
45
46 #include <test.priv.h>
47 #include <popup_msg.h>
48
49 #if HAVE_CHGAT
50 /* Solaris SVr4 curses lacks wchgat, mvgetnstr, mvwgetnstr */
51
52 #define BASE_Y 6
53 #define MAX_COLS 1024
54
55 typedef enum {
56     eGetStr = 0,
57     eGetNStr,
58     eMvGetStr,
59     eMvGetNStr,
60     eMaxFlavor
61 } Flavors;
62
63 /*
64  * Return-code is OK/ERR or a keyname.
65  */
66 static const char *
67 ok_keyname(int code)
68 {
69     return ((code == OK) ? "OK" : ((code == ERR) ? "ERR" : keyname(code)));
70 }
71
72 static bool
73 Quit(int ch)
74 {
75     return (ch == ERR || ch == 'q' || ch == QUIT || ch == ESCAPE);
76 }
77
78 static int
79 Remainder(WINDOW *txtwin)
80 {
81     int result = getmaxx(txtwin) - getcurx(txtwin);
82     return (result > 0) ? result : 0;
83 }
84
85 /*
86  * Show a highlighted line in the place where input will happen.
87  */
88 static void
89 ShowPrompt(WINDOW *txtwin, int limit)
90 {
91     wchgat(txtwin, limit, WA_REVERSE, 0, NULL);
92     wnoutrefresh(txtwin);
93 }
94
95 static void
96 MovePrompt(WINDOW *txtwin, int limit, int y, int x)
97 {
98     wchgat(txtwin, Remainder(txtwin), WA_NORMAL, 0, NULL);
99     wmove(txtwin, y, x);
100     ShowPrompt(txtwin, limit);
101 }
102
103 static int
104 ShowFlavor(WINDOW *strwin, WINDOW *txtwin, int flavor, int limit)
105 {
106     const char *name = "?";
107     bool limited = FALSE;
108     bool wins = (txtwin != stdscr);
109     int result;
110
111     switch (flavor) {
112     case eGetStr:
113         name = wins ? "wgetstr" : "getstr";
114         break;
115     case eGetNStr:
116         limited = TRUE;
117         name = wins ? "wgetnstr" : "getnstr";
118         break;
119     case eMvGetStr:
120         name = wins ? "mvwgetstr" : "mvgetstr";
121         break;
122     case eMvGetNStr:
123         limited = TRUE;
124         name = wins ? "mvwgetnstr" : "mvgetnstr";
125         break;
126     case eMaxFlavor:
127         break;
128     }
129
130     wmove(strwin, 0, 0);
131     werase(strwin);
132
133     if (limited) {
134         wprintw(strwin, "%s(%d):", name, limit);
135     } else {
136         wprintw(strwin, "%s:", name);
137     }
138     result = limited ? limit : Remainder(txtwin);
139     ShowPrompt(txtwin, result);
140
141     wnoutrefresh(strwin);
142     return result;
143 }
144
145 static int
146 recursive_test(int level, char **argv, WINDOW *strwin)
147 {
148     static const char *help[] =
149     {
150         "Commands:",
151         "  q,^Q,ESC       - quit this program",
152         "  ^Q,ESC         - quit help-screen",
153         "",
154         "  p,<Up>         - move beginning of prompt one up row",
155         "  j,<Down>       - move beginning of prompt one down row",
156         "  h,<Left>       - move beginning of prompt one left column",
157         "  l,<Right>      - move beginning of prompt one right column",
158         "",
159         "  -              - reduce getnstr buffer-size one column",
160         "  +              - increase getnstr buffer-size one column",
161         "  :              - prompt for input-text",
162         "",
163         "  <              - scroll \"left\" through getstr-functions",
164         "  >              - scroll \"right\" through getstr-functions",
165         "",
166         "  w              - recur to subwindow",
167         "  ?,<F1>         - show help-screen",
168         0
169     };
170     WINDOW *txtbox = 0;
171     WINDOW *txtwin = 0;
172     FILE *fp;
173     int ch;
174     int rc;
175     int txt_x = 0, txt_y = 0;
176     int base_y;
177     int flavor = 0;
178     int limit = getmaxx(strwin) - 5;
179     int actual;
180
181     char buffer[MAX_COLS];
182
183     if (argv[level] == 0) {
184         beep();
185         return FALSE;
186     }
187
188     if (level > 1) {
189         txtbox = newwin(LINES - BASE_Y, COLS - level, BASE_Y, level);
190         box(txtbox, 0, 0);
191         wnoutrefresh(txtbox);
192
193         txtwin = derwin(txtbox,
194                         getmaxy(txtbox) - 2,
195                         getmaxx(txtbox) - 2,
196                         1, 1);
197         base_y = 0;
198     } else {
199         txtwin = stdscr;
200         base_y = BASE_Y;
201     }
202
203     keypad(txtwin, TRUE);       /* enable keyboard mapping */
204     (void) cbreak();            /* take input chars one at a time, no wait for \n */
205     (void) noecho();            /* don't echo input */
206
207     txt_y = base_y;
208     txt_x = 0;
209     wmove(txtwin, txt_y, txt_x);
210
211     if ((fp = fopen(argv[level], "r")) != 0) {
212         while ((ch = fgetc(fp)) != EOF) {
213             if (waddch(txtwin, UChar(ch)) != OK) {
214                 break;
215             }
216         }
217         fclose(fp);
218     } else {
219         wprintw(txtwin, "Cannot open:\n%s", argv[1]);
220     }
221
222     wmove(txtwin, txt_y, txt_x);
223     actual = ShowFlavor(strwin, txtwin, flavor, limit);
224     while (!Quit(ch = mvwgetch(txtwin, txt_y, txt_x))) {
225         switch (ch) {
226         case KEY_DOWN:
227         case 'j':
228             if (txt_y < getmaxy(txtwin) - 1) {
229                 MovePrompt(txtwin, actual, ++txt_y, txt_x);
230             } else {
231                 beep();
232             }
233             break;
234         case KEY_UP:
235         case 'k':
236             if (txt_y > base_y) {
237                 MovePrompt(txtwin, actual, --txt_y, txt_x);
238             } else {
239                 beep();
240             }
241             break;
242         case KEY_LEFT:
243         case 'h':
244             if (txt_x > 0) {
245                 MovePrompt(txtwin, actual, txt_y, --txt_x);
246             } else {
247                 beep();
248             }
249             break;
250         case KEY_RIGHT:
251         case 'l':
252             if (txt_x < getmaxx(txtwin) - 1) {
253                 MovePrompt(txtwin, actual, txt_y, ++txt_x);
254             } else {
255                 beep();
256             }
257             break;
258
259         case 'w':
260             recursive_test(level + 1, argv, strwin);
261             if (txtbox != 0) {
262                 touchwin(txtbox);
263                 wnoutrefresh(txtbox);
264             } else {
265                 touchwin(txtwin);
266                 wnoutrefresh(txtwin);
267             }
268             break;
269
270         case '-':
271             if (limit > 0) {
272                 actual = ShowFlavor(strwin, txtwin, flavor, --limit);
273                 MovePrompt(txtwin, actual, txt_y, txt_x);
274             } else {
275                 beep();
276             }
277             break;
278
279         case '+':
280             actual = ShowFlavor(strwin, txtwin, flavor, ++limit);
281             MovePrompt(txtwin, actual, txt_y, txt_x);
282             break;
283
284         case '<':
285             if (flavor > 0) {
286                 actual = ShowFlavor(strwin, txtwin, --flavor, limit);
287                 MovePrompt(txtwin, actual, txt_y, txt_x);
288             } else {
289                 beep();
290             }
291             break;
292
293         case '>':
294             if (flavor + 1 < eMaxFlavor) {
295                 actual = ShowFlavor(strwin, txtwin, ++flavor, limit);
296                 MovePrompt(txtwin, actual, txt_y, txt_x);
297             } else {
298                 beep();
299             }
300             break;
301
302         case ':':
303             actual = ShowFlavor(strwin, txtwin, flavor, limit);
304             *buffer = '\0';
305             rc = ERR;
306             echo();
307             (void) wattrset(txtwin, A_REVERSE);
308             switch (flavor) {
309             case eGetStr:
310                 if (txtwin != stdscr) {
311                     wmove(txtwin, txt_y, txt_x);
312                     rc = wgetstr(txtwin, buffer);
313                 } else {
314                     move(txt_y, txt_x);
315                     rc = getstr(buffer);
316                 }
317                 break;
318             case eGetNStr:
319                 if (txtwin != stdscr) {
320                     wmove(txtwin, txt_y, txt_x);
321                     rc = wgetnstr(txtwin, buffer, limit);
322                 } else {
323                     move(txt_y, txt_x);
324                     rc = getnstr(buffer, limit);
325                 }
326                 break;
327             case eMvGetStr:
328                 if (txtwin != stdscr) {
329                     rc = mvwgetstr(txtwin, txt_y, txt_x, buffer);
330                 } else {
331                     rc = mvgetstr(txt_y, txt_x, buffer);
332                 }
333                 break;
334             case eMvGetNStr:
335                 if (txtwin != stdscr) {
336                     rc = mvwgetnstr(txtwin, txt_y, txt_x, buffer, limit);
337                 } else {
338                     rc = mvgetnstr(txt_y, txt_x, buffer, limit);
339                 }
340                 break;
341             case eMaxFlavor:
342                 break;
343             }
344             noecho();
345             (void) wattrset(txtwin, A_NORMAL);
346             wprintw(strwin, "%s:%s", ok_keyname(rc), buffer);
347             wnoutrefresh(strwin);
348             break;
349         case HELP_KEY_1:
350             popup_msg(stdscr, help);
351             break;
352         default:
353             beep();
354             break;
355         }
356         doupdate();
357     }
358     if (level > 1) {
359         delwin(txtwin);
360         delwin(txtbox);
361     }
362     return TRUE;
363 }
364
365 int
366 main(int argc, char *argv[])
367 {
368     WINDOW *chrbox;
369     WINDOW *strwin;
370
371     setlocale(LC_ALL, "");
372
373     if (argc < 2) {
374         fprintf(stderr, "usage: %s file\n", argv[0]);
375         return EXIT_FAILURE;
376     }
377
378     initscr();
379
380     chrbox = derwin(stdscr, BASE_Y, COLS, 0, 0);
381     box(chrbox, 0, 0);
382     wnoutrefresh(chrbox);
383
384     strwin = derwin(chrbox, 4, COLS - 2, 1, 1);
385
386     recursive_test(1, argv, strwin);
387
388     endwin();
389     ExitProgram(EXIT_SUCCESS);
390 }
391
392 #else
393 int
394 main(void)
395 {
396     printf("This program requires the curses chgat function\n");
397     ExitProgram(EXIT_FAILURE);
398 }
399 #endif