Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#define G_LOG_DOMAIN "TextBuffer"
+
#include "module.h"
#include "misc.h"
#include "formats.h"
static TEXT_CHUNK_REC *text_chunk_create(TEXT_BUFFER_REC *buffer)
{
TEXT_CHUNK_REC *rec;
- char *buf, *ptr, **pptr;
+ unsigned char *buf, *ptr, **pptr;
rec = g_mem_chunk_alloc(text_chunk);
rec->pos = 0;
breaks at least NetBSD/Alpha, so don't go "optimize"
it :) */
ptr = rec->buffer; pptr = &ptr;
- memcpy(buf, pptr, sizeof(char *));
+ memcpy(buf, pptr, sizeof(unsigned char *));
} else {
/* just to be safe */
mark_temp_eol(rec);
{
TEXT_CHUNK_REC *chunk;
const unsigned char *text;
- unsigned char *tmp = NULL;
+ unsigned char cmd, *tmp = NULL;
for (text = line->text;; text++) {
if (*text != '\0')
continue;
text++;
- if (*text == LINE_CMD_CONTINUE || *text == LINE_CMD_EOL) {
- if (*text == LINE_CMD_CONTINUE)
+ cmd = *text;
+ if (cmd == LINE_CMD_CONTINUE || cmd == LINE_CMD_EOL) {
+ if (cmd == LINE_CMD_CONTINUE)
memcpy(&tmp, text+1, sizeof(char *));
/* free the previous block */
text_chunk_destroy(buffer, chunk);
}
- if (*text == LINE_CMD_EOL)
+ if (cmd == LINE_CMD_EOL)
break;
text = tmp-1;
+ } else if (cmd == LINE_CMD_INDENT_FUNC) {
+ text += sizeof(int (*) ());
}
}
}
static void text_chunk_append(TEXT_BUFFER_REC *buffer,
- const char *data, int len)
+ const unsigned char *data, int len)
{
TEXT_CHUNK_REC *chunk;
int left;
chunk = buffer->cur_text;
while (chunk->pos + len >= TEXT_CHUNK_USABLE_SIZE) {
left = TEXT_CHUNK_USABLE_SIZE - chunk->pos;
- if (data[left-1] == 0) left--; /* don't split the commands */
+ if (left > 0 && data[left-1] == 0)
+ left--; /* don't split the commands */
memcpy(chunk->buffer + chunk->pos, data, left);
chunk->pos += left;
{
LINE_REC *line;
- line = textbuffer_line_create(buffer);
- if (prev == buffer->cur_line) {
- buffer->cur_line = line;
- buffer->lines = g_list_append(buffer->lines, buffer->cur_line);
+ line = textbuffer_line_create(buffer);
+ line->prev = prev;
+ if (prev == NULL) {
+ line->next = buffer->first_line;
+ if (buffer->first_line != NULL)
+ buffer->first_line->prev = line;
+ buffer->first_line = line;
} else {
- buffer->lines = g_list_insert(buffer->lines, line,
- g_list_index(buffer->lines, prev)+1);
+ line->next = prev->next;
+ if (line->next != NULL)
+ line->next->prev = line;
+ prev->next = line;
}
+
+ if (prev == buffer->cur_line)
+ buffer->cur_line = line;
buffer->lines_count++;
return line;
g_return_if_fail(buffer != NULL);
while (list != NULL) {
- textbuffer_line_unref(buffer, list->data);
+ if (list->data != NULL)
+ textbuffer_line_unref(buffer, list->data);
list = list->next;
}
}
+LINE_REC *textbuffer_line_last(TEXT_BUFFER_REC *buffer)
+{
+ LINE_REC *line;
+
+ line = buffer->cur_line;
+ if (line != NULL) {
+ while (line->next != NULL)
+ line = line->next;
+ }
+ return line;
+}
+
+int textbuffer_line_exists_after(LINE_REC *line, LINE_REC *search)
+{
+ while (line != NULL) {
+ if (line == search)
+ return TRUE;
+ line = line->next;
+ }
+ return FALSE;
+}
+
LINE_REC *textbuffer_append(TEXT_BUFFER_REC *buffer,
const unsigned char *data, int len,
LINE_INFO_REC *info)
g_return_val_if_fail(buffer != NULL, NULL);
g_return_val_if_fail(data != NULL, NULL);
+ if (len == 0)
+ return insert_after;
+
line = !buffer->last_eol ? insert_after :
textbuffer_line_insert(buffer, insert_after);
g_return_if_fail(buffer != NULL);
g_return_if_fail(line != NULL);
- buffer->lines = g_list_remove(buffer->lines, line);
+ if (buffer->first_line == line)
+ buffer->first_line = line->next;
+ if (line->prev != NULL)
+ line->prev->next = line->next;
+ if (line->next != NULL)
+ line->next->prev = line->prev;
if (buffer->cur_line == line) {
- buffer->cur_line = buffer->lines == NULL ? NULL :
- g_list_last(buffer->lines)->data;
+ buffer->cur_line = line->next != NULL ?
+ line->next : line->prev;
}
+ line->prev = line->next = NULL;
+
buffer->lines_count--;
textbuffer_line_unref(buffer, line);
}
void textbuffer_remove_all_lines(TEXT_BUFFER_REC *buffer)
{
GSList *tmp;
+ LINE_REC *line;
g_return_if_fail(buffer != NULL);
for (tmp = buffer->text_chunks; tmp != NULL; tmp = tmp->next)
g_mem_chunk_free(text_chunk, tmp->data);
g_slist_free(buffer->text_chunks);
- buffer->text_chunks = NULL;
+ buffer->text_chunks = NULL;
- g_list_free(buffer->lines);
- buffer->lines = NULL;
+ while (buffer->first_line != NULL) {
+ line = buffer->first_line->next;
+ g_mem_chunk_free(line_chunk, buffer->first_line);
+ buffer->first_line = line;
+ }
+ buffer->lines_count = 0;
buffer->cur_line = NULL;
- buffer->lines_count = 0;
+ buffer->cur_text = NULL;
+
+ buffer->last_eol = TRUE;
+}
+
+static void set_color(GString *str, int cmd, int *last_fg, int *last_bg)
+{
+ if (cmd & LINE_COLOR_DEFAULT) {
+ g_string_sprintfa(str, "\004%c", FORMAT_STYLE_DEFAULTS);
+
+ /* need to reset the fg/bg color */
+ if (cmd & LINE_COLOR_BG) {
+ *last_bg = -1;
+ if (*last_fg != -1) {
+ g_string_sprintfa(str, "\004%c%c",
+ *last_fg,
+ FORMAT_COLOR_NOCHANGE);
+ }
+ } else {
+ *last_fg = -1;
+ if (*last_bg != -1) {
+ g_string_sprintfa(str, "\004%c%c",
+ FORMAT_COLOR_NOCHANGE,
+ *last_bg);
+ }
+ }
+ return;
+ }
+
+ if ((cmd & LINE_COLOR_BG) == 0) {
+ /* change foreground color */
+ *last_fg = (cmd & 0x0f)+'0';
+ g_string_sprintfa(str, "\004%c%c", *last_fg,
+ FORMAT_COLOR_NOCHANGE);
+ } else {
+ /* change background color */
+ *last_bg = (cmd & 0x0f)+'0';
+ g_string_sprintfa(str, "\004%c%c",
+ FORMAT_COLOR_NOCHANGE, *last_bg);
+ }
}
void textbuffer_line2text(LINE_REC *line, int coloring, GString *str)
{
- unsigned char cmd;
- char *ptr, *tmp;
+ unsigned char cmd, *ptr, *tmp;
+ int last_fg, last_bg;
g_return_if_fail(line != NULL);
g_return_if_fail(str != NULL);
g_string_truncate(str, 0);
+ last_fg = last_bg = -1;
for (ptr = line->text;;) {
if (*ptr != 0) {
- g_string_append_c(str, *ptr);
+ g_string_append_c(str, (char) *ptr);
ptr++;
continue;
}
ptr++;
- cmd = (unsigned char) *ptr;
+ cmd = *ptr;
ptr++;
if (cmd == LINE_CMD_EOL || cmd == LINE_CMD_FORMAT) {
if (cmd == LINE_CMD_CONTINUE) {
/* line continues in another address.. */
- memcpy(&tmp, ptr, sizeof(char *));
+ memcpy(&tmp, ptr, sizeof(unsigned char *));
ptr = tmp;
continue;
}
if ((cmd & 0x80) == 0) {
/* set color */
- g_string_sprintfa(str, "\004%c%c",
- (cmd & 0x0f)+'0',
- ((cmd & 0xf0) >> 4)+'0');
+ set_color(str, cmd, &last_fg, &last_bg);
} else switch (cmd) {
case LINE_CMD_UNDERLINE:
g_string_append_c(str, 31);
break;
+ case LINE_CMD_REVERSE:
+ g_string_append_c(str, 22);
+ break;
case LINE_CMD_COLOR0:
g_string_sprintfa(str, "\004%c%c",
'0', FORMAT_COLOR_NOCHANGE);
break;
- case LINE_CMD_COLOR8:
- g_string_sprintfa(str, "\004%c%c",
- '8', FORMAT_COLOR_NOCHANGE);
- break;
- case LINE_CMD_BLINK:
- g_string_sprintfa(str, "\004%c", FORMAT_STYLE_BLINK);
- break;
case LINE_CMD_INDENT:
break;
+ case LINE_CMD_INDENT_FUNC:
+ ptr += sizeof(void *);
+ break;
}
}
}
GList *textbuffer_find_text(TEXT_BUFFER_REC *buffer, LINE_REC *startline,
int level, int nolevel, const char *text,
+ int before, int after,
int regexp, int fullword, int case_sensitive)
{
#ifdef HAVE_REGEX_H
regex_t preg;
#endif
- GList *line, *tmp;
+ LINE_REC *line, *pre_line;
GList *matches;
- GString *str;
+ GString *str;
+ int i, match_after, line_matched;
g_return_val_if_fail(buffer != NULL, NULL);
g_return_val_if_fail(text != NULL, NULL);
#endif
}
- matches = NULL;
+ matches = NULL; match_after = 0;
str = g_string_new(NULL);
- line = g_list_find(buffer->lines, startline);
- if (line == NULL)
- line = buffer->lines;
+ line = startline != NULL ? startline : buffer->first_line;
- for (tmp = line; tmp != NULL; tmp = tmp->next) {
- LINE_REC *rec = tmp->data;
-
- if ((rec->info.level & level) == 0 ||
- (rec->info.level & nolevel) != 0)
+ for (; line != NULL; line = line->next) {
+ if ((line->info.level & level) == 0 ||
+ (line->info.level & nolevel) != 0)
continue;
if (*text == '\0') {
/* no search word, everything matches */
- textbuffer_line_ref(rec);
- matches = g_list_append(matches, rec);
+ textbuffer_line_ref(line);
+ matches = g_list_append(matches, line);
continue;
}
- textbuffer_line2text(rec, FALSE, str);
+ textbuffer_line2text(line, FALSE, str);
- if (
+ line_matched =
#ifdef HAVE_REGEX_H
- regexp ? regexec(&preg, str->str, 0, NULL, 0) == 0 :
+ 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 */
- textbuffer_line_ref(rec);
- matches = g_list_append(matches, rec);
- }
- }
-#ifdef HAVE_REGEX_H
- if (regexp) regfree(&preg);
-#endif
- g_string_free(str, TRUE);
- return matches;
-}
-
-#if 0 /* FIXME: saving formats is broken */
-static char *line_read_format(unsigned const char **text)
-{
- GString *str;
- char *ret;
-
- str = g_string_new(NULL);
- for (;;) {
- if (**text == '\0') {
- if ((*text)[1] == LINE_CMD_EOL) {
- /* leave text at \0<eof> */
- break;
+ fullword ? strstr_full_case(str->str, text, !case_sensitive) != NULL :
+ case_sensitive ? strstr(str->str, text) != NULL :
+ stristr(str->str, text) != NULL;
+ if (line_matched) {
+ /* add the -before lines */
+ pre_line = line;
+ for (i = 0; i < before; i++) {
+ if (pre_line->prev == NULL ||
+ g_list_find(matches, pre_line->prev) != NULL)
+ break;
+ pre_line = pre_line->prev;
}
- if ((*text)[1] == LINE_CMD_FORMAT_CONT) {
- /* leave text at \0<format_cont> */
- break;
- }
- (*text)++;
- if (**text == LINE_CMD_FORMAT) {
- /* move text to start after \0<format> */
- (*text)++;
- break;
+ for (; pre_line != line; pre_line = pre_line->next) {
+ textbuffer_line_ref(pre_line);
+ matches = g_list_append(matches, pre_line);
}
- if (**text == LINE_CMD_CONTINUE) {
- unsigned char *tmp;
-
- memcpy(&tmp, (*text)+1, sizeof(char *));
- *text = tmp;
- continue;
- } else if (**text & 0x80)
- (*text)++;
- continue;
+ match_after = after;
}
- g_string_append_c(str, (char) **text);
- (*text)++;
- }
-
- ret = str->str;
- g_string_free(str, FALSE);
- return ret;
-}
-
-static char *textbuffer_line_get_format(WINDOW_REC *window, LINE_REC *line,
- GString *raw)
-{
- const unsigned char *text;
- char *module, *format_name, *args[MAX_FORMAT_PARAMS], *ret;
- TEXT_DEST_REC dest;
- int formatnum, argcount;
-
- text = (const unsigned char *) line->text;
-
- /* skip the beginning of the line until we find the format */
- g_free(line_read_format(&text));
- if (text[1] == LINE_CMD_FORMAT_CONT) {
- g_string_append_c(raw, '\0');
- g_string_append_c(raw, (char)LINE_CMD_FORMAT_CONT);
- return NULL;
- }
-
- /* read format information */
- module = line_read_format(&text);
- format_name = line_read_format(&text);
-
- if (raw != NULL) {
- g_string_append_c(raw, '\0');
- g_string_append_c(raw, (char)LINE_CMD_FORMAT);
-
- g_string_append(raw, module);
-
- g_string_append_c(raw, '\0');
- g_string_append_c(raw, (char)LINE_CMD_FORMAT);
-
- g_string_append(raw, format_name);
- }
+ if (line_matched || match_after > 0) {
+ /* matched */
+ textbuffer_line_ref(line);
+ matches = g_list_append(matches, line);
- formatnum = format_find_tag(module, format_name);
- if (formatnum == -1)
- ret = NULL;
- else {
- argcount = 0;
- memset(args, 0, sizeof(args));
- while (*text != '\0' || text[1] != LINE_CMD_EOL) {
- args[argcount] = line_read_format(&text);
- if (raw != NULL) {
- g_string_append_c(raw, '\0');
- g_string_append_c(raw,
- (char)LINE_CMD_FORMAT);
-
- g_string_append(raw, args[argcount]);
- }
- argcount++;
+ if ((!line_matched && --match_after == 0) ||
+ (line_matched && match_after == 0 && before > 0))
+ matches = g_list_append(matches, NULL);
}
-
- /* get the format text */
- format_create_dest(&dest, NULL, NULL, line->level, window);
- ret = format_get_text_theme_charargs(current_theme,
- module, &dest,
- formatnum, args);
- while (argcount > 0)
- g_free(args[--argcount]);
- }
-
- g_free(module);
- g_free(format_name);
-
- return ret;
-}
-
-void textbuffer_reformat_line(WINDOW_REC *window, LINE_REC *line)
-{
- GUI_WINDOW_REC *gui;
- TEXT_DEST_REC dest;
- GString *raw;
- char *str, *tmp, *prestr, *linestart, *leveltag;
-
- gui = WINDOW_GUI(window);
-
- raw = g_string_new(NULL);
- str = textbuffer_line_get_format(window, line, raw);
-
- if (str == NULL && raw->len == 2 &&
- raw->str[1] == (char)LINE_CMD_FORMAT_CONT) {
- /* multiline format, format explained in one the
- following lines. remove this line. */
- textbuffer_line_remove(window, line, FALSE);
- } else if (str != NULL) {
- /* FIXME: ugly ugly .. and this can't handle
- non-formatted lines.. */
- g_string_append_c(raw, '\0');
- g_string_append_c(raw, (char)LINE_CMD_EOL);
-
- textbuffer_line_text_free(gui, line);
-
- gui->temp_line = line;
- gui->temp_line->text = gui->cur_text->buffer+gui->cur_text->pos;
- gui->cur_text->lines++;
- gui->eol_marked = FALSE;
-
- format_create_dest(&dest, NULL, NULL, line->level, window);
-
- linestart = format_get_line_start(current_theme, &dest, line->time);
- leveltag = format_get_level_tag(current_theme, &dest);
-
- prestr = g_strconcat(linestart == NULL ? "" : linestart,
- leveltag, NULL);
- g_free_not_null(linestart);
- g_free_not_null(leveltag);
-
- tmp = format_add_linestart(str, prestr);
- g_free(str);
- g_free(prestr);
-
- format_send_to_gui(&dest, tmp);
- g_free(tmp);
-
- textbuffer_line_append(gui, raw->str, raw->len);
-
- gui->eol_marked = TRUE;
- gui->temp_line = NULL;
}
- g_string_free(raw, TRUE);
-}
+#ifdef HAVE_REGEX_H
+ if (regexp) regfree(&preg);
#endif
+ g_string_free(str, TRUE);
+ return matches;
+}
void textbuffer_init(void)
{