diff options
Diffstat (limited to 'src/fe-text')
-rw-r--r-- | src/fe-text/Makefile.am | 23 | ||||
-rw-r--r-- | src/fe-text/gui-entry.c | 184 | ||||
-rw-r--r-- | src/fe-text/gui-entry.h | 29 | ||||
-rw-r--r-- | src/fe-text/gui-printtext.c | 20 | ||||
-rw-r--r-- | src/fe-text/gui-printtext.h | 1 | ||||
-rw-r--r-- | src/fe-text/gui-readline.c | 289 | ||||
-rw-r--r-- | src/fe-text/gui-windows.c | 10 | ||||
-rw-r--r-- | src/fe-text/irssi.c | 136 | ||||
-rw-r--r-- | src/fe-text/lastlog.c | 48 | ||||
-rw-r--r-- | src/fe-text/mainwindows-layout.c | 3 | ||||
-rw-r--r-- | src/fe-text/module-formats.c | 1 | ||||
-rw-r--r-- | src/fe-text/module-formats.h | 1 | ||||
-rw-r--r-- | src/fe-text/statusbar-config.c | 26 | ||||
-rw-r--r-- | src/fe-text/statusbar-items.c | 38 | ||||
-rw-r--r-- | src/fe-text/statusbar.c | 8 | ||||
-rw-r--r-- | src/fe-text/term-curses.c | 415 | ||||
-rw-r--r-- | src/fe-text/term-dummy.c | 106 | ||||
-rw-r--r-- | src/fe-text/term-terminfo.c | 44 | ||||
-rw-r--r-- | src/fe-text/term.h | 7 | ||||
-rw-r--r-- | src/fe-text/terminfo-core.c | 189 | ||||
-rw-r--r-- | src/fe-text/terminfo-core.h | 8 | ||||
-rw-r--r-- | src/fe-text/textbuffer-view.c | 14 | ||||
-rw-r--r-- | src/fe-text/textbuffer-view.h | 5 | ||||
-rw-r--r-- | src/fe-text/textbuffer.c | 40 | ||||
-rw-r--r-- | src/fe-text/tparm.c | 740 |
25 files changed, 773 insertions, 1612 deletions
diff --git a/src/fe-text/Makefile.am b/src/fe-text/Makefile.am index b9538e60..bdd3df22 100644 --- a/src/fe-text/Makefile.am +++ b/src/fe-text/Makefile.am @@ -4,8 +4,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src \ -I$(top_srcdir)/src/core/ \ -I$(top_srcdir)/src/fe-common/core/ \ - $(GLIB_CFLAGS) \ - $(CURSES_INCLUDEDIR) + $(GLIB_CFLAGS) irssi_DEPENDENCIES = \ @COMMON_LIBS@ \ @@ -22,25 +21,11 @@ irssi_LDADD = \ @PROG_LIBS@ \ @TEXTUI_LIBS@ -tparm_sources = \ - tparm.c - terminfo_sources = \ term-terminfo.c \ terminfo-core.c -curses_sources = \ - term-curses.c - -if NEED_TPARM -use_tparm_sources = $(tparm_sources) -endif - -if USE_CURSES -use_term_sources = $(curses_sources) -else use_term_sources = $(terminfo_sources) -endif irssi_SOURCES = \ gui-entry.c \ @@ -56,8 +41,6 @@ irssi_SOURCES = \ statusbar-config.c \ statusbar-items.c \ term.c \ - term-dummy.c \ - $(use_tparm_sources) \ $(use_term_sources) \ textbuffer.c \ textbuffer-commands.c \ @@ -85,6 +68,4 @@ noinst_HEADERS = \ module-formats.h EXTRA_DIST = \ - $(tparm_sources) \ - $(terminfo_sources) \ - $(curses_sources) + $(terminfo_sources) diff --git a/src/fe-text/gui-entry.c b/src/fe-text/gui-entry.c index f123ce4c..f05decd2 100644 --- a/src/fe-text/gui-entry.c +++ b/src/fe-text/gui-entry.c @@ -26,30 +26,33 @@ #include "gui-entry.h" #include "gui-printtext.h" #include "term.h" +#include "recode.h" #undef i_toupper #undef i_tolower #undef i_isalnum +#define KILL_RING_MAX 10 + static unichar i_toupper(unichar c) { if (term_type == TERM_TYPE_UTF8) return g_unichar_toupper(c); - return (c >= 0 && c <= 255) ? toupper(c) : c; + return c <= 255 ? toupper(c) : c; } static unichar i_tolower(unichar c) { if (term_type == TERM_TYPE_UTF8) return g_unichar_tolower(c); - return (c >= 0 && c <= 255) ? tolower(c) : c; + return c <= 255 ? tolower(c) : c; } static int i_isalnum(unichar c) { if (term_type == TERM_TYPE_UTF8) return (g_unichar_isalnum(c) || mk_wcwidth(c) == 0); - return (c >= 0 && c <= 255) ? isalnum(c) : 0; + return c <= 255 ? isalnum(c) : 0; } GUI_ENTRY_REC *active_entry; @@ -81,11 +84,22 @@ GUI_ENTRY_REC *gui_entry_create(int xpos, int ypos, int width, int utf8) void gui_entry_destroy(GUI_ENTRY_REC *entry) { + GSList *tmp; + g_return_if_fail(entry != NULL); if (active_entry == entry) gui_entry_set_active(NULL); + for (tmp = entry->kill_ring; tmp != NULL; tmp = tmp->next) { + GUI_ENTRY_CUTBUFFER_REC *rec = tmp->data; + if (rec != NULL) { + g_free(rec->cutbuffer); + g_free(rec); + } + } + g_slist_free(entry->kill_ring); + g_free(entry->text); g_free(entry->prompt); g_free(entry); @@ -226,8 +240,8 @@ static void gui_entry_draw_from(GUI_ENTRY_REC *entry, int pos) int i; int xpos, end_xpos; - xpos = entry->xpos + entry->promptlen + - pos2scrpos(entry, pos + entry->scrstart) - + xpos = entry->xpos + entry->promptlen + + pos2scrpos(entry, pos + entry->scrstart) - pos2scrpos(entry, entry->scrstart); end_xpos = entry->xpos + entry->width; @@ -345,6 +359,19 @@ void gui_entry_set_active(GUI_ENTRY_REC *entry) } } +/* Return screen length of plain string */ +static int scrlen_str(const char *str) +{ + int len = 0; + char *stripped; + g_return_val_if_fail(str != NULL, 0); + + stripped = strip_codes(str); + len = string_width(stripped, -1); + g_free(stripped); + return len; +} + void gui_entry_set_prompt(GUI_ENTRY_REC *entry, const char *str) { int oldlen; @@ -355,11 +382,11 @@ void gui_entry_set_prompt(GUI_ENTRY_REC *entry, const char *str) if (str != NULL) { g_free_not_null(entry->prompt); entry->prompt = g_strdup(str); - entry->promptlen = format_get_length(str); + entry->promptlen = scrlen_str(str); } if (entry->prompt != NULL) - gui_printtext(entry->xpos, entry->ypos, entry->prompt); + gui_printtext_internal(entry->xpos, entry->ypos, entry->prompt); if (entry->promptlen != oldlen) { gui_entry_fix_cursor(entry); @@ -513,28 +540,51 @@ void gui_entry_insert_char(GUI_ENTRY_REC *entry, unichar chr) char *gui_entry_get_cutbuffer(GUI_ENTRY_REC *entry) { + GUI_ENTRY_CUTBUFFER_REC *tmp; char *buf; int i; g_return_val_if_fail(entry != NULL, NULL); - if (entry->cutbuffer == NULL) + if (entry->kill_ring == NULL || entry->kill_ring->data == NULL) + return NULL; + + tmp = entry->kill_ring->data; + + if (tmp->cutbuffer == NULL) return NULL; if (entry->utf8) - buf = g_ucs4_to_utf8(entry->cutbuffer, -1, NULL, NULL, NULL); + buf = g_ucs4_to_utf8(tmp->cutbuffer, -1, NULL, NULL, NULL); else { - buf = g_malloc(entry->cutbuffer_len*6 + 1); + buf = g_malloc(tmp->cutbuffer_len*6 + 1); if (term_type == TERM_TYPE_BIG5) - unichars_to_big5(entry->cutbuffer, buf); + unichars_to_big5(tmp->cutbuffer, buf); else - for (i = 0; i <= entry->cutbuffer_len; i++) - buf[i] = entry->cutbuffer[i]; + for (i = 0; i <= tmp->cutbuffer_len; i++) + buf[i] = tmp->cutbuffer[i]; } return buf; } -void gui_entry_erase_to(GUI_ENTRY_REC *entry, int pos, int update_cutbuffer) +char *gui_entry_get_next_cutbuffer(GUI_ENTRY_REC *entry) +{ + GUI_ENTRY_CUTBUFFER_REC *tmp; + + g_return_val_if_fail(entry != NULL, NULL); + + if (entry->kill_ring == NULL) + return NULL; + + tmp = entry->kill_ring->data; + + entry->kill_ring = g_slist_remove(entry->kill_ring, tmp); + entry->kill_ring = g_slist_append(entry->kill_ring, tmp); + + return gui_entry_get_cutbuffer(entry); +} + +void gui_entry_erase_to(GUI_ENTRY_REC *entry, int pos, CUTBUFFER_UPDATE_OP update_cutbuffer) { int newpos, size = 0; @@ -545,7 +595,41 @@ void gui_entry_erase_to(GUI_ENTRY_REC *entry, int pos, int update_cutbuffer) gui_entry_erase(entry, size, update_cutbuffer); } -void gui_entry_erase(GUI_ENTRY_REC *entry, int size, int update_cutbuffer) +static GUI_ENTRY_CUTBUFFER_REC *get_cutbuffer_rec(GUI_ENTRY_REC *entry, CUTBUFFER_UPDATE_OP update_cutbuffer) +{ + GUI_ENTRY_CUTBUFFER_REC *tmp; + + g_return_val_if_fail(entry != NULL, NULL); + + if (entry->kill_ring == NULL) { + /* no kill ring exists */ + entry->kill_ring = g_slist_prepend(entry->kill_ring, (void *)NULL); + } else { + tmp = entry->kill_ring->data; + + if (tmp != NULL && tmp->cutbuffer_len > 0 + && (!entry->previous_append_next_kill + || update_cutbuffer == CUTBUFFER_UPDATE_REPLACE)) { + /* a cutbuffer exists and should be replaced */ + entry->kill_ring = g_slist_prepend(entry->kill_ring, (void *)NULL); + } + } + + if (g_slist_length(entry->kill_ring) > KILL_RING_MAX) { + GUI_ENTRY_CUTBUFFER_REC *rec = g_slist_last(entry->kill_ring)->data; + entry->kill_ring = g_slist_remove(entry->kill_ring, rec); + if (rec != NULL) g_free(rec->cutbuffer); + g_free(rec); + } + + if (entry->kill_ring->data == NULL) { + entry->kill_ring->data = g_new0(GUI_ENTRY_CUTBUFFER_REC, 1); + } + + return entry->kill_ring->data; +} + +void gui_entry_erase(GUI_ENTRY_REC *entry, int size, CUTBUFFER_UPDATE_OP update_cutbuffer) { size_t w = 0; @@ -554,17 +638,59 @@ void gui_entry_erase(GUI_ENTRY_REC *entry, int size, int update_cutbuffer) if (size == 0 || entry->pos < size) return; - if (update_cutbuffer) { - /* put erased text to cutbuffer */ - if (entry->cutbuffer_len < size) { - g_free(entry->cutbuffer); - entry->cutbuffer = g_new(unichar, size+1); + if (update_cutbuffer != CUTBUFFER_UPDATE_NOOP) { + int cutbuffer_new_size; + unichar *tmpcutbuffer; + GUI_ENTRY_CUTBUFFER_REC *tmp = get_cutbuffer_rec(entry, update_cutbuffer); + + if (tmp->cutbuffer_len == 0) { + update_cutbuffer = CUTBUFFER_UPDATE_REPLACE; } - entry->cutbuffer_len = size; - entry->cutbuffer[size] = '\0'; - memcpy(entry->cutbuffer, entry->text + entry->pos - size, - size * sizeof(unichar)); + cutbuffer_new_size = tmp->cutbuffer_len + size; + tmpcutbuffer = tmp->cutbuffer; + entry->append_next_kill = TRUE; + switch (update_cutbuffer) { + case CUTBUFFER_UPDATE_APPEND: + tmp->cutbuffer = g_new(unichar, cutbuffer_new_size+1); + memcpy(tmp->cutbuffer, tmpcutbuffer, + tmp->cutbuffer_len * sizeof(unichar)); + memcpy(tmp->cutbuffer + tmp->cutbuffer_len, + entry->text + entry->pos - size, size * sizeof(unichar)); + + tmp->cutbuffer_len = cutbuffer_new_size; + tmp->cutbuffer[cutbuffer_new_size] = '\0'; + g_free(tmpcutbuffer); + break; + + case CUTBUFFER_UPDATE_PREPEND: + tmp->cutbuffer = g_new(unichar, cutbuffer_new_size+1); + memcpy(tmp->cutbuffer, entry->text + entry->pos - size, + size * sizeof(unichar)); + memcpy(tmp->cutbuffer + size, tmpcutbuffer, + tmp->cutbuffer_len * sizeof(unichar)); + + tmp->cutbuffer_len = cutbuffer_new_size; + tmp->cutbuffer[cutbuffer_new_size] = '\0'; + g_free(tmpcutbuffer); + break; + + case CUTBUFFER_UPDATE_REPLACE: + /* put erased text to cutbuffer */ + if (tmp->cutbuffer_len < size) { + g_free(tmp->cutbuffer); + tmp->cutbuffer = g_new(unichar, size+1); + } + + tmp->cutbuffer_len = size; + tmp->cutbuffer[size] = '\0'; + memcpy(tmp->cutbuffer, entry->text + entry->pos - size, size * sizeof(unichar)); + break; + + case CUTBUFFER_UPDATE_NOOP: + /* cannot happen, handled in "if" */ + break; + } } if (entry->utf8) @@ -601,7 +727,7 @@ void gui_entry_erase_cell(GUI_ENTRY_REC *entry) gui_entry_draw(entry); } -void gui_entry_erase_word(GUI_ENTRY_REC *entry, int to_space) +void gui_entry_erase_word(GUI_ENTRY_REC *entry, int to_space, CUTBUFFER_UPDATE_OP cutbuffer_op) { int to; @@ -624,10 +750,10 @@ void gui_entry_erase_word(GUI_ENTRY_REC *entry, int to_space) } if (to > 0) to++; - gui_entry_erase(entry, entry->pos-to, TRUE); + gui_entry_erase(entry, entry->pos-to, cutbuffer_op); } -void gui_entry_erase_next_word(GUI_ENTRY_REC *entry, int to_space) +void gui_entry_erase_next_word(GUI_ENTRY_REC *entry, int to_space, CUTBUFFER_UPDATE_OP cutbuffer_op) { int to, size; @@ -650,7 +776,7 @@ void gui_entry_erase_next_word(GUI_ENTRY_REC *entry, int to_space) size = to-entry->pos; entry->pos = to; - gui_entry_erase(entry, size, TRUE); + gui_entry_erase(entry, size, cutbuffer_op); } void gui_entry_transpose_chars(GUI_ENTRY_REC *entry) @@ -730,7 +856,7 @@ void gui_entry_transpose_words(GUI_ENTRY_REC *entry) g_free(second); } - + gui_entry_redraw_from(entry, spos1); gui_entry_fix_cursor(entry); gui_entry_draw(entry); diff --git a/src/fe-text/gui-entry.h b/src/fe-text/gui-entry.h index 29d8dea2..8777f083 100644 --- a/src/fe-text/gui-entry.h +++ b/src/fe-text/gui-entry.h @@ -2,11 +2,15 @@ #define __GUI_ENTRY_H typedef struct { + int cutbuffer_len; + unichar *cutbuffer; +} GUI_ENTRY_CUTBUFFER_REC; + +typedef struct { int text_len, text_alloc; /* as shorts, not chars */ unichar *text; - int cutbuffer_len; - unichar *cutbuffer; + GSList *kill_ring; /* all as shorts, not chars */ int xpos, ypos, width; /* entry position in screen */ @@ -18,8 +22,19 @@ typedef struct { int redraw_needed_from; unsigned int utf8:1; + + unsigned int previous_append_next_kill:1; + unsigned int append_next_kill:1; + unsigned int yank_preceded:1; } GUI_ENTRY_REC; +typedef enum { + CUTBUFFER_UPDATE_NOOP, + CUTBUFFER_UPDATE_REPLACE, + CUTBUFFER_UPDATE_APPEND, + CUTBUFFER_UPDATE_PREPEND +} CUTBUFFER_UPDATE_OP; + extern GUI_ENTRY_REC *active_entry; GUI_ENTRY_REC *gui_entry_create(int xpos, int ypos, int width, int utf8); @@ -40,11 +55,12 @@ void gui_entry_insert_text(GUI_ENTRY_REC *entry, const char *str); void gui_entry_insert_char(GUI_ENTRY_REC *entry, unichar chr); char *gui_entry_get_cutbuffer(GUI_ENTRY_REC *entry); -void gui_entry_erase_to(GUI_ENTRY_REC *entry, int pos, int update_cutbuffer); -void gui_entry_erase(GUI_ENTRY_REC *entry, int size, int update_cutbuffer); +char *gui_entry_get_next_cutbuffer(GUI_ENTRY_REC *entry); +void gui_entry_erase_to(GUI_ENTRY_REC *entry, int pos, CUTBUFFER_UPDATE_OP update_cutbuffer); +void gui_entry_erase(GUI_ENTRY_REC *entry, int size, CUTBUFFER_UPDATE_OP update_cutbuffer); void gui_entry_erase_cell(GUI_ENTRY_REC *entry); -void gui_entry_erase_word(GUI_ENTRY_REC *entry, int to_space); -void gui_entry_erase_next_word(GUI_ENTRY_REC *entry, int to_space); +void gui_entry_erase_word(GUI_ENTRY_REC *entry, int to_space, CUTBUFFER_UPDATE_OP cutbuffer_op); +void gui_entry_erase_next_word(GUI_ENTRY_REC *entry, int to_space, CUTBUFFER_UPDATE_OP cutbuffer_op); void gui_entry_transpose_chars(GUI_ENTRY_REC *entry); void gui_entry_transpose_words(GUI_ENTRY_REC *entry); @@ -60,4 +76,5 @@ void gui_entry_move_words(GUI_ENTRY_REC *entry, int count, int to_space); void gui_entry_redraw(GUI_ENTRY_REC *entry); + #endif diff --git a/src/fe-text/gui-printtext.c b/src/fe-text/gui-printtext.c index 547d39c9..a07451fa 100644 --- a/src/fe-text/gui-printtext.c +++ b/src/fe-text/gui-printtext.c @@ -109,6 +109,16 @@ void gui_printtext(int xpos, int ypos, const char *str) next_xpos = next_ypos = -1; } +void gui_printtext_internal(int xpos, int ypos, const char *str) +{ + next_xpos = xpos; + next_ypos = ypos; + + printtext_gui_internal(str); + + next_xpos = next_ypos = -1; +} + void gui_printtext_after_time(TEXT_DEST_REC *dest, LINE_REC *prev, const char *str, time_t time) { GUI_WINDOW_REC *gui; @@ -159,7 +169,8 @@ static void get_colors(int flags, int *fg, int *bg, int *attr) if (*bg >= 0) { *bg = mirc_colors[*bg % 100]; flags &= ~GUI_PRINT_FLAG_COLOR_24_BG; - if (settings_get_bool("mirc_blink_fix")) { + /* ignore mirc color 99 = -1 (reset) */ + if (*bg != -1 && settings_get_bool("mirc_blink_fix")) { if (*bg < 16) /* ansi bit flip :-( */ *bg = (*bg&8) | (*bg&4)>>2 | (*bg&2) | (*bg&1)<<2; *bg = term_color256map[*bg&0xff] & 7; @@ -220,16 +231,15 @@ static void sig_gui_print_text(WINDOW_REC *window, void *fgcolor, get_colors(flags, &fg, &bg, &attr); if (window == NULL) { - g_return_if_fail(next_xpos != -1); + g_return_if_fail(next_xpos != -1); term_set_color2(root_window, attr, fg, bg); term_move(root_window, next_xpos, next_ypos); if (flags & GUI_PRINT_FLAG_CLRTOEOL) term_clrtoeol(root_window); - term_addstr(root_window, str); - next_xpos += strlen(str); /* FIXME utf8 or big5 */ - return; + next_xpos += term_addstr(root_window, str); + return; } lineinfo.level = dest == NULL ? 0 : dest->level; diff --git a/src/fe-text/gui-printtext.h b/src/fe-text/gui-printtext.h index 33b7ce6f..d2671497 100644 --- a/src/fe-text/gui-printtext.h +++ b/src/fe-text/gui-printtext.h @@ -17,6 +17,7 @@ void gui_set_default_indent(const char *name); INDENT_FUNC get_default_indent_func(void); void gui_printtext(int xpos, int ypos, const char *str); +void gui_printtext_internal(int xpos, int ypos, const char *str); void gui_printtext_after(TEXT_DEST_REC *dest, LINE_REC *prev, const char *str); void gui_printtext_after_time(TEXT_DEST_REC *dest, LINE_REC *prev, const char *str, time_t time); diff --git a/src/fe-text/gui-readline.c b/src/fe-text/gui-readline.c index 476a798b..2c2eac21 100644 --- a/src/fe-text/gui-readline.c +++ b/src/fe-text/gui-readline.c @@ -37,8 +37,12 @@ #include "gui-windows.h" #include "utf8.h" +#include <string.h> #include <signal.h> +/* After LINE_SPLIT_LIMIT characters, the message will be split into multiple lines */ +#define LINE_SPLIT_LIMIT 400 + typedef void (*ENTRY_REDIRECT_KEY_FUNC) (int key, void *data, SERVER_REC *server, WI_ITEM_REC *item); typedef void (*ENTRY_REDIRECT_ENTRY_FUNC) (const char *line, void *data, SERVER_REC *server, WI_ITEM_REC *item); @@ -60,11 +64,22 @@ static int paste_detect_time, paste_verify_line_count; static char *paste_entry; static int paste_entry_pos; static GArray *paste_buffer; +static GArray *paste_buffer_rest; static char *paste_old_prompt; static int paste_prompt, paste_line_count; static int paste_join_multiline; static int paste_timeout_id; +static int paste_use_bracketed_mode; +static int paste_bracketed_mode; +static int paste_was_bracketed_mode; +static int previous_yank_preceded; + +/* Terminal sequences that surround the input when the terminal has the + * bracketed paste mode active. Fror more details see + * https://cirw.in/blog/bracketed-paste */ +static const unichar bp_start[] = { 0x1b, '[', '2', '0', '0', '~' }; +static const unichar bp_end[] = { 0x1b, '[', '2', '0', '1', '~' }; static void sig_input(void); @@ -147,7 +162,6 @@ static void window_next_page(void) static void paste_buffer_join_lines(GArray *buf) { -#define IS_WHITE(c) ((c) == ' ' || (c) == '\t') unsigned int i, count, indent, line_len; unichar *arr, *dest, *last_lf_pos; int last_lf; @@ -177,15 +191,15 @@ static void paste_buffer_join_lines(GArray *buf) if (buf->len == 0) return; - arr = (unichar *) paste_buffer->data; + arr = (unichar *)buf->data; /* first line */ - if (IS_WHITE(arr[0])) + if (isblank(arr[0])) return; /* find the first beginning of indented line */ for (i = 1; i < buf->len; i++) { - if (arr[i-1] == '\n' && IS_WHITE(arr[i])) + if (arr[i-1] == '\n' && isblank(arr[i])) break; } if (i == buf->len) @@ -193,7 +207,7 @@ static void paste_buffer_join_lines(GArray *buf) /* get how much indentation we have.. */ for (indent = 0; i < buf->len; i++, indent++) { - if (!IS_WHITE(arr[i])) + if (!isblank(arr[i])) break; } if (i == buf->len) @@ -203,7 +217,7 @@ static void paste_buffer_join_lines(GArray *buf) count = indent; last_lf = TRUE; for (; i < buf->len; i++) { if (last_lf) { - if (IS_WHITE(arr[i])) + if (isblank(arr[i])) count++; else { last_lf = FALSE; @@ -217,14 +231,14 @@ static void paste_buffer_join_lines(GArray *buf) } /* all looks fine - now remove the whitespace, but don't let lines - get longer than 400 chars */ + get longer than LINE_SPLIT_LIMIT chars */ dest = arr; last_lf = TRUE; last_lf_pos = NULL; line_len = 0; for (i = 0; i < buf->len; i++) { - if (last_lf && IS_WHITE(arr[i])) { + if (last_lf && isblank(arr[i])) { /* whitespace, ignore */ } else if (arr[i] == '\n') { if (!last_lf && i+1 != buf->len && - IS_WHITE(arr[i+1])) { + isblank(arr[i+1])) { last_lf_pos = dest; *dest++ = ' '; } else { @@ -235,9 +249,9 @@ static void paste_buffer_join_lines(GArray *buf) last_lf = TRUE; } else { last_lf = FALSE; - if (++line_len >= 400 && last_lf_pos != NULL) { + if (++line_len >= LINE_SPLIT_LIMIT && last_lf_pos != NULL) { memmove(last_lf_pos+1, last_lf_pos, - dest - last_lf_pos); + (dest - last_lf_pos) * sizeof(unichar)); *last_lf_pos = '\n'; last_lf_pos = NULL; line_len = 0; dest++; @@ -248,9 +262,16 @@ static void paste_buffer_join_lines(GArray *buf) g_array_set_size(buf, dest - arr); } +static void paste_send_line(char *text) +{ + /* we need to get the current history every time because it might change between calls */ + command_history_add(command_history_current(active_win), text); + + signal_emit("send command", 3, text, active_win->active_server, active_win->active); +} + static void paste_send(void) { - HISTORY_REC *history; unichar *arr; GString *str; char out[10], *text; @@ -275,11 +296,7 @@ static void paste_send(void) } text = gui_entry_get_text(active_entry); - history = command_history_current(active_win); - command_history_add(history, text); - - signal_emit("send command", 3, text, - active_win->active_server, active_win->active); + paste_send_line(text); g_free(text); } @@ -287,12 +304,7 @@ static void paste_send(void) str = g_string_new(NULL); for (; i < paste_buffer->len; i++) { if (arr[i] == '\r' || arr[i] == '\n') { - history = command_history_current(active_win); - command_history_add(history, str->str); - - signal_emit("send command", 3, str->str, - active_win->active_server, - active_win->active); + paste_send_line(str->str); g_string_truncate(str, 0); } else if (active_entry->utf8) { out[g_unichar_to_utf8(arr[i], out)] = '\0'; @@ -306,7 +318,14 @@ static void paste_send(void) } } - gui_entry_set_text(active_entry, str->str); + if (paste_was_bracketed_mode) { + /* the text before the bracket end should be sent along with the rest */ + paste_send_line(str->str); + gui_entry_set_text(active_entry, ""); + } else { + gui_entry_set_text(active_entry, str->str); + } + g_string_free(str, TRUE); } @@ -322,6 +341,12 @@ static void paste_flush(int send) paste_send(); g_array_set_size(paste_buffer, 0); + /* re-add anything that may have been after the bracketed paste end */ + if (paste_buffer_rest->len > 0) { + g_array_append_vals(paste_buffer, paste_buffer_rest->data, paste_buffer_rest->len); + g_array_set_size(paste_buffer_rest, 0); + } + gui_entry_set_prompt(active_entry, paste_old_prompt == NULL ? "" : paste_old_prompt); g_free(paste_old_prompt); paste_old_prompt = NULL; @@ -336,11 +361,24 @@ static void insert_paste_prompt(void) { char *str; + /* The actual number of lines that will show up post-line-split */ + int actual_line_count = paste_line_count; + int split_lines = paste_buffer->len / LINE_SPLIT_LIMIT; + + /* in case this prompt is happening due to line-splitting, calculate the + number of lines obtained from this. The number isn't entirely accurate; + we just choose the greater of the two since the exact value isn't + important */ + if (split_lines > paste_verify_line_count && + split_lines > paste_line_count) { + actual_line_count = split_lines; + } + paste_prompt = TRUE; paste_old_prompt = g_strdup(active_entry->prompt); printformat_window(active_win, MSGLEVEL_CLIENTNOTICE, TXT_PASTE_WARNING, - paste_line_count, + actual_line_count, active_win->active == NULL ? "window" : active_win->active->visible_name); @@ -392,9 +430,9 @@ static void sig_gui_key_pressed(gpointer keyp) str[g_unichar_to_utf8(key, str)] = '\0'; } - if (strcmp(str, "^") == 0) { - /* change it as ^^ */ - str[1] = '^'; + if (g_strcmp0(str, "^") == 0) { + /* change it as ^-, that is an invalid control char */ + str[1] = '-'; str[2] = '\0'; } @@ -403,11 +441,20 @@ static void sig_gui_key_pressed(gpointer keyp) gui_entry_insert_char(active_entry, key); ret = 1; } else { + previous_yank_preceded = active_entry->yank_preceded; + active_entry->yank_preceded = FALSE; + active_entry->previous_append_next_kill = active_entry->append_next_kill; + active_entry->append_next_kill = FALSE; ret = key_pressed(keyboard, str); if (ret < 0) { /* key wasn't used for anything, print it */ gui_entry_insert_char(active_entry, key); } + if (ret == 0) { + /* combo not complete, ignore append_next_kill and yank_preceded */ + active_entry->append_next_kill = active_entry->previous_append_next_kill; + active_entry->yank_preceded = previous_yank_preceded; + } } /* ret = 0 : some key create multiple characters - we're in the middle @@ -435,22 +482,21 @@ static void key_send_line(void) add_history = *str != '\0'; history = command_history_current(active_win); + if (redir != NULL && redir->flags & ENTRY_REDIRECT_FLAG_HIDDEN) + add_history = 0; + + if (add_history && history != NULL) { + command_history_add(history, str); + } + if (redir == NULL) { signal_emit("send command", 3, str, active_win->active_server, active_win->active); } else { - if (redir->flags & ENTRY_REDIRECT_FLAG_HIDDEN) - add_history = 0; handle_entry_redirect(str); } - if (add_history) { - history = command_history_find(history); - if (history != NULL) - command_history_add(history, str); - } - if (active_entry != NULL) gui_entry_set_text(active_entry, ""); command_history_clear_pos(active_win); @@ -527,7 +573,7 @@ static void key_forward_to_space(void) static void key_erase_line(void) { gui_entry_set_pos(active_entry, active_entry->text_len); - gui_entry_erase(active_entry, active_entry->text_len, TRUE); + gui_entry_erase(active_entry, active_entry->text_len, CUTBUFFER_UPDATE_REPLACE); } static void key_erase_to_beg_of_line(void) @@ -535,7 +581,7 @@ static void key_erase_to_beg_of_line(void) int pos; pos = gui_entry_get_pos(active_entry); - gui_entry_erase(active_entry, pos, TRUE); + gui_entry_erase(active_entry, pos, CUTBUFFER_UPDATE_PREPEND); } static void key_erase_to_end_of_line(void) @@ -544,7 +590,7 @@ static void key_erase_to_end_of_line(void) pos = gui_entry_get_pos(active_entry); gui_entry_set_pos(active_entry, active_entry->text_len); - gui_entry_erase(active_entry, active_entry->text_len - pos, TRUE); + gui_entry_erase(active_entry, active_entry->text_len - pos, CUTBUFFER_UPDATE_APPEND); } static void key_yank_from_cutbuffer(void) @@ -554,7 +600,32 @@ static void key_yank_from_cutbuffer(void) cutbuffer = gui_entry_get_cutbuffer(active_entry); if (cutbuffer != NULL) { gui_entry_insert_text(active_entry, cutbuffer); - g_free(cutbuffer); + active_entry->yank_preceded = TRUE; + g_free(cutbuffer); + } +} + +static void key_yank_next_cutbuffer(void) +{ + GUI_ENTRY_CUTBUFFER_REC *rec; + guint length = 0; + char *cutbuffer; + + if (!previous_yank_preceded) + return; + + if (active_entry->kill_ring == NULL) + return; + + rec = active_entry->kill_ring->data; + if (rec != NULL) length = rec->cutbuffer_len; + + cutbuffer = gui_entry_get_next_cutbuffer(active_entry); + if (cutbuffer != NULL) { + gui_entry_erase(active_entry, length, CUTBUFFER_UPDATE_NOOP); + gui_entry_insert_text(active_entry, cutbuffer); + active_entry->yank_preceded = TRUE; + g_free(cutbuffer); } } @@ -591,32 +662,44 @@ static void key_delete_character(void) static void key_backspace(void) { - gui_entry_erase(active_entry, 1, FALSE); + gui_entry_erase(active_entry, 1, CUTBUFFER_UPDATE_NOOP); } static void key_delete_previous_word(void) { - gui_entry_erase_word(active_entry, FALSE); + gui_entry_erase_word(active_entry, FALSE, CUTBUFFER_UPDATE_PREPEND); } static void key_delete_next_word(void) { - gui_entry_erase_next_word(active_entry, FALSE); + gui_entry_erase_next_word(active_entry, FALSE, CUTBUFFER_UPDATE_APPEND); } static void key_delete_to_previous_space(void) { - gui_entry_erase_word(active_entry, TRUE); + gui_entry_erase_word(active_entry, TRUE, CUTBUFFER_UPDATE_PREPEND); } static void key_delete_to_next_space(void) { - gui_entry_erase_next_word(active_entry, TRUE); + gui_entry_erase_next_word(active_entry, TRUE, CUTBUFFER_UPDATE_APPEND); +} + +static void key_append_next_kill(void) +{ + active_entry->append_next_kill = TRUE; } static gboolean paste_timeout(gpointer data) { - if (paste_line_count == 0) { + int split_lines; + paste_was_bracketed_mode = paste_bracketed_mode; + + /* number of lines after splitting extra-long messages */ + split_lines = paste_buffer->len / LINE_SPLIT_LIMIT; + + /* Take into account the fact that a line may be split every LINE_SPLIT_LIMIT characters */ + if (paste_line_count == 0 && split_lines <= paste_verify_line_count) { int i; for (i = 0; i < paste_buffer->len; i++) { @@ -625,8 +708,9 @@ static gboolean paste_timeout(gpointer data) } g_array_set_size(paste_buffer, 0); } else if (paste_verify_line_count > 0 && - paste_line_count >= paste_verify_line_count && - active_win->active != NULL) + (paste_line_count >= paste_verify_line_count || + split_lines > paste_verify_line_count) && + active_win->active != NULL) insert_paste_prompt(); else paste_flush(TRUE); @@ -634,6 +718,70 @@ static gboolean paste_timeout(gpointer data) return FALSE; } +static void paste_bracketed_end(int i, gboolean rest) +{ + unichar last_char; + + /* if there's stuff after the end bracket, save it for later */ + if (rest) { + unichar *start = ((unichar *) paste_buffer->data) + i + G_N_ELEMENTS(bp_end); + int len = paste_buffer->len - i - G_N_ELEMENTS(bp_end); + + g_array_set_size(paste_buffer_rest, 0); + g_array_append_vals(paste_buffer_rest, start, len); + } + + /* remove the rest, including the trailing sequence chars */ + g_array_set_size(paste_buffer, i); + + last_char = g_array_index(paste_buffer, unichar, i - 1); + + if (paste_line_count > 0 && last_char != '\n' && last_char != '\r') { + /* there are newlines, but there's also stuff after the newline + * adjust line count to reflect this */ + paste_line_count++; + } + + /* decide what to do with the buffer */ + paste_timeout(NULL); + + paste_bracketed_mode = FALSE; +} + +static void paste_bracketed_middle() +{ + int i; + int marklen = G_N_ELEMENTS(bp_end); + int len = paste_buffer->len - marklen; + unichar *ptr = (unichar *) paste_buffer->data; + + if (len < 0) { + return; + } + + for (i = 0; i <= len; i++, ptr++) { + if (ptr[0] == bp_end[0] && memcmp(ptr, bp_end, sizeof(bp_end)) == 0) { + + /* if there are at least 6 bytes after the end, + * check for another start marker right afterwards */ + if (i <= (len - marklen) && + memcmp(ptr + marklen, bp_start, sizeof(bp_start)) == 0) { + + /* remove both markers*/ + g_array_remove_range(paste_buffer, i, marklen * 2); + len -= marklen * 2; + + /* go one step back */ + i--; + ptr--; + continue; + } + paste_bracketed_end(i, i != len); + break; + } + } +} + static void sig_input(void) { if (!active_entry) { @@ -647,21 +795,37 @@ static void sig_input(void) unichar key; term_gets(buffer, &line_count); key = g_array_index(buffer, unichar, 0); + /* Either Ctrl-k or Ctrl-c is pressed */ if (key == 11 || key == 3) paste_flush(key == 11); g_array_free(buffer, TRUE); } else { term_gets(paste_buffer, &paste_line_count); - if (paste_detect_time > 0 && paste_buffer->len >= 3) { + + /* use the bracketed paste mode to detect when the user pastes + * some text into the entry */ + if (paste_bracketed_mode) { + paste_bracketed_middle(); + + } else if (!paste_use_bracketed_mode && paste_detect_time > 0 && paste_buffer->len >= 3) { if (paste_timeout_id != -1) g_source_remove(paste_timeout_id); paste_timeout_id = g_timeout_add(paste_detect_time, paste_timeout, NULL); - } else { + } else if (!paste_bracketed_mode) { int i; for (i = 0; i < paste_buffer->len; i++) { unichar key = g_array_index(paste_buffer, unichar, i); signal_emit("gui key pressed", 1, GINT_TO_POINTER(key)); + + if (paste_bracketed_mode) { + /* just enabled by the signal, remove what was processed so far */ + g_array_remove_range(paste_buffer, 0, i + 1); + + /* handle single-line / small pastes here */ + paste_bracketed_middle(); + return; + } } g_array_set_size(paste_buffer, 0); paste_line_count = 0; @@ -669,6 +833,11 @@ static void sig_input(void) } } +static void key_paste_start(void) +{ + paste_bracketed_mode = TRUE; +} + time_t get_idle_time(void) { return last_keypress.tv_sec; @@ -930,6 +1099,11 @@ static void setup_changed(void) paste_verify_line_count = settings_get_int("paste_verify_line_count"); paste_join_multiline = settings_get_bool("paste_join_multiline"); + paste_use_bracketed_mode = settings_get_bool("paste_use_bracketed_mode"); + + term_set_appkey_mode(settings_get_bool("term_appkey_mode")); + /* Enable the bracketed paste mode on demand */ + term_set_bracketed_paste_mode(paste_use_bracketed_mode); } void gui_readline_init(void) @@ -943,13 +1117,17 @@ void gui_readline_init(void) paste_entry = NULL; paste_entry_pos = 0; paste_buffer = g_array_new(FALSE, FALSE, sizeof(unichar)); + paste_buffer_rest = g_array_new(FALSE, FALSE, sizeof(unichar)); paste_old_prompt = NULL; paste_timeout_id = -1; + paste_bracketed_mode = FALSE; g_get_current_time(&last_keypress); input_listen_init(STDIN_FILENO); + settings_add_bool("lookandfeel", "term_appkey_mode", TRUE); settings_add_str("history", "scroll_page_count", "/2"); settings_add_time("misc", "paste_detect_time", "5msecs"); + settings_add_bool("misc", "paste_use_bracketed_mode", FALSE); /* NOTE: function keys can generate at least 5 characters long keycodes. this must be larger to allow them to work. */ settings_add_int("misc", "paste_verify_line_count", 5); @@ -1020,6 +1198,10 @@ void gui_readline_init(void) key_bind("key", NULL, "meta2-5F", "cend", (SIGNAL_FUNC) key_combo); key_bind("key", NULL, "meta2-1;5F", "cend", (SIGNAL_FUNC) key_combo); + key_bind("key", NULL, "meta-O-M", "return", (SIGNAL_FUNC) key_combo); + + key_bind("paste_start", "Bracketed paste start", "meta2-200~", "paste_start", (SIGNAL_FUNC) key_paste_start); + /* cursor movement */ key_bind("backward_character", "Move the cursor a character backward", "left", NULL, (SIGNAL_FUNC) key_backward_character); key_bind("forward_character", "Move the cursor a character forward", "right", NULL, (SIGNAL_FUNC) key_forward_character); @@ -1050,6 +1232,8 @@ void gui_readline_init(void) key_bind("erase_to_beg_of_line", "Erase everything before the cursor", NULL, NULL, (SIGNAL_FUNC) key_erase_to_beg_of_line); key_bind("erase_to_end_of_line", "Erase everything after the cursor", "^K", NULL, (SIGNAL_FUNC) key_erase_to_end_of_line); key_bind("yank_from_cutbuffer", "\"Undelete\", paste the last deleted text", "^Y", NULL, (SIGNAL_FUNC) key_yank_from_cutbuffer); + key_bind("yank_next_cutbuffer", "Revert to the previous last deleted text", NULL, NULL, (SIGNAL_FUNC) key_yank_next_cutbuffer); + key_bind("append_next_kill", "Append next deletion", NULL, NULL, (SIGNAL_FUNC) key_append_next_kill); key_bind("transpose_characters", "Swap current and previous character", "^T", NULL, (SIGNAL_FUNC) key_transpose_characters); key_bind("transpose_words", "Swap current and previous word", NULL, NULL, (SIGNAL_FUNC) key_transpose_words); key_bind("capitalize_word", "Capitalize the current word", NULL, NULL, (SIGNAL_FUNC) key_capitalize_word); @@ -1115,6 +1299,8 @@ void gui_readline_deinit(void) key_configure_freeze(); + key_unbind("paste_start", (SIGNAL_FUNC) key_paste_start); + key_unbind("backward_character", (SIGNAL_FUNC) key_backward_character); key_unbind("forward_character", (SIGNAL_FUNC) key_forward_character); key_unbind("backward_word", (SIGNAL_FUNC) key_backward_word); @@ -1137,6 +1323,8 @@ void gui_readline_deinit(void) key_unbind("erase_to_beg_of_line", (SIGNAL_FUNC) key_erase_to_beg_of_line); key_unbind("erase_to_end_of_line", (SIGNAL_FUNC) key_erase_to_end_of_line); key_unbind("yank_from_cutbuffer", (SIGNAL_FUNC) key_yank_from_cutbuffer); + key_unbind("yank_next_cutbuffer", (SIGNAL_FUNC) key_yank_next_cutbuffer); + key_unbind("append_next_kill", (SIGNAL_FUNC) key_append_next_kill); key_unbind("transpose_characters", (SIGNAL_FUNC) key_transpose_characters); key_unbind("transpose_words", (SIGNAL_FUNC) key_transpose_words); @@ -1172,6 +1360,7 @@ void gui_readline_deinit(void) key_unbind("stop_irc", (SIGNAL_FUNC) key_sig_stop); keyboard_destroy(keyboard); g_array_free(paste_buffer, TRUE); + g_array_free(paste_buffer_rest, TRUE); key_configure_thaw(); diff --git a/src/fe-text/gui-windows.c b/src/fe-text/gui-windows.c index 4213149d..c63c495c 100644 --- a/src/fe-text/gui-windows.c +++ b/src/fe-text/gui-windows.c @@ -49,6 +49,7 @@ static GUI_WINDOW_REC *gui_window_init(WINDOW_REC *window, settings_get_int("indent"), !settings_get_bool("indent_always"), get_default_indent_func()); + textbuffer_view_set_break_wide(gui->view, settings_get_bool("break_wide")); if (parent->active == window) textbuffer_view_set_window(gui->view, parent->screen_win); return gui; @@ -201,12 +202,14 @@ void gui_windows_reset_settings(void) for (tmp = windows; tmp != NULL; tmp = tmp->next) { WINDOW_REC *rec = tmp->data; - GUI_WINDOW_REC *gui = WINDOW_GUI(rec); + GUI_WINDOW_REC *gui = WINDOW_GUI(rec); - textbuffer_view_set_default_indent(gui->view, + textbuffer_view_set_break_wide(gui->view, settings_get_bool("break_wide")); + + textbuffer_view_set_default_indent(gui->view, settings_get_int("indent"), !settings_get_bool("indent_always"), - get_default_indent_func()); + get_default_indent_func()); textbuffer_view_set_scroll(gui->view, gui->use_scroll ? gui->scroll : @@ -281,6 +284,7 @@ void gui_windows_init(void) settings_add_bool("lookandfeel", "autostick_split_windows", TRUE); settings_add_int("lookandfeel", "indent", 10); settings_add_bool("lookandfeel", "indent_always", FALSE); + settings_add_bool("lookandfeel", "break_wide", FALSE); settings_add_bool("lookandfeel", "scroll", TRUE); window_create_override = -1; diff --git a/src/fe-text/irssi.c b/src/fe-text/irssi.c index c0524247..ad79e0c4 100644 --- a/src/fe-text/irssi.c +++ b/src/fe-text/irssi.c @@ -74,10 +74,7 @@ void mainwindow_activity_deinit(void); void mainwindows_layout_init(void); void mainwindows_layout_deinit(void); -void term_dummy_init(void); -void term_dummy_deinit(void); - -static int dirty, full_redraw, dummy; +static int dirty, full_redraw; static GMainLoop *main_loop; int quitting; @@ -122,7 +119,7 @@ void irssi_set_dirty(void) static void dirty_check(void) { - if (!dirty || dummy) + if (!dirty) return; term_resize_dirty(); @@ -171,27 +168,22 @@ static void textui_finish_init(void) { quitting = FALSE; - if (dummy) - term_dummy_init(); - else { - term_refresh_freeze(); - textbuffer_init(); - textbuffer_view_init(); - textbuffer_commands_init(); - gui_expandos_init(); - gui_printtext_init(); - gui_readline_init(); - lastlog_init(); - mainwindows_init(); - mainwindow_activity_init(); - mainwindows_layout_init(); - gui_windows_init(); - statusbar_init(); - term_refresh_thaw(); - - /* don't check settings with dummy mode */ - settings_check(); - } + term_refresh_freeze(); + textbuffer_init(); + textbuffer_view_init(); + textbuffer_commands_init(); + gui_expandos_init(); + gui_printtext_init(); + gui_readline_init(); + lastlog_init(); + mainwindows_init(); + mainwindow_activity_init(); + mainwindows_layout_init(); + gui_windows_init(); + statusbar_init(); + term_refresh_thaw(); + + settings_check(); module_register("core", "fe-text"); @@ -233,25 +225,21 @@ static void textui_deinit(void) dirty_check(); /* one last time to print any quit messages */ signal_remove("gui exit", (SIGNAL_FUNC) sig_exit); - if (dummy) - term_dummy_deinit(); - else { - lastlog_deinit(); - statusbar_deinit(); - gui_printtext_deinit(); - gui_readline_deinit(); - gui_windows_deinit(); - mainwindows_layout_deinit(); - mainwindow_activity_deinit(); - mainwindows_deinit(); - gui_expandos_deinit(); - textbuffer_commands_deinit(); - textbuffer_view_deinit(); - textbuffer_deinit(); - - term_refresh_thaw(); - term_deinit(); - } + lastlog_deinit(); + statusbar_deinit(); + gui_printtext_deinit(); + gui_readline_deinit(); + gui_windows_deinit(); + mainwindows_layout_deinit(); + mainwindow_activity_deinit(); + mainwindows_deinit(); + gui_expandos_deinit(); + textbuffer_commands_deinit(); + textbuffer_view_deinit(); + textbuffer_deinit(); + + term_refresh_thaw(); + term_deinit(); theme_unregister(); @@ -271,49 +259,15 @@ static void check_files(void) } } -#ifdef WIN32 -static void winsock_init(void) -{ - WORD wVersionRequested; - WSADATA wsaData; - - wVersionRequested = MAKEWORD(2, 2); - - if (WSAStartup(wVersionRequested, &wsaData) != 0) { - printf("Error initializing winsock\n"); - exit(1); - } -} -#endif - -#ifdef USE_GC -#ifdef HAVE_GC_H -# include <gc.h> -#else -# include <gc/gc.h> -#endif - -GMemVTable gc_mem_table = { - GC_malloc, - GC_realloc, - GC_free, - - NULL, NULL, NULL -}; -#endif int main(int argc, char **argv) { static int version = 0; static GOptionEntry options[] = { - { "dummy", 'd', 0, G_OPTION_ARG_NONE, &dummy, "Use the dummy terminal mode", NULL }, { "version", 'v', 0, G_OPTION_ARG_NONE, &version, "Display irssi version", NULL }, { NULL } }; - -#ifdef USE_GC - g_mem_set_vtable(&gc_mem_table); -#endif + int loglev; core_register_options(); fe_common_core_register_options(); @@ -328,15 +282,11 @@ int main(int argc, char **argv) srand(time(NULL)); - dummy = FALSE; quitting = FALSE; core_preinit(argv[0]); check_files(); -#ifdef WIN32 - winsock_init(); -#endif #ifdef HAVE_SOCKS SOCKSinit(argv[0]); #endif @@ -346,32 +296,30 @@ int main(int argc, char **argv) before this call. locales aren't actually used for anything else than autodetection - of UTF-8 currently.. + of UTF-8 currently.. - furthermore to get the users's charset with g_get_charset() properly + furthermore to get the users's charset with g_get_charset() properly you have to call setlocale(LC_ALL, "") */ setlocale(LC_ALL, ""); + loglev = g_log_set_always_fatal(G_LOG_FATAL_MASK | G_LOG_LEVEL_CRITICAL); textui_init(); - if (!dummy && !term_init()) { - fprintf(stderr, "Can't initialize screen handling, quitting.\n"); - fprintf(stderr, "You can still use the dummy mode with -d parameter\n"); + if (!term_init()) { + fprintf(stderr, "Can't initialize screen handling.\n"); return 1; } + g_log_set_always_fatal(loglev); textui_finish_init(); main_loop = g_main_new(TRUE); /* Does the same as g_main_run(main_loop), except we can call our dirty-checker after each iteration */ while (!quitting) { -#ifdef USE_GC - GC_collect_a_little(); -#endif - if (!dummy) term_refresh_freeze(); + term_refresh_freeze(); g_main_iteration(TRUE); - if (!dummy) term_refresh_thaw(); + term_refresh_thaw(); if (reload_config) { /* SIGHUP received, do /RELOAD */ diff --git a/src/fe-text/lastlog.c b/src/fe-text/lastlog.c index 417eb484..c0b1dde8 100644 --- a/src/fe-text/lastlog.c +++ b/src/fe-text/lastlog.c @@ -39,21 +39,10 @@ Returns -1 if unknown option was given. */ int cmd_options_get_level(const char *cmd, GHashTable *optlist) { - GSList *list, *tmp, *next; + GList *list; int level, retlevel; - /* get all the options, then remove the known ones. there should - be only one left - the server tag. */ - list = hashtable_get_keys(optlist); - if (cmd != NULL) { - for (tmp = list; tmp != NULL; tmp = next) { - char *option = tmp->data; - next = tmp->next; - - if (command_have_option(cmd, option)) - list = g_slist_remove(list, option); - } - } + list = optlist_remove_known(cmd, optlist); retlevel = 0; while (list != NULL) { @@ -68,12 +57,31 @@ int cmd_options_get_level(const char *cmd, GHashTable *optlist) } retlevel |= level; - list = g_slist_remove(list, list->data); + list = g_list_remove(list, list->data); } return retlevel; } +static void prepend_date(WINDOW_REC *window, LINE_REC *rec, GString *line) +{ + THEME_REC *theme = NULL; + TEXT_DEST_REC dest = {0}; + char *format = NULL, datestamp[20] = {0}; + struct tm *tm = localtime(&rec->info.time); + int ret = 0; + + theme = window->theme != NULL ? window->theme : current_theme; + format_create_dest(&dest, NULL, NULL, MSGLEVEL_LASTLOG, window); + format = format_get_text_theme(theme, MODULE_NAME, &dest, TXT_LASTLOG_DATE); + + ret = strftime(datestamp, sizeof(datestamp), format, tm); + g_free(format); + if (ret <= 0) return; + + g_string_prepend(line, datestamp); +} + static void show_lastlog(const char *searchtext, GHashTable *optlist, int start, int count, FILE *fhandle) { @@ -82,7 +90,7 @@ static void show_lastlog(const char *searchtext, GHashTable *optlist, GList *list, *tmp; GString *line; char *str; - int level, before, after, len; + int level, before, after, len, date = FALSE; level = cmd_options_get_level("lastlog", optlist); if (level == -1) return; /* error in options */ @@ -132,6 +140,9 @@ static void show_lastlog(const char *searchtext, GHashTable *optlist, atoi(str) : DEFAULT_LASTLOG_AFTER; } + if (g_hash_table_lookup(optlist, "date") != NULL) + date = TRUE; + list = textbuffer_find_text(WINDOW_GUI(window)->view->buffer, startline, level, MSGLEVEL_LASTLOG, searchtext, before, after, @@ -199,6 +210,9 @@ static void show_lastlog(const char *searchtext, GHashTable *optlist, g_string_prepend(line, timestamp); } + if (date == TRUE) + prepend_date(window, rec, line); + /* write to file/window */ if (fhandle != NULL) { fwrite(line->str, line->len, 1, fhandle); @@ -223,7 +237,7 @@ static void show_lastlog(const char *searchtext, GHashTable *optlist, } /* SYNTAX: LASTLOG [-] [-file <filename>] [-window <ref#|name>] [-new | -away] - [-<level> -<level...>] [-clear] [-count] [-case] + [-<level> -<level...>] [-clear] [-count] [-case] [-date] [-regexp | -word] [-before [<#>]] [-after [<#>]] [-<# before+after>] [<pattern>] [<count> [<start>]] */ static void cmd_lastlog(const char *data) @@ -285,7 +299,7 @@ void lastlog_init(void) { command_bind("lastlog", NULL, (SIGNAL_FUNC) cmd_lastlog); - command_set_options("lastlog", "!- # force clear -file -window new away word regexp case count @a @after @before"); + command_set_options("lastlog", "!- # force clear -file -window new away word regexp case count date @a @after @before"); } void lastlog_deinit(void) diff --git a/src/fe-text/mainwindows-layout.c b/src/fe-text/mainwindows-layout.c index 28fae924..020969e6 100644 --- a/src/fe-text/mainwindows-layout.c +++ b/src/fe-text/mainwindows-layout.c @@ -70,7 +70,7 @@ static void main_window_save(MAIN_WINDOW_REC *window, CONFIG_NODE *node) char num[MAX_INT_STRLEN]; ltoa(num, window->active->refnum); - node = config_node_section(node, num, NODE_TYPE_BLOCK); + node = iconfig_node_section(node, num, NODE_TYPE_BLOCK); iconfig_node_set_int(node, "first_line", window->first_line); iconfig_node_set_int(node, "lines", window->height); @@ -179,6 +179,7 @@ static void sig_layout_restore(void) lower_window = NULL; lower_size = 0; for (i = 0, tmp = sorted_config; i < windows_count; tmp = tmp->next, i++) { CONFIG_NODE *node = tmp->data; + if (node->key == NULL) continue; /* create a new window + mainwindow */ signal_emit("gui window create override", 1, diff --git a/src/fe-text/module-formats.c b/src/fe-text/module-formats.c index 1d905095..899827c2 100644 --- a/src/fe-text/module-formats.c +++ b/src/fe-text/module-formats.c @@ -33,6 +33,7 @@ FORMAT_REC gui_text_formats[] = { "lastlog_start", "{hilight Lastlog}:", 0 }, { "lastlog_end", "{hilight End of Lastlog}", 0 }, { "lastlog_separator", "--", 0 }, + { "lastlog_date", "%%F ", 0 }, /* ---- */ { NULL, "Windows", 0 }, diff --git a/src/fe-text/module-formats.h b/src/fe-text/module-formats.h index 4eebfc3e..3fa8c511 100644 --- a/src/fe-text/module-formats.h +++ b/src/fe-text/module-formats.h @@ -10,6 +10,7 @@ enum { TXT_LASTLOG_START, TXT_LASTLOG_END, TXT_LASTLOG_SEPARATOR, + TXT_LASTLOG_DATE, TXT_FILL_2, diff --git a/src/fe-text/statusbar-config.c b/src/fe-text/statusbar-config.c index deaa1b5d..48f4aa61 100644 --- a/src/fe-text/statusbar-config.c +++ b/src/fe-text/statusbar-config.c @@ -95,7 +95,7 @@ statusbar_config_find(STATUSBAR_GROUP_REC *group, const char *name) for (tmp = group->config_bars; tmp != NULL; tmp = tmp->next) { STATUSBAR_CONFIG_REC *config = tmp->data; - if (strcmp(config->name, name) == 0) + if (g_strcmp0(config->name, name) == 0) return config; } @@ -137,7 +137,7 @@ static void statusbar_read_item(STATUSBAR_CONFIG_REC *bar, CONFIG_NODE *node) int priority, right_alignment; priority = config_node_get_int(node, "priority", 0); - right_alignment = strcmp(config_node_get_str(node, "alignment", ""), "right") == 0; + right_alignment = g_strcmp0(config_node_get_str(node, "alignment", ""), "right") == 0; statusbar_item_config_create(bar, node->key, priority, right_alignment); } @@ -177,7 +177,7 @@ static void statusbar_read(STATUSBAR_GROUP_REC *group, CONFIG_NODE *node) bar->placement = STATUSBAR_TOP; bar->position = config_node_get_int(node, "position", 0); - node = config_node_section(node, "items", -1); + node = iconfig_node_section(node, "items", -1); if (node != NULL) { /* we're overriding the items - destroy the old */ while (bar->items != NULL) @@ -194,6 +194,8 @@ static void statusbar_read_group(CONFIG_NODE *node) STATUSBAR_GROUP_REC *group; GSList *tmp; + g_return_if_fail(is_node_list(node)); + group = statusbar_group_find(node->key); if (group == NULL) { group = statusbar_group_create(node->key); @@ -227,7 +229,7 @@ static void read_statusbar_config_from_node(CONFIG_NODE *node) CONFIG_NODE *items; GSList *tmp; - items = config_node_section(node, "items", -1); + items = iconfig_node_section(node, "items", -1); if (items != NULL) statusbar_read_items(items); @@ -369,7 +371,7 @@ static void cmd_statusbar_reset(const char *data, void *server, CONFIG_NODE *parent; parent = iconfig_node_traverse("statusbar", TRUE); - parent = config_node_section(parent, active_statusbar_group->name, + parent = iconfig_node_section(parent, active_statusbar_group->name, NODE_TYPE_BLOCK); iconfig_node_set_str(parent, node->key, NULL); @@ -432,7 +434,7 @@ static CONFIG_NODE *statusbar_items_section(CONFIG_NODE *parent) CONFIG_NODE *node; GSList *tmp; - node = config_node_section(parent, "items", -1); + node = iconfig_node_section(parent, "items", -1); if (node != NULL) return node; @@ -446,11 +448,11 @@ static CONFIG_NODE *statusbar_items_section(CONFIG_NODE *parent) /* since items list in config file overrides defaults, we'll need to copy the whole list. */ - parent = config_node_section(parent, "items", NODE_TYPE_BLOCK); + parent = iconfig_node_section(parent, "items", NODE_TYPE_BLOCK); for (tmp = bar->items; tmp != NULL; tmp = tmp->next) { SBAR_ITEM_CONFIG_REC *rec = tmp->data; - node = config_node_section(parent, rec->name, + node = iconfig_node_section(parent, rec->name, NODE_TYPE_BLOCK); if (rec->priority != 0) iconfig_node_set_int(node, "priority", rec->priority); @@ -487,7 +489,7 @@ static void cmd_statusbar_add(const char *data, void *server, if (value != NULL) index = config_node_index(node, value)+1; /* create/move item */ - node = config_node_section_index(node, name, index, NODE_TYPE_BLOCK); + node = iconfig_node_section_index(node, name, index, NODE_TYPE_BLOCK); /* set the options */ value = g_hash_table_lookup(optlist, "priority"); @@ -511,7 +513,7 @@ static void cmd_statusbar_remove(const char *data, void *server, if (node == NULL) return; - if (config_node_section(node, data, -1) != NULL) + if (iconfig_node_section(node, data, -1) != NULL) iconfig_node_set_str(node, data, NULL); else { printformat(NULL, NULL, MSGLEVEL_CLIENTERROR, @@ -545,9 +547,9 @@ static void cmd_statusbar(const char *data) /* lookup/create the statusbar node */ node = iconfig_node_traverse("statusbar", TRUE); - node = config_node_section(node, active_statusbar_group->name, + node = iconfig_node_section(node, active_statusbar_group->name, NODE_TYPE_BLOCK); - node = config_node_section(node, name, NODE_TYPE_BLOCK); + node = iconfig_node_section(node, name, NODE_TYPE_BLOCK); /* call the subcommand */ signal = g_strconcat("command statusbar ", cmd, NULL); diff --git a/src/fe-text/statusbar-items.c b/src/fe-text/statusbar-items.c index 044c2fa0..de4499b4 100644 --- a/src/fe-text/statusbar-items.c +++ b/src/fe-text/statusbar-items.c @@ -143,16 +143,34 @@ static char *get_activity_list(MAIN_WINDOW_REC *window, int normal, int hilight) static void item_act(SBAR_ITEM_REC *item, int get_size_only) { char *actlist; + int max_size; + + if (get_size_only) { + if (activity_list == NULL) + item->min_size = item->max_size = 0; + /* Skip activity calculation on regular trigger, only + set dirty */ + return; + } actlist = get_activity_list(item->bar->parent_window, TRUE, TRUE); if (actlist == NULL) { - if (get_size_only) - item->min_size = item->max_size = 0; return; } - statusbar_item_default_handler(item, get_size_only, + max_size = item->max_size; + statusbar_item_default_handler(item, TRUE, + NULL, actlist, FALSE); + statusbar_item_default_handler(item, FALSE, NULL, actlist, FALSE); + if (max_size != item->max_size) { + /* Due to above hack of skipping the calculation, we + need to manually trigger the redraw process now or + we won't see the item */ + item->bar->dirty = item->dirty = TRUE; + statusbar_redraw(item->bar, TRUE); + statusbar_redraw_dirty(); + } g_free_not_null(actlist); } @@ -289,6 +307,10 @@ static void sig_statusbar_more_updated(void) { int visible; + /* no active window, for example during /window hide */ + if (active_win == NULL) + return; + visible = g_slist_find(more_visible, WINDOW_MAIN(active_win)) != NULL; if (WINDOW_GUI(active_win)->view->more_text != visible) statusbar_items_redraw("more"); @@ -347,10 +369,14 @@ static void item_lag(SBAR_ITEM_REC *item, int get_size_only) last_lag_unknown = lag_unknown; if (lag_unknown) { - g_snprintf(str, sizeof(str), "%d (?""?)", lag/100); + // "??)" in C becomes ']' + // See: https://en.wikipedia.org/wiki/Digraphs_and_trigraphs#C + g_snprintf(str, sizeof(str), "%d (?""?)", lag / 100); } else { - g_snprintf(str, sizeof(str), - lag%100 == 0 ? "%d" : "%d.%02d", lag/100, lag%100); + if (lag % 100 == 0) + g_snprintf(str, sizeof(str), "%d", lag / 100); + else + g_snprintf(str, sizeof(str), "%d.%02d", lag / 100, lag % 100); } statusbar_item_default_handler(item, get_size_only, diff --git a/src/fe-text/statusbar.c b/src/fe-text/statusbar.c index ef5abc55..f0dff828 100644 --- a/src/fe-text/statusbar.c +++ b/src/fe-text/statusbar.c @@ -129,7 +129,7 @@ STATUSBAR_GROUP_REC *statusbar_group_find(const char *name) for (tmp = statusbar_groups; tmp != NULL; tmp = tmp->next) { STATUSBAR_GROUP_REC *rec = tmp->data; - if (strcmp(rec->name, name) == 0) + if (g_strcmp0(rec->name, name) == 0) return rec; } @@ -617,7 +617,7 @@ STATUSBAR_REC *statusbar_find(STATUSBAR_GROUP_REC *group, const char *name, STATUSBAR_REC *rec = tmp->data; if (rec->parent_window == window && - strcmp(rec->config->name, name) == 0) + g_strcmp0(rec->config->name, name) == 0) return rec; } @@ -668,11 +668,11 @@ void statusbar_item_default_handler(SBAR_ITEM_REC *item, int get_size_only, int escape_vars) { SERVER_REC *server; - WI_ITEM_REC *wiitem; + WI_ITEM_REC *wiitem; char *tmpstr, *tmpstr2; theme_rm_col reset; - strcpy(reset.m, "n"); int len; + strcpy(reset.m, "n"); if (str == NULL) str = statusbar_item_get_value(item); diff --git a/src/fe-text/term-curses.c b/src/fe-text/term-curses.c deleted file mode 100644 index 752edd7f..00000000 --- a/src/fe-text/term-curses.c +++ /dev/null @@ -1,415 +0,0 @@ -/* - term-curses.c : irssi - - Copyright (C) 1999-2001 Timo Sirainen - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -*/ - -#include "module.h" -#include "signals.h" -#include "settings.h" - -#include "term.h" -#include "mainwindows.h" - -#if defined(USE_NCURSES) && !defined(RENAMED_NCURSES) -# include <ncurses.h> -#else -# include <curses.h> -#endif -#include <termios.h> -#include <signal.h> - -#ifndef COLOR_PAIRS -# define COLOR_PAIRS 64 -#endif - -#if defined (TIOCGWINSZ) && defined (HAVE_CURSES_RESIZETERM) -# define USE_RESIZE_TERM -#endif - -#ifndef _POSIX_VDISABLE -# define _POSIX_VDISABLE 0 -#endif - -struct _TERM_WINDOW { - int x, y; - int width, height; - WINDOW *win; -}; - -TERM_WINDOW *root_window; - -static int curs_x, curs_y; -static int freeze_refresh; -static struct termios old_tio; - -static int init_curses(void) -{ - char ansi_tab[8] = { 0, 4, 2, 6, 1, 5, 3, 7 }; - int num; - struct termios tio; - - if (!initscr()) - return FALSE; - - cbreak(); noecho(); idlok(stdscr, 1); -#ifdef HAVE_CURSES_IDCOK - /*idcok(stdscr, 1); - disabled currently, causes redrawing problems with NetBSD */ -#endif - intrflush(stdscr, FALSE); nodelay(stdscr, TRUE); - - /* Disable INTR, QUIT, VDSUSP and SUSP keys */ - if (tcgetattr(0, &old_tio) == 0) { - memcpy(&tio, &old_tio, sizeof(tio)); - tio.c_cc[VINTR] = _POSIX_VDISABLE; - tio.c_cc[VQUIT] = _POSIX_VDISABLE; -#ifdef VDSUSP - tio.c_cc[VDSUSP] = _POSIX_VDISABLE; -#endif -#ifdef VSUSP - tio.c_cc[VSUSP] = _POSIX_VDISABLE; -#endif - tcsetattr(0, TCSADRAIN, &tio); - } - - if (has_colors()) - start_color(); - else if (term_use_colors) - term_use_colors = FALSE; - -#ifdef HAVE_NCURSES_USE_DEFAULT_COLORS - /* this lets us to use the "default" background color for colors <= 7 so - background pixmaps etc. show up right */ - use_default_colors(); - - for (num = 1; num < COLOR_PAIRS; num++) - init_pair(num, ansi_tab[num & 7], num <= 7 ? -1 : ansi_tab[num >> 3]); - - init_pair(63, 0, -1); /* hm.. not THAT good idea, but probably more - people want dark grey than white on white.. */ -#else - for (num = 1; num < COLOR_PAIRS; num++) - init_pair(num, ansi_tab[num & 7], ansi_tab[num >> 3]); - init_pair(63, 0, 0); -#endif - - clear(); - return TRUE; -} - -static int term_init_int(void) -{ - int ret; - - ret = init_curses(); - if (!ret) return 0; - - curs_x = curs_y = 0; - freeze_refresh = 0; - - root_window = g_new0(TERM_WINDOW, 1); - root_window->win = stdscr; - - term_width = COLS; - term_height = LINES; - return ret; -} - -static void term_deinit_int(void) -{ - tcsetattr(0, TCSADRAIN, &old_tio); - - endwin(); - g_free_and_null(root_window); -} - -int term_init(void) -{ - if (!term_init_int()) - return FALSE; - - settings_add_int("lookandfeel", "default_color", 7); - term_common_init(); - return TRUE; -} - -void term_deinit(void) -{ - term_common_deinit(); - term_deinit_int(); -} - -/* Resize terminal - if width or height is negative, - the new size is unknown and should be figured out somehow */ -void term_resize(int width, int height) -{ -#ifdef HAVE_CURSES_RESIZETERM - if (width < 0 || height < 0) { -#endif - term_deinit_int(); - term_init_int(); -#ifdef HAVE_CURSES_RESIZETERM - } else if (term_width != width || term_height != height) { - term_width = width; - term_height = height; - resizeterm(term_height, term_width); - } -#endif -} - -void term_resize_final(int width, int height) -{ -#ifdef HAVE_CURSES_RESIZETERM - if (width < 0 || height < 0) - mainwindows_recreate(); -#else - mainwindows_recreate(); -#endif -} - -/* Returns TRUE if terminal has colors */ -int term_has_colors(void) -{ - return has_colors(); -} - -/* Force the colors on any way you can */ -void term_force_colors(int set) -{ - /* don't do anything with curses */ -} - -/* Clear screen */ -void term_clear(void) -{ - term_set_color(root_window, 0); - clear(); -} - -/* Beep */ -void term_beep(void) -{ - beep(); -} - -/* Create a new window in terminal */ -TERM_WINDOW *term_window_create(int x, int y, int width, int height) -{ - TERM_WINDOW *window; - - window = g_new0(TERM_WINDOW, 1); - window->x = x; window->y = y; - window->width = width; window->height = height; - window->win = newwin(height, width, y, x); - if (window->win == NULL) - g_error("newwin() failed: %d,%d %d,%d", x, y, width, height); - idlok(window->win, 1); - - return window; -} - -/* Destroy a terminal window */ -void term_window_destroy(TERM_WINDOW *window) -{ - delwin(window->win); - g_free(window); -} - -/* Move/resize a window */ -void term_window_move(TERM_WINDOW *window, int x, int y, - int width, int height) -{ - /* some checks to make sure the window is visible in screen, - otherwise curses could get nasty and not show our window anymore. */ - if (width < 1) width = 1; - if (height < 1) height = 1; - if (x+width > term_width) x = term_width-width; - if (y+height > term_height) y = term_height-height; - -#ifdef HAVE_CURSES_WRESIZE - if (window->width != width || window->height != height) - wresize(window->win, height, width); - if (window->x != x || window->y != y) - mvwin(window->win, y, x); -#else - if (window->width != width || window->height != height || - window->x != x || window->y != y) { - delwin(window->win); - window->win = newwin(height, width, y, x); - idlok(window->win, 1); - } -#endif - window->x = x; window->y = y; - window->width = width; window->height = height; -} - -/* Clear window */ -void term_window_clear(TERM_WINDOW *window) -{ - werase(window->win); -} - -/* Scroll window up/down */ -void term_window_scroll(TERM_WINDOW *window, int count) -{ - scrollok(window->win, TRUE); - wscrl(window->win, count); - scrollok(window->win, FALSE); -} - -static int get_attr(int color) -{ - int attr; - - if ((color & FG_MASK) >> 4) - color = (color & ~FG_MASK) | term_color256map[color & FG_MASK]; - if ((color & BG_MASK) >> (BG_SHIFT + 4)) - color = (color & ~BG_MASK) | (term_color256map[(color & BG_MASK) >> BG_SHIFT] << BG_SHIFT); - if (!term_use_colors) - attr = (color & (0x7 << BG_SHIFT)) ? A_REVERSE : 0; - else if ((color & ((0xf << BG_SHIFT) | 0xf)) == 8 || (color & (FG_MASK | BG_MASK | ATTR_RESETFG)) == 0) - attr = COLOR_PAIR(63); - else if ((color & ((0x7 << BG_SHIFT) | 0x7)) == 0) - attr = A_NORMAL; - else { - if (color & ATTR_RESETFG) { - color &= ~FG_MASK; - color |= settings_get_int("default_color"); - } - attr = COLOR_PAIR((color&0x7) | ((color&(0x7<<BG_SHIFT))>>BG_SHIFT<<3)); - } - - if ((color & 0x8) || (color & ATTR_BOLD)) attr |= A_BOLD; - if (color & ATTR_BLINK) attr |= A_BLINK; - - if (color & ATTR_UNDERLINE) attr |= A_UNDERLINE; - if (color & ATTR_REVERSE) attr |= A_REVERSE; -#ifdef A_ITALIC - if (color & ATTR_ITALIC) attr |= A_ITALIC; -#endif - return attr; -} - -/* Change active color */ -void term_set_color(TERM_WINDOW *window, int col) -{ - wattrset(window->win, get_attr(col)); - wbkgdset(window->win, ' ' | get_attr(col)); -} - -void term_move(TERM_WINDOW *window, int x, int y) -{ - wmove(window->win, y, x); -} - -void term_addch(TERM_WINDOW *window, char chr) -{ - waddch(window->win, chr); -} - -void term_add_unichar(TERM_WINDOW *window, unichar chr) -{ -#ifdef WIDEC_CURSES - cchar_t wch; - wchar_t temp[2]; - temp[0] = chr; - temp[1] = 0; - if (setcchar(&wch, temp, A_NORMAL, 0, NULL) == OK) - wadd_wch(window->win, &wch); - else -#endif - waddch(window->win, chr); -} - -void term_addstr(TERM_WINDOW *window, const char *str) -{ - waddstr(window->win, (const char *) str); -} - -void term_clrtoeol(TERM_WINDOW *window) -{ - wclrtoeol(window->win); -} - -void term_move_cursor(int x, int y) -{ - curs_x = x; - curs_y = y; -} - -void term_refresh_freeze(void) -{ - freeze_refresh++; -} - -void term_refresh_thaw(void) -{ - if (freeze_refresh > 0) { - freeze_refresh--; - if (freeze_refresh == 0) term_refresh(NULL); - } -} - -void term_refresh(TERM_WINDOW *window) -{ - if (window != NULL) - wnoutrefresh(window->win); - - if (freeze_refresh == 0) { - move(curs_y, curs_x); - wnoutrefresh(stdscr); - doupdate(); - } -} - -void term_stop(void) -{ - term_deinit_int(); - kill(getpid(), SIGTSTP); - term_init_int(); - irssi_redraw(); -} - -void term_set_input_type(int type) -{ -} - -void term_gets(GArray *buffer, int *line_count) -{ -#ifdef WIDEC_CURSES - wint_t key; -#else - int key; -#endif - - for (;;) { -#ifdef WIDEC_CURSES - if (get_wch(&key) == ERR) -#else - if ((key = getch()) == ERR) -#endif - break; -#ifdef KEY_RESIZE - if (key == KEY_RESIZE) - continue; -#endif - - g_array_append_val(buffer, key); - if (key == '\r' || key == '\n') - (*line_count)++; - } -} diff --git a/src/fe-text/term-dummy.c b/src/fe-text/term-dummy.c deleted file mode 100644 index 6a56af88..00000000 --- a/src/fe-text/term-dummy.c +++ /dev/null @@ -1,106 +0,0 @@ -/* - term-dummy.c : irssi - - Copyright (C) 2001 Timo Sirainen - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -*/ - -#include "module.h" -#include "signals.h" - -#include "fe-windows.h" - -static int newline; - -static GIOChannel *stdin_channel; -static int readtag; -static GString *input; - -static void sig_gui_printtext(WINDOW_REC *window, void *fgcolor, - void *bgcolor, void *pflags, - char *str, void *level) -{ - if (newline) { - newline = FALSE; - printf("\r"); - } - - printf("%s", str); -} - -static void sig_gui_printtext_finished(WINDOW_REC *window) -{ - printf("\n"); - newline = TRUE; -} - -static void sig_window_created(WINDOW_REC *window) -{ - window->width = 80; - window->height = 25; -} - -static void readline(void) -{ - unsigned char buffer[128]; - char *p; - int ret, i; - - ret = read(0, buffer, sizeof(buffer)); - if (ret == 0 || (ret == -1 && errno != EINTR)) { - /* lost terminal */ - signal_emit("command quit", 1, "Lost terminal"); - return; - } - - for (i = 0; i < ret; i++) - g_string_append_c(input, buffer[i]); - - p = strchr(input->str, '\n'); - if (p != NULL) { - *p = '\0'; - signal_emit("send command", 3, input->str, - active_win->active_server, active_win->active); - *p = '\n'; - g_string_erase(input, 0, (int) (p-input->str)+1); - } -} - -void term_dummy_init(void) -{ - newline = TRUE; - input = g_string_new(NULL); - - signal_add("gui print text", (SIGNAL_FUNC) sig_gui_printtext); - signal_add("gui print text finished", (SIGNAL_FUNC) sig_gui_printtext_finished); - signal_add("window created", (SIGNAL_FUNC) sig_window_created); - - stdin_channel = g_io_channel_unix_new(0); - readtag = g_input_add_full(stdin_channel, - G_PRIORITY_HIGH, G_INPUT_READ, - (GInputFunction) readline, NULL); - g_io_channel_unref(stdin_channel); -} - -void term_dummy_deinit(void) -{ - signal_remove("gui print text", (SIGNAL_FUNC) sig_gui_printtext); - signal_remove("gui print text finished", (SIGNAL_FUNC) sig_gui_printtext_finished); - signal_remove("window created", (SIGNAL_FUNC) sig_window_created); - - g_source_remove(readtag); - g_string_free(input, TRUE); -} diff --git a/src/fe-text/term-terminfo.c b/src/fe-text/term-terminfo.c index 29d3f7eb..3098a4e4 100644 --- a/src/fe-text/term-terminfo.c +++ b/src/fe-text/term-terminfo.c @@ -390,7 +390,8 @@ void term_set_color(TERM_WINDOW *window, int col) } /* set background color */ - if (window && (term_color256map[bg&0xff]&8) == window->term->TI_colors) + if (window && window->term->TI_colors && + (term_color256map[bg&0xff]&8) == window->term->TI_colors) col |= ATTR_BLINK; if (col & ATTR_BLINK) current_term->set_blink(current_term); @@ -413,7 +414,8 @@ void term_set_color(TERM_WINDOW *window, int col) terminfo_set_reverse(); /* bold */ - if (window && (term_color256map[fg&0xff]&8) == window->term->TI_colors) + if (window && window->term->TI_colors && + (term_color256map[fg&0xff]&8) == window->term->TI_colors) col |= ATTR_BOLD; if (col & ATTR_BOLD) terminfo_set_bold(); @@ -520,15 +522,43 @@ void term_add_unichar(TERM_WINDOW *window, unichar chr) } } -void term_addstr(TERM_WINDOW *window, const char *str) +int term_addstr(TERM_WINDOW *window, const char *str) { - int len; + int len, raw_len; + unichar tmp; + const char *ptr; if (vcmove) term_move_real(); - len = strlen(str); /* FIXME utf8 or big5 */ + + len = 0; + raw_len = strlen(str); + + /* The string length depends on the terminal encoding */ + + ptr = str; + + if (term_type == TERM_TYPE_UTF8) { + while (*ptr != '\0') { + tmp = g_utf8_get_char_validated(ptr, -1); + /* On utf8 error, treat as single byte and try to + continue interpretting rest of string as utf8 */ + if (tmp == (gunichar)-1 || tmp == (gunichar)-2) { + len++; + ptr++; + } else { + len += unichar_isprint(tmp) ? mk_wcwidth(tmp) : 1; + ptr = g_utf8_next_char(ptr); + } + } + } else + len = raw_len; + term_printed_text(len); - fwrite(str, 1, len, window->term->out); + /* Use strlen() here since we need the number of raw bytes */ + fwrite(str, 1, raw_len, window->term->out); + + return len; } void term_clrtoeol(TERM_WINDOW *window) @@ -588,8 +618,6 @@ void term_stop(void) { terminfo_stop(current_term); kill(getpid(), SIGTSTP); - terminfo_cont(current_term); - irssi_redraw(); } static int input_utf8(const unsigned char *buffer, int size, unichar *result) diff --git a/src/fe-text/term.h b/src/fe-text/term.h index cdcc787a..0c7847f6 100644 --- a/src/fe-text/term.h +++ b/src/fe-text/term.h @@ -27,7 +27,7 @@ typedef struct _TERM_WINDOW TERM_WINDOW; #define TERM_TYPE_UTF8 1 #define TERM_TYPE_BIG5 2 -typedef guint32 unichar; +#include "utf8.h" extern TERM_WINDOW *root_window; extern int term_width, term_height; @@ -83,7 +83,7 @@ void term_set_color(TERM_WINDOW *window, int col); void term_move(TERM_WINDOW *window, int x, int y); void term_addch(TERM_WINDOW *window, char chr); void term_add_unichar(TERM_WINDOW *window, unichar chr); -void term_addstr(TERM_WINDOW *window, const char *str); +int term_addstr(TERM_WINDOW *window, const char *str); void term_clrtoeol(TERM_WINDOW *window); void term_move_cursor(int x, int y); @@ -94,6 +94,9 @@ void term_refresh(TERM_WINDOW *window); void term_stop(void); +void term_set_appkey_mode(int enable); +void term_set_bracketed_paste_mode(int enable); + /* keyboard input handling */ void term_set_input_type(int type); void term_gets(GArray *buffer, int *line_count); diff --git a/src/fe-text/terminfo-core.c b/src/fe-text/terminfo-core.c index d16987fe..9c9179a5 100644 --- a/src/fe-text/terminfo-core.c +++ b/src/fe-text/terminfo-core.c @@ -17,7 +17,6 @@ inline static int term_putchar(int c) char *tparm(); int tputs(); -#ifdef HAVE_TERMINFO int setupterm(); char *tigetstr(); int tigetnum(); @@ -25,15 +24,6 @@ int tigetflag(); #define term_getstr(x, buffer) tigetstr(x.ti_name) #define term_getnum(x) tigetnum(x.ti_name); #define term_getflag(x) tigetflag(x.ti_name); -#else -int tgetent(); -char *tgetstr(); -int tgetnum(); -int tgetflag(); -#define term_getstr(x, buffer) tgetstr(x.tc_name, &buffer) -#define term_getnum(x) tgetnum(x.tc_name) -#define term_getflag(x) tgetflag(x.tc_name) -#endif #define CAP_TYPE_FLAG 0 #define CAP_TYPE_INT 1 @@ -50,62 +40,66 @@ TERM_REC *current_term; /* Define only what we might need */ static TERMINFO_REC tcaps[] = { - /* Terminal size */ - { "cols", "co", CAP_TYPE_INT, G_STRUCT_OFFSET(TERM_REC, width) }, - { "lines", "li", CAP_TYPE_INT, G_STRUCT_OFFSET(TERM_REC, height) }, - - /* Cursor movement */ - { "smcup", "ti", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_smcup) }, - { "rmcup", "te", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_rmcup) }, - { "cup", "cm", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_cup) }, - { "hpa", "ch", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_hpa) }, - { "vpa", "vh", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_vpa) }, - { "cub1", "le", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_cub1) }, - { "cuf1", "nd", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_cuf1) }, - { "civis", "vi", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_civis) }, - { "cnorm", "ve", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_cnorm) }, + /* Terminal size */ + { "cols", "co", CAP_TYPE_INT, G_STRUCT_OFFSET(TERM_REC, width) }, + { "lines", "li", CAP_TYPE_INT, G_STRUCT_OFFSET(TERM_REC, height) }, - /* Scrolling */ - { "csr", "cs", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_csr) }, - { "wind", "wi", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_wind) }, - { "ri", "sr", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_ri) }, - { "rin", "SR", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_rin) }, - { "ind", "sf", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_ind) }, - { "indn", "SF", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_indn) }, - { "il", "AL", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_il) }, - { "il1", "al", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_il1) }, - { "dl", "DL", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_dl) }, - { "dl1", "dl", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_dl1) }, + /* Cursor movement */ + { "smcup", "ti", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_smcup) }, + { "rmcup", "te", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_rmcup) }, + { "cup", "cm", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_cup) }, + { "hpa", "ch", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_hpa) }, + { "vpa", "vh", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_vpa) }, + { "cub1", "le", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_cub1) }, + { "cuf1", "nd", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_cuf1) }, + { "civis", "vi", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_civis) }, + { "cnorm", "ve", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_cnorm) }, + + /* Scrolling */ + { "csr", "cs", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_csr) }, + { "wind", "wi", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_wind) }, + { "ri", "sr", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_ri) }, + { "rin", "SR", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_rin) }, + { "ind", "sf", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_ind) }, + { "indn", "SF", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_indn) }, + { "il", "AL", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_il) }, + { "il1", "al", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_il1) }, + { "dl", "DL", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_dl) }, + { "dl1", "dl", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_dl1) }, /* Clearing screen */ - { "clear", "cl", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_clear) }, - { "ed", "cd", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_ed) }, + { "clear", "cl", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_clear) }, + { "ed", "cd", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_ed) }, - /* Clearing to end of line */ - { "el", "ce", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_el) }, + /* Clearing to end of line */ + { "el", "ce", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_el) }, - /* Repeating character */ - { "rep", "rp", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_rep) }, + /* Repeating character */ + { "rep", "rp", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_rep) }, /* Colors */ - { "colors", "Co", CAP_TYPE_INT, G_STRUCT_OFFSET(TERM_REC, TI_colors) }, - { "sgr0", "me", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_sgr0) }, - { "smul", "us", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_smul) }, - { "rmul", "ue", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_rmul) }, - { "smso", "so", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_smso) }, - { "rmso", "se", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_rmso) }, - { "sitm", "ZH", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_sitm) }, - { "ritm", "ZR", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_ritm) }, - { "bold", "md", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_bold) }, - { "blink", "mb", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_blink) }, - { "rev", "mr", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_rev) }, - { "setaf", "AF", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_setaf) }, - { "setab", "AB", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_setab) }, - { "setf", "Sf", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_setf) }, - { "setb", "Sb", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_setb) }, - - /* Beep */ - { "bel", "bl", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_bel) }, + { "colors", "Co", CAP_TYPE_INT, G_STRUCT_OFFSET(TERM_REC, TI_colors) }, + { "sgr0", "me", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_sgr0) }, + { "smul", "us", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_smul) }, + { "rmul", "ue", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_rmul) }, + { "smso", "so", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_smso) }, + { "rmso", "se", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_rmso) }, + { "sitm", "ZH", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_sitm) }, + { "ritm", "ZR", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_ritm) }, + { "bold", "md", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_bold) }, + { "blink", "mb", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_blink) }, + { "rev", "mr", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_rev) }, + { "setaf", "AF", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_setaf) }, + { "setab", "AB", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_setab) }, + { "setf", "Sf", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_setf) }, + { "setb", "Sb", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_setb) }, + + /* Beep */ + { "bel", "bl", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_bel) }, + + /* Keyboard-transmit mode */ + { "smkx", "ks", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_smkx) }, + { "rmkx", "ke", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_rmkx) }, }; /* Move cursor (cursor_address / cup) */ @@ -391,15 +385,26 @@ static void _ignore_parm(TERM_REC *term, int param) { } +static void terminfo_set_appkey_mode(TERM_REC *term, int set) +{ + if (term->TI_smkx && term->TI_rmkx) + tput(tparm(set ? term->TI_smkx : term->TI_rmkx)); +} + +static void term_dec_set_bracketed_paste_mode(int enable) +{ + if (enable) + tputs("\e[?2004h", 0, term_putchar); + else + tputs("\e[?2004l", 0, term_putchar); +} + static void term_fill_capabilities(TERM_REC *term) { int i, ival; char *sval; void *ptr; -#ifndef HAVE_TERMINFO - char *tptr = term->buffer2; -#endif for (i = 0; i < sizeof(tcaps)/sizeof(tcaps[0]); i++) { ptr = G_STRUCT_MEMBER_P(term, tcaps[i].offset); @@ -492,12 +497,15 @@ void terminfo_setup_colors(TERM_REC *term, int force) } } -static void terminfo_input_init(TERM_REC *term) +static void terminfo_input_init0(TERM_REC *term) { tcgetattr(fileno(term->in), &term->old_tio); memcpy(&term->tio, &term->old_tio, sizeof(term->tio)); term->tio.c_lflag &= ~(ICANON | ECHO); /* CBREAK, no ECHO */ + /* Disable the ICRNL flag to disambiguate ^J and Enter, also disable the + * software flow control to leave ^Q and ^S ready to be bound */ + term->tio.c_iflag &= ~(ICRNL | IXON | IXOFF); term->tio.c_cc[VMIN] = 1; /* read() is satisfied after 1 char */ term->tio.c_cc[VTIME] = 0; /* No timer */ @@ -511,8 +519,11 @@ static void terminfo_input_init(TERM_REC *term) term->tio.c_cc[VSUSP] = _POSIX_VDISABLE; #endif - tcsetattr(fileno(term->in), TCSADRAIN, &term->tio); +} +static void terminfo_input_init(TERM_REC *term) +{ + tcsetattr(fileno(term->in), TCSADRAIN, &term->tio); } static void terminfo_input_deinit(TERM_REC *term) @@ -523,7 +534,14 @@ static void terminfo_input_deinit(TERM_REC *term) void terminfo_cont(TERM_REC *term) { if (term->TI_smcup) - tput(tparm(term->TI_smcup)); + tput(tparm(term->TI_smcup)); + + if (term->appkey_enabled) + terminfo_set_appkey_mode(term, TRUE); + + if (term->bracketed_paste_enabled) + term_dec_set_bracketed_paste_mode(TRUE); + terminfo_input_init(term); } @@ -534,10 +552,16 @@ void terminfo_stop(TERM_REC *term) /* move cursor to bottom of the screen */ terminfo_move(0, term->height-1); + if (term->bracketed_paste_enabled) + term_dec_set_bracketed_paste_mode(FALSE); + /* stop cup-mode */ if (term->TI_rmcup) tput(tparm(term->TI_rmcup)); + if (term->appkey_enabled) + terminfo_set_appkey_mode(term, FALSE); + /* reset input settings */ terminfo_input_deinit(term); fflush(term->out); @@ -546,9 +570,7 @@ void terminfo_stop(TERM_REC *term) static int term_setup(TERM_REC *term) { GString *str; -#ifdef HAVE_TERMINFO int err; -#endif char *term_env; term_env = getenv("TERM"); @@ -557,18 +579,10 @@ static int term_setup(TERM_REC *term) return 0; } -#ifdef HAVE_TERMINFO if (setupterm(term_env, 1, &err) != 0) { fprintf(stderr, "setupterm() failed for TERM=%s: %d\n", term_env, err); return 0; } -#else - if (tgetent(term->buffer1, term_env) < 1) - { - fprintf(stderr, "Termcap not found for TERM=%s\n", term_env); - return 0; - } -#endif term_fill_capabilities(term); @@ -646,11 +660,11 @@ static int term_setup(TERM_REC *term) str = g_string_new(NULL); if (term->TI_sgr0) g_string_append(str, term->TI_sgr0); - if (term->TI_rmul && (term->TI_sgr0 == NULL || strcmp(term->TI_rmul, term->TI_sgr0) != 0)) + if (term->TI_rmul && (term->TI_sgr0 == NULL || g_strcmp0(term->TI_rmul, term->TI_sgr0) != 0)) g_string_append(str, term->TI_rmul); - if (term->TI_rmso && (term->TI_sgr0 == NULL || strcmp(term->TI_rmso, term->TI_sgr0) != 0)) + if (term->TI_rmso && (term->TI_sgr0 == NULL || g_strcmp0(term->TI_rmso, term->TI_sgr0) != 0)) g_string_append(str, term->TI_rmso); - if (term->TI_ritm && (term->TI_sgr0 == NULL || strcmp(term->TI_ritm, term->TI_sgr0) != 0)) + if (term->TI_ritm && (term->TI_sgr0 == NULL || g_strcmp0(term->TI_ritm, term->TI_sgr0) != 0)) g_string_append(str, term->TI_ritm); term->TI_normal = str->str; g_string_free(str, FALSE); @@ -659,10 +673,29 @@ static int term_setup(TERM_REC *term) term->beep = term->TI_bel ? _beep : _ignore; terminfo_setup_colors(term, FALSE); + terminfo_input_init0(term); terminfo_cont(term); return 1; } +void term_set_appkey_mode(int enable) +{ + if (current_term->appkey_enabled == enable) + return; + + current_term->appkey_enabled = enable; + terminfo_set_appkey_mode(current_term, enable); +} + +void term_set_bracketed_paste_mode(int enable) +{ + if (current_term->bracketed_paste_enabled == enable) + return; + + current_term->bracketed_paste_enabled = enable; + term_dec_set_bracketed_paste_mode(enable); +} + TERM_REC *terminfo_core_init(FILE *in, FILE *out) { TERM_REC *old_term, *term; diff --git a/src/fe-text/terminfo-core.h b/src/fe-text/terminfo-core.h index 6ab4637d..1253fd9d 100644 --- a/src/fe-text/terminfo-core.h +++ b/src/fe-text/terminfo-core.h @@ -88,6 +88,14 @@ struct _TERM_REC { /* Beep */ char *TI_bel; + + /* Keyboard-transmit mode */ + const char *TI_smkx; + const char *TI_rmkx; + + /* Terminal mode states */ + int appkey_enabled; + int bracketed_paste_enabled; }; extern TERM_REC *current_term; diff --git a/src/fe-text/textbuffer-view.c b/src/fe-text/textbuffer-view.c index ad4c00b8..58bd36fb 100644 --- a/src/fe-text/textbuffer-view.c +++ b/src/fe-text/textbuffer-view.c @@ -310,7 +310,7 @@ view_update_line_cache(TEXT_BUFFER_VIEW_REC *view, LINE_REC *line) continue; } - if (!view->utf8 && char_width > 1) { + if (view->break_wide && char_width > 1) { last_space = xpos; last_space_ptr = next_ptr; last_color = color; last_fg24 = fg24; last_bg24 = bg24; @@ -668,6 +668,16 @@ void textbuffer_view_set_default_indent(TEXT_BUFFER_VIEW_REC *view, view->default_indent_func = indent_func; } +/* Enable breaking of wide chars */ +void textbuffer_view_set_break_wide(TEXT_BUFFER_VIEW_REC *view, + gboolean break_wide) +{ + if (view->break_wide != break_wide) { + view->break_wide = break_wide; + view_reset_cache(view); + } +} + static void view_unregister_indent_func(TEXT_BUFFER_VIEW_REC *view, INDENT_FUNC indent_func) { @@ -1231,7 +1241,7 @@ void textbuffer_view_remove_line(TEXT_BUFFER_VIEW_REC *view, LINE_REC *line) void textbuffer_view_remove_lines_by_level(TEXT_BUFFER_VIEW_REC *view, int level) { LINE_REC *line, *next; - + term_refresh_freeze(); line = textbuffer_view_get_lines(view); diff --git a/src/fe-text/textbuffer-view.h b/src/fe-text/textbuffer-view.h index ab6786e0..5e7a9d0a 100644 --- a/src/fe-text/textbuffer-view.h +++ b/src/fe-text/textbuffer-view.h @@ -59,6 +59,7 @@ struct _TEXT_BUFFER_VIEW_REC { unsigned int longword_noindent:1; unsigned int scroll:1; /* scroll down automatically when at bottom */ unsigned int utf8:1; /* use UTF8 in this view */ + unsigned int break_wide:1; /* Break wide chars in this view */ TEXT_BUFFER_CACHE_REC *cache; int ypos; /* cursor position - visible area is 0..height-1 */ @@ -72,7 +73,7 @@ struct _TEXT_BUFFER_VIEW_REC { /* how many empty lines are in screen. a screenful when started or used /CLEAR */ - int empty_linecount; + int empty_linecount; /* window is at the bottom of the text buffer */ unsigned int bottom:1; /* if !bottom - new text has been printed since we were at bottom */ @@ -97,6 +98,8 @@ void textbuffer_view_set_default_indent(TEXT_BUFFER_VIEW_REC *view, int longword_noindent, INDENT_FUNC indent_func); void textbuffer_views_unregister_indent_func(INDENT_FUNC indent_func); +void textbuffer_view_set_break_wide(TEXT_BUFFER_VIEW_REC *view, + gboolean break_wide); void textbuffer_view_set_scroll(TEXT_BUFFER_VIEW_REC *view, int scroll); void textbuffer_view_set_utf8(TEXT_BUFFER_VIEW_REC *view, int utf8); diff --git a/src/fe-text/textbuffer.c b/src/fe-text/textbuffer.c index 561fdabd..3668f4c7 100644 --- a/src/fe-text/textbuffer.c +++ b/src/fe-text/textbuffer.c @@ -27,7 +27,7 @@ #include "textbuffer.h" -#ifdef HAVE_REGEX_H +#ifndef USE_GREGEX # include <regex.h> #endif @@ -545,7 +545,9 @@ GList *textbuffer_find_text(TEXT_BUFFER_REC *buffer, LINE_REC *startline, int before, int after, int regexp, int fullword, int case_sensitive) { -#ifdef HAVE_REGEX_H +#ifdef USE_GREGEX + GRegex *preg; +#else regex_t preg; #endif LINE_REC *line, *pre_line; @@ -557,16 +559,23 @@ GList *textbuffer_find_text(TEXT_BUFFER_REC *buffer, LINE_REC *startline, g_return_val_if_fail(buffer != NULL, NULL); g_return_val_if_fail(text != NULL, NULL); +#ifdef USE_GREGEX + preg = NULL; + + if (regexp) { + preg = g_regex_new(text, G_REGEX_RAW | (case_sensitive ? 0 : G_REGEX_CASELESS), 0, NULL); + + if (preg == NULL) + return NULL; + } +#else if (regexp) { -#ifdef HAVE_REGEX_H int flags = REG_EXTENDED | REG_NOSUB | (case_sensitive ? 0 : REG_ICASE); if (regcomp(&preg, text, flags) != 0) return NULL; -#else - return NULL; -#endif } +#endif matches = NULL; match_after = 0; str = g_string_new(NULL); @@ -585,12 +594,15 @@ GList *textbuffer_find_text(TEXT_BUFFER_REC *buffer, LINE_REC *startline, if (*text != '\0') { textbuffer_line2text(line, FALSE, str); - if (line_matched) - line_matched = -#ifdef HAVE_REGEX_H - regexp ? regexec(&preg, str->str, 0, NULL, 0) == 0 : + if (line_matched) { + line_matched = regexp ? +#ifdef USE_GREGEX + g_regex_match(preg, str->str, 0, NULL) +#else + regexec(&preg, str->str, 0, NULL, 0) == 0 #endif - match_func(str->str, text) != NULL; + : match_func(str->str, text) != NULL; + } } if (line_matched) { @@ -618,7 +630,11 @@ GList *textbuffer_find_text(TEXT_BUFFER_REC *buffer, LINE_REC *startline, matches = g_list_append(matches, NULL); } } -#ifdef HAVE_REGEX_H + +#ifdef USE_GREGEX + if (preg != NULL) + g_regex_unref(preg); +#else if (regexp) regfree(&preg); #endif g_string_free(str, TRUE); diff --git a/src/fe-text/tparm.c b/src/fe-text/tparm.c deleted file mode 100644 index 3f58e6f3..00000000 --- a/src/fe-text/tparm.c +++ /dev/null @@ -1,740 +0,0 @@ -/* - * tparm.c - * - * By Ross Ridge - * Public Domain - * 92/02/01 07:30:36 - * - */ -#include <ctype.h> -#include <stdarg.h> -#include <stdio.h> -#include <string.h> - -#ifndef MAX_PUSHED -#define MAX_PUSHED 32 -#endif - -#define ARG 1 -#define NUM 2 - -#define INTEGER 1 -#define STRING 2 - -#define MAX_LINE 640 - -typedef void* anyptr; - -typedef struct stack_str { - int type; - int argnum; - int value; -} stack; - -static stack S[MAX_PUSHED]; -static stack vars['z'-'a'+1]; -static int pos = 0; - -static struct arg_str { - int type; - int integer; - char *string; -} arg_list[10]; - -static int argcnt; - -static va_list tparm_args; - -static int pusharg(int arg) -{ - if (pos == MAX_PUSHED) - return 1; - S[pos].type = ARG; - S[pos++].argnum = arg; - return 0; -} - -static int pushnum(int num) -{ - if (pos == MAX_PUSHED) - return 1; - S[pos].type = NUM; - S[pos++].value = num; - return 0; -} - -/* VARARGS2 */ -static int getarg(int argnum, int type, anyptr p) -{ - while (argcnt < argnum) { - arg_list[argcnt].type = INTEGER; - arg_list[argcnt++].integer = (int) va_arg(tparm_args, int); - } - if (argcnt > argnum) { - if (arg_list[argnum].type != type) - return 1; - else if (type == STRING) - *(char **)p = arg_list[argnum].string; - else - *(int *)p = arg_list[argnum].integer; - } else { - arg_list[argcnt].type = type; - if (type == STRING) - *(char **)p = arg_list[argcnt++].string - = (char *) va_arg(tparm_args, char *); - else - *(int *)p = arg_list[argcnt++].integer = (int) va_arg(tparm_args, int); - } - return 0; -} - - -static int popstring(char **str) -{ - if (pos-- == 0) - return 1; - if (S[pos].type != ARG) - return 1; - return(getarg(S[pos].argnum, STRING, (anyptr) str)); -} - -static int popnum(int *num) -{ - if (pos-- == 0) - return 1; - switch (S[pos].type) { - case ARG: - return (getarg(S[pos].argnum, INTEGER, (anyptr) num)); - case NUM: - *num = S[pos].value; - return 0; - } - return 1; -} - -static int cvtchar(const char *sp, char *c) -{ - switch(*sp) { - case '\\': - switch(*++sp) { - case '\'': - case '$': - case '\\': - case '%': - *c = *sp; - return 2; - case '\0': - *c = '\\'; - return 1; - case '0': - if (sp[1] == '0' && sp[2] == '0') { - *c = '\0'; - return 4; - } - *c = '\200'; /* '\0' ???? */ - return 2; - default: - *c = *sp; - return 2; - } - default: - *c = *sp; - return 1; - } -} - -static int termcap; - -/* sigh... this has got to be the ugliest code I've ever written. - Trying to handle everything has its cost, I guess. - - It actually isn't to hard to figure out if a given % code is supposed - to be interpeted with its termcap or terminfo meaning since almost - all terminfo codes are invalid unless something has been pushed on - the stack and termcap strings will never push things on the stack - (%p isn't used by termcap). So where we have a choice we make the - decision by wether or not somthing has been pushed on the stack. - The static variable termcap keeps track of this; it starts out set - to 1 and is incremented as each argument processed by a termcap % code, - however if something is pushed on the stack it's set to 0 and the - rest of the % codes are interpeted as terminfo % codes. Another way - of putting it is that if termcap equals one we haven't decided either - way yet, if it equals zero we're looking for terminfo codes, and if - its greater than 1 we're looking for termcap codes. - - Terminfo % codes: - - %% output a '%' - %[[:][-+# ][width][.precision]][doxXs] - output pop according to the printf format - %c output pop as a char - %'c' push character constant c. - %{n} push decimal constant n. - %p[1-9] push paramter [1-9] - %g[a-z] push variable [a-z] - %P[a-z] put pop in variable [a-z] - %l push the length of pop (a string) - %+ add pop to pop and push the result - %- subtract pop from pop and push the result - %* multiply pop and pop and push the result - %& bitwise and pop and pop and push the result - %| bitwise or pop and pop and push the result - %^ bitwise xor pop and pop and push the result - %~ push the bitwise not of pop - %= compare if pop and pop are equal and push the result - %> compare if pop is less than pop and push the result - %< compare if pop is greater than pop and push the result - %A logical and pop and pop and push the result - %O logical or pop and pop and push the result - %! push the logical not of pop - %? condition %t if_true [%e if_false] %; - if condtion evaulates as true then evaluate if_true, - else evaluate if_false. elseif's can be done: -%? cond %t true [%e cond2 %t true2] ... [%e condN %t trueN] [%e false] %; - %i add one to parameters 1 and 2. (ANSI) - - Termcap Codes: - - %% output a % - %. output parameter as a character - %d output parameter as a decimal number - %2 output parameter in printf format %02d - %3 output parameter in printf format %03d - %+x add the character x to parameter and output it as a character -(UW) %-x subtract parameter FROM the character x and output it as a char -(UW) %ax add the character x to parameter -(GNU) %a[+*-/=][cp]x - GNU arithmetic. -(UW) %sx subtract parameter FROM the character x - %>xy if parameter > character x then add character y to parameter - %B convert to BCD (parameter = (parameter/10)*16 + parameter%16) - %D Delta Data encode (parameter = parameter - 2*(paramter%16)) - %i increment the first two parameters by one - %n xor the first two parameters by 0140 -(GNU) %m xor the first two parameters by 0177 - %r swap the first two parameters -(GNU) %b backup to previous parameter -(GNU) %f skip this parameter - - Note the two definitions of %a, the GNU defintion is used if the characters - after the 'a' are valid, otherwise the UW definition is used. - - (GNU) used by GNU Emacs termcap libraries - (UW) used by the University of Waterloo (MFCF) termcap libraries - -*/ - -char *tparm(const char *str, ...) { - static char OOPS[] = "OOPS"; - static char buf[MAX_LINE]; - register const char *sp; - register char *dp; - register char *fmt; - char conv_char; - char scan_for; - int scan_depth = 0, if_depth; - static int i, j; - static char *s, c; - char fmt_buf[MAX_LINE]; - char sbuf[MAX_LINE]; - - va_start(tparm_args, str); - - sp = str; - dp = buf; - scan_for = 0; - if_depth = 0; - argcnt = 0; - pos = 0; - termcap = 1; - while (*sp != '\0') { - switch(*sp) { - case '\\': - if (scan_for) { - if (*++sp != '\0') - sp++; - break; - } - *dp++ = *sp++; - if (*sp != '\0') - *dp++ = *sp++; - break; - case '%': - sp++; - if (scan_for) { - if (*sp == scan_for && if_depth == scan_depth) { - if (scan_for == ';') - if_depth--; - scan_for = 0; - } else if (*sp == '?') - if_depth++; - else if (*sp == ';') { - if (if_depth == 0) - return OOPS; - else - if_depth--; - } - sp++; - break; - } - fmt = NULL; - switch(*sp) { - case '%': - *dp++ = *sp++; - break; - case '+': - if (!termcap) { - if (popnum(&j) || popnum(&i)) - return OOPS; - i += j; - if (pushnum(i)) - return OOPS; - sp++; - break; - } - ;/* FALLTHROUGH */ - case 'C': - if (*sp == 'C') { - if (getarg(termcap - 1, INTEGER, &i)) - return OOPS; - if (i >= 96) { - i /= 96; - if (i == '$') - *dp++ = '\\'; - *dp++ = i; - } - } - fmt = "%c"; - /* FALLTHROUGH */ - case 'a': - if (!termcap) - return OOPS; - if (getarg(termcap - 1, INTEGER, (anyptr) &i)) - return OOPS; - if (*++sp == '\0') - return OOPS; - if ((sp[1] == 'p' || sp[1] == 'c') - && sp[2] != '\0' && fmt == NULL) { - /* GNU aritmitic parameter, what they - realy need is terminfo. */ - int val, lc; - if (sp[1] == 'p' - && getarg(termcap - 1 + sp[2] - '@', - INTEGER, (anyptr) &val)) - return OOPS; - if (sp[1] == 'c') { - lc = cvtchar(sp + 2, &c) + 2; - /* Mask out 8th bit so \200 can be - used for \0 as per GNU doc's */ - val = c & 0177; - } else - lc = 2; - switch(sp[0]) { - case '=': - break; - case '+': - val = i + val; - break; - case '-': - val = i - val; - break; - case '*': - val = i * val; - break; - case '/': - val = i / val; - break; - default: - /* Not really GNU's %a after all... */ - lc = cvtchar(sp, &c); - val = c + i; - break; - } - arg_list[termcap - 1].integer = val; - sp += lc; - break; - } - sp += cvtchar(sp, &c); - arg_list[termcap - 1].integer = c + i; - if (fmt == NULL) - break; - sp--; - /* FALLTHROUGH */ - case '-': - if (!termcap) { - if (popnum(&j) || popnum(&i)) - return OOPS; - i -= j; - if (pushnum(i)) - return OOPS; - sp++; - break; - } - fmt = "%c"; - /* FALLTHROUGH */ - case 's': - if (termcap && (fmt == NULL || *sp == '-')) { - if (getarg(termcap - 1, INTEGER, &i)) - return OOPS; - if (*++sp == '\0') - return OOPS; - sp += cvtchar(sp, &c); - arg_list[termcap - 1].integer = c - i; - if (fmt == NULL) - break; - sp--; - } - if (!termcap) - return OOPS; - ;/* FALLTHROUGH */ - case '.': - if (termcap && fmt == NULL) - fmt = "%c"; - ;/* FALLTHROUGH */ - case 'd': - if (termcap && fmt == NULL) - fmt = "%d"; - ;/* FALLTHROUGH */ - case '2': - if (termcap && fmt == NULL) - fmt = "%02d"; - ;/* FALLTHROUGH */ - case '3': - if (termcap && fmt == NULL) - fmt = "%03d"; - ;/* FALLTHROUGH */ - case ':': case ' ': case '#': case 'u': - case 'x': case 'X': case 'o': case 'c': - case '0': case '1': case '4': case '5': - case '6': case '7': case '8': case '9': - if (fmt == NULL) { - if (termcap) - return OOPS; - if (*sp == ':') - sp++; - fmt = fmt_buf; - *fmt++ = '%'; - while(*sp != 's' && *sp != 'x' && *sp != 'X' && *sp != 'd' && *sp != 'o' && *sp != 'c' && *sp != 'u') { - if (*sp == '\0') - return OOPS; - *fmt++ = *sp++; - } - *fmt++ = *sp; - *fmt = '\0'; - fmt = fmt_buf; - } - conv_char = fmt[strlen(fmt) - 1]; - if (conv_char == 's') { - if (popstring(&s)) - return OOPS; - sprintf(sbuf, fmt, s); - } else { - if (termcap) { - if (getarg(termcap++ - 1, - INTEGER, &i)) - return OOPS; - } else - if (popnum(&i)) - return OOPS; - if (i == 0 && conv_char == 'c') - *sbuf = 0; - else - sprintf(sbuf, fmt, i); - } - sp++; - fmt = sbuf; - while(*fmt != '\0') { - if (*fmt == '$') - *dp++ = '\\'; - *dp++ = *fmt++; - } - break; - case 'r': - if (!termcap || getarg(1, INTEGER, &i)) - return OOPS; - arg_list[1].integer = arg_list[0].integer; - arg_list[0].integer = i; - sp++; - break; - case 'i': - if (getarg(1, INTEGER, &i) - || arg_list[0].type != INTEGER) - return OOPS; - arg_list[1].integer++; - arg_list[0].integer++; - sp++; - break; - case 'n': - if (!termcap || getarg(1, INTEGER, &i)) - return OOPS; - arg_list[0].integer ^= 0140; - arg_list[1].integer ^= 0140; - sp++; - break; - case '>': - if (!termcap) { - if (popnum(&j) || popnum(&i)) - return OOPS; - i = (i > j); - if (pushnum(i)) - return OOPS; - sp++; - break; - } - if (getarg(termcap-1, INTEGER, &i)) - return OOPS; - sp += cvtchar(sp, &c); - if (i > c) { - sp += cvtchar(sp, &c); - arg_list[termcap-1].integer += c; - } else - sp += cvtchar(sp, &c); - sp++; - break; - case 'B': - if (!termcap || getarg(termcap-1, INTEGER, &i)) - return OOPS; - arg_list[termcap-1].integer = 16*(i/10)+i%10; - sp++; - break; - case 'D': - if (!termcap || getarg(termcap-1, INTEGER, &i)) - return OOPS; - arg_list[termcap-1].integer = i - 2 * (i % 16); - sp++; - break; - case 'p': - if (termcap > 1) - return OOPS; - if (*++sp == '\0') - return OOPS; - if (*sp == '0') - i = 9; - else - i = *sp - '1'; - if (i < 0 || i > 9) - return OOPS; - if (pusharg(i)) - return OOPS; - termcap = 0; - sp++; - break; - case 'P': - if (termcap || *++sp == '\0') - return OOPS; - i = *sp++ - 'a'; - if (i < 0 || i > 25) - return OOPS; - if (pos-- == 0) - return OOPS; - switch(vars[i].type = S[pos].type) { - case ARG: - vars[i].argnum = S[pos].argnum; - break; - case NUM: - vars[i].value = S[pos].value; - break; - } - break; - case 'g': - if (termcap || *++sp == '\0') - return OOPS; - i = *sp++ - 'a'; - if (i < 0 || i > 25) - return OOPS; - switch(vars[i].type) { - case ARG: - if (pusharg(vars[i].argnum)) - return OOPS; - break; - case NUM: - if (pushnum(vars[i].value)) - return OOPS; - break; - } - break; - case '\'': - if (termcap > 1) - return OOPS; - if (*++sp == '\0') - return OOPS; - sp += cvtchar(sp, &c); - if (pushnum(c) || *sp++ != '\'') - return OOPS; - termcap = 0; - break; - case '{': - if (termcap > 1) - return OOPS; - i = 0; - sp++; - while(isdigit((int) (unsigned char) *sp)) - i = 10 * i + *sp++ - '0'; - if (*sp++ != '}' || pushnum(i)) - return OOPS; - termcap = 0; - break; - case 'l': - if (termcap || popstring(&s)) - return OOPS; - i = strlen(s); - if (pushnum(i)) - return OOPS; - sp++; - break; - case '*': - if (termcap || popnum(&j) || popnum(&i)) - return OOPS; - i *= j; - if (pushnum(i)) - return OOPS; - sp++; - break; - case '/': - if (termcap || popnum(&j) || popnum(&i)) - return OOPS; - i /= j; - if (pushnum(i)) - return OOPS; - sp++; - break; - case 'm': - if (termcap) { - if (getarg(1, INTEGER, &i)) - return OOPS; - arg_list[0].integer ^= 0177; - arg_list[1].integer ^= 0177; - sp++; - break; - } - if (popnum(&j) || popnum(&i)) - return OOPS; - i %= j; - if (pushnum(i)) - return OOPS; - sp++; - break; - case '&': - if (popnum(&j) || popnum(&i)) - return OOPS; - i &= j; - if (pushnum(i)) - return OOPS; - sp++; - break; - case '|': - if (popnum(&j) || popnum(&i)) - return OOPS; - i |= j; - if (pushnum(i)) - return OOPS; - sp++; - break; - case '^': - if (popnum(&j) || popnum(&i)) - return OOPS; - i ^= j; - if (pushnum(i)) - return OOPS; - sp++; - break; - case '=': - if (popnum(&j) || popnum(&i)) - return OOPS; - i = (i == j); - if (pushnum(i)) - return OOPS; - sp++; - break; - case '<': - if (popnum(&j) || popnum(&i)) - return OOPS; - i = (i < j); - if (pushnum(i)) - return OOPS; - sp++; - break; - case 'A': - if (popnum(&j) || popnum(&i)) - return OOPS; - i = (i && j); - if (pushnum(i)) - return OOPS; - sp++; - break; - case 'O': - if (popnum(&j) || popnum(&i)) - return OOPS; - i = (i || j); - if (pushnum(i)) - return OOPS; - sp++; - break; - case '!': - if (popnum(&i)) - return OOPS; - i = !i; - if (pushnum(i)) - return OOPS; - sp++; - break; - case '~': - if (popnum(&i)) - return OOPS; - i = ~i; - if (pushnum(i)) - return OOPS; - sp++; - break; - case '?': - if (termcap > 1) - return OOPS; - termcap = 0; - if_depth++; - sp++; - break; - case 't': - if (popnum(&i) || if_depth == 0) - return OOPS; - if (!i) { - scan_for = 'e'; - scan_depth = if_depth; - } - sp++; - break; - case 'e': - if (if_depth == 0) - return OOPS; - scan_for = ';'; - scan_depth = if_depth; - sp++; - break; - case ';': - if (if_depth-- == 0) - return OOPS; - sp++; - break; - case 'b': - if (--termcap < 1) - return OOPS; - sp++; - break; - case 'f': - if (!termcap++) - return OOPS; - sp++; - break; - } - break; - default: - if (scan_for) - sp++; - else - *dp++ = *sp++; - break; - } - } - va_end(tparm_args); - *dp = '\0'; - return buf; -} |