blob: b106ffc7d4626f3f3af64df12a86f14d0150b4e6 [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 2002-2016,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: inserts.c,v 1.34 2022/12/10 22:28:50 tom Exp $
Steve Kondikae271bc2015-11-15 02:50:53 +010031 *
32 * Demonstrate the winsstr() and winsch functions.
33 * Thomas Dickey - 2002/10/19
34 */
35
36#include <test.priv.h>
37
38#if HAVE_WINSSTR
39
40#include <linedata.h>
41
42#define InsNStr insnstr
43#define InsStr insstr
44#define MvInsNStr (void) mvinsnstr
45#define MvInsStr (void) mvinsstr
46#define MvWInsNStr (void) mvwinsnstr
47#define MvWInsStr (void) mvwinsstr
48#define WInsNStr winsnstr
49#define WInsStr winsstr
50
51#define InsCh insch
52#define MvInsCh (void) mvinsch
53#define MvWInsCh (void) mvwinsch
54#define WInsCh winsch
55
56#define MY_TABSIZE 8
57
58typedef enum {
59 oDefault = 0,
60 oMove = 1,
61 oWindow = 2,
62 oMoveWindow = 3
63} Options;
64
65static bool m_opt = FALSE;
66static bool w_opt = FALSE;
67static int n_opt = -1;
68
69static void
70legend(WINDOW *win, int level, Options state, char *buffer, int length)
71{
72 const char *showstate;
73
74 switch (state) {
75 default:
76 case oDefault:
77 showstate = "";
78 break;
79 case oMove:
80 showstate = " (mvXXX)";
81 break;
82 case oWindow:
83 showstate = " (winXXX)";
84 break;
85 case oMoveWindow:
86 showstate = " (mvwinXXX)";
87 break;
88 }
89
90 wmove(win, 0, 0);
91 wprintw(win,
92 "The Strings/Chars displays should match. Enter any characters, except:\n");
93 wprintw(win,
94 "down-arrow or ^N to repeat on next line, ^W for inner window, ESC to exit.\n");
95 wclrtoeol(win);
96 wprintw(win, "Level %d,%s inserted %d characters <%s>", level,
97 showstate, length, buffer);
98}
99
100static int
101ColOf(char *buffer, int length, int margin)
102{
103 int n;
104 int result;
105
106 for (n = 0, result = margin + 1; n < length; ++n) {
107 int ch = UChar(buffer[n]);
108 switch (ch) {
109 case '\n':
110 /* actually newline should clear the remainder of the line
111 * and move to the next line - but that seems a little awkward
112 * in this example.
113 */
114 case '\r':
115 result = 0;
116 break;
117 case '\b':
118 if (result > 0)
119 --result;
120 break;
121 case '\t':
122 result += (MY_TABSIZE - (result % MY_TABSIZE));
123 break;
124 case '\177':
125 result += 2;
126 break;
127 default:
128 ++result;
129 if (ch < 32)
130 ++result;
131 break;
132 }
133 }
134 return result;
135}
136
137#define LEN(n) ((length - (n) > n_opt) ? n_opt : (length - (n)))
138static void
139test_inserts(int level)
140{
141 static bool first = TRUE;
142
143 int ch;
144 int limit;
145 int row = 1;
146 int col;
147 int row2, col2;
148 int length;
149 char buffer[BUFSIZ];
150 WINDOW *look = 0;
151 WINDOW *work = 0;
152 WINDOW *show = 0;
153 int margin = (2 * MY_TABSIZE) - 1;
154 Options option = (Options) ((unsigned) (m_opt
155 ? oMove
156 : oDefault)
157 | (unsigned) ((w_opt || (level > 0))
158 ? oWindow
159 : oDefault));
160
161 if (first) {
162 static char cmd[80];
163 setlocale(LC_ALL, "");
164
micky3879b9f5e72025-07-08 18:04:53 -0400165 _nc_STRCPY(cmd, "TABSIZE=8", sizeof(cmd));
166 putenv(cmd);
Steve Kondikae271bc2015-11-15 02:50:53 +0100167
168 initscr();
169 (void) cbreak(); /* take input chars one at a time, no wait for \n */
170 (void) noecho(); /* don't echo input */
171 keypad(stdscr, TRUE);
172
173 /*
174 * Show the characters inserted in color, to distinguish from those
175 * that are shifted.
176 */
177 if (has_colors()) {
178 start_color();
179 init_pair(1, COLOR_WHITE, COLOR_BLUE);
180 }
181 }
182
183 limit = LINES - 5;
184 if (level > 0) {
185 look = newwin(limit, COLS - (2 * (level - 1)), 0, level - 1);
186 work = newwin(limit - 2, COLS - (2 * level), 1, level);
187 show = newwin(4, COLS, limit + 1, 0);
188 box(look, 0, 0);
189 wnoutrefresh(look);
190 limit -= 2;
191 } else {
192 work = stdscr;
193 show = derwin(stdscr, 4, COLS, limit + 1, 0);
194 }
195 keypad(work, TRUE);
196
197 for (col = margin + 1; col < COLS; col += MY_TABSIZE)
198 MvWVLine(work, row, col, '.', limit - 2);
199
200 MvWVLine(work, row, margin, ACS_VLINE, limit - 2);
201 MvWVLine(work, row, margin + 1, ACS_VLINE, limit - 2);
202 limit /= 2;
203
204 MvWAddStr(work, 1, 2, "String");
205 MvWAddStr(work, limit + 1, 2, "Chars");
206 wnoutrefresh(work);
207
208 buffer[length = 0] = '\0';
209 legend(show, level, option, buffer, length);
210 wnoutrefresh(show);
211
212 doupdate();
213
214 if (has_colors()) {
215 wbkgdset(work, (chtype) (COLOR_PAIR(1) | ' '));
216 }
217
218 while ((ch = read_linedata(work)) != ERR && !isQUIT(ch)) {
219 wmove(work, row, margin + 1);
220 switch (ch) {
221 case key_RECUR:
222 test_inserts(level + 1);
223
224 if (look)
225 touchwin(look);
226 touchwin(work);
227 touchwin(show);
228
229 if (look)
230 wnoutrefresh(look);
231 wnoutrefresh(work);
232 wnoutrefresh(show);
233
234 doupdate();
235 break;
236 case key_NEWLINE:
237 if (row < limit) {
238 ++row;
239 /* put the whole string in, all at once */
240 col2 = margin + 1;
241 switch (option) {
242 case oDefault:
243 if (n_opt > 1) {
244 for (col = 0; col < length; col += n_opt) {
245 col2 = ColOf(buffer, col, margin);
246 if (move(row, col2) != ERR) {
247 InsNStr(buffer + col, LEN(col));
248 }
249 }
250 } else {
251 if (move(row, col2) != ERR) {
252 InsStr(buffer);
253 }
254 }
255 break;
256 case oMove:
257 if (n_opt > 1) {
258 for (col = 0; col < length; col += n_opt) {
259 col2 = ColOf(buffer, col, margin);
260 MvInsNStr(row, col2, buffer + col, LEN(col));
261 }
262 } else {
263 MvInsStr(row, col2, buffer);
264 }
265 break;
266 case oWindow:
267 if (n_opt > 1) {
268 for (col = 0; col < length; col += n_opt) {
269 col2 = ColOf(buffer, col, margin);
270 if (wmove(work, row, col2) != ERR) {
271 WInsNStr(work, buffer + col, LEN(col));
272 }
273 }
274 } else {
275 if (wmove(work, row, col2) != ERR) {
276 WInsStr(work, buffer);
277 }
278 }
279 break;
280 case oMoveWindow:
281 if (n_opt > 1) {
282 for (col = 0; col < length; col += n_opt) {
283 col2 = ColOf(buffer, col, margin);
284 MvWInsNStr(work, row, col2, buffer + col, LEN(col));
285 }
286 } else {
287 MvWInsStr(work, row, col2, buffer);
288 }
289 break;
290 }
291
292 /* do the corresponding single-character insertion */
293 row2 = limit + row;
294 for (col = 0; col < length; ++col) {
295 col2 = ColOf(buffer, col, margin);
296 switch (option) {
297 case oDefault:
298 if (move(row2, col2) != ERR) {
299 InsCh(UChar(buffer[col]));
300 }
301 break;
302 case oMove:
303 MvInsCh(row2, col2, UChar(buffer[col]));
304 break;
305 case oWindow:
306 if (wmove(work, row2, col2) != ERR) {
307 WInsCh(work, UChar(buffer[col]));
308 }
309 break;
310 case oMoveWindow:
311 MvWInsCh(work, row2, col2, UChar(buffer[col]));
312 break;
313 }
314 }
315 } else {
316 beep();
317 }
318 break;
319 default:
320 if (ch <= 0 || ch > 255) {
321 beep();
322 break;
323 }
micky3879b9f5e72025-07-08 18:04:53 -0400324 if (length >= BUFSIZ - 2)
325 break;
Steve Kondikae271bc2015-11-15 02:50:53 +0100326 buffer[length++] = (char) ch;
327 buffer[length] = '\0';
328
329 /* put the string in, one character at a time */
330 col = ColOf(buffer, length - 1, margin);
331 switch (option) {
332 case oDefault:
333 if (move(row, col) != ERR) {
334 InsStr(buffer + length - 1);
335 }
336 break;
337 case oMove:
338 MvInsStr(row, col, buffer + length - 1);
339 break;
340 case oWindow:
341 if (wmove(work, row, col) != ERR) {
342 WInsStr(work, buffer + length - 1);
343 }
344 break;
345 case oMoveWindow:
346 MvWInsStr(work, row, col, buffer + length - 1);
347 break;
348 }
349
350 /* do the corresponding single-character insertion */
351 switch (option) {
352 case oDefault:
353 if (move(limit + row, col) != ERR) {
354 InsCh(UChar(ch));
355 }
356 break;
357 case oMove:
358 MvInsCh(limit + row, col, UChar(ch));
359 break;
360 case oWindow:
361 if (wmove(work, limit + row, col) != ERR) {
362 WInsCh(work, UChar(ch));
363 }
364 break;
365 case oMoveWindow:
366 MvWInsCh(work, limit + row, col, UChar(ch));
367 break;
368 }
369
370 wnoutrefresh(work);
371
372 legend(show, level, option, buffer, length);
373 wnoutrefresh(show);
374
375 doupdate();
376 break;
377 }
378 }
379 if (level > 0) {
380 delwin(work);
381 delwin(look);
382 }
383 delwin(show);
384}
385
386static void
micky3879b9f5e72025-07-08 18:04:53 -0400387usage(int ok)
Steve Kondikae271bc2015-11-15 02:50:53 +0100388{
389 static const char *tbl[] =
390 {
391 "Usage: inserts [options]"
392 ,""
micky3879b9f5e72025-07-08 18:04:53 -0400393 ,USAGE_COMMON
Steve Kondikae271bc2015-11-15 02:50:53 +0100394 ,"Options:"
micky3879b9f5e72025-07-08 18:04:53 -0400395 ," -f FILE read data from given file"
396 ," -n NUM limit string-inserts to NUM bytes on ^N replay"
397 ," -m perform wmove/move separately from insert-functions"
398 ," -w use window-parameter even when stdscr would be implied"
Steve Kondikae271bc2015-11-15 02:50:53 +0100399 };
400 unsigned n;
401 for (n = 0; n < SIZEOF(tbl); ++n)
402 fprintf(stderr, "%s\n", tbl[n]);
micky3879b9f5e72025-07-08 18:04:53 -0400403 ExitProgram(ok ? EXIT_SUCCESS : EXIT_FAILURE);
Steve Kondikae271bc2015-11-15 02:50:53 +0100404}
micky3879b9f5e72025-07-08 18:04:53 -0400405/* *INDENT-OFF* */
406VERSION_COMMON()
407/* *INDENT-ON* */
Steve Kondikae271bc2015-11-15 02:50:53 +0100408
409int
micky3879b9f5e72025-07-08 18:04:53 -0400410main(int argc, char *argv[])
Steve Kondikae271bc2015-11-15 02:50:53 +0100411{
412 int ch;
413
414 setlocale(LC_ALL, "");
415
micky3879b9f5e72025-07-08 18:04:53 -0400416 while ((ch = getopt(argc, argv, OPTS_COMMON "f:mn:w")) != -1) {
Steve Kondikae271bc2015-11-15 02:50:53 +0100417 switch (ch) {
418 case 'f':
419 init_linedata(optarg);
420 break;
421 case 'm':
422 m_opt = TRUE;
423 break;
424 case 'n':
425 n_opt = atoi(optarg);
426 if (n_opt == 0)
427 n_opt = -1;
428 break;
429 case 'w':
430 w_opt = TRUE;
431 break;
micky3879b9f5e72025-07-08 18:04:53 -0400432 case OPTS_VERSION:
433 show_version(argv);
434 ExitProgram(EXIT_SUCCESS);
Steve Kondikae271bc2015-11-15 02:50:53 +0100435 default:
micky3879b9f5e72025-07-08 18:04:53 -0400436 usage(ch == OPTS_USAGE);
437 /* NOTREACHED */
Steve Kondikae271bc2015-11-15 02:50:53 +0100438 }
439 }
440 if (optind < argc)
micky3879b9f5e72025-07-08 18:04:53 -0400441 usage(FALSE);
Steve Kondikae271bc2015-11-15 02:50:53 +0100442
443 test_inserts(0);
444 endwin();
445 ExitProgram(EXIT_SUCCESS);
446}
447#else
448int
449main(void)
450{
451 printf("This program requires the winsstr function\n");
452 ExitProgram(EXIT_FAILURE);
453}
454#endif /* HAVE_WINSSTR */