1
0
mirror of https://github.com/weechat/weechat.git synced 2026-07-08 02:33:12 +02:00

api: allow hook_line to duplicate a message on multiple buffers

This commit is contained in:
Sébastien Helleu
2023-06-23 12:02:02 +02:00
parent 49f52cc051
commit 1dcad3f029
11 changed files with 654 additions and 242 deletions
+52 -8
View File
@@ -27,6 +27,7 @@
#include <string.h>
#include "../weechat.h"
#include "../wee-arraylist.h"
#include "../wee-hashtable.h"
#include "../wee-hook.h"
#include "../wee-infolist.h"
@@ -121,17 +122,31 @@ hook_line (struct t_weechat_plugin *plugin, const char *buffer_type,
* Executes a line hook and updates the line data.
*/
void
struct t_arraylist *
hook_line_exec (struct t_gui_line *line)
{
struct t_hook *ptr_hook, *next_hook;
struct t_hashtable *hashtable, *hashtable2;
char str_value[128], *str_tags;
if (!weechat_hooks[HOOK_TYPE_LINE])
return;
struct t_arraylist *buffers;
struct t_gui_buffer *ptr_buffer;
char str_value[128], *str_tags, **str_buffers;
int i, size;
hashtable = NULL;
buffers = NULL;
str_buffers = NULL;
buffers = arraylist_new (16, 0, 0, NULL, NULL, NULL, NULL);
if (!buffers)
goto end;
arraylist_add (buffers, line->data->buffer);
if (!weechat_hooks[HOOK_TYPE_LINE])
goto end;
str_buffers = string_dyn_alloc (256);
if (!str_buffers)
goto end;
hook_exec_start ();
@@ -161,8 +176,28 @@ hook_line_exec (struct t_gui_line *line)
if (!hashtable)
break;
}
HASHTABLE_SET_POINTER("buffer", line->data->buffer);
HASHTABLE_SET_STR("buffer_name", line->data->buffer->full_name);
size = arraylist_size (buffers);
/* build list of buffer pointers */
string_dyn_copy (str_buffers, NULL);
for (i = 0; i < size; i++)
{
if (i > 0)
string_dyn_concat (str_buffers, ",", -1);
snprintf (str_value, sizeof (str_value),
"0x%lx", (unsigned long)(arraylist_get (buffers, i)));
string_dyn_concat (str_buffers, str_value, -1);
}
HASHTABLE_SET_STR("buffer", *str_buffers);
/* build list of buffer names */
string_dyn_copy (str_buffers, NULL);
for (i = 0; i < size; i++)
{
if (i > 0)
string_dyn_concat (str_buffers, ",", -1);
ptr_buffer = (struct t_gui_buffer *)arraylist_get (buffers, i);
string_dyn_concat (str_buffers, ptr_buffer->full_name, -1);
}
HASHTABLE_SET_STR("buffer_name", *str_buffers);
HASHTABLE_SET_STR("buffer_type",
gui_buffer_type_string[line->data->buffer->type]);
HASHTABLE_SET_INT("y", line->data->y);
@@ -191,7 +226,7 @@ hook_line_exec (struct t_gui_line *line)
if (hashtable2)
{
gui_line_hook_update (line, hashtable, hashtable2);
gui_line_hook_update (line, buffers, hashtable, hashtable2);
hashtable_free (hashtable2);
if (!line->data->buffer)
break;
@@ -203,8 +238,17 @@ hook_line_exec (struct t_gui_line *line)
hook_exec_end ();
end:
if (hashtable)
hashtable_free (hashtable);
if (str_buffers)
string_dyn_free (str_buffers, 1);
if (line->data->buffer && buffers && (arraylist_size (buffers) == 0))
arraylist_add (buffers, line->data->buffer);
return buffers;
}
/*
+1 -1
View File
@@ -51,7 +51,7 @@ extern struct t_hook *hook_line (struct t_weechat_plugin *plugin,
t_hook_callback_line *callback,
const void *callback_pointer,
void *callback_data);
extern void hook_line_exec (struct t_gui_line *line);
extern struct t_arraylist *hook_line_exec (struct t_gui_line *line);
extern void hook_line_free_data (struct t_hook *hook);
extern int hook_line_add_to_infolist (struct t_infolist_item *item,
struct t_hook *hook);
+207 -165
View File
@@ -32,6 +32,7 @@
#include <regex.h>
#include "../core/weechat.h"
#include "../core/wee-arraylist.h"
#include "../core/wee-config.h"
#include "../core/wee-eval.h"
#include "../core/wee-hashtable.h"
@@ -592,15 +593,18 @@ gui_chat_printf_date_tags_internal (struct t_gui_buffer *buffer,
const char *tags,
char *message)
{
int display_time, length_data, length_str;
int i, display_time, length_data, length_str, num_buffers;
char *ptr_msg, *pos_prefix, *pos_tab;
char *modifier_data, *string, *new_string, *pos_newline;
struct t_gui_line *new_line;
struct t_gui_line *new_line, *new_line2;
struct t_arraylist *buffers;
new_line = NULL;
new_line2 = NULL;
string = NULL;
modifier_data = NULL;
new_string = NULL;
buffers = NULL;
display_time = 1;
@@ -643,134 +647,132 @@ gui_chat_printf_date_tags_internal (struct t_gui_buffer *buffer,
if (!new_line)
goto no_print;
hook_line_exec (new_line);
if (!new_line->data->buffer)
buffers = hook_line_exec (new_line);
if (!buffers || !new_line->data->buffer)
goto no_print;
/* call modifier for message printed ("weechat_print") */
length_data = 64 + 1 + ((tags) ? strlen (tags) : 0) + 1;
modifier_data = malloc (length_data);
length_str = ((new_line->data->prefix && new_line->data->prefix[0]) ? strlen (new_line->data->prefix) : 1) +
1 +
(new_line->data->message ? strlen (new_line->data->message) : 0) +
1;
string = malloc (length_str);
if (modifier_data && string)
num_buffers = arraylist_size (buffers);
for (i = 0; i < num_buffers; i++)
{
snprintf (modifier_data, length_data,
"0x%lx;%s",
(unsigned long)buffer,
(tags) ? tags : "");
if (display_time)
{
snprintf (string, length_str,
"%s\t%s",
(new_line->data->prefix && new_line->data->prefix[0]) ?
new_line->data->prefix : " ",
(new_line->data->message) ? new_line->data->message : "");
}
else
{
snprintf (string, length_str,
"\t\t%s",
(new_line->data->message) ? new_line->data->message : "");
}
new_string = hook_modifier_exec (NULL,
"weechat_print",
modifier_data,
string);
if (new_string)
{
if (!new_string[0] && string[0])
{
/*
* modifier returned empty message, then we'll not
* print anything
*/
goto no_print;
}
else if (strcmp (string, new_string) != 0)
{
if (!buffer->input_multiline)
{
/* if input_multiline is not set, keep only first line */
pos_newline = strchr (new_string, '\n');
if (pos_newline)
pos_newline[0] = '\0';
}
new_line2 = gui_line_dup_for_buffer (new_line,
arraylist_get (buffers, i));
if (!new_line2)
goto no_print;
/* use new message if there are changes */
display_time = 1;
pos_prefix = NULL;
ptr_msg = new_string;
/* space followed by tab => prefix ignored */
if ((ptr_msg[0] == ' ') && (ptr_msg[1] == '\t'))
/* call modifier for message printed ("weechat_print") */
length_data = 64 + 1 + ((tags) ? strlen (tags) : 0) + 1;
modifier_data = malloc (length_data);
length_str = ((new_line2->data->prefix && new_line2->data->prefix[0]) ? strlen (new_line2->data->prefix) : 1) +
1 +
(new_line2->data->message ? strlen (new_line2->data->message) : 0) +
1;
string = malloc (length_str);
if (modifier_data && string)
{
snprintf (modifier_data, length_data,
"0x%lx;%s",
(unsigned long)buffer,
(tags) ? tags : "");
if (display_time)
{
snprintf (string, length_str,
"%s\t%s",
(new_line2->data->prefix && new_line2->data->prefix[0]) ?
new_line2->data->prefix : " ",
(new_line2->data->message) ? new_line2->data->message : "");
}
else
{
snprintf (string, length_str,
"\t\t%s",
(new_line2->data->message) ? new_line2->data->message : "");
}
new_string = hook_modifier_exec (NULL,
"weechat_print",
modifier_data,
string);
if (new_string)
{
if (!new_string[0] && string[0])
{
ptr_msg += 2;
/*
* modifier returned empty message, then we'll not
* print anything
*/
goto no_print;
}
else
else if (strcmp (string, new_string) != 0)
{
/* if two first chars are tab, then do not display time */
if ((ptr_msg[0] == '\t') && (ptr_msg[1] == '\t'))
if (!buffer->input_multiline)
{
/* if input_multiline is not set, keep only first line */
pos_newline = strchr (new_string, '\n');
if (pos_newline)
pos_newline[0] = '\0';
}
/* use new message if there are changes */
display_time = 1;
pos_prefix = NULL;
ptr_msg = new_string;
/* space followed by tab => prefix ignored */
if ((ptr_msg[0] == ' ') && (ptr_msg[1] == '\t'))
{
display_time = 0;
new_line->data->date = 0;
ptr_msg += 2;
}
else
{
/* if tab found, use prefix (before tab) */
pos_tab = strchr (ptr_msg, '\t');
if (pos_tab)
/* if two first chars are tab, then do not display time */
if ((ptr_msg[0] == '\t') && (ptr_msg[1] == '\t'))
{
pos_tab[0] = '\0';
pos_prefix = ptr_msg;
ptr_msg = pos_tab + 1;
display_time = 0;
new_line2->data->date = 0;
ptr_msg += 2;
}
else
{
/* if tab found, use prefix (before tab) */
pos_tab = strchr (ptr_msg, '\t');
if (pos_tab)
{
pos_tab[0] = '\0';
pos_prefix = ptr_msg;
ptr_msg = pos_tab + 1;
}
}
}
if ((new_line2->data->date == 0) && display_time)
new_line2->data->date = new_line2->data->date_printed;
if (new_line2->data->prefix)
string_shared_free (new_line2->data->prefix);
if (pos_prefix)
{
new_line2->data->prefix = (char *)string_shared_get (pos_prefix);
}
else
{
new_line2->data->prefix = (new_line2->data->date != 0) ?
(char *)string_shared_get ("") : NULL;
}
new_line2->data->prefix_length = gui_chat_strlen_screen (
new_line2->data->prefix);
if (new_line2->data->message)
free (new_line2->data->message);
new_line2->data->message = strdup (ptr_msg);
}
if ((new_line->data->date == 0) && display_time)
new_line->data->date = new_line->data->date_printed;
if (new_line->data->prefix)
string_shared_free (new_line->data->prefix);
if (pos_prefix)
{
new_line->data->prefix = (char *)string_shared_get (pos_prefix);
}
else
{
new_line->data->prefix = (new_line->data->date != 0) ?
(char *)string_shared_get ("") : NULL;
}
new_line->data->prefix_length = gui_chat_strlen_screen (
new_line->data->prefix);
if (new_line->data->message)
free (new_line->data->message);
new_line->data->message = strdup (ptr_msg);
}
}
/* add line in the buffer */
gui_line_add (new_line2);
/* run hook_print for the new line */
if (new_line2->data->buffer && new_line2->data->buffer->print_hooks_enabled)
hook_print_exec (new_line2->data->buffer, new_line2);
gui_buffer_ask_chat_refresh (new_line2->data->buffer, 1);
}
/* add line in the buffer */
gui_line_add (new_line);
/* run hook_print for the new line */
if (new_line->data->buffer && new_line->data->buffer->print_hooks_enabled)
hook_print_exec (new_line->data->buffer, new_line);
gui_buffer_ask_chat_refresh (new_line->data->buffer, 1);
if (string)
free (string);
if (modifier_data)
free (modifier_data);
if (new_string)
free (new_string);
return;
no_print:
if (new_line)
{
gui_line_free_data (new_line);
@@ -782,6 +784,30 @@ no_print:
free (modifier_data);
if (new_string)
free (new_string);
if (buffers)
arraylist_free (buffers);
return;
no_print:
if (new_line)
{
gui_line_free_data (new_line);
free (new_line);
}
if (new_line2)
{
gui_line_free_data (new_line2);
free (new_line2);
}
if (string)
free (string);
if (modifier_data)
free (modifier_data);
if (new_string)
free (new_string);
if (buffers)
arraylist_free (buffers);
}
/*
@@ -932,9 +958,13 @@ void
gui_chat_printf_y_date_tags (struct t_gui_buffer *buffer, int y, time_t date,
const char *tags, const char *message, ...)
{
struct t_gui_line *ptr_line, *new_line, *new_line_empty;
struct t_gui_line *ptr_line, *new_line, *new_line2, *new_line_empty;
struct t_arraylist *buffers;
time_t date_printed;
int i, last_y, num_lines_to_add;
int i, last_y, num_lines_to_add, num_buffers;
new_line = NULL;
buffers = NULL;
if (!message)
return;
@@ -964,84 +994,96 @@ gui_chat_printf_y_date_tags (struct t_gui_buffer *buffer, int y, time_t date,
if (!new_line)
goto end;
hook_line_exec (new_line);
if (!new_line->data->buffer)
buffers = hook_line_exec (new_line);
if (!buffers || !new_line->data->buffer)
{
gui_line_free_data (new_line);
free (new_line);
goto end;
}
if (new_line->data->message && new_line->data->message[0])
num_buffers = arraylist_size (buffers);
for (i = 0; i < num_buffers; i++)
{
if (gui_init_ok)
new_line2 = gui_line_dup_for_buffer (new_line,
arraylist_get (buffers, i));
if (new_line2->data->message && new_line2->data->message[0])
{
/* compute the number of lines to add before y */
if (new_line->data->buffer->own_lines
&& new_line->data->buffer->own_lines->last_line)
if (gui_init_ok)
{
num_lines_to_add = y - new_line->data->buffer->own_lines->last_line->data->y - 1;
/* compute the number of lines to add before y */
if (new_line2->data->buffer->own_lines
&& new_line2->data->buffer->own_lines->last_line)
{
num_lines_to_add = y - new_line2->data->buffer->own_lines->last_line->data->y - 1;
}
else
{
num_lines_to_add = y;
}
if (num_lines_to_add > 0)
{
/*
* add empty line(s) before asked line, to ensure there is at
* least "y" lines in buffer, and then be able to scroll
* properly buffer page by page
*/
for (i = y - num_lines_to_add; i < y; i++)
{
new_line_empty = gui_line_new (new_line2->data->buffer,
i, 0, 0, NULL, NULL, "");
if (new_line_empty)
gui_line_add_y (new_line_empty);
}
}
gui_line_add_y (new_line2);
}
else
{
num_lines_to_add = y;
string_fprintf (stdout, "%s\n", new_line2->data->message);
gui_line_free_data (new_line2);
free (new_line2);
}
if (num_lines_to_add > 0)
{
/*
* add empty line(s) before asked line, to ensure there is at
* least "y" lines in buffer, and then be able to scroll
* properly buffer page by page
*/
for (i = y - num_lines_to_add; i < y; i++)
{
new_line_empty = gui_line_new (new_line->data->buffer,
i, 0, 0, NULL, NULL, "");
if (new_line_empty)
gui_line_add_y (new_line_empty);
}
}
gui_line_add_y (new_line);
}
else
{
string_fprintf (stdout, "%s\n", new_line->data->message);
gui_line_free_data (new_line);
free (new_line);
}
}
else
{
if (gui_init_ok)
{
/* delete line */
last_y = (new_line->data->buffer->own_lines->last_line) ?
new_line->data->buffer->own_lines->last_line->data->y : 0;
if (y <= last_y)
if (gui_init_ok)
{
for (ptr_line = new_line->data->buffer->own_lines->first_line;
ptr_line; ptr_line = ptr_line->next_line)
/* delete line */
last_y = (new_line2->data->buffer->own_lines->last_line) ?
new_line2->data->buffer->own_lines->last_line->data->y : 0;
if (y <= last_y)
{
if (ptr_line->data->y >= y)
break;
}
if (ptr_line && (ptr_line->data->y == y))
{
if (ptr_line->next_line)
gui_line_clear (ptr_line);
else
gui_line_free (new_line->data->buffer, ptr_line);
gui_buffer_ask_chat_refresh (new_line->data->buffer, 2);
for (ptr_line = new_line2->data->buffer->own_lines->first_line;
ptr_line; ptr_line = ptr_line->next_line)
{
if (ptr_line->data->y >= y)
break;
}
if (ptr_line && (ptr_line->data->y == y))
{
if (ptr_line->next_line)
gui_line_clear (ptr_line);
else
gui_line_free (new_line2->data->buffer, ptr_line);
gui_buffer_ask_chat_refresh (new_line2->data->buffer, 2);
}
}
}
gui_line_free_data (new_line2);
free (new_line2);
}
gui_line_free_data (new_line);
free (new_line);
}
end:
if (new_line)
{
gui_line_free_data (new_line);
free (new_line);
}
free (vbuffer);
if (buffers)
arraylist_free (buffers);
}
/*
+172 -12
View File
@@ -30,6 +30,7 @@
#include <regex.h>
#include "../core/weechat.h"
#include "../core/wee-arraylist.h"
#include "../core/wee-config.h"
#include "../core/wee-hashtable.h"
#include "../core/wee-hdata.h"
@@ -112,6 +113,45 @@ gui_line_tags_alloc (struct t_gui_line_data *line_data, const char *tags)
}
}
/*
* Duplicates array with tags of a line into another line.
*/
void
gui_line_tags_dup (struct t_gui_line_data *line_data,
struct t_gui_line_data *line_data2)
{
int i;
if (!line_data || !line_data2)
return;
if (line_data->tags_count > 0)
{
line_data2->tags_array = malloc (
(line_data->tags_count + 1) * sizeof (*(line_data->tags_array)));
if (line_data2->tags_array)
{
line_data2->tags_count = line_data->tags_count;
for (i = 0; i < line_data->tags_count; i++)
{
line_data2->tags_array[i] = (char *)string_shared_get (
line_data->tags_array[i]);
}
line_data2->tags_array[line_data->tags_count] = NULL;
}
else
{
line_data2->tags_count = 0;
}
}
else
{
line_data2->tags_count = 0;
line_data2->tags_array = NULL;
}
}
/*
* Frees array with tags in a line_data.
*/
@@ -1561,12 +1601,96 @@ gui_line_new (struct t_gui_buffer *buffer, int y, time_t date,
return new_line;
}
/*
* Duplicates a line to print it on another buffer.
*/
struct t_gui_line *
gui_line_dup_for_buffer (struct t_gui_line *line, struct t_gui_buffer *buffer)
{
struct t_gui_line *new_line;
struct t_gui_line_data *new_line_data;
if (!line || !buffer)
return NULL;
/* create new line */
new_line = malloc (sizeof (*new_line));
if (!new_line)
return NULL;
/* create data for line */
new_line_data = malloc (sizeof (*new_line_data));
if (!new_line_data)
{
free (new_line);
return NULL;
}
new_line->data = new_line_data;
/* fill data in new line */
new_line->data->buffer = buffer;
new_line->data->message = (line->data->message) ?
strdup (line->data->message) : strdup ("");
if (buffer->type == GUI_BUFFER_TYPE_FORMATTED)
{
/*
* the line identifier is almost unique: when reaching INT_MAX, it is
* reset to 0; it is extremely unlikely all integer are used in the
* same buffer, that would mean the buffer has a huge number of lines;
* when searching a line id in a buffer, it is recommended to start
* from the last line and loop to the first
*/
new_line->data->id = buffer->next_line_id;
buffer->next_line_id = (buffer->next_line_id == INT_MAX) ?
0 : buffer->next_line_id + 1;
new_line->data->y = line->data->y;
new_line->data->date = line->data->date;
new_line->data->date_printed = line->data->date_printed;
new_line->data->str_time = (line->data->str_time) ?
strdup (line->data->str_time) : NULL;
gui_line_tags_dup (line->data, new_line->data);
new_line->data->refresh_needed = line->data->refresh_needed;
new_line->data->prefix = (line->data->prefix) ?
(char *)string_shared_get (line->data->prefix) : NULL;
new_line->data->prefix_length = line->data->prefix_length;
new_line->data->notify_level = line->data->notify_level;
new_line->data->highlight = line->data->highlight;
}
else
{
new_line->data->id = line->data->y;
new_line->data->y = line->data->y;
new_line->data->date = line->data->date;
new_line->data->date_printed = line->data->date_printed;
new_line->data->str_time = (line->data->str_time) ?
strdup (line->data->str_time) : NULL;
gui_line_tags_dup (line->data, new_line->data);
new_line->data->refresh_needed = line->data->refresh_needed;
new_line->data->prefix = (line->data->prefix) ?
(char *)string_shared_get (line->data->prefix) : NULL;
new_line->data->prefix_length = line->data->prefix_length;
new_line->data->notify_level = line->data->notify_level;
new_line->data->highlight = line->data->highlight;
}
/* set display flag (check if line is filtered or not) */
new_line->data->displayed = gui_filter_check_line (new_line->data);
new_line->prev_line = NULL;
new_line->next_line = NULL;
return new_line;
}
/*
* Updates data in a line via the hook_line.
*/
void
gui_line_hook_update (struct t_gui_line *line,
struct t_arraylist *buffers,
struct t_hashtable *hashtable,
struct t_hashtable *hashtable2)
{
@@ -1574,9 +1698,9 @@ gui_line_hook_update (struct t_gui_line *line,
struct t_gui_buffer *ptr_buffer;
unsigned long value_pointer;
long value;
char *error, *new_message, *pos_newline;
int rc, tags_updated, notify_level_updated, highlight_updated;
int max_notify_level;
char *error, *new_message, *pos_newline, **list_buffers;
int i, rc, tags_updated, notify_level_updated, highlight_updated;
int max_notify_level, num_buffers;
tags_updated = 0;
notify_level_updated = 0;
@@ -1587,12 +1711,30 @@ gui_line_hook_update (struct t_gui_line *line,
{
if (ptr_value2[0])
{
ptr_buffer = gui_buffer_search_by_full_name (ptr_value2);
if (gui_chat_buffer_valid (ptr_buffer, line->data->buffer->type))
line->data->buffer = ptr_buffer;
list_buffers = string_split (
ptr_value2, ",", NULL,
WEECHAT_STRING_SPLIT_STRIP_LEFT
| WEECHAT_STRING_SPLIT_STRIP_RIGHT
| WEECHAT_STRING_SPLIT_COLLAPSE_SEPS,
0, &num_buffers);
if (list_buffers)
{
arraylist_clear (buffers);
for (i = 0; i < num_buffers; i++)
{
ptr_buffer = gui_buffer_search_by_full_name (list_buffers[i]);
if (gui_chat_buffer_valid (ptr_buffer,
line->data->buffer->type))
{
arraylist_add (buffers, ptr_buffer);
}
}
string_free_split (list_buffers);
}
}
else
{
arraylist_clear (buffers);
line->data->buffer = NULL;
return;
}
@@ -1604,19 +1746,37 @@ gui_line_hook_update (struct t_gui_line *line,
{
if (ptr_value2[0])
{
if ((ptr_value2[0] == '0') && (ptr_value2[1] == 'x'))
list_buffers = string_split (
ptr_value2, ",", NULL,
WEECHAT_STRING_SPLIT_STRIP_LEFT
| WEECHAT_STRING_SPLIT_STRIP_RIGHT
| WEECHAT_STRING_SPLIT_COLLAPSE_SEPS,
0, &num_buffers);
if (list_buffers)
{
rc = sscanf (ptr_value2 + 2, "%lx", &value_pointer);
ptr_buffer = (struct t_gui_buffer *)value_pointer;
if ((rc != EOF) && (rc >= 1)
&& gui_chat_buffer_valid (ptr_buffer, line->data->buffer->type))
arraylist_clear (buffers);
for (i = 0; i < num_buffers; i++)
{
line->data->buffer = ptr_buffer;
if ((list_buffers[i][0] == '0')
&& (list_buffers[i][1] == 'x'))
{
rc = sscanf (list_buffers[i] + 2,
"%lx", &value_pointer);
ptr_buffer = (struct t_gui_buffer *)value_pointer;
if ((rc != EOF) && (rc >= 1)
&& gui_chat_buffer_valid (
ptr_buffer, line->data->buffer->type))
{
arraylist_add (buffers, ptr_buffer);
}
}
}
string_free_split (list_buffers);
}
}
else
{
arraylist_clear (buffers);
line->data->buffer = NULL;
return;
}
+3
View File
@@ -128,7 +128,10 @@ extern struct t_gui_line *gui_line_new (struct t_gui_buffer *buffer,
const char *tags,
const char *prefix,
const char *message);
extern struct t_gui_line *gui_line_dup_for_buffer (struct t_gui_line *line,
struct t_gui_buffer *buffer);
extern void gui_line_hook_update (struct t_gui_line *line,
struct t_arraylist *buffers,
struct t_hashtable *hashtable,
struct t_hashtable *hashtable2);
extern void gui_line_add (struct t_gui_line *line);