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); }
off_t mcview_eol (mcview_t * view, off_t current, off_t limit) { int c, prev_ch = 0; off_t filesize; filesize = mcview_get_filesize (view); if (current < 0) return 0; if (current >= filesize) return filesize; while (current < filesize && current < limit) { if (!mcview_get_byte (view, current, &c)) break; if (c == '\n') { current++; break; } else if (prev_ch == '\r') { break; } current++; prev_ch = c; } return current; }
off_t mcview_bol (mcview_t * view, off_t current, off_t limit) { int c; off_t filesize; filesize = mcview_get_filesize (view); if (current <= 0) return 0; if (current > filesize) return filesize; if (!mcview_get_byte (view, current, &c)) return current; if (c == '\n') { if (!mcview_get_byte (view, current - 1, &c)) return current; if (c == '\r') current--; } while (current > 0 && current >= limit) { if (!mcview_get_byte (view, current - 1, &c)) break; if (c == '\r' || c == '\n') break; current--; } return current; }
int mcview_calc_percent (mcview_t * view, off_t p) { const screen_dimen right = view->status_area.left + view->status_area.width; const screen_dimen height = view->status_area.height; off_t filesize; int percent; if (height < 1 || right < 4) return (-1); if (mcview_may_still_grow (view)) return (-1); filesize = mcview_get_filesize (view); if (view->hex_mode && filesize > 0) { /* p can't be beyond the last char, only over that. Compensate for this. */ filesize--; } if (filesize == 0 || p >= filesize) percent = 100; else if (p > (INT_MAX / 100)) percent = p / (filesize / 100); else percent = p * 100 / filesize; return percent; }
void mcview_moveto_eol (WView * view) { off_t bol; if (view->mode_flags.hex) { 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 { mcview_ascii_moveto_eol (view); } mcview_movement_fixups (view, FALSE); }
void mcview_moveto_bottom (mcview_t * view) { off_t filesize; mcview_update_filesize (view); if (view->growbuf_in_use) mcview_growbuf_read_until (view, OFFSETTYPE_MAX); filesize = mcview_get_filesize (view); if (view->hex_mode) { view->hex_cursor = mcview_offset_doz (filesize, 1); mcview_movement_fixups (view, TRUE); } else { const off_t datalines = view->data_area.height; view->dpy_start = filesize; mcview_move_up (view, datalines); } }
void mcview_move_right (mcview_t * view, off_t columns) { if (view->hex_mode) { off_t last_byte; off_t old_cursor = view->hex_cursor; last_byte = mcview_offset_doz (mcview_get_filesize (view), 1); #ifdef HAVE_ASSERT_H assert (columns == 1); #endif if (view->hexview_in_text || view->hexedit_lownibble) { if (view->hex_cursor < last_byte) view->hex_cursor++; } if (!view->hexview_in_text) if (old_cursor < last_byte || !view->hexedit_lownibble) view->hexedit_lownibble = !view->hexedit_lownibble; } else { view->dpy_text_column += columns; } mcview_movement_fixups (view, FALSE); }
void mcview_move_down (WView * view, off_t lines) { off_t last_byte; last_byte = mcview_get_filesize (view); if (view->mode_flags.hex) { off_t i, limit; limit = mcview_offset_doz (last_byte, (off_t) view->bytes_per_line); for (i = 0; i < lines && view->hex_cursor < limit; i++) { view->hex_cursor += view->bytes_per_line; if (lines != 1) { view->dpy_start += view->bytes_per_line; view->dpy_paragraph_skip_lines = 0; view->dpy_wrap_dirty = TRUE; } } } else { mcview_ascii_move_down (view, lines); } mcview_movement_fixups (view, TRUE); }
void mcview_percent (mcview_t * view, off_t p) { const screen_dimen top = view->status_area.top; const screen_dimen right = view->status_area.left + view->status_area.width; const screen_dimen height = view->status_area.height; int percent; off_t filesize; if (height < 1 || right < 4) return; if (mcview_may_still_grow (view)) return; filesize = mcview_get_filesize (view); if (filesize == 0 || view->dpy_end == filesize) percent = 100; else if (p > (INT_MAX / 100)) percent = p / (filesize / 100); else percent = p * 100 / filesize; widget_move (view, top, right - 4); tty_printf ("%3d%%", percent); }
void mcview_move_right (WView * view, off_t columns) { if (view->mode_flags.hex) { off_t last_byte; off_t old_cursor = view->hex_cursor; last_byte = mcview_offset_doz (mcview_get_filesize (view), 1); g_assert (columns == 1); if (view->hexview_in_text || view->hexedit_lownibble) { if (view->hex_cursor < last_byte) view->hex_cursor++; } if (!view->hexview_in_text) if (old_cursor < last_byte || !view->hexedit_lownibble) view->hexedit_lownibble = !view->hexedit_lownibble; } else if (!view->mode_flags.wrap) { view->dpy_text_column += columns; } mcview_movement_fixups (view, FALSE); }
void mcview_moveto_bottom (WView * view) { off_t filesize; mcview_update_filesize (view); if (view->growbuf_in_use) mcview_growbuf_read_all_data (view); filesize = mcview_get_filesize (view); if (view->mode_flags.hex) { view->hex_cursor = mcview_offset_doz (filesize, 1); mcview_movement_fixups (view, TRUE); } else { const off_t datalines = view->data_area.height; view->dpy_start = filesize; view->dpy_paragraph_skip_lines = 0; view->dpy_wrap_dirty = TRUE; mcview_move_up (view, datalines); } }
/** * Move down. * * It's very simple. Just invisibly format the next "lines" lines, carefully carrying the formatter * state in wrap mode. But before each step we need to check if we've already hit the end of the * file, in that case we can no longer move. This is done by walking from dpy_state_bottom. * * Note that this relies on mcview_display_text() setting dpy_state_bottom to its correct value * upon rendering the screen contents. So don't call this function from other functions (e.g. at * the bottom of mcview_ascii_move_up()) which invalidate this value. */ void mcview_ascii_move_down (WView * view, off_t lines) { while (lines-- != 0) { gboolean paragraph_ended; /* See if there's still data below the bottom line, by imaginarily displaying one * more line. This takes care of reading more data into growbuf, if required. * If the end position didn't advance, we're at EOF and hence bail out. */ if (mcview_display_line (view, &view->dpy_state_bottom, -1, ¶graph_ended, NULL) == 0) break; /* Okay, there's enough data. Move by 1 row at the top, too. No need to check for * EOF, that can't happen. */ if (!view->text_wrap_mode) { view->dpy_start = mcview_eol (view, view->dpy_start, mcview_get_filesize (view)); view->dpy_paragraph_skip_lines = 0; view->dpy_wrap_dirty = TRUE; } else { mcview_display_line (view, &view->dpy_state_top, -1, ¶graph_ended, NULL); if (!paragraph_ended) view->dpy_paragraph_skip_lines++; else { view->dpy_start = view->dpy_state_top.offset; view->dpy_paragraph_skip_lines = 0; } } } }
void mcview_set_byte (mcview_t * view, off_t offset, byte b) { (void) &b; assert (offset < mcview_get_filesize (view)); assert (view->datasource == DS_FILE); view->ds_file_datalen = 0; /* just force reloading */ }
static gboolean mcview_find (mcview_t * view, gsize search_start, gsize * len) { gsize search_end; view->search_numNeedSkipChar = 0; search_cb_char_curr_index = -1; if (mcview_search_options.backwards) { search_end = mcview_get_filesize (view); while ((int) search_start >= 0) { view->search_nroff_seq->index = search_start; mcview_nroff_seq_info (view->search_nroff_seq); if (search_end > search_start + view->search->original_len && mc_search_is_fixed_search_str (view->search)) search_end = search_start + view->search->original_len; if (mc_search_run (view->search, (void *) view, search_start, search_end, len) && view->search->normal_offset == (off_t) search_start) { if (view->text_nroff_mode) view->search->normal_offset++; return TRUE; } search_start--; } view->search->error_str = g_strdup (_("Search string not found")); return FALSE; } view->search_nroff_seq->index = search_start; mcview_nroff_seq_info (view->search_nroff_seq); return mc_search_run (view->search, (void *) view, search_start, mcview_get_filesize (view), len); }
void mcview_set_byte (mcview_t * view, off_t offset, byte b) { (void) &b; #ifndef HAVE_ASSERT_H (void) offset; #else assert (offset < mcview_get_filesize (view)); assert (view->datasource == DS_FILE); #endif view->ds_file_datalen = 0; /* just force reloading */ }
static void mcview_search_update_steps (mcview_t * view) { off_t filesize = mcview_get_filesize (view); if (filesize != 0) view->update_steps = 40000; else /* viewing a data stream, not a file */ view->update_steps = filesize / 100; /* Do not update the percent display but every 20 ks */ if (view->update_steps < 20000) view->update_steps = 20000; }
static void mcview_display_status (WView * view) { const screen_dimen top = view->status_area.top; const screen_dimen left = view->status_area.left; const screen_dimen width = view->status_area.width; const screen_dimen height = view->status_area.height; const char *file_label; if (height < 1) return; tty_setcolor (STATUSBAR_COLOR); tty_draw_hline (WIDGET (view)->y + top, WIDGET (view)->x + left, ' ', width); file_label = view->filename_vpath != NULL ? vfs_path_get_last_path_str (view->filename_vpath) : view->command != NULL ? view->command : ""; if (width > 40) { widget_move (view, top, width - 32); if (view->hex_mode) tty_printf ("0x%08" PRIxMAX, (uintmax_t) view->hex_cursor); else { char buffer[BUF_TRUNC_LEN + 1]; size_trunc_len (buffer, BUF_TRUNC_LEN, mcview_get_filesize (view), 0, panels_options.kilobyte_si); tty_printf ("%9" PRIuMAX "/%s%s %s", (uintmax_t) view->dpy_end, buffer, mcview_may_still_grow (view) ? "+" : " ", #ifdef HAVE_CHARSET mc_global.source_codepage >= 0 ? get_codepage_id (mc_global.source_codepage) : #endif ""); } } widget_move (view, top, left); if (width > 40) tty_print_string (str_fit_to_term (file_label, width - 34, J_LEFT_FIT)); else tty_print_string (str_fit_to_term (file_label, width - 5, J_LEFT_FIT)); if (width > 26) mcview_display_percent (view, view->hex_mode ? view->hex_cursor : view->dpy_end); }
static void mcview_display_status (mcview_t * view) { const screen_dimen top = view->status_area.top; const screen_dimen left = view->status_area.left; const screen_dimen width = view->status_area.width; const screen_dimen height = view->status_area.height; const char *file_label; screen_dimen file_label_width; if (height < 1) return; tty_setcolor (STATUSBAR_COLOR); widget_move (view, top, left); tty_draw_hline (-1, -1, ' ', width); file_label = view->filename ? view->filename : view->command ? view->command : ""; file_label_width = str_term_width1 (file_label) - 2; if (width > 40) { char buffer[BUF_TINY]; widget_move (view, top, width - 32); if (view->hex_mode) tty_printf ("0x%08" PRIxMAX, (uintmax_t) view->hex_cursor); else { size_trunc_len (buffer, 5, mcview_get_filesize (view), 0, panels_options.kilobyte_si); tty_printf ("%9" PRIuMAX "/%s%s %s", (uintmax_t) view->dpy_end, buffer, mcview_may_still_grow (view) ? "+" : " ", #ifdef HAVE_CHARSET mc_global.source_codepage >= 0 ? get_codepage_id (mc_global.source_codepage) : "" #else "" #endif ); } } widget_move (view, top, left); if (width > 40) tty_print_string (str_fit_to_term (file_label, width - 34, J_LEFT_FIT)); else tty_print_string (str_fit_to_term (file_label, width - 5, J_LEFT_FIT)); if (width > 26) mcview_percent (view, view->hex_mode ? view->hex_cursor : view->dpy_end); }
static gboolean mcview_find (mcview_search_status_msg_t * ssm, off_t search_start, off_t search_end, gsize * len) { WView *view = ssm->view; view->search_numNeedSkipChar = 0; search_cb_char_curr_index = -1; if (mcview_search_options.backwards) { search_end = mcview_get_filesize (view); while (search_start >= 0) { gboolean ok; view->search_nroff_seq->index = search_start; mcview_nroff_seq_info (view->search_nroff_seq); if (search_end > search_start + (off_t) view->search->original_len && mc_search_is_fixed_search_str (view->search)) search_end = search_start + view->search->original_len; ok = mc_search_run (view->search, (void *) ssm, search_start, search_end, len); if (ok && view->search->normal_offset == search_start) { if (view->text_nroff_mode) view->search->normal_offset++; return TRUE; } /* We abort the search in case of a pattern error, or if the user aborts the search. In other words: in all cases except "string not found". */ if (!ok && view->search->error != MC_SEARCH_E_NOTFOUND) return FALSE; search_start--; } mc_search_set_error (view->search, MC_SEARCH_E_NOTFOUND, "%s", _(STR_E_NOTFOUND)); return FALSE; } view->search_nroff_seq->index = search_start; mcview_nroff_seq_info (view->search_nroff_seq); return mc_search_run (view->search, (void *) ssm, search_start, search_end, len); }
static void mcview_search_update_steps (WView * view) { off_t filesize; filesize = mcview_get_filesize (view); if (filesize != 0) view->update_steps = filesize / 100; else /* viewing a data stream, not a file */ view->update_steps = 40000; /* Do not update the percent display but every 20 kb */ if (view->update_steps < 20000) view->update_steps = 20000; /* Make interrupt more responsive */ if (view->update_steps > 40000) view->update_steps = 40000; }
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; }
void mcview_do_search (mcview_t * view) { mcview_search_status_msg_t vsm; off_t search_start = 0; gboolean isFound = FALSE; gboolean need_search_again = TRUE; size_t match_len; /* for avoid infinite search loop we need to increase or decrease start offset of search */ if (view->search_start != 0) { if (!view->text_nroff_mode) search_start = view->search_start + (mcview_search_options.backwards ? -2 : 0); else { if (mcview_search_options.backwards) { mcview_nroff_t *nroff; nroff = mcview_nroff_seq_new_num (view, view->search_start); if (mcview_nroff_seq_prev (nroff) != -1) search_start = -(mcview__get_nroff_real_len (view, nroff->index - 1, 2) + nroff->char_width + 1); else search_start = -2; mcview_nroff_seq_free (&nroff); } else { search_start = mcview__get_nroff_real_len (view, view->search_start + 1, 2); } search_start += view->search_start; } } if (mcview_search_options.backwards && (int) search_start < 0) search_start = 0; /* Compute the percent steps */ mcview_search_update_steps (view); view->update_activate = search_start; vsm.first = TRUE; vsm.view = view; vsm.offset = search_start; status_msg_init (STATUS_MSG (&vsm), _("Search"), 1.0, simple_status_msg_init_cb, mcview_search_status_update_cb, NULL); do { off_t growbufsize; if (view->growbuf_in_use) growbufsize = mcview_growbuf_filesize (view); else growbufsize = view->search->original_len; if (mcview_find (&vsm, search_start, mcview_get_filesize (view), &match_len)) { mcview_search_show_result (view, match_len); need_search_again = FALSE; isFound = TRUE; break; } if (view->search->error_str == NULL) break; search_start = growbufsize - view->search->original_len; if (search_start <= 0) { search_start = 0; break; } } while (mcview_may_still_grow (view)); status_msg_deinit (STATUS_MSG (&vsm)); if (view->search_start != 0 && !isFound && need_search_again && !mcview_search_options.backwards) { int result; mcview_update (view); result = query_dialog (_("Search done"), _("Continue from beginning?"), D_NORMAL, 2, _("&Yes"), _("&No")); if (result != 0) isFound = TRUE; else search_start = 0; } if (!isFound && view->search->error_str != NULL) { /* continue search form beginning */ off_t search_end; search_end = view->search_start; /* search_start is 0 here */ view->update_activate = search_start; vsm.first = TRUE; vsm.view = view; vsm.offset = search_start; status_msg_init (STATUS_MSG (&vsm), _("Search"), 1.0, simple_status_msg_init_cb, mcview_search_status_update_cb, NULL); if (mcview_find (&vsm, search_start, search_end, &match_len)) { mcview_search_show_result (view, match_len); isFound = TRUE; } status_msg_deinit (STATUS_MSG (&vsm)); } if (!isFound && view->search->error_str != NULL) query_dialog (_("Search"), view->search->error_str, D_NORMAL, 1, _("&Dismiss")); view->dirty++; }
void mcview_ccache_dump (mcview_t * view) { FILE *f; off_t offset, line, column, nextline_offset, filesize; guint i; const coord_cache_t *cache = view->coord_cache; #ifdef HAVE_ASSERT_H assert (cache != NULL); #endif filesize = mcview_get_filesize (view); f = fopen ("mcview-ccache.out", "w"); if (f == NULL) return; (void) setvbuf (f, NULL, _IONBF, 0); /* cache entries */ for (i = 0; i < cache->size; i++) { (void) fprintf (f, "entry %8u offset %8" PRIuMAX " line %8" PRIuMAX " column %8" PRIuMAX " nroff_column %8" PRIuMAX "\n", (unsigned int) i, (uintmax_t) cache->cache[i]->cc_offset, (uintmax_t) cache->cache[i]->cc_line, (uintmax_t) cache->cache[i]->cc_column, (uintmax_t) cache->cache[i]->cc_nroff_column); } (void) fprintf (f, "\n"); /* offset -> line/column translation */ for (offset = 0; offset < filesize; offset++) { mcview_offset_to_coord (view, &line, &column, offset); (void) fprintf (f, "offset %8" PRIuMAX " line %8" PRIuMAX " column %8" PRIuMAX "\n", (uintmax_t) offset, (uintmax_t) line, (uintmax_t) column); } /* line/column -> offset translation */ for (line = 0; TRUE; line++) { mcview_coord_to_offset (view, &nextline_offset, line + 1, 0); (void) fprintf (f, "nextline_offset %8" PRIuMAX "\n", (uintmax_t) nextline_offset); for (column = 0; TRUE; column++) { mcview_coord_to_offset (view, &offset, line, column); if (offset >= nextline_offset) break; (void) fprintf (f, "line %8" PRIuMAX " column %8" PRIuMAX " offset %8" PRIuMAX "\n", (uintmax_t) line, (uintmax_t) column, (uintmax_t) offset); } if (nextline_offset >= filesize - 1) break; } (void) fclose (f); }
void mcview_do_search (WView * view, off_t want_search_start) { mcview_search_status_msg_t vsm; off_t search_start = 0; off_t orig_search_start = view->search_start; gboolean found = FALSE; size_t match_len; view->search_start = want_search_start; /* for avoid infinite search loop we need to increase or decrease start offset of search */ if (view->search_start != 0) { if (!view->text_nroff_mode) search_start = view->search_start + (mcview_search_options.backwards ? -2 : 0); else { if (mcview_search_options.backwards) { mcview_nroff_t *nroff; nroff = mcview_nroff_seq_new_num (view, view->search_start); if (mcview_nroff_seq_prev (nroff) != -1) search_start = -(mcview__get_nroff_real_len (view, nroff->index - 1, 2) + nroff->char_length + 1); else search_start = -2; mcview_nroff_seq_free (&nroff); } else { search_start = mcview__get_nroff_real_len (view, view->search_start + 1, 2); } search_start += view->search_start; } } if (mcview_search_options.backwards && search_start < 0) search_start = 0; /* Compute the percent steps */ mcview_search_update_steps (view); view->update_activate = search_start; vsm.first = TRUE; vsm.view = view; vsm.offset = search_start; status_msg_init (STATUS_MSG (&vsm), _("Search"), 1.0, simple_status_msg_init_cb, mcview_search_status_update_cb, NULL); do { off_t growbufsize; if (view->growbuf_in_use) growbufsize = mcview_growbuf_filesize (view); else growbufsize = view->search->original_len; if (mcview_find (&vsm, search_start, mcview_get_filesize (view), &match_len)) { mcview_search_show_result (view, match_len); found = TRUE; break; } if (view->search->error == MC_SEARCH_E_ABORT || view->search->error == MC_SEARCH_E_NOTFOUND) break; search_start = growbufsize - view->search->original_len; } while (search_start > 0 && mcview_may_still_grow (view)); status_msg_deinit (STATUS_MSG (&vsm)); if (orig_search_start != 0 && (!found && view->search->error == MC_SEARCH_E_NOTFOUND) && !mcview_search_options.backwards) { view->search_start = orig_search_start; mcview_update (view); if (query_dialog (_("Search done"), _("Continue from beginning?"), D_NORMAL, 2, _("&Yes"), _("&No")) != 0) found = TRUE; else { /* continue search from beginning */ view->update_activate = 0; vsm.first = TRUE; vsm.view = view; vsm.offset = 0; status_msg_init (STATUS_MSG (&vsm), _("Search"), 1.0, simple_status_msg_init_cb, mcview_search_status_update_cb, NULL); /* search from file begin up to initial search start position */ if (mcview_find (&vsm, 0, orig_search_start, &match_len)) { mcview_search_show_result (view, match_len); found = TRUE; } status_msg_deinit (STATUS_MSG (&vsm)); } } if (!found) { view->search_start = orig_search_start; mcview_update (view); if (view->search->error == MC_SEARCH_E_NOTFOUND) query_dialog (_("Search"), _(STR_E_NOTFOUND), D_NORMAL, 1, _("&Dismiss")); else if (view->search->error_str != NULL) query_dialog (_("Search"), view->search->error_str, D_NORMAL, 1, _("&Dismiss")); } view->dirty++; }
void mcview_move_down (mcview_t * view, off_t lines) { off_t last_byte; last_byte = mcview_get_filesize (view); if (view->hex_mode) { off_t i, limit; if (last_byte >= (off_t) view->bytes_per_line) limit = last_byte - view->bytes_per_line; else limit = 0; for (i = 0; i < lines && view->hex_cursor < limit; i++) { view->hex_cursor += view->bytes_per_line; if (lines != 1) view->dpy_start += view->bytes_per_line; } } else { off_t new_offset = 0; if (view->dpy_end - view->dpy_start > last_byte - view->dpy_end) { while (lines-- > 0) { if (view->text_wrap_mode) view->dpy_end = mcview_eol (view, view->dpy_end, view->dpy_end + (off_t) view->data_area.width); else view->dpy_end = mcview_eol (view, view->dpy_end, last_byte); if (view->text_wrap_mode) new_offset = mcview_eol (view, view->dpy_start, view->dpy_start + (off_t) view->data_area.width); else new_offset = mcview_eol (view, view->dpy_start, last_byte); if (new_offset < last_byte) view->dpy_start = new_offset; if (view->dpy_end >= last_byte) break; } } else { off_t i; for (i = 0; i < lines && new_offset < last_byte; i++) { if (view->text_wrap_mode) new_offset = mcview_eol (view, view->dpy_start, view->dpy_start + (off_t) view->data_area.width); else new_offset = mcview_eol (view, view->dpy_start, last_byte); if (new_offset < last_byte) view->dpy_start = new_offset; } } } mcview_movement_fixups (view, TRUE); }
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; }
/** * Parse, format and possibly display one visual line of text. * * Formatting starts at the given "state" (which encodes the file offset and parser and formatter's * internal state). In unwrap mode, this should point to the beginning of the paragraph with the * default state, the additional horizontal scrolling is added here. In wrap mode, this should * point to the beginning of the line, with the proper state at that point. * * In wrap mode, if a line ends in a newline, it is consumed, even if it's exactly at the right * edge. In unwrap mode, the whole remaining line, including the newline is consumed. Displaying * the next line should start at "state"'s new value, or if we displayed the bottom line then * state->offset tells the file offset to be shown in the top bar. * * If "row" is offscreen, don't actually display the line but still update "state" and return the * proper value. This is used by mcview_wrap_move_down to advance in the file. * * @param view ... * @param state the parser-formatter state machine's state, updated * @param row print to this row * @param paragraph_ended store TRUE if paragraph ended by newline or EOF, FALSE if wraps to next * line * @param linewidth store the width of the line here * @return the number of rows, that is, 0 if we were already at EOF, otherwise 1 */ static int mcview_display_line (WView * view, mcview_state_machine_t * state, int row, gboolean * paragraph_ended, off_t * linewidth) { const screen_dimen left = view->data_area.left; const screen_dimen top = view->data_area.top; const screen_dimen width = view->data_area.width; const screen_dimen height = view->data_area.height; off_t dpy_text_column = view->text_wrap_mode ? 0 : view->dpy_text_column; screen_dimen col = 0; int cs[1 + MAX_COMBINING_CHARS]; char str[(1 + MAX_COMBINING_CHARS) * UTF8_CHAR_LEN + 1]; int i, j; if (paragraph_ended != NULL) *paragraph_ended = TRUE; if (!view->text_wrap_mode && (row < 0 || row >= (int) height) && linewidth == NULL) { /* Optimization: Fast forward to the end of the line, rather than carefully * parsing and then not actually displaying it. */ off_t eol; int retval; eol = mcview_eol (view, state->offset, mcview_get_filesize (view)); retval = (eol > state->offset) ? 1 : 0; mcview_state_machine_init (state, eol); return retval; } while (TRUE) { int charwidth = 0; mcview_state_machine_t state_saved; int n; int color; state_saved = *state; n = mcview_next_combining_char_sequence (view, state, cs, 1 + MAX_COMBINING_CHARS, &color); if (n == 0) { if (linewidth != NULL) *linewidth = col; return (col > 0) ? 1 : 0; } if (view->search_start <= state->offset && state->offset < view->search_end) color = VIEW_SELECTED_COLOR; if (cs[0] == '\n') { /* New line: reset all formatting state for the next paragraph. */ mcview_state_machine_init (state, state->offset); if (linewidth != NULL) *linewidth = col; return 1; } if (mcview_is_non_spacing_mark (view, cs[0])) { /* Lonely combining character. Probably leftover after too many combining chars. Just ignore. */ continue; } /* Nonprintable, or lonely spacing mark */ if ((!mcview_isprint (view, cs[0]) || mcview_ismark (view, cs[0])) && cs[0] != '\t') cs[0] = '.'; for (i = 0; i < n; i++) charwidth += mcview_wcwidth (view, cs[i]); /* Adjust the width for TAB. It's handled below along with the normal characters, * so that it's wrapped consistently with them, and is painted with the proper * attributes (although currently it can't have a special color). */ if (cs[0] == '\t') { charwidth = option_tab_spacing - state->unwrapped_column % option_tab_spacing; state->print_lonely_combining = TRUE; } else state->print_lonely_combining = FALSE; /* In wrap mode only: We're done with this row if the character sequence wouldn't fit. * Except if at the first column, because then it wouldn't fit in the next row either. * In this extreme case let the unwrapped code below do its best to display it. */ if (view->text_wrap_mode && (off_t) col + charwidth > dpy_text_column + (off_t) width && col > 0) { *state = state_saved; if (paragraph_ended != NULL) *paragraph_ended = FALSE; if (linewidth != NULL) *linewidth = col; return 1; } /* Display, unless outside of the viewport. */ if (row >= 0 && row < (int) height) { if ((off_t) col >= dpy_text_column && (off_t) col + charwidth <= dpy_text_column + (off_t) width) { /* The combining character sequence fits entirely in the viewport. Print it. */ tty_setcolor (color); widget_move (view, top + row, left + ((off_t) col - dpy_text_column)); if (cs[0] == '\t') { for (i = 0; i < charwidth; i++) tty_print_char (' '); } else { j = 0; for (i = 0; i < n; i++) j += mcview_char_display (view, cs[i], str + j); str[j] = '\0'; /* This is probably a bug in our tty layer, but tty_print_string * normalizes the string, whereas tty_printf doesn't. Don't normalize, * since we handle combining characters ourselves correctly, it's * better if they are copy-pasted correctly. Ticket 3255. */ tty_printf ("%s", str); } } else if ((off_t) col < dpy_text_column && (off_t) col + charwidth > dpy_text_column) { /* The combining character sequence would cross the left edge of the viewport. * This cannot happen with wrap mode. Print replacement character(s), * or spaces with the correct attributes for partial Tabs. */ tty_setcolor (color); for (i = dpy_text_column; i < (off_t) col + charwidth && i < dpy_text_column + (off_t) width; i++) { widget_move (view, top + row, left + (i - dpy_text_column)); tty_print_anychar ((cs[0] == '\t') ? ' ' : PARTIAL_CJK_AT_LEFT_MARGIN); } } else if ((off_t) col < dpy_text_column + (off_t) width && (off_t) col + charwidth > dpy_text_column + (off_t) width) { /* The combining character sequence would cross the right edge of the viewport * and we're not wrapping. Print replacement character(s), * or spaces with the correct attributes for partial Tabs. */ tty_setcolor (color); for (i = col; i < dpy_text_column + (off_t) width; i++) { widget_move (view, top + row, left + (i - dpy_text_column)); tty_print_anychar ((cs[0] == '\t') ? ' ' : PARTIAL_CJK_AT_RIGHT_MARGIN); } } } col += charwidth; state->unwrapped_column += charwidth; if (!view->text_wrap_mode && (off_t) col >= dpy_text_column + (off_t) width && linewidth == NULL) { /* Optimization: Fast forward to the end of the line, rather than carefully * parsing and then not actually displaying it. */ off_t eol; eol = mcview_eol (view, state->offset, mcview_get_filesize (view)); mcview_state_machine_init (state, eol); return 1; } } }
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; }