diff --git a/src/fe-text/gui-windows.c b/src/fe-text/gui-windows.c index 832e5a57..f791cc9a 100644 --- a/src/fe-text/gui-windows.c +++ b/src/fe-text/gui-windows.c @@ -789,81 +789,139 @@ static void signal_window_changed(WINDOW_REC *window) screen_refresh_thaw(); } -GList *gui_window_find_text(WINDOW_REC *window, const char *text, - GList *startline, int regexp, int fullword) +void gui_window_line2text(LINE_REC *line, int coloring, GString *str) { -#ifdef HAVE_REGEX_H - regex_t preg; -#endif - GList *tmp; - GList *matches; - gchar *str, *ptr; - gint n, size; + int color; + unsigned char cmd; + char *ptr, *tmp; - g_return_val_if_fail(window != NULL, NULL); - g_return_val_if_fail(text != NULL, NULL); + g_return_if_fail(line != NULL); + g_return_if_fail(str != NULL); - matches = NULL; size = 1024; str = g_malloc(1024); + g_string_truncate(str, 0); -#ifdef HAVE_REGEX_H - if (regcomp(&preg, text, REG_ICASE|REG_EXTENDED|REG_NOSUB) != 0) - return 0; -#endif - - if (startline == NULL) startline = WINDOW_GUI(window)->lines; - for (tmp = startline; tmp != NULL; tmp = tmp->next) - { - LINE_REC *rec = tmp->data; - - if (*text == '\0') { - matches = g_list_append(matches, rec); - continue; - } - - for (n = 0, ptr = rec->text; ; ptr++) - { - if (*ptr != 0) - { - if (n+2 > size) - { - size += 1024; - str = g_realloc(str, size); + color = 0; + for (ptr = line->text;;) { + if (*ptr != 0) { + g_string_append_c(str, *ptr); + ptr++; + continue; } - str[n++] = toupper(*ptr); - } - else - { + + ptr++; + cmd = (unsigned char) *ptr; ptr++; - if ((guchar) *ptr == LINE_CMD_CONTINUE) - { - gchar *tmp; - - memcpy(&tmp, ptr+1, sizeof(gchar *)); - ptr = tmp-1; + if (cmd == LINE_CMD_EOL || cmd == LINE_CMD_FORMAT) { + /* end of line */ + break; } - else if ((guchar) *ptr == LINE_CMD_EOL || - (guchar) *ptr == LINE_CMD_FORMAT) - break; - } - } - str[n] = '\0'; - if ( -#ifdef HAVE_REGEX_H - regexp ? regexec(&preg, str, 0, NULL, 0) == 0 : -#endif - fullword ? stristr_full(str, text) != NULL : - stristr(str, text) != NULL) { - /* matched */ - matches = g_list_append(matches, rec); + if (cmd == LINE_CMD_CONTINUE) { + /* line continues in another address.. */ + memcpy(&tmp, ptr, sizeof(char *)); + ptr = tmp; + continue; + } + + if (!coloring) { + /* no colors, skip coloring commands */ + continue; + } + + if ((cmd & 0x80) == 0) { + /* set color */ + color = cmd; + g_string_sprintfa(str, "\004%c%c", + (color & 0x0f)+'0', + ((color & 0xf0) >> 4)+'0'); + } else switch (cmd) { + case LINE_CMD_UNDERLINE: + g_string_append_c(str, 31); + break; + case LINE_CMD_COLOR0: + g_string_sprintfa(str, "\004%c%c", + '0', ((color & 0xf0) >> 4)+'0'); + break; + case LINE_CMD_COLOR8: + g_string_sprintfa(str, "\004%c%c", + '8', ((color & 0xf0) >> 4)+'0'); + color &= 0xfff0; + color |= 8|ATTR_COLOR8; + break; + case LINE_CMD_BLINK: + color |= 0x80; + g_string_sprintfa(str, "\004%c%c", (color & 0x0f)+'0', + ((color & 0xf0) >> 4)+'0'); + break; + case LINE_CMD_INDENT: + break; + } } - } +} + +GList *gui_window_find_text(WINDOW_REC *window, GList *startline, + int level, int nolevel, const char *text, + int regexp, int fullword, int case_sensitive) +{ #ifdef HAVE_REGEX_H - regfree(&preg); + regex_t preg; #endif - if (str != NULL) g_free(str); - return matches; + GList *tmp; + GList *matches; + GString *str; + + g_return_val_if_fail(window != NULL, NULL); + g_return_val_if_fail(text != NULL, NULL); + + 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 + } + + matches = NULL; + str = g_string_new(NULL); + + if (startline == NULL) + startline = WINDOW_GUI(window)->lines; + + for (tmp = startline; tmp != NULL; tmp = tmp->next) { + LINE_REC *rec = tmp->data; + + if ((rec->level & level) == 0 || (rec->level & nolevel) != 0) + continue; + + if (*text == '\0') { + /* no search word, everything matches */ + matches = g_list_append(matches, rec); + continue; + } + + gui_window_line2text(rec, FALSE, str); + + if ( +#ifdef HAVE_REGEX_H + regexp ? regexec(&preg, str->str, 0, NULL, 0) == 0 : +#endif + fullword ? strstr_full_case(str->str, text, + !case_sensitive) != NULL : + case_sensitive ? strstr(str->str, text) != NULL : + stristr(str->str, text) != NULL) { + /* matched */ + matches = g_list_append(matches, rec); + } + } +#ifdef HAVE_REGEX_H + if (regexp) regfree(&preg); +#endif + g_string_free(str, TRUE); + return matches; } static void gui_update_bottom_startline(GUI_WINDOW_REC *gui) diff --git a/src/fe-text/gui-windows.h b/src/fe-text/gui-windows.h index 2159f61c..9fef4521 100644 --- a/src/fe-text/gui-windows.h +++ b/src/fe-text/gui-windows.h @@ -97,8 +97,11 @@ void gui_windows_deinit(void); WINDOW_REC *gui_window_create(MAIN_WINDOW_REC *parent); void gui_window_set_server(WINDOW_REC *window, SERVER_REC *server); -GList *gui_window_find_text(WINDOW_REC *window, const char *text, - GList *startline, int regexp, int fullword); + +void gui_window_line2text(LINE_REC *line, int coloring, GString *str); +GList *gui_window_find_text(WINDOW_REC *window, GList *startline, + int level, int nolevel, const char *text, + int regexp, int fullword, int case_sensitive); /* get number of real lines that line record takes */ int gui_window_get_linecount(GUI_WINDOW_REC *gui, LINE_REC *line); diff --git a/src/fe-text/lastlog.c b/src/fe-text/lastlog.c index 3968632c..53ae511a 100644 --- a/src/fe-text/lastlog.c +++ b/src/fe-text/lastlog.c @@ -31,6 +31,8 @@ #include "gui-windows.h" #include "gui-printtext.h" +#define MAX_LINES_WITHOUT_FORCE 1000 + static void window_lastlog_clear(WINDOW_REC *window) { GList *tmp, *next; @@ -45,84 +47,6 @@ static void window_lastlog_clear(WINDOW_REC *window) gui_window_redraw(window); } -static char *gui_window_line2text(LINE_REC *line, int coloring) -{ - GString *str; - int color; - char *ret, *ptr, *tmp; - - g_return_val_if_fail(line != NULL, NULL); - - str = g_string_new(NULL); - - color = 0; - for (ptr = line->text; ; ptr++) { - if (*ptr != 0) { - g_string_append_c(str, *ptr); - continue; - } - - ptr++; - if (!coloring) { - /* no colors, handle only commands that don't - have anything to do with colors */ - switch ((unsigned char) *ptr) { - case LINE_CMD_EOL: - case LINE_CMD_FORMAT: - ret = str->str; - g_string_free(str, FALSE); - return ret; - case LINE_CMD_CONTINUE: - memcpy(&tmp, ptr+1, sizeof(char *)); - ptr = tmp-1; - break; - } - continue; - } - - if ((*ptr & 0x80) == 0) { - /* set color */ - color = *ptr; - g_string_sprintfa(str, "\004%c%c", (color & 0x0f)+'0', - ((color & 0xf0) >> 4)+'0'); - } - else switch ((unsigned char) *ptr) - { - case LINE_CMD_EOL: - case LINE_CMD_FORMAT: - ret = str->str; - g_string_free(str, FALSE); - return ret; - case LINE_CMD_CONTINUE: - memcpy(&tmp, ptr+1, sizeof(char *)); - ptr = tmp-1; - break; - case LINE_CMD_UNDERLINE: - g_string_append_c(str, 31); - break; - case LINE_CMD_COLOR0: - g_string_sprintfa(str, "\004%c%c", - '0', ((color & 0xf0) >> 4)+'0'); - break; - case LINE_CMD_COLOR8: - g_string_sprintfa(str, "\004%c%c", - '8', ((color & 0xf0) >> 4)+'0'); - color &= 0xfff0; - color |= 8|ATTR_COLOR8; - break; - case LINE_CMD_BLINK: - color |= 0x80; - g_string_sprintfa(str, "\004%c%c", (color & 0x0f)+'0', - ((color & 0xf0) >> 4)+'0'); - break; - case LINE_CMD_INDENT: - break; - } - } - - return NULL; -} - /* Only unknown keys in `optlist' should be levels. Returns -1 if unknown option was given. */ int cmd_options_get_level(const char *cmd, GHashTable *optlist) @@ -162,40 +86,14 @@ int cmd_options_get_level(const char *cmd, GHashTable *optlist) return retlevel; } -#define lastlog_match(line, level) \ - (((line)->level & level) != 0 && ((line)->level & MSGLEVEL_LASTLOG) == 0) - -static GList *lastlog_find_startline(GList *list, int count, int start, int level) -{ - GList *tmp; - - if (count <= 0) return list; - - for (tmp = g_list_last(list); tmp != NULL; tmp = tmp->prev) { - LINE_REC *rec = tmp->data; - - if (!lastlog_match(rec, level)) - continue; - - if (start > 0) { - start--; - continue; - } - - if (--count == 0) - return tmp; - } - - return list; -} - static void show_lastlog(const char *searchtext, GHashTable *optlist, int start, int count) { WINDOW_REC *window; GList *startline, *list, *tmp; - char *str, *line; - int level, fhandle; + GString *line; + char *str; + int level, fhandle, len; level = cmd_options_get_level("lastlog", optlist); if (level == -1) return; /* error in options */ @@ -243,40 +141,63 @@ static void show_lastlog(const char *searchtext, GHashTable *optlist, startline = NULL; if (startline == NULL) startline = WINDOW_GUI(window)->lines; - list = gui_window_find_text(window, searchtext, startline, + list = gui_window_find_text(window, startline, + level, MSGLEVEL_LASTLOG, + searchtext, g_hash_table_lookup(optlist, "regexp") != NULL, - g_hash_table_lookup(optlist, "word") != NULL); - tmp = lastlog_find_startline(list, count, start, level); + g_hash_table_lookup(optlist, "word") != NULL, + g_hash_table_lookup(optlist, "case") != NULL); - for (; tmp != NULL && (count < 0 || count > 0); tmp = tmp->next) { + len = g_list_length(list); + if (count <= 0) + tmp = list; + else { + int pos = len-count; + + if (pos < 0) pos = 0; + pos += start; + + tmp = pos > len ? NULL : g_list_nth(list, pos); + len = g_list_length(tmp); + } + + if (len > MAX_LINES_WITHOUT_FORCE && fhandle == -1 && + g_hash_table_lookup(optlist, "force") == NULL) { + printformat_window(active_win, MSGLEVEL_CLIENTNOTICE, + TXT_LASTLOG_TOO_LONG, len); + g_list_free(list); + return; + } + + line = g_string_new(NULL); + while (tmp != NULL && (count < 0 || count > 0)) { LINE_REC *rec = tmp->data; - if (!lastlog_match(rec, level)) - continue; - count--; - /* get the line text */ - line = gui_window_line2text(rec, fhandle == -1); - if (settings_get_bool("timestamps")) - str = line; - else { + gui_window_line2text(rec, fhandle == -1, line); + if (!settings_get_bool("timestamps")) { struct tm *tm = localtime(&rec->time); - str = g_strdup_printf("%02d:%02d %s", - tm->tm_hour, tm->tm_min, line); + char timestamp[10]; + + g_snprintf(timestamp, sizeof(timestamp), + "%02d:%02d ", + tm->tm_hour, tm->tm_min); + g_string_prepend(line, timestamp); } /* write to file/window */ if (fhandle != -1) { - write(fhandle, line, strlen(line)); + write(fhandle, line->str, line->len); write(fhandle, "\n", 1); } else { printtext_window(active_win, MSGLEVEL_LASTLOG, - "%s", line); + "%s", line->str); } - if (str != line) g_free(str); - g_free(line); + count--; + tmp = tmp->next; } + g_string_free(line, TRUE); if (fhandle == -1 && g_hash_table_lookup(optlist, "-") == NULL) printformat(NULL, NULL, MSGLEVEL_LASTLOG, TXT_LASTLOG_END); @@ -291,8 +212,8 @@ static void show_lastlog(const char *searchtext, GHashTable *optlist, } /* SYNTAX: LASTLOG [-] [-file ] [-clear] [- -] - [-new | -away] [-regexp | -word] [-window ] - [] [ []] */ + [-new | -away] [-regexp | -word] [-case] + [-window ] [] [ []] */ static void cmd_lastlog(const char *data) { GHashTable *optlist; @@ -323,7 +244,7 @@ void lastlog_init(void) { command_bind("lastlog", NULL, (SIGNAL_FUNC) cmd_lastlog); - command_set_options("lastlog", "!- clear -file -window new away word regexp"); + command_set_options("lastlog", "!- force clear -file -window new away word regexp case"); } void lastlog_deinit(void) diff --git a/src/fe-text/module-formats.c b/src/fe-text/module-formats.c index 5bb5bcbe..be3c0eab 100644 --- a/src/fe-text/module-formats.c +++ b/src/fe-text/module-formats.c @@ -25,6 +25,7 @@ FORMAT_REC gui_text_formats[] = { { MODULE_NAME, "Text user interface", 0 }, + { "lastlog_too_long", "/LASTLOG would print $0 lines. If you really want to print all these lines use -force option.", 1, { 1 } }, { "lastlog_start", "{hilight Lastlog}:", 0 }, { "lastlog_end", "{hilight End of Lastlog}", 0 }, diff --git a/src/fe-text/module-formats.h b/src/fe-text/module-formats.h index 9fe896d8..fe33c8e2 100644 --- a/src/fe-text/module-formats.h +++ b/src/fe-text/module-formats.h @@ -3,6 +3,7 @@ enum { TXT_MODULE_NAME, + TXT_LASTLOG_TOO_LONG, TXT_LASTLOG_START, TXT_LASTLOG_END,