Add edit_add_window() function.
[midnight-commander.git] / src / viewer / nroff.c
blob4968535dac5158a8670ce65b8b1a1530f6bfd71f
1 /*
2 Internal file viewer for the Midnight Commander
3 Function for nroff-like view
5 Copyright (C) 1994, 1995, 1996, 1998, 1999, 2000, 2001, 2002, 2003,
6 2004, 2005, 2006, 2007, 2009, 2011
7 The Free Software Foundation, Inc.
9 Written by:
10 Miguel de Icaza, 1994, 1995, 1998
11 Janne Kukonlehto, 1994, 1995
12 Jakub Jelinek, 1995
13 Joseph M. Hinkle, 1996
14 Norbert Warmuth, 1997
15 Pavel Machek, 1998
16 Roland Illig <roland.illig@gmx.de>, 2004, 2005
17 Slava Zanko <slavazanko@google.com>, 2009
18 Andrew Borodin <aborodin@vmail.ru>, 2009
19 Ilia Maslakov <il.smind@gmail.com>, 2009
21 This file is part of the Midnight Commander.
23 The Midnight Commander is free software: you can redistribute it
24 and/or modify it under the terms of the GNU General Public License as
25 published by the Free Software Foundation, either version 3 of the License,
26 or (at your option) any later version.
28 The Midnight Commander is distributed in the hope that it will be useful,
29 but WITHOUT ANY WARRANTY; without even the implied warranty of
30 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
31 GNU General Public License for more details.
33 You should have received a copy of the GNU General Public License
34 along with this program. If not, see <http://www.gnu.org/licenses/>.
37 #include <config.h>
39 #include "lib/global.h"
40 #include "lib/tty/tty.h"
41 #include "lib/skin.h"
42 #include "lib/charsets.h"
44 #include "src/setup.h" /* option_tab_spacing */
46 #include "internal.h"
48 /*** global variables ****************************************************************************/
50 /*** file scope macro definitions ****************************************************************/
52 /*** file scope type declarations ****************************************************************/
54 /*** file scope variables ************************************************************************/
56 /*** file scope functions ************************************************************************/
57 /* --------------------------------------------------------------------------------------------- */
59 static gboolean
60 mcview_nroff_get_char (mcview_nroff_t * nroff, int *ret_val, off_t nroff_index)
62 int c;
63 #ifdef HAVE_CHARSET
64 if (nroff->view->utf8)
66 gboolean utf_result;
67 c = mcview_get_utf (nroff->view, nroff_index, &nroff->char_width, &utf_result);
68 if (!utf_result)
70 /* we need got symbol in any case */
71 nroff->char_width = 1;
72 if (!mcview_get_byte (nroff->view, nroff_index, &c) || !g_ascii_isprint (c))
73 return FALSE;
76 else
77 #endif
79 nroff->char_width = 1;
80 if (!mcview_get_byte (nroff->view, nroff_index, &c))
81 return FALSE;
84 *ret_val = c;
86 return g_unichar_isprint (c);
89 /* --------------------------------------------------------------------------------------------- */
90 /*** public functions ****************************************************************************/
91 /* --------------------------------------------------------------------------------------------- */
93 void
94 mcview_display_nroff (mcview_t * view)
96 const screen_dimen left = view->data_area.left;
97 const screen_dimen top = view->data_area.top;
98 const screen_dimen width = view->data_area.width;
99 const screen_dimen height = view->data_area.height;
100 screen_dimen row, col;
101 off_t from;
102 int cw = 1;
103 int c;
104 int c_prev = 0;
105 int c_next = 0;
106 struct hexedit_change_node *curr = view->change_list;
108 mcview_display_clean (view);
109 mcview_display_ruler (view);
111 /* Find the first displayable changed byte */
112 from = view->dpy_start;
113 while (curr && (curr->offset < from))
115 curr = curr->next;
118 tty_setcolor (NORMAL_COLOR);
119 for (row = 0, col = 0; row < height;)
121 #ifdef HAVE_CHARSET
122 if (view->utf8)
124 gboolean read_res = TRUE;
125 c = mcview_get_utf (view, from, &cw, &read_res);
126 if (!read_res)
127 break;
129 else
130 #endif
132 if (!mcview_get_byte (view, from, &c))
133 break;
135 from++;
136 if (cw > 1)
137 from += cw - 1;
139 if (c == '\b')
141 if (from > 1)
143 #ifdef HAVE_CHARSET
144 if (view->utf8)
146 gboolean read_res;
147 c_next = mcview_get_utf (view, from, &cw, &read_res);
149 else
150 #endif
151 mcview_get_byte (view, from, &c_next);
153 if (g_unichar_isprint (c_prev) && g_unichar_isprint (c_next)
154 && (c_prev == c_next || c_prev == '_' || (c_prev == '+' && c_next == 'o')))
156 if (col == 0)
158 if (row == 0)
160 /* We're inside an nroff character sequence at the
161 * beginning of the screen -- just skip the
162 * backspace and continue with the next character. */
163 continue;
165 row--;
166 col = width;
168 col--;
169 if (c_prev == '_'
170 && (c_next != '_' || mcview_count_backspaces (view, from + 1) == 1))
171 tty_setcolor (VIEW_UNDERLINED_COLOR);
172 else
173 tty_setcolor (VIEW_BOLD_COLOR);
174 continue;
178 if ((c == '\n') || (col >= width && view->text_wrap_mode))
180 col = 0;
181 row++;
182 if (c == '\n' || row >= height)
183 continue;
186 if (c == '\r')
188 mcview_get_byte_indexed (view, from, 1, &c);
189 if (c == '\r' || c == '\n')
190 continue;
191 col = 0;
192 row++;
193 continue;
196 if (c == '\t')
198 off_t line, column;
199 mcview_offset_to_coord (view, &line, &column, from);
200 col += (option_tab_spacing - col % option_tab_spacing);
201 if (view->text_wrap_mode && col >= width && width != 0)
203 row += col / width;
204 col %= width;
206 continue;
209 if (view->search_start <= from && from < view->search_end)
211 tty_setcolor (SELECTED_COLOR);
214 c_prev = c;
216 if ((off_t) col >= view->dpy_text_column
217 && (off_t) col - view->dpy_text_column < (off_t) width)
219 widget_move (view, top + row, left + ((off_t) col - view->dpy_text_column));
220 #ifdef HAVE_CHARSET
221 if (mc_global.utf8_display)
223 if (!view->utf8)
225 c = convert_from_8bit_to_utf_c ((unsigned char) c, view->converter);
227 if (!g_unichar_isprint (c))
228 c = '.';
230 else
232 if (view->utf8)
234 c = convert_from_utf_to_current_c (c, view->converter);
236 else
238 #endif
239 c = convert_to_display_c (c);
240 #ifdef HAVE_CHARSET
243 #endif
244 tty_print_anychar (c);
246 col++;
247 #ifdef HAVE_CHARSET
248 if (view->utf8)
250 if (g_unichar_iswide (c))
251 col++;
252 else if (g_unichar_iszerowidth (c))
253 col--;
255 #endif
256 tty_setcolor (NORMAL_COLOR);
258 view->dpy_end = from;
261 /* --------------------------------------------------------------------------------------------- */
264 mcview__get_nroff_real_len (mcview_t * view, off_t start, off_t length)
266 mcview_nroff_t *nroff;
267 int ret = 0;
268 off_t i = 0;
270 if (!view->text_nroff_mode)
271 return 0;
273 nroff = mcview_nroff_seq_new_num (view, start);
274 if (nroff == NULL)
275 return 0;
276 while (i < length)
278 switch (nroff->type)
280 case NROFF_TYPE_BOLD:
281 ret += 1 + nroff->char_width; /* real char width and 0x8 */
282 break;
283 case NROFF_TYPE_UNDERLINE:
284 ret += 2; /* underline symbol and ox8 */
285 break;
286 default:
287 break;
289 i += nroff->char_width;
290 mcview_nroff_seq_next (nroff);
293 mcview_nroff_seq_free (&nroff);
294 return ret;
297 /* --------------------------------------------------------------------------------------------- */
299 mcview_nroff_t *
300 mcview_nroff_seq_new_num (mcview_t * view, off_t lc_index)
302 mcview_nroff_t *nroff;
304 nroff = g_try_malloc0 (sizeof (mcview_nroff_t));
305 if (nroff != NULL)
307 nroff->index = lc_index;
308 nroff->view = view;
309 mcview_nroff_seq_info (nroff);
311 return nroff;
314 /* --------------------------------------------------------------------------------------------- */
316 mcview_nroff_t *
317 mcview_nroff_seq_new (mcview_t * view)
319 return mcview_nroff_seq_new_num (view, (off_t) 0);
323 /* --------------------------------------------------------------------------------------------- */
325 void
326 mcview_nroff_seq_free (mcview_nroff_t ** nroff)
328 if (nroff == NULL || *nroff == NULL)
329 return;
330 g_free (*nroff);
331 *nroff = NULL;
334 /* --------------------------------------------------------------------------------------------- */
336 nroff_type_t
337 mcview_nroff_seq_info (mcview_nroff_t * nroff)
339 int next, next2;
341 if (nroff == NULL)
342 return NROFF_TYPE_NONE;
343 nroff->type = NROFF_TYPE_NONE;
345 if (!mcview_nroff_get_char (nroff, &nroff->current_char, nroff->index))
346 return nroff->type;
348 if (!mcview_get_byte (nroff->view, nroff->index + nroff->char_width, &next) || next != '\b')
349 return nroff->type;
351 if (!mcview_nroff_get_char (nroff, &next2, nroff->index + 1 + nroff->char_width))
352 return nroff->type;
354 if (nroff->current_char == '_' && next2 == '_')
356 nroff->type = (nroff->prev_type == NROFF_TYPE_BOLD)
357 ? NROFF_TYPE_BOLD : NROFF_TYPE_UNDERLINE;
360 else if (nroff->current_char == next2)
362 nroff->type = NROFF_TYPE_BOLD;
364 else if (nroff->current_char == '_')
366 nroff->current_char = next2;
367 nroff->type = NROFF_TYPE_UNDERLINE;
369 else if (nroff->current_char == '+' && next2 == 'o')
371 /* ??? */
373 return nroff->type;
376 /* --------------------------------------------------------------------------------------------- */
379 mcview_nroff_seq_next (mcview_nroff_t * nroff)
381 if (nroff == NULL)
382 return -1;
384 nroff->prev_type = nroff->type;
386 switch (nroff->type)
388 case NROFF_TYPE_BOLD:
389 nroff->index += 1 + nroff->char_width;
390 break;
391 case NROFF_TYPE_UNDERLINE:
392 nroff->index += 2;
393 break;
394 default:
395 break;
398 nroff->index += nroff->char_width;
400 mcview_nroff_seq_info (nroff);
401 return nroff->current_char;
404 /* --------------------------------------------------------------------------------------------- */
407 mcview_nroff_seq_prev (mcview_nroff_t * nroff)
409 int prev;
410 off_t prev_index, prev_index2;
412 if (nroff == NULL)
413 return -1;
415 nroff->prev_type = NROFF_TYPE_NONE;
417 if (nroff->index == 0)
418 return -1;
420 prev_index = nroff->index - 1;
422 while (prev_index != 0)
424 if (mcview_nroff_get_char (nroff, &nroff->current_char, prev_index))
425 break;
426 prev_index--;
428 if (prev_index == 0)
430 nroff->index--;
431 mcview_nroff_seq_info (nroff);
432 return nroff->current_char;
435 prev_index--;
437 if (!mcview_get_byte (nroff->view, prev_index, &prev) || prev != '\b')
439 nroff->index = prev_index;
440 mcview_nroff_seq_info (nroff);
441 return nroff->current_char;
443 prev_index2 = prev_index - 1;
445 while (prev_index2 != 0)
447 if (mcview_nroff_get_char (nroff, &prev, prev_index))
448 break;
449 prev_index2--;
452 nroff->index = (prev_index2 == 0) ? prev_index : prev_index2;
453 mcview_nroff_seq_info (nroff);
454 return nroff->current_char;
457 /* --------------------------------------------------------------------------------------------- */