Update copyright year.
[cboard.git] / src / message.c
blob0606189b95f705c43b500b2650e60b3c04fd66b0
1 /* vim:tw=78:ts=8:sw=4:set ft=c: */
2 /*
3 Copyright (C) 2002-2024 Ben Kibbey <bjk@luxsci.net>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 #ifdef HAVE_CONFIG_H
20 #include <config.h>
21 #endif
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <stdarg.h>
26 #include <string.h>
27 #include <wctype.h>
29 #ifdef HAVE_STDARG_H
30 #include <stdarg.h>
31 #endif
33 #ifdef HAVE_LIMITS_H
34 #include <limits.h>
35 #endif
37 #include "common.h"
38 #include "conf.h"
39 #include "colors.h"
40 #include "misc.h"
41 #include "window.h"
42 #include "message.h"
44 static void
45 wordwrap_lines (wchar_t *** olines, int *nlines, int *width)
47 int i;
48 wchar_t *buf = NULL, **lines = *olines;
49 int total = *nlines, w = *width;
51 for (i = 0; i < total; i++)
53 size_t len = wcslen (lines[i]);
55 if (buf)
57 size_t blen = wcslen (buf);
59 lines[i] = Realloc (lines[i], len + blen + 1 * sizeof (wchar_t *));
60 wmemmove (&lines[i][blen], lines[i], len);
61 wmemcpy (lines[i], buf, blen);
62 lines[i][blen + len] = 0;
63 free (buf);
64 buf = NULL;
65 len = wcslen (lines[i]);
68 if (len > w)
69 w = len;
71 if (len-- > MSG_WIDTH)
73 wchar_t *p;
75 for (p = lines[i] + len; *p && len > 0; p--, len--)
77 if (iswspace (*p) && len <= MSG_WIDTH)
79 *p++ = 0;
80 buf = wcsdup (p);
81 break;
85 /* Its a very long line without any unicode space. Create a
86 * new message line. */
87 if (!buf)
89 wchar_t *t, c, *bp;
90 size_t l;
92 t = lines[i] + MSG_WIDTH;
93 c = *t;
94 *t++ = 0;
95 l = wcslen (t) + 2;
96 buf = Malloc (len * sizeof (wchar_t));
97 bp = buf;
98 *bp++ = c;
99 wmemcpy (bp, t, l - 1);
104 *width = w;
106 if (buf)
108 lines = Realloc (lines, (total + 2) * sizeof (wchar_t *));
109 lines[total++] = buf;
110 lines[total] = NULL;
111 *nlines = total;
112 *olines = lines;
113 wordwrap_lines (olines, nlines, width);
117 static void
118 build_message_lines (const char *title, const char *prompt,
119 int force_trim, const char *extra, int *h,
120 int *w, wchar_t *** str, const char *fmt, va_list ap)
122 int n;
123 char *line;
124 wchar_t **lines = NULL;
125 int width = 0, height = 0, len;
126 int total = 0;
127 wchar_t *wc, *wc_tmp, *wc_line, wc_delim[] = { '\n', 0 };
129 #ifdef HAVE_VASPRINTF
130 vasprintf (&line, fmt, ap);
131 #else
132 line = Malloc (LINE_MAX);
133 vsnprintf (line, LINE_MAX, fmt, ap);
134 #endif
136 wc = str_to_wchar (line);
137 free (line);
138 total = n = 0;
139 for (wc_line = wcstok (wc, wc_delim, &wc_tmp); wc_line;
140 wc_line = wcstok (NULL, wc_delim, &wc_tmp))
142 lines = Realloc (lines, (total + 2) * sizeof (wchar_t *));
143 lines[total++] = wcsdup (wc_line);
144 lines[total] = NULL;
147 free (wc);
148 wordwrap_lines (&lines, &total, &width);
150 if (width > MSG_WIDTH)
151 width = MSG_WIDTH;
153 if (prompt)
155 wc = str_to_wchar (prompt);
156 len = wcslen (wc);
157 width = len > width ? len : width;
158 free (wc);
161 if (extra)
163 wc = str_to_wchar (extra);
164 len = wcslen (wc);
165 width = len > width ? len : width;
166 free (wc);
169 if (title)
171 wc = str_to_wchar (title);
172 len = wcslen (wc);
173 width = len > width ? len : width;
174 free (wc);
177 height = total;
179 if (extra)
180 height++;
182 if (title)
183 height++;
185 height += 4; // 1 padding, 2 box, 1 prompt
186 width += 4; // 2 padding, 2 box
187 *h = height;
188 *w = width;
189 *str = lines;
192 static void
193 message_free (WIN *w)
195 struct message_s *m = w->data;
196 int i;
197 void *p;
199 for (i = 0; m->lines[i]; i++)
200 free (m->lines[i]);
202 free (m->lines);
203 free (m->prompt);
204 free (m->extra);
205 p = m->arg;
206 free (m);
207 w->data = p;
210 static int
211 display_message (WIN * win)
213 struct message_s *m = win->data;
214 int i;
215 int n_lines = 0;
216 int r = 0;
218 keypad (win->w, TRUE);
219 window_draw_title (win->w, win->title, m->w, CP_MESSAGE_TITLE,
220 CP_MESSAGE_BORDER);
222 for (i = 0; m->lines[i]; i++)
224 n_lines++;
226 if (m->offset && i < m->offset)
227 continue;
229 mvwprintw (win->w, (win->title) ? 2 + r : 1 + r,
230 (m->center || (!i && !m->lines[i + 1])) ?
231 CENTERX (m->w, m->lines[i]) : 1, "%ls", m->lines[i]);
232 if (++r >= LINES - 5)
233 break;
236 if (m->extra)
237 window_draw_prompt (win->w, (m->prompt) ? m->h - 3 : m->h - 2, m->w,
238 m->extra, CP_MESSAGE_PROMPT);
240 if (m->prompt)
241 window_draw_prompt (win->w, m->h - 2, m->w, m->prompt, CP_MESSAGE_PROMPT);
243 if (m->func && win->c == m->c)
245 (*m->func) (m->arg);
246 return 1;
249 if (win->c != 0)
251 if (win->c == KEY_DOWN || win->c == KEY_UP)
253 int n = 3;
255 n += m->extra ? 1 : 0;
257 if ((n_lines + n) - m->offset >= LINES - 2)
258 m->offset = win->c == KEY_DOWN ? m->offset + 1 : m->offset - 1;
259 else if (win->c == KEY_UP)
260 m->offset--;
262 if (m->offset < 0)
263 m->offset = 0;
265 werase (win->w);
266 win->c = 0;
267 return display_message (win);
270 if (win->c == KEY_RESIZE)
271 return 1;
273 message_free (win);
274 return 0;
277 return 1;
280 static void
281 message_resize_func (WIN *w)
283 struct message_s *m = w->data;
284 size_t rows = wcharv_length (m->lines);
286 if (m->offset && rows >= LINES - 5)
287 m->offset--;
289 m->h = w->rows = rows >= LINES - 5 ? LINES - 1 : rows + 5;
290 m->w = w->cols = w->cols > COLS - 2 ? COLS - 2 : w->cols;
291 wresize (w->w, w->rows, w->cols);
292 move_panel (w->p, CALCPOSY (w->rows), CALCPOSX (w->cols));
293 wclear (w->w);
294 w->func (w);
298 * The force_trim parameter will trim whitespace reguardless if there is more
299 * than one line or not (help text vs. tag viewing).
301 WIN *
302 construct_message (const char *title, const char *prompt, int center,
303 int force_trim, const char *extra_help,
304 message_func * func, void *arg, window_exit_func * efunc,
305 wint_t ckey, int freedata, window_resize_func *rfunc,
306 const char *fmt, ...)
308 wchar_t **lines = NULL;
309 va_list ap;
310 struct message_s *m = NULL;
311 WIN *win = NULL;
312 int h, w;
314 va_start (ap, fmt);
315 build_message_lines (title, prompt, force_trim, extra_help, &h, &w, &lines,
316 fmt, ap);
317 va_end (ap);
319 m = Calloc (1, sizeof (struct message_s));
320 m->lines = lines;
321 m->w = w;
322 m->h = h > LINES - 2 ? LINES - 2 : h;
323 m->center = center;
324 m->c = ckey;
325 m->func = func;
326 m->arg = arg;
328 if (prompt)
329 m->prompt = strdup (prompt);
331 if (extra_help)
332 m->extra = strdup (extra_help);
334 win = window_create (title, m->h, m->w, CALCPOSY (m->h), CALCPOSX (m->w),
335 display_message, m, efunc,
336 rfunc ? rfunc : message_resize_func);
338 win->freedata = freedata;
339 wbkgd (win->w, CP_MESSAGE_WINDOW);
340 (*win->func) (win);
341 return win;