Update copyright year to 2015.
[cboard.git] / src / message.c
blob9cb73aff8063cf64fd991dd0c7f6135a9b5dafe2
1 /* vim:tw=78:ts=8:sw=4:set ft=c: */
2 /*
3 Copyright (C) 2002-2015 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 wordwrap_lines (wchar_t ***olines, int *nlines, int *width)
46 int i;
47 wchar_t *buf = NULL, **lines = *olines;
48 int total = *nlines, w = *width;
50 for (i = 0; i < total; i++) {
51 size_t len = wcslen (lines[i]);
53 if (buf) {
54 size_t blen = wcslen (buf);
56 lines[i] = Realloc (lines[i], len+blen+1*sizeof(wchar_t *));
57 wmemmove (&lines[i][blen], lines[i], len);
58 wmemcpy (lines[i], buf, blen);
59 lines[i][blen+len] = 0;
60 free (buf);
61 buf = NULL;
62 len = wcslen (lines[i]);
65 if (len > w)
66 w = len;
68 if (len-- > MSG_WIDTH) {
69 wchar_t *p;
71 for (p = lines[i]+len; *p && len > 0; p--, len--) {
72 if (iswspace (*p) && len <= MSG_WIDTH) {
73 *p++ = 0;
74 buf = wcsdup (p);
75 break;
79 /* Its a very long line without any unicode space. Create a
80 * new message line. */
81 if (!buf) {
82 wchar_t *p, c, *bp;
83 size_t len;
85 p = lines[i]+MSG_WIDTH;
86 c = *p;
87 *p++ = 0;
88 len = wcslen (p)+2;
89 buf = Malloc (len*sizeof(wchar_t));
90 bp = buf;
91 *bp++ = c;
92 wmemcpy (bp, p, len-1);
97 *width = w;
99 if (buf) {
100 lines = Realloc (lines, (total+2)*sizeof(wchar_t *));
101 lines[total++] = buf;
102 lines[total] = NULL;
103 *nlines = total;
104 *olines = lines;
105 wordwrap_lines (olines, nlines, width);
109 static void build_message_lines(const char *title, const char *prompt,
110 int force_trim, const char *extra, int *h,
111 int *w, wchar_t ***str, const char *fmt,
112 va_list ap)
114 int n;
115 char *line;
116 wchar_t **lines = NULL;
117 int width = 0, height = 0, len;
118 int total = 0;
119 wchar_t *wc, *wc_tmp, *wc_line, wc_delim[] = { '\n', 0 };
121 #ifdef HAVE_VASPRINTF
122 vasprintf(&line, fmt, ap);
123 #else
124 line = Malloc(LINE_MAX);
125 vsnprintf(line, LINE_MAX, fmt, ap);
126 #endif
128 wc = str_to_wchar (line);
129 free (line);
130 total = n = 0;
131 for (wc_line = wcstok (wc, wc_delim, &wc_tmp); wc_line; wc_line = wcstok (NULL, wc_delim, &wc_tmp)) {
132 lines = Realloc (lines, (total+2)*sizeof(wchar_t *));
133 lines[total++] = wcsdup (wc_line);
134 lines[total] = NULL;
137 free (wc);
138 wordwrap_lines (&lines, &total, &width);
140 if (width > MSG_WIDTH)
141 width = MSG_WIDTH;
143 if (prompt) {
144 wc = str_to_wchar (prompt);
145 len = wcslen (wc);
146 width = len > width ? len : width;
147 free (wc);
150 if (extra) {
151 wc = str_to_wchar (extra);
152 len = wcslen (wc);
153 width = len > width ? len : width;
154 free (wc);
157 if (title) {
158 wc = str_to_wchar (title);
159 len = wcslen (wc);
160 width = len > width ? len : width;
161 free (wc);
164 height = total;
166 if (extra)
167 height++;
169 if (title)
170 height++;
172 height += 4; // 1 padding, 2 box, 1 prompt
173 width += 4; // 2 padding, 2 box
174 *h = height;
175 *w = width;
176 *str = lines;
179 static int display_message(WIN *win)
181 struct message_s *m = win->data;
182 int i;
183 void *p = NULL;
184 int n_lines = 0;
185 int r = 0;
187 keypad(win->w, TRUE);
188 window_draw_title(win->w, win->title, m->w, CP_MESSAGE_TITLE,
189 CP_MESSAGE_BORDER);
191 for (i = 0; m->lines[i]; i++) {
192 n_lines++;
194 if (m->offset && i < m->offset)
195 continue;
197 mvwprintw(win->w, (win->title) ? 2 + r: 1 + r,
198 (m->center || (!i && !m->lines[i+1])) ?
199 CENTERX(m->w, m->lines[i]) : 1, "%ls", m->lines[i]);
200 r++;
201 if (r >= LINES-5)
202 break;
205 if (m->extra)
206 window_draw_prompt(win->w, (m->prompt) ? m->h - 3 : m->h - 2, m->w,
207 m->extra, CP_MESSAGE_PROMPT);
209 if (m->prompt)
210 window_draw_prompt(win->w, m->h - 2, m->w, m->prompt, CP_MESSAGE_PROMPT);
212 if (m->func && win->c == m->c) {
213 (*m->func)(m->arg);
214 return 1;
217 if (win->c != 0) {
218 if (win->c == KEY_DOWN || win->c == 'k' || win->c == KEY_UP
219 || win->c == 'j') {
220 int n = 3;
222 n += m->extra ? 1 : 0;
224 if ((n_lines + n) - m->offset >= LINES-2)
225 m->offset = win->c == KEY_DOWN || win->c == 'k'
226 ? m->offset+1 : m->offset-1;
227 else if (win->c == KEY_UP || win->c == 'j')
228 m->offset--;
230 if (m->offset < 0)
231 m->offset = 0;
233 werase (win->w);
234 win->c = 0;
235 return display_message (win);
238 for (i = 0; m->lines[i]; i++)
239 free(m->lines[i]);
241 free(m->lines);
242 free(m->prompt);
243 free(m->extra);
244 p = m->arg;
245 free(m);
246 win->data = p;
247 return 0;
250 return 1;
254 * The force_trim parameter will trim whitespace reguardless if there is more
255 * than one line or not (help text vs. tag viewing).
257 WIN *construct_message(const char *title, const char *prompt, int center,
258 int force_trim, const char *extra_help,
259 message_func *func, void *arg, window_exit_func *efunc,
260 wint_t ckey, int freedata, const char *fmt, ...)
262 wchar_t **lines = NULL;
263 va_list ap;
264 struct message_s *m = NULL;
265 WIN *win = NULL;
266 int h, w;
268 va_start(ap, fmt);
269 build_message_lines(title, prompt, force_trim, extra_help, &h, &w, &lines,
270 fmt, ap);
271 va_end(ap);
273 m = Calloc(1, sizeof(struct message_s));
274 m->lines = lines;
275 m->w = w;
276 m->h = h > LINES-2 ? LINES-2 : h;
277 m->center = center;
278 m->c = ckey;
279 m->func = func;
280 m->arg = arg;
282 if (prompt)
283 m->prompt = strdup(prompt);
285 if (extra_help)
286 m->extra = strdup(extra_help);
288 win = window_create(title, m->h, m->w, CALCPOSY(m->h), CALCPOSX(m->w),
289 display_message, m, efunc);
291 win->freedata = freedata;
292 wbkgd(win->w, CP_MESSAGE_WINDOW);
293 (*win->func)(win);
294 return win;