blob: dbc0a0a271ed57b91b88c8db05e00cc1973098fb [file] [log] [blame]
Steve Kondikae271bc2015-11-15 02:50:53 +01001/****************************************************************************
micky3879b9f5e72025-07-08 18:04:53 -04002 * Copyright 2020,2022 Thomas E. Dickey *
3 * Copyright 2007-2012,2017 Free Software Foundation, Inc. *
Steve Kondikae271bc2015-11-15 02:50:53 +01004 * *
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/*
micky3879b9f5e72025-07-08 18:04:53 -040030 * $Id: test_getstr.c,v 1.16 2022/12/10 23:58:37 tom Exp $
Steve Kondikae271bc2015-11-15 02:50:53 +010031 *
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>
micky3879b9f5e72025-07-08 18:04:53 -040047#include <popup_msg.h>
Steve Kondikae271bc2015-11-15 02:50:53 +010048
49#if HAVE_CHGAT
50/* Solaris SVr4 curses lacks wchgat, mvgetnstr, mvwgetnstr */
51
52#define BASE_Y 6
53#define MAX_COLS 1024
54
55typedef 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 */
66static const char *
67ok_keyname(int code)
68{
69 return ((code == OK) ? "OK" : ((code == ERR) ? "ERR" : keyname(code)));
70}
71
72static bool
73Quit(int ch)
74{
75 return (ch == ERR || ch == 'q' || ch == QUIT || ch == ESCAPE);
76}
77
78static int
79Remainder(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 */
88static void
89ShowPrompt(WINDOW *txtwin, int limit)
90{
micky3879b9f5e72025-07-08 18:04:53 -040091 wchgat(txtwin, limit, WA_REVERSE, 0, NULL);
Steve Kondikae271bc2015-11-15 02:50:53 +010092 wnoutrefresh(txtwin);
93}
94
95static void
96MovePrompt(WINDOW *txtwin, int limit, int y, int x)
97{
micky3879b9f5e72025-07-08 18:04:53 -040098 wchgat(txtwin, Remainder(txtwin), WA_NORMAL, 0, NULL);
Steve Kondikae271bc2015-11-15 02:50:53 +010099 wmove(txtwin, y, x);
100 ShowPrompt(txtwin, limit);
101}
102
103static int
104ShowFlavor(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
145static int
micky3879b9f5e72025-07-08 18:04:53 -0400146recursive_test(int level, char **argv, WINDOW *strwin)
Steve Kondikae271bc2015-11-15 02:50:53 +0100147{
micky3879b9f5e72025-07-08 18:04:53 -0400148 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 };
Steve Kondikae271bc2015-11-15 02:50:53 +0100170 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':
micky3879b9f5e72025-07-08 18:04:53 -0400260 recursive_test(level + 1, argv, strwin);
Steve Kondikae271bc2015-11-15 02:50:53 +0100261 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;
micky3879b9f5e72025-07-08 18:04:53 -0400349 case HELP_KEY_1:
350 popup_msg(stdscr, help);
351 break;
Steve Kondikae271bc2015-11-15 02:50:53 +0100352 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
micky3879b9f5e72025-07-08 18:04:53 -0400365static void
366usage(int ok)
367{
368 static const char *msg[] =
369 {
370 "Usage: test_getstr [options] [file1 [...]]"
371 ,""
372 ,USAGE_COMMON
373 };
374 size_t n;
375
376 for (n = 0; n < SIZEOF(msg); n++)
377 fprintf(stderr, "%s\n", msg[n]);
378
379 ExitProgram(ok ? EXIT_SUCCESS : EXIT_FAILURE);
380}
381/* *INDENT-OFF* */
382VERSION_COMMON()
383/* *INDENT-ON* */
384
Steve Kondikae271bc2015-11-15 02:50:53 +0100385int
386main(int argc, char *argv[])
387{
388 WINDOW *chrbox;
389 WINDOW *strwin;
micky3879b9f5e72025-07-08 18:04:53 -0400390 int ch;
391
392 while ((ch = getopt(argc, argv, OPTS_COMMON)) != -1) {
393 switch (ch) {
394 case OPTS_VERSION:
395 show_version(argv);
396 ExitProgram(EXIT_SUCCESS);
397 default:
398 usage(ch == OPTS_USAGE);
399 /* NOTREACHED */
400 }
401 }
Steve Kondikae271bc2015-11-15 02:50:53 +0100402
403 setlocale(LC_ALL, "");
404
micky3879b9f5e72025-07-08 18:04:53 -0400405 if (optind + 1 > argc)
406 usage(FALSE);
Steve Kondikae271bc2015-11-15 02:50:53 +0100407
408 initscr();
409
410 chrbox = derwin(stdscr, BASE_Y, COLS, 0, 0);
411 box(chrbox, 0, 0);
412 wnoutrefresh(chrbox);
413
414 strwin = derwin(chrbox, 4, COLS - 2, 1, 1);
415
micky3879b9f5e72025-07-08 18:04:53 -0400416 recursive_test(optind, argv, strwin);
Steve Kondikae271bc2015-11-15 02:50:53 +0100417
418 endwin();
419 ExitProgram(EXIT_SUCCESS);
420}
421
422#else
423int
424main(void)
425{
426 printf("This program requires the curses chgat function\n");
427 ExitProgram(EXIT_FAILURE);
428}
429#endif