Fixed search for first symbol in string.
[midnight-commander.git] / src / viewer / nroff.c
blobf32279173b74a7689219736ebff5db414c2fb0da
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 if (!g_unichar_isprint (c))
86 return FALSE;
87 *ret_val = c;
88 return TRUE;
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
234 if (view->utf8)
236 c = convert_from_utf_to_current_c (c, view->converter);
238 else
240 #endif
241 c = convert_to_display_c (c);
242 #ifdef HAVE_CHARSET
245 #endif
246 tty_print_anychar (c);
248 col++;
249 #ifdef HAVE_CHARSET
250 if (view->utf8)
252 if (g_unichar_iswide (c))
253 col++;
254 else if (g_unichar_iszerowidth (c))
255 col--;
257 #endif
258 tty_setcolor (NORMAL_COLOR);
260 view->dpy_end = from;
263 /* --------------------------------------------------------------------------------------------- */
266 mcview__get_nroff_real_len (mcview_t * view, off_t start, off_t length)
268 mcview_nroff_t *nroff;
269 int ret = 0;
270 off_t i = 0;
272 if (!view->text_nroff_mode)
273 return 0;
275 nroff = mcview_nroff_seq_new_num (view, start);
276 if (nroff == NULL)
277 return 0;
279 while (i < length)
281 if (nroff->type != NROFF_TYPE_NONE)
283 ret += 1 + nroff->char_width;
285 i++;
286 mcview_nroff_seq_next (nroff);
289 mcview_nroff_seq_free (&nroff);
290 return ret;
293 /* --------------------------------------------------------------------------------------------- */
295 mcview_nroff_t *
296 mcview_nroff_seq_new_num (mcview_t * view, off_t lc_index)
298 mcview_nroff_t *nroff;
300 nroff = g_try_malloc0 (sizeof (mcview_nroff_t));
301 if (nroff != NULL)
303 nroff->index = lc_index;
304 nroff->view = view;
305 mcview_nroff_seq_info (nroff);
307 return nroff;
310 /* --------------------------------------------------------------------------------------------- */
312 mcview_nroff_t *
313 mcview_nroff_seq_new (mcview_t * view)
315 return mcview_nroff_seq_new_num (view, (off_t) 0);
319 /* --------------------------------------------------------------------------------------------- */
321 void
322 mcview_nroff_seq_free (mcview_nroff_t ** nroff)
324 if (nroff == NULL || *nroff == NULL)
325 return;
326 g_free (*nroff);
327 *nroff = NULL;
330 /* --------------------------------------------------------------------------------------------- */
332 nroff_type_t
333 mcview_nroff_seq_info (mcview_nroff_t * nroff)
335 int next, next2;
337 if (nroff == NULL)
338 return NROFF_TYPE_NONE;
339 nroff->type = NROFF_TYPE_NONE;
341 if (!mcview_nroff_get_char (nroff, &nroff->current_char, nroff->index))
342 return nroff->type;
344 if (!mcview_get_byte (nroff->view, nroff->index + nroff->char_width, &next) || next != '\b')
345 return nroff->type;
347 if (!mcview_nroff_get_char (nroff, &next2, nroff->index + 1 + nroff->char_width))
348 return nroff->type;
350 if (nroff->current_char == '_' && next2 == '_')
352 nroff->type = (nroff->prev_type == NROFF_TYPE_BOLD)
353 ? NROFF_TYPE_BOLD : NROFF_TYPE_UNDERLINE;
356 else if (nroff->current_char == next2)
358 nroff->type = NROFF_TYPE_BOLD;
360 else if (nroff->current_char == '_')
362 nroff->current_char = next2;
363 nroff->type = NROFF_TYPE_UNDERLINE;
365 else if (nroff->current_char == '+' && next2 == 'o')
367 /* ??? */
369 return nroff->type;
372 /* --------------------------------------------------------------------------------------------- */
375 mcview_nroff_seq_next (mcview_nroff_t * nroff)
377 if (nroff == NULL)
378 return -1;
380 nroff->prev_type = nroff->type;
382 nroff->index += nroff->char_width;
384 if (nroff->prev_type != NROFF_TYPE_NONE)
385 nroff->index += 2;
386 mcview_nroff_seq_info (nroff);
387 return nroff->current_char;
390 /* --------------------------------------------------------------------------------------------- */