/* Expands view macros to be displayed on the status line according to the * format string. Returns expanded line and attribute line, the latter one * contains a character in the set [0-9 ] (space included) per utf-8 character * of the former that specifies which user highlight group should be used * starting with that character. */ TSTATIC LineWithAttrs expand_status_line_macros(view_t *view, const char format[]) { const dir_entry_t *const curr = get_current_entry(view); if(curr == NULL || fentry_is_fake(curr)) { /* Fake entries don't have valid information. */ LineWithAttrs result = { .line = strdup(""), .attrs = strdup("") }; return result; } return parse_view_macros(view, &format, "nrtTfaAugsEdD-xlLSz%[]{*", 0); //mod by sim1 }
void enter_file_info_mode(FileView *v) { if(fentry_is_fake(get_current_entry(v))) { show_error_msg("File info", "Entry doesn't correspond to a file."); return; } vle_mode_set(FILE_INFO_MODE, VMT_PRIMARY); view = v; setup_menu(); redraw_file_info_dialog(); was_redraw = 0; }
int compare_move(FileView *from, FileView *to) { char from_path[PATH_MAX], to_path[PATH_MAX]; char *from_fingerprint, *to_fingerprint; const CompareType ct = from->custom.diff_cmp_type; dir_entry_t *const curr = &from->dir_entry[from->list_pos]; dir_entry_t *const other = &to->dir_entry[from->list_pos]; if(from->custom.type != CV_DIFF || !from->custom.diff_path_group) { status_bar_error("Not in diff mode with path grouping"); return 1; } if(curr->id == other->id && !fentry_is_fake(curr) && !fentry_is_fake(other)) { /* Nothing to do if files are already equal. */ return 0; } /* We're going at least to try to update one of views (which might refer to * the same directory), so schedule a reload. */ ui_view_schedule_reload(from); ui_view_schedule_reload(to); if(fentry_is_fake(curr)) { /* Just remove the other file (it can't be fake entry too). */ return fops_delete_current(to, 1, 0); } get_full_path_of(curr, sizeof(from_path), from_path); get_full_path_of(other, sizeof(to_path), to_path); if(fentry_is_fake(other)) { char to_path[PATH_MAX]; char canonical[PATH_MAX]; snprintf(to_path, sizeof(to_path), "%s/%s/%s", flist_get_dir(to), curr->origin + strlen(flist_get_dir(from)), curr->name); canonicalize_path(to_path, canonical, sizeof(canonical)); /* Copy current file to position of the other one using relative path with * different base. */ fops_replace(from, canonical, 0); /* Update the other entry to not be fake. */ remove_last_path_component(canonical); replace_string(&other->name, curr->name); replace_string(&other->origin, canonical); } else { /* Overwrite file in the other pane with corresponding file from current * pane. */ fops_replace(from, to_path, 1); } /* Obtaining file fingerprint relies on size field of entries, so try to load * it and ignore if it fails. */ other->size = get_file_size(to_path); /* Try to update id of the other entry by computing fingerprint of both files * and checking if they match. */ from_fingerprint = get_file_fingerprint(from_path, curr, ct); to_fingerprint = get_file_fingerprint(to_path, other, ct); if(!is_null_or_empty(from_fingerprint) && !is_null_or_empty(to_fingerprint)) { int match = (strcmp(from_fingerprint, to_fingerprint) == 0); if(match && ct == CT_CONTENTS) { match = files_are_identical(from_path, to_path); } if(match) { other->id = curr->id; } } free(from_fingerprint); free(to_fingerprint); return 0; }
/* Expands macros in the *format string advancing the pointer as it goes. The * opt represents conditional expression state, should be zero for non-recursive * calls. Returns newly allocated string, which should be freed by the * caller. */ static LineWithAttrs parse_view_macros(view_t *view, const char **format, const char macros[], int opt) { const dir_entry_t *const curr = get_current_entry(view); LineWithAttrs result = { .line = strdup(""), .attrs = strdup("") }; char c; int nexpansions = 0; int has_expander = 0; if(curr == NULL) { return result; } while((c = **format) != '\0') { size_t width = 0; int left_align = 0; char buf[PATH_MAX + 1]; const char *const next = ++*format; int skip, ok; if(c != '%' || (!char_is_one_of(macros, *next) && !isdigit(*next) && (*next != '=' || has_expander))) { if(strappendch(&result.line, &result.line_len, c) != 0) { break; } continue; } if(*next == '=') { (void)sync_attrs(&result, 0); if(strappend(&result.line, &result.line_len, "%=") != 0 || strappendch(&result.attrs, &result.attrs_len, '=') != 0) { break; } ++*format; has_expander = 1; continue; } if(*next == '-') { left_align = 1; ++*format; } while(isdigit(**format)) { width = width*10 + *(*format)++ - '0'; } c = *(*format)++; skip = 0; ok = 1; buf[0] = '\0'; switch(c) { case 'a': friendly_size_notation(get_free_space(curr_view->curr_dir), sizeof(buf), buf); break; case 't': format_entry_name(curr, NF_FULL, sizeof(buf), buf); break; case 'T': if(curr->type == FT_LINK) { char full_path[PATH_MAX + 1]; char link_path[PATH_MAX + 1]; //add by sim1 get_full_path_of(curr, sizeof(full_path), full_path); //mod by sim1 <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< if(get_link_target(full_path, link_path, sizeof(link_path)) != 0) { copy_str(buf, sizeof(buf), "Failed to resolve link"); } else { snprintf(buf, sizeof(buf), " -> %s", link_path); } //mod by sim1 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> } break; case 'f': get_short_path_of(view, curr, NF_FULL, 0, sizeof(buf), buf); break; case 'A': #ifndef _WIN32 get_perm_string(buf, sizeof(buf), curr->mode); #else copy_str(buf, sizeof(buf), attr_str_long(curr->attrs)); #endif break; case 'u': get_uid_string(curr, 0, sizeof(buf), buf); break; case 'g': get_gid_string(curr, 0, sizeof(buf), buf); break; case 's': friendly_size_notation(fentry_get_size(view, curr), sizeof(buf), buf); break; //add by sim1 ************************************************ case 'r': { char path[PATH_MAX] = {0}; get_full_path_at(view, view->list_pos, sizeof(path), path); (void)get_rating_string(buf, sizeof(buf), path); } break; case 'n': { int nitems = !fentry_is_dir(curr) ? 0 : (int)fentry_get_nitems(view, curr); snprintf(buf, sizeof(buf), "%d", nitems); } break; //add by sim1 ************************************************ case 'E': { uint64_t size = 0U; typedef int (*iter_f)(view_t *view, dir_entry_t **entry); /* No current element for visual mode, since it can contain truly * empty selection when cursor is on ../ directory. */ iter_f iter = vle_mode_is(VISUAL_MODE) ? &iter_selected_entries : &iter_selection_or_current; dir_entry_t *entry = NULL; while(iter(view, &entry)) { size += fentry_get_size(view, entry); } friendly_size_notation(size, sizeof(buf), buf); } break; case 'd': { struct tm *tm_ptr = localtime(&curr->mtime); strftime(buf, sizeof(buf), cfg.time_format, tm_ptr); } break; case '-': case 'x': skip = expand_num(buf, sizeof(buf), view->filtered); break; case 'l': skip = expand_num(buf, sizeof(buf), view->list_pos + 1); break; case 'L': skip = expand_num(buf, sizeof(buf), view->list_rows + view->filtered); break; case 'S': skip = expand_num(buf, sizeof(buf), view->list_rows); break; case '%': copy_str(buf, sizeof(buf), "%"); break; case 'z': copy_str(buf, sizeof(buf), get_tip()); break; case 'D': if(curr_stats.number_of_windows == 1) { view_t *const other = (view == curr_view) ? other_view : curr_view; //mod by sim1 //copy_str(buf, sizeof(buf), replace_home_part(other->curr_dir)); snprintf(buf, sizeof(buf), " ‖ %s", replace_home_part(other->curr_dir)); } break; case '[': { LineWithAttrs opt = parse_view_macros(view, format, macros, 1); copy_str(buf, sizeof(buf), opt.line); free(opt.line); char *attrs = opt.attrs; if(sync_attrs(&result, 0) && opt.attrs_len > 0U) { if(*attrs != ' ') { result.attrs[result.attrs_len - 1U] = *attrs; } ++attrs; } strappend(&result.attrs, &result.attrs_len, attrs); free(opt.attrs); break; } case ']': if(opt) { if(nexpansions == 0) { replace_string(&result.line, ""); replace_string(&result.attrs, ""); result.line_len = 0U; result.attrs_len = 0U; } if(sync_attrs(&result, 0)) { result.attrs[--result.attrs_len] = '\0'; } return result; } LOG_INFO_MSG("Unmatched %%]"); ok = 0; break; case '{': { /* Try to find matching closing bracket * TODO: implement the way to escape it, so that the expr may contain * closing brackets */ const char *e = strchr(*format, '}'); char *expr = NULL, *resstr = NULL; var_t res = var_false(); ParsingErrors parsing_error; /* If there's no matching closing bracket, just add the opening one * literally */ if(e == NULL) { ok = 0; break; } /* Create a NULL-terminated copy of the given expr. * TODO: we could temporarily use buf for that, to avoid extra * allocation, but explicitly named variable reads better. */ expr = calloc(e - (*format) + 1 /* NUL-term */, 1); memcpy(expr, *format, e - (*format)); /* Try to parse expr, and convert the res to string if succeed. */ parsing_error = parse(expr, 0, &res); if(parsing_error == PE_NO_ERROR) { resstr = var_to_str(res); } if(resstr != NULL) { copy_str(buf, sizeof(buf), resstr); } else { copy_str(buf, sizeof(buf), "<Invalid expr>"); } var_free(res); free(resstr); free(expr); *format = e + 1 /* closing bracket */; } break; case '*': if(width > 9) { snprintf(buf, sizeof(buf), "%%%d*", (int)width); width = 0; break; } (void)sync_attrs(&result, 1); result.attrs[result.attrs_len - 1] = '0' + width; width = 0; break; default: LOG_INFO_MSG("Unexpected %%-sequence: %%%c", c); ok = 0; break; } if(char_is_one_of("tTAugsEd", c) && fentry_is_fake(curr)) { buf[0] = '\0'; } if(!ok) { *format = next; if(strappendch(&result.line, &result.line_len, '%') != 0) { break; } continue; } check_expanded_str(buf, skip, &nexpansions); stralign(buf, width, ' ', left_align); if(strappend(&result.line, &result.line_len, buf) != 0) { break; } } /* Unmatched %[. */ if(opt) { (void)strprepend(&result.line, &result.line_len, "%["); } if(sync_attrs(&result, 0)) { result.attrs[--result.attrs_len] = '\0'; } return result; } /* Makes sure that result->attrs has at least as many elements as result->line * contains characters + extra_width. Returns non-zero if result->attrs has * extra characters compared to result->line. */ static int sync_attrs(LineWithAttrs *result, int extra_width) { const size_t nchars = utf8_strsw(result->line) + extra_width; if(result->attrs_len < nchars) { char *const new_attrs = format_str("%s%*s", result->attrs, (int)(nchars - result->attrs_len), ""); free(result->attrs); result->attrs = new_attrs; result->attrs_len = nchars; } return (result->attrs_len > nchars); } /* Prints number into the buffer. Returns non-zero if numeric value is * "empty" (zero). */ static int expand_num(char buf[], size_t buf_len, int val) { snprintf(buf, buf_len, "%d", val); return (val == 0); }
/* Formats status line in the "old way" (before introduction of 'statusline' * option). */ static void update_stat_window_old(view_t *view, int lazy_redraw) { const dir_entry_t *const curr = get_current_entry(view); char name_buf[160*2 + 1]; char perm_buf[26]; char size_buf[64]; char id_buf[52]; int x; int cur_x; size_t print_width; char *filename; if(curr == NULL || fentry_is_fake(curr)) { werase(stat_win); refresh_window(stat_win, lazy_redraw); return; } x = getmaxx(stdscr); wresize(stat_win, 1, x); ui_set_bg(stat_win, &cfg.cs.color[STATUS_LINE_COLOR], cfg.cs.pair[STATUS_LINE_COLOR]); filename = get_current_file_name(view); print_width = utf8_strsnlen(filename, 20 + MAX(0, x - 83)); copy_str(name_buf, MIN(sizeof(name_buf), print_width + 1), filename); friendly_size_notation(fentry_get_size(view, curr), sizeof(size_buf), size_buf); get_uid_string(curr, 0, sizeof(id_buf), id_buf); if(id_buf[0] != '\0') strcat(id_buf, ":"); get_gid_string(curr, 0, sizeof(id_buf) - strlen(id_buf), id_buf + strlen(id_buf)); #ifndef _WIN32 get_perm_string(perm_buf, sizeof(perm_buf), curr->mode); #else copy_str(perm_buf, sizeof(perm_buf), attr_str_long(curr->attrs)); #endif werase(stat_win); cur_x = 2; checked_wmove(stat_win, 0, cur_x); wprint(stat_win, name_buf); cur_x += 22; if(x > 83) cur_x += x - 83; mvwaddstr(stat_win, 0, cur_x, size_buf); cur_x += 12; mvwaddstr(stat_win, 0, cur_x, perm_buf); cur_x += 11; snprintf(name_buf, sizeof(name_buf), "%d %s filtered", view->filtered, (view->filtered == 1) ? "file" : "files"); if(view->filtered > 0) mvwaddstr(stat_win, 0, x - (strlen(name_buf) + 2), name_buf); if(cur_x + strlen(id_buf) + 1 > x - (strlen(name_buf) + 2)) break_at(id_buf, ':'); if(cur_x + strlen(id_buf) + 1 > x - (strlen(name_buf) + 2)) id_buf[0] = '\0'; mvwaddstr(stat_win, 0, cur_x, id_buf); refresh_window(stat_win, lazy_redraw); }