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; }
static gboolean mcview_nroff_get_char (mcview_nroff_t * nroff, int *ret_val, off_t nroff_index) { int c = 0; #ifdef HAVE_CHARSET if (nroff->view->utf8) { if (!mcview_get_utf (nroff->view, nroff_index, &c, &nroff->char_length)) { /* we need got symbol in any case */ nroff->char_length = 1; if (!mcview_get_byte (nroff->view, nroff_index, &c) || !g_ascii_isprint (c)) return FALSE; } } else #endif { nroff->char_length = 1; if (!mcview_get_byte (nroff->view, nroff_index, &c)) return FALSE; } *ret_val = c; return g_unichar_isprint (c); }
/** * Just for convenience, a common interface in front of mcview_get_utf and mcview_get_byte, so that * the caller doesn't have to care about utf8 vs 8-bit modes. * * Normally: stores c, updates state, returns TRUE. * At EOF: state is unchanged, c is undefined, returns FALSE. * * Also, temporary hack: handle force_max here. * TODO: move it to lower layers (datasource.c)? */ static gboolean mcview_get_next_char (WView * view, mcview_state_machine_t * state, int *c) { /* Pretend EOF if we reached force_max */ if (view->force_max >= 0 && state->offset >= view->force_max) return FALSE; #ifdef HAVE_CHARSET if (view->utf8) { gboolean result; int char_length; *c = mcview_get_utf (view, state->offset, &char_length, &result); if (!result) return FALSE; /* Pretend EOF if we crossed force_max */ if (view->force_max >= 0 && state->offset + char_length > view->force_max) return FALSE; state->offset += char_length; return TRUE; } #endif /* HAVE_CHARSET */ if (!mcview_get_byte (view, state->offset, c)) return FALSE; state->offset++; return TRUE; }
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; }
gboolean mcview_load_command_output (WView * view, const char *command) { mc_pipe_t *p; GError *error = NULL; mcview_close_datasource (view); p = mc_popen (command, &error); if (p == NULL) { mcview_display (view); mcview_show_error (view, error->message); g_error_free (error); return FALSE; } /* Check if filter produced any output */ mcview_set_datasource_stdio_pipe (view, p); if (!mcview_get_byte (view, 0, NULL)) { mcview_close_datasource (view); mcview_display (view); return FALSE; } return TRUE; }
static cb_ret_t mcview_handle_editkey (mcview_t * view, int key) { struct hexedit_change_node *node; int byte_val; /* Has there been a change at this position? */ node = view->change_list; while ((node != NULL) && (node->offset != view->hex_cursor)) node = node->next; if (!view->hexview_in_text) { /* Hex editing */ unsigned int hexvalue = 0; if (key >= '0' && key <= '9') hexvalue = 0 + (key - '0'); else if (key >= 'A' && key <= 'F') hexvalue = 10 + (key - 'A'); else if (key >= 'a' && key <= 'f') hexvalue = 10 + (key - 'a'); else return MSG_NOT_HANDLED; if (node != NULL) byte_val = node->value; else mcview_get_byte (view, view->hex_cursor, &byte_val); if (view->hexedit_lownibble) byte_val = (byte_val & 0xf0) | (hexvalue); else byte_val = (byte_val & 0x0f) | (hexvalue << 4); } else { /* Text editing */ if (key < 256 && key != '\t') byte_val = key; else return MSG_NOT_HANDLED; } if ((view->filename_vpath != NULL) && (*(vfs_path_get_last_path_str (view->filename_vpath)) != '\0') && (view->change_list == NULL)) view->locked = lock_file (view->filename_vpath); if (node == NULL) { node = g_new (struct hexedit_change_node, 1); node->offset = view->hex_cursor; node->value = byte_val; mcview_enqueue_change (&view->change_list, node); }
int mcview_search_cmd_callback (const void *user_data, gsize char_offset) { int lc_byte; mcview_t *view = (mcview_t *) user_data; /* view_read_continue (view, &view->search_onechar_info); *//* AB:FIXME */ if (!view->text_nroff_mode) { if (!mcview_get_byte (view, char_offset, &lc_byte)) return MC_SEARCH_CB_OK; return lc_byte; } if (view->search_numNeedSkipChar != 0) { view->search_numNeedSkipChar--; return MC_SEARCH_CB_SKIP; } if (search_cb_char_curr_index == -1 || search_cb_char_curr_index >= view->search_nroff_seq->char_width) { if (search_cb_char_curr_index != -1) mcview_nroff_seq_next (view->search_nroff_seq); search_cb_char_curr_index = 0; if (view->search_nroff_seq->char_width > 1) g_unichar_to_utf8 (view->search_nroff_seq->current_char, search_cb_char_buffer); else search_cb_char_buffer[0] = (char) view->search_nroff_seq->current_char; if (view->search_nroff_seq->type != NROFF_TYPE_NONE) { switch (view->search_nroff_seq->type) { case NROFF_TYPE_BOLD: view->search_numNeedSkipChar = 1 + view->search_nroff_seq->char_width; /* real char width and 0x8 */ break; case NROFF_TYPE_UNDERLINE: view->search_numNeedSkipChar = 2; /* underline symbol and ox8 */ break; default: break; } } return MC_SEARCH_CB_INVALID; } lc_byte = search_cb_char_buffer[search_cb_char_curr_index]; search_cb_char_curr_index++; return (lc_byte != -1) ? (unsigned char) lc_byte : MC_SEARCH_CB_INVALID; }
mc_search_cbret_t mcview_search_cmd_callback (const void *user_data, gsize char_offset, int *current_char) { WView *view = ((const mcview_search_status_msg_t *) user_data)->view; /* view_read_continue (view, &view->search_onechar_info); *//* AB:FIXME */ if (!view->text_nroff_mode) { mcview_get_byte (view, char_offset, current_char); return MC_SEARCH_CB_OK; } if (view->search_numNeedSkipChar != 0) { view->search_numNeedSkipChar--; return MC_SEARCH_CB_SKIP; } if (search_cb_char_curr_index == -1 || search_cb_char_curr_index >= view->search_nroff_seq->char_length) { if (search_cb_char_curr_index != -1) mcview_nroff_seq_next (view->search_nroff_seq); search_cb_char_curr_index = 0; if (view->search_nroff_seq->char_length > 1) g_unichar_to_utf8 (view->search_nroff_seq->current_char, search_cb_char_buffer); else search_cb_char_buffer[0] = (char) view->search_nroff_seq->current_char; if (view->search_nroff_seq->type != NROFF_TYPE_NONE) { switch (view->search_nroff_seq->type) { case NROFF_TYPE_BOLD: view->search_numNeedSkipChar = 1 + view->search_nroff_seq->char_length; /* real char length and 0x8 */ break; case NROFF_TYPE_UNDERLINE: view->search_numNeedSkipChar = 2; /* underline symbol and ox8 */ break; default: break; } } return MC_SEARCH_CB_INVALID; } *current_char = search_cb_char_buffer[search_cb_char_curr_index]; search_cb_char_curr_index++; return (*current_char != -1) ? MC_SEARCH_CB_OK : MC_SEARCH_CB_INVALID; }
int mcview_nroff_seq_prev (mcview_nroff_t * nroff) { int prev; off_t prev_index, prev_index2; if (nroff == NULL) return -1; nroff->prev_type = NROFF_TYPE_NONE; if (nroff->index == 0) return -1; prev_index = nroff->index - 1; while (prev_index != 0) { if (mcview_nroff_get_char (nroff, &nroff->current_char, prev_index)) break; prev_index--; } if (prev_index == 0) { nroff->index--; mcview_nroff_seq_info (nroff); return nroff->current_char; } prev_index--; if (!mcview_get_byte (nroff->view, prev_index, &prev) || prev != '\b') { nroff->index = prev_index; mcview_nroff_seq_info (nroff); return nroff->current_char; } prev_index2 = prev_index - 1; while (prev_index2 != 0) { if (mcview_nroff_get_char (nroff, &prev, prev_index)) break; prev_index2--; } nroff->index = (prev_index2 == 0) ? prev_index : prev_index2; mcview_nroff_seq_info (nroff); return nroff->current_char; }
gboolean mcview_load_command_output (mcview_t * view, const char *command) { FILE *fp; mcview_close_datasource (view); open_error_pipe (); fp = popen (command, "r"); if (fp == NULL) { /* Avoid two messages. Message from stderr has priority. */ mcview_display (view); if (!close_error_pipe (mcview_is_in_panel (view) ? -1 : D_ERROR, NULL)) mcview_show_error (view, _("Cannot spawn child process")); return FALSE; } /* First, check if filter produced any output */ mcview_set_datasource_stdio_pipe (view, fp); if (!mcview_get_byte (view, 0, NULL)) { mcview_close_datasource (view); /* Avoid two messages. Message from stderr has priority. */ mcview_display (view); if (!close_error_pipe (mcview_is_in_panel (view) ? -1 : D_ERROR, NULL)) mcview_show_error (view, _("Empty output from child filter")); return FALSE; } else { /* * At least something was read correctly. Close stderr and let * program die if it will try to write something there. * * Ideally stderr should be read asynchronously to prevent programs * from blocking (poll/select multiplexor). */ close_error_pipe (D_NORMAL, NULL); } return TRUE; }
nroff_type_t mcview_nroff_seq_info (mcview_nroff_t * nroff) { int next, next2; if (nroff == NULL) return NROFF_TYPE_NONE; nroff->type = NROFF_TYPE_NONE; if (!mcview_nroff_get_char (nroff, &nroff->current_char, nroff->index)) return nroff->type; if (!mcview_get_byte (nroff->view, nroff->index + nroff->char_length, &next) || next != '\b') return nroff->type; if (!mcview_nroff_get_char (nroff, &next2, nroff->index + 1 + nroff->char_length)) return nroff->type; if (nroff->current_char == '_' && next2 == '_') { nroff->type = (nroff->prev_type == NROFF_TYPE_BOLD) ? NROFF_TYPE_BOLD : NROFF_TYPE_UNDERLINE; } else if (nroff->current_char == next2) { nroff->type = NROFF_TYPE_BOLD; } else if (nroff->current_char == '_') { nroff->current_char = next2; nroff->type = NROFF_TYPE_UNDERLINE; } else if (nroff->current_char == '+' && next2 == 'o') { /* ??? */ } return nroff->type; }
void mcview_display_hex (mcview_t * view) { const screen_dimen top = view->data_area.top; const screen_dimen left = view->data_area.left; const screen_dimen height = view->data_area.height; const screen_dimen width = view->data_area.width; const int ngroups = view->bytes_per_line / 4; const screen_dimen text_start = 8 + 13 * ngroups + ((width < 80) ? 0 : (ngroups - 1 + 1)); /* 8 characters are used for the file offset, and every hex group * takes 13 characters. On "big" screens, the groups are separated * by an extra vertical line, and there is an extra space before the * text column. */ screen_dimen row; off_t from; int c; mark_t boldflag = MARK_NORMAL; struct hexedit_change_node *curr = view->change_list; #ifdef HAVE_CHARSET int ch = 0; #endif /* HAVE_CHARSET */ char hex_buff[10]; /* A temporary buffer for sprintf and mvwaddstr */ int bytes; /* Number of bytes already printed on the line */ mcview_display_clean (view); /* Find the first displayable changed byte */ from = view->dpy_start; while (curr && (curr->offset < from)) { curr = curr->next; } for (row = 0; mcview_get_byte (view, from, NULL) == TRUE && row < height; row++) { screen_dimen col = 0; size_t i; col = 0; /* Print the hex offset */ g_snprintf (hex_buff, sizeof (hex_buff), "%08" PRIXMAX " ", (uintmax_t) from); widget_move (view, top + row, left); tty_setcolor (VIEW_BOLD_COLOR); for (i = 0; col < width && hex_buff[i] != '\0'; i++) { tty_print_char (hex_buff[i]); /* tty_print_char(hex_buff[i]); */ col += 1; } tty_setcolor (VIEW_NORMAL_COLOR); for (bytes = 0; bytes < view->bytes_per_line; bytes++, from++) { #ifdef HAVE_CHARSET if (view->utf8) { int cw = 1; gboolean read_res = TRUE; ch = mcview_get_utf (view, from, &cw, &read_res); if (!read_res) break; /* char width is greater 0 bytes */ if (cw != 0) { int cnt; char corr_buf[UTF8_CHAR_LEN + 1]; struct hexedit_change_node *corr = curr; int res; res = g_unichar_to_utf8 (ch, (char *) corr_buf); for (cnt = 0; cnt < cw; cnt++) { if (curr != NULL && from + cnt == curr->offset) { /* replace only changed bytes in array of multibyte char */ corr_buf[cnt] = curr->value; curr = curr->next; } } corr_buf[res] = '\0'; /* Determine the state of the current multibyte char */ ch = utf8_to_int ((char *) corr_buf, &cw, &read_res); curr = corr; } } #endif /* HAVE_CHARSET */ if (!mcview_get_byte (view, from, &c)) break; /* Save the cursor position for mcview_place_cursor() */ if (from == view->hex_cursor && !view->hexview_in_text) { view->cursor_row = row; view->cursor_col = col; } /* Determine the state of the current byte */ boldflag = mcview_hex_calculate_boldflag (view, from, curr); /* Determine the value of the current byte */ if (curr != NULL && from == curr->offset) { c = curr->value; curr = curr->next; } /* Select the color for the hex number */ tty_setcolor (boldflag == MARK_NORMAL ? VIEW_NORMAL_COLOR : boldflag == MARK_SELECTED ? VIEW_BOLD_COLOR : boldflag == MARK_CHANGED ? VIEW_UNDERLINED_COLOR : /* boldflag == MARK_CURSOR */ view->hexview_in_text ? VIEW_SELECTED_COLOR : VIEW_UNDERLINED_COLOR); /* Print the hex number */ widget_move (view, top + row, left + col); if (col < width) { tty_print_char (hex_char[c / 16]); col += 1; } if (col < width) { tty_print_char (hex_char[c % 16]); col += 1; } /* Print the separator */ tty_setcolor (VIEW_NORMAL_COLOR); if (bytes != view->bytes_per_line - 1) { if (col < width) { tty_print_char (' '); col += 1; } /* After every four bytes, print a group separator */ if (bytes % 4 == 3) { if (view->data_area.width >= 80 && col < width) { tty_print_one_vline (TRUE); col += 1; } if (col < width) { tty_print_char (' '); col += 1; } } } /* Select the color for the character; this differs from the * hex color when boldflag == MARK_CURSOR */ tty_setcolor (boldflag == MARK_NORMAL ? VIEW_NORMAL_COLOR : boldflag == MARK_SELECTED ? VIEW_BOLD_COLOR : boldflag == MARK_CHANGED ? VIEW_UNDERLINED_COLOR : /* boldflag == MARK_CURSOR */ view->hexview_in_text ? VIEW_SELECTED_COLOR : MARKED_SELECTED_COLOR); #ifdef HAVE_CHARSET if (mc_global.utf8_display) { if (!view->utf8) { c = convert_from_8bit_to_utf_c ((unsigned char) c, view->converter); } if (!g_unichar_isprint (c)) c = '.'; } else if (view->utf8) ch = convert_from_utf_to_current_c (ch, view->converter); else #endif { #ifdef HAVE_CHARSET c = convert_to_display_c (c); #endif if (!is_printable (c)) c = '.'; } /* Print corresponding character on the text side */ if (text_start + bytes < width) { widget_move (view, top + row, left + text_start + bytes); #ifdef HAVE_CHARSET if (view->utf8) tty_print_anychar (ch); else #endif tty_print_char (c); } /* Save the cursor position for mcview_place_cursor() */ if (from == view->hex_cursor && view->hexview_in_text) { view->cursor_row = row; view->cursor_col = text_start + bytes; } } } /* Be polite to the other functions */ tty_setcolor (VIEW_NORMAL_COLOR); mcview_place_cursor (view); view->dpy_end = from; }
int mcview_get_utf (mcview_t * view, off_t byte_index, int *char_width, gboolean * result) { gchar *str = NULL; int res = -1; gunichar ch; gchar *next_ch = NULL; gchar utf8buf[UTF8_CHAR_LEN + 1]; *char_width = 0; *result = FALSE; switch (view->datasource) { case DS_STDIO_PIPE: case DS_VFS_PIPE: str = mcview_get_ptr_growing_buffer (view, byte_index); break; case DS_FILE: str = mcview_get_ptr_file (view, byte_index); break; case DS_STRING: str = mcview_get_ptr_string (view, byte_index); break; case DS_NONE: break; } if (str == NULL) return 0; res = g_utf8_get_char_validated (str, -1); if (res < 0) { /* Retry with explicit bytes to make sure it's not a buffer boundary */ int i; for (i = 0; i < UTF8_CHAR_LEN; i++) { if (mcview_get_byte (view, byte_index + i, &res)) utf8buf[i] = res; else { utf8buf[i] = '\0'; break; } } utf8buf[UTF8_CHAR_LEN] = '\0'; str = utf8buf; res = g_utf8_get_char_validated (str, -1); } if (res < 0) { ch = *str; *char_width = 1; } else { ch = res; /* Calculate UTF-8 char width */ next_ch = g_utf8_next_char (str); if (next_ch) *char_width = next_ch - str; else return 0; } *result = TRUE; return ch; }
void mcview_display_hex (WView * view) { const screen_dimen top = view->data_area.top; const screen_dimen left = view->data_area.left; const screen_dimen height = view->data_area.height; const screen_dimen width = view->data_area.width; const int ngroups = view->bytes_per_line / 4; /* 8 characters are used for the file offset, and every hex group * takes 13 characters. Starting at width of 80 columns, the groups * are separated by an extra vertical line. Starting at width of 81, * there is an extra space before the text column. There is always a * mostly empty column on the right, to allow overflowing CJKs. */ const screen_dimen text_start = 8 + 13 * ngroups + ((width < 80) ? 0 : (width == 80) ? (ngroups - 1) : (ngroups - 1 + 1)); int row; off_t from; mark_t boldflag_byte = MARK_NORMAL; mark_t boldflag_char = MARK_NORMAL; struct hexedit_change_node *curr = view->change_list; #ifdef HAVE_CHARSET int cont_bytes = 0; /* number of continuation bytes remanining from current UTF-8 */ gboolean cjk_right = FALSE; /* whether the second byte of a CJK is to be processed */ #endif /* HAVE_CHARSET */ gboolean utf8_changed = FALSE; /* whether any of the bytes in the UTF-8 were changed */ char hex_buff[10]; /* A temporary buffer for sprintf and mvwaddstr */ mcview_display_clean (view); /* Find the first displayable changed byte */ /* In UTF-8 mode, go back by 1 or maybe 2 lines to handle continuation bytes properly. */ from = view->dpy_start; row = 0; #ifdef HAVE_CHARSET if (view->utf8) { if (from >= view->bytes_per_line) { row--; from -= view->bytes_per_line; } if (view->bytes_per_line == 4 && from >= view->bytes_per_line) { row--; from -= view->bytes_per_line; } } #endif /* HAVE_CHARSET */ while (curr && (curr->offset < from)) { curr = curr->next; } for (; mcview_get_byte (view, from, NULL) && row < (int) height; row++) { screen_dimen col = 0; size_t i; int bytes; /* Number of bytes already printed on the line */ /* Print the hex offset */ if (row >= 0) { g_snprintf (hex_buff, sizeof (hex_buff), "%08" PRIXMAX " ", (uintmax_t) from); widget_move (view, top + row, left); tty_setcolor (VIEW_BOLD_COLOR); for (i = 0; col < width && hex_buff[i] != '\0'; col++, i++) tty_print_char (hex_buff[i]); tty_setcolor (VIEW_NORMAL_COLOR); } for (bytes = 0; bytes < view->bytes_per_line; bytes++, from++) { int c; #ifdef HAVE_CHARSET int ch = 0; if (view->utf8) { struct hexedit_change_node *corr = curr; if (cont_bytes != 0) { /* UTF-8 continuation bytes, print a space (with proper attributes)... */ cont_bytes--; ch = ' '; if (cjk_right) { /* ... except when it'd wipe out the right half of a CJK, then print nothing */ cjk_right = FALSE; ch = -1; } } else { int j; gchar utf8buf[UTF8_CHAR_LEN + 1]; int res; int first_changed = -1; for (j = 0; j < UTF8_CHAR_LEN; j++) { if (mcview_get_byte (view, from + j, &res)) utf8buf[j] = res; else { utf8buf[j] = '\0'; break; } if (curr != NULL && from + j == curr->offset) { utf8buf[j] = curr->value; if (first_changed == -1) first_changed = j; } if (curr != NULL && from + j >= curr->offset) curr = curr->next; } utf8buf[UTF8_CHAR_LEN] = '\0'; /* Determine the state of the current multibyte char */ ch = g_utf8_get_char_validated (utf8buf, -1); if (ch == -1 || ch == -2) { ch = '.'; } else { gchar *next_ch; next_ch = g_utf8_next_char (utf8buf); cont_bytes = next_ch - utf8buf - 1; if (g_unichar_iswide (ch)) cjk_right = TRUE; } utf8_changed = (first_changed >= 0 && first_changed <= cont_bytes); curr = corr; } } #endif /* HAVE_CHARSET */ /* For negative rows, the only thing we care about is overflowing * UTF-8 continuation bytes which were handled above. */ if (row < 0) { if (curr != NULL && from == curr->offset) curr = curr->next; continue; } if (!mcview_get_byte (view, from, &c)) break; /* Save the cursor position for mcview_place_cursor() */ if (from == view->hex_cursor && !view->hexview_in_text) { view->cursor_row = row; view->cursor_col = col; } /* Determine the state of the current byte */ boldflag_byte = mcview_hex_calculate_boldflag (view, from, curr, FALSE); boldflag_char = mcview_hex_calculate_boldflag (view, from, curr, utf8_changed); /* Determine the value of the current byte */ if (curr != NULL && from == curr->offset) { c = curr->value; curr = curr->next; } /* Select the color for the hex number */ tty_setcolor (boldflag_byte == MARK_NORMAL ? VIEW_NORMAL_COLOR : boldflag_byte == MARK_SELECTED ? VIEW_BOLD_COLOR : boldflag_byte == MARK_CHANGED ? VIEW_UNDERLINED_COLOR : /* boldflag_byte == MARK_CURSOR */ view->hexview_in_text ? VIEW_SELECTED_COLOR : VIEW_UNDERLINED_COLOR); /* Print the hex number */ widget_move (view, top + row, left + col); if (col < width) { tty_print_char (hex_char[c / 16]); col += 1; } if (col < width) { tty_print_char (hex_char[c % 16]); col += 1; } /* Print the separator */ tty_setcolor (VIEW_NORMAL_COLOR); if (bytes != view->bytes_per_line - 1) { if (col < width) { tty_print_char (' '); col += 1; } /* After every four bytes, print a group separator */ if (bytes % 4 == 3) { if (view->data_area.width >= 80 && col < width) { tty_print_one_vline (TRUE); col += 1; } if (col < width) { tty_print_char (' '); col += 1; } } } /* Select the color for the character; this differs from the * hex color when boldflag == MARK_CURSOR */ tty_setcolor (boldflag_char == MARK_NORMAL ? VIEW_NORMAL_COLOR : boldflag_char == MARK_SELECTED ? VIEW_BOLD_COLOR : boldflag_char == MARK_CHANGED ? VIEW_UNDERLINED_COLOR : /* boldflag_char == MARK_CURSOR */ view->hexview_in_text ? VIEW_SELECTED_COLOR : MARKED_SELECTED_COLOR); #ifdef HAVE_CHARSET if (mc_global.utf8_display) { if (!view->utf8) { c = convert_from_8bit_to_utf_c ((unsigned char) c, view->converter); } if (!g_unichar_isprint (c)) c = '.'; } else if (view->utf8) ch = convert_from_utf_to_current_c (ch, view->converter); else #endif { #ifdef HAVE_CHARSET c = convert_to_display_c (c); #endif if (!is_printable (c)) c = '.'; } /* Print corresponding character on the text side */ if (text_start + bytes < width) { widget_move (view, top + row, left + text_start + bytes); #ifdef HAVE_CHARSET if (view->utf8) tty_print_anychar (ch); else #endif tty_print_char (c); } /* Save the cursor position for mcview_place_cursor() */ if (from == view->hex_cursor && view->hexview_in_text) { view->cursor_row = row; view->cursor_col = text_start + bytes; } } } /* Be polite to the other functions */ tty_setcolor (VIEW_NORMAL_COLOR); mcview_place_cursor (view); view->dpy_end = from; }
void mcview_display_text (mcview_t * view) { 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; screen_dimen row = 0, col = 0; off_t from; int cw = 1; int c, prev_ch = 0; gboolean last_row = TRUE; struct hexedit_change_node *curr = view->change_list; mcview_display_clean (view); mcview_display_ruler (view); /* Find the first displayable changed byte */ from = view->dpy_start; while ((curr != NULL) && (curr->offset < from)) curr = curr->next; while (TRUE) { tty_setcolor (NORMAL_COLOR); if (row >= height) break; #ifdef HAVE_CHARSET if (view->utf8) { gboolean read_res = TRUE; c = mcview_get_utf (view, from, &cw, &read_res); if (!read_res) break; } else #endif if (!mcview_get_byte (view, from, &c)) break; last_row = FALSE; from++; if (cw > 1) from += cw - 1; if (c != '\n' && prev_ch == '\r') { if (++row >= height) break; col = 0; /* tty_print_anychar ('\n'); */ } prev_ch = c; if (c == '\r') continue; if (c == '\n') { col = 0; row++; continue; } if (col >= width && view->text_wrap_mode) { col = 0; if (++row >= height) break; } if (c == '\t') { col += (option_tab_spacing - col % option_tab_spacing); if (view->text_wrap_mode && col >= width && width != 0) { row += col / width; col %= width; } continue; } if (view->search_start <= from && from < view->search_end) tty_setcolor (SELECTED_COLOR); if (((off_t) col >= view->dpy_text_column) && ((off_t) col - view->dpy_text_column < (off_t) width)) { widget_move (view, top + row, left + ((off_t) col - view->dpy_text_column)); #ifdef HAVE_CHARSET if (mc_global.utf8_display) { if (!view->utf8) c = convert_from_8bit_to_utf_c ((unsigned char) c, view->converter); if (!g_unichar_isprint (c)) c = '.'; } else if (view->utf8) c = convert_from_utf_to_current_c (c, view->converter); else #endif { #ifdef HAVE_CHARSET c = convert_to_display_c (c); #endif if (!is_printable (c)) c = '.'; } tty_print_anychar (c); } col++; #ifdef HAVE_CHARSET if (view->utf8) { if (g_unichar_iswide (c)) col++; else if (g_unichar_iszerowidth (c)) col--; } #endif } view->dpy_end = from; if (mcview_show_eof != NULL && mcview_show_eof[0] != '\0') { if (last_row && mcview_get_byte (view, from - 1, &c)) if (c != '\n') row--; while (++row < height) { widget_move (view, top + row, left); tty_print_string (mcview_show_eof); } } }
void mcview_display_nroff (mcview_t * view) { 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; screen_dimen row, col; off_t from; int cw = 1; int c; int c_prev = 0; int c_next = 0; struct hexedit_change_node *curr = view->change_list; mcview_display_clean (view); mcview_display_ruler (view); /* Find the first displayable changed byte */ from = view->dpy_start; while (curr && (curr->offset < from)) { curr = curr->next; } tty_setcolor (NORMAL_COLOR); for (row = 0, col = 0; row < height;) { #ifdef HAVE_CHARSET if (view->utf8) { gboolean read_res = TRUE; c = mcview_get_utf (view, from, &cw, &read_res); if (!read_res) break; } else #endif { if (!mcview_get_byte (view, from, &c)) break; } from++; if (cw > 1) from += cw - 1; if (c == '\b') { if (from > 1) { #ifdef HAVE_CHARSET if (view->utf8) { gboolean read_res; c_next = mcview_get_utf (view, from, &cw, &read_res); } else #endif mcview_get_byte (view, from, &c_next); } if (g_unichar_isprint (c_prev) && g_unichar_isprint (c_next) && (c_prev == c_next || c_prev == '_' || (c_prev == '+' && c_next == 'o'))) { if (col == 0) { if (row == 0) { /* We're inside an nroff character sequence at the * beginning of the screen -- just skip the * backspace and continue with the next character. */ continue; } row--; col = width; } col--; if (c_prev == '_' && (c_next != '_' || mcview_count_backspaces (view, from + 1) == 1)) tty_setcolor (VIEW_UNDERLINED_COLOR); else tty_setcolor (VIEW_BOLD_COLOR); continue; } } if ((c == '\n') || (col >= width && view->text_wrap_mode)) { col = 0; row++; if (c == '\n' || row >= height) continue; } if (c == '\r') { mcview_get_byte_indexed (view, from, 1, &c); if (c == '\r' || c == '\n') continue; col = 0; row++; continue; } if (c == '\t') { off_t line, column; mcview_offset_to_coord (view, &line, &column, from); col += (option_tab_spacing - col % option_tab_spacing); if (view->text_wrap_mode && col >= width && width != 0) { row += col / width; col %= width; } continue; } if (view->search_start <= from && from < view->search_end) { tty_setcolor (SELECTED_COLOR); } c_prev = c; if ((off_t) col >= view->dpy_text_column && (off_t) col - view->dpy_text_column < (off_t) width) { widget_move (view, top + row, left + ((off_t) col - view->dpy_text_column)); #ifdef HAVE_CHARSET if (mc_global.utf8_display) { if (!view->utf8) { c = convert_from_8bit_to_utf_c ((unsigned char) c, view->converter); } if (!g_unichar_isprint (c)) c = '.'; } else if (view->utf8) c = convert_from_utf_to_current_c (c, view->converter); else c = convert_to_display_c (c); #endif tty_print_anychar (c); } col++; #ifdef HAVE_CHARSET if (view->utf8) { if (g_unichar_iswide (c)) col++; else if (g_unichar_iszerowidth (c)) col--; } #endif tty_setcolor (NORMAL_COLOR); } view->dpy_end = from; }
void mcview_ccache_lookup (mcview_t * view, coord_cache_entry_t * coord, enum ccache_type lookup_what) { size_t i; coord_cache_t *cache; coord_cache_entry_t current, next, entry; enum ccache_type sorter; off_t limit; cmp_func_t cmp_func; enum { NROFF_START, NROFF_BACKSPACE, NROFF_CONTINUATION } nroff_state; if (view->coord_cache == NULL) view->coord_cache = coord_cache_new (); cache = view->coord_cache; if (cache->size == 0) { current.cc_offset = 0; current.cc_line = 0; current.cc_column = 0; current.cc_nroff_column = 0; mcview_ccache_add_entry (cache, 0, ¤t); } sorter = (lookup_what == CCACHE_OFFSET) ? CCACHE_LINECOL : CCACHE_OFFSET; if (sorter == CCACHE_OFFSET) cmp_func = mcview_coord_cache_entry_less_offset; else if (view->text_nroff_mode) cmp_func = mcview_coord_cache_entry_less_nroff; else cmp_func = mcview_coord_cache_entry_less_plain; tty_enable_interrupt_key (); retry: /* find the two neighbor entries in the cache */ i = mcview_ccache_find (view, coord, cmp_func); /* now i points to the lower neighbor in the cache */ current = *cache->cache[i]; if (i + 1 < view->coord_cache->size) limit = cache->cache[i + 1]->cc_offset; else limit = current.cc_offset + VIEW_COORD_CACHE_GRANUL; entry = current; nroff_state = NROFF_START; for (; current.cc_offset < limit; current = next) { int c, nextc; if (!mcview_get_byte (view, current.cc_offset, &c)) break; if (!cmp_func (¤t, coord)) { if (lookup_what == CCACHE_OFFSET && view->text_nroff_mode && nroff_state != NROFF_START) { /* don't break here */ } else { break; } } /* Provide useful default values for ''next'' */ next.cc_offset = current.cc_offset + 1; next.cc_line = current.cc_line; next.cc_column = current.cc_column + 1; next.cc_nroff_column = current.cc_nroff_column + 1; /* and override some of them as necessary. */ if (c == '\r') { mcview_get_byte_indexed (view, current.cc_offset, 1, &nextc); /* Ignore '\r' if it is followed by '\r' or '\n'. If it is * followed by anything else, it is a Mac line ending and * produces a line break. */ if (nextc == '\r' || nextc == '\n') { next.cc_column = current.cc_column; next.cc_nroff_column = current.cc_nroff_column; } else { next.cc_line = current.cc_line + 1; next.cc_column = 0; next.cc_nroff_column = 0; } } else if (nroff_state == NROFF_BACKSPACE) { next.cc_nroff_column = current.cc_nroff_column - 1; } else if (c == '\t') { next.cc_column = mcview_offset_rounddown (current.cc_column, 8) + 8; next.cc_nroff_column = mcview_offset_rounddown (current.cc_nroff_column, 8) + 8; } else if (c == '\n') { next.cc_line = current.cc_line + 1; next.cc_column = 0; next.cc_nroff_column = 0; } else { /* Use all default values from above */ } switch (nroff_state) { case NROFF_START: case NROFF_CONTINUATION: nroff_state = mcview_is_nroff_sequence (view, current.cc_offset) ? NROFF_BACKSPACE : NROFF_START; break; case NROFF_BACKSPACE: nroff_state = NROFF_CONTINUATION; break; } /* Cache entries must guarantee that for each i < j, * line[i] <= line[j] and column[i] < column[j]. In the case of * nroff sequences and '\r' characters, this is not guaranteed, * so we cannot save them. */ if (nroff_state == NROFF_START && c != '\r') entry = next; } if (i + 1 == cache->size && entry.cc_offset != cache->cache[i]->cc_offset) { mcview_ccache_add_entry (cache, cache->size, &entry); if (!tty_got_interrupt ()) goto retry; } tty_disable_interrupt_key (); if (lookup_what == CCACHE_OFFSET) { coord->cc_offset = current.cc_offset; } else { coord->cc_line = current.cc_line; coord->cc_column = current.cc_column; coord->cc_nroff_column = current.cc_nroff_column; } }