source: trunk/ncurses/test/ins_wide.c@ 2787

Last change on this file since 2787 was 2621, checked in by bird, 19 years ago

GNU ncurses 5.5

File size: 10.2 KB
Line 
1/*
2 * $Id: ins_wide.c,v 1.6 2005/04/16 17:45:17 tom Exp $
3 *
4 * Demonstrate the wins_wstr() and wins_wch functions.
5 * Thomas Dickey - 2002/11/23
6 *
7 * Note: to provide inputs for *ins_wch(), we use setcchar(). A quirk of the
8 * X/Open definition for that function is that the string contains no
9 * characters with negative width. Any control character (such as tab) falls
10 * into that category. So it follows that *ins_wch() cannot render a tab
11 * character because there is no legal way to construct a cchar_t containing
12 * one. X/Open does not document this, and it would be logical to assume that
13 * *ins_wstr() has the same limitation, but it uses a wchar_t string directly,
14 * and does not document how tabs are handled.
15 */
16
17#include <test.priv.h>
18
19#if USE_WIDEC_SUPPORT
20
21/* definitions to make it simpler to compare with inserts.c */
22#define InsNStr ins_nwstr
23#define InsStr ins_wstr
24#define MvInsNStr mvins_nwstr
25#define MvInsStr mvins_wstr
26#define MvWInsNStr mvwins_nwstr
27#define MvWInsStr mvwins_wstr
28#define WInsNStr wins_nwstr
29#define WInsStr wins_wstr
30
31#define TABSIZE 8
32
33typedef enum {
34 oDefault = 0,
35 oMove = 1,
36 oWindow = 2,
37 oMoveWindow = 3
38} Options;
39
40static bool m_opt = FALSE;
41static bool w_opt = FALSE;
42static int n_opt = -1;
43
44static void
45legend(WINDOW *win, int level, Options state, wchar_t *buffer, int length)
46{
47 NCURSES_CONST char *showstate;
48
49 switch (state) {
50 default:
51 case oDefault:
52 showstate = "";
53 break;
54 case oMove:
55 showstate = " (mvXXX)";
56 break;
57 case oWindow:
58 showstate = " (winXXX)";
59 break;
60 case oMoveWindow:
61 showstate = " (mvwinXXX)";
62 break;
63 }
64
65 wmove(win, 0, 0);
66 wprintw(win,
67 "The Strings/Chars displays should match. Enter any characters, except:\n");
68 wprintw(win,
69 "down-arrow or ^N to repeat on next line, 'w' for inner window, 'q' to exit.\n");
70 wclrtoeol(win);
71 wprintw(win, "Level %d,%s inserted %d characters <", level,
72 showstate, length);
73 waddwstr(win, buffer);
74 waddstr(win, ">");
75}
76
77static int
78ColOf(wchar_t *buffer, int length, int margin)
79{
80 int n;
81 int result;
82
83 for (n = 0, result = margin + 1; n < length; ++n) {
84 int ch = buffer[n];
85 switch (ch) {
86 case '\n':
87 /* actually newline should clear the remainder of the line
88 * and move to the next line - but that seems a little awkward
89 * in this example.
90 */
91 case '\r':
92 result = 0;
93 break;
94 case '\b':
95 if (result > 0)
96 --result;
97 break;
98 case '\t':
99 result += (TABSIZE - (result % TABSIZE));
100 break;
101 case '\177':
102 result += 2;
103 break;
104 default:
105 result += wcwidth(ch);
106 if (ch < 32)
107 ++result;
108 break;
109 }
110 }
111 return result;
112}
113
114static int
115ConvertCh(chtype source, cchar_t *target)
116{
117 wchar_t tmp_wchar[2];
118
119 tmp_wchar[0] = source;
120 tmp_wchar[1] = 0;
121 if (setcchar(target, tmp_wchar, A_NORMAL, 0, (void *) 0) == ERR) {
122 beep();
123 return FALSE;
124 }
125 return TRUE;
126}
127
128static int
129MvWInsCh(WINDOW *win, int y, int x, chtype ch)
130{
131 int code;
132 cchar_t tmp_cchar;
133
134 if (ConvertCh(ch, &tmp_cchar)) {
135 code = mvwins_wch(win, y, x, &tmp_cchar);
136 } else {
137 code = mvwinsch(win, y, x, ch);
138 }
139 return code;
140}
141
142static int
143MvInsCh(int y, int x, chtype ch)
144{
145 int code;
146 cchar_t tmp_cchar;
147
148 if (ConvertCh(ch, &tmp_cchar)) {
149 code = mvins_wch(y, x, &tmp_cchar);
150 } else {
151 code = mvinsch(y, x, ch);
152 }
153 return code;
154}
155
156static int
157WInsCh(WINDOW *win, chtype ch)
158{
159 int code;
160 cchar_t tmp_cchar;
161
162 if (ConvertCh(ch, &tmp_cchar)) {
163 code = wins_wch(win, &tmp_cchar);
164 } else {
165 code = winsch(win, ch);
166 }
167 return code;
168}
169
170static int
171InsCh(chtype ch)
172{
173 int code;
174 cchar_t tmp_cchar;
175
176 if (ConvertCh(ch, &tmp_cchar)) {
177 code = ins_wch(&tmp_cchar);
178 } else {
179 code = insch(ch);
180 }
181 return code;
182}
183
184#define LEN(n) ((length - (n) > n_opt) ? n_opt : (length - (n)))
185static void
186test_inserts(int level)
187{
188 static bool first = TRUE;
189
190 wint_t ch;
191 int code;
192 int limit;
193 int row = 1;
194 int col;
195 int row2, col2;
196 int length;
197 wchar_t buffer[BUFSIZ];
198 WINDOW *look = 0;
199 WINDOW *work = 0;
200 WINDOW *show = 0;
201 int margin = (2 * TABSIZE) - 1;
202 Options option = ((m_opt ? oMove : oDefault)
203 | ((w_opt || (level > 0)) ? oWindow : oDefault));
204
205 if (first) {
206 static char cmd[80];
207 setlocale(LC_ALL, "");
208
209 putenv(strcpy(cmd, "TABSIZE=8"));
210
211 initscr();
212 (void) cbreak(); /* take input chars one at a time, no wait for \n */
213 (void) noecho(); /* don't echo input */
214 keypad(stdscr, TRUE);
215 }
216
217 limit = LINES - 5;
218 if (level > 0) {
219 look = newwin(limit, COLS - (2 * (level - 1)), 0, level - 1);
220 work = newwin(limit - 2, COLS - (2 * level), 1, level);
221 show = newwin(4, COLS, limit + 1, 0);
222 box(look, 0, 0);
223 wnoutrefresh(look);
224 limit -= 2;
225 } else {
226 work = stdscr;
227 show = derwin(stdscr, 4, COLS, limit + 1, 0);
228 }
229 keypad(work, TRUE);
230
231 for (col = margin + 1; col < COLS; col += TABSIZE)
232 mvwvline(work, row, col, '.', limit - 2);
233
234 mvwvline(work, row, margin, ACS_VLINE, limit - 2);
235 mvwvline(work, row, margin + 1, ACS_VLINE, limit - 2);
236 limit /= 2;
237
238 mvwaddstr(work, 1, 2, "String");
239 mvwaddstr(work, limit + 1, 2, "Chars");
240 wnoutrefresh(work);
241
242 buffer[length = 0] = '\0';
243 legend(show, level, option, buffer, length);
244 wnoutrefresh(show);
245
246 doupdate();
247
248 /*
249 * Show the characters inserted in color, to distinguish from those that
250 * are shifted.
251 */
252 if (has_colors()) {
253 start_color();
254 init_pair(1, COLOR_WHITE, COLOR_BLUE);
255 wbkgdset(work, COLOR_PAIR(1) | ' ');
256 }
257
258 while ((code = wget_wch(work, &ch)) != ERR) {
259
260 if (code == KEY_CODE_YES) {
261 switch (ch) {
262 case KEY_DOWN:
263 ch = CTRL('N');
264 break;
265 case KEY_BACKSPACE:
266 ch = '\b';
267 break;
268 default:
269 beep();
270 continue;
271 }
272 } else if (code == ERR) {
273 beep();
274 break;
275 }
276 if (ch == 'q')
277 break;
278
279 wmove(work, row, margin + 1);
280 switch (ch) {
281 case 'w':
282 test_inserts(level + 1);
283
284 touchwin(look);
285 touchwin(work);
286 touchwin(show);
287
288 wnoutrefresh(look);
289 wnoutrefresh(work);
290 wnoutrefresh(show);
291
292 doupdate();
293 break;
294 case CTRL('N'):
295 if (row < limit) {
296 ++row;
297 /* put the whole string in, all at once */
298 col2 = margin + 1;
299 switch (option) {
300 case oDefault:
301 if (n_opt > 1) {
302 for (col = 0; col < length; col += n_opt) {
303 col2 = ColOf(buffer, col, margin);
304 if (move(row, col2) != ERR) {
305 InsNStr(buffer + col, LEN(col));
306 }
307 }
308 } else {
309 if (move(row, col2) != ERR) {
310 InsStr(buffer);
311 }
312 }
313 break;
314 case oMove:
315 if (n_opt > 1) {
316 for (col = 0; col < length; col += n_opt) {
317 col2 = ColOf(buffer, col, margin);
318 MvInsNStr(row, col2, buffer + col, LEN(col));
319 }
320 } else {
321 MvInsStr(row, col2, buffer);
322 }
323 break;
324 case oWindow:
325 if (n_opt > 1) {
326 for (col = 0; col < length; col += n_opt) {
327 col2 = ColOf(buffer, col, margin);
328 if (wmove(work, row, col2) != ERR) {
329 WInsNStr(work, buffer + col, LEN(col));
330 }
331 }
332 } else {
333 if (wmove(work, row, col2) != ERR) {
334 WInsStr(work, buffer);
335 }
336 }
337 break;
338 case oMoveWindow:
339 if (n_opt > 1) {
340 for (col = 0; col < length; col += n_opt) {
341 col2 = ColOf(buffer, col, margin);
342 MvWInsNStr(work, row, col2, buffer + col, LEN(col));
343 }
344 } else {
345 MvWInsStr(work, row, col2, buffer);
346 }
347 break;
348 }
349
350 /* do the corresponding single-character insertion */
351 row2 = limit + row;
352 for (col = 0; col < length; ++col) {
353 col2 = ColOf(buffer, col, margin);
354 switch (option) {
355 case oDefault:
356 if (move(row2, col2) != ERR) {
357 InsCh((chtype) buffer[col]);
358 }
359 break;
360 case oMove:
361 MvInsCh(row2, col2, (chtype) buffer[col]);
362 break;
363 case oWindow:
364 if (wmove(work, row2, col2) != ERR) {
365 WInsCh(work, (chtype) buffer[col]);
366 }
367 break;
368 case oMoveWindow:
369 MvWInsCh(work, row2, col2, (chtype) buffer[col]);
370 break;
371 }
372 }
373 } else {
374 beep();
375 }
376 break;
377 case KEY_BACKSPACE:
378 ch = '\b';
379 /* FALLTHRU */
380 default:
381 buffer[length++] = ch;
382 buffer[length] = '\0';
383
384 /* put the string in, one character at a time */
385 col = ColOf(buffer, length - 1, margin);
386 switch (option) {
387 case oDefault:
388 if (move(row, col) != ERR) {
389 InsStr(buffer + length - 1);
390 }
391 break;
392 case oMove:
393 MvInsStr(row, col, buffer + length - 1);
394 break;
395 case oWindow:
396 if (wmove(work, row, col) != ERR) {
397 WInsStr(work, buffer + length - 1);
398 }
399 break;
400 case oMoveWindow:
401 MvWInsStr(work, row, col, buffer + length - 1);
402 break;
403 }
404
405 /* do the corresponding single-character insertion */
406 switch (option) {
407 case oDefault:
408 if (move(limit + row, col) != ERR) {
409 InsCh(ch);
410 }
411 break;
412 case oMove:
413 MvInsCh(limit + row, col, ch);
414 break;
415 case oWindow:
416 if (wmove(work, limit + row, col) != ERR) {
417 WInsCh(work, ch);
418 }
419 break;
420 case oMoveWindow:
421 MvWInsCh(work, limit + row, col, ch);
422 break;
423 }
424
425 wnoutrefresh(work);
426
427 legend(show, level, option, buffer, length);
428 wnoutrefresh(show);
429
430 doupdate();
431 break;
432 }
433 }
434 if (level > 0) {
435 delwin(show);
436 delwin(work);
437 delwin(look);
438 }
439}
440
441static void
442usage(void)
443{
444 static const char *tbl[] =
445 {
446 "Usage: inserts [options]"
447 ,""
448 ,"Options:"
449 ," -n NUM limit string-inserts to NUM bytes on ^N replay"
450 ," -m perform wmove/move separately from insert-functions"
451 ," -w use window-parameter even when stdscr would be implied"
452 };
453 unsigned n;
454 for (n = 0; n < SIZEOF(tbl); ++n)
455 fprintf(stderr, "%s\n", tbl[n]);
456 ExitProgram(EXIT_FAILURE);
457}
458
459int
460main(int argc GCC_UNUSED, char *argv[]GCC_UNUSED)
461{
462 int ch;
463
464 setlocale(LC_ALL, "");
465
466 while ((ch = getopt(argc, argv, "mn:w")) != EOF) {
467 switch (ch) {
468 case 'm':
469 m_opt = TRUE;
470 break;
471 case 'n':
472 n_opt = atoi(optarg);
473 if (n_opt == 0)
474 n_opt = -1;
475 break;
476 case 'w':
477 w_opt = TRUE;
478 break;
479 default:
480 usage();
481 break;
482 }
483 }
484 if (optind < argc)
485 usage();
486
487 test_inserts(0);
488 endwin();
489 ExitProgram(EXIT_SUCCESS);
490}
491#else
492int
493main(void)
494{
495 printf("This program requires the wide-ncurses library\n");
496 ExitProgram(EXIT_FAILURE);
497}
498#endif
Note: See TracBrowser for help on using the repository browser.