iconv: Bail out of the loop when an illegal sequence of bytes occurs.
[elinks/elinks-j605.git] / src / bfu / msgbox.c
blobd7af62be5f95e3ac6c7df8ff87c12006865071b5
1 /* Prefabricated message box implementation. */
3 #ifdef HAVE_CONFIG_H
4 #include "config.h"
5 #endif
7 #include <stdarg.h>
9 #include "elinks.h"
11 #include "bfu/dialog.h"
12 #include "bfu/button.h"
13 #include "bfu/msgbox.h"
14 #include "bfu/text.h"
15 #include "intl/gettext/libintl.h"
16 #include "terminal/terminal.h"
17 #include "util/color.h"
18 #include "util/memlist.h"
19 #include "util/memory.h"
20 #include "util/snprintf.h"
21 #include "util/string.h"
24 struct dialog_data *
25 msg_box(struct terminal *term, struct memory_list *ml, enum msgbox_flags flags,
26 unsigned char *title, enum format_align align,
27 unsigned char *text, void *udata, int buttons, ...)
29 struct dialog *dlg;
30 va_list ap;
32 /* Check if the info string is valid. */
33 if (!text || buttons < 0) return NULL;
35 /* Use the @flags to determine whether @text should be free()d. */
36 if (flags & MSGBOX_FREE_TEXT)
37 add_one_to_ml(&ml, text);
39 /* Use the @flags to determine whether strings should be l18n'd. */
40 if (!(flags & MSGBOX_NO_INTL)) {
41 title = _(title, term);
42 if (!(flags & MSGBOX_FREE_TEXT)
43 && !(flags & MSGBOX_NO_TEXT_INTL))
44 text = _(text, term);
45 /* Button labels will be gettextized as will they be extracted
46 * from @ap. */
49 dlg = calloc_dialog(buttons + 1, 0);
50 if (!dlg) {
51 freeml(ml);
52 return NULL;
55 add_one_to_ml(&ml, dlg);
57 dlg->title = title;
58 dlg->layouter = generic_dialog_layouter;
59 dlg->layout.padding_top = 1;
60 dlg->udata2 = udata;
62 if (flags & MSGBOX_SCROLLABLE)
63 dlg->widgets->info.text.is_scrollable = 1;
64 add_dlg_text(dlg, text, align, 0);
66 va_start(ap, buttons);
68 while (dlg->number_of_widgets < buttons + 1) {
69 unsigned char *label;
70 done_handler_T *done;
71 int bflags;
73 label = va_arg(ap, unsigned char *);
74 done = va_arg(ap, done_handler_T *);
75 bflags = va_arg(ap, int);
77 if (!label) {
78 /* Skip this button. */
79 buttons--;
80 continue;
83 if (!(flags & MSGBOX_NO_INTL))
84 label = _(label, term);
86 add_dlg_ok_button(dlg, label, bflags, done, udata);
89 va_end(ap);
91 add_dlg_end(dlg, buttons + 1);
93 return do_dialog(term, dlg, ml);
96 static inline unsigned char *
97 msg_text_do(unsigned char *format, va_list ap)
99 unsigned char *info;
100 int infolen, len;
101 va_list ap2;
103 VA_COPY(ap2, ap);
105 infolen = vsnprintf(NULL, 0, format, ap2);
106 info = mem_alloc(infolen + 1);
107 if (!info) return NULL;
109 len = vsnprintf((char *) info, infolen + 1, format, ap);
110 if (len != infolen) {
111 mem_free(info);
112 return NULL;
115 /* Wear safety boots */
116 info[infolen] = '\0';
117 return info;
120 unsigned char *
121 msg_text(struct terminal *term, unsigned char *format, ...)
123 unsigned char *info;
124 va_list ap;
126 va_start(ap, format);
127 info = msg_text_do(_(format, term), ap);
128 va_end(ap);
130 return info;
133 static void
134 abort_refreshed_msg_box_handler(struct dialog_data *dlg_data)
136 void *data = dlg_data->dlg->widgets->text;
138 if (dlg_data->dlg->udata != data)
139 mem_free(data);
142 static enum dlg_refresh_code
143 refresh_msg_box(struct dialog_data *dlg_data, void *data)
145 unsigned char *(*get_info)(struct terminal *, void *) = data;
146 void *msg_data = dlg_data->dlg->udata2;
147 unsigned char *info = get_info(dlg_data->win->term, msg_data);
149 if (!info) return REFRESH_CANCEL;
151 abort_refreshed_msg_box_handler(dlg_data);
153 dlg_data->dlg->widgets->text = info;
154 return REFRESH_DIALOG;
157 void
158 refreshed_msg_box(struct terminal *term, enum msgbox_flags flags,
159 unsigned char *title, enum format_align align,
160 unsigned char *(get_info)(struct terminal *, void *),
161 void *data)
163 /* [gettext_accelerator_context(refreshed_msg_box)] */
164 struct dialog_data *dlg_data;
165 unsigned char *info = get_info(term, data);
167 if (!info) return;
169 dlg_data = msg_box(term, NULL, flags | MSGBOX_FREE_TEXT,
170 title, align,
171 info,
172 data, 1,
173 MSG_BOX_BUTTON(N_("~OK"), NULL, B_ENTER | B_ESC));
175 if (!dlg_data) return;
177 /* Save the original text to check up on it when the dialog
178 * is freed. */
179 dlg_data->dlg->udata = info;
180 dlg_data->dlg->abort = abort_refreshed_msg_box_handler;
181 refresh_dialog(dlg_data, refresh_msg_box, get_info);
184 struct dialog_data *
185 info_box(struct terminal *term, enum msgbox_flags flags,
186 unsigned char *title, enum format_align align,
187 unsigned char *text)
189 /* [gettext_accelerator_context(info_box)] */
190 return msg_box(term, NULL, flags,
191 title, align,
192 text,
193 NULL, 1,
194 MSG_BOX_BUTTON(N_("~OK"), NULL, B_ENTER | B_ESC));