1 #ifndef MC__VIEWER_INTERNAL_H
2 #define MC__VIEWER_INTERNAL_H
3 
4 #include <limits.h>             /* CHAR_BIT */
5 #include <stdlib.h>
6 #include <stdio.h>
7 #include <sys/types.h>
8 
9 #include "lib/global.h"
10 
11 #include "lib/search.h"
12 #include "lib/widget.h"
13 #include "lib/vfs/vfs.h"        /* vfs_path_t */
14 
15 #include "src/keymap.h"         /* global_keymap_t */
16 #include "src/filemanager/dir.h"        /* dir_list */
17 
18 #include "mcviewer.h"
19 
20 /*** typedefs(not structures) and defined constants **********************************************/
21 
22 #define OFF_T_BITWIDTH ((unsigned int) (sizeof (off_t) * CHAR_BIT - 1))
23 #define OFFSETTYPE_MAX (((off_t) 1 << (OFF_T_BITWIDTH - 1)) - 1)
24 
25 typedef unsigned char byte;
26 
27 /* A width or height on the screen */
28 typedef unsigned int screen_dimen;
29 
30 /*** enums ***************************************************************************************/
31 
32 /* data sources of the view */
33 enum view_ds
34 {
35     DS_NONE,                    /* No data available */
36     DS_STDIO_PIPE,              /* Data comes from a pipe using popen/pclose */
37     DS_VFS_PIPE,                /* Data comes from a piped-in VFS file */
38     DS_FILE,                    /* Data comes from a VFS file */
39     DS_STRING                   /* Data comes from a string in memory */
40 };
41 
42 enum ccache_type
43 {
44     CCACHE_OFFSET,
45     CCACHE_LINECOL
46 };
47 
48 typedef enum
49 {
50     NROFF_TYPE_NONE = 0,
51     NROFF_TYPE_BOLD = 1,
52     NROFF_TYPE_UNDERLINE = 2
53 } nroff_type_t;
54 
55 /*** structures declarations (and typedefs of structures)*****************************************/
56 
57 /* A node for building a change list on change_list */
58 struct hexedit_change_node
59 {
60     struct hexedit_change_node *next;
61     off_t offset;
62     byte value;
63 };
64 
65 struct area
66 {
67     screen_dimen top, left;
68     screen_dimen height, width;
69 };
70 
71 /* A cache entry for mapping offsets into line/column pairs and vice versa.
72  * cc_offset, cc_line, and cc_column are the 0-based values of the offset,
73  * line and column of that cache entry. cc_nroff_column is the column
74  * corresponding to cc_offset in nroff mode.
75  */
76 typedef struct
77 {
78     off_t cc_offset;
79     off_t cc_line;
80     off_t cc_column;
81     off_t cc_nroff_column;
82 } coord_cache_entry_t;
83 
84 typedef struct
85 {
86     size_t size;
87     size_t capacity;
88     coord_cache_entry_t **cache;
89 } coord_cache_t;
90 
91 /* TODO: find a better name. This is not actually a "state machine",
92  * but a "state machine's state", but that sounds silly.
93  * Could be parser_state, formatter_state... */
94 typedef struct
95 {
96     off_t offset;               /* The file offset at which this is the state. */
97     off_t unwrapped_column;     /* Columns if the paragraph wasn't wrapped, */
98     /* used for positioning TABs in wrapped lines */
99     gboolean nroff_underscore_is_underlined;    /* whether _\b_ is underlined rather than bold */
100     gboolean print_lonely_combining;    /* whether lonely combining marks are printed on a dotted circle */
101 } mcview_state_machine_t;
102 
103 struct mcview_nroff_struct;
104 
105 struct WView
106 {
107     Widget widget;
108 
109     vfs_path_t *filename_vpath; /* Name of the file */
110     vfs_path_t *workdir_vpath;  /* Name of the working directory */
111     char *command;              /* Command used to pipe data in */
112 
113     enum view_ds datasource;    /* Where the displayed data comes from */
114 
115     /* stdio pipe data source */
116     mc_pipe_t *ds_stdio_pipe;   /* Output of a shell command */
117     gboolean pipe_first_err_msg;        /* Show only 1st message from stderr */
118 
119     /* vfs pipe data source */
120     int ds_vfs_pipe;            /* Non-seekable vfs file descriptor */
121 
122     /* vfs file data source */
123     int ds_file_fd;             /* File with random access */
124     off_t ds_file_filesize;     /* Size of the file */
125     off_t ds_file_offset;       /* Offset of the currently loaded data */
126     byte *ds_file_data;         /* Currently loaded data */
127     size_t ds_file_datalen;     /* Number of valid bytes in file_data */
128     size_t ds_file_datasize;    /* Number of allocated bytes in file_data */
129 
130     /* string data source */
131     byte *ds_string_data;       /* The characters of the string */
132     size_t ds_string_len;       /* The length of the string */
133 
134     /* Growing buffers information */
135     gboolean growbuf_in_use;    /* Use the growing buffers? */
136     GPtrArray *growbuf_blockptr;        /* Pointer to the block pointers */
137     size_t growbuf_lastindex;   /* Number of bytes in the last page of the
138                                    growing buffer */
139     gboolean growbuf_finished;  /* TRUE when all data has been read. */
140 
141     mcview_mode_flags_t mode_flags;
142 
143     /* Hex editor modes */
144     gboolean hexedit_mode;      /* Hexview or Hexedit */
145     const global_keymap_t *hex_keymap;
146     gboolean hexview_in_text;   /* Is the hexview cursor in the text area? */
147     int bytes_per_line;         /* Number of bytes per line in hex mode */
148     off_t hex_cursor;           /* Hexview cursor position in file */
149     gboolean hexedit_lownibble; /* Are we editing the last significant nibble? */
150     gboolean locked;            /* We hold lock on current file */
151 
152 #ifdef HAVE_CHARSET
153     gboolean utf8;              /* It's multibyte file codeset */
154 #endif
155 
156     coord_cache_t *coord_cache; /* Cache for mapping offsets to cursor positions */
157 
158     /* Display information */
159     screen_dimen dpy_frame_size;        /* Size of the frame surrounding the real viewer */
160     off_t dpy_start;            /* Offset of the displayed data (start of the paragraph in non-hex mode) */
161     off_t dpy_end;              /* Offset after the displayed data */
162     off_t dpy_paragraph_skip_lines;     /* Extra lines to skip in wrap mode */
163     mcview_state_machine_t dpy_state_top;       /* Parser-formatter state at the topmost visible line in wrap mode */
164     mcview_state_machine_t dpy_state_bottom;    /* Parser-formatter state after the bottomvisible line in wrap mode */
165     gboolean dpy_wrap_dirty;    /* dpy_state_top needs to be recomputed */
166     off_t dpy_text_column;      /* Number of skipped columns in non-wrap
167                                  * text mode */
168     screen_dimen cursor_col;    /* Cursor column */
169     screen_dimen cursor_row;    /* Cursor row */
170     struct hexedit_change_node *change_list;    /* Linked list of changes */
171     struct area status_area;    /* Where the status line is displayed */
172     struct area ruler_area;     /* Where the ruler is displayed */
173     struct area data_area;      /* Where the data is displayed */
174 
175     ssize_t force_max;          /* Force a max offset, or -1 */
176 
177     int dirty;                  /* Number of skipped updates */
178     gboolean dpy_bbar_dirty;    /* Does the button bar need to be updated? */
179 
180 
181     /* handle of search engine */
182     mc_search_t *search;
183     gchar *last_search_string;
184     struct mcview_nroff_struct *search_nroff_seq;
185     off_t search_start;         /* First character to start searching from */
186     off_t search_end;           /* Length of found string or 0 if none was found */
187     int search_numNeedSkipChar;
188 
189     /* Markers */
190     int marker;                 /* mark to use */
191     off_t marks[10];            /* 10 marks: 0..9 */
192 
193     off_t update_steps;         /* The number of bytes between percent increments */
194     off_t update_activate;      /* Last point where we updated the status */
195 
196     /* converter for translation of text */
197     GIConv converter;
198 
199     GArray *saved_bookmarks;
200 
201     dir_list *dir;              /* List of current directory files
202                                  * to handle CK_FileNext and CK_FilePrev commands */
203     int *dir_idx;               /* Index of current file in dir structure.
204                                  * Pointer is used here as reference to WPanel::dir::count */
205     vfs_path_t *ext_script;     /* Temporary script file created by regex_command_for() */
206 };
207 
208 typedef struct mcview_nroff_struct
209 {
210     WView *view;
211     off_t index;
212     int char_length;
213     int current_char;
214     nroff_type_t type;
215     nroff_type_t prev_type;
216 } mcview_nroff_t;
217 
218 typedef struct mcview_search_options_t
219 {
220     mc_search_type_t type;
221     gboolean case_sens;
222     gboolean backwards;
223     gboolean whole_words;
224     gboolean all_codepages;
225 } mcview_search_options_t;
226 
227 /*** global variables defined in .c file *********************************************************/
228 
229 extern mcview_search_options_t mcview_search_options;
230 
231 /*** declarations of public functions ************************************************************/
232 
233 /* actions_cmd.c:  */
234 cb_ret_t mcview_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, void *data);
235 cb_ret_t mcview_dialog_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm,
236                                  void *data);
237 
238 /* ascii.c: */
239 void mcview_display_text (WView * view);
240 void mcview_state_machine_init (mcview_state_machine_t *, off_t);
241 void mcview_ascii_move_down (WView * view, off_t lines);
242 void mcview_ascii_move_up (WView * view, off_t lines);
243 void mcview_ascii_moveto_bol (WView * view);
244 void mcview_ascii_moveto_eol (WView * view);
245 
246 /* coord_cache.c: */
247 coord_cache_t *coord_cache_new (void);
248 void coord_cache_free (coord_cache_t * cache);
249 
250 #ifdef MC_ENABLE_DEBUGGING_CODE
251 void mcview_ccache_dump (WView * view);
252 #endif
253 
254 void mcview_ccache_lookup (WView * view, coord_cache_entry_t * coord, enum ccache_type lookup_what);
255 
256 /* datasource.c: */
257 void mcview_set_datasource_none (WView * view);
258 off_t mcview_get_filesize (WView * view);
259 void mcview_update_filesize (WView * view);
260 char *mcview_get_ptr_file (WView * view, off_t byte_index);
261 char *mcview_get_ptr_string (WView * view, off_t byte_index);
262 gboolean mcview_get_utf (WView * view, off_t byte_index, int *ch, int *ch_len);
263 gboolean mcview_get_byte_string (WView * view, off_t byte_index, int *retval);
264 gboolean mcview_get_byte_none (WView * view, off_t byte_index, int *retval);
265 void mcview_set_byte (WView * view, off_t offset, byte b);
266 void mcview_file_load_data (WView * view, off_t byte_index);
267 void mcview_close_datasource (WView * view);
268 void mcview_set_datasource_file (WView * view, int fd, const struct stat *st);
269 gboolean mcview_load_command_output (WView * view, const char *command);
270 void mcview_set_datasource_vfs_pipe (WView * view, int fd);
271 void mcview_set_datasource_string (WView * view, const char *s);
272 
273 /* dialog.c: */
274 gboolean mcview_dialog_search (WView * view);
275 gboolean mcview_dialog_goto (WView * view, off_t * offset);
276 
277 /* display.c: */
278 void mcview_update (WView * view);
279 void mcview_display (WView * view);
280 void mcview_compute_areas (WView * view);
281 void mcview_update_bytes_per_line (WView * view);
282 void mcview_display_toggle_ruler (WView * view);
283 void mcview_display_clean (WView * view);
284 void mcview_display_ruler (WView * view);
285 
286 /* growbuf.c: */
287 void mcview_growbuf_init (WView * view);
288 void mcview_growbuf_done (WView * view);
289 void mcview_growbuf_free (WView * view);
290 off_t mcview_growbuf_filesize (WView * view);
291 void mcview_growbuf_read_until (WView * view, off_t ofs);
292 gboolean mcview_get_byte_growing_buffer (WView * view, off_t byte_index, int *retval);
293 char *mcview_get_ptr_growing_buffer (WView * view, off_t byte_index);
294 
295 /* hex.c: */
296 void mcview_display_hex (WView * view);
297 gboolean mcview_hexedit_save_changes (WView * view);
298 void mcview_toggle_hexedit_mode (WView * view);
299 void mcview_hexedit_free_change_list (WView * view);
300 void mcview_enqueue_change (struct hexedit_change_node **head, struct hexedit_change_node *node);
301 
302 /* lib.c: */
303 void mcview_toggle_magic_mode (WView * view);
304 void mcview_toggle_wrap_mode (WView * view);
305 void mcview_toggle_nroff_mode (WView * view);
306 void mcview_toggle_hex_mode (WView * view);
307 void mcview_init (WView * view);
308 void mcview_done (WView * view);
309 #ifdef HAVE_CHARSET
310 void mcview_select_encoding (WView * view);
311 void mcview_set_codeset (WView * view);
312 #endif
313 void mcview_show_error (WView * view, const char *error);
314 off_t mcview_bol (WView * view, off_t current, off_t limit);
315 off_t mcview_eol (WView * view, off_t current);
316 char *mcview_get_title (const WDialog * h, size_t len);
317 int mcview_calc_percent (WView * view, off_t p);
318 
319 /* move.c */
320 void mcview_move_up (WView * view, off_t lines);
321 void mcview_move_down (WView * view, off_t lines);
322 void mcview_move_left (WView * view, off_t columns);
323 void mcview_move_right (WView * view, off_t columns);
324 void mcview_moveto_top (WView * view);
325 void mcview_moveto_bottom (WView * view);
326 void mcview_moveto_bol (WView * view);
327 void mcview_moveto_eol (WView * view);
328 void mcview_moveto_offset (WView * view, off_t offset);
329 void mcview_moveto (WView * view, off_t, off_t col);
330 void mcview_coord_to_offset (WView * view, off_t * ret_offset, off_t line, off_t column);
331 void mcview_offset_to_coord (WView * view, off_t * ret_line, off_t * ret_column, off_t offset);
332 void mcview_place_cursor (WView * view);
333 void mcview_moveto_match (WView * view);
334 
335 /* nroff.c: */
336 int mcview__get_nroff_real_len (WView * view, off_t start, off_t length);
337 mcview_nroff_t *mcview_nroff_seq_new_num (WView * view, off_t lc_index);
338 mcview_nroff_t *mcview_nroff_seq_new (WView * view);
339 void mcview_nroff_seq_free (mcview_nroff_t ** nroff);
340 nroff_type_t mcview_nroff_seq_info (mcview_nroff_t * nroff);
341 int mcview_nroff_seq_next (mcview_nroff_t * nroff);
342 int mcview_nroff_seq_prev (mcview_nroff_t * nroff);
343 
344 /* search.c: */
345 gboolean mcview_search_init (WView * view);
346 void mcview_search_deinit (WView * view);
347 mc_search_cbret_t mcview_search_cmd_callback (const void *user_data, gsize char_offset,
348                                               int *current_char);
349 mc_search_cbret_t mcview_search_update_cmd_callback (const void *user_data, gsize char_offset);
350 void mcview_do_search (WView * view, off_t want_search_start);
351 
352 /* --------------------------------------------------------------------------------------------- */
353 /*** inline functions ****************************************************************************/
354 /* --------------------------------------------------------------------------------------------- */
355 
356 static inline off_t
mcview_offset_rounddown(off_t a,off_t b)357 mcview_offset_rounddown (off_t a, off_t b)
358 {
359     g_assert (b != 0);
360     return a - a % b;
361 }
362 
363 /* --------------------------------------------------------------------------------------------- */
364 
365 /* {{{ Simple Primitive Functions for WView }}} */
366 static inline gboolean
mcview_is_in_panel(WView * view)367 mcview_is_in_panel (WView * view)
368 {
369     return (view->dpy_frame_size != 0);
370 }
371 
372 /* --------------------------------------------------------------------------------------------- */
373 
374 static inline gboolean
mcview_may_still_grow(WView * view)375 mcview_may_still_grow (WView * view)
376 {
377     return (view->growbuf_in_use && !view->growbuf_finished);
378 }
379 
380 /* --------------------------------------------------------------------------------------------- */
381 
382 /* returns TRUE if the idx lies in the half-open interval
383  * [offset; offset + size), FALSE otherwise.
384  */
385 static inline gboolean
mcview_already_loaded(off_t offset,off_t idx,size_t size)386 mcview_already_loaded (off_t offset, off_t idx, size_t size)
387 {
388     return (offset <= idx && idx - offset < (off_t) size);
389 }
390 
391 /* --------------------------------------------------------------------------------------------- */
392 
393 static inline gboolean
mcview_get_byte_file(WView * view,off_t byte_index,int * retval)394 mcview_get_byte_file (WView * view, off_t byte_index, int *retval)
395 {
396     g_assert (view->datasource == DS_FILE);
397 
398     mcview_file_load_data (view, byte_index);
399     if (mcview_already_loaded (view->ds_file_offset, byte_index, view->ds_file_datalen))
400     {
401         if (retval)
402             *retval = view->ds_file_data[byte_index - view->ds_file_offset];
403         return TRUE;
404     }
405     if (retval)
406         *retval = -1;
407     return FALSE;
408 }
409 
410 /* --------------------------------------------------------------------------------------------- */
411 
412 static inline gboolean
mcview_get_byte(WView * view,off_t offset,int * retval)413 mcview_get_byte (WView * view, off_t offset, int *retval)
414 {
415     switch (view->datasource)
416     {
417     case DS_STDIO_PIPE:
418     case DS_VFS_PIPE:
419         return mcview_get_byte_growing_buffer (view, offset, retval);
420     case DS_FILE:
421         return mcview_get_byte_file (view, offset, retval);
422     case DS_STRING:
423         return mcview_get_byte_string (view, offset, retval);
424     case DS_NONE:
425         return mcview_get_byte_none (view, offset, retval);
426     default:
427         return FALSE;
428     }
429 }
430 
431 /* --------------------------------------------------------------------------------------------- */
432 
433 static inline gboolean
mcview_get_byte_indexed(WView * view,off_t base,off_t ofs,int * retval)434 mcview_get_byte_indexed (WView * view, off_t base, off_t ofs, int *retval)
435 {
436     if (base <= OFFSETTYPE_MAX - ofs)
437     {
438         return mcview_get_byte (view, base + ofs, retval);
439     }
440     if (retval)
441         *retval = -1;
442     return FALSE;
443 }
444 
445 /* --------------------------------------------------------------------------------------------- */
446 
447 static inline int
mcview_count_backspaces(WView * view,off_t offset)448 mcview_count_backspaces (WView * view, off_t offset)
449 {
450     int backspaces = 0;
451     int c;
452     while (offset >= 2 * backspaces && mcview_get_byte (view, offset - 2 * backspaces, &c)
453            && c == '\b')
454         backspaces++;
455     return backspaces;
456 }
457 
458 /* --------------------------------------------------------------------------------------------- */
459 
460 static inline gboolean
mcview_is_nroff_sequence(WView * view,off_t offset)461 mcview_is_nroff_sequence (WView * view, off_t offset)
462 {
463     int c0, c1, c2;
464 
465     /* The following commands are ordered to speed up the calculation. */
466 
467     if (!mcview_get_byte_indexed (view, offset, 1, &c1) || c1 != '\b')
468         return FALSE;
469 
470     if (!mcview_get_byte_indexed (view, offset, 0, &c0) || !g_ascii_isprint (c0))
471         return FALSE;
472 
473     if (!mcview_get_byte_indexed (view, offset, 2, &c2) || !g_ascii_isprint (c2))
474         return FALSE;
475 
476     return (c0 == c2 || c0 == '_' || (c0 == '+' && c2 == 'o'));
477 }
478 
479 /* --------------------------------------------------------------------------------------------- */
480 
481 static inline void
mcview_growbuf_read_all_data(WView * view)482 mcview_growbuf_read_all_data (WView * view)
483 {
484     mcview_growbuf_read_until (view, OFFSETTYPE_MAX);
485 }
486 
487 /* --------------------------------------------------------------------------------------------- */
488 
489 #endif /* MC__VIEWER_INTERNAL_H */
490