1 /*
2 Internal file viewer for the Midnight Commander
3 Functions for searching in nroff-like view
4
5 Copyright (C) 1994-2021
6 Free Software Foundation, Inc.
7
8 Written by:
9 Miguel de Icaza, 1994, 1995, 1998
10 Janne Kukonlehto, 1994, 1995
11 Jakub Jelinek, 1995
12 Joseph M. Hinkle, 1996
13 Norbert Warmuth, 1997
14 Pavel Machek, 1998
15 Roland Illig <roland.illig@gmx.de>, 2004, 2005
16 Slava Zanko <slavazanko@google.com>, 2009
17 Andrew Borodin <aborodin@vmail.ru>, 2009
18 Ilia Maslakov <il.smind@gmail.com>, 2009
19
20 This file is part of the Midnight Commander.
21
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 3 of the License,
25 or (at your option) any later version.
26
27 The Midnight Commander is distributed in the hope that it will be useful,
28 but WITHOUT ANY WARRANTY; without even the implied warranty of
29 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30 GNU General Public License for more details.
31
32 You should have received a copy of the GNU General Public License
33 along with this program. If not, see <http://www.gnu.org/licenses/>.
34 */
35
36 #include <config.h>
37
38 #include "lib/global.h"
39 #include "lib/tty/tty.h"
40 #include "lib/skin.h"
41 #ifdef HAVE_CHARSET
42 #include "lib/charsets.h"
43 #endif
44
45 #include "src/setup.h" /* option_tab_spacing */
46
47 #include "internal.h"
48
49 /*** global variables ****************************************************************************/
50
51 /*** file scope macro definitions ****************************************************************/
52
53 /*** file scope type declarations ****************************************************************/
54
55 /*** file scope variables ************************************************************************/
56
57 /*** file scope functions ************************************************************************/
58 /* --------------------------------------------------------------------------------------------- */
59
60 static gboolean
mcview_nroff_get_char(mcview_nroff_t * nroff,int * ret_val,off_t nroff_index)61 mcview_nroff_get_char (mcview_nroff_t * nroff, int *ret_val, off_t nroff_index)
62 {
63 int c = 0;
64
65 #ifdef HAVE_CHARSET
66 if (nroff->view->utf8)
67 {
68 if (!mcview_get_utf (nroff->view, nroff_index, &c, &nroff->char_length))
69 {
70 /* we need got symbol in any case */
71 nroff->char_length = 1;
72 if (!mcview_get_byte (nroff->view, nroff_index, &c) || !g_ascii_isprint (c))
73 return FALSE;
74 }
75 }
76 else
77 #endif
78 {
79 nroff->char_length = 1;
80 if (!mcview_get_byte (nroff->view, nroff_index, &c))
81 return FALSE;
82 }
83
84 *ret_val = c;
85
86 return g_unichar_isprint (c);
87 }
88
89 /* --------------------------------------------------------------------------------------------- */
90 /*** public functions ****************************************************************************/
91 /* --------------------------------------------------------------------------------------------- */
92
93 int
mcview__get_nroff_real_len(WView * view,off_t start,off_t length)94 mcview__get_nroff_real_len (WView * view, off_t start, off_t length)
95 {
96 mcview_nroff_t *nroff;
97 int ret = 0;
98 off_t i = 0;
99
100 if (!view->mode_flags.nroff)
101 return 0;
102
103 nroff = mcview_nroff_seq_new_num (view, start);
104 if (nroff == NULL)
105 return 0;
106 while (i < length)
107 {
108 switch (nroff->type)
109 {
110 case NROFF_TYPE_BOLD:
111 ret += 1 + nroff->char_length; /* real char length and 0x8 */
112 break;
113 case NROFF_TYPE_UNDERLINE:
114 ret += 2; /* underline symbol and ox8 */
115 break;
116 default:
117 break;
118 }
119 i += nroff->char_length;
120 mcview_nroff_seq_next (nroff);
121 }
122
123 mcview_nroff_seq_free (&nroff);
124 return ret;
125 }
126
127 /* --------------------------------------------------------------------------------------------- */
128
129 mcview_nroff_t *
mcview_nroff_seq_new_num(WView * view,off_t lc_index)130 mcview_nroff_seq_new_num (WView * view, off_t lc_index)
131 {
132 mcview_nroff_t *nroff;
133
134 nroff = g_try_malloc0 (sizeof (mcview_nroff_t));
135 if (nroff != NULL)
136 {
137 nroff->index = lc_index;
138 nroff->view = view;
139 mcview_nroff_seq_info (nroff);
140 }
141 return nroff;
142 }
143
144 /* --------------------------------------------------------------------------------------------- */
145
146 mcview_nroff_t *
mcview_nroff_seq_new(WView * view)147 mcview_nroff_seq_new (WView * view)
148 {
149 return mcview_nroff_seq_new_num (view, (off_t) 0);
150
151 }
152
153 /* --------------------------------------------------------------------------------------------- */
154
155 void
mcview_nroff_seq_free(mcview_nroff_t ** nroff)156 mcview_nroff_seq_free (mcview_nroff_t ** nroff)
157 {
158 if (nroff == NULL || *nroff == NULL)
159 return;
160 MC_PTR_FREE (*nroff);
161 }
162
163 /* --------------------------------------------------------------------------------------------- */
164
165 nroff_type_t
mcview_nroff_seq_info(mcview_nroff_t * nroff)166 mcview_nroff_seq_info (mcview_nroff_t * nroff)
167 {
168 int next, next2;
169
170 if (nroff == NULL)
171 return NROFF_TYPE_NONE;
172 nroff->type = NROFF_TYPE_NONE;
173
174 if (!mcview_nroff_get_char (nroff, &nroff->current_char, nroff->index))
175 return nroff->type;
176
177 if (!mcview_get_byte (nroff->view, nroff->index + nroff->char_length, &next) || next != '\b')
178 return nroff->type;
179
180 if (!mcview_nroff_get_char (nroff, &next2, nroff->index + 1 + nroff->char_length))
181 return nroff->type;
182
183 if (nroff->current_char == '_' && next2 == '_')
184 {
185 nroff->type = (nroff->prev_type == NROFF_TYPE_BOLD)
186 ? NROFF_TYPE_BOLD : NROFF_TYPE_UNDERLINE;
187
188 }
189 else if (nroff->current_char == next2)
190 {
191 nroff->type = NROFF_TYPE_BOLD;
192 }
193 else if (nroff->current_char == '_')
194 {
195 nroff->current_char = next2;
196 nroff->type = NROFF_TYPE_UNDERLINE;
197 }
198 else if (nroff->current_char == '+' && next2 == 'o')
199 {
200 /* ??? */
201 }
202 return nroff->type;
203 }
204
205 /* --------------------------------------------------------------------------------------------- */
206
207 int
mcview_nroff_seq_next(mcview_nroff_t * nroff)208 mcview_nroff_seq_next (mcview_nroff_t * nroff)
209 {
210 if (nroff == NULL)
211 return -1;
212
213 nroff->prev_type = nroff->type;
214
215 switch (nroff->type)
216 {
217 case NROFF_TYPE_BOLD:
218 nroff->index += 1 + nroff->char_length;
219 break;
220 case NROFF_TYPE_UNDERLINE:
221 nroff->index += 2;
222 break;
223 default:
224 break;
225 }
226
227 nroff->index += nroff->char_length;
228
229 mcview_nroff_seq_info (nroff);
230 return nroff->current_char;
231 }
232
233 /* --------------------------------------------------------------------------------------------- */
234
235 int
mcview_nroff_seq_prev(mcview_nroff_t * nroff)236 mcview_nroff_seq_prev (mcview_nroff_t * nroff)
237 {
238 int prev;
239 off_t prev_index, prev_index2;
240
241 if (nroff == NULL)
242 return -1;
243
244 nroff->prev_type = NROFF_TYPE_NONE;
245
246 if (nroff->index == 0)
247 return -1;
248
249 prev_index = nroff->index - 1;
250
251 while (prev_index != 0)
252 {
253 if (mcview_nroff_get_char (nroff, &nroff->current_char, prev_index))
254 break;
255 prev_index--;
256 }
257 if (prev_index == 0)
258 {
259 nroff->index--;
260 mcview_nroff_seq_info (nroff);
261 return nroff->current_char;
262 }
263
264 prev_index--;
265
266 if (!mcview_get_byte (nroff->view, prev_index, &prev) || prev != '\b')
267 {
268 nroff->index = prev_index;
269 mcview_nroff_seq_info (nroff);
270 return nroff->current_char;
271 }
272 prev_index2 = prev_index - 1;
273
274 while (prev_index2 != 0)
275 {
276 if (mcview_nroff_get_char (nroff, &prev, prev_index))
277 break;
278 prev_index2--;
279 }
280
281 nroff->index = (prev_index2 == 0) ? prev_index : prev_index2;
282 mcview_nroff_seq_info (nroff);
283 return nroff->current_char;
284 }
285
286 /* --------------------------------------------------------------------------------------------- */
287