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