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 499