Added SILC Thread Queue API
[crypto.git] / apps / irssi / src / fe-text / textbuffer-reformat.c
1 /*
2  textbuffer-reformat.c : Reformatting lines in text buffer
3
4     Copyright (C) 1999-2001 Timo Sirainen
5
6     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10
11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with this program; if not, write to the Free Software
18     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 */
20
21 #include "module.h"
22 #include "signals.h"
23 #include "settings.h"
24
25 #include "formats.h"
26
27 #include "gui-windows.h"
28 #include "gui-printtext.h"
29 #include "textbuffer.h"
30
31 static GString *format;
32 static int scrollback_save_formats;
33
34 /* Read one block between \0<format>s */
35 static char *line_read_format(unsigned const char **text)
36 {
37         GString *str;
38         char *ret;
39
40         str = g_string_new(NULL);
41         for (;;) {
42                 if (**text == '\0') {
43                         if ((*text)[1] == LINE_CMD_EOL) {
44                                 /* leave text at \0<eof> */
45                                 break;
46                         }
47                         if ((*text)[1] == LINE_CMD_FORMAT_CONT) {
48                                 /* leave text at \0<format_cont> */
49                                 break;
50                         }
51                         (*text)++;
52
53                          if (**text == LINE_CMD_FORMAT) {
54                                 /* move text to start after \0<format> */
55                                 (*text)++;
56                                 break;
57                         }
58
59                         if (**text == LINE_CMD_CONTINUE) {
60                                 unsigned char *tmp;
61
62                                 memcpy(&tmp, (*text)+1, sizeof(char *));
63                                 *text = tmp;
64                                 continue;
65                         } else if (**text & 0x80)
66                                 (*text)++;
67                         continue;
68                 }
69
70                 g_string_append_c(str, (char) **text);
71                 (*text)++;
72         }
73
74         ret = str->str;
75         g_string_free(str, FALSE);
76         return ret;
77 }
78
79 static char *textbuffer_line_get_format(WINDOW_REC *window, LINE_REC *line,
80                                         GString *raw)
81 {
82         const unsigned char *text;
83         char *module, *format_name, *args[MAX_FORMAT_PARAMS], *ret;
84         TEXT_DEST_REC dest;
85         int formatnum, argcount;
86
87         text = (const unsigned char *) line->text;
88
89         /* skip the beginning of the line until we find the format */
90         format_name = line_read_format(&text);
91         g_free(format_name);
92         if (text[1] == LINE_CMD_FORMAT_CONT) {
93                 if (raw != NULL) {
94                         g_string_append_c(raw, '\0');
95                         g_string_append_c(raw, (char)LINE_CMD_FORMAT_CONT);
96                 }
97                 return NULL;
98         }
99
100         /* read format information */
101         module = line_read_format(&text);
102         format_name = line_read_format(&text);
103
104         if (raw != NULL) {
105                 g_string_append_c(raw, '\0');
106                 g_string_append_c(raw, (char)LINE_CMD_FORMAT);
107
108                 g_string_append(raw, module);
109
110                 g_string_append_c(raw, '\0');
111                 g_string_append_c(raw, (char)LINE_CMD_FORMAT);
112
113                 g_string_append(raw, format_name);
114         }
115
116         formatnum = format_find_tag(module, format_name);
117         if (formatnum == -1)
118                 ret = NULL;
119         else {
120                 argcount = 0;
121                 memset(args, 0, sizeof(args));
122                 while (*text != '\0' || text[1] != LINE_CMD_EOL) {
123                         args[argcount] = line_read_format(&text);
124                         if (raw != NULL) {
125                                 g_string_append_c(raw, '\0');
126                                 g_string_append_c(raw,
127                                                   (char)LINE_CMD_FORMAT);
128
129                                 g_string_append(raw, args[argcount]);
130                         }
131                         argcount++;
132                 }
133
134                 /* get the format text */
135                 format_create_dest(&dest, NULL, NULL, line->info.level, window);
136                 ret = format_get_text_theme_charargs(current_theme,
137                                                      module, &dest,
138                                                      formatnum, args);
139                 while (argcount > 0)
140                         g_free(args[--argcount]);
141         }
142
143         g_free(module);
144         g_free(format_name);
145
146         return ret;
147 }
148
149 void textbuffer_reformat_line(WINDOW_REC *window, LINE_REC *line)
150 {
151         GUI_WINDOW_REC *gui;
152         TEXT_DEST_REC dest;
153         LINE_REC *line_prev;
154         LINE_INFO_REC line_info;
155         GString *raw;
156         char *str, *tmp, *prestr, *linestart, *leveltag;
157
158         gui = WINDOW_GUI(window);
159
160         raw = g_string_new(NULL);
161         str = textbuffer_line_get_format(window, line, raw);
162
163         if (str == NULL && raw->len == 2 &&
164             raw->str[1] == (char)LINE_CMD_FORMAT_CONT) {
165                 /* multiline format, format explained in one the
166                    following lines. remove this line. */
167                 textbuffer_view_remove_line(gui->view, line);
168         } else if (str != NULL) {
169                 /* FIXME: ugly ugly .. and this can't handle
170                    unformatted lines.. */
171                 g_string_append_c(raw, '\0');
172                 g_string_append_c(raw, (char)LINE_CMD_EOL);
173
174                 line_prev = line->prev;
175                 memcpy(&line_info, &line->info, sizeof(line_info));
176                 textbuffer_view_remove_line(gui->view, line); line = NULL;
177
178                 format_create_dest(&dest, NULL, NULL, line_info.level, window);
179
180                 linestart = format_get_line_start(current_theme, &dest, line_info.time);
181                 leveltag = format_get_level_tag(current_theme, &dest);
182
183                 prestr = g_strconcat(linestart == NULL ? "" : linestart,
184                                      leveltag, NULL);
185                 g_free_not_null(linestart);
186                 g_free_not_null(leveltag);
187
188                 tmp = format_add_linestart(str, prestr);
189                 g_free(str);
190                 g_free(prestr);
191
192                 gui_printtext_after(&dest, line_prev, tmp);
193                 g_free(tmp);
194
195                 line = textbuffer_insert(gui->view->buffer, gui->insert_after,
196                                          (unsigned char *) raw->str,
197                                          raw->len, &line_info);
198                 textbuffer_view_insert_line(gui->view, line);
199         }
200         g_string_free(raw, TRUE);
201 }
202
203 static void sig_print_format(THEME_REC *theme, const char *module,
204                              TEXT_DEST_REC *dest, void *formatnump,
205                              char **args)
206 {
207         FORMAT_REC *formats;
208         int formatnum, n;
209
210         if (!scrollback_save_formats)
211                 return;
212
213         formatnum = GPOINTER_TO_INT(formatnump);
214         formats = g_hash_table_lookup(default_formats, module);
215
216         /* <module><format_name><arg...> */
217         g_string_truncate(format, 0);
218
219         g_string_append_c(format, '\0');
220         g_string_append_c(format, (char)LINE_CMD_FORMAT);
221
222         g_string_append(format, module);
223
224         g_string_append_c(format, '\0');
225         g_string_append_c(format, (char)LINE_CMD_FORMAT);
226
227         g_string_append(format, formats[formatnum].tag);
228
229         for (n = 0; n < formats[formatnum].params; n++) {
230                 g_string_append_c(format, '\0');
231                 g_string_append_c(format, (char)LINE_CMD_FORMAT);
232
233                 if (args[n] != NULL)
234                         g_string_append(format, args[n]);
235         }
236 }
237
238 static void sig_gui_printtext_finished(WINDOW_REC *window)
239 {
240         GUI_WINDOW_REC *gui;
241         LINE_REC *insert_after;
242
243         if (format->len == 0)
244                 return;
245
246         /* save format of the line */
247         gui = WINDOW_GUI(window);
248         insert_after = gui->use_insert_after ?
249                 gui->insert_after : gui->view->buffer->cur_line;
250
251         textbuffer_insert(gui->view->buffer, insert_after,
252                           (unsigned char *) format->str,
253                           format->len, NULL);
254
255         g_string_truncate(format, 0);
256 }
257
258 static void read_settings(void)
259 {
260         scrollback_save_formats = settings_get_bool("scrollback_save_formats");
261 }
262
263 void textbuffer_reformat_init(void)
264 {
265         format = g_string_new(NULL);
266         settings_add_bool("history", "scrollback_save_formats", FALSE);
267
268         read_settings();
269         signal_add("print format", (SIGNAL_FUNC) sig_print_format);
270         signal_add_first("gui print text finished", (SIGNAL_FUNC) sig_gui_printtext_finished);
271         signal_add("setup changed", (SIGNAL_FUNC) read_settings);
272 }
273
274 void textbuffer_reformat_deinit(void)
275 {
276         g_string_free(format, TRUE);
277
278         signal_remove("print format", (SIGNAL_FUNC) sig_print_format);
279         signal_remove("gui print text finished", (SIGNAL_FUNC) sig_gui_printtext_finished);
280         signal_remove("setup changed", (SIGNAL_FUNC) read_settings);
281 }