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