(get_paragraph): fix of pointer difference.
[midnight-commander.git] / src / viewer / nroff.c
blob14fe42af34f3aece7a5e5dc6b56ed523dc4c193f
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 Free Software Foundation, Inc.
8 Written by: 1994, 1995, 1998 Miguel de Icaza
9 1994, 1995 Janne Kukonlehto
10 1995 Jakub Jelinek
11 1996 Joseph M. Hinkle
12 1997 Norbert Warmuth
13 1998 Pavel Machek
14 2004 Roland Illig <roland.illig@gmx.de>
15 2005 Roland Illig <roland.illig@gmx.de>
16 2009 Slava Zanko <slavazanko@google.com>
17 2009 Andrew Borodin <aborodin@vmail.ru>
18 2009 Ilia Maslakov <il.smind@gmail.com>
20 This file is part of the Midnight Commander.
22 The Midnight Commander is free software; you can redistribute it
23 and/or modify it under the terms of the GNU General Public License as
24 published by the Free Software Foundation; either version 2 of the
25 License, or (at your option) any later version.
27 The Midnight Commander is distributed in the hope that it will be
28 useful, but WITHOUT ANY WARRANTY; without even the implied warranty
29 of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
30 General Public License for more details.
32 You should have received a copy of the GNU General Public License
33 along with this program; if not, write to the Free Software
34 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
35 MA 02110-1301, USA.
38 #include <config.h>
40 #include "lib/global.h"
41 #include "lib/tty/tty.h"
42 #include "lib/skin.h"
43 #include "lib/charsets.h"
45 #include "src/setup.h" /* option_tab_spacing */
47 #include "internal.h"
49 /*** global variables ****************************************************************************/
51 /*** file scope macro definitions ****************************************************************/
53 /*** file scope type declarations ****************************************************************/
55 /*** file scope variables ************************************************************************/
57 /*** file scope functions ************************************************************************/
58 /* --------------------------------------------------------------------------------------------- */
60 static gboolean
61 mcview_nroff_get_char (mcview_nroff_t * nroff, int *ret_val, off_t nroff_index)
63 int c;
64 #ifdef HAVE_CHARSET
65 if (nroff->view->utf8)
67 gboolean utf_result;
68 c = mcview_get_utf (nroff->view, nroff_index, &nroff->char_width, &utf_result);
69 if (!utf_result)
71 /* we need got symbol in any case */
72 nroff->char_width = 1;
73 if (!mcview_get_byte (nroff->view, nroff_index, &c) || !g_ascii_isprint (c))
74 return FALSE;
77 else
78 #endif
80 nroff->char_width = 1;
81 if (!mcview_get_byte (nroff->view, nroff_index, &c))
82 return FALSE;
85 *ret_val = c;
87 return g_unichar_isprint (c);
90 /* --------------------------------------------------------------------------------------------- */
91 /*** public functions ****************************************************************************/
92 /* --------------------------------------------------------------------------------------------- */
94 void
95 mcview_display_nroff (mcview_t * view)
97 const screen_dimen left = view->data_area.left;
98 const screen_dimen top = view->data_area.top;
99 const screen_dimen width = view->data_area.width;
100 const screen_dimen height = view->data_area.height;
101 screen_dimen row, col;
102 off_t from;
103 int cw = 1;
104 int c;
105 int c_prev = 0;
106 int c_next = 0;
107 struct hexedit_change_node *curr = view->change_list;
109 mcview_display_clean (view);
110 mcview_display_ruler (view);
112 /* Find the first displayable changed byte */
113 from = view->dpy_start;
114 while (curr && (curr->offset < from))
116 curr = curr->next;
119 tty_setcolor (NORMAL_COLOR);
120 for (row = 0, col = 0; row < height;)
122 #ifdef HAVE_CHARSET
123 if (view->utf8)
125 gboolean read_res = TRUE;
126 c = mcview_get_utf (view, from, &cw, &read_res);
127 if (!read_res)
128 break;
130 else
131 #endif
133 if (!mcview_get_byte (view, from, &c))
134 break;
136 from++;
137 if (cw > 1)
138 from += cw - 1;
140 if (c == '\b')
142 if (from > 1)
144 #ifdef HAVE_CHARSET
145 if (view->utf8)
147 gboolean read_res;
148 c_next = mcview_get_utf (view, from, &cw, &read_res);
150 else
151 #endif
152 mcview_get_byte (view, from, &c_next);
154 if (g_unichar_isprint (c_prev) && g_unichar_isprint (c_next)
155 && (c_prev == c_next || c_prev == '_' || (c_prev == '+' && c_next == 'o')))
157 if (col == 0)
159 if (row == 0)
161 /* We're inside an nroff character sequence at the
162 * beginning of the screen -- just skip the
163 * backspace and continue with the next character. */
164 continue;
166 row--;
167 col = width;
169 col--;
170 if (c_prev == '_'
171 && (c_next != '_' || mcview_count_backspaces (view, from + 1) == 1))
172 tty_setcolor (VIEW_UNDERLINED_COLOR);
173 else
174 tty_setcolor (VIEW_BOLD_COLOR);
175 continue;
179 if ((c == '\n') || (col >= width && view->text_wrap_mode))
181 col = 0;
182 row++;
183 if (c == '\n' || row >= height)
184 continue;
187 if (c == '\r')
189 mcview_get_byte_indexed (view, from, 1, &c);
190 if (c == '\r' || c == '\n')
191 continue;
192 col = 0;
193 row++;
194 continue;
197 if (c == '\t')
199 off_t line, column;
200 mcview_offset_to_coord (view, &line, &column, from);
201 col += (option_tab_spacing - col % option_tab_spacing);
202 if (view->text_wrap_mode && col >= width && width != 0)
204 row += col / width;
205 col %= width;
207 continue;
210 if (view->search_start <= from && from < view->search_end)
212 tty_setcolor (SELECTED_COLOR);
215 c_prev = c;
217 if ((off_t) col >= view->dpy_text_column
218 && (off_t) col - view->dpy_text_column < (off_t) width)
220 widget_move (view, top + row, left + ((off_t) col - view->dpy_text_column));
221 #ifdef HAVE_CHARSET
222 if (mc_global.utf8_display)
224 if (!view->utf8)
226 c = convert_from_8bit_to_utf_c ((unsigned char) c, view->converter);
228 if (!g_unichar_isprint (c))
229 c = '.';
231 else
233 if (view->utf8)
235 c = convert_from_utf_to_current_c (c, view->converter);
237 else
239 #endif
240 c = convert_to_display_c (c);
241 #ifdef HAVE_CHARSET
244 #endif
245 tty_print_anychar (c);
247 col++;
248 #ifdef HAVE_CHARSET
249 if (view->utf8)
251 if (g_unichar_iswide (c))
252 col++;
253 else if (g_unichar_iszerowidth (c))
254 col--;
256 #endif
257 tty_setcolor (NORMAL_COLOR);
259 view->dpy_end = from;
262 /* --------------------------------------------------------------------------------------------- */
265 mcview__get_nroff_real_len (mcview_t * view, off_t start, off_t length)
267 mcview_nroff_t *nroff;
268 int ret = 0;
269 off_t i = 0;
271 if (!view->text_nroff_mode)
272 return 0;
274 nroff = mcview_nroff_seq_new_num (view, start);
275 if (nroff == NULL)
276 return 0;
277 while (i < length)
279 switch (nroff->type)
281 case NROFF_TYPE_BOLD:
282 ret += 1 + nroff->char_width; /* real char width and 0x8 */
283 break;
284 case NROFF_TYPE_UNDERLINE:
285 ret += 2; /* underline symbol and ox8 */
286 break;
287 default:
288 break;
290 i += nroff->char_width;
291 mcview_nroff_seq_next (nroff);
294 mcview_nroff_seq_free (&nroff);
295 return ret;
298 /* --------------------------------------------------------------------------------------------- */
300 mcview_nroff_t *
301 mcview_nroff_seq_new_num (mcview_t * view, off_t lc_index)
303 mcview_nroff_t *nroff;
305 nroff = g_try_malloc0 (sizeof (mcview_nroff_t));
306 if (nroff != NULL)
308 nroff->index = lc_index;
309 nroff->view = view;
310 mcview_nroff_seq_info (nroff);
312 return nroff;
315 /* --------------------------------------------------------------------------------------------- */
317 mcview_nroff_t *
318 mcview_nroff_seq_new (mcview_t * view)
320 return mcview_nroff_seq_new_num (view, (off_t) 0);
324 /* --------------------------------------------------------------------------------------------- */
326 void
327 mcview_nroff_seq_free (mcview_nroff_t ** nroff)
329 if (nroff == NULL || *nroff == NULL)
330 return;
331 g_free (*nroff);
332 *nroff = NULL;
335 /* --------------------------------------------------------------------------------------------- */
337 nroff_type_t
338 mcview_nroff_seq_info (mcview_nroff_t * nroff)
340 int next, next2;
342 if (nroff == NULL)
343 return NROFF_TYPE_NONE;
344 nroff->type = NROFF_TYPE_NONE;
346 if (!mcview_nroff_get_char (nroff, &nroff->current_char, nroff->index))
347 return nroff->type;
349 if (!mcview_get_byte (nroff->view, nroff->index + nroff->char_width, &next) || next != '\b')
350 return nroff->type;
352 if (!mcview_nroff_get_char (nroff, &next2, nroff->index + 1 + nroff->char_width))
353 return nroff->type;
355 if (nroff->current_char == '_' && next2 == '_')
357 nroff->type = (nroff->prev_type == NROFF_TYPE_BOLD)
358 ? NROFF_TYPE_BOLD : NROFF_TYPE_UNDERLINE;
361 else if (nroff->current_char == next2)
363 nroff->type = NROFF_TYPE_BOLD;
365 else if (nroff->current_char == '_')
367 nroff->current_char = next2;
368 nroff->type = NROFF_TYPE_UNDERLINE;
370 else if (nroff->current_char == '+' && next2 == 'o')
372 /* ??? */
374 return nroff->type;
377 /* --------------------------------------------------------------------------------------------- */
380 mcview_nroff_seq_next (mcview_nroff_t * nroff)
382 if (nroff == NULL)
383 return -1;
385 nroff->prev_type = nroff->type;
387 switch (nroff->type)
389 case NROFF_TYPE_BOLD:
390 nroff->index += 1 + nroff->char_width;
391 break;
392 case NROFF_TYPE_UNDERLINE:
393 nroff->index += 2;
394 break;
395 default:
396 break;
399 nroff->index += nroff->char_width;
401 mcview_nroff_seq_info (nroff);
402 return nroff->current_char;
405 /* --------------------------------------------------------------------------------------------- */
408 mcview_nroff_seq_prev (mcview_nroff_t * nroff)
410 int prev;
411 off_t prev_index, prev_index2;
413 if (nroff == NULL)
414 return -1;
416 nroff->prev_type = NROFF_TYPE_NONE;
418 if (nroff->index == 0)
419 return -1;
421 prev_index = nroff->index - 1;
423 while (prev_index != 0)
425 if (mcview_nroff_get_char (nroff, &nroff->current_char, prev_index))
426 break;
427 prev_index--;
429 if (prev_index == 0)
431 nroff->index--;
432 mcview_nroff_seq_info (nroff);
433 return nroff->current_char;
436 prev_index--;
438 if (!mcview_get_byte (nroff->view, prev_index, &prev) || prev != '\b')
440 nroff->index = prev_index;
441 mcview_nroff_seq_info (nroff);
442 return nroff->current_char;
444 prev_index2 = prev_index - 1;
446 while (prev_index2 != 0)
448 if (mcview_nroff_get_char (nroff, &prev, prev_index))
449 break;
450 prev_index2--;
453 nroff->index = (prev_index2 == 0) ? prev_index : prev_index2;
454 mcview_nroff_seq_info (nroff);
455 return nroff->current_char;
458 /* --------------------------------------------------------------------------------------------- */