da75a5a80a527279fab29e906aff27da309448cd
[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         g_free(line_read_format(&text));
91         if (text[1] == LINE_CMD_FORMAT_CONT) {
92                 if (raw != NULL) {
93                         g_string_append_c(raw, '\0');
94                         g_string_append_c(raw, (char)LINE_CMD_FORMAT_CONT);
95                 }
96                 return NULL;
97         }
98
99         /* read format information */
100         module = line_read_format(&text);
101         format_name = line_read_format(&text);
102
103         if (raw != NULL) {
104                 g_string_append_c(raw, '\0');
105                 g_string_append_c(raw, (char)LINE_CMD_FORMAT);
106
107                 g_string_append(raw, module);
108
109                 g_string_append_c(raw, '\0');
110                 g_string_append_c(raw, (char)LINE_CMD_FORMAT);
111
112                 g_string_append(raw, format_name);
113         }
114
115         formatnum = format_find_tag(module, format_name);
116         if (formatnum == -1)
117                 ret = NULL;
118         else {
119                 argcount = 0;
120                 memset(args, 0, sizeof(args));
121                 while (*text != '\0' || text[1] != LINE_CMD_EOL) {
122                         args[argcount] = line_read_format(&text);
123                         if (raw != NULL) {
124                                 g_string_append_c(raw, '\0');
125                                 g_string_append_c(raw,
126                                                   (char)LINE_CMD_FORMAT);
127
128                                 g_string_append(raw, args[argcount]);
129                         }
130                         argcount++;
131                 }
132
133                 /* get the format text */
134                 format_create_dest(&dest, NULL, NULL, line->info.level, window);
135                 ret = format_get_text_theme_charargs(current_theme,
136                                                      module, &dest,
137                                                      formatnum, args);
138                 while (argcount > 0)
139                         g_free(args[--argcount]);
140         }
141
142         g_free(module);
143         g_free(format_name);
144
145         return ret;
146 }
147
148 void textbuffer_reformat_line(WINDOW_REC *window, LINE_REC *line)
149 {
150         GUI_WINDOW_REC *gui;
151         TEXT_DEST_REC dest;
152         LINE_REC *line_prev;
153         LINE_INFO_REC line_info;
154         GString *raw;
155         char *str, *tmp, *prestr, *linestart, *leveltag;
156
157         gui = WINDOW_GUI(window);
158
159         raw = g_string_new(NULL);
160         str = textbuffer_line_get_format(window, line, raw);
161
162         if (str == NULL && raw->len == 2 &&
163             raw->str[1] == (char)LINE_CMD_FORMAT_CONT) {
164                 /* multiline format, format explained in one the
165                    following lines. remove this line. */
166                 textbuffer_view_remove_line(gui->view, line);
167         } else if (str != NULL) {
168                 /* FIXME: ugly ugly .. and this can't handle
169                    unformatted lines.. */
170                 g_string_append_c(raw, '\0');
171                 g_string_append_c(raw, (char)LINE_CMD_EOL);
172
173                 line_prev = line->prev;
174                 memcpy(&line_info, &line->info, sizeof(line_info));
175                 textbuffer_view_remove_line(gui->view, line); line = NULL;
176
177                 format_create_dest(&dest, NULL, NULL, line_info.level, window);
178
179                 linestart = format_get_line_start(current_theme, &dest, line_info.time);
180                 leveltag = format_get_level_tag(current_theme, &dest);
181
182                 prestr = g_strconcat(linestart == NULL ? "" : linestart,
183                                      leveltag, NULL);
184                 g_free_not_null(linestart);
185                 g_free_not_null(leveltag);
186
187                 tmp = format_add_linestart(str, prestr);
188                 g_free(str);
189                 g_free(prestr);
190
191                 gui_printtext_after(&dest, line_prev, tmp);
192                 g_free(tmp);
193
194                 line = textbuffer_insert(gui->view->buffer, gui->insert_after,
195                                          (unsigned char *) raw->str,
196                                          raw->len, &line_info);
197                 textbuffer_view_insert_line(gui->view, line);
198         }
199         g_string_free(raw, TRUE);
200 }
201
202 static void sig_print_format(THEME_REC *theme, const char *module,
203                              TEXT_DEST_REC *dest, void *formatnump,
204                              char **args)
205 {
206         FORMAT_REC *formats;
207         int formatnum, n;
208
209         if (!scrollback_save_formats)
210                 return;
211
212         formatnum = GPOINTER_TO_INT(formatnump);
213         formats = g_hash_table_lookup(default_formats, module);
214
215         /* <module><format_name><arg...> */
216         g_string_truncate(format, 0);
217
218         g_string_append_c(format, '\0');
219         g_string_append_c(format, (char)LINE_CMD_FORMAT);
220
221         g_string_append(format, module);
222
223         g_string_append_c(format, '\0');
224         g_string_append_c(format, (char)LINE_CMD_FORMAT);
225
226         g_string_append(format, formats[formatnum].tag);
227
228         for (n = 0; n < formats[formatnum].params; n++) {
229                 g_string_append_c(format, '\0');
230                 g_string_append_c(format, (char)LINE_CMD_FORMAT);
231
232                 if (args[n] != NULL)
233                         g_string_append(format, args[n]);
234         }
235 }
236
237 static void sig_gui_printtext_finished(WINDOW_REC *window)
238 {
239         GUI_WINDOW_REC *gui;
240         LINE_REC *insert_after;
241
242         if (format->len == 0)
243                 return;
244
245         /* save format of the line */
246         gui = WINDOW_GUI(window);
247         insert_after = gui->use_insert_after ?
248                 gui->insert_after : gui->view->buffer->cur_line;
249
250         textbuffer_insert(gui->view->buffer, insert_after,
251                           (unsigned char *) format->str,
252                           format->len, NULL);
253
254         g_string_truncate(format, 0);
255 }
256
257 static void read_settings(void)
258 {
259         scrollback_save_formats = settings_get_bool("scrollback_save_formats");
260 }
261
262 void textbuffer_reformat_init(void)
263 {
264         format = g_string_new(NULL);
265         settings_add_bool("history", "scrollback_save_formats", FALSE);
266
267         read_settings();
268         signal_add("print format", (SIGNAL_FUNC) sig_print_format);
269         signal_add_first("gui print text finished", (SIGNAL_FUNC) sig_gui_printtext_finished);
270         signal_add("setup changed", (SIGNAL_FUNC) read_settings);
271 }
272
273 void textbuffer_reformat_deinit(void)
274 {
275         g_string_free(format, TRUE);
276
277         signal_remove("print format", (SIGNAL_FUNC) sig_print_format);
278         signal_remove("print text finished", (SIGNAL_FUNC) sig_gui_printtext_finished);
279         signal_remove("setup changed", (SIGNAL_FUNC) read_settings);
280 }