blob: cddc31528fc4f0c3c8c81ce7a01be327d4b6a3d7 [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 2009-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: test_addchstr.c,v 1.29 2022/12/10 22:28:50 tom Exp $
Steve Kondikae271bc2015-11-15 02:50:53 +010031 *
32 * Demonstrate the waddchstr() and waddch functions.
33 * Thomas Dickey - 2009/9/12
34 */
35
36#include <test.priv.h>
Steve Kondikae271bc2015-11-15 02:50:53 +010037#include <linedata.h>
38
micky3879b9f5e72025-07-08 18:04:53 -040039/*
40 * redefinitions to simplify comparison between test_*str programs
41 */
Steve Kondikae271bc2015-11-15 02:50:53 +010042#undef MvAddStr
43#undef MvWAddStr
44
45#define AddNStr addchnstr
46#define AddStr addchstr
47#define MvAddNStr (void) mvaddchnstr
48#define MvAddStr (void) mvaddchstr
49#define MvWAddNStr (void) mvwaddchnstr
50#define MvWAddStr (void) mvwaddchstr
51#define WAddNStr waddchnstr
52#define WAddStr waddchstr
53
Steve Kondikae271bc2015-11-15 02:50:53 +010054#define MY_TABSIZE 8
55
56typedef enum {
57 oDefault = 0,
58 oMove = 1,
59 oWindow = 2,
60 oMoveWindow = 3
61} Options;
62
63static bool m_opt = FALSE;
64static bool pass_ctls = FALSE;
65static bool w_opt = FALSE;
66static int n_opt = -1;
67
micky3879b9f5e72025-07-08 18:04:53 -040068static chtype show_attr;
Steve Kondikae271bc2015-11-15 02:50:53 +010069static chtype *temp_buffer;
70static size_t temp_length;
71
72#define TempBuffer(source_cast)
73
74static size_t
75ChLen(const char *source)
76{
77 size_t result = strlen(source);
78
79 if (!pass_ctls) {
80 size_t adjust = 0;
81 size_t n;
82
83 for (n = 0; n < result; ++n) {
84 const char *s = unctrl(UChar(source[n]));
85 if (s != 0) {
86 adjust += (strlen(s) - 1);
87 }
88 }
89 result += adjust;
90 }
91 return result;
92}
93
94static chtype *
95ChStr(const char *source)
96{
97 if (source != 0) {
98 size_t need = ChLen(source) + 1;
99 int n = 0;
100
101 if (need > temp_length) {
102 temp_length = need * 2;
103 temp_buffer = typeRealloc(chtype, temp_length, temp_buffer);
104 if (!temp_buffer)
105 failed("TempBuffer");
106 }
107 do {
108 const char *s;
109 chtype ch = UChar(*source++);
110 if (!pass_ctls && (s = unctrl(ch)) != 0) {
111 while (*s != '\0') {
112 temp_buffer[n++] = UChar(*s++);
113 }
114 } else {
115 temp_buffer[n++] = ch;
116 }
117 } while (source[0] != 0);
118 temp_buffer[n] = 0;
119 } else if (temp_buffer != 0) {
120 free(temp_buffer);
121 temp_buffer = 0;
122 temp_length = 0;
123 }
124 return temp_buffer;
125}
126
127/* color the strings drawn in the workspace */
128static chtype *
129ChStr2(const char *source)
130{
131 size_t len = ChLen(source);
132 size_t n;
133 chtype *result = ChStr(source);
134 for (n = 0; n < len; ++n) {
135 result[n] |= show_attr;
136 }
137 return result;
138}
139
140static void
141legend(WINDOW *win, int level, Options state, char *buffer, int length)
142{
143 const char *showstate;
144
145 switch (state) {
146 default:
147 case oDefault:
148 showstate = "";
149 break;
150 case oMove:
151 showstate = " (mvXXX)";
152 break;
153 case oWindow:
154 showstate = " (winXXX)";
155 break;
156 case oMoveWindow:
157 showstate = " (mvwinXXX)";
158 break;
159 }
160
161 wmove(win, 0, 0);
162 wprintw(win,
163 "The Strings/Chars displays should match. Enter any characters, except:\n");
164 wprintw(win,
165 "down-arrow or ^N to repeat on next line, ^W for inner window, ESC to exit.\n");
166 wclrtoeol(win);
167 wprintw(win, "Level %d,%s added %d characters <%s>", level,
168 showstate, length, buffer);
169}
170
171static int
172ColOf(char *buffer, int length, int margin)
173{
174 int n;
175 int result;
176
177 for (n = 0, result = margin + 1; n < length; ++n) {
178 int ch = UChar(buffer[n]);
179 switch (ch) {
180 case '\n':
181 /* actually newline should clear the remainder of the line
182 * and move to the next line - but that seems a little awkward
183 * in this example.
184 */
185 case '\r':
186 result = 0;
187 break;
188 case '\b':
189 if (result > 0)
190 --result;
191 break;
192 case '\t':
193 result += (MY_TABSIZE - (result % MY_TABSIZE));
194 break;
195 case '\177':
196 result += 2;
197 break;
198 default:
199 ++result;
200 if (ch < 32)
201 ++result;
202 break;
203 }
204 }
205 return result;
206}
207
208#define LEN(n) ((length - (n) > n_opt) ? n_opt : (length - (n)))
209static void
micky3879b9f5e72025-07-08 18:04:53 -0400210recursive_test(int level)
Steve Kondikae271bc2015-11-15 02:50:53 +0100211{
212 static bool first = TRUE;
213
214 int ch;
215 int limit;
216 int row = 1;
217 int col;
218 int row2, col2;
219 int length;
220 char buffer[BUFSIZ];
221 WINDOW *look = 0;
222 WINDOW *work = 0;
223 WINDOW *show = 0;
224 int margin = (2 * MY_TABSIZE) - 1;
225 Options option = (Options) ((unsigned) (m_opt
226 ? oMove
227 : oDefault)
228 | (unsigned) ((w_opt || (level > 0))
229 ? oWindow
230 : oDefault));
231
232 if (first) {
233 static char cmd[80];
234 setlocale(LC_ALL, "");
235
micky3879b9f5e72025-07-08 18:04:53 -0400236 _nc_STRCPY(cmd, "TABSIZE=8", sizeof(cmd));
237 putenv(cmd);
Steve Kondikae271bc2015-11-15 02:50:53 +0100238
239 initscr();
240 (void) cbreak(); /* take input chars one at a time, no wait for \n */
241 (void) noecho(); /* don't echo input */
242 keypad(stdscr, TRUE);
243
244 /*
245 * Show the characters added in color, to distinguish from those that
246 * are shifted.
247 */
248 if (has_colors()) {
249 start_color();
250 init_pair(1, COLOR_WHITE, COLOR_BLUE);
251 }
252 }
253
254 limit = LINES - 5;
255 if (level > 0) {
256 look = newwin(limit, COLS - (2 * (level - 1)), 0, level - 1);
257 work = newwin(limit - 2, COLS - (2 * level), 1, level);
258 show = newwin(4, COLS, limit + 1, 0);
259 box(look, 0, 0);
260 wnoutrefresh(look);
261 limit -= 2;
262 } else {
263 work = stdscr;
264 show = derwin(stdscr, 4, COLS, limit + 1, 0);
265 }
266 keypad(work, TRUE);
267
268 for (col = margin + 1; col < COLS; col += MY_TABSIZE)
269 MvWVLine(work, row, col, '.', limit - 2);
270
271 MvWVLine(work, row, margin, ACS_VLINE, limit - 2);
272 MvWVLine(work, row, margin + 1, ACS_VLINE, limit - 2);
273 limit /= 2;
274
275 MvWAddChStr(work, 1, 2, ChStr("String"));
276 MvWAddChStr(work, limit + 1, 2, ChStr("Chars"));
277 wnoutrefresh(work);
278
279 buffer[length = 0] = '\0';
280 legend(show, level, option, buffer, length);
281 wnoutrefresh(show);
282
283 doupdate();
284
285 if (has_colors()) {
micky3879b9f5e72025-07-08 18:04:53 -0400286 show_attr = (chtype) COLOR_PAIR(1);
Steve Kondikae271bc2015-11-15 02:50:53 +0100287 wbkgdset(work, show_attr | ' ');
288 } else {
289 show_attr = A_STANDOUT;
290 }
291
292 while ((ch = read_linedata(work)) != ERR && !isQUIT(ch)) {
293 wmove(work, row, margin + 1);
294 switch (ch) {
295 case key_RECUR:
micky3879b9f5e72025-07-08 18:04:53 -0400296 recursive_test(level + 1);
Steve Kondikae271bc2015-11-15 02:50:53 +0100297
298 if (look)
299 touchwin(look);
300 touchwin(work);
301 touchwin(show);
302
303 if (look)
304 wnoutrefresh(look);
305 wnoutrefresh(work);
306 wnoutrefresh(show);
307
308 doupdate();
309 break;
310 case key_NEWLINE:
311 if (row < limit) {
312 ++row;
313 /* put the whole string in, all at once */
314 col2 = margin + 1;
315 switch (option) {
316 case oDefault:
317 if (n_opt > 1) {
318 for (col = 0; col < length; col += n_opt) {
319 col2 = ColOf(buffer, col, margin);
320 if (move(row, col2) != ERR) {
321 AddNStr(ChStr2(buffer + col), LEN(col));
322 }
323 }
324 } else {
325 if (move(row, col2) != ERR) {
326 AddStr(ChStr2(buffer));
327 }
328 }
329 break;
330 case oMove:
331 if (n_opt > 1) {
332 for (col = 0; col < length; col += n_opt) {
333 col2 = ColOf(buffer, col, margin);
334 MvAddNStr(row, col2, ChStr2(buffer + col), LEN(col));
335 }
336 } else {
337 MvAddStr(row, col2, ChStr2(buffer));
338 }
339 break;
340 case oWindow:
341 if (n_opt > 1) {
342 for (col = 0; col < length; col += n_opt) {
343 col2 = ColOf(buffer, col, margin);
344 if (wmove(work, row, col2) != ERR) {
345 WAddNStr(work, ChStr2(buffer + col), LEN(col));
346 }
347 }
348 } else {
349 if (wmove(work, row, col2) != ERR) {
350 WAddStr(work, ChStr2(buffer));
351 }
352 }
353 break;
354 case oMoveWindow:
355 if (n_opt > 1) {
356 for (col = 0; col < length; col += n_opt) {
357 col2 = ColOf(buffer, col, margin);
358 MvWAddNStr(work, row, col2, ChStr2(buffer + col),
359 LEN(col));
360 }
361 } else {
362 MvWAddStr(work, row, col2, ChStr2(buffer));
363 }
364 break;
365 }
366
367 /* do the corresponding single-character add */
368 row2 = limit + row;
369 for (col = 0; col < length; ++col) {
370 col2 = ColOf(buffer, col, margin);
371 switch (option) {
372 case oDefault:
373 if (move(row2, col2) != ERR) {
374 AddCh(UChar(buffer[col]));
375 }
376 break;
377 case oMove:
378 MvAddCh(row2, col2, UChar(buffer[col]));
379 break;
380 case oWindow:
381 if (wmove(work, row2, col2) != ERR) {
382 WAddCh(work, UChar(buffer[col]));
383 }
384 break;
385 case oMoveWindow:
386 MvWAddCh(work, row2, col2, UChar(buffer[col]));
387 break;
388 }
389 }
390 } else {
391 beep();
392 }
393 break;
394 case KEY_BACKSPACE:
395 ch = '\b';
396 /* FALLTHRU */
397 default:
398 if (ch <= 0 || ch > 255) {
399 beep();
400 break;
401 }
402 buffer[length++] = (char) ch;
403 buffer[length] = '\0';
404
405 /* put the string in, one character at a time */
406 col = ColOf(buffer, length - 1, margin);
407 switch (option) {
408 case oDefault:
409 if (move(row, col) != ERR) {
410 AddStr(ChStr2(buffer + length - 1));
411 }
412 break;
413 case oMove:
414 MvAddStr(row, col, ChStr2(buffer + length - 1));
415 break;
416 case oWindow:
417 if (wmove(work, row, col) != ERR) {
418 WAddStr(work, ChStr2(buffer + length - 1));
419 }
420 break;
421 case oMoveWindow:
422 MvWAddStr(work, row, col, ChStr2(buffer + length - 1));
423 break;
424 }
425
426 /* do the corresponding single-character add */
427 switch (option) {
428 case oDefault:
429 if (move(limit + row, col) != ERR) {
430 AddCh(UChar(ch));
431 }
432 break;
433 case oMove:
434 MvAddCh(limit + row, col, UChar(ch));
435 break;
436 case oWindow:
437 if (wmove(work, limit + row, col) != ERR) {
438 WAddCh(work, UChar(ch));
439 }
440 break;
441 case oMoveWindow:
442 MvWAddCh(work, limit + row, col, UChar(ch));
443 break;
444 }
445
446 wnoutrefresh(work);
447
448 legend(show, level, option, buffer, length);
449 wnoutrefresh(show);
450
451 doupdate();
452 break;
453 }
454 }
455 if (level > 0) {
456 delwin(work);
457 delwin(look);
458 }
459 delwin(show);
460}
461
462static void
micky3879b9f5e72025-07-08 18:04:53 -0400463usage(int ok)
Steve Kondikae271bc2015-11-15 02:50:53 +0100464{
465 static const char *tbl[] =
466 {
467 "Usage: test_addchstr [options]"
468 ,""
micky3879b9f5e72025-07-08 18:04:53 -0400469 ,USAGE_COMMON
Steve Kondikae271bc2015-11-15 02:50:53 +0100470 ,"Options:"
micky3879b9f5e72025-07-08 18:04:53 -0400471 ," -f FILE read data from given file"
472 ," -n NUM limit string-adds to NUM bytes on ^N replay"
473 ," -m perform wmove/move separately from add-functions"
474 ," -p pass-thru control characters without using unctrl()"
475 ," -w use window-parameter even when stdscr would be implied"
Steve Kondikae271bc2015-11-15 02:50:53 +0100476 };
477 unsigned n;
478 for (n = 0; n < SIZEOF(tbl); ++n)
479 fprintf(stderr, "%s\n", tbl[n]);
micky3879b9f5e72025-07-08 18:04:53 -0400480 ExitProgram(ok ? EXIT_SUCCESS : EXIT_FAILURE);
Steve Kondikae271bc2015-11-15 02:50:53 +0100481}
micky3879b9f5e72025-07-08 18:04:53 -0400482/* *INDENT-OFF* */
483VERSION_COMMON()
484/* *INDENT-ON* */
Steve Kondikae271bc2015-11-15 02:50:53 +0100485
486int
micky3879b9f5e72025-07-08 18:04:53 -0400487main(int argc, char *argv[])
Steve Kondikae271bc2015-11-15 02:50:53 +0100488{
489 int ch;
490
491 setlocale(LC_ALL, "");
492
micky3879b9f5e72025-07-08 18:04:53 -0400493 while ((ch = getopt(argc, argv, OPTS_COMMON "f:mn:pw")) != -1) {
Steve Kondikae271bc2015-11-15 02:50:53 +0100494 switch (ch) {
495 case 'f':
496 init_linedata(optarg);
497 break;
498 case 'm':
499 m_opt = TRUE;
500 break;
501 case 'n':
502 n_opt = atoi(optarg);
503 if (n_opt == 0)
504 n_opt = -1;
505 break;
506 case 'p':
507 pass_ctls = TRUE;
508 break;
509 case 'w':
510 w_opt = TRUE;
511 break;
micky3879b9f5e72025-07-08 18:04:53 -0400512 case OPTS_VERSION:
513 show_version(argv);
514 ExitProgram(EXIT_SUCCESS);
Steve Kondikae271bc2015-11-15 02:50:53 +0100515 default:
micky3879b9f5e72025-07-08 18:04:53 -0400516 usage(ch == OPTS_USAGE);
517 /* NOTREACHED */
Steve Kondikae271bc2015-11-15 02:50:53 +0100518 }
519 }
520 if (optind < argc)
micky3879b9f5e72025-07-08 18:04:53 -0400521 usage(FALSE);
Steve Kondikae271bc2015-11-15 02:50:53 +0100522
micky3879b9f5e72025-07-08 18:04:53 -0400523 recursive_test(0);
Steve Kondikae271bc2015-11-15 02:50:53 +0100524 endwin();
micky3879b9f5e72025-07-08 18:04:53 -0400525#if NO_LEAKS
526 free(temp_buffer);
527#endif
Steve Kondikae271bc2015-11-15 02:50:53 +0100528 ExitProgram(EXIT_SUCCESS);
529}