1/****************************************************************************
2 * Copyright (c) 2002-2006,2007 Free Software Foundation, Inc.              *
3 *                                                                          *
4 * Permission is hereby granted, free of charge, to any person obtaining a  *
5 * copy of this software and associated documentation files (the            *
6 * "Software"), to deal in the Software without restriction, including      *
7 * without limitation the rights to use, copy, modify, merge, publish,      *
8 * distribute, distribute with modifications, sublicense, and/or sell       *
9 * copies of the Software, and to permit persons to whom the Software is    *
10 * furnished to do so, subject to the following conditions:                 *
11 *                                                                          *
12 * The above copyright notice and this permission notice shall be included  *
13 * in all copies or substantial portions of the Software.                   *
14 *                                                                          *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
16 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
18 * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
19 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
20 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
21 * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
22 *                                                                          *
23 * Except as contained in this notice, the name(s) of the above copyright   *
24 * holders shall not be used in advertising or otherwise to promote the     *
25 * sale, use or other dealings in this Software without prior written       *
26 * authorization.                                                           *
27 ****************************************************************************/
28/*
29 * $Id: inserts.c,v 1.18 2007/07/21 17:41:55 tom Exp $
30 *
31 * Demonstrate the winsstr() and winsch functions.
32 * Thomas Dickey - 2002/10/19
33 */
34
35#include <test.priv.h>
36
37#if HAVE_WINSSTR
38
39#define InsNStr    insnstr
40#define InsStr     insstr
41#define MvInsNStr  mvinsnstr
42#define MvInsStr   mvinsstr
43#define MvWInsNStr mvwinsnstr
44#define MvWInsStr  mvwinsstr
45#define WInsNStr   winsnstr
46#define WInsStr    winsstr
47
48#define InsCh      insch
49#define MvInsCh    mvinsch
50#define MvWInsCh   mvwinsch
51#define WInsCh     winsch
52
53#define MY_TABSIZE 8
54
55typedef enum {
56    oDefault = 0,
57    oMove = 1,
58    oWindow = 2,
59    oMoveWindow = 3
60} Options;
61
62static bool m_opt = FALSE;
63static bool w_opt = FALSE;
64static int n_opt = -1;
65
66static void
67legend(WINDOW *win, int level, Options state, char *buffer, int length)
68{
69    NCURSES_CONST char *showstate;
70
71    switch (state) {
72    default:
73    case oDefault:
74	showstate = "";
75	break;
76    case oMove:
77	showstate = " (mvXXX)";
78	break;
79    case oWindow:
80	showstate = " (winXXX)";
81	break;
82    case oMoveWindow:
83	showstate = " (mvwinXXX)";
84	break;
85    }
86
87    wmove(win, 0, 0);
88    wprintw(win,
89	    "The Strings/Chars displays should match.  Enter any characters, except:\n");
90    wprintw(win,
91	    "down-arrow or ^N to repeat on next line, 'w' for inner window, 'q' to exit.\n");
92    wclrtoeol(win);
93    wprintw(win, "Level %d,%s inserted %d characters <%s>", level,
94	    showstate, length, buffer);
95}
96
97static int
98ColOf(char *buffer, int length, int margin)
99{
100    int n;
101    int result;
102
103    for (n = 0, result = margin + 1; n < length; ++n) {
104	int ch = UChar(buffer[n]);
105	switch (ch) {
106	case '\n':
107	    /* actually newline should clear the remainder of the line
108	     * and move to the next line - but that seems a little awkward
109	     * in this example.
110	     */
111	case '\r':
112	    result = 0;
113	    break;
114	case '\b':
115	    if (result > 0)
116		--result;
117	    break;
118	case '\t':
119	    result += (MY_TABSIZE - (result % MY_TABSIZE));
120	    break;
121	case '\177':
122	    result += 2;
123	    break;
124	default:
125	    ++result;
126	    if (ch < 32)
127		++result;
128	    break;
129	}
130    }
131    return result;
132}
133
134#define LEN(n) ((length - (n) > n_opt) ? n_opt : (length - (n)))
135static void
136test_inserts(int level)
137{
138    static bool first = TRUE;
139
140    int ch;
141    int limit;
142    int row = 1;
143    int col;
144    int row2, col2;
145    int length;
146    char buffer[BUFSIZ];
147    WINDOW *look = 0;
148    WINDOW *work = 0;
149    WINDOW *show = 0;
150    int margin = (2 * MY_TABSIZE) - 1;
151    Options option = (Options) ((unsigned) (m_opt
152					    ? oMove
153					    : oDefault)
154				| (unsigned) ((w_opt || (level > 0))
155					      ? oWindow
156					      : oDefault));
157
158    if (first) {
159	static char cmd[80];
160	setlocale(LC_ALL, "");
161
162	putenv(strcpy(cmd, "TABSIZE=8"));
163
164	initscr();
165	(void) cbreak();	/* take input chars one at a time, no wait for \n */
166	(void) noecho();	/* don't echo input */
167	keypad(stdscr, TRUE);
168    }
169
170    limit = LINES - 5;
171    if (level > 0) {
172	look = newwin(limit, COLS - (2 * (level - 1)), 0, level - 1);
173	work = newwin(limit - 2, COLS - (2 * level), 1, level);
174	show = newwin(4, COLS, limit + 1, 0);
175	box(look, 0, 0);
176	wnoutrefresh(look);
177	limit -= 2;
178    } else {
179	work = stdscr;
180	show = derwin(stdscr, 4, COLS, limit + 1, 0);
181    }
182    keypad(work, TRUE);
183
184    for (col = margin + 1; col < COLS; col += MY_TABSIZE)
185	mvwvline(work, row, col, '.', limit - 2);
186
187    mvwvline(work, row, margin, ACS_VLINE, limit - 2);
188    mvwvline(work, row, margin + 1, ACS_VLINE, limit - 2);
189    limit /= 2;
190
191    mvwaddstr(work, 1, 2, "String");
192    mvwaddstr(work, limit + 1, 2, "Chars");
193    wnoutrefresh(work);
194
195    buffer[length = 0] = '\0';
196    legend(show, level, option, buffer, length);
197    wnoutrefresh(show);
198
199    doupdate();
200
201    /*
202     * Show the characters inserted in color, to distinguish from those that
203     * are shifted.
204     */
205    if (has_colors()) {
206	start_color();
207	init_pair(1, COLOR_WHITE, COLOR_BLUE);
208	wbkgdset(work, COLOR_PAIR(1) | ' ');
209    }
210
211    while ((ch = wgetch(work)) != 'q') {
212	if (ch == ERR) {
213	    beep();
214	    break;
215	}
216	wmove(work, row, margin + 1);
217	switch (ch) {
218	case 'w':
219	    test_inserts(level + 1);
220
221	    touchwin(look);
222	    touchwin(work);
223	    touchwin(show);
224
225	    wnoutrefresh(look);
226	    wnoutrefresh(work);
227	    wnoutrefresh(show);
228
229	    doupdate();
230	    break;
231	case CTRL('N'):
232	case KEY_DOWN:
233	    if (row < limit) {
234		++row;
235		/* put the whole string in, all at once */
236		col2 = margin + 1;
237		switch (option) {
238		case oDefault:
239		    if (n_opt > 1) {
240			for (col = 0; col < length; col += n_opt) {
241			    col2 = ColOf(buffer, col, margin);
242			    if (move(row, col2) != ERR) {
243				InsNStr(buffer + col, LEN(col));
244			    }
245			}
246		    } else {
247			if (move(row, col2) != ERR) {
248			    InsStr(buffer);
249			}
250		    }
251		    break;
252		case oMove:
253		    if (n_opt > 1) {
254			for (col = 0; col < length; col += n_opt) {
255			    col2 = ColOf(buffer, col, margin);
256			    MvInsNStr(row, col2, buffer + col, LEN(col));
257			}
258		    } else {
259			MvInsStr(row, col2, buffer);
260		    }
261		    break;
262		case oWindow:
263		    if (n_opt > 1) {
264			for (col = 0; col < length; col += n_opt) {
265			    col2 = ColOf(buffer, col, margin);
266			    if (wmove(work, row, col2) != ERR) {
267				WInsNStr(work, buffer + col, LEN(col));
268			    }
269			}
270		    } else {
271			if (wmove(work, row, col2) != ERR) {
272			    WInsStr(work, buffer);
273			}
274		    }
275		    break;
276		case oMoveWindow:
277		    if (n_opt > 1) {
278			for (col = 0; col < length; col += n_opt) {
279			    col2 = ColOf(buffer, col, margin);
280			    MvWInsNStr(work, row, col2, buffer + col, LEN(col));
281			}
282		    } else {
283			MvWInsStr(work, row, col2, buffer);
284		    }
285		    break;
286		}
287
288		/* do the corresponding single-character insertion */
289		row2 = limit + row;
290		for (col = 0; col < length; ++col) {
291		    col2 = ColOf(buffer, col, margin);
292		    switch (option) {
293		    case oDefault:
294			if (move(row2, col2) != ERR) {
295			    InsCh(UChar(buffer[col]));
296			}
297			break;
298		    case oMove:
299			MvInsCh(row2, col2, UChar(buffer[col]));
300			break;
301		    case oWindow:
302			if (wmove(work, row2, col2) != ERR) {
303			    WInsCh(work, UChar(buffer[col]));
304			}
305			break;
306		    case oMoveWindow:
307			MvWInsCh(work, row2, col2, UChar(buffer[col]));
308			break;
309		    }
310		}
311	    } else {
312		beep();
313	    }
314	    break;
315	case KEY_BACKSPACE:
316	    ch = '\b';
317	    /* FALLTHRU */
318	default:
319	    if (ch <= 0 || ch > 255) {
320		beep();
321		break;
322	    }
323	    buffer[length++] = ch;
324	    buffer[length] = '\0';
325
326	    /* put the string in, one character at a time */
327	    col = ColOf(buffer, length - 1, margin);
328	    switch (option) {
329	    case oDefault:
330		if (move(row, col) != ERR) {
331		    InsStr(buffer + length - 1);
332		}
333		break;
334	    case oMove:
335		MvInsStr(row, col, buffer + length - 1);
336		break;
337	    case oWindow:
338		if (wmove(work, row, col) != ERR) {
339		    WInsStr(work, buffer + length - 1);
340		}
341		break;
342	    case oMoveWindow:
343		MvWInsStr(work, row, col, buffer + length - 1);
344		break;
345	    }
346
347	    /* do the corresponding single-character insertion */
348	    switch (option) {
349	    case oDefault:
350		if (move(limit + row, col) != ERR) {
351		    InsCh(UChar(ch));
352		}
353		break;
354	    case oMove:
355		MvInsCh(limit + row, col, UChar(ch));
356		break;
357	    case oWindow:
358		if (wmove(work, limit + row, col) != ERR) {
359		    WInsCh(work, UChar(ch));
360		}
361		break;
362	    case oMoveWindow:
363		MvWInsCh(work, limit + row, col, UChar(ch));
364		break;
365	    }
366
367	    wnoutrefresh(work);
368
369	    legend(show, level, option, buffer, length);
370	    wnoutrefresh(show);
371
372	    doupdate();
373	    break;
374	}
375    }
376    if (level > 0) {
377	delwin(show);
378	delwin(work);
379	delwin(look);
380    }
381}
382
383static void
384usage(void)
385{
386    static const char *tbl[] =
387    {
388	"Usage: inserts [options]"
389	,""
390	,"Options:"
391	,"  -n NUM  limit string-inserts to NUM bytes on ^N replay"
392	,"  -m      perform wmove/move separately from insert-functions"
393	,"  -w      use window-parameter even when stdscr would be implied"
394    };
395    unsigned n;
396    for (n = 0; n < SIZEOF(tbl); ++n)
397	fprintf(stderr, "%s\n", tbl[n]);
398    ExitProgram(EXIT_FAILURE);
399}
400
401int
402main(int argc GCC_UNUSED, char *argv[]GCC_UNUSED)
403{
404    int ch;
405
406    setlocale(LC_ALL, "");
407
408    while ((ch = getopt(argc, argv, "mn:w")) != -1) {
409	switch (ch) {
410	case 'm':
411	    m_opt = TRUE;
412	    break;
413	case 'n':
414	    n_opt = atoi(optarg);
415	    if (n_opt == 0)
416		n_opt = -1;
417	    break;
418	case 'w':
419	    w_opt = TRUE;
420	    break;
421	default:
422	    usage();
423	    break;
424	}
425    }
426    if (optind < argc)
427	usage();
428
429    test_inserts(0);
430    endwin();
431    ExitProgram(EXIT_SUCCESS);
432}
433#else
434int
435main(void)
436{
437    printf("This program requires the winsstr function\n");
438    ExitProgram(EXIT_FAILURE);
439}
440#endif /* HAVE_WINSSTR */
441