/* Navigates the view to given mark if it's valid. Returns new value for * save_msg flag. */ static int navigate_to_mark(FileView *view, char m) { const mark_t *const mark = get_mark_by_name(m); if(is_mark_valid(mark)) { navigate_to_file(view, mark->directory, mark->file); return 0; } if(!char_is_one_of(valid_marks, m)) { status_bar_message("Invalid mark name"); } else if(is_empty(mark)) { status_bar_message("Mark is not set"); } else { status_bar_message("Mark is invalid"); } fview_cursor_redraw(view); return 1; }
/* Writes marks to vifminfo file. marks is a list of length nmarks marks read * from vifminfo. */ static void write_marks(FILE *const fp, const char non_conflicting_marks[], char *marks[], const int timestamps[], int nmarks) { int active_marks[NUM_MARKS]; const int len = init_active_marks(valid_marks, active_marks); int i; fputs("\n# Marks:\n", fp); for(i = 0; i < len; ++i) { const int index = active_marks[i]; const char m = index2mark(index); if(!is_spec_mark(index) && char_is_one_of(non_conflicting_marks, m)) { const mark_t *const mark = get_mark(index); fprintf(fp, "%c%c\n", LINE_TYPE_MARK, m); fprintf(fp, "\t%s\n", mark->directory); fprintf(fp, "\t%s\n", mark->file); fprintf(fp, "%lld\n", (long long)mark->timestamp); } } for(i = 0; i < nmarks; i += 3) { fprintf(fp, "%c%c\n", LINE_TYPE_MARK, marks[i][0]); fprintf(fp, "\t%s\n", marks[i + 1]); fprintf(fp, "\t%s\n", marks[i + 2]); fprintf(fp, "%d\n", timestamps[i/3]); } }
size_t get_mods_len(const char *str) { static const char FIXED_LENGTH_FILEMODS[] = "p~.htre"; size_t result = 0; if(str[0] != ':') { } else if(char_is_one_of(FIXED_LENGTH_FILEMODS, str[1])) { result = 2; } #ifdef _WIN32 else if(str[1] == 'u') { result = 2; } #endif else if(starts_with(str, ":s") || starts_with(str, ":gs")) { const char *p; result = (str[1] == 'g') ? 3 : 2; p = find_nth_chr(str, str[result], 3); if(p != NULL) result = (p - str) + 1; else result = strlen(str); } return result; }
/* Navigates the view to given mark if it's valid. Returns new value for * save_msg flag. */ static int navigate_to_bookmark(FileView *view, char mark) { const bookmark_t *const bmark = get_bookmark(mark); if(is_bmark_valid(bmark)) { if(change_directory(view, bmark->directory) >= 0) { load_dir_list(view, 1); (void)ensure_file_is_selected(view, bmark->file); } } else { if(!char_is_one_of(valid_bookmarks, mark)) status_bar_message("Invalid mark name"); else if(is_bmark_empty(bmark)) status_bar_message("Mark is not set"); else status_bar_message("Mark is invalid"); move_to_list_pos(view, view->list_pos); return 1; } return 0; }
void set_spec_bookmark(const char mark, const char directory[], const char file[]) { if(char_is_one_of(spec_bookmarks, mark)) { set_mark(mark, directory, file, time(NULL), 1); } }
int init_active_bookmarks(const char marks[], int active_bookmarks[]) { int i, x; i = 0; for(x = 0; x < NUM_BOOKMARKS; ++x) { if(!char_is_one_of(marks, index2mark(x))) continue; if(is_bmark_empty(&bookmarks[x])) continue; active_bookmarks[i++] = x; } return i; }
int init_active_marks(const char marks[], int active_marks[]) { int i, x; i = 0; for(x = 0; x < NUM_MARKS; ++x) { if(!char_is_one_of(marks, index2mark(x))) continue; if(is_empty(get_mark(x))) continue; active_marks[i++] = x; } return i; }
/* Escapes the string for the purpose of using it in filter. Returns new * string, caller should free it. */ static char * escape_name_for_filter(const char string[]) { static const char *NEED_ESCAPING = "\\[](){}+*^$.?|"; size_t len; char *ret, *dup; len = strlen(string); dup = ret = malloc(len*2 + 2 + 1); while(*string != '\0') { if(char_is_one_of(NEED_ESCAPING, *string)) { *dup++ = '\\'; } *dup++ = *string++; } *dup = '\0'; return ret; }
/* Expands preview parameter macros specified by the key argument. If key is * unknown, skips the macro. Sets *well_formed to non-zero for valid value of * the key. Reallocates the expanded string and returns result (possibly * NULL). */ static char * expand_preview(char expanded[], int key, int *well_formed) { FileView *view; char num_str[32]; int h, w, x, y; int param; const int with_margin = (curr_stats.clear_preview == 0) && cfg.extra_padding; if(!char_is_one_of("hwxy", key)) { *well_formed = 0; return expanded; } *well_formed = 1; view = get_preview_view(curr_view); getbegyx(view->win, y, x); getmaxyx(view->win, h, w); switch(key) { case 'h': param = h - 2*with_margin; break; case 'w': param = w - 2*with_margin; break; case 'x': param = x + 1*with_margin; break; case 'y': param = y + 1*with_margin; break; default: assert(0 && "Unhandled preview property type"); param = 0; break; } snprintf(num_str, sizeof(num_str), "%d", param); return append_to_expanded(expanded, num_str); }
/* args and flags parameters can equal NULL. The string returned needs to be * freed in the calling function. After executing flags is one of MF_* * values. */ static char * expand_macros_i(const char command[], const char args[], MacroFlags *flags, int for_shell, macro_filter_func filter) { /* TODO: refactor this function expand_macros() */ /* FIXME: repetitive len = strlen(expanded) could be optimized. */ static const char MACROS_WITH_QUOTING[] = "cCfFbdDr"; size_t cmd_len; char *expanded; size_t x; int len = 0; set_flags(flags, MF_NONE); cmd_len = strlen(command); for(x = 0; x < cmd_len; x++) if(command[x] == '%') break; if(x >= cmd_len) { return strdup(command); } expanded = calloc(cmd_len + 1, sizeof(char)); strncat(expanded, command, x); x++; len = strlen(expanded); do { size_t y; char *p; int quotes = 0; if(command[x] == '"' && char_is_one_of(MACROS_WITH_QUOTING, command[x + 1])) { quotes = 1; ++x; } switch(filter("es, command[x], command[x] == '\0' ? '\0' : command[x + 1])) { case 'a': /* user arguments */ if(args != NULL) { expanded = append_to_expanded(expanded, args); len = strlen(expanded); } break; case 'b': /* selected files of both dirs */ expanded = append_selected_files(curr_view, expanded, 0, quotes, command + x + 1, for_shell); expanded = append_to_expanded(expanded, " "); expanded = append_selected_files(other_view, expanded, 0, quotes, command + x + 1, for_shell); len = strlen(expanded); break; case 'c': /* current dir file under the cursor */ expanded = append_selected_files(curr_view, expanded, 1, quotes, command + x + 1, for_shell); len = strlen(expanded); break; case 'C': /* other dir file under the cursor */ expanded = append_selected_files(other_view, expanded, 1, quotes, command + x + 1, for_shell); len = strlen(expanded); break; case 'f': /* current dir selected files */ expanded = append_selected_files(curr_view, expanded, 0, quotes, command + x + 1, for_shell); len = strlen(expanded); break; case 'F': /* other dir selected files */ expanded = append_selected_files(other_view, expanded, 0, quotes, command + x + 1, for_shell); len = strlen(expanded); break; case 'd': /* current directory */ expanded = expand_directory_path(curr_view, expanded, quotes, command + x + 1, for_shell); len = strlen(expanded); break; case 'D': /* Directory of the other view. */ expanded = expand_directory_path(other_view, expanded, quotes, command + x + 1, for_shell); len = strlen(expanded); break; case 'n': /* Forbid using of terminal multiplexer, even if active. */ set_flags(flags, MF_NO_TERM_MUX); break; case 'm': /* Use menu. */ set_flags(flags, MF_MENU_OUTPUT); break; case 'M': /* Use menu like with :locate and :find. */ set_flags(flags, MF_MENU_NAV_OUTPUT); break; case 'S': /* Show command output in the status bar */ set_flags(flags, MF_STATUSBAR_OUTPUT); break; case 's': /* Split in new screen region and execute command there. */ set_flags(flags, MF_SPLIT); break; case 'u': /* Parse output as list of files and compose custom view. */ set_flags(flags, MF_CUSTOMVIEW_OUTPUT); break; case 'U': /* Parse output as list of files and compose unsorted view. */ set_flags(flags, MF_VERYCUSTOMVIEW_OUTPUT); break; case 'i': /* Ignore output. */ set_flags(flags, MF_IGNORE); break; case 'r': /* Registers' content. */ { int well_formed; expanded = expand_register(flist_get_dir(curr_view), expanded, quotes, command + x + 2, command[x + 1], &well_formed, for_shell); len = strlen(expanded); if(well_formed) { x++; } } break; case 'p': /* Preview pane properties. */ { int well_formed; const char key = command[x + 1]; if(key == 'c') { return expanded; } expanded = expand_preview(expanded, key, &well_formed); len = strlen(expanded); if(well_formed) { ++x; } } break; case '%': expanded = append_to_expanded(expanded, "%"); len = strlen(expanded); break; case '\0': if(char_is_one_of("pr", command[x]) && command[x + 1] != '\0') { ++x; } break; } if(command[x] != '\0') x++; while(x < cmd_len) { size_t len = get_mods_len(command + x); if(len == 0) { break; } x += len; } y = x; while(x < cmd_len) { if(command[x] == '%') break; if(command[x] != '\0') x++; } assert(x >= y); assert(y <= cmd_len); p = realloc(expanded, len + (x - y) + 1); if(p == NULL) { free(expanded); return NULL; } expanded = p; strncat(expanded, command + y, x - y); len = strlen(expanded); ++x; } while(x < cmd_len); return expanded; }
/* Reads contents of the filename file as an info file and updates it with the * state of current instance. */ static void update_info_file(const char filename[]) { /* TODO: refactor this function update_info_file() */ FILE *fp; char ** list; int nlist = -1; char **ft = NULL, **fx = NULL , **fv = NULL, **cmds = NULL, **marks = NULL; char **lh = NULL, **rh = NULL, **cmdh = NULL, **srch = NULL, **regs = NULL; int *lhp = NULL, *rhp = NULL; size_t nlhp = 0, nrhp = 0; char **prompt = NULL, **trash = NULL; int nft = 0, nfx = 0, nfv = 0, ncmds = 0, nmarks = 0, nlh = 0, nrh = 0; int ncmdh = 0, nsrch = 0, nregs = 0, nprompt = 0, ntrash = 0; int i; if(cfg.vifm_info == 0) return; list = list_udf(); while(list[++nlist] != NULL); if((fp = fopen(filename, "r")) != NULL) { char *line = NULL, *line2 = NULL, *line3 = NULL; while((line = read_vifminfo_line(fp, line)) != NULL) { const char type = line[0]; const char *const line_val = line + 1; if(type == LINE_TYPE_COMMENT || type == '\0') continue; if(type == LINE_TYPE_FILETYPE) { if((line2 = read_vifminfo_line(fp, line2)) != NULL) { assoc_record_t prog; if(get_default_program_for_file(line_val, &prog)) { free_assoc_record(&prog); continue; } nft = add_to_string_array(&ft, nft, 2, line_val, line2); } } else if(type == LINE_TYPE_XFILETYPE) { if((line2 = read_vifminfo_line(fp, line2)) != NULL) { assoc_record_t x_prog; if(get_default_program_for_file(line_val, &x_prog)) { assoc_record_t console_prog; if(get_default_program_for_file(line_val, &console_prog)) { if(strcmp(x_prog.command, console_prog.command) == 0) { free_assoc_record(&console_prog); free_assoc_record(&x_prog); continue; } } free_assoc_record(&x_prog); } nfx = add_to_string_array(&fx, nfx, 2, line_val, line2); } } else if(type == LINE_TYPE_FILEVIEWER) { if((line2 = read_vifminfo_line(fp, line2)) != NULL) { if(get_viewer_for_file(line_val) != NULL) continue; nfv = add_to_string_array(&fv, nfv, 2, line_val, line2); } } else if(type == LINE_TYPE_COMMAND) { if(line_val[0] == '\0') continue; if((line2 = read_vifminfo_line(fp, line2)) != NULL) { const char *p = line_val; for(i = 0; i < nlist; i += 2) { int cmp = strcmp(list[i], p); if(cmp < 0) continue; if(cmp == 0) p = NULL; break; } if(p == NULL) continue; ncmds = add_to_string_array(&cmds, ncmds, 2, line_val, line2); } } else if(type == LINE_TYPE_LWIN_HIST) { if(line_val[0] == '\0') continue; if((line2 = read_vifminfo_line(fp, line2)) != NULL) { int pos; if(lwin.history_pos + nlh/2 == cfg.history_len - 1) continue; if(is_in_view_history(&lwin, line_val)) continue; pos = read_possible_possible_pos(fp); nlh = add_to_string_array(&lh, nlh, 2, line_val, line2); if(nlh/2 > nlhp) { nlhp = add_to_int_array(&lhp, nlhp, pos); nlhp = MIN(nlh/2, nlhp); } } } else if(type == LINE_TYPE_RWIN_HIST) { if(line_val[0] == '\0') continue; if((line2 = read_vifminfo_line(fp, line2)) != NULL) { int pos; if(rwin.history_pos + nrh/2 == cfg.history_len - 1) continue; if(is_in_view_history(&rwin, line_val)) continue; pos = read_possible_possible_pos(fp); nrh = add_to_string_array(&rh, nrh, 2, line_val, line2); if(nrh/2 > nrhp) { nrhp = add_to_int_array(&rhp, nrhp, pos); nrhp = MIN(nrh/2, nrhp); } } } else if(type == LINE_TYPE_BOOKMARK) { const char mark = line_val[0]; if(line_val[1] != '\0') { LOG_ERROR_MSG("Expected end of line, but got: %s", line_val + 1); } if((line2 = read_vifminfo_line(fp, line2)) != NULL) { if((line3 = read_vifminfo_line(fp, line3)) != NULL) { const char mark_str[] = { mark, '\0' }; if(!char_is_one_of(valid_bookmarks, mark)) continue; if(!is_bookmark_empty(mark2index(mark))) continue; nmarks = add_to_string_array(&marks, nmarks, 3, mark_str, line2, line3); } } } else if(type == LINE_TYPE_TRASH) { if((line2 = read_vifminfo_line(fp, line2)) != NULL) { if(!path_exists_at(cfg.trash_dir, line_val)) continue; if(is_in_trash(line_val)) continue; ntrash = add_to_string_array(&trash, ntrash, 2, line_val, line2); } } else if(type == LINE_TYPE_CMDLINE_HIST) { if(cfg.cmd_history_num >= 0 && is_in_string_array(cfg.cmd_history, cfg.cmd_history_num + 1, line_val)) continue; ncmdh = add_to_string_array(&cmdh, ncmdh, 1, line_val); } else if(type == LINE_TYPE_SEARCH_HIST) { if(cfg.search_history_num >= 0 && is_in_string_array(cfg.search_history, cfg.search_history_num + 1, line_val)) continue; nsrch = add_to_string_array(&srch, nsrch, 1, line_val); } else if(type == LINE_TYPE_PROMPT_HIST) { if(cfg.prompt_history_num >= 0 && is_in_string_array(cfg.prompt_history, cfg.prompt_history_num + 1, line_val)) continue; nprompt = add_to_string_array(&prompt, nprompt, 1, line_val); } else if(type == LINE_TYPE_REG) { if(register_exists(line_val[0])) continue; nregs = add_to_string_array(®s, nregs, 1, line); } } free(line); free(line2); free(line3); fclose(fp); } if((fp = fopen(filename, "w")) == NULL) { return; } fprintf(fp, "# You can edit this file by hand, but it's recommended not to do that.\n"); if(cfg.vifm_info & VIFMINFO_OPTIONS) { fputs("\n# Options:\n", fp); fprintf(fp, "=aproposprg=%s\n", escape_spaces(cfg.apropos_prg)); fprintf(fp, "=%sautochpos\n", cfg.auto_ch_pos ? "" : "no"); fprintf(fp, "=columns=%d\n", cfg.columns); fprintf(fp, "=%sconfirm\n", cfg.confirm ? "" : "no"); fprintf(fp, "=cpoptions=%s%s%s\n", cfg.filter_inverted_by_default ? "f" : "", cfg.selection_is_primary ? "s" : "", cfg.tab_switches_pane ? "t" : ""); fprintf(fp, "=%sfastrun\n", cfg.fast_run ? "" : "no"); fprintf(fp, "=findprg=%s\n", escape_spaces(cfg.find_prg)); fprintf(fp, "=%sfollowlinks\n", cfg.follow_links ? "" : "no"); fprintf(fp, "=fusehome=%s\n", escape_spaces(cfg.fuse_home)); fprintf(fp, "=%sgdefault\n", cfg.gdefault ? "" : "no"); fprintf(fp, "=grepprg=%s\n", escape_spaces(cfg.grep_prg)); fprintf(fp, "=history=%d\n", cfg.history_len); fprintf(fp, "=%shlsearch\n", cfg.hl_search ? "" : "no"); fprintf(fp, "=%siec\n", cfg.use_iec_prefixes ? "" : "no"); fprintf(fp, "=%signorecase\n", cfg.ignore_case ? "" : "no"); fprintf(fp, "=%sincsearch\n", cfg.inc_search ? "" : "no"); fprintf(fp, "=%slaststatus\n", cfg.last_status ? "" : "no"); fprintf(fp, "=lines=%d\n", cfg.lines); fprintf(fp, "=locateprg=%s\n", escape_spaces(cfg.locate_prg)); fprintf(fp, "=rulerformat=%s\n", escape_spaces(cfg.ruler_format)); fprintf(fp, "=%srunexec\n", cfg.auto_execute ? "" : "no"); fprintf(fp, "=%sscrollbind\n", cfg.scroll_bind ? "" : "no"); fprintf(fp, "=scrolloff=%d\n", cfg.scroll_off); fprintf(fp, "=shell=%s\n", escape_spaces(cfg.shell)); fprintf(fp, "=shortmess=%s\n", cfg.trunc_normal_sb_msgs ? "T" : ""); #ifndef _WIN32 fprintf(fp, "=slowfs=%s\n", escape_spaces(cfg.slow_fs_list)); #endif fprintf(fp, "=%ssmartcase\n", cfg.smart_case ? "" : "no"); fprintf(fp, "=%ssortnumbers\n", cfg.sort_numbers ? "" : "no"); fprintf(fp, "=statusline=%s\n", escape_spaces(cfg.status_line)); fprintf(fp, "=tabstop=%d\n", cfg.tab_stop); fprintf(fp, "=timefmt=%s\n", escape_spaces(cfg.time_format + 1)); fprintf(fp, "=timeoutlen=%d\n", cfg.timeout_len); fprintf(fp, "=%strash\n", cfg.use_trash ? "" : "no"); fprintf(fp, "=undolevels=%d\n", cfg.undo_levels); fprintf(fp, "=vicmd=%s%s\n", escape_spaces(cfg.vi_command), cfg.vi_cmd_bg ? " &" : ""); fprintf(fp, "=vixcmd=%s%s\n", escape_spaces(cfg.vi_x_command), cfg.vi_cmd_bg ? " &" : ""); fprintf(fp, "=%swrapscan\n", cfg.wrap_scan ? "" : "no"); fprintf(fp, "=[viewcolumns=%s\n", escape_spaces(lwin.view_columns)); fprintf(fp, "=]viewcolumns=%s\n", escape_spaces(rwin.view_columns)); fprintf(fp, "=[%slsview\n", lwin.ls_view ? "" : "no"); fprintf(fp, "=]%slsview\n", rwin.ls_view ? "" : "no"); fprintf(fp, "%s", "=dotdirs="); if(cfg.dot_dirs & DD_ROOT_PARENT) fprintf(fp, "%s", "rootparent,"); if(cfg.dot_dirs & DD_NONROOT_PARENT) fprintf(fp, "%s", "nonrootparent,"); fprintf(fp, "\n"); fprintf(fp, "=classify=%s\n", escape_spaces(classify_to_str())); fprintf(fp, "=vifminfo=options"); if(cfg.vifm_info & VIFMINFO_FILETYPES) fprintf(fp, ",filetypes"); if(cfg.vifm_info & VIFMINFO_COMMANDS) fprintf(fp, ",commands"); if(cfg.vifm_info & VIFMINFO_BOOKMARKS) fprintf(fp, ",bookmarks"); if(cfg.vifm_info & VIFMINFO_TUI) fprintf(fp, ",tui"); if(cfg.vifm_info & VIFMINFO_DHISTORY) fprintf(fp, ",dhistory"); if(cfg.vifm_info & VIFMINFO_STATE) fprintf(fp, ",state"); if(cfg.vifm_info & VIFMINFO_CS) fprintf(fp, ",cs"); if(cfg.vifm_info & VIFMINFO_SAVEDIRS) fprintf(fp, ",savedirs"); if(cfg.vifm_info & VIFMINFO_CHISTORY) fprintf(fp, ",chistory"); if(cfg.vifm_info & VIFMINFO_SHISTORY) fprintf(fp, ",shistory"); if(cfg.vifm_info & VIFMINFO_PHISTORY) fprintf(fp, ",phistory"); if(cfg.vifm_info & VIFMINFO_DIRSTACK) fprintf(fp, ",dirstack"); if(cfg.vifm_info & VIFMINFO_REGISTERS) fprintf(fp, ",registers"); fprintf(fp, "\n"); fprintf(fp, "=%svimhelp\n", cfg.use_vim_help ? "" : "no"); fprintf(fp, "=%swildmenu\n", cfg.wild_menu ? "" : "no"); fprintf(fp, "=%swrap\n", cfg.wrap_quick_view ? "" : "no"); } if(cfg.vifm_info & VIFMINFO_FILETYPES) { fputs("\n# Filetypes:\n", fp); for(i = 0; i < filetypes.count; i++) { int j; assoc_t ft_assoc = filetypes.list[i]; for(j = 0; j < ft_assoc.records.count; j++) { assoc_record_t ft_record = ft_assoc.records.list[j]; /* The type check is to prevent builtin fake associations to be written * into vifminfo file */ if(ft_record.command[0] != '\0' && ft_record.type != ART_BUILTIN) { fprintf(fp, ".%s\n\t{%s}%s\n", ft_assoc.pattern, ft_record.description, ft_record.command); } } } for(i = 0; i < nft; i += 2) fprintf(fp, ".%s\n\t%s\n", ft[i], ft[i + 1]); fputs("\n# X Filetypes:\n", fp); for(i = 0; i < xfiletypes.count; i++) { int j; assoc_t xft_assoc = xfiletypes.list[i]; for(j = 0; j < xft_assoc.records.count; j++) { assoc_record_t xft_record = xft_assoc.records.list[j]; if(xft_record.command[0] != '\0') { fprintf(fp, "x%s\n\t{%s}%s\n", xft_assoc.pattern, xft_record.description, xft_record.command); } } } for(i = 0; i < nfx; i += 2) fprintf(fp, ".%s\n\t%s\n", fx[i], fx[i + 1]); fputs("\n# Fileviewers:\n", fp); for(i = 0; i < fileviewers.count; i++) { int j; assoc_t fv_assoc = fileviewers.list[i]; for(j = 0; j < fv_assoc.records.count; j++) { assoc_record_t fv_record = fileviewers.list[i].records.list[j]; if(fv_record.command[0] != '\0') { fprintf(fp, ",%s\n\t%s\n", fv_assoc.pattern, fv_record.command); } } } for(i = 0; i < nfv; i += 2) fprintf(fp, ",%s\n\t%s\n", fv[i], fv[i + 1]); } if(cfg.vifm_info & VIFMINFO_COMMANDS) { fputs("\n# Commands:\n", fp); for(i = 0; list[i] != NULL; i += 2) fprintf(fp, "!%s\n\t%s\n", list[i], list[i + 1]); for(i = 0; i < ncmds; i += 2) fprintf(fp, "!%s\n\t%s\n", cmds[i], cmds[i + 1]); } if(cfg.vifm_info & VIFMINFO_BOOKMARKS) { int len = init_active_bookmarks(valid_bookmarks); fputs("\n# Bookmarks:\n", fp); for(i = 0; i < len; i++) { int j = active_bookmarks[i]; if(is_spec_bookmark(j)) continue; fprintf(fp, "'%c\n\t%s\n\t", index2mark(j), bookmarks[j].directory); fprintf(fp, "%s\n", bookmarks[j].file); } for(i = 0; i < nmarks; i += 3) fprintf(fp, "'%c\n\t%s\n\t%s\n", marks[i][0], marks[i + 1], marks[i + 2]); } if(cfg.vifm_info & VIFMINFO_TUI) { fputs("\n# TUI:\n", fp); fprintf(fp, "a%c\n", (curr_view == &rwin) ? 'r' : 'l'); fprintf(fp, "q%d\n", curr_stats.view); fprintf(fp, "v%d\n", curr_stats.number_of_windows); fprintf(fp, "o%c\n", (curr_stats.split == VSPLIT) ? 'v' : 'h'); fprintf(fp, "m%d\n", curr_stats.splitter_pos); put_sort_info(fp, 'l', &lwin); put_sort_info(fp, 'r', &rwin); } if((cfg.vifm_info & VIFMINFO_DHISTORY) && cfg.history_len > 0) { save_view_history(&lwin, NULL, NULL, -1); fputs("\n# Left window history (oldest to newest):\n", fp); for(i = 0; i < nlh; i += 2) fprintf(fp, "d%s\n\t%s\n%d\n", lh[i], lh[i + 1], lhp[i/2]); for(i = 0; i <= lwin.history_pos; i++) fprintf(fp, "d%s\n\t%s\n%d\n", lwin.history[i].dir, lwin.history[i].file, lwin.history[i].rel_pos); if(cfg.vifm_info & VIFMINFO_SAVEDIRS) fprintf(fp, "d\n"); save_view_history(&rwin, NULL, NULL, -1); fputs("\n# Right window history (oldest to newest):\n", fp); for(i = 0; i < nrh; i += 2) fprintf(fp, "D%s\n\t%s\n%d\n", rh[i], rh[i + 1], rhp[i/2]); for(i = 0; i <= rwin.history_pos; i++) fprintf(fp, "D%s\n\t%s\n%d\n", rwin.history[i].dir, rwin.history[i].file, rwin.history[i].rel_pos); if(cfg.vifm_info & VIFMINFO_SAVEDIRS) fprintf(fp, "D\n"); } if(cfg.vifm_info & VIFMINFO_CHISTORY) { fputs("\n# Command line history (oldest to newest):\n", fp); for(i = 0; i < MIN(ncmdh, cfg.history_len - cfg.cmd_history_num); i++) fprintf(fp, ":%s\n", cmdh[i]); for(i = cfg.cmd_history_num; i >= 0; i--) fprintf(fp, ":%s\n", cfg.cmd_history[i]); } if(cfg.vifm_info & VIFMINFO_SHISTORY) { fputs("\n# Search history (oldest to newest):\n", fp); for(i = 0; i < nsrch; i++) fprintf(fp, "/%s\n", srch[i]); for(i = cfg.search_history_num; i >= 0; i--) fprintf(fp, "/%s\n", cfg.search_history[i]); } if(cfg.vifm_info & VIFMINFO_PHISTORY) { fputs("\n# Prompt history (oldest to newest):\n", fp); for(i = 0; i < nprompt; i++) fprintf(fp, "p%s\n", prompt[i]); for(i = cfg.prompt_history_num; i >= 0; i--) fprintf(fp, "p%s\n", cfg.prompt_history[i]); } if(cfg.vifm_info & VIFMINFO_REGISTERS) { fputs("\n# Registers:\n", fp); for(i = 0; i < nregs; i++) fprintf(fp, "%s\n", regs[i]); for(i = 0; valid_registers[i] != '\0'; i++) { int j; registers_t *reg = find_register(valid_registers[i]); if(reg == NULL) continue; for(j = 0; j < reg->num_files; j++) { if(reg->files[j] == NULL) continue; fprintf(fp, "\"%c%s\n", reg->name, reg->files[j]); } } } if(cfg.vifm_info & VIFMINFO_DIRSTACK) { fputs("\n# Directory stack (oldest to newest):\n", fp); for(i = 0; i < stack_top; i++) { fprintf(fp, "S%s\n\t%s\n", stack[i].lpane_dir, stack[i].lpane_file); fprintf(fp, "S%s\n\t%s\n", stack[i].rpane_dir, stack[i].rpane_file); } } fputs("\n# Trash content:\n", fp); for(i = 0; i < nentries; i++) fprintf(fp, "t%s\n\t%s\n", trash_list[i].trash_name, trash_list[i].path); for(i = 0; i < ntrash; i += 2) fprintf(fp, "t%s\n\t%s\n", trash[i], trash[i + 1]); if(cfg.vifm_info & VIFMINFO_STATE) { fputs("\n# State:\n", fp); fprintf(fp, "f%s\n", lwin.filename_filter); fprintf(fp, "i%d\n", lwin.invert); fprintf(fp, "[.%d\n", lwin.hide_dot); fprintf(fp, "F%s\n", rwin.filename_filter); fprintf(fp, "I%d\n", rwin.invert); fprintf(fp, "].%d\n", rwin.hide_dot); fprintf(fp, "s%d\n", cfg.use_screen); } if(cfg.vifm_info & VIFMINFO_CS) { fputs("\n# Color scheme:\n", fp); fprintf(fp, "c%s\n", cfg.cs.name); } fclose(fp); free_string_array(ft, nft); free_string_array(fv, nfv); free_string_array(fx, nfx); free_string_array(cmds, ncmds); free_string_array(marks, nmarks); free_string_array(list, nlist); free_string_array(lh, nlh); free_string_array(rh, nrh); free(lhp); free(rhp); free_string_array(cmdh, ncmdh); free_string_array(srch, nsrch); free_string_array(regs, nregs); free_string_array(prompt, nprompt); free_string_array(trash, ntrash); }
int let_variable(const char *cmd) { char name[VAR_NAME_MAX + 1]; char *p; int append = 0; var_t res_var; char *str_var; ParsingErrors parsing_error; assert(initialized); /* currently we support only environment variables */ if(*cmd != '$') { text_buffer_add("Incorrect variable type"); return -1; } cmd++; /* copy variable name */ p = name; while(*cmd != '\0' && char_is_one_of(ENV_VAR_NAME_CHARS, *cmd) && *cmd != '.' && *cmd != '=' && p - name < sizeof(name) - 1) { if(*cmd != '_' && !isalnum(*cmd)) { text_buffer_add("Incorrect variable name"); return -1; } *p++ = *cmd++; } /* test for empty variable name */ if(p == name) { text_buffer_addf("%s: %s", "Unsupported variable name", "empty name"); return -1; } *p = '\0'; cmd = skip_whitespace(cmd); /* check for dot and skip it */ if(*cmd == '.') { append = 1; cmd++; } /* check for equal sign and skip it */ if(*cmd != '=') { text_buffer_addf("%s: %s", "Incorrect :let statement", "'=' expected"); return -1; } parsing_error = parse(cmd + 1, &res_var); if(parsing_error != PE_NO_ERROR) { report_parsing_error(parsing_error); return -1; } if(get_last_position() != NULL && *get_last_position() != '\0') { text_buffer_addf("%s: %s", "Incorrect :let statement", "trailing characters"); return -1; } /* update environment variable */ str_var = var_to_string(res_var); if(append) append_envvar(name, str_var); else set_envvar(name, str_var); free(str_var); var_free(res_var); return 0; }
int unlet_variables(const char *cmd) { int error = 0; assert(initialized); while(*cmd != '\0') { envvar_t *record; char name[VAR_NAME_MAX + 1]; char *p; int envvar = 1; /* check if its environment variable */ if(*cmd != '$') envvar = 0; else cmd++; /* copy variable name */ p = name; while(*cmd != '\0' && char_is_one_of(ENV_VAR_NAME_CHARS, *cmd) && p - name < sizeof(name) - 1) *p++ = *cmd++; *p = '\0'; if(*cmd != '\0' && !isspace(*cmd)) { text_buffer_add("Trailing characters"); error++; break; } cmd = skip_whitespace(cmd); /* currently we support only environment variables */ if(!envvar) { text_buffer_addf("%s: %s", "Unsupported variable type", name); cmd = skip_non_whitespace(cmd); error++; continue; } /* test for empty variable name */ if(name[0] == '\0') { text_buffer_addf("%s: %s", "Unsupported variable name", "empty name"); error++; continue; } record = find_record(name); if(record == NULL || record->removed) { text_buffer_addf("%s: %s", "No such variable", name); error++; continue; } if(record->from_parent) record->removed = 1; else free_record(record); env_remove(name); } return error; }
/* Reads contents of the filename file as an info file and updates it with the * state of current instance. */ static void update_info_file(const char filename[]) { /* TODO: refactor this function update_info_file() */ FILE *fp; char **cmds_list; int ncmds_list = -1; char **ft = NULL, **fx = NULL, **fv = NULL, **cmds = NULL, **marks = NULL; char **lh = NULL, **rh = NULL, **cmdh = NULL, **srch = NULL, **regs = NULL; int *lhp = NULL, *rhp = NULL, *bt = NULL, *bmt = NULL; char **prompt = NULL, **filter = NULL, **trash = NULL; char **bmarks = NULL; int nft = 0, nfx = 0, nfv = 0, ncmds = 0, nmarks = 0, nlh = 0, nrh = 0; int ncmdh = 0, nsrch = 0, nregs = 0, nprompt = 0, nfilter = 0, ntrash = 0; int nbmarks = 0; char **dir_stack = NULL; int ndir_stack = 0; char *non_conflicting_marks; if(cfg.vifm_info == 0) return; cmds_list = list_udf(); while(cmds_list[++ncmds_list] != NULL); non_conflicting_marks = strdup(valid_marks); if((fp = os_fopen(filename, "r")) != NULL) { size_t nlhp = 0UL, nrhp = 0UL, nbt = 0UL, nbmt = 0UL; char *line = NULL, *line2 = NULL, *line3 = NULL, *line4 = NULL; while((line = read_vifminfo_line(fp, line)) != NULL) { const char type = line[0]; const char *const line_val = line + 1; if(type == LINE_TYPE_COMMENT || type == '\0') continue; if(type == LINE_TYPE_FILETYPE) { if((line2 = read_vifminfo_line(fp, line2)) != NULL) { if(!ft_assoc_exists(&filetypes, line_val, line2)) { nft = add_to_string_array(&ft, nft, 2, line_val, line2); } } } else if(type == LINE_TYPE_XFILETYPE) { if((line2 = read_vifminfo_line(fp, line2)) != NULL) { if(!ft_assoc_exists(&xfiletypes, line_val, line2)) { nfx = add_to_string_array(&fx, nfx, 2, line_val, line2); } } } else if(type == LINE_TYPE_FILEVIEWER) { if((line2 = read_vifminfo_line(fp, line2)) != NULL) { if(!ft_assoc_exists(&fileviewers, line_val, line2)) { nfv = add_to_string_array(&fv, nfv, 2, line_val, line2); } } } else if(type == LINE_TYPE_COMMAND) { if(line_val[0] == '\0') continue; if((line2 = read_vifminfo_line(fp, line2)) != NULL) { int i; const char *p = line_val; for(i = 0; i < ncmds_list; i += 2) { int cmp = strcmp(cmds_list[i], p); if(cmp < 0) continue; if(cmp == 0) p = NULL; break; } if(p == NULL) continue; ncmds = add_to_string_array(&cmds, ncmds, 2, line_val, line2); } } else if(type == LINE_TYPE_LWIN_HIST || type == LINE_TYPE_RWIN_HIST) { if(line_val[0] == '\0') continue; if((line2 = read_vifminfo_line(fp, line2)) != NULL) { const int pos = read_optional_number(fp); if(type == LINE_TYPE_LWIN_HIST) { process_hist_entry(&lwin, line_val, line2, pos, &lh, &nlh, &lhp, &nlhp); } else { process_hist_entry(&rwin, line_val, line2, pos, &rh, &nrh, &rhp, &nrhp); } } } else if(type == LINE_TYPE_MARK) { const char mark = line_val[0]; if(line_val[1] != '\0') { LOG_ERROR_MSG("Expected end of line, but got: %s", line_val + 1); } if((line2 = read_vifminfo_line(fp, line2)) != NULL) { if((line3 = read_vifminfo_line(fp, line3)) != NULL) { const int timestamp = read_optional_number(fp); const char mark_str[] = { mark, '\0' }; if(!char_is_one_of(valid_marks, mark)) { continue; } if(is_mark_older(mark, timestamp)) { char *const pos = strchr(non_conflicting_marks, mark); if(pos != NULL) { nmarks = add_to_string_array(&marks, nmarks, 3, mark_str, line2, line3); nbt = add_to_int_array(&bt, nbt, timestamp); *pos = '\xff'; } } } } } else if(type == LINE_TYPE_BOOKMARK) { if((line2 = read_vifminfo_line(fp, line2)) != NULL) { if((line3 = read_vifminfo_line(fp, line3)) != NULL) { long timestamp; if(read_number(line3, ×tamp) && bmark_is_older(line_val, timestamp)) { nbmarks = add_to_string_array(&bmarks, nbmarks, 2, line_val, line2); nbmt = add_to_int_array(&bmt, nbmt, timestamp); } } } } else if(type == LINE_TYPE_TRASH) { if((line2 = read_vifminfo_line(fp, line2)) != NULL) { char *const trash_name = convert_old_trash_path(line_val); if(exists_in_trash(trash_name) && !is_in_trash(trash_name)) { ntrash = add_to_string_array(&trash, ntrash, 2, trash_name, line2); } free(trash_name); } } else if(type == LINE_TYPE_CMDLINE_HIST) { if(!hist_contains(&cfg.cmd_hist, line_val)) { ncmdh = add_to_string_array(&cmdh, ncmdh, 1, line_val); } } else if(type == LINE_TYPE_SEARCH_HIST) { if(!hist_contains(&cfg.search_hist, line_val)) { nsrch = add_to_string_array(&srch, nsrch, 1, line_val); } } else if(type == LINE_TYPE_PROMPT_HIST) { if(!hist_contains(&cfg.prompt_hist, line_val)) { nprompt = add_to_string_array(&prompt, nprompt, 1, line_val); } } else if(type == LINE_TYPE_FILTER_HIST) { if(!hist_contains(&cfg.filter_hist, line_val)) { nfilter = add_to_string_array(&filter, nfilter, 1, line_val); } } else if(type == LINE_TYPE_DIR_STACK) { if((line2 = read_vifminfo_line(fp, line2)) != NULL) { if((line3 = read_vifminfo_line(fp, line3)) != NULL) { if((line4 = read_vifminfo_line(fp, line4)) != NULL) { ndir_stack = add_to_string_array(&dir_stack, ndir_stack, 4, line_val, line2, line3 + 1, line4); } } } } else if(type == LINE_TYPE_REG) { if(regs_exists(line_val[0])) { continue; } nregs = add_to_string_array(®s, nregs, 1, line); } } free(line); free(line2); free(line3); free(line4); fclose(fp); } if((fp = os_fopen(filename, "w")) != NULL) { fprintf(fp, "# You can edit this file by hand, but it's recommended not to " "do that.\n"); if(cfg.vifm_info & VIFMINFO_OPTIONS) { write_options(fp); } if(cfg.vifm_info & VIFMINFO_FILETYPES) { write_assocs(fp, "Filetypes", LINE_TYPE_FILETYPE, &filetypes, nft, ft); write_assocs(fp, "X Filetypes", LINE_TYPE_XFILETYPE, &xfiletypes, nfx, fx); write_assocs(fp, "Fileviewers", LINE_TYPE_FILEVIEWER, &fileviewers, nfv, fv); } if(cfg.vifm_info & VIFMINFO_COMMANDS) { write_commands(fp, cmds_list, cmds, ncmds); } if(cfg.vifm_info & VIFMINFO_MARKS) { write_marks(fp, non_conflicting_marks, marks, bt, nmarks); } if(cfg.vifm_info & VIFMINFO_BOOKMARKS) { write_bmarks(fp, bmarks, bmt, nbmarks); } if(cfg.vifm_info & VIFMINFO_TUI) { write_tui_state(fp); } if((cfg.vifm_info & VIFMINFO_DHISTORY) && cfg.history_len > 0) { write_view_history(fp, &lwin, "Left", LINE_TYPE_LWIN_HIST, nlh, lh, lhp); write_view_history(fp, &rwin, "Right", LINE_TYPE_RWIN_HIST, nrh, rh, rhp); } if(cfg.vifm_info & VIFMINFO_CHISTORY) { write_history(fp, "Command line", LINE_TYPE_CMDLINE_HIST, MIN(ncmdh, cfg.history_len - cfg.cmd_hist.pos), cmdh, &cfg.cmd_hist); } if(cfg.vifm_info & VIFMINFO_SHISTORY) { write_history(fp, "Search", LINE_TYPE_SEARCH_HIST, nsrch, srch, &cfg.search_hist); } if(cfg.vifm_info & VIFMINFO_PHISTORY) { write_history(fp, "Prompt", LINE_TYPE_PROMPT_HIST, nprompt, prompt, &cfg.prompt_hist); } if(cfg.vifm_info & VIFMINFO_FHISTORY) { write_history(fp, "Local filter", LINE_TYPE_FILTER_HIST, nfilter, filter, &cfg.filter_hist); } if(cfg.vifm_info & VIFMINFO_REGISTERS) { write_registers(fp, regs, nregs); } if(cfg.vifm_info & VIFMINFO_DIRSTACK) { write_dir_stack(fp, dir_stack, ndir_stack); } write_trash(fp, trash, ntrash); if(cfg.vifm_info & VIFMINFO_STATE) { write_general_state(fp); } if(cfg.vifm_info & VIFMINFO_CS) { fputs("\n# Color scheme:\n", fp); fprintf(fp, "c%s\n", cfg.cs.name); } fclose(fp); } free_string_array(ft, nft); free_string_array(fv, nfv); free_string_array(fx, nfx); free_string_array(cmds, ncmds); free_string_array(marks, nmarks); free_string_array(cmds_list, ncmds_list); free_string_array(lh, nlh); free_string_array(rh, nrh); free(lhp); free(rhp); free(bt); free(bmt); free_string_array(cmdh, ncmdh); free_string_array(srch, nsrch); free_string_array(regs, nregs); free_string_array(prompt, nprompt); free_string_array(filter, nfilter); free_string_array(trash, ntrash); free_string_array(bmarks, nbmarks); free_string_array(dir_stack, ndir_stack); free(non_conflicting_marks); }
/* 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); }
int is_spec_mark(const int x) { return char_is_one_of(spec_marks, index2mark(x)); }
int is_spec_bookmark(const int x) { const char mark = index2mark(x); return char_is_one_of(spec_bookmarks, mark); }
/* 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 char * parse_view_macros(FileView *view, const char **format, const char macros[], int opt) { const dir_entry_t *const entry = &view->dir_entry[view->list_pos]; char *result = strdup(""); size_t len = 0; char c; int nexpansions = 0; while((c = **format) != '\0') { size_t width = 0; int left_align = 0; char buf[PATH_MAX]; const char *const next = ++*format; int skip, ok; if(c != '%' || (!char_is_one_of(macros, *next) && !isdigit(*next))) { if(strappendch(&result, &len, c) != 0) { break; } continue; } if(*next == '-') { left_align = 1; ++*format; } while(isdigit(**format)) { width = width*10 + *(*format)++ - '0'; } c = *(*format)++; skip = 0; ok = 1; switch(c) { case 't': format_entry_name(entry, sizeof(buf), buf); break; case 'A': #ifndef _WIN32 get_perm_string(buf, sizeof(buf), entry->mode); #else snprintf(buf, sizeof(buf), "%s", attr_str_long(entry->attrs)); #endif break; case 'u': get_uid_string(entry, 0, sizeof(buf), buf); break; case 'g': get_gid_string(entry, 0, sizeof(buf), buf); break; case 's': friendly_size_notation(entry->size, sizeof(buf), buf); break; case 'E': { uint64_t size = 0; if(view->selected_files > 0) { int i; for(i = 0; i < view->list_rows; i++) { if(view->dir_entry[i].selected) { size += get_file_size_by_entry(view, i); } } } /* Make exception for VISUAL_MODE, since it can contain empty * selection when cursor is on ../ directory. */ else if(!vle_mode_is(VISUAL_MODE)) { size = get_file_size_by_entry(view, view->list_pos); } friendly_size_notation(size, sizeof(buf), buf); } break; case 'd': { struct tm *tm_ptr = localtime(&entry->mtime); strftime(buf, sizeof(buf), cfg.time_format, tm_ptr); } break; case '-': 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 '%': snprintf(buf, sizeof(buf), "%%"); break; case '[': { char *const opt_str = parse_view_macros(view, format, macros, 1); copy_str(buf, sizeof(buf), opt_str); free(opt_str); break; } case ']': if(opt) { if(nexpansions == 0) { replace_string(&result, ""); } return result; } else { LOG_INFO_MSG("Unmatched %]", c); ok = 0; } break; default: LOG_INFO_MSG("Unexpected %%-sequence: %%%c", c); ok = 0; break; } if(!ok) { *format = next; if(strappendch(&result, &len, '%') != 0) { break; } continue; } check_expanded_str(buf, skip, &nexpansions); stralign(buf, width, ' ', left_align); if(strappend(&result, &len, buf) != 0) { break; } } /* Unmatched %[. */ if(opt) { (void)strprepend(&result, &len, "%["); } return result; }
/* Processes one :set statement. Returns zero on success. */ static int process_option(const char arg[]) { char option[OPTION_NAME_MAX + 1]; int err; const char *p; opt_t *opt; p = skip_alphas(arg); snprintf(option, p - arg + 1, "%s", arg); if(strcmp(option, "all") == 0) { print_options(); return 0; } opt = get_option(option); if(opt == NULL) { text_buffer_addf("%s: %s", "Unknown option", arg); return 1; } err = 0; if(*p == '\0') { opt_t *o = find_option(option); if(o != NULL) { if(o->type == OPT_BOOL) err = set_on(opt); else err = set_print(o); } else if(strncmp(option, "no", 2) == 0) { err = set_off(opt); } else if(strncmp(option, "inv", 3) == 0) { err = set_inv(opt); } } else if(char_is_one_of(ENDING_CHARS, *p)) { if(*(p + 1) != '\0') { text_buffer_addf("%s: %s", "Trailing characters", arg); return 1; } if(*p == '!') err = set_inv(opt); else if(*p == '?') err = set_print(opt); else err = set_reset(opt); } else if(strncmp(p, "+=", 2) == 0) { err = set_add(opt, p + 2); } else if(strncmp(p, "-=", 2) == 0) { err = set_remove(opt, p + 2); } else if(*p == '=' || *p == ':') { err = set_set(opt, p + 1); } else { text_buffer_addf("%s: %s", "Trailing characters", arg); } if(err) { text_buffer_addf("%s: %s", "Invalid argument", arg); } return err; }
/* Checks whether given mark corresponds to bookmark that can be set by a user. * Returns non-zero if so, otherwise zero is returned. */ static int is_user_bookmark(const char mark) { return char_is_one_of(valid_bookmarks, mark) && !char_is_one_of(spec_bookmarks, mark); }