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