#ifndef MC__VIEWER_INTERNAL_H #define MC__VIEWER_INTERNAL_H #include // CHAR_BIT, MB_LEN_MAX #include #include #include #include "lib/global.h" #include "lib/search.h" #include "lib/widget.h" #include "lib/vfs/vfs.h" // vfs_path_t #include "lib/util.h" // mc_pipe_t #include "src/keymap.h" // global_keymap_t #include "src/filemanager/dir.h" // dir_list #include "mcviewer.h" /*** typedefs(not structures) and defined constants **********************************************/ #define OFF_T_BITWIDTH ((unsigned int) (sizeof (off_t) * CHAR_BIT - 1)) #define OFFSETTYPE_MAX (((off_t) 1 << (OFF_T_BITWIDTH - 1)) - 1) typedef unsigned char byte; /*** enums ***************************************************************************************/ /* data sources of the view */ enum view_ds { DS_NONE, // No data available DS_STDIO_PIPE, // Data comes from a pipe using popen/pclose DS_VFS_PIPE, // Data comes from a piped-in VFS file DS_FILE, // Data comes from a VFS file DS_STRING // Data comes from a string in memory }; enum ccache_type { CCACHE_OFFSET, CCACHE_LINECOL }; typedef enum { NROFF_TYPE_NONE = 0, NROFF_TYPE_BOLD = 1, NROFF_TYPE_UNDERLINE = 2 } nroff_type_t; /*** structures declarations (and typedefs of structures)*****************************************/ /* A node for building a change list on change_list */ struct hexedit_change_node { struct hexedit_change_node *next; off_t offset; byte value; }; /* A cache entry for mapping offsets into line/column pairs and vice versa. * cc_offset, cc_line, and cc_column are the 0-based values of the offset, * line and column of that cache entry. cc_nroff_column is the column * corresponding to cc_offset in nroff mode. */ typedef struct { off_t cc_offset; off_t cc_line; off_t cc_column; off_t cc_nroff_column; } coord_cache_entry_t; /* TODO: find a better name. This is not actually a "state machine", * but a "state machine's state", but that sounds silly. * Could be parser_state, formatter_state... */ typedef struct { off_t offset; // The file offset at which this is the state. off_t unwrapped_column; // Columns if the paragraph wasn't wrapped, // used for positioning TABs in wrapped lines gboolean nroff_underscore_is_underlined; // whether _\b_ is underlined rather than bold gboolean print_lonely_combining; // whether lonely combining marks are printed on a dotted circle } mcview_state_machine_t; struct mcview_nroff_struct; struct WView { Widget widget; vfs_path_t *filename_vpath; // Name of the file vfs_path_t *workdir_vpath; // Name of the working directory char *command; // Command used to pipe data in enum view_ds datasource; // Where the displayed data comes from // stdio pipe data source mc_pipe_t *ds_stdio_pipe; // Output of a shell command gboolean pipe_first_err_msg; // Show only 1st message from stderr // vfs pipe data source int ds_vfs_pipe; // Non-seekable vfs file descriptor // vfs file data source int ds_file_fd; // File with random access off_t ds_file_filesize; // Size of the file off_t ds_file_offset; // Offset of the currently loaded data byte *ds_file_data; // Currently loaded data size_t ds_file_datalen; // Number of valid bytes in file_data size_t ds_file_datasize; // Number of allocated bytes in file_data // string data source byte *ds_string_data; // The characters of the string size_t ds_string_len; // The length of the string // Growing buffers information gboolean growbuf_in_use; // Use the growing buffers? GPtrArray *growbuf_blockptr; // Pointer to the block pointers size_t growbuf_lastindex; /* Number of bytes in the last page of the growing buffer */ gboolean growbuf_finished; // TRUE when all data has been read. mcview_mode_flags_t mode_flags; // Hex editor modes gboolean hexedit_mode; // Hexview or Hexedit const global_keymap_t *hex_keymap; gboolean hexview_in_text; // Is the hexview cursor in the text area? int bytes_per_line; // Number of bytes per line in hex mode off_t hex_cursor; // Hexview cursor position in file gboolean hexedit_lownibble; // Are we editing the last significant nibble? gboolean locked; // We hold lock on current file gboolean utf8; // It's multibyte file codeset GPtrArray *coord_cache; // Cache for mapping offsets to cursor positions // Display information int dpy_frame_size; // Size of the frame surrounding the real viewer off_t dpy_start; // Offset of the displayed data (start of the paragraph in non-hex mode) off_t dpy_end; // Offset after the displayed data off_t dpy_paragraph_skip_lines; // Extra lines to skip in wrap mode mcview_state_machine_t dpy_state_top; // Parser-formatter state at the topmost visible line in wrap mode mcview_state_machine_t dpy_state_bottom; // Parser-formatter state after the bottomvisible line in wrap mode gboolean dpy_wrap_dirty; // dpy_state_top needs to be recomputed off_t dpy_text_column; /* Number of skipped columns in non-wrap * text mode */ int cursor_col; // Cursor column int cursor_row; // Cursor row struct hexedit_change_node *change_list; // Linked list of changes WRect status_area; // Where the status line is displayed WRect ruler_area; // Where the ruler is displayed WRect data_area; // Where the data is displayed ssize_t force_max; // Force a max offset, or -1 int dirty; // Number of skipped updates gboolean dpy_bbar_dirty; // Does the button bar need to be updated? // handle of search engine mc_search_t *search; gchar *last_search_string; struct mcview_nroff_struct *search_nroff_seq; off_t search_start; // First character to start searching from off_t search_end; // Length of found string or 0 if none was found int search_numNeedSkipChar; // whether search conditions should be started with BOL(^) or ended with EOL($) mc_search_line_t search_line_type; // Markers int marker; // mark to use off_t marks[10]; // 10 marks: 0..9 off_t update_steps; // The number of bytes between percent increments off_t update_activate; // Last point where we updated the status // converter for translation of text GIConv converter; GArray *saved_bookmarks; dir_list *dir; /* List of current directory files * to handle CK_FileNext and CK_FilePrev commands */ int *dir_idx; /* Index of current file in dir structure. * Pointer is used here as reference to WPanel::dir::count */ vfs_path_t *ext_script; // Temporary script file created by regex_command_for() }; typedef struct mcview_nroff_struct { WView *view; off_t index; int char_length; int current_char; nroff_type_t type; nroff_type_t prev_type; } mcview_nroff_t; typedef struct mcview_search_options_t { mc_search_type_t type; gboolean case_sens; gboolean backwards; gboolean whole_words; gboolean all_codepages; } mcview_search_options_t; /*** global variables defined in .c file *********************************************************/ extern mcview_search_options_t mcview_search_options; /*** declarations of public functions ************************************************************/ /* actions_cmd.c: */ cb_ret_t mcview_callback (Widget *w, Widget *sender, widget_msg_t msg, int parm, void *data); cb_ret_t mcview_dialog_callback (Widget *w, Widget *sender, widget_msg_t msg, int parm, void *data); /* ascii.c: */ void mcview_display_text (WView *view); void mcview_state_machine_init (mcview_state_machine_t *, off_t); void mcview_ascii_move_down (WView *view, off_t lines); void mcview_ascii_move_up (WView *view, off_t lines); void mcview_ascii_moveto_bol (WView *view); void mcview_ascii_moveto_eol (WView *view); #ifdef MC_ENABLE_DEBUGGING_CODE void mcview_ccache_dump (WView *view); #endif void mcview_ccache_lookup (WView *view, coord_cache_entry_t *coord, enum ccache_type lookup_what); /* datasource.c: */ void mcview_set_datasource_none (WView *view); off_t mcview_get_filesize (WView *view); void mcview_update_filesize (WView *view); char *mcview_get_ptr_file (WView *view, off_t byte_index); char *mcview_get_ptr_string (WView *view, off_t byte_index); gboolean mcview_get_utf (WView *view, off_t byte_index, int *ch, int *ch_len); gboolean mcview_get_byte_string (WView *view, off_t byte_index, int *retval); gboolean mcview_get_byte_none (WView *view, off_t byte_index, int *retval); void mcview_set_byte (WView *view, off_t offset, byte b); void mcview_file_load_data (WView *view, off_t byte_index); void mcview_close_datasource (WView *view); void mcview_set_datasource_file (WView *view, int fd, const struct stat *st); gboolean mcview_load_command_output (WView *view, const char *command); void mcview_set_datasource_vfs_pipe (WView *view, int fd); void mcview_set_datasource_string (WView *view, const char *s); /* dialog.c: */ gboolean mcview_dialog_search (WView *view); gboolean mcview_dialog_goto (WView *view, off_t *offset); /* display.c: */ void mcview_update (WView *view); void mcview_display (WView *view); void mcview_compute_areas (WView *view); void mcview_update_bytes_per_line (WView *view); void mcview_display_toggle_ruler (WView *view); void mcview_display_clean (WView *view); void mcview_display_ruler (WView *view); /* growbuf.c: */ void mcview_growbuf_init (WView *view); void mcview_growbuf_done (WView *view); void mcview_growbuf_free (WView *view); off_t mcview_growbuf_filesize (WView *view); void mcview_growbuf_read_until (WView *view, off_t ofs); gboolean mcview_get_byte_growing_buffer (WView *view, off_t byte_index, int *retval); char *mcview_get_ptr_growing_buffer (WView *view, off_t byte_index); /* hex.c: */ void mcview_display_hex (WView *view); gboolean mcview_hexedit_save_changes (WView *view); void mcview_toggle_hexedit_mode (WView *view); void mcview_hexedit_free_change_list (WView *view); void mcview_enqueue_change (struct hexedit_change_node **head, struct hexedit_change_node *node); /* lib.c: */ void mcview_toggle_magic_mode (WView *view); void mcview_toggle_wrap_mode (WView *view); void mcview_toggle_nroff_mode (WView *view); void mcview_toggle_hex_mode (WView *view); void mcview_init (WView *view); void mcview_done (WView *view); void mcview_select_encoding (WView *view); void mcview_set_codeset (WView *view); void mcview_show_error (WView *view, const char *format, const char *filename); off_t mcview_bol (WView *view, off_t current, off_t limit); off_t mcview_eol (WView *view, off_t current); char *mcview_get_title (const WDialog *h, ssize_t width); int mcview_calc_percent (WView *view, off_t p); /* move.c */ void mcview_move_up (WView *view, off_t lines); void mcview_move_down (WView *view, off_t lines); void mcview_move_left (WView *view, off_t columns); void mcview_move_right (WView *view, off_t columns); void mcview_moveto_top (WView *view); void mcview_moveto_bottom (WView *view); void mcview_moveto_bol (WView *view); void mcview_moveto_eol (WView *view); void mcview_moveto_offset (WView *view, off_t offset); void mcview_moveto (WView *view, off_t, off_t col); void mcview_coord_to_offset (WView *view, off_t *ret_offset, off_t line, off_t column); void mcview_offset_to_coord (WView *view, off_t *ret_line, off_t *ret_column, off_t offset); void mcview_place_cursor (WView *view); void mcview_moveto_match (WView *view); /* nroff.c: */ int mcview__get_nroff_real_len (WView *view, off_t start, off_t length); mcview_nroff_t *mcview_nroff_seq_new_num (WView *view, off_t lc_index); mcview_nroff_t *mcview_nroff_seq_new (WView *view); void mcview_nroff_seq_free (mcview_nroff_t **nroff); nroff_type_t mcview_nroff_seq_info (mcview_nroff_t *nroff); int mcview_nroff_seq_next (mcview_nroff_t *nroff); int mcview_nroff_seq_prev (mcview_nroff_t *nroff); /* search.c: */ gboolean mcview_search_init (WView *view); void mcview_search_deinit (WView *view); mc_search_cbret_t mcview_search_cmd_callback (const void *user_data, off_t char_offset, int *current_char); mc_search_cbret_t mcview_search_update_cmd_callback (const void *user_data, off_t char_offset); void mcview_search (WView *view, gboolean start_search); /* --------------------------------------------------------------------------------------------- */ /*** inline functions ****************************************************************************/ /* --------------------------------------------------------------------------------------------- */ static inline off_t mcview_offset_rounddown (off_t a, off_t b) { g_assert (b != 0); return a - a % b; } /* --------------------------------------------------------------------------------------------- */ /* {{{ Simple Primitive Functions for WView }}} */ static inline gboolean mcview_is_in_panel (WView *view) { return (view->dpy_frame_size != 0); } /* --------------------------------------------------------------------------------------------- */ static inline gboolean mcview_may_still_grow (WView *view) { return (view->growbuf_in_use && !view->growbuf_finished); } /* --------------------------------------------------------------------------------------------- */ /* returns TRUE if the idx lies in the half-open interval * [offset; offset + size), FALSE otherwise. */ static inline gboolean mcview_already_loaded (off_t offset, off_t idx, size_t size) { return (offset <= idx && idx - offset < (off_t) size); } /* --------------------------------------------------------------------------------------------- */ static inline gboolean mcview_get_byte_file (WView *view, off_t byte_index, int *retval) { g_assert (view->datasource == DS_FILE); mcview_file_load_data (view, byte_index); if (mcview_already_loaded (view->ds_file_offset, byte_index, view->ds_file_datalen)) { if (retval) *retval = view->ds_file_data[byte_index - view->ds_file_offset]; return TRUE; } if (retval) *retval = -1; return FALSE; } /* --------------------------------------------------------------------------------------------- */ static inline gboolean mcview_get_byte (WView *view, off_t offset, int *retval) { switch (view->datasource) { case DS_STDIO_PIPE: case DS_VFS_PIPE: return mcview_get_byte_growing_buffer (view, offset, retval); case DS_FILE: return mcview_get_byte_file (view, offset, retval); case DS_STRING: return mcview_get_byte_string (view, offset, retval); case DS_NONE: return mcview_get_byte_none (view, offset, retval); default: return FALSE; } } /* --------------------------------------------------------------------------------------------- */ static inline gboolean mcview_get_byte_indexed (WView *view, off_t base, off_t ofs, int *retval) { if (base <= OFFSETTYPE_MAX - ofs) return mcview_get_byte (view, base + ofs, retval); if (retval != NULL) *retval = -1; return FALSE; } /* --------------------------------------------------------------------------------------------- */ static inline int mcview_count_backspaces (WView *view, off_t offset) { int backspaces = 0; int c; while (offset >= 2 * backspaces && mcview_get_byte (view, offset - 2 * backspaces, &c) && c == '\b') backspaces++; return backspaces; } /* --------------------------------------------------------------------------------------------- */ static inline gboolean mcview_is_nroff_sequence (WView *view, off_t offset) { int c0, c1, c2; // The following commands are ordered to speed up the calculation. if (!mcview_get_byte_indexed (view, offset, 1, &c1) || c1 != '\b') return FALSE; if (!mcview_get_byte_indexed (view, offset, 0, &c0) || !g_ascii_isprint (c0)) return FALSE; if (!mcview_get_byte_indexed (view, offset, 2, &c2) || !g_ascii_isprint (c2)) return FALSE; return (c0 == c2 || c0 == '_' || (c0 == '+' && c2 == 'o')); } /* --------------------------------------------------------------------------------------------- */ static inline void mcview_growbuf_read_all_data (WView *view) { mcview_growbuf_read_until (view, OFFSETTYPE_MAX); } /* --------------------------------------------------------------------------------------------- */ #endif