ncurses 6.2 - patch 20200418
[ncurses.git] / test / inserts.c
1 /****************************************************************************
2  * Copyright 2020 Thomas E. Dickey                                          *
3  * Copyright 2002-2016,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: inserts.c,v 1.30 2020/02/02 23:34:34 tom Exp $
31  *
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
58 typedef enum {
59     oDefault = 0,
60     oMove = 1,
61     oWindow = 2,
62     oMoveWindow = 3
63 } Options;
64
65 static bool m_opt = FALSE;
66 static bool w_opt = FALSE;
67 static int n_opt = -1;
68
69 static void
70 legend(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
100 static int
101 ColOf(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)))
138 static void
139 test_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
165         _nc_STRCPY(cmd, "TABSIZE=8", sizeof(cmd));
166         putenv(cmd);
167
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             }
324             if (length >= BUFSIZ - 2)
325                 break;
326             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
386 static void
387 usage(void)
388 {
389     static const char *tbl[] =
390     {
391         "Usage: inserts [options]"
392         ,""
393         ,"Options:"
394         ,"  -f FILE read data from given file"
395         ,"  -n NUM  limit string-inserts to NUM bytes on ^N replay"
396         ,"  -m      perform wmove/move separately from insert-functions"
397         ,"  -w      use window-parameter even when stdscr would be implied"
398     };
399     unsigned n;
400     for (n = 0; n < SIZEOF(tbl); ++n)
401         fprintf(stderr, "%s\n", tbl[n]);
402     ExitProgram(EXIT_FAILURE);
403 }
404
405 int
406 main(int argc GCC_UNUSED, char *argv[]GCC_UNUSED)
407 {
408     int ch;
409
410     setlocale(LC_ALL, "");
411
412     while ((ch = getopt(argc, argv, "f:mn:w")) != -1) {
413         switch (ch) {
414         case 'f':
415             init_linedata(optarg);
416             break;
417         case 'm':
418             m_opt = TRUE;
419             break;
420         case 'n':
421             n_opt = atoi(optarg);
422             if (n_opt == 0)
423                 n_opt = -1;
424             break;
425         case 'w':
426             w_opt = TRUE;
427             break;
428         default:
429             usage();
430             break;
431         }
432     }
433     if (optind < argc)
434         usage();
435
436     test_inserts(0);
437     endwin();
438     ExitProgram(EXIT_SUCCESS);
439 }
440 #else
441 int
442 main(void)
443 {
444     printf("This program requires the winsstr function\n");
445     ExitProgram(EXIT_FAILURE);
446 }
447 #endif /* HAVE_WINSSTR */