Update po/mc.pot and po/*.po files.
[midnight-commander.git] / src / viewer / nroff.c
bloba8a77afdb305587e4e59ea42879424657d229841
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 #ifdef HAVE_CHARSET
43 #include "lib/charsets.h"
44 #endif
46 #include "src/setup.h" /* option_tab_spacing */
48 #include "internal.h"
50 /*** global variables ****************************************************************************/
52 /*** file scope macro definitions ****************************************************************/
54 /*** file scope type declarations ****************************************************************/
56 /*** file scope variables ************************************************************************/
58 /*** file scope functions ************************************************************************/
59 /* --------------------------------------------------------------------------------------------- */
61 static gboolean
62 mcview_nroff_get_char (mcview_nroff_t * nroff, int *ret_val, off_t nroff_index)
64 int c;
65 #ifdef HAVE_CHARSET
66 if (nroff->view->utf8)
68 gboolean utf_result;
69 c = mcview_get_utf (nroff->view, nroff_index, &nroff->char_width, &utf_result);
70 if (!utf_result)
72 /* we need got symbol in any case */
73 nroff->char_width = 1;
74 if (!mcview_get_byte (nroff->view, nroff_index, &c) || !g_ascii_isprint (c))
75 return FALSE;
78 else
79 #endif
81 nroff->char_width = 1;
82 if (!mcview_get_byte (nroff->view, nroff_index, &c))
83 return FALSE;
86 *ret_val = c;
88 return g_unichar_isprint (c);
91 /* --------------------------------------------------------------------------------------------- */
92 /*** public functions ****************************************************************************/
93 /* --------------------------------------------------------------------------------------------- */
95 void
96 mcview_display_nroff (mcview_t * view)
98 const screen_dimen left = view->data_area.left;
99 const screen_dimen top = view->data_area.top;
100 const screen_dimen width = view->data_area.width;
101 const screen_dimen height = view->data_area.height;
102 screen_dimen row, col;
103 off_t from;
104 int cw = 1;
105 int c;
106 int c_prev = 0;
107 int c_next = 0;
108 struct hexedit_change_node *curr = view->change_list;
110 mcview_display_clean (view);
111 mcview_display_ruler (view);
113 /* Find the first displayable changed byte */
114 from = view->dpy_start;
115 while (curr && (curr->offset < from))
117 curr = curr->next;
120 tty_setcolor (NORMAL_COLOR);
121 for (row = 0, col = 0; row < height;)
123 #ifdef HAVE_CHARSET
124 if (view->utf8)
126 gboolean read_res = TRUE;
127 c = mcview_get_utf (view, from, &cw, &read_res);
128 if (!read_res)
129 break;
131 else
132 #endif
134 if (!mcview_get_byte (view, from, &c))
135 break;
137 from++;
138 if (cw > 1)
139 from += cw - 1;
141 if (c == '\b')
143 if (from > 1)
145 #ifdef HAVE_CHARSET
146 if (view->utf8)
148 gboolean read_res;
149 c_next = mcview_get_utf (view, from, &cw, &read_res);
151 else
152 #endif
153 mcview_get_byte (view, from, &c_next);
155 if (g_unichar_isprint (c_prev) && g_unichar_isprint (c_next)
156 && (c_prev == c_next || c_prev == '_' || (c_prev == '+' && c_next == 'o')))
158 if (col == 0)
160 if (row == 0)
162 /* We're inside an nroff character sequence at the
163 * beginning of the screen -- just skip the
164 * backspace and continue with the next character. */
165 continue;
167 row--;
168 col = width;
170 col--;
171 if (c_prev == '_'
172 && (c_next != '_' || mcview_count_backspaces (view, from + 1) == 1))
173 tty_setcolor (VIEW_UNDERLINED_COLOR);
174 else
175 tty_setcolor (VIEW_BOLD_COLOR);
176 continue;
180 if ((c == '\n') || (col >= width && view->text_wrap_mode))
182 col = 0;
183 row++;
184 if (c == '\n' || row >= height)
185 continue;
188 if (c == '\r')
190 mcview_get_byte_indexed (view, from, 1, &c);
191 if (c == '\r' || c == '\n')
192 continue;
193 col = 0;
194 row++;
195 continue;
198 if (c == '\t')
200 off_t line, column;
201 mcview_offset_to_coord (view, &line, &column, from);
202 col += (option_tab_spacing - col % option_tab_spacing);
203 if (view->text_wrap_mode && col >= width && width != 0)
205 row += col / width;
206 col %= width;
208 continue;
211 if (view->search_start <= from && from < view->search_end)
213 tty_setcolor (SELECTED_COLOR);
216 c_prev = c;
218 if ((off_t) col >= view->dpy_text_column
219 && (off_t) col - view->dpy_text_column < (off_t) width)
221 widget_move (view, top + row, left + ((off_t) col - view->dpy_text_column));
222 #ifdef HAVE_CHARSET
223 if (mc_global.utf8_display)
225 if (!view->utf8)
227 c = convert_from_8bit_to_utf_c ((unsigned char) c, view->converter);
229 if (!g_unichar_isprint (c))
230 c = '.';
232 else if (view->utf8)
233 c = convert_from_utf_to_current_c (c, view->converter);
234 else
235 c = convert_to_display_c (c);
236 #endif
237 tty_print_anychar (c);
239 col++;
240 #ifdef HAVE_CHARSET
241 if (view->utf8)
243 if (g_unichar_iswide (c))
244 col++;
245 else if (g_unichar_iszerowidth (c))
246 col--;
248 #endif
249 tty_setcolor (NORMAL_COLOR);
251 view->dpy_end = from;
254 /* --------------------------------------------------------------------------------------------- */
257 mcview__get_nroff_real_len (mcview_t * view, off_t start, off_t length)
259 mcview_nroff_t *nroff;
260 int ret = 0;
261 off_t i = 0;
263 if (!view->text_nroff_mode)
264 return 0;
266 nroff = mcview_nroff_seq_new_num (view, start);
267 if (nroff == NULL)
268 return 0;
269 while (i < length)
271 switch (nroff->type)
273 case NROFF_TYPE_BOLD:
274 ret += 1 + nroff->char_width; /* real char width and 0x8 */
275 break;
276 case NROFF_TYPE_UNDERLINE:
277 ret += 2; /* underline symbol and ox8 */
278 break;
279 default:
280 break;
282 i += nroff->char_width;
283 mcview_nroff_seq_next (nroff);
286 mcview_nroff_seq_free (&nroff);
287 return ret;
290 /* --------------------------------------------------------------------------------------------- */
292 mcview_nroff_t *
293 mcview_nroff_seq_new_num (mcview_t * view, off_t lc_index)
295 mcview_nroff_t *nroff;
297 nroff = g_try_malloc0 (sizeof (mcview_nroff_t));
298 if (nroff != NULL)
300 nroff->index = lc_index;
301 nroff->view = view;
302 mcview_nroff_seq_info (nroff);
304 return nroff;
307 /* --------------------------------------------------------------------------------------------- */
309 mcview_nroff_t *
310 mcview_nroff_seq_new (mcview_t * view)
312 return mcview_nroff_seq_new_num (view, (off_t) 0);
316 /* --------------------------------------------------------------------------------------------- */
318 void
319 mcview_nroff_seq_free (mcview_nroff_t ** nroff)
321 if (nroff == NULL || *nroff == NULL)
322 return;
323 g_free (*nroff);
324 *nroff = NULL;
327 /* --------------------------------------------------------------------------------------------- */
329 nroff_type_t
330 mcview_nroff_seq_info (mcview_nroff_t * nroff)
332 int next, next2;
334 if (nroff == NULL)
335 return NROFF_TYPE_NONE;
336 nroff->type = NROFF_TYPE_NONE;
338 if (!mcview_nroff_get_char (nroff, &nroff->current_char, nroff->index))
339 return nroff->type;
341 if (!mcview_get_byte (nroff->view, nroff->index + nroff->char_width, &next) || next != '\b')
342 return nroff->type;
344 if (!mcview_nroff_get_char (nroff, &next2, nroff->index + 1 + nroff->char_width))
345 return nroff->type;
347 if (nroff->current_char == '_' && next2 == '_')
349 nroff->type = (nroff->prev_type == NROFF_TYPE_BOLD)
350 ? NROFF_TYPE_BOLD : NROFF_TYPE_UNDERLINE;
353 else if (nroff->current_char == next2)
355 nroff->type = NROFF_TYPE_BOLD;
357 else if (nroff->current_char == '_')
359 nroff->current_char = next2;
360 nroff->type = NROFF_TYPE_UNDERLINE;
362 else if (nroff->current_char == '+' && next2 == 'o')
364 /* ??? */
366 return nroff->type;
369 /* --------------------------------------------------------------------------------------------- */
372 mcview_nroff_seq_next (mcview_nroff_t * nroff)
374 if (nroff == NULL)
375 return -1;
377 nroff->prev_type = nroff->type;
379 switch (nroff->type)
381 case NROFF_TYPE_BOLD:
382 nroff->index += 1 + nroff->char_width;
383 break;
384 case NROFF_TYPE_UNDERLINE:
385 nroff->index += 2;
386 break;
387 default:
388 break;
391 nroff->index += nroff->char_width;
393 mcview_nroff_seq_info (nroff);
394 return nroff->current_char;
397 /* --------------------------------------------------------------------------------------------- */
400 mcview_nroff_seq_prev (mcview_nroff_t * nroff)
402 int prev;
403 off_t prev_index, prev_index2;
405 if (nroff == NULL)
406 return -1;
408 nroff->prev_type = NROFF_TYPE_NONE;
410 if (nroff->index == 0)
411 return -1;
413 prev_index = nroff->index - 1;
415 while (prev_index != 0)
417 if (mcview_nroff_get_char (nroff, &nroff->current_char, prev_index))
418 break;
419 prev_index--;
421 if (prev_index == 0)
423 nroff->index--;
424 mcview_nroff_seq_info (nroff);
425 return nroff->current_char;
428 prev_index--;
430 if (!mcview_get_byte (nroff->view, prev_index, &prev) || prev != '\b')
432 nroff->index = prev_index;
433 mcview_nroff_seq_info (nroff);
434 return nroff->current_char;
436 prev_index2 = prev_index - 1;
438 while (prev_index2 != 0)
440 if (mcview_nroff_get_char (nroff, &prev, prev_index))
441 break;
442 prev_index2--;
445 nroff->index = (prev_index2 == 0) ? prev_index : prev_index2;
446 mcview_nroff_seq_info (nroff);
447 return nroff->current_char;
450 /* --------------------------------------------------------------------------------------------- */