| /**************************************************************************** |
| * Copyright (c) 2009-2010,2012 Free Software Foundation, Inc. * |
| * * |
| * Permission is hereby granted, free of charge, to any person obtaining a * |
| * copy of this software and associated documentation files (the * |
| * "Software"), to deal in the Software without restriction, including * |
| * without limitation the rights to use, copy, modify, merge, publish, * |
| * distribute, distribute with modifications, sublicense, and/or sell * |
| * copies of the Software, and to permit persons to whom the Software is * |
| * furnished to do so, subject to the following conditions: * |
| * * |
| * The above copyright notice and this permission notice shall be included * |
| * in all copies or substantial portions of the Software. * |
| * * |
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * |
| * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * |
| * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * |
| * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * |
| * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * |
| * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * |
| * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * |
| * * |
| * Except as contained in this notice, the name(s) of the above copyright * |
| * holders shall not be used in advertising or otherwise to promote the * |
| * sale, use or other dealings in this Software without prior written * |
| * authorization. * |
| ****************************************************************************/ |
| /* |
| * $Id: test_addchstr.c,v 1.18 2012/12/16 00:36:27 tom Exp $ |
| * |
| * Demonstrate the waddchstr() and waddch functions. |
| * Thomas Dickey - 2009/9/12 |
| */ |
| |
| #include <test.priv.h> |
| |
| #include <linedata.h> |
| |
| #undef MvAddStr |
| #undef MvWAddStr |
| |
| #define AddNStr addchnstr |
| #define AddStr addchstr |
| #define MvAddNStr (void) mvaddchnstr |
| #define MvAddStr (void) mvaddchstr |
| #define MvWAddNStr (void) mvwaddchnstr |
| #define MvWAddStr (void) mvwaddchstr |
| #define WAddNStr waddchnstr |
| #define WAddStr waddchstr |
| |
| #define AddCh addch |
| #define WAddCh waddch |
| |
| #define MY_TABSIZE 8 |
| |
| typedef enum { |
| oDefault = 0, |
| oMove = 1, |
| oWindow = 2, |
| oMoveWindow = 3 |
| } Options; |
| |
| static bool m_opt = FALSE; |
| static bool pass_ctls = FALSE; |
| static bool w_opt = FALSE; |
| static int n_opt = -1; |
| |
| static attr_t show_attr; |
| static chtype *temp_buffer; |
| static size_t temp_length; |
| |
| #define TempBuffer(source_cast) |
| |
| static size_t |
| ChLen(const char *source) |
| { |
| size_t result = strlen(source); |
| |
| if (!pass_ctls) { |
| size_t adjust = 0; |
| size_t n; |
| |
| for (n = 0; n < result; ++n) { |
| const char *s = unctrl(UChar(source[n])); |
| if (s != 0) { |
| adjust += (strlen(s) - 1); |
| } |
| } |
| result += adjust; |
| } |
| return result; |
| } |
| |
| static chtype * |
| ChStr(const char *source) |
| { |
| if (source != 0) { |
| size_t need = ChLen(source) + 1; |
| int n = 0; |
| |
| if (need > temp_length) { |
| temp_length = need * 2; |
| temp_buffer = typeRealloc(chtype, temp_length, temp_buffer); |
| if (!temp_buffer) |
| failed("TempBuffer"); |
| } |
| do { |
| const char *s; |
| chtype ch = UChar(*source++); |
| if (!pass_ctls && (s = unctrl(ch)) != 0) { |
| while (*s != '\0') { |
| temp_buffer[n++] = UChar(*s++); |
| } |
| } else { |
| temp_buffer[n++] = ch; |
| } |
| } while (source[0] != 0); |
| temp_buffer[n] = 0; |
| } else if (temp_buffer != 0) { |
| free(temp_buffer); |
| temp_buffer = 0; |
| temp_length = 0; |
| } |
| return temp_buffer; |
| } |
| |
| /* color the strings drawn in the workspace */ |
| static chtype * |
| ChStr2(const char *source) |
| { |
| size_t len = ChLen(source); |
| size_t n; |
| chtype *result = ChStr(source); |
| for (n = 0; n < len; ++n) { |
| result[n] |= show_attr; |
| } |
| return result; |
| } |
| |
| static void |
| legend(WINDOW *win, int level, Options state, char *buffer, int length) |
| { |
| const char *showstate; |
| |
| switch (state) { |
| default: |
| case oDefault: |
| showstate = ""; |
| break; |
| case oMove: |
| showstate = " (mvXXX)"; |
| break; |
| case oWindow: |
| showstate = " (winXXX)"; |
| break; |
| case oMoveWindow: |
| showstate = " (mvwinXXX)"; |
| break; |
| } |
| |
| wmove(win, 0, 0); |
| wprintw(win, |
| "The Strings/Chars displays should match. Enter any characters, except:\n"); |
| wprintw(win, |
| "down-arrow or ^N to repeat on next line, ^W for inner window, ESC to exit.\n"); |
| wclrtoeol(win); |
| wprintw(win, "Level %d,%s added %d characters <%s>", level, |
| showstate, length, buffer); |
| } |
| |
| static int |
| ColOf(char *buffer, int length, int margin) |
| { |
| int n; |
| int result; |
| |
| for (n = 0, result = margin + 1; n < length; ++n) { |
| int ch = UChar(buffer[n]); |
| switch (ch) { |
| case '\n': |
| /* actually newline should clear the remainder of the line |
| * and move to the next line - but that seems a little awkward |
| * in this example. |
| */ |
| case '\r': |
| result = 0; |
| break; |
| case '\b': |
| if (result > 0) |
| --result; |
| break; |
| case '\t': |
| result += (MY_TABSIZE - (result % MY_TABSIZE)); |
| break; |
| case '\177': |
| result += 2; |
| break; |
| default: |
| ++result; |
| if (ch < 32) |
| ++result; |
| break; |
| } |
| } |
| return result; |
| } |
| |
| #define LEN(n) ((length - (n) > n_opt) ? n_opt : (length - (n))) |
| static void |
| test_adds(int level) |
| { |
| static bool first = TRUE; |
| |
| int ch; |
| int limit; |
| int row = 1; |
| int col; |
| int row2, col2; |
| int length; |
| char buffer[BUFSIZ]; |
| WINDOW *look = 0; |
| WINDOW *work = 0; |
| WINDOW *show = 0; |
| int margin = (2 * MY_TABSIZE) - 1; |
| Options option = (Options) ((unsigned) (m_opt |
| ? oMove |
| : oDefault) |
| | (unsigned) ((w_opt || (level > 0)) |
| ? oWindow |
| : oDefault)); |
| |
| if (first) { |
| static char cmd[80]; |
| setlocale(LC_ALL, ""); |
| |
| putenv(strcpy(cmd, "TABSIZE=8")); |
| |
| initscr(); |
| (void) cbreak(); /* take input chars one at a time, no wait for \n */ |
| (void) noecho(); /* don't echo input */ |
| keypad(stdscr, TRUE); |
| |
| /* |
| * Show the characters added in color, to distinguish from those that |
| * are shifted. |
| */ |
| if (has_colors()) { |
| start_color(); |
| init_pair(1, COLOR_WHITE, COLOR_BLUE); |
| } |
| } |
| |
| limit = LINES - 5; |
| if (level > 0) { |
| look = newwin(limit, COLS - (2 * (level - 1)), 0, level - 1); |
| work = newwin(limit - 2, COLS - (2 * level), 1, level); |
| show = newwin(4, COLS, limit + 1, 0); |
| box(look, 0, 0); |
| wnoutrefresh(look); |
| limit -= 2; |
| } else { |
| work = stdscr; |
| show = derwin(stdscr, 4, COLS, limit + 1, 0); |
| } |
| keypad(work, TRUE); |
| |
| for (col = margin + 1; col < COLS; col += MY_TABSIZE) |
| MvWVLine(work, row, col, '.', limit - 2); |
| |
| MvWVLine(work, row, margin, ACS_VLINE, limit - 2); |
| MvWVLine(work, row, margin + 1, ACS_VLINE, limit - 2); |
| limit /= 2; |
| |
| MvWAddChStr(work, 1, 2, ChStr("String")); |
| MvWAddChStr(work, limit + 1, 2, ChStr("Chars")); |
| wnoutrefresh(work); |
| |
| buffer[length = 0] = '\0'; |
| legend(show, level, option, buffer, length); |
| wnoutrefresh(show); |
| |
| doupdate(); |
| |
| if (has_colors()) { |
| show_attr = (attr_t) COLOR_PAIR(1); |
| wbkgdset(work, show_attr | ' '); |
| } else { |
| show_attr = A_STANDOUT; |
| } |
| |
| while ((ch = read_linedata(work)) != ERR && !isQUIT(ch)) { |
| wmove(work, row, margin + 1); |
| switch (ch) { |
| case key_RECUR: |
| test_adds(level + 1); |
| |
| if (look) |
| touchwin(look); |
| touchwin(work); |
| touchwin(show); |
| |
| if (look) |
| wnoutrefresh(look); |
| wnoutrefresh(work); |
| wnoutrefresh(show); |
| |
| doupdate(); |
| break; |
| case key_NEWLINE: |
| if (row < limit) { |
| ++row; |
| /* put the whole string in, all at once */ |
| col2 = margin + 1; |
| switch (option) { |
| case oDefault: |
| if (n_opt > 1) { |
| for (col = 0; col < length; col += n_opt) { |
| col2 = ColOf(buffer, col, margin); |
| if (move(row, col2) != ERR) { |
| AddNStr(ChStr2(buffer + col), LEN(col)); |
| } |
| } |
| } else { |
| if (move(row, col2) != ERR) { |
| AddStr(ChStr2(buffer)); |
| } |
| } |
| break; |
| case oMove: |
| if (n_opt > 1) { |
| for (col = 0; col < length; col += n_opt) { |
| col2 = ColOf(buffer, col, margin); |
| MvAddNStr(row, col2, ChStr2(buffer + col), LEN(col)); |
| } |
| } else { |
| MvAddStr(row, col2, ChStr2(buffer)); |
| } |
| break; |
| case oWindow: |
| if (n_opt > 1) { |
| for (col = 0; col < length; col += n_opt) { |
| col2 = ColOf(buffer, col, margin); |
| if (wmove(work, row, col2) != ERR) { |
| WAddNStr(work, ChStr2(buffer + col), LEN(col)); |
| } |
| } |
| } else { |
| if (wmove(work, row, col2) != ERR) { |
| WAddStr(work, ChStr2(buffer)); |
| } |
| } |
| break; |
| case oMoveWindow: |
| if (n_opt > 1) { |
| for (col = 0; col < length; col += n_opt) { |
| col2 = ColOf(buffer, col, margin); |
| MvWAddNStr(work, row, col2, ChStr2(buffer + col), |
| LEN(col)); |
| } |
| } else { |
| MvWAddStr(work, row, col2, ChStr2(buffer)); |
| } |
| break; |
| } |
| |
| /* do the corresponding single-character add */ |
| row2 = limit + row; |
| for (col = 0; col < length; ++col) { |
| col2 = ColOf(buffer, col, margin); |
| switch (option) { |
| case oDefault: |
| if (move(row2, col2) != ERR) { |
| AddCh(UChar(buffer[col])); |
| } |
| break; |
| case oMove: |
| MvAddCh(row2, col2, UChar(buffer[col])); |
| break; |
| case oWindow: |
| if (wmove(work, row2, col2) != ERR) { |
| WAddCh(work, UChar(buffer[col])); |
| } |
| break; |
| case oMoveWindow: |
| MvWAddCh(work, row2, col2, UChar(buffer[col])); |
| break; |
| } |
| } |
| } else { |
| beep(); |
| } |
| break; |
| case KEY_BACKSPACE: |
| ch = '\b'; |
| /* FALLTHRU */ |
| default: |
| if (ch <= 0 || ch > 255) { |
| beep(); |
| break; |
| } |
| buffer[length++] = (char) ch; |
| buffer[length] = '\0'; |
| |
| /* put the string in, one character at a time */ |
| col = ColOf(buffer, length - 1, margin); |
| switch (option) { |
| case oDefault: |
| if (move(row, col) != ERR) { |
| AddStr(ChStr2(buffer + length - 1)); |
| } |
| break; |
| case oMove: |
| MvAddStr(row, col, ChStr2(buffer + length - 1)); |
| break; |
| case oWindow: |
| if (wmove(work, row, col) != ERR) { |
| WAddStr(work, ChStr2(buffer + length - 1)); |
| } |
| break; |
| case oMoveWindow: |
| MvWAddStr(work, row, col, ChStr2(buffer + length - 1)); |
| break; |
| } |
| |
| /* do the corresponding single-character add */ |
| switch (option) { |
| case oDefault: |
| if (move(limit + row, col) != ERR) { |
| AddCh(UChar(ch)); |
| } |
| break; |
| case oMove: |
| MvAddCh(limit + row, col, UChar(ch)); |
| break; |
| case oWindow: |
| if (wmove(work, limit + row, col) != ERR) { |
| WAddCh(work, UChar(ch)); |
| } |
| break; |
| case oMoveWindow: |
| MvWAddCh(work, limit + row, col, UChar(ch)); |
| break; |
| } |
| |
| wnoutrefresh(work); |
| |
| legend(show, level, option, buffer, length); |
| wnoutrefresh(show); |
| |
| doupdate(); |
| break; |
| } |
| } |
| if (level > 0) { |
| delwin(work); |
| delwin(look); |
| } |
| delwin(show); |
| } |
| |
| static void |
| usage(void) |
| { |
| static const char *tbl[] = |
| { |
| "Usage: test_addchstr [options]" |
| ,"" |
| ,"Options:" |
| ," -f FILE read data from given file" |
| ," -n NUM limit string-adds to NUM bytes on ^N replay" |
| ," -m perform wmove/move separately from add-functions" |
| ," -p pass-thru control characters without using unctrl()" |
| ," -w use window-parameter even when stdscr would be implied" |
| }; |
| unsigned n; |
| for (n = 0; n < SIZEOF(tbl); ++n) |
| fprintf(stderr, "%s\n", tbl[n]); |
| ExitProgram(EXIT_FAILURE); |
| } |
| |
| int |
| main(int argc GCC_UNUSED, char *argv[]GCC_UNUSED) |
| { |
| int ch; |
| |
| setlocale(LC_ALL, ""); |
| |
| while ((ch = getopt(argc, argv, "f:mn:pw")) != -1) { |
| switch (ch) { |
| case 'f': |
| init_linedata(optarg); |
| break; |
| case 'm': |
| m_opt = TRUE; |
| break; |
| case 'n': |
| n_opt = atoi(optarg); |
| if (n_opt == 0) |
| n_opt = -1; |
| break; |
| case 'p': |
| pass_ctls = TRUE; |
| break; |
| case 'w': |
| w_opt = TRUE; |
| break; |
| default: |
| usage(); |
| break; |
| } |
| } |
| if (optind < argc) |
| usage(); |
| |
| test_adds(0); |
| endwin(); |
| ExitProgram(EXIT_SUCCESS); |
| } |