/** * Move up. * * Unwrap mode: Piece of cake. Wrap mode: If we'd walk back more than the current line offset * within the paragraph, we need to jump back to the previous paragraph and compute its height to * see if we start from that paragraph, and repeat this if necessary. Once we're within the desired * paragraph, we still need to format it from its beginning to know the state. * * See the top of this file for comments about MAX_BACKWARDS_WALK_IN_PARAGRAPH. * * force_max is a nice protection against the rare extreme case that the file underneath us * changes, we don't want to endlessly consume a file of maybe full of zeros upon moving upwards. */ void mcview_ascii_move_up (WView * view, off_t lines) { if (!view->text_wrap_mode) { while (lines-- != 0) view->dpy_start = mcview_bol (view, view->dpy_start - 1, 0); view->dpy_paragraph_skip_lines = 0; view->dpy_wrap_dirty = TRUE; } else { int i; while (lines > view->dpy_paragraph_skip_lines) { /* We need to go back to the previous paragraph. */ if (view->dpy_start == 0) { /* Oops, we're already in the first paragraph. */ view->dpy_paragraph_skip_lines = 0; mcview_state_machine_init (&view->dpy_state_top, 0); return; } lines -= view->dpy_paragraph_skip_lines; view->force_max = view->dpy_start; view->dpy_start = mcview_bol (view, view->dpy_start - 1, view->dpy_start - MAX_BACKWARDS_WALK_IN_PARAGRAPH); mcview_state_machine_init (&view->dpy_state_top, view->dpy_start); /* This is a tricky way of denoting that we're at the end of the paragraph. * Normally we'd jump to the next paragraph and reset paragraph_skip_lines. But for * walking backwards this is exactly what we need. */ view->dpy_paragraph_skip_lines = mcview_display_paragraph (view, &view->dpy_state_top, view->data_area.height); view->force_max = -1; } /* Okay, we have have dpy_start pointing to the desired paragraph, and we still need to * walk back "lines" lines from the current "dpy_paragraph_skip_lines" offset. We can't do * that, so walk from the beginning of the paragraph. */ mcview_state_machine_init (&view->dpy_state_top, view->dpy_start); view->dpy_paragraph_skip_lines -= lines; for (i = 0; i < view->dpy_paragraph_skip_lines; i++) mcview_display_line (view, &view->dpy_state_top, -1, NULL, NULL); } }
void mcview_toggle_wrap_mode (mcview_t * view) { if (view->text_wrap_mode) view->dpy_start = mcview_bol (view, view->dpy_start, 0); view->text_wrap_mode = !view->text_wrap_mode; view->dpy_bbar_dirty = TRUE; view->dirty++; }
void mcview_moveto_eol (mcview_t * view) { off_t bol; if (view->hex_mode) { off_t filesize; bol = mcview_offset_rounddown (view->hex_cursor, view->bytes_per_line); if (mcview_get_byte_indexed (view, bol, view->bytes_per_line - 1, NULL) == TRUE) { view->hex_cursor = bol + view->bytes_per_line - 1; } else { filesize = mcview_get_filesize (view); view->hex_cursor = mcview_offset_doz (filesize, 1); } } else { off_t eol; bol = mcview_bol (view, view->dpy_start, 0); eol = mcview_eol (view, view->dpy_start, mcview_get_filesize (view)); if (!view->utf8) { if (eol > bol) view->dpy_text_column = eol - bol; } else { char *str = NULL; switch (view->datasource) { case DS_STDIO_PIPE: case DS_VFS_PIPE: str = mcview_get_ptr_growing_buffer (view, bol); break; case DS_FILE: str = mcview_get_ptr_file (view, bol); break; case DS_STRING: str = mcview_get_ptr_string (view, bol); break; case DS_NONE: break; } if (str != NULL && eol > bol) view->dpy_text_column = g_utf8_strlen (str, eol - bol); else view->dpy_text_column = eol - bol; } view->dpy_text_column = max (0, view->dpy_text_column - view->data_area.width); } mcview_movement_fixups (view, FALSE); }
void mcview_moveto_bol (mcview_t * view) { if (view->hex_mode) { view->hex_cursor -= view->hex_cursor % view->bytes_per_line; } else if (!view->text_wrap_mode) { view->dpy_start = mcview_bol (view, view->dpy_start, 0); } view->dpy_text_column = 0; mcview_movement_fixups (view, TRUE); }
void mcview_moveto_match (mcview_t * view) { off_t offset; offset = view->search_start; if (view->hex_mode) { view->hex_cursor = offset; view->dpy_start = offset - offset % view->bytes_per_line; } else { view->dpy_start = mcview_bol (view, offset, 0); } mcview_scroll_to_cursor (view); view->dirty++; }
void mcview_toggle_hex_mode (mcview_t * view) { view->hex_mode = !view->hex_mode; if (view->hex_mode) { view->hex_cursor = view->dpy_start; view->dpy_start = mcview_offset_rounddown (view->dpy_start, view->bytes_per_line); widget_want_cursor (WIDGET (view), TRUE); } else { view->dpy_start = mcview_bol (view, view->hex_cursor, 0); view->hex_cursor = view->dpy_start; widget_want_cursor (WIDGET (view), FALSE); } mcview_altered_hex_mode = 1; view->dpy_bbar_dirty = TRUE; view->dirty++; }
void mcview_moveto_match (WView * view) { if (view->mode_flags.hex) { view->hex_cursor = view->search_start; view->hexedit_lownibble = FALSE; view->dpy_start = view->search_start - view->search_start % view->bytes_per_line; view->dpy_end = view->search_end - view->search_end % view->bytes_per_line; view->dpy_paragraph_skip_lines = 0; view->dpy_wrap_dirty = TRUE; } else { view->dpy_start = mcview_bol (view, view->search_start, 0); view->dpy_paragraph_skip_lines = 0; view->dpy_wrap_dirty = TRUE; } mcview_scroll_to_cursor (view); view->dirty++; }
gboolean mcview_dialog_goto (WView * view, off_t * offset) { typedef enum { MC_VIEW_GOTO_LINENUM = 0, MC_VIEW_GOTO_PERCENT = 1, MC_VIEW_GOTO_OFFSET_DEC = 2, MC_VIEW_GOTO_OFFSET_HEX = 3 } mcview_goto_type_t; const char *mc_view_goto_str[] = { N_("&Line number"), N_("Pe&rcents"), N_("&Decimal offset"), N_("He&xadecimal offset") }; static mcview_goto_type_t current_goto_type = MC_VIEW_GOTO_LINENUM; size_t num_of_types; char *exp = NULL; int qd_result; gboolean res; num_of_types = G_N_ELEMENTS (mc_view_goto_str); #ifdef ENABLE_NLS { size_t i; for (i = 0; i < num_of_types; i++) mc_view_goto_str[i] = _(mc_view_goto_str[i]); } #endif { quick_widget_t quick_widgets[] = { /* *INDENT-OFF* */ QUICK_INPUT (INPUT_LAST_TEXT, MC_HISTORY_VIEW_GOTO, &exp, NULL, FALSE, FALSE, INPUT_COMPLETE_NONE), QUICK_RADIO (num_of_types, (const char **) mc_view_goto_str, (int *) ¤t_goto_type, NULL), QUICK_BUTTONS_OK_CANCEL, QUICK_END /* *INDENT-ON* */ }; quick_dialog_t qdlg = { -1, -1, 40, N_("Goto"), "[Input Line Keys]", quick_widgets, NULL, NULL }; /* run dialog */ qd_result = quick_dialog (&qdlg); } *offset = -1; /* check input line value */ res = (qd_result != B_CANCEL && exp != NULL && exp[0] != '\0'); if (res) { int base = (current_goto_type == MC_VIEW_GOTO_OFFSET_HEX) ? 16 : 10; off_t addr; char *error; addr = (off_t) g_ascii_strtoll (exp, &error, base); if ((*error == '\0') && (addr >= 0)) { switch (current_goto_type) { case MC_VIEW_GOTO_LINENUM: /* Line number entered by user is 1-based. */ if (addr > 0) addr--; mcview_coord_to_offset (view, offset, addr, 0); *offset = mcview_bol (view, *offset, 0); break; case MC_VIEW_GOTO_PERCENT: if (addr > 100) addr = 100; /* read all data from pipe to get real size */ if (view->growbuf_in_use) mcview_growbuf_read_all_data (view); *offset = addr * mcview_get_filesize (view) / 100; if (!view->mode_flags.hex) *offset = mcview_bol (view, *offset, 0); break; case MC_VIEW_GOTO_OFFSET_DEC: case MC_VIEW_GOTO_OFFSET_HEX: if (!view->mode_flags.hex) { if (view->growbuf_in_use) mcview_growbuf_read_until (view, addr); *offset = mcview_bol (view, addr, 0); } else { /* read all data from pipe to get real size */ if (view->growbuf_in_use) mcview_growbuf_read_all_data (view); *offset = addr; addr = mcview_get_filesize (view); if (*offset > addr) *offset = addr; } break; default: *offset = 0; break; } } } g_free (exp); return res; }
gboolean mcview_load (mcview_t * view, const char *command, const char *file, int start_line) { gboolean retval = FALSE; vfs_path_t *vpath = NULL; #ifdef HAVE_ASSERT_H assert (view->bytes_per_line != 0); #endif view->filename_vpath = vfs_path_from_str (file); /* get working dir */ if (file != NULL && file[0] != '\0') { vfs_path_free (view->workdir_vpath); if (!g_path_is_absolute (file)) { vfs_path_t *p; p = vfs_path_clone (vfs_get_raw_current_dir ()); view->workdir_vpath = vfs_path_append_new (p, file, (char *) NULL); vfs_path_free (p); } else { /* try extract path form filename */ const char *fname; char *dir; fname = x_basename (file); dir = g_strndup (file, (size_t) (fname - file)); view->workdir_vpath = vfs_path_from_str (dir); g_free (dir); } } if (!mcview_is_in_panel (view)) view->dpy_text_column = 0; mcview_set_codeset (view); if (command != NULL && (view->magic_mode || file == NULL || file[0] == '\0')) retval = mcview_load_command_output (view, command); else if (file != NULL && file[0] != '\0') { int fd; char tmp[BUF_MEDIUM]; struct stat st; /* Open the file */ vpath = vfs_path_from_str (file); fd = mc_open (vpath, O_RDONLY | O_NONBLOCK); if (fd == -1) { g_snprintf (tmp, sizeof (tmp), _("Cannot open \"%s\"\n%s"), file, unix_error_string (errno)); mcview_show_error (view, tmp); vfs_path_free (view->filename_vpath); view->filename_vpath = NULL; vfs_path_free (view->workdir_vpath); view->workdir_vpath = NULL; goto finish; } /* Make sure we are working with a regular file */ if (mc_fstat (fd, &st) == -1) { mc_close (fd); g_snprintf (tmp, sizeof (tmp), _("Cannot stat \"%s\"\n%s"), file, unix_error_string (errno)); mcview_show_error (view, tmp); vfs_path_free (view->filename_vpath); view->filename_vpath = NULL; vfs_path_free (view->workdir_vpath); view->workdir_vpath = NULL; goto finish; } if (!S_ISREG (st.st_mode)) { mc_close (fd); mcview_show_error (view, _("Cannot view: not a regular file")); vfs_path_free (view->filename_vpath); view->filename_vpath = NULL; vfs_path_free (view->workdir_vpath); view->workdir_vpath = NULL; goto finish; } if (st.st_size == 0 || mc_lseek (fd, 0, SEEK_SET) == -1) { /* Must be one of those nice files that grow (/proc) */ mcview_set_datasource_vfs_pipe (view, fd); } else { int type; type = get_compression_type (fd, file); if (view->magic_mode && (type != COMPRESSION_NONE)) { char *tmp_filename; vfs_path_t *vpath1; int fd1; tmp_filename = g_strconcat (file, decompress_extension (type), (char *) NULL); vpath1 = vfs_path_from_str (tmp_filename); fd1 = mc_open (vpath1, O_RDONLY | O_NONBLOCK); if (fd1 == -1) { g_snprintf (tmp, sizeof (tmp), _("Cannot open \"%s\" in parse mode\n%s"), file, unix_error_string (errno)); mcview_show_error (view, tmp); } else { mc_close (fd); fd = fd1; mc_fstat (fd, &st); } vfs_path_free (vpath1); g_free (tmp_filename); } mcview_set_datasource_file (view, fd, &st); } retval = TRUE; } finish: view->command = g_strdup (command); view->dpy_start = 0; view->search_start = 0; view->search_end = 0; view->dpy_text_column = 0; mcview_compute_areas (view); mcview_update_bytes_per_line (view); if (mcview_remember_file_position && view->filename_vpath != NULL && start_line == 0) { long line, col; off_t new_offset, max_offset; load_file_position (view->filename_vpath, &line, &col, &new_offset, &view->saved_bookmarks); max_offset = mcview_get_filesize (view) - 1; if (max_offset < 0) new_offset = 0; else new_offset = min (new_offset, max_offset); if (!view->hex_mode) view->dpy_start = mcview_bol (view, new_offset, 0); else { view->dpy_start = new_offset - new_offset % view->bytes_per_line; view->hex_cursor = new_offset; } } else if (start_line > 0) mcview_moveto (view, start_line - 1, 0); view->hexedit_lownibble = FALSE; view->hexview_in_text = FALSE; view->change_list = NULL; vfs_path_free (vpath); return retval; }
gboolean mcview_dialog_goto (mcview_t * view, off_t * offset) { typedef enum { MC_VIEW_GOTO_LINENUM = 0, MC_VIEW_GOTO_PERCENT = 1, MC_VIEW_GOTO_OFFSET_DEC = 2, MC_VIEW_GOTO_OFFSET_HEX = 3 } mcview_goto_type_t; const char *mc_view_goto_str[] = { N_("&Line number (decimal)"), N_("Pe&rcents"), N_("&Decimal offset"), N_("He&xadecimal offset") }; const int goto_dlg_height = 12; int goto_dlg_width = 40; static mcview_goto_type_t current_goto_type = MC_VIEW_GOTO_LINENUM; size_t i; size_t num_of_types = sizeof (mc_view_goto_str) / sizeof (mc_view_goto_str[0]); char *exp = NULL; int qd_result; gboolean res = FALSE; QuickWidget quick_widgets[] = { QUICK_BUTTON (6, 10, goto_dlg_height - 3, goto_dlg_height, N_("&Cancel"), B_CANCEL, NULL), QUICK_BUTTON (2, 10, goto_dlg_height - 3, goto_dlg_height, N_("&OK"), B_ENTER, NULL), QUICK_RADIO (3, goto_dlg_width, 4, goto_dlg_height, num_of_types, (const char **) mc_view_goto_str, (int *) ¤t_goto_type), QUICK_INPUT (3, goto_dlg_width, 2, goto_dlg_height, INPUT_LAST_TEXT, goto_dlg_width - 6, 0, MC_HISTORY_VIEW_GOTO, &exp), QUICK_END }; QuickDialog Quick_input = { goto_dlg_width, goto_dlg_height, -1, -1, N_("Goto"), "[Input Line Keys]", quick_widgets, NULL, NULL, FALSE }; #ifdef ENABLE_NLS for (i = 0; i < num_of_types; i++) mc_view_goto_str[i] = _(mc_view_goto_str[i]); quick_widgets[0].u.button.text = _(quick_widgets[0].u.button.text); quick_widgets[1].u.button.text = _(quick_widgets[1].u.button.text); #endif /* calculate widget coordinates */ { int b0_len, b1_len, len; const int button_gap = 2; /* preliminary dialog width */ goto_dlg_width = max (goto_dlg_width, str_term_width1 (Quick_input.title) + 4); /* length of radiobuttons */ for (i = 0; i < num_of_types; i++) goto_dlg_width = max (goto_dlg_width, str_term_width1 (mc_view_goto_str[i]) + 10); /* length of buttons */ b0_len = str_term_width1 (quick_widgets[0].u.button.text) + 3; b1_len = str_term_width1 (quick_widgets[1].u.button.text) + 5; /* default button */ len = b0_len + b1_len + button_gap * 2; /* dialog width */ Quick_input.xlen = max (goto_dlg_width, len + 6); /* correct widget coordinates */ for (i = sizeof (quick_widgets) / sizeof (quick_widgets[0]); i > 0; i--) quick_widgets[i - 1].x_divisions = Quick_input.xlen; /* input length */ quick_widgets[3].u.input.len = Quick_input.xlen - 6; /* button positions */ quick_widgets[1].relative_x = Quick_input.xlen / 2 - len / 2; quick_widgets[0].relative_x = quick_widgets[1].relative_x + b1_len + button_gap; } /* run dialog */ qd_result = quick_dialog (&Quick_input); *offset = -1; /* check input line value */ if ((qd_result != B_CANCEL) && (exp != NULL) && (exp[0] != '\0')) { int base = (current_goto_type == MC_VIEW_GOTO_OFFSET_HEX) ? 16 : 10; off_t addr; char *error; res = TRUE; addr = strtoll (exp, &error, base); if ((*error == '\0') && (addr >= 0)) { switch (current_goto_type) { case MC_VIEW_GOTO_LINENUM: mcview_coord_to_offset (view, offset, addr, 0); *offset = mcview_bol (view, *offset, 0); break; case MC_VIEW_GOTO_PERCENT: if (addr > 100) addr = 100; *offset = addr * mcview_get_filesize (view) / 100; if (!view->hex_mode) *offset = mcview_bol (view, *offset, 0); break; case MC_VIEW_GOTO_OFFSET_DEC: case MC_VIEW_GOTO_OFFSET_HEX: *offset = addr; if (!view->hex_mode) *offset = mcview_bol (view, *offset, 0); else { addr = mcview_get_filesize (view); if (*offset > addr) *offset = addr; } break; default: *offset = 0; break; } } } g_free (exp); return res; }
void mcview_move_up (mcview_t * view, off_t lines) { off_t new_offset; if (view->hex_mode) { off_t bytes = lines * view->bytes_per_line; if (view->hex_cursor >= bytes) { view->hex_cursor -= bytes; if (view->hex_cursor < view->dpy_start) view->dpy_start = mcview_offset_doz (view->dpy_start, bytes); } else { view->hex_cursor %= view->bytes_per_line; } } else { off_t i; for (i = 0; i < lines; i++) { if (view->dpy_start == 0) break; if (view->text_wrap_mode) { new_offset = mcview_bol (view, view->dpy_start, view->dpy_start - (off_t) 1); /* check if dpy_start == BOL or not (then new_offset = dpy_start - 1, * no need to check more) */ if (new_offset == view->dpy_start) { size_t last_row_length; new_offset = mcview_bol (view, new_offset - 1, 0); last_row_length = (view->dpy_start - new_offset) % view->data_area.width; if (last_row_length != 0) { /* if dpy_start == BOL in wrapped mode, find BOL of previous line * and move down all but the last rows */ new_offset = view->dpy_start - (off_t) last_row_length; } } else { /* if dpy_start != BOL in wrapped mode, just move one row up; * no need to check if > 0 as there is at least exactly one wrap * between dpy_start and BOL */ new_offset = view->dpy_start - (off_t) view->data_area.width; } view->dpy_start = new_offset; } else { /* if unwrapped -> current BOL equals dpy_start, just find BOL of previous line */ new_offset = view->dpy_start - 1; view->dpy_start = mcview_bol (view, new_offset, 0); } } } mcview_movement_fixups (view, TRUE); }