pax_global_header00006660000000000000000000000064150663203770014523gustar00rootroot0000000000000052 comment=1d1ede2253399038d293a2440e1de2ae9f1f96fd clifm-1.26.3/000077500000000000000000000000001506632037700127065ustar00rootroot00000000000000clifm-1.26.3/.editorconfig000066400000000000000000000006341506632037700153660ustar00rootroot00000000000000; This file is for unifying the coding style for different editors and IDEs. ; More information at http://EditorConfig.org root = true [*] indent_style = tab tab_width = 4 charset = utf-8 end_of_line = lf trim_trailing_whitespace = true insert_final_newline = true [*.fish] indent_style = space indent_size = 4 [*.py] indent_style = space indent_size = 4 [*.{yaml,yml}] indent_style = space indent_size = 2 clifm-1.26.3/.github/000077500000000000000000000000001506632037700142465ustar00rootroot00000000000000clifm-1.26.3/.github/FUNDING.yml000066400000000000000000000001001506632037700160520ustar00rootroot00000000000000# These are supported funding model platforms github: leo-arch clifm-1.26.3/.github/ISSUE_TEMPLATE/000077500000000000000000000000001506632037700164315ustar00rootroot00000000000000clifm-1.26.3/.github/ISSUE_TEMPLATE/config.yml000066400000000000000000000000341506632037700204160ustar00rootroot00000000000000blank_issues_enabled: false clifm-1.26.3/.github/ISSUE_TEMPLATE/feature-request.md000066400000000000000000000011231506632037700220710ustar00rootroot00000000000000--- name: Feature request about: Suggest an idea for this project title: '' labels: '' assignees: '' --- **Is your feature request related to a problem? Please describe.** A clear and concise description of what the problem is. E.g., I'm always frustrated when ... **Describe the solution you'd like** A clear and concise description of what you want to happen. **Describe alternatives you've considered** A clear and concise description of any alternative solutions or features you've considered. **Additional context** Add any other context or screenshots about the feature request here. clifm-1.26.3/.github/ISSUE_TEMPLATE/issue_template.md000066400000000000000000000012671506632037700220040ustar00rootroot00000000000000--- name: Bug report about: Create a report to help us improve title: '' labels: '' assignees: '' --- **Describe the bug** A clear and concise description of what the bug is. **To Reproduce** Steps to reproduce the behavior: 1. Run '...' 2. Then run '....' 3. See error **Expected behavior** A clear and concise description of what you expected to happen. **Screenshots** If applicable, add screenshots to help explain your problem. **Desktop (please complete the following information):** - OS: [e.g. FreeBSD] - Terminal [e.g. xterm, alacritty] - Clifm version [e.g. 1.4] - Installation source [e.g. OBS, AUR, Git] **Additional context** Add any other context about the problem here. clifm-1.26.3/.github/workflows/000077500000000000000000000000001506632037700163035ustar00rootroot00000000000000clifm-1.26.3/.github/workflows/cmake.yml000066400000000000000000000026041506632037700201100ustar00rootroot00000000000000name: CMake Build on: push: branches: [ master ] pull_request: branches: [ master ] env: # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.) BUILD_TYPE: Release jobs: build: # The CMake configure and build commands are platform agnostic and should work equally well on Windows or Mac. # You can convert this to a matrix build if you need cross-platform coverage. # See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix runs-on: macos-latest steps: - uses: actions/checkout@v4 - name: Install dependencies run: | curl -fsSLO "https://github.com/l2dy/clifm-ci-files/releases/download/v0.0.2/clifm-bootstrap.mpkg" sudo installer -pkg clifm-bootstrap.mpkg -target / echo "/opt/local/bin" >> $GITHUB_PATH - name: Configure CMake # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} - name: Build # Build your program with the given configuration run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} clifm-1.26.3/.github/workflows/codecov.yml000066400000000000000000000005321506632037700204500ustar00rootroot00000000000000name: Codecov on: workflow_dispatch: jobs: run: runs-on: ubuntu-latest steps: - name: Fetch run: | git clone https://github.com/leo-arch/clifm cd clifm/misc/codecov - name: Upload uses: codecov/codecov-action@v1 with: files: ./*.c.gcov # files: ./lib.c.gcov clifm-1.26.3/.github/workflows/codeql-analysis.yml000066400000000000000000000051131506632037700221160ustar00rootroot00000000000000# For most projects, this workflow file will not need changing; you simply need # to commit it to your repository. # # You may wish to alter this file to override the set of languages analyzed, # or to provide custom queries or build logic. # # ******** NOTE ******** # We have attempted to detect the languages in your repository. Please check # the `language` matrix defined below to confirm you have the correct set of # supported CodeQL languages. # name: "CodeQL" on: # push: # branches: [ master ] pull_request: # The branches below must be a subset of the branches above branches: [ master ] workflow_dispatch: schedule: - cron: '23 7 * * 5' jobs: analyze: name: Analyze runs-on: ubuntu-latest permissions: actions: read contents: read security-events: write strategy: fail-fast: false matrix: language: [ 'cpp' ] # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ] # Learn more: # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed steps: - name: Checkout repository uses: actions/checkout@v4 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL uses: github/codeql-action/init@v3 with: languages: ${{ matrix.language }} queries: +security-and-quality # If you wish to specify custom queries, you can do so here or in a config file. # By default, queries listed here will override any specified in a config file. # Prefix the list here with "+" to use these queries and those in the config file. # queries: ./path/to/local/query, your-org/your-repo/queries@main # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) #- name: Autobuild # uses: github/codeql-action/autobuild@v1 # ℹ️ Command-line programs to run using the OS shell. # 📚 https://git.io/JvXDl # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines # and modify them (or add more) to build your code if your project # uses a compiled language - name: Install deps run: | sudo apt-get install make gcc libcap-dev libreadline-dev libacl1-dev libmagic-dev - name: Compile Clifm run: | make - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@v3 clifm-1.26.3/.gitignore000066400000000000000000000002251506632037700146750ustar00rootroot00000000000000# Main app clifm # Gcov files src/*.gcov src/*.gcda src/*.gcno # Misc TODO/ clifm-debian/ test/ .obs/ images/ src/term_info.sh # Object files *.o clifm-1.26.3/CHANGELOG000066400000000000000000003307301506632037700141260ustar00rootroot000000000000001.26.3 - Sep 28, 2025 BUG FIXES: * Warning prompt color is broken. * Single character commands not recovering from warning prompt. * Run with "-T ~/trashfile", create a file named ~/trashfile2: this latter cannot be trashed. * Freeze when running non-interactively and in the background. * Some GTK programs chash when launched from within clifm (XDG_DATA_DIRS corruption). IMPROVEMENTS: * Replace --stdtab, --fzftab, --fzftab, and --smenutab by --tabmode=fzf|fnf|smenu|standard. * Prevent shell commands from leaving the terminal in an unusable state. * Improved key binding translation support (via the keypress translation library). * Allow the use of colon as color field separator. MISC: * Remove --fzytab (deprecated since 1.12.9). 1.26 (Fettucini Bros) - Jul 21, 2025 BUG FIXES: * No field printed after 'S' in long view. * No prompt in case of F1-F3 failure. * The 'stats' command does not count files with extended attributes. * --secure-cmds: Only the first mime placeholder (%) is sanitized: in "CMD %f %u", "%u" won't be checked. * 'p' command: no size in bytes when size is exactly 1k. * 24bit SGR sequence with foreground, background, and underline color (kitty) not working. * Accept first suggested word (Alt+f) fails with Unicode string. * './' lists only executable files and directories, even if auto-open is enabled. * Though "w:" is a reserved keyword (for workspaces), filename validation (when creating new files) does not warn about it. * "--sel-file=\\/" is interpreted as the current directory instead of the root dir. * Cannot trash '~/trashdir2' if the trash directory is '~/trashdir'. * Bad error message when a short option with a Unicode character is used. E.g.: 'clifm -ö' complains "clifm: 'clifm': Unrecognized option", when it should be '-ö'. * 'view edit' does not open the alternative shotgun file, but the default one. * 'mm info' ignores alternative shotgun file. * 'mm info' refuses to run on privileged files. * Double screen refresh after running a keybinding. * 'ow' does not support %m and %u placeholders. IMPROVEMENTS: * The 'icons' command toggles icons when used without parameters. * Harden alternative config dirs/files checks: avoid using non-dirs/reg_files respectively. * Better autodetect tab completion mode: use any of fzf, fnf, or smenu if the appropriate binary is found in PATH (and not specified otherwise in the command line or in the configuration file). * Allow tab completion for ELNs in the bookmarks screen. MISC: * Lots of code cleaning and improvements. 1.25 (Scumm Bar) - May 3, 2025 BUG FIXES: * 'kb': Some escape sequences are not properly translated (e.g. '\e[200~' for 'bracketed-paste-begin'). * Create a file (n file) and then remove it (r file). Press Alt+n and then Enter: a file named "n" is created! The same happens with 'le' and 'm' (interactive rename) when pressing Enter on empty line. * Some legacy terminals (like the FreeBSD console) froze as soon as we try to query some data from it. * 'kb bind' does not allow to switch keybindings (for example, setting F1 for bookmarks and Alt+b for show-manpage). * 'Alt+h' runs a wrong command name ('bh'). * 'Ctrl+Alt+t' attempts to trash a file named 'sel' when there are no selected files. * The 'extension' sort method takes hidden files as file extensions. * No Tab completion for the 'hidden' command. * '--disk-usage': No device name when running on Termux (Android). * Positional parameter: cannot open file URI encoded directory names. * Positional parameter: If file contains references to self or parent dir ('.' or '..'), the path is not properly resolved. * '--data-dir' rejects '/usr/share/clifm', even when this is the actual data directory. * the '=g' filter skips some files with the SGID bit set. * Compilation error on MacOS Leopard (10.5). * The 'j' command fails to change directory with escaped directory names. NEW FEATURES/IMPROVEMENTS: * Add support for the kitty keyboard protocol. Use the --kitty-keys command line flag to ask the terminal to enable this protocol. Consult the manpage for more information. * Add support for styled underlines. See https://sw.kovidgoyal.net/kitty/underlines/#colored-and-styled-underlines * Add support for the Kitty Notifications Protocol (https://sw.kovidgoyal.net/kitty/desktop-notifications/). Enable via '--desktop-notifications=kitty' in the command line or 'DesktopNotifications=kitty' in the configuration file. * If running in vi editing mode, print "(ins)" or "(cmd)" (for insert and command modes respectively) at the left of the prompt. Use the '\v' prompt escape code to handle this notification manually. * New bindable action: 'toggle-vi-mode' (bound by default to Ctrl+Alt+j). Update your 'readline.clifm' and 'keybindings.clifm' files. * Force the use of a specific color palette via $CLIFM_FORCE_COLOR (supported values: 8, 16, 256, truecolor or 24bit). * Improve 'kb bind' function (more sensible prompts and better overall flow). * Allow setting multiple keybindings for the same action. 'show-manpage2', for example, is not required anymore: just define an extra keybinding for 'show-manpage'. * Better organization for the keybindings file (update your keybindings file). * '--show-hidden','-a' now take 'true', 'first', 'last', and 'false' as optional parameters (if no parameter is given, 'true' is assumed). * Add 'first' and 'last' parameters to the 'hh'/'hidden' command. * New prompt escape codes: \Q (number of regular and special files); \g (current sort order), \j (octal permissions of the current directory). * New prompt ('counter'), using the above new prompt codes. * Image preview support for iTerm2. Set $method to 'iterm' in the clifmimg script to force the use of this protocol. Update your clifmimg script. * Allow the use of multiple positional parameters. For example, 'clifm /etc ~/Downloads' will start clifm in the '/etc' directory (first workspace), setting the second workspace to '~/Downloads'. * Consistent format for setting messages (on/off). * Make bulk rename work with 'vis' and 'helix' text editors: 'br' was complainig about the tmp file having changed on disk due to how these editors save files by default (via rename(2)). MISC: * '--no-apparent-size' is deprecated. Use '--physical-size' instead. * '--no-files-counter' is deprecated. Use '--no-file-counter' instead. * 'undel' command is deprecated. Use 'u/untrash' instead. * 'splash' command removed. 1.24 (Toothrot) - Mar 2, 2025 BUG FIXES * File extension conflicts in 'default' color scheme (16-color version). * Wrongly sorting Unicode file names ('name' and 'version' sort). * When sorting by 'extension', 'CaseSensitiveList=true' is ignored. * The value of 'PagerView' is ignored when 'Pager' is set to a value >=1. * Pressing 'c' while in the pager stops listing (like 'q'). * Running plain 'pg' overwrites the value of 'Pager' in the configuration file. * When mounting a FS via 'net mount', autocommands for this directory are not immediately executed. * The 'ad' command complains that '.rpm' and '.deb' files are not archive/compressed files. * 'name' sort behaves like 'version' when file names start with numbers. * Not properly clearing the screen on Eterm terminal. * Wrong image size when previewing images on the Ghostty terminal. * The profiles function is broken (no config file change, system messages are not reset). * Wrong file color when TAB completing globs after a path (e.g. dir/*.jpg). * When there's only one profile Ctrl-Alt-p clears the screen and still attempts to the change the profile. * If we have no access to the main configuration directory, the selections file is created in '/tmp' instead of '/tmp/clifm_$USER'. * If we have no access to the main configuration directory, selected files are not written to the selections file. * TAB completion: Matches not sorted alphabetically in FZF (e.g. ls --). Update your color scheme files. * Wrongly identifying extension conflicts when running with '--lscolors'. * '/dir/GLOB' (e.g. '/bin/p*') do not generate previews whenever it is the first word. * The 't' command informs a wrong size for the trash directory. * No lock icon for non-regular files. * A few wrong colors when any of 'xs' and/or 'xf' color codes are unset (affects old color schemes). * Kilobyte written as 'KB' instead of 'kB' when using decimal sizes ('--si'). * Ctrl-Alt-b does nothing (points to non-existent function). Removed. * Cannot rebind 'bookmarks' to 'Alt-b': clifm complains that this key conflicts with readline and refuses to continue. * Unsetting a keybinding via 'kb bind' does not work. NEW FEATURES/IMPROVEMENTS * clifmimg: Drastically reduce the size of postscript thumbnails (1500%!). Update your 'clifmimg' script. * Preview: add support for several image formats (dpx, jp2, miff, sgi, and wmf among others). Please update your 'preview.clifm' file. * 'mimelist.clifm' and 'preview.clifm' config files: The '%m' placeholder expands to the file's MIME type. * Add support for OpenRaster images (open/preview). * Add sixel support auto-detection for Yaft. * Add support for '.rpm', '.deb', '.arj', '.Z', and '.cab' archives (open) * Preview: list files in '.ztd', '.rpm', and '.deb' archives. * Preview: add support for krita images ('.kra' and '.krz'), via the 'krita' method in cligmimg. * Use 'PrioritySortChar' in the configuration file (new) to pin file names starting with 'PrioritySortChar' to the top of the files list. * Two new values added to the 'ShowHiddenFiles' option: 'first' and 'last', to list hidden files first or last. * Manually map file extensions to MIME types using the '~/.mime.types' file. Consult the manpage for more information. * Allow setting multiple chars in 'PrioritySortChar' option. * Report the current directory to the underlying terminal (via the OSC-7 escape sequence). To enable, run with '--report-cwd'. * Try harder to create a valid temporary directory (mostly in case of denied access to the directory). * If '--lscolors' (using FreeBSD LSCOLORS), read extension colors from the color scheme file. * Improve 'kb' command: attempt to display human-readable key presses (e.g. Shift-Up) instead of raw escape sequences (e.g. "\e[1;2A"). MISC * $CLIFMRC cannot be used anymore to set the path to the main configuration file (use '-c,--config-file' instead). * If 'nf' color code (unaccesible file) isn't set, use whatever color corresponds to the current file type and prepend and exclamation mark to the corresponding entry in the files list to mark it as unaccessible. Same for 'nd' (unaccessible directory). * --no-trim-names, TrimNames, and MinFilenameTrim were renamed to --no-truncate-names, TruncateNames, and MinNameTruncate respectively (old names are deprecated). * 'open-sel', 'untrash-all', and 'move-sel' keybindings are unset by default. * 'copy-sel' can be used as an alias for 'paste-sel' in keybindings. 1.23 (Piranha poodle) - Jan 20, 2025 BUG FIXES * TAB completion: file names with embedded control chars are not properly colorized. * TAB completion: no preview for file names with embedded control chars. * Image previews: 'img2txt' method not working for ANSI images ('clifmimg'). * 'view' command not working when running with '--stdtab'. * 'cl,columns' command stopped working. * 'sel *.pdf' works, but 'desel *.pdf' doesn't. * Opening applications using the '%x' flag (mimelist file) not working with '--secure-cmds'. * 'MaxFilenameLen=-1' (in the config file) is ignored. * Garbage on the command line running a keybinding in vi-mode. * Wrong image placement (ueberzug method) when '--height' is set from either $FZF_DEFAULT_OPTS or 'FzfTabOptions'. * Config: 'cmCmd=5' (rsync) does not copy directories themselves (but its content). * Cannot operate on file names containing REGEX characters (e.g. the command 's c++' REGEX expands 'c++'). * --preview/--open fail when given a file URI with percent-escaped characters (e.g. 'file:///home/user/this%20file.txt'). * Cannot open file with single quote in name (e.g. "John's file.txt"). NEW FEATURES/IMPROVEMENTS * Add file preview for javascript files. * Image previews: add support for exr, fit, hdr, heic, pbm, pgm, pnm, ppm, and xpm image formats. * Properly fail when '--opener' is given no parameter. * 'x' command: expand environment variable in TerminalCmd (first word only). * 'x' command: run terminal detached (via setsid(3)). * 'X' command: do not run with 'sudo' if already root. * Set the main configuration file path via $CLIFMRC. * Add '--help' to the 'reload' command. * 'config reload' can be used now instead of 'reload'. * Add '--mimelist-file' command line option to set an alternative mimelist file. * Check for file existence when setting alternative configuration files. * New prompt module (m_hostname_color): dinamically colorize the hostname depending on whether we're on a SSH session or not. * Adjust the number of spaces between icons and file names using the 'IconsGap' option in the configuration file. Valid values: 0, 1 (default), or 2. * Explicitly check $XDG_DATA_HOME and $XDG_DATA_DIRS when setting clifm's data directory. * Add builtin confirmation prompt to 'c' and 'm' commands. * Set a default answer for confirmation prompts via 'DefaultAnswer' in the config file (default value: "o:n,r:n,t:y,R:n,d:y"). This means: "no" for overwrite (includes 'c' and 'm' commands), remove, and bulk rename, "yes" for everything else (including trash). * Create files from templates using the 'n' command. Run 'n --help' for more information. * 'p/pp' command: print both apparent and physical sizes. * Make '--lscolors' able to understand $LSCOLORS (FreeBSD style). * Purge the thumbnails directory of dangling thumbnails using the 'view purge' command. Remember to update your 'clifmimg' script to start populating the thumbnails database: 'cp /usr/share/clifm/plugins/clifmimg ~/.config/clifm/'. Note that the thumbnails directory has been changed from '$XDG_CACHE_HOME/clifm/previews' to '$XDG_CACHE_HOME/clifm/thumbnails'. You can remove the old directory: from now on thumbnails will be stored in the new directory. * Both the mimelist and the preview configuration files now support the '%u' placeholder, which is expanded to the file URI for the original file name. * 'clifmimg': Generate thumbnail names as MD5 hashes of the file URI for the original file name (as recommended by the FreeDesktop specification - https://specifications.freedesktop.org/thumbnail-spec/latest/thumbsave.html), instead of hashing the file itself. This brings a nice performance improvement, specially when it comes to large files. This works along with the '%u' placeholder mentioned above. Update your 'clifmimg' script. * Prevent big files from generating a preview via 'PreviewMaxSize' in the config file. Supported size units: K, M, G, T; supported size range: 1K-2047G. E.g.: "PreviewMaxSize=100M". * Colorize .csv files as documents (default color scheme). * Colorize .sass and .scss files as markup files (default color scheme). * Sort completion matches for mimetype filter (@). * Add previewing app info to 'mm info' command. 1.22 (Banana picker) - Nov 23, 2024 BUG FIXES * Wrong query string when TAB completing tagged files and '--fuzzy-match' is enabled. * When pressing Ctrl-Alt-[d,x] on a secondary prompt the cursor moves up one line. * '--rl-vi-mode' not working if 'RlEditMode' is set in the config file. * No image preview for powerpoint files. * Wrong ueberzug image offset when fzf preview window border is set to 'border-[right,thinblock]'. * When clearing the screen, the scrollback buffer is not cleared on rxvt-based terminals. * Not using all available columns when running with '--no-eln'. * TAB completing file names in the 'pc' prompt after the first word. * Some keybindings (Alt-TAB, Alt-v, Alt-p) are operative in secondary prompts, when they shouldn't. * Garbage in the command line when trying to switch workspaces via a keybinding in a secondary prompt. * F12 (quit) not working on secondary prompts. * 'echo ELN' does not expand to file name (while 'stat ELN' does). * 'mf' command expands numbers to ELN's. * When multiple system messages are generated, only the last one is displayed in the prompt. * Negation ('!') does not work for workspaces and double asterisk expressions in autocmds. * Help messages ignore the command line text color. * The 'n/new' command issues a warning when attempting to create a file in the home directory using the tilde ('~/FILE'). * File previews (TAB completion or the 'view' command) ignore alternative preview file (set via either '--shotgun-file', '--config-dir', or '--profile'). * 'rr' does not work with directory names containing spaces (e.g. 'rr this\ dir'). * The 'open/preview' function matches directories as valid opening applications. NEW FEATURES/IMPROVEMENTS * Extra file type filters for the '=' keyword: 'D' for empty directories, 'F' for empty regular files, and 'L' for broken links. On Solaris, the 'D' file type char (previously used for door files) was replaced by 'O'. * Use the 'kb bind' command to customize your key bindings instead of manually editing the keybindings file (via 'kb edit'). * 'kb conflict' now checks for readline key bindings as well. * Proper error messages when appliaction does not exist/fails while previewing images (clifmimg). * Add image previewing method for mobi files (clifmimg). * Add support for legacy image formats: bmp, ico, pcx, and tga (clifmimg). * Automatic detection of image preview method. Update your clifmimg script (~/.config/clifm/clifmimg) (just remove it and restart) to make use of this new feature. By default, Clifm and the 'clifmimg' script will try to guess the best previewing method (sixel, ueberzug, kitty, or ansi). Edit the 'method' variable in the 'clifmimg' script to manually set a previewing method. * A more modern interface: If Unicode support is detected, Clifm will draw decorations using Unicode characters (use '--no-unicode' to disable Unicode decorations, and '--unicode' to force it). * The selected files indicator in the prompt was replaced by 'S' (previously '*'). * Right pad and colorize ELN's in dirhist map. * The color scheme is checked at startup for file extension conflicts. If found, the user is warned. * Use 'cs check-ext' command to manually check for file extension conflicts. * Display bookmarked paths in the bookmarks screen. * Add names completion to the bookmarks prompt in the bookmarks screen ('bm' command). * Several improvements to the 'vv' command. * Allow using tilde (~) for the home dir when editing a symbolic link ('le' command). * Active files filter ('ft' command) is always displayed. * Add files filter ('ft') and full-dir-size ('fz') to autocommands. * Allow using names for 'st' in autocommands. * Use the 'auto' command to set a temporary autocommand for the current directory. Run 'auto --help' for more info. * New config file option: 'InformAutocmd' to control how matching autocommands are displayed in the prompt. Available values: 'none', 'short', 'long', 'full', and 'prompt' (default). * Better columns arrangement when listing files (vertical list only). * Lira: make opening applications invoked with the '%x' flag run in a new session (detached from the terminal) (via setsid(3)). * Lira: Check for 'Calligra' and 'Gnumeric' when opening office documents. * Add 'N file(s) copied/moved' message to 'c' and 'm' commands. * Set 'TrashForce' to false by default. * Do not print the list of removed/trashed files after files removal/trash. * Enable file system type and mountpoint (via '--disk-usage') on Cygwin/MSYS2/Solaris. 1.21 (Lemonhead) - Sep 30, 2024 BUG FIXES * 'TimeFollowsSort' and 'TimestampMark' are missing in 'config dump'. * $XDG_DATA_HOME ignored when setting the trash directory. * Memory leak when trashing files and the trash info file cannot be opened. * When 'PrintDirCmds' is unset, it is marked as modified by 'config dump'. * Image previews not working on Kitty terminal. * Double confirmation prompt when removing write-protected files from the trash can. * The 'mime_list.sh' plugin is broken. * The 'mime import' command fails to import lines with a MIME type containing dots. * Cannot auto-open/autocd files starting with '#' and containing characters that need to be escaped (e.g. "#%${}", etc). * Completions/suggestions not working in chained commands. * Query string ignored when untagging files (TAB completion). * The -E option prints garbage next to ELN's on some terminals. * The fzfhist.sh plugin (bound to the 'h' action name) lists timestamps along with history commands. * Out of date files list after unmounting remote. * Suggestion not removed after pressing Enter. NEW FEATURES/IMPROVEMENTS * Ask for confirmation when trashing files (enable by setting 'TrashForce' to false in the config file). * Allow sorting files by file type (including executable files and file extensions): 'st type'. * Sort user and group by names, not numbers, if using ID names in long-view (see the 'PropFields' option in the configuration file). * Increase the number of bindable plugins from 4 to 16. * Read CLIFM_COLUMNS and CLIFM_LINES from the environment. * Fix columns/colors issue in the pager.sh plugin ('gg'). * Export status values (as environment variables) when running plugins. Consult the ENVIRONMENT section of the manpge for more information. * The following environment variables are now set only when running a plugin: CLIFM_PLUGINS_HELPER, CLIFM_SELFILE, CLIFM_PROFILE, and CLIFM_COLORLESS. * Plugins are disabled in 'secure-cmds' mode (it just makes sense). * Sanitize aliases when running in 'secure-cmds' mode. * New alternative color notation for the prompt: '%{color}'. See the new prompts file for details. * Add support for right prompts. See the new prompts file for details. * Allow the use of 3-digit HEX colors (e.g. #ef0 amounts to #eeff00). * New plugin: 'file_picker.sh' (removed old file_picker shell functions). * Implement fish-like abbreviation of the current directory in the prompt via the '\f' prompt code. * Implement prompt modules (via ${module}). * Use the '\b' prompt code to print the execution time of the last command. * New prompt ('pez'), implementing the new fish-like path abbreviation. * New prompt ('git'), implementing the new prompt modules feature. * New prompt ('timer'), implementing the new '\b' prompt code (last command execution time). * New prompt ('info'), implementing a right prompt. * '--max-path' and 'MaxPath' are deprecated in favor of the CLIFM_PROMPT_P_MAX_PATH environment variable. * Workspace expansion via the 'w:' construct. Example: 'c 2 w:3' to copy the file whose ELN is 2 to the third workspace. * Make 'history show-time' list timestamps and commands on the same line. 1.20 (Madam Xima) - Aug 16, 2024 BUG FIXES * The pager counter ovewrites the last entry (when columns is off or file names aren't trimmed). * 'ow' does not work on symlinks. * 'ow' does not work on file names containing spaces. * Cannot run internal command or alias in a directory containing a file named like the command/alias. * File names containing unnamed control char, line separator, or paragraph separator characters are not properly displayed. * Reading CDPATH even if running with '--secure-env'. * Enter key not working in the pager when invoked via keybinding (Alt-0). * File name with embedded DEL or C1 control chars breaks columns. * 'Bleach' cannot handle names with embedded DEL chars. * renameat(2) not found when compiling on MacOS < 10.10. * "hidden" option for 'FzfPreview' not working. * 'kb' informs "no keybindings defined" after switching profiles. * Broken prompt color when using hex colors for workspaces. * Scrollback buffer not removed when clearing the screen on Kitty (mostly because kitty does not report having this capability. See https://github.com/kovidgoyal/kitty/issues/268. * Wrong reported total size in the selection box. * No selected files indicator in stealth mode. * Error exit code (1) when deselecting all files in stealth mode. * Empty file color is overriden by the file extension color. * Ignoring 'mi' code when reading LS_COLORS. * Buffer overflow when trimming down file names in long-view and MaxNameLen is unset. * "Total size" field in 'pp' informs NULL color when the 'dz' color code is set. * The size fields at the bottom of the disk-usaga-analyzer screen ignore the size color ('dz') if it is set. NEW FEATURES/IMPROVEMENTS * Prevent external commands from refreshing the current list of files by setting 'ClearScreen' to 'internal' in the config file. * Keep in sight commands executed in the current directory via 'PrintDirCmds' in the config file. * When 'ColorLnkAsTarget' is enabled, color the selected file indicator using the same color used by the link indicator if the selected file is a symlink. * Conform to the CACHEDIR.TAG specification when creating cache files (image previews). * Choose how 'l' creates symbolic links (absolute, relative, literal) via 'LinkCreationMode' in the config file. * Allow colorizing the custom welcome message ('WelcomeMessageStr') via escape codes. * Alt-[5-9] keybindings are now disabled by default (in 'readline.clifm'). * Disallow the use of clifm for $SHELL (it will brake programs using '$SHELL' to spawn other programs - e.g. 'fzf --preview'). * Specify 8-bit (256 colors) colors using the '@NUM[-ATTR]' notation in color scheme files. * Improved and more useful 'colors' screen. * More intuitive and easily customizable default color scheme files. * Removed deprecated commands: 'bh', 'fh', and 'edit'. * Removed 'fs' command (what is free software?). * Removed the 'bm' color code (bookmark names in the bookmarks screen are now printed using the target file color). * Add 'preview' subcommand to the 'cs' command (same as 'colors', but more consistent). * Add Loupe (Gnome new image viewer) as opening application (mimelist file). * If sorting files by time, use the same time files are sorted by for the time field in long view (via 'TimeFollowsSort'). * Append an identifying character to timestamps (long view) (via 'TimestampMark'). Color code 'dt'. * The 'dg' color code is now used for group IDs, while the new one, 'du', is used for user IDs. If 'du' isn't set, we fallback to the old behavior: 'dg' is used for user IDs, and group IDs are printed using a dimmed version of 'dg'. * Remove the Unicode option from the configuration file. It has no effect anymore. * When scanning directories (full-dir-size and long-view, or disk-usage-analyzer), print currently scanned subdirs. * Disk usage analyzer: largest file not printed if sorting by size (redundant). * Use the 'dz' color code (for file sizes) for both dirs and regular files (if the code is set). 1.19 (Kozy Krypts) - June 18, 2024 BUG FIXES * Color for error code (xf) printing garbage on some terminals (ConEmu/Mintty). * Pressing Ctrl-z while running an external command leaves the shell in an unusable state. Workaround: SIGTSTP (Ctrl-z) disabled for external commands. * If the fzf option '--border' is set, long file names in TAB completion are trimmed. * Cannot pin file names containing spaces. * Wrong cursor position when suggesting file names reaching the end of the screen and the typed text contains backslashes. * './symlink' is resolved to target file when bulk renaming. * 'rr' attempts to remove files starting with '#'. * Extension colors not processed after double colon. * Wrong 'Blocks' field padding in 'p/pp' command when file is a socket/fifo. NEW FEATURES/IMPROVEMENTS: * 'pp': Count files in directories. * 'p/pp': Display files MIME type. * 'p/pp': Enclose file names containing spaces in single quotes. * Mimelist file: Add '%x' as short for '%f !EO &'. * Mimelist file: Widely use the new '%x' to run GUI opening applications detached. * du(1)-free code. * Set a custom keybinding for the commands history list (same as '!') via "cmd-hist" in the keybindings file. * Detect key bindings conflicts via 'kb conflict'. * Add '--physical-size' as an alias for '--no-apparent-size'. * Check for duplicate/existing files before bulk renaming. * Colorize config files (default-256 theme, defined as CONFIG). * Add more audio files to default-256 color scheme. * Add .djv and .xbel extensions to default color schemes. * Allow multiple ExtColors lines in the color scheme file. * Allow file extensions without the '*.' prefix in the color scheme file. 1.18 (Caniche endormi) - March 23, 2024 BUG FIXES * Color for temp/backup files not working when it's hex. * Negative dir sizes when running with '--list-and-quit --long-view --full-dir-size'. * Wrong padding in long view when max-files is set. * File names starting with non-alphanumeric characters are listed after alphanumeric names, unlike 'ls' and company. * Wrong files listed when TAB completing with "../" and the current directory is a symlink. * Cannot cd to "../" if the current directory is a symlink. * Misleading values in long view when stat(2) fails. * Printing garbage when running 'pp' on a broken link. * 'ft' command not working with file type filters (ex: 'ft =d'). * If '--invalid-option --valid-option', clifm complains about '--valid-option'. * Cannot run external command on '../dir/file name'. * Alt-Right keybinding not working as expected. * Long file names not trimmed when going back from the pager help. * PrintSelfiles not updated automatically after editing the configuration file. * TAB completion for external commands working only for first parameter. NEW FEATURES/IMPROVEMENTS * Allow hiding files listed in a '.hidden' file (includes wildcards support) via 'ReadDotHidden' in the config file. * Several improvements to the long view mode: * Use '-L,--follow-symlinks-long' to dereference symbolic links in long view. * New command 'k', to toggle follow-links in long view (keybind 'Alt-+'). * Allow ID names (instead of just numbers) via 'I' in PropFields (not available on Termux). * User/group names (instead of ID numbers) is the new default for PropFields. * Birth time support (via 'b' in PropFields). * Hard links number support (via 'l' in PropFields). Color code: 'dk'. * File allocated blocks support (via 'B' in PropFields). Color code: 'db'. * Allow not printing group information (via 'G' in PropFields). * Add missing color code for file inode number: 'de'. * Allow setting fields from the command line via '--prop-fields=FORMAT' (same values as PropFields). * Allow double space between fields via 'PropFieldsGap' in the config file. * Consistent long view colors for nord, base16, and zenburn color schemes. * Improve files counter: '0' for empty dirs, '?' for dirs with no read permission, and '-' for no-dirs. * Consistent color for backup/temp files if TEMP isn't defined in the color scheme file. * Make 8 color themes use 5 shades instead of just 3 (like 256-color and truecolor themes). * Add '--ls' as short for '--list-and-quit'. * Allow '--stat' and '--stat-full' to process multiple files at once (ex: '--stat FILE FILE2 ...'). * keybinds/suggestions/TAB-comp: exclude sorts not available in light mode. * Security: autocmd files won't be read if running on an untrusted environment ('--secure-env' or '--secure-cmds'). * Set time style via --time-style (long view) and --ptime-style (p/pp command). * Support for TIME_STYLE (long view) and PTIME_STYLE (p/pp command). * Allow sorting files by 'blocks' and 'links'. * Make "Sort" in the config file accept names, and not just numbers. * New command 'kk' to toggle max-filename-len. * 'p/pp' command: Do not abbreviate symlinks target. * Add '--color-links-as-target' command line option. * Improve extra color schemes. * Allow running the pager only once via 'pg once'. * Add keybinding to run the pager (Alt-0). * Set the pager listing mode via 'PagerView' in the config file or '--pager-view' in the command line. BREAKING CHANGES: * Since 1) it was unintuitive to have '-a' and '-l' to **disable** hidden files and long view respectively (instead of enabling them, like most files listers do (ex: ls, exa, eza, lsd)), and 2) we were using uppercase options sometimes to enable and sometimes to disable features (which is not consistent), we made the following changes: * -a enables hidden files and -A disables it * -f enables dirs-first and -F disables it * -l enables long-view * -L like ls(1) -L option (long form: --follow-symlinks-long) * -o enables autocd and -O disables it 1.17 (Lechuck) - Feb 9, 2024 BUG FIXES * When quitting via a keybinding, clifm breaks pasting into the terminal from the clipboard. * Files not colored by extension in the 'trash list' screen. * $COLUMNS and $LINES not set in 'clifmimg' script if running with '--preview'. * "ow dir/" inserts space char instead of listing subsdirs in dir. * "ow FILE APP" fails with "Key has expired" when APP does not exist. * No error message when using a custom resource opener. * Opening a file named 'config' (in the CWD) instead of running the command 'config'. * Segfault when bleach temp file is removed in the middle of the operation. * 'bl sel' command creates broken symbolic links when directory in path contains spaces. * Bookmarks named "q" or "quit" cannot be opened in the bookmarks screen (these names are now disallowed). * Segfault when processing more than 32 quoted words in the command line. * Expanding quoted ELNs for external commands. * Underlined color attribute for non-existent bookarmks takes files list after bookmarks screen. * Cannot import aliases from file name containing spaces. * Success exit code (0) when temp file changed on disk while bulk renaming/removing. * Cannot remove directories from the trash can. * 'md' sometimes fails as 'new'. * Success exit code when 'new' fails to create file. * Desel screen not working with incomplete ranges (no second field). * Virtual directories: directories, file type and MIME type expansions, file names containing spaces, selection, and globbing/regex not working. Also, cannot virtualize files names containing spaces and passed by ELN. * 'p/pp' cannot handle relative symbolic links. * 'l/le' do not allow creating relative symbolic links. * Some plugins not working with file names containing spaces. * Symlinks to directory shown when both 'only-dirs' and 'no-follow-symlinks' are enabled. * Wrong finder offset for paths containing spaces when running with --fuzzy-matching. * Quick-help not opened via pager (Solaris/Haiku). NEW FEATURES/IMPROVEMENTS * Add total size to 'trash list' screen. * Implement exit code 126 (as defined by POSIX: see exit(1p)). * Print amount of symbolic links created with the 'bl' command. * 'bl': Do not ask for links suffix: use the original filename (plus integer suffix to make it unique). * Bookmarks screen: Allow entering bookmark names containing spaces without using backslashes. * Allow bookmarking the same path multiple times. * Make cd-on-quit work with plain 'q' command. 'Q' (uppercase) command is deprecated. * Confirmation dialog for 'history clear'. * Confirmation dialog when removing files from trash. * Autocommand files ('.cfm.in' and '.cfm.out') won't be read unless 'ReadAutocmdFiles' is set to 'true' in the main config file. * Hardened autocommand files: They will be read only provided they are: non-empty regular files of at most PATH_MAX bytes, and no NUL byte is contained in them (to minimize the chances of executing random content from a binary file). * Allow marking specific jump entries as permanent. Consult the manpage for more information. * Properly right pad human sizes in long view. * Allow properties fields order customization in long view mode via PropFields. 1.16 (Big Whoop) - Jan 9, 2024 BUG FIXES * Wrong cursor position after keybind if the last exit code was error. * Black screen when changing profile via keybind and starting path does not exist. Trying to access a file immediately after the black screen segfaults. * When sorting files by extension, dir names containing a dot are sorted by their "extension" (but dirs do not have extensions). * Cannot create bookmarks if there are zero bookmarks. * Alternative config files (-c, -b, and -k) and config dir (-D) ignored after editing the main config file. * Wrong error message when valid command line option is followed by an invalid one. * Trash counter underflowed when there's no trash directory. * 'clifm -c -V' wrongly assumes that -V is a parameter to -c. * Error message not shown when removing files. * Freeze when CLIFM_FILE_COLORS is set to empty string. * 's *.conf :/dir': .conf files selected in the CWD if /dir does not exist. * Prompts for 'pc' and 'oc' commands allow commands history. * The extraction path prompt ('ad' command) is broken. * 'n file file/' reports two created files, but only one was actually created. * Cannot trash 'file' and 'dir/file' at the same time (name colition). * Binaries loaded multiple times if there are dups in PATH. * Directories in paths (in PATH) taken for actual binaries. * 'p/pp' and 'le' commands do not properly handle symlink to symlink. * No error message on bulk rename error ('br' command). * Cannot bulk rename directories on DragonFly BSD. * No (or wrong) trash indicator after error trashing a file. * "rr" opens temp file even if the current directory is empty. * Some config files not created with restrictive permissions. * Long view: file names with long extensions are not trimmed correctly. * Crash (divide by zero) when MaxJumpTotalRank is set to zero. * MaxPrintSelfiles not working with -1. * Segfault when PATH is longer than 4096. * "s01" selects the first listed file, but triggers the warning prompt. * "n 1" takes "1" as an ELN (and attempts to create the corresponding file) instead as a new file name. NEW FEATURES/IMPROVEMENTS * ".." now suggests the parent directory (this makes it more consistent with the fastback function). * Allow setting the umask from the config file via the 'Umask' option. * 'md' now runs 'n' internally instead of mkdir(1). * Added .3gp file extension to default color schemes (as VIDEO) and .vsix as ARCHIVE. * Sort file extensions alphabetically in default color schemes. * Inform the user whenever at least one file is excluded from the files list (hidden, filtered, only dirs). * If an alternative config file does not exist, create it. * Allow setting an alternative trash directory via '-T','--trash-dir'. * Make the 'r' command always ask for confirmation before removing files. * LS_COLORS support via '--lscolors' (GNU ls style only). * Security: use pledge(2) on OpenBSD. * Security: Check temporary files consistency when bulk renaming/removing. * Security: Check files consistency before removals. * Clear the screen when (re)loading the 'untrash' and the 'trash del' screens. * When restoring a trashed file, create parent directories as needed. * If the second field of a range of ELNs is omitted, the ELN of the last listed file is assumed. * Inform amount of renamed files when bulk renaming ('br' command). * Allow rename across devices when bulk renaming. * No more sticky bit: temporary directory now created as "/tmp/clifm-USER" (700 permissions). * Let the user know when changing to a directory in CDPATH. * Generate previews for trashed files ('u' and 't del' commands). 1.15 (Jolly-Roger) Bug fixes * Extended attributes printed for symlinks (if the target has them) when using the 'p' command (which does not follow symlinks). * Symbolic links marked as having extended attributes (@) (if the target has them) in long view. * Special permission bits (SUID, SGID, and sticky) are always zero in octal notation (mostly 'p' command). * Garbage in the command line after pressing keybind and there's text in the command line. * Ctrl-Alt-b, Ctrl-Alt-j, and Ctrl-Alt-k keybindings not working. Removed (didn't make much sense anyway). * 'dh !NUM' not working. * A few minor keybindings quirks were fixed. * --disk-usage crashes on file systems reporting zero total size (ex: /proc). * File names wrongly trimmed when file extension has exactly MAX_NAMELEN - 1 chars. * Wrong disk usage information (for big sizes) in some 32-bit architectures. * Two files with the same name (but different case) are both expanded even if only one is specified. * Key remaps for vi command mode not working. * Recounting hardlinks in disk usage analyzer mode. * Esc+Enter switches to vi mode. * Keybindings are executed from within some secondary prompts. * 'ws' and 'st' commands not working with fused numbers (ex: 'ws2'). * Prompt commands executed twice after keybindings. * After renaming a selected file it is actually deselected, but still marked as such. New features/improvements * Mark Libreoffice lock files (.~*#) and MS-Office temp files (~$*) as temp files. * Document the meaning of each shade in both DateShades and SizeShades. * 'p'/'pp': List files ACLs (Linux). * 'p'/'pp': Files with extended attributes/caps/ACLs are marked with '@'. This replaces the '+' in previous versions, which was a mark for ACLs only (Linux). * Extended attributes enabled by default (long view). * Faster file capabilities check (improving thus the overall listing time). * Add file system type name and device file name to the disk-usage message (--disk-usage): FREE/TOTAL (FREE_PERC) FS_TYPE_NAME DEV_NAME. * 'c'/'m' behavior for 'cp'/'mv': add final "." if last parameter is "sel". * fb2, cb7, cbt, and cba files added to the mimelist file as ebook formats. * sel: do not try regex if pattern contains just asterisks as metacharacters. * Mime: case insensitively match file name patterns (for example, file extensions). * Add foot-extra, foot-extra-direct, rio, and rio-base to our internal terminfo database. * Add support for image previews using sixel (via fzf). See clifmimg script. 1.14.6 Bug fixes * "CMD1 2" not expanding ELNs (1 and 2). * Crash with Ctrl-Alt-u keybinding. * Wrongly attempting to remove the selections file when running 't sel' and there are no selected files. * Wrong alignment for big file sizes in long view (sizes in bytes only). * Haiku: infinite "sel *" loop after keybind. * Crash when running with --list-and-quit and no parameter is provided. New features/improvements * Properly right-pad dash for unknown file sizes (in bytes) in long view mode. 1.14.5 Bug fixes * Missing --stat and --stat-full in shell completion files. * Wrongly displaying file names with invalid encodings. * Out of bounds read when bleaching file names with invalid enconding. * POSIX mode: Reading environment variables even if running in secure mode. * 'm' wrongly performs regex expansion on the last parameter (new name). * Hidden files not counted in light mode ('stats' command). * Bookmark name (in the bookmarks screen) is executred as a command name. * Crash on some OpenBSD systems. New features/improvements * Add internal 256 color scheme (stealth mode can now run in 256 colors mode). * Highlight backslashes to make escaped file names more readable (color code is 'hw'). * Read-only mode (via --readonly or the Readonly option in the config file). * The update_trash_indicator routine is almost 5x faster. * Faster symlink resolution when ColorLinkAsTarget is enabled. * Harden regex expansion to prevent undesired expansions (prepend '^' and append '$' to queries). 1.14 (Jawbreaker) Overall, 1.14 brings more preformance (regarding both speed and memory usage), better compatibility (POSIX/legacy systems), and improved security. Bug fixes * Crash on Termux when running with --secure-env. * Not recovering from warning prompt when navigating history with Up and Down arrow keys. * No screen refresh after renaming files with 'bleach' (if using the generic fs events monitor). * Not working on Linux < 2.6.27 (no inotify). * Wrong files list color for unknown file types (right color with p/pp command). * Highlight color is lost after inserting sudo command (Alt-v). * Binary names in PATH loaded multiple times. * Wrong inserted match when TAB completing the 'desel' command. * 'dup' fails when file name starts with a dash (subsequent characters are taken as command options). * Backdir (...) not working in Macos and Haiku. * Stack overflow when writing log to profile directory with not write permission. * Max name length unset not honored in long view. * Compilation with SECURITY_PARANOID does not work if no command line parameter is provided. * Commands received via plugins are not sanitized even if running in secure-cmds mode. * Wrong full directory sizes below 1K. * Mangled output for Xattributes ('p' command) in case of broken symbolic links. * Wrong size for block device files on some platforms. * Extended attribute in 'p' command sometimes prints garbage values. * Wrong icon (regular file) for executable files with capabilities. * Some plugins not working with file names containing spaces. * Properly expand history events ("sudo !!" not working). * TAB completion for envrionment variables not working. * Error building on MacOS 10.6 (Snow Leopard). * Ctrl-u deletes the current line but does not recover from the warning prompt. * The 'l' command cannot create link names containing spaces. * Wrong birth time (Unix epoch) in Solaris. New features/improvements * Secure-mode: disable core dumps; set umask to 0077 at startup; force creation mode 0600 for files and 0700 for dirs ('n command'); close non-standard file descriptors. * By default, the 'te' command sets the executable bit for the file owner only (unsets it for owner, group, and others). * If available, use the higher-quality arc4random(3) instead of the old random(3). * Use temporary random file names to communicate with TAB completers. * The SECURITY_PARANOID compilation flag takes now three possible values: 1 = secure-cmds + secure-env; 2 = secure-cmds + secure-env-full; 3 = same as 2, plus stealth-mode. * Warn when removing multi-hardlink files: file might still exists. * If running in secure mode, check config files for symlinks and multi-hardlinks (see CWE-59 and CWE-62). * Drastically reduce memory usage (~50%) under heavy load (100,000 files). (We're now the second most lightweight terminal file manager, only behind NNN!). * Increased listing speed in long view (ls(1), here we go!). * Increase the limit of files per directory from INT_MAX to SSIZE_MAX (meaningful only for 64-bit machines: these values are the same in 32-bit systems). * Lots of improvements to the POSIX version (much more compliant). * Improved compatibility with legacy systems (pre-POSIX.2008). * Increase file(1) support from 4.24 (Mar, 2008) to 3.30 (Apr, 2000). * TAB complete the third word for the 'rr' command with text editors. * Files birth time support in Haiku. * Fish versions for cd_on_quit.sh and file_picker.sh shell functions (by @spenserblack). * Allow extended file attributes in non-glibc Linux distros. * Allow nested instances. Properly set both SHLVL and CLIFMLVL environment variables. * Allow customizing the prompt when running colorless (via the 'clifm-no-color' prompt). * Allow using single/double quotes to quote regular file names via ELN expansion (using the 'QuotingStyle' option in the config file). * Colorize backup files (ending with tilde (~) or "#*#" (emacs auto-save)) using the color specified for TEMP in the color scheme file. * Improved confirmation prompt for the 'r' command. * Set a custom history file via CLIFM_HISTFILE. * Exclude commands from history via the 'HistIgnore' option in the config file. * Exclude directories from the directory history via the 'DirhistIgnore' option in the config file. * Make multi-hardlink color take precedence over empty and file extension colors. * Support for Solaris port files, NetBSD archive state files, and whiteouts. * p/pp command can now tell whether a file is sparse (has holes), in which case it adds the "sparse" label to the Size field. * 'p' cmd: print file capabilities if available (Linux). * Run as standalone stat(1) replacement via --stat and --stat-full command line options. * Customizable timestamps for the 'p/pp' command via the 'PTimeStyle' option in the config file. 1.13 (Voodoo Root) Bug fixes * A variable assignment triggers the warning prompt even if running with --int-vars. * "clifm --open=~PATH" not working. * Crash when running the 'n' command with an empty string: n "". * Suggestion persists after running a keybinding. * Image previews with 'clifmrun' are broken since ueberzug 18.2.0. * No path completion for 'x/X' command. * The 'new' command is not properly handling file names with tilde (via secondary prompt) * Some keybindings are overlapping (ex: press Alt-b and then Alt-m) * Quoted strings passed to either the 'new' or the 'filter' commands are expanded (wordexp(3)). * The regular files filter (=f) wrongly expands to non-regular files. * The 'new' command splits quoted names containing spaces (ex: 'n "a b/"'). * Wrong highlighted match in standard TAB completion when using the 'j' command. * TAB completion for ranges lists files even when the range goes beyond the number of files. * Duplicate entries in the jump database. * Wrong message when adding instead of removing a line from the tmp file in bulk remove ('rr'). * 'cs' (color scheme) does not work in autocommands if it's not the last directive. * Cannot enter cyrillic characters. * 'jo' command removed: not useful and broken since 1.11. * Wrong completer offset when warning prompt is disabled. * Prompt options in the color scheme file do not properly override options specified in the prompts file. * When customized, the warning prompt color does not match the color used for input text. * Tagging non-existent file names. * "s /path/to/dir/.*" selects self and parent directories (instead of just hidden files). * "s * -d" fails to select a directory file named "-dir". * Wrong matches color when TAB completing self or parent dir (ex: "./dir/"). * Unrecognized option '--indicator-style=none' when previewing directories on BSD. * Color scheme names containing a dot are not recognized, even if they have a .clifm extension. * Wrong file color when listing trashed files not trashed by clifm. * Quick help (?) fails if PAGER env var is set and contains spaces. * Trash dirs not properly created if they do not exist, breaking the trash function. * Wrong columns width when file names contain embedded control characters. * Wrong message ("No matches found") after recursive search (-x) * "Scanning ..." message not properly removed in case of empty directories. * --no-warning-prompt not working. * Listing files twice upon file removal (Haiku, Cygwin) * MinFilenameTrim overriden by MaxFilenameLen in long view. * Setting RlEditMode to 1 does not switch back to emacs mode. * Suggestions not properly removed in some cases (type 'bm add Camera/ cm', when suggested string is "bm add Camera/ Camera cm") * If running via the cd_on_quit.sh shell function, the shell directory is always changed, even if the exit command was not 'Q'. New features/improvements * The shell used to run external commands can be set via either CLIFM_SHELL or SHELL environment variables. * On NetBSD, OpenBSD, and MacOS, use 'grm' (the GNU version of 'rm') if available. * Add status message to the 'reload' command. * Append a slash to directory names when reporting removed files. * Harden config files creation: always set permissions to 600, disregarding umask (see CWE-732). * Add 'umask' builtin command. * 'pwd' is now a builtin. * The 'p' command do not follows symlinks (unless it is a symlink to a dir and ends with a slash), while 'pp' always does. * TAB complete authentication command (ex: sudo) with available command names. * Improved input handling for both 'new' and 'dup' commands (via secondary prompts) * Ask the user for confirmation when creating unsafe file names ('new' command). * Do not perform multi-file expansions (say, ranges), if there's a file named after the expandible expression. * Since fzy has been inactive for more than a year (and our patch has not been even reviewed), we forked it as fnf and migrated clifm to it: '--fzytab' is now '--fnftab', and the TabCompletionMode option now takes "fnf" instead of "fzy" as value. * Make file type filter chars in selection match those used by the search function. * Port to SunOS/Solaris/Illumos. * Solaris doors support. * Nano-second precision for timestamps in p/pp command. * Support for BSD file flags (p/pp command). * Honor both CLIFM_TMPDIR and TMPDIR environment variables. * A generic file system events monitor using mtimes (for when neither inotify nor kqueue are available). * In case of find(1) implementations not supporting regex (OpenBSD/Solaris) try to use gfind(1) instead. * Enable secure cmds/environment on NetBSD, Haiku, and MacOS. * Ctrl-Alt-j and Ctrl-Alt-m switch to vi editing mode, while Ctrl-Alt-e switches back to emacs mode. 1.12 - Blondebeard Bug fixes * Warning prompt color persists after recovering from wrong command * Size of empty dirs is zero when apparent-size is disabled (should print '4k' instead) * A file of 1024 bytes exactly is displayed as 1024B instead of 1K * Cannot open links to regular files (neither 'ELN' nor 'FILENAME' nor 'FILENAME APP') * Warning prompt triggered when more than one word and editing first word to 's:', 'b:', or 't:' constructs * Wrong color when TAB completing in the middle of the line and whatever is next is colored (ex: quotes) * 'update.sh' plugin is unable to retrieve lastest upstream version * Attempting to switch profiles when there is only one * Partially printed directory size ('pp' command) on wsvt25 console (NetBSD) * When you type "uc" a command description is provided, but the command doesn't exist anymore * 'mp' command not working on DragonFly BSD * 'ls' returns exit code 1 (even when there is no error) when running with --no-autols * 'ow' not honoring "![EO]" notation in the opening application string * Wrong color for non-existent tagged files * No completion for 'tag FILE :' * Query string not correctly cleared when TAB completed text is shorter (tagged files insertion) * Extension color no honored by the 'p' command for symlink targets * When running colorless, links are always shown as broken in 'p' command * When toggling the disk usage analyzer (Alt-TAB) the value of apparent-size is changed * Directory history from different instances is not preserved: the last instance overwrites everything. * New jumpt entries (visited directories) generated from a second instance is not preserved * Selected files indicator not shown in long view if ELN's are disabled * Wrong color for symlink target in 'p' command when the target is a special file * Unaccessible directory not colored as such when the user has not execute permission * The 'ne' color code has no effect at all. Removed. * Crash when attempting to run a plugin via a keyboard shortcut. * "cmdxxxx" performs TAB completion as if the string were just "cmd" * Some internal subcommands are never suggested * Version sort not correctly sorting ('file10' before 'file9'!) * Wrong screen width when using icons in long view and file names are not trimmed * Description for some commands is never suggested * 'mm --help' returns 1 (error) as exit status * Some shell completion for Bash and Zsh are broken * Files list not reloaded when unmounting remote * --print-sel is not working * Crash when changing dir and the directory history is empty * 'te' command reports success even if the operation failed (e.g. permission denied) * A file named "...file" is wrongly converted into "../../" by the fastback function * Cannot untrash file if destiny (original path) is on a different file system * Misaligned emoji-icons in foot (Wayland) * Wrong files alignment in virtual dirs when clear-screen is disabled * Select files using the same glob expression twice: wrong files got selected. * Missing space between icon and file name when running with --no-color * Broken nerdfont icons since NerdFont 3.0 * PWD not properly set in case of symlinks to directories * Words in the command line are expanded even if quoted or escaped (ex: "s '~'") * "clifm -P ." creates a profile that cannot be managed via the 'pf' command * Crash when expanding a tag some of whose tagged files are not existent, and is followed by another tag expression New features/improvements * Print dir sizes ('p' command) as human-size/bytes (as done for regular files) (GNU 'du' only) * Reload the list of binaries only when timestamps of paths in PATH differ from cached values (this might be noticeable on low-spec systems) * Warn when attempting to merge a tag with itself * Honor 'apparent-size' and 'si' options for directories on BSD systems * New command: 'unset', to remove variables from the environment * New command: 'll', to toggle long view mode * 'ff', 'hf', and 'lm' commands just toggle state if no parameter is given * 'hh' is now an alias for 'hf, hidden' * Add free percentage to disk usage message (--disk-usage, DiskUsage) * 'rf' clears the screen even when ClearScreen is set to false * Make file names trimming optional via TrimNames (config file) and --no-trim-names * Set colors for file extension to default values when running in stealth mode * Allow listing tags applied to an specific file ('tag list FILENAME...') * Colorize output of the 'jl' command * New option: 'ColorLinksAsTarget', to colorize symlinks as target files * Replace slash by dot as permission groups separator char (long view and 'p' command) * New plugin: 'xclip.sh', to copy the current line buffer to the clipboard via a custom keybinding * 'export' can now export multiple variables at once * Allow directly assigning hex colors to file extensions in color scheme files * Inform target name when editing a broken symbolic link * Append an 'add' subcommand to 'tag' for consistency with the remaining subcommands * Add 'edit' subcommand to the 'config' command * Add 'list' subcommand to the 'net' command * Add 'set' subcommand to the 'prompt' command * Add 'list' subcommand to 'kb'. Add both 'list' and 'readline' to TAB completion. * The 'log' command has now this syntax: log [cmd, msg [on, off, status, clear]] * TAB complete available subcommands for 'actions', 'config', 'fc', 'mime', 'net', 'log', and 'prompt' commands. * 'filescounter' command was removed (only 'fc' remains) * Improve logs system * Old log.clifm file split into two: cmdlogs.clifm and msglogs.clifm * Disable the use of bold colors via --no-bold * Allow the use of xterm-like color names in color schemes * Completions file for the Fish shell * Dir full sizes are preceded by '!' whenever there was an error reading a subdir (total size may not be accurate) * 'cd' returns 1 in case of EACCESS error, like most shells do. * TAB complete 'cmd edit ' with available text editors (for all internal commands taking 'edit' as subcommand) 1.11 - Cobb Bug Fixes * File names containing sapces are not properly escaped when expanding file types (=), MIME types (@), and bookmarks (b:) * Wrong directory suggestion when entering ending slash * No color on wezterm terminal * If TERM is not found in clifm's terminfo database, CLIFM_FORCE_COLOR won't work. * Wrong cursor position with fastback and multi-line path suggestions * 'jl' (an actual command) triggers the warning prompt * Error when attempting to compile without trash support (_NO_TRASH) * Error compiling with _NO_FZF, _NO_TRASH, and _NO_ICONS * When a custom welcome message is set the initial help message is not shown * 'Icons' option is missing in the config file * No error message when specifying invalid opening application to edit config files * Garbage first line when refreshing screen via ENTER * 'jl STR' is returning an error code even if a match was found * Wallpaper setter plugin not working on Wayland * 'dir/*' as first word triggers the warning prompt. PARTIALLY SOLVED: if there are matches, the prompt switches back to normal. * Wrong window offset with TAB completion for wildcards as first word * Not honoring case insensitivity when TAB completing paths * 'ListDirsFirs't in the config file is broken * Name not escaped when accepting workspace number suggestion * Highlight color for numbers (hn) not working * Ctrl-D exits clifm no matter if the command line isn't empty * If CLIFM_IFACE_COLORS, CLIFM_FILE_COLORS, and CLIFM_EXT_COLORS are set, the color scheme file won't be read * 82 is not the proper exit code for processes interrupted by a signal (e.g. Ctrl-c) * 'clifm.1' crashes man(1) in Termux * Lira fails to identify Zstandard files not ending with .zst * './FILE' triggers the warning prompt even if FILE exists in CWD * Unable to TAB complete './FILE' if FILE is not an executable file * '/bin/ls ' triggers the warning prompt, even if /bin/ls exists * In Cugwin there's no DISPLAY variable, sot that it always runs as if there's no GUI (this impacts on Lira) * Garbage text when printing full dir sizes ('pp' command) and running colorless * Device field in p command for character and block devices wrongly set to device ID instead of ID of device containing file New features/improvements * Proper error message when attempting to open multiple files at once * 'clip' plugin reintroduced and rewritten * Add a '--purge [RANK]' option to jump: purge both non existent dirs (no param) and dirs ranked below RANK * Colorize the list of jump entries ('j'), right pad fields, and sort by rank * Allow compiling profiles out (_NO_PROFILES) * Enable fzfpreview by default * The 'config' command can be used instead of 'edit' (which is now deprecated) * 'config dump': List current settings highlighting those that deviate from the default values * Allow specifying opening application for 'jump edit' and 'prompt edit' commands * Use 256 colors for file properties if available * Gradient colors for file size and timestamps in file properties * New color scheme: default-256 (a 256 colors version of the default theme) * Default to default-256 color scheme if 256 colors support is detected (ColorScheme must be unset) * Customize time format for timestamps in long view (including relative time) using TimeStyle (config file) * Default time format in long view is now ls(1)-like * Colorize the list of workspaces ('ws' command) * Allow unsetting workspaces via the 'unset' subcommand ('ws NUM unset') * Options in main config file are by default commented * Right pad ELN's and add icons (if enabled) to search results (CWD only) * Match file extensions case-insensitively * Alphabetically sort color schemes ('cs' command) * Make Alt-f behave like in most shells (if not at the end of line, move forward one word) * Remove --no-ctrl-d-quits, --unicode, --no-unicode, and --no-toggle-workspaces switches * Remove 'uc, unicode' command * Added support for extended attributes (for both long view and 'p' command). See PropFields in the config file. * Ported to DragonFly BSD * Take terminal capabilites into account when clearing the screen * Right pad ELN's when listing selected and trashed files * Add support for CLICOLOR and CLICOLOR_FORCE environment variables. See https://bixense.com/clicolors * Properly set OLDPWD * Set CLIFM_PID and CLIFM_VERSION environment variables * Apparent sizes are used now by default (--apparent-size changed to --no-apparent-size) * Add Device type field to p command for character and block devices 1.10 - Swordmaster Overall, 1.10 brings a much more solid command line experience Bug fixes * ID color not honoring secondary groups in properties * Recursive search not following symlinks * Attempting to rename a non-existent file * "Querying MIME types" message is overwritten by cmd output * Not refreshing screen if CWD is a symlink to dir (Linux) * Not refreshing screen on *BSD * Wrong default theme when argument to --color-scheme is invalid * A slash is appended to bookmark names when completing with the 'bm' command * No suggestion for ELN's after 'bm a ' * Fix 'x' command on Haiku * Wrong completion offset with "/" in standard TAB completion mode * 'net', 'cs', and 'pf' commands do not suggest case insensitively * 't:TAG' not displaying files in standard TAB completion * 'q ' (with at least one space) triggers the warning prompt * No suggestion/completion for names containing spaces (bd, bm, net, cs, pf, and prompt commands) * No completion for file names containing spaces ('u', 't del') * No file color when listing trashed files via 'u' or 't del' commands * No color when listing trashed files in standard TAB completion * Unable to remove bookmarks having no shortcut * 'b:' is broken in standard TAB completion * History completion (!) is broken in standard TAB completion mode * Extra slash appended to history entries which are directory names * Wrong columns offset when listing unicode files in standard TAB completion mode * Wrong file color after TAB completion * 'mv' and 'cp' shell commands take --help as a file name * 'export' fails with env var and home tilde * TAB completion in the middle of the command line is unstable * No path inserted when completing wildcards and there is only one match * History suggestions take precedence over jump ones when using the 'j' command * Freeze when running with --no-autols * When prepending "sudo" (Alt-v), it takes the color of the current word * Empty files not colored in TAB completion * Persistent warning prompt color after deleting a space char * Extra line when completing multi-line commands * Prompt disappears when editing first word and we're not at the end of the line * Invalid command/file name taken as correct when editing first word (fuzzy-matching enabled) * Wrong visible bell region when not at the end of the line * More directory history entries (bh/fh) than MaxDirhist * Cannot untag files tagged with a name containing spaces * Jump is not forgetting directories ranked below MinJumpRank New features/improvements * New command: 'oc', a files ownership changer * Allow setting a custom selections file (via --sel-file) * Suggest a brief description for internal commands * 'cmd' displays available commands together with a brief description * Plugins help messages reformated to fit clifm's format * Specific color for fuzzy file name suggsetions * New color scheme: aqua * New classification characters: broken symlinks (!), character device (-), and block device (+) * Make "version" the default sorting order * Extended syntax for the bookmarks command: 'bm add FILE NAME' * 'b:' completes/suggests bookmark names (instead of paths), and 'b:NAME' is expanded to NAME's path. The ExpandBookmarks option (just as --expand-bookmarks and the bookmarks suggestion strategy) is deprecated. * Multi-selection for the b: and t: constructs (bookmarks and tags respectivelly) * 's:' works exactly as 'sel', to be in line with 'b:' and 't:'. Unlike 'sel', 's:' works as first word as well * 'net unmount ' should only list mounted resources, while 'net mount ' unmounted resources only * Allow renaming profiles via the 'rename' subcommand: 'pf rename' * List file attributes (as lsattr(1) would) in file properties (Linux only) * Group file extensions by type in the default color scheme for easier customization * History timestamps via the 'show-time' subcommand: 'history show-time' * Search patterns history changed to '/*' (instead of '/') * Colorize jump entries in TAB completion (fzf): 'j ' * Pad bookmark names in the bookmarks screen * Allow jump to never forget directories by setting MinJumpRank to -1 1.9 - Sharptooth New features/improvements * Allow autocmds for workspaces as well, instead of just paths * Abbreviate target path of symlinks in the properties function * Allow starting the file preview window hidden (--fzfpreview-hidden) * Allow the 'view' command to select files * Keybinding for the 'view' command (Alt+-) * Implement 'cd -' (as it works in most shells) * 'pc' command to interactively edit file permissions * List available MIME-types: @ * List available file types: = * Optional files counter field for directories in long view * Optionally print file size in bytes in long view * Added timestamp seconds in long view * Allow setting custom values to automatically run the pager * Improve the prompt of the symlink editor (le) * Allow the 'vv' command to rename files passed as parameters, and not only selected files * Improved fastback function: absolute paths are now suggested * Private workspace settings * Customizable welcome message via WelcomeMessageStr * Make suggestions even when removing text via backspace * Automatically expand bookmarks (:b), file types (=c) and mime types (@patter) * Improve list of available file types (=) * 'stats' command now work in light mode too (reduced though) * Make the b: (or :b) construct work as first word as well * Send text cut via Alt-c to the kill-ring * Do not trim file name if there's only one file and we're not in long view * "Commands" help topic * FuzzyMatching is now an option in the config file * Improve fuzzy matching: detect consecutive chars and beginning of words (including camel case) * Make fuzzy matching Unicode aware * Allow exiting the bookmark creation screen via 'q' * Allow using tilde for bookmark paths * Properly test UTF-8 support Bug fixes * Wrong window offset when TAB completing 'tu' command and fuzzy-matching is enabled * Wrong cursor movement in some secondary prompts when Unicode text is entered * Crash when PrintSelFiles is enabled * Wrong ueberzug image position when running 'TERM -e clifmrun --fzfpreview' on some terminals * Immediately quits if exectued as terminal parameter (ex: "lxterminal -e clifm") * "=h" not expanding into multi-hardlink files * If there's a file named "file.txt" and you type "file/", "file.txt" is suggested anyway * "ELN APP" triggers the warning prompt * Unexpected trimmed file name in long view * Wrong ELN pad when max files is set and files is smaller than max files * Wrong colors for new property fields in long view * View keybind (Alt--) not working when there's a file named "view" in CWD * Mutiple screen refreshes when siwtching profiles via keybinding * Autocommands override some current settings * Autocommands are evaluated backwards (from bottom to top) * File birth time is missing for the 'p' command on NetBSD * Type '/': another slash is inserted * 'v' and 'vv' commands not expanding ELN's * Cannot remove/rename files named "-f" or "--force" * The 'view' command fails on some systems due to the ED escape code (^[[2J) * Filter set from CLIFM_FILTER is lost after changing profiles * CLIFM_FILTER="!.*\.c$" not working. The shell expands "!": either use single quotes or escape '!' * Suggesting jump entries from history ('j query') is not useful: it hides the directory targeted by the query * Wildcards expansion not working whit paths containing spaces: 's ~/Docu\ ments/*' * Wildcards not expanded when using tilde: 's ~/*' * Wrong finder offset when TAB completing in the middle of the cmd line 1.8 - Otis New features/improvements: * File previews for TAB completion (fzf mode only) * 'clifmimg' plugin to add image preview capabilities to clifm * 'view' command to preview files in full screen (via fzf) * Shotgun, a built-in files previewer similar to pistol * Remove cd prefix when suggesting jump dir and autocd is off * Change dates color in properties (blue isn't readable on some terminals) * Improved Unicode support for the suggestions system * 'bl' command automatically prepends dot to suffix if it does not start with a dot * Flat or branch view via the fzfsel.sh plugin (-f, --flat option) * Bypass aliases using a backslash: \alias_name * Cygwin support * Improved performance/portability of the suggestions system: no more slow/non-portable CPR-CUP escape sequences! These were replaced by 100% made in-house cursor position calculation plus basic/portable escape sequences: CUU, CUD, CUF, and CUB Bug fixes: * Issues with the ESC key in the interactive rename prompt * Not honoring none in FzfTabOptions * No file type color for /path/to/dir/GLOB * Wrong file colors when running as root * Script in $HOME not working with arguments (e.g. ~/script.sh arg) in mimelist.clifm file * 'fzfnav' plugin not working with Ranger's scope.sh * C-p keybinding is slow to respond * C-p and C-n keybindings do not highlight history lines * BAEJ suggestion (ex: ELN) not colored if it contains spaces * If wrong command and C-x fails, error is printed using the wrong command color * 'bl dir/file file' creates only one symlink (file.link) * Secondary prompts have issues with Unicode strings. * Termux: TAB completing/accepting suggestion of Unicode strings not working * Bulk create plugin (bn) stops creating files as soon as a unique quote (' or ") is found (ex. Peter's dog) * Cannot create directory with n command if file name contains spaces * 'fzfnav' previews not working on Wayland * Help message covered by image preview in fzfnav plugin * The "Calculating..." message in the pp command is not correctly removed on some terminals * Pager not working as expected on the Linux console * The 'dragon' plugin does not work with file names containing spaces * The manpage parser stopped working due to the file extension change * Multi-byte char takes color of previous char (if colored) * Suggestion not removed when entering a tilde path * Ctrl-Alt-d (remove sel) not working: conflicts with C-d to quit * Screen refreshed upon command error: messages are lost * Suggestion partially printed with j cmd * FZF tab offset is broken: select a few files (make sure it takes more than one line), insert all of them, type sel again and the press TAB: FZF menu appears next to the end of the screen, making its contents unreadable. * Wrong path as first word errs like a failed search * 'fzfsel' and 'fzfdesel' plugins not working * Wrong columns when longest file name is a directory * 'mime' command not taking filenames/ELNs as parameters * Recursive search not honoring case insensitive search option * FzfTabOptions not protected against command injection when running with --secure-cmds * Crash when only one file is listed and TAB is the first key pressed * Wrong path color when completing unique match via TAB *Suggestions are broken on high-latency remote connections 1.7 - Elaine New features/improvements: * Better columns arrangement in long view * ke / kd: encryption/decryption plugins * Better use of space when trimming file names (the space used by the files counter in now taken into account) * Preserve file extension when trimming file names * Allow forcefully copying, moving, and removing files * Improve in-file documentation for the default color scheme file (default.clifm) * Termux support * Transition from .cfm (ColdFusion) to .clifm config files * Allow displaying inode number in long view * Remove cc command to avoid conflicts with /bin/cc * Remove mount-ISO option if not on Linux * Optionally use numeric instead of symbolic notation for file permissions in long view mode * Timezone for dates in p command * Toggle properties fields on/off in long view * Virtual directories plugin * A nicer config file * Desktop notifications * Improve the messages log system * Move messages logs into log.cfm file and get rid of the messages.cfm file * Increase max log size to 1000 * fdups plugin ported to FreeBSD/NetBSD/OpenBSD (thanks @danfe!) * Allow glob expansion via TAB for the quick search function (/*.pdf) * smenu(1) support for TAB completion * List available bookmark paths via b: * A more readable color for unstatable files * Abbreviate file names for ds , sel and when informing deleted files via r sel * Toggle workspaces (via workspace keybindings) * Named Workspaces * Make dup command ask for a destiny directory * n should inform about created files * n should be able to create dir/file even if dir doesn't exist * Bleach: ä/ö/ü should be replaced by ae/oe/ue and Ä/Ö/Ü by Ae/Oe/Ue. Bug fixes: * Plugins not respecting --no-color * Extraneous first entry in long view when toggling max file name length * Command line garbage when deleting the whole line with the del key * No suggestion when recovering from wrong command * No color for history lines if readline.clifm isn't found * Inconsistent file colors when listing, searching, and printing file properties * Color for inaccessible directory name is extended up to properties in long view (light mode) * alias import not completing/suggesting file names * Dangling temporary file in bulk rename * Jumbled output when running with -y --no-eln --no-color * Secondary groups not honored when checking file access * Bleach lists all files even if they don't need to be cleaned up * Screen not refreshed on Enter if backspace was previously pressed on empty line * Suggestions for aliases is broken * Hex colors not working for file extensions * fzfnav plugin works only once * mime import overwrites current mimelist file * br without parameters returns error exit code (1) * rr command not working without an explicit path * mm command not working with ELN's * Bulk rename opens temporary file even for failed glob expressions * ACL files in long view break columns symmetry * No highlighting after recovering from wrong command * The file picker function does not work when selected file names contain spaces * Switching workspaces via keybinds sometimes errs with ws: filename: No such workspace * edit is running vis(1), which is not a text editor on BSD systems * Trivial messages are being logged * Wrong finder offset when expanding glob expressions via TAB * Switching workspaces via keybinds not working if there's text in the command line * ./ not listing directories * Wrong finder window offset when fuzzy-match is enabled * Completion for the ZSH shell are broken * Home not reduced to tilde on FreeBSD * Enter a single &: crash! * Multiple screen refresh when moving back and forth via keybinds * Removing a symlink to dir via the r command attempts to remove the target 1.6 - Guybrush Additions/improvements: * Rename PromptStyle option in the color scheme file to Notifications=true/false * File type expansion via TAB: '=d' * Search pattern completion: '/' * Apparent size is enabled by default in disk usage analyzer * Make ApparentSize an option in the config file * Use separate indicators for error, warning, and notice messages * Prompt msgs indicators should be kept across profiles * Add wildcards (glob) TAB expansion * Select all (C-s), deselect all (C-a), and toggle select (C-t) keybinds for TAB completion (fzf mode) * Add only-dirs option to autocommands * Help topics * File type modifiers for the search function are now the same used by find(1) * Usage message for the search function * Search strategies * More friendly file names in the selection box * Trash is now enabled in stealth mode * ELN's color is now regular cyan * New option: -r, --refresh-on-empty-line * New option: -E, --eln-use-workspace-color * Current workspace color for dividing line if 'dl' is unset * TAB completion for users home directory * List removed/trashed files * Replace references to "folders" by "directories" * Fuzzy TAB completion for file names and paths * 'prompt' command to quiclky switch prompts * More color schemes by default * Support for emojis as icons * Suggestions for sort numbers * Complete with file names instead of bookmark names when adding a new bookmark ('bm add') * Improve algorithm to calculate total sel files size * Default to FZF TAB completion if fzf is found * Reload files when (de)selecting or (un)trashing files with descriptive messages * Better TAB completion for selection and other functions * Visual bell style (readline >= 8.1) * Hex color codes support * Notice message if config files are reloaded * Built-in support for rsync to copy files * New plugin (rrm): recursively remove files via FZF * Do not record ELN& into history * Allow controling STDERR and STDOUT when opening files via Lira * Move instead of cp/rm when trashing files * Do not suggest/autocomplete/expand CliFM internals if command starts with a semicolon or a colon, or if we're in a comment (#). * Add keybind (C-A-i) to toggle disk usage analyzer mode on/off * MaxNameLen defaults to 20 * Improved bookmarks interface * Consistently reload the list of files either upon files or interface modifications * Reload files list after exiting the bookmarks screen * Reload the bookmarks screen when entering invalid bookmark * Temporarily disable cmds history via 'history [on, off, status]'. '--no-history' is also available * TAB completion for the alias command * Properly align list of aliases and actions * New command: 'fz', to toggle full dir size on/off in place * Removed colorizeProperties option from the config file * Total size for selected files calculates full directories size * Allow sizes in powers of 1000 instead of 1024 (--si) * Prepend 'cd' to jump completion when autocd is disabled * Improve img_viewer plugin * New plugin, cr, to copy files to remotes * New plugin, da, to inspect files and directories sizes * New plugin, bmi, to import bookmarks from either Ranger or MC * Add install rules for cmake * Do not sort reverse by default in disk usage analyzer mode * New plugin, fdups, to find and remove duplicate files * Enable exit on EOF (Ctrl-D) by default * A new line should be printed before quitting via keybind (Ctrl-d, F12) Bug fixes: * Symlinks to dir wrongly sorted in disk usage analyzer mode * 'pp' command displays wrong size for symlinks to dir * Garbage first entry when toggling disk usaga analyzer * Only-dirs not showing symlinks to dir * Cannot get properties of the root dir (p /) * Wrong size for empty dirs and symlinks to dir in long view mode * Slash not appended to suggested symlinks to dir * TAB completion of first word (if multiple matches) removes second word * Del last word deletes from end of line instead of current cursor position * Switch to comment color if file name contains a hash char * Error inidicator in the prompt not honored when there are multiple messages * No history line color when pressing UP for the first time * Wrong baej suggestion offset when editing line * Prepend sudo function messed up with current completion color * Autocmds not playing nice with profiles * Some plugins not working from autocommands * Cannot use backslash in search expression * '?' ELN in search list when not searching in CWD * Inconsistent color for search files in light mode * No deselection message on error * Unable to select root dir * Wrong cursor position while editing line * 'pp' cmd does not work with tilde * File overwritten when untrashing file with same name * 'st' does not suggest 'mtime' but a file name instead * Wrong exit code at exit * File extension color in TAB completion even if --no-file-ext * Alt keybinds not working on SSH * Box drawing dividing line not working * Segfault when not path is defined for a bookmark * The rename function cannot rename files named as numbers * Bookmarks names and shortcuts do not work with spaces * Sel doesn't expand braces correctly * Incomplete prompt when using standard TAB completion * Wrong color for regular files when using GNU ls in fzfnav plugin * Leading space in file names when running with --no-eln * Wrong "FZF not found message" when running with --fzftab * Keybinds not working when running new instance as root (X) * Double error message if invalid filetype in quick search * 'li' color code not respected * Wrong cursor line for suggestions after resizing terminal * Segfault when removing current dir from outside * rgfind plugin not working with multi-word strings * Wrong cursor position after editing line (first word) * Plugins cannot know we're running colorless when using --no-color only * Wrong exit code after suggestion * Sel indicator not updated when sel file is (re)moved * Suggestions do not recognize fish builtins * No error msg when 2nd param is opening app and it fails (or does not exist) * ELN expanded to alias if file name is an alias name * Cannot bookmarks files containing spaces in their names * Plugins return wrong exit status (always zero) * Total size indicator for selected files is broken * Correcting a wrong file name as first word do not recover the normal prompt * ELN runs mime-import if it refers to a file named 'import' * Starting path does not work when the path contains references to self or parent dirs (dot or double dot) * --open crashes CliFM * Completions/suggestions for jump produces wrong values when compiled with _BE_POSIX on Linux * TAB completion for jump does not honor case insensitive * Bookmarks not reloaded after 'bm edit' * Some plugins not working: img_viewer, vid_viewer, and music_player * Built-in 'export' command not working * --control-d-exits is not a valid command line option anymore 1.5.1 - Willy * Fix crash when built via makepkg on Archlinux 1.5 - Nano * Better handle non-alphanumeric chars when sorting * `Crtl-Alt-q`: Toggle max file name len on/off * Define `DATADIR` at compile time via the Makefile * MacOS port! * New instance function is available to all supported platforms * Force the use of colors via `CLIFM_FORCE_COLOR` environment variable * Accept more word delimiters for accept first suggested word and delete last word functions * `DirIconsColor` renamed `DirIconColor`in the color scheme file * Color variables support for the color scheme file * Light theme included * Suckless mode compilation via `CLIFM_SUCKLESS` * Improved theming support: interface stuff (including colors, prompt, warning prompt, dividing line, and FZF options) is defined now in the color scheme file. * Customizable color codes for files properties * Remove files in bulk via a text editor * `Etiqueta`, a files tagging system * `--sort` accepts strings as well as numeric values * Improved format for the properties string in long mode * Command line switch (`--apparent-size`) to use apparent sizes intead of actual device usage * Disk usage analyzer mode via `-t, --disk-usage-analyzer` * New command: `stats`, to print files statistics * New prompt: Security scanner * New escape codes for the prompt (files statistics) * Allow the warning prompt to understand escape sequences * Colorize command history ELN's * Add color and correctly PAD ELN's in directory history screen * Correctly pad ELN's in bookmarks screen * Replace the plugins-helper check in all plugins by a simple environment variable check: `CLIFM_PLUGINS_HELPER` * `--version` just prints the version number * Wrong size for selected files after moving previous selected files * Error when getting length of file name containing invalid multi-byte sequence * The interactive rename function fails with ~/ file names * `CLIFM_STAT_TRASH` reporting wrong number of trashed files * Wrong cursor position when suggestion is longer than `NAME_MAX` * Crash when `ExtColors` holds a really long string * Some entries not working in the interactive help plugin. * Wrong FZF offset with dynamic prompt changes (e.g. exit code) * When suggesting file names, the last matching one is suggested instead of the first one, as expected * Attempting to use suggestions in terminals that do not support it * Attempting to use colors in terminals that do not support color * Wrongly restoring regular after switching workspaces * `exit` internal command triggers the warning prompt * Color for all workspaces in the prompt is cyan when `--no-color` is passed * Missing new line char after getting media info * Invalid value passed to the `st` function results in sorting by `none` * Conflict between mime parameters(`edit`, `info`, and `import`) if there are files in CWD named likewise * Suggestions are colored in the Linux console even with `--no-color` * Double error message when invalid color scheme is passed via command line * Suggestions for shell built-in are colored even with `--no-color` * Gibberish when no date info in properties function * Inconsistently using apparent and real sizes * Root indicator printed in color even with `--no-color` * Fix mem leak when unrecognized escape code in prompt lines * Fix mem leak if duplicated entries in the config file * Conditional execution fails with fused parameters * Deletion time for trashed files cannot be read by other trash implementations * Wrong mountpoint for mounted archives * Wrong completions in FZF tab when no parameter is passed to the jump command * Wrong completion/suggestion offset for strings starting with chars that need to be quoted * Hidden files wrongly sort in version sort 1.4 - Alma * Little descriptive message for the temp file of the bulk rename function * Colorize files properties (long view and 'pr' command) * Enable FZF TAB completion mode via CLIFM_USE_FZF environment variable * -h can be used to access internal commands help * Support the URI file scheme * Support URL's when running as standalone opener * Add support for gio as resource opener * Lira matches file names now instead of just extensions * Lira can now open URL's when used as standalone resource opener * Lira can perform tilde expansion now * Device information function for the media command * 'bl' suffix generation defaults to '.link' in case the user enters no string * --help includes examples for each internal command * TAB completion for environment variables * Add number of items to prompt indicators (sel, trash, and messages) * 'kb edit', 'cs edit', and 'actions edit' allow second parameter to specify opening application * Add a header to plugins to let the user know what it is/does * Remove calls to system shell from Lira's code * Secure environment and secure commands function * Allow fzftab to select multiple entries (several commands) * The dup command can duplicate now multiple files at once * Customizable tilde color for trimmed files * Improved Unicode support * Handle file names with embedded control characters * Better help (with pager) * Allow passing no option to FZF for TAB completion * FZF theme is now 16 colors by default * A plugins helper script to get a consistent look for all FZF plugins * All FZF plugins now honor NO_COLOR * Add support for NO_COLOR environment variable * --no-color option now makes CliFM truly colorless * More image viewers and video players support out of the box * Add neovim and micro-emacs to the list of default applications for plain text files * Improve mime_list plugin using FZF * New: Backdir (bd): Quickly changes to a parent directory * When the files filter is set, print the number of excluded files * Allow quoted expressions for the filter command * Make Bleach conformant to the Portable Filename Character set * Fix file names in fzfdesel plugin * Read CLIFM_FZF_HEIGHT to get a coherent look for all plugins using fzf * fzfnav allows now to customize the FZF window height via BFG.cfm (#87) * Better sort lock, autosave, and backup files generated by emacs and other programs * New autocommands mode via .cfm.in (entering dir) and .cfm.out (leaving dir) special files * Little export implementation * Allow Lira to understand environment variables (#86) * Add nsxiv support to the mimelist file (sxiv is now unmaintained) * c and m commands sometimes fail when destiny parameter is specified * Auto-unmount not working for the net command * ow lists duplicated entries with TAB completion * No order number expansion for jo command * Wrong completions for paths starting wiht tilde * Won't work when invoked by another program, e.g. via a shell script * Hang when variable defined in profile and internal variables are disabled * plugins-helper not found for FZF plugins * Extraction path for archives triggers the warning prompt * Prompt does not recover color after warning prompt * No colors when running in stealth mode * When running on Wayland Lira does not recognize any graphical application * FZF TAB completion fails with directory names containing spaces * Error compiling with _NO_FZF flag * Directories with spaces no further completed in FZF TAB * Cannot execute command 'm4': shell cmd 'm4' gets executed instead * (SOLVED Invalid free in dup command when destinity is specified * No usage message for vv command * Wrong path when selecting ./FILENAME * Gibberish in long view when files are trimmed (VTE terminals) * Unable to kill external program via Ctrl-c * MaxFilenameLen not working with Unicode file names (#91) * pin cmd (,) triggers the warning prompt * mm info does not correctly display opening application when it has parameters * Crash when going forth to non-existing dir * The --no-color option does not produce a truly colorless interface * Wrong executable name for kakoune editor in mimelist.cfm * The rename prompt is garbled when renaming too long files names * "ELN&" triggering the warning prompt * 'sel' keyword suggested even if there are no selected files * Not switching color scheme with autocommands * Executable scripts not opened as regular files * File names with non standard characters not correctly escaped with TAB completion ------------------------------------------------------------------------ 1.3 - Sebastian * Bleach, a file names cleaner * Improved sorting for Unicode file names * Version sort for non-GNU systems * Environment variables expansion * TAB completion for 'undel' and 'trash del' * Allow directories to be opened via external applications * 'ad' could be used now as opening application in the mimelist file * Autocommands * Customizable colors for workspaces * New cmd: 'media', to handle mount/unmount of storage devices * Get out of mountpoint before unmounting * New keybinding (Alt-q) to delete last typed word * TAB completion for the 'sel' keyword and the deselect command * Allow 'ds' to deselect files passed as parameters * Mark selected files in the files list * New default colors for: some specific file extensions, files counter * Case insensitive files search * --list-on-the-fly option renamed to --autols (same for config file) * Allow settting a max file name length for listed files * The 'mf' command accepts now the 'unset' parameter * Functionality similar to 'imv(1)' for the 'm' command. * Open-with command (ow) * ls(1)-like listing mode * Suggestions for shell builtins * Independent color for the suggestions pointer (>) * ELN padding for file names alignment * Allow editing the history file via 'history edit' * The refresh function does not reset the last cmd exit code anymore * New plugin: fzfdirhist * TAB completion and suggestions for cmd names after process separator chars * Warning prompt for invalid command names * FZF mode for TAB completion * Basic syntax highlighting * Replace execle() by system() * \z returns exit code instead of ascii face * The alias function supports now both single and double quotes * The 'ds' command allows now the user to manually edit the selections file * Optionally allow to quit CliFM with Control-d * Add icon-in-terminal reference to the icons command in the manpage * Home key not bound anymore to anything * Do not split commands not taking ELN's or numbers as parameters * Append .new to file name when creating an already existent file name with the 'new' command. * Use mkstemp() instead of manually creating the file * Use the P_tmpdir macro (defined in stdio.h) to get tmp dir (defaults to /tmp) * Unique temp file for bulk rename * Add broken link error message when opening a broken symlink * MIME Associated application for directories should be clifm * Allow cd to understand CDPATH environment variable ------------------------------------------------------------------------ 1.2.2 - Laura * Add files selection capability to fzfnav * Use libmagic instead of calling file(1) to check ISO and compressed files * Use file descriptors instead of file names to avoid CWE-367. * Allow disabling some files checks for better performance * Support for Alexey Tourbin faster qsort implementation ------------------------------------------------------------------------ 1.2.1 - Ana * Basic syntax highlighting * Allow compiling features in/out * Automatic maintainance of the directory history list * Directly query libmagic library instead of calling file(1) to get MIME types * Haiku specific keybinds files * Allow unicode and strings to further customize the dividing line * Monitor file system changes via inotify (Linux) and kqueue (BSD) * A more consistent color experience out of the box * Custom readline init file to avoid keybinds conflicts * Xterm keybindings work now out of the box * The jump function can now match first and last segments of paths * Improved prompt customization features * Nerdfonts support for icons * Fish-like auto-suggestions system * Allow absolute paths and tilde in the mime file * Allow backgrounding a process with "CMD&" (besides "CMD &") * Add %f placeholder support to Lira for improved flexibility * Added a header file containing usage messages to improve maintainability * The net command is now a completely new remotes management function * Make ihelp plugin POSIX and add manpage sections * catimg and chafa are used to animate gifs * kitty image protocol support to fzfnav plugin * Improved compatibility with POSIX systems * Port to OpenBSD * Port to NetBSD * Port to Haiku * Add import function to mime command * Allow Lira to discriminate between GUI and non-GUI environments * clifmrc, keybindings, and actions.cfm files are now taken from DATADIR * The keybindings file is now keybindings.cfm * Lira uses now the built-in mimelist file by default * Load plugins and color schemes from system dirs besides local dirs * lsd support for dir previews * Automated build system (OBS) * Add DESTDIR to the Makefile for a more flexible installation process * New command: create file duplicate * Exa support for directories preview * Hide cursor while listing files * Automated static analysis * --open is now deprecated. Use positional parameters to open files * Add a config file to BFG * Use hashes as filenames to uniquely identify cached files (for BFG) * New option: -d --config-dir, to specify alternative config dir * Dirjump and path completion are now case-insensitive by default * case-ins-path-comp is now case-sens-path-comp * case-ins-dirjump is now case-sens-dirjump * -x option is now --no-ext-cmds * New logo/icon color * Keep selected files in view (optional) * Batch copy plugin * Reverse files filter ------------------------------------------------------------------------ 1.1 - Nonos * SVG preview support * New plugin: batch files/dirs creation * We finally have a decent logo! * Add command and keybinding for files/dirs creation * Remove hard coded values in config file and replace them by DEF_ macros * Prompt modifier for current profile name (\P) * Git integration (via script as prompt command) * clang-format for automatic formatting (thanks to @sundaran1122) * TAB completion for sort * sort accepts names as well * Allow operanting on particular selected files (as plugin) * Permanet reminder when running as root * Unicode is now enabled by default * Set plugin name as terminal title when running plugins * Warn the user when using ',' and no file is pinned * Add default mimelist file to /usr/share/clifm * Enable external commands by default. * Remove x functions for better portability * Split source code into multiple files for better maintainability (thanks @sundaran1122) * Clean up Makefile (thanks @sundaran1122) * Add subshell prompt notice (as shell code) * Positional parameters for starting path (-p is now deprecated). * Completions for zsh * New plugin: rgfind: Search files by content via Ripgrep, and fzfdeselect * All plugins are now POSIX sh compliant * REGEX support for Lira mimelist file (both mime types and extensions) * fzfnav plugin supports now Ranger's scope previewer script and pistol * Command substitution support for the prompt * Set terminal window title * Do not remove bookmarked, pinned directories, or directories in a workspace from the jump db * Fastback function: ... n -> ../.. n * Keybindings for plugins. Four keybinds allowed. ------------------------------------------------------------------------ 1.0 - Mario * Optional case insensitive path completion and autojump * Recursive search via find * New option to disable ELN's * Replace module operation in listdir by a simple counter * New matching algorithm for autojump using frecency (frequency + recency) + directory basename. * Only-list-matches (no cd) option for autojump (jl). * Option to run trash in place or rm to prevent from accidental deletions * Copy selected files and bulk rename them at once * Alt-. to toggle hidden files on/off * Invert search/selection: exclude via exclamation mark * Advcpmv support (wcp is also supported to copy files) * Fused parameters support for ELN's: 'o12' instead of 'o 12' * Files list max * New sorting methods: owner and group * Improved long view formatting * New, much faster long view function * New, faster listing algorithm: scandir was replaced by readdir and qsort * Workspaces (8) * String support for cmd history * Regex filter to exclude group of filenames from the files list * Option to disable columns * Read stdin: 'cmd | clifm' or 'clifm < list.txt' * Copy plugins from /usr/share/clifm/plugins on first run * Plugins can now talk to CliFM via a dedicated pipe (CLIFM_BUS) * Batch link * Icons support (depends on icons-in-terminal) * Tested on both tmux and screen * Autojump functionality * Regex for all internal commands * File picker and CD on quit (as shell functions) * Integration with FZF via plugins * Plugins: Music playlist, pdf reader, wallpaper setter, image/video preview, updates check, fuzzy finder, fuzzy jumper, drag and drop, FZF navigation, FZF selection, and interactive help plugins * Completions for Bash * Theming support via color schemes * Pinned file/dir * Show only directories option * Environment variables * Bookmark names expansion * New command line options * Stealth mode * Support for custom keybindings and configuration files * More than 20 new keybinds * Lock terminal * Filetype filter for selections * Allow changing readline to vi editing mode ------------------------------------------------------------------------ 0.29.1 * Add disk usage ------------------------------------------------------------------------ 0.29.0 * Directory history map * Avoid duplicates on directory history list * Test keybindings in different terminals: gnome-terminal, konsole, lxterminal, xfce4-terminal, mate-terminal, urxvt, aterm, xterm, terminator, terminology, guake, yakuake, kitty, alacritty, termite, sakura No working on QTerminal and Deepin-terminal (sure it is some config like in Konsole and Yakuake). * Use pointers to the scandir list instead of copying them: FASTER!! * Customizable keybindings!!! * Add max dirhist * Persistent directory history list * Command substitution support for internal commands * Allow all expansions for all parameters of the search function * Add brace expansion to the search function * Add export files function * Improve the brace expansion function using glob() * Create tmp files using random strings * Get rid of LOG_FILE_TMP * Instead of remove(3), use unlink(2) for files and rmdir(2) for dirs * Restore last path on profile switch as well * Fix the mess of the reload function * Add an option to regenerate the config file and backing up the old one * Add a desktop entry for desktop integration ------------------------------------------------------------------------ 0.28.0 * Customizable actions via shell scripts * Restore last visited directory option * Symlink editor * Customm colors for file extensions * New file type colors: multi-hardlinks and non-stat'able files * New sort methods: extension and inode * Print total size of selected files ------------------------------------------------------------------------ 0.27.3 * Integrate archiver() into open(). * Use stat() instead of lstat() in open(): 80 LOC less!! * Use 'mkisofs' to create ISO files: mkisofs -o FILE.iso DIR * I check ".iso" extension to recognize ISO files. Do something better! * Add ISO 9660 files support. * Add auto-open tips. * Add arrow keys navigation. ------------------------------------------------------------------------ 0.27.2 * Add autoopen function: same as autocd, but for files. * Add autocd function: change to dir without cd. * Try $XDG_CONFIG_HOME before falling back to $HOME/.config. * Improve the clear current line function (A-c): make it no print a new line. ------------------------------------------------------------------------ 0.27.1 * Add archive support: Use 'atool' to compress/decompress and 'archivemount' (AUR) to mount. * Add support for custom resource opener * Bulk rename. The 'fff' FM copy all selected filenames to a file, open a text editor to edit them, and then rename the original files. NICE. * Allow reverse sorting order. * Add mtime, btime, atime, and version to the sorting function. * Add different sorting methods: none, name, (c)time, size * Print some tip at startup, like MC does. * Prevent the _err function from storing consecutive equal messages. * Add a light mode to list files faster. Include config file option, command and a keyboard shortcut. * Add a dir counter to symlinks to directory. * List symlinks pointing to directories as directories when listing files. * Add an option to share (or not) the selection box among profiles. * Non-executable files should not be added to paths (that is, not available for commands tab-completion). * Allow get_properties() to recognize the existence of ACL properties, like 'ls -l' does via the plus sign. * TMP_DIR should not be /tmp/clifm, since this is common to all users, in which case network mounpoint could be overwritten. It should be rather /tmp/clifm/user. * Add an option to disable the dir counter, since this feature could slow things down too much when listing files on a remote server. * Add network support for SSH, SMB, and FTP mounts. Use sshfs, mount.cifs, and curlftpfs, for SSH, SMB, and FTP respectivelly. * Add an option to disable files sorting. * Write a better color code check (is_color()). * Remove VLA's (variable length arrays) * Comment the config file to explain the meaning of each option and value, something like the SSH and Samba config files. * Add to "bm del" the possibility to specify the bookmark name to be deleted directly from the command line ("bm del name"). * The commands log function should be disabled by default. * Log the literal command entered by the user, and not the expanded version. * Remove user from the logs line: it's redundant. * Add ranges support for 'trash del'. * Add aliases for commands TAB completion. * Add prompt customization. * Add file extension support to the mime function. * If the MIME file doesn't exist, do not create an empty one, but try to import the values from the 'mimeapps.list' file. * Add the possibility to open files in the background when no application has been passed (ex: o xx &). * Port to FreeBSD. * Port to ARM machines. * The logic of bookmarks and copy functions is crap! Rewrite it. * Add TAB completion for bookmarks. * Set the LS_COLORS environment variable to use CliFM colors for TAB completion. * Do not allow the user to trash some stupid thing like a block or a character device. * Bookmarks: replace "hotkey" by "Shortcut". * Allow the bookmarks function to add or remove bookmarks from the command line: "bm add PATH". * Allow mixed use of sequential and conditional commands. * Add support for commands conditional and sequential execution. * Add ranges to deselect and undel functions. * Disable TAB completion when in bookmarks, mountpoints, undel or desel functions. * Add an argument, -P, to use an alternative profile. * Allow the use of ANSI color codes for prompt, ELN's and text color. * Add the possibility to customize filetypes colors. * Use default values if no config file is found. * Fix calls to calloc to avoid wasting resources. * Replace the dirlist dirent struct by a simple array of string. * Add ELN auto-expansion. * Use gettext to make the program tanslatable to any language * Add to the properties function the ability list properties for more than one file: "pr 1 2-5 10". * Add to the search function the ability to search for files in any directory specified by the user: "/str /path". * Remove the -c argument (run command and exit): it's a remaining of the old shell version of this program. * The errors system can display not only errors, but also warnings, like in the case of modifiyng ~/.Xresources, and any kind of message. Replace the red "E" in the prompt by three different colors and letters: red "E" for errors, yellow "W" for warnings, and green "N" for simple notifications, hints, and so on. I should also modify the log_errors() function and other variables to reflect this change. * Add a pager for the long view mode * Add a long view mode (or info mode) for files listing * Add keybindings for some basic operations: u-j-h-k for filesystem navigation. * Construct the Path line for trashinfo files as in URL's * Add a system to log, store, and display error messages. * Automatically deselect files ONLY in case of trash, remove, or move. * Add error check for chdir(). * Add AUTOMATIC SEL EXPANSION * Add a little trash indicator to the prompt. * Add ranges to remove_function. * Add automatic ELN ranges expansion. * Replace system() by launch_execle(). * Remove the backup function. Replaced by trash. * run_glob_cmd() is now obsolete. Remove it. * Add a glob expansion function to automatically expand wildcards in the command line. Added directly in parse_input_str(). * Add a trash function. * Add some kind of pager to list directories with large amount of files. * Use const for functions parameters if these parameters won't be modified by the function. * Add a forward function as a complement to the back() function. * User defined variables only works for the CLiFM shell. Make it work for the system shell as well, it's a nice feature. * Get rid of the DEFAULT_PATH macro * Let folders-first, show-hidden, and list-on-the-fly as default. Add command line options to enable AND to disable these features. * Add an explanation of the history command (!) to help. * Make the 'back' function remember more paths. * Use the glob function to select files when using wildcards. * Add ranges to the selection function. * Add an explanation of profile and prompt commands to help. * Allow the user to define permanent custom variables in the profile file. * Add a profile file to allow the user to run custom commands when starting CliFM or before the prompt. * Do not allow 'cd' to open files. clifm-1.26.3/CMakeLists.txt000066400000000000000000000060101506632037700154430ustar00rootroot00000000000000cmake_minimum_required(VERSION 3.8) project(CLIFM) add_compile_definitions(CLIFM_DATADIR=${CMAKE_INSTALL_PREFIX}/share) file(GLOB SRC_FILES src/*.c) file(GLOB HDR_FILES src/*.h) add_executable(clifm ${SRC_FILES} ${HDR_FILES} ) if(APPLE) find_package(PkgConfig REQUIRED) find_package(Intl REQUIRED) pkg_check_modules(Readline REQUIRED readline) pkg_check_modules(Magic REQUIRED libmagic) target_include_directories(clifm PUBLIC ${Intl_INCLUDE_DIRS} ${Readline_INCLUDE_DIRS} ${Magic_INCLUDE_DIRS}) target_link_libraries(clifm PUBLIC ${Intl_LIBRARIES} ${Readline_LINK_LIBRARIES} ${Magic_LINK_LIBRARIES} ) elseif(CYGWIN) target_link_libraries(clifm PUBLIC readline acl magic intl ) elseif(UNIX) target_link_libraries(clifm PUBLIC readline acl cap magic ) endif() set(BIN "clifm") set(_MANDIR "share/man/man1") set(_BASHDIR "share/bash-completion/completions") set(_ZSHDIR "share/zsh/site-functions") set(_FISHDIR "share/fish/vendor_completions.d") set(_DESKTOPPREFIX "share/applications") set(_DESKTOPICONPREFIX "share/icons/hicolor/scalable/apps") set(_PROG_DATADIR "share/${BIN}") set(_PLUGINSDIR "${_PROG_DATADIR}/plugins") install(DIRECTORY DESTINATION bin) install(DIRECTORY DESTINATION share/man) install(DIRECTORY DESTINATION "${_MANDIR}") install(DIRECTORY DESTINATION "${_DESKTOPPREFIX}") install(DIRECTORY DESTINATION "${_PROG_DATADIR}") install(DIRECTORY DESTINATION share/icons) install(DIRECTORY DESTINATION share/icons/hicolor) install(DIRECTORY DESTINATION share/icons/hicolor/scalable) install(DIRECTORY DESTINATION "${_DESKTOPICONPREFIX}") install(DIRECTORY DESTINATION "${_ZSHDIR}") install(DIRECTORY DESTINATION share/bash-completion) install(DIRECTORY DESTINATION share/zsh) install(DIRECTORY DESTINATION "${_ZSHDIR}") install(DIRECTORY DESTINATION "${_BASHDIR}") install(TARGETS "${BIN}" DESTINATION bin) install(DIRECTORY plugins DESTINATION "${_PROG_DATADIR}" PATTERN "*.sh" PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) install(DIRECTORY misc/tools DESTINATION "${_PROG_DATADIR}" PATTERN "*.py" PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) install(FILES plugins/BFG.cfg plugins/plugins-helper DESTINATION "${_PLUGINSDIR}") install(FILES misc/actions.clifm misc/keybindings.clifm misc/mimelist.clifm misc/preview.clifm misc/nets.clifm misc/prompts.clifm misc/readline.clifm misc/clifmrc DESTINATION "${_PROG_DATADIR}") install(DIRECTORY misc/colors functions DESTINATION "${_PROG_DATADIR}") install(FILES "misc/${BIN}.desktop" DESTINATION "${_DESKTOPPREFIX}") install(FILES "misc/logo/${BIN}.svg" DESTINATION "${_DESKTOPICONPREFIX}") install(FILES "misc/${BIN}.1" DESTINATION "${_MANDIR}") install(FILES misc/completions.bash DESTINATION "${_BASHDIR}" RENAME "${BIN}") install(FILES misc/completions.zsh DESTINATION "${_ZSHDIR}" RENAME "_${BIN}") install(FILES misc/completions.fish DESTINATION "${_FISHDIR}" RENAME "${BIN}.fish") clifm-1.26.3/LICENSE000066400000000000000000000434161506632037700137230ustar00rootroot00000000000000Copyright(C) 2016 L. Abramovich SPDX-License-Identifier: GPL-2.0-or-later GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. clifm-1.26.3/Makefile000066400000000000000000000073441506632037700143560ustar00rootroot00000000000000###################### # Makefile for clifm # ###################### OS != uname -s BIN ?= clifm PREFIX ?= /usr/local BINDIR ?= $(PREFIX)/bin DATADIR ?= $(PREFIX)/share MANDIR ?= $(DATADIR)/man LOCALEDIR ?= $(DATADIR)/locale DESKTOPPREFIX ?= $(DATADIR)/applications DESKTOPICONPREFIX ?= $(DATADIR)/icons/hicolor PROG_DATADIR ?= $(DATADIR)/$(BIN) SHELL ?= /bin/sh INSTALL ?= install RM ?= rm SRCDIR = src SRC = $(SRCDIR)/*.c HEADERS = $(SRCDIR)/*.h CFLAGS ?= -O3 -fstack-protector-strong CFLAGS += -Wall -Wextra CPPFLAGS += -DCLIFM_DATADIR=$(DATADIR) LIBS_Linux ?= -lreadline -lacl -lcap -lmagic LIBS_FreeBSD ?= -I/usr/local/include -L/usr/local/lib -lreadline -lintl -lmagic LIBS_DragonFly ?= -I/usr/local/include -L/usr/local/lib -lreadline -lintl -lmagic LIBS_NetBSD ?= -I/usr/pkg/include -I/usr/pkg/include/gettext -L/usr/pkg/lib -Wl,-R/usr/pkg/lib -lreadline -lintl -lmagic -lutil LIBS_OpenBSD ?= -I/usr/local/include -L/usr/local/lib -lereadline -lintl -lmagic LIBS_Darwin ?= -I/opt/local/include -L/opt/local/lib -lreadline -lintl -lmagic $(BIN): $(SRC) $(HEADERS) @printf "Detected operating system: %s\n" "$(OS)" $(CC) -o $(BIN) $(SRC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) $(LIBS_$(OS)) build: $(BIN) clean: $(RM) -- $(BIN) $(RM) -f -- $(SRCDIR)/*.o install: $(BIN) $(INSTALL) -m 0755 -d $(DESTDIR)$(BINDIR) $(INSTALL) -m 0755 $(BIN) $(DESTDIR)$(BINDIR) $(INSTALL) -m 0755 -d $(DESTDIR)$(PROG_DATADIR) $(INSTALL) -m 0755 -d $(DESTDIR)$(MANDIR)/man1 $(INSTALL) -m 0755 -d $(DESTDIR)$(DATADIR)/bash-completion/completions $(INSTALL) -m 0755 -d $(DESTDIR)$(DATADIR)/zsh/site-functions $(INSTALL) -m 0755 -d $(DESTDIR)$(DATADIR)/fish/vendor_completions.d $(INSTALL) -m 0755 -d $(DESTDIR)$(DESKTOPPREFIX) $(INSTALL) -m 0755 -d $(DESTDIR)$(DESKTOPICONPREFIX)/scalable/apps $(INSTALL) -m 0644 misc/$(BIN).1 $(DESTDIR)$(MANDIR)/man1 $(INSTALL) -m 0644 misc/completions.bash $(DESTDIR)$(DATADIR)/bash-completion/completions/$(BIN) $(INSTALL) -m 0644 misc/completions.zsh $(DESTDIR)$(DATADIR)/zsh/site-functions/_$(BIN) $(INSTALL) -m 0644 misc/completions.fish $(DESTDIR)$(DATADIR)/fish/vendor_completions.d/$(BIN).fish $(INSTALL) -m 0644 misc/$(BIN).desktop $(DESTDIR)$(DESKTOPPREFIX) $(INSTALL) -m 0644 misc/*.clifm $(DESTDIR)$(PROG_DATADIR) $(INSTALL) -m 0644 misc/clifmrc $(DESTDIR)$(PROG_DATADIR) $(INSTALL) -m 0644 misc/logo/$(BIN).svg $(DESTDIR)$(DESKTOPICONPREFIX)/scalable/apps $(INSTALL) -m 0755 -d $(DESTDIR)$(PROG_DATADIR)/plugins $(INSTALL) -m 0755 -d $(DESTDIR)$(PROG_DATADIR)/functions $(INSTALL) -m 0755 -d $(DESTDIR)$(PROG_DATADIR)/colors $(INSTALL) -m 0755 -d $(DESTDIR)$(PROG_DATADIR)/tools $(INSTALL) -m 0755 misc/tools/imgprev/clifmrun $(DESTDIR)$(PROG_DATADIR)/plugins $(INSTALL) -m 0755 misc/tools/imgprev/clifmimg $(DESTDIR)$(PROG_DATADIR)/plugins $(INSTALL) -m 0755 plugins/* $(DESTDIR)$(PROG_DATADIR)/plugins $(INSTALL) -m 0755 misc/tools/*.py $(DESTDIR)$(PROG_DATADIR)/tools chmod 644 $(DESTDIR)$(PROG_DATADIR)/plugins/BFG.cfg chmod 644 $(DESTDIR)$(PROG_DATADIR)/plugins/plugins-helper $(INSTALL) -m 0644 misc/colors/*.clifm $(DESTDIR)$(PROG_DATADIR)/colors $(INSTALL) -m 0644 functions/* $(DESTDIR)$(PROG_DATADIR)/functions $(INSTALL) -m 0755 functions/install-extensions.fish $(DESTDIR)$(PROG_DATADIR)/functions @printf "Successfully installed $(BIN)\n" uninstall: $(RM) -- $(DESTDIR)$(BINDIR)/$(BIN) $(RM) -- $(DESTDIR)$(MANDIR)/man1/$(BIN).1* $(RM) -- $(DESTDIR)$(DATADIR)/bash-completion/completions/$(BIN) $(RM) -- $(DESTDIR)$(DATADIR)/zsh/site-functions/_$(BIN) $(RM) -- $(DESTDIR)$(DATADIR)/fish/vendor_completions.d/$(BIN).fish $(RM) -- $(DESTDIR)$(DESKTOPPREFIX)/$(BIN).desktop $(RM) -r -- $(DESTDIR)$(PROG_DATADIR) $(RM) -- $(DESTDIR)$(DESKTOPICONPREFIX)/scalable/apps/$(BIN).svg @printf "Successfully uninstalled $(BIN)\n" clifm-1.26.3/README.md000066400000000000000000001003741506632037700141720ustar00rootroot00000000000000

CliFM logo

The Command Line File Manager

No GUI, no TUI, and no menus: just you and a powerful, file-management-oriented command line.

Install · Browse the documentation · Request feature · Report bug

---

GitHub release (latest by date)

--- [![demo](https://asciinema.org/a/ov5HnwdlPvnR7ucfDrQMfeg2N.svg)](https://asciinema.org/a/ov5HnwdlPvnR7ucfDrQMfeg2N?autoplay=1) --- ## :space_invader: Brief description **Clifm** is a shell-like, text-based terminal file manager that sits on the command line. Some of its key features include: bookmarks, search, file selection, file tags, file filters, file previews (including image previews), bulk rename, archiving, trash, file opener, directory jumper, autocommands, workspaces, plugins, autosuggestions, specific command line expansions, and more. Consult the [Features](#heavy_check_mark-features) section below for a more comprehensive list. While feature-rich, powerful, and extensible, its true strength lies in its design philosophy. Unlike traditional terminal file managers, based on the text user interface (TUI), **clifm** embraces the command-line interface (CLI). This means you can interact with your filesystem by typing commands directly, just as you would in a regular shell, but with greater ease, speed, and advanced capabilities. For this reason, **clifm** does not need to be better: it's **just different!** :wink: To get started, consult the [Getting started](#bulb-getting-started) section below. --- ## :heavy_check_mark: Features
Click here to expand In addition to common file operations, such as copy, move, remove, etc., **clifm** provides the following features: - Specific - [Really CLI-based](https://github.com/leo-arch/clifm/wiki/Introduction#main-design-and-goals). No GUI nor TUI at all, but just a command-line - It can run on the kernel built-in console and even on a SSH or any other remote session - Highly compatible with old VT102-only terminal emulators like Rxvt and Rxvt-based ones: even on a terminal with only 8 colors and no Unicode support, **clifm** will just work. [It can run even on an old DEC-VT100 terminal!](https://github.com/leo-arch/clifm/wiki/Extra#clifm-running-on-a-dec-vt100-terminal-1978) - [High performance](https://github.com/leo-arch/clifm/wiki/Performance). Incredibly lightweight and fast even on really old hardware - [Short (and even one-character) commands](https://github.com/leo-arch/clifm/wiki/Introduction#commands-short-summary) - [Entry list numbers (ELNs)](https://github.com/leo-arch/clifm/wiki/Common-Operations#elns) for filenames - [Extended color codes](https://github.com/leo-arch/clifm/wiki/Customization#colors) for file-types and -extensions - [File counter](https://github.com/leo-arch/clifm/wiki/Introduction#interface) for directories and symlinks to directories - Support for files attributes, extended attributes, birth time, BSD flags, and Solaris doors. - Privacy: Zero data collection and no connection to the outside world at all - Security: [Secure environment](https://github.com/leo-arch/clifm/wiki/Specifics#security) and [secure commands](https://github.com/leo-arch/clifm/wiki/Specifics#security). See also the [stealth mode section](https://github.com/leo-arch/clifm/wiki/Specifics#stealth-mode) - Navigation and file operations - [Bookmarks](https://github.com/leo-arch/clifm/wiki/Common-Operations#bookmarks) - [File selection](https://github.com/leo-arch/clifm/wiki/Common-Operations#selection) (supports both glob and regular expressions and works even across multiple instances of the program) - [File opener](https://github.com/leo-arch/clifm/wiki/Specifics#file-opener) (supports regular expressions and is able to discern between GUI and non-GUI environments) - [File previews](https://github.com/leo-arch/clifm/wiki/Advanced#files-preview) (including [image previews](https://github.com/leo-arch/clifm/tree/master/misc/tools/imgprev)) - [File tags](https://github.com/leo-arch/clifm/wiki/Common-Operations#tagging-files) - [File filters](https://github.com/leo-arch/clifm/wiki/Advanced#files-filters) (including support for [`.hidden` files](https://github.com/leo-arch/clifm/wiki/Advanced#1b-hidden-files)) - [File search](https://github.com/leo-arch/clifm/wiki/Common-Operations#searching) (supports both glob and regular expressions) - [File templates](https://github.com/leo-arch/clifm/wiki/Introduction#n-new) - [Filenames sanitizer](https://github.com/leo-arch/clifm/wiki/Introduction#bb-bleach) - [A Freedesktop-compliant trash system](https://github.com/leo-arch/clifm/wiki/Common-Operations#trashing-files) - [copy(-as), move(-as)](https://github.com/leo-arch/clifm/wiki/Introduction#c-l-e-edit-m-md-r), [interactive rename](https://github.com/leo-arch/clifm/wiki/Introduction#c-l-e-edit-m-md-r), and [open-with](https://github.com/leo-arch/clifm/wiki/Introduction#ow) functions - [Bulk operations](https://github.com/leo-arch/clifm/wiki/Advanced#bulk-operations): rename, create, remove, and create symbolik links in bulk - [File encryption/decryption (plugin)](https://github.com/leo-arch/clifm/wiki/Advanced#plugins) - [Archiving and compression](https://github.com/leo-arch/clifm/wiki/Advanced#archives) support (including Zstandard and ISO 9660) - [Symlinks editor](https://github.com/leo-arch/clifm/wiki/Introduction#l-le) - File permissions/ownership editor via the [`pc`](https://github.com/leo-arch/clifm/wiki/Introduction#pc) and [`oc`](https://github.com/leo-arch/clifm/wiki/Introduction#oc) commands respectively - [Advanced Copy](https://github.com/leo-arch/clifm/wiki/Advanced#cpmv-with-a-progress-bar) support (just `cp` and `mv` with a nice progress bar) - [Copy files to your smart phone (plugin)](https://github.com/leo-arch/clifm/wiki/Advanced#plugins) - [Autocommands](https://github.com/leo-arch/clifm/wiki/Specifics#autocommands) - [Auto-cd](https://github.com/leo-arch/clifm/wiki/Introduction#acd-autocd), [auto-open](https://github.com/leo-arch/clifm/wiki/Introduction#ao-auto-open), and [autols](https://github.com/leo-arch/clifm/wiki/Common-Operations#navigation) - [Directory jumper](https://github.com/leo-arch/clifm/wiki/Specifics#kangaroos-frecency-algorithm) (similar to [autojump](https://github.com/wting/autojump), [z.lua](https://github.com/skywind3000/z.lua), and [zoxide](https://github.com/ajeetdsouza/zoxide)) - [Virtual directories](https://github.com/leo-arch/clifm/wiki/Advanced#virtual-directories) - [Fastback](https://github.com/leo-arch/clifm/wiki/Introduction#fastback) (quickly change to any parent directory) - [Up to eight workspaces](https://github.com/leo-arch/clifm/wiki/Specifics#workspaces) - [More than a dozen sort methods](https://github.com/leo-arch/clifm/wiki/Introduction#st-sort) - [Remote filesystems management](https://github.com/leo-arch/clifm/wiki/Introduction#net) - [Mount/unmount storage devices](https://github.com/leo-arch/clifm/wiki/Introduction#media) - Directory history map (keep in sight previous, current, and next entries in the directory history list) - Shell - [Tab completion](https://github.com/leo-arch/clifm/wiki/Specifics#expansions-completions-and-suggestions), with _fzf_ integration (including [file previews](https://github.com/leo-arch/clifm/wiki/Advanced#files-preview)) - [Command line expansions](https://github.com/leo-arch/clifm/wiki/Introduction#command-line-expansions) (including bookmarks, selected files, tags, MIME types, and file types) - [Auto-suggestions](https://github.com/leo-arch/clifm/wiki/Specifics#auto-suggestions) - [Syntax highlighting](https://github.com/leo-arch/clifm/wiki/Specifics#syntax-highlighting) - [Warning prompt](https://github.com/leo-arch/clifm/wiki/Customization#the-warning-prompt) (for invalid command names) - [Fused parameters for ELNs](https://github.com/leo-arch/clifm/wiki/Introduction#fused-parameters) - [Fuzzy completion for filenames and paths](https://github.com/leo-arch/clifm/wiki/Specifics#fuzzy-match) - Bash-like quoting system - Shell commands execution - Sequential and conditional commands execution - [Directory](https://github.com/leo-arch/clifm/wiki/Introduction#b-back) and [commands](https://github.com/leo-arch/clifm/wiki/Introduction/#commands-history) history - [Glob and regular expressions](https://github.com/leo-arch/clifm/wiki/Advanced#wildcards-and-regex) (including inverse matching) - [Aliases](https://github.com/leo-arch/clifm/wiki/Customization#aliases) - [Logs](https://github.com/leo-arch/clifm/wiki/Introduction#log) - [Prompt and profile commands](https://github.com/leo-arch/clifm/wiki/Customization#profile-and-prompt-commands) (run commands with each new prompt or at program startup) - Modes - [Stealth mode](https://github.com/leo-arch/clifm/wiki/Specifics#stealth-mode) (also known as incognito or private mode) - [Light mode](https://github.com/leo-arch/clifm/wiki/Specifics#light-mode) (just in case it is not fast enough for you) - [File opener](https://github.com/leo-arch/clifm/wiki/Specifics#using-clifm-as-a-standalone-file-opener) (similar to `xdg` and Ranger's `rifle`) - [File previewer](https://github.com/leo-arch/clifm/wiki/Advanced#shotgun) (similar to [`pistol`](https://github.com/yonasBSD/pistol) and Ranger's `scope.sh`) - [Disk usage analyzer](https://github.com/leo-arch/clifm/wiki/Specifics#disk-usage-analyzer) - [File lister (ls-mode)](https://github.com/leo-arch/clifm/wiki/Advanced#files-lister-ls-mode) - [Stat mode](https://github.com/leo-arch/clifm/wiki/Advanced/#stat1-replacement) (just like the shell command **stat**) - Customization - [Custom commands](https://github.com/leo-arch/clifm/wiki/Customization#custom-commands) - [User profiles](https://github.com/leo-arch/clifm/wiki/Specifics#profiles) - [Customizable keyboard shortcuts](https://github.com/leo-arch/clifm/wiki/Customization#keybindings) - [Theming](https://github.com/leo-arch/clifm/wiki/Customization#theming) (including [bundled color schemes](https://github.com/leo-arch/clifm/tree/master/misc/colors) and [**LS_COLORS** support](https://github.com/leo-arch/clifm/wiki/Customization#ls_colors-support)) - [Prompt customization](https://github.com/leo-arch/clifm/wiki/Customization#the-prompt) - [Customizable keybindings for custom plugins](https://github.com/leo-arch/clifm/wiki/Customization#keybindings) - [Compile features in/out](https://github.com/leo-arch/clifm/blob/master/src/README.md#compiling-features-inout) - Misc - [Plugins](https://github.com/leo-arch/clifm/wiki/Advanced#plugins) - [Icons support](https://github.com/leo-arch/clifm/wiki/Advanced#icons-smirk) (including emoji-icons :smirk:) - [Git integration](https://github.com/leo-arch/clifm/wiki/Advanced#git-integration) - [Desktop notifications](https://github.com/leo-arch/clifm/wiki/Specifics#desktop-notifications) - Unicode support. - [CD on quit](https://github.com/leo-arch/clifm/wiki/Advanced#cd-on-quit) and [file picker](https://github.com/leo-arch/clifm/wiki/Advanced#file-picker) functions - [A built-in pager](https://github.com/leo-arch/clifm/wiki/Introduction#pg-pager) for files listing - Read and list files from [STDIN (standard input)](https://github.com/leo-arch/clifm/wiki/Advanced#standard-input)


Auto-suggestions in action

--- For a detailed explanation of each of these features, follow the corresponding links or consult the [Wiki](https://github.com/leo-arch/clifm/wiki).
--- ## :clapper: Introduction video [![Alt text](https://img.youtube.com/vi/CJmcisw9F90/0.jpg)](https://www.youtube.com/watch?v=CJmcisw9F90) --- ## :floppy_disk: Installation ### From a package manager
Packaging status Packaging status Packaging status
If running on Linux, [binary packages](https://software.opensuse.org//download.html?project=home%3Aarchcrack&package=clifm) are available for most major distributions via the OpenSUSE Build System. ### From source (Linux/BSD) **Note**: Dependencies are most likely already satisfied, but, in any case, consult the [dependencies section](https://github.com/leo-arch/clifm/wiki/Introduction#1-satisfy-dependencies). ```sh git clone https://github.com/leo-arch/clifm.git cd clifm sudo make install ``` For more information/supported platforms, consult the [installation page](https://github.com/leo-arch/clifm/wiki/Introduction#installation). --- ## :bulb: Getting started To start using **clifm**, _you don't need to learn anything new_: the usual shell commands will just work. However, there is much more than just shell commands... \ ✓ The `help` command gives you a quick introduction to **clifm**: once in the command prompt, enter `help` or `?`. \ ✓ Type `cmd` to get the list of available commands and a brief description. \ ✓ Type `help ` to get the list of available _help topics_. Select the one you want and press Enter. \ ✓ To jump into the **COMMANDS** section in the [manpage](https://github.com/leo-arch/clifm/blob/master/misc/clifm.1.pdf), simply enter `cmd` or press F2. \ ✓ Press F1 to access the full manpage and F3 to access the keybindings help-page. \ ✓ To get help about some specific command, just enter `CMD -h`. For instance, `s -h`. You can also take a look at our [FAQ](https://github.com/leo-arch/clifm/wiki/FAQ) and these [basic usage-examples](https://github.com/leo-arch/clifm/wiki/Common-Operations#basic-usage-examples). \ For a complete description, please consult our [Wiki](https://github.com/leo-arch/clifm/wiki). > [!TIP] > Start **clifm** and just press a number (technically, an ELN or [Entry List Number](https://github.com/leo-arch/clifm/wiki/Common-Operations#elns)). --- ## :newspaper: What's new? Consult the [changelog file](https://github.com/leo-arch/clifm/blob/master/CHANGELOG). --- ## Support **Clifm** runs on Linux, Termux (Android), FreeBSD, NetBSD, OpenBSD, DragonFly, MacOS, Solaris/Illumos, Haiku, and Cygwin/MinGW, on x86, ARM, PowerPC, and RISC-V architectures. --- ## License This project is licensed GPL version 2 (or later). See the [LICENSE file](https://github.com/leo-arch/clifm/blob/master/LICENSE) for details. --- ## Contributing Contributions are kindly welcome! Please see our [contribution guidelines](https://github.com/leo-arch/clifm/wiki/CONTRIBUTING) for details. --- ## Community Visit the [Discussions section](https://github.com/leo-arch/clifm/discussions) of this repo and let us know what you think: ideas, comments, observations and questions are always useful. --- ## Developer [Leo Abramovich](https://github.com/leo-arch) <>. Special thanks to [all those who have contributed to this project](https://github.com/leo-arch/clifm/graphs/contributors). clifm-1.26.3/functions/000077500000000000000000000000001506632037700147165ustar00rootroot00000000000000clifm-1.26.3/functions/cd_on_quit.fish000066400000000000000000000014571506632037700177240ustar00rootroot00000000000000# CliFM CD on quit # Description # Run Clifm, read the .last file, and cd into it. # # 1) Customize this function as needed and copy it into your fish functions directory as a .fish file with the same name. # For example, with the default name, the file should be c.fish. # 2) Run clifm using the name of the function below: c [ARGS ...] # Dependecies: clifm, cut, grep # Author: Spenser Black # License: GPL3 function c --wraps=clifm --description="Change directory after exiting clifm" clifm "--cd-on-quit" $argv set --query XDG_CONFIG_HOME; and set --function config_home "$XDG_CONFIG_HOME"; or set --function config_home "$HOME/.config" set --function dir "$(grep "^\*" "$config_home/clifm/.last" 2>/dev/null | cut -d':' -f2)" if test "$dir" cd -- "$dir"; or return 1 end end clifm-1.26.3/functions/cd_on_quit.sh000066400000000000000000000010551506632037700173770ustar00rootroot00000000000000# shellcheck shell=sh # CliFM CD on quit function # Description # Run Clifm, read the .last file, and cd into it. # 1) Customize this function as you need and copy it or source it from your shell configuration file (e.g., .bashrc, .zshrc, etc) # 2) Restart your shell (for changes to take effect) # 3) Run clifm using the name of the function below: c [ARGS ...] c() { clifm "--cd-on-quit" "$@" dir="$(grep "^\*" "${XDG_CONFIG_HOME:=${HOME}/.config}/clifm/.last" 2>/dev/null | cut -d':' -f2)"; if [ -d "$dir" ]; then cd -- "$dir" || return 1 fi } clifm-1.26.3/functions/install-extensions.fish000077500000000000000000000026441506632037700214450ustar00rootroot00000000000000#!/usr/bin/env fish # Install Clifm extension functions # Description # Execute this script to install the provided fish functions to the functions directory. # Note that this will use the default, single-letter function names. # Usage: install-extensions.fish [FUNCTIONS] # # FUNCTIONS: A list of the filenames of the functions to install. # For example, install-extensions cd_on_quit will install # the function with the default name c to the functions directory. # If not provided, all functions will be installed. # Author: Spenser Black # License: GPL3 set -l dir (dirname (status -f)) argparse --name=install-extensions 'h/help' -- $argv if test $_flag_h echo "Usage: install-extensions.fish [FUNCTIONS]" echo "" echo "FUNCTIONS: A list of the filenames of the functions to install." echo " For example, install-extensions cd_on_quit will install" echo " the function with the default name c to the functions directory." echo " If not provided, all functions will be installed." exit 0 end set -l sources cd_on_quit file_picker set -l destinations c p test (count $argv) -eq 0; and set -l extensions $sources; or set -l extensions $argv for source in $sources set -l index (contains -i -- $source $extensions) set -l destination $destinations[$index] cp "$dir/$source.fish" "$__fish_config_dir/functions/$destination.fish" end clifm-1.26.3/functions/subshell_notice.sh000066400000000000000000000005211506632037700204320ustar00rootroot00000000000000# shellcheck shell=sh # Description: Change the shell prompt to notify the user that this # shell has been spawned from within Clifm # Author: L. Abramovich # License: GPL2+ # Usage: # Copy the following line or source this file from your shell # configuration file (ex: .bashrc, .zshrc, etc) [ -n "$CLIFM" ] && PS1="$PS1"'(clifm) ' clifm-1.26.3/misc/000077500000000000000000000000001506632037700136415ustar00rootroot00000000000000clifm-1.26.3/misc/GNU/000077500000000000000000000000001506632037700142725ustar00rootroot00000000000000clifm-1.26.3/misc/GNU/Makefile000066400000000000000000000116301506632037700157330ustar00rootroot00000000000000 ###################### # Makefile for clifm # ###################### OS != uname -s BIN ?= clifm PREFIX ?= /usr/local BINDIR ?= $(PREFIX)/bin DATADIR ?= $(PREFIX)/share MANDIR ?= $(DATADIR)/man LOCALEDIR ?= $(DATADIR)/locale DESKTOPPREFIX ?= $(DATADIR)/applications DESKTOPICONPREFIX ?= $(DATADIR)/icons/hicolor PROG_DATADIR ?= $(DATADIR)/$(BIN) SHELL ?= /bin/sh INSTALL ?= install RM ?= rm SRCDIR = src SRC = $(SRCDIR)/*.c HEADERS = $(SRCDIR)/*.h LMAGIC = -lmagic LINTL = -lintl LUTIL = -lutil ifdef DEBUG CFLAGS += -g else CFLAGS ?= -O3 -fstack-protector-strong endif ifdef CPU_NATIVE CFLAGS += -march=native endif ifdef CLIFM_SUCKLESS CPPFLAGS += -DCLIFM_SUCKLESS endif ifdef _NO_TAGS CPPFLAGS += -D_NO_TAGS endif ifdef _NO_BLEACH CPPFLAGS += -D_NO_BLEACH endif ifdef _TOURBIN_QSORT CPPFLAGS += -D_TOURBIN_QSORT endif ifdef _NO_HIGHLIGHT CPPFLAGS += -D_NO_HIGHLIGHT endif ifdef _NO_FZF CPPFLAGS += -D_NO_FZF endif ifdef _BE_POSIX CPPFLAGS += -D_BE_POSIX endif ifdef _NO_ARCHIVING CPPFLAGS += -D_NO_ARCHIVING endif ifdef _ICONS_IN_TERMINAL CPPFLAGS += -D_ICONS_IN_TERMINAL endif ifdef _NERD CPPFLAGS += -D_NERD endif ifdef _NO_GETTEXT CPPFLAGS += -D_NO_GETTEXT undefine LINTL endif ifdef _NO_ICONS CPPFLAGS += -D_NO_ICONS endif ifdef _NO_LIRA CPPFLAGS += -D_NO_LIRA undefine LMAGIC endif ifdef _NO_MAGIC CPPFLAGS += -D_NO_MAGIC undefine LMAGIC endif ifdef _NO_NETBSD_FFLAGS CPPFLAGS += -D_NO_NETBSD_FFLAGS undefine LUTIL endif ifdef _NO_PROFILES CPPFLAGS += -D_NO_PROFILES endif ifdef _NO_SUGGESTIONS CPPFLAGS += -D_NO_SUGGESTIONS endif ifdef _NO_TRASH CPPFLAGS += -D_NO_TRASH endif ifdef _VANILLA_READLINE CPPFLAGS += -D_VANILLA_READLINE endif CFLAGS += -Wall -Wextra CPPFLAGS += -DCLIFM_DATADIR=$(DATADIR) LIBS_Linux ?= -lreadline -lacl -lcap $(LMAGIC) LIBS_FreeBSD ?= -I/usr/local/include -L/usr/local/lib -lreadline $(LINTL) $(LMAGIC) LIBS_DragonFly ?= -I/usr/local/include -L/usr/local/lib -lreadline $(LINTL) $(LMAGIC) LIBS_NetBSD ?= -I/usr/pkg/include -L/usr/pkg/lib -Wl,-R/usr/pkg/lib -lreadline $(LINTL) $(LMAGIC) $(LUTIL) LIBS_OpenBSD ?= -I/usr/local/include -L/usr/local/lib -lereadline $(LINTL) $(LMAGIC) LIBS_Darwin ?= -I/opt/local/include -L/opt/local/lib -lreadline $(LINTL) $(LMAGIC) $(BIN): $(SRC) $(HEADERS) @printf "Detected operating system: %s\n" "$(OS)" $(CC) -o $(BIN) $(SRC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) $(LIBS_$(OS)) build: $(BIN) clean: $(RM) -- $(BIN) $(RM) -f -- $(SRCDIR)/*.o install: $(BIN) $(INSTALL) -m 0755 -d $(DESTDIR)$(BINDIR) $(INSTALL) -m 0755 $(BIN) $(DESTDIR)$(BINDIR) $(INSTALL) -m 0755 -d $(DESTDIR)$(PROG_DATADIR) $(INSTALL) -m 0755 -d $(DESTDIR)$(MANDIR)/man1 $(INSTALL) -m 0755 -d $(DESTDIR)$(DATADIR)/bash-completion/completions $(INSTALL) -m 0755 -d $(DESTDIR)$(DATADIR)/zsh/site-functions $(INSTALL) -m 0755 -d $(DESTDIR)$(DATADIR)/fish/vendor_completions.d $(INSTALL) -m 0755 -d $(DESTDIR)$(DESKTOPPREFIX) $(INSTALL) -m 0755 -d $(DESTDIR)$(DESKTOPICONPREFIX)/scalable/apps $(INSTALL) -m 0644 misc/$(BIN).1 $(DESTDIR)$(MANDIR)/man1 $(INSTALL) -m 0644 misc/completions.bash $(DESTDIR)$(DATADIR)/bash-completion/completions/$(BIN) $(INSTALL) -m 0644 misc/completions.zsh $(DESTDIR)$(DATADIR)/zsh/site-functions/_$(BIN) $(INSTALL) -m 0644 misc/completions.fish $(DESTDIR)$(DATADIR)/fish/vendor_completions.d/$(BIN).fish $(INSTALL) -m 0644 misc/$(BIN).desktop $(DESTDIR)$(DESKTOPPREFIX) $(INSTALL) -m 0644 misc/*.clifm $(DESTDIR)$(PROG_DATADIR) $(INSTALL) -m 0644 misc/clifmrc $(DESTDIR)$(PROG_DATADIR) $(INSTALL) -m 0644 misc/logo/$(BIN).svg $(DESTDIR)$(DESKTOPICONPREFIX)/scalable/apps $(INSTALL) -m 0755 -d $(DESTDIR)$(PROG_DATADIR)/plugins $(INSTALL) -m 0755 -d $(DESTDIR)$(PROG_DATADIR)/functions $(INSTALL) -m 0755 -d $(DESTDIR)$(PROG_DATADIR)/colors $(INSTALL) -m 0755 -d $(DESTDIR)$(PROG_DATADIR)/tools $(INSTALL) -m 0755 plugins/* $(DESTDIR)$(PROG_DATADIR)/plugins $(INSTALL) -m 0755 misc/tools/imgprev/clifmrun $(DESTDIR)$(PROG_DATADIR)/plugins $(INSTALL) -m 0755 misc/tools/imgprev/clifmimg $(DESTDIR)$(PROG_DATADIR)/plugins $(INSTALL) -m 0755 misc/tools/*.py $(DESTDIR)$(PROG_DATADIR)/tools chmod 644 $(DESTDIR)$(PROG_DATADIR)/plugins/BFG.cfg chmod 644 $(DESTDIR)$(PROG_DATADIR)/plugins/plugins-helper $(INSTALL) -m 0644 misc/colors/*.clifm $(DESTDIR)$(PROG_DATADIR)/colors $(INSTALL) -m 0644 functions/* $(DESTDIR)$(PROG_DATADIR)/functions $(INSTALL) -m 0755 functions/install-extensions.fish $(DESTDIR)$(PROG_DATADIR)/functions @printf "Successfully installed $(BIN)\n" uninstall: $(RM) -- $(DESTDIR)$(BINDIR)/$(BIN) $(RM) -- $(DESTDIR)$(MANDIR)/man1/$(BIN).1* $(RM) -- $(DESTDIR)$(DATADIR)/bash-completion/completions/$(BIN) $(RM) -- $(DESTDIR)$(DATADIR)/zsh/site-functions/_$(BIN) $(RM) -- $(DESTDIR)$(DATADIR)/fish/vendor_completions/$(BIN).fish $(RM) -- $(DESTDIR)$(DESKTOPPREFIX)/$(BIN).desktop $(RM) -r -- $(DESTDIR)$(PROG_DATADIR) $(RM) -- $(DESTDIR)$(DESKTOPICONPREFIX)/scalable/apps/$(BIN).svg @printf "Successfully uninstalled $(BIN)\n" clifm-1.26.3/misc/actions.clifm000066400000000000000000000021411506632037700163130ustar00rootroot00000000000000 ###################### # Clifm Actions File # ###################### # Empty and commented lines are ignored. # Define here your custom actions. # Actions are custom command names bound to an executable file located # either in DATADIR/clifm/plugins (usually /usr/share/clifm/plugins) or # in $XDG_CONFIG_HOME/clifm/plugins (usually ~/.config/clifm/plugins). # Actions can be executed directly from the Clifm command line, as if # they were any other command: the associated file will be executed # instead. # All parameters passed to the action command will be passed to the # corresponding plugin as well. +=finder.sh ++=jumper.sh -=fzfnav.sh *=fzfsel.sh **=fzfdesel.sh //=rgfind.sh _=fzcd.sh bcp=batch_copy.sh bmi=bm_import.sh bn=batch_create.sh clip=clip.sh cr=cprm.sh da=disk_analyzer.sh dr=dragondrop.sh fdups=fdups.sh gg=pager.sh h=fzfhist.sh i=img_viewer.sh ih=ihelp.sh kd=decrypt.sh ke=encrypt.sh ml=mime_list.sh music=music_player.sh ptot=pdf_viewer.sh rrm=recur_rm.sh update=update.sh vid=vid_viewer.sh vt=virtualize.sh wall=wallpaper_setter.sh plugin1=xclip.sh clifm-1.26.3/misc/clifm.1000066400000000000000000006434521506632037700150330ustar00rootroot00000000000000.TH "CLIFM" "1" "Sep 28, 2025" "clifm 1.26.3" "Clifm Manual" .SH NAME clifm \- The Command Line File Manager .SH SYNOPSIS .B clifm [\fI\,OPTION\/\fR]... [\fI\,DIR\/\fR]... .SH INDEX \fB1.\fR Getting help .sp \fB2.\fR Description .sp \fB3.\fR Parameters . Positional parameters . Options .sp \fB4.\fR Commands .sp \fB5.\fR File Filters (by filename, file type, and MIME type) .sp \fB6.\fR Keyboard shortcuts .sp \fB7.\fR Theming .sp \fB8.\fR Builtin expansions .sp \fB9.\fR Tab completion .sp \fB10.\fR File opener (third\-party openers are supported) .sp \fB11.\fR Shotgun, the file previewer .sp \fB12.\fR Auto\-suggestions (including a warning prompt for invalid command names) .sp \fB13.\fR Shell functions .sp \fB14.\fR Plugins .sp \fB15.\fR Autocommands .sp \fB16.\fR File tags .sp \fB17.\fR Virtual directories .sp \fB18.\fR Note on speed .sp \fB19.\fR Kangaroo frecency algorithm .sp \fB20.\fR Environment .sp \fB21.\fR Security .sp \fB22.\fR Miscellaneous notes .sp \fB23.\fR Files .sp \fB24.\fR Examples .SH 1. GETTING HELP There are several ways to access help in \fBclifm\fR. Once you are in the program, enter `\fB?\fR` or `\fBhelp\fR` for some basic usage examples, or press \fBF1\fR to access this manpage, \fBF2\fR to go to the \fBCOMMANDS\fR section of this manpage, or \fBF3\fR to jump to the \fBKEYBOARD SHORTCUTS\fR section. .sp To get help about some specific topic, type `\fBhelp \fR` to get a list of available help topics. Choose the topic you want and then press \fBEnter\fR. .sp For a list of available commands along with brief descriptions, type `\fBcmd\fR`. .sp You can also access help for internal commands using the \fB\-h\fR or \fB\-\-help\fR flags. For example, to get help about the selection function, enter `\fBs \-h\fR` or `\fBs \-\-help\fR`. .sp A convenient way to obtain comprehensive information about \fBclifm\fR commands is through the \fBih\fR action, which is bound by default to the interactive help plugin (\fIihelp.sh\fR). Enter `\fBih\fR` to run the plugin (note that it requires \fBfzf\fR(1)) and select the command you wish to learn more about. .sp For a quick introduction, please refer to the \fBEXAMPLES\fR section at the end of this document. .SH 2. DESCRIPTION \fBClifm\fR is a Command Line Interface File Manager. Its main feature and strength lie in the fact that all input and interacion are conducted through commands typed directly into a prompt. In other words, \fBclifm\fR operates as a Read-Eval-Print Loop (REPL), following this basic structure: \fBR\fRead (user input via the command line), \fBE\fRvaluate/\fBE\fRxecute the command, \fBP\fRrint the results, \fBL\fRoop (repeat the process). .sp Unlike most terminal file managers out there, indeed, \fBclifm\fR replaces the traditional Text User Interface (TUI), often referred to as curses or text\-menu based interface, with a straightforward command\-line interface (REPL). This design allows it to function not only as a file manager, but also as a \fBshell extension\fR. You can search for files, copy, rename, remove them, while also performing system tasks such as updating or upgrading your system, adding cron jobs, stopping services, and launching text editors like nano, vi, or emacs. .sp In summary, \fBclifm\fR keeps the command line visible and accessible, enhancing it with functionalities specifically tailored for file management. .SH 3. PARAMETERS .SH POSITIONAL PARAMETERS .TP If you specify a directory as the first non\-option parameter, \fBclifm\fR will start in that directory. Subsequent directory names are used to initialize subsequent workspaces. For example, the command `\fBclifm\ /etc ~/Downloads\fR` instructs \fBclifm\fR to start in the \fI/etc\fR directory (in the first workspace) and to set the second workspace to \fI~/Downloads\fR. Up to 8 positional parameters are supported (further parameters are ignored). .TP If no workspace is specified, \fBclifm\fR will use the first workspace. To start in a specific workspace use the \fB\-w\fR option followed by the workspace number. For instance, `\fBclifm -w4 /etc ~/Downloads\fR` will start \fBclifm\fR in the \fI/etc\fR directory within workspace 4, setting the workspace 5 to \fI~/Downloads\fR. .TP If no positional parameter is provided and the \fB\-w\fR option is not used, \fBclifm\fR will start in the last visited directory (and in the last active workspace). You can disable this behavior by using the \fB\-\-no\-restore\-last\-path\fR command line switch (or by setting the \fBRestoreLastPath\fR option to \fBfalse\fR in the configuration file), in which case the current directory will be used as starting path and all workspaces will be unset. .TP To start always in a specific directory, disregarding the current directory, you can use the \fBStartingPath\fR option in the configuration file. .SH OPTIONS .TP \fBNote\fR: If compiled in POSIX mode, the following list of options does not apply. In this case, run `\fBclifm \-h\fR` to get the actual list of options. (To make sure run `\fBclifm \-v\fR`: if compiled in POSIX mode the version number is followed by "\-POSIX"). .TP \fB\-a\fR, \fB\-\-show\-hidden[\fR=\fI\,VAL\/\fR] Show hidden files (filenames starting with '.'). Supported values are: \fBfirst\fR, \fBlast\fR, \fBtrue\fR, and \fBfalse\fR. If no value is specified, it defaults to \fBtrue\fR. .TP \fB\-A\fR, \fB\-\-no\-hidden\fR Do not show hidden files. .TP \fB\-b\fR, \fB\-\-bookmarks\-file\fR=\fI\,FILE\/\fR Set an alternative bookmarks file. .TP \fB\-c\fR, \fB\-\-config\-file\fR=\fI\,FILE\/\fR Set an alternative configuration file. .TP \fB\-D\fR, \fB\-\-config\-dir\fR=\fI\,DIR\/\fR Set an alternative configuration directory (if configuration files do not already exist, they will be created in \fIDIR\fR). .TP \fB\-e\fR, \fB\-\-no\-eln\fR Do not display Entry List Numbers (ELNs) to the left of filenames (note that while ELNs are not printed, they remain accessible and can still be used as usual). .TP \fB\-E\fR, \fB\-\-eln\-use\-workspace\-color\fR Color ELNs using the current workspace color. .TP \fB\-f\fR, \fB\-\-dirs\-first\fR List directories first. .TP \fB\-F\fR, \fB\-\-no\-dirs\-first\fR Do not list directories first. .TP \fB\-g\fR, \fB\-\-pager\fR Enable \fBMas\fR, the builtin pager for file listing. .TP \fB\-G\fR, \fB\-\-no\-pager\fR Disable the file pager. .TP \fB\-h\fR, \fB\-\-help\fR Print this help and exit. .TP \fB\-H\fR, \fB\-\-horizontal\-list\fR List files horizontally (instead of vertically). .TP \fB\-i\fR, \fB\-\-no\-case\-sensitive\fR Ignore case distinctions when listing files. .TP \fB\-I\fR, \fB\-\-case\-sensitive\fR Do not ignore case distinctions when listing files. .TP \fB\-k\fR, \fB\-\-keybindings\-file\fR=\fI\,FILE\/\fR Set an alternative keybindings file. .TP \fB\-l\fR, \fB\-\-long\-view\fR Print file extended metadata next to filenames (long view). The displayed fields can be customized using \fB\-\-prop\-fields\fR (or the \fBPropFields\fR option in the configuration file). Set a custom time/date format with \fB\-\-time\-style\fR (or the \fBTimeStyle\fR option in the configuration file). .TP \fB\-L\fR, \fB\-\-follow\-symlinks\-long\fR When in long view, display information for the files referenced by symbolic links instead of the symbolic links themselves. .TP \fB\-m\fR, \fB\-\-dirhist\-map\fR Enable the directory history map to keep in view previous, current, and next entries in the directory history list. .TP \fB\-o\fR, \fB\-\-autols\fR Automatically list files when changing the current directory with the \fBcd\fR command. .TP \fB\-O\fR, \fB\-\-no\-autols\fR Do not automatically list files when changing the current directory with the \fBcd\fR command. .TP \fB\-P\fR, \fB\-\-profile\fR=\fI\,PROFILE\/\fR Use \fIPROFILE\fR as profile. If \fIPROFILE\fR does not exist, it will be created. The default profile is \fBdefault\fR. .TP \fB\-r\fR, \fB\-\-no\-refresh\-on\-empty\-line\fR Do not refresh the current list of files when pressing \fBEnter\fR on an empty line. .TP \fB\-s\fR, \fB\-\-splash\fR Display the splash screen at startup. .TP \fB\-S\fR, \fB\-\-stealth\-mode\fR In stealth mode (also known as incognito or private mode), no trace is left on the host system. No files are read or created, and all settings revert to their default values. However, most settings can still be controlled via command line options and dedicated environment variables (see the \fBENVIRONMENT\fR section below). Additionally, refer to the \fBhistory\fR command and the \fB--no-history\fR command line switch for more options. .TP \fB\-t\fR, \fB\-\-disk\-usage\-analyzer\fR Run in disk usage analyzer mode. This is equivalent to using \fB\-\-sort=size \-\-long\-view \-\-full\-dir\-size \-\-no\-dirs\-first\fR. The recursive size of the current directory will be displayed after the list of files. You can toggle this mode in place by pressing \fBAlt+Tab\fR (or \fBCtrl+Alt+i\fR). .TP \fB\-T\fR, \fB\-\-trash\-dir\fR=\fI\,DIR\/\fR Set an alternative trash directory. .TP \fB\-v\fR, \fB\-\-version\fR Print version details and exit. .TP \fB\-w\fR, \fB\-\-workspace\fR=\fI\,NUM\/\fR Start in workspace \fINUM\fR. By default, \fBclifm\fR will recover the last visited directory for each workspace. You can override this behavior using positional parameters to start in workspace \fINUM\fR and in the specified directory (e.g.: `\fBclifm -w4 /etc\fR`). Consult the \fBPOSITIONAL PARAMETERS\fR section above for more information. .TP \fB\-x\fR, \fB\-\-no\-ext\-cmds\fR Disallow the use of external (shell) commands. .TP \fB\-y\fR, \fB\-\-light\-mode\fR Enable the light mode to speed up \fBclifm\fR (see the \fBNOTE ON SPEED\fR section below). .TP \fB\-z\fR, \fB\-\-sort\fR=\fI\,METHOD\/\fR Sort files by \fIMETHOD\fR, where \fIMETHOD\fR is one of: 0 = none, 1 = name, 2 = size, 3 = atime, 4 = btime, 5 = ctime, 6 = mtime, 7 = version, 8 = extension, 9 = inode, 10 = owner, 11 = group, 12 = blocks, 13 = links, or 14 = type. Both numbers and names are accepted. For example, you can use \fB\-\-sort=9\fR or \fB\-\-sort=inode\fR. .TP \fB\-\-bell\fR=\fI\,TYPE\/\fR Set the terminal bell type, where \fITYPE\fR is one of: 0 = none, 1 = audible, 2 = visible (requires readline >= 8.1), and 3 = flash. Defaults to \fB2\fR (\fBvisible\fR), and, if not available, \fB0\fR (\fBnone\fR). Only numbers are allowed. .TP \fB\-\-case\-sens\-dirjump\fR Do not ignore case when consulting the jump database (via the \fBj\fR command). .TP \fB\-\-case\-sens\-path\-comp\fR Enable case sensitive path completion. .TP \fB\-\-cd\-on\-quit\fR Write the last visited directory to \fI$XDG_CONFIG_HOME/clifm/.last\fR for later access by the corresponding shell function at program exit. Consult the \fBSHELL FUNCTIONS\fR section below for more information. .TP \fB\-\-color\-scheme\fR=\fI\,NAME\/\fR Use the color scheme specified by \fINAME\fR. .TP \fB\-\-color\-links\-as\-target\fR Color symbolic links using the color of the target file (an '@' character is prepended to the filename to mark it as a symbolic link). .TP \fB\-\-cwd\-in\-title\fR Print the current working directory in the terminal window title (otherwise, only the program name is printed). .TP \fB\-\-data\-dir=\fI\,DIR\/\fR Load data files, such as plugins, color schemes, and default configuration files, from \fIDIR\fR (this is by default the installation directory, usually \fI/usr/share/clifm\fR). .TP \fB\-\-desktop\-notifications[=\fISTYLE\fR] Enable desktop notifications. The notification style can be optionally specified: \fBkitty\fR (requires the Kitty terminal or a terminal supporting the Kitty Notifications Protocol), \fBsystem\fR, or \fBfalse\fR. If \fISTYLE\fR is omitted, it defaults to \fBsystem\fR. Enter `\fBhelp desktop\-notifications\fR` in \fBclifm\fR for more information. .TP \fB\-\-disk\-usage\fR Show disk usage of the filesystem where the current directory resides, in the format \fIFREE % (FREE/TOTAL) TYPE DEVICE\fR. .TP \fB\-\-full\-dir\-size\fR Display recursive directory sizes (long view only). .TP \fB\-\-fuzzy\-algo\fR=\fI\,VER\/\fR Fuzzy matching algorithm, where \fIVER\fR is either \fB1\fR (faster, but not Unicode aware), or \fB2\fR (slower, Unicode aware). Bear in mind however that the second algorithm (default) will fallback to the first one (because it is faster) whenever the query string contains only ASCII characters, to minimize the performance penalty. .TP \fB\-\-fuzzy\-matching\fR Enable fuzzy matching for filename/path completions and suggestions. .TP \fB\-\-fzfpreview\-hidden\fR Enable file previews for tab completion (\fBfzf\fR mode only) with the preview window hidden (toggle it by pressing \fBAlt+p\fR). .TP \fB\-\-icons\fR Enable icons. .TP \fB\-\-icons\-use\-file\-color\fR Instead of a specific color, icons use the color of the corresponding filename. Useful when building custom color schemes, this option implies \fB\-\-icons\fR, and is effective only when compiled with support for icons\-in\-terminal or Nerdfonts. The default build is compiled with emoji\-icons support, in which case this option is ignored, as Unicode icons have their own builtin colors. .TP \fB\-\-int\-vars Allow the use of internal variables (e.g.: `\fBVAR=/bin; cd $VAR\fR`). .TP \fB\-\-list\-and\-quit\fR List files and quit. Useful in conjunction with positional parameters (e.g.: `\fBclifm \-\-list\-and\-quit /etc\fR`). If no positional parameter is provided, the current directory is used instead. .TP \fB\-\-ls\fR .br Short for \fB\-\-list\-and\-quit\fR. .TP \fB\-\-lscolors\fR Read file colors from the \fBLS_COLORS\fR environment variable (the FreeBSD \fBLSCOLORS\fR format is also supported). Note that clifm-specific colors (like empty directories or inaccessible files) will be disabled. Note also that colors for specific filenames, as defined in \fBLS_COLORS\fR, are not supported. For more information about \fBLS_COLORS\fR, consult \fBdircolors\fR(1), or refer to the \fBls\fR(1) FreeBSD manpage for \fBLSCOLORS\fR. .TP \fB\-\-max\-dirhist\fR Maximum number of visited directories to remember. .TP \fB\-\-max\-files\fR=\fI\,NUM\/\fR List only up to \fINUM\fR files. Use \-1 or \fBunset\fR to remove this limit (default). See the \fBmf\fR command for a more detailed description. .TP \fB\-\-mimelist\-file\fR=\fI\,FILE\/\fR Set \fIFILE\fR as \fBLira\fR\'s configuration file (see the \fBFILE OPENER\fR section below for more information). .TP \fB\-\-mnt\-udisks2\fR Use \fBudisks2\fR(1) instead of \fBudevil\fR(1) (default) for the \fBmedia\fR command. .TP \fB\-\-no\-bold\fR Disable bold colors (applies to all color schemes). .TP \fB\-\-no\-cd\-auto\fR By default, \fBclifm\fR changes directories by just entering their filenames. This option forces the use of the \fBcd\fR command. .TP \fB\-\-no\-classify\fR By default, \fBclifm\fR appends a file type indicator character to filenames when running without colors (see the \fB\-\-no\-color\fR option below) and a directory indicator (along with a file counter) when running with colors. Classification characters are as follows: .sp /n: directory (n = file counter) @: symbolic link !: broken symbolic link |: FIFO/pipe =: socket *: executable file +: block device -: character device ?: unknown file type .sp Use this option to disable file type classification. Note that this option also disables the file counter. .TP \fB\-\-no\-clear\-screen\fR Do not clear the screen before listing files. .TP \fB\-\-no\-color\fR Disable colors. .TP \fB\-\-no\-columns\fR Disable columned file listing (use a single column). .TP \fB\-\-no\-file\-cap\fR Do not check file capabilities when listing files (only meaningful for performance reasons). .TP \fB\-\-no\-file\-ext\fR Do not check file extensions (mostly used to colorize specific filenames) when listing files. .TP \fB\-\-no\-file\-counter\fR Disable the file counter for directories (speeding up the listing process: counting files in directories is particularly expensive). .TP \fB\-\-no\-follow\-symlinks\fR Do not follow symbolic links when listing files (overrides both \fB\-\-follow\-symlinks\-long\fR and \fB\-\-color\-links\-as\-target\fR). .TP \fB\-\-no\-fzfpreview\fR Disable file previews for tab completion (fzf mode only). .TP \fB\-\-no\-highlight\fR Disable syntax highlighting (to customize highlighting colors, see the \fBCOLOR CODES\fR section below). .TP \fB\-\-no\-history\fR Do not write commands to the history file (see also the \fBHistIgnore\fR option in the configuration file). .TP \fB\-\-no\-open\-auto\fR By default, \fBclifm\fR opens files (using the default associated application) by just entering their filenames. Use this option to force the use of the \fBopen\fR command. Consult the \fBmime\fR command and the \fBFILE OPENER\fR section for more information about default associated applications. .TP \fB\-\-no\-refresh\-on\-resize\fR Do not attempt to refresh the list of files when the window is resized. .TP \fB\-\-no\-restore\-last\-path\fR By default, \fBclifm\fR saves the last visited directory for each workspace to restore it in the next session. Use this option to disable this behavior. .TP \fB\-\-no\-suggestions\fR Disable the auto\-suggestions system. .TP \fB\-\-no\-tips\fR Do not display startup tips. .TP \fB\-\-no\-truncate\-names\fR Do not truncate filenames (see the \fBMaxFilenameLen\fR option in the configuration file). .TP \fB\-\-no\-unicode\fR Do not use Unicode decorations. .TP \fB\-\-no\-warning\-prompt\fR Disable the warning prompt (used to highlight invalid command names). .TP \fB\-\-no\-welcome\-message\fR Disable the welcome message. .TP \fB\-\-only\-dirs\fR List directories only. .TP \fB\-\-open\fR=\fI\,FILE\/\fR Run as a standalone file opener: open \fIFILE\fR and exit, where \fIFILE\fR can be a regular file or a directory, using either standard notation (\fI/dir/file\fR), the file URI scheme (\fIfile:///dir/file\fR), or a URL (\fIwww.domain\fR or \fIhttps://domain\fR). .TP \fB\-\-opener\fR=\fI\,APPLICATION\/\fR Use \fIAPPLICATION\fR (e.g.: \fBrifle\fR or \fBxdg\-open\fR) as file opener/launcher (instead of \fBLira\fR, \fBclifm\fR's default opener). .TP \fB\-\-pager\-view\fR=\fI\,MODE\/\fR List files in the pager according to \fIMODE\fR. Supported values are: \fBauto\fR (use the current listing mode - this is the default), \fBlong\fR (list files in long view), and \fBshort\fR (list files in short view). .TP \fB\-\-physical\-size\fR Display physical file sizes (device usage) instead of logical sizes (apparent size). .TP \fB\-\-preview\fR=\fI\,FILE\/\fR Display a preview of \fIFILE\fR (via \fBShotgun\fR) and exit. Use \fB\-\-shotgun\-file\fR to set an alternative configuration file. Consult the \fBSHOTGUN\fR section below for more information. .TP \fB\-\-print\-sel\fR Print the list of selected files after the file list. The maximum number of selected files to be printed can be specified using the \fBMaxPrintSelfiles\fR option in the configuration file (by default, this option is set to 0 (auto), meaning it will never exceed half the terminal height). .TP \fB\-\-prop\-fields\fR=\fI\,FORMAT\/\fR Set fields to be displayed in long view. For information on how to construct this format string consult the \fBPropFields\fR option in the configuration file. .TP \fB\-\-ptime\-style\fR=\fI\,STYLE\/\fR Time/date style used by the \fBp\fR/\fBpp\fR command and the \fB\-\-stat\fR/\fB\-\-stat\-full\fR command line switches. Available styles: \fBdefault\fR, \fBiso\fR, \fBlong-iso\fR, \fBfull\-iso\fR, \fBfull\-iso\-nano\fR, and \fB+FORMAT\fR (FORMAT is interpreted like in \fBstrftime\fR(3). Nano-second precision is available via the \fB%N\fR modifier, like in \fBdate\fR(1)). .TP \fB\-\-readonly\fR Run in read\-only mode (internal commands able to modify the filesystem are disabled). Disabled commands are: \fBac\fR, \fBad\fR, \fBbb\fR, \fBbl/bleach\fR, \fBbr/bulk\fR, \fBc\fR, \fBdup\fR, \fBl\fR, \fBle\fR, \fBm\fR, \fBmd\fR, \fBn/new\fR, \fBoc\fR, \fBpaste\fR, \fBpc\fR, \fBr\fR, \fBrr\fR, \fBt/trash\fR, \fBtag\fR, \fBte\fR, \fBu/untrash\fR, and \fBvv\fR, plus the shell commands \fBcp\fR, \fBrm\fR, \fBmv\fR, \fBln\fR, \fBmkdir\fR, \fBrmdir\fR, \fBlink\fR, and \fBunlink\fR. .TP \fB\-\-report\-cwd\fR Report the current directory to the underlying terminal (using the \fBOSC-7\fR escape sequence, not supported by all terminals). .TP \fB\-\-rl\-vi\-mode\fR Set readline to vi editing mode (defaults to emacs editing mode). .TP \fB\-\-secure\-cmds\fR Sanitize commands passed to the OS to mitigate command injection attacks (\fB\-\-secure\-env\fR is implied). Consult the \fBSECURITY\fR section below for more information. .TP \fB\-\-secure\-env\fR Run \fBclifm\fR in a secure environment (regular mode). Consult the \fBSECURITY\fR section below. .TP \fB\-\-secure\-env\-full\fR Run \fBclifm\fR in a secure environment (full mode). Consult the \fBSECURITY\fR section below. .TP \fB\-\-sel\-file\fR=\fI\,FILE\/\fR Set \fIFILE\fR as the selections file. .TP \fB\-\-share\-selbox\fR By default, each user profile has a private Selection Box. Use this option to make the Selection Box common to all user profiles. .TP \fB\-\-shotgun\-file\fR=\fI\,FILE\/\fR Set \fIFILE\fR as the shotgun configuration file. See the \fBSHOTGUN\fR section below for more information. .TP \fB\-\-si\fR .br Display file sizes in SI units (powers of 1000) instead of IEC units (powers of 1024). .TP \fB\-\-sort\-reverse\fR Sort files in reverse order (e.g.: z\-a instead of a\-z). .TP \fB\-\-stat\fR \fI\,FILE\/\fR... Run the \fBp\fR command on \fIFILE\fR(s) and exit. This must be the \fBlast option\fR on the command line. Use \fB\-\-ptime\-style\fR to set a custom date/time format. .TP \fB\-\-stat\-full\fR \fI\,FILE\/\fR... Same as \fB\-\-stat\fR, but it runs the \fBpp\fR command (instead of \fBp\fR) on \fIFILE\fR(s). .TP \fB\-\-tabmode\fR=\fI\,MODE\/\fR Set tab completion mode. Available modes: \fBfzf\fR, \fBfnf\fR, \fBsmenu\fR, and \fBstandard\fR. .TP \fB\-\-time\-style\fR=\fI\,STYLE\/\fR Time/date style used in long view. Available styles: \fBdefault\fR, \fBrelative\fR, \fBiso\fR, \fBlong-iso\fR, \fBfull-iso\fR, \fB+FORMAT\fR (FORMAT is interpreted like in \fBstrftime\fR(3)). .TP \fB\-\-trash\-as\-rm\fR Make the \fBr\fR command move files to the trash instead of removing them. .TP \fB\-\-unicode\fR By default, Unicode decorations are used if Unicode support is detected for the running terminal. If no support is detected, you can use this option to force the use of Unicode decorations. .TP \fB\-\-virtual\-dir\fR=\fI\,PATH\/\fR Use \fIPATH\fR as \fBclifm\fR\'s virtual directory. .TP \fB\-\-virtual\-dir\-full\-paths\fR Print filenames in virtual directories as absolute paths instead of just basenames. .TP \fB\-\-vt100\fR Run in VT100 compatibility mode (use this option if running on a really ancient terminal emulator). .PP Options precedence order: 1) command line flags; 2) configuration file; 3) default values. .SH 4. COMMANDS Help for all commands listed here can be accessed via the \fB\-h\fR or \fB\-\-help\fR options. For example, use `\fBp \-\-help\fR` to get help about the \fBproperties\fR function. .sp \fBNote 1:\fR ELN = Entry List Number. For example, in the line "12 chocolatebox" (when listing files), 12 is the ELN corresponding to the file named "chocolatebox". The slash followed by a number (/xx) after directories and symbolic links to directories (the file counter) indicates the number of files in the corresponding directory, excluding self and parent directories ("." and ".." respectively). .sp \fBNote 2:\fR In case of ELN\-filename conflict, the backslash can be used to prevent ELN expansion. For example, if there are at least two files and one of them is named \fI2\fR, \fBclifm\fR cannot determine in advance if the command refers to the ELN 2 or the filename \fI2\fR. To specify the ELN, simply write the ELN number (e.g. `\fBs\ 2\fR`). To refer to the filename, escape it using the backlash character: `\fBs\ \\2\fR`. .sp \fBNote 3:\fR \fBClifm\fR supports \fBfused parameters\fR for internal commands taking an ELN or range of ELNs as parameters. Much like short options for command line programs, you can omit the space between internal commands and the corresponding ELN passed as argument. For example, you can write \fICMDELN\fR instead of \fICMD\ ELN\fR. Thus, `\fBo12\fR` or `\fBs1\-5\fR` can be used instead of `\fBo\ 12\fR` and `\fBs\ 1\-5\fR, respectively. Be aware that omitting the space character will disable tab completion and suggestions for ELNs. If there is a file named \fIo12\fR (more generally, \fICMDELN\fR), and if you want to refer to this file instead of a \fBclifm\fR command, escape the filename to prevent the split: `\fB\\o12\fR`. .TP .B \fIFILE/DIR\fR If the \fBautocd\fR and/or \fBauto-open\fR functions are enabled (default), open \fIFILE\fR or change directory to \fIDIR\fR. In other words, `\fBFILE\fR` amounts to `\fBopen\ FILE\fR` (or `\fBo\ FILE\fR`), and `\fBDIR\fR` to `\fBcd\ DIR\fR`. ELNs, of course, are allowed. For example: `\fB12\fR`. .TP .B /\fIPATTERN\fR [\fI\-FILETYPE\fR] [-x] [\fIDIR\fR] This is the \fBquick search\fR function. Type `\fB/\fR` followed by a glob or (extended) regular expression, and \fBclifm\fR will list all matches in the current directory. For example, both `\fB/*.pdf\fR` and `\fB/.pdf$\fR` expressions will list all PDF files in the current directory, the former using wildcards, and the second a regular expression. .sp You can list previously used search patterns using the TAB key: `\fB/*\fR`. .sp \fBNote 1\fR: By default, the search function attempts to resolve a pattern first as glob, and then, if no matches are found, as a regular expression. This behavior can be customizad in the configuration file, using the \fBSearchStrategy\fR option. .sp \fBNote 2\fR: If no further parameter is provided, but only a glob pattern (wildcards), you can expand the pattern into the corresponding matches by hitting the TAB key. For example, to list all C files in the current directory: `\fB/*.c\fR`. .sp \fBNote 3\fR: Expressions containing no pattern metacharacter are automatically transformed into a glob/regular expression (depending on the value of the \fBSearchStrategy\fR option). For example, `\fB/test\fR` becomes `\fB*test*\fR` or `\fB/.*test.*\fR`. .sp \fB1. Case sensitivity\fR .sp By default, regular expressions are case insensitive (glob expressions, by contrast, are always case sensitive). However, you can enable case sensitive search by setting the \fBCaseSensitiveSearch\fR option to \fBtrue\fR in the configuration file. .sp \fB2. Destination directory\fR .sp To search for files in any directory other than the current directory, specify the directory name as a further parameter (\fIDIR\fR). For example, enter `\fB/^A\ 7\fR` to search for all files starting with \'A\' in the directory corresponding to the ELN 7. .sp \fB3. File type filter\fR .sp The result of the search can be further filtered by specifying a filter type: \fB-b\fR, \fB-c\fR, \fB-d\fR, \fB-f\fR, \fB-l\fR, \fB-p\fR, \fB-s\fR, \fB-O\fR, and \fB-P\fR (block device, character device, directory, regular file, symbolic link, FIFO/pipe, socket, door (Solaris), and port (Solaris) respectively. For example, `\fB/[.\-].*d$\ \-d Documents/\fR` will list all directories containing a dot or a dash and ending with \'d\' in the directory named \fIDocuments\fR. .sp \fB4. Invert matching\fR .sp Prepend the exclamation mark (!) to invert the meaning of a given search pattern. For example: `\fB!.*s$\ \-d\ /etc\fR` will match all directories in \fI/etc\fR \fBnot\fR ending with \'s\', just as `\fB!D*\fR` will match all files in the current directory \fBnot\fR starting with \'D\'. .sp \fB5. Recursive search\fR .sp To perform a recursive search use the \fB\-x\fR parameter, and, optionally, a search path (\fIDIR\fR) (file type filter is not allowed). The search will be performed using \fBfind\fR(1) as follows: \fBfind\ \fIDIR\ MODE PATTERN\fR. If no search path is provided, the search is executed starting in the current directory. Otherwise, the search starts in \fIDIR\fR. \fIMODE\fR is one of: .sp \-name: if \fBSearchStrategy\fR is not \fBregex\-only\fR and \fBCaseSensitiveSearch\fR is set to \fBtrue\fR .sp \-iname: if \fBSearchStrategy\fR is not \fBregex\-only\fR and \fBCaseSensitiveSearch\fR is set to \fBfalse\fR .sp \-regex: if \fBSearchStrategy\fR is \fBregex\-only\fR and \fBCaseSensitiveSearch\fR is set to \fBtrue\fR .sp \-iregex: if \fBSearchStrategy\fR is \fBregex\-only\fR and \fBCaseSensitiveSearch\fR is set to \fBfalse\fR .TP .B ;\fR[\fICMD\fR], \fB:\fR[\fICMD\fR] If \fICMD\fR is not specified, run the system shell in the current directory. If \fICMD\fR is specified, skip all \fBclifm\fR expansions (see the \fBBUILT\-IN EXPANSIONS\fR section below) and run the input string (\fICMD\fR) as is via the default system shell (consult the \fBMISCELLANEOUS NOTES\fR section for information on how shell commands are executed). .TP .B ac, ad \fIFILE\fR... Archive/compress and dearchive/decompress one or multiple files and/or directories. .sp The archiver function brings two modes: \fBac\fR, to generate archives or compressed files, and \fBad\fR, to decompress or dearchive files, either just listing, extracting, recompressing, or mounting their content. In this latter case, the mountpoint used automatically is \fI$HOME/.config/clifm/PROFILE/mounts/ARCHIVE_NAME\fR. .sp Example: `\fBac\ sel\fR`, `\fBac\ 4\-25\ myfile\fR`, or `\fBad\ *.tar.gz\fR`. .sp Multiple archive/compression formats are supported, including Zstandard. Note that when it comes to ISO 9660 files only a single file is supported. .sp The archive mount function for non ISO files depends on \fBarchivemount\fR, while the remaining functions depend on \fBatool\fR and other third\-party utilities for achieve formats support, for example, \fBp7zip\fR. \fBp7zip\fR is also used to manage most decompressing options for ISO 9660 files, except for mount, in which case \fBmount(8)\fR is used. Creation of ISO files is done via \fBgenisoimage\fR(1). For more information consult \fBatool\fR(1), \fBarchivemount\fR(1), \fBzstd\fR(1), and \fB7z\fR(1). .TP .B acd, autocd \fR[on | off | status] Toggle the autocd function. If set to on, `\fBDIR\fR` amounts to `\fBcd\ DIR\fR`. .TP .B actions \fR[list | edit [\fIAPP\fR]] To list available actions (or plugins) use the \fBlist\fR subcommand. Note that, since \fBlist\fR is the default action, it can be omitted. .sp Use the \fBedit\fR subcommand to add, remove or modify custom actions (using \fIAPP\fR if specified or the default associated application for text files otherwise). .sp The aim of this function is to allow the user to easily add custom commands and functions to \fBclifm\fR. In other words, the actions function is a plugins capability. .sp This is the general procedure: \fBa)\fR edit the actions file (by running `\fBactions edit\fR`) and bind a custom action name to an executable file (written in any language you want, be it a shell or Python script, a C program or whatever you like). For example, "myaction=myscript.sh". \fBb)\fR Drop the corresponding script (in our example, \fImyscript.sh\fR) into the plugins directory, usually, \fI~/.config/clifm/plugins\fR (see the \fBFILES\fR section below). \fB3)\fR Call the script using the custom action name defined before as if it were any other command: run `\fBmyaction\fR`, and \fImyscript.sh\fR will be executed. .sp Note that all arguments passed to the action command (\fBmyaction\fR) will be passed to the script or program as well (\fImyscript.sh\fR), which is executed via the system shell (consult the \fBMISCELLANEOUS NOTES\fR section for information on how shell commands are executed). .sp To assist the user when writing plugins, \fBclifm\fR's state information is exported via environment variables while running plugins. For example, \fBCLIFM_LONG_VIEW\fR is set to 1 if currently running in long view (see the \fBENVIRONMENT\fR section for the complete list of exported values). .sp The plugins bundled with \fBclifm\fR (take a look at the plugins directory) can be used as a starting point to create new plugins. .TP .B alias \fR[import \fIFILE\fR | ls, list | \fINAME\fR] With no argument (or with \fBls,list\fR parameters), it prints the list of available aliases. To get the description of a specific alias enter `\fBalias\fR` followed by the alias name. To write a new alias simply enter \fBedit\fR (or press \fBF10\fR) to open the configuration file and add a line like this: "alias name=\'command args...\'" or "alias name=\'directory\'". .sp To import aliases from a file, provided it contains aliases in the specified form (i.e. the POSIX syntax for the \fBalias\fR shell command), use the \fBimport\fR parameter. Aliases conflicting with some of the internal commands will not be imported. .sp However, a neat usage for the \fBalias\fR function is not so much to bind short keys to commands, but to files and directories visited regularly. In this way, it is possible to bind as many files or directories, no matter how deep they are in the filesystem, to very short strings, even single characters. For example, "alias w=\'/some/file/deep/in/the/filesystem\'". Now, no matter where you are, you can enter `\fBw\fR`, provided \fBautocd\fR and/or \fBauto\-open\fR function is enabled, to access the file or directory you want. Theoretically at least, this procedure can be repeated until the system memory is exhausted. .sp To create multiple aliases for files at once, this is the recommended procedure: \fB1)\fR Select all files you want to alias with the \fBsel\fR command: `\fBs\ file1\ file2\ file3\ ...\fR`. \fB2)\fR Export the selected files into a temporary file running `\fBexp\ sel\fR`; \fB3)\fR Edit this file to contain only valid alias lines: alias a1=\'file1\' alias b1=\'file2\' alias c1=\'file3\' \fBNote\fR: Make sure alias names do not conflict with other commands, either internal or external. To bypass the conflicts check, performed automatically by the `\fBalias import\fR` command, you can edit the aliases file manually (\fBF10\fR). \fB4)\fR Finally, import this file with the \fBalias\fR command: `\fBalias\ import\ tmp_file\fR`. Now you can access any of these files by entering just a few characters: `\fBa1\fR`, `\fBb1\fR`, and `\fBc1\fR`. .TP .B auto \fR[list | none | unset | \fIOPTION=VALUE\fR...] Set a temporary autocommand for the current directory. .sp Unlike \fBpermanent\fR autocommands, defined in the configuration file via the \fBautocmd\fR keyword (see the \fBAUTOCOMMANDS\fR section below), options set via the \fBauto\fR command are \fBtemporary\fR, i.e., valid only for the current directory and the current session. .sp Options set via this command take precedence over both permament autocommands and regular options (set either via the command line or the configuration file). .sp \fBExamples\fR .sp List available autocommands \fBauto list\fR .sp List files in the current directory in long view \fBauto lv=1\fR .sp List only PDF files, set the color scheme to nord, and sort files by size \fBauto ft=.*\.pdf$,cs=nord,st=size\fR .sp The same list of options can be specified sequentially (i.e., previous options are preserved) \fBauto ft=.*\.pdf$ auto cs=nord auto st=size\fR .sp Unset the files filter and the color scheme, and change sort to blocks \fBauto ft=,cs=,st=blocks\fR .sp Unset all temporary autocommands previously set for the current directory \fBauto unset\fR .sp Reload the current directory ignoring all autocommands (including permanent autocommands) \fBauto none\fR .sp For the list of available option codes consult the \fBAUTOCOMMANDS\fR section or enter `\fBhelp autocommands\fR`. .TP .B ao, auto\-open \fR[on | off | status] Toggle the auto\-open function. If set to on, `\fBFILE\fR` amounts to `\fBopen\ FILE\fR`. .TP .B b, back \fR[h, hist | clear | !\fIELN\fR] Unlike `\fBcd\ ..\fR`, which changes to the parent directory of the current directory, this command (with no argument) changes to the previously visited directory. You can also use \fBAlt+j\fR or \fBShift-Left\fR. .sp \fBClifm\fR keeps a record of all visited directories (to prevent a directory from being added to the directory history list use the \fBDirhistIgnore\fR option in the main configuration file). You can see this list by typing `\fBb\ hist\fR` or `\fBb\ h\fR`, and you can access any element in this list by simply passing the corresponding ELN in this list (preceded by an exclamation mark) to the \fBback\fR command. Example: :) > ~ $ bh 1 /home/user 2 /etc 3 /proc :) > ~ $ b !3 :) > /proc $ .sp \fBNote:\fR The highlighted line (by default printed in bold cyan) indicates the current position of the \fBback\fR function in the directory history list. .sp Finally, you can also clear this history list by entering `\fBb\ clear\fR`. .sp The best way of navigating the directory history list, however, is using the \fBdirectory jumper\fR function (invoked by the \fBj\fR command). You can also take a look at the \fBdh\fR command. .sp Use the \fBf\fR (or \fBforth\fR) command to move forward, instead of backward, in the directory history list. .TP .B bb, bleach \fIFILE\fR... \fBBleach\fR is a builtin filenames sanitizer (based on detox [\fIhttps://github.com/dharple/detox\fR]), whose aim is to rename filenames using only ASCII characters. .sp \fBBleach\fR sanitizes filenames either by removing extended\-ASCII/Unicode characters without an ASCII alternative/similar character, or by translating these characters into an alternative ASCII character based on familiarity/similarity. .sp These following simple rules are used to compose sanitized filenames: \- NUL (\\0) and slash (/) characters are completely disallowed \- Only characters from the \fBPortable Filename Characters Set\fR (a\-zA\-Z0-9._\-) are allowed \- { [ ( ) ] } are replaced by a dash (\-). Everything else is replaced by an underscore (_) \- Unicode characters are translated, whenever possible, into an ASCII replacement. Otherwise, they are just ignored. For example, an upper case A with diacritic (accent, umlaut, diaresis, and so on) will be replaced by an ASCII A, but the smiley face emoji will be simply ignored. A few special signs will be translated into text, for instance, the pound sign will be replaced by "_pound_" and the Euro symbol by "EUR". Translations are made via a translation table (see the \fIcleaner_table.h\fR in the source code). \- Filenames never start with a dash (\-) \- Files named . and .. are not allowed \- Append .bleach to single character filenames \- Do not let a replacement filename start with a dot (hidden) if the original does not \- Max filename length is NAME_MAX (usually 255) .sp Modified filenames will be listed on the screen asking the user for confirmation, allowing besides to edit (by pressing 'e') the list of modified filenames via a text editor. .sp If the replacement filename already exists, a dash and a number (starting from 1) will be appended. E.g.: file\-3. .TP .B bd \fR[\fINAME\fR] \fBbd\fR is the \fBbackdir\fR function: it takes you back to the parent directory matching \fINAME\fR. .sp With no arguments, \fBbd\fR lists all parent directories relative to the current directory, allowing the user to select an entry. Otherwise, it checks the absolute current directory against the provided query string (\fINAME\fR): if only one match is found, it automatically changes to this directory; if multiple matches are found, the list of matches is presented to the user in a selection menu. If \fINAME\fR is a directory name, \fBbd\fR just changes to this directory, be it a parent of the current directory or not. .sp Tab completion and suggestions are available for this function. .sp \fBExample\fR: .sp Provided the current directory is \fI/home/user/git/repositories/lambda\fR, entering `\fBbd git\fR` will take you immediately to \fI/home/user/git\fR. .sp Note that there is no need to type the entire directory name; if the query is unambiguous, only a few characters, and even just one, suffices to match the appropriate directory. In our example, `\fBbd g\fR` is enough to take you to \fI/home/user/git\fR, just as `\fBbd h\fR` will take you to \fI/home\fR. .sp The query string can match any part of a directory name: `\fBbd er\fR`, for instance, will take you to \fI/home/user\fR, since it is an unambiguous query. .TP .B bl \fIFILE\fR... Create symbolic links (in the current directory) for each specified file. For example, to create symbolic links in the directory \fIdir\fR for all PNG files in the current directory, issue these commands: `\fBs *.png\fR`, `\fBcd dir\fR`, and then `\fBbl sel\fR`. .TP .B bm, bookmarks \fR[a, add \fIFILENAME\fR \fINAME\fR [\fISHORTCUT\fR] | d, del \fINAME\fR | e, edit [\fIAPP\fR] | \fINAME\fR, \fISHORTCUT\fR] Bookmarks can be managed either from the bookmark manager screen or from the command line. .sp \fB1. The bookmark manager screen\fR .sp To access the bookmark manager screen enter \fIbm\fR. Here you can cd to the desired bookmark by entering either ELN or filename (regular files can be bookmarked as well). In this screen you can also add, remove, or edit your bookmarks by entering 'e' to edit the bookmarks file (which is simply a list of lines with this format: \fINAME:PATH\fR. E.g.: "docs:/home/user/documents"). Make your changes, save, and exit. .sp \fB2. The command line\fR .TS allbox; lb lb l l. Command Description T{ bm add /media/mount mnt T} Bookmark the \fI/media/mount\fR directory as "mnt" T{ bm mnt T} Change to/open the bookmark named "mnt" T{ bm del mnt T} Delete the bookmark named "mnt" T{ bm edit T} Edit your bookmarks .TE .sp A handy use for the bookmarks function is to create bookmarks using short names, which will be later easily accessible via tab completion. .sp \fBThe b: prefix\fR .sp The \fBb:\fR prefix is used as a way to quickly access/operate on bookmarks. A few examples: .TS allbox; lb lb l l. Command Description T{ b: T} List available bookmarks T{ b:net T} Change to the bookmark named "net" \fB(1)\fR T{ p b:bm1 b:bm2 T} Print file properties of the bookmarks named "bm1" and "bm2" T{ s b: T} Select all bookmarks at once .TE .sp \fB(1)\fR If your are not sure about where a bookmark points to, type `\fBb:NAME\fR`. .TP .B br, bulk \fIFILE\fR... [:\fIEDITOR\fR] Bulk rename \fIFILE\fR(s). .sp Each filename will be copied to a temporary file, which will be opened via \fIEDITOR\fR (default associated application for plain text files if omitted), letting the user modify it. Once the file has been modified and saved, the modified names are printed on the screen and the user is asked for confirmation. .sp This builtin bulk rename function will not deal with deletions, replacements, filename conflicts and the like. For a smarter alternative use \fBqmv\fR(1). .TP \fBc\fR, \fBm\fR, \fBmd\fR, \fBr\fR Short for the following shell commands respectively: `\fBcp\ \-iRp\fR`, `\fBmv\ \-i\fR`, `\fBmkdir\ \-p\fR`, and `\fBrm\fR` (for files) or `\fBrm\ \-r\fR` (for directories). .sp By default, the \fBc\fR, \fBm\fR, and \fBr\fR commands ask for confirmation before operations. Since this might sometimes be quite intrusive (specially when operating on large number of files), it is possible to turn interactivity off in two different ways: a) For the current command only: via the \fB\-f\fR, \fB\-\-force\fR switch. For example: `\fBc \-f sel\fR`, `\fBm \-f sel\fR`, or `\fBr \-f *\fR`. b) Permanently. Use the \fBcpCmd\fR, \fBmvCmd\fR, and \fBrmForce\fR options in the configuration file to permanently set any of these commands to non\-interactive mode. .sp To use these commands without any of these options, or with any other option you want, use the appropriate shell command, for instance, \fBcp\fR instead of \fBc\fR. Of course, you can also create aliases to use your preferred commands, for example, "c=\'cp \-adp\'". Consult the \fBalias\fR command above for more information. .sp The \fBl\fR command allows the use of the \fBe, edit\fR option to modify the destination of a symbolic link. For example: `\fBl\ edit\ 12\fR` (or `\fBle\ 12\fR`) to relink the symbolic link corresponding to the file whose ELN is 12. .sp When using the \fBsel\fR keyword and no destination is provided, \fBc\fR and \fBm\fR will copy/move selected files to the current directory. .sp Whenever \fBsel\fR is not used, but just a source filename (and no destination is provided), the \fBm\fR command behaves much like the \fBimv\fR(1) shell command (from the \'renameutils\' package), providing an interactive renaming function: it prompts the user to enter a new name using the source filename as base, so that it does not need to be typed twice. For this alternative prompt, only tab completion for filenames is available. .sp \fBClifm\fR supports \fBadvcp\fR(1), \fBwcp\fR, and \fBrsync\fR(1) to copy files (they include a progress bar). To use them instead of \fBcp\fR(1) set the corresponding option (\fBcpCmd\fR) in the configuration file. If \fBadvcp\fR is selected, the command used is `\fBadvcp\ \-giRp\fR` (or `\fBadvcp \-gRp\fR`, for non\-interactive mode). If \fBrsync\fR, the command is `\fBrsync\ \-avP\fR`. \fBwcp\fR takes no argument. .sp \fBadvmv\fR(1) is also supported to move files (to add a progress bar to the move command). Use the \fBmvCmd\fR option in the configuration file to choose this alternative implementation of \fBmv\fR. In this case, the command used is `\fBadvmv\ \-gi\fR` (or \fBadvmv \-g\fR` for non-interactive mode). .TP .B cd \fR[\fIDIR\fR] Change the current working directory. .sp Directory check order: 1. If no argument is provided, change to the home directory (\fB$HOME\fR, or, if not set, the sixth field of the entry corresponding to the current user in \fI/etc/passwd\fR) 2. If the argument is an absolute path (begins with a slash character), or the first component is dot (.) or dot\-dot (..), convert to canonical form (via \fBrealpath\fR(3)) and, if a valid directory, change to this directory. 3. Check the \fBCDPATH\fR environment variable and append /\fIDIR\fR to each of the paths specified here. If the result of the concatenation is a valid directory, change to it. 4. Check directories in the current working directory. If a matching directory is found, change to it. .sp You can use either ELNs or a string to indicate the directory you want. E.g.: `\fBcd\ 12\fR` or `\fBcd\ ~/media\fR`. If \fBautocd\fR is enabled (default), `\fBcd\ 12\fR` and `\fBcd\ ~/media\fR` can be written as `\fB12\fR` and `\fB~/media\fR` respectively as well. .sp Unlike the shell \fBcd\fR command, \fBclifm\fR's builtin \fBcd\fR command not only changes the current directory, but also lists its content (provided the option \fBAutoLs\fR is enabled, which is the default) according to a comprehensive list of color codes. By default, the output of \fBcd\fR is much like this shell command: `\fBcd\ DIR\ &&\ ls\ \-\-color=auto\ \-\-group\-directories\-first\fR`. .sp Automatic file listing can be disabled by either setting \fBAutoLs\fR to \fBfalse\fR in the configuration file or running \fBclifm\fR with the \fB\-O\fR or \fB\-\-no\-autols\fR option. .TP .B cl, columns \fR[on | off] Toggle columned file listing. .TP .B cmd, commands Show this list of commands. .sp An alternative way of getting information about \fBclifm\fR commands is via the interactive help plugin (depends on \fBfzf\fR), by default bound to the \fBih\fR action name. .TP .B colors .br Preview the current color scheme (same as `\fBcs preview\fR`). .TP .B config \fR[edit [\fIAPP\fR] | reset | reload | dump] Manage the main configuration file. .sp To edit the configuration file use the \fBedit\fR subcommand. If an application is specified (`\fBconfig edit APP\fR`), \fIAPP\fR will be used to open the file (otherwise, the default associated program will be used). Edit settings to your liking, save, and quit the editor (changes are automatically applied). Note that, since \fBedit\fR is the default action, it can be omitted. Enter just `\fBconfig\fR` to open the configuration file, or `\fBconfig APP\fR` to open it using \fIAPP\fR. .sp Use the \fBreload\fR subcommand to reload the main configuration file and update settings accordingly. .sp Use the \fBreset\fR subcommand to generate a fresh configuration file and create a backup copy of the old one (named \fIclifmrc.YYYYMMDD@HH:MM:SS\fR). .sp The \fBdump\fR subcommand prints the list of settings (as defined in the main configuration file) with their current value. Those differing from the default values are highlighted, and the default value for the corresponding option is displayed in brackets. .TP .B cs, colorschemes \fR[edit [\fIAPP\fR] | n, name | p, preview | check\-ext | \fINAME\fR] With no arguments, list available color schemes (use `\fBcs name\fR` to print the current color scheme name). .sp To get a preview of the current color scheme use the \fBpreview\fR subcommand: `\fBcs preview\fR`. .sp Use the \fBcheck\-ext\fR subcommand to check for file extension conflicts: `\fBcs check\-ext\fR`. .sp Use the \fBedit\fR subcommand to open/edit the configuration file of the current color scheme (open with \fIAPP\fR if specified, or with the default associated application otherwise). .sp To switch color schemes, specify the color scheme name: `\fBcs NAME\fR`. (Use the TAB key to list available color schemes: `\fBcs \fR`). .TP .B d, dup \fIFILE\fR... Duplicate files passed as parameters, either directories or regular files. The user will be asked for a destination directory. Duplicated filenames are generated by appending ".copy" to the basename of each source file. For example: `\fBd\ /my/file\fR` will copy \fI/my/file\fR to the directory selected by the user as \fIfile.copy\fR. If \fIfile.copy\fR already exists, an extra suffix will be added as follows: \fIfile.copy\-N\fR, where \fIN\fR is a positive integer (starting at 1). .sp If \fBrsync\fR(1) is found, it will be used as follows: `\fBrsync\ \-aczvAXHS\ \-\-progress\fR`. Else, \fBcp\fR(1) will be used: `\fBcp\ \-a\fR`. .TP .B dh \fR[\fISTRING\fR] [\fIPATH\fR] [!\fIELN\fR] With no parameters, it prints the directory history list. To filter this list just pass a query string: only entries matching this query will be displayed. In both cases, tab completion is available. For example: `\fBdh down\fR` will list only those entries matching \fIdown\fR (fuzzily, if \fBfuzzy\-matching\fR is enabled). .sp To access a specific entry, you can pass the entry number preceded by an exclamation mark. For example, if you want the entry number 12, enter `\fBdh !12\fR` to change to the corresponding directory. .sp Finally, if an absolute path is passed as first parameter, \fBdh\fR works just as the \fBcd\fR command. .sp \fBNote\fR: Take a look at the \fBj\fR command as well. Both commands deal with the list of visited directories, but in slightly different ways: while \fBdh\fR deals with the list of the last \fIMaxDirhist\fR entries (see the configuration file), the \fBj\fR command deals with the \fBranked\fR list of visited directories. .TP .B ds, desel \fR[*, a, all | \fIFILE\fR]... Deselect one or more files. .sp If no parameter is passed, the user is prompted to either mark selected files to be deselected or to edit the selections file (entering \'e\') via a text editor to manually deselect files. .sp Use \fB*\fR, \fBa\fR or \fBall\fR to deselect all selected entries at once. E.g.: `\fBds\ *\fR`. .sp You can also pass the filename(s) (or ELNs) to be deselected as a parameter. For example: `\fBds\ myfile\ 24\fR`. .sp Tab completion is available for this command: `\fBds \fR` will list all currently selected files. .TP .B exp \fR[\fIFILE\fR]... With no argument, export the list of files in the current directory to a temporary file. Otherwise, export only those specified as further arguments: they can be directories, filenames, ELNs or some search expression like "*.c". .TP .B ext \fR[on | off | status] Toggle the ability to execute external commands. .TP .B f, forth \fR[h, hist | clear | !\fIELN\fR] This command works just like the \fBback\fR command, but it goes \fBforward\fR, instead of backward, in the history record. .sp Run `\fBf\fR` to change to the next visited directory (you can also just press \fBAlt+k\fR or \fBShift+Right\fR). .sp Of course, you can use `\fBf\ hist\fR`, `\fBf\ h\fR`, and `\fBf\ !ELN\fR` (consult the \fBback\fR command for details). .TP .B fc \fR[on | off | status] By default, \fBclifm\fR prints the number of files contained by listed directories next to directory names. However, since this is an expensive feature, it might be desirable (for example, when listing files on a remote machine) to disable this feature. Use the \fBoff\fR subcommand to disable it. To permanently disable it, use the \fBFileCounter\fR option in the configuration file. .TP .B ff, dirs\-first \fR[on | off | status] Toggle list directories first. .TP .B ft, filter \fR[unset] [[!]\fIREGEX\fR,=\fRFILE\-TYPE\-CHAR\fR] Filter the current list of files, either by filename (via a regular expression) or file type (via a file type character). .sp With no argument, \fBft\fR prints the current filter. To remove the current filter use the \fBunset\fR option. To set a new filter enter `\fBft\fR` followed by a filter expression (use the exclamation mark to reverse the meaning of a filter). Examples: .sp Exclude hidden files: \fBft !^\.\fR .sp List only files ending with .pdf: \fBft .*\\.pdf$\fR .sp List only symbolic links: \fBft =l\fR .sp Exclude socket files: \fBft !=s\fR .sp The list of file type characters is included in the \fBFILE FILTERS\fR section below. .sp The filter will be lost at program exit. To permanently set a filter use the \fIFilter\fR option (in the configuration file) or the \fBCLIFM_FILTER\fR environment variable (consult the \fBENVIRONMENT\fR and the \fBFILE FILTERS\fR sections below). .TP .B fz \fR[on | off] Toggle recursive directory sizes (long view only). .TP .B hf, hh, hidden \fR[on | off | first | last | status] Turn hidden files on/off (use \fBfirst\fR/\fBlast\fR to sort hidden files before/after non-hidden files respectively). .TP .B history \fR[edit [\fIAPP\fR] | clear | -\fIN\fR | on | off | status | show\-time] With no arguments, it prints the commands history list (use \fBshow\-time\fR to print timestamps as well). If \fBclear\fR is passed as argument, it will delete all entries in the history file. Use \fBedit\fR to open the history file and modify it as required (the file will be opened with \fIAPP\fR, if specified, or with the default associated application otherwise). \fB\-N\fR tells the \fBhistory\fR command to list only the last 'N' commands in the history list. Finally, you can disable history (subsequent entries will not be written into the history file) via `\fBhistory\ off\fR` (you can also use the \fBHistIgnore\fR option in the configuration file to prevent specific command lines from being added to the history list). .sp You can use the exclamation mark (!) to perform some history commands: !: List history entries !!: Execute the last command. !n: Execute the command number \'n\' in the history list. !\-n: Execute the \'last \- n\' command in the history list. !STRING: Execute the command starting with STRING. Tab completion is available in this case: \fI!STRING\fR. .TP .B icons \fR[on | off] Toggle icons. .sp \fBNote\fR: Depending on how the terminal renders icons, the apparent space between icons and filenames may not be the most appropriate. This space can be adjusted using the \fBIconsGap\fR option in the configuration file (valid values: 0, 1, 2). .TP .B j \fR[\-\-purge [\fINUM\fR] | \-\-edit], jc, jl, jp \fR[\fISTR\fR]..., \fBje\fR \fBj\fR is the fastest way of using \fBKangaroo\fR, a \fBdirectory jumper\fR function used to quickly navigate through the jump database (i.e. a database of visited directories). .sp With no argument, \fBj\fR just lists the entries in the jump database \fB(1)(2)\fR, printing: \fBa)\fR order number of the corresponding entry, \fBb)\fR total sum of visits, \fBc)\fR days since the first visit, \fBd)\fR hours since the last visit, \fBe)\fR the rank value, and \fBf)\fR the directory name itself. An asterisk next to the rank value means that the corresponding directory will not be removed from the database, despite its rank, either because it has been visited in the last 24 hours, or because it is bookmarked, pinned, or currently active in some workspace. .sp \fB(1)\fR To prevent a directory from being \fBadded\fR to the jump database use the \fBDirhistIgnore\fR option in the main configuration file. .sp \fB(2)\fR To prevent a directory from being \fBremoved\fR from the jump database, edit the database (`\fBj edit\fR`) and prepend a plus sign (+) to the corresponding line. .sp Otherwise, if a query string is provided as parameter, \fIB\fR searches for this string in the database and cd to the best ranked matching entry. Example: `\fBj\ Down\fR` will probably take you to \fI/home/user/Downloads\fR, provided this directory has been already visited and is the best ranked match in the database. For a more detailed description of the matching algorithm see the \fBKANGAROO FRECENCY ALGORITHM\fR section below. .sp Multiple query strings can be passed to the function. For example, `\fBj\ et\ mo\fR` will first check for "et" in the jump database and then will further filter the search using the second parameter: "mo". It will most probably take you (again, provided the directory has been already visited and is the best ranked match) to \fI/etc/modprobe.d\fR directory. Bear in mind that if \fISTR\fR is an actual directory, \fBjump\fR will just cd to it without performing any query. .sp The backslash (\\) and the slash (/) can be used to instruct \fBKangaroo\fR to search for the string query only in the first or last path segment of each entry in the database respectively. Let\'s suppose we have two entries matching \fBsrc\fR in the database: \fI/media/src/images\fR and \fI/home/user/Downloads/clifm/src\fR. If the first entry is better ranked than the second, `\fBj src\fR` will match this first entry. However, if what we really want is the second entry, appending a slash to the query string instructs \fBKangaroo\fR to only match entries having src in the last path segment, here \fI/home/user/Downloads/clifm/src\fR. .sp Since it is not always obvious or easy to know where exactly a query string will take you, \fBclifm\fR (if the suggestions system is enabled) will print, at the right of the cursor, the path matched by \fBKangaroo\fR. If that is the actually intended path, press the Right arrow key to accept the suggestion. Otherwise, it will be ignored. You can also use tab completion to print the list of matches for the current query string. For example: `\fBj \- c\fR` to list all entries in the directory history list containing a dash (\-) and a \'c\'. .sp The \fBj\fR command accepts four modifiers: \fBe, \fBp\fR, \fBc\fR, and \fBl\fR, the first standing for "edit", the second for "parent", the third for "child", and the last one for "list". Thus, `\fBje\fR` (or `\fBj \-\-edit\fR`) will open the jump database to be edited as required; `\fBjc\fR` will search for files querying only child directories relative to the current working directory, while `\fBjp\fR` will do the same, but for parent directories. Finally, `\fBjl\fR` just prints the matches for the given query string(s), but without changing the current directory. Examples: .TS allbox; lb lb l l. Command Description T{ jp foo T} Change to the best ranked \fBparent\fR directory containing the string "foo". T{ jc bar test T} Change to the best ranked \fBchild\fR directory containing the string "bar" and "test" T{ jl foo T} Print all entries in the database containing the word "foo" .TE .sp Use the \fB\-\-purge\fR option to shrink the database. Without further parameters, \fB\-\-purge\fR removes all non\-existent (un\-stat\'able) directories from the database. If a numeric parameter is passed, by contrast, all entries ranked below this number will be removed from the database. For example, `\fBj \-\-purge 100\fR` will remove all entries ranked below 100. .sp You can also manually edit the database file using the `\fBje\fR` (or `\fBj \-\-edit\fR`) command: edit whatever needs to be edited, save changes, and close the editor. This is useful, for example, to remove a specific entry/directory from the database (however, bear in mind that if the directory is in the directory history, it will not be removed from the jump database). .sp To mark an entry as permanent (prevent it from being removed from the database), follow any of these procedures: a. Bookmark it. b. Edit the jump database (`\fBje\fR` or `\fBj --edit\fR`) and prepend a plus sign (+) to the corresponding entry. .sp An alternative way of navigating the jump database is using the jumper plugin (located in the plugins directory and bound by default to the \fB++\fR action name), which uses \fBfzf\fR to enable fuzzy searches. Enter `\fB++\fR` to perform a fuzzy search over the jump database. .sp Take a look at the \fBdh\fR command as well. .TP .B k .br If running in long view, toggle follow-links (\fBAlt++\fR is also available). See the \fB\-L,\-\-follow\-symlinks\-long\fR command line switch. .TP .B kk .br Toggle max-filename-len (\fBCtrl+Alt+l\fR is also available) .TP .B kb, keybinds \fR[list | bind \fIFUNCTION\fR | edit [\fIAPP\fR] | conflict | reset | readline] With no argument (or if the argument is \fBlist\fR), prints the current keybindings and their associated functions. .sp To change a keybinding use the \fBbind\fR subcommand. .sp Type `\fBkb bind \fR` to get the list of bindable functions. .sp Enter `\fBkb bind FUNCTION\fR` to set a new keybinding for \fIFUNCTION\fR. For example, to bind the function \fBprevious-dir\fR to a new key, enter `\fBkb bind previous-dir\fR`. You'll see a little prompt: press the key combination you want to associate to the specified function and then press \fBEnter\fR (while in this prompt, press \fBCtrl+d\fR to abort or \fBCtrl+c\fR to clear the current line). .sp To manually edit your keybindings use the \fBedit\fR option (the keybindings file will be opened with \fIAPP\fR, if specified, or with the default associated application otherwise). .sp If you somehow messed up your keybindings, you can check for keybinding conflicts with the \fBconflict\fR option, or use the \fBreset\fR option to create a fresh keybindings file with the default values. .sp To unbind a function run `\fBkb edit\fR` and comment out the corresponding entry. Note that some functions may have several entries, associating them to multiple keybindings: comment them out all if required. .sp To list readline keybindings (defined in \fI~/.config/clifm/readline.clifm\fR), use the \fBreadline\fR option. The syntax is the same as the one used by readline's \fI.inputrc\fR file (consult \fIhttp://tiswww.case.edu/php/chet/readline/readline.html#SEC9\fR for more information.) .TP .B l, le .br Create (\fBl\fR) or edit (\fBle\fR) symbolic links. .sp The syntax for the \fBl\fR command is: l \fITARGET\fR [\fILINK_NAME\fR]\fR. Note that if \fILINK_NAME\fR is omitted, the symbolic link is created as \fITARGET_BASENAME\fR.link in the current directory. .sp By default, the link target is created literally (like `\fBln -s\fR` would). The link creation mode can be set using the \fBLinkCreationMode\fR option in the configuration file. Available modes are: \fBabsolute\fR, \fBliteral\fR, and \fBrelative\fR (like `\fBln -rs\fR` would). .sp To edit the target of a symbolic link use the \fBle\fR command followed by the desired link name. The user will be prompted to enter a new link target, using the current target as template. .TP .B ll, lv \fR[on | off] Toggle the long view. .TP .B lm \fR[on | off] Toggle the light mode. This option, aimed at making file listing faster than the default mode, is especially useful for really old hardware or when working on remote machines (for more information see the \fBNOTE ON SPEED\fR section below). .TP .B log \fR[cmd | msg] [list | on | off | status | clear] Enable, disable, clear, list or check the status of the program logs, either message (errors and warnings) or command logs. Example: `\fBlog cmd on\fR`, to enable command logs, or `\fBlog msg clear\fR`, to clear/remove message logs. .sp Consult the \fBFILES\fR section below for information about how logs are written to the logs file. .TP .B media .sp 0 \fBNote\fR: This command is Linux\-specific .sp List available storage devices and mount/unmount the selected one using either \fBudevil\fR or \fBudisks2\fR (at least one of these must be installed. \fBudevil\fR will be preferred over \fBudisks2\fR). If the device is unmounted, it will be automatically mounted, and if mounted, it will be automatically unmounted. .sp Though mountpoints are determined by the mounting application itself (\fBudevil\fR or \fBudisks2\fR), \fBclifm\fR will automatically cd to the corresponding mountpoint whenever the mount operation was successful. .sp When unmounting, and if the current directory is inside the mountpoint, \fBclifm\fR will attempt to cd to the previous visited directory, and, if none, to the home directory, before unmounting the device. .sp To get information about a device, enter `\fBiELN\fR`, for example, `\fBi12\fR`, provided \'12\' is the ELN of the device you want. .TP .B mf \fR[\fINUM\fR | unset] List only up to \fINUM\fR files (valid range: >= 0). Use \fBunset\fR to list all files (default). An indicator (listed_files/total_files) will be printed below the list of files whenever some file is excluded from the current list (e.g. 20/310). Note, however, that though some files are excluded, all of them are loaded anyway, so that you can still perform any valid operation on them. For example, even if only 10 files are listed, you can still search for all symbolic links in the corresponding directory using the appropriate command: `\fB/*\ \-l\fR`. .TP .B mm, mime \fR[open \fIFILE\fR | info \fIFILE\fR | edit [\fIAPP\fR] | import] This is \fBLira\fR, \fBclifm\fR's file opener. .sp Use the \fBopen\fR subcommand to open a file with the default associated application. Note that, since \fBopen\fR is the default action, it can be omitted. For example: `\fBmm file.pdf\fR`. The same can be achieved more easily using the \fBopen\fR command: `\fBopen file.pdf\fR` (or using the short command, `\fBo file.pdf\fR`). Or, even shorter, just `\fBfile.pdf\fR`. .sp The \fBinfo\fR option prints MIME information about \fIFILE\fR: its MIME type, and, if any, the application (for both opening and previewing) associated with this filename or with the file's MIME type. If the application is associated with the file's name, \fB[FILENAME]\fR is printed after the associated application, otherwise, if associated with the file's MIME type, \fB[MIME]\fR is printed. .sp The \fBedit\fR option allows you to edit and customize the MIME list file. So, if a file has no default associated application, first get its MIME info or its file extension (running `\fBmm\ info\ FILE\fR`), and then add a value for it to the MIME list file using the \fBedit\fR option (`\fBmm\ edit\fR` or \fBF6\fR). Check the \fBFILE OPENER\fR section below for information about the mimelist file syntax. .sp Finally, via the \fBimport\fR option \fBclifm\fR will try to import MIME associations from the system looking for \fImimeapps.list\fR files in those paths specified by the Freedesktop specification (see \fIhttps://specifications.freedesktop.org/mime\-apps\-spec/mime\-apps\-spec\-latest.html\fR). If at least one MIME association is successfully imported, it will be stored as \fImimelist.clifm.XXXXXX\fR (where XXXXXX is a random six digits alphanumerical string). You can add these new associations to your mimelist file using the `\fBmime edit\fR` command. .TP .B mp, mountpoints List available mountpoints and change the current working directory to the selected mountpoint. .TP .B msg, messages \fR[clear] With no arguments, prints the list of messages in the current session. The \fBclear\fR option tells \fBclifm\fR to empty the messages list. .TP .B n, new \fR[\fIFILE[@TEMPLATE]\fR]... [\fIDIR/\fR]... Create new regular files and/or directories. .sp If a filename ends with a slash (/), it will be taken as a directory name. Else, it will be created as a regular file. E.g.: `\fBn\ myfile\ mydir/\fR`, to create a file named \fImyfile\fR and a directory named \fImydir\fR. If no filename is provided, the user will be prompted to enter one. .sp \fBAutomatic templates\fR .sp New regular files will be created from a \fBtemplate file\fR if: .sp 1. The file to be created has a filename extension (e.g., \fIfile.html\fR). 2. A file named like this extension, here \fIhtml\fR, exists in the templates directory \fB(1)\fR. .sp If both conditions are met, running `\fBn file.html\fR` will create a new file named \fIfile.html\fR which is a copy of the \fIhtml\fR file in the templates directory. .sp Note that template names are not limited to actual file extensions: you can name your templates whatever you like (with any content you want) provided new files are created using the template name as extension. E.g.: `\fBn file.my_super_cool_template\fR`. .sp \fBExplicit templates\fR .sp If a filename is followed by the expression \fI@TEMPLATE\fR, where TEMPLATE is any regular file found in the templates directory\fB(1)\fR, the file will be created as a copy of the corresponding file template. E.g., `\fBn file.sh@my_script.sh\fR`. .sp Tab completion is available for explicit templates: `\fBn file@\fR`. .sp \fB(1)\fR The templates directory is \fB$CLIFM_TEMPLATES_DIR\fR, \fB$XDG_TEMPLATES_DIR\fR, or \fI~/Templates\fR, in this precedence order. .sp \fBFilename validation\fR is performed over names before creation. In case of an unsafe name, the user is warned and asked for confirmation. .sp A name (namely, any component of a path) is considered unsafe if: 1. Starts with a dash (\-): command option flags collision 2. Is a reserved keyword/expression (internal): fastback (...), ELN/range (12, 1\-45), and MIME/file type expansion (@query, =x) 3. Is a reserved system/shell keyword (\'~\', \'.\' ,\'..\') 4. Contains embedded control characters (0x00\-0x1f in the ASCII table) 5. Contains embedded shell meta\-characters (*?:[]"<>|(){}&'!\\;$) 6. It is too long (larger than NAME_MAX, usually 255 bytes) .sp For more information about unsafe filenames consult \fIhttps://dwheeler.com/essays/fixing\-unix\-linux\-filenames.html\fR. .TP .B net \fR[\fINAME\fR | list | edit | m, mount \fINAME\fR | u, unmount \fINAME\fR] \fB1. The configuration file\fR .sp The \fBnet\fR command manages connections to remote systems via a simple samba\-like configuration file (\fI$HOME/.config/clifm/profiles/PROFILE/nets.clifm\fR). Here you can specify multiple remotes and options for each of these remotes. Syntax example for this file: .sp [remote_name] Comment=A nice descriptive comment Mountpoint=/path/to/mountpoint MountCmd=sudo mount.cifs //192.168.0.12/share %m \-o OPTIONS UnmountCmd=sudo umount %m AutoUnmount=true (Auto\-unmount this remote at exit) AutoMount=false (Auto\-mount this remote at startup) .sp \fBNote\fR: \fB%m\fR can be used as a placeholder for \fIMountpoint\fR. \fB%m\fR will be replaced by the value of \fIMountpoint\fR. .sp \fB1.a.\fR Mounting remote filesystems .sp \fBA Samba share\fR: [samba_share] Comment=My samba share Mountpoint="~/.config/clifm/mounts/smb_share" MountCmd=sudo mount.cifs //192.168.0.26/samba_share %m \-o mapchars,credentials=/etc/samba/credentials/samba_share UnmountCmd=sudo umount %m AutoUnmount=false AutoMount=false \fBA SSH filesystem (sshfs)\fR: [ssh_share] Comment=My ssh share Mountpoint="/media/ssh" MountCmd=sshfs user@192.168.0.26: %m \-C \-p 22 UnmountCmd=fusermount3 \-u %m AutoUnmount=true AutoMount=false .sp \fB1.b.\fR Mounting local filesystems .sp Though originally intended to manage remote filesystems, \fBnet\fR can also manage \fBlocal filesystems\fR. Just provide the appropriate mount and unmount commands. Since the device name assigned by the kernel might change across reboots (specially when it comes to removable drives), it is recommended to mount using the device\'s UUID (Universal Unique Identifier) instead of the drive name. For example: MountCmd=sudo mount \-U c98d91g4\-6781... %m Here\'s an example of how to set up \fBnet\fR to mount USB devices, one with a FAT filesystem, and another with an ISO9660 filesystem: [Sandisk USB] Comment=Sandisk USB drive Mountpoint="/media/usb" MountCmd=sudo mount \-o gid=1000,fmask=113,dmask=002 \-U 5847\-xxxx %m UnmountCmd=sudo umount %m AutoUnmount=false AutoMount=false [Kingston USB] Comment=Kingston USB drive Mountpoint="/media/usb2" MountCmd=sudo mount \-t iso9660 \-U 2020\-10\-01\-15\-xx\-yy\-zz %m UnmountCmd=sudo umount %m AutoUnmount=false AutoMount=false \fBNote\fR: The \fBgid\fR, \fBfmask\fR, and \fBdmask\fR options are used to allow the user to access the mountpoint without elevated privileges. .sp If the device data is unknown, as it often happens when it comes to removable devices, you should use the \fImedia\fR command instead. .sp \fB2. Command syntax\fR .sp Without arguments (or via the \fBlist\fR subcommand), \fBnet\fR lists the configuration for each remote available in the configuration file. .sp Use the \fBedit\fR option to edit the remotes configuration file. If no further argument is specified, the file will be opened with the current file opener. However, you can pass an application as second parameter to open to configuration file. For example: `\fBnet edit nano\fR`. .sp If not already mounted, the \fBm\fR, \fBmount\fR option mounts the specified remote using the mount command and the mounpoint specified in the configuration file and automatically cd to the corresponding mountpoint. For example: `\fBnet mount smb_work\fR`. Since \fBmount\fR is the default action, it can be omitted: `\fBnet smb_work\fR`. .sp The \fBu\fR, \fBunmount\fR option unmounts the specified remote using the unmount command specified in the configuration file. For example: `\fBnet unmount smb_work\fR`. Tab completion is also available for this function. .sp \fBNote\fR: If you only need to copy some files to a remote location (including mobile phones) without the need to mount the resource, you can make use of the \fIcprm.sh\fR plugin, bound by default to the \fBcr\fR action. Set up your remotes (`\fBcr \-\-edit\fR`) and then send the file you want (`\fBcr FILE\fR`). .TP .B o, open \fIFILE\fR [\fIAPPLICATION\fR] Open \fIFILE\fR, which can be either a directory (in which case it works just like the \fBcd\fR command), a regular file, or a symbolic link to either of the two. For example: `\fBo\ 12\fR`, `\fBo\ filename\fR`, `\fBo\ /path/to/filename\fR`. .sp By default, the \fBopen\fR command will open files with the default application associated to them via \fBLira\fR, the builtin file opener (see the \fBmime\fR command above). However, if you want to open a file with a different application, add the application name as second argument, e.g. `\fBo\ 12\ leafpad\fR` or `\fBo12\ leafpad\fR`. .sp If you want to run the program in the background, simply add the ampersand character, as usual: `\fBo\ 12\ &\fR`, `\fBo\ 12&\fR`, `\fBo12&\fR` or (if auto\-open is enabled) just `\fB12&\fR`. .sp If the file to be opened is an archive/compressed file, the archive function (see the \fBad\fR command above) will be executed instead. .TP .B oc \fIFILE\fR... Interactively change file ownership. .sp A new prompt is displayed using user and primary group common to all files passed as parameters as ownership template. .sp Ownership (both user and primary group, if specified) is changed for all files passed as parameters. If the file is a symbolic link, the operation is performed on the target file, and not on the symbolic link itself. Bear in mind that recursion is not supported: use \fBchown\fR(1) (with the \fB\-R\fR option) instead. .sp Both names and ID numbers are allowed (Tab completion for names is available). .sp If only a name/number is entered, it is taken as the user who owns the file(s). .sp Use the \fBpc\fR command to edit files permissions. .TP .B opener \fR[default | \fIAPPLICATION\fR] With no argument, prints the currently used file opener (by default, \fBLira\fR, \fBclifm\fR\'s builtin opener). Otherwise, set APPLICATION (say \fBrifle\fR or \fBxdg\-open\fR) as opener or, if \fBdefault\fR is passed instead, use \fBLira\fR. .TP .B ow \fIFILE\fR [\fIAPPLICATION\fR] If \fIAPPLICATION\fR is specified, open \fIFILE\fR with \fIAPPLICATION\fR. In case you need to add parameters to \fRAPPLICATION\fR, it is recommended to quote the expression: `\fBow \fIFILE\fR "\fIAPP ARG\fR..."\fR`. .sp If \fIAPPLICATION\fR is not specified, the list of available applications associated to \fIFILE\fR (either via its MIME type or its file extension) is printed, allowing the user to choose one of these applications, and then open the file with the selected application. .sp This command supports tab completion. Type `\fBow FILE \fR` and the list of applications able to open \fIFILE\fR will be displayed . .TP .B p, pp, prop \fIFILE\fR... Print file properties for \fIFILE\fR. The output of this function is much like the combined output of the shell commands`\fBls\ \-l\fR` and `\fBstat\fR`. .sp By default, directory sizes are not displayed. Use \fBpp\fR instead of just \fIp\fR to print directory sizes as well (it could take longer depending on the directory's content). On the other side, and unlike \fBp\fR, \fBpp\fR provides information about the dereferenced symlinks (namely, the symlink target) instead of the symlink itself. However, note that, in case of symbolic links to directories, \fBp\fR provides information about the link \fBtarget\fR if the provided filename ends with a slash. Otherwise, information about \fBthe link itself\fR is displayed. .sp The time format used to display time information can be customized via the \fBPTimeStyle\fR option in the configuration file (defaults to "%Y\-%m\-%d %H:%M:%S.%N %z", where %N stands for nano\-second precision). .sp If you need to list the properties of all files in the current directory, try the long view (\fBll\fR or \fBAlt+l\fR). Fields displayed in this mode can be customized using the \fBPropFields\fR option in the configuration file. For custom timestamp formats use the \fBTimeStyle\fR option. .sp For more information about file details consult the \fBfile\-details\fR help topic: `\fBhelp file\-details\fR`. .TP .B pc \fIFILE\fR... Interactively change file permissions (only traditional Unix permissions are supported). .sp A new prompt is displayed using actual permissions (in symbolic notation) of the file to be edited as template. If editing multiple files with different sets of permissions, only shared permission bits are set in the permissions template. .sp Bear in mind that, if editing multiple files at once, say `\fBpc sel\fR` or `\fBpc *.c\fR`, the new permissions set will be applied to \fBall\fR of them. .sp Both symbolic and octal notation for the new permissions set are allowed. .sp Recursively setting file permissions is not supported. Use \fBchmod\fR(1) with the \fB\-R\fR flag instead. .sp If you just need to toggle the executable permission bit on a file, you can use the \fBte\fR command. .sp Use the \fBoc\fR command to edit files ownership. .TP .B pf, profile \fR[ls, list | set, add, del \fIPROFILE\fR | rename \fIPROFILE\fR \fINEW_NAME\fR] With no arguments, prints the name of the currently used profile. Use the \fBls\fR or \fBlist\fR option to list available profiles. To switch, add, delete, or rename a profile, use the \fBset\fR, \fBadd\fR, \fBdel\fR, and \fBrename\fR options respectively. .TP .B pg, pager \fR[on | off | once | status | \fINUM\fR] Run or set \fBMas\fR, \fBclifm\fR's builtin files pager. .sp With no parameter, just run the pager (\fBAlt+0\fR is also available). .sp If set to on, run the pager whenever the list of files does not fit on the screen. .sp Set it to any positive integer greater than 1 to run the pager whenever the number of files in the current directory is greater than or equal to this value, say 1000 (0 amounts to \fBoff\fR and 1 to \fBon\fR). .sp Set to \fBonce\fR to run the pager only a single time (overwriting whatever was its previous value). .sp While paging, the following keys are available: .sp \fB?\fR, \fBh\fR: Help \fBDown arrow\fR, \fBEnter\fR, \fBSpace\fR: Advance one line \fBPage down\fR: Advance one page \fBq\fR: Stop paging (without printing remaining files) \fBc\fR: Stop paging (printing remaining files) .sp Note: To scroll lines up, use whatever your terminal emulator has to offer (e.g.: mouse scrolling or some keybinding). .sp By default, the pager lists files using the current listing mode (long or short). Use \fBPagerView\fR in the configuration file (or \fB\-\-pager\-view\fR in the command line) to force the use of a specific mode. Possibles values: .sp \fBauto\fR: Use the current listing mode (default) \fBlong\fR: List files in long view \fBshort\fR: List files in short view .TP .B pin \fR[\fIFILE/DIR\fR] Pin a file or directory to be accessed later via the comma (,) keyword. For example, run `\fBpin mydir\fR` and then access \fImydir\fR as follows: `\fBcd\ ,\fR` where the comma is automatically expanded to the pinned file, in this case \fImydir\fR. The comma keyword could be used with any command, either internal or external, e.g, `\fBls\ ,\fR`. .sp With no arguments, the \fIpin\fR command prints the current pinned file, if any. If an argument is given, it will be taken as a filename to be pinned. Running this command again, frees the previous pinned file and sets a new one. In other words, only one pin is supported at a time. .sp An easy alternative to create as many pins or shortcuts as you want, and how you want, is to use the \fBalias\fR function. Bookmarks could also be used to achieve a very similar result. .sp At program exit, the pinned file is written to a file in the configuration directory (as \fI.pin\fR) to be loaded in the next session. .TP .B prompt \fR[set \fINAME\fR | list | edit [\fIAPP\fR] | unset | reload] Manage \fBclifm\fR's prompts. Use the \fBset\fR subcommand to temporarily change the current prompt to the prompt named NAME (use the \fBunset\fR subcommand to unset the current prompt and set the default one). Available prompts (which can be listed using `\fBprompt list\fR` or `\fBprompt set \fR`) are defined in the prompts file (\fI$HOME/.config/clifm/prompts.clifm\fR). To permanently set a prompt, edit your color scheme file (via the `\fBcs edit\fR` command) and set \fBPrompt\fR to either a prompt code or a prompt name (as defined in the prompts file). .TP .B q, quit, exit Quit \fBclifm\fR. .TP .B rf, refresh Refresh the screen, that is, reprint files in the current directory and update the prompt. If the current directory is not accessible for any reason, \fBrf\fR will go up until it finds an accessible one and then will change to this directory. .TP .B rl, reload Reload all settings, except those passed as command line arguments, from the configuration file. .TP .B rr \fR[\fIDIR\fR] [\fIEDITOR\fR] Remove files and/or directories in bulk using a text editor. .sp \fBrr\fR writes all filenames in \fIDIR\fR (or in the current directory if \fIDIR\fR is omitted) to a temporary file and opens it using \fIEDITOR\fR (or the default associated application for \fItext/plain\fR MIME type, if \fIEDITOR\fR is omitted). .sp Once in the editor, remove the lines corresponding to the files you want to delete. Save changes and close the editor. Removed files will be listed and the user asked for confirmation. .TP .B s, sel \fIFILE\fR... [[!]\fIPATTERN\fR] [\fI\-FILETYPE\fR] [\fI:PATH\fR] Mark one or more files (either regular files or directories) as selected (send to the Selection Box). \fBsel\fR accepts individual elements, range of elements, say 1\-6, filenames and paths, just as wildcards (globbing) and regular expressions. For example: `\fBs 1 4\-10 ^r file* filename /path/to/filename\fR`. .sp If not in light mode, once a file is selected, and if the file is in the current directory, the corresponding filename will be highlighted with a mark (colored according to the value of \fBli\fR in the color scheme file (by default bold green)) at the left of the filename (and at the right of its ELN). .sp Just as in the \fBsearch\fR function, it is also possible to further filter the list of matches indicating the desired file type. For instance, `\fBs ^ \-d\fR` will select all directories in the current directory. For available file type filters see the \fBsearch\fR function above. .sp By default, the selection function operates on the current working directory. To select files in any other directory use the ":PATH" expression. For example, to select all regular files with a .conf extension in the \fI/etc\fR directory, the command would be: `\fBs\ .*\\.conf$\ \-f :/etc\fR`, or using wildcards: `\fBs *.conf \-f\ :/etc\fR`. Of course, you can also do just `\fBs \-f /etc/*.conf\fR`. .sp Just as in the case of the \fBsearch\fR function, inverse matching is supported for patterns, either wildcards or regular expressions. To invert the meaning and action of a pattern, prepend an exclamation mark (!). E.g., to select all non\-hidden regular files in the Documents directory, issue this command: `\fBs !^\.\ \-f :Documents\fR`, or, to select all directories in \fI/etc\fR, except those ending with ".d": `\fBs !*.d \-d :/etc\fR`. .sp Glob and regular expressions can be used together. For example: `\fBs ^[r|R].*d$ /etc/*.conf\fR` will select all files starting with either 'r' or 'R' and ending with 'd' in the current directory, plus all .conf files in the \fI/etc\fR directory. However, this use is discouraged if both patterns refer to the same directory, since the second one will probably override the result of the first one. .sp It is important to note that glob expressions are evaluated before regular expressions, in such a way that any pattern that could be understood by both kinds of pattern matching mechanisms will be evaluated first according to the former, that is, as a glob expression. For example, '.*', as regular expression, should match all files. However, since glob expressions are evaluated first, it will only match hidden files. To select all files using a glob expression, try \'.* *\', or, with a regular expression: \'^\' or \'(.*?)\'. The keyboard shortcut \fBAlt+a\fR is also available to perform the same operation. .sp The Selection Box is accessible from different instances of the program, provided they use the same profile (see the \fBprofile\fR command below). By default, indeed, each profile keeps a private Selection Box, being thus not accessible to other profiles. You can nonetheless modify this behavior via the \fBShareSelbox\fR option in the configuration file. If \fBShareSelbox\fR is enabled, selected files are stored in \fI/tmp/clifm/username/.selbox.clifm\fR. Otherwise, \fI/tmp/clifm/username/.selbox_profilename.clifm\fR is used (this is the default). .sp \fBOperating on selected files\fR .sp To operate on one or more selected files use the \fBsel\fR keyword (\fBs:\fR can be used as well). For example, to print the file properties of all selected files: `\fBp sel\fR` (or `\fBp s:\fR)`. Use `\fBs:\fR` to list selected files (multi\-selection is available if running in fzf mode). .sp \fBListing selected files\fR .sp To list selected files use the \fIsb\fR command (standing for Selection Box). You can also type `\fBs:\fR`. .sp \fBDeselecting files\fR .sp To deselect files use the \fBds\fR command (see above). You can also press \fBAlt+d\fR to deselect all files at once. .sp \fBNote\fR: If there is a file named \fIsel\fR in the current directory, use \fI./sel\fR to distinguish it from the \fBsel\fR keyword. For example, enter `\fBp ./sel\fR` to tell \fBclifm\fR that you want to get the properties of the file named \fIsel\fR rather than the properties of the currently selected files. .sp For more information consult the \fBBUILT\-IN EXPANSIONS\fR section below. .TP .B sb, selbox Print the elements currently contained in the Selection Box. .TP .B st, sort \fR[\fIMETHOD\fR] [rev] With no argument, print the current sort order. Else, sort files by METHOD, where METHOD is one of: 0=none, 1=name, 2=size, 3=atime, 4=btime, 5=ctime, 6=mtime, 7=version, 8=extension, 9=inode, 10=owner, 11=group, 12=blocks, 13=links, or 14=type (e.g.: \fIst atime\fR or \fIst 3\fR). Methods 10 and 11 sort by owner and group ID names if using ID names in long view (see the \fBPropFields\fR option in the configuration file). Else, ID numbers are used. The default order is \fBversion\fR. .sp By default, files are sorted from less to more (e.g.: from \'a\' to \'z\' if sorting by \fBname\fR). Use the \fBrev\fR subcommand to invert this order. E.g.: `\fBst\ rev\fR` or `\fBst\ inode\ rev\fR`. Switch back to the previous state by running `\fBst rev\fR` again. .sp Take a look at the configuration file for extra sort options (\fBListDirsFirst\fR, \fBPrioritySortChar\fR, \fBShowHiddenFiles\fR). .TP .B stats .br Print file statistics for files in the current directory (not available in light mode). .TP .B t, trash \fR[\fIFILE\fR... | ls, list | clear, empty | del [\fIFILE\fR]...] Move specified files to the trash can (e.g. `\fBt file1 file2\fR`). .sp With no argument (or by passing the \fBls\fR option), it prints the list of currently trashed files. The \fBclear\fR (or \fBempty\fR) sucommand removes \fBall\fR files from the trash can, while the \fBdel\fR subcommand lists trashed files allowing the user to permanently remove one or more trashed files. If using \fBdel\fR, tab completion to list/select currently trashed files is available. .sp The trash directory is \fI$XDG_DATA_HOME/Trash\fR, falling back to \fI$HOME/.local/share/Trash\fR. To set an alternative trash directory use the \fB\-T,\-\-trash\-dir\fR command line option. .sp Since this trash system follows the Freedesktop specification, it is able to handle files trashed by different Trash implementations. .sp To restore trashed files (to their original location) see the \fBuntrash\fR command below. .TP .B tag \fR[add | del | list | list\-full | new | merge | rename | untag] [\fIFILE\fR]... [[\fI:\fR]\fITAG\fR] \fItag\fR is the main \fIEtiqueta\fR command, \fBclifm\fR's builtin files tagging system. See the \fBFILE TAGS\fR section for a complete description of this command. .TP .B te \fIFILE\fR... Toggle the executable bit (on user, group, and others) on FILE(s). It is equivalent to the \fB\-x\fR and \fB+x\fR options for the \fBchmod\fR(1) command. .TP .B tips .br Print the list of \fBclifm\fR tips. .TP .B u, untrash \fR[*, a, all | \fIFILE\fR]... If filenames are passed as parameters, restore them to their original location. Otherwise, this function prints a list of currently trashed files allowing the user to choose one or more of these files to be restored. Use the \fB*\fR, \fBa\fR or \fBall\fR parameters to restore all trashed files at once. Tab completion to list/select currently trashed files is available. .TP .B unpin .br This command takes no argument. It just frees the current pin and, if it exists, deletes the \fI.pin\fR file generated by the \fBpin\fR command. .TP .B vv \fIFILE\fR... \fIDIR\fR Copy \fIFILE\fR(s) to \fIDIR\fR and bulk rename them at once. .TP .B ver, version Show \fBclifm\fR version details. .TP .B view \fR[edit [\fIAPP\fR] | purge] preview files in the current directory (full screen). Requires \fBfzf\fR(1). \fBAlt+-\fR is also available. .sp By pressing \fBEnter\fR or \fBRight\fR, the currently highlighted file will be selected and \fBview\fR closed. To select multiple files, mark them with the TAB key and then press \fBEnter\fR or \fBRight\fR to confirm. To quit \fBview\fR press Escape or the Left arrow key. .sp Run `\fBview purge\fR` to purge the thumbnails directory (\fI$XDG_CACHE_HOME/clifm/thumbnails\fR) of dangling thumbnails. .sp To edit the previewer configuration file enter `\fBview edit\fR`, or `\fBview edit vi\fR` to open it with a specific application, in this case, \fBvi\fR(1). .sp For \fBimage previews\fR consult the Wiki (\fIhttps://github.com/leo\-arch/clifm/tree/master/misc/tools/imgprev\fR) or enter `\fBhelp image\-previews\fR`. .sp For further information consult the \fBSHOTGUN\fR section below. .TP .B ws \fR[\fINUM/NAME\fR | unset | + | -] \fBClifm\fR offers up to eight workspaces, each with its own independent path. .sp With no argument, the \fBws\fR command prints the list of workspaces and its corresponding paths, highlighting the current workspace. .sp Use \fINUM\fR to switch to the workspace number \fINUM\fR, \fINAME\fR to switch to the workspace named \fINAME\fR, the plus sign (+) to switch to the next workspace, and the minus sign (\-) to switch to the previous workspace. .sp To unset a workspace use the \fBunset\fR subcommand preceded by the workspace (either number or name) to be unset. For example: `\fBws 2 unset\fR`. .sp Four keyboard shortcuts are available to easily switch to any of the first four workspaces: \fBAlt+[1\-4]\fR. .sp Every time an empty workspace is created, it starts in the current working directory. .sp Though by default workspaces are unnamed, you can name them however you like using the \fBWorkspaceNames\fR option in the configuration file. .sp Use autocommands to persistenly set options per workspace, for example, to always list files in the third workspace in long view. See the \fBAUTOCOMMANDS\fR section below for more information. .sp Make local settings private to the current workspace by setting the \fBPrivateWorkspaceSettings\fR option to \fBtrue\fR in the configuration file: settings changed via either the command line or keyboard shortcuts (say \fBAlt+l\fR, to toggle the long view) will apply only to the current workspace and will be remembered even when switching workspaces. .sp To directly operate on a workspace (namely, the path it points to) you can use the \fBw:\fR prefix followed by a workspace number or name. For example, to copy all .png files in the current directory to the third workspace, enter `\fBc *.png w:3\fR`. Press TAB immediately after \fBw:\fR to get the list of available workspaces. .TP .B x, X \fR[\fIDIR\fR] Open \fIDIR\fR, or the current working directory if \fIDIR\fR is not specified, in a new instance of \fBclifm\fR (as root if \fBX\fR, as the current unprivileged user if \fBx\fR) using the value of \fBTerminalCmd\fR (from the configuration file) as terminal emulator. If this value is not set, \fBxterm\fR will be used as fallback terminal emulator. This function is only available for graphical environments. .TP .B Shell\-builtins implementations .sp .B pwd \fR[-LP] .sp Print the current working directory .sp .B export \fINAME\fR=\fIVALUE\fR... .sp Export variables to the environment .sp .B umask \fR[\fIVALUE\fR] .sp Print/set the current umask value .sp .B unset \fINAME\fR .sp Remove a variable from the environment .SH 5. FILE FILTERS \fBClifm\fR provides multiple ways to filter the current list of files: .sp \fBa)\fR Hidden files: via the \fB\-A\fR and \fB\-a\fR command line flags, the \fBhh\fR command, and the \fBAlt+.\fR keybinding. .sp Files listed in a file named \fI.hidden\fR in the current directory will be hidden as well whenever hidden files are not shown (wildcards are supported). .sp \fBb)\fR Directories: via the \fB\-\-only\-dirs\fR command line switch and the \fBAlt+,\fR keybinding. .sp \fBc)\fR Filenames and file types: either via a regular expression or a file type character (see below) using the \fBft\fR command (the \fBFilter\fR option in the configuration file and the \fBCLIFM_FILTER\fR environment variable are also available). For example, to exclude backup files (ending with a tilde): .sp \fBCLIFM_FILTER=\'!.*~$\' clifm\fR .sp or (in the configuration file): .sp \fBFilter="!.*~$"\fR .sp or (via the \fIft\fR command): .sp \fBft !.*~$\fR .sp See the \fBft\fR command for a few more examples. .sp \fBd)\fR Filtering files via the TAB key: .sp You can filter files \fBby name\fR using wildcards. For example: `\fBp *.mp3\fR` (or `\fB/*.mp3\fR`) to get a list of MP3 files in the current directory. .sp Files can also be filtered \fBby MIME\-type\fR using the \fB@\fR prefix. Type `\fB@\fR` to list all MIME\-types found in the current directory, or `\fB@query\fR` to list all files whose MIME\-type includes the string "query". For example, `\fB@image\fR` will list all files in the current directory whose MIME type includes the string "image". .sp Finally, files can be filtered as well \fBby file type\fR using the \fB=\fR prefix followed by a file type character (see below). For example, `\fB=l\fR` to get a list of symbolic links in the current directory. .sp Note: If using tab completion in fzf mode, multi\-selection is allowed (except in the case of `\fB@\fR`). .sp Available file type characters: \fBb\fR: Block devices \fBc\fR: Character devices \fBC\fR: Files with capabilities (1)(2) \fBd\fR: Directories \fBD\fR: Empty directories \fBf\fR: Regular files \fBF\fR: Empty regular files \fBg\fR: SGID files (2) \fBh\fR: Multi\-hardlink files (directories excluded) \fBl\fR: Symbolic links \fBL\fR: Broken symbolic links \fBo\fR: Other\-writable files (2) \fBp\fR: FIFO/pipes (2) \fBs\fR: Sockets (2) \fBO\fR: Doors (Solaris only) \fBP\fR: Event ports (Solaris only) \fBt\fR: Files with the sticky bit set (2) \fBu\fR: SUID files (2) \fBx\fR: Executable files (2) .sp (1) Only for tab completion .sp 0 (2) Not available in light mode .sp \fBe)\fR Grouping files (via automatic expansion): .sp By means of the above features, you can easily group and operate on groups of files. For example, this command: .sp \fBvt b: @image =x sel t:work *.txt\fR .sp opens a virtual directory (see the \fBVIRTUAL DIRECTORIES\fR section below) automatically expanding the above expressions as follows: .TS allbox tab(;); lb lb l l. Expression ; Description b: ; All your bookmarks (paths) @image ; All image files (CWD) =x ; All executable files (CWD) sel ; All selected files t:work ; All files tagged as \fIwork\fR *.txt ; All .txt files (CWD) .TE .SH 6. KEYBOARD SHORTCUTS .sp The following is the list of default keyboard shortcuts: .TS allbox tab(:); lb lb lb l. Key : Description Ctrl+Alt+j : Toggle the vi editing mode Right, Ctrl+f : Accept the current suggestion Alt+Right, Alt+f : Accept the first suggested word (up to the first slash or space) Alt+c : Clear the current command line buffer Alt+q : Delete last word (up to last slash or space) Alt+i, Alt+. : Toggle hidden\-files Alt+l : Toggle long\-view Alt++ : Toggle follow\-links (long view only) Alt+g : Toggle list\-directories\-first Alt+, : Toggle list\-only\-directories Ctrl+Alt+l : Toggle max\-filename\-length Ctrl+Alt+i, Alt+Tab : Toggle disk\-usage\-analyzer Alt+w : Toggle full\-path\-filenames (virtual directories) Ctrl+l : Refresh the screen (reprint the list of files in the current directory) Alt+t : Clear program messages Alt+m : List mountpoints Alt+b : Launch the Bookmark Manager Alt+h : Show the directory history Alt+n : Create new file or directory Alt+s : Open the Selection Box Alt+\- : Launch the file previewer (\fIview\fR command) Alt+a : Select all files in the current directory Alt+d : Deselect all files Alt+0 : Run MAS, the file pager Alt+p : Change to the pinned directory Alt+1 : Switch to workspace 1 Alt+2 : Switch to workspace 2 Alt+3 : Switch to workspace 3 Alt+4 : Switch to workspace 4 .TE .TS allbox tab(:); lb lb lb l. Key : Description Alt+r : Change to the root directory Alt+e, Home : Change to the home directory Alt+u, Shift+Up : Change to the parent directory Alt+j, Shift+Left : Change to the previously visited directory Alt+k, Shift+Right : Change to the next visited directory Ctrl+Alt+o : Switch to the previous profile Ctrl+Alt+p : Switch to the next profile Ctrl+Alt+a : Archive selected files Ctrl+Alt+e : Export selected files Ctrl+Alt+r : Rename selected files Ctrl+Alt+d : Remove selected files Ctrl+Alt+t : Trash selected files Ctrl+Alt+v : Copy selected files to the current directory Alt+y : Toggle light-mode Alt+z : Switch to previous sort method Alt+x : Switch to next sort method Ctrl+Alt+x : Launch a new instance of \fBclifm\fR Ctrl+y : Copy the contents of the line buffer to the clipboard \fB(1)\fR F1 : Go to the manpage F2 : List commands F3 : List keybindings F6 : Open the MIME list file F7 : Open the shotgun configuration file F8 : Open the current color scheme file F9 : Open the keybindings file F10 : Open the main configuration file F11 : Open the bookmarks file F12 : Quit .TE .TP \fB(1)\fR This shortcut is bound to the \fBxclip\fR plugin. See the \fBPLUGINS\fR section below for more information. .TP \fBCustomizing keybindings\fR .TP The above are the default keyboard shortcuts. However, they can be customized using the `\fBkb bind\fR` command (for more information consult the description for the \fBkb\fR command above). .TP The keybindings configuration file can also be manually edited using the `\fBkb edit\fR` command (for more details take a look at the description provided by this file itself). .TP .B Readline keybindings .TP Readline keybindings for command line editing, such as \fBCtrl+a\fR, to move the cursor to the beginning of the line, or \fBCtrl+e\fR, to move it to the end, should work out of the box. Of course, you can modify these keybindings by editing the \fI~/.config/clifm/readline.clifm\fR file, following the same rules used by readline itself for the \fI~/.inputrc\fR file. For more information consult the readline documentation (\fBreadline\fR(3)). .TP .B Keybindings for plugins .TP \fBclifm\fR provides sixteen customizable keybindings for custom plugins. The procedure for setting a keybinding for a plugin is the following: .TP \fB1\fR. Copy your plugin to the plugins directory (or use any of the plugins already in there) .TP \fB2\fR. Link pluginx (where \'x\' is the plugin number [1\-16]) to your plugin using the `\fBactions edit\fR` command. E.g.: "plugin1=myplugin.sh" .TP \fB3\fR. Set a keybinding for pluginx using the `\fBkb edit\fR` command. E.g.: "plugin1:\\M\-7" .TP .B Kitty keyboard protocol support .TP The Kitty Keyboard Protocol offers a significant improvement over the current handling of keyboard events in terminals. This protocol utilizes \fBCSI u\fR escape sequences and introduces several enhancements, including the ability to use extra modifier keys such as Super, Meta, and Hyper. .TP To enable the Kitty Keyboard Protocol, follow these steps: .TP \fB1\fR. Download the specially crafted keybindings configuration file designed to handle \fBCSI u\fR escape sequences (\fIhttps://github.com/leo-arch/clifm/blob/master/misc/kitty/keybindings.clifm\fR). .TP \fB2\fR. Configure \fBclifm\fR to use this new file instead of the default one (\fI~/.config/clifm/keybindings.clifm\fR) by using the \fB\-k\fR command line switch. Alternatively, you can replace the default file with the new one. .TP \fB3\fR. If your terminal is not already set up to send \fBCSI u\fR sequences, use the \fB\-\-kitty\-keys\fR command line switch. .TP Summarizing, and once you have the replacement keybindings file in place, run the following command: \fBclifm -k /path/to/keybindings/file --kitty-keys\fR .TP Important .TP When using the Kitty Keyboard Protocol, the \fBCtrl+d\fR shortcut (used to quit secondary prompts) will no longer work. To resolve this issue, add the following line to your \fIkitty.conf\fR file: \fBmap control+d send_text kitty \\x04\fR .TP This will force the terminal to emit the old value for this specific key binding, providing a workaround for the issue. .TP .B Troubleshooting .TP Some of these default keybindings may not work on your console/terminal emulator, depending on your system. Some useful tips on this regard: .TP Haiku terminal: Most of these keybindings will not work on the Haiku terminal, since \fBAlt\fR plays here the role \fBCtrl\fR usually plays in most other systems (see the Haiku documentation). To fix this, set your custom keybindings. .TP Kernel builtin console: Key sequences involving the \fBShift\fR key (\fBShift\-Up\fR, \fBShift\-Left\fR, and \fBShift\-Right\fR in our case) will just not work. Use the alternative key sequences instead: \fBAlt+u\fR, \fBAlt+j\fR, and \fBAlt+k\fR respectively. .TP NetBSD (wsvt25) and OpenBSD (vt220) kernel consoles: Key sequences involving the Alt key will not work out of the box. Here\'s how to make them work: On OpenBSD: 1) Copy \fI/etc/examples/wsconsctl.conf\fR to \fI/etc\fR (if it does not already exist) 2) Add the \fBmetaesc\fR flag to your current keyboard encoding. For example: \fBkeyboard.encoding=us.metaesc\fR You may need to reboot the machine for changes to take effect. On NetBSD: Add the \fBmetaesc\fR flag to your current encoding in \fI/etc/wscons.conf\fR. For example: \fBencoding us.metaesc\fR You may need to reboot the machine for changes to take effect. .TP Konsole: If \fBShift+left\fR and \fBShift+right\fR are not already bound to any function, you need to bind them manually. Go to Settings \-> Edit current profile \-> Keyboard \-> Default (Xfree4), and add these values: Left+Shift \\E[1;2D Right+Shift \\E[1;2C .sp If they are already bound, by contrast, you only need to unbound them. Go to "Settings \-> Configure keyboard shortcuts", click on the corresponding keybinding, and set it to "Custom (none)"). .TP Terminology/Yakuake: Shift+left and Shift+right are already bound to other functions, so that you only need to unbind them or rebind the corresponding functions to different key sequences. .TP Of course, the above two procedures should be similar in case of keybinding issues in other terminal emulators. .TP In case some of these keybindings are already used by your Window Manager, you only need to unbind the key or rebind the corresponding function to another key. Since each Window Manager uses its own mechanisms to set/unset keybindings, you should consult the appropriate manual. .SH 7. THEMING .TP All customization settings (theming) are made from a single configuration file (the color scheme file), installed by default in \fI$XDG_DATA_DIRS/clifm/colors\fR (usually \fI/usr/local/share/clifm/colors\fR or \fI/usr/share/clifm/colors\fR), though color scheme files found in \fI$XDG_CONFIG_HOME/clifm/colors\fR (usually \fI$HOME/.config/clifm/colors\fR) take precedence. .TP \fBNote\fR: Color scheme files are copied automatically to the local colors directory when running the `\fBcs edit\fR` command. .TP Each color scheme may include any (or all) of the below options: .TP \fBFiletypeColors\fR = Colors for different file types, such as directory, regular files, and so on. See the \fBCOLORS\fR section below. .TP \fBInterfaceColors\fR = Colors for \fBclifm\fR's interface, such as ELNs, file properties bits, suggestions, syntax highlighting, etc. See the \fBCOLORS\fR section below. .TP \fBExtColors\fR = Colors for files based on filename extensions. See the \fBCOLORS\fR section below. .TP \fBDateShades\fR = A comma delimited list of colors used to print timestamps (long view). Consult the default color scheme file for more information. .TP \fBSizeShades\fR = A comma delimited list of colors used to print file sizes (long view). Consult the default color scheme file for more information. .TP \fBDirIconColor\fR = Color for the directory icon (when icons are enabled). See the \fBCOLORS\fR section below. Only when using icons\-in\-terminal or Nerfonts. If using rather emoji\-icons (default build), this option is ignored. .TP \fBPrompt\fR = Define \fBclifm\fR\'s prompt. See the \fBTHE PROMPT\fR section below. .TP \fBDividingLine\fR = The line dividing the current list of files and the prompt. See the \fBTHE DIVIDING LINE\fR below. .TP \fBFzfTabOptions\fR = Options to be passed to fzf when using the fzf mode for tab completion, including colors. See the \fBTAB COMPLETION\fR section below. .TP The color scheme (or just theme) can be set either via the command line (\fB\-\-color\-scheme=NAME\fR), via the \fBColorScheme\fR option in the main configuration file, or using the \fBcs\fR command, for instance, `\fBcs mytheme\fR`. Enter just `\fBcs\fR` to list available color schemes (tab completion is available). To edit the current color scheme enter `\fBcs edit\fR`. .TP .B 1. COLORS .TP If 256 colors support is detected for the current terminal, and not set in any other way (either via the \fBColorScheme\fR option in the configuration file or the \fB\-\-color\-scheme\fR command line switch), \fBclifm\fR will attempt to load the 256 colors version of the default color scheme: default\-256. Otherwise, it falls back to the 16 colors version. .TP All color codes are specified in the corresponding color scheme file (by default \fI~/.config/clifm/colors/default.clifm\fR). You can edit this file pressing \fBF8\fR or entering `\fBcs edit\fR`. .TP \fBa. Color codes\fR .TP Colors are specified using the same format used by \fBdircolors\fR(1) and the \fBLS_COLORS\fR environment variable, namely, a colon separated list of codes with this general format: \fINAME=VALUE\fR, where \fINAME\fR refers to an interface element, and \fIVALUE\fR to the color to be used by this element. .TP This is the list of \fBfile type codes\fR (you will find them in the \fBFiletypeColors\fR section of the current color scheme file): .sp di = directory ed = empty directory nd = directory with no read/exec permission \fB(1)\fR fi = regular file ef = empty regular file nf = file with no read permission \fB(1)\fR ln = symlink mh = multi\-hardlink file or = orphaned or broken symlink bd = block device cd = character device pi = FIFO, pipe so = socket su = SUID file sg = SGID file tw = sticky and other writable directory st = sticky and not other writable directory ow = other writable directory ex = executable file ee = empty executable file ca = file with capabilities oo = door/port (Solaris only) no = unknown file type uf = inaccessible files (\fBfstatat\fR(3) error) .sp \fB(1)\fR If unset, the corresponding file type color is used and an exclamation mark is printed before the filename in the file list (provided icons are disabled -otherwise the lock icon is used- and \fBclifm\fR is not running in light mode -in light mode access checks are not performed). The color used for the exclamation mark is \fBxf\fR (see below). .TP The following codes are used for different interface elements (in the \fBInterfaceColors\fR section of the current color scheme file): .sp \fBSuggestions\fR sb = shell builtins sc = aliases and shell command names sd = internal commands description sf = ELNs, bookmarks, tag, and filenames sh = commands history entries sx = suggestions for \fBclifm\fR's internal commands and parameters sp = suggestions pointer (e.g.: 56 > filename, where '>' is the suggestion pointer) sz = filenames (fuzzy) \fBSyntax highlighting\fR hb = brackets \'()[]{}\' hc = comments (lines starting with '#') hd = slashes he = expansion chars \'~*\' hn = numbers hp = option parameters (starting with \'\-\') hq = quoted strings (both single and double quotes) hr = process redirection (>) hs = process separators (; & |) hv = variable names (starting with \'$\') hw = Backslash (aka whack) \fBPrompt elements\fR li = selected files ti = trash indicator ac = autocommand indicator em = error message indicator wm = warning message indicator nm = notice message indicator ro = read-only mode indicator si = stealth mode indicator tx = command line text (regular prompt) \fBFile properties\fR db = file allocated blocks dd = last access/change/modification time \fB(1)\fR de = file inode number (long view only) dg = group ID (provided the user has access to the file) dk = number of links (long view only) dn = dash (unset property) do = octal value for file properties dp = SUID, SGID, sticky bit dr = read permission bit dt = timestamp identification mark \fB(2)\fR du = user ID (provided the user has access to the file) dw = write permission bit dxd = executable permission bit (directories) dxr = executable permission bit (regular files) dz = size \fB(1)\fR .sp \fB(1)\fR If unset (default), gradient colors are used (based on file size and file age). .sp 0 \fB(2)\fR If unset (default), a dimmed version of the current timestamp color is used. .sp \fBNote\fR: For a better graphical representation of file properties, 256 colors are used if possible (otherwise, \fBclifm\fR falls back to 16 colors). .sp \fBMiscellaneous interface elements\fR fc = file counter df = default color dl = dividing line el = ELN color lc = symbolic link indicator (\fBColorLinksAsTarget\fR only) mi = misc indicators (disk usage, sort method, bulk rename, jump database list) ts = matching suffix for possible tab completed entries tt = tilde for truncated filenames wc = welcome message wsN = color for workspace N (1\-8) xs = exit code: success xf = exit code: failure .TP \fBb. Supported colors\fR .TP 4-bit, 8-bit (256-colors), and 24-bit (true colors) colors are supported. .TP Colors are defined basically as SGR sequences (excluding the initial escape character and the ending 'm'), the same sequences used by the \fBLS_COLORS\fR environment variable. However, shortcuts for 8-bit (256-colors) and 24-bit (true color) colors are available. For example: .sp 31 4-bit 38;5;160 8-bit @160 8-bit (short) 38;2;255;0;0 24-bit #ff0000 24-bit (short, HEX) \fB(1)\fR .TP \fB(1)\fR Both three and six digits hexadecimal colors (lower or uppercase) are supported. For example, \fB#f00\fR amounts to \fB#ff0000\fR. .TP A \fBsingle\fR attribute can be added to hex colors and 256 colors (in the form @NUM) using a dash and an attribute number (#RRGGBB-[1-9] or @NUM-[1-9]), where 1-9 is: .sp 1: Bold or increased intensity 2: Faint, decreased intensity or dim 3: Italic (Not widely supported) 4: Underline 5: Slow blink 6: Rapid blink 7: Reverse video or invert 8: Conceal or hide (Not widely supported) 9: Crossed\-out or strike .TP \fBNote\fR: Some attributes may not be supported by all terminal emulators. .TP For example, for bold red the hex code is \fB#ff0000\-1\fR, while the 256-colors code is \fB\@160\-1\fR. (for more information about SGR sequences consult \fIhttps://en.wikipedia.org/wiki/ANSI_escape_code\fR). .TP \fBc. Color names\fR .TP \fBXterm\-like color names\fR are also supported. For example: \fBex=DodgerBlue2\fR. .TP This is the list of color names (as defined by \fBvifm\fR(1)): .sp 0 Black 86 Aquamarine1 172 Orange3 1 Red 87 DarkSlateGray2 173 LightSalmon3_2 2 Green 88 DarkRed_2 174 LightPink3 3 Yellow 89 DeepPink4_2 175 Pink3 4 Blue 90 DarkMagenta 176 Plum3 5 Magenta 91 DarkMagenta_2 177 Violet 6 Cyan 92 DarkViolet 178 Gold3_2 7 White 93 Purple 179 LightGoldenrod3 8 LightBlack 94 Orange4_2 180 Tan 9 LightRed 95 LightPink4 181 MistyRose3 10 LightGreen 96 Plum4 182 Thistle3 11 LightYellow 97 MediumPurple3 183 Plum2 12 LightBlue 98 MediumPurple3_2 184 Yellow3_2 13 LightMagenta 99 SlateBlue1 185 Khaki3 14 LightCyan 100 Yellow4 186 LightGoldenrod2 15 LightWhite 101 Wheat4 187 LightYellow3 16 Grey0 102 Grey53 188 Grey84 17 NavyBlue 103 LightSlateGrey 189 LightSteelBlue1 18 DarkBlue 104 MediumPurple 190 Yellow2 19 Blue3 105 LightSlateBlue 191 DarkOliveGreen1 20 Blue3_2 106 Yellow4_2 192 DarkOliveGreen1_2 21 Blue1 107 DarkOliveGreen3 193 DarkSeaGreen1_2 22 DarkGreen 108 DarkSeaGreen 194 Honeydew2 23 DeepSkyBlue4 109 LightSkyBlue3 195 LightCyan1 24 DeepSkyBlue4_2 110 LightSkyBlue3_2 196 Red1 25 DeepSkyBlue4_3 111 SkyBlue2 197 DeepPink2 26 DodgerBlue3 112 Chartreuse2_2 198 DeepPink1 27 DodgerBlue2 113 DarkOliveGreen3_2 199 DeepPink1_2 28 Green4 114 PaleGreen3_2 200 Magenta2_2 29 SpringGreen4 115 DarkSeaGreen3 201 Magenta1 30 Turquoise4 116 DarkSlateGray3 202 OrangeRed1 31 DeepSkyBlue3 117 SkyBlue1 203 IndianRed1 32 DeepSkyBlue3_2 118 Chartreuse1 204 IndianRed1_2 33 DodgerBlue1 119 LightGreen_2 205 HotPink 34 Green3 120 LightGreen_3 206 HotPink_2 35 SpringGreen3 121 PaleGreen1 207 MediumOrchid1_2 36 DarkCyan 122 Aquamarine1_2 208 DarkOrange 37 LightSeaGreen 123 DarkSlateGray1 209 Salmon1 38 DeepSkyBlue2 124 Red3 210 LightCoral 39 DeepSkyBlue1 125 DeepPink4_3 211 PaleVioletRed1 40 Green3_2 126 MediumVioletRed 212 Orchid2 41 SpringGreen3_2 127 Magenta3 213 Orchid1 42 SpringGreen2 128 DarkViolet_2 214 Orange1 43 Cyan3 129 Purple_2 215 SandyBrown 44 DarkTurquoise 130 DarkOrange3 216 LightSalmon1 45 Turquoise2 131 IndianRed 217 LightPink1 46 Green1 132 HotPink3 218 Pink1 47 SpringGreen2_2 133 MediumOrchid3 219 Plum1 48 SpringGreen1 134 MediumOrchid 220 Gold1 49 MediumSpringGreen 135 MediumPurple2 221 LightGoldenrod2_2 50 Cyan2 136 DarkGoldenrod 222 LightGoldenrod2_3 51 Cyan1 137 LightSalmon3 223 NavajoWhite1 52 DarkRed 138 RosyBrown 224 MistyRose1 53 DeepPink4 139 Grey63 225 Thistle1 54 Purple4 140 MediumPurple2_2 226 Yellow1 55 Purple4_2 141 MediumPurple1 227 LightGoldenrod1 56 Purple3 142 Gold3 228 Khaki1 57 BlueViolet 143 DarkKhaki 229 Wheat1 58 Orange4 144 NavajoWhite3 230 Cornsilk1 59 Grey37 145 Grey69 231 Grey100 60 MediumPurple4 146 LightSteelBlue3 232 Grey3 61 SlateBlue3 147 LightSteelBlue 233 Grey7 62 SlateBlue3_2 148 Yellow3 234 Grey11 63 RoyalBlue1 149 DarkOliveGreen3_3 235 Grey15 64 Chartreuse4 150 DarkSeaGreen3_2 236 Grey19 65 DarkSeaGreen4 151 DarkSeaGreen2 237 Grey23 66 PaleTurquoise4 152 LightCyan3 238 Grey27 67 SteelBlue 153 LightSkyBlue1 239 Grey30 68 SteelBlue3 154 GreenYellow 240 Grey35 69 CornflowerBlue 155 DarkOliveGreen2 241 Grey39 70 Chartreuse3 156 PaleGreen1_2 242 Grey42 71 DarkSeaGreen4_2 157 DarkSeaGreen2_2 243 Grey46 72 CadetBlue 158 DarkSeaGreen1 244 Grey50 73 CadetBlue_2 159 PaleTurquoise1 245 Grey54 74 SkyBlue3 160 Red3_2 246 Grey58 75 SteelBlue1 161 DeepPink3 247 Grey62 76 Chartreuse3_2 162 DeepPink3_2 248 Grey66 77 PaleGreen3 163 Magenta3_2 249 Grey70 78 SeaGreen3 164 Magenta3_3 250 Grey74 79 Aquamarine3 165 Magenta2 251 Grey78 80 MediumTurquoise 166 DarkOrange3_2 252 Grey82 81 SteelBlue1_2 167 IndianRed_2 253 Grey85 82 Chartreuse2 168 HotPink3_2 254 Grey89 83 SeaGreen2 169 HotPink2 255 Grey93 84 SeaGreen1 170 Orchid 85 SeaGreen1_2 171 MediumOrchid1 .TP Just as with hex colors, a single attribute can be appended to color names. For example, \fBSteelBlue1\-1\fR to get the bold version of this color. .TP \fBd. Color variables\fR .TP Up to 128 custom color variables can be used via the \fBdefine\fR keyword to make it easier to build and read theme files. Example: \fBdefine FTYPE_DIR=31\fR \fBdefine IFACE_ELN=4;38;2;255;255;0;48;2;0;14;191\fR \fBFiletpeColors="di=FTPYE_DIR:"\fR \fBInterfaceColors="el=IFACE_ELN:"\fR .TP These variables can only be used for \fBFiletypeColors\fR, \fBInterfaceColors\fR, \fBExtColors\fR, and \fBDirIconColor\fR. The \fBPrompt\fR line (if using a prompt code) uses full SGR sequences or prompt\-specific color codes instead. .TP \fBe. Examples\fR .TP A few examples to put all this together: \fBfi=4;31\fR (regular files are 4-bit underlined red) \fBdi=@33-1\fR (directories are 8-bit bold light-blue) \fBln=#5fd7ff\fR (symbolic links are 24-bit light cyan) \fBso=Yellow3\fR (socket files are Yellow3) .TP More complex combinations can be achieved using complete SGR sequences (for example, to add a background color). E.g.: \fBfi=4;38;2;245;76;48;2;0;0;255\fR .TP will print regular files underlined and using a bold orange color on a blue background. In this case, just make sure to use a terminal emulator supporting true colors. To test your terminal color capabilities use the \fIcolors.sh\fR script (in the plugins directory). .TP \fBNote\fR: It may happen that, for some reason, you need to force \fBclifm\fR to use colors despite the value of the \fBTERM\fR variable. The OpenBSD console, for example, sets \fBTERM\fR to vt220 by default, which, according to the terminfo database, does not support color. However, the OpenBSD console does actually support color. In this case, you can set the \fBCLIFM_FORCE_COLOR\fR a specific value even if the value of \fBTERM\fR says otherwise. Supported values are: 8, 16, 256, truecolor (or 24bit). .TP To see a colored list of the currently used colors run the `\fBcs preview\fR` command. .TP To run without colors use the \fB\-\-no\-color\fR command line option or set either \fBCLIFM_NO_COLOR\fR or \fBNO_COLOR\fR environment variables to any value. For more information about the no\-color initiative see \fIhttps://no\-color.org/\fR .TP For a full no\-color experience recall to edit your prompt removing all color codes. .TP .B 2. THE PROMPT .TP \fB2.a. Description\fR .TP \fBClifm\fR's prompt is taken from the \fBPrompt\fR line in the color scheme file using a prompt name as defined in the prompts file, for example, Prompt="security\-scanner". .TP Each prompt is built following almost the same escape codes and rules used by the Bash prompt, except that it does not accept shell functions (like conditionals and loops). Command substitution (in the form \fB$(cmd)\fR), prompt modules (in the form \fB${module}\fR), color codes (in the form \fB%{color}\fR), string literals, and escape sequences can be used to build the prompt. .TP Consult the prompts file (using the `\fBprompt edit\fR` command) for detailed information and examples on how to build a prompt. .TP By default, for intstance, \fBclifm\fR's prompt line is this: \fB"%{reset}\\I[\\S%{reset}]\\l \\A \\u:\\H %{cyan}\\w%{reset}\\n<\\z%{reset}> %{blue}\\$%{reset} "\fR .TP which once decoded should look something like this: \fB[1] 13:45 user:hostname /my/path <0> $\fR .TP with the workspace number printed in blue, the path in cyan, the last exit status in green (or red in case of error), and the dollar sign in blue. .TP A more "classic" prompt can be generated as follows: \fB"\\u@\\U \\w> "\fR .TP or, using now command substitution: \fB"$(whoami)@$(hostname) $(pwd)> "\fR .TP \fB2.b. Prompt notifications\fR .TP A bold red \'R\' at the left of the prompt reminds the user that the program is running as root. A bold green \'S\' indicates that there are elements in the Selection Box. In the same way, a cyan \'T\' means that there are currently files in the trash can, just as a bold blue \'S\' means that the program is running in stealth mode. Finally, \fBclifm\fR makes use of three kind of messages: errors (a red \'E\' at the left of the prompt), warnings (a yellow \'W\'), and simple notices (a green \'N\'). .TP If \fBNotifications\fR is set to \fBfalse\fR in the prompts file, the above notifications won\'t be printed by the prompt, but are still available to the user as escape codes (see above) and environment variables (see the \fBENVIRONMENT\fR section below) to build custom prompts. .TP \fB2.c. The Warning Prompt\fR .TP The suggestions system includes a secondary, warning prompt, used to highlight wrong/invalid/non\-existent command names. Once an invalid command is entered, the regular prompt will be switched to the warning prompt. .TP The wrong command name check is omitted if the input string: Is quoted (e.g.: "string" or \'string\') Is bracketed (e.g.: (string), [string], or {string}) It starts with a stream redirection character (e.g.: string) Is a comment (e.g.: #string) It starts with one or more spaces Is an assignment (e.g.: foo=var) It is escaped (e.g.: \\string) .TP The warning prompt can be customized by means of the same rules used by the regular prompt. To use a custom warning prompt, modify the \fBWarningPrompt\fR line in the prompts file (via the `\fBprompt edit\fR` command). It defaults to \fB"%{reset}%{b:red}(!)%{n:dim} > "\fR .TP the last line of the regular prompt will become "\fB(!) > \fR", with "(!)" printed in bold red. .TP To disable this feature use the \fB\-\-no\-warning\-prompt\fR command line switch or set the \fBEnableWarningPrompt\fR option to \fBfalse\fR in the prompts file. .TP \fBNote\fR: Bear in mind that the warning prompt depends on the suggestions system, so that it will not be available if this system is disabled. .TP \fB2.d. The Right Prompt\fR .TP The right prompt is just like the regular prompt, but printed on the right side of the screen. .TP Use the \fBRightPrompt\fR option in the prompts file to set a right prompt. For a concrete usage example see the \fBinfo\fR prompt in the prompts file. .TP A few caveats: \fBa\fR. Right prompts only work with multiline regular prompts (in the case of a single line regular prompt, the right prompt is not printed). \fBb\fR. Multiple lines are not supported by right prompts (only the first line will be printed). \fBc\fR. If the decoded right prompt exceeds the number of available terminal columns, the prompt is not printed. .TP \fB3. THE DIVIDING LINE\fR .TP The line dividing the current list of files and the prompt. It can be customized using the \fBDividingLine\fR option in the color scheme file to fit your prompt design and/or color scheme. .TP \fBDividingLine\fR accepts one or more ASCII or Unicode characters (in both cases you only need to type/paste here the chosen character(s)). If only one character is specified (by default, "\-"), it will be repeatedly printed to fulfill the current line up to the right edge of the screen or terminal window. If you don't want to cover the whole line, specify two or more characters, in which case only these characters (and no more) will be used as dividing line. For example: "\-\-\-\-\-\-\->". To use an empty line, set \fBDividingLineChar\fR to "0" (that is, as a character, not as a number). Finally, if this value is not set, a special line drawn with box\-drawing characters will be used (box\-drawing characters are not supported by all terminal emulators). .TP The color of this line is set via the \fBdl\fR color code in the color scheme file. Consult the \fBCOLOR CODE\fR section above for more information. .TP \fB4. FZF WINDOW\fR .TP Refer to the \fBTAB COMPLETION\fR section below. .SH 8. BUILT\-IN EXPANSIONS .TP \fB1. ELNs\fR .sp A number representing the \fBEntry List Number\fR (ELN) of a listed file is expanded to its corresponding filename. You can type `\fBELN\fR` to convert the ELN into the filename. ELN ranges are also supported. For example, `\fBt 1-3 10 24\fR` will move the files with ELNs 1 through 3, 10 and 24 to the trash. .sp Bear in mind that ELNs will only be expanded provided some filename is listed on the screen under the corresponding numbers. For example: `\fBdiff 1 118\fR` will only expand '1', but not '118', if there is no ELN 118. In the same way, the range 1\-118 will only be expanded provided there are 118 or more filenames listed on the screen. Note that the second field of a range can be omitted, in which case the ELN of the last listed file is assumed (e.g.: provided there are 100 listed files, 12\- is equivalent to 12\-100). .sp Since ranges can be a bit tricky, tab completion is available to make sure this range actually includes the desired filenames. .sp If this feature somehow conflicts with the command you want to run, say, `\fBchmod 644 ...\fR`, because the current number of files is equal or larger than 644 (in which case \fBclifm\fR will expand that number), then you can simply run the command as external: `\fB;chmod 644 ...\fR` .TP \fB2. Selected files\fR .sp The \fBs:\fR prefix expands to all \fBselected files\fR (as absolute paths). To get the list of selected files type `\fBs:`. The \fBsel\fR keyword can be used as well, but, unlike \fBs:\fR, it can only be used after the first word, i.e., as a command parameter. For example, `\fBm sel\fR` (or `\fBm s:\fR`) will move all selected files to the current directory. To trash or remove selected files, simply run `\fBt sel\fR` or `\fBr sel\fR` respectively. .TP \fB3. Bookmarks\fR .sp The \fBb:\fR prefix expands to all \fBbookmarked files\fR (as absolute paths). Enter `\fBb:\fR` followed by a bookmark name to expand to the absolute path referred to by that bookmark. To get the list of available bookmarks, type `\fBb:\fR`. For example, `\fBp b:work\fR` will print the file properties of the bookmark named \fIwork\fR. .TP \fB4. Tagged files\fR .sp The \fBt:\fR prefix is used to access \fBtagged files\fR. Type `\fBt:\fR` to get the list of available tags. Type `\fBt:TAG\fR` to get the list of files tagged as TAG. \fIt:TAG\fR expands to all files tagged as TAG (as absolute paths). For example, `\fBs t:old\fR` will select all files tagged as "old". .TP \fB5. Workspaces\fR .sp The \fBw:\fR prefix expands to a specific \fBworkspace\fR (as absolute path). For example, `\fBc sel w:3\fR` will copy all selected files to the third workspace. .TP \fB6. File types\fR .sp The \fB=\fR (equal) prefix is used to filter files according to their \fBtype\fR. Type `\fB=\fR` to get the list of available file types in the current directory. Also, type `\fB=x\fR` to get the list of executable files in the current directory. For example, `\fBr =D =F =L\fR` will remove all empty directories, empty regular files, and broken symbolic links in the current directory. .TP \fB7. MIME types\fR .sp The \fB@\fR (at sign) prefix is used to filter files according to their \fBMIME type\fR. Type `\fB@\fR` to get the list of MIME types available in the current directory. For example, `\fBbr @image\fR` will bulk rename all files in the current directory whose MIME type includes the word "image". .TP \fB8. Pinned directory\fR .sp A single comma (,) expands to the currently \fBpinned directory\fR (see the \fBpin\fR command for more information). For example, the command `\fBc =o ,\fR` will copy all other-writable files in the current directory to the pinned directory. .TP \fB9. Parent directories\fR .sp Via the \fIfastback\fR function, you can quickly change to any parent directory using a series of dots. A single dot (.) refers to the current directory, and two dots (..) refer to the parent directory. This pattern continues, so three dots (...) refer to the parent of the parent directory, four dots (....) refer to the parent of the parent of the parent directory, and so on. In general, n dots refer to the nth level of parent directories. .TP Needless to say, combinations are possible. For example, the command `\fBc sel b:work @image =L 1-3 ,\fR` will copy all selected files, the bookmark named \fIwork\fR, all images, broken symbolic links in the current directory, and files with ELNs 1 through 3 to the pinned directory. .TP \fBNote\fR: If using the fzf mode for Tab completion (default), you can operate on \fIsome\fR files of any of these groups of files using the TAB key to mark files in the list. For example, you can type `\fBCMD sel\fR` to get the list of selected files, then use the TAB key to mark the desired files. Press \fBEnter\fR or \fBRight\fR to insert the marked files into the current command line. .SH \fB9. TAB COMPLETION\fR .TP There are four modes for tab completion: \fBstandard\fR (interface provided by readline), \fBfzf\fR, which depends on \fBfzf\fR (\fIhttps://github.com/junegunn/fzf\fR) (version 0.18.0 or later), \fBfnf\fR (\fIhttps://github.com/leo\-arch/fnf\fR), and \fBsmenu\fR (\fIhttps://github.com/p\-gen/smenu\fR). .TP By default, if any of \fBfzf\fR, \fBfnf\fR, or \fBsmenu\fR (in this order) is installed (found in \fB$PATH\fR), \fBclifm\fR will attempt to use the corresponding mode to display completions. You can force the use of a specific mode using the \fB\-\-stdtab\fR, \fB\-\-fzftab\fR, \fB\-\-fnftab\fR, and \fB\-\-smenutab\fR command line switches. The \fBTabCompletionMode\fR option in the configuration file can be used to permanently set the tab completion mode. .TP If using the \fBfzf\fR mode, the completions interface can be customized using the \fBFzfTabOptions\fR option in the color scheme file. \-\-height, \-\-margin, +i/\-i, \-\-read0, \-\-query, and \-\-ansi will be appended to set up some details of the completions interface. Set this value to \fBnone\fR to pass no option, to the empty string to load the default values, or to any other custom value. Unless set to \fBnone\fR, any option specified here will override \fBFZF_DEFAULT_OPTS\fR. .TP Default values for this option are: \-\-color=16,prompt:6,fg+:\-1,pointer:4,hl:5,hl+:5,gutter:\-1,marker:2,border:7:dim \-\-bind tab:accept,right:accept,left:abort,alt-p:toggle\-preview \-\-inline-info \-\-layout=reverse\-list \-\-preview\-window=wrap,border\-left .TP Consult \fBfzf\fR(1) for more information. .TP If set neither in \fBFzfTabOptions\fR nor in \fBFZF_DEFAULT_OPTS\fR (in this order), the height of the fzf window is set to the default value: 40% of the current terminal number of line/rows. .TP To use fzf global values (defined in \fBFZF_DEFAULT_OPTS\fR), set \fBFzfTabOptions\fR to \fBnone\fR. .TP File previews are available in fzf mode via \fBshotgun\fR. See the \fBSHOTGUN\fR section above. .TP Image previews are available via the \fBclifmimg\fR plugin. Run `\fBhelp image\-previews\fR` for more information. .TP If using the \fBsmenu\fR mode, the interface can be customized using the \fBCLIFM_SMENU_OPTIONS\fR environment variable. For example: .sp export CLIFM_SMENU_OPTIONS="\-a t:2,b b:4 c:r ct:2,r sf:6,r st:5,r mt:5,b" .TP Consult \fBsmenu\fR(1) for more information. .TP For information about how to customize \fBfnf\fR consult \fBfnf\fR(1). .TP \fBClifm\fR can perform fuzzy tab completion (just as suggestions) for filenames and paths (e.g. "dwn" is completed/suggested as "Downloads"). To enable this feature use the \fB\-\-fuzzy\-matching\fR command line switch or set \fBFuzzyMatching\fR to \fBtrue\fR in the configuration file. .SH 10. FILE OPENER As \fBclifm\fR\'s builtin file opener, \fBLira\fR takes care of opening files when no opening application has been specified in the command line (or when running as a standalone file opener, via the \fB--open\fR command line switch). It does this by automatically parsing a MIME list file (see the \fBFILES\fR section below): it looks first for a matching pattern (either a MIME type or a filename), then checks the existence of the command associated to this pattern, and finally executes it. .TP \fBLira\fR is controlled using the \fBmime\fR command. File associations are stored in the MIME list file and can be edited using the `\fBmime edit\fR` command. .TP When running for the first time, or whenever the MIME list file cannot be found, \fBclifm\fR will copy the MIME definitions file from the \fBDATADIR\fR directory (usually \fI/usr/share/clifm/mimelist.clifm\fR) to the local configuration directory. .TP \fBLira\fR will check the file line by line, and if a matching line is found, and if at least one of the specified applications exists, this application will be used to open the corresponding associated file. Else, the next line will be checked. In other words, the precedence order is top to bottom (for lines) and left to right (for applications). .TP \fBNote\fR: In case of directories (whose MIME type is \fBinode/directory\fR), the entry will be used \fBonly\fR for the open\-with command (\fBow\fR). .TP \fBA note about MIME types .TP File MIME types are determined using \fBlibmagic\fR –the same library used by \fBfile\fR(1)–, which, though highly reliable, is not bullet-proof. Sometimes it fails, either because the appropriate MIME type is not in its database, or because the database is just wrong. In either case, you can manually map file extensions to MIME types using a specific file (by default, \fI~/.mime.types\fR).\fB(1)\fR .TP By way of example, \fBlibmagic\fR knows nothing about ILBM image files, and returns \fBapplication/zip\fR for OpenRaster images. Create \fI~/.mime.types\fR with the following content: image/x-ilbm iff lbm image/openraster ora .TP Restart \fBclifm\fR and these MIME types will be immediately associated to all files having the specified extensions (to test it, run `\fBmm info\fR` on any of these files).\fB(2)\fR .TP If required, edit the mimelist and the preview files (`\fBmm edit\fR` and `\fBview edit\fR`, to specify how files are opened and previewed respectively), and add a new line handling the corresponding MIME types (say, "image/x-ilbm=APP" and "image/openraster=APP"). See below for more information. .TP \fB(1)\fR To use a different file, set \fB$CLIFM_MIMETYPES_FILE\fR to the desired file, for example, `\fBCLIFM_MIMETYPES_FILE=/etc/mime.types clifm\fR`. .TP \fB(2)\fR In case of issues, bear in mind that the \fImime.types\fR file is read top to bottom, and that, in case of conclicts (mostly duplicate extensions), only the last entry is effective. .TP \fBImportant\fR: Though sometimes convenient, determining file types by means of filename extensions alone is unreliable: a file, no matter its type, can bear any file extension, without restriction. Because of this, you might end up executing a command that was not intended due to wrong file identification. Be extra careful when doing this. .TP \fB1. Syntax\fR .TP In its most basic form, each line in the MIME list file consists of: .TP \fBa)\fR A left value: this is just a regular expression indicating what we are trying to match (it can be a filename, a file extension, or a MIME type). .TP \fBb)\fR A right value: a semicolon separated list of commands to be used as the opening application (the first existing program found in this list will be used). .TP For example: ^text/.*=leafpad .TP which is to be read as follows: Open text files (in this case we are partially matching a MIME type) using \fBleafpad\fR. .TP As explained below, this basic rule can be modified to get much more control on \fBwhat\fR we are matching and \fBhow\fR we execute the opening application. .TP The syntax is this: [!][X:][N:]REGEX=CMD [ARGS] [%[f,x]] [![E,O]] [&]; ... .TP Note that this syntax departs from the Freedesktop specification in that we do not rely on desktop files (mostly used by desktop environments), but rather on \fBcommands and parameters\fR. .TP \fB2. The left value (REGEX)\fR .TP \fB2.1. The X prefix\fR .TP Without any prefixes, the rule will attempt to match MIME types, disregarding if we are running on a graphical or non-graphical environment. For example, \fB^text/.*=leafpad\fR .TP instructs \fBlira\fR to open all text files using \fBleafpad\fR, no matter if we are running on a graphical or non-graphical environment. .TP However, we usually do not want to use \fBleafpad\fR if we are not running on a graphical environment. In this case, we can write a double rule as follows: \fBX:^text/.*=leafpad !X:^text/.*=nano\fR .TP where the first rule (via the \fBX\fR prefix) is intended for use on graphical environments, where we can use \fBleafpad\fR, and the second one (via the \fB!X\fR prefix) for non-graphical environments, where we rather prefer to use \fBnano\fR. .TP \fB2.2. The N prefix\fR .TP Sometimes MIME types are not enough to identify a file, or we just want to match a specific filename. In this case, we can use the \fBN\fR prefix to tell \fBLira\fR that we want to match a filename instead of a MIME type. For example: \fBX:N:^filename.txt$=leafpad\fR .TP in which case we want to match exactly the filename \fIfilename.txt\fR (no matter its MIME type). .TP If we want to match file extensions, instead of entire filenames, we can use a regular expression, as follows: \fBX:N:.*\.txt$=leafpad\fR .TP Here, we are not matching a specific filename, but a specific file extension, so that the rule reads as follows: open all files ending with .txt using \fBleafpad\fR. .TP \fB3. The right value (CMD)\fR .TP The right value is a semicolon separated list of commands, each of which contains a command, and optionally, command arguments and modifiers. For example: \fBX:N:.*\.txt$=leafpad --sync,geany,mousepad,nano\fR .TP which means: Open .txt files (graphical environments only) using `\fBleafpad --sync\fR`, or, if not found, \fBgeany\fR`, \fBmousepad\fR, or \fBnano\fR, in this order. The file to be opened will be appended to the command string, say `\fBleafpad --sync FILE\fR`. .TP \fB3.1. The %f placeholder\fR .TP Use the \fB%f\fR placeholder to specify the position of the file to be opened in the command, for example: \fBmpv %f --terminal=no\fR .TP will be translated into: `\fBmpv FILE --terminal=no\fR` .TP If the placeholder is not specified, the file to be opened will be appended to the command string. Thus, this: `\fBmpv --terminal=no\fR` amounts to this: `\fBmpv --terminal=no FILE\fR`. .TP \fB3.2. STDERR and STDOUT\fR .TP Sometimes we might need to silence either standard error (STDERR), standard output (STDOUT), or both. Use \fB!E\fR and \fB!O\fR to silence them respectively. Both can be used together: \fB!EO\fR. Example: `\fBleafpad %f !EO\fR`, or, to silence only STDERR: `\fBleafpad %f !E\fR`. .TP \fB3.3. Run in the background\fR .TP The ampersand character (\fB&\fR) can be used, as usual, to run the opening application in the background. Example: `\fBleafpad %f &\fR`. .TP \fB3.4. The %x flag\fR .TP The \fB%x\fR flag is a shortcut for "\fB%f !EO &\fR": the command will be executed in the background and both STDOUT and STDERR will be silenced. As a plus, the command is executed in a new session, i.e. detached from the running terminal (via \fBsetsid\fR(3). This flag is recommended to open files via graphical applications. Examples: .TP For GUI applications: \fBAPP %x\fR .TP For terminal applications: \fBTERM -e APP %x\fR .TP Replace \fITERM\fR and \fIAPP\fR by the appropriate values (say, xterm and vi respectively). The \fB\-e\fR option might vary depending on the terminal emulator used. .TP \fBNote\fR: In case of archives, the builtin \fBad\fR command can be used as opening application. .TP \fB3.5. Environment variables\fR .TP Environment variables (e.g. \fB$EDITOR\fR, \fB$VISUAL\fR, \fB$BROWSER\fR, and even \fB$PAGER\fR) are also recognized by \fBLira\fR. You can even set custom environment variables to be used exclusively by \fBclifm\fR. For example, you can set \fBCLIFM_TERM\fR, \fBCLIFM_EDITOR\fR, and \fBCLIFM_PDF\fR, and then use them to define some associations: \fBX:text/plain=$CLIFM_TERM \-e $CLIFM_EDITOR %f &\fR \fBX:N:.*\\.pdf$=$CLIFM_PDF %f &\fR .TP \fB3.6. Using shell scripts\fR Bear in mind that commands will be executed directly without shell intervention, so that no shell goodies (like pipes, conditions, loops, etc) are available. In case you need something more complex than a single command (including shell capabilities) write your own script and place the path to the script in place of the command. For example: \fBX:^text/.*:~/scripts/my_cool_script.sh\fR .TP \fB4. Examples\fR: .TP Match a complete filename: \fBX:N:some_filename=nano;vim;vi;emacs\fR .TP \fBNote\fR: If the filename contains a dot, quote it like this: some_filename\\.ext (to prevent the REGEX parser from interpreting the dot). .TP Open video files with \fBmpv\fR in the foreground and silence STDERR: \fB^video/.*=mpv %f !E\fR .TP Open video files with \fBgmplayer\fR in the background and silence both STDERR and STDOUT: \fB^video/.*=gmplayer %f !EO & (or 'gmplayer %x')\fR .TP Match multiple filenames (starting with "str"): \fBX:N:^str.*=leafpad %x;mousepad %x;kate %x;gedit %x\fR .TP Match a single extension: \fBX:N:.*\\.txt$=leafpad %x;mousepad %x;kate %x;gedit %x\fR \fB!X:N:.*\\.^txt$=nano;vim;vi;emacs\fR .TP Match multiple extensions: \fBX:N:.*\\.(sh|c|py|pl)$:geany %x;leafpad %x;nano\fR .TP Match a single mimetype: \fB!X:^audio/mp3$=mpv %f \-\-terminal=no;ffplay \-nodisp \-autoexit;mpv;mplayer\fR .TP Match multiple mimetypes: \fBX:^audio/.*=mplayer;mplayer2;vlc %x;gmplayer %x;smplayer %x;totem %x\fR .TP In case of MIME types, you can also write the entire expression without relying on any regular expression. For example: \fB!X:text/plain=$TERM \-e $EDITOR %x\fR .TP For more information take a look at the mimelist file itself (\fBF6\fR or `\fBmm edit\fR`). .TP \fB5. Using a third\-party opener\fR .TP This can be done in two ways: .TP \fBa.\fR Set \fBOpener\fR in the configuration file to the name of the desired opener. For example, to use Ranger's \fBrifle\fR(1): \fBOpener=rifle\fR .TP or, if you prefer \fBxdg\-open\fR(1): \fBOpener=xdg\-open\fR .TP \fBb.\fR Tell \fBLira\fR to open all files, no matter the MIME type or filename, via the desired opener. For example: \fB.*=rifle\fR .TP \fB6. Using Clifm as a standalone file opener\fR .TP Though \fBclifm\fR is a file manager, it can be used as a simple file opener via the \fB\-\-open\fR command line option. For example: \fBclifm \-\-open /path/to/my_file.jpg clifm \-\-open /path/to/my_dir clifm \-\-open https://some_domain\fR .TP \fBNote\fR: When opening web resources \fBclifm\fR will query the mimelist file using text/html as MIME type. Whatever association it finds for this specific MIME type will be used to open the web resource. .SH 11. SHOTGUN \fB1. Tab completion with file previews\fR .TP \fBShotgun\fR is \fBclifm\fR\'s builtin files previewer. Though, as described below, it may be used as a standalone and general purpose file previewer (similar in this regard to \fBpistol\fR(1)), it is mainly intended to be used by \fBclifm\fR's tab completion function running in fzf mode: every time tab completion is invoked for files, \fBshotgun\fR will be executed with the currently highlighted file as argument (as shown below) to generate the preview. Set the \fBFzfPreview\fR option in the configuration file to \fBfalse\fR (or run with \fB\-\-no\-fzfpreview\fR) to disable this feature. .TP \fBShotgun\fR is also used by the \fIview\fR command to display file previews in full screen. .TP \fB2. Running as a standalone files previewer\fR .TP Executed via the \fB\-\-preview\fR command line switch, \fBshotgun\fR performs file preview for any file passed as argument. For example: \fBclifm \-\-preview myfile.txt\fR .TP This command generates a preview of the file \fImyfile.txt\fR and then quits \fBclifm\fR. .TP \fB3. Customization .TP Previewing applications (based on either MIME type or filename) are defined in a configuration file (\fI$XDG_CONFIG_HOME/clifm/profiles/PROFILE/preview.clifm\fR) using the same syntax used by \fBLira\fR (the builtin file opener). See the \fBFILE OPENER\fR section above. .TP You can set an alternative configuration file using the \fB\-\-shotgun\-file\fR command line switch: \fBclifm \-\-shotgun\-file=/path/to/shotgun/config/file \-\-preview=myfile.txt\fR .TP To customize the appearance of the preview window, use the \fB\-\-preview\-window\fR option in the \fBFzfTabOptions\fR line in the current color scheme file. For example, if you want the preview window down the file list (instead of to the right): \fB\-\-preview\-window=down\fR .TP Default keybindings for the preview window: .sp \fBAlt+p\fR: Toggle the preview window \fBCtrl+Up\fR / \fBShift+Up\fR: Scroll the preview window up one line \fBCtrl+Down\fR / \fBShift+Down\fR: Scroll the preview window down one line \fBAlt+Up\fR: Scroll the preview window up one page \fBAlt+Down\fR: Scroll the preview window down one page .TP Keybindings can be customized using the \fB\-\-bind\fR option in the \fBFzfTabOptions\fR field in the color scheme file. .TP Consult \fBfzf\fR(1) for more information. .TP \fB4. Image previews\fR .TP Image previews are available via the \fBclifmimg\fR plugin. Run `\fBhelp image-previews\fR` or consult the Wiki for more information: \fIhttps://github.com/leo\-arch/clifm/tree/master/misc/tools/imgprev\fR. .SH 12. AUTO\-SUGGESTIONS \fBGemini\fR is a builtin suggestions system (similar to that provided by the Fish shell). As you type, \fBGemini\fR will suggest possible completions right after the current cursor position. The following checks are available (the order can be customized, see below): .sp a. ELNs .sp b. \fBclifm\fR commands and parameters .sp c. Entries in the command history list (already used commands) .sp d. Filenames in the current working directory and paths \fB(1)\fR .sp e. Entries in the jump database .sp f. Aliases names .sp g. Bookmarks names .sp h. Program names in \fBPATH\fR .sp i. Shell builtins \fB(2)\fR \fB(1)\fR Fuzzy suggestions are supported. For example: dwn > Downloads. Enable this feature using the \fB\-\-fuzzy\-marching\fR command line switch or setting \fBFuzzyMatching\fR to \fBtrue\fR in the configuration file. .sp \fB(2)\fR The shell name is taken from \fI/bin/sh\fR. The following shells are supported: bash, dash, fish, ksh, tcsh, and zsh. Command names are checked in the following order: \fBclifm\fR internal commands, commands in \fBPATH\fR, and shell builtins. .sp \fBNote\fR: By default, a brief description for internal commands is suggested. You can disable this feature via the \fBSuggestCmdDesc\fR option in the configuration file. .sp To accept the entire suggestion press Right or \fBCtrl+f\fR: the cursor will move to the end of the suggested command and the suggestion color will change to that of the typed text; next, you can press \fBEnter\fR to execute the command as usual. Otherwise, if the suggestion is not accepted, it will be simply ignored and you can continue editing the current command line however you want. To accept the first suggested word only (up to first slash or space), press rather \fBAlt+Right\fR or \fBAlt+f\fR. Not available for ELNs, aliases and bookmarks names. Bear in mind that suggestions for ELNs, aliases, bookmarks names, the jump function (invoked by the \fIj\fR command), just as filenames and paths (if fuzzy\-suggestions are enabled) do not work as the remaining suggestions: they do not suggest possible completions for the current input, but rather the value pointed to by it. For example, if you type "12" and the current list of files includes a filename whose ELN is '12', the filename corresponding to this ELN will be printed next to "12" as follows: \fB12_ > filename\fR (where the underscore is the current cursor position). Press Right or \fBCtrl+f\fR to accept the suggestion, in which case the text typed so far will be replaced by the suggestion. The order of the suggestion checks can be customized using the \fBSuggestionStrategy\fR option in the configuration file. Each check is assigned a lowercase character: a = Aliases names c = Possible completions e = ELNs f = Files in the current directory h = Entries in the commands history j = Entries in the jump database The value taken by \fBSuggestionStrategy\fR is a string containing one or more of the above characters. The characters order in this string specifies the order in which the suggestion checks will be performed. For example, to perform all checks in the same order above, the value of the string should be \fBacefhj\fR (without quotes). Or, if you prefer to run the history check first: \fBhacefj\fR. Finally, you can ignore one or more checks by just omitting the corresponding character (to skip all checks, set the option value to a single dash (\-)). So, to ignore the aliases and the ELN checks, set \fBSuggestionStrategy\fR to \fBhcfj\fR. The default value for this option is \fBehfjac\fR. \fBNote\fR: The check for program names in \fBPATH\fR is always executed at last, except when the \fBExternalCommands\fR option is disabled, in which case suggestions for them are simply not displayed. Suggestions will be printed using one of the following color codes (see the \fBCOLOR CODES\fR section above): \fBsf\fR: Used for file and directory names. This includes suggestions for ELNs, bookmarks names, files in the current directory, and possible completions. Default value: 2;4;36 (dimmed underlined cyan) \fBsh\fR: Used for entries in the commands history. \fBsc\fR: Used for aliases and program names in \fBPATH\fR. \fBsx\fR: Used for \fBclifm\fR internal commands and parameters. \fBsp\fR: Greater\-than sign (>) used when suggesting ELNs, bookmarks, and aliases names. You can set \fBSuggestFiletypeColor\fR to \fBtrue\fR in the configuration file to use the color of the file type of the current filename (as set in the color scheme file) instead of the value of \fBsf\fR. For example, if a suggestion is printed for a file that is a symbolic link, \fBln\fR or \fBor\fR (if it's a broken link) will be used instead of \fBsf\fR. .SH 13. SHELL FUNCTIONS \fBClifm\fR includes a few shell functions to perform specific actions (cd\-on\-quit, and subshell\-notice). Take a look at the corresponding files, in \fI/usr/share/clifm/functions\fR, and follow the instructions. Needles to say, you can write your own functions. .SH 14. PLUGINS Plugins are just scripts or programs (written in any language) intended to add, extend or improve \fBclifm\fR\'s functionalities. They are linked to actions names defined in a dedicated configuration file (\fI$XDG_CONFIG_HOME/clifm/profiles/PROFILE/actions.clifm\fR). \fBNote\fR: In \fBstealth mode\fR, since access to configuration files is not allowed, plugins are disabled. To list available actions and the plugins they are linked to, run `\fBactions\fR`. To execute a given plugin, enter the corresponding action name (plus parameters if required). To get information about a specific plugin, enter the action name followed by `\fB\-\-help\fR`. Though several plugins are provided at installation time (in the \fIplugins\fR directory), you can write your owns as you like, with any language you like, and for whatever purpose you want. Writing plugins is generally quite easy; but your mileage may vary depending on what you are trying to achieve. A good place to start is examining the provided plugins and reading the \fBactions\fR command description, just as the \fBENVIRONMENT\fR and \fBFILES\fR sections below. A convenient helper script is provided to get a consistent look across all plugins, specially those running fzf. This helper script is located in \fIDATADIR/clifm/plugins/plugins\-helper\fR, but it will be overridden by \fI$XDG_CONFIG_HOME/clifm/plugins/plugins\-helper\fR if found. The location of this file is set by \fBclifm\fR itself in the \fBCLIFM_PLUGINS_HELPER\fR environment variable to be used by plugins. Source the file and use any of the functions and variables provided by it to write a new fzf plugin: # Source our plugins helper if [ \-z "$CLIFM_PLUGINS_HELPER" ] || ! [ \-f "$CLIFM_PLUGINS_HELPER" ]; then printf "\fBclifm\fR: Unable to find plugins\-helper file\\n" >&2 exit 1 fi # shellcheck source=/dev/null . "$CLIFM_PLUGINS_HELPER" Plugins can talk to \fBclifm\fR via a dedicated pipe created for this purpose and exposed via an environment variable (\fBCLIFM_BUS\fR). Write to the pipe and \fBclifm\fR will hear and handle the message immediately after the plugin's execution. If the message is a path, \fBclifm\fR will run the \fBopen\fR function, changing the current directory to the new path, if a directory, or opening it with the default associated application if a file. Otherwise, if the message is not a path, it will be taken and executed as a command. Examples: \'echo "/tmp" > "$CLIFM_BUS"\' tells \fBclifm\fR to change the current directory to \fI/tmp\fR \'echo "s *.png" > "$CLIFM_BUS"\' makes \fBclifm\fR select all files in the current directory ending with ".png" The pipe (\fBCLIFM_BUS\fR) is deleted immediately after the execution of its content and recreated before running any other plugin. .sp This is a list of available plugins: .TS allbox; lb lb lb l l l. Action name Description Dependencies T{ bn T} Create files in batch \- T{ bcp T} Copy files in batch \- T{ bmi T} Import bookmarks \- T{ clip T} Interact with the system clipboard \fB(1)\fR T{ \fIunset\fR T} Test terminal\'s colors capability \fB(2)\fR T{ cr T} Copy files to a remote location fzf, and scp, ffsend, or croc T{ da T} Disk usage analyzer du, fzf T{ dr T} Drag and drop files dragon or dragon\-drag\-and\-drop T{ fdups T} Find/remove file dups \fB(3)\fR T{ + T} Find files in the current directory fzf or rofi T{ _ (underscore) T} Quickly change directory fzf T{ h T} Browse the commands history fzf T{ \- (yes, just a dash) T} Navigate/select/preview files See section below T{ * T} Select files (includes flat view) fzf, find T{ ** T} Deselect files fzf T{ \fIunset\fR T} Show git repo status git \fB(4)\fR T{ ih T} Browse \fBclifm\fR's manpage fzf T{ i T} Image thumbnails previewer sxiv, feh or lsix T{ ++ T} Jump to a directory in the jump database fzf or rofi T{ kd T} Decrypt a GnuPG encrypted file gpg, tar, sed, grep T{ ke T} Encrypt files/dirs using GnuPG gpg, tar, sed, fzf, awk, xargs T{ ml T} List files by a given MIME type fzf, file T{ music T} Create a music playlist mplayer T{ gg T} Pipe files in CWD through a pager less, column T{ ptot T} Preview PDF files as text pdftotext T{ rrm T} Recursively remove files find, fzf T{ // T} Search files by content fzf, ripgrep T{ \fIunset\fR T} Update plugins \fB(5)\fR T{ vid T} Preview video files thumbnails ffmpegthumbnailer T{ vt T} Virtual directory for sets of files sed T{ wall T} Set image as wallpaper \fB(6)\fR T{ \fIunset\fR T} Pick/select files via \fBclifm\fR \fB(7)\fR T{ Ctrl+y T} Copy the line buffer to the clipboard \fB(8)\fR .TE .sp \fB(1)\fR xclip or xsel (Xorg), wl\-copy/wl\-paste (Wayland), clipboard (Haiku), clip (Cygwin), pbcopy/pbget (MacOS), termux\-clipboard\-get/termux\-clipboard\-set (Termux), cb (cross\-platform: \fIhttps://github.com/Slackadays/Clipboard\fR) .sp \fB(2)\fR \fIcolors.sh\fR (by default unset) .sp \fB(3)\fR find, md5sum, sort, uniq, xargs, sed, stat .sp \fB(4)\fR The \fIgit_status.sh\fR plugin is not intended to be used as a normal plugin, that is, executed via an action name, but rather to be executed as a prompt command (it will be executed immediately before each prompt). Add this line to the main configuration file: promptcmd /usr/share/clifm/plugins/git_status.sh .sp Whereas this plugin provides basic Git integration, it could be easily modified (it is just a few lines long) to include whatever git function you might need. .sp \fB(5)\fR \fIupdate.sh\fR (by default unset) .sp \fB(6)\fR feh, xloadimage, hsetroot, or nitrogen (for X); swww or swaybg (for Wayland) .sp \fB(7)\fR \fIfile_picker.sh\fR (by default unset). Usage example: `\fBls -ld $(file_picker.sh)\fR` .sp \fB(8)\fR Dependencies: cb, wl\-copy, xclip, xsel, pbcopy, termux\-clipboard\-set, clipboard, or clip. Consult the plugin file itself (\fIxclip.sh\fR) for more information .B Dependencies of the previewer plugin (fzfnav.sh) \fBarchives\fR: atool, bsdtar, or tar \fBimages\fR: kitty terminal, imagemagick, and ueberzug or viu or catimg or img2txt or pixterm \fBfonts\fR: fontpreview or fontforge \fBdocs\fR: libreoffice, catdoc, odt2txt, pandoc \fBPDF\fR: pdftoppm, pdftotext or mutool \fBepub\fR: epub\-thumbnailer \fBDjVu\fR: djvulibre or djvutxt \fBpostscript\fR: ghostscript \fBvideos\fR: ffmpegthumbnailer \fBaudio\fR: ffmpeg, mplayer, or mpv \fBweb\fR: w3m, links, elinks, or pandoc \fBmarkdown\fR: glow \fBhighlight\fR: bat, highlight, or pygmentize \fBtorrent\fR: transmission\-cli \fBjson\fR: python or pq \fBfile info\fR: exiftool, mediainfo, or file .TP To run the \fIpager.sh\fR plugin, for example, you only need to enter the corresponding action name, in this case \fBgg\fR. In case of need, all plugins provide a \fB\-h,\-\-help\fR switch for a brief usage description. .TP \fBNote\fR: The \fBfzfnav\fR plugin uses \fBfzf\fR(1) to navigate the filesystem and \fIBFG\fR (a script located in the plugins directory) to show previews (to display image previews \fBBFG\fR requires \fBueberzug\fR(1) or the Kitty protocol via the Kitty terminal). A configuration file (\fIBFG.cfg\fR, in the plugins directory itself) is provided to customize the previewer's behavior. .TP \fBNote 2\fR: An alternative files previewing function (builtin, and thereby faster than \fBBFG\fR) is provided by \fBshotgun\fR. See the \fBSHOTGUN\fR section above for more information. .TP In addition to the builtin \fBBFG\fR previewer, \fBfzfnav\fR supports the use of both Ranger\'s \fIscope.sh\fR script and \fBpistol\fR(1). To use \fBscope\fR, edit the \fBBFG\fR configuration file and set \fIUSE_SCOPE\fR to 1 and \fISCOPE_FILE\fR to the correct path to the \fIscope.sh\fR file (normally \fI$HOME/.config/ranger/scope.sh\fR). To use \fBpistol\fR instead, set \fIUSE_PISTOL\fR to 1. .TP .TP Take a look at the Wiki for more information: \fIhttps://github.com/clifm/wiki/Advanced#plugins\fR .SH 15. AUTOCOMMANDS Heavily inspired by \fBVifm\fR, the \fBautocommands\fR function allows the user a fine\-grained control over \fBclifm\fR settings. It is mostly devised as a way to improve performance for remote filesystems (usually slower than local ones) by allowing you to turn off some features (like the file counter) that might greatly affect performance under some circumstances (like remote connections). However, the \fBautocommands\fR function is not restricted to this specific use case: use it for whatever purpose you find useful. .sp \fBNote\fR: We describe here \fBpermanent\fR autocommands, which need to be defined in the configuration file. \fBTemporary\fR autocommands (set via the command line and valid only for the current directory and the current session) are also available via the \fBauto\fR command. See above. .sp Add a line preceded by the \fBautocmd\fR keyword to the main configuration file. The general syntax is: \fIautocmd TARGET cmd,cmd,cmd\fR .sp \fBTARGET\fR specifies the object to which subsequent commands will apply. It can match either \fBdirectory names (paths)\fR or \fBworkspaces\fR. .sp 1. To match directory names use a glob pattern (as specified by \fBglob\fR(7)). If no glob metacharacter is provided, the string will be compared as is to the current working directory. To invert the meaning of a pattern, prepend an exclamation mark. To match all directories under a specific directory (including this directory itself) use the double asterisk (**). A few examples: .sp \fB~/Downloads\fR Match exactly the Downloads directory (and \fBonly\fR this directory) in your home directory \fB~/Downloads/*\fR Recursively match all subdirectories in \fI~/Downloads\fR (\fBexcluding\fR the Downloads directory itself) \fB/~/Downloads/**\fR Recursively match all subdirectories in \fI~/Downloads\fR (\fBincluding\fR the Downloads directory itself) \fB~/Downloads/*.d\fR Match all subdirectories in \fI~/Downloads\fR ending with ".d" (\fBexcluding\fR the Downloads directory itself) \fB!~/Downloads\fR Match everything except the \fI~/Downloads\fR directory .sp 2. You can match workspaces using the ampersand character (\fB@\fR) followed by the \fBws\fR keyword and then the workspace number. For example, to match the third workspace: \fB@ws3\fR, or, to match the first workspace, \fB@ws1\fR. To match instead all workspaces except the second one: \fB!@ws2\fR. .sp \fBTARGET\fR is followed by a comma separated list of commands: .sp \fB!CMD\fR: The exclamation mark allows you to run shell commands, custom binaries or scripts .sp The following codes are used to control \fBclifm\fR's file list: .sp \fBCode Description Example\fR \fBcs\fR Color scheme cs=zenburn \fBfc\fR File counter fc=0 \fBft\fR Files filter ft=.*\\.pdf$ \fBfz\fR Recursive dir sizes fz=1 \fBhf,hh\fR Hidden files hf=0 \fBlm\fR Light mode lm=1 \fBlv,ll\fR Long view lv=0 \fBmf\fR Max files mf=100 \fB(1)\fR \fBmn\fR Max filename length mn=20 \fB(1)\fR \fBod\fR Only directories od=1 \fBpg\fR Pager pg=0 \fBst\fR Sort method st=5 \fBsr\fR Reverse sort sr=1 .sp To remove a value, set the option to an empty value. For example, to remove the files filter and the color scheme: \fBft=,cs=\fR .sp \fB(1)\fR This option supports the \fBunset\fR keyword to remove the corresponding limit. E.g.: \fBmf=unset,mn=unset\fR .sp \fBExamples\fR .sp \fB1.\fR Run in light mode and disable the file counter for the \fIremotes\fR directory:\fB(1)\fR \fBautocmd /media/remotes/** lm=1,fc=0\fR \fB2.\fR Just a friendly reminder: \fBautcomd ~/important !printf "Important: keep your fingers outta here!\\n" && read \-n1\fR \fB3.\fR This directory has thousands of files. Show only the first hundred and enable the pager: \fBautocmd /usr/bin mf=100,pg=1\fR \fB4.\fR Lots of media files (with large filenames). Truncate filenames to 20 chars max and run the files previewer:\fB(2)\fR \fBautocmd ~/Downloads mn=20,!~/.config/clifm/plugins/fzfnav.sh\fR \fB5.\fR I want the second workspace, no matter what the current directory is, to list files in long view: \fBautocmd @ws2 lv=1\fR \fB6.\fR Mmm, just because I can. Be creative! \fBautocmd /home/user hf=0,cs=nord,lv=1 autocmd / lv=1,fc=0,cs=solarized,st=5\fR .sp \fB(1)\fR This is the recommended configuration for remote filesystems. .sp \fB(2)\fR As seen here, plugins can be used as well: in this case, we want to run \fBfzfnav\fR (to make use of the files preview capability) whenever we enter the \fIDownloads\fR directory, usually containing videos, music, and images. \fBNOTE\fR: If you decide to use a plugin, bear in mind that it will not be able to communicate with \fBclifm\fR, because the \fBautocommand\fR function always executes commands as external applications using the system shell. .sp Bear in mind that \fBautocmd\fR directives are evaluated from top to bottom, so that subsequent matching entries will overwrite options set by previous entries. .sp \fBAutocommand notifications\fR .sp By default, a gray 'A' is printed to the left of the prompt whenever an autocommand is active for the current directory. .sp The behavior of this indicator can be customized via the \fBInformAutocmd\fR option in the configuration file. .sp The color code used to colorize this indicator is \fBac\fR (see the \fBCOLORS\fR section above). .sp \fBAutocommand files: \fI.cfm.in\fB and \fI.cfm.out\fR .sp To use this feature, you must first set \fBReadAutocmdFiles\fR to \fBtrue\fR in the main configuration file. However, bear in mind that autocommand files will never be read if running on an untrusted environment (i.e. if running with \fB\-\-secure\-cmds\fR, \fB\-\-secure\-env\fR, or \fB\-\-secure\-env\-full\fR). .sp Two files are specifically checked by the autocommands function: \fI.cfm.in\fR and \fI.cfm.out\fR (they must be non-empty regular files of at most \fBPATH_MAX\fR (usually 4096) bytes, and no NUL byte must be contained in them). .sp The content of these files is a single instruction, either a shell command or, if you need more elaborated stuff, a script (or custom binary). Note that codes to modify \fBclifm\fR's settings (as described above) are not available here. .sp If a directory contains a file named \fI.cfm.in\fR, \fBclifm\fR will execute (via the system shell) its content when \fBentering\fR this directory (before listing files). If the file is named rather \fI.cfm.out\fR, its content will be executed immediately after \fBleaving\fR this directory (and before listing the new directory's content). .sp For example, if you want a simple notification whenever you enter or leave your home directory, create both \fI.cfm.in\fR and \fI.cfm.out\fR files in the home directory with the following content: .sp For \fI.cfm.in\fR: printf "Entering %s ..." "$PWD" && read \-n1 && clear .sp For \fI.cfm.out\fR: printf "Leaving %s ..." "$OLDPWD" && read \-n1 .SH 16. FILE TAGS .sp \fBEtiqueta\fR is \fBclifm\fR's builtin files tagging system .sp \fB1. How does Etiqueta work?\fR .sp File tags are created via symlinks using a specific directory under the user's profile: \fI${XDG_CONFIG_DIR:\-/home/USER/.config}/clifm/profiles/USER/tags\fR .sp Every time a new tag is created, a new directory named as the tag itself is created in the tags directory. Tagged files are just symbolic links to the actual files created in the appropriate directory. For example, if you tag \fI~/myfile.txt\fR as \fBwork\fR, a symbolic link to \fI~/myfile.txt\fR, named \fImyfile.txt\fR will be created in \fItags/work\fR. .sp \fB2. Handling file tags\fR .sp \fBtag\fR is the main \fBEtiqueta\fR command and is used to handle file tags. Its syntax is as follows: tag [add, del, list, list\-full, new, merge, rename, untag] [FILE]... [[:]TAG] \fBNote\fR: The \fB:TAG\fR notation is used for commands taking both file and tag names: `\fBtag add FILES(s) :TAG ...`, to tag files, and `\fBtag untag :TAG file1 file2\fR`, to untag files. Otherwise, \fITAG\fR is used (without the leading colon). For example: `\fBtag new docs\fR`, to create a new tag named \fBdocs\fR, or `\fBtag del png\fR`, to delete the tag named \fBpng\fR. .sp Both short and long command format can be used: .sp .TS allbox; lb lb lb l l l. Short format Long format Description T{ ta T} tag add Tag files T{ td T} tag del Delete tag(s) T{ tl T} tag list List tags or tagged files T{ tm T} tag rename Rename tags T{ tn T} tag new Create new tag(s) T{ tu T} tag untag Untag file(s) T{ ty T} tag merge Merge two tags .TE .sp \fB3. Usage examples\fR .sp .TS allbox; lb lb lb l l l. Short format Long format Description T{ tl T} tag list List available tags T{ \- T} tag list\-full List available tags and all tagged files T{ tl work T} tag list work List all files tagged as \fIwork\fR T{ tl file.txt T} tag list file.txt List tags applied to the file \fIfile.txt\fR T{ tn dogs cats T} tag new dogs cats Create two empty tags: \fIdogs\fR and \fIcats\fR T{ ta *.png :images :png T} tag add *.png :images :png Tag PNG files as both \fIimages\fR and \fIpng\fR \fB(1) (2)\fR T{ ta sel :special T} tag add sel :special Tag all selected files as \fIspecial\fR T{ tr documents docs T} tag rename documents docs Rename the tag \fIdocuments\fR as \fIdocs\fR T{ ty png images T} tag merge png images Merge the tag \fIpng\fR into \fIimages\fR \fB(3)\fR T{ td images T} tag del images Remove the tag \fIimages\fR \fB(4)\fR T{ tu :work file1 dir2 T} tag untag :work file1 dir2 Untag a few files from \fIwork\fR \fB(5)\fR .TE .sp \fB(1)\fR Tags are created if they do not exist .sp 0 \fB(2)\fR Since \fIadd\fR is the default action, it can be omitted: `\fBtag *.png :images :png\fR`. .sp 0 \fB(3)\fR All files tagged as \fBpng\fR will be now tagged as \fBimages\fR, and the \fBpng\fR tag will be removed. .sp 0 \fB(4)\fR Untag all files tagged as \fBimages\fR and remove the tag itself .sp 0 \fB(5)\fR Tab completion is available to complete tagged files. If using the fzf mode, multiple files can be selected using the the TAB key. .sp \fB4. Operating on tagged files\fR .sp The \fBt:TAG\fR expression is used to operate on tagged files via any command, be it internal or external. A few examples: .sp .TS allbox; lb lb l l. Command Description T{ p t:docs T} Print properties of files tagged as \fIdocs\fR T{ r t:images T} Remove all files tagged as \fIimages\fR T{ stat t:docs t:work T} Run stat(1) over all files tagged as \fBdocs\fR and all files tagged as \fBwork\fR .TE .sp \fB4.1 Operating on specific tagged files\fR .sp \fBNote\fR: This feature, as always when multi\-selection is involved, is only available when tab completion mode is set to \fBfzf\fR. See the \fBTAB COMPLETION\fR section above. .sp You may not want to operate on \fBall\fR files tagged as some specific tag, say \fBwork\fR, but rather on \fBsome\fR files tagged as \fBwork\fR. Tab completion is used to achieve this aim. .sp Let's suppose you have a tag named \fBwork\fR which contains ten tagged files, but you need to operate (say, print the file properties) only on two of them, say, \fIwork1.odt\fR and \fIwork2.odt\fR: .sp \fBp t:work\fR The list of files tagged as \fBwork\fR will be displayed via \fBfzf\fR. Now mark the two files you need using the TAB key, press \fBEnter\fR or \fBRight\fR, and the absolute path to both files will be inserted into the command line. So, `\fBp t:work\fR` will be replaced by `\fBp /path/to/work1.odt /path/to/work2.odt\fR`. .SH 17. VIRTUAL DIRECTORIES \fBClifm\fR is able to read and list files from the standard input stream (STDIN). Each file in the list should be an absolute path, terminated with a new line character (\\n) and stripped from extra characters not belonging to the path itself. The size of the input stream buffer is 262MiB (65536 paths, provided each path takes PATH_MAX bytes (usually 4096)). .sp Each file passed via standard input is stored as a symbolic link pointing to the original file in a temporary directory (called here virtual directory) with read\-only (0500) permissions. This directory, and all its contents, will be deleted at program exit. Use the \fI\-\-virtual\-dir\fR command line flag to specify a custom directory (it if does not exist, it will be created) instead of the default one, created in the system temporary directory (usually \fI/tmp/clifm/USER/vdir.XXXXXX\fR, where XXXXXX is a random six digits string). .sp The user can operate on these files as if they were any other regular file, since \fBall operations performed on these symbolic links\fR (provided the current working directory is the virtual directory where all these files are stored) \fBare performed on the target files and NOT on the symbolic links themselves\fR. .sp Once in the virtual directory, files are listed by default using only the base name of the target file. For example, if the target file is \fI/home/user/Downloads/myfile.tar.gz\fR, this file will be listed as \fImyfile.tar.gz\fR. If this file already exists in the virtual directory (because there is another target file with the same base name, say, \fI/home/user/Documents/tars/myfile.tar.gz\fR), a random six digits suffix will be appended to the file (for instance, \fImyfile.tar.gz.12Rgj6\fR). .sp Since this listing mode does not allow the user to get a clear idea of the actual location of each listed file, a keybinding (by default \fBAlt+w\fR) is available to toggle short (base names only) and long filenames: in this latter case, filenames are listed using the absolute path to the target file, replacing slashes by colons (:). For example, if the target file is \fI/home/user/Downloads/myfile.tar.gz\fR, it will be listed in the virtual directory as \fIhome:user:Downloads:myfile.tar.gz\fR. .sp If you prefer the long names approach, you can use the \fB\-\-virtual\-dir\-full\-paths\fR command line flag. .sp \fBNote\fR: Bear in mind that the restore last path function is disabled when listing in this way. .sp \fBClifm\fR provides to ways of using virtual directories: .sp \fB1\fR. Reading files from the standard input .sp \fB2\fR. Listing sets of files via the \fIvirtualize.sh\fR plugin (which is in fact a special use case of point 1) .sp \fB1. Standard input\fR .sp Examples: \fBls \-Ad /var/* | clifm\fR This command will pass all files in the directory \fI/var\fR to \fBclifm\fR .sp If you need to perform more specific queries, you can use \fBfind\fR(1) as follows: \fBfind \-maxdepth 1 \-size +500k \-print0 | tr \'\\0\' \'\\n\' | sed \'s/\.\///g\' | clifm\fR The above command will pass all files in the current directory bigger than 500KiB to \fBclifm\fR. .sp You can also use stream redirection: \fBls \-Ad $PWD/* > list.txt clifm < list.txt\fR .sp \fB2. The virtualization plugin\fR .sp The \fIvirtualize.sh\fR plugin, bound by default to the \fBvt\fR action name, is intended to provide an easy way of listing sets or collections of files, such as selected, tagged, or bookmarked files. For example, to send all selected files to a virtual directory, you can issue this command: \fBvt sel\fR .sp and, if you want rather files tagged as PDF: \fBvt t:PDF\fR .sp Of course, individual files can also be used: \fBvt file1 file2 file3\fR .sp Once executed, the vt plugin will launch a new instance of \fBclifm\fR (on a new terminal emulator window) where you can operate on the specified files as if they were just normal files. Once done, quit this new instance (via the \fBq\fR command) to return to the primary instance of \fBclifm\fR. .sp \fBNote\fR: By default, the terminal emulator used is \fBxterm\fR(1), but it can be changed by editing the plugin script (\fIvirtualize.sh\fR). .sp When navigating the filesystem, you can quickly go back to the virtual directory using the \fB\-d\fR option: `\fBvt \-d\fR`. The navigation keys (see the \fBKEYBOARD SHORTCUTS\fR section above) and the \fBCLIFM_VIRTUAL_DIR\fR environment variable are also available (Shift+Left/Shift+Right or `\fBcd $CLIFM_VIRTUAL_DIR\fR`). .sp \fBTip\fR: Write an alias to make this even easier: .sp \fBalias vtd=\'cd $CLIFM_VIRTUAL_DIR\'\fR .SH 18. NOTE ON SPEED \fBClifm\fR is by itself quite fast by default, but if speed is still an issue, it is possible to get some extra performance. .sp The two most time consuming features are: \fB1)\fR The file counter, used to print the number of files contained by listed directories. Disabling this option produces a nice performance boost. \fB2)\fR In normal mode, \fBfstatat\fR(3) is used to gather information about listed files. Since this function, especially when executed hundreds (and even thousands) of times, is quite time consuming, the \fBlight mode\fR was implemented as an alternative listing process omitting all calls to this function (this does not apply, however, to the long view: since we need to display files information, \fBfstatat\fR(3) is required). .sp When running in light mode, however, a few features are lost: .sp 1. Only basic file classification is performed, namely, that provided by the \fBd_type\fR field of a \fBdirent\fR struct (see \fBreaddir\fR(3)). Bear in mind, nonetheless, that whenever \fB_DIRENT_HAVE_D_TYPE\fR was not set at compile time, or in case of a \fBDT_UNKNOWN\fR value for a given entry (we may be facing a filesystem not returning the \fBd_type\fR value, for example, loop devices), \fBclifm\fR will fall back to \fBstat\fR(3) to get basic files classification. .sp 2. Color per file extension is disabled for performance reasons. .sp 3. The marker for selected files (*) is lost as well: to keep track of selected files and thus recognize them in the current list of files, we make use of files device and inode number, which is provided by \fBfstatat(3)\fR. .sp Besides these two features, a few more things can be disabled to get some extra speed (though perhaps unnoticeable): icons (if enabled), columns, colors, and, if already running without colors, file type indicators. Because listing lots of files could be expensive and time consuming, you can also try to limit the number of files printed for each visited directory (see the \fBmf\fR command above). .sp Despite the above, however, it is important to bear in mind that listing speed does not only depend on the program\'s code and enabled features, but also on the terminal emulator used. Old, basic terminal emulators like Xterm, Aterm, and the kernel builtin console are really slow compared to more modern ones like Urxvt, Lxterminal, ST, and Terminator, to name just a few. .sp If using Xterm, a nice speed boost is provided by the fast scroll option: set \fBfastScroll\fR to \fBtrue\fR in your \fI~/.Xresources\fR file. See \fBxterm\fR(1). .SH 19. KANGAROO FRECENCY ALGORITHM The directory jumper function is designed to learn the navigation habits of the user. The information is stored in a database (see the \fBFILES\fR section below) used to get the best match for a given string provided by the user. In this sense, Kangaroo is like a quick, smart, and evolved cd function. .sp The information stored in the database, always per directory, is: a) Permanent entry ('+'): this directory will not be removed from the database, no matter its rank b) Number of visits c) Date of first visit (seconds since the Unix epoch) d) Date of the last visit (seconds since Unix epoch) e) The absolute path to each visited directory .sp With this information it is possible to build a ranking of directories to offer the user the most accurate matches for each query string. The matching algorithm takes into account mainly two factors: frequency and recency (which is why this kind of algorithm is often called a \fBfrecency\fR algorithm). .sp After getting an initial list of matches based on the query string(s) entered by the user, the frequency algorithm is applied on each entry in the list. The algorithm is quite simple: \fB(visits * VISIT\-CREDIT) / days\-since\-first\-visit\fR. As a result, we get the average of visits per day since the day of the first visit (what we call \fIthe directory rank\fR). .sp \fBNote\fR: VISIT\-CREDIT is a hardcoded value: 200. .sp There are however some further steps in the ranking process: \fBBonus points\fR. .sp Extra credits or penalties are assigned based on the directories \fBlast access time\fR according to the following simple algorithms: Within last hour: rank * 4 Within last day: rank * 2 Within last week: rank / 2 More than a week: rank / 4 .sp If the last query string matches the \fBbasename\fR of a directory, the entry for this directory has 300 extra credits. This is done simply because users normally use directory basenames as query strings: they are easier to remember. .sp In the same way, \fBpinned\fR directories get 1000 extra credits, \fBbookmarked directories\fR 500 credits, directories active in a \fBworkspace\fR 300 credits, and directories marked as \fBpermanent\fR 300 credits. .sp For example: if the query string is "test", \fI/media/data/test\fR will be matched. Now, if this directory was accessed within the last hour, and its rank was 200, it becomes 800. But, because the search string matches its basename, it gets 300 extra credits, and, if this directory is in addition bookmarked, pinned, and marked as permanent, it gets 1800 extra credits. In this way the total rank of this directory in the matching process is 2900. In doing so, we have more chances of matching what the user actually wanted to match. .sp Once all entries in the initial list of matches have been filtered via the above procedure and ranked, we can return the best ranked entry. The higher rank a directory has, the more priority it has over the remaining entries in the initial list of matches. .sp Automatic maintenance is done on the database applying a few simple procedures: a) If \fBPurgeJumpDB\fR is set to \fBtrue\fR (see the main configuration file), each entry in the database is checked at startup to remove non\-existent directories. This option is set to \fBfalse\fR by default to avoid removing paths pointing to unmounted filesystems (like removable devices or remote locations) which you still might want to keep. Non\-existent directories, however, will be removed soon or later anyway due to their low rank value (see below). b) Once the rank of a directory falls below \fBMinJumpRank\fR (by default 10), it is forgotten and deleted from the database. The \fBMinJumpRank\fR value can be customized in the configuration file. To make non\-frequently visited directories disappear quicker from the database, increase this value. If set to 0, by contrast, directories will never be removed from the database. c) Once the sum total of ranks reaches \fBMaxJumpTotalRank\fR (by default 100000), each individual rank is divided by a dynamic factor so that the total rank becomes less than or equal to \fBMaxJumpTotalRank\fR. If some rank falls in the process below \fBMinJumpRank\fR (and provided this latter is not 0), it is removed from the database. \fBMaxJumpTotalRank\fR can be modified in the configuration file. The higher the value of \fBMaxJumpTotalRank\fR, the more time directories will be kept in the database. \fBNote\fR: Directories visited in the last 24 hours, just as pinned, bookmarked directories, and directories currently used in some workspace, will not be removed from the database, no matter what their rank is. In other words, if you want to indefinitely keep a given directory in the jump database, bookmark it, or mark it as permanent (edit the database, via `\fBje\fR` or `\fBj --edit\fR`, and prepend a plus sign (+) to the corresponding entry). .sp The idea of 'frecency' was, as far as I know, first devised and designed by Mozilla. See \fIhttps://wiki.mozilla.org/User:Mconnor/Past/PlacesFrecency\fR. However, it is also implemented, though using different algorithms, by different projects like \fBautojump\fR, \fBz.lua\fR, and \fBzoxide\fR. .SH 20. ENVIRONMENT The following variables are read at initialization time: .TP .B NO_COLOR If set to any value, \fBclifm\fR will run without colors. .TP .B CLIFM_NO_COLOR Same as \fBNO_COLOR\fR, but specific to \fBclifm\fR. .TP .B CLICOLOR_FORCE Force the use of colors, even if the terminal does not report color support. .TP .B CLIFM_FORCE_COLOR Same as \fBCLICOLOR_FORCE\fR, but accepts a specific color value (8, 16, 256, truecolor or 24bit). .TP .B COLORTERM If set to either \fBtruecolor\fR or \fB24bit\fR, \fBclifm\fR assumes the terminal emulator to be capable of displaying true colors (and thereby also 256 colors), despite what the \fBterminfo\fR(5) database reports. .TP .B CLIFM_FILE_COLORS A colon separated list of file type color codes in the same form specified above in the \fBCOLOR CODES\fR section. .TP .B CLIFM_EXT_COLORS Same as above, but for file extensions. .TP .B CLIFM_IFACE_COLORS Same as above, but for different elements of \fBclifm\fR's interface. .TP .B CLIFM_DATE_SHADES A comma separated list of colors used to print timestamps based on age. .TP .B CLIFM_SIZE_SHADES Same as \fBCLIFM_DATE_SHADES\fR, but for file sizes. .TP .B CLIFM_PREVIEW_MAX_SIZE If running with \fB\-\-preview\fR, or \fBPreviewMaxSize\fR is not set in the configuration file, no preview is generated for files larger that this value. The value must be specified in KiB: for example, 2048 is read as 2 MiB. .TP .B CLIFM_TEMPLATES_DIR A custom file templates directory. .TP .B CLIFM_HISTFILE A custom commands history file. .TP .B CLIFM_FILTER Define a file filter. If set, this variable overrides the \fBFilter\fR option in the configuration file. .TP .B CLIFM_SUDO_CMD Name of the authenticator program. Used by the \fBX\fR command (to launch a new instance of \fBclifm\fR as root), the \fBAlt+v\fR keybinding (to prepend the authenticator program name to the current command line), and for some operations on archives (ISO files). Defaults to \fBsudo\fR (or \fBdoas\fR if compiled on OpenBSD). Example: `\fBCLIFM_SUDO_CMD=doas clifm\fR`. .TP .B SHELL .sp 0 An absolute path to the shell to be used by \fBclifm\fR to run external commands. Only values found in \fI/etc/shells\fR are allowed. .TP .B CLIFM_SHELL Same as \fBSHELL\fR, but specific to \fBclifm\fR (takes precedence over \fBSHELL\fR). .TP .B TMPDIR .sp 0 Path to a directory where temporary files will be created. .TP .B CLIFM_TMPDIR Same as \fBTMPDIR\fR, but specific to \fBclifm\fR (takes precedence over \fBTMPDIR\fR). .TP .B TERM .sp 0 Terminal type for which output is to be prepared. .TP .B FZF_DEFAULT_OPTS A quoted list of options to be passed to fzf (if used for tab completion). .TP .B TIME_STYLE If set from neither \fB\-\-time\-style\fR nor \fBTimeStyle\fR (in the configuration file), use this time style for the long view. .TP .B CLIFM_TIME_STYLE Same as \fBTIME_STYLE\fR, but specific to \fBclifm\fR (takes precedence over \fBTIME_STYLE\fR). .TP .B PTIME_STYLE If set from neither \fB\-\-ptime\-style\fR nor \fBPTimeStyle\fR (in the configuration file), use this time style for the \fBp/pp\fR command and the \fB\-\-stat\fR/\fB\-\-stat\-full\fR command line switches. .TP .B CLIFM_COLUMNS The number of terminal columns. .TP .B CLIFM_LINES The number of terminal lines. .TP .B CLIFM_MIMETYPES_FILE Set a custom mime.types file (instead of the default, \fI~/.mime.types\fR). Consult the \fBFILE OPENER\fR section form more information. .TP Except when running in \fBstealth mode\fR, \fBclifm\fR sets the following environment variables: .TP .B CLIFM .sp 0 Path to the configuration directory. By inspecting this variable other programs can find out if they were spawned by \fBclifm\fR. It can also be used to quickly jump to the configuration directory: `\fBcd $CLIFM\fR` or just `\fB$CLIFM\fR`. .TP .B CLIFMRC Path to the main configuration file (by default \fI~/.config/clifm/profiles/default/clifmrc\fR). .TP .B CLIFM_PID PID number of \fBclifm\fR's running instance. .TP .B CLIFM_VERSION Version number of \fBclifm\fR's running instance. .TP .B CLIFM_VIRTUAL_DIR Path to the currently used virtual directory only if (and while) the virtual directory function is exectued. See the \fBVIRTUAL DIRECTORIES\fR section above. .TP .B SHLVL .sp 0 Incremented by one each time a new shell is started. .TP .B CLIFMLVL Same as \fBSHLVL\fR, but specific to \fBclifm\fR. .TP If \fBNotifications\fR is set to \fBfalse\fR for the current prompt, the following variables are exported to the environment to be used, if needed, by your custom prompt: .TP .B CLIFM_STAT_SEL Current number of selected files. .TP .B CLIFM_STAT_TRASH Current number of trashed files. .TP .B CLIFM_STAT_ERROR_MSGS Current number of error messages. .TP .B CLIFM_STAT_WARNING_MSGS Current number of warning messages. .TP .B CLIFM_STAT_NOTICE_MSGS Current number of notice messages. .TP .B CLIFM_STAT_WS Current workspace number. .TP .B CLIFM_STAT_EXIT Exit code of the last executed command. .TP .B CLIFM_STAT_ROOT 1 if user is root (UID = 0), 0 otherwise. .TP .B CLIFM_STAT_STEALTH 1 if running in stealth mode, 0 otherwise. .TP When running a plugin, the following environment variables are set: .TP .B CLIFM_BUS The path to a pipe by means of which plugins can talk to \fBclifm\fR. See the \fBPLUGINS\fR section for more information. .TP .B CLIFM_COLOR_SCHEME Set to the name of the current color scheme. .TP .B CLIFM_COLORLESS Set to 1 if running without colors. .TP .B CLIFM_CUR_WS Set to the current workspace number. .TP .B CLIFM_DIRS_FIRST Set to 1 if list-dirs-first is enabled. Otherwise it is set to 0. .TP .B CLIFM_FILES_COUNTER Set to 1 if files-counter is enabled. Otherwise it is set to 0. .TP .B CLIFM_FILES_FILTER Set to the files filter string. Unset if no files filter is set. .TP .B CLIFM_FILTER_REVERSE Set to 1 if filter-reverse is set or to 0 otherwise (unset if no files filter is set). .TP .B CLIFM_FOLLOW_LINKS Set to 1 if follow-symlinks is enabled. Otherwise it is set to 0. .TP .B CLIFM_LIGHT_MODE Set to 1 if light-mode is enabled. Otherwise it is set to 0. .TP .B CLIFM_LINE When running a plugin via a keybinding, this variable holds the content of the current line buffer. For a usage example see the \fIxclip.sh\fR plugin. .TP .B CLIFM_LONG_VIEW Set to 1 if long-view is enabled. Otherwise it is set to 0. .TP .B CLIFM_MAX_FILES Set to MAX_FILES if max-files is set. Unset otherwise. .TP .B CLIFM_ONLY_DIRS Set to 1 if only-dirs is enabled. Otherwise it is set to 0. .TP .B CLIFM_PLUGINS_HELPER Set to the absolute path to the plugins\-helper script used by several plugins. .TP .B CLIFM_PROFILE Set to the name of the current profile. .TP .B CLIFM_SEL_FILES Set to the number of currently selected files (unset if there are no selected files). .TP .B CLIFM_SELFILE Set to the path to the current selection file. .TP .B CLIFM_SHOW_HIDDEN Set to 1-3 if show-hidden is enabled (true, first, last, in this order). Otherwise it is set to 0. .TP .B CLIFM_SORT_REVERSE Set to 1 if sort-reverse is enabled. Otherwise it is set to 0. .TP .B CLIFM_SORT_STYLE Set to the current sort method. .TP .B CLIFM_TRASH_FILES Set to the number of currently trashed files (unset if there are no trashed files). .TP .B CLIFM_TRUNCATE_NAMES Set to 1 if truncate-names is enabled. Otherwise it is set to 0. .SH 21. SECURITY Since \fBclifm\fR executes OS commands, it needs to provide a way to securely run these commands, specially when it comes to untrusted environments. Two features are provided to achieve this aim: \fBsecure environment\fR and \fBsecure commands\fR. .TP Both features are aimed at protecting the program and the system as such from malicious input, either coming from environment variables or from indirect input, that is to say, input coming not from the command line (in which is assumed that it is the user herself who is executing the given command), but from files: this is the case of default associated applications (the \fBmime\fR command), autocommands, aliases, plugins, (un)mount commands (using the \fBnet\fR command), just as profile and prompt commands. .TP In an untrusted environment, an attacker could cause unexpected and insecure behavior (even command injection) using environment variables, or inject malicious commands via indirect input, commands which will be later executed by \fBclifm\fR without the user's consent (i.e. automatically). This is why we provide a mechanism to minimize this danger: if running in an untrusted environment, the secure environment and secure commands features are there to prevent (at least as far as possible) this kind of attacks. .TP \fBA) Secure environment\fR .TP Programs inherit the environment from the parent process. However, if this inherited environment is not trusted, not secure, it is always a good idea to sanitize it using only sane values, preventing thus undesired and uncontrolled input that might endanger the program and the system itself. .TP The \fBsecure\-environment\fR function forces \fBclifm\fR to run on a such a sanitized environment. .TP There are two secure\-environment modes, the \fBregular\fR, and the \fBfull\fR one. To enable the regular mode, run \fBclifm\fR with the \fB\-\-secure\-env\fR command line option. Otherwise, enable the full mode using \fB\-\-secure\-env\-full\fR. .TP \fBa)\fR \fBRegular\fR: in this mode, the inherited environment is cleared, though a few variables are preserved to keep \fBclifm\fR running as stable as possible. These preserved variables are: \fBTERM\fR, \fBDISPLAY\fR, \fBLANG\fR, \fBTZ\fR, and, if fzf tab completion mode is enabled, \fBFZF_DEFAULT_OPTS\fR. .TP The following variables are set in an environment agnostic way (that is, securely): \- \fBHOME\fR, \fBSHELL\fR, and \fBUSER\fR are retrieved using \fBgetpwuid\fR(3) \- \fBPATH\fR is set consulting \fB_PATH_STDPATH\fR (or \fB_CS_PATH\fR if the former is not available) \- \fBIFS\fR is set to a sane, hard\-coded value: " \\n\\t" (space, new line char, and horizontal TAB) .TP As a plus, \fB1)\fR core dumps are disabled, \fB2)\fR the umask value is set to \fB0077\fR at startup and the creation mode (when using the \fBnew\fR command) is forced to \fB0700\fR for directories and \fB0600\fR for files, \fB3)\fR non\-standard file descriptors (>2) are closed, \fB4)\fR SUID/SGID privileges, if any, are dropped, and \fB5)\fR autocommand files are not read at all (even if \fBReadAutocmdFiles\fR is set to \fBtrue\fR). .TP \fBb)\fR \fBFull\fR: this mode is just like the regular mode, except that \fBnothing\fR is imported from the environment at all and only \fBPATH\fR, \fBHOME\fR, \fBUSER\fR, \fBSHELL\fR, and \fBIFS\fR are set (as described above). Everything else remains unset, and is the user's responsibility to set environment variables (via the export function), as needed. In this case, you might want to set, at least, \fBTERM\fR, and, if running in a graphical environment, \fBDISPLAY\fR. .TP Be aware that enabling secure\-environment might break some functions, depending on the system configuration. .TP \fBB) Secure commands\fR .TP Some commands are automatically executed by \fBclifm\fR: (un)mount commands (via the \fBnet\fR command), opening applications (via \fBLira\fR), aliases, and plugins, just as prompt, profile, and autocommands. These commands are read from a configuration file and then executed. Now, if an attacker has access to any of these files, she might force \fBclifm\fR to run any arbitrary command, and thereby possibly exposing the whole system. .TP Every time a command is thus automatically executed via the system shell (i.e. without the user's direct consent), the secure commands function performs four different, though intrinsically related tasks aimed to mitigate command injection and/or unexpected behavior: .TP \fBa)\fR Plugins are disabled. .TP \fBb)\fR Only command base names are allowed: \fInano\fR, for instance, is allowed, while \fI/usr/bin/nano\fR is not. In this way we can guarantee that only commands found in a sanitized \fBPATH\fR (see the point \fBd\fR below) will be executed. This is done in order to prevent the execution of custom binaries/scripts, for example: \fI/tmp/exec_file\fR. .TP \fBc)\fR Commands are validated using a \fBwhitelist\fR of safe characters (mostly to prevent stream redirection, conditional execution, and so on, for example, 'your_command;some_injected_command'). This set of safe characters slightly vary depending on the command being executed (because they use different syntaxes): .sp Net command: a\-zA\-Z \-_.,/= Prompt, profile, autocommands: a\-zA\-Z \-_.,/"' Mime command: a\-zA\-Z \-_.,%& .TP Commands containing \fBat least one\fR unsafe character will be rejected. Of course, we cannot (and should not) prevent what looks like legitimate, benign commands from being executed. But we can stop commands that, in an untrusted environment, look suspicious. This is specially the case of stream redirection (>), pipes (|), sequential (;) and conditional execution (&&, ||), command substitution ($(cmd)), and environment variables ($VAR). .TP \fBd)\fR A secure environment is set (\fB\-\-secure\-env\fR is implied; to run on a fully sanitized environment run as follows: \fB\-\-secure\-cmds \-\-secure\-env\-full\fR. .SH 22. MISCELLANEOUS NOTES .sp \fBSequential and conditional execution of commands\fR: For each of the internal commands (see the \fBCOMMANDS\fR section above) you can use the semicolon to execute them sequentially and/or the double ampersand to execute them conditionally. For example: `\fBcmd1;\ cmd2\ &&\ cmd3\fR`. .sp Though you can use here external commands as well, bear in mind that, whenever at least one internal command is involved in a chained list of commands, \fBclifm\fR will take care of executing this list (simply because the system shell is not able to understand any of these commands), so that no shell inter\-process function (like pipes), nor any stream redirection or shell expression (like IF blocks or FOR loops) will be available. However, the shell is still used to run single external commands found in the chained list, but in isolation from the remaining commands in this list. .sp As a rule of thumb, when using chained commands make sure to always expand ELNs to avoid undesired consequences. If, for instance, you issue this command: `\fBtouch\ aaa\ &&\ r\ 3\fR`, you will end up deleting a file you were not intended to delete, simple because after the successful execution of the first command, the ELN 3 corresponds now to a different file. .sp \fBExternal commands\fR: \fBClifm\fR is not limited to its own set of internal commands, like \fBopen\fR, \fBsel\fR, \fBtrash\fR, etc. It can run external commands as well, provided external commands are allowed (see the \fB\-x\fR option, the \fBext\fR command, and the \fBExternalCommands\fR option in the configuration file). .sp External commands are executed using the system shell (say, \fI/bin/sh\fR), which is specified by \fBclifm\fR as follows: 1. If the \fBCLIFM_SHELL\fR environment variable is set, this value is used. 2. If the \fBSHELL\fR environment variable is set, this value is used. 3. If none of the above, the value is taken from the \fBpasswd\fR database (via \fBgetpwuid\fR(3)). .sp The shell is invoked as follows: \fISHELL\fR -c '\fICMD ARG\fR...', for example, `\fB/bin/sh -c 'ls -l'\fR`. .sp By beginning the external command by a colon or a semicolon (':', ';') you tell \fBclifm\fR not to parse the input string, but instead letting this task to the system shell. .sp Bear in mind that \fBclifm\fR is not intended to be used as a shell, but as the file manager it is. .sp \fBTerminal emulators and non\-ASCII characters\fR: It depends on the terminal emulator you use to correctly display non\-ASCII characters and characters from the extended ASCII charset. If, for example, you create a filenamed "ñandú" (the Spanish word for \'rhea\'), it will be correctly displayed by the Linux console, Lxterminal, and Urxvt, but not thus by more basic terminal emulators like Aterm. .sp \fBSpaces and filenames\fR: When dealing with filenames containing spaces, you can use both single and double quotes (e.g.: "this file" or 'this file') plus the backslash character (e.g.: this\\ file). .sp \fBDefault profile\fR: \fBClifm\fR's default profile is \fBdefault\fR. To create alternative profiles use the \fB\-P\fR command line option or the `\fBpf add\fR` command (see above). .SH 23. FILES .TP .B CONFIGURATION FILE The main configuration file is looked up in these places (and in this order): .sp \fB1.\fR \fB\-c\fR,\fB\-\-config\-file\fR switch \fB2.\fR \fB$CLIFMRC\fR variable \fB3.\fR \fI$XDG_CONFIG_HOME/clifm/profiles/PROFILE/clifmrc\fR directory .sp If \fB$XDG_CONFIG_HOME\fR is not set, \fI$HOME/.config\fR is used instead. If running with secure-environment (using either \fB\-\-secure\-cmds\fR, \fB\-\-secure\-env\fR, or \fB\-\-secure\-env\-full\fR) no environment variable is read, so that the home directory is taken instead from the password database (via \fBgetpwuid\fR(3)). .sp PROFILE is by default \fBdefault\fR (unless set via \fB\-P\fR,\fB\-\-profile\fR). .sp You can access the configuration file either via the \fBconfig\fR command or pressing F10. .sp A description for each option in the configuration file can be found in the configuration file itself. .TP .B PROFILE FILE The profile file is \fI$XDG_CONFIG_HOME/clifm/profiles/PROFILE/profile.clifm\fR. In this file you can add those commands you want to be executed at startup. You can also permanently set here some custom variables, e.g.: 'dir="/path/to/dir"'. This variable may be used as a shortcut to that directory, for instance: `\fBcd $dir\fR`. Custom variables can also be temporarily defined in the command prompt: E.g.: user@hostname ~ $ var="This is a test". Temporary variables will be removed at program exit. Internal variables are disabled by default; enable them using the \fB\-\-int\-vars\fR command line switch. .TP .B PROMPTS FILE This file contains prompts definitions and is located in \fIDATADIR/clifm/prompts.clifm\fR. It will be copied automatically to \fI$XDG_CONFIG_HOME/clifm/prompts.clifm\fR if it doesn't exist. The \fBPrompt\fR line in the color scheme file should point to one of the prompt names defined in this file. See the \fBPROMPT\fR section for more information. .TP .B KEYBINDINGS FILE The keybindings file is \fI$XDG_CONFIG_HOME/clifm/keybindings,cfm\fR. It will be copied from \fIDATADIR/clifm\fR (usually \fI/usr/share/clifm\fR), and if not found, it will be created anew with default values. This file is used to specify the keyboard shortcuts used for some ClifM's functions. The format for each keybinding is always "keyseq:function", where 'keyseq' is an escape sequence in GNU emacs style. A more detailed explanation can be found in the keybindings file itself. .TP .B PLUGINS DIRECTORY The directory used to store programs or scripts pointed to by actions (in other words, plugins) is \fIDATADIR/clifm/plugins\fR (usually \fI/usr/share/clifm/plugins\fR). To edit these plugins copy them to \fI$XDG_CONFIG_HOME/clifm/plugins\fR and edit them to your liking. Plugins in this local directory take precedence over those in the system one. .TP .B COLORS DIRECTORY This directory, \fI$DATADIR/clifm/colors\fR, contains available color schemes (or just themes) as files with a \fI.clifm\fR extension. You can copy these themes to the local colors directory (\fI$XDG_CONFIG_HOME/clifm/colors\fR) and edit them to your liking (or create new themes from the ground up). Themes in the local colors directory take precedence over those in the system directory. You can create as many themes as you want by dropping them into the local colors directory. The default color scheme file (\fIdefault.clifm\fR) can be used as a guide. .TP .B ACTIONS FILE The file used to define custom actions is \fI$XDG_CONFIG_HOME/clifm/profiles/PROFILE/actions.clifm\fR. It will be copied from \fIDATADIR/clifm\fR (usually \fI/usr/share/clifm\fR), and if not found, it will be created anew with default values. .TP .B MIMELIST FILE The mimelist file is \fI$XDG_CONFIG_HOME/clifm/profiles/PROFILE/mimelist.clifm\fR. It is a list of file types and name/extensions and their associated applications used by \fBlira\fR. It will be copied from \fIDATADIR/clifm\fR (usually \fI/usr/share/clifm\fR). .TP .B PREVIEW FILE The preview file is \fI$XDG_CONFIG_HOME/clifm/profiles/PROFILE/preview.clifm\fR and is shotgun's configuration file. It makes use of the same syntax used by the mimelist file. It will be copied from \fIDATADIR/clifm\fR (usually \fI/usr/share/clifm\fR). .TP .B BOOKMARKS FILE The bookmarks file is \fI$XDG_CONFIG_HOME/clifm/profiles/PROFILE/bookmarks.clifm\fR Just the list of the user's bookmarks used by the bookmarks function. .TP .SH HISTORY FILE The history file is \fI~/.config/clifm/profiles/PROFILE/history.clifm\fR. A list of commands entered by the user and used by the history function. .TP .B COMMANDS LOG FILE The commands log file is \fI$XDG_CONFIG_HOME/clifm/profiles/PROFILE/cmdlogs.clifm\fR. Command logs keep track of commands entered in the command line. These logs have this form: "[date] current_working_directory:command". .TP .B MESSAGES LOG FILE The messages log file is \fI$XDG_CONFIG_HOME/clifm/profiles/PROFILE/msglogs.clifm\fR. Message logs are a record of errors and warnings and have the following form: "[date] message". .TP .B KANGAROO DATABASE The directory jumper database is stored in \fI$XDG_CONFIG_HOME/clifm/profiles/PROFILE/jump.clifm\fR. .TP \fBNote\fR: If \fI$XDG_CONFIG_HOME\fR is not set, \fI$HOME/.config/\fR is used instead. .SH 24. EXAMPLES \fBNote 1\fR: Always try TAB. Tab completion is available for many things. \fBNote 2\fR: Suggestions for possible completions are printed next to the text typed so far. To accept the given suggestion press \fBRight\fR (or \fBAlt+f\fR to accept only the first/next suggested word). Otherwise, the suggestion is just ignored. Get help: \fBF1\fR: manpage \fBF2\fR: keybindings \fBF3\fR: commands \fB1. NAVIGATION\fR .TS allbox; lb lb l l. Command Description T{ /etc T} Change directory to \fI/etc\fR \fB(1)\fR T{ 5 T} Change to the directory whose ELN is 5 \fB(2)\fR T{ j (also dh ) T} Navigate through visited directories T{ j xproj T} Jump to \fI~/media/data/docs/work/mike/xproject\fR \fB(3)\fR T{ b (Shift+Left, Alt+j) T} Go back in the directory history list T{ f (Shift+Right, Alt+k) T} Go forth in the directory history list T{ \fR.. (Shift+Up, Alt+u) T} Change to the parent directory T{ \fR... T} Change to the parent directory of the current parent directory \fB(4)\fR T{ bd w T} Change to the parent directory matching "w" \fB(5)\fR T{ ws2 (Alt+2) T} Switch to the second workspace \fB(6)\fR T{ /*.pdf T} List PDF files (current dir) T{ =x T} List executable files (current dir) \fB(7)\fR T{ @gzip T} List files (current dir) whose MIME type includes "gzip" T{ pin mydir T} Pin the directory named \fImydir\fR T{ , T} Change to pinned directory T{ view (Alt+\-) T} Preview files (current dir) \fB(8)\fR T{ pg (Alt+0) T} Run \fBMAS\fR, the file pager, on the current directory\fR .TE .sp \fB(1)\fR `\fBcd /etc\fR` also works .sp 0 \fB(2)\fR Press TAB to make sure 5 is the file you want, or just pay attention to the suggestion. Press Right to accept the given suggestion .sp 0 \fB(3)\fR This depends on the database ranking. For more accuracy: `\fBj mike xproj\fR`. Tab completion is available: `\fBj xproj\fR` .sp 0 \fB(4)\fR This is the \fBfastback\fR function: each susequent dot after the two first dots is understood as an extra "/.." .sp 0 \fB(5)\fR Type `\fBbd \fR` to list all parent directories .sp 0 \fB(6)\fR \fBAlt+[1\-4]\fR is available for workspaces 1\-4 .sp 0 \fB(7)\fR Type `\fB=\fR` to get the list of available file type characters. Consult the \fBFILE FILTERS\fR section above for more information .sp 0 \fB(8)\fR This feature depends on \fBfzf\fR(1) \fB2. FILE OPERATIONS\fR .TS allbox; lb lb l l. Command Description T{ myfile.txt T} Open \fImyfile.txt\fR (with the default associated application) T{ myfile.txt vi T} Open \fImyfile.txt\fR using vi \fB(1)\fR T{ 24& T} Open the file whose ELN is 24 in the background T{ n myfile mydir/ T} Create a new file named \fImyfile\fR and a new directory named \fImydir\fR \fB(2)\fR\fB(3)\fR T{ p4 T} Print the properties of the file whose ELN is 4 T{ pc myfile.txt T} Edit the permission set of the file \fImyfile.txt\fR (use \fBoc\fR to edit ownership) T{ s *.c T} Select all c files in the current directory T{ s /media/* T} Interactively select files in the directory \fI/media\fR \fB(4)\fR T{ s 1\-4 8 19\-26 T} Select multiple files in the current directory by ELN T{ sb (sel or s:) T} List selected files \fB(5)\fR T{ ds (ds ) T} Selectively deselect files using a menu T{ bm add mydir/ mybm T} Bookmark the directory \fImydir/\fR as \fBmybm\fR T{ bm mybm (b:mybm) T} Access the bookmark named \fBmybm\fR \fB(6)\fR T{ bm del mybm T} Remove the bookmark named \fBmybm\fR T{ bm (Alt+b or b:) T} Open the bookmark manager T{ t 1\-3 *.old T} Trash a few files T{ u (u ) T} Selectively restore trashed files using a menu T{ t del (t del ) T} Selectively remove files from the trash can using a menu T{ t empty T} Empty the trash can T{ ta *.pdf :mypdfs T} Tag all PDF files in the current directory as \fBmypdfs\fR T{ p t:mypdfs T} Print the file properties of all files tagged as \fBmypdfs\fR T{ /*.pdf T} Search for all PDF files in the current directory T{ c sel T} Copy selected files to the current directory T{ c *.txt 2 T} Copy all txt file to the directory whose ELN is 2 T{ r sel T} Remove all selected files \fB(7)\fR T{ m4 T} Rename the file whose ELN is 4 \fB(8)\fR .TE .sp \fB(1)\fR Use the \fBow\fR command to select the opening application from a menu: `\fBow myfile.txt\fR` or `\fBow myfile.txt \fR` .sp 0 \fB(2)\fR Note the ending slash in the directory name .sp 0 \fB(3)\fR Since \fBclifm\fR is integrated to the system shell, you can also use any of the shell commands you usually use to create new files. E.g.: `\fBtouch myfile\fR` or `\fBnano myfile\fR` .sp 0 \fB(4)\fR Only for non\-standard tab completion: fzf, fnf, smenu .sp 0 \fB(5)\fR You can also TAB expand the \fBsel\fR keyword: `\fBp sel\fR` to list selected files (and optionally mark multiple selected files to operate on) .sp 0 \fB(6)\fR Type `\fBbm \fR` to get the list of available bookmark names .sp 0 \fB(7)\fR To remove files in bulk use the \fBrr\fR command .sp 0 \fB(8)\fR To rename files in bulk use the \fBbr\fR command \fB3. MISC\fR .TS allbox; lb lb l l. Command Description T{ hh (Alt+.) T} Toggle hidden files T{ ll (Alt+l) T} Toggle long-view T{ rf (Enter \-on empty line\- or Ctrl+l) T} Clear/refresh the screen T{ Alt+, T} Toggle list-directories-only T{ Alt+Tab, Ctrl+Alt+i T} Toggle disk usage analyzer mode T{ ! T} Navigate through the command history T{ config (F10) T} View/edit the main configuration file T{ pf set test T} Change to profile \fBtest\fR T{ actions T} List available actions/plugins T{ icons on T} Want icons? T{ cs (cs ) T} List available color schemes T{ prompt (prompt ) T} List available prompts T{ q T} I\'m tired, quit .TE .TP There is a lot more you can do, but this should be enough to get started. .SH EXIT STATUS \fBClifm\fR returns the exit status of the last executed command .SH LICENSE This program is distributed under the terms of the GNU GPL version 2 or later .sp 0 This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. .SH BUG AND FEATURE REQUESTS Report at .SH AUTHOR L. M. Abramovich For additional contributors, run `\fBgit shortlog \-s\fR` on the clifm.git repository. clifm-1.26.3/misc/clifm.1.pdf000066400000000000000000007262721506632037700156050ustar00rootroot00000000000000%PDF-1.4 % 3 0 obj << /Contents [4 0 R ] /Group << /CS /DeviceRGB /S /Transparency >> /Parent 2 0 R /Type /Page >> endobj 4 0 obj << /Filter /FlateDecode /Length 1126 >> stream xXn8}WQV6ikEEeU?ԥe:ԶM`ÔG33g03n̄߾v yZ$QdVKS?/h&fl  v85/%gU]74BkF4YTgR1<3͢KYеۆG,y |D15_:h*T8 :M6xO^āUp(9%;jqed$~8 V.le"եI2LtWgA6,Qv'OuRGNц=uoh5M jes FƧԉK&~qI1Lę w9M4V3H/nquU_9q$h0ZD1D-Op!OGu{ztH> /Parent 2 0 R /Type /Page >> endobj 17 0 obj << /Filter /FlateDecode /Length 3430 >> stream xZrF}W#UE;-ŦJ"U#pHQ  $[Ḁ/O31V gx69-gjgP^/b = ٞxmĀ m(y<%qbIۜ'ɇ6NCM\yό=NVSBR Dvlj?(fe}?{mU~V!3e/."4E>g)"8'f)Xy!|K2O*X?l+hk]q*.5=g0@ynRѠpɠP(Z#Fi!@։ʸ@+ʸǝ ϥB:dqkOXptEnzB0t~OÄy.5.1`9߀ʵ'L7SLMpkȊixn?J2 0[ax=k];peY5r^F6)y|vuAlP7ݭtqJzȌ^*jt%|4gԵY@gCe KՁA5wmSrUGpVEΓ-089YHZ?V=l |a5kە [ǰHVN 6u+d!K9R Aʶ&kq"#YMH ubs-*iV3T릁4ӜnF_@C?䎳Fy:Fm'i-o860LL=(YH@w#  K9?_1$/G~V4P:.A/ cKVSzN9v$/Hbr5sATW- COٻ$>BǤnC΁wVaBU! W#9p(Ys>&l(NpMl X L72j)y a zPUU[x/A%d#k'jԈLcUA0Y@5^6u.,_W16S~|ň)RD۪pZ(Y!`Am*n0P܃&; _3uogVoc|FGƜ "J[fk(,mCuɟA*lxz9ak[|LkEeϿD! Cj< |qםUŷk4msjlu)-&c1I’t x>w,= x|Ŵk0![u Lә atJ3)$B}D@A<;hBR j _L(PC@Gp(NuDʡj T[V5dQr[7|fZ51 XkAךy{-jM7-w.!iR;`gއ3|S>"6a6ZSb%ͻ#t5b//3Ml'q}F8DX7DvvѼmiꞹjtq$mgh+9 /c`?G釓RH=4ZxZbօ>  ķO@馌#YٽK f TiIƣ9්H:;JPkW O}x1{zJ'uG`, rQꥹ{B=e_X@;0SF@Ç`w%U RoQӋ L9:д2gb^@Sys LsUT3LaB4 ^/GX,y;=)L5]j r91 =c9]PZg?endstream endobj 18 0 obj << /Contents [19 0 R ] /Group << /CS /DeviceRGB /S /Transparency >> /Parent 2 0 R /Type /Page >> endobj 19 0 obj << /Filter /FlateDecode /Length 2064 >> stream xZr8ߧt˖oZ6L e%Qc[!gH_$vswnߑd_u4?#-zfaVgzs98+WB~HeYh0%ӳW$@'8/+= -3nR 9z-ɅC{h2GXdcS}yaC#,hu &w%|ZbՃqeXkPrڽR}LnQ E#42>i֧`mﻀy"b;*,GGeDآ&tF,A˜NjJD@ȍƘ@ % |d{.]Dv (M$ʶ4.3>9.l+ևە*?B7iC5׃N칶BiRk# `\"%l?E-EHӲy4h 0r#w3uMtG7ƦkppX㲽88mpjv̛PSBCg/u@Z]yMqڞON 46mBhWV_֭B\w8\:ՃXs"D즧[`S~(jx%sdcy5j!L7y(1 )MadSBYsІyP tQ.SKcqz'/mdnNjaUnd T UՋ^A&j!~`F![}kouRiwdU P9.Ъ3#ݤڔAq,/79OHBI`MaVL$!eKi<җ Eb9Mm?7!;I7-B3v:2zS-0J䛏7ד~9&M`BJ[pJrlv9hڥڶx?b'endstream endobj 20 0 obj << /Contents [21 0 R ] /Group << /CS /DeviceRGB /S /Transparency >> /Parent 2 0 R /Type /Page >> endobj 21 0 obj << /Filter /FlateDecode /Length 3009 >> stream xZr6Oy*xwƍ3:t)%ATHʲ G;7]Dp.8~Es>!牁-;1?O'Kg-lAC8?v~O7څF9 JGpFxD^גzO us_`)F|~*J Otmrlg7ÔnYjV#K1Ԅ|BDQ"~"6OC_Ga%;DI].ْ9ZNsطlXq-)d}C.H'S8vuT:hf(؃evܖ[q9T3=I= g| .|X>a 6C5uM9$f}l'qoЌ}QMl2kImxjYa]%CTIPjI<66((VC<m y!,;oj~(ް;w=` yet9mejDBn߽U?}k1߅JԲ[)/4U š q7X0 k3N|Ww|%t5]E3a\%kD+GK kT]fL ١]~CM52V>S)mVJ@Dy0iv#JN/prGCG׿_-Lk<ԅ]yjq_[ I.iM5F?+H T%fw̡{K?^kB#5΂Z6^jP,@j m`Ǯ8X$=ni@]P.G1B9J;[~ͪr,Kp:ʌUMV~ J 6Ip(ifP2ߡT ׀},'oEkB#`h$@f ?۰y =~?վ )AYKOtЏ,븥&rx|^\G2[RGt[^Pw&ɝ~_T7X`ͲkxͫDۺadNMs9?׋}jw]\YPܐR;V؝6R"oZDX=,~k_M>#Q rk7B>l:C!, ~(qӮe%pvts>N&3t^N\#/w/|= (օ%{ wm_ѩϰ y̯ݻB1Jc~B&KDFI˟ԣ81_~Qh Q+9gCr4N2ip3FfqL4\~tZ~tBe9x yw.|P<`T K8XTBDUQTP(CQ/Hh]ЂҴW3Y_=W տ7&g}uj' uѢ890;|M [atY]sT[wB Th[k@jc.j&S}F D VI뮸aF7q/ W.s{ZD`Xޕ;`1f<ėo`@lk[m<_O~=ybendstream endobj 22 0 obj << /Contents [23 0 R ] /Group << /CS /DeviceRGB /S /Transparency >> /Parent 2 0 R /Type /Page >> endobj 23 0 obj << /Filter /FlateDecode /Length 2628 >> stream xZr6O?BK;uqF]0 I)R!gȫo)"-ߴ4c2bwK&;Y8 Ķ<=I*tȳI{md%K'"gb"oYaٟ!7ScCgXdqi/~&oVr²;K-O-%t qx[ =Ǣmjn0wrf6ZM8 yQ P$)r*/H!)=|Lot \J'|ӻNp=5;x ݕwE3c?ЦE}QxVׯb8A]Ju࠾yAZyw7:bU`9W1Y/)IU*Xb?^vo?{{q`fY( /7p,wro'ld,I7'Pe_凾VC<Ked*.EVk߳ڒ_QY\“ᇋkٳC 8ogWn>^;KrU{=˩Yn-Ͷ</ED+r{f| gN&KKQ'v'&7uXN˷fXN-(u+֏5O7Ǒ7z9{^\&crWRIiiXl)l}Fր+'VYXvר&AO-òr?#ɒ,'BB5Sp> J/GiADTIºa)9~0RPNJTY?tjhߗ"(l)"nS-EױcตȁlE5@Q+%Ji}[˭|J<{TjC Ǩ;r--Y.WW?!A00..X FI/l9hC< !)Fnøs#aRm)rXPmKallOw\ۛ[NxMX]0SmE|&<py6 gYɥZ2 >za<ȒR.b+%$y;Ry>~_ɽ˨zhN'-2Y=*j{N5SGIŃ*ŋb u7)9ĒRM;v]/,Ծ@T>F=e=aC5alq{@|X&|u>xn]Q>Q )t bO]5W}H\b-1_[:ZT.HE+L:FhSf׷bh^[vpX^^ ǖdM!}IŹ㏯\g  MsOP ++ \=E zz+u;j8C ^&@ëdU*E\MM>o{_q`\ m#pI~7WaI5>5iЦwk=Mgs)'Vl݃3Xɱb =nthGݣk =PA^d9( Oڬ̴u@*R4M7F]r9R9JadJt=(dkC(1Dݫl+pZdlÕYvϒ-e5`v_9mE]Vog3IMo昹*K uoc\SѾ;b0GRi=Ս4/osi t~95N<:y5Qy@AM;?=+=RNUY|~;㟺ӠzT[A6aakDiE>J\U=3\c5r5:Ur՞تLsՔB@ ^2XQDkfu9~&OF6|\ES=U8Pc  /9:3s\AsE|Kr5]$[t_0m"YO%Om:)gMyKV+Xыh:"ހmbi݉?*먭!}j>qY ( 7ԟjS9Dw^c/fǓO >wendstream endobj 24 0 obj << /Contents [25 0 R ] /Group << /CS /DeviceRGB /S /Transparency >> /Parent 2 0 R /Type /Page >> endobj 25 0 obj << /Filter /FlateDecode /Length 2193 >> stream xYYsܸ~ׯ@0Jd=r%ڲGVrHyhyL P]Vw ~CWÿ/'~>^_|lcS8rwr~au~͇wOы ]n{RP`oW? DWoK0kGAT꠪ M!){W]m-:hVe6<]oòd]#;WI7\%{e{|@Rf`a 0NXp ݮqglɼ5~=1W/Ϸ4bTzۿߞfֆ5aV!÷KF h ?e_+k#KE53=*X0%`N@F礎t3`Dv('DBEK~k3hL3KQS$QLKy@`&alhKwym"G;ϊэ_|8x7d[>/kK4 OYi]ޤQ9a[k!%x3ЮSiu ϗWV`&LmmyxdtN $OG{p4vuc&U($f)) X,OUA"]%.t*d "iQ?vC\@.4 Te&A74I³l]=OBۖv, ݄6H2.Z 'P [pvI#%4@=W’?/fxe`K­.M2/Svb@n9glTMR+!XP\VK$0.҈!P$;:?D7:eݵQ=FIYޑchLy&,w@o)Z| ӴIQ֤[0M&ı`ՒiYԲ3)2=XOYf5&Uoe?:Ȏ,XC (ϒGLYfp#!O6z)uy*/L hc:W`-eB͹3hg %45`}Lvņ븣!d9+WnQ(O!bU$ {kŤi¢TQI lHQb{NiJxVb3s[cA=`Ì.2Ni! hӺ-O?5OAmo?\"|QonIƸ U]tv"94m:Ԍ8>c@s|kOanZY (xMC hB, g*Udpx}})h%;(PcSBŲg{r6O%xIQ(Y3$~V,dq6u$ įo=dU 1{|~|LG0cU;RZ u{4U {ǡٝCKum uj a4(˦,L%i7-c TtB' a=.Ďm@K3< Y\)V_֏`MFa-v #%i񛹺jHߓL]Mhf%u[ƙ)s~kZ-j`WpW0eȕ<7'>|o/X~p۶c4x.1 OW .grq hhDl̉pmU^ʷ)hS⻜?6zLHUBӴ9GO--gmθjZ~?c xwӗ=oK6$SV݁G% jӦB/J>4}b*55/ ~pf}WsPK25[V˞ `]L.x֕ߠ& =c-Ɍk;Vt>|>Ju4QX^|j1uoR(2Ax{S/d5&ayT|S(bZ>3jj#Җj df 62PoK(ɱ/BŴo m,qyߒ@U|F3\ϰ Yϰ| FP_1?P5䗓{lendstream endobj 26 0 obj << /Contents [27 0 R ] /Group << /CS /DeviceRGB /S /Transparency >> /Parent 2 0 R /Type /Page >> endobj 27 0 obj << /Filter /FlateDecode /Length 2113 >> stream xYr۶}WQqhg4udqQĄPd+n\H)L l0rW}W~x.q]=esur TڣŻ?]76=~ASS.ٺ@hA75k#C_ $<W^Qjrq8!]QrC!E"? s2gHb+yEVnbâ|tOrLs )8ƑMqJto[FYq߲r*WT0Z³.GA5kOA˔Q^"\i؋,cf' /TW/<A¢dk&!^4Jj%-xyC5])X3'xD7 l[ *;QyJ2VR[}3}Vk9O!_3jڈ,{qJ/4R ~]=83n3z+~ȷVy^W8p|yV~ֵI0|tQC=r#.[Vy"ux`/K 5y] կgCU>x3D7ط9銨X;@:*(U)rejKb2RJ FחLvG!\j*3T2(bh>fq6(b3ċ6G B )Lziۍ:t Hŀk|5H& /uP&dg'vy8>9"E@wȾzUW] lK JYc~3M^0V)w |u`rke2SC]$*DVrÙ9+ yH2YfWBJ3xr,`kusy}yM0]YK ey[.7,kNiA<izUsi">Bi lǠLo0tsM)ǐpdPG̨dS3U5z?@3#V6 F٪m~]IM˞@Yk1D!: Q`2\LA˽,#EILYu4-><-#GJ*E L)ycp"j> /Parent 2 0 R /Type /Page >> endobj 29 0 obj << /Filter /FlateDecode /Length 2900 >> stream xr8=_ujb0 !ŭ n%SKndw(a9:0bh}kIrwdߏgfhj&YaKkX."|2޼zfdN7^y H$^+$!:׸whM19eCFaC&@'P,g -87 @;WH5kB35[ +xmJl `z`tړVF̧vke4]4\bԆz\~0q0C q1_fiWK1WU&-b" 'uӗ@#H(뇦}(Rqu YJjj9]\=cr "Sy@k*2՟ĺGӀJ[ :lv(Cj/cBӐi:5:=Z/^A>v~@-$N&0K;2ŌYw%y4!*RMm=V$(V" dьWϳTOC⢳ň'jSM~]  9cz쭋'sv5%xcF4N@#ڑTф>4oncK/䏣? toendstream endobj 30 0 obj << /Contents [31 0 R ] /Group << /CS /DeviceRGB /S /Transparency >> /Parent 2 0 R /Type /Page >> endobj 31 0 obj << /Filter /FlateDecode /Length 3100 >> stream xZY6~_v &T|n屓xU[2DA#ÿ!)z8HTv6 G Albw=;3z"<>ӣBFE¹G-"[r{kh^=z<[b;rًsɝ|Xt*M[rŲǺ'=Wg0{Iq<9QmEbxG6A}~*ˤ?y0 :)w){$W^$#.I%UI].f;!]\zeοEI5llY`IVVͫ*K]*8MMjҙSgLyQ MF:z'~:N[E)'Pvh A u\C$/VrzK{fj, 𠯬V*{gwߠA) ;S媿6 W`ܱ=ofqݲlepV84k5ZJ0bXpmp9/T\ol"K~0)+*wΐl`6G&foh“/) r0TlOͬʍ!Wfo͞3\ŖUʺN)ޯ4v70m9aU4׳fYʙC]kuEuVv3LI1S8cvRCgd< %b4mExP6_q\ #&v1;`XB@ѻ el[Dl (OzGoq}r˳Q#NH X56`9D)3pCfo]9> u¹\| H. iCg.ёȅ#ϴ{f@X3kҹ4-c6-!ɴmZ#p钡fwNSV)2Q=}IT1|>a±4o?zBȡ~ޠ Lf;$A:[bW l4M# x׋.O}?GӀ`f}=B}o,b_FhP-%nst"91\H$m&mKc`xΐ'!Nj1vhP?P2|$'r24Cl.or'0ZVh\7z u:3bd,Uk3Fekc{\Ǽ&1P >Inc;;%EUtJQQ{Ru,nB+"?a?% Bp"#P1:R8V%.1VKL@py+#6G QjܣH];Vm#F !-< M ]䷬K`7J*۲Q80UY&iR= L3sbQ0״6m@f,MOYpPnBo=cp!:BR?QlXa9+Ūn`eVE- %@ @|A4{;umĔ?W^P Ra<ŖxxuOdo71Cj$~)lX0LTR{i wfL5Cl.bq˲Y@%l"nN0f8_z*NXfi5r` noq};\\@/ x`I_`yb6go!ay] py/4:xQ#:QqGck}^r@tz7!D$77YxnK^{E -%o5w㞁Y-vHEo8$ "B9rq(A+CKEf <[ ()6>` \' 3ETn'B Oe0 -=<`y QD~Pbc-wߡR2OEf_Q|N<ܬ#J, {Y%SFc9v! al07hqZK1w!w>P ^f<]B ]azΤ]~諚8XeUu&_I\]}@7,"lYgegF-K`nv~Op-ZM[BR&4v,+4jx jl(;ހHHHYC6%H^K#qfj.-D^gPP5(AG%4͉sLg27:W!X1l,rXnv&b;eN|4ZhS*F piMՂIX.CT\a%avei%Mu ׷hL ="x#K,;?nffGF)+&:;RɥڌXT-cZTCD7`qiY,&r08`ωlK3kdj b(92$LQ3}W/]G"ntK4,ncnlN TSʣ>a}QzP%WuiAdFf0 Nj+[Pqٖm"Yrc K^s`}xN p}s0E5B->ǚQTJRllZ`T'MQ%TL굴ם0U_t`B~zpSyUn1֘azjfiCSQ}K=((\AIY T T˯קYW#_.3M[3ʩ5=w潢GLG4&Y !uxHBgĦN@: 8XGhug߳Vo/ga|endstream endobj 32 0 obj << /Contents [33 0 R ] /Group << /CS /DeviceRGB /S /Transparency >> /Parent 2 0 R /Type /Page >> endobj 33 0 obj << /Filter /FlateDecode /Length 3146 >> stream xZr6}W UyF;][[e[֮R󒒼%Ciϐci+~nJGLN>}Dy/ǑCt^/$UBpz(ByZl-<. =ywq1:LCɰMfZ5ٺz9bUv֟ack۲#kqZ=dRsAȌ#p68stikS/vykK1f~r5]!1F?q< /&J5 9z\5pt4hZ(:i,0EM_9T|{W Kcy|fr jN cI@wAܙ.G4P\y[yhKbyߗ-؀kf!aa/z>K `wJvP{=OX&gyT31?/96C@#Z&2!"\R&Duݬ&%4zltsz[T7nFWU߉ʢ[Es[Cra絈h,#oU.Lc? -C uo6r~۵9i4嗏42GVЂ)Y`{ؼ?U5^9Eځ?Ɵ"x.Q-QyoJzAA&Rj r9$ NE}* ,]zMV6H]T^ jY`Xv(40tU ^qBXfȅgU nʓ"?ui'{!)vz΂}&IDT n&ST6<Vq!+c5",Ep فl%z0$~>jj\@D =/V"ut; KK|BdUiF(NFIzxچI{9}Zw%mZ~JL308PXuu5ٹp:5$-poxv{fu_hKZOuא#f?C$PZLLD0zw&DAAByߗ?1 C3r:""s I;Toj3"yQPz$@`$ids,eXlo{>&W۫o#P`8#KyQ߿}%7Ӟ Vz:V}\jJ`[1m9IY UgqTgGy9Uĝܸ .3wN^+߽r+^s9suY Oay1N{5Y7BA3!r:Ha&-&eS<ɍP/BA6ٰonuU@_[_NՖBR{ge?LtD˦c{W6m jYUz/˰hk #M C#0% XKt $Ԟ;n8ʊU9slzE_nŴ.\)2Sw9LIt'.z8 }!>6%@'5d5e#aݵ|(l  )W2AR~d)sf5e9^ѫΪ6nShQZa?:g܈q;3I3B:-#`FfEj$;1nzi4[m?tӟk3sq@0A!h>}'7AqndUH=;~Lf"~+ܝ JqAG7=]s3]Ѵ,m!'Ν$nZH6u%>[mhG&4S}()05DNokZH ]ZYKqzEɪ \,+U!8qROx]HF6]z f$ףRendstream endobj 34 0 obj << /Contents [35 0 R ] /Group << /CS /DeviceRGB /S /Transparency >> /Parent 2 0 R /Type /Page >> endobj 35 0 obj << /Filter /FlateDecode /Length 3247 >> stream x[rSdzAuh3#ˍ2DJSS%B3U= pAک/:ر],vPo3]P-u=qN~&_ߝU1u%,p\%wkX<9{EBa]?~r)y6s[Xr\0%O a*[ƁT` ")& 0餉$sS?rU|JHY>fe],'v&//' h8@rub`2LH01N?l͟lxSf59m]/wIy^Ʊ|,CY>?z9-ϫΤP_ăiފ3ERqS$8Jy]6|`n{O׼xczRGAQ|0s'ى aDŷo6 31Z{pe_ly^Ҟ(aϿA.}' $*7%xpU%jkzXmx}9Y69̲ʮ7W+5D}1LymNӺ(w*/@{E*=%֔Et\y9S1 YĞ =jSaul%}8N$PDy­ 7.<7q叠b$vVrb1J>^^FI_\^\aKkTCl(*,p(%cHHBխϔ$Y҅wTz7?!b\h}]ksQ0˟bR,˹ ǚ{*$_h [%XAa%'\1tf^Ex|ph% aşhN Uį.__X!q+hQ?I~ `goq )yU o:>SR~Ns7)J 6+N>8 &5fr}a3 `7Ire^E $r$tYFAŜWǠ{N޾;%uA<řDSp BQjTkaFٗ:MnM͖#Hn<jʪt1IRwC:ʕeKM2K4Ԑ@xмbu $L"kҠXSF)s雛3H<*3ӻ6G8dUg/?/Fpz` ]ul >+f.1n|Bsށ1Lc|w٩Fv V_73KBK^iP4(9A"cdPj65&]5stV5+.jLXMO<'Ymw Hƴ' ]ސYyv #!ZjFp>FFȏ8|v`""94 r|1'(Q U( ͓u'fur# ۧl%S쒯Yb]4qu;h ~fR d㆕Μnl?I!!j ]HVyMzy!V2;VNKu-Ţl^=\f+ c1ǵ| #@f˰dUmf4a-TR;o1XDrsB+4n3SQYvd@i)ʣ-?Lz'2E^-v̉3Uƴs)!v %>1l͖{mN<!tN;QC)qE5qWpzr .%EPwϥ( ~5V~ݿ>lAjX1Ryeݭ7G0:wP-ox[7' >i;Qh\Gu[˥mlDO5&E>0.^Ć֎ػeboc]{,vFY:y捽k4'ڦ$ %L KϳVqhQي=bzґY5,Nv:ؔRPyT}X;c;5' |EزS0̝oOQ4!rIXչ?р68>4`,U-zíǐ, gvoВ,I<[HTPx`j3ڝrlaJ_cb.؂T!RoYUij,l6,emRΈ7XkUr0 F+[b!m le'mT7\ѨK\YaI8kuؼ Uێ:{~` #$BT/YT9dG:naXf}Fz)؄C)B=.[+)ϛu`DnETmZ{Z/ЈXzJtSqg&e Nۿ2uieMc? AdGk+&V{nM-0&16ʃ]{WY|@NvEm.Nش3LSOC]ЃWs4eָ}g}cUg~̨9̙ޒ.;x*WT_;ɾS=}:pe^XXLҢ,('$ehզE[M FQ4^MWfmYPx P`{lqwj:xn]*Eg=׀Gihe4lqVDIvՉ+gcU]^o]M4q ي7<\鏱57gݵ#vҘa&w 13s!T/ D-ǑB+Ouww*\\wxJ{H"z}v$} yr 26<a!ɞfx٬9&nxD (m> /Parent 2 0 R /Type /Page >> endobj 37 0 obj << /Filter /FlateDecode /Length 3239 >> stream xZn8}W2eBA2ǁ nIJv1QIՒҟ2o$j+H.{?Az~9p3+$8v]`;!{^?[i!z;r=LLx3#7KɇMgo3~BIIo}~I$uCtEOFS Udӫ'ggo.N.?\K% q<b녑 d0fKk^ּ}QCÃUҟ-CF [T-YX|Qd)cǞ-INwtS!?tz]5r] k TjT/TD%&Tے<hϫycT86rSGHH!KW`Ӻ(A/'j8SyY+Q"yKi'j.c(g <JӺ"ni_Gp'9({OjpЗۍj^ˋ?<=m@<.f;V >37j% | ^%rY2Mrt'Qk( 8JVޔ xP(-\\9%4/uT @ȀO_ ӳw|g;gHNDޜnC~S&' rH[#7#u"]8 :)s 6f8$]_> /Parent 2 0 R /Type /Page >> endobj 39 0 obj << /Filter /FlateDecode /Length 2306 >> stream xYnF律!c $.8v(Q#1oŎb g.s$m%5s\7Dʿ䌠뙁mxf_ξWg*`60 J`W!on>{X4+vAn_Gś8%Mkr=[=W6}|4$7:De~ĬDQCa],6*XXe!=zTGGq.*:Tu9514+aeqV2DeT0]%3E\ jImu\k/5%tv U/ĜfZNi+l˼LX4p]G=ˁ#p*pM=1 d]| CtW)JhȮ>d0:gݳ(A_yfQz-i`+O#}mTל?IqQgg</Z&U򦡫eOA1ß ~{o~W(E<6i"֠JMg0TVO9<70AV*Bg%vxq)0d%{59ͮ'bK@6Q,<\`6L k0E-Rs剦j)7Ϡ񺀮19Th$}xG8&`Mљ )X\E)d -G xM!#IA6_ n((-{-p~ 1ED{y=˘nI KtTuZN_#IbBÆŢ$&KƢc":Ȱ]A_$g&b6$(%~KLM63?L]X:MUMņw轺2:03è,GUz=еV|iQr sIϙRv_!,`(WN͏@=U,~0sBŻPen:ĦK(eŨT8.mKHmc}SP7#N0vFL`g) `Dgqt',haŁi(ZG1$lIS@%1ÖUw֘}|yyCQw1$Rr{pK!pxR_nuKVjH8YԈLӛk~cQ`x7TJ7|Bէu \e t)$ 2⤎mk⁽V跳d Vendstream endobj 40 0 obj << /Contents [41 0 R ] /Group << /CS /DeviceRGB /S /Transparency >> /Parent 2 0 R /Type /Page >> endobj 41 0 obj << /Filter /FlateDecode /Length 2981 >> stream xZے6}@%-yx)b'LjJ i`S̋JjƍHJ8I*v@A@nr?݅^. }}w{w.NiA;زz&ȅ^~kɲ*(#5ZZ7]~=Su >AdSʋ[)䒴L~?p*> 8 {BϕGЫXAAHyLb/r'ښM$lc)ʶBK>Nlѐ*~`{Z hMDyHP4tgfA+dSG^,Oqc \6UQT Ď+c=]ADj:.;U}hOϑv'#hB)Q(P7}Byկ?brxHKwsg156U\Ӗi\ {km,m,E\k>FVIJBꖬϘz:D/2|f[-ȗ߯y7_F!\<,0m[+KN_}A2jy2d⃀ 6|TqF>w"VAZ ku& W7|A5/L48|d~`e,@f:RH]hS,OA^[McE \(JkHbhiDKpt|g8 O4Z߫)/c7DGK!3fʺڶ!IMqF-fR>Nh'Ն @.-/뷛}'\}#'*vFCD*&N+J"&;?sCGcUtp;Ѧ9T#r>t@8 . J*Uc5VJ3s-5;o{6b-~v`2ʙ8J Sb . '}P/# C[AX|Kymtmb匽D:yy vл3_4lq4@jȇŌʒuˁCv>g}"ٶ:tơ6X6Taৎ h9U;E4&NvjbI#7 5ո|q{%~H؝O*ZBs;arCѲwڗsU()ʹ,`'͜6[&SqܾJ?AJu@WTa þ_=pEFdsMߎG6j/t'Q6ÙNA@"NV22'zq7 p0 *fW=H=*<9ȑ=ˠ4,;X-XiqLX񉨱l4bcXy@ΐ${e儓 :BG޻3#(G?{5AH-c^{sYZS+5Ke Ѹ9k `tTʤ퀦XMx_1|SUr*^> ޿`֎XKA*K0%v%f/yҔMnqSW^v<淖7狟/5 endstream endobj 42 0 obj << /Contents [43 0 R ] /Group << /CS /DeviceRGB /S /Transparency >> /Parent 2 0 R /Type /Page >> endobj 43 0 obj << /Filter /FlateDecode /Length 2712 >> stream xZn۸ gmeD%=ۢm}~%*[t.$75(gx tw p7|E9O\g?s0EgWlygGAaL8hY۳$B7\zͫoIɟ5LL)O9ɝ|:{gM]rC*Ε OFw>PCگĉЏ<8iU,Ъo|ju5\_%ijP*ACOrG]scE\$ '#_ihqpDd!H"|H$=hhv%ɔWu\ƙW wn 86n\ŏ6NkE5m3(꣹Ȫ orӝx/:B{#h'=k'> /Parent 2 0 R /Type /Page >> endobj 45 0 obj << /Filter /FlateDecode /Length 3499 >> stream xZێ6} gѦEn`6{cùbb&%2j#3/yn*6NLuX,V W7_~`.?з*$8v]!- SY]K"voRr+r{LWWEݣГ|/~N9%(x &W/'7rU8aufST5jw ǺfejO Ue =Dz yެְFb33T8JT~J٘`攷[t7֋:SgF?3ϟPWn(E[԰rdnb?B(n=8y? Nllj={jx(J Ϭ#*$ۀ`Z>4lɬ>[8dXS q2 *" m^EK{iU~? eXX,>ȖŴgzAE1uԸ}BՖ'B*9/[V'ikspQH3fh_e h`ݵ`cvAق`cG8lm`uvmgn 5YVd#:`7OHv75,ؼ|8աΓfNJB+elڤLzY$O[>g’̢[UW O[X7\05eiRvh*맚ZIÚԴ!B3~XFmT>/f/kMO='7]]ֲf4w(bK@:¹( -U~P xKa3jL r:7k.p4gE7bL2E+"8s(N]%$:[ۜYg%oO(oF{O5m^&x%yo"OoE^>`NGB }I@y( 0uB%UƤiƄ^yC3broxA#WWE߆S `9Te=^g iW5sAqDy??ʤc%x<7S<ۉ<(3:4 O'PLlz6Lxe,_p6 >fg,[%3A9;f)/lŁiƾF^+t8FU,m!d153̖٥cU!=YUZx­K? IWDìHVeC}a'FKEۅG~l D d ).=X:ca0핈s2}Uvx*ІM;cmf2YcCE8"јn40v\ eAۺ jc'tH҇q=v]{([H!脱4(}<^-T|[2 -thMR:ܰTqB Z0;|1HH%3*i&)y!!iY'΃Jndؾ V㞴;#jk6O"x"?Eiq\UCͶZgF菦ь&]HVmw ͰPZ 3jL8aUU>K楌V+sqGq 0LHЄlDy8kiLn|z(BTt̛SG|aDd`zN`9zZd/X2ݩm,wID׊ Yy`afS'ͩMd [-DPĴ'q<;>'ґA`(Pוc 1hv? F?gթ<7bjԿp=l"s3REZ*ͬ7iWڹUz Ej agR_ߤ9oppSKB~lSo52m)k"aRH uP?27/PJwp]R޳^d~ D]:kDw);;>Xjhu^(3&"ڣM"f$^d8#:#JdbWAbf}Gɩ DkG%f̷M:Yz?"mf8Ws/`DM;K֦/IӜ&WW3 h42PLT܏ԄAml8P%Nask(XIF I]"ivX9 Cƾ9|}oyc 9<;KgK!H"\{cu+ʝ.O's%<-BK/E Kx}&)ȷXG tJy6ߵut7Ψ; .CEt^/ew|ݽp19kd2ƽ߃Afu=0pJ G(VWu %u N{9HDEndIҝ=If$S03K,O,X QeiҲmh зit& B&5&FގFU!**O[^.ݢr*^/ŸL1QIzbձλqǩ*oUN`]_#6qkrmbYQT % "lb[^6ugCK}N{g/f)*˓8ՕbVr0Zp`Qh,j)}ӨChۖ/PP?nP=y `1.YX=: "w2NdRwn9Ƌ>uZ˥L{'V3#K~(-;\cj2gW)'ӅN~Q4&6$ec{BWݱ -H?U}XtZ =p؟+?M!C{fp^a(Sxіb$Tv7ޖ* <0ݮrȍǓEm%,DwOUfEC/M[ ¥c6ư&vL3ŷ4Cm̷%)TYq+2LZ\Gy?P+ՠWqZqԆ* U}B|ڹD\~YnVploGk$MEⷷj;˃Q') ;qE z!UgT)>KHw,׈:UH,oW$ouk/Zendstream endobj 46 0 obj << /Contents [47 0 R ] /Group << /CS /DeviceRGB /S /Transparency >> /Parent 2 0 R /Type /Page >> endobj 47 0 obj << /Filter /FlateDecode /Length 3022 >> stream xZܶE}h:;ȹI}E[N*JQy<(~ID힛q%wD 7C0r/0~p_軋_7*N(Nu]tœ8A^=Y}WOˉߡ4TbFx·BXtmUn*#֍A2"!%yP&0Էzia+/`#/;>k}TQ}7U%Ɯ߶gN2 FxƷ$$sK;ɰ){.2;A +s"*iW[g5#(ivW)i%PRKXpl7+,dz&Jew}7m߂܍"ltᨦ ݬھA9y/3MD#8Ϯ:C<05ḱљzР3W8\\!)ܥt0 7⠔*~FS8Qj!7yל6t|Yl[$8,Gq &~>: u8ow=v%̢f3%mV4FYՑIy垁}"ώ/ei=wP5}q4_SN3x$\cClm g9.6 9YO;RС%+]@{X_7Ӕ-pf1 t:;:ʮ 5`7dQla2ęFT#;&)w yvo֝j^5l |}FP7mQzNjpTQpT28H:VBhKj\a.@;}ba^(y\5oɩ]C09(={t xA,W6UH@%O╏8$qPiQ}3v\BVi1ݮ2c\516-JJy8!7w' VH5GqaXFڬꉃw e:YE.s iYP޴͞;P ưvfiLnAa#I2n/*'!wr|~1[-̒l ꣇f*)kh.PC#کgk!?Ul- :Q- Nª7L ,tXވ>0v(doͺ5WL \ ؤУhF\pB+&n:8 =I|󍲲bqhY)gS+)͡@{F b-y@}P֡Ch_v/4/}ӥ04 \F6; h-r7pB,- >._MSKTUsxnvdFf"ўUTE gvI:S#U(VIjDc+N=A O9s1M"fQ'?8rXG@: x"F~tԽ]F9eU b m6g렗w7SkC'l[d|s  0E1e 3ciJh{gD蹲 EIPswdf GUrP\6V%*Yqd0כ܇c U\MmdN7`Pe; SV+; } ]f!1X]-J,B>^ ,k{!FgZ)a9dq^dM%%^Y;q:'v!C\d‹{M:q1[MgS%;.~5=J0tU^|)9^_?>aqzn @(]0֋R=iXڏOSpRy't62綢*Dۋ $r**Q+k;^_1S,0M*/O?] endstream endobj 48 0 obj << /Contents [49 0 R ] /Group << /CS /DeviceRGB /S /Transparency >> /Parent 2 0 R /Type /Page >> endobj 49 0 obj << /Filter /FlateDecode /Length 3094 >> stream xZr۶@KN/3v.m9;3(bL IEQWɿ>`7A3jX,v'~g3ݙ}@gg*vq8(N8_n\.a8دQ%rKMbd`jhߦ%~z\녭F<vhѫI8 <(z6{]tdA*Z>D؀ir+oG-E=lsi-$rw݄4hGCǒ1iAIa09 >d@>7yK ?;w~YDC%ͶEy"Y\R@dH5x '7nMw#hTJX(JvcQbbWӏymxq=i(;5 Y_f[Ӷ4j"Rp@YK=^2kpGOUjMjC'lX2J  B cЇZe_^؋ +1dr #Ѻ)P =`(A ',ng5$p,@Sx$lu%idk ]]pGn/sѡɕ K"ƑRA1G ֜vþS:@N: Or1 #fLL.3?:r:s{@AOoh`OÝ$=bէ`%89X5(]|> 'zRx_*Ku)rh=,̚AؐHIjz?Aql3rض> RuleX_ctb'fli \DS-+^k SԃBʗBAٶfI@xaJ|A?macNi@a=,"gO0ٮA%Seҁ=7P}T~X *(LJԵois*m@/$gQ?X:,nz9 cypUt'ސP(,I㔡 83$sDD^HLO Xn5١;MVT!}K@)0.NV[KӞ'>lҞyWU9S'O-џiImUPWX1&=OjOҬ ь5*T)Ɖa$;`o%ǮEIS$KH`ҳ֞juD{uP `;ſP3-L}Gwi:/!%=ZIv˪L?joNRAܯTc=^a|NW7ʪޑz1)xR`ߩ'Ǝ$flʈa&HV;7r,k.- En[^OAŭ CQsxT~a*_߿a} o;;-:^9 rGӻ2:8q} W6xRW7l1BB7!G`܋, [^m⥟x酇KQǬB_vPB@0"߹Qr!qߛ(E l:-*DM\ĩGtaZM/Ev^O> /Parent 2 0 R /Type /Page >> endobj 51 0 obj << /Filter /FlateDecode /Length 2759 >> stream xZrϧV`Z}T%S[JJ<]CA.=^vgؖ)a> 'z?'݉^|@.O$U`k r 42V,8ฌ_;tՋ7gYd2wh H=I9Pۅu{~&.*GopAUM)W -;cZ.b5z).HF a9k@q3:~MR!IcJBޞl[oՠg#VפnPYdL UwG 2p~-"Z{H2R?pgPV7Ⱥs6'*aeF !iHrͨWTWzq23p6J /P%͢N㆔.J6 V.v,j1ܞ?;UXNCgӰu'Vy  &m~Ghil˰{BRmZHF;(:ӡWpvjYHS[r+ ȠZ.WqY<DZk> ӛhB)=ƋY| h]T W`vl @  mWo̖eD!qG;*0ˎ\χdnh.v=^suMʳ=c#WfXC>r%r@ջyS[TŒzb}-k*۪&)X^oo  "?}5Hj]mu#6+&Vh9l%dwb2h>O(쟺M[Wnh KX*Tz213Кc5WTZü}>n" L⚾h)E]V[\ E=ߥJ/w\6uU 7d ŘzhT6_ 1W4!~7ghk~c'A0R\tsAipDX#Cg>IxZƻ|Is]gjſ-4#׉|9(u`);P[CsDd1.s3I8ݛXT1* #Ohيb7B30#=Y$ILv̷׺w>YF,XI,D} VhD}/``6IQ -V.PVJbyN@1ϵBHMF @SZ}cE#ߘQ.a2!Gj\CBM 6X 6kl". ZJ>9hjLV&)oɖ KLt" " n@Z`u WU;R4:uxˁ^+Tf4fEut_'Z-3E8NN_]'5 ÁPeynt#&P`ѹlQ s5$ExtǢ(y4 G۰|Wq/6TBВ/Tgu9K{j]Plm7t6häMLI>2u8 r0E`m%F#=cyDz]yU9.pB,#DhwB[A,{fNf?yq| Ӱm eK*Sd̠_b7}_/[Dzhq:=@Ŗf-d⤸mYش!^\eiPrmU26K+2[b慰IxRp`K{)0. R|{u |hMTO7@VΐApD,U'CsЛK8+\HJ6 0q^L@8?`6"A!!H:p;u6$OE9bIdݳ0a]6r|/ҭ"ANJQav8JRX4HBw~ W8Rq)!Udi㐞C A$ D򜮟AA4,(³]Lܷ5Ev?;ӯr/|#1'cyVu+EyYA(aBb'9F4H8#\B3mgmZ_ Y>f;fiyzڶ8,)L?ٿxzӻstO?[-3(:sUq~hKOg L];A|$citB9@,CDsBnSGy5Ρ(z!¢,'X3!Nʑu6 ۙB~EM|峿*̷2Uxx k9Cރ7llez7#d*12 xԄ"0ŷLN8w`$mZc1LBZ} fyUyg =zf 6 Bۅ-נ֏n7w7r] A#YIw^Y=ZOtN9 wLdLXn&EDGYH#dIeSVg(d89 ^ٗ,ÆQ.P(c C_7mwhrY+,媍ZrD?x?7Hendstream endobj 52 0 obj << /Contents [53 0 R ] /Group << /CS /DeviceRGB /S /Transparency >> /Parent 2 0 R /Type /Page >> endobj 53 0 obj << /Filter /FlateDecode /Length 3833 >> stream x[msܶ_ѧTHtvi7:C<މ,]A?IѤsD5:saa]ue1ݽِ%T }Yoz=*`۱NѮ$Mfڋ[{X 3Eueoul9:Tuv@װr׊/䩗&X'f8ž\ Ɓmv>&&=hk ߫ ]>ı0n$' 2t*tCzl3Nrհ֠' j*h;q])uLn4zSmvY)O!I)}4OT1‰7C}H/s[ ;  (*1D(vwǦ1h$_Op;]lu%R(Ԣ}W34y̾@8FD ev]RKvY#h y;͠WZ7M=CBwUwSmvlϡ®30`i&KoC6ǫFLPmlǎIїd٬ɂR3Lzm&q.%3 3QeYqUAॱeOؾ !i7)-OaZZ}8[%[&]TuHbe\4\*%Iо{W]dK?;0U#Mo!b"%銛t[ $6ߍS5|i6-}Bv2cgoJؼyP:G U8).&B$LC/?ݾ..x1[6tuhD 00kr az b9T tߎp3>;N)_@|]|%~:Dڙa,@VK !tOuQƤ: YIDc4q bf8 spbTb0e.Q}$Le'P&a|e94I1j a)O|) 1&b%ZE㧄u G2f4P\B h`bk(<^o3فDyY*^g44Yrz- `ߺNx"!%릑bPfe.h&RQ暁=ۗ* 4 Q93J=qS2`l9"{ZaFTzhqa7,G$x7TcOCqI{jrwH@eƜXD: ˳g ƶ^$:] bl,KΝL0YTpV3Od1[a ӆxjl +@Dѫf&.j{3ȚH1vuqz>H$3h/Β qhtM";ȶ\EDOE_5[.N˞Kc&LW)pʿhL}@R`qjA@lØ)(^Y{8'EWH3oFQ̅}R-P" -7 YUl+LpPA-7;Xw+b ؋p88R BHpr)U$~scTY5)*y.`IBtK }G5ODGf*,#I8| WsIq *Vܠ{kӎh,KONÑss~VpL /MBKFVqἆ)#;=7ɑ6gU,P)|zȅJwh2)Szy3W騍nֳT+KΥdo idiOpK<:9Gԣu]q\U^"Ў֦S\uz0.ͼ}i%XT<]Y;Jᑈ!ƏdOC>uz%[̈́ρMUu~nhr/';p2A'ύs=8S)$@>Dg'B渡F}@iotE[Yށ+Cf ZWg글i>3RꖨL{+G6`3+|Ø_*r旗藓鏻FCSj?  zү@Uw2QApdGcgNuPm8JR:#/ t4˶WWm0>#I]5oAW9/ʦ.ʞMKﬦ=;wes N5dSMA?:Iwj\X!lԡ.f*̌h tLhLu3b2%/>Foa1Sk1qG9ɏ8CfڷKLKɞ#x,&}e9j%Ֆ5K> /Parent 2 0 R /Type /Page >> endobj 55 0 obj << /Filter /FlateDecode /Length 3183 >> stream xZnFh`dZl4 8If@2GCC2<< '>qdʛę:/?#o \B\4Tm/ads' wǑܬ^~*0{y NC)9 ^?I;ô?gK qpR$$U_5zeTbMKM..lusg\k9IB ~$ҴFbObΘ?'!iUļ$E>H.KMo|Kxv2}1%d˞B@2fڞ$ SA=9+R9نUx|N88GM{КY#Wk~UVGmԱ}.e?ÊQ]0KO4:ȍSη%20ؗoפ 徾Cm8ς48az5S(@`d(S%dMvUu~ߤĚ_C5 P3e[&eίf\9(8]oGp١sA1;Jb Յ]+ $N!.Vcu y?Ψ 5@rPg54f|mr6vfXV3 FPKo$$HCD$6rD|U`ФVk: Oz30 Ah]`Uqjd4<`r?:hEnm|y%\}"PA e3^8nozJ Yx *k4H9B) icSs8tu{LAs4q >L$Klc5H$Va?yldH8Ŀv&kTa2 i54ԵTّܽNS I? oY=̨ .P(Tehe`wGǫ$NJ;s&{T"-fQkjq=+su9ɞ3>F'OwǝOT+Bªΰj =nVB[hǑa5ןc\E9gW$'8T97f۷'@m~y. :}/"y.,;e sd̦^?ɶ7;iz2N5QS47y\hSEˌPi ]L;81\$OqVWߍYO6Ak`HSo̡ڧ5"Em@jU=BaUu!Ǡ_ yaOK60LbZ_ޣԩaW:]1vp`gK L =X:JeXU837!° DDacKz2y"l_YLs~16 xx Z{ZpFkw_kqgF<]\3h΍Rokj?ry3-)uR )CN)|("k*V+tÍH@%7v;sjt͞π#s-JV888 YqqA+ڧ#iu:; PMp- #g 40H U?x 1o`T`hXu$OI,{^5~SX)U}o9W5κ!}uHӫb5!+z/NM*;j_STɚ$33᪥g)t}#KDY_>~A__w@X"Lfp+Ng[j72b95o.c*.<!Q)ԣӛՋ|j =Bwo}o9M&^|jVA^ЯxK|fTzn?.5?a.d '?չ2QӥOxSWWo넘Κ7G ۘ܀bWŏ endstream endobj 56 0 obj << /Contents [57 0 R ] /Group << /CS /DeviceRGB /S /Transparency >> /Parent 2 0 R /Type /Page >> endobj 57 0 obj << /Filter /FlateDecode /Length 3324 >> stream xZێ6},ڴ w8ɦ}Fbw+֥#3@>|${:ݔx)N*WDꊠ/WA^\^(8hSA$F[hn2 }Xz5z8'y ]S:~\#V `իV6iWbksO)$6y6he_h1 AL}f=EcuߔEʢe-M{CvVc/fkmr忿 D?޼\ c=?,$7;-{-}2ϝ 6@#V8N9%=eVt=yMEO۴,UY|;.XA)uYg;to|.Zs,m^ESAi8h/u'j P|zu4;XUO> \`\[,s.<VŨ2ͬm:l86 LG>0(ru(m mg5wMyńk)T0(`2 ʉ3>ޝ߲QZKg&S GNFKP!e96e%3>aؗ2)yo(Q|CfڜCu#_XơE -hJh͋;Ɗ<'g]V4[N3{&NB-ITomʲQf8 #1uͅDuZQvd*^Zt*ʒAˡmCT0k54]Fy7P 0BDsXiuL\o5 "ڷZkT> 8)Xn6<',ݧJaVeJz(db[ϩȁ? R]|}ngrtC`b gf]D(ZҢDgf ghE׏*B8A\_FNOk驲`w݁fĄvjñ#a@sDۦE@ؓ>ms lCӞ uz6-VM5E ㊭ Fu..HFPGaw)\Zgs{~_Ks-f~O<&vRQe˪|nl`Op^B\#54EOc?mn9nj֐tGL8Pf 14O^ TڴukD x֢v]`mciA܀OF"k;h"QiF[w2Dct[  /9xNwk{9kU >$v;Gf_=V1u?xwk+\^2Vᙍ9ͤJ9ccR}d\ gE%^5u{͏ 0ȓq*o=7* Չ%$} g (~,vH<{SA/'$XD-}cBa汶LQTb7-\/"(Ǻ~h DSIy%>-c.TNqP&!:EmyEs''1lL4O.3Tm <:H,i/@P߶˘$K=֡[}B)#6WJ9VyOPEݓY3c|oÃp{9p^ooeܵip yfw{ơ)^[N W@u{0HȨj=8C3#=diǪt}qU/93. G5`ݡsAɜKs{QpaHYp9PQS䟰Pѣ `R%% @Rb/xa8SX."-vZqf^TtzxryԑY-7;+nF C~(I.TjL5@Z־t|ڦ[ 29D޳tAz?[ pD;0I5- O+7P]|S +Ƣ ˫yуa1Hp$+CI?C!./%Y $N,).z8_u1O0bV656KB /N@tH5VO"GmZ ?OrwyQZZ Y@픣kڴ!t$fE-UNpbP%w[nn4 HN&f<'CѺ`tMON>ƌIRst 8Y'B&0 Yyd~mjABGoF>+ws@Kkm3xIrp 9W;A`ZZv뚲S?A4'|PIp"ظ5 Qu3E/AhIތUY+iװ;{뙽ObGG;A4T)ܧJqkT apaxVl]ϝuPQjuD |X?[NOcƤ^xzm15^6E=ubxJe;&װ]3 K*'=d(abtZ.jWZϣ4BbLƶKQ >/>QQ_KYR)/='mTsAoO#@ P@ D6CUm4+t{ZWPDl|y*h.\ +,&+ėQC5AAE[cr]UUStF6a((XʢW4 C@8yly SU!Nхuvt'>LJ}d8xovIH#aYDSȤ%Ög?xat\]$ ietv3T4Y ĢT%"<1RȅX04Y77ؐ*Н563\4A"nAee!aU3aGg>}s{cJ-,Ҏ"s(yj-j;It<<|k{;o;")_m,?}{,!k*$!boD\=pendstream endobj 58 0 obj << /Contents [59 0 R ] /Group << /CS /DeviceRGB /S /Transparency >> /Parent 2 0 R /Type /Page >> endobj 59 0 obj << /Filter /FlateDecode /Length 2953 >> stream xZnF 0j>Ž= dXN YHEqz4yx>_ͣ%-1ܜbuUuWGd# řYC3 xasQ6< -BH..ٰrf'6o(Fxo;t:vNC|CO]Jtu)#J.weLV &3̮j}QU2+PRnQ!m=`}dDb8/=#c'VidpoErR&A|Hسy~1)^TvR^0qb>%])6xZ/Ѽ\od64`+AcFAl N;Eo77{zg&Iҙ TFaX)HfVIWR6mJO):UVmc.=ж*nPn,iaq3jK07֖V+mG/[jPmUVbKd9p CBX 1 :r5iQJ7]`=`bK8PĶKڒؾ]4؝NJBwب+ƖG^Nvb'i0J4ص@(قQoc@Ўwhe~e|s9ߑA>[ihxԚ-Ɏ߀Gnޓ33ɩFcǍ~y~A1ҟ N{B߶CS$<#o ,dgHOe|g`mq>'n'AoB_of:7$KY$cѢmNe&.X.ITkbWnIO%>CKFs|^:vA%0A}EN$;{vpl)[Y鋋 |\ `ƳŎ;7'PJ@x;3w&h=D[o|0}+Z"*   DEYMJiJ( ~pp]1gڪa"S1XaЃ;ByGrr|`Ϋi@ګ Dh=ڣ4s}F2ѸBQ&"?RJ ⑃##1eyÚ!r_dmz;VETd C YzPu.7Q6M1®5/<I'`MQ1?5=4 )_N|'r( Ϫ9u %9<x@g`5fJOዛ8 Y7iR A!4b3ߛP=@TV7.}fd?lUqYm2O-ZtިL#;XsTIFa8=H3l(RQbw3*U~y^p1~ޚuM/Mnd1'Ù<"5 M y04Q~k ‘TN G',a)TDm`͓T d Z&zza1Z|LsJAxL rPnn|A`d?vs'xe俘Nw+B aC\=\HS{E/I|)ۑ+s}&a;ray9`+9PlԍL=_-+f(i{&`7+e @tropL8kRD+ʧ{5ff8XdNnOn; θl6bxNEpC[E76@, !t` Ց;_1Kؤ+-LLYHȉwۑYbI9-zn-+;X(0ƛ];vSY_EU e5/蓆v JDUDw" v X2M]=ʵ;^M[.S#YרĈ[uHY,"É(HY6sT[*$jYFwaK?@N<ؗBZOЛw[snTVвgE&@N.O)k}ڳG(?6 gNʆtpC0ꚰoXOZL).d*IĝҝX`\e mR>BodAVSJZS+[eyscv$BR0>Ri,9OPSZU|cȻ]a*(ߘ_ٝH>rpqz=&zݴإH.xM{p/-X_݈f#zyLۥ-f=TJ)$t2a,?5@ߴ̦N}('V28=v:rA>4s]uwM b.3SqWV W)Has-3JD9C/YФMVx4Tb\]Δ=9Qr4 }|H? fDsP?6vq{ss#=@G\܀w4$ꭠz)ID0oֿ~zsaNwo7?;ؐKmݏ`(HI47{ ͟M2Y-)SU̖HalٗZ1_w 2y@^/CǁƝ]-gc_{&Ұ{RwGа7JJ(nDDrlyO7S>*W߉Fu(i7=h0kUwDCG~ndNCO-f˰H~qCv?d6d8P]߳> /Parent 2 0 R /Type /Page >> endobj 61 0 obj << /Filter /FlateDecode /Length 1992 >> stream xYn8;DݕN&H)tfXS]\Qjl y=$%[6A;9!LU䄠뉉tbOޡ&')1:4M4I݉r \ܣ˫g!zk4yG Nd:D_4 tpGiZk%wXt<C4uL(np!2GJ)&lh ::8O±ey~ZDY+]slϜs҄@yϓF`Uњ[u@Q p>Lo2^٧Ճ>,CqށR|ljxrZsyǗoCKr]4YL̺RuQ@u)bhDgYYT5KL+([()h֞e VE槆_1\e[>vN1By_q4FݮL.r ƫ"n.SQLxlZt;׊:]zMe?"v{FӈlZL5h&0^ԗ@ZzMj_ԶI-we48w$گ, Jx7kv*DuXsX;Y-:esaskȚ%YQeZxs}DւG:n ɌB*m6k^s]V\L6#IgUA{G1<K\L:nO2 ?x~X]4 /KI5L1z#f%5G-J#R=~"4\]T968Ci|CEʤb- ?p=yp} Fp+Wϙϓ .Lg0Gs< %-BLBrqz Ԙ?4`$=3o8~ofdqE 90HLe0Z0Q_Ы&Wozzߊ"J=\OyYd"/E%]E *͈5,3IMT,+펆GjF#MZ\zz܃kzvp \f!Gg Ù5W%g֪XtVYcajWcfmLQk=T{,{msUZYs *j`Xet-Ϝ+vmSG9o#ZQ݀?lest#0SMl_Uc;pVFR[TٽT7L-4ɟf/9<)3;g}[A ];&s`S}tA+!X'wJͦ׾ om?8A!> /Parent 2 0 R /Type /Page >> endobj 63 0 obj << /Filter /FlateDecode /Length 2510 >> stream xZ_o6 FCkN;^,K]58ϐ~)J&$E{D gAo죧3=a}"cAQcqк$F3[]r9z8B7~4p?G_k)mJz#{.` NʅCڙM>Ѡxk5m-iZUTҮyAuJmڢn} v`]Q nɑɴ@M[,[e)5dVisVwzKkㅵ?@`dO8u #WE\oJ=T6X/OnoWT p'Ouc r,~:/hW~*ZHw%Hslc'ѢwGb9J3γADZir m1Ujm"48ʷWu~\-ʒ8O`? Cw_QJ~CG9o,I.|2|@ad>:C}kCd%lN`HBхrFZۡT"T$>zBX;Wąy)TXQ\[iE7I*pSJW~&ӤW_A4DL`: Y}u˞=~!H\m2sSy9&#Zg4%zۡ]a[0\8}HEn! da٥A[T5/TY=|3z5buVU %.c]Xb\6"\G:yv3 PχX,ʏo *J.,?M-WOȪ /d/ Z^*R}!V>,n11weC!JͱupU5LGYiyM3mLLUw;TT _N @$9>J"oۂ-+^2,zs@= #R..3ğ(?l@v!AKTk 3^"~dRy O*G nʗҳEYӧn߭dgȭ$Y7:A5bڥ'tyK͐tBn[H(FGDԶʼnAkClڃLP`~kuͥ-q0{t*_b2D> GO2sjr'z^_omѦoy`NeYHH:Nh:p/{xuɾ#t|!nE\Z߶|.#U-Ǒ)dE'*#8Гđ/7z!cfQS&:ZU K2uwC'ΠI *0 ȧ0Dz}5#*eӗRNȈc) $˪~(D'KD>Dj'b֐b:f0TCxsN'9=#ޮNh/fh3E2/@9d:*9Rt7/,:=LU J{AH=-Ý5#S Iȃȱ-D -ģ`hX'LXNANj޳"dQ0/6 ;#'PM "/,^i+7't$'ȩmcAk bj%sqajh&57&5E˱L#Kܫ\CfoqM7=g.i~p|8.SB&%kʧPGT"7Q;޺teUq5 B_N=d-$(&MfT}=ZxP_rlmkokv"`ȉu_ے^rG0.?8##QGChM N[>H϶ܩĕr ={s5_=̻uYEcd3h5 ~R!4܈6G ??.?+?f5?0?˾M_ϾWLl?m8 ߑGq~=/AvHendstream endobj 64 0 obj << /Contents [65 0 R ] /Group << /CS /DeviceRGB /S /Transparency >> /Parent 2 0 R /Type /Page >> endobj 65 0 obj << /Filter /FlateDecode /Length 3070 >> stream xZYo~ׯhÆ-އF{Z{fz$᱂O[~` ׌; Ru|u4?=\8{aS/lGBSE}DOm&7 zā=TzuXW,jWR"Es$?npBzZɛ7/=Lz(Nպ!GA<x#A[ %9ޥ;e9pW]ZmSTdmyGTs0M4\]Puҝv 5y ԏN)9z{C{lw58X[_ R]Jb=XBa cOnpf"d|5U6EnhJ+Jbo%n5;cw@dUS\٘n&cX^(~kHX5[u@<ؠiHQ'RZ#8 2xLQ? ae ~͚ bŁ߁|J3eL+6$[R%zUw4m5Kpndk|1 rHB3*BAgM%Am |=֗p Ky}x+T^4kE=/ZKh27hSr*h4㣻6 Poԑy[턹M_ø#5O2Rj\2^?|+- 2%M1~¯| Z9d=4|@m+M _0AY;T>nmUnERǽOhX4ë&Ulp;vN" fok0/(ٝÓe1rW>89XZ@'m/"4Ӛ@FdjYK-a}ҍBpmfQ6 lw( ԋޥNCH bJL-+^LR ~I<ٷV0H{[*;V|>3ݛ.*>߅O1ضӼn8tZ ;#y@!@W3ʺRi-@ V:ʡa€ʁ.-\ OHnTНz#blwi]fi~ ?*=PDHp9^SFOX̙#zWtZ5"dNG)%ShMC~.a;=O_w<֦2Bu&4%J` ;. #t7}8 -*JV+@ظJpOR绪T=> /Parent 2 0 R /Type /Page >> endobj 67 0 obj << /Filter /FlateDecode /Length 2645 >> stream xZn6 ;ޝru"m:Mc.6ęQ[DM.G;EQ"-'m:<|F'MO,É?^BGÖelOyaGȆ)nV }[|/lBxoП#NA"ߔ2IW =!L06M3t~p /~t&sl)86u[&]^W(vy+t c8v]vu֫%( Z‰і6^6m}&]X?yF2 URDCPhF?SFҶo!3x)CwS+:()6O ㇲ6ErO2,}0S\lt Qrp'SpSW#)Sn4Avu? !y];JAUw_p! ;{ dm)m '4ȋvb߉Ҁ0̦d_t|>-?f+| nB}BʆL (%iNA3lzA'=ߠz*"[T,MC.'+ g"c;}ے}YWB+'}-TX(QW["=onW"* 7dL;2I'E :< iy *lm >\7;o*?c7R˯nS G︒/5fL9 х%q*[V'E=Fl?^1=q&?qسuB 2%yAjQ ~,/)q&Oǟ;WQk<;,k1홧⯛U-Pϴ>4~ΏZ=:&ib+g#Ñ?)QK--stk,g!S$uoHft?tUK|p.ڶBB˦C͌Jf.Uudz/txHQ"A( ]Z&)A*:t)!f܂yV ,s 8fCxMmd>2M2@1tLPǟC))IZ&̡w:wеJR jpڤi1whIq5wCɱjmQ?i~?@S )rgL  w4h/2Rt{N;X{RPQtQN5^pTEL"@ z4PcNw=y?>^2]U#qL)t *IX@z-8Th귇Nq$C"(sä&E֒e iiH;4fZӪ'AG|cb6^3pvQ͈ܯHKwy4`h䃣Z ͆?Лg SloV7]>U cR6'Y3 +zZ3 $ӂƊF-,yahE~.z_yc(O.TmQ[T82HTv&Ǯ7۵ݗ@(z^鞡5,GT q׍fɖ: 9& mX !Zs@DiDx[n^L] τ6vQtF,a)HRd ^d1s(> G*'l0n͙A_9G!d]YuYO hI@!lUhӋӋ{!Wy"ƺ^aGTJEQR/h14C[ Ap" @~_^q}AKRF L9:G-VϿ Z@-Ew_k}C%f J&3oX&$-dt7c[n9jrbdw^'UG2 ?^8L  % ƺZO<08)y+߻Of5d4m Өc.\{P5{9ەW❄o_,Mxm$zb c,+Q+F[Q Ȗɠ?^ <75B+F\F`Ex}{Z }heae;}!@!juȕj5qǼD׌Yk)Է5 6+M=\o&_" ,Uc꽸hMDe8n<^_0{⿾̗"vi?}nPjw-_c[ |ì`C]WMN'Wu\1ajuztg`jtW]ʄ.؋(>ZR&y%oٲ 1Wa?bB>`;oDF?|endstream endobj 68 0 obj << /Contents [69 0 R ] /Group << /CS /DeviceRGB /S /Transparency >> /Parent 2 0 R /Type /Page >> endobj 69 0 obj << /Filter /FlateDecode /Length 3411 >> stream xZ7?O9}b;7#.洨Qǭn#̫x6هd'I;dί ȁşE?]88@'|ub'4H.^ ra*cܣ_|}'~V?i(f\?8)Mv^#_o}/~M%ZBqdnT-}V\ƤPUQ"/iu E;Ru\ɹ9 p: iUW }Wю4L@ˤVƠʳҍMCvYP|}\jv( FLS)(y ]vTKm^nK<G^#?T7$+%jwܶțAIî~ʺedsjCA.Eŀ]U7H[[d;λSBoENAYrKм RIW%-.2z Ης/q0Ϛ3Ia0{Rn)nj59Vu-I#b̜b4(z6wUH> Ztyuc?# Dq`!vL|D}]jw71{[7Sl lKĝ F32:Lpgj.8F:<PlaV[[g/~xu=7Gk)- wapM^ bAdmA }Ή`(KH*.Д\<s=#;krOX$H#đ3&x CAJazBLt=$42ԗ}@J)94G?y&1H Eb 0:jSW?f183nr557=Q u9='Ү 0$p'E,/Ъ)a##h1RC|F+}inba0阳,\eKD+/Ģ4ܕ<<0 TAS$Aϻ"zXwy)3Y0ȝr;=Wn€cnkd(61[jPFcHC2sSbf8ߚ#0$\ Gi#W-XW/?"an{K(N &ADxJe`P D:X"m_81rJx^d!=9 "wҊ3ڒmk 9#ZZ=:JJyL`GI ˔:*4*M}JTqԱ!5窄 LMw8 BZ89vPGA*~V"J#"wVDIND WVVSL{5ɏpI̬%4FR6.d w U2,bUҞ!ΈձJ> `Lu3*ظm0I +3V@a3>{RB./)ߚLƢn-Z;Fb3mvUQm|F5mZ ]nK[mU:$dF2}hi hW [ Ekuod-Aǽ5sh69aHc$ ?l^d2a@. FPlX8C{L&La52_8{yb[?MnٻwE{;J]S3*8׋פ$w 5$'0,Jjb 9`4cq1nGFt)yq1;;R{ = RSwkM5aZPY~ 5)bxa&{k7r-:IKr4IRL.L;:|3aJ$7LhmzkaL Ab*#}pk Dۂ*lZ`sfPh*< 10W52z(q$0KA CXiXųEδ@Dye,E_u&3}/0iW<\yh LE8GfX=:DvЁ`Qd*H'o'DJ8dU bP ;FTF/PF⃪ bfKҰ$}/9xPP$ Qћ3gjCq5\<-xgDLp6tػ9XCD:X#GKO!ͦ\ g(w-_ycеD= ,V  nb3#/}aj,( ;-m6{ L;lXu똷 $RGtww"[;deʦ'{@[pi a?U^si'r4k;DukTENMcY˙;%_`zmka'p)T Xч~}8k^<UhQkVͱzDNtX,sDQXj[*u } 38o[[0qs>y&V_k&jBd=_j%CY~ˏ7dqko)y}\EI}tbmW|0R*hA{ի[a#Dgd ʶE"־N43߈?nAˡقp+/Iu3YDwܵڳFmO(l[*1G賘~hɧXJbǃxPR=Ǻq`&Pn2|?.N[LR_OoL7/ਧXc;Da7`*XO 9T")vc6"`ɆJE ǩ)n^hf_YF͊J6I,{%ߔ36B(yHvC9kPlԛ,$_y'WBal 5}|ogca3Jnzq/ޝt~S%TUl 8R#eZˍzs'3c |?X}0͢ʧY}^=v2l@| r,C"|>Y6%|yPm%ZgS dw itSlyHX|5&^~#HvkO]p  GS)/|b~1endstream endobj 70 0 obj << /Contents [71 0 R ] /Group << /CS /DeviceRGB /S /Transparency >> /Parent 2 0 R /Type /Page >> endobj 71 0 obj << /Filter /FlateDecode /Length 3462 >> stream xZnF}Wtiw ]IH6D`dg#1cY~olR##)SPfwBK ݉K9<:QV1u%q8뒫ܜ\< Bjݑ__~gir_K0  W :#?1R.,|U+\G"oڙ4^ä&MYEuʪ4L!J/nrPf 6^mn߰-usazNۖ&v]k|ǯdWgEW_g~vQ&ŖTuGmGvuΖ6d88)ZҲm:/W-n ^4H^4`Z7b~~k  cԥxJy}}]7%6%Fei׃_oa|,ݚl^-6uY7 d>Av0As(`bƬ<0Ro{YMAEQ=0<_v=uXe;l+fGۘeGuju'_m+X _-`ҠxkkuLC%J|#7<4JhYsNJl>>=T(biX.Nlee[} .Xl ̿1/úY` lr0&N=Fnն9N=5&.YNlk!ȯ7&HHTTclО>:NN?c+pp8+ʧTE.%|٣M!9m/= CG-!s&`&rgԃ>j$Hn4/:zwK8Du#QDm+$L6c/18~?ޘ<9~ M-`j*0$$kP'Φj0j0:8cϊ#{ Rr b=(uSk*aܓЄzF?jM(k#z1.Ę$آ'Ƒd-Sb8A*Mq*CZr'ldfbT8wad Ė]VpA 0STJq |j0K$醾e {'J#>IPD* W2lmSfgcL#)]6@a80 aR3k1% Y>yΪr:MAԆ1)|*AU9 FGC WZ],:itc\OC4i|MENarRAqMh$_?lK|݆h5@&XΞ8'|Lp4}v gAsrߔzPX hרƅ ,@sF_3T09 㙎<_ Cj>P ^df2HUaȏ$$CM!iTA ^K|(WŤSG&ԋ&ĈB(zȰ<|ֆgE'cI?G䖗PNl[9Z0v;j@tJhdH$/L[/ 3Mk}K\ \ݥ-VNt{b}*5tȮ, ls9@7{ 4ݧs1Ww͚EX+R2S 1G/:^ܡඪp#X "ܢ;0)k@Ժbc]cIbY)Q)L"q6J ondJ҃P - A2{NC@ ܂RkwFhl=Ҳ8r?6Gh9Zu !@  vl+D߳ A0I)_ { ԸXdN@bVwx!E6|QvˎUAF^mUri<N5b =kDF H3`՝!8Fe? FX;&n-ȶwrQK0z1R[AB4ni?0bW0oA4C; -+]Yp8<%a0 qu¾ p+/fN ;[*ǩ4 aiCL؉ 9Y,ΐzg240po NR 귁03"ԷjA)t_u_7EaG$3bLBYyBZċkvioz:JV!?5 WKKp*;^yc^^(3q7[P5A⿿90bk<7{ #/.OըB˗3h l\dʖzвx@5/6MNǣRt]OxҶAqMۋ(ܣICU|R$詋H fP#; ۻ9QA'SoGD |'o#+yY-fsyd6X N:‡lgٺcew\ "9]7 d3y<>R%:Dʮ%=.&hmWnXű>.buvf..ʿR&._$qxcn%͡76? 6C auRO":.sNQeOg`Tmp0B/|Tv(jJ"_>ī1qW04 eƒqILcN#[!rty]ETI dIi"0}B3c ӌ[|CdI("ԕ"$cy9?r`5cOh)Xw.v)| O_JK/ӟX[ДatxWz~}E~<endstream endobj 72 0 obj << /Contents [73 0 R ] /Group << /CS /DeviceRGB /S /Transparency >> /Parent 2 0 R /Type /Page >> endobj 73 0 obj << /Filter /FlateDecode /Length 3332 >> stream xZYs۶~Ýr"wfFYęls;cgJ$6ewWx6"9K:M<ٿsψ 7'>'zq=Uk reYh%G$DKN=={}qY|4}K=RP` GDGdAol?n p &OZR (/Iu^uܞWo38؍W$)|W4ERywx8ltE;FG9[;UvI֧x" 3N6b譣pQ'#˒i*Ș 31-By\vq%.7۔hi[m 䮭U4MQΜ;G0:E|'L4#aÓ|=*vm|K*%ʗ|::E-֊91c+;}>hbD0[C|Ϲ=z%N lJ ܥB61z*Lkǡnz^u=lW'o//޽<g3i.12%|^`LgK$ ߏKᥜ(hv/"H2!iP D%0ETqt4]o1p j]Jћw[1T]K#[ n>gCk#l[ejŅ ruWvLc$JRoT KRN ўu9B@ I(DȚdsȄ1'eLل;d.~Lnd!$ -J01 '8'tV4c- @Ў&I/ɭI.{00.cqt%Dm2Yn ,JL$c-O R5N-fGcmf,48fb&M^tvybV|1`8^dR@, 7a`RA=S"37s D,m&Ci7ۆ(nG]0= {D|{> BWPD_VBd.pR&Zᶌf>2 k ,R Y*fُ!o&fJ>׎Z-VI(;JvֱNKf/:F0W2Lk=Wff`J2D}5Q4a ?toێK'}f,XG8la-\Y kY`m\]2,@Ih[=t_{س ]jFx [ Ũ6ētU\ @|iWh]1xTźm}5(^ImR6VҙJt'2 i(PBqR! nCÕEdU ZBP?O"$r-`k ߀t".ag荐c7{dxUaؿL ')m,@tF`v{ ̹쵃cχà‚;KnWZLxR#պij`hBP ـvZN9x}6c/J] 9O*&Mpdwy#VwxAStՏ-{>&В??zK\2 Lbq a" !]N:.B۝UÃB%uz1rP6Ly5 yu0x}:VʦZRڎj JO={< USLL.^o]3nGעi-jp] rWA7*mL#KZpy e(7_Rjc{L8XIJ tAA:yfF@ω2 S@Jkjys ,֓>ڱ TSw6d[Q?FN^# C'wRC&G Wϲo~6sL.˻qO? #[BK7ݛG,ĸu+G6}j="SVCLs4RD8R!2is%-_=dr%UzN m7bGZ0R"ͨEpHP.lNE]-+ʊn֡a]eׯKyA邖|+Μvƫxa_}0g ?_3XPElT[6E`cīTvh2޹zq_WMh܊eu1̋xE L(K|r!(̮X|aRhwϪVѽkBhly#f%y)Dp`wJ2Պe]i1<’3axqdzRX"Fұ>~9/q? `۞y'+ݸ"-(;[w۱ep_R(uob.zI* g 3@p:c[>w(!]Qz<ϻDu}lGalT|qo&2kZ "CWʬ⚯7b8ꊏLsl [^*Cbo1{>,( ޛox \D6g( 7܍/B@D;~@)mV_ Bi [ò{<Lڅ6.9Tƽ hdsYR$6S .bm]x]q@&i]إ2$k'n=3]=j@uńk:Kq!>:+U EZy2Ϩ苣 ߩ8싍0w%5~pJT})Ga}$7;Ք5oTH~L(DoAj,!c*.#ppT]blӯv)1l?¾8ɮZl~?'6Hendstream endobj 74 0 obj << /Contents [75 0 R ] /Group << /CS /DeviceRGB /S /Transparency >> /Parent 2 0 R /Type /Page >> endobj 75 0 obj << /Filter /FlateDecode /Length 3011 >> stream xZr6Sb/ |]:M:q68 1E*iE;}JqH%Of ȟȁ?E~>~=STAq`qHg/\vڣW/nEp ؁~O¦"_mMVYObs).$eDBstS-akL撒,h뚔Mq@M Yo((|ǭ.塏ǡ8ˋ dlā=7"./Ou8RdT۬\&{ʉCTBO ,+Ղ4"O-(W j5l@`QBy4H`wF}9Z]єga / V7kۍ:jMJRg 00{=_CEE`gj'0nvK,Gjj5Kulm e @CEH9 XRR1N1 s(NKǟѼ*OY)L-TJ!]J{`┃ YX(:rJNҖ(ȉ݁2otߝO_Ok%%`+Co pΘٮ3sO.߸8NJU@kuU}@f(]ؖ1|i-+;HkÉ3Ǿv0I"iD0I!7&|*[ȓIw'8y$4v{_Ti@??sTFl\ۛK/-J6Va 32+gkf{ϹM )0g=R-Q-XM"66vŁvۜ..*e])x;g2w;=N&kI [<ӄ}= ŪUjUUoH:21{VuɼL!)fPkmIRkbƞ7g'0aOOwjg3޼|# `?0%~s}R?uے00xF9"SzJX~o6+Qc0OXHqڼ+I؈7U*$<}~Q@%D÷Lc?MƢ2R(+Aխfs}".gH%&3I3=S3A^6KnFY_K"gL׋ 6%+p.|B ']'+K&t+N|=e𡩛ݱH:E2y|/L-;%C%AJF%TiXO8@à,lHqz*|%ˑ#CK1#u6| 7H׆j #9P`Vo!i($]|u)8M\h=XbʶoC2ǼƠ8%A[S O[P#Y& 1r lrEi{"eY%1tlT큢\f$Q?R= 3:xpO"1z!5ZS(cvWgk=E8oԺ+*搣auVu7^#u_պڇ*nYK4)ڜUI[yѼ8hR^c7so5dH7O]4]}6Y*5FEl}~>Z 9~z%Cj-hDdkJî/1Z횰9kihAc#{ʅn$kQ0!kt,7Tzî6D{" 5ʌu3MM:&*Z`%Opsѡjt!y|>/7p$ҥwsyӮ+b1 NZ=横B QZ{bꨀz7lkUtϿk+w)Q6!O3ٵmH2`睻@DjogU!4VO!)R1+Uف"wiTi69+/QQ˰@ gz;~ޑc9&nl^l۫77o\7n2fy jB&N7EM 7~OE i75ܣٍ#X֐CcEΪu1Z28[}H 9xvx'f1F>sby=LJV,eSbąoQ-P=x|i/d&+ע@UL_:S>IZWGE^$|ŗ]AVZW}0Pۅ#cSׅ yXSWw_76û0Z.OP韨 jXK'M4^` rXAUa}b"K[ /C¿).Թ5 !ڠEv?'endstream endobj 76 0 obj << /Contents [77 0 R ] /Group << /CS /DeviceRGB /S /Transparency >> /Parent 2 0 R /Type /Page >> endobj 77 0 obj << /Filter /FlateDecode /Length 2264 >> stream xYrF}W̦J U~p9:w+URjCn@Sz/P>oT$( }>YȄoz ?]A }w;f}| iu$_dr u>xYhr_-Rp`7us8ƫ,}T){)u=CSF$D:0-GA&G97 pÞgU@|4wiqM`)뻦by!3oZsZ|[]$ifhI0 ~%I9ЍQD99xI ;ݡEUmܣ8*о79[ 6>kTƶ̞] N=SVr|(t`CaB YLg.10z-){c)(2 H(.+f!v)/2SF[wx_״h'EZZyeNBQ@ZƼݥus v2DnpZ˔/r&{I_1PӦAk ^ I9MRh J%W-m%@/Hoc; 撋EI^ˢMFl!a ^`qg_Tb;HƷo>  GcUт kII 4QYEJ} َbɼnRqRh$FQh>d?Lui۩'~MbĬKKQU5jM#/]l 6~۹BQ30ӾT fT7[HP#/ 5n0/`}RE^=m`-8tqi.f1u9:HxPG*8p$uđ18Ş&>&\߼b%:J24D`@c33 PyQzc!PB̈Oi UM~p6?lJӧH YLwJ0 !Z ӑnm۟挑Uj"!ް/SO.sd)VFwߊKYL}q .'r.a/ۙYo20}R,:E\%f m[O83v+)Vhc= shWkŏfendstream endobj 78 0 obj << /Contents [79 0 R ] /Group << /CS /DeviceRGB /S /Transparency >> /Parent 2 0 R /Type /Page >> endobj 79 0 obj << /Filter /FlateDecode /Length 1957 >> stream xYnF\$.oMرq&J"*`JZYl(!)3U%)KRI#Hͱ/@A{9}v'9ӓʡ55p}uK#{f\qyɛ3@3<;Xc=cg9^o҆AC  Iئ)rX)[q/n (%l1Pˮ2paÜI0t "6|aTGebٴq-($e_IAfST]ْ'Pؿ,nbv{pk,xE0)YlOwoXuZZ٧0_,6q\s u3PQqjϕwA1ќ,UY-KkW7 ŞG1jj5&%5iʊ3` [ 0Hora=[F _sүD!Bu0!w7]kY=j`Бރ,o(%X+*Or_wa\V Pw&s_Ș-~/xM2/p<>w/v X(;Y0XX? ,zD?^8;\@`r8ǢyG\ΡK4 [BA1ز2uўMXIeTKV=1pf`Qsx3F_,U"*&Fmp(QZ?YǎJ */Q[~ܜy/>òp6a,s/(RW!w1$R6]w@f+d_ ɖ.׈ğaF\f3c6=UCR_){WU^$룄8*/˛ݾ mϸZvq . =**ky> /Parent 2 0 R /Type /Page >> endobj 81 0 obj << /Filter /FlateDecode /Length 2114 >> stream xߒ8L/W,TM6 .EAgjj 8iCU#R[-PtsdOG \f>ϠGqf_L RzB&ٿ^ q?.|_߫lyS_l ~OoMWYށq~q߀tF LæyM6y^.ٹs7ÑAgfAL zfn_6`H\XP!$U9xT2A>D.Zb.r_K 3pexˋ{q.Ώ֣cʩ tp&nPϥ w4,PNMqn^B*Vb\+d%_*g/|];ҸYfk3&nF^ M!>W-U?Pz(C(ھwak_!w]dYq~1: Ҫհ]ܶM0(1d#vS Tۢ9$g1iǤtf4 <t܂i1G1s!_]E0]sҩE,-ƈY#Z]fO.g~DmL +2bK)HVi-FĮX%J}R*YivA~H7)hD \LI~\.}u,eՁ/U`<&lH i1gaeCẗz Bj,(s"PÑga^⦠j Tx%-iN-bN+IqՅƙg]巍ey/sYQ$c=Þ}eO-TN-sԁNfĒ{Hki0*m y(eE9}MJĠǛ8>pd`2L?aeؚrFHvJ^-yvo4pV9T)9UnZLVO֢L,Z2 S8H(>2)2EZ 2tʩdQr*;nN,wɉ[PjarjBiLAJ/Bow-Gm:H]*nO*$8??brj .);Cgq;dIjd8F`F04 r  %oYuT[KIOjd_6@?kO[R.-6L$Ӻ)(0|_2&>Ą j֦6e1k ]DAhw!)F)ʩI $lJw6-'-'FlyƵ2 S$n]ZB[#/+{tZHH !SjݡWewvbwjE,Ec9AA3F95<5UsWwiJsl;6v ;h vN˄ʻO܇Lj^V-h9&%_ aԵt!_lFg<1<&I8$tpGS8@=?0*qdrvQsf)T]M9Jf\V`rjG1Q^~ 3ϲdzOhco;Y?߇l endstream endobj 82 0 obj << /Contents [83 0 R ] /Group << /CS /DeviceRGB /S /Transparency >> /Parent 2 0 R /Type /Page >> endobj 83 0 obj << /Filter /FlateDecode /Length 2359 >> stream xZv6}WQ^qHoO&㴓X}gR"$1& |A?IHHY}@ p:A~3| QtB`u2Cw0˵ͯn>^on3`%rd;x7w?JO:JM>Gy1oy/: * HŠX~? ݰa~ ;B'Dtv7^Kl#p'g렠Bߴ\ɾJX"@ÎNe]~wmsZ)%|h9EqWi,qRuŊ]kF)<vz ~aΖw_I Iשpҵ9x"'%%3F I>*h4GqRNEON$$n>+!yUR *NJHX]#)D(g ęlrzsv/9lwG^Ȓυ+XM&(4T -6ս`H $a>$zq/)Xv*9^ B!pb$tXv*dXgdD6\wI[ _k:4 4%MyPK tϠSYj{6C}mqϊ^Զx2I@M>Tvx_i+ƒ&YY6Ys'Zlb.cz_o _\hp~ $/[nLMTIv*C*`*۷ y@)T p-]ߠJS[T6U@@IuGm)(f,$B $;l"I$I`~%] xQrv,0 %;E7hS-F ;zdR.4P.dS.8YMT} " C@U)`9@c!ФypyЦy$k"c5[)iSezn68fW,*b 20(<*[MI8/glrmE>RMCN^hS$eh]ÈuU z(;Eok )$195VI'LbA٩&ئ׾o{I∩126(TbaϦl;VmۺiȑI@MU# >=v;?H&6rBx1 ǐΈ,!B@{]s--]>(ya,xAd lqϢ⾜20HT@|Ad9R'h"Ad]rҧ'ùΟPQyd#2G덻rg_T뺧+V*S-7ZC(o{ۧ6u[Jo~[r%]Gx~pφ c ߬gP pXqAeʫXܷP7kո_j B/h%ý%7vG,N*1ݴ;`"Ju<94 钥~zקvg5C vݢ{Å/.ȈXG9XۭV4u) &(cxf;}~N#xEBgMqw1wRء5}wE!Sl6Iw:F Y wΨV9O (W|.jƮQZ2aܬy%&=7O[X|fs{Tgs1PEIZ*X(\ DC]LA.H _̡mGҔw Jnl"S_i7w%1is@B*ta$if>a`s zQi3}a{G4_/hE GĘ\p{Yq7Htt 藀fBK' }'OT$K4d >[܊=: 7%'#9 ɦ+O"ެ,rx;.^AzR_{oit]sM]Pgɴu6wKXT|c<@exSl2[ِ)g:}$I^g Sjcr _uFr7Hsy%R7|һ 0 F5kwL\wsڂ\_tss{J OA%(NJXrE+̈́DYwq.Fjb4:ߩoK$6q> /Parent 2 0 R /Type /Page >> endobj 85 0 obj << /Filter /FlateDecode /Length 2851 >> stream xZrF}WL剪HCA*f֖ڀ b 7\b!9ޭ*t>}F?F߇3 {hwf}Dߜ5B< -B79 YM_3d.ocO}9,17tHx;oџ#âYѻkzrsuqqR>H|Ʈ53Cv0lcɉLr+r7=ڗuYJ JD]QH+ڣIYr9;+qVxG|511=XΩcMzlvǟ>}F)u>'zo?o*8o5M&;p4H0nGIqdc:~ _ooƭg;;{zׄmnֱb.s=Db,fx"$WqcߤC[؞e\-жüЗL z-)yO7`270egR*r ;$'H`(ͷU)Dv=ɟԓgP9jk0zJ %og>#9a{ڌ`d3rɂQ#8*O8ݬmkfPi$ǗM΅)EhoIw%kR$voirQQXG!&"ނI R"|N/ٓ`Lxb_BwQ^.{@Bz4YzKT\> @/ -};dNjOfฦt}#ص D:9TtB&82WrI)̌ JdWde'[qQRKF-O0LNHq'nt^N{2NP #;Z"@6WM빰2_ t2lڈȂriuti.idḜn$5Y9e@"I`?2ՆFJ Ts0^ GH @fͼ *a@qA-0$5wIC{:593u'dža3 % &Ѡ.ewo=@HM(q)mcu Ud 3āA wrNbFѤLxExj) F(Y[Q-'KJ ~5lA҃DB~D aeƸoΠ|wP ]*"J "`U9.v@£*a_<.JBb Tբ* s҂ye2o5d#AJrۘd_^ \IQԉJi=I߁^պU>(N`w)k:h/Ci7ʾ]NԬ<8:e|}&HQ:ܥYr ,ZVՔu\B2dgL)!Ţ00O4ZA3x_pTT*޼~ x +൦"wBF_]gMs}?f2@&82(G>SoȌ8×OM@ʻ4{n"zm'd`6$~"Kk9>g6t,t@%IZRCu^o)A'>$I lT֍zA?SnxWylz9mtV*wP\4 ꙡXCs3/?žf bT=%S$wqMw.ac^ }cхn'RAL(NQjT .L}sKj[/79muQZNXL(?m>Ugf{%*εz޽i,3d8xZk XB *) fGán1 pKJ9PYb3=~dkΎL5tU]FeIŊ̡Fd{=b?jűNK)MYl}$ FH 'T3@'G79A8#D*1 UV=Qk2IU4wb> /Parent 2 0 R /Type /Page >> endobj 87 0 obj << /Filter /FlateDecode /Length 3009 >> stream xZnHhqhG@Ve|dbawbBQ-1G*7)6ٔ EuwUWUU5?" # TDG*:?~UMqM9&1 Y\|=^_]sO&o`Ud+Ӂ6$Y4 1ҏb]d}N !|.X֚ѱ:dd4Xi_*٢J7pQEzVb?w f1f)?ʰ?4RaPŒd$`)ceaMZ9*R4 cC,ۺ^ec%CDLUp%QqE۔Hth$hfaF~>@ZQ=8Q}dA @` 8.#'Sغ+ڇ+ *K춦Qȕsw1j)OWOj.xCA g_|?80LMb 8c+mSv4ymiyhߧ֏9^D%?a12G}<&#*;[bff7"GI>A1V}jN_%aSL?) XIvB  üBQ wF ,8nC*E>GӘr&Gs2)JdZ[9[B۱+ {EM~I59ih>H:hp^C\X."ax@Ju*4@YZ8gIBWlɀeI b.r15M68x.)Pk4K̆!&{DP*u4,Yq܊PAoYj_DYe/I6ZFW_FZvf@ɐUI ǍWrnm|"@$?(4VP%@sC>9p¦:"ĵ ,Ŕ?8ɉWWmsFAAtB3^8 {Ov/lyOC-a GΏ׭&JeɧK~:TH."I EVDf(N hSI"w?&"xD&|c'abYÜ_XB*RVn7lb|5>EBɸnJ,X+)v͊՝3qk?ߙ_v$8m[ʟ:5 KZ-4rfZS%qWt pp1I0lE3=CT&~Vh/CS^~Bo/4+#$sZp5DEY+6I QRwul5oEm-X%&z 4 Ή{ 8;aK>c|P>jf DbL3nGOHnK;jԪGv*D(D}H^2r4;~A&};bGO ߔn})11#n2,&ߏ yendstream endobj 88 0 obj << /Contents [89 0 R ] /Group << /CS /DeviceRGB /S /Transparency >> /Parent 2 0 R /Type /Page >> endobj 89 0 obj << /Filter /FlateDecode /Length 2013 >> stream xYnF律{;.ƅAE]l)r$MMͰ$E'ȫ; )4c%h68s.9snȃYl.|~pvOE+qy(E<4!KX CNnM̓C5w* bOq䶢 zm^} iNcu@SI)9E?0}/8;); 'oZA"y钦a;ǁUHgIZ75)gR"P&iH[sVRһbM6}z,$K%Yy84Duo` b_׸Vl6k{]+T_ +Oٽo/J8{"%Jk NNq[Ö aiߧABM;:'O@# %'vB} J܄9Ғ7oxIIW~gꊼ`a_rVJ.{=<=1I`0=llCS༡v7Nd%bX A:>ryWjI7yV_껾Z90@T&xnB>|Ϳ0o>{&h& yc04C p:E!NS| RaKT.:f*H`΄xc蹱{alx7)BJ3 q3;sP_ܱ\w !ľ>Os=M|;>U5^f27ĮN+"猄-):Hc6|]pYg18y:Jd5@ u.)ApA|ǽu "۟#Ϝʱ *f1DS e8|Z#)PM mEJ32͒z3Ic݌:q Vy#*h/{qyN`zfVhFNGmg̡Ӂ6k8w7*AtxSs Eõ4YhоӘ PYkcBaf fzӄӂ \yn d8xS-KTq:MragPZY0.R[ ?6yz%NЉuttgCK!Р]C;Q Q4d\k=KT\ヨd>imj$PJ^`A4[kQ>MlvTiI[%:C.BnI}ߒy8y/hE;ڷi'pqJΛ742pU{vz z[̸H`L/>; wa(D1lAtGZ]?/5!4ixklk#5 Q)}g_L%Kc2~Wz݁BW=߾\WJAXWD2yr߿ʡs%&oE_7V@WID;pld IFC gӤnx_;Q35t(i+nZd(іEXM, 2{_ϐBǾg#K)E"7t2&!lEWmAWR;$pR<+Q(DNJ1ÚˉI <KO;qZ!Ⱦ:䞚܅4q-1zxEhjr!fɫy1%5g%)TK"z6srZhr "nx 7޲t4:LkT==v"xzwrwۅ{֤bH;98RhԤ=++ <(6ld1ʑt V y[4&")⛇KY\KWj@éKs- Bhig_fXk&W!ʞ3{2Z 1ݐNbGn'Į7~}c܏5_}']*rIb>&2xq 7).WlT7jo觋._endstream endobj 90 0 obj << /Contents [91 0 R ] /Group << /CS /DeviceRGB /S /Transparency >> /Parent 2 0 R /Type /Page >> endobj 91 0 obj << /Filter /FlateDecode /Length 1715 >> stream xY[o6~ aT.m؀kmSZm6Tt_пRr"J:kfs?}I|2g|?^Dv!yջ$M!"o8yWֽgr/#oN^Hh`..b@4)_e- ~ ;|{R?՟q0Mk"y7dכ5׃4H,Od)i|Q o22Oϓ5]u[^mi #TK Zbe,A~sTɎ yK @%' YTmB fcA䅓[+.ro=xflȖL"6xjcÖJ1 b nnŢ7yᗅ,lHf$/T"e ID{ 2s$AV)E$Kdg7³j3A†G WUp֮*95A!~vjC@o .I,P],&,e hf @Pl Kh\Zyؤ2FH B -R2R I AaZ;#lW>)7sEntB-G"H&OEސL$ (['zY MFɳDW=Y؁:J;"` 4=M4rmV0;m/Ŗ\@s빨1{j$0Y./i ,KK8@z3jpU]g05{y_@5zc`+m6FA,ꦲs(A9'@F0jvi Y[v]KQlgAeJHG{` ea+c-vWd+}L+-Bo6{L^\UqNit7d1u-ivrޓc Ǘ\,MiD`)(,pǫAFhF #Ъb> /Parent 2 0 R /Type /Page >> endobj 93 0 obj << /Filter /FlateDecode /Length 2160 >> stream xYRSS{J20IޙS-l 8`y=n%\\q07wql$¿hrP< \ѴCg7r[OŦC{LbXj-,-5F(e鼿VT]qF~[c2+ >ta,cVXZβRq SzWiHQc[Rh[N*X.IQlAL#4%ѽpkx1f"n6a)OŒ Η ǭɦkX5/ѸM}Ts-֏j}ṯkQf#58ݾٔUjhp[o,7>1~볳cjn2L|õ [Vx#7LǍ4n!Rt Zc bi=Uk?Jطт4_p{yZ3&t <"q! @`S^r9Vt/hNÒSbK?%?-GgPWZ]?>涇4%- 0|y < K"k K0]5%İ^ _5uLb!KԸ״tqBj}#P9Es-ISfL%}4-XlEt|iH,9̠nwޓk= ǸtTNԎ+K<5t|:n9u<ֱCTt oB8?R{ܚ{_?D/]P_CUт-zeGgYj"gRE K _?F|ˢM xhB ͵7a:ۋeV2 )!-^w7X?tۻpA`V¨Y"VD&Y"gQ~ 晡NXnZUrYL1~Hn`y0C.",%ޢ 5E. [.CH |屚 h.U2CMGonn./Ύq$zՂ!b ۓÞ&2,X9di<gN6wQ}=ʎ*aAhMCIcbV ^RdiE<;z{6 m_0rISu~.ٲ3_nbu&j;44hM]Z}FߟV8[A!vC4ă[7$z:E 5N ~ⷿSXXxLߊBW#{,l;සðendstream endobj 94 0 obj << /Contents [95 0 R ] /Group << /CS /DeviceRGB /S /Transparency >> /Parent 2 0 R /Type /Page >> endobj 95 0 obj << /Filter /FlateDecode /Length 2001 >> stream xZ[o6~clotmYh1 jFnCRRqt-΍gr^̀_fy&,g/g|=U@VʜFfy>r= +}rga7+?S%5wZX~և#<y'OK [P尛vX^l5:FeJv^/kSyrYQZcEn!BE=i|'<^maM-rC7RxkB֤vVf> n,԰DTϏ+oęynj^p)$R~Yn)7ucAYwt>:Iԭ"]OqӿRJ ^ΘE tLLֆDZ"3 N/ə:Nn!}0ӗu8B KZ(%{^mn:\FB>1 'q!-c]2"yK^:pm_uf7_ RG՟#ԟD4<# ψ8)Fl([ߊx` mj҈uMY*r{w|zՅn`Qw(FsRo\u[Hnx)\'~۝dkG/0jMPTR\0[B~u94&x8% ٽaqܽguruKVZe=_/8Yg7fw5" `$GJ 2%|"kw&;ES26b}T5&GlCNBR&YK0 ɱj-R'&IF ޾Tf< ns[/l= .G<.nuM+N kVoERop@o׫ŲZ@ $?>>8.CT8ׅ~;e ID!񥏣WXtp,^VeisҐ|ڙ&0'Bs3G'K* Bi$ir"bXnnc!Qi'I#8~WU`y[XxNZդ.Cq/],b𩚻5%x"bHgMZ\y;Z:q݌K2dbnꭋ2ROҽ6ZψKm>tIVfF&6F+ԖZB$`EQXzJtK,yh;5n:m yC7R0D;ܷ/bl&Unlt)芩R:O@jPtXt0P؂Ädi;P )|ی4aqJYD$:L7AQP?22x)ct['Md`5O07FTtwT2Ka~|brR '}vj X/7C}BIWe&Laޯ0?-hpy|e*brR2ƴX hR4$R .0sFt5zTb{(TGgJuF0q^8Mm v)ݚ4kם:sPInZy8wI8'hF. (XtJ/Ȅ9,hlJX폚flTtLf#R F"b ރ$ tc`5 :qŃ͏HнN\@\=nAk BOep̰?<#cѣ#L'>  Z$tfRm@DIZVC߹ݣ4 qCrE#7#&t< d $PLy;++a9sϫlsͮa~t٩0r8w 6gffEendstream endobj 96 0 obj << /Contents [97 0 R ] /Group << /CS /DeviceRGB /S /Transparency >> /Parent 2 0 R /Type /Page >> endobj 97 0 obj << /Filter /FlateDecode /Length 2597 >> stream xZn8}W/m ъR 8xqz"lbԑ?d?eq5) vTba^{5da?8[.26B#}@^BIGz3U1R(E {ܸC;Q4 ,$ ("gqB֖z xCPBbrg9qG1xۢ[x1x4CgEqzV\jykFa`WVzeMW5Fv6=oacCHG)7 4׶SsEH}NPPmqH(D ,ғRp>q>M§dr%e^ ڐxTQ]g4w ([E߯HqG~[e= bXG{dDUܞA](+Hyk5&= '\ hȞwf{ӓعȁltqC {BgGD9bAVӒ:v 73#:䳙0TIbIBEL(3#mAv]&t%&uggi0hm޶ȴ&NJm = H8?J(H*3D]p4}k[Kӛr5r.:t`j >@%֛LЊBsFx9+Յ} } 佬Q豋#s>uGUZX iF}T 7ykphΌ!1iWQ~83 HWe \klFm&&J u^O#Я'-Mryh'ف}hy'^k)0F^PH*z RH/P)Ř xëxC}T՜j10]^ޜ1&>kⲫa=lMC/4`?a?ʾ4wf&_çƫWH8sײ\d$Sp1Mw[]Xzjd|%Aftu-ygQgP:j5>Ȧ(j/bq86-/"olMxh޷g]GtPv[Qn6bџ,58kv;KV5R_l"XHu[P^nL~Yɯ[';*xU62I%cXJ^u0NV:B5Za#lZ>OM-z(}emî h+Y&^s]kb=|:l˶kAp m&ʦ QJ^Aڂ*U֩T91 l?EK?h)(S3Did~(_g4asj \,Y[41QϹA؏Qz̹G"s-SfUqyFਟG@ TM4Eƒ;{f'nj':CW9U%NNQYf5\ԠA)`YYuNֆ ngKmQvfbj݉]J\1/ (VR)zw:BϷAi:R@S )ӼF͸[4R h'9DcuzFCy77 B{`1-NiXצ%xqWauP9kH 58$7vPAw'GDi5K3)ڻb[n&b#,SXJڔLx B⾧*Zd*)SSrdkNW Qv j{QK{.kvh՜)@DQUVUPFlf.ۃQ#3ڤ|&x]x(tr"T7+A5# 7WZ@K0 #vSF#5DǷyU(J?~φ+|qkBy/F,6yZ $q)A(9sZZ5(IC?Q[~Ŧ|xjKc-pmvz-d[;nSmCI0sˤpUoW+E_r|q}뛃b Sy/?AXxS~0h2"GiSܴ,fUt3ц3zy ^!ϚdH #f}Ng 菣?vendstream endobj 98 0 obj << /Contents [99 0 R ] /Group << /CS /DeviceRGB /S /Transparency >> /Parent 2 0 R /Type /Page >> endobj 99 0 obj << /Filter /FlateDecode /Length 2597 >> stream xZrF}WLZPu%bɱÕ !9.40u+~n$DDĠ>"YW}&ٙ^χ3 {hsf}DOgͪƑgpa˲4%˳vl\4n_]K.~/a߬TxdQ; t,e "yMҿCn)چT,RF^釽3m+C?:xSZr8m^eERc`#$)GW(#;#LJiRE|8ތUV4l5L>v] )E-@ǔ  .KWn%u.wjp GR-p<QTJ'mlX*1L[-/ɵ7?8ok(e9m_y盶U2Wqon}sBQ^̑omطF݀r Ž>3&A!AJFf)HU xzf\[lb(3" MmV1BXݨ"eUU!}lu ;-sgyKAJc>2(Yiz6/ mkZ2'4!- m)uB7B(_"3) >Efv0t^8멱(:B F<)J{#kpY(C~ A8ǎ I31<߃~*M¶;aG?A>ط}OV4,v.ka/#+՜~鼯Ȝ^=8U8S;FCNDv\CNl-VS(Ĭ~ sZkZ0SJ5K+P3Muҹ16*粂+DMMT% *@lf[).^'F*NːaZ0B6͋ DA|Eu@Rv@ #r@"XOReKZk =Sz+Vղ6@Q.Nb0Q7s'Cio 빟p [0x- d3{DpmrN&6@㾜J&kdTM]rᄄp\vGxoU~}_q8~8 AZnI"6q=6q62yrg@G{;{Ӑ~@P.mV V! HN-@|xQpˣȂs ;;=+pS^ .T^@7]oHwpXUBFSTӋ 0C'9Vhoƍ. "JO | 3hd Ur,)T'ba̦eÝqōKˏ;O2Β&uYR]D63qM P3 y9q͓zA _'3#U7ͦ)6s:\@n6d,ߤ3ZoM>2 *S  z_ܡ ,}MdLG4+DtQ4!4̲|WJz$(+e^Hydvv.v]Ly"U+QTl۹Dv=->$^#d+"Ĕdt p;Q> `]RWjS8hXn+JRo bt46=nNO5;5_鋜Fw*%WH"Fʮ{KmwRހjKk_jA_wMaLpl- U ?X>6°N&Uqzp6zÜ=OY/ e?cmC|"aM|W$=㊁sMYe*%,Mُ{1mYh{03~Gά6 &u4I{=3xll?v|hd4ik`܀saۀ4M݋I 9tp?Oߤb, #rmvmj8z;ȝPKle| U"sImz ۆ8mg|gŖ~*x\^%ʽi|e^IvggaiTD$Fä݊f<^$\5f{~5Te-z%D7}8JQl.h;'+y*`w,t7@e8_]쉭ܮL_~9?zgendstream endobj 100 0 obj << /Contents [101 0 R ] /Group << /CS /DeviceRGB /S /Transparency >> /Parent 2 0 R /Type /Page >> endobj 101 0 obj << /Filter /FlateDecode /Length 2488 >> stream xZnH"XP:!hCI$(g91Q6,*Y1)Mb0צlgD4ڶNY!uc<c- 5[N8ct Z,5orp,!譅a%h%+y)Tɛ=ĭ]D)Rjc{Q,d!S}S/-SKS #t)wHH{'m7qO>Kgn˓4ŗ'gbaS΋/fO>'gh=GAcBs1 Ăʺ*|{܋cHb0; wlZ m{`Ԍz(ByBu2zg{r?V$vQN1.))J}%1Iws[^2?4vXߐ͒45&x [M}ZWEŒ!+0(u*k Hja ҥ[-ZT.I+,Pgr~ ! x^RH(Axj&]lUtKDr9^Sw$Q I Ve)OcpwغGX aYqU12#a@K,JVA<1rC;Ė2~49P,i Pm4+GPz;%io!X-ꢐ VVLSa~; 26IaZЅvo]4 d'I+!dEQUTl!sM{<֝N疏$BsB4;v5V $"wU~CWw)3 :'(r_H7 X‡T+!؀< !D4  ̈Sxl'YC IZkt^&l~|N)\3*p)HƊ`ز0 7\_0zlA mYZ. Yy%Kz*v"@tDyUyu*?B!f'fN3XL0Ʀ1>\ca'_(f H $}םY8p]4|}ڎ+6ݟ/Ы&&?űƶV`űwт7eKAxpEyD5(jM{ Z5vp+jt2ݪmj UPlpM[{`ݧe}lt~KwlyoT"7 i~힦 \ſ'ߒez:t1}*`ڶ}:M<-}j kgqk Ӝ6橳a>;ÎIlh2:aG@(( qFQ=jJZxO;[(粌`vrWXu*HNHll6 %rC"M!qxuỵa(16궹OdA&u*KH8,jT}vQBVм"IӺɱv8>%yv]y@ش >?85>1NlL#Ѩu!|Mc_Jlm90ѥ+ Q⢖rT?l?!hÌKLuB+,:sVH\Ҋ*FHte;"w g˚h\EFOl_^%>[9w1e@%Yg%9% *@IfyM@{ )<7 r˻ &ECŸ]1`{Z~7>O_Con޶6yuq,ri Z78g̫bf]JF h O aW/ѻ ݑY92tJzq~߼b:ֽŻqZH3=T5Q (YrSؐ8mp`zrendstream endobj 102 0 obj << /Contents [103 0 R ] /Group << /CS /DeviceRGB /S /Transparency >> /Parent 2 0 R /Type /Page >> endobj 103 0 obj << /Filter /FlateDecode /Length 3225 >> stream xZnܸOA?V/.r:$!.".`VY+m$9;?DҮ;\.3Ù|H_A+̶g~=0COgzw=ST1P0yOoI,`y?Зn~>-|ϥ/Д %1: `=`ʝ8 >~6ە71f! [o|B0eӧ7B`KJOD,ি=[Vsb#߷8U2oPͫ֨H_jh_u5F3ןzƓ{ v*5%'en.V"ʥM(=b)v$KUB]EY4sƴ7'H.V^ Kns#x&>SN= u]ˍc>ӛhse|? ǁ7& opTT/RiV뼝P#&Gi֨vuW[i#@ణnP.%[ݕŔW?ٹ=e<' ݹR l 7S V6M_o-#kvgM$7y=mQoN+[W-!ܿim(-iؑkj} s~+8U[o㠢E"l^6kBj&`j1 #UǝV}_ w[N!Nu9T ĮOi{L ~E&E?/RGGCpߡ@[gZ\ȥ%t@ \ۺѾ9}\DL4<]JM9v\H5#ac\dRMmQk܅_˴p ,m[X-rƗ 6:C/!z͑ Ϩ十G#Rj,˗F)\Lq΅g`/^$F\TV]RmQ<\bXt+I|PCW ,HiFiQKOpJY sH w 8Kx\uPCPs$++0w.`̹a_̓!O;.$t8᫷<E<)`|wHc`7LNE.rm;U9l c5=rvk:S:z@jYYC`Eʴ"O0n܀<Mf o 1Q @"h4y`>ST}l TV\0˛*-3^ҳWA0Sa9/Lt;>alE6+Tn=\j{Ҍn:o@7OmyTzS+54ʞnDt3u]nr^V9"ԋ%syq՚Uq{)05CЄ.۾>g;cb;~"Oxx0y`וJgI}q uh=b"S<.;5@Q3fLs+()ndjy%7DJkJ?,!20tܛݚhNr]+Ȧjcf1JQ{>&bix:yyL^>|Z^43KQrQ/DZ,r O"b\x3#gUO?l]zP ̈$d〺3X@Ԁ1%A H.5TJYqTuУ_:esFtp WYoQ8=Eإ*ZfSX^gМP VI*ҎdMCK?Jvo H9ծ)N 2da7]Q!<+Y!@wC ^jpX6$`zȰ^b>O@%ҥ=I%^_/5dhcfY޶/W)ww |_Lq@R N ٩P<30DВZ&f,V8`g7c;K,Q+w:$i !Qp:l vxcb_ kO< BN0 L]vlK3D׊y}FC0,ߡ>O$s0b7GP f6Խ"lQNYv#"K `n Ҍ#嬎efo ;-.]aEjD+K9E'\'S%9PϸWɇzVM>МI$/0MKXbLȰнEVTXӉao77E_?_`N8ɒw)@d/.T+~(G>ZB@E!Vϥj5B7<"zNLY Q"hceÕ;5˩8$aK$+(ˋgOIWc\?m}&:YMi$*MSN~X;*RL0r<8ߗ\@yc?_}Tv}~9`endstream endobj 104 0 obj << /Contents [105 0 R ] /Group << /CS /DeviceRGB /S /Transparency >> /Parent 2 0 R /Type /Page >> endobj 105 0 obj << /Filter /FlateDecode /Length 3383 >> stream x[r6dvgLJ&ݺ;i̮P$H3U{p!E4m)9G p{/gݙ~:Q>6&c[>qءы7׷bjA_`[3Ё#p? ^jn 1y=at9(;\;9h$ ї(JP!(rD('ahI nonPޠw\nkjxBמ/ۋ=<1zBFX ;ذN :Jr\^pPO#,b96_*d6@1@&1z+dAMmŏWmiݩ#nUĦ}f!YAK agfH$Wi~ܦt\t;w)_e& Ϟ*oymGb2}^{$ xvIfvoGM T) Jdz/vyT /Ε4R{dx2TrC;=3SN1gS9x Ӄ !ñb=ג%c/լky_7 rԜ;ZEB>g}`hNy9zLc$ǏU~ Y'e~Դz|DY2 PA^Q .Ӳ04Q'._N'iudE.9qn-|3Q-E|-jpu \^@d 4DT[v?ZanT&IК$$1J%%5OM:5{ю舭cp3 Gw3TqGAuxp|8k%,VGYZ&,b \:UZSbB4L A㡧/罜֪]ks.σ.H &HG("M?lK@N| B'gYyA*9 hx.8 Q%N%50VNkKrb.zyW@Ai x&`Yk2IOԻ$zEJD* m%­jpR[Q| "(̀QJ t/GTŭA'9+JGAvd^])3j5gچgQW [ TQ 봳8* FOf:EK`I@ÀKF& 7u4l^9N(?_\93ٔeV./ի6X*LbO ߓ_WIrytP=<@̻a)H8zid(>x N綱gAwLҽ/8Ӯf/lzm|j܎2w%IweE6׵NDI. 2w4珨ɷ Uh1V7ݾ1U&~<'9:b{N#n"9 ̗Xtb Ui L,q{kΑjkHt,_xZaQǠ~h&$۬Tj׌o,WgWa dI^V3@_FEigxZ$B>5] "#a%70tL}Q.YsxD~byOBim?P7i}8(6 ERD`!M %&:4=Mdh@`YR(Bu J>(Jf4l}W]*v0g9X0N:œ2z"QHXe>Z]^qcX]ʺhj6NK|j{ڦ_4 @hZ 7(Q:9u>i&j_>Vbur"'N )(Wi=9K ۲9U;CQ ;*ЧV I0pE.*Hr!G x%*sI!4`)uMWw cuBaPdXXуFDAUmZҌtv:Ej>ms&{VSthE;!(<ͻ<ȄTGJLZ׿.Ďv=,Kz_QUrmCbD+!(2&V86H eZ[0} 7}*c sr `OmN[Ѯ N _Ae;5J Ȏ3ڤA} 쵍 FI]kMt:ihW¶*8|IGb8]u*q`_K0Vqr댚kaJSQNO[DbDCE9g#Y9 r\ sP'{"ZA *ZbUB-(y?tuؽ}z Ds_1L[O1_ߚ+gUWsٯg1endstream endobj 106 0 obj << /Contents [107 0 R ] /Group << /CS /DeviceRGB /S /Transparency >> /Parent 2 0 R /Type /Page >> endobj 107 0 obj << /Filter /FlateDecode /Length 3139 >> stream xZK8 {pn`yt=Hf2IEV"(q{JnlQ&mgff )_}Ug/ >^NH6.g[{N$侄%7/xq ׆=ubϰ4Vplͮ_OE,j7WJghWΘq3x[4izmc^Ҫ1դd5%y,&g#9'(8!rBWg#`޶$!+&F>! #7̿QrehY- kgJ쥛iG{,~/a1zkFkZ_-o߶/t`庠hG0a?r|ccucAڳii2͊gSsm9p}E1qZFiB3rr ㆆ fJs4%M=*X!Z{yE5Wmrf׵*Kr6T'7ʵ0[P=>u:fBg`?MLzRtQ?k-A!/^ݒ_r pL GZ5̧"@OhS8oä ݂6/"`Jִ\=8ޤ[-W,կ:=\g~3L$r "bK!!fE+Rݗz] Y@Vs 5]25 cL<Pl`&8n+y*') H +f \ωHj'vKk : fhA,! DoIB.ҢؒuZs9y}lqdyѐ$h9KkX'ӂ)I޴ Q̮!c8y 6%"MC 9hUw 75?7Y&cp>@F~3[z@ԅ@bY:$<NSxeȽI . oŋ'xqYQPص\>`2/OWe| cȃk751'Tq ^pn(u9¸"?~5Z#WCC| ;s:⚅WW1Q dc e(jX(t VJǵU6",ɋBr?6=۝PkEZ}rBe#;z!G7pP3SuXWZ} ۓ@Z;2n iuã7|Rf(k GoCn0 љ;+ 1"hз\NWO2#vM`GhyeXuD]|;u|sc98LGzt矦acAS,~[:Rk[oy~o('Jl69t|, t7a9uMU"qm` 0&ju׳i &K6 ` 4X&HF-V:R5$3xҰ5`WPplpA?%djC)1 cp`355O jE$j6ڬ= [:XFoiqOZ1f+q2!{CUfOkvw6؁  C) UǝOl 9do'MlF鲹e/N!uWbk 0{B? +,-Bj8Oc~vlDiQh5cKc%E- Y] @jtv#;@k[=YQ9&keK?ŒMͪJxlZПVE?ւu=ZqQ9LMlje\,xNt1mf|ƑRNwg;+n[mW|(SClߕx`&\>U &lDxDW^#).5mںjOLnS2j` &V+[ nXQ85T3ߌiᅞ Iܬ%+vxxoж8dCD~ EDž7_b^\eL )kUY40fœ뮁I듷`v.GCG4:s(K!Hke'L[JY/C|%]3лkDkcF%\FسOq.rb8Sr84,| xZ2;ߪI%pk& x[û%xs6&a n Lr35Í=NY 9 H9vwMCH ֖~Ο$h7};IO2"6iϮNO-&bԝ]Nd*ke]q_π*=Be^ZMlCOO߼_V'(%B0 6ި8bP[|ĥu MB^`N8>zoN};^Lgβjן @;fg?>42 ƐkbR,ĐR" 5N8C6ܰ(=a;; ,ƨT3~:U$o*GR &X A&QDZ$& QǛ& &̢Ad+oZIw] 8w]-vJ̈́mq^pGD |#%@UGfĉ /&ןϘ\NADŽnJ"=no]*` endstream endobj 108 0 obj << /Contents [109 0 R ] /Group << /CS /DeviceRGB /S /Transparency >> /Parent 2 0 R /Type /Page >> endobj 109 0 obj << /Filter /FlateDecode /Length 2097 >> stream xYn6pX틋oL3hR`,:T]'"[8鬑Dq9s<]'>?x8B?o8<<]s?C>\.z!٠/ct{-M㾥A4}/5R UFY7Tcr_RH-r?2fg;`;|>>53$UNrbw< \Dfɾc+RqDm gs&1-8Ĺok#M:6Q(EoBԬ(c=^CjJE-dD~T 6teISѱYl)x`['Chf/'S2fJ!@<,EkN]"H8\ u,NiGٛvv5͏.BxfΖ[l? ]SP+&5OLϺ `ٲZrRZ/V[EZ毪C o.1-?vMk>F:imzʱg˖55mx7OНN+0Yk_ʕ`0}w)j\M9mc03Sw 0t }ˁ4q_PT(Vȣ,p~}5 E=PSr=d%` #`=認̒DU꤬sZm4-ʮwYB^6BDKVnly}G  kNw7ttKwu|[7'IXEAn,xC=m@vݡ'dUhQlBԍ%V^vERŰ7  N7SRZ7Ұ#"rrTEZ"ts:8ldW j%k@a7p&KpgܩEf}Gz$(L й_!QJl+¸KOIMhG,~S R)bW*$3Ə lnYC%(YĄJӆ.eȕ'uF&O>ynrY reHOڄ%/rל !_g8f _8U>ܩդͶbpj0[L-*[x>NZajqT woP=?y3Ӏ?o^i7_-``ȏm.FE FgJ~!wpVs?:!v×z\~th:֟i(Ί z@Jɏ5%@5x$;98h*dcj~XW('(j&GjiZ ]N~;wendstream endobj 110 0 obj << /Contents [111 0 R ] /Group << /CS /DeviceRGB /S /Transparency >> /Parent 2 0 R /Type /Page >> endobj 111 0 obj << /Filter /FlateDecode /Length 2442 >> stream xZr۶@;NG(wRɏ,vƙNwn` ВJB^ {7f)8ws?,遍XCzs'z9;V6< [f),YpjGȆ\b}zwvO,hJ\x5Oaѫ-Rdԡ4Gh|>(j[z2a%wFr1(r%ЍqfRl(zNl 9ѳb8p+AMY5ɉsB @1OS͋1$^;+b 2xdkxvOHLR+$W=]A nwrLJX6C.x$/O,l)Hox))(^[)ULfH $X[d hVD8fa9ϴyyCo -mr]hj܎cK2k{ue\`랫즭4x(0hQ=W9i]4"<=k*!,Vp]l] h$!5Td-KyIp=𭀅U"GQA:9ضIBkYtz^mu񝎌ٹoh5\v t}#=||,h$!g|Eʄ9^*) bAݛ*~BE]-tdh @OOn$bd_z)^kd-j,J>b؍ A|ψQ>^\\(Z/g!#O`)T[RE2Rf1Erp H9yjŸ:%\@Ruqmߜ b}i6L uNe"VŒ~ fnTx8i̗`LLfr%J7'抍I x>krv}2{]zݡr1=RgaL [TТlSԔ eRQx-r*!'U.VTlO?w5rd9 Ur*M`2u-u &]G-&'w2*M|ě˳:FU{ꮹ#{ !rn}Ha}=:aB;BorAk4QD z_o :goT*&:ANT \ʝ`+cwY anr7 DdpCt1ؾe =tynauVʰGJLL PWn˄d:K_i2$XǫvDһNLmX"OHO|RƜ4|ԜYH5bQK &pwGy3n0ͼZ=Q=f1AsL n9 :ahngIݞ|DԦxMeLZ_T betKv&]_{/@nfmӼǓ uDX-PR 5*Y]pФo } ɡI 2cA\Q7E~r 6}|zҖQ0@7PśB^I>.{tE4.N̴ˠ S)bfsM˗T" vj@1C4g un]$&7OU\lOg]کWOI9ACSH౉ۓ>]ӁSA-YpgdE5'IZ9͇˷WWx=_VvF)OѥzX(tE(?C6sPo\6@ؾnw۶O9Me:gR߈Rp8AQBׂe\?vB5ttphMFKLQԥ5[Ks`*(|-ʋ AG^nmmmoxK0Bo',!l{w)EwRӦtk6iA<#o7 r1G:H$Pxgsۆ'3ORAendstream endobj 112 0 obj << /Contents [113 0 R ] /Group << /CS /DeviceRGB /S /Transparency >> /Parent 2 0 R /Type /Page >> endobj 113 0 obj << /Filter /FlateDecode /Length 1677 >> stream xXn:߫0hZ4|'m?:4ĘEBZn!vVB 8{<MZg~xLdw{L~ 젻޴~ro1uahÐY Sx;t~䬃^v|?h‚8jzW Fۯp3I'Na0T>T3MokYF4`uՕsDh.& ",f$Q;L|oQ$%(!,-N(y*z94߲4ܻt!޿G&Q2f,R 䠋`7 d;J4L35cR6߽Wf"_ >df[P:vf,4]Y$up13yJtN(..:58NKm&K`ʐ,㔁ߐ={fSH!Dbvp4!Bel ii4o8=#ˢ.dod|S#k󘸮>> 84To^t]GÙT4Փ;GA?Ws9oo0y$B ̒{8l %S.2մky L>74hQ%ӔLU?fsN7b^(nd:ϭlqZ %{c:hXK/xBUߊc ?SkySZio,:YhgQvye Ԅ9fR-Ohx.N(wܡ =g]*P+2}lh * h)i^DUU;%t0Ym^XZm|[т߰*o: ar|0\EקCŮF_< h8ud(TP{12(1u-ADz yԂ4a$KOUeVkl&R;f;G75gy Vjdžzg6gr`lVUz@#l7W0H0s9$ If4{oa֡^>,ۍz}sa@wR8 wloo\ !B9%Q8O() b2[=cj65__ZRIKJX yvG}bvbרx),CC"lendstream endobj 114 0 obj << /Contents [115 0 R ] /Group << /CS /DeviceRGB /S /Transparency >> /Parent 2 0 R /Type /Page >> endobj 115 0 obj << /Filter /FlateDecode /Length 2490 >> stream xZnH}WK8yuL8$ f"hI-7x>oS$E6ټx, R9U%C*Rou-zڟ(7IVeP(hRu ?nŊ~٣ݛ˫z*l-,5t᭤S't{]0skž҆, #gh>ooU~U=iNʓҒ=fʪEW/ձ2g.؃*S$}xr;/#'HYX"E1 ?c'i{:YF+َ4zsu}uZ_KȺm^746*We QH5c! Y/2 a 2俽L?H6T[֚Od9-*4QH8v9C۷(ǏBK9HB(cTMUSehC$(Oɺߣqh؎+f=xh]|U8P^6μ({l9NeI ?oeֻz4qg<8|_팷Kz63I,N4 ȗu`/} X:>~et@Я;8DsiO(!i'+fOr+{i69Mxn RɊE]6eOӃ/l+8{DU8HEˎ=i0 :EuRdݯk!c>g KfTdڶN4MvnĬVvf i $Fm>Σ JO9.Z g^H OBMSն>Sy BOiNAJ%uIv[ % dSih|,MTn$RR tN']gԻGЭ8A^X$pcBnqmKT"&,*}VΘ T (# ʋC爎tEP +{U"E~<\oQ-*~r#m>x Sp'Jaw67%+/4}v}4PqC9rѺ Nu$Mɪ]eT 0;J1Ŷ`DP(g#IBw9cζK ~6[[4wt޸<|qΌS+k@bZk465ڢLK]$ |[ȏ+RIQ-g9g`)g@%6dczzJRhZ=yP\=v>}f."hV2:d%ǣ"5z6b`># HחUTN\'R#[χMfγs> /Parent 2 0 R /Type /Page >> endobj 117 0 obj << /Filter /FlateDecode /Length 2545 >> stream xZrFʟ@zH ڪ˱7Tڪ !9i*z9.QkD OodSQzab]tXji]ebV)l/vlx*zwYF@5Axc7R<8zMѬɷ8ws/ OT)!/sL{H٨qԫX/3b6'=ASZVU'Wy:WD%Qz\z3Pšg:>o[\=Pq2pͫS9P Ǹ>>7l Ó1qIΊkUyܓxiX|Xkp%nΚ'PYoGsnrZA5ЋSticȖtk^T-3xkrspk:x5zb&$idG,pD)e|TQ],"F6 L^a7y"y5q=vDz7JisIسr>ŴkZq]_ %OSl1z)-n?ž4_| A &:qa!eM;$*8FEEka& A[Yڏu}ww4,# T}^T,uP 5Z"ȉ@_W(>dG!M1`$q),Ck6V5].hVY{^+uMsA YVpɑr[}0Kn8:fhST0_l^M^a/Cd"o  "⣊ħ@hu~$L+!ԩRRQV?0ǖK;!}dbH$f9VѶ(>hbll\?+Y`ZT43:t ~a(w+6hN$+bV.dB[(Ck$6@]F/9i,UN.6ПЉ80t`h'룺4$SħD0HZT{p ;!Elf%Pxr+t.&Ve~͔N0Dv{Y#=lP\х6.~OۄkFT{+.|#m"lރ`I\=$U]F;mOp?o1泮>' ?PЈv~d+p"ȔB&jǶn$:(Ec~u%f5M0Łlo'p,4Eg+e5hKUmLYYh&m%yEvfOɡAKP;Y5>T\2 {O`> /Parent 2 0 R /Type /Page >> endobj 119 0 obj << /Filter /FlateDecode /Length 2908 >> stream xZnF *4[؎vcEhr$ѦHCV>_%!5IM:3g; 1?AGfN.TNt]'k Y>1`}loӫS&9{ ujJ c>%qL'iXaV_׳ߩzo)KNcLC9{m4˱㗔fᚒ(/ 6y'ْ9)W #gWd)ydS$YIcQ!iA1h %n0 !# "lOD3 ! mc(a $T -'AedyF[B]v$H7?2:!!ifKPjkղ+}^*`_B":a%/T$'lZ,bMcKqLk] k6-ou;g'V"R@R8 qԽj, "7{߶ r:H*QAc inzDkmRrX?N7m[jKaarSH8nZH .@SѢ"KʓLVxG.Z7w$XhW"Y `6ăuDVSgҸ#ow84^]u&<*/žN3h)"@& ␭1"KF.n.b2KBkUQ?\vH HTx4 @IUidS,OjHoތhxwćjFݫW|jCu.KdU5)9עA ,+'\P!$pLs=2% (NYjs7ؗH!lc5؛N{⭲FaIҐ Z=gl MQW#Z:{g:V+&cfߦMxţbWWwI&۬℅PƳIkCݯ5d֬Yzkf Yh3I 'Y^v$l~;C\87gmx:QiTumm9Z)DKTFw6e7W767o)A!M;2Q ?538\I$OO^Es;'l߳k@5Ѵ%t(Pm{@hiq*KJ-+ǪZUqoO=7 y['C6b͝d:$NB<3MPfrw?[lϽD7u^nKWmDžT4:(ZyUϠ I=bp'ps@.UIAb.1B=a紁1# Jax DSIJX3:] df~hXFnxZP$#r%O~%[?iH0OQOW!U2}IƶYP\OȂ7H9|o>I fZ/j(j8ܲ?1,ܽ;"矮O/oH:+>Ouj Ev !6E͎ߘv$-a+ 6XTY$ Ce'ƈ $/UR+4IDq>u/Moe0@;KuU?aB6޲?t֪:Zh'+*,dhjj1Ǎ^:Rxj!t;@t; ^^TT)1UXm6S7z*YݶERRDJ]c |>20 ݧ۫O@ͷCA9:1\}86 -P-VL%GdPɦd#땬s[ 0i¬R\I9~=ܑ4̖U8fbM8hM lst8,(T['A-Y&T ~F~O  ͬ/ImImHL_2h K:(TVl<#G~1ۿ^|>0ww7$l9bGrj9:; #WZ!0n*X IvZf[<^Rw @?w`DVpr_> /Parent 2 0 R /Type /Page >> endobj 121 0 obj << /Filter /FlateDecode /Length 2434 >> stream xYrFURTap#*#-;UҖC6(<^srpv%vQOu"Ȃd}D .Y'xvCBAb˲l $ˣg$D X]OxF'ROQ fBnNП%$yt$Kk*7qW \D`2" }$V/[So2vM(K>@w6N6(NksԬ(*25_%` (-Wm7ey~ٮ~öro҇ j^)0M6  -S%6\shЊ[8)e|)xMkTFU&K 7bI拢Z\||[l P]$}HnmsQdY!r}[n?hV~okI YUYP-8ôlPA"jA#t~ug0`r97@H9q,ˆ4E9ē]1Im6C^Dȳ#me̿كNDAj$v,m/MFh6+M}|5C\bA*n}@78WYrSE-Dn@q`0KZ/i vv~V-4w?[qcɤ(!5+:(3:ޡ;q7읈Ӓ dFZon Up1tMCZ'1t -KxC0E[A2~ :EWfZ~XNdsuz%F2)kiMNdMݘ>ae'xC/O'/g O5ճWYT[TNni86Vru|pjk{ .E#$?*!Ɔ8"Yy e 2[GX{E5 B C_Ƙ꽬(>WqRuml1<0fլl%W,SF2jc'x  H9<.tд#{n˥%o֪Iտť:mN9 3m}o)"laUzvZڋ0z>峋~гqX0H&bϱ3܏^bрCbaMs F/ ׶Onf׼k<$d _\^ u*478:ػ*5nY]൯.R>a@@mjKgctM󻍯nnl{hJ+\b\4>>@@ ( aN5=ؑ4JINYuDXc`FC1 ̄18O̾yG-enje dҴѻ\EC!,nnc#>R1C= [؍v>+ YGTs'lbÑݪwg&ˆ.c>퍝FLac0 /4OwilLZ HdsLK1٢LU$r &$s)^dnnP-l"bI잝DIc@@+"Ax;02 3\ x&LFRI3Cp`5|w2D|<zYCbMV4̵pǰ5Y1B/״a04"!۵8/Z8 mdp8&K'~۹OmjO6@at!*T1*f5=^0rumuEĚfs)laѕT4?(Hک>/.Y>*rl r/AcN>Ak[ȐUa@Qmih/"wd 1C隷͊Ӆr8k%Tt]lg?Q9튟zwu9dkiV5ɋ7m[ж:m+;c'Cw$DF-c\!{Bh[2v]Q˞.qE]\rٰh@mP0sL111M\ ˽) # _xAXrk+ʁvPqxV m|  ٖ/=)$"B\KN[-}g藣_Pcendstream endobj 122 0 obj << /Contents [123 0 R ] /Group << /CS /DeviceRGB /S /Transparency >> /Parent 2 0 R /Type /Page >> endobj 123 0 obj << /Filter /FlateDecode /Length 3018 >> stream x[r6SnVwtiڻݙxĘ%3dw (Lls>|c + ~|ww%FЊ<[ϲmdjF=yGauӏo]W[op H6x~|2&xyC{uս@S:)y >vGjY\c`hɯn/B}!73mfU JT3}!WS7Yݏ"|OLTeqb P ec3k@iRԦsb`xrNȔ{h$ -VRmnhPwJNS㦪w 0Aqm3*`2*qq N ޢzVcQWM vUP#Ǭ=TZ{{kОwJ}e6(ncA{L>6-@gBMP1hoXx ]U N5Ц-Zp(0^ |"+Q_ *hY{R М3hg3EM[+qڪa <+:%آ B-Ͼh ФEE8b8al28`Pto|=&h MwlآS2X`2 ?CJG鏴 =nIGcWsz=A'MU3󹜟}13Lf}jTh5p蔠q;p݋&+ A4ٵ}'nE( ꋐԲH{DΌ%ZРHiҲI֤q[5 :,,jVMYcEPE_&3Kdm_eC~g ZO3 JUCR& sCh#s]öBžy)3(u`p̰>L $8*Ï +:%4C-R̝`-ف8VzHviN hS7)ˇb"Dx4r< xMIvzO}8w <.3]í֠+ \/z8P `w9xeh*5}|sh,+  N o 9b=r#"y%z]ܢ ([y$ $9܆3sΒۀ_6.C51-_N")9 ij&E7Un(!hCp/*PMcWJPB?) ) _.Sv^K >Ю" Uzq_' *}PW~/RѢ^vE2!!GڕJKq:"ыNIh"S}(?>Pơ>A^tC+pUVd -5 *GA @tJ .gpCgCX9 \+TEktnkE@q 2[{4G7x)A/xϻ&X;#=dL[ILܾ~|=hOƦ{kT=K(r5^%N /o%x. PASN!(6d `(_N cqgF;n~}MÑCi*pG>״|GꇃZ}hbu8cu궹DTe)of@+6ya:ٷ9vSf$[E5Km"~{F[s4"׶M~ @׷ KV~.C![RRRi %nd x9@,Zmx*[ZgĖIj}!"٨q -:%v uBλCV0)RTBISE@o n%iن|Ifo5mEk*0k_lE 17 $5%刄j=ނq]g/E`3kZzhH$!ցA1W_'$OW >i5)!.6mA;>rh[pK E=ʣDhb\EP,/W\3u񝬺IBjvmlvW6G,yvi%77\會i>(KCP䃸u5я+^Ll&vڝFDŽ鞛5GAx[8M4(U>K JH|&\5+G NbZ 0seTU05nb#-pG;%Va O%MN%$J~ڥSchr4^)P.0֣h,uKp=y=s-t8uGn8 ˁMBEVBNRØ "M-IҒ W7980"!@p($#l~"s%Aŝq`_[$!aNYce%|>t .IBo8u<]%.pGԤ>&t|3}P;}? 6Xey2xrI,v*"C%$֫61>^8endstream endobj 124 0 obj << /Contents [125 0 R ] /Group << /CS /DeviceRGB /S /Transparency >> /Parent 2 0 R /Type /Page >> endobj 125 0 obj << /Filter /FlateDecode /Length 3174 >> stream xZh 2 ÛT~ɺ˲U@8gnh zLI9ؐ6"?#mw=2ӣ z3Q7 ?tfn2Xt ;_Gq7/^F,7J_x2oO¦g)emQg;r+C_ 4勤WSkLst3Lϕz(bBQ{*'3I{`%1zE"97`)5qQ b"!_qnW|'>ՔEinq0Cpݠ;đQJr+-=8)Fp-ZQ\O~X`3𲠌)܁Cl'oQ;ۮѨjfH},ăL/R\"5̽buhPtjDLvzij8=3І5_/Ugئ#K̀zj;8JUA\߰OKyG7w6ԮP _iᜑcO"<2l;'%fR:-g;]}ŬHo ;@ y|s^HsSGyCF\C>^Kd'YJqv( NsV;{d!} \3$ I{t~MLXu@պZ><=b8zƀYL"OHGQO\NEm{ᄭ6Л\99 ]*rMi>O0H2rHX|rԿVݍz[-%XҸBs-QCtT0<(7}j?9?=_:]AGӌѩ3Mn zdc{oN(aWvz g87 !_&I 8 ÛޥB ltwV8JrnJofJ l:lPaጄPVdb5{-A2TsM 4K+dh*!".Rh35 ۦMT)뾖cu19;nFdtqРF+F39Hdkʊ3imѶ-ڰ umAYr+r Wd CÛֆSd] 1OOs?f:{}84Afv`x7#VaEl&)r /a٩7E?ϕ3>PFrg1+uIQ0ZXki_ ՇP) [154҂/F2(I8W^wԕ 32Zg.M7ΠLw P<g2uY3"IuۂiQ i\ %LE Uz&:h`RjP: t2Yog㼵™B- B[³惨fK^oŢon.mp8巗o~֣3C4|1CeM9CW:25+n]u7Z,n'fMٯqԛ;ߐн̑Awq(<׳U#yeyz!|CBO4mɿ8 N=훹*?쫈*+VA{ٌ\o"PzBL[K`t`dy]fzh"GMJ',|B;*_Q/%޷|Kr_^ͷ~J$ow' !<־ژ~dTTq͐=<OcRuFmHՂ#\nWM> /Parent 2 0 R /Type /Page >> endobj 127 0 obj << /Filter /FlateDecode /Length 2727 >> stream xZ[oܸ~. T6F} 4I(>ǣDy/HJDf7E H::<\4_A6&Aߧ3{pfϾ$UHp(\yضm.;!\'X?9z;{ %%o-r{?~Ly)ǸzAUMW?HڕQfGa%T-oJ+~r}~T}NQJ(Қ^@WbG".iق"ތ&7Vo*:m.j͒z4UJUJK:+wyR:nJ#{)>Gc'ם}67P'8Y8:2 18z!K\q:<+5FxFBz+!X*'jǡd_lf5Mڪ~BR>1B""G1Ě[s6 <B1?2uUc3MO,.I: :|>H#cR2] 0 ib3s&z(Fh)MӢI.h}_+]H!~:L*Dj"vh iIklG5WmC8^h6BQL<{4o?]CJ/ſBXzwn`g6Mg("$FPW@_]C;dy^ǻ]$Q L¾4cK ĭga@Z_ @qΜo˸ vqmfiDa٠U sV=Ss8C8`8 *aSPe[Zv 1]X4~8 ooTVq8 TB챮Ψ b8C0t%{YyX!h" vY .A?q\t[" ĩ@"LsC% +gl{Duhrqɤ6Kq WR; ҈}G$|LhY^phJ.)K{e,I`)) r@nKE|چHT~ig8npYο` m p543+r1.v91*ᇦV/T<#:ʼ;$Hg]QVנ#Z 6CŁkЛ]suul s*mϜֶ*ɑ^Zz"0'xmc`i2.&Vw Inr uT!^f9&)D[kr^xiF6z#M'Js6h5 s ZcxeQV(si4=JGpuQ=v8JLޱJ$hlhq3T0u2 ǦPc1I'U:mֲYfɳ %o4eNu ~Pf+4[1ї)F̖: t/;l ] ~dFV aq9np0O? ~s 2[8rPފt> n֚~=oh6Uı=SaK;87>xk y/_u+B9& 3hLfzGA4"ޗRJM[.+Qe_Cvmcwb+P80݁xRpvðܭM!ں+aW^`zZ6xLt3`Eo( 3}K[c#I㍙د7rmg5ɖATJ믴xw\hIE|`TJ&&dwCB s>xnr,5,tq=ݱ5W 6_b:+ۀ1 4lUlʿgiJKݖҶr9ŝiucŲ;?dVcޖ"XgY%xƱP!<P xעčUlN. rmm/~%Od3-<@V-s͞a/oy|uhxeq/-}3n"$~xW{uvDx@UL3;ie+` 2'`ig( Cr*?D%2_x8"2PM 9,Ē%779eb@{wO'Ů}(~?90D+wJdz1YдPWNtAF4;ޮѯg`endstream endobj 128 0 obj << /Contents [129 0 R ] /Group << /CS /DeviceRGB /S /Transparency >> /Parent 2 0 R /Type /Page >> endobj 129 0 obj << /Filter /FlateDecode /Length 2755 >> stream xZ6?OG)\Zw$mlS/bAKD]?*y=Hdɞb "sw (+.:\跫O]X8tM\l&Zd{|aȂauЭo+S,Z^R57yp|5Z}իebgb[M~!>me=rkX䱽ynM1(KZYL1)b}dn0>XSԴԧVTQ ve9*.iTdlz+SP?fQeN,K6}_,\kD7\?6[þlWM50%(LigG}yZĴj?X?Ϩ!b4߳&E˴v :8&D(W+XSbK Q0ԑЏ?" N#1VX3){8ޥ0v;R 5`%2gڧ< VdG˪FK#xhlO.zhrI '7i.ۛ9z]~C'pϨ5+mR71O dw!wLFVv}W¶^eVw|_d)"R;P&p|ڇE, ڗ瑖T 7>TbWX4"ΞA:߼t_0)W%Xq]F-Ȟl,PvPZџQ_p/0W&T<:!һ P jH 1e7Ji>C\wb<҃"\;!4\9ֿ*4*}ۑG?A/td ir'Hm()yRcZCe1kx$'eCOSHqfgb.r8VM' 菔?DN &QR\#mau6S鏥.gͦN,Iю[e:|/bSqNZkwPl/}G^(!LK x*aEi+Tn< Eqt{#9ys⬶JoώxR׽]BFے㧪} p wM6,dOh@2|꧗83N6URaw31_A ݩ2 Ojcfʫ9(圇C%gHd ̥.vW#遹Ns[-C=F,Zao0]'{ã{h4V ٴ3[gȻk|o{SOf%?b³Fmuqkq:θ,P ӊ=H'|#ZJKAlA40M) gO͋TL hXOuP*8;B0'ǣeYsjI`WѸRRFgfIK m<(rYKqO +x"j ׃PޓnluOO9ٹ3RL:kYZ#~ `Qul~Wʎ[cq)Dg[x+LuH'.}K,Z0 )dV x>e>x/tp>i#Ll,A PR_8WG (v)z(HmLoBj^GQ 3^fJ^θt_7h%2sRmI R k4,u1\,Nc?۽2yz2 Q֠ &zuZ,QN.) ϡ`ܤp^Y);K~Uy]@ʄ"X+K \yч_菫?"endstream endobj 130 0 obj << /Contents [131 0 R ] /Group << /CS /DeviceRGB /S /Transparency >> /Parent 2 0 R /Type /Page >> endobj 131 0 obj << /Filter /FlateDecode /Length 2583 >> stream xZn8 HbM)NbbˉZYJ-n}Jqo)Q1 J<|_s:" tbm\tq:=RR(hs#% scnWWo'er[4}+0CfN,* MMZ?֍|Dڠ{LH9AO3s(;o*9)1t!(PӝӼH =d ]{y&n(޾\-u6oWee ϰf; %Wgs 3$4E,^CBۼ(4!'AJ LI/ŝeyPT7 YQ@MmmPځٚoC] <i4@8yyfynQۛք6N̹˖:犼n g=`}r)GW!V>yOSx}Hjs' e(b0v-W/Gʂh &+PC 9)s *&M^>4dTҖ`G- P!Ap2l5zVYnPBp 8Fu8ȷa]< s߿ZޓfZWi(Z樽 kk,T)KC>qumBsٮ霚^āĦ;54~X|0 6"ZIH|y=8ZUҎ9b$(tg#Z*Ny~QUjK` 0VQ74vcC/O\6S٤Ʒ78x~]TT*z1/CthȊc妀I>@q i1ZeS; kl댕1ڀo c@vd#QԘݗ^`kUM6QM#ܩl<jS1LK {++2/> nҤMvnP2KndXC%?A\Ϝz6AS=~1Y30 1)ǮZK@ِg\]~߷Sn a?DQ;b#;F6!GTGm7(V)ҢŃPًd}p nѼ*r6iJAH:Eu 1G;a\Z1~5Kveu[':-Q8fWmvœNq@_%j'@oɣأSMژ$MFϦ Z7 X>plBYAd,)G.h/&j)p(fk+%hi5ZnF +fH b_g|? 8n|-gvϴI#.`z@(.2m}@׋|u>;0ww/j˙q=r r8Q}=b#zۃfa;,5K̸$:R񬦊{Ώ_MwؘUSm&tfYM3#FYz6 WV IB53j!,T݌z 鷁J9DClo|F1}MQKKS5/{@D e#5A1]fFV0͌vz3f̃{N1y˾{ 5Ȼc*~fw;͓_HT5$`VQ0)8u)5cDZrfip0PL}LVwb'H/XқM?pM7> /Parent 2 0 R /Type /Page >> endobj 133 0 obj << /Filter /FlateDecode /Length 2918 >> stream x[뒜?OIMd$@T*Uu˷;?RTgXwa_xe{4;A'/zp.<7l}WEǁ$]<ĈY=Oo.O,Z^)%V%7 tw{&-Oi#F{`wI"yKxXPh|/藋"_!ė?2*i}ulN&8\SicE$z]wZHBB-$ ?zsM^!CMp٣vp4ym9&R  bWG4/"CeεVMa7$?@NMȩ7r4^ݩs6[PPZnQ ol~/2i (ۑj@R$#lA ,:Yb pX4Dil&G(B=uj#dh5iF@{#Tpmy"$ 5BĹip o;lKkeDRѓz ,2`L'dlh[S\7V+,9 \֌as^xeNpxD340!Wv8OE=i(4I,Z _5败Z'PKоC߾"mܻtH`3w*+$^_ fYkQS 3`9^Offr< xnuVmr+,@`iTڞHLsw`Nd}=i`d},ǬLDiTx x+]H~`Y2PiqpDדLg̿ώ_D26ͻ qWT8 F!bjIKwZf5FLYt|UN؁f(gG )BG$Αl!X<~|&!`*-UbK2g栊\09&#i)&BFL1o!9kEA~`aPA6!hK)]8±zYiwNӬ:yuxnvpjL=rٮ0 zSJcY_\GUcsq7뙻eonZV(ڈeǽ\SZ2!*eiwˆ:-TC`Z7#Ho;/n~qefwTS.'vvuj]Ca}}5ב=';;ߪΆ7Ƞb4GA$0F1mAViÒ^J\˔)pZw0,Oe+Ϭ_emUB5@L?pZ驖J;}SӁ(;sc݃S_y*XFPkuY)^J,B& ֎|1.crwԓ k^3V=8R hIcC&O}Ap`n%͂83\2~<єѓz ElʈZ܏एHPֈԚ7W`Fgn=SM4IX=cX0U4R#8V%&/Zo&.!xl4y|5ZCAA~:?lGaD̈́!)=>+`v%MSY=/uڍ1{"[b/_ArUY5 }L&MmŎ]Kݩ3[:k8uq@u!Fl.l[.>߽E֢O nJ* =id)WVѸJZ ӳh`#i (+`"^Ev$&Wuz!q[ǩ˯xdPĺpo#lRFv&P%J6=OtG䙃h͒Ȇk#lT"-mù:;o'^g_$f8!N;OCUg Krtnk `p/78xpu#'SM|s/Vł6U٤yYcMV;R#~́[hB0l'rTʬ_}44(uVQ=o*;Kx[Z8@ [>Wc~Bpm~w4\$fm"%ӯ]{Rxerh~RY5U!?6($lvOjm^,c ~QQ׮xy"V:K_=ne%Qjkw; ~CՁ}knĿG B t/0X3Wxߗ'2\1S=yE! }endstream endobj 134 0 obj << /Contents [135 0 R ] /Group << /CS /DeviceRGB /S /Transparency >> /Parent 2 0 R /Type /Page >> endobj 135 0 obj << /Filter /FlateDecode /Length 2819 >> stream xZr}W#A4v͋%#өITIXhDW>)zްK{J v߾ Pb?;(y ?CnLL8&C0M,3ز;[<raՋɣC/av q5s?&Ξ6#Y~d_Aws)C[7 !cLݠQ&h{]\=p廬_/g\n$+ʵǯȳWOgzqĵ\8xB^ŝECR[)וDjȯ'aTr E uu^1tveTu{5;ķeu;wU5ceduw0ѡ[>{fun^hKFrTvZ]5wm c;=@"=19z?'u\fIxCnzOc?ԡ5nH1d'jS[Yޒ!n=Ak4+ugԶ|qm]殊EMqZ$q-#?+ʹ$8d KL-07YK>u۱xX%[PKR˳^'O@Aī$FyA$}@ ts kI,#XkqB+juO1<4cϠT;F?d} d;V8f1FM=0< 2$*:aDŤ4(>dhuED芟ȡHZ`Q&Af:Eo~?\@Zrq7@qeIJ@RD+rPRl53!5uN0*)h=^AfoTY5SVr0saMY=Ж5xMD1i8j+!@Z]t4sӃ=X)]6:%`)]b(?ahOZzbccqYp9 A|"K: )$<?j9 (KpAj ' {yI߼mox#hX(Z{7oNcp~7-iS :Gn&` Z@ v! =gbw9t5LĶ`@E eBYmESkPk+eƕvGc?R˱:,OaYqT; tx6jPߓ/ּ@ 2z1ȋe"ԝ~`QXM莭~ w5Ґ*qĎ*}X._Բ]#tMy]ɣV/bƅ(f.բ< :^3,ZnWmi(W֠x?Mqv9gsP4] UO xF(M:Ðu}OhZGoca8pKz;>b7+^M?;uty ,N ±4 O  9v/7ѷa^)W1O҂V>%2^QQ'|l.&68 aT9T܇EB @,!# 4BVa؟N9cfv2`{;k#` z;?Z]5%̓IU~j*P Bsz?pa"jSq$2ƁJ#Nz9߃? oIw|P8L7COE3 ֗\MQMy>'@+j.e@|bf=~pMR!mun~FvcW7;PEΤh_]=T퉸6dۡ927e S@~h$П6qm r+;&>ycgXHZJZk.5ӣIE!.$̶p0q'_H_nI>>Ugʢe>HbPcC! 5:h FNвj*0xj NJZ}؁>{~њH`K$_) wS\25P^\A'E|:<`Ky,eF2D<_#cwS,+T7To ][Gz-yhn.]n7М;8J}.ɷo_|b~BGޑk?Nb-e-R5u=5Rn;d5yҘW]ZHҪ"TEhW_; s3/E !F,1T\Ѯ#D%췳jRendstream endobj 136 0 obj << /Contents [137 0 R ] /Group << /CS /DeviceRGB /S /Transparency >> /Parent 2 0 R /Type /Page >> endobj 137 0 obj << /Filter /FlateDecode /Length 2763 >> stream xZrF}W>PU[eGƎ#;6W*ڒGP 40J= Uq\=ࠧtSK?8''gtqbwE.}DO!5l=y̍ ,)x ~xϧQ%5;x5sN_OyZy{ȍ|-ܡ{o)nҗ<%~h>< &ŌA_{X*Y<|l ?xȆ/|-Z9cΑ?"J'meVGe5"YHcգ}NeCR0NV׍jolg )%|4Rd$[)0F;BC`TeT4gp g2 %9v ̨VgS`Xf"'h:u 4 ^.`;z!oX2^HunPuJ>mti4+WC[/TdO$E3^NR]Rˣ3tKG\q[_&:ދi5f_ qDpx~# :3oD,353Nl3Ajfq=HfIt#v:o%DA B%IVKd4ڕmނAX*4e)ߒ[( <ԲAȡ.'- ^e&vWq|2Qd1Jr%j.[+XMv{';u0J ;ܱ7mHn`ہ27[4ZHYfPڊFWTM az57Q@8†M3b h;}j63Q^8Ir?{ /SEK<9ߨJfTʂ6;;[%y40I U1S*Ka;ԌnѣvIhW'GEA;+Ih-+=9pۛlMq!CXdABQ-[ <ݔua:k,&C^Z(Ȋ 2#F>=ϲ 0[#Qg- Jо"t,Wl EݬFvG% G}F,yn6{=3GfZq(m!>3P FTvD<+4')r įIX^STd MU.Q#E62ΡjICɂ1(鄀LBl&d].D/e'?Ü"x$$)<~= be` t6CPgNyo',g05Ew`ySO3]S,+D*ɈJq="9R$i+8#FY=GTۋ9GҞgg=Jz,:&q`$ًiD ddzJ?h5M7J0 | x ֙TpzZDkdj߱,EgUr)$:VM*wvDT=.zh[QgpGӹO%`s "FUP=@6:RYVNDΧd`OiA%!`}NV)[WMQͳ(O'*]0$ ݁9gbc܇^U+l 4ߏ06̀9hoƦhhTFjHi=V"f .1x +3 QPY^F'ȗMzh֮Yt[A5:Q0iV˪I .!Oϣ;PR QqjܝU^"㓧c#xe!l-Jpq]ͱ \\D/ z #+<\1˜ƞxӰ-Hk |bўau7YnJyF|*/]t-.,sip`.ѷJ 45 MDQrͻt?2 Iv ᩪ!߇4$o!ߒxs ,˿%18DŽw̷^,/'Hlmendstream endobj 138 0 obj << /Contents [139 0 R ] /Group << /CS /DeviceRGB /S /Transparency >> /Parent 2 0 R /Type /Page >> endobj 139 0 obj << /Filter /FlateDecode /Length 3124 >> stream xZv}Wa_&˒C[K,щsœp< +zV7;L9tD BUu-Gf1pfÙitf>o4U`k r 4$gO_Z!puL?N篮^>gO"S]ROS*Dxn$y`y{gU|3 '%"usv3e<ޚd>6]ŸuSi~`x,>WpoۚR8T򯓡 5튒 %Ņ)q)'~8f̊Ȓw ZZEwƢ9hrz97:Y6 !<9Q-X]XmSռdf $JcK&*gz8c7*1/1"7ƾT=}B#p8l[AUYL5F| cBj+vYvImY~h8znX& ~dljJk}XtU>)Cfi~FzgUxXvpҁe*bb{ُe- LOn$)~'+!~BvTu8݆oٞoTF9McoE+#$O@2U;pc^X%طZTPYk}Jy?0`. )QcQ ^"Wkݍ0J׃KuR%xpUÐV Gry/lWߖ_JDeHd i@=P[6A?,MF Au+1 (:Ix.t:Yzlj<_g?UEX?">h47%|B^F'LQ Ox"059̆3FsGQf '? ꓶ{؇̥OVjil4O $5, u_]E9S7`t{OV9vE ښ$'aTu(Cztz^PjLs9j].LnLd F T<˫W/˘v$<6ÔB||*0S kc+d8%Lj89Mۣb6pdy?90.3J+Yit:c+j?t?y<ˢ]zdBmDg4`ՁmmCJrinٽWA}X&F&Tsx}tBLB߰,|C%C=8(,C _,:ry8/G?9|h!1jԁis@8, j#(y~rk'yB@8QɷV*H$A SZ?'&E9_DΚd e|U W#WE@ޑ{BYw9/TbnW\P`]EU[i͸O u0V4f= #{`XP[=PIk) zI<4v Q7 CǩH]ǰ4f.^ESIiP{9ȟ?Vzh:s2hu3[@;ä~X<g5 ᮎ%&pa!閠}7%ZUw4R7jYtGLŸ%><o:kǜg;B84r;yZ^ZGbG{=]#r hDZ}XAaƣvDeٜAaekjG$M sxRu^. ULrfm@*Uͦ쉋2%-}=߽7{ۻBo ?S,?YVg!/"t E5eDoE_TՊZ3k=W<f6<>ya&nnj!j jG6]6oZ̼өsɆa!#CMв.a" +m6R}Soa:o]S5ű +&XTz2}Spi9G2N.=ݨ/[&GzRO&l8lފԎ":9C'wTvP{j?dY7%Y ])y-ɚ zO*p㷦r68ՇjaJo(F]6"0ӥJWy/$%Z^Kq~$4GӾsnڍ~mAYBka*i+a]$>,TnyEU6q+Ft#ۃ7?ҰK`=ɜ&|(lY}1ۻLe;bE;`\]hxXFendstream endobj 140 0 obj << /Contents [141 0 R ] /Group << /CS /DeviceRGB /S /Transparency >> /Parent 2 0 R /Type /Page >> endobj 141 0 obj << /Filter /FlateDecode /Length 3555 >> stream xZvF}WK3Mvͼs!E4 ǹ&'Ku-nU?%"r8?>on̨zY4<Cή~x\f)s Ͽo.e!7146# bs?j-;릑ZB= N*C^{Lgrxg6 O˚ͦh]U%'Mo/YpuCʪޱ-^W˶15d;G)c}lں(Ma7q%EGjN8k.ոdt:kפHw|wk5? 00Hyu,U* & -OrPǩf>; 2/}ߟ/096,j:.3(x=1}_hx ΙU?5#E⤈UqyEa2YǨz8!cCh;KsU?-B–mz4ɃtJm @ښ]r wJS/ mp>̣%yN'w[0swÀ=oHe)0 Y/V-We0.3p糬%>2q2˼޵&K"dk+M}QDK8#k.Ayy6*NwiGQU@#C5j=G~B"t #㎿VBdHo$*ҁq7uj:Lں+ʛ0ǻf"}r3xQ.+[coՈ|- ; رF?d8d8tsAɛm堎7p>n%p_S^&18P qȷL fb5J6=:CW|ˣdn+w`"}ɓdrUD%< 2k738.DMGntؕ)]C>oW[M Arx:NVw2/<2rZpi$Mz:P}C hmC/HQ:h8~2 ^/ b|;Gu:{.u͜&7:LVT2HB;nˤ7YN J,4 ٲV+K只h- x:Aևrpˮ|* uuދZ'7Ee(`v8Tv{ԃ!ХQyKp+2}?ۜ wUsŷ\Ϻv36uR)ҽ(*8C/Zr0Q */QvGQ+*biˮ+Pṹ^ ,Dˑ(4:ԣh2Bugg4i&>u@#DESIhp ?7ɧXKӽ#jژcߨLtnyȡuY׭'NQ6bVWc̓g שAkaL#Q|םӜ:tOcWYt;]v4rs.*gͭ]R7wA,{dnĈMtȨ3HbHj@I&B|Jws b>P:˜kLyv"Q`a;c1fjcv4gNu&0UȑA/b}J십h8œnv?Oීf}?/cpڽK3$Vf[[E}a5T' Ty2ϓyRwsf>DD?P( q'wBc7Y$Rf0-}a>L9N "Ed,ZJղOjU< hPFÚ7#;MFrߴLsJ,ZOT81Ƹ>qM5N -vLҘ.'վ57JVOr E%75 4&9^yu &D\`7߿>Z q:.m(Ӂ.OjT~JY+5J+l f%s>+B6>YNQV J]^& LZ羹Zѻ' QǖcU#/yDocTd( }AAc M9:*rzWr`ue< yFMynYF>Ә+.:1qO./ņcvQѰ]C⮄MU>h{]f_=;ƽsy>Nr3aNFc/B]&hq_vZr# G9OuڶB  %j c^i7^.Kfg<2,CMI++jvE]T_#r>_0>Lٴ: o׫T D8 wWjx})꫟eY _V5[h:1ięAMcȢi8P9ƶ vdEUd۪Tk3n>.UZ ԓLԀufzXL2E^nR;_ƌum%nlg{G/gGJ;8Jv?z⳷s|R#߿_t_e;endstream endobj 142 0 obj << /Contents [143 0 R ] /Group << /CS /DeviceRGB /S /Transparency >> /Parent 2 0 R /Type /Page >> endobj 143 0 obj << /Filter /FlateDecode /Length 2290 >> stream xZ[s6~[!{gFYkFJBdH 㸿q.x5>( 8sΡ?#G~3隅tgv}Vr ͳt:Zaٛ+C w0\M.W)A0.gJ |ĸ#wA2 w{$qAo!׵ܩC'ܔO|*q5tOtml$ys}\ɰ",rzD\Uf|z[?' FQCA%;GT^trE4 1 wBZN} e(Nr4r)"#tkA36"{C~M9H kޅ  RZi$*(xp# *_lm~z:8v ?Ѱza9yM"!Fs'`w:E14v4&h+J)il$cbOYm.*?""y <6 I&jJ nZzE>fUkwc=]s{IOH4n&_j#pY67*ʔq =gLb9T94~\նGu+w't'Z+զLL<ևa\IU $~},U Nןϛ[GiFs˜JL* yge]$)6Hc*YCɤ%6rڒ ҿ]!+kN3 ZYPx2yh_@DCh |X"[0NUUQaev,*C,c=_^_pZb0[ Sl­A{ R^)^ʢh±0 5gc6_[xX?08o݋kOő1f5T!~ y-zR$`M39ʂ,~MBqTriHՐӪBBNg7٘leUo!|yI򘑽>r"1>{GJmeyP+ʪGRe7uW3]pYA$=NLM\H$9/ty K5kԖ4}e[N689R)a&zS!߱QS~qz%ܢR* OVb}Es)bu#RTC3lw"0 i[A"كf{/[UImQۄQQ6CFt[C?`Tv5e6ֽaA3rI5F Z7w둸6n-]fÒ)J 0heFl 0z:lcE 5e>h TrMş ]x5tG/U'Xw2*N8KsyсyFF3DQnBm&g׹=.:IhhW0cٴAb4G}96cR2k@+ K!7סZ/olj66py=\7z}jœHBˠZȹ!#{N voFLW|-z`߶؏Fۺ3&/=T,TD=}#l[1xS> /Parent 2 0 R /Type /Page >> endobj 145 0 obj << /Filter /FlateDecode /Length 2010 >> stream xYRH}+aVTAKq%T"B..^ q{4#[#i,C*}O!~ GbOfWr4*r<1 ;|H%<}S'w'蕧VE0ԪG EGdq.ct'u}htsro|qTXIe>>]_'#>jO7y8-NǶ3K-4F ;S)/"^u[ߔ$c3F\QWvk z63klcHP¤1HA<^_01"Oʜ넹 5uʒ[A0[#EQ\05A5ԏm*?PA : Ϝ gBo۶|o@ j5iɢ1Ni=2_a;$!@<-(zQ4RnH;&vrt-PPp I_AKT, Aq 7MSmqi 3c|4|7qZ2xEQPpH Y*də_Tƃ+ YpM!2*Xu +CWC 9NSC(lNY[ t$!ä2frv>:M۱nkI$$4#(L5윟 W@V! $ AOz Qq̾8]Cub/tE)7B7JXK=u$3CÖsfi@w\Q@gPn~{j_f͍1M|qC5fBDIf<.$g-yDrmE ZF扃Xj7!J:~Haea(u 60~` * ϖ@+A Y(f6F]~AAYݖj!Fe{/z=6='ꋡFG nHP>(#MǓ@dv_3Ȏ} &YVH7ְkփꔃj* WYe =S3?l08+xP7R8pe*&7T3aM=Q>@A4+L]/l|v:֧LW (4t~g`0hS)a920aNzX2 Su$Q A |Bz냒^イP~CPC!JKu顦ZVĶ}Ӿ-KOrA83ņ KӴ[Ry(wOw[깍hmSݤJN\͏@ƫ`tźV9ikҨnZ@> /Parent 2 0 R /Type /Page >> endobj 147 0 obj << /Filter /FlateDecode /Length 1506 >> stream xXRHSOtlp0*(qt0üʾNHVXӧw_D->UjI}[k)`SS$I@%1shBppyAݞ %&&O?|' 7Ѝf v eG eBdzx+|[Ǯ=O'vZa]gY<^DzQڞ>Lv*1gqL8fUd~+ůq) \V j,-|2ַ-BN[Lֻ"7QQwQԱaV{aSuu@Y8 oҧ 0_kʛш0j9M7ͪy[ys%4F^(JS~p@S Dx%T~2/Ll|)X}-BYz B sAܯaAÍj- \G ioҭ*r!0oe޼8 VoE}Xws} '(zcàT ýOD(%X ,{1WyK?P@0aZx`\'D2$90PGbjp =f8xl'M(,ɵQAdY;@uAhS(/m4uc JS Д)tM#uF~]v{bnКH R+/]DYahrرc ֠7/L6L,LV{fA@] Ɠ%E—I⨨؊.5>5a~BQ| J+#gni^N&*IcC Q5v*"7&x"jLjE5+TT~nݘrTC|/fAǂC{]Jc r~J+0nu!N;A M> _ԋk{z3̸ev;(Ehv@r<>,QVbdE˛cVdz@c`:VXCY'T&TmC*-+ 2ehUz٠l{XPEjڞ:Ke/yCD"uO5 ;gFj@8Y> /Parent 2 0 R /Type /Page >> endobj 149 0 obj << /Filter /FlateDecode /Length 3166 >> stream xZrF}WLRU[%[R;"[! \(ߐ_?{1@Nʲ)fONb?͉A~?_Nt&xy;?iWy:[u7duÕ>.<;r?yw{s:[2 :J.\L)Il:y& yfu~}={WMqW̿nUIHfW7pij]q=3Z*'՚mXGuQЬ"%MiT%yFN֩ 4S%&&h8{PX *܋2 \ hfZ`jy-52K(fЇo4< 'KVUBC sdIQ0Z'M"w*$|o/^d8mB6{\lGPa*3Q55}5juyѩ4,4ئos R]n[X+$TيS"_sn!sQ $J2] }u]I`kkA`{IY~]X$z#},N аZ,cmluvͦ! j67\a;pU IF\ۭ},k4K'%F.aq ?τL9*i֌x /NsؠᐠV7(aǷUl QttttaVb d݂& 5a4©Uޥ{4mzd;9 P Znr(]^@UU|% ARPBA+RqT4&d$P<1ª 14_K\uAAM) $O A= :l]wze/Ť _W3WȰm).~D;LdxJ2t)e@BRh)@=qƣ]:s.!??)/*_^ I߭[4@uA̲!}>$]po_8e9ء*`7F0K N&!oqh{!`zY[Ezqx]bpTR@x:v AhP() KOb+5ۼ,,W=Xy*+[h+Pv錱OfIPiWsDYPy~GtcFׄg8PN,%ݶl+CA~<Ź*gjoպ+RTH5%k Tޛ sw{ahޑQx߅HZ& j3c2[7GL3 ta6{AGD3[Owc̪y@c箃zF<ƸPs 7/d=O}bUa1HBjWku.ϨGx`vF;%i "Y/g}xQ5LM??,`8GF=fڭH8Bcq) #/Pρ'HM!|Nf ΰ{hB{Š~v C;wM̨/vtj+щ" "zVdl Vk˖;B?cIj+^ͳ4B;ر G6YIxcP˽h<8Y{+1(eq1$u߮޸ٸMt8)B<Ûov}y{;FaTnrEA"mpp G+ZmwuKm1i7ogBHIףh%bzmViu Qx@l l~|(ݬ D[\DbC k/XOalr$9,ۼHHka?GP:Uzے9 Y,Ţ'6̵|+^-C7?$MJHʳ*LuOm˝rsSmZy_.כ`AbWq08~8ބ2dkay%@?EUo_4Gx$E*.펿S6ĉHH~AK5ܯ?TO|"! 4Wn{Ql c|Qj|?zُ7b"b< 6IJ^\FnV8J:zk;<5ƒ<=eEݢj/6zCXɔH17{%L,TI9fCঁH"PM|Q뫋\|XLOVyP};Úbhxs^UWSh*M_?8 ~css/'Rendstream endobj 150 0 obj << /Contents [151 0 R ] /Group << /CS /DeviceRGB /S /Transparency >> /Parent 2 0 R /Type /Page >> endobj 151 0 obj << /Filter /FlateDecode /Length 3606 >> stream xZnFh,[Q 8V Y,Y؜DDŽMz W;nEn$-R}UuW_UW"=sp{ޯ臫=5*vq8(qtU7A.<^ՊEgNOы]CC5R.fbN!,:{g:O6u@/e AB}t͏䯔^]'304+i *:i|߮#f՚ SKg I&T1ʛc/i  92Dӑw+i`ɴA"][e,o@_^hWYFCfYꆬ>$GRٟKVWeAqSɥRr2:{/A>PhӱLw@e t'ir +9s\@6Ujuj a\y`*pC@0w-YxVS=1v O\AP囊=Sd'GÖևˬ<?)AOK=5g.J(1G[J7mZ'\wn2kiZKFlɨ= SPԖVdScڔυn+HJV6-@j: k߬cgT@7LqU^Ut=5:9AyWŽ!p sIP6Vq Ʃɷ:~RrDQn,n-0^yId US{1] \et=1e<_9IL'K_7ن؎X$l2%p [pqrYz=;@vIQ[Vz+neAdp'v$',|-tHs1b@1(;_dH[ $S&@zǣz@ eoLHWeU[Pd߮'@>/<v.Ds]\HeJ |-endstream endobj 152 0 obj << /Contents [153 0 R ] /Group << /CS /DeviceRGB /S /Transparency >> /Parent 2 0 R /Type /Page >> endobj 153 0 obj << /Filter /FlateDecode /Length 2535 >> stream xZ[o۸~ϯ uWMnm8--ѱ;%oGq21y1~HcL%R=G,_7͠/ V]( ZIњHn8v9^D+,h,h(pm캍5wQZ Ǧ19 ь!ǒ3l6]K+CņAHn_OWۻtWDi2W48gQRsXYg"x@.` P{&k(dZYIe&nˌ7-g۾43$Eۺ=QtBg 7bA IƳ/]Ifu\n #6$򪖵2[P(1K:Kʎ>8\1^DIy$O7/%wE L@ӌ/lh9M做# I=R^8xshEmc.vFg\l& U)/Bt Ty!1}Tlu42Kע r*bTq´52-`Rc_'"9'cFiӺek/׭GfS4&bԌq' fy6֣qi;ALAz wM!/8 EE 'ma'qa%C^^\}@tȣGLeSx? 9:vGB>d6gXU=ФɘӴ{vDž(ȵ,[.q J ^:`gyw@y*=z|C~6%#fT̲_q)+uaqZ99z;%|r֞ūO;}ݛs[4زc>?ܴW1X@tF@ F`J.zHw%9Zu}m;{([C%)ySaV,mHyM%ײFmJ竏xqӕ:(3vƒ෶Տ37ĥV pJc"}><ӪkAC/q߱4sd˻ $i-y*r|2˜.P(zgAaX}< $CIPMy6 (Oy/,6閡&;R^ihhķxUGNYBƕ'c2_- AP8G^1295sB|9snb[jj~=IfKendstream endobj 154 0 obj << /Contents [155 0 R ] /Group << /CS /DeviceRGB /S /Transparency >> /Parent 2 0 R /Type /Page >> endobj 155 0 obj << /Filter /FlateDecode /Length 3336 >> stream xZn8 l(QW l'$3IbFQmMRG}JqD;bU ?!lWMG=<-nlz8RTBb "mhS"   s<zqN#-(Fx5W<`:{g5&߀R]$eDBcU&&BvT꛽~#A._,u]>=y2>l2]E+&acg 8g]͚"O)g4>gf^s:_6Pˏtf<uul%#~i} ;CM JI&EIY|nP -y{uu\,u>T9͞b c۔!Ml%YJb2m|H)DYM|e T6GLھkٓTؗ[zS1hܹgɳ_zz_^.si'I&\z3߽F[4,pWkJ$ `o70&r1 eshpE>@ 1#Nzlhs ujt)+)gkj$t\x5!b~fE &KKÉq)9cL"lk8R,ϙU.%cbyOzܗ@)ppO9${]k`a3[/YN0-ΔH?ҸJR),:? )_PZp/^IA\!ȊgN`X1DMqm|.|mʳ"E6QыJ7*^^=(*zmp[EE0YˢYkCys s|#FeOy ŵ m0 r2}??@%F\϶o|~=  LG qPk6$, Dfop i:V,ѲLiq_\[.IS+E߿df,x28?D`(&Ԑol\>sX>ЇI<[} @A"leSk4SƷC:oӿC"_ZcT w6Mw!Ai&ioC!kY*Yk^i(iv!)K`{q'篞3X9A,e+TOh$U PH$#]=h-0o4F':8#Y ȩ0P!PyRYH*Il Mwڼ|e[H֬%]Ȓ 8 UUSpZx ^ B$%;ј(oi~.\򈡊[!{K-xKѽ86M?=PJwnYMK^Qus! $@~jR점Э?^uP(շrC0L2J۫;Ъ'5& Ik5)s~6"c˴vp\/{v-T:{j;&_ʔyG~ݰr.@9-/kcXyF&٣'%X bws㺶msSVKz6ys 18@$E 8Ńx8c[CIƅODD0%z(7'fO [Q#ɂմl\KPRm˦y#?ܠw>܂ēNB#Pzt}Ϯ|N]G aweǠ(\svߡ5NH,A  !F_^iQf^~53lh%pXKaa3#9VCwvdb(koʌUBa#'4!Q3U{zQ?z9b彗q2N0vY/aMaKHh3+L"H(\}w);|P ѣSlQ3Sb»{JF7]&(IQߦM&g/[=Egp󋳗oۻ*bH+:3H#H)<̏AT͝󭖫vvē2vS0'mJ YxI$Y d Ϫx%7K7@9 <(" <ޗp-[phy-v8ww՛ ?½f)Ũz1ƳY^*F ,ٷwr= )!w^5M¾VKD$M]E3݉vDotV]ʊ8LOZ?p7ЅnzCӃu߱;ܞ֣߼8,n,ֺ?xb$ݐݎ*q&`t"rcHܛ^ũq5{ޥEZWwNG;t_MLvDe&J P7?z(߿?orx'S× )Gly l{@z_tendstream endobj 156 0 obj << /Contents [157 0 R ] /Group << /CS /DeviceRGB /S /Transparency >> /Parent 2 0 R /Type /Page >> endobj 157 0 obj << /Filter /FlateDecode /Length 2726 >> stream xZr8}W\ 8][$Yfݚx*CKD["5$0__<2[F! ῧ>[hw`%س 6 ݯ`|F]^]7Qtg`F|%&[E5 mH蠪W?`+W *ľ͞~/֡6] FDO\ 0Z]\"dNv%Xk9ZN[ďep=2$}Q_}]zDic:,Ec;,dx\?&+L}N4Yxj8 As͞؂0>]3e'q{֚"+z,[P8`¥. qJ6 <nF}iѮ<ҒSNd%b;w[ o)A~A|0kNG[,{괃G7ello ,=. Ub"| (oe"ca~I(RXbh3*NvUhdYĄ1fFPJUCD%GyRą\d f4ч`uU8TXR՘S՞`: 7y!"kqYn #m4UJ,-oe;ObYC[7+<@VԜkʿΕ'JE}ī9/N4`y>;(="3J ,##n`teqa#@:-_{zf91X35t-Dc?7hӾAz ߤ1g:BQceo<2VPB0 ؠV+DJS.n;7XE{Aq}`.IfupW/UU4B9 hއ46GS4*r7-9)D+0-*©mz!` 5C0MU3Hn%M*,F h`DxT[&e^^hnÈ`wB`zXA !p=֋Rdz7=?Yկkѯ͛L u0֯v/2lȴWRGRzʥw+[vEbĤl Ñ%u๼1v/VOCdtdޕLLR E)i ^PF@F 8Ʋ`Gzlغ _~+6w`p[ +ȵ!(POZE2ȥuu} ~> /Parent 2 0 R /Type /Page >> endobj 159 0 obj << /Filter /FlateDecode /Length 3100 >> stream x[6OʇK* {Txvۃ2y x-ɲe[ .,ɲ׭_wK=A+L3^3zru&GGÎ㠫ܜ=zF"Dq W)_=}/a0ԗ# l\G|ɇIWOm~Ic+ =1y+*I !9.+!bH^\CR>~uuAMvȊ͠,ԧ6Odԃ*)v V۞0WP'XGY2 {#Ic!"} :#?|w' ̐χJQԎ[0jߣdd2?fWhWD ]컞W@BQ>Y )`Շ(" :CI߉q ?&vzz]f>F8ZLMfw)BDs}OǬhM9xLMV׹j]@;Q5c,7()P&GhcgJ0a)&*ǟUΪ/tȴ{ޠڝ 挭jJ@~I@]MYz^h VI{ MehINpP?kλ߁ =Oc]}HҬFYBRקX-*ePbU)-o@@T䪼;DJ$ Z2OaK=GIop %k7>-oA/ճ//[ Yne'a@y]}"^gsD:rO֥ak-X3[w5Ogg)4w ͒X P3d3l"{$Qb4^|8Qz;\&gB;3h;rٻaL+^C0ذ03nesV J:l;u-uRlӯ,5(YA$Ou#߯p󹙵8Mm! XNfu&w{8w)*`XC0ΤF,Zg(oQ@۩(m1* kUeu+l4oiݏlك-[`Gv,8wjߖu._by Jo;e)R,zڔ1NE̶,f͋JP6$9k{C䰧Lpk~3&&N XDKx K2dx] \`MD&./>2p`q,Sm`p,n}o^o]!CUКgZ &k‡[gqKSқqKgtK]+dV建fIz5zQ䰎 LggjA B B*D8p}aZD1V:wrzu-^Nv*t5z~Y=lpL{dX œbGD6C'>b1\m Hg ى j'pOό&N|K7χQy<􉒁x2@g |`kq9H@F'Fzƙ $dg/l1 -p/Y. )pB)YB5dy/ p1n yn}]llN0$ >S#srqF]zwr05lmEm΁Nsds<)21? v*f=tq<90ccwg;vv>eTI} dmfjȚkX\U`֍--;{$d 7?}a M1&K#7Tf q"% DŽ~oqUˑGiR,=4{9y_`}٩//Cs`}\Y ѷpTg< &WsBff[2e.]3As-l.;6wE;18dMrsm ء6zzsN$Uz/a ݍ#nzF 6B&B&s iyzMU;FLzuB@!=]r B8(+#)ō,T*;,*J91`-<6 gM^ 4-vXTv*X3 J 6cYA4Ah#4PSrܦΟ5.`(p<+|GKiˠC#%bLW9xe a>!]Zڕ+_,'%+9qY6)wj3^^ έҲ#FC"3ȠF4쪜+*B;?Ē|NYIҼWqq).zU6aUFVlFeAgay]0TcHD4D80nWt,e峓J)9m{@xJ_Sd9xNgkɾ.!eo#3,N+3)%tb} Fp +6%5RQE kM`!NC07X_ݧbQqAki[#( ,6$~`[,, h%%MVA]s1|y?|k0Kcj%Dq{筘<)q솓zh*L 6lQ#,/6p' ۂq)^00]T᪍΂uumQmٵF׬x2mWĎd {|sN2 } g|- '}ykP{8'|:ѥ}iV*g,=+4bJ0;l۰T\ H%o9w``+j(⸇FMB2U,U1׳xendstream endobj 160 0 obj << /Contents [161 0 R ] /Group << /CS /DeviceRGB /S /Transparency >> /Parent 2 0 R /Type /Page >> endobj 161 0 obj << /Filter /FlateDecode /Length 1962 >> stream xYr6}WoԆ$L&ȩ3rNܙDH;7WE*Ol{1۞]+"HLzL4LDC'_ŤCih.dvLlDq O|ܢOӣ'ЁF7լz3SrSd¤ӣ0Xm;7)ewObP>TCxK6URZL&frj9821bRG!OQ 3ewek&dE^ٸrVem00zwr~TGXAZ5n@&̈́:vX&7mo#tcLV⩗YG{P1T6*7Cu~&tנkD rKVra9>Y0~x-[5x7xmx8n^ k1mw$ICIB8H3GH 0 5DBmQdUu{!69\Oٞ(YyAQ, G[dlT7M`$$Awԋ)KO7cCGDjTڂ5G]oȍ_&^FωS-W ̌R~g0ƈU 5.e-=D0&K&$rc D2psy SL̆ /_JJK+ɸVQXaaKoXwz_Yƅ~gCdP= @`6("ژ|jvȧn&ug4YJzUW(@hXc c-D;rKtK13{OW@뉀Hga@bآDڻCL6Uۡ5 +llQt=bGqʪQiJʧtޚo2IŒ Y 5LljʢCͪQ!MSUtP1q@bԪQ%$ Zy n~8qkql skJK sUoL9 uwX E./$pts#3o8atp8Qȇ'$K+QbbTqR3deRb7Vfe)ꒁZRlv7}U6;2"Y#jo e{Rqɷ=XT肜ɦŞR8&*Swΰ#Nlh~z>ȡfROTy}. aEaQ_5;@%tCLEf@]-.^wu Fr zI*r_]á+,Nfr,T6Q,vWftz?ch1A|No޻(s,)4rP[@$.85γ0z_E:f9`,Arz UE"z3Jq$n_ cݧ{<*Ib`}N(}ƯTOŗ\CL;.[~w&n#]GwYȻ)MWٌ"0kendstream endobj 1 0 obj << /Dests 5 0 R /Outlines 162 0 R /Pages 2 0 R /Type /Catalog >> endobj 197 0 obj << /CreationDate (D:20250725053516+00'00') /Creator (groff version 1.23.0) /ModDate (D:20250725053516+00'00') /Producer (gropdf version 1.23.0) >> endobj 5 0 obj << /pdf:bm1 [3 0 R /FitH 811 ] /pdf:bm10 [30 0 R /FitH 381.4 ] /pdf:bm11 [76 0 R /FitH 412.6 ] /pdf:bm12 [80 0 R /FitH 660.2 ] /pdf:bm13 [86 0 R /FitH 587.8 ] /pdf:bm14 [102 0 R /FitH 775 ] /pdf:bm15 [106 0 R /FitH 688.6 ] /pdf:bm16 [114 0 R /FitH 599.8 ] /pdf:bm17 [116 0 R /FitH 671.8 ] /pdf:bm18 [118 0 R /FitH 254.2 ] /pdf:bm19 [118 0 R /FitH 189.4 ] /pdf:bm2 [3 0 R /FitH 775 ] /pdf:bm20 [124 0 R /FitH 206.2 ] /pdf:bm21 [130 0 R /FitH 590.2 ] /pdf:bm22 [134 0 R /FitH 775 ] /pdf:bm23 [136 0 R /FitH 350.2 ] /pdf:bm24 [138 0 R /FitH 518.2 ] /pdf:bm25 [140 0 R /FitH 230.2 ] /pdf:bm26 [148 0 R /FitH 590.2 ] /pdf:bm27 [150 0 R /FitH 331 ] /pdf:bm28 [152 0 R /FitH 266.2 ] /pdf:bm29 [156 0 R /FitH 775 ] /pdf:bm3 [3 0 R /FitH 746.2 ] /pdf:bm30 [156 0 R /FitH 571 ] /pdf:bm31 [160 0 R /FitH 485.4 ] /pdf:bm32 [160 0 R /FitH 444.6 ] /pdf:bm33 [160 0 R /FitH 367.8 ] /pdf:bm34 [160 0 R /FitH 327 ] /pdf:bm4 [3 0 R /FitH 705.4 ] /pdf:bm5 [16 0 R /FitH 746.2 ] /pdf:bm6 [16 0 R /FitH 513.4 ] /pdf:bm7 [16 0 R /FitH 316.6 ] /pdf:bm8 [16 0 R /FitH 304.6 ] /pdf:bm9 [18 0 R /FitH 734.2 ] >> endobj 6 0 obj << /BaseFont /Times-Italic /Encoding 7 0 R /FirstChar 0 /FontDescriptor 8 0 R /LastChar 255 /Subtype /Type1 /ToUnicode 9 0 R /Type /Font /Widths [422 541 500 556 389 389 556 980 214 500 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 250 333 420 500 500 833 778 333 333 333 500 675 250 333 250 278 500 500 500 500 500 500 500 500 500 500 333 333 675 675 675 500 920 611 611 667 722 611 611 722 722 333 444 667 556 833 667 722 611 722 611 500 556 722 611 833 611 556 556 389 278 389 333 500 333 500 500 444 500 444 278 500 500 278 278 444 278 722 500 500 500 500 389 389 278 500 444 667 444 444 389 400 275 400 333 0 333 500 500 350 500 167 1000 500 500 500 889 0 500 500 0 0 278 0 333 333 333 333 333 333 333 556 556 667 278 556 944 556 0 389 500 500 500 500 275 500 333 760 276 333 675 675 760 333 400 675 300 300 333 514 523 250 333 300 310 333 750 750 750 500 611 611 611 611 611 611 889 667 611 611 611 611 333 333 333 333 722 667 722 722 722 722 722 675 722 722 722 722 722 556 611 500 500 500 500 500 500 500 667 444 444 444 444 444 278 278 278 278 500 500 500 500 500 500 500 675 500 500 500 500 500 444 500 444 889 ] >> endobj 7 0 obj << /Differences [0 /asciicircum /asciitilde /Scaron /Zcaron /scaron /zcaron /Ydieresis /trademark /quotesingle /Euro /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /space /exclam /quotedbl /numbersign /dollar /percent /ampersand /quoteright /parenleft /parenright /asterisk /plus /comma /hyphen /period /slash /zero /one /two /three /four /five /six /seven /eight /nine /colon /semicolon /less /equal /greater /question /at /A /B /C /D /E /F /G /H /I /J /K /L /M /N /O /P /Q /R /S /T /U /V /W /X /Y /Z /bracketleft /backslash /bracketright /circumflex /underscore /quoteleft /a /b /c /d /e /f /g /h /i /j /k /l /m /n /o /p /q /r /s /t /u /v /w /x /y /z /braceleft /bar /braceright /tilde /.notdef /quotesinglbase /guillemotleft /guillemotright /bullet /florin /fraction /perthousand /dagger /daggerdbl /endash /emdash /.notdef /fi /fl /.notdef /.notdef /dotlessi /.notdef /grave /hungarumlaut /dotaccent /breve /caron /ring /ogonek /quotedblleft /quotedblright /oe /lslash /quotedblbase /OE /Lslash /.notdef /exclamdown /cent /sterling /currency /yen /brokenbar /section /dieresis /copyright /ordfeminine /guilsinglleft /logicalnot /minus /registered /macron /degree /plusminus /twosuperior /threesuperior /acute /mu /paragraph /periodcentered /cedilla /onesuperior /ordmasculine /guilsinglright /onequarter /onehalf /threequarters /questiondown /Agrave /Aacute /Acircumflex /Atilde /Adieresis /Aring /AE /Ccedilla /Egrave /Eacute /Ecircumflex /Edieresis /Igrave /Iacute /Icircumflex /Idieresis /Eth /Ntilde /Ograve /Oacute /Ocircumflex /Otilde /Odieresis /multiply /Oslash /Ugrave /Uacute /Ucircumflex /Udieresis /Yacute /Thorn /germandbls /agrave /aacute /acircumflex /atilde /adieresis /aring /ae /ccedilla /egrave /eacute /ecircumflex /edieresis /igrave /iacute /icircumflex /idieresis /eth /ntilde /ograve /oacute /ocircumflex /otilde /odieresis /divide /oslash /ugrave /uacute /ucircumflex /udieresis /yacute /thorn /ydieresis ] /Type /Encoding >> endobj 8 0 obj << /Ascent 783 /CapHeight 668 /CharSet (/asciicircum/asciitilde/Scaron/Zcaron/scaron/zcaron/Ydieresis/trademark/quotesingle/Euro/space/exclam/quotedbl/numbersign/dollar/percent/ampersand/quoteright/parenleft/parenright/asterisk/plus/comma/hyphen/period/slash/zero/one/two/three/four/five/six/seven/eight/nine/colon/semicolon/less/equal/greater/question/at/A/B/C/D/E/F/G/H/I/J/K/L/M/N/O/P/Q/R/S/T/U/V/W/X/Y/Z/bracketleft/backslash/bracketright/circumflex/underscore/quoteleft/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z/braceleft/bar/braceright/tilde/quotesinglbase/guillemotleft/guillemotright/bullet/florin/fraction/perthousand/dagger/daggerdbl/endash/emdash/fi/fl/dotlessi/grave/hungarumlaut/dotaccent/breve/caron/ring/ogonek/quotedblleft/quotedblright/oe/lslash/quotedblbase/OE/Lslash/exclamdown/cent/sterling/currency/yen/brokenbar/section/dieresis/copyright/ordfeminine/guilsinglleft/logicalnot/minus/registered/macron/degree/plusminus/twosuperior/threesuperior/acute/mu/paragraph/periodcentered/cedilla/onesuperior/ordmasculine/guilsinglright/onequarter/onehalf/threequarters/questiondown/Agrave/Aacute/Acircumflex/Atilde/Adieresis/Aring/AE/Ccedilla/Egrave/Eacute/Ecircumflex/Edieresis/Igrave/Iacute/Icircumflex/Idieresis/Eth/Ntilde/Ograve/Oacute/Ocircumflex/Otilde/Odieresis/multiply/Oslash/Ugrave/Uacute/Ucircumflex/Udieresis/Yacute/Thorn/germandbls/agrave/aacute/acircumflex/atilde/adieresis/aring/ae/ccedilla/egrave/eacute/ecircumflex/edieresis/igrave/iacute/icircumflex/idieresis/eth/ntilde/ograve/oacute/ocircumflex/otilde/odieresis/divide/oslash/ugrave/uacute/ucircumflex/udieresis/yacute/thorn/ydieresis/ellipsis) /Descent -217 /Flags 96 /FontBBox [0 -217 1000 883 ] /FontName /Times-Italic /ItalicAngle -7 /StemV 0 /Type /FontDescriptor >> endobj 9 0 obj << /Filter /FlateDecode /Length 252 >> stream x]PKk0 W029-Cc9Ov*ɒx>&ѫtQ!8XNh-*e`2%[gdV?+endstream endobj 10 0 obj << /BaseFont /Times-Roman /Encoding 11 0 R /FirstChar 0 /FontDescriptor 12 0 R /LastChar 255 /Subtype /Type1 /ToUnicode 9 0 R /Type /Font /Widths [469 541 556 611 389 444 722 980 180 500 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 250 333 408 500 500 833 778 333 333 333 500 564 250 333 250 278 500 500 500 500 500 500 500 500 500 500 278 278 564 564 564 444 921 722 667 667 722 611 556 722 722 333 389 722 611 889 722 722 556 722 667 556 611 722 722 944 722 722 611 333 278 333 333 500 333 444 500 444 500 444 333 500 500 278 278 500 278 778 500 500 500 500 333 389 278 500 500 722 500 500 444 480 200 480 333 0 333 500 500 350 500 167 1000 500 500 500 1000 0 556 556 0 0 278 0 333 333 333 333 333 333 333 444 444 722 278 444 889 611 0 333 500 500 500 500 200 500 333 760 276 333 564 564 760 333 400 564 300 300 333 510 453 250 333 300 310 333 750 750 750 444 722 722 722 722 722 722 889 667 611 611 611 611 333 333 333 333 722 722 722 722 722 722 722 564 722 722 722 722 722 722 556 500 444 444 444 444 444 444 667 444 444 444 444 444 278 278 278 278 500 500 500 500 500 500 500 564 500 500 500 500 500 500 500 500 1000 ] >> endobj 11 0 obj << /Differences [0 /asciicircum /asciitilde /Scaron /Zcaron /scaron /zcaron /Ydieresis /trademark /quotesingle /Euro /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /space /exclam /quotedbl /numbersign /dollar /percent /ampersand /quoteright /parenleft /parenright /asterisk /plus /comma /hyphen /period /slash /zero /one /two /three /four /five /six /seven /eight /nine /colon /semicolon /less /equal /greater /question /at /A /B /C /D /E /F /G /H /I /J /K /L /M /N /O /P /Q /R /S /T /U /V /W /X /Y /Z /bracketleft /backslash /bracketright /circumflex /underscore /quoteleft /a /b /c /d /e /f /g /h /i /j /k /l /m /n /o /p /q /r /s /t /u /v /w /x /y /z /braceleft /bar /braceright /tilde /.notdef /quotesinglbase /guillemotleft /guillemotright /bullet /florin /fraction /perthousand /dagger /daggerdbl /endash /emdash /.notdef /fi /fl /.notdef /.notdef /dotlessi /.notdef /grave /hungarumlaut /dotaccent /breve /caron /ring /ogonek /quotedblleft /quotedblright /oe /lslash /quotedblbase /OE /Lslash /.notdef /exclamdown /cent /sterling /currency /yen /brokenbar /section /dieresis /copyright /ordfeminine /guilsinglleft /logicalnot /minus /registered /macron /degree /plusminus /twosuperior /threesuperior /acute /mu /paragraph /periodcentered /cedilla /onesuperior /ordmasculine /guilsinglright /onequarter /onehalf /threequarters /questiondown /Agrave /Aacute /Acircumflex /Atilde /Adieresis /Aring /AE /Ccedilla /Egrave /Eacute /Ecircumflex /Edieresis /Igrave /Iacute /Icircumflex /Idieresis /Eth /Ntilde /Ograve /Oacute /Ocircumflex /Otilde /Odieresis /multiply /Oslash /Ugrave /Uacute /Ucircumflex /Udieresis /Yacute /Thorn /germandbls /agrave /aacute /acircumflex /atilde /adieresis /aring /ae /ccedilla /egrave /eacute /ecircumflex /edieresis /igrave /iacute /icircumflex /idieresis /eth /ntilde /ograve /oacute /ocircumflex /otilde /odieresis /divide /oslash /ugrave /uacute /ucircumflex /udieresis /yacute /thorn /ydieresis ] /Type /Encoding >> endobj 12 0 obj << /Ascent 782 /CapHeight 676 /CharSet (/asciicircum/asciitilde/Scaron/Zcaron/scaron/zcaron/Ydieresis/trademark/quotesingle/Euro/space/exclam/quotedbl/numbersign/dollar/percent/ampersand/quoteright/parenleft/parenright/asterisk/plus/comma/hyphen/period/slash/zero/one/two/three/four/five/six/seven/eight/nine/colon/semicolon/less/equal/greater/question/at/A/B/C/D/E/F/G/H/I/J/K/L/M/N/O/P/Q/R/S/T/U/V/W/X/Y/Z/bracketleft/backslash/bracketright/circumflex/underscore/quoteleft/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z/braceleft/bar/braceright/tilde/quotesinglbase/guillemotleft/guillemotright/bullet/florin/fraction/perthousand/dagger/daggerdbl/endash/emdash/fi/fl/dotlessi/grave/hungarumlaut/dotaccent/breve/caron/ring/ogonek/quotedblleft/quotedblright/oe/lslash/quotedblbase/OE/Lslash/exclamdown/cent/sterling/currency/yen/brokenbar/section/dieresis/copyright/ordfeminine/guilsinglleft/logicalnot/minus/registered/macron/degree/plusminus/twosuperior/threesuperior/acute/mu/paragraph/periodcentered/cedilla/onesuperior/ordmasculine/guilsinglright/onequarter/onehalf/threequarters/questiondown/Agrave/Aacute/Acircumflex/Atilde/Adieresis/Aring/AE/Ccedilla/Egrave/Eacute/Ecircumflex/Edieresis/Igrave/Iacute/Icircumflex/Idieresis/Eth/Ntilde/Ograve/Oacute/Ocircumflex/Otilde/Odieresis/multiply/Oslash/Ugrave/Uacute/Ucircumflex/Udieresis/Yacute/Thorn/germandbls/agrave/aacute/acircumflex/atilde/adieresis/aring/ae/ccedilla/egrave/eacute/ecircumflex/edieresis/igrave/iacute/icircumflex/idieresis/eth/ntilde/ograve/oacute/ocircumflex/otilde/odieresis/divide/oslash/ugrave/uacute/ucircumflex/udieresis/yacute/thorn/ydieresis/ellipsis) /Descent -218 /Flags 32 /FontBBox [0 -218 1000 898 ] /FontName /Times-Roman /ItalicAngle 0 /StemV 0 /Type /FontDescriptor >> endobj 13 0 obj << /BaseFont /Times-Bold /Encoding 14 0 R /FirstChar 0 /FontDescriptor 15 0 R /LastChar 255 /Subtype /Type1 /ToUnicode 9 0 R /Type /Font /Widths [581 520 556 667 389 444 722 1000 278 500 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 250 333 555 500 500 1000 833 333 333 333 500 570 250 333 250 278 500 500 500 500 500 500 500 500 500 500 333 333 570 570 570 500 930 722 667 722 722 667 611 778 778 389 500 778 667 944 722 778 611 778 722 556 667 722 722 1000 722 722 667 333 278 333 333 500 333 500 556 444 556 444 333 500 556 278 333 556 278 833 556 500 556 556 444 389 333 556 500 722 500 500 444 394 220 394 333 0 333 500 500 350 500 167 1000 500 500 500 1000 0 556 556 0 0 278 0 333 333 333 333 333 333 333 500 500 722 278 500 1000 667 0 333 500 500 500 500 220 500 333 747 300 333 570 570 747 333 400 570 300 300 333 601 540 250 333 300 330 333 750 750 750 500 722 722 722 722 722 722 1000 722 667 667 667 667 389 389 389 389 722 722 778 778 778 778 778 570 778 722 722 722 722 722 611 556 500 500 500 500 500 500 722 444 444 444 444 444 278 278 278 278 500 556 500 500 500 500 500 570 500 556 556 556 556 500 556 500 1000 ] >> endobj 14 0 obj << /Differences [0 /asciicircum /asciitilde /Scaron /Zcaron /scaron /zcaron /Ydieresis /trademark /quotesingle /Euro /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /space /exclam /quotedbl /numbersign /dollar /percent /ampersand /quoteright /parenleft /parenright /asterisk /plus /comma /hyphen /period /slash /zero /one /two /three /four /five /six /seven /eight /nine /colon /semicolon /less /equal /greater /question /at /A /B /C /D /E /F /G /H /I /J /K /L /M /N /O /P /Q /R /S /T /U /V /W /X /Y /Z /bracketleft /backslash /bracketright /circumflex /underscore /quoteleft /a /b /c /d /e /f /g /h /i /j /k /l /m /n /o /p /q /r /s /t /u /v /w /x /y /z /braceleft /bar /braceright /tilde /.notdef /quotesinglbase /guillemotleft /guillemotright /bullet /florin /fraction /perthousand /dagger /daggerdbl /endash /emdash /.notdef /fi /fl /.notdef /.notdef /dotlessi /.notdef /grave /hungarumlaut /dotaccent /breve /caron /ring /ogonek /quotedblleft /quotedblright /oe /lslash /quotedblbase /OE /Lslash /.notdef /exclamdown /cent /sterling /currency /yen /brokenbar /section /dieresis /copyright /ordfeminine /guilsinglleft /logicalnot /minus /registered /macron /degree /plusminus /twosuperior /threesuperior /acute /mu /paragraph /periodcentered /cedilla /onesuperior /ordmasculine /guilsinglright /onequarter /onehalf /threequarters /questiondown /Agrave /Aacute /Acircumflex /Atilde /Adieresis /Aring /AE /Ccedilla /Egrave /Eacute /Ecircumflex /Edieresis /Igrave /Iacute /Icircumflex /Idieresis /Eth /Ntilde /Ograve /Oacute /Ocircumflex /Otilde /Odieresis /multiply /Oslash /Ugrave /Uacute /Ucircumflex /Udieresis /Yacute /Thorn /germandbls /agrave /aacute /acircumflex /atilde /adieresis /aring /ae /ccedilla /egrave /eacute /ecircumflex /edieresis /igrave /iacute /icircumflex /idieresis /eth /ntilde /ograve /oacute /ocircumflex /otilde /odieresis /divide /oslash /ugrave /uacute /ucircumflex /udieresis /yacute /thorn /ydieresis ] /Type /Encoding >> endobj 15 0 obj << /Ascent 782 /CapHeight 692 /CharSet (/asciicircum/asciitilde/Scaron/Zcaron/scaron/zcaron/Ydieresis/trademark/quotesingle/Euro/space/exclam/quotedbl/numbersign/dollar/percent/ampersand/quoteright/parenleft/parenright/asterisk/plus/comma/hyphen/period/slash/zero/one/two/three/four/five/six/seven/eight/nine/colon/semicolon/less/equal/greater/question/at/A/B/C/D/E/F/G/H/I/J/K/L/M/N/O/P/Q/R/S/T/U/V/W/X/Y/Z/bracketleft/backslash/bracketright/circumflex/underscore/quoteleft/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z/braceleft/bar/braceright/tilde/quotesinglbase/guillemotleft/guillemotright/bullet/florin/fraction/perthousand/dagger/daggerdbl/endash/emdash/fi/fl/dotlessi/grave/hungarumlaut/dotaccent/breve/caron/ring/ogonek/quotedblleft/quotedblright/oe/lslash/quotedblbase/OE/Lslash/exclamdown/cent/sterling/currency/yen/brokenbar/section/dieresis/copyright/ordfeminine/guilsinglleft/logicalnot/minus/registered/macron/degree/plusminus/twosuperior/threesuperior/acute/mu/paragraph/periodcentered/cedilla/onesuperior/ordmasculine/guilsinglright/onequarter/onehalf/threequarters/questiondown/Agrave/Aacute/Acircumflex/Atilde/Adieresis/Aring/AE/Ccedilla/Egrave/Eacute/Ecircumflex/Edieresis/Igrave/Iacute/Icircumflex/Idieresis/Eth/Ntilde/Ograve/Oacute/Ocircumflex/Otilde/Odieresis/multiply/Oslash/Ugrave/Uacute/Ucircumflex/Udieresis/Yacute/Thorn/germandbls/agrave/aacute/acircumflex/atilde/adieresis/aring/ae/ccedilla/egrave/eacute/ecircumflex/edieresis/igrave/iacute/icircumflex/idieresis/eth/ntilde/ograve/oacute/ocircumflex/otilde/odieresis/divide/oslash/ugrave/uacute/ucircumflex/udieresis/yacute/thorn/ydieresis/ellipsis) /Descent -218 /Flags 32 /FontBBox [0 -218 1000 935 ] /FontName /Times-Bold /ItalicAngle 0 /StemV 0 /Type /FontDescriptor >> endobj 162 0 obj << /Count 34 /First 163 0 R /Last 163 0 R >> endobj 163 0 obj << /Count 33 /Dest /pdf:bm1 /First 164 0 R /Last 196 0 R /Parent 162 0 R /Title (CLIFM\(1\)) >> endobj 164 0 obj << /Dest /pdf:bm2 /Next 165 0 R /Parent 163 0 R /Title (NAME) >> endobj 165 0 obj << /Dest /pdf:bm3 /Next 166 0 R /Parent 163 0 R /Prev 164 0 R /Title (SYNOPSIS) >> endobj 166 0 obj << /Dest /pdf:bm4 /Next 167 0 R /Parent 163 0 R /Prev 165 0 R /Title (INDEX) >> endobj 167 0 obj << /Dest /pdf:bm5 /Next 168 0 R /Parent 163 0 R /Prev 166 0 R /Title (1. GETTING HELP) >> endobj 168 0 obj << /Dest /pdf:bm6 /Next 169 0 R /Parent 163 0 R /Prev 167 0 R /Title (2. DESCRIPTION) >> endobj 169 0 obj << /Dest /pdf:bm7 /Next 170 0 R /Parent 163 0 R /Prev 168 0 R /Title (3. PARAMETERS) >> endobj 170 0 obj << /Dest /pdf:bm8 /Next 171 0 R /Parent 163 0 R /Prev 169 0 R /Title (POSITIONAL PARAMETERS) >> endobj 171 0 obj << /Dest /pdf:bm9 /Next 172 0 R /Parent 163 0 R /Prev 170 0 R /Title (OPTIONS) >> endobj 172 0 obj << /Dest /pdf:bm10 /Next 173 0 R /Parent 163 0 R /Prev 171 0 R /Title (4. COMMANDS) >> endobj 173 0 obj << /Dest /pdf:bm11 /Next 174 0 R /Parent 163 0 R /Prev 172 0 R /Title (5. FILE FILTERS) >> endobj 174 0 obj << /Dest /pdf:bm12 /Next 175 0 R /Parent 163 0 R /Prev 173 0 R /Title (6. KEYBOARD SHORTCUTS) >> endobj 175 0 obj << /Dest /pdf:bm13 /Next 176 0 R /Parent 163 0 R /Prev 174 0 R /Title (7. THEMING) >> endobj 176 0 obj << /Dest /pdf:bm14 /Next 177 0 R /Parent 163 0 R /Prev 175 0 R /Title (8. BUILTIN EXPANSIONS) >> endobj 177 0 obj << /Dest /pdf:bm15 /Next 178 0 R /Parent 163 0 R /Prev 176 0 R /Title (10. FILE OPENER) >> endobj 178 0 obj << /Dest /pdf:bm16 /Next 179 0 R /Parent 163 0 R /Prev 177 0 R /Title (11. SHOTGUN) >> endobj 179 0 obj << /Dest /pdf:bm17 /Next 180 0 R /Parent 163 0 R /Prev 178 0 R /Title (12. AUTOSUGGESTIONS) >> endobj 180 0 obj << /Dest /pdf:bm18 /Next 181 0 R /Parent 163 0 R /Prev 179 0 R /Title (13. SHELL FUNCTIONS) >> endobj 181 0 obj << /Dest /pdf:bm19 /Next 182 0 R /Parent 163 0 R /Prev 180 0 R /Title (14. PLUGINS) >> endobj 182 0 obj << /Dest /pdf:bm20 /Next 183 0 R /Parent 163 0 R /Prev 181 0 R /Title (15. AUTOCOMMANDS) >> endobj 183 0 obj << /Dest /pdf:bm21 /Next 184 0 R /Parent 163 0 R /Prev 182 0 R /Title (16. FILE TAGS) >> endobj 184 0 obj << /Dest /pdf:bm22 /Next 185 0 R /Parent 163 0 R /Prev 183 0 R /Title (17. VIRTUAL DIRECTORIES) >> endobj 185 0 obj << /Dest /pdf:bm23 /Next 186 0 R /Parent 163 0 R /Prev 184 0 R /Title (18. NOTE ON SPEED) >> endobj 186 0 obj << /Dest /pdf:bm24 /Next 187 0 R /Parent 163 0 R /Prev 185 0 R /Title (19. KANGAROO FRECENCY ALGORITHM) >> endobj 187 0 obj << /Dest /pdf:bm25 /Next 188 0 R /Parent 163 0 R /Prev 186 0 R /Title (20. ENVIRONMENT) >> endobj 188 0 obj << /Dest /pdf:bm26 /Next 189 0 R /Parent 163 0 R /Prev 187 0 R /Title (21. SECURITY) >> endobj 189 0 obj << /Dest /pdf:bm27 /Next 190 0 R /Parent 163 0 R /Prev 188 0 R /Title (22. MISCELLANEOUS NOTES) >> endobj 190 0 obj << /Dest /pdf:bm28 /Next 191 0 R /Parent 163 0 R /Prev 189 0 R /Title (23. FILES) >> endobj 191 0 obj << /Dest /pdf:bm29 /Next 192 0 R /Parent 163 0 R /Prev 190 0 R /Title (HISTORY FILE) >> endobj 192 0 obj << /Dest /pdf:bm30 /Next 193 0 R /Parent 163 0 R /Prev 191 0 R /Title (24. EXAMPLES) >> endobj 193 0 obj << /Dest /pdf:bm31 /Next 194 0 R /Parent 163 0 R /Prev 192 0 R /Title (EXIT STATUS) >> endobj 194 0 obj << /Dest /pdf:bm32 /Next 195 0 R /Parent 163 0 R /Prev 193 0 R /Title (LICENSE) >> endobj 195 0 obj << /Dest /pdf:bm33 /Next 196 0 R /Parent 163 0 R /Prev 194 0 R /Title (BUG AND FEATURE REQUESTS) >> endobj 196 0 obj << /Dest /pdf:bm34 /Parent 163 0 R /Prev 195 0 R /Title (AUTHOR) >> endobj 2 0 obj << /Count 74 /Kids [3 0 R 16 0 R 18 0 R 20 0 R 22 0 R 24 0 R 26 0 R 28 0 R 30 0 R 32 0 R 34 0 R 36 0 R 38 0 R 40 0 R 42 0 R 44 0 R 46 0 R 48 0 R 50 0 R 52 0 R 54 0 R 56 0 R 58 0 R 60 0 R 62 0 R 64 0 R 66 0 R 68 0 R 70 0 R 72 0 R 74 0 R 76 0 R 78 0 R 80 0 R 82 0 R 84 0 R 86 0 R 88 0 R 90 0 R 92 0 R 94 0 R 96 0 R 98 0 R 100 0 R 102 0 R 104 0 R 106 0 R 108 0 R 110 0 R 112 0 R 114 0 R 116 0 R 118 0 R 120 0 R 122 0 R 124 0 R 126 0 R 128 0 R 130 0 R 132 0 R 134 0 R 136 0 R 138 0 R 140 0 R 142 0 R 144 0 R 146 0 R 148 0 R 150 0 R 152 0 R 154 0 R 156 0 R 158 0 R 160 0 R ] /MediaBox [0 0 595 842 ] /Resources << /Font << /F16 13 0 R /F18 6 0 R /F5 10 0 R >> /ProcSet [/PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Type /Pages >> endobj xref 0 198 0000000000 65535 f 0000215375 00000 n 0000235958 00000 n 0000000015 00000 n 0000000127 00000 n 0000215622 00000 n 0000216723 00000 n 0000217865 00000 n 0000219985 00000 n 0000221763 00000 n 0000222086 00000 n 0000223232 00000 n 0000225353 00000 n 0000227130 00000 n 0000228280 00000 n 0000230401 00000 n 0000001325 00000 n 0000001439 00000 n 0000004942 00000 n 0000005056 00000 n 0000007193 00000 n 0000007307 00000 n 0000010389 00000 n 0000010503 00000 n 0000013204 00000 n 0000013318 00000 n 0000015584 00000 n 0000015698 00000 n 0000017884 00000 n 0000017998 00000 n 0000020971 00000 n 0000021085 00000 n 0000024258 00000 n 0000024372 00000 n 0000027591 00000 n 0000027705 00000 n 0000031025 00000 n 0000031139 00000 n 0000034451 00000 n 0000034565 00000 n 0000036944 00000 n 0000037058 00000 n 0000040112 00000 n 0000040226 00000 n 0000043011 00000 n 0000043125 00000 n 0000046697 00000 n 0000046811 00000 n 0000049906 00000 n 0000050020 00000 n 0000053187 00000 n 0000053301 00000 n 0000056133 00000 n 0000056247 00000 n 0000060153 00000 n 0000060267 00000 n 0000063523 00000 n 0000063637 00000 n 0000067034 00000 n 0000067148 00000 n 0000070174 00000 n 0000070288 00000 n 0000072353 00000 n 0000072467 00000 n 0000075050 00000 n 0000075164 00000 n 0000078307 00000 n 0000078421 00000 n 0000081139 00000 n 0000081253 00000 n 0000084737 00000 n 0000084851 00000 n 0000088386 00000 n 0000088500 00000 n 0000091905 00000 n 0000092019 00000 n 0000095103 00000 n 0000095217 00000 n 0000097554 00000 n 0000097668 00000 n 0000099698 00000 n 0000099812 00000 n 0000101999 00000 n 0000102113 00000 n 0000104545 00000 n 0000104659 00000 n 0000107583 00000 n 0000107697 00000 n 0000110779 00000 n 0000110893 00000 n 0000112979 00000 n 0000113093 00000 n 0000114881 00000 n 0000114995 00000 n 0000117228 00000 n 0000117342 00000 n 0000119416 00000 n 0000119530 00000 n 0000122200 00000 n 0000122314 00000 n 0000124984 00000 n 0000125100 00000 n 0000127662 00000 n 0000127778 00000 n 0000131077 00000 n 0000131193 00000 n 0000134650 00000 n 0000134766 00000 n 0000137979 00000 n 0000138095 00000 n 0000140266 00000 n 0000140382 00000 n 0000142898 00000 n 0000143014 00000 n 0000144765 00000 n 0000144881 00000 n 0000147445 00000 n 0000147561 00000 n 0000150180 00000 n 0000150296 00000 n 0000153278 00000 n 0000153394 00000 n 0000155902 00000 n 0000156018 00000 n 0000159110 00000 n 0000159226 00000 n 0000162474 00000 n 0000162590 00000 n 0000165391 00000 n 0000165507 00000 n 0000168336 00000 n 0000168452 00000 n 0000171109 00000 n 0000171225 00000 n 0000174217 00000 n 0000174333 00000 n 0000177226 00000 n 0000177342 00000 n 0000180179 00000 n 0000180295 00000 n 0000183493 00000 n 0000183609 00000 n 0000187238 00000 n 0000187354 00000 n 0000189718 00000 n 0000189834 00000 n 0000191918 00000 n 0000192034 00000 n 0000193614 00000 n 0000193730 00000 n 0000196970 00000 n 0000197086 00000 n 0000200766 00000 n 0000200882 00000 n 0000203491 00000 n 0000203607 00000 n 0000207017 00000 n 0000207133 00000 n 0000209933 00000 n 0000210049 00000 n 0000213223 00000 n 0000213339 00000 n 0000232177 00000 n 0000232241 00000 n 0000232357 00000 n 0000232441 00000 n 0000232544 00000 n 0000232644 00000 n 0000232754 00000 n 0000232863 00000 n 0000232971 00000 n 0000233087 00000 n 0000233189 00000 n 0000233296 00000 n 0000233407 00000 n 0000233524 00000 n 0000233630 00000 n 0000233747 00000 n 0000233858 00000 n 0000233965 00000 n 0000234080 00000 n 0000234195 00000 n 0000234302 00000 n 0000234414 00000 n 0000234523 00000 n 0000234642 00000 n 0000234755 00000 n 0000234882 00000 n 0000234993 00000 n 0000235101 00000 n 0000235220 00000 n 0000235325 00000 n 0000235433 00000 n 0000235541 00000 n 0000235648 00000 n 0000235751 00000 n 0000235871 00000 n 0000215458 00000 n trailer << /Info 197 0 R /Root 1 0 R /Size 198 >> startxref 236781 %%EOF clifm-1.26.3/misc/clifm.desktop000066400000000000000000000004321506632037700163250ustar00rootroot00000000000000[Desktop Entry] Type=Application Name=Clifm Comment=The command line file manager GenericName=File Manager Icon=clifm Terminal=true Exec=clifm %F Categories=ConsoleOnly;System;FileTools;FileManager MimeType=inode/directory; Keywords=File;Directory;Manager;Browser;Explorer;Launcher clifm-1.26.3/misc/clifmrc000066400000000000000000000546021506632037700152120ustar00rootroot00000000000000 ########################################### # CLIFM # # The Command Line File Manager # ########################################### # This is Clifm's main configuration file. # Lines starting with either '#' or ';' are commented out (ignored). # Options starting with a ';' hold the default value, but are commented out. # To override a default value uncomment the corresponding option (remove # the leading ';') and set the option to any supported value. #=====================================# # 1. INTERFACE # #=====================================# # Show hidden files (i.e. files starting with a dot). # Supported values: true, false, first, last. # If 'true', hidden files are sorted according to the value of the Sort # option (see below). ;ShowHiddenFiles=false # Files listed in a '.hidden' file in the current directory will be hidden # when hidden files are not shown (i.e. when ShowHiddenFiles is set to false). # Both plain filenames and wildcards are supported for specifying hidden files. ;ReadDotHidden=false # Use a regular expression to filter files from the files list. # For example: "!.*~$" to exclude backup files (ending with ~), or "^\." to # list only hidden files. File type filters are also supported, such as # "=d" to list directories only, or "!=l" to exclude symbolic links. # Run 'help file-filters' for more information on how to use this feature. ;Filter="" # List directories first. ;ListDirsFirst=true # Display the number of files contained in each directory next to the # directory name. This feature may slow down performance when, for example, # listing files on a remote server. The files counter can be disabled here, # via the --no-files-counter option, or using the 'fc' command while in the # program itself. # Note: This option requires Classify (see below) to be set to true. ;FilesCounter=true # When using colors, append directory indicator to directories. If colors # are disabled (via the --no-color option), append file type indicator to # filenames instead: # '/' for directories # '@' for symbolic links # '=' for sockets # '|' for FIFO/pipes # '*' for for executable files # '+' for block special files # '-' for character special files # '?' for unknown file types # Bear in mind that when running in light mode the check for executable # files will not be performed, and thereby no indicator will be added to # executable files. # Note: Disabling this option also disables the files counter. ;Classify=true # Color symbolic links according to their target filename. An indicator # character (by default '@') is placed at the beginning of the name to mark # it as a symbolic link. # The color of this indicator can be customized in the color scheme file # (InterfaceColors field) via the 'lc' code. ;ColorLinksAsTarget=false # Control the use of the file list pager. Supported values are: # 0/false = Disable the pager. # 1/true = Run the pager whenever the list of files does not fit on the screen. # >1 = Run the pager whenever the number of files in the current directory is # greater than or equal to this value (e.g., 1000). ;Pager=false # Specify how to list files in the pager. Supported values: # auto = Use the current listing mode # long = List files in long view # short = List files in short view ;PagerView=auto # Choose how to list files: 0 = vertically (like ls), 1 = horizontally. ;ListingMode=0 # Determine the sort method for listed files. # Supported values include: none, name, version, extension, type, blocks, # size, links, atime, btime, ctime, mtime, inode, owner, and group. ;Sort=version # By default, files are sorted in ascending order (e.g.: from 'a' to 'z' if # using the "name" method). Set SortReverse to true to invert this ordering. # You can also use the --sort-reverse option or the 'st rev' command to achieve # the same effect. ;SortReverse=false # Sort filenames starting with PrioritySortChar first. # Multiple values are allowed (e.g. 'PrioritySortChar=._#') # Leave empty to unset this option (no priority character). # Supported values are ASCII characters from SPACE to TILDE. # Tip: A common value for this option is underscore (_). # Note: This option takes precedence over SkipNonAlnumPrefix (see below). ;PrioritySortChar= # Display extended file metadata next to filenames (long listing format). ;LongViewMode=false # Specify which properties to display for each filename in long view mode: # f = Files counter (for directories) # B = File allocated blocks # d = Inode number # l = Number of hard links # p|n = Permissions: either symbolic (p) or numeric/octal (n) # i|I = User/group IDs: either as number (i) or name (I) # G = If i|I is set, don't print groups # a|b|m|c = Last (a)ccess, (b)irth, (m)odification, or status (c)hange time # s|S = Size (either human readable (s) or bytes (S)) # x = Extended attributes/capabilities/ACLs (marked as '@') # (requires p|n) # # A single dash ("-") disables all fields. # # Note that, exception made of 'x' and 'G', fields will be displayed in the # order specified here. # # Example: display only permissions (numeric) and size (human readable): #PropFields="ns" # or, to display file permissions, modification time, and size (in bytes): #PropFields="pmS" ;PropFields="xfpIsm" # Set the number of spaces between fields in long view. Possible values: 1 or 2. ;PropFieldsGap=1 # Choose the style for printing timestamps in long view mode. # Supported values: default, relative, iso, long-iso, full-iso, +FORMAT # FORMAT is interpreted like in strftime(3). # Defaults to "+%b %e %H:%M" for recent files (< 6 months) and "+%b %e %Y" # for older files. # Examples: ;TimeStyle="full-iso" ;TimeStyle="relative" ;TimeStyle="+%F %T" # If files are sorted by time in the file list, this option specifies whether # to use the same timestamp in long view mode, regardless of the value set in # PropFields. ;TimeFollowsSort=true # Append an indicator ('a', 'b', 'c', or 'm') to the timestamp in long view # mode to indicate the type of timestamp: access, birth, status change, or # modification time, respectively. For relative times, uppercase characters # are used for better visibility. ;TimestampMark=false # Similar to TimeStyle, but specifically for the 'p/pp' command. # Supported values: default, iso, long-iso, full-iso, full-iso-nano, +FORMAT # Nano-second precision is available via the %N modifier. ;PTimeStyle="+%Y-%m-%d %H:%M:%S.%N %z" # Display recursive directory sizes (long view only). ;FullDirSize=false # Display apparent file sizes (logical size) instead of actual device # usage (physical size). ;ApparentSize=true # In light mode, extra file type checks are disabled to speed up the listing # process. This means that checks for readability, executability, SUID, SGID, # broken symlinks, etc., are not performed. The file extension check is also # ignored, disabling the color per-extension feature. ;LightMode=false # Clear the terminal screen before listing files. # Supported values: true, false, internal (restrict this behavior to # internal commands only: shell commands will not clear the screen). # Note: If set to 'internal', the current list of files will not be refreshed # even if an external command creates, removes, or renames a file in the # current directory. ;ClearScreen=true # Set the maximum filename length for listed files. If TruncateNames is enabled, # names longer than MaxFilenameLen will be truncated using a tilde (~). # Set it to -1 (or leave empty) to remove this limit. # If running in long view mode, this setting is overriden by MinNameTruncate # if MaxFilenameLen is smaller than MinNameTruncate. ;MaxFilenameLen=20 # Truncate filenames longer than MaxFilenameLen. ;TruncateNames=true # Minimum length at which a filename can be truncated in long view mode. # When running in long mode, this setting overrides MaxFilenameLen # if MaxFilenameLen is smaller than MinNameTruncate. ;MinNameTruncate=20 # A comma separated list of workspace names in the format NUM=NAME. # Example: "1=MAIN,2=EXTRA,3=GIT" or "1=α,2=β,3=γ" ;WorkspaceNames="" # If set to true, settings changed in the current workspace (only via # the command line or keyboard shortcuts) are kept private to that # workspace and made persistent (for the current session only), even # when switching workspaces. ;PrivateWorkspaceSettings=false # Show disk usage of the filesystem where the current directory resides, # in the format "FREE % (FREE/TOTAL) TYPE DEVICE". ;DiskUsage=false # Print a map of the current position in the directory history list, # showing previous, current, and next entries. ;DirhistMap=false # Print the list of selected files after the file list. Since this # list can become extensive, you can limit the number of printed # entries using the MaxPrintSelfiles option below. ;PrintSelfiles=false # Maximum number of selected files to be printed if PrinSelFiles is # enabled. Supported values: -1 = no limit, 0 = auto (never print more # than half terminal height), or any positive value. ;MaxPrintSelfiles=0 # Color schemes (or just themes) are stored in the colors directory # ($XDG_DATA_DIRS/clifm/colors, usually /usr/local/share/clifm/colors # or /usr/share/clifm/colors). You can place your custom themes in # $HOME/.config/clifm/colors. # # Use the 'cs' command or the '--color-scheme' command line option to set # a theme. # # Run 'cs edit' to modify the current theme. # # Each theme includes color definitions, just as definitions for the # prompt, the warning prompt, the dividing line, and the FZF window. # # Use TAB to list available themes: 'cs '. # # For additional themes, visit https://github.com/leo-arch/clifm-colors. # # Defaults to 'default-256', or 'default' (16 colors) if 256-color support # is not detected. ;ColorScheme= # Enable the use of icons in the file list. # By default, emojis (widely available today) are used as icons, but # Nerd-fonts and icons-in-terminal are supported as well, though Clifm # needs to be recompiled in order to enable support. Consult our Wiki # (https://github.com/leo-arch/clifm/wiki) for more information. ;Icons=false # Number of spaces between icons and filenames (supported values: 0, 1, or 2). ;IconsGap=1 #=====================================# # 2. COMMAND LINE # #=====================================# # Set the quoting style used to expand ELNs (regular files only). # Supported values: 'backslash' (default), 'single', or 'double' quotes. # This option is particularly useful for shells that do not support # backslashes as quoting mechanism, such as nushell or xonsh. ;QuotingStyle=backslash # Enable fuzzy matching for filename and path completions and suggestions. ;FuzzyMatching=false # Choose the fuzzy matching algorithm to use. Supported values: # 1 = faster, but not Unicode aware # 2 = slower, but Unicode aware (note that this algorithm will nonetheless # fall back to the first one whenever the query string does not contain # Unicode characters, minimizing thus the performance impact). ;FuzzyAlgorithm=2 # Set the tab completion mode. Supported values: standard, fzf, fnf, smenu. # Defaults to 'fzf', 'fnf', or 'smenu' (in this order), if the corresponding # binary is found in PATH. Othwerwise, the standard mode is used. ;TabCompletionMode= # Enable file previews for tab completion (fzf mode only). Supported values: # true, false, hidden (enabled, but hidden; toggle with Alt-p). ;FzfPreview=true # Do not preview files larger than PreviewMaxSize. # Supported size units: K, M, G, T (e.g. 100M). # Supported size range: 1K-2047G. # Set to -1 (or leave empty) to disable this feature (allow all file sizes). ;PreviewMaxSize= # Enable auto-suggestions for commands, file paths, and options as you type. ;AutoSuggestions=true # The following suggestion checks will be performed in the order # specified by SuggestionStrategy. Available checks include: # a = Alias names # c = Path completion # e = ELNs # f = Filenames in current directory # h = Command history # j = Jump database # Use a single dash (-) to skip all of these checks. ;SuggestionStrategy=ehfjac # Suggest filenames using the corresponding file type color (as defined in # the color scheme file). ;SuggestFiletypeColor=false # Provide a brief description for internal commands as part of the suggestions. ;SuggestCmdDesc=true # Enable syntax highlighting for improved readability of commands as you type. ;SyntaxHighlighting=true # Allow the execution of external shell commands within Clifm. ;ExternalCommands=true #=====================================# # 3. COMMANDS # #=====================================# # Automatically list files after changing the current directory. ;AutoLs=true # If enabled, a command name that is the name of a directory or a # file, is executed as if it were the argument to the 'cd' or the # 'open' commands respectively: 'DIR' is equivalent 'cd DIR' and # 'FILE' to 'open FILE'. ;Autocd=true ;AutoOpen=true # Execute autocommand files (.cfm.in and .cfm.out) found in the current # directory. For more information consult the manpage. ;ReadAutocmdFiles=false # Inform about autocommand options set for the current directory. # Supported values: # none = No message is displayed. # mini = Minimal message with no option details. # short = List of autocommand options without their values. # long = Like 'short', but includes the value of each option (multiple # matching autocommands are merged into a single line). # full = Like 'long', but multiple autocommands are printed on separate # lines. Also, a 'T' is appended to mark temporary autocommands # (i.e., set via the 'auto' command). # prompt = Display a small notification (a gray 'A') in the prompt. # The color code used for this notification is 'ac' (see the color # scheme file). # If Notifications is set to false for the current prompt (see the # prompts file), nothing is printed (you can use the '\y' prompt # code in the prompts file to manually set this notification). ;InformAutocmd=prompt # Run in read-only mode (internal commands able to modify the filesystem # are disabled). Consult the manpage for the list of affected commands. ;Readonly=false # Make the 'r' command move files to the trash instead of permanently # removing them. ;TrashAsRm=false # If set to true, do not ask for confirmation before moving files to the trash. ;TrashForce=false # If set to true, do not ask for confirmation before removing files with the # 'r' command. # Note: If set to false, you can still use the '-f' parameter to turn # confirmation off for a single command. E.g.: 'r -f FILE'. ;rmForce=false # Set the default command used for copying files. Supported values: # 0 = 'cp -Rp' # 1 = 'cp -Rp' (force: do not prompt before overwrite) # 2 = 'advcp -gRp' # 3 = 'advcp -gRp' (force) # 4 = 'wcp' # 5 = 'rsync -avP' # Note: Options 2-5 include a progress bar. ;cpCmd=0 # Set the default command used for moving files. Supported values: # 0 = 'mv' # 1 = 'mv' (force: do not prompt before overwrite) # 2 = 'advmv -g' # 3 = 'advmv -g' (force) # Note: Options 2 and 3 include a progress bar. ;mvCmd=0 # Define default responses for confirmation prompts using a comma-separated # line of fields. Each field consists of two values separated by a colon (':'). # # The left value specifies a confirmation prompt: # o = overwrite files (mostly 'c' and 'm' commands) # r = remove ('r' command) # t = trash ('t' command) # R = bulk rename ('br' command) # d = All confirmation prompts (excluding, if defined, the above ones) # D = All confirmation prompts (including the above ones, no matter their value) # # The right value holds the default answer for the corresponding prompt: # 'y', 'n', or 'u' (unset - no default answer, wait for explicit input). # # If a value, left or right, is unset (or set to any other value), no default # answer will be used ('y' or 'n' will be explicitly required, unless 'd' or 'D' # are set to any valid value, in which case this value is used instead). # # For example, to set 'n' as the default answer for the 'r' command, unset for # trash, and 'y' for everything else: "r:n,t:u,d:y". ;DefaultAnswer="o:n,r:n,t:y,R:n,d:y" # Specify how the 'l' command creates symbolic links. Supported values: # absolute = Make the target an absolute path # relative = Make the target relative to the link location (like 'ln -rs') # literal = Do not resolve the target at all (like 'ln -s') ;LinkCreationMode=literal # Choose the file opener for opening files with their default associated # application (e.g. Ranger's rifle or xdg-open). If not specified, 'lira', # Clifm's builtin opener, will be used. ;Opener= # Command used to launch a terminal emulator for opening a new Clifm instance # (with the 'x' command). ;TerminalCmd="xterm -e" # Set the file mode creation mask. Defaults to the value inherited from # the shell (though 077 is recommended). # This option is ignored in secure mode (umask is forcefully set to 077). ;Umask=077 # Choose the search strategy for the quick search function. Supported values: # 0 = glob-only # 1 = regex-only # 2 = glob-regex (default) ;SearchStrategy=2 # Minimum rank for directories in the jump database. Directories with a rank # below this value will be removed. If set to 0, directories will be retained # indefinitely. ;MinJumpRank=10 # Maximum total rank allowed in the jump database. When exceeded, all ranks # will be reduced dynamically to ensure the total falls below this limit. # Entries below MinJumpRank will be deleted. ;MaxJumpTotalRank=100000 # Automatically remove non-existing directories from the jump database at # startup. Note that this will also remove paths pointing to unmounted # removable devices and remote filesystems. ;PurgeJumpDB=false # Print the list of commands executed in the current directory (the list will # be cleared after changing the directory). ;PrintDirCmds=false #=====================================# # 4. LOGS AND HISTORY # #=====================================# # Display user alerts (errors, warnings, and notices) using desktop notifications. # Supported values: # kitty = Use the Kitty Notifications Protocol (requires the Kitty terminal or a # terminal supporting this protocol). # system = Use the system notifications daemon. # false = Print alerts before the prompt (no desktop notification is displayed). ;DesktopNotifications=false # Log errors and warnings. ;LogMsgs=false # Log commands entered in the command line. ;LogCmds=false # Keep only the last MaxLog lines in the log files. ;MaxLog=1000 # A regular expression to filter out specific command lines from being added to # the history list. Set this line to the empty string to disable history filters. ;HistIgnore="^[q,Q]$|^quit$|^exit$|^ .*|^#.*|^[0-9]+$|^\.+$" # Limit the size of the command history file to MaxHistory entries. ;MaxHistory=1000 # Same as HistIgnore, but for the directory history list. ;DirhistIgnore="" # Limit the size of the directory history file to MaxDirhist entries. ;MaxDirhist=100 #=====================================# # 5. MISC # #=====================================# # Enable case-sensitive listing of files in the current directory. ;CaseSensitiveList=false # Enable case-sensitive lookups for the directory jumper function (via # the 'j' command). ;CaseSensitiveDirJump=false # Enable case-sensitive filename completion. ;CaseSensitivePathComp=false # Enable case-sensitive search. ;CaseSensitiveSearch=false # When sorting files by 'version' or 'name', skip non-alphanumeric characters. # For example, '__file' will be sorted as 'file'. # This also affects hidden files: if set to false, '.hidden' will appear # before 'afile'; if set to true, it will appear after 'gfile' (unless # ShowHiddenFiles is set to 'first' or 'last'). ;SkipNonAlnumPrefix=true # Set a custom starting path. If not specified, it defaults to the current # working directory. If set, this option overrides RestoreLastPath. ;StartingPath= # Start Clifm in the last visited directory (and in the last used # workspace). This option is overriden by StartingPath (if set). ;RestoreLastPath=true # Set the readline editing mode: 0 for vi and 1 for emacs (default). ;RlEditMode=1 # Save the last visited directory to $XDG_CONFIG_HOME/clifm/.last, allowing # it to be accessed by the corresponding shell function upon program exit. # To enable this feature consult the manpage. ;CdOnQuit=false # Share the Selection Box among different profiles. ;ShareSelbox=false # Print a usage tip at startup. ;Tips=true # Just a kind welcome message at startup. ;WelcomeMessage=true # Set a custom welcome message. # Colors are available via escape codes. E.g.: "\e[34mWelcome!\e[0m". # An ending new line character will be appended automatically. ;WelcomeMessageStr="" # Print Clifm's logo screen at startup. ;SplashScreen=false #=====================================# # 6. ALIASES # #=====================================# # Bind '?' to the interactive help plugin. Use the 'actions' command to # display a list of available plugins. #alias ?='ih' # Bind 'b' to the directory history navigation plugin. #alias b='dh' # Replace the builtin deselect command (ds) with the fzfdesel plugin. #alias ds='**' # You can use this alias to quickly change to the current virtual directory. #alias vtd='cd $CLIFM_VIRTUAL_DIR' # Replace the builtin bulk rename function (br) with vidir(1). #br='vidir' #=====================================# # 7. PROMPT COMMANDS # #=====================================# # Specify commands to be executed before each prompt is displayed. For example: #promptcmd /usr/local/share/clifm/plugins/git_status.sh #promptcmd date | awk '{print $1", "$2,$3", "$4}' #=====================================# # 8. AUTOCOMMANDS # #=====================================# # Control Clifm's settings on a per-directory basis. For more information # consult the manpage. # Remote file systems are slow: let's speed this up by enabling the light # mode and disabling the files counter. #autocmd /media/remotes/** lm=1,fc=0 # Just a friendly reminder when entering the ~/important directory. #autocmd ~/important !printf "Keep your fingers outta here!\n" && read -n1 # Plenty of images and videos? Launch the files previewer plugin. #autocmd ~/Downloads !/usr/local/share/clifm/plugins/fzfnav.sh # Use the nord color scheme and disable hidden files in the ~/Documents # directory. #autocmd ~/Documents/** cs=nord,hf=0 # I want files in the third workspace to be listed in long view. #autocmd @ws3 lv=1 clifm-1.26.3/misc/cmake/000077500000000000000000000000001506632037700147215ustar00rootroot00000000000000clifm-1.26.3/misc/cmake/Makefile000066400000000000000000000055661506632037700163750ustar00rootroot00000000000000###################### # Makefile for clifm # ###################### BIN ?= clifm PREFIX ?= /usr/local DATADIR ?= $(PREFIX)/share MANDIR ?= $(PREFIX)/man LOCALEDIR ?= $(DATADIR)/locale DESKTOPPREFIX ?= $(DATADIR)/applications DESKTOPICONPREFIX ?= $(DATADIR)/icons/hicolor PROG_DATADIR ?= $(DATADIR)/$(BIN) SHELL ?= /bin/sh INSTALL ?= install RM ?= rm SRCDIR = ../clifm-build SRC = $(SRCDIR)/*.c HEADERS = $(SRCDIR)/*.h clean: $(RM) -rf -- $(SRCDIR) install: $(INSTALL) -m 0755 -d $(DESTDIR)$(PREFIX)/bin $(INSTALL) -m 0755 $(SRCDIR)/$(BIN) $(DESTDIR)$(PREFIX)/bin $(INSTALL) -m 0755 -d $(DESTDIR)$(PROG_DATADIR) $(INSTALL) -m 0755 -d $(DESTDIR)$(MANDIR)/man1 $(INSTALL) -m 0755 -d $(DESTDIR)$(DATADIR)/bash-completion/completions $(INSTALL) -m 0755 -d $(DESTDIR)$(DATADIR)/zsh/site-functions $(INSTALL) -m 0755 -d $(DESTDIR)$(DATADIR)/fish/vendor_completions.d $(INSTALL) -m 0755 -d $(DESTDIR)$(DESKTOPPREFIX) $(INSTALL) -m 0755 -d $(DESTDIR)$(DESKTOPICONPREFIX)/scalable/apps $(INSTALL) -m 0644 misc/manpage/$(BIN).1 $(DESTDIR)$(MANDIR)/man1 $(INSTALL) -m 0644 misc/completions.bash $(DESTDIR)$(DATADIR)/bash-completion/completions/$(BIN) $(INSTALL) -m 0644 misc/completions.zsh $(DESTDIR)$(DATADIR)/zsh/site-functions/_$(BIN) $(INSTALL) -m 0644 misc/completions.fish $(DESTDIR)$(DATADIR)/fish/vendor_completions.d/$(BIN).fish $(INSTALL) -m 0644 misc/$(BIN).desktop $(DESTDIR)$(DESKTOPPREFIX) $(INSTALL) -m 0644 misc/*.clifm $(DESTDIR)$(PROG_DATADIR) $(INSTALL) -m 0644 misc/clifmrc $(DESTDIR)$(PROG_DATADIR) $(INSTALL) -m 0644 images/logo/$(BIN).svg $(DESTDIR)$(DESKTOPICONPREFIX)/scalable/apps $(INSTALL) -m 0755 -d $(DESTDIR)$(PROG_DATADIR)/plugins $(INSTALL) -m 0755 -d $(DESTDIR)$(PROG_DATADIR)/functions $(INSTALL) -m 0755 -d $(DESTDIR)$(PROG_DATADIR)/colors $(INSTALL) -m 0755 -d $(DESTDIR)$(PROG_DATADIR)/tools $(INSTALL) -m 0755 misc/tools/imgprev/clifmrun $(DESTDIR)$(PROG_DATADIR)/plugins $(INSTALL) -m 0755 misc/tools/imgprev/clifmimg $(DESTDIR)$(PROG_DATADIR)/plugins $(INSTALL) -m 0755 plugins/* $(DESTDIR)$(PROG_DATADIR)/plugins $(INSTALL) -m 0755 misc/tools/*.py $(DESTDIR)$(PROG_DATADIR)/tools chmod 644 $(DESTDIR)$(PROG_DATADIR)/plugins/BFG.cfg chmod 644 $(DESTDIR)$(PROG_DATADIR)/plugins/plugins-helper $(INSTALL) -m 0644 misc/colors/*.clifm $(DESTDIR)$(PROG_DATADIR)/colors $(INSTALL) -m 0644 functions/* $(DESTDIR)$(PROG_DATADIR)/functions @printf "Successfully installed $(BIN)\n" uninstall: $(RM) -- $(DESTDIR)$(PREFIX)/bin/$(BIN) $(RM) -- $(DESTDIR)$(MANDIR)/man1/$(BIN).1* $(RM) -- $(DESTDIR)$(DATADIR)/bash-completion/completions/$(BIN) $(RM) -- $(DESTDIR)$(DATADIR)/zsh/site-functions/_$(BIN) $(RM) -- $(DESTDIR)$(DATADIR)/fish/vendor_completions.d/$(BIN).fish $(RM) -- $(DESTDIR)$(DESKTOPPREFIX)/$(BIN).desktop $(RM) -r -- $(DESTDIR)$(PROG_DATADIR) $(RM) -- $(DESTDIR)$(DESKTOPICONPREFIX)/scalable/apps/$(BIN).svg @printf "Successfully uninstalled $(BIN)\n" clifm-1.26.3/misc/codecov/000077500000000000000000000000001506632037700152635ustar00rootroot00000000000000clifm-1.26.3/misc/codecov/actions.c.gcov000066400000000000000000000416251506632037700200340ustar00rootroot00000000000000 -: 0:Source:actions.c -: 1:/* actions.c -- a few functions for the plugins systems */ -: 2: -: 3:/* -: 4: * This file is part of CliFM -: 5: * -: 6: * Copyright (C) 2016-2021, L. Abramovich -: 7: * All rights reserved. -: 8: -: 9: * CliFM is free software; you can redistribute it and/or modify -: 10: * it under the terms of the GNU General Public License as published by -: 11: * the Free Software Foundation; either version 2 of the License, or -: 12: * (at your option) any later version. -: 13: * -: 14: * CliFM is distributed in the hope that it will be useful, -: 15: * but WITHOUT ANY WARRANTY; without even the implied warranty of -: 16: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -: 17: * GNU General Public License for more details. -: 18: * -: 19: * You should have received a copy of the GNU General Public License -: 20: * along with this program; if not, write to the Free Software -: 21: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, -: 22: * MA 02110-1301, USA. -: 23:*/ -: 24: -: 25:#include "helpers.h" -: 26: -: 27:#include -: 28:#include -: 29:#include -: 30:#include -: 31:#include -: 32:#include -: 33:#include -: 34: -: 35:#include "aux.h" -: 36:#include "checks.h" -: 37:#include "exec.h" -: 38:#include "file_operations.h" -: 39:#include "init.h" -: 40:#include "mime.h" -: 41:#include "misc.h" -: 42: -: 43:/* The core of this function was taken from NNN's run_selected_plugin -: 44: * function and modified to fit our needs. Thanks NNN! */ -: 45:int function run_action called 2 returned 100% blocks executed 38% 2: 46:run_action(char *action, char **args) -: 47:{ 2: 48: if (!action) 2: 48-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 2 #####: 49: return EXIT_FAILURE; %%%%%: 49-block 0 unconditional 0 never executed -: 50: 2: 51: int exit_status = EXIT_SUCCESS; 2: 52: char *cmd = (char *)NULL; 2: 53: size_t len = 0, 2: 54: action_len = strlen(action); -: 55: -: 56: /* ##################################### -: 57: * # 1) CREATE CMD TO BE EXECUTED # -: 58: * ##################################### */ -: 59: -: 60: /* Remove terminating new line char */ 2: 61: if (action[action_len - 1] == '\n') 2: 61-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 2 #####: 62: action[action_len - 1] = '\0'; %%%%%: 62-block 0 unconditional 0 never executed -: 63: 2: 64: int dir_path = 0; 2: 65: if (strchr(action, '/')) { 2: 65-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 2 #####: 66: cmd = (char *)xnmalloc(action_len + 1, sizeof(char)); %%%%%: 66-block 0 call 0 never executed #####: 67: strcpy(cmd, action); #####: 68: dir_path = 1; unconditional 0 never executed -: 69: } else { /* If not a path, PLUGINS_DIR is assumed */ 2: 70: cmd = (char *)xnmalloc(action_len + strlen(plugins_dir) + 2, 2: 70-block 0 call 0 returned 2 -: 71: sizeof(char)); 2: 72: sprintf(cmd, "%s/%s", plugins_dir, action); unconditional 0 taken 2 -: 73: } -: 74: -: 75: /* Check if the action file exists and is executable */ 2: 76: if (access(cmd, X_OK) == -1) { 2: 76-block 0 call 0 returned 2 branch 1 taken 0 (fallthrough) branch 2 taken 2 -: 77: /* If not in local dir, check system data dir as well */ #####: 78: if (data_dir && !dir_path) { %%%%%: 78-block 0 branch 0 never executed branch 1 never executed %%%%%: 78-block 1 branch 2 never executed branch 3 never executed #####: 79: cmd = (char *)xrealloc(cmd, (action_len + strlen(data_dir) #####: 80: + strlen(PNL) + 11) * sizeof(char)); %%%%%: 80-block 0 call 0 never executed #####: 81: sprintf(cmd, "%s/%s/plugins/%s", data_dir, PNL, action); #####: 82: if (access(cmd, X_OK) == -1) { call 0 never executed branch 1 never executed branch 2 never executed #####: 83: fprintf(stderr, "actions: %s: %s\n", cmd, strerror(errno)); %%%%%: 83-block 0 call 0 never executed call 1 never executed #####: 84: free(cmd); #####: 85: return EXIT_FAILURE; unconditional 0 never executed -: 86: } -: 87: } else { #####: 88: fprintf(stderr, "actions: %s: %s\n", cmd, strerror(errno)); %%%%%: 88-block 0 call 0 never executed call 1 never executed #####: 89: free(cmd); #####: 90: return EXIT_FAILURE; unconditional 0 never executed -: 91: } -: 92: } -: 93: -: 94: /* Append arguments to command */ -: 95: size_t i; 2: 96: len = strlen(cmd); 2*: 97: for (i = 1; args[i]; i++) { 2: 97-block 0 unconditional 0 taken 2 2: 97-block 1 branch 1 taken 0 branch 2 taken 2 (fallthrough) #####: 98: len += (strlen(args[i]) + 2); #####: 99: cmd = (char *)xrealloc(cmd, len * sizeof(char)); %%%%%: 99-block 0 call 0 never executed #####: 100: strcat(cmd, " "); #####: 101: strcat(cmd, args[i]); unconditional 0 never executed -: 102: } -: 103: -: 104: /* ############################## -: 105: * # 2) CREATE A PIPE FILE # -: 106: * ############################## */ -: 107: 2: 108: char *rand_ext = gen_rand_str(6); 2: 108-block 0 call 0 returned 2 -: 109: 2: 110: if (!rand_ext) { branch 0 taken 0 (fallthrough) branch 1 taken 2 #####: 111: free(cmd); #####: 112: return EXIT_FAILURE; %%%%%: 112-block 0 unconditional 0 never executed -: 113: } -: 114: -: 115: char fifo_path[PATH_MAX]; 2: 116: sprintf(fifo_path, "%s/.pipe.%s", tmp_dir, rand_ext); 2: 117: free(rand_ext); -: 118: 2: 119: setenv("CLIFM_BUS", fifo_path, 1); 2: 119-block 0 call 0 returned 2 -: 120: 2: 121: if (mkfifo(fifo_path, 0600) != EXIT_SUCCESS) { call 0 returned 2 branch 1 taken 0 (fallthrough) branch 2 taken 2 #####: 122: free(cmd); #####: 123: printf("%s: %s\n", fifo_path, strerror(errno)); %%%%%: 123-block 0 call 0 never executed call 1 never executed #####: 124: return EXIT_FAILURE; unconditional 0 never executed -: 125: } -: 126: -: 127: /* ################################################ -: 128: * # 3) EXEC CMD & LET THE CHILD WRITE TO PIPE # -: 129: * ################################################ */ -: 130: -: 131: /* Set terminal title to plugin name */ 2: 132: if (xargs.cwd_in_title == 1) 2: 132-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 0 2: 133: set_term_title(action); 2: 133-block 0 call 0 returned 2 unconditional 1 taken 2 -: 134: 2: 135: pid_t pid = fork(); 2: 135-block 0 call 0 returned 2 -: 136: 2: 137: if (pid == 0) { branch 0 taken 0 (fallthrough) branch 1 taken 2 -: 138: /* Child: write-only end of the pipe */ #####: 139: int wfd = open(fifo_path, O_WRONLY | O_CLOEXEC); %%%%%: 139-block 0 call 0 never executed -: 140: #####: 141: if (wfd == -1) branch 0 never executed branch 1 never executed #####: 142: _exit(EXIT_FAILURE); %%%%%: 142-block 0 call 0 never executed -: 143: #####: 144: launch_execle(cmd); %%%%%: 144-block 0 call 0 never executed -: 145: #####: 146: close(wfd); call 0 never executed #####: 147: _exit(EXIT_SUCCESS); call 0 never executed -: 148: } -: 149: 2: 150: free(cmd); 2: 150-block 0 unconditional 0 taken 2 -: 151: -: 152: /* ######################################## -: 153: * # 4) LET THE PARENT READ THE PIPE # -: 154: * ######################################## */ -: 155: -: 156: /* Parent: read-only end of the pipe */ -: 157: int rfd; -: 158: -: 159: do 2: 160: rfd = open(fifo_path, O_RDONLY); 2: 160-block 0 call 0 returned 2 2*: 161: while (rfd == -1 && errno == EINTR); branch 0 taken 0 (fallthrough) branch 1 taken 2 %%%%%: 161-block 0 branch 2 never executed branch 3 never executed -: 162: 2: 163: char buf[PATH_MAX] = ""; 2: 164: ssize_t buf_len = 0; 2: 164-block 0 unconditional 0 taken 2 -: 165: -: 166: do 2: 167: buf_len = read(rfd, buf, sizeof(buf)); 2: 167-block 0 call 0 returned 2 2*: 168: while (buf_len == -1 && errno == EINTR); branch 0 taken 0 (fallthrough) branch 1 taken 2 %%%%%: 168-block 0 branch 2 never executed branch 3 never executed -: 169: 2: 170: close(rfd); 2: 170-block 0 call 0 returned 2 -: 171: -: 172: /* Wait for the child to finish. Otherwise, the child is left as -: 173: * zombie process */ 2: 174: int status = 0; 2: 175: waitpid(pid, &status, 0); call 0 returned 2 -: 176: -: 177: /* If the pipe is empty */ 2: 178: if (!*buf) { branch 0 taken 2 (fallthrough) branch 1 taken 0 2: 179: unlink(fifo_path); 2: 179-block 0 call 0 returned 2 2: 180: if (xargs.cwd_in_title == 1) branch 0 taken 2 (fallthrough) branch 1 taken 0 2: 181: set_term_title(ws[cur_ws].path); 2: 181-block 0 call 0 returned 2 unconditional 1 taken 2 2: 182: return EXIT_SUCCESS; 2: 182-block 0 unconditional 0 taken 2 -: 183: } -: 184: #####: 185: if (buf[buf_len - 1] == '\n') %%%%%: 185-block 0 branch 0 never executed branch 1 never executed #####: 186: buf[buf_len - 1] = '\0'; %%%%%: 186-block 0 unconditional 0 never executed -: 187: -: 188: /* If a valid file */ -: 189: struct stat attr; -: 190: #####: 191: if (lstat(buf, &attr) != -1) { %%%%%: 191-block 0 call 0 never executed branch 1 never executed branch 2 never executed #####: 192: char *o_cmd[] = {"o", buf, NULL}; #####: 193: exit_status = open_function(o_cmd); %%%%%: 193-block 0 call 0 never executed -: 194: } -: 195: -: 196: /* If not a file, take it as a command*/ -: 197: else { #####: 198: size_t old_args = args_n; #####: 199: args_n = 0; -: 200: #####: 201: char **_cmd = parse_input_str(buf); %%%%%: 201-block 0 call 0 never executed -: 202: #####: 203: if (_cmd) { branch 0 never executed branch 1 never executed -: 204: #####: 205: char **alias_cmd = check_for_alias(_cmd); %%%%%: 205-block 0 call 0 never executed -: 206: #####: 207: if (alias_cmd) { branch 0 never executed branch 1 never executed #####: 208: exit_status = exec_cmd(alias_cmd); %%%%%: 208-block 0 call 0 never executed -: 209: #####: 210: for (i = 0; alias_cmd[i]; i++) unconditional 0 never executed %%%%%: 210-block 0 branch 1 never executed branch 2 never executed #####: 211: free(alias_cmd[i]); %%%%%: 211-block 0 unconditional 0 never executed -: 212: #####: 213: free(alias_cmd); %%%%%: 213-block 0 unconditional 0 never executed -: 214: } else { #####: 215: exit_status = exec_cmd(_cmd); %%%%%: 215-block 0 call 0 never executed -: 216: #####: 217: for (i = 0; i <= args_n; i++) unconditional 0 never executed %%%%%: 217-block 0 branch 1 never executed branch 2 never executed #####: 218: free(_cmd[i]); %%%%%: 218-block 0 unconditional 0 never executed -: 219: #####: 220: free(_cmd); %%%%%: 220-block 0 unconditional 0 never executed -: 221: } -: 222: } -: 223: #####: 224: args_n = old_args; %%%%%: 224-block 0 unconditional 0 never executed -: 225: } -: 226: -: 227: /* Remove the pipe file */ #####: 228: unlink(fifo_path); %%%%%: 228-block 0 call 0 never executed -: 229: #####: 230: if (xargs.cwd_in_title == 1) branch 0 never executed branch 1 never executed #####: 231: set_term_title(ws[cur_ws].path); %%%%%: 231-block 0 call 0 never executed unconditional 1 never executed -: 232: #####: 233: return exit_status; %%%%%: 233-block 0 unconditional 0 never executed -: 234:} -: 235: -: 236:int function edit_actions called 3 returned 100% blocks executed 77% 3: 237:edit_actions(void) -: 238:{ 3: 239: if (xargs.stealth_mode == 1) { 3: 239-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 3 #####: 240: printf("%s: Access to configuration files is not allowed in " %%%%%: 240-block 0 call 0 never executed -: 241: "stealth mode\n", PROGRAM_NAME); #####: 242: return EXIT_SUCCESS; unconditional 0 never executed -: 243: } -: 244: -: 245: /* Get actions file's current modification time */ -: 246: struct stat file_attrib; -: 247: 3: 248: if (stat(actions_file, &file_attrib) == -1) { 3: 248-block 0 call 0 returned 3 branch 1 taken 0 (fallthrough) branch 2 taken 3 #####: 249: fprintf(stderr, "actions: %s: %s\n", actions_file, strerror(errno)); %%%%%: 249-block 0 call 0 never executed call 1 never executed #####: 250: return EXIT_FAILURE; unconditional 0 never executed -: 251: } -: 252: 3: 253: time_t mtime_bfr = (time_t)file_attrib.st_mtime; -: 254: 3: 255: int ret = open_file(actions_file); 3: 255-block 0 call 0 returned 3 3: 256: if (ret != EXIT_SUCCESS) branch 0 taken 0 (fallthrough) branch 1 taken 3 #####: 257: return EXIT_FAILURE; %%%%%: 257-block 0 unconditional 0 never executed -: 258: -: 259: /* Get modification time after opening the file */ 3: 260: stat(actions_file, &file_attrib); 3: 260-block 0 call 0 returned 3 -: 261: -: 262: /* If modification times differ, the file was modified after being -: 263: * opened */ 3: 264: if (mtime_bfr != (time_t)file_attrib.st_mtime) { branch 0 taken 2 (fallthrough) branch 1 taken 1 -: 265: -: 266: /* Reload the array of available actions */ 2: 267: if (load_actions() != EXIT_SUCCESS) 2: 267-block 0 call 0 returned 2 branch 1 taken 0 (fallthrough) branch 2 taken 2 #####: 268: return EXIT_FAILURE; %%%%%: 268-block 0 unconditional 0 never executed -: 269: -: 270: /* Reload PATH commands as well to add new action(s) */ 2: 271: if (bin_commands) { 2: 271-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 0 -: 272: size_t i; 7493: 273: for (i = 0; bin_commands[i]; i++) 2: 273-block 0 unconditional 0 taken 2 7493: 273-block 1 branch 1 taken 7491 branch 2 taken 2 (fallthrough) 7491: 274: free(bin_commands[i]); 7491: 274-block 0 unconditional 0 taken 7491 -: 275: 2: 276: free(bin_commands); 2: 277: bin_commands = (char **)NULL; 2: 277-block 0 unconditional 0 taken 2 -: 278: } -: 279: 2: 280: if (paths) { 2: 280-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 0 -: 281: size_t i; 14: 282: for (i = 0; i < path_n; i++) 2: 282-block 0 unconditional 0 taken 2 14: 282-block 1 branch 1 taken 12 branch 2 taken 2 (fallthrough) 12: 283: free(paths[i]); 12: 283-block 0 unconditional 0 taken 12 -: 284: } -: 285: 2: 286: path_n = (size_t)get_path_env(); 2: 286-block 0 call 0 returned 2 -: 287: 2: 288: get_path_programs(); call 0 returned 2 unconditional 1 taken 2 -: 289: } -: 290: 3: 291: return EXIT_SUCCESS; 3: 291-block 0 unconditional 0 taken 3 -: 292:} clifm-1.26.3/misc/codecov/archives.c.gcov000066400000000000000000002100531506632037700201710ustar00rootroot00000000000000 -: 0:Source:archives.c -: 1:/* archives.c -- archiving functions */ -: 2: -: 3:/* -: 4: * This file is part of CliFM -: 5: * -: 6: * Copyright (C) 2016-2021, L. Abramovich -: 7: * All rights reserved. -: 8: -: 9: * CliFM is free software; you can redistribute it and/or modify -: 10: * it under the terms of the GNU General Public License as published by -: 11: * the Free Software Foundation; either version 2 of the License, or -: 12: * (at your option) any later version. -: 13: * -: 14: * CliFM is distributed in the hope that it will be useful, -: 15: * but WITHOUT ANY WARRANTY; without even the implied warranty of -: 16: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -: 17: * GNU General Public License for more details. -: 18: * -: 19: * You should have received a copy of the GNU General Public License -: 20: * along with this program; if not, write to the Free Software -: 21: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, -: 22: * MA 02110-1301, USA. -: 23:*/ -: 24:#ifndef _NO_ARCHIVING -: 25: -: 26:#include "helpers.h" -: 27: -: 28:#include -: 29:#include -: 30:#include -: 31:#include -: 32:#include -: 33: -: 34:#include "aux.h" -: 35:#include "exec.h" -: 36:#include "history.h" -: 37:#include "jump.h" -: 38:#include "listing.h" -: 39:#include "navigation.h" -: 40:#include "readline.h" -: 41:#include "checks.h" -: 42: -: 43:#ifndef _NO_MAGIC -: 44:#include "mime.h" -: 45:#endif -: 46: -: 47:static int zstandard(char *in_file, char *out_file, char mode, char op); -: 48: -: 49:static int function handle_iso called 2 returned 100% blocks executed 48% 2: 50:handle_iso(char *file) -: 51:{ 2: 52: int exit_status = EXIT_SUCCESS; -: 53: -: 54: /* Use 7z to -: 55: * list (l) -: 56: * extract (e) -: 57: * extrat to dir (x -oDIR FILE) -: 58: * test (t) */ -: 59: 2: 60: printf(_("%s[e]%sxtract %s[E]%sxtract-to-dir %s[l]%sist " 2: 60-block 0 call 0 returned 2 call 1 returned 2 -: 61: "%s[t]%stest %s[m]%sount %s[q]%suit\n"), BOLD, df_c, BOLD, -: 62: df_c, BOLD, df_c, BOLD, df_c, BOLD, df_c, BOLD, df_c); -: 63: 2: 64: char sel_op = 0; 2: 65: char *operation = (char *)NULL; 2: 66: while (!operation) { unconditional 0 taken 2 2: 66-block 0 branch 1 taken 2 branch 2 taken 0 (fallthrough) 2: 67: operation = rl_no_hist(_("Operation: ")); 2: 67-block 0 call 0 returned 2 call 1 returned 2 2*: 68: if (!operation) branch 0 taken 0 (fallthrough) branch 1 taken 2 #####: 69: continue; %%%%%: 69-block 0 unconditional 0 never executed 2*: 70: if (!*operation || operation[1] != '\0') { 2: 70-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 0 2: 70-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 2 #####: 71: free(operation); #####: 72: operation = (char *)NULL; #####: 73: continue; %%%%%: 73-block 0 unconditional 0 never executed -: 74: } -: 75: 2: 76: switch (*operation) { 2: 76-block 0 branch 0 taken 2 branch 1 taken 0 branch 2 taken 0 2: 77: case 'e': /* fallthrough */ -: 78: case 'E': /* fallthrough */ -: 79: case 'l': /* fallthrough */ -: 80: case 'm': /* fallthrough */ -: 81: case 't': 2: 82: sel_op = *operation; 2: 83: free(operation); 2: 84: break; 2: 84-block 0 unconditional 0 taken 2 -: 85: #####: 86: case 'q': #####: 87: free(operation); #####: 88: return EXIT_SUCCESS; %%%%%: 88-block 0 unconditional 0 never executed -: 89: #####: 90: default: #####: 91: free(operation); #####: 92: operation = (char *)NULL; #####: 93: break; %%%%%: 93-block 0 unconditional 0 never executed -: 94: } -: 95: 2: 96: if (sel_op) 2: 96-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 0 2: 97: break; 2: 97-block 0 unconditional 0 taken 2 -: 98: } -: 99: 2: 100: char *ret = strchr(file, '\\'); 2: 101: if (ret) { 2: 101-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 2 #####: 102: char *deq_file = dequote_str(file, 0); %%%%%: 102-block 0 call 0 never executed #####: 103: if (deq_file) { branch 0 never executed branch 1 never executed #####: 104: strcpy(file, deq_file); #####: 105: free(deq_file); %%%%%: 105-block 0 unconditional 0 never executed -: 106: } #####: 107: ret = (char *)NULL; %%%%%: 107-block 0 unconditional 0 never executed -: 108: } -: 109: 2: 110: switch (sel_op) { 2: 110-block 0 branch 0 taken 0 branch 1 taken 0 branch 2 taken 1 branch 3 taken 1 branch 4 taken 0 branch 5 taken 0 -: 111: -: 112: /* ########## EXTRACT #######*/ #####: 113: case 'e': { -: 114: /* 7z x -oDIR FILE (use FILE as DIR) */ #####: 115: char *o_option = (char *)xnmalloc(strlen(file) + 7, sizeof(char)); %%%%%: 115-block 0 call 0 never executed #####: 116: sprintf(o_option, "-o%s.dir", file); -: 117: -: 118: /* Construct and execute cmd */ #####: 119: char *cmd[] = {"7z", "x", o_option, file, NULL}; #####: 120: if (launch_execve(cmd, FOREGROUND, E_NOFLAG) != EXIT_SUCCESS) call 0 never executed branch 1 never executed branch 2 never executed #####: 121: exit_status = EXIT_FAILURE; %%%%%: 121-block 0 unconditional 0 never executed -: 122: #####: 123: free(o_option); #####: 124: } break; %%%%%: 124-block 0 unconditional 0 never executed -: 125: -: 126: /* ########## EXTRACT TO DIR ####### */ #####: 127: case 'E': { -: 128: /* 7z x -oDIR FILE (ask for DIR) */ #####: 129: char *ext_path = (char *)NULL; #####: 130: while (!ext_path) { %%%%%: 130-block 0 unconditional 0 never executed %%%%%: 130-block 1 branch 1 never executed branch 2 never executed #####: 131: ext_path = rl_no_hist(_("Extraction path: ")); %%%%%: 131-block 0 call 0 never executed call 1 never executed #####: 132: if (!ext_path) branch 0 never executed branch 1 never executed #####: 133: continue; %%%%%: 133-block 0 unconditional 0 never executed #####: 134: if (!*ext_path) { %%%%%: 134-block 0 branch 0 never executed branch 1 never executed #####: 135: free(ext_path); #####: 136: ext_path = (char *)NULL; #####: 137: continue; %%%%%: 137-block 0 unconditional 0 never executed -: 138: } -: 139: } -: 140: #####: 141: char *o_option = (char *)xnmalloc(strlen(ext_path) + 3, %%%%%: 141-block 0 call 0 never executed -: 142: sizeof(char)); #####: 143: sprintf(o_option, "-o%s", ext_path); -: 144: -: 145: /* Construct and execute cmd */ #####: 146: char *cmd[] = {"7z", "x", o_option, file, NULL}; #####: 147: if (launch_execve(cmd, FOREGROUND, E_NOFLAG) != EXIT_SUCCESS) call 0 never executed branch 1 never executed branch 2 never executed #####: 148: exit_status = EXIT_FAILURE; %%%%%: 148-block 0 unconditional 0 never executed -: 149: #####: 150: free(ext_path); #####: 151: free(o_option); #####: 152: ext_path = (char *)NULL; #####: 153: } break; %%%%%: 153-block 0 unconditional 0 never executed -: 154: -: 155: /* ########## LIST ####### */ 1: 156: case 'l': { -: 157: /* 7z l FILE */ 1: 158: char *cmd[] = {"7z", "l", file, NULL}; 1: 159: if (launch_execve(cmd, FOREGROUND, E_NOFLAG) != EXIT_SUCCESS) 1: 159-block 0 call 0 returned 1 branch 1 taken 0 (fallthrough) branch 2 taken 1 #####: 160: exit_status = EXIT_FAILURE; %%%%%: 160-block 0 unconditional 0 never executed 1: 161: } break; 1: 161-block 0 unconditional 0 taken 1 -: 162: -: 163: /* ########## MOUNT ####### */ -: 164: 1: 165: case 'm': { -: 166: /* Create mountpoint */ 1: 167: char *mountpoint = (char *)NULL; -: 168: 1: 169: if (xargs.stealth_mode == 1) { 1: 169-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 1 #####: 170: mountpoint = (char *)xnmalloc(strlen(file) + 19, sizeof(char)); %%%%%: 170-block 0 call 0 never executed #####: 171: sprintf(mountpoint, "/tmp/clifm-mounts/%s", file); unconditional 0 never executed -: 172: } else { 1: 173: mountpoint = (char *)xnmalloc(strlen(config_dir) + strlen(file) + 9, sizeof(char)); 1: 173-block 0 call 0 returned 1 1: 174: sprintf(mountpoint, "%s/mounts/%s", config_dir, file); unconditional 0 taken 1 -: 175: } -: 176: 1: 177: char *dir_cmd[] = {"mkdir", "-pm700", mountpoint, NULL}; 1: 178: if (launch_execve(dir_cmd, FOREGROUND, E_NOFLAG) != EXIT_SUCCESS) { 1: 178-block 0 call 0 returned 1 branch 1 taken 0 (fallthrough) branch 2 taken 1 #####: 179: free(mountpoint); #####: 180: return EXIT_FAILURE; %%%%%: 180-block 0 unconditional 0 never executed %%%%%: 180-block 1 unconditional 1 never executed -: 181: } -: 182: -: 183: /* Construct and execute cmd */ 1: 184: char *sudo = get_sudo_path(); 1: 184-block 0 call 0 returned 1 1: 185: if (!sudo) { branch 0 taken 0 (fallthrough) branch 1 taken 1 #####: 186: free(mountpoint); #####: 187: return EXIT_FAILURE; %%%%%: 187-block 0 unconditional 0 never executed -: 188: } -: 189: 1: 190: char *cmd[] = {sudo, "mount", "-o", "loop", file, -: 191: mountpoint, NULL}; 1: 192: if (launch_execve(cmd, FOREGROUND, E_NOFLAG) != EXIT_SUCCESS) { 1: 192-block 0 call 0 returned 1 branch 1 taken 0 (fallthrough) branch 2 taken 1 #####: 193: free(mountpoint); #####: 194: free(sudo); #####: 195: return EXIT_FAILURE; %%%%%: 195-block 0 unconditional 0 never executed -: 196: } 1: 197: free(sudo); -: 198: -: 199: /* List content of mountpoint */ 1: 200: if (xchdir(mountpoint, SET_TITLE) == -1) { 1: 200-block 0 call 0 returned 1 branch 1 taken 0 (fallthrough) branch 2 taken 1 #####: 201: fprintf(stderr, "archiver: %s: %s\n", mountpoint, call 0 never executed #####: 202: strerror(errno)); %%%%%: 202-block 0 call 0 never executed #####: 203: free(mountpoint); #####: 204: return EXIT_FAILURE; unconditional 0 never executed -: 205: } -: 206: 1: 207: free(ws[cur_ws].path); 1: 208: ws[cur_ws].path = savestring(mountpoint, strlen(mountpoint)); 1: 208-block 0 call 0 returned 1 1: 209: add_to_jumpdb(ws[cur_ws].path); call 0 returned 1 -: 210: 1: 211: if (cd_lists_on_the_fly) { branch 0 taken 1 (fallthrough) branch 1 taken 0 1: 212: free_dirlist(); 1: 212-block 0 call 0 returned 1 1: 213: if (list_dir() != EXIT_SUCCESS) call 0 returned 1 branch 1 taken 0 (fallthrough) branch 2 taken 1 #####: 214: exit_status = EXIT_FAILURE; %%%%%: 214-block 0 unconditional 0 never executed 1: 215: add_to_dirhist(ws[cur_ws].path); 1: 215-block 0 call 0 returned 1 unconditional 1 taken 1 -: 216: } else { #####: 217: printf("%s: Successfully mounted on %s\n", file, mountpoint); %%%%%: 217-block 0 call 0 never executed unconditional 1 never executed -: 218: } -: 219: 1: 220: free(mountpoint); 1: 221: } break; 1: 221-block 0 unconditional 0 taken 1 -: 222: -: 223: /* ########## TEST #######*/ #####: 224: case 't': { -: 225: /* 7z t FILE */ #####: 226: char *cmd[] = {"7z", "t", file, NULL}; #####: 227: if (launch_execve(cmd, FOREGROUND, E_NOFLAG) != EXIT_SUCCESS) %%%%%: 227-block 0 call 0 never executed branch 1 never executed branch 2 never executed #####: 228: exit_status = EXIT_FAILURE; %%%%%: 228-block 0 unconditional 0 never executed #####: 229: } break; %%%%%: 229-block 0 unconditional 0 never executed -: 230: } -: 231: 2: 232: return exit_status; 2: 232-block 0 unconditional 0 taken 2 -: 233:} -: 234: -: 235:static int function create_iso called 0 returned 0% blocks executed 0% #####: 236:create_iso(char *in_file, char *out_file) -: 237:{ #####: 238: int exit_status = EXIT_SUCCESS; -: 239: struct stat file_attrib; #####: 240: if (lstat(in_file, &file_attrib) == -1) { %%%%%: 240-block 0 call 0 never executed branch 1 never executed branch 2 never executed #####: 241: fprintf(stderr, "archiver: %s: %s\n", in_file, strerror(errno)); %%%%%: 241-block 0 call 0 never executed call 1 never executed #####: 242: return EXIT_FAILURE; unconditional 0 never executed -: 243: } -: 244: -: 245: /* If IN_FILE is a directory */ #####: 246: if ((file_attrib.st_mode & S_IFMT) == S_IFDIR) { %%%%%: 246-block 0 branch 0 never executed branch 1 never executed #####: 247: char *cmd[] = {"mkisofs", "-R", "-o", out_file, in_file, NULL}; #####: 248: if (launch_execve(cmd, FOREGROUND, E_NOFLAG) != EXIT_SUCCESS) %%%%%: 248-block 0 call 0 never executed branch 1 never executed branch 2 never executed #####: 249: exit_status = EXIT_FAILURE; %%%%%: 249-block 0 unconditional 0 never executed -: 250: } -: 251: -: 252: /* If IN_FILE is a block device */ #####: 253: else if ((file_attrib.st_mode & S_IFMT) == S_IFBLK) { %%%%%: 253-block 0 branch 0 never executed branch 1 never executed #####: 254: char *if_option = (char *)xnmalloc(strlen(in_file) + 4, sizeof(char)); %%%%%: 254-block 0 call 0 never executed #####: 255: sprintf(if_option, "if=%s", in_file); -: 256: #####: 257: char *of_option = (char *)xnmalloc(strlen(out_file) + 4, sizeof(char)); call 0 never executed #####: 258: sprintf(of_option, "of=%s", out_file); -: 259: #####: 260: char *sudo = get_sudo_path(); call 0 never executed #####: 261: if (!sudo) { branch 0 never executed branch 1 never executed #####: 262: free(if_option); #####: 263: free(of_option); #####: 264: return EXIT_FAILURE; %%%%%: 264-block 0 unconditional 0 never executed -: 265: } -: 266: #####: 267: char *cmd[] = {sudo, "dd", if_option, of_option, "bs=64k", -: 268: "conv=noerror,sync", "status=progress", NULL}; #####: 269: if (launch_execve(cmd, FOREGROUND, E_NOFLAG) != EXIT_SUCCESS) %%%%%: 269-block 0 call 0 never executed branch 1 never executed branch 2 never executed #####: 270: exit_status = EXIT_FAILURE; %%%%%: 270-block 0 unconditional 0 never executed -: 271: #####: 272: free(sudo); #####: 273: free(if_option); #####: 274: free(of_option); %%%%%: 274-block 0 unconditional 0 never executed -: 275: } -: 276: -: 277: else { #####: 278: fprintf(stderr, "archiver: %s: Invalid file format\nFile " %%%%%: 278-block 0 call 0 never executed -: 279: "should be either a directory or a block device\n", -: 280: in_file); #####: 281: return EXIT_FAILURE; unconditional 0 never executed -: 282: } -: 283: #####: 284: return exit_status; %%%%%: 284-block 0 unconditional 0 never executed -: 285:} -: 286: -: 287:/* Run the 'file' command on FILE and look for "ISO 9660" and -: 288: * string in its output. Returns zero if found, one if not, and -1 -: 289: * in case of error */ -: 290:static int function check_iso called 5 returned 100% blocks executed 62% 5: 291:check_iso(char *file) -: 292:{ 5: 293: if (!file || !*file) { 5: 293-block 0 branch 0 taken 5 (fallthrough) branch 1 taken 0 5: 293-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 5 #####: 294: fputs(_("Error querying file type\n"), stderr); %%%%%: 294-block 0 call 0 never executed call 1 never executed #####: 295: return -1; unconditional 0 never executed -: 296: } -: 297: 5: 298: int is_iso = 0; -: 299: -: 300:#ifndef _NO_MAGIC 5: 301: char *t = xmagic(file, TEXT_DESC); 5: 301-block 0 call 0 returned 5 5: 302: if (!t) { branch 0 taken 0 (fallthrough) branch 1 taken 5 #####: 303: fputs(_("Error querying file type\n"), stderr); %%%%%: 303-block 0 call 0 never executed call 1 never executed #####: 304: return (-1); unconditional 0 never executed -: 305: } -: 306: 5: 307: char *ret = strstr(t, "ISO 9660"); 5: 308: if (ret) 5: 308-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 3 2: 309: is_iso = 1; 2: 309-block 0 unconditional 0 taken 2 -: 310: 5: 311: free(t); -: 312:#else -: 313: char iso_tmp_file[PATH_MAX] = ""; -: 314: char *rand_ext = gen_rand_str(6); -: 315: if (!rand_ext) -: 316: return (-1); -: 317: -: 318: if (xargs.stealth_mode == 1) -: 319: sprintf(iso_tmp_file, "/tmp/clifm-archiver.%s", rand_ext); -: 320: else -: 321: sprintf(iso_tmp_file, "%s/archiver.%s", tmp_dir, rand_ext); -: 322: free(rand_ext); -: 323: -: 324: int fd; -: 325: FILE *fp = open_fstream_w(iso_tmp_file, &fd); -: 326: if (!fp) { -: 327: fprintf(stderr, "%s: %s: %s\n", PROGRAM_NAME, iso_tmp_file, -: 328: strerror(errno)); -: 329: return (-1); -: 330: } -: 331: -: 332: FILE *fpp = fopen("/dev/null", "w"); -: 333: if (!fpp) { -: 334: fprintf(stderr, "%s: /dev/null: %s\n", PROGRAM_NAME, strerror(errno)); -: 335: close_fstream(fp, fd); -: 336: return (-1); -: 337: } -: 338: -: 339: int stdout_bk = dup(STDOUT_FILENO); /* Store original stdout */ -: 340: int stderr_bk = dup(STDERR_FILENO); /* Store original stderr */ -: 341: -: 342: /* Redirect stdout to the desired file */ -: 343: if (dup2(fileno(fp), STDOUT_FILENO) == -1) { -: 344: fprintf(stderr, "%s: %s\n", PROGRAM_NAME, strerror(errno)); -: 345: close_fstream(fp, fd); -: 346: fclose(fpp); -: 347: return (-1); -: 348: } -: 349: -: 350: /* Redirect stderr to /dev/null */ -: 351: if (dup2(fileno(fpp), STDERR_FILENO) == -1) { -: 352: fprintf(stderr, "%s: %s\n", PROGRAM_NAME, strerror(errno)); -: 353: close_fstream(fp, fd); -: 354: fclose(fpp); -: 355: return (-1); -: 356: } -: 357: -: 358: close_fstream(fp, fd); -: 359: fclose(fpp); -: 360: -: 361: char *cmd[] = {"file", "-b", file, NULL}; -: 362: int retval = launch_execve(cmd, FOREGROUND, E_NOFLAG); -: 363: -: 364: dup2(stdout_bk, STDOUT_FILENO); /* Restore original stdout */ -: 365: dup2(stderr_bk, STDERR_FILENO); /* Restore original stderr */ -: 366: close(stdout_bk); -: 367: close(stderr_bk); -: 368: -: 369: if (retval != EXIT_SUCCESS) -: 370: return (-1); -: 371: -: 372: if (access(iso_tmp_file, F_OK) == 0) { -: 373: fp = open_fstream_r(iso_tmp_file, &fd); -: 374: if (fp) { -: 375: char line[255] = ""; -: 376: if (fgets(line, (int)sizeof(line), fp) == NULL) { -: 377: close_fstream(fp, fd); -: 378: unlink(iso_tmp_file); -: 379: return EXIT_FAILURE; -: 380: } -: 381: char *ret = strstr(line, "ISO 9660"); -: 382: if (ret) -: 383: is_iso = 1; -: 384: close_fstream(fp, fd); -: 385: } -: 386: unlink(iso_tmp_file); -: 387: } -: 388:#endif /* !_NO_MAGIC */ -: 389: 5: 390: if (is_iso) 5: 390-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 3 2: 391: return EXIT_SUCCESS; 2: 391-block 0 unconditional 0 taken 2 -: 392: 3: 393: return EXIT_FAILURE; 3: 393-block 0 unconditional 0 taken 3 -: 394:} -: 395: -: 396:/* Run the 'file' command on FILE and look for "archive" and -: 397: * "compressed" strings in its output. Returns zero if compressed, -: 398: * one if not, and -1 in case of error. -: 399: * test_iso is used to determine if ISO files should be checked as -: 400: * well: this is the case when called from open_function() or -: 401: * mime_open(), since both need to check compressed and ISOs as -: 402: * well (and there is no need to run two functions (is_compressed and -: 403: * check_iso), when we can run just one) */ -: 404:int function is_compressed called 18 returned 100% blocks executed 67% 18: 405:is_compressed(char *file, int test_iso) -: 406:{ 18: 407: if (!file || !*file) { 18: 407-block 0 branch 0 taken 18 (fallthrough) branch 1 taken 0 18: 407-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 18 #####: 408: fputs(_("Error querying file type\n"), stderr); %%%%%: 408-block 0 call 0 never executed call 1 never executed #####: 409: return (-1); unconditional 0 never executed -: 410: } -: 411: 18: 412: int compressed = 0; -: 413: -: 414:#ifndef _NO_MAGIC 18: 415: char *t = xmagic(file, TEXT_DESC); 18: 415-block 0 call 0 returned 18 18: 416: if (!t) { branch 0 taken 0 (fallthrough) branch 1 taken 18 #####: 417: fputs(_("Error querying file type\n"), stderr); %%%%%: 417-block 0 call 0 never executed call 1 never executed #####: 418: return (-1); unconditional 0 never executed -: 419: } -: 420: 18: 421: char *ret = strstr(t, "archive"); 18: 422: if (ret) { 18: 422-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 18 #####: 423: compressed = 1; %%%%%: 423-block 0 unconditional 0 never executed -: 424: } else { 18: 425: ret = strstr(t, "compressed"); 18: 426: if (ret) { 18: 426-block 0 branch 0 taken 5 (fallthrough) branch 1 taken 13 5: 427: compressed = 1; 5: 427-block 0 unconditional 0 taken 5 13: 428: } else if (test_iso) { 13: 428-block 0 branch 0 taken 13 (fallthrough) branch 1 taken 0 13: 429: ret = strstr(t, "ISO 9660"); 13: 430: if (ret) 13: 430-block 0 branch 0 taken 4 (fallthrough) branch 1 taken 9 4: 431: compressed = 1; 4: 431-block 0 unconditional 0 taken 4 -: 432: } -: 433: } -: 434: 18: 435: free(t); -: 436:#else -: 437: char *rand_ext = gen_rand_str(6); -: 438: if (!rand_ext) -: 439: return (-1); -: 440: -: 441: char archiver_tmp_file[PATH_MAX]; -: 442: if (xargs.stealth_mode == 1) -: 443: sprintf(archiver_tmp_file, "/tmp/clifm-archiver.%s", rand_ext); -: 444: else -: 445: sprintf(archiver_tmp_file, "%s/archiver.%s", tmp_dir, rand_ext); -: 446: free(rand_ext); -: 447: -: 448: int fd; -: 449: FILE *fp = open_fstream_w(archiver_tmp_file, &fd); -: 450: if (!fp) { -: 451: fprintf(stderr, "%s: %s: %s\n", PROGRAM_NAME, -: 452: archiver_tmp_file, strerror(errno)); -: 453: return (-1); -: 454: } -: 455: -: 456:/* if (access(archiver_tmp_file, F_OK) == 0) -: 457: unlinkat(fd, archiver_tmp_file, 0); */ -: 458: -: 459: FILE *fpp = fopen("/dev/null", "w"); -: 460: if (!fpp) { -: 461: fprintf(stderr, "%s: /dev/null: %s\n", PROGRAM_NAME, strerror(errno)); -: 462: close_fstream(fp, fd); -: 463: return -1; -: 464: } -: 465: -: 466: int stdout_bk = dup(STDOUT_FILENO); /* Store original stdout */ -: 467: int stderr_bk = dup(STDERR_FILENO); /* Store original stderr */ -: 468: -: 469: /* Redirect stdout to the desired file */ -: 470: if (dup2(fileno(fp), STDOUT_FILENO) == -1) { -: 471: fprintf(stderr, "%s: %s\n", PROGRAM_NAME, strerror(errno)); -: 472: close_fstream(fp, fd); -: 473: fclose(fpp); -: 474: return (-1); -: 475: } -: 476: -: 477: /* Redirect stderr to /dev/null */ -: 478: if (dup2(fileno(fpp), STDERR_FILENO) == -1) { -: 479: fprintf(stderr, "%s: %s\n", PROGRAM_NAME, strerror(errno)); -: 480: close_fstream(fp, fd); -: 481: fclose(fpp); -: 482: return -1; -: 483: } -: 484: -: 485: close_fstream(fp, fd); -: 486: fclose(fpp); -: 487: -: 488: char *cmd[] = {"file", "-b", file, NULL}; -: 489: int retval = launch_execve(cmd, FOREGROUND, E_NOFLAG); -: 490: -: 491: dup2(stdout_bk, STDOUT_FILENO); /* Restore original stdout */ -: 492: dup2(stderr_bk, STDERR_FILENO); /* Restore original stderr */ -: 493: close(stdout_bk); -: 494: close(stderr_bk); -: 495: -: 496: if (retval != EXIT_SUCCESS) -: 497: return (-1); -: 498: -: 499: if (access(archiver_tmp_file, F_OK) == 0) { -: 500: fp = open_fstream_r(archiver_tmp_file, &fd); -: 501: if (fp) { -: 502: char line[255]; -: 503: if (fgets(line, (int)sizeof(line), fp) == NULL) { -: 504: close_fstream(fp, fd); -: 505: unlink(archiver_tmp_file); -: 506: return EXIT_FAILURE; -: 507: } -: 508: char *ret = strstr(line, "archive"); -: 509: -: 510: if (ret) { -: 511: compressed = 1; -: 512: } else { -: 513: ret = strstr(line, "compressed"); -: 514: if (ret) { -: 515: compressed = 1; -: 516: } else if (test_iso) { -: 517: ret = strstr(line, "ISO 9660"); -: 518: if (ret) -: 519: compressed = 1; -: 520: } -: 521: } -: 522: -: 523: close_fstream(fp, fd); -: 524: } -: 525: -: 526: unlink(archiver_tmp_file); -: 527: } -: 528:#endif /* !_NO_MAGIC */ -: 529: 18: 530: if (compressed) 18: 530-block 0 branch 0 taken 9 (fallthrough) branch 1 taken 9 9: 531: return EXIT_SUCCESS; 9: 531-block 0 unconditional 0 taken 9 -: 532: 9: 533: return EXIT_FAILURE; 9: 533-block 0 unconditional 0 taken 9 -: 534:} -: 535: -: 536:/* Handle archives and/or compressed files (ARGS) according to MODE: -: 537: * 'c' for archiving/compression, and 'd' for dearchiving/decompression -: 538: * (including listing, extracting, repacking, and mounting). Returns -: 539: * zero on success and one on error. Depends on 'zstd' for Zdtandard -: 540: * files 'atool' and 'archivemount' for the remaining types. */ -: 541:int function archiver called 7 returned 100% blocks executed 40% 7: 542:archiver(char **args, char mode) -: 543:{ -: 544: size_t i; 7: 545: int exit_status = EXIT_SUCCESS; -: 546: 7: 547: if (!args[1]) 7: 547-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 7 #####: 548: return EXIT_FAILURE; %%%%%: 548-block 0 unconditional 0 never executed -: 549: 7: 550: if (mode == 'c') { 7: 550-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 5 -: 551: -: 552: /* ################################## -: 553: * # 1 - COMPRESSION # -: 554: * ##################################*/ -: 555: -: 556: /* Get archive name/type */ -: 557: 2: 558: puts(_("Use extension to specify archive/compression type " 2: 558-block 0 call 0 returned 2 call 1 returned 2 -: 559: "(defaults to .tar.gz)\nExample: myarchive.xz")); 2: 560: char *name = (char *)NULL; 4: 561: while (!name) { unconditional 0 taken 2 4: 561-block 0 branch 1 taken 2 branch 2 taken 2 (fallthrough) 2: 562: name = rl_no_hist(_("File name ('q' to quit): ")); 2: 562-block 0 call 0 returned 2 call 1 returned 2 2*: 563: if (!name) branch 0 taken 0 (fallthrough) branch 1 taken 2 #####: 564: continue; %%%%%: 564-block 0 unconditional 0 never executed 2*: 565: if (!*name) { 2: 565-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 2 #####: 566: free(name); #####: 567: name = (char *)NULL; #####: 568: continue; %%%%%: 568-block 0 unconditional 0 never executed -: 569: } -: 570: 2*: 571: if (*name == 'q' && name[1] == '\0') { 2: 571-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 2 %%%%%: 571-block 1 branch 2 never executed branch 3 never executed #####: 572: free(name); #####: 573: return EXIT_SUCCESS; %%%%%: 573-block 0 unconditional 0 never executed -: 574: } -: 575: 2: 576: char *dot = strrchr(name, '.'); -: 577: /* If no extension, add the default */ 2: 578: if (!dot) { 2: 578-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 0 2: 579: size_t name_len = strlen(name); 2: 580: char *t = (char *)xnmalloc(name_len + 1, sizeof(char)); 2: 580-block 0 call 0 returned 2 2: 581: strcpy(t, name); 2: 582: name = (char *)xrealloc(name, (name_len + 8) * sizeof(char)); call 0 returned 2 2: 583: sprintf(name, "%s.tar.gz", t); 2: 584: free(t); unconditional 0 taken 2 #####: 585: } else if (dot == name) { /* Dot is first char */ %%%%%: 585-block 0 branch 0 never executed branch 1 never executed #####: 586: fprintf(stderr, _("Invalid file name\n")); %%%%%: 586-block 0 call 0 never executed call 1 never executed #####: 587: free(name); #####: 588: name = (char *)NULL; unconditional 0 never executed -: 589: } -: 590: } -: 591: -: 592: /* ########################## -: 593: * # ZSTANDARD # -: 594: * ########################## */ -: 595: 2: 596: char *ret = strrchr(name, '.'); 2: 597: if (strcmp(ret, ".zst") == 0) { 2: 597-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 2 -: 598: /* Multiple files */ #####: 599: if (args[2]) { %%%%%: 599-block 0 branch 0 never executed branch 1 never executed #####: 600: printf(_("\n%sNOTE%s: Zstandard does not support " %%%%%: 600-block 0 call 0 never executed call 1 never executed -: 601: "compression of multiple files into one single " -: 602: "compressed file. Files will be compressed rather " -: 603: "into multiple compressed files using original " -: 604: "file names\n"), BOLD, df_c); -: 605: #####: 606: for (i = 1; args[i]; i++) { unconditional 0 never executed %%%%%: 606-block 0 unconditional 1 never executed %%%%%: 606-block 1 branch 2 never executed branch 3 never executed #####: 607: if (zstandard(args[i], NULL, 'c', 0) != EXIT_SUCCESS) %%%%%: 607-block 0 call 0 never executed branch 1 never executed branch 2 never executed #####: 608: exit_status = EXIT_FAILURE; %%%%%: 608-block 0 unconditional 0 never executed -: 609: } -: 610: } -: 611: -: 612: /* Only one file */ -: 613: else #####: 614: exit_status = zstandard(args[1], name, 'c', 0); %%%%%: 614-block 0 call 0 never executed unconditional 1 never executed #####: 615: free(name); #####: 616: return exit_status; %%%%%: 616-block 0 unconditional 0 never executed -: 617: } -: 618: -: 619: /* ########################## -: 620: * # ISO 9660 # -: 621: * ########################## */ -: 622: 2: 623: if (strcmp(ret, ".iso") == 0) { 2: 623-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 2 #####: 624: exit_status = create_iso(args[1], name); %%%%%: 624-block 0 call 0 never executed #####: 625: free(name); #####: 626: return exit_status; unconditional 0 never executed -: 627: } -: 628: -: 629: /* ########################## -: 630: * # OTHERS # -: 631: * ########################## */ -: 632: -: 633: /* Escape the string, if needed */ 2: 634: char *esc_name = escape_str(name); 2: 634-block 0 call 0 returned 2 2: 635: if (!esc_name) { branch 0 taken 0 (fallthrough) branch 1 taken 2 #####: 636: fprintf(stderr, _("archiver: %s: Error escaping string\n"), %%%%%: 636-block 0 call 0 never executed call 1 never executed -: 637: name); #####: 638: free(name); #####: 639: return EXIT_FAILURE; unconditional 0 never executed -: 640: } -: 641: 2: 642: free(name); -: 643: -: 644: /* Construct the command */ 2: 645: char *cmd = (char *)NULL; 2: 646: char *ext_ok = strrchr(esc_name, '.'); 2*: 647: size_t cmd_len = strlen(esc_name) + 10 + (!ext_ok ? 8 : 0); 2: 647-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 2 %%%%%: 647-block 1 unconditional 2 never executed 2: 647-block 2 unconditional 3 taken 2 2: 648: cmd = (char *)xnmalloc(cmd_len, sizeof(char)); 2: 648-block 0 call 0 returned 2 -: 649: /* If name has no extension, add the default */ 2*: 650: sprintf(cmd, "atool -a %s%s", esc_name, !ext_ok ? ".tar.gz" : ""); branch 0 taken 0 (fallthrough) branch 1 taken 2 %%%%%: 650-block 0 unconditional 2 never executed 2: 650-block 1 unconditional 3 taken 2 -: 651: 7: 652: for (i = 1; args[i]; i++) { 2: 652-block 0 unconditional 0 taken 2 5: 652-block 1 unconditional 1 taken 5 7: 652-block 2 branch 2 taken 5 branch 3 taken 2 (fallthrough) 5: 653: char *_name = (char *)NULL; 5: 654: if (!strchr(args[i], '\\')) { 5: 654-block 0 branch 0 taken 5 (fallthrough) branch 1 taken 0 5: 655: _name = escape_str(args[i]); 5: 655-block 0 call 0 returned 5 5*: 656: if (!_name) { branch 0 taken 0 (fallthrough) branch 1 taken 5 #####: 657: fprintf(stderr, _("%s: Error escaping file name\n"), args[i]); %%%%%: 657-block 0 call 0 never executed call 1 never executed #####: 658: continue; unconditional 0 never executed -: 659: } -: 660: } 5*: 661: cmd_len += strlen(_name ? _name : args[i]) + 1; 5: 661-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 5 %%%%%: 661-block 1 unconditional 2 never executed 5: 661-block 2 unconditional 3 taken 5 5: 662: cmd = (char *)xrealloc(cmd, (cmd_len + 1) * sizeof(char)); 5: 662-block 0 call 0 returned 5 5: 663: strcat(cmd, " "); 5*: 664: strcat(cmd, _name ? _name : args[i]); branch 0 taken 0 (fallthrough) branch 1 taken 5 %%%%%: 664-block 0 unconditional 2 never executed 5: 664-block 1 unconditional 3 taken 5 5: 665: free(_name); 5: 665-block 0 unconditional 0 taken 5 -: 666: } -: 667: 2: 668: if (launch_execle(cmd) != EXIT_SUCCESS) 2: 668-block 0 call 0 returned 2 branch 1 taken 0 (fallthrough) branch 2 taken 2 #####: 669: exit_status = EXIT_FAILURE; %%%%%: 669-block 0 unconditional 0 never executed -: 670: 2: 671: free(cmd); 2: 672: free(esc_name); 2: 673: return exit_status; 2: 673-block 0 unconditional 0 taken 2 -: 674: } -: 675: -: 676: /* mode == 'd' */ -: 677: -: 678: /* ################################## -: 679: * # 2 - DECOMPRESSION # -: 680: * ##################################*/ -: 681: -: 682: /* Exit if at least one non-compressed file is found */ 10: 683: for (i = 1; args[i]; i++) { 5: 683-block 0 unconditional 0 taken 5 5: 683-block 1 unconditional 1 taken 5 10: 683-block 2 branch 2 taken 5 branch 3 taken 5 (fallthrough) 5: 684: char *deq = (char *)NULL; 5: 685: if (strchr(args[i], '\\')) { 5: 685-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 5 #####: 686: deq = dequote_str(args[i], 0); %%%%%: 686-block 0 call 0 never executed #####: 687: strcpy(args[i], deq); #####: 688: free(deq); unconditional 0 never executed -: 689: } -: 690: 5: 691: if (is_compressed(args[i], 1) != 0) { 5: 691-block 0 call 0 returned 5 branch 1 taken 0 (fallthrough) branch 2 taken 5 #####: 692: fprintf(stderr, _("archiver: %s: Not an archive/compressed file\n"), call 0 never executed #####: 693: args[i]); %%%%%: 693-block 0 call 0 never executed #####: 694: return EXIT_FAILURE; unconditional 0 never executed -: 695: } -: 696: } -: 697: -: 698: /* ########################## -: 699: * # ISO 9660 # -: 700: * ########################## */ -: 701: 5: 702: char *ret = strrchr(args[1], '.'); 5: 703: if ((ret && strcmp(ret, ".iso") == 0) || check_iso(args[1]) == 0) 5: 703-block 0 branch 0 taken 5 (fallthrough) branch 1 taken 0 5: 703-block 1 branch 2 taken 5 (fallthrough) branch 3 taken 0 5: 703-block 2 call 4 returned 5 branch 5 taken 2 (fallthrough) branch 6 taken 3 2: 704: return handle_iso(args[1]); 2: 704-block 0 call 0 returned 2 unconditional 1 taken 2 -: 705: -: 706: /* ########################## -: 707: * # ZSTANDARD # -: 708: * ########################## */ -: 709: -: 710: /* Check if we have at least one Zstandard file */ -: 711: 3: 712: int zst_index = -1; 3: 713: size_t files_num = 0; -: 714: 6: 715: for (i = 1; args[i]; i++) { 3: 715-block 0 unconditional 0 taken 3 3: 715-block 1 unconditional 1 taken 3 6: 715-block 2 branch 2 taken 3 branch 3 taken 3 (fallthrough) 3: 716: files_num++; 3: 717: if (args[i][strlen(args[i]) - 1] == 't') { 3: 717-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 3 #####: 718: char *retval = strrchr(args[i], '.'); #####: 719: if (retval) { %%%%%: 719-block 0 branch 0 never executed branch 1 never executed #####: 720: if (strcmp(retval, ".zst") == 0) %%%%%: 720-block 0 branch 0 never executed branch 1 never executed #####: 721: zst_index = (int)i; %%%%%: 721-block 0 unconditional 0 never executed -: 722: } -: 723: } -: 724: } -: 725: 3: 726: if (zst_index != -1) { 3: 726-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 3 -: 727: /* Multiple files */ #####: 728: if (files_num > 1) { %%%%%: 728-block 0 branch 0 never executed branch 1 never executed #####: 729: printf(_("%sNOTE%s: Using Zstandard\n"), BOLD, df_c); %%%%%: 729-block 0 call 0 never executed call 1 never executed #####: 730: printf(_("%s[e]%sxtract %s[t]%sest %s[i]%snfo %s[q]%suit\n"), call 0 never executed call 1 never executed -: 731: BOLD, df_c, BOLD, df_c, BOLD, df_c, BOLD, df_c); -: 732: #####: 733: char *operation = (char *)NULL; #####: 734: char sel_op = 0; #####: 735: while (!operation) { unconditional 0 never executed %%%%%: 735-block 0 branch 1 never executed branch 2 never executed #####: 736: operation = rl_no_hist(_("Operation: ")); %%%%%: 736-block 0 call 0 never executed call 1 never executed #####: 737: if (!operation) branch 0 never executed branch 1 never executed #####: 738: continue; %%%%%: 738-block 0 unconditional 0 never executed #####: 739: if (!*operation || operation[1] != '\0') { %%%%%: 739-block 0 branch 0 never executed branch 1 never executed %%%%%: 739-block 1 branch 2 never executed branch 3 never executed #####: 740: free(operation); #####: 741: operation = (char *)NULL; #####: 742: continue; %%%%%: 742-block 0 unconditional 0 never executed -: 743: } -: 744: #####: 745: switch (*operation) { %%%%%: 745-block 0 branch 0 never executed branch 1 never executed branch 2 never executed #####: 746: case 'e': /* fallthrough */ -: 747: case 't': /* fallthrough */ -: 748: case 'i': #####: 749: sel_op = *operation; #####: 750: break; %%%%%: 750-block 0 unconditional 0 never executed -: 751: #####: 752: case 'q': #####: 753: free(operation); #####: 754: return EXIT_SUCCESS; %%%%%: 754-block 0 unconditional 0 never executed -: 755: #####: 756: default: #####: 757: free(operation); #####: 758: operation = (char *)NULL; #####: 759: break; %%%%%: 759-block 0 unconditional 0 never executed -: 760: } -: 761: } -: 762: #####: 763: for (i = 1; args[i]; i++) { %%%%%: 763-block 0 unconditional 0 never executed %%%%%: 763-block 1 unconditional 1 never executed %%%%%: 763-block 2 branch 2 never executed branch 3 never executed #####: 764: if (zstandard(args[i], NULL, 'd', sel_op) != EXIT_SUCCESS) %%%%%: 764-block 0 call 0 never executed branch 1 never executed branch 2 never executed #####: 765: exit_status = EXIT_FAILURE; %%%%%: 765-block 0 unconditional 0 never executed -: 766: } -: 767: #####: 768: free(operation); #####: 769: return exit_status; %%%%%: 769-block 0 unconditional 0 never executed -: 770: } -: 771: -: 772: /* Just one file */ -: 773: else { #####: 774: if (zstandard(args[zst_index], NULL, 'd', 0) != EXIT_SUCCESS) %%%%%: 774-block 0 call 0 never executed branch 1 never executed branch 2 never executed #####: 775: exit_status = EXIT_FAILURE; %%%%%: 775-block 0 unconditional 0 never executed #####: 776: return exit_status; %%%%%: 776-block 0 unconditional 0 never executed -: 777: } -: 778: } -: 779: -: 780: /* ########################## -: 781: * # OTHERS # -: 782: * ########################## */ -: 783: -: 784: /* 1) Get operation to be performed -: 785: * ################################ */ -: 786: 3: 787: printf(_("%s[e]%sxtract %s[E]%sxtract-to-dir %s[l]%sist " 3: 787-block 0 call 0 returned 3 call 1 returned 3 -: 788: "%s[m]%sount %s[r]%sepack %s[q]%suit\n"), BOLD, df_c, BOLD, -: 789: df_c, BOLD, df_c, BOLD, df_c, BOLD, df_c, BOLD, df_c); -: 790: 3: 791: char *operation = (char *)NULL; 3: 792: char sel_op = 0; -: 793: 3: 794: while (!operation) { unconditional 0 taken 3 3: 794-block 0 branch 1 taken 3 branch 2 taken 0 (fallthrough) 3: 795: operation = rl_no_hist(_("Operation: ")); 3: 795-block 0 call 0 returned 3 call 1 returned 3 3*: 796: if (!operation) branch 0 taken 0 (fallthrough) branch 1 taken 3 #####: 797: continue; %%%%%: 797-block 0 unconditional 0 never executed 3*: 798: if (!*operation || operation[1] != '\0') { 3: 798-block 0 branch 0 taken 3 (fallthrough) branch 1 taken 0 3: 798-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 3 #####: 799: free(operation); #####: 800: operation = (char *)NULL; #####: 801: continue; %%%%%: 801-block 0 unconditional 0 never executed -: 802: } -: 803: 3: 804: switch (*operation) { 3: 804-block 0 branch 0 taken 2 branch 1 taken 1 branch 2 taken 0 2: 805: case 'e': /* fallthrough */ -: 806: case 'E': /* fallthrough */ -: 807: case 'l': /* fallthrough */ -: 808: case 'm': /* fallthrough */ -: 809: case 'r': 2: 810: sel_op = *operation; 2: 811: free(operation); 2: 812: break; 2: 812-block 0 unconditional 0 taken 2 -: 813: 1: 814: case 'q': 1: 815: free(operation); 1: 816: return EXIT_SUCCESS; 1: 816-block 0 unconditional 0 taken 1 -: 817: #####: 818: default: #####: 819: free(operation); #####: 820: operation = (char *)NULL; #####: 821: break; %%%%%: 821-block 0 unconditional 0 never executed -: 822: } -: 823: 2: 824: if (sel_op) 2: 824-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 0 2: 825: break; 2: 825-block 0 unconditional 0 taken 2 -: 826: } -: 827: -: 828: /* 2) Prepare files based on operation -: 829: * #################################### */ -: 830: 2: 831: char *dec_files = (char *)NULL; -: 832: 2: 833: switch (sel_op) { 2: 833-block 0 branch 0 taken 1 branch 1 taken 1 branch 2 taken 0 1: 834: case 'e': /* fallthrough */ -: 835: case 'r': { -: 836: /* Store all file names into one single variable */ 1: 837: size_t len = 1; 1: 838: dec_files = (char *)xnmalloc(len, sizeof(char)); 1: 838-block 0 call 0 returned 1 1: 839: *dec_files = '\0'; -: 840: 2: 841: for (i = 1; args[i]; i++) { unconditional 0 taken 1 1: 841-block 0 unconditional 1 taken 1 2: 841-block 1 branch 2 taken 1 branch 3 taken 1 (fallthrough) -: 842: /* Escape the string, if needed */ 1: 843: char *esc_name = escape_str(args[i]); 1: 843-block 0 call 0 returned 1 1*: 844: if (!esc_name) branch 0 taken 0 (fallthrough) branch 1 taken 1 #####: 845: continue; %%%%%: 845-block 0 unconditional 0 never executed -: 846: 1: 847: len += strlen(esc_name) + 1; 1: 848: dec_files = (char *)xrealloc(dec_files, (len + 1) * sizeof(char)); 1: 848-block 0 call 0 returned 1 1: 849: strcat(dec_files, " "); 1: 850: strcat(dec_files, esc_name); 1: 851: free(esc_name); unconditional 0 taken 1 -: 852: } 1: 853: } break; 1: 853-block 0 unconditional 0 taken 1 -: 854: 1: 855: case 'E': /* fallthtough */ -: 856: case 'l': /* fallthtough */ -: 857: case 'm': { -: 858: /* These operation won't be executed via the system shell, -: 859: * so that we need to deescape files if necessary */ 2: 860: for (i = 1; args[i]; i++) { 1: 860-block 0 unconditional 0 taken 1 1: 860-block 1 unconditional 1 taken 1 2: 860-block 2 branch 2 taken 1 branch 3 taken 1 (fallthrough) 1: 861: if (strchr(args[i], '\\')) { 1: 861-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 1 #####: 862: char *deq_name = dequote_str(args[i], 0); %%%%%: 862-block 0 call 0 never executed #####: 863: if (!deq_name) { branch 0 never executed branch 1 never executed #####: 864: fprintf(stderr, _("archiver: %s: Error " call 0 never executed #####: 865: "dequoting file name\n"), args[i]); %%%%%: 865-block 0 call 0 never executed #####: 866: return EXIT_FAILURE; unconditional 0 never executed -: 867: } -: 868: #####: 869: strcpy(args[i], deq_name); #####: 870: free(deq_name); #####: 871: deq_name = (char *)NULL; %%%%%: 871-block 0 unconditional 0 never executed -: 872: } -: 873: } 1: 874: } break; 1: 874-block 0 unconditional 0 taken 1 -: 875: } -: 876: -: 877: /* 3) Construct and run the corresponding commands -: 878: * ############################################### */ -: 879: 2: 880: switch (sel_op) { 2: 880-block 0 branch 0 taken 1 branch 1 taken 0 branch 2 taken 1 branch 3 taken 0 branch 4 taken 0 branch 5 taken 0 1: 881: case 'e': { /* ########## EXTRACT ############## */ 1: 882: char *cmd = (char *)NULL; 1: 883: cmd = (char *)xnmalloc(strlen(dec_files) + 13, sizeof(char)); 1: 883-block 0 call 0 returned 1 1: 884: sprintf(cmd, "atool -x -e %s", dec_files); 1: 885: if (launch_execle(cmd) != EXIT_SUCCESS) call 0 returned 1 branch 1 taken 0 (fallthrough) branch 2 taken 1 #####: 886: exit_status = EXIT_FAILURE; %%%%%: 886-block 0 unconditional 0 never executed -: 887: 1: 888: free(cmd); 1: 889: free(dec_files); 1: 890: } break; 1: 890-block 0 unconditional 0 taken 1 -: 891: #####: 892: case 'E': /* ########## EXTRACT TO DIR ############## */ #####: 893: for (i = 1; args[i]; i++) { %%%%%: 893-block 0 unconditional 0 never executed %%%%%: 893-block 1 branch 1 never executed branch 2 never executed -: 894: /* Ask for extraction path */ #####: 895: printf(_("%sFile%s: %s\n"), BOLD, df_c, args[i]); %%%%%: 895-block 0 call 0 never executed call 1 never executed -: 896: #####: 897: char *ext_path = (char *)NULL; #####: 898: while (!ext_path) { unconditional 0 never executed %%%%%: 898-block 0 branch 1 never executed branch 2 never executed #####: 899: ext_path = rl_no_hist(_("Extraction path: ")); %%%%%: 899-block 0 call 0 never executed call 1 never executed #####: 900: if (!ext_path) branch 0 never executed branch 1 never executed #####: 901: continue; %%%%%: 901-block 0 unconditional 0 never executed #####: 902: if (!*ext_path) { %%%%%: 902-block 0 branch 0 never executed branch 1 never executed #####: 903: free(ext_path); #####: 904: ext_path = (char *)NULL; #####: 905: continue; %%%%%: 905-block 0 unconditional 0 never executed -: 906: } -: 907: } -: 908: -: 909: /* Construct and execute cmd */ #####: 910: char *cmd[] = {"atool", "-X", ext_path, args[i], NULL}; #####: 911: if (launch_execve(cmd, FOREGROUND, E_NOFLAG) != EXIT_SUCCESS) %%%%%: 911-block 0 call 0 never executed branch 1 never executed branch 2 never executed #####: 912: exit_status = EXIT_FAILURE; %%%%%: 912-block 0 unconditional 0 never executed -: 913: #####: 914: free(ext_path); #####: 915: ext_path = (char *)NULL; %%%%%: 915-block 0 unconditional 0 never executed -: 916: } #####: 917: break; %%%%%: 917-block 0 unconditional 0 never executed -: 918: -: 919: /* ########## LIST ############## */ -: 920: 1: 921: case 'l': 2: 922: for (i = 1; args[i]; i++) { 1: 922-block 0 unconditional 0 taken 1 1: 922-block 1 unconditional 1 taken 1 2: 922-block 2 branch 2 taken 1 branch 3 taken 1 (fallthrough) 1*: 923: printf(_("%s%sFile%s: %s\n"), (i > 1) ? "\n" : "", %%%%%: 923-block 0 unconditional 0 never executed 1: 923-block 1 unconditional 1 taken 1 1: 923-block 2 call 2 returned 1 call 3 returned 1 1: 924: BOLD, df_c, args[i]); 1: 924-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 1 -: 925: 1: 926: char *cmd[] = {"atool", "-l", args[i], NULL}; 1: 927: if (launch_execve(cmd, FOREGROUND, E_NOFLAG) != EXIT_SUCCESS) call 0 returned 1 branch 1 taken 0 (fallthrough) branch 2 taken 1 #####: 928: exit_status = EXIT_FAILURE; %%%%%: 928-block 0 unconditional 0 never executed -: 929: } 1: 930: break; 1: 930-block 0 unconditional 0 taken 1 -: 931: -: 932: /* ########## MOUNT ############## */ -: 933: #####: 934: case 'm': #####: 935: for (i = 1; args[i]; i++) { %%%%%: 935-block 0 unconditional 0 never executed %%%%%: 935-block 1 unconditional 1 never executed %%%%%: 935-block 2 branch 2 never executed branch 3 never executed -: 936: /* Create mountpoint */ #####: 937: char *mountpoint = (char *)NULL; #####: 938: if (xargs.stealth_mode == 1) { %%%%%: 938-block 0 branch 0 never executed branch 1 never executed #####: 939: mountpoint = (char *)xnmalloc(strlen(args[i]) + 19, %%%%%: 939-block 0 call 0 never executed -: 940: sizeof(char)); #####: 941: sprintf(mountpoint, "/tmp/clifm-mounts/%s", #####: 942: args[i]); unconditional 0 never executed -: 943: } else { #####: 944: mountpoint = (char *)xnmalloc(strlen(config_dir) + strlen(args[i]) + 9, sizeof(char)); %%%%%: 944-block 0 call 0 never executed #####: 945: sprintf(mountpoint, "%s/mounts/%s", config_dir, args[i]); unconditional 0 never executed -: 946: } -: 947: #####: 948: char *dir_cmd[] = {"mkdir", "-pm700", mountpoint, NULL}; #####: 949: if (launch_execve(dir_cmd, FOREGROUND, E_NOFLAG) != EXIT_SUCCESS) { %%%%%: 949-block 0 call 0 never executed branch 1 never executed branch 2 never executed #####: 950: free(mountpoint); #####: 951: return EXIT_FAILURE; %%%%%: 951-block 0 unconditional 0 never executed %%%%%: 951-block 1 unconditional 1 never executed -: 952: } -: 953: -: 954: /* Construct and execute cmd */ #####: 955: char *cmd[] = {"archivemount", args[i], mountpoint, NULL}; #####: 956: if (launch_execve(cmd, FOREGROUND, E_NOFLAG) != EXIT_SUCCESS) { %%%%%: 956-block 0 call 0 never executed branch 1 never executed branch 2 never executed #####: 957: free(mountpoint); #####: 958: continue; %%%%%: 958-block 0 unconditional 0 never executed %%%%%: 958-block 1 unconditional 1 never executed -: 959: } -: 960: -: 961: /* List content of mountpoint if there is only -: 962: * one archive */ #####: 963: if (files_num > 1) { %%%%%: 963-block 0 branch 0 never executed branch 1 never executed #####: 964: printf(_("%s%s%s: Succesfully mounted on %s\n"), call 0 never executed #####: 965: BOLD, args[i], df_c, mountpoint); %%%%%: 965-block 0 call 0 never executed #####: 966: free(mountpoint); #####: 967: continue; unconditional 0 never executed -: 968: } -: 969: #####: 970: if (xchdir(mountpoint, SET_TITLE) == -1) { %%%%%: 970-block 0 call 0 never executed branch 1 never executed branch 2 never executed #####: 971: fprintf(stderr, "archiver: %s: %s\n", mountpoint, strerror(errno)); %%%%%: 971-block 0 call 0 never executed call 1 never executed #####: 972: free(mountpoint); #####: 973: return EXIT_FAILURE; unconditional 0 never executed -: 974: } -: 975: #####: 976: free(ws[cur_ws].path); #####: 977: ws[cur_ws].path = (char *)xcalloc(strlen(mountpoint) + 1, %%%%%: 977-block 0 call 0 never executed -: 978: sizeof(char)); #####: 979: strcpy(ws[cur_ws].path, mountpoint); #####: 980: free(mountpoint); -: 981: #####: 982: add_to_jumpdb(ws[cur_ws].path); call 0 never executed -: 983: #####: 984: if (cd_lists_on_the_fly) { branch 0 never executed branch 1 never executed #####: 985: free_dirlist(); %%%%%: 985-block 0 call 0 never executed #####: 986: if (list_dir() != EXIT_SUCCESS) call 0 never executed branch 1 never executed branch 2 never executed #####: 987: exit_status = EXIT_FAILURE; %%%%%: 987-block 0 unconditional 0 never executed #####: 988: add_to_dirhist(ws[cur_ws].path); %%%%%: 988-block 0 call 0 never executed unconditional 1 never executed -: 989: } -: 990: } #####: 991: break; %%%%%: 991-block 0 unconditional 0 never executed -: 992: -: 993: /* ########## REPACK ############## */ -: 994: #####: 995: case 'r': { -: 996: /* Ask for new archive/compression format */ #####: 997: puts(_("Enter 'q' to quit")); %%%%%: 997-block 0 call 0 never executed call 1 never executed -: 998: #####: 999: char *format = (char *)NULL; #####: 1000: while (!format) { unconditional 0 never executed %%%%%: 1000-block 0 branch 1 never executed branch 2 never executed #####: 1001: format = rl_no_hist(_("New format (Ex: .tar.xz): ")); %%%%%: 1001-block 0 call 0 never executed call 1 never executed #####: 1002: if (!format) branch 0 never executed branch 1 never executed #####: 1003: continue; %%%%%: 1003-block 0 unconditional 0 never executed #####: 1004: if (!*format || (*format != '.' && *format != 'q')) { %%%%%: 1004-block 0 branch 0 never executed branch 1 never executed %%%%%: 1004-block 1 branch 2 never executed branch 3 never executed %%%%%: 1004-block 2 branch 4 never executed branch 5 never executed #####: 1005: free(format); #####: 1006: format = (char *)NULL; #####: 1007: continue; %%%%%: 1007-block 0 unconditional 0 never executed -: 1008: } #####: 1009: if (*format == 'q' && format[1] == '\0') { %%%%%: 1009-block 0 branch 0 never executed branch 1 never executed %%%%%: 1009-block 1 branch 2 never executed branch 3 never executed #####: 1010: free(format); #####: 1011: free(dec_files); #####: 1012: return EXIT_SUCCESS; %%%%%: 1012-block 0 unconditional 0 never executed -: 1013: } -: 1014: } -: 1015: -: 1016: /* Construct and execute cmd */ #####: 1017: char *cmd = (char *)NULL; #####: 1018: cmd = (char *)xnmalloc(strlen(format) + strlen(dec_files) + 16, sizeof(char)); %%%%%: 1018-block 0 call 0 never executed #####: 1019: sprintf(cmd, "arepack -F %s -e %s", format, dec_files); -: 1020: #####: 1021: if (launch_execle(cmd) != EXIT_SUCCESS) call 0 never executed branch 1 never executed branch 2 never executed #####: 1022: exit_status = EXIT_FAILURE; %%%%%: 1022-block 0 unconditional 0 never executed -: 1023: #####: 1024: free(format); #####: 1025: free(dec_files); #####: 1026: free(cmd); #####: 1027: } break; %%%%%: 1027-block 0 unconditional 0 never executed -: 1028: } -: 1029: 2: 1030: return exit_status; 2: 1030-block 0 unconditional 0 taken 2 -: 1031:} -: 1032: -: 1033:/* If MODE is 'c', compress IN_FILE producing a zstandard compressed -: 1034: * file named OUT_FILE. If MODE is 'd', extract, test or get -: 1035: * information about IN_FILE. OP is used only for the 'd' mode: it -: 1036: * tells if we have one or multiple file. Returns zero on success and -: 1037: * one on error */ -: 1038:int function zstandard called 0 returned 0% blocks executed 0% #####: 1039:zstandard(char *in_file, char *out_file, char mode, char op) -: 1040:{ #####: 1041: int exit_status = EXIT_SUCCESS; #####: 1042: char *deq_file = dequote_str(in_file, 0); %%%%%: 1042-block 0 call 0 never executed #####: 1043: if (!deq_file) { branch 0 never executed branch 1 never executed #####: 1044: fprintf(stderr, _("archiver: %s: Error dequoting file name\n"), in_file); %%%%%: 1044-block 0 call 0 never executed call 1 never executed #####: 1045: return EXIT_FAILURE; unconditional 0 never executed -: 1046: } -: 1047: #####: 1048: if (mode == 'c') { %%%%%: 1048-block 0 branch 0 never executed branch 1 never executed #####: 1049: if (out_file) { %%%%%: 1049-block 0 branch 0 never executed branch 1 never executed #####: 1050: char *cmd[] = {"zstd", "-zo", out_file, deq_file, NULL}; #####: 1051: if (launch_execve(cmd, FOREGROUND, E_NOFLAG) != EXIT_SUCCESS) %%%%%: 1051-block 0 call 0 never executed branch 1 never executed branch 2 never executed #####: 1052: exit_status = EXIT_FAILURE; %%%%%: 1052-block 0 unconditional 0 never executed -: 1053: } else { #####: 1054: char *cmd[] = {"zstd", "-z", deq_file, NULL}; -: 1055: #####: 1056: if (launch_execve(cmd, FOREGROUND, E_NOFLAG) != EXIT_SUCCESS) %%%%%: 1056-block 0 call 0 never executed branch 1 never executed branch 2 never executed #####: 1057: exit_status = EXIT_FAILURE; %%%%%: 1057-block 0 unconditional 0 never executed -: 1058: } -: 1059: #####: 1060: free(deq_file); #####: 1061: return exit_status; %%%%%: 1061-block 0 unconditional 0 never executed -: 1062: } -: 1063: -: 1064: /* mode == 'd' */ -: 1065: -: 1066: /* op is non-zero when multiple files, including at least one -: 1067: * zst file, are passed to the archiver function */ #####: 1068: if (op != 0) { %%%%%: 1068-block 0 branch 0 never executed branch 1 never executed #####: 1069: char option[3] = ""; -: 1070: #####: 1071: switch (op) { %%%%%: 1071-block 0 branch 0 never executed branch 1 never executed branch 2 never executed branch 3 never executed #####: 1072: case 'e': strcpy(option, "-d"); break; %%%%%: 1072-block 0 unconditional 0 never executed #####: 1073: case 't': strcpy(option, "-t"); break; %%%%%: 1073-block 0 unconditional 0 never executed #####: 1074: case 'i': strcpy(option, "-l"); break; %%%%%: 1074-block 0 unconditional 0 never executed -: 1075: } -: 1076: #####: 1077: char *cmd[] = {"zstd", option, deq_file, NULL}; #####: 1078: exit_status = launch_execve(cmd, FOREGROUND, E_NOFLAG); %%%%%: 1078-block 0 call 0 never executed #####: 1079: free(deq_file); -: 1080: #####: 1081: if (exit_status != EXIT_SUCCESS) branch 0 never executed branch 1 never executed #####: 1082: return EXIT_FAILURE; %%%%%: 1082-block 0 unconditional 0 never executed -: 1083: #####: 1084: return EXIT_SUCCESS; %%%%%: 1084-block 0 unconditional 0 never executed -: 1085: } -: 1086: #####: 1087: printf(_("%s[e]%sxtract %s[t]%sest %s[i]%snfo %s[q]%suit\n"), %%%%%: 1087-block 0 call 0 never executed call 1 never executed -: 1088: BOLD, df_c, BOLD, df_c, BOLD, df_c, BOLD, df_c); -: 1089: #####: 1090: char *operation = (char *)NULL; #####: 1091: while (!operation) { unconditional 0 never executed %%%%%: 1091-block 0 branch 1 never executed branch 2 never executed #####: 1092: operation = rl_no_hist(_("Operation: ")); %%%%%: 1092-block 0 call 0 never executed call 1 never executed #####: 1093: if (!operation) branch 0 never executed branch 1 never executed #####: 1094: continue; %%%%%: 1094-block 0 unconditional 0 never executed #####: 1095: if (!*operation || operation[1] != '\0') { %%%%%: 1095-block 0 branch 0 never executed branch 1 never executed %%%%%: 1095-block 1 branch 2 never executed branch 3 never executed #####: 1096: free(operation); #####: 1097: operation = (char *)NULL; #####: 1098: continue; %%%%%: 1098-block 0 unconditional 0 never executed -: 1099: } -: 1100: #####: 1101: switch (*operation) { %%%%%: 1101-block 0 branch 0 never executed branch 1 never executed branch 2 never executed branch 3 never executed branch 4 never executed #####: 1102: case 'e': { #####: 1103: char *cmd[] = {"zstd", "-d", deq_file, NULL}; #####: 1104: if (launch_execve(cmd, FOREGROUND, E_NOFLAG) != EXIT_SUCCESS) %%%%%: 1104-block 0 call 0 never executed branch 1 never executed branch 2 never executed #####: 1105: exit_status = EXIT_FAILURE; %%%%%: 1105-block 0 unconditional 0 never executed #####: 1106: } break; %%%%%: 1106-block 0 unconditional 0 never executed -: 1107: #####: 1108: case 't': { #####: 1109: char *cmd[] = {"zstd", "-t", deq_file, NULL}; #####: 1110: if (launch_execve(cmd, FOREGROUND, E_NOFLAG) != EXIT_SUCCESS) %%%%%: 1110-block 0 call 0 never executed branch 1 never executed branch 2 never executed #####: 1111: exit_status = EXIT_FAILURE; %%%%%: 1111-block 0 unconditional 0 never executed #####: 1112: } break; %%%%%: 1112-block 0 unconditional 0 never executed -: 1113: #####: 1114: case 'i': { #####: 1115: char *cmd[] = {"zstd", "-l", deq_file, NULL}; #####: 1116: if (launch_execve(cmd, FOREGROUND, E_NOFLAG) != EXIT_SUCCESS) %%%%%: 1116-block 0 call 0 never executed branch 1 never executed branch 2 never executed #####: 1117: exit_status = EXIT_FAILURE; %%%%%: 1117-block 0 unconditional 0 never executed #####: 1118: } break; %%%%%: 1118-block 0 unconditional 0 never executed -: 1119: #####: 1120: case 'q': #####: 1121: free(operation); #####: 1122: free(deq_file); #####: 1123: return EXIT_SUCCESS; %%%%%: 1123-block 0 unconditional 0 never executed -: 1124: #####: 1125: default: #####: 1126: free(operation); #####: 1127: operation = (char *)NULL; #####: 1128: break; %%%%%: 1128-block 0 unconditional 0 never executed -: 1129: } -: 1130: } -: 1131: #####: 1132: free(operation); #####: 1133: free(deq_file); #####: 1134: return exit_status; %%%%%: 1134-block 0 unconditional 0 never executed -: 1135:} -: 1136:#endif /* !_NO_ARCHIVING */ -: 1137: clifm-1.26.3/misc/codecov/aux.c.gcov000066400000000000000000000727061506632037700171750ustar00rootroot00000000000000 -: 0:Source:aux.c -: 1:/* aux.c -- functions that do not fit in any other file */ -: 2: -: 3:/* -: 4: * This file is part of CliFM -: 5: * -: 6: * Copyright (C) 2016-2021, L. Abramovich -: 7: * All rights reserved. -: 8: -: 9: * CliFM is free software; you can redistribute it and/or modify -: 10: * it under the terms of the GNU General Public License as published by -: 11: * the Free Software Foundation; either version 2 of the License, or -: 12: * (at your option) any later version. -: 13: * -: 14: * CliFM is distributed in the hope that it will be useful, -: 15: * but WITHOUT ANY WARRANTY; without even the implied warranty of -: 16: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -: 17: * GNU General Public License for more details. -: 18: * -: 19: * You should have received a copy of the GNU General Public License -: 20: * along with this program; if not, write to the Free Software -: 21: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, -: 22: * MA 02110-1301, USA. -: 23: */ -: 24: -: 25:#include "helpers.h" -: 26: -: 27:#include -: 28:#include -: 29:#include -: 30:#include -: 31:#include -: 32:#include -: 33:#include -: 34:#include -: 35:#include -: 36:#include -: 37: -: 38:#include "aux.h" -: 39:#include "exec.h" -: 40:#include "misc.h" -: 41: -: 42:/* Open a file for read only. Return a file stream associated to a file -: 43: * descriptor (FD) for the file named NAME */ -: 44:FILE * function open_fstream_r called 739 returned 100% blocks executed 75% 739: 45:open_fstream_r(char *name, int *fd) -: 46:{ 739: 47: if (!name || !*name) 739: 47-block 0 branch 0 taken 739 (fallthrough) branch 1 taken 0 739: 47-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 739 #####: 48: return (FILE *)NULL; %%%%%: 48-block 0 unconditional 0 never executed -: 49: 739: 50: *fd = open(name, O_RDONLY); 739: 50-block 0 call 0 returned 739 739: 51: if (*fd == -1) branch 0 taken 469 (fallthrough) branch 1 taken 270 469: 52: return (FILE *)NULL; 469: 52-block 0 unconditional 0 taken 469 -: 53: 270: 54: FILE *fp = fdopen(*fd, "r"); 270: 54-block 0 call 0 returned 270 270: 55: if (!fp) { branch 0 taken 0 (fallthrough) branch 1 taken 270 #####: 56: close(*fd); %%%%%: 56-block 0 call 0 never executed #####: 57: return (FILE *)NULL; unconditional 0 never executed -: 58: } -: 59: 270: 60: return fp; 270: 60-block 0 unconditional 0 taken 270 -: 61:} -: 62: -: 63:/* Create a file for writing. Return a file stream associated to a file -: 64: * descriptor (FD) for the file named NAME */ -: 65:FILE * function open_fstream_w called 9 returned 100% blocks executed 67% 9: 66:open_fstream_w(char *name, int *fd) -: 67:{ 9: 68: if (!name || !*name) 9: 68-block 0 branch 0 taken 9 (fallthrough) branch 1 taken 0 9: 68-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 9 #####: 69: return (FILE *)NULL; %%%%%: 69-block 0 unconditional 0 never executed -: 70: 9: 71: *fd = open(name, O_WRONLY | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR); 9: 71-block 0 call 0 returned 9 9: 72: if (*fd == -1) branch 0 taken 0 (fallthrough) branch 1 taken 9 #####: 73: return (FILE *)NULL; %%%%%: 73-block 0 unconditional 0 never executed -: 74: 9: 75: FILE *fp = fdopen(*fd, "w"); 9: 75-block 0 call 0 returned 9 9: 76: if (!fp) { branch 0 taken 0 (fallthrough) branch 1 taken 9 #####: 77: close(*fd); %%%%%: 77-block 0 call 0 never executed #####: 78: return (FILE *)NULL; unconditional 0 never executed -: 79: } -: 80: 9: 81: return fp; 9: 81-block 0 unconditional 0 taken 9 -: 82:} -: 83: -: 84:/* Close file stream FP and file descriptor FD */ -: 85:void function close_fstream called 279 returned 100% blocks executed 100% 279: 86:close_fstream(FILE *fp, int fd) -: 87:{ 279: 88: fclose(fp); 279: 88-block 0 call 0 returned 279 279: 89: close(fd); call 0 returned 279 279: 90:} -: 91: -: 92:/* -: 93:static int -: 94:hex2int(char *str) -: 95:{ -: 96: int i, n[2] = { 0 }; -: 97: for (i = 1; i >= 0; i--) { -: 98: if (str[i] >= '0' && str[i] <= '9') { -: 99: n[i] = str[i] - '0'; -: 100: } else { -: 101: switch (str[i]) { -: 102: case 'A': -: 103: case 'a': -: 104: n[i] = 10; -: 105: break; -: 106: case 'B': -: 107: case 'b': -: 108: n[i] = 11; -: 109: break; -: 110: case 'C': -: 111: case 'c': -: 112: n[i] = 12; -: 113: break; -: 114: case 'D': -: 115: case 'd': -: 116: n[i] = 13; -: 117: break; -: 118: case 'E': -: 119: case 'e': -: 120: n[i] = 14; -: 121: break; -: 122: case 'F': -: 123: case 'f': -: 124: n[i] = 15; -: 125: break; -: 126: default: -: 127: break; -: 128: } -: 129: } -: 130: } -: 131: -: 132: return ((n[0] * 16) + n[1]); -: 133:} */ -: 134: -: 135:/* Given this value: \xA0\xA1\xA2, return an array of integers with -: 136: * the integer values for A0, A1, and A2 respectivelly */ -: 137:/*int * -: 138:get_hex_num(const char *str) -: 139:{ -: 140: size_t i = 0; -: 141: int *hex_n = (int *)xnmalloc(3, sizeof(int)); -: 142: -: 143: while (*str) { -: 144: if (*str != '\\') { -: 145: str++; -: 146: continue; -: 147: } -: 148: -: 149: if (*(str + 1) != 'x') -: 150: break; -: 151: -: 152: str += 2; -: 153: char *tmp = xnmalloc(3, sizeof(char)); -: 154: xstrsncpy(tmp, str, 2); -: 155: -: 156: if (i >= 3) -: 157: hex_n = xrealloc(hex_n, (i + 1) * sizeof(int *)); -: 158: -: 159: hex_n[i++] = hex2int(tmp); -: 160: -: 161: free(tmp); -: 162: tmp = (char *)NULL; -: 163: str++; -: 164: } -: 165: -: 166: hex_n = xrealloc(hex_n, (i + 1) * sizeof(int)); -: 167: hex_n[i] = -1; // -1 marks the end of the int array -: 168: -: 169: return hex_n; -: 170:} */ -: 171: -: 172:/* Count files in DIR_PATH, including self and parent. If POP is set to 1, -: 173: * The function will just check if the directory is populated (it has at -: 174: * least 3 files, including self and parent)*/ -: 175:int function count_dir called 3453 returned 100% blocks executed 88% 3453: 176:count_dir(const char *dir, int pop) -: 177:{ 3453: 178: if (!dir) 3453: 178-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 3453 #####: 179: return -1; %%%%%: 179-block 0 unconditional 0 never executed -: 180: -: 181: DIR *p; 3453: 182: if ((p = opendir(dir)) == NULL) { 3453: 182-block 0 call 0 returned 3453 branch 1 taken 10 (fallthrough) branch 2 taken 3443 10: 183: if (errno == ENOMEM) 10: 183-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 10 #####: 184: exit(EXIT_FAILURE); %%%%%: 184-block 0 call 0 never executed -: 185: else 10: 186: return -1; 10: 186-block 0 unconditional 0 taken 10 -: 187: } -: 188: 3443: 189: int c = 0; -: 190:// struct dirent *ent; -: 191: 185318: 192: while (readdir(p)) { 3443: 192-block 0 unconditional 0 taken 3443 185318: 192-block 1 call 1 returned 185318 branch 2 taken 181876 branch 3 taken 3442 (fallthrough) 181876: 193: c++; 181876: 194: if (pop && c > 2) 181876: 194-block 0 branch 0 taken 81 (fallthrough) branch 1 taken 181795 81: 194-block 1 branch 2 taken 1 (fallthrough) branch 3 taken 80 1: 195: break; 1: 195-block 0 unconditional 0 taken 1 -: 196: } -: 197: 3443: 198: closedir(p); 3443: 198-block 0 call 0 returned 3443 3443: 199: return c; unconditional 0 taken 3443 -: 200:} -: 201: -: 202:/* Get the path of a given command from the PATH environment variable. -: 203: * It basically does the same as the 'which' Unix command */ -: 204:char * function get_cmd_path called 44 returned 100% blocks executed 89% 44: 205:get_cmd_path(const char *cmd) -: 206:{ 44: 207: char *cmd_path = (char *)NULL; -: 208: size_t i; -: 209: 44: 210: cmd_path = (char *)xnmalloc(PATH_MAX + 1, sizeof(char)); 44: 210-block 0 call 0 returned 44 -: 211: 132: 212: for (i = 0; i < path_n; i++) { /* Get each path from PATH */ unconditional 0 taken 44 88: 212-block 0 unconditional 1 taken 88 132: 212-block 1 branch 2 taken 132 branch 3 taken 0 (fallthrough) -: 213: /* Append cmd to each path and check if it exists and is -: 214: * executable */ 132: 215: snprintf(cmd_path, PATH_MAX, "%s/%s", paths[i], cmd); -: 216: 132: 217: if (access(cmd_path, X_OK) == 0) 132: 217-block 0 call 0 returned 132 branch 1 taken 44 (fallthrough) branch 2 taken 88 44: 218: return cmd_path; 44: 218-block 0 unconditional 0 taken 44 -: 219: } -: 220: #####: 221: free(cmd_path); #####: 222: return (char *)NULL; %%%%%: 222-block 0 unconditional 0 never executed -: 223:} -: 224: -: 225:/* Convert FILE_SIZE to human readeable form */ -: 226:char * function get_size_unit called 236 returned 100% blocks executed 100% 236: 227:get_size_unit(off_t size) -: 228:{ -: 229:#define MAX_UNIT_SIZE 9 -: 230: /* Max size type length == 9 == "1023.99K\0" */ 236: 231: char *str = xnmalloc(MAX_UNIT_SIZE, sizeof(char)); 236: 231-block 0 call 0 returned 236 -: 232: 236: 233: size_t n = 0; 236: 234: float s = (float)size; -: 235: 408: 236: while (s > 1024) { unconditional 0 taken 236 408: 236-block 0 branch 1 taken 172 branch 2 taken 236 (fallthrough) 172: 237: s = s / 1024; 172: 238: ++n; 172: 238-block 0 unconditional 0 taken 172 -: 239: } -: 240: 236: 241: int x = (int)s; -: 242: /* If s - x == 0, then S has no reminder (zero) -: 243: * We don't want to print the reminder when it is zero */ -: 244: 236: 245: const char *const u = "BKMGTPEZY"; 236: 246: snprintf(str, MAX_UNIT_SIZE, "%.*f%c", (s == 0 || s - (float)x == 0) 218: 246-block 0 branch 0 taken 154 (fallthrough) branch 1 taken 64 172: 246-block 1 unconditional 2 taken 172 64: 246-block 2 unconditional 3 taken 64 236: 247: ? 0 : 2, (double)s, u[n]); 236: 247-block 0 branch 0 taken 218 (fallthrough) branch 1 taken 18 -: 248: 236: 249: return str; 236: 249-block 0 unconditional 0 taken 236 -: 250:} -: 251: -: 252:off_t function dir_size called 1 returned 100% blocks executed 82% 1: 253:dir_size(char *dir) -: 254:{ 1: 255: if (!dir) 1: 255-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 1 #####: 256: return -1; %%%%%: 256-block 0 unconditional 0 never executed -: 257: 1: 258: char *rand_ext = gen_rand_str(6); 1: 258-block 0 call 0 returned 1 1: 259: if (!rand_ext) branch 0 taken 0 (fallthrough) branch 1 taken 1 #####: 260: return -1; %%%%%: 260-block 0 unconditional 0 never executed -: 261: -: 262: char file[15]; 1: 263: sprintf(file, "/tmp/du.%s", rand_ext); 1: 264: free(rand_ext); -: 265: -: 266: int fd; 1: 267: FILE *fp = open_fstream_w(file, &fd); 1: 267-block 0 call 0 returned 1 1: 268: if (!fp) branch 0 taken 0 (fallthrough) branch 1 taken 1 #####: 269: return -1; %%%%%: 269-block 0 unconditional 0 never executed -: 270: 1: 271: int stdout_bk = dup(STDOUT_FILENO); /* Save original stdout */ 1: 271-block 0 call 0 returned 1 1: 272: dup2(fileno(fp), STDOUT_FILENO); /* Redirect stdout to the desired call 0 returned 1 call 1 returned 1 -: 273: file */ 1: 274: close_fstream(fp, fd); call 0 returned 1 -: 275: 1: 276: char *cmd[] = {"du", "-ks", dir, NULL}; 1: 277: launch_execve(cmd, FOREGROUND, E_NOSTDERR); call 0 returned 1 -: 278: 1: 279: dup2(stdout_bk, STDOUT_FILENO); /* Restore original stdout */ call 0 returned 1 1: 280: close(stdout_bk); call 0 returned 1 -: 281: 1: 282: off_t retval = -1; -: 283: 1: 284: if (access(file, F_OK) == 0) { call 0 returned 1 branch 1 taken 1 (fallthrough) branch 2 taken 0 1: 285: fp = open_fstream_r(file, &fd); 1: 285-block 0 call 0 returned 1 1: 286: if (fp) { branch 0 taken 1 (fallthrough) branch 1 taken 0 -: 287: /* I only need here the first field of the line, which is a -: 288: * file size and could only take a few bytes, so that 32 -: 289: * bytes is more than enough */ 1: 290: char line[32] = ""; 1: 291: if (fgets(line, (int)sizeof(line), fp) == NULL) { 1: 291-block 0 call 0 returned 1 branch 1 taken 0 (fallthrough) branch 2 taken 1 #####: 292: close_fstream(fp, fd); %%%%%: 292-block 0 call 0 never executed #####: 293: unlink(file); call 0 never executed #####: 294: return -1; unconditional 0 never executed -: 295: } -: 296: 1: 297: char *file_size = strbfr(line, '\t'); 1: 297-block 0 call 0 returned 1 1: 298: if (file_size) { branch 0 taken 1 (fallthrough) branch 1 taken 0 1: 299: retval = (off_t)atoll(file_size); 1: 300: free(file_size); 1: 300-block 0 unconditional 0 taken 1 -: 301: } -: 302: 1: 303: close_fstream(fp, fd); 1: 303-block 0 call 0 returned 1 -: 304: } -: 305: 1: 306: unlink(file); 1: 306-block 0 call 0 returned 1 unconditional 1 taken 1 -: 307: } -: 308: 1: 309: return retval; 1: 309-block 0 unconditional 0 taken 1 -: 310:} -: 311: -: 312:/* Return the file type of the file pointed to by LINK, or -1 in case of -: 313: * error. Possible return values: -: 314:S_IFDIR: 40000 (octal) / 16384 (decimal, integer) -: 315:S_IFREG: 100000 / 32768 -: 316:S_IFLNK: 120000 / 40960 -: 317:S_IFSOCK: 140000 / 49152 -: 318:S_IFBLK: 60000 / 24576 -: 319:S_IFCHR: 20000 / 8192 -: 320:S_IFIFO: 10000 / 4096 -: 321: * See the inode manpage */ -: 322:int function get_link_ref called 0 returned 0% blocks executed 0% #####: 323:get_link_ref(const char *link) -: 324:{ #####: 325: if (!link) %%%%%: 325-block 0 branch 0 never executed branch 1 never executed #####: 326: return (-1); %%%%%: 326-block 0 unconditional 0 never executed -: 327: #####: 328: char *linkname = realpath(link, (char *)NULL); %%%%%: 328-block 0 call 0 never executed #####: 329: if (linkname) { branch 0 never executed branch 1 never executed -: 330: struct stat file_attrib; #####: 331: stat(linkname, &file_attrib); %%%%%: 331-block 0 call 0 never executed #####: 332: free(linkname); #####: 333: return (int)(file_attrib.st_mode & S_IFMT); unconditional 0 never executed -: 334: } -: 335: #####: 336: return (-1); %%%%%: 336-block 0 unconditional 0 never executed -: 337:} -: 338: -: 339:/* Transform an integer (N) into a string of chars -: 340: * This exists because some Operating systems do not support itoa */ -: 341:char * function xitoa called 2540 returned 100% blocks executed 88% 2540: 342:xitoa(int n) -: 343:{ 2540: 344: if (!n) 2540: 344-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 2540 #####: 345: return "0"; %%%%%: 345-block 0 unconditional 0 never executed -: 346: -: 347: static char buf[32] = {0}; 2540: 348: int i = 30; -: 349: 5980: 350: while (n && i) { 2540: 350-block 0 unconditional 0 taken 2540 5980: 350-block 1 branch 1 taken 3440 (fallthrough) branch 2 taken 2540 3440: 350-block 2 branch 3 taken 3440 branch 4 taken 0 (fallthrough) 3440: 351: int rem = n / 10; 3440: 352: buf[i] = (char)('0' + (n - (rem * 10))); 3440: 353: n = rem; 3440: 354: --i; 3440: 354-block 0 unconditional 0 taken 3440 -: 355: } -: 356: 2540: 357: return &buf[++i]; 2540: 357-block 0 unconditional 0 taken 2540 -: 358:} -: 359: -: 360:/* Some memory wrapper functions */ -: 361:void * function xrealloc called 84449 returned 100% blocks executed 50% 84449: 362:xrealloc(void *ptr, size_t size) -: 363:{ 84449: 364: void *new_ptr = realloc(ptr, size); -: 365: 84449: 366: if (!new_ptr) { 84449: 366-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 84449 #####: 367: free(ptr); #####: 368: _err(0, NOPRINT_PROMPT, _("%s: %s failed to allocate %zu bytes\n"), %%%%%: 368-block 0 call 0 never executed call 1 never executed -: 369: PROGRAM_NAME, __func__, size); #####: 370: exit(EXIT_FAILURE); call 0 never executed -: 371: } -: 372: 84449: 373: return new_ptr; 84449: 373-block 0 unconditional 0 taken 84449 -: 374:} -: 375: -: 376:void * function xcalloc called 869 returned 100% blocks executed 50% 869: 377:xcalloc(size_t nmemb, size_t size) -: 378:{ 869: 379: void *new_ptr = calloc(nmemb, size); -: 380: 869: 381: if (!new_ptr) { 869: 381-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 869 #####: 382: _err(0, NOPRINT_PROMPT, _("%s: %s failed to allocate %zu bytes\n"), %%%%%: 382-block 0 call 0 never executed call 1 never executed -: 383: PROGRAM_NAME, __func__, nmemb * size); #####: 384: exit(EXIT_FAILURE); call 0 never executed -: 385: } -: 386: 869: 387: return new_ptr; 869: 387-block 0 unconditional 0 taken 869 -: 388:} -: 389: -: 390:void * function xnmalloc called 67076 returned 100% blocks executed 50% 67076: 391:xnmalloc(size_t nmemb, size_t size) -: 392:{ 67076: 393: void *new_ptr = malloc(nmemb * size); -: 394: 67076: 395: if (!new_ptr) { 67076: 395-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 67076 #####: 396: _err(0, NOPRINT_PROMPT, _("%s: %s failed to allocate %zu bytes\n"), %%%%%: 396-block 0 call 0 never executed call 1 never executed -: 397: PROGRAM_NAME, __func__, nmemb * size); #####: 398: exit(EXIT_FAILURE); call 0 never executed -: 399: } -: 400: 67076: 401: return new_ptr; 67076: 401-block 0 unconditional 0 taken 67076 -: 402:} -: 403: -: 404:/* Unlike getchar this does not wait for newline('\n') -: 405:https://stackoverflow.com/questions/12710582/how-can-i-capture-a-key-stroke-immediately-in-linux -: 406:*/ -: 407:char function xgetchar called 121 returned 100% blocks executed 100% 121: 408:xgetchar(void) -: 409:{ -: 410: struct termios oldt, newt; -: 411: char ch; -: 412: 121: 413: tcgetattr(STDIN_FILENO, &oldt); 121: 413-block 0 call 0 returned 121 121: 414: newt = oldt; 121: 415: newt.c_lflag &= (tcflag_t)~(ICANON | ECHO); 121: 416: tcsetattr(STDIN_FILENO, TCSANOW, &newt); call 0 returned 121 121: 417: ch = (char)getchar(); call 0 returned 121 121: 418: tcsetattr(STDIN_FILENO, TCSANOW, &oldt); call 0 returned 121 -: 419: 121: 420: return ch; unconditional 0 taken 121 -: 421:} -: 422: -: 423:/* The following four functions (from_hex, to_hex, url_encode, and -: 424: * url_decode) were taken from "http://www.geekhideout.com/urlcode.shtml" -: 425: * and modified to comform to RFC 2395, as recommended by the -: 426: * freedesktop trash specification */ -: 427: -: 428:/* Converts a hex char to its integer value */ -: 429:char function from_hex called 0 returned 0% blocks executed 0% #####: 430:from_hex(char c) -: 431:{ #####: 432: return (char)(isdigit(c) ? c - '0' : tolower(c) - 'a' + 10); %%%%%: 432-block 0 branch 0 never executed branch 1 never executed %%%%%: 432-block 1 unconditional 2 never executed %%%%%: 432-block 2 unconditional 3 never executed %%%%%: 432-block 3 unconditional 4 never executed -: 433:} -: 434: -: 435:/* Converts an integer value to its hex form */ -: 436:char function to_hex called 0 returned 0% blocks executed 0% #####: 437:to_hex(char c) -: 438:{ -: 439: static char hex[] = "0123456789ABCDEF"; #####: 440: return hex[c & 15]; %%%%%: 440-block 0 unconditional 0 never executed -: 441:} -: 442: -: 443:/* Returns a url-encoded version of str */ -: 444:char * function url_encode called 11 returned 100% blocks executed 75% 11: 445:url_encode(char *str) -: 446:{ 11: 447: if (!str || *str == '\0') 11: 447-block 0 branch 0 taken 11 (fallthrough) branch 1 taken 0 11: 447-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 11 #####: 448: return (char *)NULL; %%%%%: 448-block 0 unconditional 0 never executed -: 449: -: 450: char *p; 11: 451: p = (char *)calloc((strlen(str) * 3) + 1, sizeof(char)); -: 452: /* The max lenght of our buffer is 3 times the length of STR plus -: 453: * 1 extra byte for the null byte terminator: each char in STR will -: 454: * be, if encoded, %XX (3 chars) */ 11: 455: if (!p) 11: 455-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 11 #####: 456: return (char *)NULL; %%%%%: 456-block 0 unconditional 0 never executed -: 457: -: 458: char *buf; 11: 459: buf = p; 11: 460: p = (char *)NULL; -: 461: -: 462: /* Copies of STR and BUF pointers to be able -: 463: * to increase and/or decrease them without loosing the original -: 464: * memory location */ -: 465: char *pstr, *pbuf; 11: 466: pstr = str; 11: 467: pbuf = buf; -: 468: 468: 469: for (; *pstr; pstr++) { 11: 469-block 0 unconditional 0 taken 11 457: 469-block 1 unconditional 1 taken 457 468: 469-block 2 branch 2 taken 457 branch 3 taken 11 (fallthrough) 457: 470: if (isalnum(*pstr) || *pstr == '-' || *pstr == '_' || *pstr == '.' 457: 470-block 0 branch 0 taken 84 (fallthrough) branch 1 taken 373 84: 470-block 1 branch 2 taken 84 (fallthrough) branch 3 taken 0 84: 470-block 2 branch 4 taken 70 (fallthrough) branch 5 taken 14 70: 470-block 3 branch 6 taken 66 (fallthrough) branch 7 taken 4 66: 471: || *pstr == '~' || *pstr == '/') { 66: 471-block 0 branch 0 taken 66 (fallthrough) branch 1 taken 0 66: 471-block 1 branch 2 taken 66 (fallthrough) branch 3 taken 0 -: 472: /* Do not encode the above chars */ 457: 473: *pbuf++ = *pstr; 457: 473-block 0 unconditional 0 taken 457 -: 474: } else { -: 475: /* Encode char to URL format. Example: space char to %20 */ #####: 476: *pbuf++ = '%'; #####: 477: *pbuf++ = to_hex(*pstr >> 4); /* Right shift operation */ %%%%%: 477-block 0 call 0 never executed #####: 478: *pbuf++ = to_hex(*pstr & 15); /* Bitwise AND operation */ call 0 never executed unconditional 1 never executed -: 479: } -: 480: } -: 481: 11: 482: return buf; 11: 482-block 0 unconditional 0 taken 11 -: 483:} -: 484: -: 485:/* Returns a url-decoded version of str */ -: 486:char * function url_decode called 10 returned 100% blocks executed 59% 10: 487:url_decode(char *str) -: 488:{ 10: 489: if (!str || str[0] == '\0') 10: 489-block 0 branch 0 taken 10 (fallthrough) branch 1 taken 0 10: 489-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 10 #####: 490: return (char *)NULL; %%%%%: 490-block 0 unconditional 0 never executed -: 491: 10: 492: char *p = (char *)NULL; 10: 493: p = (char *)calloc(strlen(str) + 1, sizeof(char)); -: 494: /* The decoded string will be at most as long as the encoded -: 495: * string */ -: 496: 10: 497: if (!p) 10: 497-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 10 #####: 498: return (char *)NULL; %%%%%: 498-block 0 unconditional 0 never executed -: 499: -: 500: char *buf; 10: 501: buf = p; 10: 502: p = (char *)NULL; -: 503: -: 504: char *pstr, *pbuf; 10: 505: pstr = str; 10: 506: pbuf = buf; 427: 507: for (; *pstr; pstr++) { 10: 507-block 0 unconditional 0 taken 10 417: 507-block 1 unconditional 1 taken 417 427: 507-block 2 branch 2 taken 417 branch 3 taken 10 (fallthrough) 417: 508: if (*pstr == '%') { 417: 508-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 417 #####: 509: if (pstr[1] && pstr[2]) { %%%%%: 509-block 0 branch 0 never executed branch 1 never executed %%%%%: 509-block 1 branch 2 never executed branch 3 never executed -: 510: /* Decode URL code. Example: %20 to space char */ -: 511: /* Left shift and bitwise OR operations */ #####: 512: *pbuf++ = (char)(from_hex(pstr[1]) << 4 | from_hex(pstr[2])); %%%%%: 512-block 0 call 0 never executed call 1 never executed #####: 513: pstr += 2; unconditional 0 never executed -: 514: } -: 515: } else { 417: 516: *pbuf++ = *pstr; 417: 516-block 0 unconditional 0 taken 417 -: 517: } -: 518: } -: 519: 10: 520: return buf; 10: 520-block 0 unconditional 0 taken 10 -: 521:} -: 522: -: 523:/* Convert octal string into integer. -: 524: * Taken from: https://www.geeksforgeeks.org/program-octal-decimal-conversion/ -: 525: * Used by decode_prompt() to make things like this work: \033[1;34m */ -: 526:int function read_octal called 0 returned 0% blocks executed 0% #####: 527:read_octal(char *str) -: 528:{ #####: 529: if (!str) %%%%%: 529-block 0 branch 0 never executed branch 1 never executed #####: 530: return -1; %%%%%: 530-block 0 unconditional 0 never executed -: 531: #####: 532: int n = atoi(str); #####: 533: int num = n; #####: 534: int dec_value = 0; -: 535: -: 536: /* Initializing base value to 1, i.e 8^0 */ #####: 537: int base = 1; -: 538: #####: 539: int temp = num; #####: 540: while (temp) { %%%%%: 540-block 0 unconditional 0 never executed %%%%%: 540-block 1 branch 1 never executed branch 2 never executed -: 541: /* Extracting last digit */ #####: 542: int last_digit = temp % 10; #####: 543: temp = temp / 10; -: 544: -: 545: /* Multiplying last digit with appropriate -: 546: * base value and adding it to dec_value */ #####: 547: dec_value += last_digit * base; #####: 548: base = base * 8; %%%%%: 548-block 0 unconditional 0 never executed -: 549: } -: 550: #####: 551: return dec_value; %%%%%: 551-block 0 unconditional 0 never executed -: 552:} clifm-1.26.3/misc/codecov/bookmarks.c.gcov000066400000000000000000001633141506632037700203640ustar00rootroot00000000000000 -: 0:Source:bookmarks.c -: 1:/* bookmarks.c -- bookmarking functions */ -: 2: -: 3:/* -: 4: * This file is part of CliFM -: 5: * -: 6: * Copyright (C) 2016-2021, L. Abramovich -: 7: * All rights reserved. -: 8: -: 9: * CliFM is free software; you can redistribute it and/or modify -: 10: * it under the terms of the GNU General Public License as published by -: 11: * the Free Software Foundation; either version 2 of the License, or -: 12: * (at your option) any later version. -: 13: * -: 14: * CliFM is distributed in the hope that it will be useful, -: 15: * but WITHOUT ANY WARRANTY; without even the implied warranty of -: 16: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -: 17: * GNU General Public License for more details. -: 18: * -: 19: * You should have received a copy of the GNU General Public License -: 20: * along with this program; if not, write to the Free Software -: 21: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, -: 22: * MA 02110-1301, USA. -: 23:*/ -: 24: -: 25:#include "helpers.h" -: 26: -: 27:#include -: 28:#include -: 29:#include -: 30:#include -: 31:#include -: 32: -: 33:#include "aux.h" -: 34:#include "bookmarks.h" -: 35:#include "checks.h" -: 36:#include "exec.h" -: 37:#include "file_operations.h" -: 38:#include "init.h" -: 39:#include "mime.h" -: 40:#include "readline.h" -: 41:#include "messages.h" -: 42: -: 43:void function free_bookmarks called 21 returned 100% blocks executed 100% 21: 44:free_bookmarks(void) -: 45:{ 21: 46: if (!bm_n) 21: 46-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 20 1: 47: return; 1: 47-block 0 unconditional 0 taken 1 -: 48: -: 49: size_t i; 336: 50: for (i = 0; i < bm_n; i++) { 20: 50-block 0 unconditional 0 taken 20 316: 50-block 1 unconditional 1 taken 316 336: 50-block 2 branch 2 taken 316 branch 3 taken 20 (fallthrough) 316: 51: if (bookmarks[i].shortcut) 316: 51-block 0 branch 0 taken 316 (fallthrough) branch 1 taken 0 316: 52: free(bookmarks[i].shortcut); 316: 52-block 0 unconditional 0 taken 316 -: 53: 316: 54: if (bookmarks[i].name) 316: 54-block 0 branch 0 taken 260 (fallthrough) branch 1 taken 56 260: 55: free(bookmarks[i].name); 260: 55-block 0 unconditional 0 taken 260 -: 56: 316: 57: if (bookmarks[i].path) 316: 57-block 0 branch 0 taken 316 (fallthrough) branch 1 taken 0 316: 58: free(bookmarks[i].path); 316: 58-block 0 unconditional 0 taken 316 -: 59: } -: 60: 20: 61: free(bookmarks); 20: 62: bookmarks = (struct bookmarks_t *)NULL; -: 63: 280: 64: for (i = 0; bookmark_names[i]; i++) 20: 64-block 0 unconditional 0 taken 20 280: 64-block 1 branch 1 taken 260 branch 2 taken 20 (fallthrough) 260: 65: free(bookmark_names[i]); 260: 65-block 0 unconditional 0 taken 260 20: 66: free(bookmark_names); 20: 67: bookmark_names = (char **)NULL; 20: 68: bm_n = 0; 20: 69: return; 20: 69-block 0 unconditional 0 taken 20 -: 70:} -: 71: -: 72:static char ** function bm_prompt called 11 returned 100% blocks executed 100% 11: 73:bm_prompt(void) -: 74:{ 11: 75: char *bm_sel = (char *)NULL; 11: 76: printf(_("%s%s\nEnter '%c' to edit your bookmarks or '%c' to quit.\n"), 11: 76-block 0 call 0 returned 11 call 1 returned 11 -: 77: NC, df_c, 'e', 'q'); -: 78: 22: 79: while (!bm_sel) unconditional 0 taken 11 22: 79-block 0 branch 1 taken 11 branch 2 taken 11 (fallthrough) 11: 80: bm_sel = rl_no_hist(_("Choose a bookmark: ")); 11: 80-block 0 call 0 returned 11 call 1 returned 11 unconditional 2 taken 11 -: 81: 11: 82: char **comm_bm = get_substr(bm_sel, ' '); 11: 82-block 0 call 0 returned 11 11: 83: free(bm_sel); 11: 84: return comm_bm; unconditional 0 taken 11 -: 85:} -: 86: -: 87:static int function bookmark_del called 3 returned 100% blocks executed 54% 3: 88:bookmark_del(char *name) -: 89:{ 3: 90: FILE *bm_fp = NULL; 3: 91: bm_fp = fopen(bm_file, "r"); 3: 91-block 0 call 0 returned 3 3: 92: if (!bm_fp) branch 0 taken 0 (fallthrough) branch 1 taken 3 #####: 93: return EXIT_FAILURE; %%%%%: 93-block 0 unconditional 0 never executed -: 94: 3: 95: size_t i = 0; -: 96: -: 97: /* Get bookmarks from file */ 3: 98: size_t line_size = 0; 3: 99: char *line = (char *)NULL, **bms = (char **)NULL; 3: 100: size_t bmn = 0; 3: 101: ssize_t line_len = 0; -: 102: 81: 103: while ((line_len = getline(&line, &line_size, bm_fp)) > 0) { 3: 103-block 0 unconditional 0 taken 3 81: 103-block 1 call 1 returned 81 branch 2 taken 78 branch 3 taken 3 (fallthrough) 78: 104: if (!line || !*line || *line == '#' || *line == '\n') 78: 104-block 0 branch 0 taken 78 (fallthrough) branch 1 taken 0 78: 104-block 1 branch 2 taken 78 (fallthrough) branch 3 taken 0 78: 104-block 2 branch 4 taken 69 (fallthrough) branch 5 taken 9 69: 104-block 3 branch 6 taken 0 (fallthrough) branch 7 taken 69 9: 105: continue; 9: 105-block 0 unconditional 0 taken 9 -: 106: 69: 107: int slash = 0; 677: 108: for (i = 0; i < (size_t)line_len; i++) { 69: 108-block 0 unconditional 0 taken 69 608: 108-block 1 unconditional 1 taken 608 677: 108-block 2 branch 2 taken 677 branch 3 taken 0 (fallthrough) 677: 109: if (line[i] == '/') { 677: 109-block 0 branch 0 taken 69 (fallthrough) branch 1 taken 608 69: 110: slash = 1; 69: 111: break; 69: 111-block 0 unconditional 0 taken 69 -: 112: } -: 113: } -: 114: 69*: 115: if (!slash) 69: 115-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 69 #####: 116: continue; %%%%%: 116-block 0 unconditional 0 never executed -: 117: 69: 118: if (line[line_len - 1] == '\n') 69: 118-block 0 branch 0 taken 69 (fallthrough) branch 1 taken 0 69: 119: line[line_len - 1] = '\0'; 69: 119-block 0 unconditional 0 taken 69 -: 120: 69: 121: bms = (char **)xrealloc(bms, (bmn + 1) * sizeof(char *)); 69: 121-block 0 call 0 returned 69 69: 122: bms[bmn++] = savestring(line, (size_t)line_len); call 0 returned 69 unconditional 1 taken 69 -: 123: } -: 124: 3: 125: free(line); 3: 126: line = (char *)NULL; -: 127: 3: 128: if (!bmn) { 3: 128-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 3 #####: 129: puts(_("bookmarks: There are no bookmarks")); %%%%%: 129-block 0 call 0 never executed call 1 never executed #####: 130: fclose(bm_fp); call 0 never executed #####: 131: return EXIT_SUCCESS; unconditional 0 never executed -: 132: } -: 133: 3: 134: char **del_elements = (char **)NULL; 3: 135: int cmd_line = -1; -: 136: /* This variable let us know two things: a) bookmark name was -: 137: * specified in command line; b) the index of this name in the -: 138: * bookmarks array. It is initialized as -1 since the index name -: 139: * could be zero */ -: 140: 3: 141: if (name) { 3: 141-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 1 45: 142: for (i = 0; i < bmn; i++) { 2: 142-block 0 unconditional 0 taken 2 43: 142-block 1 unconditional 1 taken 43 45: 142-block 2 branch 2 taken 45 branch 3 taken 0 (fallthrough) 45: 143: char *bm_name = strbtw(bms[i], ']', ':'); 45: 143-block 0 call 0 returned 45 45: 144: if (!bm_name) branch 0 taken 8 (fallthrough) branch 1 taken 37 8: 145: continue; 8: 145-block 0 unconditional 0 taken 8 37: 146: if (strcmp(name, bm_name) == 0) { 37: 146-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 35 2: 147: free(bm_name); 2: 148: cmd_line = (int)i; 2: 149: break; 2: 149-block 0 unconditional 0 taken 2 -: 150: } 35: 151: free(bm_name); 35: 151-block 0 unconditional 0 taken 35 -: 152: } -: 153: } -: 154: -: 155: /* If a valid bookmark name was passed in command line, copy the -: 156: * corresponding bookmark index (plus 1, as if it were typed in the -: 157: * bookmarks screen) to the del_elements array */ 3: 158: if (cmd_line != -1) { 3: 158-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 1 2: 159: del_elements = (char **)xnmalloc(2, sizeof(char *)); 2: 159-block 0 call 0 returned 2 2*: 160: del_elements[0] = (char *)xnmalloc((size_t)DIGINUM(cmd_line + 1) + 1, sizeof(char)); branch 0 taken 2 (fallthrough) branch 1 taken 0 2: 160-block 0 branch 2 taken 0 (fallthrough) branch 3 taken 2 %%%%%: 160-block 1 branch 4 never executed branch 5 never executed %%%%%: 160-block 2 branch 6 never executed branch 7 never executed %%%%%: 160-block 3 branch 8 never executed branch 9 never executed %%%%%: 160-block 4 branch 10 never executed branch 11 never executed %%%%%: 160-block 5 branch 12 never executed branch 13 never executed %%%%%: 160-block 6 branch 14 never executed branch 15 never executed %%%%%: 160-block 7 branch 16 never executed branch 17 never executed %%%%%: 160-block 8 unconditional 18 never executed %%%%%: 160-block 9 unconditional 19 never executed %%%%%: 160-block 10 unconditional 20 never executed %%%%%: 160-block 11 unconditional 21 never executed %%%%%: 160-block 12 unconditional 22 never executed %%%%%: 160-block 13 unconditional 23 never executed %%%%%: 160-block 14 unconditional 24 never executed %%%%%: 160-block 15 unconditional 25 never executed %%%%%: 160-block 16 unconditional 26 never executed %%%%%: 160-block 17 unconditional 27 never executed %%%%%: 160-block 18 unconditional 28 never executed %%%%%: 160-block 19 unconditional 29 never executed %%%%%: 160-block 20 unconditional 30 never executed %%%%%: 160-block 21 unconditional 31 never executed %%%%%: 160-block 22 unconditional 32 never executed 2: 160-block 23 unconditional 33 taken 2 2: 160-block 24 unconditional 34 taken 2 %%%%%: 160-block 25 unconditional 35 never executed 2: 160-block 26 call 36 returned 2 2: 161: sprintf(del_elements[0], "%d", cmd_line + 1); 2: 162: del_elements[1] = (char *)NULL; unconditional 0 taken 2 -: 163: } -: 164: -: 165: /* If bookmark name was passed but it is not a valid bookmark */ 1: 166: else if (name) { 1: 166-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 1 #####: 167: fprintf(stderr, _("bookmarks: %s: No such bookmark\n"), name); %%%%%: 167-block 0 call 0 never executed call 1 never executed #####: 168: for (i = 0; i < bmn; i++) unconditional 0 never executed %%%%%: 168-block 0 branch 1 never executed branch 2 never executed #####: 169: free(bms[i]); %%%%%: 169-block 0 unconditional 0 never executed #####: 170: free(bms); #####: 171: fclose(bm_fp); %%%%%: 171-block 0 call 0 never executed #####: 172: return EXIT_FAILURE; unconditional 0 never executed -: 173: } -: 174: -: 175: /* If not name, list bookmarks and get user input */ -: 176: else { 1: 177: printf(_("%sBookmarks%s\n\n"), BOLD, df_c); 1: 177-block 0 call 0 returned 1 call 1 returned 1 -: 178: 24: 179: for (i = 0; i < bmn; i++) unconditional 0 taken 1 unconditional 1 taken 23 24: 179-block 0 branch 2 taken 23 branch 3 taken 1 (fallthrough) 23: 180: printf("%s%zu %s%s%s\n", el_c, i + 1, bm_c, bms[i], df_c); 23: 180-block 0 call 0 returned 23 -: 181: -: 182: /* Get user input */ 1: 183: printf(_("\n%sEnter '%c' to quit.\n"), df_c, 'q'); 1: 183-block 0 call 0 returned 1 call 1 returned 1 1: 184: char *input = (char *)NULL; 2: 185: while (!input) unconditional 0 taken 1 2: 185-block 0 branch 1 taken 1 branch 2 taken 1 (fallthrough) 1: 186: input = rl_no_hist(_("Bookmark(s) to be deleted " 1: 186-block 0 call 0 returned 1 call 1 returned 1 unconditional 2 taken 1 -: 187: "(ex: 1 2-6, or *): ")); 1: 188: del_elements = get_substr(input, ' '); 1: 188-block 0 call 0 returned 1 1: 189: free(input); 1: 190: input = (char *)NULL; -: 191: 1: 192: if (!del_elements) { branch 0 taken 0 (fallthrough) branch 1 taken 1 #####: 193: for (i = 0; i < bmn; i++) %%%%%: 193-block 0 unconditional 0 never executed %%%%%: 193-block 1 branch 1 never executed branch 2 never executed #####: 194: free(bms[i]); %%%%%: 194-block 0 unconditional 0 never executed #####: 195: free(bms); #####: 196: fclose(bm_fp); %%%%%: 196-block 0 call 0 never executed #####: 197: fprintf(stderr, _("bookmarks: Error parsing input\n")); call 0 never executed call 1 never executed #####: 198: return EXIT_FAILURE; unconditional 0 never executed -: 199: } -: 200: } -: 201: -: 202: /* We have input */ -: 203: /* If quit */ -: 204: /* I inspect all substrings entered by the user for "q" before any -: 205: * other value to prevent some accidental deletion, like "1 q", or -: 206: * worst, "* q" */ 6: 207: for (i = 0; del_elements[i]; i++) { 3: 207-block 0 unconditional 0 taken 3 3: 207-block 1 unconditional 1 taken 3 6: 207-block 2 branch 2 taken 3 branch 3 taken 3 (fallthrough) 3: 208: int quit = 0; -: 209: 3: 210: if (strcmp(del_elements[i], "q") == 0) { 3: 210-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 3 #####: 211: quit = 1; %%%%%: 211-block 0 unconditional 0 never executed 3: 212: } else if (is_number(del_elements[i]) && (atoi(del_elements[i]) <= 0 3: 212-block 0 call 0 returned 3 branch 1 taken 3 (fallthrough) branch 2 taken 0 3: 212-block 1 branch 3 taken 3 (fallthrough) branch 4 taken 0 3: 213: || atoi(del_elements[i]) > (int)bmn)) { 3: 213-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 3 #####: 214: fprintf(stderr, _("bookmarks: %s: No such bookmark\n"), call 0 never executed #####: 215: del_elements[i]); %%%%%: 215-block 0 call 0 never executed #####: 216: quit = 1; unconditional 0 never executed -: 217: } -: 218: 3: 219: if (quit) { 3: 219-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 3 #####: 220: for (i = 0; i < bmn; i++) %%%%%: 220-block 0 unconditional 0 never executed %%%%%: 220-block 1 branch 1 never executed branch 2 never executed #####: 221: free(bms[i]); %%%%%: 221-block 0 unconditional 0 never executed #####: 222: free(bms); -: 223: #####: 224: for (i = 0; del_elements[i]; i++) %%%%%: 224-block 0 unconditional 0 never executed %%%%%: 224-block 1 branch 1 never executed branch 2 never executed #####: 225: free(del_elements[i]); %%%%%: 225-block 0 unconditional 0 never executed #####: 226: free(del_elements); #####: 227: fclose(bm_fp); %%%%%: 227-block 0 call 0 never executed #####: 228: return EXIT_SUCCESS; unconditional 0 never executed -: 229: } -: 230: } -: 231: -: 232: /* If "*", simply remove the bookmarks file */ -: 233: /* If there is some "*" in the input line (like "1 5 6-9 *"), it -: 234: * makes no sense to remove singles bookmarks: Just delete all of -: 235: * them at once */ 6: 236: for (i = 0; del_elements[i]; i++) { 3: 236-block 0 unconditional 0 taken 3 3: 236-block 1 unconditional 1 taken 3 6: 236-block 2 branch 2 taken 3 branch 3 taken 3 (fallthrough) 3: 237: if (strcmp(del_elements[i], "*") == 0) { 3: 237-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 3 -: 238: /* Create a backup copy of the bookmarks file, just in case */ #####: 239: char *bk_file = (char *)NULL; #####: 240: bk_file = (char *)xcalloc(strlen(config_dir) + 14, %%%%%: 240-block 0 call 0 never executed -: 241: sizeof(char)); #####: 242: sprintf(bk_file, "%s/bookmarks.bk", config_dir); #####: 243: char *tmp_cmd[] = {"cp", bm_file, bk_file, NULL}; -: 244: #####: 245: int ret = launch_execve(tmp_cmd, FOREGROUND, E_NOFLAG); call 0 never executed -: 246: /* Remove the bookmarks file, free stuff, and exit */ #####: 247: if (ret == EXIT_SUCCESS) { branch 0 never executed branch 1 never executed #####: 248: unlink(bm_file); %%%%%: 248-block 0 call 0 never executed #####: 249: printf(_("bookmarks: All bookmarks were deleted\n " call 0 never executed call 1 never executed -: 250: "However, a backup copy was created (%s)\n"), bk_file); #####: 251: free(bk_file); #####: 252: bk_file = (char *)NULL; unconditional 0 never executed -: 253: } else { #####: 254: printf(_("bookmarks: Error creating backup file. No " %%%%%: 254-block 0 call 0 never executed call 1 never executed unconditional 2 never executed -: 255: "bookmark was deleted\n")); -: 256: } -: 257: #####: 258: for (i = 0; i < bmn; i++) %%%%%: 258-block 0 unconditional 0 never executed %%%%%: 258-block 1 branch 1 never executed branch 2 never executed #####: 259: free(bms[i]); %%%%%: 259-block 0 unconditional 0 never executed #####: 260: free(bms); -: 261: #####: 262: for (i = 0; del_elements[i]; i++) %%%%%: 262-block 0 unconditional 0 never executed %%%%%: 262-block 1 branch 1 never executed branch 2 never executed #####: 263: free(del_elements[i]); %%%%%: 263-block 0 unconditional 0 never executed #####: 264: free(del_elements); -: 265: #####: 266: fclose(bm_fp); %%%%%: 266-block 0 call 0 never executed -: 267: /* Update bookmark names for TAB completion */ -: 268: /* get_bm_names(); */ #####: 269: free_bookmarks(); call 0 never executed #####: 270: load_bookmarks(); call 0 never executed -: 271: -: 272: /* If the argument "*" was specified in command line */ #####: 273: if (cmd_line != -1) branch 0 never executed branch 1 never executed #####: 274: fputs(_("All bookmarks succesfully removed\n"), stdout); %%%%%: 274-block 0 call 0 never executed call 1 never executed unconditional 2 never executed -: 275: #####: 276: return EXIT_SUCCESS; %%%%%: 276-block 0 unconditional 0 never executed -: 277: } -: 278: } -: 279: -: 280: /* Remove single bookmarks */ -: 281: /* Open a temporary file */ 3: 282: char *tmp_file = (char *)NULL; 3: 283: tmp_file = (char *)xnmalloc(strlen(config_dir) + 8, sizeof(char)); 3: 283-block 0 call 0 returned 3 3: 284: sprintf(tmp_file, "%s/bm_tmp", config_dir); -: 285: 3: 286: FILE *tmp_fp = fopen(tmp_file, "w+"); call 0 returned 3 3: 287: if (!tmp_fp) { branch 0 taken 0 (fallthrough) branch 1 taken 3 #####: 288: for (i = 0; i < bmn; i++) %%%%%: 288-block 0 unconditional 0 never executed %%%%%: 288-block 1 branch 1 never executed branch 2 never executed #####: 289: free(bms[i]); %%%%%: 289-block 0 unconditional 0 never executed #####: 290: free(bms); -: 291: #####: 292: for (i = 0; del_elements[i]; i++) %%%%%: 292-block 0 unconditional 0 never executed %%%%%: 292-block 1 branch 1 never executed branch 2 never executed #####: 293: free(del_elements[i]); %%%%%: 293-block 0 unconditional 0 never executed #####: 294: free(del_elements); -: 295: #####: 296: fclose(bm_fp); %%%%%: 296-block 0 call 0 never executed #####: 297: fprintf(stderr, _("bookmarks: Error creating temporary file\n")); call 0 never executed call 1 never executed -: 298: #####: 299: return EXIT_FAILURE; unconditional 0 never executed -: 300: } -: 301: -: 302: /* Go back to the beginning of the bookmarks file */ 3: 303: fseek(bm_fp, 0, SEEK_SET); 3: 303-block 0 call 0 returned 3 -: 304: -: 305: /* Dump into the tmp file everything except bookmarks marked for -: 306: * deletion */ -: 307: 3: 308: char *lineb = (char *)NULL; 81: 309: while ((line_len = getline(&lineb, &line_size, bm_fp)) > 0) { unconditional 0 taken 3 81: 309-block 0 call 1 returned 81 branch 2 taken 78 branch 3 taken 3 (fallthrough) 78: 310: if (lineb[line_len - 1] == '\n') 78: 310-block 0 branch 0 taken 78 (fallthrough) branch 1 taken 0 78: 311: lineb[line_len - 1] = '\0'; 78: 311-block 0 unconditional 0 taken 78 -: 312: 78: 313: int bm_found = 0; -: 314: size_t j; -: 315: 156: 316: for (j = 0; del_elements[j]; j++) { 78: 316-block 0 unconditional 0 taken 78 78: 316-block 1 unconditional 1 taken 78 156: 316-block 2 branch 2 taken 78 branch 3 taken 78 (fallthrough) 78*: 317: if (!is_number(del_elements[j])) 78: 317-block 0 call 0 returned 78 branch 1 taken 0 (fallthrough) branch 2 taken 78 #####: 318: continue; %%%%%: 318-block 0 unconditional 0 never executed 78: 319: if (strcmp(bms[atoi(del_elements[j]) - 1], lineb) == 0) 78: 319-block 0 branch 0 taken 3 (fallthrough) branch 1 taken 75 3: 320: bm_found = 1; 3: 320-block 0 unconditional 0 taken 3 -: 321: } -: 322: 78: 323: if (bm_found) 78: 323-block 0 branch 0 taken 3 (fallthrough) branch 1 taken 75 3: 324: continue; 3: 324-block 0 unconditional 0 taken 3 -: 325: 75: 326: fprintf(tmp_fp, "%s\n", lineb); 75: 326-block 0 call 0 returned 75 unconditional 1 taken 75 -: 327: } -: 328: 3: 329: free(lineb); -: 330: -: 331: /* Free stuff */ 6: 332: for (i = 0; del_elements[i]; i++) 3: 332-block 0 unconditional 0 taken 3 6: 332-block 1 branch 1 taken 3 branch 2 taken 3 (fallthrough) 3: 333: free(del_elements[i]); 3: 333-block 0 unconditional 0 taken 3 3: 334: free(del_elements); -: 335: 72: 336: for (i = 0; i < bmn; i++) 3: 336-block 0 unconditional 0 taken 3 72: 336-block 1 branch 1 taken 69 branch 2 taken 3 (fallthrough) 69: 337: free(bms[i]); 69: 337-block 0 unconditional 0 taken 69 3: 338: free(bms); -: 339: -: 340: /* Close files */ 3: 341: fclose(bm_fp); 3: 341-block 0 call 0 returned 3 3: 342: fclose(tmp_fp); call 0 returned 3 -: 343: -: 344: /* Remove the old bookmarks file and make the tmp file the new -: 345: * bookmarks file*/ 3: 346: unlink(bm_file); call 0 returned 3 3: 347: rename(tmp_file, bm_file); call 0 returned 3 3: 348: free(tmp_file); -: 349: -: 350: /* Update bookmark names for TAB completion */ -: 351: /* get_bm_names(); */ 3: 352: free_bookmarks(); call 0 returned 3 3: 353: load_bookmarks(); call 0 returned 3 -: 354: -: 355: /* If the bookmark to be removed was specified in command line */ 3: 356: if (cmd_line != -1) branch 0 taken 2 (fallthrough) branch 1 taken 1 2: 357: printf(_("Successfully removed '%s'\n"), name); 2: 357-block 0 call 0 returned 2 call 1 returned 2 unconditional 2 taken 2 -: 358: 3: 359: return EXIT_SUCCESS; 3: 359-block 0 unconditional 0 taken 3 -: 360:} -: 361: -: 362:static int function bookmark_add called 2 returned 100% blocks executed 56% 2: 363:bookmark_add(char *file) -: 364:{ 2: 365: if (!file) 2: 365-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 2 #####: 366: return EXIT_FAILURE; %%%%%: 366-block 0 unconditional 0 never executed -: 367: 2: 368: int mod_file = 0; -: 369: /* If not absolute path, prepend current path to file */ 2: 370: if (*file != '/') { 2: 370-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 1 1: 371: char *tmp_file = (char *)NULL; 1: 372: tmp_file = (char *)xnmalloc((strlen(ws[cur_ws].path) + strlen(file) + 2), sizeof(char)); 1: 372-block 0 call 0 returned 1 1: 373: sprintf(tmp_file, "%s/%s", ws[cur_ws].path, file); 1: 374: file = tmp_file; 1: 375: tmp_file = (char *)NULL; 1: 376: mod_file = 1; unconditional 0 taken 1 -: 377: } -: 378: -: 379: /* Check if FILE is an available path */ -: 380: 2: 381: FILE *bm_fp = fopen(bm_file, "r"); 2: 381-block 0 call 0 returned 2 2: 382: if (!bm_fp) { branch 0 taken 0 (fallthrough) branch 1 taken 2 #####: 383: fprintf(stderr, _("bookmarks: Error opening the bookmarks file\n")); %%%%%: 383-block 0 call 0 never executed call 1 never executed #####: 384: if (mod_file) branch 0 never executed branch 1 never executed #####: 385: free(file); %%%%%: 385-block 0 unconditional 0 never executed -: 386: #####: 387: return EXIT_FAILURE; %%%%%: 387-block 0 unconditional 0 never executed -: 388: } -: 389: 2: 390: int dup = 0; 2: 391: char **bms = (char **)NULL; 2: 392: size_t line_size = 0, i, bmn = 0; 2: 393: char *line = (char *)NULL; -: 394: 52: 395: while (getline(&line, &line_size, bm_fp) > 0) { 2: 395-block 0 unconditional 0 taken 2 52: 395-block 1 call 1 returned 52 branch 2 taken 50 branch 3 taken 2 (fallthrough) 50: 396: if (!line || !*line || *line == '#' || *line == '\n') 50: 396-block 0 branch 0 taken 50 (fallthrough) branch 1 taken 0 50: 396-block 1 branch 2 taken 50 (fallthrough) branch 3 taken 0 50: 396-block 2 branch 4 taken 44 (fallthrough) branch 5 taken 6 44: 396-block 3 branch 6 taken 0 (fallthrough) branch 7 taken 44 6: 397: continue; 6: 397-block 0 unconditional 0 taken 6 -: 398: 44: 399: char *tmp_line = (char *)NULL; 44: 400: tmp_line = strchr(line, '/'); 44: 401: if (tmp_line) { 44: 401-block 0 branch 0 taken 44 (fallthrough) branch 1 taken 0 44: 402: size_t tmp_line_len = strlen(tmp_line); -: 403: 44: 404: if (tmp_line_len && tmp_line[tmp_line_len - 1] == '\n') 44: 404-block 0 branch 0 taken 44 (fallthrough) branch 1 taken 0 44: 404-block 1 branch 2 taken 44 (fallthrough) branch 3 taken 0 44: 405: tmp_line[tmp_line_len - 1] = '\0'; 44: 405-block 0 unconditional 0 taken 44 -: 406: 44: 407: if (strcmp(tmp_line, file) == 0) { 44: 407-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 44 #####: 408: fprintf(stderr, _("bookmarks: %s: Path already " %%%%%: 408-block 0 call 0 never executed call 1 never executed -: 409: "bookmarked\n"), -: 410: file); #####: 411: dup = 1; #####: 412: break; unconditional 0 never executed -: 413: } -: 414: 44: 415: tmp_line = (char *)NULL; 44: 415-block 0 unconditional 0 taken 44 -: 416: } -: 417: -: 418: /* Store lines: used later to check hotkeys */ 44: 419: bms = (char **)xrealloc(bms, (bmn + 1) * sizeof(char *)); 44: 419-block 0 call 0 returned 44 44: 420: bms[bmn++] = savestring(line, strlen(line)); call 0 returned 44 unconditional 1 taken 44 -: 421: } -: 422: 2: 423: free(line); 2: 424: line = (char *)NULL; 2: 425: fclose(bm_fp); 2: 425-block 0 call 0 returned 2 -: 426: 2: 427: if (dup) { branch 0 taken 0 (fallthrough) branch 1 taken 2 #####: 428: for (i = 0; i < bmn; i++) %%%%%: 428-block 0 unconditional 0 never executed %%%%%: 428-block 1 branch 1 never executed branch 2 never executed #####: 429: free(bms[i]); %%%%%: 429-block 0 unconditional 0 never executed #####: 430: free(bms); #####: 431: if (mod_file) %%%%%: 431-block 0 branch 0 never executed branch 1 never executed #####: 432: free(file); %%%%%: 432-block 0 unconditional 0 never executed #####: 433: return EXIT_FAILURE; %%%%%: 433-block 0 unconditional 0 never executed -: 434: } -: 435: -: 436: /* If path is available */ -: 437: 2: 438: char *name = (char *)NULL, *hk = (char *)NULL, *tmp = (char *)NULL; -: 439: -: 440: /* Ask for data to construct the bookmark line. Both values could be -: 441: * NULL */ 2: 442: puts(_("Bookmark line example: [sc]name:path")); 2: 442-block 0 call 0 returned 2 call 1 returned 2 2: 443: hk = rl_no_hist("Shortcut: "); call 0 returned 2 -: 444: -: 445: /* Check if hotkey is available */ 2: 446: if (hk) { branch 0 taken 2 (fallthrough) branch 1 taken 0 2: 447: char *tmp_line = (char *)NULL; -: 448: 46: 449: for (i = 0; i < bmn; i++) { 2: 449-block 0 unconditional 0 taken 2 44: 449-block 1 unconditional 1 taken 44 46: 449-block 2 branch 2 taken 44 branch 3 taken 2 (fallthrough) 44: 450: tmp_line = strbtw(bms[i], '[', ']'); 44: 450-block 0 call 0 returned 44 44: 451: if (tmp_line) { branch 0 taken 44 (fallthrough) branch 1 taken 0 44: 452: if (strcmp(hk, tmp_line) == 0) { 44: 452-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 44 #####: 453: fprintf(stderr, _("bookmarks: %s: This shortcut is " %%%%%: 453-block 0 call 0 never executed call 1 never executed -: 454: "already in use\n"), hk); -: 455: #####: 456: dup = 1; #####: 457: free(tmp_line); #####: 458: break; unconditional 0 never executed -: 459: } -: 460: 44: 461: free(tmp_line); 44: 461-block 0 unconditional 0 taken 44 -: 462: } -: 463: } -: 464: } -: 465: 2: 466: if (dup) { 2: 466-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 2 #####: 467: if (hk) %%%%%: 467-block 0 branch 0 never executed branch 1 never executed #####: 468: free(hk); %%%%%: 468-block 0 unconditional 0 never executed #####: 469: for (i = 0; i < bmn; i++) %%%%%: 469-block 0 unconditional 0 never executed %%%%%: 469-block 1 branch 1 never executed branch 2 never executed #####: 470: free(bms[i]); %%%%%: 470-block 0 unconditional 0 never executed #####: 471: free(bms); #####: 472: if (mod_file) %%%%%: 472-block 0 branch 0 never executed branch 1 never executed #####: 473: free(file); %%%%%: 473-block 0 unconditional 0 never executed #####: 474: return EXIT_FAILURE; %%%%%: 474-block 0 unconditional 0 never executed -: 475: } -: 476: 2: 477: name = rl_no_hist("Name: "); 2: 477-block 0 call 0 returned 2 -: 478: 2: 479: if (name) { branch 0 taken 2 (fallthrough) branch 1 taken 0 -: 480: /* Check name is not duplicated */ 2: 481: char *tmp_line = (char *)NULL; 46: 482: for (i = 0; i < bmn; i++) { 2: 482-block 0 unconditional 0 taken 2 44: 482-block 1 unconditional 1 taken 44 46: 482-block 2 branch 2 taken 44 branch 3 taken 2 (fallthrough) 44: 483: tmp_line = strbtw(bms[i], ']', ':'); 44: 483-block 0 call 0 returned 44 44: 484: if (tmp_line) { branch 0 taken 36 (fallthrough) branch 1 taken 8 36: 485: if (strcmp(name, tmp_line) == 0) { 36: 485-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 36 #####: 486: fprintf(stderr, _("bookmarks: %s: This name is " %%%%%: 486-block 0 call 0 never executed call 1 never executed -: 487: "already in use\n"), name); #####: 488: dup = 1; #####: 489: free(tmp_line); #####: 490: break; unconditional 0 never executed -: 491: } 36: 492: free(tmp_line); 36: 492-block 0 unconditional 0 taken 36 -: 493: } -: 494: } -: 495: 2: 496: if (dup) { 2: 496-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 2 #####: 497: free(name); #####: 498: if (hk) %%%%%: 498-block 0 branch 0 never executed branch 1 never executed #####: 499: free(hk); %%%%%: 499-block 0 unconditional 0 never executed #####: 500: for (i = 0; i < bmn; i++) %%%%%: 500-block 0 unconditional 0 never executed %%%%%: 500-block 1 branch 1 never executed branch 2 never executed #####: 501: free(bms[i]); %%%%%: 501-block 0 unconditional 0 never executed #####: 502: free(bms); #####: 503: if (mod_file) %%%%%: 503-block 0 branch 0 never executed branch 1 never executed #####: 504: free(file); %%%%%: 504-block 0 unconditional 0 never executed #####: 505: return EXIT_FAILURE; %%%%%: 505-block 0 unconditional 0 never executed -: 506: } -: 507: -: 508: /* Generate the bookmark line */ 2: 509: if (hk) { /* name AND hk */ 2: 509-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 0 2: 510: tmp = (char *)xcalloc(strlen(hk) + strlen(name) + strlen(file) + 5, sizeof(char)); 2: 510-block 0 call 0 returned 2 2: 511: sprintf(tmp, "[%s]%s:%s\n", hk, name, file); 2: 512: free(hk); unconditional 0 taken 2 -: 513: } else { /* Only name */ #####: 514: tmp = (char *)xnmalloc(strlen(name) + strlen(file) + 3, %%%%%: 514-block 0 call 0 never executed -: 515: sizeof(char)); #####: 516: sprintf(tmp, "%s:%s\n", name, file); unconditional 0 never executed -: 517: } -: 518: 2: 519: free(name); 2: 520: name = (char *)NULL; 2: 520-block 0 unconditional 0 taken 2 -: 521: } -: 522: #####: 523: else if (hk) { /* Only hk */ %%%%%: 523-block 0 branch 0 never executed branch 1 never executed #####: 524: tmp = (char *)xnmalloc(strlen(hk) + strlen(file) + 4, %%%%%: 524-block 0 call 0 never executed -: 525: sizeof(char)); #####: 526: sprintf(tmp, "[%s]%s\n", hk, file); #####: 527: free(hk); #####: 528: hk = (char *)NULL; unconditional 0 never executed -: 529: } else { /* Neither shortcut nor name: only path */ #####: 530: tmp = (char *)xnmalloc(strlen(file) + 2, sizeof(char)); %%%%%: 530-block 0 call 0 never executed #####: 531: sprintf(tmp, "%s\n", file); unconditional 0 never executed -: 532: } -: 533: 46: 534: for (i = 0; i < bmn; i++) 2: 534-block 0 unconditional 0 taken 2 46: 534-block 1 branch 1 taken 44 branch 2 taken 2 (fallthrough) 44: 535: free(bms[i]); 44: 535-block 0 unconditional 0 taken 44 2: 536: free(bms); 2: 537: bms = (char **)NULL; -: 538: 2: 539: if (!tmp) { 2: 539-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 2 #####: 540: fprintf(stderr, _("bookmarks: Error generating the bookmark line\n")); %%%%%: 540-block 0 call 0 never executed call 1 never executed #####: 541: return EXIT_FAILURE; unconditional 0 never executed -: 542: } -: 543: -: 544: /* Once we have the bookmark line, write it to the bookmarks file */ -: 545: 2: 546: bm_fp = fopen(bm_file, "a+"); 2: 546-block 0 call 0 returned 2 2: 547: if (!bm_fp) { branch 0 taken 0 (fallthrough) branch 1 taken 2 #####: 548: fprintf(stderr, _("bookmarks: Error opening the bookmarks file\n")); %%%%%: 548-block 0 call 0 never executed call 1 never executed #####: 549: free(tmp); #####: 550: return EXIT_FAILURE; unconditional 0 never executed -: 551: } -: 552: 2: 553: if (mod_file) 2: 553-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 1 1: 554: free(file); 1: 554-block 0 unconditional 0 taken 1 -: 555: 2: 556: if (fseek(bm_fp, 0L, SEEK_END) == -1) { 2: 556-block 0 call 0 returned 2 branch 1 taken 0 (fallthrough) branch 2 taken 2 #####: 557: fprintf(stderr, _("bookmarks: Error opening the bookmarks file\n")); %%%%%: 557-block 0 call 0 never executed call 1 never executed #####: 558: free(tmp); #####: 559: fclose(bm_fp); call 0 never executed #####: 560: return EXIT_FAILURE; unconditional 0 never executed -: 561: } -: 562: -: 563: /* Everything is fine: add the new bookmark to the bookmarks file */ 2: 564: fprintf(bm_fp, "%s", tmp); 2: 564-block 0 call 0 returned 2 2: 565: fclose(bm_fp); call 0 returned 2 2: 566: printf(_("File succesfully bookmarked\n")); call 0 returned 2 call 1 returned 2 2: 567: free(tmp); -: 568: /* Update bookmark names for TAB completion */ -: 569: /* get_bm_names(); */ 2: 570: free_bookmarks(); call 0 returned 2 2: 571: load_bookmarks(); call 0 returned 2 2: 572: return EXIT_SUCCESS; unconditional 0 taken 2 -: 573:} -: 574: -: 575:int function edit_bookmarks called 7 returned 100% blocks executed 45% 7: 576:edit_bookmarks(char *cmd) -: 577:{ 7: 578: int exit_status = EXIT_SUCCESS; -: 579: 7: 580: if (!cmd) { 7: 580-block 0 branch 0 taken 7 (fallthrough) branch 1 taken 0 7: 581: exit_status = open_file(bm_file); 7: 581-block 0 call 0 returned 7 unconditional 1 taken 7 -: 582: } else { #####: 583: char *tmp_cmd[] = {cmd, bm_file, NULL}; #####: 584: if (launch_execve(tmp_cmd, FOREGROUND, E_NOSTDERR) != EXIT_SUCCESS) %%%%%: 584-block 0 call 0 never executed branch 1 never executed branch 2 never executed #####: 585: exit_status = EXIT_FAILURE; %%%%%: 585-block 0 unconditional 0 never executed -: 586: } -: 587: 7: 588: if (exit_status == EXIT_FAILURE) 7: 588-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 7 #####: 589: fprintf(stderr, _("%s: Cannot open the bookmarks file"), PROGRAM_NAME); %%%%%: 589-block 0 call 0 never executed call 1 never executed unconditional 2 never executed -: 590: 7: 591: return exit_status; 7: 591-block 0 unconditional 0 taken 7 -: 592:} -: 593: -: 594:int function open_bookmark called 11 returned 100% blocks executed 78% 11: 595:open_bookmark(void) -: 596:{ -: 597: /* If no bookmarks */ 11: 598: if (bm_n == 0) { 11: 598-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 11 #####: 599: printf(_("Bookmarks: There are no bookmarks\nEnter 'bm edit' " %%%%%: 599-block 0 call 0 never executed call 1 never executed -: 600: "or press F11 to edit the bookmarks file. You can " -: 601: "also enter 'bm add PATH' to add a new bookmark\n")); #####: 602: return EXIT_SUCCESS; unconditional 0 never executed -: 603: } -: 604: -: 605: /* We have bookmarks... */ -: 606: struct stat file_attrib; -: 607: 11: 608: if (clear_screen) 11: 608-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 11 #####: 609: CLEAR; %%%%%: 609-block 0 call 0 never executed unconditional 1 never executed -: 610: 11: 611: printf(_("%sBookmarks Manager%s\n\n"), BOLD, df_c); 11: 611-block 0 call 0 returned 11 call 1 returned 11 -: 612: -: 613: /* Print bookmarks taking into account the existence of shortcut, -: 614: * name, and path for each bookmark */ 11: 615: size_t i, eln = 0; -: 616: 255: 617: for (i = 0; i < bm_n; i++) { unconditional 0 taken 11 244: 617-block 0 unconditional 1 taken 244 255: 617-block 1 branch 2 taken 244 branch 3 taken 11 (fallthrough) 244*: 618: if (!bookmarks[i].path || !*bookmarks[i].path) 244: 618-block 0 branch 0 taken 244 (fallthrough) branch 1 taken 0 244: 618-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 244 #####: 619: continue; %%%%%: 619-block 0 unconditional 0 never executed 244: 620: eln++; 244: 621: int is_dir = 0, sc_ok = 0, name_ok = 0, non_existent = 0; 244: 622: int path_ok = stat(bookmarks[i].path, &file_attrib); 244: 622-block 0 call 0 returned 244 -: 623: 244: 624: if (bookmarks[i].shortcut) branch 0 taken 244 (fallthrough) branch 1 taken 0 244: 625: sc_ok = 1; 244: 625-block 0 unconditional 0 taken 244 -: 626: 244: 627: if (bookmarks[i].name) 244: 627-block 0 branch 0 taken 200 (fallthrough) branch 1 taken 44 200: 628: name_ok = 1; 200: 628-block 0 unconditional 0 taken 200 -: 629: 244: 630: if (path_ok == -1) { 244: 630-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 242 2: 631: non_existent = 1; 2: 631-block 0 unconditional 0 taken 2 -: 632: } else { 242: 633: switch ((file_attrib.st_mode & S_IFMT)) { 242: 633-block 0 branch 0 taken 232 branch 1 taken 10 branch 2 taken 0 232: 634: case S_IFDIR: is_dir = 1; break; 232: 634-block 0 unconditional 0 taken 232 10: 635: case S_IFREG: break; 10: 635-block 0 unconditional 0 taken 10 #####: 636: default: non_existent = 1; break; %%%%%: 636-block 0 unconditional 0 never executed -: 637: } -: 638: } -: 639: 974*: 640: printf("%s%zu%s %s%c%s%c%s %s%s%s\n", el_c, eln, df_c, 244: 640-block 0 branch 0 taken 200 (fallthrough) branch 1 taken 44 244: 640-block 1 branch 2 taken 242 (fallthrough) branch 3 taken 2 242: 640-block 2 unconditional 4 taken 242 2: 640-block 3 unconditional 5 taken 2 244: 640-block 4 branch 6 taken 244 (fallthrough) branch 7 taken 0 244: 640-block 5 unconditional 8 taken 244 %%%%%: 640-block 6 unconditional 9 never executed 244: 640-block 7 branch 10 taken 244 (fallthrough) branch 11 taken 0 %%%%%: 640-block 8 unconditional 12 never executed 244: 640-block 9 branch 13 taken 244 (fallthrough) branch 14 taken 0 244: 640-block 10 unconditional 15 taken 244 %%%%%: 640-block 11 unconditional 16 never executed 244: 640-block 12 call 17 returned 244 unconditional 18 taken 244 244: 641: BOLD, sc_ok ? '[' : 0, sc_ok ? bookmarks[i].shortcut : "", 244: 641-block 0 unconditional 0 taken 244 242: 642: sc_ok ? ']' : 0, df_c, non_existent ? GRAY : (is_dir ? bm_c : fi_c), 242: 642-block 0 branch 0 taken 232 (fallthrough) branch 1 taken 10 232: 642-block 1 unconditional 2 taken 232 10: 642-block 2 unconditional 3 taken 10 244: 643: name_ok ? bookmarks[i].name : bookmarks[i].path, df_c); 200: 643-block 0 unconditional 0 taken 200 44: 643-block 1 unconditional 1 taken 44 -: 644: } -: 645: -: 646: /* User selection. Display the prompt */ 11: 647: char **arg = bm_prompt(); 11: 647-block 0 call 0 returned 11 11: 648: if (!arg || !*arg) branch 0 taken 11 (fallthrough) branch 1 taken 0 11: 648-block 0 branch 2 taken 0 (fallthrough) branch 3 taken 11 #####: 649: return EXIT_FAILURE; %%%%%: 649-block 0 unconditional 0 never executed -: 650: 11: 651: int exit_status = EXIT_SUCCESS; -: 652: -: 653: /* Case "edit" */ 11*: 654: if (*arg[0] == 'e' && (!arg[0][1] || strcmp(arg[0], "edit") == 0)) { 11: 654-block 0 branch 0 taken 3 (fallthrough) branch 1 taken 8 3: 654-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 3 %%%%%: 654-block 2 branch 4 never executed branch 5 never executed 3: 655: stat(bm_file, &file_attrib); 3: 655-block 0 call 0 returned 3 3: 656: time_t mtime_bfr = (time_t)file_attrib.st_mtime; -: 657: 3: 658: edit_bookmarks(arg[1] ? arg[1] : NULL); call 0 returned 3 -: 659: 3: 660: stat(bm_file, &file_attrib); call 0 returned 3 3: 661: if (mtime_bfr != (time_t)file_attrib.st_mtime) { branch 0 taken 3 (fallthrough) branch 1 taken 0 3: 662: free_bookmarks(); 3: 662-block 0 call 0 returned 3 3: 663: load_bookmarks(); call 0 returned 3 unconditional 1 taken 3 -: 664: } -: 665: 6: 666: for (i = 0; arg[i]; i++) 3: 666-block 0 unconditional 0 taken 3 6: 666-block 1 branch 1 taken 3 branch 2 taken 3 (fallthrough) 3: 667: free(arg[i]); 3: 667-block 0 unconditional 0 taken 3 3: 668: free(arg); -: 669: 3: 670: arg = (char **)NULL; -: 671: 3: 672: char *tmp_cmd[] = {"bm", NULL}; 3: 673: bookmarks_function(tmp_cmd); 3: 673-block 0 call 0 returned 3 3: 674: return EXIT_SUCCESS; unconditional 0 taken 3 -: 675: } -: 676: -: 677: /* Case "quit" */ 8*: 678: if (*arg[0] == 'q' && (!arg[0][1] || strcmp(arg[0], "quit") == 0)) 8: 678-block 0 branch 0 taken 5 (fallthrough) branch 1 taken 3 5: 678-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 5 %%%%%: 678-block 2 branch 4 never executed branch 5 never executed 5: 679: goto FREE_AND_EXIT; 5: 679-block 0 unconditional 0 taken 5 -: 680: 3: 681: char *tmp_path = (char *)NULL; -: 682: -: 683: /* Get the corresponding bookmark path */ -: 684: /* If an ELN */ 3: 685: if (is_number(arg[0])) { 3: 685-block 0 call 0 returned 3 branch 1 taken 2 (fallthrough) branch 2 taken 1 2: 686: int num = atoi(arg[0]); 2: 687: if (num <= 0 || (size_t)num > bm_n) { 2: 687-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 0 2: 687-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 2 #####: 688: fprintf(stderr, _("Bookmarks: %d: No such ELN\n"), num); %%%%%: 688-block 0 call 0 never executed call 1 never executed #####: 689: exit_status = EXIT_FAILURE; #####: 690: goto FREE_AND_EXIT; unconditional 0 never executed -: 691: } else { 2: 692: tmp_path = bookmarks[num - 1].path; 2: 692-block 0 unconditional 0 taken 2 -: 693: } -: 694: } else { -: 695: /* If string, check shortcuts and names */ 5: 696: for (i = 0; i < bm_n; i++) { 1: 696-block 0 unconditional 0 taken 1 4: 696-block 1 unconditional 1 taken 4 5: 696-block 2 branch 2 taken 5 branch 3 taken 0 (fallthrough) 5: 697: if ((bookmarks[i].shortcut && *arg[0] == *bookmarks[i].shortcut 5: 697-block 0 branch 0 taken 5 (fallthrough) branch 1 taken 0 5: 697-block 1 branch 2 taken 1 (fallthrough) branch 3 taken 4 1: 698: && strcmp(arg[0], bookmarks[i].shortcut) == 0) 1: 698-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 1 4: 699: || (bookmarks[i].name && *arg[0] == *bookmarks[i].name 4: 699-block 0 branch 0 taken 4 (fallthrough) branch 1 taken 0 4: 699-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 4 #####: 700: && strcmp(arg[0], bookmarks[i].name) == 0)) { %%%%%: 700-block 0 branch 0 never executed branch 1 never executed -: 701: 1: 702: if (bookmarks[i].path) { 1: 702-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 0 1: 703: char *tmp_cmd[] = {"o", bookmarks[i].path, -: 704: arg[1] ? arg[1] : NULL, -: 705: NULL}; -: 706: 1: 707: exit_status = open_function(tmp_cmd); 1: 707-block 0 call 0 returned 1 1: 708: goto FREE_AND_EXIT; unconditional 0 taken 1 -: 709: } -: 710: #####: 711: fprintf(stderr, _("%s: %s: Invalid bookmark\n"), %%%%%: 711-block 0 call 0 never executed call 1 never executed -: 712: PROGRAM_NAME, arg[0]); #####: 713: exit_status = EXIT_FAILURE; #####: 714: goto FREE_AND_EXIT; unconditional 0 never executed -: 715: } -: 716: } -: 717: } -: 718: 2: 719: if (!tmp_path) { 2: 719-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 2 #####: 720: fprintf(stderr, _("Bookmarks: %s: No such bookmark\n"), %%%%%: 720-block 0 call 0 never executed call 1 never executed -: 721: arg[0]); #####: 722: exit_status = EXIT_FAILURE; #####: 723: goto FREE_AND_EXIT; unconditional 0 never executed -: 724: } -: 725: 2: 726: char *tmp_cmd[] = {"o", tmp_path, arg[1] ? arg[1] : NULL, NULL}; 2: 727: exit_status = open_function(tmp_cmd); 2: 727-block 0 call 0 returned 2 2: 728: goto FREE_AND_EXIT; unconditional 0 taken 2 -: 729: 8: 730:FREE_AND_EXIT : { 16: 731: for (i = 0; arg[i]; i++) 8: 731-block 0 unconditional 0 taken 8 16: 731-block 1 branch 1 taken 8 branch 2 taken 8 (fallthrough) 8: 732: free(arg[i]); 8: 732-block 0 unconditional 0 taken 8 8: 733: free(arg); 8: 734: arg = (char **)NULL; 8: 735: return exit_status; 8: 735-block 0 unconditional 0 taken 8 -: 736:} -: 737:} -: 738: -: 739:int function bookmarks_function called 20 returned 100% blocks executed 44% 20: 740:bookmarks_function(char **cmd) -: 741:{ 20: 742: if (xargs.stealth_mode == 1) { 20: 742-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 20 #####: 743: printf(_("%s: Access to configuration files is not allowed in " %%%%%: 743-block 0 call 0 never executed call 1 never executed -: 744: "stealth mode\n"), PROGRAM_NAME); #####: 745: return EXIT_SUCCESS; unconditional 0 never executed -: 746: } -: 747: 20: 748: if (!config_ok) { 20: 748-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 20 #####: 749: fprintf(stderr, _("Bookmarks function disabled\n")); %%%%%: 749-block 0 call 0 never executed call 1 never executed #####: 750: return EXIT_FAILURE; unconditional 0 never executed -: 751: } -: 752: -: 753: /* If the bookmarks file doesn't exist, create it. NOTE: This file -: 754: * should be created at startup (by get_bm_names()), but we check -: 755: * it again here just in case it was meanwhile deleted for some -: 756: * reason */ -: 757: -: 758: /* If no arguments */ 20: 759: if (!cmd[1]) 20: 759-block 0 branch 0 taken 11 (fallthrough) branch 1 taken 9 11: 760: return open_bookmark(); 11: 760-block 0 call 0 returned 11 unconditional 1 taken 11 -: 761: -: 762: /* Check arguments */ -: 763: -: 764: /* Add a bookmark */ 9: 765: if (*cmd[1] == 'a' && (!cmd[1][1] || strcmp(cmd[1], "add") == 0)) { 9: 765-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 7 2: 765-block 1 branch 2 taken 1 (fallthrough) branch 3 taken 1 1: 765-block 2 branch 4 taken 1 (fallthrough) branch 5 taken 0 2: 766: if (!cmd[2]) { 2: 766-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 2 #####: 767: puts(_(BOOKMARKS_USAGE)); %%%%%: 767-block 0 call 0 never executed call 1 never executed #####: 768: return EXIT_SUCCESS; unconditional 0 never executed -: 769: } -: 770: 2: 771: if (access(cmd[2], F_OK) != 0) { 2: 771-block 0 call 0 returned 2 branch 1 taken 0 (fallthrough) branch 2 taken 2 #####: 772: fprintf(stderr, _("Bookmarks: %s: %s\n"), cmd[2], call 0 never executed call 1 never executed #####: 773: strerror(errno)); %%%%%: 773-block 0 call 0 never executed #####: 774: return EXIT_FAILURE; unconditional 0 never executed -: 775: } -: 776: 2: 777: return bookmark_add(cmd[2]); 2: 777-block 0 call 0 returned 2 unconditional 1 taken 2 -: 778: } -: 779: -: 780: /* Delete bookmarks */ 7: 781: if (*cmd[1] == 'd' && (!cmd[1][1] || strcmp(cmd[1], "del") == 0)) 7: 781-block 0 branch 0 taken 3 (fallthrough) branch 1 taken 4 3: 781-block 1 branch 2 taken 3 (fallthrough) branch 3 taken 0 3: 781-block 2 branch 4 taken 3 (fallthrough) branch 5 taken 0 3: 782: return bookmark_del(cmd[2] ? cmd[2] : NULL); 3: 782-block 0 call 0 returned 3 unconditional 1 taken 3 -: 783: -: 784: /* Edit */ 4: 785: if (*cmd[1] == 'e' && (!cmd[1][1] || strcmp(cmd[1], "edit") == 0)) 4: 785-block 0 branch 0 taken 4 (fallthrough) branch 1 taken 0 4: 785-block 1 branch 2 taken 4 (fallthrough) branch 3 taken 0 4: 785-block 2 branch 4 taken 4 (fallthrough) branch 5 taken 0 4: 786: return edit_bookmarks(cmd[2] ? cmd[2] : NULL); 4: 786-block 0 call 0 returned 4 unconditional 1 taken 4 -: 787: -: 788: /* Shortcut or bm name */ -: 789: size_t i; #####: 790: for (i = 0; i < bm_n; i++) { %%%%%: 790-block 0 unconditional 0 never executed %%%%%: 790-block 1 unconditional 1 never executed %%%%%: 790-block 2 branch 2 never executed branch 3 never executed #####: 791: if ((bookmarks[i].shortcut && *cmd[1] == *bookmarks[i].shortcut %%%%%: 791-block 0 branch 0 never executed branch 1 never executed %%%%%: 791-block 1 branch 2 never executed branch 3 never executed #####: 792: && strcmp(cmd[1], bookmarks[i].shortcut) == 0) %%%%%: 792-block 0 branch 0 never executed branch 1 never executed #####: 793: || (bookmarks[i].name && *cmd[1] == *bookmarks[i].name %%%%%: 793-block 0 branch 0 never executed branch 1 never executed %%%%%: 793-block 1 branch 2 never executed branch 3 never executed #####: 794: && strcmp(cmd[1], bookmarks[i].name) == 0)) { %%%%%: 794-block 0 branch 0 never executed branch 1 never executed -: 795: #####: 796: if (bookmarks[i].path) { %%%%%: 796-block 0 branch 0 never executed branch 1 never executed #####: 797: char *tmp_cmd[] = {"o", bookmarks[i].path, -: 798: cmd[2] ? cmd[2] : NULL, NULL}; #####: 799: return open_function(tmp_cmd); %%%%%: 799-block 0 call 0 never executed unconditional 1 never executed -: 800: } -: 801: #####: 802: fprintf(stderr, _("Bookmarks: %s: Invalid bookmark\n"), call 0 never executed #####: 803: cmd[1]); %%%%%: 803-block 0 call 0 never executed #####: 804: return EXIT_FAILURE; unconditional 0 never executed -: 805: } -: 806: } -: 807: #####: 808: fprintf(stderr, _("Bookmarks: %s: No such bookmark\n"), cmd[1]); %%%%%: 808-block 0 call 0 never executed call 1 never executed #####: 809: return EXIT_FAILURE; unconditional 0 never executed -: 810:} clifm-1.26.3/misc/codecov/checks.c.gcov000066400000000000000000001104711506632037700176300ustar00rootroot00000000000000 -: 0:Source:checks.c -: 1:/* checks.c -- misc check functions */ -: 2: -: 3:/* -: 4: * This file is part of CliFM -: 5: * -: 6: * Copyright (C) 2016-2021, L. Abramovich -: 7: * All rights reserved. -: 8: -: 9: * CliFM is free software; you can redistribute it and/or modify -: 10: * it under the terms of the GNU General Public License as published by -: 11: * the Free Software Foundation; either version 2 of the License, or -: 12: * (at your option) any later version. -: 13: * -: 14: * CliFM is distributed in the hope that it will be useful, -: 15: * but WITHOUT ANY WARRANTY; without even the implied warranty of -: 16: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -: 17: * GNU General Public License for more details. -: 18: * -: 19: * You should have received a copy of the GNU General Public License -: 20: * along with this program; if not, write to the Free Software -: 21: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, -: 22: * MA 02110-1301, USA. -: 23:*/ -: 24: -: 25:#include "helpers.h" -: 26: -: 27:#include -: 28:#include -: 29:#include -: 30: -: 31:#ifdef __NetBSD__ -: 32:# include -: 33:# if __NetBSD_Prereq__(9,99,63) -: 34:# include -: 35:# define _ACL_OK -: 36:# endif /* __NetBSD_Prereq__ */ -: 37:#elif !defined(__HAIKU__) && !defined(__OpenBSD__) -: 38:# include -: 39:# define _ACL_OK -: 40:#endif /* __NetBSD__ */ -: 41: -: 42:#include -: 43:#include -: 44:#include -: 45: -: 46:#include "aux.h" -: 47:#include "misc.h" -: 48: -: 49:/* Terminals known not to be able to handle escape sequences */ -: 50:static const char *UNSUPPORTED_TERM[] = {"dumb", /*"cons25",*/ "emacs", NULL}; -: 51: -: 52:void function check_term called 4 returned 100% blocks executed 53% 4: 53:check_term(void) -: 54:{ 4: 55: char *_term = getenv("TERM"); 4: 55-block 0 call 0 returned 4 4: 56: if (!_term) { branch 0 taken 0 (fallthrough) branch 1 taken 4 #####: 57: fprintf(stderr, _("%s: Error getting terminal type\n"), PROGRAM_NAME); %%%%%: 57-block 0 call 0 never executed call 1 never executed #####: 58: exit(EXIT_FAILURE); call 0 never executed -: 59: } -: 60: -: 61: int i; 12: 62: for (i = 0; UNSUPPORTED_TERM[i]; i++) { 4: 62-block 0 unconditional 0 taken 4 8: 62-block 1 unconditional 1 taken 8 12: 62-block 2 branch 2 taken 8 branch 3 taken 4 (fallthrough) 8: 63: if (*_term == *UNSUPPORTED_TERM[i] 8: 63-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 8 #####: 64: && strcmp(_term, UNSUPPORTED_TERM[i]) == 0) { %%%%%: 64-block 0 branch 0 never executed branch 1 never executed #####: 65: fprintf(stderr, _("%s: '%s': Unsupported terminal. This " %%%%%: 65-block 0 call 0 never executed call 1 never executed -: 66: "terminal cannot understand escape sequences\n"), -: 67: PROGRAM_NAME, UNSUPPORTED_TERM[i]); #####: 68: exit(EXIT_FAILURE); call 0 never executed -: 69: } -: 70: } -: 71: 4: 72: return; 4: 72-block 0 unconditional 0 taken 4 -: 73:} -: 74: -: 75:/* Return 1 if current user has access to FILE. Otherwise, return zero */ -: 76:int function check_file_access called 33188 returned 100% blocks executed 76% 33188: 77:check_file_access(const struct fileinfo file) -: 78:{ 33188: 79: int f = 0; /* Hold file ownership flags */ -: 80: 33188: 81: mode_t val = (file.mode & (mode_t)~S_IFMT); 33188: 82: if (val & S_IRUSR) f |= R_USR; 33188: 82-block 0 branch 0 taken 33188 (fallthrough) branch 1 taken 0 33188: 82-block 1 unconditional 2 taken 33188 33188: 83: if (val & S_IXUSR) f |= X_USR; 33188: 83-block 0 branch 0 taken 28281 (fallthrough) branch 1 taken 4907 28281: 83-block 1 unconditional 2 taken 28281 -: 84: 33188: 85: if (val & S_IRGRP) f |= R_GRP; 33188: 85-block 0 branch 0 taken 28728 (fallthrough) branch 1 taken 4460 28728: 85-block 1 unconditional 2 taken 28728 33188: 86: if (val & S_IXGRP) f |= X_GRP; 33188: 86-block 0 branch 0 taken 28245 (fallthrough) branch 1 taken 4943 28245: 86-block 1 unconditional 2 taken 28245 -: 87: 33188: 88: if (val & S_IROTH) f |= R_OTH; 33188: 88-block 0 branch 0 taken 28715 (fallthrough) branch 1 taken 4473 28715: 88-block 1 unconditional 2 taken 28715 33188: 89: if (val & S_IXOTH) f |= X_OTH; 33188: 89-block 0 branch 0 taken 28236 (fallthrough) branch 1 taken 4952 28236: 89-block 1 unconditional 2 taken 28236 -: 90: 33188: 91: if (file.dir) { 33188: 91-block 0 branch 0 taken 3 (fallthrough) branch 1 taken 33185 3: 92: if ((f & R_USR) && (f & X_USR) && file.uid == user.uid) 3: 92-block 0 branch 0 taken 3 (fallthrough) branch 1 taken 0 3: 92-block 1 branch 2 taken 3 (fallthrough) branch 3 taken 0 3: 92-block 2 branch 4 taken 3 (fallthrough) branch 5 taken 0 3: 93: return 1; 3: 93-block 0 unconditional 0 taken 3 #####: 94: if ((f & R_GRP) && (f & X_GRP) && file.gid == user.gid) %%%%%: 94-block 0 branch 0 never executed branch 1 never executed %%%%%: 94-block 1 branch 2 never executed branch 3 never executed %%%%%: 94-block 2 branch 4 never executed branch 5 never executed #####: 95: return 1; %%%%%: 95-block 0 unconditional 0 never executed #####: 96: if ((f & R_OTH) && (f & X_OTH)) %%%%%: 96-block 0 branch 0 never executed branch 1 never executed %%%%%: 96-block 1 branch 2 never executed branch 3 never executed #####: 97: return 1; %%%%%: 97-block 0 unconditional 0 never executed -: 98: } else { 33185: 99: if ((f & R_USR) && file.uid == user.uid) 33185: 99-block 0 branch 0 taken 33185 (fallthrough) branch 1 taken 0 33185: 99-block 1 branch 2 taken 4988 (fallthrough) branch 3 taken 28197 4988: 100: return 1; 4988: 100-block 0 unconditional 0 taken 4988 28197: 101: if ((f & R_GRP) && file.gid == user.gid) 28197: 101-block 0 branch 0 taken 28188 (fallthrough) branch 1 taken 9 28188: 101-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 28188 #####: 102: return 1; %%%%%: 102-block 0 unconditional 0 never executed 28197: 103: if (f & R_OTH) 28197: 103-block 0 branch 0 taken 28179 (fallthrough) branch 1 taken 18 28179: 104: return 1; 28179: 104-block 0 unconditional 0 taken 28179 -: 105: } -: 106: 18: 107: return 0; 18: 107-block 0 unconditional 0 taken 18 -: 108:} -: 109: -: 110:char * function get_sudo_path called 2 returned 100% blocks executed 50% 2: 111:get_sudo_path(void) -: 112:{ 2: 113: char *p = getenv("CLIFM_SUDO_CMD"); 2: 113-block 0 call 0 returned 2 2*: 114: char *sudo = get_cmd_path(p ? p : DEF_SUDO_CMD); branch 0 taken 0 (fallthrough) branch 1 taken 2 %%%%%: 114-block 0 unconditional 2 never executed 2: 114-block 1 unconditional 3 taken 2 2: 114-block 2 call 4 returned 2 -: 115: 2: 116: if (!sudo) { branch 0 taken 0 (fallthrough) branch 1 taken 2 #####: 117: fprintf(stderr, _("%s: %s: No such file or directory\n"), %%%%%: 117-block 0 branch 0 never executed branch 1 never executed %%%%%: 117-block 1 unconditional 2 never executed %%%%%: 117-block 2 unconditional 3 never executed %%%%%: 117-block 3 call 4 never executed call 5 never executed -: 118: PROGRAM_NAME, p ? p : DEF_SUDO_CMD); #####: 119: return (char *)NULL; unconditional 0 never executed -: 120: } -: 121: 2: 122: return sudo; 2: 122-block 0 unconditional 0 taken 2 -: 123:} -: 124: -: 125:/* Check a file's immutable bit. Returns 1 if true, zero if false, and -: 126: * -1 in case of error */ -: 127:int function check_immutable_bit called 9 returned 100% blocks executed 100% 9: 128:check_immutable_bit(char *file) -: 129:{ -: 130:#if !defined(FS_IOC_GETFLAGS) || !defined(FS_IMMUTABLE_FL) -: 131: UNUSED(file); 9: 132: return 0; 9: 132-block 0 unconditional 0 taken 9 -: 133:#else -: 134: int attr, fd, immut_flag = -1; -: 135: -: 136: fd = open(file, O_RDONLY); -: 137: if (fd == -1) { -: 138: fprintf(stderr, "'%s': %s\n", file, strerror(errno)); -: 139: return -1; -: 140: } -: 141: -: 142: ioctl(fd, FS_IOC_GETFLAGS, &attr); -: 143: if (attr & FS_IMMUTABLE_FL) -: 144: immut_flag = 1; -: 145: else -: 146: immut_flag = 0; -: 147: -: 148: close(fd); -: 149: -: 150: if (immut_flag) -: 151: return 1; -: 152: -: 153: return 0; -: 154:#endif /* !defined(FS_IOC_GETFLAGS) || !defined(FS_IMMUTABLE_FL) */ -: 155:} -: 156: -: 157:/* Return 1 if FILE has some ACL property and zero if none -: 158: * See: https://man7.org/tlpi/code/online/diff/acl/acl_view.c.html */ -: 159:int function is_acl called 217 returned 100% blocks executed 88% 217: 160:is_acl(char *file) -: 161:{ -: 162:#ifndef _ACL_OK -: 163: UNUSED(file); -: 164: return 0; -: 165:#else 217: 166: if (!file || !*file) 217: 166-block 0 branch 0 taken 217 (fallthrough) branch 1 taken 0 217: 166-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 217 #####: 167: return 0; %%%%%: 167-block 0 unconditional 0 never executed -: 168: -: 169: acl_t acl; 217: 170: acl = acl_get_file(file, ACL_TYPE_ACCESS); 217: 170-block 0 call 0 returned 217 -: 171: 217: 172: if (!acl) branch 0 taken 3 (fallthrough) branch 1 taken 214 3: 173: return 0; 3: 173-block 0 unconditional 0 taken 3 -: 174: -: 175: acl_entry_t entry; 214: 176: int entryid, num = 0; -: 177: 214: 178: for (entryid = ACL_FIRST_ENTRY;; entryid = ACL_NEXT_ENTRY) { 214: 178-block 0 unconditional 0 taken 214 856: 179: if (acl_get_entry(acl, entryid, &entry) != 1) 856: 179-block 0 call 0 returned 856 branch 1 taken 214 (fallthrough) branch 2 taken 642 214: 180: break; 214: 180-block 0 unconditional 0 taken 214 642: 181: num++; 642: 181-block 0 unconditional 0 taken 642 -: 182: } -: 183: 214: 184: acl_free(acl); 214: 184-block 0 call 0 returned 214 -: 185: -: 186: /* If num > 3 we have something else besides owner, group, and others, -: 187: * that is, we have at least one ACL property */ 214: 188: if (num > 3) branch 0 taken 0 (fallthrough) branch 1 taken 214 #####: 189: return 1; %%%%%: 189-block 0 unconditional 0 never executed -: 190: 214: 191: return 0; 214: 191-block 0 unconditional 0 taken 214 -: 192:#endif /* _ACL_OK */ -: 193:} -: 194: -: 195:/* Check whether a given string contains only digits. Returns 1 if true -: 196: * and 0 if false. It does not work with negative numbers */ -: 197:int function is_number called 3363 returned 100% blocks executed 100% 3363: 198:is_number(const char *restrict str) -: 199:{ 20924: 200: for (; *str; str++) 3363: 200-block 0 unconditional 0 taken 3363 17561: 200-block 1 unconditional 1 taken 17561 20924: 200-block 2 branch 2 taken 18196 branch 3 taken 2728 (fallthrough) 18196: 201: if (*str > '9' || *str < '0') 18196: 201-block 0 branch 0 taken 17667 (fallthrough) branch 1 taken 529 17667: 201-block 1 branch 2 taken 106 (fallthrough) branch 3 taken 17561 635: 202: return 0; 635: 202-block 0 unconditional 0 taken 635 -: 203: 2728: 204: return 1; 2728: 204-block 0 unconditional 0 taken 2728 -: 205:} -: 206: -: 207:/* Check CMD against a list of internal commands */ -: 208:int function is_internal_c called 190 returned 100% blocks executed 79% 190: 209:is_internal_c(const char *restrict cmd) -: 210:{ 190: 211: const char *int_cmds[] = { -: 212: "?", "help", -: 213: "ac", "ad", -: 214: "acd", "autocd", -: 215: "actions", -: 216: "alias", -: 217: "ao", "auto-open", -: 218: "b", "back", -: 219: "bh", "fh", -: 220: "bm", "bookmarks", -: 221: "br", "bulk", -: 222: "c", "cp", -: 223: "cc", "colors", -: 224: "cd", -: 225: "cl", "columns", -: 226: "cmd", "commands", -: 227: "cs", "colorschemes", -: 228: "d", "dup", -: 229: "ds", "desel", -: 230: "edit", -: 231: "exp", "export", -: 232: "ext", -: 233: "f", "forth", -: 234: "fc", -: 235: "ff", "folders-first", -: 236: "fs", -: 237: "ft", "filter", -: 238: "history", -: 239: "hf", "hidden", -: 240: "icons", -: 241: "jump", "je", "jc", "jp", "jo", -: 242: "kb", "keybinds", -: 243: "l", "ln", "le", -: 244: "lm", -: 245: "log", -: 246: "m", "mv", -: 247: "md", "mkdir", -: 248: "mf", -: 249: "mm", "mime", -: 250: "mp", "mountpoints", -: 251: "msg", "messages", -: 252: "n", "new", -: 253: "net", -: 254: "o", "open", -: 255: "opener", -: 256: "p", "pp", "pr", "prop", -: 257: "path", "cwd", -: 258: "paste", -: 259: "pf", "prof", "profile", -: 260: "pg", "pager", -: 261: "pin", "unpin", -: 262: "quit", -: 263: "r", "rm", -: 264: "rf", "refresh", -: 265: "rl", "reload", -: 266: "s", "sel", -: 267: "sb", "selbox", -: 268: "shell", -: 269: "splash", -: 270: "st", "sort", -: 271: "t", "tr", "trash", -: 272: "te", -: 273: "tips", -: 274: "touch", -: 275: "u", "undel", "untrash", -: 276: "uc", "unicode", -: 277: "unlink", -: 278: "v", -: 279: "ver", "version", -: 280: "ws", -: 281: "x", "X", -: 282: NULL}; -: 283: 190: 284: int found = 0; 190: 285: int i = (int)(sizeof(int_cmds) / sizeof(char *)) - 1; -: 286: 21591: 287: while (--i >= 0) { 190: 287-block 0 unconditional 0 taken 190 21591: 287-block 1 branch 1 taken 21435 branch 2 taken 156 (fallthrough) 21435: 288: if (*cmd == *int_cmds[i] && strcmp(cmd, int_cmds[i]) == 0) { 21435: 288-block 0 branch 0 taken 1100 (fallthrough) branch 1 taken 20335 1100: 288-block 1 branch 2 taken 34 (fallthrough) branch 3 taken 1066 34: 289: found = 1; 34: 290: break; 34: 290-block 0 unconditional 0 taken 34 -: 291: } -: 292: } -: 293: 190: 294: if (found) 190: 294-block 0 branch 0 taken 34 (fallthrough) branch 1 taken 156 34: 295: return 1; 34: 295-block 0 unconditional 0 taken 34 -: 296: -: 297: /* Check for the search and history functions as well */ 156: 298: else if ((*cmd == '/' && access(cmd, F_OK) != 0) || (*cmd == '!' 156: 298-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 155 1: 298-block 1 call 2 returned 1 branch 3 taken 0 (fallthrough) branch 4 taken 1 155: 298-block 2 branch 5 taken 0 (fallthrough) branch 6 taken 155 #####: 299: && (_ISDIGIT(cmd[1]) || (cmd[1] == '-' && _ISDIGIT(cmd[2])) %%%%%: 299-block 0 branch 0 never executed branch 1 never executed %%%%%: 299-block 1 branch 2 never executed branch 3 never executed %%%%%: 299-block 2 branch 4 never executed branch 5 never executed #####: 300: || cmd[1] == '!'))) %%%%%: 300-block 0 branch 0 never executed branch 1 never executed 1: 301: return 1; 1: 301-block 0 unconditional 0 taken 1 -: 302: 155: 303: return 0; 155: 303-block 0 unconditional 0 taken 155 -: 304:} -: 305: -: 306:/* Check cmd against a list of internal commands. Used by parse_input_str() -: 307: * to know if it should perform additional expansions, like glob, regex, -: 308: * tilde, and so on. Only internal commands dealing with file names -: 309: * should be checked here */ -: 310:int function is_internal called 500 returned 100% blocks executed 100% 500: 311:is_internal(const char *cmd) -: 312:{ 500: 313: const char *int_cmds[] = { -: 314: "cd", -: 315: "o", "open", -: 316: "s", "sel", -: 317: "p", "pr", "prop", -: 318: "r", -: 319: "t", "tr", "trash", -: 320: "mm", "mime", -: 321: "n", "new", -: 322: "bm", "bookmarks", -: 323: "br", "bulk", -: 324: "ac", "ad", -: 325: "exp", "export", -: 326: "pin", -: 327: "jc", "jp", -: 328: "bl", "le", -: 329: "te", -: 330: NULL}; -: 331: 500: 332: int found = 0; 500: 333: int i = (int)(sizeof(int_cmds) / sizeof(char *)) - 1; -: 334: 14626: 335: while (--i >= 0) { 500: 335-block 0 unconditional 0 taken 500 14626: 335-block 1 branch 1 taken 14195 branch 2 taken 431 (fallthrough) 14195: 336: if (*cmd == *int_cmds[i] && strcmp(cmd, int_cmds[i]) == 0) { 14195: 336-block 0 branch 0 taken 703 (fallthrough) branch 1 taken 13492 703: 336-block 1 branch 2 taken 69 (fallthrough) branch 3 taken 634 69: 337: found = 1; 69: 338: break; 69: 338-block 0 unconditional 0 taken 69 -: 339: } -: 340: } -: 341: 500: 342: if (found) 500: 342-block 0 branch 0 taken 69 (fallthrough) branch 1 taken 431 69: 343: return 1; 69: 343-block 0 unconditional 0 taken 69 -: 344: -: 345: /* Check for the search function as well */ 431: 346: else if (*cmd == '/' && access(cmd, F_OK) != 0) 431: 346-block 0 branch 0 taken 22 (fallthrough) branch 1 taken 409 22: 346-block 1 call 2 returned 22 branch 3 taken 5 (fallthrough) branch 4 taken 17 5: 347: return 1; 5: 347-block 0 unconditional 0 taken 5 -: 348: 426: 349: return 0; 426: 349-block 0 unconditional 0 taken 426 -: 350:} -: 351: -: 352:/* Return one if STR is a command in PATH or zero if not */ -: 353:int function is_bin_cmd called 15 returned 100% blocks executed 94% 15: 354:is_bin_cmd(const char *str) -: 355:{ 15: 356: char *p = (char *)str, *q = (char *)str; 15: 357: int index = 0, space_index = -1; -: 358: 85: 359: while (*p) { 15: 359-block 0 unconditional 0 taken 15 85: 359-block 1 branch 1 taken 78 branch 2 taken 7 (fallthrough) 78: 360: if (*p == ' ') { 78: 360-block 0 branch 0 taken 8 (fallthrough) branch 1 taken 70 8: 361: *p = '\0'; 8: 362: space_index = index; 8: 363: break; 8: 363-block 0 unconditional 0 taken 8 -: 364: } 70: 365: p++; 70: 366: index++; 70: 366-block 0 unconditional 0 taken 70 -: 367: } -: 368: -: 369: size_t i; 52503: 370: for (i = 0; bin_commands[i]; i++) { 15: 370-block 0 unconditional 0 taken 15 52488: 370-block 1 unconditional 1 taken 52488 52503: 370-block 2 branch 2 taken 52489 branch 3 taken 14 (fallthrough) 52489: 371: if (*q == *bin_commands[i] && q[1] == bin_commands[i][1] && strcmp(q, bin_commands[i]) == 0) { 52489: 371-block 0 branch 0 taken 1970 (fallthrough) branch 1 taken 50519 1970: 371-block 1 branch 2 taken 3 (fallthrough) branch 3 taken 1967 3: 371-block 2 branch 4 taken 1 (fallthrough) branch 5 taken 2 1: 372: if (space_index != -1) 1: 372-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 1 #####: 373: q[space_index] = ' '; %%%%%: 373-block 0 unconditional 0 never executed 1: 374: return 1; 1: 374-block 0 unconditional 0 taken 1 -: 375: } -: 376: } -: 377: 14: 378: if (space_index != -1) 14: 378-block 0 branch 0 taken 8 (fallthrough) branch 1 taken 6 8: 379: q[space_index] = ' '; 8: 379-block 0 unconditional 0 taken 8 -: 380: 14: 381: return 0; 14: 381-block 0 unconditional 0 taken 14 -: 382:} -: 383: -: 384:/* Returns 0 if digit is found and preceded by a letter in STR, or one if not */ -: 385:int function digit_found called 503 returned 100% blocks executed 100% 503: 386:digit_found(const char *str) -: 387:{ 503: 388: char *p = (char *)str; 503: 389: int c = 0; -: 390: 2458: 391: while (*p) { 503: 391-block 0 unconditional 0 taken 503 2458: 391-block 1 branch 1 taken 1970 branch 2 taken 488 (fallthrough) 1970: 392: if (c++ && _ISDIGIT(*p) && _ISALPHA(*(p - 1))) 1970: 392-block 0 branch 0 taken 1467 (fallthrough) branch 1 taken 503 1467: 392-block 1 branch 2 taken 83 (fallthrough) branch 3 taken 1384 83: 392-block 2 branch 4 taken 15 (fallthrough) branch 5 taken 68 15: 392-block 3 branch 6 taken 15 (fallthrough) branch 7 taken 0 15: 393: return 1; 15: 393-block 0 unconditional 0 taken 15 1955: 394: p++; 1955: 394-block 0 unconditional 0 taken 1955 -: 395: } -: 396: 488: 397: return 0; 488: 397-block 0 unconditional 0 taken 488 -: 398:} -: 399: -: 400:/* Check if the 'file' command is available: it is needed by the mime -: 401: * function */ -: 402:/* -: 403:void -: 404:file_cmd_check(void) -: 405:{ -: 406: file_cmd_path = get_cmd_path("file"); -: 407: -: 408: if (!file_cmd_path) { -: 409: flags &= ~FILE_CMD_OK; -: 410: _err('n', PRINT_PROMPT, _("%s: 'file' command not found. " -: 411: "Specify an application when opening files. Ex: 'o 12 nano' " -: 412: "or just 'nano 12'\n"), PROGRAM_NAME); -: 413: } -: 414: -: 415: else -: 416: flags |= FILE_CMD_OK; -: 417:} */ -: 418: -: 419:int function check_regex called 141 returned 100% blocks executed 95% 141: 420:check_regex(char *str) -: 421:{ 141: 422: if (!str || !*str) 141: 422-block 0 branch 0 taken 141 (fallthrough) branch 1 taken 0 141: 422-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 141 #####: 423: return EXIT_FAILURE; %%%%%: 423-block 0 unconditional 0 never executed -: 424: 141: 425: int char_found = 0; 141: 426: char *p = str; -: 427: 1191: 428: while (*p) { 141: 428-block 0 unconditional 0 taken 141 1191: 428-block 1 branch 1 taken 1069 branch 2 taken 122 (fallthrough) -: 429: /* If STR contains at least one of the following chars */ 1069: 430: if (*p == '*' || *p == '?' || *p == '[' || *p == '{' || *p == '^' 1069: 430-block 0 branch 0 taken 1063 (fallthrough) branch 1 taken 6 1063: 430-block 1 branch 2 taken 1063 (fallthrough) branch 3 taken 0 1063: 430-block 2 branch 4 taken 1063 (fallthrough) branch 5 taken 0 1063: 430-block 3 branch 6 taken 1063 (fallthrough) branch 7 taken 0 1063: 430-block 4 branch 8 taken 1062 (fallthrough) branch 9 taken 1 1062: 431: || *p == '.' || *p == '|' || *p == '+' || *p == '$') { 1062: 431-block 0 branch 0 taken 1050 (fallthrough) branch 1 taken 12 1050: 431-block 1 branch 2 taken 1050 (fallthrough) branch 3 taken 0 1050: 431-block 2 branch 4 taken 1050 (fallthrough) branch 5 taken 0 1050: 431-block 3 branch 6 taken 0 (fallthrough) branch 7 taken 1050 19: 432: char_found = 1; 19: 433: break; 19: 433-block 0 unconditional 0 taken 19 -: 434: } -: 435: 1050: 436: p++; 1050: 436-block 0 unconditional 0 taken 1050 -: 437: } -: 438: -: 439: /* And if STR is not a file name, take it as a possible regex */ 141: 440: if (char_found) 141: 440-block 0 branch 0 taken 19 (fallthrough) branch 1 taken 122 19: 441: if (access(str, F_OK) == -1) 19: 441-block 0 call 0 returned 19 branch 1 taken 9 (fallthrough) branch 2 taken 10 9: 442: return EXIT_SUCCESS; 9: 442-block 0 unconditional 0 taken 9 -: 443: 132: 444: return EXIT_FAILURE; 132: 444-block 0 unconditional 0 taken 132 -: 445:} -: 446: -: 447:/* Returns the parsed aliased command in an array of strings, if -: 448: * matching alias is found, or NULL if not. */ -: 449:char ** function check_for_alias called 406 returned 100% blocks executed 38% 406: 450:check_for_alias(char **args) -: 451:{ 406: 452: if (!aliases_n || !aliases || !args) 406: 452-block 0 branch 0 taken 404 (fallthrough) branch 1 taken 2 404: 452-block 1 branch 2 taken 404 (fallthrough) branch 3 taken 0 404: 452-block 2 branch 4 taken 0 (fallthrough) branch 5 taken 404 2: 453: return (char **)NULL; 2: 453-block 0 unconditional 0 taken 2 -: 454: 404: 455: char *aliased_cmd = (char *)NULL; 404: 456: size_t cmd_len = strlen(args[0]); -: 457: char tmp_cmd[PATH_MAX * 2 + 1]; 404: 458: snprintf(tmp_cmd, sizeof(tmp_cmd), "%s=", args[0]); -: 459: 404: 460: register int i = (int)aliases_n; 2424: 461: while (--i >= 0) { 404: 461-block 0 unconditional 0 taken 404 2424: 461-block 1 branch 1 taken 2020 branch 2 taken 404 (fallthrough) -: 462: 2020*: 463: if (!aliases[i]) 2020: 463-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 2020 #####: 464: continue; %%%%%: 464-block 0 unconditional 0 never executed -: 465: /* Look for this string: "command=", in the aliases file */ -: 466: /* If a match is found */ -: 467: 2020: 468: if (*aliases[i] != *args[0] || 2020: 468-block 0 branch 0 taken 81 (fallthrough) branch 1 taken 1939 81: 469: strncmp(tmp_cmd, aliases[i], cmd_len + 1) != 0) 81: 469-block 0 branch 0 taken 81 (fallthrough) branch 1 taken 0 2020: 470: continue; 2020: 470-block 0 unconditional 0 taken 2020 -: 471: -: 472: /* Get the aliased command */ #####: 473: aliased_cmd = strbtw(aliases[i], '\'', '\''); %%%%%: 473-block 0 call 0 never executed -: 474: #####: 475: if (!aliased_cmd) branch 0 never executed branch 1 never executed #####: 476: return (char **)NULL; %%%%%: 476-block 0 unconditional 0 never executed -: 477: #####: 478: if (!*aliased_cmd) { /* zero length */ %%%%%: 478-block 0 branch 0 never executed branch 1 never executed #####: 479: free(aliased_cmd); #####: 480: return (char **)NULL; %%%%%: 480-block 0 unconditional 0 never executed -: 481: } -: 482: #####: 483: args_n = 0; /* Reset args_n to be used by parse_input_str() */ -: 484: -: 485: /* Parse the aliased cmd */ #####: 486: char **alias_comm = parse_input_str(aliased_cmd); %%%%%: 486-block 0 call 0 never executed #####: 487: free(aliased_cmd); -: 488: #####: 489: if (!alias_comm) { branch 0 never executed branch 1 never executed #####: 490: args_n = 0; #####: 491: fprintf(stderr, _("%s: Error parsing aliased command\n"), PROGRAM_NAME); %%%%%: 491-block 0 call 0 never executed call 1 never executed #####: 492: return (char **)NULL; unconditional 0 never executed -: 493: } -: 494: -: 495: register size_t j; -: 496: -: 497: /* Add input parameters, if any, to alias_comm */ #####: 498: if (args[1]) { %%%%%: 498-block 0 branch 0 never executed branch 1 never executed #####: 499: for (j = 1; args[j]; j++) { %%%%%: 499-block 0 unconditional 0 never executed %%%%%: 499-block 1 branch 1 never executed branch 2 never executed #####: 500: alias_comm = (char **)xrealloc(alias_comm, #####: 501: (++args_n + 2) * sizeof(char *)); %%%%%: 501-block 0 call 0 never executed #####: 502: alias_comm[args_n] = savestring(args[j], unconditional 0 never executed #####: 503: strlen(args[j])); call 0 never executed -: 504: } -: 505: } -: 506: -: 507: /* Add a terminating NULL string */ #####: 508: alias_comm[args_n + 1] = (char *)NULL; -: 509: -: 510: /* Free original command */ #####: 511: for (j = 0; args[j]; j++) %%%%%: 511-block 0 unconditional 0 never executed %%%%%: 511-block 1 branch 1 never executed branch 2 never executed #####: 512: free(args[j]); %%%%%: 512-block 0 unconditional 0 never executed #####: 513: free(args); -: 514: #####: 515: return alias_comm; %%%%%: 515-block 0 unconditional 0 never executed -: 516: } -: 517: 404: 518: return (char **)NULL; 404: 518-block 0 unconditional 0 taken 404 -: 519:} -: 520: -: 521:/* Keep only the last MAX records in FILE */ -: 522:void function check_file_size called 30 returned 100% blocks executed 74% 30: 523:check_file_size(char *file, int max) -: 524:{ 30: 525: if (!config_ok) 30: 525-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 30 #####: 526: return; %%%%%: 526-block 0 unconditional 0 never executed -: 527: -: 528: /* Create the file, if it doesn't exist */ 30: 529: FILE *fp = (FILE *)NULL; -: 530: struct stat attr; -: 531: -: 532: int fd; 30: 533: if (stat(file, &attr) == -1) { 30: 533-block 0 call 0 returned 30 branch 1 taken 2 (fallthrough) branch 2 taken 28 2: 534: fp = open_fstream_w(file, &fd); 2: 534-block 0 call 0 returned 2 2: 535: if (!fp) { branch 0 taken 0 (fallthrough) branch 1 taken 2 #####: 536: _err(0, NOPRINT_PROMPT, "%s: '%s': %s\n", PROGRAM_NAME, call 0 never executed unconditional 1 never executed #####: 537: file, strerror(errno)); %%%%%: 537-block 0 call 0 never executed -: 538: } else { 2: 539: close_fstream(fp, fd); 2: 539-block 0 call 0 returned 2 unconditional 1 taken 2 -: 540: } -: 541: 2: 542: return; /* Return anyway, for, being a new empty file, there's 2: 542-block 0 unconditional 0 taken 2 -: 543: no need to truncate it */ -: 544: } -: 545: -: 546: /* Once we know the files exists, keep only MAX entries */ 28: 547: fp = open_fstream_r(file, &fd); 28: 547-block 0 call 0 returned 28 28: 548: if (!fp) { branch 0 taken 0 (fallthrough) branch 1 taken 28 #####: 549: _err(0, NOPRINT_PROMPT, "%s: log: %s: %s\n", PROGRAM_NAME, call 0 never executed #####: 550: file, strerror(errno)); %%%%%: 550-block 0 call 0 never executed #####: 551: return; unconditional 0 never executed -: 552: } -: 553: 28: 554: int n = 0, c; -: 555: -: 556: /* Count newline chars to get amount of lines in the file */ 292651: 557: while ((c = fgetc(fp)) != EOF) { 28: 557-block 0 unconditional 0 taken 28 292651: 557-block 1 call 1 returned 292651 branch 2 taken 292623 branch 3 taken 28 (fallthrough) 292623: 558: if (c == '\n') 292623: 558-block 0 branch 0 taken 4248 (fallthrough) branch 1 taken 288375 4248: 559: n++; 4248: 559-block 0 unconditional 0 taken 4248 -: 560: } -: 561: 28: 562: if (n <= max) { 28: 562-block 0 branch 0 taken 26 (fallthrough) branch 1 taken 2 26: 563: close_fstream(fp, fd); 26: 563-block 0 call 0 returned 26 26: 564: return; unconditional 0 taken 26 -: 565: } -: 566: -: 567: /* Set the file pointer to the beginning of the log file */ 2: 568: fseek(fp, 0, SEEK_SET); 2: 568-block 0 call 0 returned 2 -: 569: -: 570: /* Create a temp file to store only newest logs */ 2: 571: char *rand_ext = gen_rand_str(6); call 0 returned 2 2: 572: if (!rand_ext) { branch 0 taken 0 (fallthrough) branch 1 taken 2 #####: 573: close_fstream(fp, fd); %%%%%: 573-block 0 call 0 never executed #####: 574: return; unconditional 0 never executed -: 575: } -: 576: 2: 577: char *tmp = (char *)xnmalloc(strlen(config_dir) + 12, sizeof(char)); 2: 577-block 0 call 0 returned 2 2: 578: sprintf(tmp, "%s/log.%s", config_dir, rand_ext); 2: 579: free(rand_ext); -: 580: -: 581: int fdd; 2: 582: FILE *fpp = open_fstream_w(tmp, &fdd); call 0 returned 2 2: 583: if (!fpp) { branch 0 taken 0 (fallthrough) branch 1 taken 2 #####: 584: fprintf(stderr, "log: %s: %s", tmp, strerror(errno)); %%%%%: 584-block 0 call 0 never executed call 1 never executed #####: 585: close_fstream(fp, fd); call 0 never executed #####: 586: free(tmp); #####: 587: return; unconditional 0 never executed -: 588: } -: 589: 2: 590: int i = 1; 2: 591: size_t line_size = 0; 2: 592: char *line = (char *)NULL; -: 593: 522: 594: while (getline(&line, &line_size, fp) > 0) { 2: 594-block 0 unconditional 0 taken 2 522: 594-block 1 call 1 returned 522 branch 2 taken 520 branch 3 taken 2 (fallthrough) -: 595: /* Delete old entries = copy only new ones */ 520: 596: if (i++ >= n - (max - 1)) 520: 596-block 0 branch 0 taken 200 (fallthrough) branch 1 taken 320 200: 597: fprintf(fpp, "%s", line); 200: 597-block 0 call 0 returned 200 unconditional 1 taken 200 -: 598: } -: 599: 2: 600: free(line); 2: 601: unlinkat(fd, file, 0); 2: 601-block 0 call 0 returned 2 2: 602: renameat(fdd, tmp, fd, file); call 0 returned 2 2: 603: close_fstream(fpp, fdd); call 0 returned 2 2: 604: close_fstream(fp, fd); call 0 returned 2 2: 605: free(tmp); -: 606: 2: 607: return; unconditional 0 taken 2 -: 608:} clifm-1.26.3/misc/codecov/colors.c.gcov000066400000000000000000004065701506632037700177010ustar00rootroot00000000000000 -: 0:Source:colors.c -: 1:/* colors.c -- functions to control interface color */ -: 2: -: 3:/* -: 4: * This file is part of CliFM -: 5: * -: 6: * Copyright (C) 2016-2021, L. Abramovich -: 7: * All rights reserved. -: 8: -: 9: * CliFM is free software; you can redistribute it and/or modify -: 10: * it under the terms of the GNU General Public License as published by -: 11: * the Free Software Foundation; either version 2 of the License, or -: 12: * (at your option) any later version. -: 13: * -: 14: * CliFM is distributed in the hope that it will be useful, -: 15: * but WITHOUT ANY WARRANTY; without even the implied warranty of -: 16: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -: 17: * GNU General Public License for more details. -: 18: * -: 19: * You should have received a copy of the GNU General Public License -: 20: * along with this program; if not, write to the Free Software -: 21: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, -: 22: * MA 02110-1301, USA. -: 23:*/ -: 24: -: 25:#include "helpers.h" -: 26: -: 27:#include -: 28:#include -: 29:#include -: 30:#ifdef __linux__ -: 31:#include -: 32:#endif -: 33:#include -: 34:#include -: 35:#include -: 36:#include -: 37: -: 38:#include "aux.h" -: 39:#include "colors.h" -: 40:#include "listing.h" -: 41:#include "mime.h" -: 42:#include "misc.h" -: 43:#include "messages.h" -: 44:#include "file_operations.h" -: 45: -: 46:/* Returns a pointer to the corresponding color code for EXT, if some -: 47: * color was defined */ -: 48:char * function get_ext_color called 3826 returned 100% blocks executed 95% 3826: 49:get_ext_color(const char *ext) -: 50:{ 3826: 51: if (!ext || !ext_colors_n) 3826: 51-block 0 branch 0 taken 3826 (fallthrough) branch 1 taken 0 3826: 51-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 3826 #####: 52: return (char *)NULL; %%%%%: 52-block 0 unconditional 0 never executed -: 53: 3826: 54: ext++; -: 55: 3826: 56: int i = (int)ext_colors_n; 246690: 57: while (--i >= 0) { 3826: 57-block 0 unconditional 0 taken 3826 246690: 57-block 1 branch 1 taken 243356 branch 2 taken 3334 (fallthrough) 243356: 58: if (!ext_colors[i] || !*ext_colors[i] || !ext_colors[i][2]) 243356: 58-block 0 branch 0 taken 243356 (fallthrough) branch 1 taken 0 243356: 58-block 1 branch 2 taken 239530 (fallthrough) branch 3 taken 3826 239530: 58-block 2 branch 4 taken 0 (fallthrough) branch 5 taken 239530 3826: 59: continue; 3826: 59-block 0 unconditional 0 taken 3826 -: 60: 239530: 61: char *p = (char *)ext, 239530: 62: *q = ext_colors[i]; -: 63: /* +2 because stored extensions have this form: *.ext */ 239530: 64: q += 2; -: 65: 239530: 66: size_t match = 1; 247233: 67: while (*p) { 239530: 67-block 0 unconditional 0 taken 239530 247233: 67-block 1 branch 1 taken 245871 branch 2 taken 1362 (fallthrough) 245871: 68: if (*p++ != *q++) { 245871: 68-block 0 branch 0 taken 238168 (fallthrough) branch 1 taken 7703 238168: 69: match = 0; 238168: 70: break; 238168: 70-block 0 unconditional 0 taken 238168 -: 71: } -: 72: } -: 73: 239530: 74: if (!match || *q != '=') 239530: 74-block 0 branch 0 taken 1362 (fallthrough) branch 1 taken 238168 1362: 74-block 1 branch 2 taken 870 (fallthrough) branch 3 taken 492 239038: 75: continue; 239038: 75-block 0 unconditional 0 taken 239038 492: 76: return ++q; 492: 76-block 0 unconditional 0 taken 492 -: 77: } -: 78: 3334: 79: return (char *)NULL; 3334: 79-block 0 unconditional 0 taken 3334 -: 80:} -: 81: -: 82:/* Check if STR has the format of a color code string (a number or a -: 83: * semicolon list (max 12 fields) of numbers of at most 3 digits each). -: 84: * Returns 1 if true and 0 if false. */ -: 85:static int function is_color_code called 3028 returned 100% blocks executed 76% 3028: 86:is_color_code(const char *str) -: 87:{ 3028: 88: if (!str || !*str) 3028: 88-block 0 branch 0 taken 3028 (fallthrough) branch 1 taken 0 3028: 88-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 3028 #####: 89: return 0; %%%%%: 89-block 0 unconditional 0 never executed -: 90: 3028: 91: size_t digits = 0, semicolon = 0; -: 92: 20761: 93: while (*str) { 3028: 93-block 0 unconditional 0 taken 3028 20761: 93-block 1 branch 1 taken 17733 branch 2 taken 3028 (fallthrough) 17733: 94: if (*str >= '0' && *str <= '9') { 17733: 94-block 0 branch 0 taken 17733 (fallthrough) branch 1 taken 0 17733: 94-block 1 branch 2 taken 13879 (fallthrough) branch 3 taken 3854 13879: 95: digits++; 13879: 95-block 0 unconditional 0 taken 13879 3854: 96: } else if (*str == ';') { 3854: 96-block 0 branch 0 taken 3854 (fallthrough) branch 1 taken 0 3854: 97: if (*(str + 1) == ';') /* Consecutive semicolons */ 3854: 97-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 3854 #####: 98: return 0; %%%%%: 98-block 0 unconditional 0 never executed 3854: 99: digits = 0; 3854: 100: semicolon++; 3854: 100-block 0 unconditional 0 taken 3854 #####: 101: } else if (*str != '\n') { %%%%%: 101-block 0 branch 0 never executed branch 1 never executed -: 102: /* Neither digit nor semicolon */ #####: 103: return 0; %%%%%: 103-block 0 unconditional 0 never executed -: 104: } 17733: 105: str++; 17733: 105-block 0 unconditional 0 taken 17733 -: 106: } -: 107: -: 108: /* No digits at all, ending semicolon, more than eleven fields, or -: 109: * more than three consecutive digits */ 3028: 110: if (!digits || digits > 3 || semicolon > 11) 3028: 110-block 0 branch 0 taken 3028 (fallthrough) branch 1 taken 0 3028: 110-block 1 branch 2 taken 3028 (fallthrough) branch 3 taken 0 3028: 110-block 2 branch 4 taken 0 (fallthrough) branch 5 taken 3028 #####: 111: return 0; %%%%%: 111-block 0 unconditional 0 never executed -: 112: -: 113: /* At this point, we have a semicolon separated string of digits (3 -: 114: * consecutive max) with at most 12 fields. The only thing not -: 115: * validated here are numbers themselves */ 3028: 116: return 1; 3028: 116-block 0 unconditional 0 taken 3028 -: 117:} -: 118: -: 119:/* Strip color lines from the config file (FiletypeColors, if mode is -: 120: * 't', and ExtColors, if mode is 'x') returning the same string -: 121: * containing only allowed characters */ -: 122:static char * function strip_color_line called 78 returned 100% blocks executed 92% 78: 123:strip_color_line(const char *str, char mode) -: 124:{ 78: 125: if (!str || !*str) 78: 125-block 0 branch 0 taken 78 (fallthrough) branch 1 taken 0 78: 125-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 78 #####: 126: return (char *)NULL; %%%%%: 126-block 0 unconditional 0 never executed -: 127: 78: 128: char *buf = (char *)xnmalloc(strlen(str) + 1, sizeof(char)); 78: 128-block 0 call 0 returned 78 78: 129: size_t len = 0; -: 130: 78: 131: switch (mode) { branch 0 taken 52 branch 1 taken 26 branch 2 taken 0 52: 132: case 't': /* di=01;31: */ 12689: 133: while (*str) { 52: 133-block 0 unconditional 0 taken 52 12689: 133-block 1 branch 1 taken 12637 branch 2 taken 52 (fallthrough) 12637: 134: if ((*str >= '0' && *str <= '9') || (*str >= 'a' && *str <= 'z') 12637: 134-block 0 branch 0 taken 12481 (fallthrough) branch 1 taken 156 12481: 134-block 1 branch 2 taken 6694 (fallthrough) branch 3 taken 5787 6850: 134-block 2 branch 4 taken 2532 (fallthrough) branch 5 taken 4318 2532: 134-block 3 branch 6 taken 0 (fallthrough) branch 7 taken 2532 4318: 135: || *str == '=' || *str == ';' || *str == ':') 4318: 135-block 0 branch 0 taken 3052 (fallthrough) branch 1 taken 1266 3052: 135-block 1 branch 2 taken 1422 (fallthrough) branch 3 taken 1630 1422: 135-block 2 branch 4 taken 1266 (fallthrough) branch 5 taken 156 12481: 136: buf[len++] = *str; 12481: 136-block 0 unconditional 0 taken 12481 12637: 137: str++; 12637: 137-block 0 unconditional 0 taken 12637 -: 138: } 52: 139: break; 52: 139-block 0 unconditional 0 taken 52 -: 140: 26: 141: case 'x': /* *.tar=01;31: */ 22832: 142: while (*str) { 26: 142-block 0 unconditional 0 taken 26 22832: 142-block 1 branch 1 taken 22806 branch 2 taken 26 (fallthrough) 22806: 143: if ((*str >= '0' && *str <= '9') || (*str >= 'a' && *str <= 'z') 22806: 143-block 0 branch 0 taken 19204 (fallthrough) branch 1 taken 3602 19204: 143-block 1 branch 2 taken 10826 (fallthrough) branch 3 taken 8378 14428: 143-block 2 branch 4 taken 5078 (fallthrough) branch 5 taken 9350 5078: 143-block 3 branch 6 taken 0 (fallthrough) branch 7 taken 5078 9350*: 144: || (*str >= 'A' && *str <= 'Z') || *str == '*' || *str == '.' 9350: 144-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 9350 %%%%%: 144-block 1 branch 2 never executed branch 3 never executed 9350: 144-block 2 branch 4 taken 7588 (fallthrough) branch 5 taken 1762 7588: 144-block 3 branch 6 taken 5826 (fallthrough) branch 7 taken 1762 5826: 145: || *str == '=' || *str == ';' || *str == ':') 5826: 145-block 0 branch 0 taken 4064 (fallthrough) branch 1 taken 1762 4064: 145-block 1 branch 2 taken 1840 (fallthrough) branch 3 taken 2224 1840: 145-block 2 branch 4 taken 1762 (fallthrough) branch 5 taken 78 22728: 146: buf[len++] = *str; 22728: 146-block 0 unconditional 0 taken 22728 22806: 147: str++; 22806: 147-block 0 unconditional 0 taken 22806 -: 148: } 26: 149: break; 26: 149-block 0 unconditional 0 taken 26 -: 150: } -: 151: 78: 152: if (!len || !*buf) { 78: 152-block 0 branch 0 taken 78 (fallthrough) branch 1 taken 0 78: 152-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 78 #####: 153: free(buf); #####: 154: return (char *)NULL; %%%%%: 154-block 0 unconditional 0 never executed -: 155: } -: 156: 78: 157: buf[len] = '\0'; 78: 158: return buf; 78: 158-block 0 unconditional 0 taken 78 -: 159:} -: 160: -: 161:static void function free_colors called 3 returned 100% blocks executed 100% 3: 162:free_colors(void) -: 163:{ -: 164: /* Reset whatever value was loaded */ 3: 165: *sh_c = '\0'; 3: 166: *sf_c = '\0'; 3: 167: *sc_c = '\0'; 3: 168: *sx_c = '\0'; 3: 169: *bm_c = '\0'; 3: 170: *dl_c = '\0'; 3: 171: *el_c = '\0'; 3: 172: *mi_c = '\0'; 3: 173: *tx_c = '\0'; 3: 174: *df_c = '\0'; 3: 175: *dc_c = '\0'; 3: 176: *wc_c = '\0'; 3: 177: *dh_c = '\0'; 3: 178: *li_c = '\0'; 3: 179: *ti_c = '\0'; 3: 180: *em_c = '\0'; 3: 181: *wm_c = '\0'; 3: 182: *nm_c = '\0'; 3: 183: *si_c = '\0'; 3: 184: *nd_c = '\0'; 3: 185: *nf_c = '\0'; 3: 186: *di_c = '\0'; 3: 187: *ed_c = '\0'; 3: 188: *ne_c = '\0'; 3: 189: *ex_c = '\0'; 3: 190: *ee_c = '\0'; 3: 191: *bd_c = '\0'; 3: 192: *ln_c = '\0'; 3: 193: *mh_c = '\0'; 3: 194: *or_c = '\0'; 3: 195: *so_c = '\0'; 3: 196: *pi_c = '\0'; 3: 197: *cd_c = '\0'; 3: 198: *fi_c = '\0'; 3: 199: *ef_c = '\0'; 3: 200: *su_c = '\0'; 3: 201: *sg_c = '\0'; 3: 202: *ca_c = '\0'; 3: 203: *st_c = '\0'; 3: 204: *tw_c = '\0'; 3: 205: *ow_c = '\0'; 3: 206: *no_c = '\0'; 3: 207: *uf_c = '\0'; 3: 208: return; 3: 208-block 0 unconditional 0 taken 3 -: 209:} -: 210: -: 211:int function cschemes_function called 5 returned 100% blocks executed 57% 5: 212:cschemes_function(char **args) -: 213:{ 5: 214: if (xargs.stealth_mode == 1) { 5: 214-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 5 #####: 215: fprintf(stderr, _("%s: The color schemes function is " %%%%%: 215-block 0 call 0 never executed call 1 never executed -: 216: "disabled in stealth mode\nTIP: To change the current " -: 217: "color scheme use the following environment " -: 218: "variables: CLIFM_FILE_COLORS, CLIFM_IFACE_COLORS, " -: 219: "and CLIFM_EXT_COLORS\n"), PROGRAM_NAME); #####: 220: return EXIT_FAILURE; unconditional 0 never executed -: 221: } -: 222: 5: 223: if (!args) 5: 223-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 5 #####: 224: return EXIT_FAILURE; %%%%%: 224-block 0 unconditional 0 never executed -: 225: 5: 226: if (!args[1]) { 5: 226-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 4 1: 227: if (!cschemes_n) { 1: 227-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 1 #####: 228: printf(_("%s: No color schemes found\n"), PROGRAM_NAME); %%%%%: 228-block 0 call 0 never executed call 1 never executed #####: 229: return EXIT_SUCCESS; unconditional 0 never executed -: 230: } -: 231: size_t i; 21: 232: for (i = 0; color_schemes[i]; i++) { 1: 232-block 0 unconditional 0 taken 1 20: 232-block 1 unconditional 1 taken 20 21: 232-block 2 branch 2 taken 20 branch 3 taken 1 (fallthrough) 20: 233: if (cur_cscheme == color_schemes[i]) 20: 233-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 19 1: 234: printf("%s%s%s\n", mi_c, color_schemes[i], df_c); 1: 234-block 0 call 0 returned 1 unconditional 1 taken 1 -: 235: else 19: 236: printf("%s\n", color_schemes[i]); 19: 236-block 0 call 0 returned 19 unconditional 1 taken 19 -: 237: } -: 238: 1: 239: return EXIT_SUCCESS; 1: 239-block 0 unconditional 0 taken 1 -: 240: } -: 241: 4*: 242: if (*args[1] == '-' && strcmp(args[1], "--help") == 0) { 4: 242-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 4 %%%%%: 242-block 1 branch 2 never executed branch 3 never executed #####: 243: puts(_(CS_USAGE)); %%%%%: 243-block 0 call 0 never executed call 1 never executed #####: 244: return EXIT_SUCCESS; unconditional 0 never executed -: 245: } -: 246: 4: 247: if (*args[1] == 'e' && (!args[1][1] || strcmp(args[1], "edit") == 0)) { 4: 247-block 0 branch 0 taken 3 (fallthrough) branch 1 taken 1 3: 247-block 1 branch 2 taken 2 (fallthrough) branch 3 taken 1 2: 247-block 2 branch 4 taken 2 (fallthrough) branch 5 taken 0 -: 248: char file[PATH_MAX]; 3: 249: snprintf(file, PATH_MAX - 1, "%s/%s.cfm", colors_dir, cur_cscheme); -: 250: struct stat attr; 3: 251: if (stat(file, &attr) == -1) { 3: 251-block 0 call 0 returned 3 branch 1 taken 0 (fallthrough) branch 2 taken 3 #####: 252: if (data_dir) { %%%%%: 252-block 0 branch 0 never executed branch 1 never executed #####: 253: snprintf(file, PATH_MAX - 1, "%s/%s/colors/%s.cfm", -: 254: data_dir, PNL, cur_cscheme); #####: 255: if (access(file, W_OK) == -1) { %%%%%: 255-block 0 call 0 never executed branch 1 never executed branch 2 never executed #####: 256: fprintf(stderr, "%s: %s: %s\n", PROGRAM_NAME, call 0 never executed #####: 257: file, strerror(errno)); %%%%%: 257-block 0 call 0 never executed #####: 258: return EXIT_FAILURE; unconditional 0 never executed -: 259: } -: 260: } else { #####: 261: fprintf(stderr, "%s: %s: %s\n", PROGRAM_NAME, call 0 never executed #####: 262: file, strerror(errno)); %%%%%: 262-block 0 call 0 never executed #####: 263: return EXIT_FAILURE; unconditional 0 never executed -: 264: } -: 265: } -: 266: 3: 267: stat(file, &attr); 3: 267-block 0 call 0 returned 3 3: 268: time_t mtime_bfr = (time_t)attr.st_mtime; -: 269: 3: 270: int ret = open_file(file); call 0 returned 3 3: 271: if (ret != EXIT_FAILURE) { branch 0 taken 3 (fallthrough) branch 1 taken 0 3: 272: stat(file, &attr); 3: 272-block 0 call 0 returned 3 3: 273: if (mtime_bfr != (time_t)attr.st_mtime branch 0 taken 2 (fallthrough) branch 1 taken 1 2: 274: && set_colors(cur_cscheme, 0) == EXIT_SUCCESS 2: 274-block 0 call 0 returned 2 branch 1 taken 2 (fallthrough) branch 2 taken 0 2: 275: && cd_lists_on_the_fly) { 2: 275-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 0 2: 276: free_dirlist(); 2: 276-block 0 call 0 returned 2 2: 277: list_dir(); call 0 returned 2 unconditional 1 taken 2 -: 278: } -: 279: } -: 280: 3: 281: return ret; 3: 281-block 0 unconditional 0 taken 3 -: 282: } -: 283: 1*: 284: if (*args[1] == 'n' && (!args[1][1] || strcmp(args[1], "name") == 0)) { 1: 284-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 1 %%%%%: 284-block 1 branch 2 never executed branch 3 never executed %%%%%: 284-block 2 branch 4 never executed branch 5 never executed #####: 285: printf(_("%s: current color scheme: %s\n"), PROGRAM_NAME, %%%%%: 285-block 0 unconditional 0 never executed %%%%%: 285-block 1 unconditional 1 never executed %%%%%: 285-block 2 call 2 never executed call 3 never executed #####: 286: cur_cscheme ? cur_cscheme : "?"); %%%%%: 286-block 0 branch 0 never executed branch 1 never executed #####: 287: return EXIT_SUCCESS; unconditional 0 never executed -: 288: } -: 289: 1: 290: size_t i, cs_found = 0; 2: 291: for (i = 0; color_schemes[i]; i++) { 1: 291-block 0 unconditional 0 taken 1 1: 291-block 1 unconditional 1 taken 1 2: 291-block 2 branch 2 taken 2 branch 3 taken 0 (fallthrough) 2: 292: if (*args[1] == *color_schemes[i] 2: 292-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 1 1: 293: && strcmp(args[1], color_schemes[i]) == 0) { 1: 293-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 0 1: 294: cs_found = 1; 1: 295: if (set_colors(args[1], 0) == EXIT_SUCCESS) { 1: 295-block 0 call 0 returned 1 branch 1 taken 1 (fallthrough) branch 2 taken 0 1: 296: cur_cscheme = color_schemes[i]; 1: 297: switch_cscheme = 1; -: 298: 1: 299: if (cd_lists_on_the_fly) { 1: 299-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 0 1: 300: free_dirlist(); 1: 300-block 0 call 0 returned 1 1: 301: list_dir(); call 0 returned 1 unconditional 1 taken 1 -: 302: } -: 303: 1: 304: switch_cscheme = 0; 1: 305: return EXIT_SUCCESS; 1: 305-block 0 unconditional 0 taken 1 -: 306: } -: 307: } -: 308: } -: 309: #####: 310: if (!cs_found) %%%%%: 310-block 0 branch 0 never executed branch 1 never executed #####: 311: fprintf(stderr, _("%s: No such color scheme\n"), PROGRAM_NAME); %%%%%: 311-block 0 call 0 never executed call 1 never executed unconditional 2 never executed -: 312: #####: 313: return EXIT_FAILURE; %%%%%: 313-block 0 unconditional 0 never executed -: 314:} -: 315: -: 316:/* Open the config file, get values for file type and extension colors -: 317: * and copy these values into the corresponding variable. If some value -: 318: * is not found, or if it's a wrong value, the default is set. */ -: 319:int function set_colors called 27 returned 100% blocks executed 86% 27: 320:set_colors(const char *colorscheme, int env) -: 321:{ 27: 322: char *filecolors = (char *)NULL, 27: 323: *extcolors = (char *)NULL, 27: 324: *ifacecolors = (char *)NULL; -: 325: -: 326:#ifndef _NO_ICONS 27: 327: *dir_ico_c = '\0'; -: 328:#endif -: 329: -: 330: /* Set a pointer to the current color scheme */ 27: 331: if (colorscheme && *colorscheme && color_schemes) { 27: 331-block 0 branch 0 taken 27 (fallthrough) branch 1 taken 0 27: 331-block 1 branch 2 taken 27 (fallthrough) branch 3 taken 0 27: 331-block 2 branch 4 taken 27 (fallthrough) branch 5 taken 0 27: 332: char *def_cscheme = (char *)NULL; -: 333: size_t i; 100: 334: for (i = 0; color_schemes[i]; i++) { 27: 334-block 0 unconditional 0 taken 27 73: 334-block 1 unconditional 1 taken 73 100: 334-block 2 branch 2 taken 99 branch 3 taken 1 (fallthrough) 99: 335: if (*colorscheme == *color_schemes[i] 99: 335-block 0 branch 0 taken 34 (fallthrough) branch 1 taken 65 34: 336: && strcmp(colorscheme, color_schemes[i]) == 0) { 34: 336-block 0 branch 0 taken 26 (fallthrough) branch 1 taken 8 26: 337: cur_cscheme = color_schemes[i]; 26: 338: break; 26: 338-block 0 unconditional 0 taken 26 -: 339: } -: 340: 73: 341: if (*color_schemes[i] == 'd' 73: 341-block 0 branch 0 taken 10 (fallthrough) branch 1 taken 63 10: 342: && strcmp(color_schemes[i], "default") == 0) 10: 342-block 0 branch 0 taken 5 (fallthrough) branch 1 taken 5 5: 343: def_cscheme = color_schemes[i]; 5: 343-block 0 unconditional 0 taken 5 -: 344: } -: 345: 27: 346: if (!cur_cscheme) { 27: 346-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 27 #####: 347: _err('w', PRINT_PROMPT, _("%s: %s: No such color scheme. " %%%%%: 347-block 0 call 0 never executed call 1 never executed -: 348: "Falling back to the default one\n"), -: 349: PROGRAM_NAME, colorscheme); -: 350: #####: 351: if (def_cscheme) branch 0 never executed branch 1 never executed #####: 352: cur_cscheme = def_cscheme; %%%%%: 352-block 0 unconditional 0 never executed -: 353: } -: 354: } -: 355: -: 356: /* env is true only when the function is called from main() */ 27: 357: if (env) { 27: 357-block 0 branch 0 taken 24 (fallthrough) branch 1 taken 3 -: 358: /* Try to get colors from environment variables */ 24: 359: char *env_filecolors = getenv("CLIFM_FILE_COLORS"); 24: 359-block 0 call 0 returned 24 24: 360: char *env_extcolors = getenv("CLIFM_EXT_COLORS"); call 0 returned 24 24: 361: char *env_ifacecolors = getenv("CLIFM_IFACE_COLORS"); call 0 returned 24 -: 362: 24: 363: if (env_filecolors) branch 0 taken 0 (fallthrough) branch 1 taken 24 #####: 364: filecolors = savestring(env_filecolors, strlen(env_filecolors)); %%%%%: 364-block 0 call 0 never executed unconditional 1 never executed -: 365: 24: 366: env_filecolors = (char *)NULL; 24: 367: if (env_extcolors) 24: 367-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 24 #####: 368: extcolors = savestring(env_extcolors, strlen(env_extcolors)); %%%%%: 368-block 0 call 0 never executed unconditional 1 never executed -: 369: 24: 370: env_extcolors = (char *)NULL; 24: 371: if (env_ifacecolors) 24: 371-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 24 #####: 372: ifacecolors = savestring(env_ifacecolors, strlen(env_ifacecolors)); %%%%%: 372-block 0 call 0 never executed unconditional 1 never executed -: 373: 24: 374: env_ifacecolors = (char *)NULL; 24: 374-block 0 unconditional 0 taken 24 -: 375: } -: 376: 27*: 377: if (xargs.stealth_mode != 1 && (!filecolors || !extcolors || !ifacecolors)) { 27: 377-block 0 branch 0 taken 27 (fallthrough) branch 1 taken 0 27: 377-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 27 %%%%%: 377-block 2 branch 4 never executed branch 5 never executed %%%%%: 377-block 3 branch 6 never executed branch 7 never executed -: 378: /* Get color lines, for both file types and extensions, from -: 379: * COLORSCHEME file */ -: 380: char colorscheme_file[PATH_MAX]; 27: 381: *colorscheme_file = '\0'; 27: 382: if (config_ok) { 27: 382-block 0 branch 0 taken 27 (fallthrough) branch 1 taken 0 27*: 383: snprintf(colorscheme_file, PATH_MAX - 1, "%s/%s.cfm", colors_dir, 27: 383-block 0 branch 0 taken 27 (fallthrough) branch 1 taken 0 27: 383-block 1 unconditional 2 taken 27 %%%%%: 383-block 2 unconditional 3 never executed 27: 383-block 3 unconditional 4 taken 27 -: 384: colorscheme ? colorscheme : "default"); -: 385: } -: 386: -: 387: /* If not in local dir, check system data dir as well */ -: 388: struct stat attr; 27: 389: if (data_dir && (!*colorscheme_file || stat(colorscheme_file, &attr) == -1)) { 27: 389-block 0 branch 0 taken 27 (fallthrough) branch 1 taken 0 27: 389-block 1 branch 2 taken 27 (fallthrough) branch 3 taken 0 27: 389-block 2 call 4 returned 27 branch 5 taken 1 (fallthrough) branch 6 taken 26 1*: 390: snprintf(colorscheme_file, PATH_MAX- 1, "%s/%s/colors/%s.cfm", 1: 390-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 0 1: 390-block 1 unconditional 2 taken 1 %%%%%: 390-block 2 unconditional 3 never executed 1: 390-block 3 unconditional 4 taken 1 -: 391: data_dir, PNL, colorscheme ? colorscheme : "default"); -: 392: } -: 393: 27: 394: FILE *fp_colors = fopen(colorscheme_file, "r"); 27: 394-block 0 call 0 returned 27 27: 395: if (fp_colors) { branch 0 taken 26 (fallthrough) branch 1 taken 1 -: 396: -: 397: /* If called from the color scheme function, reset all -: 398: * color values before proceeding */ 26: 399: if (!env) 26: 399-block 0 branch 0 taken 3 (fallthrough) branch 1 taken 23 3: 400: free_colors(); 3: 400-block 0 call 0 returned 3 unconditional 1 taken 3 -: 401: 26: 402: char *line = (char *)NULL; 26: 403: size_t line_size = 0; 26: 404: ssize_t line_len = 0; 26: 405: int file_type_found = 0, 26: 406: ext_type_found = 0, -: 407:#ifndef _NO_ICONS 26: 408: iface_found = 0, 26: 409: dir_icon_found = 0; -: 410:#else -: 411: iface_found = 0; -: 412:#endif -: 413: 388: 414: while ((line_len = getline(&line, &line_size, fp_colors)) > 0) { 26: 414-block 0 unconditional 0 taken 26 388: 414-block 1 call 1 returned 388 branch 2 taken 387 branch 3 taken 1 (fallthrough) -: 415: /* Interface colors */ 387: 416: if (!ifacecolors && *line == 'I' 387: 416-block 0 branch 0 taken 281 (fallthrough) branch 1 taken 106 281: 416-block 1 branch 2 taken 26 (fallthrough) branch 3 taken 255 26: 417: && strncmp(line, "InterfaceColors=", 16) == 0) { 26: 417-block 0 branch 0 taken 26 (fallthrough) branch 1 taken 0 26: 418: iface_found = 1; 26: 419: char *opt_str = strchr(line, '='); 26*: 420: if (!opt_str) 26: 420-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 26 #####: 421: continue; %%%%%: 421-block 0 unconditional 0 never executed -: 422: 26: 423: opt_str++; 26: 424: char *color_line = strip_color_line(opt_str, 't'); 26: 424-block 0 call 0 returned 26 26*: 425: if (!color_line) branch 0 taken 0 (fallthrough) branch 1 taken 26 #####: 426: continue; %%%%%: 426-block 0 unconditional 0 never executed -: 427: 26: 428: ifacecolors = savestring(color_line, strlen(color_line)); 26: 428-block 0 call 0 returned 26 26: 429: free(color_line); unconditional 0 taken 26 -: 430: } -: 431: -: 432: /* Filetype Colors */ 387: 433: if (!filecolors && *line == 'F' 387: 433-block 0 branch 0 taken 229 (fallthrough) branch 1 taken 158 229: 433-block 1 branch 2 taken 26 (fallthrough) branch 3 taken 203 26: 434: && strncmp(line, "FiletypeColors=", 15) == 0) { 26: 434-block 0 branch 0 taken 26 (fallthrough) branch 1 taken 0 26: 435: file_type_found = 1; 26: 436: char *opt_str = strchr(line, '='); 26*: 437: if (!opt_str) 26: 437-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 26 #####: 438: continue; %%%%%: 438-block 0 unconditional 0 never executed -: 439: 26: 440: opt_str++; -: 441: 26: 442: char *color_line = strip_color_line(opt_str, 't'); 26: 442-block 0 call 0 returned 26 26*: 443: if (!color_line) branch 0 taken 0 (fallthrough) branch 1 taken 26 #####: 444: continue; %%%%%: 444-block 0 unconditional 0 never executed -: 445: 26: 446: filecolors = savestring(color_line, strlen(color_line)); 26: 446-block 0 call 0 returned 26 26: 447: free(color_line); unconditional 0 taken 26 -: 448: } -: 449: -: 450: /* File extension colors */ 387: 451: if (!extcolors && *line == 'E' && strncmp(line, "ExtColors=", 10) == 0) { 387: 451-block 0 branch 0 taken 335 (fallthrough) branch 1 taken 52 335: 451-block 1 branch 2 taken 26 (fallthrough) branch 3 taken 309 26: 451-block 2 branch 4 taken 26 (fallthrough) branch 5 taken 0 26: 452: ext_type_found = 1; 26: 453: char *opt_str = strchr(line, '='); 26*: 454: if (!opt_str) 26: 454-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 26 #####: 455: continue; %%%%%: 455-block 0 unconditional 0 never executed -: 456: 26: 457: opt_str++; 26: 458: char *color_line = strip_color_line(opt_str, 'x'); 26: 458-block 0 call 0 returned 26 26*: 459: if (!color_line) branch 0 taken 0 (fallthrough) branch 1 taken 26 #####: 460: continue; %%%%%: 460-block 0 unconditional 0 never executed -: 461: 26: 462: extcolors = savestring(color_line, strlen(color_line)); 26: 462-block 0 call 0 returned 26 26: 463: free(color_line); unconditional 0 taken 26 -: 464: } -: 465: -: 466:#ifndef _NO_ICONS -: 467: /* Dir icons Color */ 387: 468: if (*line == 'D' && strncmp(line, "DirIconsColor=", 14) == 0) { 387: 468-block 0 branch 0 taken 26 (fallthrough) branch 1 taken 361 26: 468-block 1 branch 2 taken 26 (fallthrough) branch 3 taken 0 26: 469: dir_icon_found = 1; 26: 470: char *opt_str = strchr(line, '='); 26*: 471: if (!opt_str) 26: 471-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 26 #####: 472: continue; %%%%%: 472-block 0 unconditional 0 never executed 26: 473: if (!*(++opt_str)) 26: 473-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 25 1: 474: continue; 1: 474-block 0 unconditional 0 taken 1 -: 475: 25: 476: if (*opt_str == '\'' || *opt_str == '"') 25: 476-block 0 branch 0 taken 25 (fallthrough) branch 1 taken 0 25: 476-block 1 branch 2 taken 22 (fallthrough) branch 3 taken 3 22: 477: opt_str++; 22: 477-block 0 unconditional 0 taken 22 25*: 478: if (!*opt_str) 25: 478-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 25 #####: 479: continue; %%%%%: 479-block 0 unconditional 0 never executed -: 480: 25: 481: int nl_removed = 0; 25: 482: if (line[line_len - 1] == '\n') { 25: 482-block 0 branch 0 taken 22 (fallthrough) branch 1 taken 3 22: 483: line[line_len - 1] = '\0'; 22: 484: nl_removed = 1; 22: 484-block 0 unconditional 0 taken 22 -: 485: } -: 486: 25: 487: int end_char = (int)line_len - 1; -: 488: 25: 489: if (nl_removed) 25: 489-block 0 branch 0 taken 22 (fallthrough) branch 1 taken 3 22: 490: end_char--; 22: 490-block 0 unconditional 0 taken 22 -: 491: 25: 492: if (line[end_char] == '\'' || line[end_char] == '"') 25: 492-block 0 branch 0 taken 25 (fallthrough) branch 1 taken 0 25: 492-block 1 branch 2 taken 22 (fallthrough) branch 3 taken 3 22: 493: line[end_char] = '\0'; 22: 493-block 0 unconditional 0 taken 22 -: 494: 25: 495: sprintf(dir_ico_c, "\x1b[%sm", opt_str); 25: 495-block 0 unconditional 0 taken 25 -: 496: } -: 497:#endif /* !_NO_ICONS */ -: 498: 386: 499: if (file_type_found && ext_type_found 386: 499-block 0 branch 0 taken 183 (fallthrough) branch 1 taken 203 183: 499-block 1 branch 2 taken 77 (fallthrough) branch 3 taken 106 -: 500:#ifndef _NO_ICONS 77: 501: && iface_found && dir_icon_found) 77: 501-block 0 branch 0 taken 77 (fallthrough) branch 1 taken 0 77: 501-block 1 branch 2 taken 25 (fallthrough) branch 3 taken 52 -: 502:#else -: 503: && iface_found) -: 504:#endif 25: 505: break; 25: 505-block 0 unconditional 0 taken 25 -: 506: } -: 507: 26: 508: free(line); 26: 509: line = (char *)NULL; 26: 510: fclose(fp_colors); 26: 510-block 0 call 0 returned 26 -: 511: } -: 512: -: 513: /* If fopen failed */ -: 514: else { 1: 515: if (!env) { 1: 515-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 1 #####: 516: fprintf(stderr, "%s: %s: %s\n", PROGRAM_NAME, call 0 never executed #####: 517: colorscheme_file, strerror(errno)); %%%%%: 517-block 0 call 0 never executed #####: 518: return EXIT_FAILURE; unconditional 0 never executed -: 519: } else { 1: 520: _err('w', PRINT_PROMPT, _("%s: %s: No such color scheme. " 1: 520-block 0 call 0 returned 1 call 1 returned 1 unconditional 2 taken 1 -: 521: "Falling back to the default one\n"), PROGRAM_NAME, -: 522: colorscheme); -: 523: } -: 524: } -: 525: } -: 526: -: 527: /* ############################## -: 528: * # FILE EXTENSION COLORS # -: 529: * ############################## */ -: 530: -: 531: /* Split the colors line into substrings (one per color) */ -: 532: 27: 533: if (!extcolors) { 27: 533-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 26 -: 534: /* Unload current extension colors */ 1: 535: if (ext_colors_n) { 1: 535-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 0 1: 536: int i = (int)ext_colors_n; 68: 537: while (--i >= 0) 1: 537-block 0 unconditional 0 taken 1 68: 537-block 1 branch 1 taken 67 branch 2 taken 1 (fallthrough) 67: 538: free(ext_colors[i]); 67: 538-block 0 unconditional 0 taken 67 1: 539: free(ext_colors); 1: 540: ext_colors = (char **)NULL; 1: 541: free(ext_colors_len); 1: 542: ext_colors_n = 0; 1: 542-block 0 unconditional 0 taken 1 -: 543: } -: 544: } else { 26: 545: char *p = extcolors, *buf = (char *)NULL; 26: 546: size_t len = 0; 26: 547: int eol = 0; -: 548: 26: 549: if (ext_colors_n) { 26: 549-block 0 branch 0 taken 21 (fallthrough) branch 1 taken 5 21: 550: int i = (int)ext_colors_n; 1428: 551: while (--i >= 0) 21: 551-block 0 unconditional 0 taken 21 1428: 551-block 1 branch 1 taken 1407 branch 2 taken 21 (fallthrough) 1407: 552: free(ext_colors[i]); 1407: 552-block 0 unconditional 0 taken 1407 21: 553: free(ext_colors); 21: 554: ext_colors = (char **)NULL; 21: 555: free(ext_colors_len); 21: 556: ext_colors_n = 0; 21: 556-block 0 unconditional 0 taken 21 -: 557: } -: 558: 22780: 559: while (!eol) { 26: 559-block 0 unconditional 0 taken 26 22780: 559-block 1 branch 1 taken 22754 branch 2 taken 26 (fallthrough) 22754: 560: switch (*p) { 22754: 560-block 0 branch 0 taken 1788 branch 1 taken 20966 -: 561: 1788: 562: case '\0': /* fallthrough */ -: 563: case '\n': /* fallthrough */ -: 564: case ':': 1788: 565: if (!buf) 1788: 565-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 1788 #####: 566: break; %%%%%: 566-block 0 unconditional 0 never executed 1788: 567: buf[len] = '\0'; 3576: 568: ext_colors = (char **)xrealloc(ext_colors, 1788: 569: (ext_colors_n + 1) * sizeof(char *)); 1788: 569-block 0 call 0 returned 1788 1788: 570: ext_colors[ext_colors_n++] = savestring(buf, len); call 0 returned 1788 1788: 571: *buf = '\0'; -: 572: 1788: 573: if (!*p) branch 0 taken 26 (fallthrough) branch 1 taken 1762 26: 574: eol = 1; 26: 574-block 0 unconditional 0 taken 26 -: 575: 1788: 576: len = 0; 1788: 577: p++; 1788: 578: break; 1788: 578-block 0 unconditional 0 taken 1788 -: 579: 20966: 580: default: 20966: 581: buf = (char *)xrealloc(buf, (len + 2) * sizeof(char)); 20966: 581-block 0 call 0 returned 20966 20966: 582: buf[len++] = *(p++); 20966: 583: break; unconditional 0 taken 20966 -: 584: } -: 585: } -: 586: 26: 587: p = (char *)NULL; 26: 588: free(extcolors); 26: 589: extcolors = (char *)NULL; -: 590: 26: 591: if (buf) { 26: 591-block 0 branch 0 taken 26 (fallthrough) branch 1 taken 0 26: 592: free(buf); 26: 593: buf = (char *)NULL; 26: 593-block 0 unconditional 0 taken 26 -: 594: } -: 595: 26: 596: if (ext_colors) { 26: 596-block 0 branch 0 taken 26 (fallthrough) branch 1 taken 0 26: 597: ext_colors = (char **)xrealloc(ext_colors, (ext_colors_n + 1) * sizeof(char *)); 26: 597-block 0 call 0 returned 26 26: 598: ext_colors[ext_colors_n] = (char *)NULL; unconditional 0 taken 26 -: 599: } -: 600: -: 601: /* Make sure we have valid color codes and store the length -: 602: * of each stored extension: this length will be used later -: 603: * when listing files */ 26: 604: ext_colors_len = (size_t *)xnmalloc(ext_colors_n, sizeof(size_t)); 26: 604-block 0 call 0 returned 26 -: 605: 26: 606: int i = (int)ext_colors_n; 1814: 607: while (--i >= 0) { unconditional 0 taken 26 1814: 607-block 0 branch 1 taken 1788 branch 2 taken 26 (fallthrough) 1788: 608: char *ret = strrchr(ext_colors[i], '='); 1788: 609: if (!ret || !is_color_code(ret + 1)) { 1788: 609-block 0 branch 0 taken 1762 (fallthrough) branch 1 taken 26 1762: 609-block 1 call 2 returned 1762 branch 3 taken 0 (fallthrough) branch 4 taken 1762 26: 610: *ext_colors[i] = '\0'; 26: 611: ext_colors_len[i] = 0; 26: 612: continue; 26: 612-block 0 unconditional 0 taken 26 -: 613: } -: 614: 1762: 615: size_t j, ext_len = 0; 7126: 616: for (j = 2; ext_colors[i][j] && ext_colors[i][j] != '='; j++) 1762: 616-block 0 unconditional 0 taken 1762 7126: 616-block 1 branch 1 taken 7126 (fallthrough) branch 2 taken 0 7126: 616-block 2 branch 3 taken 5364 branch 4 taken 1762 (fallthrough) 5364: 617: ext_len++; 5364: 617-block 0 unconditional 0 taken 5364 -: 618: 1762: 619: ext_colors_len[i] = ext_len; 1762: 619-block 0 unconditional 0 taken 1762 -: 620: } -: 621: } -: 622: -: 623: /* ############################## -: 624: * # INTERFACE COLORS # -: 625: * ############################## */ -: 626: 27: 627: if (!ifacecolors) { 27: 627-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 26 -: 628: /* Free and reset whatever value was loaded */ 1: 629: *hb_c = '\0'; 1: 630: *hc_c = '\0'; 1: 631: *he_c = '\0'; 1: 632: *hn_c = '\0'; 1: 633: *hp_c = '\0'; 1: 634: *hq_c = '\0'; 1: 635: *hr_c = '\0'; 1: 636: *hs_c = '\0'; 1: 637: *hv_c = '\0'; 1: 638: *sh_c = '\0'; 1: 639: *sf_c = '\0'; 1: 640: *sc_c = '\0'; 1: 641: *sx_c = '\0'; 1: 642: *bm_c = '\0'; 1: 643: *dl_c = '\0'; 1: 644: *el_c = '\0'; 1: 645: *mi_c = '\0'; 1: 646: *tx_c = '\0'; 1: 647: *df_c = '\0'; 1: 648: *dc_c = '\0'; 1: 649: *wc_c = '\0'; 1: 650: *dh_c = '\0'; 1: 651: *li_c = '\0'; 1: 652: *ti_c = '\0'; 1: 653: *em_c = '\0'; 1: 654: *wm_c = '\0'; 1: 655: *nm_c = '\0'; 1: 656: *si_c = '\0'; 1: 656-block 0 unconditional 0 taken 1 -: 657: } else { 26: 658: char *p = ifacecolors, *buf = (char *)NULL, 26: 659: **colors = (char **)NULL; 26: 660: size_t len = 0, words = 0; 26: 661: int eol = 0; -: 662: 6092: 663: while (!eol) { 26: 663-block 0 unconditional 0 taken 26 6092: 663-block 1 branch 1 taken 6066 branch 2 taken 26 (fallthrough) 6066: 664: switch (*p) { 6066: 664-block 0 branch 0 taken 668 branch 1 taken 5398 -: 665: 668: 666: case '\0': /* fallthrough */ -: 667: case '\n': /* fallthrough */ -: 668: case ':': 668: 669: if (!buf) 668: 669-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 668 #####: 670: break; %%%%%: 670-block 0 unconditional 0 never executed 668: 671: buf[len] = '\0'; 668: 672: colors = (char **)xrealloc(colors, (words + 1) * sizeof(char *)); 668: 672-block 0 call 0 returned 668 668: 673: colors[words++] = savestring(buf, len); call 0 returned 668 668: 674: *buf = '\0'; -: 675: 668: 676: if (!*p) branch 0 taken 26 (fallthrough) branch 1 taken 642 26: 677: eol = 1; 26: 677-block 0 unconditional 0 taken 26 -: 678: 668: 679: len = 0; 668: 680: p++; 668: 681: break; 668: 681-block 0 unconditional 0 taken 668 -: 682: 5398: 683: default: 5398: 684: buf = (char *)xrealloc(buf, (len + 2) * sizeof(char)); 5398: 684-block 0 call 0 returned 5398 5398: 685: buf[len++] = *(p++); 5398: 686: break; unconditional 0 taken 5398 -: 687: } -: 688: } -: 689: 26: 690: p = (char *)NULL; 26: 691: free(ifacecolors); 26: 692: ifacecolors = (char *)NULL; -: 693: 26: 694: if (buf) { 26: 694-block 0 branch 0 taken 26 (fallthrough) branch 1 taken 0 26: 695: free(buf); 26: 696: buf = (char *)NULL; 26: 696-block 0 unconditional 0 taken 26 -: 697: } -: 698: 26: 699: if (colors) { 26: 699-block 0 branch 0 taken 26 (fallthrough) branch 1 taken 0 26: 700: colors = (char **)xrealloc(colors, (words + 1) * sizeof(char *)); 26: 700-block 0 call 0 returned 26 26: 701: colors[words] = (char *)NULL; unconditional 0 taken 26 -: 702: } -: 703: 26: 704: int i = (int)words; -: 705: /* Set the color variables */ 694: 706: while (--i >= 0) { 26: 706-block 0 unconditional 0 taken 26 694: 706-block 1 branch 1 taken 668 branch 2 taken 26 (fallthrough) 668: 707: if (*colors[i] == 't' && strncmp(colors[i], "tx=", 3) == 0) { 668: 707-block 0 branch 0 taken 52 (fallthrough) branch 1 taken 616 52: 707-block 1 branch 2 taken 26 (fallthrough) branch 3 taken 26 26: 708: if (!is_color_code(colors[i] + 3)) { 26: 708-block 0 call 0 returned 26 branch 1 taken 0 (fallthrough) branch 2 taken 26 -: 709: /* zero the corresponding variable as a flag for -: 710: * the check after this for loop to prepare the -: 711: * variable to hold the default color */ #####: 712: *tx_c = '\0'; %%%%%: 712-block 0 unconditional 0 never executed -: 713: } else { 26: 714: snprintf(tx_c, MAX_COLOR + 2, "\001\x1b[%sm\002", 26: 715: colors[i] + 3); 26: 715-block 0 unconditional 0 taken 26 -: 716: } -: 717: } -: 718: 642: 719: else if (*colors[i] == 'h' && strncmp(colors[i], "hb=", 3) == 0) { 642: 719-block 0 branch 0 taken 189 (fallthrough) branch 1 taken 453 189: 719-block 1 branch 2 taken 21 (fallthrough) branch 3 taken 168 21: 720: if (!is_color_code(colors[i] + 3)) 21: 720-block 0 call 0 returned 21 branch 1 taken 0 (fallthrough) branch 2 taken 21 #####: 721: *hb_c = '\0'; %%%%%: 721-block 0 unconditional 0 never executed -: 722: else 21: 723: snprintf(hb_c, MAX_COLOR - 1, "\x1b[%sm", 21: 724: colors[i] + 3); 21: 724-block 0 unconditional 0 taken 21 -: 725: } -: 726: 621: 727: else if (*colors[i] == 'h' && strncmp(colors[i], "hc=", 3) == 0) { 621: 727-block 0 branch 0 taken 168 (fallthrough) branch 1 taken 453 168: 727-block 1 branch 2 taken 21 (fallthrough) branch 3 taken 147 21: 728: if (!is_color_code(colors[i] + 3)) 21: 728-block 0 call 0 returned 21 branch 1 taken 0 (fallthrough) branch 2 taken 21 #####: 729: *hc_c = '\0'; %%%%%: 729-block 0 unconditional 0 never executed -: 730: else 21: 731: snprintf(hc_c, MAX_COLOR - 1, "\x1b[%sm", 21: 732: colors[i] + 3); 21: 732-block 0 unconditional 0 taken 21 -: 733: } -: 734: 600: 735: else if (*colors[i] == 'h' && strncmp(colors[i], "he=", 3) == 0) { 600: 735-block 0 branch 0 taken 147 (fallthrough) branch 1 taken 453 147: 735-block 1 branch 2 taken 21 (fallthrough) branch 3 taken 126 21: 736: if (!is_color_code(colors[i] + 3)) 21: 736-block 0 call 0 returned 21 branch 1 taken 0 (fallthrough) branch 2 taken 21 #####: 737: *he_c = '\0'; %%%%%: 737-block 0 unconditional 0 never executed -: 738: else 21: 739: snprintf(he_c, MAX_COLOR - 1, "\x1b[%sm", 21: 740: colors[i] + 3); 21: 740-block 0 unconditional 0 taken 21 -: 741: } -: 742: 579: 743: else if (*colors[i] == 'h' && strncmp(colors[i], "hn=", 3) == 0) { 579: 743-block 0 branch 0 taken 126 (fallthrough) branch 1 taken 453 126: 743-block 1 branch 2 taken 21 (fallthrough) branch 3 taken 105 21: 744: if (!is_color_code(colors[i] + 3)) 21: 744-block 0 call 0 returned 21 branch 1 taken 0 (fallthrough) branch 2 taken 21 #####: 745: *hn_c = '\0'; %%%%%: 745-block 0 unconditional 0 never executed -: 746: else 21: 747: snprintf(hn_c, MAX_COLOR - 1, "\x1b[%sm", 21: 748: colors[i] + 3); 21: 748-block 0 unconditional 0 taken 21 -: 749: } -: 750: 558: 751: else if (*colors[i] == 'h' && strncmp(colors[i], "hp=", 3) == 0) { 558: 751-block 0 branch 0 taken 105 (fallthrough) branch 1 taken 453 105: 751-block 1 branch 2 taken 21 (fallthrough) branch 3 taken 84 21: 752: if (!is_color_code(colors[i] + 3)) 21: 752-block 0 call 0 returned 21 branch 1 taken 0 (fallthrough) branch 2 taken 21 #####: 753: *hp_c = '\0'; %%%%%: 753-block 0 unconditional 0 never executed -: 754: else 21: 755: snprintf(hp_c, MAX_COLOR - 1, "\x1b[%sm", 21: 756: colors[i] + 3); 21: 756-block 0 unconditional 0 taken 21 -: 757: } -: 758: 537: 759: else if (*colors[i] == 'h' && strncmp(colors[i], "hq=", 3) == 0) { 537: 759-block 0 branch 0 taken 84 (fallthrough) branch 1 taken 453 84: 759-block 1 branch 2 taken 21 (fallthrough) branch 3 taken 63 21: 760: if (!is_color_code(colors[i] + 3)) 21: 760-block 0 call 0 returned 21 branch 1 taken 0 (fallthrough) branch 2 taken 21 #####: 761: *hq_c = '\0'; %%%%%: 761-block 0 unconditional 0 never executed -: 762: else 21: 763: snprintf(hq_c, MAX_COLOR - 1, "\x1b[%sm", 21: 764: colors[i] + 3); 21: 764-block 0 unconditional 0 taken 21 -: 765: } -: 766: 516: 767: else if (*colors[i] == 'h' && strncmp(colors[i], "hr=", 3) == 0) { 516: 767-block 0 branch 0 taken 63 (fallthrough) branch 1 taken 453 63: 767-block 1 branch 2 taken 21 (fallthrough) branch 3 taken 42 21: 768: if (!is_color_code(colors[i] + 3)) 21: 768-block 0 call 0 returned 21 branch 1 taken 0 (fallthrough) branch 2 taken 21 #####: 769: *hr_c = '\0'; %%%%%: 769-block 0 unconditional 0 never executed -: 770: else 21: 771: snprintf(hr_c, MAX_COLOR - 1, "\x1b[%sm", 21: 772: colors[i] + 3); 21: 772-block 0 unconditional 0 taken 21 -: 773: } -: 774: 495: 775: else if (*colors[i] == 'h' && strncmp(colors[i], "hs=", 3) == 0) { 495: 775-block 0 branch 0 taken 42 (fallthrough) branch 1 taken 453 42: 775-block 1 branch 2 taken 21 (fallthrough) branch 3 taken 21 21: 776: if (!is_color_code(colors[i] + 3)) 21: 776-block 0 call 0 returned 21 branch 1 taken 0 (fallthrough) branch 2 taken 21 #####: 777: *hs_c = '\0'; %%%%%: 777-block 0 unconditional 0 never executed -: 778: else 21: 779: snprintf(hs_c, MAX_COLOR - 1, "\x1b[%sm", 21: 780: colors[i] + 3); 21: 780-block 0 unconditional 0 taken 21 -: 781: } -: 782: 474: 783: else if (*colors[i] == 'h' && strncmp(colors[i], "hv=", 3) == 0) { 474: 783-block 0 branch 0 taken 21 (fallthrough) branch 1 taken 453 21: 783-block 1 branch 2 taken 21 (fallthrough) branch 3 taken 0 21: 784: if (!is_color_code(colors[i] + 3)) 21: 784-block 0 call 0 returned 21 branch 1 taken 0 (fallthrough) branch 2 taken 21 #####: 785: *hv_c = '\0'; %%%%%: 785-block 0 unconditional 0 never executed -: 786: else 21: 787: snprintf(hv_c, MAX_COLOR - 1, "\x1b[%sm", 21: 788: colors[i] + 3); 21: 788-block 0 unconditional 0 taken 21 -: 789: } -: 790: 453: 791: else if (*colors[i] == 's' && strncmp(colors[i], "sh=", 3) == 0) { 453: 791-block 0 branch 0 taken 89 (fallthrough) branch 1 taken 364 89: 791-block 1 branch 2 taken 21 (fallthrough) branch 3 taken 68 21: 792: if (!is_color_code(colors[i] + 3)) 21: 792-block 0 call 0 returned 21 branch 1 taken 0 (fallthrough) branch 2 taken 21 #####: 793: *sh_c = '\0'; %%%%%: 793-block 0 unconditional 0 never executed -: 794: else 21: 795: snprintf(sh_c, MAX_COLOR - 1, "\x1b[%sm", 21: 796: colors[i] + 3); 21: 796-block 0 unconditional 0 taken 21 -: 797: } -: 798: 432: 799: else if (*colors[i] == 's' && strncmp(colors[i], "sf=", 3) == 0) { 432: 799-block 0 branch 0 taken 68 (fallthrough) branch 1 taken 364 68: 799-block 1 branch 2 taken 21 (fallthrough) branch 3 taken 47 21: 800: if (!is_color_code(colors[i] + 3)) 21: 800-block 0 call 0 returned 21 branch 1 taken 0 (fallthrough) branch 2 taken 21 #####: 801: *sf_c = '\0'; %%%%%: 801-block 0 unconditional 0 never executed -: 802: else 21: 803: snprintf(sf_c, MAX_COLOR - 1, "\x1b[%sm", 21: 804: colors[i] + 3); 21: 804-block 0 unconditional 0 taken 21 -: 805: } -: 806: 411: 807: else if (*colors[i] == 's' && strncmp(colors[i], "sc=", 3) == 0) { 411: 807-block 0 branch 0 taken 47 (fallthrough) branch 1 taken 364 47: 807-block 1 branch 2 taken 21 (fallthrough) branch 3 taken 26 21: 808: if (!is_color_code(colors[i] + 3)) 21: 808-block 0 call 0 returned 21 branch 1 taken 0 (fallthrough) branch 2 taken 21 #####: 809: *sc_c = '\0'; %%%%%: 809-block 0 unconditional 0 never executed -: 810: else 21: 811: snprintf(sc_c, MAX_COLOR - 1, "\x1b[%sm", 21: 812: colors[i] + 3); 21: 812-block 0 unconditional 0 taken 21 -: 813: } -: 814: 390: 815: else if (*colors[i] == 's' && strncmp(colors[i], "sx=", 3) == 0) { 390: 815-block 0 branch 0 taken 26 (fallthrough) branch 1 taken 364 26: 815-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 26 #####: 816: if (!is_color_code(colors[i] + 3)) %%%%%: 816-block 0 call 0 never executed branch 1 never executed branch 2 never executed #####: 817: *sx_c = '\0'; %%%%%: 817-block 0 unconditional 0 never executed -: 818: else #####: 819: snprintf(sx_c, MAX_COLOR - 1, "\x1b[%sm", #####: 820: colors[i] + 3); %%%%%: 820-block 0 unconditional 0 never executed -: 821: } -: 822: 390: 823: else if (*colors[i] == 'b' && strncmp(colors[i], "bm=", 3) == 0) { 390: 823-block 0 branch 0 taken 26 (fallthrough) branch 1 taken 364 26: 823-block 1 branch 2 taken 26 (fallthrough) branch 3 taken 0 26: 824: if (!is_color_code(colors[i] + 3)) 26: 824-block 0 call 0 returned 26 branch 1 taken 0 (fallthrough) branch 2 taken 26 #####: 825: *bm_c = '\0'; %%%%%: 825-block 0 unconditional 0 never executed -: 826: else 26: 827: snprintf(bm_c, MAX_COLOR - 1, "\x1b[%sm", colors[i] + 3); 26: 827-block 0 unconditional 0 taken 26 -: 828: } -: 829: 364: 830: else if (*colors[i] == 'l' && strncmp(colors[i], "li=", 3) == 0) { 364: 830-block 0 branch 0 taken 26 (fallthrough) branch 1 taken 338 26: 830-block 1 branch 2 taken 26 (fallthrough) branch 3 taken 0 26: 831: if (!is_color_code(colors[i] + 3)) 26: 831-block 0 call 0 returned 26 branch 1 taken 0 (fallthrough) branch 2 taken 26 #####: 832: *li_c = '\0'; %%%%%: 832-block 0 unconditional 0 never executed -: 833: else 26: 834: snprintf(li_c, MAX_COLOR + 2, "\001\x1b[%sm\002", 26: 835: colors[i] + 3); 26: 835-block 0 unconditional 0 taken 26 -: 836: } -: 837: 338: 838: else if (*colors[i] == 't' && strncmp(colors[i], "ti=", 3) == 0) { 338: 838-block 0 branch 0 taken 26 (fallthrough) branch 1 taken 312 26: 838-block 1 branch 2 taken 26 (fallthrough) branch 3 taken 0 26: 839: if (!is_color_code(colors[i] + 3)) 26: 839-block 0 call 0 returned 26 branch 1 taken 0 (fallthrough) branch 2 taken 26 #####: 840: *ti_c = '\0'; %%%%%: 840-block 0 unconditional 0 never executed -: 841: else 26: 842: snprintf(ti_c, MAX_COLOR + 2, "\001\x1b[%sm\002", 26: 843: colors[i] + 3); 26: 843-block 0 unconditional 0 taken 26 -: 844: } -: 845: 312: 846: else if (*colors[i] == 'e' && strncmp(colors[i], "em=", 3) == 0) { 312: 846-block 0 branch 0 taken 52 (fallthrough) branch 1 taken 260 52: 846-block 1 branch 2 taken 26 (fallthrough) branch 3 taken 26 26: 847: if (!is_color_code(colors[i] + 3)) 26: 847-block 0 call 0 returned 26 branch 1 taken 0 (fallthrough) branch 2 taken 26 #####: 848: *em_c = '\0'; %%%%%: 848-block 0 unconditional 0 never executed -: 849: else 26: 850: snprintf(em_c, MAX_COLOR + 2, "\001\x1b[%sm\002", 26: 851: colors[i] + 3); 26: 851-block 0 unconditional 0 taken 26 -: 852: } -: 853: 286: 854: else if (*colors[i] == 'w' && strncmp(colors[i], "wm=", 3) == 0) { 286: 854-block 0 branch 0 taken 52 (fallthrough) branch 1 taken 234 52: 854-block 1 branch 2 taken 26 (fallthrough) branch 3 taken 26 26: 855: if (!is_color_code(colors[i] + 3)) 26: 855-block 0 call 0 returned 26 branch 1 taken 0 (fallthrough) branch 2 taken 26 #####: 856: *wm_c = '\0'; %%%%%: 856-block 0 unconditional 0 never executed -: 857: else 26: 858: snprintf(wm_c, MAX_COLOR + 2, "\001\x1b[%sm\002", 26: 859: colors[i] + 3); 26: 859-block 0 unconditional 0 taken 26 -: 860: } -: 861: 260: 862: else if (*colors[i] == 'n' && strncmp(colors[i], "nm=", 3) == 0) { 260: 862-block 0 branch 0 taken 26 (fallthrough) branch 1 taken 234 26: 862-block 1 branch 2 taken 26 (fallthrough) branch 3 taken 0 26: 863: if (!is_color_code(colors[i] + 3)) 26: 863-block 0 call 0 returned 26 branch 1 taken 0 (fallthrough) branch 2 taken 26 #####: 864: *nm_c = '\0'; %%%%%: 864-block 0 unconditional 0 never executed -: 865: else 26: 866: snprintf(nm_c, MAX_COLOR + 2, "\001\x1b[%sm\002", 26: 867: colors[i] + 3); 26: 867-block 0 unconditional 0 taken 26 -: 868: } -: 869: 234: 870: else if (*colors[i] == 's' && strncmp(colors[i], "si=", 3) == 0) { 234: 870-block 0 branch 0 taken 26 (fallthrough) branch 1 taken 208 26: 870-block 1 branch 2 taken 26 (fallthrough) branch 3 taken 0 26: 871: if (!is_color_code(colors[i] + 3)) 26: 871-block 0 call 0 returned 26 branch 1 taken 0 (fallthrough) branch 2 taken 26 #####: 872: *si_c = '\0'; %%%%%: 872-block 0 unconditional 0 never executed -: 873: else 26: 874: snprintf(si_c, MAX_COLOR + 2, "\001\x1b[%sm\002", 26: 875: colors[i] + 3); 26: 875-block 0 unconditional 0 taken 26 -: 876: } -: 877: 208: 878: else if (*colors[i] == 'e' && strncmp(colors[i], "el=", 3) == 0) { 208: 878-block 0 branch 0 taken 26 (fallthrough) branch 1 taken 182 26: 878-block 1 branch 2 taken 26 (fallthrough) branch 3 taken 0 26: 879: if (!is_color_code(colors[i] + 3)) 26: 879-block 0 call 0 returned 26 branch 1 taken 0 (fallthrough) branch 2 taken 26 #####: 880: *el_c = '\0'; %%%%%: 880-block 0 unconditional 0 never executed -: 881: else 26: 882: snprintf(el_c, MAX_COLOR - 1, "\x1b[%sm", colors[i] + 3); 26: 882-block 0 unconditional 0 taken 26 -: 883: } -: 884: 182: 885: else if (*colors[i] == 'm' && strncmp(colors[i], "mi=", 3) == 0) { 182: 885-block 0 branch 0 taken 26 (fallthrough) branch 1 taken 156 26: 885-block 1 branch 2 taken 26 (fallthrough) branch 3 taken 0 26: 886: if (!is_color_code(colors[i] + 3)) 26: 886-block 0 call 0 returned 26 branch 1 taken 0 (fallthrough) branch 2 taken 26 #####: 887: *mi_c = '\0'; %%%%%: 887-block 0 unconditional 0 never executed -: 888: else 26: 889: snprintf(mi_c, MAX_COLOR - 1, "\x1b[%sm", colors[i] + 3); 26: 889-block 0 unconditional 0 taken 26 -: 890: } -: 891: 156: 892: else if (*colors[i] == 'd' && strncmp(colors[i], "dl=", 3) == 0) { 156: 892-block 0 branch 0 taken 104 (fallthrough) branch 1 taken 52 104: 892-block 1 branch 2 taken 26 (fallthrough) branch 3 taken 78 26: 893: if (!is_color_code(colors[i] + 3)) 26: 893-block 0 call 0 returned 26 branch 1 taken 0 (fallthrough) branch 2 taken 26 #####: 894: *dl_c = '\0'; %%%%%: 894-block 0 unconditional 0 never executed -: 895: else 26: 896: snprintf(dl_c, MAX_COLOR - 1, "\x1b[%sm", colors[i] + 3); 26: 896-block 0 unconditional 0 taken 26 -: 897: } -: 898: 130: 899: else if (*colors[i] == 'd' && strncmp(colors[i], "df=", 3) == 0) { 130: 899-block 0 branch 0 taken 78 (fallthrough) branch 1 taken 52 78: 899-block 1 branch 2 taken 26 (fallthrough) branch 3 taken 52 26: 900: if (!is_color_code(colors[i] + 3)) 26: 900-block 0 call 0 returned 26 branch 1 taken 0 (fallthrough) branch 2 taken 26 #####: 901: *df_c = '\0'; %%%%%: 901-block 0 unconditional 0 never executed -: 902: else 26: 903: snprintf(df_c, MAX_COLOR - 1, "\x1b[%s;49m", 26: 904: colors[i] + 3); 26: 904-block 0 unconditional 0 taken 26 -: 905: } -: 906: 104: 907: else if (*colors[i] == 'd' && strncmp(colors[i], "dc=", 3) == 0) { 104: 907-block 0 branch 0 taken 52 (fallthrough) branch 1 taken 52 52: 907-block 1 branch 2 taken 26 (fallthrough) branch 3 taken 26 26: 908: if (!is_color_code(colors[i] + 3)) 26: 908-block 0 call 0 returned 26 branch 1 taken 0 (fallthrough) branch 2 taken 26 #####: 909: *dc_c = '\0'; %%%%%: 909-block 0 unconditional 0 never executed -: 910: else 26: 911: snprintf(dc_c, MAX_COLOR - 1, "\x1b[%sm", colors[i] + 3); 26: 911-block 0 unconditional 0 taken 26 -: 912: } -: 913: 78: 914: else if (*colors[i] == 'w' && strncmp(colors[i], "wc=", 3) == 0) { 78: 914-block 0 branch 0 taken 26 (fallthrough) branch 1 taken 52 26: 914-block 1 branch 2 taken 26 (fallthrough) branch 3 taken 0 26: 915: if (!is_color_code(colors[i] + 3)) 26: 915-block 0 call 0 returned 26 branch 1 taken 0 (fallthrough) branch 2 taken 26 #####: 916: *wc_c = '\0'; %%%%%: 916-block 0 unconditional 0 never executed -: 917: else 26: 918: snprintf(wc_c, MAX_COLOR - 1, "\x1b[%sm", colors[i] + 3); 26: 918-block 0 unconditional 0 taken 26 -: 919: } -: 920: 52: 921: else if (*colors[i] == 'd' && strncmp(colors[i], "dh=", 3) == 0) { 52: 921-block 0 branch 0 taken 26 (fallthrough) branch 1 taken 26 26: 921-block 1 branch 2 taken 26 (fallthrough) branch 3 taken 0 26: 922: if (!is_color_code(colors[i] + 3)) 26: 922-block 0 call 0 returned 26 branch 1 taken 0 (fallthrough) branch 2 taken 26 #####: 923: *dh_c = '\0'; %%%%%: 923-block 0 unconditional 0 never executed -: 924: else 26: 925: snprintf(dh_c, MAX_COLOR - 1, "\x1b[%sm", colors[i] + 3); 26: 925-block 0 unconditional 0 taken 26 -: 926: } -: 927: 668: 928: free(colors[i]); 668: 928-block 0 unconditional 0 taken 668 -: 929: } -: 930: 26: 931: free(colors); 26: 932: colors = (char **)NULL; 26: 932-block 0 unconditional 0 taken 26 -: 933: } -: 934: 27: 935: if (!filecolors) { 27: 935-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 26 1: 936: *nd_c = '\0'; 1: 937: *nf_c = '\0'; 1: 938: *di_c = '\0'; 1: 939: *ed_c = '\0'; 1: 940: *ne_c = '\0'; 1: 941: *ex_c = '\0'; 1: 942: *ee_c = '\0'; 1: 943: *bd_c = '\0'; 1: 944: *ln_c = '\0'; 1: 945: *mh_c = '\0'; 1: 946: *or_c = '\0'; 1: 947: *so_c = '\0'; 1: 948: *pi_c = '\0'; 1: 949: *cd_c = '\0'; 1: 950: *fi_c = '\0'; 1: 951: *ef_c = '\0'; 1: 952: *su_c = '\0'; 1: 953: *sg_c = '\0'; 1: 954: *ca_c = '\0'; 1: 955: *st_c = '\0'; 1: 956: *tw_c = '\0'; 1: 957: *ow_c = '\0'; 1: 958: *no_c = '\0'; 1: 959: *uf_c = '\0'; -: 960: -: 961: /* Set the LS_COLORS environment variable with default values */ 1: 962: char lsc[] = DEF_LS_COLORS; -: 963: 1: 964: if (setenv("LS_COLORS", lsc, 1) == -1) 1: 964-block 0 call 0 returned 1 branch 1 taken 0 (fallthrough) branch 2 taken 1 #####: 965: fprintf(stderr, _("%s: Error registering environment colors\n"), %%%%%: 965-block 0 call 0 never executed call 1 never executed unconditional 2 never executed -: 966: PROGRAM_NAME); -: 967: } else { -: 968: /* Set the LS_COLORS environment variable to use CliFM own -: 969: * colors. In this way, files listed for TAB completion will -: 970: * use CliFM colors instead of system colors */ -: 971: -: 972: /* Strip CLiFM custom file types (nd, ne, nf, ed, ef, ee, uf, -: 973: * bm, el, mi, dl, tx, df, dc, wc, dh, li, ti, em, wm, nm, si, -: 974: * and ca), from filecolors to construct a valid value for -: 975: * LS_COLORS */ 26: 976: size_t buflen = 0, linec_len = strlen(filecolors); 26: 977: char *ls_buf = (char *)NULL; 26: 978: int i = 0; -: 979: 26: 980: ls_buf = (char *)xnmalloc(linec_len + 1, sizeof(char)); 26: 980-block 0 call 0 returned 26 -: 981: 4575: 982: while (filecolors[i]) { unconditional 0 taken 26 4575: 982-block 0 branch 1 taken 4549 branch 2 taken 26 (fallthrough) 4549: 983: int rem = 0; -: 984: 4549: 985: if ((int)i < (int)(linec_len - 3) && ((filecolors[i] == 'n' 4549: 985-block 0 branch 0 taken 4549 (fallthrough) branch 1 taken 0 4549: 985-block 1 branch 2 taken 130 (fallthrough) branch 3 taken 4419 130: 986: && (filecolors[i + 1] == 'd' || filecolors[i + 1] == 'e' 130: 986-block 0 branch 0 taken 104 (fallthrough) branch 1 taken 26 104: 986-block 1 branch 2 taken 78 (fallthrough) branch 3 taken 26 4497: 987: || filecolors[i + 1] == 'f')) || (filecolors[i] == 'e' 78: 987-block 0 branch 0 taken 52 (fallthrough) branch 1 taken 26 4471: 987-block 1 branch 2 taken 104 (fallthrough) branch 3 taken 4367 104: 988: && (filecolors[i + 1] == 'd' || filecolors[i + 1] == 'f' 104: 988-block 0 branch 0 taken 78 (fallthrough) branch 1 taken 26 78: 988-block 1 branch 2 taken 52 (fallthrough) branch 3 taken 26 4419: 989: || filecolors[i + 1] == 'e')) || (filecolors[i] == 'u' 52: 989-block 0 branch 0 taken 26 (fallthrough) branch 1 taken 26 4393: 989-block 1 branch 2 taken 52 (fallthrough) branch 3 taken 4341 4393: 990: && filecolors[i + 1] == 'f') || (filecolors[i] == 'c' 52: 990-block 0 branch 0 taken 26 (fallthrough) branch 1 taken 26 4367: 990-block 1 branch 2 taken 52 (fallthrough) branch 3 taken 4315 4367: 991: && filecolors[i + 1] == 'a') || (filecolors[i] == 's' 52: 991-block 0 branch 0 taken 26 (fallthrough) branch 1 taken 26 4341: 991-block 1 branch 2 taken 104 (fallthrough) branch 3 taken 4237 4341: 992: && filecolors[i + 1] == 'h') || (filecolors[i] == 's' 104: 992-block 0 branch 0 taken 104 (fallthrough) branch 1 taken 0 4341: 992-block 1 branch 2 taken 104 (fallthrough) branch 3 taken 4237 4341: 993: && filecolors[i + 1] == 'f') || (filecolors[i] == 's' 104: 993-block 0 branch 0 taken 104 (fallthrough) branch 1 taken 0 4341: 993-block 1 branch 2 taken 104 (fallthrough) branch 3 taken 4237 4341: 994: && filecolors[i + 1] == 'c') || (filecolors[i] == 's' 104: 994-block 0 branch 0 taken 104 (fallthrough) branch 1 taken 0 4341: 994-block 1 branch 2 taken 104 (fallthrough) branch 3 taken 4237 4341: 995: && filecolors[i + 1] == 'x') || (filecolors[i] == 'h' 104: 995-block 0 branch 0 taken 104 (fallthrough) branch 1 taken 0 4341: 995-block 1 branch 2 taken 26 (fallthrough) branch 3 taken 4315 4341: 996: && filecolors[i + 1] == 'b') || (filecolors[i] == 'h' 26: 996-block 0 branch 0 taken 26 (fallthrough) branch 1 taken 0 4341: 996-block 1 branch 2 taken 26 (fallthrough) branch 3 taken 4315 4341: 997: && filecolors[i + 1] == 'c') || (filecolors[i] == 'h' 26: 997-block 0 branch 0 taken 26 (fallthrough) branch 1 taken 0 4341: 997-block 1 branch 2 taken 26 (fallthrough) branch 3 taken 4315 4341: 998: && filecolors[i + 1] == 'e') || (filecolors[i] == 'h' 26: 998-block 0 branch 0 taken 26 (fallthrough) branch 1 taken 0 4341: 998-block 1 branch 2 taken 26 (fallthrough) branch 3 taken 4315 4341: 999: && filecolors[i + 1] == 'n') || (filecolors[i] == 'h' 26: 999-block 0 branch 0 taken 26 (fallthrough) branch 1 taken 0 4341: 999-block 1 branch 2 taken 26 (fallthrough) branch 3 taken 4315 4341: 1000: && filecolors[i + 1] == 'p') || (filecolors[i] == 'h' 26: 1000-block 0 branch 0 taken 26 (fallthrough) branch 1 taken 0 4341: 1000-block 1 branch 2 taken 26 (fallthrough) branch 3 taken 4315 4341: 1001: && filecolors[i + 1] == 'q') || (filecolors[i] == 'h' 26: 1001-block 0 branch 0 taken 26 (fallthrough) branch 1 taken 0 4341: 1001-block 1 branch 2 taken 26 (fallthrough) branch 3 taken 4315 4341: 1002: && filecolors[i + 1] == 'r') || (filecolors[i] == 'h' 26: 1002-block 0 branch 0 taken 26 (fallthrough) branch 1 taken 0 4341: 1002-block 1 branch 2 taken 26 (fallthrough) branch 3 taken 4315 4341: 1003: && filecolors[i + 1] == 's') || (filecolors[i] == 'h' 26: 1003-block 0 branch 0 taken 26 (fallthrough) branch 1 taken 0 4341: 1003-block 1 branch 2 taken 26 (fallthrough) branch 3 taken 4315 234: 1004: && filecolors[i + 1] == 'v')) && filecolors[i + 2] == '=') { 26: 1004-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 26 208: 1004-block 1 branch 2 taken 208 (fallthrough) branch 3 taken 0 -: 1005: -: 1006: /* If one of the above is found, move to the next -: 1007: * color code */ 208: 1008: rem = 1; 1476: 1009: for (i += 3; filecolors[i] && filecolors[i] != ':'; i++); 208: 1009-block 0 unconditional 0 taken 208 1268: 1009-block 1 unconditional 1 taken 1268 1476: 1009-block 2 branch 2 taken 1476 (fallthrough) branch 3 taken 0 1476: 1009-block 3 branch 4 taken 1268 branch 5 taken 208 (fallthrough) -: 1010: } -: 1011: 4549: 1012: if (filecolors[i]) { 4549: 1012-block 0 branch 0 taken 4549 (fallthrough) branch 1 taken 0 4549: 1013: if (!rem) 4549: 1013-block 0 branch 0 taken 4341 (fallthrough) branch 1 taken 208 4341: 1014: ls_buf[buflen++] = filecolors[i]; 4341: 1014-block 0 unconditional 0 taken 4341 -: 1015: } else { #####: 1016: break; %%%%%: 1016-block 0 unconditional 0 never executed -: 1017: } -: 1018: 4549: 1019: i++; 4549: 1019-block 0 unconditional 0 taken 4549 -: 1020: } -: 1021: 26: 1022: if (buflen) { 26: 1022-block 0 branch 0 taken 26 (fallthrough) branch 1 taken 0 26: 1023: ls_buf[buflen] = '\0'; -: 1024: 26: 1025: if (setenv("LS_COLORS", ls_buf, 1) == -1) 26: 1025-block 0 call 0 returned 26 branch 1 taken 0 (fallthrough) branch 2 taken 26 #####: 1026: fprintf(stderr, _("%s: Error registering environment " %%%%%: 1026-block 0 call 0 never executed call 1 never executed unconditional 2 never executed -: 1027: "colors\n"), PROGRAM_NAME); 26: 1028: free(ls_buf); 26: 1029: ls_buf = (char *)NULL; 26: 1029-block 0 unconditional 0 taken 26 -: 1030: } -: 1031: -: 1032: /* Split the colors line into substrings (one per color) */ 26: 1033: char *p = filecolors, *buf = (char *)NULL, **colors = (char **)NULL; 26: 1034: size_t len = 0, words = 0; 26: 1035: int eol = 0; -: 1036: 6493: 1037: while (!eol) { 26: 1037-block 0 unconditional 0 taken 26 6493: 1037-block 1 branch 1 taken 6467 branch 2 taken 26 (fallthrough) 6467: 1038: switch (*p) { 6467: 1038-block 0 branch 0 taken 650 branch 1 taken 5817 -: 1039: 650: 1040: case '\0': /* fallthrough */ -: 1041: case '\n': /* fallthrough */ -: 1042: case ':': 650: 1043: if (!buf) 650: 1043-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 650 #####: 1044: break; %%%%%: 1044-block 0 unconditional 0 never executed 650: 1045: buf[len] = '\0'; 650: 1046: colors = (char **)xrealloc(colors, (words + 1) * sizeof(char *)); 650: 1046-block 0 call 0 returned 650 650: 1047: colors[words++] = savestring(buf, len); call 0 returned 650 650: 1048: *buf = '\0'; -: 1049: 650: 1050: if (!*p) branch 0 taken 26 (fallthrough) branch 1 taken 624 26: 1051: eol = 1; 26: 1051-block 0 unconditional 0 taken 26 -: 1052: 650: 1053: len = 0; 650: 1054: p++; 650: 1055: break; 650: 1055-block 0 unconditional 0 taken 650 -: 1056: 5817: 1057: default: 5817: 1058: buf = (char *)xrealloc(buf, (len + 2) * sizeof(char)); 5817: 1058-block 0 call 0 returned 5817 5817: 1059: buf[len++] = *(p++); 5817: 1060: break; unconditional 0 taken 5817 -: 1061: } -: 1062: } -: 1063: 26: 1064: p = (char *)NULL; 26: 1065: free(filecolors); 26: 1066: filecolors = (char *)NULL; -: 1067: 26: 1068: if (buf) { 26: 1068-block 0 branch 0 taken 26 (fallthrough) branch 1 taken 0 26: 1069: free(buf); 26: 1070: buf = (char *)NULL; 26: 1070-block 0 unconditional 0 taken 26 -: 1071: } -: 1072: 26: 1073: if (colors) { 26: 1073-block 0 branch 0 taken 26 (fallthrough) branch 1 taken 0 26: 1074: colors = (char **)xrealloc(colors, (words + 1) * sizeof(char *)); 26: 1074-block 0 call 0 returned 26 26: 1075: colors[words] = (char *)NULL; unconditional 0 taken 26 -: 1076: } -: 1077: -: 1078: /* Set the color variables */ 26: 1079: i = (int)words; 676: 1080: while (--i >= 0) { 26: 1080-block 0 unconditional 0 taken 26 676: 1080-block 1 branch 1 taken 650 branch 2 taken 26 (fallthrough) 650: 1081: if (*colors[i] == 'd' && strncmp(colors[i], "di=", 3) == 0) { 650: 1081-block 0 branch 0 taken 26 (fallthrough) branch 1 taken 624 26: 1081-block 1 branch 2 taken 26 (fallthrough) branch 3 taken 0 26: 1082: if (!is_color_code(colors[i] + 3)) 26: 1082-block 0 call 0 returned 26 branch 1 taken 0 (fallthrough) branch 2 taken 26 #####: 1083: *di_c = '\0'; %%%%%: 1083-block 0 unconditional 0 never executed -: 1084: else 26: 1085: snprintf(di_c, MAX_COLOR - 1, "\x1b[%sm", colors[i] + 3); 26: 1085-block 0 unconditional 0 taken 26 -: 1086: 624*: 1087: } else if (*colors[i] == 'd' && strncmp(colors[i], "df=", 3) == 0) { 624: 1087-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 624 %%%%%: 1087-block 1 branch 2 never executed branch 3 never executed #####: 1088: if (!is_color_code(colors[i] + 3)) %%%%%: 1088-block 0 call 0 never executed branch 1 never executed branch 2 never executed #####: 1089: *df_c = '\0'; %%%%%: 1089-block 0 unconditional 0 never executed -: 1090: else #####: 1091: snprintf(df_c, MAX_COLOR - 1, "\x1b[%s;49m", #####: 1092: colors[i] + 3); %%%%%: 1092-block 0 unconditional 0 never executed -: 1093: 624*: 1094: } else if (*colors[i] == 'd' && strncmp(colors[i], "dc=", 3) == 0) { 624: 1094-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 624 %%%%%: 1094-block 1 branch 2 never executed branch 3 never executed #####: 1095: if (!is_color_code(colors[i] + 3)) %%%%%: 1095-block 0 call 0 never executed branch 1 never executed branch 2 never executed #####: 1096: *dc_c = '\0'; %%%%%: 1096-block 0 unconditional 0 never executed -: 1097: else #####: 1098: snprintf(dc_c, MAX_COLOR - 1, "\x1b[%sm", colors[i] + 3); %%%%%: 1098-block 0 unconditional 0 never executed -: 1099: -: 1100:/* } else if (*colors[i] == 'w' && strncmp(colors[i], "wc=", 3) == 0) { -: 1101: if (!is_color_code(colors[i] + 3)) -: 1102: *wc_c = '\0'; -: 1103: else -: 1104: snprintf(wc_c, MAX_COLOR - 1, "\x1b[%sm", colors[i] + 3); -: 1105: -: 1106: } else if (*colors[i] == 's' && strncmp(colors[i], "sh=", 3) == 0) { -: 1107: if (!is_color_code(colors[i] + 3)) -: 1108: *sh_c = '\0'; -: 1109: else -: 1110: snprintf(sh_c, MAX_COLOR - 1, "\x1b[%sm", -: 1111: colors[i] + 3); -: 1112: -: 1113: } else if (*colors[i] == 's' && strncmp(colors[i], "sf=", 3) == 0) { -: 1114: if (!is_color_code(colors[i] + 3)) -: 1115: *sf_c = '\0'; -: 1116: else -: 1117: snprintf(sf_c, MAX_COLOR - 1, "\x1b[%sm", -: 1118: colors[i] + 3); -: 1119: -: 1120: } else if (*colors[i] == 's' && strncmp(colors[i], "sc=", 3) == 0) { -: 1121: if (!is_color_code(colors[i] + 3)) -: 1122: *sc_c = '\0'; -: 1123: else -: 1124: snprintf(sc_c, MAX_COLOR - 1, "\x1b[%sm", -: 1125: colors[i] + 3); -: 1126: -: 1127: } else if (*colors[i] == 's' && strncmp(colors[i], "sx=", 3) == 0) { -: 1128: if (!is_color_code(colors[i] + 3)) -: 1129: *sx_c = '\0'; -: 1130: else -: 1131: snprintf(sx_c, MAX_COLOR - 1, "\x1b[%sm", -: 1132: colors[i] + 3); */ -: 1133: 624*: 1134: } else if (*colors[i] == 'd' && strncmp(colors[i], "dh=", 3) == 0) { 624: 1134-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 624 %%%%%: 1134-block 1 branch 2 never executed branch 3 never executed #####: 1135: if (!is_color_code(colors[i] + 3)) %%%%%: 1135-block 0 call 0 never executed branch 1 never executed branch 2 never executed #####: 1136: *dh_c = '\0'; %%%%%: 1136-block 0 unconditional 0 never executed -: 1137: else #####: 1138: snprintf(dh_c, MAX_COLOR - 1, "\x1b[%sm", colors[i] + 3); %%%%%: 1138-block 0 unconditional 0 never executed 624: 1139: } else if (*colors[i] == 'n' && strncmp(colors[i], "nd=", 3) == 0) { 624: 1139-block 0 branch 0 taken 104 (fallthrough) branch 1 taken 520 104: 1139-block 1 branch 2 taken 26 (fallthrough) branch 3 taken 78 26: 1140: if (!is_color_code(colors[i] + 3)) 26: 1140-block 0 call 0 returned 26 branch 1 taken 0 (fallthrough) branch 2 taken 26 #####: 1141: *nd_c = '\0'; %%%%%: 1141-block 0 unconditional 0 never executed -: 1142: else 26: 1143: snprintf(nd_c, MAX_COLOR - 1, "\x1b[%sm", colors[i] + 3); 26: 1143-block 0 unconditional 0 taken 26 -: 1144: 598: 1145: } else if (*colors[i] == 'e' && strncmp(colors[i], "ed=", 3) == 0) { 598: 1145-block 0 branch 0 taken 104 (fallthrough) branch 1 taken 494 104: 1145-block 1 branch 2 taken 26 (fallthrough) branch 3 taken 78 26: 1146: if (!is_color_code(colors[i] + 3)) 26: 1146-block 0 call 0 returned 26 branch 1 taken 0 (fallthrough) branch 2 taken 26 #####: 1147: *ed_c = '\0'; %%%%%: 1147-block 0 unconditional 0 never executed -: 1148: else 26: 1149: snprintf(ed_c, MAX_COLOR - 1, "\x1b[%sm", colors[i] + 3); 26: 1149-block 0 unconditional 0 taken 26 -: 1150: 572: 1151: } else if (*colors[i] == 'n' && strncmp(colors[i], "ne=", 3) == 0) { 572: 1151-block 0 branch 0 taken 78 (fallthrough) branch 1 taken 494 78: 1151-block 1 branch 2 taken 26 (fallthrough) branch 3 taken 52 26: 1152: if (!is_color_code(colors[i] + 3)) 26: 1152-block 0 call 0 returned 26 branch 1 taken 0 (fallthrough) branch 2 taken 26 #####: 1153: *ne_c = '\0'; %%%%%: 1153-block 0 unconditional 0 never executed -: 1154: else 26: 1155: snprintf(ne_c, MAX_COLOR - 1, "\x1b[%sm", colors[i] + 3); 26: 1155-block 0 unconditional 0 taken 26 -: 1156: 546: 1157: } else if (*colors[i] == 'f' && strncmp(colors[i], "fi=", 3) == 0) { 546: 1157-block 0 branch 0 taken 26 (fallthrough) branch 1 taken 520 26: 1157-block 1 branch 2 taken 26 (fallthrough) branch 3 taken 0 26: 1158: if (!is_color_code(colors[i] + 3)) 26: 1158-block 0 call 0 returned 26 branch 1 taken 0 (fallthrough) branch 2 taken 26 #####: 1159: *fi_c = '\0'; %%%%%: 1159-block 0 unconditional 0 never executed -: 1160: else 26: 1161: snprintf(fi_c, MAX_COLOR - 1, "\x1b[%sm", colors[i] + 3); 26: 1161-block 0 unconditional 0 taken 26 -: 1162: 520: 1163: } else if (*colors[i] == 'e' && strncmp(colors[i], "ef=", 3) == 0) { 520: 1163-block 0 branch 0 taken 78 (fallthrough) branch 1 taken 442 78: 1163-block 1 branch 2 taken 26 (fallthrough) branch 3 taken 52 26: 1164: if (!is_color_code(colors[i] + 3)) 26: 1164-block 0 call 0 returned 26 branch 1 taken 0 (fallthrough) branch 2 taken 26 #####: 1165: *ef_c = '\0'; %%%%%: 1165-block 0 unconditional 0 never executed -: 1166: else 26: 1167: snprintf(ef_c, MAX_COLOR - 1, "\x1b[%sm", colors[i] + 3); 26: 1167-block 0 unconditional 0 taken 26 -: 1168: 494: 1169: } else if (*colors[i] == 'n' && strncmp(colors[i], "nf=", 3) == 0) { 494: 1169-block 0 branch 0 taken 52 (fallthrough) branch 1 taken 442 52: 1169-block 1 branch 2 taken 26 (fallthrough) branch 3 taken 26 26: 1170: if (!is_color_code(colors[i] + 3)) 26: 1170-block 0 call 0 returned 26 branch 1 taken 0 (fallthrough) branch 2 taken 26 #####: 1171: *nf_c = '\0'; %%%%%: 1171-block 0 unconditional 0 never executed -: 1172: else 26: 1173: snprintf(nf_c, MAX_COLOR - 1, "\x1b[%sm", colors[i] + 3); 26: 1173-block 0 unconditional 0 taken 26 -: 1174: 468: 1175: } else if (*colors[i] == 'l' && strncmp(colors[i], "ln=", 3) == 0) { 468: 1175-block 0 branch 0 taken 26 (fallthrough) branch 1 taken 442 26: 1175-block 1 branch 2 taken 26 (fallthrough) branch 3 taken 0 26: 1176: if (!is_color_code(colors[i] + 3)) 26: 1176-block 0 call 0 returned 26 branch 1 taken 0 (fallthrough) branch 2 taken 26 #####: 1177: *ln_c = '\0'; %%%%%: 1177-block 0 unconditional 0 never executed -: 1178: else 26: 1179: snprintf(ln_c, MAX_COLOR - 1, "\x1b[%sm", colors[i] + 3); 26: 1179-block 0 unconditional 0 taken 26 -: 1180: 442: 1181: } else if (*colors[i] == 'o' && strncmp(colors[i], "or=", 3) == 0) { 442: 1181-block 0 branch 0 taken 52 (fallthrough) branch 1 taken 390 52: 1181-block 1 branch 2 taken 26 (fallthrough) branch 3 taken 26 26: 1182: if (!is_color_code(colors[i] + 3)) 26: 1182-block 0 call 0 returned 26 branch 1 taken 0 (fallthrough) branch 2 taken 26 #####: 1183: *or_c = '\0'; %%%%%: 1183-block 0 unconditional 0 never executed -: 1184: else 26: 1185: snprintf(or_c, MAX_COLOR - 1, "\x1b[%sm", colors[i] + 3); 26: 1185-block 0 unconditional 0 taken 26 -: 1186: 416: 1187: } else if (*colors[i] == 'e' && strncmp(colors[i], "ex=", 3) == 0) { 416: 1187-block 0 branch 0 taken 52 (fallthrough) branch 1 taken 364 52: 1187-block 1 branch 2 taken 26 (fallthrough) branch 3 taken 26 26: 1188: if (!is_color_code(colors[i] + 3)) 26: 1188-block 0 call 0 returned 26 branch 1 taken 0 (fallthrough) branch 2 taken 26 #####: 1189: *ex_c = '\0'; %%%%%: 1189-block 0 unconditional 0 never executed -: 1190: else 26: 1191: snprintf(ex_c, MAX_COLOR - 1, "\x1b[%sm", colors[i] + 3); 26: 1191-block 0 unconditional 0 taken 26 -: 1192: 390: 1193: } else if (*colors[i] == 'e' && strncmp(colors[i], "ee=", 3) == 0) { 390: 1193-block 0 branch 0 taken 26 (fallthrough) branch 1 taken 364 26: 1193-block 1 branch 2 taken 26 (fallthrough) branch 3 taken 0 26: 1194: if (!is_color_code(colors[i] + 3)) 26: 1194-block 0 call 0 returned 26 branch 1 taken 0 (fallthrough) branch 2 taken 26 #####: 1195: *ee_c = '\0'; %%%%%: 1195-block 0 unconditional 0 never executed -: 1196: else 26: 1197: snprintf(ee_c, MAX_COLOR - 1, "\x1b[%sm", colors[i] + 3); 26: 1197-block 0 unconditional 0 taken 26 -: 1198: 364: 1199: } else if (*colors[i] == 'b' && strncmp(colors[i], "bd=", 3) == 0) { 364: 1199-block 0 branch 0 taken 26 (fallthrough) branch 1 taken 338 26: 1199-block 1 branch 2 taken 26 (fallthrough) branch 3 taken 0 26: 1200: if (!is_color_code(colors[i] + 3)) 26: 1200-block 0 call 0 returned 26 branch 1 taken 0 (fallthrough) branch 2 taken 26 #####: 1201: *bd_c = '\0'; %%%%%: 1201-block 0 unconditional 0 never executed -: 1202: else 26: 1203: snprintf(bd_c, MAX_COLOR - 1, "\x1b[%sm", colors[i] + 3); 26: 1203-block 0 unconditional 0 taken 26 -: 1204: 338: 1205: } else if (*colors[i] == 'c' && strncmp(colors[i], "cd=", 3) == 0) { 338: 1205-block 0 branch 0 taken 52 (fallthrough) branch 1 taken 286 52: 1205-block 1 branch 2 taken 26 (fallthrough) branch 3 taken 26 26: 1206: if (!is_color_code(colors[i] + 3)) 26: 1206-block 0 call 0 returned 26 branch 1 taken 0 (fallthrough) branch 2 taken 26 #####: 1207: *cd_c = '\0'; %%%%%: 1207-block 0 unconditional 0 never executed -: 1208: else 26: 1209: snprintf(cd_c, MAX_COLOR - 1, "\x1b[%sm", colors[i] + 3); 26: 1209-block 0 unconditional 0 taken 26 -: 1210: 312: 1211: } else if (*colors[i] == 'p' && strncmp(colors[i], "pi=", 3) == 0) { 312: 1211-block 0 branch 0 taken 26 (fallthrough) branch 1 taken 286 26: 1211-block 1 branch 2 taken 26 (fallthrough) branch 3 taken 0 26: 1212: if (!is_color_code(colors[i] + 3)) 26: 1212-block 0 call 0 returned 26 branch 1 taken 0 (fallthrough) branch 2 taken 26 #####: 1213: *pi_c = '\0'; %%%%%: 1213-block 0 unconditional 0 never executed -: 1214: else 26: 1215: snprintf(pi_c, MAX_COLOR - 1, "\x1b[%sm", colors[i] + 3); 26: 1215-block 0 unconditional 0 taken 26 -: 1216: 286: 1217: } else if (*colors[i] == 's' && strncmp(colors[i], "so=", 3) == 0) { 286: 1217-block 0 branch 0 taken 104 (fallthrough) branch 1 taken 182 104: 1217-block 1 branch 2 taken 26 (fallthrough) branch 3 taken 78 26: 1218: if (!is_color_code(colors[i] + 3)) 26: 1218-block 0 call 0 returned 26 branch 1 taken 0 (fallthrough) branch 2 taken 26 #####: 1219: *so_c = '\0'; %%%%%: 1219-block 0 unconditional 0 never executed -: 1220: else 26: 1221: snprintf(so_c, MAX_COLOR - 1, "\x1b[%sm", colors[i] + 3); 26: 1221-block 0 unconditional 0 taken 26 -: 1222: 260: 1223: } else if (*colors[i] == 's' && strncmp(colors[i], "su=", 3) == 0) { 260: 1223-block 0 branch 0 taken 78 (fallthrough) branch 1 taken 182 78: 1223-block 1 branch 2 taken 26 (fallthrough) branch 3 taken 52 26: 1224: if (!is_color_code(colors[i] + 3)) 26: 1224-block 0 call 0 returned 26 branch 1 taken 0 (fallthrough) branch 2 taken 26 #####: 1225: *su_c = '\0'; %%%%%: 1225-block 0 unconditional 0 never executed -: 1226: else 26: 1227: snprintf(su_c, MAX_COLOR - 1, "\x1b[%sm", colors[i] + 3); 26: 1227-block 0 unconditional 0 taken 26 -: 1228: 234: 1229: } else if (*colors[i] == 's' && strncmp(colors[i], "sg=", 3) == 0) { 234: 1229-block 0 branch 0 taken 52 (fallthrough) branch 1 taken 182 52: 1229-block 1 branch 2 taken 26 (fallthrough) branch 3 taken 26 26: 1230: if (!is_color_code(colors[i] + 3)) 26: 1230-block 0 call 0 returned 26 branch 1 taken 0 (fallthrough) branch 2 taken 26 #####: 1231: *sg_c = '\0'; %%%%%: 1231-block 0 unconditional 0 never executed -: 1232: else 26: 1233: snprintf(sg_c, MAX_COLOR - 1, "\x1b[%sm", colors[i] + 3); 26: 1233-block 0 unconditional 0 taken 26 -: 1234: 208: 1235: } else if (*colors[i] == 't' && strncmp(colors[i], "tw=", 3) == 0) { 208: 1235-block 0 branch 0 taken 26 (fallthrough) branch 1 taken 182 26: 1235-block 1 branch 2 taken 26 (fallthrough) branch 3 taken 0 26: 1236: if (!is_color_code(colors[i] + 3)) 26: 1236-block 0 call 0 returned 26 branch 1 taken 0 (fallthrough) branch 2 taken 26 #####: 1237: *tw_c = '\0'; %%%%%: 1237-block 0 unconditional 0 never executed -: 1238: else 26: 1239: snprintf(tw_c, MAX_COLOR - 1, "\x1b[%sm", colors[i] + 3); 26: 1239-block 0 unconditional 0 taken 26 -: 1240: 182: 1241: } else if (*colors[i] == 's' && strncmp(colors[i], "st=", 3) == 0) { 182: 1241-block 0 branch 0 taken 26 (fallthrough) branch 1 taken 156 26: 1241-block 1 branch 2 taken 26 (fallthrough) branch 3 taken 0 26: 1242: if (!is_color_code(colors[i] + 3)) 26: 1242-block 0 call 0 returned 26 branch 1 taken 0 (fallthrough) branch 2 taken 26 #####: 1243: *st_c = '\0'; %%%%%: 1243-block 0 unconditional 0 never executed -: 1244: else 26: 1245: snprintf(st_c, MAX_COLOR - 1, "\x1b[%sm", colors[i] + 3); 26: 1245-block 0 unconditional 0 taken 26 -: 1246: 156: 1247: } else if (*colors[i] == 'o' && strncmp(colors[i], "ow=", 3) == 0) { 156: 1247-block 0 branch 0 taken 26 (fallthrough) branch 1 taken 130 26: 1247-block 1 branch 2 taken 26 (fallthrough) branch 3 taken 0 26: 1248: if (!is_color_code(colors[i] + 3)) 26: 1248-block 0 call 0 returned 26 branch 1 taken 0 (fallthrough) branch 2 taken 26 #####: 1249: *ow_c = '\0'; %%%%%: 1249-block 0 unconditional 0 never executed -: 1250: else 26: 1251: snprintf(ow_c, MAX_COLOR - 1, "\x1b[%sm", colors[i] + 3); 26: 1251-block 0 unconditional 0 taken 26 -: 1252: 130: 1253: } else if (*colors[i] == 'c' && strncmp(colors[i], "ca=", 3) == 0) { 130: 1253-block 0 branch 0 taken 26 (fallthrough) branch 1 taken 104 26: 1253-block 1 branch 2 taken 26 (fallthrough) branch 3 taken 0 26: 1254: if (!is_color_code(colors[i] + 3)) 26: 1254-block 0 call 0 returned 26 branch 1 taken 0 (fallthrough) branch 2 taken 26 #####: 1255: *ca_c = '\0'; %%%%%: 1255-block 0 unconditional 0 never executed -: 1256: else 26: 1257: snprintf(ca_c, MAX_COLOR - 1, "\x1b[%sm", colors[i] + 3); 26: 1257-block 0 unconditional 0 taken 26 -: 1258: 104: 1259: } else if (*colors[i] == 'n' && strncmp(colors[i], "no=", 3) == 0) { 104: 1259-block 0 branch 0 taken 26 (fallthrough) branch 1 taken 78 26: 1259-block 1 branch 2 taken 26 (fallthrough) branch 3 taken 0 26: 1260: if (!is_color_code(colors[i] + 3)) 26: 1260-block 0 call 0 returned 26 branch 1 taken 0 (fallthrough) branch 2 taken 26 #####: 1261: *no_c = '\0'; %%%%%: 1261-block 0 unconditional 0 never executed -: 1262: else 26: 1263: snprintf(no_c, MAX_COLOR - 1, "\x1b[%sm", colors[i] + 3); 26: 1263-block 0 unconditional 0 taken 26 -: 1264: 78: 1265: } else if (*colors[i] == 'm' && strncmp(colors[i], "mh=", 3) == 0) { 78: 1265-block 0 branch 0 taken 26 (fallthrough) branch 1 taken 52 26: 1265-block 1 branch 2 taken 26 (fallthrough) branch 3 taken 0 26: 1266: if (!is_color_code(colors[i] + 3)) 26: 1266-block 0 call 0 returned 26 branch 1 taken 0 (fallthrough) branch 2 taken 26 #####: 1267: *mh_c = '\0'; %%%%%: 1267-block 0 unconditional 0 never executed -: 1268: else 26: 1269: snprintf(mh_c, MAX_COLOR - 1, "\x1b[%sm", colors[i] + 3); 26: 1269-block 0 unconditional 0 taken 26 -: 1270: 52: 1271: } else if (*colors[i] == 'u' && strncmp(colors[i], "uf=", 3) == 0) { 52: 1271-block 0 branch 0 taken 26 (fallthrough) branch 1 taken 26 26: 1271-block 1 branch 2 taken 26 (fallthrough) branch 3 taken 0 26: 1272: if (!is_color_code(colors[i] + 3)) 26: 1272-block 0 call 0 returned 26 branch 1 taken 0 (fallthrough) branch 2 taken 26 #####: 1273: *uf_c = '\0'; %%%%%: 1273-block 0 unconditional 0 never executed -: 1274: else 26: 1275: snprintf(uf_c, MAX_COLOR - 1, "\x1b[%sm", colors[i] + 3); 26: 1275-block 0 unconditional 0 taken 26 -: 1276: } -: 1277: 650: 1278: free(colors[i]); 650: 1278-block 0 unconditional 0 taken 650 -: 1279: } -: 1280: 26: 1281: free(colors); 26: 1282: colors = (char **)NULL; 26: 1282-block 0 unconditional 0 taken 26 -: 1283: } -: 1284: -: 1285: /* If some color was not set or it was a wrong color code, set the -: 1286: * default */ 27: 1287: if (!*hb_c) 27: 1287-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 25 2: 1288: strcpy(hb_c, DEF_HB_C); 2: 1288-block 0 unconditional 0 taken 2 27: 1289: if (!*hc_c) 27: 1289-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 25 2: 1290: strcpy(hc_c, DEF_HC_C); 2: 1290-block 0 unconditional 0 taken 2 27: 1291: if (!*he_c) 27: 1291-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 25 2: 1292: strcpy(he_c, DEF_HE_C); 2: 1292-block 0 unconditional 0 taken 2 27: 1293: if (!*hn_c) 27: 1293-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 25 2: 1294: strcpy(hn_c, DEF_HN_C); 2: 1294-block 0 unconditional 0 taken 2 27: 1295: if (!*hp_c) 27: 1295-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 25 2: 1296: strcpy(hp_c, DEF_HP_C); 2: 1296-block 0 unconditional 0 taken 2 27: 1297: if (!*hq_c) 27: 1297-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 25 2: 1298: strcpy(hq_c, DEF_HQ_C); 2: 1298-block 0 unconditional 0 taken 2 27: 1299: if (!*hr_c) 27: 1299-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 25 2: 1300: strcpy(hr_c, DEF_HR_C); 2: 1300-block 0 unconditional 0 taken 2 27: 1301: if (!*hs_c) 27: 1301-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 25 2: 1302: strcpy(hs_c, DEF_HS_C); 2: 1302-block 0 unconditional 0 taken 2 27: 1303: if (!*hv_c) 27: 1303-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 25 2: 1304: strcpy(hv_c, DEF_HV_C); 2: 1304-block 0 unconditional 0 taken 2 -: 1305: 27: 1306: if (!*sh_c) 27: 1306-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 25 2: 1307: strcpy(sh_c, DEF_SH_C); 2: 1307-block 0 unconditional 0 taken 2 27: 1308: if (!*sf_c) 27: 1308-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 25 2: 1309: strcpy(sf_c, DEF_SF_C); 2: 1309-block 0 unconditional 0 taken 2 27: 1310: if (!*sc_c) 27: 1310-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 25 2: 1311: strcpy(sc_c, DEF_SC_C); 2: 1311-block 0 unconditional 0 taken 2 27: 1312: if (!*sx_c) 27: 1312-block 0 branch 0 taken 8 (fallthrough) branch 1 taken 19 8: 1313: strcpy(sx_c, DEF_SX_C); 8: 1313-block 0 unconditional 0 taken 8 -: 1314: 27: 1315: if (!*el_c) 27: 1315-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 26 1: 1316: strcpy(el_c, DEF_EL_C); 1: 1316-block 0 unconditional 0 taken 1 27: 1317: if (!*mi_c) 27: 1317-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 26 1: 1318: strcpy(mi_c, DEF_MI_C); 1: 1318-block 0 unconditional 0 taken 1 27: 1319: if (!*dl_c) 27: 1319-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 26 1: 1320: strcpy(dl_c, DEF_DL_C); 1: 1320-block 0 unconditional 0 taken 1 27: 1321: if (!*df_c) 27: 1321-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 26 1: 1322: strcpy(df_c, DEF_DF_C); 1: 1322-block 0 unconditional 0 taken 1 27: 1323: if (!*dc_c) 27: 1323-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 26 1: 1324: strcpy(dc_c, DEF_DC_C); 1: 1324-block 0 unconditional 0 taken 1 27: 1325: if (!*wc_c) 27: 1325-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 26 1: 1326: strcpy(wc_c, DEF_WC_C); 1: 1326-block 0 unconditional 0 taken 1 27: 1327: if (!*dh_c) 27: 1327-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 26 1: 1328: strcpy(dh_c, DEF_DH_C); 1: 1328-block 0 unconditional 0 taken 1 27: 1329: if (!*tx_c) 27: 1329-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 26 1: 1330: strcpy(tx_c, DEF_TX_C); 1: 1330-block 0 unconditional 0 taken 1 27: 1331: if (!*li_c) 27: 1331-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 26 1: 1332: strcpy(li_c, DEF_LI_C); 1: 1332-block 0 unconditional 0 taken 1 27: 1333: if (!*ti_c) 27: 1333-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 26 1: 1334: strcpy(ti_c, DEF_TI_C); 1: 1334-block 0 unconditional 0 taken 1 27: 1335: if (!*em_c) 27: 1335-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 26 1: 1336: strcpy(em_c, DEF_EM_C); 1: 1336-block 0 unconditional 0 taken 1 27: 1337: if (!*wm_c) 27: 1337-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 26 1: 1338: strcpy(wm_c, DEF_WM_C); 1: 1338-block 0 unconditional 0 taken 1 27: 1339: if (!*nm_c) 27: 1339-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 26 1: 1340: strcpy(nm_c, DEF_NM_C); 1: 1340-block 0 unconditional 0 taken 1 27: 1341: if (!*si_c) 27: 1341-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 26 1: 1342: strcpy(si_c, DEF_SI_C); 1: 1342-block 0 unconditional 0 taken 1 27: 1343: if (!*bm_c) 27: 1343-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 26 1: 1344: strcpy(bm_c, DEF_BM_C); 1: 1344-block 0 unconditional 0 taken 1 -: 1345: 27: 1346: if (!*di_c) 27: 1346-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 26 1: 1347: strcpy(di_c, DEF_DI_C); 1: 1347-block 0 unconditional 0 taken 1 27: 1348: if (!*nd_c) 27: 1348-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 26 1: 1349: strcpy(nd_c, DEF_ND_C); 1: 1349-block 0 unconditional 0 taken 1 27: 1350: if (!*ed_c) 27: 1350-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 26 1: 1351: strcpy(ed_c, DEF_ED_C); 1: 1351-block 0 unconditional 0 taken 1 27: 1352: if (!*ne_c) 27: 1352-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 26 1: 1353: strcpy(ne_c, DEF_NE_C); 1: 1353-block 0 unconditional 0 taken 1 27: 1354: if (!*fi_c) 27: 1354-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 26 1: 1355: strcpy(fi_c, DEF_FI_C); 1: 1355-block 0 unconditional 0 taken 1 27: 1356: if (!*ef_c) 27: 1356-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 26 1: 1357: strcpy(ef_c, DEF_EF_C); 1: 1357-block 0 unconditional 0 taken 1 27: 1358: if (!*nf_c) 27: 1358-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 26 1: 1359: strcpy(nf_c, DEF_NF_C); 1: 1359-block 0 unconditional 0 taken 1 27: 1360: if (!*ln_c) 27: 1360-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 26 1: 1361: strcpy(ln_c, DEF_LN_C); 1: 1361-block 0 unconditional 0 taken 1 27: 1362: if (!*or_c) 27: 1362-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 26 1: 1363: strcpy(or_c, DEF_OR_C); 1: 1363-block 0 unconditional 0 taken 1 27: 1364: if (!*pi_c) 27: 1364-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 26 1: 1365: strcpy(pi_c, DEF_PI_C); 1: 1365-block 0 unconditional 0 taken 1 27: 1366: if (!*so_c) 27: 1366-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 26 1: 1367: strcpy(so_c, DEF_SO_C); 1: 1367-block 0 unconditional 0 taken 1 27: 1368: if (!*bd_c) 27: 1368-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 26 1: 1369: strcpy(bd_c, DEF_BD_C); 1: 1369-block 0 unconditional 0 taken 1 27: 1370: if (!*cd_c) 27: 1370-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 26 1: 1371: strcpy(cd_c, DEF_CD_C); 1: 1371-block 0 unconditional 0 taken 1 27: 1372: if (!*su_c) 27: 1372-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 26 1: 1373: strcpy(su_c, DEF_SU_C); 1: 1373-block 0 unconditional 0 taken 1 27: 1374: if (!*sg_c) 27: 1374-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 26 1: 1375: strcpy(sg_c, DEF_SG_C); 1: 1375-block 0 unconditional 0 taken 1 27: 1376: if (!*st_c) 27: 1376-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 26 1: 1377: strcpy(st_c, DEF_ST_C); 1: 1377-block 0 unconditional 0 taken 1 27: 1378: if (!*tw_c) 27: 1378-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 26 1: 1379: strcpy(tw_c, DEF_TW_C); 1: 1379-block 0 unconditional 0 taken 1 27: 1380: if (!*ow_c) 27: 1380-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 26 1: 1381: strcpy(ow_c, DEF_OW_C); 1: 1381-block 0 unconditional 0 taken 1 27: 1382: if (!*ex_c) 27: 1382-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 26 1: 1383: strcpy(ex_c, DEF_EX_C); 1: 1383-block 0 unconditional 0 taken 1 27: 1384: if (!*ee_c) 27: 1384-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 26 1: 1385: strcpy(ee_c, DEF_EE_C); 1: 1385-block 0 unconditional 0 taken 1 27: 1386: if (!*ca_c) 27: 1386-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 26 1: 1387: strcpy(ca_c, DEF_CA_C); 1: 1387-block 0 unconditional 0 taken 1 27: 1388: if (!*no_c) 27: 1388-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 26 1: 1389: strcpy(no_c, DEF_NO_C); 1: 1389-block 0 unconditional 0 taken 1 27: 1390: if (!*uf_c) 27: 1390-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 26 1: 1391: strcpy(uf_c, DEF_UF_C); 1: 1391-block 0 unconditional 0 taken 1 27: 1392: if (!*mh_c) 27: 1392-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 26 1: 1393: strcpy(mh_c, DEF_MH_C); 1: 1393-block 0 unconditional 0 taken 1 -: 1394:#ifndef _NO_ICONS 27: 1395: if (!*dir_ico_c) 27: 1395-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 25 2: 1396: strcpy(dir_ico_c, DEF_DIR_ICO_C); 2: 1396-block 0 unconditional 0 taken 2 -: 1397:#endif -: 1398: 27: 1399: return EXIT_SUCCESS; 27: 1399-block 0 unconditional 0 taken 27 -: 1400:} -: 1401: -: 1402:/* Print ENTRY using color codes and I as ELN, right padding PAD -: 1403: * chars and terminating ENTRY with or without a new line char (NEW_LINE -: 1404: * 1 or 0 respectivelly) */ -: 1405:void function colors_list called 79 returned 100% blocks executed 54% 79: 1406:colors_list(const char *ent, const int i, const int pad, const int new_line) -: 1407:{ 79*: 1408: size_t i_digits = (size_t)DIGINUM(i); 79: 1408-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 79 %%%%%: 1408-block 1 branch 2 never executed branch 3 never executed %%%%%: 1408-block 2 branch 4 never executed branch 5 never executed %%%%%: 1408-block 3 branch 6 never executed branch 7 never executed %%%%%: 1408-block 4 branch 8 never executed branch 9 never executed %%%%%: 1408-block 5 branch 10 never executed branch 11 never executed %%%%%: 1408-block 6 branch 12 never executed branch 13 never executed %%%%%: 1408-block 7 branch 14 never executed branch 15 never executed %%%%%: 1408-block 8 branch 16 never executed branch 17 never executed %%%%%: 1408-block 9 unconditional 18 never executed %%%%%: 1408-block 10 unconditional 19 never executed %%%%%: 1408-block 11 unconditional 20 never executed %%%%%: 1408-block 12 unconditional 21 never executed %%%%%: 1408-block 13 unconditional 22 never executed %%%%%: 1408-block 14 unconditional 23 never executed %%%%%: 1408-block 15 unconditional 24 never executed %%%%%: 1408-block 16 unconditional 25 never executed %%%%%: 1408-block 17 unconditional 26 never executed %%%%%: 1408-block 18 unconditional 27 never executed %%%%%: 1408-block 19 unconditional 28 never executed %%%%%: 1408-block 20 unconditional 29 never executed %%%%%: 1408-block 21 unconditional 30 never executed %%%%%: 1408-block 22 unconditional 31 never executed %%%%%: 1408-block 23 unconditional 32 never executed %%%%%: 1408-block 24 unconditional 33 never executed %%%%%: 1408-block 25 unconditional 34 never executed 79: 1408-block 26 unconditional 35 taken 79 -: 1409: -: 1410: /* Num (i) + space + null byte */ 79: 1411: char *index = (char *)xnmalloc(i_digits + 2, sizeof(char)); 79: 1411-block 0 call 0 returned 79 -: 1412: 79: 1413: if (i > 0) /* When listing files in CWD */ branch 0 taken 73 (fallthrough) branch 1 taken 6 73: 1414: sprintf(index, "%d ", i); 73: 1414-block 0 unconditional 0 taken 73 6: 1415: else if (i == -1) /* ELN for entry could not be found */ 6: 1415-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 6 #####: 1416: sprintf(index, "? "); %%%%%: 1416-block 0 unconditional 0 never executed -: 1417: else -: 1418: /* When listing files NOT in CWD (called from search function and -: 1419: * first argument is a path: "/search_str /path") 'i' is zero. In -: 1420: * this case, no index should be printed at all */ 6: 1421: index[0] = '\0'; 6: 1421-block 0 unconditional 0 taken 6 -: 1422: -: 1423: struct stat file_attrib; 79: 1424: if (lstat(ent, &file_attrib) == -1) { 79: 1424-block 0 call 0 returned 79 branch 1 taken 1 (fallthrough) branch 2 taken 78 1*: 1425: fprintf(stderr, "%s%s%s%s%-*s%s%s", el_c, index, df_c, 1: 1425-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 0 1: 1425-block 1 unconditional 2 taken 1 %%%%%: 1425-block 2 unconditional 3 never executed 1: 1425-block 3 call 4 returned 1 -: 1426: uf_c, pad, ent, df_c, new_line ? "\n" : ""); 1: 1427: free(index); 1: 1428: return; unconditional 0 taken 1 -: 1429: } -: 1430: 78: 1431: char *linkname = (char *)NULL; 78: 1432: char ext_color[MAX_COLOR] = ""; 78: 1433: char *color = fi_c; -: 1434: -: 1435:#ifdef _LINUX_CAP -: 1436: cap_t cap; -: 1437:#endif -: 1438: 78: 1439: switch (file_attrib.st_mode & S_IFMT) { 78: 1439-block 0 branch 0 taken 57 branch 1 taken 16 branch 2 taken 5 branch 3 taken 0 branch 4 taken 0 branch 5 taken 0 branch 6 taken 0 branch 7 taken 0 -: 1440: 57: 1441: case S_IFREG: 57: 1442: if (access(ent, R_OK) == -1) { 57: 1442-block 0 call 0 returned 57 branch 1 taken 0 (fallthrough) branch 2 taken 57 #####: 1443: color = nf_c; %%%%%: 1443-block 0 unconditional 0 never executed 57: 1444: } else if (file_attrib.st_mode & S_ISUID) { /* set uid file */ 57: 1444-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 57 #####: 1445: color = su_c; %%%%%: 1445-block 0 unconditional 0 never executed 57: 1446: } else if (file_attrib.st_mode & S_ISGID) { /* set gid file */ 57: 1446-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 57 #####: 1447: color = sg_c; %%%%%: 1447-block 0 unconditional 0 never executed -: 1448: } else { -: 1449:#ifdef _LINUX_CAP 57: 1450: cap = cap_get_file(ent); 57: 1450-block 0 call 0 returned 57 57: 1451: if (cap) { branch 0 taken 0 (fallthrough) branch 1 taken 57 #####: 1452: color = ca_c; #####: 1453: cap_free(cap); %%%%%: 1453-block 0 call 0 never executed unconditional 1 never executed 57: 1454: } else if (file_attrib.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) { 57: 1454-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 57 -: 1455:#else -: 1456: if (file_attrib.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) { -: 1457:#endif #####: 1458: if (file_attrib.st_size == 0) %%%%%: 1458-block 0 branch 0 never executed branch 1 never executed #####: 1459: color = ee_c; %%%%%: 1459-block 0 unconditional 0 never executed -: 1460: else #####: 1461: color = ex_c; %%%%%: 1461-block 0 unconditional 0 never executed 57: 1462: } else if (file_attrib.st_size == 0) { 57: 1462-block 0 branch 0 taken 47 (fallthrough) branch 1 taken 10 47: 1463: color = ef_c; 47: 1463-block 0 unconditional 0 taken 47 10: 1464: } else if (file_attrib.st_nlink > 1) { 10: 1464-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 10 #####: 1465: color = mh_c; %%%%%: 1465-block 0 unconditional 0 never executed -: 1466: } else { 10: 1467: char *ext = (strrchr(ent, '.')); 10: 1468: if (ext) { 10: 1468-block 0 branch 0 taken 8 (fallthrough) branch 1 taken 2 8: 1469: char *extcolor = get_ext_color(ext); 8: 1469-block 0 call 0 returned 8 8: 1470: if (extcolor) { branch 0 taken 6 (fallthrough) branch 1 taken 2 6: 1471: snprintf(ext_color, MAX_COLOR, "\x1b[%sm", -: 1472: extcolor); 6: 1473: color = ext_color; 6: 1474: extcolor = (char *)NULL; 6: 1474-block 0 unconditional 0 taken 6 -: 1475: } 8: 1476: ext = (char *)NULL; 8: 1476-block 0 unconditional 0 taken 8 -: 1477: } -: 1478: } -: 1479: } -: 1480: 57: 1481: break; 57: 1481-block 0 unconditional 0 taken 57 -: 1482: 16: 1483: case S_IFDIR: 16: 1484: if (access(ent, R_OK | X_OK) != 0) { 16: 1484-block 0 call 0 returned 16 branch 1 taken 0 (fallthrough) branch 2 taken 16 #####: 1485: color = nd_c; %%%%%: 1485-block 0 unconditional 0 never executed -: 1486: } else { 16: 1487: int is_oth_w = 0; -: 1488: 16: 1489: if (file_attrib.st_mode & S_IWOTH) 16: 1489-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 16 #####: 1490: is_oth_w = 1; %%%%%: 1490-block 0 unconditional 0 never executed -: 1491: 16: 1492: int files_dir = count_dir(ent, NO_CPOP); 16: 1492-block 0 call 0 returned 16 -: 1493: 16: 1494: color = (file_attrib.st_mode & S_ISVTX) ? (is_oth_w 16: 1494-block 0 unconditional 0 taken 16 32*: 1495: ? tw_c : st_c) : (is_oth_w ? ow_c : branch 0 taken 0 (fallthrough) branch 1 taken 16 %%%%%: 1495-block 0 branch 2 never executed branch 3 never executed %%%%%: 1495-block 1 unconditional 4 never executed %%%%%: 1495-block 2 unconditional 5 never executed %%%%%: 1495-block 3 unconditional 6 never executed 16: 1495-block 4 branch 7 taken 16 (fallthrough) branch 8 taken 0 16: 1495-block 5 unconditional 9 taken 16 %%%%%: 1495-block 6 unconditional 10 never executed 16: 1495-block 7 unconditional 11 taken 16 -: 1496: /* If folder is empty, it contains only "." -: 1497: * and ".." (2 elements). If not mounted (ex: -: 1498: * /media/usb) the result will be zero. */ 16: 1499: (files_dir == 2 || files_dir == 0) ? ed_c : di_c); 16: 1499-block 0 branch 0 taken 11 (fallthrough) branch 1 taken 5 11: 1499-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 11 5: 1499-block 2 unconditional 4 taken 5 11: 1499-block 3 unconditional 5 taken 11 -: 1500: } 16: 1501: break; 16: 1501-block 0 unconditional 0 taken 16 -: 1502: 5: 1503: case S_IFLNK: 5: 1504: linkname = realpath(ent, (char *)NULL); 5: 1504-block 0 call 0 returned 5 5: 1505: if (linkname) { branch 0 taken 2 (fallthrough) branch 1 taken 3 2: 1506: color = ln_c; 2: 1507: free(linkname); 2: 1507-block 0 unconditional 0 taken 2 -: 1508: } else { 3: 1509: color = or_c; 3: 1509-block 0 unconditional 0 taken 3 -: 1510: } 5: 1511: break; 5: 1511-block 0 unconditional 0 taken 5 -: 1512: #####: 1513: case S_IFIFO: color = pi_c; break; %%%%%: 1513-block 0 unconditional 0 never executed #####: 1514: case S_IFBLK: color = bd_c; break; %%%%%: 1514-block 0 unconditional 0 never executed #####: 1515: case S_IFCHR: color = cd_c; break; %%%%%: 1515-block 0 unconditional 0 never executed #####: 1516: case S_IFSOCK: color = so_c; break; %%%%%: 1516-block 0 unconditional 0 never executed -: 1517: /* In case all the above conditions are false... */ #####: 1518: default: color = no_c; break; %%%%%: 1518-block 0 unconditional 0 never executed -: 1519: } -: 1520: 78: 1521: printf("%s%s%s%s%s%s%s%-*s", el_c, index, df_c, color, 78: 1521-block 0 branch 0 taken 69 (fallthrough) branch 1 taken 9 69: 1521-block 1 unconditional 2 taken 69 9: 1521-block 2 unconditional 3 taken 9 78: 1521-block 3 call 4 returned 78 -: 1522: ent, df_c, new_line ? "\n" : "", pad, ""); 78: 1523: free(index); unconditional 0 taken 78 -: 1524:} -: 1525: -: 1526:size_t function get_colorschemes called 4 returned 100% blocks executed 88% 4: 1527:get_colorschemes(void) -: 1528:{ -: 1529: struct stat attr; 4: 1530: int schemes_total = 0; -: 1531: struct dirent *ent; -: 1532: DIR *dir_p; 4: 1533: size_t i = 0; -: 1534: 4: 1535: if (colors_dir && stat(colors_dir, &attr) == EXIT_SUCCESS) { 4: 1535-block 0 branch 0 taken 4 (fallthrough) branch 1 taken 0 4: 1535-block 1 call 2 returned 4 branch 3 taken 4 (fallthrough) branch 4 taken 0 4: 1536: schemes_total = count_dir(colors_dir, NO_CPOP) - 2; 4: 1536-block 0 call 0 returned 4 4: 1537: if (schemes_total) { branch 0 taken 4 (fallthrough) branch 1 taken 0 8: 1538: color_schemes = (char **)xrealloc(color_schemes, 4: 1539: ((size_t)schemes_total + 2) * sizeof(char *)); 4: 1539-block 0 call 0 returned 4 -: 1540: -: 1541: /* count_dir already opened and read this directory succesfully, -: 1542: * so that we don't need to check opendir for errors */ 4: 1543: dir_p = opendir(colors_dir); call 0 returned 4 73: 1544: while ((ent = readdir(dir_p)) != NULL) { unconditional 0 taken 4 73: 1544-block 0 call 1 returned 73 branch 2 taken 69 branch 3 taken 4 (fallthrough) -: 1545: /* Skipp . and .. */ 69: 1546: char *name = ent->d_name; 69: 1547: if (*name == '.' && (!name[1] || (name[1] == '.' && !name[2]))) 69: 1547-block 0 branch 0 taken 8 (fallthrough) branch 1 taken 61 8: 1547-block 1 branch 2 taken 4 (fallthrough) branch 3 taken 4 4: 1547-block 2 branch 4 taken 4 (fallthrough) branch 5 taken 0 4: 1547-block 3 branch 6 taken 4 (fallthrough) branch 7 taken 0 8: 1548: continue; 8: 1548-block 0 unconditional 0 taken 8 -: 1549: 61: 1550: char *ret = strchr(name, '.'); -: 1551: /* If the file contains not dot, or if its extension is not -: 1552: * .cfm, or if it's just a hidden file named ".cfm", skip it */ 61*: 1553: if (!ret || strcmp(ret, ".cfm") != 0 || ret == name) 61: 1553-block 0 branch 0 taken 61 (fallthrough) branch 1 taken 0 61: 1553-block 1 branch 2 taken 61 (fallthrough) branch 3 taken 0 61: 1553-block 2 branch 4 taken 0 (fallthrough) branch 5 taken 61 #####: 1554: continue; %%%%%: 1554-block 0 unconditional 0 never executed -: 1555: 61: 1556: *ret = '\0'; 61: 1557: color_schemes[i++] = savestring(name, strlen(name)); 61: 1557-block 0 call 0 returned 61 unconditional 1 taken 61 -: 1558: } -: 1559: 4: 1560: closedir(dir_p); 4: 1560-block 0 call 0 returned 4 4: 1561: color_schemes[i] = (char *)NULL; unconditional 0 taken 4 -: 1562: } -: 1563: } -: 1564: 4: 1565: if (!data_dir) 4: 1565-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 4 #####: 1566: return i; %%%%%: 1566-block 0 unconditional 0 never executed -: 1567: -: 1568: char sys_colors_dir[PATH_MAX]; 4: 1569: snprintf(sys_colors_dir, PATH_MAX - 1, "%s/%s/colors", data_dir, PNL); -: 1570: 4: 1571: if (stat(sys_colors_dir, &attr) == -1) 4: 1571-block 0 call 0 returned 4 branch 1 taken 0 (fallthrough) branch 2 taken 4 #####: 1572: return i; %%%%%: 1572-block 0 unconditional 0 never executed -: 1573: 4: 1574: int total_tmp = schemes_total; 4: 1575: schemes_total += (count_dir(sys_colors_dir, NO_CPOP) - 2); 4: 1575-block 0 call 0 returned 4 -: 1576: 4: 1577: if (schemes_total <= total_tmp) branch 0 taken 0 (fallthrough) branch 1 taken 4 #####: 1578: return i; %%%%%: 1578-block 0 unconditional 0 never executed -: 1579: 8: 1580: color_schemes = (char **)xrealloc(color_schemes, 4: 1581: ((size_t)schemes_total + 2) * sizeof(char *)); 4: 1581-block 0 call 0 returned 4 -: 1582: 4: 1583: size_t i_tmp = i; -: 1584: 4: 1585: dir_p = opendir(sys_colors_dir); call 0 returned 4 16: 1586: while ((ent = readdir(dir_p)) != NULL) { unconditional 0 taken 4 16: 1586-block 0 call 1 returned 16 branch 2 taken 12 branch 3 taken 4 (fallthrough) -: 1587: /* Skipp . and .. */ 12: 1588: char *name = ent->d_name; 12: 1589: if (*name == '.' && (!name[1] || (name[1] == '.' && !name[2]))) 12: 1589-block 0 branch 0 taken 8 (fallthrough) branch 1 taken 4 8: 1589-block 1 branch 2 taken 4 (fallthrough) branch 3 taken 4 4: 1589-block 2 branch 4 taken 4 (fallthrough) branch 5 taken 0 4: 1589-block 3 branch 6 taken 4 (fallthrough) branch 7 taken 0 8: 1590: continue; 8: 1590-block 0 unconditional 0 taken 8 -: 1591: 4: 1592: char *ret = strchr(name, '.'); -: 1593: /* If the file contains not dot, or if its extension is not -: 1594: * .cfm, or if it's just a hidden file named ".cfm", skip it */ 4*: 1595: if (!ret || ret == name || strcmp(ret, ".cfm") != 0) 4: 1595-block 0 branch 0 taken 4 (fallthrough) branch 1 taken 0 4: 1595-block 1 branch 2 taken 4 (fallthrough) branch 3 taken 0 4: 1595-block 2 branch 4 taken 0 (fallthrough) branch 5 taken 4 #####: 1596: continue; %%%%%: 1596-block 0 unconditional 0 never executed -: 1597: 4: 1598: *ret = '\0'; -: 1599: -: 1600: size_t j; 4: 1601: int dup = 0; 7: 1602: for (j = 0; j < i_tmp; j++) { 4: 1602-block 0 unconditional 0 taken 4 3: 1602-block 1 unconditional 1 taken 3 7: 1602-block 2 branch 2 taken 7 branch 3 taken 0 (fallthrough) 7: 1603: if (*color_schemes[j] == *name && strcmp(name, color_schemes[j]) == 0) { 7: 1603-block 0 branch 0 taken 4 (fallthrough) branch 1 taken 3 4: 1603-block 1 branch 2 taken 4 (fallthrough) branch 3 taken 0 4: 1604: dup = 1; 4: 1605: break; 4: 1605-block 0 unconditional 0 taken 4 -: 1606: } -: 1607: } -: 1608: 4: 1609: if (dup) 4: 1609-block 0 branch 0 taken 4 (fallthrough) branch 1 taken 0 4: 1610: continue; 4: 1610-block 0 unconditional 0 taken 4 -: 1611: #####: 1612: color_schemes[i++] = savestring(name, strlen(name)); %%%%%: 1612-block 0 call 0 never executed unconditional 1 never executed -: 1613: } -: 1614: 4: 1615: closedir(dir_p); 4: 1615-block 0 call 0 returned 4 4: 1616: color_schemes[i] = (char *)NULL; 4: 1617: return i; unconditional 0 taken 4 -: 1618:} -: 1619: -: 1620:/* List color codes for file types used by the program */ -: 1621:void function color_codes called 2 returned 100% blocks executed 96% 2: 1622:color_codes(void) -: 1623:{ 2: 1624: if (!colorize) { 2: 1624-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 2 #####: 1625: printf(_("%s: Currently running without colors\n"), %%%%%: 1625-block 0 call 0 never executed call 1 never executed -: 1626: PROGRAM_NAME); #####: 1627: return; unconditional 0 never executed -: 1628: } -: 1629: 2: 1630: if (ext_colors_n) 2: 1630-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 0 2: 1631: printf(_("%sFile type colors%s\n\n"), BOLD, df_c); 2: 1631-block 0 call 0 returned 2 call 1 returned 2 unconditional 2 taken 2 2: 1632: printf(_(" %sfile name%s: Directory with no read permission (nd)\n"), 2: 1632-block 0 call 0 returned 2 call 1 returned 2 -: 1633: nd_c, df_c); 2: 1634: printf(_(" %sfile name%s: File with no read permission (nf)\n"), call 0 returned 2 call 1 returned 2 -: 1635: nf_c, df_c); 2: 1636: printf(_(" %sfile name%s: Directory* (di)\n"), di_c, df_c); call 0 returned 2 call 1 returned 2 2: 1637: printf(_(" %sfile name%s: EMPTY directory (ed)\n"), ed_c, df_c); call 0 returned 2 call 1 returned 2 2: 1638: printf(_(" %sfile name%s: EMPTY directory with no read " call 0 returned 2 call 1 returned 2 -: 1639: "permission (ne)\n"), -: 1640: ne_c, df_c); 2: 1641: printf(_(" %sfile name%s: Executable file (ex)\n"), ex_c, df_c); call 0 returned 2 call 1 returned 2 2: 1642: printf(_(" %sfile name%s: Empty executable file (ee)\n"), ee_c, df_c); call 0 returned 2 call 1 returned 2 2: 1643: printf(_(" %sfile name%s: Block special file (bd)\n"), bd_c, df_c); call 0 returned 2 call 1 returned 2 2: 1644: printf(_(" %sfile name%s: Symbolic link* (ln)\n"), ln_c, df_c); call 0 returned 2 call 1 returned 2 2: 1645: printf(_(" %sfile name%s: Broken symbolic link (or)\n"), or_c, df_c); call 0 returned 2 call 1 returned 2 2: 1646: printf(_(" %sfile name%s: Multi-hardlink (mh)\n"), mh_c, df_c); call 0 returned 2 call 1 returned 2 2: 1647: printf(_(" %sfile name%s: Socket file (so)\n"), so_c, df_c); call 0 returned 2 call 1 returned 2 2: 1648: printf(_(" %sfile name%s: Pipe or FIFO special file (pi)\n"), pi_c, df_c); call 0 returned 2 call 1 returned 2 2: 1649: printf(_(" %sfile name%s: Character special file (cd)\n"), cd_c, df_c); call 0 returned 2 call 1 returned 2 2: 1650: printf(_(" %sfile name%s: Regular file (fi)\n"), fi_c, df_c); call 0 returned 2 call 1 returned 2 2: 1651: printf(_(" %sfile name%s: Empty (zero-lenght) file (ef)\n"), ef_c, df_c); call 0 returned 2 call 1 returned 2 2: 1652: printf(_(" %sfile name%s: SUID file (su)\n"), su_c, df_c); call 0 returned 2 call 1 returned 2 2: 1653: printf(_(" %sfile name%s: SGID file (sg)\n"), sg_c, df_c); call 0 returned 2 call 1 returned 2 2: 1654: printf(_(" %sfile name%s: File with capabilities (ca)\n"), ca_c, df_c); call 0 returned 2 call 1 returned 2 2: 1655: printf(_(" %sfile name%s: Sticky and NOT other-writable " call 0 returned 2 call 1 returned 2 -: 1656: "directory* (st)\n"), -: 1657: st_c, df_c); 2: 1658: printf(_(" %sfile name%s: Sticky and other-writable " call 0 returned 2 call 1 returned 2 -: 1659: "directory* (tw)\n"), -: 1660: tw_c, df_c); 2: 1661: printf(_(" %sfile name%s: Other-writable and NOT sticky " call 0 returned 2 call 1 returned 2 -: 1662: "directory* (ow)\n"), -: 1663: ow_c, df_c); 2: 1664: printf(_(" %sfile name%s: Unknown file type (no)\n"), no_c, df_c); call 0 returned 2 call 1 returned 2 2: 1665: printf(_(" %sfile name%s: Unaccessible (non-stat'able) file " call 0 returned 2 call 1 returned 2 -: 1666: "(uf)\n"), -: 1667: uf_c, df_c); -: 1668: 2: 1669: printf(_("\n*The slash followed by a number (/xx) after directories " call 0 returned 2 call 1 returned 2 -: 1670: "or symbolic links to directories indicates the amount of " -: 1671: "files contained by the corresponding directory, excluding " -: 1672: "self (.) and parent (..) directories.\n")); 2: 1673: printf(_("\nThe value in parentheses is the code that is to be used " call 0 returned 2 call 1 returned 2 -: 1674: "to modify the color of the corresponding file type in the " -: 1675: "color scheme file (in the \"FiletypeColors\" line), " -: 1676: "using the same ANSI style color format used by dircolors. " -: 1677: "By default, %s uses only 8 colors, but you can use 256 " -: 1678: "and RGB colors as well.\n\n"), PROGRAM_NAME); -: 1679: 2: 1680: if (ext_colors_n) { branch 0 taken 2 (fallthrough) branch 1 taken 0 -: 1681: size_t i, j; 2: 1682: printf(_("%sExtension colors%s\n\n"), BOLD, df_c); 2: 1682-block 0 call 0 returned 2 call 1 returned 2 136: 1683: for (i = 0; i < ext_colors_n; i++) { unconditional 0 taken 2 134: 1683-block 0 unconditional 1 taken 134 136: 1683-block 1 branch 2 taken 134 branch 3 taken 2 (fallthrough) 134: 1684: char *ret = strrchr(ext_colors[i], '='); 134: 1685: if (!ret) 134: 1685-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 132 2: 1686: continue; 2: 1686-block 0 unconditional 0 taken 2 132: 1687: printf(" \x1b[%sm", ret + 1); 132: 1687-block 0 call 0 returned 132 798: 1688: for (j = 0; ext_colors[i][j] != '='; j++) unconditional 0 taken 132 unconditional 1 taken 666 798: 1688-block 0 branch 2 taken 666 branch 3 taken 132 (fallthrough) 666: 1689: putchar(ext_colors[i][j]); 666: 1689-block 0 call 0 returned 666 132: 1690: puts("\x1b[0m"); 132: 1690-block 0 call 0 returned 132 unconditional 1 taken 132 -: 1691: } 2: 1692: putchar('\n'); 2: 1692-block 0 call 0 returned 2 unconditional 1 taken 2 -: 1693: } -: 1694:} clifm-1.26.3/misc/codecov/config.c.gcov000066400000000000000000005120271506632037700176400ustar00rootroot00000000000000 -: 0:Source:config.c -: 1:/* config.c -- functions to define, create, and set configuration files */ -: 2: -: 3:/* -: 4: * This file is part of CliFM -: 5: * -: 6: * Copyright (C) 2016-2021, L. Abramovich -: 7: * All rights reserved. -: 8: -: 9: * CliFM is free software; you can redistribute it and/or modify -: 10: * it under the terms of the GNU General Public License as published by -: 11: * the Free Software Foundation; either version 2 of the License, or -: 12: * (at your option) any later version. -: 13: * -: 14: * CliFM is distributed in the hope that it will be useful, -: 15: * but WITHOUT ANY WARRANTY; without even the implied warranty of -: 16: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -: 17: * GNU General Public License for more details. -: 18: * -: 19: * You should have received a copy of the GNU General Public License -: 20: * along with this program; if not, write to the Free Software -: 21: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, -: 22: * MA 02110-1301, USA. -: 23:*/ -: 24: -: 25:#include "helpers.h" -: 26: -: 27:#include -: 28:#include -: 29:#include -: 30:#include -: 31:#include -: 32:#include -: 33:#include -: 34:#include -: 35: -: 36:#include "aux.h" -: 37:#include "colors.h" -: 38:#include "config.h" -: 39:#include "exec.h" -: 40:#include "init.h" -: 41:#include "listing.h" -: 42:#include "mime.h" -: 43:#include "misc.h" -: 44:#include "navigation.h" -: 45:#include "file_operations.h" -: 46: -: 47:/* Regenerate the configuration file and create a back up of the old -: 48: * one */ -: 49:static int function regen_config called 0 returned 0% blocks executed 0% #####: 50:regen_config(void) -: 51:{ #####: 52: int config_found = 1; -: 53: struct stat config_attrib; -: 54: #####: 55: if (stat(config_file, &config_attrib) == -1) { %%%%%: 55-block 0 call 0 never executed branch 1 never executed branch 2 never executed #####: 56: puts(_("No configuration file found")); %%%%%: 56-block 0 call 0 never executed call 1 never executed #####: 57: config_found = 0; unconditional 0 never executed -: 58: } -: 59: #####: 60: if (config_found) { %%%%%: 60-block 0 branch 0 never executed branch 1 never executed #####: 61: time_t rawtime = time(NULL); %%%%%: 61-block 0 call 0 never executed -: 62: struct tm t; #####: 63: localtime_r(&rawtime, &t); call 0 never executed -: 64: -: 65: char date[18]; #####: 66: strftime(date, 18, "%Y%m%d@%H:%M:%S", &t); -: 67: #####: 68: char *bk = (char *)xnmalloc(strlen(config_file) + strlen(date) + 2, sizeof(char)); call 0 never executed #####: 69: sprintf(bk, "%s.%s", config_file, date); -: 70: #####: 71: char *cmd[] = {"mv", config_file, bk, NULL}; -: 72: #####: 73: if (launch_execve(cmd, FOREGROUND, E_NOFLAG) != EXIT_SUCCESS) { call 0 never executed branch 1 never executed branch 2 never executed #####: 74: free(bk); #####: 75: return EXIT_FAILURE; %%%%%: 75-block 0 unconditional 0 never executed -: 76: } -: 77: #####: 78: printf(_("Old configuration file stored as '%s'\n"), bk); %%%%%: 78-block 0 call 0 never executed call 1 never executed #####: 79: free(bk); unconditional 0 never executed -: 80: } -: 81: #####: 82: if (create_config(config_file) != EXIT_SUCCESS) %%%%%: 82-block 0 call 0 never executed branch 1 never executed branch 2 never executed #####: 83: return EXIT_FAILURE; %%%%%: 83-block 0 unconditional 0 never executed -: 84: #####: 85: printf(_("New configuration file written to '%s'\n"), config_file); %%%%%: 85-block 0 call 0 never executed call 1 never executed #####: 86: reload_config(); call 0 never executed #####: 87: return EXIT_SUCCESS; unconditional 0 never executed -: 88:} -: 89: -: 90:/* Edit the config file, either via the mime function or via the first -: 91: * passed argument (Ex: 'edit nano'). The 'gen' option regenerates -: 92: * the configuration file and creates a back up of the old one. */ -: 93:int function edit_function called 9 returned 100% blocks executed 49% 9: 94:edit_function(char **comm) -: 95:{ 9: 96: if (xargs.stealth_mode == 1) { 9: 96-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 9 #####: 97: printf(_("%s: Access to configuration files is not allowed in " %%%%%: 97-block 0 call 0 never executed call 1 never executed -: 98: "stealth mode\n"), PROGRAM_NAME); #####: 99: return EXIT_SUCCESS; unconditional 0 never executed -: 100: } -: 101: 9*: 102: if (comm[1] && *comm[1] == '-' && strcmp(comm[1], "--help") == 0) { 9: 102-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 9 %%%%%: 102-block 1 branch 2 never executed branch 3 never executed %%%%%: 102-block 2 branch 4 never executed branch 5 never executed #####: 103: printf("%s\n", EDIT_USAGE); %%%%%: 103-block 0 call 0 never executed #####: 104: return EXIT_SUCCESS; unconditional 0 never executed -: 105: } -: 106: 9*: 107: if (comm[1] && *comm[1] == 'r' && strcmp(comm[1], "reset") == 0) 9: 107-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 9 %%%%%: 107-block 1 branch 2 never executed branch 3 never executed %%%%%: 107-block 2 branch 4 never executed branch 5 never executed #####: 108: return regen_config(); %%%%%: 108-block 0 call 0 never executed unconditional 1 never executed -: 109: 9: 110: if (!config_ok) { 9: 110-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 9 #####: 111: fprintf(stderr, _("%s: Cannot access the configuration file\n"), %%%%%: 111-block 0 call 0 never executed call 1 never executed -: 112: PROGRAM_NAME); #####: 113: return EXIT_FAILURE; unconditional 0 never executed -: 114: } -: 115: -: 116: /* Get modification time of the config file before opening it */ -: 117: struct stat file_attrib; -: 118: -: 119: /* If, for some reason (like someone erasing the file while the -: 120: * program is running) clifmrc doesn't exist, recreate the -: 121: * configuration file. Then run 'stat' again to reread the attributes -: 122: * of the file */ 9: 123: if (stat(config_file, &file_attrib) == -1) { 9: 123-block 0 call 0 returned 9 branch 1 taken 0 (fallthrough) branch 2 taken 9 #####: 124: create_config(config_file); %%%%%: 124-block 0 call 0 never executed #####: 125: stat(config_file, &file_attrib); call 0 never executed unconditional 1 never executed -: 126: } -: 127: 9: 128: time_t mtime_bfr = (time_t)file_attrib.st_mtime; 9: 129: int ret = EXIT_SUCCESS; -: 130: -: 131: /* If there is an argument... */ 9: 132: if (comm[1]) { 9: 132-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 9 #####: 133: char *cmd[] = {comm[1], config_file, NULL}; #####: 134: ret = launch_execve(cmd, FOREGROUND, E_NOSTDERR); %%%%%: 134-block 0 call 0 never executed -: 135: } else { -: 136: /* If no application was passed as 2nd argument */ 9: 137: ret = open_file(config_file); 9: 137-block 0 call 0 returned 9 unconditional 1 taken 9 -: 138: } -: 139: 9: 140: if (ret != EXIT_SUCCESS) 9: 140-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 9 #####: 141: return EXIT_FAILURE; %%%%%: 141-block 0 unconditional 0 never executed -: 142: -: 143: /* Get modification time after opening the config file */ 9: 144: stat(config_file, &file_attrib); 9: 144-block 0 call 0 returned 9 -: 145: /* If modification times differ, the file was modified after being -: 146: * opened */ -: 147: 9: 148: if (mtime_bfr != (time_t)file_attrib.st_mtime) { branch 0 taken 8 (fallthrough) branch 1 taken 1 -: 149: /* Reload configuration only if the config file was modified */ 8: 150: reload_config(); 8: 150-block 0 call 0 returned 8 8: 151: welcome_message = 0; -: 152: 8: 153: if (cd_lists_on_the_fly) { branch 0 taken 8 (fallthrough) branch 1 taken 0 8: 154: free_dirlist(); 8: 154-block 0 call 0 returned 8 8: 155: ret = list_dir(); call 0 returned 8 unconditional 1 taken 8 -: 156: } -: 157: } -: 158: 9: 159: return ret; 9: 159-block 0 unconditional 0 taken 9 -: 160:} -: 161: -: 162:void function set_env called 24 returned 100% blocks executed 90% 24: 163:set_env(void) -: 164:{ 24: 165: if (xargs.stealth_mode == 1) 24: 165-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 24 #####: 166: return; %%%%%: 166-block 0 unconditional 0 never executed -: 167: -: 168: /* Set a few environment variables, mostly useful to run custom -: 169: * scripts via the actions function */ -: 170: /* CLIFM env variable is set to one when CliFM is running, so that -: 171: * external programs can determine if they were spawned by CliFM */ 24: 172: setenv("CLIFM", "1", 1); 24: 172-block 0 call 0 returned 24 24: 173: setenv("CLIFM_PROFILE", alt_profile ? alt_profile : "default", 1); branch 0 taken 6 (fallthrough) branch 1 taken 18 6: 173-block 0 unconditional 2 taken 6 18: 173-block 1 unconditional 3 taken 18 24: 173-block 2 call 4 returned 24 -: 174: 24: 175: if (sel_file) branch 0 taken 24 (fallthrough) branch 1 taken 0 24: 176: setenv("CLIFM_SELFILE", sel_file, 1); 24: 176-block 0 call 0 returned 24 unconditional 1 taken 24 -: 177:} -: 178: -: 179:/* Define the file for the Selection Box */ -: 180:void function set_sel_file called 24 returned 100% blocks executed 64% 24: 181:set_sel_file(void) -: 182:{ 24: 183: if (sel_file) { 24: 183-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 24 #####: 184: free(sel_file); #####: 185: sel_file = (char *)NULL; %%%%%: 185-block 0 unconditional 0 never executed -: 186: } -: 187: 24: 188: if (!config_dir) 24: 188-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 24 #####: 189: return; %%%%%: 189-block 0 unconditional 0 never executed -: 190: 24: 191: size_t config_len = strlen(config_dir); -: 192: 24: 193: if (!share_selbox) { 24: 193-block 0 branch 0 taken 24 (fallthrough) branch 1 taken 0 -: 194: /* Private selection box is stored in the profile -: 195: * directory */ 24: 196: sel_file = (char *)xnmalloc(config_len + 9, sizeof(char)); 24: 196-block 0 call 0 returned 24 -: 197: 24: 198: sprintf(sel_file, "%s/selbox", config_dir); unconditional 0 taken 24 -: 199: } else { -: 200: /* Common selection box is stored in the general -: 201: * configuration directory */ #####: 202: sel_file = (char *)xnmalloc(config_len + 17, sizeof(char)); %%%%%: 202-block 0 call 0 never executed #####: 203: sprintf(sel_file, "%s/.config/%s/selbox", user.home, PNL); unconditional 0 never executed -: 204: } -: 205: 24: 206: return; 24: 206-block 0 unconditional 0 taken 24 -: 207:} -: 208: -: 209:int function create_kbinds_file called 4 returned 100% blocks executed 26% 4: 210:create_kbinds_file(void) -: 211:{ 4: 212: if (!config_ok) 4: 212-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 4 #####: 213: return EXIT_FAILURE; %%%%%: 213-block 0 unconditional 0 never executed -: 214: -: 215: struct stat attr; -: 216: /* If the file already exists, do nothing */ 4: 217: if (stat(kbinds_file, &attr) == EXIT_SUCCESS) 4: 217-block 0 call 0 returned 4 branch 1 taken 4 (fallthrough) branch 2 taken 0 4: 218: return EXIT_SUCCESS; 4: 218-block 0 unconditional 0 taken 4 -: 219: -: 220: /* If not, try to import it from DATADIR */ #####: 221: if (data_dir) { %%%%%: 221-block 0 branch 0 never executed branch 1 never executed -: 222: char sys_file[PATH_MAX]; #####: 223: snprintf(sys_file, PATH_MAX - 1, "%s/%s/keybindings.cfm", data_dir, PNL); #####: 224: if (stat(sys_file, &attr) == EXIT_SUCCESS) { %%%%%: 224-block 0 call 0 never executed branch 1 never executed branch 2 never executed #####: 225: char *cmd[] = {"cp", sys_file, kbinds_file, NULL}; #####: 226: if (launch_execve(cmd, FOREGROUND, E_NOFLAG) == EXIT_SUCCESS) %%%%%: 226-block 0 call 0 never executed branch 1 never executed branch 2 never executed #####: 227: return EXIT_SUCCESS; %%%%%: 227-block 0 unconditional 0 never executed -: 228: } -: 229: } -: 230: -: 231: /* Else, create it */ #####: 232: FILE *fp = fopen(kbinds_file, "w"); %%%%%: 232-block 0 call 0 never executed #####: 233: if (!fp) { branch 0 never executed branch 1 never executed #####: 234: _err('w', PRINT_PROMPT, "%s: '%s': %s\n", PROGRAM_NAME, kbinds_file, call 0 never executed #####: 235: strerror(errno)); %%%%%: 235-block 0 call 0 never executed #####: 236: return EXIT_FAILURE; unconditional 0 never executed -: 237: } -: 238: #####: 239: fprintf(fp, "# Keybindings file for %s\n\n\ %%%%%: 239-block 0 call 0 never executed -: 240:# Use the 'kbgen' plugin (compile it first: gcc -o kbgen kbgen.c) to \n\ -: 241:# find out the escape code for the key or key sequence you want. Use \n\ -: 242:# either octal, hexadecimal codes or symbols.\n\ -: 243:# Ex: For Alt-/ (in rxvt terminals) 'kbgen' will print the following \n\ -: 244:# lines:\n\ -: 245:# Hex | Oct | Symbol\n\ -: 246:# ---- | ---- | ------\n\ -: 247:# \\x1b | \\033 | ESC (\\e)\n\ -: 248:# \\x2f | \\057 | /\n\ -: 249:# In this case, the keybinding, if using symbols, is: \"\\e/:function\"\n\ -: 250:# In case you prefer the hex codes it would be: \\x1b\\x2f:function.\n\ -: 251:# GNU emacs escape sequences are also allowed (ex: \"\\M-a\", Alt-a\n\ -: 252:# in most keyboards, or \"\\C-r\" for Ctrl-r).\n\ -: 253:# Some codes, especially those involving keys like Ctrl or the arrow\n\ -: 254:# keys, vary depending on the terminal emulator and the system settings.\n\ -: 255:# These keybindings should be set up thus on a per terminal basis.\n\ -: 256:# You can also consult the terminfo database via the infocmp command.\n\ -: 257:# See terminfo(5) and infocmp(1).\n\ -: 258:\n\ -: 259:# Alt-j\n\ -: 260:previous-dir:\\M-j\n\ -: 261:# Shift-Left (rxvt)\n\ -: 262:previous-dir2:\\e[d\n\ -: 263:# Shift-Left (xterm)\n\ -: 264:previous-dir3:\\e[2D\n\ -: 265:# Shift-Left (others)\n\ -: 266:previous-dir4:\\e[1;2D\n\ -: 267:\n\ -: 268:# Alt-k\n\ -: 269:next-dir:\\M-k\n\ -: 270:# Shift-right (rxvt)\n\ -: 271:next-dir2:\\e[c\n\ -: 272:# Shift-Right (xterm)\n\ -: 273:next-dir3:\\e[2C\n\ -: 274:# Shift-Right (others)\n\ -: 275:next-dir4:\\e[1;2C\n\ -: 276:first-dir:\\C-\\M-j\n\ -: 277:last-dir:\\C-\\M-k\n\ -: 278:\n\ -: 279:# Alt-u\n\ -: 280:parent-dir:\\M-u\n\ -: 281:# Shift-Up (rxvt)\n\ -: 282:parent-dir2:\\e[a\n\ -: 283:# Shift-Up (xterm)\n\ -: 284:parent-dir3:\\e[2A\n\ -: 285:# Shift-Up (others)\n\ -: 286:parent-dir4:\\e[1;2A\n\ -: 287:\n\ -: 288:# Alt-e\n\ -: 289:home-dir:\\M-e\n\ -: 290:# Home key (rxvt)\n\ -: 291:home-dir2:\\e[7~\n\ -: 292:# Home key (xterm)\n\ -: 293:home-dir3:\\e[H\n\ -: 294:home-dir4:\n\ -: 295:\n\ -: 296:# Alt-r\n\ -: 297:root-dir:\\M-r\n\ -: 298:# Alt-/ (rxvt)\n\ -: 299:root-dir2:\\e/\n\ -: 300:#root-dir3:\n\ -: 301:\n\ -: 302:pinned-dir:\\M-p\n\ -: 303:workspace1:\\M-1\n\ -: 304:workspace2:\\M-2\n\ -: 305:workspace3:\\M-3\n\ -: 306:workspace4:\\M-4\n\ -: 307:\n\ -: 308:# Help\n\ -: 309:# F1-3\n\ -: 310:show-manpage:\\eOP\n\ -: 311:show-cmds:\\eOQ\n\ -: 312:show-kbinds:\\eOR\n\ -: 313:\n\ -: 314:prepend-sudo:\\M-v\n\ -: 315:create-file:\\M-n\n\ -: 316:new-instance:\\C-x\n\ -: 317:previous-profile:\\C-\\M-o\n\ -: 318:next-profile:\\C-\\M-p\n\ -: 319:archive-sel:\\C-\\M-a\n\ -: 320:rename-sel:\\C-\\M-r\n\ -: 321:remove-sel:\\C-\\M-d\n\ -: 322:trash-sel:\\C-\\M-t\n\ -: 323:untrash-all:\\C-\\M-u\n\ -: 324:paste-sel:\\C-\\M-v\n\ -: 325:move-sel:\\C-\\M-n\n\ -: 326:export-sel:\\C-\\M-e\n\ -: 327:open-sel:\\C-\\M-g\n\ -: 328:bookmark-sel:\\C-\\M-b\n\ -: 329:refresh-screen:\\C-r\n\ -: 330:clear-line:\\M-c\n\ -: 331:clear-msgs:\\M-t\n\ -: 332:show-dirhist:\\M-h\n\ -: 333:toggle-hidden:\\M-i\n\ -: 334:toggle-hidden2:\\M-.\n\ -: 335:toggle-light:\\M-y\n\ -: 336:toggle-long:\\M-l\n\ -: 337:sort-previous:\\M-z\n\ -: 338:sort-next:\\M-x\n\ -: 339:bookmarks:\\M-b\n\ -: 340:select-all:\\M-a\n\ -: 341:deselect-all:\\M-d\n\ -: 342:mountpoints:\\M-m\n\ -: 343:folders-first:\\M-g\n\ -: 344:selbox:\\M-s\n\ -: 345:lock:\\M-o\n\ -: 346:# F6-12\n\ -: 347:open-mime:\\e[17~\n\ -: 348:open-jump-db:\\e[18~\n\ -: 349:edit-color-scheme:\\e[19~\n\ -: 350:open-keybinds:\\e[20~\n\ -: 351:open-config:\\e[21~\n\ -: 352:open-bookmarks:\\e[23~\n\ -: 353:quit:\\e[24~\n\n\ -: 354:# Plugins\n\ -: 355:# 1) Make sure your plugin is in the plugins directory (or use any of the\n\ -: 356:# plugins in there)\n\ -: 357:# 2) Link pluginx to your plugin using the 'actions edit' command. Ex:\n\ -: 358:# \"plugin1=myplugin.sh\"\n\ -: 359:# 3) Set a keybinding here for pluginx. Ex: \"plugin1:\\M-7\"\n\n\ -: 360:#plugin1:\n\ -: 361:#plugin2:\n\ -: 362:#plugin3:\n\ -: 363:#plugin4:\n", -: 364: PROGRAM_NAME); -: 365: #####: 366: fclose(fp); call 0 never executed #####: 367: return EXIT_SUCCESS; unconditional 0 never executed -: 368:} -: 369: -: 370:static int function create_actions_file called 24 returned 100% blocks executed 52% 24: 371:create_actions_file(char *file) -: 372:{ -: 373: struct stat attr; -: 374: /* If the file already exists, do nothing */ 24: 375: if (stat(file, &attr) == EXIT_SUCCESS) 24: 375-block 0 call 0 returned 24 branch 1 taken 23 (fallthrough) branch 2 taken 1 23: 376: return EXIT_SUCCESS; 23: 376-block 0 unconditional 0 taken 23 -: 377: -: 378: /* If not, try to import it from DATADIR */ 1: 379: if (data_dir) { 1: 379-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 0 -: 380: char sys_file[PATH_MAX]; 1: 381: snprintf(sys_file, PATH_MAX - 1, "%s/%s/actions.cfm", data_dir, PNL); 1: 382: if (stat(sys_file, &attr) == EXIT_SUCCESS) { 1: 382-block 0 call 0 returned 1 branch 1 taken 1 (fallthrough) branch 2 taken 0 1: 383: char *cmd[] = {"cp", sys_file, file, NULL}; 1: 384: if (launch_execve(cmd, FOREGROUND, E_NOFLAG) == EXIT_SUCCESS) 1: 384-block 0 call 0 returned 1 branch 1 taken 1 (fallthrough) branch 2 taken 0 1: 385: return EXIT_SUCCESS; 1: 385-block 0 unconditional 0 taken 1 -: 386: } -: 387: } -: 388: -: 389: /* Else, create it */ -: 390: int fd; #####: 391: FILE *fp = open_fstream_w(file, &fd); %%%%%: 391-block 0 call 0 never executed #####: 392: if (!fp) { branch 0 never executed branch 1 never executed #####: 393: _err('e', PRINT_PROMPT, "%s: '%s': %s\n", PROGRAM_NAME, call 0 never executed #####: 394: file, strerror(errno)); %%%%%: 394-block 0 call 0 never executed #####: 395: return EXIT_FAILURE; unconditional 0 never executed -: 396: } -: 397: #####: 398: fprintf(fp, "######################\n" %%%%%: 398-block 0 call 0 never executed -: 399: "# Actions file for %s #\n" -: 400: "######################\n\n" -: 401: "# Define here your custom actions. Actions are " -: 402: "custom command names\n" -: 403: "# bound to a executable file located either in " -: 404: "DATADIR/clifm/plugins\n" -: 405: "# (usually /usr/share/clifm/plugins) or in " -: 406: "$XDG_CONFIG_HOME/clifm/plugins.\n" -: 407: "# Actions can be executed directly from " -: 408: "%s command line, as if they\n" -: 409: "# were any other command, and the associated " -: 410: "file will be executed\n" -: 411: "# instead. All parameters passed to the action " -: 412: "command will be passed\n" -: 413: "# to the corresponding plugin as well.\n\n" -: 414: "i=img_viewer.sh\n" -: 415: "kbgen=kbgen\n" -: 416: "vid=vid_viewer.sh\n" -: 417: "ptot=pdf_viewer.sh\n" -: 418: "music=music_player.sh\n" -: 419: "update=update.sh\n" -: 420: "wall=wallpaper_setter.sh\n" -: 421: "dragon=dragondrop.sh\n" -: 422: "bn=batch_create.sh\n" -: 423: "+=finder.sh\n" -: 424: "++=jumper.sh\n" -: 425: "-=fzfnav.sh\n" -: 426: "*=fzfsel.sh\n" -: 427: "**=fzfdesel.sh\n" -: 428: "h=fzfhist.sh\n" -: 429: "//=rgfind.sh\n" -: 430: "ih=ihelp.sh\n", -: 431: PROGRAM_NAME, PROGRAM_NAME); -: 432: #####: 433: close_fstream(fp, fd); call 0 never executed #####: 434: return EXIT_SUCCESS; unconditional 0 never executed -: 435:} -: 436: -: 437:void function create_tmp_files called 24 returned 100% blocks executed 37% 24: 438:create_tmp_files(void) -: 439:{ 24: 440: if (!user.name) 24: 440-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 24 #####: 441: return; %%%%%: 441-block 0 unconditional 0 never executed -: 442: 24: 443: size_t pnl_len = strlen(PNL); -: 444: -: 445: /* #### CHECK THE TMP DIR #### */ -: 446: -: 447: /* If the temporary directory doesn't exist, create it. I create -: 448: * the parent directory (/tmp/clifm) with 1777 permissions (world -: 449: * writable with the sticky bit set), so that every user is able -: 450: * to create files in here, but only the file's owner can remove -: 451: * or modify them */ -: 452: 24: 453: size_t user_len = strlen(user.name); 24: 454: tmp_dir = (char *)xnmalloc(pnl_len + user_len + 7, sizeof(char)); 24: 454-block 0 call 0 returned 24 24: 455: snprintf(tmp_dir, pnl_len + 6, "/tmp/%s", PNL); -: 456: -: 457: struct stat file_attrib; 24: 458: if (stat(tmp_dir, &file_attrib) == -1) { call 0 returned 24 branch 1 taken 0 (fallthrough) branch 2 taken 24 #####: 459: char *md_cmd[] = {"mkdir", "-pm1777", tmp_dir, NULL}; #####: 460: if (launch_execve(md_cmd, FOREGROUND, E_NOFLAG) != EXIT_SUCCESS) { %%%%%: 460-block 0 call 0 never executed branch 1 never executed branch 2 never executed #####: 461: _err('e', PRINT_PROMPT, _("%s: '%s': Error creating temporary " %%%%%: 461-block 0 call 0 never executed call 1 never executed unconditional 2 never executed -: 462: "directory\n"), PROGRAM_NAME, tmp_dir); -: 463: } -: 464: } -: 465: -: 466: /* Once the parent directory exists, create the user's directory to -: 467: * store the list of selected files: -: 468: * TMP_DIR/clifm/username/.selbox_PROFILE. I use here very -: 469: * restrictive permissions (700), since only the corresponding user -: 470: * must be able to read and/or modify this list */ -: 471: 24: 472: snprintf(tmp_dir, pnl_len + user_len + 7, "/tmp/%s/%s", PNL, user.name); -: 473: 24: 474: if (stat(tmp_dir, &file_attrib) == -1) { 24: 474-block 0 call 0 returned 24 branch 1 taken 1 (fallthrough) branch 2 taken 23 1: 475: char *md_cmd2[] = {"mkdir", "-pm700", tmp_dir, NULL}; 1: 476: if (launch_execve(md_cmd2, FOREGROUND, E_NOFLAG) != EXIT_SUCCESS) { 1: 476-block 0 call 0 returned 1 branch 1 taken 0 (fallthrough) branch 2 taken 1 #####: 477: selfile_ok = 0; #####: 478: _err('e', PRINT_PROMPT, _("%s: '%s': Error creating temporary " %%%%%: 478-block 0 call 0 never executed call 1 never executed unconditional 2 never executed -: 479: "directory\n"), PROGRAM_NAME, tmp_dir); -: 480: } -: 481: } -: 482: -: 483: /* If the directory exists, check it is writable */ 23: 484: else if (access(tmp_dir, W_OK) == -1) { 23: 484-block 0 call 0 returned 23 branch 1 taken 0 (fallthrough) branch 2 taken 23 #####: 485: if (!sel_file) { %%%%%: 485-block 0 branch 0 never executed branch 1 never executed #####: 486: selfile_ok = 0; #####: 487: _err('w', PRINT_PROMPT, "%s: '%s': Directory not writable. Selected " %%%%%: 487-block 0 call 0 never executed unconditional 1 never executed -: 488: "files will be lost after program exit\n", -: 489: PROGRAM_NAME, tmp_dir); -: 490: } -: 491: } -: 492: -: 493: /* If the config directory isn't available, define an alternative -: 494: * selection file in /tmp */ 24*: 495: if (!sel_file && xargs.stealth_mode != 1) { 24: 495-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 24 %%%%%: 495-block 1 branch 2 never executed branch 3 never executed #####: 496: size_t tmp_dir_len = strlen(tmp_dir); -: 497: #####: 498: if (!share_selbox) { %%%%%: 498-block 0 branch 0 never executed branch 1 never executed #####: 499: size_t prof_len = 0; -: 500: #####: 501: if (alt_profile) %%%%%: 501-block 0 branch 0 never executed branch 1 never executed #####: 502: prof_len = strlen(alt_profile); %%%%%: 502-block 0 unconditional 0 never executed -: 503: else #####: 504: prof_len = 7; /* Lenght of "default" */ %%%%%: 504-block 0 unconditional 0 never executed -: 505: #####: 506: sel_file = (char *)xnmalloc(tmp_dir_len + prof_len + 9, %%%%%: 506-block 0 call 0 never executed -: 507: sizeof(char)); #####: 508: sprintf(sel_file, "%s/selbox_%s", tmp_dir, %%%%%: 508-block 0 unconditional 0 never executed %%%%%: 508-block 1 unconditional 1 never executed %%%%%: 508-block 2 unconditional 2 never executed #####: 509: (alt_profile) ? alt_profile : "default"); branch 0 never executed branch 1 never executed -: 510: } else { #####: 511: sel_file = (char *)xnmalloc(tmp_dir_len + 8, sizeof(char)); %%%%%: 511-block 0 call 0 never executed #####: 512: sprintf(sel_file, "%s/selbox", tmp_dir); unconditional 0 never executed -: 513: } -: 514: #####: 515: _err('w', PRINT_PROMPT, _("%s: '%s': Using a temporary directory for " %%%%%: 515-block 0 call 0 never executed call 1 never executed unconditional 2 never executed -: 516: "the Selection Box. Selected files won't be persistent accros " -: 517: "reboots"), PROGRAM_NAME, tmp_dir); -: 518: } -: 519:} -: 520: -: 521:static void function define_config_file_names called 24 returned 100% blocks executed 77% 24: 522:define_config_file_names(void) -: 523:{ 24: 524: size_t pnl_len = strlen(PNL); -: 525: 24: 526: if (alt_config_dir) { 24: 526-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 24 #####: 527: config_dir_gral = (char *)xnmalloc(strlen(alt_config_dir) + pnl_len %%%%%: 527-block 0 call 0 never executed -: 528: + 2, sizeof(char)); #####: 529: sprintf(config_dir_gral, "%s/%s", alt_config_dir, PNL); #####: 530: free(alt_config_dir); unconditional 0 never executed -: 531: } else { -: 532: /* If $XDG_CONFIG_HOME is set, use it for the config file. -: 533: * Else, fall back to $HOME/.config */ 24: 534: char *xdg_config_home = getenv("XDG_CONFIG_HOME"); 24: 534-block 0 call 0 returned 24 -: 535: 24: 536: if (xdg_config_home) { branch 0 taken 0 (fallthrough) branch 1 taken 24 #####: 537: size_t xdg_config_home_len = strlen(xdg_config_home); -: 538: #####: 539: config_dir_gral = (char *)xnmalloc(xdg_config_home_len + pnl_len %%%%%: 539-block 0 call 0 never executed -: 540: + 2, sizeof(char)); #####: 541: sprintf(config_dir_gral, "%s/%s", xdg_config_home, PNL); -: 542: #####: 543: xdg_config_home = (char *)NULL; unconditional 0 never executed -: 544: } else { 24: 545: config_dir_gral = (char *)xnmalloc(user.home_len + pnl_len + 11, 24: 545-block 0 call 0 returned 24 -: 546: sizeof(char)); 24: 547: sprintf(config_dir_gral, "%s/.config/%s", user.home, PNL); unconditional 0 taken 24 -: 548: } -: 549: } -: 550: 24: 551: size_t config_gral_len = strlen(config_dir_gral); -: 552: -: 553: /* alt_profile will not be NULL whenever the -P option is used -: 554: * to run the program under an alternative profile */ 24: 555: if (alt_profile) { 24: 555-block 0 branch 0 taken 6 (fallthrough) branch 1 taken 18 6: 556: config_dir = (char *)xnmalloc(config_gral_len + strlen(alt_profile) + 11, sizeof(char)); 6: 556-block 0 call 0 returned 6 6: 557: sprintf(config_dir, "%s/profiles/%s", config_dir_gral, alt_profile); unconditional 0 taken 6 -: 558: } else { 18: 559: config_dir = (char *)xnmalloc(config_gral_len + 18, sizeof(char)); 18: 559-block 0 call 0 returned 18 18: 560: sprintf(config_dir, "%s/profiles/default", config_dir_gral); unconditional 0 taken 18 -: 561: } -: 562: 24: 563: if (alt_kbinds_file) { 24: 563-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 24 #####: 564: kbinds_file = savestring(alt_kbinds_file, strlen(alt_kbinds_file)); %%%%%: 564-block 0 call 0 never executed #####: 565: free(alt_kbinds_file); #####: 566: alt_kbinds_file = (char *)NULL; unconditional 0 never executed -: 567: } else { -: 568: /* Keybindings per user, not per profile */ 24: 569: kbinds_file = (char *)xnmalloc(config_gral_len + 17, sizeof(char)); 24: 569-block 0 call 0 returned 24 24: 570: sprintf(kbinds_file, "%s/keybindings.cfm", config_dir_gral); unconditional 0 taken 24 -: 571: } -: 572: 24: 573: colors_dir = (char *)xnmalloc(config_gral_len + 8, sizeof(char)); 24: 573-block 0 call 0 returned 24 24: 574: sprintf(colors_dir, "%s/colors", config_dir_gral); -: 575: 24: 576: plugins_dir = (char *)xnmalloc(config_gral_len + 9, sizeof(char)); call 0 returned 24 24: 577: sprintf(plugins_dir, "%s/plugins", config_dir_gral); -: 578: -: 579:#ifndef _NO_TRASH 24: 580: trash_dir = (char *)xnmalloc(user.home_len + 20, sizeof(char)); call 0 returned 24 24: 581: sprintf(trash_dir, "%s/.local/share/Trash", user.home); -: 582: 24: 583: size_t trash_len = strlen(trash_dir); -: 584: 24: 585: trash_files_dir = (char *)xnmalloc(trash_len + 7, sizeof(char)); call 0 returned 24 24: 586: sprintf(trash_files_dir, "%s/files", trash_dir); -: 587: 24: 588: trash_info_dir = (char *)xnmalloc(trash_len + 6, sizeof(char)); call 0 returned 24 24: 589: sprintf(trash_info_dir, "%s/info", trash_dir); -: 590:#endif -: 591: 24: 592: size_t config_len = strlen(config_dir); -: 593: 24: 594: dirhist_file = (char *)xnmalloc(config_len + 13, sizeof(char)); call 0 returned 24 24: 595: sprintf(dirhist_file, "%s/dirhist.cfm", config_dir); -: 596: 24: 597: if (!alt_bm_file) { branch 0 taken 24 (fallthrough) branch 1 taken 0 24: 598: bm_file = (char *)xnmalloc(config_len + 15, sizeof(char)); 24: 598-block 0 call 0 returned 24 24: 599: sprintf(bm_file, "%s/bookmarks.cfm", config_dir); unconditional 0 taken 24 -: 600: } else { #####: 601: bm_file = savestring(alt_bm_file, strlen(alt_bm_file)); %%%%%: 601-block 0 call 0 never executed #####: 602: free(alt_bm_file); #####: 603: alt_bm_file = (char *)NULL; unconditional 0 never executed -: 604: } -: 605: 24: 606: log_file = (char *)xnmalloc(config_len + 9, sizeof(char)); 24: 606-block 0 call 0 returned 24 24: 607: sprintf(log_file, "%s/log.cfm", config_dir); -: 608: 24: 609: hist_file = (char *)xnmalloc(config_len + 13, sizeof(char)); call 0 returned 24 24: 610: sprintf(hist_file, "%s/history.cfm", config_dir); -: 611: 24: 612: if (!alt_config_file) { branch 0 taken 24 (fallthrough) branch 1 taken 0 24: 613: config_file = (char *)xnmalloc(config_len + pnl_len + 4, sizeof(char)); 24: 613-block 0 call 0 returned 24 24: 614: sprintf(config_file, "%s/%src", config_dir, PNL); unconditional 0 taken 24 -: 615: } else { #####: 616: config_file = savestring(alt_config_file, strlen(alt_config_file)); %%%%%: 616-block 0 call 0 never executed #####: 617: free(alt_config_file); #####: 618: alt_config_file = (char *)NULL; unconditional 0 never executed -: 619: } -: 620: 24: 621: profile_file = (char *)xnmalloc(config_len + 13, sizeof(char)); 24: 621-block 0 call 0 returned 24 24: 622: sprintf(profile_file, "%s/profile.cfm", config_dir); -: 623: 24: 624: msg_log_file = (char *)xnmalloc(config_len + 14, sizeof(char)); call 0 returned 24 24: 625: sprintf(msg_log_file, "%s/messages.cfm", config_dir); -: 626: 24: 627: mime_file = (char *)xnmalloc(config_len + 14, sizeof(char)); call 0 returned 24 24: 628: sprintf(mime_file, "%s/mimelist.cfm", config_dir); -: 629: 24: 630: actions_file = (char *)xnmalloc(config_len + 13, sizeof(char)); call 0 returned 24 24: 631: sprintf(actions_file, "%s/actions.cfm", config_dir); -: 632: 24: 633: remotes_file = (char *)xnmalloc(config_len + 10, sizeof(char)); call 0 returned 24 24: 634: sprintf(remotes_file, "%s/nets.cfm", config_dir); -: 635: 24: 636: return; unconditional 0 taken 24 -: 637:} -: 638: -: 639:static int function import_rl_file called 24 returned 100% blocks executed 47% 24: 640:import_rl_file(void) -: 641:{ 24: 642: if (!data_dir || !config_dir_gral) 24: 642-block 0 branch 0 taken 24 (fallthrough) branch 1 taken 0 24: 642-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 24 #####: 643: return EXIT_FAILURE; %%%%%: 643-block 0 unconditional 0 never executed -: 644: -: 645: char tmp[PATH_MAX]; 24: 646: sprintf(tmp, "%s/readline.cfm", config_dir_gral); -: 647: struct stat attr; 24: 648: if (lstat(tmp, &attr) == 0) 24: 648-block 0 call 0 returned 24 branch 1 taken 24 (fallthrough) branch 2 taken 0 24: 649: return EXIT_SUCCESS; 24: 649-block 0 unconditional 0 taken 24 -: 650: -: 651: char rl_file[PATH_MAX]; #####: 652: snprintf(rl_file, PATH_MAX - 1, "%s/%s/readline.cfm", data_dir, PNL); #####: 653: if (stat(rl_file, &attr) == EXIT_SUCCESS) { %%%%%: 653-block 0 call 0 never executed branch 1 never executed branch 2 never executed #####: 654: char *cmd[] = {"cp", rl_file, config_dir_gral, NULL}; #####: 655: if (launch_execve(cmd, FOREGROUND, E_NOSTDERR) == EXIT_SUCCESS) %%%%%: 655-block 0 call 0 never executed branch 1 never executed branch 2 never executed #####: 656: return EXIT_SUCCESS; %%%%%: 656-block 0 unconditional 0 never executed -: 657: } -: 658: #####: 659: return EXIT_FAILURE; %%%%%: 659-block 0 unconditional 0 never executed -: 660:} -: 661: -: 662:int function create_config called 1 returned 100% blocks executed 38% 1: 663:create_config(char *file) -: 664:{ -: 665: struct stat attr; -: 666: -: 667: /* First, try to import it from DATADIR */ 1: 668: if (data_dir) { 1: 668-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 0 -: 669: char sys_file[PATH_MAX]; 1: 670: snprintf(sys_file, PATH_MAX - 1, "%s/%s/%src", data_dir, PNL, PNL); 1: 671: if (stat(sys_file, &attr) == EXIT_SUCCESS) { 1: 671-block 0 call 0 returned 1 branch 1 taken 1 (fallthrough) branch 2 taken 0 1: 672: char *cmd[] = {"cp", sys_file, file, NULL}; 1: 673: if (launch_execve(cmd, FOREGROUND, E_NOFLAG) == EXIT_SUCCESS) 1: 673-block 0 call 0 returned 1 branch 1 taken 1 (fallthrough) branch 2 taken 0 1: 674: return EXIT_SUCCESS; 1: 674-block 0 unconditional 0 taken 1 -: 675: } -: 676: } -: 677: -: 678: /* If not found, create it */ -: 679: int fd; #####: 680: FILE *config_fp = open_fstream_w(file, &fd); %%%%%: 680-block 0 call 0 never executed -: 681: #####: 682: if (!config_fp) { branch 0 never executed branch 1 never executed #####: 683: fprintf(stderr, "%s: fopen: %s: %s\n", PROGRAM_NAME, file, strerror(errno)); %%%%%: 683-block 0 call 0 never executed call 1 never executed #####: 684: return EXIT_FAILURE; unconditional 0 never executed -: 685: } -: 686: -: 687: /* Do not translate anything in the config file */ #####: 688: fprintf(config_fp, %%%%%: 688-block 0 call 0 never executed -: 689: -: 690: "\t\t###########################################\n\ -: 691:\t\t# CLIFM #\n\ -: 692:\t\t# The anti-eye-candy, KISS file manager #\n\ -: 693:\t\t###########################################\n\n" -: 694: -: 695: "# This is the configuration file for CliFM\n\n" -: 696: -: 697: "# Color schemes are stored in the colors directory. By default,\n\ -: 698:# the 'default' color scheme is used. Visit %s\n\ -: 699:# to get a few more\n\ -: 700:ColorScheme=%s\n\n" -: 701: -: 702: "# The amount of files contained by a directory is informed next\n\ -: 703:# to the directory name. However, this feature might slow things down when,\n\ -: 704:# for example, listing files on a remote server. The filescounter can be\n\ -: 705:# disabled here, via the --no-files-counter option, or using the 'fc'\n\ -: 706:# command while in the program itself.\n\ -: 707:FilesCounter=%s\n\n" -: 708: -: 709: "# The character used to construct the line dividing the list of files and\n\ -: 710:# the prompt. DividingLineChar accepts both literal characters (in single\n\ -: 711:# quotes) and decimal numbers.\n\ -: 712:DividingLineChar='%c'\n\n" -: 713: -: 714: "# If set to true, print a map of the current position in the directory\n\ -: 715:# history list, showing previous, current, and next entries\n\ -: 716:DirhistMap=%s\n\n" -: 717: -: 718: "# Use a regex expression to filter file names when listing files.\n\ -: 719:# Example: !.*~$ to exclude backup files (ending with ~), or ^\\. to list \n\ -: 720:# only hidden files. Do not quote the regular expression\n\ -: 721:Filter=\n\n" -: 722: -: 723: "# Set the default copy command. Available options are: 0 = cp,\n\ -: 724:# 1 = advcp, and 2 = wcp. Both 1 and 2 add a progress bar to cp.\n\ -: 725:cpCmd=%d\n\n" -: 726: -: 727: "# Set the default move command. Available options are: 0 = mv,\n\ -: 728:# and 1 = advmv. 1 adds a progress bar to mv.\n\ -: 729:mvCmd=%d\n\n" -: 730: -: 731: "# The prompt line is built using string literals and/or one or more of\n\ -: 732:# the following escape sequences:\n" -: 733: "# \\e: Escape character\n\ -: 734:# \\h: The hostname, up to the first dot\n\ -: 735:# \\u: The username\n\ -: 736:# \\H: The full hostname\n\ -: 737:# \\n: A newline character\n\ -: 738:# \\r: A carriage return\n\ -: 739:# \\a: A bell character\n\ -: 740:# \\d: The date, in abbrevieted form (ex: 'Tue May 26')\n\ -: 741:# \\s: The name of the shell (everything after the last slash) currently used\n\ -: 742:# by CliFM\n\ -: 743:# \\S: The number of the current workspace\n\ -: 744:# \\l: Print an 'L' if running in light mode\n\ -: 745:# \\P: Current profile name\n\ -: 746:# \\t: The time, in 24-hour HH:MM:SS format\n\ -: 747:# \\T: The time, in 12-hour HH:MM:SS format\n\ -: 748:# \\@: The time, in 12-hour am/pm format\n\ -: 749:# \\A: The time, in 24-hour HH:MM format\n\ -: 750:# \\w: The full current working directory, with $HOME abbreviated with a tilde\n\ -: 751:# \\W: The basename of $PWD, with $HOME abbreviated with a tilde\n\ -: 752:# \\p: A mix of the two above, it abbreviates the current working directory \n\ -: 753:# only if longer than PathMax (a value defined in the configuration file).\n\ -: 754:# \\z: Exit code of the last executed command. :) if success and :( in case of\n\ -: 755:# error\n\ -: 756:# \\$ '#', if the effective user ID is 0, and '$' otherwise\n\ -: 757:# \\nnn: The character whose ASCII code is the octal value nnn\n\ -: 758:# \\\\: A backslash\n\ -: 759:# \\[: Begin a sequence of non-printing characters. This is mostly used to\n\ -: 760:# add color to the prompt line\n\ -: 761:# \\]: End a sequence of non-printing characters\n\n" -: 762: -: 763: "Prompt=\"%s\"\n\n" -: 764: -: 765: "# If set to 'default', CliFM state information (selected files,\n\ -: 766:# trashed files, current workspace, messages, and stealth mode) will be printed\n\ -: 767:# to the left of the prompt. Otherwise, if set to 'custom', this information\n\ -: 768:# will be stored in environment variables to be handled by the prompt string\n\ -: 769:# itself. Consult the manpage for more information.\n\ -: 770:PromptStyle=default\n\n", -: 771: -: 772: COLORS_REPO, -: 773: DEF_COLOR_SCHEME, -: 774: DEF_FILES_COUNTER == 1 ? "true" : "false", -: 775: DEF_DIV_LINE_CHAR, -: 776: DEF_DIRHIST_MAP == 1 ? "true" : "false", -: 777: DEF_CP_CMD, -: 778: DEF_MV_CMD, -: 779: DEFAULT_PROMPT); -: 780: #####: 781: fprintf(config_fp, call 0 never executed -: 782: "# MaxPath is only used for the /p option of the prompt: the current working\n\ -: 783:# directory will be abbreviated to its basename (everything after last slash)\n\ -: 784:# whenever the current path is longer than MaxPath.\n\ -: 785:MaxPath=%d\n\n" -: 786: -: 787: "WelcomeMessage=%s\n\n\ -: 788:# Print %s's logo screen at startup\n\ -: 789:SplashScreen=%s\n\n\ -: 790:ShowHiddenFiles=%s\n\n\ -: 791:# List files properties next to file names instead of just file names\n\ -: 792:LongViewMode=%s\n\n\ -: 793:# Keep a record of both external commands and internal commands able to\n\ -: 794:# modify the files system (e.g. 'r', 'c', 'm', and so on)\n\ -: 795:LogCmds=%s\n\n" -: 796: -: 797: "# Minimum length at which a file name can be trimmed in long view mode\n\ -: 798:# (including ELN length and spaces)\n\ -: 799:MinFilenameTrim=%d\n\n" -: 800: -: 801: "# When a directory rank in the jump database is below MinJumpRank, it\n\ -: 802:# will be forgotten\n\ -: 803:MinJumpRank=%d\n\n" -: 804: -: 805: "# When the sum of all ranks in the jump database reaches MaxJumpTotalRank,\n\ -: 806:# all ranks will be reduced 10%%, and those falling below MinJumpRank will\n\ -: 807:# be deleted\n\ -: 808:MaxJumpTotalRank=%d\n\n" -: 809: -: 810: "# Should CliFM be allowed to run external, shell commands?\n\ -: 811:ExternalCommands=%s\n\n" -: 812: -: 813: "# Write the last visited directory to $XDG_CONFIG_HOME/clifm/.last to be\n\ -: 814:# later accessed by the corresponding shell function at program exit.\n\ -: 815:# To enable this feature consult the manpage.\n\ -: 816:CdOnQuit=%s\n\n" -: 817: -: 818: "# If set to true, a command name that is the name of a directory or a\n\ -: 819:# file is executed as if it were the argument to the the 'cd' or the \n\ -: 820:# 'open' commands respectivelly: 'cd DIR' works the same as just 'DIR'\n\ -: 821:# and 'open FILE' works the same as just 'FILE'.\n\ -: 822:Autocd=%s\n\ -: 823:AutoOpen=%s\n\n" -: 824: -: 825: "# If set to true, enable auto-suggestions.\n\ -: 826:AutoSuggestions=%s\n\n" -: 827: -: 828: "# The following checks will be performed in the order specified\n\ -: 829:# by SuggestionStrategy. Available checks:\n\ -: 830:# a = Aliases names\n\ -: 831:# b = Bookmarks names\n\ -: 832:# c = Possible completions\n\ -: 833:# e = ELN's\n\ -: 834:# f = File names in current directory\n\ -: 835:# h = Commands history\n\ -: 836:# j = Jump database\n\ -: 837:# Use a dash (-) to skip a check. Ex: 'eahfj-c' to skip the bookmarks check\n\ -: 838:SuggestionStrategy=%s\n\n" -: 839: -: 840: "# If set to true, suggest file names using the corresponding\n\ -: 841:# file type color (set via the color scheme file).\n\ -: 842:SuggestFiletypeColor=%s\n\n" -: 843: -: 844:"SyntaxHighlighting=%s\n\n" -: 845: -: 846: "# If set to true, expand bookmark names into the corresponding bookmark\n\ -: 847:# path: if the bookmark is \"name=/path\", \"name\" will be interpreted\n\ -: 848:# as /path. TAB completion is also available for bookmark names.\n\ -: 849:ExpandBookmarks=%s\n\n" -: 850: -: 851: "# In light mode, extra file type checks (except those provided by\n\ -: 852:# the d_type field of the dirent structure (see readdir(3))\n\ -: 853:# are disabled to speed up the listing process. stat(3) and access(3)\n\ -: 854:# are not executed at all, so that we cannot know in advance if a file\n\ -: 855:# is readable by the current user, if it is executable, SUID, SGID, if a\n\ -: 856:# symlink is broken, and so on. The file extension check is ignored as\n\ -: 857:# well, so that the color per extension feature is disabled.\n\ -: 858:LightMode=%s\n\n", -: 859: -: 860: DEF_MAX_PATH, -: 861: DEF_WELCOME_MESSAGE == 1 ? "true" : "false", -: 862: PROGRAM_NAME, -: 863: DEF_SPLASH_SCREEN == 1 ? "true" : "false", -: 864: DEF_SHOW_HIDDEN == 1 ? "true" : "false", -: 865: DEF_LONG_VIEW == 1 ? "true" : "false", -: 866: DEF_LOGS_ENABLED == 1 ? "true" : "false", -: 867: DEF_MIN_NAME_TRIM, -: 868: DEF_MIN_JUMP_RANK, -: 869: DEF_MAX_JUMP_TOTAL_RANK, -: 870: DEF_EXT_CMD_OK == 1 ? "true" : "false", -: 871: DEF_CD_ON_QUIT == 1 ? "true" : "false", -: 872: DEF_AUTOCD == 1 ? "true" : "false", -: 873: DEF_AUTO_OPEN == 1 ? "true" : "false", -: 874: DEF_SUGGESTIONS == 1 ? "true" : "false", -: 875: DEF_SUG_STRATEGY, -: 876: DEF_SUG_FILETYPE_COLOR == 1 ? "true" : "false", -: 877: DEF_HIGHLIGHT == 1 ? "true" : "false", -: 878: DEF_EXPAND_BOOKMARKS == 1 ? "true" : "false", -: 879: DEF_LIGHT_MODE == 1 ? "true" : "false" -: 880: ); -: 881: #####: 882: fprintf(config_fp, call 0 never executed -: 883: "# If running with colors, append directory indicator and files counter\n\ -: 884:# to directories. If running without colors (via the --no-colors option),\n\ -: 885:# append file type indicator at the end of file names: '/' for directories,\n\ -: 886:# '@' for symbolic links, '=' for sockets, '|' for FIFO/pipes, '*'\n\ -: 887:# for for executable files, and '?' for unknown file types. Bear in mind\n\ -: 888:# that when running in light mode the check for executable files won't be\n\ -: 889:# performed, and thereby no indicator will be added to executable files.\n\ -: 890:Classify=%s\n\n" -: 891: -: 892: "# Should the Selection Box be shared among different profiles?\n\ -: 893:ShareSelbox=%s\n\n" -: 894: -: 895: "# Choose the resource opener to open files with their default associated\n\ -: 896:# application. If not set, 'lira', CLiFM's built-in opener, is used.\n\ -: 897:Opener=\n\n" -: 898: -: 899: "# Set the shell to be used when running external commands. Defaults to the\n\ -: 900:# user's shell as specified in '/etc/passwd'.\n\ -: 901:SystemShell=\n\n" -: 902: -: 903: "# Only used when opening a directory via a new CliFM instance (with the 'x'\n\ -: 904:# command), this option specifies the command to be used to launch a\n\ -: 905:# terminal emulator to run CliFM on it.\n\ -: 906:TerminalCmd='%s'\n\n" -: 907: -: 908: "# Choose sorting method: 0 = none, 1 = name, 2 = size, 3 = atime\n\ -: 909:# 4 = btime (ctime if not available), 5 = ctime, 6 = mtime, 7 = version\n\ -: 910:# (name if note available) 8 = extension, 9 = inode, 10 = owner, 11 = group\n\ -: 911:# NOTE: the 'version' method is not available on FreeBSD\n\ -: 912:Sort=%d\n\ -: 913:# By default, CliFM sorts files from less to more (ex: from 'a' to 'z' if\n\ -: 914:# using the \"name\" method). To invert this ordering, set SortReverse to\n\ -: 915:# true (you can also use the --sort-reverse option or the 'st' command)\n\ -: 916:SortReverse=%s\n\n" -: 917: -: 918: "# Print a usage tip at startup\n\ -: 919:Tips=%s\n\n\ -: 920:ListFoldersFirst=%s\n\ -: 921:CdListsAutomatically=%s\n\n\ -: 922:# Enable case sensitive listing for files in the current directory\n\ -: 923:CaseSensitiveList=%s\n\n\ -: 924:# Enable case sensitive lookup for the directory jumper function (via \n\ -: 925:# the 'j' command)\n\ -: 926:CaseSensitiveDirJump=%s\n\n\ -: 927:# Enable case sensitive completion for file names\n\ -: 928:CaseSensitivePathComp=%s\n\n\ -: 929:Unicode=%s\n\n\ -: 930:# Enable Mas, the files list pager (executed whenever the list of files\n\ -: 931:# does not fit in the screen)\n\ -: 932:Pager=%s\n\n\ -: 933:MaxHistory=%d\n\ -: 934:MaxDirhist=%d\n\ -: 935:MaxLog=%d\n\ -: 936:DiskUsage=%s\n\n" -: 937: -: 938: "# If set to true, always print the list of selected files. Since this\n\ -: 939:# list could become quite extensive, you can limit the number of printed \n\ -: 940:# entries using the MaxPrintSelfiles option (-1 = no limit, 0 = auto (never\n\ -: 941:# print more than half terminal height), or any custom value)\n\ -: 942:PrintSelfiles=%s\n\ -: 943:MaxPrintSelfiles=%d\n\n" -: 944: -: 945: "# If set to true, clear the screen before listing files\n\ -: 946:ClearScreen=%s\n\n" -: 947: -: 948: "# If not specified, StartingPath defaults to the current working\n\ -: 949:# directory.\n\ -: 950:StartingPath=\n\n" -: 951: -: 952: "# If set to true, start CliFM in the last visited directory (and in the\n\ -: 953:# last used workspace). This option overrides StartingPath.\n\ -: 954:RestoreLastPath=%s\n\n" -: 955: -: 956: "# If set to true, the 'r' command executes 'trash' instead of 'rm' to\n\ -: 957:# prevent accidental deletions.\n\ -: 958:TrashAsRm=%s\n\n" -: 959: -: 960: "# Set readline editing mode: 0 for vi and 1 for emacs (default).\n\ -: 961:RlEditMode=%d\n\n" -: 962: -: 963: "#END OF OPTIONS\n\n", -: 964: -: 965: DEF_CLASSIFY == 1 ? "true" : "false", -: 966: DEF_SHARE_SELBOX == 1 ? "true" : "false", -: 967: DEFAULT_TERM_CMD, -: 968: DEF_SORT, -: 969: DEF_SORT_REVERSE == 1 ? "true" : "false", -: 970: DEF_TIPS == 1 ? "true" : "false", -: 971: DEF_LIST_FOLDERS_FIRST == 1 ? "true" : "false", -: 972: DEF_CD_LISTS_ON_THE_FLY == 1 ? "true" : "false", -: 973: DEF_CASE_SENSITIVE == 1 ? "true" : "false", -: 974: DEF_CASE_SENS_DIRJUMP == 1 ? "true" : "false", -: 975: DEF_CASE_SENS_PATH_COMP == 1 ? "true" : "false", -: 976: DEF_UNICODE == 1 ? "true" : "false", -: 977: DEF_PAGER == 1 ? "true" : "false", -: 978: DEF_MAX_HIST, -: 979: DEF_MAX_DIRHIST, -: 980: DEF_MAX_LOG, -: 981: DEF_DISK_USAGE == 1 ? "true" : "false", -: 982: DEF_PRINTSEL == 1 ? "true" : "false", -: 983: DEF_MAXPRINTSEL, -: 984: DEF_CLEAR_SCREEN == 1 ? "true" : "false", -: 985: DEF_RESTORE_LAST_PATH == 1 ? "true" : "false", -: 986: DEF_TRASRM == 1 ? "true" : "false", -: 987: DEF_RL_EDIT_MODE -: 988: ); -: 989: #####: 990: fputs( call 0 never executed -: 991: -: 992: "#ALIASES\n\ -: 993:#alias ls='ls --color=auto -A'\n\n" -: 994: -: 995: "#PROMPT COMMANDS\n\n" -: 996: "# Write below the commands you want to be executed before the prompt.\n\ -: 997:# Ex:\n\ -: 998:#/usr/share/clifm/plugins/git_status.sh\n\ -: 999:#date | awk '{print $1\", \"$2,$3\", \"$4}'\n\n" -: 1000: "#END OF PROMPT COMMANDS\n\n", -: 1001: config_fp); -: 1002: #####: 1003: close_fstream(config_fp, fd); call 0 never executed #####: 1004: return EXIT_SUCCESS; unconditional 0 never executed -: 1005:} -: 1006: -: 1007:static void function create_def_cscheme called 24 returned 100% blocks executed 44% 24: 1008:create_def_cscheme(void) -: 1009:{ 24: 1010: if (!colors_dir) 24: 1010-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 24 #####: 1011: return; %%%%%: 1011-block 0 unconditional 0 never executed -: 1012: 24: 1013: char *cscheme_file = (char *)xnmalloc(strlen(colors_dir) + 13, sizeof(char)); 24: 1013-block 0 call 0 returned 24 24: 1014: sprintf(cscheme_file, "%s/default.cfm", colors_dir); -: 1015: -: 1016: /* If the file already exists, do nothing */ -: 1017: struct stat attr; 24: 1018: if (stat(cscheme_file, &attr) != -1) { call 0 returned 24 branch 1 taken 24 (fallthrough) branch 2 taken 0 24: 1019: free(cscheme_file); 24: 1020: return; 24: 1020-block 0 unconditional 0 taken 24 -: 1021: } -: 1022: -: 1023: int fd; #####: 1024: FILE *fp = open_fstream_w(cscheme_file, &fd); %%%%%: 1024-block 0 call 0 never executed #####: 1025: if (!fp) { branch 0 never executed branch 1 never executed #####: 1026: _err('w', PRINT_PROMPT, "%s: Error creating default color scheme " call 0 never executed #####: 1027: "file: %s\n", PROGRAM_NAME, strerror(errno)); %%%%%: 1027-block 0 call 0 never executed #####: 1028: free(cscheme_file); #####: 1029: return; unconditional 0 never executed -: 1030: } -: 1031: #####: 1032: fprintf(fp, "# Default color scheme for %s\n\n\ %%%%%: 1032-block 0 call 0 never executed -: 1033:# FiletypeColors defines the color used for file types when listing files,\n\ -: 1034:# just as InterfaceColors defines colors for CliFM's interface and ExtColors\n\ -: 1035:# for file extensions. They all make use of the same format used by the\n\ -: 1036:# LS_COLORS environment variable. Thus, \"di=01;34\" means that (non-empty)\n\ -: 1037:# directories will be listed in bold blue.\n\ -: 1038:# Color codes are traditional ANSI escape sequences less the escape char and\n\ -: 1039:# the final 'm'. 8 bit, 256 colors, and RGB colors are supported.\n\ -: 1040:# A detailed explanation of all these codes can be found in the manpage.\n\n" -: 1041: -: 1042: "FiletypeColors=\"%s\"\n\n" -: 1043: -: 1044: "InterfaceColors=\"%s\"\n\n" -: 1045: -: 1046: "# Same as FiletypeColors, but for file extensions. The format is always\n\ -: 1047:# *.EXT=COLOR\n" -: 1048:#ifndef _NO_ICONS -: 1049: "ExtColors=\"%s\"\n\n" -: 1050: -: 1051: "DirIconsColor=\"00;33\"\n", -: 1052:#else -: 1053: "ExtColors=\"%s\"\n\n", -: 1054:#endif -: 1055: PROGRAM_NAME, -: 1056: DEF_FILE_COLORS, -: 1057: DEF_IFACE_COLORS, -: 1058: DEF_EXT_COLORS); -: 1059: #####: 1060: close_fstream(fp, fd); call 0 never executed #####: 1061: free(cscheme_file); #####: 1062: return; unconditional 0 never executed -: 1063:} -: 1064: -: 1065:static int function create_remotes_file called 24 returned 100% blocks executed 75% 24: 1066:create_remotes_file(void) -: 1067:{ 24: 1068: if (!remotes_file || !*remotes_file) 24: 1068-block 0 branch 0 taken 24 (fallthrough) branch 1 taken 0 24: 1068-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 24 #####: 1069: return EXIT_FAILURE; %%%%%: 1069-block 0 unconditional 0 never executed -: 1070: -: 1071: struct stat attr; 24: 1072: if (stat(remotes_file, &attr) == EXIT_SUCCESS) 24: 1072-block 0 call 0 returned 24 branch 1 taken 23 (fallthrough) branch 2 taken 1 23: 1073: return EXIT_SUCCESS; 23: 1073-block 0 unconditional 0 taken 23 -: 1074: -: 1075: int fd; 1: 1076: FILE *fp = open_fstream_w(remotes_file, &fd); 1: 1076-block 0 call 0 returned 1 1: 1077: if (!fp) { branch 0 taken 0 (fallthrough) branch 1 taken 1 #####: 1078: _err('e', PRINT_PROMPT, "%s: '%s': %s\n", PROGRAM_NAME, call 0 never executed #####: 1079: remotes_file, strerror(errno)); %%%%%: 1079-block 0 call 0 never executed #####: 1080: return EXIT_FAILURE; unconditional 0 never executed -: 1081: } -: 1082: 1: 1083: fprintf(fp, "#####################################\n" 1: 1083-block 0 call 0 returned 1 -: 1084: "# Remotes management file for %s #\n" -: 1085: "#####################################\n\n" -: 1086: "# Blank and commented lines are omitted\n\n" -: 1087: "# Example:\n" -: 1088: "# A name for this remote. It will be used by the 'net' command\n" -: 1089: "# and will be available for TAB completion\n" -: 1090: "# [work_smb]\n\n" -: 1091: "# Comment=My work samba server\n" -: 1092: "# Mountpoint=/home/user/.config/clifm/mounts/work_smb\n\n" -: 1093: "# Use %%m as a placeholder for Mountpoint\n" -: 1094: "# MountCmd=mount.cifs //WORK_IP/shared %%m -o OPTIONS\n" -: 1095: "# UnmountCmd=umount %%m\n\n" -: 1096: "# Automatically mount this remote at startup\n" -: 1097: "# AutoMount=true\n\n" -: 1098: "# Automatically unmount this remote at exit\n" -: 1099: "# AutoUnmount=true\n\n", PROGRAM_NAME); -: 1100: 1: 1101: close_fstream(fp, fd); call 0 returned 1 1: 1102: return EXIT_SUCCESS; unconditional 0 taken 1 -: 1103:} -: 1104: -: 1105:static void function create_config_files called 24 returned 100% blocks executed 45% 24: 1106:create_config_files(void) -: 1107:{ -: 1108: struct stat attr; -: 1109: -: 1110: /* ############################# -: 1111: * # TRASH DIRS # -: 1112: * ############################# */ -: 1113:#ifndef _NO_TRASH 24: 1114: if (stat(trash_dir, &attr) == -1) { 24: 1114-block 0 call 0 returned 24 branch 1 taken 0 (fallthrough) branch 2 taken 24 #####: 1115: char *trash_files = (char *)NULL; #####: 1116: trash_files = (char *)xnmalloc(strlen(trash_dir) + 7, sizeof(char)); %%%%%: 1116-block 0 call 0 never executed -: 1117: #####: 1118: sprintf(trash_files, "%s/files", trash_dir); #####: 1119: char *trash_info = (char *)NULL; #####: 1120: trash_info = (char *)xnmalloc(strlen(trash_dir) + 6, sizeof(char)); call 0 never executed -: 1121: #####: 1122: sprintf(trash_info, "%s/info", trash_dir); #####: 1123: char *cmd[] = {"mkdir", "-p", trash_files, trash_info, NULL}; -: 1124: #####: 1125: int ret = launch_execve(cmd, FOREGROUND, E_NOFLAG); call 0 never executed #####: 1126: free(trash_files); #####: 1127: free(trash_info); -: 1128: #####: 1129: if (ret != EXIT_SUCCESS) { branch 0 never executed branch 1 never executed #####: 1130: trash_ok = 0; #####: 1131: _err('w', PRINT_PROMPT, _("%s: mkdir: '%s': Error creating trash " %%%%%: 1131-block 0 call 0 never executed call 1 never executed unconditional 2 never executed -: 1132: "directory. Trash function disabled\n"), PROGRAM_NAME, trash_dir); -: 1133: } -: 1134: } -: 1135: -: 1136: /* If it exists, check it is writable */ 24: 1137: else if (access(trash_dir, W_OK) == -1) { 24: 1137-block 0 call 0 returned 24 branch 1 taken 0 (fallthrough) branch 2 taken 24 #####: 1138: trash_ok = 0; #####: 1139: _err('w', PRINT_PROMPT, _("%s: '%s': Directory not writable. " %%%%%: 1139-block 0 call 0 never executed call 1 never executed unconditional 2 never executed -: 1140: "Trash function disabled\n"), PROGRAM_NAME, trash_dir); -: 1141: } -: 1142:#endif -: 1143: /* #################### -: 1144: * # CONFIG DIR # -: 1145: * #################### */ -: 1146: -: 1147: /* If the config directory doesn't exist, create it */ -: 1148: /* Use the GNU mkdir to let it handle parent directories */ 24: 1149: if (stat(config_dir, &attr) == -1) { 24: 1149-block 0 call 0 returned 24 branch 1 taken 0 (fallthrough) branch 2 taken 24 #####: 1150: char *tmp_cmd[] = {"mkdir", "-p", config_dir, NULL}; #####: 1151: if (launch_execve(tmp_cmd, FOREGROUND, E_NOFLAG) != EXIT_SUCCESS) { %%%%%: 1151-block 0 call 0 never executed branch 1 never executed branch 2 never executed #####: 1152: config_ok = 0; #####: 1153: _err('e', PRINT_PROMPT, _("%s: mkdir: '%s': Error creating " %%%%%: 1153-block 0 call 0 never executed call 1 never executed -: 1154: "configuration directory. Bookmarks, commands logs, and " -: 1155: "command history are disabled. Program messages won't be " -: 1156: "persistent. Using default options\n"), -: 1157: PROGRAM_NAME, config_dir); #####: 1158: return; unconditional 0 never executed -: 1159: } -: 1160: } -: 1161: -: 1162: /* If it exists, check it is writable */ 24: 1163: else if (access(config_dir, W_OK) == -1) { 24: 1163-block 0 call 0 returned 24 branch 1 taken 0 (fallthrough) branch 2 taken 24 #####: 1164: config_ok = 0; #####: 1165: _err('e', PRINT_PROMPT, _("%s: '%s': Directory not writable. Bookmarks, " %%%%%: 1165-block 0 call 0 never executed call 1 never executed -: 1166: "commands logs, and commands history are disabled. Program messages " -: 1167: "won't be persistent. Using default options\n"), -: 1168: PROGRAM_NAME, config_dir); #####: 1169: return; unconditional 0 never executed -: 1170: } -: 1171: -: 1172: /* ##################### -: 1173: * # CONFIG FILE # -: 1174: * #####################*/ -: 1175: 24: 1176: if (stat(config_file, &attr) == -1) { 24: 1176-block 0 call 0 returned 24 branch 1 taken 0 (fallthrough) branch 2 taken 24 #####: 1177: if (create_config(config_file) == EXIT_SUCCESS) %%%%%: 1177-block 0 call 0 never executed branch 1 never executed branch 2 never executed #####: 1178: config_ok = 1; %%%%%: 1178-block 0 unconditional 0 never executed -: 1179: else #####: 1180: config_ok = 0; %%%%%: 1180-block 0 unconditional 0 never executed -: 1181: } -: 1182: 24: 1183: if (!config_ok) 24: 1183-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 24 #####: 1184: return; %%%%%: 1184-block 0 unconditional 0 never executed -: 1185: -: 1186: /* ###################### -: 1187: * # PROFILE FILE # -: 1188: * ###################### */ -: 1189: 24: 1190: if (stat(profile_file, &attr) == -1) { 24: 1190-block 0 call 0 returned 24 branch 1 taken 1 (fallthrough) branch 2 taken 23 1: 1191: FILE *profile_fp = fopen(profile_file, "w"); 1: 1191-block 0 call 0 returned 1 1: 1192: if (!profile_fp) { branch 0 taken 0 (fallthrough) branch 1 taken 1 #####: 1193: _err('e', PRINT_PROMPT, "%s: fopen: '%s': %s\n", PROGRAM_NAME, call 0 never executed unconditional 1 never executed #####: 1194: profile_file, strerror(errno)); %%%%%: 1194-block 0 call 0 never executed -: 1195: } else { 1: 1196: fprintf(profile_fp, _("#%s profile\n\ 1: 1196-block 0 call 0 returned 1 call 1 returned 1 -: 1197:# Write here the commands you want to be executed at startup\n\ -: 1198:# Ex:\n#echo -e \"%s, the anti-eye-candy/KISS file manager\"\n"), -: 1199: PROGRAM_NAME, PROGRAM_NAME); 1: 1200: fclose(profile_fp); call 0 returned 1 unconditional 1 taken 1 -: 1201: } -: 1202: } -: 1203: -: 1204: /* ##################### -: 1205: * # COLORS DIR # -: 1206: * ##################### */ -: 1207: 24: 1208: if (stat(colors_dir, &attr) == -1) { 24: 1208-block 0 call 0 returned 24 branch 1 taken 0 (fallthrough) branch 2 taken 24 #####: 1209: char *cmd[] = {"mkdir", colors_dir, NULL}; #####: 1210: if (launch_execve(cmd, FOREGROUND, E_NOFLAG) != EXIT_SUCCESS) { %%%%%: 1210-block 0 call 0 never executed branch 1 never executed branch 2 never executed #####: 1211: _err('w', PRINT_PROMPT, _("%s: mkdir: Error creating colors " %%%%%: 1211-block 0 call 0 never executed call 1 never executed unconditional 2 never executed -: 1212: "directory. Using the default color scheme\n"), -: 1213: PROGRAM_NAME); -: 1214: } -: 1215: } -: 1216: -: 1217: /* Generate the default color scheme file */ 24: 1218: create_def_cscheme(); 24: 1218-block 0 call 0 returned 24 -: 1219: -: 1220: /* ##################### -: 1221: * # PLUGINS # -: 1222: * #####################*/ -: 1223: 24: 1224: if (stat(plugins_dir, &attr) == -1) { call 0 returned 24 branch 1 taken 0 (fallthrough) branch 2 taken 24 #####: 1225: char *cmd[] = {"mkdir", plugins_dir, NULL}; #####: 1226: if (launch_execve(cmd, FOREGROUND, E_NOFLAG) != EXIT_SUCCESS) { %%%%%: 1226-block 0 call 0 never executed branch 1 never executed branch 2 never executed #####: 1227: _err('e', PRINT_PROMPT, _("%s: mkdir: Error creating plugins " %%%%%: 1227-block 0 call 0 never executed call 1 never executed unconditional 2 never executed -: 1228: "directory. The actions function is disabled\n"), -: 1229: PROGRAM_NAME); -: 1230: } -: 1231: } -: 1232: 24: 1233: import_rl_file(); 24: 1233-block 0 call 0 returned 24 24: 1234: create_actions_file(actions_file); call 0 returned 24 24: 1235: create_mime_file(mime_file, 0); call 0 returned 24 24: 1236: create_remotes_file(); call 0 returned 24 -: 1237:} -: 1238: -: 1239:int function create_mime_file called 25 returned 100% blocks executed 63% 25: 1240:create_mime_file(char *file, int new_prof) -: 1241:{ -: 1242: struct stat attr; 25: 1243: if (stat(file, &attr) == EXIT_SUCCESS) 25: 1243-block 0 call 0 returned 25 branch 1 taken 24 (fallthrough) branch 2 taken 1 24: 1244: return EXIT_SUCCESS; 24: 1244-block 0 unconditional 0 taken 24 -: 1245: 1: 1246: if (!data_dir) 1: 1246-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 1 #####: 1247: return EXIT_FAILURE; %%%%%: 1247-block 0 unconditional 0 never executed -: 1248: -: 1249: char sys_mimelist[PATH_MAX]; 1: 1250: snprintf(sys_mimelist, PATH_MAX - 1, "%s/%s/mimelist.cfm", data_dir, PNL); -: 1251: 1: 1252: if (stat(sys_mimelist, &attr) == -1) { 1: 1252-block 0 call 0 returned 1 branch 1 taken 0 (fallthrough) branch 2 taken 1 #####: 1253: _err('e', PRINT_PROMPT, "%s: %s: %s\n", PROGRAM_NAME, call 0 never executed #####: 1254: sys_mimelist, strerror(errno)); %%%%%: 1254-block 0 call 0 never executed #####: 1255: return EXIT_FAILURE; unconditional 0 never executed -: 1256: } -: 1257: 1: 1258: char *cmd[] = {"cp", "-f", sys_mimelist, file, NULL}; 1: 1259: if (launch_execve(cmd, FOREGROUND, E_NOFLAG) == EXIT_SUCCESS) { 1: 1259-block 0 call 0 returned 1 branch 1 taken 1 (fallthrough) branch 2 taken 0 1: 1260: if (!new_prof) { 1: 1260-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 1 #####: 1261: _err('n', PRINT_PROMPT, _("%s created a new MIME list file (%s) " %%%%%: 1261-block 0 call 0 never executed call 1 never executed unconditional 2 never executed -: 1262: "It is recommended to edit this file (entering 'mm edit' or " -: 1263: "pressing F6) to add the programs you use and remove those " -: 1264: "you don't. This will make the process of opening files " -: 1265: "faster and smoother\n"), -: 1266: PROGRAM_NAME, file, sys_mimelist); -: 1267: } 1: 1268: return EXIT_SUCCESS; 1: 1268-block 0 unconditional 0 taken 1 -: 1269: } -: 1270: #####: 1271: return EXIT_FAILURE; %%%%%: 1271-block 0 unconditional 0 never executed -: 1272:} -: 1273: -: 1274:int function create_bm_file called 21 returned 100% blocks executed 71% 21: 1275:create_bm_file(void) -: 1276:{ 21: 1277: if (!bm_file) 21: 1277-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 21 #####: 1278: return EXIT_FAILURE; %%%%%: 1278-block 0 unconditional 0 never executed -: 1279: -: 1280: struct stat file_attrib; 21: 1281: if (stat(bm_file, &file_attrib) == -1) { 21: 1281-block 0 call 0 returned 21 branch 1 taken 1 (fallthrough) branch 2 taken 20 1: 1282: FILE *fp = fopen(bm_file, "w+"); 1: 1282-block 0 call 0 returned 1 1: 1283: if (!fp) { branch 0 taken 0 (fallthrough) branch 1 taken 1 #####: 1284: _err('e', PRINT_PROMPT, "bookmarks: '%s': %s\n", bm_file, call 0 never executed #####: 1285: strerror(errno)); %%%%%: 1285-block 0 call 0 never executed #####: 1286: return EXIT_FAILURE; unconditional 0 never executed -: 1287: } else { 1*: 1288: fprintf(fp, "### This is the bookmarks file for %s ###\n\n" 1: 1288-block 0 unconditional 0 taken 1 %%%%%: 1288-block 1 unconditional 1 never executed 1: 1288-block 2 call 2 returned 1 -: 1289: "# Empty and commented lines are ommited\n" -: 1290: "# The bookmarks syntax is: [shortcut]name:path\n" -: 1291: "# Example:\n" -: 1292: "[c]clifm:%s\n", 1: 1293: PROGRAM_NAME, config_dir ? config_dir : "path/to/file"); 1: 1293-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 0 1: 1294: fclose(fp); call 0 returned 1 unconditional 1 taken 1 -: 1295: } -: 1296: } -: 1297: 21: 1298: return EXIT_SUCCESS; 21: 1298-block 0 unconditional 0 taken 21 -: 1299:} -: 1300: -: 1301:static void function read_config called 24 returned 100% blocks executed 76% 24: 1302:read_config(void) -: 1303:{ 24: 1304: int ret = -1; -: 1305: -: 1306: int fd; 24: 1307: FILE *config_fp = open_fstream_r(config_file, &fd); 24: 1307-block 0 call 0 returned 24 24: 1308: if (!config_fp) { branch 0 taken 0 (fallthrough) branch 1 taken 24 #####: 1309: _err('e', PRINT_PROMPT, _("%s: fopen: '%s': %s. Using default values.\n"), call 0 never executed call 1 never executed #####: 1310: PROGRAM_NAME, config_file, strerror(errno)); %%%%%: 1310-block 0 call 0 never executed #####: 1311: return; unconditional 0 never executed -: 1312: } -: 1313: 24: 1314: if (xargs.rl_vi_mode == 1) 24: 1314-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 24 #####: 1315: rl_vi_editing_mode(1, 0); %%%%%: 1315-block 0 call 0 never executed unconditional 1 never executed -: 1316: 24: 1317: *div_line_char = '\0'; -: 1318:#define MAX_BOOL 6 /* false (5) + 1 */ -: 1319: /* starting path(14) + PATH_MAX + \n(1)*/ -: 1320: char line[PATH_MAX + 15]; -: 1321: 5795: 1322: while (fgets(line, (int)sizeof(line), config_fp)) { 24: 1322-block 0 unconditional 0 taken 24 5795: 1322-block 1 call 1 returned 5795 branch 2 taken 5795 branch 3 taken 0 (fallthrough) 5795: 1323: if (*line == '\n' || (*line == '#' && line[1] != 'E')) 5795: 1323-block 0 branch 0 taken 4740 (fallthrough) branch 1 taken 1055 4740: 1323-block 1 branch 2 taken 3308 (fallthrough) branch 3 taken 1432 3308: 1323-block 2 branch 4 taken 3284 (fallthrough) branch 5 taken 24 4339: 1324: continue; 4339: 1324-block 0 unconditional 0 taken 4339 1456: 1325: if (*line == '#' && strncmp(line, "#END OF OPTIONS", 15) == 0) 1456: 1325-block 0 branch 0 taken 24 (fallthrough) branch 1 taken 1432 24: 1325-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 24 -: 1326: break; -: 1327: 1432: 1328: else if (xargs.autocd == UNSET && *line == 'A' 1432: 1328-block 0 branch 0 taken 1432 (fallthrough) branch 1 taken 0 1432: 1328-block 1 branch 2 taken 81 (fallthrough) branch 3 taken 1351 104: 1329: && strncmp(line, "Autocd=", 7) == 0) { 81: 1329-block 0 branch 0 taken 23 (fallthrough) branch 1 taken 58 23: 1329-block 1 unconditional 2 taken 23 23: 1330: char opt_str[MAX_BOOL] = ""; 23: 1331: ret = sscanf(line, "Autocd=%5s\n", opt_str); 23*: 1332: if (ret == -1) 23: 1332-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 23 #####: 1333: continue; %%%%%: 1333-block 0 unconditional 0 never executed 23: 1334: if (strncmp(opt_str, "true", 4) == 0) 23: 1334-block 0 branch 0 taken 23 (fallthrough) branch 1 taken 0 23: 1335: autocd = 1; 23: 1335-block 0 unconditional 0 taken 23 #####: 1336: else if (strncmp(opt_str, "false", 5) == 0) %%%%%: 1336-block 0 branch 0 never executed branch 1 never executed #####: 1337: autocd = 0; %%%%%: 1337-block 0 unconditional 0 never executed -: 1338: } -: 1339: 1409: 1340: else if (xargs.autojump == UNSET && *line == 'A' 1409: 1340-block 0 branch 0 taken 1409 (fallthrough) branch 1 taken 0 1409: 1340-block 1 branch 2 taken 58 (fallthrough) branch 3 taken 1351 75: 1341: && strncmp(line, "AutoJump=", 9) == 0) { 58: 1341-block 0 branch 0 taken 17 (fallthrough) branch 1 taken 41 17: 1341-block 1 unconditional 2 taken 17 17: 1342: char opt_str[MAX_BOOL] = ""; 17: 1343: ret = sscanf(line, "AutoJump=%5s\n", opt_str); 17*: 1344: if (ret == -1) 17: 1344-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 17 #####: 1345: continue; %%%%%: 1345-block 0 unconditional 0 never executed 17: 1346: if (strncmp(opt_str, "true", 4) == 0) 17: 1346-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 17 #####: 1347: autojump = autocd = 1; %%%%%: 1347-block 0 unconditional 0 never executed 17: 1348: else if (strncmp(opt_str, "false", 5) == 0) 17: 1348-block 0 branch 0 taken 17 (fallthrough) branch 1 taken 0 17: 1349: autojump = 0; 17: 1349-block 0 unconditional 0 taken 17 -: 1350: } -: 1351: 1392: 1352: else if (xargs.auto_open == UNSET && *line == 'A' 1392: 1352-block 0 branch 0 taken 1392 (fallthrough) branch 1 taken 0 1392: 1352-block 1 branch 2 taken 41 (fallthrough) branch 3 taken 1351 64: 1353: && strncmp(line, "AutoOpen=", 9) == 0) { 41: 1353-block 0 branch 0 taken 23 (fallthrough) branch 1 taken 18 23: 1353-block 1 unconditional 2 taken 23 23: 1354: char opt_str[MAX_BOOL] = ""; 23: 1355: ret = sscanf(line, "AutoOpen=%5s\n", opt_str); 23*: 1356: if (ret == -1) 23: 1356-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 23 #####: 1357: continue; %%%%%: 1357-block 0 unconditional 0 never executed 23: 1358: if (strncmp(opt_str, "true", 4) == 0) 23: 1358-block 0 branch 0 taken 23 (fallthrough) branch 1 taken 0 23: 1359: auto_open = 1; 23: 1359-block 0 unconditional 0 taken 23 #####: 1360: else if (strncmp(opt_str, "false", 5) == 0) %%%%%: 1360-block 0 branch 0 never executed branch 1 never executed #####: 1361: auto_open = 0; %%%%%: 1361-block 0 unconditional 0 never executed -: 1362: } -: 1363: 1369: 1364: else if (xargs.suggestions == UNSET && *line == 'A' 1369: 1364-block 0 branch 0 taken 1369 (fallthrough) branch 1 taken 0 1369: 1364-block 1 branch 2 taken 18 (fallthrough) branch 3 taken 1351 36: 1365: && strncmp(line, "AutoSuggestions=", 16) == 0) { 18: 1365-block 0 branch 0 taken 18 (fallthrough) branch 1 taken 0 18: 1365-block 1 unconditional 2 taken 18 18: 1366: char opt_str[MAX_BOOL] = ""; 18: 1367: ret = sscanf(line, "AutoSuggestions=%5s\n", opt_str); 18*: 1368: if (ret == -1) 18: 1368-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 18 #####: 1369: continue; %%%%%: 1369-block 0 unconditional 0 never executed 18: 1370: if (strncmp(opt_str, "true", 4) == 0) 18: 1370-block 0 branch 0 taken 18 (fallthrough) branch 1 taken 0 18: 1371: suggestions = 1; 18: 1371-block 0 unconditional 0 taken 18 #####: 1372: else if (strncmp(opt_str, "false", 5) == 0) %%%%%: 1372-block 0 branch 0 never executed branch 1 never executed #####: 1373: suggestions = 0; %%%%%: 1373-block 0 unconditional 0 never executed -: 1374: } -: 1375: 1351: 1376: else if (xargs.case_sens_dirjump == UNSET && *line == 'C' 1351: 1376-block 0 branch 0 taken 1351 (fallthrough) branch 1 taken 0 1351: 1376-block 1 branch 2 taken 186 (fallthrough) branch 3 taken 1165 208: 1377: && strncmp(line, "CaseSensitiveDirJump=", 21) == 0) { 186: 1377-block 0 branch 0 taken 22 (fallthrough) branch 1 taken 164 22: 1377-block 1 unconditional 2 taken 22 22: 1378: char opt_str[MAX_BOOL] = ""; 22: 1379: ret = sscanf(line, "CaseSensitiveDirJump=%5s\n", opt_str); -: 1380: 22*: 1381: if (ret == -1) 22: 1381-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 22 #####: 1382: continue; %%%%%: 1382-block 0 unconditional 0 never executed -: 1383: 22: 1384: if (strncmp(opt_str, "true", 4) == 0) 22: 1384-block 0 branch 0 taken 4 (fallthrough) branch 1 taken 18 4: 1385: case_sens_dirjump = 1; 4: 1385-block 0 unconditional 0 taken 4 18: 1386: else if (strncmp(opt_str, "false", 5) == 0) 18: 1386-block 0 branch 0 taken 18 (fallthrough) branch 1 taken 0 18: 1387: case_sens_dirjump = 0; 18: 1387-block 0 unconditional 0 taken 18 -: 1388: } -: 1389: 1329: 1390: else if (xargs.sensitive == UNSET && *line == 'C' 1329: 1390-block 0 branch 0 taken 1329 (fallthrough) branch 1 taken 0 1329: 1390-block 1 branch 2 taken 164 (fallthrough) branch 3 taken 1165 188: 1391: && strncmp(line, "CaseSensitiveList=", 18) == 0) { 164: 1391-block 0 branch 0 taken 24 (fallthrough) branch 1 taken 140 24: 1391-block 1 unconditional 2 taken 24 24: 1392: char opt_str[MAX_BOOL] = ""; 24: 1393: ret = sscanf(line, "CaseSensitiveList=%5s\n", -: 1394: opt_str); 24*: 1395: if (ret == -1) 24: 1395-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 24 #####: 1396: continue; %%%%%: 1396-block 0 unconditional 0 never executed 24: 1397: if (strncmp(opt_str, "true", 4) == 0) 24: 1397-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 24 #####: 1398: case_sensitive = 1; %%%%%: 1398-block 0 unconditional 0 never executed 24: 1399: else if (strncmp(opt_str, "false", 5) == 0) 24: 1399-block 0 branch 0 taken 24 (fallthrough) branch 1 taken 0 24: 1400: case_sensitive = 0; 24: 1400-block 0 unconditional 0 taken 24 -: 1401: } -: 1402: 1305: 1403: else if (xargs.case_sens_path_comp == UNSET && *line == 'C' 1305: 1403-block 0 branch 0 taken 1305 (fallthrough) branch 1 taken 0 1305: 1403-block 1 branch 2 taken 140 (fallthrough) branch 3 taken 1165 162: 1404: && strncmp(line, "CaseSensitivePathComp=", 22) == 0) { 140: 1404-block 0 branch 0 taken 22 (fallthrough) branch 1 taken 118 22: 1404-block 1 unconditional 2 taken 22 22: 1405: char opt_str[MAX_BOOL] = ""; 22: 1406: ret = sscanf(line, "CaseSensitivePathComp=%5s\n", opt_str); 22*: 1407: if (ret == -1) 22: 1407-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 22 #####: 1408: continue; %%%%%: 1408-block 0 unconditional 0 never executed 22: 1409: if (strncmp(opt_str, "true", 4) == 0) 22: 1409-block 0 branch 0 taken 4 (fallthrough) branch 1 taken 18 4: 1410: case_sens_path_comp = 1; 4: 1410-block 0 unconditional 0 taken 4 18: 1411: else if (strncmp(opt_str, "false", 5) == 0) 18: 1411-block 0 branch 0 taken 18 (fallthrough) branch 1 taken 0 18: 1412: case_sens_path_comp = 0; 18: 1412-block 0 unconditional 0 taken 18 -: 1413: } -: 1414: 1283: 1415: else if (xargs.cd_list_auto == UNSET && *line == 'C' 1283: 1415-block 0 branch 0 taken 1283 (fallthrough) branch 1 taken 0 1283: 1415-block 1 branch 2 taken 118 (fallthrough) branch 3 taken 1165 142: 1416: && strncmp(line, "CdListsAutomatically=", 21) == 0) { 118: 1416-block 0 branch 0 taken 24 (fallthrough) branch 1 taken 94 24: 1416-block 1 unconditional 2 taken 24 24: 1417: char opt_str[MAX_BOOL] = ""; 24: 1418: ret = sscanf(line, "CdListsAutomatically=%5s\n", -: 1419: opt_str); 24*: 1420: if (ret == -1) 24: 1420-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 24 #####: 1421: continue; %%%%%: 1421-block 0 unconditional 0 never executed 24: 1422: if (strncmp(opt_str, "true", 4) == 0) 24: 1422-block 0 branch 0 taken 24 (fallthrough) branch 1 taken 0 24: 1423: cd_lists_on_the_fly = 1; 24: 1423-block 0 unconditional 0 taken 24 #####: 1424: else if (strncmp(opt_str, "false", 5) == 0) %%%%%: 1424-block 0 branch 0 never executed branch 1 never executed #####: 1425: cd_lists_on_the_fly = 0; %%%%%: 1425-block 0 unconditional 0 never executed -: 1426: } -: 1427: 1259: 1428: else if (xargs.cd_on_quit == UNSET && *line == 'C' 1259: 1428-block 0 branch 0 taken 1259 (fallthrough) branch 1 taken 0 1259: 1428-block 1 branch 2 taken 94 (fallthrough) branch 3 taken 1165 117: 1429: && strncmp(line, "CdOnQuit=", 9) == 0) { 94: 1429-block 0 branch 0 taken 23 (fallthrough) branch 1 taken 71 23: 1429-block 1 unconditional 2 taken 23 23: 1430: char opt_str[MAX_BOOL] = ""; 23: 1431: ret = sscanf(line, "CdOnQuit=%5s\n", opt_str); 23*: 1432: if (ret == -1) 23: 1432-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 23 #####: 1433: continue; %%%%%: 1433-block 0 unconditional 0 never executed 23: 1434: if (strncmp(opt_str, "true", 4) == 0) 23: 1434-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 23 #####: 1435: cd_on_quit = 1; %%%%%: 1435-block 0 unconditional 0 never executed 23: 1436: else if (strncmp(opt_str, "false", 5) == 0) 23: 1436-block 0 branch 0 taken 23 (fallthrough) branch 1 taken 0 23: 1437: cd_on_quit = 0; 23: 1437-block 0 unconditional 0 taken 23 -: 1438: } -: 1439: 1236: 1440: else if (xargs.classify == UNSET && *line == 'C' 1236: 1440-block 0 branch 0 taken 1236 (fallthrough) branch 1 taken 0 1236: 1440-block 1 branch 2 taken 71 (fallthrough) branch 3 taken 1165 94: 1441: && strncmp(line, "Classify=", 9) == 0) { 71: 1441-block 0 branch 0 taken 23 (fallthrough) branch 1 taken 48 23: 1441-block 1 unconditional 2 taken 23 23: 1442: char opt_str[MAX_BOOL] = ""; 23: 1443: ret = sscanf(line, "Classify=%5s\n", opt_str); 23*: 1444: if (ret == -1) 23: 1444-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 23 #####: 1445: continue; %%%%%: 1445-block 0 unconditional 0 never executed 23: 1446: if (strncmp(opt_str, "true", 4) == 0) 23: 1446-block 0 branch 0 taken 23 (fallthrough) branch 1 taken 0 23: 1447: classify = 1; 23: 1447-block 0 unconditional 0 taken 23 #####: 1448: else if (strncmp(opt_str, "false", 5) == 0) %%%%%: 1448-block 0 branch 0 never executed branch 1 never executed #####: 1449: classify = 0; %%%%%: 1449-block 0 unconditional 0 never executed -: 1450: } -: 1451: 1213: 1452: else if (xargs.clear_screen == UNSET && *line == 'C' 1213: 1452-block 0 branch 0 taken 1213 (fallthrough) branch 1 taken 0 1213: 1452-block 1 branch 2 taken 48 (fallthrough) branch 3 taken 1165 72: 1453: && strncmp(line, "ClearScreen=", 12) == 0) { 48: 1453-block 0 branch 0 taken 24 (fallthrough) branch 1 taken 24 24: 1453-block 1 unconditional 2 taken 24 24: 1454: char opt_str[MAX_BOOL] = ""; 24: 1455: ret = sscanf(line, "ClearScreen=%5s\n", -: 1456: opt_str); 24*: 1457: if (ret == -1) 24: 1457-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 24 #####: 1458: continue; %%%%%: 1458-block 0 unconditional 0 never executed 24: 1459: if (strncmp(opt_str, "true", 4) == 0) 24: 1459-block 0 branch 0 taken 6 (fallthrough) branch 1 taken 18 6: 1460: clear_screen = 1; 6: 1460-block 0 unconditional 0 taken 6 18: 1461: else if (strncmp(opt_str, "false", 5) == 0) 18: 1461-block 0 branch 0 taken 18 (fallthrough) branch 1 taken 0 18: 1462: clear_screen = 0; 18: 1462-block 0 unconditional 0 taken 18 -: 1463: } -: 1464: 1189: 1465: else if (!usr_cscheme && *line == 'C' && strncmp(line, "ColorScheme=", 12) == 0) { 1189: 1465-block 0 branch 0 taken 168 (fallthrough) branch 1 taken 1021 168: 1465-block 1 branch 2 taken 24 (fallthrough) branch 3 taken 144 24: 1465-block 2 branch 4 taken 24 (fallthrough) branch 5 taken 0 24: 1466: char *opt = strchr(line, '='); 24*: 1467: if (!opt) 24: 1467-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 24 #####: 1468: continue; %%%%%: 1468-block 0 unconditional 0 never executed -: 1469: 24: 1470: size_t len = strlen(opt); 24: 1471: if (opt[len - 1] == '\n') 24: 1471-block 0 branch 0 taken 24 (fallthrough) branch 1 taken 0 24: 1472: opt[len - 1] = '\0'; 24: 1472-block 0 unconditional 0 taken 24 -: 1473: 24: 1474: if (!*(++opt)) 24: 1474-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 23 1: 1475: continue; 1: 1475-block 0 unconditional 0 taken 1 -: 1476: 23: 1477: usr_cscheme = savestring(opt, len); 23: 1477-block 0 call 0 returned 23 unconditional 1 taken 23 -: 1478: } -: 1479: 1188: 1480: else if (*line == 'c' && strncmp(line, "cpCmd=", 6) == 0) { 1165: 1480-block 0 branch 0 taken 23 (fallthrough) branch 1 taken 1142 23: 1480-block 1 branch 2 taken 23 (fallthrough) branch 3 taken 0 23: 1480-block 2 unconditional 4 taken 23 23: 1481: int opt_num = 0; 23: 1482: ret = sscanf(line, "cpCmd=%d\n", &opt_num); 23*: 1483: if (ret == -1) 23: 1483-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 23 #####: 1484: continue; %%%%%: 1484-block 0 unconditional 0 never executed 23: 1485: if (opt_num >= 0 && opt_num <= 2) 23: 1485-block 0 branch 0 taken 23 (fallthrough) branch 1 taken 0 23: 1485-block 1 branch 2 taken 23 (fallthrough) branch 3 taken 0 23: 1486: cp_cmd = opt_num; 23: 1486-block 0 unconditional 0 taken 23 -: 1487: else /* default (sort by name) */ #####: 1488: cp_cmd = DEF_CP_CMD; %%%%%: 1488-block 0 unconditional 0 never executed -: 1489: } -: 1490: 1142: 1491: else if (xargs.dirmap == UNSET && *line == 'D' 1142: 1491-block 0 branch 0 taken 1142 (fallthrough) branch 1 taken 0 1142: 1491-block 1 branch 2 taken 71 (fallthrough) branch 3 taken 1071 94: 1492: && strncmp(line, "DirhistMap=", 11) == 0) { 71: 1492-block 0 branch 0 taken 23 (fallthrough) branch 1 taken 48 23: 1492-block 1 unconditional 2 taken 23 23: 1493: char opt_str[MAX_BOOL] = ""; 23: 1494: ret = sscanf(line, "DirhistMap=%5s\n", opt_str); 23*: 1495: if (ret == -1) 23: 1495-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 23 #####: 1496: continue; %%%%%: 1496-block 0 unconditional 0 never executed 23: 1497: if (strncmp(opt_str, "true", 4) == 0) 23: 1497-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 23 #####: 1498: dirhist_map = 1; %%%%%: 1498-block 0 unconditional 0 never executed 23: 1499: else if (strncmp(opt_str, "false", 5) == 0) 23: 1499-block 0 branch 0 taken 23 (fallthrough) branch 1 taken 0 23: 1500: dirhist_map = 0; 23: 1500-block 0 unconditional 0 taken 23 -: 1501: } -: 1502: 1119: 1503: else if (xargs.disk_usage == UNSET && *line == 'D' 1119: 1503-block 0 branch 0 taken 1119 (fallthrough) branch 1 taken 0 1119: 1503-block 1 branch 2 taken 48 (fallthrough) branch 3 taken 1071 71: 1504: && strncmp(line, "DiskUsage=", 10) == 0) { 48: 1504-block 0 branch 0 taken 23 (fallthrough) branch 1 taken 25 23: 1504-block 1 unconditional 2 taken 23 23: 1505: char opt_str[MAX_BOOL] = ""; 23: 1506: ret = sscanf(line, "DiskUsage=%5s\n", opt_str); 23*: 1507: if (ret == -1) 23: 1507-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 23 #####: 1508: continue; %%%%%: 1508-block 0 unconditional 0 never executed 23: 1509: if (strncmp(opt_str, "true", 4) == 0) 23: 1509-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 23 #####: 1510: disk_usage = 1; %%%%%: 1510-block 0 unconditional 0 never executed 23: 1511: else if (strncmp(opt_str, "false", 5) == 0) 23: 1511-block 0 branch 0 taken 23 (fallthrough) branch 1 taken 0 23: 1512: disk_usage = 0; 23: 1512-block 0 unconditional 0 taken 23 -: 1513: } -: 1514: 1120: 1515: else if (*line == 'D' && strncmp(line, "DividingLineChar=", 17) == 0) { 1096: 1515-block 0 branch 0 taken 25 (fallthrough) branch 1 taken 1071 25: 1515-block 1 branch 2 taken 24 (fallthrough) branch 3 taken 1 24: 1515-block 2 unconditional 4 taken 24 24: 1516: char *opt = strchr(line, '='); 24: 1517: if (!opt || !*opt || !*(++opt)) { 24: 1517-block 0 branch 0 taken 24 (fallthrough) branch 1 taken 0 24: 1517-block 1 branch 2 taken 24 (fallthrough) branch 3 taken 0 24: 1517-block 2 branch 4 taken 0 (fallthrough) branch 5 taken 24 #####: 1518: div_line_char[0] = DEF_DIV_LINE_CHAR; #####: 1519: div_line_char[1] = '\0'; %%%%%: 1519-block 0 unconditional 0 never executed -: 1520: } else { 24: 1521: char *tmp = remove_quotes(opt); 24: 1521-block 0 call 0 returned 24 24*: 1522: xstrsncpy(div_line_char, tmp ? tmp : opt, NAME_MAX); branch 0 taken 24 (fallthrough) branch 1 taken 0 24: 1522-block 0 unconditional 2 taken 24 %%%%%: 1522-block 1 unconditional 3 never executed 24: 1522-block 2 call 4 returned 24 unconditional 5 taken 24 -: 1523: } -: 1524: } -: 1525: 1072: 1526: else if (xargs.expand_bookmarks == UNSET && *line == 'E' 1072: 1526-block 0 branch 0 taken 1072 (fallthrough) branch 1 taken 0 1072: 1526-block 1 branch 2 taken 47 (fallthrough) branch 3 taken 1025 70: 1527: && strncmp(line, "ExpandBookmarks=", 16) == 0) { 47: 1527-block 0 branch 0 taken 23 (fallthrough) branch 1 taken 24 23: 1527-block 1 unconditional 2 taken 23 23: 1528: char opt_str[MAX_BOOL] = ""; 23: 1529: ret = sscanf(line, "ExpandBookmarks=%5s\n", -: 1530: opt_str); 23*: 1531: if (ret == -1) 23: 1531-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 23 #####: 1532: continue; %%%%%: 1532-block 0 unconditional 0 never executed 23: 1533: if (strncmp(opt_str, "true", 4) == 0) 23: 1533-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 23 #####: 1534: expand_bookmarks = 1; %%%%%: 1534-block 0 unconditional 0 never executed 23: 1535: else if (strncmp(opt_str, "false", 5) == 0) 23: 1535-block 0 branch 0 taken 23 (fallthrough) branch 1 taken 0 23: 1536: expand_bookmarks = 0; 23: 1536-block 0 unconditional 0 taken 23 -: 1537: } -: 1538: 1049: 1539: else if (xargs.ext == UNSET && *line == 'E' 1049: 1539-block 0 branch 0 taken 1049 (fallthrough) branch 1 taken 0 1049: 1539-block 1 branch 2 taken 24 (fallthrough) branch 3 taken 1025 48: 1540: && strncmp(line, "ExternalCommands=", 17) == 0) { 24: 1540-block 0 branch 0 taken 24 (fallthrough) branch 1 taken 0 24: 1540-block 1 unconditional 2 taken 24 24: 1541: char opt_str[MAX_BOOL] = ""; 24: 1542: ret = sscanf(line, "ExternalCommands=%5s\n", -: 1543: opt_str); 24*: 1544: if (ret == -1) 24: 1544-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 24 #####: 1545: continue; %%%%%: 1545-block 0 unconditional 0 never executed 24: 1546: if (strncmp(opt_str, "true", 4) == 0) 24: 1546-block 0 branch 0 taken 22 (fallthrough) branch 1 taken 2 22: 1547: ext_cmd_ok = 1; 22: 1547-block 0 unconditional 0 taken 22 2: 1548: else if (strncmp(opt_str, "false", 5) == 0) 2: 1548-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 0 2: 1549: ext_cmd_ok = 0; 2: 1549-block 0 unconditional 0 taken 2 -: 1550: } -: 1551: 1025: 1552: else if (xargs.files_counter == UNSET && *line == 'F' 1025: 1552-block 0 branch 0 taken 1025 (fallthrough) branch 1 taken 0 1025: 1552-block 1 branch 2 taken 46 (fallthrough) branch 3 taken 979 69: 1553: && strncmp(line, "FilesCounter=", 13) == 0) { 46: 1553-block 0 branch 0 taken 23 (fallthrough) branch 1 taken 23 23: 1553-block 1 unconditional 2 taken 23 23: 1554: char opt_str[MAX_BOOL] = ""; 23: 1555: ret = sscanf(line, "FilesCounter=%5s\n", opt_str); 23*: 1556: if (ret == -1) 23: 1556-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 23 #####: 1557: continue; %%%%%: 1557-block 0 unconditional 0 never executed 23: 1558: if (strncmp(opt_str, "true", 4) == 0) 23: 1558-block 0 branch 0 taken 23 (fallthrough) branch 1 taken 0 23: 1559: files_counter = 1; 23: 1559-block 0 unconditional 0 taken 23 #####: 1560: else if (strncmp(opt_str, "false", 5) == 0) %%%%%: 1560-block 0 branch 0 never executed branch 1 never executed #####: 1561: files_counter = 0; %%%%%: 1561-block 0 unconditional 0 never executed -: 1562: } -: 1563: 1002*: 1564: else if (!filter && *line == 'F' && strncmp(line, "Filter=", 7) == 0) { 1002: 1564-block 0 branch 0 taken 1002 (fallthrough) branch 1 taken 0 1002: 1564-block 1 branch 2 taken 23 (fallthrough) branch 3 taken 979 23: 1564-block 2 branch 4 taken 23 (fallthrough) branch 5 taken 0 23: 1565: char *opt_str = strchr(line, '='); 23*: 1566: if (!opt_str) 23: 1566-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 23 #####: 1567: continue; %%%%%: 1567-block 0 unconditional 0 never executed 23: 1568: size_t len = strlen(opt_str); 23: 1569: if (opt_str[len - 1] == '\n') 23: 1569-block 0 branch 0 taken 23 (fallthrough) branch 1 taken 0 23: 1570: opt_str[len - 1] = '\0'; 23: 1570-block 0 unconditional 0 taken 23 -: 1571: 23: 1572: if (!*(++opt_str)) 23: 1572-block 0 branch 0 taken 23 (fallthrough) branch 1 taken 0 23: 1573: continue; 23: 1573-block 0 unconditional 0 taken 23 -: 1574: #####: 1575: if (*opt_str == '!') { %%%%%: 1575-block 0 branch 0 never executed branch 1 never executed #####: 1576: filter_rev = 1; #####: 1577: opt_str++; #####: 1578: len--; %%%%%: 1578-block 0 unconditional 0 never executed -: 1579: } else { #####: 1580: filter_rev = 0; %%%%%: 1580-block 0 unconditional 0 never executed -: 1581: } -: 1582: #####: 1583: filter = savestring(opt_str, len); %%%%%: 1583-block 0 call 0 never executed unconditional 1 never executed -: 1584: } -: 1585: -: 1586:#ifndef _NO_HIGHLIGHT 979: 1587: else if (xargs.highlight == UNSET && *line == 'S' 979: 1587-block 0 branch 0 taken 979 (fallthrough) branch 1 taken 0 979: 1587-block 1 branch 2 taken 254 (fallthrough) branch 3 taken 725 271: 1588: && strncmp(line, "SyntaxHighlighting=", 19) == 0) { 254: 1588-block 0 branch 0 taken 17 (fallthrough) branch 1 taken 237 17: 1588-block 1 unconditional 2 taken 17 17: 1589: char opt_str[MAX_BOOL] = ""; 17: 1590: ret = sscanf(line, "SyntaxHighlighting=%5s\n", opt_str); 17*: 1591: if (ret == -1) 17: 1591-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 17 #####: 1592: continue; %%%%%: 1592-block 0 unconditional 0 never executed 17: 1593: if (strncmp(opt_str, "true", 4) == 0) 17: 1593-block 0 branch 0 taken 17 (fallthrough) branch 1 taken 0 17: 1594: highlight = 1; 17: 1594-block 0 unconditional 0 taken 17 #####: 1595: else if (strncmp(opt_str, "false", 5) == 0) %%%%%: 1595-block 0 branch 0 never executed branch 1 never executed #####: 1596: highlight = 0; %%%%%: 1596-block 0 unconditional 0 never executed -: 1597: } -: 1598:#endif -: 1599: 962: 1600: else if (xargs.light == UNSET && *line == 'L' 962: 1600-block 0 branch 0 taken 962 (fallthrough) branch 1 taken 0 962: 1600-block 1 branch 2 taken 95 (fallthrough) branch 3 taken 867 118: 1601: && strncmp(line, "LightMode=", 10) == 0) { 95: 1601-block 0 branch 0 taken 23 (fallthrough) branch 1 taken 72 23: 1601-block 1 unconditional 2 taken 23 23: 1602: char opt_str[MAX_BOOL] = ""; 23: 1603: ret = sscanf(line, "LightMode=%5s\n", opt_str); 23*: 1604: if (ret == -1) 23: 1604-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 23 #####: 1605: continue; %%%%%: 1605-block 0 unconditional 0 never executed 23: 1606: if (strncmp(opt_str, "true", 4) == 0) 23: 1606-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 23 #####: 1607: light_mode = 1; %%%%%: 1607-block 0 unconditional 0 never executed 23: 1608: else if (strncmp(opt_str, "false", 5) == 0) 23: 1608-block 0 branch 0 taken 23 (fallthrough) branch 1 taken 0 23: 1609: light_mode = 0; 23: 1609-block 0 unconditional 0 taken 23 -: 1610: } -: 1611: 939: 1612: else if (xargs.ffirst == UNSET && *line == 'L' 939: 1612-block 0 branch 0 taken 939 (fallthrough) branch 1 taken 0 939: 1612-block 1 branch 2 taken 72 (fallthrough) branch 3 taken 867 96: 1613: && strncmp(line, "ListFoldersFirst=", 17) == 0) { 72: 1613-block 0 branch 0 taken 24 (fallthrough) branch 1 taken 48 24: 1613-block 1 unconditional 2 taken 24 24: 1614: char opt_str[MAX_BOOL] = ""; 24: 1615: ret = sscanf(line, "ListFoldersFirst=%5s\n", -: 1616: opt_str); 24*: 1617: if (ret == -1) 24: 1617-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 24 #####: 1618: continue; %%%%%: 1618-block 0 unconditional 0 never executed 24: 1619: if (strncmp(opt_str, "true", 4) == 0) 24: 1619-block 0 branch 0 taken 24 (fallthrough) branch 1 taken 0 24: 1620: list_folders_first = 1; 24: 1620-block 0 unconditional 0 taken 24 #####: 1621: else if (strncmp(opt_str, "false", 5) == 0) %%%%%: 1621-block 0 branch 0 never executed branch 1 never executed #####: 1622: list_folders_first = 0; %%%%%: 1622-block 0 unconditional 0 never executed -: 1623: } -: 1624: 915: 1625: else if (xargs.longview == UNSET && *line == 'L' 915: 1625-block 0 branch 0 taken 915 (fallthrough) branch 1 taken 0 915: 1625-block 1 branch 2 taken 48 (fallthrough) branch 3 taken 867 72: 1626: && strncmp(line, "LongViewMode=", 13) == 0) { 48: 1626-block 0 branch 0 taken 24 (fallthrough) branch 1 taken 24 24: 1626-block 1 unconditional 2 taken 24 24: 1627: char opt_str[MAX_BOOL] = ""; 24: 1628: ret = sscanf(line, "LongViewMode=%5s\n", -: 1629: opt_str); 24*: 1630: if (ret == -1) 24: 1630-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 24 #####: 1631: continue; %%%%%: 1631-block 0 unconditional 0 never executed 24: 1632: if (strncmp(opt_str, "true", 4) == 0) 24: 1632-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 24 #####: 1633: long_view = 1; %%%%%: 1633-block 0 unconditional 0 never executed 24: 1634: else if (strncmp(opt_str, "false", 5) == 0) 24: 1634-block 0 branch 0 taken 24 (fallthrough) branch 1 taken 0 24: 1635: long_view = 0; 24: 1635-block 0 unconditional 0 taken 24 -: 1636: } -: 1637: 891: 1638: else if (xargs.logs == UNSET && *line == 'L' 891: 1638-block 0 branch 0 taken 891 (fallthrough) branch 1 taken 0 891: 1638-block 1 branch 2 taken 24 (fallthrough) branch 3 taken 867 48: 1639: && strncmp(line, "LogCmds=", 8) == 0) { 24: 1639-block 0 branch 0 taken 24 (fallthrough) branch 1 taken 0 24: 1639-block 1 unconditional 2 taken 24 24: 1640: char opt_str[MAX_BOOL] = ""; 24: 1641: ret = sscanf(line, "LogCmds=%5s\n", opt_str); 24*: 1642: if (ret == -1) 24: 1642-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 24 #####: 1643: continue; %%%%%: 1643-block 0 unconditional 0 never executed 24: 1644: if (strncmp(opt_str, "true", 4) == 0) 24: 1644-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 24 #####: 1645: logs_enabled = 1; %%%%%: 1645-block 0 unconditional 0 never executed 24: 1646: else if (strncmp(opt_str, "false", 5) == 0) 24: 1646-block 0 branch 0 taken 24 (fallthrough) branch 1 taken 0 24: 1647: logs_enabled = 0; 24: 1647-block 0 unconditional 0 taken 24 -: 1648: } -: 1649: 867: 1650: else if (xargs.max_dirhist == UNSET && *line == 'M' 867: 1650-block 0 branch 0 taken 867 (fallthrough) branch 1 taken 0 867: 1650-block 1 branch 2 taken 182 (fallthrough) branch 3 taken 685 206: 1651: && strncmp(line, "MaxDirhist=", 11) == 0) { 182: 1651-block 0 branch 0 taken 24 (fallthrough) branch 1 taken 158 24: 1651-block 1 unconditional 2 taken 24 24: 1652: int opt_num = 0; 24: 1653: ret = sscanf(line, "MaxDirhist=%d\n", &opt_num); 24*: 1654: if (ret == -1) 24: 1654-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 24 #####: 1655: continue; %%%%%: 1655-block 0 unconditional 0 never executed 24: 1656: if (opt_num >= 0) 24: 1656-block 0 branch 0 taken 24 (fallthrough) branch 1 taken 0 24: 1657: max_dirhist = opt_num; 24: 1657-block 0 unconditional 0 taken 24 -: 1658: else /* default */ #####: 1659: max_dirhist = DEF_MAX_DIRHIST; %%%%%: 1659-block 0 unconditional 0 never executed -: 1660: } -: 1661: 843: 1662: else if (*line == 'M' && strncmp(line, "MaxHistory=", 11) == 0) { 843: 1662-block 0 branch 0 taken 158 (fallthrough) branch 1 taken 685 158: 1662-block 1 branch 2 taken 24 (fallthrough) branch 3 taken 134 24: 1663: int opt_num = 0; 24: 1664: sscanf(line, "MaxHistory=%d\n", &opt_num); 24*: 1665: if (opt_num <= 0) 24: 1665-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 24 #####: 1666: continue; %%%%%: 1666-block 0 unconditional 0 never executed 24: 1667: max_hist = opt_num; 24: 1667-block 0 unconditional 0 taken 24 -: 1668: } -: 1669: 819: 1670: else if (*line == 'M' && strncmp(line, "MaxJumpTotalRank=", 17) == 0) { 819: 1670-block 0 branch 0 taken 134 (fallthrough) branch 1 taken 685 134: 1670-block 1 branch 2 taken 22 (fallthrough) branch 3 taken 112 22: 1671: int opt_num = 0; 22: 1672: ret = sscanf(line, "MaxJumpTotalRank=%d\n", &opt_num); 22*: 1673: if (ret == -1 || opt_num < INT_MIN || opt_num > INT_MAX) 22: 1673-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 22 #####: 1674: continue; %%%%%: 1674-block 0 unconditional 0 never executed 22: 1675: max_jump_total_rank = opt_num; 22: 1675-block 0 unconditional 0 taken 22 -: 1676: } -: 1677: 797: 1678: else if (*line == 'M' && strncmp(line, "MaxLog=", 7) == 0) { 797: 1678-block 0 branch 0 taken 112 (fallthrough) branch 1 taken 685 112: 1678-block 1 branch 2 taken 24 (fallthrough) branch 3 taken 88 24: 1679: int opt_num = 0; 24: 1680: sscanf(line, "MaxLog=%d\n", &opt_num); 24*: 1681: if (opt_num <= 0) 24: 1681-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 24 #####: 1682: continue; %%%%%: 1682-block 0 unconditional 0 never executed 24: 1683: max_log = opt_num; 24: 1683-block 0 unconditional 0 taken 24 -: 1684: } -: 1685: 773: 1686: else if (xargs.max_path == UNSET && *line == 'M' 773: 1686-block 0 branch 0 taken 773 (fallthrough) branch 1 taken 0 773: 1686-block 1 branch 2 taken 88 (fallthrough) branch 3 taken 685 88: 1687: && strncmp(line, "MaxPath=", 8) == 0) { 88: 1687-block 0 branch 0 taken 24 (fallthrough) branch 1 taken 64 24: 1688: int opt_num = 0; 24: 1689: sscanf(line, "MaxPath=%d\n", &opt_num); 24*: 1690: if (opt_num <= 0) 24: 1690-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 24 #####: 1691: continue; %%%%%: 1691-block 0 unconditional 0 never executed 24: 1692: max_path = opt_num; 24: 1692-block 0 unconditional 0 taken 24 -: 1693: } -: 1694: 749: 1695: else if (*line == 'M' && strncmp(line, "MaxPrintSelfiles=", 17) == 0) { 749: 1695-block 0 branch 0 taken 64 (fallthrough) branch 1 taken 685 64: 1695-block 1 branch 2 taken 19 (fallthrough) branch 3 taken 45 19: 1696: int opt_num = 0; 19: 1697: ret = sscanf(line, "MaxPrintSelfiles=%d\n", &opt_num); 19*: 1698: if (ret == -1) 19: 1698-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 19 #####: 1699: continue; %%%%%: 1699-block 0 unconditional 0 never executed 19: 1700: max_printselfiles = opt_num; 19: 1700-block 0 unconditional 0 taken 19 -: 1701: } -: 1702: 753: 1703: else if (*line == 'M' && strncmp(line, "MinFilenameTrim=", 16) == 0) { 730: 1703-block 0 branch 0 taken 45 (fallthrough) branch 1 taken 685 45: 1703-block 1 branch 2 taken 23 (fallthrough) branch 3 taken 22 23: 1703-block 2 unconditional 4 taken 23 23: 1704: int opt_num = 0; 23: 1705: ret = sscanf(line, "MinFilenameTrim=%d\n", &opt_num); 23*: 1706: if (ret == -1) 23: 1706-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 23 #####: 1707: continue; %%%%%: 1707-block 0 unconditional 0 never executed 23: 1708: if (opt_num > 0) 23: 1708-block 0 branch 0 taken 23 (fallthrough) branch 1 taken 0 23: 1709: min_name_trim = opt_num; 23: 1709-block 0 unconditional 0 taken 23 -: 1710: else /* default */ #####: 1711: min_name_trim = DEF_MIN_NAME_TRIM; %%%%%: 1711-block 0 unconditional 0 never executed -: 1712: } -: 1713: 707: 1714: else if (*line == 'M' && strncmp(line, "MinJumpRank=", 12) == 0) { 707: 1714-block 0 branch 0 taken 22 (fallthrough) branch 1 taken 685 22: 1714-block 1 branch 2 taken 22 (fallthrough) branch 3 taken 0 22: 1715: int opt_num = 0; 22: 1716: ret = sscanf(line, "MinJumpRank=%d\n", &opt_num); 22*: 1717: if (ret == -1 || opt_num < INT_MIN || opt_num > INT_MAX) 22: 1717-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 22 #####: 1718: continue; %%%%%: 1718-block 0 unconditional 0 never executed 22: 1719: min_jump_rank = opt_num; 22: 1719-block 0 unconditional 0 taken 22 -: 1720: } -: 1721: 708: 1722: else if (*line == 'm' && strncmp(line, "mvCmd=", 6) == 0) { 685: 1722-block 0 branch 0 taken 23 (fallthrough) branch 1 taken 662 23: 1722-block 1 branch 2 taken 23 (fallthrough) branch 3 taken 0 23: 1722-block 2 unconditional 4 taken 23 23: 1723: int opt_num = 0; 23: 1724: ret = sscanf(line, "mvCmd=%d\n", &opt_num); 23*: 1725: if (ret == -1) 23: 1725-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 23 #####: 1726: continue; %%%%%: 1726-block 0 unconditional 0 never executed 23*: 1727: if (opt_num == 0 || opt_num == 1) 23: 1727-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 23 %%%%%: 1727-block 1 branch 2 never executed branch 3 never executed 23: 1728: mv_cmd = opt_num; 23: 1728-block 0 unconditional 0 taken 23 -: 1729: else /* default (sort by name) */ #####: 1730: mv_cmd = DEF_MV_CMD; %%%%%: 1730-block 0 unconditional 0 never executed -: 1731: } -: 1732: 662*: 1733: else if (!opener && *line == 'O' && strncmp(line, "Opener=", 7) == 0) { 662: 1733-block 0 branch 0 taken 662 (fallthrough) branch 1 taken 0 662: 1733-block 1 branch 2 taken 23 (fallthrough) branch 3 taken 639 23: 1733-block 2 branch 4 taken 23 (fallthrough) branch 5 taken 0 23: 1734: char *opt = strchr(line, '='); 23*: 1735: if (!opt || !*opt || !*(++opt)) 23: 1735-block 0 branch 0 taken 23 (fallthrough) branch 1 taken 0 23: 1735-block 1 branch 2 taken 23 (fallthrough) branch 3 taken 0 23: 1735-block 2 branch 4 taken 0 (fallthrough) branch 5 taken 23 #####: 1736: continue; %%%%%: 1736-block 0 unconditional 0 never executed 23: 1737: char *tmp = remove_quotes(opt); 23: 1737-block 0 call 0 returned 23 23: 1738: if (!tmp) branch 0 taken 23 (fallthrough) branch 1 taken 0 23: 1739: continue; 23: 1739-block 0 unconditional 0 taken 23 #####: 1740: opener = savestring(tmp, strlen(tmp)); %%%%%: 1740-block 0 call 0 never executed unconditional 1 never executed -: 1741: } -: 1742: 639: 1743: else if (xargs.pager == UNSET && *line == 'P' 639: 1743-block 0 branch 0 taken 639 (fallthrough) branch 1 taken 0 639: 1743-block 1 branch 2 taken 85 (fallthrough) branch 3 taken 554 109: 1744: && strncmp(line, "Pager=", 6) == 0) { 85: 1744-block 0 branch 0 taken 24 (fallthrough) branch 1 taken 61 24: 1744-block 1 unconditional 2 taken 24 24: 1745: char opt_str[MAX_BOOL] = ""; 24: 1746: ret = sscanf(line, "Pager=%5s\n", opt_str); 24*: 1747: if (ret == -1) 24: 1747-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 24 #####: 1748: continue; %%%%%: 1748-block 0 unconditional 0 never executed 24: 1749: if (strncmp(opt_str, "true", 4) == 0) 24: 1749-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 24 #####: 1750: pager = 1; %%%%%: 1750-block 0 unconditional 0 never executed 24: 1751: else if (strncmp(opt_str, "false", 5) == 0) 24: 1751-block 0 branch 0 taken 24 (fallthrough) branch 1 taken 0 24: 1752: pager = 0; 24: 1752-block 0 unconditional 0 taken 24 -: 1753: } -: 1754: 615: 1755: else if (xargs.printsel == UNSET && *line == 'P' 615: 1755-block 0 branch 0 taken 615 (fallthrough) branch 1 taken 0 615: 1755-block 1 branch 2 taken 61 (fallthrough) branch 3 taken 554 80: 1756: && strncmp(line, "PrintSelfiles=", 14) == 0) { 61: 1756-block 0 branch 0 taken 19 (fallthrough) branch 1 taken 42 19: 1756-block 1 unconditional 2 taken 19 19: 1757: char opt_str[MAX_BOOL] = ""; 19: 1758: ret = sscanf(line, "PrintSelfiles=%5s\n", opt_str); 19*: 1759: if (ret == -1) 19: 1759-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 19 #####: 1760: continue; %%%%%: 1760-block 0 unconditional 0 never executed 19: 1761: if (strncmp(opt_str, "true", 4) == 0) 19: 1761-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 19 #####: 1762: print_selfiles = 1; %%%%%: 1762-block 0 unconditional 0 never executed 19: 1763: else if (strncmp(opt_str, "false", 5) == 0) 19: 1763-block 0 branch 0 taken 19 (fallthrough) branch 1 taken 0 19: 1764: print_selfiles = 0; 19: 1764-block 0 unconditional 0 taken 19 -: 1765: } -: 1766: 596: 1767: else if (*line == 'P' && strncmp(line, "Prompt=", 7) == 0) { 596: 1767-block 0 branch 0 taken 42 (fallthrough) branch 1 taken 554 42: 1767-block 1 branch 2 taken 24 (fallthrough) branch 3 taken 18 24: 1768: if (encoded_prompt) 24: 1768-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 24 #####: 1769: free(encoded_prompt); %%%%%: 1769-block 0 unconditional 0 never executed 24: 1770: encoded_prompt = straft(line, '='); 24: 1770-block 0 call 0 returned 24 unconditional 1 taken 24 -: 1771: } -: 1772: 590: 1773: else if (*line == 'P' && strncmp(line, "PromptStyle=", 12) == 0) { 572: 1773-block 0 branch 0 taken 18 (fallthrough) branch 1 taken 554 18: 1773-block 1 branch 2 taken 18 (fallthrough) branch 3 taken 0 18: 1773-block 2 unconditional 4 taken 18 18: 1774: char opt_str[8] = ""; 18: 1775: ret = sscanf(line, "PromptStyle=%7s\n", opt_str); 18*: 1776: if (ret == -1) 18: 1776-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 18 #####: 1777: continue; %%%%%: 1777-block 0 unconditional 0 never executed 18: 1778: if (strncmp(opt_str, "default", 7) == 0) 18: 1778-block 0 branch 0 taken 18 (fallthrough) branch 1 taken 0 18: 1779: prompt_style = DEF_PROMPT_STYLE; 18: 1779-block 0 unconditional 0 taken 18 #####: 1780: else if (strncmp(opt_str, "custom", 6) == 0) %%%%%: 1780-block 0 branch 0 never executed branch 1 never executed #####: 1781: prompt_style = CUSTOM_PROMPT_STYLE; %%%%%: 1781-block 0 unconditional 0 never executed -: 1782: else #####: 1783: prompt_style = DEF_PROMPT_STYLE; %%%%%: 1783-block 0 unconditional 0 never executed -: 1784: } -: 1785: 554: 1786: else if (xargs.restore_last_path == UNSET && *line == 'R' 554: 1786-block 0 branch 0 taken 554 (fallthrough) branch 1 taken 0 554: 1786-block 1 branch 2 taken 47 (fallthrough) branch 3 taken 507 71: 1787: && strncmp(line, "RestoreLastPath=", 16) == 0) { 47: 1787-block 0 branch 0 taken 24 (fallthrough) branch 1 taken 23 24: 1787-block 1 unconditional 2 taken 24 24: 1788: char opt_str[MAX_BOOL] = ""; 24: 1789: ret = sscanf(line, "RestoreLastPath=%5s\n", opt_str); 24*: 1790: if (ret == -1) 24: 1790-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 24 #####: 1791: continue; %%%%%: 1791-block 0 unconditional 0 never executed 24: 1792: if (strncmp(opt_str, "true", 4) == 0) 24: 1792-block 0 branch 0 taken 19 (fallthrough) branch 1 taken 5 19: 1793: restore_last_path = 1; 19: 1793-block 0 unconditional 0 taken 19 5: 1794: else if (strncmp(opt_str, "false", 5) == 0) 5: 1794-block 0 branch 0 taken 5 (fallthrough) branch 1 taken 0 5: 1795: restore_last_path = 0; 5: 1795-block 0 unconditional 0 taken 5 -: 1796: } -: 1797: 530: 1798: else if (*line == 'R' && strncmp(line, "RlEditMode=0", 12) == 0) { 530: 1798-block 0 branch 0 taken 23 (fallthrough) branch 1 taken 507 23: 1798-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 23 #####: 1799: rl_vi_editing_mode(1, 0); %%%%%: 1799-block 0 call 0 never executed unconditional 1 never executed -: 1800: /* By default, readline uses emacs editing -: 1801: * mode */ -: 1802: } -: 1803: 530: 1804: else if (xargs.share_selbox == UNSET && *line == 'S' 530: 1804-block 0 branch 0 taken 530 (fallthrough) branch 1 taken 0 530: 1804-block 1 branch 2 taken 237 (fallthrough) branch 3 taken 293 261: 1805: && strncmp(line, "ShareSelbox=", 12) == 0) { 237: 1805-block 0 branch 0 taken 24 (fallthrough) branch 1 taken 213 24: 1805-block 1 unconditional 2 taken 24 24: 1806: char opt_str[MAX_BOOL] = ""; 24: 1807: ret = sscanf(line, "ShareSelbox=%5s\n", opt_str); 24*: 1808: if (ret == -1) 24: 1808-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 24 #####: 1809: continue; %%%%%: 1809-block 0 unconditional 0 never executed 24: 1810: if (strncmp(opt_str, "true", 4) == 0) 24: 1810-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 24 #####: 1811: share_selbox = 1; %%%%%: 1811-block 0 unconditional 0 never executed 24: 1812: else if (strncmp(opt_str, "false", 5) == 0) 24: 1812-block 0 branch 0 taken 24 (fallthrough) branch 1 taken 0 24: 1813: share_selbox = 0; 24: 1813-block 0 unconditional 0 taken 24 -: 1814: } -: 1815: 506: 1816: else if (xargs.hidden == UNSET && *line == 'S' 506: 1816-block 0 branch 0 taken 506 (fallthrough) branch 1 taken 0 506: 1816-block 1 branch 2 taken 213 (fallthrough) branch 3 taken 293 237: 1817: && strncmp(line, "ShowHiddenFiles=", 16) == 0) { 213: 1817-block 0 branch 0 taken 24 (fallthrough) branch 1 taken 189 24: 1817-block 1 unconditional 2 taken 24 24: 1818: char opt_str[MAX_BOOL] = ""; 24: 1819: ret = sscanf(line, "ShowHiddenFiles=%5s\n", -: 1820: opt_str); 24*: 1821: if (ret == -1) 24: 1821-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 24 #####: 1822: continue; %%%%%: 1822-block 0 unconditional 0 never executed 24: 1823: if (strncmp(opt_str, "true", 4) == 0) 24: 1823-block 0 branch 0 taken 19 (fallthrough) branch 1 taken 5 19: 1824: show_hidden = 1; 19: 1824-block 0 unconditional 0 taken 19 5: 1825: else if (strncmp(opt_str, "false", 5) == 0) 5: 1825-block 0 branch 0 taken 5 (fallthrough) branch 1 taken 0 5: 1826: show_hidden = 0; 5: 1826-block 0 unconditional 0 taken 5 -: 1827: } -: 1828: 505: 1829: else if (xargs.sort == UNSET && *line == 'S' && strncmp(line, "Sort=", 5) == 0) { 482: 1829-block 0 branch 0 taken 482 (fallthrough) branch 1 taken 0 482: 1829-block 1 branch 2 taken 189 (fallthrough) branch 3 taken 293 189: 1829-block 2 branch 4 taken 23 (fallthrough) branch 5 taken 166 23: 1829-block 3 unconditional 6 taken 23 23: 1830: int opt_num = 0; 23: 1831: ret = sscanf(line, "Sort=%d\n", &opt_num); 23*: 1832: if (ret == -1) 23: 1832-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 23 #####: 1833: continue; %%%%%: 1833-block 0 unconditional 0 never executed 23: 1834: if (opt_num >= 0 && opt_num <= SORT_TYPES) 23: 1834-block 0 branch 0 taken 23 (fallthrough) branch 1 taken 0 23: 1834-block 1 branch 2 taken 23 (fallthrough) branch 3 taken 0 23: 1835: sort = opt_num; 23: 1835-block 0 unconditional 0 taken 23 -: 1836: else /* default (sort by name) */ #####: 1837: sort = DEF_SORT; %%%%%: 1837-block 0 unconditional 0 never executed -: 1838: } -: 1839: 459: 1840: else if (xargs.sort_reverse == UNSET && *line == 'S' 459: 1840-block 0 branch 0 taken 459 (fallthrough) branch 1 taken 0 459: 1840-block 1 branch 2 taken 166 (fallthrough) branch 3 taken 293 189: 1841: && strncmp(line, "SortReverse=", 12) == 0) { 166: 1841-block 0 branch 0 taken 23 (fallthrough) branch 1 taken 143 23: 1841-block 1 unconditional 2 taken 23 23: 1842: char opt_str[MAX_BOOL] = ""; 23: 1843: ret = sscanf(line, "SortReverse=%5s\n", opt_str); 23*: 1844: if (ret == -1) 23: 1844-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 23 #####: 1845: continue; %%%%%: 1845-block 0 unconditional 0 never executed 23: 1846: if (strncmp(opt_str, "true", 4) == 0) 23: 1846-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 23 #####: 1847: sort_reverse = 1; %%%%%: 1847-block 0 unconditional 0 never executed 23: 1848: else if (strncmp(opt_str, "false", 5) == 0) 23: 1848-block 0 branch 0 taken 23 (fallthrough) branch 1 taken 0 23: 1849: sort_reverse = 0; 23: 1849-block 0 unconditional 0 taken 23 -: 1850: } -: 1851: -: 1852: /* Check for the xargs.splash flag. If -1, it was -: 1853: * not set via command line, so that it must be -: 1854: * set here */ 436: 1855: else if (xargs.splash == UNSET && *line == 'S' 436: 1855-block 0 branch 0 taken 436 (fallthrough) branch 1 taken 0 436: 1855-block 1 branch 2 taken 143 (fallthrough) branch 3 taken 293 167: 1856: && strncmp(line, "SplashScreen=", 13) == 0) { 143: 1856-block 0 branch 0 taken 24 (fallthrough) branch 1 taken 119 24: 1856-block 1 unconditional 2 taken 24 24: 1857: char opt_str[MAX_BOOL] = ""; 24: 1858: ret = sscanf(line, "SplashScreen=%5s\n", opt_str); -: 1859: /* According to cppcheck: "sscanf() without field -: 1860: * width limits can crash with huge input data". -: 1861: * Field width limits = %5s */ 24*: 1862: if (ret == -1) 24: 1862-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 24 #####: 1863: continue; %%%%%: 1863-block 0 unconditional 0 never executed -: 1864: 24: 1865: if (strncmp(opt_str, "true", 4) == 0) 24: 1865-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 24 #####: 1866: splash_screen = 1; %%%%%: 1866-block 0 unconditional 0 never executed 24: 1867: else if (strncmp(opt_str, "false", 5) == 0) 24: 1867-block 0 branch 0 taken 24 (fallthrough) branch 1 taken 0 24: 1868: splash_screen = 0; 24: 1868-block 0 unconditional 0 taken 24 -: 1869: } -: 1870: 412: 1871: else if (xargs.path == UNSET && cur_ws == UNSET && *line == 'S' 412: 1871-block 0 branch 0 taken 380 (fallthrough) branch 1 taken 32 380: 1871-block 1 branch 2 taken 38 (fallthrough) branch 3 taken 342 38: 1871-block 2 branch 4 taken 12 (fallthrough) branch 5 taken 26 12*: 1872: && strncmp(line, "StartingPath=", 13) == 0) { 12: 1872-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 10 %%%%%: 1872-block 1 unconditional 2 never executed 2: 1873: char *opt = strchr(line, '='); 2*: 1874: if (!opt || !*opt || !*(++opt) ) 2: 1874-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 0 2: 1874-block 1 branch 2 taken 2 (fallthrough) branch 3 taken 0 2: 1874-block 2 branch 4 taken 0 (fallthrough) branch 5 taken 2 #####: 1875: continue; %%%%%: 1875-block 0 unconditional 0 never executed -: 1876: 2: 1877: char *tmp = remove_quotes(opt); 2: 1877-block 0 call 0 returned 2 2: 1878: if (!tmp) branch 0 taken 2 (fallthrough) branch 1 taken 0 2: 1879: continue; 2: 1879-block 0 unconditional 0 taken 2 -: 1880: -: 1881: /* If starting path is not NULL, and exists, and is a -: 1882: * directory, and the user has appropriate permissions, -: 1883: * set path to starting path. If any of these conditions -: 1884: * is false, path will be set to default, that is, CWD */ #####: 1885: if (xchdir(tmp, SET_TITLE) == 0) { %%%%%: 1885-block 0 call 0 never executed branch 1 never executed branch 2 never executed #####: 1886: free(ws[cur_ws].path); #####: 1887: ws[cur_ws].path = savestring(tmp, strlen(tmp)); %%%%%: 1887-block 0 call 0 never executed unconditional 1 never executed -: 1888: } else { #####: 1889: _err('w', PRINT_PROMPT, _("%s: '%s': %s. Using the " call 0 never executed call 1 never executed unconditional 2 never executed -: 1890: "current working directory as starting path\n"), #####: 1891: PROGRAM_NAME, tmp, strerror(errno)); %%%%%: 1891-block 0 call 0 never executed -: 1892: } -: 1893: } -: 1894: -: 1895:#ifndef _NO_SUGGESTIONS 428: 1896: else if (*line == 'S' && strncmp(line, "SuggestFiletypeColor=", 21) == 0) { 410: 1896-block 0 branch 0 taken 117 (fallthrough) branch 1 taken 293 117: 1896-block 1 branch 2 taken 18 (fallthrough) branch 3 taken 99 18: 1896-block 2 unconditional 4 taken 18 18: 1897: char opt_str[MAX_BOOL] = ""; 18: 1898: ret = sscanf(line, "SuggestFiletypeColor=%5s\n", opt_str); 18*: 1899: if (ret == -1) 18: 1899-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 18 #####: 1900: continue; %%%%%: 1900-block 0 unconditional 0 never executed 18: 1901: if (strncmp(opt_str, "true", 4) == 0) 18: 1901-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 18 #####: 1902: suggest_filetype_color = 1; %%%%%: 1902-block 0 unconditional 0 never executed 18: 1903: else if (strncmp(opt_str, "false", 5) == 0) 18: 1903-block 0 branch 0 taken 18 (fallthrough) branch 1 taken 0 18: 1904: suggest_filetype_color = 0; 18: 1904-block 0 unconditional 0 taken 18 -: 1905: } -: 1906: 392: 1907: else if (*line == 'S' 392: 1907-block 0 branch 0 taken 99 (fallthrough) branch 1 taken 293 99: 1908: && strncmp(line, "SuggestionStrategy=", 19) == 0) { 99: 1908-block 0 branch 0 taken 18 (fallthrough) branch 1 taken 81 18: 1909: char opt_str[SUG_STRATS + 1] = ""; 18: 1910: ret = sscanf(line, "SuggestionStrategy=%7s\n", opt_str); 18*: 1911: if (ret == -1) 18: 1911-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 18 #####: 1912: continue; %%%%%: 1912-block 0 unconditional 0 never executed %%%%%: 1912-block 1 unconditional 1 never executed 18: 1913: int fail = 0; 18: 1914: size_t s = 0; 144: 1915: for (; opt_str[s]; s++) { 18: 1915-block 0 unconditional 0 taken 18 126: 1915-block 1 unconditional 1 taken 126 144: 1915-block 2 branch 2 taken 126 branch 3 taken 18 (fallthrough) 126: 1916: if (opt_str[s] != 'a' && opt_str[s] != 'b' 126: 1916-block 0 branch 0 taken 108 (fallthrough) branch 1 taken 18 108: 1916-block 1 branch 2 taken 90 (fallthrough) branch 3 taken 18 90: 1917: && opt_str[s] != 'c' && opt_str[s] != 'e' 90: 1917-block 0 branch 0 taken 72 (fallthrough) branch 1 taken 18 72: 1917-block 1 branch 2 taken 54 (fallthrough) branch 3 taken 18 54: 1918: && opt_str[s] != 'f' && opt_str[s] != 'h' 54: 1918-block 0 branch 0 taken 36 (fallthrough) branch 1 taken 18 36: 1918-block 1 branch 2 taken 18 (fallthrough) branch 3 taken 18 18*: 1919: && opt_str[s] != 'j' && opt_str[s] != '-') { 18: 1919-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 18 %%%%%: 1919-block 1 branch 2 never executed branch 3 never executed #####: 1920: fail = 1; #####: 1921: break; %%%%%: 1921-block 0 unconditional 0 never executed -: 1922: } -: 1923: } 18*: 1924: if (fail || s != SUG_STRATS) 18: 1924-block 0 branch 0 taken 18 (fallthrough) branch 1 taken 0 18: 1924-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 18 #####: 1925: continue; %%%%%: 1925-block 0 unconditional 0 never executed 18: 1926: suggestion_strategy = savestring(opt_str, strlen(opt_str)); 18: 1926-block 0 call 0 returned 18 unconditional 1 taken 18 -: 1927: } -: 1928:#endif /* !_NO_SUGGESTIONS */ -: 1929: 391: 1930: else if (*line == 'S' && strncmp(line, "SystemShell=", 12) == 0) { 374: 1930-block 0 branch 0 taken 81 (fallthrough) branch 1 taken 293 81: 1930-block 1 branch 2 taken 24 (fallthrough) branch 3 taken 57 17: 1930-block 2 unconditional 4 taken 17 24: 1931: free(user.shell); 24: 1932: user.shell = (char *)NULL; 24: 1933: char *opt = strchr(line, '='); 24*: 1934: if (!opt || !*opt || !*(++opt)) 24: 1934-block 0 branch 0 taken 24 (fallthrough) branch 1 taken 0 24: 1934-block 1 branch 2 taken 24 (fallthrough) branch 3 taken 0 24: 1934-block 2 branch 4 taken 0 (fallthrough) branch 5 taken 24 #####: 1935: continue; %%%%%: 1935-block 0 unconditional 0 never executed -: 1936: 24: 1937: char *tmp = remove_quotes(opt); 24: 1937-block 0 call 0 returned 24 24: 1938: if (!tmp) branch 0 taken 7 (fallthrough) branch 1 taken 17 7: 1939: continue; 7: 1939-block 0 unconditional 0 taken 7 -: 1940: 17: 1941: if (*tmp == '/') { 17: 1941-block 0 branch 0 taken 17 (fallthrough) branch 1 taken 0 17*: 1942: if (access(tmp, F_OK | X_OK) != 0) 17: 1942-block 0 call 0 returned 17 branch 1 taken 0 (fallthrough) branch 2 taken 17 #####: 1943: continue; %%%%%: 1943-block 0 unconditional 0 never executed 17: 1944: user.shell = savestring(tmp, strlen(tmp)); 17: 1944-block 0 call 0 returned 17 unconditional 1 taken 17 -: 1945: } else { #####: 1946: char *shell_path = get_cmd_path(tmp); %%%%%: 1946-block 0 call 0 never executed #####: 1947: if (!shell_path) branch 0 never executed branch 1 never executed #####: 1948: continue; %%%%%: 1948-block 0 unconditional 0 never executed -: 1949: #####: 1950: user.shell = savestring(shell_path, strlen(shell_path)); %%%%%: 1950-block 0 call 0 never executed #####: 1951: free(shell_path); unconditional 0 never executed -: 1952: } -: 1953: } -: 1954: 350: 1955: else if (*line == 'T' && strncmp(line, "TerminalCmd=", 12) == 0) { 350: 1955-block 0 branch 0 taken 70 (fallthrough) branch 1 taken 280 70: 1955-block 1 branch 2 taken 24 (fallthrough) branch 3 taken 46 24: 1956: if (term) { 24: 1956-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 24 #####: 1957: free(term); #####: 1958: term = (char *)NULL; %%%%%: 1958-block 0 unconditional 0 never executed -: 1959: } -: 1960: 24: 1961: char *opt = strchr(line, '='); 24*: 1962: if (!opt || !*opt || !*(++opt)) 24: 1962-block 0 branch 0 taken 24 (fallthrough) branch 1 taken 0 24: 1962-block 1 branch 2 taken 24 (fallthrough) branch 3 taken 0 24: 1962-block 2 branch 4 taken 0 (fallthrough) branch 5 taken 24 #####: 1963: continue; %%%%%: 1963-block 0 unconditional 0 never executed -: 1964: 24: 1965: char *tmp = remove_quotes(opt); 24: 1965-block 0 call 0 returned 24 24*: 1966: if (!tmp) branch 0 taken 0 (fallthrough) branch 1 taken 24 #####: 1967: continue; %%%%%: 1967-block 0 unconditional 0 never executed -: 1968: 24: 1969: term = savestring(tmp, strlen(tmp)); 24: 1969-block 0 call 0 returned 24 unconditional 1 taken 24 -: 1970: } -: 1971: 349: 1972: else if (xargs.tips == UNSET && *line == 'T' && strncmp(line, "Tips=", 5) == 0) { 326: 1972-block 0 branch 0 taken 326 (fallthrough) branch 1 taken 0 326: 1972-block 1 branch 2 taken 46 (fallthrough) branch 3 taken 280 46: 1972-block 2 branch 4 taken 23 (fallthrough) branch 5 taken 23 23: 1972-block 3 unconditional 6 taken 23 23: 1973: char opt_str[MAX_BOOL] = ""; 23: 1974: ret = sscanf(line, "Tips=%5s\n", opt_str); 23*: 1975: if (ret == -1) 23: 1975-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 23 #####: 1976: continue; %%%%%: 1976-block 0 unconditional 0 never executed 23: 1977: if (strncmp(opt_str, "false", 5) == 0) 23: 1977-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 23 #####: 1978: tips = 0; %%%%%: 1978-block 0 unconditional 0 never executed 23: 1979: else if (strncmp(opt_str, "true", 4) == 0) 23: 1979-block 0 branch 0 taken 23 (fallthrough) branch 1 taken 0 23: 1980: tips = 1; 23: 1980-block 0 unconditional 0 taken 23 -: 1981: } -: 1982: -: 1983:#ifndef _NO_TRASH 303: 1984: else if (xargs.trasrm == UNSET && *line == 'T' 303: 1984-block 0 branch 0 taken 303 (fallthrough) branch 1 taken 0 303: 1984-block 1 branch 2 taken 23 (fallthrough) branch 3 taken 280 46: 1985: && strncmp(line, "TrashAsRm=", 10) == 0) { 23: 1985-block 0 branch 0 taken 23 (fallthrough) branch 1 taken 0 23: 1985-block 1 unconditional 2 taken 23 23: 1986: char opt_str[MAX_BOOL] = ""; 23: 1987: ret = sscanf(line, "TrashAsRm=%5s\n", opt_str); 23*: 1988: if (ret == -1) 23: 1988-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 23 #####: 1989: continue; %%%%%: 1989-block 0 unconditional 0 never executed 23: 1990: if (strncmp(opt_str, "true", 4) == 0) 23: 1990-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 23 #####: 1991: tr_as_rm = 1; %%%%%: 1991-block 0 unconditional 0 never executed 23: 1992: else if (strncmp(opt_str, "false", 5) == 0) 23: 1992-block 0 branch 0 taken 23 (fallthrough) branch 1 taken 0 23: 1993: tr_as_rm = 0; 23: 1993-block 0 unconditional 0 taken 23 -: 1994: } -: 1995:#endif -: 1996: 280: 1997: else if (xargs.unicode == UNSET && *line == 'U' 280: 1997-block 0 branch 0 taken 280 (fallthrough) branch 1 taken 0 280: 1997-block 1 branch 2 taken 24 (fallthrough) branch 3 taken 256 48: 1998: && strncmp(line, "Unicode=", 8) == 0) { 24: 1998-block 0 branch 0 taken 24 (fallthrough) branch 1 taken 0 24: 1998-block 1 unconditional 2 taken 24 24: 1999: char opt_str[MAX_BOOL] = ""; 24: 2000: ret = sscanf(line, "Unicode=%5s\n", opt_str); 24*: 2001: if (ret == -1) 24: 2001-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 24 #####: 2002: continue; %%%%%: 2002-block 0 unconditional 0 never executed 24: 2003: if (strncmp(opt_str, "true", 4) == 0) 24: 2003-block 0 branch 0 taken 21 (fallthrough) branch 1 taken 3 21: 2004: unicode = 1; 21: 2004-block 0 unconditional 0 taken 21 3: 2005: else if (strncmp(opt_str, "false", 5) == 0) 3: 2005-block 0 branch 0 taken 3 (fallthrough) branch 1 taken 0 3: 2006: unicode = 0; 3: 2006-block 0 unconditional 0 taken 3 -: 2007: } -: 2008: 256: 2009: else if (xargs.welcome_message == UNSET && *line == 'W' 256: 2009-block 0 branch 0 taken 256 (fallthrough) branch 1 taken 0 256: 2009-block 1 branch 2 taken 41 (fallthrough) branch 3 taken 215 41: 2010: && strncmp(line, "WelcomeMessage=", 15) == 0) { 41: 2010-block 0 branch 0 taken 24 (fallthrough) branch 1 taken 17 24: 2011: char opt_str[MAX_BOOL] = ""; 24: 2012: ret = sscanf(line, "WelcomeMessage=%5s\n", -: 2013: opt_str); 24*: 2014: if (ret == -1) 24: 2014-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 24 #####: 2015: continue; %%%%%: 2015-block 0 unconditional 0 never executed 24: 2016: if (strncmp(opt_str, "true", 4) == 0) 24: 2016-block 0 branch 0 taken 24 (fallthrough) branch 1 taken 0 24: 2017: welcome_message = 1; 24: 2017-block 0 unconditional 0 taken 24 #####: 2018: else if (strncmp(opt_str, "false", 5) == 0) %%%%%: 2018-block 0 branch 0 never executed branch 1 never executed #####: 2019: welcome_message = 0; %%%%%: 2019-block 0 unconditional 0 never executed -: 2020: } -: 2021: } -: 2022: 24: 2023: close_fstream(config_fp, fd); 24: 2023-block 0 call 0 returned 24 -: 2024: 24: 2025: if (filter) { branch 0 taken 0 (fallthrough) branch 1 taken 24 #####: 2026: ret = regcomp(®ex_exp, filter, REG_NOSUB | REG_EXTENDED); %%%%%: 2026-block 0 call 0 never executed #####: 2027: if (ret != EXIT_SUCCESS) { branch 0 never executed branch 1 never executed #####: 2028: _err('w', PRINT_PROMPT, _("%s: '%s': Invalid regular " %%%%%: 2028-block 0 call 0 never executed call 1 never executed -: 2029: "expression\n"), PROGRAM_NAME, filter); #####: 2030: free(filter); #####: 2031: filter = (char *)NULL; #####: 2032: regfree(®ex_exp); call 0 never executed unconditional 1 never executed -: 2033: } -: 2034: } -: 2035: 24: 2036: return; 24: 2036-block 0 unconditional 0 taken 24 -: 2037:} -: 2038: -: 2039:/* Set up CliFM directories and config files. Load the user's -: 2040: * configuration from clifmrc */ -: 2041:void function init_config called 24 returned 100% blocks executed 75% 24: 2042:init_config(void) -: 2043:{ 24: 2044: if (xargs.stealth_mode == 1) { 24: 2044-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 24 #####: 2045: _err(0, PRINT_PROMPT, _("%s: Running in stealth mode: trash, " %%%%%: 2045-block 0 call 0 never executed call 1 never executed -: 2046: "persistent selection and directory history, just as bookmarks, " -: 2047: "logs and configuration files, are disabled.\n"), -: 2048: PROGRAM_NAME); #####: 2049: config_ok = 0; #####: 2050: return; unconditional 0 never executed -: 2051: } -: 2052: -: 2053: /* Store a pointer to the current LS_COLORS value to be used by -: 2054: * external commands */ 24: 2055: ls_colors_bk = getenv("LS_COLORS"); 24: 2055-block 0 call 0 returned 24 -: 2056: 24: 2057: if (!home_ok) branch 0 taken 0 (fallthrough) branch 1 taken 24 #####: 2058: return; %%%%%: 2058-block 0 unconditional 0 never executed -: 2059: 24: 2060: define_config_file_names(); 24: 2060-block 0 call 0 returned 24 24: 2061: create_config_files(); call 0 returned 24 -: 2062: 24: 2063: if (config_ok) branch 0 taken 24 (fallthrough) branch 1 taken 0 24: 2064: read_config(); 24: 2064-block 0 call 0 returned 24 unconditional 1 taken 24 -: 2065: 24: 2066: if ((flags & GUI) && getenv("XTERM_VERSION")) { 24: 2066-block 0 branch 0 taken 24 (fallthrough) branch 1 taken 0 24: 2066-block 1 call 2 returned 24 branch 3 taken 23 (fallthrough) branch 4 taken 1 -: 2067: /* If running Xterm, instruct it to send an escape code (27) -: 2068: * for Meta (Alt) key sequences. Otherwise, Alt keybindings won't -: 2069: * work */ 23: 2070: printf("\x1b[?1036h"); /* metaSendsEscape = true */ 23: 2070-block 0 call 0 returned 23 unconditional 1 taken 23 -: 2071:/* printf("\x1b[?1034l"); // eightBitInput = false -: 2072: printf("\x1b[>1;1m"); // modifyCursorKeys = 1 -: 2073: printf("\x1b[>2;1m"); // modifyFunctionKeys = 1 -: 2074: ("\x1b[>1m" and "\x1b[>2m", reset to initial value) */ -: 2075: } -: 2076:} -: 2077: -: 2078:static void function reset_variables called 20 returned 100% blocks executed 67% 20: 2079:reset_variables(void) -: 2080:{ -: 2081: /* Free everything */ 20: 2082: free(config_dir_gral); 20: 2083: free(config_dir); 20: 2084: config_dir = config_dir_gral = (char *)NULL; -: 2085: -: 2086:#ifndef _NO_TRASH 20: 2087: free(trash_dir); 20: 2088: free(trash_files_dir); 20: 2089: free(trash_info_dir); 20: 2090: trash_dir = trash_files_dir = trash_info_dir = (char *)NULL; -: 2091:#endif -: 2092: 20: 2093: free(bm_file); 20: 2094: free(log_file); 20: 2095: free(hist_file); 20: 2096: free(dirhist_file); 20: 2097: bm_file = log_file = hist_file = dirhist_file = (char *)NULL; -: 2098: 20: 2099: free(config_file); 20: 2100: free(profile_file); 20: 2101: free(msg_log_file); 20: 2102: config_file = profile_file = msg_log_file = (char *)NULL; -: 2103: 20: 2104: free(mime_file); 20: 2105: free(plugins_dir); 20: 2106: free(actions_file); 20: 2107: free(kbinds_file); 20: 2108: mime_file = plugins_dir = actions_file = kbinds_file = (char *)NULL; -: 2109: 20: 2110: free(colors_dir); 20: 2111: free(tmp_dir); 20: 2112: free(sel_file); 20: 2113: free(remotes_file); 20: 2114: tmp_dir = colors_dir = sel_file = remotes_file = (char *)NULL; -: 2115: -: 2116:#ifndef _NO_SUGGESTIONS 20: 2117: free(suggestion_buf); 20: 2118: suggestion_buf = (char *)NULL; -: 2119: 20: 2120: free(suggestion_strategy); 20: 2121: suggestion_strategy = (char *)NULL; -: 2122:#endif -: 2123: 20: 2124: free_remotes(0); 20: 2124-block 0 call 0 returned 20 -: 2125: 20: 2126: if (filter) { branch 0 taken 0 (fallthrough) branch 1 taken 20 #####: 2127: regfree(®ex_exp); %%%%%: 2127-block 0 call 0 never executed #####: 2128: free(filter); #####: 2129: filter = (char *)NULL; unconditional 0 never executed -: 2130: } -: 2131: 20: 2132: free(opener); 20: 2133: opener = (char *)NULL; -: 2134: 20: 2135: free(encoded_prompt); 20: 2136: encoded_prompt = (char *)NULL; -: 2137: 20: 2138: free(term); 20: 2139: term = (char *)NULL; -: 2140: 20: 2141: free(user.shell); 20: 2142: user.shell = (char *)NULL; -: 2143: -: 2144: /* Reset all variables */ 20: 2145: auto_open = UNSET; 20: 2146: autocd = UNSET; 20: 2147: autojump = UNSET; 20: 2148: case_sens_dirjump = UNSET; 20: 2149: case_sens_path_comp = UNSET; 20: 2150: case_sensitive = UNSET; 20: 2151: cd_lists_on_the_fly = UNSET; 20: 2152: cd_on_quit = UNSET; 20: 2153: check_cap = UNSET; 20: 2154: check_ext = UNSET; 20: 2155: classify = UNSET; 20: 2156: clear_screen = UNSET; 20: 2157: columned = UNSET; 20: 2158: dirhist_map = UNSET; 20: 2159: disk_usage = UNSET; 20: 2160: ext_cmd_ok = UNSET; 20: 2161: files_counter = UNSET; 20: 2162: follow_symlinks = UNSET; -: 2163:#ifndef _NO_HIGHLIGHT 20: 2164: highlight = UNSET; -: 2165:#endif 20: 2166: light_mode = UNSET; 20: 2167: list_folders_first = UNSET; 20: 2168: logs_enabled = UNSET; 20: 2169: long_view = UNSET; 20: 2170: max_jump_total_rank = UNSET; 20: 2171: max_printselfiles = UNSET; 20: 2172: min_name_trim = UNSET; 20: 2173: min_jump_rank = UNSET; 20: 2174: no_eln = UNSET; 20: 2175: pager = UNSET; 20: 2176: print_selfiles = UNSET; 20: 2177: prompt_style = UNSET; 20: 2178: restore_last_path = UNSET; 20: 2179: share_selbox = UNSET; 20: 2180: show_hidden = UNSET; 20: 2181: sort = UNSET; 20: 2182: splash_screen = UNSET; 20: 2183: tips = UNSET; 20: 2184: unicode = UNSET; 20: 2185: welcome_message = UNSET; -: 2186: -: 2187:#ifndef _NO_SUGGESTIONS 20: 2188: suggestions = suggest_filetype_color = UNSET; -: 2189:#endif -: 2190: -: 2191:#ifndef _NO_TRASH 20: 2192: tr_as_rm = UNSET; 20: 2193: trash_ok = 1; -: 2194:#endif -: 2195: 20: 2196: dequoted = 0; 20: 2197: internal_cmd = 0; 20: 2198: is_sel = 0; 20: 2199: kbind_busy = 0; 20: 2200: mime_match = 0; 20: 2201: no_log = 0; 20: 2202: print_msg = 0; 20: 2203: recur_perm_error_flag = 0; 20: 2204: sel_is_last = 0; 20: 2205: shell_is_interactive = 0; 20: 2206: shell_terminal = 0; 20: 2207: sort_reverse = 0; 20: 2208: sort_switch = 0; -: 2209: 20: 2210: config_ok = 1; 20: 2211: home_ok = 1; 20: 2212: selfile_ok = 1; -: 2213: 20: 2214: pmsg = NOMSG; -: 2215: 20: 2216: return; 20: 2216-block 0 unconditional 0 taken 20 -: 2217:} -: 2218: -: 2219:static void function check_cmd_line_options called 20 returned 100% blocks executed 51% 20: 2220:check_cmd_line_options(void) -: 2221:{ -: 2222:#ifndef _NO_SUGGESTIONS 20: 2223: if (xargs.suggestions != UNSET) 20: 2223-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 20 #####: 2224: suggestions = xargs.suggestions; %%%%%: 2224-block 0 unconditional 0 never executed -: 2225:#endif -: 2226: -: 2227:#ifndef _NO_TRASH 20: 2228: if (xargs.trasrm != UNSET) 20: 2228-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 20 #####: 2229: tr_as_rm = xargs.trasrm; %%%%%: 2229-block 0 unconditional 0 never executed -: 2230:#endif -: 2231: -: 2232:#ifndef _NO_ICONS 20: 2233: if (xargs.icons != UNSET) 20: 2233-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 20 #####: 2234: icons = xargs.icons; %%%%%: 2234-block 0 unconditional 0 never executed -: 2235:#endif -: 2236: 20: 2237: if (xargs.auto_open != UNSET) 20: 2237-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 20 #####: 2238: auto_open = xargs.auto_open; %%%%%: 2238-block 0 unconditional 0 never executed -: 2239: 20: 2240: if (xargs.autocd != UNSET) 20: 2240-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 20 #####: 2241: autocd = xargs.autocd; %%%%%: 2241-block 0 unconditional 0 never executed -: 2242: 20: 2243: if (xargs.autojump != UNSET) 20: 2243-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 20 #####: 2244: autojump = xargs.autojump; %%%%%: 2244-block 0 unconditional 0 never executed 20: 2245: if (autojump) 20: 2245-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 20 #####: 2246: autocd = 1; %%%%%: 2246-block 0 unconditional 0 never executed -: 2247: 20: 2248: if (xargs.case_sens_dirjump != UNSET) 20: 2248-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 20 #####: 2249: case_sens_dirjump = xargs.case_sens_dirjump; %%%%%: 2249-block 0 unconditional 0 never executed -: 2250: 20: 2251: if (xargs.case_sens_path_comp != UNSET) 20: 2251-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 20 #####: 2252: case_sens_path_comp = xargs.case_sens_path_comp; %%%%%: 2252-block 0 unconditional 0 never executed -: 2253: 20: 2254: if (xargs.cd_list_auto != UNSET) 20: 2254-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 20 #####: 2255: cd_lists_on_the_fly = xargs.cd_list_auto; %%%%%: 2255-block 0 unconditional 0 never executed -: 2256: 20: 2257: if (xargs.cd_on_quit != UNSET) 20: 2257-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 20 #####: 2258: cd_on_quit = xargs.cd_on_quit; %%%%%: 2258-block 0 unconditional 0 never executed -: 2259: 20: 2260: if (xargs.classify != UNSET) 20: 2260-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 20 #####: 2261: classify = xargs.classify; %%%%%: 2261-block 0 unconditional 0 never executed -: 2262: 20: 2263: if (xargs.clear_screen != UNSET) 20: 2263-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 20 #####: 2264: clear_screen = xargs.clear_screen; %%%%%: 2264-block 0 unconditional 0 never executed -: 2265: 20: 2266: if (xargs.dirmap != UNSET) 20: 2266-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 20 #####: 2267: dirhist_map = xargs.dirmap; %%%%%: 2267-block 0 unconditional 0 never executed -: 2268: 20: 2269: if (xargs.disk_usage != UNSET) 20: 2269-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 20 #####: 2270: disk_usage = xargs.disk_usage; %%%%%: 2270-block 0 unconditional 0 never executed -: 2271: 20: 2272: if (xargs.expand_bookmarks != UNSET) 20: 2272-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 20 #####: 2273: expand_bookmarks = xargs.expand_bookmarks; %%%%%: 2273-block 0 unconditional 0 never executed -: 2274: 20: 2275: if (xargs.ext != UNSET) 20: 2275-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 20 #####: 2276: ext_cmd_ok = xargs.ext; %%%%%: 2276-block 0 unconditional 0 never executed -: 2277: 20: 2278: if (xargs.ffirst != UNSET) 20: 2278-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 20 #####: 2279: list_folders_first = xargs.ffirst; %%%%%: 2279-block 0 unconditional 0 never executed -: 2280: 20: 2281: if (xargs.files_counter != UNSET) 20: 2281-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 20 #####: 2282: files_counter = xargs.files_counter; %%%%%: 2282-block 0 unconditional 0 never executed -: 2283: 20: 2284: if (xargs.hidden != UNSET) 20: 2284-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 20 #####: 2285: show_hidden = xargs.hidden; %%%%%: 2285-block 0 unconditional 0 never executed -: 2286: 20: 2287: if (xargs.light != UNSET) 20: 2287-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 20 #####: 2288: light_mode = xargs.light; %%%%%: 2288-block 0 unconditional 0 never executed -: 2289: 20: 2290: if (xargs.logs != UNSET) 20: 2290-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 20 #####: 2291: logs_enabled = xargs.logs; %%%%%: 2291-block 0 unconditional 0 never executed -: 2292: 20: 2293: if (xargs.longview != UNSET) 20: 2293-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 20 #####: 2294: long_view = xargs.longview; %%%%%: 2294-block 0 unconditional 0 never executed -: 2295: 20: 2296: if (xargs.max_dirhist != UNSET) 20: 2296-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 20 #####: 2297: max_dirhist = xargs.max_dirhist; %%%%%: 2297-block 0 unconditional 0 never executed -: 2298: 20: 2299: if (xargs.max_path != UNSET) 20: 2299-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 20 #####: 2300: max_path = xargs.max_path; %%%%%: 2300-block 0 unconditional 0 never executed -: 2301: 20: 2302: if (xargs.no_colors != UNSET) 20: 2302-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 20 #####: 2303: colorize = xargs.no_colors; %%%%%: 2303-block 0 unconditional 0 never executed -: 2304: 20: 2305: if (xargs.no_columns != UNSET) 20: 2305-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 20 #####: 2306: columned = xargs.no_columns; %%%%%: 2306-block 0 unconditional 0 never executed -: 2307: 20: 2308: if (xargs.noeln != UNSET) 20: 2308-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 20 #####: 2309: no_eln = xargs.noeln; %%%%%: 2309-block 0 unconditional 0 never executed -: 2310: 20: 2311: if (xargs.only_dirs != UNSET) 20: 2311-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 20 #####: 2312: only_dirs = xargs.only_dirs; %%%%%: 2312-block 0 unconditional 0 never executed -: 2313: 20: 2314: if (xargs.pager != UNSET) 20: 2314-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 20 #####: 2315: pager = xargs.pager; %%%%%: 2315-block 0 unconditional 0 never executed -: 2316: 20: 2317: if (xargs.printsel != UNSET) 20: 2317-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 20 #####: 2318: print_selfiles = xargs.printsel; %%%%%: 2318-block 0 unconditional 0 never executed -: 2319: 20: 2320: if (xargs.restore_last_path != UNSET) 20: 2320-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 20 #####: 2321: restore_last_path = xargs.restore_last_path; %%%%%: 2321-block 0 unconditional 0 never executed -: 2322: 20: 2323: if (xargs.sensitive != UNSET) 20: 2323-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 20 #####: 2324: case_sensitive = xargs.sensitive; %%%%%: 2324-block 0 unconditional 0 never executed -: 2325: 20: 2326: if (xargs.share_selbox != UNSET) 20: 2326-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 20 #####: 2327: share_selbox = xargs.share_selbox; %%%%%: 2327-block 0 unconditional 0 never executed -: 2328: 20: 2329: if (xargs.sort != UNSET) 20: 2329-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 20 #####: 2330: sort = xargs.sort; %%%%%: 2330-block 0 unconditional 0 never executed -: 2331: 20: 2332: if (xargs.sort_reverse != UNSET) 20: 2332-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 20 #####: 2333: sort_reverse = xargs.sort_reverse; %%%%%: 2333-block 0 unconditional 0 never executed -: 2334: 20: 2335: if (xargs.splash != UNSET) 20: 2335-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 20 #####: 2336: splash_screen = xargs.splash; %%%%%: 2336-block 0 unconditional 0 never executed -: 2337: 20: 2338: if (xargs.tips != UNSET) 20: 2338-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 20 #####: 2339: tips = xargs.tips; %%%%%: 2339-block 0 unconditional 0 never executed -: 2340: 20: 2341: if (xargs.unicode != UNSET) 20: 2341-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 20 #####: 2342: unicode = xargs.unicode; %%%%%: 2342-block 0 unconditional 0 never executed -: 2343: 20: 2344: if (xargs.welcome_message != UNSET) 20: 2344-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 20 #####: 2345: welcome_message = xargs.welcome_message; %%%%%: 2345-block 0 unconditional 0 never executed -: 2346: 20: 2347: return; 20: 2347-block 0 unconditional 0 taken 20 -: 2348:} -: 2349: -: 2350:int function reload_config called 20 returned 100% blocks executed 97% 20: 2351:reload_config(void) -: 2352:{ 20: 2353: reset_variables(); 20: 2353-block 0 call 0 returned 20 -: 2354: -: 2355: /* Set up config files and options */ 20: 2356: init_config(); call 0 returned 20 -: 2357: -: 2358: /* If some option was not set, set it to the default value*/ 20: 2359: check_options(); call 0 returned 20 20: 2360: set_sel_file(); call 0 returned 20 20: 2361: create_tmp_files(); call 0 returned 20 20*: 2362: set_colors(usr_cscheme ? usr_cscheme : "default", 1); branch 0 taken 20 (fallthrough) branch 1 taken 0 20: 2362-block 0 unconditional 2 taken 20 %%%%%: 2362-block 1 unconditional 3 never executed 20: 2362-block 2 call 4 returned 20 20: 2363: free(usr_cscheme); 20: 2364: usr_cscheme = (char *)NULL; -: 2365: -: 2366: /* If some option was set via command line, keep that value -: 2367: * for any profile */ 20: 2368: check_cmd_line_options(); call 0 returned 20 -: 2369: -: 2370: /* Free the aliases and prompt_cmds arrays to be allocated again */ 20: 2371: int i = dirhist_total_index; 1662: 2372: while (--i >= 0) unconditional 0 taken 20 1662: 2372-block 0 branch 1 taken 1642 branch 2 taken 20 (fallthrough) 1642: 2373: free(old_pwd[i]); 1642: 2373-block 0 unconditional 0 taken 1642 -: 2374: 20: 2375: free(old_pwd); 20: 2376: old_pwd = (char **)NULL; -: 2377: 20: 2378: if (jump_db) { 20: 2378-block 0 branch 0 taken 16 (fallthrough) branch 1 taken 4 685: 2379: for (i = 0; jump_db[i].path; i++) 16: 2379-block 0 unconditional 0 taken 16 685: 2379-block 1 branch 1 taken 669 branch 2 taken 16 (fallthrough) 669: 2380: free(jump_db[i].path); 669: 2380-block 0 unconditional 0 taken 669 -: 2381: 16: 2382: free(jump_db); 16: 2383: jump_db = (struct jump_t *)NULL; 16: 2383-block 0 unconditional 0 taken 16 -: 2384: } -: 2385: 20: 2386: jump_n = 0; 20: 2387: i = (int)aliases_n; 90: 2388: while (--i >= 0) 20: 2388-block 0 unconditional 0 taken 20 90: 2388-block 1 branch 1 taken 70 branch 2 taken 20 (fallthrough) 70: 2389: free(aliases[i]); 70: 2389-block 0 unconditional 0 taken 70 -: 2390: 20: 2391: i = (int)prompt_cmds_n; 74: 2392: while (--i >= 0) 20: 2392-block 0 unconditional 0 taken 20 74: 2392-block 1 branch 1 taken 54 branch 2 taken 20 (fallthrough) 54: 2393: free(prompt_cmds[i]); 54: 2393-block 0 unconditional 0 taken 54 -: 2394: 20: 2395: aliases_n = 0; 20: 2396: dirhist_total_index = 0; 20: 2397: prompt_cmds_n = 0; -: 2398: 20: 2399: get_aliases(); 20: 2399-block 0 call 0 returned 20 20: 2400: get_prompt_cmds(); call 0 returned 20 20: 2401: load_dirhist(); call 0 returned 20 20: 2402: load_jumpdb(); call 0 returned 20 20: 2403: load_remotes(); call 0 returned 20 -: 2404: -: 2405: /* Set the current poistion of the dirhist index to the last -: 2406: * entry */ 20: 2407: dirhist_cur_index = dirhist_total_index - 1; -: 2408: 20: 2409: set_env(); call 0 returned 20 20: 2410: return EXIT_SUCCESS; unconditional 0 taken 20 -: 2411:} clifm-1.26.3/misc/codecov/exec.c.gcov000066400000000000000000004706651506632037700173320ustar00rootroot00000000000000 -: 0:Source:exec.c -: 1:/* exec.c -- functions controlling the execution of programs */ -: 2: -: 3:/* -: 4: * This file is part of CliFM -: 5: * -: 6: * Copyright (C) 2016-2021, L. Abramovich -: 7: * All rights reserved. -: 8: -: 9: * CliFM is free software; you can redistribute it and/or modify -: 10: * it under the terms of the GNU General Public License as published by -: 11: * the Free Software Foundation; either version 2 of the License, or -: 12: * (at your option) any later version. -: 13: * -: 14: * CliFM is distributed in the hope that it will be useful, -: 15: * but WITHOUT ANY WARRANTY; without even the implied warranty of -: 16: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -: 17: * GNU General Public License for more details. -: 18: * -: 19: * You should have received a copy of the GNU General Public License -: 20: * along with this program; if not, write to the Free Software -: 21: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, -: 22: * MA 02110-1301, USA. -: 23:*/ -: 24: -: 25:#include "helpers.h" -: 26:#ifdef __OpenBSD__ -: 27:#include -: 28:#endif -: 29:#include -: 30:#include -: 31:#include -: 32:#include -: 33:#include -: 34:#include -: 35:#include -: 36:#include -: 37:#include -: 38: -: 39:#include "actions.h" -: 40:#ifndef _NO_ARCHIVING -: 41:#include "archives.h" -: 42:#endif -: 43:#include "aux.h" -: 44:#include "bookmarks.h" -: 45:#include "checks.h" -: 46:#include "colors.h" -: 47:#include "config.h" -: 48:#include "exec.h" -: 49:#include "file_operations.h" -: 50:#include "history.h" -: 51:#include "init.h" -: 52:#include "jump.h" -: 53:#include "keybinds.h" -: 54:#include "listing.h" -: 55:#include "mime.h" -: 56:#include "misc.h" -: 57:#include "navigation.h" -: 58:#include "profiles.h" -: 59:#include "properties.h" -: 60:#include "readline.h" -: 61:#include "remotes.h" -: 62:#include "search.h" -: 63:#include "selection.h" -: 64:#include "sort.h" -: 65:#include "strings.h" -: 66:#ifndef _NO_TRASH -: 67:#include "trash.h" -: 68:#endif -: 69:#include "messages.h" -: 70: -: 71:char **_comm = (char **)NULL; -: 72: -: 73:/* Run a command via execle() and refresh the screen in case of success */ -: 74:int function run_and_refresh called 4 returned 100% blocks executed 58% 4: 75:run_and_refresh(char **comm) -: 76:{ 4: 77: if (!comm) 4: 77-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 4 #####: 78: return EXIT_FAILURE; %%%%%: 78-block 0 unconditional 0 never executed -: 79: 4: 80: log_function(comm); 4: 80-block 0 call 0 returned 4 -: 81: 4: 82: size_t i = 0, total_len = 0; 16: 83: for (i = 0; i <= args_n; i++) unconditional 0 taken 4 16: 83-block 0 branch 1 taken 12 branch 2 taken 4 (fallthrough) 12: 84: total_len += strlen(comm[i]); 12: 84-block 0 unconditional 0 taken 12 -: 85: 4: 86: char *tmp_cmd = (char *)NULL; 4: 87: tmp_cmd = (char *)xcalloc(total_len + (i + 1) + 1, sizeof(char)); 4: 87-block 0 call 0 returned 4 -: 88: 16: 89: for (i = 0; i <= args_n; i++) { unconditional 0 taken 4 16: 89-block 0 branch 1 taken 12 branch 2 taken 4 (fallthrough) 12: 90: strcat(tmp_cmd, comm[i]); 12: 91: strcat(tmp_cmd, " "); 12: 91-block 0 unconditional 0 taken 12 -: 92: } -: 93: 4: 94: int ret = launch_execle(tmp_cmd); 4: 94-block 0 call 0 returned 4 4: 95: free(tmp_cmd); -: 96: 4: 97: if (ret != EXIT_SUCCESS) branch 0 taken 0 (fallthrough) branch 1 taken 4 #####: 98: return EXIT_FAILURE; %%%%%: 98-block 0 unconditional 0 never executed -: 99: /* Error messages will be printed by launch_execve() itself */ -: 100: -: 101: /* If 'rm sel' and command is successful, deselect everything */ 4*: 102: if (is_sel && *comm[0] == 'r' && comm[0][1] == 'm' && (!comm[0][2] 4: 102-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 4 %%%%%: 102-block 1 branch 2 never executed branch 3 never executed %%%%%: 102-block 2 branch 4 never executed branch 5 never executed %%%%%: 102-block 3 branch 6 never executed branch 7 never executed #####: 103: || comm[0][2] == ' ')) { %%%%%: 103-block 0 branch 0 never executed branch 1 never executed #####: 104: int j = (int)sel_n; #####: 105: while (--j >= 0) %%%%%: 105-block 0 unconditional 0 never executed %%%%%: 105-block 1 branch 1 never executed branch 2 never executed #####: 106: free(sel_elements[j]); %%%%%: 106-block 0 unconditional 0 never executed #####: 107: sel_n = 0; #####: 108: save_sel(); %%%%%: 108-block 0 call 0 never executed unconditional 1 never executed -: 109: } -: 110: -: 111:#ifdef __HAIKU__ -: 112: if (cd_lists_on_the_fly && strcmp(comm[1], "--help") != 0 -: 113: && strcmp(comm[1], "--version") != 0) { -: 114: free_dirlist(); -: 115: list_dir(); -: 116: } -: 117:#endif -: 118: 4: 119: return EXIT_SUCCESS; 4: 119-block 0 unconditional 0 taken 4 -: 120:} -: 121: -: 122:static int function run_in_foreground called 118 returned 100% blocks executed 50% 118: 123:run_in_foreground(pid_t pid) -: 124:{ 118: 125: int status = 0; -: 126: -: 127: /* The parent process calls waitpid() on the child */ 118: 128: if (waitpid(pid, &status, 0) > 0) { 118: 128-block 0 call 0 returned 118 branch 1 taken 118 (fallthrough) branch 2 taken 0 118: 129: if (WIFEXITED(status) && !WEXITSTATUS(status)) { 118: 129-block 0 branch 0 taken 118 (fallthrough) branch 1 taken 0 118: 129-block 1 branch 2 taken 118 (fallthrough) branch 3 taken 0 -: 130: /* The program terminated normally and executed successfully -: 131: * (WEXITSTATUS(status) == 0) */ 118: 132: return EXIT_SUCCESS; 118: 132-block 0 unconditional 0 taken 118 #####: 133: } else if (WIFEXITED(status) && WEXITSTATUS(status)) { %%%%%: 133-block 0 branch 0 never executed branch 1 never executed %%%%%: 133-block 1 branch 2 never executed branch 3 never executed -: 134: /* Program terminated normally, but returned a -: 135: * non-zero status. Error codes should be printed by the -: 136: * program itself */ #####: 137: return WEXITSTATUS(status); %%%%%: 137-block 0 unconditional 0 never executed -: 138: } else { -: 139: /* The program didn't terminate normally. In this case too, -: 140: * error codes should be printed by the program */ #####: 141: return EXCRASHERR; %%%%%: 141-block 0 unconditional 0 never executed -: 142: } -: 143: } else { -: 144: /* waitpid() failed */ #####: 145: fprintf(stderr, "%s: waitpid: %s\n", PROGRAM_NAME, call 0 never executed #####: 146: strerror(errno)); %%%%%: 146-block 0 call 0 never executed #####: 147: return errno; unconditional 0 never executed -: 148: } -: 149: -: 150: return EXIT_FAILURE; /* Never reached */ -: 151:} -: 152: -: 153:static void function run_in_background called 5 returned 100% blocks executed 100% 5: 154:run_in_background(pid_t pid) -: 155:{ 5: 156: int status = 0; -: 157: /* Keep it in the background */ 5: 158: waitpid(pid, &status, WNOHANG); /* or: kill(pid, SIGCONT); */ 5: 158-block 0 call 0 returned 5 5: 159:} -: 160: -: 161:/* Execute a command using the system shell (/bin/sh), which takes care -: 162: * of special functions such as pipes and stream redirection, and special -: 163: * chars like wildcards, quotes, and escape sequences. Use only when the -: 164: * shell is needed; otherwise, launch_execve() should be used instead. */ -: 165:int function launch_execle called 1532 returned 100% blocks executed 44% 1532: 166:launch_execle(const char *cmd) -: 167:{ 1532: 168: if (!cmd) 1532: 168-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 1532 #####: 169: return EXNULLERR; %%%%%: 169-block 0 unconditional 0 never executed -: 170: -: 171: /* Reenable SIGCHLD, in case it was disabled. Otherwise, waitpid won't -: 172: * be able to catch error codes coming from the child */ 1532: 173: signal(SIGCHLD, SIG_DFL); 1532: 173-block 0 call 0 returned 1532 -: 174: -: 175: int status; 1532: 176: pid_t pid = fork(); call 0 returned 1532 1532: 177: if (pid < 0) { branch 0 taken 0 (fallthrough) branch 1 taken 1532 #####: 178: fprintf(stderr, "%s: fork: %s\n", PROGRAM_NAME, strerror(errno)); %%%%%: 178-block 0 call 0 never executed call 1 never executed #####: 179: return EXFORKERR; unconditional 0 never executed 1532: 180: } else if (pid == 0) { 1532: 180-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 1532 -: 181: /* Reenable signals only for the child, in case they were -: 182: * disabled for the parent */ #####: 183: signal(SIGHUP, SIG_DFL); %%%%%: 183-block 0 call 0 never executed #####: 184: signal(SIGINT, SIG_DFL); call 0 never executed #####: 185: signal(SIGQUIT, SIG_DFL); call 0 never executed #####: 186: signal(SIGTERM, SIG_DFL); call 0 never executed -: 187: -: 188: /* Get shell base name */ #####: 189: char *name = strrchr(user.shell, '/'); -: 190: #####: 191: execl(user.shell, name ? name + 1 : user.shell, "-c", cmd, NULL); branch 0 never executed branch 1 never executed %%%%%: 191-block 0 unconditional 2 never executed %%%%%: 191-block 1 unconditional 3 never executed %%%%%: 191-block 2 call 4 never executed #####: 192: fprintf(stderr, "%s: %s: execle: %s\n", PROGRAM_NAME, user.shell, call 0 never executed #####: 193: strerror(errno)); call 0 never executed #####: 194: _exit(errno); call 0 never executed -: 195: } -: 196: /* Get command status */ -: 197: else { -: 198: /* The parent process calls waitpid() on the child */ 1532: 199: if (waitpid(pid, &status, 0) > 0) { 1532: 199-block 0 call 0 returned 1532 branch 1 taken 1532 (fallthrough) branch 2 taken 0 1532: 200: if (WIFEXITED(status) && !WEXITSTATUS(status)) { 1532: 200-block 0 branch 0 taken 1532 (fallthrough) branch 1 taken 0 1532: 200-block 1 branch 2 taken 1035 (fallthrough) branch 3 taken 497 -: 201: /* The program terminated normally and executed -: 202: * successfully */ 1035: 203: return EXIT_SUCCESS; 1035: 203-block 0 unconditional 0 taken 1035 497: 204: } else if (WIFEXITED(status) && WEXITSTATUS(status)) { 497: 204-block 0 branch 0 taken 497 (fallthrough) branch 1 taken 0 497: 204-block 1 branch 2 taken 497 (fallthrough) branch 3 taken 0 -: 205: /* Either "command not found" (WEXITSTATUS(status) == 127), -: 206: * "permission denied" (not executable) (WEXITSTATUS(status) == -: 207: * 126) or the program terminated normally, but returned a -: 208: * non-zero status. These exit codes will be handled by the -: 209: * system shell itself, since we're using here execle() */ 497: 210: return WEXITSTATUS(status); 497: 210-block 0 unconditional 0 taken 497 -: 211: } else { -: 212: /* The program didn't terminate normally */ #####: 213: return EXCRASHERR; %%%%%: 213-block 0 unconditional 0 never executed -: 214: } -: 215: } else { -: 216: /* Waitpid() failed */ #####: 217: fprintf(stderr, "%s: waitpid: %s\n", PROGRAM_NAME, call 0 never executed #####: 218: strerror(errno)); %%%%%: 218-block 0 call 0 never executed #####: 219: return errno; unconditional 0 never executed -: 220: } -: 221: } -: 222: -: 223: /* Never reached */ -: 224: return EXIT_FAILURE; -: 225:} -: 226: -: 227:/* Execute a command and return the corresponding exit status. The exit -: 228: * status could be: zero, if everything went fine, or a non-zero value -: 229: * in case of error. The function takes as first arguement an array of -: 230: * strings containing the command name to be executed and its arguments -: 231: * (cmd), an integer (bg) specifying if the command should be -: 232: * backgrounded (1) or not (0), and a flag to control file descriptors */ -: 233:int function launch_execve called 123 returned 100% blocks executed 33% 123: 234:launch_execve(char **cmd, int bg, int xflags) -: 235:{ 123: 236: if (!cmd) 123: 236-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 123 #####: 237: return EXNULLERR; %%%%%: 237-block 0 unconditional 0 never executed -: 238: -: 239: /* Reenable SIGCHLD, in case it was disabled. Otherwise, waitpid -: 240: * won't be able to catch error codes coming from the child. */ 123: 241: signal(SIGCHLD, SIG_DFL); 123: 241-block 0 call 0 returned 123 -: 242: 123: 243: pid_t pid = fork(); call 0 returned 123 123: 244: if (pid < 0) { branch 0 taken 0 (fallthrough) branch 1 taken 123 #####: 245: fprintf(stderr, "%s: fork: %s\n", PROGRAM_NAME, strerror(errno)); %%%%%: 245-block 0 call 0 never executed call 1 never executed #####: 246: return errno; unconditional 0 never executed 123: 247: } else if (pid == 0) { 123: 247-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 123 #####: 248: if (!bg) { %%%%%: 248-block 0 branch 0 never executed branch 1 never executed -: 249: /* If the program runs in the foreground, reenable signals -: 250: * only for the child, in case they were disabled for the -: 251: * parent */ #####: 252: signal(SIGHUP, SIG_DFL); %%%%%: 252-block 0 call 0 never executed #####: 253: signal(SIGINT, SIG_DFL); call 0 never executed #####: 254: signal(SIGQUIT, SIG_DFL); call 0 never executed #####: 255: signal(SIGTERM, SIG_DFL); call 0 never executed unconditional 1 never executed -: 256: } -: 257: #####: 258: if (xflags) { %%%%%: 258-block 0 branch 0 never executed branch 1 never executed #####: 259: int fd = open("/dev/null", O_WRONLY, 0200); %%%%%: 259-block 0 call 0 never executed -: 260: #####: 261: if (xflags & E_NOSTDIN) branch 0 never executed branch 1 never executed #####: 262: dup2(fd, STDIN_FILENO); %%%%%: 262-block 0 call 0 never executed unconditional 1 never executed -: 263: #####: 264: if (xflags & E_NOSTDOUT) %%%%%: 264-block 0 branch 0 never executed branch 1 never executed #####: 265: dup2(fd, STDOUT_FILENO); %%%%%: 265-block 0 call 0 never executed unconditional 1 never executed -: 266: #####: 267: if (xflags & E_NOSTDERR) %%%%%: 267-block 0 branch 0 never executed branch 1 never executed #####: 268: dup2(fd, STDERR_FILENO); %%%%%: 268-block 0 call 0 never executed unconditional 1 never executed -: 269: #####: 270: close(fd); %%%%%: 270-block 0 call 0 never executed unconditional 1 never executed -: 271: } -: 272: #####: 273: execvp(cmd[0], cmd); %%%%%: 273-block 0 call 0 never executed #####: 274: fprintf(stderr, "%s: %s: %s\n", PROGRAM_NAME, cmd[0], call 0 never executed #####: 275: strerror(errno)); call 0 never executed #####: 276: _exit(errno); call 0 never executed -: 277: } -: 278: -: 279: /* Get command status (pid > 0) */ -: 280: else { 123: 281: if (bg) { 123: 281-block 0 branch 0 taken 5 (fallthrough) branch 1 taken 118 5: 282: run_in_background(pid); 5: 282-block 0 call 0 returned 5 5: 283: return EXIT_SUCCESS; unconditional 0 taken 5 -: 284: } else { 118: 285: return run_in_foreground(pid); 118: 285-block 0 call 0 returned 118 unconditional 1 taken 118 -: 286: } -: 287: } -: 288: -: 289: /* Never reached */ -: 290: return EXIT_FAILURE; -: 291:} -: 292: -: 293:/* Take the command entered by the user, already splitted into substrings -: 294: * by parse_input_str(), and call the corresponding function. Return zero -: 295: * in case of success and one in case of error */ -: 296:int function exec_cmd called 503 returned 99% blocks executed 68% 503: 297:exec_cmd(char **comm) -: 298:{ 503: 299: fputs(df_c, stdout); 503: 299-block 0 call 0 returned 503 -: 300: -: 301: /* Exit flag. exit_code is zero (sucess) by default. In case of error -: 302: * in any of the functions below, it will be set to one (failure). -: 303: * This will be the value returned by this function. Used by the \z -: 304: * escape code in the prompt to print the exit status of the last -: 305: * executed command */ 503: 306: exit_code = EXIT_SUCCESS; -: 307: 503: 308: if (*comm[0] == '#') branch 0 taken 0 (fallthrough) branch 1 taken 503 #####: 309: return exit_code; %%%%%: 309-block 0 unconditional 0 never executed -: 310: -: 311: /* ########################## -: 312: * # AUTOJUMP # -: 313: * ########################## */ -: 314: -: 315:/* if (autojump) { -: 316: exit_code = run_autojump(comm); -: 317: if (exit_code != -1) -: 318: return exit_code; -: 319: } */ -: 320: -: 321: /* Warn when using the ',' keyword and there's no pinned file */ 503: 322: int k = (int)args_n + 1; 1231: 323: while (--k >= 0) { 503: 323-block 0 unconditional 0 taken 503 1231: 323-block 1 branch 1 taken 728 branch 2 taken 503 (fallthrough) 728*: 324: if (*comm[k] == ',' && !comm[k][1]) { 728: 324-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 728 %%%%%: 324-block 1 branch 2 never executed branch 3 never executed #####: 325: fprintf(stderr, _("%s: No pinned file\n"), PROGRAM_NAME); %%%%%: 325-block 0 call 0 never executed call 1 never executed #####: 326: return (exit_code = EXIT_FAILURE); unconditional 0 never executed -: 327: } -: 328: } -: 329: -: 330: /* User defined actions */ 503: 331: if (actions_n) { 503: 331-block 0 branch 0 taken 503 (fallthrough) branch 1 taken 0 503: 332: int i = (int)actions_n; 12023: 333: while (--i >= 0) { 503: 333-block 0 unconditional 0 taken 503 12023: 333-block 1 branch 1 taken 11522 branch 2 taken 501 (fallthrough) 11522: 334: if (*comm[0] == *usr_actions[i].name 11522: 334-block 0 branch 0 taken 283 (fallthrough) branch 1 taken 11239 283: 335: && strcmp(comm[0], usr_actions[i].name) == 0) 283: 335-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 281 2: 336: return (exit_code = run_action(usr_actions[i].value, comm)); 2: 336-block 0 call 0 returned 2 unconditional 1 taken 2 -: 337: } -: 338: } -: 339: -: 340: /* User defined variables */ 501: 341: if (flags & IS_USRVAR_DEF) { 501: 341-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 501 #####: 342: flags &= ~IS_USRVAR_DEF; #####: 343: return (exit_code = create_usr_var(comm[0])); %%%%%: 343-block 0 call 0 never executed unconditional 1 never executed -: 344: } -: 345: 501: 346: if (comm[0][0] == ';' || comm[0][0] == ':') { 501: 346-block 0 branch 0 taken 499 (fallthrough) branch 1 taken 2 499: 346-block 1 branch 2 taken 1 (fallthrough) branch 3 taken 498 3: 347: if (!comm[0][1]) { 3: 347-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 1 -: 348: /* If just ":" or ";", launch the default shell */ 2: 349: char *cmd[] = {user.shell, NULL}; 2: 350: if (launch_execve(cmd, FOREGROUND, E_NOFLAG) != EXIT_SUCCESS) 2: 350-block 0 call 0 returned 2 branch 1 taken 0 (fallthrough) branch 2 taken 2 #####: 351: exit_code = EXIT_FAILURE; %%%%%: 351-block 0 unconditional 0 never executed 2: 352: return exit_code; 2: 352-block 0 unconditional 0 taken 2 1: 353: } else if (comm[0][1] == ';' || comm[0][1] == ':') { 1: 353-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 0 1: 353-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 1 -: 354: /* If double semi colon or colon (or ";:" or ":;") */ #####: 355: fprintf(stderr, _("%s: '%s': Syntax error\n"), PROGRAM_NAME, comm[0]); %%%%%: 355-block 0 call 0 never executed call 1 never executed #####: 356: return (exit_code = EXIT_FAILURE); unconditional 0 never executed -: 357: } -: 358: } -: 359: -: 360: /* ############################### -: 361: * # AUTOCD & AUTO-OPEN (1) # -: 362: * ############################### */ -: 363: 499: 364: char *deq_str = (char *)NULL; 499: 365: if (autocd || auto_open) { 499: 365-block 0 branch 0 taken 4 (fallthrough) branch 1 taken 495 4: 365-block 1 branch 2 taken 4 (fallthrough) branch 3 taken 0 -: 366: /* Expand tilde */ 499: 367: if (*comm[0] == '~') { 499: 367-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 499 #####: 368: char *exp_path = tilde_expand(comm[0]); %%%%%: 368-block 0 call 0 never executed #####: 369: if (exp_path) { branch 0 never executed branch 1 never executed #####: 370: comm[0] = (char *)xrealloc(comm[0], (strlen(exp_path) + 1) * sizeof(char)); %%%%%: 370-block 0 call 0 never executed #####: 371: strcpy(comm[0], exp_path); #####: 372: free(exp_path); unconditional 0 never executed -: 373: } -: 374: } -: 375: -: 376: /* Deescape the string (only if file name) */ 499: 377: if (strchr(comm[0], '\\')) { 499: 377-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 499 #####: 378: deq_str = dequote_str(comm[0], 0); %%%%%: 378-block 0 call 0 never executed unconditional 1 never executed -: 379:/* if (deq_str) { -: 380: if (access(deq_str, F_OK) == 0) -: 381: strcpy(comm[0], deq_str); -: 382: free(deq_str); -: 383: } */ -: 384: } -: 385: } -: 386: -: 387: /* Only autocd or auto-open here if not absolute path and if there -: 388: * is no second argument or if second argument is "&" */ 499: 389: if (*comm[0] != '/' && (autocd || auto_open) && (!comm[1] 499: 389-block 0 branch 0 taken 477 (fallthrough) branch 1 taken 22 477: 389-block 1 branch 2 taken 4 (fallthrough) branch 3 taken 473 4: 389-block 2 branch 4 taken 4 (fallthrough) branch 5 taken 0 477: 389-block 3 branch 6 taken 173 (fallthrough) branch 7 taken 304 173*: 390: || (*comm[1] == '&' && !comm[1][1]))) { 173: 390-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 173 %%%%%: 390-block 1 branch 2 never executed branch 3 never executed 304*: 391: char *tmp = deq_str ? deq_str : comm[0]; 304: 391-block 0 branch 0 taken 304 (fallthrough) branch 1 taken 0 304: 391-block 1 unconditional 2 taken 304 %%%%%: 391-block 2 unconditional 3 never executed 304: 392: size_t tmp_len = strlen(tmp); 304: 393: if (tmp[tmp_len - 1] == '/') 304: 393-block 0 branch 0 taken 15 (fallthrough) branch 1 taken 289 15: 394: tmp[tmp_len - 1] = '\0'; 15: 394-block 0 unconditional 0 taken 15 -: 395: 304: 396: if (autocd && cdpath_n && !comm[1] 304: 396-block 0 branch 0 taken 301 (fallthrough) branch 1 taken 3 301: 396-block 1 branch 2 taken 300 (fallthrough) branch 3 taken 1 300: 396-block 2 branch 4 taken 300 (fallthrough) branch 5 taken 0 300: 397: && cd_function(comm[0], CD_NO_PRINT_ERROR) == EXIT_SUCCESS) { 300: 397-block 0 call 0 returned 300 branch 1 taken 16 (fallthrough) branch 2 taken 284 16: 398: free(deq_str); 16: 399: return EXIT_SUCCESS; 16: 399-block 0 unconditional 0 taken 16 -: 400: } -: 401: 288: 402: int i = (int)files; 50965: 403: while (--i >= 0) { 288: 403-block 0 unconditional 0 taken 288 50965: 403-block 1 branch 1 taken 50689 branch 2 taken 276 (fallthrough) 50689: 404: if (*tmp != *file_info[i].name) 50689: 404-block 0 branch 0 taken 48796 (fallthrough) branch 1 taken 1893 48796: 405: continue; 48796: 405-block 0 unconditional 0 taken 48796 -: 406: 1893: 407: if (strcmp(tmp, file_info[i].name) != 0) 1893: 407-block 0 branch 0 taken 1881 (fallthrough) branch 1 taken 12 1881: 408: continue; 1881: 408-block 0 unconditional 0 taken 1881 -: 409: 12: 410: free(deq_str); 12: 411: deq_str = (char *)NULL; -: 412: 12: 413: if (autocd && (file_info[i].type == DT_DIR || file_info[i].dir == 1)) 12: 413-block 0 branch 0 taken 11 (fallthrough) branch 1 taken 1 11: 413-block 1 branch 2 taken 11 (fallthrough) branch 3 taken 0 11: 413-block 2 branch 4 taken 0 (fallthrough) branch 5 taken 11 #####: 414: return (exit_code = cd_function(comm[0], CD_PRINT_ERROR)); %%%%%: 414-block 0 call 0 never executed unconditional 1 never executed -: 415: 12: 416: if (auto_open && (file_info[i].type == DT_REG 12: 416-block 0 branch 0 taken 11 (fallthrough) branch 1 taken 1 11: 416-block 1 branch 2 taken 6 (fallthrough) branch 3 taken 5 6: 417: || file_info[i].type == DT_LNK)) { 6: 417-block 0 branch 0 taken 5 (fallthrough) branch 1 taken 1 10: 418: char *cmd[] = {"open", comm[0], -: 419: comm[1] ? comm[1] : NULL, NULL}; 10: 420: return (exit_code = open_function(cmd)); 10: 420-block 0 call 0 returned 10 unconditional 1 taken 10 -: 421: } else { -: 422: break; -: 423: } -: 424: } -: 425: } -: 426: 473: 427: free(deq_str); -: 428: -: 429: /* The more often a function is used, the more on top should it be -: 430: * in this if...else..if chain. It will be found faster this way. */ -: 431: -: 432: /* #################################################### -: 433: * # BUILTIN COMMANDS # -: 434: * ####################################################*/ -: 435: -: 436: /* ############### CD ################## */ 473: 437: if (*comm[0] == 'c' && comm[0][1] == 'd' && !comm[0][2]) { 473: 437-block 0 branch 0 taken 20 (fallthrough) branch 1 taken 453 20: 437-block 1 branch 2 taken 5 (fallthrough) branch 3 taken 15 5: 437-block 2 branch 4 taken 5 (fallthrough) branch 5 taken 0 5: 438: if (!comm[1]) 5: 438-block 0 branch 0 taken 4 (fallthrough) branch 1 taken 1 4: 439: exit_code = cd_function(NULL, CD_PRINT_ERROR); 4: 439-block 0 call 0 returned 4 unconditional 1 taken 4 1*: 440: else if (*comm[1] == '-' && strcmp(comm[1], "--help") == 0) 1: 440-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 1 %%%%%: 440-block 1 branch 2 never executed branch 3 never executed #####: 441: puts(_(CD_USAGE)); %%%%%: 441-block 0 call 0 never executed call 1 never executed unconditional 2 never executed -: 442: else 1: 443: exit_code = cd_function(comm[1], CD_PRINT_ERROR); 1: 443-block 0 call 0 returned 1 unconditional 1 taken 1 5: 444: return exit_code; 5: 444-block 0 unconditional 0 taken 5 -: 445: } -: 446: -: 447: /* ############### OPEN ################## */ 468*: 448: else if (*comm[0] == 'o' && (!comm[0][1] || strcmp(comm[0], "open") == 0)) { 468: 448-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 466 2: 448-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 2 %%%%%: 448-block 2 branch 4 never executed branch 5 never executed 2: 449: if (!comm[1]) { 2: 449-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 2 #####: 450: puts(_(OPEN_USAGE)); %%%%%: 450-block 0 call 0 never executed call 1 never executed #####: 451: exit_code = EXIT_FAILURE; unconditional 0 never executed 2*: 452: } else if (*comm[1] == '-' && strcmp(comm[1], "--help") == 0) { 2: 452-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 2 %%%%%: 452-block 1 branch 2 never executed branch 3 never executed #####: 453: puts(_(OPEN_USAGE)); %%%%%: 453-block 0 call 0 never executed call 1 never executed unconditional 2 never executed -: 454: } else { 2: 455: exit_code = open_function(comm); 2: 455-block 0 call 0 returned 2 unconditional 1 taken 2 -: 456: } 2: 457: return exit_code; 2: 457-block 0 unconditional 0 taken 2 -: 458: } -: 459: -: 460: /* ############## DIRECTORY JUMPER ################## */ 466: 461: else if (*comm[0] == 'j' && (!comm[0][1] || ((comm[0][1] == 'c' 466: 461-block 0 branch 0 taken 8 (fallthrough) branch 1 taken 458 8: 461-block 1 branch 2 taken 4 (fallthrough) branch 3 taken 4 4: 461-block 2 branch 4 taken 4 (fallthrough) branch 5 taken 0 4: 462: || comm[0][1] == 'p' || comm[0][1] == 'e' || comm[0][1] == 'o' 4: 462-block 0 branch 0 taken 3 (fallthrough) branch 1 taken 1 3: 462-block 1 branch 2 taken 2 (fallthrough) branch 3 taken 1 2: 462-block 2 branch 4 taken 2 (fallthrough) branch 5 taken 0 4: 463: || comm[0][1] == 'l') && !comm[0][2]))) 2: 463-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 0 4: 463-block 1 branch 2 taken 4 (fallthrough) branch 3 taken 0 8: 464: return (exit_code = dirjump(comm, NO_SUG_JUMP)); 8: 464-block 0 call 0 returned 8 unconditional 1 taken 8 -: 465: -: 466: /* ############### REFRESH ################## */ 458: 467: else if (*comm[0] == 'r' && ((comm[0][1] == 'f' && !comm[0][2]) 458: 467-block 0 branch 0 taken 132 (fallthrough) branch 1 taken 326 132: 467-block 1 branch 2 taken 124 (fallthrough) branch 3 taken 8 124: 467-block 2 branch 4 taken 0 (fallthrough) branch 5 taken 124 8: 468: || strcmp(comm[0], "refresh") == 0)) { 8: 468-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 8 124: 469: if (cd_lists_on_the_fly) { 124: 469-block 0 branch 0 taken 124 (fallthrough) branch 1 taken 0 124: 470: free_dirlist(); 124: 470-block 0 call 0 returned 124 124: 471: exit_code = list_dir(); call 0 returned 124 unconditional 1 taken 124 -: 472: } 124: 473: return exit_code; 124: 473-block 0 unconditional 0 taken 124 -: 474: } -: 475: -: 476: /* ############### BOOKMARKS ################## */ 334: 477: else if (*comm[0] == 'b' && ((comm[0][1] == 'm' && !comm[0][2]) 334: 477-block 0 branch 0 taken 46 (fallthrough) branch 1 taken 288 46: 477-block 1 branch 2 taken 17 (fallthrough) branch 3 taken 29 17: 477-block 2 branch 4 taken 0 (fallthrough) branch 5 taken 17 29: 478: || strcmp(comm[0], "bookmarks") == 0)) { 29: 478-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 29 17: 479: if (comm[1] && strcmp(comm[1], "--help") == 0) { 17: 479-block 0 branch 0 taken 9 (fallthrough) branch 1 taken 8 9: 479-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 9 #####: 480: puts(_(BOOKMARKS_USAGE)); %%%%%: 480-block 0 call 0 never executed call 1 never executed #####: 481: return EXIT_SUCCESS; unconditional 0 never executed -: 482: } -: 483: /* Disable keyboard shortcuts. Otherwise, the function will -: 484: * still be waiting for input while the screen have been taken -: 485: * by another function */ 17: 486: kbind_busy = 1; -: 487: /* Disable TAB completion while in Bookmarks */ 17: 488: rl_attempted_completion_function = NULL; 17: 489: exit_code = bookmarks_function(comm); 17: 489-block 0 call 0 returned 17 -: 490: /* Reenable TAB completion */ 17: 491: rl_attempted_completion_function = my_rl_completion; -: 492: /* Reenable keyboard shortcuts */ 17: 493: kbind_busy = 0; 17: 494: return exit_code; unconditional 0 taken 17 -: 495: } -: 496: -: 497: /* ############### BACK AND FORTH ################## */ 317: 498: else if (*comm[0] == 'b' && (!comm[0][1] || strcmp(comm[0], "back") == 0)) 317: 498-block 0 branch 0 taken 29 (fallthrough) branch 1 taken 288 29: 498-block 1 branch 2 taken 4 (fallthrough) branch 3 taken 25 4: 498-block 2 branch 4 taken 0 (fallthrough) branch 5 taken 4 25: 499: return (exit_code = back_function(comm)); 25: 499-block 0 call 0 returned 25 unconditional 1 taken 25 -: 500: 292: 501: else if (*comm[0] == 'f' && (!comm[0][1] || strcmp(comm[0], "forth") == 0)) 292: 501-block 0 branch 0 taken 19 (fallthrough) branch 1 taken 273 19: 501-block 1 branch 2 taken 16 (fallthrough) branch 3 taken 3 16: 501-block 2 branch 4 taken 0 (fallthrough) branch 5 taken 16 3: 502: return (exit_code = forth_function(comm)); 3: 502-block 0 call 0 returned 3 unconditional 1 taken 3 -: 503: 289: 504: else if ((*comm[0] == 'b' && comm[0][1] == 'h' && !comm[0][2]) 289: 504-block 0 branch 0 taken 4 (fallthrough) branch 1 taken 285 4: 504-block 1 branch 2 taken 1 (fallthrough) branch 3 taken 3 1: 504-block 2 branch 4 taken 0 (fallthrough) branch 5 taken 1 288*: 505: || (*comm[0] == 'f' && comm[0][1] == 'h' && !comm[0][2])) { 288: 505-block 0 branch 0 taken 16 (fallthrough) branch 1 taken 272 16: 505-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 16 %%%%%: 505-block 2 branch 4 never executed branch 5 never executed -: 506: int i; 111: 507: for (i = 0; i < dirhist_total_index; i++) { 1: 507-block 0 unconditional 0 taken 1 110: 507-block 1 unconditional 1 taken 110 111: 507-block 2 branch 2 taken 110 branch 3 taken 1 (fallthrough) 110*: 508: if (!old_pwd[i] || *old_pwd[i] == _ESC) 110: 508-block 0 branch 0 taken 110 (fallthrough) branch 1 taken 0 110: 508-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 110 #####: 509: continue; %%%%%: 509-block 0 unconditional 0 never executed 110: 510: if (i == dirhist_cur_index) 110: 510-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 109 1: 511: printf(" %d %s%s%s\n", i + 1, dh_c, old_pwd[i], df_c); 1: 511-block 0 call 0 returned 1 unconditional 1 taken 1 -: 512: else 109: 513: printf(" %d %s\n", i + 1, old_pwd[i]); 109: 513-block 0 call 0 returned 109 unconditional 1 taken 109 -: 514: } 1: 515: return EXIT_SUCCESS; 1: 515-block 0 unconditional 0 taken 1 -: 516: } -: 517: -: 518: -: 519: /* ############### NEW FILE ################## */ 288: 520: else if (*comm[0] == 'n' && (!comm[0][1] || strcmp(comm[0], "new") == 0)) 288: 520-block 0 branch 0 taken 12 (fallthrough) branch 1 taken 276 12: 520-block 1 branch 2 taken 10 (fallthrough) branch 3 taken 2 10: 520-block 2 branch 4 taken 0 (fallthrough) branch 5 taken 10 2: 521: exit_code = create_file(comm); 2: 521-block 0 call 0 returned 2 unconditional 1 taken 2 -: 522: -: 523: /* ############### DUPLICATE FILE ################## */ 286: 524: else if (*comm[0] == 'd' && (!comm[0][1] || strcmp(comm[0], "dup") == 0)) { 286: 524-block 0 branch 0 taken 13 (fallthrough) branch 1 taken 273 13: 524-block 1 branch 2 taken 11 (fallthrough) branch 3 taken 2 11: 524-block 2 branch 4 taken 0 (fallthrough) branch 5 taken 11 2*: 525: if (!comm[1] || (*comm[1] == '-' && strcmp(comm[1], "--help") == 0)) { 2: 525-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 0 2: 525-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 2 %%%%%: 525-block 2 branch 4 never executed branch 5 never executed #####: 526: puts(DUP_USAGE); %%%%%: 526-block 0 call 0 never executed #####: 527: return EXIT_SUCCESS; unconditional 0 never executed -: 528: } 2: 529: exit_code = dup_file(comm[1], comm[2] ? comm[2] : NULL); 2: 529-block 0 call 0 returned 2 unconditional 1 taken 2 -: 530: } -: 531: -: 532:#ifdef __HAIKU__ -: 533: else if ((*comm[0] == 'c' || *comm[0] == 'r' || *comm[0] == 'm' -: 534: || *comm[0] == 't' || *comm[0] == 'u' || *comm[0] == 'l') -: 535: && (strcmp(comm[0], "cp") == 0 || strcmp(comm[0], "rm") == 0 -: 536: || strcmp(comm[0], "mkdir") == 0 || strcmp(comm[0], "unlink") == 0 -: 537: || strcmp(comm[0], "touch") == 0 || strcmp(comm[0], "ln") == 0 -: 538: || strcmp(comm[0], "chmod") == 0)) -: 539: return (exit_code = run_and_refresh(comm)); -: 540:#endif -: 541: -: 542: /* ############### COPY AND MOVE ################## */ 284: 543: else if ((*comm[0] == 'c' && (!comm[0][1] || (comm[0][1] == 'p' 284: 543-block 0 branch 0 taken 15 (fallthrough) branch 1 taken 269 15: 543-block 1 branch 2 taken 12 (fallthrough) branch 3 taken 3 12: 543-block 2 branch 4 taken 0 (fallthrough) branch 5 taken 12 #####: 544: && !comm[0][2]))) %%%%%: 544-block 0 branch 0 never executed branch 1 never executed -: 545: 281: 546: || (*comm[0] == 'm' && (!comm[0][1] || (comm[0][1] == 'v' 281: 546-block 0 branch 0 taken 10 (fallthrough) branch 1 taken 271 10: 546-block 1 branch 2 taken 7 (fallthrough) branch 3 taken 3 7: 546-block 2 branch 4 taken 0 (fallthrough) branch 5 taken 7 #####: 547: && !comm[0][2]))) %%%%%: 547-block 0 branch 0 never executed branch 1 never executed -: 548: 278: 549: || (*comm[0] == 'v' && (!comm[0][1] || (comm[0][1] == 'v' 278: 549-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 277 1: 549-block 1 branch 2 taken 1 (fallthrough) branch 3 taken 0 1: 549-block 2 branch 4 taken 0 (fallthrough) branch 5 taken 1 #####: 550: && !comm[0][2]))) %%%%%: 550-block 0 branch 0 never executed branch 1 never executed -: 551: 278: 552: || (*comm[0] == 'p' && strcmp(comm[0], "paste") == 0)) { 278: 552-block 0 branch 0 taken 14 (fallthrough) branch 1 taken 264 14: 552-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 14 -: 553: 6: 554: if (((*comm[0] == 'c' || *comm[0] == 'v') && !comm[0][1]) 6: 554-block 0 branch 0 taken 3 (fallthrough) branch 1 taken 3 3: 554-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 3 3: 554-block 2 branch 4 taken 0 (fallthrough) branch 5 taken 3 3*: 555: || (*comm[0] == 'v' && comm[0][1] == 'v' && !comm[0][2]) 3: 555-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 3 %%%%%: 555-block 1 branch 2 never executed branch 3 never executed %%%%%: 555-block 2 branch 4 never executed branch 5 never executed 3: 556: || strcmp(comm[0], "paste") == 0) { 3: 556-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 3 -: 557: 3*: 558: if (comm[1] && *comm[1] == '-' && strcmp(comm[1], "--help") == 0) { 3: 558-block 0 branch 0 taken 3 (fallthrough) branch 1 taken 0 3: 558-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 3 %%%%%: 558-block 2 branch 4 never executed branch 5 never executed #####: 559: puts(_(WRAPPERS_USAGE)); %%%%%: 559-block 0 call 0 never executed call 1 never executed #####: 560: return EXIT_SUCCESS; unconditional 0 never executed -: 561: } -: 562: 3*: 563: if (*comm[0] == 'v' && comm[0][1] == 'v' && !comm[0][2]) 3: 563-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 3 %%%%%: 563-block 1 branch 2 never executed branch 3 never executed %%%%%: 563-block 2 branch 4 never executed branch 5 never executed #####: 564: copy_n_rename = 1; %%%%%: 564-block 0 unconditional 0 never executed -: 565: 3: 566: comm[0] = (char *)xrealloc(comm[0], 12 * sizeof(char)); 3: 566-block 0 call 0 returned 3 3: 567: if (!copy_n_rename) { branch 0 taken 3 (fallthrough) branch 1 taken 0 3: 568: if (cp_cmd == CP_CP) 3: 568-block 0 branch 0 taken 3 (fallthrough) branch 1 taken 0 3: 569: strcpy(comm[0], "cp -iRp"); 3: 569-block 0 unconditional 0 taken 3 #####: 570: else if (cp_cmd == CP_ADVCP) %%%%%: 570-block 0 branch 0 never executed branch 1 never executed #####: 571: strcpy(comm[0], "advcp -giRp"); %%%%%: 571-block 0 unconditional 0 never executed -: 572: else #####: 573: strcpy(comm[0], "wcp"); %%%%%: 573-block 0 unconditional 0 never executed -: 574: } else { #####: 575: strcpy(comm[0], "cp"); %%%%%: 575-block 0 unconditional 0 never executed -: 576: } 3: 577: } else if (*comm[0] == 'm' && !comm[0][1]) { 3: 577-block 0 branch 0 taken 3 (fallthrough) branch 1 taken 0 3: 577-block 1 branch 2 taken 3 (fallthrough) branch 3 taken 0 3*: 578: if (comm[1] && *comm[1] == '-' && strcmp(comm[1], "--help") == 0) { 3: 578-block 0 branch 0 taken 3 (fallthrough) branch 1 taken 0 3: 578-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 3 %%%%%: 578-block 2 branch 4 never executed branch 5 never executed #####: 579: puts(_(WRAPPERS_USAGE)); %%%%%: 579-block 0 call 0 never executed call 1 never executed #####: 580: return EXIT_SUCCESS; unconditional 0 never executed -: 581: } 3: 582: comm[0] = (char *)xrealloc(comm[0], 10 * sizeof(char)); 3: 582-block 0 call 0 returned 3 3: 583: if (mv_cmd == MV_MV) branch 0 taken 3 (fallthrough) branch 1 taken 0 3: 584: strcpy(comm[0], "mv -i"); 3: 584-block 0 unconditional 0 taken 3 -: 585: else #####: 586: strcpy(comm[0], "advmv -gi"); %%%%%: 586-block 0 unconditional 0 never executed -: 587: } -: 588: 6: 589: kbind_busy = 1; 6: 590: exit_code = copy_function(comm); 6: 590-block 0 call 0 returned 6 6: 591: kbind_busy = 0; unconditional 0 taken 6 -: 592: } -: 593: -: 594: /* ############### TRASH ################## */ 278: 595: else if (*comm[0] == 't' && (!comm[0][1] || strcmp(comm[0], "tr") == 0 278: 595-block 0 branch 0 taken 11 (fallthrough) branch 1 taken 267 11: 595-block 1 branch 2 taken 3 (fallthrough) branch 3 taken 8 3: 595-block 2 branch 4 taken 3 (fallthrough) branch 5 taken 0 3: 596: || strcmp(comm[0], "trash") == 0)) { 3: 596-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 3 -: 597:#ifndef _NO_TRASH 8*: 598: if (comm[1] && *comm[1] == '-' && strcmp(comm[1], "--help") == 0) { 8: 598-block 0 branch 0 taken 7 (fallthrough) branch 1 taken 1 7: 598-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 7 %%%%%: 598-block 2 branch 4 never executed branch 5 never executed #####: 599: puts(_(TRASH_USAGE)); %%%%%: 599-block 0 call 0 never executed call 1 never executed #####: 600: return EXIT_SUCCESS; unconditional 0 never executed -: 601: } -: 602: 8: 603: exit_code = trash_function(comm); 8: 603-block 0 call 0 returned 8 -: 604: 8: 605: if (is_sel) { /* If 'tr sel', deselect everything */ branch 0 taken 1 (fallthrough) branch 1 taken 7 1: 606: int i = (int)sel_n; 5: 607: while (--i >= 0) 1: 607-block 0 unconditional 0 taken 1 5: 607-block 1 branch 1 taken 4 branch 2 taken 1 (fallthrough) 4: 608: free(sel_elements[i]); 4: 608-block 0 unconditional 0 taken 4 1: 609: sel_n = 0; 1: 610: if (save_sel() != 0) 1: 610-block 0 call 0 returned 1 branch 1 taken 0 (fallthrough) branch 2 taken 1 #####: 611: exit_code = EXIT_FAILURE; %%%%%: 611-block 0 unconditional 0 never executed -: 612: } -: 613:#else -: 614: fprintf(stderr, _("%s: trash: %s\n"), PROGRAM_NAME, _(NOT_AVAILABLE)); -: 615: return EXIT_FAILURE; -: 616:#endif /* !_NO_TRASH */ -: 617: } -: 618: 270: 619: else if (*comm[0] == 'u' && (!comm[0][1] || strcmp(comm[0], "undel") == 0 270: 619-block 0 branch 0 taken 10 (fallthrough) branch 1 taken 260 10: 619-block 1 branch 2 taken 6 (fallthrough) branch 3 taken 4 6: 619-block 2 branch 4 taken 6 (fallthrough) branch 5 taken 0 6: 620: || strcmp(comm[0], "untrash") == 0)) { 6: 620-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 6 -: 621:#ifndef _NO_TRASH 4*: 622: if (comm[1] && *comm[1] == '-' && strcmp(comm[1], "--help") == 0) { 4: 622-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 2 2: 622-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 2 %%%%%: 622-block 2 branch 4 never executed branch 5 never executed #####: 623: puts(_(UNTRASH_USAGE)); %%%%%: 623-block 0 call 0 never executed call 1 never executed #####: 624: return EXIT_SUCCESS; unconditional 0 never executed -: 625: } -: 626: 4: 627: kbind_busy = 1; 4: 628: rl_attempted_completion_function = NULL; 4: 629: exit_code = untrash_function(comm); 4: 629-block 0 call 0 returned 4 4: 630: rl_attempted_completion_function = my_rl_completion; 4: 631: kbind_busy = 0; unconditional 0 taken 4 -: 632:#else -: 633: fprintf(stderr, _("%s: trash: %s\n"), PROGRAM_NAME, _(NOT_AVAILABLE)); -: 634: return EXIT_FAILURE; -: 635:#endif /* !_NO_TRASH */ -: 636: } -: 637: -: 638: /* ############### SELECTION ################## */ 266: 639: else if (*comm[0] == 's' && (!comm[0][1] || strcmp(comm[0], "sel") == 0)) 266: 639-block 0 branch 0 taken 29 (fallthrough) branch 1 taken 237 29: 639-block 1 branch 2 taken 19 (fallthrough) branch 3 taken 10 19: 639-block 2 branch 4 taken 3 (fallthrough) branch 5 taken 16 13: 640: return (exit_code = sel_function(comm)); 13: 640-block 0 call 0 returned 13 unconditional 1 taken 13 -: 641: 253: 642: else if (*comm[0] == 's' && (strcmp(comm[0], "sb") == 0 253: 642-block 0 branch 0 taken 16 (fallthrough) branch 1 taken 237 16: 642-block 1 branch 2 taken 15 (fallthrough) branch 3 taken 1 15: 643: || strcmp(comm[0], "selbox") == 0)) { 15: 643-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 15 1: 644: show_sel_files(); 1: 644-block 0 call 0 returned 1 1: 645: return EXIT_SUCCESS; unconditional 0 taken 1 -: 646: } -: 647: 252: 648: else if (*comm[0] == 'd' && (strcmp(comm[0], "ds") == 0 252: 648-block 0 branch 0 taken 11 (fallthrough) branch 1 taken 241 11: 648-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 11 #####: 649: || strcmp(comm[0], "desel") == 0)) { %%%%%: 649-block 0 branch 0 never executed branch 1 never executed 11*: 650: if (comm[1] && *comm[1] == '-' && strcmp(comm[1], "--help") == 0) { 11: 650-block 0 branch 0 taken 8 (fallthrough) branch 1 taken 3 8: 650-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 8 %%%%%: 650-block 2 branch 4 never executed branch 5 never executed #####: 651: puts(_(DESEL_USAGE)); %%%%%: 651-block 0 call 0 never executed call 1 never executed #####: 652: return EXIT_SUCCESS; unconditional 0 never executed -: 653: } -: 654: 11: 655: kbind_busy = 1; 11: 656: rl_attempted_completion_function = NULL; 11: 657: exit_code = deselect(comm); 11: 657-block 0 call 0 returned 11 11: 658: rl_attempted_completion_function = my_rl_completion; 11: 659: kbind_busy = 0; 11: 660: return exit_code; unconditional 0 taken 11 -: 661: } -: 662: -: 663: /* ############### SOME SHELL CMD WRAPPERS ################## */ -: 664: 241: 665: else if ((*comm[0] == 'r' || *comm[0] == 'm' || *comm[0] == 'l') 241: 665-block 0 branch 0 taken 233 (fallthrough) branch 1 taken 8 233: 665-block 1 branch 2 taken 226 (fallthrough) branch 3 taken 7 226: 665-block 2 branch 4 taken 12 (fallthrough) branch 5 taken 214 27: 666: && (strcmp(comm[0], "r") == 0 || strcmp(comm[0], "l") == 0 27: 666-block 0 branch 0 taken 23 (fallthrough) branch 1 taken 4 23: 666-block 1 branch 2 taken 22 (fallthrough) branch 3 taken 1 22: 667: || strcmp(comm[0], "md") == 0 || strcmp(comm[0], "le") == 0)) { 22: 667-block 0 branch 0 taken 22 (fallthrough) branch 1 taken 0 22: 667-block 1 branch 2 taken 2 (fallthrough) branch 3 taken 20 -: 668: /* This help is only for c, l, le, m, r, t, and md commands */ 7*: 669: if (comm[1] && *comm[1] == '-' && strcmp(comm[1], "--help") == 0) { 7: 669-block 0 branch 0 taken 7 (fallthrough) branch 1 taken 0 7: 669-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 7 %%%%%: 669-block 2 branch 4 never executed branch 5 never executed #####: 670: puts(_(WRAPPERS_USAGE)); %%%%%: 670-block 0 call 0 never executed call 1 never executed #####: 671: return EXIT_SUCCESS; unconditional 0 never executed -: 672: } -: 673: 7: 674: if (*comm[0] == 'l' && !comm[0][1]) { 7: 674-block 0 branch 0 taken 3 (fallthrough) branch 1 taken 4 3: 674-block 1 branch 2 taken 1 (fallthrough) branch 3 taken 2 1: 675: comm[0] = (char *)xrealloc(comm[0], 7 * sizeof(char)); 1: 675-block 0 call 0 returned 1 1: 676: strcpy(comm[0], "ln -sn"); -: 677: -: 678: /* Make sure the symlink source is always an absolute path */ 1: 679: if (comm[1] && *comm[1] != '/' && *comm[1] != '~') { branch 0 taken 1 (fallthrough) branch 1 taken 0 1: 679-block 0 branch 2 taken 1 (fallthrough) branch 3 taken 0 1: 679-block 1 branch 4 taken 1 (fallthrough) branch 5 taken 0 -: 680: char tmp[NAME_MAX]; 1: 681: xstrsncpy(tmp, comm[1], NAME_MAX); 1: 681-block 0 call 0 returned 1 2: 682: comm[1] = (char *)xrealloc(comm[1], (strlen(tmp) 1: 683: + strlen(ws[cur_ws].path) + 2) * sizeof(char)); call 0 returned 1 1: 684: sprintf(comm[1], "%s/%s", ws[cur_ws].path, tmp); unconditional 0 taken 1 -: 685: } 6: 686: } else if (*comm[0] == 'r' && !comm[0][1]) { 6: 686-block 0 branch 0 taken 4 (fallthrough) branch 1 taken 2 4: 686-block 1 branch 2 taken 4 (fallthrough) branch 3 taken 0 4: 687: exit_code = remove_file(comm); 4: 687-block 0 call 0 returned 4 4: 688: goto CHECK_EVENTS; unconditional 0 taken 4 2*: 689: } else if (*comm[0] == 'm' && comm[0][1] == 'd' && !comm[0][2]) { 2: 689-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 2 %%%%%: 689-block 1 branch 2 never executed branch 3 never executed %%%%%: 689-block 2 branch 4 never executed branch 5 never executed #####: 690: comm[0] = (char *)xrealloc(comm[0], 9 * sizeof(char)); %%%%%: 690-block 0 call 0 never executed #####: 691: strcpy(comm[0], "mkdir -p"); unconditional 0 never executed -: 692: } -: 693: 3: 694: if (*comm[0] == 'l' && comm[0][1] == 'e' && !comm[0][2]) { 3: 694-block 0 branch 0 taken 3 (fallthrough) branch 1 taken 0 3: 694-block 1 branch 2 taken 2 (fallthrough) branch 3 taken 1 2: 694-block 2 branch 4 taken 2 (fallthrough) branch 5 taken 0 2: 695: if (!comm[1]) { 2: 695-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 2 #####: 696: fprintf(stderr, "%s\n", _(LE_USAGE)); %%%%%: 696-block 0 call 0 never executed call 1 never executed #####: 697: return (exit_code = EXIT_FAILURE); unconditional 0 never executed -: 698: } 2: 699: exit_code = edit_link(comm[1]); 2: 699-block 0 call 0 returned 2 2: 700: goto CHECK_EVENTS; unconditional 0 taken 2 1: 701: } else if (*comm[0] == 'l' && comm[0][1] == 'n' && !comm[0][2]) { 1: 701-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 0 1: 701-block 1 branch 2 taken 1 (fallthrough) branch 3 taken 0 1: 701-block 2 branch 4 taken 0 (fallthrough) branch 5 taken 1 #####: 702: if (comm[1] && (strcmp(comm[1], "edit") == 0 %%%%%: 702-block 0 branch 0 never executed branch 1 never executed %%%%%: 702-block 1 branch 2 never executed branch 3 never executed #####: 703: || strcmp(comm[1], "e") == 0)) { %%%%%: 703-block 0 branch 0 never executed branch 1 never executed #####: 704: if (!comm[2]) { %%%%%: 704-block 0 branch 0 never executed branch 1 never executed #####: 705: fprintf(stderr, "%s\n", _(LE_USAGE)); %%%%%: 705-block 0 call 0 never executed call 1 never executed #####: 706: return (exit_code = EXIT_FAILURE); unconditional 0 never executed -: 707: } #####: 708: exit_code = edit_link(comm[2]); %%%%%: 708-block 0 call 0 never executed #####: 709: goto CHECK_EVENTS; unconditional 0 never executed -: 710: } -: 711: } -: 712: 1: 713: kbind_busy = 1; 1: 714: exit_code = run_and_refresh(comm); 1: 714-block 0 call 0 returned 1 1: 715: kbind_busy = 0; unconditional 0 taken 1 -: 716: } -: 717: -: 718: /* ############### TOGGLE EXEC ################## */ 236: 719: else if (*comm[0] == 't' && comm[0][1] == 'e' && !comm[0][2]) { 234: 719-block 0 branch 0 taken 3 (fallthrough) branch 1 taken 231 3: 719-block 1 branch 2 taken 2 (fallthrough) branch 3 taken 1 2: 719-block 2 branch 4 taken 2 (fallthrough) branch 5 taken 0 2: 719-block 3 unconditional 6 taken 2 2*: 720: if (!comm[1] || (*comm[1] == '-' && strcmp(comm[1], "--help") == 0)) { 2: 720-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 0 2: 720-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 2 %%%%%: 720-block 2 branch 4 never executed branch 5 never executed #####: 721: puts(_(TE_USAGE)); %%%%%: 721-block 0 call 0 never executed call 1 never executed #####: 722: return EXIT_SUCCESS; unconditional 0 never executed -: 723: } -: 724: -: 725: size_t j; 4: 726: for (j = 1; comm[j]; j++) { 2: 726-block 0 unconditional 0 taken 2 2: 726-block 1 unconditional 1 taken 2 4: 726-block 2 branch 2 taken 2 branch 3 taken 2 (fallthrough) -: 727: struct stat attr; 2: 728: if (strchr(comm[j], '\\')) { 2: 728-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 2 #####: 729: char *tmp = dequote_str(comm[j], 0); %%%%%: 729-block 0 call 0 never executed #####: 730: if (tmp) { branch 0 never executed branch 1 never executed #####: 731: strcpy(comm[j], tmp); #####: 732: free(tmp); %%%%%: 732-block 0 unconditional 0 never executed -: 733: } -: 734: } -: 735: 2*: 736: if (lstat(comm[j], &attr) == -1) { 2: 736-block 0 call 0 returned 2 branch 1 taken 0 (fallthrough) branch 2 taken 2 #####: 737: fprintf(stderr, "stat: %s: %s\n", comm[j], strerror(errno)); %%%%%: 737-block 0 call 0 never executed call 1 never executed #####: 738: exit_code = EXIT_FAILURE; #####: 739: continue; unconditional 0 never executed -: 740: } -: 741: 2: 742: if (xchmod(comm[j], attr.st_mode) == -1) 2: 742-block 0 call 0 returned 2 branch 1 taken 0 (fallthrough) branch 2 taken 2 #####: 743: exit_code = EXIT_FAILURE; %%%%%: 743-block 0 unconditional 0 never executed -: 744: } -: 745: 2: 746: if (exit_code == EXIT_SUCCESS) 2: 746-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 0 2: 747: printf(_("%s: Toggled executable bit on %zu file(s)\n"), 2: 747-block 0 call 0 returned 2 call 1 returned 2 unconditional 2 taken 2 -: 748: PROGRAM_NAME, args_n); -: 749: } -: 750: -: 751: /* ############### PINNED FILE ################## */ 232: 752: else if (*comm[0] == 'p' && strcmp(comm[0], "pin") == 0) { 232: 752-block 0 branch 0 taken 14 (fallthrough) branch 1 taken 218 14: 752-block 1 branch 2 taken 1 (fallthrough) branch 3 taken 13 1: 753: if (comm[1]) { 1: 753-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 0 1*: 754: if (*comm[1] == '-' && strcmp(comm[1], "--help") == 0) 1: 754-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 1 %%%%%: 754-block 1 branch 2 never executed branch 3 never executed #####: 755: puts(PIN_USAGE); %%%%%: 755-block 0 call 0 never executed unconditional 1 never executed -: 756: else 1: 757: exit_code = pin_directory(comm[1]); 1: 757-block 0 call 0 returned 1 unconditional 1 taken 1 -: 758: } else { #####: 759: if (pinned_dir) %%%%%: 759-block 0 branch 0 never executed branch 1 never executed #####: 760: printf(_("pinned file: %s\n"), pinned_dir); %%%%%: 760-block 0 call 0 never executed call 1 never executed unconditional 2 never executed -: 761: else #####: 762: puts(_("No pinned file")); %%%%%: 762-block 0 call 0 never executed call 1 never executed unconditional 2 never executed -: 763: } 1: 764: return exit_code; 1: 764-block 0 unconditional 0 taken 1 -: 765: } -: 766: 231: 767: else if (*comm[0] == 'u' && strcmp(comm[0], "unpin") == 0) 231: 767-block 0 branch 0 taken 6 (fallthrough) branch 1 taken 225 6: 767-block 1 branch 2 taken 2 (fallthrough) branch 3 taken 4 2: 768: return (exit_code = unpin_dir()); 2: 768-block 0 call 0 returned 2 unconditional 1 taken 2 -: 769: -: 770: /* ############### PROPERTIES ################## */ 229: 771: else if (*comm[0] == 'p' && (!comm[0][1] || strcmp(comm[0], "pr") == 0 229: 771-block 0 branch 0 taken 13 (fallthrough) branch 1 taken 216 13: 771-block 1 branch 2 taken 11 (fallthrough) branch 3 taken 2 11: 771-block 2 branch 4 taken 11 (fallthrough) branch 5 taken 0 11: 772: || strcmp(comm[0], "pp") == 0 || strcmp(comm[0], "prop") == 0)) { 11: 772-block 0 branch 0 taken 10 (fallthrough) branch 1 taken 1 10: 772-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 10 3: 773: if (!comm[1]) { 3: 773-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 3 #####: 774: fprintf(stderr, "%s\n", _(PROP_USAGE)); %%%%%: 774-block 0 call 0 never executed call 1 never executed #####: 775: exit_code = EXIT_FAILURE; #####: 776: return EXIT_FAILURE; unconditional 0 never executed 3*: 777: } else if (*comm[1] == '-' && strcmp(comm[1], "--help") == 0) { 3: 777-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 3 %%%%%: 777-block 1 branch 2 never executed branch 3 never executed #####: 778: puts(_(PROP_USAGE)); %%%%%: 778-block 0 call 0 never executed call 1 never executed #####: 779: return EXIT_SUCCESS; unconditional 0 never executed -: 780: } -: 781: 3: 782: return (exit_code = properties_function(comm)); 3: 782-block 0 call 0 returned 3 unconditional 1 taken 3 -: 783: } -: 784: -: 785: /* ############### SEARCH ################## */ 226: 786: else if (*comm[0] == '/' && access(comm[0], F_OK) != 0) { 226: 786-block 0 branch 0 taken 22 (fallthrough) branch 1 taken 204 22: 786-block 1 call 2 returned 22 branch 3 taken 5 (fallthrough) branch 4 taken 17 -: 787: /* If not absolute path */ -: 788: /* Try first globbing, and if no result, try regex */ 5: 789: if (search_glob(comm, (comm[0][1] == '!') ? 1 : 0) == EXIT_FAILURE) 5: 789-block 0 call 0 returned 5 branch 1 taken 2 (fallthrough) branch 2 taken 3 2: 790: exit_code = search_regex(comm, (comm[0][1] == '!') ? 1 : 0); 2: 790-block 0 call 0 returned 2 unconditional 1 taken 2 -: 791: else 3: 792: exit_code = EXIT_SUCCESS; 3: 792-block 0 unconditional 0 taken 3 5: 793: return exit_code; 5: 793-block 0 unconditional 0 taken 5 -: 794: } -: 795: -: 796: /* ############### HISTORY ################## */ 221: 797: else if (*comm[0] == '!' && comm[0][1] != ' ' && comm[0][1] != '\t' 221: 797-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 219 2: 797-block 1 branch 2 taken 2 (fallthrough) branch 3 taken 0 2: 797-block 2 branch 4 taken 2 (fallthrough) branch 5 taken 0 2: 798: && comm[0][1] != '\n' && comm[0][1] != '=' && comm[0][1] != '(') 2: 798-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 0 2: 798-block 1 branch 2 taken 2 (fallthrough) branch 3 taken 0 2: 798-block 2 branch 4 taken 2 (fallthrough) branch 5 taken 0 2: 799: exit_code = run_history_cmd(comm[0] + 1); 2: 799-block 0 call 0 returned 2 unconditional 1 taken 2 -: 800: -: 801: /* ############### BATCH LINK ################## */ 219*: 802: else if (*comm[0] == 'b' && comm[0][1] == 'l' && !comm[0][2]) 219: 802-block 0 branch 0 taken 3 (fallthrough) branch 1 taken 216 3: 802-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 3 %%%%%: 802-block 2 branch 4 never executed branch 5 never executed #####: 803: exit_code = batch_link(comm); %%%%%: 803-block 0 call 0 never executed unconditional 1 never executed -: 804: -: 805: /* ############### BULK RENAME ################## */ 219: 806: else if (*comm[0] == 'b' && ((comm[0][1] == 'r' && !comm[0][2]) 219: 806-block 0 branch 0 taken 3 (fallthrough) branch 1 taken 216 3: 806-block 1 branch 2 taken 3 (fallthrough) branch 3 taken 0 3: 806-block 2 branch 4 taken 0 (fallthrough) branch 5 taken 3 #####: 807: || strcmp(comm[0], "bulk") == 0)) { %%%%%: 807-block 0 branch 0 never executed branch 1 never executed 3: 808: if (!comm[1]) { 3: 808-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 3 #####: 809: fprintf(stderr, "%s\n", _(BULK_USAGE)); %%%%%: 809-block 0 call 0 never executed call 1 never executed #####: 810: return (exit_code = EXIT_FAILURE); unconditional 0 never executed -: 811: } -: 812: 3*: 813: if (*comm[1] == '-' && strcmp(comm[1], "--help") == 0) { 3: 813-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 3 %%%%%: 813-block 1 branch 2 never executed branch 3 never executed #####: 814: puts(_(BULK_USAGE)); %%%%%: 814-block 0 call 0 never executed call 1 never executed #####: 815: return EXIT_SUCCESS; unconditional 0 never executed -: 816: } 3: 817: exit_code = bulk_rename(comm); 3: 817-block 0 call 0 returned 3 unconditional 1 taken 3 -: 818: } -: 819: -: 820: /* ################ SORT ################## */ 216: 821: else if (*comm[0] == 's' && ((comm[0][1] == 't' && !comm[0][2]) 216: 821-block 0 branch 0 taken 15 (fallthrough) branch 1 taken 201 15: 821-block 1 branch 2 taken 9 (fallthrough) branch 3 taken 6 9: 821-block 2 branch 4 taken 0 (fallthrough) branch 5 taken 9 6: 822: || strcmp(comm[0], "sort") == 0)) { 6: 822-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 6 9*: 823: if (comm[1] && *comm[1] == '-' && strcmp(comm[1], "--help") == 0) { 9: 823-block 0 branch 0 taken 6 (fallthrough) branch 1 taken 3 6: 823-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 6 %%%%%: 823-block 2 branch 4 never executed branch 5 never executed #####: 824: puts(_(SORT_USAGE)); %%%%%: 824-block 0 call 0 never executed call 1 never executed #####: 825: return EXIT_SUCCESS; unconditional 0 never executed -: 826: } 9: 827: return (exit_code = sort_function(comm)); 9: 827-block 0 call 0 returned 9 unconditional 1 taken 9 -: 828: } -: 829: -: 830: /* ################ ARCHIVER ################## */ 207: 831: else if (*comm[0] == 'a' && ((comm[0][1] == 'c' || comm[0][1] == 'd') 207: 831-block 0 branch 0 taken 18 (fallthrough) branch 1 taken 189 18: 831-block 1 branch 2 taken 7 (fallthrough) branch 3 taken 11 7: 831-block 2 branch 4 taken 1 (fallthrough) branch 5 taken 6 12: 832: && !comm[0][2])) { 12: 832-block 0 branch 0 taken 3 (fallthrough) branch 1 taken 9 -: 833:#ifndef _NO_ARCHIVING 3*: 834: if (!comm[1] || (*comm[1] == '-' && strcmp(comm[1], "--help") == 0)) { 3: 834-block 0 branch 0 taken 3 (fallthrough) branch 1 taken 0 3: 834-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 3 %%%%%: 834-block 2 branch 4 never executed branch 5 never executed #####: 835: puts(_(ARCHIVE_USAGE)); %%%%%: 835-block 0 call 0 never executed call 1 never executed #####: 836: return EXIT_SUCCESS; unconditional 0 never executed -: 837: } -: 838: 3: 839: if (comm[0][1] == 'c') 3: 839-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 1 2: 840: exit_code = archiver(comm, 'c'); 2: 840-block 0 call 0 returned 2 unconditional 1 taken 2 -: 841: else 1: 842: exit_code = archiver(comm, 'd'); 1: 842-block 0 call 0 returned 1 unconditional 1 taken 1 -: 843:#else -: 844: fprintf(stderr, _("%s: archiving: %s\n"), PROGRAM_NAME, _(NOT_AVAILABLE)); -: 845: return EXIT_FAILURE; -: 846:#endif -: 847: } -: 848: -: 849: /* ################################################## -: 850: * # MINOR FUNCTIONS # -: 851: * ##################################################*/ -: 852: 204: 853: else if (*comm[0] == 'w' && comm[0][1] == 's' && !comm[0][2]) 204: 853-block 0 branch 0 taken 19 (fallthrough) branch 1 taken 185 19: 853-block 1 branch 2 taken 19 (fallthrough) branch 3 taken 0 19: 853-block 2 branch 4 taken 18 (fallthrough) branch 5 taken 1 18: 854: return (exit_code = workspaces(comm[1] ? comm[1] : NULL)); 18: 854-block 0 call 0 returned 18 unconditional 1 taken 18 -: 855: 186: 856: else if (*comm[0] == 'f' && ((comm[0][1] == 't' && !comm[0][2]) 186: 856-block 0 branch 0 taken 16 (fallthrough) branch 1 taken 170 16: 856-block 1 branch 2 taken 7 (fallthrough) branch 3 taken 9 7: 856-block 2 branch 4 taken 0 (fallthrough) branch 5 taken 7 9: 857: || strcmp(comm[0], "filter") == 0)) 9: 857-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 9 7: 858: return (exit_code = filter_function(comm[1])); 7: 858-block 0 call 0 returned 7 unconditional 1 taken 7 -: 859: 179: 860: else if (*comm[0] == 'c' && ((comm[0][1] == 'l' && !comm[0][2]) 179: 860-block 0 branch 0 taken 12 (fallthrough) branch 1 taken 167 12: 860-block 1 branch 2 taken 3 (fallthrough) branch 3 taken 9 3: 860-block 2 branch 4 taken 1 (fallthrough) branch 5 taken 2 10: 861: || strcmp(comm[0], "columns") == 0)) { 10: 861-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 10 2*: 862: if (!comm[1] || (*comm[1] == '-' && strcmp(comm[1], "--help") == 0)) { 2: 862-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 0 2: 862-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 2 %%%%%: 862-block 2 branch 4 never executed branch 5 never executed #####: 863: puts(_(COLUMNS_USAGE)); %%%%%: 863-block 0 call 0 never executed call 1 never executed #####: 864: return EXIT_SUCCESS; unconditional 0 never executed 2: 865: } else if (*comm[1] == 'o' && comm[1][1] == 'n' && !comm[1][2]) { 2: 865-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 0 2: 865-block 1 branch 2 taken 1 (fallthrough) branch 3 taken 1 1: 865-block 2 branch 4 taken 1 (fallthrough) branch 5 taken 0 1: 866: columned = 1; 1: 867: if (cd_lists_on_the_fly) { 1: 867-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 0 1: 868: free_dirlist(); 1: 868-block 0 call 0 returned 1 1: 869: exit_code = list_dir(); call 0 returned 1 unconditional 1 taken 1 -: 870: } 1: 871: } else if (*comm[1] == 'o' && strcmp(comm[1], "off") == 0) { 1: 871-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 0 1: 871-block 1 branch 2 taken 1 (fallthrough) branch 3 taken 0 1: 872: columned = 0; 1: 873: if (cd_lists_on_the_fly) { 1: 873-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 0 1: 874: free_dirlist(); 1: 874-block 0 call 0 returned 1 1: 875: exit_code = list_dir(); call 0 returned 1 unconditional 1 taken 1 -: 876: } -: 877: } else { #####: 878: fprintf(stderr, "%s\n", _(COLUMNS_USAGE)); %%%%%: 878-block 0 call 0 never executed call 1 never executed #####: 879: exit_code = EXIT_FAILURE; #####: 880: return EXIT_FAILURE; unconditional 0 never executed -: 881: } 2: 882: return exit_code; 2: 882-block 0 unconditional 0 taken 2 -: 883: } 177: 884: else if (*comm[0] == 'i' && strcmp(comm[0], "icons") == 0) { 177: 884-block 0 branch 0 taken 3 (fallthrough) branch 1 taken 174 3: 884-block 1 branch 2 taken 3 (fallthrough) branch 3 taken 0 -: 885:#ifndef _NO_ICONS 3*: 886: if (!comm[1] || (*comm[1] == '-' && strcmp(comm[1], "--help") == 0)) { 3: 886-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 1 2: 886-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 2 %%%%%: 886-block 2 branch 4 never executed branch 5 never executed 1: 887: puts(_(ICONS_USAGE)); 1: 887-block 0 call 0 returned 1 call 1 returned 1 unconditional 2 taken 1 2: 888: } else if (*comm[1] == 'o' && comm[1][1] == 'n' && !comm[1][2]) { 2: 888-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 0 2: 888-block 1 branch 2 taken 1 (fallthrough) branch 3 taken 1 1: 888-block 2 branch 4 taken 1 (fallthrough) branch 5 taken 0 1: 889: icons = 1; 1: 890: if (cd_lists_on_the_fly) { 1: 890-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 0 1: 891: free_dirlist(); 1: 891-block 0 call 0 returned 1 1: 892: exit_code = list_dir(); call 0 returned 1 unconditional 1 taken 1 -: 893: } 1: 894: } else if (*comm[1] == 'o' && strcmp(comm[1], "off") == 0) { 1: 894-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 0 1: 894-block 1 branch 2 taken 1 (fallthrough) branch 3 taken 0 1: 895: icons = 0; 1: 896: if (cd_lists_on_the_fly) { 1: 896-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 0 1: 897: free_dirlist(); 1: 897-block 0 call 0 returned 1 1: 898: exit_code = list_dir(); call 0 returned 1 unconditional 1 taken 1 -: 899: } -: 900: } else { #####: 901: fprintf(stderr, "%s\n", _(ICONS_USAGE)); %%%%%: 901-block 0 call 0 never executed call 1 never executed #####: 902: exit_code = EXIT_FAILURE; #####: 903: return EXIT_FAILURE; unconditional 0 never executed -: 904: } -: 905: 3: 906: return EXIT_SUCCESS; 3: 906-block 0 unconditional 0 taken 3 -: 907:#else -: 908: fprintf(stderr, _("%s: icons: %s\n"), PROGRAM_NAME, _(NOT_AVAILABLE)); -: 909: return EXIT_SUCCESS; -: 910:#endif /* _NO_ICONS */ -: 911: } -: 912: 174: 913: else if (*comm[0] == 'c' && ((comm[0][1] == 's' && !comm[0][2]) 174: 913-block 0 branch 0 taken 10 (fallthrough) branch 1 taken 164 10: 913-block 1 branch 2 taken 5 (fallthrough) branch 3 taken 5 5: 913-block 2 branch 4 taken 0 (fallthrough) branch 5 taken 5 5: 914: || strcmp(comm[0], "colorschemes") == 0)) 5: 914-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 5 5: 915: return (exit_code = cschemes_function(comm)); 5: 915-block 0 call 0 returned 5 unconditional 1 taken 5 -: 916: 169: 917: else if (*comm[0] == 'k' && ((comm[0][1] == 'b' && !comm[0][2]) 169: 917-block 0 branch 0 taken 5 (fallthrough) branch 1 taken 164 5: 917-block 1 branch 2 taken 4 (fallthrough) branch 3 taken 1 4: 917-block 2 branch 4 taken 0 (fallthrough) branch 5 taken 4 1: 918: || strcmp(comm[0], "keybinds") == 0)) 1: 918-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 1 4: 919: return (exit_code = kbinds_function(comm)); 4: 919-block 0 call 0 returned 4 unconditional 1 taken 4 -: 920: 165: 921: else if (*comm[0] == 'e' && (strcmp(comm[0], "exp") == 0 165: 921-block 0 branch 0 taken 14 (fallthrough) branch 1 taken 151 14: 921-block 1 branch 2 taken 12 (fallthrough) branch 3 taken 2 12: 922: || strcmp(comm[0], "export") == 0)) { 12: 922-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 12 2*: 923: if (comm[1] && *comm[1] == '-' && strcmp(comm[1], "--help") == 0) { 2: 923-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 1 1: 923-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 1 %%%%%: 923-block 2 branch 4 never executed branch 5 never executed #####: 924: puts(_(EXPORT_USAGE)); %%%%%: 924-block 0 call 0 never executed call 1 never executed #####: 925: return EXIT_SUCCESS; unconditional 0 never executed -: 926: } -: 927: 2: 928: char *ret = export(comm, 1); 2: 928-block 0 call 0 returned 2 2: 929: if (ret) { branch 0 taken 2 (fallthrough) branch 1 taken 0 2: 930: printf("Files exported to: %s\n", ret); 2: 930-block 0 call 0 returned 2 2: 931: free(ret); 2: 932: return EXIT_SUCCESS; unconditional 0 taken 2 -: 933: } -: 934: #####: 935: return (exit_code = EXIT_FAILURE); %%%%%: 935-block 0 unconditional 0 never executed -: 936: } -: 937: 163*: 938: else if (*comm[0] == 'o' && strcmp(comm[0], "opener") == 0) { 163: 938-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 163 %%%%%: 938-block 1 branch 2 never executed branch 3 never executed #####: 939: if (!comm[1]) { %%%%%: 939-block 0 branch 0 never executed branch 1 never executed #####: 940: printf("opener: %s\n", (opener) ? opener : "lira (built-in)"); %%%%%: 940-block 0 branch 0 never executed branch 1 never executed %%%%%: 940-block 1 unconditional 2 never executed %%%%%: 940-block 2 unconditional 3 never executed %%%%%: 940-block 3 call 4 never executed #####: 941: return EXIT_SUCCESS; unconditional 0 never executed -: 942: } #####: 943: if (*comm[1] == '-' && strcmp(comm[1], "--help") == 0) { %%%%%: 943-block 0 branch 0 never executed branch 1 never executed %%%%%: 943-block 1 branch 2 never executed branch 3 never executed #####: 944: puts(_(OPENER_USAGE)); %%%%%: 944-block 0 call 0 never executed call 1 never executed #####: 945: return EXIT_SUCCESS; unconditional 0 never executed -: 946: } #####: 947: if (opener) { %%%%%: 947-block 0 branch 0 never executed branch 1 never executed #####: 948: free(opener); #####: 949: opener = (char *)NULL; %%%%%: 949-block 0 unconditional 0 never executed -: 950: } #####: 951: if (strcmp(comm[1], "default") != 0 && strcmp(comm[1], "lira") != 0) { %%%%%: 951-block 0 branch 0 never executed branch 1 never executed %%%%%: 951-block 1 branch 2 never executed branch 3 never executed #####: 952: opener = (char *)xnmalloc(strlen(comm[1]) + 1, sizeof(char)); %%%%%: 952-block 0 call 0 never executed #####: 953: strcpy(opener, comm[1]); unconditional 0 never executed -: 954: } #####: 955: printf(_("opener: Opener set to '%s'\n"), (opener) ? opener %%%%%: 955-block 0 branch 0 never executed branch 1 never executed %%%%%: 955-block 1 unconditional 2 never executed %%%%%: 955-block 2 unconditional 3 never executed %%%%%: 955-block 3 call 4 never executed call 5 never executed -: 956: : "lira (built-in)"); #####: 957: return EXIT_SUCCESS; unconditional 0 never executed -: 958: } -: 959: -: 960: /* #### TIPS #### */ 163: 961: else if (*comm[0] == 't' && strcmp(comm[0], "tips") == 0) { 163: 961-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 162 1: 961-block 1 branch 2 taken 1 (fallthrough) branch 3 taken 0 1: 962: print_tips(1); 1: 962-block 0 call 0 returned 1 1: 963: return EXIT_SUCCESS; unconditional 0 taken 1 -: 964: } -: 965: -: 966: /* #### ACTIONS #### */ 162: 967: else if (*comm[0] == 'a' && strcmp(comm[0], "actions") == 0) { 162: 967-block 0 branch 0 taken 15 (fallthrough) branch 1 taken 147 15: 967-block 1 branch 2 taken 6 (fallthrough) branch 3 taken 9 6: 968: if (!comm[1]) { 6: 968-block 0 branch 0 taken 3 (fallthrough) branch 1 taken 3 3: 969: if (actions_n) { 3: 969-block 0 branch 0 taken 3 (fallthrough) branch 1 taken 0 -: 970: size_t i; 73: 971: for (i = 0; i < actions_n; i++) 3: 971-block 0 unconditional 0 taken 3 unconditional 1 taken 70 73: 971-block 1 branch 2 taken 70 branch 3 taken 3 70: 972: printf("%s %s->%s %s\n", usr_actions[i].name, 70: 973: mi_c, df_c, usr_actions[i].value); 70: 973-block 0 call 0 returned 70 -: 974: } else { #####: 975: puts(_("actions: No actions defined. Use the 'actions " %%%%%: 975-block 0 call 0 never executed call 1 never executed unconditional 2 never executed -: 976: "edit' command to add some")); -: 977: } 3: 978: } else if (strcmp(comm[1], "edit") == 0) { 3: 978-block 0 branch 0 taken 3 (fallthrough) branch 1 taken 0 3: 979: return (exit_code = edit_actions()); 3: 979-block 0 call 0 returned 3 unconditional 1 taken 3 #####: 980: } else if (*comm[1] == '-' && strcmp(comm[1], "--help") == 0) { %%%%%: 980-block 0 branch 0 never executed branch 1 never executed %%%%%: 980-block 1 branch 2 never executed branch 3 never executed #####: 981: puts(_(ACTIONS_USAGE)); %%%%%: 981-block 0 call 0 never executed call 1 never executed unconditional 2 never executed -: 982: } else { #####: 983: fprintf(stderr, "%s\n", _(ACTIONS_USAGE)); %%%%%: 983-block 0 call 0 never executed call 1 never executed #####: 984: exit_code = EXIT_FAILURE; #####: 985: return EXIT_FAILURE; unconditional 0 never executed -: 986: } 3: 987: return exit_code; 3: 987-block 0 unconditional 0 taken 3 -: 988: } -: 989: -: 990: /* #### LIGHT MODE #### */ 156: 991: else if (*comm[0] == 'l' && comm[0][1] == 'm' && !comm[0][2]) { 156: 991-block 0 branch 0 taken 9 (fallthrough) branch 1 taken 147 9: 991-block 1 branch 2 taken 4 (fallthrough) branch 3 taken 5 4: 991-block 2 branch 4 taken 4 (fallthrough) branch 5 taken 0 4: 992: if (comm[1]) { 4: 992-block 0 branch 0 taken 4 (fallthrough) branch 1 taken 0 4: 993: if (*comm[1] == 'o' && strcmp(comm[1], "on") == 0) { 4: 993-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 2 2: 993-block 1 branch 2 taken 1 (fallthrough) branch 3 taken 1 1: 994: light_mode = 1; 1: 995: puts(_("Light mode is on")); 1: 995-block 0 call 0 returned 1 call 1 returned 1 unconditional 2 taken 1 3: 996: } else if (*comm[1] == 'o' && strcmp(comm[1], "off") == 0) { 3: 996-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 2 1: 996-block 1 branch 2 taken 1 (fallthrough) branch 3 taken 0 1: 997: light_mode = 0; 1: 998: puts(_("Light mode is off")); 1: 998-block 0 call 0 returned 1 call 1 returned 1 unconditional 2 taken 1 -: 999: } else { 2: 1000: puts(_(LM_USAGE)); 2: 1000-block 0 call 0 returned 2 call 1 returned 2 2: 1001: exit_code = EXIT_FAILURE; unconditional 0 taken 2 -: 1002: } -: 1003: } else { #####: 1004: fprintf(stderr, "%s\n", _(LM_USAGE)); %%%%%: 1004-block 0 call 0 never executed call 1 never executed #####: 1005: exit_code = EXIT_FAILURE; unconditional 0 never executed -: 1006: } 4: 1007: return exit_code; 4: 1007-block 0 unconditional 0 taken 4 -: 1008: } -: 1009: -: 1010: /* ############### RELOAD ################## */ 152: 1011: else if (*comm[0] == 'r' && ((comm[0][1] == 'l' && !comm[0][2]) 152: 1011-block 0 branch 0 taken 4 (fallthrough) branch 1 taken 148 4: 1011-block 1 branch 2 taken 1 (fallthrough) branch 3 taken 3 1: 1011-block 2 branch 4 taken 0 (fallthrough) branch 5 taken 1 3: 1012: || strcmp(comm[0], "reload") == 0)) { 3: 1012-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 1 3: 1013: exit_code = reload_config(); 3: 1013-block 0 call 0 returned 3 3: 1014: welcome_message = 0; 3: 1015: if (cd_lists_on_the_fly) { branch 0 taken 3 (fallthrough) branch 1 taken 0 3: 1016: free_dirlist(); 3: 1016-block 0 call 0 returned 3 3: 1017: if (list_dir() != EXIT_SUCCESS) call 0 returned 3 branch 1 taken 0 (fallthrough) branch 2 taken 3 #####: 1018: exit_code = EXIT_FAILURE; %%%%%: 1018-block 0 unconditional 0 never executed -: 1019: } 3: 1020: return exit_code; 3: 1020-block 0 unconditional 0 taken 3 -: 1021: } -: 1022: -: 1023: /* #### NEW INSTANCE #### */ 149: 1024: else if ((*comm[0] == 'x' || *comm[0] == 'X') && !comm[0][1]) { 149: 1024-block 0 branch 0 taken 147 (fallthrough) branch 1 taken 2 147: 1024-block 1 branch 2 taken 1 (fallthrough) branch 3 taken 146 3: 1024-block 2 branch 4 taken 3 (fallthrough) branch 5 taken 0 3: 1025: if (comm[1]) { 3: 1025-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 1 2*: 1026: if (*comm[1] == '-' && strcmp(comm[1], "--help") == 0) { 2: 1026-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 2 %%%%%: 1026-block 1 branch 2 never executed branch 3 never executed #####: 1027: puts(_(X_USAGE)); %%%%%: 1027-block 0 call 0 never executed call 1 never executed #####: 1028: return EXIT_SUCCESS; unconditional 0 never executed 2: 1029: } else if (*comm[0] == 'x') { 2: 1029-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 0 2: 1030: exit_code = new_instance(comm[1], 0); 2: 1030-block 0 call 0 returned 2 unconditional 1 taken 2 -: 1031: } else { /* Run as root */ #####: 1032: exit_code = new_instance(comm[1], 1); %%%%%: 1032-block 0 call 0 never executed unconditional 1 never executed -: 1033: } -: 1034: } else { -: 1035: /* Run new instance in CWD */ 1: 1036: if (*comm[0] == 'x') 1: 1036-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 1 #####: 1037: exit_code = new_instance(ws[cur_ws].path, 0); %%%%%: 1037-block 0 call 0 never executed unconditional 1 never executed -: 1038: else 1: 1039: exit_code = new_instance(ws[cur_ws].path, 1); 1: 1039-block 0 call 0 returned 1 unconditional 1 taken 1 -: 1040: } -: 1041: 3: 1042: return exit_code; 3: 1042-block 0 unconditional 0 taken 3 -: 1043: } -: 1044: -: 1045: /* #### NET #### */ 146: 1046: else if (*comm[0] == 'n' && (strcmp(comm[0], "net") == 0)) 146: 1046-block 0 branch 0 taken 10 (fallthrough) branch 1 taken 136 10: 1046-block 1 branch 2 taken 10 (fallthrough) branch 3 taken 0 10: 1047: return (exit_code = remotes_function(comm)); 10: 1047-block 0 call 0 returned 10 unconditional 1 taken 10 -: 1048: -: 1049: /* #### MIME #### */ 136: 1050: else if (*comm[0] == 'm' && ((comm[0][1] == 'm' && !comm[0][2]) 136: 1050-block 0 branch 0 taken 7 (fallthrough) branch 1 taken 129 7: 1050-block 1 branch 2 taken 2 (fallthrough) branch 3 taken 5 2: 1050-block 2 branch 4 taken 0 (fallthrough) branch 5 taken 2 5: 1051: || strcmp(comm[0], "mime") == 0)) { 5: 1051-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 5 -: 1052:#ifndef _NO_LIRA 2: 1053: return (exit_code = mime_open(comm)); 2: 1053-block 0 call 0 returned 2 unconditional 1 taken 2 -: 1054:#else -: 1055: fprintf(stderr, _("%s: Lira: %s\n"), PROGRAM_NAME, _(NOT_AVAILABLE)); -: 1056: return EXIT_FAILURE; -: 1057:#endif -: 1058: } -: 1059: 134*: 1060: else if (*comm[0] == 'l' && comm[0][1] == 's' && !comm[0][2] && !cd_lists_on_the_fly) { 134: 1060-block 0 branch 0 taken 5 (fallthrough) branch 1 taken 129 5: 1060-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 5 %%%%%: 1060-block 2 branch 4 never executed branch 5 never executed %%%%%: 1060-block 3 branch 6 never executed branch 7 never executed #####: 1061: free_dirlist(); %%%%%: 1061-block 0 call 0 never executed #####: 1062: exit_code = list_dir(); call 0 never executed #####: 1063: if (get_sel_files() != EXIT_SUCCESS) call 0 never executed branch 1 never executed branch 2 never executed #####: 1064: exit_code = EXIT_FAILURE; %%%%%: 1064-block 0 unconditional 0 never executed #####: 1065: return exit_code; %%%%%: 1065-block 0 unconditional 0 never executed -: 1066: } -: 1067: -: 1068: /* #### PROFILE #### */ 134: 1069: else if (*comm[0] == 'p' && ((comm[0][1] == 'f' && !comm[0][2]) || strcmp(comm[0], "prof") == 0 || strcmp(comm[0], "profile") == 0)) 134: 1069-block 0 branch 0 taken 10 (fallthrough) branch 1 taken 124 10: 1069-block 1 branch 2 taken 4 (fallthrough) branch 3 taken 6 4: 1069-block 2 branch 4 taken 0 (fallthrough) branch 5 taken 4 6: 1069-block 3 branch 6 taken 6 (fallthrough) branch 7 taken 0 6: 1069-block 4 branch 8 taken 0 (fallthrough) branch 9 taken 6 4: 1070: return (exit_code = profile_function(comm)); 4: 1070-block 0 call 0 returned 4 unconditional 1 taken 4 -: 1071: -: 1072: /* #### MOUNTPOINTS #### */ 130: 1073: else if (*comm[0] == 'm' && ((comm[0][1] == 'p' && !comm[0][2]) || strcmp(comm[0], "mountpoints") == 0)) { 130: 1073-block 0 branch 0 taken 5 (fallthrough) branch 1 taken 125 5: 1073-block 1 branch 2 taken 1 (fallthrough) branch 3 taken 4 1: 1073-block 2 branch 4 taken 0 (fallthrough) branch 5 taken 1 4: 1073-block 3 branch 6 taken 0 (fallthrough) branch 7 taken 4 1*: 1074: if (comm[1] && *comm[1] == '-' && strcmp(comm[1], "--help") == 0) { 1: 1074-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 1 %%%%%: 1074-block 1 branch 2 never executed branch 3 never executed %%%%%: 1074-block 2 branch 4 never executed branch 5 never executed #####: 1075: puts(_(MOUNPOINTS_USAGE)); %%%%%: 1075-block 0 call 0 never executed call 1 never executed #####: 1076: return EXIT_SUCCESS; unconditional 0 never executed -: 1077: } else { 1: 1078: kbind_busy = 1; 1: 1079: rl_attempted_completion_function = NULL; 1: 1080: exit_code = list_mountpoints(); 1: 1080-block 0 call 0 returned 1 1: 1081: rl_attempted_completion_function = my_rl_completion; 1: 1082: kbind_busy = 0; 1: 1083: return exit_code; unconditional 0 taken 1 -: 1084: } -: 1085: } -: 1086: -: 1087: /* #### MAX FILES #### */ 129: 1088: else if (*comm[0] == 'm' && comm[0][1] == 'f' && !comm[0][2]) { 129: 1088-block 0 branch 0 taken 4 (fallthrough) branch 1 taken 125 4: 1088-block 1 branch 2 taken 2 (fallthrough) branch 3 taken 2 2: 1088-block 2 branch 4 taken 2 (fallthrough) branch 5 taken 0 2: 1089: if (!comm[1]) { 2: 1089-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 2 #####: 1090: printf(_("Max files: %d"), max_files); %%%%%: 1090-block 0 call 0 never executed call 1 never executed #####: 1091: if (max_files == -1) branch 0 never executed branch 1 never executed #####: 1092: puts(_(" (no limit)")); %%%%%: 1092-block 0 call 0 never executed call 1 never executed unconditional 2 never executed -: 1093: else #####: 1094: putchar('\n'); %%%%%: 1094-block 0 call 0 never executed unconditional 1 never executed #####: 1095: return EXIT_SUCCESS; %%%%%: 1095-block 0 unconditional 0 never executed -: 1096: } -: 1097: 2: 1098: if (*comm[1] == '-' && strcmp(comm[1], "--help") == 0) { 2: 1098-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 1 1: 1098-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 1 #####: 1099: puts(_(MF_USAGE)); %%%%%: 1099-block 0 call 0 never executed call 1 never executed #####: 1100: return EXIT_SUCCESS; unconditional 0 never executed -: 1101: } -: 1102: 2: 1103: if (strcmp(comm[1], "-1") != 0 && !is_number(comm[1])) { 2: 1103-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 1 1: 1103-block 1 call 2 returned 1 branch 3 taken 0 (fallthrough) branch 4 taken 1 #####: 1104: fprintf(stderr, _("%s: %s\n"), PROGRAM_NAME, MF_USAGE); %%%%%: 1104-block 0 call 0 never executed call 1 never executed #####: 1105: return (exit_code = EXIT_FAILURE); unconditional 0 never executed -: 1106: } -: 1107: 2: 1108: int inum = atoi(comm[1]); 2: 1109: if (inum < -1) { 2: 1109-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 2 #####: 1110: max_files = inum; #####: 1111: fprintf(stderr, _("%s: %d: Invalid number\n"), PROGRAM_NAME, %%%%%: 1111-block 0 call 0 never executed call 1 never executed -: 1112: inum); #####: 1113: return (exit_code = EXIT_FAILURE); unconditional 0 never executed -: 1114: } -: 1115: 2: 1116: max_files = inum; 2: 1117: if (max_files == -1) 2: 1117-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 1 1: 1118: puts(_("Max files unset")); 1: 1118-block 0 call 0 returned 1 call 1 returned 1 unconditional 2 taken 1 -: 1119: else 1: 1120: printf(_("Max files set to %d\n"), max_files); 1: 1120-block 0 call 0 returned 1 call 1 returned 1 unconditional 2 taken 1 2: 1121: return EXIT_SUCCESS; 2: 1121-block 0 unconditional 0 taken 2 -: 1122: } -: 1123: -: 1124: /* #### EXT #### */ 127: 1125: else if (*comm[0] == 'e' && comm[0][1] == 'x' && comm[0][2] == 't' 127: 1125-block 0 branch 0 taken 12 (fallthrough) branch 1 taken 115 12: 1125-block 1 branch 2 taken 3 (fallthrough) branch 3 taken 9 3: 1125-block 2 branch 4 taken 3 (fallthrough) branch 5 taken 0 3: 1126: && !comm[0][3]) { 3: 1126-block 0 branch 0 taken 3 (fallthrough) branch 1 taken 0 3: 1127: if (!comm[1]) { 3: 1127-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 3 #####: 1128: puts(_(EXT_USAGE)); %%%%%: 1128-block 0 call 0 never executed call 1 never executed #####: 1129: return (exit_code = EXIT_FAILURE); unconditional 0 never executed 3*: 1130: } else if (*comm[1] == '-' && strcmp(comm[1], "--help") == 0) { 3: 1130-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 3 %%%%%: 1130-block 1 branch 2 never executed branch 3 never executed #####: 1131: puts(_(EXT_USAGE)); %%%%%: 1131-block 0 call 0 never executed call 1 never executed unconditional 2 never executed -: 1132: } else { 3: 1133: if (*comm[1] == 's' && strcmp(comm[1], "status") == 0) { 3: 1133-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 2 1: 1133-block 1 branch 2 taken 1 (fallthrough) branch 3 taken 0 1: 1134: printf(_("%s: External commands %s\n"), PROGRAM_NAME, 1: 1134-block 0 call 0 returned 1 call 1 returned 1 unconditional 2 taken 1 1*: 1135: (ext_cmd_ok) ? _("enabled") : _("disabled")); 1: 1135-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 0 1: 1135-block 1 call 2 returned 1 unconditional 3 taken 1 %%%%%: 1135-block 2 call 4 never executed unconditional 5 never executed 2: 1136: } else if (*comm[1] == 'o' && strcmp(comm[1], "on") == 0) { 2: 1136-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 0 2: 1136-block 1 branch 2 taken 1 (fallthrough) branch 3 taken 1 1: 1137: ext_cmd_ok = 1; 1: 1138: printf(_("%s: External commands enabled\n"), PROGRAM_NAME); 1: 1138-block 0 call 0 returned 1 call 1 returned 1 unconditional 2 taken 1 1: 1139: } else if (*comm[1] == 'o' && strcmp(comm[1], "off") == 0) { 1: 1139-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 0 1: 1139-block 1 branch 2 taken 1 (fallthrough) branch 3 taken 0 1: 1140: ext_cmd_ok = 0; 1: 1141: printf(_("%s: External commands disabled\n"), PROGRAM_NAME); 1: 1141-block 0 call 0 returned 1 call 1 returned 1 unconditional 2 taken 1 -: 1142: } else { #####: 1143: fprintf(stderr, "%s\n", _(EXT_USAGE)); %%%%%: 1143-block 0 call 0 never executed call 1 never executed #####: 1144: exit_code = EXIT_FAILURE; unconditional 0 never executed -: 1145: } -: 1146: } 3: 1147: return exit_code; 3: 1147-block 0 unconditional 0 taken 3 -: 1148: } -: 1149: -: 1150: /* #### PAGER #### */ 124: 1151: else if (*comm[0] == 'p' && ((comm[0][1] == 'g' && !comm[0][2]) 124: 1151-block 0 branch 0 taken 6 (fallthrough) branch 1 taken 118 6: 1151-block 1 branch 2 taken 2 (fallthrough) branch 3 taken 4 2: 1151-block 2 branch 4 taken 0 (fallthrough) branch 5 taken 2 4: 1152: || strcmp(comm[0], "pager") == 0)) { 4: 1152-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 4 2: 1153: if (!comm[1]) { 2: 1153-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 2 #####: 1154: puts(_(PAGER_USAGE)); %%%%%: 1154-block 0 call 0 never executed call 1 never executed #####: 1155: return (exit_code = EXIT_FAILURE); unconditional 0 never executed 2*: 1156: } else if (*comm[1] == '-' && strcmp(comm[1], "--help") == 0) { 2: 1156-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 2 %%%%%: 1156-block 1 branch 2 never executed branch 3 never executed #####: 1157: puts(_(PAGER_USAGE)); %%%%%: 1157-block 0 call 0 never executed call 1 never executed #####: 1158: return EXIT_SUCCESS; unconditional 0 never executed -: 1159: } else { 2*: 1160: if (*comm[1] == 's' && strcmp(comm[1], "status") == 0) { 2: 1160-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 2 %%%%%: 1160-block 1 branch 2 never executed branch 3 never executed #####: 1161: printf(_("%s: Pager %s\n"), PROGRAM_NAME, %%%%%: 1161-block 0 call 0 never executed call 1 never executed unconditional 2 never executed #####: 1162: (pager) ? _("enabled") : _("disabled")); %%%%%: 1162-block 0 branch 0 never executed branch 1 never executed %%%%%: 1162-block 1 call 2 never executed unconditional 3 never executed %%%%%: 1162-block 2 call 4 never executed unconditional 5 never executed 2: 1163: } else if (*comm[1] == 'o' && strcmp(comm[1], "on") == 0) { 2: 1163-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 0 2: 1163-block 1 branch 2 taken 1 (fallthrough) branch 3 taken 1 1: 1164: pager = 1; 1: 1165: printf(_("%s: Pager enabled\n"), PROGRAM_NAME); 1: 1165-block 0 call 0 returned 1 call 1 returned 1 unconditional 2 taken 1 1: 1166: } else if (*comm[1] == 'o' && strcmp(comm[1], "off") == 0) { 1: 1166-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 0 1: 1166-block 1 branch 2 taken 1 (fallthrough) branch 3 taken 0 1: 1167: pager = 0; 1: 1168: printf(_("%s: Pager disabled\n"), PROGRAM_NAME); 1: 1168-block 0 call 0 returned 1 call 1 returned 1 unconditional 2 taken 1 -: 1169: } else { #####: 1170: fprintf(stderr, "%s\n", _(PAGER_USAGE)); %%%%%: 1170-block 0 call 0 never executed call 1 never executed #####: 1171: exit_code = EXIT_FAILURE; unconditional 0 never executed -: 1172: } -: 1173: } 2: 1174: return exit_code; 2: 1174-block 0 unconditional 0 taken 2 -: 1175: } -: 1176: -: 1177: /* #### FILES COUNTER #### */ 122: 1178: else if (*comm[0] == 'f' && ((comm[0][1] == 'c' && !comm[0][2]) 122: 1178-block 0 branch 0 taken 9 (fallthrough) branch 1 taken 113 9: 1178-block 1 branch 2 taken 2 (fallthrough) branch 3 taken 7 2: 1178-block 2 branch 4 taken 0 (fallthrough) branch 5 taken 2 7: 1179: || strcmp(comm[0], "filescounter") == 0)) { 7: 1179-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 7 2: 1180: if (!comm[1]) { 2: 1180-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 2 #####: 1181: fprintf(stderr, "%s\n", _(FC_USAGE)); %%%%%: 1181-block 0 call 0 never executed call 1 never executed #####: 1182: return (exit_code = EXIT_FAILURE); unconditional 0 never executed -: 1183: } -: 1184: 2: 1185: if (*comm[1] == 'o' && strcmp(comm[1], "on") == 0) { 2: 1185-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 0 2: 1185-block 1 branch 2 taken 1 (fallthrough) branch 3 taken 1 1: 1186: files_counter = 1; 1: 1187: puts(_("Filescounter is enabled")); 1: 1187-block 0 call 0 returned 1 call 1 returned 1 1: 1188: return EXIT_SUCCESS; unconditional 0 taken 1 -: 1189: } -: 1190: 1: 1191: if (*comm[1] == 'o' && strcmp(comm[1], "off") == 0) { 1: 1191-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 0 1: 1191-block 1 branch 2 taken 1 (fallthrough) branch 3 taken 0 1: 1192: files_counter = 0; 1: 1193: puts(_("Filescounter is disabled")); 1: 1193-block 0 call 0 returned 1 call 1 returned 1 1: 1194: return EXIT_SUCCESS; unconditional 0 taken 1 -: 1195: } -: 1196: #####: 1197: if (*comm[1] == 's' && strcmp(comm[1], "status") == 0) { %%%%%: 1197-block 0 branch 0 never executed branch 1 never executed %%%%%: 1197-block 1 branch 2 never executed branch 3 never executed #####: 1198: if (files_counter) %%%%%: 1198-block 0 branch 0 never executed branch 1 never executed #####: 1199: puts(_("Filescounter is enabled")); %%%%%: 1199-block 0 call 0 never executed call 1 never executed unconditional 2 never executed -: 1200: else #####: 1201: puts(_("Filescounter is disabled")); %%%%%: 1201-block 0 call 0 never executed call 1 never executed unconditional 2 never executed #####: 1202: return EXIT_SUCCESS; %%%%%: 1202-block 0 unconditional 0 never executed -: 1203: } else { #####: 1204: fprintf(stderr, "%s\n", _(FC_USAGE)); %%%%%: 1204-block 0 call 0 never executed call 1 never executed #####: 1205: return (exit_code = EXIT_FAILURE); unconditional 0 never executed -: 1206: } -: 1207: } -: 1208: -: 1209: /* #### UNICODE #### */ 120: 1210: else if (*comm[0] == 'u' && ((comm[0][1] == 'c' && !comm[0][2]) 120: 1210-block 0 branch 0 taken 4 (fallthrough) branch 1 taken 116 4: 1210-block 1 branch 2 taken 4 (fallthrough) branch 3 taken 0 4: 1210-block 2 branch 4 taken 0 (fallthrough) branch 5 taken 4 #####: 1211: || strcmp(comm[0], "unicode") == 0)) { %%%%%: 1211-block 0 branch 0 never executed branch 1 never executed 4: 1212: if (!comm[1]) { 4: 1212-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 3 1: 1213: fprintf(stderr, "%s\n", _(UNICODE_USAGE)); 1: 1213-block 0 call 0 returned 1 call 1 returned 1 1: 1214: return (exit_code = EXIT_FAILURE); unconditional 0 taken 1 3*: 1215: } else if (*comm[1] == '-' && strcmp(comm[1], "--help") == 0) { 3: 1215-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 3 %%%%%: 1215-block 1 branch 2 never executed branch 3 never executed #####: 1216: puts(_(UNICODE_USAGE)); %%%%%: 1216-block 0 call 0 never executed call 1 never executed #####: 1217: return EXIT_SUCCESS; unconditional 0 never executed -: 1218: } else { 3: 1219: if (*comm[1] == 's' && strcmp(comm[1], "status") == 0) { 3: 1219-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 2 1: 1219-block 1 branch 2 taken 1 (fallthrough) branch 3 taken 0 1: 1220: printf(_("%s: Unicode %s\n"), PROGRAM_NAME, 1: 1220-block 0 call 0 returned 1 call 1 returned 1 unconditional 2 taken 1 1*: 1221: (unicode) ? _("enabled") : _("disabled")); 1: 1221-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 0 1: 1221-block 1 call 2 returned 1 unconditional 3 taken 1 %%%%%: 1221-block 2 call 4 never executed unconditional 5 never executed 2: 1222: } else if (*comm[1] == 'o' && strcmp(comm[1], "on") == 0) { 2: 1222-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 0 2: 1222-block 1 branch 2 taken 1 (fallthrough) branch 3 taken 1 1: 1223: unicode = 1; 1: 1224: printf(_("%s: Unicode enabled\n"), PROGRAM_NAME); 1: 1224-block 0 call 0 returned 1 call 1 returned 1 unconditional 2 taken 1 1: 1225: } else if (*comm[1] == 'o' && strcmp(comm[1], "off") == 0) { 1: 1225-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 0 1: 1225-block 1 branch 2 taken 1 (fallthrough) branch 3 taken 0 1: 1226: unicode = 0; 1: 1227: printf(_("%s: Unicode disabled\n"), PROGRAM_NAME); 1: 1227-block 0 call 0 returned 1 call 1 returned 1 unconditional 2 taken 1 -: 1228: } else { #####: 1229: fprintf(stderr, "%s\n", _(UNICODE_USAGE)); %%%%%: 1229-block 0 call 0 never executed call 1 never executed #####: 1230: exit_code = EXIT_FAILURE; unconditional 0 never executed -: 1231: } -: 1232: } 3: 1233: return exit_code; 3: 1233-block 0 unconditional 0 taken 3 -: 1234: } -: 1235: -: 1236: /* #### FOLDERS FIRST #### */ 116: 1237: else if (*comm[0] == 'f' && ((comm[0][1] == 'f' && !comm[0][2]) 116: 1237-block 0 branch 0 taken 7 (fallthrough) branch 1 taken 109 7: 1237-block 1 branch 2 taken 3 (fallthrough) branch 3 taken 4 3: 1237-block 2 branch 4 taken 0 (fallthrough) branch 5 taken 3 4: 1238: || strcmp(comm[0], "folders-first") == 0)) { 4: 1238-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 4 3: 1239: if (cd_lists_on_the_fly == 0) 3: 1239-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 3 #####: 1240: return EXIT_SUCCESS; %%%%%: 1240-block 0 unconditional 0 never executed 3: 1241: if (!comm[1]) { 3: 1241-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 3 #####: 1242: fprintf(stderr, "%s\n", _(FF_USAGE)); %%%%%: 1242-block 0 call 0 never executed call 1 never executed #####: 1243: return (exit_code = EXIT_FAILURE); unconditional 0 never executed -: 1244: } 3*: 1245: if (*comm[1] == '-' && strcmp(comm[1], "--help") == 0) { 3: 1245-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 3 %%%%%: 1245-block 1 branch 2 never executed branch 3 never executed #####: 1246: puts(_(FF_USAGE)); %%%%%: 1246-block 0 call 0 never executed call 1 never executed #####: 1247: return EXIT_SUCCESS; unconditional 0 never executed -: 1248: } -: 1249: 3: 1250: int status = list_folders_first; 3: 1251: if (*comm[1] == 's' && strcmp(comm[1], "status") == 0) { 3: 1251-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 2 1: 1251-block 1 branch 2 taken 1 (fallthrough) branch 3 taken 0 1: 1252: printf(_("%s: Folders first %s\n"), PROGRAM_NAME, 1: 1252-block 0 call 0 returned 1 call 1 returned 1 unconditional 2 taken 1 1*: 1253: (list_folders_first) ? _("enabled") : _("disabled")); 1: 1253-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 0 1: 1253-block 1 call 2 returned 1 unconditional 3 taken 1 %%%%%: 1253-block 2 call 4 never executed unconditional 5 never executed 2: 1254: } else if (*comm[1] == 'o' && strcmp(comm[1], "on") == 0) { 2: 1254-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 0 2: 1254-block 1 branch 2 taken 1 (fallthrough) branch 3 taken 1 1: 1255: list_folders_first = 1; 1: 1255-block 0 unconditional 0 taken 1 1: 1256: } else if (*comm[1] == 'o' && strcmp(comm[1], "off") == 0) { 1: 1256-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 0 1: 1256-block 1 branch 2 taken 1 (fallthrough) branch 3 taken 0 1: 1257: list_folders_first = 0; 1: 1257-block 0 unconditional 0 taken 1 -: 1258: } else { #####: 1259: fprintf(stderr, "%s\n", _(FF_USAGE)); %%%%%: 1259-block 0 call 0 never executed call 1 never executed #####: 1260: return (exit_code = EXIT_FAILURE); unconditional 0 never executed -: 1261: } -: 1262: 3: 1263: if (list_folders_first != status) { 3: 1263-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 1 2: 1264: if (cd_lists_on_the_fly) { 2: 1264-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 0 2: 1265: free_dirlist(); 2: 1265-block 0 call 0 returned 2 2: 1266: exit_code = list_dir(); call 0 returned 2 unconditional 1 taken 2 -: 1267: } -: 1268: } 3: 1269: return exit_code; 3: 1269-block 0 unconditional 0 taken 3 -: 1270: } -: 1271: -: 1272: /* #### LOG #### */ 113: 1273: else if (*comm[0] == 'l' && strcmp(comm[0], "log") == 0) { 113: 1273-block 0 branch 0 taken 5 (fallthrough) branch 1 taken 108 5: 1273-block 1 branch 2 taken 5 (fallthrough) branch 3 taken 0 5: 1274: if (comm[1] && *comm[1] == '-' && strcmp(comm[1], "--help") == 0) { 5: 1274-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 3 2: 1274-block 1 branch 2 taken 1 (fallthrough) branch 3 taken 1 1: 1274-block 2 branch 4 taken 1 (fallthrough) branch 5 taken 0 1: 1275: puts(_(LOG_USAGE)); 1: 1275-block 0 call 0 returned 1 call 1 returned 1 1: 1276: return EXIT_SUCCESS; unconditional 0 taken 1 -: 1277: } -: 1278: -: 1279: /* I make this check here, and not in the function itself, -: 1280: * because this function is also called by other instances of -: 1281: * the program where no message should be printed */ 4: 1282: if (!config_ok) { 4: 1282-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 4 #####: 1283: fprintf(stderr, _("%s: Log function disabled\n"), PROGRAM_NAME); %%%%%: 1283-block 0 call 0 never executed call 1 never executed #####: 1284: return (exit_code = EXIT_FAILURE); unconditional 0 never executed -: 1285: } -: 1286: 4: 1287: return (exit_code = log_function(comm)); 4: 1287-block 0 call 0 returned 4 unconditional 1 taken 4 -: 1288: } -: 1289: -: 1290: /* #### MESSAGES #### */ 108: 1291: else if (*comm[0] == 'm' && (strcmp(comm[0], "msg") == 0 108: 1291-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 106 2: 1291-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 2 #####: 1292: || strcmp(comm[0], "messages") == 0)) { %%%%%: 1292-block 0 branch 0 never executed branch 1 never executed 2: 1293: if (comm[1] && strcmp(comm[1], "--help") == 0) { 2: 1293-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 1 1: 1293-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 1 #####: 1294: puts(_(MSG_USAGE)); %%%%%: 1294-block 0 call 0 never executed call 1 never executed #####: 1295: return EXIT_SUCCESS; unconditional 0 never executed -: 1296: } -: 1297: 2: 1298: if (comm[1] && strcmp(comm[1], "clear") == 0) { 2: 1298-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 1 1: 1298-block 1 branch 2 taken 1 (fallthrough) branch 3 taken 0 1: 1299: if (!msgs_n) { 1: 1299-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 1 #####: 1300: printf(_("%s: There are no messages\n"), PROGRAM_NAME); %%%%%: 1300-block 0 call 0 never executed call 1 never executed #####: 1301: return EXIT_SUCCESS; unconditional 0 never executed -: 1302: } -: 1303: -: 1304: size_t i; 3: 1305: for (i = 0; i < (size_t)msgs_n; i++) 1: 1305-block 0 unconditional 0 taken 1 3: 1305-block 1 branch 1 taken 2 branch 2 taken 1 (fallthrough) 2: 1306: free(messages[i]); 2: 1306-block 0 unconditional 0 taken 2 -: 1307: 1: 1308: msgs_n = 0; 1: 1309: pmsg = NOMSG; 1: 1309-block 0 unconditional 0 taken 1 -: 1310: } else { 1: 1311: if (msgs_n) { 1: 1311-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 1 -: 1312: size_t i; #####: 1313: for (i = 0; i < (size_t)msgs_n; i++) %%%%%: 1313-block 0 unconditional 0 never executed unconditional 1 never executed %%%%%: 1313-block 1 branch 2 never executed branch 3 never executed #####: 1314: printf("%s", messages[i]); %%%%%: 1314-block 0 call 0 never executed -: 1315: } else { 1: 1316: printf(_("%s: There are no messages\n"), PROGRAM_NAME); 1: 1316-block 0 call 0 returned 1 call 1 returned 1 unconditional 2 taken 1 -: 1317: } -: 1318: } 2: 1319: return exit_code; 2: 1319-block 0 unconditional 0 taken 2 -: 1320: } -: 1321: -: 1322: /* #### ALIASES #### */ 106: 1323: else if (*comm[0] == 'a' && strcmp(comm[0], "alias") == 0) { 106: 1323-block 0 branch 0 taken 9 (fallthrough) branch 1 taken 97 9: 1323-block 1 branch 2 taken 1 (fallthrough) branch 3 taken 8 1: 1324: if (comm[1]) { 1: 1324-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 1 #####: 1325: if (*comm[1] == '-' && strcmp(comm[1], "--help") == 0) { %%%%%: 1325-block 0 branch 0 never executed branch 1 never executed %%%%%: 1325-block 1 branch 2 never executed branch 3 never executed #####: 1326: puts(_(ALIAS_USAGE)); %%%%%: 1326-block 0 call 0 never executed call 1 never executed #####: 1327: return EXIT_SUCCESS; unconditional 0 never executed #####: 1328: } else if (*comm[1] == 'i' && strcmp(comm[1], "import") == 0) { %%%%%: 1328-block 0 branch 0 never executed branch 1 never executed %%%%%: 1328-block 1 branch 2 never executed branch 3 never executed #####: 1329: if (!comm[2]) { %%%%%: 1329-block 0 branch 0 never executed branch 1 never executed #####: 1330: fprintf(stderr, "%s\n", _(ALIAS_USAGE)); %%%%%: 1330-block 0 call 0 never executed call 1 never executed #####: 1331: return (exit_code = EXIT_FAILURE); unconditional 0 never executed -: 1332: } #####: 1333: return (exit_code = alias_import(comm[2])); %%%%%: 1333-block 0 call 0 never executed unconditional 1 never executed -: 1334: } -: 1335: } -: 1336: 1: 1337: if (aliases_n) { 1: 1337-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 0 -: 1338: size_t i; 6: 1339: for (i = 0; i < aliases_n; i++) 1: 1339-block 0 unconditional 0 taken 1 unconditional 1 taken 5 6: 1339-block 1 branch 2 taken 5 branch 3 taken 1 (fallthrough) 5: 1340: printf("%s", aliases[i]); 5: 1340-block 0 call 0 returned 5 -: 1341: } 1: 1342: return EXIT_SUCCESS; 1: 1342-block 0 unconditional 0 taken 1 -: 1343: } -: 1344: -: 1345: /* #### SHELL #### */ 105: 1346: else if (*comm[0] == 's' && strcmp(comm[0], "shell") == 0) { 105: 1346-block 0 branch 0 taken 6 (fallthrough) branch 1 taken 99 6: 1346-block 1 branch 2 taken 5 (fallthrough) branch 3 taken 1 5: 1347: if (!comm[1]) { 5: 1347-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 3 2: 1348: if (user.shell) 2: 1348-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 0 2: 1349: printf("%s: shell: %s\n", PROGRAM_NAME, user.shell); 2: 1349-block 0 call 0 returned 2 unconditional 1 taken 2 -: 1350: else #####: 1351: printf(_("%s: shell: unknown\n"), PROGRAM_NAME); %%%%%: 1351-block 0 call 0 never executed call 1 never executed unconditional 2 never executed 3: 1352: } else if (*comm[1] == '-' && strcmp(comm[1], "--help") == 0) { 3: 1352-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 2 1: 1352-block 1 branch 2 taken 1 (fallthrough) branch 3 taken 0 1: 1353: puts(_(SHELL_USAGE)); 1: 1353-block 0 call 0 returned 1 call 1 returned 1 1: 1354: return EXIT_SUCCESS; unconditional 0 taken 1 -: 1355: } else { 2: 1356: return (exit_code = set_shell(comm[1])); 2: 1356-block 0 call 0 returned 2 unconditional 1 taken 2 -: 1357: } -: 1358: } -: 1359: -: 1360: /* #### EDIT #### */ 100: 1361: else if (*comm[0] == 'e' && strcmp(comm[0], "edit") == 0) 100: 1361-block 0 branch 0 taken 9 (fallthrough) branch 1 taken 91 9: 1361-block 1 branch 2 taken 9 (fallthrough) branch 3 taken 0 9: 1362: return (exit_code = edit_function(comm)); 9: 1362-block 0 call 0 returned 9 unconditional 1 taken 9 -: 1363: -: 1364: /* #### HISTORY #### */ 91: 1365: else if (*comm[0] == 'h' && strcmp(comm[0], "history") == 0) 91: 1365-block 0 branch 0 taken 7 (fallthrough) branch 1 taken 84 7: 1365-block 1 branch 2 taken 1 (fallthrough) branch 3 taken 6 1: 1366: return (exit_code = history_function(comm)); 1: 1366-block 0 call 0 returned 1 unconditional 1 taken 1 -: 1367: -: 1368: /* #### HIDDEN FILES #### */ 90: 1369: else if (*comm[0] == 'h' && ((comm[0][1] == 'f' && !comm[0][2]) 90: 1369-block 0 branch 0 taken 6 (fallthrough) branch 1 taken 84 6: 1369-block 1 branch 2 taken 3 (fallthrough) branch 3 taken 3 3: 1369-block 2 branch 4 taken 0 (fallthrough) branch 5 taken 3 3: 1370: || strcmp(comm[0], "hidden") == 0)) { 3: 1370-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 3 3: 1371: if (!comm[1]) { 3: 1371-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 3 #####: 1372: fprintf(stderr, "%s\n", _(HF_USAGE)); %%%%%: 1372-block 0 call 0 never executed call 1 never executed #####: 1373: return (exit_code = EXIT_FAILURE); unconditional 0 never executed 3*: 1374: } else if (*comm[1] == '-' && strcmp(comm[1], "--help") == 0) { 3: 1374-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 3 %%%%%: 1374-block 1 branch 2 never executed branch 3 never executed -: 1375: /* The same message is in hidden_function(), and printed -: 1376: * whenever an invalid argument is entered */ #####: 1377: puts(_(HF_USAGE)); %%%%%: 1377-block 0 call 0 never executed call 1 never executed #####: 1378: return EXIT_SUCCESS; unconditional 0 never executed -: 1379: } else { 3: 1380: return (exit_code = hidden_function(comm)); 3: 1380-block 0 call 0 returned 3 unconditional 1 taken 3 -: 1381: } -: 1382: } -: 1383: -: 1384: /* #### AUTOCD #### */ 87: 1385: else if (*comm[0] == 'a' && (strcmp(comm[0], "acd") == 0 87: 1385-block 0 branch 0 taken 8 (fallthrough) branch 1 taken 79 8: 1385-block 1 branch 2 taken 5 (fallthrough) branch 3 taken 3 5: 1386: || strcmp(comm[0], "autocd") == 0)) { 5: 1386-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 5 3: 1387: if (!comm[1]) { 3: 1387-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 3 #####: 1388: fprintf(stderr, "%s\n", _(AUTOCD_USAGE)); %%%%%: 1388-block 0 call 0 never executed call 1 never executed #####: 1389: return (exit_code = EXIT_FAILURE); unconditional 0 never executed -: 1390: } -: 1391: 3: 1392: if (strcmp(comm[1], "on") == 0) { 3: 1392-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 2 1: 1393: autocd = 1; 1: 1394: printf(_("%s: autocd is enabled\n"), PROGRAM_NAME); 1: 1394-block 0 call 0 returned 1 call 1 returned 1 unconditional 2 taken 1 2: 1395: } else if (strcmp(comm[1], "off") == 0) { 2: 1395-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 1 1: 1396: autocd = 0; 1: 1397: printf(_("%s: autocd is disabled\n"), PROGRAM_NAME); 1: 1397-block 0 call 0 returned 1 call 1 returned 1 unconditional 2 taken 1 1: 1398: } else if (strcmp(comm[1], "status") == 0) { 1: 1398-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 0 1: 1399: if (autocd) 1: 1399-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 0 1: 1400: printf(_("%s: autocd is enabled\n"), PROGRAM_NAME); 1: 1400-block 0 call 0 returned 1 call 1 returned 1 unconditional 2 taken 1 -: 1401: else #####: 1402: printf(_("%s: autocd is disabled\n"), PROGRAM_NAME); %%%%%: 1402-block 0 call 0 never executed call 1 never executed unconditional 2 never executed #####: 1403: } else if (*comm[1] == '-' && strcmp(comm[1], "--help") == 0) { %%%%%: 1403-block 0 branch 0 never executed branch 1 never executed %%%%%: 1403-block 1 branch 2 never executed branch 3 never executed #####: 1404: puts(_(AUTOCD_USAGE)); %%%%%: 1404-block 0 call 0 never executed call 1 never executed unconditional 2 never executed -: 1405: } else { #####: 1406: fprintf(stderr, "%s\n", _(AUTOCD_USAGE)); %%%%%: 1406-block 0 call 0 never executed call 1 never executed #####: 1407: return (exit_code = EXIT_FAILURE); unconditional 0 never executed -: 1408: } 3: 1409: return EXIT_SUCCESS; 3: 1409-block 0 unconditional 0 taken 3 -: 1410: } -: 1411: -: 1412: /* #### AUTO-OPEN #### */ 84: 1413: else if (*comm[0] == 'a' && ((comm[0][1] == 'o' && !comm[0][2]) 84: 1413-block 0 branch 0 taken 5 (fallthrough) branch 1 taken 79 5: 1413-block 1 branch 2 taken 3 (fallthrough) branch 3 taken 2 3: 1413-block 2 branch 4 taken 0 (fallthrough) branch 5 taken 3 2: 1414: || strcmp(comm[0], "auto-open") == 0)) { 2: 1414-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 2 3: 1415: if (!comm[1]) { 3: 1415-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 3 #####: 1416: fprintf(stderr, "%s\n", _(AUTO_OPEN_USAGE)); %%%%%: 1416-block 0 call 0 never executed call 1 never executed #####: 1417: return (exit_code = EXIT_FAILURE); unconditional 0 never executed -: 1418: } -: 1419: 3: 1420: if (strcmp(comm[1], "on") == 0) { 3: 1420-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 2 1: 1421: auto_open = 1; 1: 1422: printf(_("%s: auto-open is enabled\n"), PROGRAM_NAME); 1: 1422-block 0 call 0 returned 1 call 1 returned 1 unconditional 2 taken 1 2: 1423: } else if (strcmp(comm[1], "off") == 0) { 2: 1423-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 1 1: 1424: auto_open = 0; 1: 1425: printf(_("%s: auto-open is disabled\n"), PROGRAM_NAME); 1: 1425-block 0 call 0 returned 1 call 1 returned 1 unconditional 2 taken 1 1: 1426: } else if (strcmp(comm[1], "status") == 0) { 1: 1426-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 0 1: 1427: if (auto_open) 1: 1427-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 0 1: 1428: printf(_("%s: auto-open is enabled\n"), PROGRAM_NAME); 1: 1428-block 0 call 0 returned 1 call 1 returned 1 unconditional 2 taken 1 -: 1429: else #####: 1430: printf(_("%s: auto-open is disabled\n"), PROGRAM_NAME); %%%%%: 1430-block 0 call 0 never executed call 1 never executed unconditional 2 never executed #####: 1431: } else if (strcmp(comm[1], "--help") == 0) { %%%%%: 1431-block 0 branch 0 never executed branch 1 never executed #####: 1432: puts(_(AUTO_OPEN_USAGE)); %%%%%: 1432-block 0 call 0 never executed call 1 never executed unconditional 2 never executed -: 1433: } else { #####: 1434: fprintf(stderr, "%s\n", _(AUTO_OPEN_USAGE)); %%%%%: 1434-block 0 call 0 never executed call 1 never executed #####: 1435: return (exit_code = EXIT_FAILURE); unconditional 0 never executed -: 1436: } 3: 1437: return EXIT_SUCCESS; 3: 1437-block 0 unconditional 0 taken 3 -: 1438: } -: 1439: -: 1440: /* #### COMMANDS #### */ 81: 1441: else if (*comm[0] == 'c' && (strcmp(comm[0], "cmd") == 0 81: 1441-block 0 branch 0 taken 5 (fallthrough) branch 1 taken 76 5: 1441-block 1 branch 2 taken 4 (fallthrough) branch 3 taken 1 4: 1442: || strcmp(comm[0], "commands") == 0)) 4: 1442-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 4 1: 1443: return (exit_code = list_commands()); 1: 1443-block 0 call 0 returned 1 unconditional 1 taken 1 -: 1444: -: 1445: /* #### AND THESE ONES TOO #### */ -: 1446: /* These functions just print stuff, so that the value of exit_code -: 1447: * is always zero, that is to say, success */ 80: 1448: else if (strcmp(comm[0], "path") == 0 || strcmp(comm[0], "cwd") == 0) { 80: 1448-block 0 branch 0 taken 79 (fallthrough) branch 1 taken 1 79: 1448-block 1 branch 2 taken 1 (fallthrough) branch 3 taken 78 2: 1449: printf("%s\n", ws[cur_ws].path); 2: 1449-block 0 call 0 returned 2 2: 1450: return EXIT_SUCCESS; unconditional 0 taken 2 -: 1451: } -: 1452: 78: 1453: else if ((*comm[0] == '?' && !comm[0][1]) || strcmp(comm[0], "help") == 0) { 78: 1453-block 0 branch 0 taken 36 (fallthrough) branch 1 taken 42 36: 1453-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 36 42: 1453-block 2 branch 4 taken 2 (fallthrough) branch 5 taken 40 38: 1454: help_function(); 38: 1454-block 0 call 0 returned 38 38: 1455: return EXIT_SUCCESS; unconditional 0 taken 38 -: 1456: } -: 1457: 40: 1458: else if (*comm[0] == 'c' && ((comm[0][1] == 'c' && !comm[0][2]) 40: 1458-block 0 branch 0 taken 3 (fallthrough) branch 1 taken 37 3: 1458-block 1 branch 2 taken 1 (fallthrough) branch 3 taken 2 1: 1458-block 2 branch 4 taken 0 (fallthrough) branch 5 taken 1 2: 1459: || strcmp(comm[0], "colors") == 0)) { 2: 1459-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 1 2*: 1460: if (comm[1] && *comm[1] == '-' && strcmp(comm[1], "--help") == 0) 2: 1460-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 2 %%%%%: 1460-block 1 branch 2 never executed branch 3 never executed %%%%%: 1460-block 2 branch 4 never executed branch 5 never executed #####: 1461: puts(_(COLORS_USAGE)); %%%%%: 1461-block 0 call 0 never executed call 1 never executed unconditional 2 never executed -: 1462: else 2: 1463: color_codes(); 2: 1463-block 0 call 0 returned 2 unconditional 1 taken 2 2: 1464: return EXIT_SUCCESS; 2: 1464-block 0 unconditional 0 taken 2 -: 1465: } -: 1466: 38: 1467: else if (*comm[0] == 'v' && (strcmp(comm[0], "ver") == 0 38: 1467-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 37 1: 1467-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 1 #####: 1468: || strcmp(comm[0], "version") == 0)) { %%%%%: 1468-block 0 branch 0 never executed branch 1 never executed 1: 1469: version_function(); 1: 1469-block 0 call 0 returned 1 1: 1470: return EXIT_SUCCESS; unconditional 0 taken 1 -: 1471: } -: 1472: 37: 1473: else if (*comm[0] == 'f' && comm[0][1] == 's' && !comm[0][2]) { 37: 1473-block 0 branch 0 taken 4 (fallthrough) branch 1 taken 33 4: 1473-block 1 branch 2 taken 1 (fallthrough) branch 3 taken 3 1: 1473-block 2 branch 4 taken 1 (fallthrough) branch 5 taken 0 1: 1474: free_software(); 1: 1474-block 0 call 0 returned 1 1: 1475: return EXIT_SUCCESS; unconditional 0 taken 1 -: 1476: } -: 1477: 36*: 1478: else if (*comm[0] == 'b' && strcmp(comm[0], "bonus") == 0) { 36: 1478-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 36 %%%%%: 1478-block 1 branch 2 never executed branch 3 never executed #####: 1479: bonus_function(); %%%%%: 1479-block 0 call 0 never executed #####: 1480: return EXIT_SUCCESS; unconditional 0 never executed -: 1481: } -: 1482: 36: 1483: else if (*comm[0] == 's' && strcmp(comm[0], "splash") == 0) { 36: 1483-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 35 1: 1483-block 1 branch 2 taken 1 (fallthrough) branch 3 taken 0 1: 1484: splash(); 1: 1484-block 0 call 0 returned 1 1: 1485: return EXIT_SUCCESS; unconditional 0 taken 1 -: 1486: } -: 1487: -: 1488: /* #### QUIT #### */ 35: 1489: else if ((*comm[0] == 'q' && !comm[0][1]) || strcmp(comm[0], "quit") == 0 35: 1489-block 0 branch 0 taken 4 (fallthrough) branch 1 taken 31 4: 1489-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 4 31: 1489-block 2 branch 4 taken 31 (fallthrough) branch 5 taken 0 31: 1490: || strcmp(comm[0], "exit") == 0) { 31: 1490-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 31 -: 1491: /* Free everything and exit */ 4: 1492: int i = (int)args_n + 1; 8: 1493: while (--i >= 0) 4: 1493-block 0 unconditional 0 taken 4 8: 1493-block 1 branch 1 taken 4 branch 2 taken 4 (fallthrough) 4: 1494: free(comm[i]); 4: 1494-block 0 unconditional 0 taken 4 4: 1495: free(comm); 4: 1496: exit(exit_code); 4: 1496-block 0 call 0 returned 0 -: 1497: } -: 1498: 31*: 1499: else if (*comm[0] == 'Q' && !comm[0][1]) { 31: 1499-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 31 %%%%%: 1499-block 1 branch 2 never executed branch 3 never executed #####: 1500: int i = (int)args_n + 1; #####: 1501: while (--i >= 0) %%%%%: 1501-block 0 unconditional 0 never executed %%%%%: 1501-block 1 branch 1 never executed branch 2 never executed #####: 1502: free(comm[i]); %%%%%: 1502-block 0 unconditional 0 never executed #####: 1503: free(comm); #####: 1504: cd_on_quit = 1; #####: 1505: exit(exit_code); %%%%%: 1505-block 0 call 0 never executed -: 1506: } -: 1507: -: 1508: else { -: 1509: -: 1510: /* ############################### -: 1511: * # AUTOCD & AUTO-OPEN (2) # -: 1512: * ############################### */ -: 1513: 31: 1514: if (autocd && cdpath_n && !comm[1] 31: 1514-block 0 branch 0 taken 30 (fallthrough) branch 1 taken 1 30: 1514-block 1 branch 2 taken 30 (fallthrough) branch 3 taken 0 30: 1514-block 2 branch 4 taken 26 (fallthrough) branch 5 taken 4 26: 1515: && cd_function(comm[0], CD_NO_PRINT_ERROR) == EXIT_SUCCESS) 26: 1515-block 0 call 0 returned 26 branch 1 taken 17 (fallthrough) branch 2 taken 9 24: 1516: return (exit_code = EXIT_SUCCESS); 17: 1516-block 0 unconditional 0 taken 17 24: 1516-block 1 unconditional 1 taken 24 -: 1517: -: 1518: struct stat file_attrib; 14: 1519: if (stat(comm[0], &file_attrib) == 0) { 14: 1519-block 0 call 0 returned 14 branch 1 taken 5 (fallthrough) branch 2 taken 9 5: 1520: if ((file_attrib.st_mode & S_IFMT) == S_IFDIR) { 5: 1520-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 4 1: 1521: if (autocd) 1: 1521-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 1 #####: 1522: return (exit_code = cd_function(comm[0], CD_PRINT_ERROR)); %%%%%: 1522-block 0 call 0 never executed unconditional 1 never executed -: 1523: 1: 1524: fprintf(stderr, _("%s: %s: Is a directory\n"), 1: 1524-block 0 call 0 returned 1 call 1 returned 1 -: 1525: PROGRAM_NAME, comm[0]); 1: 1526: return (exit_code = EXIT_FAILURE); unconditional 0 taken 1 4: 1527: } else if (auto_open && (file_attrib.st_mode & S_IFMT) == S_IFREG) { 4: 1527-block 0 branch 0 taken 3 (fallthrough) branch 1 taken 1 3: 1527-block 1 branch 2 taken 3 (fallthrough) branch 3 taken 0 -: 1528: /* Make sure we have not an executable file */ 3: 1529: if (!(file_attrib.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))) { 3: 1529-block 0 branch 0 taken 3 (fallthrough) branch 1 taken 0 9: 1530: char *cmd[] = {"open", comm[0], (args_n >= 1) ? comm[1] 3*: 1531: : NULL, (args_n >= 2) ? comm[2] : NULL, NULL}; 3: 1531-block 0 branch 0 taken 3 (fallthrough) branch 1 taken 0 3: 1531-block 1 unconditional 2 taken 3 %%%%%: 1531-block 2 unconditional 3 never executed 3: 1531-block 3 branch 4 taken 0 (fallthrough) branch 5 taken 3 %%%%%: 1531-block 4 unconditional 6 never executed 3: 1531-block 5 unconditional 7 taken 3 3: 1532: args_n++; 3: 1533: exit_code = open_function(cmd); 3: 1533-block 0 call 0 returned 3 3: 1534: args_n--; 3: 1535: return exit_code; unconditional 0 taken 3 -: 1536: } -: 1537: } -: 1538: } -: 1539: -: 1540: /* #################################################### -: 1541: * # EXTERNAL/SHELL COMMANDS # -: 1542: * ####################################################*/ -: 1543: -: 1544: /* LOG EXTERNAL COMMANDS -: 1545: * 'no_log' will be true when running profile or prompt commands */ 10: 1546: if (!no_log) 10: 1546-block 0 branch 0 taken 10 (fallthrough) branch 1 taken 0 10: 1547: exit_code = log_function(comm); 10: 1547-block 0 call 0 returned 10 unconditional 1 taken 10 -: 1548: -: 1549: /* PREVENT UNGRACEFUL EXIT */ -: 1550: /* Prevent the user from killing the program via the 'kill', -: 1551: * 'pkill' or 'killall' commands, from within CliFM itself. -: 1552: * Otherwise, the program will be forcefully terminated without -: 1553: * freeing allocated memory */ 10: 1554: if ((*comm[0] == 'k' || *comm[0] == 'p') && (strcmp(comm[0], "kill") == 0 || strcmp(comm[0], "killall") == 0 || strcmp(comm[0], "pkill") == 0)) { 10: 1554-block 0 branch 0 taken 9 (fallthrough) branch 1 taken 1 9: 1554-block 1 branch 2 taken 3 (fallthrough) branch 3 taken 6 4: 1554-block 2 branch 4 taken 4 (fallthrough) branch 5 taken 0 4: 1554-block 3 branch 6 taken 3 (fallthrough) branch 7 taken 1 3: 1554-block 4 branch 8 taken 0 (fallthrough) branch 9 taken 3 -: 1555: size_t i; 1*: 1556: for (i = 1; i <= args_n; i++) { 1: 1556-block 0 unconditional 0 taken 1 %%%%%: 1556-block 1 unconditional 1 never executed 1: 1556-block 2 branch 2 taken 1 branch 3 taken 0 (fallthrough) 1*: 1557: if ((strcmp(comm[0], "kill") == 0 && atoi(comm[i]) == (int)own_pid) || ((strcmp(comm[0], "killall") == 0 || strcmp(comm[0], "pkill") == 0) && strcmp(comm[i], argv_bk[0]) == 0)) { 1: 1557-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 1 %%%%%: 1557-block 1 branch 2 never executed branch 3 never executed 1: 1557-block 2 branch 4 taken 0 (fallthrough) branch 5 taken 1 %%%%%: 1557-block 3 branch 6 never executed branch 7 never executed 1: 1557-block 4 branch 8 taken 1 (fallthrough) branch 9 taken 0 1: 1558: fprintf(stderr, _("%s: To gracefully quit enter 'quit'\n"), 1: 1558-block 0 call 0 returned 1 call 1 returned 1 -: 1559: PROGRAM_NAME); 1: 1560: return (exit_code = EXIT_FAILURE); unconditional 0 taken 1 -: 1561: } -: 1562: } -: 1563: } -: 1564: -: 1565: /* CHECK WHETHER EXTERNAL COMMANDS ARE ALLOWED */ 9: 1566: if (!ext_cmd_ok) { 9: 1566-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 8 1: 1567: fprintf(stderr, _("%s: External commands are not allowed. " 1: 1567-block 0 call 0 returned 1 call 1 returned 1 -: 1568: "Run 'ext on' to enable them.\n"), PROGRAM_NAME); 1: 1569: return (exit_code = EXIT_FAILURE); unconditional 0 taken 1 -: 1570: } -: 1571: 8: 1572: if (*comm[0] == *argv_bk[0] && strcmp(comm[0], argv_bk[0]) == 0) { 8: 1572-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 7 1: 1572-block 1 branch 2 taken 1 (fallthrough) branch 3 taken 0 1: 1573: fprintf(stderr, "%s: Nested instances are not allowed\n", 1: 1573-block 0 call 0 returned 1 -: 1574: PROGRAM_NAME); 1: 1575: return EXIT_FAILURE; unconditional 0 taken 1 -: 1576: } -: 1577: -: 1578: /* -: 1579: * By making precede the command by a colon or a semicolon, the -: 1580: * user can BYPASS CliFM parsing, expansions, and checks to be -: 1581: * executed DIRECTLY by the system shell (execle). For example: -: 1582: * if the amount of files listed on the screen (ELN's) is larger -: 1583: * or equal than 644 and the user tries to issue this command: -: 1584: * "chmod 644 filename", CLIFM will take 644 to be an ELN, and -: 1585: * will thereby try to expand it into the corresponding file name, -: 1586: * which is not what the user wants. To prevent this, simply run -: 1587: * the command as follows: ";chmod 644 filename" */ -: 1588: 7: 1589: if (*comm[0] == ':' || *comm[0] == ';') { 7: 1589-block 0 branch 0 taken 7 (fallthrough) branch 1 taken 0 7: 1589-block 1 branch 2 taken 1 (fallthrough) branch 3 taken 6 -: 1590: /* Remove the colon from the beginning of the first argument, -: 1591: * that is, move the pointer to the next (second) position */ 1: 1592: char *comm_tmp = savestring(comm[0] + 1, strlen(comm[0] + 1)); 1: 1592-block 0 call 0 returned 1 -: 1593: /* If string == ":" or ";" */ 1: 1594: if (!comm_tmp || !*comm_tmp) { branch 0 taken 1 (fallthrough) branch 1 taken 0 1: 1594-block 0 branch 2 taken 0 (fallthrough) branch 3 taken 1 #####: 1595: fprintf(stderr, _("%s: '%c': Syntax error\n"), call 0 never executed #####: 1596: PROGRAM_NAME, *comm[0]); %%%%%: 1596-block 0 call 0 never executed #####: 1597: exit_code = EXIT_FAILURE; #####: 1598: if (comm_tmp) branch 0 never executed branch 1 never executed #####: 1599: free(comm_tmp); %%%%%: 1599-block 0 unconditional 0 never executed #####: 1600: return EXIT_FAILURE; %%%%%: 1600-block 0 unconditional 0 never executed -: 1601: } else { 1: 1602: strcpy(comm[0], comm_tmp); 1: 1603: free(comm_tmp); 1: 1603-block 0 unconditional 0 taken 1 -: 1604: } -: 1605: } -: 1606: -: 1607: /* #### RUN THE EXTERNAL COMMAND #### */ -: 1608: -: 1609: /* Store the command and each argument into a single array to be -: 1610: * executed by execle() using the system shell (/bin/sh -c) */ 7: 1611: char *ext_cmd = (char *)NULL; 7: 1612: size_t ext_cmd_len = strlen(comm[0]); 7: 1613: ext_cmd = (char *)xnmalloc(ext_cmd_len + 1, sizeof(char)); 7: 1613-block 0 call 0 returned 7 7: 1614: strcpy(ext_cmd, comm[0]); -: 1615: -: 1616: register size_t i; 7: 1617: if (args_n) { /* This will be false in case of ";cmd" or ":cmd" */ branch 0 taken 0 (fallthrough) branch 1 taken 7 #####: 1618: for (i = 1; i <= args_n; i++) { %%%%%: 1618-block 0 unconditional 0 never executed %%%%%: 1618-block 1 branch 1 never executed branch 2 never executed #####: 1619: ext_cmd_len += strlen(comm[i]) + 1; #####: 1620: ext_cmd = (char *)xrealloc(ext_cmd, (ext_cmd_len + 1) * sizeof(char)); %%%%%: 1620-block 0 call 0 never executed #####: 1621: strcat(ext_cmd, " "); #####: 1622: strcat(ext_cmd, comm[i]); unconditional 0 never executed -: 1623: } -: 1624: } -: 1625: -: 1626: /* Append final ampersand if background */ 7: 1627: if (bg_proc) { 7: 1627-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 7 #####: 1628: ext_cmd = (char *)xrealloc(ext_cmd, (ext_cmd_len + 2) * sizeof(char)); %%%%%: 1628-block 0 call 0 never executed #####: 1629: ext_cmd[ext_cmd_len] = '&'; #####: 1630: ext_cmd[ext_cmd_len + 1] = '\0'; unconditional 0 never executed -: 1631: } -: 1632: -: 1633: /* Since we modified LS_COLORS, store its current value and unset -: 1634: * it. Some shell commands use LS_COLORS to display their outputs -: 1635: * ("ls -l", for example, use the "no" value to print file -: 1636: * properties). So, we unset it to prevent wrong color output -: 1637: * for external commands. The disadvantage of this procedure is -: 1638: * that if the user uses a customized LS_COLORS, unsetting it -: 1639: * set its value to default, and the customization is lost. */ -: 1640: -: 1641:#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) -: 1642: char *my_ls_colors = (char *)NULL, *p = (char *)NULL; -: 1643: /* For some reason, when running on FreeBSD Valgrind complains -: 1644: * about overlapping source and destiny in setenv() if I just -: 1645: * copy the address returned by getenv() instead of the string -: 1646: * itself. Not sure why, but this makes the error go away */ -: 1647: p = getenv("LS_COLORS"); -: 1648: my_ls_colors = (char *)xnmalloc(strlen(p) + 1, sizeof(char *)); -: 1649: strcpy(my_ls_colors, p); -: 1650: p = (char *)NULL; -: 1651: -: 1652:#else -: 1653: static char *my_ls_colors = (char *)NULL; 7: 1654: my_ls_colors = getenv("LS_COLORS"); 7: 1654-block 0 call 0 returned 7 -: 1655:#endif -: 1656: 7: 1657: if (ls_colors_bk && *ls_colors_bk != '\0') branch 0 taken 6 (fallthrough) branch 1 taken 1 6: 1657-block 0 branch 2 taken 6 (fallthrough) branch 3 taken 0 6: 1658: setenv("LS_COLORS", ls_colors_bk, 1); 6: 1658-block 0 call 0 returned 6 unconditional 1 taken 6 -: 1659: else 1: 1660: unsetenv("LS_COLORS"); 1: 1660-block 0 call 0 returned 1 unconditional 1 taken 1 -: 1661: 7: 1662: if (launch_execle(ext_cmd) != EXIT_SUCCESS) 7: 1662-block 0 call 0 returned 7 branch 1 taken 6 (fallthrough) branch 2 taken 1 6: 1663: exit_code = EXIT_FAILURE; 6: 1663-block 0 unconditional 0 taken 6 7: 1664: free(ext_cmd); -: 1665: -: 1666: /* Restore LS_COLORS value to use CliFM colors */ 7: 1667: setenv("LS_COLORS", my_ls_colors, 1); 7: 1667-block 0 call 0 returned 7 -: 1668: -: 1669:#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) -: 1670: free(my_ls_colors); -: 1671:#endif -: 1672: -: 1673: /* Reload the list of available commands in PATH for TAB completion. -: 1674: * Why? If this list is not updated, whenever some new program is -: 1675: * installed, renamed, or removed from some of the paths in PATH -: 1676: * while in CliFM, this latter needs to be restarted in order -: 1677: * to be able to recognize the new program for TAB completion */ -: 1678: -: 1679: int j; 7: 1680: if (bin_commands) { branch 0 taken 7 (fallthrough) branch 1 taken 0 7: 1681: j = (int)path_progsn; 26222: 1682: while (--j >= 0) 7: 1682-block 0 unconditional 0 taken 7 26222: 1682-block 1 branch 1 taken 26215 branch 2 taken 7 (fallthrough) 26215: 1683: free(bin_commands[j]); 26215: 1683-block 0 unconditional 0 taken 26215 7: 1684: free(bin_commands); 7: 1685: bin_commands = (char **)NULL; 7: 1685-block 0 unconditional 0 taken 7 -: 1686: } -: 1687: 7: 1688: if (paths) { 7: 1688-block 0 branch 0 taken 7 (fallthrough) branch 1 taken 0 7: 1689: j = (int)path_n; 49: 1690: while (--j >= 0) 7: 1690-block 0 unconditional 0 taken 7 49: 1690-block 1 branch 1 taken 42 branch 2 taken 7 (fallthrough) 42: 1691: free(paths[j]); 42: 1691-block 0 unconditional 0 taken 42 -: 1692: } -: 1693: 7: 1694: path_n = (size_t)get_path_env(); 7: 1694-block 0 call 0 returned 7 7: 1695: get_path_programs(); call 0 returned 7 -: 1696: } -: 1697: 48: 1698:CHECK_EVENTS: 48: 1699: if (!cd_lists_on_the_fly) 48: 1699-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 48 #####: 1700: return exit_code; %%%%%: 1700-block 0 unconditional 0 never executed -: 1701: -: 1702:#ifdef LINUX_INOTIFY 48: 1703: if (watch) 48: 1703-block 0 branch 0 taken 48 (fallthrough) branch 1 taken 0 48: 1704: read_inotify(); 48: 1704-block 0 call 0 returned 48 unconditional 1 taken 48 -: 1705:#elif defined(BSD_KQUEUE) -: 1706: if (watch && event_fd >= 0) -: 1707: read_kqueue(); -: 1708:#endif -: 1709: 48: 1710: return exit_code; 48: 1710-block 0 unconditional 0 taken 48 -: 1711:} -: 1712: -: 1713:/* Execute chained commands (cmd1;cmd2 and/or cmd1 && cmd2). The function -: 1714: * is called by parse_input_str() if some non-quoted double ampersand or -: 1715: * semicolon is found in the input string AND at least one of these -: 1716: * chained commands is internal */ -: 1717:void function exec_chained_cmds called 0 returned 0% blocks executed 0% #####: 1718:exec_chained_cmds(char *cmd) -: 1719:{ #####: 1720: if (!cmd) %%%%%: 1720-block 0 branch 0 never executed branch 1 never executed #####: 1721: return; %%%%%: 1721-block 0 unconditional 0 never executed -: 1722: #####: 1723: size_t i = 0, cmd_len = strlen(cmd); #####: 1724: for (i = 0; i < cmd_len; i++) { %%%%%: 1724-block 0 unconditional 0 never executed %%%%%: 1724-block 1 unconditional 1 never executed %%%%%: 1724-block 2 branch 2 never executed branch 3 never executed #####: 1725: char *str = (char *)NULL; #####: 1726: size_t len = 0, cond_exec = 0; -: 1727: -: 1728: /* Get command */ #####: 1729: str = (char *)xcalloc(strlen(cmd) + 1, sizeof(char)); %%%%%: 1729-block 0 call 0 never executed #####: 1730: while (cmd[i] && cmd[i] != '&' && cmd[i] != ';') unconditional 0 never executed %%%%%: 1730-block 0 branch 1 never executed branch 2 never executed %%%%%: 1730-block 1 branch 3 never executed branch 4 never executed %%%%%: 1730-block 2 branch 5 never executed branch 6 never executed #####: 1731: str[len++] = cmd[i++]; %%%%%: 1731-block 0 unconditional 0 never executed -: 1732: #####: 1733: if (!*str) { %%%%%: 1733-block 0 branch 0 never executed branch 1 never executed #####: 1734: free(str); #####: 1735: continue; %%%%%: 1735-block 0 unconditional 0 never executed -: 1736: } -: 1737: -: 1738: /* Should we execute conditionally? */ #####: 1739: if (cmd[i] == '&') %%%%%: 1739-block 0 branch 0 never executed branch 1 never executed #####: 1740: cond_exec = 1; %%%%%: 1740-block 0 unconditional 0 never executed -: 1741: -: 1742: /* Execute the command */ #####: 1743: char **tmp_cmd = parse_input_str(str); %%%%%: 1743-block 0 call 0 never executed #####: 1744: free(str); -: 1745: #####: 1746: if (!tmp_cmd) branch 0 never executed branch 1 never executed #####: 1747: continue; %%%%%: 1747-block 0 unconditional 0 never executed -: 1748: #####: 1749: int error_code = 0; -: 1750: size_t j; #####: 1751: char **alias_cmd = check_for_alias(tmp_cmd); %%%%%: 1751-block 0 call 0 never executed #####: 1752: if (alias_cmd) { branch 0 never executed branch 1 never executed #####: 1753: if (exec_cmd(alias_cmd) != 0) %%%%%: 1753-block 0 call 0 never executed branch 1 never executed branch 2 never executed #####: 1754: error_code = 1; %%%%%: 1754-block 0 unconditional 0 never executed #####: 1755: for (j = 0; alias_cmd[j]; j++) %%%%%: 1755-block 0 unconditional 0 never executed %%%%%: 1755-block 1 branch 1 never executed branch 2 never executed #####: 1756: free(alias_cmd[j]); %%%%%: 1756-block 0 unconditional 0 never executed #####: 1757: free(alias_cmd); %%%%%: 1757-block 0 unconditional 0 never executed -: 1758: } else { #####: 1759: if (exec_cmd(tmp_cmd) != 0) %%%%%: 1759-block 0 call 0 never executed branch 1 never executed branch 2 never executed #####: 1760: error_code = 1; %%%%%: 1760-block 0 unconditional 0 never executed #####: 1761: for (j = 0; j <= args_n; j++) %%%%%: 1761-block 0 unconditional 0 never executed %%%%%: 1761-block 1 branch 1 never executed branch 2 never executed #####: 1762: free(tmp_cmd[j]); %%%%%: 1762-block 0 unconditional 0 never executed #####: 1763: free(tmp_cmd); %%%%%: 1763-block 0 unconditional 0 never executed -: 1764: } -: 1765: /* Do not continue if the execution was condtional and -: 1766: * the previous command failed */ #####: 1767: if (cond_exec && error_code) %%%%%: 1767-block 0 branch 0 never executed branch 1 never executed %%%%%: 1767-block 1 branch 2 never executed branch 3 never executed #####: 1768: break; %%%%%: 1768-block 0 unconditional 0 never executed -: 1769: } -: 1770:} -: 1771: -: 1772:void function exec_profile called 13 returned 100% blocks executed 45% 13: 1773:exec_profile(void) -: 1774:{ 13: 1775: if (!config_ok || !profile_file) 13: 1775-block 0 branch 0 taken 13 (fallthrough) branch 1 taken 0 13: 1775-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 13 #####: 1776: return; %%%%%: 1776-block 0 unconditional 0 never executed %%%%%: 1776-block 1 unconditional 1 never executed -: 1777: 13: 1778: FILE *fp = fopen(profile_file, "r"); 13: 1778-block 0 call 0 returned 13 13: 1779: if (!fp) branch 0 taken 0 (fallthrough) branch 1 taken 13 #####: 1780: return; %%%%%: 1780-block 0 unconditional 0 never executed -: 1781: 13: 1782: size_t line_size = 0; 13: 1783: char *line = (char *)NULL; 13: 1784: ssize_t line_len = 0; -: 1785: 71: 1786: while ((line_len = getline(&line, &line_size, fp)) > 0) { 13: 1786-block 0 unconditional 0 taken 13 71: 1786-block 1 call 1 returned 71 branch 2 taken 58 branch 3 taken 13 (fallthrough) -: 1787: /* Skip empty and commented lines */ 58: 1788: if (!*line || *line == '\n' || *line == '#') 58: 1788-block 0 branch 0 taken 58 (fallthrough) branch 1 taken 0 58: 1788-block 1 branch 2 taken 58 (fallthrough) branch 3 taken 0 58: 1788-block 2 branch 4 taken 58 (fallthrough) branch 5 taken 0 58: 1789: continue; 58: 1789-block 0 unconditional 0 taken 58 -: 1790: -: 1791: /* Remove trailing new line char */ #####: 1792: if (line[line_len - 1] == '\n') %%%%%: 1792-block 0 branch 0 never executed branch 1 never executed #####: 1793: line[line_len - 1] = '\0'; %%%%%: 1793-block 0 unconditional 0 never executed -: 1794: #####: 1795: if (strchr(line, '=') && !_ISDIGIT(*line)) { %%%%%: 1795-block 0 branch 0 never executed branch 1 never executed %%%%%: 1795-block 1 branch 2 never executed branch 3 never executed #####: 1796: create_usr_var(line); %%%%%: 1796-block 0 call 0 never executed unconditional 1 never executed #####: 1797: } else if (strlen(line) != 0) { %%%%%: 1797-block 0 branch 0 never executed branch 1 never executed -: 1798: /* Parse line and execute it */ #####: 1799: args_n = 0; -: 1800: #####: 1801: char **cmds = parse_input_str(line); %%%%%: 1801-block 0 call 0 never executed -: 1802: #####: 1803: if (cmds) { branch 0 never executed branch 1 never executed #####: 1804: no_log = 1; #####: 1805: exec_cmd(cmds); %%%%%: 1805-block 0 call 0 never executed #####: 1806: no_log = 0; #####: 1807: int i = (int)args_n + 1; #####: 1808: while (--i >= 0) unconditional 0 never executed %%%%%: 1808-block 0 branch 1 never executed branch 2 never executed #####: 1809: free(cmds[i]); %%%%%: 1809-block 0 unconditional 0 never executed #####: 1810: free(cmds); #####: 1811: cmds = (char **)NULL; %%%%%: 1811-block 0 unconditional 0 never executed -: 1812: } #####: 1813: args_n = 0; %%%%%: 1813-block 0 unconditional 0 never executed -: 1814: } -: 1815: } -: 1816: 13: 1817: free(line); 13: 1818: fclose(fp); 13: 1818-block 0 call 0 returned 13 -: 1819:} clifm-1.26.3/misc/codecov/file_operations.c.gcov000066400000000000000000002142641506632037700215570ustar00rootroot00000000000000 -: 0:Source:file_operations.c -: 1:/* file_operations.c -- control multiple file operations */ -: 2: -: 3:/* -: 4: * This file is part of CliFM -: 5: * -: 6: * Copyright (C) 2016-2021, L. Abramovich -: 7: * All rights reserved. -: 8: -: 9: * CliFM is free software; you can redistribute it and/or modify -: 10: * it under the terms of the GNU General Public License as published by -: 11: * the Free Software Foundation; either version 2 of the License, or -: 12: * (at your option) any later version. -: 13: * -: 14: * CliFM is distributed in the hope that it will be useful, -: 15: * but WITHOUT ANY WARRANTY; without even the implied warranty of -: 16: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -: 17: * GNU General Public License for more details. -: 18: * -: 19: * You should have received a copy of the GNU General Public License -: 20: * along with this program; if not, write to the Free Software -: 21: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, -: 22: * MA 02110-1301, USA. -: 23:*/ -: 24: -: 25:#include "helpers.h" -: 26: -: 27:#include -: 28:#include -: 29:#include -: 30:#include -: 31:#include -: 32:#include -: 33:#include -: 34: -: 35:#include -: 36: -: 37:#ifndef _NO_ARCHIVING -: 38:#include "archives.h" -: 39:#endif -: 40:#include "aux.h" -: 41:#include "checks.h" -: 42:#include "colors.h" -: 43:#include "exec.h" -: 44:#include "file_operations.h" -: 45:#include "history.h" -: 46:#include "listing.h" -: 47:#include "mime.h" -: 48:#include "misc.h" -: 49:#include "navigation.h" -: 50:#include "readline.h" -: 51:#include "selection.h" -: 52:#include "messages.h" -: 53: -: 54:/* Open a file via OPENER, if set, or via LIRA. If not compiled with -: 55: * Lira support, fallback to open (Haiku), or xdg-open. Returns zero -: 56: * on success and one on failure */ -: 57:int function open_file called 38 returned 100% blocks executed 58% 38: 58:open_file(char *file) -: 59:{ 38: 60: if (!file || !*file) 38: 60-block 0 branch 0 taken 38 (fallthrough) branch 1 taken 0 38: 60-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 38 #####: 61: return EXIT_FAILURE; %%%%%: 61-block 0 unconditional 0 never executed -: 62: 38: 63: int exit_status = EXIT_SUCCESS; -: 64: 38: 65: if (opener) { 38: 65-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 38 #####: 66: char *cmd[] = {opener, file, NULL}; #####: 67: if (launch_execve(cmd, FOREGROUND, E_NOSTDERR) != EXIT_SUCCESS) %%%%%: 67-block 0 call 0 never executed branch 1 never executed branch 2 never executed #####: 68: exit_status = EXIT_FAILURE; %%%%%: 68-block 0 unconditional 0 never executed -: 69: } else { -: 70:#ifndef _NO_LIRA 38: 71: char *cmd[] = {"mm", file, NULL}; 38: 72: exit_status = mime_open(cmd); 38: 72-block 0 call 0 returned 38 -: 73:#else -: 74: /* Fallback to (xdg-)open */ -: 75:#ifdef __HAIKU__ -: 76: char *cmd[] = {"open", file, NULL}; -: 77:#else -: 78: char *cmd[] = {"xdg-open", file, NULL}; -: 79:#endif /* __HAIKU__ */ -: 80: if (launch_execve(cmd, FOREGROUND, E_NOSTDERR) != EXIT_SUCCESS) -: 81: exit_status = EXIT_FAILURE; -: 82:#endif /* _NO_LIRA */ -: 83: } -: 84: 38: 85: return exit_status; 38: 85-block 0 unconditional 0 taken 38 -: 86:} -: 87: -: 88:/* Toggle executable bit on file */ -: 89:int function xchmod called 2 returned 100% blocks executed 73% 2: 90:xchmod(const char *file, mode_t mode) -: 91:{ -: 92: /* Set or unset S_IXUSR, S_IXGRP, and S_IXOTH */ 2: 93: (0100 & mode) ? (mode &= (mode_t)~0111) : (mode |= 0111); 2: 93-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 1 1: 93-block 1 unconditional 2 taken 1 1: 93-block 2 unconditional 3 taken 1 -: 94: 2: 95: log_function(NULL); 2: 95-block 0 call 0 returned 2 -: 96: 2: 97: if (chmod(file, mode) == -1) { call 0 returned 2 branch 1 taken 0 (fallthrough) branch 2 taken 2 #####: 98: fprintf(stderr, "%s: %s: %s\n", PROGRAM_NAME, file, strerror(errno)); %%%%%: 98-block 0 call 0 never executed call 1 never executed #####: 99: return EXIT_FAILURE; unconditional 0 never executed -: 100: } -: 101: 2: 102: return EXIT_SUCCESS; 2: 102-block 0 unconditional 0 taken 2 -: 103:} -: 104: -: 105:/* Create a duplicate of a file/dir using rsync or cp */ -: 106:int function dup_file called 2 returned 100% blocks executed 31% 2: 107:dup_file(char *source, char *dest) -: 108:{ 2: 109: if (!source || !*source) 2: 109-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 0 2: 109-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 2 #####: 110: return EXIT_FAILURE; %%%%%: 110-block 0 unconditional 0 never executed -: 111: 2: 112: log_function(NULL); 2: 112-block 0 call 0 returned 2 -: 113: 2: 114: if (strchr(source, '\\')) { branch 0 taken 0 (fallthrough) branch 1 taken 2 #####: 115: char *deq_str = dequote_str(source, 0); %%%%%: 115-block 0 call 0 never executed #####: 116: if (!deq_str) { branch 0 never executed branch 1 never executed #####: 117: fprintf(stderr, "%s: %s: Error dequoting file name\n", %%%%%: 117-block 0 call 0 never executed -: 118: PROGRAM_NAME, source); #####: 119: return EXIT_FAILURE; unconditional 0 never executed -: 120: } #####: 121: strcpy(source, deq_str); #####: 122: free(deq_str); %%%%%: 122-block 0 unconditional 0 never executed -: 123: } -: 124: 2: 125: if (dest) { 2: 125-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 0 2: 126: if (strchr(dest, '\\')) { 2: 126-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 2 #####: 127: char *deq_str = dequote_str(dest, 0); %%%%%: 127-block 0 call 0 never executed #####: 128: if (!deq_str) { branch 0 never executed branch 1 never executed #####: 129: fprintf(stderr, "%s: %s: Error dequoting file name\n", %%%%%: 129-block 0 call 0 never executed -: 130: PROGRAM_NAME, source); #####: 131: return EXIT_FAILURE; unconditional 0 never executed -: 132: } #####: 133: strcpy(dest, deq_str); #####: 134: free(deq_str); %%%%%: 134-block 0 unconditional 0 never executed -: 135: } -: 136: } -: 137: 2: 138: int exit_status = EXIT_SUCCESS; 2: 139: int free_dest = 0; -: 140: -: 141: /* If no dest, use source as file name: source.copy, and, if already -: 142: * exists, source.copy.YYYYMMDDHHMMSS */ 2: 143: if (!dest) { 2: 143-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 2 #####: 144: size_t source_len = strlen(source); #####: 145: if (strcmp(source, "/") != 0 && source[source_len - 1] == '/') %%%%%: 145-block 0 branch 0 never executed branch 1 never executed %%%%%: 145-block 1 branch 2 never executed branch 3 never executed #####: 146: source[source_len - 1] = '\0'; %%%%%: 146-block 0 unconditional 0 never executed -: 147: #####: 148: char *tmp = strrchr(source, '/'); -: 149: char *source_name; -: 150: #####: 151: if (tmp && *(tmp + 1)) %%%%%: 151-block 0 branch 0 never executed branch 1 never executed %%%%%: 151-block 1 branch 2 never executed branch 3 never executed #####: 152: source_name = tmp + 1; %%%%%: 152-block 0 unconditional 0 never executed -: 153: else #####: 154: source_name = source; %%%%%: 154-block 0 unconditional 0 never executed -: 155: #####: 156: free_dest = 1; #####: 157: dest = (char *)xnmalloc(strlen(source_name) + 6, sizeof(char)); %%%%%: 157-block 0 call 0 never executed #####: 158: sprintf(dest, "%s.copy", source_name); -: 159: -: 160: struct stat attr; #####: 161: if (stat(dest, &attr) == EXIT_SUCCESS) { call 0 never executed branch 1 never executed branch 2 never executed #####: 162: time_t rawtime = time(NULL); %%%%%: 162-block 0 call 0 never executed -: 163: struct tm tm; #####: 164: localtime_r(&rawtime, &tm); call 0 never executed #####: 165: char date[64] = ""; #####: 166: strftime(date, sizeof(date), "%b %d %H:%M:%S %Y", &tm); -: 167: #####: 168: char suffix[68] = ""; #####: 169: snprintf(suffix, 67, "%d%d%d%d%d%d", tm.tm_year + 1900, #####: 170: tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, -: 171: tm.tm_sec); -: 172: -: 173: char tmp_dest[PATH_MAX]; #####: 174: xstrsncpy(tmp_dest, dest, PATH_MAX); call 0 never executed #####: 175: dest = (char *)xrealloc(dest, (strlen(tmp_dest) + strlen(suffix) + 2) call 0 never executed -: 176: * sizeof(char)); #####: 177: sprintf(dest, "%s.%s", tmp_dest, suffix); unconditional 0 never executed -: 178: } -: 179: } -: 180: 2: 181: char *rsync_path = get_cmd_path("rsync"); 2: 181-block 0 call 0 returned 2 2: 182: if (rsync_path) { branch 0 taken 2 (fallthrough) branch 1 taken 0 2: 183: char *cmd[] = {"rsync", "-aczvAXHS", "--progress", source, dest, NULL}; 2: 184: if (launch_execve(cmd, FOREGROUND, E_NOFLAG) != EXIT_SUCCESS) 2: 184-block 0 call 0 returned 2 branch 1 taken 0 (fallthrough) branch 2 taken 2 #####: 185: exit_status = EXIT_FAILURE; %%%%%: 185-block 0 unconditional 0 never executed 2: 186: free(rsync_path); 2: 186-block 0 unconditional 0 taken 2 -: 187: } else { #####: 188: char *cmd[] = {"cp", "-a", source, dest, NULL}; #####: 189: if (launch_execve(cmd, FOREGROUND, E_NOFLAG) != EXIT_SUCCESS) %%%%%: 189-block 0 call 0 never executed branch 1 never executed branch 2 never executed #####: 190: exit_status = EXIT_FAILURE; %%%%%: 190-block 0 unconditional 0 never executed -: 191: } -: 192: 2: 193: if (free_dest) 2: 193-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 2 #####: 194: free(dest); %%%%%: 194-block 0 unconditional 0 never executed 2: 195: return exit_status; 2: 195-block 0 unconditional 0 taken 2 -: 196:} -: 197: -: 198:int function create_file called 2 returned 100% blocks executed 44% 2: 199:create_file(char **cmd) -: 200:{ 2*: 201: if (cmd[1] && *cmd[1] == '-' && strcmp(cmd[1], "--help") == 0) { 2: 201-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 0 2: 201-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 2 %%%%%: 201-block 2 branch 4 never executed branch 5 never executed #####: 202: puts(_(NEW_USAGE)); %%%%%: 202-block 0 call 0 never executed call 1 never executed #####: 203: return EXIT_FAILURE; unconditional 0 never executed -: 204: } -: 205: 2: 206: log_function(NULL); 2: 206-block 0 call 0 returned 2 -: 207: 2: 208: int exit_status = EXIT_SUCCESS; -: 209:#ifdef __HAIKU__ -: 210: int file_in_cwd = 0; -: 211:#endif 2: 212: int free_cmd = 0; -: 213: -: 214: /* If no argument provided, ask the user for a filename */ 2: 215: if (!cmd[1]) { branch 0 taken 0 (fallthrough) branch 1 taken 2 #####: 216: char *filename = (char *)NULL; #####: 217: while (!filename) { %%%%%: 217-block 0 unconditional 0 never executed %%%%%: 217-block 1 branch 1 never executed branch 2 never executed #####: 218: puts(_("End filename with a slash to create a directory")); %%%%%: 218-block 0 call 0 never executed call 1 never executed #####: 219: filename = rl_no_hist(_("Filename ('q' to quit): ")); call 0 never executed call 1 never executed -: 220: #####: 221: if (!filename) branch 0 never executed branch 1 never executed #####: 222: continue; %%%%%: 222-block 0 unconditional 0 never executed -: 223: #####: 224: if (!*filename) { %%%%%: 224-block 0 branch 0 never executed branch 1 never executed #####: 225: free(filename); #####: 226: filename = (char *)NULL; #####: 227: continue; %%%%%: 227-block 0 unconditional 0 never executed -: 228: } -: 229: } -: 230: #####: 231: if (*filename == 'q' && !filename[1]) { %%%%%: 231-block 0 branch 0 never executed branch 1 never executed %%%%%: 231-block 1 branch 2 never executed branch 3 never executed #####: 232: free(filename); #####: 233: return EXIT_SUCCESS; %%%%%: 233-block 0 unconditional 0 never executed -: 234: } -: 235: -: 236: /* Once we have the filename, reconstruct the cmd array */ #####: 237: char **tmp_cmd = (char **)xnmalloc(args_n + 3, sizeof(char *)); %%%%%: 237-block 0 call 0 never executed #####: 238: tmp_cmd[0] = (char *)xnmalloc(2, sizeof(char)); call 0 never executed #####: 239: *tmp_cmd[0] = 'n'; #####: 240: tmp_cmd[0][1] = '\0'; #####: 241: tmp_cmd[1] = (char *)xnmalloc(strlen(filename) + 1, sizeof(char)); call 0 never executed #####: 242: strcpy(tmp_cmd[1], filename); #####: 243: tmp_cmd[2] = (char *)NULL; #####: 244: cmd = tmp_cmd; #####: 245: free_cmd = 1; #####: 246: free(filename); unconditional 0 never executed -: 247: } -: 248: -: 249: /* Properly format filenames */ -: 250: size_t i; 5: 251: for (i = 1; cmd[i]; i++) { 2: 251-block 0 unconditional 0 taken 2 3: 251-block 1 unconditional 1 taken 3 5: 251-block 2 branch 2 taken 3 branch 3 taken 2 (fallthrough) 3: 252: if (strchr(cmd[i], '\\')) { 3: 252-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 3 #####: 253: char *deq_str = dequote_str(cmd[i], 0); %%%%%: 253-block 0 call 0 never executed #####: 254: if (!deq_str) { branch 0 never executed branch 1 never executed #####: 255: _err('w', PRINT_PROMPT, _("%s: %s: Error dequoting filename\n"), call 0 never executed #####: 256: PROGRAM_NAME, cmd[i]); %%%%%: 256-block 0 call 0 never executed #####: 257: continue; unconditional 0 never executed -: 258: } -: 259: #####: 260: strcpy(cmd[i], deq_str); #####: 261: free(deq_str); %%%%%: 261-block 0 unconditional 0 never executed -: 262: } -: 263: 3: 264: if (*cmd[i] == '~') { 3: 264-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 3 #####: 265: char *exp_path = tilde_expand(cmd[i]); %%%%%: 265-block 0 call 0 never executed #####: 266: if (exp_path) { branch 0 never executed branch 1 never executed #####: 267: cmd[i] = (char *)xrealloc(cmd[i], (strlen(exp_path) + 1) %%%%%: 267-block 0 call 0 never executed -: 268: * sizeof(char)); #####: 269: strcpy(cmd[i], exp_path); #####: 270: free(exp_path); unconditional 0 never executed -: 271: } -: 272: } -: 273: -: 274:#ifdef __HAIKU__ -: 275: /* If at least one filename lacks a slash (or it is the last char, -: 276: * in which case we have a directory in CWD), we are creating a -: 277: * file in CWD, and thereby we need to update the screen */ -: 278: char *ret = strrchr(cmd[i], '/'); -: 279: if (!ret || !*(ret + 1)) -: 280: file_in_cwd = 1; -: 281:#endif -: 282: } -: 283: -: 284: /* Construct commands */ 2: 285: size_t files_num = i - 1; -: 286: 2: 287: char **nfiles = (char **)xnmalloc(files_num + 2, sizeof(char *)); 2: 287-block 0 call 0 returned 2 2: 288: char **ndirs = (char **)xnmalloc(files_num + 3, sizeof(char *)); call 0 returned 2 -: 289: -: 290: /* Let's use 'touch' for files and 'mkdir -p' for dirs */ 2: 291: nfiles[0] = (char *)xnmalloc(6, sizeof(char)); call 0 returned 2 2: 292: strcpy(nfiles[0], "touch"); -: 293: 2: 294: ndirs[0] = (char *)xnmalloc(6, sizeof(char)); call 0 returned 2 2: 295: strcpy(ndirs[0], "mkdir"); -: 296: 2: 297: ndirs[1] = (char *)xnmalloc(3, sizeof(char)); call 0 returned 2 2: 298: ndirs[1][0] = '-'; 2: 299: ndirs[1][1] = 'p'; 2: 300: ndirs[1][2] = '\0'; -: 301: 2: 302: size_t cnfiles = 1, cndirs = 2; -: 303: 5: 304: for (i = 1; cmd[i]; i++) { unconditional 0 taken 2 3: 304-block 0 unconditional 1 taken 3 5: 304-block 1 branch 2 taken 3 branch 3 taken 2 (fallthrough) 3: 305: size_t cmd_len = strlen(cmd[i]); -: 306: /* Filenames ending with a slash are taken as dir names */ 3: 307: if (cmd[i][cmd_len - 1] == '/') 3: 307-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 1 2: 308: ndirs[cndirs++] = cmd[i]; 2: 308-block 0 unconditional 0 taken 2 -: 309: else 1: 310: nfiles[cnfiles++] = cmd[i]; 1: 310-block 0 unconditional 0 taken 1 -: 311: } -: 312: 2: 313: ndirs[cndirs] = (char *)NULL; 2: 314: nfiles[cnfiles] = (char *)NULL; -: 315: -: 316: /* Execute commands */ 2: 317: if (cnfiles > 1) { 2: 317-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 1 1: 318: if (launch_execve(nfiles, FOREGROUND, 0) != EXIT_SUCCESS) 1: 318-block 0 call 0 returned 1 branch 1 taken 0 (fallthrough) branch 2 taken 1 #####: 319: exit_status = EXIT_FAILURE; %%%%%: 319-block 0 unconditional 0 never executed -: 320: } -: 321: 2: 322: if (cndirs > 2) { 2: 322-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 0 2: 323: if (launch_execve(ndirs, FOREGROUND, 0) != EXIT_SUCCESS) 2: 323-block 0 call 0 returned 2 branch 1 taken 0 (fallthrough) branch 2 taken 2 #####: 324: exit_status = EXIT_FAILURE; %%%%%: 324-block 0 unconditional 0 never executed -: 325: } -: 326: 2: 327: free(nfiles[0]); 2: 328: free(ndirs[0]); 2: 329: free(ndirs[1]); 2: 330: free(nfiles); 2: 331: free(ndirs); 2: 332: if (free_cmd) { 2: 332-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 2 #####: 333: for (i = 0; cmd[i]; i++) %%%%%: 333-block 0 unconditional 0 never executed %%%%%: 333-block 1 branch 1 never executed branch 2 never executed #####: 334: free(cmd[i]); %%%%%: 334-block 0 unconditional 0 never executed #####: 335: free(cmd); %%%%%: 335-block 0 unconditional 0 never executed -: 336: } -: 337: -: 338:#ifdef __HAIKU__ -: 339: if (exit_status == EXIT_SUCCESS && cd_lists_on_the_fly && file_in_cwd) { -: 340: free_dirlist(); -: 341: if (list_dir() != EXIT_SUCCESS) -: 342: exit_status = EXIT_FAILURE; -: 343: } -: 344:#endif -: 345: 2: 346: return exit_status; 2: 346-block 0 unconditional 0 taken 2 -: 347:} -: 348: -: 349:int function open_function called 19 returned 100% blocks executed 55% 19: 350:open_function(char **cmd) -: 351:{ 19: 352: if (!cmd) 19: 352-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 19 #####: 353: return EXIT_FAILURE; %%%%%: 353-block 0 unconditional 0 never executed -: 354: 19: 355: if (*cmd[0] == 'o' && (!cmd[0][1] || strcmp(cmd[0], "open") == 0)) { 19: 355-block 0 branch 0 taken 19 (fallthrough) branch 1 taken 0 19: 355-block 1 branch 2 taken 13 (fallthrough) branch 3 taken 6 13: 355-block 2 branch 4 taken 13 (fallthrough) branch 5 taken 0 19: 356: if (strchr(cmd[1], '\\')) { 19: 356-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 19 #####: 357: char *deq_path = dequote_str(cmd[1], 0); %%%%%: 357-block 0 call 0 never executed #####: 358: if (!deq_path) { branch 0 never executed branch 1 never executed #####: 359: fprintf(stderr, _("%s: %s: Error dequoting filename\n"), call 0 never executed #####: 360: PROGRAM_NAME, cmd[1]); %%%%%: 360-block 0 call 0 never executed #####: 361: return EXIT_FAILURE; unconditional 0 never executed -: 362: } -: 363: #####: 364: strcpy(cmd[1], deq_path); #####: 365: free(deq_path); %%%%%: 365-block 0 unconditional 0 never executed -: 366: } -: 367: } -: 368: 19: 369: char *file = cmd[1]; -: 370: -: 371: /* Check file existence */ -: 372: struct stat attr; 19: 373: if (stat(file, &attr) == -1) { 19: 373-block 0 call 0 returned 19 branch 1 taken 3 (fallthrough) branch 2 taken 16 3: 374: fprintf(stderr, "%s: open: %s: %s\n", PROGRAM_NAME, cmd[1], call 0 returned 3 3: 375: strerror(errno)); 3: 375-block 0 call 0 returned 3 3: 376: return EXIT_FAILURE; unconditional 0 taken 3 -: 377: } -: 378: -: 379: /* Check file type: only directories, symlinks, and regular files -: 380: * will be opened */ -: 381: 16: 382: char no_open_file = 1, file_type[128]; -: 383: /* Reserve a good amount of bytes for file type: it cannot be -: 384: * known beforehand how many bytes the TRANSLATED string will -: 385: * need */ -: 386: 16: 387: switch ((attr.st_mode & S_IFMT)) { 16: 387-block 0 branch 0 taken 0 branch 1 taken 0 branch 2 taken 0 branch 3 taken 0 branch 4 taken 3 branch 5 taken 13 branch 6 taken 0 -: 388: /* Store file type to compose and print the error message, if -: 389: * necessary */ #####: 390: case S_IFBLK: strcpy(file_type, _("block device")); break; %%%%%: 390-block 0 call 0 never executed unconditional 1 never executed #####: 391: case S_IFCHR: strcpy(file_type, _("character device")); break; %%%%%: 391-block 0 call 0 never executed unconditional 1 never executed #####: 392: case S_IFSOCK: strcpy(file_type, _("socket")); break; %%%%%: 392-block 0 call 0 never executed unconditional 1 never executed #####: 393: case S_IFIFO: strcpy(file_type, _("FIFO/pipe")); break; %%%%%: 393-block 0 call 0 never executed unconditional 1 never executed 3: 394: case S_IFDIR: return cd_function(file, CD_PRINT_ERROR); 3: 394-block 0 call 0 returned 3 unconditional 1 taken 3 13: 395: case S_IFREG: -: 396:#ifndef _NO_ARCHIVING -: 397: /* If an archive/compressed file, call archiver() */ 13: 398: if (is_compressed(file, 1) == 0) { 13: 398-block 0 call 0 returned 13 branch 1 taken 4 (fallthrough) branch 2 taken 9 4: 399: char *tmp_cmd[] = {"ad", file, NULL}; 4: 400: return archiver(tmp_cmd, 'd'); 4: 400-block 0 call 0 returned 4 unconditional 1 taken 4 -: 401: } -: 402:#endif 9: 403: no_open_file = 0; 9: 404: break; 9: 404-block 0 unconditional 0 taken 9 -: 405: #####: 406: default: #####: 407: strcpy(file_type, _("unknown file type")); %%%%%: 407-block 0 call 0 never executed #####: 408: break; unconditional 0 never executed -: 409: } -: 410: -: 411: /* If neither directory nor regular file nor symlink (to directory -: 412: * or regular file), print the corresponding error message and -: 413: * exit */ 9: 414: if (no_open_file) { 9: 414-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 9 #####: 415: fprintf(stderr, _("%s: %s (%s): Cannot open file. Try " call 0 never executed #####: 416: "'APPLICATION FILENAME'.\n"), PROGRAM_NAME, cmd[1], file_type); %%%%%: 416-block 0 call 0 never executed #####: 417: return EXIT_FAILURE; unconditional 0 never executed -: 418: } -: 419: -: 420: /* At this point we know the file to be openend is either a regular -: 421: * file or a symlink to a regular file. So, just open the file */ 9*: 422: if (!cmd[2] || (*cmd[2] == '&' && !cmd[2][1])) { 9: 422-block 0 branch 0 taken 3 (fallthrough) branch 1 taken 6 3: 422-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 3 %%%%%: 422-block 2 branch 4 never executed branch 5 never executed 6: 423: int ret = open_file(file); 6: 423-block 0 call 0 returned 6 6: 424: if (!opener && ret == EXIT_FAILURE) { branch 0 taken 6 (fallthrough) branch 1 taken 0 6: 424-block 0 branch 2 taken 0 (fallthrough) branch 3 taken 6 #####: 425: fputs("Add a new entry to the mimelist file ('mime " %%%%%: 425-block 0 call 0 never executed -: 426: "edit' or F6) or run 'open FILE APPLICATION'\n", stderr); #####: 427: return EXIT_FAILURE; unconditional 0 never executed -: 428: } 6: 429: return ret; 6: 429-block 0 unconditional 0 taken 6 -: 430: } -: 431: -: 432: /* If some application was specified to open the file */ 3: 433: char *tmp_cmd[] = {cmd[2], file, NULL}; 3: 434: int ret = launch_execve(tmp_cmd, bg_proc ? BACKGROUND : FOREGROUND, E_NOSTDERR); 3: 434-block 0 call 0 returned 3 3: 435: if (ret != EXIT_SUCCESS) branch 0 taken 0 (fallthrough) branch 1 taken 3 #####: 436: return EXIT_FAILURE; %%%%%: 436-block 0 unconditional 0 never executed -: 437: 3: 438: return EXIT_SUCCESS; 3: 438-block 0 unconditional 0 taken 3 -: 439:} -: 440: -: 441:/* Relink symlink to new path */ -: 442:int function edit_link called 2 returned 100% blocks executed 48% 2: 443:edit_link(char *link) -: 444:{ 2: 445: if (!link || !*link) 2: 445-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 0 2: 445-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 2 #####: 446: return EXIT_FAILURE; %%%%%: 446-block 0 unconditional 0 never executed -: 447: 2: 448: log_function(NULL); 2: 448-block 0 call 0 returned 2 -: 449: -: 450: /* Dequote the file name, if necessary */ 2: 451: if (strchr(link, '\\')) { branch 0 taken 0 (fallthrough) branch 1 taken 2 #####: 452: char *tmp = dequote_str(link, 0); %%%%%: 452-block 0 call 0 never executed #####: 453: if (!tmp) { branch 0 never executed branch 1 never executed #####: 454: fprintf(stderr, _("%s: %s: Error dequoting file\n"), %%%%%: 454-block 0 call 0 never executed call 1 never executed -: 455: PROGRAM_NAME, link); #####: 456: return EXIT_FAILURE; unconditional 0 never executed -: 457: } -: 458: #####: 459: strcpy(link, tmp); #####: 460: free(tmp); %%%%%: 460-block 0 unconditional 0 never executed -: 461: } -: 462: -: 463: /* Check we have a valid symbolic link */ -: 464: struct stat file_attrib; 2: 465: if (lstat(link, &file_attrib) == -1) { 2: 465-block 0 call 0 returned 2 branch 1 taken 0 (fallthrough) branch 2 taken 2 #####: 466: fprintf(stderr, "%s: %s: %s\n", PROGRAM_NAME, link, call 0 never executed #####: 467: strerror(errno)); %%%%%: 467-block 0 call 0 never executed #####: 468: return EXIT_FAILURE; unconditional 0 never executed -: 469: } -: 470: 2: 471: if ((file_attrib.st_mode & S_IFMT) != S_IFLNK) { 2: 471-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 2 #####: 472: fprintf(stderr, _("%s: %s: Not a symbolic link\n"), %%%%%: 472-block 0 call 0 never executed call 1 never executed -: 473: PROGRAM_NAME, link); #####: 474: return EXIT_FAILURE; unconditional 0 never executed -: 475: } -: 476: -: 477: /* Get file pointed to by symlink and report to the user */ 2: 478: char *real_path = realpath(link, NULL); 2: 478-block 0 call 0 returned 2 2: 479: if (!real_path) { branch 0 taken 1 (fallthrough) branch 1 taken 1 1: 480: printf(_("%s%s%s currently pointing to nowhere (broken link)\n"), 1: 480-block 0 call 0 returned 1 call 1 returned 1 unconditional 2 taken 1 -: 481: or_c, link, df_c); -: 482: } else { 1: 483: printf(_("%s%s%s currently pointing to "), ln_c, link, df_c); 1: 483-block 0 call 0 returned 1 call 1 returned 1 1: 484: colors_list(real_path, NO_ELN, NO_PAD, PRINT_NEWLINE); call 0 returned 1 1: 485: free(real_path); 1: 486: real_path = (char *)NULL; unconditional 0 taken 1 -: 487: } -: 488: 2: 489: char *new_path = (char *)NULL; -: 490: /* Enable autocd and auto-open (in case they are not already -: 491: * enabled) to allow TAB completion for ELN's */ 2: 492: int autocd_status = autocd, auto_open_status = auto_open; 2: 493: autocd = auto_open = 1; -: 494: 4: 495: while (!new_path) { 2: 495-block 0 unconditional 0 taken 2 4: 495-block 1 branch 1 taken 2 branch 2 taken 2 (fallthrough) 2: 496: new_path = rl_no_hist(_("New path ('q' to quit): ")); 2: 496-block 0 call 0 returned 2 call 1 returned 2 2*: 497: if (!new_path) branch 0 taken 0 (fallthrough) branch 1 taken 2 #####: 498: continue; %%%%%: 498-block 0 unconditional 0 never executed 2*: 499: if (!*new_path) { 2: 499-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 2 #####: 500: free(new_path); #####: 501: new_path = (char *)NULL; #####: 502: continue; %%%%%: 502-block 0 unconditional 0 never executed -: 503: } -: 504: 2*: 505: if (*new_path == 'q' && !new_path[1]) { 2: 505-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 2 %%%%%: 505-block 1 branch 2 never executed branch 3 never executed #####: 506: free(new_path); #####: 507: return EXIT_SUCCESS; %%%%%: 507-block 0 unconditional 0 never executed -: 508: } -: 509: } -: 510: -: 511: /* Set autocd and auto-open to their original values */ 2: 512: autocd = autocd_status; 2: 513: auto_open = auto_open_status; -: 514: -: 515: /* If an ELN, replace by the corresponding file name */ 2: 516: if (is_number(new_path)) { 2: 516-block 0 call 0 returned 2 branch 1 taken 0 (fallthrough) branch 2 taken 2 #####: 517: int i_new_path = atoi(new_path) - 1; #####: 518: if (file_info[i_new_path].name) { %%%%%: 518-block 0 branch 0 never executed branch 1 never executed #####: 519: new_path = (char *)xrealloc(new_path, #####: 520: (strlen(file_info[i_new_path].name) + 1) * sizeof(char)); %%%%%: 520-block 0 call 0 never executed #####: 521: strcpy(new_path, file_info[i_new_path].name); unconditional 0 never executed -: 522: } -: 523: } -: 524: -: 525: /* Remove terminating space. TAB completion puts a final space -: 526: * after file names */ 2: 527: size_t path_len = strlen(new_path); 2: 528: if (new_path[path_len - 1] == ' ') 2: 528-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 1 1: 529: new_path[path_len - 1] = '\0'; 1: 529-block 0 unconditional 0 taken 1 -: 530: -: 531: /* Dequote new path, if needed */ 2: 532: if (strchr(new_path, '\\')) { 2: 532-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 2 #####: 533: char *tmp = dequote_str(new_path, 0); %%%%%: 533-block 0 call 0 never executed #####: 534: if (!tmp) { branch 0 never executed branch 1 never executed #####: 535: fprintf(stderr, _("%s: %s: Error dequoting file\n"), %%%%%: 535-block 0 call 0 never executed call 1 never executed -: 536: PROGRAM_NAME, new_path); #####: 537: free(new_path); #####: 538: return EXIT_FAILURE; unconditional 0 never executed -: 539: } -: 540: #####: 541: strcpy(new_path, tmp); #####: 542: free(tmp); %%%%%: 542-block 0 unconditional 0 never executed -: 543: } -: 544: -: 545: /* Check new_path existence and warn the user if it does not -: 546: * exist */ 2: 547: if (lstat(new_path, &file_attrib) == -1) { 2: 547-block 0 call 0 returned 2 branch 1 taken 0 (fallthrough) branch 2 taken 2 #####: 548: printf("'%s': %s\n", new_path, strerror(errno)); %%%%%: 548-block 0 call 0 never executed call 1 never executed #####: 549: char *answer = (char *)NULL; #####: 550: while (!answer) { unconditional 0 never executed %%%%%: 550-block 0 branch 1 never executed branch 2 never executed #####: 551: answer = rl_no_hist(_("Relink as a broken symbolic link? [y/n] ")); %%%%%: 551-block 0 call 0 never executed call 1 never executed #####: 552: if (!answer) branch 0 never executed branch 1 never executed #####: 553: continue; %%%%%: 553-block 0 unconditional 0 never executed #####: 554: if (!*answer) { %%%%%: 554-block 0 branch 0 never executed branch 1 never executed #####: 555: free(answer); #####: 556: answer = (char *)NULL; #####: 557: continue; %%%%%: 557-block 0 unconditional 0 never executed -: 558: } -: 559: #####: 560: if (*answer != 'y' && *answer != 'n') { %%%%%: 560-block 0 branch 0 never executed branch 1 never executed %%%%%: 560-block 1 branch 2 never executed branch 3 never executed #####: 561: free(answer); #####: 562: answer = (char *)NULL; #####: 563: continue; %%%%%: 563-block 0 unconditional 0 never executed -: 564: } -: 565: #####: 566: if (answer[1]) { %%%%%: 566-block 0 branch 0 never executed branch 1 never executed #####: 567: free(answer); #####: 568: answer = (char *)NULL; #####: 569: continue; %%%%%: 569-block 0 unconditional 0 never executed -: 570: } -: 571: #####: 572: if (*answer == 'y') { %%%%%: 572-block 0 branch 0 never executed branch 1 never executed #####: 573: free(answer); #####: 574: break; %%%%%: 574-block 0 unconditional 0 never executed -: 575: } else { #####: 576: free(answer); #####: 577: free(new_path); #####: 578: return EXIT_SUCCESS; %%%%%: 578-block 0 unconditional 0 never executed -: 579: } -: 580: } -: 581: } -: 582: -: 583: /* Finally, relink the symlink to new_path */ 2: 584: char *cmd[] = {"ln", "-sfn", new_path, link, NULL}; 2: 585: if (launch_execve(cmd, FOREGROUND, E_NOFLAG) != EXIT_SUCCESS) { 2: 585-block 0 call 0 returned 2 branch 1 taken 0 (fallthrough) branch 2 taken 2 #####: 586: free(new_path); #####: 587: return EXIT_FAILURE; %%%%%: 587-block 0 unconditional 0 never executed -: 588: } -: 589: 2: 590: real_path = realpath(link, NULL); 2: 590-block 0 call 0 returned 2 2*: 591: printf(_("%s%s%s successfully relinked to "), real_path ? ln_c branch 0 taken 2 (fallthrough) branch 1 taken 0 2: 591-block 0 unconditional 2 taken 2 %%%%%: 591-block 1 unconditional 3 never executed 2: 591-block 2 call 4 returned 2 call 5 returned 2 -: 592: : or_c, link, df_c); 2: 593: colors_list(new_path, NO_ELN, NO_PAD, PRINT_NEWLINE); call 0 returned 2 2: 594: free(new_path); 2: 595: if (real_path) branch 0 taken 2 (fallthrough) branch 1 taken 0 2: 596: free(real_path); 2: 596-block 0 unconditional 0 taken 2 -: 597: 2: 598: return EXIT_SUCCESS; 2: 598-block 0 unconditional 0 taken 2 -: 599:} -: 600: -: 601:int function copy_function called 6 returned 100% blocks executed 53% 6: 602:copy_function(char **comm) -: 603:{ 6: 604: log_function(NULL); 6: 604-block 0 call 0 returned 6 -: 605: 6: 606: if (!is_sel) branch 0 taken 3 (fallthrough) branch 1 taken 3 3: 607: return run_and_refresh(comm); 3: 607-block 0 call 0 returned 3 unconditional 1 taken 3 -: 608: 3: 609: char *tmp_cmd = (char *)NULL; 3: 610: size_t total_len = 0, i = 0; -: 611: 14: 612: for (i = 0; i <= args_n; i++) 3: 612-block 0 unconditional 0 taken 3 14: 612-block 1 branch 1 taken 11 branch 2 taken 3 (fallthrough) 11: 613: total_len += strlen(comm[i]); 11: 613-block 0 unconditional 0 taken 11 -: 614: 3: 615: tmp_cmd = (char *)xcalloc(total_len + (i + 1) + 2, sizeof(char)); 3: 615-block 0 call 0 returned 3 -: 616: 14: 617: for (i = 0; i <= args_n; i++) { unconditional 0 taken 3 14: 617-block 0 branch 1 taken 11 branch 2 taken 3 (fallthrough) 11: 618: strcat(tmp_cmd, comm[i]); 11: 619: strcat(tmp_cmd, " "); 11: 619-block 0 unconditional 0 taken 11 -: 620: } -: 621: 3: 622: if (sel_is_last) 3: 622-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 1 2: 623: strcat(tmp_cmd, "."); 2: 623-block 0 unconditional 0 taken 2 -: 624: 3: 625: int ret = 0; 3: 626: ret = launch_execle(tmp_cmd); 3: 626-block 0 call 0 returned 3 3: 627: free(tmp_cmd); -: 628: 3: 629: if (ret != EXIT_SUCCESS) branch 0 taken 1 (fallthrough) branch 1 taken 2 1: 630: return EXIT_FAILURE; 1: 630-block 0 unconditional 0 taken 1 -: 631: 2: 632: if (copy_n_rename) { /* vv */ 2: 632-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 2 #####: 633: char **tmp = (char **)xnmalloc(sel_n + 3, sizeof(char *)); %%%%%: 633-block 0 call 0 never executed #####: 634: tmp[0] = savestring("br", 2); call 0 never executed -: 635: -: 636: size_t j; #####: 637: for (j = 0; j < sel_n; j++) { unconditional 0 never executed %%%%%: 637-block 0 branch 1 never executed branch 2 never executed #####: 638: size_t arg_len = strlen(sel_elements[j]); -: 639: #####: 640: if (sel_elements[j][arg_len - 1] == '/') %%%%%: 640-block 0 branch 0 never executed branch 1 never executed #####: 641: sel_elements[j][arg_len - 1] = '\0'; %%%%%: 641-block 0 unconditional 0 never executed -: 642: #####: 643: if (*comm[args_n] == '~') { %%%%%: 643-block 0 branch 0 never executed branch 1 never executed #####: 644: char *exp_dest = tilde_expand(comm[args_n]); %%%%%: 644-block 0 call 0 never executed #####: 645: comm[args_n] = xrealloc(comm[args_n], #####: 646: (strlen(exp_dest) + 1) * sizeof(char)); call 0 never executed #####: 647: strcpy(comm[args_n], exp_dest); #####: 648: free(exp_dest); unconditional 0 never executed -: 649: } -: 650: #####: 651: size_t dest_len = strlen(comm[args_n]); #####: 652: if (comm[args_n][dest_len - 1] == '/') { %%%%%: 652-block 0 branch 0 never executed branch 1 never executed #####: 653: comm[args_n][dest_len - 1] = '\0'; %%%%%: 653-block 0 unconditional 0 never executed -: 654: } -: 655: -: 656: char dest[PATH_MAX]; #####: 657: strcpy(dest, (sel_is_last || strcmp(comm[args_n], ".") == 0) %%%%%: 657-block 0 branch 0 never executed branch 1 never executed %%%%%: 657-block 1 branch 2 never executed branch 3 never executed #####: 658: ? ws[cur_ws].path %%%%%: 658-block 0 unconditional 0 never executed #####: 659: : comm[args_n]); %%%%%: 659-block 0 unconditional 0 never executed -: 660: #####: 661: char *ret_val = strrchr(sel_elements[j], '/'); #####: 662: char *tmp_str = (char *)xnmalloc(strlen(dest) #####: 663: + strlen(ret_val + 1) + 2, sizeof(char)); %%%%%: 663-block 0 call 0 never executed -: 664: #####: 665: sprintf(tmp_str, "%s/%s", dest, ret_val + 1); -: 666: #####: 667: tmp[j + 1] = savestring(tmp_str, strlen(tmp_str)); call 0 never executed #####: 668: free(tmp_str); unconditional 0 never executed -: 669: } -: 670: #####: 671: tmp[j + 1] = (char *)NULL; #####: 672: bulk_rename(tmp); %%%%%: 672-block 0 call 0 never executed -: 673: #####: 674: for (i = 0; tmp[i]; i++) unconditional 0 never executed %%%%%: 674-block 0 branch 1 never executed branch 2 never executed #####: 675: free(tmp[i]); %%%%%: 675-block 0 unconditional 0 never executed #####: 676: free(tmp); #####: 677: copy_n_rename = 0; #####: 678: return EXIT_SUCCESS; %%%%%: 678-block 0 unconditional 0 never executed -: 679: } -: 680: -: 681: /* If 'mv sel' and command is successful deselect everything, -: 682: * since sel files are note there anymore */ 2: 683: if (*comm[0] == 'm' && comm[0][1] == 'v' 2: 683-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 1 1: 683-block 1 branch 2 taken 1 (fallthrough) branch 3 taken 0 1: 684: && (!comm[0][2] || comm[0][2] == ' ')) { 1: 684-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 0 1: 684-block 1 branch 2 taken 1 (fallthrough) branch 3 taken 0 4: 685: for (i = 0; i < sel_n; i++) 1: 685-block 0 unconditional 0 taken 1 4: 685-block 1 branch 1 taken 3 branch 2 taken 1 (fallthrough) 3: 686: free(sel_elements[i]); 3: 686-block 0 unconditional 0 taken 3 1: 687: sel_n = 0; 1: 688: save_sel(); 1: 688-block 0 call 0 returned 1 unconditional 1 taken 1 -: 689: } -: 690: -: 691:#ifdef __HAIKU__ -: 692: if (cd_lists_on_the_fly) { -: 693: free_dirlist(); -: 694: list_dir(); -: 695: } -: 696:#endif -: 697: 2: 698: return EXIT_SUCCESS; 2: 698-block 0 unconditional 0 taken 2 -: 699:} -: 700: -: 701:int function remove_file called 4 returned 100% blocks executed 82% 4: 702:remove_file(char **args) -: 703:{ 4: 704: int cwd = 0, exit_status = EXIT_SUCCESS; -: 705: 4: 706: log_function(NULL); 4: 706-block 0 call 0 returned 4 -: 707: 4: 708: char **rm_cmd = (char **)xnmalloc(args_n + 4, sizeof(char *)); call 0 returned 4 4: 709: int i, j = 3, dirs = 0; -: 710: 10: 711: for (i = 1; args[i]; i++) { unconditional 0 taken 4 6: 711-block 0 unconditional 1 taken 6 10: 711-block 1 branch 2 taken 6 branch 3 taken 4 (fallthrough) -: 712: /* Check if at least one file is in the current directory. If not, -: 713: * there is no need to refresh the screen */ 6: 714: if (!cwd) { 6: 714-block 0 branch 0 taken 4 (fallthrough) branch 1 taken 2 4: 715: char *ret = strchr(args[i], '/'); -: 716: /* If there's no slash, or if slash is the last char and -: 717: * the file is not root "/", we have a file in CWD */ 4: 718: if (!ret || (!*(ret + 1) && ret != args[i])) 4: 718-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 2 2: 718-block 1 branch 2 taken 1 (fallthrough) branch 3 taken 1 1: 718-block 2 branch 4 taken 1 (fallthrough) branch 5 taken 0 3: 719: cwd = 1; 3: 719-block 0 unconditional 0 taken 3 -: 720: } -: 721: 6: 722: char *tmp = (char *)NULL; 6: 723: if (strchr(args[i], '\\')) { 6: 723-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 6 #####: 724: tmp = dequote_str(args[i], 0); %%%%%: 724-block 0 call 0 never executed #####: 725: if (tmp) { branch 0 never executed branch 1 never executed -: 726: /* Start storing file names in 3: 0 is for 'rm', and 1 -: 727: * and 2 for parameters, including end of parameters (--) */ #####: 728: rm_cmd[j++] = savestring(tmp, strlen(tmp)); %%%%%: 728-block 0 call 0 never executed #####: 729: free(tmp); unconditional 0 never executed -: 730: } else { #####: 731: fprintf(stderr, "%s: %s: Error dequoting file name\n", #####: 732: PROGRAM_NAME, args[i]); %%%%%: 732-block 0 call 0 never executed #####: 733: continue; unconditional 0 never executed -: 734: } -: 735: } else { 6: 736: rm_cmd[j++] = savestring(args[i], strlen(args[i])); 6: 736-block 0 call 0 returned 6 unconditional 1 taken 6 -: 737: } -: 738: -: 739: struct stat attr; 6: 740: if (!dirs && lstat(rm_cmd[j - 1], &attr) != -1 6: 740-block 0 branch 0 taken 6 (fallthrough) branch 1 taken 0 6: 740-block 1 call 2 returned 6 branch 3 taken 6 (fallthrough) branch 4 taken 0 6: 741: && (attr.st_mode & S_IFMT) == S_IFDIR) 6: 741-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 4 2: 742: dirs = 1; 2: 742-block 0 unconditional 0 taken 2 -: 743: } -: 744: 4: 745: rm_cmd[j] = (char *)NULL; -: 746: 4: 747: rm_cmd[0] = savestring("rm", 2); 4: 747-block 0 call 0 returned 4 4: 748: if (dirs) branch 0 taken 2 (fallthrough) branch 1 taken 2 -: 749:#if defined(__NetBSD__) || defined(__OpenBSD__) -: 750: rm_cmd[1] = savestring("-r", 2); -: 751:#else 2: 752: rm_cmd[1] = savestring("-dIr", 4); 2: 752-block 0 call 0 returned 2 unconditional 1 taken 2 -: 753:#endif -: 754: else -: 755:#if defined(__NetBSD__) || defined(__OpenBSD__) -: 756: rm_cmd[1] = savestring("-f", 2); -: 757:#else 2: 758: rm_cmd[1] = savestring("-I", 2); 2: 758-block 0 call 0 returned 2 unconditional 1 taken 2 -: 759:#endif 4: 760: rm_cmd[2] = savestring("--", 2); 4: 760-block 0 call 0 returned 4 -: 761: 4: 762: if (launch_execve(rm_cmd, FOREGROUND, E_NOFLAG) != EXIT_SUCCESS) call 0 returned 4 branch 1 taken 0 (fallthrough) branch 2 taken 4 #####: 763: exit_status = EXIT_FAILURE; %%%%%: 763-block 0 unconditional 0 never executed -: 764:#ifdef __HAIKU__ -: 765: else { -: 766: if (cwd && cd_lists_on_the_fly && strcmp(args[1], "--help") != 0 -: 767: && strcmp(args[1], "--version") != 0) { -: 768: free_dirlist(); -: 769: exit_status = list_dir(); -: 770: } -: 771: } -: 772:#endif -: 773: 22: 774: for (i = 0; rm_cmd[i]; i++) 4: 774-block 0 unconditional 0 taken 4 22: 774-block 1 branch 1 taken 18 branch 2 taken 4 (fallthrough) 18: 775: free(rm_cmd[i]); 18: 775-block 0 unconditional 0 taken 18 4: 776: free(rm_cmd); 4: 777: return exit_status; 4: 777-block 0 unconditional 0 taken 4 -: 778:} -: 779: -: 780:/* Rename a bulk of files (ARGS) at once. Takes files to be renamed -: 781: * as arguments, and returns zero on success and one on error. The -: 782: * procedude is quite simple: file names to be renamed are copied into -: 783: * a temporary file, which is opened via the mime function and shown -: 784: * to the user to modify it. Once the file names have been modified and -: 785: * saved, modifications are printed on the screen and the user is -: 786: * asked whether to perform the actual bulk renaming (via mv) or not. -: 787: * I took this bulk rename method, just because it is quite simple and -: 788: * KISS, from the fff filemanager. So, thanks fff! BTW, this method -: 789: * is also implemented by ranger and nnn */ -: 790:int function bulk_rename called 3 returned 100% blocks executed 55% 3: 791:bulk_rename(char **args) -: 792:{ 3: 793: if (!args[1]) 3: 793-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 3 #####: 794: return EXIT_FAILURE; %%%%%: 794-block 0 unconditional 0 never executed -: 795: 3: 796: log_function(NULL); 3: 796-block 0 call 0 returned 3 -: 797: 3: 798: int exit_status = EXIT_SUCCESS; -: 799: -: 800: char bulk_file[PATH_MAX]; 3: 801: if (xargs.stealth_mode == 1) branch 0 taken 0 (fallthrough) branch 1 taken 3 #####: 802: sprintf(bulk_file, "/tmp/.clifm_bulk_rename"); %%%%%: 802-block 0 unconditional 0 never executed -: 803: else 3: 804: sprintf(bulk_file, "%s/.bulk_rename", tmp_dir); 3: 804-block 0 unconditional 0 taken 3 -: 805: -: 806: int fd; 3: 807: FILE *fp = open_fstream_w(bulk_file, &fd); 3: 807-block 0 call 0 returned 3 3: 808: if (!fp) { branch 0 taken 0 (fallthrough) branch 1 taken 3 #####: 809: _err('e', PRINT_PROMPT, "bulk: '%s': %s\n", bulk_file, strerror(errno)); %%%%%: 809-block 0 call 0 never executed call 1 never executed #####: 810: return EXIT_FAILURE; unconditional 0 never executed -: 811: } -: 812: 3: 813: size_t i, arg_total = 0; -: 814: -: 815: /* Copy all files to be renamed to the bulk file */ 10: 816: for (i = 1; args[i]; i++) { 3: 816-block 0 unconditional 0 taken 3 7: 816-block 1 unconditional 1 taken 7 10: 816-block 2 branch 2 taken 7 branch 3 taken 3 (fallthrough) -: 817: /* Dequote file name, if necessary */ 7: 818: if (strchr(args[i], '\\')) { 7: 818-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 7 #####: 819: char *deq_file = dequote_str(args[i], 0); %%%%%: 819-block 0 call 0 never executed #####: 820: if (!deq_file) { branch 0 never executed branch 1 never executed #####: 821: fprintf(stderr, _("bulk: %s: Error dequoting " call 0 never executed #####: 822: "file name\n"), args[i]); %%%%%: 822-block 0 call 0 never executed #####: 823: continue; unconditional 0 never executed -: 824: } #####: 825: strcpy(args[i], deq_file); #####: 826: free(deq_file); %%%%%: 826-block 0 unconditional 0 never executed -: 827: } -: 828: 7: 829: fprintf(fp, "%s\n", args[i]); 7: 829-block 0 call 0 returned 7 unconditional 1 taken 7 -: 830: } -: 831: 3: 832: arg_total = i; 3: 833: close_fstream(fp, fd); 3: 833-block 0 call 0 returned 3 -: 834: 3: 835: fp = open_fstream_r(bulk_file, &fd); call 0 returned 3 3: 836: if (!fp) { branch 0 taken 0 (fallthrough) branch 1 taken 3 #####: 837: _err('e', PRINT_PROMPT, "bulk: '%s': %s\n", bulk_file, strerror(errno)); %%%%%: 837-block 0 call 0 never executed call 1 never executed #####: 838: return EXIT_FAILURE; unconditional 0 never executed -: 839: } -: 840: -: 841: /* Store the last modification time of the bulk file. This time -: 842: * will be later compared to the modification time of the same -: 843: * file after shown to the user */ -: 844: struct stat attr; 3: 845: fstat(fd, &attr); 3: 845-block 0 call 0 returned 3 3: 846: time_t mtime_bfr = (time_t)attr.st_mtime; -: 847: -: 848: /* Open the bulk file */ 3: 849: if (open_file(bulk_file) != EXIT_SUCCESS) call 0 returned 3 branch 1 taken 0 (fallthrough) branch 2 taken 3 #####: 850: return EXIT_FAILURE; %%%%%: 850-block 0 unconditional 0 never executed -: 851: -: 852: /* Compare the new modification time to the stored one: if they -: 853: * match, nothing was modified */ 3: 854: fstat(fd, &attr); 3: 854-block 0 call 0 returned 3 3: 855: if (mtime_bfr == (time_t)attr.st_mtime) { branch 0 taken 0 (fallthrough) branch 1 taken 3 #####: 856: puts(_("bulk: Nothing to do")); %%%%%: 856-block 0 call 0 never executed call 1 never executed #####: 857: if (unlinkat(fd, bulk_file, 0) == -1) { call 0 never executed branch 1 never executed branch 2 never executed #####: 858: _err('e', PRINT_PROMPT, "%s: '%s': %s\n", PROGRAM_NAME, call 0 never executed #####: 859: bulk_file, strerror(errno)); %%%%%: 859-block 0 call 0 never executed #####: 860: exit_status = EXIT_FAILURE; unconditional 0 never executed -: 861: } #####: 862: close_fstream(fp, fd); %%%%%: 862-block 0 call 0 never executed #####: 863: return exit_status; unconditional 0 never executed -: 864: } -: 865: -: 866: /* Go back to the beginning of the bulk file */ 3: 867: fseek(fp, 0, SEEK_SET); 3: 867-block 0 call 0 returned 3 -: 868: -: 869: /* Make sure there are as many lines in the bulk file as files -: 870: * to be renamed */ 3: 871: size_t file_total = 1; -: 872: char tmp_line[256]; 10: 873: while (fgets(tmp_line, (int)sizeof(tmp_line), fp)) unconditional 0 taken 3 10: 873-block 0 call 1 returned 10 branch 2 taken 7 branch 3 taken 3 (fallthrough) 7: 874: file_total++; 7: 874-block 0 unconditional 0 taken 7 -: 875: 3: 876: if (arg_total != file_total) { 3: 876-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 3 #####: 877: fputs(_("bulk: Line mismatch in rename file\n"), stderr); %%%%%: 877-block 0 call 0 never executed call 1 never executed #####: 878: if (unlinkat(fd, bulk_file, 0) == -1) call 0 never executed branch 1 never executed branch 2 never executed #####: 879: _err('e', PRINT_PROMPT, "%s: '%s': %s\n", PROGRAM_NAME, call 0 never executed unconditional 1 never executed #####: 880: bulk_file, strerror(errno)); %%%%%: 880-block 0 call 0 never executed #####: 881: close_fstream(fp, fd); %%%%%: 881-block 0 call 0 never executed #####: 882: return EXIT_FAILURE; unconditional 0 never executed -: 883: } -: 884: -: 885: /* Go back to the beginning of the bulk file, again */ 3: 886: fseek(fp, 0L, SEEK_SET); 3: 886-block 0 call 0 returned 3 -: 887: 3: 888: size_t line_size = 0; 3: 889: char *line = (char *)NULL; 3: 890: ssize_t line_len = 0; 3: 891: int modified = 0; -: 892: 3: 893: i = 1; -: 894: /* Print what would be done */ 10: 895: while ((line_len = getline(&line, &line_size, fp)) > 0) { unconditional 0 taken 3 10: 895-block 0 call 1 returned 10 branch 2 taken 7 branch 3 taken 3 (fallthrough) 7: 896: if (line[line_len - 1] == '\n') 7: 896-block 0 branch 0 taken 7 (fallthrough) branch 1 taken 0 7: 897: line[line_len - 1] = '\0'; 7: 897-block 0 unconditional 0 taken 7 -: 898: 7: 899: if (args[i] && strcmp(args[i], line) != 0) { 7: 899-block 0 branch 0 taken 7 (fallthrough) branch 1 taken 0 7: 899-block 1 branch 2 taken 7 (fallthrough) branch 3 taken 0 7: 900: printf("%s %s->%s %s\n", args[i], mi_c, df_c, line); 7: 900-block 0 call 0 returned 7 7: 901: modified++; unconditional 0 taken 7 -: 902: } -: 903: 7: 904: i++; 7: 904-block 0 unconditional 0 taken 7 -: 905: } -: 906: -: 907: /* If no file name was modified */ 3: 908: if (!modified) { 3: 908-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 3 #####: 909: puts(_("bulk: Nothing to do")); %%%%%: 909-block 0 call 0 never executed call 1 never executed #####: 910: if (unlinkat(fd, bulk_file, 0) == -1) { call 0 never executed branch 1 never executed branch 2 never executed #####: 911: _err('e', PRINT_PROMPT, "%s: '%s': %s\n", PROGRAM_NAME, call 0 never executed #####: 912: bulk_file, strerror(errno)); %%%%%: 912-block 0 call 0 never executed #####: 913: exit_status = EXIT_FAILURE; unconditional 0 never executed -: 914: } #####: 915: free(line); #####: 916: close_fstream(fp, fd); %%%%%: 916-block 0 call 0 never executed #####: 917: return exit_status; unconditional 0 never executed -: 918: } -: 919: -: 920: /* Ask the user for confirmation */ 3: 921: char *answer = (char *)NULL; 6: 922: while (!answer) { 3: 922-block 0 unconditional 0 taken 3 6: 922-block 1 branch 1 taken 3 branch 2 taken 3 (fallthrough) 3: 923: answer = rl_no_hist(_("Continue? [y/N] ")); 3: 923-block 0 call 0 returned 3 call 1 returned 3 3*: 924: if (strlen(answer) > 1) { branch 0 taken 0 (fallthrough) branch 1 taken 3 #####: 925: free(answer); #####: 926: answer = (char *)NULL; #####: 927: continue; %%%%%: 927-block 0 unconditional 0 never executed -: 928: } -: 929: 3: 930: switch (*answer) { 3: 930-block 0 branch 0 taken 3 branch 1 taken 0 branch 2 taken 0 3: 931: case 'y': /* fallthrough */ 3: 932: case 'Y': break; 3: 932-block 0 unconditional 0 taken 3 -: 933: #####: 934: case 'n': /* fallthrough */ -: 935: case 'N': /* fallthrough */ -: 936: case '\0': #####: 937: free(answer); #####: 938: free(line); #####: 939: close_fstream(fp, fd); %%%%%: 939-block 0 call 0 never executed #####: 940: return EXIT_SUCCESS; unconditional 0 never executed -: 941: #####: 942: default: #####: 943: free(answer); #####: 944: answer = (char *)NULL; #####: 945: break; %%%%%: 945-block 0 unconditional 0 never executed -: 946: } -: 947: } -: 948: 3: 949: free(answer); -: 950: -: 951: /* Once again */ 3: 952: fseek(fp, 0L, SEEK_SET); 3: 952-block 0 call 0 returned 3 -: 953: 3: 954: i = 1; -: 955: -: 956: /* Rename each file */ 10: 957: while ((line_len = getline(&line, &line_size, fp)) > 0) { unconditional 0 taken 3 10: 957-block 0 call 1 returned 10 branch 2 taken 7 branch 3 taken 3 (fallthrough) 7*: 958: if (!args[i]) { 7: 958-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 7 #####: 959: i++; #####: 960: continue; %%%%%: 960-block 0 unconditional 0 never executed -: 961: } -: 962: 7: 963: if (line[line_len - 1] == '\n') 7: 963-block 0 branch 0 taken 7 (fallthrough) branch 1 taken 0 7: 964: line[line_len - 1] = '\0'; 7: 964-block 0 unconditional 0 taken 7 7: 965: if (args[i] && strcmp(args[i], line) != 0) { 7: 965-block 0 branch 0 taken 7 (fallthrough) branch 1 taken 0 7: 965-block 1 branch 2 taken 7 (fallthrough) branch 3 taken 0 7: 966: if (renameat(AT_FDCWD, args[i], AT_FDCWD, line) == -1) 7: 966-block 0 call 0 returned 7 branch 1 taken 0 (fallthrough) branch 2 taken 7 #####: 967: exit_status = EXIT_FAILURE; %%%%%: 967-block 0 unconditional 0 never executed -: 968: } -: 969: 7: 970: i++; 7: 970-block 0 unconditional 0 taken 7 -: 971: } -: 972: 3: 973: free(line); -: 974: 3: 975: if (unlinkat(fd, bulk_file, 0) == -1) { 3: 975-block 0 call 0 returned 3 branch 1 taken 0 (fallthrough) branch 2 taken 3 #####: 976: _err('e', PRINT_PROMPT, "%s: '%s': %s\n", PROGRAM_NAME, call 0 never executed #####: 977: bulk_file, strerror(errno)); %%%%%: 977-block 0 call 0 never executed #####: 978: exit_status = EXIT_FAILURE; unconditional 0 never executed -: 979: } 3: 980: close_fstream(fp, fd); 3: 980-block 0 call 0 returned 3 -: 981: -: 982:#ifdef __HAIKU__ -: 983: if (cd_lists_on_the_fly) { -: 984: free_dirlist(); -: 985: if (list_dir() != EXIT_SUCCESS) -: 986: exit_status = EXIT_FAILURE; -: 987: } -: 988:#endif -: 989: 3: 990: return exit_status; unconditional 0 taken 3 -: 991:} -: 992: -: 993:/* Export files in CWD (if FILENAMES is NULL), or files in FILENAMES, -: 994: * into a temporary file. Return the address of this empt file if -: 995: * success (it must be freed) or NULL in case of error */ function export called 2 returned 100% blocks executed 72% 2: 996:char *export(char **filenames, int open) -: 997:{ 2: 998: char *rand_ext = gen_rand_str(6); 2: 998-block 0 call 0 returned 2 2: 999: if (!rand_ext) branch 0 taken 0 (fallthrough) branch 1 taken 2 #####: 1000: return (char *)NULL; %%%%%: 1000-block 0 unconditional 0 never executed -: 1001: 2: 1002: char *tmp_file = (char *)xnmalloc(strlen(tmp_dir) + 14, sizeof(char)); 2: 1002-block 0 call 0 returned 2 2: 1003: sprintf(tmp_file, "%s/.clifm%s", tmp_dir, rand_ext); 2: 1004: free(rand_ext); -: 1005: 2: 1006: FILE *fp = fopen(tmp_file, "w"); call 0 returned 2 2: 1007: if (!fp) { branch 0 taken 0 (fallthrough) branch 1 taken 2 #####: 1008: free(tmp_file); #####: 1009: return (char *)NULL; %%%%%: 1009-block 0 unconditional 0 never executed -: 1010: } -: 1011: -: 1012: size_t i; -: 1013: -: 1014: /* If no argument, export files in CWD */ 2: 1015: if (!filenames[1]) { 2: 1015-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 1 6: 1016: for (i = 0; file_info[i].name; i++) 1: 1016-block 0 unconditional 0 taken 1 unconditional 1 taken 5 6: 1016-block 1 branch 2 taken 5 branch 3 taken 1 5: 1017: fprintf(fp, "%s\n", file_info[i].name); 5: 1017-block 0 call 0 returned 5 -: 1018: } else { 2: 1019: for (i = 1; filenames[i]; i++) { 1: 1019-block 0 unconditional 0 taken 1 1: 1019-block 1 unconditional 1 taken 1 2: 1019-block 2 branch 2 taken 1 branch 3 taken 1 (fallthrough) 1*: 1020: if (*filenames[i] == '.' && (!filenames[i][1] || (filenames[i][1] == '.' && !filenames[i][2]))) 1: 1020-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 1 %%%%%: 1020-block 1 branch 2 never executed branch 3 never executed %%%%%: 1020-block 2 branch 4 never executed branch 5 never executed %%%%%: 1020-block 3 branch 6 never executed branch 7 never executed #####: 1021: continue; %%%%%: 1021-block 0 unconditional 0 never executed 1: 1022: fprintf(fp, "%s\n", filenames[i]); 1: 1022-block 0 call 0 returned 1 unconditional 1 taken 1 -: 1023: } -: 1024: } -: 1025: 2: 1026: fclose(fp); 2: 1026-block 0 call 0 returned 2 -: 1027: 2: 1028: if (!open) branch 0 taken 0 (fallthrough) branch 1 taken 2 #####: 1029: return tmp_file; %%%%%: 1029-block 0 unconditional 0 never executed -: 1030: 2: 1031: int ret = open_file(tmp_file); 2: 1031-block 0 call 0 returned 2 2: 1032: if (ret == EXIT_SUCCESS) { branch 0 taken 2 (fallthrough) branch 1 taken 0 2: 1033: return tmp_file; 2: 1033-block 0 unconditional 0 taken 2 -: 1034: } else { #####: 1035: free(tmp_file); #####: 1036: return (char *)NULL; %%%%%: 1036-block 0 unconditional 0 never executed -: 1037: } -: 1038:} -: 1039: -: 1040:int function batch_link called 0 returned 0% blocks executed 0% #####: 1041:batch_link(char **args) -: 1042:{ #####: 1043: if (!args) %%%%%: 1043-block 0 branch 0 never executed branch 1 never executed #####: 1044: return EXIT_FAILURE; %%%%%: 1044-block 0 unconditional 0 never executed -: 1045: #####: 1046: if (!args[1] || (*args[1] == '-' && strcmp(args[1], "--help") == 0)) { %%%%%: 1046-block 0 branch 0 never executed branch 1 never executed %%%%%: 1046-block 1 branch 2 never executed branch 3 never executed %%%%%: 1046-block 2 branch 4 never executed branch 5 never executed #####: 1047: puts(_(BL_USAGE)); %%%%%: 1047-block 0 call 0 never executed call 1 never executed #####: 1048: return EXIT_SUCCESS; unconditional 0 never executed -: 1049: } -: 1050: #####: 1051: log_function(NULL); %%%%%: 1051-block 0 call 0 never executed -: 1052: #####: 1053: char *suffix = (char *)NULL; #####: 1054: while (!suffix) { unconditional 0 never executed %%%%%: 1054-block 0 branch 1 never executed branch 2 never executed #####: 1055: suffix = rl_no_hist(_("Enter links suffix ('n' for none): ")); %%%%%: 1055-block 0 call 0 never executed call 1 never executed #####: 1056: if (!suffix) branch 0 never executed branch 1 never executed #####: 1057: continue; %%%%%: 1057-block 0 unconditional 0 never executed #####: 1058: if (!*suffix) { %%%%%: 1058-block 0 branch 0 never executed branch 1 never executed #####: 1059: free(suffix); #####: 1060: suffix = (char *)NULL; #####: 1061: continue; %%%%%: 1061-block 0 unconditional 0 never executed -: 1062: } -: 1063: } -: 1064: -: 1065: size_t i; #####: 1066: int exit_status = EXIT_SUCCESS; -: 1067: char tmp[NAME_MAX]; -: 1068: #####: 1069: for (i = 1; args[i]; i++) { %%%%%: 1069-block 0 unconditional 0 never executed %%%%%: 1069-block 1 unconditional 1 never executed %%%%%: 1069-block 2 branch 2 never executed branch 3 never executed #####: 1070: char *linkname = (char *)NULL; -: 1071: #####: 1072: if (*suffix == 'n' && !suffix[1]) { %%%%%: 1072-block 0 branch 0 never executed branch 1 never executed %%%%%: 1072-block 1 branch 2 never executed branch 3 never executed #####: 1073: linkname = args[i]; %%%%%: 1073-block 0 unconditional 0 never executed -: 1074: } else { #####: 1075: snprintf(tmp, NAME_MAX, "%s%s", args[i], suffix); #####: 1076: linkname = tmp; %%%%%: 1076-block 0 unconditional 0 never executed -: 1077: } -: 1078: #####: 1079: char *ptr = strrchr(linkname, '/'); #####: 1080: if (symlinkat(args[i], AT_FDCWD, ptr ? ++ptr : linkname) == -1) { %%%%%: 1080-block 0 branch 0 never executed branch 1 never executed %%%%%: 1080-block 1 unconditional 2 never executed %%%%%: 1080-block 2 unconditional 3 never executed %%%%%: 1080-block 3 call 4 never executed branch 5 never executed branch 6 never executed #####: 1081: exit_status = EXIT_FAILURE; #####: 1082: fprintf(stderr, _("%s: %s: Cannot create symlink: %s\n"), branch 0 never executed branch 1 never executed %%%%%: 1082-block 0 unconditional 2 never executed %%%%%: 1082-block 1 unconditional 3 never executed %%%%%: 1082-block 2 call 4 never executed call 5 never executed unconditional 6 never executed #####: 1083: PROGRAM_NAME, ptr ? ptr : linkname, strerror(errno)); %%%%%: 1083-block 0 call 0 never executed -: 1084: } -: 1085: } -: 1086: -: 1087:#ifdef __HAIKU__ -: 1088: if (exit_status == EXIT_SUCCESS && cd_lists_on_the_fly) { -: 1089: free_dirlist(); -: 1090: -: 1091: if (list_dir() != EXIT_SUCCESS) -: 1092: exit_status = EXIT_FAILURE; -: 1093: } -: 1094:#endif -: 1095: #####: 1096: free(suffix); #####: 1097: return exit_status; %%%%%: 1097-block 0 unconditional 0 never executed -: 1098:} clifm-1.26.3/misc/codecov/history.c.gcov000066400000000000000000001443461506632037700201010ustar00rootroot00000000000000 -: 0:Source:history.c -: 1:/* history.c -- functions for the history system */ -: 2: -: 3:/* -: 4: * This file is part of CliFM -: 5: * -: 6: * Copyright (C) 2016-2021, L. Abramovich -: 7: * All rights reserved. -: 8: -: 9: * CliFM is free software; you can redistribute it and/or modify -: 10: * it under the terms of the GNU General Public License as published by -: 11: * the Free Software Foundation; either version 2 of the License, or -: 12: * (at your option) any later version. -: 13: * -: 14: * CliFM is distributed in the hope that it will be useful, -: 15: * but WITHOUT ANY WARRANTY; without even the implied warranty of -: 16: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -: 17: * GNU General Public License for more details. -: 18: * -: 19: * You should have received a copy of the GNU General Public License -: 20: * along with this program; if not, write to the Free Software -: 21: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, -: 22: * MA 02110-1301, USA. -: 23:*/ -: 24: -: 25:#include "helpers.h" -: 26: -: 27:#include -: 28:#include -: 29:#include -: 30:#include -: 31:#include -: 32: -: 33:#include "aux.h" -: 34:#include "checks.h" -: 35:#include "exec.h" -: 36:#include "history.h" -: 37:#include "init.h" -: 38:#include "misc.h" -: 39:#include "messages.h" -: 40: -: 41:/* Log COMM into LOG_FILE (global) */ -: 42:int function log_function called 39 returned 100% blocks executed 56% 39: 43:log_function(char **comm) -: 44:{ -: 45: /* If cmd logs are disabled, allow only "log" commands */ 39: 46: if (!logs_enabled) { 39: 46-block 0 branch 0 taken 39 (fallthrough) branch 1 taken 0 39: 47: if (comm && comm[0] && strcmp(comm[0], "log") != 0) 39: 47-block 0 branch 0 taken 18 (fallthrough) branch 1 taken 21 18: 47-block 1 branch 2 taken 18 (fallthrough) branch 3 taken 0 18: 47-block 2 branch 4 taken 14 (fallthrough) branch 5 taken 4 14: 48: return EXIT_SUCCESS; 14: 48-block 0 unconditional 0 taken 14 -: 49: } -: 50: 25: 51: if (!config_ok) 25: 51-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 25 #####: 52: return EXIT_FAILURE; %%%%%: 52-block 0 unconditional 0 never executed -: 53: 25: 54: int clear_log = 0; -: 55: -: 56: /* If the command was just 'log' */ 25: 57: if (comm && comm[0] && *comm[0] == 'l' && strcmp(comm[0], "log") == 0 && !comm[1]) { 25: 57-block 0 branch 0 taken 4 (fallthrough) branch 1 taken 21 4: 57-block 1 branch 2 taken 4 (fallthrough) branch 3 taken 0 4: 57-block 2 branch 4 taken 4 (fallthrough) branch 5 taken 0 4: 57-block 3 branch 6 taken 4 (fallthrough) branch 7 taken 0 4: 57-block 4 branch 8 taken 3 (fallthrough) branch 9 taken 1 -: 58: FILE *log_fp; 3: 59: log_fp = fopen(log_file, "r"); 3: 59-block 0 call 0 returned 3 3: 60: if (!log_fp) { branch 0 taken 0 (fallthrough) branch 1 taken 3 #####: 61: _err(0, NOPRINT_PROMPT, "%s: log: '%s': %s\n", call 0 never executed #####: 62: PROGRAM_NAME, log_file, strerror(errno)); %%%%%: 62-block 0 call 0 never executed #####: 63: return EXIT_FAILURE; unconditional 0 never executed -: 64: } else { 3: 65: size_t line_size = 0; 3: 66: char *line_buff = (char *)NULL; -: 67: 267: 68: while (getline(&line_buff, &line_size, log_fp) > 0) 3: 68-block 0 unconditional 0 taken 3 267: 68-block 1 call 1 returned 267 branch 2 taken 264 branch 3 taken 3 (fallthrough) 264: 69: fputs(line_buff, stdout); 264: 69-block 0 call 0 returned 264 unconditional 1 taken 264 -: 70: 3: 71: free(line_buff); 3: 72: fclose(log_fp); 3: 72-block 0 call 0 returned 3 3: 73: return EXIT_SUCCESS; unconditional 0 taken 3 -: 74: } -: 75: } -: 76: 22: 77: else if (comm && comm[0] && *comm[0] == 'l' && strcmp(comm[0], "log") == 0 22: 77-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 21 1: 77-block 1 branch 2 taken 1 (fallthrough) branch 3 taken 0 1: 77-block 2 branch 4 taken 1 (fallthrough) branch 5 taken 0 1: 77-block 3 branch 6 taken 1 (fallthrough) branch 7 taken 0 1: 78: && comm[1]) { 1: 78-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 0 1: 79: if (*comm[1] == 'c' && strcmp(comm[1], "clear") == 0) 1: 79-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 0 1: 79-block 1 branch 2 taken 1 (fallthrough) branch 3 taken 0 1: 80: clear_log = 1; 1: 80-block 0 unconditional 0 taken 1 #####: 81: else if (*comm[1] == 's' && strcmp(comm[1], "status") == 0) { %%%%%: 81-block 0 branch 0 never executed branch 1 never executed %%%%%: 81-block 1 branch 2 never executed branch 3 never executed #####: 82: printf(_("Logs %s\n"), (logs_enabled) ? _("enabled") %%%%%: 82-block 0 branch 0 never executed branch 1 never executed %%%%%: 82-block 1 call 2 never executed unconditional 3 never executed %%%%%: 82-block 2 call 4 never executed call 5 never executed #####: 83: : _("disabled")); %%%%%: 83-block 0 call 0 never executed unconditional 1 never executed #####: 84: return EXIT_SUCCESS; unconditional 0 never executed #####: 85: } else if (*comm[1] == 'o' && strcmp(comm[1], "on") == 0) { %%%%%: 85-block 0 branch 0 never executed branch 1 never executed %%%%%: 85-block 1 branch 2 never executed branch 3 never executed #####: 86: if (logs_enabled) { %%%%%: 86-block 0 branch 0 never executed branch 1 never executed #####: 87: puts(_("Logs already enabled")); %%%%%: 87-block 0 call 0 never executed call 1 never executed unconditional 2 never executed -: 88: } else { #####: 89: logs_enabled = 1; #####: 90: puts(_("Logs successfully enabled")); %%%%%: 90-block 0 call 0 never executed call 1 never executed unconditional 2 never executed -: 91: } #####: 92: return EXIT_SUCCESS; %%%%%: 92-block 0 unconditional 0 never executed #####: 93: } else if (*comm[1] == 'o' && strcmp(comm[1], "off") == 0) { %%%%%: 93-block 0 branch 0 never executed branch 1 never executed %%%%%: 93-block 1 branch 2 never executed branch 3 never executed -: 94: /* If logs were already disabled, just exit. Otherwise, log -: 95: * the "log off" command */ #####: 96: if (!logs_enabled) { %%%%%: 96-block 0 branch 0 never executed branch 1 never executed #####: 97: puts(_("Logs already disabled")); %%%%%: 97-block 0 call 0 never executed call 1 never executed #####: 98: return EXIT_SUCCESS; unconditional 0 never executed -: 99: } else { #####: 100: puts(_("Logs succesfully disabled")); %%%%%: 100-block 0 call 0 never executed call 1 never executed #####: 101: logs_enabled = 0; unconditional 0 never executed -: 102: } -: 103: } -: 104: } -: 105: -: 106: /* Construct the log line */ 22: 107: if (!last_cmd) { 22: 107-block 0 branch 0 taken 22 (fallthrough) branch 1 taken 0 22: 108: if (!logs_enabled) { 22: 108-block 0 branch 0 taken 22 (fallthrough) branch 1 taken 0 -: 109: /* When cmd logs are disabled, "log clear" and "log off" are -: 110: * the only commands that can reach this code */ 22: 111: if (clear_log) { 22: 111-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 21 1: 112: last_cmd = (char *)xnmalloc(10, sizeof(char)); 1: 112-block 0 call 0 returned 1 1: 113: strcpy(last_cmd, "log clear"); unconditional 0 taken 1 -: 114: } else { 21: 115: last_cmd = (char *)xnmalloc(8, sizeof(char)); 21: 115-block 0 call 0 returned 21 21: 116: strcpy(last_cmd, "log off"); unconditional 0 taken 21 -: 117: } -: 118: } else { -: 119: /* last_cmd should never be NULL if logs are enabled (this -: 120: * variable is set immediately after taking valid user input -: 121: * in the prompt function). However ... */ #####: 122: last_cmd = (char *)xnmalloc(23, sizeof(char)); %%%%%: 122-block 0 call 0 never executed #####: 123: strcpy(last_cmd, _("Error getting command!")); call 0 never executed unconditional 1 never executed -: 124: } -: 125: } -: 126: 22: 127: char *date = get_date(); 22: 127-block 0 call 0 returned 22 22: 128: size_t log_len = strlen(date) + strlen(ws[cur_ws].path) 22: 129: + strlen(last_cmd) + 6; 22: 130: char *full_log = (char *)xnmalloc(log_len, sizeof(char)); call 0 returned 22 -: 131: 22: 132: snprintf(full_log, log_len, "[%s] %s:%s\n", date, ws[cur_ws].path, last_cmd); -: 133: 22: 134: free(date); 22: 135: free(last_cmd); 22: 136: last_cmd = (char *)NULL; -: 137: -: 138: /* Write the log into LOG_FILE */ -: 139: FILE *log_fp; -: 140: /* If not 'log clear', append the log to the existing logs */ -: 141: 22: 142: if (!clear_log) branch 0 taken 21 (fallthrough) branch 1 taken 1 21: 143: log_fp = fopen(log_file, "a"); 21: 143-block 0 call 0 returned 21 unconditional 1 taken 21 -: 144: else -: 145: /* Else, overwrite the log file leaving only the 'log clear' -: 146: * command */ 1: 147: log_fp = fopen(log_file, "w+"); 1: 147-block 0 call 0 returned 1 unconditional 1 taken 1 -: 148: 22: 149: if (!log_fp) { 22: 149-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 22 #####: 150: _err('e', PRINT_PROMPT, "%s: log: '%s': %s\n", PROGRAM_NAME, call 0 never executed #####: 151: log_file, strerror(errno)); %%%%%: 151-block 0 call 0 never executed #####: 152: free(full_log); #####: 153: return EXIT_FAILURE; unconditional 0 never executed -: 154: } else { /* If LOG_FILE was correctly opened, write the log */ 22: 155: fputs(full_log, log_fp); 22: 155-block 0 call 0 returned 22 22: 156: free(full_log); 22: 157: fclose(log_fp); call 0 returned 22 -: 158: 22: 159: return EXIT_SUCCESS; unconditional 0 taken 22 -: 160: } -: 161:} -: 162: -: 163:/* Handle the error message MSG. Store MSG in an array of error -: 164: * messages, write it into an error log file, and print it immediately -: 165: * (if PRINT is zero (NOPRINT_PROMPT) or tell the next prompt, if PRINT -: 166: * is one to do it (PRINT_PROMPT)). Messages wrote to the error log file -: 167: * have the following format: -: 168: * "[date] msg", where 'date' is YYYY-MM-DDTHH:MM:SS */ -: 169:void function log_msg called 3 returned 100% blocks executed 67% 3: 170:log_msg(char *_msg, int print) -: 171:{ 3: 172: if (!_msg) 3: 172-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 3 #####: 173: return; %%%%%: 173-block 0 unconditional 0 never executed -: 174: 3: 175: size_t msg_len = strlen(_msg); 3: 176: if (msg_len == 0) 3: 176-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 3 #####: 177: return; %%%%%: 177-block 0 unconditional 0 never executed -: 178: -: 179: /* Store messages (for current session only) in an array, so that -: 180: * the user can check them via the 'msg' command */ 3: 181: msgs_n++; 3: 182: messages = (char **)xrealloc(messages, (size_t)(msgs_n + 1) * sizeof(char *)); 3: 182-block 0 call 0 returned 3 3: 183: messages[msgs_n - 1] = savestring(_msg, msg_len); call 0 returned 3 3: 184: messages[msgs_n] = (char *)NULL; -: 185: 3: 186: if (print) /* PRINT_PROMPT */ branch 0 taken 3 (fallthrough) branch 1 taken 0 -: 187: /* The next prompt will take care of printing the message */ 3: 188: print_msg = 1; 3: 188-block 0 unconditional 0 taken 3 -: 189: else /* NOPRINT_PROMPT */ -: 190: /* Print the message directly here */ #####: 191: fputs(_msg, stderr); %%%%%: 191-block 0 call 0 never executed unconditional 1 never executed -: 192: -: 193: /* If the config dir cannot be found or if msg log file isn't set -: 194: * yet... This will happen if an error occurs before running -: 195: * init_config(), for example, if the user's home cannot be found */ 3: 196: if (!config_ok || !msg_log_file || !*msg_log_file) 3: 196-block 0 branch 0 taken 3 (fallthrough) branch 1 taken 0 3: 196-block 1 branch 2 taken 3 (fallthrough) branch 3 taken 0 3: 196-block 2 branch 4 taken 0 (fallthrough) branch 5 taken 3 #####: 197: return; %%%%%: 197-block 0 unconditional 0 never executed -: 198: 3: 199: FILE *msg_fp = fopen(msg_log_file, "a"); 3: 199-block 0 call 0 returned 3 3: 200: if (!msg_fp) { branch 0 taken 0 (fallthrough) branch 1 taken 3 -: 201: /* Do not log this error: We might incur in an infinite loop -: 202: * trying to access a file that cannot be accessed */ #####: 203: fprintf(stderr, "%s: %s: %s\n", PROGRAM_NAME, msg_log_file, call 0 never executed #####: 204: strerror(errno)); %%%%%: 204-block 0 call 0 never executed #####: 205: fputs("Press any key to continue... ", stdout); call 0 never executed #####: 206: xgetchar(); call 0 never executed #####: 207: putchar('\n'); call 0 never executed unconditional 1 never executed -: 208: } else { -: 209: /* Write message to messages file: [date] msg */ 3: 210: time_t rawtime = time(NULL); 3: 210-block 0 call 0 returned 3 -: 211: struct tm tm; 3: 212: localtime_r(&rawtime, &tm); call 0 returned 3 3: 213: char date[64] = ""; -: 214: 3: 215: strftime(date, sizeof(date), "%b %d %H:%M:%S %Y", &tm); 3: 216: fprintf(msg_fp, "[%d-%d-%dT%d:%d:%d] ", tm.tm_year + 1900, 3: 217: tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); call 0 returned 3 3: 218: fputs(_msg, msg_fp); call 0 returned 3 3: 219: fclose(msg_fp); call 0 returned 3 -: 220: } -: 221:} -: 222: -: 223:int function save_dirhist called 4 returned 100% blocks executed 67% 4: 224:save_dirhist(void) -: 225:{ 4: 226: if (!dirhist_file) 4: 226-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 4 #####: 227: return EXIT_FAILURE; %%%%%: 227-block 0 unconditional 0 never executed -: 228: 4: 229: if (!old_pwd || !old_pwd[0]) 4: 229-block 0 branch 0 taken 4 (fallthrough) branch 1 taken 0 4: 229-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 4 #####: 230: return EXIT_SUCCESS; %%%%%: 230-block 0 unconditional 0 never executed -: 231: 4: 232: FILE *fp = fopen(dirhist_file, "w"); 4: 232-block 0 call 0 returned 4 4: 233: if (!fp) { branch 0 taken 0 (fallthrough) branch 1 taken 4 #####: 234: fprintf(stderr, _("%s: Could not save directory history: %s\n"), call 0 never executed call 1 never executed #####: 235: PROGRAM_NAME, strerror(errno)); %%%%%: 235-block 0 call 0 never executed #####: 236: return EXIT_FAILURE; unconditional 0 never executed -: 237: } -: 238: -: 239: int i; 482: 240: for (i = 0; i < dirhist_total_index; i++) { 4: 240-block 0 unconditional 0 taken 4 478: 240-block 1 unconditional 1 taken 478 482: 240-block 2 branch 2 taken 478 branch 3 taken 4 (fallthrough) -: 241: /* Exclude invalid entries */ 478*: 242: if (!old_pwd[i] || *old_pwd[i] == _ESC) 478: 242-block 0 branch 0 taken 478 (fallthrough) branch 1 taken 0 478: 242-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 478 #####: 243: continue; %%%%%: 243-block 0 unconditional 0 never executed 478: 244: fprintf(fp, "%s\n", old_pwd[i]); 478: 244-block 0 call 0 returned 478 unconditional 1 taken 478 -: 245: } -: 246: 4: 247: fclose(fp); 4: 247-block 0 call 0 returned 4 4: 248: return EXIT_SUCCESS; unconditional 0 taken 4 -: 249:} -: 250: -: 251:/* Add DIR_PATH to visited directory history (old_pwd) */ -: 252:void function add_to_dirhist called 67 returned 100% blocks executed 100% 67: 253:add_to_dirhist(const char *dir_path) -: 254:{ -: 255: /* static size_t end_counter = 11, mid_counter = 11; */ -: 256: -: 257: /* If already at the end of dirhist, add new entry */ 67: 258: if (dirhist_cur_index + 1 >= dirhist_total_index) { 67: 258-block 0 branch 0 taken 58 (fallthrough) branch 1 taken 9 -: 259: /* Do not add anything if new path equals last entry in -: 260: * directory history */ 58: 261: if ((dirhist_total_index - 1) >= 0 && old_pwd[dirhist_total_index - 1] && *(dir_path + 1) == *(old_pwd[dirhist_total_index - 1] + 1) && strcmp(dir_path, old_pwd[dirhist_total_index - 1]) == 0) 58: 261-block 0 branch 0 taken 58 (fallthrough) branch 1 taken 0 58: 261-block 1 branch 2 taken 58 (fallthrough) branch 3 taken 0 58: 261-block 2 branch 4 taken 53 (fallthrough) branch 5 taken 5 53: 261-block 3 branch 6 taken 3 (fallthrough) branch 7 taken 50 3: 262: return; 3: 262-block 0 unconditional 0 taken 3 -: 263: -: 264: /* Realloc only once per 10 operations */ -: 265: /* if (end_counter > 10) { -: 266: end_counter = 1; */ -: 267: /* 20: Realloc dirhist_total + (2 * 10) */ 110: 268: old_pwd = (char **)xrealloc(old_pwd, 55: 269: (size_t)(dirhist_total_index + 2) * sizeof(char *)); 55: 269-block 0 call 0 returned 55 -: 270: /* } -: 271: -: 272: end_counter++; */ -: 273: 55: 274: dirhist_cur_index = dirhist_total_index; 55: 275: old_pwd[dirhist_total_index++] = savestring(dir_path, strlen(dir_path)); call 0 returned 55 55: 276: old_pwd[dirhist_total_index] = (char *)NULL; unconditional 0 taken 55 -: 277: } -: 278: -: 279: /* I not at the end of dirhist, add previous AND new entry */ -: 280: else { -: 281: /* if (mid_counter > 10) { -: 282: mid_counter = 1; */ -: 283: /* 30: Realloc dirhist_total + (3 * 10) */ 18: 284: old_pwd = (char **)xrealloc(old_pwd, 9: 285: (size_t)(dirhist_total_index + 3) * sizeof(char *)); 9: 285-block 0 call 0 returned 9 -: 286: /* } -: 287: -: 288: mid_counter++; */ -: 289: 18: 290: old_pwd[dirhist_total_index++] = savestring( 9: 291: old_pwd[dirhist_cur_index], 9: 292: strlen(old_pwd[dirhist_cur_index])); call 0 returned 9 -: 293: 9: 294: dirhist_cur_index = dirhist_total_index; 9: 295: old_pwd[dirhist_total_index++] = savestring(dir_path, strlen(dir_path)); call 0 returned 9 -: 296: 9: 297: old_pwd[dirhist_total_index] = (char *)NULL; unconditional 0 taken 9 -: 298: } -: 299:} -: 300: -: 301:int function history_function called 1 returned 100% blocks executed 18% 1: 302:history_function(char **comm) -: 303:{ 1: 304: if (!config_ok) { 1: 304-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 1 #####: 305: fprintf(stderr, _("%s: History function disabled\n"), PROGRAM_NAME); %%%%%: 305-block 0 call 0 never executed call 1 never executed #####: 306: return EXIT_FAILURE; unconditional 0 never executed -: 307: } -: 308: -: 309: /* If no arguments, print the history list */ 1: 310: if (args_n == 0) { 1: 310-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 0 -: 311: size_t i; 1111: 312: for (i = 0; i < current_hist_n; i++) 1: 312-block 0 unconditional 0 taken 1 unconditional 1 taken 1110 1111: 312-block 1 branch 2 taken 1110 branch 3 taken 1 (fallthrough) 1110: 313: printf(" %zu %s\n", i + 1, history[i]); 1110: 313-block 0 call 0 returned 1110 1: 314: return EXIT_SUCCESS; 1: 314-block 0 unconditional 0 taken 1 -: 315: } -: 316: -: 317: /* If 'history clear', guess what, clear the history list! */ #####: 318: if (args_n == 1 && strcmp(comm[1], "clear") == 0) { %%%%%: 318-block 0 branch 0 never executed branch 1 never executed %%%%%: 318-block 1 branch 2 never executed branch 3 never executed #####: 319: FILE *hist_fp = fopen(hist_file, "w+"); %%%%%: 319-block 0 call 0 never executed #####: 320: if (!hist_fp) { branch 0 never executed branch 1 never executed #####: 321: _err(0, NOPRINT_PROMPT, "%s: history: %s: %s\n", call 0 never executed #####: 322: PROGRAM_NAME, hist_file, strerror(errno)); %%%%%: 322-block 0 call 0 never executed #####: 323: return EXIT_FAILURE; unconditional 0 never executed -: 324: } -: 325: -: 326: /* Do not create an empty file */ #####: 327: fprintf(hist_fp, "%s %s\n", comm[0], comm[1]); %%%%%: 327-block 0 call 0 never executed #####: 328: fclose(hist_fp); call 0 never executed -: 329: -: 330: /* Reset readline history */ #####: 331: clear_history(); call 0 never executed #####: 332: read_history(hist_file); call 0 never executed #####: 333: history_truncate_file(hist_file, max_hist); call 0 never executed -: 334: -: 335: /* Update the history array */ #####: 336: int exit_status = EXIT_SUCCESS; -: 337: #####: 338: if (get_history() != 0) call 0 never executed branch 1 never executed branch 2 never executed #####: 339: exit_status = EXIT_FAILURE; %%%%%: 339-block 0 unconditional 0 never executed -: 340: #####: 341: if (log_function(comm) != 0) %%%%%: 341-block 0 call 0 never executed branch 1 never executed branch 2 never executed #####: 342: exit_code = EXIT_FAILURE; %%%%%: 342-block 0 unconditional 0 never executed -: 343: #####: 344: return exit_status; %%%%%: 344-block 0 unconditional 0 never executed -: 345: } -: 346: -: 347: /* If 'history -n', print the last -n elements */ #####: 348: if (args_n == 1 && comm[1][0] == '-' && is_number(comm[1] + 1)) { %%%%%: 348-block 0 branch 0 never executed branch 1 never executed %%%%%: 348-block 1 branch 2 never executed branch 3 never executed %%%%%: 348-block 2 call 4 never executed branch 5 never executed branch 6 never executed #####: 349: int num = atoi(comm[1] + 1); -: 350: #####: 351: if (num < 0 || num > (int)current_hist_n) %%%%%: 351-block 0 branch 0 never executed branch 1 never executed %%%%%: 351-block 1 branch 2 never executed branch 3 never executed #####: 352: num = (int)current_hist_n; %%%%%: 352-block 0 unconditional 0 never executed -: 353: -: 354: size_t i; #####: 355: for (i = current_hist_n - (size_t)num; i < current_hist_n; i++) %%%%%: 355-block 0 unconditional 0 never executed unconditional 1 never executed %%%%%: 355-block 1 branch 2 never executed branch 3 never executed #####: 356: printf("%zu %s\n", i + 1, history[i]); %%%%%: 356-block 0 call 0 never executed -: 357: #####: 358: return EXIT_SUCCESS; %%%%%: 358-block 0 unconditional 0 never executed -: 359: } -: 360: -: 361: /* None of the above */ #####: 362: puts(_(HISTORY_USAGE)); %%%%%: 362-block 0 call 0 never executed call 1 never executed #####: 363: return EXIT_SUCCESS; unconditional 0 never executed -: 364:} -: 365: -: 366:/* Takes as argument the history cmd less the first exclamation mark. -: 367: * Example: if exec_cmd() gets "!-10" it pass to this function "-10", -: 368: * that is, comm + 1 */ -: 369:int function run_history_cmd called 2 returned 100% blocks executed 28% 2: 370:run_history_cmd(const char *cmd) -: 371:{ -: 372: /* If "!n" */ 2: 373: int exit_status = EXIT_SUCCESS; -: 374: size_t i; -: 375: 2: 376: if (is_number(cmd)) { 2: 376-block 0 call 0 returned 2 branch 1 taken 0 (fallthrough) branch 2 taken 2 #####: 377: int num = atoi(cmd); -: 378: #####: 379: if (num <= 0 || num >= (int)current_hist_n) { %%%%%: 379-block 0 branch 0 never executed branch 1 never executed %%%%%: 379-block 1 branch 2 never executed branch 3 never executed #####: 380: fprintf(stderr, _("%s: !%d: event not found\n"), PROGRAM_NAME, num); %%%%%: 380-block 0 call 0 never executed call 1 never executed #####: 381: return EXIT_FAILURE; unconditional 0 never executed -: 382: } -: 383: #####: 384: size_t old_args = args_n; -: 385: #####: 386: if (record_cmd(history[num - 1])) %%%%%: 386-block 0 call 0 never executed branch 1 never executed branch 2 never executed #####: 387: add_to_cmdhist(history[num - 1]); %%%%%: 387-block 0 call 0 never executed unconditional 1 never executed -: 388: #####: 389: char **cmd_hist = parse_input_str(history[num - 1]); %%%%%: 389-block 0 call 0 never executed #####: 390: if (!cmd_hist) { branch 0 never executed branch 1 never executed #####: 391: fprintf(stderr, _("%s: Error parsing history command\n"), %%%%%: 391-block 0 call 0 never executed call 1 never executed -: 392: PROGRAM_NAME); #####: 393: return EXIT_FAILURE; unconditional 0 never executed -: 394: } -: 395: #####: 396: char **alias_cmd = check_for_alias(cmd_hist); %%%%%: 396-block 0 call 0 never executed #####: 397: if (alias_cmd) { branch 0 never executed branch 1 never executed -: 398: /* If an alias is found, the function frees cmd_hist -: 399: * and returns alias_cmd in its place to be executed -: 400: * by exec_cmd() */ -: 401: #####: 402: if (exec_cmd(alias_cmd) != 0) %%%%%: 402-block 0 call 0 never executed branch 1 never executed branch 2 never executed #####: 403: exit_status = EXIT_FAILURE; %%%%%: 403-block 0 unconditional 0 never executed -: 404: #####: 405: for (i = 0; alias_cmd[i]; i++) %%%%%: 405-block 0 unconditional 0 never executed %%%%%: 405-block 1 branch 1 never executed branch 2 never executed #####: 406: free(alias_cmd[i]); %%%%%: 406-block 0 unconditional 0 never executed #####: 407: free(alias_cmd); #####: 408: alias_cmd = (char **)NULL; %%%%%: 408-block 0 unconditional 0 never executed -: 409: } else { #####: 410: if (exec_cmd(cmd_hist) != 0) %%%%%: 410-block 0 call 0 never executed branch 1 never executed branch 2 never executed #####: 411: exit_status = EXIT_FAILURE; %%%%%: 411-block 0 unconditional 0 never executed -: 412: #####: 413: for (i = 0; cmd_hist[i]; i++) %%%%%: 413-block 0 unconditional 0 never executed %%%%%: 413-block 1 branch 1 never executed branch 2 never executed #####: 414: free(cmd_hist[i]); %%%%%: 414-block 0 unconditional 0 never executed #####: 415: free(cmd_hist); %%%%%: 415-block 0 unconditional 0 never executed -: 416: } -: 417: #####: 418: args_n = old_args; #####: 419: return exit_status; %%%%%: 419-block 0 unconditional 0 never executed -: 420: } -: 421: -: 422: /* If "!!", execute the last command */ 2: 423: if (*cmd == '!' && !cmd[1]) { 2: 423-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 1 1: 423-block 1 branch 2 taken 1 (fallthrough) branch 3 taken 0 1: 424: size_t old_args = args_n; -: 425: 1: 426: if (record_cmd(history[current_hist_n - 1])) 1: 426-block 0 call 0 returned 1 branch 1 taken 0 (fallthrough) branch 2 taken 1 #####: 427: add_to_cmdhist(history[current_hist_n - 1]); %%%%%: 427-block 0 call 0 never executed unconditional 1 never executed -: 428: 1: 429: char **cmd_hist = parse_input_str(history[current_hist_n - 1]); 1: 429-block 0 call 0 returned 1 1: 430: if (!cmd_hist) { branch 0 taken 0 (fallthrough) branch 1 taken 1 #####: 431: fprintf(stderr, _("%s: Error parsing history command\n"), %%%%%: 431-block 0 call 0 never executed call 1 never executed -: 432: PROGRAM_NAME); #####: 433: return EXIT_FAILURE; unconditional 0 never executed -: 434: } -: 435: 1: 436: char **alias_cmd = check_for_alias(cmd_hist); 1: 436-block 0 call 0 returned 1 1: 437: if (alias_cmd) { branch 0 taken 0 (fallthrough) branch 1 taken 1 #####: 438: if (exec_cmd(alias_cmd) != 0) %%%%%: 438-block 0 call 0 never executed branch 1 never executed branch 2 never executed #####: 439: exit_status = EXIT_FAILURE; %%%%%: 439-block 0 unconditional 0 never executed -: 440: #####: 441: for (i = 0; alias_cmd[i]; i++) %%%%%: 441-block 0 unconditional 0 never executed %%%%%: 441-block 1 branch 1 never executed branch 2 never executed #####: 442: free(alias_cmd[i]); %%%%%: 442-block 0 unconditional 0 never executed #####: 443: free(alias_cmd); -: 444: #####: 445: alias_cmd = (char **)NULL; %%%%%: 445-block 0 unconditional 0 never executed -: 446: } else { 1: 447: if (exec_cmd(cmd_hist) != 0) 1: 447-block 0 call 0 returned 1 branch 1 taken 0 (fallthrough) branch 2 taken 1 #####: 448: exit_status = EXIT_FAILURE; %%%%%: 448-block 0 unconditional 0 never executed -: 449: 3: 450: for (i = 0; cmd_hist[i]; i++) 1: 450-block 0 unconditional 0 taken 1 3: 450-block 1 branch 1 taken 2 branch 2 taken 1 (fallthrough) 2: 451: free(cmd_hist[i]); 2: 451-block 0 unconditional 0 taken 2 1: 452: free(cmd_hist); 1: 452-block 0 unconditional 0 taken 1 -: 453: } -: 454: 1: 455: args_n = old_args; 1: 456: return exit_status; 1: 456-block 0 unconditional 0 taken 1 -: 457: } -: 458: -: 459: /* If "!-n" */ 1: 460: if (*cmd == '-') { 1: 460-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 0 -: 461: /* If not number or zero or bigger than max... */ 1: 462: int acmd = atoi(cmd + 1); -: 463: 1: 464: if (!is_number(cmd + 1) || acmd == 0 || acmd > (int)current_hist_n - 1) { 1: 464-block 0 call 0 returned 1 branch 1 taken 1 (fallthrough) branch 2 taken 0 1: 464-block 1 branch 3 taken 1 (fallthrough) branch 4 taken 0 1: 464-block 2 branch 5 taken 0 (fallthrough) branch 6 taken 1 #####: 465: fprintf(stderr, _("%s: !%s: Event not found\n"), PROGRAM_NAME, cmd); %%%%%: 465-block 0 call 0 never executed call 1 never executed #####: 466: return EXIT_FAILURE; unconditional 0 never executed -: 467: } -: 468: 1: 469: size_t old_args = args_n; 1: 470: char **cmd_hist = parse_input_str(history[current_hist_n - (size_t)acmd - 1]); 1: 470-block 0 call 0 returned 1 1: 471: if (cmd_hist) { branch 0 taken 1 (fallthrough) branch 1 taken 0 1: 472: char **alias_cmd = check_for_alias(cmd_hist); 1: 472-block 0 call 0 returned 1 1: 473: if (alias_cmd) { branch 0 taken 0 (fallthrough) branch 1 taken 1 #####: 474: if (exec_cmd(alias_cmd) != 0) %%%%%: 474-block 0 call 0 never executed branch 1 never executed branch 2 never executed #####: 475: exit_status = EXIT_FAILURE; %%%%%: 475-block 0 unconditional 0 never executed -: 476: #####: 477: for (i = 0; alias_cmd[i]; i++) %%%%%: 477-block 0 unconditional 0 never executed %%%%%: 477-block 1 branch 1 never executed branch 2 never executed #####: 478: free(alias_cmd[i]); %%%%%: 478-block 0 unconditional 0 never executed #####: 479: free(alias_cmd); #####: 480: alias_cmd = (char **)NULL; %%%%%: 480-block 0 unconditional 0 never executed -: 481: } else { 1: 482: if (exec_cmd(cmd_hist) != 0) 1: 482-block 0 call 0 returned 1 branch 1 taken 0 (fallthrough) branch 2 taken 1 #####: 483: exit_status = EXIT_FAILURE; %%%%%: 483-block 0 unconditional 0 never executed -: 484: 2: 485: for (i = 0; cmd_hist[i]; i++) 1: 485-block 0 unconditional 0 taken 1 2: 485-block 1 branch 1 taken 1 branch 2 taken 1 (fallthrough) 1: 486: free(cmd_hist[i]); 1: 486-block 0 unconditional 0 taken 1 1: 487: free(cmd_hist); 1: 487-block 0 unconditional 0 taken 1 -: 488: } -: 489: 1: 490: if (record_cmd(history[current_hist_n - (size_t)acmd - 1])) 1: 490-block 0 call 0 returned 1 branch 1 taken 1 (fallthrough) branch 2 taken 0 1: 491: add_to_cmdhist(history[current_hist_n - (size_t)acmd - 1]); 1: 491-block 0 call 0 returned 1 unconditional 1 taken 1 -: 492: 1: 493: args_n = old_args; 1: 494: return exit_status; 1: 494-block 0 unconditional 0 taken 1 -: 495: } -: 496: #####: 497: if (record_cmd(history[current_hist_n - (size_t)acmd - 1])) %%%%%: 497-block 0 call 0 never executed branch 1 never executed branch 2 never executed #####: 498: add_to_cmdhist(history[current_hist_n - (size_t)acmd - 1]); %%%%%: 498-block 0 call 0 never executed unconditional 1 never executed -: 499: #####: 500: fprintf(stderr, _("%s: Error parsing history command\n"), PROGRAM_NAME); %%%%%: 500-block 0 call 0 never executed call 1 never executed #####: 501: return EXIT_FAILURE; unconditional 0 never executed -: 502: } -: 503: #####: 504: if ((*cmd >= 'a' && *cmd <= 'z') || (*cmd >= 'A' && *cmd <= 'Z')) { %%%%%: 504-block 0 branch 0 never executed branch 1 never executed %%%%%: 504-block 1 branch 2 never executed branch 3 never executed %%%%%: 504-block 2 branch 4 never executed branch 5 never executed %%%%%: 504-block 3 branch 6 never executed branch 7 never executed #####: 505: size_t len = strlen(cmd), #####: 506: old_args = args_n; -: 507: #####: 508: for (i = 0; history[i]; i++) { %%%%%: 508-block 0 unconditional 0 never executed %%%%%: 508-block 1 unconditional 1 never executed %%%%%: 508-block 2 branch 2 never executed branch 3 never executed #####: 509: if (*cmd == *history[i] && strncmp(cmd, history[i], len) == 0) { %%%%%: 509-block 0 branch 0 never executed branch 1 never executed %%%%%: 509-block 1 branch 2 never executed branch 3 never executed #####: 510: char **cmd_hist = parse_input_str(history[i]); %%%%%: 510-block 0 call 0 never executed #####: 511: if (!cmd_hist) branch 0 never executed branch 1 never executed #####: 512: continue; %%%%%: 512-block 0 unconditional 0 never executed -: 513: #####: 514: char **alias_cmd = check_for_alias(cmd_hist); %%%%%: 514-block 0 call 0 never executed #####: 515: if (alias_cmd) { branch 0 never executed branch 1 never executed #####: 516: if (exec_cmd(alias_cmd) != EXIT_SUCCESS) %%%%%: 516-block 0 call 0 never executed branch 1 never executed branch 2 never executed #####: 517: exit_status = EXIT_FAILURE; %%%%%: 517-block 0 unconditional 0 never executed -: 518: #####: 519: for (i = 0; alias_cmd[i]; i++) %%%%%: 519-block 0 unconditional 0 never executed %%%%%: 519-block 1 branch 1 never executed branch 2 never executed #####: 520: free(alias_cmd[i]); %%%%%: 520-block 0 unconditional 0 never executed #####: 521: free(alias_cmd); #####: 522: alias_cmd = (char **)NULL; %%%%%: 522-block 0 unconditional 0 never executed -: 523: } else { #####: 524: if (exec_cmd(cmd_hist) != EXIT_SUCCESS) %%%%%: 524-block 0 call 0 never executed branch 1 never executed branch 2 never executed #####: 525: exit_status = EXIT_FAILURE; %%%%%: 525-block 0 unconditional 0 never executed -: 526: #####: 527: for (i = 0; cmd_hist[i]; i++) %%%%%: 527-block 0 unconditional 0 never executed %%%%%: 527-block 1 branch 1 never executed branch 2 never executed #####: 528: free(cmd_hist[i]); %%%%%: 528-block 0 unconditional 0 never executed #####: 529: free(cmd_hist); %%%%%: 529-block 0 unconditional 0 never executed -: 530: } -: 531: #####: 532: args_n = old_args; #####: 533: return exit_status; %%%%%: 533-block 0 unconditional 0 never executed -: 534: } -: 535: } -: 536: #####: 537: fprintf(stderr, _("%s: !%s: Event not found\n"), PROGRAM_NAME, cmd); %%%%%: 537-block 0 call 0 never executed call 1 never executed #####: 538: return EXIT_FAILURE; unconditional 0 never executed -: 539: } -: 540: #####: 541: puts(_(HISTEXEC_USAGE)); %%%%%: 541-block 0 call 0 never executed call 1 never executed #####: 542: return EXIT_SUCCESS; unconditional 0 never executed -: 543:} -: 544: -: 545:int function get_history called 13 returned 100% blocks executed 84% 13: 546:get_history(void) -: 547:{ 13: 548: if (!config_ok) 13: 548-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 13 #####: 549: return EXIT_FAILURE; %%%%%: 549-block 0 unconditional 0 never executed -: 550: 13: 551: if (current_hist_n == 0) { /* Coming from main() */ 13: 551-block 0 branch 0 taken 4 (fallthrough) branch 1 taken 9 4: 552: history = (char **)xcalloc(1, sizeof(char *)); 4: 552-block 0 call 0 returned 4 unconditional 1 taken 4 -: 553: } else { /* Only true when comming from 'history clear' */ -: 554: size_t i; 3605: 555: for (i = 0; history[i]; i++) 9: 555-block 0 unconditional 0 taken 9 3605: 555-block 1 branch 1 taken 3596 branch 2 taken 9 (fallthrough) 3596: 556: free(history[i]); 3596: 556-block 0 unconditional 0 taken 3596 9: 557: history = (char **)xrealloc(history, 1 * sizeof(char *)); 9: 557-block 0 call 0 returned 9 9: 558: current_hist_n = 0; unconditional 0 taken 9 -: 559: } -: 560: 13: 561: FILE *hist_fp = fopen(hist_file, "r"); 13: 561-block 0 call 0 returned 13 13: 562: if (!hist_fp) { branch 0 taken 0 (fallthrough) branch 1 taken 13 #####: 563: _err('e', PRINT_PROMPT, "%s: history: '%s': %s\n", call 0 never executed #####: 564: PROGRAM_NAME, hist_file, strerror(errno)); %%%%%: 564-block 0 call 0 never executed #####: 565: return EXIT_FAILURE; unconditional 0 never executed -: 566: } -: 567: 13: 568: size_t line_size = 0; 13: 569: char *line_buff = (char *)NULL; 13: 570: ssize_t line_len = 0; -: 571: 6503: 572: while ((line_len = getline(&line_buff, &line_size, hist_fp)) > 0) { 13: 572-block 0 unconditional 0 taken 13 6503: 572-block 1 call 1 returned 6503 branch 2 taken 6490 branch 3 taken 13 (fallthrough) 6490: 573: line_buff[line_len - 1] = '\0'; 6490: 574: history = (char **)xrealloc(history, (current_hist_n + 2) * sizeof(char *)); 6490: 574-block 0 call 0 returned 6490 6490: 575: history[current_hist_n++] = savestring(line_buff, (size_t)line_len); call 0 returned 6490 unconditional 1 taken 6490 -: 576: } -: 577: 13: 578: history[current_hist_n] = (char *)NULL; 13: 579: free(line_buff); 13: 580: fclose(hist_fp); 13: 580-block 0 call 0 returned 13 13: 581: return EXIT_SUCCESS; unconditional 0 taken 13 -: 582:} -: 583: -: 584:void function add_to_cmdhist called 248 returned 100% blocks executed 89% 248: 585:add_to_cmdhist(const char *cmd) -: 586:{ 248: 587: if (!cmd) 248: 587-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 248 #####: 588: return; %%%%%: 588-block 0 unconditional 0 never executed -: 589: -: 590: /* For readline */ 248: 591: add_history(cmd); 248: 591-block 0 call 0 returned 248 -: 592: 248: 593: if (config_ok) branch 0 taken 248 (fallthrough) branch 1 taken 0 248: 594: append_history(1, hist_file); 248: 594-block 0 call 0 returned 248 unconditional 1 taken 248 -: 595: -: 596: /* For us */ -: 597: /* Add the new input to the history array */ 248: 598: size_t cmd_len = strlen(cmd); 248: 599: history = (char **)xrealloc(history, (size_t)(current_hist_n + 2) * sizeof(char *)); 248: 599-block 0 call 0 returned 248 248: 600: history[current_hist_n++] = savestring(cmd, cmd_len); call 0 returned 248 248: 601: history[current_hist_n] = (char *)NULL; unconditional 0 taken 248 -: 602:} -: 603: -: 604:/* Returns 1 if INPUT should be stored in history and 0 if not */ -: 605:int function record_cmd called 510 returned 100% blocks executed 77% 510: 606:record_cmd(char *input) -: 607:{ -: 608: /* NULL input */ 510: 609: if (!input) 510: 609-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 510 #####: 610: return 0; %%%%%: 610-block 0 unconditional 0 never executed -: 611: -: 612: /* Blank lines */ 510: 613: unsigned int blank = 1; 510: 614: char *p = input; -: 615: 510: 616: while (*p) { 510: 616-block 0 unconditional 0 taken 510 510: 616-block 1 branch 1 taken 510 branch 2 taken 0 (fallthrough) 510: 617: if (*p > ' ') { 510: 617-block 0 branch 0 taken 510 (fallthrough) branch 1 taken 0 510: 618: blank = 0; 510: 619: break; 510: 619-block 0 unconditional 0 taken 510 -: 620: } #####: 621: p++; %%%%%: 621-block 0 unconditional 0 never executed -: 622: } -: 623: 510: 624: if (blank) 510: 624-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 510 #####: 625: return 0; %%%%%: 625-block 0 unconditional 0 never executed -: 626: -: 627: /* Rewind the pointer to the beginning of the input line */ 510: 628: p = input; -: 629: -: 630: /* Commands starting with space */ 510: 631: if (*p == ' ') 510: 631-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 510 #####: 632: return 0; %%%%%: 632-block 0 unconditional 0 never executed -: 633: 510: 634: switch (*p) { 510: 634-block 0 branch 0 taken 28 branch 1 taken 12 branch 2 taken 8 branch 3 taken 175 branch 4 taken 4 branch 5 taken 0 branch 6 taken 4 branch 7 taken 279 -: 635: /* Do not record single ELN's */ 28: 636: case '0': /* fallthrough */ -: 637: case '1': /* fallthrough */ -: 638: case '2': /* fallthrough */ -: 639: case '3': /* fallthrough */ -: 640: case '4': /* fallthrough */ -: 641: case '5': /* fallthrough */ -: 642: case '6': /* fallthrough */ -: 643: case '7': /* fallthrough */ -: 644: case '8': /* fallthrough */ -: 645: case '9': 28: 646: if (is_number(p)) 28: 646-block 0 call 0 returned 28 branch 1 taken 25 (fallthrough) branch 2 taken 3 25: 647: return 0; 25: 647-block 0 unconditional 0 taken 25 3: 648: break; 3: 648-block 0 unconditional 0 taken 3 -: 649: 12: 650: case '.': /* . */ 12: 651: if (!*(p + 1)) 12: 651-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 12 #####: 652: return 0; %%%%%: 652-block 0 unconditional 0 never executed 12: 653: break; 12: 653-block 0 unconditional 0 taken 12 -: 654: -: 655: /* Do not record the history command itself */ 8: 656: case 'h': 8: 657: if (*(p + 1) == 'i' && strcmp(p, "history") == 0) 8: 657-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 7 1: 657-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 1 #####: 658: return 0; %%%%%: 658-block 0 unconditional 0 never executed 8: 659: break; 8: 659-block 0 unconditional 0 taken 8 -: 660: 175: 661: case 'r': /* rf command */ 175: 662: if (*(p + 1) == 'f' && !*(p + 2)) 175: 662-block 0 branch 0 taken 168 (fallthrough) branch 1 taken 7 168: 662-block 1 branch 2 taken 168 (fallthrough) branch 3 taken 0 168: 663: return 0; 168: 663-block 0 unconditional 0 taken 168 7: 664: break; 7: 664-block 0 unconditional 0 taken 7 -: 665: -: 666: /* Do not record exit commands */ 4: 667: case 'q': 4*: 668: if (*(p + 1) == '\0' || strcmp(p, "quit") == 0) 4: 668-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 4 %%%%%: 668-block 1 branch 2 never executed branch 3 never executed 4: 669: return 0; 4: 669-block 0 unconditional 0 taken 4 #####: 670: break; %%%%%: 670-block 0 unconditional 0 never executed -: 671: #####: 672: case 'Q': #####: 673: if (*(p + 1) == '\0') %%%%%: 673-block 0 branch 0 never executed branch 1 never executed #####: 674: return 0; %%%%%: 674-block 0 unconditional 0 never executed #####: 675: break; %%%%%: 675-block 0 unconditional 0 never executed -: 676: 4: 677: case 'e': 4: 678: if (*(p + 1) == 'x' && strcmp(p, "exit") == 0) 4: 678-block 0 branch 0 taken 4 (fallthrough) branch 1 taken 0 4: 678-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 4 #####: 679: return 0; %%%%%: 679-block 0 unconditional 0 never executed 4: 680: break; 4: 680-block 0 unconditional 0 taken 4 -: 681: -: 682:/* case 'z': -: 683: if (*(p + 1) == 'z' && *(p + 2) == '\0') -: 684: return 0; -: 685: break; -: 686: -: 687: case 's': -: 688: if (*(p + 1) == 'a' && strcmp(p, "salir") == 0) -: 689: return 0; -: 690: break; -: 691: -: 692: case 'c': -: 693: if (*(p + 1) == 'h' && strcmp(p, "chau") == 0) -: 694: return 0; -: 695: break; */ -: 696: 279: 697: default: break; 279: 697-block 0 unconditional 0 taken 279 -: 698: } -: 699: -: 700: /* History */ 313: 701: if (*p == '!' && (_ISDIGIT(*(p + 1)) || (*(p + 1) == '-' 313: 701-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 311 2: 701-block 1 branch 2 taken 2 (fallthrough) branch 3 taken 0 2: 701-block 2 branch 4 taken 1 (fallthrough) branch 5 taken 1 2: 702: && _ISDIGIT(*(p + 2))) || ((*(p + 1) == '!') && *(p + 2) == '\0'))) 1: 702-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 1 1: 702-block 1 branch 2 taken 1 (fallthrough) branch 3 taken 0 1: 702-block 2 branch 4 taken 1 (fallthrough) branch 5 taken 0 2: 703: return 0; 2: 703-block 0 unconditional 0 taken 2 -: 704: -: 705: /* Consequtively equal commands in history */ 311: 706: if (history && history[current_hist_n - 1] 311: 706-block 0 branch 0 taken 311 (fallthrough) branch 1 taken 0 311: 706-block 1 branch 2 taken 311 (fallthrough) branch 3 taken 0 311: 707: && *p == *history[current_hist_n - 1] 311: 707-block 0 branch 0 taken 153 (fallthrough) branch 1 taken 158 153: 708: && strcmp(p, history[current_hist_n - 1]) == 0) 153: 708-block 0 branch 0 taken 63 (fallthrough) branch 1 taken 90 63: 709: return 0; 63: 709-block 0 unconditional 0 taken 63 -: 710: 248: 711: return 1; 248: 711-block 0 unconditional 0 taken 248 -: 712:} clifm-1.26.3/misc/codecov/init.c.gcov000066400000000000000000004631311506632037700173370ustar00rootroot00000000000000 -: 0:Source:init.c -: 1:/* init.c -- functions controlling the program initialization */ -: 2: -: 3:/* -: 4: * This file is part of CliFM -: 5: * -: 6: * Copyright (C) 2016-2021, L. Abramovich -: 7: * All rights reserved. -: 8: -: 9: * CliFM is free software; you can redistribute it and/or modify -: 10: * it under the terms of the GNU General Public License as published by -: 11: * the Free Software Foundation; either version 2 of the License, or -: 12: * (at your option) any later version. -: 13: * -: 14: * CliFM is distributed in the hope that it will be useful, -: 15: * but WITHOUT ANY WARRANTY; without even the implied warranty of -: 16: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -: 17: * GNU General Public License for more details. -: 18: * -: 19: * You should have received a copy of the GNU General Public License -: 20: * along with this program; if not, write to the Free Software -: 21: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, -: 22: * MA 02110-1301, USA. -: 23:*/ -: 24: -: 25:#include "helpers.h" -: 26: -: 27:#include -: 28:#include -: 29:#include -: 30:#include -: 31:#include -: 32:#include -: 33:#include -: 34:#include -: 35:#include -: 36:#include -: 37:#include -: 38:#include -: 39:#include -: 40:#ifdef __NetBSD__ -: 41:#include -: 42:#endif -: 43: -: 44:#include "aux.h" -: 45:#include "checks.h" -: 46:#include "config.h" -: 47:#include "exec.h" -: 48:#include "init.h" -: 49:#include "mime.h" -: 50:#include "misc.h" -: 51:#include "navigation.h" -: 52:#include "sort.h" -: 53:#include "string.h" -: 54:#include "history.h" -: 55:#include "file_operations.h" -: 56: -: 57:struct user_t user; -: 58: -: 59:/* -: 60: * functions -: 61: */ -: 62: -: 63:#ifndef _NO_GETTEXT -: 64:/* Initialize gettext for translations support */ -: 65:int function init_gettext called 4 returned 100% blocks executed 86% 4: 66:init_gettext(void) -: 67:{ -: 68: char locale_dir[PATH_MAX]; 4*: 69: snprintf(locale_dir, PATH_MAX - 1, "%s/locale", data_dir 4: 69-block 0 unconditional 0 taken 4 %%%%%: 69-block 1 unconditional 1 never executed 4: 70: ? data_dir : "/usr/share"); 4: 70-block 0 branch 0 taken 4 (fallthrough) branch 1 taken 0 4: 71: bindtextdomain(PNL, locale_dir); 4: 71-block 0 call 0 returned 4 4: 72: textdomain(PNL); call 0 returned 4 4: 73: return EXIT_SUCCESS; unconditional 0 taken 4 -: 74: -: 75:} -: 76:#endif -: 77: -: 78:int function backup_argv called 4 returned 100% blocks executed 100% 4: 79:backup_argv(int argc, char **argv) -: 80:{ 4: 81: argc_bk = argc; 4: 82: argv_bk = (char **)xnmalloc((size_t)argc + 1, sizeof(char *)); 4: 82-block 0 call 0 returned 4 -: 83: 4: 84: register int i = argc; 12: 85: while (--i >= 0) unconditional 0 taken 4 12: 85-block 0 branch 1 taken 8 branch 2 taken 4 (fallthrough) 8: 86: argv_bk[i] = savestring(argv[i], strlen(argv[i])); 8: 86-block 0 call 0 returned 8 unconditional 1 taken 8 4: 87: argv_bk[argc] = (char *)NULL; -: 88: 4: 89: return EXIT_SUCCESS; 4: 89-block 0 unconditional 0 taken 4 -: 90:} -: 91: -: 92:int function init_workspaces called 4 returned 100% blocks executed 100% 4: 93:init_workspaces(void) -: 94:{ 4: 95: ws = (struct ws_t *)xnmalloc(MAX_WS, sizeof(struct ws_t)); 4: 95-block 0 call 0 returned 4 4: 96: int i = MAX_WS; 36: 97: while (--i >= 0) unconditional 0 taken 4 36: 97-block 0 branch 1 taken 32 branch 2 taken 4 (fallthrough) 32: 98: ws[i].path = (char *)NULL; 32: 98-block 0 unconditional 0 taken 32 -: 99: 4: 100: return EXIT_SUCCESS; 4: 100-block 0 unconditional 0 taken 4 -: 101:} -: 102: -: 103:int function get_home called 4 returned 100% blocks executed 57% 4: 104:get_home(void) -: 105:{ 4: 106: if (access(user.home, W_OK) == -1) { 4: 106-block 0 call 0 returned 4 branch 1 taken 0 (fallthrough) branch 2 taken 4 -: 107: /* If no user's home, or if it's not writable, there won't be -: 108: * any config nor trash directory. These flags are used to -: 109: * prevent functions from trying to access any of these -: 110: * directories */ #####: 111: home_ok = 0; #####: 112: config_ok = 0; -: 113:#ifndef _NO_TRASH #####: 114: trash_ok = 0; -: 115:#endif -: 116: /* Print message: trash, bookmarks, command logs, commands -: 117: * history and program messages won't be stored */ #####: 118: _err('e', PRINT_PROMPT, _("%s: Cannot access the home directory. " %%%%%: 118-block 0 call 0 never executed call 1 never executed -: 119: "Trash, bookmarks, commands logs, and commands history are " -: 120: "disabled. Program messages and selected files won't be " -: 121: "persistent. Using default options\n"), PROGRAM_NAME); #####: 122: return EXIT_FAILURE; unconditional 0 never executed -: 123: } -: 124: 4: 125: user_home_len = strlen(user.home); 4: 126: return EXIT_SUCCESS; 4: 126-block 0 unconditional 0 taken 4 -: 127:} -: 128: -: 129:int function init_history called 4 returned 100% blocks executed 60% 4: 130:init_history(void) -: 131:{ -: 132: /* Limit the log files size */ 4: 133: check_file_size(log_file, max_log); 4: 133-block 0 call 0 returned 4 4: 134: check_file_size(msg_log_file, max_log); call 0 returned 4 -: 135: -: 136: /* Get history */ -: 137: struct stat attr; 4: 138: if (stat(hist_file, &attr) == 0 && attr.st_size != 0) { call 0 returned 4 branch 1 taken 4 (fallthrough) branch 2 taken 0 4: 138-block 0 branch 3 taken 4 (fallthrough) branch 4 taken 0 -: 139: /* If the size condition is not included, and in case of a zero -: 140: * size file, read_history() produces malloc errors */ -: 141: /* Recover history from the history file */ 4: 142: read_history(hist_file); /* This line adds more leaks to 4: 142-block 0 call 0 returned 4 -: 143: readline */ -: 144: /* Limit the size of the history file to max_hist lines */ 4: 145: history_truncate_file(hist_file, max_hist); call 0 returned 4 unconditional 1 taken 4 -: 146: } else { -: 147: /* If the history file doesn't exist, create it */ #####: 148: FILE *hist_fp = fopen(hist_file, "w+"); %%%%%: 148-block 0 call 0 never executed #####: 149: if (!hist_fp) { branch 0 never executed branch 1 never executed #####: 150: _err('w', PRINT_PROMPT, "%s: fopen: '%s': %s\n", call 0 never executed unconditional 1 never executed #####: 151: PROGRAM_NAME, hist_file, strerror(errno)); %%%%%: 151-block 0 call 0 never executed -: 152: } else { -: 153: /* To avoid malloc errors in read_history(), do not -: 154: * create an empty file */ #####: 155: fputs("edit\n", hist_fp); %%%%%: 155-block 0 call 0 never executed -: 156: /* There is no need to run read_history() here, since -: 157: * the history file is still empty */ #####: 158: fclose(hist_fp); call 0 never executed unconditional 1 never executed -: 159: } -: 160: } -: 161: 4: 162: return EXIT_SUCCESS; 4: 162-block 0 unconditional 0 taken 4 -: 163:} -: 164: -: 165:int function set_start_path called 4 returned 100% blocks executed 22% 4: 166:set_start_path(void) -: 167:{ -: 168: /* Last path is overriden by positional parameters in the command line */ 4: 169: if (restore_last_path) 4: 169-block 0 branch 0 taken 3 (fallthrough) branch 1 taken 1 3: 170: get_last_path(); 3: 170-block 0 call 0 returned 3 unconditional 1 taken 3 -: 171: 4: 172: if (cur_ws == UNSET) 4: 172-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 4 #####: 173: cur_ws = DEF_CUR_WS; %%%%%: 173-block 0 unconditional 0 never executed -: 174: 4: 175: if (cur_ws > MAX_WS - 1) { 4: 175-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 4 #####: 176: cur_ws = DEF_CUR_WS; #####: 177: _err('w', PRINT_PROMPT, _("%s: %zu: Invalid workspace." %%%%%: 177-block 0 call 0 never executed call 1 never executed unconditional 2 never executed -: 178: "\nFalling back to workspace %zu\n"), PROGRAM_NAME, -: 179: cur_ws, cur_ws + 1); -: 180: } -: 181: -: 182: /* If path was not set (neither in the config file nor via command -: 183: * line nor via the RestoreLastPath option), set the default (CWD), -: 184: * and if CWD is not set, use the user's home directory, and if the -: 185: * home cannot be found either, try the root directory, and if -: 186: * there's no access to the root dir either, exit. -: 187: * Bear in mind that if you launch CliFM through a terminal emulator, -: 188: * say xterm (xterm -e clifm), xterm will run a shell, say bash, and -: 189: * the shell will read its config file. Now, if this config file -: 190: * changes the CWD, this will be the CWD for CliFM */ 4: 191: if (!ws[cur_ws].path) { 4: 191-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 4 #####: 192: char cwd[PATH_MAX] = ""; #####: 193: if (getcwd(cwd, sizeof(cwd)) == NULL) {} %%%%%: 193-block 0 call 0 never executed -: 194: #####: 195: if (!*cwd || strlen(cwd) == 0) { branch 0 never executed branch 1 never executed %%%%%: 195-block 0 branch 2 never executed branch 3 never executed #####: 196: if (user_home) { %%%%%: 196-block 0 branch 0 never executed branch 1 never executed #####: 197: ws[cur_ws].path = savestring(user_home, strlen(user_home)); %%%%%: 197-block 0 call 0 never executed unconditional 1 never executed -: 198: } else { #####: 199: if (access("/", R_OK | X_OK) == -1) { %%%%%: 199-block 0 call 0 never executed branch 1 never executed branch 2 never executed #####: 200: fprintf(stderr, "%s: /: %s\n", PROGRAM_NAME, call 0 never executed #####: 201: strerror(errno)); %%%%%: 201-block 0 call 0 never executed #####: 202: exit(EXIT_FAILURE); call 0 never executed -: 203: } else { #####: 204: ws[cur_ws].path = savestring("/", 1); %%%%%: 204-block 0 call 0 never executed unconditional 1 never executed -: 205: } -: 206: } -: 207: } else { #####: 208: ws[cur_ws].path = savestring(cwd, strlen(cwd)); %%%%%: 208-block 0 call 0 never executed unconditional 1 never executed -: 209: } -: 210: } -: 211: -: 212: /* Make path the CWD */ -: 213: /* If chdir(path) fails, set path to cwd, list files and print the -: 214: * error message. If no access to CWD either, exit */ 4: 215: if (xchdir(ws[cur_ws].path, NO_TITLE) == -1) { 4: 215-block 0 call 0 returned 4 branch 1 taken 0 (fallthrough) branch 2 taken 4 #####: 216: _err('e', PRINT_PROMPT, "%s: chdir: '%s': %s\n", PROGRAM_NAME, #####: 217: ws[cur_ws].path, strerror(errno)); %%%%%: 217-block 0 call 0 never executed call 1 never executed -: 218: #####: 219: char cwd[PATH_MAX] = ""; #####: 220: if (getcwd(cwd, sizeof(cwd)) == NULL) { call 0 never executed branch 1 never executed branch 2 never executed #####: 221: _err(0, NOPRINT_PROMPT, _("%s: Fatal error! Failed " %%%%%: 221-block 0 call 0 never executed call 1 never executed -: 222: "retrieving current working directory\n"), PROGRAM_NAME); #####: 223: exit(EXIT_FAILURE); call 0 never executed -: 224: } -: 225: #####: 226: if (ws[cur_ws].path) %%%%%: 226-block 0 branch 0 never executed branch 1 never executed #####: 227: free(ws[cur_ws].path); %%%%%: 227-block 0 unconditional 0 never executed #####: 228: ws[cur_ws].path = savestring(cwd, strlen(cwd)); %%%%%: 228-block 0 call 0 never executed unconditional 1 never executed -: 229: } -: 230: 4: 231: return EXIT_SUCCESS; 4: 231-block 0 unconditional 0 taken 4 -: 232:} -: 233: -: 234:/* Get the system data directory (usually /usr/share) */ -: 235:void function get_data_dir called 4 returned 100% blocks executed 90% 4: 236:get_data_dir(void) -: 237:{ -: 238: /* First try standard values for DATADIR */ 4: 239: char *data_dirs[] = { -: 240: "/usr/share", -: 241: "/usr/local/share", -: 242:#if defined(__HAIKU__) -: 243: "/boot/system/non-packaged/data", -: 244: "/boot/system/data", -: 245:#endif -: 246: NULL }; -: 247: -: 248: struct stat attr; -: 249: size_t i; -: 250: 4*: 251: for (i = 0; data_dirs[i]; i++) { 4: 251-block 0 unconditional 0 taken 4 %%%%%: 251-block 1 unconditional 1 never executed 4: 251-block 2 branch 2 taken 4 branch 3 taken 0 (fallthrough) -: 252: char tmp[PATH_MAX]; 4: 253: snprintf(tmp, PATH_MAX - 1, "%s/%s", data_dirs[i], PNL); 4: 254: if (stat(tmp, &attr) == EXIT_SUCCESS) { 4: 254-block 0 call 0 returned 4 branch 1 taken 4 (fallthrough) branch 2 taken 0 4: 255: data_dir = (char *)xrealloc(data_dir, (strlen(data_dirs[i]) + 1) 4: 255-block 0 call 0 returned 4 -: 256: * sizeof(char)); 4: 257: strcpy(data_dir, data_dirs[i]); 4: 258: break; unconditional 0 taken 4 -: 259: } -: 260: } -: 261: -: 262:/* if (data_dir) -: 263: return; */ 4: 264: return; 4: 264-block 0 unconditional 0 taken 4 -: 265: -: 266: /* If not found, try to get DATADIR from executable's path */ -: 267:/* data_dir = get_cmd_path(PNL); -: 268: -: 269: if (!data_dir) -: 270: return; -: 271: -: 272: size_t j = strlen(data_dir), -: 273: count = 0; -: 274: -: 275: while (--j >= 0) { -: 276: if (data_dir[j] == '/') -: 277: count++; -: 278: if (count == 2) { -: 279: data_dir[j] = '\0'; -: 280: break; -: 281: } -: 282: } -: 283: -: 284: char tmp[PATH_MAX]; -: 285: snprintf(tmp, PATH_MAX - 1, "%s/share/%s", data_dir, PNL); -: 286: if (stat(tmp, &attr) == EXIT_SUCCESS) { -: 287: snprintf(tmp, PATH_MAX - 1, "%s/share", data_dir); -: 288: data_dir = (char *)xrealloc(data_dir, (strlen(tmp) + 1) * sizeof(char)); -: 289: strcpy(data_dir, tmp); -: 290: return; -: 291: } */ -: 292:} -: 293: -: 294:void function check_env_filter called 4 returned 100% blocks executed 45% 4: 295:check_env_filter(void) -: 296:{ 4: 297: if (filter) 4: 297-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 4 #####: 298: return; %%%%%: 298-block 0 unconditional 0 never executed -: 299: 4: 300: char *p = getenv("CLIFM_FILTER"); 4: 300-block 0 call 0 returned 4 4: 301: if (!p) branch 0 taken 4 (fallthrough) branch 1 taken 0 4: 302: return; 4: 302-block 0 unconditional 0 taken 4 -: 303: #####: 304: if (*p == '!') { %%%%%: 304-block 0 branch 0 never executed branch 1 never executed #####: 305: filter_rev = 1; #####: 306: p++; %%%%%: 306-block 0 unconditional 0 never executed -: 307: } else { #####: 308: filter_rev = 0; %%%%%: 308-block 0 unconditional 0 never executed -: 309: } -: 310: #####: 311: filter = savestring(p, strlen(p)); %%%%%: 311-block 0 call 0 never executed unconditional 1 never executed -: 312:} -: 313: -: 314:char * function get_date called 22 returned 100% blocks executed 88% 22: 315:get_date(void) -: 316:{ 22: 317: time_t rawtime = time(NULL); 22: 317-block 0 call 0 returned 22 -: 318: struct tm tm; 22: 319: localtime_r(&rawtime, &tm); call 0 returned 22 22: 320: size_t date_max = 128; -: 321: 22: 322: char *p = (char *)malloc((date_max + 1) * sizeof(char)), *date; 22: 323: if (p) { branch 0 taken 22 (fallthrough) branch 1 taken 0 22: 324: date = p; 22: 325: p = (char *)NULL; 22: 325-block 0 unconditional 0 taken 22 -: 326: } else { #####: 327: return (char *)NULL; %%%%%: 327-block 0 unconditional 0 never executed -: 328: } -: 329: 22: 330: strftime(date, date_max, "%Y-%m-%dT%T%z", &tm); 22: 331: return date; 22: 331-block 0 unconditional 0 taken 22 -: 332:} -: 333: -: 334:static pid_t function get_own_pid called 4 returned 100% blocks executed 80% 4: 335:get_own_pid(void) -: 336:{ -: 337: pid_t pid; -: 338: -: 339: /* Get the process id */ 4: 340: pid = getpid(); 4: 340-block 0 call 0 returned 4 -: 341: 4: 342: if (pid < 0) branch 0 taken 0 (fallthrough) branch 1 taken 4 #####: 343: return 0; %%%%%: 343-block 0 unconditional 0 never executed 4: 344: return pid; 4: 344-block 0 unconditional 0 taken 4 -: 345:} -: 346: -: 347:/* Returns pointer to user data struct, exits if not found */ -: 348:struct user_t function get_user called 11 returned 100% blocks executed 64% 11: 349:get_user(void) -: 350:{ -: 351: struct passwd *pw; -: 352: struct user_t tmp_user; -: 353: 11: 354: pw = getpwuid(geteuid()); 11: 354-block 0 call 0 returned 11 call 1 returned 11 11: 355: if (!pw) { branch 0 taken 0 (fallthrough) branch 1 taken 11 #####: 356: _err('e', NOPRINT_PROMPT, _("%s: Cannot detect user data. Exiting early"), %%%%%: 356-block 0 call 0 never executed call 1 never executed -: 357: PROGRAM_NAME); #####: 358: exit(-1); call 0 never executed -: 359: } -: 360: 11: 361: tmp_user.uid = pw->pw_uid; 11: 362: tmp_user.gid = pw->pw_gid; 11: 363: char *p = getenv("HOME"); 11: 363-block 0 call 0 returned 11 11: 364: if (!p) branch 0 taken 0 (fallthrough) branch 1 taken 11 #####: 365: tmp_user.home = savestring(pw->pw_dir, strlen(pw->pw_dir)); %%%%%: 365-block 0 call 0 never executed unconditional 1 never executed -: 366: else 11: 367: tmp_user.home = savestring(p, strlen(p)); 11: 367-block 0 call 0 returned 11 unconditional 1 taken 11 11: 368: tmp_user.name = savestring(pw->pw_name, strlen(pw->pw_name)); 11: 368-block 0 call 0 returned 11 11: 369: tmp_user.shell = savestring(pw->pw_shell, strlen(pw->pw_shell)); call 0 returned 11 -: 370: 11: 371: if (!tmp_user.home || !tmp_user.name || !tmp_user.shell) { branch 0 taken 11 (fallthrough) branch 1 taken 0 11: 371-block 0 branch 2 taken 11 (fallthrough) branch 3 taken 0 11: 371-block 1 branch 4 taken 0 (fallthrough) branch 5 taken 11 #####: 372: _err('e', NOPRINT_PROMPT, _("%s: Cannot detect user data. Exiting"), %%%%%: 372-block 0 call 0 never executed call 1 never executed -: 373: PROGRAM_NAME); #####: 374: exit(-1); call 0 never executed -: 375: } -: 376: 11: 377: tmp_user.home_len = strlen(tmp_user.home); 11: 378: return tmp_user; 11: 378-block 0 unconditional 0 taken 11 -: 379:} -: 380: -: 381:/* Reconstruct the jump database from database file */ -: 382:void function load_jumpdb called 24 returned 100% blocks executed 85% 24: 383:load_jumpdb(void) -: 384:{ 24: 385: if (xargs.no_dirjump == 1 || !config_ok || !config_dir) 24: 385-block 0 branch 0 taken 24 (fallthrough) branch 1 taken 0 24: 385-block 1 branch 2 taken 24 (fallthrough) branch 3 taken 0 24: 385-block 2 branch 4 taken 0 (fallthrough) branch 5 taken 24 4*: 386: return; %%%%%: 386-block 0 unconditional 0 never executed 4: 386-block 1 unconditional 1 taken 4 -: 387: 24: 388: size_t dir_len = strlen(config_dir); 24: 389: char *jump_file = (char *)xnmalloc(dir_len + 10, sizeof(char)); 24: 389-block 0 call 0 returned 24 24: 390: snprintf(jump_file, dir_len + 10, "%s/jump.cfm", config_dir); -: 391: -: 392: int fd; 24: 393: FILE *fp = open_fstream_r(jump_file, &fd); call 0 returned 24 24: 394: if (!fp) { branch 0 taken 2 (fallthrough) branch 1 taken 22 2: 395: free(jump_file); 2: 396: return; 2: 396-block 0 unconditional 0 taken 2 -: 397: } -: 398: -: 399: char tmp_line[PATH_MAX]; 22: 400: size_t jump_lines = 0; -: 401: 858: 402: while (fgets(tmp_line, (int)sizeof(tmp_line), fp)) { 22: 402-block 0 unconditional 0 taken 22 858: 402-block 1 call 1 returned 858 branch 2 taken 836 branch 3 taken 22 (fallthrough) 836: 403: if (*tmp_line != '\n' && *tmp_line >= '0' && *tmp_line <= '9') 836: 403-block 0 branch 0 taken 836 (fallthrough) branch 1 taken 0 836: 403-block 1 branch 2 taken 836 (fallthrough) branch 3 taken 0 836: 403-block 2 branch 4 taken 816 (fallthrough) branch 5 taken 20 816: 404: jump_lines++; 816: 404-block 0 unconditional 0 taken 816 -: 405: } -: 406: 22: 407: if (!jump_lines) { 22: 407-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 22 #####: 408: free(jump_file); #####: 409: close_fstream(fp, fd); %%%%%: 409-block 0 call 0 never executed #####: 410: return; unconditional 0 never executed -: 411: } -: 412: 22: 413: jump_db = (struct jump_t *)xnmalloc(jump_lines + 2, sizeof(struct jump_t)); 22: 413-block 0 call 0 returned 22 -: 414: 22: 415: fseek(fp, 0L, SEEK_SET); call 0 returned 22 -: 416: 22: 417: size_t line_size = 0; 22: 418: char *line = (char *)NULL; 22: 419: ssize_t line_len = 0; -: 420: 858: 421: while ((line_len = getline(&line, &line_size, fp)) > 0) { unconditional 0 taken 22 858: 421-block 0 call 1 returned 858 branch 2 taken 836 branch 3 taken 22 (fallthrough) 836*: 422: if (!*line || *line == '\n') 836: 422-block 0 branch 0 taken 836 (fallthrough) branch 1 taken 0 836: 422-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 836 #####: 423: continue; %%%%%: 423-block 0 unconditional 0 never executed 836: 424: if (*line == '@') { 836: 424-block 0 branch 0 taken 20 (fallthrough) branch 1 taken 816 20: 425: if (line[line_len - 1] == '\n') 20: 425-block 0 branch 0 taken 20 (fallthrough) branch 1 taken 0 20: 426: line[line_len - 1] = '\0'; 20: 426-block 0 unconditional 0 taken 20 20: 427: if (is_number(line + 1)) 20: 427-block 0 call 0 returned 20 branch 1 taken 20 (fallthrough) branch 2 taken 0 20: 428: jump_total_rank = atoi(line + 1); 20: 428-block 0 unconditional 0 taken 20 20: 429: continue; 20: 429-block 0 unconditional 0 taken 20 -: 430: } 816*: 431: if (*line < '0' || *line > '9') 816: 431-block 0 branch 0 taken 816 (fallthrough) branch 1 taken 0 816: 431-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 816 #####: 432: continue; %%%%%: 432-block 0 unconditional 0 never executed -: 433: 816: 434: if (line[line_len - 1] == '\n') 816: 434-block 0 branch 0 taken 816 (fallthrough) branch 1 taken 0 816: 435: line[line_len - 1] = '\0'; 816: 435-block 0 unconditional 0 taken 816 -: 436: 816: 437: char *tmp = strchr(line, ':'); 816*: 438: if (!tmp) 816: 438-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 816 #####: 439: continue; %%%%%: 439-block 0 unconditional 0 never executed -: 440: 816: 441: *tmp = '\0'; 816*: 442: if (!*(++tmp)) 816: 442-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 816 #####: 443: continue; %%%%%: 443-block 0 unconditional 0 never executed -: 444: 816: 445: int visits = 1; -: 446: 816: 447: if (is_number(line)) 816: 447-block 0 call 0 returned 816 branch 1 taken 816 (fallthrough) branch 2 taken 0 816: 448: visits = atoi(line); 816: 448-block 0 unconditional 0 taken 816 -: 449: 816: 450: char *tmpb = strchr(tmp, ':'); 816: 451: if (!tmpb) 816: 451-block 0 branch 0 taken 12 (fallthrough) branch 1 taken 804 12: 452: continue; 12: 452-block 0 unconditional 0 taken 12 -: 453: 804: 454: *tmpb = '\0'; -: 455: 804*: 456: if (!*(++tmpb)) 804: 456-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 804 #####: 457: continue; %%%%%: 457-block 0 unconditional 0 never executed -: 458: 804: 459: time_t first = 0; -: 460: 804: 461: if (is_number(tmp)) 804: 461-block 0 call 0 returned 804 branch 1 taken 804 (fallthrough) branch 2 taken 0 804: 462: first = (time_t)atoi(tmp); 804: 462-block 0 unconditional 0 taken 804 -: 463: 804: 464: char *tmpc = strchr(tmpb, ':'); 804: 465: if (!tmpc) 804: 465-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 802 2: 466: continue; 2: 466-block 0 unconditional 0 taken 2 -: 467: 802: 468: *tmpc = '\0'; -: 469: 802*: 470: if (!*(++tmpc)) 802: 470-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 802 #####: 471: continue; %%%%%: 471-block 0 unconditional 0 never executed -: 472: -: 473: /* Purge the database from non-existent directories */ 802*: 474: if (access(tmpc, F_OK) == -1) 802: 474-block 0 call 0 returned 802 branch 1 taken 0 (fallthrough) branch 2 taken 802 #####: 475: continue; %%%%%: 475-block 0 unconditional 0 never executed -: 476: 802: 477: jump_db[jump_n].visits = (size_t)visits; 802: 478: jump_db[jump_n].first_visit = first; -: 479: 802: 480: if (is_number(tmpb)) 802: 480-block 0 call 0 returned 802 branch 1 taken 802 (fallthrough) branch 2 taken 0 802: 481: jump_db[jump_n].last_visit = (time_t)atoi(tmpb); 802: 481-block 0 unconditional 0 taken 802 -: 482: else #####: 483: jump_db[jump_n].last_visit = 0; /* UNIX Epoch */ %%%%%: 483-block 0 unconditional 0 never executed -: 484: 802: 485: jump_db[jump_n].keep = 0; 802: 486: jump_db[jump_n].rank = 0; 802: 487: jump_db[jump_n++].path = savestring(tmpc, strlen(tmpc)); 802: 487-block 0 call 0 returned 802 unconditional 1 taken 802 -: 488: } -: 489: 22: 490: close_fstream(fp, fd); 22: 490-block 0 call 0 returned 22 22: 491: free(line); 22: 492: free(jump_file); -: 493: 22: 494: if (!jump_n) { branch 0 taken 2 (fallthrough) branch 1 taken 20 2: 495: free(jump_db); 2: 496: jump_db = (struct jump_t *)NULL; 2: 497: return; 2: 497-block 0 unconditional 0 taken 2 -: 498: } -: 499: 20: 500: jump_db[jump_n].path = (char *)NULL; 20: 501: jump_db[jump_n].rank = 0; 20: 502: jump_db[jump_n].keep = 0; 20: 503: jump_db[jump_n].visits = 0; 20: 504: jump_db[jump_n].first_visit = -1; 20: 504-block 0 unconditional 0 taken 20 -: 505:} -: 506: -: 507:int function load_bookmarks called 21 returned 100% blocks executed 77% 21: 508:load_bookmarks(void) -: 509:{ 21: 510: if (create_bm_file() == EXIT_FAILURE) 21: 510-block 0 call 0 returned 21 branch 1 taken 0 (fallthrough) branch 2 taken 21 #####: 511: return EXIT_FAILURE; %%%%%: 511-block 0 unconditional 0 never executed -: 512: 21: 513: if (!bm_file) 21: 513-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 21 #####: 514: return EXIT_FAILURE; %%%%%: 514-block 0 unconditional 0 never executed -: 515: -: 516: int fd; 21: 517: FILE *fp = open_fstream_r(bm_file, &fd); 21: 517-block 0 call 0 returned 21 21: 518: if (!fp) branch 0 taken 0 (fallthrough) branch 1 taken 21 #####: 519: return EXIT_FAILURE; %%%%%: 519-block 0 unconditional 0 never executed -: 520: 21: 521: size_t bm_total = 0; -: 522: char tmp_line[256]; 421: 523: while (fgets(tmp_line, (int)sizeof(tmp_line), fp)) { 21: 523-block 0 unconditional 0 taken 21 421: 523-block 1 call 1 returned 421 branch 2 taken 400 branch 3 taken 21 (fallthrough) 400: 524: if (!*tmp_line || *tmp_line == '#' || *tmp_line == '\n') 400: 524-block 0 branch 0 taken 400 (fallthrough) branch 1 taken 0 400: 524-block 1 branch 2 taken 323 (fallthrough) branch 3 taken 77 323: 524-block 2 branch 4 taken 7 (fallthrough) branch 5 taken 316 84: 525: continue; 84: 525-block 0 unconditional 0 taken 84 316: 526: bm_total++; 316: 526-block 0 unconditional 0 taken 316 -: 527: } -: 528: 21: 529: if (!bm_total) { 21: 529-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 20 1: 530: close_fstream(fp, fd); 1: 530-block 0 call 0 returned 1 1: 531: return EXIT_SUCCESS; unconditional 0 taken 1 -: 532: } -: 533: 20: 534: fseek(fp, 0L, SEEK_SET); 20: 534-block 0 call 0 returned 20 -: 535: 20: 536: bookmarks = (struct bookmarks_t *)xnmalloc(bm_total + 1, call 0 returned 20 -: 537: sizeof(struct bookmarks_t)); 20: 538: size_t line_size = 0; 20: 539: char *line = (char *)NULL; 20: 540: ssize_t line_len = 0; -: 541: 414: 542: while ((line_len = getline(&line, &line_size, fp)) > 0) { unconditional 0 taken 20 414: 542-block 0 call 1 returned 414 branch 2 taken 394 branch 3 taken 20 (fallthrough) 394: 543: if (!*line || *line == '\n' || *line == '#') 394: 543-block 0 branch 0 taken 394 (fallthrough) branch 1 taken 0 394: 543-block 1 branch 2 taken 388 (fallthrough) branch 3 taken 6 388: 543-block 2 branch 4 taken 72 (fallthrough) branch 5 taken 316 78: 544: continue; 78: 544-block 0 unconditional 0 taken 78 316: 545: if (line[line_len - 1] == '\n') 316: 545-block 0 branch 0 taken 315 (fallthrough) branch 1 taken 1 315: 546: line[line_len - 1] = '\0'; 315: 546-block 0 unconditional 0 taken 315 -: 547: -: 548: /* Neither hotkey nor name, but only a path */ 316*: 549: if (*line == '/') { 316: 549-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 316 #####: 550: bookmarks[bm_n].shortcut = (char *)NULL; #####: 551: bookmarks[bm_n].name = (char *)NULL; #####: 552: bookmarks[bm_n++].path = savestring(line, strlen(line)); %%%%%: 552-block 0 call 0 never executed #####: 553: continue; unconditional 0 never executed -: 554: } -: 555: 316: 556: if (*line == '[') { 316: 556-block 0 branch 0 taken 316 (fallthrough) branch 1 taken 0 316: 557: char *p = line; 316: 558: p++; 316: 559: char *tmp = strchr(line, ']'); 316*: 560: if (!tmp) { 316: 560-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 316 #####: 561: bookmarks[bm_n].shortcut = (char *)NULL; #####: 562: bookmarks[bm_n].name = (char *)NULL; #####: 563: bookmarks[bm_n++].path = (char *)NULL; #####: 564: continue; %%%%%: 564-block 0 unconditional 0 never executed -: 565: } -: 566: 316: 567: *tmp = '\0'; -: 568: 316: 569: bookmarks[bm_n].shortcut = savestring(p, strlen(p)); 316: 569-block 0 call 0 returned 316 -: 570: 316: 571: tmp++; 316: 572: p = tmp; 316: 573: tmp = strchr(p, ':'); -: 574: 316: 575: if (!tmp) { branch 0 taken 56 (fallthrough) branch 1 taken 260 56: 576: bookmarks[bm_n].name = (char *)NULL; 56: 577: if (*p) 56: 577-block 0 branch 0 taken 56 (fallthrough) branch 1 taken 0 56: 578: bookmarks[bm_n++].path = savestring(p, strlen(p)); 56: 578-block 0 call 0 returned 56 unconditional 1 taken 56 -: 579: else #####: 580: bookmarks[bm_n++].path = (char *)NULL; %%%%%: 580-block 0 unconditional 0 never executed 56: 581: continue; 56: 581-block 0 unconditional 0 taken 56 -: 582: } -: 583: 260: 584: *tmp = '\0'; 260: 585: bookmarks[bm_n].name = savestring(p, strlen(p)); 260: 585-block 0 call 0 returned 260 -: 586: 260*: 587: if (!*(++tmp)) { branch 0 taken 0 (fallthrough) branch 1 taken 260 #####: 588: bookmarks[bm_n++].path = (char *)NULL; #####: 589: continue; %%%%%: 589-block 0 unconditional 0 never executed -: 590: } -: 591: 260: 592: bookmarks[bm_n++].path = savestring(tmp, strlen(tmp)); 260: 592-block 0 call 0 returned 260 260: 593: continue; unconditional 0 taken 260 -: 594: } -: 595: -: 596: /* No shortcut. Let's try with name */ #####: 597: bookmarks[bm_n].shortcut = (char *)NULL; #####: 598: char *tmp = strchr(line, ':'); -: 599: -: 600: /* No name either */ #####: 601: if (!tmp) { %%%%%: 601-block 0 branch 0 never executed branch 1 never executed #####: 602: bookmarks[bm_n].name = (char *)NULL; #####: 603: bookmarks[bm_n++].path = (char *)NULL; #####: 604: continue; %%%%%: 604-block 0 unconditional 0 never executed -: 605: } -: 606: #####: 607: *tmp = '\0'; #####: 608: bookmarks[bm_n].name = savestring(line, strlen(line)); %%%%%: 608-block 0 call 0 never executed -: 609: #####: 610: if (!*(++tmp)) { branch 0 never executed branch 1 never executed #####: 611: bookmarks[bm_n++].path = (char *)NULL; #####: 612: continue; %%%%%: 612-block 0 unconditional 0 never executed -: 613: } else { #####: 614: bookmarks[bm_n++].path = savestring(tmp, strlen(tmp)); %%%%%: 614-block 0 call 0 never executed unconditional 1 never executed -: 615: } -: 616: } -: 617: 20: 618: free(line); 20: 619: close_fstream(fp, fd); 20: 619-block 0 call 0 returned 20 -: 620: 20: 621: if (!bm_n) { branch 0 taken 0 (fallthrough) branch 1 taken 20 #####: 622: free(bookmarks); #####: 623: bookmarks = (struct bookmarks_t *)NULL; #####: 624: return EXIT_SUCCESS; %%%%%: 624-block 0 unconditional 0 never executed -: 625: } -: 626: -: 627: /* bookmark_names array shouldn't exist: is only used for bookmark -: 628: * completion. xbookmarks[i].name should be used instead, but is -: 629: * currently not working */ -: 630: 20: 631: size_t i, j = 0; 20: 632: bookmark_names = (char **)xnmalloc(bm_n + 2, sizeof(char *)); 20: 632-block 0 call 0 returned 20 -: 633: 336: 634: for (i = 0; i < bm_n; i++) { unconditional 0 taken 20 316: 634-block 0 unconditional 1 taken 316 336: 634-block 1 branch 2 taken 316 branch 3 taken 20 (fallthrough) 316: 635: if (!bookmarks[i].name || !*bookmarks[i].name) 316: 635-block 0 branch 0 taken 260 (fallthrough) branch 1 taken 56 260: 635-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 260 56: 636: continue; 56: 636-block 0 unconditional 0 taken 56 260: 637: bookmark_names[j++] = savestring(bookmarks[i].name, unconditional 0 taken 260 260: 638: strlen(bookmarks[i].name)); 260: 638-block 0 call 0 returned 260 -: 639: } -: 640: 20: 641: bookmark_names[j] = (char *)NULL; 20: 642: return EXIT_SUCCESS; 20: 642-block 0 unconditional 0 taken 20 -: 643:} -: 644: -: 645:/* Store actions from the actions file into a struct */ -: 646:int function load_actions called 15 returned 100% blocks executed 90% 15: 647:load_actions(void) -: 648:{ 15: 649: if (!config_ok) 15: 649-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 15 #####: 650: return EXIT_FAILURE; %%%%%: 650-block 0 unconditional 0 never executed -: 651: -: 652: /* Free the actions struct array */ 15: 653: if (actions_n) { 15: 653-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 13 2: 654: int i = (int)actions_n; 49: 655: while (--i >= 0) { 2: 655-block 0 unconditional 0 taken 2 49: 655-block 1 branch 1 taken 47 branch 2 taken 2 (fallthrough) 47: 656: free(usr_actions[i].name); 47: 657: free(usr_actions[i].value); 47: 657-block 0 unconditional 0 taken 47 -: 658: } -: 659: 2: 660: free(usr_actions); 2: 661: usr_actions = (struct actions_t *)xnmalloc(1, sizeof(struct actions_t)); 2: 661-block 0 call 0 returned 2 2: 662: actions_n = 0; unconditional 0 taken 2 -: 663: } -: 664: -: 665: /* Open the actions file */ -: 666: int fd; 15: 667: FILE *fp = open_fstream_r(actions_file, &fd); 15: 667-block 0 call 0 returned 15 15: 668: if (!fp) branch 0 taken 0 (fallthrough) branch 1 taken 15 #####: 669: return EXIT_FAILURE; %%%%%: 669-block 0 unconditional 0 never executed -: 670: 15: 671: size_t line_size = 0; 15: 672: char *line = (char *)NULL; 15: 673: ssize_t line_len = 0; -: 674: 488: 675: while ((line_len = getline(&line, &line_size, fp)) > 0) { 15: 675-block 0 unconditional 0 taken 15 488: 675-block 1 call 1 returned 488 branch 2 taken 473 branch 3 taken 15 (fallthrough) 473: 676: if (!line || !*line || *line == '#' || *line == '\n') 473: 676-block 0 branch 0 taken 473 (fallthrough) branch 1 taken 0 473: 676-block 1 branch 2 taken 473 (fallthrough) branch 3 taken 0 473: 676-block 2 branch 4 taken 303 (fallthrough) branch 5 taken 170 303: 676-block 3 branch 6 taken 36 (fallthrough) branch 7 taken 267 206: 677: continue; 206: 677-block 0 unconditional 0 taken 206 267: 678: if (line[line_len - 1] == '\n') 267: 678-block 0 branch 0 taken 267 (fallthrough) branch 1 taken 0 267: 679: line[line_len - 1] = '\0'; 267: 679-block 0 unconditional 0 taken 267 -: 680: 267: 681: char *tmp = (char *)NULL; 267: 682: tmp = strrchr(line, '='); 267*: 683: if (!tmp) 267: 683-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 267 #####: 684: continue; %%%%%: 684-block 0 unconditional 0 never executed -: 685: -: 686: /* Now copy left and right value of each action into the -: 687: * actions struct */ 267: 688: usr_actions = xrealloc(usr_actions, (size_t)(actions_n + 1) 267: 688-block 0 call 0 returned 267 -: 689: * sizeof(struct actions_t)); 267: 690: usr_actions[actions_n].value = savestring(tmp + 1, strlen(tmp + 1)); call 0 returned 267 267: 691: *tmp = '\0'; 267: 692: usr_actions[actions_n++].name = savestring(line, strlen(line)); call 0 returned 267 unconditional 1 taken 267 -: 693: } -: 694: 15: 695: free(line); 15: 696: close_fstream(fp, fd); 15: 696-block 0 call 0 returned 15 15: 697: return EXIT_SUCCESS; unconditional 0 taken 15 -: 698:} -: 699: -: 700:/* Load remotes information from FILE */ -: 701:int function load_remotes called 26 returned 100% blocks executed 83% 26: 702:load_remotes(void) -: 703:{ 26: 704: if (!remotes_file || !*remotes_file) 26: 704-block 0 branch 0 taken 26 (fallthrough) branch 1 taken 0 26: 704-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 26 #####: 705: return EXIT_FAILURE; %%%%%: 705-block 0 unconditional 0 never executed -: 706: -: 707: int fd; 26: 708: FILE *fp = open_fstream_r(remotes_file, &fd); 26: 708-block 0 call 0 returned 26 26: 709: if (!fp) { branch 0 taken 0 (fallthrough) branch 1 taken 26 #####: 710: fprintf(stderr, "%s: %s\n", remotes_file, strerror(errno)); %%%%%: 710-block 0 call 0 never executed call 1 never executed #####: 711: return EXIT_FAILURE; unconditional 0 never executed -: 712: } -: 713: 26: 714: size_t n = 0; 26: 715: remotes = (struct remote_t *)xnmalloc(n + 1, sizeof(struct remote_t)); 26: 715-block 0 call 0 returned 26 26: 716: remotes[n].name = (char *)NULL; 26: 717: remotes[n].desc = (char *)NULL; 26: 718: remotes[n].mountpoint = (char *)NULL; 26: 719: remotes[n].mount_cmd = (char *)NULL; 26: 720: remotes[n].unmount_cmd = (char *)NULL; 26: 721: remotes[n].auto_unmount = 0; 26: 722: remotes[n].auto_mount = 0; 26: 723: remotes[n].mounted = 0; -: 724: 26: 725: size_t line_sz = 0; 26: 726: char *line = (char *)NULL; -: 727: 954: 728: while (getline(&line, &line_sz, fp) > 0) { unconditional 0 taken 26 954: 728-block 0 call 1 returned 954 branch 2 taken 928 branch 3 taken 26 (fallthrough) 928: 729: if (!*line || *line == '#' || *line == '\n') 928: 729-block 0 branch 0 taken 928 (fallthrough) branch 1 taken 0 928: 729-block 1 branch 2 taken 486 (fallthrough) branch 3 taken 442 486: 729-block 2 branch 4 taken 201 (fallthrough) branch 5 taken 285 643: 730: continue; 643: 730-block 0 unconditional 0 taken 643 285: 731: if (*line == '[') { 285: 731-block 0 branch 0 taken 38 (fallthrough) branch 1 taken 247 38: 732: if (remotes[n].name) 38: 732-block 0 branch 0 taken 19 (fallthrough) branch 1 taken 19 19: 733: n++; 19: 733-block 0 unconditional 0 taken 19 38: 734: remotes = (struct remote_t *)xrealloc( 38: 734-block 0 call 0 returned 38 -: 735: remotes, (n + 2) * sizeof(struct remote_t)); -: 736: 38: 737: remotes[n].name = (char *)NULL; 38: 738: remotes[n].desc = (char *)NULL; 38: 739: remotes[n].mountpoint = (char *)NULL; 38: 740: remotes[n].mount_cmd = (char *)NULL; 38: 741: remotes[n].unmount_cmd = (char *)NULL; 38: 742: remotes[n].auto_unmount = 0; 38: 743: remotes[n].auto_mount = 0; 38: 744: remotes[n].mounted = 0; -: 745: 38: 746: char *name = strbtw(line, '[', ']'); call 0 returned 38 38*: 747: if (!name) branch 0 taken 0 (fallthrough) branch 1 taken 38 #####: 748: continue; %%%%%: 748-block 0 unconditional 0 never executed 38*: 749: if (!*name) { 38: 749-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 38 #####: 750: free(name); #####: 751: name = (char *)NULL; #####: 752: continue; %%%%%: 752-block 0 unconditional 0 never executed -: 753: } 76: 754: remotes[n].name = (char *)xrealloc(remotes[n].name, 38: 755: (strlen(name) + 1) * sizeof(char)); 38: 755-block 0 call 0 returned 38 38: 756: strcpy(remotes[n].name, name); 38: 757: free(name); 38: 758: name = (char *)NULL; unconditional 0 taken 38 -: 759: } -: 760: 285*: 761: if (!remotes[n].name) 285: 761-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 285 #####: 762: continue; %%%%%: 762-block 0 unconditional 0 never executed -: 763: 285: 764: char *ret = strchr(line, '='); 285: 765: if (!ret) 285: 765-block 0 branch 0 taken 57 (fallthrough) branch 1 taken 228 57: 766: continue; 57: 766-block 0 unconditional 0 taken 57 228*: 767: if (!*(++ret)) 228: 767-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 228 #####: 768: continue; %%%%%: 768-block 0 unconditional 0 never executed -: 769: 228: 770: size_t ret_len = strlen(ret); 228: 771: if (ret[ret_len - 1] == '\n') 228: 771-block 0 branch 0 taken 228 (fallthrough) branch 1 taken 0 228: 772: ret[--ret_len] = '\0'; 228: 772-block 0 unconditional 0 taken 228 -: 773: 228: 774: char *deq_str = remove_quotes(ret); 228: 774-block 0 call 0 returned 228 228: 775: if (deq_str) branch 0 taken 228 (fallthrough) branch 1 taken 0 228: 776: ret = deq_str; 228: 776-block 0 unconditional 0 taken 228 -: 777: 228: 778: if (strncmp(line, "Comment=", 8) == 0) { 228: 778-block 0 branch 0 taken 38 (fallthrough) branch 1 taken 190 76: 779: remotes[n].desc = (char *)xrealloc(remotes[n].desc, 38: 780: (ret_len + 1) * sizeof(char)); 38: 780-block 0 call 0 returned 38 38: 781: strcpy(remotes[n].desc, ret); unconditional 0 taken 38 190: 782: } else if (strncmp(line, "Mountpoint=", 11) == 0) { 190: 782-block 0 branch 0 taken 38 (fallthrough) branch 1 taken 152 38: 783: char *tmp = (char *)NULL; 38: 784: if (*ret == '~') 38: 784-block 0 branch 0 taken 19 (fallthrough) branch 1 taken 19 19: 785: tmp = tilde_expand(ret); 19: 785-block 0 call 0 returned 19 unconditional 1 taken 19 57: 786: remotes[n].mountpoint = (char *)xrealloc(remotes[n].mountpoint, 38: 786-block 0 branch 0 taken 19 (fallthrough) branch 1 taken 19 19: 786-block 1 unconditional 2 taken 19 38: 786-block 2 call 3 returned 38 19: 787: ((tmp ? strlen(tmp) : ret_len) + 1) 19: 787-block 0 unconditional 0 taken 19 -: 788: * sizeof(char)); 38: 789: strcpy(remotes[n].mountpoint, tmp ? tmp : ret); branch 0 taken 19 (fallthrough) branch 1 taken 19 19: 789-block 0 unconditional 2 taken 19 19: 789-block 1 unconditional 3 taken 19 38: 790: free(tmp); 38: 791: if (count_dir(remotes[n].mountpoint, CPOP) > 2) 38: 791-block 0 call 0 returned 38 branch 1 taken 0 (fallthrough) branch 2 taken 38 #####: 792: remotes[n].mounted = 1; %%%%%: 792-block 0 unconditional 0 never executed 152: 793: } else if (strncmp(line, "MountCmd=", 9) == 0) { 152: 793-block 0 branch 0 taken 38 (fallthrough) branch 1 taken 114 38: 794: int replaced = 0; 38: 795: if (remotes[n].mountpoint) { 38: 795-block 0 branch 0 taken 38 (fallthrough) branch 1 taken 0 38: 796: char *rep = replace_substr(ret, "%m", remotes[n].mountpoint); 38: 796-block 0 call 0 returned 38 38: 797: if (rep) { branch 0 taken 38 (fallthrough) branch 1 taken 0 76: 798: remotes[n].mount_cmd = (char *)xrealloc( 38: 799: remotes[n].mount_cmd, 38: 800: (strlen(rep) + 1) * sizeof(char)); 38: 800-block 0 call 0 returned 38 38: 801: strcpy(remotes[n].mount_cmd, rep); 38: 802: free(rep); 38: 803: replaced = 1; unconditional 0 taken 38 -: 804: } -: 805: } -: 806: 38: 807: if (!replaced) { 38: 807-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 38 #####: 808: remotes[n].mount_cmd = (char *)xrealloc(remotes[n].mount_cmd, #####: 809: (ret_len + 1) * sizeof(char)); %%%%%: 809-block 0 call 0 never executed #####: 810: strcpy(remotes[n].mount_cmd, ret); unconditional 0 never executed -: 811: } 114: 812: } else if (strncmp(line, "UnmountCmd=", 11) == 0) { 114: 812-block 0 branch 0 taken 38 (fallthrough) branch 1 taken 76 38: 813: int replaced = 0; 38: 814: if (remotes[n].mountpoint) { 38: 814-block 0 branch 0 taken 38 (fallthrough) branch 1 taken 0 38: 815: char *rep = replace_substr(ret, "%m", remotes[n].mountpoint); 38: 815-block 0 call 0 returned 38 38: 816: if (rep) { branch 0 taken 38 (fallthrough) branch 1 taken 0 76: 817: remotes[n].unmount_cmd = (char *)xrealloc( 38: 818: remotes[n].unmount_cmd, 38: 819: (strlen(rep) + 1) * sizeof(char)); 38: 819-block 0 call 0 returned 38 38: 820: strcpy(remotes[n].unmount_cmd, rep); 38: 821: free(rep); 38: 822: replaced = 1; unconditional 0 taken 38 -: 823: } -: 824: } -: 825: 38: 826: if (!replaced) { 38: 826-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 38 #####: 827: remotes[n].mount_cmd = (char *)xrealloc(remotes[n].unmount_cmd, #####: 828: (ret_len + 1) * sizeof(char)); %%%%%: 828-block 0 call 0 never executed #####: 829: strcpy(remotes[n].unmount_cmd, ret); unconditional 0 never executed -: 830: } 76: 831: } else if (strncmp(line, "AutoUnmount=", 12) == 0) { 76: 831-block 0 branch 0 taken 38 (fallthrough) branch 1 taken 38 38: 832: if (strcmp(ret, "true") == 0) 38: 832-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 37 1: 833: remotes[n].auto_unmount = 1; 1: 833-block 0 unconditional 0 taken 1 38: 834: } else if (strncmp(line, "AutoMount=", 10) == 0) { 38: 834-block 0 branch 0 taken 38 (fallthrough) branch 1 taken 0 38: 835: if (strcmp(ret, "true") == 0) 38: 835-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 38 #####: 836: remotes[n].auto_mount = 1; %%%%%: 836-block 0 unconditional 0 never executed -: 837: } -: 838: } -: 839: 26: 840: free(line); 26: 841: close_fstream(fp, fd); 26: 841-block 0 call 0 returned 26 -: 842: 26: 843: if (remotes[n].name) { branch 0 taken 19 (fallthrough) branch 1 taken 7 19: 844: ++n; 19: 845: remotes[n].name = (char *)NULL; 19: 845-block 0 unconditional 0 taken 19 -: 846: } -: 847: 26: 848: remotes_n = n; 26: 849: return EXIT_SUCCESS; 26: 849-block 0 unconditional 0 taken 26 -: 850:} -: 851: -: 852:/* Evaluate external arguments, if any, and change initial variables to -: 853: * its corresponding value */ -: 854:void function external_arguments called 4 returned 100% blocks executed 13% 4: 855:external_arguments(int argc, char **argv) -: 856:{ -: 857: /* Disable automatic error messages to be able to handle them -: 858: * myself via the '?' case in the switch */ 4: 859: opterr = optind = 0; -: 860: -: 861: /* Link long (--option) and short options (-o) for the getopt_long -: 862: * function */ -: 863: static struct option longopts[] = { -: 864: {"no-hidden", no_argument, 0, 'a'}, -: 865: {"show-hidden", no_argument, 0, 'A'}, -: 866: {"bookmarks-file", no_argument, 0, 'b'}, -: 867: {"config-file", no_argument, 0, 'c'}, -: 868: {"config-dir", required_argument, 0, 'D'}, -: 869: {"no-eln", no_argument, 0, 'e'}, -: 870: {"no-folders-first", no_argument, 0, 'f'}, -: 871: {"folders-first", no_argument, 0, 'F'}, -: 872: {"pager", no_argument, 0, 'g'}, -: 873: {"no-pager", no_argument, 0, 'G'}, -: 874: {"help", no_argument, 0, 'h'}, -: 875: {"no-case-sensitive", no_argument, 0, 'i'}, -: 876: {"case-sensitive", no_argument, 0, 'I'}, -: 877: {"keybindings-file", no_argument, 0, 'k'}, -: 878: {"no-long-view", no_argument, 0, 'l'}, -: 879: {"long-view", no_argument, 0, 'L'}, -: 880: {"dirhist-map", no_argument, 0, 'm'}, -: 881: {"no-list-on-the-fly", no_argument, 0, 'o'}, -: 882: {"list-on-the-fly", no_argument, 0, 'O'}, -: 883: {"path", required_argument, 0, 'p'}, -: 884: {"profile", required_argument, 0, 'P'}, -: 885: {"splash", no_argument, 0, 's'}, -: 886: {"stealth-mode", no_argument, 0, 'S'}, -: 887: {"unicode", no_argument, 0, 'U'}, -: 888: {"no-unicode", no_argument, 0, 'u'}, -: 889: {"version", no_argument, 0, 'v'}, -: 890: {"workspace", required_argument, 0, 'w'}, -: 891: {"no-ext-cmds", no_argument, 0, 'x'}, -: 892: {"light-mode", no_argument, 0, 'y'}, -: 893: {"sort", required_argument, 0, 'z'}, -: 894: -: 895: /* Only long options */ -: 896: {"no-cd-auto", no_argument, 0, 0}, -: 897: {"no-open-auto", no_argument, 0, 1}, -: 898: {"no-restore-last-path", no_argument, 0, 2}, -: 899: {"no-tips", no_argument, 0, 3}, -: 900: {"disk-usage", no_argument, 0, 4}, -: 901: {"no-classify", no_argument, 0, 6}, -: 902: {"share-selbox", no_argument, 0, 7}, -: 903: {"rl-vi-mode", no_argument, 0, 8}, -: 904: {"max-dirhist", required_argument, 0, 9}, -: 905: {"sort-reverse", no_argument, 0, 10}, -: 906: {"no-files-counter", no_argument, 0, 11}, -: 907: {"no-welcome-message", no_argument, 0, 12}, -: 908: {"no-clear-screen", no_argument, 0, 13}, -: 909: {"enable-logs", no_argument, 0, 15}, -: 910: {"max-path", required_argument, 0, 16}, -: 911: {"opener", required_argument, 0, 17}, -: 912: {"expand-bookmarks", no_argument, 0, 18}, -: 913: {"only-dirs", no_argument, 0, 19}, -: 914: {"list-and-quit", no_argument, 0, 20}, -: 915: {"color-scheme", required_argument, 0, 21}, -: 916: {"cd-on-quit", no_argument, 0, 22}, -: 917: {"no-dir-jumper", no_argument, 0, 23}, -: 918: {"icons", no_argument, 0, 24}, -: 919: {"icons-use-file-color", no_argument, 0, 25}, -: 920: {"no-columns", no_argument, 0, 26}, -: 921: {"no-colors", no_argument, 0, 27}, -: 922: {"max-files", required_argument, 0, 28}, -: 923: {"trash-as-rm", no_argument, 0, 29}, -: 924: {"case-sens-dirjump", no_argument, 0, 30}, -: 925: {"case-sens-path-comp", no_argument, 0, 31}, -: 926: {"cwd-in-title", no_argument, 0, 32}, -: 927: {"open", required_argument, 0, 33}, -: 928: {"print-sel", no_argument, 0, 34}, -: 929: {"no-suggestions", no_argument, 0, 35}, -: 930: {"autojump", no_argument, 0, 36}, -: 931: {"highlight", no_argument, 0, 37}, -: 932: {"no-file-cap", no_argument, 0, 38}, -: 933: {"no-file-ext", no_argument, 0, 39}, -: 934: {"no-follow-symlink", no_argument, 0, 40}, -: 935: {0, 0, 0, 0}}; -: 936: -: 937: /* Increment whenever a new (only) long option is added */ 4: 938: int long_opts = 33; -: 939: int optc; -: 940: /* Variables to store arguments to options (-c, -p and -P) */ 4: 941: char *path_value = (char *)NULL, 4: 942: *alt_profile_value = (char *)NULL, 4: 943: *alt_dir_value = (char *)NULL, 4: 944: *config_value = (char *)NULL, 4: 945: *kbinds_value = (char *)NULL, 4: 946: *bm_value = (char *)NULL; -: 947: 6: 948: while ((optc = getopt_long(argc, argv, 4: 948-block 0 unconditional 0 taken 4 6: 948-block 1 call 1 returned 6 -: 949: "+aAb:c:D:efFgGhiIk:lLmoOp:P:sSUuvw:xyz:", longopts, 6: 950: (int *)0)) != EOF) { branch 0 taken 2 branch 1 taken 4 (fallthrough) -: 951: /* ':' and '::' in the short options string means 'required' and -: 952: * 'optional argument' respectivelly. Thus, 'p' and 'P' require -: 953: * an argument here. The plus char (+) tells getopt to stop -: 954: * processing at the first non-option (and non-argument) */ 2: 955: switch (optc) { 2: 955-block 0 branch 0 taken 0 branch 1 taken 0 branch 2 taken 0 branch 3 taken 0 branch 4 taken 0 branch 5 taken 0 branch 6 taken 0 branch 7 taken 0 branch 8 taken 0 branch 9 taken 0 branch 10 taken 0 branch 11 taken 0 branch 12 taken 0 branch 13 taken 0 branch 14 taken 0 branch 15 taken 0 branch 16 taken 0 branch 17 taken 0 branch 18 taken 0 branch 19 taken 0 branch 20 taken 0 branch 21 taken 0 branch 22 taken 0 branch 23 taken 0 branch 24 taken 0 branch 25 taken 0 branch 26 taken 0 branch 27 taken 0 branch 28 taken 0 branch 29 taken 0 branch 30 taken 2 branch 31 taken 0 branch 32 taken 0 branch 33 taken 0 branch 34 taken 0 branch 35 taken 0 branch 36 taken 0 branch 37 taken 0 branch 38 taken 0 branch 39 taken 0 branch 40 taken 0 branch 41 taken 0 branch 42 taken 0 branch 43 taken 0 branch 44 taken 0 branch 45 taken 0 branch 46 taken 0 branch 47 taken 0 branch 48 taken 0 branch 49 taken 0 branch 50 taken 0 branch 51 taken 0 branch 52 taken 0 branch 53 taken 0 branch 54 taken 0 branch 55 taken 0 branch 56 taken 0 branch 57 taken 0 branch 58 taken 0 branch 59 taken 0 branch 60 taken 0 branch 61 taken 0 branch 62 taken 0 branch 63 taken 0 branch 64 taken 0 branch 65 taken 0 branch 66 taken 0 branch 67 taken 0 branch 68 taken 0 branch 69 taken 0 branch 70 taken 0 -: 956: #####: 957: case 0: xargs.autocd = autocd = 0; break; %%%%%: 957-block 0 unconditional 0 never executed #####: 958: case 1: xargs.auto_open = auto_open = 0; break; %%%%%: 958-block 0 unconditional 0 never executed #####: 959: case 2: xargs.restore_last_path = restore_last_path = 0; break; %%%%%: 959-block 0 unconditional 0 never executed #####: 960: case 3: xargs.tips = tips = 0; break; %%%%%: 960-block 0 unconditional 0 never executed #####: 961: case 4: xargs.disk_usage = disk_usage = 1; break; %%%%%: 961-block 0 unconditional 0 never executed -: 962: #####: 963: case 6: xargs.classify = classify = 0; break; %%%%%: 963-block 0 unconditional 0 never executed #####: 964: case 7: xargs.share_selbox = share_selbox = 1; break; %%%%%: 964-block 0 unconditional 0 never executed #####: 965: case 8: xargs.rl_vi_mode = 1; break; %%%%%: 965-block 0 unconditional 0 never executed -: 966: #####: 967: case 9: { #####: 968: if (!is_number(optarg)) %%%%%: 968-block 0 call 0 never executed branch 1 never executed branch 2 never executed #####: 969: break; %%%%%: 969-block 0 unconditional 0 never executed #####: 970: int opt_int = atoi(optarg); #####: 971: if (opt_int >= 0) %%%%%: 971-block 0 branch 0 never executed branch 1 never executed #####: 972: xargs.max_dirhist = max_dirhist = opt_int; %%%%%: 972-block 0 unconditional 0 never executed #####: 973: } break; %%%%%: 973-block 0 unconditional 0 never executed -: 974: #####: 975: case 10: xargs.sort_reverse = sort_reverse = 1; break; %%%%%: 975-block 0 unconditional 0 never executed #####: 976: case 11: xargs.files_counter = files_counter = 0; break; %%%%%: 976-block 0 unconditional 0 never executed #####: 977: case 12: xargs.welcome_message = welcome_message = 0; break; %%%%%: 977-block 0 unconditional 0 never executed #####: 978: case 13: xargs.clear_screen = clear_screen = 0; break; %%%%%: 978-block 0 unconditional 0 never executed -: 979: #####: 980: case 15: xargs.logs = logs_enabled = 1; break; %%%%%: 980-block 0 unconditional 0 never executed -: 981: #####: 982: case 16: { #####: 983: if (!is_number(optarg)) %%%%%: 983-block 0 call 0 never executed branch 1 never executed branch 2 never executed #####: 984: break; %%%%%: 984-block 0 unconditional 0 never executed #####: 985: int opt_int = atoi(optarg); #####: 986: if (opt_int >= 0) %%%%%: 986-block 0 branch 0 never executed branch 1 never executed #####: 987: xargs.max_path = max_path = opt_int; %%%%%: 987-block 0 unconditional 0 never executed #####: 988: } break; %%%%%: 988-block 0 unconditional 0 never executed -: 989: #####: 990: case 17: opener = savestring(optarg, strlen(optarg)); break; %%%%%: 990-block 0 call 0 never executed unconditional 1 never executed #####: 991: case 18: xargs.expand_bookmarks = expand_bookmarks = 1; break; %%%%%: 991-block 0 unconditional 0 never executed #####: 992: case 19: xargs.only_dirs = only_dirs = 1; break; %%%%%: 992-block 0 unconditional 0 never executed #####: 993: case 20: xargs.list_and_quit = 1; break; %%%%%: 993-block 0 unconditional 0 never executed #####: 994: case 21: usr_cscheme = savestring(optarg, strlen(optarg)); break; %%%%%: 994-block 0 call 0 never executed unconditional 1 never executed #####: 995: case 22: xargs.cd_on_quit = cd_on_quit = 1; break; %%%%%: 995-block 0 unconditional 0 never executed #####: 996: case 23: xargs.no_dirjump = 1; break; %%%%%: 996-block 0 unconditional 0 never executed -: 997:#ifndef _NO_ICONS #####: 998: case 24: xargs.icons = icons = 1; break; %%%%%: 998-block 0 unconditional 0 never executed #####: 999: case 25: #####: 1000: xargs.icons = icons = 1; #####: 1001: xargs.icons_use_file_color = 1; #####: 1002: break; %%%%%: 1002-block 0 unconditional 0 never executed -: 1003:#else -: 1004: case 24: /* fallthrough */ -: 1005: case 25: -: 1006: fprintf(stderr, _("%s: icons: %s\n"), PROGRAM_NAME, _(NOT_AVAILABLE)); -: 1007: exit(EXIT_FAILURE); -: 1008:#endif #####: 1009: case 26: #####: 1010: xargs.no_columns = 1; #####: 1011: columned = 0; #####: 1012: break; %%%%%: 1012-block 0 unconditional 0 never executed -: 1013: #####: 1014: case 27: #####: 1015: xargs.no_colors = 1; #####: 1016: colorize = 0; #####: 1017: break; %%%%%: 1017-block 0 unconditional 0 never executed -: 1018: #####: 1019: case 28: #####: 1020: if (!is_number(optarg)) %%%%%: 1020-block 0 call 0 never executed branch 1 never executed branch 2 never executed #####: 1021: break; %%%%%: 1021-block 0 unconditional 0 never executed #####: 1022: int opt_int = atoi(optarg); #####: 1023: if (opt_int >= 0) %%%%%: 1023-block 0 branch 0 never executed branch 1 never executed #####: 1024: xargs.max_files = max_files = opt_int; %%%%%: 1024-block 0 unconditional 0 never executed #####: 1025: break; %%%%%: 1025-block 0 unconditional 0 never executed -: 1026: #####: 1027: case 29: -: 1028:#ifndef _NO_TRASH #####: 1029: xargs.trasrm = tr_as_rm = 1; break; %%%%%: 1029-block 0 unconditional 0 never executed -: 1030:#else -: 1031: fprintf(stderr, _("%s: trash: %s\n"), PROGRAM_NAME, _(NOT_AVAILABLE)); -: 1032: exit(EXIT_FAILURE); -: 1033:#endif #####: 1034: case 30: xargs.case_sens_dirjump = case_sens_dirjump = 1; break; %%%%%: 1034-block 0 unconditional 0 never executed #####: 1035: case 31: xargs.case_sens_path_comp = case_sens_path_comp = 1; break; %%%%%: 1035-block 0 unconditional 0 never executed 2: 1036: case 32: xargs.cwd_in_title = 1; break; 2: 1036-block 0 unconditional 0 taken 2 -: 1037: #####: 1038: case 33: { -: 1039: struct stat attr; #####: 1040: if (stat(optarg, &attr) == -1) { %%%%%: 1040-block 0 call 0 never executed branch 1 never executed branch 2 never executed #####: 1041: fprintf(stderr, "%s: %s: %s", PROGRAM_NAME, optarg, call 0 never executed #####: 1042: strerror(errno)); %%%%%: 1042-block 0 call 0 never executed #####: 1043: exit(EXIT_FAILURE); call 0 never executed -: 1044: } -: 1045: #####: 1046: if ((attr.st_mode & S_IFMT) != S_IFDIR) { %%%%%: 1046-block 0 branch 0 never executed branch 1 never executed #####: 1047: tmp_dir = (char *)xnmalloc(5, sizeof(char)); %%%%%: 1047-block 0 call 0 never executed #####: 1048: strcpy(tmp_dir, "/tmp"); #####: 1049: mime_file = (char *)xnmalloc(PATH_MAX, sizeof(char)); call 0 never executed #####: 1050: snprintf(mime_file, PATH_MAX, %%%%%: 1050-block 0 unconditional 0 never executed %%%%%: 1050-block 1 unconditional 1 never executed %%%%%: 1050-block 2 call 2 never executed -: 1051: "%s/.config/clifm/profiles/%s/mimelist.cfm", #####: 1052: getenv("HOME"), alt_profile ? alt_profile : "default"); branch 0 never executed branch 1 never executed #####: 1053: int ret = open_file(optarg); call 0 never executed #####: 1054: exit(ret); call 0 never executed -: 1055: } -: 1056: #####: 1057: printf(_("%s: %s: Is a directory\n"), PROGRAM_NAME, optarg); %%%%%: 1057-block 0 call 0 never executed call 1 never executed #####: 1058: exit(EXIT_FAILURE); call 0 never executed -: 1059: -: 1060: /* flags |= START_PATH; -: 1061: path_value = optarg; -: 1062: xargs.path = 1; */ -: 1063: } break; -: 1064: #####: 1065: case 34: xargs.printsel = 1; break; %%%%%: 1065-block 0 unconditional 0 never executed #####: 1066: case 35: xargs.suggestions = suggestions = 0; break; %%%%%: 1066-block 0 unconditional 0 never executed #####: 1067: case 36: xargs.autojump = autojump = 0; break; %%%%%: 1067-block 0 unconditional 0 never executed -: 1068:#ifndef _NO_HIGHLIGHT #####: 1069: case 37: xargs.highlight = highlight = 1; break; %%%%%: 1069-block 0 unconditional 0 never executed -: 1070:#endif #####: 1071: case 38: xargs.check_cap = check_cap = 0; break; %%%%%: 1071-block 0 unconditional 0 never executed #####: 1072: case 39: xargs.check_ext = check_ext = 0; break; %%%%%: 1072-block 0 unconditional 0 never executed #####: 1073: case 40: xargs.follow_symlinks = follow_symlinks = 0; break; %%%%%: 1073-block 0 unconditional 0 never executed -: 1074: #####: 1075: case 'a': #####: 1076: flags &= ~HIDDEN; /* Remove HIDDEN from 'flags' */ #####: 1077: show_hidden = xargs.hidden = 0; #####: 1078: break; %%%%%: 1078-block 0 unconditional 0 never executed -: 1079: #####: 1080: case 'A': #####: 1081: flags |= HIDDEN; /* Add HIDDEN to 'flags' */ #####: 1082: show_hidden = xargs.hidden = 1; #####: 1083: break; %%%%%: 1083-block 0 unconditional 0 never executed -: 1084: #####: 1085: case 'b': #####: 1086: xargs.bm_file = 1; #####: 1087: bm_value = optarg; #####: 1088: break; %%%%%: 1088-block 0 unconditional 0 never executed -: 1089: #####: 1090: case 'c': #####: 1091: xargs.config = 1; #####: 1092: config_value = optarg; #####: 1093: break; %%%%%: 1093-block 0 unconditional 0 never executed -: 1094: #####: 1095: case 'D': alt_dir_value = optarg; break; %%%%%: 1095-block 0 unconditional 0 never executed #####: 1096: case 'e': xargs.noeln = no_eln = 1; break; %%%%%: 1096-block 0 unconditional 0 never executed -: 1097: #####: 1098: case 'f': #####: 1099: flags &= ~FOLDERS_FIRST; #####: 1100: list_folders_first = xargs.ffirst = 0; #####: 1101: break; %%%%%: 1101-block 0 unconditional 0 never executed -: 1102: #####: 1103: case 'F': #####: 1104: flags |= FOLDERS_FIRST; #####: 1105: list_folders_first = xargs.ffirst = 1; #####: 1106: break; %%%%%: 1106-block 0 unconditional 0 never executed -: 1107: #####: 1108: case 'g': pager = xargs.pager = 1; break; %%%%%: 1108-block 0 unconditional 0 never executed #####: 1109: case 'G': pager = xargs.pager = 0; break; %%%%%: 1109-block 0 unconditional 0 never executed -: 1110: #####: 1111: case 'h': #####: 1112: flags |= HELP; -: 1113: /* Do not display "Press any key to continue" */ #####: 1114: flags |= EXT_HELP; #####: 1115: help_function(); %%%%%: 1115-block 0 call 0 never executed #####: 1116: exit(EXIT_SUCCESS); call 0 never executed -: 1117: #####: 1118: case 'i': #####: 1119: flags &= ~CASE_SENS; #####: 1120: case_sensitive = xargs.sensitive = 0; #####: 1121: break; %%%%%: 1121-block 0 unconditional 0 never executed -: 1122: #####: 1123: case 'I': #####: 1124: flags |= CASE_SENS; #####: 1125: case_sensitive = xargs.sensitive = 1; #####: 1126: break; %%%%%: 1126-block 0 unconditional 0 never executed -: 1127: #####: 1128: case 'k': kbinds_value = optarg; break; %%%%%: 1128-block 0 unconditional 0 never executed #####: 1129: case 'l': long_view = xargs.longview = 0; break; %%%%%: 1129-block 0 unconditional 0 never executed #####: 1130: case 'L': long_view = xargs.longview = 1; break; %%%%%: 1130-block 0 unconditional 0 never executed #####: 1131: case 'm': dirhist_map = xargs.dirmap = 1; break; %%%%%: 1131-block 0 unconditional 0 never executed -: 1132: #####: 1133: case 'o': #####: 1134: flags &= ~ON_THE_FLY; #####: 1135: cd_lists_on_the_fly = xargs.cd_list_auto = 0; #####: 1136: break; %%%%%: 1136-block 0 unconditional 0 never executed -: 1137: #####: 1138: case 'O': #####: 1139: flags |= ON_THE_FLY; #####: 1140: cd_lists_on_the_fly = xargs.cd_list_auto = 1; #####: 1141: break; %%%%%: 1141-block 0 unconditional 0 never executed -: 1142: #####: 1143: case 'p': #####: 1144: flags |= START_PATH; #####: 1145: path_value = optarg; #####: 1146: xargs.path = 1; #####: 1147: break; %%%%%: 1147-block 0 unconditional 0 never executed -: 1148: #####: 1149: case 'P': #####: 1150: flags |= ALT_PROFILE; #####: 1151: alt_profile_value = optarg; #####: 1152: break; %%%%%: 1152-block 0 unconditional 0 never executed -: 1153: #####: 1154: case 's': #####: 1155: flags |= SPLASH; #####: 1156: splash_screen = xargs.splash = 1; #####: 1157: break; %%%%%: 1157-block 0 unconditional 0 never executed -: 1158: #####: 1159: case 'S': xargs.stealth_mode = 1; break; %%%%%: 1159-block 0 unconditional 0 never executed #####: 1160: case 'u': unicode = xargs.unicode = 0; break; %%%%%: 1160-block 0 unconditional 0 never executed #####: 1161: case 'U': unicode = xargs.unicode = 1; break; %%%%%: 1161-block 0 unconditional 0 never executed -: 1162: #####: 1163: case 'v': #####: 1164: flags |= PRINT_VERSION; #####: 1165: version_function(); %%%%%: 1165-block 0 call 0 never executed #####: 1166: exit(EXIT_SUCCESS); call 0 never executed -: 1167: #####: 1168: case 'w': { #####: 1169: if (!is_number(optarg)) %%%%%: 1169-block 0 call 0 never executed branch 1 never executed branch 2 never executed #####: 1170: break; %%%%%: 1170-block 0 unconditional 0 never executed #####: 1171: int iopt = atoi(optarg); -: 1172: #####: 1173: if (iopt >= 0 && iopt <= MAX_WS) %%%%%: 1173-block 0 branch 0 never executed branch 1 never executed %%%%%: 1173-block 1 branch 2 never executed branch 3 never executed #####: 1174: cur_ws = iopt - 1; %%%%%: 1174-block 0 unconditional 0 never executed #####: 1175: } break; %%%%%: 1175-block 0 unconditional 0 never executed -: 1176: #####: 1177: case 'x': ext_cmd_ok = xargs.ext = 0; break; %%%%%: 1177-block 0 unconditional 0 never executed #####: 1178: case 'y': light_mode = xargs.light = 1; break; %%%%%: 1178-block 0 unconditional 0 never executed -: 1179: #####: 1180: case 'z': { #####: 1181: int arg = atoi(optarg); #####: 1182: if (!is_number(optarg) || arg < 0 || arg > SORT_TYPES) %%%%%: 1182-block 0 call 0 never executed branch 1 never executed branch 2 never executed %%%%%: 1182-block 1 branch 3 never executed branch 4 never executed %%%%%: 1182-block 2 branch 5 never executed branch 6 never executed #####: 1183: sort = 1; %%%%%: 1183-block 0 unconditional 0 never executed -: 1184: else #####: 1185: sort = arg; %%%%%: 1185-block 0 unconditional 0 never executed #####: 1186: xargs.sort = sort; #####: 1187: } break; %%%%%: 1187-block 0 unconditional 0 never executed -: 1188: #####: 1189: case '?': /* If some unrecognized option was found... */ -: 1190: -: 1191: /* Options that requires an argument */ -: 1192: /* Short options */ #####: 1193: switch (optopt) { %%%%%: 1193-block 0 branch 0 never executed branch 1 never executed #####: 1194: case 'b': /* fallthrough */ -: 1195: case 'c': /* fallthrough */ -: 1196: case 'k': /* fallthrough */ -: 1197: case 'p': /* fallthrough */ -: 1198: case 'P': /* fallthrough */ -: 1199: case 'w': /* fallthrough */ -: 1200: case 'z': #####: 1201: fprintf(stderr, _("%s: option requires an argument -- " %%%%%: 1201-block 0 call 0 never executed call 1 never executed -: 1202: "'%c'\nTry '%s --help' for more information.\n"), -: 1203: PROGRAM_NAME, optopt, PNL); #####: 1204: exit(EXIT_FAILURE); call 0 never executed -: 1205: } -: 1206: -: 1207: /* Long options */ #####: 1208: if (optopt >= 0 && optopt <= long_opts) { %%%%%: 1208-block 0 branch 0 never executed branch 1 never executed %%%%%: 1208-block 1 branch 2 never executed branch 3 never executed #####: 1209: fprintf(stderr, _("%s: option requires an argument\nTry '%s " %%%%%: 1209-block 0 call 0 never executed call 1 never executed -: 1210: "--help' for more information.\n"), PROGRAM_NAME, PNL); #####: 1211: exit(EXIT_FAILURE); call 0 never executed -: 1212: } -: 1213: -: 1214: /* If unknown option is printable... */ #####: 1215: if (isprint(optopt)) { %%%%%: 1215-block 0 branch 0 never executed branch 1 never executed #####: 1216: fprintf(stderr, _("%s: invalid option -- '%c'\nUsage: " %%%%%: 1216-block 0 call 0 never executed call 1 never executed unconditional 2 never executed -: 1217: "%s %s\nTry '%s --help' for more information.\n"), -: 1218: PROGRAM_NAME, optopt, GRAL_USAGE, PNL, PNL); -: 1219: } else { #####: 1220: fprintf(stderr, _("%s: unknown option character '\\%x'\n"), %%%%%: 1220-block 0 call 0 never executed call 1 never executed unconditional 2 never executed -: 1221: PROGRAM_NAME, (unsigned int)optopt); -: 1222: } -: 1223: #####: 1224: exit(EXIT_FAILURE); %%%%%: 1224-block 0 call 0 never executed -: 1225: #####: 1226: default: #####: 1227: break; %%%%%: 1227-block 0 unconditional 0 never executed -: 1228: } -: 1229: } -: 1230: -: 1231: /* Positional parameters. If a directory, use it as CliFM starting -: 1232: * path. Otherwise, open the file with the associated application -: 1233: * and exit */ 4: 1234: int i = optind; 4: 1235: if (argv[i]) { 4: 1235-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 2 -: 1236: struct stat attr; 2: 1237: char *_exp_path = tilde_expand(argv[i]); 2: 1237-block 0 call 0 returned 2 2: 1238: if (_exp_path) { branch 0 taken 2 (fallthrough) branch 1 taken 0 2: 1239: if (stat(_exp_path, &attr) == -1) { 2: 1239-block 0 call 0 returned 2 branch 1 taken 0 (fallthrough) branch 2 taken 2 #####: 1240: fprintf(stderr, "%s: %s: %s", PROGRAM_NAME, _exp_path, call 0 never executed #####: 1241: strerror(errno)); %%%%%: 1241-block 0 call 0 never executed #####: 1242: free(_exp_path); #####: 1243: exit(EXIT_FAILURE); call 0 never executed -: 1244: } 2: 1245: free(_exp_path); 2: 1245-block 0 unconditional 0 taken 2 -: 1246: } else { #####: 1247: fprintf(stderr, _("%s: Error expanding tilde\n"), PROGRAM_NAME); %%%%%: 1247-block 0 call 0 never executed call 1 never executed #####: 1248: exit(EXIT_FAILURE); call 0 never executed -: 1249: } -: 1250: 2: 1251: if ((attr.st_mode & S_IFMT) != S_IFDIR) { 2: 1251-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 2 #####: 1252: tmp_dir = (char *)xnmalloc(5, sizeof(char)); %%%%%: 1252-block 0 call 0 never executed #####: 1253: strcpy(tmp_dir, "/tmp"); #####: 1254: mime_file = (char *)xnmalloc(PATH_MAX, sizeof(char)); call 0 never executed #####: 1255: snprintf(mime_file, PATH_MAX, %%%%%: 1255-block 0 unconditional 0 never executed %%%%%: 1255-block 1 unconditional 1 never executed %%%%%: 1255-block 2 call 2 never executed -: 1256: "%s/.config/clifm/profiles/%s/mimelist.cfm", #####: 1257: getenv("HOME"), alt_profile ? alt_profile : "default"); branch 0 never executed branch 1 never executed #####: 1258: int ret = open_file(argv[i]); call 0 never executed #####: 1259: exit(ret); call 0 never executed -: 1260: } -: 1261: 2: 1262: flags |= START_PATH; 2: 1263: path_value = argv[i]; 2: 1264: xargs.path = 1; 2: 1264-block 0 unconditional 0 taken 2 -: 1265: } -: 1266: 4: 1267: if (bm_value) { 4: 1267-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 4 #####: 1268: char *bm_exp = (char *)NULL; -: 1269: #####: 1270: if (*bm_value == '~') { %%%%%: 1270-block 0 branch 0 never executed branch 1 never executed #####: 1271: bm_exp = tilde_expand(bm_value); %%%%%: 1271-block 0 call 0 never executed #####: 1272: bm_value = bm_exp; unconditional 0 never executed -: 1273: } -: 1274: #####: 1275: if (access(bm_value, R_OK) == -1) { %%%%%: 1275-block 0 call 0 never executed branch 1 never executed branch 2 never executed #####: 1276: _err('e', PRINT_PROMPT, _("%s: %s: %s\n" call 0 never executed call 1 never executed unconditional 2 never executed -: 1277: "Falling back to the default bookmarks file\n"), #####: 1278: PROGRAM_NAME, bm_value, strerror(errno)); %%%%%: 1278-block 0 call 0 never executed -: 1279: } else { #####: 1280: alt_bm_file = savestring(bm_value, strlen(bm_value)); %%%%%: 1280-block 0 call 0 never executed #####: 1281: _err('n', PRINT_PROMPT, _("%s: Loaded alternative " call 0 never executed call 1 never executed unconditional 2 never executed -: 1282: "bookmarks file\n"), PROGRAM_NAME); -: 1283: } -: 1284: } -: 1285: 4: 1286: if (alt_dir_value) { 4: 1286-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 4 #####: 1287: char *dir_exp = (char *)NULL; -: 1288: #####: 1289: if (*alt_dir_value == '~') { %%%%%: 1289-block 0 branch 0 never executed branch 1 never executed #####: 1290: dir_exp = tilde_expand(alt_dir_value); %%%%%: 1290-block 0 call 0 never executed #####: 1291: alt_dir_value = dir_exp; unconditional 0 never executed -: 1292: } -: 1293: #####: 1294: int dir_ok = 1; -: 1295: struct stat attr; #####: 1296: if (stat(alt_dir_value, &attr) == -1) { %%%%%: 1296-block 0 call 0 never executed branch 1 never executed branch 2 never executed #####: 1297: char *tmp_cmd[] = {"mkdir", "-p", alt_dir_value, NULL}; #####: 1298: int ret = launch_execve(tmp_cmd, FOREGROUND, E_NOSTDERR); %%%%%: 1298-block 0 call 0 never executed #####: 1299: if (ret != EXIT_SUCCESS) { branch 0 never executed branch 1 never executed #####: 1300: _err('e', PRINT_PROMPT, _("%s: %s: Cannot create directory " %%%%%: 1300-block 0 call 0 never executed call 1 never executed -: 1301: "(error %d)\nFalling back to default configuration directory\n"), -: 1302: PROGRAM_NAME, alt_dir_value, ret); #####: 1303: dir_ok = 0; unconditional 0 never executed -: 1304: } -: 1305: } -: 1306: #####: 1307: if (access(alt_dir_value, W_OK) == -1) { %%%%%: 1307-block 0 call 0 never executed branch 1 never executed branch 2 never executed #####: 1308: if (dir_ok) { %%%%%: 1308-block 0 branch 0 never executed branch 1 never executed #####: 1309: _err('e', PRINT_PROMPT, _("%s: %s: %s\n" call 0 never executed call 1 never executed unconditional 2 never executed -: 1310: "Falling back to default configuration directory\n"), #####: 1311: PROGRAM_NAME, alt_dir_value, strerror(errno)); %%%%%: 1311-block 0 call 0 never executed -: 1312: } -: 1313: } else { #####: 1314: alt_config_dir = savestring(alt_dir_value, strlen(alt_dir_value)); %%%%%: 1314-block 0 call 0 never executed #####: 1315: _err(0, PRINT_PROMPT, _("%s: %s: Using alternative " call 0 never executed call 1 never executed unconditional 2 never executed -: 1316: "configuration directory\n"), PROGRAM_NAME, alt_config_dir); -: 1317: } -: 1318: #####: 1319: if (dir_exp) %%%%%: 1319-block 0 branch 0 never executed branch 1 never executed #####: 1320: free(dir_exp); %%%%%: 1320-block 0 unconditional 0 never executed -: 1321: } -: 1322: 4: 1323: if (kbinds_value) { 4: 1323-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 4 #####: 1324: char *kbinds_exp = (char *)NULL; #####: 1325: if (*kbinds_value == '~') { %%%%%: 1325-block 0 branch 0 never executed branch 1 never executed #####: 1326: kbinds_exp = tilde_expand(kbinds_value); %%%%%: 1326-block 0 call 0 never executed #####: 1327: kbinds_value = kbinds_exp; unconditional 0 never executed -: 1328: } -: 1329: -: 1330: /* if (alt_kbinds_file) { -: 1331: free(alt_kbinds_file); -: 1332: alt_kbinds_file = (char *)NULL; -: 1333: } */ -: 1334: #####: 1335: if (access(kbinds_value, R_OK) == -1) { %%%%%: 1335-block 0 call 0 never executed branch 1 never executed branch 2 never executed #####: 1336: _err('e', PRINT_PROMPT, _("%s: %s: %s\n" call 0 never executed call 1 never executed unconditional 2 never executed -: 1337: "Falling back to the default keybindings file\n"), #####: 1338: PROGRAM_NAME, kbinds_value, strerror(errno)); %%%%%: 1338-block 0 call 0 never executed -: 1339: /* xargs.config = -1; */ -: 1340: } else { #####: 1341: alt_kbinds_file = savestring(kbinds_value, strlen(kbinds_value)); %%%%%: 1341-block 0 call 0 never executed #####: 1342: _err('n', PRINT_PROMPT, _("%s: Loaded alternative " call 0 never executed call 1 never executed unconditional 2 never executed -: 1343: "keybindings file\n"), PROGRAM_NAME); -: 1344: } -: 1345: #####: 1346: if (kbinds_exp) %%%%%: 1346-block 0 branch 0 never executed branch 1 never executed #####: 1347: free(kbinds_exp); %%%%%: 1347-block 0 unconditional 0 never executed -: 1348: } -: 1349: 4: 1350: if (xargs.config && config_value) { 4: 1350-block 0 branch 0 taken 4 (fallthrough) branch 1 taken 0 4: 1350-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 4 #####: 1351: char *config_exp = (char *)NULL; -: 1352: #####: 1353: if (*config_value == '~') { %%%%%: 1353-block 0 branch 0 never executed branch 1 never executed #####: 1354: config_exp = tilde_expand(config_value); %%%%%: 1354-block 0 call 0 never executed #####: 1355: config_value = config_exp; unconditional 0 never executed -: 1356: } -: 1357: -: 1358: /* if (alt_config_file) { -: 1359: free(alt_config_file); -: 1360: alt_config_file = (char *)NULL; -: 1361: } */ -: 1362: #####: 1363: if (access(config_value, R_OK) == -1) { %%%%%: 1363-block 0 call 0 never executed branch 1 never executed branch 2 never executed #####: 1364: _err('e', PRINT_PROMPT, _("%s: %s: %s\n" call 0 never executed call 1 never executed -: 1365: "Falling back to default\n"), PROGRAM_NAME, #####: 1366: config_value, strerror(errno)); %%%%%: 1366-block 0 call 0 never executed #####: 1367: xargs.config = -1; unconditional 0 never executed -: 1368: } else { #####: 1369: alt_config_file = savestring(config_value, strlen(config_value)); %%%%%: 1369-block 0 call 0 never executed #####: 1370: _err('n', PRINT_PROMPT, _("%s: Loaded alternative " call 0 never executed call 1 never executed unconditional 2 never executed -: 1371: "configuration file\n"), PROGRAM_NAME); -: 1372: } -: 1373: #####: 1374: if (config_exp) %%%%%: 1374-block 0 branch 0 never executed branch 1 never executed #####: 1375: free(config_exp); %%%%%: 1375-block 0 unconditional 0 never executed -: 1376: } -: 1377: 4: 1378: if ((flags & START_PATH) && path_value) { 4: 1378-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 2 2: 1378-block 1 branch 2 taken 2 (fallthrough) branch 3 taken 0 2: 1379: char *path_exp = (char *)NULL; -: 1380: char path_tmp[PATH_MAX]; -: 1381: 2: 1382: if (*path_value == '~') { 2: 1382-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 2 #####: 1383: path_exp = tilde_expand(path_value); %%%%%: 1383-block 0 call 0 never executed #####: 1384: xstrsncpy(path_tmp, path_exp, PATH_MAX); call 0 never executed unconditional 1 never executed 2: 1385: } else if (*path_value != '/') { 2: 1385-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 2 #####: 1386: snprintf(path_tmp, PATH_MAX - 1, "%s/%s", getenv("PWD"), path_value); %%%%%: 1386-block 0 call 0 never executed unconditional 1 never executed -: 1387: } else { 2: 1388: xstrsncpy(path_tmp, path_value, PATH_MAX); 2: 1388-block 0 call 0 returned 2 unconditional 1 taken 2 -: 1389: } -: 1390: 2: 1391: if (xchdir(path_tmp, SET_TITLE) == 0) { 2: 1391-block 0 call 0 returned 2 branch 1 taken 2 (fallthrough) branch 2 taken 0 2: 1392: if (cur_ws == UNSET) 2: 1392-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 0 2: 1393: cur_ws = DEF_CUR_WS; 2: 1393-block 0 unconditional 0 taken 2 2: 1394: if (ws[cur_ws].path) 2: 1394-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 2 #####: 1395: free(ws[cur_ws].path); %%%%%: 1395-block 0 unconditional 0 never executed -: 1396: 2: 1397: ws[cur_ws].path = savestring(path_tmp, strlen(path_tmp)); 2: 1397-block 0 call 0 returned 2 unconditional 1 taken 2 -: 1398: } else { /* Error changing directory */ #####: 1399: if (xargs.list_and_quit == 1) { %%%%%: 1399-block 0 branch 0 never executed branch 1 never executed #####: 1400: fprintf(stderr, "%s: %s: %s\n", PROGRAM_NAME, call 0 never executed #####: 1401: path_tmp, strerror(errno)); %%%%%: 1401-block 0 call 0 never executed #####: 1402: exit(EXIT_FAILURE); call 0 never executed -: 1403: } -: 1404: #####: 1405: _err('w', PRINT_PROMPT, "%s: %s: %s\n", PROGRAM_NAME, call 0 never executed unconditional 1 never executed #####: 1406: path_tmp, strerror(errno)); %%%%%: 1406-block 0 call 0 never executed -: 1407: } -: 1408: 2: 1409: if (path_exp) 2: 1409-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 2 #####: 1410: free(path_exp); %%%%%: 1410-block 0 unconditional 0 never executed -: 1411: } -: 1412: 4*: 1413: if ((flags & ALT_PROFILE) && alt_profile_value) { 4: 1413-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 4 %%%%%: 1413-block 1 branch 2 never executed branch 3 never executed #####: 1414: if (alt_profile) %%%%%: 1414-block 0 branch 0 never executed branch 1 never executed #####: 1415: free(alt_profile); %%%%%: 1415-block 0 unconditional 0 never executed #####: 1416: alt_profile = savestring(alt_profile_value, strlen(alt_profile_value)); %%%%%: 1416-block 0 call 0 never executed unconditional 1 never executed -: 1417: } 4: 1418:} -: 1419: -: 1420:void function unset_xargs called 4 returned 100% blocks executed 100% 4: 1421:unset_xargs(void) -: 1422:{ 4: 1423: xargs.autojump = UNSET; 4: 1424: xargs.auto_open = UNSET; 4: 1425: xargs.autocd = UNSET; 4: 1426: xargs.bm_file = UNSET; 4: 1427: xargs.case_sens_dirjump = UNSET; 4: 1428: xargs.case_sens_path_comp = UNSET; 4: 1429: xargs.cd_list_auto = UNSET; 4: 1430: xargs.check_cap = UNSET; 4: 1431: xargs.check_ext = UNSET; 4: 1432: xargs.cd_on_quit = UNSET; 4: 1433: xargs.classify = UNSET; 4: 1434: xargs.clear_screen = UNSET; 4: 1435: xargs.color_scheme = UNSET; 4: 1436: xargs.config = UNSET; 4: 1437: xargs.cwd_in_title = UNSET; 4: 1438: xargs.dirmap = UNSET; 4: 1439: xargs.disk_usage = UNSET; 4: 1440: xargs.expand_bookmarks = UNSET; 4: 1441: xargs.ext = UNSET; 4: 1442: xargs.ffirst = UNSET; 4: 1443: xargs.files_counter = UNSET; 4: 1444: xargs.follow_symlinks = UNSET; 4: 1445: xargs.hidden = UNSET; -: 1446:#ifndef _NO_HIGHLIGHT 4: 1447: xargs.highlight = UNSET; -: 1448:#endif -: 1449:#ifndef _NO_ICONS 4: 1450: xargs.icons = UNSET; 4: 1451: xargs.icons_use_file_color = UNSET; -: 1452:#endif 4: 1453: xargs.light = UNSET; 4: 1454: xargs.list_and_quit = UNSET; 4: 1455: xargs.logs = UNSET; 4: 1456: xargs.longview = UNSET; 4: 1457: xargs.max_dirhist = UNSET; 4: 1458: xargs.max_path = UNSET; 4: 1459: xargs.no_colors = UNSET; 4: 1460: xargs.no_columns = UNSET; 4: 1461: xargs.no_dirjump = UNSET; 4: 1462: xargs.noeln = UNSET; 4: 1463: xargs.only_dirs = UNSET; 4: 1464: xargs.path = UNSET; 4: 1465: xargs.pager = UNSET; 4: 1466: xargs.printsel = UNSET; 4: 1467: xargs.restore_last_path = UNSET; 4: 1468: xargs.rl_vi_mode = UNSET; 4: 1469: xargs.sensitive = UNSET; 4: 1470: xargs.share_selbox = UNSET; 4: 1471: xargs.sort = UNSET; 4: 1472: xargs.sort_reverse = UNSET; 4: 1473: xargs.splash = UNSET; 4: 1474: xargs.stealth_mode = UNSET; -: 1475:#ifndef _NO_SUGGESTIONS 4: 1476: xargs.suggestions = UNSET; -: 1477:#endif 4: 1478: xargs.tips = UNSET; -: 1479:#ifndef _NO_TRASH 4: 1480: xargs.trasrm = UNSET; -: 1481:#endif 4: 1482: xargs.unicode = UNSET; 4: 1483: xargs.welcome_message = UNSET; 4: 1484:} -: 1485: -: 1486:/* Keep track of attributes of the shell. Make sure the shell is running -: 1487: * interactively as the foreground job before proceeding. -: 1488: * Taken from: -: 1489: * https://www.gnu.org/software/libc/manual/html_node/Initializing-the-Shell.html#Initializing-the-Shell -: 1490: * */ -: 1491:void function init_shell called 4 returned 100% blocks executed 71% 4: 1492:init_shell(void) -: 1493:{ -: 1494: /* If shell is not interactive */ 4: 1495: if (!isatty(STDIN_FILENO)) { 4: 1495-block 0 call 0 returned 4 branch 1 taken 0 (fallthrough) branch 2 taken 4 #####: 1496: handle_stdin(); %%%%%: 1496-block 0 call 0 never executed #####: 1497: return; unconditional 0 never executed -: 1498: } -: 1499: -: 1500: /* Loop until we are in the foreground */ 4: 1501: while (tcgetpgrp(STDIN_FILENO) != (own_pid = getpgrp())) 4: 1501-block 0 unconditional 0 taken 4 4: 1501-block 1 call 1 returned 4 call 2 returned 4 branch 3 taken 0 branch 4 taken 4 (fallthrough) #####: 1502: kill(-own_pid, SIGTTIN); %%%%%: 1502-block 0 call 0 never executed unconditional 1 never executed -: 1503: -: 1504: /* Ignore interactive and job-control signals */ 4: 1505: set_signals_to_ignore(); 4: 1505-block 0 call 0 returned 4 -: 1506: /* Put ourselves in our own process group */ 4: 1507: own_pid = get_own_pid(); call 0 returned 4 -: 1508: 4: 1509: if (flags & ROOT_USR) { branch 0 taken 1 (fallthrough) branch 1 taken 3 -: 1510: /* Make the shell pgid (process group id) equal to its pid */ -: 1511: /* Without the setpgid line below, the program cannot be run -: 1512: * with sudo, but it can be run nonetheless by the root user */ 1: 1513: if (setpgid(own_pid, own_pid) < 0) { 1: 1513-block 0 call 0 returned 1 branch 1 taken 0 (fallthrough) branch 2 taken 1 #####: 1514: _err(0, NOPRINT_PROMPT, "%s: setpgid: %s\n", PROGRAM_NAME, call 0 never executed #####: 1515: strerror(errno)); %%%%%: 1515-block 0 call 0 never executed #####: 1516: exit(EXIT_FAILURE); call 0 never executed -: 1517: } -: 1518: } -: 1519: -: 1520: /* Grab control of the terminal */ 4: 1521: tcsetpgrp(STDIN_FILENO, own_pid); 4: 1521-block 0 call 0 returned 4 -: 1522: /* Save default terminal attributes for shell */ 4: 1523: tcgetattr(STDIN_FILENO, &shell_tmodes); call 0 returned 4 4: 1524: return; unconditional 0 taken 4 -: 1525:} -: 1526: -: 1527:/* Get current entries in the Selection Box, if any. */ -: 1528:int function get_sel_files called 513 returned 100% blocks executed 92% 513: 1529:get_sel_files(void) -: 1530:{ 513: 1531: if (!selfile_ok || !config_ok) 513: 1531-block 0 branch 0 taken 513 (fallthrough) branch 1 taken 0 513: 1531-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 513 #####: 1532: return EXIT_FAILURE; %%%%%: 1532-block 0 unconditional 0 never executed -: 1533: -: 1534: /* First, clear the sel array, in case it was already used */ 513: 1535: if (sel_n > 0) { 513: 1535-block 0 branch 0 taken 53 (fallthrough) branch 1 taken 460 53: 1536: int i = (int)sel_n; 180: 1537: while (--i >= 0) 53: 1537-block 0 unconditional 0 taken 53 180: 1537-block 1 branch 1 taken 127 branch 2 taken 53 (fallthrough) 127: 1538: free(sel_elements[i]); 127: 1538-block 0 unconditional 0 taken 127 -: 1539: } -: 1540: -: 1541: /* free(sel_elements); */ -: 1542: 513: 1543: sel_n = 0; -: 1544: -: 1545: /* Open the tmp sel file and load its contents into the sel array */ -: 1546: int fd; 513: 1547: FILE *fp = open_fstream_r(sel_file, &fd); 513: 1547-block 0 call 0 returned 513 -: 1548: /* sel_elements = xcalloc(1, sizeof(char *)); */ 513: 1549: if (!fp) branch 0 taken 460 (fallthrough) branch 1 taken 53 460: 1550: return EXIT_FAILURE; 460: 1550-block 0 unconditional 0 taken 460 -: 1551: -: 1552: /* Since this file contains only paths, we can be sure no line -: 1553: * length will be larger than PATH_MAX */ 53: 1554: char line[PATH_MAX] = ""; 180: 1555: while (fgets(line, (int)sizeof(line), fp)) { 53: 1555-block 0 unconditional 0 taken 53 180: 1555-block 1 call 1 returned 180 branch 2 taken 127 branch 3 taken 53 (fallthrough) 127: 1556: size_t len = strlen(line); -: 1557: 127: 1558: if (line[len - 1] == '\n') 127: 1558-block 0 branch 0 taken 127 (fallthrough) branch 1 taken 0 127: 1559: line[len - 1] = '\0'; 127: 1559-block 0 unconditional 0 taken 127 -: 1560: 127*: 1561: if (!*line || *line == '#') 127: 1561-block 0 branch 0 taken 127 (fallthrough) branch 1 taken 0 127: 1561-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 127 #####: 1562: continue; %%%%%: 1562-block 0 unconditional 0 never executed -: 1563: 127: 1564: sel_elements = (char **)xrealloc(sel_elements, (sel_n + 1) * sizeof(char *)); 127: 1564-block 0 call 0 returned 127 127: 1565: sel_elements[sel_n++] = savestring(line, len); call 0 returned 127 unconditional 1 taken 127 -: 1566: } -: 1567: 53: 1568: close_fstream(fp, fd); 53: 1568-block 0 call 0 returned 53 53: 1569: return EXIT_SUCCESS; unconditional 0 taken 53 -: 1570:} -: 1571: -: 1572:size_t function get_cdpath called 4 returned 100% blocks executed 100% 4: 1573:get_cdpath(void) -: 1574:{ 4: 1575: char *p = getenv("CDPATH"); 4: 1575-block 0 call 0 returned 4 4: 1576: if (!p || !*p) branch 0 taken 3 (fallthrough) branch 1 taken 1 3: 1576-block 0 branch 2 taken 0 (fallthrough) branch 3 taken 3 1: 1577: return 0; 1: 1577-block 0 unconditional 0 taken 1 -: 1578: 3: 1579: char *t = savestring(p, strlen(p)); 3: 1579-block 0 call 0 returned 3 -: 1580: -: 1581: /* Get each path in CDPATH */ 3: 1582: size_t i, n = 0, len = 0; 6: 1583: for (i = 0; t[i]; i++) { unconditional 0 taken 3 3: 1583-block 0 unconditional 1 taken 3 6: 1583-block 1 branch 2 taken 6 branch 3 taken 0 (fallthrough) -: 1584: /* Store path in CDPATH in a tmp buffer */ -: 1585: char buf[PATH_MAX]; 54: 1586: while (t[i] && t[i] != ':') 6: 1586-block 0 unconditional 0 taken 6 54: 1586-block 1 branch 1 taken 51 (fallthrough) branch 2 taken 3 51: 1586-block 2 branch 3 taken 48 branch 4 taken 3 (fallthrough) 48: 1587: buf[len++] = t[i++]; 48: 1587-block 0 unconditional 0 taken 48 6: 1588: buf[len] = '\0'; -: 1589: -: 1590: /* Make room in cdpaths for a new path */ 6: 1591: cdpaths = (char **)xrealloc(cdpaths, (n + 2) * sizeof(char *)); 6: 1591-block 0 call 0 returned 6 -: 1592: -: 1593: /* Dump the buffer into the global cdpaths array */ 6: 1594: cdpaths[n++] = savestring(buf, len); call 0 returned 6 -: 1595: 6: 1596: len = 0; 6: 1597: if (!t[i]) branch 0 taken 3 (fallthrough) branch 1 taken 3 3: 1598: break; 3: 1598-block 0 unconditional 0 taken 3 -: 1599: } -: 1600: 3: 1601: cdpaths[n] = (char *)NULL; -: 1602: 3: 1603: free(t); 3: 1604: return n; 3: 1604-block 0 unconditional 0 taken 3 -: 1605:} -: 1606: -: 1607:/* Store all paths in the PATH environment variable into a globally -: 1608: * declared array (paths) */ -: 1609:size_t function get_path_env called 22 returned 100% blocks executed 95% 22: 1610:get_path_env(void) -: 1611:{ 22: 1612: size_t i = 0; -: 1613: /* Get the value of the PATH env variable */ 22: 1614: char *path_tmp = (char *)NULL; -: 1615: -: 1616:#if __linux__ 550: 1617: for (i = 0; __environ[i]; i++) { 22: 1617-block 0 unconditional 0 taken 22 528: 1617-block 1 unconditional 1 taken 528 550: 1617-block 2 branch 2 taken 550 branch 3 taken 0 (fallthrough) 550: 1618: if (*__environ[i] == 'P' && strncmp(__environ[i], "PATH", 4) == 0) { 550: 1618-block 0 branch 0 taken 43 (fallthrough) branch 1 taken 507 43: 1618-block 1 branch 2 taken 22 (fallthrough) branch 3 taken 21 22: 1619: path_tmp = straft(__environ[i], '='); 22: 1619-block 0 call 0 returned 22 22: 1620: break; unconditional 0 taken 22 -: 1621: } -: 1622: } -: 1623:#else -: 1624: char *ptr = getenv("PATH"); -: 1625: if (!ptr || !*ptr) -: 1626: return 0; -: 1627: path_tmp = savestring(ptr, strlen(ptr)); -: 1628:#endif -: 1629: 22: 1630: if (!path_tmp) 22: 1630-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 22 #####: 1631: return 0; %%%%%: 1631-block 0 unconditional 0 never executed -: 1632: -: 1633: /* Get each path in PATH */ 22: 1634: size_t path_num = 0, length = 0; 132: 1635: for (i = 0; path_tmp[i]; i++) { 22: 1635-block 0 unconditional 0 taken 22 110: 1635-block 1 unconditional 1 taken 110 132: 1635-block 2 branch 2 taken 132 branch 3 taken 0 (fallthrough) -: 1636: /* Store path in PATH in a tmp buffer */ -: 1637: char buf[PATH_MAX]; 2178: 1638: while (path_tmp[i] && path_tmp[i] != ':') 132: 1638-block 0 unconditional 0 taken 132 2178: 1638-block 1 branch 1 taken 2156 (fallthrough) branch 2 taken 22 2156: 1638-block 2 branch 3 taken 2046 branch 4 taken 110 (fallthrough) 2046: 1639: buf[length++] = path_tmp[i++]; 2046: 1639-block 0 unconditional 0 taken 2046 132: 1640: buf[length] = '\0'; -: 1641: -: 1642: /* Make room in paths for a new path */ 132: 1643: paths = (char **)xrealloc(paths, (path_num + 1) * sizeof(char *)); 132: 1643-block 0 call 0 returned 132 -: 1644: -: 1645: /* Dump the buffer into the global paths array */ 132: 1646: paths[path_num] = savestring(buf, length); call 0 returned 132 -: 1647: 132: 1648: path_num++; 132: 1649: length = 0; 132: 1650: if (!path_tmp[i]) branch 0 taken 22 (fallthrough) branch 1 taken 110 22: 1651: break; 22: 1651-block 0 unconditional 0 taken 22 -: 1652: } -: 1653: 22: 1654: free(path_tmp); 22: 1655: return path_num; 22: 1655-block 0 unconditional 0 taken 22 -: 1656:} -: 1657: -: 1658:/* Set PATH to last visited directory and CUR_WS to last used -: 1659: * workspace */ -: 1660:int function get_last_path called 8 returned 100% blocks executed 88% 8: 1661:get_last_path(void) -: 1662:{ 8: 1663: if (!config_dir) 8: 1663-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 8 #####: 1664: return EXIT_FAILURE; %%%%%: 1664-block 0 unconditional 0 never executed -: 1665: 8: 1666: char *last_file = (char *)xnmalloc(strlen(config_dir) + 7, sizeof(char)); 8: 1666-block 0 call 0 returned 8 8: 1667: sprintf(last_file, "%s/.last", config_dir); -: 1668: -: 1669: int fd; 8: 1670: FILE *fp = open_fstream_r(last_file, &fd); call 0 returned 8 8: 1671: if (!fp) { branch 0 taken 1 (fallthrough) branch 1 taken 7 1: 1672: free(last_file); 1: 1673: return EXIT_FAILURE; 1: 1673-block 0 unconditional 0 taken 1 -: 1674: } -: 1675: -: 1676: /* size_t i; -: 1677: for (i = 0; i < MAX_WS; i++) { -: 1678: -: 1679: if (ws[i].path) { -: 1680: free(ws[i].path); -: 1681: ws[i].path = (char *)NULL; -: 1682: } -: 1683: } */ -: 1684: 7: 1685: char line[PATH_MAX] = ""; 35: 1686: while (fgets(line, (int)sizeof(line), fp)) { 7: 1686-block 0 unconditional 0 taken 7 35: 1686-block 1 call 1 returned 35 branch 2 taken 28 branch 3 taken 7 (fallthrough) 28: 1687: char *p = line; 28*: 1688: if (!*p || !strchr(p, '/')) 28: 1688-block 0 branch 0 taken 28 (fallthrough) branch 1 taken 0 28: 1688-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 28 #####: 1689: continue; %%%%%: 1689-block 0 unconditional 0 never executed 28*: 1690: if (!strchr(p, ':')) 28: 1690-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 28 #####: 1691: continue; %%%%%: 1691-block 0 unconditional 0 never executed -: 1692: 28: 1693: size_t len = strlen(p); 28: 1694: if (p[len - 1] == '\n') 28: 1694-block 0 branch 0 taken 28 (fallthrough) branch 1 taken 0 28: 1695: p[len - 1] = '\0'; 28: 1695-block 0 unconditional 0 taken 28 -: 1696: 28: 1697: int cur = 0; 28: 1698: if (*p == '*') { 28: 1698-block 0 branch 0 taken 7 (fallthrough) branch 1 taken 21 7*: 1699: if (!*(++p)) 7: 1699-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 7 #####: 1700: continue; %%%%%: 1700-block 0 unconditional 0 never executed 7: 1701: cur = 1; 7: 1701-block 0 unconditional 0 taken 7 -: 1702: } -: 1703: 28: 1704: int ws_n = *p - '0'; 28: 1705: if (cur && cur_ws == UNSET) 28: 1705-block 0 branch 0 taken 7 (fallthrough) branch 1 taken 21 7: 1705-block 1 branch 2 taken 6 (fallthrough) branch 3 taken 1 6: 1706: cur_ws = ws_n; 6: 1706-block 0 unconditional 0 taken 6 -: 1707: 28: 1708: if (ws_n >= 0 && ws_n < MAX_WS && !ws[ws_n].path) 28: 1708-block 0 branch 0 taken 28 (fallthrough) branch 1 taken 0 28: 1708-block 1 branch 2 taken 28 (fallthrough) branch 3 taken 0 28: 1708-block 2 branch 4 taken 27 (fallthrough) branch 5 taken 1 27: 1709: ws[ws_n].path = savestring(p + 2, strlen(p + 2)); 27: 1709-block 0 call 0 returned 27 unconditional 1 taken 27 -: 1710: } -: 1711: 7: 1712: close_fstream(fp, fd); 7: 1712-block 0 call 0 returned 7 7: 1713: free(last_file); 7: 1714: return EXIT_SUCCESS; unconditional 0 taken 7 -: 1715:} -: 1716: -: 1717:/* Restore pinned dir from file */ -: 1718:int function load_pinned_dir called 4 returned 100% blocks executed 33% 4: 1719:load_pinned_dir(void) -: 1720:{ 4: 1721: if (!config_ok) 4: 1721-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 4 #####: 1722: return EXIT_FAILURE; %%%%%: 1722-block 0 unconditional 0 never executed -: 1723: 4: 1724: char *pin_file = (char *)xnmalloc(strlen(config_dir) + 6, sizeof(char)); 4: 1724-block 0 call 0 returned 4 4: 1725: sprintf(pin_file, "%s/.pin", config_dir); -: 1726: -: 1727: int fd; 4: 1728: FILE *fp = open_fstream_r(pin_file, &fd); call 0 returned 4 4: 1729: if (!fp) { branch 0 taken 4 (fallthrough) branch 1 taken 0 4: 1730: free(pin_file); 4: 1731: return EXIT_FAILURE; 4: 1731-block 0 unconditional 0 taken 4 -: 1732: } -: 1733: #####: 1734: char line[PATH_MAX] = ""; #####: 1735: if (fgets(line, (int)sizeof(line), fp) == NULL) { %%%%%: 1735-block 0 call 0 never executed branch 1 never executed branch 2 never executed #####: 1736: free(pin_file); #####: 1737: close_fstream(fp, fd); %%%%%: 1737-block 0 call 0 never executed #####: 1738: return EXIT_FAILURE; unconditional 0 never executed -: 1739: } -: 1740: #####: 1741: if (!*line || !strchr(line, '/')) { %%%%%: 1741-block 0 branch 0 never executed branch 1 never executed %%%%%: 1741-block 1 branch 2 never executed branch 3 never executed #####: 1742: free(pin_file); #####: 1743: close_fstream(fp, fd); %%%%%: 1743-block 0 call 0 never executed #####: 1744: return EXIT_FAILURE; unconditional 0 never executed -: 1745: } -: 1746: #####: 1747: if (pinned_dir) { %%%%%: 1747-block 0 branch 0 never executed branch 1 never executed #####: 1748: free(pinned_dir); #####: 1749: pinned_dir = (char *)NULL; %%%%%: 1749-block 0 unconditional 0 never executed -: 1750: } -: 1751: #####: 1752: pinned_dir = savestring(line, strlen(line)); %%%%%: 1752-block 0 call 0 never executed #####: 1753: close_fstream(fp, fd); call 0 never executed #####: 1754: free(pin_file); #####: 1755: return EXIT_SUCCESS; unconditional 0 never executed -: 1756:} -: 1757: -: 1758:/* Get the list of files in PATH, plus CliFM internal commands, and send -: 1759: * them into an array to be read by my readline custom auto-complete -: 1760: * function (my_rl_completion) */ -: 1761:void function get_path_programs called 22 returned 100% blocks executed 94% 22: 1762:get_path_programs(void) -: 1763:{ 22: 1764: int i, j, l = 0, total_cmd = 0; 22: 1765: int *cmd_n = (int *)0; 22: 1766: struct dirent ***commands_bin = (struct dirent ***)NULL; -: 1767: 22: 1768: if (ext_cmd_ok) { 22: 1768-block 0 branch 0 taken 20 (fallthrough) branch 1 taken 2 20: 1769: char cwd[PATH_MAX] = ""; 20: 1770: if (getcwd(cwd, sizeof(cwd)) == NULL) {} 20: 1770-block 0 call 0 returned 20 -: 1771: 20: 1772: commands_bin = (struct dirent ***)xnmalloc( call 0 returned 20 -: 1773: path_n, sizeof(struct dirent)); 20: 1774: cmd_n = (int *)xnmalloc(path_n, sizeof(int)); call 0 returned 20 -: 1775: 20: 1776: i = (int)path_n; 140: 1777: while (--i >= 0) { unconditional 0 taken 20 140: 1777-block 0 branch 1 taken 120 branch 2 taken 20 (fallthrough) 120*: 1778: if (!paths[i] || !*paths[i] || xchdir(paths[i], NO_TITLE) == -1) { 120: 1778-block 0 branch 0 taken 120 (fallthrough) branch 1 taken 0 120: 1778-block 1 branch 2 taken 120 (fallthrough) branch 3 taken 0 120: 1778-block 2 call 4 returned 120 branch 5 taken 0 (fallthrough) branch 6 taken 120 #####: 1779: cmd_n[i] = 0; #####: 1780: continue; %%%%%: 1780-block 0 unconditional 0 never executed -: 1781: } -: 1782: 120*: 1783: cmd_n[i] = scandir(paths[i], &commands_bin[i], 120: 1783-block 0 unconditional 0 taken 120 %%%%%: 1783-block 1 unconditional 1 never executed 120: 1783-block 2 call 2 returned 120 120: 1784: light_mode ? NULL : skip_nonexec, xalphasort); 120: 1784-block 0 branch 0 taken 120 (fallthrough) branch 1 taken 0 -: 1785: /* If paths[i] directory does not exist, scandir returns -1. -: 1786: * Fedora, for example, adds $HOME/bin and $HOME/.local/bin to -: 1787: * PATH disregarding if they exist or not. If paths[i] dir is -: 1788: * empty do not use it either */ 120: 1789: if (cmd_n[i] > 0) branch 0 taken 120 (fallthrough) branch 1 taken 0 120: 1790: total_cmd += cmd_n[i]; 120: 1790-block 0 unconditional 0 taken 120 -: 1791: } 20: 1792: xchdir(cwd, NO_TITLE); 20: 1792-block 0 call 0 returned 20 -: 1793: } -: 1794: -: 1795: /* Add internal commands */ 22: 1796: size_t internal_cmd_n = 0; 1188: 1797: while (internal_cmds[internal_cmd_n]) 22: 1797-block 0 unconditional 0 taken 22 1188: 1797-block 1 branch 1 taken 1166 branch 2 taken 22 (fallthrough) 1166: 1798: internal_cmd_n++; 1166: 1798-block 0 unconditional 0 taken 1166 -: 1799: 44: 1800: bin_commands = (char **)xnmalloc((size_t)total_cmd + internal_cmd_n + 22: 1801: aliases_n + actions_n + 2, sizeof(char *)); 22: 1801-block 0 call 0 returned 22 -: 1802: 22: 1803: i = (int)internal_cmd_n; 1188: 1804: while (--i >= 0) unconditional 0 taken 22 1188: 1804-block 0 branch 1 taken 1166 branch 2 taken 22 (fallthrough) 1166: 1805: bin_commands[l++] = savestring(internal_cmds[i], 1166: 1805-block 0 call 0 returned 1166 unconditional 1 taken 1166 -: 1806: strlen(internal_cmds[i])); -: 1807: -: 1808: /* Now add aliases, if any */ 22: 1809: if (aliases_n) { 22: 1809-block 0 branch 0 taken 15 (fallthrough) branch 1 taken 7 15: 1810: i = (int)aliases_n; 90: 1811: while (--i >= 0) { 15: 1811-block 0 unconditional 0 taken 15 90: 1811-block 1 branch 1 taken 75 branch 2 taken 15 (fallthrough) 75: 1812: int index = strcntchr(aliases[i], '='); 75: 1812-block 0 call 0 returned 75 75: 1813: if (index != -1) { branch 0 taken 75 (fallthrough) branch 1 taken 0 75: 1814: bin_commands[l] = (char *)xnmalloc((size_t)index + 1, 75: 1814-block 0 call 0 returned 75 -: 1815: sizeof(char)); 75: 1816: xstrsncpy(bin_commands[l], aliases[i], (size_t)index); call 0 returned 75 75: 1817: bin_commands[l++][index] = '\0'; unconditional 0 taken 75 -: 1818: } -: 1819: } -: 1820: } -: 1821: -: 1822: /* And user defined actions too, if any */ 22: 1823: if (actions_n) { 22: 1823-block 0 branch 0 taken 20 (fallthrough) branch 1 taken 2 20: 1824: i = (int)actions_n; 448: 1825: while (--i >= 0) { 20: 1825-block 0 unconditional 0 taken 20 448: 1825-block 1 branch 1 taken 428 branch 2 taken 20 (fallthrough) 428: 1826: bin_commands[l++] = savestring(usr_actions[i].name, unconditional 0 taken 428 428: 1827: strlen(usr_actions[i].name)); 428: 1827-block 0 call 0 returned 428 -: 1828: } -: 1829: } -: 1830: 22: 1831: if (ext_cmd_ok && total_cmd) { 22: 1831-block 0 branch 0 taken 20 (fallthrough) branch 1 taken 2 20: 1831-block 1 branch 2 taken 20 (fallthrough) branch 3 taken 0 -: 1832: /* And finally, add commands in PATH */ 20: 1833: i = (int)path_n; 140: 1834: while (--i >= 0) { 20: 1834-block 0 unconditional 0 taken 20 140: 1834-block 1 branch 1 taken 120 branch 2 taken 20 (fallthrough) 120*: 1835: if (!cmd_n[i] || cmd_n[i] <= 0) 120: 1835-block 0 branch 0 taken 120 (fallthrough) branch 1 taken 0 120: 1835-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 120 #####: 1836: continue; %%%%%: 1836-block 0 unconditional 0 never executed -: 1837: 120: 1838: j = cmd_n[i]; 73403: 1839: while (--j >= 0) { 120: 1839-block 0 unconditional 0 taken 120 73403: 1839-block 1 branch 1 taken 73283 branch 2 taken 120 (fallthrough) 146566: 1840: bin_commands[l++] = savestring(commands_bin[i][j]->d_name, 73283: 1841: strlen(commands_bin[i][j]->d_name)); 73283: 1841-block 0 call 0 returned 73283 73283: 1842: free(commands_bin[i][j]); unconditional 0 taken 73283 -: 1843: } -: 1844: 120: 1845: free(commands_bin[i]); 120: 1845-block 0 unconditional 0 taken 120 -: 1846: } -: 1847: 20: 1848: free(commands_bin); 20: 1849: free(cmd_n); 20: 1849-block 0 unconditional 0 taken 20 -: 1850: } -: 1851: 22: 1852: path_progsn = (size_t)l; 22: 1853: bin_commands[l] = (char *)NULL; 22: 1854:} -: 1855: -: 1856:void function get_aliases called 24 returned 100% blocks executed 64% 24: 1857:get_aliases(void) -: 1858:{ 24: 1859: if (!config_ok) 24: 1859-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 24 #####: 1860: return; %%%%%: 1860-block 0 unconditional 0 never executed %%%%%: 1860-block 1 unconditional 1 never executed -: 1861: -: 1862: int fd; 24: 1863: FILE *fp = open_fstream_r(config_file, &fd); 24: 1863-block 0 call 0 returned 24 24: 1864: if (!fp) { branch 0 taken 0 (fallthrough) branch 1 taken 24 #####: 1865: _err('e', PRINT_PROMPT, "%s: alias: '%s': %s\n", call 0 never executed #####: 1866: PROGRAM_NAME, config_file, strerror(errno)); %%%%%: 1866-block 0 call 0 never executed #####: 1867: return; unconditional 0 never executed -: 1868: } -: 1869: 24: 1870: if (aliases_n) { 24: 1870-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 24 #####: 1871: int i = (int)aliases_n; #####: 1872: while (--i >= 0) %%%%%: 1872-block 0 unconditional 0 never executed %%%%%: 1872-block 1 branch 1 never executed branch 2 never executed #####: 1873: free(aliases[i]); %%%%%: 1873-block 0 unconditional 0 never executed #####: 1874: free(aliases); #####: 1875: aliases = (char **)NULL; #####: 1876: aliases_n = 0; %%%%%: 1876-block 0 unconditional 0 never executed -: 1877: } -: 1878: 24: 1879: char *line = (char *)NULL; 24: 1880: size_t line_size = 0; -: 1881: 6179: 1882: while (getline(&line, &line_size, fp) > 0) { 24: 1882-block 0 unconditional 0 taken 24 6179: 1882-block 1 call 1 returned 6179 branch 2 taken 6155 branch 3 taken 24 (fallthrough) 6155: 1883: if (*line == 'a' && strncmp(line, "alias ", 6) == 0) { 6155: 1883-block 0 branch 0 taken 85 (fallthrough) branch 1 taken 6070 85: 1883-block 1 branch 2 taken 85 (fallthrough) branch 3 taken 0 85: 1884: char *alias_line = strchr(line, ' '); 85: 1885: if (alias_line) { 85: 1885-block 0 branch 0 taken 85 (fallthrough) branch 1 taken 0 85: 1886: alias_line++; 85: 1887: aliases = (char **)xrealloc(aliases, (aliases_n + 1) 85: 1887-block 0 call 0 returned 85 -: 1888: * sizeof(char *)); 85: 1889: aliases[aliases_n++] = savestring(alias_line, call 0 returned 85 unconditional 1 taken 85 -: 1890: strlen(alias_line)); -: 1891: } -: 1892: } -: 1893: } -: 1894: 24: 1895: free(line); 24: 1896: close_fstream(fp, fd); 24: 1896-block 0 call 0 returned 24 -: 1897:} -: 1898: -: 1899:int function load_dirhist called 24 returned 100% blocks executed 86% 24: 1900:load_dirhist(void) -: 1901:{ 24: 1902: if (!config_ok) 24: 1902-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 24 #####: 1903: return EXIT_FAILURE; %%%%%: 1903-block 0 unconditional 0 never executed -: 1904: -: 1905: int fd; 24: 1906: FILE *fp = open_fstream_r(dirhist_file, &fd); 24: 1906-block 0 call 0 returned 24 24: 1907: if (!fp) branch 0 taken 2 (fallthrough) branch 1 taken 22 2: 1908: return EXIT_FAILURE; 2: 1908-block 0 unconditional 0 taken 2 -: 1909: 22: 1910: size_t dirs = 0; -: 1911: -: 1912: char tmp_line[PATH_MAX]; 2069: 1913: while (fgets(tmp_line, (int)sizeof(tmp_line), fp)) 22: 1913-block 0 unconditional 0 taken 22 2069: 1913-block 1 call 1 returned 2069 branch 2 taken 2047 branch 3 taken 22 (fallthrough) 2047: 1914: dirs++; 2047: 1914-block 0 unconditional 0 taken 2047 -: 1915: 22: 1916: if (!dirs) { 22: 1916-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 22 #####: 1917: close_fstream(fp, fd); %%%%%: 1917-block 0 call 0 never executed #####: 1918: return EXIT_SUCCESS; unconditional 0 never executed -: 1919: } -: 1920: 22: 1921: old_pwd = (char **)xnmalloc(dirs + 2, sizeof(char *)); 22: 1921-block 0 call 0 returned 22 -: 1922: 22: 1923: fseek(fp, 0L, SEEK_SET); call 0 returned 22 -: 1924: 22: 1925: size_t line_size = 0; 22: 1926: char *line = (char *)NULL; 22: 1927: ssize_t line_len = 0; -: 1928: 22: 1929: dirhist_total_index = 0; -: 1930: 2069: 1931: while ((line_len = getline(&line, &line_size, fp)) > 0) { unconditional 0 taken 22 2069: 1931-block 0 call 1 returned 2069 branch 2 taken 2047 branch 3 taken 22 (fallthrough) 2047*: 1932: if (!line || !*line || *line == '\n') 2047: 1932-block 0 branch 0 taken 2047 (fallthrough) branch 1 taken 0 2047: 1932-block 1 branch 2 taken 2047 (fallthrough) branch 3 taken 0 2047: 1932-block 2 branch 4 taken 0 (fallthrough) branch 5 taken 2047 #####: 1933: continue; %%%%%: 1933-block 0 unconditional 0 never executed 2047: 1934: if (line[line_len - 1] == '\n') 2047: 1934-block 0 branch 0 taken 2047 (fallthrough) branch 1 taken 0 2047: 1935: line[line_len - 1] = '\0'; 2047: 1935-block 0 unconditional 0 taken 2047 2047: 1936: old_pwd[dirhist_total_index] = (char *)xnmalloc((size_t)line_len + 1, 2047: 1936-block 0 call 0 returned 2047 -: 1937: sizeof(char)); 2047: 1938: strcpy(old_pwd[dirhist_total_index++], line); unconditional 0 taken 2047 -: 1939: } -: 1940: 22: 1941: close_fstream(fp, fd); 22: 1941-block 0 call 0 returned 22 22: 1942: old_pwd[dirhist_total_index] = (char *)NULL; 22: 1943: free(line); 22: 1944: dirhist_cur_index = dirhist_total_index - 1; 22: 1945: return EXIT_SUCCESS; unconditional 0 taken 22 -: 1946:} -: 1947: -: 1948:void function get_prompt_cmds called 24 returned 100% blocks executed 68% 24: 1949:get_prompt_cmds(void) -: 1950:{ 24: 1951: if (!config_ok) 24: 1951-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 24 #####: 1952: return; %%%%%: 1952-block 0 unconditional 0 never executed %%%%%: 1952-block 1 unconditional 1 never executed -: 1953: -: 1954: int fd; 24: 1955: FILE *fp = open_fstream_r(config_file, &fd); 24: 1955-block 0 call 0 returned 24 24: 1956: if (!fp) { branch 0 taken 0 (fallthrough) branch 1 taken 24 #####: 1957: _err('e', PRINT_PROMPT, "%s: prompt: '%s': %s\n", call 0 never executed #####: 1958: PROGRAM_NAME, config_file, strerror(errno)); %%%%%: 1958-block 0 call 0 never executed #####: 1959: return; unconditional 0 never executed -: 1960: } -: 1961: 24: 1962: if (prompt_cmds_n) { 24: 1962-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 24 -: 1963: size_t i; #####: 1964: for (i = 0; i < prompt_cmds_n; i++) %%%%%: 1964-block 0 unconditional 0 never executed %%%%%: 1964-block 1 branch 1 never executed branch 2 never executed #####: 1965: free(prompt_cmds[i]); %%%%%: 1965-block 0 unconditional 0 never executed #####: 1966: free(prompt_cmds); #####: 1967: prompt_cmds = (char **)NULL; #####: 1968: prompt_cmds_n = 0; %%%%%: 1968-block 0 unconditional 0 never executed -: 1969: } -: 1970: 24: 1971: int prompt_line_found = 0; 24: 1972: char *line = (char *)NULL; 24: 1973: size_t line_size = 0; 24: 1974: ssize_t line_len = 0; -: 1975: 6148: 1976: while ((line_len = getline(&line, &line_size, fp)) > 0) { 24: 1976-block 0 unconditional 0 taken 24 6148: 1976-block 1 call 1 returned 6148 branch 2 taken 6148 branch 3 taken 0 (fallthrough) 6148: 1977: if (prompt_line_found) { 6148: 1977-block 0 branch 0 taken 165 (fallthrough) branch 1 taken 5983 165: 1978: if (strncmp(line, "#END OF PROMPT", 14) == 0) 165: 1978-block 0 branch 0 taken 24 (fallthrough) branch 1 taken 141 24: 1979: break; 24: 1979-block 0 unconditional 0 taken 24 141: 1980: if (*line != '#') { 141: 1980-block 0 branch 0 taken 65 (fallthrough) branch 1 taken 76 130: 1981: prompt_cmds = (char **)xrealloc(prompt_cmds, 65: 1982: (prompt_cmds_n + 1) * sizeof(char *)); 65: 1982-block 0 call 0 returned 65 65: 1983: prompt_cmds[prompt_cmds_n++] = savestring( call 0 returned 65 unconditional 1 taken 65 -: 1984: line, (size_t)line_len); -: 1985: } 5983: 1986: } else if (strncmp(line, "#PROMPT", 7) == 0) { 5983: 1986-block 0 branch 0 taken 24 (fallthrough) branch 1 taken 5959 24: 1987: prompt_line_found = 1; 24: 1987-block 0 unconditional 0 taken 24 -: 1988: } -: 1989: } -: 1990: 24: 1991: free(line); 24: 1992: close_fstream(fp, fd); 24: 1992-block 0 call 0 returned 24 -: 1993:} -: 1994: -: 1995:/* If some option was not set, set it to the default value */ -: 1996:void function check_options called 24 returned 100% blocks executed 56% 24: 1997:check_options(void) -: 1998:{ 24: 1999: if (!usr_cscheme) 24: 1999-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 23 1: 2000: usr_cscheme = savestring("default", 7); 1: 2000-block 0 call 0 returned 1 unconditional 1 taken 1 -: 2001: -: 2002: /* Do no override command line options */ 24: 2003: if (xargs.cwd_in_title == UNSET) 24: 2003-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 22 2: 2004: xargs.cwd_in_title = DEF_CWD_IN_TITLE; 2: 2004-block 0 unconditional 0 taken 2 -: 2005: 24: 2006: if (cp_cmd == UNSET) 24: 2006-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 24 #####: 2007: cp_cmd = DEF_CP_CMD; %%%%%: 2007-block 0 unconditional 0 never executed -: 2008: 24: 2009: if (check_cap == UNSET) 24: 2009-block 0 branch 0 taken 24 (fallthrough) branch 1 taken 0 24: 2010: check_cap = DEF_CHECK_CAP; 24: 2010-block 0 unconditional 0 taken 24 -: 2011: 24: 2012: if (check_ext == UNSET) 24: 2012-block 0 branch 0 taken 24 (fallthrough) branch 1 taken 0 24: 2013: check_ext = DEF_CHECK_EXT; 24: 2013-block 0 unconditional 0 taken 24 -: 2014: 24: 2015: if (follow_symlinks == UNSET) 24: 2015-block 0 branch 0 taken 24 (fallthrough) branch 1 taken 0 24: 2016: follow_symlinks = DEF_FOLLOW_SYMLINKS; 24: 2016-block 0 unconditional 0 taken 24 -: 2017: 24: 2018: if (mv_cmd == UNSET) 24: 2018-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 24 #####: 2019: mv_cmd = DEF_MV_CMD; %%%%%: 2019-block 0 unconditional 0 never executed -: 2020: 24: 2021: if (min_name_trim == UNSET) 24: 2021-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 23 1: 2022: min_name_trim = DEF_MIN_NAME_TRIM; 1: 2022-block 0 unconditional 0 taken 1 -: 2023: 24: 2024: if (min_jump_rank == UNSET) 24: 2024-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 22 2: 2025: min_jump_rank = DEF_MIN_JUMP_RANK; 2: 2025-block 0 unconditional 0 taken 2 -: 2026: 24: 2027: if (max_jump_total_rank == UNSET) 24: 2027-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 22 2: 2028: max_jump_total_rank = DEF_MAX_JUMP_TOTAL_RANK; 2: 2028-block 0 unconditional 0 taken 2 -: 2029: 24: 2030: if (no_eln == UNSET) { 24: 2030-block 0 branch 0 taken 24 (fallthrough) branch 1 taken 0 24: 2031: if (xargs.noeln == UNSET) 24: 2031-block 0 branch 0 taken 24 (fallthrough) branch 1 taken 0 24: 2032: no_eln = DEF_NOELN; 24: 2032-block 0 unconditional 0 taken 24 -: 2033: else #####: 2034: no_eln = xargs.noeln; %%%%%: 2034-block 0 unconditional 0 never executed -: 2035: } -: 2036: 24: 2037: if (prompt_style == UNSET) 24: 2037-block 0 branch 0 taken 6 (fallthrough) branch 1 taken 18 6: 2038: prompt_style = DEF_PROMPT_STYLE; 6: 2038-block 0 unconditional 0 taken 6 -: 2039: -: 2040:#ifndef _NO_HIGHLIGHT 24: 2041: if (highlight == UNSET) { 24: 2041-block 0 branch 0 taken 7 (fallthrough) branch 1 taken 17 7: 2042: if (xargs.highlight == UNSET) 7: 2042-block 0 branch 0 taken 7 (fallthrough) branch 1 taken 0 7: 2043: highlight = DEF_HIGHLIGHT; 7: 2043-block 0 unconditional 0 taken 7 -: 2044: else #####: 2045: highlight = xargs.highlight; %%%%%: 2045-block 0 unconditional 0 never executed -: 2046: } -: 2047:#endif -: 2048: -: 2049:#ifndef _NO_SUGGESTIONS 24: 2050: if (suggestions == UNSET) { 24: 2050-block 0 branch 0 taken 6 (fallthrough) branch 1 taken 18 6: 2051: if (xargs.suggestions == UNSET) 6: 2051-block 0 branch 0 taken 6 (fallthrough) branch 1 taken 0 6: 2052: suggestions = DEF_SUGGESTIONS; 6: 2052-block 0 unconditional 0 taken 6 -: 2053: else #####: 2054: suggestions = xargs.suggestions; %%%%%: 2054-block 0 unconditional 0 never executed -: 2055: } -: 2056: 24: 2057: if (!suggestion_strategy) 24: 2057-block 0 branch 0 taken 6 (fallthrough) branch 1 taken 18 6: 2058: suggestion_strategy = savestring(DEF_SUG_STRATEGY, SUG_STRATS); 6: 2058-block 0 call 0 returned 6 unconditional 1 taken 6 -: 2059: 24: 2060: if (suggest_filetype_color == UNSET) 24: 2060-block 0 branch 0 taken 6 (fallthrough) branch 1 taken 18 6: 2061: suggest_filetype_color = DEF_SUG_FILETYPE_COLOR; 6: 2061-block 0 unconditional 0 taken 6 -: 2062:#endif -: 2063: 24: 2064: if (print_selfiles == UNSET) { 24: 2064-block 0 branch 0 taken 5 (fallthrough) branch 1 taken 19 5: 2065: if (xargs.printsel == UNSET) 5: 2065-block 0 branch 0 taken 5 (fallthrough) branch 1 taken 0 5: 2066: print_selfiles = DEF_PRINTSEL; 5: 2066-block 0 unconditional 0 taken 5 -: 2067: else #####: 2068: print_selfiles = xargs.printsel; %%%%%: 2068-block 0 unconditional 0 never executed -: 2069: } -: 2070: 24: 2071: if (max_printselfiles == UNSET) 24: 2071-block 0 branch 0 taken 5 (fallthrough) branch 1 taken 19 5: 2072: max_printselfiles = DEF_MAXPRINTSEL; 5: 2072-block 0 unconditional 0 taken 5 -: 2073: 24: 2074: if (case_sens_dirjump == UNSET) { 24: 2074-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 22 2: 2075: if (xargs.case_sens_dirjump == UNSET) 2: 2075-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 0 2: 2076: case_sens_dirjump = DEF_CASE_SENS_DIRJUMP; 2: 2076-block 0 unconditional 0 taken 2 -: 2077: else #####: 2078: case_sens_dirjump = xargs.case_sens_dirjump; %%%%%: 2078-block 0 unconditional 0 never executed -: 2079: } -: 2080: 24: 2081: if (case_sens_path_comp == UNSET) { 24: 2081-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 22 2: 2082: if (xargs.case_sens_path_comp == UNSET) 2: 2082-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 0 2: 2083: case_sens_path_comp = DEF_CASE_SENS_PATH_COMP; 2: 2083-block 0 unconditional 0 taken 2 -: 2084: else #####: 2085: case_sens_path_comp = xargs.case_sens_path_comp; %%%%%: 2085-block 0 unconditional 0 never executed -: 2086: } -: 2087:#ifndef _NO_TRASH 24: 2088: if (tr_as_rm == UNSET) { 24: 2088-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 23 1: 2089: if (xargs.trasrm == UNSET) 1: 2089-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 0 1: 2090: tr_as_rm = DEF_TRASRM; 1: 2090-block 0 unconditional 0 taken 1 -: 2091: else #####: 2092: tr_as_rm = xargs.trasrm; %%%%%: 2092-block 0 unconditional 0 never executed -: 2093: } -: 2094:#endif 24*: 2095: if (xargs.stealth_mode == 1 && !opener) 24: 2095-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 24 %%%%%: 2095-block 1 branch 2 never executed branch 3 never executed #####: 2096: opener = savestring(FALLBACK_OPENER, strlen(FALLBACK_OPENER)); %%%%%: 2096-block 0 call 0 never executed unconditional 1 never executed -: 2097: 24: 2098: if (only_dirs == UNSET) { 24: 2098-block 0 branch 0 taken 4 (fallthrough) branch 1 taken 20 4: 2099: if (xargs.only_dirs == UNSET) 4: 2099-block 0 branch 0 taken 4 (fallthrough) branch 1 taken 0 4: 2100: only_dirs = DEF_ONLY_DIRS; 4: 2100-block 0 unconditional 0 taken 4 -: 2101: else #####: 2102: only_dirs = xargs.only_dirs; %%%%%: 2102-block 0 unconditional 0 never executed -: 2103: } -: 2104: 24: 2105: if (colorize == UNSET) { 24: 2105-block 0 branch 0 taken 4 (fallthrough) branch 1 taken 20 4: 2106: if (xargs.no_colors == UNSET) 4: 2106-block 0 branch 0 taken 4 (fallthrough) branch 1 taken 0 4: 2107: colorize = DEF_COLORS; 4: 2107-block 0 unconditional 0 taken 4 -: 2108: else #####: 2109: colorize = xargs.no_colors; %%%%%: 2109-block 0 unconditional 0 never executed -: 2110: } -: 2111: 24: 2112: if (expand_bookmarks == UNSET) { 24: 2112-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 24 #####: 2113: if (xargs.expand_bookmarks == UNSET) %%%%%: 2113-block 0 branch 0 never executed branch 1 never executed #####: 2114: expand_bookmarks = DEF_EXPAND_BOOKMARKS; %%%%%: 2114-block 0 unconditional 0 never executed -: 2115: else #####: 2116: expand_bookmarks = xargs.expand_bookmarks; %%%%%: 2116-block 0 unconditional 0 never executed -: 2117: } -: 2118: 24: 2119: if (splash_screen == UNSET) { 24: 2119-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 24 #####: 2120: if (xargs.splash == UNSET) %%%%%: 2120-block 0 branch 0 never executed branch 1 never executed #####: 2121: splash_screen = DEF_SPLASH_SCREEN; %%%%%: 2121-block 0 unconditional 0 never executed -: 2122: else #####: 2123: splash_screen = xargs.splash; %%%%%: 2123-block 0 unconditional 0 never executed -: 2124: } -: 2125: 24: 2126: if (welcome_message == UNSET) { 24: 2126-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 24 #####: 2127: if (xargs.welcome_message == UNSET) %%%%%: 2127-block 0 branch 0 never executed branch 1 never executed #####: 2128: welcome_message = DEF_WELCOME_MESSAGE; %%%%%: 2128-block 0 unconditional 0 never executed -: 2129: else #####: 2130: welcome_message = xargs.welcome_message; %%%%%: 2130-block 0 unconditional 0 never executed -: 2131: } -: 2132: 24: 2133: if (show_hidden == UNSET) { 24: 2133-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 24 #####: 2134: if (xargs.hidden == UNSET) %%%%%: 2134-block 0 branch 0 never executed branch 1 never executed #####: 2135: show_hidden = DEF_SHOW_HIDDEN; %%%%%: 2135-block 0 unconditional 0 never executed -: 2136: else #####: 2137: show_hidden = xargs.hidden; %%%%%: 2137-block 0 unconditional 0 never executed -: 2138: } -: 2139: 24: 2140: if (files_counter == UNSET) { 24: 2140-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 23 1: 2141: if (xargs.files_counter == UNSET) 1: 2141-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 0 1: 2142: files_counter = DEF_FILES_COUNTER; 1: 2142-block 0 unconditional 0 taken 1 -: 2143: else #####: 2144: files_counter = xargs.files_counter; %%%%%: 2144-block 0 unconditional 0 never executed -: 2145: } -: 2146: 24: 2147: if (long_view == UNSET) { 24: 2147-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 24 #####: 2148: if (xargs.longview == UNSET) %%%%%: 2148-block 0 branch 0 never executed branch 1 never executed #####: 2149: long_view = DEF_LONG_VIEW; %%%%%: 2149-block 0 unconditional 0 never executed -: 2150: else #####: 2151: long_view = xargs.longview; %%%%%: 2151-block 0 unconditional 0 never executed -: 2152: } -: 2153: 24: 2154: if (ext_cmd_ok == UNSET) { 24: 2154-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 24 #####: 2155: if (xargs.ext == UNSET) %%%%%: 2155-block 0 branch 0 never executed branch 1 never executed #####: 2156: ext_cmd_ok = DEF_EXT_CMD_OK; %%%%%: 2156-block 0 unconditional 0 never executed -: 2157: else #####: 2158: ext_cmd_ok = xargs.ext; %%%%%: 2158-block 0 unconditional 0 never executed -: 2159: } -: 2160: 24: 2161: if (pager == UNSET) { 24: 2161-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 24 #####: 2162: if (xargs.pager == UNSET) %%%%%: 2162-block 0 branch 0 never executed branch 1 never executed #####: 2163: pager = DEF_PAGER; %%%%%: 2163-block 0 unconditional 0 never executed -: 2164: else #####: 2165: pager = xargs.pager; %%%%%: 2165-block 0 unconditional 0 never executed -: 2166: } -: 2167: 24: 2168: if (max_dirhist == UNSET) { 24: 2168-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 24 #####: 2169: if (xargs.max_dirhist == UNSET) %%%%%: 2169-block 0 branch 0 never executed branch 1 never executed #####: 2170: max_dirhist = DEF_MAX_DIRHIST; %%%%%: 2170-block 0 unconditional 0 never executed -: 2171: else #####: 2172: max_dirhist = xargs.max_dirhist; %%%%%: 2172-block 0 unconditional 0 never executed -: 2173: } -: 2174: 24: 2175: if (clear_screen == UNSET) { 24: 2175-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 24 #####: 2176: if (xargs.clear_screen == UNSET) %%%%%: 2176-block 0 branch 0 never executed branch 1 never executed #####: 2177: clear_screen = DEF_CLEAR_SCREEN; %%%%%: 2177-block 0 unconditional 0 never executed -: 2178: else #####: 2179: clear_screen = xargs.clear_screen; %%%%%: 2179-block 0 unconditional 0 never executed -: 2180: } -: 2181: 24: 2182: if (list_folders_first == UNSET) { 24: 2182-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 24 #####: 2183: if (xargs.ffirst == UNSET) %%%%%: 2183-block 0 branch 0 never executed branch 1 never executed #####: 2184: list_folders_first = DEF_LIST_FOLDERS_FIRST; %%%%%: 2184-block 0 unconditional 0 never executed -: 2185: else #####: 2186: list_folders_first = xargs.ffirst; %%%%%: 2186-block 0 unconditional 0 never executed -: 2187: } -: 2188: 24: 2189: if (cd_lists_on_the_fly == UNSET) { 24: 2189-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 24 #####: 2190: if (xargs.cd_list_auto == UNSET) %%%%%: 2190-block 0 branch 0 never executed branch 1 never executed #####: 2191: cd_lists_on_the_fly = DEF_CD_LISTS_ON_THE_FLY; %%%%%: 2191-block 0 unconditional 0 never executed -: 2192: else #####: 2193: cd_lists_on_the_fly = xargs.cd_list_auto; %%%%%: 2193-block 0 unconditional 0 never executed -: 2194: } -: 2195: 24: 2196: if (case_sensitive == UNSET) { 24: 2196-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 24 #####: 2197: if (xargs.sensitive == UNSET) %%%%%: 2197-block 0 branch 0 never executed branch 1 never executed #####: 2198: case_sensitive = DEF_CASE_SENSITIVE; %%%%%: 2198-block 0 unconditional 0 never executed -: 2199: else #####: 2200: case_sensitive = xargs.sensitive; %%%%%: 2200-block 0 unconditional 0 never executed -: 2201: } -: 2202: 24: 2203: if (unicode == UNSET) { 24: 2203-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 24 #####: 2204: if (xargs.unicode == UNSET) %%%%%: 2204-block 0 branch 0 never executed branch 1 never executed #####: 2205: unicode = DEF_UNICODE; %%%%%: 2205-block 0 unconditional 0 never executed -: 2206: else #####: 2207: unicode = xargs.unicode; %%%%%: 2207-block 0 unconditional 0 never executed -: 2208: } -: 2209: 24: 2210: if (max_path == UNSET) { 24: 2210-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 24 #####: 2211: if (xargs.max_path == UNSET) %%%%%: 2211-block 0 branch 0 never executed branch 1 never executed #####: 2212: max_path = DEF_MAX_PATH; %%%%%: 2212-block 0 unconditional 0 never executed -: 2213: else #####: 2214: max_path = xargs.max_path; %%%%%: 2214-block 0 unconditional 0 never executed -: 2215: } -: 2216: 24: 2217: if (logs_enabled == UNSET) { 24: 2217-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 24 #####: 2218: if (xargs.logs == UNSET) %%%%%: 2218-block 0 branch 0 never executed branch 1 never executed #####: 2219: logs_enabled = DEF_LOGS_ENABLED; %%%%%: 2219-block 0 unconditional 0 never executed -: 2220: else #####: 2221: logs_enabled = xargs.logs; %%%%%: 2221-block 0 unconditional 0 never executed -: 2222: } -: 2223: 24: 2224: if (light_mode == UNSET) { 24: 2224-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 23 1: 2225: if (xargs.light == UNSET) 1: 2225-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 0 1: 2226: light_mode = DEF_LIGHT_MODE; 1: 2226-block 0 unconditional 0 taken 1 -: 2227: else #####: 2228: light_mode = xargs.light; %%%%%: 2228-block 0 unconditional 0 never executed -: 2229: } -: 2230: 24: 2231: if (classify == UNSET) { 24: 2231-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 23 1: 2232: if (xargs.classify == UNSET) 1: 2232-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 0 1: 2233: classify = DEF_CLASSIFY; 1: 2233-block 0 unconditional 0 taken 1 -: 2234: else #####: 2235: classify = xargs.classify; %%%%%: 2235-block 0 unconditional 0 never executed -: 2236: } -: 2237: 24: 2238: if (share_selbox == UNSET) { 24: 2238-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 24 #####: 2239: if (xargs.share_selbox == UNSET) %%%%%: 2239-block 0 branch 0 never executed branch 1 never executed #####: 2240: share_selbox = DEF_SHARE_SELBOX; %%%%%: 2240-block 0 unconditional 0 never executed -: 2241: else #####: 2242: share_selbox = xargs.share_selbox; %%%%%: 2242-block 0 unconditional 0 never executed -: 2243: } -: 2244: 24: 2245: if (sort == UNSET) { 24: 2245-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 23 1: 2246: if (xargs.sort == UNSET) 1: 2246-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 0 1: 2247: sort = DEF_SORT; 1: 2247-block 0 unconditional 0 taken 1 -: 2248: else #####: 2249: sort = xargs.sort; %%%%%: 2249-block 0 unconditional 0 never executed -: 2250: } -: 2251: 24: 2252: if (sort_reverse == UNSET) { 24: 2252-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 24 #####: 2253: if (xargs.sort_reverse == UNSET) %%%%%: 2253-block 0 branch 0 never executed branch 1 never executed #####: 2254: sort_reverse = DEF_SORT_REVERSE; %%%%%: 2254-block 0 unconditional 0 never executed -: 2255: else #####: 2256: sort_reverse = xargs.sort_reverse; %%%%%: 2256-block 0 unconditional 0 never executed -: 2257: } -: 2258: 24: 2259: if (tips == UNSET) { 24: 2259-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 23 1: 2260: if (xargs.tips == UNSET) 1: 2260-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 0 1: 2261: tips = DEF_TIPS; 1: 2261-block 0 unconditional 0 taken 1 -: 2262: else #####: 2263: tips = xargs.tips; %%%%%: 2263-block 0 unconditional 0 never executed -: 2264: } -: 2265: 24: 2266: if (autocd == UNSET) { 24: 2266-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 23 1: 2267: if (xargs.autocd == UNSET) 1: 2267-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 0 1: 2268: autocd = DEF_AUTOCD; 1: 2268-block 0 unconditional 0 taken 1 -: 2269: else #####: 2270: autocd = xargs.autocd; %%%%%: 2270-block 0 unconditional 0 never executed -: 2271: } -: 2272: 24: 2273: if (auto_open == UNSET) { 24: 2273-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 23 1: 2274: if (xargs.auto_open == UNSET) 1: 2274-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 0 1: 2275: auto_open = DEF_AUTO_OPEN; 1: 2275-block 0 unconditional 0 taken 1 -: 2276: else #####: 2277: auto_open = xargs.auto_open; %%%%%: 2277-block 0 unconditional 0 never executed -: 2278: } -: 2279: 24: 2280: if (autojump == UNSET) { 24: 2280-block 0 branch 0 taken 7 (fallthrough) branch 1 taken 17 7: 2281: if (xargs.autojump == UNSET) 7: 2281-block 0 branch 0 taken 7 (fallthrough) branch 1 taken 0 7: 2282: autojump = DEF_AUTOJUMP; 7: 2282-block 0 unconditional 0 taken 7 -: 2283: else #####: 2284: autojump = xargs.autojump; %%%%%: 2284-block 0 unconditional 0 never executed 7: 2285: if (autojump == 1) 7: 2285-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 7 #####: 2286: autocd = 1; %%%%%: 2286-block 0 unconditional 0 never executed -: 2287: } -: 2288: 24: 2289: if (cd_on_quit == UNSET) { 24: 2289-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 23 1: 2290: if (xargs.cd_on_quit == UNSET) 1: 2290-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 0 1: 2291: cd_on_quit = DEF_CD_ON_QUIT; 1: 2291-block 0 unconditional 0 taken 1 -: 2292: else #####: 2293: cd_on_quit = xargs.cd_on_quit; %%%%%: 2293-block 0 unconditional 0 never executed -: 2294: } -: 2295: 24: 2296: if (dirhist_map == UNSET) { 24: 2296-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 23 1: 2297: if (xargs.dirmap == UNSET) 1: 2297-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 0 1: 2298: dirhist_map = DEF_DIRHIST_MAP; 1: 2298-block 0 unconditional 0 taken 1 -: 2299: else #####: 2300: dirhist_map = xargs.dirmap; %%%%%: 2300-block 0 unconditional 0 never executed -: 2301: } -: 2302: 24: 2303: if (disk_usage == UNSET) { 24: 2303-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 23 1: 2304: if (xargs.disk_usage == UNSET) 1: 2304-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 0 1: 2305: disk_usage = DEF_DISK_USAGE; 1: 2305-block 0 unconditional 0 taken 1 -: 2306: else #####: 2307: disk_usage = xargs.disk_usage; %%%%%: 2307-block 0 unconditional 0 never executed -: 2308: } -: 2309: 24: 2310: if (restore_last_path == UNSET) { 24: 2310-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 24 #####: 2311: if (xargs.restore_last_path == UNSET) %%%%%: 2311-block 0 branch 0 never executed branch 1 never executed #####: 2312: restore_last_path = DEF_RESTORE_LAST_PATH; %%%%%: 2312-block 0 unconditional 0 never executed -: 2313: else #####: 2314: restore_last_path = xargs.restore_last_path; %%%%%: 2314-block 0 unconditional 0 never executed -: 2315: } -: 2316: 24: 2317: if (!*div_line_char) { 24: 2317-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 24 #####: 2318: *div_line_char = DEF_DIV_LINE_CHAR; #####: 2319: div_line_char[1] = '\0'; %%%%%: 2319-block 0 unconditional 0 never executed -: 2320: } -: 2321: 24: 2322: if (max_hist == UNSET) 24: 2322-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 24 #####: 2323: max_hist = DEF_MAX_HIST; %%%%%: 2323-block 0 unconditional 0 never executed -: 2324: 24: 2325: if (max_log == UNSET) 24: 2325-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 24 #####: 2326: max_log = DEF_MAX_LOG; %%%%%: 2326-block 0 unconditional 0 never executed -: 2327: 24: 2328: if (!user.shell) { 24: 2328-block 0 branch 0 taken 7 (fallthrough) branch 1 taken 17 7: 2329: struct user_t tmp_user = get_user(); 7: 2329-block 0 call 0 returned 7 7: 2330: user.shell = tmp_user.shell; -: 2331: -: 2332: /* We don't need these values of the user struct: free(d) them */ 7: 2333: free(tmp_user.name); 7: 2334: free(tmp_user.home); -: 2335: 7: 2336: if (!user.shell) branch 0 taken 0 (fallthrough) branch 1 taken 7 #####: 2337: user.shell = savestring(FALLBACK_SHELL, strlen(FALLBACK_SHELL)); %%%%%: 2337-block 0 call 0 never executed unconditional 1 never executed -: 2338: } -: 2339: 24: 2340: if (!term) 24: 2340-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 24 #####: 2341: term = savestring(DEFAULT_TERM_CMD, strlen(DEFAULT_TERM_CMD)); %%%%%: 2341-block 0 call 0 never executed unconditional 1 never executed -: 2342: 24: 2343: if (!encoded_prompt) 24: 2343-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 24 #####: 2344: encoded_prompt = savestring(DEFAULT_PROMPT, strlen(DEFAULT_PROMPT)); %%%%%: 2344-block 0 call 0 never executed unconditional 1 never executed -: 2345: -: 2346: /* Since in stealth mode we have no access to the config file, we -: 2347: * cannot use 'lira', since it relays on a file. -: 2348: * Set it thus to xdg-open, if not already set via command line */ 24*: 2349: if (xargs.stealth_mode == 1 && !opener) 24: 2349-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 24 %%%%%: 2349-block 1 branch 2 never executed branch 3 never executed #####: 2350: opener = savestring(FALLBACK_OPENER, strlen(FALLBACK_OPENER)); %%%%%: 2350-block 0 call 0 never executed unconditional 1 never executed 24: 2351:} clifm-1.26.3/misc/codecov/jump.c.gcov000066400000000000000000001422061506632037700173440ustar00rootroot00000000000000 -: 0:Source:jump.c -: 1:/* jump.c -- functions for Kangaroo, the directory jumper function */ -: 2: -: 3:/* -: 4: * This file is part of CliFM -: 5: * -: 6: * Copyright (C) 2016-2021, L. Abramovich -: 7: * All rights reserved. -: 8: -: 9: * CliFM is free software; you can redistribute it and/or modify -: 10: * it under the terms of the GNU General Public License as published by -: 11: * the Free Software Foundation; either version 2 of the License, or -: 12: * (at your option) any later version. -: 13: * -: 14: * CliFM is distributed in the hope that it will be useful, -: 15: * but WITHOUT ANY WARRANTY; without even the implied warranty of -: 16: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -: 17: * GNU General Public License for more details. -: 18: * -: 19: * You should have received a copy of the GNU General Public License -: 20: * along with this program; if not, write to the Free Software -: 21: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, -: 22: * MA 02110-1301, USA. -: 23:*/ -: 24: -: 25:#include "helpers.h" -: 26: -: 27:#include -: 28:#include -: 29:#include -: 30:#include -: 31:#include -: 32: -: 33:#include "aux.h" -: 34:#include "checks.h" -: 35:#include "file_operations.h" -: 36:#include "init.h" -: 37:#include "navigation.h" -: 38:#include "messages.h" -: 39: -: 40:int function add_to_jumpdb called 74 returned 100% blocks executed 85% 74: 41:add_to_jumpdb(const char *dir) -: 42:{ 74: 43: if (xargs.no_dirjump == 1 || !dir || !*dir) 74: 43-block 0 branch 0 taken 74 (fallthrough) branch 1 taken 0 74: 43-block 1 branch 2 taken 74 (fallthrough) branch 3 taken 0 74: 43-block 2 branch 4 taken 0 (fallthrough) branch 5 taken 74 #####: 44: return EXIT_FAILURE; %%%%%: 44-block 0 unconditional 0 never executed -: 45: 74: 46: if (!jump_db) { 74: 46-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 74 #####: 47: jump_db = (struct jump_t *)xnmalloc(1, sizeof(struct jump_t)); %%%%%: 47-block 0 call 0 never executed #####: 48: jump_n = 0; unconditional 0 never executed -: 49: } -: 50: 74: 51: int i = (int)jump_n, new_entry = 1; 1826: 52: while (--i >= 0) { 74: 52-block 0 unconditional 0 taken 74 1826: 52-block 1 branch 1 taken 1816 branch 2 taken 10 (fallthrough) 1816: 53: if (dir[1] == jump_db[i].path[1] && strcmp(jump_db[i].path, dir) == 0) { 1816: 53-block 0 branch 0 taken 1261 (fallthrough) branch 1 taken 555 1261: 53-block 1 branch 2 taken 64 (fallthrough) branch 3 taken 1197 64: 54: jump_db[i].visits++; 64: 55: jump_db[i].last_visit = time(NULL); 64: 55-block 0 call 0 returned 64 64: 56: new_entry = 0; 64: 57: break; unconditional 0 taken 64 -: 58: } -: 59: } -: 60: 74: 61: if (!new_entry) 74: 61-block 0 branch 0 taken 64 (fallthrough) branch 1 taken 10 64: 62: return EXIT_SUCCESS; 64: 62-block 0 unconditional 0 taken 64 -: 63: 10: 64: jump_db = (struct jump_t *)xrealloc(jump_db, (jump_n + 2) * sizeof(struct jump_t)); 10: 64-block 0 call 0 returned 10 10: 65: jump_db[jump_n].visits = 1; 10: 66: time_t now = time(NULL); call 0 returned 10 10: 67: jump_db[jump_n].first_visit = now; 10: 68: jump_db[jump_n].last_visit = now; 10: 69: jump_db[jump_n].rank = 0; 10: 70: jump_db[jump_n].keep = 0; -: 71: 10: 72: jump_db[jump_n++].path = savestring(dir, strlen(dir)); call 0 returned 10 -: 73: 10: 74: jump_db[jump_n].path = (char *)NULL; 10: 75: jump_db[jump_n].visits = 0; 10: 76: jump_db[jump_n].rank = 0; 10: 77: jump_db[jump_n].keep = 0; 10: 78: jump_db[jump_n].first_visit = -1; 10: 79: jump_db[jump_n].last_visit = -1; -: 80: 10: 81: return EXIT_SUCCESS; unconditional 0 taken 10 -: 82:} -: 83: -: 84:/* Store the jump database into a file */ -: 85:void function save_jumpdb called 5 returned 100% blocks executed 93% 5: 86:save_jumpdb(void) -: 87:{ 5: 88: if (xargs.no_dirjump == 1 || !config_ok || !config_dir || !jump_db 5: 88-block 0 branch 0 taken 5 (fallthrough) branch 1 taken 0 5: 88-block 1 branch 2 taken 5 (fallthrough) branch 3 taken 0 5: 88-block 2 branch 4 taken 5 (fallthrough) branch 5 taken 0 5: 88-block 3 branch 6 taken 5 (fallthrough) branch 7 taken 0 5: 89: || jump_n == 0) 5: 89-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 5 #####: 90: return; %%%%%: 90-block 0 unconditional 0 never executed -: 91: 5: 92: char *jump_file = (char *)xnmalloc(strlen(config_dir) + 10, sizeof(char)); 5: 92-block 0 call 0 returned 5 5: 93: sprintf(jump_file, "%s/jump.cfm", config_dir); -: 94: 5: 95: FILE *fp = fopen(jump_file, "w+"); call 0 returned 5 5: 96: if (!fp) { branch 0 taken 0 (fallthrough) branch 1 taken 5 #####: 97: free(jump_file); #####: 98: return; %%%%%: 98-block 0 unconditional 0 never executed -: 99: } -: 100: 5: 101: int i, reduce = 0, tmp_rank = 0, total_rank = 0; 5: 102: time_t now = time(NULL); 5: 102-block 0 call 0 returned 5 -: 103: -: 104: /* Calculate both total rank sum and rank for each entry */ 5: 105: i = (int)jump_n; 195: 106: while (--i >= 0) { unconditional 0 taken 5 195: 106-block 0 branch 1 taken 190 branch 2 taken 5 (fallthrough) -: 107: 190: 108: int days_since_first = (int)(now - jump_db[i].first_visit) / 60 / 60 / 24; 191: 109: int rank = days_since_first > 1 ? ((int)jump_db[i].visits * 100) 190: 110: / days_since_first : ((int)jump_db[i].visits * 100); 190: 110-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 189 1: 110-block 1 unconditional 2 taken 1 189: 110-block 2 unconditional 3 taken 189 -: 111: 190: 112: int hours_since_last = (int)(now - jump_db[i].last_visit) / 60 / 60; -: 113: -: 114: /* Do not remove directories visited in the last 24 hours, no -: 115: * matter what their rank is */ 190: 116: tmp_rank = rank; 190: 117: if (hours_since_last == 0) { /* Last hour */ 190: 117-block 0 branch 0 taken 23 (fallthrough) branch 1 taken 167 23: 118: rank = JHOUR(tmp_rank); 23: 119: jump_db[i].keep = 1; 23: 119-block 0 unconditional 0 taken 23 167: 120: } else if (hours_since_last <= 24) { /* Last day */ 167: 120-block 0 branch 0 taken 134 (fallthrough) branch 1 taken 33 134: 121: rank = JDAY(tmp_rank); 134: 122: jump_db[i].keep = 1; 134: 122-block 0 unconditional 0 taken 134 33: 123: } else if (hours_since_last <= 168) { /* Last week */ 33: 123-block 0 branch 0 taken 32 (fallthrough) branch 1 taken 1 32: 124: rank = JWEEK(tmp_rank); 32: 124-block 0 unconditional 0 taken 32 -: 125: } else { /* More than a week */ 1: 126: rank = JOLDER(tmp_rank); 1: 126-block 0 unconditional 0 taken 1 -: 127: } -: 128: 190: 129: jump_db[i].rank = rank; -: 130: -: 131: /* Do not remove bookmarked, pinned, or workspaced directories */ -: 132: /* Add bonus points */ 190: 133: int j = (int)bm_n; 3900: 134: while (--j >= 0) { 190: 134-block 0 unconditional 0 taken 190 3900: 134-block 1 branch 1 taken 3758 branch 2 taken 142 (fallthrough) 3758: 135: if (bookmarks[j].path[1] == jump_db[i].path[1] 3758: 135-block 0 branch 0 taken 1564 (fallthrough) branch 1 taken 2194 1564: 136: && strcmp(bookmarks[j].path, jump_db[i].path) == 0) { 1564: 136-block 0 branch 0 taken 48 (fallthrough) branch 1 taken 1516 48: 137: jump_db[i].rank += BOOKMARK_BONUS; 48: 138: jump_db[i].keep = 1; 48: 139: break; 48: 139-block 0 unconditional 0 taken 48 -: 140: } -: 141: } -: 142: 190: 143: if (pinned_dir && pinned_dir[1] == jump_db[i].path[1] 190: 143-block 0 branch 0 taken 47 (fallthrough) branch 1 taken 143 47: 143-block 1 branch 2 taken 36 (fallthrough) branch 3 taken 11 36: 144: && strcmp(pinned_dir, jump_db[i].path) == 0) { 36: 144-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 36 #####: 145: jump_db[i].rank += PINNED_BONUS; #####: 146: jump_db[i].keep = 1; %%%%%: 146-block 0 unconditional 0 never executed -: 147: } -: 148: 190: 149: j = MAX_WS; 1669: 150: while (--j >= 0) { 190: 150-block 0 unconditional 0 taken 190 1669: 150-block 1 branch 1 taken 1496 branch 2 taken 173 (fallthrough) 1496: 151: if (ws[j].path && ws[j].path[1] == jump_db[i].path[1] 1496: 151-block 0 branch 0 taken 730 (fallthrough) branch 1 taken 766 730: 151-block 1 branch 2 taken 554 (fallthrough) branch 3 taken 176 554: 152: && strcmp(jump_db[i].path, ws[j].path) == 0) { 554: 152-block 0 branch 0 taken 17 (fallthrough) branch 1 taken 537 17: 153: jump_db[i].rank += WORKSPACE_BONUS; 17: 154: jump_db[i].keep = 1; 17: 155: break; 17: 155-block 0 unconditional 0 taken 17 -: 156: } -: 157: } -: 158: -: 159:/* jump_db[i].rank = rank; -: 160: total_rank += rank; */ 190: 161: total_rank += jump_db[i].rank; 190: 161-block 0 unconditional 0 taken 190 -: 162: } -: 163: -: 164: /* Once we have the total rank, check if we need to reduce ranks, -: 165: * and then write entries into the database */ 5: 166: if (total_rank > max_jump_total_rank) 5: 166-block 0 branch 0 taken 4 (fallthrough) branch 1 taken 1 4: 167: reduce = (total_rank / max_jump_total_rank) + 1; 4: 167-block 0 unconditional 0 taken 4 -: 168: 5: 169: int jump_num = 0; -: 170: 195: 171: for (i = 0; i < (int)jump_n; i++) { 5: 171-block 0 unconditional 0 taken 5 190: 171-block 1 unconditional 1 taken 190 195: 171-block 2 branch 2 taken 190 branch 3 taken 5 (fallthrough) 190: 172: if (total_rank > max_jump_total_rank) { 190: 172-block 0 branch 0 taken 188 (fallthrough) branch 1 taken 2 -: 173: /* Once we reach MAX_JUMP_TOTAL_RANK, start forgetting */ 188: 174: if (reduce) { 188: 174-block 0 branch 0 taken 188 (fallthrough) branch 1 taken 0 188: 175: tmp_rank = jump_db[i].rank; 188: 176: jump_db[i].rank = tmp_rank / reduce; 188: 176-block 0 unconditional 0 taken 188 -: 177: } -: 178: -: 179: /* Forget directories ranked below MIN_JUMP_RANK */ 188*: 180: if (jump_db[i].keep != 1 && jump_db[i].rank < min_jump_rank) { 188: 180-block 0 branch 0 taken 27 (fallthrough) branch 1 taken 161 27: 180-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 27 -: 181: /* Discount from TOTAL_RANK the rank of the now forgotten -: 182: * directory to keep this total up to date */ #####: 183: total_rank -= jump_db[i].rank; #####: 184: continue; %%%%%: 184-block 0 unconditional 0 never executed -: 185: } -: 186: } -: 187: 190: 188: jump_num++; -: 189:#ifndef __OpenBSD__ 190: 190: fprintf(fp, "%zu:%ld:%ld:%s\n", jump_db[i].visits, -: 191:#else -: 192: fprintf(fp, "%zu:%lld:%lld:%s\n", jump_db[i].visits, -: 193:#endif 190: 194: jump_db[i].first_visit, jump_db[i].last_visit, 190: 195: jump_db[i].path); 190: 195-block 0 call 0 returned 190 unconditional 1 taken 190 -: 196: } -: 197: 5: 198: fprintf(fp, "@%d\n", total_rank); 5: 198-block 0 call 0 returned 5 5: 199: fclose(fp); call 0 returned 5 5: 200: free(jump_file); unconditional 0 taken 5 -: 201:} -: 202: -: 203:int function edit_jumpdb called 1 returned 100% blocks executed 52% 1: 204:edit_jumpdb(void) -: 205:{ 1: 206: if (!config_ok || !config_dir) 1: 206-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 0 1: 206-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 1 #####: 207: return EXIT_FAILURE; %%%%%: 207-block 0 unconditional 0 never executed -: 208: 1: 209: save_jumpdb(); 1: 209-block 0 call 0 returned 1 -: 210: 1: 211: char *jump_file = (char *)xnmalloc(strlen(config_dir) + 10, call 0 returned 1 -: 212: sizeof(char)); 1: 213: sprintf(jump_file, "%s/jump.cfm", config_dir); -: 214: -: 215: struct stat attr; 1: 216: if (stat(jump_file, &attr) == -1) { call 0 returned 1 branch 1 taken 0 (fallthrough) branch 2 taken 1 #####: 217: fprintf(stderr, "%s: %s: %s\n", PROGRAM_NAME, jump_file, call 0 never executed #####: 218: strerror(errno)); %%%%%: 218-block 0 call 0 never executed #####: 219: free(jump_file); #####: 220: return EXIT_FAILURE; unconditional 0 never executed -: 221: } -: 222: 1: 223: time_t mtime_bfr = (time_t)attr.st_mtime; -: 224: 1: 225: char *cmd[] = {"o", jump_file, NULL}; 1: 226: open_function(cmd); 1: 226-block 0 call 0 returned 1 -: 227: 1: 228: stat(jump_file, &attr); call 0 returned 1 -: 229: 1: 230: if (mtime_bfr == (time_t)attr.st_mtime) { branch 0 taken 1 (fallthrough) branch 1 taken 0 1: 231: free(jump_file); 1: 232: return EXIT_SUCCESS; 1: 232-block 0 unconditional 0 taken 1 -: 233: } -: 234: #####: 235: if (jump_db) { %%%%%: 235-block 0 branch 0 never executed branch 1 never executed #####: 236: int i = (int)jump_n; -: 237: #####: 238: while (--i >= 0) %%%%%: 238-block 0 unconditional 0 never executed %%%%%: 238-block 1 branch 1 never executed branch 2 never executed #####: 239: free(jump_db[i].path); %%%%%: 239-block 0 unconditional 0 never executed -: 240: #####: 241: free(jump_db); #####: 242: jump_db = (struct jump_t *)NULL; #####: 243: jump_n = 0; %%%%%: 243-block 0 unconditional 0 never executed -: 244: } -: 245: #####: 246: load_jumpdb(); %%%%%: 246-block 0 call 0 never executed #####: 247: free(jump_file); #####: 248: return EXIT_SUCCESS; unconditional 0 never executed -: 249:} -: 250: -: 251:/* Save jump entry into the suggestions buffer */ -: 252:static int function save_suggestion called 16 returned 100% blocks executed 73% 16: 253:save_suggestion(char *str) -: 254:{ 16: 255: free(jump_suggestion); 16: 256: size_t len = strlen(str); -: 257: 16: 258: int slash = 0; 16: 259: if (str[len - 1] == '/') 16: 259-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 16 #####: 260: slash = 1; %%%%%: 260-block 0 unconditional 0 never executed -: 261: 16*: 262: jump_suggestion = xnmalloc(len + (slash ? 1 : 2), sizeof(char)); 16: 262-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 16 %%%%%: 262-block 1 unconditional 2 never executed 16: 262-block 2 unconditional 3 taken 16 16: 262-block 3 call 4 returned 16 16: 263: if (!slash) branch 0 taken 16 (fallthrough) branch 1 taken 0 16: 264: sprintf(jump_suggestion, "%s/", str); 16: 264-block 0 unconditional 0 taken 16 -: 265: else #####: 266: strcpy(jump_suggestion, str); %%%%%: 266-block 0 unconditional 0 never executed -: 267: 16: 268: return EXIT_SUCCESS; 16: 268-block 0 unconditional 0 taken 16 -: 269:} -: 270: -: 271:/* Jump into best ranked directory matched by ARGS */ -: 272:int function dirjump called 38 returned 100% blocks executed 71% 38: 273:dirjump(char **args, int mode) -: 274:{ -: 275:/* if (!args || !*args[0]) -: 276: return EXIT_FAILURE; */ -: 277: 38: 278: if (xargs.no_dirjump == 1) { 38: 278-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 38 #####: 279: printf(_("%s: Directory jumper function disabled\n"), PROGRAM_NAME); %%%%%: 279-block 0 call 0 never executed call 1 never executed #####: 280: return EXIT_FAILURE; unconditional 0 never executed -: 281: } -: 282: 38: 283: time_t now = time(NULL); 38: 283-block 0 call 0 returned 38 38: 284: int reduce = 0; -: 285: -: 286: /* If the sum total of ranks is greater than max, divide each entry -: 287: * to make the sum total less than or equal to max */ 38: 288: if (jump_total_rank > max_jump_total_rank) branch 0 taken 38 (fallthrough) branch 1 taken 0 38: 289: reduce = (jump_total_rank / max_jump_total_rank) + 1; 38: 289-block 0 unconditional 0 taken 38 -: 290: -: 291: /* If no parameter, print the list of entries in the jump -: 292: * database together with the corresponding information */ 38: 293: if (mode == NO_SUG_JUMP && !args[1] && args[0][1] != 'e') { 38: 293-block 0 branch 0 taken 8 (fallthrough) branch 1 taken 30 8: 293-block 1 branch 2 taken 3 (fallthrough) branch 3 taken 5 3: 293-block 2 branch 4 taken 2 (fallthrough) branch 5 taken 1 2: 294: if (!jump_n) { 2: 294-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 2 #####: 295: printf("%s: Database still empty\n", PROGRAM_NAME); %%%%%: 295-block 0 call 0 never executed #####: 296: return EXIT_SUCCESS; unconditional 0 never executed -: 297: } -: 298: 2: 299: puts(_("NOTE: First time access is displayed in days, while last " 2: 299-block 0 call 0 returned 2 call 1 returned 2 -: 300: "time access is displayed in hours")); 2: 301: puts(_("NOTE 2: An asterisk next rank values means that the " call 0 returned 2 call 1 returned 2 -: 302: "corresponding directory is bookmarked, pinned, or currently " -: 303: "used in some workspace\n")); 2: 304: puts(_("Order\tVisits\tFirst\tLast\tRank\tDirectory")); call 0 returned 2 call 1 returned 2 -: 305: -: 306: size_t i; 2: 307: int ranks_sum = 0, visits_sum = 0; -: 308: 96: 309: for (i = 0; i < jump_n; i++) { unconditional 0 taken 2 94: 309-block 0 unconditional 1 taken 94 96: 309-block 1 branch 2 taken 94 branch 3 taken 2 (fallthrough) -: 310: 94: 311: int days_since_first = (int)(now - jump_db[i].first_visit) / 60 / 60 / 24; 94: 312: int hours_since_last = (int)(now - jump_db[i].last_visit) / 60 / 60; -: 313: -: 314: int rank; 94: 315: rank = days_since_first > 1 #####: 316: ? ((int)jump_db[i].visits * 100) / days_since_first 94*: 317: : (int)jump_db[i].visits * 100; 94: 317-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 94 %%%%%: 317-block 1 unconditional 2 never executed 94: 317-block 2 unconditional 3 taken 94 -: 318: 94: 319: int tmp_rank = rank; 94: 320: if (hours_since_last == 0) /* Last hour */ 94: 320-block 0 branch 0 taken 4 (fallthrough) branch 1 taken 90 4: 321: rank = JHOUR(tmp_rank); 4: 321-block 0 unconditional 0 taken 4 90: 322: else if (hours_since_last <= 24) /* Last day */ 90: 322-block 0 branch 0 taken 68 (fallthrough) branch 1 taken 22 68: 323: rank = JDAY(tmp_rank); 68: 323-block 0 unconditional 0 taken 68 22: 324: else if (hours_since_last <= 168) /* Last week */ 22: 324-block 0 branch 0 taken 22 (fallthrough) branch 1 taken 0 22: 325: rank = JWEEK(tmp_rank); 22: 325-block 0 unconditional 0 taken 22 -: 326: else /* More than a week */ #####: 327: rank = JOLDER(tmp_rank); %%%%%: 327-block 0 unconditional 0 never executed -: 328: 94: 329: int j = (int)bm_n, bpw = 0; /* Bookmarked, pinned or workspace */ 1948: 330: while (--j >= 0) { 94: 330-block 0 unconditional 0 taken 94 1948: 330-block 1 branch 1 taken 1878 branch 2 taken 70 (fallthrough) 1878: 331: if (bookmarks[j].path[1] == jump_db[i].path[1] 1878: 331-block 0 branch 0 taken 782 (fallthrough) branch 1 taken 1096 782: 332: && strcmp(bookmarks[j].path, jump_db[i].path) == 0) { 782: 332-block 0 branch 0 taken 24 (fallthrough) branch 1 taken 758 24: 333: rank += BOOKMARK_BONUS; 24: 334: bpw = 1; 24: 335: break; 24: 335-block 0 unconditional 0 taken 24 -: 336: } -: 337: } -: 338: 94: 339: if (pinned_dir && pinned_dir[1] == jump_db[i].path[1] 94: 339-block 0 branch 0 taken 94 (fallthrough) branch 1 taken 0 94: 339-block 1 branch 2 taken 72 (fallthrough) branch 3 taken 22 72: 340: && strcmp(pinned_dir, jump_db[i].path) == 0) { 72: 340-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 72 #####: 341: rank += PINNED_BONUS; #####: 342: bpw = 1; %%%%%: 342-block 0 unconditional 0 never executed -: 343: } -: 344: 94: 345: j = MAX_WS; 826: 346: while (--j >= 0) { 94: 346-block 0 unconditional 0 taken 94 826: 346-block 1 branch 1 taken 740 branch 2 taken 86 (fallthrough) 740: 347: if (ws[j].path && ws[j].path[1] == jump_db[i].path[1] 740: 347-block 0 branch 0 taken 364 (fallthrough) branch 1 taken 376 364: 347-block 1 branch 2 taken 276 (fallthrough) branch 3 taken 88 276: 348: && strcmp(jump_db[i].path, ws[j].path) == 0) { 276: 348-block 0 branch 0 taken 8 (fallthrough) branch 1 taken 268 8: 349: rank += WORKSPACE_BONUS; 8: 350: bpw = 1; 8: 351: break; 8: 351-block 0 unconditional 0 taken 8 -: 352: } -: 353: } -: 354: 94: 355: if (reduce) { 94: 355-block 0 branch 0 taken 94 (fallthrough) branch 1 taken 0 94: 356: tmp_rank = rank; 94: 357: rank = tmp_rank / reduce; 94: 357-block 0 unconditional 0 taken 94 -: 358: } -: 359: 94: 360: ranks_sum += rank; 94: 361: visits_sum += (int)jump_db[i].visits; -: 362: 94: 363: if (ws[cur_ws].path[1] == jump_db[i].path[1] 94: 363-block 0 branch 0 taken 72 (fallthrough) branch 1 taken 22 72: 364: && strcmp(ws[cur_ws].path, jump_db[i].path) == 0) { 72: 364-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 70 2*: 365: printf(" %s%zu\t %zu\t %d\t %d\t%d%c\t%s%s \n", mi_c, 2: 365-block 0 unconditional 0 taken 2 %%%%%: 365-block 1 unconditional 1 never executed 2: 366: i + 1, jump_db[i].visits, days_since_first, 2: 366-block 0 call 0 returned 2 unconditional 1 taken 2 -: 367: hours_since_last, rank, bpw ? '*' : 0, 2: 368: jump_db[i].path, df_c); 2: 368-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 0 -: 369: } else { 92: 370: printf(" %zu\t %zu\t %d\t %d\t%d%c\t%s \n", i + 1, 28: 370-block 0 unconditional 0 taken 28 64: 370-block 1 unconditional 1 taken 64 92: 371: jump_db[i].visits, days_since_first, 92: 371-block 0 call 0 returned 92 unconditional 1 taken 92 -: 372: hours_since_last, rank, 92: 373: bpw ? '*' : 0, jump_db[i].path); 92: 373-block 0 branch 0 taken 28 (fallthrough) branch 1 taken 64 -: 374: } -: 375: } -: 376: 2: 377: printf("\nTotal rank: %d/%d\nTotal visits: %d\n", ranks_sum, 2: 377-block 0 call 0 returned 2 -: 378: max_jump_total_rank, visits_sum); -: 379: 2: 380: return EXIT_SUCCESS; unconditional 0 taken 2 -: 381: } -: 382: 36: 383: if (mode == NO_SUG_JUMP && args[1] && *args[1] == '-' 36: 383-block 0 branch 0 taken 6 (fallthrough) branch 1 taken 30 6: 383-block 1 branch 2 taken 5 (fallthrough) branch 3 taken 1 5: 383-block 2 branch 4 taken 1 (fallthrough) branch 5 taken 4 1: 384: && strcmp(args[1], "--help") == 0) { 1: 384-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 0 1: 385: puts(_(JUMP_USAGE)); 1: 385-block 0 call 0 returned 1 call 1 returned 1 1: 386: return EXIT_SUCCESS; unconditional 0 taken 1 -: 387: } -: 388: 35: 389: enum jump jump_opt = NONE; -: 390: 35: 391: switch (args[0][1]) { 35: 391-block 0 branch 0 taken 1 branch 1 taken 6 branch 2 taken 2 branch 3 taken 0 branch 4 taken 1 branch 5 taken 25 branch 6 taken 0 1: 392: case 'e': return edit_jumpdb(); 1: 392-block 0 call 0 returned 1 unconditional 1 taken 1 6: 393: case 'c': jump_opt = JCHILD; break; 6: 393-block 0 unconditional 0 taken 6 2: 394: case 'p': jump_opt = JPARENT; break; 2: 394-block 0 unconditional 0 taken 2 #####: 395: case 'o': jump_opt = JORDER; break; %%%%%: 395-block 0 unconditional 0 never executed 1: 396: case 'l': jump_opt = JLIST; break; 1: 396-block 0 unconditional 0 taken 1 25: 397: case '\0': jump_opt = NONE; break; 25: 397-block 0 unconditional 0 taken 25 #####: 398: default: #####: 399: fprintf(stderr, _("%s: '%c': Invalid option\n"), PROGRAM_NAME, call 0 never executed #####: 400: args[0][1]); %%%%%: 400-block 0 call 0 never executed #####: 401: fprintf(stderr, "%s\n", _(JUMP_USAGE)); call 0 never executed call 1 never executed #####: 402: return EXIT_FAILURE; unconditional 0 never executed -: 403: } -: 404: 34: 405: if (jump_opt == JORDER) { 34: 405-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 34 #####: 406: if (!args[1]) { %%%%%: 406-block 0 branch 0 never executed branch 1 never executed #####: 407: if (mode == NO_SUG_JUMP) %%%%%: 407-block 0 branch 0 never executed branch 1 never executed #####: 408: fprintf(stderr, "%s\n", _(JUMP_USAGE)); %%%%%: 408-block 0 call 0 never executed call 1 never executed unconditional 2 never executed #####: 409: return EXIT_FAILURE; %%%%%: 409-block 0 unconditional 0 never executed -: 410: } -: 411: #####: 412: if (!is_number(args[1])) { %%%%%: 412-block 0 call 0 never executed branch 1 never executed branch 2 never executed #####: 413: if (mode == NO_SUG_JUMP) %%%%%: 413-block 0 branch 0 never executed branch 1 never executed #####: 414: return cd_function(args[1], CD_PRINT_ERROR); %%%%%: 414-block 0 call 0 never executed unconditional 1 never executed -: 415: else #####: 416: return EXIT_FAILURE; %%%%%: 416-block 0 unconditional 0 never executed -: 417: } else { #####: 418: int int_order = atoi(args[1]); -: 419: #####: 420: if (int_order <= 0 || int_order > (int)jump_n) { %%%%%: 420-block 0 branch 0 never executed branch 1 never executed %%%%%: 420-block 1 branch 2 never executed branch 3 never executed #####: 421: if (mode == NO_SUG_JUMP) { %%%%%: 421-block 0 branch 0 never executed branch 1 never executed #####: 422: fprintf(stderr, _("%s: %d: No such order number\n"), %%%%%: 422-block 0 call 0 never executed call 1 never executed unconditional 2 never executed -: 423: PROGRAM_NAME, int_order); -: 424: } #####: 425: return EXIT_FAILURE; %%%%%: 425-block 0 unconditional 0 never executed -: 426: } -: 427: #####: 428: if (mode == NO_SUG_JUMP) %%%%%: 428-block 0 branch 0 never executed branch 1 never executed #####: 429: return cd_function(jump_db[int_order - 1].path, CD_PRINT_ERROR); %%%%%: 429-block 0 call 0 never executed unconditional 1 never executed #####: 430: return save_suggestion(jump_db[int_order - 1].path); %%%%%: 430-block 0 call 0 never executed unconditional 1 never executed -: 431: } -: 432: } -: 433: -: 434: /* If ARG is an actual directory, just cd into it */ -: 435: struct stat attr; 34: 436: if (args[1] && !args[2] && lstat(args[1], &attr) != -1) { 34: 436-block 0 branch 0 taken 34 (fallthrough) branch 1 taken 0 34: 436-block 1 branch 2 taken 34 (fallthrough) branch 3 taken 0 34: 436-block 2 call 4 returned 34 branch 5 taken 1 (fallthrough) branch 6 taken 33 1: 437: if (mode == NO_SUG_JUMP) 1: 437-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 0 1: 438: return cd_function(args[1], CD_PRINT_ERROR); 1: 438-block 0 call 0 returned 1 unconditional 1 taken 1 #####: 439: return save_suggestion(args[1]); %%%%%: 439-block 0 call 0 never executed unconditional 1 never executed -: 440: } -: 441: -: 442: /* Jump into a visited directory using ARGS as filter(s) */ -: 443: size_t i; 33: 444: int j, match = 0; 33: 445: char **matches = (char **)xnmalloc(jump_n + 1, sizeof(char *)); 33: 445-block 0 call 0 returned 33 33: 446: char **needles = (char **)xnmalloc(jump_n + 1, sizeof(char *)); call 0 returned 33 33: 447: size_t *visits = (size_t *)xnmalloc(jump_n + 1, sizeof(size_t)); call 0 returned 33 33: 448: time_t *first = (time_t *)xnmalloc(jump_n + 1, sizeof(time_t)); call 0 returned 33 33: 449: time_t *last = (time_t *)xnmalloc(jump_n + 1, sizeof(time_t)); call 0 returned 33 33: 450: int last_segment = 0, first_segment = 0; -: 451: 66: 452: for (i = 1; args[i]; i++) { unconditional 0 taken 33 33: 452-block 0 unconditional 1 taken 33 66: 452-block 1 branch 2 taken 33 branch 3 taken 33 (fallthrough) -: 453: /* 1) Using the first parameter, get a list of matches in the -: 454: * database */ -: 455: -: 456: /* If the query string ends with a slash, we want this query -: 457: * string to match only the last segment of the path (i.e., -: 458: * there must be no slash after the match) */ 33: 459: size_t _len = strlen(args[i]); 33: 460: if (args[i][_len - 1] == '/') { 33: 460-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 32 1: 461: args[i][_len - 1] = '\0'; 1: 462: last_segment = 1; 1: 463: first_segment = 0; 1: 463-block 0 unconditional 0 taken 1 32: 464: } else if (args[i][_len - 1] == '\\') { 32: 464-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 32 #####: 465: args[i][_len - 1] = '\0'; #####: 466: last_segment = 0; #####: 467: first_segment = 1; %%%%%: 467-block 0 unconditional 0 never executed -: 468: } else { 32: 469: last_segment = 0; 32: 470: first_segment = 0; 32: 470-block 0 unconditional 0 taken 32 -: 471: } -: 472: 33: 473: if (!match) { 33: 473-block 0 branch 0 taken 33 (fallthrough) branch 1 taken 0 33: 474: j = (int)jump_n; 1623: 475: while (--j >= 0) { 33: 475-block 0 unconditional 0 taken 33 1623: 475-block 1 branch 1 taken 1590 branch 2 taken 33 -: 476: /* Pointer to the beginning of the search str in the -: 477: * jump entry. Used to search for subsequent search -: 478: * strings starting from this position in the entry -: 479: * and not before */ 1590: 480: char *needle = case_sens_dirjump #####: 481: ? strstr(jump_db[j].path, args[i]) %%%%%: 481-block 0 unconditional 0 never executed 1590: 482: : strcasestr(jump_db[j].path, args[i]); 1590: 482-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 1590 1590: 482-block 1 unconditional 2 taken 1590 1590: 483: if (!needle || (last_segment && strchr(needle, '/'))) 1590: 483-block 0 branch 0 taken 561 (fallthrough) branch 1 taken 1029 561: 483-block 1 branch 2 taken 42 (fallthrough) branch 3 taken 519 42: 483-block 2 branch 4 taken 40 (fallthrough) branch 5 taken 2 1069: 484: continue; 1069: 484-block 0 unconditional 0 taken 1069 -: 485: 521: 486: if (first_segment) { 521: 486-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 521 #####: 487: char p = *needle; #####: 488: *needle = '\0'; #####: 489: if (strrchr(jump_db[j].path, '/') != jump_db[j].path) { %%%%%: 489-block 0 branch 0 never executed branch 1 never executed #####: 490: *needle = p; #####: 491: continue; %%%%%: 491-block 0 unconditional 0 never executed -: 492: } #####: 493: *needle = p; %%%%%: 493-block 0 unconditional 0 never executed -: 494: } -: 495: -: 496: /* Exclue CWD */ 521: 497: if (jump_db[j].path[1] == ws[cur_ws].path[1] 521: 497-block 0 branch 0 taken 490 (fallthrough) branch 1 taken 31 490: 498: && strcmp(jump_db[j].path, ws[cur_ws].path) == 0) 490: 498-block 0 branch 0 taken 16 (fallthrough) branch 1 taken 474 16: 499: continue; 16: 499-block 0 unconditional 0 taken 16 -: 500: 505: 501: int exclude = 0; -: 502: /* Filter matches according to parent or -: 503: * child options */ 505: 504: switch (jump_opt) { 505: 504-block 0 branch 0 taken 74 branch 1 taken 193 branch 2 taken 238 74: 505: case JPARENT: 74: 506: if (!strstr(ws[cur_ws].path, jump_db[j].path)) 74: 506-block 0 branch 0 taken 72 (fallthrough) branch 1 taken 2 72: 507: exclude = 1; 72: 507-block 0 unconditional 0 taken 72 74: 508: break; 74: 508-block 0 unconditional 0 taken 74 -: 509: 193: 510: case JCHILD: 193: 511: if (!strstr(jump_db[j].path, ws[cur_ws].path)) 193: 511-block 0 branch 0 taken 177 (fallthrough) branch 1 taken 16 177: 512: exclude = 1; 177: 512-block 0 unconditional 0 taken 177 -: 513: -: 514: case NONE: /* fallthrough */ 431: 515: default: break; 431: 515-block 0 unconditional 0 taken 431 -: 516: } -: 517: 505: 518: if (exclude) 505: 518-block 0 branch 0 taken 249 (fallthrough) branch 1 taken 256 249: 519: continue; 249: 519-block 0 unconditional 0 taken 249 -: 520: 256: 521: visits[match] = jump_db[j].visits; 256: 522: first[match] = jump_db[j].first_visit; 256: 523: last[match] = jump_db[j].last_visit; 256: 524: needles[match] = needle; 256: 525: matches[match++] = jump_db[j].path; 256: 525-block 0 unconditional 0 taken 256 -: 526: } -: 527: } -: 528: -: 529: /* 2) Once we have the list of matches, perform a reverse -: 530: * matching process, that is, excluding non-matches, -: 531: * using subsequent parameters */ -: 532: else { #####: 533: j = (int)match; #####: 534: while (--j >= 0) { %%%%%: 534-block 0 unconditional 0 never executed %%%%%: 534-block 1 branch 1 never executed branch 2 never executed #####: 535: if (!matches[j] || !*matches[j]) { %%%%%: 535-block 0 branch 0 never executed branch 1 never executed %%%%%: 535-block 1 branch 2 never executed branch 3 never executed #####: 536: matches[j] = (char *)NULL; #####: 537: continue; %%%%%: 537-block 0 unconditional 0 never executed -: 538: } -: 539: #####: 540: char *_needle = case_sens_dirjump #####: 541: ? strstr(needles[j] + 1, args[i]) %%%%%: 541-block 0 unconditional 0 never executed #####: 542: : strcasestr(needles[j] + 1, args[i]); %%%%%: 542-block 0 branch 0 never executed branch 1 never executed %%%%%: 542-block 1 unconditional 2 never executed -: 543: #####: 544: if (!_needle || (last_segment && strchr(_needle, '/'))){ %%%%%: 544-block 0 branch 0 never executed branch 1 never executed %%%%%: 544-block 1 branch 2 never executed branch 3 never executed %%%%%: 544-block 2 branch 4 never executed branch 5 never executed #####: 545: matches[j] = (char *)NULL; #####: 546: continue; %%%%%: 546-block 0 unconditional 0 never executed -: 547: } -: 548: #####: 549: if (first_segment) { %%%%%: 549-block 0 branch 0 never executed branch 1 never executed #####: 550: char p = *_needle; #####: 551: *_needle = '\0'; #####: 552: if (strrchr(matches[j], '/') != matches[j]) { %%%%%: 552-block 0 branch 0 never executed branch 1 never executed #####: 553: *_needle = p; #####: 554: matches[j] = (char *)NULL; #####: 555: continue; %%%%%: 555-block 0 unconditional 0 never executed -: 556: } #####: 557: *_needle = p; %%%%%: 557-block 0 unconditional 0 never executed -: 558: } -: 559: -: 560: /* Update the needle for the next search string */ #####: 561: needles[j] = _needle; %%%%%: 561-block 0 unconditional 0 never executed -: 562: } -: 563: } -: 564: } -: 565: -: 566: /* 3) If something remains, we have at least one match */ -: 567: -: 568: /* 4) Further filter the list of matches by frecency, so that only -: 569: * the best ranked directory will be returned */ -: 570: 33: 571: int found = 0, exit_status = EXIT_FAILURE, 33: 572: best_ranked = 0, max = -1, k; -: 573: 33: 574: j = match; 289: 575: while (--j >= 0) { 33: 575-block 0 unconditional 0 taken 33 289: 575-block 1 branch 1 taken 256 branch 2 taken 33 (fallthrough) 256*: 576: if (!matches[j]) 256: 576-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 256 #####: 577: continue; %%%%%: 577-block 0 unconditional 0 never executed -: 578: 256: 579: found = 1; -: 580: 256: 581: if (jump_opt == JLIST) { 256: 581-block 0 branch 0 taken 3 (fallthrough) branch 1 taken 253 3: 582: printf("%s\n", matches[j]); 3: 582-block 0 call 0 returned 3 unconditional 1 taken 3 -: 583: } else { 253: 584: int days_since_first = (int)(now - first[j]) / 60 / 60 / 24; -: 585: -: 586: /* Calculate the rank as frecency. The algorithm is based -: 587: * on Mozilla, zoxide, and z.lua. See: -: 588: * "https://wiki.mozilla.org/User:Mconnor/Past/PlacesFrecency" -: 589: * "https://github.com/ajeetdsouza/zoxide/wiki/Algorithm#aging" -: 590: * "https://github.com/skywind3000/z.lua#aging" */ -: 591: int rank; 367: 592: rank = days_since_first > 0 ? ((int)visits[j] * 100) 253: 593: / days_since_first : ((int)visits[j] * 100); 253: 593-block 0 branch 0 taken 114 (fallthrough) branch 1 taken 139 114: 593-block 1 unconditional 2 taken 114 139: 593-block 2 unconditional 3 taken 139 -: 594: 253: 595: int hours_since_last = (int)(now - last[j]) / 60 / 60; -: 596: -: 597: /* Credit or penalty based on last directory access */ 253: 598: int tmp_rank = rank; 253: 599: if (hours_since_last == 0) /* Last hour */ 253: 599-block 0 branch 0 taken 29 (fallthrough) branch 1 taken 224 29: 600: rank = JHOUR(tmp_rank); 29: 600-block 0 unconditional 0 taken 29 224: 601: else if (hours_since_last <= 24) /* Last day */ 224: 601-block 0 branch 0 taken 181 (fallthrough) branch 1 taken 43 181: 602: rank = JDAY(tmp_rank); 181: 602-block 0 unconditional 0 taken 181 43: 603: else if (hours_since_last <= 168) /* Last week */ 43: 603-block 0 branch 0 taken 43 (fallthrough) branch 1 taken 0 43: 604: rank = JWEEK(tmp_rank); 43: 604-block 0 unconditional 0 taken 43 -: 605: else /* More than a week */ #####: 606: rank = JOLDER(tmp_rank); %%%%%: 606-block 0 unconditional 0 never executed -: 607: -: 608: /* Matches in directory basename have extra credit */ 253: 609: char *tmp = strrchr(matches[j], '/'); 253: 610: if (tmp && *(++tmp)) { 253: 610-block 0 branch 0 taken 253 (fallthrough) branch 1 taken 0 253: 610-block 1 branch 2 taken 253 (fallthrough) branch 3 taken 0 253: 611: if (strstr(tmp, args[args_n])) 253: 611-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 252 1: 612: rank += BASENAME_BONUS; 1: 612-block 0 unconditional 0 taken 1 -: 613: } -: 614: -: 615: /* Bookmarked directories have extra credit */ 253: 616: k = (int)bm_n; 5387: 617: while (--k >= 0) { 253: 617-block 0 unconditional 0 taken 253 5387: 617-block 1 branch 1 taken 5187 branch 2 taken 200 (fallthrough) 5187: 618: if (bookmarks[k].path[1] == matches[j][1] 5187: 618-block 0 branch 0 taken 2489 (fallthrough) branch 1 taken 2698 2489: 619: && strcmp(bookmarks[k].path, matches[j]) == 0) { 2489: 619-block 0 branch 0 taken 53 (fallthrough) branch 1 taken 2436 53: 620: rank += BOOKMARK_BONUS; 53: 621: break; 53: 621-block 0 unconditional 0 taken 53 -: 622: } -: 623: } -: 624: 253: 625: if (pinned_dir && pinned_dir[1] == matches[j][1] 253: 625-block 0 branch 0 taken 253 (fallthrough) branch 1 taken 0 253: 625-block 1 branch 2 taken 237 (fallthrough) branch 3 taken 16 237: 626: && strcmp(pinned_dir, matches[j]) == 0) 237: 626-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 237 #####: 627: rank += PINNED_BONUS; %%%%%: 627-block 0 unconditional 0 never executed -: 628: 253: 629: k = MAX_WS; 2221: 630: while (--k >= 0) { 253: 630-block 0 unconditional 0 taken 253 2221: 630-block 1 branch 1 taken 1987 branch 2 taken 234 (fallthrough) 1987: 631: if (ws[k].path && ws[k].path[1] == matches[j][1] 1987: 631-block 0 branch 0 taken 975 (fallthrough) branch 1 taken 1012 975: 631-block 1 branch 2 taken 911 (fallthrough) branch 3 taken 64 911: 632: && strcmp(ws[k].path, matches[j]) == 0) { 911: 632-block 0 branch 0 taken 19 (fallthrough) branch 1 taken 892 19: 633: rank += WORKSPACE_BONUS; 19: 634: break; 19: 634-block 0 unconditional 0 taken 19 -: 635: } -: 636: } -: 637: 253: 638: if (reduce) { 253: 638-block 0 branch 0 taken 253 (fallthrough) branch 1 taken 0 253: 639: tmp_rank = rank; 253: 640: rank = tmp_rank / reduce; 253: 640-block 0 unconditional 0 taken 253 -: 641: } -: 642: 253: 643: if (rank > max) { 253: 643-block 0 branch 0 taken 28 (fallthrough) branch 1 taken 225 28: 644: max = rank; 28: 645: best_ranked = j; 28: 645-block 0 unconditional 0 taken 28 -: 646: } -: 647: } -: 648: } -: 649: 33: 650: if (!found) { 33: 650-block 0 branch 0 taken 15 (fallthrough) branch 1 taken 18 15: 651: if (mode == NO_SUG_JUMP) 15: 651-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 14 1: 652: printf(_("%s: jump: No matches found\n"), PROGRAM_NAME); 1: 652-block 0 call 0 returned 1 call 1 returned 1 unconditional 2 taken 1 15: 653: exit_status = EXIT_FAILURE; 15: 653-block 0 unconditional 0 taken 15 18: 654: } else if (jump_opt != JLIST) { 18: 654-block 0 branch 0 taken 17 (fallthrough) branch 1 taken 1 17: 655: if (mode == NO_SUG_JUMP) 17: 655-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 16 1: 656: exit_status = cd_function(matches[best_ranked], CD_PRINT_ERROR); 1: 656-block 0 call 0 returned 1 unconditional 1 taken 1 -: 657: else 16: 658: exit_status = save_suggestion(matches[best_ranked]); 16: 658-block 0 call 0 returned 16 unconditional 1 taken 16 -: 659: } -: 660: 33: 661: free(matches); 33: 662: free(needles); 33: 663: free(first); 33: 664: free(last); 33: 665: free(visits); 33: 666: return exit_status; 33: 666-block 0 unconditional 0 taken 33 -: 667:} -: 668: -: 669:/* This function is called if the autojump option is enabled. If the -: 670: * first word in CMD is not a program in PATH, append the j command to -: 671: * the current command line and run the dirjump function */ -: 672:int function run_autojump called 0 returned 0% blocks executed 0% #####: 673:run_autojump(char **cmd) -: 674:{ #####: 675: if (!cmd || !cmd[0] || !*cmd[0]) %%%%%: 675-block 0 branch 0 never executed branch 1 never executed %%%%%: 675-block 1 branch 2 never executed branch 3 never executed %%%%%: 675-block 2 branch 4 never executed branch 5 never executed #####: 676: return -1; %%%%%: 676-block 0 unconditional 0 never executed -: 677: #####: 678: if (is_internal_c(cmd[0])) %%%%%: 678-block 0 call 0 never executed branch 1 never executed branch 2 never executed #####: 679: return -1; %%%%%: 679-block 0 unconditional 0 never executed -: 680: #####: 681: char *ret = get_cmd_path(cmd[0]); %%%%%: 681-block 0 call 0 never executed #####: 682: if (ret) { branch 0 never executed branch 1 never executed #####: 683: free(ret); #####: 684: return -1; %%%%%: 684-block 0 unconditional 0 never executed -: 685: } -: 686: -: 687: int i; -: 688: #####: 689: char **__cmd = (char **)xnmalloc(args_n + 3, sizeof(char *)); %%%%%: 689-block 0 call 0 never executed #####: 690: __cmd[0] = (char *)xnmalloc(2, sizeof(char)); call 0 never executed #####: 691: *__cmd[0] = 'j'; #####: 692: __cmd[0][1] = '\0'; -: 693: #####: 694: for (i = 0; i <= (int)args_n; i++) { unconditional 0 never executed %%%%%: 694-block 0 branch 1 never executed branch 2 never executed #####: 695: __cmd[i + 1] = (char *)xnmalloc(strlen(cmd[i]) + 1, %%%%%: 695-block 0 call 0 never executed -: 696: sizeof(char)); #####: 697: strcpy(__cmd[i + 1], cmd[i]); unconditional 0 never executed -: 698: } -: 699: #####: 700: __cmd[args_n + 2] = (char *)NULL; -: 701: #####: 702: args_n++; #####: 703: exit_code = dirjump(__cmd, NO_SUG_JUMP); %%%%%: 703-block 0 call 0 never executed #####: 704: args_n--; -: 705: #####: 706: i = (int)args_n + 2; #####: 707: while (--i >= 0) unconditional 0 never executed %%%%%: 707-block 0 branch 1 never executed branch 2 never executed #####: 708: free(__cmd[i]); %%%%%: 708-block 0 unconditional 0 never executed #####: 709: free(__cmd); -: 710: #####: 711: return exit_code; %%%%%: 711-block 0 unconditional 0 never executed -: 712:} clifm-1.26.3/misc/codecov/keybinds.c.gcov000066400000000000000000003102661506632037700202040ustar00rootroot00000000000000 -: 0:Source:keybinds.c -: 1:/* keybinds.c -- functions keybindings configuration */ -: 2: -: 3:/* -: 4: * This file is part of CliFM -: 5: * -: 6: * Copyright (C) 2016-2021, L. Abramovich -: 7: * All rights reserved. -: 8: -: 9: * CliFM is free software; you can redistribute it and/or modify -: 10: * it under the terms of the GNU General Public License as published by -: 11: * the Free Software Foundation; either version 2 of the License, or -: 12: * (at your option) any later version. -: 13: * -: 14: * CliFM is distributed in the hope that it will be useful, -: 15: * but WITHOUT ANY WARRANTY; without even the implied warranty of -: 16: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -: 17: * GNU General Public License for more details. -: 18: * -: 19: * You should have received a copy of the GNU General Public License -: 20: * along with this program; if not, write to the Free Software -: 21: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, -: 22: * MA 02110-1301, USA. -: 23:*/ -: 24: -: 25:#include "helpers.h" -: 26: -: 27:#include -: 28:#include -: 29:#ifdef __OpenBSD__ -: 30:typedef char *rl_cpvfunc_t; -: 31:#include -: 32:#else -: 33:#include -: 34:#endif -: 35:#ifdef __TINYC__ -: 36:/* Silence a tcc warning. We don't use CTRL anyway */ -: 37:#undef CTRL -: 38:#endif -: 39:#include -: 40:#include -: 41:#ifdef __NetBSD__ -: 42:#include -: 43:#endif -: 44:#include -: 45: -: 46:#include "aux.h" -: 47:#include "config.h" -: 48:#include "exec.h" -: 49:#include "keybinds.h" -: 50:#include "listing.h" -: 51:#include "mime.h" -: 52:#include "misc.h" -: 53:#include "profiles.h" -: 54:#include "prompt.h" -: 55:#include "messages.h" -: 56:#include "strings.h" -: 57:#include "readline.h" -: 58:#include "file_operations.h" -: 59: -: 60:#ifndef _NO_SUGGESTIONS -: 61:#include "suggestions.h" -: 62:#endif -: 63: -: 64:int accept_first_word = 0; -: 65: -: 66:int function kbinds_reset called 0 returned 0% blocks executed 0% #####: 67:kbinds_reset(void) -: 68:{ #####: 69: int exit_status = EXIT_SUCCESS; -: 70: struct stat file_attrib; -: 71: #####: 72: if (stat(kbinds_file, &file_attrib) == -1) { %%%%%: 72-block 0 call 0 never executed branch 1 never executed branch 2 never executed #####: 73: exit_status = create_kbinds_file(); %%%%%: 73-block 0 call 0 never executed unconditional 1 never executed -: 74: } else { #####: 75: char *cmd[] = {"rm", kbinds_file, NULL}; #####: 76: if (launch_execve(cmd, FOREGROUND, E_NOFLAG) == EXIT_SUCCESS) %%%%%: 76-block 0 call 0 never executed branch 1 never executed branch 2 never executed #####: 77: exit_status = create_kbinds_file(); %%%%%: 77-block 0 call 0 never executed unconditional 1 never executed -: 78: else #####: 79: exit_status = EXIT_FAILURE; %%%%%: 79-block 0 unconditional 0 never executed -: 80: } -: 81: #####: 82: if (exit_status == EXIT_SUCCESS) %%%%%: 82-block 0 branch 0 never executed branch 1 never executed #####: 83: _err('n', PRINT_PROMPT, _("%s: Restart the program for changes " %%%%%: 83-block 0 call 0 never executed call 1 never executed unconditional 2 never executed -: 84: "to take effect\n"), PROGRAM_NAME); -: 85: #####: 86: return exit_status; %%%%%: 86-block 0 unconditional 0 never executed -: 87:} -: 88: -: 89:static int function kbinds_edit called 2 returned 100% blocks executed 70% 2: 90:kbinds_edit(void) -: 91:{ 2: 92: if (xargs.stealth_mode == 1) { 2: 92-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 2 #####: 93: printf("%s: Access to configuration files is not allowed in " %%%%%: 93-block 0 call 0 never executed -: 94: "stealth mode\n", PROGRAM_NAME); #####: 95: return EXIT_SUCCESS; unconditional 0 never executed -: 96: } -: 97: 2: 98: if (!kbinds_file) 2: 98-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 2 #####: 99: return EXIT_FAILURE; %%%%%: 99-block 0 unconditional 0 never executed -: 100: -: 101: struct stat file_attrib; 2: 102: if (stat(kbinds_file, &file_attrib) == -1) { 2: 102-block 0 call 0 returned 2 branch 1 taken 0 (fallthrough) branch 2 taken 2 #####: 103: create_kbinds_file(); %%%%%: 103-block 0 call 0 never executed #####: 104: stat(kbinds_file, &file_attrib); call 0 never executed unconditional 1 never executed -: 105: } -: 106: 2: 107: time_t mtime_bfr = (time_t)file_attrib.st_mtime; -: 108: 2: 109: int ret = open_file(kbinds_file); 2: 109-block 0 call 0 returned 2 2: 110: if (ret != EXIT_SUCCESS) branch 0 taken 0 (fallthrough) branch 1 taken 2 #####: 111: return EXIT_FAILURE; %%%%%: 111-block 0 unconditional 0 never executed -: 112: 2: 113: stat(kbinds_file, &file_attrib); 2: 113-block 0 call 0 returned 2 2: 114: if (mtime_bfr == (time_t)file_attrib.st_mtime) branch 0 taken 1 (fallthrough) branch 1 taken 1 1: 115: return EXIT_SUCCESS; 1: 115-block 0 unconditional 0 taken 1 -: 116: 1: 117: _err('n', PRINT_PROMPT, _("%s: Restart the program for changes to " 1: 117-block 0 call 0 returned 1 call 1 returned 1 -: 118: "take effect\n"), PROGRAM_NAME); 1: 119: return EXIT_SUCCESS; unconditional 0 taken 1 -: 120:} -: 121: -: 122:int function kbinds_function called 4 returned 100% blocks executed 66% 4: 123:kbinds_function(char **args) -: 124:{ 4: 125: if (!args) 4: 125-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 4 #####: 126: return EXIT_FAILURE; %%%%%: 126-block 0 unconditional 0 never executed -: 127: 4: 128: if (!args[1]) { 4: 128-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 3 -: 129: size_t i; 72: 130: for (i = 0; i < kbinds_n; i++) { 1: 130-block 0 unconditional 0 taken 1 unconditional 1 taken 71 72: 130-block 1 branch 2 taken 71 branch 3 taken 1 (fallthrough) 71: 131: printf("%s: %s\n", kbinds[i].key, kbinds[i].function); 71: 131-block 0 call 0 returned 71 -: 132: } -: 133: 1: 134: return EXIT_SUCCESS; 1: 134-block 0 unconditional 0 taken 1 -: 135: } -: 136: 3*: 137: if (*args[1] == '-' && strcmp(args[1], "--help") == 0) { 3: 137-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 3 %%%%%: 137-block 1 branch 2 never executed branch 3 never executed #####: 138: puts(_(KB_USAGE)); %%%%%: 138-block 0 call 0 never executed call 1 never executed #####: 139: return EXIT_SUCCESS; unconditional 0 never executed -: 140: } -: 141: 3: 142: if (*args[1] == 'e' && strcmp(args[1], "edit") == 0) 3: 142-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 1 2: 142-block 1 branch 2 taken 2 (fallthrough) branch 3 taken 0 2: 143: return kbinds_edit(); 2: 143-block 0 call 0 returned 2 unconditional 1 taken 2 -: 144: 1: 145: if (*args[1] == 'r' && strcmp(args[1], "reset") == 0) 1: 145-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 0 1: 145-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 1 #####: 146: return kbinds_reset(); %%%%%: 146-block 0 call 0 never executed unconditional 1 never executed -: 147: 1: 148: if (*args[1] == 'r' && strcmp(args[1], "readline") == 0) { 1: 148-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 0 1: 148-block 1 branch 2 taken 1 (fallthrough) branch 3 taken 0 1: 149: rl_function_dumper(1); 1: 149-block 0 call 0 returned 1 1: 150: return EXIT_SUCCESS; unconditional 0 taken 1 -: 151: } -: 152: #####: 153: fprintf(stderr, "%s\n", _(KB_USAGE)); %%%%%: 153-block 0 call 0 never executed call 1 never executed #####: 154: return EXIT_FAILURE; unconditional 0 never executed -: 155:} -: 156: -: 157:/* Store keybinds from the keybinds file into a struct */ -: 158:int function load_keybinds called 4 returned 100% blocks executed 77% 4: 159:load_keybinds(void) -: 160:{ 4: 161: if (!config_ok) 4: 161-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 4 #####: 162: return EXIT_FAILURE; %%%%%: 162-block 0 unconditional 0 never executed -: 163: -: 164: /* Free the keybinds struct array */ 4: 165: if (kbinds_n) { 4: 165-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 4 #####: 166: int i = (int)kbinds_n; -: 167: #####: 168: while (--i >= 0) { %%%%%: 168-block 0 unconditional 0 never executed %%%%%: 168-block 1 branch 1 never executed branch 2 never executed #####: 169: free(kbinds[i].function); #####: 170: free(kbinds[i].key); %%%%%: 170-block 0 unconditional 0 never executed -: 171: } -: 172: #####: 173: free(kbinds); #####: 174: kbinds = (struct kbinds_t *)xnmalloc(1, sizeof(struct kbinds_t)); %%%%%: 174-block 0 call 0 never executed #####: 175: kbinds_n = 0; unconditional 0 never executed -: 176: } -: 177: -: 178: /* Open the keybinds file */ 4: 179: FILE *fp = fopen(kbinds_file, "r"); 4: 179-block 0 call 0 returned 4 4: 180: if (!fp) branch 0 taken 0 (fallthrough) branch 1 taken 4 #####: 181: return EXIT_FAILURE; %%%%%: 181-block 0 unconditional 0 never executed -: 182: 4: 183: size_t line_size = 0; 4: 184: char *line = (char *)NULL; 4: 185: ssize_t line_len = 0; -: 186: 530: 187: while ((line_len = getline(&line, &line_size, fp)) > 0) { 4: 187-block 0 unconditional 0 taken 4 530: 187-block 1 call 1 returned 530 branch 2 taken 526 branch 3 taken 4 (fallthrough) 526: 188: if (!line || !*line || *line == '#' || *line == '\n') 526: 188-block 0 branch 0 taken 526 (fallthrough) branch 1 taken 0 526: 188-block 1 branch 2 taken 526 (fallthrough) branch 3 taken 0 526: 188-block 2 branch 4 taken 323 (fallthrough) branch 5 taken 203 323: 188-block 3 branch 6 taken 44 (fallthrough) branch 7 taken 279 247: 189: continue; 247: 189-block 0 unconditional 0 taken 247 -: 190: 279: 191: if (line[line_len - 1] == '\n') 279: 191-block 0 branch 0 taken 279 (fallthrough) branch 1 taken 0 279: 192: line[line_len - 1] = '\0'; 279: 192-block 0 unconditional 0 taken 279 -: 193: 279: 194: char *tmp = (char *)NULL; 279: 195: tmp = strchr(line, ':'); 279: 196: if (!tmp || !*(tmp + 1)) 279: 196-block 0 branch 0 taken 279 (fallthrough) branch 1 taken 0 279: 196-block 1 branch 2 taken 1 (fallthrough) branch 3 taken 278 1: 197: continue; 1: 197-block 0 unconditional 0 taken 1 -: 198: -: 199: /* Now copy left and right value of each keybind into the -: 200: * keybinds struct */ 278: 201: kbinds = xrealloc(kbinds, (kbinds_n + 1) * sizeof(struct kbinds_t)); 278: 201-block 0 call 0 returned 278 278: 202: kbinds[kbinds_n].key = savestring(tmp + 1, strlen(tmp + 1)); call 0 returned 278 -: 203: 278: 204: *tmp = '\0'; -: 205: 278: 206: kbinds[kbinds_n++].function = savestring(line, strlen(line)); call 0 returned 278 unconditional 1 taken 278 -: 207: } -: 208: 4: 209: free(line); 4: 210: return EXIT_SUCCESS; 4: 210-block 0 unconditional 0 taken 4 -: 211:} -: 212: -: 213:/* Runs any command recognized by CliFM via a keybind. Example: -: 214: * keybind_exec_cmd("sel *") */ -: 215:static int function keybind_exec_cmd called 97 returned 100% blocks executed 81% 97: 216:keybind_exec_cmd(char *str) -: 217:{ 97: 218: size_t old_args = args_n; 97: 219: args_n = 0; -: 220: -: 221:#ifndef _NO_SUGGESTIONS 97*: 222: if (suggestion.printed && suggestion_buf) 97: 222-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 97 %%%%%: 222-block 1 branch 2 never executed branch 3 never executed #####: 223: free_suggestion(); %%%%%: 223-block 0 call 0 never executed unconditional 1 never executed -: 224:#endif -: 225: 97: 226: int exit_status = EXIT_FAILURE; 97: 227: char **cmd = parse_input_str(str); 97: 227-block 0 call 0 returned 97 97: 228: putchar('\n'); call 0 returned 97 -: 229: 97: 230: if (cmd) { branch 0 taken 97 (fallthrough) branch 1 taken 0 97: 231: exit_status = exec_cmd(cmd); 97: 231-block 0 call 0 returned 97 -: 232: -: 233: /* While in the bookmarks or mountpoints screen, the kbind_busy -: 234: * flag will be set to 1 and no keybinding will work. Once the -: 235: * corresponding function exited, set the kbind_busy flag to zero, -: 236: * so that keybindings work again */ 97: 237: if (kbind_busy) branch 0 taken 0 (fallthrough) branch 1 taken 97 #####: 238: kbind_busy = 0; %%%%%: 238-block 0 unconditional 0 never executed -: 239: 97: 240: int i = (int)args_n + 1; 248: 241: while (--i >= 0) 97: 241-block 0 unconditional 0 taken 97 248: 241-block 1 branch 1 taken 151 branch 2 taken 97 (fallthrough) 151: 242: free(cmd[i]); 151: 242-block 0 unconditional 0 taken 151 97: 243: free(cmd); -: 244: -: 245: /* This call to prompt() just updates the prompt in case it was -: 246: * modified, for example, in case of chdir, files selection, and -: 247: * so on */ 97: 248: char *buf = prompt(); 97: 248-block 0 call 0 returned 97 97: 249: free(buf); unconditional 0 taken 97 -: 250: } -: 251: 97: 252: args_n = old_args; 97: 253: return exit_status; 97: 253-block 0 unconditional 0 taken 97 -: 254:} -: 255: -: 256:static int function run_kb_cmd called 74 returned 100% blocks executed 78% 74: 257:run_kb_cmd(char *cmd) -: 258:{ 74: 259: if (!cmd || !*cmd) 74: 259-block 0 branch 0 taken 74 (fallthrough) branch 1 taken 0 74: 259-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 74 #####: 260: return EXIT_FAILURE; %%%%%: 260-block 0 unconditional 0 never executed -: 261: 74: 262: if (kbind_busy) 74: 262-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 74 #####: 263: return EXIT_SUCCESS; %%%%%: 263-block 0 unconditional 0 never executed -: 264: 74: 265: keybind_exec_cmd(cmd); 74: 265-block 0 call 0 returned 74 74: 266: rl_reset_line_state(); call 0 returned 74 74: 267: return EXIT_SUCCESS; unconditional 0 taken 74 -: 268:} -: 269: -: 270:/* Retrieve the key sequence associated to FUNCTION */ -: 271:static char * function find_key called 308 returned 100% blocks executed 90% 308: 272:find_key(char *function) -: 273:{ 308: 274: if (!kbinds_n) 308: 274-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 308 #####: 275: return (char *)NULL; %%%%%: 275-block 0 unconditional 0 never executed -: 276: 308: 277: int n = (int)kbinds_n; 11623: 278: while (--n >= 0) { 308: 278-block 0 unconditional 0 taken 308 11623: 278-block 1 branch 1 taken 11597 branch 2 taken 26 (fallthrough) 11597: 279: if (*function != *kbinds[n].function) 11597: 279-block 0 branch 0 taken 10322 (fallthrough) branch 1 taken 1275 10322: 280: continue; 10322: 280-block 0 unconditional 0 taken 10322 1275: 281: if (strcmp(function, kbinds[n].function) == 0) 1275: 281-block 0 branch 0 taken 282 (fallthrough) branch 1 taken 993 282: 282: return kbinds[n].key; 282: 282-block 0 unconditional 0 taken 282 -: 283: } -: 284: 26: 285: return (char *)NULL; 26: 285-block 0 unconditional 0 taken 26 -: 286:} -: 287: -: 288:/* Prepend sudo/doas to the current input string */ -: 289:static int function rl_prepend_sudo called 2 returned 100% blocks executed 82% 2: 290:rl_prepend_sudo(int count, int key) -: 291:{ -: 292: UNUSED(count); UNUSED(key); 2: 293: int free_s = 1; 2: 294: size_t len = 0; 2: 295: char *t = getenv("CLIFM_SUDO_CMD"), 2: 295-block 0 call 0 returned 2 2: 296: *s = (char *)NULL; -: 297: 2: 298: if (t) { branch 0 taken 0 (fallthrough) branch 1 taken 2 #####: 299: len = strlen(t); #####: 300: if (t[len - 1] != ' ') { %%%%%: 300-block 0 branch 0 never executed branch 1 never executed #####: 301: s = (char *)xnmalloc(len + 2, sizeof(char)); %%%%%: 301-block 0 call 0 never executed #####: 302: sprintf(s, "%s ", t); #####: 303: len++; unconditional 0 never executed -: 304: } else { #####: 305: s = t; #####: 306: free_s = 0; %%%%%: 306-block 0 unconditional 0 never executed -: 307: } -: 308: } else { 2: 309: len = strlen(DEF_SUDO_CMD) + 1; 2: 310: s = (char *)xnmalloc(len + 1, sizeof(char)); 2: 310-block 0 call 0 returned 2 2: 311: sprintf(s, "%s ", DEF_SUDO_CMD); unconditional 0 taken 2 -: 312: } -: 313: 2: 314: int p = rl_point; 2: 315: if (*rl_line_buffer == *s 2: 315-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 1 1: 316: && strncmp(rl_line_buffer, s, len) == 0) { 1: 316-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 0 1: 317: rl_delete_text(0, (int)len); 1: 317-block 0 call 0 returned 1 1: 318: rl_point = p - (int)len; unconditional 0 taken 1 -: 319: } else { 1: 320: rl_point = 0; 1: 321: rl_insert_text(s); 1: 321-block 0 call 0 returned 1 1: 322: rl_point = p + (int)len; unconditional 0 taken 1 -: 323: } -: 324: 2: 325: if (free_s) 2: 325-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 0 2: 326: free(s); 2: 326-block 0 unconditional 0 taken 2 -: 327: -: 328:#ifndef _NO_SUGGESTIONS 2: 329: if (suggestion.offset == 0 && suggestion_buf) { 2: 329-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 0 2: 329-block 1 branch 2 taken 1 (fallthrough) branch 3 taken 1 1: 330: int r = rl_point; 1: 331: rl_point = rl_end; 1: 332: clear_suggestion(); 1: 332-block 0 call 0 returned 1 1: 333: free(suggestion_buf); 1: 334: suggestion_buf = (char *)NULL; 1: 335: rl_point = r; unconditional 0 taken 1 -: 336: } -: 337:#endif 2: 338: return EXIT_SUCCESS; 2: 338-block 0 unconditional 0 taken 2 -: 339:} -: 340: -: 341:static int function rl_create_file called 0 returned 0% blocks executed 0% #####: 342:rl_create_file(int count, int key) -: 343:{ -: 344: UNUSED(count); UNUSED(key); #####: 345: return run_kb_cmd("n"); %%%%%: 345-block 0 call 0 never executed -: 346:} -: 347: -: 348:#ifndef _NO_SUGGESTIONS -: 349:static int function rl_accept_suggestion called 45 returned 100% blocks executed 72% 45: 350:rl_accept_suggestion(int count, int key) -: 351:{ -: 352: UNUSED(count); UNUSED(key); 45: 353: if (kbind_busy) { 45: 353-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 45 -: 354: /* If not at the end of the typed string, just move the cursor -: 355: * forward one column */ #####: 356: if (rl_point < rl_end) %%%%%: 356-block 0 branch 0 never executed branch 1 never executed #####: 357: rl_point++; %%%%%: 357-block 0 unconditional 0 never executed #####: 358: return EXIT_SUCCESS; %%%%%: 358-block 0 unconditional 0 never executed -: 359: } -: 360: 45: 361: fputs(df_c, stdout); 45: 361-block 0 call 0 returned 45 -: 362: -: 363: /* Only accept the current suggestion if the cursor is at the end -: 364: * of the line typed so far */ 45: 365: if (!suggestions || rl_point != rl_end || !suggestion_buf) { branch 0 taken 45 (fallthrough) branch 1 taken 0 45: 365-block 0 branch 2 taken 35 (fallthrough) branch 3 taken 10 35: 365-block 1 branch 4 taken 1 (fallthrough) branch 5 taken 34 11: 366: if (rl_point < rl_end) 11: 366-block 0 branch 0 taken 10 (fallthrough) branch 1 taken 1 10: 367: rl_point++; /* Just move the cursor forward one column */ 10: 367-block 0 unconditional 0 taken 10 11: 368: return EXIT_SUCCESS; 11: 368-block 0 unconditional 0 taken 11 -: 369: } -: 370: -: 371: /* If accepting the first suggested word, accept only up to next -: 372: * slash or space */ 34: 373: char *s = (char *)NULL, _s = 0; 34: 374: int slash = 0; 34: 375: if (accept_first_word) { 34: 375-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 32 2: 376: size_t i = 0; 2: 377: char *p = suggestion_buf + (rl_point - suggestion.offset); -: 378: /* Skip leading spaces */ 3: 379: while (*(p + i) == ' ') 2: 379-block 0 unconditional 0 taken 2 3: 379-block 1 branch 1 taken 1 branch 2 taken 2 (fallthrough) 1: 380: i++; 1: 380-block 0 unconditional 0 taken 1 -: 381: -: 382: /* Trim the suggestion up to first slash or space */ 2: 383: s = strchr(p + i, '/'); -: 384: /* If the slash is immediately preceded by a space, move to -: 385: * the next slash */ 2*: 386: if (s && s != p && *(s - 1) == ' ') { 2: 386-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 2 %%%%%: 386-block 1 branch 2 never executed branch 3 never executed %%%%%: 386-block 2 branch 4 never executed branch 5 never executed #####: 387: char *ss = strchr(s + 1, '/'); #####: 388: if (ss) %%%%%: 388-block 0 branch 0 never executed branch 1 never executed #####: 389: s = ss; %%%%%: 389-block 0 unconditional 0 never executed -: 390: } 2: 391: char *sp = strchr(p + i, ' '); 2: 392: if (s) { 2: 392-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 2 -: 393: /* If there is a space somewhere before the slash */ #####: 394: if (sp && sp < s) { %%%%%: 394-block 0 branch 0 never executed branch 1 never executed %%%%%: 394-block 1 branch 2 never executed branch 3 never executed #####: 395: s = sp; %%%%%: 395-block 0 unconditional 0 never executed -: 396: } else { -: 397: /* In case of slash, keep a copy of the next char, if any: -: 398: * we cannot know in advance what comes after the slash */ #####: 399: if (*(++s)) %%%%%: 399-block 0 branch 0 never executed branch 1 never executed #####: 400: _s = *s; %%%%%: 400-block 0 unconditional 0 never executed #####: 401: slash = 1; %%%%%: 401-block 0 unconditional 0 never executed -: 402: } 2: 403: } else if (sp) { 2: 403-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 1 1: 404: s = sp; 1: 404-block 0 unconditional 0 taken 1 -: 405: } -: 406: 2*: 407: if (s && (slash ? *s : *(s + 1)) && s != p) { 2: 407-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 1 1: 407-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 1 %%%%%: 407-block 2 branch 4 never executed branch 5 never executed 1: 407-block 3 branch 6 taken 1 (fallthrough) branch 7 taken 0 1: 407-block 4 branch 8 taken 1 (fallthrough) branch 9 taken 0 1: 408: *s = '\0'; 1: 408-block 0 unconditional 0 taken 1 -: 409: } else { -: 410: /* Last word: neither space nor slash */ 1: 411: size_t len = strlen(suggestion_buf); 1: 412: if (suggestion_buf[len - 1] != '/' 1: 412-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 0 1: 413: && suggestion_buf[len - 1] != ' ') 1: 413-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 0 1: 414: suggestion.type = NO_SUG; 1: 414-block 0 unconditional 0 taken 1 -: 415:/* clear_suggestion(); */ 1: 416: accept_first_word = 0; 1: 416-block 0 unconditional 0 taken 1 -: 417: } -: 418: } -: 419: 34: 420: rl_delete_text(suggestion.offset, rl_end); 34: 420-block 0 call 0 returned 34 34: 421: rl_point = suggestion.offset; -: 422: 34: 423: if (!accept_first_word && (suggestion.type == BOOKMARK_SUG branch 0 taken 33 (fallthrough) branch 1 taken 1 33: 423-block 0 branch 2 taken 33 (fallthrough) branch 3 taken 0 33: 424: || suggestion.type == ALIAS_SUG || suggestion.type == ELN_SUG 33: 424-block 0 branch 0 taken 33 (fallthrough) branch 1 taken 0 33: 424-block 1 branch 2 taken 18 (fallthrough) branch 3 taken 15 18: 425: || suggestion.type == JCMD_SUG || suggestion.type == JCMD_SUG_NOACD)) 18: 425-block 0 branch 0 taken 16 (fallthrough) branch 1 taken 2 16: 425-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 16 17: 426: clear_suggestion(); 17: 426-block 0 call 0 returned 17 unconditional 1 taken 17 -: 427: -: 428:/* -: 429:#ifndef _NO_HIGHLIGHT -: 430: if (*suggestion_buf == '#') -: 431: fputs(hc_c, stdout); -: 432:#endif */ -: 433: 34: 434: switch(suggestion.type) { 34: 434-block 0 branch 0 taken 17 branch 1 taken 3 branch 2 taken 0 branch 3 taken 14 -: 435: 17: 436: case JCMD_SUG: /* fallthrough */ -: 437: case BOOKMARK_SUG: /* fallthrough */ -: 438: case COMP_SUG: /* fallthrough */ -: 439: case ELN_SUG: /* fallthrough */ -: 440: case FILE_SUG: { 17: 441: char *tmp = (char *)NULL; 17: 442: size_t i, isquote = 0; 158: 443: for (i = 0; suggestion_buf[i]; i++) { 17: 443-block 0 unconditional 0 taken 17 141: 443-block 1 unconditional 1 taken 141 158: 443-block 2 branch 2 taken 141 branch 3 taken 17 (fallthrough) 141: 444: if (is_quote_char(suggestion_buf[i])) { 141: 444-block 0 call 0 returned 141 branch 1 taken 0 (fallthrough) branch 2 taken 141 #####: 445: isquote = 1; #####: 446: break; %%%%%: 446-block 0 unconditional 0 never executed -: 447: } -: 448: } 17: 449: if (isquote) 17: 449-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 17 #####: 450: tmp = escape_str(suggestion_buf); %%%%%: 450-block 0 call 0 never executed unconditional 1 never executed -: 451: 17: 452: if (tmp) { 17: 452-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 17 #####: 453: rl_insert_text(tmp); %%%%%: 453-block 0 call 0 never executed #####: 454: free(tmp); unconditional 0 never executed -: 455: } else { 17: 456: rl_insert_text(suggestion_buf); 17: 456-block 0 call 0 returned 17 unconditional 1 taken 17 -: 457: } 17: 458: if (suggestion.filetype != DT_DIR) 17: 458-block 0 branch 0 taken 13 (fallthrough) branch 1 taken 4 13: 459: rl_stuff_char(' '); 13: 459-block 0 call 0 returned 13 unconditional 1 taken 13 17: 460: suggestion.type = NO_SUG; -: 461: } 17: 462: break; 17: 462-block 0 unconditional 0 taken 17 -: 463: 3: 464: case FIRST_WORD: /* fallthrough */ -: 465: case JCMD_SUG_NOACD: /* fallthrough */ -: 466: case HIST_SUG: 3: 467: rl_insert_text(suggestion_buf); 3: 467-block 0 call 0 returned 3 3: 468: break; unconditional 0 taken 3 -: 469: #####: 470: case VAR_SUG: -: 471:/* -: 472:#ifndef _NO_HIGHLIGHT -: 473: if (highlight) -: 474: fputs(hv_c, stdout); -: 475:#endif */ #####: 476: rl_insert_text(suggestion_buf); %%%%%: 476-block 0 call 0 never executed #####: 477: rl_stuff_char(' '); call 0 never executed #####: 478: break; unconditional 0 never executed -: 479: 14: 480: default: 14: 481: rl_insert_text(suggestion_buf); 14: 481-block 0 call 0 returned 14 14: 482: rl_stuff_char(' '); call 0 returned 14 14: 483: break; unconditional 0 taken 14 -: 484: } -: 485: -: 486: /* Move the cursor to the end of the line */ 34: 487: rl_point = rl_end; 34: 488: if (!accept_first_word) { 34: 488-block 0 branch 0 taken 33 (fallthrough) branch 1 taken 1 33: 489: suggestion.printed = 0; 33: 490: free(suggestion_buf); 33: 491: suggestion_buf = (char *)NULL; 33: 491-block 0 unconditional 0 taken 33 -: 492: } else { 1: 493: if (s) { 1: 493-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 0 -: 494: /* Reinsert the char we removed to print only the first word */ 1: 495: if (slash) 1: 495-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 1 #####: 496: *s = _s; %%%%%: 496-block 0 unconditional 0 never executed -: 497: else 1: 498: *s = ' '; 1: 498-block 0 unconditional 0 taken 1 -: 499: } 1: 500: accept_first_word = 0; 1: 500-block 0 unconditional 0 taken 1 -: 501: } -: 502: 34: 503: return EXIT_SUCCESS; 34: 503-block 0 unconditional 0 taken 34 -: 504:} -: 505: -: 506:static int function rl_accept_first_word called 2 returned 100% blocks executed 100% 2: 507:rl_accept_first_word(int count, int key) -: 508:{ -: 509: /* Accepting the first suggested word is not supported for ELN's, -: 510: * bookmarks and aliases names */ 2: 511: if (suggestion.type != ELN_SUG && suggestion.type != BOOKMARK_SUG 2: 511-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 0 2: 511-block 1 branch 2 taken 2 (fallthrough) branch 3 taken 0 2: 512: && suggestion.type != ALIAS_SUG && suggestion.type != JCMD_SUG 2: 512-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 0 2: 512-block 1 branch 2 taken 2 (fallthrough) branch 3 taken 0 2: 513: && suggestion.type != JCMD_SUG_NOACD) { 2: 513-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 0 2: 514: accept_first_word = 1; 2: 515: suggestion.type = FIRST_WORD; 2: 515-block 0 unconditional 0 taken 2 -: 516: } 2: 517: return rl_accept_suggestion(count, key); 2: 517-block 0 call 0 returned 2 -: 518:} -: 519:#endif /* !_NO_SUGGESTIONS */ -: 520: -: 521:static int function rl_refresh called 1 returned 100% blocks executed 75% 1: 522:rl_refresh(int count, int key) -: 523:{ -: 524: UNUSED(count); UNUSED(key); 1: 525: if (kbind_busy) 1: 525-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 1 #####: 526: return EXIT_SUCCESS; %%%%%: 526-block 0 unconditional 0 never executed -: 527: 1: 528: if (clear_screen) 1: 528-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 1 #####: 529: CLEAR; %%%%%: 529-block 0 call 0 never executed unconditional 1 never executed 1: 530: keybind_exec_cmd("rf"); 1: 530-block 0 call 0 returned 1 1: 531: rl_reset_line_state(); call 0 returned 1 1: 532: return EXIT_SUCCESS; unconditional 0 taken 1 -: 533:} -: 534: -: 535:static int function rl_parent_dir called 1 returned 100% blocks executed 80% 1: 536:rl_parent_dir(int count, int key) -: 537:{ -: 538: UNUSED(count); UNUSED(key); -: 539: /* If already root dir, do nothing */ 1: 540: if (*ws[cur_ws].path == '/' && !ws[cur_ws].path[1]) 1: 540-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 0 1: 540-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 1 #####: 541: return EXIT_SUCCESS; %%%%%: 541-block 0 unconditional 0 never executed 1: 542: return run_kb_cmd("cd .."); 1: 542-block 0 call 0 returned 1 unconditional 1 taken 1 -: 543:} -: 544: -: 545:static int function rl_root_dir called 0 returned 0% blocks executed 0% #####: 546:rl_root_dir(int count, int key) -: 547:{ -: 548: UNUSED(count); UNUSED(key); -: 549: /* If already root dir, do nothing */ #####: 550: if (*ws[cur_ws].path == '/' && !ws[cur_ws].path[1]) %%%%%: 550-block 0 branch 0 never executed branch 1 never executed %%%%%: 550-block 1 branch 2 never executed branch 3 never executed #####: 551: return EXIT_SUCCESS; %%%%%: 551-block 0 unconditional 0 never executed #####: 552: return run_kb_cmd("cd /"); %%%%%: 552-block 0 call 0 never executed unconditional 1 never executed -: 553:} -: 554: -: 555:static int function rl_home_dir called 1 returned 100% blocks executed 80% 1: 556:rl_home_dir(int count, int key) -: 557:{ -: 558: UNUSED(count); UNUSED(key); -: 559: /* If already in home, do nothing */ 1: 560: if (*ws[cur_ws].path == *user.home && strcmp(ws[cur_ws].path, user.home) == 0) 1: 560-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 0 1: 560-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 1 #####: 561: return EXIT_SUCCESS; %%%%%: 561-block 0 unconditional 0 never executed 1: 562: return run_kb_cmd("cd"); 1: 562-block 0 call 0 returned 1 unconditional 1 taken 1 -: 563:} -: 564: -: 565:static int function rl_next_dir called 2 returned 100% blocks executed 75% 2: 566:rl_next_dir(int count, int key) -: 567:{ -: 568: UNUSED(count); UNUSED(key); -: 569: /* If already at the end of dir hist, do nothing */ 2: 570: if (dirhist_cur_index + 1 == dirhist_total_index) 2: 570-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 2 #####: 571: return EXIT_SUCCESS; %%%%%: 571-block 0 unconditional 0 never executed 2: 572: return run_kb_cmd("f"); 2: 572-block 0 call 0 returned 2 unconditional 1 taken 2 -: 573:} -: 574: -: 575:static int function rl_first_dir called 1 returned 100% blocks executed 75% 1: 576:rl_first_dir(int count, int key) -: 577:{ -: 578: UNUSED(count); UNUSED(key); -: 579: /* If already at the beginning of dir hist, do nothing */ 1: 580: if (dirhist_cur_index == 0) 1: 580-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 1 #####: 581: return EXIT_SUCCESS; %%%%%: 581-block 0 unconditional 0 never executed -: 582: 1: 583: return run_kb_cmd("b !1"); 1: 583-block 0 call 0 returned 1 unconditional 1 taken 1 -: 584:} -: 585: -: 586:static int function rl_last_dir called 1 returned 100% blocks executed 78% 1: 587:rl_last_dir(int count, int key) -: 588:{ -: 589: UNUSED(count); UNUSED(key); 1: 590: if (kbind_busy) 1: 590-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 1 #####: 591: return EXIT_SUCCESS; %%%%%: 591-block 0 unconditional 0 never executed -: 592: -: 593: /* If already at the end of dir hist, do nothing */ 1: 594: if (dirhist_cur_index + 1 == dirhist_total_index) 1: 594-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 1 #####: 595: return EXIT_SUCCESS; %%%%%: 595-block 0 unconditional 0 never executed -: 596: -: 597: char cmd[PATH_MAX + 4]; 1: 598: sprintf(cmd, "b !%d", dirhist_total_index); 1: 599: keybind_exec_cmd(cmd); 1: 599-block 0 call 0 returned 1 1: 600: rl_reset_line_state(); call 0 returned 1 1: 601: return EXIT_SUCCESS; unconditional 0 taken 1 -: 602:} -: 603: -: 604:static int function rl_previous_dir called 22 returned 100% blocks executed 75% 22: 605:rl_previous_dir(int count, int key) -: 606:{ -: 607: UNUSED(count); UNUSED(key); -: 608: /* If already at the beginning of dir hist, do nothing */ 22: 609: if (dirhist_cur_index == 0) 22: 609-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 22 #####: 610: return EXIT_SUCCESS; %%%%%: 610-block 0 unconditional 0 never executed 22: 611: return run_kb_cmd("b"); 22: 611-block 0 call 0 returned 22 unconditional 1 taken 22 -: 612:} -: 613: -: 614:static int function rl_long called 4 returned 100% blocks executed 75% 4: 615:rl_long(int count, int key) -: 616:{ -: 617: UNUSED(count); UNUSED(key); 4: 618: if (kbind_busy) 4: 618-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 4 #####: 619: return EXIT_SUCCESS; %%%%%: 619-block 0 unconditional 0 never executed -: 620: 4: 621: long_view = long_view ? 0 : 1; -: 622: 4: 623: if (clear_screen) 4: 623-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 4 #####: 624: CLEAR; %%%%%: 624-block 0 call 0 never executed unconditional 1 never executed 4: 625: keybind_exec_cmd("rf"); 4: 625-block 0 call 0 returned 4 4: 626: rl_reset_line_state(); call 0 returned 4 4: 627: return EXIT_SUCCESS; unconditional 0 taken 4 -: 628:} -: 629: -: 630:static int function rl_folders_first called 2 returned 100% blocks executed 71% 2: 631:rl_folders_first(int count, int key) -: 632:{ -: 633: UNUSED(count); UNUSED(key); 2: 634: if (kbind_busy) 2: 634-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 2 #####: 635: return EXIT_SUCCESS; %%%%%: 635-block 0 unconditional 0 never executed -: 636: -: 637:#ifndef _NO_SUGGESTIONS 2*: 638: if (suggestion.printed && suggestion_buf) 2: 638-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 2 %%%%%: 638-block 1 branch 2 never executed branch 3 never executed #####: 639: free_suggestion(); %%%%%: 639-block 0 call 0 never executed unconditional 1 never executed -: 640:#endif -: 641: 2: 642: list_folders_first = list_folders_first ? 0 : 1; -: 643: 2: 644: if (cd_lists_on_the_fly) { 2: 644-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 0 2: 645: if (clear_screen) 2: 645-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 2 #####: 646: CLEAR; %%%%%: 646-block 0 call 0 never executed unconditional 1 never executed 2: 647: free_dirlist(); 2: 647-block 0 call 0 returned 2 -: 648: /* Without this putchar(), the first entries of the directories -: 649: * list are printed in the prompt line */ 2: 650: putchar('\n'); call 0 returned 2 2: 651: list_dir(); call 0 returned 2 unconditional 1 taken 2 -: 652: } -: 653: 2: 654: rl_reset_line_state(); 2: 654-block 0 call 0 returned 2 2: 655: return EXIT_SUCCESS; unconditional 0 taken 2 -: 656:} -: 657: -: 658:static int function rl_light called 4 returned 100% blocks executed 75% 4: 659:rl_light(int count, int key) -: 660:{ -: 661: UNUSED(count); UNUSED(key); 4: 662: if (kbind_busy) 4: 662-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 4 #####: 663: return EXIT_SUCCESS; %%%%%: 663-block 0 unconditional 0 never executed -: 664: 4: 665: light_mode = light_mode ? 0 : 1; -: 666: 4: 667: if (clear_screen) 4: 667-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 4 #####: 668: CLEAR; %%%%%: 668-block 0 call 0 never executed unconditional 1 never executed 4: 669: keybind_exec_cmd("rf"); 4: 669-block 0 call 0 returned 4 4: 670: rl_reset_line_state(); call 0 returned 4 4: 671: return EXIT_SUCCESS; unconditional 0 taken 4 -: 672:} -: 673: -: 674:static int function rl_hidden called 4 returned 100% blocks executed 71% 4: 675:rl_hidden(int count, int key) -: 676:{ -: 677: UNUSED(count); UNUSED(key); 4: 678: if (kbind_busy) 4: 678-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 4 #####: 679: return EXIT_SUCCESS; %%%%%: 679-block 0 unconditional 0 never executed -: 680:#ifndef _NO_SUGGESTIONS 4*: 681: if (suggestion.printed && suggestion_buf) 4: 681-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 4 %%%%%: 681-block 1 branch 2 never executed branch 3 never executed #####: 682: free_suggestion(); %%%%%: 682-block 0 call 0 never executed unconditional 1 never executed -: 683:#endif 4: 684: show_hidden = show_hidden ? 0 : 1; -: 685: 4: 686: if (cd_lists_on_the_fly) { 4: 686-block 0 branch 0 taken 4 (fallthrough) branch 1 taken 0 4: 687: if (clear_screen) 4: 687-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 4 #####: 688: CLEAR; %%%%%: 688-block 0 call 0 never executed unconditional 1 never executed 4: 689: free_dirlist(); 4: 689-block 0 call 0 returned 4 4: 690: putchar('\n'); call 0 returned 4 4: 691: list_dir(); call 0 returned 4 unconditional 1 taken 4 -: 692: } -: 693: 4: 694: rl_reset_line_state(); 4: 694-block 0 call 0 returned 4 4: 695: return EXIT_SUCCESS; unconditional 0 taken 4 -: 696:} -: 697: -: 698:static int function rl_open_config called 9 returned 100% blocks executed 100% 9: 699:rl_open_config(int count, int key) -: 700:{ -: 701: UNUSED(count); UNUSED(key); 9: 702: return run_kb_cmd("edit"); 9: 702-block 0 call 0 returned 9 -: 703:} -: 704: -: 705:static int function rl_open_keybinds called 1 returned 100% blocks executed 100% 1: 706:rl_open_keybinds(int count, int key) -: 707:{ -: 708: UNUSED(count); UNUSED(key); 1: 709: return run_kb_cmd("kb edit"); 1: 709-block 0 call 0 returned 1 -: 710:} -: 711: -: 712:static int function rl_open_cscheme called 1 returned 100% blocks executed 100% 1: 713:rl_open_cscheme(int count, int key) -: 714:{ -: 715: UNUSED(count); UNUSED(key); 1: 716: return run_kb_cmd("cs e"); 1: 716-block 0 call 0 returned 1 -: 717:} -: 718: -: 719:static int function rl_open_bm_file called 1 returned 100% blocks executed 100% 1: 720:rl_open_bm_file(int count, int key) -: 721:{ -: 722: UNUSED(count); UNUSED(key); 1: 723: return run_kb_cmd("bm edit"); 1: 723-block 0 call 0 returned 1 -: 724:} -: 725: -: 726:static int function rl_open_jump_db called 1 returned 100% blocks executed 100% 1: 727:rl_open_jump_db(int count, int key) -: 728:{ -: 729: UNUSED(count); UNUSED(key); 1: 730: return run_kb_cmd("je"); 1: 730-block 0 call 0 returned 1 -: 731:} -: 732: -: 733:static int function rl_open_mime called 0 returned 0% blocks executed 0% #####: 734:rl_open_mime(int count, int key) -: 735:{ -: 736: UNUSED(count); UNUSED(key); #####: 737: return run_kb_cmd("mm edit"); %%%%%: 737-block 0 call 0 never executed -: 738:} -: 739: -: 740:static int function rl_mountpoints called 1 returned 100% blocks executed 100% 1: 741:rl_mountpoints(int count, int key) -: 742:{ -: 743: UNUSED(count); UNUSED(key); -: 744: /* Call the function only if it's not already running */ 1: 745: kbind_busy = 1; 1: 746: keybind_exec_cmd("mp"); 1: 746-block 0 call 0 returned 1 1: 747: rl_reset_line_state(); call 0 returned 1 1: 748: return EXIT_SUCCESS; unconditional 0 taken 1 -: 749:} -: 750: -: 751:static int function rl_select_all called 1 returned 100% blocks executed 100% 1: 752:rl_select_all(int count, int key) -: 753:{ -: 754: UNUSED(count); UNUSED(key); 1: 755: return run_kb_cmd("s ^"); 1: 755-block 0 call 0 returned 1 -: 756:} -: 757: -: 758:static int function rl_deselect_all called 7 returned 100% blocks executed 100% 7: 759:rl_deselect_all(int count, int key) -: 760:{ -: 761: UNUSED(count); UNUSED(key); 7: 762: return run_kb_cmd("ds *"); 7: 762-block 0 call 0 returned 7 -: 763:} -: 764: -: 765:static int function rl_bookmarks called 5 returned 100% blocks executed 83% 5: 766:rl_bookmarks(int count, int key) -: 767:{ -: 768: UNUSED(count); UNUSED(key); 5: 769: if (kbind_busy) 5: 769-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 5 #####: 770: return EXIT_SUCCESS; %%%%%: 770-block 0 unconditional 0 never executed -: 771: 5: 772: kbind_busy = 1; 5: 773: keybind_exec_cmd("bm"); 5: 773-block 0 call 0 returned 5 5: 774: rl_reset_line_state(); call 0 returned 5 5: 775: return EXIT_SUCCESS; unconditional 0 taken 5 -: 776:} -: 777: -: 778:static int function rl_selbox called 1 returned 100% blocks executed 100% 1: 779:rl_selbox(int count, int key) -: 780:{ -: 781: UNUSED(count); UNUSED(key); 1: 782: return run_kb_cmd("ds"); 1: 782-block 0 call 0 returned 1 -: 783:} -: 784: -: 785:static int function rl_clear_line called 2 returned 100% blocks executed 58% 2: 786:rl_clear_line(int count, int key) -: 787:{ -: 788: UNUSED(count); UNUSED(key); 2: 789: if (kbind_busy) 2: 789-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 2 #####: 790: return EXIT_SUCCESS; %%%%%: 790-block 0 unconditional 0 never executed -: 791:#ifndef _NO_SUGGESTIONS 2: 792: if (suggestion.nlines > term_rows) { 2: 792-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 2 #####: 793: rl_on_new_line(); %%%%%: 793-block 0 call 0 never executed #####: 794: return EXIT_SUCCESS; unconditional 0 never executed -: 795: } -: 796: 2: 797: cur_color = df_c; 2: 798: fputs(cur_color, stdout); 2: 798-block 0 call 0 returned 2 -: 799: 2: 800: if (suggestion_buf) { branch 0 taken 0 (fallthrough) branch 1 taken 2 #####: 801: clear_suggestion(); %%%%%: 801-block 0 call 0 never executed #####: 802: suggestion.printed = 0; #####: 803: suggestion.nlines = 0; #####: 804: free(suggestion_buf); #####: 805: suggestion_buf = (char *)NULL; unconditional 0 never executed -: 806: } -: 807:#endif 2: 808: rl_point = 0; 2: 809: rl_delete_text(rl_point, rl_end); 2: 809-block 0 call 0 returned 2 2: 810: rl_end = 0; 2: 811: return EXIT_SUCCESS; unconditional 0 taken 2 -: 812:} -: 813: -: 814:static int function rl_sort_next called 2 returned 100% blocks executed 71% 2: 815:rl_sort_next(int count, int key) -: 816:{ -: 817: UNUSED(count); UNUSED(key); 2: 818: if (kbind_busy) 2: 818-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 2 #####: 819: return EXIT_SUCCESS; %%%%%: 819-block 0 unconditional 0 never executed -: 820:#ifndef _NO_SUGGESTIONS 2*: 821: if (suggestion.printed && suggestion_buf) 2: 821-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 2 %%%%%: 821-block 1 branch 2 never executed branch 3 never executed #####: 822: free_suggestion(); %%%%%: 822-block 0 call 0 never executed unconditional 1 never executed -: 823:#endif 2: 824: sort++; 2: 825: if (sort > SORT_TYPES) 2: 825-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 2 #####: 826: sort = 0; %%%%%: 826-block 0 unconditional 0 never executed -: 827: 2: 828: if (cd_lists_on_the_fly) { 2: 828-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 0 2: 829: if (clear_screen) 2: 829-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 2 #####: 830: CLEAR; %%%%%: 830-block 0 call 0 never executed unconditional 1 never executed 2: 831: sort_switch = 1; 2: 832: free_dirlist(); 2: 832-block 0 call 0 returned 2 2: 833: putchar('\n'); call 0 returned 2 2: 834: list_dir(); call 0 returned 2 2: 835: sort_switch = 0; unconditional 0 taken 2 -: 836: } -: 837: 2: 838: rl_reset_line_state(); 2: 838-block 0 call 0 returned 2 2: 839: return EXIT_SUCCESS; unconditional 0 taken 2 -: 840:} -: 841: -: 842:static int function rl_sort_previous called 14 returned 100% blocks executed 76% 14: 843:rl_sort_previous(int count, int key) -: 844:{ -: 845: UNUSED(count); UNUSED(key); 14: 846: if (kbind_busy) 14: 846-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 14 #####: 847: return EXIT_SUCCESS; %%%%%: 847-block 0 unconditional 0 never executed -: 848:#ifndef _NO_SUGGESTIONS 14*: 849: if (suggestion.printed && suggestion_buf) 14: 849-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 14 %%%%%: 849-block 1 branch 2 never executed branch 3 never executed #####: 850: free_suggestion(); %%%%%: 850-block 0 call 0 never executed unconditional 1 never executed -: 851:#endif 14: 852: sort--; 14: 853: if (sort < 0) 14: 853-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 13 1: 854: sort = SORT_TYPES; 1: 854-block 0 unconditional 0 taken 1 -: 855: 14: 856: if (cd_lists_on_the_fly) { 14: 856-block 0 branch 0 taken 14 (fallthrough) branch 1 taken 0 14: 857: if (clear_screen) 14: 857-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 14 #####: 858: CLEAR; %%%%%: 858-block 0 call 0 never executed unconditional 1 never executed 14: 859: sort_switch = 1; 14: 860: free_dirlist(); 14: 860-block 0 call 0 returned 14 14: 861: putchar('\n'); call 0 returned 14 14: 862: list_dir(); call 0 returned 14 14: 863: sort_switch = 0; unconditional 0 taken 14 -: 864: } -: 865: 14: 866: rl_reset_line_state(); 14: 866-block 0 call 0 returned 14 14: 867: return EXIT_SUCCESS; unconditional 0 taken 14 -: 868:} -: 869: -: 870:static int function rl_lock called 1 returned 100% blocks executed 75% 1: 871:rl_lock(int count, int key) -: 872:{ -: 873: UNUSED(count); UNUSED(key); 1: 874: int ret = EXIT_SUCCESS; -: 875:#ifndef _NO_SUGGESTIONS 1*: 876: if (suggestion.printed && suggestion_buf) 1: 876-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 1 %%%%%: 876-block 1 branch 2 never executed branch 3 never executed #####: 877: free_suggestion(); %%%%%: 877-block 0 call 0 never executed unconditional 1 never executed -: 878:#endif 1: 879: rl_deprep_terminal(); 1: 879-block 0 call 0 returned 1 -: 880: -: 881:#if __FreeBSD__ || __NetBSD__ || __OpenBSD__ -: 882: char *cmd[] = {"lock", NULL}; -: 883:#elif __APPLE__ -: 884: char *cmd[] = {"bashlock", NULL}; -: 885:#elif __HAIKU__ -: 886: char *cmd[] = {"peaclock", NULL}; -: 887:#else 1: 888: char *cmd[] = {"vlock", NULL}; -: 889:#endif 1: 890: ret = launch_execve(cmd, FOREGROUND, E_NOFLAG); call 0 returned 1 -: 891: 1: 892: rl_prep_terminal(0); call 0 returned 1 1: 893: rl_reset_line_state(); call 0 returned 1 -: 894: 1: 895: if (ret != EXIT_SUCCESS) branch 0 taken 0 (fallthrough) branch 1 taken 1 #####: 896: return EXIT_FAILURE; %%%%%: 896-block 0 unconditional 0 never executed 1: 897: return EXIT_SUCCESS; 1: 897-block 0 unconditional 0 taken 1 -: 898:} -: 899: -: 900:static int function rl_remove_sel called 1 returned 100% blocks executed 88% 1: 901:rl_remove_sel(int count, int key) -: 902:{ -: 903: UNUSED(count); UNUSED(key); 1: 904: if (kbind_busy) 1: 904-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 1 #####: 905: return EXIT_SUCCESS; %%%%%: 905-block 0 unconditional 0 never executed -: 906: 1: 907: rl_deprep_terminal(); 1: 907-block 0 call 0 returned 1 1: 908: kb_shortcut = 1; 1: 909: keybind_exec_cmd("r sel"); call 0 returned 1 1: 910: kb_shortcut = 0; 1: 911: rl_prep_terminal(0); call 0 returned 1 1: 912: rl_reset_line_state(); call 0 returned 1 1: 913: return EXIT_SUCCESS; unconditional 0 taken 1 -: 914:} -: 915: -: 916:static int function rl_export_sel called 1 returned 100% blocks executed 83% 1: 917:rl_export_sel(int count, int key) -: 918:{ -: 919: UNUSED(count); UNUSED(key); 1: 920: if (kbind_busy) 1: 920-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 1 #####: 921: return EXIT_SUCCESS; %%%%%: 921-block 0 unconditional 0 never executed -: 922: 1: 923: kb_shortcut = 1; 1: 924: keybind_exec_cmd("exp sel"); 1: 924-block 0 call 0 returned 1 1: 925: kb_shortcut = 0; 1: 926: rl_reset_line_state(); call 0 returned 1 1: 927: return EXIT_SUCCESS; unconditional 0 taken 1 -: 928:} -: 929: -: 930:static int function rl_move_sel called 1 returned 100% blocks executed 83% 1: 931:rl_move_sel(int count, int key) -: 932:{ -: 933: UNUSED(count); UNUSED(key); 1: 934: if (kbind_busy) 1: 934-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 1 #####: 935: return EXIT_SUCCESS; %%%%%: 935-block 0 unconditional 0 never executed -: 936: 1: 937: kb_shortcut = 1; 1: 938: keybind_exec_cmd("m sel"); 1: 938-block 0 call 0 returned 1 1: 939: kb_shortcut = 0; 1: 940: rl_reset_line_state(); call 0 returned 1 1: 941: return EXIT_SUCCESS; unconditional 0 taken 1 -: 942:} -: 943: -: 944:static int function rl_rename_sel called 1 returned 100% blocks executed 83% 1: 945:rl_rename_sel(int count, int key) -: 946:{ -: 947: UNUSED(count); UNUSED(key); 1: 948: if (kbind_busy) 1: 948-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 1 #####: 949: return EXIT_SUCCESS; %%%%%: 949-block 0 unconditional 0 never executed -: 950: 1: 951: kb_shortcut = 1; 1: 952: keybind_exec_cmd("br sel"); 1: 952-block 0 call 0 returned 1 1: 953: kb_shortcut = 0; 1: 954: rl_reset_line_state(); call 0 returned 1 1: 955: return EXIT_SUCCESS; unconditional 0 taken 1 -: 956:} -: 957: -: 958:static int function rl_paste_sel called 1 returned 100% blocks executed 88% 1: 959:rl_paste_sel(int count, int key) -: 960:{ -: 961: UNUSED(count); UNUSED(key); 1: 962: if (kbind_busy) 1: 962-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 1 #####: 963: return EXIT_SUCCESS; %%%%%: 963-block 0 unconditional 0 never executed -: 964: 1: 965: kb_shortcut = 1; 1: 966: rl_deprep_terminal(); 1: 966-block 0 call 0 returned 1 1: 967: keybind_exec_cmd("c sel"); call 0 returned 1 1: 968: rl_prep_terminal(0); call 0 returned 1 1: 969: kb_shortcut = 0; 1: 970: rl_reset_line_state(); call 0 returned 1 1: 971: return EXIT_SUCCESS; unconditional 0 taken 1 -: 972:} -: 973: -: 974:static int function rl_quit called 0 returned 0% blocks executed 0% #####: 975:rl_quit(int count, int key) -: 976:{ -: 977: UNUSED(count); UNUSED(key); #####: 978: if (kbind_busy) %%%%%: 978-block 0 branch 0 never executed branch 1 never executed #####: 979: return EXIT_SUCCESS; %%%%%: 979-block 0 unconditional 0 never executed -: 980: -: 981: /* Reset terminal attributes before exiting. Without this line, the program -: 982: * quits, but terminal input is not printed to STDOUT */ #####: 983: tcsetattr(STDIN_FILENO, TCSANOW, &shell_tmodes); %%%%%: 983-block 0 call 0 never executed #####: 984: exit(EXIT_SUCCESS); call 0 never executed -: 985: return EXIT_SUCCESS; -: 986:} -: 987: -: 988:static int function rl_previous_profile called 6 returned 100% blocks executed 88% 6: 989:rl_previous_profile(int count, int key) -: 990:{ -: 991: UNUSED(count); UNUSED(key); 6: 992: if (kbind_busy) 6: 992-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 6 #####: 993: return EXIT_SUCCESS; %%%%%: 993-block 0 unconditional 0 never executed -: 994:#ifndef _NO_SUGGESTIONS 6*: 995: if (suggestion.printed && suggestion_buf) 6: 995-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 6 %%%%%: 995-block 1 branch 2 never executed branch 3 never executed #####: 996: free_suggestion(); %%%%%: 996-block 0 call 0 never executed unconditional 1 never executed -: 997:#endif 6: 998: int prev_prof, i, cur_prof = -1, total_profs = 0; 36: 999: for (i = 0; profile_names[i]; i++) { 6: 999-block 0 unconditional 0 taken 6 30: 999-block 1 unconditional 1 taken 30 36: 999-block 2 branch 2 taken 30 branch 3 taken 6 (fallthrough) 30: 1000: total_profs++; -: 1001: 30: 1002: if (!alt_profile) { 30: 1002-block 0 branch 0 taken 5 (fallthrough) branch 1 taken 25 5: 1003: if (*profile_names[i] == 'd' 5: 1003-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 4 1: 1004: && strcmp(profile_names[i], "default") == 0) { 1: 1004-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 0 1: 1005: cur_prof = i; 1: 1005-block 0 unconditional 0 taken 1 -: 1006: } -: 1007: } else { 25: 1008: if (*alt_profile == *profile_names[i] 25: 1008-block 0 branch 0 taken 11 (fallthrough) branch 1 taken 14 11: 1009: && strcmp(alt_profile, profile_names[i]) == 0) { 11: 1009-block 0 branch 0 taken 5 (fallthrough) branch 1 taken 6 5: 1010: cur_prof = i; 5: 1010-block 0 unconditional 0 taken 5 -: 1011: } -: 1012: } -: 1013: } -: 1014: 6: 1015: if (cur_prof == -1 || !profile_names[cur_prof]) 6: 1015-block 0 branch 0 taken 6 (fallthrough) branch 1 taken 0 6: 1015-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 6 #####: 1016: return EXIT_FAILURE; %%%%%: 1016-block 0 unconditional 0 never executed -: 1017: 6: 1018: prev_prof = cur_prof - 1; 6: 1019: total_profs--; -: 1020: 6: 1021: if (prev_prof < 0 || !profile_names[prev_prof]) 6: 1021-block 0 branch 0 taken 5 (fallthrough) branch 1 taken 1 5: 1021-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 5 1: 1022: prev_prof = total_profs; 1: 1022-block 0 unconditional 0 taken 1 -: 1023: 6: 1024: if (clear_screen) { 6: 1024-block 0 branch 0 taken 4 (fallthrough) branch 1 taken 2 4: 1025: CLEAR; 4: 1025-block 0 call 0 returned 4 unconditional 1 taken 4 -: 1026: } else 2: 1027: putchar('\n'); 2: 1027-block 0 call 0 returned 2 unconditional 1 taken 2 -: 1028: 6: 1029: if (profile_set(profile_names[prev_prof]) == EXIT_SUCCESS) { 6: 1029-block 0 call 0 returned 6 branch 1 taken 6 (fallthrough) branch 2 taken 0 6: 1030: printf(_("%s->%s Switched to profile '%s'\n"), mi_c, df_c, call 0 returned 6 6: 1031: profile_names[prev_prof]); 6: 1031-block 0 call 0 returned 6 6: 1032: char *input = prompt(); call 0 returned 6 6: 1033: free(input); unconditional 0 taken 6 -: 1034: } -: 1035: 6: 1036: return EXIT_SUCCESS; 6: 1036-block 0 unconditional 0 taken 6 -: 1037:} -: 1038: -: 1039:static int function rl_next_profile called 1 returned 100% blocks executed 72% 1: 1040:rl_next_profile(int count, int key) -: 1041:{ -: 1042: UNUSED(count); UNUSED(key); 1: 1043: if (kbind_busy) 1: 1043-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 1 #####: 1044: return EXIT_SUCCESS; %%%%%: 1044-block 0 unconditional 0 never executed -: 1045:#ifndef _NO_SUGGESTIONS 1*: 1046: if (suggestion.printed && suggestion_buf) 1: 1046-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 1 %%%%%: 1046-block 1 branch 2 never executed branch 3 never executed #####: 1047: free_suggestion(); %%%%%: 1047-block 0 call 0 never executed unconditional 1 never executed -: 1048:#endif 1: 1049: int next_prof, i, cur_prof = -1, total_profs = 0; 6: 1050: for (i = 0; profile_names[i]; i++) { 1: 1050-block 0 unconditional 0 taken 1 5: 1050-block 1 unconditional 1 taken 5 6: 1050-block 2 branch 2 taken 5 branch 3 taken 1 (fallthrough) 5: 1051: total_profs++; -: 1052: 5: 1053: if (!alt_profile) { 5: 1053-block 0 branch 0 taken 5 (fallthrough) branch 1 taken 0 5: 1054: if (*profile_names[i] == 'd' 5: 1054-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 4 1: 1055: && strcmp(profile_names[i], "default") == 0) { 1: 1055-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 0 1: 1056: cur_prof = i; 1: 1056-block 0 unconditional 0 taken 1 -: 1057: } -: 1058: } else { #####: 1059: if (*alt_profile == *profile_names[i] %%%%%: 1059-block 0 branch 0 never executed branch 1 never executed #####: 1060: && strcmp(alt_profile, profile_names[i]) == 0) { %%%%%: 1060-block 0 branch 0 never executed branch 1 never executed #####: 1061: cur_prof = i; %%%%%: 1061-block 0 unconditional 0 never executed -: 1062: } -: 1063: } -: 1064: } -: 1065: 1: 1066: if (cur_prof == -1 || !profile_names[cur_prof]) 1: 1066-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 0 1: 1066-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 1 #####: 1067: return EXIT_FAILURE; %%%%%: 1067-block 0 unconditional 0 never executed -: 1068: 1: 1069: next_prof = cur_prof + 1; 1: 1070: total_profs--; -: 1071: 1: 1072: if (next_prof > (int)total_profs || !profile_names[next_prof]) 1: 1072-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 0 1: 1072-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 1 #####: 1073: next_prof = 0; %%%%%: 1073-block 0 unconditional 0 never executed -: 1074: 1: 1075: if (clear_screen) { 1: 1075-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 1 #####: 1076: CLEAR; %%%%%: 1076-block 0 call 0 never executed unconditional 1 never executed -: 1077: } else 1: 1078: putchar('\n'); 1: 1078-block 0 call 0 returned 1 unconditional 1 taken 1 -: 1079: 1: 1080: if (profile_set(profile_names[next_prof]) == EXIT_SUCCESS) { 1: 1080-block 0 call 0 returned 1 branch 1 taken 1 (fallthrough) branch 2 taken 0 1: 1081: printf(_("%s->%s Switched to profile '%s'\n"), mi_c, df_c, call 0 returned 1 1: 1082: profile_names[next_prof]); 1: 1082-block 0 call 0 returned 1 1: 1083: char *input = prompt(); call 0 returned 1 1: 1084: free(input); unconditional 0 taken 1 -: 1085: } -: 1086: 1: 1087: return EXIT_SUCCESS; 1: 1087-block 0 unconditional 0 taken 1 -: 1088:} -: 1089: -: 1090:static int function rl_dirhist called 1 returned 100% blocks executed 100% 1: 1091:rl_dirhist(int count, int key) -: 1092:{ -: 1093: UNUSED(count); UNUSED(key); 1: 1094: return run_kb_cmd("bh"); 1: 1094-block 0 call 0 returned 1 -: 1095:} -: 1096: -: 1097:static int function rl_archive_sel called 1 returned 100% blocks executed 100% 1: 1098:rl_archive_sel(int count, int key) -: 1099:{ -: 1100: UNUSED(count); UNUSED(key); 1: 1101: return run_kb_cmd("ac sel"); 1: 1101-block 0 call 0 returned 1 -: 1102:} -: 1103: -: 1104:static int function rl_new_instance called 2 returned 100% blocks executed 100% 2: 1105:rl_new_instance(int count, int key) -: 1106:{ -: 1107: UNUSED(count); UNUSED(key); 2: 1108: return run_kb_cmd("x ."); 2: 1108-block 0 call 0 returned 2 -: 1109:} -: 1110: -: 1111:static int function rl_clear_msgs called 1 returned 100% blocks executed 100% 1: 1112:rl_clear_msgs(int count, int key) -: 1113:{ -: 1114: UNUSED(count); UNUSED(key); 1: 1115: return run_kb_cmd("msg clear"); 1: 1115-block 0 call 0 returned 1 -: 1116:} -: 1117: -: 1118:static int function rl_trash_sel called 1 returned 100% blocks executed 100% 1: 1119:rl_trash_sel(int count, int key) -: 1120:{ -: 1121: UNUSED(count); UNUSED(key); 1: 1122: return run_kb_cmd("t sel"); 1: 1122-block 0 call 0 returned 1 -: 1123:} -: 1124: -: 1125:static int function rl_untrash_all called 2 returned 100% blocks executed 100% 2: 1126:rl_untrash_all(int count, int key) -: 1127:{ -: 1128: UNUSED(count); UNUSED(key); 2: 1129: return run_kb_cmd("u *"); 2: 1129-block 0 call 0 returned 2 -: 1130:} -: 1131: -: 1132:static int function rl_open_sel called 2 returned 100% blocks executed 92% 2: 1133:rl_open_sel(int count, int key) -: 1134:{ -: 1135: UNUSED(count); UNUSED(key); 2: 1136: if (kbind_busy) 2: 1136-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 2 #####: 1137: return EXIT_SUCCESS; %%%%%: 1137-block 0 unconditional 0 never executed -: 1138: 2: 1139: if (sel_n == 0 || !sel_elements[sel_n - 1]) { 2: 1139-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 1 1: 1139-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 1 1: 1140: fprintf(stderr, _("\n%s: No selected files\n"), PROGRAM_NAME); 1: 1140-block 0 call 0 returned 1 call 1 returned 1 1: 1141: rl_reset_line_state(); call 0 returned 1 1: 1142: return EXIT_FAILURE; unconditional 0 taken 1 -: 1143: } -: 1144: -: 1145: char cmd[PATH_MAX + 3]; 1: 1146: sprintf(cmd, "o %s", sel_elements[sel_n - 1]); -: 1147: 1: 1148: keybind_exec_cmd(cmd); 1: 1148-block 0 call 0 returned 1 1: 1149: rl_reset_line_state(); call 0 returned 1 1: 1150: return EXIT_SUCCESS; unconditional 0 taken 1 -: 1151:} -: 1152: -: 1153:static int function rl_bm_sel called 1 returned 100% blocks executed 62% 1: 1154:rl_bm_sel(int count, int key) -: 1155:{ -: 1156: UNUSED(count); UNUSED(key); 1: 1157: if (kbind_busy) 1: 1157-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 1 #####: 1158: return EXIT_SUCCESS; %%%%%: 1158-block 0 unconditional 0 never executed -: 1159: 1: 1160: if (sel_n == 0 || !sel_elements[sel_n - 1]) { 1: 1160-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 0 1: 1160-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 1 #####: 1161: fprintf(stderr, _("\n%s: No selected files\n"), PROGRAM_NAME); %%%%%: 1161-block 0 call 0 never executed call 1 never executed #####: 1162: rl_reset_line_state(); call 0 never executed #####: 1163: return EXIT_FAILURE; unconditional 0 never executed -: 1164: } -: 1165: -: 1166: char cmd[PATH_MAX + 6]; 1: 1167: sprintf(cmd, "bm a %s", sel_elements[sel_n - 1]); -: 1168: 1: 1169: keybind_exec_cmd(cmd); 1: 1169-block 0 call 0 returned 1 1: 1170: rl_reset_line_state(); call 0 returned 1 1: 1171: return EXIT_SUCCESS; unconditional 0 taken 1 -: 1172:} -: 1173: -: 1174:static int function rl_kbinds_help called 1 returned 100% blocks executed 56% 1: 1175:rl_kbinds_help(int count, int key) -: 1176:{ -: 1177: UNUSED(count); UNUSED(key); -: 1178:#ifndef _NO_SUGGESTIONS 1*: 1179: if (suggestion.printed && suggestion_buf) 1: 1179-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 1 %%%%%: 1179-block 1 branch 2 never executed branch 3 never executed #####: 1180: free_suggestion(); %%%%%: 1180-block 0 call 0 never executed unconditional 1 never executed -: 1181:#endif -: 1182: 1: 1183: char *mp = (char *)NULL; 1: 1184: char *p = getenv("MANPAGER"); 1: 1184-block 0 call 0 returned 1 1: 1185: if (p) { branch 0 taken 0 (fallthrough) branch 1 taken 1 #####: 1186: mp = (char *)xnmalloc(strlen(p) + 1, sizeof(char *)); %%%%%: 1186-block 0 call 0 never executed #####: 1187: strcpy(mp, p); #####: 1188: unsetenv("MANPAGER"); call 0 never executed unconditional 1 never executed -: 1189: } -: 1190: char cmd[PATH_MAX]; 1: 1191: snprintf(cmd, PATH_MAX - 1, -: 1192: "export PAGER=\"less -p ^[0-9]+\\.[[:space:]]KEYBOARD[[:space:]]SHORTCUTS\"; man %s\n", -: 1193: PNL); 1: 1194: int ret = launch_execle(cmd) != EXIT_SUCCESS; 1: 1194-block 0 call 0 returned 1 -: 1195: 1: 1196: if (mp) { branch 0 taken 0 (fallthrough) branch 1 taken 1 #####: 1197: setenv("MANPAGER", mp, 1); %%%%%: 1197-block 0 call 0 never executed #####: 1198: free(mp); unconditional 0 never executed -: 1199: } -: 1200: 1: 1201: if (!ret) 1: 1201-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 0 1: 1202: return EXIT_FAILURE; 1: 1202-block 0 unconditional 0 taken 1 #####: 1203: return EXIT_SUCCESS; %%%%%: 1203-block 0 unconditional 0 never executed -: 1204:} -: 1205: -: 1206:static int function rl_cmds_help called 1 returned 100% blocks executed 56% 1: 1207:rl_cmds_help(int count, int key) -: 1208:{ -: 1209: UNUSED(count); UNUSED(key); -: 1210:#ifndef _NO_SUGGESTIONS 1*: 1211: if (suggestion.printed && suggestion_buf) 1: 1211-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 1 %%%%%: 1211-block 1 branch 2 never executed branch 3 never executed #####: 1212: free_suggestion(); %%%%%: 1212-block 0 call 0 never executed unconditional 1 never executed -: 1213:#endif -: 1214: 1: 1215: char *mp = (char *)NULL; 1: 1216: char *p = getenv("MANPAGER"); 1: 1216-block 0 call 0 returned 1 1: 1217: if (p) { branch 0 taken 0 (fallthrough) branch 1 taken 1 #####: 1218: mp = (char *)xnmalloc(strlen(p) + 1, sizeof(char *)); %%%%%: 1218-block 0 call 0 never executed #####: 1219: strcpy(mp, p); #####: 1220: unsetenv("MANPAGER"); call 0 never executed unconditional 1 never executed -: 1221: } -: 1222: char cmd[PATH_MAX]; 1: 1223: snprintf(cmd, PATH_MAX - 1, -: 1224: "export PAGER=\"less -p ^[0-9]+\\.[[:space:]]COMMANDS\"; man %s\n", -: 1225: PNL); 1: 1226: int ret = launch_execle(cmd) != EXIT_SUCCESS; 1: 1226-block 0 call 0 returned 1 -: 1227: 1: 1228: if (mp) { branch 0 taken 0 (fallthrough) branch 1 taken 1 #####: 1229: setenv("MANPAGER", mp, 1); %%%%%: 1229-block 0 call 0 never executed #####: 1230: free(mp); unconditional 0 never executed -: 1231: } -: 1232: 1: 1233: if (!ret) 1: 1233-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 0 1: 1234: return EXIT_FAILURE; 1: 1234-block 0 unconditional 0 taken 1 #####: 1235: return EXIT_SUCCESS; %%%%%: 1235-block 0 unconditional 0 never executed -: 1236:} -: 1237: -: 1238:static int function rl_manpage called 2 returned 100% blocks executed 89% 2: 1239:rl_manpage(int count, int key) -: 1240:{ -: 1241: UNUSED(count); UNUSED(key); -: 1242:#ifndef _NO_SUGGESTIONS 2: 1243: if (suggestion.printed && suggestion_buf) 2: 1243-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 1 1: 1243-block 1 branch 2 taken 1 (fallthrough) branch 3 taken 0 1: 1244: free_suggestion(); 1: 1244-block 0 call 0 returned 1 unconditional 1 taken 1 -: 1245:#endif 2: 1246: char *cmd[] = {"man", PNL, NULL}; 2: 1247: if (launch_execve(cmd, FOREGROUND, E_NOFLAG) != EXIT_SUCCESS) 2: 1247-block 0 call 0 returned 2 branch 1 taken 0 (fallthrough) branch 2 taken 2 #####: 1248: return EXIT_FAILURE; %%%%%: 1248-block 0 unconditional 0 never executed 2: 1249: return EXIT_SUCCESS; 2: 1249-block 0 unconditional 0 taken 2 -: 1250:} -: 1251: -: 1252:static int function rl_pinned_dir called 1 returned 100% blocks executed 43% 1: 1253:rl_pinned_dir(int count, int key) -: 1254:{ -: 1255: UNUSED(count); UNUSED(key); 1: 1256: if (!pinned_dir) { 1: 1256-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 1 #####: 1257: printf(_("%s: No pinned file\n"), PROGRAM_NAME); %%%%%: 1257-block 0 call 0 never executed call 1 never executed #####: 1258: rl_reset_line_state(); call 0 never executed #####: 1259: return EXIT_SUCCESS; unconditional 0 never executed -: 1260: } -: 1261: 1: 1262: return run_kb_cmd(","); 1: 1262-block 0 call 0 returned 1 unconditional 1 taken 1 -: 1263:} -: 1264: -: 1265:static int function rl_ws1 called 5 returned 100% blocks executed 100% 5: 1266:rl_ws1(int count, int key) -: 1267:{ -: 1268: UNUSED(count); UNUSED(key); 5: 1269: return run_kb_cmd("ws 1"); 5: 1269-block 0 call 0 returned 5 -: 1270:} -: 1271: -: 1272:static int function rl_ws2 called 5 returned 100% blocks executed 100% 5: 1273:rl_ws2(int count, int key) -: 1274:{ -: 1275: UNUSED(count); UNUSED(key); 5: 1276: return run_kb_cmd("ws 2"); 5: 1276-block 0 call 0 returned 5 -: 1277:} -: 1278: -: 1279:static int function rl_ws3 called 4 returned 100% blocks executed 100% 4: 1280:rl_ws3(int count, int key) -: 1281:{ -: 1282: UNUSED(count); UNUSED(key); 4: 1283: return run_kb_cmd("ws 3"); 4: 1283-block 0 call 0 returned 4 -: 1284:} -: 1285: -: 1286:static int function rl_ws4 called 2 returned 100% blocks executed 100% 2: 1287:rl_ws4(int count, int key) -: 1288:{ -: 1289: UNUSED(count); UNUSED(key); 2: 1290: return run_kb_cmd("ws 4"); 2: 1290-block 0 call 0 returned 2 -: 1291:} -: 1292: -: 1293:static int function rl_plugin1 called 0 returned 0% blocks executed 0% #####: 1294:rl_plugin1(int count, int key) -: 1295:{ -: 1296: UNUSED(count); UNUSED(key); #####: 1297: return run_kb_cmd("plugin1"); %%%%%: 1297-block 0 call 0 never executed -: 1298:} -: 1299: -: 1300:static int function rl_plugin2 called 0 returned 0% blocks executed 0% #####: 1301:rl_plugin2(int count, int key) -: 1302:{ -: 1303: UNUSED(count); UNUSED(key); #####: 1304: return run_kb_cmd("plugin2"); %%%%%: 1304-block 0 call 0 never executed -: 1305:} -: 1306: -: 1307:static int function rl_plugin3 called 0 returned 0% blocks executed 0% #####: 1308:rl_plugin3(int count, int key) -: 1309:{ -: 1310: UNUSED(count); UNUSED(key); #####: 1311: return run_kb_cmd("plugin3"); %%%%%: 1311-block 0 call 0 never executed -: 1312:} -: 1313: -: 1314:static int function rl_plugin4 called 0 returned 0% blocks executed 0% #####: 1315:rl_plugin4(int count, int key) -: 1316:{ -: 1317: UNUSED(count); UNUSED(key); #####: 1318: return run_kb_cmd("plugin4"); %%%%%: 1318-block 0 call 0 never executed -: 1319:} -: 1320: -: 1321:static int function rl_onlydirs called 0 returned 0% blocks executed 0% #####: 1322:rl_onlydirs(int count, int key) -: 1323:{ -: 1324: UNUSED(count); UNUSED(key); -: 1325: #####: 1326: if (kbind_busy) %%%%%: 1326-block 0 branch 0 never executed branch 1 never executed #####: 1327: return EXIT_SUCCESS; %%%%%: 1327-block 0 unconditional 0 never executed -: 1328: #####: 1329: only_dirs = only_dirs ? 0 : 1; -: 1330: #####: 1331: int exit_status = EXIT_SUCCESS; #####: 1332: if (cd_lists_on_the_fly) { %%%%%: 1332-block 0 branch 0 never executed branch 1 never executed #####: 1333: if (clear_screen) %%%%%: 1333-block 0 branch 0 never executed branch 1 never executed #####: 1334: CLEAR; %%%%%: 1334-block 0 call 0 never executed unconditional 1 never executed #####: 1335: free_dirlist(); %%%%%: 1335-block 0 call 0 never executed #####: 1336: putchar('\n'); call 0 never executed #####: 1337: exit_status = list_dir(); call 0 never executed unconditional 1 never executed -: 1338: } else { #####: 1339: printf(_("%s: List only directories set to %s\n"), %%%%%: 1339-block 0 call 0 never executed call 1 never executed unconditional 2 never executed #####: 1340: PROGRAM_NAME, only_dirs ? _("true"): _("false")); %%%%%: 1340-block 0 branch 0 never executed branch 1 never executed %%%%%: 1340-block 1 call 2 never executed unconditional 3 never executed %%%%%: 1340-block 2 call 4 never executed unconditional 5 never executed -: 1341: } -: 1342: #####: 1343: rl_reset_line_state(); %%%%%: 1343-block 0 call 0 never executed #####: 1344: return exit_status; unconditional 0 never executed -: 1345:} -: 1346: -: 1347:/*static int -: 1348:rl_test(int count, int key) -: 1349:{ -: 1350: UNUSED(count); UNUSED(key); -: 1351: printf("test\n"); -: 1352: return EXIT_SUCCESS; -: 1353:} */ -: 1354: -: 1355:/* -: 1356:void -: 1357:add_func_to_rl(void) -: 1358:{ -: 1359: rl_add_defun("my-test", rl_test, -1); -: 1360:} */ -: 1361: -: 1362:/* To get the keyseq value for a given key do this in an Xterm terminal: -: 1363: * C-v and then press the key (or the key combination). So, for example, -: 1364: * C-v, C-right arrow gives "[[1;5C", which here should be written like -: 1365: * this: -: 1366: * "\\x1b[1;5C" */ -: 1367:void function readline_kbinds called 4 returned 100% blocks executed 70% 4: 1368:readline_kbinds(void) -: 1369:{ -: 1370: -: 1371: /* ############################## -: 1372: * # KEYBINDINGS # -: 1373: * ##############################*/ -: 1374: 4: 1375: if (kbinds_file) { 4: 1375-block 0 branch 0 taken 4 (fallthrough) branch 1 taken 0 -: 1376: /* Help */ 4: 1377: rl_bind_keyseq(find_key("show-manpage"), rl_manpage); 4: 1377-block 0 call 0 returned 4 call 1 returned 4 4: 1378: rl_bind_keyseq(find_key("show-manpage2"), rl_manpage); call 0 returned 4 call 1 returned 4 4: 1379: rl_bind_keyseq(find_key("show-cmds"), rl_cmds_help); call 0 returned 4 call 1 returned 4 4: 1380: rl_bind_keyseq(find_key("show-cmds2"), rl_cmds_help); call 0 returned 4 call 1 returned 4 4: 1381: rl_bind_keyseq(find_key("show-kbinds"), rl_kbinds_help); call 0 returned 4 call 1 returned 4 4: 1382: rl_bind_keyseq(find_key("show-kbinds2"), rl_kbinds_help); call 0 returned 4 call 1 returned 4 -: 1383: -: 1384: /* Navigation */ -: 1385: /* Define multiple keybinds for different terminals: -: 1386: * rxvt, xterm, kernel console */ -: 1387: /* rl_bind_keyseq("\\M-[D", rl_test); // Left arrow key -: 1388: rl_bind_keyseq("\\M-+", rl_test); */ 4: 1389: rl_bind_keyseq(find_key("parent-dir"), rl_parent_dir); call 0 returned 4 call 1 returned 4 4: 1390: rl_bind_keyseq(find_key("parent-dir2"), rl_parent_dir); call 0 returned 4 call 1 returned 4 4: 1391: rl_bind_keyseq(find_key("parent-dir3"), rl_parent_dir); call 0 returned 4 call 1 returned 4 4: 1392: rl_bind_keyseq(find_key("parent-dir4"), rl_parent_dir); call 0 returned 4 call 1 returned 4 4: 1393: rl_bind_keyseq(find_key("previous-dir"), rl_previous_dir); call 0 returned 4 call 1 returned 4 4: 1394: rl_bind_keyseq(find_key("previous-dir2"), rl_previous_dir); call 0 returned 4 call 1 returned 4 4: 1395: rl_bind_keyseq(find_key("previous-dir3"), rl_previous_dir); call 0 returned 4 call 1 returned 4 4: 1396: rl_bind_keyseq(find_key("previous-dir4"), rl_previous_dir); call 0 returned 4 call 1 returned 4 4: 1397: rl_bind_keyseq(find_key("next-dir"), rl_next_dir); call 0 returned 4 call 1 returned 4 4: 1398: rl_bind_keyseq(find_key("next-dir2"), rl_next_dir); call 0 returned 4 call 1 returned 4 4: 1399: rl_bind_keyseq(find_key("next-dir3"), rl_next_dir); call 0 returned 4 call 1 returned 4 4: 1400: rl_bind_keyseq(find_key("next-dir4"), rl_next_dir); call 0 returned 4 call 1 returned 4 4: 1401: rl_bind_keyseq(find_key("home-dir"), rl_home_dir); call 0 returned 4 call 1 returned 4 4: 1402: rl_bind_keyseq(find_key("home-dir2"), rl_home_dir); call 0 returned 4 call 1 returned 4 4: 1403: rl_bind_keyseq(find_key("home-dir3"), rl_home_dir); call 0 returned 4 call 1 returned 4 4: 1404: rl_bind_keyseq(find_key("home-dir4"), rl_home_dir); call 0 returned 4 call 1 returned 4 4: 1405: rl_bind_keyseq(find_key("root-dir"), rl_root_dir); call 0 returned 4 call 1 returned 4 4: 1406: rl_bind_keyseq(find_key("root-dir2"), rl_root_dir); call 0 returned 4 call 1 returned 4 4: 1407: rl_bind_keyseq(find_key("root-dir3"), rl_root_dir); call 0 returned 4 call 1 returned 4 4: 1408: rl_bind_keyseq(find_key("first-dir"), rl_first_dir); call 0 returned 4 call 1 returned 4 4: 1409: rl_bind_keyseq(find_key("last-dir"), rl_last_dir); call 0 returned 4 call 1 returned 4 4: 1410: rl_bind_keyseq(find_key("pinned-dir"), rl_pinned_dir); call 0 returned 4 call 1 returned 4 4: 1411: rl_bind_keyseq(find_key("workspace1"), rl_ws1); call 0 returned 4 call 1 returned 4 4: 1412: rl_bind_keyseq(find_key("workspace2"), rl_ws2); call 0 returned 4 call 1 returned 4 4: 1413: rl_bind_keyseq(find_key("workspace3"), rl_ws3); call 0 returned 4 call 1 returned 4 4: 1414: rl_bind_keyseq(find_key("workspace4"), rl_ws4); call 0 returned 4 call 1 returned 4 -: 1415: -: 1416: /* Operations on files */ 4: 1417: rl_bind_keyseq(find_key("create-file"), rl_create_file); call 0 returned 4 call 1 returned 4 4: 1418: rl_bind_keyseq(find_key("bookmark-sel"), rl_bm_sel); call 0 returned 4 call 1 returned 4 4: 1419: rl_bind_keyseq(find_key("archive-sel"), rl_archive_sel); call 0 returned 4 call 1 returned 4 4: 1420: rl_bind_keyseq(find_key("open-sel"), rl_open_sel); call 0 returned 4 call 1 returned 4 4: 1421: rl_bind_keyseq(find_key("export-sel"), rl_export_sel); call 0 returned 4 call 1 returned 4 4: 1422: rl_bind_keyseq(find_key("move-sel"), rl_move_sel); call 0 returned 4 call 1 returned 4 4: 1423: rl_bind_keyseq(find_key("rename-sel"), rl_rename_sel); call 0 returned 4 call 1 returned 4 4: 1424: rl_bind_keyseq(find_key("remove-sel"), rl_remove_sel); call 0 returned 4 call 1 returned 4 4: 1425: rl_bind_keyseq(find_key("trash-sel"), rl_trash_sel); call 0 returned 4 call 1 returned 4 4: 1426: rl_bind_keyseq(find_key("untrash-all"), rl_untrash_all); call 0 returned 4 call 1 returned 4 4: 1427: rl_bind_keyseq(find_key("paste-sel"), rl_paste_sel); call 0 returned 4 call 1 returned 4 4: 1428: rl_bind_keyseq(find_key("select-all"), rl_select_all); call 0 returned 4 call 1 returned 4 4: 1429: rl_bind_keyseq(find_key("deselect-all"), rl_deselect_all); call 0 returned 4 call 1 returned 4 -: 1430: -: 1431: /* Config files */ 4: 1432: rl_bind_keyseq(find_key("open-mime"), rl_open_mime); call 0 returned 4 call 1 returned 4 4: 1433: rl_bind_keyseq(find_key("open-jump-db"), rl_open_jump_db); call 0 returned 4 call 1 returned 4 4: 1434: rl_bind_keyseq(find_key("edit-color-scheme"), rl_open_cscheme); call 0 returned 4 call 1 returned 4 4: 1435: rl_bind_keyseq(find_key("open-config"), rl_open_config); call 0 returned 4 call 1 returned 4 4: 1436: rl_bind_keyseq(find_key("open-keybinds"), rl_open_keybinds); call 0 returned 4 call 1 returned 4 4: 1437: rl_bind_keyseq(find_key("open-bookmarks"), rl_open_bm_file); call 0 returned 4 call 1 returned 4 -: 1438: -: 1439: /* Settings */ 4: 1440: rl_bind_keyseq(find_key("clear-msgs"), rl_clear_msgs); call 0 returned 4 call 1 returned 4 4: 1441: rl_bind_keyseq(find_key("next-profile"), rl_next_profile); call 0 returned 4 call 1 returned 4 4: 1442: rl_bind_keyseq(find_key("previous-profile"), rl_previous_profile); call 0 returned 4 call 1 returned 4 4: 1443: rl_bind_keyseq(find_key("quit"), rl_quit); call 0 returned 4 call 1 returned 4 4: 1444: rl_bind_keyseq(find_key("lock"), rl_lock); call 0 returned 4 call 1 returned 4 4: 1445: rl_bind_keyseq(find_key("refresh-screen"), rl_refresh); call 0 returned 4 call 1 returned 4 4: 1446: rl_bind_keyseq(find_key("clear-line"), rl_clear_line); call 0 returned 4 call 1 returned 4 4: 1447: rl_bind_keyseq(find_key("toggle-hidden"), rl_hidden); call 0 returned 4 call 1 returned 4 4: 1448: rl_bind_keyseq(find_key("toggle-hidden2"), rl_hidden); call 0 returned 4 call 1 returned 4 4: 1449: rl_bind_keyseq(find_key("toggle-long"), rl_long); call 0 returned 4 call 1 returned 4 4: 1450: rl_bind_keyseq(find_key("toggle-light"), rl_light); call 0 returned 4 call 1 returned 4 4: 1451: rl_bind_keyseq(find_key("folders-first"), rl_folders_first); call 0 returned 4 call 1 returned 4 4: 1452: rl_bind_keyseq(find_key("sort-previous"), rl_sort_previous); call 0 returned 4 call 1 returned 4 4: 1453: rl_bind_keyseq(find_key("sort-next"), rl_sort_next); call 0 returned 4 call 1 returned 4 4: 1454: rl_bind_keyseq(find_key("only-dirs"), rl_onlydirs); call 0 returned 4 call 1 returned 4 -: 1455: 4: 1456: rl_bind_keyseq(find_key("new-instance"), rl_new_instance); call 0 returned 4 call 1 returned 4 4: 1457: rl_bind_keyseq(find_key("show-dirhist"), rl_dirhist); call 0 returned 4 call 1 returned 4 4: 1458: rl_bind_keyseq(find_key("bookmarks"), rl_bookmarks); call 0 returned 4 call 1 returned 4 4: 1459: rl_bind_keyseq(find_key("mountpoints"), rl_mountpoints); call 0 returned 4 call 1 returned 4 4: 1460: rl_bind_keyseq(find_key("selbox"), rl_selbox); call 0 returned 4 call 1 returned 4 4: 1461: rl_bind_keyseq(find_key("prepend-sudo"), rl_prepend_sudo); call 0 returned 4 call 1 returned 4 -: 1462: -: 1463: /* Plugins */ 4: 1464: rl_bind_keyseq(find_key("plugin1"), rl_plugin1); call 0 returned 4 call 1 returned 4 4: 1465: rl_bind_keyseq(find_key("plugin2"), rl_plugin2); call 0 returned 4 call 1 returned 4 4: 1466: rl_bind_keyseq(find_key("plugin3"), rl_plugin3); call 0 returned 4 call 1 returned 4 4: 1467: rl_bind_keyseq(find_key("plugin4"), rl_plugin4); call 0 returned 4 call 1 returned 4 -: 1468: 4: 1469: rl_bind_keyseq(find_key("quit"), rl_quit); call 0 returned 4 call 1 returned 4 unconditional 2 taken 4 -: 1470: } -: 1471: -: 1472: /* If no kbinds file is found, set the defaults */ -: 1473: else { -: 1474: /* Help */ #####: 1475: rl_bind_keyseq("\\eOP", rl_manpage); %%%%%: 1475-block 0 call 0 never executed #####: 1476: rl_bind_keyseq("\\eOQ", rl_cmds_help); call 0 never executed #####: 1477: rl_bind_keyseq("\\eOR", rl_kbinds_help); call 0 never executed #####: 1478: rl_bind_keyseq("\\e[11~", rl_manpage); call 0 never executed #####: 1479: rl_bind_keyseq("\\e[12~", rl_cmds_help); call 0 never executed #####: 1480: rl_bind_keyseq("\\e[13~", rl_kbinds_help); call 0 never executed -: 1481: -: 1482: /* Navigation */ #####: 1483: rl_bind_keyseq("\\M-u", rl_parent_dir); call 0 never executed #####: 1484: rl_bind_keyseq("\\e[a", rl_parent_dir); call 0 never executed #####: 1485: rl_bind_keyseq("\\e[2A", rl_parent_dir); call 0 never executed #####: 1486: rl_bind_keyseq("\\e[1;2A", rl_parent_dir); call 0 never executed #####: 1487: rl_bind_keyseq("\\M-j", rl_previous_dir); call 0 never executed #####: 1488: rl_bind_keyseq("\\e[d", rl_previous_dir); call 0 never executed #####: 1489: rl_bind_keyseq("\\e[2D", rl_previous_dir); call 0 never executed #####: 1490: rl_bind_keyseq("\\e[1;2D", rl_previous_dir); call 0 never executed #####: 1491: rl_bind_keyseq("\\M-k", rl_next_dir); call 0 never executed #####: 1492: rl_bind_keyseq("\\e[c", rl_next_dir); call 0 never executed #####: 1493: rl_bind_keyseq("\\e[2C", rl_next_dir); call 0 never executed #####: 1494: rl_bind_keyseq("\\e[1;2C", rl_next_dir); call 0 never executed #####: 1495: rl_bind_keyseq("\\M-e", rl_home_dir); call 0 never executed #####: 1496: rl_bind_keyseq("\\e[1~", rl_home_dir); call 0 never executed #####: 1497: rl_bind_keyseq("\\e[7~", rl_home_dir); call 0 never executed #####: 1498: rl_bind_keyseq("\\e[H", rl_home_dir); call 0 never executed #####: 1499: rl_bind_keyseq("\\M-r", rl_root_dir); call 0 never executed #####: 1500: rl_bind_keyseq("\\e/", rl_root_dir); call 0 never executed #####: 1501: rl_bind_keyseq("\\C-\\M-j", rl_first_dir); call 0 never executed #####: 1502: rl_bind_keyseq("\\C-\\M-k", rl_last_dir); call 0 never executed #####: 1503: rl_bind_keyseq("\\M-p", rl_pinned_dir); call 0 never executed #####: 1504: rl_bind_keyseq("\\M-1", rl_ws1); call 0 never executed #####: 1505: rl_bind_keyseq("\\M-2", rl_ws2); call 0 never executed #####: 1506: rl_bind_keyseq("\\M-3", rl_ws3); call 0 never executed #####: 1507: rl_bind_keyseq("\\M-4", rl_ws4); call 0 never executed -: 1508: -: 1509: /* Operations on files */ #####: 1510: rl_bind_keyseq("\\M-n", rl_create_file); call 0 never executed #####: 1511: rl_bind_keyseq("\\C-\\M-b", rl_bm_sel); call 0 never executed #####: 1512: rl_bind_keyseq("\\C-\\M-a", rl_archive_sel); call 0 never executed #####: 1513: rl_bind_keyseq("\\C-\\M-g", rl_open_sel); call 0 never executed #####: 1514: rl_bind_keyseq("\\C-\\M-e", rl_export_sel); call 0 never executed #####: 1515: rl_bind_keyseq("\\C-\\M-n", rl_move_sel); call 0 never executed #####: 1516: rl_bind_keyseq("\\C-\\M-r", rl_rename_sel); call 0 never executed #####: 1517: rl_bind_keyseq("\\C-\\M-d", rl_remove_sel); call 0 never executed #####: 1518: rl_bind_keyseq("\\C-\\M-t", rl_trash_sel); call 0 never executed #####: 1519: rl_bind_keyseq("\\C-\\M-u", rl_untrash_all); call 0 never executed #####: 1520: rl_bind_keyseq("\\C-\\M-v", rl_paste_sel); call 0 never executed #####: 1521: rl_bind_keyseq("\\M-a", rl_select_all); call 0 never executed #####: 1522: rl_bind_keyseq("\\M-d", rl_deselect_all); call 0 never executed #####: 1523: rl_bind_keyseq("\\M-v", rl_prepend_sudo); call 0 never executed -: 1524: -: 1525: /* Config files */ #####: 1526: rl_bind_keyseq("\\e[17~", rl_open_mime); call 0 never executed #####: 1527: rl_bind_keyseq("\\e[18~", rl_open_jump_db); call 0 never executed #####: 1528: rl_bind_keyseq("\\e[19~", rl_open_cscheme); call 0 never executed #####: 1529: rl_bind_keyseq("\\e[20~", rl_open_keybinds); call 0 never executed #####: 1530: rl_bind_keyseq("\\e[21~", rl_open_config); call 0 never executed #####: 1531: rl_bind_keyseq("\\e[23~", rl_open_bm_file); call 0 never executed -: 1532: -: 1533: /* Settings */ #####: 1534: rl_bind_keyseq("\\M-t", rl_clear_msgs); call 0 never executed -: 1535: /* rl_bind_keyseq("", rl_next_profile); -: 1536: rl_bind_keyseq("", rl_previous_profile); */ #####: 1537: rl_bind_keyseq("\\M-o", rl_lock); call 0 never executed #####: 1538: rl_bind_keyseq("\\C-r", rl_refresh); call 0 never executed #####: 1539: rl_bind_keyseq("\\M-c", rl_clear_line); call 0 never executed #####: 1540: rl_bind_keyseq("\\M-i", rl_hidden); call 0 never executed #####: 1541: rl_bind_keyseq("\\M-.", rl_hidden); call 0 never executed #####: 1542: rl_bind_keyseq("\\M-l", rl_long); call 0 never executed #####: 1543: rl_bind_keyseq("\\M-y", rl_light); call 0 never executed #####: 1544: rl_bind_keyseq("\\M-g", rl_folders_first); call 0 never executed #####: 1545: rl_bind_keyseq("\\M-z", rl_sort_previous); call 0 never executed #####: 1546: rl_bind_keyseq("\\M-x", rl_sort_next); call 0 never executed #####: 1547: rl_bind_keyseq("\\M-,", rl_onlydirs); call 0 never executed -: 1548: #####: 1549: rl_bind_keyseq("\\C-x", rl_new_instance); call 0 never executed #####: 1550: rl_bind_keyseq("\\M-h", rl_dirhist); call 0 never executed #####: 1551: rl_bind_keyseq("\\M-b", rl_bookmarks); call 0 never executed #####: 1552: rl_bind_keyseq("\\M-m", rl_mountpoints); call 0 never executed #####: 1553: rl_bind_keyseq("\\M-s", rl_selbox); call 0 never executed -: 1554: #####: 1555: rl_bind_keyseq("\\e[24~", rl_quit); call 0 never executed unconditional 1 never executed -: 1556: } -: 1557: -: 1558:/* char *term = getenv("TERM"); -: 1559: tgetent(NULL, term); -: 1560: char *_right_arrow = tgetstr("nd", NULL); -: 1561: char *s_right_arrow = tgetstr("%i", NULL); -: 1562: char *s_left_arrow = tgetstr("#4", NULL); */ -: 1563: -: 1564: /* Bind Right arrow key and Ctrl-f to accept the whole suggestion */ -: 1565:/* rl_bind_keyseq(_right_arrow, rl_accept_suggestion); -: 1566: rl_bind_key(6, rl_accept_suggestion); -: 1567: rl_bind_keyseq(s_left_arrow, rl_previous_dir); -: 1568: rl_bind_keyseq(s_right_arrow, rl_next_dir); */ -: 1569: -: 1570:#ifndef _NO_SUGGESTIONS -: 1571:#ifndef __HAIKU__ 4: 1572: rl_bind_keyseq("\\C-f", rl_accept_suggestion); 4: 1572-block 0 call 0 returned 4 4: 1573: rl_bind_keyseq("\x1b[C", rl_accept_suggestion); call 0 returned 4 4: 1574: rl_bind_keyseq("\x1bOC", rl_accept_suggestion); call 0 returned 4 -: 1575: -: 1576: /* Bind Alt-Right and Alt-f to accept the first suggested word */ -: 1577:/* rl_bind_key(('f' | 0200), rl_accept_first_word); */ // Alt-f 4: 1578: rl_bind_keyseq("\x1b\x66", rl_accept_first_word); call 0 returned 4 4: 1579: rl_bind_keyseq("\x1b[3C", rl_accept_first_word); call 0 returned 4 4: 1580: rl_bind_keyseq("\x1b\x1b[C", rl_accept_first_word); call 0 returned 4 4: 1581: rl_bind_keyseq("\x1b[1;3C", rl_accept_first_word); call 0 returned 4 -: 1582:#else -: 1583: rl_bind_keyseq("\x1bOC", rl_accept_suggestion); -: 1584: rl_bind_keyseq("\\C-f", rl_accept_first_word); -: 1585:#endif /* __HAIKU__ */ -: 1586:#endif /* !_NO_SUGGESTIONS */ 4: 1587:} clifm-1.26.3/misc/codecov/listing.c.gcov000066400000000000000000004167421506632037700200530ustar00rootroot00000000000000 -: 0:Source:listing.c -: 1:/* listing.c -- functions controlling what is listed on the screen */ -: 2: -: 3:/* -: 4: * This file is part of CliFM -: 5: * -: 6: * Copyright (C) 2016-2021, L. Abramovich -: 7: * All rights reserved. -: 8: -: 9: * CliFM is free software; you can redistribute it and/or modify -: 10: * it under the terms of the GNU General Public License as published by -: 11: * the Free Software Foundation; either version 2 of the License, or -: 12: * (at your option) any later version. -: 13: * -: 14: * CliFM is distributed in the hope that it will be useful, -: 15: * but WITHOUT ANY WARRANTY; without even the implied warranty of -: 16: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -: 17: * GNU General Public License for more details. -: 18: * -: 19: * You should have received a copy of the GNU General Public License -: 20: * along with this program; if not, write to the Free Software -: 21: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, -: 22: * MA 02110-1301, USA. -: 23:*/ -: 24: -: 25:#include "helpers.h" -: 26: -: 27:#include -: 28:#include -: 29:#include -: 30:#include -: 31:#include -: 32:#ifdef __linux__ -: 33:#include -: 34:#endif -: 35:#include -: 36:#include -: 37:#include -: 38:#include -: 39:#include -: 40: -: 41:#ifdef _LIST_SPEED -: 42:#include -: 43:#endif -: 44: -: 45:#ifdef TOURBIN_QSORT -: 46:#include "qsort.h" -: 47:#define ENTLESS(i, j) (entrycmp(file_info + (i), file_indo + (j)) < 0) -: 48:#define ENTSWAP(i, j) (swap_ent((i), (j))) -: 49:#define ENTSORT(file_info, n, entrycmp) QSORT((n), ENTLESS, ENTSWAP) -: 50:#else -: 51:#define ENTSORT(file_info, n, entrycmp) qsort((file_info), (n), sizeof(*(file_info)), (entrycmp)) -: 52:#endif -: 53: -: 54:#include "aux.h" -: 55:#include "colors.h" -: 56:#include "misc.h" -: 57:#include "properties.h" -: 58:#include "sort.h" -: 59: -: 60:#include "checks.h" -: 61: -: 62:#ifndef _NO_ICONS -: 63:#include "icons.h" -: 64:#endif -: 65: -: 66:#ifdef _PALAND_PRINTF -: 67:#include "printf.h" -: 68:#define xprintf printf_ -: 69:#else -: 70:#define xprintf printf -: 71:#endif -: 72: -: 73:static void function print_sort_method called 22 returned 100% blocks executed 76% 22: 74:print_sort_method(void) -: 75:{ 22: 76: printf(_("%s->%s Sorted by: "), mi_c, df_c); 22: 76-block 0 call 0 returned 22 call 1 returned 22 -: 77: 22: 78: switch (sort) { branch 0 taken 2 branch 1 taken 8 branch 2 taken 3 branch 3 taken 1 branch 4 taken 1 branch 5 taken 1 branch 6 taken 1 branch 7 taken 1 branch 8 taken 1 branch 9 taken 1 branch 10 taken 1 branch 11 taken 1 branch 12 taken 0 2: 79: case SNONE: 2: 80: puts(_("none")); 2: 80-block 0 call 0 returned 2 call 1 returned 2 2: 81: break; unconditional 0 taken 2 8: 82: case SNAME: 8: 83: printf(_("name %s\n"), (sort_reverse) ? "[rev]" : ""); 8: 83-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 6 2: 83-block 1 unconditional 2 taken 2 6: 83-block 2 unconditional 3 taken 6 8: 83-block 3 call 4 returned 8 call 5 returned 8 8: 84: break; unconditional 0 taken 8 3: 85: case SSIZE: 3*: 86: printf(_("size %s\n"), (sort_reverse) ? "[rev]" : ""); 3: 86-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 3 %%%%%: 86-block 1 unconditional 2 never executed 3: 86-block 2 unconditional 3 taken 3 3: 86-block 3 call 4 returned 3 call 5 returned 3 3: 87: break; unconditional 0 taken 3 1: 88: case SATIME: 1*: 89: printf(_("atime %s\n"), (sort_reverse) ? "[rev]" : ""); 1: 89-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 1 %%%%%: 89-block 1 unconditional 2 never executed 1: 89-block 2 unconditional 3 taken 1 1: 89-block 3 call 4 returned 1 call 5 returned 1 1: 90: break; unconditional 0 taken 1 1: 91: case SBTIME: -: 92:#if defined(HAVE_ST_BIRTHTIME) || defined(__BSD_VISIBLE) || defined(_STATX) 1*: 93: printf(_("btime %s\n"), (sort_reverse) ? "[rev]" : ""); 1: 93-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 1 %%%%%: 93-block 1 unconditional 2 never executed 1: 93-block 2 unconditional 3 taken 1 1: 93-block 3 call 4 returned 1 call 5 returned 1 -: 94:#else -: 95: printf(_("btime (not available: using 'ctime') %s\n"), -: 96: (sort_reverse) ? "[rev]" : ""); -: 97:#endif 1: 98: break; unconditional 0 taken 1 1: 99: case SCTIME: 1*: 100: printf(_("ctime %s\n"), (sort_reverse) ? "[rev]" : ""); 1: 100-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 1 %%%%%: 100-block 1 unconditional 2 never executed 1: 100-block 2 unconditional 3 taken 1 1: 100-block 3 call 4 returned 1 call 5 returned 1 1: 101: break; unconditional 0 taken 1 1: 102: case SMTIME: 1*: 103: printf(_("mtime %s\n"), (sort_reverse) ? "[rev]" : ""); 1: 103-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 1 %%%%%: 103-block 1 unconditional 2 never executed 1: 103-block 2 unconditional 3 taken 1 1: 103-block 3 call 4 returned 1 call 5 returned 1 1: 104: break; unconditional 0 taken 1 -: 105:#if __FreeBSD__ || __NetBSD__ || __OpenBSD__ || _BE_POSIX -: 106: case SVER: -: 107: printf(_("version (not available: using 'name') %s\n"), -: 108: (sort_reverse) ? "[rev]" : ""); -: 109:#else 1: 110: case SVER: 1*: 111: printf(_("version %s\n"), (sort_reverse) ? "[rev]" : ""); 1: 111-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 1 %%%%%: 111-block 1 unconditional 2 never executed 1: 111-block 2 unconditional 3 taken 1 1: 111-block 3 call 4 returned 1 call 5 returned 1 -: 112:#endif 1: 113: break; unconditional 0 taken 1 1: 114: case SEXT: 1*: 115: printf(_("extension %s\n"), (sort_reverse) ? "[rev]" : ""); 1: 115-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 1 %%%%%: 115-block 1 unconditional 2 never executed 1: 115-block 2 unconditional 3 taken 1 1: 115-block 3 call 4 returned 1 call 5 returned 1 1: 116: break; unconditional 0 taken 1 1: 117: case SINO: 1*: 118: printf(_("inode %s\n"), (sort_reverse) ? "[rev]" : ""); 1: 118-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 1 %%%%%: 118-block 1 unconditional 2 never executed 1: 118-block 2 unconditional 3 taken 1 1: 118-block 3 call 4 returned 1 call 5 returned 1 1: 119: break; unconditional 0 taken 1 1: 120: case SOWN: 1: 121: if (light_mode) { 1: 121-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 1 #####: 122: printf(_("owner (not available: using 'name') %s\n"), %%%%%: 122-block 0 unconditional 0 never executed %%%%%: 122-block 1 unconditional 1 never executed %%%%%: 122-block 2 call 2 never executed call 3 never executed unconditional 4 never executed #####: 123: (sort_reverse) ? "[rev]" : ""); %%%%%: 123-block 0 branch 0 never executed branch 1 never executed -: 124: } else { 1*: 125: printf(_("owner %s\n"), (sort_reverse) ? "[rev]" : ""); 1: 125-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 1 %%%%%: 125-block 1 unconditional 2 never executed 1: 125-block 2 unconditional 3 taken 1 1: 125-block 3 call 4 returned 1 call 5 returned 1 unconditional 6 taken 1 -: 126: } 1: 127: break; 1: 127-block 0 unconditional 0 taken 1 1: 128: case SGRP: 1: 129: if (light_mode) { 1: 129-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 1 #####: 130: printf(_("group (not available: using 'name') %s\n"), %%%%%: 130-block 0 unconditional 0 never executed %%%%%: 130-block 1 unconditional 1 never executed %%%%%: 130-block 2 call 2 never executed call 3 never executed unconditional 4 never executed #####: 131: (sort_reverse) ? "[rev]" : ""); %%%%%: 131-block 0 branch 0 never executed branch 1 never executed -: 132: } else { 1*: 133: printf(_("group %s\n"), (sort_reverse) ? "[rev]" : ""); 1: 133-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 1 %%%%%: 133-block 1 unconditional 2 never executed 1: 133-block 2 unconditional 3 taken 1 1: 133-block 3 call 4 returned 1 call 5 returned 1 unconditional 6 taken 1 -: 134: } 1: 135: break; 1: 135-block 0 unconditional 0 taken 1 -: 136: } 22: 137:} -: 138: -: 139:/* Print the line divinding files and prompt using DIV_LINE_CHAR. If -: 140: * DIV_LINE_CHAR takes more than two columns to be printed (ASCII chars -: 141: * take only one, but unicode chars could take two), print exactly the -: 142: * content of DIV_LINE_CHAR. Otherwise, repeat DIV_LINE_CHAR to fulfill -: 143: * all terminal columns. */ -: 144:static void function print_div_line called 305 returned 100% blocks executed 100% 305: 145:print_div_line(void) -: 146:{ 305: 147: fputs(dl_c, stdout); 305: 147-block 0 call 0 returned 305 -: 148: 305: 149: size_t len = wc_xstrlen(div_line_char); call 0 returned 305 305: 150: if (len <= 2) { branch 0 taken 7 (fallthrough) branch 1 taken 298 -: 151: int i; 532: 152: for (i = (int)(term_cols / len); i--;) 7: 152-block 0 unconditional 0 taken 7 532: 152-block 1 branch 1 taken 525 branch 2 taken 7 525: 153: fputs(div_line_char, stdout); 525: 153-block 0 call 0 returned 525 unconditional 1 taken 525 -: 154: } else { 298: 155: puts(div_line_char); 298: 155-block 0 call 0 returned 298 unconditional 1 taken 298 -: 156: } -: 157: 305: 158: fputs(df_c, stdout); 305: 158-block 0 call 0 returned 305 305: 159: fflush(stdout); call 0 returned 305 305: 160:} -: 161: -: 162:/* Print free/total space for the filesystem of the current working -: 163: * directory */ -: 164:static void function print_disk_usage called 0 returned 0% blocks executed 0% #####: 165:print_disk_usage(void) -: 166:{ #####: 167: if (!ws || !ws[cur_ws].path || !*ws[cur_ws].path) %%%%%: 167-block 0 branch 0 never executed branch 1 never executed %%%%%: 167-block 1 branch 2 never executed branch 3 never executed %%%%%: 167-block 2 branch 4 never executed branch 5 never executed #####: 168: return; %%%%%: 168-block 0 unconditional 0 never executed -: 169: -: 170: struct statvfs stat; #####: 171: if (statvfs(ws[cur_ws].path, &stat) != EXIT_SUCCESS) { %%%%%: 171-block 0 call 0 never executed branch 1 never executed branch 2 never executed #####: 172: _err('w', PRINT_PROMPT, "statvfs: %s\n", strerror(errno)); %%%%%: 172-block 0 call 0 never executed call 1 never executed #####: 173: return; unconditional 0 never executed -: 174: } -: 175: #####: 176: char *free_space = get_size_unit((off_t)(stat.f_frsize * stat.f_bavail)); %%%%%: 176-block 0 call 0 never executed #####: 177: char *size = get_size_unit((off_t)(stat.f_blocks * stat.f_frsize)); call 0 never executed #####: 178: printf("%s->%s %s/%s\n", mi_c, df_c, free_space ? free_space : "?", branch 0 never executed branch 1 never executed %%%%%: 178-block 0 unconditional 2 never executed %%%%%: 178-block 1 unconditional 3 never executed %%%%%: 178-block 2 branch 4 never executed branch 5 never executed %%%%%: 178-block 3 unconditional 6 never executed %%%%%: 178-block 4 unconditional 7 never executed %%%%%: 178-block 5 call 8 never executed -: 179: size ? size : "?"); -: 180: #####: 181: free(free_space); #####: 182: free(size); #####: 183: return; unconditional 0 never executed -: 184:} -: 185: -: 186:static void function _print_selfiles called 0 returned 0% blocks executed 0% #####: 187:_print_selfiles(unsigned short t_rows) -: 188:{ #####: 189: int limit = max_printselfiles; -: 190: #####: 191: if (max_printselfiles == 0) { %%%%%: 191-block 0 branch 0 never executed branch 1 never executed -: 192: /* Never take more than half terminal height */ #####: 193: limit = (t_rows / 2) - 4; -: 194: /* 4 = 2 div lines, 2 prompt lines */ #####: 195: if (limit <= 0) %%%%%: 195-block 0 branch 0 never executed branch 1 never executed #####: 196: limit = 1; %%%%%: 196-block 0 unconditional 0 never executed -: 197: } -: 198: #####: 199: if (limit > (int)sel_n) %%%%%: 199-block 0 branch 0 never executed branch 1 never executed #####: 200: limit = (int)sel_n; %%%%%: 200-block 0 unconditional 0 never executed -: 201: -: 202: int i; #####: 203: for (i = 0; i < (max_printselfiles != UNSET ? limit : (int)sel_n); i++) %%%%%: 203-block 0 unconditional 0 never executed unconditional 1 never executed %%%%%: 203-block 1 branch 2 never executed branch 3 never executed %%%%%: 203-block 2 unconditional 4 never executed %%%%%: 203-block 3 unconditional 5 never executed %%%%%: 203-block 4 branch 6 never executed branch 7 never executed #####: 204: colors_list(sel_elements[i], 0, NO_PAD, PRINT_NEWLINE); %%%%%: 204-block 0 call 0 never executed -: 205: #####: 206: if (max_printselfiles != UNSET && limit < (int)sel_n) %%%%%: 206-block 0 branch 0 never executed branch 1 never executed %%%%%: 206-block 1 branch 2 never executed branch 3 never executed #####: 207: printf("%d/%zu\n", i, sel_n); %%%%%: 207-block 0 call 0 never executed unconditional 1 never executed -: 208: #####: 209: print_div_line(); %%%%%: 209-block 0 call 0 never executed #####: 210:} -: 211: -: 212:static void function print_dirhist_map called 0 returned 0% blocks executed 0% #####: 213:print_dirhist_map(void) -: 214:{ -: 215: size_t i; #####: 216: for (i = 0; i < (size_t)dirhist_total_index; i++) { %%%%%: 216-block 0 unconditional 0 never executed %%%%%: 216-block 1 unconditional 1 never executed %%%%%: 216-block 2 branch 2 never executed branch 3 never executed #####: 217: if (i != (size_t)dirhist_cur_index) %%%%%: 217-block 0 branch 0 never executed branch 1 never executed #####: 218: continue; %%%%%: 218-block 0 unconditional 0 never executed -: 219: #####: 220: if (i > 0 && old_pwd[i - 1]) %%%%%: 220-block 0 branch 0 never executed branch 1 never executed %%%%%: 220-block 1 branch 2 never executed branch 3 never executed #####: 221: printf("%zu %s\n", i, old_pwd[i - 1]); %%%%%: 221-block 0 call 0 never executed unconditional 1 never executed -: 222: #####: 223: printf("%zu %s%s%s\n", i + 1, dh_c, #####: 224: old_pwd[i], df_c); %%%%%: 224-block 0 call 0 never executed -: 225: #####: 226: if (i + 1 < (size_t)dirhist_total_index && old_pwd[i + 1]) branch 0 never executed branch 1 never executed %%%%%: 226-block 0 branch 2 never executed branch 3 never executed #####: 227: printf("%zu %s\n", i + 2, old_pwd[i + 1]); %%%%%: 227-block 0 call 0 never executed unconditional 1 never executed -: 228: #####: 229: break; %%%%%: 229-block 0 unconditional 0 never executed -: 230: } #####: 231:} -: 232: -: 233:#ifndef _NO_ICONS -: 234:/* Set the icon field to the corresponding icon for FILE. If not found, -: 235: * set the default icon */ -: 236:static void function get_file_icon called 1 returned 100% blocks executed 75% 1: 237:get_file_icon(const char *file, int n) -: 238:{ 1: 239: if (!file) 1: 239-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 1 #####: 240: return; %%%%%: 240-block 0 unconditional 0 never executed -: 241: 1: 242: int i = (int)(sizeof(icon_filenames) / sizeof(struct icons_t)); 8: 243: while (--i >= 0) { 1: 243-block 0 unconditional 0 taken 1 8: 243-block 1 branch 1 taken 7 branch 2 taken 1 (fallthrough) 7*: 244: if (TOUPPER(*file) == TOUPPER(*icon_filenames[i].name) 7: 244-block 0 branch 0 taken 7 (fallthrough) branch 1 taken 0 7: 244-block 1 branch 2 taken 7 (fallthrough) branch 3 taken 0 7: 244-block 2 unconditional 4 taken 7 %%%%%: 244-block 3 unconditional 5 never executed 7: 244-block 4 branch 6 taken 1 (fallthrough) branch 7 taken 6 1: 244-block 5 branch 8 taken 1 (fallthrough) branch 9 taken 0 1: 244-block 6 unconditional 10 taken 1 6: 244-block 7 unconditional 11 taken 6 7: 244-block 8 branch 12 taken 0 (fallthrough) branch 13 taken 7 #####: 245: && strcasecmp(file, icon_filenames[i].name) == 0) { %%%%%: 245-block 0 branch 0 never executed branch 1 never executed #####: 246: file_info[n].icon = icon_filenames[i].icon; #####: 247: file_info[n].icon_color = icon_filenames[i].color; #####: 248: break; %%%%%: 248-block 0 unconditional 0 never executed -: 249: } -: 250: } -: 251:} -: 252: -: 253:/* Set the icon field to the corresponding icon for DIR. If not found, -: 254: * set the default icon */ -: 255:static void function get_dir_icon called 3 returned 100% blocks executed 69% 3: 256:get_dir_icon(const char *dir, int n) -: 257:{ -: 258: /* Default values for directories */ 3: 259: file_info[n].icon = DEF_DIR_ICON; 3: 260: file_info[n].icon_color = DEF_DIR_ICON_COLOR; -: 261: 3: 262: if (!dir) 3: 262-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 3 #####: 263: return; %%%%%: 263-block 0 unconditional 0 never executed -: 264: 3: 265: int i = (int)(sizeof(icon_dirnames) / sizeof(struct icons_t)); 30: 266: while (--i >= 0) { 3: 266-block 0 unconditional 0 taken 3 30: 266-block 1 branch 1 taken 27 branch 2 taken 3 (fallthrough) 27*: 267: if (TOUPPER(*dir) == TOUPPER(*icon_dirnames[i].name) 27: 267-block 0 branch 0 taken 27 (fallthrough) branch 1 taken 0 27: 267-block 1 branch 2 taken 27 (fallthrough) branch 3 taken 0 27: 267-block 2 unconditional 4 taken 27 %%%%%: 267-block 3 unconditional 5 never executed 27: 267-block 4 branch 6 taken 0 (fallthrough) branch 7 taken 27 %%%%%: 267-block 5 branch 8 never executed branch 9 never executed %%%%%: 267-block 6 unconditional 10 never executed 27: 267-block 7 unconditional 11 taken 27 27: 267-block 8 branch 12 taken 6 (fallthrough) branch 13 taken 21 6: 268: && strcasecmp(dir, icon_dirnames[i].name) == 0) { 6: 268-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 6 #####: 269: file_info[n].icon = icon_dirnames[i].icon; #####: 270: file_info[n].icon_color = icon_dirnames[i].color; #####: 271: break; %%%%%: 271-block 0 unconditional 0 never executed -: 272: } -: 273: } -: 274:} -: 275: -: 276:/* Set the icon field to the corresponding icon for EXT. If not found, -: 277: * set the default icon */ -: 278:static void function get_ext_icon called 2 returned 100% blocks executed 83% 2: 279:get_ext_icon(const char *restrict ext, int n) -: 280:{ 2: 281: file_info[n].icon = DEF_FILE_ICON; 2: 282: file_info[n].icon_color = DEF_FILE_ICON_COLOR; -: 283: 2: 284: if (!ext) 2: 284-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 2 #####: 285: return; %%%%%: 285-block 0 unconditional 0 never executed -: 286: 2: 287: ext++; -: 288: 2: 289: int i = (int)(sizeof(icon_ext) / sizeof(struct icons_t)); 224: 290: while (--i >= 0) { 2: 290-block 0 unconditional 0 taken 2 224: 290-block 1 branch 1 taken 224 branch 2 taken 0 (fallthrough) -: 291: /* Tolower */ 224*: 292: char c = (*ext >= 'A' && *ext <= 'Z') 224: 292-block 0 branch 0 taken 224 (fallthrough) branch 1 taken 0 224: 292-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 224 224: 292-block 2 unconditional 4 taken 224 #####: 293: ? (char)(*ext - 'A' + 'a') : *ext; %%%%%: 293-block 0 unconditional 0 never executed 224: 294: if (c == *icon_ext[i].name && strcasecmp(ext, icon_ext[i].name) == 0) { 224: 294-block 0 branch 0 taken 4 (fallthrough) branch 1 taken 220 4: 294-block 1 branch 2 taken 2 (fallthrough) branch 3 taken 2 2: 295: file_info[n].icon = icon_ext[i].icon; 2: 296: file_info[n].icon_color = icon_ext[i].color; 2: 297: break; 2: 297-block 0 unconditional 0 taken 2 -: 298: } -: 299: } -: 300:} -: 301:#endif /* _NO_ICONS */ -: 302: -: 303:/* List files in the current working directory (global variable 'path'). -: 304: * Unlike list_dir(), however, this function uses no color and runs -: 305: * neither stat() nor count_dir(), which makes it quite faster. Return -: 306: * zero on success or one on error */ -: 307:static int function list_dir_light called 3 returned 100% blocks executed 34% 3: 308:list_dir_light(void) -: 309:{ -: 310:#ifdef _LIST_SPEED -: 311: clock_t start = clock(); -: 312:#endif -: 313: /* Hide the cursor while listing */ 3: 314: fputs("\x1b[?25l", stdout); 3: 314-block 0 call 0 returned 3 -: 315: -: 316: DIR *dir; -: 317: struct dirent *ent; 3: 318: int reset_pager = 0; 3: 319: int close_dir = 1; -: 320: /* Get terminal current amount of rows and columns */ -: 321: struct winsize w; 3: 322: ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); call 0 returned 3 -: 323: /* ws_col and ws_row are both unsigned short int according to -: 324: * /bits/ioctl-types.h */ -: 325: -: 326: /* These two are global */ 3: 327: term_cols = w.ws_col; 3: 328: term_rows = w.ws_row; -: 329: 3: 330: if ((dir = opendir(ws[cur_ws].path)) == NULL) { call 0 returned 3 branch 1 taken 0 (fallthrough) branch 2 taken 3 #####: 331: fprintf(stderr, "%s: %s: %s\n", PROGRAM_NAME, ws[cur_ws].path, call 0 never executed #####: 332: strerror(errno)); %%%%%: 332-block 0 call 0 never executed #####: 333: close_dir = 0; #####: 334: goto END; unconditional 0 never executed -: 335: } -: 336: -: 337:#ifdef LINUX_INOTIFY 3: 338: if (inotify_wd >= 0) { 3: 338-block 0 branch 0 taken 3 (fallthrough) branch 1 taken 0 3: 339: inotify_rm_watch(inotify_fd, inotify_wd); 3: 339-block 0 call 0 returned 3 3: 340: inotify_wd = -1; unconditional 0 taken 3 -: 341: } 3: 342: inotify_wd = inotify_add_watch(inotify_fd, ws[cur_ws].path, INOTIFY_MASK); 3: 342-block 0 call 0 returned 3 -: 343: -: 344:#elif defined(BSD_KQUEUE) -: 345: if (event_fd >= 0) { -: 346: close(event_fd); -: 347: event_fd = -1; -: 348: } -: 349:#if defined(O_EVTONLY) -: 350: event_fd = open(ws[cur_ws].path, O_EVTONLY); -: 351:#else -: 352: event_fd = open(ws[cur_ws].path, O_RDONLY); -: 353:#endif -: 354: if (event_fd >= 0) { -: 355: EV_SET(&events_to_monitor[0], event_fd, EVFILT_VNODE, -: 356: EV_ADD | EV_CLEAR, KQUEUE_FFLAGS, 0, ws[cur_ws].path); -: 357: } -: 358:#endif -: 359: 3: 360: errno = 0; 3: 361: longest = 0; 3: 362: register unsigned int n = 0; 3: 363: unsigned int total_dents = 0, count = 0; -: 364: 3: 365: file_info = (struct fileinfo *)xnmalloc(ENTRY_N + 2, call 0 returned 3 -: 366: sizeof(struct fileinfo)); -: 367: 24: 368: while ((ent = readdir(dir))) { unconditional 0 taken 3 24: 368-block 0 call 1 returned 24 branch 2 taken 21 branch 3 taken 3 (fallthrough) 21: 369: char *ename = ent->d_name; -: 370: /* Skip self and parent directories */ 21: 371: if (*ename == '.' && (!ename[1] || (ename[1] == '.' && !ename[2]))) 21: 371-block 0 branch 0 taken 6 (fallthrough) branch 1 taken 15 6: 371-block 1 branch 2 taken 3 (fallthrough) branch 3 taken 3 3: 371-block 2 branch 4 taken 3 (fallthrough) branch 5 taken 0 3: 371-block 3 branch 6 taken 3 (fallthrough) branch 7 taken 0 6: 372: continue; 6: 372-block 0 unconditional 0 taken 6 -: 373: -: 374: /* Skip files according to FILTER */ 15: 375: if (filter) { 15: 375-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 15 #####: 376: if (regexec(®ex_exp, ename, 0, NULL, 0) == EXIT_SUCCESS) { %%%%%: 376-block 0 call 0 never executed branch 1 never executed branch 2 never executed #####: 377: if (filter_rev) %%%%%: 377-block 0 branch 0 never executed branch 1 never executed #####: 378: continue; %%%%%: 378-block 0 unconditional 0 never executed #####: 379: } else if (!filter_rev) { %%%%%: 379-block 0 branch 0 never executed branch 1 never executed #####: 380: continue; %%%%%: 380-block 0 unconditional 0 never executed -: 381: } -: 382: } -: 383: 15*: 384: if (!show_hidden && *ename == '.') 15: 384-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 15 %%%%%: 384-block 1 branch 2 never executed branch 3 never executed #####: 385: continue; %%%%%: 385-block 0 unconditional 0 never executed -: 386:#if !defined(_DIRENT_HAVE_D_TYPE) -: 387: struct stat attr; -: 388: if (lstat(ename, &attr) == -1) -: 389: continue; -: 390: if (only_dirs && (attr.st_mode & S_IFMT) != S_IFDIR) -: 391:#else 15*: 392: if (only_dirs && ent->d_type != DT_DIR) 15: 392-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 15 %%%%%: 392-block 1 branch 2 never executed branch 3 never executed -: 393:#endif /* !_DIRENT_HAVE_D_TYPE */ #####: 394: continue; %%%%%: 394-block 0 unconditional 0 never executed -: 395: 15: 396: if (count > ENTRY_N) { 15: 396-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 15 #####: 397: count = 0; #####: 398: total_dents = n + ENTRY_N; #####: 399: file_info = xrealloc(file_info, (total_dents + 2) * sizeof(struct fileinfo)); %%%%%: 399-block 0 call 0 never executed unconditional 1 never executed -: 400: } -: 401: 15: 402: file_info[n].name = (char *)xnmalloc(NAME_MAX + 1, sizeof(char)); 15: 402-block 0 call 0 returned 15 -: 403: 15: 404: if (!unicode) { branch 0 taken 0 (fallthrough) branch 1 taken 15 #####: 405: file_info[n].len = xstrsncpy(file_info[n].name, ename, NAME_MAX); %%%%%: 405-block 0 call 0 never executed unconditional 1 never executed -: 406: } else { 15: 407: xstrsncpy(file_info[n].name, ename, NAME_MAX); 15: 407-block 0 call 0 returned 15 15: 408: file_info[n].len = wc_xstrlen(ename); call 0 returned 15 unconditional 1 taken 15 -: 409: } -: 410: -: 411: /* ################ */ -: 412:#if !defined(_DIRENT_HAVE_D_TYPE) -: 413: switch (attr.st_mode & S_IFMT) { -: 414: case S_IFBLK: file_info[n].type = DT_BLK; break; -: 415: case S_IFCHR: file_info[n].type = DT_CHR; break; -: 416: case S_IFDIR: file_info[n].type = DT_DIR; break; -: 417: case S_IFIFO: file_info[n].type = DT_FIFO; break; -: 418: case S_IFLNK: file_info[n].type = DT_LNK; break; -: 419: case S_IFREG: file_info[n].type = DT_REG; break; -: 420: case S_IFSOCK: file_info[n].type = DT_SOCK; break; -: 421: default: file_info[n].type = DT_UNKNOWN; break; -: 422: } -: 423: file_info[n].dir = (file_info[n].type == DT_DIR) ? 1 : 0; -: 424: file_info[n].symlink = (file_info[n].type == DT_LNK) ? 1 : 0; -: 425:#else 15: 426: file_info[n].dir = (ent->d_type == DT_DIR) ? 1 : 0; 15: 427: file_info[n].symlink = (ent->d_type == DT_LNK) ? 1 : 0; 15: 428: file_info[n].type = ent->d_type; -: 429:#endif /* !_DIRENT_HAVE_D_TYPE */ 15: 430: file_info[n].inode = ent->d_ino; 15: 431: file_info[n].linkn = 1; 15: 432: file_info[n].size = 1; 15: 433: file_info[n].color = (char *)NULL; 15: 434: file_info[n].ext_color = (char *)NULL; 15: 435: file_info[n].exec = 0; 15: 436: file_info[n].ruser = 1; 15: 437: file_info[n].filesn = 0; 15: 438: file_info[n].time = 0; -: 439:#ifndef _NO_ICONS 15: 440: file_info[n].icon = DEF_FILE_ICON; 15: 441: file_info[n].icon_color = DEF_FILE_ICON_COLOR; -: 442:#endif 15: 443: switch (file_info[n].type) { 15: 443-block 0 branch 0 taken 6 branch 1 taken 3 branch 2 taken 6 branch 3 taken 0 branch 4 taken 0 branch 5 taken 0 branch 6 taken 0 branch 7 taken 0 branch 8 taken 0 -: 444: 6: 445: case DT_DIR: -: 446:#ifndef _NO_ICONS 6: 447: if (icons) { 6: 447-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 6 #####: 448: get_dir_icon(file_info[n].name, (int)n); %%%%%: 448-block 0 call 0 never executed -: 449: /* If set from the color scheme file */ #####: 450: if (*dir_ico_c) branch 0 never executed branch 1 never executed #####: 451: file_info[n].icon_color = dir_ico_c; %%%%%: 451-block 0 unconditional 0 never executed -: 452: } -: 453:#endif -: 454: -: 455: files_counter 6: 456: ? (file_info[n].filesn = (count_dir(ename, NO_CPOP) - 2)) 6: 456-block 0 call 0 returned 6 12*: 457: : (file_info[n].filesn = 1); 6: 457-block 0 branch 0 taken 6 (fallthrough) branch 1 taken 0 unconditional 2 taken 6 %%%%%: 457-block 1 unconditional 3 never executed -: 458: 6: 459: if (file_info[n].filesn > 0) { 6: 459-block 0 branch 0 taken 5 (fallthrough) branch 1 taken 1 5: 460: file_info[n].color = di_c; 5: 460-block 0 unconditional 0 taken 5 1: 461: } else if (file_info[n].filesn == 0) { 1: 461-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 0 1: 462: file_info[n].color = ed_c; 1: 462-block 0 unconditional 0 taken 1 -: 463: } else { #####: 464: file_info[n].color = nd_c; -: 465:#ifndef _NO_ICONS #####: 466: file_info[n].icon = ICON_LOCK; #####: 467: file_info[n].icon_color = YELLOW; %%%%%: 467-block 0 unconditional 0 never executed -: 468:#endif -: 469: } -: 470: 6: 471: break; 6: 471-block 0 unconditional 0 taken 6 -: 472: 3: 473: case DT_LNK: -: 474:#ifndef _NO_ICONS 3: 475: file_info[n].icon = ICON_LINK; -: 476:#endif 3: 477: file_info[n].color = ln_c; 3: 478: break; 3: 478-block 0 unconditional 0 taken 3 -: 479: 6: 480: case DT_REG: file_info[n].color = fi_c; break; 6: 480-block 0 unconditional 0 taken 6 #####: 481: case DT_SOCK: file_info[n].color = so_c; break; %%%%%: 481-block 0 unconditional 0 never executed #####: 482: case DT_FIFO: file_info[n].color = pi_c; break; %%%%%: 482-block 0 unconditional 0 never executed #####: 483: case DT_BLK: file_info[n].color = bd_c; break; %%%%%: 483-block 0 unconditional 0 never executed #####: 484: case DT_CHR: file_info[n].color = cd_c; break; %%%%%: 484-block 0 unconditional 0 never executed #####: 485: case DT_UNKNOWN: file_info[n].color = uf_c; break; %%%%%: 485-block 0 unconditional 0 never executed #####: 486: default: file_info[n].color = df_c; break; %%%%%: 486-block 0 unconditional 0 never executed -: 487: } -: 488: -: 489:#ifndef _NO_ICONS 15*: 490: if (xargs.icons_use_file_color == 1 && icons) 15: 490-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 15 %%%%%: 490-block 1 branch 2 never executed branch 3 never executed #####: 491: file_info[n].icon_color = file_info[n].color; %%%%%: 491-block 0 unconditional 0 never executed -: 492:#endif -: 493: 15: 494: n++; 15: 495: count++; 15: 495-block 0 unconditional 0 taken 15 -: 496: } -: 497: 3: 498: file_info[n].name = (char *)NULL; 3: 499: files = (size_t)n; -: 500: 3: 501: if (n == 0) { 3: 501-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 3 #####: 502: printf("%s. ..%s\n", colorize ? di_c : df_c, df_c); %%%%%: 502-block 0 branch 0 never executed branch 1 never executed %%%%%: 502-block 1 unconditional 2 never executed %%%%%: 502-block 2 unconditional 3 never executed %%%%%: 502-block 3 call 4 never executed #####: 503: free(file_info); #####: 504: goto END; unconditional 0 never executed -: 505: } -: 506: 3: 507: if (sort) 3: 507-block 0 branch 0 taken 3 (fallthrough) branch 1 taken 0 3: 508: ENTSORT(file_info, n, entrycmp); 3: 508-block 0 call 0 returned 3 unconditional 1 taken 3 -: 509: -: 510: int i; 3: 511: register size_t counter = 0; 3: 512: size_t columns_n = 1; -: 513: -: 514: /* Get the longest file name */ 3*: 515: if (columned || long_view) { 3: 515-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 3 %%%%%: 515-block 1 branch 2 never executed branch 3 never executed 3: 516: i = (int)n; 18: 517: while (--i >= 0) { 3: 517-block 0 unconditional 0 taken 3 18: 517-block 1 branch 1 taken 15 branch 2 taken 3 (fallthrough) 15: 518: size_t total_len = 0; 15*: 519: file_info[i].eln_n = no_eln ? -1 : DIGINUM(i + 1); 15: 519-block 0 branch 0 taken 15 (fallthrough) branch 1 taken 0 15: 519-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 15 %%%%%: 519-block 2 branch 4 never executed branch 5 never executed %%%%%: 519-block 3 branch 6 never executed branch 7 never executed %%%%%: 519-block 4 branch 8 never executed branch 9 never executed %%%%%: 519-block 5 branch 10 never executed branch 11 never executed %%%%%: 519-block 6 branch 12 never executed branch 13 never executed %%%%%: 519-block 7 branch 14 never executed branch 15 never executed %%%%%: 519-block 8 branch 16 never executed branch 17 never executed %%%%%: 519-block 9 branch 18 never executed branch 19 never executed %%%%%: 519-block 10 unconditional 20 never executed %%%%%: 519-block 11 unconditional 21 never executed %%%%%: 519-block 12 unconditional 22 never executed %%%%%: 519-block 13 unconditional 23 never executed %%%%%: 519-block 14 unconditional 24 never executed %%%%%: 519-block 15 unconditional 25 never executed %%%%%: 519-block 16 unconditional 26 never executed %%%%%: 519-block 17 unconditional 27 never executed %%%%%: 519-block 18 unconditional 28 never executed %%%%%: 519-block 19 unconditional 29 never executed %%%%%: 519-block 20 unconditional 30 never executed %%%%%: 519-block 21 unconditional 31 never executed %%%%%: 519-block 22 unconditional 32 never executed %%%%%: 519-block 23 unconditional 33 never executed %%%%%: 519-block 24 unconditional 34 never executed %%%%%: 519-block 25 unconditional 35 never executed %%%%%: 519-block 26 unconditional 36 never executed 15: 519-block 27 unconditional 37 taken 15 15: 519-block 28 unconditional 38 taken 15 %%%%%: 519-block 29 unconditional 39 never executed 15: 520: total_len = (size_t)file_info[i].eln_n + 1 + file_info[i].len; -: 521: 15: 522: if (!long_view && classify) { 15: 522-block 0 branch 0 taken 15 (fallthrough) branch 1 taken 0 15: 522-block 1 branch 2 taken 15 (fallthrough) branch 3 taken 0 15: 523: if (file_info[i].dir) 15: 523-block 0 branch 0 taken 6 (fallthrough) branch 1 taken 9 6: 524: total_len++; 6: 524-block 0 unconditional 0 taken 6 -: 525: 15: 526: if (file_info[i].filesn > 0 && files_counter) 15: 526-block 0 branch 0 taken 5 (fallthrough) branch 1 taken 10 5: 526-block 1 branch 2 taken 5 (fallthrough) branch 3 taken 0 5*: 527: total_len += DIGINUM(file_info[i].filesn); 5: 527-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 5 %%%%%: 527-block 1 branch 2 never executed branch 3 never executed %%%%%: 527-block 2 branch 4 never executed branch 5 never executed %%%%%: 527-block 3 branch 6 never executed branch 7 never executed %%%%%: 527-block 4 branch 8 never executed branch 9 never executed %%%%%: 527-block 5 branch 10 never executed branch 11 never executed %%%%%: 527-block 6 branch 12 never executed branch 13 never executed %%%%%: 527-block 7 branch 14 never executed branch 15 never executed %%%%%: 527-block 8 branch 16 never executed branch 17 never executed %%%%%: 527-block 9 unconditional 18 never executed %%%%%: 527-block 10 unconditional 19 never executed %%%%%: 527-block 11 unconditional 20 never executed %%%%%: 527-block 12 unconditional 21 never executed %%%%%: 527-block 13 unconditional 22 never executed %%%%%: 527-block 14 unconditional 23 never executed %%%%%: 527-block 15 unconditional 24 never executed %%%%%: 527-block 16 unconditional 25 never executed %%%%%: 527-block 17 unconditional 26 never executed %%%%%: 527-block 18 unconditional 27 never executed %%%%%: 527-block 19 unconditional 28 never executed %%%%%: 527-block 20 unconditional 29 never executed %%%%%: 527-block 21 unconditional 30 never executed %%%%%: 527-block 22 unconditional 31 never executed %%%%%: 527-block 23 unconditional 32 never executed %%%%%: 527-block 24 unconditional 33 never executed %%%%%: 527-block 25 unconditional 34 never executed 5: 527-block 26 unconditional 35 taken 5 5: 527-block 27 unconditional 36 taken 5 -: 528: 15: 529: if (!file_info[i].dir && !colorize) { 15: 529-block 0 branch 0 taken 9 (fallthrough) branch 1 taken 6 9: 529-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 9 #####: 530: switch (file_info[i].type) { %%%%%: 530-block 0 branch 0 never executed branch 1 never executed branch 2 never executed #####: 531: case DT_REG: #####: 532: if (file_info[i].exec) %%%%%: 532-block 0 branch 0 never executed branch 1 never executed #####: 533: total_len++; %%%%%: 533-block 0 unconditional 0 never executed #####: 534: break; %%%%%: 534-block 0 unconditional 0 never executed #####: 535: case DT_LNK: /* fallthrough */ -: 536: case DT_SOCK: /* fallthrough */ -: 537: case DT_FIFO: /* fallthrough */ #####: 538: case DT_UNKNOWN: total_len++; break; %%%%%: 538-block 0 unconditional 0 never executed -: 539: } -: 540: } -: 541: } -: 542: 15: 543: if (total_len > longest) { 15: 543-block 0 branch 0 taken 6 (fallthrough) branch 1 taken 9 6: 544: if (max_files == UNSET) 6: 544-block 0 branch 0 taken 6 (fallthrough) branch 1 taken 0 6: 545: longest = total_len; 6: 545-block 0 unconditional 0 taken 6 #####: 546: else if (i < max_files) %%%%%: 546-block 0 branch 0 never executed branch 1 never executed #####: 547: longest = total_len; %%%%%: 547-block 0 unconditional 0 never executed -: 548: } -: 549: } -: 550:#ifndef _NO_ICONS 3*: 551: if (icons && !long_view && columned) 3: 551-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 3 %%%%%: 551-block 1 branch 2 never executed branch 3 never executed %%%%%: 551-block 2 branch 4 never executed branch 5 never executed #####: 552: longest += 3; %%%%%: 552-block 0 unconditional 0 never executed -: 553:#endif -: 554: } -: 555: -: 556: /* ######################## -: 557: * # LONG VIEW MODE # -: 558: * ######################## */ -: 559: 3: 560: if (long_view) { 3: 560-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 3 -: 561: struct stat lattr; #####: 562: int space_left = (int)term_cols - MAX_PROP_STR; -: 563: #####: 564: if (space_left < min_name_trim) %%%%%: 564-block 0 branch 0 never executed branch 1 never executed #####: 565: space_left = min_name_trim; %%%%%: 565-block 0 unconditional 0 never executed -: 566: #####: 567: if ((int)longest < space_left) %%%%%: 567-block 0 branch 0 never executed branch 1 never executed #####: 568: space_left = (int)longest; %%%%%: 568-block 0 unconditional 0 never executed -: 569: #####: 570: int k = (int)files; #####: 571: for (i = 0; i < k; i++) { %%%%%: 571-block 0 unconditional 0 never executed %%%%%: 571-block 1 unconditional 1 never executed %%%%%: 571-block 2 branch 2 never executed branch 3 never executed #####: 572: if (max_files != UNSET && i == max_files) %%%%%: 572-block 0 branch 0 never executed branch 1 never executed %%%%%: 572-block 1 branch 2 never executed branch 3 never executed #####: 573: break; %%%%%: 573-block 0 unconditional 0 never executed #####: 574: if (lstat(file_info[i].name, &lattr) == -1) %%%%%: 574-block 0 call 0 never executed branch 1 never executed branch 2 never executed #####: 575: continue; %%%%%: 575-block 0 unconditional 0 never executed -: 576: #####: 577: if (pager) { %%%%%: 577-block 0 branch 0 never executed branch 1 never executed #####: 578: if (counter > (size_t)(term_rows - 2)) { %%%%%: 578-block 0 branch 0 never executed branch 1 never executed #####: 579: fputs("\x1b[7;97m--Mas--\x1b[0;49m", stdout); %%%%%: 579-block 0 call 0 never executed -: 580: #####: 581: switch (xgetchar()) { call 0 never executed branch 1 never executed branch 2 never executed branch 3 never executed branch 4 never executed branch 5 never executed -: 582: /* Advance one line at a time */ #####: 583: case 66: /* fallthrough */ /* Down arrow */ -: 584: case 10: /* fallthrough */ /* Enter */ -: 585: case 32: /* Space */ #####: 586: break; %%%%%: 586-block 0 unconditional 0 never executed -: 587: -: 588: /* Advance one page at a time */ #####: 589: case 126: #####: 590: counter = 0; /* Page Down */ #####: 591: break; %%%%%: 591-block 0 unconditional 0 never executed -: 592: #####: 593: case 63: /* fallthrough */ /* ? */ -: 594: case 104: { /* h: Print pager help */ #####: 595: CLEAR; %%%%%: 595-block 0 call 0 never executed -: 596: #####: 597: fputs(_("?, h: help\n" call 0 never executed call 1 never executed -: 598: "Down arrow, Enter, Space: Advance one line\n" -: 599: "Page Down: Advance one page\n" -: 600: "q: Stop pagging\n"), stdout); -: 601: #####: 602: int l = (int)term_rows - 5; #####: 603: while (--l >= 0) unconditional 0 never executed %%%%%: 603-block 0 branch 1 never executed branch 2 never executed #####: 604: putchar('\n'); %%%%%: 604-block 0 call 0 never executed unconditional 1 never executed -: 605: #####: 606: fputs("\x1b[7;97m--Mas--\x1b[0;49m", stdout); %%%%%: 606-block 0 call 0 never executed -: 607: #####: 608: i -= (term_rows - 1); #####: 609: if (i < 0) branch 0 never executed branch 1 never executed #####: 610: i = 0; %%%%%: 610-block 0 unconditional 0 never executed -: 611: #####: 612: counter = 0; #####: 613: xgetchar(); %%%%%: 613-block 0 call 0 never executed #####: 614: CLEAR; call 0 never executed #####: 615: } break; unconditional 0 never executed -: 616: -: 617: /* Stop paging (and set a flag to reenable the pager -: 618: * later) */ #####: 619: case 99: /* 'c' */ -: 620: case 112: /* 'p' */ -: 621: case 113: #####: 622: pager = 0, reset_pager = 1; /* 'q' */ #####: 623: break; %%%%%: 623-block 0 unconditional 0 never executed -: 624: -: 625: /* If another key is pressed, go back one position. -: 626: * Otherwise, some file names won't be listed.*/ #####: 627: default: #####: 628: i--; #####: 629: fputs("\r\x1b[K\x1b[3J", stdout); %%%%%: 629-block 0 call 0 never executed #####: 630: continue; unconditional 0 never executed -: 631: } -: 632: #####: 633: fputs("\r\x1b[K\x1b[3J", stdout); %%%%%: 633-block 0 call 0 never executed unconditional 1 never executed -: 634: } -: 635: #####: 636: counter++; %%%%%: 636-block 0 unconditional 0 never executed -: 637: } -: 638: #####: 639: file_info[i].uid = lattr.st_uid; #####: 640: file_info[i].gid = lattr.st_gid; #####: 641: file_info[i].ltime = (time_t)lattr.st_mtim.tv_sec; #####: 642: file_info[i].mode = lattr.st_mode; #####: 643: file_info[i].size = lattr.st_size; -: 644: -: 645: /* Print ELN. The remaining part of the line will be -: 646: * printed by print_entry_props() */ #####: 647: if (!no_eln) %%%%%: 647-block 0 branch 0 never executed branch 1 never executed #####: 648: printf("%s%d%s ", el_c, i + 1, df_c); %%%%%: 648-block 0 call 0 never executed unconditional 1 never executed -: 649: #####: 650: print_entry_props(&file_info[i], (size_t)space_left); %%%%%: 650-block 0 call 0 never executed unconditional 1 never executed -: 651: } -: 652: #####: 653: goto END; %%%%%: 653-block 0 unconditional 0 never executed -: 654: } -: 655: -: 656: /* ######################## -: 657: * # NORMAL VIEW MODE # -: 658: * ######################## */ -: 659: 3: 660: int last_column = 0; -: 661: -: 662:/* char *line_buf = (char *)xcalloc(term_cols * 10, sizeof(char)); -: 663: size_t line_sz = 0; */ -: 664: -: 665: /* Get possible amount of columns for the dirlist screen */ 3: 666: if (!columned) { 3: 666-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 3 #####: 667: columns_n = 1; %%%%%: 667-block 0 unconditional 0 never executed -: 668: } else { 3: 669: columns_n = (size_t)term_cols / (longest + 1); /* +1 for the -: 670: space between file names */ -: 671: -: 672: /* If longest is bigger than terminal columns, columns_n will -: 673: * be negative or zero. To avoid this: */ 3: 674: if (columns_n < 1) 3: 674-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 3 #####: 675: columns_n = 1; %%%%%: 675-block 0 unconditional 0 never executed -: 676: -: 677: /* If we have only three files, we don't want four columns */ 3: 678: if (columns_n > (size_t)n) 3: 678-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 2 1: 679: columns_n = (size_t)n; 1: 679-block 0 unconditional 0 taken 1 -: 680: } -: 681: 3: 682: int nn = (int)n; 3: 683: size_t cur_cols = 0; 18: 684: for (i = 0; i < nn; i++) { 3: 684-block 0 unconditional 0 taken 3 15: 684-block 1 unconditional 1 taken 15 18: 684-block 2 branch 2 taken 15 branch 3 taken 3 (fallthrough) 15*: 685: if (max_files != UNSET && i == max_files) 15: 685-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 15 %%%%%: 685-block 1 branch 2 never executed branch 3 never executed #####: 686: break; %%%%%: 686-block 0 unconditional 0 never executed -: 687: -: 688: /* A basic pager for directories containing large amount of -: 689: * files. What's missing? It only goes downwards. To go -: 690: * backwards, use the terminal scrollback function */ 15: 691: if (pager) { 15: 691-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 15 -: 692: /* Run the pager only once all columns and rows fitting in -: 693: * the screen are filled with the corresponding file names */ #####: 694: if (last_column && counter > columns_n * ((size_t)term_rows - 2)) { %%%%%: 694-block 0 branch 0 never executed branch 1 never executed %%%%%: 694-block 1 branch 2 never executed branch 3 never executed #####: 695: fputs("\x1b[7;97m--Mas--\x1b[0;49m", stdout); %%%%%: 695-block 0 call 0 never executed -: 696: #####: 697: switch (xgetchar()) { call 0 never executed branch 1 never executed branch 2 never executed branch 3 never executed branch 4 never executed branch 5 never executed -: 698: -: 699: /* Advance one line at a time */ #####: 700: case 66: /* fallthrough */ /* Down arrow */ -: 701: case 10: /* fallthrough */ /* Enter */ -: 702: case 32: /* Space */ #####: 703: break; %%%%%: 703-block 0 unconditional 0 never executed -: 704: -: 705: /* Advance one page at a time */ #####: 706: case 126: #####: 707: counter = 0; /* Page Down */ #####: 708: break; %%%%%: 708-block 0 unconditional 0 never executed -: 709: #####: 710: case 63: /* fallthrough */ /* ? */ -: 711: case 104: { /* h: Print pager help */ #####: 712: CLEAR; %%%%%: 712-block 0 call 0 never executed -: 713: #####: 714: fputs(_("?, h: help\n" call 0 never executed call 1 never executed -: 715: "Down arrow, Enter, Space: Advance one line\n" -: 716: "Page Down: Advance one page\n" -: 717: "q: Stop pagging\n"), stdout); -: 718: #####: 719: int l = (int)term_rows - 5; #####: 720: while (--l >= 0) unconditional 0 never executed %%%%%: 720-block 0 branch 1 never executed branch 2 never executed #####: 721: putchar('\n'); %%%%%: 721-block 0 call 0 never executed unconditional 1 never executed -: 722: #####: 723: fputs("\x1b[7;97m--Mas--\x1b[0;49m", stdout); %%%%%: 723-block 0 call 0 never executed -: 724: #####: 725: i -= (int)((term_rows * columns_n) - 1); #####: 726: if (i < 0) branch 0 never executed branch 1 never executed #####: 727: i = 0; %%%%%: 727-block 0 unconditional 0 never executed -: 728: #####: 729: counter = 0; #####: 730: xgetchar(); %%%%%: 730-block 0 call 0 never executed #####: 731: CLEAR; call 0 never executed #####: 732: } break; unconditional 0 never executed -: 733: -: 734: /* Stop paging (and set a flag to reenable the pager -: 735: * later) */ #####: 736: case 99: /* 'c' */ -: 737: case 112: /* 'p' */ -: 738: case 113: #####: 739: pager = 0, reset_pager = 1; /* 'q' */ #####: 740: break; %%%%%: 740-block 0 unconditional 0 never executed -: 741: -: 742: /* If another key is pressed, go back one position. -: 743: * Otherwise, some file names won't be listed.*/ #####: 744: default: #####: 745: i--; #####: 746: fputs("\r\x1b[K\x1b[3J", stdout); %%%%%: 746-block 0 call 0 never executed #####: 747: continue; unconditional 0 never executed -: 748: } -: 749: #####: 750: fputs("\r\x1b[K\x1b[3J", stdout); %%%%%: 750-block 0 call 0 never executed unconditional 1 never executed -: 751: } -: 752: #####: 753: counter++; %%%%%: 753-block 0 unconditional 0 never executed -: 754: } -: 755: 15: 756: if (++cur_cols == columns_n) { 15: 756-block 0 branch 0 taken 3 (fallthrough) branch 1 taken 12 3: 757: cur_cols = 0; 3: 758: last_column = 1; 3: 758-block 0 unconditional 0 taken 3 -: 759: } else { 12: 760: last_column = 0; 12: 760-block 0 unconditional 0 taken 12 -: 761: } -: 762: 15*: 763: file_info[i].eln_n = no_eln ? -1 : DIGINUM(i + 1); 15: 763-block 0 branch 0 taken 15 (fallthrough) branch 1 taken 0 15: 763-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 15 %%%%%: 763-block 2 branch 4 never executed branch 5 never executed %%%%%: 763-block 3 branch 6 never executed branch 7 never executed %%%%%: 763-block 4 branch 8 never executed branch 9 never executed %%%%%: 763-block 5 branch 10 never executed branch 11 never executed %%%%%: 763-block 6 branch 12 never executed branch 13 never executed %%%%%: 763-block 7 branch 14 never executed branch 15 never executed %%%%%: 763-block 8 branch 16 never executed branch 17 never executed %%%%%: 763-block 9 branch 18 never executed branch 19 never executed %%%%%: 763-block 10 unconditional 20 never executed %%%%%: 763-block 11 unconditional 21 never executed %%%%%: 763-block 12 unconditional 22 never executed %%%%%: 763-block 13 unconditional 23 never executed %%%%%: 763-block 14 unconditional 24 never executed %%%%%: 763-block 15 unconditional 25 never executed %%%%%: 763-block 16 unconditional 26 never executed %%%%%: 763-block 17 unconditional 27 never executed %%%%%: 763-block 18 unconditional 28 never executed %%%%%: 763-block 19 unconditional 29 never executed %%%%%: 763-block 20 unconditional 30 never executed %%%%%: 763-block 21 unconditional 31 never executed %%%%%: 763-block 22 unconditional 32 never executed %%%%%: 763-block 23 unconditional 33 never executed %%%%%: 763-block 24 unconditional 34 never executed %%%%%: 763-block 25 unconditional 35 never executed %%%%%: 763-block 26 unconditional 36 never executed 15: 763-block 27 unconditional 37 taken 15 15: 763-block 28 unconditional 38 taken 15 %%%%%: 763-block 29 unconditional 39 never executed 15: 764: int ind_char = 1; -: 765: 15: 766: if (!classify) 15: 766-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 15 #####: 767: ind_char = 0; %%%%%: 767-block 0 unconditional 0 never executed -: 768: 15: 769: if (colorize) { 15: 769-block 0 branch 0 taken 15 (fallthrough) branch 1 taken 0 15: 770: ind_char = 0; -: 771:#ifndef _NO_ICONS 15: 772: if (icons) { 15: 772-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 15 #####: 773: if (xargs.icons_use_file_color == 1) %%%%%: 773-block 0 branch 0 never executed branch 1 never executed #####: 774: file_info[i].icon_color = file_info[i].color; %%%%%: 774-block 0 unconditional 0 never executed -: 775: #####: 776: if (no_eln) { %%%%%: 776-block 0 branch 0 never executed branch 1 never executed #####: 777: xprintf("%s%s %s%s%s", file_info[i].icon_color, #####: 778: file_info[i].icon, file_info[i].color, #####: 779: file_info[i].name, df_c); %%%%%: 779-block 0 call 0 never executed unconditional 1 never executed -: 780: } else { #####: 781: xprintf("%s%d%s %s%s %s%s%s", el_c, i + 1, df_c, #####: 782: file_info[i].icon_color, file_info[i].icon, #####: 783: file_info[i].color, file_info[i].name, df_c); %%%%%: 783-block 0 call 0 never executed unconditional 1 never executed -: 784: } -: 785: } else { 15: 786: if (no_eln) { 15: 786-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 15 #####: 787: xprintf("%s%s%s", file_info[i].color, #####: 788: file_info[i].name, df_c); %%%%%: 788-block 0 call 0 never executed unconditional 1 never executed -: 789: } else { 15: 790: xprintf("%s%d%s %s%s%s", el_c, i + 1, df_c, 15: 791: file_info[i].color, file_info[i].name, df_c); 15: 791-block 0 call 0 returned 15 unconditional 1 taken 15 -: 792:/* line_sz += (size_t)sprintf(line_buf + line_sz, -: 793: "%s%d%s %s%s%s", el_c, i + 1, df_c, -: 794: file_info[i].color, file_info[i].name, df_c); */ -: 795: } -: 796: } -: 797:#else -: 798: if (no_eln) { -: 799: xprintf("%s%s%s", file_info[i].color, file_info[i].name, df_c); -: 800: } else { -: 801: xprintf("%s%d%s %s%s%s", el_c, i + 1, df_c, -: 802: file_info[i].color, file_info[i].name, df_c); -: 803: } -: 804:#endif /* !_NO_ICONS */ -: 805: 15: 806: if (file_info[i].dir && classify) { 15: 806-block 0 branch 0 taken 6 (fallthrough) branch 1 taken 9 6: 806-block 1 branch 2 taken 6 (fallthrough) branch 3 taken 0 -: 807:// *(line_buf + line_sz++) = '/'; 6: 808: putchar('/'); 6: 808-block 0 call 0 returned 6 6: 809: if (file_info[i].filesn > 0 && files_counter) { branch 0 taken 5 (fallthrough) branch 1 taken 1 5: 809-block 0 branch 2 taken 5 (fallthrough) branch 3 taken 0 5: 810: fputs(xitoa(file_info[i].filesn), stdout); 5: 810-block 0 call 0 returned 5 call 1 returned 5 unconditional 2 taken 5 -: 811:/* char *fc = xitoa(file_info[i].filesn); -: 812: strcat(line_buf + line_sz, xitoa(file_info[i].filesn)); -: 813: line_sz += strlen(fc); */ -: 814: } -: 815: } -: 816: } -: 817: -: 818: /* No color */ -: 819: else { -: 820:#ifndef _NO_ICONS #####: 821: if (icons) { %%%%%: 821-block 0 branch 0 never executed branch 1 never executed #####: 822: if (no_eln) %%%%%: 822-block 0 branch 0 never executed branch 1 never executed #####: 823: xprintf("%s %s", file_info[i].icon, file_info[i].name); %%%%%: 823-block 0 call 0 never executed unconditional 1 never executed -: 824: else #####: 825: xprintf("%s%d%s %s %s", el_c, i + 1, df_c, #####: 826: file_info[i].icon, file_info[i].name); %%%%%: 826-block 0 call 0 never executed unconditional 1 never executed -: 827: } else { #####: 828: if (no_eln) %%%%%: 828-block 0 branch 0 never executed branch 1 never executed #####: 829: fputs(file_info[i].name, stdout); %%%%%: 829-block 0 call 0 never executed unconditional 1 never executed -: 830: else #####: 831: xprintf("%s%d%s %s", el_c, i + 1, df_c, file_info[i].name); %%%%%: 831-block 0 call 0 never executed unconditional 1 never executed -: 832: } -: 833:#else -: 834: if (no_eln) -: 835: fputs(file_info[i].name, stdout); -: 836: else -: 837: xprintf("%s%d%s %s", el_c, i + 1, df_c, file_info[i].name); -: 838:#endif /* !_NO_ICONS */ -: 839: #####: 840: if (classify) { %%%%%: 840-block 0 branch 0 never executed branch 1 never executed #####: 841: switch (file_info[i].type) { %%%%%: 841-block 0 branch 0 never executed branch 1 never executed branch 2 never executed branch 3 never executed branch 4 never executed branch 5 never executed #####: 842: case DT_DIR: #####: 843: ind_char = 0; #####: 844: putchar('/'); %%%%%: 844-block 0 call 0 never executed #####: 845: if (file_info[i].filesn > 0 && files_counter) branch 0 never executed branch 1 never executed %%%%%: 845-block 0 branch 2 never executed branch 3 never executed #####: 846: fputs(xitoa(file_info[i].filesn), stdout); %%%%%: 846-block 0 call 0 never executed call 1 never executed unconditional 2 never executed #####: 847: break; %%%%%: 847-block 0 unconditional 0 never executed -: 848: #####: 849: case DT_FIFO: putchar('|'); break; %%%%%: 849-block 0 call 0 never executed unconditional 1 never executed #####: 850: case DT_LNK: putchar('@'); break; %%%%%: 850-block 0 call 0 never executed unconditional 1 never executed #####: 851: case DT_SOCK: putchar('='); break; %%%%%: 851-block 0 call 0 never executed unconditional 1 never executed #####: 852: case DT_UNKNOWN: putchar('?'); break; %%%%%: 852-block 0 call 0 never executed unconditional 1 never executed #####: 853: default: ind_char = 0; break; %%%%%: 853-block 0 unconditional 0 never executed -: 854: } -: 855: } -: 856: } -: 857: 15: 858: if (!last_column) { 15: 858-block 0 branch 0 taken 12 (fallthrough) branch 1 taken 3 -: 859: /* Add spaces needed to equate the longest file name length */ -: 860:#ifndef _NO_ICONS 12*: 861: int cur_len = (int)file_info[i].eln_n + 1 + (icons ? 3 : 0) 12: 861-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 12 %%%%%: 861-block 1 unconditional 2 never executed 12: 861-block 2 unconditional 3 taken 12 -: 862:#else -: 863: int cur_len = (int)file_info[i].eln_n + 1 -: 864:#endif 12: 865: + (int)file_info[i].len + (ind_char ? 1 : 0); 12: 866: if (classify) { 12: 866-block 0 branch 0 taken 12 (fallthrough) branch 1 taken 0 12: 867: if (file_info[i].dir) 12: 867-block 0 branch 0 taken 6 (fallthrough) branch 1 taken 6 6: 868: cur_len++; 6: 868-block 0 unconditional 0 taken 6 12: 869: if (file_info[i].filesn > 0 && files_counter 12: 869-block 0 branch 0 taken 5 (fallthrough) branch 1 taken 7 5: 869-block 1 branch 2 taken 5 (fallthrough) branch 3 taken 0 5: 870: && file_info[i].ruser) 5: 870-block 0 branch 0 taken 5 (fallthrough) branch 1 taken 0 5*: 871: cur_len += DIGINUM((int)file_info[i].filesn); 5: 871-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 5 %%%%%: 871-block 1 branch 2 never executed branch 3 never executed %%%%%: 871-block 2 branch 4 never executed branch 5 never executed %%%%%: 871-block 3 branch 6 never executed branch 7 never executed %%%%%: 871-block 4 branch 8 never executed branch 9 never executed %%%%%: 871-block 5 branch 10 never executed branch 11 never executed %%%%%: 871-block 6 branch 12 never executed branch 13 never executed %%%%%: 871-block 7 branch 14 never executed branch 15 never executed %%%%%: 871-block 8 branch 16 never executed branch 17 never executed %%%%%: 871-block 9 unconditional 18 never executed %%%%%: 871-block 10 unconditional 19 never executed %%%%%: 871-block 11 unconditional 20 never executed %%%%%: 871-block 12 unconditional 21 never executed %%%%%: 871-block 13 unconditional 22 never executed %%%%%: 871-block 14 unconditional 23 never executed %%%%%: 871-block 15 unconditional 24 never executed %%%%%: 871-block 16 unconditional 25 never executed %%%%%: 871-block 17 unconditional 26 never executed %%%%%: 871-block 18 unconditional 27 never executed %%%%%: 871-block 19 unconditional 28 never executed %%%%%: 871-block 20 unconditional 29 never executed %%%%%: 871-block 21 unconditional 30 never executed %%%%%: 871-block 22 unconditional 31 never executed %%%%%: 871-block 23 unconditional 32 never executed %%%%%: 871-block 24 unconditional 33 never executed %%%%%: 871-block 25 unconditional 34 never executed 5: 871-block 26 unconditional 35 taken 5 5: 871-block 27 unconditional 36 taken 5 -: 872: } -: 873: 12: 874: int diff = (int)longest - cur_len; -: 875:// xprintf("\x1b[%dC", diff + 1); -: 876: register int j; 90: 877: for (j = diff + 1; j--;) { 12: 877-block 0 unconditional 0 taken 12 90: 877-block 1 branch 1 taken 78 branch 2 taken 12 78: 878: putchar(' '); 78: 878-block 0 call 0 returned 78 unconditional 1 taken 78 -: 879:// *(line_buf + line_sz++) = ' '; -: 880: } -: 881: } else { -: 882:/* *(line_buf + line_sz++) = '\n'; -: 883: fputs(line_buf, stdout); -: 884: memset(line_buf, '\0', line_sz); -: 885: line_sz = 0; */ 3: 886: putchar('\n'); 3: 886-block 0 call 0 returned 3 unconditional 1 taken 3 -: 887: -: 888: } -: 889: } -: 890: 3: 891: if (!last_column) 3: 891-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 2 2: 892: putchar('\n'); 2: 892-block 0 call 0 returned 2 unconditional 1 taken 2 -: 893: -: 894:// free(line_buf); -: 895: 1: 896:END: 1: 896-block 0 unconditional 0 taken 1 -: 897: /* Unhide the cursor */ 3: 898: fputs("\x1b[?25h", stdout); 3: 898-block 0 call 0 returned 3 -: 899: 3: 900: if (close_dir && closedir(dir) == -1) branch 0 taken 3 (fallthrough) branch 1 taken 0 3: 900-block 0 call 2 returned 3 branch 3 taken 0 (fallthrough) branch 4 taken 3 #####: 901: return EXIT_FAILURE; %%%%%: 901-block 0 unconditional 0 never executed -: 902: 3: 903: if (xargs.list_and_quit == 1) 3: 903-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 3 #####: 904: exit(exit_code); %%%%%: 904-block 0 call 0 never executed -: 905: 3: 906: if (reset_pager) 3: 906-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 3 #####: 907: pager = 1; %%%%%: 907-block 0 unconditional 0 never executed -: 908: 3*: 909: if (max_files != UNSET && (int)files > max_files) 3: 909-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 3 %%%%%: 909-block 1 branch 2 never executed branch 3 never executed #####: 910: printf("%d/%zu\n", max_files, files); %%%%%: 910-block 0 call 0 never executed unconditional 1 never executed -: 911: -: 912: /* Print a dividing line between the files list and the -: 913: * prompt */ 3: 914: print_div_line(); 3: 914-block 0 call 0 returned 3 -: 915: 3: 916: if (dirhist_map) { branch 0 taken 0 (fallthrough) branch 1 taken 3 -: 917: /* Print current, previous, and next entries */ #####: 918: print_dirhist_map(); %%%%%: 918-block 0 call 0 never executed #####: 919: print_div_line(); call 0 never executed unconditional 1 never executed -: 920: } -: 921: 3: 922: if (disk_usage) 3: 922-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 3 #####: 923: print_disk_usage(); %%%%%: 923-block 0 call 0 never executed unconditional 1 never executed -: 924: 3: 925: if (sort_switch) 3: 925-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 3 #####: 926: print_sort_method(); %%%%%: 926-block 0 call 0 never executed unconditional 1 never executed -: 927: 3*: 928: if (print_selfiles && sel_n > 0) 3: 928-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 3 %%%%%: 928-block 1 branch 2 never executed branch 3 never executed #####: 929: _print_selfiles(term_rows); %%%%%: 929-block 0 call 0 never executed unconditional 1 never executed -: 930: -: 931: /* Unhide the cursor */ 3: 932: fputs("\x1b[?25h", stdout); 3: 932-block 0 call 0 returned 3 -: 933: -: 934:#ifdef _LIST_SPEED -: 935: clock_t end = clock(); -: 936: printf("list_dir time: %f\n", (double)(end-start)/CLOCKS_PER_SEC); -: 937:#endif -: 938: 3: 939: return EXIT_SUCCESS; unconditional 0 taken 3 -: 940:} -: 941: -: 942:/* List files in the current working directory. Uses file type colors -: 943: * and columns. Return zero on success or one on error */ -: 944:int function list_dir called 305 returned 100% blocks executed 69% 305: 945:list_dir(void) -: 946:{ -: 947:#ifdef _LIST_SPEED -: 948: clock_t start = clock(); -: 949:#endif 305: 950: if (clear_screen) 305: 950-block 0 branch 0 taken 6 (fallthrough) branch 1 taken 299 6: 951: CLEAR; 6: 951-block 0 call 0 returned 6 unconditional 1 taken 6 -: 952: 305: 953: if (light_mode) 305: 953-block 0 branch 0 taken 3 (fallthrough) branch 1 taken 302 3: 954: return list_dir_light(); 3: 954-block 0 call 0 returned 3 unconditional 1 taken 3 -: 955: -: 956: /* Hide the cursor while listing */ 302: 957: fputs("\x1b[?25l", stdout); 302: 957-block 0 call 0 returned 302 -: 958: -: 959: DIR *dir; -: 960: struct dirent *ent; -: 961: struct stat attr; 302: 962: int reset_pager = 0; 302: 963: int close_dir = 1; -: 964: /* Get terminal current amount of rows and columns */ -: 965: struct winsize w; 302: 966: ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); call 0 returned 302 -: 967: /* These two are global */ 302: 968: term_cols = w.ws_col; 302: 969: term_rows = w.ws_row; -: 970: 302: 971: if ((dir = opendir(ws[cur_ws].path)) == NULL) { call 0 returned 302 branch 1 taken 0 (fallthrough) branch 2 taken 302 #####: 972: fprintf(stderr, "%s: %s: %s\n", PROGRAM_NAME, ws[cur_ws].path, call 0 never executed #####: 973: strerror(errno)); %%%%%: 973-block 0 call 0 never executed #####: 974: close_dir = 0; #####: 975: goto END; unconditional 0 never executed -: 976: } -: 977: -: 978:#ifdef LINUX_INOTIFY 302: 979: if (inotify_wd >= 0) { 302: 979-block 0 branch 0 taken 298 (fallthrough) branch 1 taken 4 298: 980: inotify_rm_watch(inotify_fd, inotify_wd); 298: 980-block 0 call 0 returned 298 298: 981: inotify_wd = -1; 298: 982: watch = 0; unconditional 0 taken 298 -: 983: } 302: 984: inotify_wd = inotify_add_watch(inotify_fd, ws[cur_ws].path, INOTIFY_MASK); 302: 984-block 0 call 0 returned 302 302: 985: if (inotify_wd > 0) branch 0 taken 302 (fallthrough) branch 1 taken 0 302: 986: watch = 1; 302: 986-block 0 unconditional 0 taken 302 -: 987: -: 988:#elif defined(BSD_KQUEUE) -: 989: if (event_fd >= 0) { -: 990: close(event_fd); -: 991: event_fd = -1; -: 992: watch = 0; -: 993: } -: 994:#if defined(O_EVTONLY) -: 995: event_fd = open(ws[cur_ws].path, O_EVTONLY); -: 996:#else -: 997: event_fd = open(ws[cur_ws].path, O_RDONLY); -: 998:#endif -: 999: if (event_fd >= 0) { -: 1000: /* Prepare for events */ -: 1001: EV_SET(&events_to_monitor[0], event_fd, EVFILT_VNODE, -: 1002: EV_ADD | EV_CLEAR, KQUEUE_FFLAGS, 0, ws[cur_ws].path); -: 1003: watch = 1; -: 1004: /* Register events */ -: 1005: kevent(kq, events_to_monitor, NUM_EVENT_SLOTS, -: 1006: NULL, 0, NULL); -: 1007: -: 1008: } -: 1009:#endif /* LINUX_INOTIFY */ -: 1010: 302: 1011: int fd = dirfd(dir); 302: 1011-block 0 call 0 returned 302 -: 1012: -: 1013: /* ########################################## -: 1014: * # GATHER AND STORE FILE INFORMATION # -: 1015: * ########################################## */ -: 1016: 302: 1017: errno = 0; 302: 1018: longest = 0; 302: 1019: register unsigned int n = 0; 302: 1020: unsigned int total_dents = 0, count = 0; -: 1021: 302: 1022: file_info = (struct fileinfo *)xnmalloc(ENTRY_N + 2, call 0 returned 302 -: 1023: sizeof(struct fileinfo)); -: 1024: 41077: 1025: while ((ent = readdir(dir))) { unconditional 0 taken 302 41077: 1025-block 0 call 1 returned 41077 branch 2 taken 40775 branch 3 taken 302 (fallthrough) 40775: 1026: char *ename = ent->d_name; -: 1027: /* Skip self and parent directories */ 40775: 1028: if (*ename == '.' && (!ename[1] || (ename[1] == '.' && !ename[2]))) 40775: 1028-block 0 branch 0 taken 3156 (fallthrough) branch 1 taken 37619 3156: 1028-block 1 branch 2 taken 2854 (fallthrough) branch 3 taken 302 2854: 1028-block 2 branch 4 taken 302 (fallthrough) branch 5 taken 2552 302: 1028-block 3 branch 6 taken 302 (fallthrough) branch 7 taken 0 604: 1029: continue; 604: 1029-block 0 unconditional 0 taken 604 -: 1030: -: 1031: /* Filter files according to FILTER */ 40171: 1032: if (filter) { 40171: 1032-block 0 branch 0 taken 28 (fallthrough) branch 1 taken 40143 28: 1033: if (regexec(®ex_exp, ename, 0, NULL, 0) == EXIT_SUCCESS) { 28: 1033-block 0 call 0 returned 28 branch 1 taken 16 (fallthrough) branch 2 taken 12 16: 1034: if (filter_rev) 16: 1034-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 14 2: 1035: continue; 2: 1035-block 0 unconditional 0 taken 2 12: 1036: } else if (!filter_rev) { 12: 1036-block 0 branch 0 taken 7 (fallthrough) branch 1 taken 5 7: 1037: continue; 7: 1037-block 0 unconditional 0 taken 7 -: 1038: } -: 1039: } -: 1040: 40162: 1041: if (!show_hidden && *ename == '.') 40162: 1041-block 0 branch 0 taken 154 (fallthrough) branch 1 taken 40008 154: 1041-block 1 branch 2 taken 96 (fallthrough) branch 3 taken 58 96: 1042: continue; 96: 1042-block 0 unconditional 0 taken 96 -: 1043: 40066: 1044: fstatat(fd, ename, &attr, AT_SYMLINK_NOFOLLOW); 40066: 1044-block 0 call 0 returned 40066 -: 1045: -: 1046:#if !defined(_DIRENT_HAVE_D_TYPE) -: 1047: if (only_dirs && (attr.st_mode & S_IFMT) == S_IFDIR) -: 1048:#else 40066*: 1049: if (only_dirs && ent->d_type != DT_DIR) branch 0 taken 0 (fallthrough) branch 1 taken 40066 %%%%%: 1049-block 0 branch 2 never executed branch 3 never executed -: 1050:#endif #####: 1051: continue; %%%%%: 1051-block 0 unconditional 0 never executed -: 1052: 40066: 1053: if (count > ENTRY_N) { 40066: 1053-block 0 branch 0 taken 524 (fallthrough) branch 1 taken 39542 524: 1054: count = 0; 524: 1055: total_dents = n + ENTRY_N; 524: 1056: file_info = xrealloc(file_info, (total_dents + 2) * sizeof(struct fileinfo)); 524: 1056-block 0 call 0 returned 524 unconditional 1 taken 524 -: 1057: } -: 1058: 40066: 1059: file_info[n].name = (char *)xnmalloc(NAME_MAX + 1, sizeof(char)); 40066: 1059-block 0 call 0 returned 40066 -: 1060: 40066: 1061: if (!unicode) { branch 0 taken 70 (fallthrough) branch 1 taken 39996 70: 1062: file_info[n].len = xstrsncpy(file_info[n].name, ename, NAME_MAX); 70: 1062-block 0 call 0 returned 70 unconditional 1 taken 70 -: 1063: } else { 39996: 1064: xstrsncpy(file_info[n].name, ename, NAME_MAX); 39996: 1064-block 0 call 0 returned 39996 39996: 1065: file_info[n].len = wc_xstrlen(ename); call 0 returned 39996 unconditional 1 taken 39996 -: 1066: } -: 1067: 40066: 1068: file_info[n].exec = 0; -: 1069: -: 1070:#if !defined(_DIRENT_HAVE_D_TYPE) -: 1071: switch (attr.st_mode & S_IFMT) { -: 1072: case S_IFBLK: file_info[n].type = DT_BLK; break; -: 1073: case S_IFCHR: file_info[n].type = DT_CHR; break; -: 1074: case S_IFDIR: file_info[n].type = DT_DIR; break; -: 1075: case S_IFIFO: file_info[n].type = DT_FIFO; break; -: 1076: case S_IFLNK: file_info[n].type = DT_LNK; break; -: 1077: case S_IFREG: file_info[n].type = DT_REG; break; -: 1078: case S_IFSOCK: file_info[n].type = DT_SOCK; break; -: 1079: default: file_info[n].type = DT_UNKNOWN; break; -: 1080: } -: 1081: file_info[n].dir = (file_info[n].type == DT_DIR) ? 1 : 0; -: 1082: file_info[n].symlink = (file_info[n].type == DT_LNK) ? 1 : 0; -: 1083:#else 40066: 1084: file_info[n].dir = (ent->d_type == DT_DIR) ? 1 : 0; 40066: 1085: file_info[n].symlink = (ent->d_type == DT_LNK) ? 1 : 0; 40066: 1086: file_info[n].type = ent->d_type; -: 1087:#endif /* _DIRENT_HAVE_D_TYPE */ -: 1088: 40066: 1089: file_info[n].inode = ent->d_ino; 40066: 1090: file_info[n].linkn = attr.st_nlink; 40066: 1091: file_info[n].size = attr.st_size; -: 1092: 40066: 1093: file_info[n].uid = attr.st_uid; 40066: 1094: file_info[n].gid = attr.st_gid; 40066: 1095: file_info[n].mode = attr.st_mode; 40066: 1096: if (long_view) 40066: 1096-block 0 branch 0 taken 214 (fallthrough) branch 1 taken 39852 214: 1097: file_info[n].ltime = (time_t)attr.st_mtim.tv_sec; 214: 1097-block 0 unconditional 0 taken 214 -: 1098: -: 1099:/* if (long_view) { -: 1100: file_info[n].uid = attr.st_uid; -: 1101: file_info[n].gid = attr.st_gid; -: 1102: file_info[n].ltime = (time_t)attr.st_mtim.tv_sec; -: 1103: file_info[n].mode = attr.st_mode; -: 1104: } else if (sort == SOWN || sort == SGRP) { -: 1105: file_info[n].uid = attr.st_uid; -: 1106: file_info[n].gid = attr.st_gid; -: 1107: } */ -: 1108: 40066: 1109: file_info[n].color = (char *)NULL; 40066: 1110: file_info[n].ext_color = (char *)NULL; -: 1111: -: 1112:#ifndef _NO_ICONS -: 1113: /* Default icon for all files */ 40066: 1114: file_info[n].icon = DEF_FILE_ICON; 40066: 1115: file_info[n].icon_color = DEF_FILE_ICON_COLOR; -: 1116:#endif -: 1117: 40066: 1118: file_info[n].ruser = 1; 40066: 1119: file_info[n].filesn = 0; -: 1120: 40066: 1121: switch (sort) { 40066: 1121-block 0 branch 0 taken 60 branch 1 taken 60 branch 2 taken 60 branch 3 taken 60 branch 4 taken 39826 60: 1122: case SATIME: 60: 1123: file_info[n].time = (time_t)attr.st_atime; 60: 1124: break; 60: 1124-block 0 unconditional 0 taken 60 -: 1125:#if defined(HAVE_ST_BIRTHTIME) || defined(__BSD_VISIBLE) -: 1126: case SBTIME: -: 1127:#ifdef __OpenBSD__ -: 1128: file_info[n].time = (time_t)attr.__st_birthtim.tv_sec; -: 1129:#else -: 1130: file_info[n].time = (time_t)attr.st_birthtime; -: 1131:#endif /* HAVE_ST_BIRTHTIME || __BSD_VISIBLE */ -: 1132: break; -: 1133:#elif defined(_STATX) 60: 1134: case SBTIME: { -: 1135: struct statx attx; 60: 1136: if (statx(AT_FDCWD, ename, AT_SYMLINK_NOFOLLOW, 60: 1136-block 0 call 0 returned 60 branch 1 taken 0 (fallthrough) branch 2 taken 60 -: 1137: STATX_BTIME, &attx) == -1) #####: 1138: file_info[n].time = 0; %%%%%: 1138-block 0 unconditional 0 never executed -: 1139: else 60: 1140: file_info[n].time = (time_t)attx.stx_btime.tv_sec; 60: 1140-block 0 unconditional 0 taken 60 60: 1141: } break; 60: 1141-block 0 unconditional 0 taken 60 -: 1142:#else -: 1143: case SBTIME: file_info[n].time = (time_t)attr.st_ctime; break; -: 1144:#endif /* _STATX */ 60: 1145: case SCTIME: file_info[n].time = (time_t)attr.st_ctime; break; 60: 1145-block 0 unconditional 0 taken 60 60: 1146: case SMTIME: file_info[n].time = (time_t)attr.st_mtime; break; 60: 1146-block 0 unconditional 0 taken 60 39826: 1147: default: file_info[n].time = 0; break; 39826: 1147-block 0 unconditional 0 taken 39826 -: 1148: } -: 1149: 40066: 1150: switch (file_info[n].type) { 40066: 1150-block 0 branch 0 taken 2804 branch 1 taken 4033 branch 2 taken 33187 branch 3 taken 1 branch 4 taken 0 branch 5 taken 0 branch 6 taken 0 branch 7 taken 41 branch 8 taken 0 -: 1151: 2804: 1152: case DT_DIR: -: 1153:#ifndef _NO_ICONS 2804: 1154: if (icons) { 2804: 1154-block 0 branch 0 taken 3 (fallthrough) branch 1 taken 2801 3: 1155: get_dir_icon(file_info[n].name, (int)n); 3: 1155-block 0 call 0 returned 3 -: 1156: -: 1157: /* If set from the color scheme file */ 3: 1158: if (*dir_ico_c) branch 0 taken 3 (fallthrough) branch 1 taken 0 3: 1159: file_info[n].icon_color = dir_ico_c; 3: 1159-block 0 unconditional 0 taken 3 -: 1160: } -: 1161:#endif /* _NO_ICONS */ 2804: 1162: if (files_counter) { 2804: 1162-block 0 branch 0 taken 2801 (fallthrough) branch 1 taken 3 2801: 1163: file_info[n].filesn = count_dir(ename, NO_CPOP) - 2; 2801: 1163-block 0 call 0 returned 2801 unconditional 1 taken 2801 -: 1164: } else { 3: 1165: if (check_file_access(file_info[n]) == 0) 3: 1165-block 0 call 0 returned 3 branch 1 taken 0 (fallthrough) branch 2 taken 3 #####: 1166: file_info[n].filesn = -1; %%%%%: 1166-block 0 unconditional 0 never executed -: 1167: else 3: 1168: file_info[n].filesn = 1; 3: 1168-block 0 unconditional 0 taken 3 -: 1169: } 2804: 1170: if (file_info[n].filesn > 0) { /* S_ISVTX*/ 2804: 1170-block 0 branch 0 taken 2568 (fallthrough) branch 1 taken 236 2568: 1171: file_info[n].color = (attr.st_mode & 01000) 2568: 1171-block 0 unconditional 0 taken 2568 1*: 1172: ? ((attr.st_mode & 00002) ? tw_c : st_c) 1: 1172-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 0 1: 1172-block 1 unconditional 2 taken 1 %%%%%: 1172-block 2 unconditional 3 never executed 2569*: 1173: : ((attr.st_mode & 00002) ? ow_c : di_c); 2568: 1173-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 2567 1: 1173-block 1 unconditional 2 taken 1 2567: 1173-block 2 branch 3 taken 0 (fallthrough) branch 4 taken 2567 %%%%%: 1173-block 3 unconditional 5 never executed 2567: 1173-block 4 unconditional 6 taken 2567 2567: 1173-block 5 unconditional 7 taken 2567 -: 1174: /* S_ISWOTH*/ 236: 1175: } else if (file_info[n].filesn == 0) { 236: 1175-block 0 branch 0 taken 226 (fallthrough) branch 1 taken 10 226: 1176: file_info[n].color = (attr.st_mode & 01000) 226: 1176-block 0 unconditional 0 taken 226 1*: 1177: ? ((attr.st_mode & 00002) ? tw_c : st_c) 1: 1177-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 0 1: 1177-block 1 unconditional 2 taken 1 %%%%%: 1177-block 2 unconditional 3 never executed 227*: 1178: : ((attr.st_mode & 00002) ? ow_c : ed_c); 226: 1178-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 225 1: 1178-block 1 unconditional 2 taken 1 225: 1178-block 2 branch 3 taken 0 (fallthrough) branch 4 taken 225 %%%%%: 1178-block 3 unconditional 5 never executed 225: 1178-block 4 unconditional 6 taken 225 225: 1178-block 5 unconditional 7 taken 225 -: 1179: } else { 10: 1180: file_info[n].color = nd_c; -: 1181:#ifndef _NO_ICONS 10: 1182: file_info[n].icon = ICON_LOCK; 10: 1183: file_info[n].icon_color = YELLOW; 10: 1183-block 0 unconditional 0 taken 10 -: 1184:#endif -: 1185: } -: 1186: 2804: 1187: break; 2804: 1187-block 0 unconditional 0 taken 2804 -: 1188: 4033: 1189: case DT_LNK: { -: 1190:#ifndef _NO_ICONS 4033: 1191: file_info[n].icon = ICON_LINK; -: 1192:#endif 4033: 1193: if (!follow_symlinks) { 4033: 1193-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 4033 #####: 1194: file_info[n].color = ln_c; #####: 1195: break; %%%%%: 1195-block 0 unconditional 0 never executed -: 1196: } -: 1197: struct stat attrl; 4033: 1198: if (fstatat(fd, ename, &attrl, 0) == -1) { 4033: 1198-block 0 call 0 returned 4033 branch 1 taken 54 (fallthrough) branch 2 taken 3979 54: 1199: file_info[n].color = or_c; 54: 1199-block 0 unconditional 0 taken 54 -: 1200: } else { 3979: 1201: if (S_ISDIR(attrl.st_mode)) { 3979: 1201-block 0 branch 0 taken 61 (fallthrough) branch 1 taken 3918 61: 1202: file_info[n].dir = 1; -: 1203: files_counter 61: 1204: ? (file_info[n].filesn = (count_dir(ename, NO_CPOP) - 2)) 61: 1204-block 0 call 0 returned 61 122*: 1205: : (file_info[n].filesn = 0); 61: 1205-block 0 branch 0 taken 61 (fallthrough) branch 1 taken 0 unconditional 2 taken 61 %%%%%: 1205-block 1 unconditional 3 never executed -: 1206: } 3979: 1207: file_info[n].color = ln_c; 3979: 1207-block 0 unconditional 0 taken 3979 -: 1208: } -: 1209: } 4033: 1210: break; 4033: 1210-block 0 unconditional 0 taken 4033 -: 1211: 33187: 1212: case DT_REG: { -: 1213:#ifdef _LINUX_CAP -: 1214: cap_t cap; -: 1215:#endif -: 1216: /* Do not perform the access check if the user is root */ 33187: 1217: if (!(flags & ROOT_USR) 33187: 1217-block 0 branch 0 taken 33185 (fallthrough) branch 1 taken 2 33185: 1218: && check_file_access(file_info[n]) == 0) { 33185: 1218-block 0 call 0 returned 33185 branch 1 taken 18 (fallthrough) branch 2 taken 33167 -: 1219:#ifndef _NO_ICONS 18: 1220: file_info[n].icon = ICON_LOCK; 18: 1221: file_info[n].icon_color = YELLOW; -: 1222:#endif 18: 1223: file_info[n].color = nf_c; 18: 1223-block 0 unconditional 0 taken 18 33169: 1224: } else if (attr.st_mode & 04000) { /* SUID */ 33169: 1224-block 0 branch 0 taken 210 (fallthrough) branch 1 taken 32959 210: 1225: file_info[n].exec = 1; 210: 1226: file_info[n].color = su_c; -: 1227:#ifndef _NO_ICONS 210: 1228: file_info[n].icon = ICON_EXEC; 210: 1228-block 0 unconditional 0 taken 210 -: 1229:#endif 32959: 1230: } else if (attr.st_mode & 02000) { /* SGID */ 32959: 1230-block 0 branch 0 taken 18 (fallthrough) branch 1 taken 32941 18: 1231: file_info[n].exec = 1; 18: 1232: file_info[n].color = sg_c; -: 1233:#ifndef _NO_ICONS 18: 1234: file_info[n].icon = ICON_EXEC; 18: 1234-block 0 unconditional 0 taken 18 -: 1235:#endif -: 1236: } -: 1237: -: 1238:#ifdef _LINUX_CAP 32941: 1239: else if (check_cap && (cap = cap_get_file(ename))) { 32941: 1239-block 0 branch 0 taken 32941 (fallthrough) branch 1 taken 0 32941: 1239-block 1 call 2 returned 32941 branch 3 taken 45 (fallthrough) branch 4 taken 32896 45: 1240: file_info[n].color = ca_c; 45: 1241: cap_free(cap); 45: 1241-block 0 call 0 returned 45 unconditional 1 taken 45 -: 1242: } -: 1243:#endif -: 1244: 32896: 1245: else if ((attr.st_mode & 00100) /* Exec */ 32896: 1245-block 0 branch 0 taken 4906 (fallthrough) branch 1 taken 27990 4906: 1246: || (attr.st_mode & 00010) || (attr.st_mode & 00001)) { 4906: 1246-block 0 branch 0 taken 4906 (fallthrough) branch 1 taken 0 4906: 1246-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 4906 27990: 1247: file_info[n].exec = 1; -: 1248:#ifndef _NO_ICONS 27990: 1249: file_info[n].icon = ICON_EXEC; -: 1250:#endif 27990: 1251: if (file_info[n].size == 0) 27990: 1251-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 27989 1: 1252: file_info[n].color = ee_c; 1: 1252-block 0 unconditional 0 taken 1 -: 1253: else 27989: 1254: file_info[n].color = ex_c; 27989: 1254-block 0 unconditional 0 taken 27989 4906: 1255: } else if (file_info[n].size == 0) { 4906: 1255-block 0 branch 0 taken 428 (fallthrough) branch 1 taken 4478 428: 1256: file_info[n].color = ef_c; 428: 1256-block 0 unconditional 0 taken 428 4478: 1257: } else if (file_info[n].linkn > 1) { /* Multi-hardlink */ 4478: 1257-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 4478 #####: 1258: file_info[n].color = mh_c; %%%%%: 1258-block 0 unconditional 0 never executed -: 1259: } else { /* Regular file */ 4478: 1260: file_info[n].color = fi_c; 4478: 1260-block 0 unconditional 0 taken 4478 -: 1261: } -: 1262: -: 1263: /* Check file extension */ 33187: 1264: char *ext = (char *)NULL; 33187: 1265: if (check_ext) 33187: 1265-block 0 branch 0 taken 33187 (fallthrough) branch 1 taken 0 33187: 1266: ext = strrchr(file_info[n].name, '.'); 33187: 1266-block 0 unconditional 0 taken 33187 -: 1267: /* Make sure not to take a hidden file for a file extension */ 33187: 1268: if (ext && ext != file_info[n].name) { 33187: 1268-block 0 branch 0 taken 4642 (fallthrough) branch 1 taken 28545 4642: 1268-block 1 branch 2 taken 3822 (fallthrough) branch 3 taken 820 -: 1269:#ifndef _NO_ICONS 3822: 1270: if (icons) 3822: 1270-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 3820 2: 1271: get_ext_icon(ext, (int)n); 2: 1271-block 0 call 0 returned 2 unconditional 1 taken 2 -: 1272:#endif -: 1273: /* Check extension color only if some is defined */ 3822: 1274: if (ext_colors_n) { 3822: 1274-block 0 branch 0 taken 3818 (fallthrough) branch 1 taken 4 3818: 1275: char *extcolor = get_ext_color(ext); 3818: 1275-block 0 call 0 returned 3818 -: 1276: 3818: 1277: if (extcolor) { branch 0 taken 486 (fallthrough) branch 1 taken 3332 972: 1278: file_info[n].ext_color = (char *)xnmalloc( 486: 1279: strlen(extcolor) + 4, sizeof(char)); 486: 1279-block 0 call 0 returned 486 486: 1280: sprintf(file_info[n].ext_color, "\x1b[%sm", -: 1281: extcolor); 486: 1282: file_info[n].color = file_info[n].ext_color; 486: 1283: extcolor = (char *)NULL; unconditional 0 taken 486 -: 1284: } -: 1285: } -: 1286: } -: 1287: -: 1288:#ifndef _NO_ICONS -: 1289: /* No extension. Check icons for specific file names */ 29365: 1290: else if (icons) 29365: 1290-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 29364 1: 1291: get_file_icon(file_info[n].name, (int)n); 1: 1291-block 0 call 0 returned 1 unconditional 1 taken 1 -: 1292:#endif -: 1293: -: 1294: } /* End of DT_REG block */ 33187: 1295: break; 33187: 1295-block 0 unconditional 0 taken 33187 -: 1296: 1: 1297: case DT_SOCK: file_info[n].color = so_c; break; 1: 1297-block 0 unconditional 0 taken 1 #####: 1298: case DT_FIFO: file_info[n].color = pi_c; break; %%%%%: 1298-block 0 unconditional 0 never executed #####: 1299: case DT_BLK: file_info[n].color = bd_c; break; %%%%%: 1299-block 0 unconditional 0 never executed #####: 1300: case DT_CHR: file_info[n].color = cd_c; break; %%%%%: 1300-block 0 unconditional 0 never executed 41: 1301: case DT_UNKNOWN: file_info[n].color = uf_c; break; 41: 1301-block 0 unconditional 0 taken 41 #####: 1302: default: file_info[n].color = df_c; break; %%%%%: 1302-block 0 unconditional 0 never executed -: 1303: } -: 1304: -: 1305:#ifndef _NO_ICONS 40066*: 1306: if (xargs.icons_use_file_color == 1 && icons) 40066: 1306-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 40066 %%%%%: 1306-block 1 branch 2 never executed branch 3 never executed #####: 1307: file_info[n].icon_color = file_info[n].color; %%%%%: 1307-block 0 unconditional 0 never executed -: 1308:#endif -: 1309: 40066: 1310: n++; 40066: 1311: count++; 40066: 1311-block 0 unconditional 0 taken 40066 -: 1312: } -: 1313: 302: 1314: file_info[n].name = (char *)NULL; 302: 1315: files = n; -: 1316: 302: 1317: if (n == 0) { 302: 1317-block 0 branch 0 taken 4 (fallthrough) branch 1 taken 298 4*: 1318: printf("%s. ..%s\n", colorize ? di_c : df_c, df_c); 4: 1318-block 0 branch 0 taken 4 (fallthrough) branch 1 taken 0 4: 1318-block 1 unconditional 2 taken 4 %%%%%: 1318-block 2 unconditional 3 never executed 4: 1318-block 3 call 4 returned 4 4: 1319: free(file_info); 4: 1320: goto END; unconditional 0 taken 4 -: 1321: } -: 1322: -: 1323: /* ############################################# -: 1324: * # SORT FILES ACCORDING TO SORT METHOD # -: 1325: * ############################################# */ -: 1326: 298: 1327: if (sort) 298: 1327-block 0 branch 0 taken 296 (fallthrough) branch 1 taken 2 296: 1328: ENTSORT(file_info, n, entrycmp); 296: 1328-block 0 call 0 returned 296 unconditional 1 taken 296 -: 1329: -: 1330: /* ########################################## -: 1331: * # GET INFO TO PRINT COLUMNED OUTPUT # -: 1332: * ########################################## */ -: 1333: -: 1334: int i; 298: 1335: register size_t counter = 0; 298: 1336: size_t columns_n = 1; -: 1337: -: 1338: /* Get the longest file name */ 298: 1339: if (columned || long_view) { 298: 1339-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 297 1: 1339-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 1 297: 1340: i = (int)n; 40356: 1341: while (--i >= 0) { 297: 1341-block 0 unconditional 0 taken 297 40356: 1341-block 1 branch 1 taken 40059 branch 2 taken 297 (fallthrough) 40059: 1342: size_t total_len = 0; 40059*: 1343: file_info[i].eln_n = no_eln ? -1 : DIGINUM(i + 1); 40059: 1343-block 0 branch 0 taken 40059 (fallthrough) branch 1 taken 0 40059: 1343-block 1 branch 2 taken 38106 (fallthrough) branch 3 taken 1953 38106: 1343-block 2 branch 4 taken 32352 (fallthrough) branch 5 taken 5754 32352: 1343-block 3 branch 6 taken 23040 (fallthrough) branch 7 taken 9312 23040: 1343-block 4 branch 8 taken 0 (fallthrough) branch 9 taken 23040 %%%%%: 1343-block 5 branch 10 never executed branch 11 never executed %%%%%: 1343-block 6 branch 12 never executed branch 13 never executed %%%%%: 1343-block 7 branch 14 never executed branch 15 never executed %%%%%: 1343-block 8 branch 16 never executed branch 17 never executed %%%%%: 1343-block 9 branch 18 never executed branch 19 never executed %%%%%: 1343-block 10 unconditional 20 never executed %%%%%: 1343-block 11 unconditional 21 never executed %%%%%: 1343-block 12 unconditional 22 never executed %%%%%: 1343-block 13 unconditional 23 never executed %%%%%: 1343-block 14 unconditional 24 never executed %%%%%: 1343-block 15 unconditional 25 never executed %%%%%: 1343-block 16 unconditional 26 never executed %%%%%: 1343-block 17 unconditional 27 never executed %%%%%: 1343-block 18 unconditional 28 never executed %%%%%: 1343-block 19 unconditional 29 never executed %%%%%: 1343-block 20 unconditional 30 never executed 23040: 1343-block 21 unconditional 31 taken 23040 23040: 1343-block 22 unconditional 32 taken 23040 9312: 1343-block 23 unconditional 33 taken 9312 32352: 1343-block 24 unconditional 34 taken 32352 5754: 1343-block 25 unconditional 35 taken 5754 38106: 1343-block 26 unconditional 36 taken 38106 1953: 1343-block 27 unconditional 37 taken 1953 40059: 1343-block 28 unconditional 38 taken 40059 %%%%%: 1343-block 29 unconditional 39 never executed 40059: 1344: total_len = (size_t)file_info[i].eln_n + 1 + file_info[i].len; -: 1345: 40059: 1346: if (!long_view && classify) { 40059: 1346-block 0 branch 0 taken 39845 (fallthrough) branch 1 taken 214 39845: 1346-block 1 branch 2 taken 39845 (fallthrough) branch 3 taken 0 39845: 1347: if (file_info[i].dir) 39845: 1347-block 0 branch 0 taken 2763 (fallthrough) branch 1 taken 37082 2763: 1348: total_len++; 2763: 1348-block 0 unconditional 0 taken 2763 -: 1349: 39845: 1350: if (file_info[i].filesn > 0 && files_counter) 39845: 1350-block 0 branch 0 taken 2532 (fallthrough) branch 1 taken 37313 2532: 1350-block 1 branch 2 taken 2529 (fallthrough) branch 3 taken 3 2529*: 1351: total_len += DIGINUM(file_info[i].filesn); 2529: 1351-block 0 branch 0 taken 766 (fallthrough) branch 1 taken 1763 766: 1351-block 1 branch 2 taken 123 (fallthrough) branch 3 taken 643 123: 1351-block 2 branch 4 taken 7 (fallthrough) branch 5 taken 116 7: 1351-block 3 branch 6 taken 1 (fallthrough) branch 7 taken 6 1: 1351-block 4 branch 8 taken 1 (fallthrough) branch 9 taken 0 1: 1351-block 5 branch 10 taken 0 (fallthrough) branch 11 taken 1 %%%%%: 1351-block 6 branch 12 never executed branch 13 never executed %%%%%: 1351-block 7 branch 14 never executed branch 15 never executed %%%%%: 1351-block 8 branch 16 never executed branch 17 never executed %%%%%: 1351-block 9 unconditional 18 never executed %%%%%: 1351-block 10 unconditional 19 never executed %%%%%: 1351-block 11 unconditional 20 never executed %%%%%: 1351-block 12 unconditional 21 never executed %%%%%: 1351-block 13 unconditional 22 never executed %%%%%: 1351-block 14 unconditional 23 never executed %%%%%: 1351-block 15 unconditional 24 never executed 1: 1351-block 16 unconditional 25 taken 1 1: 1351-block 17 unconditional 26 taken 1 %%%%%: 1351-block 18 unconditional 27 never executed 1: 1351-block 19 unconditional 28 taken 1 6: 1351-block 20 unconditional 29 taken 6 7: 1351-block 21 unconditional 30 taken 7 116: 1351-block 22 unconditional 31 taken 116 123: 1351-block 23 unconditional 32 taken 123 643: 1351-block 24 unconditional 33 taken 643 766: 1351-block 25 unconditional 34 taken 766 1763: 1351-block 26 unconditional 35 taken 1763 2529: 1351-block 27 unconditional 36 taken 2529 -: 1352: 39845: 1353: if (!file_info[i].dir && !colorize) { 39845: 1353-block 0 branch 0 taken 37082 (fallthrough) branch 1 taken 2763 37082: 1353-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 37082 #####: 1354: switch (file_info[i].type) { %%%%%: 1354-block 0 branch 0 never executed branch 1 never executed branch 2 never executed #####: 1355: case DT_REG: #####: 1356: if (file_info[i].exec) %%%%%: 1356-block 0 branch 0 never executed branch 1 never executed #####: 1357: total_len++; %%%%%: 1357-block 0 unconditional 0 never executed #####: 1358: break; %%%%%: 1358-block 0 unconditional 0 never executed #####: 1359: case DT_LNK: /* fallthrough */ -: 1360: case DT_SOCK: /* fallthrough */ -: 1361: case DT_FIFO: /* fallthrough */ #####: 1362: case DT_UNKNOWN: total_len += 1; break; %%%%%: 1362-block 0 unconditional 0 never executed -: 1363: } -: 1364: } -: 1365: } -: 1366: 40059: 1367: if (total_len > longest) { 40059: 1367-block 0 branch 0 taken 4410 (fallthrough) branch 1 taken 35649 4410: 1368: if (max_files == UNSET) 4410: 1368-block 0 branch 0 taken 948 (fallthrough) branch 1 taken 3462 948: 1369: longest = total_len; 948: 1369-block 0 unconditional 0 taken 948 -: 1370: /* If MAX_FILES is set, get longest file name from -: 1371: * the first MAX_FILES file names */ 3462: 1372: else if (i < max_files) 3462: 1372-block 0 branch 0 taken 3 (fallthrough) branch 1 taken 3459 3: 1373: longest = total_len; 3: 1373-block 0 unconditional 0 taken 3 -: 1374: } -: 1375: } -: 1376: -: 1377:#ifndef _NO_ICONS 297: 1378: if (icons && !long_view && columned) 297: 1378-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 296 1: 1378-block 1 branch 2 taken 1 (fallthrough) branch 3 taken 0 1: 1378-block 2 branch 4 taken 1 (fallthrough) branch 5 taken 0 1: 1379: longest += 3; 1: 1379-block 0 unconditional 0 taken 1 -: 1380:#endif -: 1381: } -: 1382: -: 1383: /* ######################## -: 1384: * # LONG VIEW MODE # -: 1385: * ######################## */ -: 1386: 298: 1387: if (long_view) { 298: 1387-block 0 branch 0 taken 5 (fallthrough) branch 1 taken 293 5: 1388: int space_left = term_cols - MAX_PROP_STR; -: 1389: /* SPACE_LEFT is the max space that should be used to print the -: 1390: * file name (plus space char) */ -: 1391: -: 1392: /* Do not allow SPACE_LEFT to be less than MIN_NAME_TRIM, -: 1393: * especially because the result of the above operation could -: 1394: * be negative */ 5: 1395: if (space_left < min_name_trim) 5: 1395-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 5 #####: 1396: space_left = min_name_trim; %%%%%: 1396-block 0 unconditional 0 never executed -: 1397: 5: 1398: if ((int)longest < space_left) 5: 1398-block 0 branch 0 taken 4 (fallthrough) branch 1 taken 1 4: 1399: space_left = (int)longest; 4: 1399-block 0 unconditional 0 taken 4 -: 1400: 5: 1401: int k = (int)files; 219: 1402: for (i = 0; i < k; i++) { 5: 1402-block 0 unconditional 0 taken 5 214: 1402-block 1 unconditional 1 taken 214 219: 1402-block 2 branch 2 taken 214 branch 3 taken 5 (fallthrough) 214*: 1403: if (max_files != UNSET && i == max_files) 214: 1403-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 214 %%%%%: 1403-block 1 branch 2 never executed branch 3 never executed #####: 1404: break; %%%%%: 1404-block 0 unconditional 0 never executed -: 1405: 214: 1406: if (pager) { 214: 1406-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 214 #####: 1407: if (counter > (size_t)(term_rows - 2)) { %%%%%: 1407-block 0 branch 0 never executed branch 1 never executed #####: 1408: fputs("\x1b[7;97m--Mas--\x1b[0;49m", stdout); %%%%%: 1408-block 0 call 0 never executed -: 1409: #####: 1410: switch (xgetchar()) { call 0 never executed branch 1 never executed branch 2 never executed branch 3 never executed branch 4 never executed branch 5 never executed -: 1411: /* Advance one line at a time */ #####: 1412: case 66: /* fallthrough */ /* Down arrow */ -: 1413: case 10: /* fallthrough */ /* Enter */ -: 1414: case 32: /* Space */ #####: 1415: break; %%%%%: 1415-block 0 unconditional 0 never executed -: 1416: -: 1417: /* Advance one page at a time */ #####: 1418: case 126: /* Page Down */ #####: 1419: counter = 0; #####: 1420: break; %%%%%: 1420-block 0 unconditional 0 never executed -: 1421: #####: 1422: case 63: /* fallthrough */ /* ? */ -: 1423: case 104: { /* h: Print pager help */ #####: 1424: CLEAR; %%%%%: 1424-block 0 call 0 never executed #####: 1425: fputs(_("?, h: help\n" call 0 never executed call 1 never executed -: 1426: "Down arrow, Enter, Space: Advance one line\n" -: 1427: "Page Down: Advance one page\n" -: 1428: "q: Stop pagging\n"), stdout); -: 1429: #####: 1430: int l = (int)term_rows - 5; #####: 1431: while (--l >= 0) unconditional 0 never executed %%%%%: 1431-block 0 branch 1 never executed branch 2 never executed #####: 1432: putchar('\n'); %%%%%: 1432-block 0 call 0 never executed unconditional 1 never executed -: 1433: #####: 1434: fputs("\x1b[7;97m--Mas--\x1b[0;49m", stdout); %%%%%: 1434-block 0 call 0 never executed -: 1435: #####: 1436: i -= (term_rows - 1); #####: 1437: if (i < 0) branch 0 never executed branch 1 never executed #####: 1438: i = 0; %%%%%: 1438-block 0 unconditional 0 never executed -: 1439: #####: 1440: counter = 0; #####: 1441: xgetchar(); %%%%%: 1441-block 0 call 0 never executed #####: 1442: CLEAR; call 0 never executed #####: 1443: } break; unconditional 0 never executed -: 1444: -: 1445: /* Stop paging (and set a flag to reenable the pager -: 1446: * later) */ #####: 1447: case 99: /* fallthrough */ /* 'c' */ -: 1448: case 112: /* fallthrough */ /* 'p' */ -: 1449: case 113: #####: 1450: pager = 0, reset_pager = 1; /* 'q' */ #####: 1451: break; %%%%%: 1451-block 0 unconditional 0 never executed -: 1452: -: 1453: /* If another key is pressed, go back one position. -: 1454: * Otherwise, some file names won't be listed.*/ #####: 1455: default: #####: 1456: i--; #####: 1457: fputs("\r\x1b[K\x1b[3J", stdout); %%%%%: 1457-block 0 call 0 never executed #####: 1458: continue; unconditional 0 never executed -: 1459: } -: 1460: #####: 1461: fputs("\r\x1b[K\x1b[3J", stdout); %%%%%: 1461-block 0 call 0 never executed unconditional 1 never executed -: 1462: } -: 1463: #####: 1464: counter++; %%%%%: 1464-block 0 unconditional 0 never executed -: 1465: } -: 1466: -: 1467: /* Print ELN. The remaining part of the line will be -: 1468: * printed by print_entry_props() */ 214: 1469: if (!no_eln) 214: 1469-block 0 branch 0 taken 214 (fallthrough) branch 1 taken 0 214: 1470: printf("%s%d%s ", el_c, i + 1, df_c); 214: 1470-block 0 call 0 returned 214 unconditional 1 taken 214 -: 1471: 214: 1472: print_entry_props(&file_info[i], (size_t)space_left); 214: 1472-block 0 call 0 returned 214 unconditional 1 taken 214 -: 1473: } -: 1474: 5: 1475: goto END; 5: 1475-block 0 unconditional 0 taken 5 -: 1476: } -: 1477: -: 1478: /* ######################## -: 1479: * # NORMAL VIEW MODE # -: 1480: * ######################## */ -: 1481: 293: 1482: int last_column = 0; -: 1483: -: 1484: /* Get amount of columns needed to print files in CWD */ 293: 1485: if (!columned) { 293: 1485-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 292 1: 1486: columns_n = 1; 1: 1486-block 0 unconditional 0 taken 1 -: 1487: } else { 292: 1488: columns_n = (size_t)term_cols / (longest + 1); /* +1 for the -: 1489: space between file names */ -: 1490: -: 1491: /* If longest is bigger than terminal columns, columns_n will -: 1492: * be negative or zero. To avoid this: */ 292: 1493: if (columns_n < 1) 292: 1493-block 0 branch 0 taken 4 (fallthrough) branch 1 taken 288 4: 1494: columns_n = 1; 4: 1494-block 0 unconditional 0 taken 4 -: 1495: -: 1496: /* If we have only three files, we don't want four columns */ 292: 1497: if (columns_n > (size_t)n) 292: 1497-block 0 branch 0 taken 84 (fallthrough) branch 1 taken 208 84: 1498: columns_n = (size_t)n; 84: 1498-block 0 unconditional 0 taken 84 -: 1499: } -: 1500: 293: 1501: int nn = (int)n; 293: 1502: size_t cur_cols = 0; 36787: 1503: for (i = 0; i < nn; i++) { 293: 1503-block 0 unconditional 0 taken 293 36494: 1503-block 1 unconditional 1 taken 36494 36787: 1503-block 2 branch 2 taken 36495 branch 3 taken 292 (fallthrough) 36495: 1504: if (max_files != UNSET && i == max_files) 36495: 1504-block 0 branch 0 taken 101 (fallthrough) branch 1 taken 36394 101: 1504-block 1 branch 2 taken 1 (fallthrough) branch 3 taken 100 1: 1505: break; 1: 1505-block 0 unconditional 0 taken 1 -: 1506: -: 1507: /* ###################### -: 1508: * # A SIMPLE PAGER # -: 1509: * ###################### */ -: 1510: -: 1511: /* A basic pager for directories containing large amount of -: 1512: * files. What's missing? It only goes downwards. To go -: 1513: * backwards, use the terminal scrollback function */ 36494: 1514: if (pager) { 36494: 1514-block 0 branch 0 taken 312 (fallthrough) branch 1 taken 36182 -: 1515: /* Run the pager only once all columns and rows fitting in -: 1516: * the screen are filled with the corresponding file names */ 312: 1517: if (last_column && counter > columns_n * ((size_t)term_rows - 2)) { 312: 1517-block 0 branch 0 taken 309 (fallthrough) branch 1 taken 3 309: 1517-block 1 branch 2 taken 120 (fallthrough) branch 3 taken 189 120: 1518: fputs("\x1b[7;97m--Mas--\x1b[0;49m", stdout); 120: 1518-block 0 call 0 returned 120 -: 1519: 120: 1520: switch (xgetchar()) { call 0 returned 120 branch 1 taken 32 branch 2 taken 5 branch 3 taken 1 branch 4 taken 3 branch 5 taken 79 -: 1521: /* Advance one line at a time */ 32: 1522: case 66: /* fallthrough */ /* Down arrow */ -: 1523: case 10: /* fallthrough */ /* Enter */ -: 1524: case 32: /* Space */ 32: 1525: break; 32: 1525-block 0 unconditional 0 taken 32 -: 1526: -: 1527: /* Advance one page at a time */ 5: 1528: case 126: /* Page Down */ 5: 1529: counter = 0; break; 5: 1529-block 0 unconditional 0 taken 5 -: 1530: 1: 1531: case 63: /* fallthrough */ /* ? */ -: 1532: case 104: { /* h: Print pager help */ 1: 1533: CLEAR; 1: 1533-block 0 call 0 returned 1 -: 1534: 1: 1535: fputs(_("?, h: help\n" call 0 returned 1 call 1 returned 1 -: 1536: "Down arrow, Enter, Space: Advance one line\n" -: 1537: "Page Down: Advance one page\n" -: 1538: "q: Stop pagging\n"), stdout); -: 1539: 1: 1540: int l = (int)term_rows - 5; 19: 1541: while (--l >= 0) unconditional 0 taken 1 19: 1541-block 0 branch 1 taken 18 branch 2 taken 1 (fallthrough) 18: 1542: putchar('\n'); 18: 1542-block 0 call 0 returned 18 unconditional 1 taken 18 -: 1543: 1: 1544: fputs("\x1b[7;97m--Mas--\x1b[0;49m", stdout); 1: 1544-block 0 call 0 returned 1 -: 1545: 1: 1546: i -= ((term_rows * (int)columns_n) - 1); -: 1547: 1: 1548: if (i < 0) branch 0 taken 0 (fallthrough) branch 1 taken 1 #####: 1549: i = 0; %%%%%: 1549-block 0 unconditional 0 never executed -: 1550: 1: 1551: counter = 0; 1: 1552: xgetchar(); 1: 1552-block 0 call 0 returned 1 1: 1553: CLEAR; call 0 returned 1 1: 1554: } break; unconditional 0 taken 1 -: 1555: -: 1556: /* Stop paging (and set a flag to reenable the pager -: 1557: * later) */ 3: 1558: case 99: /* fallthrough */ /* 'c' */ -: 1559: case 112: /* fallthrough */ /* 'p' */ -: 1560: case 113: 3: 1561: pager = 0, reset_pager = 1; /* 'q' */ 3: 1562: break; 3: 1562-block 0 unconditional 0 taken 3 -: 1563: -: 1564: /* If another key is pressed, go back one position. -: 1565: * Otherwise, some file names won't be listed.*/ 79: 1566: default: 79: 1567: i--; 79: 1568: fputs("\r\x1b[K\x1b[3J", stdout); 79: 1568-block 0 call 0 returned 79 79: 1569: continue; unconditional 0 taken 79 -: 1570: } -: 1571: 41: 1572: fputs("\r\x1b[K\x1b[3J", stdout); 41: 1572-block 0 call 0 returned 41 unconditional 1 taken 41 -: 1573: } -: 1574: 233: 1575: counter++; 233: 1575-block 0 unconditional 0 taken 233 -: 1576: } -: 1577: -: 1578: /* Determine if current entry is in the last column, in which -: 1579: * case a new line char will be appended */ 36415: 1580: if (++cur_cols == columns_n) { 36415: 1580-block 0 branch 0 taken 32210 (fallthrough) branch 1 taken 4205 32210: 1581: cur_cols = 0; 32210: 1582: last_column = 1; 32210: 1582-block 0 unconditional 0 taken 32210 -: 1583: } else { 4205: 1584: last_column = 0; 4205: 1584-block 0 unconditional 0 taken 4205 -: 1585: } -: 1586: 36415*: 1587: file_info[i].eln_n = no_eln ? -1 : DIGINUM(i + 1); 36415: 1587-block 0 branch 0 taken 36415 (fallthrough) branch 1 taken 0 36415: 1587-block 1 branch 2 taken 34479 (fallthrough) branch 3 taken 1936 34479: 1587-block 2 branch 4 taken 28893 (fallthrough) branch 5 taken 5586 28893: 1587-block 3 branch 6 taken 20480 (fallthrough) branch 7 taken 8413 20480: 1587-block 4 branch 8 taken 0 (fallthrough) branch 9 taken 20480 %%%%%: 1587-block 5 branch 10 never executed branch 11 never executed %%%%%: 1587-block 6 branch 12 never executed branch 13 never executed %%%%%: 1587-block 7 branch 14 never executed branch 15 never executed %%%%%: 1587-block 8 branch 16 never executed branch 17 never executed %%%%%: 1587-block 9 branch 18 never executed branch 19 never executed %%%%%: 1587-block 10 unconditional 20 never executed %%%%%: 1587-block 11 unconditional 21 never executed %%%%%: 1587-block 12 unconditional 22 never executed %%%%%: 1587-block 13 unconditional 23 never executed %%%%%: 1587-block 14 unconditional 24 never executed %%%%%: 1587-block 15 unconditional 25 never executed %%%%%: 1587-block 16 unconditional 26 never executed %%%%%: 1587-block 17 unconditional 27 never executed %%%%%: 1587-block 18 unconditional 28 never executed %%%%%: 1587-block 19 unconditional 29 never executed %%%%%: 1587-block 20 unconditional 30 never executed 20480: 1587-block 21 unconditional 31 taken 20480 20480: 1587-block 22 unconditional 32 taken 20480 8413: 1587-block 23 unconditional 33 taken 8413 28893: 1587-block 24 unconditional 34 taken 28893 5586: 1587-block 25 unconditional 35 taken 5586 34479: 1587-block 26 unconditional 36 taken 34479 1936: 1587-block 27 unconditional 37 taken 1936 36415: 1587-block 28 unconditional 38 taken 36415 %%%%%: 1587-block 29 unconditional 39 never executed 36415: 1588: int ind_char = 1; 36415: 1589: if (!classify) 36415: 1589-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 36415 #####: 1590: ind_char = 0; %%%%%: 1590-block 0 unconditional 0 never executed -: 1591: -: 1592: /* ################################# -: 1593: * # PRINT THE CURRENT ENTRY # -: 1594: * ################################# */ -: 1595: 36415: 1596: if (colorize) { 36415: 1596-block 0 branch 0 taken 36415 (fallthrough) branch 1 taken 0 36415: 1597: ind_char = 0; -: 1598:#ifndef _NO_ICONS 36415: 1599: if (icons) { 36415: 1599-block 0 branch 0 taken 7 (fallthrough) branch 1 taken 36408 7: 1600: if (no_eln) { 7: 1600-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 7 #####: 1601: xprintf("%s%s %s%s%s", file_info[i].icon_color, #####: 1602: file_info[i].icon, file_info[i].color, #####: 1603: file_info[i].name, df_c); %%%%%: 1603-block 0 call 0 never executed unconditional 1 never executed -: 1604: } else { 7: 1605: xprintf("%s%d%s %s%s %s%s%s", el_c, i + 1, df_c, 7: 1606: file_info[i].icon_color, file_info[i].icon, 7: 1607: file_info[i].color, file_info[i].name, df_c); 7: 1607-block 0 call 0 returned 7 unconditional 1 taken 7 -: 1608: } -: 1609: } else { 36408: 1610: if (no_eln) { 36408: 1610-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 36408 #####: 1611: xprintf("%s%s%s", file_info[i].color, #####: 1612: file_info[i].name, df_c); %%%%%: 1612-block 0 call 0 never executed unconditional 1 never executed -: 1613: } else { 36408: 1614: xprintf("%s%d%s %s%s%s", el_c, i + 1, df_c, 36408: 1615: file_info[i].color, file_info[i].name, df_c); 36408: 1615-block 0 call 0 returned 36408 unconditional 1 taken 36408 -: 1616: } -: 1617: } -: 1618:#else -: 1619: if (no_eln) { -: 1620: xprintf("%s%s%s", file_info[i].color, file_info[i].name, df_c); -: 1621: } else { -: 1622: xprintf("%s%d%s %s%s%s", el_c, i + 1, df_c, -: 1623: file_info[i].color, file_info[i].name, df_c); -: 1624: } -: 1625:#endif /* !_NO_ICONS */ -: 1626: 36415: 1627: if (classify) { 36415: 1627-block 0 branch 0 taken 36415 (fallthrough) branch 1 taken 0 -: 1628: /* Append directory indicator and files counter */ 36415: 1629: switch (file_info[i].type) { 36415: 1629-block 0 branch 0 taken 2712 branch 1 taken 3615 branch 2 taken 30088 2712: 1630: case DT_DIR: 2712: 1631: putchar('/'); 2712: 1631-block 0 call 0 returned 2712 2712: 1632: if (file_info[i].filesn > 0 && files_counter) branch 0 taken 2479 (fallthrough) branch 1 taken 233 2479: 1632-block 0 branch 2 taken 2476 (fallthrough) branch 3 taken 3 2476: 1633: fputs(xitoa(file_info[i].filesn), stdout); 2476: 1633-block 0 call 0 returned 2476 call 1 returned 2476 unconditional 2 taken 2476 2712: 1634: break; 2712: 1634-block 0 unconditional 0 taken 2712 -: 1635: 3615: 1636: case DT_LNK: 3615: 1637: if (file_info[i].dir) 3615: 1637-block 0 branch 0 taken 59 (fallthrough) branch 1 taken 3556 59: 1638: putchar('/'); 59: 1638-block 0 call 0 returned 59 unconditional 1 taken 59 3615: 1639: if (file_info[i].filesn > 0 && files_counter) 3615: 1639-block 0 branch 0 taken 59 (fallthrough) branch 1 taken 3556 59: 1639-block 1 branch 2 taken 59 (fallthrough) branch 3 taken 0 59: 1640: fputs(xitoa(file_info[i].filesn), stdout); 59: 1640-block 0 call 0 returned 59 call 1 returned 59 unconditional 2 taken 59 3615: 1641: break; 3615: 1641-block 0 unconditional 0 taken 3615 -: 1642: } -: 1643: } -: 1644: } -: 1645: -: 1646: /* No color */ -: 1647: else { -: 1648:#ifndef _NO_ICONS #####: 1649: if (icons) { %%%%%: 1649-block 0 branch 0 never executed branch 1 never executed #####: 1650: if (no_eln) %%%%%: 1650-block 0 branch 0 never executed branch 1 never executed #####: 1651: xprintf("%s %s", file_info[i].icon, file_info[i].name); %%%%%: 1651-block 0 call 0 never executed unconditional 1 never executed -: 1652: else #####: 1653: xprintf("%s%d%s %s %s", el_c, i + 1, df_c, #####: 1654: file_info[i].icon, file_info[i].name); %%%%%: 1654-block 0 call 0 never executed unconditional 1 never executed -: 1655: } else { #####: 1656: if (no_eln) { %%%%%: 1656-block 0 branch 0 never executed branch 1 never executed #####: 1657: fputs(file_info[i].name, stdout); %%%%%: 1657-block 0 call 0 never executed unconditional 1 never executed -: 1658: } else { #####: 1659: xprintf("%s%d%s %s", el_c, i + 1, df_c, file_info[i].name); %%%%%: 1659-block 0 call 0 never executed unconditional 1 never executed -: 1660: /* fputs(el_c, stdout); -: 1661: fputs(xitoa(i + 1), stdout); -: 1662: fputs(df_c, stdout); -: 1663: putchar(' '); -: 1664: fputs(file_info[i].name, stdout); */ -: 1665: } -: 1666: } -: 1667:#else -: 1668: if (no_eln) { -: 1669: fputs(file_info[i].name, stdout); -: 1670: } else { -: 1671: xprintf("%s%d%s %s", el_c, i + 1, df_c, file_info[i].name); -: 1672: } -: 1673:#endif /* !_NO_ICONS */ -: 1674: #####: 1675: if (classify) { %%%%%: 1675-block 0 branch 0 never executed branch 1 never executed -: 1676: /* Append file type indicator */ #####: 1677: switch (file_info[i].type) { %%%%%: 1677-block 0 branch 0 never executed branch 1 never executed branch 2 never executed branch 3 never executed branch 4 never executed branch 5 never executed branch 6 never executed #####: 1678: case DT_DIR: #####: 1679: ind_char = 0; #####: 1680: putchar('/'); %%%%%: 1680-block 0 call 0 never executed #####: 1681: if (file_info[i].filesn > 0 && files_counter) branch 0 never executed branch 1 never executed %%%%%: 1681-block 0 branch 2 never executed branch 3 never executed #####: 1682: fputs(xitoa(file_info[i].filesn), stdout); %%%%%: 1682-block 0 call 0 never executed call 1 never executed unconditional 2 never executed #####: 1683: break; %%%%%: 1683-block 0 unconditional 0 never executed -: 1684: #####: 1685: case DT_LNK: #####: 1686: if (file_info[i].dir) { %%%%%: 1686-block 0 branch 0 never executed branch 1 never executed #####: 1687: ind_char = 0; #####: 1688: putchar('/'); %%%%%: 1688-block 0 call 0 never executed #####: 1689: if (file_info[i].filesn > 0 && files_counter) branch 0 never executed branch 1 never executed %%%%%: 1689-block 0 branch 2 never executed branch 3 never executed #####: 1690: fputs(xitoa(file_info[i].filesn), stdout); %%%%%: 1690-block 0 call 0 never executed call 1 never executed unconditional 2 never executed -: 1691: } else { #####: 1692: putchar('@'); %%%%%: 1692-block 0 call 0 never executed unconditional 1 never executed -: 1693: } #####: 1694: break; %%%%%: 1694-block 0 unconditional 0 never executed -: 1695: #####: 1696: case DT_REG: #####: 1697: if (file_info[i].exec) %%%%%: 1697-block 0 branch 0 never executed branch 1 never executed #####: 1698: putchar('*'); %%%%%: 1698-block 0 call 0 never executed unconditional 1 never executed -: 1699: else #####: 1700: ind_char = 0; %%%%%: 1700-block 0 unconditional 0 never executed #####: 1701: break; %%%%%: 1701-block 0 unconditional 0 never executed -: 1702: #####: 1703: case DT_FIFO: putchar('|'); break; %%%%%: 1703-block 0 call 0 never executed unconditional 1 never executed #####: 1704: case DT_SOCK: putchar('='); break; %%%%%: 1704-block 0 call 0 never executed unconditional 1 never executed #####: 1705: case DT_UNKNOWN: putchar('?'); break; %%%%%: 1705-block 0 call 0 never executed unconditional 1 never executed #####: 1706: default: ind_char = 0; %%%%%: 1706-block 0 unconditional 0 never executed -: 1707: } -: 1708: } -: 1709: } -: 1710: 36415: 1711: if (!last_column) { 36415: 1711-block 0 branch 0 taken 4205 (fallthrough) branch 1 taken 32210 -: 1712: /* Pad the current file name to equate the longest file name length */ -: 1713:#ifndef _NO_ICONS 4205: 1714: int cur_len = (int)file_info[i].eln_n + 1 + (icons ? 3 : 0) + (int)file_info[i].len + (ind_char ? 1 : 0); 4205: 1714-block 0 branch 0 taken 5 (fallthrough) branch 1 taken 4200 5: 1714-block 1 unconditional 2 taken 5 4200: 1714-block 2 unconditional 3 taken 4200 -: 1715:#else -: 1716: int cur_len = (int)file_info[i].eln_n + 1 + (int)file_info[i].len + (ind_char ? 1 : 0); -: 1717:#endif 4205: 1718: if (file_info[i].dir && classify) { 4205: 1718-block 0 branch 0 taken 1853 (fallthrough) branch 1 taken 2352 1853: 1718-block 1 branch 2 taken 1853 (fallthrough) branch 3 taken 0 1853: 1719: cur_len++; 1853: 1720: if (file_info[i].filesn > 0 && files_counter && file_info[i].ruser) 1853: 1720-block 0 branch 0 taken 1688 (fallthrough) branch 1 taken 165 1688: 1720-block 1 branch 2 taken 1685 (fallthrough) branch 3 taken 3 1685: 1720-block 2 branch 4 taken 1685 (fallthrough) branch 5 taken 0 1685*: 1721: cur_len += DIGINUM((int)file_info[i].filesn); 1685: 1721-block 0 branch 0 taken 530 (fallthrough) branch 1 taken 1155 530: 1721-block 1 branch 2 taken 32 (fallthrough) branch 3 taken 498 32: 1721-block 2 branch 4 taken 4 (fallthrough) branch 5 taken 28 4: 1721-block 3 branch 6 taken 1 (fallthrough) branch 7 taken 3 1: 1721-block 4 branch 8 taken 1 (fallthrough) branch 9 taken 0 1: 1721-block 5 branch 10 taken 0 (fallthrough) branch 11 taken 1 %%%%%: 1721-block 6 branch 12 never executed branch 13 never executed %%%%%: 1721-block 7 branch 14 never executed branch 15 never executed %%%%%: 1721-block 8 branch 16 never executed branch 17 never executed %%%%%: 1721-block 9 unconditional 18 never executed %%%%%: 1721-block 10 unconditional 19 never executed %%%%%: 1721-block 11 unconditional 20 never executed %%%%%: 1721-block 12 unconditional 21 never executed %%%%%: 1721-block 13 unconditional 22 never executed %%%%%: 1721-block 14 unconditional 23 never executed %%%%%: 1721-block 15 unconditional 24 never executed 1: 1721-block 16 unconditional 25 taken 1 1: 1721-block 17 unconditional 26 taken 1 %%%%%: 1721-block 18 unconditional 27 never executed 1: 1721-block 19 unconditional 28 taken 1 3: 1721-block 20 unconditional 29 taken 3 4: 1721-block 21 unconditional 30 taken 4 28: 1721-block 22 unconditional 31 taken 28 32: 1721-block 23 unconditional 32 taken 32 498: 1721-block 24 unconditional 33 taken 498 530: 1721-block 25 unconditional 34 taken 530 1155: 1721-block 26 unconditional 35 taken 1155 1685: 1721-block 27 unconditional 36 taken 1685 -: 1722: } -: 1723: 4205: 1724: int diff = (int)longest - cur_len; -: 1725: /* Move the cursor %d columns to the right */ 4205: 1726: xprintf("\x1b[%dC", diff + 1); 4205: 1726-block 0 call 0 returned 4205 unconditional 1 taken 4205 -: 1727:/* register int j; -: 1728: for (j = diff + 1; j--;) -: 1729: putchar(' '); */ -: 1730: } else { 32210: 1731: putchar('\n'); 32210: 1731-block 0 call 0 returned 32210 unconditional 1 taken 32210 -: 1732: } -: 1733: } -: 1734: 293: 1735: if (!last_column) 293: 1735-block 0 branch 0 taken 169 (fallthrough) branch 1 taken 124 124: 1736: putchar('\n'); 124: 1736-block 0 call 0 returned 124 unconditional 1 taken 124 -: 1737: -: 1738: /* ######################### -: 1739: * # POST LISTING STUFF # -: 1740: * ######################### */ -: 1741: 169: 1742:END: 169: 1742-block 0 unconditional 0 taken 169 -: 1743: /* Unhide the cursor */ 302: 1744: fputs("\x1b[?25h", stdout); 302: 1744-block 0 call 0 returned 302 -: 1745: 302: 1746: if (close_dir && closedir(dir) == -1) branch 0 taken 302 (fallthrough) branch 1 taken 0 302: 1746-block 0 call 2 returned 302 branch 3 taken 0 (fallthrough) branch 4 taken 302 #####: 1747: return EXIT_FAILURE; %%%%%: 1747-block 0 unconditional 0 never executed -: 1748: 302: 1749: if (xargs.list_and_quit == 1) 302: 1749-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 302 #####: 1750: exit(exit_code); %%%%%: 1750-block 0 call 0 never executed -: 1751: 302: 1752: if (reset_pager) 302: 1752-block 0 branch 0 taken 3 (fallthrough) branch 1 taken 299 3: 1753: pager = 1; 3: 1753-block 0 unconditional 0 taken 3 -: 1754: 302: 1755: if (max_files != UNSET && (int)files > max_files) 302: 1755-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 301 1: 1755-block 1 branch 2 taken 1 (fallthrough) branch 3 taken 0 1: 1756: printf("%d/%zu\n", max_files, files); 1: 1756-block 0 call 0 returned 1 unconditional 1 taken 1 -: 1757: -: 1758: /* Print a dividing line between the files list and the -: 1759: * prompt */ 302: 1760: print_div_line(); 302: 1760-block 0 call 0 returned 302 -: 1761: 302: 1762: if (dirhist_map) { branch 0 taken 0 (fallthrough) branch 1 taken 302 -: 1763: /* Print current, previous, and next entries */ #####: 1764: print_dirhist_map(); %%%%%: 1764-block 0 call 0 never executed #####: 1765: print_div_line(); call 0 never executed unconditional 1 never executed -: 1766: } -: 1767: 302: 1768: if (disk_usage) 302: 1768-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 302 #####: 1769: print_disk_usage(); %%%%%: 1769-block 0 call 0 never executed unconditional 1 never executed -: 1770: 302: 1771: if (sort_switch) 302: 1771-block 0 branch 0 taken 22 (fallthrough) branch 1 taken 280 22: 1772: print_sort_method(); 22: 1772-block 0 call 0 returned 22 unconditional 1 taken 22 -: 1773: 302*: 1774: if (print_selfiles && sel_n > 0) 302: 1774-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 302 %%%%%: 1774-block 1 branch 2 never executed branch 3 never executed #####: 1775: _print_selfiles(term_rows); %%%%%: 1775-block 0 call 0 never executed unconditional 1 never executed -: 1776: -: 1777:#ifdef _LIST_SPEED -: 1778: clock_t end = clock(); -: 1779: printf("list_dir time: %f\n", (double)(end-start)/CLOCKS_PER_SEC); -: 1780:#endif 302: 1781: return EXIT_SUCCESS; 302: 1781-block 0 unconditional 0 taken 302 -: 1782:} -: 1783: -: 1784:void function free_dirlist called 305 returned 100% blocks executed 100% 305: 1785:free_dirlist(void) -: 1786:{ 305: 1787: if (!file_info || !files) 305: 1787-block 0 branch 0 taken 305 (fallthrough) branch 1 taken 0 305: 1787-block 1 branch 2 taken 4 (fallthrough) branch 3 taken 301 4: 1788: return; 4: 1788-block 0 unconditional 0 taken 4 -: 1789: 301: 1790: int i = (int)files; 40382: 1791: while (--i >= 0) { 301: 1791-block 0 unconditional 0 taken 301 40382: 1791-block 1 branch 1 taken 40081 branch 2 taken 301 (fallthrough) 40081: 1792: free(file_info[i].name); 40081: 1793: if (file_info[i].ext_color) 40081: 1793-block 0 branch 0 taken 486 (fallthrough) branch 1 taken 39595 486: 1794: free(file_info[i].ext_color); 486: 1794-block 0 unconditional 0 taken 486 -: 1795: } -: 1796: 301: 1797: free(file_info); 301: 1798: file_info = (struct fileinfo *)NULL; 301: 1798-block 0 unconditional 0 taken 301 -: 1799:} clifm-1.26.3/misc/codecov/main.c.gcov000066400000000000000000001136231506632037700173160ustar00rootroot00000000000000 -: 0:Source:main.c -: 1: -: 2: /* ######################################## -: 3: * # CliFM # -: 4: * # The KISS/non-curses file manager # -: 5: * ######################################## */ -: 6: -: 7:/* GPL2+ License -: 8: * Copyright (C) 2016-2021, L. Abramovich -: 9: * All rights reserved. -: 10: -: 11: * This program is free software; you can redistribute it and/or modify -: 12: * it under the terms of the GNU General Public License as published by -: 13: * the Free Software Foundation; either version 2 of the License, or -: 14: * (at your option) any later version. -: 15: * -: 16: * This program is distributed in the hope that it will be useful, -: 17: * but WITHOUT ANY WARRANTY; without even the implied warranty of -: 18: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -: 19: * GNU General Public License for more details. -: 20: * -: 21: * You should have received a copy of the GNU General Public License -: 22: * along with this program; if not, write to the Free Software -: 23: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, -: 24: * MA 02110-1301, USA. -: 25: * -: 26: */ -: 27: -: 28:#include "helpers.h" -: 29: -: 30:#include -: 31:#include -: 32:#include -: 33:#include -: 34:#include -: 35:#include -: 36:#include -: 37:#include -: 38:#include -: 39:#include -: 40:#include -: 41: -: 42:#include "aux.h" -: 43:#include "checks.h" -: 44:#include "colors.h" -: 45:#include "config.h" -: 46:#include "exec.h" -: 47:#include "history.h" -: 48:#include "init.h" -: 49:#include "jump.h" -: 50:#include "keybinds.h" -: 51:#include "listing.h" -: 52:#include "misc.h" -: 53:#include "navigation.h" -: 54:#include "profiles.h" -: 55:#include "prompt.h" -: 56:#include "readline.h" -: 57:#include "strings.h" -: 58:#include "remotes.h" -: 59: -: 60:/* Globals */ -: 61: -: 62: -: 63: -: 64:struct usrvar_t *usr_var = (struct usrvar_t *)NULL; -: 65:struct actions_t *usr_actions = (struct actions_t *)NULL; -: 66:struct ws_t *ws = (struct ws_t *)NULL; -: 67:struct kbinds_t *kbinds = (struct kbinds_t *)NULL; -: 68:struct jump_t *jump_db = (struct jump_t *)NULL; -: 69:struct bookmarks_t *bookmarks = (struct bookmarks_t *)NULL; -: 70:struct fileinfo *file_info = (struct fileinfo *)NULL; -: 71:struct remote_t *remotes = (struct remote_t *)NULL; -: 72:#ifndef _NO_SUGGESTIONS -: 73:struct suggestions_t suggestion; -: 74:#endif -: 75:/* pmsg holds the current program message type */ -: 76:enum prog_msg pmsg = NOMSG; -: 77:struct param xargs; -: 78:unsigned short term_cols; -: 79: -: 80:int curcol = 0, -: 81: currow = 0, -: 82: flags; -: 83: -: 84:struct termios -: 85: orig_termios, -: 86: shell_tmodes; -: 87: -: 88:off_t total_sel_size = 0; -: 89:pid_t own_pid = 0; -: 90: -: 91:unsigned short -: 92: term_cols = 0, -: 93: term_rows = 0; -: 94: -: 95:regex_t regex_exp; -: 96:size_t *ext_colors_len = (size_t *)NULL; -: 97: -: 98:int -: 99: auto_open = UNSET, -: 100: autocd = UNSET, -: 101: autojump = UNSET, -: 102: bg_proc = 0, -: 103: case_sens_dirjump = UNSET, -: 104: case_sens_path_comp = UNSET, -: 105: case_sensitive = UNSET, -: 106: cd_lists_on_the_fly = UNSET, -: 107: cd_on_quit = UNSET, -: 108: check_cap = UNSET, -: 109: check_ext = UNSET, -: 110: classify = UNSET, -: 111: clear_screen = UNSET, -: 112: colorize = UNSET, -: 113: columned = UNSET, -: 114: config_ok = 1, -: 115: copy_n_rename = 0, -: 116: cp_cmd = UNSET, -: 117: cur_ws = UNSET, -: 118: dequoted = 0, -: 119: dirhist_map = UNSET, -: 120: disk_usage = UNSET, -: 121: expand_bookmarks = UNSET, -: 122: ext_cmd_ok = UNSET, -: 123: files_counter = UNSET, -: 124: filter_rev = 0, -: 125: follow_symlinks = UNSET, -: 126: highlight = UNSET, -: 127: home_ok = 1, -: 128:#ifndef _NO_ICONS -: 129: icons = 0, -: 130:#endif -: 131: internal_cmd = 0, -: 132: is_sel = 0, -: 133: kb_shortcut = 0, -: 134: kbind_busy = 0, -: 135: light_mode = UNSET, -: 136: list_folders_first = UNSET, -: 137: logs_enabled = UNSET, -: 138: long_view = UNSET, -: 139: mime_match = 0, -: 140: min_name_trim = UNSET, -: 141: mv_cmd = UNSET, -: 142: no_eln = UNSET, -: 143: no_log = 0, -: 144: only_dirs = UNSET, -: 145: pager = UNSET, -: 146: tips = UNSET, -: 147: print_msg = 0, -: 148: print_selfiles = UNSET, -: 149: prompt_style = UNSET, -: 150: recur_perm_error_flag = 0, -: 151: restore_last_path = UNSET, -: 152: sel_is_last = 0, -: 153: selfile_ok = 1, -: 154: share_selbox = UNSET, -: 155: shell_terminal = 0, -: 156: show_hidden = UNSET, -: 157: sort = UNSET, -: 158: sort_reverse = 0, -: 159: sort_switch = 0, -: 160: splash_screen = UNSET, -: 161: suggestions = UNSET, -: 162: suggest_filetype_color = UNSET, -: 163: switch_cscheme = 0, -: 164:#ifndef _NO_TRASH -: 165: tr_as_rm = UNSET, -: 166: trash_ok = 1, -: 167:#endif -: 168: unicode = UNSET, -: 169: welcome_message = UNSET; -: 170: -: 171:int -: 172: argc_bk = 0, -: 173: dirhist_cur_index = 0, -: 174: exit_code = 0, -: 175: dirhist_total_index = 0, -: 176: jump_total_rank = 0, -: 177: max_dirhist = UNSET, -: 178: max_files = UNSET, -: 179: max_hist = UNSET, -: 180: min_jump_rank = UNSET, -: 181: max_jump_total_rank = UNSET, -: 182: max_log = UNSET, -: 183: max_path = UNSET, -: 184: max_printselfiles = UNSET, -: 185: shell_is_interactive = 0, -: 186: trash_n = 0, -: 187: *eln_as_file = (int *)0; -: 188: -: 189:size_t -: 190: actions_n = 0, -: 191: aliases_n = 0, -: 192: args_n = 0, -: 193: bm_n = 0, -: 194: cdpath_n = 0, -: 195: cschemes_n = 0, -: 196: current_hist_n = 0, -: 197: eln_as_file_n = 0, -: 198: ext_colors_n = 0, -: 199: files = 0, -: 200: jump_n = 0, -: 201: kbinds_n = 0, -: 202: longest = 0, -: 203: msgs_n = 0, -: 204: path_n = 0, -: 205: path_progsn = 0, -: 206: prompt_cmds_n = 0, -: 207: remotes_n = 0, -: 208: sel_n = 0, -: 209: user_home_len = 0, -: 210: usrvar_n = 0; -: 211: -: 212:char -: 213: div_line_char[NAME_MAX], -: 214: hostname[HOST_NAME_MAX], -: 215: -: 216: *actions_file = (char *)NULL, -: 217: *alt_bm_file = (char *)NULL, -: 218: *alt_config_dir = (char *)NULL, -: 219: *alt_config_file = (char *)NULL, -: 220: *alt_kbinds_file = (char *)NULL, -: 221: *alt_profile = (char *)NULL, -: 222: *bm_file = (char *)NULL, -: 223: *colors_dir = (char *)NULL, -: 224: *config_dir = (char *)NULL, -: 225: *config_dir_gral = (char *)NULL, -: 226: *config_file = (char *)NULL, -: 227: *cur_color = (char *)NULL, -: 228: *data_dir = (char *)NULL, -: 229: *cur_cscheme = (char *)NULL, -: 230: *dirhist_file = (char *)NULL, -: 231: *encoded_prompt = (char *)NULL, -: 232: *file_cmd_path = (char *)NULL, -: 233: *filter = (char *)NULL, -: 234: *hist_file = (char *)NULL, -: 235: *jump_suggestion = (char *)NULL, -: 236: *kbinds_file = (char *)NULL, -: 237: *last_cmd = (char *)NULL, -: 238: *log_file = (char *)NULL, -: 239: *ls_colors_bk = (char *)NULL, -: 240: *mime_file = (char *)NULL, -: 241: *msg_log_file = (char *)NULL, -: 242: *opener = (char *)NULL, -: 243: *pinned_dir = (char *)NULL, -: 244: *plugins_dir = (char *)NULL, -: 245: *profile_file = (char *)NULL, -: 246: *qc = (char *)NULL, -: 247: *remotes_file = (char *)NULL, -: 248: *sel_file = (char *)NULL, -: 249: *stdin_tmp_dir = (char *)NULL, -: 250:#ifndef _NO_SUGGESTIONS -: 251: *suggestion_buf = (char *)NULL, -: 252: *suggestion_strategy = (char *)NULL, -: 253:#endif -: 254: *sys_shell = (char *)NULL, -: 255: *term = (char *)NULL, -: 256: *tmp_dir = (char *)NULL, -: 257:#ifndef _NO_TRASH -: 258: *trash_dir = (char *)NULL, -: 259: *trash_files_dir = (char *)NULL, -: 260: *trash_info_dir = (char *)NULL, -: 261:#endif -: 262: *usr_cscheme = (char *)NULL, -: 263: *user_home = (char *)NULL, -: 264: -: 265: **aliases = (char **)NULL, -: 266: **argv_bk = (char **)NULL, -: 267: **bin_commands = (char **)NULL, -: 268: **bookmark_names = (char **)NULL, -: 269: **cdpaths = (char **)NULL, -: 270: **color_schemes = (char **)NULL, -: 271: **ext_colors = (char **)NULL, -: 272: **history = (char **)NULL, -: 273: **messages = (char **)NULL, -: 274: **old_pwd = (char **)NULL, -: 275: **paths = (char **)NULL, -: 276: **profile_names = (char **)NULL, -: 277: **prompt_cmds = (char **)NULL, -: 278: **sel_elements = (char **)NULL; -: 279: -: 280:/* This is not a comprehensive list of commands. It only lists -: 281: * commands long version for TAB completion */ -: 282:const char *internal_cmds[] = { -: 283: "actions", -: 284: "alias", -: 285: "auto-open", -: 286: "autocd", -: 287: "back", -: 288: "bookmarks", -: 289: "colors", -: 290: "colorschemes", -: 291: "columns", -: 292: "commands", -: 293: "desel", -: 294: "dup", -: 295: "edit", -: 296: "exit", -: 297: "export", -: 298: "filter", -: 299: "folders-first", -: 300: "forth", -: 301: "help", -: 302: "hidden", -: 303: "history", -: 304: "icons", -: 305: "jump", -: 306: "keybinds", -: 307: "log", -: 308: "messages", -: 309: "mime", -: 310: "mountpoints", -: 311: "move", -: 312: "new", -: 313: "open", -: 314: "opener", -: 315: "pager", -: 316: "paste", -: 317: "path", -: 318: "pin", -: 319: "profile", -: 320: "prop", -: 321: "quit", -: 322: "refresh", -: 323: "reload", -: 324: "sel", -: 325: "selbox", -: 326: "shell", -: 327: "sort", -: 328: "splash", -: 329: "tips", -: 330: "trash", -: 331: "undel", -: 332: "unicode", -: 333: "unpin", -: 334: "untrash", -: 335: "version", -: 336: NULL}; -: 337: -: 338:/* Just a list of internal commands and fixed parameters for the -: 339: * auto-suggestions system */ -: 340:const char *param_str[] = { -: 341: "actions edit", -: 342: "autocd on", -: 343: "acd on", -: 344: "autocd off", -: 345: "acd off", -: 346: "autocd status", -: 347: "acd status", -: 348: "alias import", -: 349: "ao on", -: 350: "auto-open on", -: 351: "ao off", -: 352: "auto-open off", -: 353: "ao status", -: 354: "auto-open status", -: 355: "b hist", -: 356: "b clear", -: 357: "back hist", -: 358: "back clear", -: 359: "bm add", -: 360: "bm del", -: 361: "bm edit", -: 362: "bookmarks add", -: 363: "bookmarks del", -: 364: "bookmarks edit", -: 365: "cs edit", -: 366: "colorscheme edit", -: 367: "edit", -: 368: "edit reset", -: 369: "ext on", -: 370: "ext off", -: 371: "ext status", -: 372: "f hist", -: 373: "f clear", -: 374: "forth hist", -: 375: "forth clear", -: 376: "fc on", -: 377: "filescounter on", -: 378: "fc off", -: 379: "filescounter off", -: 380: "fc status", -: 381: "filescounter status", -: 382: "ff on", -: 383: "folders-first on", -: 384: "ff off", -: 385: "folders-first off", -: 386: "ff status", -: 387: "folders-first status", -: 388: "ft unset", -: 389: "filter unset", -: 390: "hf on", -: 391: "hf off", -: 392: "hf status", -: 393: "hidden on", -: 394: "hidden off", -: 395: "hidden status", -: 396: "history clear", -: 397: "icons on", -: 398: "icons off", -: 399: "kb edit", -: 400: "keybinds edit", -: 401: "kb reset", -: 402: "keybinds reset", -: 403: "kb readline", -: 404: "keybinds readline", -: 405: "l edit", -: 406: "lm on", -: 407: "lm off", -: 408: "log clear", -: 409: "mm info", -: 410: "mm edit", -: 411: "mm import", -: 412: "mime info", -: 413: "mime edit", -: 414: "mime import", -: 415: "msg clear", -: 416: "messages clear", -: 417: "net edit", -: 418: "net mount", -: 419: "net unmount", -: 420: "pg on", -: 421: "pager on", -: 422: "pg off", -: 423: "pager off", -: 424: "pg status", -: 425: "pager status", -: 426: "pf set", -: 427: "pf add", -: 428: "pf del", -: 429: "profile set", -: 430: "profile add", -: 431: "profile del", -: 432: "st none", -: 433: "st name", -: 434: "st size", -: 435: "st atime", -: 436: "st btime", -: 437: "st ctime", -: 438: "st owner", -: 439: "st group", -: 440: "st ext", -: 441: "st inode", -: 442: "st version", -: 443: "sort none", -: 444: "sort name", -: 445: "sort size", -: 446: "sort atime", -: 447: "sort btime", -: 448: "sort ctime", -: 449: "sort owner", -: 450: "sort group", -: 451: "sort ext", -: 452: "sort inode", -: 453: "sort version", -: 454: "st rev", -: 455: "sort rev", -: 456: "t list", -: 457: "t clear", -: 458: "t del", -: 459: "tr list", -: 460: "tr clear", -: 461: "tr del", -: 462: "trash list", -: 463: "trash clear", -: 464: "trash del", -: 465: "u all", -: 466: "undel all", -: 467: "untrash all", -: 468: "uc on", -: 469: "unicode on", -: 470: "uc off", -: 471: "unicode off", -: 472: "uc status", -: 473: "unicode status", -: 474: NULL}; -: 475: -: 476:/* To store all the 39 color variables I use, with 46 bytes each, I need -: 477: * a total of 1,8Kb. It's not much but it could be less if I'd use -: 478: * dynamically allocated arrays for them (which, on the other side, -: 479: * would make the whole thing slower and more tedious) */ -: 480: -: 481:/* Colors */ -: 482:char -: 483: /* File types */ -: 484: bd_c[MAX_COLOR], /* Block device */ -: 485: ca_c[MAX_COLOR], /* Cap file */ -: 486: cd_c[MAX_COLOR], /* Char device */ -: 487: di_c[MAX_COLOR], /* Directory */ -: 488: ed_c[MAX_COLOR], /* Empty dir */ -: 489: ee_c[MAX_COLOR], /* Empty executable */ -: 490: ef_c[MAX_COLOR], /* Empty reg file */ -: 491: ex_c[MAX_COLOR], /* Executable */ -: 492: fi_c[MAX_COLOR], /* Reg file */ -: 493: ln_c[MAX_COLOR], /* Symlink */ -: 494: mh_c[MAX_COLOR], /* Multi-hardlink file */ -: 495: nd_c[MAX_COLOR], /* No read directory */ -: 496: ne_c[MAX_COLOR], /* No read empty dir */ -: 497: nf_c[MAX_COLOR], /* No read file */ -: 498: no_c[MAX_COLOR], /* Unknown */ -: 499: or_c[MAX_COLOR], /* Broken symlink */ -: 500: ow_c[MAX_COLOR], /* Other writable */ -: 501: pi_c[MAX_COLOR], /* FIFO, pipe */ -: 502: sg_c[MAX_COLOR], /* SGID file */ -: 503: so_c[MAX_COLOR], /* Socket */ -: 504: st_c[MAX_COLOR], /* Sticky (not ow)*/ -: 505: su_c[MAX_COLOR], /* SUID file */ -: 506: tw_c[MAX_COLOR], /* Sticky other writable */ -: 507: uf_c[MAX_COLOR], /* Non-'stat'able file */ -: 508: -: 509: /* Interface */ -: 510: bm_c[MAX_COLOR], /* Bookmarked directory */ -: 511: dc_c[MAX_COLOR], /* Files counter color */ -: 512: df_c[MAX_COLOR], /* Default color */ -: 513: dh_c[MAX_COLOR], /* Dirhist index color */ -: 514: dl_c[MAX_COLOR], /* Dividing line index color */ -: 515: el_c[MAX_COLOR], /* ELN color */ -: 516: mi_c[MAX_COLOR], /* Misc indicators color */ -: 517: -: 518: /* Suggestions */ -: 519: sc_c[MAX_COLOR], /* Auto-suggestions: external commands */ -: 520: sh_c[MAX_COLOR], /* Auto-suggestions: history */ -: 521: sf_c[MAX_COLOR], /* Auto-suggestions: filenames */ -: 522: sx_c[MAX_COLOR], /* Auto-suggestions: internal commands and params */ -: 523: wc_c[MAX_COLOR], /* Welcome message color */ -: 524: -: 525:#ifndef _NO_ICONS -: 526: dir_ico_c[MAX_COLOR], /* Directories icon color */ -: 527:#endif -: 528: -: 529: /* Syntax highlighting */ -: 530: hb_c[MAX_COLOR], /* Brackets: () [] {} */ -: 531: hc_c[MAX_COLOR], /* Comments */ -: 532: he_c[MAX_COLOR], /* Expansion operators: * ~ */ -: 533: hn_c[MAX_COLOR], /* Numbers */ -: 534: hp_c[MAX_COLOR], /* Parameters: - */ -: 535: hq_c[MAX_COLOR], /* Quoted strings */ -: 536: hr_c[MAX_COLOR], /* Redirection: > */ -: 537: hs_c[MAX_COLOR], /* Process separators: | & ; */ -: 538: hv_c[MAX_COLOR], /* Variables: $ */ -: 539: -: 540: /* Colors used in the prompt, so that \001 and \002 needs to -: 541: * be added. This is why MAX_COLOR + 2 */ -: 542: em_c[MAX_COLOR + 2], /* Error msg color */ -: 543: li_c[MAX_COLOR + 2], /* Sel indicator color */ -: 544: nm_c[MAX_COLOR + 2], /* Notice msg color */ -: 545: wm_c[MAX_COLOR + 2], /* Warning msg color */ -: 546: si_c[MAX_COLOR + 2], /* stealth indicator color */ -: 547: ti_c[MAX_COLOR + 2], /* Trash indicator color */ -: 548: tx_c[MAX_COLOR + 2]; /* Text color */ -: 549: -: 550:#ifdef LINUX_INOTIFY -: 551:int inotify_fd, inotify_wd = -1; -: 552:unsigned int INOTIFY_MASK = /*IN_ATTRIB |*/ IN_CREATE | IN_DELETE -: 553: | IN_DELETE_SELF | /*IN_MODIFY |*/ IN_MOVE_SELF -: 554: | IN_MOVED_FROM | IN_MOVED_TO | IN_EXCL_UNLINK ; -: 555:#elif defined(BSD_KQUEUE) -: 556:int kq, event_fd = -1; -: 557:struct kevent events_to_monitor[NUM_EVENT_FDS]; -: 558:unsigned int KQUEUE_FFLAGS = NOTE_DELETE | NOTE_EXTEND| NOTE_LINK -: 559: | NOTE_RENAME | NOTE_REVOKE | NOTE_WRITE; -: 560:struct timespec timeout; -: 561:#endif -: 562:int watch = -1; -: 563: -: 564: /** -: 565: * ############################# -: 566: * # MAIN # -: 567: * ############################# -: 568: * */ -: 569: -: 570:int function main called 4 returned 0% blocks executed 85% 4: 571:main(int argc, char *argv[]) -: 572:{ -: 573: /* Though this program might perfectly work on other architectures, -: 574: * I just didn't test anything beyond x86 and ARM */ -: 575:#if !defined(__x86_64__) && !defined(__i386__) && !defined(__ARM_ARCH) -: 576: fprintf(stderr, "%s: Unsupported CPU architecture\n", PROGRAM_NAME); -: 577: exit(EXIT_FAILURE); -: 578:#endif -: 579: -: 580:#if !defined(__linux__) && !defined(__FreeBSD__) \ -: 581:&& !defined(__NetBSD__) && !defined(__OpenBSD__) && !defined(__HAIKU__) -: 582: fprintf(stderr, _("%s: Unsupported operating system\n"), PROGRAM_NAME); -: 583: exit(EXIT_FAILURE); -: 584:#endif -: 585: -: 586: /* Make sure we are running on a supported terminal */ 4: 587: check_term(); 4: 587-block 0 call 0 returned 4 -: 588: -: 589: /* Set the default color */ -: 590:/* fputs(DEF_DF_C, stdout); -: 591: fflush(stdout); */ -: 592: -: 593: /* If running the program locally, that is, not from a path in PATH, -: 594: * remove the leading "./" to get the correct program invocation -: 595: * name */ 4: 596: if (*argv[0] == '.' && *(argv[0] + 1) == '/') branch 0 taken 2 (fallthrough) branch 1 taken 2 2: 596-block 0 branch 2 taken 2 (fallthrough) branch 3 taken 0 2: 597: argv[0] += 2; 2: 597-block 0 unconditional 0 taken 2 -: 598: -: 599: /* Use the locale specified by the environment */ 4: 600: setlocale(LC_ALL, ""); 4: 600-block 0 call 0 returned 4 -: 601: 4: 602: unicode = DEF_UNICODE; -: 603: -: 604: /* Store external arguments to be able to rerun external_arguments() -: 605: * in case the user edits the config file, in which case the program -: 606: * must rerun init_config(), get_aliases(), get_prompt_cmds(), and -: 607: * then external_arguments() */ 4: 608: backup_argv(argc, argv); call 0 returned 4 -: 609: -: 610: /* free_stuff does some cleaning */ 4: 611: atexit(free_stuff); call 0 returned 4 -: 612: 4: 613: user = get_user(); call 0 returned 4 4: 614: get_home(); call 0 returned 4 -: 615: 4: 616: if (geteuid() == 0) call 0 returned 4 branch 1 taken 1 (fallthrough) branch 2 taken 3 1: 617: flags |= ROOT_USR; 1: 617-block 0 unconditional 0 taken 1 -: 618: -: 619: /* Running in a graphical environment? */ -: 620:#if __linux__ 4: 621: if (getenv("DISPLAY") != NULL && strncmp(getenv("TERM"), "linux", 5) != 0) 4: 621-block 0 call 0 returned 4 branch 1 taken 4 (fallthrough) branch 2 taken 0 4: 621-block 1 call 3 returned 4 branch 4 taken 4 (fallthrough) branch 5 taken 0 -: 622:#else -: 623: if (getenv("DISPLAY") != NULL) -: 624:#endif 4: 625: flags |= GUI; 4: 625-block 0 unconditional 0 taken 4 -: 626: -: 627: /* Get paths from PATH environment variable. These paths will be -: 628: * used later by get_path_programs (for the autocomplete function) -: 629: * and get_cmd_path() */ 4: 630: path_n = get_path_env(); 4: 630-block 0 call 0 returned 4 4: 631: cdpath_n = get_cdpath(); call 0 returned 4 -: 632: 4: 633: init_workspaces(); call 0 returned 4 -: 634: -: 635: /* Set all external arguments flags to uninitialized state */ 4: 636: unset_xargs(); call 0 returned 4 -: 637: -: 638: /* Manage external arguments, but only if any: argc == 1 equates to -: 639: * no argument, since this '1' is just the program invokation name. -: 640: * External arguments will override initialization values -: 641: * (init_config) */ 4: 642: if (argc > 1) branch 0 taken 4 (fallthrough) branch 1 taken 0 4: 643: external_arguments(argc, argv); 4: 643-block 0 call 0 returned 4 unconditional 1 taken 4 -: 644: /* external_arguments is executed before init_config because, if -: 645: * specified (-P option), it sets the value of alt_profile, which -: 646: * is then checked by init_config */ -: 647: 4: 648: check_env_filter(); 4: 648-block 0 call 0 returned 4 4: 649: get_data_dir(); call 0 returned 4 -: 650: -: 651: /* Initialize program paths and files, set options from the config -: 652: * file, if they were not already set via external arguments, and -: 653: * load sel elements, if any. All these configurations are made -: 654: * per user basis */ -: 655: 4: 656: init_config(); call 0 returned 4 4: 657: check_options(); call 0 returned 4 -: 658: 4: 659: set_sel_file(); call 0 returned 4 4: 660: create_tmp_files(); call 0 returned 4 4: 661: load_actions(); call 0 returned 4 4: 662: get_aliases(); call 0 returned 4 -: 663: -: 664: /* Get the list of available applications in PATH to be used by my -: 665: * custom TAB-completion function */ 4: 666: get_path_programs(); call 0 returned 4 -: 667: -: 668: /* Initialize gettext() for translations */ -: 669:#ifndef _NO_GETTEXT 4: 670: init_gettext(); call 0 returned 4 -: 671:#endif -: 672: 4: 673: cschemes_n = get_colorschemes(); call 0 returned 4 4*: 674: set_colors(usr_cscheme ? usr_cscheme : "default", 1); branch 0 taken 4 (fallthrough) branch 1 taken 0 4: 674-block 0 unconditional 2 taken 4 %%%%%: 674-block 1 unconditional 3 never executed 4: 674-block 2 call 4 returned 4 4: 675: free(usr_cscheme); 4: 676: usr_cscheme = (char *)NULL; -: 677: 4: 678: fputs(df_c, stdout); call 0 returned 4 4: 679: fflush(stdout); call 0 returned 4 -: 680: 4: 681: if (flags & ROOT_USR) { branch 0 taken 1 (fallthrough) branch 1 taken 3 1: 682: _err(0, PRINT_PROMPT, _("%s%s: %sRunning as root%s\n"), 1: 682-block 0 call 0 returned 1 call 1 returned 1 unconditional 2 taken 1 -: 683: BOLD, PROGRAM_NAME, _RED, df_c); -: 684: } -: 685: 4: 686: load_remotes(); 4: 686-block 0 call 0 returned 4 4: 687: automount_remotes(); call 0 returned 4 -: 688: 4: 689: if (splash_screen) { branch 0 taken 0 (fallthrough) branch 1 taken 4 #####: 690: splash(); %%%%%: 690-block 0 call 0 never executed #####: 691: splash_screen = 0; #####: 692: CLEAR; call 0 never executed unconditional 1 never executed -: 693: } -: 694: 4: 695: set_start_path(); 4: 695-block 0 call 0 returned 4 -: 696: 4: 697: if (ws == (struct ws_t *)NULL || !ws[cur_ws].path || !*ws[cur_ws].path) { branch 0 taken 4 (fallthrough) branch 1 taken 0 4: 697-block 0 branch 2 taken 4 (fallthrough) branch 3 taken 0 4: 697-block 1 branch 4 taken 0 (fallthrough) branch 5 taken 4 #####: 698: _err(0, NOPRINT_PROMPT, _("%s: Fatal error! Failed " %%%%%: 698-block 0 call 0 never executed call 1 never executed -: 699: "retrieving current working directory\n"), PROGRAM_NAME); #####: 700: exit(EXIT_FAILURE); call 0 never executed -: 701: } -: 702: -: 703: /* Set terminal window title */ 4: 704: if (flags & GUI) { 4: 704-block 0 branch 0 taken 4 (fallthrough) branch 1 taken 0 4: 705: if (xargs.cwd_in_title == 0) { 4: 705-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 2 2: 706: printf("\033]2;%s\007", PROGRAM_NAME); 2: 706-block 0 call 0 returned 2 2: 707: fflush(stdout); call 0 returned 2 unconditional 1 taken 2 -: 708: } else { 2: 709: set_term_title(ws[cur_ws].path); 2: 709-block 0 call 0 returned 2 unconditional 1 taken 2 -: 710: } -: 711: } -: 712: 4: 713: exec_profile(); 4: 713-block 0 call 0 returned 4 4: 714: load_dirhist(); call 0 returned 4 4: 715: add_to_dirhist(ws[cur_ws].path); call 0 returned 4 4: 716: get_sel_files(); call 0 returned 4 -: 717: -: 718: /* Start listing as soon as possible to speed up startup time */ 4: 719: if (cd_lists_on_the_fly && isatty(STDIN_FILENO)) { branch 0 taken 4 (fallthrough) branch 1 taken 0 4: 719-block 0 call 2 returned 4 branch 3 taken 4 (fallthrough) branch 4 taken 0 -: 720:#ifdef LINUX_INOTIFY -: 721: /* Initialize inotify */ 4: 722: inotify_fd = inotify_init1(IN_NONBLOCK); 4: 722-block 0 call 0 returned 4 4: 723: if (inotify_fd < 0) { branch 0 taken 0 (fallthrough) branch 1 taken 4 #####: 724: _err('w', PRINT_PROMPT, "%s: inotify: %s\n", PROGRAM_NAME, call 0 never executed unconditional 1 never executed #####: 725: strerror(errno)); %%%%%: 725-block 0 call 0 never executed -: 726: } -: 727:#elif defined(BSD_KQUEUE) -: 728: kq = kqueue(); -: 729: if (kq < 0) { -: 730: _err('w', PRINT_PROMPT, "%s: kqueue: %s\n", PROGRAM_NAME, -: 731: strerror(errno)); -: 732: } -: 733:#endif 4: 734: list_dir(); 4: 734-block 0 call 0 returned 4 unconditional 1 taken 4 -: 735: } -: 736: 4: 737: create_kbinds_file(); 4: 737-block 0 call 0 returned 4 4: 738: load_bookmarks(); call 0 returned 4 4: 739: load_keybinds(); call 0 returned 4 4: 740: load_jumpdb(); call 0 returned 4 4: 741: if (!jump_db || xargs.path == 1) branch 0 taken 4 (fallthrough) branch 1 taken 0 4: 741-block 0 branch 2 taken 2 (fallthrough) branch 3 taken 2 2: 742: add_to_jumpdb(ws[cur_ws].path); 2: 742-block 0 call 0 returned 2 unconditional 1 taken 2 -: 743: 4: 744: initialize_readline(); 4: 744-block 0 call 0 returned 4 -: 745: -: 746: /*Trim the directory history file if necessary */ 4: 747: check_file_size(dirhist_file, max_dirhist); call 0 returned 4 -: 748: -: 749: /* Check whether we have a working shell */ 4: 750: if (access(user.shell, X_OK) == -1) { call 0 returned 4 branch 1 taken 0 (fallthrough) branch 2 taken 4 #####: 751: _err('w', PRINT_PROMPT, _("%s: %s: System shell not found. " %%%%%: 751-block 0 call 0 never executed call 1 never executed unconditional 2 never executed -: 752: "Please edit the configuration file to specify a working " -: 753: "shell.\n"), PROGRAM_NAME, user.shell); -: 754: } -: 755: 4: 756: get_prompt_cmds(); 4: 756-block 0 call 0 returned 4 -: 757: -: 758:#ifndef _NO_TRASH 4: 759: if (trash_ok) { branch 0 taken 4 (fallthrough) branch 1 taken 0 4: 760: trash_n = count_dir(trash_files_dir, NO_CPOP); 4: 760-block 0 call 0 returned 4 4: 761: if (trash_n <= 2) branch 0 taken 4 (fallthrough) branch 1 taken 0 4: 762: trash_n = 0; 4: 762-block 0 unconditional 0 taken 4 -: 763: } -: 764:#endif -: 765: 4: 766: if (gethostname(hostname, sizeof(hostname)) == -1) { 4: 766-block 0 call 0 returned 4 branch 1 taken 0 (fallthrough) branch 2 taken 4 #####: 767: hostname[0] = '?'; #####: 768: hostname[1] = '\0'; #####: 769: _err('e', PRINT_PROMPT, _("%s: Error getting hostname\n"), %%%%%: 769-block 0 call 0 never executed call 1 never executed unconditional 2 never executed -: 770: PROGRAM_NAME); -: 771: } -: 772: 4: 773: init_shell(); 4: 773-block 0 call 0 returned 4 -: 774: 4: 775: if (config_ok) branch 0 taken 4 (fallthrough) branch 1 taken 0 4: 776: init_history(); 4: 776-block 0 call 0 returned 4 unconditional 1 taken 4 -: 777: -: 778: /* Store history into an array to be able to manipulate it */ 4: 779: get_history(); 4: 779-block 0 call 0 returned 4 -: 780: -: 781: /* Check if the 'file' command is available: we need it for Lira */ -: 782:/* if (!opener) -: 783: file_cmd_check(); */ -: 784: 4: 785: get_profile_names(); call 0 returned 4 4: 786: load_pinned_dir(); call 0 returned 4 4: 787: set_env(); call 0 returned 4 unconditional 1 taken 4 -: 788: -: 789: /* ########################### -: 790: * # 2) MAIN PROGRAM LOOP # -: 791: * ########################### */ -: 792: -: 793: /* This is the main structure of any basic shell -: 794: 1 - Infinite loop -: 795: 2 - Grab user input -: 796: 3 - Parse user input -: 797: 4 - Execute command -: 798: See https://brennan.io/2015/01/16/write-a-shell-in-c/ -: 799: */ -: 800: -: 801: int i; -: 802: /* 1) Infinite loop to keep the program running */ 401: 803: while (1) { -: 804: /* 2) Grab input string from the prompt */ 405: 805: char *input = prompt(); 405: 805-block 0 call 0 returned 405 405: 806: if (!input) branch 0 taken 1 (fallthrough) branch 1 taken 404 1: 807: continue; 1: 807-block 0 unconditional 0 taken 1 -: 808: -: 809: /* 3) Parse input string */ 404: 810: char **cmd = parse_input_str(input); 404: 810-block 0 call 0 returned 404 404: 811: free(input); 404: 812: input = (char *)NULL; -: 813: 404*: 814: if (!cmd) branch 0 taken 0 (fallthrough) branch 1 taken 404 #####: 815: continue; %%%%%: 815-block 0 unconditional 0 never executed -: 816: -: 817: /* 4) Execute input string */ 404: 818: char **alias_cmd = check_for_alias(cmd); 404: 818-block 0 call 0 returned 404 404: 819: if (alias_cmd) { branch 0 taken 0 (fallthrough) branch 1 taken 404 -: 820: /* If an alias is found, check_for_alias() frees cmd -: 821: * and returns alias_cmd in its place to be executed by -: 822: * exec_cmd() */ #####: 823: exec_cmd(alias_cmd); %%%%%: 823-block 0 call 0 never executed -: 824: #####: 825: for (i = 0; alias_cmd[i]; i++) unconditional 0 never executed %%%%%: 825-block 0 branch 1 never executed branch 2 never executed #####: 826: free(alias_cmd[i]); %%%%%: 826-block 0 unconditional 0 never executed -: 827: #####: 828: free(alias_cmd); #####: 829: alias_cmd = (char **)NULL; %%%%%: 829-block 0 unconditional 0 never executed -: 830: } else { 404: 831: exec_cmd(cmd); 404: 831-block 0 call 0 returned 400 -: 832: 400: 833: i = (int)args_n + 1; 970: 834: while (--i >= 0) unconditional 0 taken 400 970: 834-block 0 branch 1 taken 570 branch 2 taken 400 (fallthrough) 570: 835: free(cmd[i]); 570: 835-block 0 unconditional 0 taken 570 -: 836: 400: 837: free(cmd); 400: 838: cmd = (char **)NULL; 400: 838-block 0 unconditional 0 taken 400 -: 839: } -: 840: } -: 841: -: 842: return exit_code; /* Never reached */ -: 843:} clifm-1.26.3/misc/codecov/mime.c.gcov000066400000000000000000001405521506632037700173220ustar00rootroot00000000000000 -: 0:Source:mime.c -: 1:/* mime.c -- functions controlling Lira, the resource opener */ -: 2: -: 3:/* -: 4: * This file is part of CliFM -: 5: * -: 6: * Copyright (C) 2016-2021, L. Abramovich -: 7: * All rights reserved. -: 8: -: 9: * CliFM is free software; you can redistribute it and/or modify -: 10: * it under the terms of the GNU General Public License as published by -: 11: * the Free Software Foundation; either version 2 of the License, or -: 12: * (at your option) any later version. -: 13: * -: 14: * CliFM is distributed in the hope that it will be useful, -: 15: * but WITHOUT ANY WARRANTY; without even the implied warranty of -: 16: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -: 17: * GNU General Public License for more details. -: 18: * -: 19: * You should have received a copy of the GNU General Public License -: 20: * along with this program; if not, write to the Free Software -: 21: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, -: 22: * MA 02110-1301, USA. -: 23:*/ -: 24: -: 25:#ifndef _NO_LIRA -: 26: -: 27:#include "helpers.h" -: 28: -: 29:#include -: 30:#include -: 31:#include -: 32:#include -: 33:#include -: 34:#include -: 35:#include -: 36: -: 37:#ifndef _NO_MAGIC -: 38:#include -: 39:#endif -: 40: -: 41:#include "archives.h" -: 42:#include "aux.h" -: 43:#include "checks.h" -: 44:#include "exec.h" -: 45:#include "mime.h" -: 46:#include "messages.h" -: 47:#include "navigation.h" -: 48: -: 49:/* Get application associated to a given MIME file type or file extension. -: 50: * Returns the first matching line in the MIME file or NULL if none is -: 51: * found */ -: 52:static char * function get_app called 40 returned 100% blocks executed 65% 40: 53:get_app(const char *mime, const char *ext) -: 54:{ 40: 55: if (!mime) 40: 55-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 40 #####: 56: return (char *)NULL; %%%%%: 56-block 0 unconditional 0 never executed -: 57: 40: 58: if (!mime_file || !*mime_file) 40: 58-block 0 branch 0 taken 40 (fallthrough) branch 1 taken 0 40: 58-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 40 #####: 59: return (char *)NULL; %%%%%: 59-block 0 unconditional 0 never executed -: 60: 40: 61: FILE *defs_fp = fopen(mime_file, "r"); 40: 61-block 0 call 0 returned 40 40: 62: if (!defs_fp) { branch 0 taken 0 (fallthrough) branch 1 taken 40 #####: 63: fprintf(stderr, _("%s: %s: Error opening file\n"), %%%%%: 63-block 0 call 0 never executed call 1 never executed -: 64: PROGRAM_NAME, mime_file); #####: 65: return (char *)NULL; unconditional 0 never executed -: 66: } -: 67: 40: 68: int found = 0, cmd_ok = 0; 40: 69: size_t line_size = 0; 40: 70: char *line = (char *)NULL, *app = (char *)NULL; -: 71:/* ssize_t line_len = 0; */ -: 72: 825: 73: while (getline(&line, &line_size, defs_fp) > 0) { 40: 73-block 0 unconditional 0 taken 40 825: 73-block 1 call 1 returned 825 branch 2 taken 825 branch 3 taken 0 (fallthrough) 825: 74: found = mime_match = 0; /* Global variable to tell mime_open() -: 75: if the application is associated to the file's extension or MIME -: 76: type */ 825: 77: if (*line == '#' || *line == '[' || *line == '\n') 825: 77-block 0 branch 0 taken 538 (fallthrough) branch 1 taken 287 538: 77-block 1 branch 2 taken 538 (fallthrough) branch 3 taken 0 538: 77-block 2 branch 4 taken 127 (fallthrough) branch 5 taken 411 785: 78: continue; 414: 78-block 0 unconditional 0 taken 414 785: 78-block 1 unconditional 1 taken 785 -: 79: 411: 80: char *p = line; 411: 81: if (!(flags & GUI)) { 411: 81-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 411 #####: 82: if (*p != '!' || *(p + 1) != 'X' || *(p + 2) != ':') %%%%%: 82-block 0 branch 0 never executed branch 1 never executed %%%%%: 82-block 1 branch 2 never executed branch 3 never executed %%%%%: 82-block 2 branch 4 never executed branch 5 never executed #####: 83: continue; %%%%%: 83-block 0 unconditional 0 never executed -: 84: else #####: 85: p += 3; %%%%%: 85-block 0 unconditional 0 never executed -: 86: } else { 411: 87: if (*p == '!' && *(p + 1) == 'X') 411: 87-block 0 branch 0 taken 42 (fallthrough) branch 1 taken 369 42: 87-block 1 branch 2 taken 42 (fallthrough) branch 3 taken 0 42: 88: continue; 42: 88-block 0 unconditional 0 taken 42 369: 89: if (*p == 'X' && *(p + 1) == ':') 369: 89-block 0 branch 0 taken 368 (fallthrough) branch 1 taken 1 368: 89-block 1 branch 2 taken 368 (fallthrough) branch 3 taken 0 368: 90: p += 2; 368: 90-block 0 unconditional 0 taken 368 -: 91: } -: 92: 369: 93: char *tmp = strchr(p, '='); 369*: 94: if (!tmp || !*(tmp + 1)) 369: 94-block 0 branch 0 taken 369 (fallthrough) branch 1 taken 0 369: 94-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 369 #####: 95: continue; %%%%%: 95-block 0 unconditional 0 never executed -: 96: -: 97: /* Truncate line in '=' to get only the ext/mimetype pattern/string */ 369: 98: *tmp = '\0'; -: 99: regex_t regex; -: 100: 369: 101: if (ext && *p == 'E' && *(p + 1) == ':') { 369: 101-block 0 branch 0 taken 180 (fallthrough) branch 1 taken 189 180: 101-block 1 branch 2 taken 100 (fallthrough) branch 3 taken 80 100: 101-block 2 branch 4 taken 100 (fallthrough) branch 5 taken 0 100: 102: if (regcomp(®ex, p + 2, REG_NOSUB | REG_EXTENDED) == 0 100: 102-block 0 call 0 returned 100 branch 1 taken 100 (fallthrough) branch 2 taken 0 100: 103: && regexec(®ex, ext, 0, NULL, 0) == 0) 100: 103-block 0 call 0 returned 100 branch 1 taken 0 (fallthrough) branch 2 taken 100 #####: 104: found = 1; %%%%%: 104-block 0 unconditional 0 never executed 269: 105: } else if (regcomp(®ex, p, REG_NOSUB | REG_EXTENDED) == 0 269: 105-block 0 call 0 returned 269 branch 1 taken 269 (fallthrough) branch 2 taken 0 269: 106: && regexec(®ex, mime, 0, NULL, 0) == 0) { 269: 106-block 0 call 0 returned 269 branch 1 taken 40 (fallthrough) branch 2 taken 229 40: 107: found = mime_match = 1; 40: 107-block 0 unconditional 0 taken 40 -: 108: } -: 109: 369: 110: regfree(®ex); 369: 110-block 0 call 0 returned 369 -: 111: 369: 112: if (!found) branch 0 taken 329 (fallthrough) branch 1 taken 40 329: 113: continue; 329: 113-block 0 unconditional 0 taken 329 -: 114: 40: 115: tmp++; /* We don't want the '=' char */ -: 116: 40: 117: size_t tmp_len = strlen(tmp); 40: 118: app = (char *)xrealloc(app, (tmp_len + 1) * sizeof(char)); 40: 118-block 0 call 0 returned 40 -: 119: 40: 120: while (*tmp) { unconditional 0 taken 40 40: 120-block 0 branch 1 taken 40 branch 2 taken 0 (fallthrough) 40: 121: size_t app_len = 0; -: 122: /* Split the appplications line into substrings, if -: 123: * any */ 361: 124: while (*tmp != '\0' && *tmp != ';' && *tmp != '\n' && *tmp != '\'' 40: 124-block 0 unconditional 0 taken 40 321: 124-block 1 branch 1 taken 281 (fallthrough) branch 2 taken 40 281: 124-block 2 branch 3 taken 281 (fallthrough) branch 4 taken 0 281: 124-block 3 branch 5 taken 281 (fallthrough) branch 6 taken 0 602: 125: && *tmp != '"') 321: 125-block 0 branch 0 taken 321 (fallthrough) branch 1 taken 0 281: 125-block 1 branch 2 taken 281 branch 3 taken 0 (fallthrough) 281: 126: app[app_len++] = *(tmp++); 281: 126-block 0 unconditional 0 taken 281 -: 127: 40: 128: while (*tmp == ' ') /* Remove leading spaces */ 40: 128-block 0 unconditional 0 taken 40 40: 128-block 1 branch 1 taken 0 branch 2 taken 40 (fallthrough) #####: 129: tmp++; %%%%%: 129-block 0 unconditional 0 never executed -: 130: 40: 131: if (app_len) { 40: 131-block 0 branch 0 taken 40 (fallthrough) branch 1 taken 0 40: 132: app[app_len] = '\0'; -: 133: /* Check each application existence */ 40: 134: char *file_path = (char *)NULL; -: 135: /* If app contains spaces, the command to check is -: 136: * the string before the first space */ 40: 137: char *ret = strchr(app, ' '); 40: 138: if (ret) { 40: 138-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 40 #####: 139: *ret = '\0'; #####: 140: if (*app == '~') { %%%%%: 140-block 0 branch 0 never executed branch 1 never executed #####: 141: file_path = tilde_expand(app); %%%%%: 141-block 0 call 0 never executed #####: 142: if (access(file_path, X_OK) != 0) { call 0 never executed branch 1 never executed branch 2 never executed #####: 143: free(file_path); #####: 144: file_path = (char *)NULL; %%%%%: 144-block 0 unconditional 0 never executed -: 145: } #####: 146: } else if (*app == '/') { %%%%%: 146-block 0 branch 0 never executed branch 1 never executed #####: 147: if (access(app, X_OK) == 0) { %%%%%: 147-block 0 call 0 never executed branch 1 never executed branch 2 never executed #####: 148: file_path = app; %%%%%: 148-block 0 unconditional 0 never executed -: 149: } -: 150: } else { #####: 151: file_path = get_cmd_path(app); %%%%%: 151-block 0 call 0 never executed unconditional 1 never executed -: 152: } #####: 153: *ret = ' '; %%%%%: 153-block 0 unconditional 0 never executed -: 154: } else { 40: 155: if (*app == '~') { 40: 155-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 40 #####: 156: file_path = tilde_expand(app); %%%%%: 156-block 0 call 0 never executed #####: 157: if (access(file_path, X_OK) != 0) { call 0 never executed branch 1 never executed branch 2 never executed #####: 158: free(file_path); #####: 159: file_path = (char *)NULL; %%%%%: 159-block 0 unconditional 0 never executed -: 160: } -: 161: } 40: 162: else if (*app == '/') { 40: 162-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 40 #####: 163: if (access(app, X_OK) == 0) { %%%%%: 163-block 0 call 0 never executed branch 1 never executed branch 2 never executed #####: 164: file_path = app; %%%%%: 164-block 0 unconditional 0 never executed -: 165: } -: 166: } else { 40: 167: file_path = get_cmd_path(app); 40: 167-block 0 call 0 returned 40 unconditional 1 taken 40 -: 168: } -: 169: } -: 170: 40*: 171: if (file_path) { 40: 171-block 0 branch 0 taken 40 (fallthrough) branch 1 taken 0 -: 172: /* If the app exists, break the loops and -: 173: * return it */ 40: 174: if (*app != '/') { 40: 174-block 0 branch 0 taken 40 (fallthrough) branch 1 taken 0 40: 175: free(file_path); 40: 176: file_path = (char *)NULL; 40: 176-block 0 unconditional 0 taken 40 -: 177: } 40: 178: cmd_ok = 1; 40: 178-block 0 unconditional 0 taken 40 -: 179: } else { #####: 180: continue; %%%%%: 180-block 0 unconditional 0 never executed -: 181: } -: 182: } -: 183: 40: 184: if (cmd_ok) 40: 184-block 0 branch 0 taken 40 (fallthrough) branch 1 taken 0 40: 185: break; 40: 185-block 0 unconditional 0 taken 40 #####: 186: tmp++; %%%%%: 186-block 0 unconditional 0 never executed -: 187: } -: 188: 40: 189: if (cmd_ok) 40: 189-block 0 branch 0 taken 40 (fallthrough) branch 1 taken 0 40: 190: break; 40: 190-block 0 unconditional 0 taken 40 -: 191: } -: 192: 40: 193: free(line); 40: 194: fclose(defs_fp); 40: 194-block 0 call 0 returned 40 -: 195: 40: 196: if (found) { branch 0 taken 40 (fallthrough) branch 1 taken 0 40: 197: if (app) 40: 197-block 0 branch 0 taken 40 (fallthrough) branch 1 taken 0 40: 198: return app; 40: 198-block 0 unconditional 0 taken 40 -: 199: } else { #####: 200: if (app) %%%%%: 200-block 0 branch 0 never executed branch 1 never executed #####: 201: free(app); %%%%%: 201-block 0 unconditional 0 never executed -: 202: } -: 203: #####: 204: return (char *)NULL; %%%%%: 204-block 0 unconditional 0 never executed -: 205:} -: 206: -: 207:#ifndef _NO_MAGIC -: 208:/* Get FILE's MIME type using the libmagic library */ -: 209:char * function xmagic called 63 returned 100% blocks executed 78% 63: 210:xmagic(const char *file, const int query_mime) -: 211:{ 63: 212: if (!file || !*file) 63: 212-block 0 branch 0 taken 63 (fallthrough) branch 1 taken 0 63: 212-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 63 #####: 213: return (char *)NULL; %%%%%: 213-block 0 unconditional 0 never executed -: 214: 63: 215: magic_t cookie = magic_open(query_mime ? (MAGIC_MIME_TYPE | MAGIC_ERROR) 63: 215-block 0 branch 0 taken 40 (fallthrough) branch 1 taken 23 40: 215-block 1 unconditional 2 taken 40 23: 215-block 2 unconditional 3 taken 23 63: 215-block 3 call 4 returned 63 -: 216: : MAGIC_ERROR); 63: 217: if (!cookie) branch 0 taken 0 (fallthrough) branch 1 taken 63 #####: 218: return (char *)NULL; %%%%%: 218-block 0 unconditional 0 never executed -: 219: 63: 220: magic_load(cookie, NULL); 63: 220-block 0 call 0 returned 63 -: 221: 63: 222: const char *mime = magic_file(cookie, file); call 0 returned 63 63: 223: if (!mime) { branch 0 taken 0 (fallthrough) branch 1 taken 63 #####: 224: magic_close(cookie); %%%%%: 224-block 0 call 0 never executed #####: 225: return (char *)NULL; unconditional 0 never executed -: 226: } -: 227: 63: 228: char *str = (char *)xnmalloc(strlen(mime) + 1, sizeof(char)); 63: 228-block 0 call 0 returned 63 63: 229: strcpy(str, mime); 63: 230: magic_close(cookie); call 0 returned 63 63: 231: return str; unconditional 0 taken 63 -: 232:} -: 233: -: 234:#else -: 235:static char * -: 236:get_mime(char *file) -: 237:{ -: 238: if (!file || !*file) { -: 239: fputs(_("Error opening temporary file\n"), stderr); -: 240: return (char *)NULL; -: 241: } -: 242: -: 243: char *rand_ext = gen_rand_str(6); -: 244: if (!rand_ext) -: 245: return (char *)NULL; -: 246: -: 247: char MIME_TMP_FILE[PATH_MAX] = ""; -: 248: sprintf(MIME_TMP_FILE, "%s/mime.%s", TMP_DIR, rand_ext); -: 249: free(rand_ext); -: 250: -: 251: if (access(MIME_TMP_FILE, F_OK) == 0) -: 252: unlink(MIME_TMP_FILE); -: 253: -: 254: FILE *file_fp = fopen(MIME_TMP_FILE, "w"); -: 255: if (!file_fp) { -: 256: fprintf(stderr, "%s: %s: %s\n", PROGRAM_NAME, MIME_TMP_FILE, -: 257: strerror(errno)); -: 258: return (char *)NULL; -: 259: } -: 260: -: 261: FILE *file_fp_err = fopen("/dev/null", "w"); -: 262: if (!file_fp_err) { -: 263: fprintf(stderr, "%s: /dev/null: %s\n", PROGRAM_NAME, strerror(errno)); -: 264: fclose(file_fp); -: 265: return (char *)NULL; -: 266: } -: 267: -: 268: int stdout_bk = dup(STDOUT_FILENO); /* Store original stdout */ -: 269: int stderr_bk = dup(STDERR_FILENO); /* Store original stderr */ -: 270: -: 271: /* Redirect stdout to the desired file */ -: 272: if (dup2(fileno(file_fp), STDOUT_FILENO) == -1) { -: 273: fprintf(stderr, "%s: %s\n", PROGRAM_NAME, strerror(errno)); -: 274: fclose(file_fp); -: 275: fclose(file_fp_err); -: 276: return (char *)NULL; -: 277: } -: 278: -: 279: /* Redirect stderr to /dev/null */ -: 280: if (dup2(fileno(file_fp_err), STDERR_FILENO) == -1) { -: 281: fprintf(stderr, "%s: %s\n", PROGRAM_NAME, strerror(errno)); -: 282: fclose(file_fp); -: 283: fclose(file_fp_err); -: 284: return (char *)NULL; -: 285: } -: 286: -: 287: fclose(file_fp); -: 288: fclose(file_fp_err); -: 289: -: 290: char *cmd[] = {"file", "--mime-type", file, NULL}; -: 291: int ret = launch_execve(cmd, FOREGROUND, E_NOFLAG); -: 292: -: 293: dup2(stdout_bk, STDOUT_FILENO); /* Restore original stdout */ -: 294: dup2(stderr_bk, STDERR_FILENO); /* Restore original stderr */ -: 295: close(stdout_bk); -: 296: close(stderr_bk); -: 297: -: 298: if (ret != EXIT_SUCCESS) -: 299: return (char *)NULL; -: 300: -: 301: if (access(MIME_TMP_FILE, F_OK) != 0) -: 302: return (char *)NULL; -: 303: -: 304: file_fp = fopen(MIME_TMP_FILE, "r"); -: 305: if (!file_fp) { -: 306: unlink(MIME_TMP_FILE); -: 307: return (char *)NULL; -: 308: } -: 309: -: 310: char *mime_type = (char *)NULL; -: 311: -: 312: char line[255] = ""; -: 313: if (fgets(line, (int)sizeof(line), file_fp) == NULL) { -: 314: fclose(file_fp); -: 315: unlink(MIME_TMP_FILE); -: 316: return (char *)NULL; -: 317: } -: 318: char *tmp = strrchr(line, ' '); -: 319: if (tmp) { -: 320: size_t len = strlen(tmp); -: 321: if (tmp[len - 1] == '\n') -: 322: tmp[len - 1] = '\0'; -: 323: mime_type = savestring(tmp + 1, strlen(tmp) - 1); -: 324: } -: 325: -: 326: fclose(file_fp); -: 327: unlink(MIME_TMP_FILE); -: 328: return mime_type; -: 329:} -: 330:#endif /* !_NO_MAGIC */ -: 331: -: 332:/* Import MIME definitions from the system and store them into FILE. -: 333: * Returns the amount of definitions found, if any, or -1 in case of error -: 334: * or no association found */ -: 335:static int function mime_import called 0 returned 0% blocks executed 0% #####: 336:mime_import(char *file) -: 337:{ -: 338:#ifdef __HAIKU__ -: 339: fprintf(stderr, "%s: Importing MIME definitions is not supported on Haiku\n", -: 340: PROGRAM_NAME); -: 341: return (-1); -: 342:#endif -: 343: /* If not in X, exit) */ #####: 344: if (!(flags & GUI)) { %%%%%: 344-block 0 branch 0 never executed branch 1 never executed #####: 345: fprintf(stderr, _("%s: Nothing was imported. No graphical " %%%%%: 345-block 0 call 0 never executed call 1 never executed -: 346: "environment found\n"), PROGRAM_NAME); #####: 347: return (-1); unconditional 0 never executed -: 348: } -: 349: #####: 350: if (!user.home) { %%%%%: 350-block 0 branch 0 never executed branch 1 never executed #####: 351: fprintf(stderr, _("%s: Error getting home directory\n"), PROGRAM_NAME); %%%%%: 351-block 0 call 0 never executed call 1 never executed #####: 352: return (-1); unconditional 0 never executed -: 353: } -: 354: -: 355: /* Open the local MIME file */ #####: 356: FILE *mime_fp = fopen(file, "w"); %%%%%: 356-block 0 call 0 never executed #####: 357: if (!mime_fp) { branch 0 never executed branch 1 never executed #####: 358: fprintf(stderr, "%s: %s: %s\n", PROGRAM_NAME, file, strerror(errno)); %%%%%: 358-block 0 call 0 never executed call 1 never executed #####: 359: return (-1); unconditional 0 never executed -: 360: } -: 361: -: 362: /* Create a list of possible paths for the 'mimeapps.list' file as -: 363: * specified by the Freedesktop specification */ #####: 364: size_t home_len = strlen(user.home); #####: 365: char *config_path = (char *)NULL, *local_path = (char *)NULL; #####: 366: config_path = (char *)xnmalloc(home_len + 23, sizeof(char)); %%%%%: 366-block 0 call 0 never executed #####: 367: local_path = (char *)xnmalloc(home_len + 41, sizeof(char)); call 0 never executed #####: 368: sprintf(config_path, "%s/.config/mimeapps.list", user.home); #####: 369: sprintf(local_path, "%s/.local/share/applications/mimeapps.list", user.home); -: 370: #####: 371: char *mime_paths[] = {config_path, local_path, -: 372: "/usr/local/share/applications/mimeapps.list", -: 373: "/usr/share/applications/mimeapps.list", -: 374: "/etc/xdg/mimeapps.list", NULL}; -: 375: -: 376: /* Check each mimeapps.list file and store its associations into -: 377: * FILE */ -: 378: size_t i; #####: 379: int mime_defs = 0; -: 380: #####: 381: for (i = 0; mime_paths[i]; i++) { unconditional 0 never executed %%%%%: 381-block 0 unconditional 1 never executed %%%%%: 381-block 1 branch 2 never executed branch 3 never executed #####: 382: FILE *sys_mime_fp = fopen(mime_paths[i], "r"); %%%%%: 382-block 0 call 0 never executed #####: 383: if (!sys_mime_fp) branch 0 never executed branch 1 never executed #####: 384: continue; %%%%%: 384-block 0 unconditional 0 never executed -: 385: #####: 386: size_t line_size = 0; #####: 387: char *line = (char *)NULL; -: 388: /* Only store associations in the "Default Applications" section */ #####: 389: int da_found = 0; -: 390: #####: 391: while (getline(&line, &line_size, sys_mime_fp) > 0) { %%%%%: 391-block 0 unconditional 0 never executed %%%%%: 391-block 1 call 1 never executed branch 2 never executed branch 3 never executed #####: 392: if (!da_found && strncmp(line, "[Default Applications]", 22) == 0) { %%%%%: 392-block 0 branch 0 never executed branch 1 never executed %%%%%: 392-block 1 branch 2 never executed branch 3 never executed #####: 393: da_found = 1; #####: 394: continue; %%%%%: 394-block 0 unconditional 0 never executed -: 395: } -: 396: #####: 397: if (da_found) { %%%%%: 397-block 0 branch 0 never executed branch 1 never executed #####: 398: if (*line == '[') %%%%%: 398-block 0 branch 0 never executed branch 1 never executed #####: 399: break; %%%%%: 399-block 0 unconditional 0 never executed #####: 400: if (*line == '#' || *line == '\n') %%%%%: 400-block 0 branch 0 never executed branch 1 never executed %%%%%: 400-block 1 branch 2 never executed branch 3 never executed #####: 401: continue; %%%%%: 401-block 0 unconditional 0 never executed -: 402: #####: 403: int index = strcntchr(line, '.'); %%%%%: 403-block 0 call 0 never executed #####: 404: if (index != -1) branch 0 never executed branch 1 never executed #####: 405: line[index] = '\0'; %%%%%: 405-block 0 unconditional 0 never executed -: 406: #####: 407: fprintf(mime_fp, "%s\n", line); %%%%%: 407-block 0 call 0 never executed #####: 408: mime_defs++; unconditional 0 never executed -: 409: } -: 410: } -: 411: #####: 412: free(line); #####: 413: line = (char *)NULL; #####: 414: fclose(sys_mime_fp); %%%%%: 414-block 0 call 0 never executed -: 415: } -: 416: #####: 417: free(config_path); #####: 418: free(local_path); -: 419: #####: 420: if (mime_defs <= 0) { %%%%%: 420-block 0 branch 0 never executed branch 1 never executed #####: 421: fclose(mime_fp); %%%%%: 421-block 0 call 0 never executed #####: 422: fprintf(stderr, _("%s: Nothing was imported. No MIME definitions " call 0 never executed call 1 never executed -: 423: "found\n"), PROGRAM_NAME); #####: 424: return (-1); unconditional 0 never executed -: 425: } -: 426: -: 427: /* Make sure there is an entry for text/plain and *.cfm files, so -: 428: * that at least 'mm edit' will work. Gedit, kate, pluma, mousepad, -: 429: * and leafpad, are the default text editors of Gnome, KDE, Mate, -: 430: * XFCE, and LXDE respectivelly */ #####: 431: fputs("X:text/plain=gedit;kate;pluma;mousepad;leafpad;nano;vim;" %%%%%: 431-block 0 call 0 never executed -: 432: "vi;emacs;ed\n" -: 433: "X:E:^cfm$=gedit;kate;pluma;mousepad;leafpad;nano;vim;vi;" -: 434: "emacs;ed\n", mime_fp); -: 435: #####: 436: fclose(mime_fp); call 0 never executed #####: 437: return mime_defs; unconditional 0 never executed -: 438:} -: 439: -: 440:static int function mime_edit called 1 returned 100% blocks executed 46% 1: 441:mime_edit(char **args) -: 442:{ 1: 443: int exit_status = EXIT_SUCCESS; -: 444: 1: 445: if (!args[2]) { 1: 445-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 0 1: 446: char *cmd[] = {"mime", mime_file, NULL}; 1: 447: if (mime_open(cmd) != 0) { 1: 447-block 0 call 0 returned 1 branch 1 taken 0 (fallthrough) branch 2 taken 1 #####: 448: fputs(_("Try 'mm, mime edit APPLICATION'\n"), stderr); %%%%%: 448-block 0 call 0 never executed call 1 never executed #####: 449: exit_status = EXIT_FAILURE; unconditional 0 never executed -: 450: } -: 451: -: 452: } else { #####: 453: char *cmd[] = {args[2], mime_file, NULL}; #####: 454: if (launch_execve(cmd, FOREGROUND, E_NOSTDERR) != EXIT_SUCCESS) %%%%%: 454-block 0 call 0 never executed branch 1 never executed branch 2 never executed #####: 455: exit_status = EXIT_FAILURE; %%%%%: 455-block 0 unconditional 0 never executed -: 456: } -: 457: 1: 458: return exit_status; 1: 458-block 0 unconditional 0 taken 1 -: 459:} -: 460: -: 461:/* Open a file according to the application associated to its MIME type -: 462: * or extension. It also accepts the 'info' and 'edit' arguments, the -: 463: * former providing MIME info about the corresponding file and the -: 464: * latter opening the MIME list file */ -: 465:int function mime_open called 41 returned 100% blocks executed 54% 41: 466:mime_open(char **args) -: 467:{ -: 468: /* Check arguments */ 41*: 469: if (!args[1] || (*args[1] == '-' && strcmp(args[1], "--help") == 0)) { 41: 469-block 0 branch 0 taken 41 (fallthrough) branch 1 taken 0 41: 469-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 41 %%%%%: 469-block 2 branch 4 never executed branch 5 never executed #####: 470: puts(_(MIME_USAGE)); %%%%%: 470-block 0 call 0 never executed call 1 never executed #####: 471: return EXIT_FAILURE; unconditional 0 never executed -: 472: } -: 473: 41: 474: if (args[1] && *args[1] == 'i' && strcmp(args[1], "import") == 0) { 41: 474-block 0 branch 0 taken 41 (fallthrough) branch 1 taken 0 41: 474-block 1 branch 2 taken 1 (fallthrough) branch 3 taken 40 1: 474-block 2 branch 4 taken 0 (fallthrough) branch 5 taken 1 #####: 475: time_t rawtime = time(NULL); %%%%%: 475-block 0 call 0 never executed -: 476: struct tm tm; #####: 477: localtime_r(&rawtime, &tm); call 0 never executed -: 478: char date[64]; #####: 479: strftime(date, sizeof(date), "%b %d %H:%M:%S %Y", &tm); -: 480: -: 481: char suffix[68]; #####: 482: snprintf(suffix, 67, "%d%d%d%d%d%d", tm.tm_year + 1900, #####: 483: tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, -: 484: tm.tm_sec); -: 485: -: 486: char new[PATH_MAX]; #####: 487: snprintf(new, PATH_MAX - 1, "%s.%s", mime_file, suffix); #####: 488: rename(mime_file, new); call 0 never executed -: 489: #####: 490: int mime_defs = mime_import(mime_file); call 0 never executed #####: 491: if (mime_defs > 0) { branch 0 never executed branch 1 never executed #####: 492: printf(_("%s: %d MIME definition(s) imported from the system. " %%%%%: 492-block 0 call 0 never executed call 1 never executed -: 493: "Old MIME list file stored as %s\n"), -: 494: PROGRAM_NAME, mime_defs, new); #####: 495: return EXIT_SUCCESS; unconditional 0 never executed -: 496: } else { #####: 497: rename(new, mime_file); %%%%%: 497-block 0 call 0 never executed #####: 498: return EXIT_FAILURE; unconditional 0 never executed -: 499: } -: 500: } -: 501: -: 502: /* Check the existence of the 'file' command. */ -: 503:/* char *file_path_tmp = (char *)NULL; -: 504: if ((file_path_tmp = get_cmd_path("file")) == NULL) { -: 505: fprintf(stderr, _("%s: file: Command not found\n"), PROGRAM_NAME); -: 506: return EXIT_FAILURE; -: 507: } -: 508: -: 509: free(file_path_tmp); -: 510: file_path_tmp = (char *)NULL; */ -: 511: 41: 512: char *file_path = (char *)NULL, 41: 513: *deq_file = (char *)NULL; 41: 514: int info = 0, 41: 515: file_index = 0; -: 516: 41: 517: if (*args[1] == 'e' && strcmp(args[1], "edit") == 0) { 41: 517-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 40 1: 517-block 1 branch 2 taken 1 (fallthrough) branch 3 taken 0 1: 518: return mime_edit(args); 1: 518-block 0 call 0 returned 1 unconditional 1 taken 1 -: 519: } -: 520: 40: 521: else if (*args[1] == 'i' && strcmp(args[1], "info") == 0) { 40: 521-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 39 1: 521-block 1 branch 2 taken 1 (fallthrough) branch 3 taken 0 1: 522: if (!args[2]) { 1: 522-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 1 #####: 523: fprintf(stderr, "%s\n", _(MIME_USAGE)); %%%%%: 523-block 0 call 0 never executed call 1 never executed #####: 524: return EXIT_FAILURE; unconditional 0 never executed -: 525: } -: 526: 1: 527: if (strchr(args[2], '\\')) { 1: 527-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 1 #####: 528: deq_file = dequote_str(args[2], 0); %%%%%: 528-block 0 call 0 never executed #####: 529: file_path = realpath(deq_file, NULL); call 0 never executed #####: 530: free(deq_file); #####: 531: deq_file = (char *)NULL; unconditional 0 never executed -: 532: } else { 1: 533: file_path = realpath(args[2], NULL); 1: 533-block 0 call 0 returned 1 unconditional 1 taken 1 -: 534: } -: 535: 1: 536: if (!file_path) { 1: 536-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 1 #####: 537: fprintf(stderr, "%s: %s: %s\n", PROGRAM_NAME, args[2], branch 0 never executed branch 1 never executed %%%%%: 537-block 0 call 2 never executed #####: 538: (is_number(args[2]) == 1) ? _("No such ELN") : strerror(errno)); %%%%%: 538-block 0 call 0 never executed %%%%%: 538-block 1 call 1 never executed unconditional 2 never executed %%%%%: 538-block 2 call 3 never executed unconditional 4 never executed #####: 539: return EXIT_FAILURE; unconditional 0 never executed -: 540: } -: 541: 1: 542: if (access(file_path, R_OK) == -1) { 1: 542-block 0 call 0 returned 1 branch 1 taken 0 (fallthrough) branch 2 taken 1 #####: 543: fprintf(stderr, "%s: %s: %s\n", PROGRAM_NAME, file_path, call 0 never executed #####: 544: strerror(errno)); %%%%%: 544-block 0 call 0 never executed #####: 545: free(file_path); #####: 546: return EXIT_FAILURE; unconditional 0 never executed -: 547: } -: 548: 1: 549: info = 1; 1: 550: file_index = 2; 1: 550-block 0 unconditional 0 taken 1 -: 551: } -: 552: -: 553: else { -: 554: /* Only dequote the file name if coming from the mime command */ 39: 555: if (*args[0] == 'm' && strchr(args[1], '\\')) { 39: 555-block 0 branch 0 taken 39 (fallthrough) branch 1 taken 0 39: 555-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 39 #####: 556: deq_file = dequote_str(args[1], 0); %%%%%: 556-block 0 call 0 never executed #####: 557: file_path = realpath(deq_file, NULL); call 0 never executed #####: 558: free(deq_file); #####: 559: deq_file = (char *)NULL; unconditional 0 never executed -: 560: } 39: 561: if (!file_path) 39: 561-block 0 branch 0 taken 39 (fallthrough) branch 1 taken 0 39: 562: file_path = realpath(args[1], NULL); 39: 562-block 0 call 0 returned 39 unconditional 1 taken 39 -: 563: 39: 564: if (!file_path) { 39: 564-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 39 #####: 565: fprintf(stderr, "%s: %s: %s\n", PROGRAM_NAME, args[1], call 0 never executed #####: 566: strerror(errno)); %%%%%: 566-block 0 call 0 never executed #####: 567: return -1; unconditional 0 never executed %%%%%: 567-block 0 unconditional 1 never executed -: 568: } -: 569: -: 570: struct stat a; 39: 571: if (lstat(file_path, &a) == 0 && (a.st_mode & S_IFMT) == S_IFDIR) { 39: 571-block 0 call 0 returned 39 branch 1 taken 39 (fallthrough) branch 2 taken 0 39: 571-block 1 branch 3 taken 0 (fallthrough) branch 4 taken 39 #####: 572: int _exit_status = cd_function(file_path, CD_PRINT_ERROR); %%%%%: 572-block 0 call 0 never executed #####: 573: free(file_path); #####: 574: return _exit_status; unconditional 0 never executed -: 575: } -: 576: 39: 577: if (access(file_path, R_OK) == -1) { 39: 577-block 0 call 0 returned 39 branch 1 taken 0 (fallthrough) branch 2 taken 39 #####: 578: fprintf(stderr, "%s: %s: %s\n", PROGRAM_NAME, file_path, call 0 never executed #####: 579: strerror(errno)); %%%%%: 579-block 0 call 0 never executed #####: 580: free(file_path); -: 581: /* Since this function is called by open_function, and since -: 582: * this latter prints an error message itself whenever the -: 583: * exit code of mime_open is EXIT_FAILURE, and since we -: 584: * don't want that message in this case, return -1 instead -: 585: * to prevent that message from being printed */ #####: 586: return -1; unconditional 0 never executed -: 587: } -: 588: 39: 589: file_index = 1; 39: 589-block 0 unconditional 0 taken 39 -: 590: } -: 591: 40: 592: if (!file_path) { 40: 592-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 40 #####: 593: fprintf(stderr, "%s: %s\n", args[file_index], strerror(errno)); %%%%%: 593-block 0 call 0 never executed call 1 never executed #####: 594: return EXIT_FAILURE; unconditional 0 never executed -: 595: } -: 596: -: 597: /* Get file's mime-type */ -: 598:#ifndef _NO_MAGIC 40: 599: char *mime = xmagic(file_path, MIME_TYPE); 40: 599-block 0 call 0 returned 40 -: 600:#else -: 601: char *mime = get_mime(file_path); -: 602:#endif 40: 603: if (!mime) { branch 0 taken 0 (fallthrough) branch 1 taken 40 #####: 604: fprintf(stderr, _("%s: Error getting mime-type\n"), PROGRAM_NAME); %%%%%: 604-block 0 call 0 never executed call 1 never executed #####: 605: free(file_path); #####: 606: return EXIT_FAILURE; unconditional 0 never executed -: 607: } -: 608: 40: 609: if (info) 40: 609-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 39 1: 610: printf(_("MIME type: %s\n"), mime); 1: 610-block 0 call 0 returned 1 call 1 returned 1 unconditional 2 taken 1 -: 611: -: 612: /* Get file extension, if any */ 40: 613: char *ext = (char *)NULL; 40: 614: char *filename = strrchr(file_path, '/'); 40: 615: if (filename) { 40: 615-block 0 branch 0 taken 40 (fallthrough) branch 1 taken 0 40: 616: filename++; /* Remove leading slash */ 40: 617: if (*filename == '.') 40: 617-block 0 branch 0 taken 5 (fallthrough) branch 1 taken 35 5: 618: filename++; /* Skip leading dot if hidden */ 5: 618-block 0 unconditional 0 taken 5 -: 619: 40: 620: char *ext_tmp = strrchr(filename, '.'); 40: 621: if (ext_tmp) { 40: 621-block 0 branch 0 taken 20 (fallthrough) branch 1 taken 20 20: 622: ext_tmp++; /* Remove dot from extension */ 20: 623: ext = savestring(ext_tmp, strlen(ext_tmp)); 20: 623-block 0 call 0 returned 20 20: 624: ext_tmp = (char *)NULL; unconditional 0 taken 20 -: 625: } -: 626: 40: 627: filename = (char *)NULL; 40: 627-block 0 unconditional 0 taken 40 -: 628: } -: 629: 40: 630: if (info) 40: 630-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 39 1*: 631: printf(_("Extension: %s\n"), ext ? ext : "None"); 1: 631-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 1 %%%%%: 631-block 1 unconditional 2 never executed 1: 631-block 2 unconditional 3 taken 1 1: 631-block 3 call 4 returned 1 call 5 returned 1 unconditional 6 taken 1 -: 632: -: 633: /* Get default application for MIME or extension */ 40: 634: char *app = get_app(mime, ext); 40: 634-block 0 call 0 returned 40 40: 635: if (!app) { branch 0 taken 0 (fallthrough) branch 1 taken 40 #####: 636: if (info) { %%%%%: 636-block 0 branch 0 never executed branch 1 never executed #####: 637: fputs(_("Associated application: None\n"), stderr); %%%%%: 637-block 0 call 0 never executed call 1 never executed unconditional 2 never executed -: 638: } else { -: 639:#ifndef _NO_ARCHIVING -: 640: /* If an archive/compressed file, run the archiver function */ #####: 641: if (is_compressed(file_path, 1) == 0) { %%%%%: 641-block 0 call 0 never executed branch 1 never executed branch 2 never executed #####: 642: char *tmp_cmd[] = {"ad", file_path, NULL}; #####: 643: int exit_status = archiver(tmp_cmd, 'd'); %%%%%: 643-block 0 call 0 never executed -: 644: #####: 645: free(file_path); #####: 646: free(mime); -: 647: #####: 648: if (ext) branch 0 never executed branch 1 never executed #####: 649: free(ext); %%%%%: 649-block 0 unconditional 0 never executed -: 650: #####: 651: return exit_status; %%%%%: 651-block 0 unconditional 0 never executed -: 652: } else { #####: 653: fprintf(stderr, _("%s: %s: No associated application " call 0 never executed unconditional 1 never executed #####: 654: "found\n"), PROGRAM_NAME, args[1]); %%%%%: 654-block 0 call 0 never executed -: 655: } -: 656:#else -: 657: fprintf(stderr, _("%s: %s: No associated application " -: 658: "found\n"), PROGRAM_NAME, args[1]); -: 659:#endif -: 660: } -: 661: #####: 662: free(file_path); #####: 663: free(mime); -: 664: #####: 665: if (ext) %%%%%: 665-block 0 branch 0 never executed branch 1 never executed #####: 666: free(ext); %%%%%: 666-block 0 unconditional 0 never executed -: 667: #####: 668: return EXIT_FAILURE; %%%%%: 668-block 0 unconditional 0 never executed -: 669: } -: 670: 40: 671: if (info) { 40: 671-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 39 -: 672: /* In case of "cmd args" print only cmd */ 1: 673: char *ret = strchr(app, ' '); 1: 674: if (ret) 1: 674-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 1 #####: 675: *ret = '\0'; %%%%%: 675-block 0 unconditional 0 never executed -: 676: 1*: 677: printf(_("Associated application: %s (%s)\n"), app, 1: 677-block 0 unconditional 0 taken 1 %%%%%: 677-block 1 unconditional 1 never executed 1: 677-block 2 call 2 returned 1 call 3 returned 1 1: 678: mime_match ? "MIME" : "ext"); 1: 678-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 0 -: 679: 1: 680: free(file_path); 1: 681: free(mime); 1: 682: free(app); -: 683: 1: 684: if (ext) branch 0 taken 0 (fallthrough) branch 1 taken 1 #####: 685: free(ext); %%%%%: 685-block 0 unconditional 0 never executed -: 686: 1: 687: return EXIT_SUCCESS; 1: 687-block 0 unconditional 0 taken 1 -: 688: } -: 689: 39: 690: free(mime); -: 691: 39: 692: if (ext) 39: 692-block 0 branch 0 taken 20 (fallthrough) branch 1 taken 19 20: 693: free(ext); 20: 693-block 0 unconditional 0 taken 20 -: 694: -: 695: /* If not info, open the file with the associated application */ -: 696: -: 697: /* Get number of arguments to check for final ampersand */ 39: 698: int args_num = 0; 117: 699: for (args_num = 0; args[args_num]; args_num++); 39: 699-block 0 unconditional 0 taken 39 78: 699-block 1 unconditional 1 taken 78 117: 699-block 2 branch 2 taken 78 branch 3 taken 39 (fallthrough) -: 700: -: 701: /* Construct the command and run it */ -: 702: -: 703: /* Two pointers to store different positions in the APP string */ 39: 704: char *p = app; 39: 705: char *pp = app; -: 706: -: 707: /* The number of spaces in APP is (at least) the number of paramenters -: 708: * passed to the command. Extra spaces will be ignored */ 39: 709: size_t spaces = 0; 312: 710: while (*p) { 39: 710-block 0 unconditional 0 taken 39 312: 710-block 1 branch 1 taken 273 branch 2 taken 39 (fallthrough) 273: 711: if (*(p++) == ' ') 273: 711-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 273 #####: 712: spaces++; %%%%%: 712-block 0 unconditional 0 never executed -: 713: } -: 714: -: 715: /* To the number of spaces/parametes we need to add the command itself, -: 716: * the file name and the final NULL string (spaces + 3) */ 39: 717: char **cmd = (char **)xnmalloc(spaces + 3, sizeof(char *)); 39: 717-block 0 call 0 returned 39 -: 718: -: 719: /* Rewind P to the beginning of APP */ 39: 720: p = pp; -: 721: -: 722: /* Store each substring in APP into a two dimensional array (CMD) */ 39: 723: int pos = 0; unconditional 0 taken 39 -: 724: while (1) { 312: 725: if (!*p) { 312: 725-block 0 branch 0 taken 39 (fallthrough) branch 1 taken 273 39: 726: if (*pp) 39: 726-block 0 branch 0 taken 39 (fallthrough) branch 1 taken 0 39: 727: cmd[pos++] = savestring(pp, strlen(pp)); 39: 727-block 0 call 0 returned 39 unconditional 1 taken 39 39: 728: break; 39: 728-block 0 unconditional 0 taken 39 -: 729: } -: 730: 273: 731: if (*p == ' ') { 273: 731-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 273 #####: 732: *p = '\0'; #####: 733: if (*pp) %%%%%: 733-block 0 branch 0 never executed branch 1 never executed #####: 734: cmd[pos++] = savestring(pp, strlen(pp)); %%%%%: 734-block 0 call 0 never executed unconditional 1 never executed #####: 735: pp = ++p; %%%%%: 735-block 0 unconditional 0 never executed -: 736: } else { 273: 737: p++; 273: 737-block 0 unconditional 0 taken 273 -: 738: } -: 739: } -: 740: -: 741: /* If %f placeholder is found, replace it by FILE_PATH. Else, append -: 742: * FILE_PATH to the end of CMD */ 39: 743: int i = pos, 39: 744: found = 0; 78: 745: while (--i >= 0) { 39: 745-block 0 unconditional 0 taken 39 78: 745-block 1 branch 1 taken 39 branch 2 taken 39 (fallthrough) 39*: 746: if (*cmd[i] == '%' && *(cmd[i] + 1) == 'f') { 39: 746-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 39 %%%%%: 746-block 1 branch 2 never executed branch 3 never executed #####: 747: found = 1; #####: 748: break; %%%%%: 748-block 0 unconditional 0 never executed -: 749: } -: 750: } -: 751: 39: 752: if (found) { 39: 752-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 39 #####: 753: cmd[i] = (char *)xrealloc(cmd[i], (strlen(file_path) + 1) * sizeof(char)); %%%%%: 753-block 0 call 0 never executed #####: 754: strcpy(cmd[i], file_path); unconditional 0 never executed -: 755: } else { 39: 756: cmd[pos++] = savestring(file_path, strlen(file_path)); 39: 756-block 0 call 0 returned 39 unconditional 1 taken 39 -: 757: } -: 758: 39: 759: cmd[pos] = (char *)NULL; -: 760: 39: 761: int ret = launch_execve(cmd, bg_proc ? BACKGROUND : FOREGROUND, E_NOSTDERR); 39: 761-block 0 call 0 returned 39 -: 762: 39: 763: free(file_path); 39: 764: free(app); -: 765: 39: 766: i = pos; 117: 767: while (--i >= 0) unconditional 0 taken 39 117: 767-block 0 branch 1 taken 78 branch 2 taken 39 (fallthrough) 78: 768: free(cmd[i]); 78: 768-block 0 unconditional 0 taken 78 39: 769: free(cmd); 39: 770: return ret; 39: 770-block 0 unconditional 0 taken 39 -: 771:} -: 772:#endif /* !_NO_LIRA */ clifm-1.26.3/misc/codecov/misc.c.gcov000066400000000000000000003676661506632037700173470ustar00rootroot00000000000000 -: 0:Source:misc.c -: 1:/* misc.c -- functions that do not fit in any other file */ -: 2: -: 3:/* -: 4: * This file is part of CliFM -: 5: * -: 6: * Copyright (C) 2016-2021, L. Abramovich -: 7: * All rights reserved. -: 8: -: 9: * CliFM is free software; you can redistribute it and/or modify -: 10: * it under the terms of the GNU General Public License as published by -: 11: * the Free Software Foundation; either version 2 of the License, or -: 12: * (at your option) any later version. -: 13: * -: 14: * CliFM is distributed in the hope that it will be useful, -: 15: * but WITHOUT ANY WARRANTY; without even the implied warranty of -: 16: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -: 17: * GNU General Public License for more details. -: 18: * -: 19: * You should have received a copy of the GNU General Public License -: 20: * along with this program; if not, write to the Free Software -: 21: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, -: 22: * MA 02110-1301, USA. -: 23:*/ -: 24: -: 25:#include "helpers.h" -: 26: -: 27:#include -: 28:#include -: 29:#include -: 30:#include -: 31:#include -: 32:#include -: 33:#include -: 34:#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) -: 35:#include -: 36:#include -: 37:#endif -: 38:/* -: 39:#if defined(__HAIKU__) -: 40:#include -: 41:#include -: 42:#endif */ -: 43:#include -: 44:#include -: 45:#include -: 46:#ifdef LINUX_INOTIFY -: 47:#include -: 48:#endif -: 49: -: 50:#include "aux.h" -: 51:#include "bookmarks.h" -: 52:#include "checks.h" -: 53:#include "exec.h" -: 54:#include "history.h" -: 55:#include "init.h" -: 56:#include "jump.h" -: 57:#include "listing.h" -: 58:#include "navigation.h" -: 59:#include "readline.h" -: 60:#include "strings.h" -: 61:#include "remotes.h" -: 62:#include "messages.h" -: 63: -: 64:#ifdef LINUX_INOTIFY -: 65:void function read_inotify called 48 returned 100% blocks executed 93% 48: 66:read_inotify(void) -: 67:{ -: 68: int i; -: 69: struct inotify_event *event; -: 70: char inotify_buf[EVENT_BUF_LEN]; -: 71: 48: 72: memset((void *)inotify_buf, '\0', EVENT_BUF_LEN); 48: 73: i = (int)read(inotify_fd, inotify_buf, EVENT_BUF_LEN); 48: 73-block 0 call 0 returned 48 -: 74: 48: 75: if (i <= 0) branch 0 taken 3 (fallthrough) branch 1 taken 45 3: 76: return; 3: 76-block 0 unconditional 0 taken 3 -: 77: 45: 78: int ignore_event = 0, refresh = 0; 45: 79: for (char *ptr = inotify_buf; 45: 79-block 0 unconditional 0 taken 45 409: 80: ptr + ((struct inotify_event *)ptr)->len < inotify_buf + i; 409: 80-block 0 branch 0 taken 364 branch 1 taken 45 (fallthrough) 364: 81: ptr += sizeof(struct inotify_event) + event->len) { 364: 81-block 0 unconditional 0 taken 364 364: 82: event = (struct inotify_event *)ptr; 364: 83: if (!event->wd) 364: 83-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 364 #####: 84: break; %%%%%: 84-block 0 unconditional 0 never executed -: 85: 364: 86: if (event->mask & IN_CREATE) { 364: 86-block 0 branch 0 taken 25 (fallthrough) branch 1 taken 339 -: 87:/* puts("IN_CREATE"); */ -: 88: struct stat a; 25: 89: if (stat(event->name, &a) != 0) 25: 89-block 0 call 0 returned 25 branch 1 taken 5 (fallthrough) branch 2 taken 20 -: 90: /* The file was created, but doesn't exist anymore */ 5: 91: ignore_event = 1; 5: 91-block 0 unconditional 0 taken 5 -: 92: } 364: 93: if (event->mask & IN_DELETE) { 364: 93-block 0 branch 0 taken 17 (fallthrough) branch 1 taken 347 -: 94:/* puts("IN_DELETE"); */ -: 95: struct stat a; 17: 96: if (stat(event->name, &a) == 0) 17: 96-block 0 call 0 returned 17 branch 1 taken 0 (fallthrough) branch 2 taken 17 -: 97: /* The file was removed, but is still there */ #####: 98: ignore_event = 1; %%%%%: 98-block 0 unconditional 0 never executed -: 99: } -: 100:/* if (event->mask & IN_DELETE_SELF) -: 101: puts("IN_DELETE_SELF"); -: 102: if (event->mask & IN_MOVE_SELF) -: 103: puts("IN_MOVE_SELF"); -: 104: if (event->mask & IN_MOVED_FROM) -: 105: puts("IN_MOVED_FROM"); -: 106: if (event->mask & IN_MOVED_TO) -: 107: puts("IN_MOVED_TO"); -: 108: if (event->mask & IN_IGNORED) { -: 109: puts("IN_IGNORED"); -: 110: } */ -: 111: 364: 112: if (!ignore_event && (event->mask & INOTIFY_MASK)) 364: 112-block 0 branch 0 taken 342 (fallthrough) branch 1 taken 22 342: 112-block 1 branch 2 taken 57 (fallthrough) branch 3 taken 285 57: 113: refresh = 1; 57: 113-block 0 unconditional 0 taken 57 -: 114: } -: 115: 45: 116: if (refresh) { 45: 116-block 0 branch 0 taken 26 (fallthrough) branch 1 taken 19 26: 117: free_dirlist(); 26: 117-block 0 call 0 returned 26 26: 118: list_dir(); call 0 returned 26 unconditional 1 taken 26 -: 119: } -: 120: 45: 121: return; 45: 121-block 0 unconditional 0 taken 45 -: 122:} -: 123:#elif defined(BSD_KQUEUE) -: 124:void -: 125:read_kqueue(void) -: 126:{ -: 127: struct kevent event_data[NUM_EVENT_SLOTS]; -: 128: memset((void *)event_data, '\0', sizeof(struct kevent) -: 129: * NUM_EVENT_SLOTS); -: 130: int i, refresh = 0; -: 131: -: 132: int count = kevent(kq, NULL, 0, event_data, 4096, &timeout); -: 133: -: 134: for (i = 0; i < count; i++) { -: 135:/* if (event_data[i].fflags & NOTE_DELETE) -: 136: puts("NOTE_DELETE"); -: 137: if (event_data[i].fflags & NOTE_WRITE) -: 138: puts("NOTE_WRITE"); -: 139: if (event_data[i].fflags & NOTE_EXTEND) -: 140: puts("NOTE_EXTEND"); -: 141: if (event_data[i].fflags & NOTE_ATTRIB) -: 142: puts("NOTE_ATTRIB"); -: 143: if (event_data[i].fflags & NOTE_LINK) -: 144: puts("NOTE_LINK"); -: 145: if (event_data[i].fflags & NOTE_RENAME) -: 146: puts("NOTE_RENAME"); -: 147: if (event_data[i].fflags & NOTE_REVOKE) -: 148: puts("NOTE_REVOKE"); */ -: 149: -: 150: if (event_data[i].fflags & KQUEUE_FFLAGS) { -: 151: refresh = 1; -: 152: break; -: 153: } -: 154: } -: 155: -: 156: if (refresh) { -: 157: free_dirlist(); -: 158: if (list_dir() != EXIT_SUCCESS) -: 159: exit_code = EXIT_FAILURE; -: 160: return; -: 161: } -: 162: -: 163: if (event_fd >= 0) { -: 164: close(event_fd); -: 165: event_fd = -1; -: 166: watch = 0; -: 167: } -: 168:} -: 169:#endif -: 170: -: 171:void function set_term_title called 613 returned 100% blocks executed 89% 613: 172:set_term_title(const char *str) -: 173:{ 613: 174: char *tmp = (char *)NULL; 613: 175: tmp = home_tilde(str); 613: 175-block 0 call 0 returned 613 -: 176: 613*: 177: printf("\033]2;%s - %s\007", PROGRAM_NAME, tmp ? tmp : str); branch 0 taken 613 (fallthrough) branch 1 taken 0 613: 177-block 0 unconditional 2 taken 613 %%%%%: 177-block 1 unconditional 3 never executed 613: 177-block 2 call 4 returned 613 613: 178: fflush(stdout); call 0 returned 613 -: 179: 613: 180: if (tmp) branch 0 taken 613 (fallthrough) branch 1 taken 0 613: 181: free(tmp); 613: 181-block 0 unconditional 0 taken 613 613: 182:} -: 183: -: 184:int function filter_function called 7 returned 100% blocks executed 85% 7: 185:filter_function(const char *arg) -: 186:{ 7: 187: if (!arg) { 7: 187-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 5 2*: 188: printf(_("Current filter: %c%s\n"), filter_rev ? '!' : 0, 1: 188-block 0 unconditional 0 taken 1 1: 188-block 1 unconditional 1 taken 1 2: 188-block 2 branch 2 taken 0 (fallthrough) branch 3 taken 2 %%%%%: 188-block 3 unconditional 4 never executed 2: 188-block 4 unconditional 5 taken 2 2: 188-block 5 call 6 returned 2 call 7 returned 2 2: 189: filter ? filter : "none"); 2: 189-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 1 2: 190: return EXIT_SUCCESS; unconditional 0 taken 2 -: 191: } -: 192: 5: 193: if (*arg == '-' && strcmp(arg, "--help") == 0) { 5: 193-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 4 1: 193-block 1 branch 2 taken 1 (fallthrough) branch 3 taken 0 1: 194: puts(_(FILTER_USAGE)); 1: 194-block 0 call 0 returned 1 call 1 returned 1 1: 195: return EXIT_SUCCESS; unconditional 0 taken 1 -: 196: } -: 197: 4: 198: if (*arg == 'u' && strcmp(arg, "unset") == 0) { 4: 198-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 3 1: 198-block 1 branch 2 taken 1 (fallthrough) branch 3 taken 0 1: 199: if (filter) { 1: 199-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 0 1: 200: free(filter); 1: 201: filter = (char *)NULL; 1: 202: regfree(®ex_exp); 1: 202-block 0 call 0 returned 1 1: 203: puts(_("Filter unset")); call 0 returned 1 call 1 returned 1 1: 204: filter_rev = 0; unconditional 0 taken 1 -: 205: } else { #####: 206: puts(_("No filter set")); %%%%%: 206-block 0 call 0 never executed call 1 never executed unconditional 2 never executed -: 207: } -: 208: 1: 209: return EXIT_SUCCESS; 1: 209-block 0 unconditional 0 taken 1 -: 210: } -: 211: 3: 212: if (filter) 3: 212-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 1 2: 213: free(filter); 2: 213-block 0 unconditional 0 taken 2 -: 214: 3: 215: regfree(®ex_exp); 3: 215-block 0 call 0 returned 3 -: 216: 3: 217: if (*arg == '!') { branch 0 taken 1 (fallthrough) branch 1 taken 2 1: 218: filter_rev = 1; 1: 219: arg++; 1: 219-block 0 unconditional 0 taken 1 -: 220: } else { 2: 221: filter_rev = 0; 2: 221-block 0 unconditional 0 taken 2 -: 222: } -: 223: 3: 224: filter = savestring(arg, strlen(arg)); 3: 224-block 0 call 0 returned 3 -: 225: 3: 226: if (regcomp(®ex_exp, filter, REG_NOSUB | REG_EXTENDED) != EXIT_SUCCESS) { call 0 returned 3 branch 1 taken 0 (fallthrough) branch 2 taken 3 #####: 227: fprintf(stderr, _("%s: '%s': Invalid regular expression\n"), %%%%%: 227-block 0 call 0 never executed call 1 never executed -: 228: PROGRAM_NAME, filter); #####: 229: free(filter); #####: 230: filter = (char *)NULL; #####: 231: regfree(®ex_exp); call 0 never executed unconditional 1 never executed -: 232: } else { 3: 233: puts(_("New filter successfully set")); 3: 233-block 0 call 0 returned 3 call 1 returned 3 unconditional 2 taken 3 -: 234: } -: 235: 3: 236: return EXIT_SUCCESS; 3: 236-block 0 unconditional 0 taken 3 -: 237:} -: 238: -: 239:/* Print either all tips (if ALL == 1) or just a random one (ALL == 0) */ -: 240:void function print_tips called 5 returned 100% blocks executed 100% 5: 241:print_tips(int all) -: 242:{ 5: 243: const char *TIPS[] = { -: 244: "Try the autocd and auto-open functions: run 'FILE' instead " -: 245: "of 'open FILE' or 'cd FILE'", -: 246: "Add a new entry to the mimelist file with 'mm edit' or F6", -: 247: "Do not forget to take a look at the manpage", -: 248: "Need more speed? Try the light mode (Alt-y)", -: 249: "The Selection Box is shared among different instances of CliFM", -: 250: "Select files here and there with the 's' command", -: 251: "Use wildcards and regular expressions with the 's' command: " -: 252: "'s *.c' or 's .*\\.c$'", -: 253: "ELN's and the 'sel' keyword work for shell commands as well: " -: 254: "'file 1 sel'", -: 255: "Press TAB to automatically expand an ELN: 's 2' -> TAB -> " -: 256: "'s FILENAME'", -: 257: "Easily copy everything in CWD into another directory: 's * " -: 258: "&& c sel ELN/DIR'", -: 259: "Use ranges (ELN-ELN) to easily move multiple files: 'm 3-12 " -: 260: "ELN/DIR'", -: 261: "Trash files with a simple 't ELN'", -: 262: "Get mime information for a file: 'mm info ELN'", -: 263: "If too many files are listed, try enabling the pager ('pg on')", -: 264: "Once in the pager, go backwards pressing the keyboard shortcut " -: 265: "provided by your terminal emulator", -: 266: "Once in the pager, press 'q' to stop it", -: 267: "Press 'Alt-l' to switch to long view mode", -: 268: "Search for files using the slash command: '/*.png'", -: 269: "The search function allows regular expressions: '/^c'", -: 270: "Add a new bookmark by just entering 'bm a ELN/FILE'", -: 271: "Use c, l, m, md, and r instead of cp, ln, mv, mkdir, and rm", -: 272: "Access a remote file system using the 'net' command", -: 273: "Manage default associated applications with the 'mime' command", -: 274: "Go back and forth in the directory history with 'Alt-j' and 'Alt-k' " -: 275: "or Shift-Left and Shift-Right", -: 276: "Open a new instance of CliFM with the 'x' command: 'x ELN/DIR'", -: 277: "Send a command directly to the system shell with ';CMD'", -: 278: "Run the last executed command by just running '!!'", -: 279: "Import aliases from file using 'alias import FILE'", -: 280: "List available aliases by running 'alias'", -: 281: "Create aliases to easily run your preferred commands", -: 282: "Open and edit the configuration file with 'edit'", -: 283: "Find a description for each CliFM command by running 'cmd'", -: 284: "Print the currently used color codes list by entering 'cc'", -: 285: "Press 'Alt-i' or 'Alt-.' to toggle hidden files on/off", -: 286: "List mountpoints by pressing 'Alt-m'", -: 287: "Disallow the use of shell commands with the -x option: 'clifm -x'", -: 288: "Go to the root directory by just pressing 'Alt-r'", -: 289: "Go to the home directory by just pressing 'Alt-e'", -: 290: "Press 'F8' to open and edit current color scheme", -: 291: "Press 'F9' to open and edit the keybindings file", -: 292: "Press 'F10' to open and edit the configuration file", -: 293: "Press 'F11' to open and edit the bookmarks file", -: 294: "Set the starting path: 'clifm PATH'", -: 295: "Use the 'o' command to open files and directories: '12'", -: 296: "Bypass the resource opener specifying an application: '12 " -: 297: "leafpad'", -: 298: "Open a file and send it to the background running '24&'", -: 299: "Create a custom prompt editing the configuration file", -: 300: "Customize color codes via 'cs edit' command (F6)", -: 301: "Open the bookmarks manager by just pressing 'Alt-b'", -: 302: "Chain commands using ; and &&: 's 2 7-10; r sel'", -: 303: "Add emojis to the prompt by copying them to the Prompt line " -: 304: "in the configuration file", -: 305: "Create a new profile running 'pf add PROFILE' or 'clifm -P " -: 306: "PROFILE'", -: 307: "Switch profiles using 'pf set PROFILE'", -: 308: "Delete a profile using 'pf del PROFILE'", -: 309: "Copy selected files into CWD by just running 'v sel' or " -: 310: "pressing Ctrl-Alt-v", -: 311: "Use 'p ELN' to print file properties for ELN", -: 312: "Deselect all selected files by pressing 'Alt-d'", -: 313: "Select all files in CWD by pressing 'Alt-a'", -: 314: "Jump to the Selection Box by pressing 'Alt-s'", -: 315: "Restore trashed files using the 'u' command", -: 316: "Empty the trash bin running 't clear'", -: 317: "Press Alt-f to toggle list-folders-first on/off", -: 318: "Use the 'fc' command to disable the files counter", -: 319: "Take a look at the splash screen with the 'splash' command", -: 320: "Have some fun trying the 'bonus' command", -: 321: "Launch the default system shell in CWD using ':' or ';'", -: 322: "Use 'Alt-z' and 'Alt-x' to switch sorting methods", -: 323: "Reverse sorting order using the 'rev' option: 'st rev'", -: 324: "Compress and decompress files using the 'ac' and 'ad' " -: 325: "commands respectivelly", -: 326: "Rename multiple files at once with the bulk rename function: " -: 327: "'br *.txt'", -: 328: "Need no more tips? Disable this feature in the configuration " -: 329: "file", -: 330: "Need root privileges? Launch a new instance of CLifM as root " -: 331: "running the 'X' command", -: 332: "Create custom commands and features using the 'actions' command", -: 333: "Create a fresh configuration file by running 'edit gen'", -: 334: "Use 'ln edit' (or 'le') to edit symbolic links", -: 335: "Change default keyboard shortcuts by editing the keybindings file (F9)", -: 336: "Keep in sight previous and next visited directories enabling the " -: 337: "DirhistMap option in the configuration file", -: 338: "Leave no traces at all running in stealth mode (-S)", -: 339: "Pin a file via the 'pin' command and then use it with the " -: 340: "period keyword (,). Ex: 'pin DIR' and then 'cd ,'", -: 341: "Switch between color schemes using the 'cs' command", -: 342: "Try the 'j' command to quickly navigate through visited " -: 343: "directories", -: 344: "Switch workspaces by pressing Alt-[1-4]", -: 345: "Use the 'ws' command to list available workspaces", -: 346: "Take a look at available plugins using the 'actions' command", -: 347: "Space is not needed: enter 'p12' instead of 'p 12'", -: 348: "When searching or selecting files, use the exclamation mark " -: 349: "to reverse the meaning of a pattern", -: 350: "Enable the TrashAsRm option to prevent accidental deletions", -: 351: "Don't like ELN's? Disable them using the -e option", -: 352: "Use the 'n' command to create multiple files and/or directories", -: 353: "Customize your prompt by adding prompt commands via the 'edit' " -: 354: "command (F10)", -: 355: "Need git integration? Consult the manpage", -: 356: "Accept a given suggestion by pressing the Right arrow key", -: 357: "Accept only the first suggested word by pressing Alt-f or Alt-Right", -: 358: "Enter 'c sel' to copy selected files into the current directory", -: 359: "Take a look at available plugins via the 'actions' command", -: 360: NULL}; -: 361: 5: 362: size_t tipsn = (sizeof(TIPS) / sizeof(TIPS[0])) - 1; -: 363: 5: 364: if (all) { 5: 364-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 4 -: 365: size_t i; 96: 366: for (i = 0; i < tipsn; i++) 1: 366-block 0 unconditional 0 taken 1 unconditional 1 taken 95 96: 366-block 1 branch 2 taken 95 branch 3 taken 1 (fallthrough) 95: 367: printf("%sTIP %zu%s: %s\n", BOLD, i, df_c, TIPS[i]); 95: 367-block 0 call 0 returned 95 -: 368: 1: 369: return; 1: 369-block 0 unconditional 0 taken 1 -: 370: } -: 371: 4: 372: srand((unsigned int)time(NULL)); 4: 372-block 0 call 0 returned 4 call 1 returned 4 4: 373: printf("%sTIP%s: %s\n", BOLD, df_c, TIPS[rand() % (int)tipsn]); call 0 returned 4 call 1 returned 4 -: 374:} -: 375: -: 376:/* Open DIR in a new instance of the program (using TERM, set in the config -: 377: * file, as terminal emulator) */ -: 378:int function new_instance called 3 returned 100% blocks executed 60% 3: 379:new_instance(char *dir, int sudo) -: 380:{ -: 381:#if defined(__HAIKU__) -: 382: UNUSED(dir); UNUSED(sudo); -: 383: fprintf(stderr, _("%s: This function is not available on Haiku\n"), -: 384: PROGRAM_NAME); -: 385: return EXIT_FAILURE; -: 386:#elif defined(__OpenBSD__) -: 387: UNUSED(dir); UNUSED(sudo); -: 388: fprintf(stderr, _("%s: This function is not available on OpenBSD\n"), -: 389: PROGRAM_NAME); -: 390: return EXIT_FAILURE; -: 391:#else 3: 392: if (!term) { 3: 392-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 3 #####: 393: fprintf(stderr, _("%s: Default terminal not set. Use the " %%%%%: 393-block 0 call 0 never executed call 1 never executed -: 394: "configuration file to set one\n"), PROGRAM_NAME); #####: 395: return EXIT_FAILURE; unconditional 0 never executed -: 396: } -: 397: 3: 398: if (!(flags & GUI)) { 3: 398-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 3 #####: 399: fprintf(stderr, _("%s: Function only available for graphical " %%%%%: 399-block 0 call 0 never executed call 1 never executed -: 400: "environments\n"), PROGRAM_NAME); #####: 401: return EXIT_FAILURE; unconditional 0 never executed -: 402: } -: 403: -: 404: /* Get absolute path of executable name of itself */ -: 405:#if defined(__linux__) 3: 406: char *self = realpath("/proc/self/exe", NULL); 3: 406-block 0 call 0 returned 3 -: 407: 3: 408: if (!self) { branch 0 taken 0 (fallthrough) branch 1 taken 3 -: 409:#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) -: 410: const int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 }; -: 411: char *self = malloc(PATH_MAX); -: 412: size_t len = PATH_MAX; -: 413: -: 414: if (!self || sysctl(mib, 4, self, &len, NULL, 0) == -1) { -: 415:#endif #####: 416: fprintf(stderr, "%s: %s\n", PROGRAM_NAME, strerror(errno)); %%%%%: 416-block 0 call 0 never executed call 1 never executed #####: 417: return EXIT_FAILURE; unconditional 0 never executed -: 418: } -: 419: 3: 420: if (!dir) { 3: 420-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 3 #####: 421: free(self); #####: 422: return EXIT_FAILURE; %%%%%: 422-block 0 unconditional 0 never executed -: 423: } -: 424: 3: 425: char *_sudo = (char *)NULL; 3: 426: if (sudo) { 3: 426-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 2 1: 427: _sudo = get_sudo_path(); 1: 427-block 0 call 0 returned 1 1: 428: if (!_sudo) { branch 0 taken 0 (fallthrough) branch 1 taken 1 #####: 429: free(self); #####: 430: return EXIT_FAILURE; %%%%%: 430-block 0 unconditional 0 never executed -: 431: } -: 432: } -: 433: 3: 434: char *deq_dir = dequote_str(dir, 0); 3: 434-block 0 call 0 returned 3 -: 435: 3: 436: if (!deq_dir) { branch 0 taken 0 (fallthrough) branch 1 taken 3 #####: 437: fprintf(stderr, _("%s: %s: Error dequoting file name\n"), %%%%%: 437-block 0 call 0 never executed call 1 never executed -: 438: PROGRAM_NAME, dir); #####: 439: free(self); #####: 440: return EXIT_FAILURE; unconditional 0 never executed -: 441: } -: 442: -: 443: struct stat file_attrib; -: 444: 3: 445: if (stat(deq_dir, &file_attrib) == -1) { 3: 445-block 0 call 0 returned 3 branch 1 taken 0 (fallthrough) branch 2 taken 3 #####: 446: fprintf(stderr, "%s: %s: %s\n", PROGRAM_NAME, deq_dir, call 0 never executed #####: 447: strerror(errno)); %%%%%: 447-block 0 call 0 never executed #####: 448: free(self); #####: 449: free(deq_dir); #####: 450: return EXIT_FAILURE; unconditional 0 never executed -: 451: } -: 452: 3: 453: if ((file_attrib.st_mode & S_IFMT) != S_IFDIR) { 3: 453-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 3 #####: 454: fprintf(stderr, _("%s: %s: Not a directory\n"), PROGRAM_NAME, deq_dir); %%%%%: 454-block 0 call 0 never executed call 1 never executed #####: 455: free(self); #####: 456: free(deq_dir); #####: 457: return EXIT_FAILURE; unconditional 0 never executed -: 458: } -: 459: 3: 460: char *path_dir = (char *)NULL; -: 461: 3: 462: if (*deq_dir != '/') { 3: 462-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 3 #####: 463: path_dir = (char *)xnmalloc(strlen(ws[cur_ws].path) #####: 464: + strlen(deq_dir) + 2, sizeof(char)); %%%%%: 464-block 0 call 0 never executed #####: 465: sprintf(path_dir, "%s/%s", ws[cur_ws].path, deq_dir); #####: 466: free(deq_dir); unconditional 0 never executed -: 467: } else { 3: 468: path_dir = deq_dir; 3: 468-block 0 unconditional 0 taken 3 -: 469: } -: 470: 3: 471: char **tmp_term = (char **)NULL, 3: 472: **tmp_cmd = (char **)NULL; -: 473: 3: 474: if (strcntchr(term, ' ') != -1) { 3: 474-block 0 call 0 returned 3 branch 1 taken 3 (fallthrough) branch 2 taken 0 3: 475: tmp_term = get_substr(term, ' '); 3: 475-block 0 call 0 returned 3 -: 476: 3: 477: if (tmp_term) { branch 0 taken 3 (fallthrough) branch 1 taken 0 -: 478: int i; 9: 479: for (i = 0; tmp_term[i]; i++); 3: 479-block 0 unconditional 0 taken 3 6: 479-block 1 unconditional 1 taken 6 9: 479-block 2 branch 2 taken 6 branch 3 taken 3 (fallthrough) -: 480: 3: 481: int num = i; 3: 482: tmp_cmd = (char **)xrealloc(tmp_cmd, ((size_t)i + (sudo ? 4 : 3)) 3: 482-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 2 1: 482-block 1 unconditional 2 taken 1 2: 482-block 2 unconditional 3 taken 2 3: 482-block 3 call 4 returned 3 -: 483: * sizeof(char *)); 9: 484: for (i = 0; tmp_term[i]; i++) { unconditional 0 taken 3 9: 484-block 0 branch 1 taken 6 branch 2 taken 3 (fallthrough) 6: 485: tmp_cmd[i] = savestring(tmp_term[i], strlen(tmp_term[i])); 6: 485-block 0 call 0 returned 6 6: 486: free(tmp_term[i]); unconditional 0 taken 6 -: 487: } 3: 488: free(tmp_term); -: 489: 3: 490: i = num - 1; 3: 491: int plus = 1; -: 492: 3: 493: if (sudo) { 3: 493-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 2 1: 494: tmp_cmd[i + plus] = (char *)xnmalloc(strlen(self) + 1, 1: 494-block 0 call 0 returned 1 -: 495: sizeof(char)); 1: 496: strcpy(tmp_cmd[i + plus], _sudo); 1: 497: plus++; unconditional 0 taken 1 -: 498: } -: 499: 3: 500: tmp_cmd[i + plus] = (char *)xnmalloc(strlen(self) + 1, sizeof(char)); 3: 500-block 0 call 0 returned 3 3: 501: strcpy(tmp_cmd[i + plus++], self); 3: 502: tmp_cmd[i + plus] = (char *)xnmalloc(strlen(path_dir) + 1, sizeof(char)); call 0 returned 3 3: 503: strcpy(tmp_cmd[i + plus++], path_dir); 3: 504: tmp_cmd[i + plus] = (char *)NULL; unconditional 0 taken 3 -: 505: } -: 506: } -: 507: 3: 508: int ret = -1; -: 509: 3: 510: if (tmp_cmd) { 3: 510-block 0 branch 0 taken 3 (fallthrough) branch 1 taken 0 3: 511: ret = launch_execve(tmp_cmd, BACKGROUND, E_NOFLAG); 3: 511-block 0 call 0 returned 3 -: 512: size_t i; 16: 513: for (i = 0; tmp_cmd[i]; i++) unconditional 0 taken 3 16: 513-block 0 branch 1 taken 13 branch 2 taken 3 (fallthrough) 13: 514: free(tmp_cmd[i]); 13: 514-block 0 unconditional 0 taken 13 3: 515: free(tmp_cmd); 3: 515-block 0 unconditional 0 taken 3 -: 516: } else { #####: 517: fprintf(stderr, _("%s: No option specified for '%s'\n" call 0 never executed -: 518: "Trying '%s -e %s %s'\n"), PROGRAM_NAME, term, #####: 519: term, self, ws[cur_ws].path); %%%%%: 519-block 0 call 0 never executed #####: 520: if (sudo) { branch 0 never executed branch 1 never executed #####: 521: char *cmd[] = {term, "-e", _sudo, self, path_dir, NULL}; #####: 522: ret = launch_execve(cmd, BACKGROUND, E_NOFLAG); %%%%%: 522-block 0 call 0 never executed -: 523: } else { #####: 524: char *cmd[] = {term, "-e", self, path_dir, NULL}; #####: 525: ret = launch_execve(cmd, BACKGROUND, E_NOFLAG); %%%%%: 525-block 0 call 0 never executed -: 526: } -: 527: } -: 528: 3: 529: free(_sudo); 3: 530: free(path_dir); 3: 531: free(self); -: 532: 3: 533: if (ret != EXIT_SUCCESS) 3: 533-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 3 #####: 534: fprintf(stderr, _("%s: Error lauching new instance\n"), PROGRAM_NAME); %%%%%: 534-block 0 call 0 never executed call 1 never executed unconditional 2 never executed -: 535: 3: 536: return ret; 3: 536-block 0 unconditional 0 taken 3 -: 537:#endif /* !__HAIKU__ */ -: 538:// cppcheck-suppress syntaxError -: 539:} -: 540: -: 541:int function alias_import called 0 returned 0% blocks executed 0% #####: 542:alias_import(char *file) -: 543:{ #####: 544: if (xargs.stealth_mode == 1) { %%%%%: 544-block 0 branch 0 never executed branch 1 never executed #####: 545: printf("%s: The alias function is disabled in stealth mode\n", %%%%%: 545-block 0 call 0 never executed -: 546: PROGRAM_NAME); #####: 547: return EXIT_SUCCESS; unconditional 0 never executed -: 548: } -: 549: #####: 550: if (!file) %%%%%: 550-block 0 branch 0 never executed branch 1 never executed #####: 551: return EXIT_FAILURE; %%%%%: 551-block 0 unconditional 0 never executed -: 552: #####: 553: char rfile[PATH_MAX] = ""; #####: 554: rfile[0] = '\0'; -: 555: -: 556: /* if (*file == '~' && *(file + 1) == '/') { */ -: 557: #####: 558: if (*file == '~') { %%%%%: 558-block 0 branch 0 never executed branch 1 never executed #####: 559: char *file_exp = tilde_expand(file); %%%%%: 559-block 0 call 0 never executed #####: 560: if (!file_exp) { branch 0 never executed branch 1 never executed #####: 561: fprintf(stderr, "%s: %s: %s\n", PROGRAM_NAME, file, strerror(errno)); %%%%%: 561-block 0 call 0 never executed call 1 never executed #####: 562: return EXIT_FAILURE; unconditional 0 never executed -: 563: } -: 564: #####: 565: if (realpath(file_exp, rfile) == NULL) { %%%%%: 565-block 0 call 0 never executed branch 1 never executed branch 2 never executed #####: 566: fprintf(stderr, "%s: %s: %s\n", PROGRAM_NAME, file_exp, call 0 never executed #####: 567: strerror(errno)); %%%%%: 567-block 0 call 0 never executed #####: 568: free(file_exp); #####: 569: return EXIT_FAILURE; unconditional 0 never executed -: 570: } #####: 571: free(file_exp); %%%%%: 571-block 0 unconditional 0 never executed -: 572: } else { #####: 573: if (realpath(file, rfile) == NULL) { %%%%%: 573-block 0 call 0 never executed branch 1 never executed branch 2 never executed #####: 574: fprintf(stderr, "%s: %s: %s\n", PROGRAM_NAME, file, strerror(errno)); %%%%%: 574-block 0 call 0 never executed call 1 never executed #####: 575: return EXIT_FAILURE; unconditional 0 never executed -: 576: } -: 577: } -: 578: #####: 579: if (rfile[0] == '\0') { %%%%%: 579-block 0 branch 0 never executed branch 1 never executed #####: 580: fprintf(stderr, "%s: %s: %s\n", PROGRAM_NAME, file, strerror(errno)); %%%%%: 580-block 0 call 0 never executed call 1 never executed #####: 581: return EXIT_FAILURE; unconditional 0 never executed -: 582: } -: 583: -: 584: /* Open the file to import aliases from */ -: 585: int fd; #####: 586: FILE *fp = open_fstream_r(rfile, &fd); %%%%%: 586-block 0 call 0 never executed #####: 587: if (!fp) { branch 0 never executed branch 1 never executed #####: 588: fprintf(stderr, "b%s: '%s': %s\n", PROGRAM_NAME, rfile, strerror(errno)); %%%%%: 588-block 0 call 0 never executed call 1 never executed #####: 589: return EXIT_FAILURE; unconditional 0 never executed -: 590: } -: 591: -: 592: /* Open CliFM's config file as well */ #####: 593: FILE *config_fp = fopen(config_file, "a"); %%%%%: 593-block 0 call 0 never executed #####: 594: if (!config_fp) { branch 0 never executed branch 1 never executed #####: 595: fprintf(stderr, "%s: %s: %s\n", PROGRAM_NAME, config_file, call 0 never executed #####: 596: strerror(errno)); %%%%%: 596-block 0 call 0 never executed #####: 597: close_fstream(fp, fd); call 0 never executed #####: 598: return EXIT_FAILURE; unconditional 0 never executed -: 599: } -: 600: #####: 601: size_t line_size = 0, i; #####: 602: char *line = (char *)NULL; #####: 603: size_t alias_found = 0, alias_imported = 0; #####: 604: int first = 1; -: 605: #####: 606: while (getline(&line, &line_size, fp) > 0) { %%%%%: 606-block 0 unconditional 0 never executed %%%%%: 606-block 1 call 1 never executed branch 2 never executed branch 3 never executed #####: 607: if (*line == 'a' && strncmp(line, "alias ", 6) == 0) { %%%%%: 607-block 0 branch 0 never executed branch 1 never executed %%%%%: 607-block 1 branch 2 never executed branch 3 never executed #####: 608: alias_found++; -: 609: -: 610: /* If alias name conflicts with some internal command, -: 611: * skip it */ #####: 612: char *alias_name = strbtw(line, ' ', '='); %%%%%: 612-block 0 call 0 never executed #####: 613: if (!alias_name) branch 0 never executed branch 1 never executed #####: 614: continue; %%%%%: 614-block 0 unconditional 0 never executed -: 615: #####: 616: if (is_internal_c(alias_name)) { %%%%%: 616-block 0 call 0 never executed branch 1 never executed branch 2 never executed #####: 617: fprintf(stderr, _("%s: Alias conflicts with " %%%%%: 617-block 0 call 0 never executed call 1 never executed -: 618: "internal command\n"), alias_name); #####: 619: free(alias_name); #####: 620: continue; unconditional 0 never executed -: 621: } -: 622: #####: 623: char *p = line + 6; /* p points now to the beginning of the -: 624: alias name (because "alias " == 6) */ -: 625: -: 626: /* Only accept single quoted aliases commands */ #####: 627: char *tmp = strchr(p, '='); #####: 628: if (!tmp) %%%%%: 628-block 0 branch 0 never executed branch 1 never executed #####: 629: continue; %%%%%: 629-block 0 unconditional 0 never executed #####: 630: if (*(++tmp) != '\'') { %%%%%: 630-block 0 branch 0 never executed branch 1 never executed #####: 631: free(alias_name); #####: 632: continue; %%%%%: 632-block 0 unconditional 0 never executed -: 633: } -: 634: -: 635: /* If alias already exists, skip it too */ #####: 636: int exists = 0; -: 637: #####: 638: for (i = 0; i < aliases_n; i++) { %%%%%: 638-block 0 unconditional 0 never executed %%%%%: 638-block 1 unconditional 1 never executed %%%%%: 638-block 2 branch 2 never executed branch 3 never executed #####: 639: int alias_len = strcntchr(aliases[i], '='); %%%%%: 639-block 0 call 0 never executed #####: 640: if (alias_len != -1 && strncmp(aliases[i], p, branch 0 never executed branch 1 never executed #####: 641: (size_t)alias_len + 1) == 0) { %%%%%: 641-block 0 branch 0 never executed branch 1 never executed #####: 642: exists = 1; #####: 643: break; %%%%%: 643-block 0 unconditional 0 never executed -: 644: } -: 645: } -: 646: #####: 647: if (!exists) { %%%%%: 647-block 0 branch 0 never executed branch 1 never executed #####: 648: if (first) { %%%%%: 648-block 0 branch 0 never executed branch 1 never executed #####: 649: first = 0; #####: 650: fputs("\n\n", config_fp); %%%%%: 650-block 0 call 0 never executed unconditional 1 never executed -: 651: } -: 652: #####: 653: alias_imported++; -: 654: -: 655: /* Write the new alias into CLiFM config file */ #####: 656: fputs(line, config_fp); %%%%%: 656-block 0 call 0 never executed unconditional 1 never executed -: 657: } else { #####: 658: fprintf(stderr, _("%s: Alias already exists\n"), %%%%%: 658-block 0 call 0 never executed call 1 never executed unconditional 2 never executed -: 659: alias_name); -: 660: } -: 661: #####: 662: free(alias_name); %%%%%: 662-block 0 unconditional 0 never executed -: 663: } -: 664: } -: 665: #####: 666: free(line); #####: 667: close_fstream(fp, fd); %%%%%: 667-block 0 call 0 never executed #####: 668: fclose(config_fp); call 0 never executed -: 669: -: 670: /* No alias was found in FILE */ #####: 671: if (alias_found == 0) { branch 0 never executed branch 1 never executed #####: 672: fprintf(stderr, _("%s: %s: No alias found\n"), PROGRAM_NAME, %%%%%: 672-block 0 call 0 never executed call 1 never executed -: 673: rfile); #####: 674: return EXIT_FAILURE; unconditional 0 never executed -: 675: } -: 676: -: 677: /* Aliases were found in FILE, but none was imported (either because -: 678: * they conflicted with internal commands or the alias already -: 679: * existed) */ #####: 680: else if (alias_imported == 0) { %%%%%: 680-block 0 branch 0 never executed branch 1 never executed #####: 681: fprintf(stderr, _("%s: No alias imported\n"), PROGRAM_NAME); %%%%%: 681-block 0 call 0 never executed call 1 never executed #####: 682: return EXIT_FAILURE; unconditional 0 never executed -: 683: } -: 684: -: 685: /* If some alias was found and imported, print the corresponding -: 686: * message and update the aliases array */ #####: 687: if (alias_imported > 1) { %%%%%: 687-block 0 branch 0 never executed branch 1 never executed #####: 688: printf(_("%s: %zu aliases were successfully imported\n"), %%%%%: 688-block 0 call 0 never executed call 1 never executed unconditional 2 never executed -: 689: PROGRAM_NAME, alias_imported); -: 690: } else { #####: 691: printf(_("%s: 1 alias was successfully imported\n"), PROGRAM_NAME); %%%%%: 691-block 0 call 0 never executed call 1 never executed unconditional 2 never executed -: 692: } -: 693: -: 694: /* Add new aliases to the internal list of aliases */ #####: 695: get_aliases(); %%%%%: 695-block 0 call 0 never executed -: 696: -: 697: /* Add new aliases to the commands list for TAB completion */ #####: 698: if (bin_commands) { branch 0 never executed branch 1 never executed #####: 699: for (i = 0; bin_commands[i]; i++) %%%%%: 699-block 0 unconditional 0 never executed %%%%%: 699-block 1 branch 1 never executed branch 2 never executed #####: 700: free(bin_commands[i]); %%%%%: 700-block 0 unconditional 0 never executed #####: 701: free(bin_commands); #####: 702: bin_commands = (char **)NULL; %%%%%: 702-block 0 unconditional 0 never executed -: 703: } -: 704: #####: 705: get_path_programs(); %%%%%: 705-block 0 call 0 never executed #####: 706: return EXIT_SUCCESS; unconditional 0 never executed -: 707:} -: 708: -: 709:/* Store last visited directory for the restore last path and the -: 710: * cd on quit functions */ -: 711:void function save_last_path called 8 returned 100% blocks executed 76% 8: 712:save_last_path(void) -: 713:{ 8: 714: if (!config_ok || !config_dir) 8: 714-block 0 branch 0 taken 8 (fallthrough) branch 1 taken 0 8: 714-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 8 #####: 715: return; %%%%%: 715-block 0 unconditional 0 never executed -: 716: 8: 717: char *last_dir = (char *)xnmalloc(strlen(config_dir) + 7, sizeof(char)); 8: 717-block 0 call 0 returned 8 8: 718: sprintf(last_dir, "%s/.last", config_dir); -: 719: -: 720: FILE *last_fp; 8: 721: last_fp = fopen(last_dir, "w"); call 0 returned 8 8: 722: if (!last_fp) { branch 0 taken 0 (fallthrough) branch 1 taken 8 #####: 723: fprintf(stderr, _("%s: Error saving last visited " %%%%%: 723-block 0 call 0 never executed call 1 never executed -: 724: "directory\n"), -: 725: PROGRAM_NAME); #####: 726: free(last_dir); #####: 727: return; unconditional 0 never executed -: 728: } -: 729: -: 730: size_t i; 72: 731: for (i = 0; i < MAX_WS; i++) { 8: 731-block 0 unconditional 0 taken 8 64: 731-block 1 unconditional 1 taken 64 72: 731-block 2 branch 2 taken 64 branch 3 taken 8 (fallthrough) 64: 732: if (ws[i].path) { 64: 732-block 0 branch 0 taken 29 (fallthrough) branch 1 taken 35 -: 733: /* Mark current workspace with an asterisk. It will -: 734: * be read at startup by get_last_path */ 29: 735: if ((size_t)cur_ws == i) 29: 735-block 0 branch 0 taken 8 (fallthrough) branch 1 taken 21 8: 736: fprintf(last_fp, "*%zu:%s\n", i, ws[i].path); 8: 736-block 0 call 0 returned 8 unconditional 1 taken 8 -: 737: else 21: 738: fprintf(last_fp, "%zu:%s\n", i, ws[i].path); 21: 738-block 0 call 0 returned 21 unconditional 1 taken 21 -: 739: } -: 740: } -: 741: 8: 742: fclose(last_fp); 8: 742-block 0 call 0 returned 8 -: 743: 8: 744: char *last_dir_tmp = xnmalloc(strlen(config_dir_gral) + 7, sizeof(char *)); call 0 returned 8 8: 745: sprintf(last_dir_tmp, "%s/.last", config_dir_gral); -: 746: 8: 747: if (cd_on_quit) { branch 0 taken 0 (fallthrough) branch 1 taken 8 #####: 748: char *cmd[] = {"cp", "-p", last_dir, last_dir_tmp, -: 749: NULL}; -: 750: #####: 751: launch_execve(cmd, FOREGROUND, E_NOFLAG); %%%%%: 751-block 0 call 0 never executed -: 752: } else { -: 753: /* If not cd on quit, remove the file */ 8: 754: char *cmd[] = {"rm", "-f", last_dir_tmp, NULL}; 8: 755: launch_execve(cmd, FOREGROUND, E_NOFLAG); 8: 755-block 0 call 0 returned 8 -: 756: } -: 757: 8: 758: free(last_dir_tmp); 8: 759: free(last_dir); 8: 760: return; 8: 760-block 0 unconditional 0 taken 8 -: 761:} -: 762: -: 763:char * function parse_usrvar_value called 0 returned 0% blocks executed 0% #####: 764:parse_usrvar_value(const char *str, const char c) -: 765:{ #####: 766: if (c == '\0' || !str) %%%%%: 766-block 0 branch 0 never executed branch 1 never executed %%%%%: 766-block 1 branch 2 never executed branch 3 never executed #####: 767: return (char *)NULL; %%%%%: 767-block 0 unconditional 0 never executed -: 768: -: 769: /* Get whatever comes after c */ #####: 770: char *tmp = (char *)NULL; #####: 771: tmp = strchr(str, c); -: 772: -: 773: /* If no C or there's nothing after C */ #####: 774: if (!tmp || !*(++tmp)) %%%%%: 774-block 0 branch 0 never executed branch 1 never executed %%%%%: 774-block 1 branch 2 never executed branch 3 never executed #####: 775: return (char *)NULL; %%%%%: 775-block 0 unconditional 0 never executed -: 776: -: 777: /* Remove leading quotes */ #####: 778: if (*tmp == '"' || *tmp == '\'') %%%%%: 778-block 0 branch 0 never executed branch 1 never executed %%%%%: 778-block 1 branch 2 never executed branch 3 never executed #####: 779: tmp++; %%%%%: 779-block 0 unconditional 0 never executed -: 780: -: 781: /* Remove trailing spaces, tabs, new line chars, and quotes */ #####: 782: size_t tmp_len = strlen(tmp), -: 783: i; -: 784: #####: 785: for (i = tmp_len - 1; tmp[i] && i > 0; i--) { %%%%%: 785-block 0 unconditional 0 never executed %%%%%: 785-block 1 branch 1 never executed branch 2 never executed %%%%%: 785-block 2 branch 3 never executed branch 4 never executed #####: 786: if (tmp[i] != ' ' && tmp[i] != '\t' && tmp[i] != '"' && tmp[i] != '\'' %%%%%: 786-block 0 branch 0 never executed branch 1 never executed %%%%%: 786-block 1 branch 2 never executed branch 3 never executed %%%%%: 786-block 2 branch 4 never executed branch 5 never executed %%%%%: 786-block 3 branch 6 never executed branch 7 never executed #####: 787: && tmp[i] != '\n') %%%%%: 787-block 0 branch 0 never executed branch 1 never executed -: 788: break; -: 789: else #####: 790: tmp[i] = '\0'; %%%%%: 790-block 0 unconditional 0 never executed -: 791: } -: 792: #####: 793: if (!*tmp) %%%%%: 793-block 0 branch 0 never executed branch 1 never executed #####: 794: return (char *)NULL; %%%%%: 794-block 0 unconditional 0 never executed -: 795: -: 796: /* Copy the result string into a buffer and return it */ #####: 797: char *buf = (char *)NULL; #####: 798: buf = savestring(tmp, strlen(tmp)); %%%%%: 798-block 0 call 0 never executed #####: 799: tmp = (char *)NULL; -: 800: #####: 801: if (buf) branch 0 never executed branch 1 never executed #####: 802: return buf; %%%%%: 802-block 0 unconditional 0 never executed #####: 803: return (char *)NULL; %%%%%: 803-block 0 unconditional 0 never executed -: 804:} -: 805: -: 806:int function create_usr_var called 0 returned 0% blocks executed 0% #####: 807:create_usr_var(char *str) -: 808:{ #####: 809: char *name = strbfr(str, '='); %%%%%: 809-block 0 call 0 never executed #####: 810: char *value = parse_usrvar_value(str, '='); call 0 never executed -: 811: #####: 812: if (!name) { branch 0 never executed branch 1 never executed #####: 813: if (value) %%%%%: 813-block 0 branch 0 never executed branch 1 never executed #####: 814: free(value); %%%%%: 814-block 0 unconditional 0 never executed #####: 815: fprintf(stderr, _("%s: Error getting variable name\n"), %%%%%: 815-block 0 call 0 never executed call 1 never executed -: 816: PROGRAM_NAME); #####: 817: return EXIT_FAILURE; unconditional 0 never executed -: 818: } -: 819: #####: 820: if (!value) { %%%%%: 820-block 0 branch 0 never executed branch 1 never executed #####: 821: free(name); #####: 822: fprintf(stderr, _("%s: Error getting variable value\n"), %%%%%: 822-block 0 call 0 never executed call 1 never executed -: 823: PROGRAM_NAME); #####: 824: return EXIT_FAILURE; unconditional 0 never executed -: 825: } -: 826: #####: 827: usr_var = xrealloc(usr_var, (size_t)(usrvar_n + 1) * sizeof(struct usrvar_t)); %%%%%: 827-block 0 call 0 never executed #####: 828: usr_var[usrvar_n].name = savestring(name, strlen(name)); call 0 never executed #####: 829: usr_var[usrvar_n++].value = savestring(value, strlen(value)); call 0 never executed -: 830: #####: 831: free(name); #####: 832: free(value); #####: 833: return EXIT_SUCCESS; unconditional 0 never executed -: 834:} -: 835: -: 836:/* Custom POSIX implementation of GNU asprintf() modified to log program -: 837: * messages. MSG_TYPE is one of: 'e', 'w', 'n', or zero (meaning this -: 838: * latter that no message mark (E, W, or N) will be added to the prompt). -: 839: * PROMPT tells whether to print the message immediately before the -: 840: * prompt or rather in place. Based on littlstar's xasprintf -: 841: * implementation: -: 842: * https://github.com/littlstar/asprintf.c/blob/master/asprintf.c*/ -: 843:__attribute__((__format__(__printf__, 3, 0))) -: 844:/* We use __attribute__ here to silence clang warning: "format string is -: 845: * not a string literal" */ -: 846:int function _err called 3 returned 100% blocks executed 72% 3: 847:_err(int msg_type, int prompt, const char *format, ...) -: 848:{ -: 849: va_list arglist, tmp_list; 3: 850: int size = 0; -: 851: 3: 852: va_start(arglist, format); 3: 853: va_copy(tmp_list, arglist); 3: 854: size = vsnprintf((char *)NULL, 0, format, tmp_list); 3: 855: va_end(tmp_list); -: 856: 3: 857: if (size < 0) { 3: 857-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 3 #####: 858: va_end(arglist); #####: 859: return EXIT_FAILURE; %%%%%: 859-block 0 unconditional 0 never executed -: 860: } -: 861: 3: 862: char *buf = (char *)xcalloc((size_t)size + 1, sizeof(char)); 3: 862-block 0 call 0 returned 3 -: 863: 3: 864: vsprintf(buf, format, arglist); 3: 865: va_end(arglist); -: 866: -: 867: /* If the new message is the same as the last message, skip it */ 3: 868: if (msgs_n && strcmp(messages[msgs_n - 1], buf) == 0) { branch 0 taken 1 (fallthrough) branch 1 taken 2 1: 868-block 0 branch 2 taken 0 (fallthrough) branch 3 taken 1 #####: 869: free(buf); #####: 870: return EXIT_SUCCESS; %%%%%: 870-block 0 unconditional 0 never executed -: 871: } -: 872: 3: 873: if (buf) { 3: 873-block 0 branch 0 taken 3 (fallthrough) branch 1 taken 0 3: 874: if (msg_type) { 3: 874-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 1 2: 875: switch (msg_type) { 2: 875-block 0 branch 0 taken 0 branch 1 taken 1 branch 2 taken 1 branch 3 taken 0 #####: 876: case 'e': pmsg = ERROR; break; %%%%%: 876-block 0 unconditional 0 never executed 1: 877: case 'w': pmsg = WARNING; break; 1: 877-block 0 unconditional 0 taken 1 1: 878: case 'n': pmsg = NOTICE; break; 1: 878-block 0 unconditional 0 taken 1 #####: 879: default: pmsg = NOMSG; %%%%%: 879-block 0 unconditional 0 never executed -: 880: } -: 881: } -: 882: 3: 883: log_msg(buf, (prompt) ? PRINT_PROMPT : NOPRINT_PROMPT); 3: 883-block 0 call 0 returned 3 3: 884: free(buf); 3: 885: return EXIT_SUCCESS; unconditional 0 taken 3 -: 886: } -: 887: #####: 888: return EXIT_FAILURE; %%%%%: 888-block 0 unconditional 0 never executed -: 889:} -: 890: -: 891:/* Set STR as the program current shell */ -: 892:int function set_shell called 2 returned 100% blocks executed 70% 2: 893:set_shell(char *str) -: 894:{ 2: 895: if (!str || !*str) 2: 895-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 0 2: 895-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 2 #####: 896: return EXIT_FAILURE; %%%%%: 896-block 0 unconditional 0 never executed -: 897: -: 898: /* IF no slash in STR, check PATH env variable for a file named STR -: 899: * and get its full path*/ 2: 900: char *full_path = (char *)NULL; -: 901: 2: 902: if (strcntchr(str, '/') == -1) 2: 902-block 0 call 0 returned 2 branch 1 taken 0 (fallthrough) branch 2 taken 2 #####: 903: full_path = get_cmd_path(str); %%%%%: 903-block 0 call 0 never executed unconditional 1 never executed -: 904: 2: 905: char *tmp = (char *)NULL; -: 906: 2: 907: if (full_path) 2: 907-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 2 #####: 908: tmp = full_path; %%%%%: 908-block 0 unconditional 0 never executed -: 909: else 2: 910: tmp = str; 2: 910-block 0 unconditional 0 taken 2 -: 911: 2: 912: if (access(tmp, X_OK) == -1) { 2: 912-block 0 call 0 returned 2 branch 1 taken 0 (fallthrough) branch 2 taken 2 #####: 913: fprintf(stderr, "%s: %s: %s\n", PROGRAM_NAME, tmp, strerror(errno)); %%%%%: 913-block 0 call 0 never executed call 1 never executed #####: 914: return EXIT_FAILURE; unconditional 0 never executed -: 915: } -: 916: 2: 917: if (user.shell) 2: 917-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 0 2: 918: free(user.shell); 2: 918-block 0 unconditional 0 taken 2 -: 919: 2: 920: user.shell = savestring(tmp, strlen(tmp)); 2: 920-block 0 call 0 returned 2 2: 921: printf(_("Successfully set '%s' as %s default shell\n"), user.shell, call 0 returned 2 call 1 returned 2 -: 922: PROGRAM_NAME); -: 923: 2: 924: if (full_path) branch 0 taken 0 (fallthrough) branch 1 taken 2 #####: 925: free(full_path); %%%%%: 925-block 0 unconditional 0 never executed 2: 926: return EXIT_SUCCESS; 2: 926-block 0 unconditional 0 taken 2 -: 927:} -: 928: -: 929:/* List available mountpoints and chdir into one of them */ -: 930:int function list_mountpoints called 1 returned 100% blocks executed 77% 1: 931:list_mountpoints(void) -: 932:{ -: 933:#if defined(__HAIKU__) -: 934: fprintf(stderr, "%s: Mountpoints: This feature is not available on Haiku\n", -: 935: PROGRAM_NAME); -: 936: return EXIT_FAILURE; -: 937:#endif -: 938: -: 939:#if defined(__linux__) 1: 940: FILE *mp_fp = fopen("/proc/mounts", "r"); 1: 940-block 0 call 0 returned 1 1: 941: if (!mp_fp) { branch 0 taken 0 (fallthrough) branch 1 taken 1 #####: 942: fprintf(stderr, "%s: mp: fopen: /proc/mounts: %s\n", call 0 never executed #####: 943: PROGRAM_NAME, strerror(errno)); %%%%%: 943-block 0 call 0 never executed #####: 944: return EXIT_FAILURE; unconditional 0 never executed -: 945: } -: 946:#endif -: 947: 1: 948: printf(_("%sMountpoints%s\n\n"), BOLD, df_c); 1: 948-block 0 call 0 returned 1 call 1 returned 1 -: 949: 1: 950: char **mountpoints = (char **)NULL; 1: 951: size_t mp_n = 0; 1: 952: int i, exit_status = EXIT_SUCCESS; -: 953: -: 954:#if defined(__linux__) 1: 955: size_t line_size = 0; 1: 956: char *line = (char *)NULL; -: 957: 37: 958: while (getline(&line, &line_size, mp_fp) > 0) { unconditional 0 taken 1 37: 958-block 0 call 1 returned 37 branch 2 taken 36 branch 3 taken 1 (fallthrough) -: 959: /* Do not list all mountpoints, but only those corresponding -: 960: * to a block device (/dev) */ 36: 961: if (strncmp(line, "/dev/", 5) == 0) { 36: 961-block 0 branch 0 taken 5 (fallthrough) branch 1 taken 31 5: 962: char *str = (char *)NULL; 5: 963: size_t counter = 0; -: 964: -: 965: /* use strtok() to split LINE into tokens using space as -: 966: * IFS */ 5: 967: str = strtok(line, " "); 5: 967-block 0 call 0 returned 5 5: 968: size_t dev_len = strlen(str); -: 969: 5: 970: char *device = savestring(str, dev_len); call 0 returned 5 -: 971: /* Print only the first two fileds of each /proc/mounts -: 972: * line */ 15: 973: while (str && counter < 2) { unconditional 0 taken 5 15: 973-block 0 branch 1 taken 15 (fallthrough) branch 2 taken 0 15: 973-block 1 branch 3 taken 10 branch 4 taken 5 (fallthrough) 10: 974: if (counter == 1) { /* 1 == second field */ 10: 974-block 0 branch 0 taken 5 (fallthrough) branch 1 taken 5 5*: 975: printf("%s%zu%s %s%s%s (%s)\n", el_c, mp_n + 1, branch 0 taken 5 (fallthrough) branch 1 taken 0 5: 975-block 0 unconditional 2 taken 5 %%%%%: 975-block 1 unconditional 3 never executed 5: 975-block 2 call 4 returned 5 5: 976: df_c, (access(str, R_OK | X_OK) == 0) ? di_c : nd_c, 5: 976-block 0 call 0 returned 5 -: 977: str, df_c, device); -: 978: /* Store the second field (mountpoint) into an -: 979: * array */ 5: 980: mountpoints = (char **)xrealloc(mountpoints, 5: 981: (mp_n + 1) * sizeof(char *)); call 0 returned 5 5: 982: mountpoints[mp_n++] = savestring(str, strlen(str)); call 0 returned 5 unconditional 1 taken 5 -: 983: } -: 984: 10: 985: str = strtok(NULL, " ,"); 10: 985-block 0 call 0 returned 10 10: 986: counter++; unconditional 0 taken 10 -: 987: } -: 988: 5: 989: free(device); 5: 989-block 0 unconditional 0 taken 5 -: 990: } -: 991: } -: 992: 1: 993: free(line); 1: 994: line = (char *)NULL; 1: 995: fclose(mp_fp); 1: 995-block 0 call 0 returned 1 -: 996: -: 997:#elif defined(__FreeBSD__) || defined(__OpenBSD__) -: 998: struct statfs *fslist; -: 999: mp_n = (size_t)getmntinfo(&fslist, MNT_NOWAIT); -: 1000:#elif defined(__NetBSD__) -: 1001: struct statvfs *fslist; -: 1002: mp_n = (size_t)getmntinfo(&fslist, MNT_NOWAIT); -: 1003:#endif -: 1004: -: 1005: /* This should never happen: There should always be a mountpoint, -: 1006: * at least "/" */ -: 1007: // cppcheck-suppress knownConditionTrueFalse 1: 1008: if (mp_n == 0) { branch 0 taken 0 (fallthrough) branch 1 taken 1 #####: 1009: fputs(_("mp: There are no available mountpoints\n"), stdout); %%%%%: 1009-block 0 call 0 never executed call 1 never executed #####: 1010: return EXIT_SUCCESS; unconditional 0 never executed -: 1011: } -: 1012:#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) -: 1013: int j; -: 1014: for (i = j = 0; i < (int)mp_n; i++) { -: 1015: /* Do not list all mountpoints, but only those corresponding -: 1016: * to a block device (/dev) */ -: 1017: if (strncmp(fslist[i].f_mntfromname, "/dev/", 5) == 0) { -: 1018: printf("%s%d%s %s%s%s (%s)\n", el_c, j + 1, df_c, -: 1019: (access(fslist[i].f_mntonname, R_OK | X_OK) == 0) -: 1020: ? di_c : nd_c, fslist[i].f_mntonname, -: 1021: df_c, fslist[i].f_mntfromname); -: 1022: /* Store the mountpoint into an array */ -: 1023: mountpoints = (char **)xrealloc(mountpoints, -: 1024: (size_t)(j + 1) * sizeof(char *)); -: 1025: mountpoints[j++] = savestring(fslist[i].f_mntonname, -: 1026: strlen(fslist[i].f_mntonname)); -: 1027: } -: 1028: } -: 1029: /* Update filesystem counter as it would be used to free() the -: 1030: * mountpoints entries later (below) */ -: 1031: mp_n = (size_t)j; -: 1032:#endif -: 1033: 1: 1034: putchar('\n'); 1: 1034-block 0 call 0 returned 1 -: 1035: /* Ask the user and chdir into the selected mountpoint */ 1: 1036: char *input = (char *)NULL; 2: 1037: while (!input) unconditional 0 taken 1 2: 1037-block 0 branch 1 taken 1 branch 2 taken 1 (fallthrough) 1: 1038: input = rl_no_hist(_("Choose a mountpoint ('q' to quit): ")); 1: 1038-block 0 call 0 returned 1 call 1 returned 1 unconditional 2 taken 1 -: 1039: 1*: 1040: if (!(*input == 'q' && *(input + 1) == '\0')) { 1: 1040-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 1 %%%%%: 1040-block 1 branch 2 never executed branch 3 never executed 1: 1041: int atoi_num = atoi(input); 1: 1042: if (atoi_num > 0 && atoi_num <= (int)mp_n) { 1: 1042-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 0 1: 1042-block 1 branch 2 taken 1 (fallthrough) branch 3 taken 0 1: 1043: if (xchdir(mountpoints[atoi_num - 1], SET_TITLE) == EXIT_SUCCESS) { 1: 1043-block 0 call 0 returned 1 branch 1 taken 1 (fallthrough) branch 2 taken 0 1: 1044: free(ws[cur_ws].path); 2: 1045: ws[cur_ws].path = savestring(mountpoints[atoi_num - 1], 1: 1046: strlen(mountpoints[atoi_num - 1])); 1: 1046-block 0 call 0 returned 1 -: 1047: 1: 1048: if (cd_lists_on_the_fly) { branch 0 taken 1 (fallthrough) branch 1 taken 0 1: 1049: free_dirlist(); 1: 1049-block 0 call 0 returned 1 1: 1050: if (list_dir() != EXIT_SUCCESS) call 0 returned 1 branch 1 taken 0 (fallthrough) branch 2 taken 1 #####: 1051: exit_status = EXIT_FAILURE; %%%%%: 1051-block 0 unconditional 0 never executed -: 1052: } -: 1053: 1: 1054: add_to_dirhist(ws[cur_ws].path); 1: 1054-block 0 call 0 returned 1 1: 1055: add_to_jumpdb(ws[cur_ws].path); call 0 returned 1 unconditional 1 taken 1 -: 1056: } else { #####: 1057: fprintf(stderr, "%s: %s: %s\n", PROGRAM_NAME, #####: 1058: mountpoints[atoi_num - 1], strerror(errno)); %%%%%: 1058-block 0 call 0 never executed call 1 never executed #####: 1059: exit_status = EXIT_FAILURE; unconditional 0 never executed -: 1060: } -: 1061: } else { #####: 1062: fprintf(stderr, "%s: %s: %s\n", PROGRAM_NAME, #####: 1063: mountpoints[atoi_num - 1], strerror(errno)); %%%%%: 1063-block 0 call 0 never executed call 1 never executed #####: 1064: exit_status = EXIT_FAILURE; unconditional 0 never executed -: 1065: } -: 1066: } -: 1067: -: 1068: /* Free stuff and exit */ 1: 1069: free(input); -: 1070: 1: 1071: i = (int)mp_n; 6: 1072: while (--i >= 0) 1: 1072-block 0 unconditional 0 taken 1 6: 1072-block 1 branch 1 taken 5 branch 2 taken 1 (fallthrough) 5: 1073: free(mountpoints[i]); 5: 1073-block 0 unconditional 0 taken 5 1: 1074: free(mountpoints); -: 1075: 1: 1076: return exit_status; 1: 1076-block 0 unconditional 0 taken 1 -: 1077:} -: 1078: -: 1079:/* Store pinned directory for the next session */ -: 1080:void function save_pinned_dir called 4 returned 100% blocks executed 83% 4: 1081:save_pinned_dir(void) -: 1082:{ 4: 1083: if (pinned_dir && config_ok) { 4: 1083-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 3 1: 1083-block 1 branch 2 taken 1 (fallthrough) branch 3 taken 0 -: 1084: 1: 1085: char *pin_file = (char *)xnmalloc(strlen(config_dir) + 7, 1: 1085-block 0 call 0 returned 1 -: 1086: sizeof(char)); 1: 1087: sprintf(pin_file, "%s/.pin", config_dir); -: 1088: 1: 1089: FILE *fp = fopen(pin_file, "w"); call 0 returned 1 1: 1090: if (!fp) { branch 0 taken 0 (fallthrough) branch 1 taken 1 #####: 1091: fprintf(stderr, _("%s: Error storing pinned " %%%%%: 1091-block 0 call 0 never executed call 1 never executed unconditional 2 never executed -: 1092: "directory\n"), PROGRAM_NAME); -: 1093: } else { 1: 1094: fprintf(fp, "%s", pinned_dir); 1: 1094-block 0 call 0 returned 1 1: 1095: fclose(fp); call 0 returned 1 unconditional 1 taken 1 -: 1096: } -: 1097: 1: 1098: free(pin_file); 1: 1098-block 0 unconditional 0 taken 1 -: 1099: } -: 1100: 4: 1101: return; 4: 1101-block 0 unconditional 0 taken 4 -: 1102:} -: 1103: -: 1104:int function free_remotes called 26 returned 100% blocks executed 100% 26: 1105:free_remotes(int exit) -: 1106:{ 26: 1107: if (exit) 26: 1107-block 0 branch 0 taken 4 (fallthrough) branch 1 taken 22 4: 1108: autounmount_remotes(); 4: 1108-block 0 call 0 returned 4 unconditional 1 taken 4 -: 1109: -: 1110: size_t i; 64: 1111: for (i = 0; i < remotes_n; i++) { 26: 1111-block 0 unconditional 0 taken 26 64: 1111-block 1 branch 1 taken 38 branch 2 taken 26 (fallthrough) 38: 1112: free(remotes[i].name); 38: 1113: free(remotes[i].desc); 38: 1114: free(remotes[i].mountpoint); 38: 1115: free(remotes[i].mount_cmd); 38: 1116: free(remotes[i].unmount_cmd); 38: 1116-block 0 unconditional 0 taken 38 -: 1117: } 26: 1118: free(remotes); 26: 1119: remotes_n = 0; -: 1120: 26: 1121: return EXIT_SUCCESS; 26: 1121-block 0 unconditional 0 taken 26 -: 1122:} -: 1123: -: 1124:/* This function is called by atexit() to clear whatever is there at exit -: 1125: * time and avoid thus memory leaks */ -: 1126:void function free_stuff called 4 returned 100% blocks executed 91% 4: 1127:free_stuff(void) -: 1128:{ 4: 1129: int i = 0; -: 1130: -: 1131:#ifdef LINUX_INOTIFY -: 1132: /* Shutdown inotify */ 4: 1133: if (inotify_wd >= 0) 4: 1133-block 0 branch 0 taken 4 (fallthrough) branch 1 taken 0 4: 1134: inotify_rm_watch(inotify_fd, inotify_wd); 4: 1134-block 0 call 0 returned 4 unconditional 1 taken 4 4: 1135: close(inotify_fd); 4: 1135-block 0 call 0 returned 4 -: 1136:#elif defined(BSD_KQUEUE) -: 1137: if (event_fd >= 0) -: 1138: close(event_fd); -: 1139: close(kq); -: 1140:#endif -: 1141: 4: 1142: if (xargs.stealth_mode != 1) { branch 0 taken 4 (fallthrough) branch 1 taken 0 4: 1143: save_pinned_dir(); 4: 1143-block 0 call 0 returned 4 4: 1144: save_jumpdb(); call 0 returned 4 unconditional 1 taken 4 -: 1145: } -: 1146: 4: 1147: save_dirhist(); 4: 1147-block 0 call 0 returned 4 -: 1148: 4: 1149: if (restore_last_path || cd_on_quit) branch 0 taken 1 (fallthrough) branch 1 taken 3 1: 1149-block 0 branch 2 taken 0 (fallthrough) branch 3 taken 1 3: 1150: save_last_path(); 3: 1150-block 0 call 0 returned 3 unconditional 1 taken 3 -: 1151: 4: 1152: free(alt_profile); 4: 1153: free_bookmarks(); 4: 1153-block 0 call 0 returned 4 4: 1154: free(encoded_prompt); 4: 1155: free_dirlist(); call 0 returned 4 4: 1156: free(opener); -: 1157: 4: 1158: if (stdin_tmp_dir) { branch 0 taken 0 (fallthrough) branch 1 taken 4 #####: 1159: char *rm_cmd[] = {"rm", "-rd", "--", stdin_tmp_dir, NULL}; #####: 1160: launch_execve(rm_cmd, FOREGROUND, E_NOFLAG); %%%%%: 1160-block 0 call 0 never executed #####: 1161: free(stdin_tmp_dir); unconditional 0 never executed -: 1162: } -: 1163: 4: 1164: if (color_schemes) { 4: 1164-block 0 branch 0 taken 4 (fallthrough) branch 1 taken 0 65: 1165: for (i = 0; color_schemes[i]; i++) 4: 1165-block 0 unconditional 0 taken 4 65: 1165-block 1 branch 1 taken 61 branch 2 taken 4 (fallthrough) 61: 1166: free(color_schemes[i]); 61: 1166-block 0 unconditional 0 taken 61 4: 1167: free(color_schemes); 4: 1167-block 0 unconditional 0 taken 4 -: 1168: } -: 1169: 4: 1170: if (jump_db) { 4: 1170-block 0 branch 0 taken 4 (fallthrough) branch 1 taken 0 4: 1171: i = (int)jump_n; 147: 1172: while (--i >= 0) 4: 1172-block 0 unconditional 0 taken 4 147: 1172-block 1 branch 1 taken 143 branch 2 taken 4 (fallthrough) 143: 1173: free(jump_db[i].path); 143: 1173-block 0 unconditional 0 taken 143 4: 1174: free(jump_db); 4: 1174-block 0 unconditional 0 taken 4 -: 1175: } -: 1176: 4: 1177: if (pinned_dir) 4: 1177-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 3 1: 1178: free(pinned_dir); 1: 1178-block 0 unconditional 0 taken 1 -: 1179: 4: 1180: if (filter) { 4: 1180-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 4 #####: 1181: regfree(®ex_exp); %%%%%: 1181-block 0 call 0 never executed #####: 1182: free(filter); unconditional 0 never executed -: 1183: } -: 1184: 4: 1185: if (eln_as_file_n) 4: 1185-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 4 #####: 1186: free(eln_as_file); %%%%%: 1186-block 0 unconditional 0 never executed -: 1187: 4: 1188: if (ext_colors_n) 4: 1188-block 0 branch 0 taken 4 (fallthrough) branch 1 taken 0 4: 1189: free(ext_colors_len); 4: 1189-block 0 unconditional 0 taken 4 -: 1190: -: 1191: 4: 1192: if (profile_names) { 4: 1192-block 0 branch 0 taken 4 (fallthrough) branch 1 taken 0 20: 1193: for (i = 0; profile_names[i]; i++) 4: 1193-block 0 unconditional 0 taken 4 20: 1193-block 1 branch 1 taken 16 branch 2 taken 4 (fallthrough) 16: 1194: free(profile_names[i]); 16: 1194-block 0 unconditional 0 taken 16 4: 1195: free(profile_names); 4: 1195-block 0 unconditional 0 taken 4 -: 1196: } -: 1197: 4: 1198: if (sel_n > 0) { 4: 1198-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 4 #####: 1199: i = (int)sel_n; #####: 1200: while (--i >= 0) %%%%%: 1200-block 0 unconditional 0 never executed %%%%%: 1200-block 1 branch 1 never executed branch 2 never executed #####: 1201: free(sel_elements[i]); %%%%%: 1201-block 0 unconditional 0 never executed #####: 1202: free(sel_elements); %%%%%: 1202-block 0 unconditional 0 never executed -: 1203: } -: 1204: 4: 1205: if (bin_commands) { 4: 1205-block 0 branch 0 taken 4 (fallthrough) branch 1 taken 0 4: 1206: i = (int)path_progsn; 14975: 1207: while (--i >= 0) 4: 1207-block 0 unconditional 0 taken 4 14975: 1207-block 1 branch 1 taken 14971 branch 2 taken 4 (fallthrough) 14971: 1208: free(bin_commands[i]); 14971: 1208-block 0 unconditional 0 taken 14971 4: 1209: free(bin_commands); 4: 1209-block 0 unconditional 0 taken 4 -: 1210: } -: 1211: 4: 1212: if (paths) { 4: 1212-block 0 branch 0 taken 4 (fallthrough) branch 1 taken 0 4: 1213: i = (int)path_n; 28: 1214: while (--i >= 0) 4: 1214-block 0 unconditional 0 taken 4 28: 1214-block 1 branch 1 taken 24 branch 2 taken 4 (fallthrough) 24: 1215: free(paths[i]); 24: 1215-block 0 unconditional 0 taken 24 4: 1216: free(paths); 4: 1216-block 0 unconditional 0 taken 4 -: 1217: } -: 1218: 4: 1219: if (cdpaths) { 4: 1219-block 0 branch 0 taken 3 (fallthrough) branch 1 taken 1 3: 1220: i = (int)cdpath_n; 9: 1221: while (--i >= 0) 3: 1221-block 0 unconditional 0 taken 3 9: 1221-block 1 branch 1 taken 6 branch 2 taken 3 (fallthrough) 6: 1222: free(cdpaths[i]); 6: 1222-block 0 unconditional 0 taken 6 3: 1223: free(cdpaths); 3: 1223-block 0 unconditional 0 taken 3 -: 1224: } -: 1225: 4: 1226: if (history) { 4: 1226-block 0 branch 0 taken 4 (fallthrough) branch 1 taken 0 4: 1227: i = (int)current_hist_n; 3146: 1228: while (--i >= 0) 4: 1228-block 0 unconditional 0 taken 4 3146: 1228-block 1 branch 1 taken 3142 branch 2 taken 4 (fallthrough) 3142: 1229: free(history[i]); 3142: 1229-block 0 unconditional 0 taken 3142 4: 1230: free(history); 4: 1230-block 0 unconditional 0 taken 4 -: 1231: } -: 1232: 4: 1233: if (argv_bk) { 4: 1233-block 0 branch 0 taken 4 (fallthrough) branch 1 taken 0 4: 1234: i = argc_bk; 12: 1235: while (--i >= 0) 4: 1235-block 0 unconditional 0 taken 4 12: 1235-block 1 branch 1 taken 8 branch 2 taken 4 (fallthrough) 8: 1236: free(argv_bk[i]); 8: 1236-block 0 unconditional 0 taken 8 4: 1237: free(argv_bk); 4: 1237-block 0 unconditional 0 taken 4 -: 1238: } -: 1239: 4: 1240: if (dirhist_total_index) { 4: 1240-block 0 branch 0 taken 4 (fallthrough) branch 1 taken 0 4: 1241: i = (int)dirhist_total_index; 482: 1242: while (--i >= 0) 4: 1242-block 0 unconditional 0 taken 4 482: 1242-block 1 branch 1 taken 478 branch 2 taken 4 (fallthrough) 478: 1243: free(old_pwd[i]); 478: 1243-block 0 unconditional 0 taken 478 4: 1244: free(old_pwd); 4: 1244-block 0 unconditional 0 taken 4 -: 1245: } -: 1246: 4: 1247: i = (int)kbinds_n; 211: 1248: while (--i >= 0) { 4: 1248-block 0 unconditional 0 taken 4 211: 1248-block 1 branch 1 taken 207 branch 2 taken 4 (fallthrough) 207: 1249: free(kbinds[i].function); 207: 1250: free(kbinds[i].key); 207: 1250-block 0 unconditional 0 taken 207 -: 1251: } 4: 1252: free(kbinds); -: 1253: 4: 1254: i = (int)usrvar_n; 4: 1255: while (--i >= 0) { 4: 1255-block 0 unconditional 0 taken 4 4: 1255-block 1 branch 1 taken 0 branch 2 taken 4 (fallthrough) #####: 1256: free(usr_var[i].name); #####: 1257: free(usr_var[i].value); %%%%%: 1257-block 0 unconditional 0 never executed -: 1258: } 4: 1259: free(usr_var); -: 1260: 4: 1261: i = (int)actions_n; 89: 1262: while (--i >= 0) { 4: 1262-block 0 unconditional 0 taken 4 89: 1262-block 1 branch 1 taken 85 branch 2 taken 4 (fallthrough) 85: 1263: free(usr_actions[i].name); 85: 1264: free(usr_actions[i].value); 85: 1264-block 0 unconditional 0 taken 85 -: 1265: } 4: 1266: free(usr_actions); -: 1267: 4: 1268: i = (int)aliases_n; 19: 1269: while (--i >= 0) 4: 1269-block 0 unconditional 0 taken 4 19: 1269-block 1 branch 1 taken 15 branch 2 taken 4 (fallthrough) 15: 1270: free(aliases[i]); 15: 1270-block 0 unconditional 0 taken 15 4: 1271: free(aliases); -: 1272: 4: 1273: i = (int)prompt_cmds_n; 15: 1274: while (--i >= 0) 4: 1274-block 0 unconditional 0 taken 4 15: 1274-block 1 branch 1 taken 11 branch 2 taken 4 (fallthrough) 11: 1275: free(prompt_cmds[i]); 11: 1275-block 0 unconditional 0 taken 11 4: 1276: free(prompt_cmds); -: 1277: -: 1278:/* if (flags & FILE_CMD_OK) -: 1279: free(file_cmd_path); */ -: 1280: 4: 1281: if (msgs_n) { 4: 1281-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 3 1: 1282: i = (int)msgs_n; 2: 1283: while (--i >= 0) 1: 1283-block 0 unconditional 0 taken 1 2: 1283-block 1 branch 1 taken 1 branch 2 taken 1 (fallthrough) 1: 1284: free(messages[i]); 1: 1284-block 0 unconditional 0 taken 1 1: 1285: free(messages); 1: 1285-block 0 unconditional 0 taken 1 -: 1286: } -: 1287: 4: 1288: if (ext_colors_n) { 4: 1288-block 0 branch 0 taken 4 (fallthrough) branch 1 taken 0 4: 1289: i = (int)ext_colors_n; 318: 1290: while (--i >= 0) 4: 1290-block 0 unconditional 0 taken 4 318: 1290-block 1 branch 1 taken 314 branch 2 taken 4 (fallthrough) 314: 1291: free(ext_colors[i]); 314: 1291-block 0 unconditional 0 taken 314 4: 1292: free(ext_colors); 4: 1292-block 0 unconditional 0 taken 4 -: 1293: } -: 1294: 4: 1295: if (ws && ws[0].path) { 4: 1295-block 0 branch 0 taken 4 (fallthrough) branch 1 taken 0 4: 1295-block 1 branch 2 taken 4 (fallthrough) branch 3 taken 0 4: 1296: i = MAX_WS; 36: 1297: while (--i >= 0) 4: 1297-block 0 unconditional 0 taken 4 36: 1297-block 1 branch 1 taken 32 branch 2 taken 4 (fallthrough) 32: 1298: if (ws[i].path) 32: 1298-block 0 branch 0 taken 13 (fallthrough) branch 1 taken 19 13: 1299: free(ws[i].path); 13: 1299-block 0 unconditional 0 taken 13 4: 1300: free(ws); 4: 1300-block 0 unconditional 0 taken 4 -: 1301: } -: 1302: 4: 1303: free(actions_file); 4: 1304: free(bm_file); 4: 1305: free(data_dir); 4: 1306: free(colors_dir); 4: 1307: free(config_dir_gral); 4: 1308: free(config_dir); 4: 1309: free(config_file); 4: 1310: free(dirhist_file); 4: 1311: free(hist_file); 4: 1312: free(kbinds_file); 4: 1313: free(log_file); 4: 1314: free(mime_file); 4: 1315: free(msg_log_file); 4: 1316: free(plugins_dir); 4: 1317: free(profile_file); 4: 1318: free(remotes_file); -: 1319: 4: 1320: free_remotes(1); 4: 1320-block 0 call 0 returned 4 -: 1321: -: 1322:#ifndef _NO_SUGGESTIONS 4: 1323: free(suggestion_buf); 4: 1324: free(suggestion_strategy); -: 1325:#endif -: 1326: 4: 1327: free(sel_file); 4: 1328: free(tmp_dir); 4: 1329: free(user.name); 4: 1330: free(user.home); 4: 1331: free(user.shell); -: 1332:#ifndef _NO_TRASH 4: 1333: free(trash_dir); 4: 1334: free(trash_files_dir); 4: 1335: free(trash_info_dir); -: 1336:#endif -: 1337: -: 1338: /* Restore the color of the running terminal */ 4: 1339: fputs("\x1b[0;39;49m", stdout); call 0 returned 4 4: 1340:} -: 1341: -: 1342:void function set_signals_to_ignore called 4 returned 100% blocks executed 100% 4: 1343:set_signals_to_ignore(void) -: 1344:{ -: 1345: /* signal(SIGINT, signal_handler); C-c */ 4: 1346: signal(SIGINT, SIG_IGN); /* C-c */ 4: 1346-block 0 call 0 returned 4 4: 1347: signal(SIGQUIT, SIG_IGN); /* C-\ */ call 0 returned 4 4: 1348: signal(SIGTSTP, SIG_IGN); /* C-z */ call 0 returned 4 -: 1349: /* signal(SIGTERM, SIG_IGN); -: 1350: signal(SIGTTIN, SIG_IGN); -: 1351: signal(SIGTTOU, SIG_IGN); */ 4: 1352:} -: 1353: -: 1354:void function handle_stdin called 0 returned 0% blocks executed 0% #####: 1355:handle_stdin() -: 1356:{ -: 1357: /* If files are passed via stdin, we need to disable restore -: 1358: * last path in order to correctly understand relative paths */ #####: 1359: restore_last_path = 0; -: 1360: -: 1361: /* Max input size: 512 * (512 * 1024) -: 1362: * 512 chunks of 524288 bytes (512KiB) each -: 1363: * == (65535 * PATH_MAX) -: 1364: * == 262MiB of data ((65535 * PATH_MAX) / 1024) */ -: 1365: #####: 1366: size_t chunk = 512 * 1024, #####: 1367: chunks_n = 1, #####: 1368: total_len = 0, #####: 1369: max_chunks = 512; -: 1370: #####: 1371: ssize_t input_len = 0; -: 1372: -: 1373: /* Initial buffer allocation == 1 chunk */ #####: 1374: char *buf = (char *)xnmalloc(chunk, sizeof(char)); %%%%%: 1374-block 0 call 0 never executed -: 1375: #####: 1376: while (chunks_n < max_chunks) { unconditional 0 never executed %%%%%: 1376-block 0 branch 1 never executed branch 2 never executed #####: 1377: input_len = read(STDIN_FILENO, buf + total_len, chunk); %%%%%: 1377-block 0 call 0 never executed -: 1378: -: 1379: /* Error */ #####: 1380: if (input_len < 0) { branch 0 never executed branch 1 never executed #####: 1381: free(buf); #####: 1382: return; %%%%%: 1382-block 0 unconditional 0 never executed -: 1383: } -: 1384: -: 1385: /* Nothing else to be read */ #####: 1386: if (input_len == 0) %%%%%: 1386-block 0 branch 0 never executed branch 1 never executed #####: 1387: break; %%%%%: 1387-block 0 unconditional 0 never executed -: 1388: #####: 1389: total_len += (size_t)input_len; #####: 1390: chunks_n++; -: 1391: -: 1392: /* Append a new chunk of memory to the buffer */ #####: 1393: buf = (char *)xrealloc(buf, (chunks_n + 1) * chunk); %%%%%: 1393-block 0 call 0 never executed unconditional 1 never executed -: 1394: } -: 1395: #####: 1396: if (total_len == 0) %%%%%: 1396-block 0 branch 0 never executed branch 1 never executed #####: 1397: goto FREE_N_EXIT; %%%%%: 1397-block 0 unconditional 0 never executed -: 1398: -: 1399: /* Null terminate the input buffer */ #####: 1400: buf[total_len] = '\0'; -: 1401: -: 1402: /* Create tmp dir to store links to files */ #####: 1403: char *rand_ext = gen_rand_str(6); %%%%%: 1403-block 0 call 0 never executed #####: 1404: if (!rand_ext) branch 0 never executed branch 1 never executed #####: 1405: goto FREE_N_EXIT; %%%%%: 1405-block 0 unconditional 0 never executed -: 1406: #####: 1407: if (tmp_dir) { %%%%%: 1407-block 0 branch 0 never executed branch 1 never executed #####: 1408: stdin_tmp_dir = (char *)xnmalloc(strlen(tmp_dir) + 14, sizeof(char)); %%%%%: 1408-block 0 call 0 never executed #####: 1409: sprintf(stdin_tmp_dir, "%s/clifm.%s", tmp_dir, rand_ext); unconditional 0 never executed -: 1410: } else { #####: 1411: stdin_tmp_dir = (char *)xnmalloc(18, sizeof(char)); %%%%%: 1411-block 0 call 0 never executed #####: 1412: sprintf(stdin_tmp_dir, "/tmp/clifm.%s", rand_ext); unconditional 0 never executed -: 1413: } -: 1414: #####: 1415: free(rand_ext); -: 1416: #####: 1417: char *cmd[] = {"mkdir", "-p", stdin_tmp_dir, NULL}; #####: 1418: if (launch_execve(cmd, FOREGROUND, E_NOFLAG) != EXIT_SUCCESS) %%%%%: 1418-block 0 call 0 never executed branch 1 never executed branch 2 never executed #####: 1419: goto FREE_N_EXIT; %%%%%: 1419-block 0 unconditional 0 never executed -: 1420: -: 1421: /* Get CWD: we need it to prepend it to relative paths */ #####: 1422: char *cwd = (char *)NULL; #####: 1423: cwd = getcwd(NULL, 0); %%%%%: 1423-block 0 call 0 never executed #####: 1424: if (!cwd) branch 0 never executed branch 1 never executed #####: 1425: goto FREE_N_EXIT; %%%%%: 1425-block 0 unconditional 0 never executed -: 1426: -: 1427: /* Get substrings from buf */ #####: 1428: char *p = buf, *q = buf; -: 1429: #####: 1430: while (*p) { %%%%%: 1430-block 0 unconditional 0 never executed %%%%%: 1430-block 1 branch 1 never executed branch 2 never executed #####: 1431: if (!*p || *p == '\n') { %%%%%: 1431-block 0 branch 0 never executed branch 1 never executed %%%%%: 1431-block 1 branch 2 never executed branch 3 never executed #####: 1432: *p = '\0'; -: 1433: -: 1434: /* Create symlinks (in tmp dir) to each valid file in -: 1435: * the buffer */ -: 1436: -: 1437: /* If file does not exist */ -: 1438: struct stat attr; #####: 1439: if (lstat(q, &attr) == -1) %%%%%: 1439-block 0 call 0 never executed branch 1 never executed branch 2 never executed #####: 1440: continue; %%%%%: 1440-block 0 unconditional 0 never executed -: 1441: -: 1442: /* Construct source and destiny files */ #####: 1443: char *tmp_file = strrchr(q, '/'); #####: 1444: if (!tmp_file || !*(++tmp_file)) %%%%%: 1444-block 0 branch 0 never executed branch 1 never executed %%%%%: 1444-block 1 branch 2 never executed branch 3 never executed #####: 1445: tmp_file = q; %%%%%: 1445-block 0 unconditional 0 never executed -: 1446: -: 1447: char source[PATH_MAX]; #####: 1448: if (*q != '/' || !q[1]) %%%%%: 1448-block 0 branch 0 never executed branch 1 never executed %%%%%: 1448-block 1 branch 2 never executed branch 3 never executed #####: 1449: snprintf(source, PATH_MAX, "%s/%s", cwd, q); %%%%%: 1449-block 0 unconditional 0 never executed -: 1450: else #####: 1451: xstrsncpy(source, q, PATH_MAX); %%%%%: 1451-block 0 call 0 never executed unconditional 1 never executed -: 1452: -: 1453: char dest[PATH_MAX + 1]; #####: 1454: snprintf(dest, PATH_MAX, "%s/%s", stdin_tmp_dir, tmp_file); -: 1455: #####: 1456: if (symlink(source, dest) == -1) %%%%%: 1456-block 0 call 0 never executed branch 1 never executed branch 2 never executed #####: 1457: _err('w', PRINT_PROMPT, "ln: '%s': %s\n", q, strerror(errno)); %%%%%: 1457-block 0 call 0 never executed call 1 never executed unconditional 2 never executed -: 1458: #####: 1459: q = p + 1; %%%%%: 1459-block 0 unconditional 0 never executed -: 1460: } -: 1461: #####: 1462: p++; %%%%%: 1462-block 0 unconditional 0 never executed -: 1463: } -: 1464: -: 1465: /* chdir to tmp dir and update path var */ #####: 1466: if (xchdir(stdin_tmp_dir, SET_TITLE) == -1) { %%%%%: 1466-block 0 call 0 never executed branch 1 never executed branch 2 never executed #####: 1467: fprintf(stderr, "%s: %s: %s\n", PROGRAM_NAME, stdin_tmp_dir, call 0 never executed #####: 1468: strerror(errno)); %%%%%: 1468-block 0 call 0 never executed -: 1469: #####: 1470: char *rm_cmd[] = {"rm", "-drf", stdin_tmp_dir, NULL}; #####: 1471: launch_execve(rm_cmd, FOREGROUND, E_NOFLAG); call 0 never executed -: 1472: #####: 1473: free(cwd); #####: 1474: goto FREE_N_EXIT; unconditional 0 never executed -: 1475: } -: 1476: #####: 1477: free(cwd); -: 1478: #####: 1479: if (ws[cur_ws].path) %%%%%: 1479-block 0 branch 0 never executed branch 1 never executed #####: 1480: free(ws[cur_ws].path); %%%%%: 1480-block 0 unconditional 0 never executed -: 1481: #####: 1482: ws[cur_ws].path = savestring(stdin_tmp_dir, strlen(stdin_tmp_dir)); %%%%%: 1482-block 0 call 0 never executed #####: 1483: goto FREE_N_EXIT; unconditional 0 never executed -: 1484: #####: 1485:FREE_N_EXIT: #####: 1486: free(buf); -: 1487: -: 1488: /* Go back to tty */ #####: 1489: dup2(STDOUT_FILENO, STDIN_FILENO); %%%%%: 1489-block 0 call 0 never executed -: 1490: #####: 1491: if (cd_lists_on_the_fly) { branch 0 never executed branch 1 never executed #####: 1492: free_dirlist(); %%%%%: 1492-block 0 call 0 never executed #####: 1493: list_dir(); call 0 never executed #####: 1494: add_to_dirhist(ws[cur_ws].path); call 0 never executed unconditional 1 never executed -: 1495: } -: 1496: #####: 1497: return; %%%%%: 1497-block 0 unconditional 0 never executed -: 1498:} -: 1499: -: 1500:int function pin_directory called 1 returned 100% blocks executed 61% 1: 1501:pin_directory(char *dir) -: 1502:{ 1: 1503: if (!dir || !*dir) 1: 1503-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 0 1: 1503-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 1 #####: 1504: return EXIT_FAILURE; %%%%%: 1504-block 0 unconditional 0 never executed -: 1505: -: 1506: struct stat attr; 1: 1507: if (lstat(dir, &attr) == -1) { 1: 1507-block 0 call 0 returned 1 branch 1 taken 0 (fallthrough) branch 2 taken 1 #####: 1508: fprintf(stderr, "%s: %s: %s\n", PROGRAM_NAME, dir, strerror(errno)); %%%%%: 1508-block 0 call 0 never executed call 1 never executed #####: 1509: return EXIT_FAILURE; unconditional 0 never executed -: 1510: } -: 1511: 1: 1512: if (pinned_dir) { 1: 1512-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 1 #####: 1513: free(pinned_dir); #####: 1514: pinned_dir = (char *)NULL; %%%%%: 1514-block 0 unconditional 0 never executed -: 1515: } -: 1516: -: 1517: /* If absolute path */ 1: 1518: if (*dir == '/') { 1: 1518-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 1 #####: 1519: pinned_dir = savestring(dir, strlen(dir)); %%%%%: 1519-block 0 call 0 never executed unconditional 1 never executed -: 1520: } else { /* If relative path */ -: 1521: 1: 1522: if (strcmp(ws[cur_ws].path, "/") == 0) { 1: 1522-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 1 #####: 1523: pinned_dir = (char *)xnmalloc(strlen(dir) + 2, sizeof(char)); %%%%%: 1523-block 0 call 0 never executed #####: 1524: sprintf(pinned_dir, "/%s", dir); unconditional 0 never executed -: 1525: } else { 2: 1526: pinned_dir = (char *)xnmalloc(strlen(dir) 1: 1527: + strlen(ws[cur_ws].path) + 2, sizeof(char)); 1: 1527-block 0 call 0 returned 1 1: 1528: sprintf(pinned_dir, "%s/%s", ws[cur_ws].path, dir); unconditional 0 taken 1 -: 1529: } -: 1530: } -: 1531: 1: 1532: printf(_("%s: Succesfully pinned '%s'\n"), PROGRAM_NAME, dir); 1: 1532-block 0 call 0 returned 1 call 1 returned 1 1: 1533: return EXIT_SUCCESS; unconditional 0 taken 1 -: 1534:} -: 1535: -: 1536:int function unpin_dir called 2 returned 100% blocks executed 67% 2: 1537:unpin_dir(void) -: 1538:{ 2: 1539: if (!pinned_dir) { 2: 1539-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 2 #####: 1540: printf(_("%s: No pinned file\n"), PROGRAM_NAME); %%%%%: 1540-block 0 call 0 never executed call 1 never executed #####: 1541: return EXIT_SUCCESS; unconditional 0 never executed -: 1542: } -: 1543: 2: 1544: if (config_dir && xargs.stealth_mode != 1) { 2: 1544-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 0 2: 1544-block 1 branch 2 taken 2 (fallthrough) branch 3 taken 0 2: 1545: int cmd_error = 0; 2: 1546: char *pin_file = (char *)xnmalloc(strlen(config_dir) + 7, sizeof(char)); 2: 1546-block 0 call 0 returned 2 2: 1547: sprintf(pin_file, "%s/.pin", config_dir); -: 1548: 2: 1549: if (unlink(pin_file) == -1) { call 0 returned 2 branch 1 taken 2 (fallthrough) branch 2 taken 0 2: 1550: fprintf(stderr, "%s: %s: %s\n", PROGRAM_NAME, pin_file, call 0 returned 2 2: 1551: strerror(errno)); 2: 1551-block 0 call 0 returned 2 2: 1552: cmd_error = 1; unconditional 0 taken 2 -: 1553: } -: 1554: 2: 1555: free(pin_file); 2: 1556: if (cmd_error) 2: 1556-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 0 2: 1557: return EXIT_FAILURE; 2: 1557-block 0 unconditional 0 taken 2 -: 1558: } -: 1559: #####: 1560: printf(_("Succesfully unpinned %s\n"), pinned_dir); %%%%%: 1560-block 0 call 0 never executed call 1 never executed -: 1561: #####: 1562: free(pinned_dir); #####: 1563: pinned_dir = (char *)NULL; #####: 1564: return EXIT_SUCCESS; unconditional 0 never executed -: 1565:} -: 1566: -: 1567:int function hidden_function called 3 returned 100% blocks executed 85% 3: 1568:hidden_function(char **comm) -: 1569:{ 3: 1570: int exit_status = EXIT_SUCCESS; -: 1571: 3: 1572: if (strcmp(comm[1], "status") == 0) { 3: 1572-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 2 1: 1573: printf(_("%s: Hidden files %s\n"), PROGRAM_NAME, 1: 1573-block 0 call 0 returned 1 call 1 returned 1 unconditional 2 taken 1 1*: 1574: (show_hidden) ? _("enabled") : _("disabled")); 1: 1574-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 0 1: 1574-block 1 call 2 returned 1 unconditional 3 taken 1 %%%%%: 1574-block 2 call 4 never executed unconditional 5 never executed 2: 1575: } else if (strcmp(comm[1], "off") == 0) { 2: 1575-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 1 1: 1576: if (show_hidden == 1) { 1: 1576-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 0 1: 1577: show_hidden = 0; -: 1578: 1: 1579: if (cd_lists_on_the_fly) { 1: 1579-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 0 1: 1580: free_dirlist(); 1: 1580-block 0 call 0 returned 1 1: 1581: exit_status = list_dir(); call 0 returned 1 unconditional 1 taken 1 -: 1582: } -: 1583: } 1: 1584: } else if (strcmp(comm[1], "on") == 0) { 1: 1584-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 0 1: 1585: if (show_hidden == 0) { 1: 1585-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 0 1: 1586: show_hidden = 1; -: 1587: 1: 1588: if (cd_lists_on_the_fly) { 1: 1588-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 0 1: 1589: free_dirlist(); 1: 1589-block 0 call 0 returned 1 1: 1590: exit_status = list_dir(); call 0 returned 1 unconditional 1 taken 1 -: 1591: } -: 1592: } -: 1593: } else { #####: 1594: fprintf(stderr, "%s\n", _(HF_USAGE)); %%%%%: 1594-block 0 call 0 never executed call 1 never executed unconditional 2 never executed -: 1595: } -: 1596: 3: 1597: return exit_status; 3: 1597-block 0 unconditional 0 taken 3 -: 1598:} -: 1599: -: 1600:/* Instead of recreating here the commands description, just jump to the -: 1601: * corresponding section in the manpage */ -: 1602:int function list_commands called 1 returned 100% blocks executed 83% 1: 1603:list_commands(void) -: 1604:{ -: 1605: char cmd[PATH_MAX]; 1: 1606: snprintf(cmd, PATH_MAX - 1, "export PAGER=\"less -p '^[0-9]+\\.[[:space:]]COMMANDS'\"; man %s\n", -: 1607: PNL); 1: 1608: if (launch_execle(cmd) != EXIT_SUCCESS) 1: 1608-block 0 call 0 returned 1 branch 1 taken 0 (fallthrough) branch 2 taken 1 #####: 1609: return EXIT_FAILURE; %%%%%: 1609-block 0 unconditional 0 never executed -: 1610: 1: 1611: return EXIT_SUCCESS; 1: 1611-block 0 unconditional 0 taken 1 -: 1612:} -: 1613: -: 1614:void function help_function called 38 returned 100% blocks executed 95% 38: 1615:help_function(void) -: 1616:{ 38: 1617: fputs("\x1b[0m", stdout); 38: 1617-block 0 call 0 returned 38 38*: 1618: printf(_("%s%s %s (%s), by %s\n"), (flags & EXT_HELP) ? "" : df_c, branch 0 taken 0 (fallthrough) branch 1 taken 38 %%%%%: 1618-block 0 unconditional 2 never executed 38: 1618-block 1 unconditional 3 taken 38 38: 1618-block 2 call 4 returned 38 call 5 returned 38 -: 1619: PROGRAM_NAME, VERSION, DATE, AUTHOR); -: 1620: 38: 1621: printf(_("\nUSAGE: %s %s\n\ call 0 returned 38 call 1 returned 38 -: 1622:\n -a, --no-hidden\t\t do not show hidden files (default)\ -: 1623:\n -A, --show-hidden\t\t show hidden files\ -: 1624:\n -b, --bookmarks-file=FILE\t specify an alternative bookmarks file\ -: 1625:\n -c, --config-file=FILE\t\t specify an alternative configuration file\ -: 1626:\n -D, --config-dir=DIR\t\t specify an alternative configuration directory\ -: 1627:\n -e, --no-eln\t\t\t do not print ELN (entry list number) at \ -: 1628:\n the left of each file name \ -: 1629:\n -f, --no-folders-first\t\t do not list folders first\ -: 1630:\n -F, --folders-first\t\t list folders first (default)\ -: 1631:\n -g, --pager\t\t\t enable the pager\ -: 1632:\n -G, --no-pager\t\t\t disable the pager (default)\ -: 1633:\n -h, --help\t\t\t show this help and exit\ -: 1634:\n -i, --no-case-sensitive\t no case-sensitive files listing (default)\ -: 1635:\n -I, --case-sensitive\t\t case-sensitive files listing\ -: 1636:\n -k, --keybindings-file=FILE\t specify an alternative keybindings file\ -: 1637:\n -l, --no-long-view\t\t disable long view mode (default)\ -: 1638:\n -L, --long-view\t\t enable long view mode\ -: 1639:\n -m, --dihist-map\t\t enable the directory history map\ -: 1640:\n -o, --no-list-on-the-fly\t 'cd' works as the shell 'cd' command\ -: 1641:\n -O, --list-on-the-fly\t\t 'cd' lists files on the fly (default)\ -: 1642:\n -p, --path=PATH\t\t (Deprecated: use positional parameters instead)\ -: 1643:\n use PATH as %s starting path\ -: 1644:\n -P, --profile=PROFILE\t\t use (or create) PROFILE as profile\ -: 1645:\n -s, --splash \t\t\t enable the splash screen\ -: 1646:\n -S, --stealth-mode \t\t leave no trace on the host system.\ -: 1647:\n Nothing is read from any file nor any file \ -: 1648:\n is created: all settings are set to the \ -: 1649:\n default value. However, most settings can \ -: 1650:\n be controlled via command line options\ -: 1651:\n -u, --no-unicode \t\t disable unicode\ -: 1652:\n -U, --unicode \t\t\t enable unicode to correctly list file names \ -: 1653:\n containing accents, tildes, umlauts, \ -: 1654:\n non-latin letters, etc. This option is \ -: 1655:\n enabled by default\ -: 1656:\n -v, --version\t\t\t show version details and exit\ -: 1657:\n -w, --workspace=NUM\t\t start in workspace NUM\ -: 1658:\n -x, --no-ext-cmds\t\t disallow the use of external commands\ -: 1659:\n -y, --light-mode\t\t enable the light mode\ -: 1660:\n -z, --sort=METHOD\t\t sort files by METHOD, where METHOD \ -: 1661:\n could be: 0 = none, 1 = name, 2 = size, \ -: 1662:\n 3 = atime, 4 = btime, 5 = ctime, \ -: 1663:\n 6 = mtime, 7 = version, 8 = extension, \ -: 1664:\n 9 = inode, 10 = owner, 11 = group"), -: 1665: PNL, GRAL_USAGE, PROGRAM_NAME); -: 1666: 38: 1667: printf("\ call 0 returned 38 -: 1668:\n --autojump\t enable the autojump function (run the directory \ -: 1669:\n jumper omitting the j command: 'STR...' == 'j STR...')\ -: 1670:\n --case-sens-dirjump\t do not ignore case when consulting the \ -: 1671:\n jump database (via the 'j' command)\ -: 1672:\n --case-sens-path-comp\t enable case sensitive path completion\ -: 1673:\n --cd-on-quit\t\t write last visited path to \ -: 1674:\n $XDG_CONFIG_HOME/clifm/.last to be accessed\ -: 1675:\n later by a shell funtion. See the manpage\ -: 1676:\n --color-scheme=NAME\t use color scheme NAME\ -: 1677:\n --cwd-in-title\t\t print current directory in terminal \ -: 1678:\n window title\ -: 1679:\n --disk-usage\t\t show disk usage (free/total) for the\ -: 1680:\n filesystem to which the current directory \ -: 1681:\n belongs\ -: 1682:\n --enable-logs\t\t enable program logs\ -: 1683:\n --expand-bookmarks\t\t expand bookmark names into the \ -: 1684:\n corresponding bookmark paths. TAB \ -: 1685:\n completion for bookmark names is also \ -: 1686:\n available\ -: 1687:\n --icons\t\t\t enable icons\ -: 1688:\n --icons-use-file-color\t icons color follows file color\ -: 1689:\n --list-and-quit\t\t list files and quit. It may be used\ -: 1690:\n in conjunction with -p\ -: 1691:\n --max-dirhist\t\t maximum number of visited directories to \ -: 1692:\n remember\ -: 1693:\n --max-files=NUM\t\t list only up to NUM files\ -: 1694:\n --max-path=NUM\t\t set the maximun number of characters \ -: 1695:\n after which the current directory in the \ -: 1696:\n prompt line will be abreviated to the \ -: 1697:\n directory base name (if \\z is used in \ -: 1698:\n the prompt\ -: 1699:\n --no-dir-jumper\t\t disable the directory jumper function\ -: 1700:\n --no-cd-auto\t\t by default, %s changes to directories \ -: 1701:\n\t\t\t\tby just specifying the corresponding ELN \ -: 1702:\n (e.g. '12' instead of 'cd 12'). This \ -: 1703:\n option forces the use of 'cd'\ -: 1704:\n --no-classify\t\t do not append file type indicators\ -: 1705:\n --no-clear-screen\t\t do not clear the screen when listing \ -: 1706:\n directories\ -: 1707:\n --no-colors\t\t disable file type colors for files listing \ -: 1708:\n --no-columns\t\t disable columned files listing\ -: 1709:\n --no-file-cap\t\t do not check files capabilities when\ -: 1710:\n listing files\ -: 1711:\n --no-file-ext\t\t do not check files extension when\ -: 1712:\n listing files\ -: 1713:\n --no-files-counter\t\t disable the files counter for \ -: 1714:\n directories. This option is especially \ -: 1715:\n useful to speed up the listing process; \ -: 1716:\n counting files in directories is expensive\ -: 1717:\n --no-follow-symlink\t do not follow symbolic links when\ -: 1718:\n listing files\ -: 1719:\n --no-open-auto\t\t same as no-cd-auto, but for files\ -: 1720:\n --no-tips\t\t\t disable startup tips\ -: 1721:\n --no-restore-last-path\t save last visited directory to be \ -: 1722:\n restored in the next session\ -: 1723:\n --no-suggestions\t\t disable auto-suggestions\ -: 1724:\n --no-welcome-message\t disable the welcome message\ -: 1725:\n --only-dirs\t\t list only directories and symbolic links\ -: 1726:\n to directories\ -: 1727:\n --open=FILE\t run as a stand-alone resource opener: open\ -: 1728:\n FILE and exit\ -: 1729:\n --opener=APPLICATION\t resource opener to use instead of 'lira',\ -: 1730:\n %s built-in opener\ -: 1731:\n --print-sel\t\t keep the list of selected files in sight\ -: 1732:\n --rl-vi-mode\t\t set readline to vi editing mode (defaults \ -: 1733:\n to emacs editing mode)\ -: 1734:\n --share-selbox\t\t make the Selection Box common to \ -: 1735:\n different profiles\ -: 1736:\n --sort-reverse\t\t sort in reverse order, for example: z-a \ -: 1737:\n instead of a-z, which is the default order)\ -: 1738:\n --trash-as-rm\t\t the 'r' command executes 'trash' instead of \ -: 1739: 'rm' to prevent accidental deletions\n", -: 1740: PROGRAM_NAME, PROGRAM_NAME); -: 1741: 38: 1742: printf(_("\nBUILT-IN COMMANDS:\n\nThe following is just a brief list of " call 0 returned 38 call 1 returned 38 -: 1743: "available commands and possible parameters.\n\nFor a complete " -: 1744: "description of each of these commands run 'cmd' (or press " -: 1745: "F2) or consult the manpage (F1).\n\nYou can also try " -: 1746: "the 'ih' action to run the interactive help plugin (it " -: 1747: "depends on FZF). Just enter 'ih', that's it.\n\nIt is also " -: 1748: "recommended to consult the project's wiki " -: 1749: "(https://github.com/leo-arch/clifm/wiki)\n\n")); -: 1750: 38: 1751: puts(_("ELN/FILE/DIR (auto-open and autocd functions)\n\ call 0 returned 38 call 1 returned 38 -: 1752: /PATTERN [DIR] [-filetype] [-x] (quick search)\n\ -: 1753: ;[CMD], :[CMD] (run CMD via the system shell)\n\ -: 1754: ac, ad ELN/FILE ... (archiving functions)\n\ -: 1755: acd, autocd [on, off, status]\n\ -: 1756: actions [edit]\n\ -: 1757: alias [import FILE]\n\ -: 1758: ao, auto-open [on, off, status]\n\ -: 1759: b, back [h, hist] [clear] [!ELN]\n\ -: 1760: bl ELN/FILE ... (batch links)\n\ -: 1761: bm, bookmarks [a, add PATH] [d, del] [edit] [SHORTCUT or NAME]\n\ -: 1762: br, bulk ELN/FILE ...\n\ -: 1763: c, l [e, edit], m, md, r (copy, link, move, makedir, and remove)\n\ -: 1764: cc, colors\n\ -: 1765: cd [ELN/DIR]\n\ -: 1766: cl, columns [on, off]\n\ -: 1767: cmd, commands\n\ -: 1768: cs, colorscheme [edit] [COLORSCHEME]\n\ -: 1769: d, dup SOURCE [DEST]\n\ -: 1770: ds, desel [*, a, all]\n\ -: 1771: edit [APPLICATION] [reset]\n\ -: 1772: exp, export [ELN/FILE ...]\n\ -: 1773: ext [on, off, status]\n\ -: 1774: f, forth [h, hist] [clear] [!ELN]\n\ -: 1775: fc, filescounter [on, off, status]\n\ -: 1776: ff, folders-first [on, off, status]\n\ -: 1777: fs\n\ -: 1778: ft, filter [unset] [REGEX]\n\ -: 1779: hf, hidden [on, off, status]\n\ -: 1780: history [clear] [-n]\n\ -: 1781: icons [on, off]\n\ -: 1782: j, jc, jp, jl [STRING ...] jo [NUM], je (directory jumper function)\n\ -: 1783: kb, keybinds [edit] [reset] [readline]\n\ -: 1784: lm [on, off] (lightmode)\n\ -: 1785: log [clear]\n\ -: 1786: mf NUM (List up to NUM files)\n\ -: 1787: mm, mime [info ELN/FILE] [edit] [import] (resource opener)\n\ -: 1788: mp, mountpoints\n\ -: 1789: msg, messages [clear]\n\ -: 1790: n, new FILE DIR/ ...n\n\ -: 1791: net [NAME] [edit] [m, mount NAME] [u, unmount NAME]\n\ -: 1792: o, open [ELN/FILE] [APPLICATION]\n\ -: 1793: opener [default] [APPLICATION]\n\ -: 1794: p, pr, pp, prop [ELN/FILE ... n]\n\ -: 1795: path, cwd\n\ -: 1796: pf, prof, profile [ls, list] [set, add, del PROFILE]\n\ -: 1797: pg, pager [on, off, status]\n\ -: 1798: pin [FILE/DIR]\n\ -: 1799: q, quit, exit\n\ -: 1800: Q\n\ -: 1801: rf, refresh\n\ -: 1802: rl, reload\n\ -: 1803: s, sel ELN/FILE... [[!]PATTERN] [-FILETYPE] [:PATH]\n\ -: 1804: sb, selbox\n\ -: 1805: shell [SHELL]\n\ -: 1806: splash\n\ -: 1807: st, sort [METHOD] [rev]\n\ -: 1808: t, tr, trash [ELN/FILE ... n] [ls, list] [clear] [del, rm]\n\ -: 1809: te [FILE(s)]\n\ -: 1810: tips\n\ -: 1811: u, undel, untrash [*, a, all]\n\ -: 1812: uc, unicode [on, off, status]\n\ -: 1813: unpin\n\ -: 1814: v, vv, paste sel [DESTINY]\n\ -: 1815: ver, version\n\ -: 1816: ws [NUM, +, -] (workspaces)\n\ -: 1817: x, X [ELN/DIR] (new instance)\n")); -: 1818: 38: 1819: printf(_("DEFAULT KEYBOARD SHORTCUTS:\n\n" call 0 returned 38 call 1 returned 38 -: 1820: " Right, C-f: Accept the entire suggestion\n\ -: 1821: M-Right, M-f: Accept the first suggested word\n\ -: 1822: M-c: Clear the current command line buffer\n\ -: 1823: M-g: Toggle list-folders-first on/off\n\ -: 1824: C-r: Refresh the screen\n\ -: 1825: M-l: Toggle long view mode on/off\n\ -: 1826: M-m: List mountpoints\n\ -: 1827: M-t: Clear messages\n\ -: 1828: M-h: Show directory history\n\ -: 1829: M-i, M-.: Toggle hidden files on/off\n\ -: 1830: M-s: Open the Selection Box\n\ -: 1831: M-a: Select all files in the current working directory\n\ -: 1832: M-d: Deselect all selected files\n\ -: 1833: M-r: Change to the root directory\n\ -: 1834: M-e, Home: Change to the home directory\n\ -: 1835: M-u, S-Up: Change to the parent directory\n\ -: 1836: M-j, S-Left: Change to previous visited directory\n\ -: 1837: M-k, S-Right: Change to next visited directory\n\ -: 1838: M-o: Lock terminal\n\ -: 1839: M-p: Change to pinned directory\n\ -: 1840: M-1: Switch to workspace 1\n\ -: 1841: M-2: Switch to workspace 2\n\ -: 1842: M-3: Switch to workspace 3\n\ -: 1843: M-4: Switch to workspace 4\n\ -: 1844: C-M-j: Change to first visited directory\n\ -: 1845: C-M-k: Change to last visited directory\n\ -: 1846: C-M-o: Switch to previous profile\n\ -: 1847: C-M-p: Switch to next profile\n\ -: 1848: C-M-a: Archive selected files\n\ -: 1849: C-M-e: Export selected files\n\ -: 1850: C-M-r: Rename selected files\n\ -: 1851: C-M-d: Remove selected files\n\ -: 1852: C-M-t: Trash selected files\n\ -: 1853: C-M-u: Restore trashed files\n\ -: 1854: C-M-b: Bookmark last selected file or directory\n\ -: 1855: C-M-g: Open/change-into last selected file/directory\n\ -: 1856: C-M-n: Move selected files into the current working directory\n\ -: 1857: C-M-v: Copy selected files into the current working directory\n\ -: 1858: M-y: Toggle light mode on/off\n\ -: 1859: M-z: Switch to previous sorting method\n\ -: 1860: M-x: Switch to next sorting method\n\ -: 1861: C-x: Launch a new instance\n\ -: 1862: F1: Manual page\n\ -: 1863: F2: Commands help\n\ -: 1864: F3: Keybindings help\n\ -: 1865: F6: Open the MIME list file\n\ -: 1866: F7: Open the jump database file\n\ -: 1867: F8: Open the current color scheme file\n\ -: 1868: F9: Open the keybindings file\n\ -: 1869: F10: Open the configuration file\n\ -: 1870: F11: Open the bookmarks file\n\ -: 1871: F12: Quit\n\n" -: 1872: "NOTE: C stands for Ctrl, S for Shift, and M for Meta (Alt key in " -: 1873: "most keyboards)\n\n")); -: 1874: 38: 1875: puts(_("Run the 'colors' or 'cc' command to see the list " call 0 returned 38 call 1 returned 38 -: 1876: "of currently used color codes.\n")); -: 1877: 38: 1878: puts(_("The configuration and profile files allow you to customize " call 0 returned 38 call 1 returned 38 -: 1879: "colors, define some prompt commands and aliases, and more. " -: 1880: "For a full description consult the manpage.")); 38: 1881:} -: 1882: -: 1883:void function free_software called 1 returned 100% blocks executed 100% 1: 1884:free_software(void) -: 1885:{ 1: 1886: puts(_("Excerpt from 'What is Free Software?', by Richard Stallman. \ 1: 1886-block 0 call 0 returned 1 call 1 returned 1 -: 1887:Source: https://www.gnu.org/philosophy/free-sw.html\n \ -: 1888:\n\"'Free software' means software that respects users' freedom and \ -: 1889:community. Roughly, it means that the users have the freedom to run, \ -: 1890:copy, distribute, study, change and improve the software. Thus, 'free \ -: 1891:software' is a matter of liberty, not price. To understand the concept, \ -: 1892:you should think of 'free' as in 'free speech', not as in 'free beer'. \ -: 1893:We sometimes call it 'libre software', borrowing the French or Spanish \ -: 1894:word for 'free' as in freedom, to show we do not mean the software is \ -: 1895:gratis.\n\ -: 1896:\nWe campaign for these freedoms because everyone deserves them. With \ -: 1897:these freedoms, the users (both individually and collectively) control \ -: 1898:the program and what it does for them. When users don't control the \ -: 1899:program, we call it a 'nonfree' or proprietary program. The nonfree \ -: 1900:program controls the users, and the developer controls the program; \ -: 1901:this makes the program an instrument of unjust power. \n\ -: 1902:\nA program is free software if the program's users have the four \ -: 1903:essential freedoms:\n\n\ -: 1904:- The freedom to run the program as you wish, for any purpose \ -: 1905:(freedom 0).\n\ -: 1906:- The freedom to study how the program works, and change it so it does \ -: 1907:your computing as you wish (freedom 1). Access to the source code is a \ -: 1908:precondition for this.\n\ -: 1909:- The freedom to redistribute copies so you can help your neighbor \ -: 1910:(freedom 2).\n\ -: 1911:- The freedom to distribute copies of your modified versions to others \ -: 1912:(freedom 3). By doing this you can give the whole community a chance to \ -: 1913:benefit from your changes. Access to the source code is a precondition \ -: 1914:for this. \n\ -: 1915:\nA program is free software if it gives users adequately all of these \ -: 1916:freedoms. Otherwise, it is nonfree. While we can distinguish various \ -: 1917:nonfree distribution schemes in terms of how far they fall short of \ -: 1918:being free, we consider them all equally unethical (...)\"")); 1: 1919:} -: 1920: -: 1921:void function version_function called 1 returned 100% blocks executed 100% 1: 1922:version_function(void) -: 1923:{ 1: 1924: printf(_("%s %s (%s), by %s\nContact: %s\nWebsite: " 1: 1924-block 0 call 0 returned 1 call 1 returned 1 -: 1925: "%s\nLicense: %s\n"), PROGRAM_NAME, VERSION, DATE, -: 1926: AUTHOR, CONTACT, WEBSITE, LICENSE); 1: 1927:} -: 1928: -: 1929:void function splash called 1 returned 100% blocks executed 60% 1: 1930:splash(void) -: 1931:{ 1: 1932: printf("\n%s" 1: 1932-block 0 call 0 returned 1 -: 1933:" .okkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkd. \n" -: 1934:" 'kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkc\n" -: 1935:" xkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk\n" -: 1936:" xkkkkkc::::::::::::::::::dkkkkkkc:::::kkkkkk\n" -: 1937:" xkkkkk'..................okkkkkk'.....kkkkkk\n" -: 1938:" xkkkkk'..................okkkkkk'.....kkkkkk\n" -: 1939:" xkkkkk'.....okkkkkk,.....okkkkkk'.....kkkkkk\n" -: 1940:" xkkkkk'.....dkkkkkk;.....okkkkkk'.....kkkkkk\n" -: 1941:" xkkkkk'.....dkkkkkk;.....okkkkkk'.....kkkkkk\n" -: 1942:" xkkkkk'.....dkkkkkk;.....okkkkkk'.....kkkkkk\n" -: 1943:" xkkkkk'.....dkkkkkk;.....okkkkkk'.....kkkkkk\n" -: 1944:" xkkkkk'.....dkkkkkk;.....okkkkkk'.....kkkkkk\n" -: 1945:" xkkkkk'.....dkkkkkk;.....okkkkkk'.....kkkkkk\n" -: 1946:" xkkkkk'.....dkkkkkk;.....okkkkkk'.....kkkkkk\n" -: 1947:" xkkkkk'.....dkkkkkk;.....okkkkkk'.....kkkkkk\n" -: 1948:" xkkkkk'.....coooooo'.....:llllll......kkkkkk\n" -: 1949:" xkkkkk'...............................kkkkkk\n" -: 1950:" xkkkkk'...............................kkkkkk\n" -: 1951:" xkkkkklccccccccccccccccccccccccccccccckkkkkk\n" -: 1952:" lkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkx\n" -: 1953:" ;kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkc \n" -: 1954:" :c::::::::::::::::::::::::::::::::::.", -: 1955: D_CYAN); -: 1956: 1: 1957: printf(_("\n\n%s%s\t\t CliFM%s\n\tThe KISS/non-curses file manager\n"), call 0 returned 1 call 1 returned 1 -: 1958: df_c, BOLD, df_c); -: 1959: 1: 1960: if (splash_screen) { branch 0 taken 0 (fallthrough) branch 1 taken 1 #####: 1961: printf(_("\n\t\t\tPress any key to continue... ")); %%%%%: 1961-block 0 call 0 never executed call 1 never executed #####: 1962: xgetchar(); call 0 never executed #####: 1963: putchar('\n'); call 0 never executed unconditional 1 never executed -: 1964: } else { 1: 1965: putchar('\n'); 1: 1965-block 0 call 0 returned 1 unconditional 1 taken 1 -: 1966: } 1: 1967:} -: 1968: -: 1969:void function bonus_function called 0 returned 0% blocks executed 0% #####: 1970:bonus_function(void) -: 1971:{ #####: 1972: char *phrases[] = { -: 1973: "\"Vamos Boca Juniors Carajo!\" (La mitad + 1)", -: 1974: "\"Hey! Look behind you! A three-headed monkey! (G. Threepweed)", -: 1975: "\"Free as in free speech, not as in free beer\" (R. M. S)", -: 1976: "\"Nothing great has been made in the world without passion\" (G. W. F. Hegel)", -: 1977: "\"Simplicity is the ultimate sophistication\" (Leo Da Vinci)", -: 1978: "\"Yo vendí semillas de alambre de púa, al contado, y me lo agradecieron\" (Marquitos, 9 Reinas)", -: 1979: "\"I'm so happy, because today I've found my friends, they're in my head\" (K. D. Cobain)", -: 1980: "\"The best code is written with the delete key (Someone, somewhere, sometime)", -: 1981: "\"I'm selling these fine leather jackets (Indy)", -: 1982: "\"I pray to God to make me free of God\" (Meister Eckhart)", -: 1983: "¡Truco y quiero retruco mierda!", -: 1984: "The only truth is that there is no truth", -: 1985: "\"This is a lie\" (The liar paradox)", -: 1986: "\"There are two ways to write error-free programs; only the third one works\" (Alan J. Perlis)", -: 1987: "The man who sold the world was later sold by the big G", -: 1988: "A programmer is always one year older than herself", -: 1989: "A smartphone is anything but smart", -: 1990: "And he did it: he killed the one who killed him", -: 1991: ">++('>", -: 1992: ":(){:|:&};:", -: 1993: "Keep it simple, stupid", -: 1994: "If ain't broken, brake it", -: 1995: "An Archer knows her target like the back of her hands", -: 1996: "\"I only know that I know nothing\" (Socrates)", -: 1997: "(Learned) Ignorance is the true outcome of wisdom (Nicholas " -: 1998: "of Cusa)", -: 1999: "True intelligence is about questions, not about answers", -: 2000: "Humanity is just an arrow released towards God", -: 2001: "Buzz is right: infinity is our only and ultimate goal", -: 2002: "That stain will never ever be erased (La 12)", -: 2003: "\"A work of art is never finished, but adandoned\" (J. L. Guerrero)", -: 2004: "At the beginning, software was hardware; but today hardware is " -: 2005: "being absorbed by software", -: 2006: NULL}; -: 2007: #####: 2008: size_t num = (sizeof(phrases) / sizeof(phrases[0])) - 1; #####: 2009: srand((unsigned int)time(NULL)); %%%%%: 2009-block 0 call 0 never executed call 1 never executed #####: 2010: puts(phrases[rand() % (int)num]); call 0 never executed call 1 never executed #####: 2011:} clifm-1.26.3/misc/codecov/navigation.c.gcov000066400000000000000000001020251506632037700205230ustar00rootroot00000000000000 -: 0:Source:navigation.c -: 1:/* navigation.c -- functions the navigation system */ -: 2: -: 3:/* -: 4: * This file is part of CliFM -: 5: * -: 6: * Copyright (C) 2016-2021, L. Abramovich -: 7: * All rights reserved. -: 8: -: 9: * CliFM is free software; you can redistribute it and/or modify -: 10: * it under the terms of the GNU General Public License as published by -: 11: * the Free Software Foundation; either version 2 of the License, or -: 12: * (at your option) any later version. -: 13: * -: 14: * CliFM is distributed in the hope that it will be useful, -: 15: * but WITHOUT ANY WARRANTY; without even the implied warranty of -: 16: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -: 17: * GNU General Public License for more details. -: 18: * -: 19: * You should have received a copy of the GNU General Public License -: 20: * along with this program; if not, write to the Free Software -: 21: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, -: 22: * MA 02110-1301, USA. -: 23:*/ -: 24: -: 25:#include "helpers.h" -: 26: -: 27:#include -: 28:#include -: 29:#include -: 30:#include -: 31:#include -: 32:#include -: 33: -: 34:#include "aux.h" -: 35:#include "checks.h" -: 36:#include "history.h" -: 37:#include "jump.h" -: 38:#include "listing.h" -: 39:#include "misc.h" -: 40:#include "navigation.h" -: 41:#include "messages.h" -: 42: -: 43:int function workspaces called 18 returned 100% blocks executed 53% 18: 44:workspaces(char *str) -: 45:{ 18: 46: if (!str || !*str) { 18: 46-block 0 branch 0 taken 18 (fallthrough) branch 1 taken 0 18: 46-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 18 -: 47: int i; #####: 48: for (i = 0; i < MAX_WS; i++) { %%%%%: 48-block 0 unconditional 0 never executed %%%%%: 48-block 1 unconditional 1 never executed %%%%%: 48-block 2 branch 2 never executed branch 3 never executed #####: 49: if (i == cur_ws) %%%%%: 49-block 0 branch 0 never executed branch 1 never executed #####: 50: printf("%s%d: %s%s\n", mi_c, i + 1, ws[i].path, df_c); %%%%%: 50-block 0 call 0 never executed unconditional 1 never executed -: 51: else #####: 52: printf("%d: %s\n", i + 1, ws[i].path ? ws[i].path : "none"); %%%%%: 52-block 0 branch 0 never executed branch 1 never executed %%%%%: 52-block 1 unconditional 2 never executed %%%%%: 52-block 2 unconditional 3 never executed %%%%%: 52-block 3 call 4 never executed unconditional 5 never executed -: 53: } #####: 54: return EXIT_SUCCESS; %%%%%: 54-block 0 unconditional 0 never executed -: 55: } -: 56: 18: 57: if (*str == '-' && strcmp(str, "--help") == 0) { 18: 57-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 17 1: 57-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 1 #####: 58: puts(_(WS_USAGE)); %%%%%: 58-block 0 call 0 never executed call 1 never executed #####: 59: return EXIT_SUCCESS; unconditional 0 never executed -: 60: } -: 61: 18: 62: int tmp_ws = 0; -: 63: 18: 64: if (is_number(str)) { 18: 64-block 0 call 0 returned 18 branch 1 taken 16 (fallthrough) branch 2 taken 2 16: 65: int istr = atoi(str); 16: 66: if (istr <= 0 || istr > MAX_WS) { 16: 66-block 0 branch 0 taken 16 (fallthrough) branch 1 taken 0 16: 66-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 16 #####: 67: fprintf(stderr, _("%s: %d: Invalid workspace number\n"), %%%%%: 67-block 0 call 0 never executed call 1 never executed -: 68: PROGRAM_NAME, istr); #####: 69: return EXIT_FAILURE; unconditional 0 never executed -: 70: } -: 71: 16: 72: tmp_ws = istr - 1; -: 73: 16: 74: if (tmp_ws == cur_ws) 16: 74-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 15 1: 75: return EXIT_FAILURE; 1: 75-block 0 unconditional 0 taken 1 2: 76: } else if (*str == '+' && !str[1]) { 2: 76-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 1 1: 76-block 1 branch 2 taken 1 (fallthrough) branch 3 taken 0 1: 77: if ((cur_ws + 1) < MAX_WS) 1: 77-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 0 1: 78: tmp_ws = cur_ws + 1; 1: 78-block 0 unconditional 0 taken 1 -: 79: else #####: 80: return EXIT_FAILURE; %%%%%: 80-block 0 unconditional 0 never executed 1: 81: } else if (*str == '-' && !str[1]) { 1: 81-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 0 1: 81-block 1 branch 2 taken 1 (fallthrough) branch 3 taken 0 1: 82: if ((cur_ws - 1) >= 0) 1: 82-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 0 1: 83: tmp_ws = cur_ws - 1; 1: 83-block 0 unconditional 0 taken 1 -: 84: else #####: 85: return EXIT_FAILURE; %%%%%: 85-block 0 unconditional 0 never executed -: 86: } -: 87: -: 88: /* If new workspace has no path yet, copy the path of the current -: 89: * workspace */ 17: 90: if (!ws[tmp_ws].path) { 17: 90-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 17 #####: 91: ws[tmp_ws].path = savestring(ws[cur_ws].path, unconditional 0 never executed #####: 92: strlen(ws[cur_ws].path)); %%%%%: 92-block 0 call 0 never executed 17: 93: } else if (access(ws[tmp_ws].path, R_OK | X_OK) != EXIT_SUCCESS) { 17: 93-block 0 call 0 returned 17 branch 1 taken 0 (fallthrough) branch 2 taken 17 #####: 94: fprintf(stderr, "%s: %s: %s\n", PROGRAM_NAME, ws[tmp_ws].path, call 0 never executed #####: 95: strerror(errno)); %%%%%: 95-block 0 call 0 never executed #####: 96: free(ws[tmp_ws].path); #####: 97: ws[tmp_ws].path = savestring(ws[cur_ws].path, unconditional 0 never executed #####: 98: strlen(ws[cur_ws].path)); call 0 never executed -: 99: } -: 100: 17: 101: if (xchdir(ws[tmp_ws].path, SET_TITLE) == -1) { 17: 101-block 0 call 0 returned 17 branch 1 taken 0 (fallthrough) branch 2 taken 17 #####: 102: fprintf(stderr, "%s: %s: %s\n", PROGRAM_NAME, ws[tmp_ws].path, call 0 never executed #####: 103: strerror(errno)); %%%%%: 103-block 0 call 0 never executed #####: 104: return EXIT_FAILURE; unconditional 0 never executed -: 105: } -: 106: 17: 107: cur_ws = tmp_ws; 17: 108: int exit_status = EXIT_SUCCESS; -: 109: 17: 110: if (cd_lists_on_the_fly) { 17: 110-block 0 branch 0 taken 17 (fallthrough) branch 1 taken 0 17: 111: free_dirlist(); 17: 111-block 0 call 0 returned 17 17: 112: exit_status = list_dir(); call 0 returned 17 unconditional 1 taken 17 -: 113: } -: 114: 17: 115: add_to_dirhist(ws[cur_ws].path); 17: 115-block 0 call 0 returned 17 17: 116: return exit_status; unconditional 0 taken 17 -: 117:} -: 118: -: 119:/* Make sure DIR exists, it is actually a directory and is readable. -: 120: * Only then change directory */ -: 121:int function xchdir called 786 returned 100% blocks executed 100% 786: 122:xchdir(const char *dir, const int set_title) -: 123:{ 786: 124: DIR *dirp = opendir(dir); 786: 124-block 0 call 0 returned 786 -: 125: 786: 126: if (!dirp) branch 0 taken 9 (fallthrough) branch 1 taken 777 9: 127: return -1; 9: 127-block 0 unconditional 0 taken 9 -: 128: 777: 129: closedir(dirp); 777: 129-block 0 call 0 returned 777 -: 130: -: 131: int ret; 777: 132: ret = chdir(dir); call 0 returned 777 -: 133: 777: 134: if (set_title && ret == 0 && xargs.cwd_in_title == 1) branch 0 taken 611 (fallthrough) branch 1 taken 166 611: 134-block 0 branch 2 taken 611 (fallthrough) branch 3 taken 0 611: 134-block 1 branch 4 taken 607 (fallthrough) branch 5 taken 4 607: 135: set_term_title(dir); 607: 135-block 0 call 0 returned 607 unconditional 1 taken 607 -: 136: 777: 137: return ret; 777: 137-block 0 unconditional 0 taken 777 -: 138:} -: 139: -: 140:static char * function check_cdpath called 332 returned 100% blocks executed 92% 332: 141:check_cdpath(char *name) -: 142:{ 332: 143: if (cdpath_n == 0 || !name || !*name) 332: 143-block 0 branch 0 taken 332 (fallthrough) branch 1 taken 0 332: 143-block 1 branch 2 taken 332 (fallthrough) branch 3 taken 0 332: 143-block 2 branch 4 taken 0 (fallthrough) branch 5 taken 332 #####: 144: return (char *)NULL; %%%%%: 144-block 0 unconditional 0 never executed -: 145: 332: 146: if (*name == '/' || (*name == '.' && name[1] == '/') 332: 146-block 0 branch 0 taken 310 (fallthrough) branch 1 taken 22 310: 146-block 1 branch 2 taken 2 (fallthrough) branch 3 taken 308 2: 146-block 2 branch 4 taken 2 (fallthrough) branch 5 taken 0 310: 147: || (*name == '.' && name[1] == '.' && name[2] == '/')) 310: 147-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 308 2: 147-block 1 branch 2 taken 1 (fallthrough) branch 3 taken 1 1: 147-block 2 branch 4 taken 1 (fallthrough) branch 5 taken 0 23: 148: return (char *)NULL; 23: 148-block 0 unconditional 0 taken 23 -: 149: -: 150: size_t i; -: 151: char t[PATH_MAX]; 309: 152: char *p = (char *)NULL; -: 153: struct stat attr; 919: 154: for (i = 0; cdpaths[i]; i++) { 309: 154-block 0 unconditional 0 taken 309 610: 154-block 1 unconditional 1 taken 610 919: 154-block 2 branch 2 taken 614 branch 3 taken 305 (fallthrough) 614: 155: size_t len = strlen(cdpaths[i]); 614: 156: if (cdpaths[i][len - 1] == '/') 614: 156-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 614 #####: 157: snprintf(t, PATH_MAX, "%s%s", cdpaths[i], name); %%%%%: 157-block 0 unconditional 0 never executed -: 158: else 614: 159: snprintf(t, PATH_MAX, "%s/%s", cdpaths[i], name); 614: 159-block 0 unconditional 0 taken 614 614: 160: if (stat(t, &attr) != -1 && (attr.st_mode & S_IFMT) == S_IFDIR) { 614: 160-block 0 call 0 returned 614 branch 1 taken 4 (fallthrough) branch 2 taken 610 4: 160-block 1 branch 3 taken 4 (fallthrough) branch 4 taken 0 4: 161: p = (char *)xnmalloc(strlen(t) + 1, sizeof(char)); 4: 161-block 0 call 0 returned 4 4: 162: strcpy(p, t); 4: 163: break; unconditional 0 taken 4 -: 164: } -: 165: } -: 166: 309: 167: return p; 309: 167-block 0 unconditional 0 taken 309 -: 168:} -: 169: -: 170:/* Change CliFM working directory to NEW_PATH */ -: 171:int function cd_function called 336 returned 100% blocks executed 61% 336: 172:cd_function(char *new_path, const int print_error) -: 173:{ -: 174: /* If no argument, change to home */ 336: 175: if (!new_path || !*new_path) { 336: 175-block 0 branch 0 taken 332 (fallthrough) branch 1 taken 4 332: 175-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 332 4: 176: if (!user.home) { 4: 176-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 4 #####: 177: if (print_error) { %%%%%: 177-block 0 branch 0 never executed branch 1 never executed #####: 178: fprintf(stderr, _("%s: cd: Home directory not found\n"), %%%%%: 178-block 0 call 0 never executed call 1 never executed unconditional 2 never executed -: 179: PROGRAM_NAME); -: 180: } #####: 181: return EXIT_FAILURE; %%%%%: 181-block 0 unconditional 0 never executed -: 182: } -: 183: 4: 184: if (xchdir(user.home, SET_TITLE) != EXIT_SUCCESS) { 4: 184-block 0 call 0 returned 4 branch 1 taken 0 (fallthrough) branch 2 taken 4 #####: 185: if (print_error) { %%%%%: 185-block 0 branch 0 never executed branch 1 never executed #####: 186: fprintf(stderr, "%s: cd: %s: %s\n", PROGRAM_NAME, call 0 never executed unconditional 1 never executed #####: 187: user.home, strerror(errno)); %%%%%: 187-block 0 call 0 never executed -: 188: } #####: 189: return EXIT_FAILURE; %%%%%: 189-block 0 unconditional 0 never executed -: 190: } -: 191: 4: 192: free(ws[cur_ws].path); 4: 193: ws[cur_ws].path = savestring(user.home, strlen(user.home)); 4: 193-block 0 call 0 returned 4 unconditional 1 taken 4 -: 194: } -: 195: -: 196: /* If we have some argument, dequote it, resolve it with realpath(), -: 197: * cd into the resolved path, and set the path variable to this -: 198: * latter */ -: 199: else { 332: 200: if (strchr(new_path, '\\')) { 332: 200-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 332 #####: 201: char *deq_path = dequote_str(new_path, 0); %%%%%: 201-block 0 call 0 never executed #####: 202: if (deq_path) { branch 0 never executed branch 1 never executed #####: 203: strcpy(new_path, deq_path); #####: 204: free(deq_path); %%%%%: 204-block 0 unconditional 0 never executed -: 205: } -: 206: } -: 207: 332: 208: char *p = check_cdpath(new_path); 332: 208-block 0 call 0 returned 332 332: 209: char *q = realpath(p ? p : new_path, NULL); branch 0 taken 4 (fallthrough) branch 1 taken 328 4: 209-block 0 unconditional 2 taken 4 328: 209-block 1 unconditional 3 taken 328 332: 209-block 2 call 4 returned 332 332: 210: if (!q) { branch 0 taken 284 (fallthrough) branch 1 taken 48 284: 211: if (print_error) { 284: 211-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 284 #####: 212: fprintf(stderr, "%s: cd: %s: %s\n", PROGRAM_NAME, branch 0 never executed branch 1 never executed %%%%%: 212-block 0 unconditional 2 never executed %%%%%: 212-block 1 unconditional 3 never executed %%%%%: 212-block 2 call 4 never executed unconditional 5 never executed #####: 213: p ? p : new_path, strerror(errno)); %%%%%: 213-block 0 call 0 never executed -: 214: } 284: 215: free(p); 284: 216: return EXIT_FAILURE; 284: 216-block 0 unconditional 0 taken 284 -: 217: } 48: 218: free(p); -: 219: 48: 220: if (xchdir(q, SET_TITLE) != EXIT_SUCCESS) { 48: 220-block 0 call 0 returned 48 branch 1 taken 9 (fallthrough) branch 2 taken 39 9: 221: if (print_error) { 9: 221-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 9 #####: 222: fprintf(stderr, "%s: cd: %s: %s\n", PROGRAM_NAME, call 0 never executed unconditional 1 never executed #####: 223: q, strerror(errno)); %%%%%: 223-block 0 call 0 never executed -: 224: } 9: 225: free(q); 9: 226: return EXIT_FAILURE; 9: 226-block 0 unconditional 0 taken 9 -: 227: } -: 228: 39: 229: free(ws[cur_ws].path); 39: 230: ws[cur_ws].path = savestring(q, strlen(q)); 39: 230-block 0 call 0 returned 39 39: 231: free(q); unconditional 0 taken 39 -: 232: } -: 233: 43: 234: int exit_status = EXIT_SUCCESS; 43: 235: add_to_dirhist(ws[cur_ws].path); 43: 235-block 0 call 0 returned 43 -: 236: 43: 237: if (cd_lists_on_the_fly) { branch 0 taken 43 (fallthrough) branch 1 taken 0 43: 238: free_dirlist(); 43: 238-block 0 call 0 returned 43 43: 239: if (list_dir() != EXIT_SUCCESS) call 0 returned 43 branch 1 taken 0 (fallthrough) branch 2 taken 43 #####: 240: exit_status = EXIT_FAILURE; %%%%%: 240-block 0 unconditional 0 never executed -: 241: } -: 242: 43: 243: add_to_jumpdb(ws[cur_ws].path); 43: 243-block 0 call 0 returned 43 43: 244: return exit_status; unconditional 0 taken 43 -: 245:} -: 246: -: 247:/* Convert ... n into ../.. n */ -: 248:char * function fastback called 3 returned 100% blocks executed 68% 3: 249:fastback(const char *str) -: 250:{ 3: 251: if (!str || !*str) 3: 251-block 0 branch 0 taken 3 (fallthrough) branch 1 taken 0 3: 251-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 3 #####: 252: return (char *)NULL; %%%%%: 252-block 0 unconditional 0 never executed -: 253: 3: 254: char *p = (char *)str; 3: 255: size_t dots = 0; -: 256: 3: 257: char *rem = (char *)NULL; 12: 258: while (*p) { 3: 258-block 0 unconditional 0 taken 3 12: 258-block 1 branch 1 taken 9 branch 2 taken 3 (fallthrough) 9: 259: if (*p != '.') { 9: 259-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 9 #####: 260: rem = p; #####: 261: break; %%%%%: 261-block 0 unconditional 0 never executed -: 262: } 9: 263: dots++; 9: 264: p++; 9: 264-block 0 unconditional 0 taken 9 -: 265: } -: 266: 3: 267: if (dots <= 2) 3: 267-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 3 #####: 268: return (char *)NULL; %%%%%: 268-block 0 unconditional 0 never executed -: 269: 3: 270: char *q = (char *)NULL; 3: 271: if (rem) 3: 271-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 3 #####: 272: q = (char *)xnmalloc((dots * 3 + strlen(rem) + 2), sizeof(char)); %%%%%: 272-block 0 call 0 never executed unconditional 1 never executed -: 273: else 3: 274: q = (char *)xnmalloc((dots * 3), sizeof(char)); 3: 274-block 0 call 0 returned 3 unconditional 1 taken 3 -: 275: 3: 276: q[0] = '.'; 3: 277: q[1] = '.'; -: 278: 3: 279: size_t i, c = 2; 6: 280: for (i = 2; c < dots;) { 3: 280-block 0 unconditional 0 taken 3 6: 280-block 1 branch 1 taken 3 branch 2 taken 3 (fallthrough) 3: 281: q[i++] = '/'; 3: 282: q[i++] = '.'; 3: 283: q[i++] = '.'; 3: 284: c++; 3: 284-block 0 unconditional 0 taken 3 -: 285: } -: 286: 3: 287: q[i] = '\0'; -: 288: 3: 289: if (rem) { 3: 289-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 3 #####: 290: if (*rem != '/') { %%%%%: 290-block 0 branch 0 never executed branch 1 never executed #####: 291: q[i] = '/'; #####: 292: q[i + 1] = '\0'; %%%%%: 292-block 0 unconditional 0 never executed -: 293: } #####: 294: strcat(q, rem); %%%%%: 294-block 0 unconditional 0 never executed -: 295: } -: 296: 3: 297: return q; 3: 297-block 0 unconditional 0 taken 3 -: 298:} -: 299: -: 300:static int function surf_hist called 2 returned 100% blocks executed 41% 2: 301:surf_hist(char **comm) -: 302:{ 2*: 303: if (*comm[1] == 'h' && (strcmp(comm[1], "h") == 0 2: 303-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 2 %%%%%: 303-block 1 branch 2 never executed branch 3 never executed #####: 304: || strcmp(comm[1], "hist") == 0)) { %%%%%: 304-block 0 branch 0 never executed branch 1 never executed -: 305: /* Print the list of already visited directories */ -: 306: int i; #####: 307: for (i = 0; i < dirhist_total_index; i++) { %%%%%: 307-block 0 unconditional 0 never executed %%%%%: 307-block 1 unconditional 1 never executed %%%%%: 307-block 2 branch 2 never executed branch 3 never executed #####: 308: if (!old_pwd[i] || *old_pwd[i] == _ESC) %%%%%: 308-block 0 branch 0 never executed branch 1 never executed %%%%%: 308-block 1 branch 2 never executed branch 3 never executed #####: 309: continue; %%%%%: 309-block 0 unconditional 0 never executed #####: 310: if (i == dirhist_cur_index) %%%%%: 310-block 0 branch 0 never executed branch 1 never executed #####: 311: printf(" %d %s%s%s\n", i + 1, dh_c, old_pwd[i], df_c); %%%%%: 311-block 0 call 0 never executed unconditional 1 never executed -: 312: else #####: 313: printf(" %d %s\n", i + 1, old_pwd[i]); %%%%%: 313-block 0 call 0 never executed unconditional 1 never executed -: 314: } #####: 315: return EXIT_SUCCESS; %%%%%: 315-block 0 unconditional 0 never executed -: 316: } -: 317: 2*: 318: if (*comm[1] == 'c' && strcmp(comm[1], "clear") == 0) { 2: 318-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 2 %%%%%: 318-block 1 branch 2 never executed branch 3 never executed #####: 319: int i = dirhist_total_index; #####: 320: while (--i >= 0) %%%%%: 320-block 0 unconditional 0 never executed %%%%%: 320-block 1 branch 1 never executed branch 2 never executed #####: 321: free(old_pwd[i]); %%%%%: 321-block 0 unconditional 0 never executed #####: 322: dirhist_cur_index = dirhist_total_index = 0; #####: 323: add_to_dirhist(ws[cur_ws].path); %%%%%: 323-block 0 call 0 never executed #####: 324: return EXIT_SUCCESS; unconditional 0 never executed -: 325: } -: 326: 2: 327: int exit_status = EXIT_FAILURE; -: 328: 4: 329: if (*comm[1] == '!' && is_number(comm[1] + 1) == 1) { 2: 329-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 0 2: 329-block 1 call 2 returned 2 branch 3 taken 2 (fallthrough) branch 4 taken 0 2: 329-block 2 unconditional 5 taken 2 -: 330: /* Go the the specified directory (first arg) in the directory -: 331: * history list */ 2: 332: int atoi_comm = atoi(comm[1] + 1); 4: 333: if (atoi_comm > 0 && atoi_comm <= dirhist_total_index) { 2: 333-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 0 2: 333-block 1 branch 2 taken 2 (fallthrough) branch 3 taken 0 2: 333-block 2 unconditional 4 taken 2 2: 334: if (!old_pwd[atoi_comm - 1] || *old_pwd[atoi_comm - 1] == _ESC) { 2: 334-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 0 2: 334-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 2 #####: 335: fprintf(stderr, _("%s: Invalid history entry\n"), PROGRAM_NAME); %%%%%: 335-block 0 call 0 never executed call 1 never executed #####: 336: exit_status = EXIT_FAILURE; #####: 337: return exit_status; unconditional 0 never executed -: 338: } 2: 339: int ret = xchdir(old_pwd[atoi_comm - 1], SET_TITLE); 2: 339-block 0 call 0 returned 2 2: 340: if (ret == 0) { branch 0 taken 2 (fallthrough) branch 1 taken 0 2: 341: free(ws[cur_ws].path); 4: 342: ws[cur_ws].path = (char *)xnmalloc(strlen( 2: 343: old_pwd[atoi_comm - 1]) + 1, sizeof(char)); 2: 343-block 0 call 0 returned 2 2: 344: strcpy(ws[cur_ws].path, old_pwd[atoi_comm - 1]); -: 345: 2: 346: dirhist_cur_index = atoi_comm - 1; -: 347: 2: 348: exit_status = EXIT_SUCCESS; -: 349: 2: 350: if (cd_lists_on_the_fly) { branch 0 taken 2 (fallthrough) branch 1 taken 0 2: 351: free_dirlist(); 2: 351-block 0 call 0 returned 2 2: 352: exit_status = list_dir(); call 0 returned 2 unconditional 1 taken 2 -: 353: } -: 354: } else { #####: 355: fprintf(stderr, "%s: %s: %s\n", PROGRAM_NAME, #####: 356: old_pwd[atoi_comm - 1], strerror(errno)); %%%%%: 356-block 0 call 0 never executed call 1 never executed unconditional 2 never executed -: 357: } -: 358: } else { #####: 359: fprintf(stderr, _("history: %d: No such ELN\n"), call 0 never executed unconditional 1 never executed #####: 360: atoi(comm[1] + 1)); %%%%%: 360-block 0 call 0 never executed -: 361: } -: 362: } else { #####: 363: fprintf(stderr, "%s\n", _(DIRHIST_USAGE)); %%%%%: 363-block 0 call 0 never executed call 1 never executed unconditional 2 never executed -: 364: } -: 365: 2: 366: return exit_status; 2: 366-block 0 unconditional 0 taken 2 -: 367:} -: 368: -: 369:/* Go back one entry in dirhist */ -: 370:int function back_function called 25 returned 100% blocks executed 57% 25: 371:back_function(char **comm) -: 372:{ 25: 373: if (!comm) 25: 373-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 25 #####: 374: return EXIT_FAILURE; %%%%%: 374-block 0 unconditional 0 never executed -: 375: 25: 376: if (comm[1]) { 25: 376-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 23 2*: 377: if (*comm[1] == '-' && strcmp(comm[1], "--help") == 0) { 2: 377-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 2 %%%%%: 377-block 1 branch 2 never executed branch 3 never executed #####: 378: puts(_(BACK_USAGE)); %%%%%: 378-block 0 call 0 never executed call 1 never executed #####: 379: return EXIT_SUCCESS; unconditional 0 never executed -: 380: } 2: 381: return surf_hist(comm); 2: 381-block 0 call 0 returned 2 unconditional 1 taken 2 -: 382: } -: 383: -: 384: /* If just 'back', with no arguments */ -: 385: -: 386: /* If first path in current dirhist was reached, do nothing */ 23: 387: if (dirhist_cur_index <= 0) 23: 387-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 23 #####: 388: return EXIT_SUCCESS; %%%%%: 388-block 0 unconditional 0 never executed -: 389: 23: 390: int exit_status = EXIT_FAILURE; 23: 391: dirhist_cur_index--; -: 392: 23: 393: if (!old_pwd[dirhist_cur_index] || *old_pwd[dirhist_cur_index] == _ESC) { 23: 393-block 0 branch 0 taken 23 (fallthrough) branch 1 taken 0 23: 393-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 23 #####: 394: if (dirhist_cur_index) %%%%%: 394-block 0 branch 0 never executed branch 1 never executed #####: 395: dirhist_cur_index--; %%%%%: 395-block 0 unconditional 0 never executed -: 396: else #####: 397: return exit_status; %%%%%: 397-block 0 unconditional 0 never executed -: 398: } -: 399: 23: 400: if (xchdir(old_pwd[dirhist_cur_index], SET_TITLE) == EXIT_SUCCESS) { 23: 400-block 0 call 0 returned 23 branch 1 taken 23 (fallthrough) branch 2 taken 0 23: 401: free(ws[cur_ws].path); 46: 402: ws[cur_ws].path = savestring(old_pwd[dirhist_cur_index], 23: 403: strlen(old_pwd[dirhist_cur_index])); 23: 403-block 0 call 0 returned 23 -: 404: 23: 405: exit_status = EXIT_SUCCESS; 23: 406: add_to_jumpdb(ws[cur_ws].path); call 0 returned 23 -: 407: 23: 408: if (cd_lists_on_the_fly) { branch 0 taken 23 (fallthrough) branch 1 taken 0 23: 409: free_dirlist(); 23: 409-block 0 call 0 returned 23 23: 410: exit_status = list_dir(); call 0 returned 23 unconditional 1 taken 23 -: 411: } -: 412: } else { #####: 413: fprintf(stderr, "%s: %s: %s\n", PROGRAM_NAME, #####: 414: old_pwd[dirhist_cur_index], strerror(errno)); %%%%%: 414-block 0 call 0 never executed call 1 never executed -: 415: /* Invalidate this entry */ #####: 416: *old_pwd[dirhist_cur_index] = _ESC; #####: 417: if (dirhist_cur_index) branch 0 never executed branch 1 never executed #####: 418: dirhist_cur_index--; %%%%%: 418-block 0 unconditional 0 never executed -: 419: } -: 420: 23: 421: return exit_status; 23: 421-block 0 unconditional 0 taken 23 -: 422:} -: 423: -: 424:/* Go forth one entry in dirhist */ -: 425:int function forth_function called 3 returned 100% blocks executed 47% 3: 426:forth_function(char **comm) -: 427:{ 3: 428: if (!comm) 3: 428-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 3 #####: 429: return EXIT_FAILURE; %%%%%: 429-block 0 unconditional 0 never executed -: 430: 3: 431: if (comm[1]) { 3: 431-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 3 #####: 432: if (*comm[1] == '-' && strcmp(comm[1], "--help") == 0) { %%%%%: 432-block 0 branch 0 never executed branch 1 never executed %%%%%: 432-block 1 branch 2 never executed branch 3 never executed #####: 433: puts(_(FORTH_USAGE)); %%%%%: 433-block 0 call 0 never executed call 1 never executed #####: 434: return EXIT_SUCCESS; unconditional 0 never executed -: 435: } #####: 436: return surf_hist(comm); %%%%%: 436-block 0 call 0 never executed unconditional 1 never executed -: 437: } -: 438: -: 439: /* If just 'forth', with no arguments */ -: 440: -: 441: /* If last path in dirhist was reached, do nothing */ 3: 442: if (dirhist_cur_index + 1 >= dirhist_total_index) 3: 442-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 3 #####: 443: return EXIT_SUCCESS; %%%%%: 443-block 0 unconditional 0 never executed -: 444: 3: 445: int exit_status = EXIT_FAILURE; 3: 446: dirhist_cur_index++; -: 447: 3: 448: if (!old_pwd[dirhist_cur_index] || *old_pwd[dirhist_cur_index] == _ESC) { 3: 448-block 0 branch 0 taken 3 (fallthrough) branch 1 taken 0 3: 448-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 3 #####: 449: if (dirhist_cur_index < dirhist_total_index) %%%%%: 449-block 0 branch 0 never executed branch 1 never executed #####: 450: dirhist_cur_index++; %%%%%: 450-block 0 unconditional 0 never executed -: 451: else #####: 452: return exit_status; %%%%%: 452-block 0 unconditional 0 never executed -: 453: } -: 454: 3: 455: if (xchdir(old_pwd[dirhist_cur_index], SET_TITLE) == EXIT_SUCCESS) { 3: 455-block 0 call 0 returned 3 branch 1 taken 3 (fallthrough) branch 2 taken 0 3: 456: free(ws[cur_ws].path); 6: 457: ws[cur_ws].path = savestring(old_pwd[dirhist_cur_index], 3: 458: strlen(old_pwd[dirhist_cur_index])); 3: 458-block 0 call 0 returned 3 -: 459: 3: 460: add_to_jumpdb(ws[cur_ws].path); call 0 returned 3 3: 461: exit_status = EXIT_SUCCESS; -: 462: 3: 463: if (cd_lists_on_the_fly) { branch 0 taken 3 (fallthrough) branch 1 taken 0 3: 464: free_dirlist(); 3: 464-block 0 call 0 returned 3 3: 465: exit_status = list_dir(); call 0 returned 3 unconditional 1 taken 3 -: 466: } -: 467: } else { #####: 468: fprintf(stderr, "%s: %s: %s\n", PROGRAM_NAME, #####: 469: old_pwd[dirhist_cur_index], strerror(errno)); %%%%%: 469-block 0 call 0 never executed call 1 never executed -: 470: /* Invalidate this entry */ #####: 471: *old_pwd[dirhist_cur_index] = _ESC; #####: 472: if (dirhist_cur_index < dirhist_total_index) branch 0 never executed branch 1 never executed #####: 473: dirhist_cur_index++; %%%%%: 473-block 0 unconditional 0 never executed -: 474: } -: 475: 3: 476: return exit_status; 3: 476-block 0 unconditional 0 taken 3 -: 477:} clifm-1.26.3/misc/codecov/profiles.c.gcov000066400000000000000000001006261506632037700202140ustar00rootroot00000000000000 -: 0:Source:profiles.c -: 1:/* profiles.c -- functions controlling user profiles */ -: 2: -: 3:/* -: 4: * This file is part of CliFM -: 5: * -: 6: * Copyright (C) 2016-2021, L. Abramovich -: 7: * All rights reserved. -: 8: -: 9: * CliFM is free software; you can redistribute it and/or modify -: 10: * it under the terms of the GNU General Public License as published by -: 11: * the Free Software Foundation; either version 2 of the License, or -: 12: * (at your option) any later version. -: 13: * -: 14: * CliFM is distributed in the hope that it will be useful, -: 15: * but WITHOUT ANY WARRANTY; without even the implied warranty of -: 16: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -: 17: * GNU General Public License for more details. -: 18: * -: 19: * You should have received a copy of the GNU General Public License -: 20: * along with this program; if not, write to the Free Software -: 21: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, -: 22: * MA 02110-1301, USA. -: 23:*/ -: 24: -: 25:#include "helpers.h" -: 26: -: 27:#include -: 28:#include -: 29:#include -: 30:#include -: 31:#include -: 32:#include -: 33: -: 34:#include "actions.h" -: 35:#include "aux.h" -: 36:#include "bookmarks.h" -: 37:#include "checks.h" -: 38:#include "config.h" -: 39:#include "exec.h" -: 40:#include "history.h" -: 41:#include "init.h" -: 42:#include "listing.h" -: 43:#include "mime.h" -: 44:#include "misc.h" -: 45:#include "navigation.h" -: 46:#include "profiles.h" -: 47:#include "sort.h" -: 48:#include "messages.h" -: 49: -: 50:int function get_profile_names called 6 returned 100% blocks executed 89% 6: 51:get_profile_names(void) -: 52:{ 6: 53: if (!config_dir_gral) 6: 53-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 6 #####: 54: return EXIT_FAILURE; %%%%%: 54-block 0 unconditional 0 never executed -: 55: 6: 56: char *pf_dir = (char *)xnmalloc(strlen(config_dir_gral) + 10, sizeof(char)); 6: 56-block 0 call 0 returned 6 6: 57: sprintf(pf_dir, "%s/profiles", config_dir_gral); -: 58: 6: 59: struct dirent **profs = (struct dirent **)NULL; 6: 60: int files_n = scandir(pf_dir, &profs, NULL, xalphasort); call 0 returned 6 -: 61: 6: 62: if (files_n == -1) { branch 0 taken 0 (fallthrough) branch 1 taken 6 #####: 63: free(pf_dir); #####: 64: return EXIT_FAILURE; %%%%%: 64-block 0 unconditional 0 never executed -: 65: } -: 66: 6: 67: size_t i, pf_n = 0; -: 68:#if !defined(_DIRENT_HAVE_D_TYPE) -: 69: struct stat attr; -: 70:#endif -: 71: 45: 72: for (i = 0; i < (size_t)files_n; i++) { 6: 72-block 0 unconditional 0 taken 6 45: 72-block 1 branch 1 taken 39 branch 2 taken 6 (fallthrough) -: 73: -: 74:#if !defined(_DIRENT_HAVE_D_TYPE) -: 75: char tmp[PATH_MAX]; -: 76: snprintf(tmp, PATH_MAX - 1, "%s/%s", pf_dir,profs[i]->d_name); -: 77: if (lstat(tmp, &attr) == -1) -: 78: continue; -: 79: if ((attr.st_mode & S_IFMT) == S_IFDIR -: 80:#else 39: 81: if (profs[i]->d_type == DT_DIR 39: 81-block 0 branch 0 taken 39 (fallthrough) branch 1 taken 0 -: 82:#endif -: 83: /* Discard ".", "..", and hidden dirs */ 39: 84: && *profs[i]->d_name != '.') { 39: 84-block 0 branch 0 taken 27 (fallthrough) branch 1 taken 12 27: 85: profile_names = (char **)xrealloc(profile_names, (pf_n + 1) 27: 85-block 0 call 0 returned 27 -: 86: * sizeof(char *)); 27: 87: profile_names[pf_n++] = savestring(profs[i]->d_name, unconditional 0 taken 27 27: 88: strlen(profs[i]->d_name)); call 0 returned 27 -: 89: } -: 90: 39: 91: free(profs[i]); 39: 91-block 0 unconditional 0 taken 39 -: 92: } -: 93: 6: 94: free(pf_dir); 6: 95: free(profs); -: 96: 6: 97: profile_names = (char **)xrealloc(profile_names, (pf_n + 1) * sizeof(char *)); 6: 97-block 0 call 0 returned 6 6: 98: profile_names[pf_n] = (char *)NULL; -: 99: 6: 100: return EXIT_SUCCESS; unconditional 0 taken 6 -: 101:} -: 102: -: 103:int function profile_function called 4 returned 100% blocks executed 51% 4: 104:profile_function(char **comm) -: 105:{ 4: 106: if (xargs.stealth_mode == 1) { 4: 106-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 4 #####: 107: printf("%s: The profile function is disabled in stealth mode\n", %%%%%: 107-block 0 call 0 never executed -: 108: PROGRAM_NAME); #####: 109: return EXIT_SUCCESS; unconditional 0 never executed -: 110: } -: 111: 4: 112: int exit_status = EXIT_SUCCESS; -: 113: 4: 114: if (comm[1]) { 4: 114-block 0 branch 0 taken 4 (fallthrough) branch 1 taken 0 4*: 115: if (*comm[1] == '-' && strcmp(comm[1], "--help") == 0) 4: 115-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 4 %%%%%: 115-block 1 branch 2 never executed branch 3 never executed #####: 116: puts(_(PROFILES_USAGE)); %%%%%: 116-block 0 call 0 never executed call 1 never executed unconditional 2 never executed -: 117: -: 118: /* List profiles */ 4: 119: else if (comm[1] && (strcmp(comm[1], "ls") == 0 4: 119-block 0 branch 0 taken 4 (fallthrough) branch 1 taken 0 4: 119-block 1 branch 2 taken 4 (fallthrough) branch 3 taken 0 4*: 120: || strcmp(comm[1], "list") == 0)) { 4: 120-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 4 %%%%%: 120-block 1 unconditional 2 never executed -: 121: size_t i; -: 122: #####: 123: for (i = 0; profile_names[i]; i++) %%%%%: 123-block 0 unconditional 0 never executed unconditional 1 never executed %%%%%: 123-block 1 branch 2 never executed branch 3 never executed #####: 124: printf("%s\n", profile_names[i]); %%%%%: 124-block 0 call 0 never executed -: 125: } -: 126: -: 127: /* Create a new profile */ 4: 128: else if (strcmp(comm[1], "add") == 0) 4: 128-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 3 -: 129: 1: 130: if (comm[2]) { 1: 130-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 0 1: 131: exit_status = profile_add(comm[2]); 1: 131-block 0 call 0 returned 1 unconditional 1 taken 1 -: 132: } -: 133: -: 134: else { #####: 135: fprintf(stderr, "%s\n", PROFILES_USAGE); %%%%%: 135-block 0 call 0 never executed #####: 136: exit_status = EXIT_FAILURE; unconditional 0 never executed -: 137: } -: 138: -: 139: /* Delete a profile */ 3: 140: else if (*comm[1] == 'd' && strcmp(comm[1], "del") == 0) 3: 140-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 2 1: 140-block 1 branch 2 taken 1 (fallthrough) branch 3 taken 0 1: 141: if (comm[2]) 1: 141-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 0 1: 142: exit_status = profile_del(comm[2]); 1: 142-block 0 call 0 returned 1 unconditional 1 taken 1 -: 143: else { #####: 144: fprintf(stderr, "%s\n", PROFILES_USAGE); %%%%%: 144-block 0 call 0 never executed #####: 145: exit_status = EXIT_FAILURE; unconditional 0 never executed -: 146: } -: 147: -: 148: /* Switch to another profile */ 2: 149: else if (*comm[1] == 's' && strcmp(comm[1], "set") == 0) { 2: 149-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 0 2: 149-block 1 branch 2 taken 2 (fallthrough) branch 3 taken 0 -: 150: 2: 151: if (comm[2]) 2: 151-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 0 2: 152: exit_status = profile_set(comm[2]); 2: 152-block 0 call 0 returned 2 unconditional 1 taken 2 -: 153: -: 154: else { #####: 155: fprintf(stderr, "%s\n", PROFILES_USAGE); %%%%%: 155-block 0 call 0 never executed #####: 156: exit_status = EXIT_FAILURE; unconditional 0 never executed -: 157: } -: 158: } -: 159: -: 160: /* None of the above == error */ -: 161: else { #####: 162: fprintf(stderr, "%s\n", PROFILES_USAGE); %%%%%: 162-block 0 call 0 never executed #####: 163: exit_status = EXIT_FAILURE; unconditional 0 never executed -: 164: } -: 165: } -: 166: -: 167: /* If only "pr" print the current profile name */ #####: 168: else if (!alt_profile) %%%%%: 168-block 0 branch 0 never executed branch 1 never executed #####: 169: printf("%s: profile: default\n", PROGRAM_NAME); %%%%%: 169-block 0 call 0 never executed unconditional 1 never executed -: 170: -: 171: else #####: 172: printf("%s: profile: '%s'\n", PROGRAM_NAME, alt_profile); %%%%%: 172-block 0 call 0 never executed unconditional 1 never executed -: 173: 4: 174: return exit_status; 4: 174-block 0 unconditional 0 taken 4 -: 175:} -: 176: -: 177:/* Switch profile to PROF */ -: 178:int function profile_set called 9 returned 100% blocks executed 73% 9: 179:profile_set(const char *prof) -: 180:{ 9: 181: if (xargs.stealth_mode == 1) { 9: 181-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 9 #####: 182: printf("%s: The profile function is disabled in stealth mode\n", %%%%%: 182-block 0 call 0 never executed -: 183: PROGRAM_NAME); #####: 184: return EXIT_SUCCESS; unconditional 0 never executed -: 185: } -: 186: 9: 187: if (!prof) 9: 187-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 9 #####: 188: return EXIT_FAILURE; %%%%%: 188-block 0 unconditional 0 never executed -: 189: -: 190: /* Check if prof is a valid profile */ 9: 191: int found = 0; -: 192: int i; -: 193: 21: 194: for (i = 0; profile_names[i]; i++) { 9: 194-block 0 unconditional 0 taken 9 12: 194-block 1 unconditional 1 taken 12 21: 194-block 2 branch 2 taken 21 branch 3 taken 0 (fallthrough) -: 195: 21: 196: if (*prof == *profile_names[i] && strcmp(prof, profile_names[i]) == 0) { 21: 196-block 0 branch 0 taken 12 (fallthrough) branch 1 taken 9 12: 196-block 1 branch 2 taken 9 (fallthrough) branch 3 taken 3 9: 197: found = 1; 9: 198: break; 9: 198-block 0 unconditional 0 taken 9 -: 199: } -: 200: } -: 201: 9: 202: if (!found) { 9: 202-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 9 #####: 203: fprintf(stderr, _("%s: %s: No such profile\nTo add a new " %%%%%: 203-block 0 call 0 never executed call 1 never executed -: 204: "profile enter 'pf add PROFILE'\n"), -: 205: PROGRAM_NAME, prof); -: 206: #####: 207: return EXIT_FAILURE; unconditional 0 never executed -: 208: } -: 209: -: 210: /* If changing to the current profile, do nothing */ 9*: 211: if ((!alt_profile && *prof == 'd' && strcmp(prof, "default") == 0) 9: 211-block 0 branch 0 taken 3 (fallthrough) branch 1 taken 6 3: 211-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 3 %%%%%: 211-block 2 branch 4 never executed branch 5 never executed 9: 212: || (alt_profile && *prof == *alt_profile && strcmp(prof, alt_profile) == 0)) { 9: 212-block 0 branch 0 taken 6 (fallthrough) branch 1 taken 3 6: 212-block 1 branch 2 taken 2 (fallthrough) branch 3 taken 4 2: 212-block 2 branch 4 taken 0 (fallthrough) branch 5 taken 2 -: 213: #####: 214: printf(_("%s: '%s' is the current profile\n"), PROGRAM_NAME, %%%%%: 214-block 0 call 0 never executed call 1 never executed -: 215: prof); -: 216: #####: 217: return EXIT_SUCCESS; unconditional 0 never executed -: 218: } -: 219: 9: 220: if (restore_last_path) 9: 220-block 0 branch 0 taken 5 (fallthrough) branch 1 taken 4 5: 221: save_last_path(); 5: 221-block 0 call 0 returned 5 unconditional 1 taken 5 -: 222: 9: 223: if (alt_profile) { 9: 223-block 0 branch 0 taken 6 (fallthrough) branch 1 taken 3 6: 224: free(alt_profile); 6: 225: alt_profile = (char *)NULL; 6: 225-block 0 unconditional 0 taken 6 -: 226: } -: 227: -: 228: /* Set the new profile value */ -: 229: /* Default profile == (alt_profile == NULL) */ 9: 230: if (*prof != 'd' || strcmp(prof, "default") != 0) 9: 230-block 0 branch 0 taken 3 (fallthrough) branch 1 taken 6 3: 230-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 3 6: 231: alt_profile = savestring(prof, strlen(prof)); 6: 231-block 0 call 0 returned 6 unconditional 1 taken 6 -: 232: -: 233: /* Reset everything */ 9: 234: reload_config(); 9: 234-block 0 call 0 returned 9 -: 235: -: 236: /* Check whether we have a working shell */ 9: 237: if (access(user.shell, X_OK) == -1) { call 0 returned 9 branch 1 taken 0 (fallthrough) branch 2 taken 9 #####: 238: _err('w', PRINT_PROMPT, _("%s: %s: System shell not found. Please " %%%%%: 238-block 0 call 0 never executed call 1 never executed unconditional 2 never executed -: 239: "edit the configuration file to specify a working shell.\n"), -: 240: PROGRAM_NAME, user.shell); -: 241: } -: 242: 9: 243: i = (int)usrvar_n; 9: 244: while (--i >= 0) { 9: 244-block 0 unconditional 0 taken 9 9: 244-block 1 branch 1 taken 0 branch 2 taken 9 (fallthrough) #####: 245: free(usr_var[i].name); #####: 246: free(usr_var[i].value); %%%%%: 246-block 0 unconditional 0 never executed -: 247: } 9: 248: usrvar_n = 0; -: 249: 9: 250: i = (int)kbinds_n; 80: 251: while (--i >= 0) { 9: 251-block 0 unconditional 0 taken 9 80: 251-block 1 branch 1 taken 71 branch 2 taken 9 (fallthrough) 71: 252: free(kbinds[i].function); 71: 253: free(kbinds[i].key); 71: 253-block 0 unconditional 0 taken 71 -: 254: } 9: 255: kbinds_n = 0; -: 256: 9: 257: i = (int)actions_n; 144: 258: while (--i >= 0) { 9: 258-block 0 unconditional 0 taken 9 144: 258-block 1 branch 1 taken 135 branch 2 taken 9 (fallthrough) 135: 259: free(usr_actions[i].name); 135: 260: free(usr_actions[i].value); 135: 260-block 0 unconditional 0 taken 135 -: 261: } 9: 262: actions_n = 0; -: 263: -: 264: /* my_rl_unbind_functions(); -: 265: -: 266: create_kbinds_file(); -: 267: -: 268: load_keybinds(); -: 269: -: 270: rl_unbind_function_in_map(rl_hidden, rl_get_keymap()); -: 271: rl_bind_keyseq(find_key("toggle-hidden"), rl_hidden); -: 272: my_rl_bind_functions(); */ -: 273: 9: 274: exec_profile(); 9: 274-block 0 call 0 returned 9 -: 275: 9: 276: if (msgs_n) { branch 0 taken 0 (fallthrough) branch 1 taken 9 #####: 277: i = (int)msgs_n; #####: 278: while (--i >= 0) %%%%%: 278-block 0 unconditional 0 never executed %%%%%: 278-block 1 branch 1 never executed branch 2 never executed #####: 279: free(messages[i]); %%%%%: 279-block 0 unconditional 0 never executed -: 280: } 9: 281: msgs_n = 0; -: 282: 9: 283: if (config_ok) { 9: 283-block 0 branch 0 taken 9 (fallthrough) branch 1 taken 0 -: 284: /* Limit the log files size */ 9: 285: check_file_size(log_file, max_log); 9: 285-block 0 call 0 returned 9 9: 286: check_file_size(msg_log_file, max_log); call 0 returned 9 -: 287: -: 288: /* Reset history */ 9: 289: if (access(hist_file, F_OK | W_OK) == 0) { call 0 returned 9 branch 1 taken 9 (fallthrough) branch 2 taken 0 9: 290: clear_history(); /* This is for readline */ 9: 290-block 0 call 0 returned 9 9: 291: read_history(hist_file); call 0 returned 9 9: 292: history_truncate_file(hist_file, max_hist); call 0 returned 9 unconditional 1 taken 9 -: 293: } -: 294: -: 295: else { #####: 296: FILE *hist_fp = fopen(hist_file, "w"); %%%%%: 296-block 0 call 0 never executed -: 297: #####: 298: if (hist_fp) { branch 0 never executed branch 1 never executed #####: 299: fputs("edit\n", hist_fp); %%%%%: 299-block 0 call 0 never executed #####: 300: fclose(hist_fp); call 0 never executed unconditional 1 never executed -: 301: } -: 302: -: 303: else { #####: 304: _err('w', PRINT_PROMPT, _("%s: Error opening the " %%%%%: 304-block 0 call 0 never executed call 1 never executed unconditional 2 never executed -: 305: "history file\n"), PROGRAM_NAME); -: 306: } -: 307: } -: 308: 9: 309: get_history(); /* This is only for us */ 9: 309-block 0 call 0 returned 9 unconditional 1 taken 9 -: 310: } -: 311: 9: 312: free_bookmarks(); 9: 312-block 0 call 0 returned 9 9: 313: load_bookmarks(); call 0 returned 9 -: 314: 9: 315: load_actions(); call 0 returned 9 -: 316: -: 317: /* Reload PATH commands (actions are profile specific) */ 9: 318: if (bin_commands) { branch 0 taken 9 (fallthrough) branch 1 taken 0 -: 319: 26284: 320: for (i = 0; bin_commands[i]; i++) 9: 320-block 0 unconditional 0 taken 9 26284: 320-block 1 branch 1 taken 26275 branch 2 taken 9 (fallthrough) 26275: 321: free(bin_commands[i]); 26275: 321-block 0 unconditional 0 taken 26275 -: 322: 9: 323: free(bin_commands); 9: 324: bin_commands = (char **)NULL; 9: 324-block 0 unconditional 0 taken 9 -: 325: } -: 326: 9: 327: if (paths) { 9: 327-block 0 branch 0 taken 9 (fallthrough) branch 1 taken 0 -: 328: 9: 329: i = (int)path_n; 63: 330: while (--i >= 0) 9: 330-block 0 unconditional 0 taken 9 63: 330-block 1 branch 1 taken 54 branch 2 taken 9 (fallthrough) 54: 331: free(paths[i]); 54: 331-block 0 unconditional 0 taken 54 -: 332: } -: 333: 9: 334: path_n = (size_t)get_path_env(); 9: 334-block 0 call 0 returned 9 -: 335: 9: 336: get_path_programs(); call 0 returned 9 -: 337: 9: 338: i = MAX_WS; 81: 339: while (--i >= 0) { unconditional 0 taken 9 81: 339-block 0 branch 1 taken 72 branch 2 taken 9 (fallthrough) 72: 340: free(ws[i].path); 72: 341: ws[i].path = (char *)NULL; 72: 341-block 0 unconditional 0 taken 72 -: 342: } -: 343: 9: 344: cur_ws = UNSET; -: 345: 9: 346: if (restore_last_path) 9: 346-block 0 branch 0 taken 5 (fallthrough) branch 1 taken 4 5: 347: get_last_path(); 5: 347-block 0 call 0 returned 5 unconditional 1 taken 5 -: 348: 9: 349: if (cur_ws == UNSET) 9: 349-block 0 branch 0 taken 5 (fallthrough) branch 1 taken 4 5: 350: cur_ws = DEF_CUR_WS; 5: 350-block 0 unconditional 0 taken 5 -: 351: 9: 352: if (!ws[cur_ws].path) { 9: 352-block 0 branch 0 taken 5 (fallthrough) branch 1 taken 4 5: 353: char cwd[PATH_MAX] = ""; 5: 354: if (getcwd(cwd, sizeof(cwd)) == NULL) {} 5: 354-block 0 call 0 returned 5 5: 355: if (!*cwd) { branch 0 taken 0 (fallthrough) branch 1 taken 5 #####: 356: fprintf(stderr, "%s: %s\n", PROGRAM_NAME, strerror(errno)); %%%%%: 356-block 0 call 0 never executed call 1 never executed #####: 357: exit(EXIT_FAILURE); call 0 never executed -: 358: } 5: 359: ws[cur_ws].path = savestring(cwd, strlen(cwd)); 5: 359-block 0 call 0 returned 5 unconditional 1 taken 5 -: 360: } -: 361: 9: 362: if (xchdir(ws[cur_ws].path, SET_TITLE) == -1) { 9: 362-block 0 call 0 returned 9 branch 1 taken 0 (fallthrough) branch 2 taken 9 #####: 363: fprintf(stderr, "%s: %s: %s\n", PROGRAM_NAME, ws[cur_ws].path, call 0 never executed #####: 364: strerror(errno)); %%%%%: 364-block 0 call 0 never executed #####: 365: return EXIT_FAILURE; unconditional 0 never executed -: 366: } -: 367: 9: 368: int exit_status = EXIT_SUCCESS; -: 369: 9: 370: if (cd_lists_on_the_fly) { 9: 370-block 0 branch 0 taken 9 (fallthrough) branch 1 taken 0 9: 371: free_dirlist(); 9: 371-block 0 call 0 returned 9 9: 372: exit_status = list_dir(); call 0 returned 9 unconditional 1 taken 9 -: 373: } -: 374: 9: 375: return exit_status; 9: 375-block 0 unconditional 0 taken 9 -: 376:} -: 377: -: 378:int function profile_add called 1 returned 100% blocks executed 62% 1: 379:profile_add(const char *prof) -: 380:{ 1: 381: if (!prof) 1: 381-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 1 #####: 382: return EXIT_FAILURE; %%%%%: 382-block 0 unconditional 0 never executed -: 383: 1: 384: int found = 0; -: 385: size_t i; -: 386: 6: 387: for (i = 0; profile_names[i]; i++) { 1: 387-block 0 unconditional 0 taken 1 5: 387-block 1 unconditional 1 taken 5 6: 387-block 2 branch 2 taken 5 branch 3 taken 1 (fallthrough) -: 388: 5*: 389: if (*prof == *profile_names[i] && strcmp(prof, profile_names[i]) == 0) { 5: 389-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 5 %%%%%: 389-block 1 branch 2 never executed branch 3 never executed #####: 390: found = 1; #####: 391: break; %%%%%: 391-block 0 unconditional 0 never executed -: 392: } -: 393: } -: 394: 1: 395: if (found) { 1: 395-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 1 #####: 396: fprintf(stderr, _("%s: %s: Profile already exists\n"), PROGRAM_NAME, prof); %%%%%: 396-block 0 call 0 never executed call 1 never executed #####: 397: return EXIT_FAILURE; unconditional 0 never executed -: 398: } -: 399: 1: 400: if (!home_ok) { 1: 400-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 1 #####: 401: fprintf(stderr, _("%s: %s: Cannot create profile: Home " %%%%%: 401-block 0 call 0 never executed call 1 never executed -: 402: "directory not found\n"), PROGRAM_NAME, prof); #####: 403: return EXIT_FAILURE; unconditional 0 never executed -: 404: } -: 405: 1: 406: size_t pnl_len = strlen(PNL); -: 407: /* ### GENERATE PROGRAM'S CONFIG DIRECTORY NAME ### */ 1: 408: char *nconfig_dir = (char *)xnmalloc(strlen(config_dir_gral) + strlen(prof) + 11, sizeof(char)); 1: 408-block 0 call 0 returned 1 1: 409: sprintf(nconfig_dir, "%s/profiles/%s", config_dir_gral, prof); -: 410: -: 411: /* #### CREATE THE CONFIG DIR #### */ 1: 412: char *tmp_cmd[] = {"mkdir", "-p", nconfig_dir, NULL}; 1: 413: int ret = launch_execve(tmp_cmd, FOREGROUND, E_NOFLAG); call 0 returned 1 -: 414: 1: 415: if (ret != EXIT_SUCCESS) { branch 0 taken 0 (fallthrough) branch 1 taken 1 #####: 416: fprintf(stderr, _("%s: mkdir: %s: Error creating " %%%%%: 416-block 0 call 0 never executed call 1 never executed -: 417: "configuration directory\n"), PROGRAM_NAME, nconfig_dir); -: 418: #####: 419: free(nconfig_dir); -: 420: #####: 421: return EXIT_FAILURE; unconditional 0 never executed -: 422: } -: 423: -: 424: /* If the config dir is fine, generate config file names */ 1: 425: int exit_status = EXIT_SUCCESS; 1: 426: size_t config_len = strlen(nconfig_dir); -: 427: 1: 428: char *nconfig_file = (char *)xnmalloc(config_len + pnl_len + 4, 1: 428-block 0 call 0 returned 1 -: 429: sizeof(char)); 1: 430: sprintf(nconfig_file, "%s/%src", nconfig_dir, PNL); 1: 431: char *nhist_file = (char *)xnmalloc(config_len + 13, sizeof(char)); call 0 returned 1 1: 432: sprintf(nhist_file, "%s/history.cfm", nconfig_dir); 1: 433: char *nmime_file = (char *)xnmalloc(config_len + 14, sizeof(char)); call 0 returned 1 1: 434: sprintf(nmime_file, "%s/mimelist.cfm", nconfig_dir); -: 435: -: 436: /* Create config files */ -: 437: -: 438: /* #### CREATE THE HISTORY FILE #### */ 1: 439: FILE *hist_fp = fopen(nhist_file, "w+"); call 0 returned 1 -: 440: 1: 441: if (!hist_fp) { branch 0 taken 0 (fallthrough) branch 1 taken 1 #####: 442: fprintf(stderr, "%s: fopen: %s: %s\n", PROGRAM_NAME, call 0 never executed #####: 443: nhist_file, strerror(errno)); %%%%%: 443-block 0 call 0 never executed #####: 444: exit_status = EXIT_FAILURE; unconditional 0 never executed -: 445: } else { -: 446: /* To avoid malloc errors in read_history(), do not create -: 447: * an empty file */ 1: 448: fputs("edit\n", hist_fp); 1: 448-block 0 call 0 returned 1 1: 449: fclose(hist_fp); call 0 returned 1 unconditional 1 taken 1 -: 450: } -: 451: -: 452: /* #### CREATE THE MIME CONFIG FILE #### */ 1: 453: if (create_mime_file(nmime_file, 1) != EXIT_SUCCESS) 1: 453-block 0 call 0 returned 1 branch 1 taken 0 (fallthrough) branch 2 taken 1 #####: 454: exit_status = EXIT_FAILURE; %%%%%: 454-block 0 unconditional 0 never executed -: 455: -: 456: /* #### CREATE THE CONFIG FILE #### */ 1: 457: if (create_config(nconfig_file) != EXIT_SUCCESS) 1: 457-block 0 call 0 returned 1 branch 1 taken 0 (fallthrough) branch 2 taken 1 #####: 458: exit_status = EXIT_FAILURE; %%%%%: 458-block 0 unconditional 0 never executed -: 459: -: 460: /* Free stuff */ 1: 461: free(nconfig_dir); 1: 462: free(nconfig_file); 1: 463: free(nhist_file); 1: 464: free(nmime_file); -: 465: 1: 466: if (exit_status == EXIT_SUCCESS) { 1: 466-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 0 1: 467: printf(_("%s: '%s': Profile succesfully created\n"), PROGRAM_NAME, prof); 1: 467-block 0 call 0 returned 1 call 1 returned 1 -: 468: 6: 469: for (i = 0; profile_names[i]; i++) unconditional 0 taken 1 6: 469-block 0 branch 1 taken 5 branch 2 taken 1 (fallthrough) 5: 470: free(profile_names[i]); 5: 470-block 0 unconditional 0 taken 5 -: 471: 1: 472: get_profile_names(); 1: 472-block 0 call 0 returned 1 unconditional 1 taken 1 -: 473: } else { #####: 474: fprintf(stderr, _("%s: %s: Error creating profile\n"), %%%%%: 474-block 0 call 0 never executed call 1 never executed unconditional 2 never executed -: 475: PROGRAM_NAME, prof); -: 476: } -: 477: 1: 478: return exit_status; 1: 478-block 0 unconditional 0 taken 1 -: 479:} -: 480: -: 481:int function profile_del called 1 returned 100% blocks executed 70% 1: 482:profile_del(const char *prof) -: 483:{ 1: 484: if (xargs.stealth_mode == 1) { 1: 484-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 1 #####: 485: printf("%s: The profile function is disabled in stealth mode\n", %%%%%: 485-block 0 call 0 never executed -: 486: PROGRAM_NAME); #####: 487: return EXIT_SUCCESS; unconditional 0 never executed -: 488: } -: 489: 1: 490: if (!prof) 1: 490-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 1 #####: 491: return EXIT_FAILURE; %%%%%: 491-block 0 unconditional 0 never executed -: 492: -: 493: /* Check if prof is a valid profile */ 1: 494: int found = 0; -: 495: size_t i; 2: 496: for (i = 0; profile_names[i]; i++) { 1: 496-block 0 unconditional 0 taken 1 1: 496-block 1 unconditional 1 taken 1 2: 496-block 2 branch 2 taken 2 branch 3 taken 0 (fallthrough) 2: 497: if (*prof == *profile_names[i] && strcmp(prof, profile_names[i]) == 0) { 2: 497-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 1 1: 497-block 1 branch 2 taken 1 (fallthrough) branch 3 taken 0 1: 498: found = 1; 1: 499: break; 1: 499-block 0 unconditional 0 taken 1 -: 500: } -: 501: } -: 502: 1: 503: if (!found) { 1: 503-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 1 #####: 504: fprintf(stderr, _("%s: %s: No such profile\n"), PROGRAM_NAME, prof); %%%%%: 504-block 0 call 0 never executed call 1 never executed #####: 505: return EXIT_FAILURE; unconditional 0 never executed -: 506: } -: 507: 1: 508: char *tmp = (char *)xnmalloc(strlen(config_dir_gral) + strlen(prof) + 11, 1: 508-block 0 call 0 returned 1 -: 509: sizeof(char)); 1: 510: sprintf(tmp, "%s/profiles/%s", config_dir_gral, prof); -: 511: 1: 512: char *cmd[] = {"rm", "-r", tmp, NULL}; 1: 513: int ret = launch_execve(cmd, FOREGROUND, E_NOFLAG); call 0 returned 1 1: 514: free(tmp); -: 515: 1: 516: if (ret == EXIT_SUCCESS) { branch 0 taken 1 (fallthrough) branch 1 taken 0 1: 517: printf(_("%s: '%s': Profile successfully removed\n"), PROGRAM_NAME, prof); 1: 517-block 0 call 0 returned 1 call 1 returned 1 -: 518: 7: 519: for (i = 0; profile_names[i]; i++) unconditional 0 taken 1 7: 519-block 0 branch 1 taken 6 branch 2 taken 1 (fallthrough) 6: 520: free(profile_names[i]); 6: 520-block 0 unconditional 0 taken 6 -: 521: 1: 522: get_profile_names(); 1: 522-block 0 call 0 returned 1 -: 523: 1: 524: return EXIT_SUCCESS; unconditional 0 taken 1 -: 525: } -: 526: #####: 527: fprintf(stderr, _("%s: %s: Error removing profile\n"), PROGRAM_NAME, prof); %%%%%: 527-block 0 call 0 never executed call 1 never executed #####: 528: return EXIT_FAILURE; unconditional 0 never executed -: 529:} clifm-1.26.3/misc/codecov/prompt.c.gcov000066400000000000000000001234221506632037700177110ustar00rootroot00000000000000 -: 0:Source:prompt.c -: 1:/* prompt.c -- functions controlling the appearance and behaviour of the prompt */ -: 2: -: 3:/* -: 4: * This file is part of CliFM -: 5: * -: 6: * Copyright (C) 2016-2021, L. Abramovich -: 7: * All rights reserved. -: 8: -: 9: * CliFM is free software; you can redistribute it and/or modify -: 10: * it under the terms of the GNU General Public License as published by -: 11: * the Free Software Foundation; either version 2 of the License, or -: 12: * (at your option) any later version. -: 13: * -: 14: * CliFM is distributed in the hope that it will be useful, -: 15: * but WITHOUT ANY WARRANTY; without even the implied warranty of -: 16: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -: 17: * GNU General Public License for more details. -: 18: * -: 19: * You should have received a copy of the GNU General Public License -: 20: * along with this program; if not, write to the Free Software -: 21: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, -: 22: * MA 02110-1301, USA. -: 23:*/ -: 24: -: 25:#include "helpers.h" -: 26: -: 27:#include -: 28:#include -: 29:#if !defined(__HAIKU__) && !defined(__OpenBSD__) -: 30:#include -: 31:#endif -: 32:#include -: 33: -: 34:#include "aux.h" -: 35:#include "exec.h" -: 36:#include "history.h" -: 37:#include "init.h" -: 38:#include "listing.h" -: 39:#include "misc.h" -: 40:#include "navigation.h" -: 41:#include "prompt.h" -: 42:#ifndef _NO_TRASH -: 43:#include "trash.h" -: 44:#else -: 45:#include -: 46:#endif -: 47: -: 48:/* Decode the prompt string (encoded_prompt global variable) taken from -: 49: * the configuration file. Based on the decode_prompt_string function -: 50: * found in an old bash release (1.14.7). */ -: 51:static char * function decode_prompt called 509 returned 100% blocks executed 50% 509: 52:decode_prompt(const char *line) -: 53:{ 509: 54: if (!line) 509: 54-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 509 #####: 55: return (char *)NULL; %%%%%: 55-block 0 unconditional 0 never executed -: 56: -: 57:#define CTLESC '\001' -: 58:#define CTLNUL '\177' -: 59: 509: 60: char *temp = (char *)NULL, *result = (char *)NULL; 509: 61: size_t result_len = 0; -: 62: int c; -: 63: 37065: 64: while ((c = *line++)) { 509: 64-block 0 unconditional 0 taken 509 37065: 64-block 1 branch 1 taken 36556 branch 2 taken 509 (fallthrough) -: 65: /* We have an escape char */ 36556: 66: if (c == '\\') { 36556: 66-block 0 branch 0 taken 15214 (fallthrough) branch 1 taken 21342 -: 67: /* Now move on to the next char */ 15214: 68: c = *line; 15214: 69: switch (c) { 15214: 69-block 0 branch 0 taken 507 branch 1 taken 3547 branch 2 taken 0 branch 3 taken 0 branch 4 taken 0 branch 5 taken 507 branch 6 taken 509 branch 7 taken 509 branch 8 taken 0 branch 9 taken 507 branch 10 taken 506 branch 11 taken 509 branch 12 taken 509 branch 13 taken 507 branch 14 taken 7096 branch 15 taken 0 branch 16 taken 1 -: 70: 507: 71: case 'z': /* Exit status of last executed command */ 507: 72: temp = (char *)xnmalloc(3, sizeof(char)); 507: 72-block 0 call 0 returned 507 507: 73: temp[0] = ':'; 507: 74: temp[1] = (exit_code) ? '(' : ')'; branch 0 taken 22 (fallthrough) branch 1 taken 485 22: 74-block 0 unconditional 2 taken 22 485: 74-block 1 unconditional 3 taken 485 507: 75: temp[2] = '\0'; 507: 76: goto add_string; 507: 76-block 0 unconditional 0 taken 507 -: 77: -: 78:/* case 'x': // Hex numbers -: 79: { -: 80: // Go back one char, so that we have "\x ... n", which -: 81: // is what the get_hex_num() requires -: 82: line--; -: 83: // get_hex_num returns an array on integers corresponding -: 84: // to the hex codes found in line up to the fisrt non-hex -: 85: // expression -: 86: int *hex = get_hex_num(line); -: 87: int n = 0, i = 0, j; -: 88: // Count how many hex expressions were found -: 89: while (hex[n++] != -1); -: 90: n--; -: 91: // 2 + n == CTLEST + 0x00 + amount of hex numbers -: 92: temp = xnmalloc(2 + (size_t)n, sizeof(char)); -: 93: // Construct the line: "\001hex1hex2...n0x00" -: 94: temp[0] = CTLESC; -: 95: for (j = 1; j < (1 + n); j++) -: 96: temp[j] = (char)hex[i++]; -: 97: temp[1 + n] = '\0'; -: 98: // Set the line pointer after the first non-hex -: 99: // expression to continue processing -: 100: line += (i * 4); -: 101: c = 0; -: 102: free(hex); -: 103: goto add_string; -: 104: } */ -: 105: 3547: 106: case 'e': /* Escape char */ 3547: 107: temp = xnmalloc(2, sizeof(char)); 3547: 107-block 0 call 0 returned 3547 3547: 108: line++; -: 109: /* 27 (dec) == 033 (octal) == 0x1b (hex) == \e */ 3547: 110: temp[0] = '\033'; 3547: 111: temp[1] = '\0'; 3547: 112: c = 0; 3547: 113: goto add_string; unconditional 0 taken 3547 -: 114: #####: 115: case '0': /* Octal char */ -: 116: case '1': -: 117: case '2': -: 118: case '3': -: 119: case '4': -: 120: case '5': -: 121: case '6': -: 122: case '7': { -: 123: char octal_string[4]; -: 124: int n; -: 125: #####: 126: xstrsncpy(octal_string, line, 3); %%%%%: 126-block 0 call 0 never executed #####: 127: octal_string[3] = '\0'; -: 128: #####: 129: n = read_octal(octal_string); call 0 never executed #####: 130: temp = xnmalloc(3, sizeof(char)); call 0 never executed -: 131: #####: 132: if (n == CTLESC || n == CTLNUL) { branch 0 never executed branch 1 never executed %%%%%: 132-block 0 branch 2 never executed branch 3 never executed #####: 133: line += 3; #####: 134: temp[0] = CTLESC; #####: 135: temp[1] = (char)n; #####: 136: temp[2] = '\0'; %%%%%: 136-block 0 unconditional 0 never executed #####: 137: } else if (n == -1) { %%%%%: 137-block 0 branch 0 never executed branch 1 never executed #####: 138: temp[0] = '\\'; #####: 139: temp[1] = '\0'; %%%%%: 139-block 0 unconditional 0 never executed -: 140: } else { #####: 141: line += 3; #####: 142: temp[0] = (char)n; #####: 143: temp[1] = '\0'; %%%%%: 143-block 0 unconditional 0 never executed -: 144: } -: 145: #####: 146: c = 0; #####: 147: goto add_string; %%%%%: 147-block 0 unconditional 0 never executed -: 148: } -: 149: #####: 150: case 'c': /* Program name */ #####: 151: temp = savestring(PNL, strlen(PNL)); %%%%%: 151-block 0 call 0 never executed #####: 152: goto add_string; unconditional 0 never executed -: 153: #####: 154: case 'P': /* Current profile name */ #####: 155: if (!alt_profile) %%%%%: 155-block 0 branch 0 never executed branch 1 never executed #####: 156: temp = savestring("default", 7); %%%%%: 156-block 0 call 0 never executed unconditional 1 never executed -: 157: else #####: 158: temp = savestring(alt_profile, strlen(alt_profile)); %%%%%: 158-block 0 call 0 never executed unconditional 1 never executed #####: 159: goto add_string; %%%%%: 159-block 0 unconditional 0 never executed -: 160: 507: 161: case 't': /* Time: 24-hour HH:MM:SS format */ -: 162: case 'T': /* 12-hour HH:MM:SS format */ -: 163: case 'A': /* 24-hour HH:MM format */ -: 164: case '@': /* 12-hour HH:MM:SS am/pm format */ -: 165: case 'd': /* Date: abrev_weak_day, abrev_month_day month_num */ -: 166: { 507: 167: time_t rawtime = time(NULL); 507: 167-block 0 call 0 returned 507 -: 168: struct tm tm; 507: 169: localtime_r(&rawtime, &tm); call 0 returned 507 507: 170: if (c == 't') { branch 0 taken 0 (fallthrough) branch 1 taken 507 #####: 171: char time[9] = ""; #####: 172: strftime(time, sizeof(time), "%H:%M:%S", &tm); #####: 173: temp = savestring(time, sizeof(time)); %%%%%: 173-block 0 call 0 never executed 507: 174: } else if (c == 'T') { 507: 174-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 507 #####: 175: char time[9] = ""; #####: 176: strftime(time, sizeof(time), "%I:%M:%S", &tm); #####: 177: temp = savestring(time, sizeof(time)); %%%%%: 177-block 0 call 0 never executed 507: 178: } else if (c == 'A') { 507: 178-block 0 branch 0 taken 507 (fallthrough) branch 1 taken 0 507: 179: char time[6] = ""; 507: 180: strftime(time, sizeof(time), "%H:%M", &tm); 507: 181: temp = savestring(time, sizeof(time)); 507: 181-block 0 call 0 returned 507 #####: 182: } else if (c == '@') { %%%%%: 182-block 0 branch 0 never executed branch 1 never executed #####: 183: char time[12] = ""; #####: 184: strftime(time, sizeof(time), "%I:%M:%S %p", &tm); #####: 185: temp = savestring(time, sizeof(time)); %%%%%: 185-block 0 call 0 never executed -: 186: } else { /* c == 'd' */ #####: 187: char time[12] = ""; #####: 188: strftime(time, sizeof(time), "%a %b %d", &tm); #####: 189: temp = savestring(time, sizeof(time)); %%%%%: 189-block 0 call 0 never executed -: 190: } 507: 191: goto add_string; 507: 191-block 0 unconditional 0 taken 507 -: 192: } -: 193: 509: 194: case 'u': /* User name */ 509: 195: if (!user.name) 509: 195-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 509 #####: 196: temp = savestring("?", 1); %%%%%: 196-block 0 call 0 never executed unconditional 1 never executed -: 197: else 509: 198: temp = savestring(user.name, strlen(user.name)); 509: 198-block 0 call 0 returned 509 unconditional 1 taken 509 509: 199: goto add_string; 509: 199-block 0 unconditional 0 taken 509 -: 200: 509: 201: case 'h': /* Hostname up to first '.' */ -: 202: case 'H': /* Full hostname */ 509: 203: temp = savestring(hostname, strlen(hostname)); 509: 203-block 0 call 0 returned 509 509: 204: if (c == 'h') { branch 0 taken 0 (fallthrough) branch 1 taken 509 #####: 205: int ret = strcntchr(hostname, '.'); %%%%%: 205-block 0 call 0 never executed #####: 206: if (ret != -1) branch 0 never executed branch 1 never executed #####: 207: temp[ret] = '\0'; %%%%%: 207-block 0 unconditional 0 never executed -: 208: } 509: 209: goto add_string; 509: 209-block 0 unconditional 0 taken 509 -: 210: #####: 211: case 's': /* Shell name (after last slash)*/ -: 212: { #####: 213: if (!user.shell) { %%%%%: 213-block 0 branch 0 never executed branch 1 never executed #####: 214: line++; #####: 215: break; %%%%%: 215-block 0 unconditional 0 never executed -: 216: } #####: 217: char *shell_name = strrchr(user.shell, '/'); #####: 218: temp = savestring(shell_name + 1, strlen(shell_name) - 1); %%%%%: 218-block 0 call 0 never executed #####: 219: goto add_string; unconditional 0 never executed -: 220: } -: 221: 507: 222: case 'S': { /* Current workspace */ -: 223: char s[12]; 507: 224: sprintf(s, "%d", cur_ws + 1); 507: 225: temp = savestring(s, 1); 507: 225-block 0 call 0 returned 507 507: 226: goto add_string; unconditional 0 taken 507 -: 227: } -: 228: 506: 229: case 'l': { /* Current mode */ -: 230: char s[2]; 506: 231: s[0] = (light_mode ? 'L' : '\0'); 506: 231-block 0 branch 0 taken 4 (fallthrough) branch 1 taken 502 4: 231-block 1 unconditional 2 taken 4 502: 231-block 2 unconditional 3 taken 502 506: 232: s[1] = '\0'; 506: 233: temp = savestring(s, 1); 506: 233-block 0 call 0 returned 506 506: 234: goto add_string; unconditional 0 taken 506 -: 235: } -: 236: 509: 237: case 'p': -: 238: case 'w': /* Full PWD */ -: 239: case 'W': /* Short PWD */ -: 240: { 509: 241: if (!ws[cur_ws].path) { 509: 241-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 509 #####: 242: line++; #####: 243: break; %%%%%: 243-block 0 unconditional 0 never executed -: 244: } -: 245: -: 246: /* Reduce HOME to "~" */ 509: 247: int free_tmp_path = 0; 509: 248: char *tmp_path = (char *)NULL; 509: 249: if (strncmp(ws[cur_ws].path, user.home, 509: 249-block 0 branch 0 taken 488 (fallthrough) branch 1 taken 21 -: 250: user.home_len) == 0) 488: 251: tmp_path = home_tilde(ws[cur_ws].path); 488: 251-block 0 call 0 returned 488 unconditional 1 taken 488 509: 252: if (!tmp_path) 509: 252-block 0 branch 0 taken 21 (fallthrough) branch 1 taken 488 21: 253: tmp_path = ws[cur_ws].path; 21: 253-block 0 unconditional 0 taken 21 -: 254: else 488: 255: free_tmp_path = 1; 488: 255-block 0 unconditional 0 taken 488 -: 256: 509: 257: if (c == 'W') { 509: 257-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 509 #####: 258: char *ret = (char *)NULL; -: 259: /* If not root dir (/), get last dir name */ #####: 260: if (!(*tmp_path == '/' && !*(tmp_path + 1))) %%%%%: 260-block 0 branch 0 never executed branch 1 never executed %%%%%: 260-block 1 branch 2 never executed branch 3 never executed #####: 261: ret = strrchr(tmp_path, '/'); %%%%%: 261-block 0 unconditional 0 never executed -: 262: #####: 263: if (!ret) %%%%%: 263-block 0 branch 0 never executed branch 1 never executed #####: 264: temp = savestring(tmp_path, strlen(tmp_path)); %%%%%: 264-block 0 call 0 never executed unconditional 1 never executed -: 265: else #####: 266: temp = savestring(ret + 1, strlen(ret) - 1); %%%%%: 266-block 0 call 0 never executed unconditional 1 never executed -: 267: } -: 268: -: 269: /* Reduce path only if longer than max_path */ 509: 270: else if (c == 'p') { 509: 270-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 509 #####: 271: if (strlen(tmp_path) > (size_t)max_path) { %%%%%: 271-block 0 branch 0 never executed branch 1 never executed #####: 272: char *ret = (char *)NULL; #####: 273: ret = strrchr(tmp_path, '/'); #####: 274: if (!ret) %%%%%: 274-block 0 branch 0 never executed branch 1 never executed #####: 275: temp = savestring(tmp_path, strlen(tmp_path)); %%%%%: 275-block 0 call 0 never executed unconditional 1 never executed -: 276: else #####: 277: temp = savestring(ret + 1, strlen(ret) - 1); %%%%%: 277-block 0 call 0 never executed unconditional 1 never executed -: 278: } else { #####: 279: temp = savestring(tmp_path, strlen(tmp_path)); %%%%%: 279-block 0 call 0 never executed unconditional 1 never executed -: 280: } -: 281: } else { /* If c == 'w' */ 509: 282: temp = savestring(tmp_path, strlen(tmp_path)); 509: 282-block 0 call 0 returned 509 unconditional 1 taken 509 -: 283: } -: 284: 509: 285: if (free_tmp_path) 509: 285-block 0 branch 0 taken 488 (fallthrough) branch 1 taken 21 488: 286: free(tmp_path); 488: 286-block 0 unconditional 0 taken 488 -: 287: 509: 288: goto add_string; 509: 288-block 0 unconditional 0 taken 509 -: 289: } -: 290: 509: 291: case '$': /* '$' or '#' for normal and root user */ 509: 292: if ((flags & ROOT_USR)) 509: 292-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 508 1: 293: temp = savestring("#", 1); 1: 293-block 0 call 0 returned 1 unconditional 1 taken 1 -: 294: else 508: 295: temp = savestring("$", 1); 508: 295-block 0 call 0 returned 508 unconditional 1 taken 508 509: 296: goto add_string; 509: 296-block 0 unconditional 0 taken 509 -: 297: 507: 298: case 'a': /* Bell character */ -: 299: case 'r': /* Carriage return */ -: 300: case 'n': /* New line char */ 507: 301: temp = savestring(" ", 1); 507: 301-block 0 call 0 returned 507 507: 302: if (c == 'n') branch 0 taken 507 (fallthrough) branch 1 taken 0 507: 303: temp[0] = '\n'; 507: 303-block 0 unconditional 0 taken 507 #####: 304: else if (c == 'r') %%%%%: 304-block 0 branch 0 never executed branch 1 never executed #####: 305: temp[0] = '\r'; %%%%%: 305-block 0 unconditional 0 never executed -: 306: else #####: 307: temp[0] = '\a'; %%%%%: 307-block 0 unconditional 0 never executed 507: 308: goto add_string; 507: 308-block 0 unconditional 0 taken 507 -: 309: 7096: 310: case '[': /* Begin a sequence of non-printing characters. -: 311: Mostly used to add color sequences. Ex: \[\033[1;34m\] */ -: 312: case ']': /* End the sequence */ 7096: 313: temp = xnmalloc(2, sizeof(char)); 7096: 313-block 0 call 0 returned 7096 7096: 314: temp[0] = (c == '[') ? RL_PROMPT_START_IGNORE branch 0 taken 3548 (fallthrough) branch 1 taken 3548 3548: 314-block 0 unconditional 2 taken 3548 3548: 314-block 1 unconditional 3 taken 3548 -: 315: : RL_PROMPT_END_IGNORE; 7096: 316: temp[1] = '\0'; 7096: 317: goto add_string; 7096: 317-block 0 unconditional 0 taken 7096 -: 318: #####: 319: case '\\': /* Literal backslash */ #####: 320: temp = savestring("\\", 1); %%%%%: 320-block 0 call 0 never executed #####: 321: goto add_string; unconditional 0 never executed -: 322: 1: 323: default: 1: 324: temp = savestring("\\ ", 2); 1: 324-block 0 call 0 returned 1 1: 325: temp[1] = (char)c; unconditional 0 taken 1 -: 326: 15214: 327: add_string: 15214: 328: if (c) 15214: 328-block 0 branch 0 taken 11667 (fallthrough) branch 1 taken 3547 11667: 329: line++; 11667: 329-block 0 unconditional 0 taken 11667 15214: 330: result_len += strlen(temp); 15214: 331: if (!result) 15214: 331-block 0 branch 0 taken 507 (fallthrough) branch 1 taken 14707 507: 332: result = (char *)xcalloc(result_len + 1, sizeof(char)); 507: 332-block 0 call 0 returned 507 unconditional 1 taken 507 -: 333: else 14707: 334: result = (char *)xrealloc(result, (result_len + 1) * sizeof(char)); 14707: 334-block 0 call 0 returned 14707 unconditional 1 taken 14707 15214: 335: strcat(result, temp); 15214: 336: free(temp); 15214: 337: break; 15214: 337-block 0 unconditional 0 taken 15214 -: 338: } -: 339: } -: 340: -: 341: /* If not escape code, check for command substitution, and if not, -: 342: * just add whatever char is there */ -: 343: else { -: 344: /* Remove non-escaped quotes */ 21342: 345: if (c == '\'' || c == '"') 21342: 345-block 0 branch 0 taken 21342 (fallthrough) branch 1 taken 0 21342: 345-block 1 branch 2 taken 1018 (fallthrough) branch 3 taken 20324 1018: 346: continue; 1018: 346-block 0 unconditional 0 taken 1018 -: 347: -: 348:#if !defined(__HAIKU__) && !defined(__OpenBSD__) -: 349: /* Command substitution */ 20324*: 350: if (c == '$' && *line == '(') { 20324: 350-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 20324 %%%%%: 350-block 1 branch 2 never executed branch 3 never executed -: 351: /* Look for the ending parenthesis */ #####: 352: int tmp = strcntchr(line, ')'); %%%%%: 352-block 0 call 0 never executed #####: 353: if (tmp == -1) branch 0 never executed branch 1 never executed #####: 354: continue; %%%%%: 354-block 0 unconditional 0 never executed -: 355: -: 356: /* Copy the cmd to be substituted and pass it to wordexp */ #####: 357: char *tmp_str = (char *)xnmalloc(strlen(line) + 2, sizeof(char)); %%%%%: 357-block 0 call 0 never executed #####: 358: sprintf(tmp_str, "$%s", line); -: 359: #####: 360: tmp_str[tmp + 2] = '\0'; #####: 361: line += tmp + 1; -: 362: #####: 363: const char *old_value = getenv("IFS"); call 0 never executed #####: 364: setenv("IFS", "", 1); call 0 never executed -: 365: -: 366: wordexp_t wordbuf; #####: 367: if (wordexp(tmp_str, &wordbuf, 0) != EXIT_SUCCESS) { call 0 never executed branch 1 never executed branch 2 never executed #####: 368: free(tmp_str); #####: 369: if (old_value) %%%%%: 369-block 0 branch 0 never executed branch 1 never executed #####: 370: setenv("IFS", old_value, 1); %%%%%: 370-block 0 call 0 never executed unconditional 1 never executed -: 371: else #####: 372: unsetenv("IFS"); %%%%%: 372-block 0 call 0 never executed unconditional 1 never executed #####: 373: continue; %%%%%: 373-block 0 unconditional 0 never executed -: 374: } -: 375: #####: 376: if (old_value) %%%%%: 376-block 0 branch 0 never executed branch 1 never executed #####: 377: setenv("IFS", old_value, 1); %%%%%: 377-block 0 call 0 never executed unconditional 1 never executed -: 378: else #####: 379: unsetenv("IFS"); %%%%%: 379-block 0 call 0 never executed unconditional 1 never executed -: 380: #####: 381: free(tmp_str); -: 382: #####: 383: if (wordbuf.we_wordc) { %%%%%: 383-block 0 branch 0 never executed branch 1 never executed -: 384: size_t j; #####: 385: for (j = 0; j < wordbuf.we_wordc; j++) { %%%%%: 385-block 0 unconditional 0 never executed %%%%%: 385-block 1 branch 1 never executed branch 2 never executed -: 386: #####: 387: size_t word_len = strlen(wordbuf.we_wordv[j]); #####: 388: result_len += word_len; -: 389: #####: 390: if (!result) %%%%%: 390-block 0 branch 0 never executed branch 1 never executed #####: 391: result = (char *)xcalloc(result_len + 2, sizeof(char)); %%%%%: 391-block 0 call 0 never executed unconditional 1 never executed -: 392: else #####: 393: result = (char *)xrealloc(result, (result_len + 2) %%%%%: 393-block 0 call 0 never executed unconditional 1 never executed -: 394: * sizeof(char)); #####: 395: strcat(result, wordbuf.we_wordv[j]); %%%%%: 395-block 0 unconditional 0 never executed -: 396: -: 397: /* If not the last word in cmd output, add an space */ -: 398:/* if (j < wordbuf.we_wordc - 1) { -: 399: result[result_len++] = ' '; -: 400: result[result_len] = '\0'; -: 401: } */ -: 402: } -: 403: } -: 404: #####: 405: wordfree(&wordbuf); %%%%%: 405-block 0 call 0 never executed #####: 406: continue; unconditional 0 never executed -: 407: } -: 408:#endif /* __HAIKU__ && __OpenBSD__ */ -: 409: 20324: 410: result = (char *)xrealloc(result, (result_len + 2) * sizeof(char)); 20324: 410-block 0 call 0 returned 20324 20324: 411: result[result_len++] = (char)c; 20324: 412: result[result_len] = '\0'; unconditional 0 taken 20324 -: 413: } -: 414: } -: 415: -: 416: /* Remove trailing new line char, if any */ 509: 417: if (result && result[result_len - 1] == '\n') 509: 417-block 0 branch 0 taken 509 (fallthrough) branch 1 taken 0 509: 417-block 1 branch 2 taken 509 (fallthrough) branch 3 taken 0 509: 418: result[result_len - 1] = '\0'; 509: 418-block 0 unconditional 0 taken 509 -: 419: 509: 420: return result; 509: 420-block 0 unconditional 0 taken 509 -: 421:} -: 422: -: 423:/* Print the prompt and return the string entered by the user (to be -: 424: * parsed later by parse_input_str()) */ -: 425:char * function prompt called 509 returned 100% blocks executed 71% 509: 426:prompt(void) -: 427:{ -: 428: /* Make sure CWD exists; if not, go up to the parent, and so -: 429: * on */ 509: 430: while (xchdir(ws[cur_ws].path, SET_TITLE) != EXIT_SUCCESS) { 509: 430-block 0 unconditional 0 taken 509 509: 430-block 1 call 1 returned 509 branch 2 taken 0 branch 3 taken 509 (fallthrough) #####: 431: char *ret = strrchr(ws[cur_ws].path, '/'); #####: 432: if (ret && ret != ws[cur_ws].path) %%%%%: 432-block 0 branch 0 never executed branch 1 never executed %%%%%: 432-block 1 branch 2 never executed branch 3 never executed #####: 433: *ret = '\0'; %%%%%: 433-block 0 unconditional 0 never executed -: 434: else -: 435: break; -: 436: } -: 437: -: 438: /* Remove all final slash(es) from path, if any */ 509: 439: size_t path_len = strlen(ws[cur_ws].path), i; -: 440: 509*: 441: for (i = path_len - 1; ws[cur_ws].path[i] && i > 0; i--) { 509: 441-block 0 unconditional 0 taken 509 509: 441-block 1 branch 1 taken 509 (fallthrough) branch 2 taken 0 509: 441-block 2 branch 3 taken 508 branch 4 taken 1 (fallthrough) 508: 442: if (ws[cur_ws].path[i] != '/') 508: 442-block 0 branch 0 taken 508 (fallthrough) branch 1 taken 0 508: 443: break; 508: 443-block 0 unconditional 0 taken 508 -: 444: else #####: 445: ws[cur_ws].path[i] = '\0'; %%%%%: 445-block 0 unconditional 0 never executed -: 446: } -: 447: 509: 448: if (welcome_message) { 509: 448-block 0 branch 0 taken 13 (fallthrough) branch 1 taken 496 13: 449: printf(_("%s%s > %s\n%s%s\n"), wc_c, PROGRAM_NAME, PROG_DESC, 13: 449-block 0 call 0 returned 13 call 1 returned 13 call 2 returned 13 -: 450: df_c, _(HELP_MESSAGE)); 13: 451: welcome_message = 0; unconditional 0 taken 13 -: 452: } -: 453: -: 454: /* Print the tip of the day (only for the first run) */ 509: 455: if (tips) { 509: 455-block 0 branch 0 taken 509 (fallthrough) branch 1 taken 0 -: 456: static int first_run = 1; 509: 457: if (first_run) { 509: 457-block 0 branch 0 taken 4 (fallthrough) branch 1 taken 505 4: 458: print_tips(0); 4: 458-block 0 call 0 returned 4 4: 459: first_run = 0; unconditional 0 taken 4 -: 460: } -: 461: } -: 462: 509: 463: fputs(df_c, stdout); 509: 463-block 0 call 0 returned 509 509: 464: fflush(stdout); call 0 returned 509 -: 465: /* Execute prompt commands, if any, and only if external commands -: 466: * are allowed */ 509: 467: if (ext_cmd_ok && prompt_cmds_n > 0) { branch 0 taken 505 (fallthrough) branch 1 taken 4 505: 467-block 0 branch 2 taken 505 (fallthrough) branch 3 taken 0 2015: 468: for (i = 0; i < prompt_cmds_n; i++) 505: 468-block 0 unconditional 0 taken 505 unconditional 1 taken 1510 2015: 468-block 1 branch 2 taken 1510 branch 3 taken 505 (fallthrough) 1510: 469: launch_execle(prompt_cmds[i]); 1510: 469-block 0 call 0 returned 1510 -: 470: } -: 471:#ifndef _NO_TRASH -: 472: /* Update trash and sel file indicator on every prompt call */ 509: 473: if (trash_ok) { 509: 473-block 0 branch 0 taken 509 (fallthrough) branch 1 taken 0 509: 474: trash_n = count_dir(trash_files_dir, NO_CPOP); 509: 474-block 0 call 0 returned 509 509: 475: if (trash_n <= 2) branch 0 taken 501 (fallthrough) branch 1 taken 8 501: 476: trash_n = 0; 501: 476-block 0 unconditional 0 taken 501 -: 477: } -: 478:#endif 509: 479: get_sel_files(); 509: 479-block 0 call 0 returned 509 -: 480: -: 481: /* Messages are categorized in three groups: errors, warnings, and -: 482: * notices. The kind of message should be specified by the function -: 483: * printing the message itself via a global enum: pmsg, with the -: 484: * following values: NOMSG, ERROR, WARNING, and NOTICE. */ 509: 485: char msg_str[MAX_COLOR + 1 + 16] = ""; -: 486: 509: 487: if (msgs_n) { branch 0 taken 74 (fallthrough) branch 1 taken 435 -: 488: /* Errors take precedence over warnings, and warnings over -: 489: * notices. That is to say, if there is an error message AND a -: 490: * warning message, the prompt will always display the error -: 491: * message sign: a red 'E'. */ 74: 492: switch (pmsg) { 74: 492-block 0 branch 0 taken 71 branch 1 taken 0 branch 2 taken 1 branch 3 taken 2 branch 4 taken 0 71: 493: case NOMSG: break; 71: 493-block 0 unconditional 0 taken 71 #####: 494: case ERROR: sprintf(msg_str, "%sE%s", em_c, RL_NC); break; %%%%%: 494-block 0 unconditional 0 never executed 1: 495: case WARNING: sprintf(msg_str, "%sW%s", wm_c, RL_NC); break; 1: 495-block 0 unconditional 0 taken 1 2: 496: case NOTICE: sprintf(msg_str, "%sN%s", nm_c, RL_NC); break; 2: 496-block 0 unconditional 0 taken 2 #####: 497: default: break; %%%%%: 497-block 0 unconditional 0 never executed -: 498: } -: 499: } -: 500: -: 501: /* Generate the prompt string */ 509: 502: if (prompt_style == CUSTOM_PROMPT_STYLE) { 509: 502-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 509 -: 503: /* Set environment variables with CliFM state information -: 504: * (sel files, trash, stealth mode, messages) to be handled by -: 505: * the prompt itself */ -: 506: char t[32]; #####: 507: sprintf(t, "%d", (int)sel_n); #####: 508: setenv("CLIFM_STAT_SEL", t, 1); %%%%%: 508-block 0 call 0 never executed #####: 509: sprintf(t, "%d", (int)trash_n); #####: 510: setenv("CLIFM_STAT_TRASH", t, 1); call 0 never executed #####: 511: sprintf(t, "%d", (msgs_n && pmsg) ? (int)msgs_n : 0); branch 0 never executed branch 1 never executed %%%%%: 511-block 0 branch 2 never executed branch 3 never executed %%%%%: 511-block 1 unconditional 4 never executed %%%%%: 511-block 2 unconditional 5 never executed #####: 512: setenv("CLIFM_STAT_MSG", t, 1); %%%%%: 512-block 0 call 0 never executed #####: 513: sprintf(t, "%d", cur_ws + 1); #####: 514: setenv("CLIFM_STAT_WS", t, 1); call 0 never executed #####: 515: sprintf(t, "%d", exit_code); #####: 516: setenv("CLIFM_STAT_EXIT", t, 1); call 0 never executed #####: 517: setenv("CLIFM_STAT_ROOT", (flags & ROOT_USR) ? "1" : "0", 1); branch 0 never executed branch 1 never executed %%%%%: 517-block 0 unconditional 2 never executed %%%%%: 517-block 1 unconditional 3 never executed %%%%%: 517-block 2 call 4 never executed #####: 518: setenv("CLIFM_STAT_STEALTH", (xargs.stealth_mode == 1) ? "1" : "0", 1); branch 0 never executed branch 1 never executed %%%%%: 518-block 0 unconditional 2 never executed %%%%%: 518-block 1 unconditional 3 never executed %%%%%: 518-block 2 call 4 never executed -: 519: } -: 520: -: 521: /* First, grab and decode the prompt line of the config file (stored -: 522: * in encoded_prompt at startup) */ 509: 523: char *decoded_prompt = decode_prompt(encoded_prompt); 509: 523-block 0 call 0 returned 509 -: 524: -: 525: /* Emergency prompt, just in case decode_prompt fails */ 509: 526: if (!decoded_prompt) { branch 0 taken 0 (fallthrough) branch 1 taken 509 #####: 527: fprintf(stderr, _("%s: Error decoding prompt line. Using an " %%%%%: 527-block 0 call 0 never executed call 1 never executed -: 528: "emergency prompt\n"), PROGRAM_NAME); #####: 529: decoded_prompt = (char *)xnmalloc(9, sizeof(char)); call 0 never executed #####: 530: sprintf(decoded_prompt, "\001\x1b[0m\002> "); unconditional 0 never executed -: 531: } -: 532: -: 533: size_t decoded_prompt_len; -: 534:/* if (unicode || prompt_style == CUSTOM_PROMPT_STYLE) -: 535: decoded_prompt_len = u8_xstrlen(decoded_prompt); -: 536: else */ 509: 537: decoded_prompt_len = strlen(decoded_prompt); -: 538: 509: 539: size_t prompt_length = 0; -: 540: 509: 541: if (prompt_style == DEF_PROMPT_STYLE) { 509: 541-block 0 branch 0 taken 509 (fallthrough) branch 1 taken 0 509: 542: prompt_length = (size_t)(decoded_prompt_len 509*: 543: + (xargs.stealth_mode == 1 ? 16 : 0) + ((flags & ROOT_USR) ? 16 : 0) 509: 543-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 509 %%%%%: 543-block 1 unconditional 2 never executed 509: 543-block 2 unconditional 3 taken 509 509: 544: + (sel_n ? 16 : 0) + (trash_n ? 16 : 0) + ((msgs_n && pmsg) ? 16 : 0) 509: 544-block 0 branch 0 taken 53 (fallthrough) branch 1 taken 456 53: 544-block 1 unconditional 2 taken 53 456: 544-block 2 unconditional 3 taken 456 509: 544-block 3 branch 4 taken 8 (fallthrough) branch 5 taken 501 8: 544-block 4 unconditional 6 taken 8 501: 544-block 5 unconditional 7 taken 501 509: 544-block 6 branch 8 taken 74 (fallthrough) branch 9 taken 435 74: 544-block 7 branch 10 taken 3 (fallthrough) branch 11 taken 71 3: 544-block 8 unconditional 12 taken 3 506: 544-block 9 unconditional 13 taken 506 509: 544-block 10 unconditional 14 taken 509 -: 545: + 6 + sizeof(tx_c) + 1); -: 546: } else { #####: 547: prompt_length = (size_t)(decoded_prompt_len + 6 + sizeof(tx_c) + 1); %%%%%: 547-block 0 unconditional 0 never executed -: 548: } -: 549: -: 550: /* 16 = color_b({red,green,yellow}_b)+letter (sel, trash, msg)+RL_NC; -: 551: * 6 = RL_NC -: 552: * 1 = null terminating char */ -: 553: 509: 554: char *the_prompt = (char *)xnmalloc(prompt_length, sizeof(char)); 509: 554-block 0 call 0 returned 509 -: 555: 509: 556: if (prompt_style == DEF_PROMPT_STYLE) { branch 0 taken 509 (fallthrough) branch 1 taken 0 4072*: 557: snprintf(the_prompt, prompt_length, "%s%s%s%s%s%s%s%s%s%s%s", 53: 557-block 0 unconditional 0 taken 53 456: 557-block 1 unconditional 1 taken 456 53: 557-block 2 unconditional 2 taken 53 456: 557-block 3 unconditional 3 taken 456 8: 557-block 4 unconditional 4 taken 8 501: 557-block 5 unconditional 5 taken 501 8: 557-block 6 unconditional 6 taken 8 501: 557-block 7 unconditional 7 taken 501 %%%%%: 557-block 8 unconditional 8 never executed 509: 557-block 9 unconditional 9 taken 509 %%%%%: 557-block 10 unconditional 10 never executed 509: 557-block 11 unconditional 11 taken 509 3: 557-block 12 unconditional 12 taken 3 506: 557-block 13 unconditional 13 taken 506 1: 557-block 14 unconditional 14 taken 1 508: 557-block 15 unconditional 15 taken 508 509: 557-block 16 unconditional 16 taken 509 509: 558: (flags & ROOT_USR) ? "\001\x1b[1;31mR\x1b[0m\002" : "", 509: 558-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 508 1018: 559: (msgs_n && pmsg) ? msg_str : "", (xargs.stealth_mode == 1) 509: 559-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 509 509: 559-block 1 branch 2 taken 74 (fallthrough) branch 3 taken 435 74: 559-block 2 branch 4 taken 3 (fallthrough) branch 5 taken 71 509: 560: ? si_c : "", (xargs.stealth_mode == 1) ? "S\001\x1b[0m\002" 509: 560-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 509 1018: 561: : "", (trash_n) ? ti_c : "", (trash_n) ? "T\001\x1b[0m\002" : "", 509: 561-block 0 branch 0 taken 8 (fallthrough) branch 1 taken 501 509: 561-block 1 branch 2 taken 8 (fallthrough) branch 3 taken 501 1018: 562: (sel_n) ? li_c : "", (sel_n) ? "*\001\x1b[0m\002" : "", 509: 562-block 0 branch 0 taken 53 (fallthrough) branch 1 taken 456 509: 562-block 1 branch 2 taken 53 (fallthrough) branch 3 taken 456 -: 563: decoded_prompt, RL_NC, tx_c); -: 564: } else { #####: 565: snprintf(the_prompt, prompt_length, "%s%s%s", decoded_prompt, RL_NC, %%%%%: 565-block 0 unconditional 0 never executed -: 566: tx_c); -: 567: } -: 568: 509: 569: free(decoded_prompt); -: 570: -: 571: /* Print error messages, if any. 'print_errors' is set to true by -: 572: * log_msg() with the PRINT_PROMPT flag. If NOPRINT_PROMPT is -: 573: * passed instead, 'print_msg' will be false and the message will -: 574: * be printed in place by log_msg() itself, without waiting for -: 575: * the next prompt */ 509: 576: if (print_msg && msgs_n) { 509: 576-block 0 branch 0 taken 3 (fallthrough) branch 1 taken 506 3: 576-block 1 branch 2 taken 3 (fallthrough) branch 3 taken 0 3: 577: fputs(messages[msgs_n - 1], stderr); 3: 577-block 0 call 0 returned 3 3: 578: print_msg = 0; /* Print messages only once */ unconditional 0 taken 3 -: 579: } -: 580: 509: 581: args_n = 0; -: 582: -: 583: /* Restore forground color */ 509: 584: fputs(df_c, stdout); 509: 584-block 0 call 0 returned 509 -: 585: /* Print the prompt and get user input */ 509: 586: char *input = (char *)NULL; 509: 587: input = readline(the_prompt); call 0 returned 509 509: 588: free(the_prompt); -: 589: 509: 590: if (!input) branch 0 taken 0 (fallthrough) branch 1 taken 509 #####: 591: return (char *)NULL; %%%%%: 591-block 0 unconditional 0 never executed -: 592: 509: 593: if (!*input) { 509: 593-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 508 1: 594: free(input); 1: 595: input = (char *)NULL; 1: 596: return (char *)NULL; 1: 596-block 0 unconditional 0 taken 1 -: 597: } -: 598: -: 599: /* Keep a literal copy of the last entered command to compose the -: 600: * commands log, if needed and enabled */ 508: 601: if (logs_enabled) { 508: 601-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 508 #####: 602: if (last_cmd) %%%%%: 602-block 0 branch 0 never executed branch 1 never executed #####: 603: free(last_cmd); %%%%%: 603-block 0 unconditional 0 never executed #####: 604: last_cmd = savestring(input, strlen(input)); %%%%%: 604-block 0 call 0 never executed unconditional 1 never executed -: 605: } -: 606: -: 607: /* Do not record empty lines, exit, history commands, consecutively -: 608: * equal inputs, or lines starting with space */ 508: 609: if (record_cmd(input)) 508: 609-block 0 call 0 returned 508 branch 1 taken 247 (fallthrough) branch 2 taken 261 247: 610: add_to_cmdhist(input); 247: 610-block 0 call 0 returned 247 unconditional 1 taken 247 -: 611: 508: 612: return input; 508: 612-block 0 unconditional 0 taken 508 -: 613:} clifm-1.26.3/misc/codecov/properties.c.gcov000066400000000000000000001201431506632037700205610ustar00rootroot00000000000000 -: 0:Source:properties.c -: 1:/* properties.c -- functions to get files properties */ -: 2: -: 3:/* -: 4: * This file is part of CliFM -: 5: * -: 6: * Copyright (C) 2016-2021, L. Abramovich -: 7: * All rights reserved. -: 8: -: 9: * CliFM is free software; you can redistribute it and/or modify -: 10: * it under the terms of the GNU General Public License as published by -: 11: * the Free Software Foundation; either version 2 of the License, or -: 12: * (at your option) any later version. -: 13: * -: 14: * CliFM is distributed in the hope that it will be useful, -: 15: * but WITHOUT ANY WARRANTY; without even the implied warranty of -: 16: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -: 17: * GNU General Public License for more details. -: 18: * -: 19: * You should have received a copy of the GNU General Public License -: 20: * along with this program; if not, write to the Free Software -: 21: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, -: 22: * MA 02110-1301, USA. -: 23:*/ -: 24: -: 25:#include "helpers.h" -: 26: -: 27:#include -: 28:#include -: 29:#include -: 30:#include -: 31:#include -: 32:#include -: 33:#ifdef __linux__ -: 34:#include -: 35:#endif -: 36:#include -: 37:#include -: 38:#include -: 39:#include -: 40: -: 41:#include "aux.h" -: 42:#include "checks.h" -: 43:#include "colors.h" -: 44: -: 45:static int function get_properties called 3 returned 100% blocks executed 66% 3: 46:get_properties(char *filename, const int dsize) -: 47:{ 3: 48: if (!filename || !*filename) 3: 48-block 0 branch 0 taken 3 (fallthrough) branch 1 taken 0 3: 48-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 3 #####: 49: return EXIT_FAILURE; %%%%%: 49-block 0 unconditional 0 never executed -: 50: 3: 51: size_t len = strlen(filename); 3: 52: if (filename[len - 1] == '/') 3: 52-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 2 1: 53: filename[len - 1] = '\0'; 1: 53-block 0 unconditional 0 taken 1 -: 54: -: 55: /* Check file existence */ -: 56: struct stat file_attrib; 3: 57: if (lstat(filename, &file_attrib) == -1) { 3: 57-block 0 call 0 returned 3 branch 1 taken 0 (fallthrough) branch 2 taken 3 #####: 58: fprintf(stderr, "%s: pr: '%s': %s\n", PROGRAM_NAME, filename, call 0 never executed #####: 59: strerror(errno)); %%%%%: 59-block 0 call 0 never executed #####: 60: return EXIT_FAILURE; unconditional 0 never executed -: 61: } -: 62: -: 63: /* Get file size */ 3: 64: char *size_type = get_size_unit(file_attrib.st_size); 3: 64-block 0 call 0 returned 3 -: 65: -: 66: /* Get file type (and color): */ 3: 67: char file_type = 0; 3: 68: char *linkname = (char *)NULL, *color = (char *)NULL; -: 69: 3: 70: switch (file_attrib.st_mode & S_IFMT) { branch 0 taken 1 branch 1 taken 1 branch 2 taken 1 branch 3 taken 0 branch 4 taken 0 branch 5 taken 0 branch 6 taken 0 branch 7 taken 0 1: 71: case S_IFREG: { 1: 72: char *ext = (char *)NULL; 1: 73: file_type = '-'; 1: 74: if (light_mode) 1: 74-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 1 #####: 75: color = fi_c; %%%%%: 75-block 0 unconditional 0 never executed 1: 76: else if (access(filename, R_OK) == -1) 1: 76-block 0 call 0 returned 1 branch 1 taken 0 (fallthrough) branch 2 taken 1 #####: 77: color = nf_c; %%%%%: 77-block 0 unconditional 0 never executed 1: 78: else if (file_attrib.st_mode & S_ISUID) 1: 78-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 1 #####: 79: color = su_c; %%%%%: 79-block 0 unconditional 0 never executed 1: 80: else if (file_attrib.st_mode & S_ISGID) 1: 80-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 1 #####: 81: color = sg_c; %%%%%: 81-block 0 unconditional 0 never executed -: 82: else { -: 83:#ifdef _LINUX_CAP 1: 84: cap_t cap = cap_get_file(filename); 1: 84-block 0 call 0 returned 1 1: 85: if (cap) { branch 0 taken 0 (fallthrough) branch 1 taken 1 #####: 86: color = ca_c; #####: 87: cap_free(cap); %%%%%: 87-block 0 call 0 never executed unconditional 1 never executed 1: 88: } else if (file_attrib.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) { 1: 88-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 0 -: 89:#else -: 90: if (file_attrib.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) { -: 91:#endif 1: 92: if (file_attrib.st_size == 0) 1: 92-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 1 #####: 93: color = ee_c; %%%%%: 93-block 0 unconditional 0 never executed -: 94: else 1: 95: color = ex_c; 1: 95-block 0 unconditional 0 taken 1 -: 96: } -: 97: #####: 98: else if (file_attrib.st_size == 0) %%%%%: 98-block 0 branch 0 never executed branch 1 never executed #####: 99: color = ef_c; %%%%%: 99-block 0 unconditional 0 never executed #####: 100: else if (file_attrib.st_nlink > 1) %%%%%: 100-block 0 branch 0 never executed branch 1 never executed #####: 101: color = mh_c; %%%%%: 101-block 0 unconditional 0 never executed -: 102: else { #####: 103: ext = strrchr(filename, '.'); #####: 104: if (ext) { %%%%%: 104-block 0 branch 0 never executed branch 1 never executed #####: 105: char *extcolor = get_ext_color(ext); %%%%%: 105-block 0 call 0 never executed #####: 106: if (extcolor) { branch 0 never executed branch 1 never executed #####: 107: char ext_color[MAX_COLOR] = ""; #####: 108: sprintf(ext_color, "\x1b[%sm", extcolor); #####: 109: color = ext_color; #####: 110: extcolor = (char *)NULL; %%%%%: 110-block 0 unconditional 0 never executed -: 111: } else { /* No matching extension found */ #####: 112: color = fi_c; %%%%%: 112-block 0 unconditional 0 never executed -: 113: } -: 114: } else { #####: 115: color = fi_c; %%%%%: 115-block 0 unconditional 0 never executed -: 116: } -: 117: } -: 118: } 1: 119: } break; 1: 119-block 0 unconditional 0 taken 1 1: 120: case S_IFDIR: 1: 121: file_type = 'd'; 1: 122: if (light_mode) 1: 122-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 1 #####: 123: color = di_c; %%%%%: 123-block 0 unconditional 0 never executed 1: 124: else if (access(filename, R_OK | X_OK) != 0) { 1: 124-block 0 call 0 returned 1 branch 1 taken 0 (fallthrough) branch 2 taken 1 #####: 125: color = nd_c; %%%%%: 125-block 0 unconditional 0 never executed -: 126: } else { 1: 127: int sticky = 0; 1: 128: int is_oth_w = 0; 1: 129: if (file_attrib.st_mode & S_ISVTX) 1: 129-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 1 #####: 130: sticky = 1; %%%%%: 130-block 0 unconditional 0 never executed -: 131: 1: 132: if (file_attrib.st_mode & S_IWOTH) 1: 132-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 1 #####: 133: is_oth_w = 1; %%%%%: 133-block 0 unconditional 0 never executed -: 134: 1: 135: int files_dir = count_dir(filename, CPOP); 1: 135-block 0 call 0 returned 1 -: 136: 2*: 137: color = sticky ? (is_oth_w ? tw_c : st_c) : is_oth_w ? ow_c branch 0 taken 0 (fallthrough) branch 1 taken 1 %%%%%: 137-block 0 branch 2 never executed branch 3 never executed %%%%%: 137-block 1 unconditional 4 never executed %%%%%: 137-block 2 unconditional 5 never executed %%%%%: 137-block 3 unconditional 6 never executed 1: 137-block 4 unconditional 7 taken 1 1: 137-block 5 unconditional 8 taken 1 1*: 138: : ((files_dir == 2 || files_dir == 0) ? ed_c : di_c); 1: 138-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 0 1: 138-block 1 branch 2 taken 1 (fallthrough) branch 3 taken 0 1: 138-block 2 branch 4 taken 0 (fallthrough) branch 5 taken 1 %%%%%: 138-block 3 unconditional 6 never executed 1: 138-block 4 unconditional 7 taken 1 1: 138-block 5 unconditional 8 taken 1 %%%%%: 138-block 6 unconditional 9 never executed -: 139: } -: 140: 1: 141: break; 1: 141-block 0 unconditional 0 taken 1 1: 142: case S_IFLNK: 1: 143: file_type = 'l'; 1: 144: if (light_mode) { 1: 144-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 1 #####: 145: color = ln_c; %%%%%: 145-block 0 unconditional 0 never executed -: 146: } else { 1: 147: linkname = realpath(filename, (char *)NULL); 1: 147-block 0 call 0 returned 1 1: 148: if (linkname) branch 0 taken 1 (fallthrough) branch 1 taken 0 1: 149: color = ln_c; 1: 149-block 0 unconditional 0 taken 1 -: 150: else #####: 151: color = or_c; %%%%%: 151-block 0 unconditional 0 never executed -: 152: } 1: 153: break; 1: 153-block 0 unconditional 0 taken 1 #####: 154: case S_IFSOCK: file_type = 's'; #####: 155: color = so_c; #####: 156: break; %%%%%: 156-block 0 unconditional 0 never executed #####: 157: case S_IFBLK: #####: 158: file_type = 'b'; #####: 159: color = bd_c; #####: 160: break; %%%%%: 160-block 0 unconditional 0 never executed #####: 161: case S_IFCHR: #####: 162: file_type = 'c'; #####: 163: color = cd_c; #####: 164: break; %%%%%: 164-block 0 unconditional 0 never executed #####: 165: case S_IFIFO: #####: 166: file_type = 'p'; #####: 167: color = pi_c; #####: 168: break; %%%%%: 168-block 0 unconditional 0 never executed #####: 169: default: #####: 170: file_type = '?'; #####: 171: color = no_c; %%%%%: 171-block 0 unconditional 0 never executed -: 172: } -: 173: -: 174: /* Get file permissions */ 3: 175: char read_usr = '-', write_usr = '-', exec_usr = '-', 3: 176: read_grp = '-', write_grp = '-', exec_grp = '-', 3: 177: read_others = '-', write_others = '-', exec_others = '-'; -: 178: 3: 179: mode_t val = (file_attrib.st_mode & (mode_t)~S_IFMT); 3: 180: if (val & S_IRUSR) read_usr = 'r'; 3: 180-block 0 branch 0 taken 3 (fallthrough) branch 1 taken 0 3: 180-block 1 unconditional 2 taken 3 3: 181: if (val & S_IWUSR) write_usr = 'w'; 3: 181-block 0 branch 0 taken 3 (fallthrough) branch 1 taken 0 3: 181-block 1 unconditional 2 taken 3 3: 182: if (val & S_IXUSR) exec_usr = 'x'; 3: 182-block 0 branch 0 taken 3 (fallthrough) branch 1 taken 0 3: 182-block 1 unconditional 2 taken 3 -: 183: 3: 184: if (val & S_IRGRP) read_grp = 'r'; 3: 184-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 2 1: 184-block 1 unconditional 2 taken 1 3: 185: if (val & S_IWGRP) write_grp = 'w'; 3: 185-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 2 1: 185-block 1 unconditional 2 taken 1 3: 186: if (val & S_IXGRP) exec_grp = 'x'; 3: 186-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 1 2: 186-block 1 unconditional 2 taken 2 -: 187: 3: 188: if (val & S_IROTH) read_others = 'r'; 3: 188-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 2 1: 188-block 1 unconditional 2 taken 1 3: 189: if (val & S_IWOTH) write_others = 'w'; 3: 189-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 2 1: 189-block 1 unconditional 2 taken 1 3: 190: if (val & S_IXOTH) exec_others = 'x'; 3: 190-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 1 2: 190-block 1 unconditional 2 taken 2 -: 191: 3: 192: if (file_attrib.st_mode & S_ISUID) 3: 192-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 3 #####: 193: (val & S_IXUSR) ? (exec_usr = 's') : (exec_usr = 'S'); %%%%%: 193-block 0 branch 0 never executed branch 1 never executed %%%%%: 193-block 1 unconditional 2 never executed %%%%%: 193-block 2 unconditional 3 never executed 3: 194: if (file_attrib.st_mode & S_ISGID) 3: 194-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 3 #####: 195: (val & S_IXGRP) ? (exec_grp = 's') : (exec_grp = 'S'); %%%%%: 195-block 0 branch 0 never executed branch 1 never executed %%%%%: 195-block 1 unconditional 2 never executed %%%%%: 195-block 2 unconditional 3 never executed 3: 196: if (file_attrib.st_mode & S_ISVTX) 3: 196-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 3 #####: 197: (val & S_IXOTH) ? (exec_others = 't'): (exec_others = 'T'); %%%%%: 197-block 0 branch 0 never executed branch 1 never executed %%%%%: 197-block 1 unconditional 2 never executed %%%%%: 197-block 2 unconditional 3 never executed -: 198: -: 199: /* Get number of links to the file */ 3: 200: nlink_t link_n = file_attrib.st_nlink; -: 201: -: 202: /* Get modification time */ 3: 203: time_t time = (time_t)file_attrib.st_mtim.tv_sec; -: 204: struct tm tm; 3: 205: localtime_r(&time, &tm); 3: 205-block 0 call 0 returned 3 3: 206: char mod_time[128] = ""; -: 207: 3: 208: if (time) branch 0 taken 3 (fallthrough) branch 1 taken 0 -: 209: /* Store formatted (and localized) date-time string into -: 210: * mod_time */ 3: 211: strftime(mod_time, sizeof(mod_time), "%b %d %H:%M:%S %Y", &tm); 3: 211-block 0 unconditional 0 taken 3 -: 212: else #####: 213: mod_time[0] = '-'; %%%%%: 213-block 0 unconditional 0 never executed -: 214: -: 215: /* Get owner and group names */ 3: 216: uid_t owner_id = file_attrib.st_uid; /* owner ID */ 3: 217: gid_t group_id = file_attrib.st_gid; /* group ID */ -: 218: struct group *group; -: 219: struct passwd *owner; 3: 220: group = getgrgid(group_id); 3: 220-block 0 call 0 returned 3 3: 221: owner = getpwuid(owner_id); call 0 returned 3 -: 222: -: 223: /* Print file properties */ 6*: 224: printf("(%04o)%c/%c%c%c/%c%c%c/%c%c%c%s %zu %s %s %s %s ", 3: 224-block 0 unconditional 0 taken 3 %%%%%: 224-block 1 unconditional 1 never executed 3: 224-block 2 branch 2 taken 3 (fallthrough) branch 3 taken 0 3: 224-block 3 unconditional 4 taken 3 %%%%%: 224-block 4 unconditional 5 never executed 3: 224-block 5 branch 6 taken 0 (fallthrough) branch 7 taken 3 3: 224-block 6 unconditional 8 taken 3 3: 224-block 7 branch 9 taken 0 (fallthrough) branch 10 taken 3 3: 224-block 8 unconditional 11 taken 3 branch 12 taken 0 (fallthrough) branch 13 taken 3 %%%%%: 224-block 9 unconditional 14 never executed 3: 224-block 10 unconditional 15 taken 3 3: 225: file_attrib.st_mode & 07777, file_type, 3: 225-block 0 call 0 returned 3 -: 226: read_usr, write_usr, exec_usr, read_grp, -: 227: write_grp, exec_grp, read_others, write_others, exec_others, 3: 228: is_acl(filename) ? "+" : "", (size_t)link_n, 3: 228-block 0 call 0 returned 3 #####: 229: (!owner) ? _("unknown") : owner->pw_name, %%%%%: 229-block 0 call 0 never executed unconditional 1 never executed #####: 230: (!group) ? _("unknown") : group->gr_name, %%%%%: 230-block 0 call 0 never executed unconditional 1 never executed -: 231: (size_type) ? size_type : "?", 3: 232: (mod_time[0] != '\0') ? mod_time : "?"); branch 0 taken 3 (fallthrough) branch 1 taken 0 -: 233: 3: 234: if (file_type && file_type != 'l') { branch 0 taken 3 (fallthrough) branch 1 taken 0 3: 234-block 0 branch 2 taken 2 (fallthrough) branch 3 taken 1 2: 235: printf("%s%s%s\n", color, filename, df_c); 2: 235-block 0 call 0 returned 2 unconditional 1 taken 2 1: 236: } else if (linkname) { 1: 236-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 0 1: 237: printf("%s%s%s -> %s\n", color, filename, df_c, linkname); 1: 237-block 0 call 0 returned 1 1: 238: free(linkname); unconditional 0 taken 1 -: 239: } else { /* Broken link */ #####: 240: char link[PATH_MAX] = ""; #####: 241: ssize_t ret = readlink(filename, link, PATH_MAX); %%%%%: 241-block 0 call 0 never executed -: 242: #####: 243: if (ret) { branch 0 never executed branch 1 never executed #####: 244: printf(_("%s%s%s -> %s (broken link)\n"), color, filename, %%%%%: 244-block 0 call 0 never executed call 1 never executed unconditional 2 never executed -: 245: df_c, link); -: 246: } else { #####: 247: printf("%s%s%s -> ???\n", color, filename, df_c); %%%%%: 247-block 0 call 0 never executed unconditional 1 never executed -: 248: } -: 249: } -: 250: -: 251: /* Stat information */ -: 252: /* Last access time */ 3: 253: time = (time_t)file_attrib.st_atim.tv_sec; 3: 254: localtime_r(&time, &tm); 3: 254-block 0 call 0 returned 3 3: 255: char access_time[128] = ""; -: 256: 3: 257: if (time) branch 0 taken 3 (fallthrough) branch 1 taken 0 -: 258: /* Store formatted (and localized) date-time string into -: 259: * access_time */ 3: 260: strftime(access_time, sizeof(access_time), "%b %d %H:%M:%S %Y", &tm); 3: 260-block 0 unconditional 0 taken 3 -: 261: else #####: 262: access_time[0] = '-'; %%%%%: 262-block 0 unconditional 0 never executed -: 263: -: 264: /* Last properties change time */ 3: 265: time = (time_t)file_attrib.st_ctim.tv_sec; 3: 266: localtime_r(&time, &tm); 3: 266-block 0 call 0 returned 3 3: 267: char change_time[128] = ""; 3: 268: if (time) branch 0 taken 3 (fallthrough) branch 1 taken 0 3: 269: strftime(change_time, sizeof(change_time), "%b %d %H:%M:%S %Y", &tm); 3: 269-block 0 unconditional 0 taken 3 -: 270: else #####: 271: change_time[0] = '-'; %%%%%: 271-block 0 unconditional 0 never executed -: 272: -: 273: /* Get creation (birth) time */ -: 274:#if defined(HAVE_ST_BIRTHTIME) || defined(__BSD_VISIBLE) -: 275:#ifdef __OpenBSD__ -: 276: time = file_attrib.__st_birthtim.tv_sec; -: 277:#else -: 278: time = file_attrib.st_birthtime; -: 279:#endif -: 280: localtime_r(&time, &tm); -: 281: char creation_time[128] = ""; -: 282: if (!time) -: 283: creation_time[0] = '-'; -: 284: else -: 285: strftime(creation_time, sizeof(creation_time), -: 286: "%b %d %H:%M:%S %Y", &tm); -: 287:#elif defined(_STATX) -: 288: struct statx attrx; 3: 289: statx(AT_FDCWD, filename, AT_SYMLINK_NOFOLLOW, STATX_BTIME, &attrx); 3: 289-block 0 call 0 returned 3 3: 290: time = (time_t)attrx.stx_btime.tv_sec; 3: 291: localtime_r(&time, &tm); call 0 returned 3 3: 292: char creation_time[128] = ""; -: 293: 3: 294: if (!time) { branch 0 taken 0 (fallthrough) branch 1 taken 3 #####: 295: creation_time[0] = '-'; %%%%%: 295-block 0 unconditional 0 never executed -: 296: } else { 3: 297: strftime(creation_time, sizeof(creation_time), 3: 297-block 0 unconditional 0 taken 3 -: 298: "%b %d %H:%M:%S %Y", &tm); -: 299: } -: 300:#endif -: 301: 3: 302: switch (file_type) { 3: 302-block 0 branch 0 taken 1 branch 1 taken 0 branch 2 taken 1 branch 3 taken 0 branch 4 taken 0 branch 5 taken 0 branch 6 taken 1 branch 7 taken 0 1: 303: case 'd': printf(_("Directory")); break; 1: 303-block 0 call 0 returned 1 call 1 returned 1 unconditional 2 taken 1 #####: 304: case 's': printf(_("Socket")); break; %%%%%: 304-block 0 call 0 never executed call 1 never executed unconditional 2 never executed 1: 305: case 'l': printf(_("Symbolic link")); break; 1: 305-block 0 call 0 returned 1 call 1 returned 1 unconditional 2 taken 1 #####: 306: case 'b': printf(_("Block special file")); break; %%%%%: 306-block 0 call 0 never executed call 1 never executed unconditional 2 never executed #####: 307: case 'c': printf(_("Character special file")); break; %%%%%: 307-block 0 call 0 never executed call 1 never executed unconditional 2 never executed #####: 308: case 'p': printf(_("Fifo")); break; %%%%%: 308-block 0 call 0 never executed call 1 never executed unconditional 2 never executed 1: 309: case '-': printf(_("Regular file")); break; 1: 309-block 0 call 0 returned 1 call 1 returned 1 unconditional 2 taken 1 #####: 310: default: break; %%%%%: 310-block 0 unconditional 0 never executed -: 311: } -: 312:#ifdef __OpenBSD__ -: 313: printf(_("\tBlocks: %lld"), file_attrib.st_blocks); -: 314:#else 3: 315: printf(_("\tBlocks: %ld"), file_attrib.st_blocks); 3: 315-block 0 call 0 returned 3 call 1 returned 3 -: 316:#endif -: 317:#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) -: 318: printf(_("\tIO Block: %d"), file_attrib.st_blksize); -: 319:#else 3: 320: printf(_("\tIO Block: %ld"), file_attrib.st_blksize); call 0 returned 3 call 1 returned 3 -: 321:#endif -: 322:#ifdef __OpenBSD__ -: 323: printf(_("\tInode: %llu\n"), file_attrib.st_ino); -: 324:#else 3: 325: printf(_("\tInode: %zu\n"), file_attrib.st_ino); call 0 returned 3 call 1 returned 3 -: 326:#endif -: 327:#ifdef __OpenBSD__ -: 328: printf(_("Device: %d"), file_attrib.st_dev); -: 329:#else 3: 330: printf(_("Device: %zu"), file_attrib.st_dev); call 0 returned 3 call 1 returned 3 -: 331:#endif 3*: 332: printf(_("\tUid: %u (%s)"), file_attrib.st_uid, (!owner) ? _("unknown") branch 0 taken 0 (fallthrough) branch 1 taken 3 %%%%%: 332-block 0 call 2 never executed unconditional 3 never executed 3: 332-block 1 unconditional 4 taken 3 3: 332-block 2 call 5 returned 3 call 6 returned 3 -: 333: : owner->pw_name); 3*: 334: printf(_("\tGid: %u (%s)\n"), file_attrib.st_gid, (!group) ? _("unknown") branch 0 taken 0 (fallthrough) branch 1 taken 3 %%%%%: 334-block 0 call 2 never executed unconditional 3 never executed 3: 334-block 1 unconditional 4 taken 3 3: 334-block 2 call 5 returned 3 call 6 returned 3 -: 335: : group->gr_name); -: 336: -: 337: /* Print file timestamps */ 3: 338: printf(_("Access: \t%s\n"), access_time); call 0 returned 3 call 1 returned 3 3: 339: printf(_("Modify: \t%s\n"), mod_time); call 0 returned 3 call 1 returned 3 3: 340: printf(_("Change: \t%s\n"), change_time); call 0 returned 3 call 1 returned 3 -: 341: -: 342:#if defined(HAVE_ST_BIRTHTIME) || defined(__BSD_VISIBLE) || defined(_STATX) 3: 343: printf(_("Birth: \t\t%s\n"), creation_time); call 0 returned 3 call 1 returned 3 -: 344:#endif -: 345: -: 346: /* Print size */ 3: 347: if ((file_attrib.st_mode & S_IFMT) == S_IFDIR) { branch 0 taken 1 (fallthrough) branch 1 taken 2 1: 348: if (dsize) { 1: 348-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 0 1: 349: fputs(_("Total size: \t"), stdout); 1: 349-block 0 call 0 returned 1 call 1 returned 1 1: 350: off_t total_size = dir_size(filename); call 0 returned 1 1: 351: if (total_size != -1) { branch 0 taken 1 (fallthrough) branch 1 taken 0 1: 352: char *human_size = get_size_unit(total_size * 1024); 1: 352-block 0 call 0 returned 1 1: 353: if (human_size) { branch 0 taken 1 (fallthrough) branch 1 taken 0 1: 354: printf("%s\n", human_size); 1: 354-block 0 call 0 returned 1 1: 355: free(human_size); unconditional 0 taken 1 -: 356: } else { #####: 357: puts("?"); %%%%%: 357-block 0 call 0 never executed unconditional 1 never executed -: 358: } -: 359: } else { #####: 360: puts("?"); %%%%%: 360-block 0 call 0 never executed unconditional 1 never executed -: 361: } -: 362: } -: 363: } else { 2*: 364: printf(_("Size: \t\t%s\n"), size_type ? size_type : "?"); 2: 364-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 0 2: 364-block 1 unconditional 2 taken 2 %%%%%: 364-block 2 unconditional 3 never executed 2: 364-block 3 call 4 returned 2 call 5 returned 2 unconditional 6 taken 2 -: 365: } -: 366: 3: 367: if (size_type) 3: 367-block 0 branch 0 taken 3 (fallthrough) branch 1 taken 0 3: 368: free(size_type); 3: 368-block 0 unconditional 0 taken 3 -: 369: 3: 370: return EXIT_SUCCESS; 3: 370-block 0 unconditional 0 taken 3 -: 371:} -: 372: -: 373:int function print_entry_props called 214 returned 100% blocks executed 70% 214: 374:print_entry_props(const struct fileinfo *props, size_t max) -: 375:{ -: 376: /* Get file size */ 214: 377: char *size_type = get_size_unit(props->size); 214: 377-block 0 call 0 returned 214 -: 378: -: 379: /* Get file type indicator */ 214: 380: char file_type = 0; -: 381: 214: 382: switch (props->mode & S_IFMT) { branch 0 taken 111 branch 1 taken 97 branch 2 taken 6 branch 3 taken 0 branch 4 taken 0 branch 5 taken 0 branch 6 taken 0 branch 7 taken 0 111: 383: case S_IFREG: file_type = '-'; break; 111: 383-block 0 unconditional 0 taken 111 97: 384: case S_IFDIR: file_type = 'd'; break; 97: 384-block 0 unconditional 0 taken 97 6: 385: case S_IFLNK: file_type = 'l'; break; 6: 385-block 0 unconditional 0 taken 6 #####: 386: case S_IFSOCK: file_type = 's'; break; %%%%%: 386-block 0 unconditional 0 never executed #####: 387: case S_IFBLK: file_type = 'b'; break; %%%%%: 387-block 0 unconditional 0 never executed #####: 388: case S_IFCHR: file_type = 'c'; break; %%%%%: 388-block 0 unconditional 0 never executed #####: 389: case S_IFIFO: file_type = 'p'; break; %%%%%: 389-block 0 unconditional 0 never executed #####: 390: default: file_type = '?'; %%%%%: 390-block 0 unconditional 0 never executed -: 391: } -: 392: -: 393: /* Get file permissions */ 214: 394: char read_usr = '-', write_usr = '-', exec_usr = '-', 214: 395: read_grp = '-', write_grp = '-', exec_grp = '-', 214: 396: read_others = '-', write_others = '-', exec_others = '-'; -: 397: 214: 398: mode_t val = (props->mode & (mode_t)~S_IFMT); 214: 399: if (val & S_IRUSR) read_usr = 'r'; 214: 399-block 0 branch 0 taken 214 (fallthrough) branch 1 taken 0 214: 399-block 1 unconditional 2 taken 214 214: 400: if (val & S_IWUSR) write_usr = 'w'; 214: 400-block 0 branch 0 taken 214 (fallthrough) branch 1 taken 0 214: 400-block 1 unconditional 2 taken 214 214: 401: if (val & S_IXUSR) exec_usr = 'x'; 214: 401-block 0 branch 0 taken 107 (fallthrough) branch 1 taken 107 107: 401-block 1 unconditional 2 taken 107 -: 402: 214: 403: if (val & S_IRGRP) read_grp = 'r'; 214: 403-block 0 branch 0 taken 13 (fallthrough) branch 1 taken 201 13: 403-block 1 unconditional 2 taken 13 214: 404: if (val & S_IWGRP) write_grp = 'w'; 214: 404-block 0 branch 0 taken 8 (fallthrough) branch 1 taken 206 8: 404-block 1 unconditional 2 taken 8 214: 405: if (val & S_IXGRP) exec_grp = 'x'; 214: 405-block 0 branch 0 taken 12 (fallthrough) branch 1 taken 202 12: 405-block 1 unconditional 2 taken 12 -: 406: 214: 407: if (val & S_IROTH) read_others = 'r'; 214: 407-block 0 branch 0 taken 13 (fallthrough) branch 1 taken 201 13: 407-block 1 unconditional 2 taken 13 214: 408: if (val & S_IWOTH) write_others = 'w'; 214: 408-block 0 branch 0 taken 6 (fallthrough) branch 1 taken 208 6: 408-block 1 unconditional 2 taken 6 214: 409: if (val & S_IXOTH) exec_others = 'x'; 214: 409-block 0 branch 0 taken 12 (fallthrough) branch 1 taken 202 12: 409-block 1 unconditional 2 taken 12 -: 410: 214: 411: if (props->mode & S_ISUID) 214: 411-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 214 #####: 412: (val & S_IXUSR) ? (exec_usr = 's') : (exec_usr = 'S'); %%%%%: 412-block 0 branch 0 never executed branch 1 never executed %%%%%: 412-block 1 unconditional 2 never executed %%%%%: 412-block 2 unconditional 3 never executed 214: 413: if (props->mode & S_ISGID) 214: 413-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 214 #####: 414: (val & S_IXGRP) ? (exec_grp = 's') : (exec_grp = 'S'); %%%%%: 414-block 0 branch 0 never executed branch 1 never executed %%%%%: 414-block 1 unconditional 2 never executed %%%%%: 414-block 2 unconditional 3 never executed 214: 415: if (props->mode & S_ISVTX) 214: 415-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 214 #####: 416: (val & S_IXOTH) ? (exec_others = 't'): (exec_others = 'T'); %%%%%: 416-block 0 branch 0 never executed branch 1 never executed %%%%%: 416-block 1 unconditional 2 never executed %%%%%: 416-block 2 unconditional 3 never executed -: 417: -: 418: /* Get modification time */ -: 419: char mod_time[128]; 214: 420: if (props->ltime) { 214: 420-block 0 branch 0 taken 214 (fallthrough) branch 1 taken 0 -: 421: struct tm t; 214: 422: localtime_r(&props->ltime, &t); 214: 422-block 0 call 0 returned 214 214: 423: snprintf(mod_time, 128, "%d-%02d-%02d %02d:%02d", t.tm_year + 1900, 214: 424: t.tm_mon + 1, t.tm_mday, t.tm_hour, t.tm_min); unconditional 0 taken 214 -: 425: } else { #####: 426: strcpy(mod_time, "- "); %%%%%: 426-block 0 unconditional 0 never executed -: 427: } -: 428: -: 429: /* Get owner and group names */ -: 430: /* struct group *group; -: 431: struct passwd *owner; -: 432: group = getgrgid(props->uid); -: 433: owner = getpwuid(props->gid); */ -: 434: -: 435: /* If file name length is greater than max, truncate it -: 436: * to max (later a tilde (~) will be appended to let the user know -: 437: * the file name was truncated) */ -: 438: char trim_name[NAME_MAX]; 214: 439: int trim = 0; -: 440: 214: 441: size_t cur_len = (size_t)props->eln_n + 1 + props->len; -: 442:#ifndef _NO_ICONS 214: 443: if (icons) { 214: 443-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 214 #####: 444: cur_len += 3; #####: 445: max += 3; %%%%%: 445-block 0 unconditional 0 never executed -: 446: } -: 447:#endif -: 448: 214: 449: if (cur_len > max) { 214: 449-block 0 branch 0 taken 16 (fallthrough) branch 1 taken 198 16: 450: int rest = (int)(cur_len - max); 16: 451: trim = 1; 16: 452: strcpy(trim_name, props->name); 16: 453: int a = (int)props->len - rest - 1; 16: 454: if (a < 0) 16: 454-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 16 #####: 455: a = 0; %%%%%: 455-block 0 unconditional 0 never executed 16: 456: if (unicode) 16: 456-block 0 branch 0 taken 16 (fallthrough) branch 1 taken 0 16: 457: u8truncstr(trim_name, (size_t)(a)); 16: 457-block 0 call 0 returned 16 unconditional 1 taken 16 -: 458: else #####: 459: trim_name[a] = '\0'; %%%%%: 459-block 0 unconditional 0 never executed 16: 460: cur_len -= (size_t)rest; 16: 460-block 0 unconditional 0 taken 16 -: 461: } -: 462: -: 463: /* Calculate pad for each file */ -: 464: int pad; 214: 465: pad = (int)(max - cur_len); 214: 466: if (pad < 0) 214: 466-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 214 #####: 467: pad = 0; %%%%%: 467-block 0 unconditional 0 never executed -: 468: -: 469:#ifndef _NO_ICONS 1712*: 470: printf("%s%s%c%s%s%s%-*s%s%c %c/%c%c%c/%c%c%c/%c%c%c%s " 214: 470-block 0 branch 0 taken 214 (fallthrough) branch 1 taken 0 214: 470-block 1 unconditional 2 taken 214 %%%%%: 470-block 2 unconditional 3 never executed 214: 470-block 3 unconditional 4 taken 214 %%%%%: 470-block 4 unconditional 5 never executed branch 6 taken 0 (fallthrough) branch 7 taken 214 %%%%%: 470-block 5 unconditional 8 never executed 214: 470-block 6 unconditional 9 taken 214 214: 470-block 7 branch 10 taken 16 (fallthrough) branch 11 taken 198 16: 470-block 8 unconditional 12 taken 16 198: 470-block 9 unconditional 13 taken 198 %%%%%: 470-block 10 unconditional 14 never executed 214: 470-block 11 unconditional 15 taken 214 214: 470-block 12 branch 16 taken 198 (fallthrough) branch 17 taken 16 198: 470-block 13 unconditional 18 taken 198 16: 470-block 14 unconditional 19 taken 16 214: 470-block 15 unconditional 20 taken 214 %%%%%: 470-block 16 unconditional 21 never executed %%%%%: 470-block 17 unconditional 22 never executed 214: 470-block 18 unconditional 23 taken 214 %%%%%: 470-block 19 unconditional 24 never executed 214: 470-block 20 unconditional 25 taken 214 214: 470-block 21 unconditional 26 taken 214 %%%%%: 470-block 22 unconditional 27 never executed 214: 470-block 23 call 28 returned 214 -: 471: "%u:%u %s %s\n", 214: 472: colorize ? props->icon_color : "", 214: 472-block 0 branch 0 taken 214 (fallthrough) branch 1 taken 0 428: 473: icons ? props->icon : "", icons ? ' ' : 0, 214: 473-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 214 214: 473-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 214 -: 474:#else -: 475: printf("%s%s%s%-*s%s%c %c/%c%c%c/%c%c%c/%c%c%c%s " -: 476: "%u:%u %s %s\n", -: 477:#endif 214: 478: colorize ? props->color : "", 214: 478-block 0 branch 0 taken 214 (fallthrough) branch 1 taken 0 -: 479: !trim ? props->name : trim_name, 214: 480: light_mode ? "" : df_c, pad, "", df_c, 214: 480-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 214 -: 481: trim ? '~' : 0, file_type, -: 482: read_usr, write_usr, exec_usr, -: 483: read_grp, write_grp, exec_grp, -: 484: read_others, write_others, exec_others, 214: 485: is_acl(props->name) ? "+" : "", -: 486: /* !owner ? _("?") : owner->pw_name, -: 487: !group ? _("?") : group->gr_name, */ 214: 488: props->uid, props->gid, 214: 488-block 0 call 0 returned 214 214: 489: *mod_time ? mod_time : "?", 214: 489-block 0 branch 0 taken 214 (fallthrough) branch 1 taken 0 -: 490: size_type ? size_type : "?"); -: 491: 214: 492: if (size_type) branch 0 taken 214 (fallthrough) branch 1 taken 0 214: 493: free(size_type); 214: 493-block 0 unconditional 0 taken 214 -: 494: 214: 495: return EXIT_SUCCESS; 214: 495-block 0 unconditional 0 taken 214 -: 496:} -: 497: -: 498:int function properties_function called 3 returned 100% blocks executed 62% 3: 499:properties_function(char **comm) -: 500:{ 3: 501: if (!comm) 3: 501-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 3 #####: 502: return EXIT_FAILURE; %%%%%: 502-block 0 unconditional 0 never executed -: 503: -: 504: size_t i; 3: 505: int exit_status = EXIT_SUCCESS; 3: 506: int _dir_size = 0; -: 507: 3: 508: if (*comm[0] == 'p' && comm[0][1] == 'p' && !comm[0][2]) 3: 508-block 0 branch 0 taken 3 (fallthrough) branch 1 taken 0 3: 508-block 1 branch 2 taken 1 (fallthrough) branch 3 taken 2 1: 508-block 2 branch 4 taken 1 (fallthrough) branch 5 taken 0 1: 509: _dir_size = 1; 1: 509-block 0 unconditional 0 taken 1 -: 510: -: 511: /* If "pr file file..." */ 6: 512: for (i = 1; i <= args_n; i++) { 3: 512-block 0 unconditional 0 taken 3 3: 512-block 1 unconditional 1 taken 3 6: 512-block 2 branch 2 taken 3 branch 3 taken 3 (fallthrough) 3: 513: if (strchr(comm[i], '\\')) { 3: 513-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 3 #####: 514: char *deq_file = dequote_str(comm[i], 0); %%%%%: 514-block 0 call 0 never executed #####: 515: if (!deq_file) { branch 0 never executed branch 1 never executed #####: 516: fprintf(stderr, _("%s: %s: Error dequoting file name\n"), call 0 never executed #####: 517: PROGRAM_NAME, comm[i]); %%%%%: 517-block 0 call 0 never executed #####: 518: exit_status = EXIT_FAILURE; #####: 519: continue; unconditional 0 never executed -: 520: } -: 521: #####: 522: strcpy(comm[i], deq_file); #####: 523: free(deq_file); %%%%%: 523-block 0 unconditional 0 never executed -: 524: } -: 525: 3: 526: if (get_properties(comm[i], _dir_size) != 0) 3: 526-block 0 call 0 returned 3 branch 1 taken 0 (fallthrough) branch 2 taken 3 #####: 527: exit_status = EXIT_FAILURE; %%%%%: 527-block 0 unconditional 0 never executed -: 528: } -: 529: 3: 530: return exit_status; 3: 530-block 0 unconditional 0 taken 3 -: 531:} clifm-1.26.3/misc/codecov/readline.c.gcov000066400000000000000000003041451506632037700201560ustar00rootroot00000000000000 -: 0:Source:readline.c -: 1:/* readline.c -- functions to control the behaviour of readline, -: 2: * specially completions. It also introduces the suggestions system -: 3: * via my_rl_getc function */ -: 4: -: 5:/* -: 6: * This file is part of CliFM -: 7: * -: 8: * Copyright (C) 2016-2021, L. Abramovich -: 9: * All rights reserved. -: 10: -: 11: * CliFM is free software; you can redistribute it and/or modify -: 12: * it under the terms of the GNU General Public License as published by -: 13: * the Free Software Foundation; either version 2 of the License, or -: 14: * (at your option) any later version. -: 15: * -: 16: * CliFM is distributed in the hope that it will be useful, -: 17: * but WITHOUT ANY WARRANTY; without even the implied warranty of -: 18: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -: 19: * GNU General Public License for more details. -: 20: * -: 21: * You should have received a copy of the GNU General Public License -: 22: * along with this program; if not, write to the Free Software -: 23: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, -: 24: * MA 02110-1301, USA. -: 25:*/ -: 26: -: 27:#include "helpers.h" -: 28: -: 29:#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) -: 30:#include -: 31:#endif -: 32:#include -: 33:#include -: 34:#include -: 35:#include -: 36:#ifdef __OpenBSD__ -: 37:#include -: 38:#endif -: 39:#include -: 40:#include -: 41: -: 42:#ifdef __OpenBSD__ -: 43:typedef char *rl_cpvfunc_t; -: 44:#include -: 45:#include -: 46:#else -: 47:#include -: 48:#include -: 49:#endif -: 50: -: 51:#include "misc.h" -: 52:#include "aux.h" -: 53:#include "checks.h" -: 54:#include "keybinds.h" -: 55:#include "navigation.h" -: 56:#include "readline.h" -: 57:#ifndef _NO_SUGGESTIONS -: 58:#include "suggestions.h" -: 59:#endif -: 60: -: 61:#if !defined(_NO_SUGGESTIONS) && defined(__FreeBSD__) -: 62:int freebsd_sc_console = 0; -: 63:#endif /* __FreeBSD__ */ -: 64: -: 65:/* -: 66:#ifndef _NO_HIGHLIGHT -: 67:#define _SINGLE 0 -: 68:#define _DOUBLE 1 -: 69: -: 70:static char * -: 71:get_cur_color(const int point) -: 72:{ -: 73: int m = point; -: 74: int sep = -1, sp = -1, t = -1; -: 75: char *c = (char *)NULL; -: 76: m--; -: 77: -: 78: -: 79: while (m >= 0) { -: 80: switch(rl_line_buffer[m]) { -: 81: case ' ': sp = m; break; -: 82: case '&': // fallthrough -: 83: case '|': // fallthrough -: 84: case ';': sep = m; break; -: 85: case '\'': // fallthrough -: 86: case '"': c = hq_c; t = m; break; -: 87: case '-': c = hp_c; t = m; break; -: 88: case '#': c = hc_c; t = m; break; -: 89: case '$': c = hv_c; t = m; break; -: 90: default: c = df_c; break; -: 91: } -: 92: -: 93: if (t != -1) -: 94: break; -: 95: -: 96: --m; -: 97: } -: 98: -: 99: if (t != -1) { -: 100: if (c == hc_c || c == hq_c) { -: 101: if (t > sep) -: 102: return c; -: 103: else -: 104: return df_c; -: 105: } else { -: 106: if (t > sep && t > sp) -: 107: return c; -: 108: else -: 109: return df_c; -: 110: } -: 111: } -: 112: -: 113: return df_c; -: 114:} -: 115: -: 116:static char * -: 117:get_highlight_color(const char c, const size_t *qn, const int point) -: 118:{ -: 119: if (c >= '0' && c <= '9') -: 120: return hn_c; -: 121: -: 122: char *cl = cur_color; -: 123: char *p = (char *)NULL; -: 124: static int open_quote = 0; -: 125: -: 126: switch(c) { -: 127: case '{': // fallthrough -: 128: case '}': // fallthrough -: 129: case '(': // fallthrough -: 130: case ')': // fallthrough -: 131: case '[': // fallthrough -: 132: case ']': p = hb_c; break; -: 133: -: 134: case '#': p = hc_c; break; -: 135: case '~': // fallthrough -: 136: case '*': p = he_c; break; -: 137: case '-': p = hp_c; break; -: 138: -: 139: case '\'': -: 140: case '"': -: 141: if ((qn[(c == '\'' ? _SINGLE : _DOUBLE)] + 1) % 2 == 0) { -: 142: open_quote = 0; -: 143: p = df_c; -: 144: } else { -: 145: p = hq_c; -: 146: open_quote = 1; -: 147: } -: 148: break; -: 149: -: 150: case '>': p = hr_c; break; -: 151: case '|': // fallthrough -: 152: case ';': // fallthrough -: 153: case '&': p = hs_c; break; -: 154: case '$': p = hv_c; break; -: 155: -: 156: case ENTER: p = df_c; break; -: 157: -: 158: case ' ': return (char *)NULL; -: 159: // It works, but open_quote should be !open_quote -: 160: if (open_quote && cl != hc_c) -: 161: p = df_c; -: 162: break; -: 163: -: 164: default: -: 165: if (point < rl_end) -: 166: p = get_cur_color(point); -: 167: else if (open_quote && cl != hv_c && cl != hp_c && cl != hc_c) -: 168: p = df_c; -: 169: break; -: 170: } -: 171: -: 172: return p; -: 173:} -: 174: -: 175:static void -: 176:rl_highlight(const char c) -: 177:{ -: 178: if (rl_readline_state & RL_STATE_MOREINPUT) -: 179: return; -: 180: -: 181: if (c < 32 && c != BS && c != ENTER) -: 182: return; -: 183: -: 184: if (rl_end == 1 && (c == BS || c == 127)) { -: 185: cur_color = df_c; -: 186: return; -: 187: } -: 188: -: 189: int m = rl_point; -: 190: size_t qn[2] = {0}; -: 191: m--; -: 192: -: 193: while (m >= 0) { -: 194: if (rl_line_buffer[m] == '\'') -: 195: qn[_SINGLE]++; -: 196: else if (rl_line_buffer[m] == '"') -: 197: qn[_DOUBLE]++; -: 198: --m; -: 199: } -: 200: -: 201: char *p = rl_line_buffer; -: 202: char *cl = (char *)NULL; -: 203: int bk = rl_point; -: 204: rl_point = 0; -: 205: -: 206: for (rl_point = 0; p[rl_point]; rl_point++) -: 207: cl = get_highlight_color(p[rl_point], qn, bk); -: 208: -: 209: cl = get_highlight_color(c, qn, bk); -: 210: -: 211: rl_point = bk; -: 212: -: 213: int skip = 0; -: 214: if ((c == '\'' && qn[_SINGLE] % 2 != 0) -: 215: || (c == '"' && qn[_DOUBLE] % 2 != 0)) -: 216: skip = 1; -: 217: -: 218: if (!skip && cl) { -: 219: cur_color = cl; -: 220: fputs(cl, stdout); -: 221: } -: 222: -: 223: return; -: 224:} */ -: 225: -: 226:/* -: 227:static void -: 228:rl_highlight(const char ch) -: 229:{ -: 230: char *c = cur_color; -: 231: static int skip = 0, open_quote = 0; -: 232: int d = 0; -: 233: -: 234: if (rl_readline_state & RL_STATE_MOREINPUT) -: 235: return; -: 236: -: 237: if (ch < 32 && ch != BS && ch != ENTER) -: 238: return; -: 239: -: 240: if (rl_point == rl_end) { -: 241: if (ch >= '0' && ch <= '9') { -: 242: fputs(hn_c, stdout); -: 243: fflush(stdout); -: 244: cur_color = hn_c; -: 245: return; -: 246: } -: 247: -: 248: switch(ch) { -: 249: case '(': // fallthrough -: 250: case ')': // fallthrough -: 251: case '[': // fallthrough -: 252: case ']': // fallthrough -: 253: case '{': // fallthrough -: 254: case '}': c = hb_c; skip = 0; d = 2; break; -: 255: -: 256: case '#': c = hc_c; d = 1; skip = 0; break; -: 257: -: 258: case '-': c = hp_c; d = 1; skip = 0; break; -: 259: -: 260: case '"': // fallthrough -: 261: case '\'': -: 262: c = hq_c; -: 263: size_t n = 0; -: 264: char *p = rl_line_buffer; -: 265: while (*p) { -: 266: if (*p == ch) -: 267: n++; -: 268: p++; -: 269: } -: 270: if (++n % 2 != 0) { // Opening quote -: 271: // Keep color until closing quote is entered -: 272: skip = 0; -: 273: d = 1; -: 274: open_quote = 1; -: 275: } else { // Closing quote -: 276: // Reset to default color -: 277: c = df_c; -: 278: skip = 1; -: 279: d = 2; -: 280: open_quote = 0; -: 281: } -: 282: break; -: 283: -: 284: case '~': // fallthrough -: 285: case '*': c = he_c; skip = 0; d = 2; break; -: 286: -: 287: case '$': c = hv_c; d = 1; skip = 0; break; -: 288: -: 289: case '>': c = hr_c; skip = 0; d = 2; break; -: 290: -: 291: case '&': // fallthrough -: 292: case ';': // fallthrough -: 293: case '|': c = hs_c; skip = 0; d = 2; break; -: 294: -: 295: case ENTER: c = df_c; skip = 0; break; -: 296: case ' ': -: 297: if (!open_quote && c != hc_c) { -: 298: c = df_c; -: 299: skip = 0; -: 300: } -: 301: break; -: 302: default: -: 303: if (c != hv_c && !open_quote) -: 304: c = df_c; -: 305: break; -: 306: } -: 307: -: 308: if (rl_end == 1 && (ch == BS || ch == 127)) -: 309: c = df_c; -: 310: -: 311: goto END; -: 312: } -: 313: -: 314: int m = rl_point; -: 315: int separator = -1; -: 316: int t = -1; -: 317: size_t q_count[2] = {0}, single = 0, _double = 1; -: 318: skip = 0; -: 319: m--; -: 320: -: 321: while (m >= 0) { -: 322: if (rl_line_buffer[m] == '\'') -: 323: q_count[single]++; -: 324: if (rl_line_buffer[m] == '"') -: 325: q_count[_double]++; -: 326: --m; -: 327: } -: 328: -: 329: m = rl_point; -: 330: if (rl_line_buffer[m] != '"' && rl_line_buffer[m] != '\'') -: 331: --m; -: 332: while (m >= 0) { -: 333: switch(rl_line_buffer[m]) { -: 334: case ' ': separator = m; break; -: 335: -: 336: case '&': // fallthrough -: 337: case ';': // fallthrough -: 338: case '|': d = 1; c = df_c; break; -: 339: -: 340: case '#': c = hc_c; d = 1; t = m; break; -: 341: case '\'': -: 342: if (q_count[single] % 2 != 0) { -: 343: c = hq_c; -: 344: d = 1; -: 345: t = m; -: 346: } -: 347: break; -: 348: case '"': -: 349: if (q_count[_double] % 2 != 0) { -: 350: c = hq_c; -: 351: d = 1; -: 352: t = m; -: 353: } -: 354: break; -: 355: case '$': c = hv_c; d = 1; t = m; break; -: 356: case '-': c = hp_c; d = 1; t = m; break; -: 357: default: c = df_c; break; -: 358: } -: 359: --m; -: 360: -: 361: if (d && c != hc_c && c != hq_c && separator > t) { -: 362: c = df_c; -: 363: continue; -: 364: } -: 365: -: 366: if (d) -: 367: break; -: 368: } -: 369: -: 370: if (rl_end == 1 && (ch == BS || ch == 127)) -: 371: c = df_c; -: 372: -: 373: if (t != -1) -: 374: goto END; -: 375: -: 376: d = 0; -: 377: switch(ch) { -: 378: case '0': // fallthrough -: 379: case '1': // fallthrough -: 380: case '2': // fallthrough -: 381: case '3': // fallthrough -: 382: case '4': // fallthrough -: 383: case '5': // fallthrough -: 384: case '6': // fallthrough -: 385: case '7': // fallthrough -: 386: case '8': // fallthrough -: 387: case '9': c = hn_c; skip = 0; d = 2; break; -: 388: case ' ': return; -: 389: case '(': // fallthrough -: 390: case ')': // fallthrough -: 391: case '[': // fallthrough -: 392: case ']': // fallthrough -: 393: case '{': // fallthrough -: 394: case '}': c = hb_c; skip = 0; d = 2; break; -: 395: case '~': // fallthrough -: 396: case '*': c = he_c; skip = 0; d = 2; break; -: 397: case '>': c = hr_c; skip = 0; d = 2; break; -: 398: case '&': // fallthrough -: 399: case ';': // fallthrough -: 400: case '|': c = hs_c; skip = 0; d = 2; break; -: 401: } -: 402: -: 403: if (rl_end == 1 && (ch == BS || ch == 127)) -: 404: c = df_c; -: 405: -: 406:END: -: 407: if (!skip) { -: 408: fputs(c, stdout); -: 409: fflush(stdout); -: 410: } -: 411: -: 412: if (d == 1) { -: 413: skip = 1; -: 414: } else if (d == 2) { -: 415: skip = 0; -: 416: c = df_c; -: 417: } -: 418: -: 419: cur_color = c; -: 420: return; -: 421:} -: 422:#endif */ -: 423: -: 424:/* This function is automatically called by readline() to handle input. -: 425: * Taken from Bash 1.14.7 and modified to fit our needs. Used -: 426: * to introduce the suggestions system */ -: 427:static int function my_rl_getc called 2984 returned 100% blocks executed 34% 3004: 428:my_rl_getc(FILE *stream) -: 429:{ -: 430: int result; -: 431: unsigned char c; -: 432: -: 433:#if defined(__GO32__) -: 434: if (isatty(0)) -: 435: return (getkey() & 0x7F); -: 436:#endif /* __GO32__ */ -: 437: -: 438: while(1) { 3004: 439: result = (int)read(fileno(stream), &c, sizeof(unsigned char)); 3004: 439-block 0 call 0 returned 3004 call 1 returned 3004 3004: 440: if (result == sizeof(unsigned char)) { branch 0 taken 3004 (fallthrough) branch 1 taken 0 -: 441:/*#ifndef _NO_HIGHLIGHT -: 442: if (highlight) -: 443: rl_highlight(c); -: 444:#endif // _NO_HIGHLIGHT */ -: 445: -: 446:#ifndef _NO_SUGGESTIONS 3004: 447: if (suggestions) { 3004: 447-block 0 branch 0 taken 2893 (fallthrough) branch 1 taken 111 -: 448: /* rl_suggestions returns -1 is C was inserted before -: 449: * the end of the current line, in which case we don't -: 450: * want to return it here (otherwise, it would be added -: 451: * to rl_line_buffer) */ -: 452:#ifdef __FreeBSD__ -: 453: /* For the time being, suggestions do not work on the FreeBSD -: 454: * console (vt). The escape code to retrieve the current cursor -: 455: * position doesn't seem to work. Switching the console to 'sc' -: 456: * solves the issue */ -: 457: if (flags & GUI) { -: 458: if (rl_suggestions(c) == -1) { -: 459: rl_redisplay(); -: 460: continue; -: 461: } -: 462: } else if (freebsd_sc_console && rl_suggestions(c) == -1) { -: 463: rl_redisplay(); -: 464: continue; -: 465: } -: 466:#else 2893: 467: if (rl_suggestions(c) == -1) { 2893: 467-block 0 call 0 returned 2893 branch 1 taken 20 (fallthrough) branch 2 taken 2873 20: 468: rl_redisplay(); 20: 468-block 0 call 0 returned 20 20: 469: continue; unconditional 0 taken 20 -: 470: } -: 471:#endif /* __FreeBSD__ */ -: 472: } -: 473:#endif /* _NO_SUGGESTIONS */ 2984: 474: return (c); 2984: 474-block 0 unconditional 0 taken 2984 -: 475: } -: 476: /* If zero characters are returned, then the file that we are -: 477: reading from is empty! Return EOF in that case. */ #####: 478: if (result == 0) %%%%%: 478-block 0 branch 0 never executed branch 1 never executed #####: 479: return (EOF); %%%%%: 479-block 0 unconditional 0 never executed -: 480: -: 481:#if defined(EWOULDBLOCK) #####: 482: if (errno == EWOULDBLOCK) { %%%%%: 482-block 0 branch 0 never executed branch 1 never executed -: 483: int xflags; -: 484: #####: 485: if ((xflags = fcntl(fileno(stream), F_GETFL, 0)) < 0) %%%%%: 485-block 0 call 0 never executed call 1 never executed branch 2 never executed branch 3 never executed #####: 486: return (EOF); %%%%%: 486-block 0 unconditional 0 never executed #####: 487: if (xflags & O_NDELAY) { %%%%%: 487-block 0 branch 0 never executed branch 1 never executed -: 488:/* xflags &= ~O_NDELAY; */ #####: 489: fcntl(fileno(stream), F_SETFL, flags); %%%%%: 489-block 0 call 0 never executed call 1 never executed #####: 490: continue; unconditional 0 never executed -: 491: } #####: 492: continue; %%%%%: 492-block 0 unconditional 0 never executed -: 493: } -: 494:#endif /* EWOULDBLOCK */ -: 495: -: 496:#if defined(_POSIX_VERSION) && defined(EAGAIN) && defined(O_NONBLOCK) #####: 497: if (errno == EAGAIN) { %%%%%: 497-block 0 branch 0 never executed branch 1 never executed -: 498: int xflags; -: 499: #####: 500: if ((xflags = fcntl(fileno(stream), F_GETFL, 0)) < 0) %%%%%: 500-block 0 call 0 never executed call 1 never executed branch 2 never executed branch 3 never executed #####: 501: return (EOF); %%%%%: 501-block 0 unconditional 0 never executed #####: 502: if (xflags & O_NONBLOCK) { %%%%%: 502-block 0 branch 0 never executed branch 1 never executed -: 503:// xflags &= ~O_NONBLOCK; #####: 504: fcntl(fileno(stream), F_SETFL, flags); %%%%%: 504-block 0 call 0 never executed call 1 never executed #####: 505: continue; unconditional 0 never executed -: 506: } -: 507: } -: 508:#endif /* _POSIX_VERSION && EAGAIN && O_NONBLOCK */ -: 509: -: 510:#if !defined(__GO32__) -: 511: /* If the error that we received was SIGINT, then try again, -: 512: this is simply an interrupted system call to read (). -: 513: Otherwise, some error ocurred, also signifying EOF. */ #####: 514: if (errno != EINTR) %%%%%: 514-block 0 branch 0 never executed branch 1 never executed #####: 515: return (EOF); %%%%%: 515-block 0 unconditional 0 never executed -: 516:#endif /* !__GO32__ */ -: 517: } -: 518:} -: 519: -: 520:/* Simply check a single chartacter (c) against the quoting characters -: 521: * list defined in the qc global array (which takes its values from -: 522: * rl_filename_quote_characters */ -: 523:int function is_quote_char called 2622 returned 100% blocks executed 89% 2622: 524:is_quote_char(const char c) -: 525:{ 2622: 526: if (c == '\0' || !qc) 2622: 526-block 0 branch 0 taken 2622 (fallthrough) branch 1 taken 0 2622: 526-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 2622 #####: 527: return -1; %%%%%: 527-block 0 unconditional 0 never executed -: 528: 2622: 529: char *p = qc; -: 530: 70785: 531: while (*p) { 2622: 531-block 0 unconditional 0 taken 2622 70785: 531-block 1 branch 1 taken 68164 branch 2 taken 2621 (fallthrough) 68164: 532: if (c == *(p++)) 68164: 532-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 68163 1: 533: return 1; 1: 533-block 0 unconditional 0 taken 1 -: 534: } -: 535: 2621: 536: return 0; 2621: 536-block 0 unconditional 0 taken 2621 -: 537:} -: 538: -: 539:char * function rl_no_hist called 37 returned 100% blocks executed 79% 37: 540:rl_no_hist(const char *prompt) -: 541:{ 37: 542: int bk = suggestions; 37: 543: suggestions = 0; 37: 544: stifle_history(0); /* Prevent readline from using the history 37: 544-block 0 call 0 returned 37 -: 545: setting */ 37: 546: char *input = readline(prompt); call 0 returned 37 37: 547: unstifle_history(); /* Reenable history */ call 0 returned 37 37: 548: read_history(hist_file); /* Reload history lines from file */ call 0 returned 37 37: 549: suggestions = bk; -: 550: 37: 551: if (input) { branch 0 taken 37 (fallthrough) branch 1 taken 0 -: 552: /* Make sure input isn't empty string */ 37: 553: if (!*input) { 37: 553-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 37 #####: 554: free(input); #####: 555: return (char *)NULL; %%%%%: 555-block 0 unconditional 0 never executed -: 556: } -: 557: -: 558: /* Check we have some non-blank char */ 37: 559: int no_blank = 0; 37: 560: char *p = input; -: 561: 37: 562: while (*p) { 37: 562-block 0 unconditional 0 taken 37 37: 562-block 1 branch 1 taken 37 branch 2 taken 0 (fallthrough) 37: 563: if (*p != ' ' && *p != '\n' && *p != '\t') { 37: 563-block 0 branch 0 taken 37 (fallthrough) branch 1 taken 0 37: 563-block 1 branch 2 taken 37 (fallthrough) branch 3 taken 0 37: 563-block 2 branch 4 taken 37 (fallthrough) branch 5 taken 0 37: 564: no_blank = 1; 37: 565: break; 37: 565-block 0 unconditional 0 taken 37 -: 566: } #####: 567: p++; %%%%%: 567-block 0 unconditional 0 never executed -: 568: } -: 569: 37: 570: if (!no_blank) { 37: 570-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 37 #####: 571: free(input); #####: 572: return (char *)NULL; %%%%%: 572-block 0 unconditional 0 never executed -: 573: } -: 574: 37: 575: return input; 37: 575-block 0 unconditional 0 taken 37 -: 576: } -: 577: #####: 578: return (char *)NULL; %%%%%: 578-block 0 unconditional 0 never executed -: 579:} -: 580: -: 581:/* Used by readline to check if a char in the string being completed is -: 582: * quoted or not */ -: 583:static int function quote_detector called 0 returned 0% blocks executed 0% #####: 584:quote_detector(char *line, int index) -: 585:{ #####: 586: if (index > 0 && line[index - 1] == '\\' && !quote_detector(line, index - 1)) %%%%%: 586-block 0 branch 0 never executed branch 1 never executed %%%%%: 586-block 1 branch 2 never executed branch 3 never executed %%%%%: 586-block 2 call 4 never executed branch 5 never executed branch 6 never executed #####: 587: return 1; %%%%%: 587-block 0 unconditional 0 never executed -: 588: #####: 589: return 0; %%%%%: 589-block 0 unconditional 0 never executed -: 590:} -: 591: -: 592:/* Performs bash-style filename quoting for readline (put a backslash -: 593: * before any char listed in rl_filename_quote_characters. -: 594: * Modified version of: -: 595: * https://utcc.utoronto.ca/~cks/space/blog/programming/ReadlineQuotingExample*/ -: 596:static char * function my_rl_quote called 0 returned 0% blocks executed 0% #####: 597:my_rl_quote(char *text, int mt, char *qp) -: 598:{ -: 599: /* NOTE: mt and qp arguments are not used here, but are required by -: 600: * rl_filename_quoting_function */ -: 601: UNUSED(mt); UNUSED(qp); -: 602: -: 603: /* -: 604: * How it works: P and R are pointers to the same memory location -: 605: * initialized (calloced) twice as big as the line that needs to be -: 606: * quoted (in case all chars in the line need to be quoted); TP is a -: 607: * pointer to TEXT, which contains the string to be quoted. We move -: 608: * through TP to find all chars that need to be quoted ("a's" becomes -: 609: * "a\'s", for example). At this point we cannot return P, since this -: 610: * pointer is at the end of the string, so that we return R instead, -: 611: * which is at the beginning of the same string pointed to by P. -: 612: * */ #####: 613: char *r = (char *)NULL, *p = (char *)NULL, *tp = (char *)NULL; -: 614: #####: 615: size_t text_len = strlen(text); -: 616: /* Worst case: every character of text needs to be escaped. In this -: 617: * case we need 2x text's bytes plus the NULL byte. */ #####: 618: p = (char *)xnmalloc((text_len * 2) + 1, sizeof(char)); %%%%%: 618-block 0 call 0 never executed #####: 619: r = p; -: 620: #####: 621: if (r == NULL) branch 0 never executed branch 1 never executed #####: 622: return (char *)NULL; %%%%%: 622-block 0 unconditional 0 never executed -: 623: -: 624: /* Escape whatever char that needs to be escaped */ #####: 625: for (tp = text; *tp; tp++) { %%%%%: 625-block 0 unconditional 0 never executed %%%%%: 625-block 1 branch 1 never executed branch 2 never executed #####: 626: if (is_quote_char(*tp)) %%%%%: 626-block 0 call 0 never executed branch 1 never executed branch 2 never executed #####: 627: *p++ = '\\'; %%%%%: 627-block 0 unconditional 0 never executed -: 628: #####: 629: *p++ = *tp; %%%%%: 629-block 0 unconditional 0 never executed -: 630: } -: 631: -: 632: /* Add a final null byte to the string */ #####: 633: *p = '\0'; #####: 634: return r; %%%%%: 634-block 0 unconditional 0 never executed -: 635:} -: 636: -: 637:/* This is the filename_completion_function() function of an old Bash -: 638: * release (1.14.7) modified to fit CliFM needs */ -: 639:static char * function my_rl_path_completion called 4523 returned 100% blocks executed 48% 4523: 640:my_rl_path_completion(const char *text, int state) -: 641:{ 4523: 642: if (!text || !*text) 4523: 642-block 0 branch 0 taken 4523 (fallthrough) branch 1 taken 0 4523: 642-block 1 branch 2 taken 9 (fallthrough) branch 3 taken 4514 9: 643: return (char *)NULL; 9: 643-block 0 unconditional 0 taken 9 -: 644: /* state is zero before completion, and 1 ... n after getting -: 645: * possible completions. Example: -: 646: * cd Do[TAB] -> state 0 -: 647: * cuments/ -> state 1 -: 648: * wnloads/ -> state 2 -: 649: * */ -: 650: -: 651: /* Dequote string to be completed (text), if necessary */ -: 652: static char *tmp_text = (char *)NULL; -: 653: 4514: 654: if (strchr(text, '\\')) { 4514: 654-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 4514 #####: 655: char *p = savestring(text, strlen(text)); %%%%%: 655-block 0 call 0 never executed #####: 656: tmp_text = dequote_str(p, 0); call 0 never executed #####: 657: free(p); #####: 658: p = (char *)NULL; #####: 659: if (!tmp_text) branch 0 never executed branch 1 never executed #####: 660: return (char *)NULL; %%%%%: 660-block 0 unconditional 0 never executed -: 661: } -: 662: 4514: 663: if (*text == '.' && text[1] == '.' && text[2] == '.') { 4514: 663-block 0 branch 0 taken 6 (fallthrough) branch 1 taken 4508 6: 663-block 1 branch 2 taken 2 (fallthrough) branch 3 taken 4 2: 663-block 2 branch 4 taken 2 (fallthrough) branch 5 taken 0 2: 664: char *p = savestring(text, strlen(text)); 2: 664-block 0 call 0 returned 2 2: 665: tmp_text = fastback(p); call 0 returned 2 -: 666: 2: 667: free(p); 2: 668: p = (char *)NULL; -: 669: 2: 670: if (!tmp_text) branch 0 taken 0 (fallthrough) branch 1 taken 2 #####: 671: return (char *)NULL; %%%%%: 671-block 0 unconditional 0 never executed -: 672: } -: 673: -: 674:/* int rl_complete_with_tilde_expansion = 0; */ -: 675: /* ~/Doc -> /home/user/Doc */ -: 676: -: 677: static DIR *directory; -: 678: static char *filename = (char *)NULL; -: 679: static char *dirname = (char *)NULL; -: 680: static char *users_dirname = (char *)NULL; -: 681: static size_t filename_len; -: 682: static int match, ret; 4514: 683: struct dirent *ent = (struct dirent *)NULL; -: 684: static int exec = 0, exec_path = 0; -: 685: static char *dir_tmp = (char *)NULL; -: 686: static char tmp[PATH_MAX]; -: 687: -: 688: /* If we don't have any state, then do some initialization. */ 4514: 689: if (!state) { 4514: 689-block 0 branch 0 taken 401 (fallthrough) branch 1 taken 4113 -: 690: char *temp; -: 691: 401: 692: if (dirname) 401: 692-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 401 #####: 693: free(dirname); %%%%%: 693-block 0 unconditional 0 never executed 401: 694: if (filename) 401: 694-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 401 #####: 695: free(filename); %%%%%: 695-block 0 unconditional 0 never executed 401: 696: if (users_dirname) 401: 696-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 401 #####: 697: free(users_dirname); %%%%%: 697-block 0 unconditional 0 never executed -: 698: -: 699: /* tmp_text is true whenever text was dequoted */ 401: 700: size_t text_len = strlen((tmp_text) ? tmp_text : text); 401: 700-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 400 1: 700-block 1 unconditional 2 taken 1 400: 700-block 2 unconditional 3 taken 400 401: 701: if (text_len) 401: 701-block 0 branch 0 taken 401 (fallthrough) branch 1 taken 0 401: 702: filename = savestring((tmp_text) ? tmp_text : text, text_len); 401: 702-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 400 1: 702-block 1 unconditional 2 taken 1 400: 702-block 2 unconditional 3 taken 400 401: 702-block 3 call 4 returned 401 unconditional 5 taken 401 -: 703: else #####: 704: filename = savestring("", 1); %%%%%: 704-block 0 call 0 never executed unconditional 1 never executed -: 705: 401: 706: if (!*text) 401: 706-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 401 #####: 707: text = "."; %%%%%: 707-block 0 unconditional 0 never executed -: 708: 401: 709: if (text_len) 401: 709-block 0 branch 0 taken 401 (fallthrough) branch 1 taken 0 401: 710: dirname = savestring((tmp_text) ? tmp_text : text, text_len); 401: 710-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 400 1: 710-block 1 unconditional 2 taken 1 400: 710-block 2 unconditional 3 taken 400 401: 710-block 3 call 4 returned 401 unconditional 5 taken 401 -: 711: else #####: 712: dirname = savestring("", 1); %%%%%: 712-block 0 call 0 never executed unconditional 1 never executed -: 713: 401: 714: if (dirname[0] == '.' && dirname[1] == '/') 401: 714-block 0 branch 0 taken 3 (fallthrough) branch 1 taken 398 3: 714-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 3 #####: 715: exec = 1; %%%%%: 715-block 0 unconditional 0 never executed -: 716: else 401: 717: exec = 0; 401: 717-block 0 unconditional 0 taken 401 -: 718: -: 719: /* Get everything after last slash */ 401: 720: temp = strrchr(dirname, '/'); -: 721: 401: 722: if (temp) { 401: 722-block 0 branch 0 taken 40 (fallthrough) branch 1 taken 361 40: 723: strcpy(filename, ++temp); 40: 724: *temp = '\0'; 40: 724-block 0 unconditional 0 taken 40 -: 725: } else { 361: 726: strcpy(dirname, "."); 361: 726-block 0 unconditional 0 taken 361 -: 727: } -: 728: -: 729: /* We aren't done yet. We also support the "~user" syntax. */ -: 730: -: 731: /* Save the version of the directory that the user typed. */ 401: 732: size_t dirname_len = strlen(dirname); -: 733: 401: 734: users_dirname = savestring(dirname, dirname_len); 401: 734-block 0 call 0 returned 401 -: 735: /* { */ -: 736: char *temp_dirname; -: 737: int replace_dirname; -: 738: 401: 739: temp_dirname = tilde_expand(dirname); call 0 returned 401 401: 740: free(dirname); 401: 741: dirname = temp_dirname; -: 742: 401: 743: replace_dirname = 0; -: 744: 401: 745: if (rl_directory_completion_hook) branch 0 taken 0 (fallthrough) branch 1 taken 401 #####: 746: replace_dirname = (*rl_directory_completion_hook)(&dirname); %%%%%: 746-block 0 call 0 never executed unconditional 1 never executed -: 747: 401: 748: if (replace_dirname) { 401: 748-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 401 #####: 749: free(users_dirname); #####: 750: users_dirname = savestring(dirname, dirname_len); %%%%%: 750-block 0 call 0 never executed unconditional 1 never executed -: 751: } -: 752: /* } */ 401: 753: directory = opendir(dirname); 401: 753-block 0 call 0 returned 401 401: 754: filename_len = strlen(filename); -: 755: 401: 756: rl_filename_completion_desired = 1; unconditional 0 taken 401 -: 757: } -: 758: 4514: 759: if (tmp_text) { 4514: 759-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 4512 2: 760: free(tmp_text); 2: 761: tmp_text = (char *)NULL; 2: 761-block 0 unconditional 0 taken 2 -: 762: } -: 763: -: 764: /* Now that we have some state, we can read the directory. If we found -: 765: * a match among files in dir, break the loop and print the match */ -: 766: 4514: 767: match = 0; -: 768: 4514: 769: size_t dirname_len = 0; 4514: 770: if (dirname) 4514: 770-block 0 branch 0 taken 4514 (fallthrough) branch 1 taken 0 4514: 771: dirname_len = strlen(dirname); 4514: 771-block 0 unconditional 0 taken 4514 -: 772: -: 773: /* This block is used only in case of "/path/./" to remove the -: 774: * ending "./" from dirname and to be able to perform thus the -: 775: * executable check via access() */ 4514: 776: exec_path = 0; -: 777: 4514: 778: if (dirname_len > 2) { 4514: 778-block 0 branch 0 taken 4118 (fallthrough) branch 1 taken 396 -: 779: 4118*: 780: if (dirname[dirname_len - 3] == '/' && dirname[dirname_len - 2] == '.' 4118: 780-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 4118 %%%%%: 780-block 1 branch 2 never executed branch 3 never executed #####: 781: && dirname[dirname_len - 1] == '/') { %%%%%: 781-block 0 branch 0 never executed branch 1 never executed #####: 782: dir_tmp = savestring(dirname, dirname_len); %%%%%: 782-block 0 call 0 never executed -: 783: #####: 784: if (dir_tmp) { branch 0 never executed branch 1 never executed #####: 785: dir_tmp[dirname_len - 2] = '\0'; #####: 786: exec_path = 1; %%%%%: 786-block 0 unconditional 0 never executed -: 787: } -: 788: } -: 789: } -: 790: -: 791: /* ############### COMPLETION FILTER ################## */ -: 792: /* # This is the heart of the function # -: 793: * #################################################### */ -: 794: mode_t type; -: 795: 75929: 796: while (directory && (ent = readdir(directory))) { 4514: 796-block 0 unconditional 0 taken 4514 75929: 796-block 1 branch 1 taken 75923 (fallthrough) branch 2 taken 6 75923: 796-block 2 call 3 returned 75923 branch 4 taken 75528 branch 5 taken 395 (fallthrough) -: 797:#if !defined(_DIRENT_HAVE_D_TYPE) -: 798: struct stat attr; -: 799: if (!dirname || (*dirname == '.' && !*(dirname + 1))) -: 800: xstrsncpy(tmp, ent->d_name, PATH_MAX); -: 801: else -: 802: snprintf(tmp, PATH_MAX, "%s%s", dirname, ent->d_name); -: 803: -: 804: if (lstat(tmp, &attr) == -1) { -: 805: continue; -: 806: } -: 807: -: 808: switch (attr.st_mode & S_IFMT) { -: 809: case S_IFBLK: type = DT_BLK; break; -: 810: case S_IFCHR: type = DT_CHR; break; -: 811: case S_IFDIR: type = DT_DIR; break; -: 812: case S_IFIFO: type = DT_FIFO; break; -: 813: case S_IFLNK: type = DT_LNK; break; -: 814: case S_IFREG: type = DT_REG; break; -: 815: case S_IFSOCK: type = DT_SOCK; break; -: 816: default: type = DT_UNKNOWN; break; -: 817: } -: 818:#else 75528: 819: type = ent->d_type; -: 820:#endif /* !_DIRENT_HAVE_D_TYPE */ -: 821: -: 822: /* If the user entered nothing before TAB (ex: "cd [TAB]") */ 75528: 823: if (!filename_len) { 75528: 823-block 0 branch 0 taken 3561 (fallthrough) branch 1 taken 71967 -: 824: /* Exclude "." and ".." as possible completions */ 3561: 825: if (SELFORPARENT(ent->d_name)) 3561: 825-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 3559 2: 825-block 1 branch 2 taken 1 (fallthrough) branch 3 taken 1 1: 825-block 2 branch 4 taken 1 (fallthrough) branch 5 taken 0 1: 825-block 3 branch 6 taken 1 (fallthrough) branch 7 taken 0 2: 826: continue; 2: 826-block 0 unconditional 0 taken 2 -: 827: -: 828: /* If 'cd', match only dirs or symlinks to dir */ 3559: 829: if (*rl_line_buffer == 'c' 3559: 829-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 3559 #####: 830: && strncmp(rl_line_buffer, "cd ", 3) == 0) { %%%%%: 830-block 0 branch 0 never executed branch 1 never executed #####: 831: ret = -1; -: 832: #####: 833: switch (type) { %%%%%: 833-block 0 branch 0 never executed branch 1 never executed branch 2 never executed #####: 834: case DT_LNK: #####: 835: if (dirname[0] == '.' && !dirname[1]) { %%%%%: 835-block 0 branch 0 never executed branch 1 never executed %%%%%: 835-block 1 branch 2 never executed branch 3 never executed #####: 836: ret = get_link_ref(ent->d_name); %%%%%: 836-block 0 call 0 never executed unconditional 1 never executed -: 837: } else { #####: 838: snprintf(tmp, PATH_MAX, "%s%s", dirname, ent->d_name); #####: 839: ret = get_link_ref(tmp); %%%%%: 839-block 0 call 0 never executed unconditional 1 never executed -: 840: } -: 841: #####: 842: if (ret == S_IFDIR) %%%%%: 842-block 0 branch 0 never executed branch 1 never executed #####: 843: match = 1; %%%%%: 843-block 0 unconditional 0 never executed -: 844: #####: 845: break; %%%%%: 845-block 0 unconditional 0 never executed -: 846: #####: 847: case DT_DIR: #####: 848: match = 1; #####: 849: break; %%%%%: 849-block 0 unconditional 0 never executed -: 850: #####: 851: default: #####: 852: break; %%%%%: 852-block 0 unconditional 0 never executed -: 853: } -: 854: } -: 855: -: 856: /* If 'open', allow only reg files, dirs, and symlinks */ 3559: 857: else if (*rl_line_buffer == 'o' 3559: 857-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 3559 #####: 858: && (strncmp(rl_line_buffer, "o ", 2) == 0 %%%%%: 858-block 0 branch 0 never executed branch 1 never executed #####: 859: || strncmp(rl_line_buffer, "open ", 5) == 0)) { %%%%%: 859-block 0 branch 0 never executed branch 1 never executed #####: 860: ret = -1; -: 861: #####: 862: switch (type) { %%%%%: 862-block 0 branch 0 never executed branch 1 never executed branch 2 never executed #####: 863: case DT_LNK: #####: 864: if (dirname[0] == '.' && !dirname[1]) { %%%%%: 864-block 0 branch 0 never executed branch 1 never executed %%%%%: 864-block 1 branch 2 never executed branch 3 never executed #####: 865: ret = get_link_ref(ent->d_name); %%%%%: 865-block 0 call 0 never executed unconditional 1 never executed -: 866: } else { #####: 867: snprintf(tmp, PATH_MAX, "%s%s", dirname, ent->d_name); #####: 868: ret = get_link_ref(tmp); %%%%%: 868-block 0 call 0 never executed unconditional 1 never executed -: 869: } -: 870: #####: 871: if (ret == S_IFDIR || ret == S_IFREG) %%%%%: 871-block 0 branch 0 never executed branch 1 never executed %%%%%: 871-block 1 branch 2 never executed branch 3 never executed #####: 872: match = 1; %%%%%: 872-block 0 unconditional 0 never executed -: 873: #####: 874: break; %%%%%: 874-block 0 unconditional 0 never executed -: 875: #####: 876: case DT_REG: /* fallthrough */ #####: 877: case DT_DIR: match = 1; break; %%%%%: 877-block 0 unconditional 0 never executed -: 878: #####: 879: default: break; %%%%%: 879-block 0 unconditional 0 never executed -: 880: } -: 881: } -: 882: -: 883: /* If 'trash', allow only reg files, dirs, symlinks, pipes -: 884: * and sockets. You should not trash a block or a character -: 885: * device */ 3559: 886: else if (*rl_line_buffer == 't' 3559: 886-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 3559 #####: 887: && (strncmp(rl_line_buffer, "t ", 2) == 0 %%%%%: 887-block 0 branch 0 never executed branch 1 never executed #####: 888: || strncmp(rl_line_buffer, "tr ", 2) == 0 %%%%%: 888-block 0 branch 0 never executed branch 1 never executed #####: 889: || strncmp(rl_line_buffer, "trash ", 6) == 0)) { %%%%%: 889-block 0 branch 0 never executed branch 1 never executed -: 890: #####: 891: if (type != DT_BLK && type != DT_CHR) %%%%%: 891-block 0 branch 0 never executed branch 1 never executed %%%%%: 891-block 1 branch 2 never executed branch 3 never executed #####: 892: match = 1; %%%%%: 892-block 0 unconditional 0 never executed -: 893: } -: 894: -: 895: /* If "./", list only executable regular files */ 3559: 896: else if (exec) { 3559: 896-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 3559 #####: 897: if (type == DT_REG && access(ent->d_name, X_OK) == 0) %%%%%: 897-block 0 branch 0 never executed branch 1 never executed %%%%%: 897-block 1 call 2 never executed branch 3 never executed branch 4 never executed #####: 898: match = 1; %%%%%: 898-block 0 unconditional 0 never executed -: 899: } -: 900: -: 901: /* If "/path/./", list only executable regular files */ 3559: 902: else if (exec_path) { 3559: 902-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 3559 #####: 903: if (type == DT_REG) { %%%%%: 903-block 0 branch 0 never executed branch 1 never executed -: 904: /* dir_tmp is dirname less "./", already -: 905: * allocated before the while loop */ #####: 906: snprintf(tmp, PATH_MAX, "%s%s", dir_tmp, ent->d_name); -: 907: #####: 908: if (access(tmp, X_OK) == 0) %%%%%: 908-block 0 call 0 never executed branch 1 never executed branch 2 never executed #####: 909: match = 1; %%%%%: 909-block 0 unconditional 0 never executed -: 910: } -: 911: } -: 912: -: 913: /* No filter for everything else. Just print whatever is -: 914: * there */ -: 915: else 3559: 916: match = 1; 3559: 916-block 0 unconditional 0 taken 3559 -: 917: } -: 918: -: 919: /* If there is at least one char to complete (ex: "cd .[TAB]") */ -: 920: else { -: 921: /* Check if possible completion match up to the length of -: 922: * filename. */ 71967: 923: if (case_sens_path_comp) { 71967: 923-block 0 branch 0 taken 7 (fallthrough) branch 1 taken 71960 7: 924: if (*ent->d_name != *filename 7: 924-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 7 #####: 925: || (strncmp(filename, ent->d_name, filename_len) != 0)) %%%%%: 925-block 0 branch 0 never executed branch 1 never executed 7: 926: continue; 7: 926-block 0 unconditional 0 taken 7 -: 927: } else { 71960: 928: if (TOUPPER(*ent->d_name) != TOUPPER(*filename) 71960: 928-block 0 branch 0 taken 69903 (fallthrough) branch 1 taken 2057 69903: 928-block 1 branch 2 taken 69903 (fallthrough) branch 3 taken 0 69903: 928-block 2 unconditional 4 taken 69903 2057: 928-block 3 unconditional 5 taken 2057 71960: 928-block 4 branch 6 taken 60573 (fallthrough) branch 7 taken 11387 60573: 928-block 5 branch 8 taken 60573 (fallthrough) branch 9 taken 0 60573: 928-block 6 unconditional 10 taken 60573 11387: 928-block 7 unconditional 11 taken 11387 71960: 928-block 8 branch 12 taken 2049 (fallthrough) branch 13 taken 69911 2049: 929: || (strncasecmp(filename, ent->d_name, filename_len) != 0)) 2049: 929-block 0 branch 0 taken 1495 (fallthrough) branch 1 taken 554 71406: 930: continue; 71406: 930-block 0 unconditional 0 taken 71406 -: 931: } -: 932: 554: 933: if (*rl_line_buffer == 'c' 554: 933-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 554 #####: 934: && strncmp(rl_line_buffer, "cd ", 3) == 0) { %%%%%: 934-block 0 branch 0 never executed branch 1 never executed #####: 935: ret = -1; -: 936: #####: 937: switch (type) { %%%%%: 937-block 0 branch 0 never executed branch 1 never executed branch 2 never executed #####: 938: case DT_LNK: #####: 939: if (dirname[0] == '.' && !dirname[1]) { %%%%%: 939-block 0 branch 0 never executed branch 1 never executed %%%%%: 939-block 1 branch 2 never executed branch 3 never executed #####: 940: ret = get_link_ref(ent->d_name); %%%%%: 940-block 0 call 0 never executed unconditional 1 never executed -: 941: } else { #####: 942: snprintf(tmp, PATH_MAX, "%s%s", dirname, ent->d_name); #####: 943: ret = get_link_ref(tmp); %%%%%: 943-block 0 call 0 never executed unconditional 1 never executed -: 944: } -: 945: #####: 946: if (ret == S_IFDIR) %%%%%: 946-block 0 branch 0 never executed branch 1 never executed #####: 947: match = 1; %%%%%: 947-block 0 unconditional 0 never executed #####: 948: break; %%%%%: 948-block 0 unconditional 0 never executed -: 949: #####: 950: case DT_DIR: match = 1; break; %%%%%: 950-block 0 unconditional 0 never executed -: 951: #####: 952: default: break; %%%%%: 952-block 0 unconditional 0 never executed -: 953: } -: 954: } -: 955: 554: 956: else if (*rl_line_buffer == 'o' 554: 956-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 554 #####: 957: && (strncmp(rl_line_buffer, "o ", 2) == 0 %%%%%: 957-block 0 branch 0 never executed branch 1 never executed #####: 958: || strncmp(rl_line_buffer, "open ", 5) == 0)) { %%%%%: 958-block 0 branch 0 never executed branch 1 never executed #####: 959: ret = -1; -: 960: #####: 961: switch (type) { %%%%%: 961-block 0 branch 0 never executed branch 1 never executed branch 2 never executed #####: 962: case DT_REG: /* fallthrough */ #####: 963: case DT_DIR: match = 1; break; %%%%%: 963-block 0 unconditional 0 never executed -: 964: #####: 965: case DT_LNK: #####: 966: if (dirname[0] == '.' && !dirname[1]) { %%%%%: 966-block 0 branch 0 never executed branch 1 never executed %%%%%: 966-block 1 branch 2 never executed branch 3 never executed #####: 967: ret = get_link_ref(ent->d_name); %%%%%: 967-block 0 call 0 never executed unconditional 1 never executed -: 968: } else { #####: 969: snprintf(tmp, PATH_MAX, "%s%s", dirname, ent->d_name); #####: 970: ret = get_link_ref(tmp); %%%%%: 970-block 0 call 0 never executed unconditional 1 never executed -: 971: } -: 972: #####: 973: if (ret == S_IFDIR || ret == S_IFREG) %%%%%: 973-block 0 branch 0 never executed branch 1 never executed %%%%%: 973-block 1 branch 2 never executed branch 3 never executed #####: 974: match = 1; %%%%%: 974-block 0 unconditional 0 never executed #####: 975: break; %%%%%: 975-block 0 unconditional 0 never executed -: 976: #####: 977: default: break; %%%%%: 977-block 0 unconditional 0 never executed -: 978: } -: 979: } -: 980: 554: 981: else if (*rl_line_buffer == 't' 554: 981-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 554 #####: 982: && (strncmp(rl_line_buffer, "t ", 2) == 0 %%%%%: 982-block 0 branch 0 never executed branch 1 never executed #####: 983: || strncmp(rl_line_buffer, "tr ", 3) == 0 %%%%%: 983-block 0 branch 0 never executed branch 1 never executed #####: 984: || strncmp(rl_line_buffer, "trash ", 6) == 0)) { %%%%%: 984-block 0 branch 0 never executed branch 1 never executed #####: 985: if (type != DT_BLK && type != DT_CHR) %%%%%: 985-block 0 branch 0 never executed branch 1 never executed %%%%%: 985-block 1 branch 2 never executed branch 3 never executed #####: 986: match = 1; %%%%%: 986-block 0 unconditional 0 never executed -: 987: } -: 988: 554: 989: else if (exec) { 554: 989-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 554 #####: 990: if (type == DT_REG && access(ent->d_name, X_OK) == 0) %%%%%: 990-block 0 branch 0 never executed branch 1 never executed %%%%%: 990-block 1 call 2 never executed branch 3 never executed branch 4 never executed #####: 991: match = 1; %%%%%: 991-block 0 unconditional 0 never executed -: 992: } -: 993: 554: 994: else if (exec_path) { 554: 994-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 554 #####: 995: if (type == DT_REG) { %%%%%: 995-block 0 branch 0 never executed branch 1 never executed #####: 996: snprintf(tmp, PATH_MAX, "%s%s", dir_tmp, ent->d_name); #####: 997: if (access(tmp, X_OK) == 0) %%%%%: 997-block 0 call 0 never executed branch 1 never executed branch 2 never executed #####: 998: match = 1; %%%%%: 998-block 0 unconditional 0 never executed -: 999: } -: 1000: } -: 1001: -: 1002: else 554: 1003: match = 1; 554: 1003-block 0 unconditional 0 taken 554 -: 1004: } -: 1005: 4113: 1006: if (match) 4113: 1006-block 0 branch 0 taken 4113 (fallthrough) branch 1 taken 0 4113: 1007: break; 4113: 1007-block 0 unconditional 0 taken 4113 -: 1008: } -: 1009: 4514: 1010: if (dir_tmp) { /* == exec_path */ 4514: 1010-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 4514 #####: 1011: free(dir_tmp); #####: 1012: dir_tmp = (char *)NULL; %%%%%: 1012-block 0 unconditional 0 never executed -: 1013: } -: 1014: -: 1015: /* readdir() returns NULL on reaching the end of directory stream. -: 1016: * So that if entry is NULL, we have no matches */ -: 1017: 4514: 1018: if (!ent) { /* == !match */ 4514: 1018-block 0 branch 0 taken 401 (fallthrough) branch 1 taken 4113 401: 1019: if (directory) { 401: 1019-block 0 branch 0 taken 395 (fallthrough) branch 1 taken 6 395: 1020: closedir(directory); 395: 1020-block 0 call 0 returned 395 395: 1021: directory = (DIR *)NULL; unconditional 0 taken 395 -: 1022: } -: 1023: 401: 1024: if (dirname) { 401: 1024-block 0 branch 0 taken 401 (fallthrough) branch 1 taken 0 401: 1025: free(dirname); 401: 1026: dirname = (char *)NULL; 401: 1026-block 0 unconditional 0 taken 401 -: 1027: } -: 1028: 401: 1029: if (filename) { 401: 1029-block 0 branch 0 taken 401 (fallthrough) branch 1 taken 0 401: 1030: free(filename); 401: 1031: filename = (char *)NULL; 401: 1031-block 0 unconditional 0 taken 401 -: 1032: } -: 1033: 401: 1034: if (users_dirname) { 401: 1034-block 0 branch 0 taken 401 (fallthrough) branch 1 taken 0 401: 1035: free(users_dirname); 401: 1036: users_dirname = (char *)NULL; 401: 1036-block 0 unconditional 0 taken 401 -: 1037: } -: 1038: 401: 1039: return (char *)NULL; 401: 1039-block 0 unconditional 0 taken 401 -: 1040: } -: 1041: -: 1042: /* We have a match */ -: 1043: else { 4113: 1044: char *temp = (char *)NULL; -: 1045: -: 1046: /* dirname && (strcmp(dirname, ".") != 0) */ 4113: 1047: if (dirname && (dirname[0] != '.' || dirname[1])) { 4113: 1047-block 0 branch 0 taken 4113 (fallthrough) branch 1 taken 0 4113: 1047-block 1 branch 2 taken 4 (fallthrough) branch 3 taken 4109 4: 1047-block 2 branch 4 taken 1 (fallthrough) branch 5 taken 3 -: 1048:/* if (rl_complete_with_tilde_expansion && *users_dirname == '~') { -: 1049: size_t dirlen = strlen(dirname); -: 1050: temp = (char *)xnmalloc(dirlen + strlen(ent->d_name) + 2, -: 1051: sizeof(char)); -: 1052: strcpy(temp, dirname); -: 1053: // Canonicalization cuts off any final slash present. -: 1054: // We need to add it back. -: 1055: -: 1056: if (dirname[dirlen - 1] != '/') { -: 1057: temp[dirlen] = '/'; -: 1058: temp[dirlen + 1] = '\0'; -: 1059: } -: 1060: } else { */ 4110: 1061: temp = (char *)xnmalloc(strlen(users_dirname) + 4110: 1062: strlen(ent->d_name) + 1, sizeof(char)); 4110: 1062-block 0 call 0 returned 4110 4110: 1063: strcpy(temp, users_dirname); -: 1064:/* } */ 4110: 1065: strcat(temp, ent->d_name); unconditional 0 taken 4110 -: 1066: } else { 3: 1067: temp = savestring(ent->d_name, strlen(ent->d_name)); 3: 1067-block 0 call 0 returned 3 unconditional 1 taken 3 -: 1068: } -: 1069: 4113: 1070: return (temp); 4113: 1070-block 0 unconditional 0 taken 4113 -: 1071: } -: 1072:} -: 1073: -: 1074:/* Used by bookmarks completion */ -: 1075:static char * function bookmarks_generator called 41 returned 100% blocks executed 91% 41: 1076:bookmarks_generator(const char *text, int state) -: 1077:{ 41: 1078: if (!bookmark_names) 41: 1078-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 41 #####: 1079: return (char *)NULL; %%%%%: 1079-block 0 unconditional 0 never executed -: 1080: -: 1081: static int i; -: 1082: static size_t len; -: 1083: char *name; -: 1084: 41: 1085: if (!state) { 41: 1085-block 0 branch 0 taken 3 (fallthrough) branch 1 taken 38 3: 1086: i = 0; 3: 1087: len = strlen(text); 3: 1087-block 0 unconditional 0 taken 3 -: 1088: } -: 1089: -: 1090: /* Look for bookmarks in bookmark names for a match */ 60: 1091: while ((name = bookmark_names[i++]) != NULL) { 41: 1091-block 0 unconditional 0 taken 41 60: 1091-block 1 branch 1 taken 57 branch 2 taken 3 (fallthrough) 57: 1092: if (strncmp(name, text, len) == 0) 57: 1092-block 0 branch 0 taken 38 (fallthrough) branch 1 taken 19 38: 1093: return strdup(name); 38: 1093-block 0 call 0 returned 38 unconditional 1 taken 38 -: 1094: } -: 1095: 3: 1096: return (char *)NULL; 3: 1096-block 0 unconditional 0 taken 3 -: 1097:} -: 1098: -: 1099:/* Used by history completion */ -: 1100:static char * function hist_generator called 0 returned 0% blocks executed 0% #####: 1101:hist_generator(const char *text, int state) -: 1102:{ #####: 1103: if (!history) %%%%%: 1103-block 0 branch 0 never executed branch 1 never executed #####: 1104: return (char *)NULL; %%%%%: 1104-block 0 unconditional 0 never executed -: 1105: -: 1106: static int i; -: 1107: static size_t len; -: 1108: char *name; -: 1109: #####: 1110: if (!state) { %%%%%: 1110-block 0 branch 0 never executed branch 1 never executed #####: 1111: i = 0; #####: 1112: len = strlen(text); %%%%%: 1112-block 0 unconditional 0 never executed -: 1113: } -: 1114: -: 1115: /* Look for cmd history entries for a match */ #####: 1116: while ((name = history[i++]) != NULL) { %%%%%: 1116-block 0 unconditional 0 never executed %%%%%: 1116-block 1 branch 1 never executed branch 2 never executed #####: 1117: if (strncmp(name, text, len) == 0) %%%%%: 1117-block 0 branch 0 never executed branch 1 never executed #####: 1118: return strdup(name); %%%%%: 1118-block 0 call 0 never executed unconditional 1 never executed -: 1119: } -: 1120: #####: 1121: return (char *)NULL; %%%%%: 1121-block 0 unconditional 0 never executed -: 1122:} -: 1123: -: 1124:/* Expand string into matching path in the jump database. Used by -: 1125: * j, jc, and jp commands */ -: 1126:static char * function jump_generator called 18 returned 100% blocks executed 75% 18: 1127:jump_generator(const char *text, int state) -: 1128:{ -: 1129: static int i; -: 1130: char *name; -: 1131: 18: 1132: if (!state) 18: 1132-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 17 1: 1133: i = 0; 1: 1133-block 0 unconditional 0 taken 1 -: 1134: 18: 1135: if (!jump_db) 18: 1135-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 18 #####: 1136: return (char *)NULL; %%%%%: 1136-block 0 unconditional 0 never executed -: 1137: -: 1138: /* Look for matches in the dirhist list */ 48: 1139: while ((name = jump_db[i++].path) != NULL) { 18: 1139-block 0 unconditional 0 taken 18 48: 1139-block 1 branch 1 taken 47 branch 2 taken 1 (fallthrough) -: 1140: /* Exclude CWD */ 47: 1141: if (name[1] == ws[cur_ws].path[1] && strcmp(name, ws[cur_ws].path) == 0) 47: 1141-block 0 branch 0 taken 36 (fallthrough) branch 1 taken 11 36: 1141-block 1 branch 2 taken 1 (fallthrough) branch 3 taken 35 1: 1142: continue; 1: 1142-block 0 unconditional 0 taken 1 -: 1143: /* Filter by parent */ 46: 1144: if (rl_line_buffer[1] == 'p') { 46: 1144-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 46 #####: 1145: if (!strstr(ws[cur_ws].path, name)) %%%%%: 1145-block 0 branch 0 never executed branch 1 never executed #####: 1146: continue; %%%%%: 1146-block 0 unconditional 0 never executed -: 1147: } -: 1148: /* Filter by child */ 46: 1149: else if (rl_line_buffer[1] == 'c') { 46: 1149-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 46 #####: 1150: if (!strstr(name, ws[cur_ws].path)) %%%%%: 1150-block 0 branch 0 never executed branch 1 never executed #####: 1151: continue; %%%%%: 1151-block 0 unconditional 0 never executed -: 1152: } -: 1153: 46: 1154: if (strstr(name, text)) 46: 1154-block 0 branch 0 taken 17 (fallthrough) branch 1 taken 29 17: 1155: return strdup(name); 17: 1155-block 0 call 0 returned 17 unconditional 1 taken 17 -: 1156: } -: 1157: 1: 1158: return (char *)NULL; 1: 1158-block 0 unconditional 0 taken 1 -: 1159:} -: 1160: -: 1161:/* Expand jump order number into the corresponding path. Used by the -: 1162: * jo command */ -: 1163:static char * function jump_entries_generator called 0 returned 0% blocks executed 0% #####: 1164:jump_entries_generator(const char *text, int state) -: 1165:{ -: 1166: static size_t i; -: 1167: char *name; -: 1168: #####: 1169: if (!state) %%%%%: 1169-block 0 branch 0 never executed branch 1 never executed #####: 1170: i = 0; %%%%%: 1170-block 0 unconditional 0 never executed -: 1171: #####: 1172: int num_text = atoi(text); -: 1173: -: 1174: /* Check list of jump entries for a match */ #####: 1175: while (i <= jump_n && (name = jump_db[i++].path) != NULL) %%%%%: 1175-block 0 unconditional 0 never executed %%%%%: 1175-block 1 branch 1 never executed branch 2 never executed %%%%%: 1175-block 2 branch 3 never executed branch 4 never executed #####: 1176: if (*name == *jump_db[num_text - 1].path && strcmp(name, %%%%%: 1176-block 0 branch 0 never executed branch 1 never executed #####: 1177: jump_db[num_text - 1].path) == 0) %%%%%: 1177-block 0 branch 0 never executed branch 1 never executed #####: 1178: return strdup(name); %%%%%: 1178-block 0 call 0 never executed unconditional 1 never executed -: 1179: #####: 1180: return (char *)NULL; %%%%%: 1180-block 0 unconditional 0 never executed -: 1181:} -: 1182: -: 1183:static char * function cschemes_generator called 21 returned 100% blocks executed 91% 21: 1184:cschemes_generator(const char *text, int state) -: 1185:{ 21: 1186: if (!color_schemes) 21: 1186-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 21 #####: 1187: return (char *)NULL; %%%%%: 1187-block 0 unconditional 0 never executed -: 1188: -: 1189: static int i; -: 1190: static size_t len; -: 1191: char *name; -: 1192: 21: 1193: if (!state) { 21: 1193-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 20 1: 1194: i = 0; 1: 1195: len = strlen(text); 1: 1195-block 0 unconditional 0 taken 1 -: 1196: } /* The state variable is zero only the first time the function is -: 1197: called, and a non-zero positive in later calls. This means that i -: 1198: and len will be necessarilly initialized the first time */ -: 1199: -: 1200: /* Look for color schemes in color_schemes for a match */ 21: 1201: while ((name = color_schemes[i++]) != NULL) { 21: 1201-block 0 unconditional 0 taken 21 21: 1201-block 1 branch 1 taken 20 branch 2 taken 1 (fallthrough) 20: 1202: if (strncmp(name, text, len) == 0) 20: 1202-block 0 branch 0 taken 20 (fallthrough) branch 1 taken 0 20: 1203: return strdup(name); 20: 1203-block 0 call 0 returned 20 unconditional 1 taken 20 -: 1204: } -: 1205: 1: 1206: return (char *)NULL; 1: 1206-block 0 unconditional 0 taken 1 -: 1207:} -: 1208: -: 1209:/* Used by profiles completion */ -: 1210:static char * function profiles_generator called 8 returned 100% blocks executed 91% 8: 1211:profiles_generator(const char *text, int state) -: 1212:{ 8: 1213: if (!profile_names) 8: 1213-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 8 #####: 1214: return (char *)NULL; %%%%%: 1214-block 0 unconditional 0 never executed -: 1215: -: 1216: static int i; -: 1217: static size_t len; -: 1218: char *name; -: 1219: 8: 1220: if (!state) { 8: 1220-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 6 2: 1221: i = 0; 2: 1222: len = strlen(text); 2: 1222-block 0 unconditional 0 taken 2 -: 1223: } /* The state variable is zero only the first time the function is -: 1224: called, and a non-zero positive in later calls. This means that i -: 1225: and len will be necessarilly initialized the first time */ -: 1226: -: 1227: /* Look for profiles in profile_names for a match */ 13: 1228: while ((name = profile_names[i++]) != NULL) { 8: 1228-block 0 unconditional 0 taken 8 13: 1228-block 1 branch 1 taken 11 branch 2 taken 2 (fallthrough) 11: 1229: if (strncmp(name, text, len) == 0) 11: 1229-block 0 branch 0 taken 6 (fallthrough) branch 1 taken 5 6: 1230: return strdup(name); 6: 1230-block 0 call 0 returned 6 unconditional 1 taken 6 -: 1231: } -: 1232: 2: 1233: return (char *)NULL; 2: 1233-block 0 unconditional 0 taken 2 -: 1234:} -: 1235: -: 1236:/* Used by ELN expansion */ -: 1237:static char * function filenames_gen_text called 7 returned 100% blocks executed 92% 7: 1238:filenames_gen_text(const char *text, int state) -: 1239:{ -: 1240: static size_t i, len = 0; -: 1241: char *name; 7: 1242: rl_filename_completion_desired = 1; -: 1243: /* According to the GNU readline documention: "If it is set to a -: 1244: * non-zero value, directory names have a slash appended and -: 1245: * Readline attempts to quote completed file names if they contain -: 1246: * any embedded word break characters." To make the quoting part -: 1247: * work I had to specify a custom quoting function (my_rl_quote) */ 7: 1248: if (!state) { /* state is zero only the first time readline is 7: 1248-block 0 branch 0 taken 4 (fallthrough) branch 1 taken 3 -: 1249: executed */ 4: 1250: i = 0; 4: 1251: len = strlen(text); 4: 1251-block 0 unconditional 0 taken 4 -: 1252: } -: 1253: -: 1254: /* Check list of currently displayed files for a match */ 132: 1255: while (i < files && (name = file_info[i++].name) != NULL) 7: 1255-block 0 unconditional 0 taken 7 132: 1255-block 1 branch 1 taken 128 (fallthrough) branch 2 taken 4 128: 1255-block 2 branch 3 taken 128 branch 4 taken 0 (fallthrough) 256*: 1256: if (case_sens_path_comp ? strncmp(name, text, len) == 0 128: 1256-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 128 %%%%%: 1256-block 1 unconditional 2 never executed 128: 1256-block 2 branch 3 taken 3 (fallthrough) branch 4 taken 125 128: 1257: : strncasecmp(name, text, len) == 0) 128: 1257-block 0 unconditional 0 taken 128 3: 1258: return strdup(name); 3: 1258-block 0 call 0 returned 3 unconditional 1 taken 3 -: 1259: 4: 1260: return (char *)NULL; 4: 1260-block 0 unconditional 0 taken 4 -: 1261:} -: 1262: -: 1263:/* Used by ELN expansion */ -: 1264:static char * function filenames_gen_eln called 0 returned 0% blocks executed 0% #####: 1265:filenames_gen_eln(const char *text, int state) -: 1266:{ -: 1267: static size_t i; -: 1268: char *name; #####: 1269: rl_filename_completion_desired = 1; -: 1270: #####: 1271: if (!state) %%%%%: 1271-block 0 branch 0 never executed branch 1 never executed #####: 1272: i = 0; %%%%%: 1272-block 0 unconditional 0 never executed -: 1273: #####: 1274: int num_text = atoi(text); -: 1275: -: 1276: /* Check list of currently displayed files for a match */ #####: 1277: while (i < files && (name = file_info[i++].name) != NULL) { %%%%%: 1277-block 0 unconditional 0 never executed %%%%%: 1277-block 1 branch 1 never executed branch 2 never executed %%%%%: 1277-block 2 branch 3 never executed branch 4 never executed #####: 1278: if (*name == *file_info[num_text - 1].name %%%%%: 1278-block 0 branch 0 never executed branch 1 never executed #####: 1279: && strcmp(name, file_info[num_text - 1].name) == 0) { %%%%%: 1279-block 0 branch 0 never executed branch 1 never executed -: 1280:#ifndef _NO_SUGGESTIONS #####: 1281: if (suggestion_buf) %%%%%: 1281-block 0 branch 0 never executed branch 1 never executed #####: 1282: clear_suggestion(); %%%%%: 1282-block 0 call 0 never executed unconditional 1 never executed -: 1283:#endif #####: 1284: return strdup(name); %%%%%: 1284-block 0 call 0 never executed unconditional 1 never executed -: 1285: } -: 1286: } -: 1287: #####: 1288: return (char *)NULL; %%%%%: 1288-block 0 unconditional 0 never executed -: 1289:} -: 1290: -: 1291:/* Used by commands completion */ -: 1292:static char * function bin_cmd_generator called 2 returned 100% blocks executed 92% 2: 1293:bin_cmd_generator(const char *text, int state) -: 1294:{ 2: 1295: if (!bin_commands) 2: 1295-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 2 #####: 1296: return (char *)NULL; %%%%%: 1296-block 0 unconditional 0 never executed -: 1297: -: 1298: static int i; -: 1299: static size_t len; -: 1300: char *name; -: 1301: 2: 1302: if (!state) { 2: 1302-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 1 1: 1303: i = 0; 1: 1304: len = strlen(text); 1: 1304-block 0 unconditional 0 taken 1 -: 1305: } -: 1306: 3746: 1307: while ((name = bin_commands[i++]) != NULL) { 2: 1307-block 0 unconditional 0 taken 2 3746: 1307-block 1 branch 1 taken 3745 branch 2 taken 1 (fallthrough) 3745: 1308: if (*text == *name && strncmp(name, text, len) == 0) 3745: 1308-block 0 branch 0 taken 60 (fallthrough) branch 1 taken 3685 60: 1308-block 1 branch 2 taken 1 (fallthrough) branch 3 taken 59 1: 1309: return strdup(name); 1: 1309-block 0 call 0 returned 1 unconditional 1 taken 1 -: 1310: } -: 1311: 1: 1312: return (char *)NULL; 1: 1312-block 0 unconditional 0 taken 1 -: 1313:} -: 1314: -: 1315:static char * function sort_num_generator called 0 returned 0% blocks executed 0% #####: 1316:sort_num_generator(const char *text, int state) -: 1317:{ -: 1318: static size_t i; -: 1319: char *name; #####: 1320: rl_filename_completion_desired = 1; -: 1321: #####: 1322: if (!state) %%%%%: 1322-block 0 branch 0 never executed branch 1 never executed #####: 1323: i = 0; %%%%%: 1323-block 0 unconditional 0 never executed -: 1324: #####: 1325: int num_text = atoi(text); -: 1326: static char *sorts[] = { -: 1327: "none", -: 1328: "name", -: 1329: "size", -: 1330: "atime", -: 1331: "btime", -: 1332: "ctime", -: 1333: "mtime", -: 1334: "version", -: 1335: "extension", -: 1336: "inode", -: 1337: "owner", -: 1338: "group", -: 1339: NULL -: 1340: }; -: 1341: -: 1342: /* Check list of currently displayed files for a match */ #####: 1343: while (i <= SORT_TYPES && (name = sorts[i++]) != NULL) { %%%%%: 1343-block 0 unconditional 0 never executed %%%%%: 1343-block 1 branch 1 never executed branch 2 never executed %%%%%: 1343-block 2 branch 3 never executed branch 4 never executed #####: 1344: if (*name == *sorts[num_text] %%%%%: 1344-block 0 branch 0 never executed branch 1 never executed #####: 1345: && strcmp(name, sorts[num_text]) == 0) %%%%%: 1345-block 0 branch 0 never executed branch 1 never executed #####: 1346: return strdup(name); %%%%%: 1346-block 0 call 0 never executed unconditional 1 never executed -: 1347: } -: 1348: #####: 1349: return (char *)NULL; %%%%%: 1349-block 0 unconditional 0 never executed -: 1350:} -: 1351: -: 1352:static char * function nets_generator called 0 returned 0% blocks executed 0% #####: 1353:nets_generator(const char *text, int state) -: 1354:{ #####: 1355: if (!remotes) %%%%%: 1355-block 0 branch 0 never executed branch 1 never executed #####: 1356: return (char *)NULL; %%%%%: 1356-block 0 unconditional 0 never executed -: 1357: -: 1358: static int i; -: 1359: static size_t len; -: 1360: char *name; -: 1361: #####: 1362: if (!state) { %%%%%: 1362-block 0 branch 0 never executed branch 1 never executed #####: 1363: i = 0; #####: 1364: len = strlen(text); %%%%%: 1364-block 0 unconditional 0 never executed -: 1365: } -: 1366: #####: 1367: while ((name = remotes[i++].name) != NULL) { %%%%%: 1367-block 0 unconditional 0 never executed %%%%%: 1367-block 1 branch 1 never executed branch 2 never executed #####: 1368: if (strncmp(name, text, len) == 0) %%%%%: 1368-block 0 branch 0 never executed branch 1 never executed #####: 1369: return strdup(name); %%%%%: 1369-block 0 call 0 never executed unconditional 1 never executed -: 1370: } -: 1371: #####: 1372: return (char *)NULL; %%%%%: 1372-block 0 unconditional 0 never executed -: 1373:} -: 1374: -: 1375:static char * function sort_name_generator called 0 returned 0% blocks executed 0% #####: 1376:sort_name_generator(const char *text, int state) -: 1377:{ -: 1378: static int i; -: 1379: static size_t len; -: 1380: char *name; -: 1381: #####: 1382: if (!state) { %%%%%: 1382-block 0 branch 0 never executed branch 1 never executed #####: 1383: i = 0; #####: 1384: len = strlen(text); %%%%%: 1384-block 0 unconditional 0 never executed -: 1385: } -: 1386: -: 1387: static char *sorts[] = { -: 1388: "none", -: 1389: "name", -: 1390: "size", -: 1391: "atime", -: 1392: "btime", -: 1393: "ctime", -: 1394: "mtime", -: 1395: "version", -: 1396: "extension", -: 1397: "inode", -: 1398: "owner", -: 1399: "group", -: 1400: NULL}; -: 1401: #####: 1402: while ((name = sorts[i++]) != NULL) { %%%%%: 1402-block 0 unconditional 0 never executed %%%%%: 1402-block 1 branch 1 never executed branch 2 never executed #####: 1403: if (*text == *name && strncmp(name, text, len) == 0) %%%%%: 1403-block 0 branch 0 never executed branch 1 never executed %%%%%: 1403-block 1 branch 2 never executed branch 3 never executed #####: 1404: return strdup(name); %%%%%: 1404-block 0 call 0 never executed unconditional 1 never executed -: 1405: } -: 1406: #####: 1407: return (char *)NULL; %%%%%: 1407-block 0 unconditional 0 never executed -: 1408:} -: 1409: -: 1410:/* Generate entries from the jump database (not using the j function)*/ -: 1411:/*char * -: 1412:jump_gen(const char *text, int state) -: 1413:{ -: 1414: static int i; -: 1415: static size_t len; -: 1416: char *name; -: 1417: -: 1418: if (!state) { -: 1419: i = 0; -: 1420: len = strlen(text); -: 1421: } -: 1422: -: 1423: while ((name = jump_db[i++].path) != NULL) { -: 1424: if (case_sens_path_comp ? strncmp(name, text, len) == 0 -: 1425: : strncasecmp(name, text, len) == 0) -: 1426: return strdup(name); -: 1427: } -: 1428: -: 1429: return (char *)NULL; -: 1430:} */ -: 1431: -: 1432:char ** function my_rl_completion called 19 returned 100% blocks executed 49% 19: 1433:my_rl_completion(const char *text, int start, int end) -: 1434:{ 19: 1435: char **matches = (char **)NULL; -: 1436: 19: 1437: if (start == 0) { /* Only for the first word entered in the prompt */ 19: 1437-block 0 branch 0 taken 4 (fallthrough) branch 1 taken 15 -: 1438: /* Commands completion */ 4: 1439: if (end == 0) { /* If text is empty, do nothing */ 4: 1439-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 4 -: 1440: /* Prevent readline from attempting path completion if -: 1441: * rl_completion matches returns NULL */ #####: 1442: rl_attempted_completion_over = 1; #####: 1443: return (char **)NULL; %%%%%: 1443-block 0 unconditional 0 never executed -: 1444: } -: 1445: -: 1446: /* History cmd completion */ 4: 1447: if (*text == '!') 4: 1447-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 4 #####: 1448: matches = rl_completion_matches(text + 1, &hist_generator); %%%%%: 1448-block 0 call 0 never executed unconditional 1 never executed -: 1449: -: 1450: /* If autocd or auto-open, try to expand ELN's first */ 4*: 1451: if (!matches && (autocd || auto_open)) { 4: 1451-block 0 branch 0 taken 4 (fallthrough) branch 1 taken 0 4: 1451-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 4 %%%%%: 1451-block 2 branch 4 never executed branch 5 never executed 4: 1452: if (*text >= '1' && *text <= '9') { 4: 1452-block 0 branch 0 taken 4 (fallthrough) branch 1 taken 0 4: 1452-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 4 #####: 1453: int num_text = atoi(text); -: 1454: #####: 1455: if (is_number(text) && num_text > 0 && num_text <= (int)files) %%%%%: 1455-block 0 call 0 never executed branch 1 never executed branch 2 never executed %%%%%: 1455-block 1 branch 3 never executed branch 4 never executed %%%%%: 1455-block 2 branch 5 never executed branch 6 never executed #####: 1456: matches = rl_completion_matches(text, &filenames_gen_eln); %%%%%: 1456-block 0 call 0 never executed unconditional 1 never executed -: 1457: } -: 1458: -: 1459: /* Compĺete with files in CWD */ 4: 1460: if (!matches && *text != '/') 4: 1460-block 0 branch 0 taken 4 (fallthrough) branch 1 taken 0 4: 1460-block 1 branch 2 taken 4 (fallthrough) branch 3 taken 0 4: 1461: matches = rl_completion_matches(text, &filenames_gen_text); 4: 1461-block 0 call 0 returned 4 unconditional 1 taken 4 -: 1462: -: 1463: /* Complete with entries in the jump database */ -: 1464:/* if (autocd && !matches) -: 1465: matches = rl_completion_matches(text, &jump_gen); */ -: 1466: } -: 1467: -: 1468: /* Bookmarks completion */ 4*: 1469: if (!matches && (autocd || auto_open) && expand_bookmarks) 4: 1469-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 3 1: 1469-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 1 %%%%%: 1469-block 2 branch 4 never executed branch 5 never executed 1: 1469-block 3 branch 6 taken 0 (fallthrough) branch 7 taken 1 #####: 1470: matches = rl_completion_matches(text, &bookmarks_generator); %%%%%: 1470-block 0 call 0 never executed unconditional 1 never executed -: 1471: -: 1472: /* If neither autocd nor auto-open, try to complete with -: 1473: * command names */ 4: 1474: if (!matches) 4: 1474-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 3 1: 1475: matches = rl_completion_matches(text, &bin_cmd_generator); 1: 1475-block 0 call 0 returned 1 unconditional 1 taken 1 -: 1476: } -: 1477: -: 1478: /* Second word or more */ -: 1479: else { -: 1480: /* #### ELN AND JUMP ORDER EXPANSION ### */ -: 1481: -: 1482: /* Perform this check only if the first char of the string to be -: 1483: * completed is a number in order to prevent an unnecessary call -: 1484: * to atoi */ 15*: 1485: if (*text >= '0' && *text <= '9') { 15: 1485-block 0 branch 0 taken 3 (fallthrough) branch 1 taken 12 3: 1485-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 3 %%%%%: 1485-block 2 unconditional 4 never executed #####: 1486: int num_text = atoi(text); -: 1487: -: 1488: /* Dirjump: jo command */ #####: 1489: if (*rl_line_buffer == 'j' && rl_line_buffer[1] == 'o' %%%%%: 1489-block 0 branch 0 never executed branch 1 never executed %%%%%: 1489-block 1 branch 2 never executed branch 3 never executed #####: 1490: && rl_line_buffer[2] == ' ') { %%%%%: 1490-block 0 branch 0 never executed branch 1 never executed #####: 1491: if (is_number(text) && num_text > 0 && num_text <= (int)jump_n) { %%%%%: 1491-block 0 call 0 never executed branch 1 never executed branch 2 never executed %%%%%: 1491-block 1 branch 3 never executed branch 4 never executed %%%%%: 1491-block 2 branch 5 never executed branch 6 never executed #####: 1492: matches = rl_completion_matches(text, %%%%%: 1492-block 0 call 0 never executed unconditional 1 never executed -: 1493: &jump_entries_generator); -: 1494: } -: 1495: } -: 1496: -: 1497: /* Sort number expansion */ #####: 1498: else if (*rl_line_buffer == 's' %%%%%: 1498-block 0 branch 0 never executed branch 1 never executed #####: 1499: && (strncmp(rl_line_buffer, "st ", 3) == 0 %%%%%: 1499-block 0 branch 0 never executed branch 1 never executed #####: 1500: || strncmp(rl_line_buffer, "sort ", 5) == 0) %%%%%: 1500-block 0 branch 0 never executed branch 1 never executed #####: 1501: && is_number(text) && num_text >= 0 && num_text <= SORT_TYPES) %%%%%: 1501-block 0 call 0 never executed branch 1 never executed branch 2 never executed %%%%%: 1501-block 1 branch 3 never executed branch 4 never executed %%%%%: 1501-block 2 branch 5 never executed branch 6 never executed #####: 1502: matches = rl_completion_matches(text, &sort_num_generator); %%%%%: 1502-block 0 call 0 never executed unconditional 1 never executed -: 1503: -: 1504: /* ELN expansion */ #####: 1505: else if (is_number(text) && num_text > 0 && num_text <= (int)files) %%%%%: 1505-block 0 call 0 never executed branch 1 never executed branch 2 never executed %%%%%: 1505-block 1 branch 3 never executed branch 4 never executed %%%%%: 1505-block 2 branch 5 never executed branch 6 never executed #####: 1506: matches = rl_completion_matches(text, &filenames_gen_eln); %%%%%: 1506-block 0 call 0 never executed unconditional 1 never executed -: 1507: } -: 1508: -: 1509: /* ### DIRJUMP COMPLETION ### */ -: 1510: /* j, jc, jp commands */ 15: 1511: else if (*rl_line_buffer == 'j' && (rl_line_buffer[1] == ' ' 15: 1511-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 14 1: 1511-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 1 #####: 1512: || ((rl_line_buffer[1] == 'c' || rl_line_buffer[1] == 'p') %%%%%: 1512-block 0 branch 0 never executed branch 1 never executed %%%%%: 1512-block 1 branch 2 never executed branch 3 never executed #####: 1513: && rl_line_buffer[2] == ' ') %%%%%: 1513-block 0 branch 0 never executed branch 1 never executed #####: 1514: || strncmp(rl_line_buffer, "jump ", 5) == 0)) %%%%%: 1514-block 0 branch 0 never executed branch 1 never executed 1: 1515: matches = rl_completion_matches(text, &jump_generator); 1: 1515-block 0 call 0 returned 1 unconditional 1 taken 1 -: 1516: -: 1517: /* ### BOOKMARKS COMPLETION ### */ -: 1518: 14: 1519: else if (*rl_line_buffer == 'b' && (rl_line_buffer[1] == 'm' 14: 1519-block 0 branch 0 taken 3 (fallthrough) branch 1 taken 11 3: 1519-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 3 #####: 1520: || rl_line_buffer[1] == 'o') %%%%%: 1520-block 0 branch 0 never executed branch 1 never executed 3: 1521: && (strncmp(rl_line_buffer, "bm ", 3) == 0 3: 1521-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 3 #####: 1522: || strncmp(rl_line_buffer, "bookmarks ", 10) == 0)) { %%%%%: 1522-block 0 branch 0 never executed branch 1 never executed -: 1523:#ifndef _NO_SUGGESTIONS 3: 1524: if (suggestion.type != FILE_SUG) 3: 1524-block 0 branch 0 taken 3 (fallthrough) branch 1 taken 0 3: 1525: rl_attempted_completion_over = 1; 3: 1525-block 0 unconditional 0 taken 3 -: 1526:#endif 3: 1527: matches = rl_completion_matches(text, &bookmarks_generator); 3: 1527-block 0 call 0 returned 3 unconditional 1 taken 3 -: 1528: } -: 1529: -: 1530: /* ### COLOR SCHEMES COMPLETION ### */ 11: 1531: else if (*rl_line_buffer == 'c' && ((rl_line_buffer[1] == 's' 11: 1531-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 10 1: 1531-block 1 branch 2 taken 1 (fallthrough) branch 3 taken 0 1: 1532: && rl_line_buffer[2] == ' ') 1: 1532-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 1 #####: 1533: || strncmp(rl_line_buffer, "colorschemes ", 13) == 0)) { %%%%%: 1533-block 0 branch 0 never executed branch 1 never executed 1: 1534: matches = rl_completion_matches(text, 1: 1534-block 0 call 0 returned 1 unconditional 1 taken 1 -: 1535: &cschemes_generator); -: 1536: } -: 1537: -: 1538: /* ### PROFILES COMPLETION ### */ -: 1539: 10: 1540: else if (*rl_line_buffer == 'p' && (rl_line_buffer[1] == 'r' 10: 1540-block 0 branch 0 taken 4 (fallthrough) branch 1 taken 6 4: 1540-block 1 branch 2 taken 4 (fallthrough) branch 3 taken 0 4: 1541: || rl_line_buffer[1] == 'f') 4: 1541-block 0 branch 0 taken 4 (fallthrough) branch 1 taken 0 4: 1542: && (strncmp(rl_line_buffer, "pf set ", 7) == 0 4: 1542-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 2 2: 1543: || strncmp(rl_line_buffer, "profile set ", 12) == 0 2: 1543-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 0 2: 1544: || strncmp(rl_line_buffer, "pf del ", 7) == 0 2: 1544-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 0 2: 1545: || strncmp(rl_line_buffer, "profile del ", 12) == 0)) { 2: 1545-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 2 -: 1546:#ifndef _NO_SUGGESTIONS 2: 1547: if (suggestion.type != FILE_SUG) 2: 1547-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 0 2: 1548: rl_attempted_completion_over = 1; 2: 1548-block 0 unconditional 0 taken 2 -: 1549:#endif /* _NO_SUGGESTIONS */ 2: 1550: matches = rl_completion_matches(text, &profiles_generator); 2: 1550-block 0 call 0 returned 2 unconditional 1 taken 2 -: 1551: } -: 1552: 8: 1553: else if (expand_bookmarks) { 8: 1553-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 8 #####: 1554: matches = rl_completion_matches(text, &bookmarks_generator); %%%%%: 1554-block 0 call 0 never executed unconditional 1 never executed -: 1555: } -: 1556: 8: 1557: else if (*rl_line_buffer == 's' 8: 1557-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 8 #####: 1558: && (strncmp(rl_line_buffer, "st ", 3) == 0 %%%%%: 1558-block 0 branch 0 never executed branch 1 never executed #####: 1559: || strncmp(rl_line_buffer, "sort ", 5) == 0)) %%%%%: 1559-block 0 branch 0 never executed branch 1 never executed #####: 1560: matches = rl_completion_matches(text, &sort_name_generator); %%%%%: 1560-block 0 call 0 never executed unconditional 1 never executed -: 1561: 8: 1562: else if (*rl_line_buffer == 'n' 8: 1562-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 8 #####: 1563: && strncmp(rl_line_buffer, "net ", 4) == 0) %%%%%: 1563-block 0 branch 0 never executed branch 1 never executed #####: 1564: matches = rl_completion_matches(text, &nets_generator); %%%%%: 1564-block 0 call 0 never executed unconditional 1 never executed -: 1565: } -: 1566: -: 1567: /* ### PATH COMPLETION ### */ -: 1568: -: 1569: /* If none of the above, readline will attempt -: 1570: * path completion instead via my custom my_rl_path_completion() */ 19: 1571: return matches; 19: 1571-block 0 unconditional 0 taken 19 -: 1572:} -: 1573: -: 1574:int function initialize_readline called 4 returned 100% blocks executed 91% 4: 1575:initialize_readline(void) -: 1576:{ -: 1577: /* #### INITIALIZE READLINE (what a hard beast to tackle!!) #### */ -: 1578: -: 1579: /* Set the name of the program using readline. Mostly used for -: 1580: * conditional constructs in the inputrc file */ 4: 1581: rl_readline_name = argv_bk[0]; -: 1582: -: 1583:/* add_func_to_rl(); */ -: 1584: -: 1585: /* Load readline initialization file. Check order: -: 1586: * INPUTRC env var -: 1587: * ~/.config/clifm/readline.cfm -: 1588: * ~/.inputrc -: 1589: * /etc/inputrc */ 4: 1590: char *p = getenv("INPUTRC"); 4: 1590-block 0 call 0 returned 4 4: 1591: if (p) { branch 0 taken 0 (fallthrough) branch 1 taken 4 #####: 1592: rl_read_init_file(p); %%%%%: 1592-block 0 call 0 never executed unconditional 1 never executed 4: 1593: } else if (config_dir_gral) { 4: 1593-block 0 branch 0 taken 4 (fallthrough) branch 1 taken 0 4: 1594: char *rl_file = (char *)xnmalloc(strlen(config_dir_gral) + 14, 4: 1594-block 0 call 0 returned 4 -: 1595: sizeof(char)); 4: 1596: sprintf(rl_file, "%s/readline.cfm", config_dir_gral); 4: 1597: rl_read_init_file(rl_file); call 0 returned 4 4: 1598: free(rl_file); unconditional 0 taken 4 -: 1599: } -: 1600: -: 1601: /* Enable tab auto-completion for commands (in PATH) in case of -: 1602: * first entered string (if autocd and/or auto-open are enabled, check -: 1603: * for paths as well). The second and later entered strings will -: 1604: * be autocompleted with paths instead, just like in Bash, or with -: 1605: * listed file names, in case of ELN's. I use a custom completion -: 1606: * function to add command and ELN completion, since readline's -: 1607: * internal completer only performs path completion */ -: 1608: -: 1609: /* Define a function for path completion. -: 1610: * NULL means to use filename_entry_function (), the default -: 1611: * filename completer. */ 4: 1612: rl_completion_entry_function = my_rl_path_completion; -: 1613: -: 1614: /* Pointer to alternative function to create matches. -: 1615: * Function is called with TEXT, START, and END. -: 1616: * START and END are indices in RL_LINE_BUFFER saying what the -: 1617: * boundaries of TEXT are. -: 1618: * If this function exists and returns NULL then call the value of -: 1619: * rl_completion_entry_function to try to match, otherwise use the -: 1620: * array of strings returned. */ 4: 1621: rl_attempted_completion_function = my_rl_completion; 4: 1622: rl_ignore_completion_duplicates = 1; -: 1623: -: 1624: /* I'm using here a custom quoting function. If not specified, -: 1625: * readline uses the default internal function. */ 4: 1626: rl_filename_quoting_function = my_rl_quote; -: 1627: -: 1628: /* Tell readline what char to use for quoting. This is only the -: 1629: * readline internal quoting function, and for custom ones, like the -: 1630: * one I use above. However, custom quoting functions, though they -: 1631: * need to define their own quoting chars, won't be called at all -: 1632: * if this variable isn't set. */ 4: 1633: rl_completer_quote_characters = "\"'"; 4: 1634: rl_completer_word_break_characters = " "; -: 1635: -: 1636: /* Whenever readline finds any of the following chars, it will call -: 1637: * the quoting function */ 4: 1638: rl_filename_quote_characters = " \t\n\"\\'`@$><=,;|&{[()]}?!*^"; -: 1639: /* According to readline documentation, the following string is -: 1640: * the default and the one used by Bash: " \t\n\"\\'`@$><=;|&{(" */ -: 1641: -: 1642: /* Executed immediately before calling the completer function, it -: 1643: * tells readline if a space char, which is a word break character -: 1644: * (see the above rl_completer_word_break_characters variable) is -: 1645: * quoted or not. If it is, readline then passes the whole string -: 1646: * to the completer function (ex: "user\ file"), and if not, only -: 1647: * wathever it found after the space char (ex: "file") -: 1648: * Thanks to George Brocklehurst for pointing out this function: -: 1649: * https://thoughtbot.com/blog/tab-completion-in-gnu-readline*/ 4: 1650: rl_char_is_quoted_p = quote_detector; -: 1651: -: 1652: /* Define a function to handle suggestions and syntax highlighting */ 4: 1653: rl_getc_function = my_rl_getc; -: 1654: -: 1655: /* This function is executed inmediately before path completion. So, -: 1656: * if the string to be completed is, for instance, "user\ file" (see -: 1657: * the above comment), this function should return the dequoted -: 1658: * string so it won't conflict with system file names: you want -: 1659: * "user file", because "user\ file" does not exist, and, in this -: 1660: * latter case, readline won't find any matches */ 4: 1661: rl_filename_dequoting_function = dequote_str; -: 1662: -: 1663: /* Initialize the keyboard bindings function */ 4: 1664: readline_kbinds(); 4: 1664-block 0 call 0 returned 4 -: 1665: -: 1666: /* Copy the list of quote chars to a global variable to be used -: 1667: * later by some of the program functions like split_str(), -: 1668: * my_rl_quote(), is_quote_char(), and my_rl_dequote() */ 4: 1669: qc = savestring(rl_filename_quote_characters, call 0 returned 4 -: 1670: strlen(rl_filename_quote_characters)); -: 1671: -: 1672:#if !defined(_NO_SUGGESTIONS) && defined(__FreeBSD__) -: 1673: if (!(flags & GUI) && getenv("CLIFM_FREEBSD_CONSOLE_SC")) -: 1674: freebsd_sc_console = 1; -: 1675:#endif -: 1676: 4: 1677: return EXIT_SUCCESS; unconditional 0 taken 4 -: 1678:} clifm-1.26.3/misc/codecov/remotes.c.gcov000066400000000000000000000601621506632037700200470ustar00rootroot00000000000000 -: 0:Source:remotes.c -: 1:/* remote.c -- functions to manage remotes */ -: 2: -: 3:/* -: 4: * This file is part of CliFM -: 5: * -: 6: * Copyright (C) 2016-2021, L. Abramovich -: 7: * All rights reserved. -: 8: -: 9: * CliFM is free software; you can redistribute it and/or modify -: 10: * it under the terms of the GNU General Public License as published by -: 11: * the Free Software Foundation; either version 2 of the License, or -: 12: * (at your option) any later version. -: 13: * -: 14: * CliFM is distributed in the hope that it will be useful, -: 15: * but WITHOUT ANY WARRANTY; without even the implied warranty of -: 16: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -: 17: * GNU General Public License for more details. -: 18: * -: 19: * You should have received a copy of the GNU General Public License -: 20: * along with this program; if not, write to the Free Software -: 21: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, -: 22: * MA 02110-1301, USA. -: 23:*/ -: 24: -: 25:#include "helpers.h" -: 26: -: 27:#include -: 28:#include -: 29:#include -: 30:#include -: 31: -: 32:#include "aux.h" -: 33:#include "exec.h" -: 34:#include "listing.h" -: 35:#include "navigation.h" -: 36:#include "history.h" -: 37:#include "mime.h" -: 38:#include "misc.h" -: 39:#include "jump.h" -: 40:#include "messages.h" -: 41:#include "file_operations.h" -: 42: -: 43:static int function remotes_list called 5 returned 100% blocks executed 86% 5: 44:remotes_list(void) -: 45:{ 5: 46: if (!remotes_n) { 5: 46-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 5 #####: 47: printf(_("%s: No remotes defined\n"), PROGRAM_NAME); %%%%%: 47-block 0 call 0 never executed call 1 never executed #####: 48: return EXIT_SUCCESS; unconditional 0 never executed -: 49: } -: 50: -: 51: size_t i; 15: 52: for (i = 0; i < remotes_n; i++) { 5: 52-block 0 unconditional 0 taken 5 10: 52-block 1 unconditional 1 taken 10 15: 52-block 2 branch 2 taken 10 branch 3 taken 5 (fallthrough) 10*: 53: if (!remotes[i].name) 10: 53-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 10 #####: 54: continue; %%%%%: 54-block 0 unconditional 0 never executed 10: 55: printf(_("Name: %s\n"), remotes[i].name); 10: 55-block 0 call 0 returned 10 call 1 returned 10 10: 56: if (remotes[i].desc) branch 0 taken 10 (fallthrough) branch 1 taken 0 10: 57: printf(_(" Comment: %s\n"), remotes[i].desc); 10: 57-block 0 call 0 returned 10 call 1 returned 10 unconditional 2 taken 10 10: 58: if (remotes[i].mountpoint) 10: 58-block 0 branch 0 taken 10 (fallthrough) branch 1 taken 0 10: 59: printf(_(" Mountpoint: %s\n"), remotes[i].mountpoint); 10: 59-block 0 call 0 returned 10 call 1 returned 10 unconditional 2 taken 10 10: 60: if (remotes[i].mount_cmd) 10: 60-block 0 branch 0 taken 10 (fallthrough) branch 1 taken 0 10: 61: printf(_(" Mount command: %s\n"), remotes[i].mount_cmd); 10: 61-block 0 call 0 returned 10 call 1 returned 10 unconditional 2 taken 10 10: 62: if (remotes[i].unmount_cmd) 10: 62-block 0 branch 0 taken 10 (fallthrough) branch 1 taken 0 10: 63: printf(_(" Unmount command: %s\n"), remotes[i].unmount_cmd); 10: 63-block 0 call 0 returned 10 call 1 returned 10 unconditional 2 taken 10 20: 64: printf(_(" Auto-unmount: %s\n"), (remotes[i].auto_unmount == 0) 10: 64-block 0 branch 0 taken 8 (fallthrough) branch 1 taken 2 10: 64-block 1 call 2 returned 10 call 3 returned 10 10: 65: ? _("false") : _("true")); 8: 65-block 0 call 0 returned 8 unconditional 1 taken 8 2: 65-block 1 call 2 returned 2 unconditional 3 taken 2 20: 66: printf(_(" Auto-mount: %s\n"), (remotes[i].auto_mount == 0) branch 0 taken 10 (fallthrough) branch 1 taken 0 10: 66-block 0 call 2 returned 10 call 3 returned 10 10*: 67: ? _("false") : _("true")); 10: 67-block 0 call 0 returned 10 unconditional 1 taken 10 %%%%%: 67-block 1 call 2 never executed unconditional 3 never executed 10: 68: printf(_(" Mounted: %s\n"), (remotes[i].mounted == 0) ? _("No") branch 0 taken 10 (fallthrough) branch 1 taken 0 10: 68-block 0 call 2 returned 10 unconditional 3 taken 10 10: 68-block 1 call 4 returned 10 call 5 returned 10 #####: 69: : _("Yes")); %%%%%: 69-block 0 call 0 never executed unconditional 1 never executed 10: 70: if (i < remotes_n - 1) branch 0 taken 5 (fallthrough) branch 1 taken 5 5: 71: puts(""); 5: 71-block 0 call 0 returned 5 unconditional 1 taken 5 -: 72: } 5: 73: return EXIT_SUCCESS; 5: 73-block 0 unconditional 0 taken 5 -: 74:} -: 75: -: 76:/* Get the index of the remote named NAME from the remotes list */ -: 77:static int function get_remote called 2 returned 100% blocks executed 60% 2: 78:get_remote(char *name) -: 79:{ 2: 80: int i = (int)remotes_n, 2: 81: found = 0; -: 82: 2: 83: while (--i >= 0) { 2: 83-block 0 unconditional 0 taken 2 2: 83-block 1 branch 1 taken 2 branch 2 taken 0 (fallthrough) 2: 84: if (*name == *remotes[i].name && strcmp(name, remotes[i].name) == 0) { 2: 84-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 0 2: 84-block 1 branch 2 taken 2 (fallthrough) branch 3 taken 0 2: 85: found = 1; 2: 86: break; 2: 86-block 0 unconditional 0 taken 2 -: 87: } -: 88: } -: 89: 2: 90: if (!found) { 2: 90-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 2 #####: 91: fprintf(stderr, _("%s: %s: No such remote\n"), PROGRAM_NAME, name); %%%%%: 91-block 0 call 0 never executed call 1 never executed #####: 92: return -1; unconditional 0 never executed -: 93: } -: 94: 2: 95: if (!remotes[i].mountpoint) { 2: 95-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 2 #####: 96: fprintf(stderr, _("%s: No mountpoint specified for '%s'\n"), PROGRAM_NAME, call 0 never executed #####: 97: remotes[i].name); %%%%%: 97-block 0 call 0 never executed #####: 98: return -1; unconditional 0 never executed -: 99: } -: 100: 2: 101: return i; 2: 101-block 0 unconditional 0 taken 2 -: 102:} -: 103: -: 104:static int function remotes_mount called 1 returned 100% blocks executed 55% 1: 105:remotes_mount(char *name) -: 106:{ 1: 107: if (!name || !*name) 1: 107-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 0 1: 107-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 1 #####: 108: return EXIT_FAILURE; %%%%%: 108-block 0 unconditional 0 never executed -: 109: 1: 110: int i = get_remote(name); 1: 110-block 0 call 0 returned 1 1: 111: if (i == -1) branch 0 taken 0 (fallthrough) branch 1 taken 1 #####: 112: return EXIT_FAILURE; %%%%%: 112-block 0 unconditional 0 never executed -: 113: 1: 114: if (!remotes[i].mount_cmd) { 1: 114-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 1 #####: 115: fprintf(stderr, _("%s: No mount command specified for '%s'\n"), call 0 never executed #####: 116: PROGRAM_NAME, remotes[i].name); %%%%%: 116-block 0 call 0 never executed #####: 117: return EXIT_FAILURE; unconditional 0 never executed -: 118: } -: 119: -: 120: struct stat attr; 1: 121: if (lstat(remotes[i].mountpoint, &attr) == -1) { 1: 121-block 0 call 0 returned 1 branch 1 taken 0 (fallthrough) branch 2 taken 1 #####: 122: char *cmd[] = {"mkdir", "-p", remotes[i].mountpoint, NULL}; #####: 123: if (launch_execve(cmd, FOREGROUND, E_NOFLAG) != EXIT_SUCCESS) { %%%%%: 123-block 0 call 0 never executed branch 1 never executed branch 2 never executed #####: 124: fprintf(stderr, _("%s: %s: %s\n"), PROGRAM_NAME, call 0 never executed #####: 125: remotes[i].mountpoint, strerror(errno)); %%%%%: 125-block 0 call 0 never executed call 1 never executed #####: 126: return EXIT_FAILURE; unconditional 0 never executed -: 127: } -: 128: } -: 129: 1: 130: if (count_dir(remotes[i].mountpoint, CPOP) <= 2 1: 130-block 0 call 0 returned 1 branch 1 taken 1 (fallthrough) branch 2 taken 0 1: 131: && launch_execle(remotes[i].mount_cmd) != EXIT_SUCCESS) 1: 131-block 0 call 0 returned 1 branch 1 taken 0 (fallthrough) branch 2 taken 1 #####: 132: return EXIT_FAILURE; %%%%%: 132-block 0 unconditional 0 never executed -: 133: 1: 134: if (xchdir(remotes[i].mountpoint, SET_TITLE) == -1) { 1: 134-block 0 call 0 returned 1 branch 1 taken 0 (fallthrough) branch 2 taken 1 #####: 135: fprintf(stderr, "%s: %s: %s\n", PROGRAM_NAME, #####: 136: remotes[i].mountpoint, strerror(errno)); %%%%%: 136-block 0 call 0 never executed call 1 never executed #####: 137: return EXIT_FAILURE; unconditional 0 never executed -: 138: } -: 139: 1: 140: int exit_status = EXIT_SUCCESS; 1: 141: if (cd_lists_on_the_fly) { 1: 141-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 0 1: 142: free(ws[cur_ws].path); 2: 143: ws[cur_ws].path = savestring(remotes[i].mountpoint, 1: 144: strlen(remotes[i].mountpoint)); 1: 144-block 0 call 0 returned 1 1: 145: add_to_jumpdb(ws[cur_ws].path); call 0 returned 1 1: 146: add_to_dirhist(ws[cur_ws].path); call 0 returned 1 1: 147: free_dirlist(); call 0 returned 1 1: 148: if (list_dir() != EXIT_SUCCESS) call 0 returned 1 branch 1 taken 0 (fallthrough) branch 2 taken 1 #####: 149: exit_status = EXIT_FAILURE; %%%%%: 149-block 0 unconditional 0 never executed -: 150: } else { #####: 151: printf(_("%s: %s: Remote mounted on %s\n"), PROGRAM_NAME, call 0 never executed unconditional 1 never executed #####: 152: remotes[i].name, remotes[i].mountpoint); %%%%%: 152-block 0 call 0 never executed -: 153: } -: 154: 1: 155: remotes[i].mounted = 1; 1: 156: return exit_status; 1: 156-block 0 unconditional 0 taken 1 -: 157:} -: 158: -: 159:static int function remotes_unmount called 1 returned 100% blocks executed 60% 1: 160:remotes_unmount(char *name) -: 161:{ 1: 162: if (!name || !*name) 1: 162-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 0 1: 162-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 1 #####: 163: return EXIT_FAILURE; %%%%%: 163-block 0 unconditional 0 never executed -: 164: 1: 165: int i = get_remote(name); 1: 165-block 0 call 0 returned 1 1: 166: if (i == -1) branch 0 taken 0 (fallthrough) branch 1 taken 1 #####: 167: return EXIT_FAILURE; %%%%%: 167-block 0 unconditional 0 never executed -: 168: 1: 169: if (!remotes[i].unmount_cmd) { 1: 169-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 1 #####: 170: fprintf(stderr, _("%s: No unmount command found for '%s'\n"), call 0 never executed #####: 171: PROGRAM_NAME, remotes[i].name); %%%%%: 171-block 0 call 0 never executed #####: 172: return EXIT_FAILURE; unconditional 0 never executed -: 173: } -: 174: 1: 175: if (launch_execle(remotes[i].unmount_cmd) != EXIT_SUCCESS) 1: 175-block 0 call 0 returned 1 branch 1 taken 0 (fallthrough) branch 2 taken 1 #####: 176: return EXIT_FAILURE; %%%%%: 176-block 0 unconditional 0 never executed -: 177: 1: 178: remotes[i].mounted = 0; 1: 179: return EXIT_SUCCESS; 1: 179-block 0 unconditional 0 taken 1 -: 180:} -: 181: -: 182:static int function remotes_edit called 3 returned 100% blocks executed 58% 3: 183:remotes_edit(char *app) -: 184:{ 3: 185: if (!remotes_file) 3: 185-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 3 #####: 186: return EXIT_FAILURE; %%%%%: 186-block 0 unconditional 0 never executed -: 187: -: 188: struct stat attr; 3: 189: if (stat(remotes_file, &attr) == -1) { 3: 189-block 0 call 0 returned 3 branch 1 taken 0 (fallthrough) branch 2 taken 3 #####: 190: fprintf(stderr, "%s: %s: %s\n", PROGRAM_NAME, remotes_file, call 0 never executed #####: 191: strerror(errno)); %%%%%: 191-block 0 call 0 never executed #####: 192: return EXIT_FAILURE; unconditional 0 never executed -: 193: } -: 194: 3: 195: time_t mtime_bfr = (time_t)attr.st_mtime; -: 196: 3: 197: int ret = EXIT_SUCCESS; 3: 198: if (app) { 3: 198-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 3 #####: 199: char *cmd[] = {app, remotes_file, NULL}; #####: 200: ret = launch_execve(cmd, FOREGROUND, E_NOSTDERR); %%%%%: 200-block 0 call 0 never executed -: 201: } else { 3: 202: ret = open_file(remotes_file); 3: 202-block 0 call 0 returned 3 unconditional 1 taken 3 -: 203: } -: 204: 3: 205: if (ret != EXIT_SUCCESS) 3: 205-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 3 #####: 206: return EXIT_FAILURE; %%%%%: 206-block 0 unconditional 0 never executed -: 207: 3: 208: if (stat(remotes_file, &attr) == -1) { 3: 208-block 0 call 0 returned 3 branch 1 taken 0 (fallthrough) branch 2 taken 3 #####: 209: fprintf(stderr, "%s: %s: %s\n", PROGRAM_NAME, remotes_file, call 0 never executed #####: 210: strerror(errno)); %%%%%: 210-block 0 call 0 never executed #####: 211: return EXIT_FAILURE; unconditional 0 never executed -: 212: } -: 213: 3: 214: if (mtime_bfr != (time_t)attr.st_mtime) { 3: 214-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 1 2: 215: free_remotes(0); 2: 215-block 0 call 0 returned 2 2: 216: load_remotes(); call 0 returned 2 unconditional 1 taken 2 -: 217: } -: 218: 3: 219: return EXIT_SUCCESS; 3: 219-block 0 unconditional 0 taken 3 -: 220:} -: 221: -: 222:int function remotes_function called 10 returned 100% blocks executed 47% 10: 223:remotes_function(char **args) -: 224:{ 10: 225: if (xargs.stealth_mode == 1) { 10: 225-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 10 #####: 226: fprintf(stderr, "%s: The net function is disabled in stealth mode\n", %%%%%: 226-block 0 call 0 never executed -: 227: PROGRAM_NAME); #####: 228: return EXIT_FAILURE; unconditional 0 never executed -: 229: } -: 230: 10: 231: if (!args[1]) 10: 231-block 0 branch 0 taken 5 (fallthrough) branch 1 taken 5 5: 232: return remotes_list(); 5: 232-block 0 call 0 returned 5 unconditional 1 taken 5 -: 233: 5*: 234: if (*args[1] == '-' && strcmp(args[1], "--help") == 0) { 5: 234-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 5 %%%%%: 234-block 1 branch 2 never executed branch 3 never executed #####: 235: puts(_(NET_USAGE)); %%%%%: 235-block 0 call 0 never executed call 1 never executed #####: 236: return EXIT_SUCCESS; unconditional 0 never executed -: 237: } -: 238: 5: 239: if (*args[1] == 'e' && strcmp(args[1], "edit") == 0) { 5: 239-block 0 branch 0 taken 4 (fallthrough) branch 1 taken 1 4: 239-block 1 branch 2 taken 3 (fallthrough) branch 3 taken 1 3: 240: if (args[2]) 3: 240-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 3 #####: 241: return remotes_edit(args[2]); %%%%%: 241-block 0 call 0 never executed unconditional 1 never executed 3: 242: return remotes_edit(NULL); 3: 242-block 0 call 0 returned 3 unconditional 1 taken 3 -: 243: } -: 244: 2*: 245: if (*args[1] == 'u' && (!*(args[1] + 1) || strcmp(args[1], "unmount") == 0)) { 2: 245-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 1 1: 245-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 1 %%%%%: 245-block 2 branch 4 never executed branch 5 never executed 1: 246: if (!args[2]) { 1: 246-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 1 #####: 247: fprintf(stderr, "%s\n", _(NET_USAGE)); %%%%%: 247-block 0 call 0 never executed call 1 never executed #####: 248: return EXIT_FAILURE; unconditional 0 never executed -: 249: } 1: 250: return remotes_unmount(args[2]); 1: 250-block 0 call 0 returned 1 unconditional 1 taken 1 -: 251: } -: 252: 1*: 253: if (*args[1] == 'm' && (!*(args[1] + 1) || strcmp(args[1], "mount") == 0)) { 1: 253-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 1 %%%%%: 253-block 1 branch 2 never executed branch 3 never executed %%%%%: 253-block 2 branch 4 never executed branch 5 never executed #####: 254: if (!args[2]) { %%%%%: 254-block 0 branch 0 never executed branch 1 never executed #####: 255: fprintf(stderr, "%s\n", _(NET_USAGE)); %%%%%: 255-block 0 call 0 never executed call 1 never executed #####: 256: return EXIT_FAILURE; unconditional 0 never executed -: 257: } #####: 258: return remotes_mount(args[2]); %%%%%: 258-block 0 call 0 never executed unconditional 1 never executed -: 259: } -: 260: 1: 261: return remotes_mount(args[1]); 1: 261-block 0 call 0 returned 1 unconditional 1 taken 1 -: 262:} -: 263: -: 264:int function automount_remotes called 4 returned 100% blocks executed 30% 4: 265:automount_remotes(void) -: 266:{ 4: 267: if (!remotes_n) 4: 267-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 3 1: 268: return EXIT_SUCCESS; 1: 268-block 0 unconditional 0 taken 1 -: 269: 3: 270: int i = (int)remotes_n, 3: 271: exit_status = EXIT_SUCCESS; 9: 272: while (--i >= 0) { 3: 272-block 0 unconditional 0 taken 3 9: 272-block 1 branch 1 taken 6 branch 2 taken 3 (fallthrough) 6: 273: if (remotes[i].name && remotes[i].auto_mount == 1 6: 273-block 0 branch 0 taken 6 (fallthrough) branch 1 taken 0 6: 273-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 6 #####: 274: && remotes[i].mountpoint && remotes[i].mount_cmd) { %%%%%: 274-block 0 branch 0 never executed branch 1 never executed %%%%%: 274-block 1 branch 2 never executed branch 3 never executed -: 275: struct stat attr; #####: 276: if (stat(remotes[i].mountpoint, &attr) == -1) { %%%%%: 276-block 0 call 0 never executed branch 1 never executed branch 2 never executed #####: 277: char *cmd[] = {"mkdir", "-p", remotes[i].mountpoint, NULL}; #####: 278: if (launch_execve(cmd, FOREGROUND, E_NOFLAG) != EXIT_SUCCESS) %%%%%: 278-block 0 call 0 never executed branch 1 never executed branch 2 never executed #####: 279: continue; %%%%%: 279-block 0 unconditional 0 never executed #####: 280: } else if (count_dir(remotes[i].mountpoint, CPOP) > 2) { %%%%%: 280-block 0 call 0 never executed branch 1 never executed branch 2 never executed #####: 281: continue; %%%%%: 281-block 0 unconditional 0 never executed -: 282: } #####: 283: printf(_("%s: Mounting remote...\n"), remotes[i].name); %%%%%: 283-block 0 call 0 never executed call 1 never executed #####: 284: if (launch_execle(remotes[i].mount_cmd) != EXIT_SUCCESS) call 0 never executed branch 1 never executed branch 2 never executed #####: 285: exit_status = EXIT_FAILURE; %%%%%: 285-block 0 unconditional 0 never executed -: 286: else #####: 287: remotes[i].mounted = 1; %%%%%: 287-block 0 unconditional 0 never executed -: 288: } -: 289: } -: 290: 3: 291: return exit_status; 3: 291-block 0 unconditional 0 taken 3 -: 292:} -: 293: -: 294:int function autounmount_remotes called 4 returned 100% blocks executed 33% 4: 295:autounmount_remotes(void) -: 296:{ 4: 297: if (!remotes_n) 4: 297-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 3 1: 298: return EXIT_SUCCESS; 1: 298-block 0 unconditional 0 taken 1 -: 299: 3: 300: int i = (int)remotes_n, 3: 301: exit_status = EXIT_SUCCESS; 9: 302: while (--i >= 0) { 3: 302-block 0 unconditional 0 taken 3 9: 302-block 1 branch 1 taken 6 branch 2 taken 3 (fallthrough) 6: 303: if (remotes[i].name && remotes[i].auto_unmount == 1 6: 303-block 0 branch 0 taken 6 (fallthrough) branch 1 taken 0 6: 303-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 6 #####: 304: && remotes[i].mountpoint && remotes[i].unmount_cmd) { %%%%%: 304-block 0 branch 0 never executed branch 1 never executed %%%%%: 304-block 1 branch 2 never executed branch 3 never executed #####: 305: if (count_dir(remotes[i].mountpoint, CPOP) <= 2) %%%%%: 305-block 0 call 0 never executed branch 1 never executed branch 2 never executed #####: 306: continue; %%%%%: 306-block 0 unconditional 0 never executed #####: 307: int dir_change = 0; #####: 308: if (*ws[cur_ws].path == *remotes[i].mountpoint %%%%%: 308-block 0 branch 0 never executed branch 1 never executed #####: 309: && strcmp(remotes[i].mountpoint, ws[cur_ws].path) == 0) { %%%%%: 309-block 0 branch 0 never executed branch 1 never executed #####: 310: xchdir("/", NO_TITLE); %%%%%: 310-block 0 call 0 never executed #####: 311: dir_change = 1; unconditional 0 never executed -: 312: } #####: 313: printf(_("%s: Unmounting remote...\n"), remotes[i].name); %%%%%: 313-block 0 call 0 never executed call 1 never executed #####: 314: if (launch_execle(remotes[i].unmount_cmd) != EXIT_SUCCESS) call 0 never executed branch 1 never executed branch 2 never executed #####: 315: exit_status = EXIT_FAILURE; %%%%%: 315-block 0 unconditional 0 never executed #####: 316: if (dir_change) %%%%%: 316-block 0 branch 0 never executed branch 1 never executed #####: 317: xchdir(ws[cur_ws].path, NO_TITLE); %%%%%: 317-block 0 call 0 never executed unconditional 1 never executed -: 318: } -: 319: } -: 320: 3: 321: return exit_status; 3: 321-block 0 unconditional 0 taken 3 -: 322:} clifm-1.26.3/misc/codecov/search.c.gcov000066400000000000000000001667331506632037700176510ustar00rootroot00000000000000 -: 0:Source:search.c -: 1:/* search.c -- functions for the search system */ -: 2: -: 3:/* -: 4: * This file is part of CliFM -: 5: * -: 6: * Copyright (C) 2016-2021, L. Abramovich -: 7: * All rights reserved. -: 8: -: 9: * CliFM is free software; you can redistribute it and/or modify -: 10: * it under the terms of the GNU General Public License as published by -: 11: * the Free Software Foundation; either version 2 of the License, or -: 12: * (at your option) any later version. -: 13: * -: 14: * CliFM is distributed in the hope that it will be useful, -: 15: * but WITHOUT ANY WARRANTY; without even the implied warranty of -: 16: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -: 17: * GNU General Public License for more details. -: 18: * -: 19: * You should have received a copy of the GNU General Public License -: 20: * along with this program; if not, write to the Free Software -: 21: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, -: 22: * MA 02110-1301, USA. -: 23:*/ -: 24: -: 25:#include "helpers.h" -: 26: -: 27:#include -: 28:#include -: 29:#include -: 30:#include -: 31:#include -: 32:#include -: 33:#include -: 34:#include -: 35:#include -: 36: -: 37:#include "aux.h" -: 38:#include "checks.h" -: 39:#include "colors.h" -: 40:#include "exec.h" -: 41:#include "glob.h" -: 42:#include "navigation.h" -: 43:#include "sort.h" -: 44: -: 45:/* List matching file names in the specified directory */ -: 46:int function search_glob called 5 returned 100% blocks executed 50% 5: 47:search_glob(char **comm, int invert) -: 48:{ 5: 49: if (!comm || !comm[0]) 5: 49-block 0 branch 0 taken 5 (fallthrough) branch 1 taken 0 5: 49-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 5 #####: 50: return EXIT_FAILURE; %%%%%: 50-block 0 unconditional 0 never executed -: 51: 5: 52: char *search_str = (char *)NULL, 5: 53: *search_path = (char *)NULL; -: 54: 5: 55: mode_t file_type = 0; -: 56: struct stat file_attrib; -: 57: -: 58: /* If there are two arguments, the one starting with '-' is the -: 59: * file type and the other is the path */ 5: 60: if (comm[1] && comm[2]) { 5: 60-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 3 2: 60-block 1 branch 2 taken 1 (fallthrough) branch 3 taken 1 -: 61: 1: 62: if (comm[1][0] == '-') { 1: 62-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 0 1: 63: file_type = (mode_t)comm[1][1]; 1: 64: search_path = comm[2]; 1: 64-block 0 unconditional 0 taken 1 -: 65: } -: 66: #####: 67: else if (comm[2][0] == '-') { %%%%%: 67-block 0 branch 0 never executed branch 1 never executed #####: 68: file_type = (mode_t)comm[2][1]; #####: 69: search_path = comm[1]; %%%%%: 69-block 0 unconditional 0 never executed -: 70: } -: 71: -: 72: else #####: 73: search_path = comm[1]; %%%%%: 73-block 0 unconditional 0 never executed -: 74: } -: 75: -: 76: /* If just one argument, '-' indicates file type. Else, we have a -: 77: * path */ 4: 78: else if (comm[1]) { 4: 78-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 3 -: 79: 1: 80: if (comm[1][0] == '-') 1: 80-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 1 #####: 81: file_type = (mode_t)comm[1][1]; %%%%%: 81-block 0 unconditional 0 never executed -: 82: else 1: 83: search_path = comm[1]; 1: 83-block 0 unconditional 0 taken 1 -: 84: } -: 85: -: 86: /* If no arguments, search_path will be NULL and file_type zero */ -: 87: 5: 88: int recursive = 0; -: 89: 5: 90: if (file_type) { 5: 90-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 4 -: 91: -: 92: /* Convert file type into a macro that can be decoded by stat(). -: 93: * If file type is specified, matches will be checked against -: 94: * this value */ 1: 95: switch (file_type) { 1: 95-block 0 branch 0 taken 0 branch 1 taken 1 branch 2 taken 0 branch 3 taken 0 branch 4 taken 0 branch 5 taken 0 branch 6 taken 0 branch 7 taken 0 branch 8 taken 0 #####: 96: case 'd': #####: 97: file_type = invert ? DT_DIR : S_IFDIR; %%%%%: 97-block 0 branch 0 never executed branch 1 never executed %%%%%: 97-block 1 unconditional 2 never executed %%%%%: 97-block 2 unconditional 3 never executed #####: 98: break; %%%%%: 98-block 0 unconditional 0 never executed 1: 99: case 'r': 1*: 100: file_type = invert ? DT_REG : S_IFREG; 1: 100-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 1 %%%%%: 100-block 1 unconditional 2 never executed 1: 100-block 2 unconditional 3 taken 1 1: 101: break; 1: 101-block 0 unconditional 0 taken 1 #####: 102: case 'l': #####: 103: file_type = invert ? DT_LNK : S_IFLNK; %%%%%: 103-block 0 branch 0 never executed branch 1 never executed %%%%%: 103-block 1 unconditional 2 never executed %%%%%: 103-block 2 unconditional 3 never executed #####: 104: break; %%%%%: 104-block 0 unconditional 0 never executed #####: 105: case 's': #####: 106: file_type = invert ? DT_SOCK : S_IFSOCK; %%%%%: 106-block 0 branch 0 never executed branch 1 never executed %%%%%: 106-block 1 unconditional 2 never executed %%%%%: 106-block 2 unconditional 3 never executed #####: 107: break; %%%%%: 107-block 0 unconditional 0 never executed #####: 108: case 'f': #####: 109: file_type = invert ? DT_FIFO : S_IFIFO; %%%%%: 109-block 0 branch 0 never executed branch 1 never executed %%%%%: 109-block 1 unconditional 2 never executed %%%%%: 109-block 2 unconditional 3 never executed #####: 110: break; %%%%%: 110-block 0 unconditional 0 never executed #####: 111: case 'b': #####: 112: file_type = invert ? DT_BLK : S_IFBLK; %%%%%: 112-block 0 branch 0 never executed branch 1 never executed %%%%%: 112-block 1 unconditional 2 never executed %%%%%: 112-block 2 unconditional 3 never executed #####: 113: break; %%%%%: 113-block 0 unconditional 0 never executed #####: 114: case 'c': #####: 115: file_type = invert ? DT_CHR : S_IFCHR; %%%%%: 115-block 0 branch 0 never executed branch 1 never executed %%%%%: 115-block 1 unconditional 2 never executed %%%%%: 115-block 2 unconditional 3 never executed #####: 116: break; %%%%%: 116-block 0 unconditional 0 never executed #####: 117: case 'x': #####: 118: recursive = 1; #####: 119: break; %%%%%: 119-block 0 unconditional 0 never executed -: 120: #####: 121: default: #####: 122: fprintf(stderr, _("%s: '%c': Unrecognized file type\n"), call 0 never executed #####: 123: PROGRAM_NAME, (char)file_type); %%%%%: 123-block 0 call 0 never executed #####: 124: return EXIT_FAILURE; unconditional 0 never executed -: 125: } -: 126: } -: 127: 5: 128: if (recursive) { 5: 128-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 5 #####: 129: char *cmd[] = {"find", (search_path && *search_path) ? search_path %%%%%: 129-block 0 branch 0 never executed branch 1 never executed #####: 130: : ".", "-name", comm[0] + 1, NULL}; %%%%%: 130-block 0 branch 0 never executed branch 1 never executed %%%%%: 130-block 1 unconditional 2 never executed %%%%%: 130-block 2 unconditional 3 never executed #####: 131: launch_execve(cmd, FOREGROUND, E_NOSTDERR); %%%%%: 131-block 0 call 0 never executed #####: 132: return EXIT_SUCCESS; unconditional 0 never executed -: 133: } -: 134: -: 135: /* If we have a path ("/str /path"), chdir into it, since -: 136: * glob() works on CWD */ 5: 137: if (search_path && *search_path) { 5: 137-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 3 2: 137-block 1 branch 2 taken 2 (fallthrough) branch 3 taken 0 -: 138: -: 139: /* Deescape the search path, if necessary */ 2: 140: if (strchr(search_path, '\\')) { 2: 140-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 2 #####: 141: char *deq_dir = dequote_str(search_path, 0); %%%%%: 141-block 0 call 0 never executed -: 142: #####: 143: if (!deq_dir) { branch 0 never executed branch 1 never executed #####: 144: fprintf(stderr, _("%s: %s: Error dequoting file name\n"), call 0 never executed #####: 145: PROGRAM_NAME, comm[1]); %%%%%: 145-block 0 call 0 never executed #####: 146: return EXIT_FAILURE; unconditional 0 never executed -: 147: } -: 148: #####: 149: strcpy(search_path, deq_dir); #####: 150: free(deq_dir); %%%%%: 150-block 0 unconditional 0 never executed -: 151: } -: 152: 2: 153: size_t path_len = strlen(search_path); 2: 154: if (search_path[path_len - 1] == '/') 2: 154-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 2 #####: 155: search_path[path_len - 1] = '\0'; %%%%%: 155-block 0 unconditional 0 never executed -: 156: -: 157: /* If search is current directory */ 2*: 158: if ((*search_path == '.' && !search_path[1]) || 2: 158-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 2 %%%%%: 158-block 1 branch 2 never executed branch 3 never executed 2: 159: (search_path[1] == ws[cur_ws].path[1] 2: 159-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 1 1: 160: && strcmp(search_path, ws[cur_ws].path) == 0)) { 1: 160-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 0 1: 161: search_path = (char *)NULL; 1: 161-block 0 unconditional 0 taken 1 1: 162: } else if (xchdir(search_path, NO_TITLE) == -1) { 1: 162-block 0 call 0 returned 1 branch 1 taken 0 (fallthrough) branch 2 taken 1 #####: 163: fprintf(stderr, "%s: %s: %s\n", PROGRAM_NAME, search_path, call 0 never executed #####: 164: strerror(errno)); %%%%%: 164-block 0 call 0 never executed #####: 165: return EXIT_FAILURE; unconditional 0 never executed -: 166: } -: 167: } -: 168: -: 169: int i; -: 170: 5: 171: char *tmp = comm[0]; -: 172: 5: 173: if (invert) 5: 173-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 4 1: 174: tmp++; 1: 174-block 0 unconditional 0 taken 1 -: 175: -: 176: /* Search for globbing char */ 5: 177: int glob_char_found = 0; 17: 178: for (i = 1; tmp[i]; i++) { 5: 178-block 0 unconditional 0 taken 5 12: 178-block 1 unconditional 1 taken 12 17: 178-block 2 branch 2 taken 14 branch 3 taken 3 (fallthrough) 14: 179: if (tmp[i] == '*' || tmp[i] == '?' || tmp[i] == '[' || tmp[i] == '{' 14: 179-block 0 branch 0 taken 14 (fallthrough) branch 1 taken 0 14: 179-block 1 branch 2 taken 14 (fallthrough) branch 3 taken 0 14: 179-block 2 branch 4 taken 14 (fallthrough) branch 5 taken 0 14: 179-block 3 branch 6 taken 14 (fallthrough) branch 7 taken 0 -: 180: /* Consider regex chars as well: we don't want this "r$" -: 181: * to become this "*r$*" */ 14: 182: || tmp[i] == '|' || tmp[i] == '^' || tmp[i] == '+' || tmp[i] == '$' 14: 182-block 0 branch 0 taken 14 (fallthrough) branch 1 taken 0 14: 182-block 1 branch 2 taken 14 (fallthrough) branch 3 taken 0 14: 182-block 2 branch 4 taken 14 (fallthrough) branch 5 taken 0 14: 182-block 3 branch 6 taken 14 (fallthrough) branch 7 taken 0 14: 183: || tmp[i] == '.') { 14: 183-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 12 2: 184: glob_char_found = 1; 2: 185: break; 2: 185-block 0 unconditional 0 taken 2 -: 186: } -: 187: } -: 188: -: 189: /* If search string is just "STR" (no glob chars), change it -: 190: * to "*STR*" */ -: 191: 5: 192: if (!glob_char_found) { 5: 192-block 0 branch 0 taken 3 (fallthrough) branch 1 taken 2 3: 193: size_t search_str_len = strlen(comm[0]); -: 194: 3: 195: comm[0] = (char *)xrealloc(comm[0], (search_str_len + 2) * 3: 195-block 0 call 0 returned 3 -: 196: sizeof(char)); 3: 197: tmp = comm[0]; 3: 198: if (invert) { branch 0 taken 0 (fallthrough) branch 1 taken 3 #####: 199: ++tmp; #####: 200: search_str_len = strlen(tmp); %%%%%: 200-block 0 unconditional 0 never executed -: 201: } -: 202: 3: 203: tmp[0] = '*'; 3: 204: tmp[search_str_len] = '*'; 3: 205: tmp[search_str_len + 1] = '\0'; 3: 206: search_str = tmp; 3: 206-block 0 unconditional 0 taken 3 -: 207: } -: 208: -: 209: else 2: 210: search_str = tmp + 1; 2: 210-block 0 unconditional 0 taken 2 -: 211: -: 212: /* Get matches, if any */ -: 213: glob_t globbed_files; 5: 214: int ret = glob(search_str, GLOB_BRACE, NULL, &globbed_files); 5: 214-block 0 call 0 returned 5 -: 215: 5: 216: if (ret != 0) { branch 0 taken 2 (fallthrough) branch 1 taken 3 2: 217: puts(_("Glob: No matches found. Trying regex...")); 2: 217-block 0 call 0 returned 2 call 1 returned 2 -: 218: 2: 219: globfree(&globbed_files); call 0 returned 2 -: 220: 2: 221: if (search_path) { branch 0 taken 0 (fallthrough) branch 1 taken 2 -: 222: /* Go back to the directory we came from */ #####: 223: if (xchdir(ws[cur_ws].path, NO_TITLE) == -1) %%%%%: 223-block 0 call 0 never executed branch 1 never executed branch 2 never executed #####: 224: fprintf(stderr, "%s: %s: %s\n", PROGRAM_NAME, #####: 225: ws[cur_ws].path, strerror(errno)); %%%%%: 225-block 0 call 0 never executed call 1 never executed unconditional 2 never executed -: 226: } -: 227: 2: 228: return EXIT_FAILURE; 2: 228-block 0 unconditional 0 taken 2 -: 229: } -: 230: -: 231: /* We have matches */ 3: 232: int scandir_files = 0, 3: 233: found = 0; -: 234: 3: 235: size_t flongest = 0; -: 236: -: 237: /* We need to store pointers to matching file names in array of -: 238: * pointers, just as the file name length (to construct the -: 239: * columned output), and, if searching in CWD, its index (ELN) -: 240: * in the dirlist array as well */ 3: 241: char **pfiles = (char **)NULL; 3: 242: int *eln = (int *)0; 3: 243: size_t *files_len = (size_t *)0; 3: 244: struct dirent **ent = (struct dirent **)NULL; -: 245: 3: 246: if (invert) { 3: 246-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 3 #####: 247: if (!search_path) { %%%%%: 247-block 0 branch 0 never executed branch 1 never executed -: 248: int k; -: 249: #####: 250: pfiles = (char **)xnmalloc(files + 1, sizeof(char *)); %%%%%: 250-block 0 call 0 never executed #####: 251: eln = (int *)xnmalloc(files + 1, sizeof(int)); call 0 never executed #####: 252: files_len = (size_t *)xnmalloc(files + 1, sizeof(size_t)); call 0 never executed -: 253: #####: 254: for (k = 0; file_info[k].name; k++) { unconditional 0 never executed %%%%%: 254-block 0 unconditional 1 never executed %%%%%: 254-block 1 branch 2 never executed branch 3 never executed #####: 255: int l, f = 0; -: 256: #####: 257: for (l = 0; globbed_files.gl_pathv[l]; l++) { %%%%%: 257-block 0 unconditional 0 never executed %%%%%: 257-block 1 unconditional 1 never executed %%%%%: 257-block 2 branch 2 never executed branch 3 never executed #####: 258: if (*globbed_files.gl_pathv[l] == *file_info[k].name %%%%%: 258-block 0 branch 0 never executed branch 1 never executed #####: 259: && strcmp(globbed_files.gl_pathv[l], file_info[k].name) == 0) { %%%%%: 259-block 0 branch 0 never executed branch 1 never executed #####: 260: f = 1; #####: 261: break; %%%%%: 261-block 0 unconditional 0 never executed -: 262: } -: 263: } -: 264: #####: 265: if (!f) { %%%%%: 265-block 0 branch 0 never executed branch 1 never executed -: 266: #####: 267: if (file_type && file_info[k].type != file_type) %%%%%: 267-block 0 branch 0 never executed branch 1 never executed %%%%%: 267-block 1 branch 2 never executed branch 3 never executed #####: 268: continue; %%%%%: 268-block 0 unconditional 0 never executed -: 269: #####: 270: eln[found] = (int)(k + 1); #####: 271: files_len[found] = file_info[k].len #####: 272: + (size_t)file_info[k].eln_n + 1; #####: 273: if (files_len[found] > flongest) %%%%%: 273-block 0 branch 0 never executed branch 1 never executed #####: 274: flongest = files_len[found]; %%%%%: 274-block 0 unconditional 0 never executed -: 275: #####: 276: pfiles[found++] = file_info[k].name; %%%%%: 276-block 0 unconditional 0 never executed -: 277: } -: 278: } -: 279: } -: 280: -: 281: else { #####: 282: scandir_files = scandir(search_path, &ent, skip_files, %%%%%: 282-block 0 call 0 never executed -: 283: xalphasort); -: 284: #####: 285: if (scandir_files != -1) { branch 0 never executed branch 1 never executed -: 286: #####: 287: pfiles = (char **)xnmalloc((size_t)scandir_files + 1, %%%%%: 287-block 0 call 0 never executed -: 288: sizeof(char *)); #####: 289: eln = (int *)xnmalloc((size_t)scandir_files + 1, call 0 never executed -: 290: sizeof(int)); #####: 291: files_len = (size_t *)xnmalloc((size_t)scandir_files + 1, call 0 never executed -: 292: sizeof(size_t)); -: 293: -: 294: int k, l; -: 295: #####: 296: for (k = 0; k < scandir_files; k++) { unconditional 0 never executed %%%%%: 296-block 0 unconditional 1 never executed %%%%%: 296-block 1 branch 2 never executed branch 3 never executed #####: 297: int f = 0; -: 298: #####: 299: for (l = 0; globbed_files.gl_pathv[l]; l++) { %%%%%: 299-block 0 unconditional 0 never executed %%%%%: 299-block 1 unconditional 1 never executed %%%%%: 299-block 2 branch 2 never executed branch 3 never executed #####: 300: if (*ent[k]->d_name == *globbed_files.gl_pathv[l] %%%%%: 300-block 0 branch 0 never executed branch 1 never executed #####: 301: && strcmp(ent[k]->d_name, globbed_files.gl_pathv[l]) == 0) { %%%%%: 301-block 0 branch 0 never executed branch 1 never executed #####: 302: f = 1; #####: 303: break; %%%%%: 303-block 0 unconditional 0 never executed -: 304: } -: 305: } -: 306: #####: 307: if (!f) { %%%%%: 307-block 0 branch 0 never executed branch 1 never executed -: 308: -: 309:#if !defined(_DIRENT_HAVE_D_TYPE) -: 310: struct stat attr; -: 311: mode_t type; -: 312: if (lstat(ent[k]->d_name, &attr) == -1) -: 313: continue; -: 314: switch (attr.st_mode & S_IFMT) { -: 315: case S_IFBLK: type = DT_BLK; break; -: 316: case S_IFCHR: type = DT_CHR; break; -: 317: case S_IFDIR: type = DT_DIR; break; -: 318: case S_IFIFO: type = DT_FIFO; break; -: 319: case S_IFLNK: type = DT_LNK; break; -: 320: case S_IFREG: type = DT_REG; break; -: 321: case S_IFSOCK: type = DT_SOCK; break; -: 322: default: type = DT_UNKNOWN; break; -: 323: } -: 324: -: 325: if (file_type && type != file_type) -: 326:#else #####: 327: if (file_type && ent[k]->d_type != file_type) %%%%%: 327-block 0 branch 0 never executed branch 1 never executed %%%%%: 327-block 1 branch 2 never executed branch 3 never executed -: 328:#endif #####: 329: continue; %%%%%: 329-block 0 unconditional 0 never executed -: 330: #####: 331: eln[found] = -1; #####: 332: files_len[found] = unicode #####: 333: ? wc_xstrlen(ent[k]->d_name) %%%%%: 333-block 0 call 0 never executed unconditional 1 never executed #####: 334: : strlen(ent[k]->d_name); %%%%%: 334-block 0 branch 0 never executed branch 1 never executed %%%%%: 334-block 1 unconditional 2 never executed -: 335: #####: 336: if (files_len[found] > flongest) %%%%%: 336-block 0 branch 0 never executed branch 1 never executed #####: 337: flongest = files_len[found]; %%%%%: 337-block 0 unconditional 0 never executed -: 338: #####: 339: pfiles[found++] = ent[k]->d_name; %%%%%: 339-block 0 unconditional 0 never executed -: 340: } -: 341: } -: 342: } -: 343: } -: 344: } -: 345: -: 346: else { /* No invert search */ -: 347: 3: 348: pfiles = (char **)xnmalloc(globbed_files.gl_pathc + 1, 3: 348-block 0 call 0 returned 3 -: 349: sizeof(char *)); 3: 350: eln = (int *)xnmalloc(globbed_files.gl_pathc + 1, sizeof(int)); call 0 returned 3 3: 351: files_len = (size_t *)xnmalloc(globbed_files.gl_pathc + 1, sizeof(size_t)); call 0 returned 3 -: 352: 12: 353: for (i = 0; globbed_files.gl_pathv[i]; i++) { unconditional 0 taken 3 9: 353-block 0 unconditional 1 taken 9 12: 353-block 1 branch 2 taken 9 branch 3 taken 3 (fallthrough) -: 354: 9*: 355: if (*globbed_files.gl_pathv[i] == '.' 9: 355-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 9 #####: 356: && (!globbed_files.gl_pathv[i][1] %%%%%: 356-block 0 branch 0 never executed branch 1 never executed #####: 357: || (globbed_files.gl_pathv[i][1] == '.' %%%%%: 357-block 0 branch 0 never executed branch 1 never executed #####: 358: && !globbed_files.gl_pathv[i][2]))) %%%%%: 358-block 0 branch 0 never executed branch 1 never executed #####: 359: continue; %%%%%: 359-block 0 unconditional 0 never executed -: 360: 9: 361: if (file_type) { 9: 361-block 0 branch 0 taken 3 (fallthrough) branch 1 taken 6 -: 362: -: 363: /* Simply skip all files not matching file_type */ 3*: 364: if (lstat(globbed_files.gl_pathv[i], &file_attrib) == -1) 3: 364-block 0 call 0 returned 3 branch 1 taken 0 (fallthrough) branch 2 taken 3 #####: 365: continue; %%%%%: 365-block 0 unconditional 0 never executed -: 366: 3*: 367: if ((file_attrib.st_mode & S_IFMT) != file_type) 3: 367-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 3 #####: 368: continue; %%%%%: 368-block 0 unconditional 0 never executed -: 369: } -: 370: 9: 371: pfiles[found] = globbed_files.gl_pathv[i]; -: 372: -: 373: /* Get the longest file name in the list */ -: 374: -: 375: /* If not searching in CWD, we only need to know the file's -: 376: * length (no ELN) */ 9: 377: if (search_path) { 9: 377-block 0 branch 0 taken 3 (fallthrough) branch 1 taken 6 -: 378: -: 379: /* This will be passed to colors_list(): -1 means no ELN */ 3: 380: eln[found] = -1; -: 381: 3: 382: files_len[found] = unicode ? wc_xstrlen(pfiles[found]) 3: 382-block 0 call 0 returned 3 unconditional 1 taken 3 3*: 383: : strlen(pfiles[found]); 3: 383-block 0 branch 0 taken 3 (fallthrough) branch 1 taken 0 %%%%%: 383-block 1 unconditional 2 never executed -: 384: 3: 385: if (files_len[found] > flongest) 3: 385-block 0 branch 0 taken 3 (fallthrough) branch 1 taken 0 3: 386: flongest = files_len[found]; 3: 386-block 0 unconditional 0 taken 3 -: 387: 3: 388: found++; 3: 388-block 0 unconditional 0 taken 3 -: 389: } -: 390: -: 391: /* If searching in CWD, take into account the file's ELN -: 392: * when calculating its legnth */ -: 393: else { -: 394: size_t j; -: 395: 36: 396: for (j = 0; file_info[j].name; j++) { 6: 396-block 0 unconditional 0 taken 6 30: 396-block 1 unconditional 1 taken 30 36: 396-block 2 branch 2 taken 30 branch 3 taken 6 (fallthrough) -: 397: 30: 398: if (*pfiles[found] != *file_info[j].name 30: 398-block 0 branch 0 taken 18 (fallthrough) branch 1 taken 12 18: 399: || strcmp(pfiles[found], file_info[j].name) != 0) 18: 399-block 0 branch 0 taken 12 (fallthrough) branch 1 taken 6 24: 400: continue; 24: 400-block 0 unconditional 0 taken 24 -: 401: 6: 402: eln[found] = (int)(j + 1); -: 403: 6: 404: files_len[found] = file_info[j].len 6: 405: + (size_t)file_info[j].eln_n + 1; -: 406: 6: 407: if (files_len[found] > flongest) 6: 407-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 4 2: 408: flongest = files_len[found]; 2: 408-block 0 unconditional 0 taken 2 -: 409: } -: 410: 6: 411: found++; 6: 411-block 0 unconditional 0 taken 6 -: 412: } -: 413: } -: 414: } -: 415: -: 416: /* Print the results using colors and columns */ 3: 417: if (found) { 3: 417-block 0 branch 0 taken 3 (fallthrough) branch 1 taken 0 -: 418: 3: 419: int columns_n = 0, 3: 420: last_column = 0; -: 421: -: 422: struct winsize w; 3: 423: ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); 3: 423-block 0 call 0 returned 3 3: 424: unsigned short tcols = w.ws_col; -: 425: 3: 426: if (flongest == 0 || flongest > tcols) branch 0 taken 3 (fallthrough) branch 1 taken 0 3: 426-block 0 branch 2 taken 0 (fallthrough) branch 3 taken 3 #####: 427: columns_n = 1; %%%%%: 427-block 0 unconditional 0 never executed -: 428: else 3: 429: columns_n = (int)(tcols / (flongest + 1)); 3: 429-block 0 unconditional 0 taken 3 -: 430: 3: 431: if (columns_n > found) 3: 431-block 0 branch 0 taken 3 (fallthrough) branch 1 taken 0 3: 432: columns_n = found; 3: 432-block 0 unconditional 0 taken 3 -: 433: 12: 434: for (i = 0; i < found; i++) { 3: 434-block 0 unconditional 0 taken 3 9: 434-block 1 unconditional 1 taken 9 12: 434-block 2 branch 2 taken 9 branch 3 taken 3 (fallthrough) -: 435: 9*: 436: if (!pfiles[i]) 9: 436-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 9 #####: 437: continue; %%%%%: 437-block 0 unconditional 0 never executed -: 438: 9: 439: if ((i + 1) % columns_n == 0) 9: 439-block 0 branch 0 taken 3 (fallthrough) branch 1 taken 6 3: 440: last_column = 1; 3: 440-block 0 unconditional 0 taken 3 -: 441: else 6: 442: last_column = 0; 6: 442-block 0 unconditional 0 taken 6 -: 443: 21: 444: colors_list(pfiles[i], (eln[i] && eln[i] != -1) ? eln[i] : 0, 9: 444-block 0 branch 0 taken 6 (fallthrough) branch 1 taken 3 3: 444-block 1 unconditional 2 taken 3 6: 444-block 2 unconditional 3 taken 6 9: 444-block 3 branch 4 taken 6 (fallthrough) branch 5 taken 3 3: 444-block 4 unconditional 6 taken 3 9: 444-block 5 branch 7 taken 9 (fallthrough) branch 8 taken 0 9: 444-block 6 branch 9 taken 6 (fallthrough) branch 10 taken 3 6: 444-block 7 unconditional 11 taken 6 3: 444-block 8 unconditional 12 taken 3 9: 444-block 9 call 13 returned 9 unconditional 14 taken 9 6: 445: (last_column || i == (found - 1)) ? 0 : 6: 445-block 0 branch 0 taken 6 (fallthrough) branch 1 taken 0 6: 446: (int)(flongest - files_len[i]) + 1, 6: 446-block 0 unconditional 0 taken 6 6: 447: (last_column || i == found - 1) ? 1 : 0); 6: 447-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 6 -: 448: /* Second argument to colors_list() is: -: 449: * 0: Do not print any ELN -: 450: * Positive number: Print positive number as ELN -: 451: * -1: Print "?" instead of an ELN */ -: 452: } -: 453: 3: 454: printf(_("Matches found: %d\n"), found); 3: 454-block 0 call 0 returned 3 call 1 returned 3 -: 455: } -: 456: -: 457: /* else -: 458: printf(_("%s: No matches found\n"), PROGRAM_NAME); */ -: 459: -: 460: /* Free stuff */ 3*: 461: if (invert && search_path) { 3: 461-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 3 %%%%%: 461-block 1 branch 2 never executed branch 3 never executed #####: 462: i = scandir_files; #####: 463: while (--i >= 0) %%%%%: 463-block 0 unconditional 0 never executed %%%%%: 463-block 1 branch 1 never executed branch 2 never executed #####: 464: free(ent[i]); %%%%%: 464-block 0 unconditional 0 never executed #####: 465: free(ent); %%%%%: 465-block 0 unconditional 0 never executed -: 466: } -: 467: 3: 468: free(eln); 3: 469: free(files_len); 3: 470: free(pfiles); 3: 471: globfree(&globbed_files); 3: 471-block 0 call 0 returned 3 -: 472: -: 473: /* If needed, go back to the directory we came from */ 3: 474: if (search_path) { branch 0 taken 1 (fallthrough) branch 1 taken 2 1: 475: if (xchdir(ws[cur_ws].path, NO_TITLE) == -1) { 1: 475-block 0 call 0 returned 1 branch 1 taken 0 (fallthrough) branch 2 taken 1 #####: 476: fprintf(stderr, "%s: %s: %s\n", PROGRAM_NAME, #####: 477: ws[cur_ws].path, strerror(errno)); %%%%%: 477-block 0 call 0 never executed call 1 never executed #####: 478: return EXIT_FAILURE; unconditional 0 never executed -: 479: } -: 480: } -: 481: 3: 482: if (!found) 3: 482-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 3 #####: 483: return EXIT_FAILURE; %%%%%: 483-block 0 unconditional 0 never executed -: 484: 3: 485: return EXIT_SUCCESS; 3: 485-block 0 unconditional 0 taken 3 -: 486:} -: 487: -: 488:/* List matching (or not marching, if inverse is set to 1) file names -: 489: * in the specified directory */ -: 490:int function search_regex called 2 returned 100% blocks executed 37% 2: 491:search_regex(char **comm, int invert) -: 492:{ 2: 493: if (!comm || !comm[0]) 2: 493-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 0 2: 493-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 2 #####: 494: return EXIT_FAILURE; %%%%%: 494-block 0 unconditional 0 never executed -: 495: 2: 496: char *search_str = (char *)NULL, *search_path = (char *)NULL; 2: 497: mode_t file_type = 0; -: 498: -: 499: /* If there are two arguments, the one starting with '-' is the -: 500: * file type and the other is the path */ 2*: 501: if (comm[1] && comm[2]) { 2: 501-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 2 %%%%%: 501-block 1 branch 2 never executed branch 3 never executed -: 502: #####: 503: if (*comm[1] == '-') { %%%%%: 503-block 0 branch 0 never executed branch 1 never executed #####: 504: file_type = (mode_t) * (comm[1] + 1); #####: 505: search_path = comm[2]; %%%%%: 505-block 0 unconditional 0 never executed -: 506: } -: 507: #####: 508: else if (*comm[2] == '-') { %%%%%: 508-block 0 branch 0 never executed branch 1 never executed #####: 509: file_type = (mode_t) * (comm[2] + 1); #####: 510: search_path = comm[1]; %%%%%: 510-block 0 unconditional 0 never executed -: 511: } -: 512: -: 513: else #####: 514: search_path = comm[1]; %%%%%: 514-block 0 unconditional 0 never executed -: 515: } -: 516: -: 517: /* If just one argument, '-' indicates file type. Else, we have a -: 518: * path */ 2: 519: else if (comm[1]) { 2: 519-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 2 #####: 520: if (*comm[1] == '-') %%%%%: 520-block 0 branch 0 never executed branch 1 never executed #####: 521: file_type = (mode_t) * (comm[1] + 1); %%%%%: 521-block 0 unconditional 0 never executed -: 522: else #####: 523: search_path = comm[1]; %%%%%: 523-block 0 unconditional 0 never executed -: 524: } -: 525: -: 526: /* If no arguments, search_path will be NULL and file_type zero */ -: 527: 2: 528: if (file_type) { 2: 528-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 2 -: 529: -: 530: /* If file type is specified, matches will be checked against -: 531: * this value */ #####: 532: switch (file_type) { %%%%%: 532-block 0 branch 0 never executed branch 1 never executed branch 2 never executed branch 3 never executed branch 4 never executed branch 5 never executed branch 6 never executed branch 7 never executed #####: 533: case 'd': #####: 534: file_type = DT_DIR; #####: 535: break; %%%%%: 535-block 0 unconditional 0 never executed #####: 536: case 'r': #####: 537: file_type = DT_REG; #####: 538: break; %%%%%: 538-block 0 unconditional 0 never executed #####: 539: case 'l': #####: 540: file_type = DT_LNK; #####: 541: break; %%%%%: 541-block 0 unconditional 0 never executed #####: 542: case 's': #####: 543: file_type = DT_SOCK; #####: 544: break; %%%%%: 544-block 0 unconditional 0 never executed #####: 545: case 'f': #####: 546: file_type = DT_FIFO; #####: 547: break; %%%%%: 547-block 0 unconditional 0 never executed #####: 548: case 'b': #####: 549: file_type = DT_BLK; #####: 550: break; %%%%%: 550-block 0 unconditional 0 never executed #####: 551: case 'c': #####: 552: file_type = DT_CHR; #####: 553: break; %%%%%: 553-block 0 unconditional 0 never executed -: 554: #####: 555: default: #####: 556: fprintf(stderr, _("%s: '%c': Unrecognized file type\n"), call 0 never executed #####: 557: PROGRAM_NAME, (char)file_type); %%%%%: 557-block 0 call 0 never executed #####: 558: return EXIT_FAILURE; unconditional 0 never executed -: 559: } -: 560: } -: 561: 2: 562: struct dirent **reg_dirlist = (struct dirent **)NULL; 2: 563: int tmp_files = 0; -: 564: -: 565: /* If we have a path ("/str /path"), chdir into it, since -: 566: * regex() works on CWD */ 2*: 567: if (search_path && *search_path) { 2: 567-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 2 %%%%%: 567-block 1 branch 2 never executed branch 3 never executed -: 568: -: 569: /* Deescape the search path, if necessary */ #####: 570: if (strchr(search_path, '\\')) { %%%%%: 570-block 0 branch 0 never executed branch 1 never executed #####: 571: char *deq_dir = dequote_str(search_path, 0); %%%%%: 571-block 0 call 0 never executed -: 572: #####: 573: if (!deq_dir) { branch 0 never executed branch 1 never executed #####: 574: fprintf(stderr, _("%s: %s: Error dequoting file name\n"), call 0 never executed #####: 575: PROGRAM_NAME, comm[1]); %%%%%: 575-block 0 call 0 never executed #####: 576: return EXIT_FAILURE; unconditional 0 never executed -: 577: } -: 578: #####: 579: strcpy(search_path, deq_dir); #####: 580: free(deq_dir); %%%%%: 580-block 0 unconditional 0 never executed -: 581: } -: 582: #####: 583: size_t path_len = strlen(search_path); #####: 584: if (search_path[path_len - 1] == '/') %%%%%: 584-block 0 branch 0 never executed branch 1 never executed #####: 585: search_path[path_len - 1] = '\0'; %%%%%: 585-block 0 unconditional 0 never executed -: 586: #####: 587: if ((*search_path == '.' && !search_path[1]) %%%%%: 587-block 0 branch 0 never executed branch 1 never executed %%%%%: 587-block 1 branch 2 never executed branch 3 never executed #####: 588: || (search_path[1] == ws[cur_ws].path[1] %%%%%: 588-block 0 branch 0 never executed branch 1 never executed #####: 589: && strcmp(search_path, ws[cur_ws].path) == 0)) %%%%%: 589-block 0 branch 0 never executed branch 1 never executed #####: 590: search_path = (char *)NULL; %%%%%: 590-block 0 unconditional 0 never executed -: 591: #####: 592: if (search_path && *search_path) { %%%%%: 592-block 0 branch 0 never executed branch 1 never executed %%%%%: 592-block 1 branch 2 never executed branch 3 never executed #####: 593: if (xchdir(search_path, NO_TITLE) == -1) { %%%%%: 593-block 0 call 0 never executed branch 1 never executed branch 2 never executed #####: 594: fprintf(stderr, "%s: %s: %s\n", PROGRAM_NAME, call 0 never executed #####: 595: search_path, strerror(errno)); %%%%%: 595-block 0 call 0 never executed #####: 596: return EXIT_FAILURE; unconditional 0 never executed -: 597: } -: 598: #####: 599: tmp_files = scandir(".", ®_dirlist, skip_files, xalphasort); %%%%%: 599-block 0 call 0 never executed -: 600: -: 601: /* tmp_files = scandir(".", ®_dirlist, skip_files, -: 602: sort == 0 ? NULL : sort == 1 ? m_alphasort -: 603: : sort == 2 ? size_sort : sort == 3 -: 604: ? atime_sort : sort == 4 ? btime_sort -: 605: : sort == 5 ? ctime_sort : sort == 6 -: 606: ? mtime_sort : sort == 7 ? m_versionsort -: 607: : sort == 8 ? ext_sort : inode_sort); */ -: 608: #####: 609: if (tmp_files == -1) { branch 0 never executed branch 1 never executed #####: 610: fprintf(stderr, "scandir: %s: %s\n", search_path, call 0 never executed #####: 611: strerror(errno)); %%%%%: 611-block 0 call 0 never executed -: 612: #####: 613: if (xchdir(ws[cur_ws].path, NO_TITLE) == -1) call 0 never executed branch 1 never executed branch 2 never executed #####: 614: fprintf(stderr, "%s: %s: %s\n", PROGRAM_NAME, #####: 615: ws[cur_ws].path, strerror(errno)); %%%%%: 615-block 0 call 0 never executed call 1 never executed unconditional 2 never executed -: 616: #####: 617: return EXIT_FAILURE; %%%%%: 617-block 0 unconditional 0 never executed -: 618: } -: 619: } -: 620: } -: 621: -: 622: size_t i; -: 623: -: 624: /* Search for regex expression */ 2: 625: int regex_found = check_regex(comm[0] + 1); 2: 625-block 0 call 0 returned 2 -: 626: -: 627: /* If search string is just "STR" (no regex chars), change it -: 628: * to ".*STR.*" */ 2: 629: if (regex_found == EXIT_FAILURE) { branch 0 taken 0 (fallthrough) branch 1 taken 2 #####: 630: size_t search_str_len = strlen(comm[0]); -: 631: #####: 632: comm[0] = (char *)xrealloc(comm[0], (search_str_len + 5) * %%%%%: 632-block 0 call 0 never executed -: 633: sizeof(char)); -: 634: #####: 635: char *tmp_str = (char *)xnmalloc(search_str_len + 1, sizeof(char)); call 0 never executed -: 636: #####: 637: strcpy(tmp_str, comm[0] + (invert ? 2 : 1)); branch 0 never executed branch 1 never executed %%%%%: 637-block 0 unconditional 2 never executed %%%%%: 637-block 1 unconditional 3 never executed -: 638: #####: 639: *comm[0] = '.'; #####: 640: *(comm[0] + 1) = '*'; #####: 641: *(comm[0] + 2) = '\0'; #####: 642: strcat(comm[0], tmp_str); #####: 643: free(tmp_str); #####: 644: *(comm[0] + search_str_len + 1) = '.'; #####: 645: *(comm[0] + search_str_len + 2) = '*'; #####: 646: *(comm[0] + search_str_len + 3) = '\0'; #####: 647: search_str = comm[0]; %%%%%: 647-block 0 unconditional 0 never executed -: 648: } -: 649: -: 650: else 2: 651: search_str = comm[0] + (invert ? 2 : 1); 2: 651-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 1 1: 651-block 1 unconditional 2 taken 1 1: 651-block 2 unconditional 3 taken 1 2: 651-block 3 unconditional 4 taken 2 -: 652: -: 653: /* Get matches, if any, using regular expressions */ -: 654: regex_t regex_files; 2: 655: int ret = regcomp(®ex_files, search_str, REG_NOSUB | REG_EXTENDED); 2: 655-block 0 call 0 returned 2 -: 656: 2: 657: if (ret != EXIT_SUCCESS) { branch 0 taken 0 (fallthrough) branch 1 taken 2 #####: 658: fprintf(stderr, _("'%s': Invalid regular expression\n"), search_str); %%%%%: 658-block 0 call 0 never executed call 1 never executed -: 659: #####: 660: regfree(®ex_files); call 0 never executed -: 661: #####: 662: if (search_path) { branch 0 never executed branch 1 never executed #####: 663: for (i = 0; i < (size_t)tmp_files; i++) %%%%%: 663-block 0 unconditional 0 never executed %%%%%: 663-block 1 branch 1 never executed branch 2 never executed #####: 664: free(reg_dirlist[i]); %%%%%: 664-block 0 unconditional 0 never executed -: 665: #####: 666: free(reg_dirlist); -: 667: #####: 668: if (xchdir(ws[cur_ws].path, NO_TITLE) == -1) %%%%%: 668-block 0 call 0 never executed branch 1 never executed branch 2 never executed #####: 669: fprintf(stderr, "%s: %s: %s\n", PROGRAM_NAME, #####: 670: ws[cur_ws].path, strerror(errno)); %%%%%: 670-block 0 call 0 never executed call 1 never executed unconditional 2 never executed -: 671: } -: 672: #####: 673: return EXIT_FAILURE; %%%%%: 673-block 0 unconditional 0 never executed -: 674: } -: 675: 2: 676: size_t found = 0; 4*: 677: int *regex_index = (int *)xnmalloc((search_path ? (size_t)tmp_files 2: 677-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 2 %%%%%: 677-block 1 unconditional 2 never executed 2: 677-block 2 call 3 returned 2 2: 678: : files) + 2: 678-block 0 unconditional 0 taken 2 -: 679: 1, -: 680: sizeof(int)); -: 681: 12*: 682: for (i = 0; i < (search_path ? (size_t)tmp_files : files); i++) { unconditional 0 taken 2 10: 682-block 0 unconditional 1 taken 10 12: 682-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 12 %%%%%: 682-block 2 unconditional 4 never executed 12: 682-block 3 unconditional 5 taken 12 12: 682-block 4 branch 6 taken 10 branch 7 taken 2 (fallthrough) 20*: 683: if (regexec(®ex_files, (search_path ? reg_dirlist[i]->d_name 10: 683-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 10 %%%%%: 683-block 1 unconditional 2 never executed 10: 683-block 2 call 3 returned 10 branch 4 taken 2 (fallthrough) branch 5 taken 8 10: 684: : file_info[i].name), 0, NULL, 0) == EXIT_SUCCESS) { 10: 684-block 0 unconditional 0 taken 10 2: 685: if (!invert) 2: 685-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 1 1: 686: regex_index[found++] = (int)i; 1: 686-block 0 unconditional 0 taken 1 8: 687: } else if (invert) 8: 687-block 0 branch 0 taken 4 (fallthrough) branch 1 taken 4 4: 688: regex_index[found++] = (int)i; 4: 688-block 0 unconditional 0 taken 4 -: 689: } -: 690: 2: 691: regfree(®ex_files); 2: 691-block 0 call 0 returned 2 -: 692: 2: 693: if (!found) { branch 0 taken 0 (fallthrough) branch 1 taken 2 #####: 694: fprintf(stderr, _("No matches found\n")); %%%%%: 694-block 0 call 0 never executed call 1 never executed #####: 695: free(regex_index); -: 696: #####: 697: if (search_path) { branch 0 never executed branch 1 never executed -: 698: #####: 699: int j = tmp_files; #####: 700: while (--j >= 0) %%%%%: 700-block 0 unconditional 0 never executed %%%%%: 700-block 1 branch 1 never executed branch 2 never executed #####: 701: free(reg_dirlist[j]); %%%%%: 701-block 0 unconditional 0 never executed -: 702: #####: 703: free(reg_dirlist); -: 704: #####: 705: if (xchdir(ws[cur_ws].path, NO_TITLE) == -1) %%%%%: 705-block 0 call 0 never executed branch 1 never executed branch 2 never executed #####: 706: fprintf(stderr, "%s: %s: %s\n", PROGRAM_NAME, #####: 707: ws[cur_ws].path, strerror(errno)); %%%%%: 707-block 0 call 0 never executed call 1 never executed unconditional 2 never executed -: 708: } -: 709: #####: 710: return EXIT_FAILURE; %%%%%: 710-block 0 unconditional 0 never executed -: 711: } -: 712: -: 713: /* We have matches */ 2: 714: size_t flongest = 0, 2: 715: type_ok = 0; -: 716: 2: 717: size_t *files_len = (size_t *)xnmalloc(found + 1, sizeof(size_t)); 2: 717-block 0 call 0 returned 2 2: 718: int *match_type = (int *)xnmalloc(found + 1, sizeof(int)); call 0 returned 2 -: 719: -: 720: /* Get the longest file name in the list */ 2: 721: int j = (int)found; 7: 722: while (--j >= 0) { unconditional 0 taken 2 7: 722-block 0 branch 1 taken 5 branch 2 taken 2 (fallthrough) -: 723: -: 724: /* Simply skip all files not matching file_type */ 5: 725: if (file_type) { 5: 725-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 5 -: 726: #####: 727: match_type[j] = 0; -: 728: #####: 729: if (search_path) { %%%%%: 729-block 0 branch 0 never executed branch 1 never executed -: 730:#if !defined(_DIRENT_HAVE_D_TYPE) -: 731: mode_t type; -: 732: struct stat attr; -: 733: if (lstat(reg_dirlist[regex_index[j]]->d_name, &attr) == -1) -: 734: continue; -: 735: switch (attr.st_mode & S_IFMT) { -: 736: case S_IFBLK: type = DT_BLK; break; -: 737: case S_IFCHR: type = DT_CHR; break; -: 738: case S_IFDIR: type = DT_DIR; break; -: 739: case S_IFIFO: type = DT_FIFO; break; -: 740: case S_IFLNK: type = DT_LNK; break; -: 741: case S_IFREG: type = DT_REG; break; -: 742: case S_IFSOCK: type = DT_SOCK; break; -: 743: default: type = DT_UNKNOWN; break; -: 744: } -: 745: if (type != file_type) -: 746:#else #####: 747: if (reg_dirlist[regex_index[j]]->d_type != file_type) %%%%%: 747-block 0 branch 0 never executed branch 1 never executed -: 748:#endif #####: 749: continue; %%%%%: 749-block 0 unconditional 0 never executed #####: 750: } else if (file_info[regex_index[j]].type != file_type) { %%%%%: 750-block 0 branch 0 never executed branch 1 never executed #####: 751: continue; %%%%%: 751-block 0 unconditional 0 never executed -: 752: } -: 753: } -: 754: -: 755: /* Amount of non-filtered files */ 5: 756: type_ok++; -: 757: /* Index of each non-filtered files */ 5: 758: match_type[j] = 1; -: 759: -: 760: /* If not searching in CWD, we only need to know the file's -: 761: * length (no ELN) */ 5: 762: if (search_path) { 5: 762-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 5 #####: 763: files_len[j] = unicode ? wc_xstrlen( #####: 764: reg_dirlist[regex_index[j]]->d_name) %%%%%: 764-block 0 call 0 never executed unconditional 1 never executed #####: 765: : strlen(reg_dirlist[regex_index[j]]->d_name); %%%%%: 765-block 0 branch 0 never executed branch 1 never executed %%%%%: 765-block 1 unconditional 2 never executed -: 766: #####: 767: if (files_len[j] > flongest) %%%%%: 767-block 0 branch 0 never executed branch 1 never executed #####: 768: flongest = files_len[j]; %%%%%: 768-block 0 unconditional 0 never executed -: 769: } -: 770: -: 771: /* If searching in CWD, take into account the file's ELN -: 772: * when calculating its legnth */ -: 773: else { 10: 774: files_len[j] = file_info[regex_index[j]].len 5*: 775: + (size_t)DIGINUM(regex_index[j] + 1) + 1; 5: 775-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 5 %%%%%: 775-block 1 branch 2 never executed branch 3 never executed %%%%%: 775-block 2 branch 4 never executed branch 5 never executed %%%%%: 775-block 3 branch 6 never executed branch 7 never executed %%%%%: 775-block 4 branch 8 never executed branch 9 never executed %%%%%: 775-block 5 branch 10 never executed branch 11 never executed %%%%%: 775-block 6 branch 12 never executed branch 13 never executed %%%%%: 775-block 7 branch 14 never executed branch 15 never executed %%%%%: 775-block 8 branch 16 never executed branch 17 never executed %%%%%: 775-block 9 unconditional 18 never executed %%%%%: 775-block 10 unconditional 19 never executed %%%%%: 775-block 11 unconditional 20 never executed %%%%%: 775-block 12 unconditional 21 never executed %%%%%: 775-block 13 unconditional 22 never executed %%%%%: 775-block 14 unconditional 23 never executed %%%%%: 775-block 15 unconditional 24 never executed %%%%%: 775-block 16 unconditional 25 never executed %%%%%: 775-block 17 unconditional 26 never executed %%%%%: 775-block 18 unconditional 27 never executed %%%%%: 775-block 19 unconditional 28 never executed %%%%%: 775-block 20 unconditional 29 never executed %%%%%: 775-block 21 unconditional 30 never executed %%%%%: 775-block 22 unconditional 31 never executed %%%%%: 775-block 23 unconditional 32 never executed %%%%%: 775-block 24 unconditional 33 never executed %%%%%: 775-block 25 unconditional 34 never executed 5: 775-block 26 unconditional 35 taken 5 -: 776: 5: 777: if (files_len[j] > flongest) 5: 777-block 0 branch 0 taken 3 (fallthrough) branch 1 taken 2 3: 778: flongest = files_len[j]; 3: 778-block 0 unconditional 0 taken 3 -: 779: } -: 780: } -: 781: 2: 782: if (type_ok) { 2: 782-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 0 -: 783: 2: 784: int last_column = 0; 2: 785: size_t total_cols = 0; -: 786: -: 787: struct winsize w; 2: 788: ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); 2: 788-block 0 call 0 returned 2 2: 789: unsigned short terminal_cols = w.ws_col; -: 790: 2: 791: if (flongest == 0 || flongest > terminal_cols) branch 0 taken 2 (fallthrough) branch 1 taken 0 2: 791-block 0 branch 2 taken 0 (fallthrough) branch 3 taken 2 #####: 792: total_cols = 1; %%%%%: 792-block 0 unconditional 0 never executed -: 793: else 2: 794: total_cols = (size_t)terminal_cols / (flongest + 1); 2: 794-block 0 unconditional 0 taken 2 -: 795: 2: 796: if (total_cols > type_ok) 2: 796-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 0 2: 797: total_cols = type_ok; 2: 797-block 0 unconditional 0 taken 2 -: 798: -: 799: /* cur_col: Current columns number */ 2: 800: size_t cur_col = 0, 2: 801: counter = 0; -: 802: 7: 803: for (i = 0; i < found; i++) { 2: 803-block 0 unconditional 0 taken 2 5: 803-block 1 unconditional 1 taken 5 7: 803-block 2 branch 2 taken 5 branch 3 taken 2 (fallthrough) -: 804: 5*: 805: if (match_type[i] == 0) 5: 805-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 5 #####: 806: continue; %%%%%: 806-block 0 unconditional 0 never executed -: 807: -: 808: /* Print the results using colors and columns */ 5: 809: cur_col++; -: 810: -: 811: /* If the current file is in the last column or is the last -: 812: * listed file, we need to print no pad and a newline char. -: 813: * Else, print the corresponding pad, to equate the longest -: 814: * file length, and no newline char */ 5: 815: if (cur_col == total_cols) { 5: 815-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 3 2: 816: last_column = 1; 2: 817: cur_col = 0; 2: 817-block 0 unconditional 0 taken 2 -: 818: } else { 3: 819: last_column = 0; 3: 819-block 0 unconditional 0 taken 3 -: 820: } -: 821: -: 822: /* Counter: Current amount of non-filtered files: if -: 823: * COUNTER equals TYPE_OK (total amount of non-filtered -: 824: * files), we have the last file to be printed */ 5: 825: counter++; -: 826: 18*: 827: colors_list(search_path ? reg_dirlist[regex_index[i]]->d_name 5: 827-block 0 branch 0 taken 3 (fallthrough) branch 1 taken 2 3: 827-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 3 2: 827-block 2 unconditional 4 taken 2 3: 827-block 3 unconditional 5 taken 3 5: 827-block 4 branch 6 taken 3 (fallthrough) branch 7 taken 2 2: 827-block 5 unconditional 8 taken 2 5: 827-block 6 branch 9 taken 5 (fallthrough) branch 10 taken 0 %%%%%: 827-block 7 unconditional 11 never executed 5: 827-block 8 branch 12 taken 0 (fallthrough) branch 13 taken 5 %%%%%: 827-block 9 unconditional 14 never executed 5: 827-block 10 call 15 returned 5 unconditional 16 taken 5 5: 828: : file_info[regex_index[i]].name, search_path ? NO_ELN 5: 828-block 0 unconditional 0 taken 5 8: 829: : regex_index[i] + 1, (last_column || counter == type_ok) 3: 829-block 0 branch 0 taken 3 (fallthrough) branch 1 taken 0 5: 829-block 1 unconditional 2 taken 5 3: 830: ? NO_PAD : (int)(flongest - files_len[i]) + 1, 3: 830-block 0 unconditional 0 taken 3 -: 831: (last_column || counter == type_ok) ? PRINT_NEWLINE -: 832: : NO_NEWLINE); -: 833: } -: 834: 2: 835: printf(_("Matches found: %zu\n"), counter); 2: 835-block 0 call 0 returned 2 call 1 returned 2 -: 836: } -: 837: -: 838: else #####: 839: fputs(_("No matches found\n"), stderr); %%%%%: 839-block 0 call 0 never executed call 1 never executed unconditional 2 never executed -: 840: -: 841: /* Free stuff */ 2: 842: free(files_len); 2: 843: free(match_type); 2: 844: free(regex_index); 2: 845: regfree(®ex_files); 2: 845-block 0 call 0 returned 2 -: 846: -: 847: /* If needed, go back to the directory we came from */ 2: 848: if (search_path) { branch 0 taken 0 (fallthrough) branch 1 taken 2 #####: 849: j = tmp_files; #####: 850: while (--j >= 0) %%%%%: 850-block 0 unconditional 0 never executed %%%%%: 850-block 1 branch 1 never executed branch 2 never executed #####: 851: free(reg_dirlist[j]); %%%%%: 851-block 0 unconditional 0 never executed -: 852: #####: 853: free(reg_dirlist); -: 854: #####: 855: if (xchdir(ws[cur_ws].path, NO_TITLE) == -1) { %%%%%: 855-block 0 call 0 never executed branch 1 never executed branch 2 never executed #####: 856: fprintf(stderr, "%s: %s: %s\n", PROGRAM_NAME, #####: 857: ws[cur_ws].path, strerror(errno)); %%%%%: 857-block 0 call 0 never executed call 1 never executed #####: 858: return EXIT_FAILURE; unconditional 0 never executed -: 859: } -: 860: } -: 861: 2: 862: if (type_ok) 2: 862-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 0 2: 863: return EXIT_SUCCESS; 2: 863-block 0 unconditional 0 taken 2 -: 864: #####: 865: return EXIT_FAILURE; %%%%%: 865-block 0 unconditional 0 never executed -: 866:} clifm-1.26.3/misc/codecov/selection.c.gcov000066400000000000000000002021001506632037700203440ustar00rootroot00000000000000 -: 0:Source:selection.c -: 1:/* selection.c -- files selection functions */ -: 2: -: 3:/* -: 4: * This file is part of CliFM -: 5: * -: 6: * Copyright (C) 2016-2021, L. Abramovich -: 7: * All rights reserved. -: 8: -: 9: * CliFM is free software; you can redistribute it and/or modify -: 10: * it under the terms of the GNU General Public License as published by -: 11: * the Free Software Foundation; either version 2 of the License, or -: 12: * (at your option) any later version. -: 13: * -: 14: * CliFM is distributed in the hope that it will be useful, -: 15: * but WITHOUT ANY WARRANTY; without even the implied warranty of -: 16: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -: 17: * GNU General Public License for more details. -: 18: * -: 19: * You should have received a copy of the GNU General Public License -: 20: * along with this program; if not, write to the Free Software -: 21: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, -: 22: * MA 02110-1301, USA. -: 23:*/ -: 24: -: 25:#include "helpers.h" -: 26: -: 27:#include -: 28:#include -: 29:#include -: 30:#include -: 31:#include -: 32:#include -: 33:#include -: 34:#include -: 35:#include -: 36:#if defined(__linux__) || defined(__HAIKU__) -: 37:#ifdef __TINYC__ -: 38:/* Silence a tcc warning. We don't use CTRL anyway */ -: 39:#undef CTRL -: 40:#endif -: 41:#include -: 42:#endif -: 43: -: 44:#include "aux.h" -: 45:#include "checks.h" -: 46:#include "colors.h" -: 47:#include "listing.h" -: 48:#include "misc.h" -: 49:#include "navigation.h" -: 50:#include "readline.h" -: 51:#include "selection.h" -: 52:#include "sort.h" -: 53:#include "messages.h" -: 54: -: 55:/* Save selected elements into a tmp file. Returns 1 if success and 0 -: 56: * if error. This function allows the user to work with multiple -: 57: * instances of the program: he/she can select some files in the -: 58: * first instance and then execute a second one to operate on those -: 59: * files as he/she whises. */ -: 60:int function save_sel called 27 returned 100% blocks executed 70% 27: 61:save_sel(void) -: 62:{ 27: 63: if (!selfile_ok || !config_ok) 27: 63-block 0 branch 0 taken 27 (fallthrough) branch 1 taken 0 27: 63-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 27 #####: 64: return EXIT_FAILURE; %%%%%: 64-block 0 unconditional 0 never executed -: 65: 27: 66: if (sel_n == 0) { 27: 66-block 0 branch 0 taken 12 (fallthrough) branch 1 taken 15 12: 67: if (unlink(sel_file) == -1) { 12: 67-block 0 call 0 returned 12 branch 1 taken 0 (fallthrough) branch 2 taken 12 #####: 68: fprintf(stderr, "%s: sel: %s: %s\n", PROGRAM_NAME, call 0 never executed #####: 69: sel_file, strerror(errno)); %%%%%: 69-block 0 call 0 never executed #####: 70: return EXIT_FAILURE; unconditional 0 never executed -: 71: } else { 12: 72: return EXIT_SUCCESS; 12: 72-block 0 unconditional 0 taken 12 -: 73: } -: 74: } -: 75: 15: 76: FILE *sel_fp = fopen(sel_file, "w"); 15: 76-block 0 call 0 returned 15 -: 77: 15: 78: if (!sel_fp) { branch 0 taken 0 (fallthrough) branch 1 taken 15 #####: 79: _err(0, NOPRINT_PROMPT, "%s: sel: %s: %s\n", PROGRAM_NAME, call 0 never executed #####: 80: sel_file, strerror(errno)); %%%%%: 80-block 0 call 0 never executed #####: 81: return EXIT_FAILURE; unconditional 0 never executed -: 82: } -: 83: -: 84: size_t i; 57: 85: for (i = 0; i < sel_n; i++) { 15: 85-block 0 unconditional 0 taken 15 unconditional 1 taken 42 57: 85-block 1 branch 2 taken 42 branch 3 taken 15 (fallthrough) 42: 86: fputs(sel_elements[i], sel_fp); 42: 86-block 0 call 0 returned 42 42: 87: fputc('\n', sel_fp); call 0 returned 42 -: 88: } -: 89: 15: 90: fclose(sel_fp); 15: 90-block 0 call 0 returned 15 15: 91: return EXIT_SUCCESS; unconditional 0 taken 15 -: 92:} -: 93: -: 94:static int function select_file called 38 returned 100% blocks executed 94% 38: 95:select_file(char *file) -: 96:{ 38: 97: if (!file || !*file) 38: 97-block 0 branch 0 taken 38 (fallthrough) branch 1 taken 0 38: 97-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 38 #####: 98: return 0; %%%%%: 98-block 0 unconditional 0 never executed -: 99: -: 100: /* Check if the selected element is already in the selection -: 101: * box */ 38: 102: int exists = 0, new_sel = 0, j; -: 103: 38: 104: j = (int)sel_n; 91: 105: while (--j >= 0) { 38: 105-block 0 unconditional 0 taken 38 91: 105-block 1 branch 1 taken 55 branch 2 taken 36 (fallthrough) 55: 106: if (*file == *sel_elements[j] && strcmp(sel_elements[j], file) == 0) { 55: 106-block 0 branch 0 taken 55 (fallthrough) branch 1 taken 0 55: 106-block 1 branch 2 taken 2 (fallthrough) branch 3 taken 53 2: 107: exists = 1; 2: 108: break; 2: 108-block 0 unconditional 0 taken 2 -: 109: } -: 110: } -: 111: 38: 112: if (!exists) { 38: 112-block 0 branch 0 taken 36 (fallthrough) branch 1 taken 2 36: 113: sel_elements = (char **)xrealloc(sel_elements, (sel_n + 2) 36: 113-block 0 call 0 returned 36 -: 114: * sizeof(char *)); 36: 115: sel_elements[sel_n++] = savestring(file, strlen(file)); call 0 returned 36 36: 116: sel_elements[sel_n] = (char *)NULL; 36: 117: new_sel++; unconditional 0 taken 36 -: 118: } else { 2: 119: fprintf(stderr, _("%s: sel: %s: Already selected\n"), 2: 119-block 0 call 0 returned 2 call 1 returned 2 unconditional 2 taken 2 -: 120: PROGRAM_NAME, file); -: 121: } -: 122: 38: 123: return new_sel; 38: 123-block 0 unconditional 0 taken 38 -: 124:} -: 125: -: 126:static int function sel_glob called 7 returned 100% blocks executed 43% 7: 127:sel_glob(char *str, const char *sel_path, mode_t filetype) -: 128:{ 7: 129: if (!str || !*str) 7: 129-block 0 branch 0 taken 7 (fallthrough) branch 1 taken 0 7: 129-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 7 #####: 130: return -1; %%%%%: 130-block 0 unconditional 0 never executed -: 131: -: 132: glob_t gbuf; 7: 133: char *pattern = str; 7: 134: int invert = 0, ret = -1; -: 135: 7: 136: if (*pattern == '!') { 7: 136-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 7 #####: 137: pattern++; #####: 138: invert = 1; %%%%%: 138-block 0 unconditional 0 never executed -: 139: } -: 140: 7: 141: ret = glob(pattern, 0, NULL, &gbuf); 7: 141-block 0 call 0 returned 7 -: 142: 7: 143: if (ret == GLOB_NOSPACE || ret == GLOB_ABORTED) { branch 0 taken 7 (fallthrough) branch 1 taken 0 7: 143-block 0 branch 2 taken 0 (fallthrough) branch 3 taken 7 #####: 144: globfree(&gbuf); %%%%%: 144-block 0 call 0 never executed #####: 145: return -1; unconditional 0 never executed -: 146: } -: 147: 7: 148: if (ret == GLOB_NOMATCH) { 7: 148-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 6 1: 149: globfree(&gbuf); 1: 149-block 0 call 0 returned 1 1: 150: return 0; unconditional 0 taken 1 -: 151: } -: 152: 6: 153: char **matches = (char **)NULL; 6: 154: int i, k = 0; 6: 155: struct dirent **ent = (struct dirent **)NULL; -: 156: 6: 157: if (invert) { 6: 157-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 6 #####: 158: if (!sel_path) { %%%%%: 158-block 0 branch 0 never executed branch 1 never executed #####: 159: matches = (char **)xnmalloc(files + 2, sizeof(char *)); %%%%%: 159-block 0 call 0 never executed -: 160: #####: 161: i = (int)files; #####: 162: while (--i >= 0) { unconditional 0 never executed %%%%%: 162-block 0 branch 1 never executed branch 2 never executed #####: 163: if (filetype && file_info[i].type != filetype) %%%%%: 163-block 0 branch 0 never executed branch 1 never executed %%%%%: 163-block 1 branch 2 never executed branch 3 never executed #####: 164: continue; %%%%%: 164-block 0 unconditional 0 never executed -: 165: #####: 166: int found = 0; #####: 167: int j = (int)gbuf.gl_pathc; #####: 168: while (--j >= 0) { %%%%%: 168-block 0 unconditional 0 never executed %%%%%: 168-block 1 branch 1 never executed branch 2 never executed #####: 169: if (*file_info[i].name == *gbuf.gl_pathv[j] %%%%%: 169-block 0 branch 0 never executed branch 1 never executed #####: 170: && strcmp(file_info[i].name, gbuf.gl_pathv[j]) == 0) { %%%%%: 170-block 0 branch 0 never executed branch 1 never executed #####: 171: found = 1; #####: 172: break; %%%%%: 172-block 0 unconditional 0 never executed -: 173: } -: 174: } -: 175: #####: 176: if (!found) %%%%%: 176-block 0 branch 0 never executed branch 1 never executed #####: 177: matches[k++] = file_info[i].name; %%%%%: 177-block 0 unconditional 0 never executed -: 178: } -: 179: } else { #####: 180: ret = scandir(sel_path, &ent, skip_files, xalphasort); %%%%%: 180-block 0 call 0 never executed #####: 181: if (ret == -1) { branch 0 never executed branch 1 never executed #####: 182: fprintf(stderr, "%s: %s: %s\n", PROGRAM_NAME, call 0 never executed #####: 183: sel_path, strerror(errno)); %%%%%: 183-block 0 call 0 never executed #####: 184: globfree(&gbuf); call 0 never executed #####: 185: return -1; unconditional 0 never executed -: 186: } -: 187: #####: 188: matches = (char **)xnmalloc((size_t)ret + 2, sizeof(char *)); %%%%%: 188-block 0 call 0 never executed -: 189: #####: 190: i = ret; #####: 191: while (--i >= 0) { unconditional 0 never executed %%%%%: 191-block 0 branch 1 never executed branch 2 never executed -: 192:#if !defined(_DIRENT_HAVE_D_TYPE) -: 193: mode_t type; -: 194: struct stat attr; -: 195: if (lstat(ent[i]->d_name, &attr) == -1) -: 196: continue; -: 197: switch (attr.st_mode & S_IFMT) { -: 198: case S_IFBLK: type = DT_BLK; break; -: 199: case S_IFCHR: type = DT_CHR; break; -: 200: case S_IFDIR: type = DT_DIR; break; -: 201: case S_IFIFO: type = DT_FIFO; break; -: 202: case S_IFLNK: type = DT_LNK; break; -: 203: case S_IFREG: type = DT_REG; break; -: 204: case S_IFSOCK: type = DT_SOCK; break; -: 205: default: type = DT_UNKNOWN; break; -: 206: } -: 207: if (filetype && type != filetype) -: 208:#else #####: 209: if (filetype && ent[i]->d_type != filetype) %%%%%: 209-block 0 branch 0 never executed branch 1 never executed %%%%%: 209-block 1 branch 2 never executed branch 3 never executed -: 210:#endif #####: 211: continue; %%%%%: 211-block 0 unconditional 0 never executed -: 212: #####: 213: int j = (int)gbuf.gl_pathc; #####: 214: while (--j >= 0) { %%%%%: 214-block 0 unconditional 0 never executed %%%%%: 214-block 1 branch 1 never executed branch 2 never executed #####: 215: if (*ent[i]->d_name == *gbuf.gl_pathv[j] %%%%%: 215-block 0 branch 0 never executed branch 1 never executed #####: 216: && strcmp(ent[i]->d_name, gbuf.gl_pathv[j]) == 0) %%%%%: 216-block 0 branch 0 never executed branch 1 never executed #####: 217: break; %%%%%: 217-block 0 unconditional 0 never executed -: 218: } -: 219: #####: 220: if (!gbuf.gl_pathv[j]) %%%%%: 220-block 0 branch 0 never executed branch 1 never executed #####: 221: matches[k++] = ent[i]->d_name; %%%%%: 221-block 0 unconditional 0 never executed -: 222: } -: 223: } -: 224: } -: 225: -: 226: else { 6: 227: matches = (char **)xnmalloc(gbuf.gl_pathc + 2, 6: 227-block 0 call 0 returned 6 -: 228: sizeof(char *)); 6: 229: mode_t t = 0; 6: 230: if (filetype) { branch 0 taken 2 (fallthrough) branch 1 taken 4 -: 231: 2: 232: switch (filetype) { 2: 232-block 0 branch 0 taken 2 branch 1 taken 0 branch 2 taken 0 branch 3 taken 0 branch 4 taken 0 branch 5 taken 0 branch 6 taken 0 branch 7 taken 0 2: 233: case DT_DIR: t = S_IFDIR; break; 2: 233-block 0 unconditional 0 taken 2 #####: 234: case DT_REG: t = S_IFREG; break; %%%%%: 234-block 0 unconditional 0 never executed #####: 235: case DT_LNK: t = S_IFLNK; break; %%%%%: 235-block 0 unconditional 0 never executed #####: 236: case DT_SOCK: t = S_IFSOCK; break; %%%%%: 236-block 0 unconditional 0 never executed #####: 237: case DT_FIFO: t = S_IFIFO; break; %%%%%: 237-block 0 unconditional 0 never executed #####: 238: case DT_BLK: t = S_IFBLK; break; %%%%%: 238-block 0 unconditional 0 never executed #####: 239: case DT_CHR: t = S_IFCHR; break; %%%%%: 239-block 0 unconditional 0 never executed -: 240: } -: 241: } -: 242: 6: 243: i = (int)gbuf.gl_pathc; 26: 244: while (--i >= 0) { 6: 244-block 0 unconditional 0 taken 6 26: 244-block 1 branch 1 taken 20 branch 2 taken 6 (fallthrough) -: 245: /* We need to run stat(3) here, so that the d_type macros -: 246: * won't work: convert them into st_mode macros */ 20: 247: if (filetype) { 20: 247-block 0 branch 0 taken 6 (fallthrough) branch 1 taken 14 -: 248: struct stat attr; 6*: 249: if (lstat(gbuf.gl_pathv[i], &attr) == -1) 6: 249-block 0 call 0 returned 6 branch 1 taken 0 (fallthrough) branch 2 taken 6 2*: 250: continue; %%%%%: 250-block 0 unconditional 0 never executed 2: 250-block 1 unconditional 1 taken 2 6: 251: if ((attr.st_mode & S_IFMT) != t) 6: 251-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 4 2: 252: continue; 2: 252-block 0 unconditional 0 taken 2 -: 253: } -: 254: 18*: 255: if (*gbuf.gl_pathv[i] == '.' && (!gbuf.gl_pathv[i][1] 18: 255-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 18 %%%%%: 255-block 1 branch 2 never executed branch 3 never executed #####: 256: || (gbuf.gl_pathv[i][1] == '.' && !gbuf.gl_pathv[i][2]))) %%%%%: 256-block 0 branch 0 never executed branch 1 never executed %%%%%: 256-block 1 branch 2 never executed branch 3 never executed #####: 257: continue; %%%%%: 257-block 0 unconditional 0 never executed -: 258: 18: 259: matches[k++] = gbuf.gl_pathv[i]; 18: 259-block 0 unconditional 0 taken 18 -: 260: } -: 261: } -: 262: 6: 263: matches[k] = (char *)NULL; 6: 264: int new_sel = 0; -: 265: 6: 266: i = k; 24: 267: while (--i >= 0) { 6: 267-block 0 unconditional 0 taken 6 24: 267-block 1 branch 1 taken 18 branch 2 taken 6 (fallthrough) 18*: 268: if (!matches[i]) 18: 268-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 18 #####: 269: continue; %%%%%: 269-block 0 unconditional 0 never executed -: 270: 18: 271: if (!sel_path) { 18: 271-block 0 branch 0 taken 11 (fallthrough) branch 1 taken 7 11: 272: if (*matches[i] == '/') { 11: 272-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 11 #####: 273: new_sel += select_file(matches[i]); %%%%%: 273-block 0 call 0 never executed unconditional 1 never executed -: 274: } else { 11: 275: char *tmp = (char *)NULL; 11: 276: if (*ws[cur_ws].path == '/' && !*(ws[cur_ws].path + 1)) { 11: 276-block 0 branch 0 taken 11 (fallthrough) branch 1 taken 0 11: 276-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 11 #####: 277: tmp = (char *)xnmalloc(strlen(matches[i]) + 2, %%%%%: 277-block 0 call 0 never executed -: 278: sizeof(char)); #####: 279: sprintf(tmp, "/%s", matches[i]); unconditional 0 never executed -: 280: } else { 11: 281: tmp = (char *)xnmalloc(strlen(ws[cur_ws].path) 11: 282: + strlen(matches[i]) + 2, sizeof(char)); 11: 282-block 0 call 0 returned 11 11: 283: sprintf(tmp, "%s/%s", ws[cur_ws].path, matches[i]); unconditional 0 taken 11 -: 284: } 11: 285: new_sel += select_file(tmp); 11: 285-block 0 call 0 returned 11 11: 286: free(tmp); unconditional 0 taken 11 -: 287: } -: 288: } else { 7: 289: char *tmp = (char *)xnmalloc(strlen(sel_path) 7: 290: + strlen(matches[i]) + 2, sizeof(char)); 7: 290-block 0 call 0 returned 7 7: 291: sprintf(tmp, "%s/%s", sel_path, matches[i]); 7: 292: new_sel += select_file(tmp); call 0 returned 7 7: 293: free(tmp); unconditional 0 taken 7 -: 294: } -: 295: } -: 296: 6: 297: free(matches); 6: 298: globfree(&gbuf); 6: 298-block 0 call 0 returned 6 -: 299: 6*: 300: if (invert && sel_path) { branch 0 taken 0 (fallthrough) branch 1 taken 6 %%%%%: 300-block 0 branch 2 never executed branch 3 never executed #####: 301: i = ret; #####: 302: while (--i >= 0) %%%%%: 302-block 0 unconditional 0 never executed %%%%%: 302-block 1 branch 1 never executed branch 2 never executed #####: 303: free(ent[i]); %%%%%: 303-block 0 unconditional 0 never executed #####: 304: free(ent); %%%%%: 304-block 0 unconditional 0 never executed -: 305: } -: 306: 6: 307: return new_sel; 6: 307-block 0 unconditional 0 taken 6 -: 308:} -: 309: -: 310:static int function sel_regex called 2 returned 100% blocks executed 39% 2: 311:sel_regex(char *str, const char *sel_path, mode_t filetype) -: 312:{ 2: 313: if (!str || !*str) 2: 313-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 0 2: 313-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 2 #####: 314: return -1; %%%%%: 314-block 0 unconditional 0 never executed -: 315: 2: 316: char *pattern = str; -: 317: 2: 318: int invert = 0; 2: 319: if (*pattern == '!') { 2: 319-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 2 #####: 320: pattern++; #####: 321: invert = 1; %%%%%: 321-block 0 unconditional 0 never executed -: 322: } -: 323: -: 324: regex_t regex; 2: 325: if (regcomp(®ex, pattern, REG_NOSUB | REG_EXTENDED) != EXIT_SUCCESS) { 2: 325-block 0 call 0 returned 2 branch 1 taken 1 (fallthrough) branch 2 taken 1 1: 326: fprintf(stderr, _("%s: sel: %s: Invalid regular " 1: 326-block 0 call 0 returned 1 call 1 returned 1 -: 327: "expression\n"), PROGRAM_NAME, str); -: 328: 1: 329: regfree(®ex); call 0 returned 1 1: 330: return -1; unconditional 0 taken 1 -: 331: } -: 332: 1: 333: int new_sel = 0, i; -: 334: 1: 335: if (!sel_path) { /* Check pattern (STR) against files in CWD */ 1: 335-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 0 1: 336: i = (int)files; 8: 337: while (--i >= 0) { 1: 337-block 0 unconditional 0 taken 1 8: 337-block 1 branch 1 taken 7 branch 2 taken 1 7*: 338: if (filetype && file_info[i].type != filetype) 7: 338-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 7 %%%%%: 338-block 1 branch 2 never executed branch 3 never executed #####: 339: continue; %%%%%: 339-block 0 unconditional 0 never executed -: 340: -: 341: char tmp_path[PATH_MAX]; 7: 342: if (*ws[cur_ws].path == '/' && !*(ws[cur_ws].path + 1)) { 7: 342-block 0 branch 0 taken 7 (fallthrough) branch 1 taken 0 7: 342-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 7 #####: 343: snprintf(tmp_path, PATH_MAX - 1, "/%s", file_info[i].name); %%%%%: 343-block 0 unconditional 0 never executed -: 344: } else { 7: 345: snprintf(tmp_path, PATH_MAX - 1, "%s/%s", ws[cur_ws].path, 7: 346: file_info[i].name); 7: 346-block 0 unconditional 0 taken 7 -: 347: } -: 348: 7: 349: if (regexec(®ex, file_info[i].name, 0, NULL, 0) == EXIT_SUCCESS) { 7: 349-block 0 call 0 returned 7 branch 1 taken 7 (fallthrough) branch 2 taken 0 7: 350: if (!invert) 7: 350-block 0 branch 0 taken 7 (fallthrough) branch 1 taken 0 7: 351: new_sel += select_file(tmp_path); 7: 351-block 0 call 0 returned 7 unconditional 1 taken 7 #####: 352: } else if (invert) { %%%%%: 352-block 0 branch 0 never executed branch 1 never executed #####: 353: new_sel += select_file(tmp_path); %%%%%: 353-block 0 call 0 never executed unconditional 1 never executed -: 354: } -: 355: } -: 356: } else { /* Check pattern against files in SEL_PATH */ #####: 357: struct dirent **list = (struct dirent **)NULL; #####: 358: int filesn = scandir(sel_path, &list, skip_files, xalphasort); %%%%%: 358-block 0 call 0 never executed -: 359: #####: 360: if (filesn == -1) { branch 0 never executed branch 1 never executed #####: 361: fprintf(stderr, "sel: %s: %s\n", sel_path, strerror(errno)); %%%%%: 361-block 0 call 0 never executed call 1 never executed #####: 362: return -1; unconditional 0 never executed -: 363: } -: 364: #####: 365: mode_t t = 0; #####: 366: if (filetype) { %%%%%: 366-block 0 branch 0 never executed branch 1 never executed -: 367: #####: 368: switch (filetype) { %%%%%: 368-block 0 branch 0 never executed branch 1 never executed branch 2 never executed branch 3 never executed branch 4 never executed branch 5 never executed branch 6 never executed branch 7 never executed #####: 369: case DT_DIR: t = S_IFDIR; break; %%%%%: 369-block 0 unconditional 0 never executed #####: 370: case DT_REG: t = S_IFREG; break; %%%%%: 370-block 0 unconditional 0 never executed #####: 371: case DT_LNK: t = S_IFLNK; break; %%%%%: 371-block 0 unconditional 0 never executed #####: 372: case DT_SOCK: t = S_IFSOCK; break; %%%%%: 372-block 0 unconditional 0 never executed #####: 373: case DT_FIFO: t = S_IFIFO; break; %%%%%: 373-block 0 unconditional 0 never executed #####: 374: case DT_BLK: t = S_IFBLK; break; %%%%%: 374-block 0 unconditional 0 never executed #####: 375: case DT_CHR: t = S_IFCHR; break; %%%%%: 375-block 0 unconditional 0 never executed -: 376: } -: 377: } -: 378: #####: 379: i = (int)filesn; #####: 380: while (--i >= 0) { %%%%%: 380-block 0 unconditional 0 never executed %%%%%: 380-block 1 branch 1 never executed branch 2 never executed #####: 381: if (filetype) { %%%%%: 381-block 0 branch 0 never executed branch 1 never executed -: 382: struct stat attr; #####: 383: if (lstat(list[i]->d_name, &attr) != -1) { %%%%%: 383-block 0 call 0 never executed branch 1 never executed branch 2 never executed #####: 384: if ((attr.st_mode & S_IFMT) != t) { %%%%%: 384-block 0 branch 0 never executed branch 1 never executed #####: 385: free(list[i]); #####: 386: continue; %%%%%: 386-block 0 unconditional 0 never executed -: 387: } -: 388: } -: 389: } -: 390: #####: 391: char *tmp_path = (char *)xnmalloc(strlen(sel_path) #####: 392: + strlen(list[i]->d_name) + 2, sizeof(char)); %%%%%: 392-block 0 call 0 never executed #####: 393: sprintf(tmp_path, "%s/%s", sel_path, list[i]->d_name); -: 394: #####: 395: if (regexec(®ex, list[i]->d_name, 0, NULL, 0) == EXIT_SUCCESS) { call 0 never executed branch 1 never executed branch 2 never executed #####: 396: if (!invert) %%%%%: 396-block 0 branch 0 never executed branch 1 never executed #####: 397: new_sel += select_file(tmp_path); %%%%%: 397-block 0 call 0 never executed unconditional 1 never executed #####: 398: } else if (invert) { %%%%%: 398-block 0 branch 0 never executed branch 1 never executed #####: 399: new_sel += select_file(tmp_path); %%%%%: 399-block 0 call 0 never executed unconditional 1 never executed -: 400: } -: 401: #####: 402: free(tmp_path); #####: 403: free(list[i]); %%%%%: 403-block 0 unconditional 0 never executed -: 404: } -: 405: #####: 406: free(list); %%%%%: 406-block 0 unconditional 0 never executed -: 407: } -: 408: 1: 409: regfree(®ex); 1: 409-block 0 call 0 returned 1 1: 410: return new_sel; unconditional 0 taken 1 -: 411:} -: 412: -: 413:int function sel_function called 13 returned 100% blocks executed 58% 13: 414:sel_function(char **args) -: 415:{ 13: 416: if (!args) 13: 416-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 13 #####: 417: return EXIT_FAILURE; %%%%%: 417-block 0 unconditional 0 never executed -: 418: 13*: 419: if (!args[1] || (*args[1] == '-' && args[1][1] == '-' 13: 419-block 0 branch 0 taken 13 (fallthrough) branch 1 taken 0 13: 419-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 13 %%%%%: 419-block 2 branch 4 never executed branch 5 never executed #####: 420: && strcmp(args[1], "--help") == 0)) { %%%%%: 420-block 0 branch 0 never executed branch 1 never executed #####: 421: puts(_(SEL_USAGE)); %%%%%: 421-block 0 call 0 never executed call 1 never executed #####: 422: return EXIT_SUCCESS; unconditional 0 never executed -: 423: } -: 424: 13: 425: char *sel_path = (char *)NULL; 13: 426: mode_t filetype = 0; 13: 427: int i, ifiletype = 0, isel_path = 0, new_sel = 0; -: 428: 38: 429: for (i = 1; args[i]; i++) { 13: 429-block 0 unconditional 0 taken 13 25: 429-block 1 unconditional 1 taken 25 38: 429-block 2 branch 2 taken 25 branch 3 taken 13 (fallthrough) 25: 430: if (*args[i] == '-') { 25: 430-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 23 2: 431: ifiletype = i; 2: 432: filetype = (mode_t) * (args[i] + 1); 2: 432-block 0 unconditional 0 taken 2 -: 433: } -: 434: 25: 435: if (*args[i] == ':') { 25: 435-block 0 branch 0 taken 3 (fallthrough) branch 1 taken 22 3: 436: isel_path = i; 3: 437: sel_path = args[i] + 1; 3: 437-block 0 unconditional 0 taken 3 -: 438: } -: 439: 25: 440: if (*args[i] == '~') { 25: 440-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 25 #####: 441: char *exp_path = tilde_expand(args[i]); %%%%%: 441-block 0 call 0 never executed #####: 442: if (!exp_path) { branch 0 never executed branch 1 never executed #####: 443: fprintf(stderr, "%s: %s: %s\n", PROGRAM_NAME, args[i], call 0 never executed #####: 444: strerror(errno)); %%%%%: 444-block 0 call 0 never executed #####: 445: return EXIT_FAILURE; unconditional 0 never executed -: 446: } -: 447: #####: 448: args[i] = (char *)xrealloc(args[i], (strlen(exp_path) + 1) * %%%%%: 448-block 0 call 0 never executed -: 449: sizeof(char)); #####: 450: strcpy(args[i], exp_path); #####: 451: free(exp_path); unconditional 0 never executed -: 452: } -: 453: } -: 454: 13: 455: if (filetype) { 13: 455-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 11 -: 456: /* Convert file type into a macro that can be decoded by stat(). -: 457: * If file type is specified, matches will be checked against -: 458: * this value */ 2: 459: switch (filetype) { 2: 459-block 0 branch 0 taken 2 branch 1 taken 0 branch 2 taken 0 branch 3 taken 0 branch 4 taken 0 branch 5 taken 0 branch 6 taken 0 branch 7 taken 0 2: 460: case 'd': filetype = DT_DIR; break; 2: 460-block 0 unconditional 0 taken 2 #####: 461: case 'r': filetype = DT_REG; break; %%%%%: 461-block 0 unconditional 0 never executed #####: 462: case 'l': filetype = DT_LNK; break; %%%%%: 462-block 0 unconditional 0 never executed #####: 463: case 's': filetype = DT_SOCK; break; %%%%%: 463-block 0 unconditional 0 never executed #####: 464: case 'f': filetype = DT_FIFO; break; %%%%%: 464-block 0 unconditional 0 never executed #####: 465: case 'b': filetype = DT_BLK; break; %%%%%: 465-block 0 unconditional 0 never executed #####: 466: case 'c': filetype = DT_CHR; break; %%%%%: 466-block 0 unconditional 0 never executed #####: 467: default: #####: 468: fprintf(stderr, _("%s: '%c': Unrecognized file type\n"), call 0 never executed #####: 469: PROGRAM_NAME, (char)filetype); %%%%%: 469-block 0 call 0 never executed #####: 470: return EXIT_FAILURE; unconditional 0 never executed -: 471: } -: 472: } -: 473: -: 474: char dir[PATH_MAX]; -: 475: 13: 476: if (sel_path) { 13: 476-block 0 branch 0 taken 3 (fallthrough) branch 1 taken 10 3: 477: size_t sel_path_len = strlen(sel_path); 3: 478: if (sel_path[sel_path_len - 1] == '/') 3: 478-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 3 #####: 479: sel_path[sel_path_len - 1] = '\0'; %%%%%: 479-block 0 unconditional 0 never executed -: 480: 3: 481: char *tmpdir = xnmalloc(PATH_MAX + 1, sizeof(char)); 3: 481-block 0 call 0 returned 3 -: 482: 3: 483: if (strchr(sel_path, '\\')) { branch 0 taken 0 (fallthrough) branch 1 taken 3 #####: 484: char *deq_str = dequote_str(sel_path, 0); %%%%%: 484-block 0 call 0 never executed #####: 485: if (deq_str) { branch 0 never executed branch 1 never executed #####: 486: strcpy(sel_path, deq_str); #####: 487: free(deq_str); %%%%%: 487-block 0 unconditional 0 never executed -: 488: } -: 489: } -: 490: 3: 491: strcpy(tmpdir, sel_path); -: 492: 3: 493: if (*sel_path == '.') { 3: 493-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 3 #####: 494: if (realpath(sel_path, tmpdir) == NULL) { %%%%%: 494-block 0 call 0 never executed branch 1 never executed branch 2 never executed #####: 495: fprintf(stderr, "%s: %s: %s\n", PROGRAM_NAME, sel_path, call 0 never executed #####: 496: strerror(errno)); %%%%%: 496-block 0 call 0 never executed #####: 497: return EXIT_FAILURE; unconditional 0 never executed -: 498: } -: 499: } -: 500: 3: 501: if (*sel_path == '~') { 3: 501-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 3 #####: 502: char *exp_path = tilde_expand(sel_path); %%%%%: 502-block 0 call 0 never executed #####: 503: if (!exp_path) { branch 0 never executed branch 1 never executed #####: 504: fprintf(stderr, _("%s: Error expanding path\n"), PROGRAM_NAME); %%%%%: 504-block 0 call 0 never executed call 1 never executed #####: 505: free(tmpdir); #####: 506: return EXIT_FAILURE; unconditional 0 never executed -: 507: } #####: 508: strcpy(tmpdir, exp_path); #####: 509: free(exp_path); %%%%%: 509-block 0 unconditional 0 never executed -: 510: } -: 511: 3: 512: if (*tmpdir != '/') { 3: 512-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 3 #####: 513: snprintf(dir, PATH_MAX, "%s/%s", ws[cur_ws].path, tmpdir); %%%%%: 513-block 0 unconditional 0 never executed -: 514: } else 3: 515: strcpy(dir, tmpdir); 3: 515-block 0 unconditional 0 taken 3 -: 516: 3: 517: free(tmpdir); -: 518: 3: 519: if (access(dir, X_OK) == -1) { 3: 519-block 0 call 0 returned 3 branch 1 taken 0 (fallthrough) branch 2 taken 3 #####: 520: fprintf(stderr, "%s: %s: %s\n", PROGRAM_NAME, dir, call 0 never executed #####: 521: strerror(errno)); %%%%%: 521-block 0 call 0 never executed #####: 522: return EXIT_FAILURE; unconditional 0 never executed -: 523: } -: 524: 3: 525: if (xchdir(dir, NO_TITLE) == -1) { 3: 525-block 0 call 0 returned 3 branch 1 taken 0 (fallthrough) branch 2 taken 3 #####: 526: fprintf(stderr, "%s: %s: %s\n", PROGRAM_NAME, dir, call 0 never executed #####: 527: strerror(errno)); %%%%%: 527-block 0 call 0 never executed #####: 528: return EXIT_FAILURE; unconditional 0 never executed -: 529: } -: 530: } -: 531: 13: 532: char *pattern = (char *)NULL; -: 533: 38: 534: for (i = 1; args[i]; i++) { 13: 534-block 0 unconditional 0 taken 13 25: 534-block 1 unconditional 1 taken 25 38: 534-block 2 branch 2 taken 25 branch 3 taken 13 (fallthrough) 25: 535: if (i == ifiletype || i == isel_path) 25: 535-block 0 branch 0 taken 23 (fallthrough) branch 1 taken 2 23: 535-block 1 branch 2 taken 3 (fallthrough) branch 3 taken 20 5: 536: continue; 5: 536-block 0 unconditional 0 taken 5 -: 537: /* int invert = 0; */ -: 538: 20: 539: if (check_regex(args[i]) == EXIT_SUCCESS) { 20: 539-block 0 call 0 returned 20 branch 1 taken 7 (fallthrough) branch 2 taken 13 7: 540: pattern = args[i]; 7: 541: if (*pattern == '!') { 7: 541-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 7 #####: 542: pattern++; %%%%%: 542-block 0 unconditional 0 never executed -: 543: /* invert = 1; */ -: 544: } -: 545: } -: 546: 20: 547: if (!pattern) { 20: 547-block 0 branch 0 taken 13 (fallthrough) branch 1 taken 7 13: 548: if (strchr(args[i], '\\')) { 13: 548-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 13 #####: 549: char *deq_str = dequote_str(args[i], 0); %%%%%: 549-block 0 call 0 never executed #####: 550: if (deq_str) { branch 0 never executed branch 1 never executed #####: 551: strcpy(args[i], deq_str); #####: 552: free(deq_str); %%%%%: 552-block 0 unconditional 0 never executed -: 553: } -: 554: } -: 555: 13: 556: char *tmp = (char *)NULL; -: 557: 13: 558: if (*args[i] != '/') { 13: 558-block 0 branch 0 taken 13 (fallthrough) branch 1 taken 0 13: 559: if (!sel_path) { 13: 559-block 0 branch 0 taken 13 (fallthrough) branch 1 taken 0 13: 560: if (*ws[cur_ws].path == '/' && !*(ws[cur_ws].path + 1)) { 13: 560-block 0 branch 0 taken 13 (fallthrough) branch 1 taken 0 13: 560-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 13 #####: 561: tmp = (char *)xnmalloc(strlen(args[i]) + 2, %%%%%: 561-block 0 call 0 never executed -: 562: sizeof(char)); #####: 563: sprintf(tmp, "/%s", args[i]); unconditional 0 never executed -: 564: } else { 13: 565: tmp = (char *)xnmalloc(strlen(ws[cur_ws].path) 13: 566: + strlen(args[i]) + 2, sizeof(char)); 13: 566-block 0 call 0 returned 13 13: 567: sprintf(tmp, "%s/%s", ws[cur_ws].path, args[i]); unconditional 0 taken 13 -: 568: } -: 569: } else { #####: 570: tmp = (char *)xnmalloc(strlen(dir) + strlen(args[i]) %%%%%: 570-block 0 call 0 never executed -: 571: + 2, sizeof(char)); #####: 572: sprintf(tmp, "%s/%s", dir, args[i]); unconditional 0 never executed -: 573: } -: 574: -: 575: struct stat fattr; 13: 576: if (lstat(tmp, &fattr) == -1) { 13: 576-block 0 call 0 returned 13 branch 1 taken 0 (fallthrough) branch 2 taken 13 #####: 577: fprintf(stderr, "%s: %s: %s\n", PROGRAM_NAME, #####: 578: args[i], strerror(errno)); %%%%%: 578-block 0 call 0 never executed call 1 never executed unconditional 2 never executed -: 579: } else { 13: 580: new_sel += select_file(tmp); 13: 580-block 0 call 0 returned 13 unconditional 1 taken 13 -: 581: } 13: 582: free(tmp); 13: 582-block 0 unconditional 0 taken 13 -: 583: } else { -: 584: struct stat fattr; #####: 585: if (lstat(args[i], &fattr) == -1) { %%%%%: 585-block 0 call 0 never executed branch 1 never executed branch 2 never executed #####: 586: fprintf(stderr, "%s: %s: %s\n", PROGRAM_NAME, #####: 587: args[i], strerror(errno)); %%%%%: 587-block 0 call 0 never executed call 1 never executed unconditional 2 never executed -: 588: } else { #####: 589: new_sel += select_file(args[i]); %%%%%: 589-block 0 call 0 never executed unconditional 1 never executed -: 590: } -: 591: } -: 592: } else { -: 593: /* We have a pattern */ -: 594: /* GLOB */ 7: 595: int ret = -1; 7: 596: ret = sel_glob(args[i], sel_path ? dir : NULL, 7: 596-block 0 branch 0 taken 3 (fallthrough) branch 1 taken 4 3: 596-block 1 unconditional 2 taken 3 4: 596-block 2 unconditional 3 taken 4 7: 596-block 3 call 4 returned 7 -: 597: filetype ? filetype : 0); -: 598: -: 599: /* If glob failed, try REGEX */ 7: 600: if (ret <= 0) { branch 0 taken 2 (fallthrough) branch 1 taken 5 2: 601: ret = sel_regex(args[i], sel_path ? dir : NULL, 2: 601-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 1 1: 601-block 1 unconditional 2 taken 1 1: 601-block 2 unconditional 3 taken 1 2: 601-block 3 call 4 returned 2 -: 602: filetype); 2: 603: if (ret > 0) branch 0 taken 1 (fallthrough) branch 1 taken 1 1: 604: new_sel += ret; 1: 604-block 0 unconditional 0 taken 1 -: 605: } else { 5: 606: new_sel += ret; 5: 606-block 0 unconditional 0 taken 5 -: 607: } -: 608: } -: 609: } -: 610: 13: 611: if (new_sel > 0 && xargs.stealth_mode != 1) { 13: 611-block 0 branch 0 taken 12 (fallthrough) branch 1 taken 1 12: 611-block 1 branch 2 taken 12 (fallthrough) branch 3 taken 0 12: 612: if (save_sel() != EXIT_SUCCESS) { 12: 612-block 0 call 0 returned 12 branch 1 taken 0 (fallthrough) branch 2 taken 12 #####: 613: _err('e', PRINT_PROMPT, _("%s: Error writing selected files " %%%%%: 613-block 0 call 0 never executed call 1 never executed unconditional 2 never executed -: 614: "to the selections file\n"), PROGRAM_NAME); -: 615: } -: 616: } -: 617: 13: 618: if (sel_path && xchdir(ws[cur_ws].path, NO_TITLE) == -1) { 13: 618-block 0 branch 0 taken 3 (fallthrough) branch 1 taken 10 3: 618-block 1 call 2 returned 3 branch 3 taken 0 (fallthrough) branch 4 taken 3 #####: 619: fprintf(stderr, "%s: %s: %s\n", PROGRAM_NAME, ws[cur_ws].path, call 0 never executed #####: 620: strerror(errno)); %%%%%: 620-block 0 call 0 never executed #####: 621: return EXIT_FAILURE; unconditional 0 never executed -: 622: } -: 623: 13: 624: if (new_sel <= 0) { 13: 624-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 12 1: 625: if (pattern) 1: 625-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 0 1: 626: fprintf(stderr, _("%s: No matches found\n"), PROGRAM_NAME); 1: 626-block 0 call 0 returned 1 call 1 returned 1 unconditional 2 taken 1 1: 627: return EXIT_FAILURE; 1: 627-block 0 unconditional 0 taken 1 -: 628: } -: 629: -: 630: /* Get total size of sel files */ -: 631: struct stat sattr; -: 632: 12: 633: i = (int)sel_n; 48: 634: while (--i >= 0) { 12: 634-block 0 unconditional 0 taken 12 48: 634-block 1 branch 1 taken 36 branch 2 taken 12 (fallthrough) 36: 635: if (lstat(sel_elements[i], &sattr) != -1) { 36: 635-block 0 call 0 returned 36 branch 1 taken 36 (fallthrough) branch 2 taken 0 -: 636: /* if ((sattr.st_mode & S_IFMT) == S_IFDIR) { -: 637: off_t dsize = dir_size(sel_elements[i]); -: 638: total_sel_size += dsize; -: 639: } -: 640: else */ 36: 641: total_sel_size += sattr.st_size; 36: 641-block 0 unconditional 0 taken 36 -: 642: } -: 643: } -: 644: -: 645: /* Print entries */ 12: 646: if (sel_n > 10) { 12: 646-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 12 #####: 647: printf(_("%zu files are now in the Selection Box\n"), sel_n); %%%%%: 647-block 0 call 0 never executed call 1 never executed unconditional 2 never executed 12: 648: } else if (sel_n > 0) { 12: 648-block 0 branch 0 taken 12 (fallthrough) branch 1 taken 0 21: 649: printf(_("%zu selected %s:\n\n"), sel_n, (sel_n == 1) ? _("file") 12: 649-block 0 branch 0 taken 3 (fallthrough) branch 1 taken 9 3: 649-block 1 call 2 returned 3 unconditional 3 taken 3 12: 649-block 2 call 4 returned 12 call 5 returned 12 9: 650: : _("files")); 9: 650-block 0 call 0 returned 9 unconditional 1 taken 9 -: 651: 48: 652: for (i = 0; i < (int)sel_n; i++) unconditional 0 taken 12 unconditional 1 taken 36 48: 652-block 0 branch 2 taken 36 branch 3 taken 12 (fallthrough) 36: 653: colors_list(sel_elements[i], (int)i + 1, NO_PAD, 36: 653-block 0 call 0 returned 36 -: 654: PRINT_NEWLINE); -: 655: } -: 656: -: 657: /* Print total size */ 12: 658: char *human_size = get_size_unit(total_sel_size); 12: 658-block 0 call 0 returned 12 -: 659: 12: 660: if (sel_n > 10) branch 0 taken 0 (fallthrough) branch 1 taken 12 #####: 661: printf(_("Total size: %s\n"), human_size); %%%%%: 661-block 0 call 0 never executed call 1 never executed unconditional 2 never executed 12: 662: else if (sel_n > 0) 12: 662-block 0 branch 0 taken 12 (fallthrough) branch 1 taken 0 12: 663: printf(_("\n%s%sTotal size%s: %s\n"), df_c, BOLD, df_c, human_size); 12: 663-block 0 call 0 returned 12 call 1 returned 12 unconditional 2 taken 12 -: 664: 12: 665: free(human_size); 12: 666: return EXIT_SUCCESS; 12: 666-block 0 unconditional 0 taken 12 -: 667:} -: 668: -: 669:void function show_sel_files called 1 returned 100% blocks executed 61% 1: 670:show_sel_files(void) -: 671:{ 1: 672: if (clear_screen) 1: 672-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 1 #####: 673: CLEAR; %%%%%: 673-block 0 call 0 never executed unconditional 1 never executed -: 674: 1: 675: printf(_("%s%sSelection Box%s\n"), df_c, BOLD, df_c); 1: 675-block 0 call 0 returned 1 call 1 returned 1 -: 676: 1: 677: int reset_pager = 0; -: 678: 1: 679: if (sel_n == 0) { branch 0 taken 0 (fallthrough) branch 1 taken 1 #####: 680: puts(_("Empty")); %%%%%: 680-block 0 call 0 never executed call 1 never executed unconditional 2 never executed -: 681: } else { 1: 682: putchar('\n'); 1: 682-block 0 call 0 returned 1 -: 683: struct winsize w; 1: 684: ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); call 0 returned 1 1: 685: size_t counter = 0; 1: 686: int t_rows = (int)w.ws_row; 1: 687: t_rows -= 2; -: 688: size_t i; -: 689: 2: 690: for (i = 0; i < sel_n; i++) { unconditional 0 taken 1 1: 690-block 0 unconditional 1 taken 1 2: 690-block 1 branch 2 taken 1 branch 3 taken 1 (fallthrough) -: 691: /* if (pager && counter > (term_rows-2)) { */ 1*: 692: if (pager && counter > (size_t)t_rows) { 1: 692-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 1 %%%%%: 692-block 1 branch 2 never executed branch 3 never executed #####: 693: switch (xgetchar()) { %%%%%: 693-block 0 call 0 never executed branch 1 never executed branch 2 never executed branch 3 never executed branch 4 never executed -: 694: /* Advance one line at a time */ #####: 695: case 66: /* fallthrough */ /* Down arrow */ -: 696: case 10: /* fallthrough */ /* Enter */ -: 697: case 32: /* Space */ #####: 698: break; %%%%%: 698-block 0 unconditional 0 never executed -: 699: /* Advance one page at a time */ #####: 700: case 126: #####: 701: counter = 0; /* Page Down */ #####: 702: break; %%%%%: 702-block 0 unconditional 0 never executed -: 703: /* Stop paging (and set a flag to reenable the pager -: 704: * later) */ #####: 705: case 99: /* fallthrough */ /* 'c' */ -: 706: case 112: /* fallthrough */ /* 'p' */ -: 707: case 113: #####: 708: pager = 0, reset_pager = 1; /* 'q' */ #####: 709: break; %%%%%: 709-block 0 unconditional 0 never executed -: 710: /* If another key is pressed, go back one position. -: 711: * Otherwise, some file names won't be listed.*/ #####: 712: default: #####: 713: i--; #####: 714: continue; %%%%%: 714-block 0 unconditional 0 never executed -: 715: break; -: 716: } -: 717: } -: 718: 1: 719: counter++; 1: 720: colors_list(sel_elements[i], (int)i + 1, NO_PAD, PRINT_NEWLINE); 1: 720-block 0 call 0 returned 1 unconditional 1 taken 1 -: 721: } -: 722: 1: 723: char *human_size = get_size_unit(total_sel_size); 1: 723-block 0 call 0 returned 1 1: 724: printf(_("\n%s%sTotal size%s: %s\n"), df_c, BOLD, df_c, human_size); call 0 returned 1 call 1 returned 1 1: 725: free(human_size); unconditional 0 taken 1 -: 726: } -: 727: 1: 728: if (reset_pager) 1: 728-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 1 #####: 729: pager = 1; %%%%%: 729-block 0 unconditional 0 never executed 1: 730:} -: 731: -: 732:int function deselect called 14 returned 100% blocks executed 73% 14: 733:deselect(char **comm) -: 734:{ 14: 735: if (!comm) 14: 735-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 14 #####: 736: return EXIT_FAILURE; %%%%%: 736-block 0 unconditional 0 never executed -: 737: 14*: 738: if (comm[1] && (strcmp(comm[1], "*") == 0 || strcmp(comm[1], "a") == 0 14: 738-block 0 branch 0 taken 8 (fallthrough) branch 1 taken 6 8: 738-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 8 %%%%%: 738-block 2 branch 4 never executed branch 5 never executed #####: 739: || strcmp(comm[1], "all") == 0)) { %%%%%: 739-block 0 branch 0 never executed branch 1 never executed -: 740: 8: 741: if (sel_n > 0) { 8: 741-block 0 branch 0 taken 8 (fallthrough) branch 1 taken 0 8: 742: int i = (int)sel_n; -: 743: 29: 744: while (--i >= 0) 8: 744-block 0 unconditional 0 taken 8 29: 744-block 1 branch 1 taken 21 branch 2 taken 8 (fallthrough) 21: 745: free(sel_elements[i]); 21: 745-block 0 unconditional 0 taken 21 -: 746: 8: 747: sel_n = 0; 8: 748: total_sel_size = 0; -: 749: 8: 750: if (save_sel() != 0) 8: 750-block 0 call 0 returned 8 branch 1 taken 0 (fallthrough) branch 2 taken 8 #####: 751: return EXIT_FAILURE; %%%%%: 751-block 0 unconditional 0 never executed -: 752: else 8: 753: return EXIT_SUCCESS; 8: 753-block 0 unconditional 0 taken 8 -: 754: } else { #####: 755: puts(_("desel: There are no selected files")); %%%%%: 755-block 0 call 0 never executed call 1 never executed #####: 756: return EXIT_SUCCESS; unconditional 0 never executed -: 757: } -: 758: } -: 759: -: 760: register int i; -: 761: -: 762:/* if (clear_screen) -: 763: CLEAR; */ -: 764: 6: 765: printf(_("%sSelection Box%s\n"), BOLD, df_c); 6: 765-block 0 call 0 returned 6 call 1 returned 6 -: 766: 6: 767: if (sel_n == 0) { branch 0 taken 1 (fallthrough) branch 1 taken 5 1: 768: puts(_("Empty")); 1: 768-block 0 call 0 returned 1 call 1 returned 1 1: 769: return EXIT_SUCCESS; unconditional 0 taken 1 -: 770: } -: 771: 5: 772: putchar('\0'); 5: 772-block 0 call 0 returned 5 -: 773: 19: 774: for (i = 0; i < (int)sel_n; i++) unconditional 0 taken 5 unconditional 1 taken 14 19: 774-block 0 branch 2 taken 14 branch 3 taken 5 (fallthrough) 14: 775: colors_list(sel_elements[i], (int)i + 1, NO_PAD, PRINT_NEWLINE); 14: 775-block 0 call 0 returned 14 -: 776: 5: 777: char *human_size = get_size_unit(total_sel_size); 5: 777-block 0 call 0 returned 5 5: 778: printf(_("\n%s%sTotal size%s: %s\n"), df_c, BOLD, df_c, human_size); call 0 returned 5 call 1 returned 5 5: 779: free(human_size); -: 780: 5: 781: printf(_("\n%sEnter '%c' to quit.\n"), df_c, 'q'); call 0 returned 5 call 1 returned 5 5: 782: size_t desel_n = 0; 5: 783: char *line = NULL, **desel_elements = (char **)NULL; -: 784: 10: 785: while (!line) unconditional 0 taken 5 10: 785-block 0 branch 1 taken 5 branch 2 taken 5 (fallthrough) 5: 786: line = rl_no_hist(_("File(s) to be deselected (ex: 1 2-6, or *): ")); 5: 786-block 0 call 0 returned 5 call 1 returned 5 unconditional 2 taken 5 -: 787: 5: 788: desel_elements = get_substr(line, ' '); 5: 788-block 0 call 0 returned 5 5: 789: free(line); -: 790: 5: 791: if (!desel_elements) branch 0 taken 0 (fallthrough) branch 1 taken 5 #####: 792: return EXIT_FAILURE; %%%%%: 792-block 0 unconditional 0 never executed -: 793: 10: 794: for (i = 0; desel_elements[i]; i++) 5: 794-block 0 unconditional 0 taken 5 10: 794-block 1 branch 1 taken 5 branch 2 taken 5 (fallthrough) 5: 795: desel_n++; 5: 795-block 0 unconditional 0 taken 5 -: 796: 5: 797: i = (int)desel_n; 9: 798: while (--i >= 0) { /* Validation */ 5: 798-block 0 unconditional 0 taken 5 9: 798-block 1 branch 1 taken 5 branch 2 taken 4 (fallthrough) -: 799: /* If not a number */ 5: 800: if (!is_number(desel_elements[i])) { 5: 800-block 0 call 0 returned 5 branch 1 taken 1 (fallthrough) branch 2 taken 4 1: 801: if (strcmp(desel_elements[i], "q") == 0) { 1: 801-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 1 #####: 802: i = (int)desel_n; #####: 803: while (--i >= 0) %%%%%: 803-block 0 unconditional 0 never executed %%%%%: 803-block 1 branch 1 never executed branch 2 never executed #####: 804: free(desel_elements[i]); %%%%%: 804-block 0 unconditional 0 never executed #####: 805: free(desel_elements); #####: 806: return EXIT_SUCCESS; %%%%%: 806-block 0 unconditional 0 never executed 1: 807: } else if (strcmp(desel_elements[i], "*") == 0) { 1: 807-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 0 -: 808: /* Clear the sel array */ 1: 809: i = (int)sel_n; 5: 810: while (--i >= 0) 1: 810-block 0 unconditional 0 taken 1 5: 810-block 1 branch 1 taken 4 branch 2 taken 1 (fallthrough) 4: 811: free(sel_elements[i]); 4: 811-block 0 unconditional 0 taken 4 -: 812: 1: 813: sel_n = 0; 1: 814: total_sel_size = 0; -: 815: 1: 816: i = (int)desel_n; 2: 817: while (--i >= 0) 1: 817-block 0 unconditional 0 taken 1 2: 817-block 1 branch 1 taken 1 branch 2 taken 1 (fallthrough) 1: 818: free(desel_elements[i]); 1: 818-block 0 unconditional 0 taken 1 -: 819: 1: 820: int exit_status = EXIT_SUCCESS; -: 821: 1: 822: if (save_sel() != 0) 1: 822-block 0 call 0 returned 1 branch 1 taken 0 (fallthrough) branch 2 taken 1 #####: 823: exit_status = EXIT_FAILURE; %%%%%: 823-block 0 unconditional 0 never executed -: 824: 1: 825: free(desel_elements); -: 826: 1: 827: if (cd_lists_on_the_fly) { 1: 827-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 0 1: 828: free_dirlist(); 1: 828-block 0 call 0 returned 1 1: 829: if (list_dir() != EXIT_SUCCESS) call 0 returned 1 branch 1 taken 0 (fallthrough) branch 2 taken 1 #####: 830: exit_status = EXIT_FAILURE; %%%%%: 830-block 0 unconditional 0 never executed -: 831: } -: 832: 1: 833: return exit_status; 1: 833-block 0 unconditional 0 taken 1 -: 834: } else { #####: 835: printf(_("desel: '%s': Invalid element\n"), desel_elements[i]); %%%%%: 835-block 0 call 0 never executed call 1 never executed #####: 836: int j = (int)desel_n; #####: 837: while (--j >= 0) unconditional 0 never executed %%%%%: 837-block 0 branch 1 never executed branch 2 never executed #####: 838: free(desel_elements[j]); %%%%%: 838-block 0 unconditional 0 never executed #####: 839: free(desel_elements); #####: 840: return EXIT_FAILURE; %%%%%: 840-block 0 unconditional 0 never executed -: 841: } -: 842: } -: 843: -: 844: /* If a number, check it's a valid ELN */ -: 845: else { 4: 846: int atoi_desel = atoi(desel_elements[i]); 4: 847: if (atoi_desel == 0 || (size_t)atoi_desel > sel_n) { 4: 847-block 0 branch 0 taken 4 (fallthrough) branch 1 taken 0 4: 847-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 4 #####: 848: printf(_("desel: '%s': Invalid ELN\n"), desel_elements[i]); %%%%%: 848-block 0 call 0 never executed call 1 never executed #####: 849: int j = (int)desel_n; #####: 850: while (--j >= 0) unconditional 0 never executed %%%%%: 850-block 0 branch 1 never executed branch 2 never executed #####: 851: free(desel_elements[j]); %%%%%: 851-block 0 unconditional 0 never executed #####: 852: free(desel_elements); #####: 853: return EXIT_FAILURE; %%%%%: 853-block 0 unconditional 0 never executed -: 854: } -: 855: } -: 856: } -: 857: -: 858: /* If a valid ELN and not asterisk... */ -: 859: /* Store the full path of all the elements to be deselected in a new -: 860: * array (desel_path). I need to do this because after the first -: 861: * rearragement of the sel array, that is, after the removal of the -: 862: * first element, the index of the next elements changed, and cannot -: 863: * thereby be found by their index. The only way to find them is to -: 864: * compare string by string */ 4: 865: char **desel_path = (char **)NULL; 4: 866: desel_path = (char **)xnmalloc(desel_n, sizeof(char *)); 4: 866-block 0 call 0 returned 4 -: 867: 4: 868: i = (int)desel_n; 8: 869: while (--i >= 0) { unconditional 0 taken 4 8: 869-block 0 branch 1 taken 4 branch 2 taken 4 (fallthrough) 4: 870: int desel_int = atoi(desel_elements[i]); 4: 871: desel_path[i] = savestring(sel_elements[desel_int - 1], unconditional 0 taken 4 4: 872: strlen(sel_elements[desel_int - 1])); 4: 872-block 0 call 0 returned 4 -: 873: } -: 874: -: 875: /* Search the sel array for the path of the element to deselect and -: 876: * store its index */ -: 877: struct stat desel_attrib; -: 878: 4: 879: i = (int)desel_n; 8: 880: while (--i >= 0) { 4: 880-block 0 unconditional 0 taken 4 8: 880-block 1 branch 1 taken 4 branch 2 taken 4 (fallthrough) 4: 881: int j, k, desel_index = 0; -: 882: 4: 883: k = (int)sel_n; 10: 884: while (--k >= 0) { 4: 884-block 0 unconditional 0 taken 4 10: 884-block 1 branch 1 taken 10 branch 2 taken 0 (fallthrough) 10: 885: if (strcmp(sel_elements[k], desel_path[i]) == 0) { 10: 885-block 0 branch 0 taken 4 (fallthrough) branch 1 taken 6 -: 886: /* Sustract size from total size */ 4: 887: if (lstat(sel_elements[k], &desel_attrib) != -1) { 4: 887-block 0 call 0 returned 4 branch 1 taken 4 (fallthrough) branch 2 taken 0 4: 888: if ((desel_attrib.st_mode & S_IFMT) == S_IFDIR) 4: 888-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 4 #####: 889: total_sel_size -= dir_size(sel_elements[k]); %%%%%: 889-block 0 call 0 never executed unconditional 1 never executed -: 890: else 4: 891: total_sel_size -= desel_attrib.st_size; 4: 891-block 0 unconditional 0 taken 4 -: 892: } -: 893: 4: 894: desel_index = k; 4: 895: break; 4: 895-block 0 unconditional 0 taken 4 -: 896: } -: 897: } -: 898: -: 899: /* Once the index was found, rearrange the sel array removing the -: 900: * deselected element (actually, moving each string after it to -: 901: * the previous position) */ 10: 902: for (j = desel_index; j < (int)(sel_n - 1); j++) { 4: 902-block 0 unconditional 0 taken 4 10: 902-block 1 branch 1 taken 6 branch 2 taken 4 (fallthrough) 12: 903: sel_elements[j] = (char *)xrealloc(sel_elements[j], 6: 904: (strlen(sel_elements[j + 1]) + 1) * sizeof(char)); 6: 904-block 0 call 0 returned 6 6: 905: strcpy(sel_elements[j], sel_elements[j + 1]); unconditional 0 taken 6 -: 906: } -: 907: } -: 908: -: 909: /* Free the last DESEL_N elements from the old sel array. They won't -: 910: * be used anymore, for they contain the same value as the last -: 911: * non-deselected element due to the above array rearrangement */ 8: 912: for (i = 1; i <= (int)desel_n; i++) 4: 912-block 0 unconditional 0 taken 4 4: 912-block 1 unconditional 1 taken 4 8: 912-block 2 branch 2 taken 4 branch 3 taken 4 (fallthrough) 4: 913: if (((int)sel_n - i) >= 0 && sel_elements[(int)sel_n - i]) 4: 913-block 0 branch 0 taken 4 (fallthrough) branch 1 taken 0 4: 913-block 1 branch 2 taken 4 (fallthrough) branch 3 taken 0 4: 914: free(sel_elements[(int)sel_n - i]); 4: 914-block 0 unconditional 0 taken 4 -: 915: -: 916: /* Reallocate the sel array according to the new size */ 4: 917: sel_n = (sel_n - desel_n); -: 918: 4: 919: if ((int)sel_n < 0) { 4: 919-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 4 #####: 920: sel_n = 0; #####: 921: total_sel_size = 0; %%%%%: 921-block 0 unconditional 0 never executed -: 922: } -: 923: 4: 924: if (sel_n) 4: 924-block 0 branch 0 taken 3 (fallthrough) branch 1 taken 1 3: 925: sel_elements = (char **)xrealloc(sel_elements, sel_n * sizeof(char *)); 3: 925-block 0 call 0 returned 3 unconditional 1 taken 3 -: 926: -: 927: /* Deallocate local arrays */ 4: 928: i = (int)desel_n; 8: 929: while (--i >= 0) { 4: 929-block 0 unconditional 0 taken 4 8: 929-block 1 branch 1 taken 4 branch 2 taken 4 (fallthrough) 4: 930: free(desel_path[i]); 4: 931: free(desel_elements[i]); 4: 931-block 0 unconditional 0 taken 4 -: 932: } 4: 933: free(desel_path); 4: 934: free(desel_elements); -: 935: 4: 936: if (args_n > 0) { 4: 936-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 4 #####: 937: for (i = 1; i <= (int)args_n; i++) %%%%%: 937-block 0 unconditional 0 never executed %%%%%: 937-block 1 branch 1 never executed branch 2 never executed #####: 938: free(comm[i]); %%%%%: 938-block 0 unconditional 0 never executed #####: 939: comm = (char **)xrealloc(comm, 1 * sizeof(char *)); %%%%%: 939-block 0 call 0 never executed #####: 940: args_n = 0; unconditional 0 never executed -: 941: } -: 942: 4: 943: int exit_status = EXIT_SUCCESS; -: 944: 4: 945: if (save_sel() != 0) 4: 945-block 0 call 0 returned 4 branch 1 taken 0 (fallthrough) branch 2 taken 4 #####: 946: exit_status = EXIT_FAILURE; %%%%%: 946-block 0 unconditional 0 never executed -: 947: -: 948: /* If there is still some selected file, reload the desel screen */ 4: 949: if (sel_n) 4: 949-block 0 branch 0 taken 3 (fallthrough) branch 1 taken 1 3: 950: if (deselect(comm) != 0) 3: 950-block 0 call 0 returned 3 branch 1 taken 0 (fallthrough) branch 2 taken 3 #####: 951: exit_status = EXIT_FAILURE; %%%%%: 951-block 0 unconditional 0 never executed -: 952: 4: 953: return exit_status; 4: 953-block 0 unconditional 0 taken 4 -: 954:} clifm-1.26.3/misc/codecov/sort.c.gcov000066400000000000000000000703421506632037700173610ustar00rootroot00000000000000 -: 0:Source:sort.c -: 1:/* sort.c -- functions used to sort files */ -: 2: -: 3:/* -: 4: * This file is part of CliFM -: 5: * -: 6: * Copyright (C) 2016-2021, L. Abramovich -: 7: * All rights reserved. -: 8: -: 9: * CliFM is free software; you can redistribute it and/or modify -: 10: * it under the terms of the GNU General Public License as published by -: 11: * the Free Software Foundation; either version 2 of the License, or -: 12: * (at your option) any later version. -: 13: * -: 14: * CliFM is distributed in the hope that it will be useful, -: 15: * but WITHOUT ANY WARRANTY; without even the implied warranty of -: 16: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -: 17: * GNU General Public License for more details. -: 18: * -: 19: * You should have received a copy of the GNU General Public License -: 20: * along with this program; if not, write to the Free Software -: 21: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, -: 22: * MA 02110-1301, USA. -: 23:*/ -: 24: -: 25:#include "helpers.h" -: 26: -: 27:#include -: 28:#include -: 29:#include -: 30:#include -: 31:#include -: 32:#ifdef __OpenBSD__ -: 33:#include -: 34:#endif -: 35://#include -: 36: -: 37:#include "checks.h" -: 38:#include "listing.h" -: 39:#include "messages.h" -: 40: -: 41:int function skip_nonexec called 73420 returned 100% blocks executed 100% 73420: 42:skip_nonexec(const struct dirent *ent) -: 43:{ 73420: 44: if (access(ent->d_name, X_OK) == -1) 73420: 44-block 0 call 0 returned 73420 branch 1 taken 137 (fallthrough) branch 2 taken 73283 137: 45: return 0; 137: 45-block 0 unconditional 0 taken 137 73283: 46: return 1; 73283: 46-block 0 unconditional 0 taken 73283 -: 47: -: 48:/* int f = 0; // Hold file ownership flags -: 49: -: 50: struct stat a; -: 51: if (stat(ent->d_name, &a) == -1) -: 52: return 0; -: 53: -: 54: mode_t val = (a.st_mode & (mode_t)~S_IFMT); -: 55: if (val & S_IXUSR) f |= X_USR; -: 56: if (val & S_IXGRP) f |= X_GRP; -: 57: if (val & S_IXOTH) f |= X_OTH; -: 58: -: 59: if ((f & X_USR) && a.st_uid == user.uid) -: 60: return 1; -: 61: if ((f & X_GRP) && a.st_gid == user.gid) -: 62: return 1; -: 63: if (f & X_OTH) -: 64: return 1; -: 65: -: 66: return 0; */ -: 67:} -: 68: -: 69:int function skip_files called 33 returned 100% blocks executed 64% 33: 70:skip_files(const struct dirent *ent) -: 71:{ -: 72: /* In case a directory isn't reacheable, like a failed -: 73: * mountpoint... */ -: 74: /* struct stat file_attrib; -: 75: -: 76: if (lstat(entry->d_name, &file_attrib) == -1) { -: 77: fprintf(stderr, _("stat: cannot access '%s': %s\n"), -: 78: entry->d_name, strerror(errno)); -: 79: return 0; -: 80: } */ -: 81: -: 82: /* Skip "." and ".." */ 33: 83: if (*ent->d_name == '.' && (!ent->d_name[1] || (ent->d_name[1] == '.' && !ent->d_name[2]))) 33: 83-block 0 branch 0 taken 14 (fallthrough) branch 1 taken 19 14: 83-block 1 branch 2 taken 7 (fallthrough) branch 3 taken 7 7: 83-block 2 branch 4 taken 7 (fallthrough) branch 5 taken 0 7: 83-block 3 branch 6 taken 7 (fallthrough) branch 7 taken 0 14: 84: return 0; 14: 84-block 0 unconditional 0 taken 14 -: 85: -: 86: /* Skip files matching FILTER */ 19*: 87: if (filter && regexec(®ex_exp, ent->d_name, 0, NULL, 0) == EXIT_SUCCESS) 19: 87-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 19 %%%%%: 87-block 1 call 2 never executed branch 3 never executed branch 4 never executed #####: 88: return 0; %%%%%: 88-block 0 unconditional 0 never executed -: 89: -: 90: /* If not hidden files */ 19*: 91: if (!show_hidden && *ent->d_name == '.') 19: 91-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 19 %%%%%: 91-block 1 branch 2 never executed branch 3 never executed #####: 92: return 0; %%%%%: 92-block 0 unconditional 0 never executed -: 93: 19: 94: return 1; 19: 94-block 0 unconditional 0 taken 19 -: 95:} -: 96: -: 97:int function namecmp called 370705 returned 100% blocks executed 95% 370705: 98:namecmp(const char *s1, const char *s2) -: 99:{ -: 100: /* Do not take initial dot into account */ 370705: 101: if (*s1 == '.') 370705: 101-block 0 branch 0 taken 7465 (fallthrough) branch 1 taken 363240 7465: 102: s1++; 7465: 102-block 0 unconditional 0 taken 7465 -: 103: 370705: 104: if (*s2 == '.') 370705: 104-block 0 branch 0 taken 8015 (fallthrough) branch 1 taken 362690 8015: 105: s2++; 8015: 105-block 0 unconditional 0 taken 8015 -: 106: 370705: 107: char ac = *s1, bc = *s2; -: 108: 370705: 109: if (!case_sensitive) { 370705: 109-block 0 branch 0 taken 370705 (fallthrough) branch 1 taken 0 370705: 110: ac = (char)TOUPPER(*s1); 370705: 110-block 0 branch 0 taken 365644 (fallthrough) branch 1 taken 5061 365644: 110-block 1 branch 2 taken 365644 (fallthrough) branch 3 taken 0 365644: 110-block 2 unconditional 4 taken 365644 5061: 110-block 3 unconditional 5 taken 5061 370705: 111: bc = (char)TOUPPER(*s2); 370705: 111-block 0 branch 0 taken 365935 (fallthrough) branch 1 taken 4770 365935: 111-block 1 branch 2 taken 365935 (fallthrough) branch 3 taken 0 365935: 111-block 2 unconditional 4 taken 365935 4770: 111-block 3 unconditional 5 taken 4770 370705: 111-block 4 unconditional 6 taken 370705 -: 112: } -: 113: 370705: 114: if (bc > ac) 370705: 114-block 0 branch 0 taken 76140 (fallthrough) branch 1 taken 294565 76140: 115: return -1; 76140: 115-block 0 unconditional 0 taken 76140 -: 116: 294565: 117: if (bc < ac) 294565: 117-block 0 branch 0 taken 81327 (fallthrough) branch 1 taken 213238 81327: 118: return 1; 81327: 118-block 0 unconditional 0 taken 81327 -: 119: 213238: 120: if (!case_sensitive) 213238: 120-block 0 branch 0 taken 213238 (fallthrough) branch 1 taken 0 213238: 121: return strcasecmp(s1, s2); 213238: 121-block 0 unconditional 0 taken 213238 -: 122: #####: 123: return strcmp(s1, s2); %%%%%: 123-block 0 unconditional 0 never executed -: 124:} -: 125: -: 126:int function entrycmp called 376432 returned 100% blocks executed 91% 376432: 127:entrycmp(const void *a, const void *b) -: 128:{ 376432: 129: const struct fileinfo *pa = (struct fileinfo *)a; 376432: 130: const struct fileinfo *pb = (struct fileinfo *)b; -: 131: 376432: 132: if (list_folders_first) { 376432: 132-block 0 branch 0 taken 376136 (fallthrough) branch 1 taken 296 376136: 133: if (pb->dir != pa->dir) { 376136: 133-block 0 branch 0 taken 4206 (fallthrough) branch 1 taken 371930 4206: 134: if (pb->dir) 4206: 134-block 0 branch 0 taken 2234 (fallthrough) branch 1 taken 1972 2234: 135: return 1; 2234: 135-block 0 unconditional 0 taken 2234 -: 136: 1972: 137: return -1; 1972: 137-block 0 unconditional 0 taken 1972 -: 138: } -: 139: } -: 140: 372226: 141: int ret = 0, st = sort; -: 142: -: 143:#ifndef _GNU_SOURCE -: 144: if (st == SVER) -: 145: st = SNAME; -: 146:#endif -: 147: 372226: 148: if (light_mode && (st == SOWN || st == SGRP)) 372226: 148-block 0 branch 0 taken 12 (fallthrough) branch 1 taken 372214 12: 148-block 1 branch 2 taken 12 (fallthrough) branch 3 taken 0 12: 148-block 2 branch 4 taken 0 (fallthrough) branch 5 taken 12 #####: 149: st = SNAME; %%%%%: 149-block 0 unconditional 0 never executed -: 150: 372226: 151: switch (st) { 372226: 151-block 0 branch 0 taken 456 branch 1 taken 917 branch 2 taken 236 branch 3 taken 237 branch 4 taken 233 branch 5 taken 233 branch 6 taken 233 branch 7 taken 369681 -: 152: 456: 153: case SSIZE: 456: 154: if (pa->size > pb->size) 456: 154-block 0 branch 0 taken 70 (fallthrough) branch 1 taken 386 70: 155: ret = 1; 70: 155-block 0 unconditional 0 taken 70 386: 156: else if (pa->size < pb->size) 386: 156-block 0 branch 0 taken 75 (fallthrough) branch 1 taken 311 75: 157: ret = -1; 75: 157-block 0 unconditional 0 taken 75 456: 158: break; 456: 158-block 0 unconditional 0 taken 456 -: 159: 917: 160: case SATIME: /* fallthrough */ -: 161: case SBTIME: /* fallthrough */ -: 162: case SCTIME: /* fallthrough */ -: 163: case SMTIME: 917: 164: if (pa->time > pb->time) 917: 164-block 0 branch 0 taken 448 (fallthrough) branch 1 taken 469 448: 165: ret = 1; 448: 165-block 0 unconditional 0 taken 448 469: 166: else if (pa->time < pb->time) 469: 166-block 0 branch 0 taken 432 (fallthrough) branch 1 taken 37 432: 167: ret = -1; 432: 167-block 0 unconditional 0 taken 432 917: 168: break; 917: 168-block 0 unconditional 0 taken 917 -: 169: -: 170:#ifdef _GNU_SOURCE 236: 171: case SVER: 236: 172: ret = strverscmp(pa->name, pb->name); 236: 173: break; 236: 173-block 0 unconditional 0 taken 236 -: 174:#endif -: 175: 237: 176: case SEXT: { 237: 177: char *aext = (char *)NULL, *bext = (char *)NULL, *val; 237: 178: val = strrchr(pa->name, '.'); 237: 179: if (val && val != pa->name) 237: 179-block 0 branch 0 taken 181 (fallthrough) branch 1 taken 56 181: 179-block 1 branch 2 taken 10 (fallthrough) branch 3 taken 171 10: 180: aext = val + 1; 10: 180-block 0 unconditional 0 taken 10 -: 181: 237: 182: val = strrchr(pb->name, '.'); 237: 183: if (val && val != pb->name) 237: 183-block 0 branch 0 taken 200 (fallthrough) branch 1 taken 37 200: 183-block 1 branch 2 taken 22 (fallthrough) branch 3 taken 178 22: 184: bext = val + 1; 22: 184-block 0 unconditional 0 taken 22 -: 185: 237: 186: if (aext || bext) { 237: 186-block 0 branch 0 taken 227 (fallthrough) branch 1 taken 10 227: 186-block 1 branch 2 taken 17 (fallthrough) branch 3 taken 210 27: 187: if (!aext) 27: 187-block 0 branch 0 taken 17 (fallthrough) branch 1 taken 10 17: 188: ret = -1; 17: 188-block 0 unconditional 0 taken 17 10: 189: else if (!bext) 10: 189-block 0 branch 0 taken 5 (fallthrough) branch 1 taken 5 5: 190: ret = 1; 5: 190-block 0 unconditional 0 taken 5 -: 191: -: 192: else 5: 193: ret = strcasecmp(aext, bext); 5: 193-block 0 unconditional 0 taken 5 -: 194: } 237: 195: } break; 237: 195-block 0 unconditional 0 taken 237 -: 196: 233: 197: case SINO: 233: 198: if (pa->inode > pb->inode) 233: 198-block 0 branch 0 taken 115 (fallthrough) branch 1 taken 118 115: 199: ret = 1; 115: 199-block 0 unconditional 0 taken 115 118: 200: else if (pa->inode < pb->inode) 118: 200-block 0 branch 0 taken 118 (fallthrough) branch 1 taken 0 118: 201: ret = -1; 118: 201-block 0 unconditional 0 taken 118 233: 202: break; 233: 202-block 0 unconditional 0 taken 233 -: 203: 233: 204: case SOWN: 233: 205: if (pa->uid > pb->uid) 233: 205-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 233 #####: 206: ret = 1; %%%%%: 206-block 0 unconditional 0 never executed 233: 207: else if (pa->uid < pb->uid) 233: 207-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 233 #####: 208: ret = -1; %%%%%: 208-block 0 unconditional 0 never executed 233: 209: break; 233: 209-block 0 unconditional 0 taken 233 -: 210: 233: 211: case SGRP: 233: 212: if (pa->gid > pb->gid) 233: 212-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 233 #####: 213: ret = 1; %%%%%: 213-block 0 unconditional 0 never executed 233: 214: else if (pa->gid < pb->gid) 233: 214-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 233 #####: 215: ret = -1; %%%%%: 215-block 0 unconditional 0 never executed 233: 216: break; 233: 216-block 0 unconditional 0 taken 233 -: 217: } -: 218: 372226: 219: if (!ret) 372226: 219-block 0 branch 0 taken 370705 (fallthrough) branch 1 taken 1521 370705: 220: ret = namecmp(pa->name, pb->name); 370705: 220-block 0 call 0 returned 370705 unconditional 1 taken 370705 -: 221: 372226: 222: if (!sort_reverse) 372226: 222-block 0 branch 0 taken 371986 (fallthrough) branch 1 taken 240 371986: 223: return ret; 371986: 223-block 0 unconditional 0 taken 371986 -: 224: 240: 225: return (ret - (ret * 2)); 240: 225-block 0 unconditional 0 taken 240 -: 226:} -: 227: -: 228:/* Same as alphasort, but is uses strcmp instead of sctroll, which is -: 229: * slower. However, bear in mind that, unlike strcmp(), strcoll() is locale -: 230: * aware. Use only with C and english locales */ -: 231:int function xalphasort called 759605 returned 100% blocks executed 89% 759605: 232:xalphasort(const struct dirent **a, const struct dirent **b) -: 233:{ 759605: 234: int ret = 0; -: 235: -: 236: /* The if statements prevent strcmp from running in every -: 237: * call to the function (it will be called only if the first -: 238: * character of the two strings is the same), which makes the -: 239: * function faster */ 759605: 240: if ((*a)->d_name[0] > (*b)->d_name[0]) 759605: 240-block 0 branch 0 taken 160941 (fallthrough) branch 1 taken 598664 160941: 241: ret = 1; 160941: 241-block 0 unconditional 0 taken 160941 598664: 242: else if ((*a)->d_name[0] < (*b)->d_name[0]) 598664: 242-block 0 branch 0 taken 151411 (fallthrough) branch 1 taken 447253 151411: 243: ret = -1; 151411: 243-block 0 unconditional 0 taken 151411 -: 244: else 447253: 245: ret = strcmp((*a)->d_name, (*b)->d_name); 447253: 245-block 0 unconditional 0 taken 447253 -: 246: 759605: 247: if (!sort_reverse) 759605: 247-block 0 branch 0 taken 759605 (fallthrough) branch 1 taken 0 759605: 248: return ret; 759605: 248-block 0 unconditional 0 taken 759605 -: 249: -: 250: /* If sort_reverse, return the opposite value */ #####: 251: return (ret - (ret * 2)); %%%%%: 251-block 0 unconditional 0 never executed -: 252:} -: 253: -: 254:int function sort_function called 9 returned 100% blocks executed 32% 9: 255:sort_function(char **arg) -: 256:{ 9: 257: int exit_status = EXIT_FAILURE; -: 258: -: 259: /* No argument: Just print current sorting method */ 9: 260: if (!arg[1]) { 9: 260-block 0 branch 0 taken 3 (fallthrough) branch 1 taken 6 -: 261: 3: 262: printf(_("Sorting method: ")); 3: 262-block 0 call 0 returned 3 call 1 returned 3 -: 263: 3: 264: switch (sort) { branch 0 taken 0 branch 1 taken 3 branch 2 taken 0 branch 3 taken 0 branch 4 taken 0 branch 5 taken 0 branch 6 taken 0 branch 7 taken 0 branch 8 taken 0 branch 9 taken 0 branch 10 taken 0 branch 11 taken 0 branch 12 taken 0 #####: 265: case SNONE: #####: 266: printf(_("none %s\n"), (sort_reverse) ? "[rev]" : ""); %%%%%: 266-block 0 branch 0 never executed branch 1 never executed %%%%%: 266-block 1 unconditional 2 never executed %%%%%: 266-block 2 unconditional 3 never executed %%%%%: 266-block 3 call 4 never executed call 5 never executed #####: 267: break; unconditional 0 never executed 3: 268: case SNAME: 3: 269: printf(_("name %s\n"), (sort_reverse) ? "[rev]" : ""); 3: 269-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 2 1: 269-block 1 unconditional 2 taken 1 2: 269-block 2 unconditional 3 taken 2 3: 269-block 3 call 4 returned 3 call 5 returned 3 3: 270: break; unconditional 0 taken 3 #####: 271: case SSIZE: #####: 272: printf(_("size %s\n"), (sort_reverse) ? "[rev]" : ""); %%%%%: 272-block 0 branch 0 never executed branch 1 never executed %%%%%: 272-block 1 unconditional 2 never executed %%%%%: 272-block 2 unconditional 3 never executed %%%%%: 272-block 3 call 4 never executed call 5 never executed #####: 273: break; unconditional 0 never executed #####: 274: case SATIME: #####: 275: printf(_("atime %s\n"), (sort_reverse) ? "[rev]" : ""); %%%%%: 275-block 0 branch 0 never executed branch 1 never executed %%%%%: 275-block 1 unconditional 2 never executed %%%%%: 275-block 2 unconditional 3 never executed %%%%%: 275-block 3 call 4 never executed call 5 never executed #####: 276: break; unconditional 0 never executed #####: 277: case SBTIME: -: 278:#if defined(HAVE_ST_BIRTHTIME) || defined(__BSD_VISIBLE) || defined(_STATX) #####: 279: printf(_("btime %s\n"), (sort_reverse) ? "[rev]" : ""); %%%%%: 279-block 0 branch 0 never executed branch 1 never executed %%%%%: 279-block 1 unconditional 2 never executed %%%%%: 279-block 2 unconditional 3 never executed %%%%%: 279-block 3 call 4 never executed call 5 never executed -: 280:#else -: 281: printf(_("ctime %s\n"), (sort_reverse) ? "[rev]" : ""); -: 282:#endif #####: 283: break; unconditional 0 never executed #####: 284: case SCTIME: #####: 285: printf(_("ctime %s\n"), (sort_reverse) ? "[rev]" : ""); %%%%%: 285-block 0 branch 0 never executed branch 1 never executed %%%%%: 285-block 1 unconditional 2 never executed %%%%%: 285-block 2 unconditional 3 never executed %%%%%: 285-block 3 call 4 never executed call 5 never executed #####: 286: break; unconditional 0 never executed #####: 287: case SMTIME: #####: 288: printf(_("mtime %s\n"), (sort_reverse) ? "[rev]" : ""); %%%%%: 288-block 0 branch 0 never executed branch 1 never executed %%%%%: 288-block 1 unconditional 2 never executed %%%%%: 288-block 2 unconditional 3 never executed %%%%%: 288-block 3 call 4 never executed call 5 never executed #####: 289: break; unconditional 0 never executed #####: 290: case SVER: -: 291:#if __FreeBSD__ || __NetBSD__ || __OpenBSD__ || _BE_POSIX -: 292: printf(_("name %s\n"), (sort_reverse) ? "[rev]" : ""); -: 293:#else #####: 294: printf(_("version %s\n"), (sort_reverse) ? "[rev]" : ""); %%%%%: 294-block 0 branch 0 never executed branch 1 never executed %%%%%: 294-block 1 unconditional 2 never executed %%%%%: 294-block 2 unconditional 3 never executed %%%%%: 294-block 3 call 4 never executed call 5 never executed -: 295:#endif #####: 296: break; unconditional 0 never executed #####: 297: case SEXT: #####: 298: printf(_("extension %s\n"), (sort_reverse) ? "[rev]" : ""); %%%%%: 298-block 0 branch 0 never executed branch 1 never executed %%%%%: 298-block 1 unconditional 2 never executed %%%%%: 298-block 2 unconditional 3 never executed %%%%%: 298-block 3 call 4 never executed call 5 never executed #####: 299: break; unconditional 0 never executed #####: 300: case SINO: #####: 301: printf(_("inode %s\n"), (sort_reverse) ? "[rev]" : ""); %%%%%: 301-block 0 branch 0 never executed branch 1 never executed %%%%%: 301-block 1 unconditional 2 never executed %%%%%: 301-block 2 unconditional 3 never executed %%%%%: 301-block 3 call 4 never executed call 5 never executed #####: 302: break; unconditional 0 never executed #####: 303: case SOWN: #####: 304: printf(_("owner %s\n"), (sort_reverse) ? "[rev]" : ""); %%%%%: 304-block 0 branch 0 never executed branch 1 never executed %%%%%: 304-block 1 unconditional 2 never executed %%%%%: 304-block 2 unconditional 3 never executed %%%%%: 304-block 3 call 4 never executed call 5 never executed #####: 305: break; unconditional 0 never executed #####: 306: case SGRP: #####: 307: printf(_("group %s\n"), (sort_reverse) ? "[rev]" : ""); %%%%%: 307-block 0 branch 0 never executed branch 1 never executed %%%%%: 307-block 1 unconditional 2 never executed %%%%%: 307-block 2 unconditional 3 never executed %%%%%: 307-block 3 call 4 never executed call 5 never executed #####: 308: break; unconditional 0 never executed -: 309: } -: 310: 3: 311: return EXIT_SUCCESS; 3: 311-block 0 unconditional 0 taken 3 -: 312: } -: 313: -: 314: /* Argument is alphanumerical string */ 6: 315: if (!is_number(arg[1])) { 6: 315-block 0 call 0 returned 6 branch 1 taken 4 (fallthrough) branch 2 taken 2 -: 316: -: 317: struct sort_t { -: 318: const char *name; -: 319: int num; -: 320: int padding; /* Used only to properly align the struct */ -: 321: }; -: 322: -: 323: static struct sort_t sorts[] = { -: 324: {"none", 0, 0}, -: 325: {"name", 1, 0}, -: 326: {"size", 2, 0}, -: 327: {"atime", 3, 0}, -: 328: {"btime", 4, 0}, -: 329: {"ctime", 5, 0}, -: 330: {"mtime", 6, 0}, -: 331: {"version", 7, 0}, -: 332: {"extension", 8, 0}, -: 333: {"inode", 9, 0}, -: 334: {"owner", 10, 0}, -: 335: {"group", 11, 0}, -: 336: }; -: 337: -: 338: size_t i; 52: 339: for (i = 0; i < sizeof(sorts) / sizeof(struct sort_t); i++) { 4: 339-block 0 unconditional 0 taken 4 48: 339-block 1 unconditional 1 taken 48 52: 339-block 2 branch 2 taken 48 branch 3 taken 4 (fallthrough) 48: 340: if (strcmp(arg[1], sorts[i].name) == 0) { 48: 340-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 48 #####: 341: sprintf(arg[1], "%d", sorts[i].num); #####: 342: break; %%%%%: 342-block 0 unconditional 0 never executed -: 343: } -: 344: } -: 345: 4: 346: if (strcmp(arg[1], "rev") == 0) { 4: 346-block 0 branch 0 taken 4 (fallthrough) branch 1 taken 0 -: 347: 4: 348: if (sort_reverse) 4: 348-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 2 2: 349: sort_reverse = 0; 2: 349-block 0 unconditional 0 taken 2 -: 350: else 2: 351: sort_reverse = 1; 2: 351-block 0 unconditional 0 taken 2 -: 352: 4: 353: if (cd_lists_on_the_fly) { 4: 353-block 0 branch 0 taken 4 (fallthrough) branch 1 taken 0 -: 354: /* sort_switch just tells list_dir() to print a line -: 355: * with the current sorting method at the end of the -: 356: * files list */ 4: 357: sort_switch = 1; 4: 358: free_dirlist(); 4: 358-block 0 call 0 returned 4 4: 359: exit_status = list_dir(); call 0 returned 4 4: 360: sort_switch = 0; unconditional 0 taken 4 -: 361: } -: 362: 4: 363: return exit_status; 4: 363-block 0 unconditional 0 taken 4 -: 364: } -: 365: -: 366: /* If arg1 is not a number and is not "rev", the fputs() -: 367: * above is executed */ -: 368: } -: 369: -: 370: /* Argument is a number */ 2: 371: int int_arg = atoi(arg[1]); -: 372: 2: 373: if (int_arg >= 0 && int_arg <= SORT_TYPES) { 2: 373-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 0 2: 373-block 1 branch 2 taken 2 (fallthrough) branch 3 taken 0 2: 374: sort = int_arg; -: 375: 2*: 376: if (arg[2] && strcmp(arg[2], "rev") == 0) { 2: 376-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 2 %%%%%: 376-block 1 branch 2 never executed branch 3 never executed #####: 377: if (sort_reverse) %%%%%: 377-block 0 branch 0 never executed branch 1 never executed #####: 378: sort_reverse = 0; %%%%%: 378-block 0 unconditional 0 never executed -: 379: else #####: 380: sort_reverse = 1; %%%%%: 380-block 0 unconditional 0 never executed -: 381: } -: 382: 2: 383: if (cd_lists_on_the_fly) { 2: 383-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 0 2: 384: sort_switch = 1; 2: 385: free_dirlist(); 2: 385-block 0 call 0 returned 2 2: 386: exit_status = list_dir(); call 0 returned 2 2: 387: sort_switch = 0; unconditional 0 taken 2 -: 388: } -: 389: 2: 390: return exit_status; 2: 390-block 0 unconditional 0 taken 2 -: 391: } -: 392: -: 393: /* If arg1 is a number but is not in the range 0-SORT_TYPES, -: 394: * error */ #####: 395: fprintf(stderr, "%s\n", _(SORT_USAGE)); %%%%%: 395-block 0 call 0 never executed call 1 never executed -: 396: #####: 397: return EXIT_FAILURE; unconditional 0 never executed -: 398:} -: 399: -: 400:/* This is a modification of the alphasort function that makes it case -: 401: * insensitive. It also sorts without taking the initial dot of hidden -: 402: * files into account. Note that strcasecmp() isn't locale aware. Use -: 403: * only with C and english locales */ -: 404:int function alphasort_insensitive called 0 returned 0% blocks executed 0% #####: 405:alphasort_insensitive(const struct dirent **a, const struct dirent **b) -: 406:{ #####: 407: int ret = strcasecmp(((*a)->d_name[0] == '.') ? (*a)->d_name + 1 %%%%%: 407-block 0 branch 0 never executed branch 1 never executed %%%%%: 407-block 1 unconditional 2 never executed #####: 408: : (*a)->d_name, ((*b)->d_name[0] == '.') ? (*b)->d_name + 1 : (*b)->d_name); %%%%%: 408-block 0 branch 0 never executed branch 1 never executed %%%%%: 408-block 1 unconditional 2 never executed %%%%%: 408-block 2 unconditional 3 never executed %%%%%: 408-block 3 unconditional 4 never executed -: 409: #####: 410: if (!sort_reverse) %%%%%: 410-block 0 branch 0 never executed branch 1 never executed #####: 411: return ret; %%%%%: 411-block 0 unconditional 0 never executed -: 412: #####: 413: return (ret - (ret * 2)); %%%%%: 413-block 0 unconditional 0 never executed -: 414:} clifm-1.26.3/misc/codecov/strings.c.gcov000066400000000000000000004453401506632037700200670ustar00rootroot00000000000000 -: 0:Source:strings.c -: 1:/* strings.c -- misc string manipulation function */ -: 2: -: 3:/* -: 4: * This file is part of CliFM -: 5: * -: 6: * Copyright (C) 2016-2021, L. Abramovich -: 7: * All rights reserved. -: 8: -: 9: * CliFM is free software; you can redistribute it and/or modify -: 10: * it under the terms of the GNU General Public License as published by -: 11: * the Free Software Foundation; either version 2 of the License, or -: 12: * (at your option) any later version. -: 13: * -: 14: * CliFM is distributed in the hope that it will be useful, -: 15: * but WITHOUT ANY WARRANTY; without even the implied warranty of -: 16: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -: 17: * GNU General Public License for more details. -: 18: * -: 19: * You should have received a copy of the GNU General Public License -: 20: * along with this program; if not, write to the Free Software -: 21: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, -: 22: * MA 02110-1301, USA. -: 23:*/ -: 24: -: 25:#include "helpers.h" -: 26: -: 27:#include -: 28:#include -: 29:#include -: 30:#include -: 31:#include -: 32:#include -: 33:#if !defined(__HAIKU__) && !defined(__OpenBSD__) -: 34:#include -: 35:#endif -: 36:#include "aux.h" -: 37:#include "checks.h" -: 38:#include "exec.h" -: 39:#include "navigation.h" -: 40:#include "readline.h" -: 41: -: 42:#ifndef _BE_POSIX -: 43:#define CMD_LEN_MAX (PATH_MAX + ((NAME_MAX + 1) << 1)) -: 44:char len_buf[CMD_LEN_MAX] __attribute__((aligned)); -: 45:#endif -: 46: -: 47:/* Taken from NNN's source code: very clever */ -: 48:size_t function xstrsncpy called 40271 returned 100% blocks executed 100% 40271: 49:xstrsncpy(char *restrict dst, const char *restrict src, size_t n) -: 50:{ 40271: 51: n++; 40271: 52: char *end = memccpy(dst, src, '\0', n); 40271: 52-block 0 call 0 returned 40271 40271: 53: if (!end) { branch 0 taken 75 (fallthrough) branch 1 taken 40196 75: 54: dst[n - 1] = '\0'; 75: 55: end = dst + n; 75: 55-block 0 unconditional 0 taken 75 -: 56: } -: 57: 40271: 58: return (size_t)(end - dst - 1); 40271: 58-block 0 unconditional 0 taken 40271 -: 59:} -: 60: -: 61:size_t function wc_xstrlen called 41181 returned 100% blocks executed 86% 41181: 62:wc_xstrlen(const char *restrict str) -: 63:{ -: 64: size_t len, _len; -: 65:/*#ifndef _BE_POSIX */ 41181: 66: wchar_t *const wbuf = (wchar_t *)len_buf; -: 67: -: 68: /* Convert multi-byte to wide char */ 41181: 69: _len = mbstowcs(wbuf, str, NAME_MAX); 41181: 69-block 0 call 0 returned 41181 41181: 70: int p = wcswidth(wbuf, _len); call 0 returned 41181 41181: 71: if (p != -1) branch 0 taken 41181 (fallthrough) branch 1 taken 0 41181: 72: len = (size_t)p; 41181: 72-block 0 unconditional 0 taken 41181 -: 73: else #####: 74: len = 0; %%%%%: 74-block 0 unconditional 0 never executed -: 75:/*#else -: 76: len = u8_xstrlen(str); -: 77:#endif */ -: 78: 41181: 79: return len; 41181: 79-block 0 unconditional 0 taken 41181 -: 80:} -: 81: -: 82:/* Truncate an UTF-8 string at length N. Returns zero if truncated and -: 83: * one if not */ -: 84:int function u8truncstr called 16 returned 100% blocks executed 86% 16: 85:u8truncstr(char *restrict str, size_t n) -: 86:{ 16: 87: size_t len = 0; -: 88: 256: 89: while (*(str++)) { 16: 89-block 0 unconditional 0 taken 16 256: 89-block 1 branch 1 taken 256 branch 2 taken 0 (fallthrough) -: 90: /* Do not count continuation bytes (used by multibyte, that is, -: 91: * wide or non-ASCII characters) */ 256: 92: if ((*str & 0xc0) != 0x80) { 256: 92-block 0 branch 0 taken 256 (fallthrough) branch 1 taken 0 256: 93: len++; 256: 94: if (len == n) { 256: 94-block 0 branch 0 taken 16 (fallthrough) branch 1 taken 240 16: 95: *str = '\0'; 16: 96: return EXIT_SUCCESS; 16: 96-block 0 unconditional 0 taken 16 -: 97: } -: 98: } -: 99: } -: 100: #####: 101: return EXIT_FAILURE; %%%%%: 101-block 0 unconditional 0 never executed -: 102:} -: 103: -: 104:/* An strlen implementation able to handle unicode characters. Taken from: -: 105:* https://stackoverflow.com/questions/5117393/number-of-character-cells-used-by-string -: 106:* Explanation: strlen() counts bytes, not chars. Now, since ASCII chars -: 107:* take each 1 byte, the amount of bytes equals the amount of chars. -: 108:* However, non-ASCII or wide chars are multibyte chars, that is, one char -: 109:* takes more than 1 byte, and this is why strlen() does not work as -: 110:* expected for this kind of chars: a 6 chars string might take 12 or -: 111:* more bytes */ -: 112:size_t function u8_xstrlen called 0 returned 0% blocks executed 0% #####: 113:u8_xstrlen(const char *restrict str) -: 114:{ #####: 115: size_t len = 0; -: 116: #####: 117: while (*(str++)) { %%%%%: 117-block 0 unconditional 0 never executed %%%%%: 117-block 1 branch 1 never executed branch 2 never executed #####: 118: if ((*str & 0xc0) != 0x80) %%%%%: 118-block 0 branch 0 never executed branch 1 never executed #####: 119: len++; %%%%%: 119-block 0 unconditional 0 never executed -: 120: } -: 121: #####: 122: return len; %%%%%: 122-block 0 unconditional 0 never executed -: 123:} -: 124: -: 125:/* Returns the index of the first appearance of c in str, if any, and -: 126: * -1 if c was not found or if no str. NOTE: Same thing as strchr(), -: 127: * except that returns an index, not a pointer */ -: 128:int function strcntchr called 84 returned 100% blocks executed 78% 84: 129:strcntchr(const char *str, const char c) -: 130:{ 84: 131: if (!str) 84: 131-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 84 #####: 132: return -1; %%%%%: 132-block 0 unconditional 0 never executed -: 133: 84: 134: register int i = 0; -: 135: 388: 136: while (*str) { 84: 136-block 0 unconditional 0 taken 84 388: 136-block 1 branch 1 taken 388 branch 2 taken 0 (fallthrough) 388: 137: if (*str == c) 388: 137-block 0 branch 0 taken 84 (fallthrough) branch 1 taken 304 84: 138: return i; 84: 138-block 0 unconditional 0 taken 84 304: 139: i++; 304: 140: str++; 304: 140-block 0 unconditional 0 taken 304 -: 141: } -: 142: #####: 143: return -1; %%%%%: 143-block 0 unconditional 0 never executed -: 144:} -: 145: -: 146:/* Returns the index of the last appearance of c in str, if any, and -: 147: * -1 if c was not found or if no str */ -: 148:int function strcntchrlst called 1512 returned 100% blocks executed 89% 1512: 149:strcntchrlst(const char *str, const char c) -: 150:{ 1512: 151: if (!str) 1512: 151-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 1512 #####: 152: return -1; %%%%%: 152-block 0 unconditional 0 never executed -: 153: 1512: 154: register int i = 0; -: 155: 1512: 156: int p = -1; 5463: 157: while (*str) { 1512: 157-block 0 unconditional 0 taken 1512 5463: 157-block 1 branch 1 taken 3951 branch 2 taken 1512 (fallthrough) 3951: 158: if (*str == c) 3951: 158-block 0 branch 0 taken 554 (fallthrough) branch 1 taken 3397 554: 159: p = i; 554: 159-block 0 unconditional 0 taken 554 3951: 160: i++; 3951: 161: str++; 3951: 161-block 0 unconditional 0 taken 3951 -: 162: } -: 163: 1512: 164: return p; 1512: 164-block 0 unconditional 0 taken 1512 -: 165:} -: 166: -: 167:/* Returns the string after the first appearance of a given char, or -: 168: * returns NULL if C is not found in STR or C is the last char in STR. */ -: 169:char * function straft called 60 returned 100% blocks executed 81% 60: 170:straft(char *str, const char c) -: 171:{ 60: 172: if (!str || !*str || !c) 60: 172-block 0 branch 0 taken 60 (fallthrough) branch 1 taken 0 60: 172-block 1 branch 2 taken 60 (fallthrough) branch 3 taken 0 60: 172-block 2 branch 4 taken 0 (fallthrough) branch 5 taken 60 #####: 173: return (char *)NULL; %%%%%: 173-block 0 unconditional 0 never executed -: 174: 60: 175: char *p = str, *q = (char *)NULL; -: 176: 336: 177: while (*p) { 60: 177-block 0 unconditional 0 taken 60 336: 177-block 1 branch 1 taken 336 branch 2 taken 0 (fallthrough) 336: 178: if (*p == c) { 336: 178-block 0 branch 0 taken 60 (fallthrough) branch 1 taken 276 60: 179: q = p; 60: 180: break; 60: 180-block 0 unconditional 0 taken 60 -: 181: } 276: 182: p++; 276: 182-block 0 unconditional 0 taken 276 -: 183: } -: 184: -: 185: /* If C was not found or there is nothing after C */ 60: 186: if (!q || !*(q + 1)) 60: 186-block 0 branch 0 taken 60 (fallthrough) branch 1 taken 0 60: 186-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 60 #####: 187: return (char *)NULL; %%%%%: 187-block 0 unconditional 0 never executed -: 188: 60: 189: char *buf = (char *)malloc(strlen(q + 1) + 1); -: 190: 60: 191: if (!buf) 60: 191-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 60 #####: 192: return (char *)NULL; %%%%%: 192-block 0 unconditional 0 never executed -: 193: 60: 194: strcpy(buf, q + 1); 60: 195: return buf; 60: 195-block 0 unconditional 0 taken 60 -: 196:} -: 197: -: 198:/* Returns the string after the last appearance of a given char, or -: 199: * NULL if no match */ -: 200:char * function straftlst called 11 returned 100% blocks executed 81% 11: 201:straftlst(char *str, const char c) -: 202:{ 11: 203: if (!str || !*str || !c) 11: 203-block 0 branch 0 taken 11 (fallthrough) branch 1 taken 0 11: 203-block 1 branch 2 taken 11 (fallthrough) branch 3 taken 0 11: 203-block 2 branch 4 taken 0 (fallthrough) branch 5 taken 11 #####: 204: return (char *)NULL; %%%%%: 204-block 0 unconditional 0 never executed -: 205: 11: 206: char *p = str, *q = (char *)NULL; -: 207: 468: 208: while (*p) { 11: 208-block 0 unconditional 0 taken 11 468: 208-block 1 branch 1 taken 457 branch 2 taken 11 (fallthrough) 457: 209: if (*p == c) 457: 209-block 0 branch 0 taken 66 (fallthrough) branch 1 taken 391 66: 210: q = p; 66: 210-block 0 unconditional 0 taken 66 457: 211: p++; 457: 211-block 0 unconditional 0 taken 457 -: 212: } -: 213: 11: 214: if (!q || !*(q + 1)) 11: 214-block 0 branch 0 taken 11 (fallthrough) branch 1 taken 0 11: 214-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 11 #####: 215: return (char *)NULL; %%%%%: 215-block 0 unconditional 0 never executed -: 216: 11: 217: char *buf = (char *)malloc(strlen(q + 1) + 1); -: 218: 11: 219: if (!buf) 11: 219-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 11 #####: 220: return (char *)NULL; %%%%%: 220-block 0 unconditional 0 never executed -: 221: 11: 222: strcpy(buf, q + 1); 11: 223: return buf; 11: 223-block 0 unconditional 0 taken 11 -: 224:} -: 225: -: 226:/* Returns the substring in str before the first appearance of c. If -: 227: * not found, or C is the first char in STR, returns NULL */ -: 228:char * function strbfr called 10 returned 100% blocks executed 88% 10: 229:strbfr(char *str, const char c) -: 230:{ 10: 231: if (!str || !*str || !c) 10: 231-block 0 branch 0 taken 10 (fallthrough) branch 1 taken 0 10: 231-block 1 branch 2 taken 10 (fallthrough) branch 3 taken 0 10: 231-block 2 branch 4 taken 0 (fallthrough) branch 5 taken 10 #####: 232: return (char *)NULL; %%%%%: 232-block 0 unconditional 0 never executed -: 233: 10: 234: char *p = str, *q = (char *)NULL; 16: 235: while (*p) { 10: 235-block 0 unconditional 0 taken 10 16: 235-block 1 branch 1 taken 16 branch 2 taken 0 (fallthrough) 16: 236: if (*p == c) { 16: 236-block 0 branch 0 taken 10 (fallthrough) branch 1 taken 6 10: 237: q = p; /* q is now a pointer to C in STR */ 10: 238: break; 10: 238-block 0 unconditional 0 taken 10 -: 239: } 6: 240: p++; 6: 240-block 0 unconditional 0 taken 6 -: 241: } -: 242: -: 243: /* C was not found or it was the first char in STR */ 10: 244: if (!q || q == str) 10: 244-block 0 branch 0 taken 10 (fallthrough) branch 1 taken 0 10: 244-block 1 branch 2 taken 5 (fallthrough) branch 3 taken 5 5: 245: return (char *)NULL; 5: 245-block 0 unconditional 0 taken 5 -: 246: 5: 247: *q = '\0'; -: 248: /* Now C (because q points to C) is the null byte and STR ends in -: 249: * C, which is what we want */ -: 250: 5: 251: char *buf = (char *)malloc((size_t)(q - str + 1)); -: 252: 5: 253: if (!buf) { /* Memory allocation error */ 5: 253-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 5 -: 254: /* Give back to C its original value, so that STR is not -: 255: * modified in the process */ #####: 256: *q = c; #####: 257: return (char *)NULL; %%%%%: 257-block 0 unconditional 0 never executed -: 258: } -: 259: 5: 260: strcpy(buf, str); 5: 261: *q = c; 5: 262: return buf; 5: 262-block 0 unconditional 0 taken 5 -: 263:} -: 264: -: 265:/* Get substring in STR before the last appearance of C. Returns -: 266: * substring if C is found and NULL if not (or if C was the first -: 267: * char in STR). */ -: 268:char * function strbfrlst called 21 returned 100% blocks executed 81% 21: 269:strbfrlst(char *str, const char c) -: 270:{ 21: 271: if (!str || !*str || !c) 21: 271-block 0 branch 0 taken 21 (fallthrough) branch 1 taken 0 21: 271-block 1 branch 2 taken 21 (fallthrough) branch 3 taken 0 21: 271-block 2 branch 4 taken 0 (fallthrough) branch 5 taken 21 #####: 272: return (char *)NULL; %%%%%: 272-block 0 unconditional 0 never executed -: 273: 21: 274: char *p = str, *q = (char *)NULL; 895: 275: while (*p) { 21: 275-block 0 unconditional 0 taken 21 895: 275-block 1 branch 1 taken 874 branch 2 taken 21 (fallthrough) 874: 276: if (*p == c) 874: 276-block 0 branch 0 taken 126 (fallthrough) branch 1 taken 748 126: 277: q = p; 126: 277-block 0 unconditional 0 taken 126 874: 278: p++; 874: 278-block 0 unconditional 0 taken 874 -: 279: } -: 280: 21: 281: if (!q || q == str) 21: 281-block 0 branch 0 taken 21 (fallthrough) branch 1 taken 0 21: 281-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 21 #####: 282: return (char *)NULL; %%%%%: 282-block 0 unconditional 0 never executed -: 283: 21: 284: *q = '\0'; -: 285: 21: 286: char *buf = (char *)malloc((size_t)(q - str + 1)); 21: 287: if (!buf) { 21: 287-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 21 #####: 288: *q = c; #####: 289: return (char *)NULL; %%%%%: 289-block 0 unconditional 0 never executed -: 290: } -: 291: 21: 292: strcpy(buf, str); 21: 293: *q = c; 21: 294: return buf; 21: 294-block 0 unconditional 0 taken 21 -: 295:} -: 296: -: 297:/* Returns the string between first ocurrence of A and the first -: 298: * ocurrence of B in STR, or NULL if: there is nothing between A and -: 299: * B, or A and/or B are not found */ -: 300:char * function strbtw called 171 returned 100% blocks executed 89% 171: 301:strbtw(char *str, const char a, const char b) -: 302:{ 171: 303: if (!str || !*str || !a || !b) 171: 303-block 0 branch 0 taken 171 (fallthrough) branch 1 taken 0 171: 303-block 1 branch 2 taken 171 (fallthrough) branch 3 taken 0 171: 303-block 2 branch 4 taken 171 (fallthrough) branch 5 taken 0 171: 303-block 3 branch 6 taken 0 (fallthrough) branch 7 taken 171 #####: 304: return (char *)NULL; %%%%%: 304-block 0 unconditional 0 never executed -: 305: 171: 306: char *p = str, *pa = (char *)NULL, *pb = (char *)NULL; 1293: 307: while (*p) { 171: 307-block 0 unconditional 0 taken 171 1293: 307-block 1 branch 1 taken 1277 branch 2 taken 16 (fallthrough) 1277: 308: if (!pa) { 1277: 308-block 0 branch 0 taken 382 (fallthrough) branch 1 taken 895 382: 309: if (*p == a) 382: 309-block 0 branch 0 taken 171 (fallthrough) branch 1 taken 211 171: 310: pa = p; 171: 310-block 0 unconditional 0 taken 171 895: 311: } else if (*p == b) { 895: 311-block 0 branch 0 taken 155 (fallthrough) branch 1 taken 740 155: 312: pb = p; 155: 313: break; 155: 313-block 0 unconditional 0 taken 155 -: 314: } 1122: 315: p++; 1122: 315-block 0 unconditional 0 taken 1122 -: 316: } -: 317: 171: 318: if (!pb) 171: 318-block 0 branch 0 taken 16 (fallthrough) branch 1 taken 155 16: 319: return (char *)NULL; 16: 319-block 0 unconditional 0 taken 16 -: 320: 155: 321: *pb = '\0'; -: 322: 155: 323: char *buf = (char *)malloc((size_t)(pb - pa)); -: 324: 155: 325: if (!buf) { 155: 325-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 155 #####: 326: *pb = b; #####: 327: return (char *)NULL; %%%%%: 327-block 0 unconditional 0 never executed -: 328: } -: 329: 155: 330: strcpy(buf, pa + 1); 155: 331: *pb = b; 155: 332: return buf; 155: 332-block 0 unconditional 0 taken 155 -: 333:} -: 334: -: 335:/* Replace the first occurrence of NEEDLE in HAYSTACK by REP */ -: 336:char * function replace_substr called 76 returned 100% blocks executed 87% 76: 337:replace_substr(char *haystack, char *needle, char *rep) -: 338:{ 76: 339: if (!haystack || !*haystack || !needle || !*needle || !rep) 76: 339-block 0 branch 0 taken 76 (fallthrough) branch 1 taken 0 76: 339-block 1 branch 2 taken 76 (fallthrough) branch 3 taken 0 76: 339-block 2 branch 4 taken 76 (fallthrough) branch 5 taken 0 76: 339-block 3 branch 6 taken 76 (fallthrough) branch 7 taken 0 76: 339-block 4 branch 8 taken 0 (fallthrough) branch 9 taken 76 #####: 340: return (char *)NULL; %%%%%: 340-block 0 unconditional 0 never executed -: 341: 76: 342: char *ret = strstr(haystack, needle); 76: 343: if (!ret) 76: 343-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 76 #####: 344: return (char *)NULL; %%%%%: 344-block 0 unconditional 0 never executed -: 345: 76: 346: char *needle_end = ret + strlen(needle); 76: 347: *ret = '\0'; -: 348: 76: 349: if (*needle_end) { 76: 349-block 0 branch 0 taken 19 (fallthrough) branch 1 taken 57 19: 350: size_t rem_len = strlen(needle_end); 19: 351: char *rem = (char *)xnmalloc(rem_len + 1, sizeof(char)); 19: 351-block 0 call 0 returned 19 19: 352: strcpy(rem, needle_end); -: 353: 19: 354: char *new_str = (char *)xnmalloc(strlen(haystack) + strlen(rep) 19: 355: + rem_len + 1, sizeof(char)); call 0 returned 19 19: 356: strcpy(new_str, haystack); 19: 357: strcat(new_str, rep); 19: 358: strcat(new_str, rem); 19: 359: free(rem); 19: 360: return new_str; unconditional 0 taken 19 -: 361: } -: 362: 57: 363: char *new_str = (char *)xnmalloc(strlen(haystack) + strlen(rep) 57: 363-block 0 call 0 returned 57 -: 364: + 1, sizeof(char)); 57: 365: strcpy(new_str, haystack); 57: 366: strcat(new_str, rep); 57: 367: return new_str; unconditional 0 taken 57 -: 368:} -: 369: -: 370:/* Generate a random string of LEN bytes using characters from CHARSET */ -: 371:char * function gen_rand_str called 7 returned 100% blocks executed 83% 7: 372:gen_rand_str(size_t len) -: 373:{ 7: 374: char charset[] = "0123456789#%-_" -: 375: "abcdefghijklmnopqrstuvwxyz" -: 376: "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; -: 377: 7: 378: srand((unsigned int)time(NULL)); 7: 378-block 0 call 0 returned 7 call 1 returned 7 -: 379: 7: 380: char *str = (char *)malloc((len + 1) * sizeof(char)); 7: 381: char *p = str; -: 382: 7: 383: if (!p) { branch 0 taken 0 (fallthrough) branch 1 taken 7 #####: 384: fprintf(stderr, "Error allocating %zu bytes\n", len); %%%%%: 384-block 0 call 0 never executed #####: 385: return (char *)NULL; unconditional 0 never executed -: 386: } -: 387: 49: 388: while (len--) { 7: 388-block 0 unconditional 0 taken 7 49: 388-block 1 branch 1 taken 42 branch 2 taken 7 (fallthrough) 42: 389: int i = rand() % (int)(sizeof(charset) - 1); 42: 389-block 0 call 0 returned 42 42: 390: *p++ = charset[i]; unconditional 0 taken 42 -: 391: } -: 392: 7: 393: *p = '\0'; 7: 394: return str; 7: 394-block 0 unconditional 0 taken 7 -: 395:} -: 396: -: 397:/* Removes end of line char and quotes (single and double) from STR. -: 398: * Returns a pointer to the modified STR if the result is non-blank -: 399: * or NULL */ -: 400:char * function remove_quotes called 325 returned 100% blocks executed 88% 325: 401:remove_quotes(char *str) -: 402:{ 325: 403: if (!str || !*str) 325: 403-block 0 branch 0 taken 325 (fallthrough) branch 1 taken 0 325: 403-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 325 #####: 404: return (char *)NULL; %%%%%: 404-block 0 unconditional 0 never executed -: 405: 325: 406: char *p = str; 325: 407: size_t len = strlen(p); -: 408: 325: 409: if (len > 0 && p[len - 1] == '\n') { 325: 409-block 0 branch 0 taken 325 (fallthrough) branch 1 taken 0 325: 409-block 1 branch 2 taken 97 (fallthrough) branch 3 taken 228 97: 410: p[len - 1] = '\0'; 97: 411: len--; 97: 411-block 0 unconditional 0 taken 97 -: 412: } -: 413: 325: 414: if (len > 0 && (p[len - 1] == '\'' || p[len - 1] == '"')) 325: 414-block 0 branch 0 taken 293 (fallthrough) branch 1 taken 32 293: 414-block 1 branch 2 taken 245 (fallthrough) branch 3 taken 48 245: 414-block 2 branch 4 taken 38 (fallthrough) branch 5 taken 207 86: 415: p[len - 1] = '\0'; 86: 415-block 0 unconditional 0 taken 86 -: 416: 325: 417: if (*p == '\'' || *p == '"') 325: 417-block 0 branch 0 taken 277 (fallthrough) branch 1 taken 48 277: 417-block 1 branch 2 taken 38 (fallthrough) branch 3 taken 239 86: 418: p++; 86: 418-block 0 unconditional 0 taken 86 -: 419: 325: 420: if (!*p) 325: 420-block 0 branch 0 taken 32 (fallthrough) branch 1 taken 293 32: 421: return (char *)NULL; 32: 421-block 0 unconditional 0 taken 32 -: 422: 293: 423: char *q = p; 293: 424: int blank = 1; -: 425: 293: 426: while (*q) { 293: 426-block 0 unconditional 0 taken 293 293: 426-block 1 branch 1 taken 293 branch 2 taken 0 (fallthrough) 293: 427: if (*q != ' ' && *q != '\n' && *q != '\t') { 293: 427-block 0 branch 0 taken 293 (fallthrough) branch 1 taken 0 293: 427-block 1 branch 2 taken 293 (fallthrough) branch 3 taken 0 293: 427-block 2 branch 4 taken 293 (fallthrough) branch 5 taken 0 293: 428: blank = 0; 293: 429: break; 293: 429-block 0 unconditional 0 taken 293 -: 430: } #####: 431: q++; %%%%%: 431-block 0 unconditional 0 never executed -: 432: } -: 433: 293: 434: if (!blank) 293: 434-block 0 branch 0 taken 293 (fallthrough) branch 1 taken 0 293: 435: return p; 293: 435-block 0 unconditional 0 taken 293 #####: 436: return (char *)NULL; %%%%%: 436-block 0 unconditional 0 never executed -: 437:} -: 438: -: 439:/* This function takes a string as argument and split it into substrings -: 440: * taking tab, new line char, and space as word delimiters, except when -: 441: * they are preceded by a quote char (single or double quotes) or in -: 442: * case of command substitution ($(cmd) or `cmd`), in which case -: 443: * eveything after the corresponding closing char is taken as one single -: 444: * string. It also escapes spaecial chars. It returns an array of -: 445: * splitted strings (without leading and terminating spaces) or NULL if -: 446: * str is NULL or if no substring was found, i.e., if str contains -: 447: * only spaces. */ -: 448:char ** function split_str called 500 returned 100% blocks executed 41% 500: 449:split_str(const char *str) -: 450:{ 500: 451: if (!str) 500: 451-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 500 #####: 452: return (char **)NULL; %%%%%: 452-block 0 unconditional 0 never executed -: 453: 500: 454: size_t buf_len = 0, words = 0, str_len = 0; 500: 455: char *buf = (char *)NULL; 500: 456: buf = (char *)xnmalloc(1, sizeof(char)); 500: 456-block 0 call 0 returned 500 500: 457: int quote = 0, close = 0; 500: 458: char **substr = (char **)NULL; -: 459: 2583: 460: while (*str) { unconditional 0 taken 500 2583: 460-block 0 branch 1 taken 2083 branch 2 taken 500 (fallthrough) 2083: 461: switch (*str) { 2083: 461-block 0 branch 0 taken 2 branch 1 taken 0 branch 2 taken 223 branch 3 taken 1858 -: 462: /* Command substitution */ 2: 463: case '$': /* fallthrough */ -: 464: case '`': -: 465: /* Define the closing char: If "$(" then ')', else '`' */ 2: 466: if (*str == '$') { 2: 466-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 0 -: 467: /* If escaped, it has no special meaning */ 2: 468: if ((str_len && *(str - 1) == '\\') || *(str + 1) != '(') { 2: 468-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 0 2: 468-block 1 branch 2 taken 2 (fallthrough) branch 3 taken 0 2: 468-block 2 branch 4 taken 2 (fallthrough) branch 5 taken 0 2: 469: buf = (char *)xrealloc(buf, (buf_len + 1) * sizeof(char *)); 2: 469-block 0 call 0 returned 2 2: 470: buf[buf_len++] = *str; 2: 471: break; unconditional 0 taken 2 -: 472: } else { #####: 473: close = ')'; %%%%%: 473-block 0 unconditional 0 never executed -: 474: } -: 475: } else { -: 476: /* If escaped, it has no special meaning */ #####: 477: if (str_len && *(str - 1) == '\\') { %%%%%: 477-block 0 branch 0 never executed branch 1 never executed %%%%%: 477-block 1 branch 2 never executed branch 3 never executed #####: 478: buf = (char *)xrealloc(buf, (buf_len + 1) * sizeof(char *)); %%%%%: 478-block 0 call 0 never executed #####: 479: buf[buf_len++] = *str; #####: 480: break; unconditional 0 never executed -: 481: } else { -: 482: /* If '`' advance one char. Otherwise the while -: 483: * below will stop at first char, which is not -: 484: * what we want */ #####: 485: close = *str; #####: 486: str++; #####: 487: buf = (char *)xrealloc(buf, (buf_len + 1) * sizeof(char *)); %%%%%: 487-block 0 call 0 never executed #####: 488: buf[buf_len++] = '`'; unconditional 0 never executed -: 489: } -: 490: } -: 491: -: 492: /* Copy everything until null byte or closing char */ #####: 493: while (*str && *str != close) { %%%%%: 493-block 0 unconditional 0 never executed %%%%%: 493-block 1 branch 1 never executed branch 2 never executed %%%%%: 493-block 2 branch 3 never executed branch 4 never executed #####: 494: buf = (char *)xrealloc(buf, (buf_len + 1) * sizeof(char *)); %%%%%: 494-block 0 call 0 never executed #####: 495: buf[buf_len++] = *(str++); unconditional 0 never executed -: 496: } -: 497: -: 498: /* If the while loop stopped with a null byte, there was -: 499: * no ending close (either ')' or '`')*/ #####: 500: if (!*str) { %%%%%: 500-block 0 branch 0 never executed branch 1 never executed #####: 501: fprintf(stderr, _("%s: Missing '%c'\n"), PROGRAM_NAME, %%%%%: 501-block 0 call 0 never executed call 1 never executed -: 502: close); -: 503: #####: 504: free(buf); #####: 505: buf = (char *)NULL; #####: 506: int i = (int)words; -: 507: #####: 508: while (--i >= 0) unconditional 0 never executed %%%%%: 508-block 0 branch 1 never executed branch 2 never executed #####: 509: free(substr[i]); %%%%%: 509-block 0 unconditional 0 never executed #####: 510: free(substr); -: 511: #####: 512: return (char **)NULL; %%%%%: 512-block 0 unconditional 0 never executed -: 513: } -: 514: -: 515: /* Copy the closing char and add an space: this function -: 516: * takes space as word breaking char, so that everything -: 517: * in the buffer will be copied as one single word */ #####: 518: buf = (char *)xrealloc(buf, (buf_len + 2) * sizeof(char *)); %%%%%: 518-block 0 call 0 never executed #####: 519: buf[buf_len++] = *str; #####: 520: buf[buf_len] = ' '; -: 521: #####: 522: break; unconditional 0 never executed -: 523: #####: 524: case '\'': /* fallthrough */ -: 525: case '"': -: 526: /* If the quote is escaped, it has no special meaning */ #####: 527: if (str_len && *(str - 1) == '\\') { %%%%%: 527-block 0 branch 0 never executed branch 1 never executed %%%%%: 527-block 1 branch 2 never executed branch 3 never executed #####: 528: buf = (char *)xrealloc(buf, (buf_len + 1) * sizeof(char *)); %%%%%: 528-block 0 call 0 never executed #####: 529: buf[buf_len++] = *str; #####: 530: break; unconditional 0 never executed -: 531: } -: 532: -: 533: /* If not escaped, move on to the next char */ #####: 534: quote = *str; #####: 535: str++; -: 536: -: 537: /* Copy into the buffer whatever is after the first quote -: 538: * up to the last quote or NULL */ #####: 539: while (*str && *str != quote) { %%%%%: 539-block 0 unconditional 0 never executed %%%%%: 539-block 1 branch 1 never executed branch 2 never executed %%%%%: 539-block 2 branch 3 never executed branch 4 never executed -: 540: /* If char has special meaning, escape it */ #####: 541: if (is_quote_char(*str)) { %%%%%: 541-block 0 call 0 never executed branch 1 never executed branch 2 never executed #####: 542: buf = (char *)xrealloc(buf, (buf_len + 1) * sizeof(char *)); %%%%%: 542-block 0 call 0 never executed #####: 543: buf[buf_len++] = '\\'; unconditional 0 never executed -: 544: } -: 545: #####: 546: buf = (char *)xrealloc(buf, (buf_len + 1) * sizeof(char *)); %%%%%: 546-block 0 call 0 never executed #####: 547: buf[buf_len++] = *(str++); unconditional 0 never executed -: 548: } -: 549: -: 550: /* The above while breaks with NULL or quote, so that if -: 551: * *str is a null byte there was not ending quote */ #####: 552: if (!*str) { %%%%%: 552-block 0 branch 0 never executed branch 1 never executed #####: 553: fprintf(stderr, _("%s: Missing '%c'\n"), PROGRAM_NAME, quote); %%%%%: 553-block 0 call 0 never executed call 1 never executed -: 554: /* Free the current buffer and whatever was already -: 555: * allocated */ #####: 556: free(buf); #####: 557: buf = (char *)NULL; #####: 558: int i = (int)words; -: 559: #####: 560: while (--i >= 0) unconditional 0 never executed %%%%%: 560-block 0 branch 1 never executed branch 2 never executed #####: 561: free(substr[i]); %%%%%: 561-block 0 unconditional 0 never executed #####: 562: free(substr); #####: 563: return (char **)NULL; %%%%%: 563-block 0 unconditional 0 never executed -: 564: } #####: 565: break; %%%%%: 565-block 0 unconditional 0 never executed -: 566: -: 567: /* TAB, new line char, and space are taken as word breaking -: 568: * characters */ 223: 569: case '\t': -: 570: case '\n': -: 571: case ' ': -: 572: /* If escaped, just copy it into the buffer */ 223: 573: if (str_len && *(str - 1) == '\\') { 223: 573-block 0 branch 0 taken 223 (fallthrough) branch 1 taken 0 223: 573-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 223 #####: 574: buf = (char *)xrealloc(buf, (buf_len + 1) * sizeof(char *)); %%%%%: 574-block 0 call 0 never executed #####: 575: buf[buf_len++] = *str; unconditional 0 never executed -: 576: } else { -: 577: /* If not escaped, break the string */ -: 578: /* Add a terminating null byte to the buffer, and, if -: 579: * not empty, dump the buffer into the substrings -: 580: * array */ 223: 581: buf[buf_len] = '\0'; -: 582: 223: 583: if (buf_len > 0) { 223: 583-block 0 branch 0 taken 223 (fallthrough) branch 1 taken 0 223: 584: substr = (char **)xrealloc(substr, (words + 1) * sizeof(char *)); 223: 584-block 0 call 0 returned 223 223: 585: substr[words] = savestring(buf, buf_len); call 0 returned 223 223: 586: words++; unconditional 0 taken 223 -: 587: } -: 588: -: 589: /* Clear te buffer to get a new string */ 223: 590: memset(buf, '\0', buf_len); 223: 591: buf_len = 0; 223: 591-block 0 unconditional 0 taken 223 -: 592: } 223: 593: break; 223: 593-block 0 unconditional 0 taken 223 -: 594: -: 595: /* If neither a quote nor a breaking word char nor command -: 596: * substitution, just dump it into the buffer */ 1858: 597: default: 1858: 598: buf = (char *)xrealloc(buf, (buf_len + 1) * sizeof(char *)); 1858: 598-block 0 call 0 returned 1858 1858: 599: buf[buf_len++] = *str; 1858: 600: break; unconditional 0 taken 1858 -: 601: } -: 602: 2083: 603: str++; 2083: 604: str_len++; 2083: 604-block 0 unconditional 0 taken 2083 -: 605: } -: 606: -: 607: /* The while loop stops when the null byte is reached, so that the -: 608: * last substring is not printed, but still stored in the buffer. -: 609: * Therefore, we need to add it, if not empty, to our subtrings -: 610: * array */ 500: 611: buf[buf_len] = '\0'; -: 612: 500: 613: if (buf_len > 0) { 500: 613-block 0 branch 0 taken 478 (fallthrough) branch 1 taken 22 478: 614: if (!words) 478: 614-block 0 branch 0 taken 322 (fallthrough) branch 1 taken 156 322: 615: substr = (char **)xcalloc(words + 1, sizeof(char *)); 322: 615-block 0 call 0 returned 322 unconditional 1 taken 322 -: 616: else 156: 617: substr = (char **)xrealloc(substr, (words + 1) * sizeof(char *)); 156: 617-block 0 call 0 returned 156 unconditional 1 taken 156 -: 618: 478: 619: substr[words] = savestring(buf, buf_len); 478: 619-block 0 call 0 returned 478 478: 620: words++; unconditional 0 taken 478 -: 621: } -: 622: 500: 623: free(buf); 500: 624: buf = (char *)NULL; -: 625: 500: 626: if (words) { 500: 626-block 0 branch 0 taken 500 (fallthrough) branch 1 taken 0 -: 627: /* Add a final null string to the array */ 500: 628: substr = (char **)xrealloc(substr, (words + 1) * sizeof(char *)); 500: 628-block 0 call 0 returned 500 500: 629: substr[words] = (char *)NULL; -: 630: 500: 631: args_n = words - 1; 500: 632: return substr; unconditional 0 taken 500 -: 633: } else { #####: 634: args_n = 0; /* Just in case, but I think it's not needed */ #####: 635: return (char **)NULL; %%%%%: 635-block 0 unconditional 0 never executed -: 636: } -: 637:} -: 638: -: 639:/* Return 1 if STR contains only numbers of a range of number, and zero -: 640: * if not */ -: 641:static int function check_fused_param called 181 returned 100% blocks executed 75% 181: 642:check_fused_param(const char *str) -: 643:{ 181: 644: char *p = (char *)str; 181: 645: size_t c = 0, i = 0; 181: 646: int ok = 1; -: 647: 204: 648: while (*p) { 181: 648-block 0 unconditional 0 taken 181 204: 648-block 1 branch 1 taken 199 branch 2 taken 5 (fallthrough) 199*: 649: if (i && *p == '-' && *(p - 1) >= '0' && *(p - 1) <= '9' 199: 649-block 0 branch 0 taken 18 (fallthrough) branch 1 taken 181 18: 649-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 18 %%%%%: 649-block 2 branch 4 never executed branch 5 never executed %%%%%: 649-block 3 branch 6 never executed branch 7 never executed #####: 650: && *(p + 1) >= '1' && *(p + 1) <= '9') { %%%%%: 650-block 0 branch 0 never executed branch 1 never executed %%%%%: 650-block 1 branch 2 never executed branch 3 never executed #####: 651: c++; %%%%%: 651-block 0 unconditional 0 never executed 199: 652: } else if (*p == ' ') { 199: 652-block 0 branch 0 taken 20 (fallthrough) branch 1 taken 179 20: 653: break; 20: 653-block 0 unconditional 0 taken 20 179: 654: } else if (*p < '0' || *p > '9') { 179: 654-block 0 branch 0 taken 152 (fallthrough) branch 1 taken 27 152: 654-block 1 branch 2 taken 129 (fallthrough) branch 3 taken 23 156: 655: ok = 0; 156: 656: break; 156: 656-block 0 unconditional 0 taken 156 -: 657: } 23: 658: p++; 23: 659: i++; 23: 659-block 0 unconditional 0 taken 23 -: 660: } -: 661: 181: 662: if (ok && c <= 1) 181: 662-block 0 branch 0 taken 25 (fallthrough) branch 1 taken 156 25: 662-block 1 branch 2 taken 25 (fallthrough) branch 3 taken 0 25: 663: return 1; 25: 663-block 0 unconditional 0 taken 25 156: 664: return 0; 156: 664-block 0 unconditional 0 taken 156 -: 665:} -: 666: -: 667:static char * function split_fusedcmd called 14 returned 100% blocks executed 73% 14: 668:split_fusedcmd(char *str) -: 669:{ 14: 670: if (!str || !*str || *str == ';' || *str == ':' || *str == '\\') 14: 670-block 0 branch 0 taken 14 (fallthrough) branch 1 taken 0 14: 670-block 1 branch 2 taken 14 (fallthrough) branch 3 taken 0 14: 670-block 2 branch 4 taken 14 (fallthrough) branch 5 taken 0 14: 670-block 3 branch 6 taken 14 (fallthrough) branch 7 taken 0 14: 670-block 4 branch 8 taken 0 (fallthrough) branch 9 taken 14 #####: 671: return (char *)NULL; %%%%%: 671-block 0 unconditional 0 never executed -: 672: 14: 673: char *space = strchr(str, ' '); 14: 674: char *slash = strchr(str, '/'); -: 675: 14: 676: if (!space && slash) /* If "/some/path/" */ 14: 676-block 0 branch 0 taken 6 (fallthrough) branch 1 taken 8 6: 676-block 1 branch 2 taken 2 (fallthrough) branch 3 taken 4 2: 677: return (char *)NULL; 2: 677-block 0 unconditional 0 taken 2 -: 678: 12: 679: if (space && slash && slash < space) /* If "/some/string something" */ 12: 679-block 0 branch 0 taken 8 (fallthrough) branch 1 taken 4 8: 679-block 1 branch 2 taken 5 (fallthrough) branch 3 taken 3 5: 679-block 2 branch 4 taken 0 (fallthrough) branch 5 taken 5 #####: 680: return (char *)NULL; %%%%%: 680-block 0 unconditional 0 never executed -: 681: -: 682: /* The buffer size is the double of STR, just in case each subtr -: 683: * needs to be splitted */ 12: 684: char *buf = (char *)xnmalloc(((strlen(str) * 2) + 2), sizeof(char)); 12: 684-block 0 call 0 returned 12 -: 685: 12: 686: char *p = str, *pp = str; 12: 687: char *q = buf; 12: 688: char *s = (char *)NULL; 12: 689: size_t word_n = 1; 12: 690: size_t c = 0; -: 691: 193: 692: while (*p) { unconditional 0 taken 12 193: 692-block 0 branch 1 taken 181 branch 2 taken 12 (fallthrough) 181: 693: switch(*p) { 181: 693-block 0 branch 0 taken 14 branch 1 taken 0 branch 2 taken 167 14: 694: case ' ': -: 695: /* We only allow splitting for first command word */ 14: 696: s = p; /* Pointer to last space */ 14: 697: if (c && *(p - 1) != ' ' && *(p - 1) != '|' 14: 697-block 0 branch 0 taken 14 (fallthrough) branch 1 taken 0 14: 697-block 1 branch 2 taken 14 (fallthrough) branch 3 taken 0 14: 697-block 2 branch 4 taken 14 (fallthrough) branch 5 taken 0 14: 698: && *(p - 1) != '&' && *(p - 1) != ';') 14: 698-block 0 branch 0 taken 14 (fallthrough) branch 1 taken 0 14: 698-block 1 branch 2 taken 14 (fallthrough) branch 3 taken 0 14: 699: word_n++; 14: 699-block 0 unconditional 0 taken 14 14: 700: break; 14: 700-block 0 unconditional 0 taken 14 #####: 701: case '|': /* fallthrough */ -: 702: case '&': /* fallthrough */ #####: 703: case ';': word_n = 1; break; %%%%%: 703-block 0 unconditional 0 never executed 167: 704: default: break; 167: 704-block 0 unconditional 0 taken 167 -: 705: } -: 706: -: 707: /* Transform "cmdeln" into "cmd eln" */ 181: 708: if (check_fused_param(p)) { 181: 708-block 0 call 0 returned 181 branch 1 taken 25 (fallthrough) branch 2 taken 156 -: 709: /* If a number, move from last to next space/nul looking for -: 710: * a slash. If found, do nothing */ 25: 711: if (s) { 25: 711-block 0 branch 0 taken 21 (fallthrough) branch 1 taken 4 21: 712: if (word_n > 1) { 21: 712-block 0 branch 0 taken 21 (fallthrough) branch 1 taken 0 21: 713: *(q++) = *(p++); 21: 714: continue; 21: 714-block 0 unconditional 0 taken 21 -: 715: } -: 716: #####: 717: int _cont = 0; #####: 718: char *ss = s + 1; #####: 719: while (*ss && *ss != ' ') { %%%%%: 719-block 0 unconditional 0 never executed %%%%%: 719-block 1 branch 1 never executed branch 2 never executed %%%%%: 719-block 2 branch 3 never executed branch 4 never executed #####: 720: if (*ss == '/') { %%%%%: 720-block 0 branch 0 never executed branch 1 never executed #####: 721: _cont = 1; #####: 722: break; %%%%%: 722-block 0 unconditional 0 never executed -: 723: } #####: 724: ss++; %%%%%: 724-block 0 unconditional 0 never executed -: 725: } #####: 726: if (_cont) { %%%%%: 726-block 0 branch 0 never executed branch 1 never executed #####: 727: *(q++) = *(p++); #####: 728: continue; %%%%%: 728-block 0 unconditional 0 never executed -: 729: } -: 730: } -: 731: 4: 732: char tmp = *p; 4: 733: *p = '\0'; -: 734: 4*: 735: if (!is_internal_c(pp)) { 4: 735-block 0 call 0 returned 4 branch 1 taken 0 (fallthrough) branch 2 taken 4 #####: 736: *p = tmp; #####: 737: *(q++) = *(p++); #####: 738: continue; %%%%%: 738-block 0 unconditional 0 never executed -: 739: } -: 740: 4: 741: *p = tmp; 4: 742: *(q++) = ' '; 4: 743: *(q++) = *(p++); 4: 743-block 0 unconditional 0 taken 4 -: 744: } -: 745: -: 746: else { 156*: 747: if (*p == ' ' && *(p + 1)) 156: 747-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 156 %%%%%: 747-block 1 branch 2 never executed branch 3 never executed #####: 748: pp = p + 1; %%%%%: 748-block 0 unconditional 0 never executed 156: 749: *(q++) = *(p++); 156: 749-block 0 unconditional 0 taken 156 -: 750: } -: 751: 160: 752: c++; 160: 752-block 0 unconditional 0 taken 160 -: 753: } -: 754: 12: 755: *q = '\0'; -: 756: -: 757: /* Readjust the buffer size */ 12: 758: size_t len = strlen(buf); 12: 759: buf = (char *)xrealloc(buf, (len + 1) * sizeof(char)); 12: 759-block 0 call 0 returned 12 12: 760: return buf; unconditional 0 taken 12 -: 761:} -: 762: -: 763:/* -: 764: * This function is one of the keys of CliFM. It will perform a series of -: 765: * actions: -: 766: * 1) Take the string stored by readline and get its substrings without -: 767: * spaces. -: 768: * 2) In case of user defined variable (var=value), it will pass the -: 769: * whole string to exec_cmd(), which will take care of storing the -: 770: * variable; -: 771: * 3) If the input string begins with ';' or ':' the whole string is -: 772: * send to exec_cmd(), where it will be directly executed by the system -: 773: * shell (via launch_execle()) to prevent all of the expansions made -: 774: * here. -: 775: * 4) The following expansions (especific to CLiFM) are performed here: -: 776: * ELN's, "sel" keyword, ranges of numbers (ELN's), pinned dir and -: 777: * bookmark names, and, for internal commands only, tilde, braces, -: 778: * wildcards, command and paramenter substitution, and regex expansion -: 779: * are performed here as well. -: 780: * These expansions are the most import part of this function. -: 781: */ -: 782: -: 783:/* NOTE: Though file names could consist of everything except of slash -: 784: * and null characters, POSIX.1 recommends restricting file names to -: 785: * consist of the following characters: letters (a-z, A-Z), numbers -: 786: * (0-9), period (.), dash (-), and underscore ( _ ). -: 787: -: 788: * NOTE 2: There is no any need to pass anything to this function, since -: 789: * the input string I need here is already in the readline buffer. So, -: 790: * instead of taking the buffer from a function parameter (str) I could -: 791: * simply use rl_line_buffer. However, since I use this function to -: 792: * parse other strings, like history lines, I need to keep the str -: 793: * argument */ -: 794:char ** function parse_input_str called 503 returned 100% blocks executed 53% 503: 795:parse_input_str(char *str) -: 796:{ 503: 797: register size_t i = 0; 503: 798: int fusedcmd_ok = 0; -: 799: -: 800: /** ###################### */ -: 801: /* Before splitting 'CMDNUM' into 'CMD NUM', make sure CMDNUM is not -: 802: * a cmd in PATH (for example, md5sum) */ 503: 803: if (digit_found(str) && !is_bin_cmd(str)) { 503: 803-block 0 call 0 returned 503 branch 1 taken 15 (fallthrough) branch 2 taken 488 15: 803-block 1 call 3 returned 15 branch 4 taken 14 (fallthrough) branch 5 taken 1 14: 804: char *p = split_fusedcmd(str); 14: 804-block 0 call 0 returned 14 14: 805: if (p) { branch 0 taken 12 (fallthrough) branch 1 taken 2 12: 806: fusedcmd_ok = 1; 12: 807: str = p; 12: 808: p = (char *)NULL; 12: 808-block 0 unconditional 0 taken 12 -: 809: } -: 810: } -: 811: /** ###################### */ -: 812: -: 813: /* ######################################## -: 814: * # 0) CHECK FOR SPECIAL FUNCTIONS # -: 815: * ########################################*/ -: 816: 503: 817: int chaining = 0, cond_cmd = 0, send_shell = 0; -: 818: -: 819: /* ########################### -: 820: * # 0.a) RUN AS EXTERNAL # -: 821: * ###########################*/ -: 822: -: 823: /* If invoking a command via ';' or ':' set the send_shell flag to -: 824: * true and send the whole string to exec_cmd(), in which case no -: 825: * expansion is made: the command is send to the system shell as -: 826: * is. */ 503: 827: if (*str == ';' || *str == ':') 503: 827-block 0 branch 0 taken 501 (fallthrough) branch 1 taken 2 501: 827-block 1 branch 2 taken 1 (fallthrough) branch 3 taken 500 3: 828: send_shell = 1; 3: 828-block 0 unconditional 0 taken 3 -: 829: 503: 830: if (!send_shell) { 503: 830-block 0 branch 0 taken 500 (fallthrough) branch 1 taken 3 2583: 831: for (i = 0; str[i]; i++) { 500: 831-block 0 unconditional 0 taken 500 2083: 831-block 1 unconditional 1 taken 2083 2583: 831-block 2 branch 2 taken 2083 branch 3 taken 500 (fallthrough) -: 832: -: 833: /* ################################## -: 834: * # 0.b) CONDITIONAL EXECUTION # -: 835: * ##################################*/ -: 836: -: 837: /* Check for chained commands (cmd1;cmd2) */ 2083*: 838: if (!chaining && str[i] == ';' && i > 0 && str[i - 1] != '\\') 2083: 838-block 0 branch 0 taken 2083 (fallthrough) branch 1 taken 0 2083: 838-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 2083 %%%%%: 838-block 2 branch 4 never executed branch 5 never executed %%%%%: 838-block 3 branch 6 never executed branch 7 never executed #####: 839: chaining = 1; %%%%%: 839-block 0 unconditional 0 never executed -: 840: -: 841: /* Check for conditional execution (cmd1 && cmd 2)*/ 2083: 842: if (!cond_cmd && str[i] == '&' && i > 0 && str[i - 1] != '\\' 2083: 842-block 0 branch 0 taken 2083 (fallthrough) branch 1 taken 0 2083: 842-block 1 branch 2 taken 2 (fallthrough) branch 3 taken 2081 2: 842-block 2 branch 4 taken 2 (fallthrough) branch 5 taken 0 2: 842-block 3 branch 6 taken 2 (fallthrough) branch 7 taken 0 2*: 843: && str[i + 1] && str[i + 1] == '&') 2: 843-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 2 %%%%%: 843-block 1 branch 2 never executed branch 3 never executed #####: 844: cond_cmd = 1; %%%%%: 844-block 0 unconditional 0 never executed -: 845: -: 846: /* ################################## -: 847: * # 0.c) USER DEFINED VARIABLE # -: 848: * ##################################*/ -: 849: -: 850: /* If user defined variable send the whole string to -: 851: * exec_cmd(), which will take care of storing the -: 852: * variable. */ 2083*: 853: if (!(flags & IS_USRVAR_DEF) && str[i] == '=' && i > 0 2083: 853-block 0 branch 0 taken 2083 (fallthrough) branch 1 taken 0 2083: 853-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 2083 %%%%%: 853-block 2 branch 4 never executed branch 5 never executed #####: 854: && str[i - 1] != '\\' && str[0] != '=') { %%%%%: 854-block 0 branch 0 never executed branch 1 never executed %%%%%: 854-block 1 branch 2 never executed branch 3 never executed -: 855: /* Remove leading spaces. This: ' a="test"' should be -: 856: * taken as a valid variable declaration */ #####: 857: char *p = str; #####: 858: while (*p == ' ' || *p == '\t') %%%%%: 858-block 0 unconditional 0 never executed %%%%%: 858-block 1 branch 1 never executed branch 2 never executed %%%%%: 858-block 2 branch 3 never executed branch 4 never executed #####: 859: p++; %%%%%: 859-block 0 unconditional 0 never executed -: 860: -: 861: /* If first non-space is a number, it's not a variable -: 862: * name */ #####: 863: if (!_ISDIGIT(*p)) { %%%%%: 863-block 0 branch 0 never executed branch 1 never executed #####: 864: int space_found = 0; -: 865: /* If there are no spaces before '=', take it as a -: 866: * variable. This check is done in order to avoid -: 867: * taking as a variable things like: -: 868: * 'ls -color=auto' */ #####: 869: while (*p != '=') { %%%%%: 869-block 0 unconditional 0 never executed %%%%%: 869-block 1 branch 1 never executed branch 2 never executed #####: 870: if (*(p++) == ' ') %%%%%: 870-block 0 branch 0 never executed branch 1 never executed #####: 871: space_found = 1; %%%%%: 871-block 0 unconditional 0 never executed -: 872: } -: 873: #####: 874: if (!space_found) %%%%%: 874-block 0 branch 0 never executed branch 1 never executed #####: 875: flags |= IS_USRVAR_DEF; %%%%%: 875-block 0 unconditional 0 never executed -: 876: } -: 877: #####: 878: p = (char *)NULL; %%%%%: 878-block 0 unconditional 0 never executed -: 879: } -: 880: } -: 881: } -: 882: -: 883: /* If chained commands, check each of them. If at least one of them -: 884: * is internal, take care of the job (the system shell does not know -: 885: * our internal commands and therefore cannot execute them); else, -: 886: * if no internal command is found, let it to the system shell */ 503: 887: if (chaining || cond_cmd) { 503: 887-block 0 branch 0 taken 503 (fallthrough) branch 1 taken 0 503: 887-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 503 -: 888: /* User defined variables are always internal, so that there is -: 889: * no need to check whatever else is in the command string */ #####: 890: if (flags & IS_USRVAR_DEF) { %%%%%: 890-block 0 branch 0 never executed branch 1 never executed #####: 891: exec_chained_cmds(str); %%%%%: 891-block 0 call 0 never executed #####: 892: if (fusedcmd_ok) branch 0 never executed branch 1 never executed #####: 893: free(str); %%%%%: 893-block 0 unconditional 0 never executed #####: 894: return (char **)NULL; %%%%%: 894-block 0 unconditional 0 never executed -: 895: } -: 896: #####: 897: register size_t j = 0; #####: 898: size_t str_len = strlen(str), len = 0, internal_ok = 0; #####: 899: char *buf = (char *)NULL; -: 900: -: 901: /* Get each word (cmd) in STR */ #####: 902: buf = (char *)xcalloc(str_len + 1, sizeof(char)); %%%%%: 902-block 0 call 0 never executed #####: 903: for (j = 0; j < str_len; j++) { unconditional 0 never executed %%%%%: 903-block 0 branch 1 never executed branch 2 never executed #####: 904: while (str[j] && str[j] != ' ' && str[j] != ';' && str[j] != '&') { %%%%%: 904-block 0 unconditional 0 never executed %%%%%: 904-block 1 branch 1 never executed branch 2 never executed %%%%%: 904-block 2 branch 3 never executed branch 4 never executed %%%%%: 904-block 3 branch 5 never executed branch 6 never executed %%%%%: 904-block 4 branch 7 never executed branch 8 never executed #####: 905: buf[len++] = str[j++]; %%%%%: 905-block 0 unconditional 0 never executed -: 906: } -: 907: #####: 908: if (strcmp(buf, "&&") != 0) { %%%%%: 908-block 0 branch 0 never executed branch 1 never executed #####: 909: if (is_internal_c(buf)) { %%%%%: 909-block 0 call 0 never executed branch 1 never executed branch 2 never executed #####: 910: internal_ok = 1; #####: 911: break; %%%%%: 911-block 0 unconditional 0 never executed -: 912: } -: 913: } -: 914: #####: 915: memset(buf, '\0', len); #####: 916: len = 0; %%%%%: 916-block 0 unconditional 0 never executed -: 917: } -: 918: #####: 919: free(buf); #####: 920: buf = (char *)NULL; -: 921: #####: 922: if (internal_ok) { %%%%%: 922-block 0 branch 0 never executed branch 1 never executed #####: 923: exec_chained_cmds(str); %%%%%: 923-block 0 call 0 never executed #####: 924: if (fusedcmd_ok) branch 0 never executed branch 1 never executed #####: 925: free(str); %%%%%: 925-block 0 unconditional 0 never executed #####: 926: return (char **)NULL; %%%%%: 926-block 0 unconditional 0 never executed -: 927: } -: 928: } -: 929: 503: 930: if (flags & IS_USRVAR_DEF || send_shell) { 503: 930-block 0 branch 0 taken 503 (fallthrough) branch 1 taken 0 503: 930-block 1 branch 2 taken 3 (fallthrough) branch 3 taken 500 -: 931: /* Remove leading spaces, again */ 3: 932: char *p = str; 3: 933: while (*p == ' ' || *p == '\t') 3: 933-block 0 unconditional 0 taken 3 3: 933-block 1 branch 1 taken 0 branch 2 taken 3 (fallthrough) 3: 933-block 2 branch 3 taken 0 branch 4 taken 3 (fallthrough) #####: 934: p++; %%%%%: 934-block 0 unconditional 0 never executed -: 935: 3: 936: args_n = 0; -: 937: 3: 938: char **cmd = (char **)NULL; 3: 939: cmd = (char **)xnmalloc(2, sizeof(char *)); 3: 939-block 0 call 0 returned 3 3: 940: cmd[0] = savestring(p, strlen(p)); call 0 returned 3 3: 941: cmd[1] = (char *)NULL; -: 942: 3: 943: p = (char *)NULL; -: 944: 3: 945: if (fusedcmd_ok) branch 0 taken 0 (fallthrough) branch 1 taken 3 #####: 946: free(str); %%%%%: 946-block 0 unconditional 0 never executed -: 947: 3: 948: return cmd; 3: 948-block 0 unconditional 0 taken 3 -: 949: /* If ";cmd" or ":cmd" the whole input line will be send to -: 950: * exec_cmd() and will be executed by the system shell via -: 951: * execle(). Since we don't run split_str() here, dequoting -: 952: * and deescaping is performed directly by the system shell */ -: 953: } -: 954: -: 955: /* ################################################ -: 956: * # 1) SPLIT INPUT STRING INTO SUBSTRINGS # -: 957: * ################################################ */ -: 958: -: 959: /* split_str() returns an array of strings without leading, -: 960: * terminating and double spaces. */ 500: 961: char **substr = split_str(str); 500: 961-block 0 call 0 returned 500 -: 962: -: 963: /** ###################### */ 500: 964: if (fusedcmd_ok) /* Just in case split_fusedcmd returned NULL */ branch 0 taken 12 (fallthrough) branch 1 taken 488 12: 965: free(str); 12: 965-block 0 unconditional 0 taken 12 -: 966: /** ###################### */ -: 967: -: 968: /* NOTE: isspace() not only checks for space, but also for new line, -: 969: * carriage return, vertical and horizontal TAB. Be careful when -: 970: * replacing this function. */ -: 971: 500: 972: if (!substr) 500: 972-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 500 #####: 973: return (char **)NULL; %%%%%: 973-block 0 unconditional 0 never executed -: 974: -: 975: /* Handle background/foreground process */ 500: 976: bg_proc = 0; -: 977: 500: 978: if (*substr[args_n] == '&' && !*(substr[args_n] + 1)) { 500: 978-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 499 1: 978-block 1 branch 2 taken 1 (fallthrough) branch 3 taken 0 1: 979: bg_proc = 1; 1: 980: free(substr[args_n]); 1: 981: substr[args_n--] = (char *)NULL; 1: 981-block 0 unconditional 0 taken 1 -: 982: } else { 499: 983: size_t len = strlen(substr[args_n]); 499: 984: if (substr[args_n][len - 1] == '&' && !substr[args_n][len]) { 499: 984-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 498 1: 984-block 1 branch 2 taken 1 (fallthrough) branch 3 taken 0 1: 985: substr[args_n][len - 1] = '\0'; 1: 986: bg_proc = 1; 1: 986-block 0 unconditional 0 taken 1 -: 987: } -: 988: } -: 989: -: 990: /* ###################### -: 991: * # TRASH AS RM # -: 992: * ###################### */ -: 993:#ifndef _NO_TRASH 500*: 994: if (tr_as_rm && substr[0] && *substr[0] == 'r' && !substr[0][1]) { 500: 994-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 500 %%%%%: 994-block 1 branch 2 never executed branch 3 never executed %%%%%: 994-block 2 branch 4 never executed branch 5 never executed %%%%%: 994-block 3 branch 6 never executed branch 7 never executed #####: 995: substr[0] = (char *)xrealloc(substr[0], 3 * sizeof(char)); %%%%%: 995-block 0 call 0 never executed #####: 996: *substr[0] = 't'; #####: 997: substr[0][1] = 'r'; #####: 998: substr[0][2] = '\0'; unconditional 0 never executed -: 999: } -: 1000:#endif -: 1001: /* ############################## -: 1002: * # 2) BUILTIN EXPANSIONS # -: 1003: * ############################## -: 1004: -: 1005: * Ranges, sel, ELN, pinned dirs, bookmarks, and internal variables. -: 1006: * These expansions are specific to CliFM. To be able to use them -: 1007: * even with external commands, they must be expanded here, before -: 1008: * sending the input string, in case the command is external, to -: 1009: * the system shell */ -: 1010: 500: 1011: is_sel = 0, sel_is_last = 0; -: 1012: 500: 1013: size_t int_array_max = 10, ranges_ok = 0; 500: 1014: int *range_array = (int *)xnmalloc(int_array_max, sizeof(int)); 500: 1014-block 0 call 0 returned 500 -: 1015: 1200: 1016: for (i = 0; i <= args_n; i++) { unconditional 0 taken 500 700: 1016-block 0 unconditional 1 taken 700 1200: 1016-block 1 branch 2 taken 700 branch 3 taken 500 (fallthrough) 700*: 1017: if (!substr[i]) 700: 1017-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 700 #####: 1018: continue; %%%%%: 1018-block 0 unconditional 0 never executed -: 1019: 700: 1020: register size_t j = 0; -: 1021: /* Replace . and .. by absolute paths */ 700: 1022: if (*substr[i] == '.' && (!substr[i][1] || (substr[i][1] == '.' 700: 1022-block 0 branch 0 taken 16 (fallthrough) branch 1 taken 684 16: 1022-block 1 branch 2 taken 13 (fallthrough) branch 3 taken 3 13: 1022-block 2 branch 4 taken 12 (fallthrough) branch 5 taken 1 12: 1023: && !substr[i][2]))) { 12: 1023-block 0 branch 0 taken 11 (fallthrough) branch 1 taken 1 14: 1024: char *tmp = (char *)NULL; 14: 1025: tmp = realpath(substr[i], NULL); 14: 1025-block 0 call 0 returned 14 14: 1026: substr[i] = (char *)xrealloc(substr[i], (strlen(tmp) + 1) call 0 returned 14 -: 1027: * sizeof(char)); 14: 1028: strcpy(substr[i], tmp); 14: 1029: free(tmp); unconditional 0 taken 14 -: 1030: } -: 1031: -: 1032: /* ###################################### -: 1033: * # 2.a) FASTBACK EXPANSION # -: 1034: * ###################################### */ -: 1035: 700: 1036: if (*substr[i] == '.' && substr[i][1] == '.' && substr[i][2] == '.') { 700: 1036-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 698 2: 1036-block 1 branch 2 taken 1 (fallthrough) branch 3 taken 1 1: 1036-block 2 branch 4 taken 1 (fallthrough) branch 5 taken 0 1: 1037: char *tmp = fastback(substr[i]); 1: 1037-block 0 call 0 returned 1 1: 1038: if (tmp) { branch 0 taken 1 (fallthrough) branch 1 taken 0 1: 1039: substr[i] = (char *)xrealloc(substr[i], (strlen(tmp) + 1) 1: 1039-block 0 call 0 returned 1 -: 1040: * sizeof(char)); 1: 1041: strcpy(substr[i], tmp); 1: 1042: free(tmp); unconditional 0 taken 1 -: 1043: } -: 1044: } -: 1045: -: 1046: /* ###################################### -: 1047: * # 2.b) PINNED DIR EXPANSION # -: 1048: * ###################################### */ -: 1049: 700: 1050: if (*substr[i] == ',' && !substr[i][1] && pinned_dir) { 700: 1050-block 0 branch 0 taken 3 (fallthrough) branch 1 taken 697 3: 1050-block 1 branch 2 taken 3 (fallthrough) branch 3 taken 0 3: 1050-block 2 branch 4 taken 3 (fallthrough) branch 5 taken 0 3: 1051: substr[i] = (char *)xrealloc(substr[i], (strlen(pinned_dir) + 1) 3: 1051-block 0 call 0 returned 3 -: 1052: * sizeof(char)); 3: 1053: strcpy(substr[i], pinned_dir); unconditional 0 taken 3 -: 1054: } -: 1055: -: 1056: /* ###################################### -: 1057: * # 2.c) BOOKMARKS EXPANSION # -: 1058: * ###################################### */ -: 1059: -: 1060: /* Expand bookmark names into paths */ 700: 1061: if (expand_bookmarks) { 700: 1061-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 700 #####: 1062: int bm_exp = 0; -: 1063: #####: 1064: for (j = 0; j < bm_n; j++) { %%%%%: 1064-block 0 unconditional 0 never executed %%%%%: 1064-block 1 unconditional 1 never executed %%%%%: 1064-block 2 branch 2 never executed branch 3 never executed #####: 1065: if (bookmarks[j].name && *substr[i] == *bookmarks[j].name %%%%%: 1065-block 0 branch 0 never executed branch 1 never executed %%%%%: 1065-block 1 branch 2 never executed branch 3 never executed #####: 1066: && strcmp(substr[i], bookmarks[j].name) == 0) { %%%%%: 1066-block 0 branch 0 never executed branch 1 never executed -: 1067: -: 1068: /* Do not expand bookmark names that conflicts -: 1069: * with a file name in CWD */ #####: 1070: int conflict = 0, k = (int)files; #####: 1071: while (--k >= 0) { %%%%%: 1071-block 0 unconditional 0 never executed %%%%%: 1071-block 1 branch 1 never executed branch 2 never executed #####: 1072: if (*bookmarks[j].name == *file_info[k].name %%%%%: 1072-block 0 branch 0 never executed branch 1 never executed #####: 1073: && strcmp(bookmarks[j].name, file_info[k].name) == 0) { %%%%%: 1073-block 0 branch 0 never executed branch 1 never executed #####: 1074: conflict = 1; #####: 1075: break; %%%%%: 1075-block 0 unconditional 0 never executed -: 1076: } -: 1077: } -: 1078: #####: 1079: if (!conflict && bookmarks[j].path) { %%%%%: 1079-block 0 branch 0 never executed branch 1 never executed %%%%%: 1079-block 1 branch 2 never executed branch 3 never executed #####: 1080: substr[i] = (char *)xrealloc(substr[i], #####: 1081: (strlen(bookmarks[j].path) + 1) * sizeof(char)); %%%%%: 1081-block 0 call 0 never executed #####: 1082: strcpy(substr[i], bookmarks[j].path); -: 1083: #####: 1084: bm_exp = 1; -: 1085: #####: 1086: break; unconditional 0 never executed -: 1087: } -: 1088: } -: 1089: } -: 1090: -: 1091: /* Do not perform further checks on the expanded bookmark */ #####: 1092: if (bm_exp) %%%%%: 1092-block 0 branch 0 never executed branch 1 never executed #####: 1093: continue; %%%%%: 1093-block 0 unconditional 0 never executed -: 1094: } -: 1095: -: 1096: /* ############################################# */ -: 1097: 700: 1098: size_t substr_len = strlen(substr[i]); -: 1099: -: 1100: /* Check for ranges */ 805: 1101: for (j = 0; substr[i][j]; j++) { 700: 1101-block 0 unconditional 0 taken 700 105: 1101-block 1 unconditional 1 taken 105 805: 1101-block 2 branch 2 taken 732 branch 3 taken 73 (fallthrough) -: 1102: /* If some alphabetic char, besides '-', is found in the -: 1103: * string, we have no range */ 732: 1104: if (substr[i][j] != '-' && !_ISDIGIT(substr[i][j])) 732: 1104-block 0 branch 0 taken 712 (fallthrough) branch 1 taken 20 712: 1104-block 1 branch 2 taken 627 (fallthrough) branch 3 taken 85 627: 1105: break; 627: 1105-block 0 unconditional 0 taken 627 -: 1106: -: 1107: /* If a range is found, store its index */ 105: 1108: if (j > 0 && j < substr_len && substr[i][j] == '-' && 105: 1108-block 0 branch 0 taken 24 (fallthrough) branch 1 taken 81 24: 1108-block 1 branch 2 taken 24 (fallthrough) branch 3 taken 0 24: 1108-block 2 branch 4 taken 9 (fallthrough) branch 5 taken 15 9: 1109: _ISDIGIT(substr[i][j - 1]) && _ISDIGIT(substr[i][j + 1])) 9: 1109-block 0 branch 0 taken 4 (fallthrough) branch 1 taken 5 4: 1109-block 1 branch 2 taken 4 (fallthrough) branch 3 taken 0 4: 1110: if (ranges_ok < int_array_max) 4: 1110-block 0 branch 0 taken 4 (fallthrough) branch 1 taken 0 4: 1111: range_array[ranges_ok++] = (int)i; 4: 1111-block 0 unconditional 0 taken 4 -: 1112: } -: 1113: -: 1114: /* Expand 'sel' only as an argument, not as command */ 700: 1115: if (i > 0 && *substr[i] == 's' && strcmp(substr[i], "sel") == 0) 700: 1115-block 0 branch 0 taken 200 (fallthrough) branch 1 taken 500 200: 1115-block 1 branch 2 taken 18 (fallthrough) branch 3 taken 182 18: 1115-block 2 branch 4 taken 9 (fallthrough) branch 5 taken 9 9: 1116: is_sel = (short)i; 9: 1116-block 0 unconditional 0 taken 9 -: 1117: } -: 1118: -: 1119: /* #################################### -: 1120: * # 2.d) RANGES EXPANSION # -: 1121: * ####################################*/ -: 1122: -: 1123: /* Expand expressions like "1-3" to "1 2 3" if all the numbers in -: 1124: * the range correspond to an ELN */ -: 1125: 500: 1126: if (ranges_ok) { 500: 1126-block 0 branch 0 taken 4 (fallthrough) branch 1 taken 496 4: 1127: size_t old_ranges_n = 0; 4: 1128: register size_t r = 0; -: 1129: 8: 1130: for (r = 0; r < ranges_ok; r++) { 4: 1130-block 0 unconditional 0 taken 4 8: 1130-block 1 branch 1 taken 4 branch 2 taken 4 (fallthrough) 4: 1131: size_t ranges_n = 0; 4: 1132: int *ranges = expand_range(substr[range_array[r] + 4: 1133: (int)old_ranges_n], 1); 4: 1133-block 0 call 0 returned 4 4: 1134: if (ranges) { branch 0 taken 4 (fallthrough) branch 1 taken 0 4: 1135: register size_t j = 0; -: 1136: 18: 1137: for (ranges_n = 0; ranges[ranges_n]; ranges_n++); 4: 1137-block 0 unconditional 0 taken 4 14: 1137-block 1 unconditional 1 taken 14 18: 1137-block 2 branch 2 taken 14 branch 3 taken 4 (fallthrough) -: 1138: 4: 1139: char **ranges_cmd = (char **)NULL; 4: 1140: ranges_cmd = (char **)xcalloc(args_n + ranges_n + 2, 4: 1140-block 0 call 0 returned 4 -: 1141: sizeof(char *)); -: 1142: 8: 1143: for (i = 0; i < (size_t)range_array[r] + old_ranges_n; i++) unconditional 0 taken 4 8: 1143-block 0 branch 1 taken 4 branch 2 taken 4 (fallthrough) 4: 1144: ranges_cmd[j++] = savestring(substr[i], strlen(substr[i])); 4: 1144-block 0 call 0 returned 4 unconditional 1 taken 4 -: 1145: 18: 1146: for (i = 0; i < ranges_n; i++) { 4: 1146-block 0 unconditional 0 taken 4 18: 1146-block 1 branch 1 taken 14 branch 2 taken 4 (fallthrough) 14*: 1147: ranges_cmd[j] = (char *)xcalloc((size_t)DIGINUM(ranges[i]) 14: 1147-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 14 %%%%%: 1147-block 1 unconditional 2 never executed 14: 1147-block 2 unconditional 3 taken 14 14: 1147-block 3 call 4 returned 14 #####: 1148: + 1, sizeof(int)); %%%%%: 1148-block 0 branch 0 never executed branch 1 never executed %%%%%: 1148-block 1 branch 2 never executed branch 3 never executed %%%%%: 1148-block 2 branch 4 never executed branch 5 never executed %%%%%: 1148-block 3 branch 6 never executed branch 7 never executed %%%%%: 1148-block 4 branch 8 never executed branch 9 never executed %%%%%: 1148-block 5 branch 10 never executed branch 11 never executed %%%%%: 1148-block 6 branch 12 never executed branch 13 never executed %%%%%: 1148-block 7 branch 14 never executed branch 15 never executed %%%%%: 1148-block 8 unconditional 16 never executed %%%%%: 1148-block 9 unconditional 17 never executed %%%%%: 1148-block 10 unconditional 18 never executed %%%%%: 1148-block 11 unconditional 19 never executed %%%%%: 1148-block 12 unconditional 20 never executed %%%%%: 1148-block 13 unconditional 21 never executed %%%%%: 1148-block 14 unconditional 22 never executed %%%%%: 1148-block 15 unconditional 23 never executed %%%%%: 1148-block 16 unconditional 24 never executed %%%%%: 1148-block 17 unconditional 25 never executed %%%%%: 1148-block 18 unconditional 26 never executed %%%%%: 1148-block 19 unconditional 27 never executed %%%%%: 1148-block 20 unconditional 28 never executed %%%%%: 1148-block 21 unconditional 29 never executed %%%%%: 1148-block 22 unconditional 30 never executed %%%%%: 1148-block 23 unconditional 31 never executed 14: 1149: sprintf(ranges_cmd[j++], "%d", ranges[i]); unconditional 0 taken 14 -: 1150: } -: 1151: 4: 1152: for (i = (size_t)range_array[r] + old_ranges_n + 1; 4: 1152-block 0 unconditional 0 taken 4 4*: 1153: i <= args_n; i++) { 4: 1153-block 0 branch 0 taken 0 branch 1 taken 4 (fallthrough) #####: 1154: ranges_cmd[j++] = savestring(substr[i], unconditional 0 never executed #####: 1155: strlen(substr[i])); %%%%%: 1155-block 0 call 0 never executed -: 1156: } -: 1157: 4: 1158: ranges_cmd[j] = NULL; 4: 1159: free(ranges); -: 1160: 12: 1161: for (i = 0; i <= args_n; i++) 4: 1161-block 0 unconditional 0 taken 4 12: 1161-block 1 branch 1 taken 8 branch 2 taken 4 (fallthrough) 8: 1162: free(substr[i]); 8: 1162-block 0 unconditional 0 taken 8 -: 1163: 4: 1164: substr = (char **)xrealloc(substr, (args_n + ranges_n + 2) 4: 1164-block 0 call 0 returned 4 -: 1165: * sizeof(char *)); -: 1166: 22: 1167: for (i = 0; i < j; i++) { unconditional 0 taken 4 22: 1167-block 0 branch 1 taken 18 branch 2 taken 4 (fallthrough) 18: 1168: substr[i] = savestring(ranges_cmd[i], strlen(ranges_cmd[i])); 18: 1168-block 0 call 0 returned 18 18: 1169: free(ranges_cmd[i]); unconditional 0 taken 18 -: 1170: } -: 1171: 4: 1172: free(ranges_cmd); 4: 1173: args_n = j - 1; 4: 1173-block 0 unconditional 0 taken 4 -: 1174: } -: 1175: 4: 1176: old_ranges_n += (ranges_n - 1); 4: 1176-block 0 unconditional 0 taken 4 -: 1177: } -: 1178: } -: 1179: 500: 1180: free(range_array); -: 1181: -: 1182: /* ########################## -: 1183: * # 2.e) SEL EXPANSION # -: 1184: * ##########################*/ -: 1185: -: 1186: /* if (is_sel && *substr[0] != '/') { */ 500: 1187: if (is_sel) { 500: 1187-block 0 branch 0 taken 9 (fallthrough) branch 1 taken 491 9: 1188: if ((size_t)is_sel == args_n) 9: 1188-block 0 branch 0 taken 8 (fallthrough) branch 1 taken 1 8: 1189: sel_is_last = 1; 8: 1189-block 0 unconditional 0 taken 8 -: 1190: 9: 1191: if (sel_n) { 9: 1191-block 0 branch 0 taken 9 (fallthrough) branch 1 taken 0 9: 1192: register size_t j = 0; 9: 1193: char **sel_array = (char **)NULL; 9: 1194: sel_array = (char **)xnmalloc(args_n + sel_n + 2, sizeof(char *)); 9: 1194-block 0 call 0 returned 9 -: 1195: 18: 1196: for (i = 0; i < (size_t)is_sel; i++) { unconditional 0 taken 9 9: 1196-block 0 unconditional 1 taken 9 18: 1196-block 1 branch 2 taken 9 branch 3 taken 9 (fallthrough) 9*: 1197: if (!substr[i]) 9: 1197-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 9 #####: 1198: continue; %%%%%: 1198-block 0 unconditional 0 never executed 9: 1199: sel_array[j++] = savestring(substr[i], strlen(substr[i])); 9: 1199-block 0 call 0 returned 9 unconditional 1 taken 9 -: 1200: } -: 1201: 29: 1202: for (i = 0; i < sel_n; i++) { 9: 1202-block 0 unconditional 0 taken 9 20: 1202-block 1 unconditional 1 taken 20 29: 1202-block 2 branch 2 taken 20 branch 3 taken 9 (fallthrough) -: 1203: /* Escape selected file names and copy them into tmp -: 1204: * array */ 20: 1205: char *esc_str = escape_str(sel_elements[i]); 20: 1205-block 0 call 0 returned 20 20: 1206: if (esc_str) { branch 0 taken 20 (fallthrough) branch 1 taken 0 20: 1207: sel_array[j++] = savestring(esc_str, strlen(esc_str)); 20: 1207-block 0 call 0 returned 20 20: 1208: free(esc_str); 20: 1209: esc_str = (char *)NULL; unconditional 0 taken 20 -: 1210: } else { #####: 1211: fprintf(stderr, _("%s: %s: Error quoting file name\n"), call 0 never executed #####: 1212: PROGRAM_NAME, sel_elements[j]); %%%%%: 1212-block 0 call 0 never executed -: 1213: /* Free elements selected thus far and and all the -: 1214: * input substrings */ #####: 1215: register size_t k = 0; #####: 1216: for (k = 0; k < j; k++) unconditional 0 never executed %%%%%: 1216-block 0 branch 1 never executed branch 2 never executed #####: 1217: free(sel_array[k]); %%%%%: 1217-block 0 unconditional 0 never executed #####: 1218: free(sel_array); -: 1219: #####: 1220: for (k = 0; k <= args_n; k++) %%%%%: 1220-block 0 unconditional 0 never executed %%%%%: 1220-block 1 branch 1 never executed branch 2 never executed #####: 1221: free(substr[k]); %%%%%: 1221-block 0 unconditional 0 never executed #####: 1222: free(substr); -: 1223: #####: 1224: return (char **)NULL; %%%%%: 1224-block 0 unconditional 0 never executed -: 1225: } -: 1226: } -: 1227: 10: 1228: for (i = (size_t)is_sel + 1; i <= args_n; i++) 9: 1228-block 0 unconditional 0 taken 9 10: 1228-block 1 branch 1 taken 1 branch 2 taken 9 (fallthrough) 1: 1229: sel_array[j++] = savestring(substr[i], strlen(substr[i])); 1: 1229-block 0 call 0 returned 1 unconditional 1 taken 1 -: 1230: 28: 1231: for (i = 0; i <= args_n; i++) 9: 1231-block 0 unconditional 0 taken 9 28: 1231-block 1 branch 1 taken 19 branch 2 taken 9 (fallthrough) 19: 1232: free(substr[i]); 19: 1232-block 0 unconditional 0 taken 19 -: 1233: 9: 1234: substr = (char **)xrealloc(substr, (args_n + sel_n + 2) 9: 1234-block 0 call 0 returned 9 -: 1235: * sizeof(char *)); -: 1236: 39: 1237: for (i = 0; i < j; i++) { unconditional 0 taken 9 39: 1237-block 0 branch 1 taken 30 branch 2 taken 9 (fallthrough) 30: 1238: substr[i] = savestring(sel_array[i], strlen(sel_array[i])); 30: 1238-block 0 call 0 returned 30 30: 1239: free(sel_array[i]); unconditional 0 taken 30 -: 1240: } -: 1241: 9: 1242: free(sel_array); 9: 1243: substr[i] = (char *)NULL; 9: 1244: args_n = j - 1; 9: 1244-block 0 unconditional 0 taken 9 -: 1245: } -: 1246: -: 1247: else { -: 1248: /* 'sel' is an argument, but there are no selected files. */ #####: 1249: fprintf(stderr, _("%c%s: There are no selected files%c"), %%%%%: 1249-block 0 unconditional 0 never executed %%%%%: 1249-block 1 unconditional 1 never executed %%%%%: 1249-block 2 unconditional 2 never executed %%%%%: 1249-block 3 unconditional 3 never executed %%%%%: 1249-block 4 call 4 never executed call 5 never executed #####: 1250: kb_shortcut ? '\n' : '\0', PROGRAM_NAME, %%%%%: 1250-block 0 branch 0 never executed branch 1 never executed #####: 1251: kb_shortcut ? '\0' : '\n'); %%%%%: 1251-block 0 branch 0 never executed branch 1 never executed -: 1252: #####: 1253: register size_t j = 0; #####: 1254: for (j = 0; j <= args_n; j++) unconditional 0 never executed %%%%%: 1254-block 0 branch 1 never executed branch 2 never executed #####: 1255: free(substr[j]); %%%%%: 1255-block 0 unconditional 0 never executed #####: 1256: free(substr); -: 1257: #####: 1258: return (char **)NULL; %%%%%: 1258-block 0 unconditional 0 never executed -: 1259: } -: 1260: } -: 1261: 500: 1262: int stdin_dir_ok = 0; 500*: 1263: if (stdin_tmp_dir && strcmp(ws[cur_ws].path, stdin_tmp_dir) == 0) 500: 1263-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 500 %%%%%: 1263-block 1 branch 2 never executed branch 3 never executed #####: 1264: stdin_dir_ok = 1; %%%%%: 1264-block 0 unconditional 0 never executed -: 1265: 1221: 1266: for (i = 0; i <= args_n; i++) { 500: 1266-block 0 unconditional 0 taken 500 721: 1266-block 1 unconditional 1 taken 721 1221: 1266-block 2 branch 2 taken 721 branch 3 taken 500 (fallthrough) 721*: 1267: if (!substr[i]) 721: 1267-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 721 #####: 1268: continue; %%%%%: 1268-block 0 unconditional 0 never executed -: 1269: -: 1270: /* ########################## -: 1271: * # 2.f) ELN EXPANSION # -: 1272: * ##########################*/ -: 1273: -: 1274: /* If autocd is set to false, i must be bigger than zero because -: 1275: * the first string in comm_array, the command name, should NOT -: 1276: * be expanded, but only arguments. Otherwise, if the expanded -: 1277: * ELN happens to be a program name as well, this program will -: 1278: * be executed, and this, for sure, is to be avoided */ -: 1279: -: 1280: /* The 'sort', 'mf', 'ws', and 'jo' commands take digits as -: 1281: * arguments. So, do not expand ELN's in these cases */ 721: 1282: if (substr[0] && strcmp(substr[0], "mf") != 0 721: 1282-block 0 branch 0 taken 721 (fallthrough) branch 1 taken 0 721: 1282-block 1 branch 2 taken 717 (fallthrough) branch 3 taken 4 717: 1283: && strcmp(substr[0], "st") != 0 && strcmp(substr[0], "ws") != 0 717: 1283-block 0 branch 0 taken 702 (fallthrough) branch 1 taken 15 702: 1283-block 1 branch 2 taken 666 (fallthrough) branch 3 taken 36 666: 1284: && strcmp(substr[0], "sort") != 0 && strcmp(substr[0], "jo") != 0) { 666: 1284-block 0 branch 0 taken 666 (fallthrough) branch 1 taken 0 666: 1284-block 1 branch 2 taken 666 (fallthrough) branch 3 taken 0 -: 1285: 666: 1286: if (is_number(substr[i])) { 666: 1286-block 0 call 0 returned 666 branch 1 taken 61 (fallthrough) branch 2 taken 605 -: 1287: /* Expand first word only if autocd is set to true */ 61*: 1288: if ((i == 0 && !autocd && !auto_open) || !substr[i]) 61: 1288-block 0 branch 0 taken 26 (fallthrough) branch 1 taken 35 26: 1288-block 1 branch 2 taken 1 (fallthrough) branch 3 taken 25 1: 1288-block 2 branch 4 taken 1 (fallthrough) branch 5 taken 0 61: 1288-block 3 branch 6 taken 0 (fallthrough) branch 7 taken 61 #####: 1289: continue; %%%%%: 1289-block 0 unconditional 0 never executed -: 1290: 61: 1291: int num = atoi(substr[i]); -: 1292: /* Expand numbers only if there is a corresponding ELN */ -: 1293: -: 1294: /* Do not expand ELN if there is a file named as the -: 1295: * ELN */ 61: 1296: if (eln_as_file_n) { 61: 1296-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 61 #####: 1297: int conflict = 0; #####: 1298: if (eln_as_file_n > 1) { %%%%%: 1298-block 0 branch 0 never executed branch 1 never executed -: 1299: size_t j; -: 1300: #####: 1301: for (j = 0; j < eln_as_file_n; j++) { %%%%%: 1301-block 0 unconditional 0 never executed %%%%%: 1301-block 1 unconditional 1 never executed %%%%%: 1301-block 2 branch 2 never executed branch 3 never executed #####: 1302: if (atoi(file_info[eln_as_file[j]].name) == num) { %%%%%: 1302-block 0 branch 0 never executed branch 1 never executed #####: 1303: conflict = num; -: 1304: /* One conflicting file name is enough */ #####: 1305: break; %%%%%: 1305-block 0 unconditional 0 never executed -: 1306: } -: 1307: } -: 1308: } else { #####: 1309: if (atoi(file_info[eln_as_file[0]].name) == num) %%%%%: 1309-block 0 branch 0 never executed branch 1 never executed #####: 1310: conflict = num; %%%%%: 1310-block 0 unconditional 0 never executed -: 1311: } -: 1312: #####: 1313: if (conflict) { %%%%%: 1313-block 0 branch 0 never executed branch 1 never executed -: 1314: size_t j; -: 1315: #####: 1316: for (j = 0; j <= args_n; j++) %%%%%: 1316-block 0 unconditional 0 never executed %%%%%: 1316-block 1 branch 1 never executed branch 2 never executed #####: 1317: free(substr[j]); %%%%%: 1317-block 0 unconditional 0 never executed #####: 1318: free(substr); -: 1319: #####: 1320: fprintf(stderr, _("%s: %d: ELN-filename " %%%%%: 1320-block 0 call 0 never executed call 1 never executed -: 1321: "conflict. Bypass internal expansions " -: 1322: "to fix this issue: ';CMD " -: 1323: "FILENAME'\n"), PROGRAM_NAME, conflict); #####: 1324: return (char **)NULL; unconditional 0 never executed -: 1325: } -: 1326: } -: 1327: 61: 1328: if (num > 0 && num <= (int)files) { 61: 1328-block 0 branch 0 taken 61 (fallthrough) branch 1 taken 0 61: 1328-block 1 branch 2 taken 61 (fallthrough) branch 3 taken 0 -: 1329: /* Replace the ELN by the corresponding escaped -: 1330: * file name */ 61: 1331: int j = num - 1; 61: 1332: char *esc_str = escape_str(file_info[j].name); 61: 1332-block 0 call 0 returned 61 -: 1333: 61: 1334: if (esc_str) { branch 0 taken 61 (fallthrough) branch 1 taken 0 61: 1335: if (file_info[j].dir && 61: 1335-block 0 branch 0 taken 24 (fallthrough) branch 1 taken 37 24: 1336: file_info[j].name[file_info[j].len - 1] != '/') { 24: 1336-block 0 branch 0 taken 24 (fallthrough) branch 1 taken 0 48: 1337: substr[i] = (char *)xrealloc(substr[i], 24: 1338: (strlen(esc_str) + 2) * sizeof(char)); 24: 1338-block 0 call 0 returned 24 24: 1339: sprintf(substr[i], "%s/", esc_str); unconditional 0 taken 24 -: 1340: } else { 74: 1341: substr[i] = (char *)xrealloc(substr[i], 37: 1342: (strlen(esc_str) + 1) * sizeof(char)); 37: 1342-block 0 call 0 returned 37 37: 1343: strcpy(substr[i], esc_str); unconditional 0 taken 37 -: 1344: } -: 1345: 61: 1346: free(esc_str); 61: 1347: esc_str = (char *)NULL; 61: 1347-block 0 unconditional 0 taken 61 -: 1348: } else { #####: 1349: fprintf(stderr, _("%s: %s: Error quoting " call 0 never executed -: 1350: "file name\n"), #####: 1351: PROGRAM_NAME, file_info[num - 1].name); %%%%%: 1351-block 0 call 0 never executed -: 1352: /* Free whatever was allocated thus far */ -: 1353: #####: 1354: for (j = 0; j <= (int)args_n; j++) unconditional 0 never executed %%%%%: 1354-block 0 branch 1 never executed branch 2 never executed #####: 1355: free(substr[j]); %%%%%: 1355-block 0 unconditional 0 never executed #####: 1356: free(substr); #####: 1357: return (char **)NULL; %%%%%: 1357-block 0 unconditional 0 never executed -: 1358: } -: 1359: } -: 1360: } -: 1361: } -: 1362: -: 1363: /* ############################################# -: 1364: * # 2.g) USER DEFINED VARIABLES EXPANSION # -: 1365: * #############################################*/ -: 1366: 721*: 1367: if (substr[i][0] == '$' && substr[i][1] != '(' && substr[i][1] != '{') { 721: 1367-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 721 %%%%%: 1367-block 1 branch 2 never executed branch 3 never executed %%%%%: 1367-block 2 branch 4 never executed branch 5 never executed #####: 1368: char *var_name = strchr(substr[i], '$'); #####: 1369: if (var_name && *(++var_name)) { %%%%%: 1369-block 0 branch 0 never executed branch 1 never executed %%%%%: 1369-block 1 branch 2 never executed branch 3 never executed %%%%%: 1369-block 2 unconditional 4 never executed #####: 1370: int j = (int)usrvar_n; #####: 1371: while (--j >= 0) { %%%%%: 1371-block 0 unconditional 0 never executed %%%%%: 1371-block 1 branch 1 never executed branch 2 never executed #####: 1372: if (*var_name == *usr_var[j].name %%%%%: 1372-block 0 branch 0 never executed branch 1 never executed #####: 1373: && strcmp(var_name, usr_var[j].name) == 0) { %%%%%: 1373-block 0 branch 0 never executed branch 1 never executed #####: 1374: substr[i] = (char *)xrealloc(substr[i], #####: 1375: (strlen(usr_var[j].value) + 1) * sizeof(char)); %%%%%: 1375-block 0 call 0 never executed #####: 1376: strcpy(substr[i], usr_var[j].value); #####: 1377: break; unconditional 0 never executed -: 1378: } -: 1379: } -: 1380: } else { #####: 1381: fprintf(stderr, _("%s: %s: Error getting variable name\n"), call 0 never executed #####: 1382: PROGRAM_NAME, substr[i]); %%%%%: 1382-block 0 call 0 never executed -: 1383: size_t j; #####: 1384: for (j = 0; j <= args_n; j++) unconditional 0 never executed %%%%%: 1384-block 0 branch 1 never executed branch 2 never executed #####: 1385: free(substr[j]); %%%%%: 1385-block 0 unconditional 0 never executed #####: 1386: free(substr); #####: 1387: return (char **)NULL; %%%%%: 1387-block 0 unconditional 0 never executed -: 1388: } -: 1389: } -: 1390: -: 1391: /* We are in STDIN_TMP_DIR: Expand symlinks to target */ 721: 1392: if (stdin_dir_ok) { 721: 1392-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 721 #####: 1393: char *real_path = realpath(substr[i], NULL); %%%%%: 1393-block 0 call 0 never executed #####: 1394: if (real_path) { branch 0 never executed branch 1 never executed #####: 1395: substr[i] = (char *)xrealloc(substr[i], #####: 1396: (strlen(real_path) + 1) * sizeof(char)); %%%%%: 1396-block 0 call 0 never executed #####: 1397: strcpy(substr[i], real_path); #####: 1398: free(real_path); unconditional 0 never executed -: 1399: } -: 1400: } -: 1401: } -: 1402: -: 1403: /* #### 3) NULL TERMINATE THE INPUT STRING ARRAY #### */ 500: 1404: substr = (char **)xrealloc(substr, sizeof(char *) * (args_n + 2)); 500: 1404-block 0 call 0 returned 500 500: 1405: substr[args_n + 1] = (char *)NULL; -: 1406: 500: 1407: if (!is_internal(substr[0])) call 0 returned 500 branch 1 taken 426 (fallthrough) branch 2 taken 74 426: 1408: return substr; 426: 1408-block 0 unconditional 0 taken 426 -: 1409: -: 1410: /* ############################################################# -: 1411: * # ONLY FOR INTERNAL COMMANDS # -: 1412: * #############################################################*/ -: 1413: -: 1414: /* Some functions of CliFM are purely internal, that is, they are not -: 1415: * wrappers of a shell command and do not call the system shell at all. -: 1416: * For this reason, some expansions normally made by the system shell -: 1417: * must be made here (in the lobby [got it?]) in order to be able to -: 1418: * understand these expansions at all. */ -: 1419: -: 1420: /* ############################################### -: 1421: * # 3) WILDCARD, BRACE, AND TILDE EXPANSION # -: 1422: * ############################################### */ -: 1423: 74: 1424: int *glob_array = (int *)xnmalloc(int_array_max, sizeof(int)); 74: 1424-block 0 call 0 returned 74 74: 1425: size_t glob_n = 0; -: 1426:#if !defined(__HAIKU__) && !defined(__OpenBSD__) 74: 1427: int *word_array = (int *)xnmalloc(int_array_max, sizeof(int)); call 0 returned 74 74: 1428: size_t word_n = 0; -: 1429:#endif -: 1430: 235: 1431: for (i = 0; substr[i]; i++) { unconditional 0 taken 74 161: 1431-block 0 unconditional 1 taken 161 235: 1431-block 1 branch 2 taken 161 branch 3 taken 74 (fallthrough) -: 1432: -: 1433: /* Do not perform any of the expansions below for selected -: 1434: * elements: they are full path file names that, as such, do not -: 1435: * need any expansion */ 161: 1436: if (is_sel) { /* is_sel is true only for the current input and if 161: 1436-block 0 branch 0 taken 19 (fallthrough) branch 1 taken 142 -: 1437: there was some "sel" keyword in it */ -: 1438: /* Strings between is_sel and sel_n are selected file names */ 19: 1439: if (i >= (size_t)is_sel && i <= sel_n) 19: 1439-block 0 branch 0 taken 13 (fallthrough) branch 1 taken 6 13: 1439-block 1 branch 2 taken 13 (fallthrough) branch 3 taken 0 13: 1440: continue; 13: 1440-block 0 unconditional 0 taken 13 -: 1441: } -: 1442: -: 1443: /* Ignore the first string of the search function: it will be -: 1444: * expanded by the search function itself */ 148: 1445: if (substr[0][0] == '/' && i == 0) 148: 1445-block 0 branch 0 taken 8 (fallthrough) branch 1 taken 140 8: 1445-block 1 branch 2 taken 5 (fallthrough) branch 3 taken 3 5: 1446: continue; 5: 1446-block 0 unconditional 0 taken 5 -: 1447: -: 1448: /* Tilde expansion is made by glob() */ 143: 1449: if (*substr[i] == '~') { 143: 1449-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 143 #####: 1450: if (glob_n < int_array_max) %%%%%: 1450-block 0 branch 0 never executed branch 1 never executed #####: 1451: glob_array[glob_n++] = (int)i; %%%%%: 1451-block 0 unconditional 0 never executed -: 1452: } -: 1453: 143: 1454: register size_t j = 0; 784: 1455: for (j = 0; substr[i][j]; j++) { 143: 1455-block 0 unconditional 0 taken 143 641: 1455-block 1 unconditional 1 taken 641 784: 1455-block 2 branch 2 taken 641 branch 3 taken 143 (fallthrough) -: 1456: /* Brace and wildcard expansion is made by glob() -: 1457: * as well */ 641: 1458: if ((substr[i][j] == '*' || substr[i][j] == '?' 641: 1458-block 0 branch 0 taken 630 (fallthrough) branch 1 taken 11 630: 1458-block 1 branch 2 taken 630 (fallthrough) branch 3 taken 0 630: 1459: || substr[i][j] == '[' || substr[i][j] == '{') 630: 1459-block 0 branch 0 taken 630 (fallthrough) branch 1 taken 0 630: 1459-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 630 11: 1460: && substr[i][j + 1] != ' ') { 11: 1460-block 0 branch 0 taken 11 (fallthrough) branch 1 taken 0 -: 1461: /* Strings containing these characters are taken as -: 1462: * wildacard patterns and are expanded by the glob -: 1463: * function. See man (7) glob */ 11: 1464: if (glob_n < int_array_max) 11: 1464-block 0 branch 0 taken 11 (fallthrough) branch 1 taken 0 11: 1465: glob_array[glob_n++] = (int)i; 11: 1465-block 0 unconditional 0 taken 11 -: 1466: } -: 1467: -: 1468:#if !defined(__HAIKU__) && !defined(__OpenBSD__) -: 1469: /* Command substitution is made by wordexp() */ 641*: 1470: if (substr[i][j] == '$' && (substr[i][j + 1] == '(' 641: 1470-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 641 %%%%%: 1470-block 1 branch 2 never executed branch 3 never executed #####: 1471: || substr[i][j + 1] == '{')) { %%%%%: 1471-block 0 branch 0 never executed branch 1 never executed #####: 1472: if (word_n < int_array_max) %%%%%: 1472-block 0 branch 0 never executed branch 1 never executed #####: 1473: word_array[word_n++] = (int)i; %%%%%: 1473-block 0 unconditional 0 never executed -: 1474: } -: 1475: 641*: 1476: if (substr[i][j] == '`' && substr[i][j + 1] != ' ') { 641: 1476-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 641 %%%%%: 1476-block 1 branch 2 never executed branch 3 never executed #####: 1477: if (word_n < int_array_max) %%%%%: 1477-block 0 branch 0 never executed branch 1 never executed #####: 1478: word_array[word_n++] = (int)i; %%%%%: 1478-block 0 unconditional 0 never executed -: 1479: } -: 1480:#endif /* __HAIKU__ */ -: 1481: } -: 1482: } -: 1483: -: 1484: /* Do not expand if command is deselect, sel or untrash, just to -: 1485: * allow the use of "*" for desel and untrash ("ds *" and "u *") -: 1486: * and to let the sel function handle patterns itself */ 74: 1487: if (glob_n && strcmp(substr[0], "s") != 0 && strcmp(substr[0], "sel") != 0 74: 1487-block 0 branch 0 taken 8 (fallthrough) branch 1 taken 66 8: 1487-block 1 branch 2 taken 5 (fallthrough) branch 3 taken 3 5: 1487-block 2 branch 4 taken 2 (fallthrough) branch 5 taken 3 2: 1488: && strcmp(substr[0], "ds") != 0 && strcmp(substr[0], "desel") != 0 2: 1488-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 0 2: 1488-block 1 branch 2 taken 2 (fallthrough) branch 3 taken 0 2: 1489: && strcmp(substr[0], "u") != 0 && strcmp(substr[0], "undel") != 0 2: 1489-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 0 2: 1489-block 1 branch 2 taken 2 (fallthrough) branch 3 taken 0 2: 1490: && strcmp(substr[0], "untrash") != 0) { 2: 1490-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 0 -: 1491: /* 1) Expand glob -: 1492: 2) Create a new array, say comm_array_glob, large enough to store -: 1493: the expanded glob and the remaining (non-glob) arguments -: 1494: (args_n+gl_pathc) -: 1495: 3) Copy into this array everything before the glob -: 1496: (i=0;i (files + args_n)) 127: 1673-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 127 #####: 1674: break; %%%%%: 1674-block 0 unconditional 0 never executed -: 1675: -: 1676: /* Ignore the first string of the search function: it will be -: 1677: * expanded by the search function itself */ 127: 1678: if (*substr[0] == '/') { 127: 1678-block 0 branch 0 taken 8 (fallthrough) branch 1 taken 119 8: 1679: regex_files[r_files++] = substr[i]; 127: 1680: continue; 8: 1680-block 0 unconditional 0 taken 8 127: 1680-block 1 unconditional 1 taken 127 -: 1681: } -: 1682: 119: 1683: if (check_regex(substr[i]) != EXIT_SUCCESS) { 119: 1683-block 0 call 0 returned 119 branch 1 taken 119 (fallthrough) branch 2 taken 0 119: 1684: regex_files[r_files++] = substr[i]; 119: 1685: continue; 119: 1685-block 0 unconditional 0 taken 119 -: 1686: } -: 1687: -: 1688: regex_t regex; #####: 1689: if (regcomp(®ex, substr[i], REG_NOSUB | REG_EXTENDED) != EXIT_SUCCESS) { %%%%%: 1689-block 0 call 0 never executed branch 1 never executed branch 2 never executed -: 1690: /* fprintf(stderr, "%s: %s: Invalid regular expression", -: 1691: PROGRAM_NAME, substr[i]); */ #####: 1692: regfree(®ex); %%%%%: 1692-block 0 call 0 never executed #####: 1693: regex_files[r_files++] = substr[i]; #####: 1694: continue; unconditional 0 never executed -: 1695: } -: 1696: #####: 1697: int reg_found = 0; -: 1698: #####: 1699: for (j = 0; j < files; j++) { %%%%%: 1699-block 0 unconditional 0 never executed %%%%%: 1699-block 1 unconditional 1 never executed %%%%%: 1699-block 2 branch 2 never executed branch 3 never executed #####: 1700: if (regexec(®ex, file_info[j].name, 0, NULL, 0) == EXIT_SUCCESS) { %%%%%: 1700-block 0 call 0 never executed branch 1 never executed branch 2 never executed #####: 1701: regex_files[r_files++] = file_info[j].name; #####: 1702: reg_found = 1; %%%%%: 1702-block 0 unconditional 0 never executed -: 1703: } -: 1704: } -: 1705: #####: 1706: if (!reg_found) %%%%%: 1706-block 0 branch 0 never executed branch 1 never executed #####: 1707: regex_files[r_files++] = substr[i]; %%%%%: 1707-block 0 unconditional 0 never executed -: 1708: #####: 1709: regfree(®ex); %%%%%: 1709-block 0 call 0 never executed -: 1710: } -: 1711: 61: 1712: if (r_files) { 61: 1712-block 0 branch 0 taken 61 (fallthrough) branch 1 taken 0 61: 1713: regex_files[r_files] = (char *)NULL; 61: 1714: char **tmp_files = (char **)xnmalloc(r_files + 2, sizeof(char *)); 61: 1714-block 0 call 0 returned 61 61: 1715: size_t k = 0; 188: 1716: for (j = 0; regex_files[j]; j++) unconditional 0 taken 61 188: 1716-block 0 branch 1 taken 127 branch 2 taken 61 (fallthrough) 127: 1717: tmp_files[k++] = savestring(regex_files[j], strlen(regex_files[j])); 127: 1717-block 0 call 0 returned 127 unconditional 1 taken 127 61: 1718: tmp_files[k] = (char *)NULL; -: 1719: 188: 1720: for (j = 0; j <= args_n; j++) 61: 1720-block 0 unconditional 0 taken 61 188: 1720-block 1 branch 1 taken 127 branch 2 taken 61 (fallthrough) 127: 1721: free(substr[j]); 127: 1721-block 0 unconditional 0 taken 127 61: 1722: free(substr); -: 1723: 61: 1724: substr = tmp_files; 61: 1725: tmp_files = (char **)NULL; 61: 1726: args_n = k - 1; 61: 1727: free(tmp_files); 61: 1727-block 0 unconditional 0 taken 61 -: 1728: } -: 1729: 61: 1730: free(regex_files); 61: 1731: substr = (char **)xrealloc(substr, (args_n + 2) * sizeof(char *)); 61: 1731-block 0 call 0 returned 61 61: 1732: substr[args_n + 1] = (char *)NULL; 61: 1733: return substr; unconditional 0 taken 61 -: 1734:} -: 1735: -: 1736:/* Reduce "$HOME" to tilde ("~"). The new_path variable is always either -: 1737: * "$HOME" or "$HOME/file", that's why there's no need to check for -: 1738: * "/file" */ -: 1739:char * function home_tilde called 1101 returned 100% blocks executed 94% 1101: 1740:home_tilde(const char *new_path) -: 1741:{ 1101: 1742: if (!home_ok || !new_path || !*new_path || !user.home) 1101: 1742-block 0 branch 0 taken 1101 (fallthrough) branch 1 taken 0 1101: 1742-block 1 branch 2 taken 1101 (fallthrough) branch 3 taken 0 1101: 1742-block 2 branch 4 taken 1101 (fallthrough) branch 5 taken 0 1101: 1742-block 3 branch 6 taken 0 (fallthrough) branch 7 taken 1101 #####: 1743: return (char *)NULL; %%%%%: 1743-block 0 unconditional 0 never executed -: 1744: 1101: 1745: char *path_tilde = (char *)NULL; -: 1746: -: 1747: /* If path == HOME */ 1101: 1748: if (new_path[1] == user.home[1] && strcmp(new_path, user.home) == 0) { 1101: 1748-block 0 branch 0 taken 1073 (fallthrough) branch 1 taken 28 1073: 1748-block 1 branch 2 taken 127 (fallthrough) branch 3 taken 946 127: 1749: path_tilde = (char *)xnmalloc(2, sizeof(char)); 127: 1749-block 0 call 0 returned 127 127: 1750: path_tilde[0] = '~'; 127: 1751: path_tilde[1] = '\0'; unconditional 0 taken 127 974: 1752: } else if (new_path[1] == user.home[1] 974: 1752-block 0 branch 0 taken 946 (fallthrough) branch 1 taken 28 946: 1753: && strncmp(new_path, user.home, user.home_len) == 0) { 946: 1753-block 0 branch 0 taken 946 (fallthrough) branch 1 taken 0 -: 1754: /* If path == HOME/file */ 946: 1755: path_tilde = (char *)xnmalloc(strlen(new_path + user.home_len + 1) + 3, 946: 1755-block 0 call 0 returned 946 -: 1756: sizeof(char)); 946: 1757: sprintf(path_tilde, "~/%s", new_path + user.home_len + 1); unconditional 0 taken 946 -: 1758: } else { 28: 1759: path_tilde = (char *)xnmalloc(strlen(new_path) + 1, sizeof(char)); 28: 1759-block 0 call 0 returned 28 28: 1760: strcpy(path_tilde, new_path); unconditional 0 taken 28 -: 1761: } -: 1762: 1101: 1763: return path_tilde; 1101: 1763-block 0 unconditional 0 taken 1101 -: 1764:} -: 1765: -: 1766:/* Expand a range of numbers given by str. It will expand the range -: 1767: * provided that both extremes are numbers, bigger than zero, equal or -: 1768: * smaller than the amount of files currently listed on the screen, and -: 1769: * the second (right) extreme is bigger than the first (left). Returns -: 1770: * an array of int's with the expanded range or NULL if one of the -: 1771: * above conditions is not met */ -: 1772:int * function expand_range called 4 returned 100% blocks executed 73% 4: 1773:expand_range(char *str, int listdir) -: 1774:{ 4: 1775: if (strcntchr(str, '-') == -1) 4: 1775-block 0 call 0 returned 4 branch 1 taken 0 (fallthrough) branch 2 taken 4 #####: 1776: return (int *)NULL; %%%%%: 1776-block 0 unconditional 0 never executed -: 1777: 4: 1778: char *first = (char *)NULL; 4: 1779: first = strbfr(str, '-'); 4: 1779-block 0 call 0 returned 4 -: 1780: 4: 1781: if (!first) branch 0 taken 0 (fallthrough) branch 1 taken 4 #####: 1782: return (int *)NULL; %%%%%: 1782-block 0 unconditional 0 never executed -: 1783: 4: 1784: if (!is_number(first)) { 4: 1784-block 0 call 0 returned 4 branch 1 taken 0 (fallthrough) branch 2 taken 4 #####: 1785: free(first); #####: 1786: return (int *)NULL; %%%%%: 1786-block 0 unconditional 0 never executed -: 1787: } -: 1788: 4: 1789: char *second = (char *)NULL; 4: 1790: second = straft(str, '-'); 4: 1790-block 0 call 0 returned 4 -: 1791: 4: 1792: if (!second) { branch 0 taken 0 (fallthrough) branch 1 taken 4 #####: 1793: free(first); #####: 1794: return (int *)NULL; %%%%%: 1794-block 0 unconditional 0 never executed -: 1795: } -: 1796: 4: 1797: if (!is_number(second)) { 4: 1797-block 0 call 0 returned 4 branch 1 taken 0 (fallthrough) branch 2 taken 4 #####: 1798: free(first); #####: 1799: free(second); #####: 1800: return (int *)NULL; %%%%%: 1800-block 0 unconditional 0 never executed -: 1801: } -: 1802: 4: 1803: int afirst = atoi(first), asecond = atoi(second); 4: 1804: free(first); 4: 1805: free(second); -: 1806: 4: 1807: if (listdir) { 4: 1807-block 0 branch 0 taken 4 (fallthrough) branch 1 taken 0 4: 1808: if (afirst <= 0 || afirst > (int)files || asecond <= 0 4: 1808-block 0 branch 0 taken 4 (fallthrough) branch 1 taken 0 4: 1808-block 1 branch 2 taken 4 (fallthrough) branch 3 taken 0 4: 1808-block 2 branch 4 taken 4 (fallthrough) branch 5 taken 0 4: 1809: || asecond > (int)files || afirst >= asecond) 4: 1809-block 0 branch 0 taken 4 (fallthrough) branch 1 taken 0 4: 1809-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 4 #####: 1810: return (int *)NULL; %%%%%: 1810-block 0 unconditional 0 never executed -: 1811: } else { #####: 1812: if (afirst >= asecond) %%%%%: 1812-block 0 branch 0 never executed branch 1 never executed #####: 1813: return (int *)NULL; %%%%%: 1813-block 0 unconditional 0 never executed -: 1814: } -: 1815: 4: 1816: int *buf = (int *)NULL; 4: 1817: buf = (int *)xcalloc((size_t)(asecond - afirst) + 2, sizeof(int)); 4: 1817-block 0 call 0 returned 4 -: 1818: 4: 1819: size_t i, j = 0; 18: 1820: for (i = (size_t)afirst; i <= (size_t)asecond; i++) unconditional 0 taken 4 18: 1820-block 0 branch 1 taken 14 branch 2 taken 4 (fallthrough) 14: 1821: buf[j++] = (int)i; 14: 1821-block 0 unconditional 0 taken 14 -: 1822: 4: 1823: return buf; 4: 1823-block 0 unconditional 0 taken 4 -: 1824:} -: 1825: -: 1826:/* used a lot. -: 1827: * creates a copy of a string */ -: 1828:char * function savestring called 95251 returned 100% blocks executed 67% 95251: 1829:savestring(const char *restrict str, size_t size) -: 1830:{ 95251: 1831: if (!str) 95251: 1831-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 95251 #####: 1832: return (char *)NULL; %%%%%: 1832-block 0 unconditional 0 never executed -: 1833: 95251: 1834: char *ptr = (char *)NULL; 95251: 1835: ptr = (char *)malloc((size + 1) * sizeof(char)); -: 1836: 95251: 1837: if (!ptr) 95251: 1837-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 95251 #####: 1838: return (char *)NULL; %%%%%: 1838-block 0 unconditional 0 never executed 95251: 1839: strcpy(ptr, str); -: 1840: 95251: 1841: return ptr; 95251: 1841-block 0 unconditional 0 taken 95251 -: 1842:} -: 1843: -: 1844:/* Take a string and returns the same string escaped. If nothing to be -: 1845: * escaped, the original string is returned */ -: 1846:char * function escape_str called 139 returned 100% blocks executed 91% 139: 1847:escape_str(const char *str) -: 1848:{ 139: 1849: if (!str) 139: 1849-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 139 #####: 1850: return (char *)NULL; %%%%%: 1850-block 0 unconditional 0 never executed -: 1851: 139: 1852: size_t len = 0; 139: 1853: char *buf = (char *)NULL; -: 1854: 139: 1855: buf = (char *)xnmalloc(strlen(str) * 2 + 1, sizeof(char)); 139: 1855-block 0 call 0 returned 139 -: 1856: 2620: 1857: while (*str) { unconditional 0 taken 139 2620: 1857-block 0 branch 1 taken 2481 branch 2 taken 139 (fallthrough) 2481: 1858: if (is_quote_char(*str)) 2481: 1858-block 0 call 0 returned 2481 branch 1 taken 1 (fallthrough) branch 2 taken 2480 1: 1859: buf[len++] = '\\'; 1: 1859-block 0 unconditional 0 taken 1 2481: 1860: buf[len++] = *(str++); 2481: 1860-block 0 unconditional 0 taken 2481 -: 1861: } -: 1862: 139: 1863: buf[len] = '\0'; 139: 1864: return buf; 139: 1864-block 0 unconditional 0 taken 139 -: 1865:} -: 1866: -: 1867:/* Get all substrings from STR using IFS as substring separator, and, -: 1868: * if there is a range, expand it. Returns an array containing all -: 1869: * substrings in STR plus expandes ranges, or NULL if: STR is NULL or -: 1870: * empty, STR contains only IFS(s), or in case of memory allocation -: 1871: * error */ -: 1872:char ** function get_substr called 53 returned 100% blocks executed 35% 53: 1873:get_substr(char *str, const char ifs) -: 1874:{ 53: 1875: if (!str || *str == '\0') 53: 1875-block 0 branch 0 taken 53 (fallthrough) branch 1 taken 0 53: 1875-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 53 #####: 1876: return (char **)NULL; %%%%%: 1876-block 0 unconditional 0 never executed -: 1877: -: 1878: /* ############## SPLIT THE STRING #######################*/ -: 1879: 53: 1880: char **substr = (char **)NULL; 53: 1881: void *p = (char *)NULL; 53: 1882: size_t str_len = strlen(str); 53: 1883: size_t length = 0, substr_n = 0; 53: 1884: char *buf = (char *)xnmalloc(str_len + 1, sizeof(char)); 53: 1884-block 0 call 0 returned 53 -: 1885: 172: 1886: while (*str) { unconditional 0 taken 53 172: 1886-block 0 branch 1 taken 119 branch 2 taken 53 (fallthrough) 261: 1887: while (*str != ifs && *str != '\0' && length < (str_len + 1)) 119: 1887-block 0 unconditional 0 taken 119 261: 1887-block 1 branch 1 taken 195 (fallthrough) branch 2 taken 66 195: 1887-block 2 branch 3 taken 142 (fallthrough) branch 4 taken 53 142: 1887-block 3 branch 5 taken 142 branch 6 taken 0 (fallthrough) 142: 1888: buf[length++] = *(str++); 142: 1888-block 0 unconditional 0 taken 142 119: 1889: if (length) { 119: 1889-block 0 branch 0 taken 86 (fallthrough) branch 1 taken 33 86: 1890: buf[length] = '\0'; 86: 1891: p = (char *)realloc(substr, (substr_n + 1) * sizeof(char *)); 86: 1892: if (!p) { 86: 1892-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 86 -: 1893: /* Free whatever was allocated so far */ -: 1894: size_t i; #####: 1895: for (i = 0; i < substr_n; i++) %%%%%: 1895-block 0 unconditional 0 never executed %%%%%: 1895-block 1 branch 1 never executed branch 2 never executed #####: 1896: free(substr[i]); %%%%%: 1896-block 0 unconditional 0 never executed #####: 1897: free(substr); #####: 1898: return (char **)NULL; %%%%%: 1898-block 0 unconditional 0 never executed -: 1899: } 86: 1900: substr = (char **)p; 86: 1901: p = (char *)malloc(length + 1); -: 1902: 86: 1903: if (!p) { 86: 1903-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 86 -: 1904: size_t i; #####: 1905: for (i = 0; i < substr_n; i++) %%%%%: 1905-block 0 unconditional 0 never executed %%%%%: 1905-block 1 branch 1 never executed branch 2 never executed #####: 1906: free(substr[i]); %%%%%: 1906-block 0 unconditional 0 never executed #####: 1907: free(substr); #####: 1908: return (char **)NULL; %%%%%: 1908-block 0 unconditional 0 never executed -: 1909: } -: 1910: 86: 1911: substr[substr_n] = p; 86: 1912: p = (char *)NULL; 86: 1913: xstrsncpy(substr[substr_n++], buf, length); 86: 1913-block 0 call 0 returned 86 86: 1914: length = 0; unconditional 0 taken 86 -: 1915: } else { 33: 1916: str++; 33: 1916-block 0 unconditional 0 taken 33 -: 1917: } -: 1918: } -: 1919: 53: 1920: free(buf); -: 1921: 53: 1922: if (!substr_n) 53: 1922-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 53 #####: 1923: return (char **)NULL; %%%%%: 1923-block 0 unconditional 0 never executed -: 1924: 53: 1925: size_t i = 0, j = 0; 53: 1926: p = (char *)realloc(substr, (substr_n + 1) * sizeof(char *)); 53: 1927: if (!p) { 53: 1927-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 53 #####: 1928: for (i = 0; i < substr_n; i++) %%%%%: 1928-block 0 unconditional 0 never executed %%%%%: 1928-block 1 branch 1 never executed branch 2 never executed #####: 1929: free(substr[i]); %%%%%: 1929-block 0 unconditional 0 never executed #####: 1930: free(substr); #####: 1931: substr = (char **)NULL; #####: 1932: return (char **)NULL; %%%%%: 1932-block 0 unconditional 0 never executed -: 1933: } -: 1934: 53: 1935: substr = (char **)p; 53: 1936: p = (char *)NULL; 53: 1937: substr[substr_n] = (char *)NULL; -: 1938: -: 1939: /* ################### EXPAND RANGES ######################*/ -: 1940: 53: 1941: int afirst = 0, asecond = 0; -: 1942: 139: 1943: for (i = 0; substr[i]; i++) { 53: 1943-block 0 unconditional 0 taken 53 86: 1943-block 1 unconditional 1 taken 86 139: 1943-block 2 branch 2 taken 86 branch 3 taken 53 (fallthrough) -: 1944: /* Check if substr is a valid range */ 86: 1945: int ranges_ok = 0; -: 1946: /* If range, get both extremes of it */ 127: 1947: for (j = 1; substr[i][j]; j++) { 86: 1947-block 0 unconditional 0 taken 86 41: 1947-block 1 unconditional 1 taken 41 127: 1947-block 2 branch 2 taken 46 branch 3 taken 81 (fallthrough) 46: 1948: if (substr[i][j] == '-') { 46: 1948-block 0 branch 0 taken 5 (fallthrough) branch 1 taken 41 -: 1949: /* Get strings before and after the dash */ 5: 1950: char *first = strbfr(substr[i], '-'); 5: 1950-block 0 call 0 returned 5 5: 1951: if (!first) branch 0 taken 5 (fallthrough) branch 1 taken 0 5: 1952: break; 5: 1952-block 0 unconditional 0 taken 5 -: 1953: #####: 1954: char *second = straft(substr[i], '-'); %%%%%: 1954-block 0 call 0 never executed #####: 1955: if (!second) { branch 0 never executed branch 1 never executed #####: 1956: free(first); #####: 1957: break; %%%%%: 1957-block 0 unconditional 0 never executed -: 1958: } -: 1959: -: 1960: /* Make sure it is a valid range */ #####: 1961: if (is_number(first) && is_number(second)) { %%%%%: 1961-block 0 call 0 never executed branch 1 never executed branch 2 never executed %%%%%: 1961-block 1 call 3 never executed branch 4 never executed branch 5 never executed #####: 1962: afirst = atoi(first), asecond = atoi(second); #####: 1963: if (asecond <= afirst) { %%%%%: 1963-block 0 branch 0 never executed branch 1 never executed #####: 1964: free(first); #####: 1965: free(second); #####: 1966: break; %%%%%: 1966-block 0 unconditional 0 never executed -: 1967: } -: 1968: -: 1969: /* We have a valid range */ #####: 1970: ranges_ok = 1; #####: 1971: free(first); #####: 1972: free(second); %%%%%: 1972-block 0 unconditional 0 never executed -: 1973: } else { #####: 1974: free(first); #####: 1975: free(second); #####: 1976: break; %%%%%: 1976-block 0 unconditional 0 never executed -: 1977: } -: 1978: } -: 1979: } -: 1980: 86: 1981: if (!ranges_ok) 86: 1981-block 0 branch 0 taken 86 (fallthrough) branch 1 taken 0 86: 1982: continue; 86: 1982-block 0 unconditional 0 taken 86 -: 1983: -: 1984: /* If a valid range */ #####: 1985: size_t k = 0, next = 0; #####: 1986: char **rbuf = (char **)NULL; #####: 1987: rbuf = (char **)xnmalloc((substr_n + (size_t)(asecond - afirst) + 1), %%%%%: 1987-block 0 call 0 never executed -: 1988: sizeof(char *)); -: 1989: /* Copy everything before the range expression -: 1990: * into the buffer */ #####: 1991: for (j = 0; j < i; j++) unconditional 0 never executed %%%%%: 1991-block 0 branch 1 never executed branch 2 never executed #####: 1992: rbuf[k++] = savestring(substr[j], strlen(substr[j])); %%%%%: 1992-block 0 call 0 never executed unconditional 1 never executed -: 1993: -: 1994: /* Copy the expanded range into the buffer */ #####: 1995: for (j = (size_t)afirst; j <= (size_t)asecond; j++) { %%%%%: 1995-block 0 unconditional 0 never executed %%%%%: 1995-block 1 branch 1 never executed branch 2 never executed #####: 1996: rbuf[k] = (char *)xnmalloc((size_t)DIGINUM((int)j) + 1, sizeof(char)); %%%%%: 1996-block 0 branch 0 never executed branch 1 never executed %%%%%: 1996-block 1 branch 2 never executed branch 3 never executed %%%%%: 1996-block 2 branch 4 never executed branch 5 never executed %%%%%: 1996-block 3 branch 6 never executed branch 7 never executed %%%%%: 1996-block 4 branch 8 never executed branch 9 never executed %%%%%: 1996-block 5 branch 10 never executed branch 11 never executed %%%%%: 1996-block 6 branch 12 never executed branch 13 never executed %%%%%: 1996-block 7 branch 14 never executed branch 15 never executed %%%%%: 1996-block 8 branch 16 never executed branch 17 never executed %%%%%: 1996-block 9 unconditional 18 never executed %%%%%: 1996-block 10 unconditional 19 never executed %%%%%: 1996-block 11 unconditional 20 never executed %%%%%: 1996-block 12 unconditional 21 never executed %%%%%: 1996-block 13 unconditional 22 never executed %%%%%: 1996-block 14 unconditional 23 never executed %%%%%: 1996-block 15 unconditional 24 never executed %%%%%: 1996-block 16 unconditional 25 never executed %%%%%: 1996-block 17 unconditional 26 never executed %%%%%: 1996-block 18 unconditional 27 never executed %%%%%: 1996-block 19 unconditional 28 never executed %%%%%: 1996-block 20 unconditional 29 never executed %%%%%: 1996-block 21 unconditional 30 never executed %%%%%: 1996-block 22 unconditional 31 never executed %%%%%: 1996-block 23 unconditional 32 never executed %%%%%: 1996-block 24 unconditional 33 never executed %%%%%: 1996-block 25 unconditional 34 never executed %%%%%: 1996-block 26 unconditional 35 never executed %%%%%: 1996-block 27 call 36 never executed #####: 1997: sprintf(rbuf[k++], "%zu", j); unconditional 0 never executed -: 1998: } -: 1999: -: 2000: /* Copy everything after the range expression into -: 2001: * the buffer, if anything */ #####: 2002: if (substr[i + 1]) { %%%%%: 2002-block 0 branch 0 never executed branch 1 never executed #####: 2003: next = k; #####: 2004: for (j = (i + 1); substr[j]; j++) { %%%%%: 2004-block 0 unconditional 0 never executed %%%%%: 2004-block 1 branch 1 never executed branch 2 never executed #####: 2005: rbuf[k++] = savestring(substr[j], strlen(substr[j])); %%%%%: 2005-block 0 call 0 never executed unconditional 1 never executed -: 2006: } -: 2007: } else { /* If there's nothing after last range, there's no next -: 2008: either */ #####: 2009: next = 0; %%%%%: 2009-block 0 unconditional 0 never executed -: 2010: } -: 2011: -: 2012: /* Repopulate the original array with the expanded range and -: 2013: * remaining strings */ #####: 2014: substr_n = k; #####: 2015: for (j = 0; substr[j]; j++) %%%%%: 2015-block 0 unconditional 0 never executed %%%%%: 2015-block 1 branch 1 never executed branch 2 never executed #####: 2016: free(substr[j]); %%%%%: 2016-block 0 unconditional 0 never executed -: 2017: #####: 2018: substr = (char **)xrealloc(substr, (substr_n + 1) * sizeof(char *)); %%%%%: 2018-block 0 call 0 never executed -: 2019: #####: 2020: for (j = 0; j < substr_n; j++) { unconditional 0 never executed %%%%%: 2020-block 0 branch 1 never executed branch 2 never executed #####: 2021: substr[j] = savestring(rbuf[j], strlen(rbuf[j])); %%%%%: 2021-block 0 call 0 never executed #####: 2022: free(rbuf[j]); unconditional 0 never executed -: 2023: } #####: 2024: free(rbuf); -: 2025: #####: 2026: substr[j] = (char *)NULL; -: 2027: -: 2028: /* Proceede only if there's something after the last range */ #####: 2029: if (next) %%%%%: 2029-block 0 branch 0 never executed branch 1 never executed #####: 2030: i = next; %%%%%: 2030-block 0 unconditional 0 never executed -: 2031: else #####: 2032: break; %%%%%: 2032-block 0 unconditional 0 never executed -: 2033: } -: 2034: -: 2035: /* ############## REMOVE DUPLICATES ###############*/ -: 2036: 53: 2037: char **dstr = (char **)NULL; 53: 2038: size_t len = 0, d; -: 2039: 139: 2040: for (i = 0; i < substr_n; i++) { 53: 2040-block 0 unconditional 0 taken 53 86: 2040-block 1 unconditional 1 taken 86 139: 2040-block 2 branch 2 taken 86 branch 3 taken 53 (fallthrough) 86: 2041: int duplicate = 0; 119: 2042: for (d = (i + 1); d < substr_n; d++) { 86: 2042-block 0 unconditional 0 taken 86 33: 2042-block 1 unconditional 1 taken 33 119: 2042-block 2 branch 2 taken 33 branch 3 taken 86 (fallthrough) 33*: 2043: if (*substr[i] == *substr[d] && strcmp(substr[i], substr[d]) == 0) { 33: 2043-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 33 %%%%%: 2043-block 1 branch 2 never executed branch 3 never executed #####: 2044: duplicate = 1; #####: 2045: break; %%%%%: 2045-block 0 unconditional 0 never executed -: 2046: } -: 2047: } -: 2048: 86*: 2049: if (duplicate) { 86: 2049-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 86 #####: 2050: free(substr[i]); #####: 2051: continue; %%%%%: 2051-block 0 unconditional 0 never executed -: 2052: } -: 2053: 86: 2054: dstr = (char **)xrealloc(dstr, (len + 1) * sizeof(char *)); 86: 2054-block 0 call 0 returned 86 86: 2055: dstr[len++] = savestring(substr[i], strlen(substr[i])); call 0 returned 86 86: 2056: free(substr[i]); unconditional 0 taken 86 -: 2057: } -: 2058: 53: 2059: free(substr); 53: 2060: dstr = (char **)xrealloc(dstr, (len + 1) * sizeof(char *)); 53: 2060-block 0 call 0 returned 53 53: 2061: dstr[len] = (char *)NULL; 53: 2062: return dstr; unconditional 0 taken 53 -: 2063:} -: 2064: -: 2065:/* This function simply deescapes whatever escaped chars it founds in -: 2066: * TEXT, so that readline can compare it to system file names when -: 2067: * completing paths. Returns a string containing text without escape -: 2068: * sequences */ -: 2069:char * function dequote_str called 14 returned 100% blocks executed 79% 14: 2070:dequote_str(char *text, int mt) -: 2071:{ -: 2072: UNUSED(mt); 14: 2073: if (!text || !*text) 14: 2073-block 0 branch 0 taken 14 (fallthrough) branch 1 taken 0 14: 2073-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 14 #####: 2074: return (char *)NULL; %%%%%: 2074-block 0 unconditional 0 never executed -: 2075: -: 2076: /* At most, we need as many bytes as text (in case no escape sequence -: 2077: * is found)*/ 14: 2078: char *buf = (char *)NULL; 14: 2079: buf = (char *)xnmalloc(strlen(text) + 1, sizeof(char)); 14: 2079-block 0 call 0 returned 14 14: 2080: size_t len = 0; -: 2081: 331: 2082: while (*text) { unconditional 0 taken 14 331: 2082-block 0 branch 1 taken 317 branch 2 taken 14 (fallthrough) 317: 2083: switch (*text) { 317: 2083-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 317 #####: 2084: case '\\': #####: 2085: buf[len++] = *(++text); #####: 2086: break; %%%%%: 2086-block 0 unconditional 0 never executed 317: 2087: default: 317: 2088: buf[len++] = *text; 317: 2089: break; 317: 2089-block 0 unconditional 0 taken 317 -: 2090: } 317: 2091: if (!*text) 317: 2091-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 317 #####: 2092: break; %%%%%: 2092-block 0 unconditional 0 never executed 317: 2093: text++; 317: 2093-block 0 unconditional 0 taken 317 -: 2094: } -: 2095: 14: 2096: buf[len] = '\0'; 14: 2097: return buf; 14: 2097-block 0 unconditional 0 taken 14 -: 2098:} clifm-1.26.3/misc/codecov/suggestions.c.gcov000066400000000000000000003237101506632037700207440ustar00rootroot00000000000000 -: 0:Source:suggestions.c -: 1:/* suggestions.c -- functions to manage the suggestions system */ -: 2: -: 3:/* -: 4: * This file is part of CliFM -: 5: * -: 6: * Copyright (C) 2016-2021, L. Abramovich -: 7: * All rights reserved. -: 8: -: 9: * CliFM is free software; you can redistribute it and/or modify -: 10: * it under the terms of the GNU General Public License as published by -: 11: * the Free Software Foundation; either version 2 of the License, or -: 12: * (at your option) any later version. -: 13: * -: 14: * CliFM is distributed in the hope that it will be useful, -: 15: * but WITHOUT ANY WARRANTY; without even the implied warranty of -: 16: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -: 17: * GNU General Public License for more details. -: 18: * -: 19: * You should have received a copy of the GNU General Public License -: 20: * along with this program; if not, write to the Free Software -: 21: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, -: 22: * MA 02110-1301, USA. -: 23:*/ -: 24:#ifndef _NO_SUGGESTIONS -: 25: -: 26:#include "helpers.h" -: 27: -: 28:#include -: 29:#include -: 30:#include -: 31:#include -: 32:#ifdef __OpenBSD__ -: 33:#include -: 34:#endif -: 35:#include -: 36:#include -: 37:#include -: 38:#include -: 39: -: 40:#ifdef __linux__ -: 41:#include -: 42:#endif -: 43: -: 44:#ifdef __OpenBSD__ -: 45:typedef char *rl_cpvfunc_t; -: 46:#include -: 47:#else -: 48:#include -: 49:#endif -: 50: -: 51:#include "suggestions.h" -: 52:#include "aux.h" -: 53:#include "checks.h" -: 54:#include "colors.h" -: 55:#include "jump.h" -: 56:#include "readline.h" -: 57: -: 58:static int free_color = 0; -: 59: -: 60:/* The following three functions were taken from -: 61: * https://github.com/antirez/linenoise/blob/master/linenoise.c -: 62: * and modified to fir our needs: they are used to get current cursor -: 63: * position (both vertical and horizontal) by the suggestions system */ -: 64: -: 65:/* Set the terminal into raw mode. Return 0 on success and -1 on error */ -: 66:static int function enable_raw_mode called 873 returned 100% blocks executed 69% 873: 67:enable_raw_mode(const int fd) -: 68:{ -: 69: struct termios raw; -: 70: 873: 71: if (!isatty(STDIN_FILENO)) 873: 71-block 0 call 0 returned 873 branch 1 taken 0 (fallthrough) branch 2 taken 873 #####: 72: goto FAIL; %%%%%: 72-block 0 unconditional 0 never executed -: 73: 873: 74: if (tcgetattr(fd, &orig_termios) == -1) 873: 74-block 0 call 0 returned 873 branch 1 taken 0 (fallthrough) branch 2 taken 873 #####: 75: goto FAIL; %%%%%: 75-block 0 unconditional 0 never executed -: 76: 873: 77: raw = orig_termios; /* modify the original mode */ -: 78: /* input modes: no break, no CR to NL, no parity check, no strip char, -: 79: * * no start/stop output control. */ 873: 80: raw.c_iflag &= (tcflag_t)~(BRKINT | ICRNL | INPCK | ISTRIP | IXON); -: 81: /* output modes - disable post processing */ 873: 82: raw.c_oflag &= (tcflag_t)~(OPOST); -: 83: /* control modes - set 8 bit chars */ 873: 84: raw.c_cflag |= (CS8); -: 85: /* local modes - choing off, canonical off, no extended functions, -: 86: * no signal chars (^Z,^C) */ 873: 87: raw.c_lflag &= (tcflag_t)~(ECHO | ICANON | IEXTEN | ISIG); -: 88: /* control chars - set return condition: min number of bytes and timer. -: 89: * We want read to return every single byte, without timeout. */ 873: 90: raw.c_cc[VMIN] = 1; raw.c_cc[VTIME] = 0; /* 1 byte, no timer */ -: 91: -: 92: /* put terminal in raw mode after flushing */ 873: 93: if (tcsetattr(fd, TCSAFLUSH, &raw) < 0) 873: 93-block 0 call 0 returned 873 branch 1 taken 0 (fallthrough) branch 2 taken 873 #####: 94: goto FAIL; %%%%%: 94-block 0 unconditional 0 never executed -: 95: 873: 96: return 0; 873: 96-block 0 unconditional 0 taken 873 -: 97: #####: 98:FAIL: #####: 99: errno = ENOTTY; #####: 100: return -1; %%%%%: 100-block 0 unconditional 0 never executed -: 101:} -: 102: -: 103:static int function disable_raw_mode called 873 returned 100% blocks executed 80% 873: 104:disable_raw_mode(const int fd) -: 105:{ 873: 106: if (tcsetattr(fd, TCSAFLUSH, &orig_termios) != -1) 873: 106-block 0 call 0 returned 873 branch 1 taken 873 (fallthrough) branch 2 taken 0 873: 107: return EXIT_SUCCESS; 873: 107-block 0 unconditional 0 taken 873 #####: 108: return EXIT_FAILURE; %%%%%: 108-block 0 unconditional 0 never executed -: 109:} -: 110: -: 111:/* Use the "ESC [6n" escape sequence to query the cursor position (both -: 112: * vertical and horizontal) and store both values into global variables. -: 113: * Return 0 on success and 1 on error */ -: 114:static int function get_cursor_position called 873 returned 100% blocks executed 72% 873: 115:get_cursor_position(const int ifd, const int ofd) -: 116:{ -: 117: char buf[32]; -: 118: int cols, rows; 873: 119: unsigned int i = 0; -: 120: 873: 121: if (enable_raw_mode(ifd) == -1) 873: 121-block 0 call 0 returned 873 branch 1 taken 0 (fallthrough) branch 2 taken 873 #####: 122: return EXIT_FAILURE; %%%%%: 122-block 0 unconditional 0 never executed -: 123: -: 124: /* Report cursor location */ 873: 125: if (write(ofd, "\x1b[6n", 4) != 4) 873: 125-block 0 call 0 returned 873 branch 1 taken 0 (fallthrough) branch 2 taken 873 #####: 126: goto FAIL; %%%%%: 126-block 0 unconditional 0 never executed -: 127: -: 128: /* Read the response: "ESC [ rows ; cols R" */ 6241: 129: while (i < sizeof(buf) - 1) { 873: 129-block 0 unconditional 0 taken 873 6241: 129-block 1 branch 1 taken 6241 branch 2 taken 0 (fallthrough) 6241: 130: if (read(ifd, buf + i, 1) != 1) 6241: 130-block 0 call 0 returned 6241 branch 1 taken 0 (fallthrough) branch 2 taken 6241 #####: 131: break; %%%%%: 131-block 0 unconditional 0 never executed 6241: 132: if (buf[i] == 'R') 6241: 132-block 0 branch 0 taken 873 (fallthrough) branch 1 taken 5368 873: 133: break; 873: 133-block 0 unconditional 0 taken 873 5368: 134: i++; 5368: 134-block 0 unconditional 0 taken 5368 -: 135: } 873: 136: buf[i] = '\0'; -: 137: -: 138: /* Parse it */ 873: 139: if (buf[0] != _ESC || buf[1] != '[') 873: 139-block 0 branch 0 taken 873 (fallthrough) branch 1 taken 0 873: 139-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 873 #####: 140: goto FAIL; %%%%%: 140-block 0 unconditional 0 never executed 873: 141: if (sscanf(buf + 2, "%d;%d", &rows, &cols) != 2) 873: 141-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 873 #####: 142: goto FAIL; %%%%%: 142-block 0 unconditional 0 never executed -: 143: 873: 144: currow = rows; 873: 145: curcol = cols; -: 146: 873: 147: disable_raw_mode(ifd); 873: 147-block 0 call 0 returned 873 873: 148: return EXIT_SUCCESS; unconditional 0 taken 873 -: 149: #####: 150:FAIL: #####: 151: disable_raw_mode(ifd); %%%%%: 151-block 0 call 0 never executed #####: 152: return EXIT_FAILURE; unconditional 0 never executed -: 153:} -: 154: -: 155:/* This function is only used before running a keybind command. We don't -: 156: * want the suggestion buffer after running a keybind */ -: 157:void function free_suggestion called 1 returned 100% blocks executed 100% 1: 158:free_suggestion(void) -: 159:{ 1: 160: free(suggestion_buf); 1: 161: suggestion_buf = (char *)NULL; 1: 162: suggestion.printed = 0; 1: 163: suggestion.nlines = 0; 1: 164:} -: 165: -: 166:void function clear_suggestion called 843 returned 100% blocks executed 100% 843: 167:clear_suggestion(void) -: 168:{ -: 169: /* Delete everything in the current line starting from the current -: 170: * cursor position */ 843: 171: if (write(STDOUT_FILENO, DLFC, DLFC_LEN) <= 0) {} 843: 171-block 0 call 0 returned 843 -: 172: 843: 173: if (suggestion.nlines > 1) { branch 0 taken 11 (fallthrough) branch 1 taken 832 -: 174: /* Save cursor position */ 11: 175: get_cursor_position(STDIN_FILENO, STDOUT_FILENO); 11: 175-block 0 call 0 returned 11 -: 176: 11: 177: int i = (int)suggestion.nlines; 22: 178: while (--i > 0) { unconditional 0 taken 11 22: 178-block 0 branch 1 taken 11 branch 2 taken 11 (fallthrough) -: 179: /* Move the cursor to the beginning of the next line */ 11: 180: if (write(STDOUT_FILENO, "\x1b[1E", 4) <= 0) {} 11: 180-block 0 call 0 returned 11 -: 181: /* Delete the line */ 11: 182: if (write(STDOUT_FILENO, "\x1b[0K", 4) <= 0) {} call 0 returned 11 unconditional 1 taken 11 -: 183: } -: 184: /* Restore cursor position */ 11: 185: printf("\x1b[%d;%dH", currow, curcol); 11: 185-block 0 call 0 returned 11 11: 186: fflush(stdout); call 0 returned 11 11: 187: suggestion.nlines = 0; unconditional 0 taken 11 -: 188: } -: 189: 843: 190: suggestion.printed = 0; 843: 191:} -: 192: -: 193:/* Clear the line, print the suggestion (STR) at OFFSET in COLOR, and -: 194: * move the cursor back to the original position. -: 195: * OFFSET marks the point in STR that is already typed: the suggestion -: 196: * will be printed starting from this point */ -: 197:static void function print_suggestion called 862 returned 100% blocks executed 91% 862: 198:print_suggestion(const char *str, size_t offset, const char *color) -: 199:{ 862: 200: if (suggestion.printed) 862: 200-block 0 branch 0 taken 427 (fallthrough) branch 1 taken 435 427: 201: clear_suggestion(); 427: 201-block 0 call 0 returned 427 unconditional 1 taken 427 -: 202: 862: 203: free(suggestion_buf); 862: 204: suggestion_buf = (char *)NULL; -: 205: -: 206: /* Store cursor position in two global variables: currow and curcol */ 862: 207: get_cursor_position(STDIN_FILENO, STDOUT_FILENO); 862: 207-block 0 call 0 returned 862 -: 208: -: 209: /* Do not print suggestions bigger than what the current terminal -: 210: * window size can hold */ 862: 211: size_t suggestion_len = wc_xstrlen(str + offset); call 0 returned 862 862: 212: if ((int)suggestion_len > (term_cols * term_rows) - curcol) branch 0 taken 0 (fallthrough) branch 1 taken 862 #####: 213: return; %%%%%: 213-block 0 unconditional 0 never executed -: 214: 862: 215: size_t cuc = (size_t)curcol; /* Current cursor column position*/ 862: 216: int baej = 0; /* Bookmark, alias, ELN, or jump */ -: 217: 862: 218: if (suggestion.type == BOOKMARK_SUG || suggestion.type == ALIAS_SUG 862: 218-block 0 branch 0 taken 846 (fallthrough) branch 1 taken 16 846: 218-block 1 branch 2 taken 840 (fallthrough) branch 3 taken 6 840: 219: || suggestion.type == ELN_SUG || suggestion.type == JCMD_SUG 840: 219-block 0 branch 0 taken 760 (fallthrough) branch 1 taken 80 760: 219-block 1 branch 2 taken 744 (fallthrough) branch 3 taken 16 744: 220: || suggestion.type == JCMD_SUG_NOACD) { 744: 220-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 744 -: 221: /* 4 = 2 (two chars forward) + 2 (" >") */ 118: 222: cuc += 4; 118: 223: baej = 1; 118: 223-block 0 unconditional 0 taken 118 -: 224: } -: 225: 862: 226: size_t cucs = cuc + suggestion_len; -: 227: /* slines: amount of lines we need to print the suggestion, including -: 228: * the current line */ 862: 229: size_t slines = 1; -: 230: 862: 231: if (cucs > term_cols) { 862: 231-block 0 branch 0 taken 11 (fallthrough) branch 1 taken 851 11: 232: slines = cucs / (size_t)term_cols; 11: 233: int cucs_rem = (int)cucs % term_cols; 11: 234: if (cucs_rem > 0) 11: 234-block 0 branch 0 taken 11 (fallthrough) branch 1 taken 0 11: 235: slines++; 11: 235-block 0 unconditional 0 taken 11 -: 236: } -: 237: 862: 238: if (slines > (size_t)term_rows) 862: 238-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 862 #####: 239: return; %%%%%: 239-block 0 unconditional 0 never executed -: 240: -: 241: /* Store the suggestion in a buffer to be used later by the -: 242: * rl_accept_suggestion function (keybinds.c) */ 862: 243: suggestion_buf = xnmalloc(strlen(str) + 1, sizeof(char)); 862: 243-block 0 call 0 returned 862 862: 244: strcpy(suggestion_buf, str); -: 245: -: 246: /* Erase everything after the current cursor position */ 862: 247: if (write(STDOUT_FILENO, DLFC, DLFC_LEN) <= 0) {} call 0 returned 862 -: 248: -: 249: /* If not at the end of the line, move the cursor there */ 862: 250: if (rl_end > rl_point) branch 0 taken 2 (fallthrough) branch 1 taken 860 2: 251: printf("\x1b[%dC", rl_end - rl_point); 2: 251-block 0 call 0 returned 2 unconditional 1 taken 2 -: 252: /* rl_end and rl_point are not updated: they do not include -: 253: * the last typed char. However, since we only care here about -: 254: * the difference between them, it doesn't matter: the result -: 255: * is the same (7 - 4 == 6 - 3 == 1) */ -: 256: 862: 257: if (baej) { 862: 257-block 0 branch 0 taken 118 (fallthrough) branch 1 taken 744 -: 258: /* Move the cursor two columns to the right and print "> " */ 118: 259: printf("\x1b[2C"); 118: 259-block 0 call 0 returned 118 118: 260: printf("%s> \x1b[0m", mi_c); call 0 returned 118 unconditional 1 taken 118 -: 261: } -: 262: -: 263: /* Print the suggestion */ -: 264:// printf("%s%s%s", color, str + offset - (offset ? 1 : 0), df_c); 862*: 265: printf("%s%s", color, str + offset - (offset ? 1 : 0)); 862: 265-block 0 branch 0 taken 862 (fallthrough) branch 1 taken 0 862: 265-block 1 unconditional 2 taken 862 %%%%%: 265-block 2 unconditional 3 never executed 862: 265-block 3 call 4 returned 862 862: 266: fflush(stdout); call 0 returned 862 -: 267: -: 268: /* Update the row number, if needed */ -: 269: /* If the cursor is in the last row, printing a multi-line suggestion -: 270: * will move the beginning of the current line up the number of -: 271: * lines taken by the suggestion, so that we need to update the -: 272: * value to move the cursor back to the correct row (the beginning -: 273: * of the line) */ 862: 274: int old_currow = currow; -: 275: /* extra_rows: amount of extra rows we need to print the suggestion -: 276: * (excluding the current row) */ 862: 277: int extra_rows = (int)slines - 1; 862: 278: if (extra_rows && old_currow + extra_rows >= term_rows) branch 0 taken 11 (fallthrough) branch 1 taken 851 11: 278-block 0 branch 2 taken 11 (fallthrough) branch 3 taken 0 11: 279: currow -= extra_rows - (term_rows - old_currow); 11: 279-block 0 unconditional 0 taken 11 -: 280: -: 281: /* Restore cursor position */ 862: 282: printf("\x1b[%d;%dH", currow, curcol); 862: 282-block 0 call 0 returned 862 -: 283: -: 284: /* Store the amount of lines taken by the current command line -: 285: * (plus the suggestion's length) to be able to correctly -: 286: * remove it later (via the clear_suggestion function) */ 862: 287: suggestion.nlines = slines; 862: 288: return; unconditional 0 taken 862 -: 289:} -: 290: -: 291:/* Used by the check_completions function to get file names color -: 292: * according to file type */ -: 293:static char * function get_comp_color called 0 returned 0% blocks executed 0% #####: 294:get_comp_color(const char *filename, const struct stat attr) -: 295:{ #####: 296: char *color = no_c; -: 297: #####: 298: switch(attr.st_mode & S_IFMT) { %%%%%: 298-block 0 branch 0 never executed branch 1 never executed branch 2 never executed branch 3 never executed branch 4 never executed branch 5 never executed branch 6 never executed branch 7 never executed #####: 299: case S_IFDIR: #####: 300: if (light_mode) %%%%%: 300-block 0 branch 0 never executed branch 1 never executed #####: 301: return di_c; %%%%%: 301-block 0 unconditional 0 never executed #####: 302: if (access(filename, R_OK | X_OK) != 0) { %%%%%: 302-block 0 call 0 never executed branch 1 never executed branch 2 never executed #####: 303: color = nd_c; %%%%%: 303-block 0 unconditional 0 never executed -: 304: } else { #####: 305: int sticky = 0; #####: 306: int is_oth_w = 0; #####: 307: if (attr.st_mode & S_ISVTX) %%%%%: 307-block 0 branch 0 never executed branch 1 never executed #####: 308: sticky = 1; %%%%%: 308-block 0 unconditional 0 never executed -: 309: #####: 310: if (attr.st_mode & S_IWOTH) %%%%%: 310-block 0 branch 0 never executed branch 1 never executed #####: 311: is_oth_w = 1; %%%%%: 311-block 0 unconditional 0 never executed -: 312: #####: 313: int files_dir = count_dir(filename, CPOP); %%%%%: 313-block 0 call 0 never executed -: 314: #####: 315: color = sticky ? (is_oth_w ? tw_c : st_c) : is_oth_w ? ow_c branch 0 never executed branch 1 never executed %%%%%: 315-block 0 branch 2 never executed branch 3 never executed %%%%%: 315-block 1 unconditional 4 never executed %%%%%: 315-block 2 unconditional 5 never executed %%%%%: 315-block 3 unconditional 6 never executed %%%%%: 315-block 4 unconditional 7 never executed %%%%%: 315-block 5 unconditional 8 never executed #####: 316: : ((files_dir == 2 || files_dir == 0) ? ed_c : di_c); %%%%%: 316-block 0 branch 0 never executed branch 1 never executed %%%%%: 316-block 1 branch 2 never executed branch 3 never executed %%%%%: 316-block 2 branch 4 never executed branch 5 never executed %%%%%: 316-block 3 unconditional 6 never executed %%%%%: 316-block 4 unconditional 7 never executed %%%%%: 316-block 5 unconditional 8 never executed %%%%%: 316-block 6 unconditional 9 never executed -: 317: } #####: 318: break; %%%%%: 318-block 0 unconditional 0 never executed -: 319: #####: 320: case S_IFREG: #####: 321: if (light_mode) %%%%%: 321-block 0 branch 0 never executed branch 1 never executed #####: 322: return fi_c; %%%%%: 322-block 0 unconditional 0 never executed #####: 323: if (access(filename, R_OK) == -1) %%%%%: 323-block 0 call 0 never executed branch 1 never executed branch 2 never executed #####: 324: color = nf_c; %%%%%: 324-block 0 unconditional 0 never executed #####: 325: else if (attr.st_mode & S_ISUID) %%%%%: 325-block 0 branch 0 never executed branch 1 never executed #####: 326: color = su_c; %%%%%: 326-block 0 unconditional 0 never executed #####: 327: else if (attr.st_mode & S_ISGID) %%%%%: 327-block 0 branch 0 never executed branch 1 never executed #####: 328: color = sg_c; %%%%%: 328-block 0 unconditional 0 never executed -: 329: else { -: 330:#ifdef _LINUX_CAP #####: 331: cap_t cap = cap_get_file(filename); %%%%%: 331-block 0 call 0 never executed #####: 332: if (cap) { branch 0 never executed branch 1 never executed #####: 333: color = ca_c; #####: 334: cap_free(cap); %%%%%: 334-block 0 call 0 never executed unconditional 1 never executed #####: 335: } else if (attr.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) { %%%%%: 335-block 0 branch 0 never executed branch 1 never executed -: 336:#else -: 337: if (attr.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) { -: 338:#endif #####: 339: if (attr.st_size == 0) %%%%%: 339-block 0 branch 0 never executed branch 1 never executed #####: 340: color = ee_c; %%%%%: 340-block 0 unconditional 0 never executed -: 341: else #####: 342: color = ex_c; %%%%%: 342-block 0 unconditional 0 never executed #####: 343: } else if (attr.st_size == 0) %%%%%: 343-block 0 branch 0 never executed branch 1 never executed #####: 344: color = ef_c; %%%%%: 344-block 0 unconditional 0 never executed #####: 345: else if (attr.st_nlink > 1) %%%%%: 345-block 0 branch 0 never executed branch 1 never executed #####: 346: color = mh_c; %%%%%: 346-block 0 unconditional 0 never executed -: 347: else { #####: 348: char *ext = strrchr(filename, '.'); #####: 349: if (ext && ext != filename) { %%%%%: 349-block 0 branch 0 never executed branch 1 never executed %%%%%: 349-block 1 branch 2 never executed branch 3 never executed %%%%%: 349-block 2 unconditional 4 never executed #####: 350: char *extcolor = get_ext_color(ext); %%%%%: 350-block 0 call 0 never executed #####: 351: if (extcolor) { branch 0 never executed branch 1 never executed #####: 352: char *ext_color = (char *)xnmalloc(strlen(extcolor) %%%%%: 352-block 0 call 0 never executed -: 353: + 4, sizeof(char)); #####: 354: sprintf(ext_color, "\x1b[%sm", extcolor); #####: 355: color = ext_color; #####: 356: free_color = 1; #####: 357: extcolor = (char *)NULL; unconditional 0 never executed -: 358: } else { #####: 359: color = fi_c; %%%%%: 359-block 0 unconditional 0 never executed -: 360: } -: 361: } else { #####: 362: color = fi_c; %%%%%: 362-block 0 unconditional 0 never executed -: 363: } -: 364: } -: 365: } #####: 366: break; %%%%%: 366-block 0 unconditional 0 never executed -: 367: #####: 368: case S_IFLNK: { #####: 369: if (light_mode) %%%%%: 369-block 0 branch 0 never executed branch 1 never executed #####: 370: return ln_c; %%%%%: 370-block 0 unconditional 0 never executed #####: 371: char *linkname = realpath(filename, (char *)NULL); %%%%%: 371-block 0 call 0 never executed #####: 372: if (linkname) branch 0 never executed branch 1 never executed #####: 373: color = ln_c; %%%%%: 373-block 0 unconditional 0 never executed -: 374: else #####: 375: color = or_c; %%%%%: 375-block 0 unconditional 0 never executed -: 376: } #####: 377: break; %%%%%: 377-block 0 unconditional 0 never executed -: 378: #####: 379: case S_IFSOCK: color = so_c; break; %%%%%: 379-block 0 unconditional 0 never executed #####: 380: case S_IFBLK: color = bd_c; break; %%%%%: 380-block 0 unconditional 0 never executed #####: 381: case S_IFCHR: color = cd_c; break; %%%%%: 381-block 0 unconditional 0 never executed #####: 382: case S_IFIFO: color = pi_c; break; %%%%%: 382-block 0 unconditional 0 never executed #####: 383: default: color = no_c; break; %%%%%: 383-block 0 unconditional 0 never executed -: 384: } -: 385: #####: 386: return color; %%%%%: 386-block 0 unconditional 0 never executed -: 387:} -: 388: -: 389:static int function check_completions called 402 returned 100% blocks executed 70% 402: 390:check_completions(const char *str, size_t len, const unsigned char c) -: 391:{ 402: 392: int printed = 0; -: 393: size_t i; -: 394: struct stat attr; 402: 395: char **_matches = rl_completion_matches(str, rl_completion_entry_function); 402: 395-block 0 call 0 returned 402 -: 396: 402: 397: suggestion.filetype = DT_REG; 402: 398: free_color = 0; -: 399: 402: 400: char *color = (char *)NULL, *_color = (char *)NULL; 402: 401: if (suggest_filetype_color) branch 0 taken 0 (fallthrough) branch 1 taken 402 #####: 402: color = no_c; %%%%%: 402-block 0 unconditional 0 never executed -: 403: else 402: 404: color = sf_c; 402: 404-block 0 unconditional 0 taken 402 -: 405: 402: 406: if (!_matches) 402: 406-block 0 branch 0 taken 376 (fallthrough) branch 1 taken 26 376: 407: return printed; 376: 407-block 0 unconditional 0 taken 376 -: 408: 26: 409: if (!len) 26: 409-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 26 #####: 410: goto FREE; %%%%%: 410-block 0 unconditional 0 never executed -: 411: -: 412: /* If only one match */ 26: 413: if (_matches[0] && *_matches[0] && strlen(_matches[0]) > len) { 26: 413-block 0 branch 0 taken 26 (fallthrough) branch 1 taken 0 26: 413-block 1 branch 2 taken 26 (fallthrough) branch 3 taken 0 26: 413-block 2 branch 4 taken 2 (fallthrough) branch 5 taken 24 2: 414: int append_slash = 0; -: 415: 2: 416: char *p = (char *)NULL; 2: 417: if (*_matches[0] == '~') 2: 417-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 2 #####: 418: p = tilde_expand(_matches[0]); %%%%%: 418-block 0 call 0 never executed unconditional 1 never executed -: 419: 2*: 420: if (lstat(p ? p : _matches[0], &attr) != -1) { 2: 420-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 0 2: 420-block 1 unconditional 2 taken 2 %%%%%: 420-block 2 unconditional 3 never executed 2: 420-block 3 call 4 returned 2 branch 5 taken 2 (fallthrough) branch 6 taken 0 2: 421: if ((attr.st_mode & S_IFMT) == S_IFDIR) { 2: 421-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 1 1: 422: append_slash = 1; 1: 423: suggestion.filetype = DT_DIR; 1: 423-block 0 unconditional 0 taken 1 -: 424: } 2: 425: if (suggest_filetype_color) 2: 425-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 2 #####: 426: color = get_comp_color(p ? p : _matches[0], attr); %%%%%: 426-block 0 branch 0 never executed branch 1 never executed %%%%%: 426-block 1 unconditional 2 never executed %%%%%: 426-block 2 unconditional 3 never executed %%%%%: 426-block 3 call 4 never executed unconditional 5 never executed -: 427: } else { -: 428: /* We have a partial completion. Set filetype to DT_DIR -: 429: * so that the rl_accept_suggestion function won't append -: 430: * a space after the file name */ #####: 431: suggestion.filetype = DT_DIR; %%%%%: 431-block 0 unconditional 0 never executed -: 432: } -: 433: 2: 434: free(p); -: 435: -: 436: char t[NAME_MAX + 2]; 2: 437: *t = '\0'; 2: 438: if (append_slash) 2: 438-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 1 1: 439: snprintf(t, NAME_MAX + 2, "%s/", _matches[0]); 1: 439-block 0 unconditional 0 taken 1 2: 440: char *tmp = escape_str(*t ? t : _matches[0]); 2: 440-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 1 1: 440-block 1 unconditional 2 taken 1 1: 440-block 2 unconditional 3 taken 1 2: 440-block 3 call 4 returned 2 -: 441: 2: 442: if (c != BS) branch 0 taken 2 (fallthrough) branch 1 taken 0 2: 443: suggestion.type = COMP_SUG; 2: 443-block 0 unconditional 0 taken 2 -: 444: 2: 445: if (tmp) { 2: 445-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 0 2: 446: print_suggestion(tmp, len, color); 2: 446-block 0 call 0 returned 2 2: 447: free(tmp); unconditional 0 taken 2 -: 448: } else { #####: 449: print_suggestion(_matches[0], len, color); %%%%%: 449-block 0 call 0 never executed unconditional 1 never executed -: 450: } -: 451: 2: 452: printed = 1; 2: 452-block 0 unconditional 0 taken 2 -: 453: } else { -: 454: /* If multiple matches, suggest the first one */ 24: 455: if (_matches[1] && *_matches[1] 24: 455-block 0 branch 0 taken 10 (fallthrough) branch 1 taken 14 14: 455-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 14 14: 456: && strlen(_matches[1]) > len) { 14: 456-block 0 branch 0 taken 4 (fallthrough) branch 1 taken 10 10: 457: int append_slash = 0; -: 458: 10: 459: char *p = (char *)NULL; 10: 460: if (*_matches[1] == '~') 10: 460-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 10 #####: 461: p = tilde_expand(_matches[1]); %%%%%: 461-block 0 call 0 never executed unconditional 1 never executed -: 462: 10*: 463: if (lstat(p ? p : _matches[1], &attr) != -1) { 10: 463-block 0 branch 0 taken 10 (fallthrough) branch 1 taken 0 10: 463-block 1 unconditional 2 taken 10 %%%%%: 463-block 2 unconditional 3 never executed 10: 463-block 3 call 4 returned 10 branch 5 taken 10 (fallthrough) branch 6 taken 0 10: 464: if ((attr.st_mode & S_IFMT) == S_IFDIR) { 10: 464-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 10 #####: 465: append_slash = 1; #####: 466: suggestion.filetype = DT_DIR; %%%%%: 466-block 0 unconditional 0 never executed -: 467: } -: 468: 10: 469: if (suggest_filetype_color) { 10: 469-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 10 #####: 470: _color = get_comp_color(p ? p : _matches[1], attr); %%%%%: 470-block 0 branch 0 never executed branch 1 never executed %%%%%: 470-block 1 unconditional 2 never executed %%%%%: 470-block 2 unconditional 3 never executed %%%%%: 470-block 3 call 4 never executed #####: 471: if (_color) branch 0 never executed branch 1 never executed #####: 472: color = _color; %%%%%: 472-block 0 unconditional 0 never executed -: 473: } -: 474: } else { #####: 475: suggestion.filetype = DT_DIR; %%%%%: 475-block 0 unconditional 0 never executed -: 476: } -: 477: 10: 478: free(p); -: 479: -: 480: char _tmp[NAME_MAX + 2]; 10: 481: *_tmp = '\0'; 10: 482: if (append_slash) 10: 482-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 10 #####: 483: snprintf(_tmp, NAME_MAX + 2, "%s/", _matches[1]); %%%%%: 483-block 0 unconditional 0 never executed 10*: 484: char *tmp = escape_str(*_tmp ? _tmp : _matches[1]); 10: 484-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 10 %%%%%: 484-block 1 unconditional 2 never executed 10: 484-block 2 unconditional 3 taken 10 10: 484-block 3 call 4 returned 10 -: 485: 10: 486: if (c != BS) branch 0 taken 10 (fallthrough) branch 1 taken 0 10: 487: suggestion.type = COMP_SUG; 10: 487-block 0 unconditional 0 taken 10 -: 488: 10: 489: if (tmp) { 10: 489-block 0 branch 0 taken 10 (fallthrough) branch 1 taken 0 10: 490: print_suggestion(tmp, len, color); 10: 490-block 0 call 0 returned 10 10: 491: free(tmp); unconditional 0 taken 10 -: 492: } else { #####: 493: print_suggestion(_matches[1], len, color); %%%%%: 493-block 0 call 0 never executed unconditional 1 never executed -: 494: } -: 495: 10: 496: printed = 1; 10: 496-block 0 unconditional 0 taken 10 -: 497: } -: 498: } -: 499: 14*: 500:FREE: 10: 500-block 0 unconditional 0 taken 10 %%%%%: 500-block 1 unconditional 1 never executed 4: 500-block 2 unconditional 2 taken 4 4153: 501: for (i = 0; _matches[i]; i++) 26: 501-block 0 unconditional 0 taken 26 4153: 501-block 1 branch 1 taken 4127 branch 2 taken 26 (fallthrough) 4127: 502: free(_matches[i]); 4127: 502-block 0 unconditional 0 taken 4127 26: 503: free(_matches); -: 504: 26: 505: if (free_color) { 26: 505-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 26 #####: 506: free(_color); #####: 507: free_color = 0; %%%%%: 507-block 0 unconditional 0 never executed -: 508: } -: 509: 26: 510: return printed; 26: 510-block 0 unconditional 0 taken 26 -: 511:} -: 512: -: 513:static int function check_filenames called 446 returned 100% blocks executed 84% 446: 514:check_filenames(const char *str, const size_t len, const unsigned char c, const int first_word) -: 515:{ 446: 516: int i = (int)files; 446: 517: char *color = (char *)NULL; -: 518: 446: 519: if (suggest_filetype_color) 446: 519-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 446 #####: 520: color = no_c; %%%%%: 520-block 0 unconditional 0 never executed -: 521: else 446: 522: color = sf_c; 446: 522-block 0 unconditional 0 taken 446 -: 523: 35844: 524: while (--i >= 0) { 446: 524-block 0 unconditional 0 taken 446 35844: 524-block 1 branch 1 taken 35414 branch 2 taken 430 (fallthrough) 35414: 525: if (!file_info[i].name || TOUPPER(*str) != TOUPPER(*file_info[i].name)) 35414: 525-block 0 branch 0 taken 35414 (fallthrough) branch 1 taken 0 35414: 525-block 1 branch 2 taken 24045 (fallthrough) branch 3 taken 11369 24045: 525-block 2 branch 4 taken 24045 (fallthrough) branch 5 taken 0 24045: 525-block 3 unconditional 6 taken 24045 11369: 525-block 4 unconditional 7 taken 11369 35414: 525-block 5 branch 8 taken 34440 (fallthrough) branch 9 taken 974 34440: 525-block 6 branch 10 taken 34440 (fallthrough) branch 11 taken 0 34440: 525-block 7 unconditional 12 taken 34440 974: 525-block 8 unconditional 13 taken 974 35414: 525-block 9 branch 14 taken 33676 (fallthrough) branch 15 taken 1738 33676: 526: continue; 33676: 526-block 0 unconditional 0 taken 33676 3476*: 527: if (len && (case_sens_path_comp ? strncmp(str, file_info[i].name, len) 1738: 527-block 0 branch 0 taken 1738 (fallthrough) branch 1 taken 0 1738: 527-block 1 branch 2 taken 17 (fallthrough) branch 3 taken 1721 1738*: 528: : strncasecmp(str, file_info[i].name, len)) == 0 1738: 528-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 1738 %%%%%: 528-block 1 unconditional 2 never executed 1738: 528-block 2 unconditional 3 taken 1738 17: 529: && file_info[i].len > len) { 17: 529-block 0 branch 0 taken 16 (fallthrough) branch 1 taken 1 16: 530: if (suggest_filetype_color) 16: 530-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 16 #####: 531: color = file_info[i].color; %%%%%: 531-block 0 unconditional 0 never executed -: 532: 16: 533: if (file_info[i].dir) { 16: 533-block 0 branch 0 taken 4 (fallthrough) branch 1 taken 12 4*: 534: if (first_word && !autocd) 4: 534-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 4 %%%%%: 534-block 1 branch 2 never executed branch 3 never executed #####: 535: continue; %%%%%: 535-block 0 unconditional 0 never executed -: 536: 4: 537: suggestion.filetype = DT_DIR; -: 538: -: 539: char tmp[NAME_MAX + 2]; 4: 540: snprintf(tmp, NAME_MAX + 2, "%s/", file_info[i].name); -: 541: 4: 542: if (c != BS) 4: 542-block 0 branch 0 taken 4 (fallthrough) branch 1 taken 0 4: 543: suggestion.type = FILE_SUG; 4: 543-block 0 unconditional 0 taken 4 -: 544: 4: 545: char *_tmp = escape_str(tmp); 4: 545-block 0 call 0 returned 4 4: 546: if (_tmp) { branch 0 taken 4 (fallthrough) branch 1 taken 0 4: 547: print_suggestion(_tmp, len, color); 4: 547-block 0 call 0 returned 4 4: 548: free(_tmp); unconditional 0 taken 4 -: 549: } else { #####: 550: print_suggestion(tmp, len, color); %%%%%: 550-block 0 call 0 never executed unconditional 1 never executed -: 551: } -: 552: } else { 12*: 553: if (first_word && !auto_open) 12: 553-block 0 branch 0 taken 9 (fallthrough) branch 1 taken 3 9: 553-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 9 #####: 554: continue; %%%%%: 554-block 0 unconditional 0 never executed -: 555: 12: 556: if (c != BS) 12: 556-block 0 branch 0 taken 12 (fallthrough) branch 1 taken 0 12: 557: suggestion.type = FILE_SUG; 12: 557-block 0 unconditional 0 taken 12 12: 558: suggestion.filetype = DT_REG; -: 559: 12: 560: char *tmp = escape_str(file_info[i].name); 12: 560-block 0 call 0 returned 12 12: 561: if (tmp) { branch 0 taken 12 (fallthrough) branch 1 taken 0 12: 562: print_suggestion(tmp, len, color); 12: 562-block 0 call 0 returned 12 12: 563: free(tmp); unconditional 0 taken 12 -: 564: } else { #####: 565: print_suggestion(file_info[i].name, len, color); %%%%%: 565-block 0 call 0 never executed unconditional 1 never executed -: 566: } -: 567: } 16: 568: return 1; 16: 568-block 0 unconditional 0 taken 16 -: 569: } -: 570: } 430: 571: return 0; 430: 571-block 0 unconditional 0 taken 430 -: 572:} -: 573: -: 574:static int function check_history called 851 returned 100% blocks executed 92% 851: 575:check_history(const char *str, const size_t len) -: 576:{ 851: 577: if (!str || !*str || !len) 851: 577-block 0 branch 0 taken 851 (fallthrough) branch 1 taken 0 851: 577-block 1 branch 2 taken 851 (fallthrough) branch 3 taken 0 851: 577-block 2 branch 4 taken 0 (fallthrough) branch 5 taken 851 #####: 578: return 0; %%%%%: 578-block 0 unconditional 0 never executed -: 579: 851: 580: int i = (int)current_hist_n; 505453: 581: while (--i >= 0) { 851: 581-block 0 unconditional 0 taken 851 505453: 581-block 1 branch 1 taken 505007 branch 2 taken 446 (fallthrough) 505007: 582: if (!history[i] || TOUPPER(*str) != TOUPPER(*history[i])) 505007: 582-block 0 branch 0 taken 505007 (fallthrough) branch 1 taken 0 505007: 582-block 1 branch 2 taken 413020 (fallthrough) branch 3 taken 91987 413020: 582-block 2 branch 4 taken 413020 (fallthrough) branch 5 taken 0 413020: 582-block 3 unconditional 6 taken 413020 91987: 582-block 4 unconditional 7 taken 91987 505007: 582-block 5 branch 8 taken 361424 (fallthrough) branch 9 taken 143583 361424: 582-block 6 branch 10 taken 361424 (fallthrough) branch 11 taken 0 361424: 582-block 7 unconditional 12 taken 361424 143583: 582-block 8 unconditional 13 taken 143583 505007: 582-block 9 branch 14 taken 485155 (fallthrough) branch 15 taken 19852 485155: 583: continue; 485155: 583-block 0 unconditional 0 taken 485155 -: 584: 19852*: 585: if ((case_sens_path_comp ? strncmp(str, history[i], len) 19852: 585-block 0 branch 0 taken 1853 (fallthrough) branch 1 taken 17999 19852*: 586: : strncasecmp(str, history[i], len)) == 0 19852: 586-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 19852 %%%%%: 586-block 1 unconditional 2 never executed 19852: 586-block 2 unconditional 3 taken 19852 1853: 587: && strlen(history[i]) > len) { 1853: 587-block 0 branch 0 taken 405 (fallthrough) branch 1 taken 1448 405: 588: suggestion.type = HIST_SUG; 405: 589: print_suggestion(history[i], len, sh_c); 405: 589-block 0 call 0 returned 405 405: 590: return 1; unconditional 0 taken 405 -: 591: } -: 592: } -: 593: 446: 594: return 0; 446: 594-block 0 unconditional 0 taken 446 -: 595:} -: 596: -: 597:static int function check_cmds called 284 returned 100% blocks executed 94% 284: 598:check_cmds(const char *str, const size_t len) -: 599:{ 284: 600: int i = (int)path_progsn; 861672: 601: while (--i >= 0) { 284: 601-block 0 unconditional 0 taken 284 861672: 601-block 1 branch 1 taken 861547 branch 2 taken 125 (fallthrough) 861547: 602: if (!bin_commands[i] || *str != *bin_commands[i]) 861547: 602-block 0 branch 0 taken 861547 (fallthrough) branch 1 taken 0 861547: 602-block 1 branch 2 taken 840121 (fallthrough) branch 3 taken 21426 840121: 603: continue; 840121: 603-block 0 unconditional 0 taken 840121 -: 604: 21426: 605: if (len && strncmp(str, bin_commands[i], len) == 0 21426: 605-block 0 branch 0 taken 21426 (fallthrough) branch 1 taken 0 21426: 605-block 1 branch 2 taken 166 (fallthrough) branch 3 taken 21260 166: 606: && strlen(bin_commands[i]) > len) { 166: 606-block 0 branch 0 taken 159 (fallthrough) branch 1 taken 7 159: 607: if (is_internal_c(bin_commands[i])) { 159: 607-block 0 call 0 returned 159 branch 1 taken 4 (fallthrough) branch 2 taken 155 4: 608: suggestion.type = CMD_SUG; 4: 609: print_suggestion(bin_commands[i], len, sx_c); 4: 609-block 0 call 0 returned 4 unconditional 1 taken 4 155*: 610: } else if (ext_cmd_ok) { 155: 610-block 0 branch 0 taken 155 (fallthrough) branch 1 taken 0 155: 611: suggestion.type = CMD_SUG; 155: 612: print_suggestion(bin_commands[i], len, sc_c); 155: 612-block 0 call 0 returned 155 unconditional 1 taken 155 -: 613: } else { #####: 614: continue; %%%%%: 614-block 0 unconditional 0 never executed -: 615: } 159: 616: return 1; 159: 616-block 0 unconditional 0 taken 159 -: 617: } -: 618: } -: 619: 125: 620: return 0; 125: 620-block 0 unconditional 0 taken 125 -: 621:} -: 622: -: 623:static int function check_jumpdb called 428 returned 100% blocks executed 84% 428: 624:check_jumpdb(const char *str, const size_t len) -: 625:{ 428: 626: char *color = (char *)NULL; -: 627: 428: 628: if (suggest_filetype_color) 428: 628-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 428 #####: 629: color = di_c; %%%%%: 629-block 0 unconditional 0 never executed -: 630: else 428: 631: color = sf_c; 428: 631-block 0 unconditional 0 taken 428 -: 632: 428: 633: int i = (int)jump_n; 20833: 634: while (--i >= 0) { 428: 634-block 0 unconditional 0 taken 428 20833: 634-block 1 branch 1 taken 20411 branch 2 taken 422 (fallthrough) 20411*: 635: if (!jump_db[i].path || TOUPPER(*str) != TOUPPER(*jump_db[i].path)) 20411: 635-block 0 branch 0 taken 20411 (fallthrough) branch 1 taken 0 20411: 635-block 1 branch 2 taken 14810 (fallthrough) branch 3 taken 5601 14810: 635-block 2 branch 4 taken 14810 (fallthrough) branch 5 taken 0 14810: 635-block 3 unconditional 6 taken 14810 5601: 635-block 4 unconditional 7 taken 5601 20411: 635-block 5 branch 8 taken 0 (fallthrough) branch 9 taken 20411 %%%%%: 635-block 6 branch 10 never executed branch 11 never executed %%%%%: 635-block 7 unconditional 12 never executed 20411: 635-block 8 unconditional 13 taken 20411 20411: 635-block 9 branch 14 taken 18686 (fallthrough) branch 15 taken 1725 18686: 636: continue; 18686: 636-block 0 unconditional 0 taken 18686 -: 637: 1725: 638: size_t db_len = strlen(jump_db[i].path); 3450*: 639: if (len && (case_sens_path_comp ? strncmp(str, jump_db[i].path, len) 1725: 639-block 0 branch 0 taken 1725 (fallthrough) branch 1 taken 0 1725: 639-block 1 branch 2 taken 15 (fallthrough) branch 3 taken 1710 1725*: 640: : strncasecmp(str, jump_db[i].path, len)) == 0 1725: 640-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 1725 %%%%%: 640-block 1 unconditional 2 never executed 1725: 640-block 2 unconditional 3 taken 1725 15: 641: && db_len > len) { 15: 641-block 0 branch 0 taken 6 (fallthrough) branch 1 taken 9 6: 642: suggestion.type = FILE_SUG; 6: 643: suggestion.filetype = DT_DIR; -: 644: char tmp[NAME_MAX + 2]; 6: 645: *tmp = '\0'; 6: 646: if (jump_db[i].path[db_len - 1] != '/') 6: 646-block 0 branch 0 taken 6 (fallthrough) branch 1 taken 0 6: 647: snprintf(tmp, NAME_MAX + 2, "%s/", jump_db[i].path); 6: 647-block 0 unconditional 0 taken 6 6*: 648: print_suggestion(*tmp ? tmp : jump_db[i].path, len, color); 6: 648-block 0 branch 0 taken 6 (fallthrough) branch 1 taken 0 6: 648-block 1 unconditional 2 taken 6 %%%%%: 648-block 2 unconditional 3 never executed 6: 648-block 3 call 4 returned 6 6: 649: return 1; unconditional 0 taken 6 -: 650: } -: 651: } -: 652: 422: 653: return 0; 422: 653-block 0 unconditional 0 taken 422 -: 654:} -: 655: -: 656:static int function check_bookmarks called 424 returned 100% blocks executed 73% 424: 657:check_bookmarks(const char *str, const size_t len) -: 658:{ 424: 659: if (!bm_n) 424: 659-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 424 #####: 660: return 0; %%%%%: 660-block 0 unconditional 0 never executed -: 661: 424: 662: char *color = (char *)NULL; -: 663: struct stat attr; 424: 664: if (!suggest_filetype_color) 424: 664-block 0 branch 0 taken 424 (fallthrough) branch 1 taken 0 424: 665: color = sf_c; 424: 665-block 0 unconditional 0 taken 424 -: 666: 424: 667: int i = (int)bm_n; 9535: 668: while (--i >= 0) { 424: 668-block 0 unconditional 0 taken 424 9535: 668-block 1 branch 1 taken 9127 branch 2 taken 408 (fallthrough) 9127: 669: if (!bookmarks[i].name || TOUPPER(*str) != TOUPPER(*bookmarks[i].name)) 9127: 669-block 0 branch 0 taken 7443 (fallthrough) branch 1 taken 1684 7443: 669-block 1 branch 2 taken 5409 (fallthrough) branch 3 taken 2034 5409: 669-block 2 branch 4 taken 5409 (fallthrough) branch 5 taken 0 5409: 669-block 3 unconditional 6 taken 5409 2034: 669-block 4 unconditional 7 taken 2034 7443: 669-block 5 branch 8 taken 2480 (fallthrough) branch 9 taken 4963 2480: 669-block 6 branch 10 taken 2480 (fallthrough) branch 11 taken 0 2480: 669-block 7 unconditional 12 taken 2480 4963: 669-block 8 unconditional 13 taken 4963 7443: 669-block 9 branch 14 taken 7096 (fallthrough) branch 15 taken 347 8780: 670: continue; 8780: 670-block 0 unconditional 0 taken 8780 -: 671: 694*: 672: if (len && (case_sens_path_comp ? strncmp(str, bookmarks[i].name, len) 347: 672-block 0 branch 0 taken 347 (fallthrough) branch 1 taken 0 347: 672-block 1 branch 2 taken 16 (fallthrough) branch 3 taken 331 347*: 673: : strncasecmp(str, bookmarks[i].name, len)) == 0) { 347: 673-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 347 %%%%%: 673-block 1 unconditional 2 never executed 347: 673-block 2 unconditional 3 taken 347 16*: 674: if (lstat(bookmarks[i].path, &attr) == -1) 16: 674-block 0 call 0 returned 16 branch 1 taken 0 (fallthrough) branch 2 taken 16 #####: 675: continue; %%%%%: 675-block 0 unconditional 0 never executed -: 676: 16: 677: else if ((attr.st_mode & S_IFMT) == S_IFDIR) { 16: 677-block 0 branch 0 taken 16 (fallthrough) branch 1 taken 0 16: 678: suggestion.type = BOOKMARK_SUG; 16: 679: suggestion.filetype = DT_DIR; -: 680: -: 681: char tmp[PATH_MAX + 2]; 16: 682: size_t path_len = strlen(bookmarks[i].path); 16: 683: if (bookmarks[i].path[path_len - 1] != '/') 16: 683-block 0 branch 0 taken 14 (fallthrough) branch 1 taken 2 14: 684: snprintf(tmp, PATH_MAX + 2, "%s/", bookmarks[i].path); 14: 684-block 0 unconditional 0 taken 14 -: 685: else 2: 686: xstrsncpy(tmp, bookmarks[i].path, PATH_MAX + 2); 2: 686-block 0 call 0 returned 2 unconditional 1 taken 2 -: 687: 16: 688: if (suggest_filetype_color) 16: 688-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 16 #####: 689: color = di_c; %%%%%: 689-block 0 unconditional 0 never executed -: 690: 16: 691: char *_tmp = escape_str(tmp); 16: 691-block 0 call 0 returned 16 16*: 692: print_suggestion(_tmp ? _tmp : tmp, 1, color); branch 0 taken 0 (fallthrough) branch 1 taken 16 %%%%%: 692-block 0 unconditional 2 never executed 16: 692-block 1 unconditional 3 taken 16 16: 692-block 2 call 4 returned 16 16: 693: if (_tmp) branch 0 taken 16 (fallthrough) branch 1 taken 0 16: 694: free(_tmp); 16: 694-block 0 unconditional 0 taken 16 -: 695: } else { #####: 696: suggestion.type = BOOKMARK_SUG; #####: 697: suggestion.filetype = DT_REG; -: 698: #####: 699: if (suggest_filetype_color) %%%%%: 699-block 0 branch 0 never executed branch 1 never executed #####: 700: color = get_comp_color(bookmarks[i].path, attr); %%%%%: 700-block 0 call 0 never executed unconditional 1 never executed -: 701: #####: 702: char *_tmp = escape_str(bookmarks[i].path); %%%%%: 702-block 0 call 0 never executed #####: 703: print_suggestion(_tmp ? _tmp : bookmarks[i].path, 1, color); branch 0 never executed branch 1 never executed %%%%%: 703-block 0 unconditional 2 never executed %%%%%: 703-block 1 unconditional 3 never executed %%%%%: 703-block 2 call 4 never executed #####: 704: if (_tmp) branch 0 never executed branch 1 never executed #####: 705: free(_tmp); %%%%%: 705-block 0 unconditional 0 never executed -: 706: } 16: 707: return 1; 16: 707-block 0 unconditional 0 taken 16 -: 708: } -: 709: } -: 710: 408: 711: return 0; 408: 711-block 0 unconditional 0 taken 408 -: 712:} -: 713: -: 714:/* -: 715:static int -: 716:check_bookmarks(const char *str, const size_t len) -: 717:{ -: 718: int i = bm_n; -: 719: char *color = (char *)NULL; -: 720: struct stat attr; -: 721: if (!suggest_filetype_color) -: 722: color = sf_c; -: 723: -: 724: while (--i >= 0) { -: 725: if (!bookmarks[i].path || *str != *bookmarks[i].path) -: 726: continue; -: 727: if (len && strncmp(str, bookmarks[i].path, len) == 0 -: 728: && strlen(bookmarks[i].path) > len) { -: 729: if (lstat(bookmarks[i].path, &attr) == -1) -: 730: continue; -: 731: else if ((attr.st_mode & S_IFMT) == S_IFDIR) { -: 732: char tmp[NAME_MAX + 2]; -: 733: snprintf(tmp, NAME_MAX + 2, "%s/", bookmarks[i].path); -: 734: if (suggest_filetype_color) -: 735: color = di_c; -: 736: char *_tmp = escape_str(tmp); -: 737: print_suggestion(_tmp ? _tmp : tmp, len, color); -: 738: if (_tmp) -: 739: free(_tmp); -: 740: suggestion.type = FILE_SUG; -: 741: suggestion.filetype = DT_DIR; -: 742: } else { -: 743: if (suggest_filetype_color) -: 744: color = get_comp_color(bookmarks[i].path, attr); -: 745: char *_tmp = escape_str(bookmarks[i].path); -: 746: print_suggestion(_tmp ? _tmp : bookmarks[i].path, len, -: 747: color); -: 748: if (_tmp) -: 749: free(_tmp); -: 750: print_suggestion(bookmarks[i].path, len, color); -: 751: suggestion.type = FILE_SUG; -: 752: suggestion.filetype = DT_REG; -: 753: } -: 754: return 1; -: 755: } -: 756: } -: 757: -: 758: return 0; -: 759:} */ -: 760: -: 761:static int function check_int_params called 347 returned 100% blocks executed 100% 347: 762:check_int_params(const char *str, const size_t len) -: 763:{ -: 764: size_t i; 40453: 765: for (i = 0; param_str[i]; i++) { 347: 765-block 0 unconditional 0 taken 347 40106: 765-block 1 unconditional 1 taken 40106 40453: 765-block 2 branch 2 taken 40186 branch 3 taken 267 (fallthrough) 40186: 766: if (*str != *param_str[i]) 40186: 766-block 0 branch 0 taken 37047 (fallthrough) branch 1 taken 3139 37047: 767: continue; 37047: 767-block 0 unconditional 0 taken 37047 3139: 768: if (len && strncmp(str, param_str[i], len) == 0 3139: 768-block 0 branch 0 taken 3139 (fallthrough) branch 1 taken 0 3139: 768-block 1 branch 2 taken 90 (fallthrough) branch 3 taken 3049 90: 769: && strlen(param_str[i]) > len) { 90: 769-block 0 branch 0 taken 80 (fallthrough) branch 1 taken 10 80: 770: suggestion.type = INT_CMD; 80: 771: print_suggestion(param_str[i], len, sx_c); 80: 771-block 0 call 0 returned 80 80: 772: return 1; unconditional 0 taken 80 -: 773: } -: 774: } -: 775: 267: 776: return 0; 267: 776-block 0 unconditional 0 taken 267 -: 777:} -: 778: -: 779:static int function check_eln called 80 returned 100% blocks executed 84% 80: 780:check_eln(const char *str) -: 781:{ 80: 782: if (!str || !*str) 80: 782-block 0 branch 0 taken 80 (fallthrough) branch 1 taken 0 80: 782-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 80 #####: 783: return 0; %%%%%: 783-block 0 unconditional 0 never executed -: 784: 80: 785: int n = atoi(str); 80: 786: if (n < 1 || n > (int)files || !file_info[n - 1].name) 80: 786-block 0 branch 0 taken 80 (fallthrough) branch 1 taken 0 80: 786-block 1 branch 2 taken 80 (fallthrough) branch 3 taken 0 80: 786-block 2 branch 4 taken 0 (fallthrough) branch 5 taken 80 #####: 787: return 0; %%%%%: 787-block 0 unconditional 0 never executed -: 788: 80: 789: n--; 80: 790: char *color = sf_c; 80: 791: suggestion.type = ELN_SUG; 80: 792: if (suggest_filetype_color) 80: 792-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 80 #####: 793: color = file_info[n].color; %%%%%: 793-block 0 unconditional 0 never executed -: 794: -: 795: char tmp[NAME_MAX + 1]; 80: 796: *tmp = '\0'; 80: 797: if (file_info[n].dir) { 80: 797-block 0 branch 0 taken 37 (fallthrough) branch 1 taken 43 37: 798: snprintf(tmp, NAME_MAX + 1, "%s/", file_info[n].name); 37: 799: suggestion.filetype = DT_DIR; 37: 799-block 0 unconditional 0 taken 37 -: 800: } else { 43: 801: suggestion.filetype = DT_REG; 43: 801-block 0 unconditional 0 taken 43 -: 802: } -: 803: 80: 804: print_suggestion(!*tmp ? file_info[n].name : tmp, 1, color); 80: 804-block 0 branch 0 taken 43 (fallthrough) branch 1 taken 37 43: 804-block 1 unconditional 2 taken 43 37: 804-block 2 unconditional 3 taken 37 80: 804-block 3 call 4 returned 80 80: 805: return 1; unconditional 0 taken 80 -: 806:} -: 807: -: 808:static int function check_aliases called 408 returned 100% blocks executed 85% 408: 809:check_aliases(const char *str, const size_t len) -: 810:{ 408: 811: if (!aliases_n) 408: 811-block 0 branch 0 taken 3 (fallthrough) branch 1 taken 405 3: 812: return 0; 3: 812-block 0 unconditional 0 taken 3 -: 813: 405: 814: char *color = sc_c; -: 815: 405: 816: int i = (int)aliases_n; 2410: 817: while (--i >= 0) { 405: 817-block 0 unconditional 0 taken 405 2410: 817-block 1 branch 1 taken 2011 branch 2 taken 399 (fallthrough) 2011*: 818: if (!aliases[i]) 2011: 818-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 2011 #####: 819: continue; %%%%%: 819-block 0 unconditional 0 never executed 2011: 820: char *p = aliases[i]; 2011*: 821: if (TOUPPER(*p) != TOUPPER(*str)) 2011: 821-block 0 branch 0 taken 2011 (fallthrough) branch 1 taken 0 2011: 821-block 1 branch 2 taken 2011 (fallthrough) branch 3 taken 0 2011: 821-block 2 unconditional 4 taken 2011 %%%%%: 821-block 3 unconditional 5 never executed 2011: 821-block 4 branch 6 taken 1446 (fallthrough) branch 7 taken 565 1446: 821-block 5 branch 8 taken 1446 (fallthrough) branch 9 taken 0 1446: 821-block 6 unconditional 10 taken 1446 565: 821-block 7 unconditional 11 taken 565 2011: 821-block 8 branch 12 taken 1948 (fallthrough) branch 13 taken 63 1948: 822: continue; 1948: 822-block 0 unconditional 0 taken 1948 63*: 823: if ((case_sens_path_comp ? strncmp(p, str, len) 63: 823-block 0 branch 0 taken 57 (fallthrough) branch 1 taken 6 63*: 824: : strncasecmp(p, str, len)) != 0) 63: 824-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 63 %%%%%: 824-block 1 unconditional 2 never executed 63: 824-block 2 unconditional 3 taken 63 57: 825: continue; 57: 825-block 0 unconditional 0 taken 57 6: 826: char *ret = strchr(p, '='); 6*: 827: if (!*(++ret)) 6: 827-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 6 #####: 828: continue; %%%%%: 828-block 0 unconditional 0 never executed 6*: 829: if (!*(++ret)) 6: 829-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 6 #####: 830: continue; %%%%%: 830-block 0 unconditional 0 never executed 6: 831: size_t str_len = strlen(ret); 6: 832: if (ret[str_len - 1] == '\n') { 6: 832-block 0 branch 0 taken 3 (fallthrough) branch 1 taken 3 3: 833: ret[str_len - 1] = '\0'; 3: 834: str_len--; 3: 834-block 0 unconditional 0 taken 3 -: 835: } 6: 836: if (ret[str_len - 1] == '\'' || ret[str_len - 1] == '"') 6: 836-block 0 branch 0 taken 3 (fallthrough) branch 1 taken 3 3: 836-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 3 3: 837: ret[str_len - 1] = '\0'; 3: 837-block 0 unconditional 0 taken 3 6: 838: suggestion.type = ALIAS_SUG; 6: 839: print_suggestion(ret, 1, color); 6: 839-block 0 call 0 returned 6 6: 840: return 1; unconditional 0 taken 6 -: 841: } -: 842: 399: 843: return 0; 399: 843-block 0 unconditional 0 taken 399 -: 844:} -: 845: -: 846:/* Get a match from the jump database and print the suggestion */ -: 847:static int function check_jcmd called 30 returned 100% blocks executed 67% 30: 848:check_jcmd(char *line) -: 849:{ 30: 850: if (suggestion_buf) 30: 850-block 0 branch 0 taken 14 (fallthrough) branch 1 taken 16 14: 851: clear_suggestion(); 14: 851-block 0 call 0 returned 14 unconditional 1 taken 14 -: 852: -: 853: /* Split line into an array of substrings */ 30: 854: char **substr = get_substr(line, ' '); 30: 854-block 0 call 0 returned 30 30: 855: if (!substr) branch 0 taken 0 (fallthrough) branch 1 taken 30 #####: 856: return 0; %%%%%: 856-block 0 unconditional 0 never executed -: 857: -: 858: /* Check the jump database for a match. If a match is found, it will -: 859: * be stored in jump_suggestion (global) */ 30: 860: dirjump(substr, SUG_JUMP); 30: 860-block 0 call 0 returned 30 -: 861: -: 862: size_t i; 90: 863: for (i = 0; substr[i]; i++) unconditional 0 taken 30 90: 863-block 0 branch 1 taken 60 branch 2 taken 30 (fallthrough) 60: 864: free(substr[i]); 60: 864-block 0 unconditional 0 taken 60 30: 865: free(substr); -: 866: 30: 867: if (!jump_suggestion) 30: 867-block 0 branch 0 taken 14 (fallthrough) branch 1 taken 16 14: 868: return 0; 14: 868-block 0 unconditional 0 taken 14 -: 869: 16: 870: suggestion.type = JCMD_SUG; 16: 871: suggestion.filetype = DT_DIR; 16: 872: if (!autocd) { 16: 872-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 16 #####: 873: char *tmp = xnmalloc(strlen(jump_suggestion) + 4, sizeof(char)); %%%%%: 873-block 0 call 0 never executed #####: 874: sprintf(tmp, "cd %s", jump_suggestion); #####: 875: print_suggestion(tmp, 1, suggest_filetype_color ? di_c : sf_c); branch 0 never executed branch 1 never executed %%%%%: 875-block 0 unconditional 2 never executed %%%%%: 875-block 1 unconditional 3 never executed %%%%%: 875-block 2 call 4 never executed #####: 876: suggestion.type = JCMD_SUG_NOACD; #####: 877: free(tmp); unconditional 0 never executed -: 878: } else { 16*: 879: print_suggestion(jump_suggestion, 1, suggest_filetype_color ? di_c 16: 879-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 16 %%%%%: 879-block 1 unconditional 2 never executed 16: 879-block 2 unconditional 3 taken 16 16: 879-block 3 call 4 returned 16 unconditional 5 taken 16 -: 880: : sf_c); -: 881: } 16: 882: suggestion.offset = 0; 16: 883: free(jump_suggestion); 16: 884: jump_suggestion = (char *)NULL; 16: 885: return 1; 16: 885-block 0 unconditional 0 taken 16 -: 886:} -: 887: -: 888:/* Check if we must suggest --help for internal commands */ -: 889:static int function check_help called 31 returned 100% blocks executed 90% 31: 890:check_help(char *full_line, const char *last_word) -: 891:{ 31: 892: size_t len = strlen(last_word); 31: 893: if (strncmp(last_word, "--help", len) != 0) 31: 893-block 0 branch 0 taken 3 (fallthrough) branch 1 taken 28 3: 894: return 0; 3: 894-block 0 unconditional 0 taken 3 -: 895: 28: 896: char *ret = strchr(full_line, ' '); 28: 897: if (!ret) 28: 897-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 27 1: 898: return 0; 1: 898-block 0 unconditional 0 taken 1 -: 899: 27: 900: *ret = '\0'; 27: 901: if (!is_internal_c(full_line)) 27: 901-block 0 call 0 returned 27 branch 1 taken 0 (fallthrough) branch 2 taken 27 #####: 902: return 0; %%%%%: 902-block 0 unconditional 0 never executed -: 903: 27: 904: suggestion.type = CMD_SUG; 27: 905: print_suggestion("--help", len, sx_c); 27: 905-block 0 call 0 returned 27 27: 906: return 1; unconditional 0 taken 27 -: 907:} -: 908: -: 909:static int function check_variables called 0 returned 0% blocks executed 0% #####: 910:check_variables(const char *str, const size_t len) -: 911:{ #####: 912: int printed = 0; -: 913: size_t i; #####: 914: for (i = 0; environ[i]; i++) { %%%%%: 914-block 0 unconditional 0 never executed %%%%%: 914-block 1 unconditional 1 never executed %%%%%: 914-block 2 branch 2 never executed branch 3 never executed #####: 915: if (TOUPPER(*environ[i]) == TOUPPER(*str) %%%%%: 915-block 0 branch 0 never executed branch 1 never executed %%%%%: 915-block 1 branch 2 never executed branch 3 never executed %%%%%: 915-block 2 unconditional 4 never executed %%%%%: 915-block 3 unconditional 5 never executed %%%%%: 915-block 4 branch 6 never executed branch 7 never executed %%%%%: 915-block 5 branch 8 never executed branch 9 never executed %%%%%: 915-block 6 unconditional 10 never executed %%%%%: 915-block 7 unconditional 11 never executed %%%%%: 915-block 8 branch 12 never executed branch 13 never executed #####: 916: && strncasecmp(str, environ[i], len) == 0) { %%%%%: 916-block 0 branch 0 never executed branch 1 never executed #####: 917: char *ret = strchr(environ[i], '='); #####: 918: *ret = '\0'; #####: 919: suggestion.type = VAR_SUG; -: 920: char t[NAME_MAX + 1]; #####: 921: snprintf(t, NAME_MAX + 1, "$%s", environ[i]); #####: 922: print_suggestion(t, len + 1, sh_c); %%%%%: 922-block 0 call 0 never executed #####: 923: printed = 1; #####: 924: *ret = '='; #####: 925: break; unconditional 0 never executed -: 926: } -: 927: } -: 928: #####: 929: if (printed) %%%%%: 929-block 0 branch 0 never executed branch 1 never executed #####: 930: return 1; %%%%%: 930-block 0 unconditional 0 never executed -: 931: #####: 932: if (!usrvar_n) %%%%%: 932-block 0 branch 0 never executed branch 1 never executed #####: 933: return 0; %%%%%: 933-block 0 unconditional 0 never executed -: 934: #####: 935: for (i = 0; usr_var[i].name; i++) { %%%%%: 935-block 0 unconditional 0 never executed %%%%%: 935-block 1 unconditional 1 never executed %%%%%: 935-block 2 branch 2 never executed branch 3 never executed #####: 936: if (TOUPPER(*str) == TOUPPER(*usr_var[i].name) %%%%%: 936-block 0 branch 0 never executed branch 1 never executed %%%%%: 936-block 1 branch 2 never executed branch 3 never executed %%%%%: 936-block 2 unconditional 4 never executed %%%%%: 936-block 3 unconditional 5 never executed %%%%%: 936-block 4 branch 6 never executed branch 7 never executed %%%%%: 936-block 5 branch 8 never executed branch 9 never executed %%%%%: 936-block 6 unconditional 10 never executed %%%%%: 936-block 7 unconditional 11 never executed %%%%%: 936-block 8 branch 12 never executed branch 13 never executed #####: 937: && strncasecmp(str, usr_var[i].name, len) == 0) { %%%%%: 937-block 0 branch 0 never executed branch 1 never executed #####: 938: suggestion.type = CMD_SUG; -: 939: char t[NAME_MAX + 1]; #####: 940: snprintf(t, NAME_MAX + 1, "$%s", usr_var[i].name); #####: 941: print_suggestion(t, len + 1, sh_c); %%%%%: 941-block 0 call 0 never executed #####: 942: printed = 1; #####: 943: break; unconditional 0 never executed -: 944: } -: 945: } -: 946: #####: 947: if (printed) %%%%%: 947-block 0 branch 0 never executed branch 1 never executed #####: 948: return 1; %%%%%: 948-block 0 unconditional 0 never executed -: 949: #####: 950: return 0; %%%%%: 950-block 0 unconditional 0 never executed -: 951:} -: 952: -: 953:static void function remove_suggestion_not_end called 1 returned 100% blocks executed 100% 1: 954:remove_suggestion_not_end(void) -: 955:{ 1: 956: printf("\x1b[%dC", rl_end - rl_point); 1: 956-block 0 call 0 returned 1 1: 957: fflush(stdout); call 0 returned 1 1: 958: clear_suggestion(); call 0 returned 1 1: 959: printf("\x1b[%dD", rl_end - rl_point); call 0 returned 1 1: 960: fflush(stdout); call 0 returned 1 1: 961:} -: 962: -: 963:/* Check for available suggestions. Returns zero if true, one if not, -: 964: * and -1 if C was inserted before the end of the current line. -: 965: * If a suggestion is found, it will be printed by print_suggestion() */ -: 966:int function rl_suggestions called 2893 returned 100% blocks executed 94% 2893: 967:rl_suggestions(const unsigned char c) -: 968:{ 2893: 969: char *last_word = (char *)NULL; 2893: 970: char *full_line = (char *)NULL; 2893: 971: int printed = 0; 2893: 972: int inserted_c = 0; -: 973:/* static int msg_area = 0; */ -: 974: -: 975: /* ###################################### -: 976: * # 1) Filter input # -: 977: * ######################################*/ -: 978: -: 979: /* Skip escape sequences, mostly arrow keys */ 2893: 980: if (rl_readline_state & RL_STATE_MOREINPUT) { 2893: 980-block 0 branch 0 taken 513 (fallthrough) branch 1 taken 2380 513: 981: if (c == '~') { 513: 981-block 0 branch 0 taken 14 (fallthrough) branch 1 taken 499 14: 982: if (rl_point != rl_end && suggestion.printed) { 14: 982-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 13 1: 982-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 1 -: 983: /* This should be the delete key */ #####: 984: remove_suggestion_not_end(); %%%%%: 984-block 0 call 0 never executed #####: 985: goto FAIL; unconditional 0 never executed 14: 986: } else if (suggestion.printed) { 14: 986-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 14 #####: 987: clear_suggestion(); %%%%%: 987-block 0 call 0 never executed #####: 988: free(suggestion_buf); #####: 989: suggestion_buf = (char *)NULL; unconditional 0 never executed -: 990: } -: 991: } -: 992: /* Handle history events. If a suggestion has been printed and -: 993: * a history event is triggered (usually via the Up and Down arrow -: 994: * keys), the suggestion buffer won't be freed. Let's do it -: 995: * here */ 499: 996: else if ((c == 'A' || c == 'B') && suggestion_buf) { 499: 996-block 0 branch 0 taken 472 (fallthrough) branch 1 taken 27 472: 996-block 1 branch 2 taken 11 (fallthrough) branch 3 taken 461 38: 996-block 2 branch 4 taken 1 (fallthrough) branch 5 taken 37 1: 997: clear_suggestion(); 1: 997-block 0 call 0 returned 1 1: 998: goto FAIL; unconditional 0 taken 1 -: 999: } 512: 1000: if (suggestion_buf) { 512: 1000-block 0 branch 0 taken 74 (fallthrough) branch 1 taken 438 74: 1001: printed = 1; 74: 1002: goto SUCCESS; 74: 1002-block 0 unconditional 0 taken 74 -: 1003: } 438: 1004: goto FAIL; 438: 1004-block 0 unconditional 0 taken 438 -: 1005: } -: 1006: -: 1007: /* Skip control characters (0 - 31) except backspace (8), tab(9), -: 1008: * enter (13), and escape (27) */ 2380: 1009: if (c < 32 && c != BS && c != _TAB && c != ENTER && c != _ESC) { 2380: 1009-block 0 branch 0 taken 868 (fallthrough) branch 1 taken 1512 868: 1009-block 1 branch 2 taken 677 (fallthrough) branch 3 taken 191 677: 1009-block 2 branch 4 taken 659 (fallthrough) branch 5 taken 18 659: 1009-block 3 branch 6 taken 254 (fallthrough) branch 7 taken 405 254: 1009-block 4 branch 8 taken 3 (fallthrough) branch 9 taken 251 3: 1010: if (suggestion_buf) { 3: 1010-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 3 #####: 1011: printed = 1; #####: 1012: goto SUCCESS; %%%%%: 1012-block 0 unconditional 0 never executed -: 1013: } else { 3: 1014: goto FAIL; 3: 1014-block 0 unconditional 0 taken 3 -: 1015: } -: 1016: } -: 1017: -: 1018: /* Skip backspace, Enter, and TAB keys */ 2377: 1019: switch(c) { 2377: 1019-block 0 branch 0 taken 191 branch 1 taken 405 branch 2 taken 251 branch 3 taken 18 branch 4 taken 1512 191: 1020: case DELETE: /* fallthrough */ -: 1021:/* if (rl_point != rl_end && suggestion.printed) -: 1022: clear_suggestion(); -: 1023: goto FAIL; */ -: 1024: -: 1025: case BS: 191: 1026: if (suggestion.printed && suggestion_buf) { 191: 1026-block 0 branch 0 taken 21 (fallthrough) branch 1 taken 170 21: 1026-block 1 branch 2 taken 21 (fallthrough) branch 3 taken 0 21: 1027: if (rl_point != rl_end) { 21: 1027-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 20 1: 1028: remove_suggestion_not_end(); 1: 1028-block 0 call 0 returned 1 unconditional 1 taken 1 -: 1029: } else { 20: 1030: clear_suggestion(); 20: 1030-block 0 call 0 returned 20 unconditional 1 taken 20 -: 1031: } -: 1032: } 191: 1033: goto FAIL; 191: 1033-block 0 unconditional 0 taken 191 -: 1034: 405: 1035: case ENTER: 405: 1036: if (suggestion.printed && suggestion_buf) 405: 1036-block 0 branch 0 taken 279 (fallthrough) branch 1 taken 126 279: 1036-block 1 branch 2 taken 279 (fallthrough) branch 3 taken 0 279: 1037: clear_suggestion(); 279: 1037-block 0 call 0 returned 279 unconditional 1 taken 279 405: 1038: goto FAIL; 405: 1038-block 0 unconditional 0 taken 405 -: 1039:/* case SPACE: -: 1040: if (msg_area) { -: 1041: rl_restore_prompt(); -: 1042: rl_clear_message(); -: 1043: msg_area = 0; -: 1044: if (c == ENTER) -: 1045: goto FAIL; -: 1046: break; -: 1047: } else { -: 1048: if (c == ENTER) -: 1049: goto FAIL; -: 1050: break; -: 1051: } */ -: 1052: 251: 1053: case _ESC: 251: 1054: if (suggestion.printed) 251: 1054-block 0 branch 0 taken 39 (fallthrough) branch 1 taken 212 39: 1055: printed = 1; 39: 1055-block 0 unconditional 0 taken 39 251: 1056: goto SUCCESS; 251: 1056-block 0 unconditional 0 taken 251 -: 1057: 18: 1058: case _TAB: 18: 1059: if (suggestion.printed) { 18: 1059-block 0 branch 0 taken 8 (fallthrough) branch 1 taken 10 8: 1060: if (suggestion.nlines < 2 && suggestion.type != ELN_SUG 8: 1060-block 0 branch 0 taken 8 (fallthrough) branch 1 taken 0 8: 1060-block 1 branch 2 taken 8 (fallthrough) branch 3 taken 0 8: 1061: && suggestion.type != BOOKMARK_SUG 8: 1061-block 0 branch 0 taken 8 (fallthrough) branch 1 taken 0 8: 1062: && suggestion.type != ALIAS_SUG 8: 1062-block 0 branch 0 taken 8 (fallthrough) branch 1 taken 0 8: 1063: && suggestion.type != JCMD_SUG) { 8: 1063-block 0 branch 0 taken 7 (fallthrough) branch 1 taken 1 7: 1064: printed = 1; 7: 1064-block 0 unconditional 0 taken 7 -: 1065: } else { 1: 1066: clear_suggestion(); 1: 1066-block 0 call 0 returned 1 1: 1067: goto FAIL; unconditional 0 taken 1 -: 1068: } -: 1069: } 17: 1070: goto SUCCESS; 17: 1070-block 0 unconditional 0 taken 17 -: 1071: 1512: 1072: default: break; 1512: 1072-block 0 unconditional 0 taken 1512 -: 1073: } -: 1074: -: 1075: /* ###################################### -: 1076: * # 2) Handle last entered char # -: 1077: * ######################################*/ -: 1078: -: 1079: /* If not at the end of line, insert C in the current cursor -: 1080: * position. Else, append it to current readline buffer to -: 1081: * correctly find matches: at this point (rl_getc), readline has -: 1082: * not appended this char to rl_line_buffer yet, so that we must -: 1083: * do it manually. -: 1084: * Line editing is only allowed for the last word */ 1512: 1085: int s = strcntchrlst(rl_line_buffer, ' '); 1512: 1085-block 0 call 0 returned 1512 -: 1086: /* Do not take into account final spaces */ 1512: 1087: if (s >= 0 && !rl_line_buffer[s + 1]) branch 0 taken 487 (fallthrough) branch 1 taken 1025 487: 1087-block 0 branch 2 taken 164 (fallthrough) branch 3 taken 323 164: 1088: s = -1; 164: 1088-block 0 unconditional 0 taken 164 1512: 1089: if (rl_point != rl_end && c != _ESC) { 1512: 1089-block 0 branch 0 taken 20 (fallthrough) branch 1 taken 1492 20: 1089-block 1 branch 2 taken 20 (fallthrough) branch 3 taken 0 20: 1090: if (rl_point < s) { 20: 1090-block 0 branch 0 taken 6 (fallthrough) branch 1 taken 14 6: 1091: if (suggestion.printed) { 6: 1091-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 6 #####: 1092: remove_suggestion_not_end(); %%%%%: 1092-block 0 call 0 never executed #####: 1093: goto FAIL; unconditional 0 never executed -: 1094: } -: 1095: } -: 1096: char text[2]; 20: 1097: text[0] = (char)c; 20: 1098: text[1] = '\0'; 20: 1099: rl_insert_text(text); 20: 1099-block 0 call 0 returned 20 -: 1100: /* This flag is used to tell my_rl_getc not to append C to the -: 1101: * line buffer (rl_line_buffer), since it was already inserted -: 1102: * here */ 20: 1103: inserted_c = 1; unconditional 0 taken 20 -: 1104: } -: 1105: 1512: 1106: size_t buflen = (size_t)rl_end; -: 1107:/* size_t buflen = strlen(rl_line_buffer); */ 1512: 1108: suggestion.full_line_len = buflen + 1; 1512: 1109: char *last_space = strrchr(rl_line_buffer, ' '); 1512: 1110: if (last_space && last_space != rl_line_buffer 1512: 1110-block 0 branch 0 taken 487 (fallthrough) branch 1 taken 1025 487: 1110-block 1 branch 2 taken 487 (fallthrough) branch 3 taken 0 487: 1111: && *(last_space - 1) == '\\') 487: 1111-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 487 #####: 1112: last_space = (char *)NULL; %%%%%: 1112-block 0 unconditional 0 never executed -: 1113: -: 1114: /* We need a copy of the complete line */ 1512: 1115: full_line = (char *)xnmalloc(buflen + 2, sizeof(char)); 1512: 1115-block 0 call 0 returned 1512 1512: 1116: if (inserted_c) branch 0 taken 20 (fallthrough) branch 1 taken 1492 20: 1117: strcpy(full_line, rl_line_buffer); 20: 1117-block 0 unconditional 0 taken 20 -: 1118: else 1492: 1119: sprintf(full_line, "%s%c", rl_line_buffer, c); 1492: 1119-block 0 unconditional 0 taken 1492 -: 1120: -: 1121: /* And a copy of the last entered word as well */ 1512: 1122: int last_word_offset = 0; -: 1123: 1512: 1124: if (last_space) { 1512: 1124-block 0 branch 0 taken 487 (fallthrough) branch 1 taken 1025 487: 1125: int j = (int)buflen; 1252: 1126: while (--j >= 0) { 487: 1126-block 0 unconditional 0 taken 487 1252: 1126-block 1 branch 1 taken 1252 branch 2 taken 0 (fallthrough) 1252: 1127: if (rl_line_buffer[j] == ' ') 1252: 1127-block 0 branch 0 taken 487 (fallthrough) branch 1 taken 765 487: 1128: break; 487: 1128-block 0 unconditional 0 taken 487 -: 1129: } 487: 1130: last_word_offset = j + 1; 487: 1131: buflen = strlen(last_space); -: 1132: 487: 1133: if (*(++last_space)) { 487: 1133-block 0 branch 0 taken 323 (fallthrough) branch 1 taken 164 323: 1134: buflen--; 323: 1135: last_word = (char *)xnmalloc(buflen + 2, sizeof(char)); 323: 1135-block 0 call 0 returned 323 323: 1136: if (inserted_c) branch 0 taken 19 (fallthrough) branch 1 taken 304 19: 1137: strcpy(last_word, last_space); 19: 1137-block 0 unconditional 0 taken 19 -: 1138: else 304: 1139: sprintf(last_word, "%s%c", last_space, c); 304: 1139-block 0 unconditional 0 taken 304 -: 1140: } else { 164: 1141: last_word = (char *)xnmalloc(2, sizeof(char)); 164: 1141-block 0 call 0 returned 164 164: 1142: if (inserted_c) { branch 0 taken 1 (fallthrough) branch 1 taken 163 1: 1143: *last_word = '\0'; 1: 1143-block 0 unconditional 0 taken 1 -: 1144: } else { 163: 1145: *last_word = (char)c; 163: 1146: last_word[1] = '\0'; 163: 1146-block 0 unconditional 0 taken 163 -: 1147: } -: 1148: } -: 1149: } else { 1025: 1150: last_word = (char *)xnmalloc(buflen + 2, sizeof(char)); 1025: 1150-block 0 call 0 returned 1025 1025: 1151: if (inserted_c) branch 0 taken 0 (fallthrough) branch 1 taken 1025 #####: 1152: strcpy(last_word, rl_line_buffer); %%%%%: 1152-block 0 unconditional 0 never executed -: 1153: else 1025: 1154: sprintf(last_word, "%s%c", rl_line_buffer, c); 1025: 1154-block 0 unconditional 0 taken 1025 -: 1155: } -: 1156: -: 1157: /* ###################################### -: 1158: * # 3) Search for suggestions # -: 1159: * ######################################*/ -: 1160: 1512: 1161: char *lb = rl_line_buffer; -: 1162: /* 3.a) Let's suggest non-fixed parameters for internal commands */ -: 1163: 1512: 1164: switch(*lb) { 1512: 1164-block 0 branch 0 taken 68 branch 1 taken 59 branch 2 taken 49 branch 3 taken 43 branch 4 taken 104 branch 5 taken 1189 68: 1165: case 'b': /* Bookmarks names */ 68: 1166: if (lb[1] == 'm' && lb[2] == ' ' && strncmp(lb + 3, "add", 3) != 0) { 68: 1166-block 0 branch 0 taken 44 (fallthrough) branch 1 taken 24 44: 1166-block 1 branch 2 taken 37 (fallthrough) branch 3 taken 7 37: 1166-block 2 branch 4 taken 34 (fallthrough) branch 5 taken 3 34: 1167: size_t i = 0, len = strlen(last_word); 642: 1168: for (; bookmark_names[i]; i++) { 34: 1168-block 0 unconditional 0 taken 34 608: 1168-block 1 unconditional 1 taken 608 642: 1168-block 2 branch 2 taken 616 branch 3 taken 26 (fallthrough) 616: 1169: if (*last_word == *bookmark_names[i] 616: 1169-block 0 branch 0 taken 14 (fallthrough) branch 1 taken 602 14: 1170: && strncmp(bookmark_names[i], last_word, len) == 0) { 14: 1170-block 0 branch 0 taken 8 (fallthrough) branch 1 taken 6 8: 1171: suggestion.type = CMD_SUG; 8: 1172: suggestion.offset = last_word_offset; 8: 1173: print_suggestion(bookmark_names[i], len, sx_c); 8: 1173-block 0 call 0 returned 8 8: 1174: printed = 1; 8: 1175: break; unconditional 0 taken 8 -: 1176: } -: 1177: } 34: 1178: if (printed) { 34: 1178-block 0 branch 0 taken 8 (fallthrough) branch 1 taken 26 8: 1179: goto SUCCESS; 8: 1179-block 0 unconditional 0 taken 8 -: 1180: } -: 1181: } 60: 1182: break; 60: 1182-block 0 unconditional 0 taken 60 -: 1183: 59: 1184: case 'c': /* Color schemes */ 59: 1185: if (lb[1] == 's' && lb[2] == ' ') { 59: 1185-block 0 branch 0 taken 15 (fallthrough) branch 1 taken 44 15: 1185-block 1 branch 2 taken 11 (fallthrough) branch 3 taken 4 11: 1186: size_t i = 0, len = strlen(last_word); 174: 1187: for (; color_schemes[i]; i++) { 11: 1187-block 0 unconditional 0 taken 11 163: 1187-block 1 unconditional 1 taken 163 174: 1187-block 2 branch 2 taken 166 branch 3 taken 8 (fallthrough) 166: 1188: if (*last_word == *color_schemes[i] 166: 1188-block 0 branch 0 taken 3 (fallthrough) branch 1 taken 163 3: 1189: && strncmp(color_schemes[i], last_word, len) == 0) { 3: 1189-block 0 branch 0 taken 3 (fallthrough) branch 1 taken 0 3: 1190: suggestion.type = CMD_SUG; 3: 1191: suggestion.offset = last_word_offset; 3: 1192: print_suggestion(color_schemes[i], len, sx_c); 3: 1192-block 0 call 0 returned 3 3: 1193: printed = 1; 3: 1194: break; unconditional 0 taken 3 -: 1195: } -: 1196: } 11: 1197: if (printed) { 11: 1197-block 0 branch 0 taken 3 (fallthrough) branch 1 taken 8 3: 1198: goto SUCCESS; 3: 1198-block 0 unconditional 0 taken 3 -: 1199: } -: 1200: } 56: 1201: break; 56: 1201-block 0 unconditional 0 taken 56 -: 1202: 49: 1203: case 'j': /* j command */ 49: 1204: if (lb[1] == ' ' || ((lb[1] == 'c' || lb[1] == 'o' 49: 1204-block 0 branch 0 taken 26 (fallthrough) branch 1 taken 23 26: 1204-block 1 branch 2 taken 18 (fallthrough) branch 3 taken 8 18: 1204-block 2 branch 4 taken 18 (fallthrough) branch 5 taken 0 26: 1205: || lb[1] == 'p') && lb[2] == ' ')) { 18: 1205-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 16 10: 1205-block 1 branch 2 taken 7 (fallthrough) branch 3 taken 3 30: 1206: printed = check_jcmd(full_line); 30: 1206-block 0 call 0 returned 30 30: 1207: if (printed) { branch 0 taken 16 (fallthrough) branch 1 taken 14 16: 1208: goto SUCCESS; 16: 1208-block 0 unconditional 0 taken 16 -: 1209: } else { 14: 1210: free(full_line); 14: 1211: full_line = (char *)NULL; 14: 1212: goto FAIL; 14: 1212-block 0 unconditional 0 taken 14 -: 1213: } -: 1214: } 19: 1215: break; 19: 1215-block 0 unconditional 0 taken 19 -: 1216: 43: 1217: case 'n': /* Remotes */ 43: 1218: if (lb[1] == 'e' && lb[2] == 't' && lb[3] == ' ') { 43: 1218-block 0 branch 0 taken 18 (fallthrough) branch 1 taken 25 18: 1218-block 1 branch 2 taken 12 (fallthrough) branch 3 taken 6 12: 1218-block 2 branch 4 taken 8 (fallthrough) branch 5 taken 4 8: 1219: size_t i = 0, len = strlen(last_word); 19: 1220: for (; remotes[i].name; i++) { 8: 1220-block 0 unconditional 0 taken 8 11: 1220-block 1 unconditional 1 taken 11 19: 1220-block 2 branch 2 taken 16 branch 3 taken 3 (fallthrough) 16: 1221: if (*last_word == *remotes[i].name 16: 1221-block 0 branch 0 taken 6 (fallthrough) branch 1 taken 10 6: 1222: && strncmp(remotes[i].name, last_word, len) == 0) { 6: 1222-block 0 branch 0 taken 5 (fallthrough) branch 1 taken 1 5: 1223: suggestion.type = CMD_SUG; 5: 1224: suggestion.offset = last_word_offset; 5: 1225: print_suggestion(remotes[i].name, len, sx_c); 5: 1225-block 0 call 0 returned 5 5: 1226: printed = 1; 5: 1227: break; unconditional 0 taken 5 -: 1228: } -: 1229: } 8: 1230: if (printed) 8: 1230-block 0 branch 0 taken 5 (fallthrough) branch 1 taken 3 5: 1231: goto SUCCESS; 5: 1231-block 0 unconditional 0 taken 5 -: 1232: } 38: 1233: break; 38: 1233-block 0 unconditional 0 taken 38 -: 1234: 104: 1235: case 'p': /* Profiles */ 104: 1236: if (lb[1] == 'f' && lb[2] == ' ' && (strncmp(lb + 3, "set", 3) == 0 104: 1236-block 0 branch 0 taken 46 (fallthrough) branch 1 taken 58 46: 1236-block 1 branch 2 taken 42 (fallthrough) branch 3 taken 4 42: 1236-block 2 branch 4 taken 34 (fallthrough) branch 5 taken 8 34: 1237: || strncmp(lb + 3, "del", 3) == 0)) { 34: 1237-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 32 10: 1238: size_t i = 0, len = strlen(last_word); 37: 1239: for (; profile_names[i]; i++) { 10: 1239-block 0 unconditional 0 taken 10 27: 1239-block 1 unconditional 1 taken 27 37: 1239-block 2 branch 2 taken 33 branch 3 taken 4 (fallthrough) 33: 1240: if (*last_word == *profile_names[i] 33: 1240-block 0 branch 0 taken 7 (fallthrough) branch 1 taken 26 7: 1241: && strncmp(profile_names[i], last_word, len) == 0) { 7: 1241-block 0 branch 0 taken 6 (fallthrough) branch 1 taken 1 6: 1242: suggestion.type = CMD_SUG; 6: 1243: suggestion.offset = last_word_offset; 6: 1244: print_suggestion(profile_names[i], len, sx_c); 6: 1244-block 0 call 0 returned 6 6: 1245: printed = 1; 6: 1246: break; unconditional 0 taken 6 -: 1247: } -: 1248: } 10: 1249: if (printed) { 10: 1249-block 0 branch 0 taken 6 (fallthrough) branch 1 taken 4 6: 1250: goto SUCCESS; 6: 1250-block 0 unconditional 0 taken 6 -: 1251: } else { 4: 1252: free(full_line); 4: 1253: full_line = (char *)NULL; 4: 1254: goto FAIL; 4: 1254-block 0 unconditional 0 taken 4 -: 1255: } -: 1256: } 94: 1257: break; 94: 1257-block 0 unconditional 0 taken 94 -: 1258: 1189: 1259: default: break; 1189: 1259-block 0 unconditional 0 taken 1189 -: 1260: } -: 1261: -: 1262: /* 3.b) Check already suggested string */ 1456: 1263: if (suggestion_buf && suggestion.printed && !_ISDIGIT(c) 1456: 1263-block 0 branch 0 taken 893 (fallthrough) branch 1 taken 563 893: 1263-block 1 branch 2 taken 893 (fallthrough) branch 3 taken 0 893: 1263-block 2 branch 4 taken 847 (fallthrough) branch 5 taken 46 847: 1264: && strncmp(full_line, suggestion_buf, strlen(full_line)) == 0) { 847: 1264-block 0 branch 0 taken 401 (fallthrough) branch 1 taken 446 401: 1265: printed = 1; 401: 1266: suggestion.offset = 0; 401: 1267: goto SUCCESS; 401: 1267-block 0 unconditional 0 taken 401 -: 1268: } -: 1269: -: 1270: /* 3.c) Check CliFM internal parameters */ 1055: 1271: char *ret = strchr(full_line, ' '); 1055: 1272: if (ret) { 1055: 1272-block 0 branch 0 taken 364 (fallthrough) branch 1 taken 691 364: 1273: size_t len = strlen(last_word); -: 1274: /* 3.c.1) Suggest the sel keyword only if not first word */ 364: 1275: if (*last_word == 's' && strncmp(last_word, "sel", len) == 0) { 364: 1275-block 0 branch 0 taken 41 (fallthrough) branch 1 taken 323 41: 1275-block 1 branch 2 taken 17 (fallthrough) branch 3 taken 24 17: 1276: suggestion.type = CMD_SUG; 17: 1277: suggestion.offset = last_word_offset; 17: 1278: printed = 1; 17: 1279: print_suggestion("sel", len, sx_c); 17: 1279-block 0 call 0 returned 17 17: 1280: goto SUCCESS; unconditional 0 taken 17 -: 1281: } -: 1282: -: 1283: /* 3.c.2) Check commands fixed parameters */ 347: 1284: printed = check_int_params(full_line, strlen(full_line)); 347: 1284-block 0 call 0 returned 347 347: 1285: if (printed) { branch 0 taken 80 (fallthrough) branch 1 taken 267 80: 1286: suggestion.offset = 0; 80: 1287: goto SUCCESS; 80: 1287-block 0 unconditional 0 taken 80 -: 1288: } -: 1289: } -: 1290: -: 1291: /* 3.c.3) Let's suggest --help for internal commands */ 958: 1292: if (*last_word == '-') { 958: 1292-block 0 branch 0 taken 31 (fallthrough) branch 1 taken 927 31: 1293: printed = check_help(full_line, last_word); 31: 1293-block 0 call 0 returned 31 31: 1294: if (printed) { branch 0 taken 27 (fallthrough) branch 1 taken 4 27: 1295: suggestion.offset = last_word_offset; 27: 1296: goto SUCCESS; 27: 1296-block 0 unconditional 0 taken 27 -: 1297: } -: 1298: } -: 1299: -: 1300: /* 3.d) Execute the following check in the order specified by -: 1301: * suggestion_strategy (the value is taken form the configuration -: 1302: * file) */ 931: 1303: size_t st = 0; 4282: 1304: for (; st < SUG_STRATS; st++) { 931: 1304-block 0 unconditional 0 taken 931 3351: 1304-block 1 unconditional 1 taken 3351 4282: 1304-block 2 branch 2 taken 3892 branch 3 taken 390 (fallthrough) 3892: 1305: switch(suggestion_strategy[st]) { 3892: 1305-block 0 branch 0 taken 408 branch 1 taken 424 branch 2 taken 402 branch 3 taken 931 branch 4 taken 446 branch 5 taken 851 branch 6 taken 430 branch 7 taken 0 branch 8 taken 0 -: 1306: 408: 1307: case 'a': /* 3.d.1) Aliases */ 408: 1308: printed = check_aliases(last_word, strlen(last_word)); 408: 1308-block 0 call 0 returned 408 408: 1309: if (printed) { branch 0 taken 6 (fallthrough) branch 1 taken 402 6: 1310: suggestion.offset = last_word_offset; 6: 1311: goto SUCCESS; 6: 1311-block 0 unconditional 0 taken 6 -: 1312: } 402: 1313: break; 402: 1313-block 0 unconditional 0 taken 402 -: 1314: 424: 1315: case 'b': /* 3.d.2) Bookmarks */ 424: 1316: if (last_space || autocd || auto_open) { 424: 1316-block 0 branch 0 taken 291 (fallthrough) branch 1 taken 133 291: 1316-block 1 branch 2 taken 2 (fallthrough) branch 3 taken 289 2: 1316-block 2 branch 4 taken 2 (fallthrough) branch 5 taken 0 424: 1317: printed = check_bookmarks(last_word, strlen(last_word)); 424: 1317-block 0 call 0 returned 424 424: 1318: if (printed) { branch 0 taken 16 (fallthrough) branch 1 taken 408 16: 1319: suggestion.offset = last_word_offset; 16: 1320: goto SUCCESS; 16: 1320-block 0 unconditional 0 taken 16 -: 1321: } -: 1322: } 408: 1323: break; 408: 1323-block 0 unconditional 0 taken 408 -: 1324: 402: 1325: case 'c': /* 3.d.3) Possible completions */ 402: 1326: if (last_space || autocd || auto_open) { 402: 1326-block 0 branch 0 taken 285 (fallthrough) branch 1 taken 117 285: 1326-block 1 branch 2 taken 2 (fallthrough) branch 3 taken 283 2: 1326-block 2 branch 4 taken 2 (fallthrough) branch 5 taken 0 402: 1327: printed = check_completions(last_word, strlen(last_word), c); 402: 1327-block 0 call 0 returned 402 402: 1328: if (printed) { branch 0 taken 12 (fallthrough) branch 1 taken 390 12: 1329: suggestion.offset = last_word_offset; 12: 1330: goto SUCCESS; 12: 1330-block 0 unconditional 0 taken 12 -: 1331: } -: 1332: } 390: 1333: break; 390: 1333-block 0 unconditional 0 taken 390 -: 1334: 931: 1335: case 'e': /* 3.d.4) ELN's */ 931: 1336: if (*last_word >= '1' && *last_word <= '9' && is_number(last_word)) { 931: 1336-block 0 branch 0 taken 852 (fallthrough) branch 1 taken 79 852: 1336-block 1 branch 2 taken 95 (fallthrough) branch 3 taken 757 95: 1336-block 2 call 4 returned 95 branch 5 taken 80 (fallthrough) branch 6 taken 15 80: 1337: printed = check_eln(last_word); 80: 1337-block 0 call 0 returned 80 80: 1338: if (printed) { branch 0 taken 80 (fallthrough) branch 1 taken 0 80: 1339: suggestion.offset = last_word_offset; 80: 1340: goto SUCCESS; 80: 1340-block 0 unconditional 0 taken 80 -: 1341: } -: 1342: } 851: 1343: break; 851: 1343-block 0 unconditional 0 taken 851 -: 1344: 446: 1345: case 'f': /* 3.d.5) File names in CWD */ -: 1346: /* Do not check dirs and filenames if first word and -: 1347: * neither autocd nor auto-open are enabled */ 446: 1348: if (last_space || autocd || auto_open) { 446: 1348-block 0 branch 0 taken 300 (fallthrough) branch 1 taken 146 300: 1348-block 1 branch 2 taken 2 (fallthrough) branch 3 taken 298 2: 1348-block 2 branch 4 taken 2 (fallthrough) branch 5 taken 0 446: 1349: printed = check_filenames(last_word, strlen(last_word), 446: 1349-block 0 call 0 returned 446 -: 1350: c, last_space ? 0 : 1); 446: 1351: if (printed) { branch 0 taken 16 (fallthrough) branch 1 taken 430 16: 1352: suggestion.offset = last_word_offset; 16: 1353: goto SUCCESS; 16: 1353-block 0 unconditional 0 taken 16 -: 1354: } -: 1355: } 430: 1356: break; 430: 1356-block 0 unconditional 0 taken 430 -: 1357: 851: 1358: case 'h': /* 3.d.6) Commands history */ 851: 1359: printed = check_history(full_line, strlen(full_line)); 851: 1359-block 0 call 0 returned 851 851: 1360: if (printed) { branch 0 taken 405 (fallthrough) branch 1 taken 446 405: 1361: suggestion.offset = 0; 405: 1362: goto SUCCESS; 405: 1362-block 0 unconditional 0 taken 405 -: 1363: } 446: 1364: break; 446: 1364-block 0 unconditional 0 taken 446 -: 1365: 430: 1366: case 'j': /* 3.d.7) Jump database */ -: 1367: /* We don't care about auto-open here: the jump function -: 1368: * deals with directories only */ 430: 1369: if (last_space || autocd) { 430: 1369-block 0 branch 0 taken 291 (fallthrough) branch 1 taken 139 291: 1369-block 1 branch 2 taken 289 (fallthrough) branch 3 taken 2 428: 1370: printed = check_jumpdb(last_word, strlen(last_word)); 428: 1370-block 0 call 0 returned 428 428: 1371: if (printed) { branch 0 taken 6 (fallthrough) branch 1 taken 422 6: 1372: suggestion.offset = last_word_offset; 6: 1373: goto SUCCESS; 6: 1373-block 0 unconditional 0 taken 6 -: 1374: } -: 1375: } 424: 1376: break; 424: 1376-block 0 unconditional 0 taken 424 -: 1377: #####: 1378: case '-': break; /* Ignore check */ %%%%%: 1378-block 0 unconditional 0 never executed -: 1379: #####: 1380: default: break; %%%%%: 1380-block 0 unconditional 0 never executed -: 1381: } -: 1382: } -: 1383: -: 1384: /* 3.e) Variable names, both environment and internal */ 390: 1385: if (*last_word == '$') { 390: 1385-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 390 #####: 1386: printed = check_variables(last_word + 1, strlen(last_word + 1)); %%%%%: 1386-block 0 call 0 never executed #####: 1387: if (printed) { branch 0 never executed branch 1 never executed #####: 1388: suggestion.offset = last_word_offset; #####: 1389: goto SUCCESS; %%%%%: 1389-block 0 unconditional 0 never executed -: 1390: } -: 1391: } -: 1392: -: 1393: /* 3.f) Check commands in PATH and CliFM internals commands, but -: 1394: * only for the first word */ 390: 1395: if (!last_space) { 390: 1395-block 0 branch 0 taken 284 (fallthrough) branch 1 taken 106 284: 1396: size_t w_len = strlen(last_word); 284: 1397: printed = check_cmds(last_word, w_len); 284: 1397-block 0 call 0 returned 284 284: 1398: if (printed) { branch 0 taken 159 (fallthrough) branch 1 taken 125 159: 1399: suggestion.offset = 0; 159: 1400: goto SUCCESS; 159: 1400-block 0 unconditional 0 taken 159 -: 1401: }/* else { -: 1402: rl_delete_text(0, rl_end); -: 1403: rl_end = rl_point = 0; -: 1404: cur_color = nf_c; -: 1405: fputs("\x1b[0;31m", stdout); -: 1406: fflush(stdout); -: 1407: last_word[w_len - 1] = '\0'; -: 1408: rl_insert_text(last_word); -: 1409:// printed = 1; -: 1410: goto FAIL; -: 1411: } */ -: 1412: } -: 1413: -: 1414: /* No suggestion found */ -: 1415: -: 1416:/* int k = bm_n; -: 1417: while (--k >= 0) { -: 1418: if (!bookmarks[k].name) -: 1419: continue; -: 1420: if (strncmp(last_word, bookmarks[k].name, strlen(last_word)) == 0) { -: 1421: if (!bookmarks[k].path) -: 1422: continue; -: 1423: msg_area = 1; -: 1424: rl_save_prompt(); -: 1425: rl_message("\001\x1b[0;36m(%s):\002\x1b[0m ", bookmarks[k].path); -: 1426: break; -: 1427: } -: 1428: } -: 1429: -: 1430: if (k < 0 && msg_area == 1) { -: 1431: rl_restore_prompt(); -: 1432: rl_clear_message(); -: 1433: } */ -: 1434: -: 1435: /* Clear current suggestion, if any, only if no escape char is contained -: 1436: * in the current input sequence. This is mainly to avoid erasing -: 1437: * the suggestion if moving thought the text via the arrow keys */ 231: 1438: if (suggestion.printed) { 231: 1438-block 0 branch 0 taken 149 (fallthrough) branch 1 taken 82 82: 1439: if (!strchr(last_word, '\x1b')) { 82: 1439-block 0 branch 0 taken 82 (fallthrough) branch 1 taken 0 82: 1440: clear_suggestion(); 82: 1440-block 0 call 0 returned 82 82: 1441: free(full_line); 82: 1442: goto FAIL; unconditional 0 taken 82 -: 1443: } else { -: 1444: /* Go to SUCCESS to avoid removing the suggestion buffer */ #####: 1445: printed = 1; #####: 1446: goto SUCCESS; %%%%%: 1446-block 0 unconditional 0 never executed -: 1447: } -: 1448: } -: 1449: 149: 1450:SUCCESS: 149: 1450-block 0 unconditional 0 taken 149 1754: 1451: free(full_line); 1754: 1452: if (printed) { 1754: 1452-block 0 branch 0 taken 1383 (fallthrough) branch 1 taken 371 1383: 1453: suggestion.printed = 1; -: 1454: /* Restore color */ 1383: 1455: fputs("\x1b[0m", stdout); 1383: 1455-block 0 call 0 returned 1383 1383: 1456: if (!cur_color) branch 0 taken 241 (fallthrough) branch 1 taken 1142 241: 1457: fputs(df_c, stdout); 241: 1457-block 0 call 0 returned 241 unconditional 1 taken 241 -: 1458: else 1142: 1459: fputs(cur_color, stdout); 1142: 1459-block 0 call 0 returned 1142 unconditional 1 taken 1142 -: 1460: } else { 371: 1461: suggestion.printed = 0; 371: 1461-block 0 unconditional 0 taken 371 -: 1462: } 1754: 1463: free(last_word); 1754: 1464: if (inserted_c) 1754: 1464-block 0 branch 0 taken 16 (fallthrough) branch 1 taken 1738 16: 1465: return -1; 16: 1465-block 0 unconditional 0 taken 16 1738: 1466: return EXIT_SUCCESS; 1738: 1466-block 0 unconditional 0 taken 1738 -: 1467: 1139: 1468:FAIL: 1139: 1469: suggestion.printed = 0; 1139: 1470: free(last_word); 1139: 1471: free(suggestion_buf); 1139: 1472: suggestion_buf = (char *)NULL; 1139: 1473: if (inserted_c) 1139: 1473-block 0 branch 0 taken 4 (fallthrough) branch 1 taken 1135 4: 1474: return -1; 4: 1474-block 0 unconditional 0 taken 4 1135: 1475: return EXIT_FAILURE; 1135: 1475-block 0 unconditional 0 taken 1135 -: 1476:} -: 1477: -: 1478:#endif /* !_NO_SUGGESTIONS */ clifm-1.26.3/misc/codecov/trash.c.gcov000066400000000000000000002224431506632037700175140ustar00rootroot00000000000000 -: 0:Source:trash.c -: 1:/* trash.c -- functions controlling the trash system */ -: 2: -: 3:/* -: 4: * This file is part of CliFM -: 5: * -: 6: * Copyright (C) 2016-2021, L. Abramovich -: 7: * All rights reserved. -: 8: -: 9: * CliFM is free software; you can redistribute it and/or modify -: 10: * it under the terms of the GNU General Public License as published by -: 11: * the Free Software Foundation; either version 2 of the License, or -: 12: * (at your option) any later version. -: 13: * -: 14: * CliFM is distributed in the hope that it will be useful, -: 15: * but WITHOUT ANY WARRANTY; without even the implied warranty of -: 16: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -: 17: * GNU General Public License for more details. -: 18: * -: 19: * You should have received a copy of the GNU General Public License -: 20: * along with this program; if not, write to the Free Software -: 21: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, -: 22: * MA 02110-1301, USA. -: 23:*/ -: 24: -: 25:#ifndef _NO_TRASH -: 26: -: 27:#include "helpers.h" -: 28: -: 29:#include -: 30:#include -: 31:#include -: 32:#include -: 33:#include -: 34:#include -: 35:#include -: 36:#include -: 37: -: 38:#include "aux.h" -: 39:#include "checks.h" -: 40:#include "colors.h" -: 41:#include "exec.h" -: 42:#include "misc.h" -: 43:#include "navigation.h" -: 44:#include "readline.h" -: 45:#include "sort.h" -: 46:#include "trash.h" -: 47: -: 48:/* Recursively check directory permissions (write and execute). Returns -: 49: * zero if OK, and one if at least one subdirectory does not have -: 50: * write/execute permissions */ -: 51:static int function recur_perm_check called 2 returned 100% blocks executed 65% 2: 52:recur_perm_check(const char *dirname) -: 53:{ -: 54: DIR *dir; -: 55: struct dirent *ent; -: 56:#if !defined(_DIRENT_HAVE_D_TYPE) -: 57: struct stat attr; -: 58:#endif -: 59: 2: 60: if (!(dir = opendir(dirname))) 2: 60-block 0 call 0 returned 2 branch 1 taken 0 (fallthrough) branch 2 taken 2 #####: 61: return EXIT_FAILURE; %%%%%: 61-block 0 unconditional 0 never executed -: 62: 8: 63: while ((ent = readdir(dir)) != NULL) { 2: 63-block 0 unconditional 0 taken 2 8: 63-block 1 call 1 returned 8 branch 2 taken 6 branch 3 taken 2 (fallthrough) -: 64:#if !defined(_DIRENT_HAVE_D_TYPE) -: 65: if (lstat(ent->d_name, &attr) == -1) -: 66: continue; -: 67: if ((attr.st_mode & S_IFMT) == S_IFDIR) { -: 68:#else 6: 69: if (ent->d_type == DT_DIR) { 6: 69-block 0 branch 0 taken 4 (fallthrough) branch 1 taken 2 -: 70:#endif 4: 71: char dirpath[PATH_MAX] = ""; -: 72: 4: 73: if (*ent->d_name == '.' && (!ent->d_name[1] 4: 73-block 0 branch 0 taken 4 (fallthrough) branch 1 taken 0 4: 73-block 1 branch 2 taken 2 (fallthrough) branch 3 taken 2 2: 74: || (ent->d_name[1] == '.' && !ent->d_name[2]))) 2: 74-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 0 2: 74-block 1 branch 2 taken 2 (fallthrough) branch 3 taken 0 4: 75: continue; 4: 75-block 0 unconditional 0 taken 4 -: 76: #####: 77: snprintf(dirpath, PATH_MAX, "%s/%s", dirname, ent->d_name); -: 78: #####: 79: if (access(dirpath, W_OK | X_OK) != 0) { %%%%%: 79-block 0 call 0 never executed branch 1 never executed branch 2 never executed -: 80: /* recur_perm_error_flag needs to be a global variable. -: 81: * Otherwise, since this function calls itself -: 82: * recursivelly, the flag would be reset upon every -: 83: * new call, without preserving the error code, which -: 84: * is what the flag is aimed to do. On the other side, -: 85: * if I use a local static variable for this flag, it -: 86: * will never drop the error value, and all subsequent -: 87: * calls to the function will allways return error -: 88: * (even if there's no actual error) */ #####: 89: recur_perm_error_flag = 1; #####: 90: fprintf(stderr, _("%s: Permission denied\n"), dirpath); %%%%%: 90-block 0 call 0 never executed call 1 never executed unconditional 2 never executed -: 91: } -: 92: #####: 93: recur_perm_check(dirpath); %%%%%: 93-block 0 call 0 never executed -: 94: } -: 95: } -: 96: 2: 97: closedir(dir); 2: 97-block 0 call 0 returned 2 -: 98: 2: 99: if (recur_perm_error_flag) branch 0 taken 0 (fallthrough) branch 1 taken 2 #####: 100: return EXIT_FAILURE; %%%%%: 100-block 0 unconditional 0 never executed -: 101: 2: 102: return EXIT_SUCCESS; 2: 102-block 0 unconditional 0 taken 2 -: 103:} -: 104: -: 105:/* Check whether the current user has enough permissions (write, execute) -: 106: * to modify the contents of the parent directory of 'file'. 'file' needs -: 107: * to be an absolute path. Returns zero if yes and one if no. Useful to -: 108: * know if a file can be removed from or copied into the parent. In case -: 109: * FILE is a directory, the function checks all its subdirectories for -: 110: * appropriate permissions, including the immutable bit */ -: 111:static int function wx_parent_check called 11 returned 100% blocks executed 49% 11: 112:wx_parent_check(char *file) -: 113:{ -: 114: struct stat file_attrib; 11: 115: int exit_status = -1, ret = -1; 11: 116: size_t file_len = strlen(file); -: 117: 11: 118: if (file[file_len - 1] == '/') 11: 118-block 0 branch 0 taken 3 (fallthrough) branch 1 taken 8 3: 119: file[file_len - 1] = '\0'; 3: 119-block 0 unconditional 0 taken 3 -: 120: 11: 121: if (lstat(file, &file_attrib) == -1) { 11: 121-block 0 call 0 returned 11 branch 1 taken 0 (fallthrough) branch 2 taken 11 #####: 122: fprintf(stderr, _("%s: No such file or directory\n"), file); %%%%%: 122-block 0 call 0 never executed call 1 never executed #####: 123: return EXIT_FAILURE; unconditional 0 never executed -: 124: } -: 125: 11: 126: char *parent = strbfrlst(file, '/'); 11: 126-block 0 call 0 returned 11 11: 127: if (!parent) { branch 0 taken 0 (fallthrough) branch 1 taken 11 -: 128: /* strbfrlst() will return NULL if file's parent is root (/), -: 129: * simply because in this case there's nothing before the last -: 130: * slash. So, check if file's parent dir is root */ #####: 131: if (file[0] == '/' && strcntchr(file + 1, '/') == -1) { %%%%%: 131-block 0 branch 0 never executed branch 1 never executed %%%%%: 131-block 1 call 2 never executed branch 3 never executed branch 4 never executed #####: 132: parent = (char *)xnmalloc(2, sizeof(char)); %%%%%: 132-block 0 call 0 never executed #####: 133: parent[0] = '/'; #####: 134: parent[1] = '\0'; unconditional 0 never executed -: 135: } else { #####: 136: fprintf(stderr, _("%s: %s: Error getting parent directory\n"), %%%%%: 136-block 0 call 0 never executed call 1 never executed -: 137: PROGRAM_NAME, file); #####: 138: return EXIT_FAILURE; unconditional 0 never executed -: 139: } -: 140: } -: 141: 11: 142: switch (file_attrib.st_mode & S_IFMT) { 11: 142-block 0 branch 0 taken 3 branch 1 taken 6 branch 2 taken 2 branch 3 taken 0 3: 143: case S_IFDIR: 3: 144: ret = check_immutable_bit(file); 3: 144-block 0 call 0 returned 3 -: 145: 3: 146: if (ret == -1) { branch 0 taken 0 (fallthrough) branch 1 taken 3 -: 147: /* Error message is printed by check_immutable_bit() itself */ #####: 148: exit_status = EXIT_FAILURE; %%%%%: 148-block 0 unconditional 0 never executed 3: 149: } else if (ret == 1) { 3: 149-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 3 #####: 150: fprintf(stderr, _("%s: Directory is immutable\n"), file); %%%%%: 150-block 0 call 0 never executed call 1 never executed #####: 151: exit_status = EXIT_FAILURE; unconditional 0 never executed 3: 152: } else if (access(parent, W_OK | X_OK) == 0) { 3: 152-block 0 call 0 returned 3 branch 1 taken 3 (fallthrough) branch 2 taken 0 -: 153: /* Check the parent for appropriate permissions */ 3: 154: int files_n = count_dir(parent, NO_CPOP); 3: 154-block 0 call 0 returned 3 -: 155: 3: 156: if (files_n > 2) { branch 0 taken 3 (fallthrough) branch 1 taken 0 -: 157: /* I manually check here subdir because recur_perm_check() -: 158: * will only check the contents of subdir, but not subdir -: 159: * itself */ -: 160: /* If the parent is ok and not empty, check subdir */ 3: 161: if (access(file, W_OK | X_OK) == 0) { 3: 161-block 0 call 0 returned 3 branch 1 taken 3 (fallthrough) branch 2 taken 0 -: 162: /* If subdir is ok and not empty, recusivelly check -: 163: * subdir */ 3: 164: files_n = count_dir(file, NO_CPOP); 3: 164-block 0 call 0 returned 3 -: 165: 3: 166: if (files_n > 2) { branch 0 taken 2 (fallthrough) branch 1 taken 1 -: 167: /* Reset the recur_perm_check() error flag. See -: 168: * the note in the function block. */ 2: 169: recur_perm_error_flag = 0; -: 170: 2: 171: if (recur_perm_check(file) == 0) { 2: 171-block 0 call 0 returned 2 branch 1 taken 2 (fallthrough) branch 2 taken 0 2: 172: exit_status = EXIT_SUCCESS; 2: 172-block 0 unconditional 0 taken 2 -: 173: } else { -: 174: /* recur_perm_check itself will print the -: 175: * error messages */ #####: 176: exit_status = EXIT_FAILURE; %%%%%: 176-block 0 unconditional 0 never executed -: 177: } -: 178: } else { /* Subdir is ok and empty */ 1: 179: exit_status = EXIT_SUCCESS; 1: 179-block 0 unconditional 0 taken 1 -: 180: } -: 181: } else { /* No permission for subdir */ #####: 182: fprintf(stderr, _("%s: Permission denied\n"), %%%%%: 182-block 0 call 0 never executed call 1 never executed -: 183: file); #####: 184: exit_status = EXIT_FAILURE; unconditional 0 never executed -: 185: } -: 186: } -: 187: -: 188: else #####: 189: exit_status = EXIT_SUCCESS; %%%%%: 189-block 0 unconditional 0 never executed -: 190: } else { /* No permission for parent */ #####: 191: fprintf(stderr, _("%s: Permission denied\n"), parent); %%%%%: 191-block 0 call 0 never executed call 1 never executed #####: 192: exit_status = EXIT_FAILURE; unconditional 0 never executed -: 193: } 3: 194: break; 3: 194-block 0 unconditional 0 taken 3 -: 195: 6: 196: case S_IFREG: 6: 197: ret = check_immutable_bit(file); 6: 197-block 0 call 0 returned 6 -: 198: 6: 199: if (ret == -1) { branch 0 taken 0 (fallthrough) branch 1 taken 6 -: 200: /* Error message is printed by check_immutable_bit() -: 201: * itself */ #####: 202: exit_status = EXIT_FAILURE; %%%%%: 202-block 0 unconditional 0 never executed 6: 203: } else if (ret == 1) { 6: 203-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 6 #####: 204: fprintf(stderr, _("%s: File is immutable\n"), file); %%%%%: 204-block 0 call 0 never executed call 1 never executed #####: 205: exit_status = EXIT_FAILURE; unconditional 0 never executed 6: 206: } else if (parent) { 6: 206-block 0 branch 0 taken 6 (fallthrough) branch 1 taken 0 6: 207: if (access(parent, W_OK | X_OK) == 0) { 6: 207-block 0 call 0 returned 6 branch 1 taken 6 (fallthrough) branch 2 taken 0 6: 208: exit_status = EXIT_SUCCESS; 6: 208-block 0 unconditional 0 taken 6 -: 209: } else { #####: 210: fprintf(stderr, _("%s: Permission denied\n"), parent); %%%%%: 210-block 0 call 0 never executed call 1 never executed #####: 211: exit_status = EXIT_FAILURE; unconditional 0 never executed -: 212: } -: 213: } -: 214: 6: 215: break; 6: 215-block 0 unconditional 0 taken 6 -: 216: 2: 217: case S_IFSOCK: -: 218: case S_IFIFO: -: 219: case S_IFLNK: -: 220: /* Symlinks, sockets and pipes do not support immutable bit */ 2: 221: if (parent) { 2: 221-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 0 2: 222: if (access(parent, W_OK | X_OK) == 0) { 2: 222-block 0 call 0 returned 2 branch 1 taken 2 (fallthrough) branch 2 taken 0 2: 223: exit_status = EXIT_SUCCESS; 2: 223-block 0 unconditional 0 taken 2 -: 224: } else { #####: 225: fprintf(stderr, _("%s: Permission denied\n"), parent); %%%%%: 225-block 0 call 0 never executed call 1 never executed #####: 226: exit_status = EXIT_FAILURE; unconditional 0 never executed -: 227: } -: 228: } 2: 229: break; 2: 229-block 0 unconditional 0 taken 2 -: 230: -: 231: /* DO NOT TRASH BLOCK AND CHAR DEVICES */ #####: 232: default: #####: 233: fprintf(stderr, _("%s: trash: %s (%s): Unsupported file type\n"), %%%%%: 233-block 0 unconditional 0 never executed %%%%%: 233-block 1 unconditional 1 never executed %%%%%: 233-block 2 call 2 never executed call 3 never executed #####: 234: PROGRAM_NAME, file, ((file_attrib.st_mode & S_IFMT) == S_IFBLK) %%%%%: 234-block 0 branch 0 never executed branch 1 never executed #####: 235: ? "Block device" : ((file_attrib.st_mode & S_IFMT) == S_IFCHR) #####: 236: ? "Character device" : "Unknown file type"); %%%%%: 236-block 0 branch 0 never executed branch 1 never executed %%%%%: 236-block 1 unconditional 2 never executed %%%%%: 236-block 2 unconditional 3 never executed #####: 237: exit_status = EXIT_FAILURE; #####: 238: break; unconditional 0 never executed -: 239: } -: 240: 11: 241: if (parent) 11: 241-block 0 branch 0 taken 11 (fallthrough) branch 1 taken 0 11: 242: free(parent); 11: 242-block 0 unconditional 0 taken 11 -: 243: 11: 244: return exit_status; 11: 244-block 0 unconditional 0 taken 11 -: 245:} -: 246: -: 247:static int function trash_clear called 0 returned 0% blocks executed 0% #####: 248:trash_clear(void) -: 249:{ #####: 250: struct dirent **trash_files = (struct dirent **)NULL; #####: 251: int files_n = -1, exit_status = EXIT_SUCCESS; -: 252: #####: 253: if (xchdir(trash_files_dir, NO_TITLE) == -1) { %%%%%: 253-block 0 call 0 never executed branch 1 never executed branch 2 never executed #####: 254: _err(0, NOPRINT_PROMPT, "%s: trash: '%s': %s\n", PROGRAM_NAME, call 0 never executed #####: 255: trash_files_dir, strerror(errno)); %%%%%: 255-block 0 call 0 never executed #####: 256: return EXIT_FAILURE; unconditional 0 never executed -: 257: } -: 258: #####: 259: files_n = scandir(trash_files_dir, &trash_files, skip_files, xalphasort); %%%%%: 259-block 0 call 0 never executed -: 260: #####: 261: if (!files_n) { branch 0 never executed branch 1 never executed #####: 262: puts(_("trash: There are no trashed files")); %%%%%: 262-block 0 call 0 never executed call 1 never executed #####: 263: return EXIT_SUCCESS; unconditional 0 never executed -: 264: } -: 265: -: 266: size_t i; #####: 267: for (i = 0; i < (size_t)files_n; i++) { %%%%%: 267-block 0 unconditional 0 never executed %%%%%: 267-block 1 branch 1 never executed branch 2 never executed #####: 268: size_t info_file_len = strlen(trash_files[i]->d_name) + 11; #####: 269: char *info_file = (char *)xnmalloc(info_file_len, sizeof(char)); %%%%%: 269-block 0 call 0 never executed #####: 270: sprintf(info_file, "%s.trashinfo", trash_files[i]->d_name); -: 271: #####: 272: char *file1 = (char *)NULL; #####: 273: file1 = (char *)xnmalloc(strlen(trash_files_dir) + #####: 274: strlen(trash_files[i]->d_name) + 2, sizeof(char)); call 0 never executed -: 275: #####: 276: sprintf(file1, "%s/%s", trash_files_dir, trash_files[i]->d_name); -: 277: #####: 278: char *file2 = (char *)NULL; #####: 279: file2 = (char *)xnmalloc(strlen(trash_info_dir) + #####: 280: strlen(info_file) + 2, sizeof(char)); call 0 never executed #####: 281: sprintf(file2, "%s/%s", trash_info_dir, info_file); -: 282: #####: 283: char *tmp_cmd[] = {"rm", "-r", file1, file2, NULL}; #####: 284: int ret = launch_execve(tmp_cmd, FOREGROUND, E_NOFLAG); call 0 never executed -: 285: #####: 286: free(file1); #####: 287: free(file2); -: 288: #####: 289: if (ret != EXIT_SUCCESS) { branch 0 never executed branch 1 never executed #####: 290: fprintf(stderr, _("%s: trash: %s: Error removing " call 0 never executed #####: 291: "trashed file\n"), PROGRAM_NAME, trash_files[i]->d_name); %%%%%: 291-block 0 call 0 never executed #####: 292: exit_status = EXIT_FAILURE; unconditional 0 never executed -: 293: /* If there is at least one error, return error */ -: 294: } -: 295: #####: 296: free(info_file); #####: 297: free(trash_files[i]); %%%%%: 297-block 0 unconditional 0 never executed -: 298: } -: 299: #####: 300: free(trash_files); -: 301: #####: 302: if (xchdir(ws[cur_ws].path, NO_TITLE) == -1) { %%%%%: 302-block 0 call 0 never executed branch 1 never executed branch 2 never executed #####: 303: _err(0, NOPRINT_PROMPT, "%s: trash: '%s': %s\n", PROGRAM_NAME, #####: 304: ws[cur_ws].path, strerror(errno)); %%%%%: 304-block 0 call 0 never executed call 1 never executed #####: 305: return EXIT_FAILURE; unconditional 0 never executed -: 306: } -: 307: #####: 308: return exit_status; %%%%%: 308-block 0 unconditional 0 never executed -: 309:} -: 310: -: 311:static int function trash_element called 11 returned 100% blocks executed 48% 11: 312:trash_element(const char *suffix, struct tm *tm, char *file) -: 313:{ -: 314: /* Check file's existence */ -: 315: struct stat file_attrib; -: 316: 11: 317: if (lstat(file, &file_attrib) == -1) { 11: 317-block 0 call 0 returned 11 branch 1 taken 0 (fallthrough) branch 2 taken 11 #####: 318: fprintf(stderr, "%s: trash: %s: %s\n", PROGRAM_NAME, file, call 0 never executed #####: 319: strerror(errno)); %%%%%: 319-block 0 call 0 never executed #####: 320: return EXIT_FAILURE; unconditional 0 never executed -: 321: } -: 322: -: 323: /* Check whether the user has enough permissions to remove file */ -: 324: /* If relative path */ 11: 325: char full_path[PATH_MAX] = ""; -: 326: 11: 327: if (*file != '/') { 11: 327-block 0 branch 0 taken 7 (fallthrough) branch 1 taken 4 -: 328: /* Construct absolute path for file */ 7: 329: snprintf(full_path, PATH_MAX, "%s/%s", ws[cur_ws].path, file); 7: 330: if (wx_parent_check(full_path) != 0) 7: 330-block 0 call 0 returned 7 branch 1 taken 0 (fallthrough) branch 2 taken 7 #####: 331: return EXIT_FAILURE; %%%%%: 331-block 0 unconditional 0 never executed 4: 332: } else if (wx_parent_check(file) != 0) { 4: 332-block 0 call 0 returned 4 branch 1 taken 0 (fallthrough) branch 2 taken 4 -: 333: /* If absolute path */ #####: 334: return EXIT_FAILURE; %%%%%: 334-block 0 unconditional 0 never executed -: 335: } -: 336: 11: 337: int ret = -1; -: 338: -: 339: /* Create the trashed file name: orig_filename.suffix, where SUFFIX is -: 340: * current date and time */ 11: 341: char *filename = (char *)NULL; 11: 342: if (*file != '/') /* If relative path */ 11: 342-block 0 branch 0 taken 7 (fallthrough) branch 1 taken 4 7: 343: filename = straftlst(full_path, '/'); 7: 343-block 0 call 0 returned 7 unconditional 1 taken 7 -: 344: else /* If absolute path */ 4: 345: filename = straftlst(file, '/'); 4: 345-block 0 call 0 returned 4 unconditional 1 taken 4 -: 346: 11: 347: if (!filename) { 11: 347-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 11 #####: 348: fprintf(stderr, _("%s: trash: %s: Error getting file name\n"), %%%%%: 348-block 0 call 0 never executed call 1 never executed -: 349: PROGRAM_NAME, file); #####: 350: return EXIT_FAILURE; unconditional 0 never executed -: 351: } -: 352: /* If the length of the trashed file name (orig_filename.suffix) is -: 353: * longer than NAME_MAX (255), trim the original filename, so that -: 354: * (original_filename_len + 1 (dot) + suffix_len) won't be longer -: 355: * than NAME_MAX */ 11: 356: size_t filename_len = strlen(filename), suffix_len = strlen(suffix); 11: 357: int size = (int)(filename_len + suffix_len + 1) - NAME_MAX; -: 358: 11: 359: if (size > 0) { 11: 359-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 11 -: 360: /* If SIZE is a positive value, that is, the trashed file name -: 361: * exceeds NAME_MAX by SIZE bytes, reduce the original file name -: 362: * SIZE bytes. Terminate the original file name (FILENAME) with -: 363: * a tilde (~), to let the user know it is trimmed */ #####: 364: filename[filename_len - (size_t)size - 1] = '~'; #####: 365: filename[filename_len - (size_t)size] = '\0'; %%%%%: 365-block 0 unconditional 0 never executed -: 366: } -: 367: -: 368: /* 2 = dot + null byte */ 11: 369: size_t file_suffix_len = filename_len + suffix_len + 2; 11: 370: char *file_suffix = (char *)xnmalloc(file_suffix_len, sizeof(char)); 11: 370-block 0 call 0 returned 11 -: 371: /* No need for memset. sprintf adds the terminating null byte by -: 372: * itself */ 11: 373: sprintf(file_suffix, "%s.%s", filename, suffix); -: 374: -: 375: /* Copy the original file into the trash files directory */ 11: 376: char *dest = (char *)NULL; 11: 377: dest = (char *)xnmalloc(strlen(trash_files_dir) + strlen(file_suffix) + 2, call 0 returned 11 -: 378: sizeof(char)); 11: 379: sprintf(dest, "%s/%s", trash_files_dir, file_suffix); -: 380: 11: 381: char *tmp_cmd[] = {"cp", "-a", file, dest, NULL}; -: 382: 11: 383: free(filename); -: 384: 11: 385: ret = launch_execve(tmp_cmd, FOREGROUND, E_NOFLAG); call 0 returned 11 11: 386: free(dest); 11: 387: dest = (char *)NULL; -: 388: 11: 389: if (ret != EXIT_SUCCESS) { branch 0 taken 0 (fallthrough) branch 1 taken 11 #####: 390: fprintf(stderr, _("%s: trash: %s: Failed copying file to " %%%%%: 390-block 0 call 0 never executed call 1 never executed -: 391: "Trash\n"), PROGRAM_NAME, file); #####: 392: free(file_suffix); #####: 393: return EXIT_FAILURE; unconditional 0 never executed -: 394: } -: 395: -: 396: /* Generate the info file */ 11: 397: size_t info_file_len = strlen(trash_info_dir) + strlen(file_suffix) + 12; -: 398: 11: 399: char *info_file = (char *)xnmalloc(info_file_len, sizeof(char)); 11: 399-block 0 call 0 returned 11 11: 400: sprintf(info_file, "%s/%s.trashinfo", trash_info_dir, file_suffix); -: 401: 11: 402: FILE *info_fp = fopen(info_file, "w"); call 0 returned 11 11: 403: if (!info_fp) { /* If error creating the info file */ branch 0 taken 0 (fallthrough) branch 1 taken 11 #####: 404: fprintf(stderr, "%s: %s: %s\n", PROGRAM_NAME, info_file, call 0 never executed #####: 405: strerror(errno)); %%%%%: 405-block 0 call 0 never executed -: 406: /* Remove the trash file */ #####: 407: char *trash_file = (char *)NULL; #####: 408: trash_file = (char *)xnmalloc(strlen(trash_files_dir) #####: 409: + strlen(file_suffix) + 2, sizeof(char)); call 0 never executed #####: 410: sprintf(trash_file, "%s/%s", trash_files_dir, file_suffix); -: 411: #####: 412: char *tmp_cmd2[] = {"rm", "-r", trash_file, NULL}; #####: 413: ret = launch_execve(tmp_cmd2, FOREGROUND, E_NOFLAG); call 0 never executed -: 414: #####: 415: free(trash_file); -: 416: #####: 417: if (ret != EXIT_SUCCESS) branch 0 never executed branch 1 never executed #####: 418: fprintf(stderr, _("%s: trash: %s/%s: Failed removing trash " %%%%%: 418-block 0 call 0 never executed call 1 never executed unconditional 2 never executed -: 419: "file\nTry removing it manually\n"), PROGRAM_NAME, -: 420: trash_files_dir, file_suffix); -: 421: #####: 422: free(file_suffix); #####: 423: free(info_file); -: 424: #####: 425: return EXIT_FAILURE; %%%%%: 425-block 0 unconditional 0 never executed -: 426: } -: 427: -: 428: else { /* If info file was generated successfully */ -: 429: /* Encode path to URL format (RF 2396) */ 11: 430: char *url_str = (char *)NULL; -: 431: 11: 432: if (*file != '/') 11: 432-block 0 branch 0 taken 7 (fallthrough) branch 1 taken 4 7: 433: url_str = url_encode(full_path); 7: 433-block 0 call 0 returned 7 unconditional 1 taken 7 -: 434: else 4: 435: url_str = url_encode(file); 4: 435-block 0 call 0 returned 4 unconditional 1 taken 4 -: 436: 11: 437: if (!url_str) { 11: 437-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 11 #####: 438: fprintf(stderr, _("%s: trash: %s: Failed encoding path\n"), %%%%%: 438-block 0 call 0 never executed call 1 never executed -: 439: PROGRAM_NAME, file); -: 440: #####: 441: fclose(info_fp); call 0 never executed #####: 442: free(info_file); #####: 443: free(file_suffix); #####: 444: return EXIT_FAILURE; unconditional 0 never executed -: 445: } -: 446: -: 447: /* Write trashed file information into the info file */ 11: 448: fprintf(info_fp, -: 449: "[Trash Info]\nPath=%s\nDeletionDate=%d%d%dT%d:%d:%d\n", 11: 450: url_str, tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, 11: 450-block 0 call 0 returned 11 -: 451: tm->tm_hour, tm->tm_min, tm->tm_sec); 11: 452: fclose(info_fp); call 0 returned 11 11: 453: free(url_str); 11: 454: url_str = (char *)NULL; -: 455: } -: 456: -: 457: /* Remove the file to be trashed */ 11: 458: char *tmp_cmd3[] = {"rm", "-r", file, NULL}; 11: 459: ret = launch_execve(tmp_cmd3, FOREGROUND, E_NOFLAG); call 0 returned 11 -: 460: -: 461: /* If remove fails, remove trash and info files */ 11: 462: if (ret != EXIT_SUCCESS) { branch 0 taken 0 (fallthrough) branch 1 taken 11 #####: 463: fprintf(stderr, _("%s: trash: %s: Failed removing file\n"), %%%%%: 463-block 0 call 0 never executed call 1 never executed -: 464: PROGRAM_NAME, file); #####: 465: char *trash_file = (char *)NULL; #####: 466: trash_file = (char *)xnmalloc(strlen(trash_files_dir) #####: 467: + strlen(file_suffix) + 2, sizeof(char)); call 0 never executed #####: 468: sprintf(trash_file, "%s/%s", trash_files_dir, file_suffix); -: 469: #####: 470: char *tmp_cmd4[] = {"rm", "-r", trash_file, info_file, NULL}; #####: 471: ret = launch_execve(tmp_cmd4, FOREGROUND, E_NOFLAG); call 0 never executed #####: 472: free(trash_file); -: 473: #####: 474: if (ret != EXIT_SUCCESS) { branch 0 never executed branch 1 never executed #####: 475: fprintf(stderr, _("%s: trash: Failed removing temporary " %%%%%: 475-block 0 call 0 never executed call 1 never executed -: 476: "files from Trash.\nTry removing them manually\n"), -: 477: PROGRAM_NAME); #####: 478: free(file_suffix); #####: 479: free(info_file); #####: 480: return EXIT_FAILURE; unconditional 0 never executed -: 481: } -: 482: } -: 483: 11: 484: free(info_file); 11: 485: free(file_suffix); 11: 486: return EXIT_SUCCESS; 11: 486-block 0 unconditional 0 taken 11 -: 487:} -: 488: -: 489:static int function remove_from_trash called 1 returned 100% blocks executed 45% 1: 490:remove_from_trash(void) -: 491:{ -: 492: /* List trashed files */ -: 493: /* Change CWD to the trash directory. Otherwise, scandir() will fail */ 1: 494: if (xchdir(trash_files_dir, NO_TITLE) == -1) { 1: 494-block 0 call 0 returned 1 branch 1 taken 0 (fallthrough) branch 2 taken 1 #####: 495: _err(0, NOPRINT_PROMPT, "%s: trash: '%s': %s\n", PROGRAM_NAME, call 0 never executed #####: 496: trash_files_dir, strerror(errno)); %%%%%: 496-block 0 call 0 never executed #####: 497: return EXIT_FAILURE; unconditional 0 never executed -: 498: } -: 499: 1: 500: size_t i = 0; 1: 501: struct dirent **trash_files = (struct dirent **)NULL; 1*: 502: int files_n = scandir(trash_files_dir, &trash_files, %%%%%: 502-block 0 unconditional 0 never executed %%%%%: 502-block 1 unconditional 1 never executed %%%%%: 502-block 2 unconditional 2 never executed 1: 502-block 3 unconditional 3 taken 1 1: 502-block 4 call 4 returned 1 1: 503: skip_files, (unicode) ? alphasort : (case_sensitive) 1: 503-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 1 #####: 504: ? xalphasort : alphasort_insensitive); %%%%%: 504-block 0 branch 0 never executed branch 1 never executed -: 505: 1: 506: if (files_n) { branch 0 taken 1 (fallthrough) branch 1 taken 0 1: 507: printf(_("%sTrashed files%s\n\n"), BOLD, df_c); 1: 507-block 0 call 0 returned 1 call 1 returned 1 -: 508: 2: 509: for (i = 0; i < (size_t)files_n; i++) unconditional 0 taken 1 unconditional 1 taken 1 2: 509-block 0 branch 2 taken 1 branch 3 taken 1 1: 510: colors_list(trash_files[i]->d_name, (int)i + 1, NO_PAD, 1: 510-block 0 call 0 returned 1 -: 511: PRINT_NEWLINE); -: 512: } else { #####: 513: puts(_("trash: There are no trashed files")); %%%%%: 513-block 0 call 0 never executed call 1 never executed -: 514: /* Restore CWD and return */ #####: 515: if (xchdir(ws[cur_ws].path, NO_TITLE) == -1) { call 0 never executed branch 1 never executed branch 2 never executed #####: 516: _err(0, NOPRINT_PROMPT, "%s: trash: '%s': %s\n", #####: 517: PROGRAM_NAME, ws[cur_ws].path, strerror(errno)); %%%%%: 517-block 0 call 0 never executed call 1 never executed unconditional 2 never executed -: 518: } -: 519: #####: 520: return EXIT_SUCCESS; %%%%%: 520-block 0 unconditional 0 never executed -: 521: } -: 522: -: 523: /* Restore CWD and continue */ 1: 524: if (xchdir(ws[cur_ws].path, NO_TITLE) == -1) { 1: 524-block 0 call 0 returned 1 branch 1 taken 0 (fallthrough) branch 2 taken 1 #####: 525: _err(0, NOPRINT_PROMPT, "%s: trash: '%s': %s\n", PROGRAM_NAME, #####: 526: ws[cur_ws].path, strerror(errno)); %%%%%: 526-block 0 call 0 never executed call 1 never executed #####: 527: return EXIT_FAILURE; unconditional 0 never executed -: 528: } -: 529: -: 530: /* Get user input */ 1: 531: printf(_("\n%sEnter 'q' to quit.\n"), df_c); 1: 531-block 0 call 0 returned 1 call 1 returned 1 1: 532: char *line = (char *)NULL, **rm_elements = (char **)NULL; -: 533: 2: 534: while (!line) unconditional 0 taken 1 2: 534-block 0 branch 1 taken 1 branch 2 taken 1 (fallthrough) 1: 535: line = rl_no_hist(_("File(s) to be removed (ex: 1 2-6, or *): ")); 1: 535-block 0 call 0 returned 1 call 1 returned 1 unconditional 2 taken 1 -: 536: 1: 537: rm_elements = get_substr(line, ' '); 1: 537-block 0 call 0 returned 1 1: 538: free(line); -: 539: 1: 540: if (!rm_elements) branch 0 taken 0 (fallthrough) branch 1 taken 1 #####: 541: return EXIT_FAILURE; %%%%%: 541-block 0 unconditional 0 never executed -: 542: -: 543: /* Remove files */ 1: 544: char rm_file[PATH_MAX] = "", rm_info[PATH_MAX] = ""; 1: 545: int ret = -1, exit_status = EXIT_SUCCESS; -: 546: -: 547: /* First check for exit, wildcard, and non-number args */ 2: 548: for (i = 0; rm_elements[i]; i++) { 1: 548-block 0 unconditional 0 taken 1 1: 548-block 1 unconditional 1 taken 1 2: 548-block 2 branch 2 taken 1 branch 3 taken 1 (fallthrough) -: 549: /* Quit */ 1: 550: if (strcmp(rm_elements[i], "q") == 0) { 1: 550-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 1 -: 551: size_t j; #####: 552: for (j = 0; rm_elements[j]; j++) %%%%%: 552-block 0 unconditional 0 never executed %%%%%: 552-block 1 branch 1 never executed branch 2 never executed #####: 553: free(rm_elements[j]); %%%%%: 553-block 0 unconditional 0 never executed #####: 554: free(rm_elements); -: 555: #####: 556: for (j = 0; j < (size_t)files_n; j++) %%%%%: 556-block 0 unconditional 0 never executed %%%%%: 556-block 1 branch 1 never executed branch 2 never executed #####: 557: free(trash_files[j]); %%%%%: 557-block 0 unconditional 0 never executed #####: 558: free(trash_files); -: 559: #####: 560: return exit_status; %%%%%: 560-block 0 unconditional 0 never executed -: 561: } -: 562: -: 563: /* Asterisk */ 1: 564: else if (strcmp(rm_elements[i], "*") == 0) { 1: 564-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 1 -: 565: size_t j; #####: 566: for (j = 0; j < (size_t)files_n; j++) { %%%%%: 566-block 0 unconditional 0 never executed %%%%%: 566-block 1 branch 1 never executed branch 2 never executed #####: 567: snprintf(rm_file, PATH_MAX, "%s/%s", trash_files_dir, #####: 568: trash_files[j]->d_name); #####: 569: snprintf(rm_info, PATH_MAX, "%s/%s.trashinfo", #####: 570: trash_info_dir, trash_files[j]->d_name); -: 571: #####: 572: char *tmp_cmd[] = {"rm", "-r", rm_file, rm_info, NULL}; -: 573: #####: 574: ret = launch_execve(tmp_cmd, FOREGROUND, E_NOFLAG); %%%%%: 574-block 0 call 0 never executed #####: 575: if (ret != EXIT_SUCCESS) { branch 0 never executed branch 1 never executed #####: 576: fprintf(stderr, _("%s: trash: Error trashing %s\n"), call 0 never executed #####: 577: PROGRAM_NAME, trash_files[j]->d_name); %%%%%: 577-block 0 call 0 never executed #####: 578: exit_status = EXIT_FAILURE; unconditional 0 never executed -: 579: } -: 580: #####: 581: free(trash_files[j]); %%%%%: 581-block 0 unconditional 0 never executed -: 582: } -: 583: #####: 584: free(trash_files); -: 585: #####: 586: for (j = 0; rm_elements[j]; j++) %%%%%: 586-block 0 unconditional 0 never executed %%%%%: 586-block 1 branch 1 never executed branch 2 never executed #####: 587: free(rm_elements[j]); %%%%%: 587-block 0 unconditional 0 never executed -: 588: #####: 589: free(rm_elements); -: 590: #####: 591: return exit_status; %%%%%: 591-block 0 unconditional 0 never executed -: 592: } -: 593: 1: 594: else if (!is_number(rm_elements[i])) { 1: 594-block 0 call 0 returned 1 branch 1 taken 0 (fallthrough) branch 2 taken 1 -: 595: #####: 596: fprintf(stderr, _("%s: trash: %s: Invalid ELN\n"), call 0 never executed #####: 597: PROGRAM_NAME, rm_elements[i]); %%%%%: 597-block 0 call 0 never executed #####: 598: exit_status = EXIT_FAILURE; -: 599: -: 600: size_t j; #####: 601: for (j = 0; rm_elements[j]; j++) unconditional 0 never executed %%%%%: 601-block 0 branch 1 never executed branch 2 never executed #####: 602: free(rm_elements[j]); %%%%%: 602-block 0 unconditional 0 never executed #####: 603: free(rm_elements); -: 604: #####: 605: for (j = 0; j < (size_t)files_n; j++) %%%%%: 605-block 0 unconditional 0 never executed %%%%%: 605-block 1 branch 1 never executed branch 2 never executed #####: 606: free(trash_files[j]); %%%%%: 606-block 0 unconditional 0 never executed #####: 607: free(trash_files); -: 608: #####: 609: return exit_status; %%%%%: 609-block 0 unconditional 0 never executed -: 610: } -: 611: } -: 612: -: 613: /* If all args are numbers, and neither 'q' nor wildcard */ 2: 614: for (i = 0; rm_elements[i]; i++) { 1: 614-block 0 unconditional 0 taken 1 1: 614-block 1 unconditional 1 taken 1 2: 614-block 2 branch 2 taken 1 branch 3 taken 1 (fallthrough) 1: 615: int rm_num = atoi(rm_elements[i]); -: 616: 1*: 617: if (rm_num <= 0 || rm_num > files_n) { 1: 617-block 0 branch 0 taken 1 (fallthrough) branch 1 taken 0 1: 617-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 1 #####: 618: fprintf(stderr, _("%s: trash: %d: Invalid ELN\n"), %%%%%: 618-block 0 call 0 never executed call 1 never executed -: 619: PROGRAM_NAME, rm_num); #####: 620: free(rm_elements[i]); #####: 621: exit_status = EXIT_FAILURE; #####: 622: continue; unconditional 0 never executed -: 623: } -: 624: 1: 625: snprintf(rm_file, PATH_MAX, "%s/%s", trash_files_dir, 1: 626: trash_files[rm_num - 1]->d_name); 1: 627: snprintf(rm_info, PATH_MAX, "%s/%s.trashinfo", trash_info_dir, 1: 628: trash_files[rm_num - 1]->d_name); -: 629: 1: 630: char *tmp_cmd2[] = {"rm", "-r", rm_file, rm_info, NULL}; -: 631: 1: 632: ret = launch_execve(tmp_cmd2, FOREGROUND, E_NOFLAG); 1: 632-block 0 call 0 returned 1 1: 633: if (ret != EXIT_SUCCESS) { branch 0 taken 0 (fallthrough) branch 1 taken 1 #####: 634: fprintf(stderr, _("%s: trash: Error trashing %s\n"), call 0 never executed #####: 635: PROGRAM_NAME, trash_files[rm_num - 1]->d_name); %%%%%: 635-block 0 call 0 never executed #####: 636: exit_status = EXIT_FAILURE; unconditional 0 never executed -: 637: } -: 638: 1: 639: free(rm_elements[i]); 1: 639-block 0 unconditional 0 taken 1 -: 640: } -: 641: 1: 642: free(rm_elements); -: 643: 2: 644: for (i = 0; i < (size_t)files_n; i++) 1: 644-block 0 unconditional 0 taken 1 2: 644-block 1 branch 1 taken 1 branch 2 taken 1 (fallthrough) 1: 645: free(trash_files[i]); 1: 645-block 0 unconditional 0 taken 1 1: 646: free(trash_files); -: 647: 1: 648: return exit_status; 1: 648-block 0 unconditional 0 taken 1 -: 649:} -: 650: -: 651:static int function untrash_element called 10 returned 100% blocks executed 52% 10: 652:untrash_element(char *file) -: 653:{ 10: 654: if (!file) 10: 654-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 10 #####: 655: return EXIT_FAILURE; %%%%%: 655-block 0 unconditional 0 never executed -: 656: -: 657: char undel_file[PATH_MAX], undel_info[PATH_MAX]; 10: 658: snprintf(undel_file, PATH_MAX, "%s/%s", trash_files_dir, file); 10: 659: snprintf(undel_info, PATH_MAX, "%s/%s.trashinfo", trash_info_dir, -: 660: file); -: 661: -: 662: FILE *info_fp; 10: 663: info_fp = fopen(undel_info, "r"); 10: 663-block 0 call 0 returned 10 10: 664: if (!info_fp) { branch 0 taken 0 (fallthrough) branch 1 taken 10 #####: 665: fprintf(stderr, _("%s: undel: Info file for '%s' not found. " %%%%%: 665-block 0 call 0 never executed call 1 never executed -: 666: "Try restoring the file manually\n"), PROGRAM_NAME, file); #####: 667: return EXIT_FAILURE; unconditional 0 never executed -: 668: } -: 669: 10: 670: char *orig_path = (char *)NULL; -: 671: /* The max length for line is Path=(5) + PATH_MAX + \n(1) */ -: 672: char line[PATH_MAX + 6]; 10: 673: memset(line, '\0', PATH_MAX + 6); -: 674: 40: 675: while (fgets(line, (int)sizeof(line), info_fp)) { 10: 675-block 0 unconditional 0 taken 10 40: 675-block 1 call 1 returned 40 branch 2 taken 30 branch 3 taken 10 (fallthrough) 30: 676: if (strncmp(line, "Path=", 5) == 0) 30: 676-block 0 branch 0 taken 10 (fallthrough) branch 1 taken 20 10: 677: orig_path = straft(line, '='); 10: 677-block 0 call 0 returned 10 unconditional 1 taken 10 -: 678: } -: 679: 10: 680: fclose(info_fp); 10: 680-block 0 call 0 returned 10 -: 681: -: 682: /* If original path is NULL or empty, return error */ 10: 683: if (!orig_path) branch 0 taken 0 (fallthrough) branch 1 taken 10 #####: 684: return EXIT_FAILURE; %%%%%: 684-block 0 unconditional 0 never executed -: 685: 10: 686: if (*orig_path == '\0') { 10: 686-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 10 #####: 687: free(orig_path); #####: 688: return EXIT_FAILURE; %%%%%: 688-block 0 unconditional 0 never executed -: 689: } -: 690: -: 691: /* Remove new line char from original path, if any */ 10: 692: size_t orig_path_len = strlen(orig_path); 10: 693: if (orig_path[orig_path_len - 1] == '\n') 10: 693-block 0 branch 0 taken 10 (fallthrough) branch 1 taken 0 10: 694: orig_path[orig_path_len - 1] = '\0'; 10: 694-block 0 unconditional 0 taken 10 -: 695: -: 696: /* Decode original path's URL format */ 10: 697: char *url_decoded = url_decode(orig_path); 10: 697-block 0 call 0 returned 10 -: 698: 10: 699: if (!url_decoded) { branch 0 taken 0 (fallthrough) branch 1 taken 10 #####: 700: fprintf(stderr, _("%s: undel: %s: Failed decoding path\n"), %%%%%: 700-block 0 call 0 never executed call 1 never executed -: 701: PROGRAM_NAME, orig_path); #####: 702: free(orig_path); #####: 703: return EXIT_FAILURE; unconditional 0 never executed -: 704: } -: 705: 10: 706: free(orig_path); 10: 707: orig_path = (char *)NULL; -: 708: -: 709: /* Check existence and permissions of parent directory */ 10: 710: char *parent = (char *)NULL; 10: 711: parent = strbfrlst(url_decoded, '/'); 10: 711-block 0 call 0 returned 10 -: 712: 10: 713: if (!parent) { branch 0 taken 0 (fallthrough) branch 1 taken 10 -: 714: /* strbfrlst() returns NULL is file's parent is root (simply -: 715: * because there's nothing before last slash in this case). -: 716: * So, check if file's parent is root. Else returns */ #####: 717: if (url_decoded[0] == '/' && strcntchr(url_decoded + 1, '/') == -1) { %%%%%: 717-block 0 branch 0 never executed branch 1 never executed %%%%%: 717-block 1 call 2 never executed branch 3 never executed branch 4 never executed #####: 718: parent = (char *)xnmalloc(2, sizeof(char)); %%%%%: 718-block 0 call 0 never executed #####: 719: parent[0] = '/'; #####: 720: parent[1] = '\0'; unconditional 0 never executed -: 721: } else { #####: 722: free(url_decoded); #####: 723: return EXIT_FAILURE; %%%%%: 723-block 0 unconditional 0 never executed -: 724: } -: 725: } -: 726: 10: 727: if (access(parent, F_OK) != 0) { 10: 727-block 0 call 0 returned 10 branch 1 taken 0 (fallthrough) branch 2 taken 10 #####: 728: fprintf(stderr, _("%s: undel: %s: No such file or directory\n"), %%%%%: 728-block 0 call 0 never executed call 1 never executed -: 729: PROGRAM_NAME, parent); #####: 730: free(parent); #####: 731: free(url_decoded); #####: 732: return EXIT_FAILURE; unconditional 0 never executed -: 733: } -: 734: 10: 735: if (access(parent, X_OK | W_OK) != 0) { 10: 735-block 0 call 0 returned 10 branch 1 taken 0 (fallthrough) branch 2 taken 10 #####: 736: fprintf(stderr, _("%s: undel: %s: Permission denied\n"), %%%%%: 736-block 0 call 0 never executed call 1 never executed -: 737: PROGRAM_NAME, parent); #####: 738: free(parent); #####: 739: free(url_decoded); #####: 740: return EXIT_FAILURE; unconditional 0 never executed -: 741: } -: 742: 10: 743: free(parent); -: 744: 10: 745: char *tmp_cmd[] = {"cp", "-a", undel_file, url_decoded, NULL}; 10: 746: int ret = -1; 10: 747: ret = launch_execve(tmp_cmd, FOREGROUND, E_NOFLAG); 10: 747-block 0 call 0 returned 10 10: 748: free(url_decoded); -: 749: 10: 750: if (ret == EXIT_SUCCESS) { branch 0 taken 10 (fallthrough) branch 1 taken 0 10: 751: char *tmp_cmd2[] = {"rm", "-r", undel_file, undel_info, NULL}; 10: 752: ret = launch_execve(tmp_cmd2, FOREGROUND, E_NOFLAG); 10: 752-block 0 call 0 returned 10 -: 753: 10: 754: if (ret != EXIT_SUCCESS) { branch 0 taken 0 (fallthrough) branch 1 taken 10 #####: 755: fprintf(stderr, _("%s: undel: %s: Failed removing info file\n"), %%%%%: 755-block 0 call 0 never executed call 1 never executed -: 756: PROGRAM_NAME, undel_info); #####: 757: return EXIT_FAILURE; unconditional 0 never executed -: 758: } else { 10: 759: return EXIT_SUCCESS; 10: 759-block 0 unconditional 0 taken 10 -: 760: } -: 761: } else { #####: 762: fprintf(stderr, _("%s: undel: %s: Failed restoring trashed file\n"), %%%%%: 762-block 0 call 0 never executed call 1 never executed -: 763: PROGRAM_NAME, undel_file); #####: 764: return EXIT_FAILURE; unconditional 0 never executed -: 765: } -: 766: -: 767: return EXIT_FAILURE; /* Never reached */ -: 768:} -: 769: -: 770:int function untrash_function called 4 returned 100% blocks executed 54% 4: 771:untrash_function(char **comm) -: 772:{ 4: 773: if (xargs.stealth_mode == 1) { 4: 773-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 4 #####: 774: printf("%s: The trash function is disabled in stealth mode\n", %%%%%: 774-block 0 call 0 never executed -: 775: PROGRAM_NAME); #####: 776: return EXIT_SUCCESS; unconditional 0 never executed -: 777: } -: 778: 4: 779: if (!comm) 4: 779-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 4 #####: 780: return EXIT_FAILURE; %%%%%: 780-block 0 unconditional 0 never executed -: 781: 4: 782: if (!trash_ok) { 4: 782-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 4 #####: 783: fprintf(stderr, _("%s: Trash function disabled\n"), PROGRAM_NAME); %%%%%: 783-block 0 call 0 never executed call 1 never executed #####: 784: return EXIT_FAILURE; unconditional 0 never executed -: 785: } -: 786: -: 787: /* Change CWD to the trash directory to make scandir() work */ 4: 788: if (xchdir(trash_files_dir, NO_TITLE) == -1) { 4: 788-block 0 call 0 returned 4 branch 1 taken 0 (fallthrough) branch 2 taken 4 #####: 789: _err(0, NOPRINT_PROMPT, "%s: undel: '%s': %s\n", PROGRAM_NAME, call 0 never executed #####: 790: trash_files_dir, strerror(errno)); %%%%%: 790-block 0 call 0 never executed #####: 791: return EXIT_FAILURE; unconditional 0 never executed -: 792: } -: 793: -: 794: /* Get trashed files */ 4: 795: struct dirent **trash_files = (struct dirent **)NULL; 4*: 796: int trash_files_n = scandir(trash_files_dir, &trash_files, %%%%%: 796-block 0 unconditional 0 never executed %%%%%: 796-block 1 unconditional 1 never executed %%%%%: 796-block 2 unconditional 2 never executed 4: 796-block 3 unconditional 3 taken 4 4: 796-block 4 call 4 returned 4 4*: 797: skip_files, (unicode) ? alphasort : (case_sensitive) ? xalphasort 4: 797-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 4 %%%%%: 797-block 1 branch 2 never executed branch 3 never executed -: 798: : alphasort_insensitive); 4: 799: if (trash_files_n <= 0) { branch 0 taken 0 (fallthrough) branch 1 taken 4 #####: 800: puts(_("trash: There are no trashed files")); %%%%%: 800-block 0 call 0 never executed call 1 never executed -: 801: #####: 802: if (xchdir(ws[cur_ws].path, NO_TITLE) == -1) { call 0 never executed branch 1 never executed branch 2 never executed #####: 803: _err(0, NOPRINT_PROMPT, "%s: undel: '%s': %s\n", #####: 804: PROGRAM_NAME, ws[cur_ws].path, strerror(errno)); %%%%%: 804-block 0 call 0 never executed call 1 never executed #####: 805: return EXIT_FAILURE; unconditional 0 never executed -: 806: } -: 807: #####: 808: return EXIT_SUCCESS; %%%%%: 808-block 0 unconditional 0 never executed -: 809: } -: 810: 4: 811: int exit_status = EXIT_SUCCESS; -: 812: /* if "undel all" (or "u a" or "u *") */ 4*: 813: if (comm[1] && (strcmp(comm[1], "*") == 0 || strcmp(comm[1], "a") == 0 4: 813-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 2 2: 813-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 2 %%%%%: 813-block 2 branch 4 never executed branch 5 never executed #####: 814: || strcmp(comm[1], "all") == 0)) { %%%%%: 814-block 0 branch 0 never executed branch 1 never executed -: 815: size_t j; 10: 816: for (j = 0; j < (size_t)trash_files_n; j++) { 2: 816-block 0 unconditional 0 taken 2 10: 816-block 1 branch 1 taken 8 branch 2 taken 2 (fallthrough) 8: 817: if (untrash_element(trash_files[j]->d_name) != 0) 8: 817-block 0 call 0 returned 8 branch 1 taken 0 (fallthrough) branch 2 taken 8 #####: 818: exit_status = EXIT_FAILURE; %%%%%: 818-block 0 unconditional 0 never executed -: 819: 8: 820: free(trash_files[j]); 8: 820-block 0 unconditional 0 taken 8 -: 821: } -: 822: 2: 823: free(trash_files); -: 824: 2: 825: if (xchdir(ws[cur_ws].path, NO_TITLE) == -1) { 2: 825-block 0 call 0 returned 2 branch 1 taken 0 (fallthrough) branch 2 taken 2 #####: 826: _err(0, NOPRINT_PROMPT, "%s: undel: '%s': %s\n", #####: 827: PROGRAM_NAME, ws[cur_ws].path, strerror(errno)); %%%%%: 827-block 0 call 0 never executed call 1 never executed #####: 828: return EXIT_FAILURE; unconditional 0 never executed -: 829: } -: 830: 2: 831: return exit_status; 2: 831-block 0 unconditional 0 taken 2 -: 832: } -: 833: -: 834: /* List trashed files */ 2: 835: printf(_("%sTrashed files%s\n\n"), BOLD, df_c); 2: 835-block 0 call 0 returned 2 call 1 returned 2 -: 836: size_t i; -: 837: 4: 838: for (i = 0; i < (size_t)trash_files_n; i++) unconditional 0 taken 2 unconditional 1 taken 2 4: 838-block 0 branch 2 taken 2 branch 3 taken 2 (fallthrough) 2: 839: colors_list(trash_files[i]->d_name, (int)i + 1, NO_PAD, 2: 839-block 0 call 0 returned 2 -: 840: PRINT_NEWLINE); -: 841: -: 842: /* Go back to previous path */ 2: 843: if (xchdir(ws[cur_ws].path, NO_TITLE) == -1) { 2: 843-block 0 call 0 returned 2 branch 1 taken 0 (fallthrough) branch 2 taken 2 #####: 844: _err(0, NOPRINT_PROMPT, "%s: undel: '%s': %s\n", PROGRAM_NAME, #####: 845: ws[cur_ws].path, strerror(errno)); %%%%%: 845-block 0 call 0 never executed call 1 never executed #####: 846: return EXIT_FAILURE; unconditional 0 never executed -: 847: } -: 848: -: 849: /* Get user input */ 2: 850: printf(_("\n%sEnter 'q' to quit.\n"), df_c); 2: 850-block 0 call 0 returned 2 call 1 returned 2 2: 851: int undel_n = 0; 2: 852: char *line = (char *)NULL, **undel_elements = (char **)NULL; 4: 853: while (!line) unconditional 0 taken 2 4: 853-block 0 branch 1 taken 2 branch 2 taken 2 (fallthrough) 2: 854: line = rl_no_hist(_("File(s) to be undeleted (ex: 1 2-6, or *): ")); 2: 854-block 0 call 0 returned 2 call 1 returned 2 unconditional 2 taken 2 -: 855: 2: 856: undel_elements = get_substr(line, ' '); 2: 856-block 0 call 0 returned 2 2: 857: free(line); 2: 858: line = (char *)NULL; 2: 859: if (undel_elements) { branch 0 taken 2 (fallthrough) branch 1 taken 0 4: 860: for (i = 0; undel_elements[i]; i++) 2: 860-block 0 unconditional 0 taken 2 4: 860-block 1 branch 1 taken 2 branch 2 taken 2 2: 861: undel_n++; 2: 861-block 0 unconditional 0 taken 2 -: 862: } else { #####: 863: return EXIT_FAILURE; %%%%%: 863-block 0 unconditional 0 never executed -: 864: } -: 865: -: 866: /* First check for quit, *, and non-number args */ 2: 867: int free_and_return = 0; -: 868: 4: 869: for (i = 0; i < (size_t)undel_n; i++) { 2: 869-block 0 unconditional 0 taken 2 2: 869-block 1 unconditional 1 taken 2 4: 869-block 2 branch 2 taken 2 branch 3 taken 2 (fallthrough) 2: 870: if (strcmp(undel_elements[i], "q") == 0) { 2: 870-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 2 #####: 871: free_and_return = 1; %%%%%: 871-block 0 unconditional 0 never executed 2: 872: } else if (strcmp(undel_elements[i], "*") == 0) { 2: 872-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 2 -: 873: size_t j; -: 874: #####: 875: for (j = 0; j < (size_t)trash_files_n; j++) %%%%%: 875-block 0 unconditional 0 never executed %%%%%: 875-block 1 unconditional 1 never executed %%%%%: 875-block 2 branch 2 never executed branch 3 never executed #####: 876: if (untrash_element(trash_files[j]->d_name) != 0) %%%%%: 876-block 0 call 0 never executed branch 1 never executed branch 2 never executed #####: 877: exit_status = EXIT_FAILURE; %%%%%: 877-block 0 unconditional 0 never executed -: 878: #####: 879: free_and_return = 1; %%%%%: 879-block 0 unconditional 0 never executed 2: 880: } else if (!is_number(undel_elements[i])) { 2: 880-block 0 call 0 returned 2 branch 1 taken 0 (fallthrough) branch 2 taken 2 #####: 881: fprintf(stderr, _("undel: %s: Invalid ELN\n"), undel_elements[i]); %%%%%: 881-block 0 call 0 never executed call 1 never executed #####: 882: exit_status = EXIT_FAILURE; #####: 883: free_and_return = 1; unconditional 0 never executed -: 884: } -: 885: } -: 886: -: 887: /* Free and return if any of the above conditions is true */ 2: 888: if (free_and_return) { 2: 888-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 2 #####: 889: size_t j = 0; #####: 890: for (j = 0; j < (size_t)undel_n; j++) %%%%%: 890-block 0 unconditional 0 never executed %%%%%: 890-block 1 branch 1 never executed branch 2 never executed #####: 891: free(undel_elements[j]); %%%%%: 891-block 0 unconditional 0 never executed #####: 892: free(undel_elements); -: 893: #####: 894: for (j = 0; j < (size_t)trash_files_n; j++) %%%%%: 894-block 0 unconditional 0 never executed %%%%%: 894-block 1 branch 1 never executed branch 2 never executed #####: 895: free(trash_files[j]); %%%%%: 895-block 0 unconditional 0 never executed #####: 896: free(trash_files); -: 897: #####: 898: return exit_status; %%%%%: 898-block 0 unconditional 0 never executed -: 899: } -: 900: -: 901: /* Undelete trashed files */ 4: 902: for (i = 0; i < (size_t)undel_n; i++) { 2: 902-block 0 unconditional 0 taken 2 2: 902-block 1 unconditional 1 taken 2 4: 902-block 2 branch 2 taken 2 branch 3 taken 2 (fallthrough) 2: 903: int undel_num = atoi(undel_elements[i]); -: 904: 2*: 905: if (undel_num <= 0 || undel_num > trash_files_n) { 2: 905-block 0 branch 0 taken 2 (fallthrough) branch 1 taken 0 2: 905-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 2 #####: 906: fprintf(stderr, _("%s: undel: %d: Invalid ELN\n"), %%%%%: 906-block 0 call 0 never executed call 1 never executed -: 907: PROGRAM_NAME, undel_num); #####: 908: free(undel_elements[i]); #####: 909: continue; unconditional 0 never executed -: 910: } -: 911: -: 912: /* If valid ELN */ 2: 913: if (untrash_element(trash_files[undel_num - 1]->d_name) != 0) 2: 913-block 0 call 0 returned 2 branch 1 taken 0 (fallthrough) branch 2 taken 2 #####: 914: exit_status = EXIT_FAILURE; %%%%%: 914-block 0 unconditional 0 never executed 2: 915: free(undel_elements[i]); 2: 915-block 0 unconditional 0 taken 2 -: 916: } -: 917: 2: 918: free(undel_elements); -: 919: -: 920: /* Free trashed files list */ 4: 921: for (i = 0; i < (size_t)trash_files_n; i++) 2: 921-block 0 unconditional 0 taken 2 4: 921-block 1 branch 1 taken 2 branch 2 taken 2 (fallthrough) 2: 922: free(trash_files[i]); 2: 922-block 0 unconditional 0 taken 2 2: 923: free(trash_files); -: 924: -: 925: /* If some trashed file still remains, reload the undel screen */ 2: 926: trash_n = count_dir(trash_files_dir, NO_CPOP); 2: 926-block 0 call 0 returned 2 -: 927: 2: 928: if (trash_n <= 2) branch 0 taken 2 (fallthrough) branch 1 taken 0 2: 929: trash_n = 0; 2: 929-block 0 unconditional 0 taken 2 -: 930: 2: 931: if (trash_n) 2: 931-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 2 #####: 932: untrash_function(comm); %%%%%: 932-block 0 call 0 never executed unconditional 1 never executed -: 933: 2: 934: return exit_status; 2: 934-block 0 unconditional 0 taken 2 -: 935:} -: 936: -: 937:int function trash_function called 8 returned 100% blocks executed 56% 8: 938:trash_function(char **comm) -: 939:{ 8: 940: if (xargs.stealth_mode == 1) { 8: 940-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 8 #####: 941: printf("%s: The trash function is disabled in " %%%%%: 941-block 0 call 0 never executed -: 942: "stealth mode\n", PROGRAM_NAME); #####: 943: return EXIT_SUCCESS; unconditional 0 never executed -: 944: } -: 945: -: 946: /* Create trash dirs, if necessary */ -: 947: /* struct stat file_attrib; -: 948: if (stat (trash_dir, &file_attrib) == -1) { -: 949: char *trash_files = NULL; -: 950: trash_files = xcalloc(strlen(trash_dir) + 7, sizeof(char)); -: 951: sprintf(trash_files, "%s/files", trash_dir); -: 952: char *trash_info=NULL; -: 953: trash_info = xcalloc(strlen(trash_dir) + 6, sizeof(char)); -: 954: sprintf(trash_info, "%s/info", trash_dir); -: 955: char *cmd[] = { "mkdir", "-p", trash_files, trash_info, NULL }; -: 956: int ret = launch_execve (cmd, FOREGROUND, E_NOFLAG); -: 957: free(trash_files); -: 958: free(trash_info); -: 959: if (ret != EXIT_SUCCESS) { -: 960: _err(0, NOPRINT_PROMPT, _("%s: mkdir: '%s': Error creating " -: 961: "trash directory\n"), PROGRAM_NAME, trash_dir); -: 962: return; -: 963: } -: 964: } */ -: 965: 8: 966: if (!comm) 8: 966-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 8 #####: 967: return EXIT_FAILURE; %%%%%: 967-block 0 unconditional 0 never executed -: 968: 8: 969: if (!trash_ok || !config_ok) { 8: 969-block 0 branch 0 taken 8 (fallthrough) branch 1 taken 0 8: 969-block 1 branch 2 taken 0 (fallthrough) branch 3 taken 8 #####: 970: fprintf(stderr, _("%s: Trash function disabled\n"), PROGRAM_NAME); %%%%%: 970-block 0 call 0 never executed call 1 never executed #####: 971: return EXIT_FAILURE; unconditional 0 never executed -: 972: } -: 973: -: 974: /* List trashed files ('tr' or 'tr ls') */ 8: 975: if (!comm[1] || strcmp(comm[1], "ls") == 0 || strcmp(comm[1], "list") == 0) { 8: 975-block 0 branch 0 taken 7 (fallthrough) branch 1 taken 1 7: 975-block 1 branch 2 taken 6 (fallthrough) branch 3 taken 1 6: 975-block 2 branch 4 taken 0 (fallthrough) branch 5 taken 6 -: 976: /* List files in the Trash/files dir */ 2: 977: if (xchdir(trash_files_dir, NO_TITLE) == -1) { 2: 977-block 0 call 0 returned 2 branch 1 taken 0 (fallthrough) branch 2 taken 2 #####: 978: _err(0, NOPRINT_PROMPT, "%s: trash: %s: %s\n", call 0 never executed #####: 979: PROGRAM_NAME, trash_files_dir, strerror(errno)); %%%%%: 979-block 0 call 0 never executed #####: 980: return EXIT_FAILURE; unconditional 0 never executed -: 981: } -: 982: 2: 983: struct dirent **trash_files = (struct dirent **)NULL; 2*: 984: int files_n = scandir(trash_files_dir, &trash_files, %%%%%: 984-block 0 unconditional 0 never executed %%%%%: 984-block 1 unconditional 1 never executed %%%%%: 984-block 2 unconditional 2 never executed 2: 984-block 3 unconditional 3 taken 2 2: 984-block 4 call 4 returned 2 2: 985: skip_files, (unicode) ? alphasort : (case_sensitive) 2: 985-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 2 #####: 986: ? xalphasort : alphasort_insensitive); %%%%%: 986-block 0 branch 0 never executed branch 1 never executed 2: 987: if (files_n) { branch 0 taken 2 (fallthrough) branch 1 taken 0 -: 988: size_t i; 10: 989: for (i = 0; i < (size_t)files_n; i++) { 2: 989-block 0 unconditional 0 taken 2 10: 989-block 1 branch 1 taken 8 branch 2 taken 2 (fallthrough) 8: 990: colors_list(trash_files[i]->d_name, (int)i + 1, NO_PAD, 8: 990-block 0 call 0 returned 8 -: 991: PRINT_NEWLINE); 8: 992: free(trash_files[i]); unconditional 0 taken 8 -: 993: } -: 994: 2: 995: free(trash_files); 2: 995-block 0 unconditional 0 taken 2 -: 996: } else { #####: 997: puts(_("trash: There are no trashed files")); %%%%%: 997-block 0 call 0 never executed call 1 never executed unconditional 2 never executed -: 998: } -: 999: 2: 1000: if (xchdir(ws[cur_ws].path, NO_TITLE) == -1) { 2: 1000-block 0 call 0 returned 2 branch 1 taken 0 (fallthrough) branch 2 taken 2 #####: 1001: _err(0, NOPRINT_PROMPT, "%s: trash: '%s': %s\n", #####: 1002: PROGRAM_NAME, ws[cur_ws].path, strerror(errno)); %%%%%: 1002-block 0 call 0 never executed call 1 never executed #####: 1003: return EXIT_FAILURE; unconditional 0 never executed -: 1004: } else { 2: 1005: return EXIT_SUCCESS; 2: 1005-block 0 unconditional 0 taken 2 -: 1006: } -: 1007: } -: 1008: -: 1009: else { -: 1010: /* Create suffix from current date and time to create unique -: 1011: * file names for trashed files */ 6: 1012: int exit_status = EXIT_SUCCESS; 6: 1013: time_t rawtime = time(NULL); 6: 1013-block 0 call 0 returned 6 -: 1014: struct tm tm; 6: 1015: localtime_r(&rawtime, &tm); call 0 returned 6 6: 1016: char date[64] = ""; -: 1017: 6: 1018: strftime(date, sizeof(date), "%b %d %H:%M:%S %Y", &tm); -: 1019: 6: 1020: char suffix[68] = ""; -: 1021: 6: 1022: snprintf(suffix, 67, "%d%d%d%d%d%d", tm.tm_year + 1900, 6: 1023: tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, -: 1024: tm.tm_sec); -: 1025: -: 1026: /* Remove file(s) from Trash */ 6: 1027: if (strcmp(comm[1], "del") == 0 || strcmp(comm[1], "rm") == 0) { branch 0 taken 5 (fallthrough) branch 1 taken 1 5: 1027-block 0 branch 2 taken 0 (fallthrough) branch 3 taken 5 1: 1028: exit_status = remove_from_trash(); 1: 1028-block 0 call 0 returned 1 unconditional 1 taken 1 5: 1029: } else if (strcmp(comm[1], "clear") == 0) { 5: 1029-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 5 #####: 1030: trash_clear(); %%%%%: 1030-block 0 call 0 never executed unconditional 1 never executed -: 1031: } else { -: 1032: /* Trash files passed as arguments */ -: 1033: size_t i; 16: 1034: for (i = 1; comm[i]; i++) { 5: 1034-block 0 unconditional 0 taken 5 11: 1034-block 1 unconditional 1 taken 11 16: 1034-block 2 branch 2 taken 11 branch 3 taken 5 (fallthrough) 11: 1035: char *deq_file = dequote_str(comm[i], 0); 11: 1035-block 0 call 0 returned 11 11: 1036: char tmp_comm[PATH_MAX] = ""; -: 1037: 11: 1038: if (deq_file[0] == '/') { /* If absolute path */ branch 0 taken 4 (fallthrough) branch 1 taken 7 4: 1039: strcpy(tmp_comm, deq_file); 4: 1039-block 0 unconditional 0 taken 4 -: 1040: } else { /* If relative path, add path to check against -: 1041: TRASH_DIR */ 7: 1042: snprintf(tmp_comm, PATH_MAX, "%s/%s", ws[cur_ws].path, 7: 1042-block 0 unconditional 0 taken 7 -: 1043: deq_file); -: 1044: } -: 1045: -: 1046: /* Some filters: you cannot trash wathever you want */ -: 1047: /* Do not trash any of the parent directories of TRASH_DIR, -: 1048: * that is, /, /home, ~/, ~/.local, ~/.local/share */ 11*: 1049: if (strncmp(tmp_comm, trash_dir, strlen(tmp_comm)) == 0) { 11: 1049-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 11 #####: 1050: fprintf(stderr, _("trash: Cannot trash '%s'\n"), tmp_comm); %%%%%: 1050-block 0 call 0 never executed call 1 never executed #####: 1051: exit_status = EXIT_FAILURE; #####: 1052: free(deq_file); #####: 1053: continue; unconditional 0 never executed %%%%%: 1053-block 0 unconditional 1 never executed 11*: 1054: } else if (strncmp(tmp_comm, trash_dir, strlen(trash_dir)) == 0) { 11: 1054-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 11 -: 1055: /* Do no trash TRASH_DIR itself nor anything inside it, -: 1056: * that is, already trashed files */ #####: 1057: puts(_("trash: Use 'trash del' to remove trashed files")); %%%%%: 1057-block 0 call 0 never executed call 1 never executed #####: 1058: exit_status = EXIT_FAILURE; #####: 1059: free(deq_file); #####: 1060: continue; unconditional 0 never executed -: 1061: } -: 1062: -: 1063: struct stat file_attrib; 11*: 1064: if (lstat(deq_file, &file_attrib) == -1) { 11: 1064-block 0 call 0 returned 11 branch 1 taken 0 (fallthrough) branch 2 taken 11 #####: 1065: fprintf(stderr, _("trash: %s: %s\n"), deq_file, call 0 never executed call 1 never executed #####: 1066: strerror(errno)); %%%%%: 1066-block 0 call 0 never executed #####: 1067: exit_status = EXIT_FAILURE; #####: 1068: free(deq_file); #####: 1069: continue; unconditional 0 never executed -: 1070: } else { -: 1071: /* Do not trash block or character devices */ 11*: 1072: if ((file_attrib.st_mode & S_IFMT) == S_IFBLK) { 11: 1072-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 11 #####: 1073: fprintf(stderr, _("trash: %s: Cannot trash a " %%%%%: 1073-block 0 call 0 never executed call 1 never executed -: 1074: "block device\n"), deq_file); #####: 1075: exit_status = EXIT_FAILURE; #####: 1076: free(deq_file); #####: 1077: continue; unconditional 0 never executed 11*: 1078: } else if ((file_attrib.st_mode & S_IFMT) == S_IFCHR) { 11: 1078-block 0 branch 0 taken 0 (fallthrough) branch 1 taken 11 #####: 1079: fprintf(stderr, _("trash: %s: Cannot trash a " %%%%%: 1079-block 0 call 0 never executed call 1 never executed -: 1080: "character device\n"), deq_file); #####: 1081: exit_status = EXIT_FAILURE; #####: 1082: free(deq_file); #####: 1083: continue; unconditional 0 never executed -: 1084: } -: 1085: } -: 1086: -: 1087: /* Once here, everything is fine: trash the file */ 11: 1088: exit_status = trash_element(suffix, &tm, deq_file); 11: 1088-block 0 call 0 returned 11 -: 1089: /* The trash_element() function will take care of -: 1090: * printing error messages, if any */ 11: 1091: free(deq_file); unconditional 0 taken 11 -: 1092: } -: 1093: } -: 1094: 6: 1095: return exit_status; 6: 1095-block 0 unconditional 0 taken 6 -: 1096: } -: 1097:} -: 1098:#endif /* !_NO_TRASH */ -: 1099: clifm-1.26.3/misc/colors/000077500000000000000000000000001506632037700151425ustar00rootroot00000000000000clifm-1.26.3/misc/colors/aqua.clifm000066400000000000000000000150341506632037700171100ustar00rootroot00000000000000# Theme file for Clifm # Theme name: aqua # Author: L. Abramovich # License: GPL2+ define D=37 # Default define BD=1;2;37 # Bold dimmed default define R=31 # Red define BR=1;31 # Bold red define DR=2;31 # Dimmed red define UDR=4;02;31 # Underlined dimmed red define UBR=4;01;31 # Underlined bold red define G=32 # Green define BG=1;32 # Bold green define DG=2;32 # Dimmed green define Y=33 # Yellow define BY=1;33 # Bold yellow define DY=2;33 # Dimmed yellow define RY=7;33 # Reverse yellow define UDY=4;02;33 # Underlined dimmed yellow define BDY=1;02;33 # Bold dimmed yellow define B=34 # Blue define BB=1;34 # Bold blue define DB=2;34 # Dimmed blue define M=35 # Magenta define BM=1;35 # Bold Magenta define DM=2;35 # Dimmed magenta define UM=4;35 # Underlined magenta define RM=7;35 # Reverse magenta define C=36 # Cyan define BC=1;36 # Bold cyan define DC=2;36 # Dimmed cyan define UDC=4;02;36 # Underlined dimmed cyan define BDC=1;02;36 # Bold dimmed cyan define W=37 # White define DW=2;37 # Dimmed white define BDW=1;02;37 # Bold dimmed white define URW=4;31;47 # Red on white define UBW=4;34;47 # Blue on white define WR=37;41 # White on red define KR=30;41 # Black on red define KG=30;42 # Black on green define BGr=34;42 # Blue on green define WB=37;44 # White on blue define KC=30;46 # Black on cyan define ARCHIVE=1;31 # Bold red define AUDIO=36 # Cyan define CODE=1;37 # Bold white define DOC=35 # Magenta define EBOOK=31 # Red define IMAGE=1;35 # Bold magenta define TEMP=2;37 # Dimmed white define VIDEO=1;35 # Bold magenta FiletypeColors="bd=BB:ca=KR:cd=B:di=BC:ed=DC:ee=G:ef=DW:ex=BG:fi=W:ln=BY:mh=RY:nd=UBR:nf=:no=URW:or=UDY:ow=BGr:pi=RM:so=RM:su=WR:sg=KC:st=WB:tw=KG:uf=UBW:" InterfaceColors="ac=:df=D:dl=DW:db=B:dd=:de=C:dg=Y:dk=R:dn=DW:dr=Y:do=C:dp=M:dw=R:dxd=G:dxr=C:dz=:el=BDW:em=BR:fc=DC:hb=C:hc=DR:hd=C:he=C:hn=D:hp=C:hq=Y:hr=R:hs=G:hv=G:hw=R:lc=BY:li=BG:mi=BC:nm=BG:si=BB:sb=DY:sc=DR:sd=:sf=UDC:sh=:sp=DR:sx=DG:ti=BC:ts=UM:tt=BDC:tx=D:wc=BC:wm=BY:ws1=B:ws2=R:ws3=Y:ws4=G:ws5=C:ws6=C:ws7=C:ws8=C:xs=G:xf=BR:" ExtColors="*.7z=ARCHIVE:*.ace=ARCHIVE:*.alz=ARCHIVE:*.apk=ARCHIVE:*.arc=ARCHIVE:*.arj=ARCHIVE:*.bz=ARCHIVE:*.bz2=ARCHIVE:*.cab=ARCHIVE:*.cpio=ARCHIVE:*.deb=ARCHIVE:*.dmg=ARCHIVE:*.dwm=ARCHIVE:*.dz=ARCHIVE:*.ear=ARCHIVE:*.esd=ARCHIVE:*.gz=ARCHIVE:*.img=ARCHIVE:*.iso=ARCHIVE:*.jar=ARCHIVE:*.lha=ARCHIVE:*.lrz=ARCHIVE:*.lz=ARCHIVE:*.lz4=ARCHIVE:*.lzh=ARCHIVE:*.lzma=ARCHIVE:*.lzo=ARCHIVE:*.qcow=ARCHIVE:*.qcow2=ARCHIVE:*.rar=ARCHIVE:*.rpm=ARCHIVE:*.rz=ARCHIVE:*.sar=ARCHIVE:*.swm=ARCHIVE:*.t7z=ARCHIVE:*.tar=ARCHIVE:*.taz=ARCHIVE:*.tbz=ARCHIVE:*.tbz2=ARCHIVE:*.tgz=ARCHIVE:*.tlz=ARCHIVE:*.toast=ARCHIVE:*.txz=ARCHIVE:*.tz=ARCHIVE:*.tzo=ARCHIVE:*.tzst=ARCHIVE:*.vcd=ARCHIVE:*.vdi=ARCHIVE:*.vhd=ARCHIVE:*.vhdx=ARCHIVE:*.vmdk=ARCHIVE:*.vsix=ARCHIVE:*.war=ARCHIVE:*.wim=ARCHIVE:*.xz=ARCHIVE:*.z=ARCHIVE:*.zip=ARCHIVE:*.zoo=ARCHIVE:*.zst=ARCHIVE:*.aac=AUDIO:*.aif=AUDIO:*.aifc=AUDIO:*.aiff=AUDIO:*.alac=AUDIO:*.ape=AUDIO:*.au=AUDIO:*.flac=AUDIO:*.m4a=AUDIO:*.mid=AUDIO:*.midi=AUDIO:*.mka=AUDIO:*.mp3=AUDIO:*.ogg=AUDIO:*.opus=AUDIO:*.pcm=AUDIO:*.spx=AUDIO:*.wav=AUDIO:*.wma=AUDIO:*.wv=AUDIO:*.applescript=CODE:*.as=CODE:*.asa=CODE:*.awk=CODE:*.bash=CODE:*.c=CODE:*.c++=CODE:*.cabal=CODE:*.cc=CODE:*.cgi=CODE:*.clj=CODE:*.cp=CODE:*.cpp=CODE:*.cr=CODE:*.cs=CODE:*.csx=CODE:*.cxx=CODE:*.d=CODE:*.dart=CODE:*.def=CODE:*.di=CODE:*.dpr=CODE:*.el=CODE:*.elm=CODE:*.epp=CODE:*.erl=CODE:*.ex=CODE:*.exs=CODE:*.fish=CODE:*.fs=CODE:*.fsi=CODE:*.fsx=CODE:*.gd=CODE:*.go=CODE:*.gradle=CODE:*.groovy=CODE:*.gv=CODE:*.gvy=CODE:*.h=CODE:*.h++=CODE:*.hgrc=CODE:*.hh=CODE:*.hpp=CODE:*.hs=CODE:*.htc=CODE:*.hxx=CODE:*.inc=CODE:*.inl=CODE:*.ipp=CODE:*.ipynb=CODE:*.java=CODE:*.jl=CODE:*.js=CODE:*.jsx=CODE:*.kt=CODE:*.kts=CODE:*.lhs=CODE:*.lisp=CODE:*.ll=CODE:*.lua=CODE:*.m=CODE:*.matlab=CODE:*.mir=CODE:*.ml=CODE:*.mli=CODE:*.mn=CODE:*.nb=CODE:*.p=CODE:*.pas=CODE:*.php=CODE:*.pl=CODE:*.pm=CODE:*.pod=CODE:*.pp=CODE:*.pro=CODE:*.ps1=CODE:*.psd1=CODE:*.psm1=CODE:*.purs=CODE:*.py=CODE:*.r=CODE:*.rb=CODE:*.rs=CODE:*.sbt=CODE:*.scala=CODE:*.sh=CODE:*.swift=CODE:*.t=CODE:*.tcl=CODE:*.td=CODE:*.ts=CODE:*.tsx=CODE:*.vb=CODE:*.vsh=CODE:*.zig=CODE:*.zsh=CODE:*.abw=DOC:*.doc=DOC:*.docx=DOC:*.fodg:*.fodp=DOC:*.fods=DOC:*.fodt=DOC:*.odg=DOC:*.odp=DOC:*.ods=DOC:*.odt=DOC:*.pps=DOC:*.ppt=DOC:*.pptx=DOC:*.rtf=DOC:*.sxi=DOC:*.sxw=DOC:*.txt=DOC:*.xlr=DOC:*.xls=DOC:*.xlsx=DOC:*.azw=EBOOK:*.azw3=EBOOK:*.cb7=EBOOK:*.cba=EBOOK:*.cbr=EBOOK:*.cbt=EBOOK:*.cbz=EBOOK:*.djvu=EBOOK:*.epub=EBOOK:*.fb2=EBOOK:*.kf8=EBOOK:*.kfx=EBOOK:*.mobi=EBOOK:*.oxps=EBOOK:*.pdb=EBOOK:*.pdf=EBOOK:*.ps=EBOOK:*.xps=EBOOK:*.avif=IMAGE:*.bmp=IMAGE:*.gif=IMAGE:*.ico=IMAGE:*.jpeg=IMAGE:*.jpg=IMAGE:*.jxl=IMAGE:*.mjpeg=IMAGE:*.mjpg=IMAGE:*.mng=IMAGE:*.pbm=IMAGE:*.pcx=IMAGE:*.pgm=IMAGE:*.png=IMAGE:*.ppm=IMAGE:*.psd=IMAGE:*.svg=IMAGE:*.svgz=IMAGE:*.tga=IMAGE:*.tif=IMAGE:*.tiff=IMAGE:*.webp=IMAGE:*.xbm=IMAGE:*.xcf=IMAGE:*.xpm=IMAGE:*.css=MARKUP:*.htm=MARKUP:*.html=MARKUP:*.ltx=MARKUP:*.markdown=MARKUP:*.md=MARKUP:*.mdown=MARKUP:*.opf=MARKUP:*.rss=MARKUP:*.shtml=MARKUP:*.tex=MARKUP:*.xhtml=MARKUP:*.xml=MARKUP:*.aux=TEMP:*.bak=TEMP:*.bbl=TEMP:*.bc=TEMP:*.cache=TEMP:*.class=TEMP:*.git=TEMP:*.hi=TEMP:*.idx=TEMP:*.ilg=TEMP:*.ind=TEMP:*.la=TEMP:*.lo=TEMP:*.localized=TEMP:*.lock=TEMP:*.log=TEMP:*.o=TEMP:*.orig=TEMP:*.out=TEMP:*.pid=TEMP:*.pyc=TEMP:*.pyd=TEMP:*.pyo=TEMP:*.rej=TEMP:*.rlib=TEMP:*.sty=TEMP:*.swp=TEMP:*.tmp=TEMP:*.toc=TEMP:*.3gp=VIDEO:*.asf=VIDEO:*.avi=VIDEO:*.cgm=VIDEO:*.dl=VIDEO:*.emf=VIDEO:*.flc=VIDEO:*.fli=VIDEO:*.flv=VIDEO:*.h264=VIDEO:*.heics=VIDEO:*.gl=VIDEO:*.m2ts=VIDEO:*.m2v=VIDEO:*.m4v=VIDEO:*.mkv=VIDEO:*.mov=VIDEO:*.mp4=VIDEO:*.mp4v=VIDEO:*.mpeg=VIDEO:*.mpg=VIDEO:*.nuv=VIDEO:*.ogm=VIDEO:*.ogv=VIDEO:*.ogx=VIDEO:*.qt=VIDEO:*.rm=VIDEO:*.rmvb=VIDEO:*.vob=VIDEO:*.webm=VIDEO:*.wmv=VIDEO:*.xwd=VIDEO:*.yuv=VIDEO:" DateShades="1,31-2,37-1,37,37-2,36,36-2" SizeShades="1,31-2,36,32,33,31,35" DirIconColor="C" Prompt="\[\e[0;37m\][\S\[\e[0;37m\]]\l \A \u:\H \[\e[0;36m\]\w\n\[\e[0;37m\]<\z\[\e[0;37m\]> \[\e[0;34m\]\$ \[\e[0m\]" Notifications=true EnableWarningPrompt=true WarningPrompt="\[\e[0;1;31m\](!)\[\e[0;2m\] > " DividingLine="-" FzfTabOptions="--color='dark,prompt:6,fg+:-1,pointer:4,hl:5,hl+:5,gutter:-1,marker:2:bold,border:7:dim' --marker='*' --bind tab:accept,right:accept,left:abort,alt-p:toggle-preview,change:top,alt-up:preview-page-up,alt-down:preview-page-down --tiebreak=begin --inline-info --layout=reverse-list --preview-window=wrap,border-left" clifm-1.26.3/misc/colors/base16.clifm000066400000000000000000000135321506632037700172430ustar00rootroot00000000000000# Color scheme file for Clifm # Theme name: base16 # Author: L. Abramovich # License: GPL2+ define W=#d6d5d4 define BDW=#a5a2a2-1 define DW=#a5a2a2 define BB=#01a0e4-1 define DB=#01a0e4 define BB4=01;34 define R=#db2d20 define BR=#db2d20-1 define C=#b5e4e0 define BC=#b5e4e0-1 define DC=#b5e4e0-2 define C4=36 define Y=#fded02 define BY=#fded02-1 define DY=#a16a30 define BY4=1;33 define G=#01a252 define BG=#01a282-1 define BG4=1;32 define M=#a16a94 define P=#af87d7 define KC4=30;46 define KR=38;2;9;3;0;48;2;219;45;32 define KY=38;2;9;3;0;48;2;253;237;2 define RK=38;2;219;45;32;48;2;9;3;0 define RW=48;2;214;213;212;38;2;219;45;32 define BlGr=38;2;1;160;228;48;2;1;162;82 define WG=48;2;1;162;82 define WB=38;2;214;213;212;48;2;1;160;228 define WR=38;2;214;213;212;48;2;219;45;32 define DfGr=48;2;1;162;82 define ARCHIVE=#db2d20-1 define AUDIO=36 define CODE=#a5a2a2-1 define DOC=#fded02 define EBOOK=#db2d20 define IMAGE=#a16a94 define MARKUP=#a1b56c define TEMP=#a5a2a2 define VIDEO=#a16a94-1 FiletypeColors="bd=BY:ca=KR=WG:cd=BDW:di=BB:ed=DB:ee=G:ef=DW:ex=BG:fi=:ln=BC:mh=KC4:nd=BR:nf=:no=RW:or=C4:ow=BlGr:pi=M:sg=KY:so=DY:su=WR:st=WB:tw=DfGr:uf=RK:" InterfaceColors="ac=:db=Y:dc=W:dd=:de=C:df=W:dg=P:dk=R:dl=DB:dn=DW:do=C:dp=M:dr=Y:dw=R:dxd=G:dxr=C:dz=:el=DC:em=R:hb=C:hc=DR:hd=C:he=C:hn=D:hp=C:hq=Y:hr=R:hs=G:hv=G:lc=BC:li=BG4:mi=BC:nm=BG4:si=BB4:ti=BY4:tx=W:wc=C:wm=BY4:ws1=B:ws2=R:ws3=Y:ws4=G:ws5=C:ws6=M:ws7=DW:ws8=W:xf=R:xs=G:" ExtColors="*.7z=ARCHIVE:*.ace=ARCHIVE:*.alz=ARCHIVE:*.apk=ARCHIVE:*.arc=ARCHIVE:*.arj=ARCHIVE:*.bz=ARCHIVE:*.bz2=ARCHIVE:*.cab=ARCHIVE:*.cpio=ARCHIVE:*.deb=ARCHIVE:*.dmg=ARCHIVE:*.dwm=ARCHIVE:*.dz=ARCHIVE:*.ear=ARCHIVE:*.esd=ARCHIVE:*.gz=ARCHIVE:*.img=ARCHIVE:*.iso=ARCHIVE:*.jar=ARCHIVE:*.lha=ARCHIVE:*.lrz=ARCHIVE:*.lz=ARCHIVE:*.lz4=ARCHIVE:*.lzh=ARCHIVE:*.lzma=ARCHIVE:*.lzo=ARCHIVE:*.qcow=ARCHIVE:*.qcow2=ARCHIVE:*.rar=ARCHIVE:*.rpm=ARCHIVE:*.rz=ARCHIVE:*.sar=ARCHIVE:*.swm=ARCHIVE:*.t7z=ARCHIVE:*.tar=ARCHIVE:*.taz=ARCHIVE:*.tbz=ARCHIVE:*.tbz2=ARCHIVE:*.tgz=ARCHIVE:*.tlz=ARCHIVE:*.toast=ARCHIVE:*.txz=ARCHIVE:*.tz=ARCHIVE:*.tzo=ARCHIVE:*.tzst=ARCHIVE:*.vcd=ARCHIVE:*.vdi=ARCHIVE:*.vhd=ARCHIVE:*.vhdx=ARCHIVE:*.vmdk=ARCHIVE:*.vsix=ARCHIVE:*.war=ARCHIVE:*.wim=ARCHIVE:*.xz=ARCHIVE:*.z=ARCHIVE:*.zip=ARCHIVE:*.zoo=ARCHIVE:*.zst=ARCHIVE:*.aac=AUDIO:*.aif=AUDIO:*.aifc=AUDIO:*.aiff=AUDIO:*.alac=AUDIO:*.ape=AUDIO:*.au=AUDIO:*.flac=AUDIO:*.m4a=AUDIO:*.mid=AUDIO:*.midi=AUDIO:*.mka=AUDIO:*.mp3=AUDIO:*.ogg=AUDIO:*.opus=AUDIO:*.pcm=AUDIO:*.spx=AUDIO:*.wav=AUDIO:*.wma=AUDIO:*.wv=AUDIO:*.applescript=CODE:*.as=CODE:*.asa=CODE:*.awk=CODE:*.bash=CODE:*.c=CODE:*.c++=CODE:*.cabal=CODE:*.cc=CODE:*.cgi=CODE:*.clj=CODE:*.cp=CODE:*.cpp=CODE:*.cr=CODE:*.cs=CODE:*.csx=CODE:*.cxx=CODE:*.d=CODE:*.dart=CODE:*.def=CODE:*.di=CODE:*.dpr=CODE:*.el=CODE:*.elm=CODE:*.epp=CODE:*.erl=CODE:*.ex=CODE:*.exs=CODE:*.fish=CODE:*.fs=CODE:*.fsi=CODE:*.fsx=CODE:*.gd=CODE:*.go=CODE:*.gradle=CODE:*.groovy=CODE:*.gv=CODE:*.gvy=CODE:*.h=CODE:*.h++=CODE:*.hgrc=CODE:*.hh=CODE:*.hpp=CODE:*.hs=CODE:*.htc=CODE:*.hxx=CODE:*.inc=CODE:*.inl=CODE:*.ipp=CODE:*.ipynb=CODE:*.java=CODE:*.jl=CODE:*.js=CODE:*.jsx=CODE:*.kt=CODE:*.kts=CODE:*.lhs=CODE:*.lisp=CODE:*.ll=CODE:*.lua=CODE:*.m=CODE:*.matlab=CODE:*.mir=CODE:*.ml=CODE:*.mli=CODE:*.mn=CODE:*.nb=CODE:*.p=CODE:*.pas=CODE:*.php=CODE:*.pl=CODE:*.pm=CODE:*.pod=CODE:*.pp=CODE:*.pro=CODE:*.ps1=CODE:*.psd1=CODE:*.psm1=CODE:*.purs=CODE:*.py=CODE:*.r=CODE:*.rb=CODE:*.rs=CODE:*.sbt=CODE:*.scala=CODE:*.sh=CODE:*.swift=CODE:*.t=CODE:*.tcl=CODE:*.td=CODE:*.ts=CODE:*.tsx=CODE:*.vb=CODE:*.vsh=CODE:*.zig=CODE:*.zsh=CODE:*.abw=DOC:*.doc=DOC:*.docx=DOC:*.fodg:*.fodp=DOC:*.fods=DOC:*.fodt=DOC:*.odg=DOC:*.odp=DOC:*.ods=DOC:*.odt=DOC:*.pps=DOC:*.ppt=DOC:*.pptx=DOC:*.rtf=DOC:*.sxi=DOC:*.sxw=DOC:*.txt=DOC:*.xlr=DOC:*.xls=DOC:*.xlsx=DOC:*.azw=EBOOK:*.azw3=EBOOK:*.cb7=EBOOK:*.cba=EBOOK:*.cbr=EBOOK:*.cbt=EBOOK:*.cbz=EBOOK:*.djvu=EBOOK:*.epub=EBOOK:*.fb2=EBOOK:*.kf8=EBOOK:*.kfx=EBOOK:*.mobi=EBOOK:*.oxps=EBOOK:*.pdb=EBOOK:*.pdf=EBOOK:*.ps=EBOOK:*.xps=EBOOK:*.avif=IMAGE:*.bmp=IMAGE:*.gif=IMAGE:*.ico=IMAGE:*.jpeg=IMAGE:*.jpg=IMAGE:*.jxl=IMAGE:*.mjpeg=IMAGE:*.mjpg=IMAGE:*.mng=IMAGE:*.pbm=IMAGE:*.pcx=IMAGE:*.pgm=IMAGE:*.png=IMAGE:*.ppm=IMAGE:*.psd=IMAGE:*.svg=IMAGE:*.svgz=IMAGE:*.tga=IMAGE:*.tif=IMAGE:*.tiff=IMAGE:*.webp=IMAGE:*.xbm=IMAGE:*.xcf=IMAGE:*.xpm=IMAGE:*.css=MARKUP:*.htm=MARKUP:*.html=MARKUP:*.ltx=MARKUP:*.markdown=MARKUP:*.md=MARKUP:*.mdown=MARKUP:*.opf=MARKUP:*.rss=MARKUP:*.shtml=MARKUP:*.tex=MARKUP:*.xhtml=MARKUP:*.xml=MARKUP:*.aux=TEMP:*.bak=TEMP:*.bbl=TEMP:*.bc=TEMP:*.cache=TEMP:*.class=TEMP:*.git=TEMP:*.hi=TEMP:*.idx=TEMP:*.ilg=TEMP:*.ind=TEMP:*.la=TEMP:*.lo=TEMP:*.localized=TEMP:*.lock=TEMP:*.log=TEMP:*.o=TEMP:*.orig=TEMP:*.out=TEMP:*.pid=TEMP:*.pyc=TEMP:*.pyd=TEMP:*.pyo=TEMP:*.rej=TEMP:*.rlib=TEMP:*.sty=TEMP:*.swp=TEMP:*.tmp=TEMP:*.toc=TEMP:*.3gp=VIDEO:*.asf=VIDEO:*.avi=VIDEO:*.cgm=VIDEO:*.dl=VIDEO:*.emf=VIDEO:*.flc=VIDEO:*.fli=VIDEO:*.flv=VIDEO:*.h264=VIDEO:*.heics=VIDEO:*.gl=VIDEO:*.m2ts=VIDEO:*.m2v=VIDEO:*.m4v=VIDEO:*.mkv=VIDEO:*.mov=VIDEO:*.mp4=VIDEO:*.mp4v=VIDEO:*.mpeg=VIDEO:*.mpg=VIDEO:*.nuv=VIDEO:*.ogm=VIDEO:*.ogv=VIDEO:*.ogx=VIDEO:*.qt=VIDEO:*.rm=VIDEO:*.rmvb=VIDEO:*.vob=VIDEO:*.webm=VIDEO:*.wmv=VIDEO:*.xwd=VIDEO:*.yuv=VIDEO:" DirIconColor="Y" SizeShades="3,#db2d20-2,#b5e4e0,#01a252,#fded02,#bd5187" Prompt="\[\e[00;38;2;214;213;212m\][\S\[\e[00;38;2;214;213;212m\]]\l \A \u:\H \[\e[01;38;2;1;162;82m\]\w\n\[\e[00;38;2;214;213;212m\]<\z\[\e[00;38;2;214;213;212m\]> \[\e[01;38;2;1;160;228m\]\$ \[\e[00;38;2;214;213;212m\]" Notifications=true EnableWarningPrompt=true WarningPrompt="\[\e[0;1;38;2;219;45;32m\](!)\[\e[0;2m\] > " DividingLine="-" FzfTabOptions="--color='dark,prompt:6,fg+:-1,pointer:4,hl:2,hl+:2,gutter:-1,marker:2:bold,border:8' --marker='*' --bind tab:accept,right:accept,left:abort,alt-p:toggle-preview,change:top,alt-up:preview-page-up,alt-down:preview-page-down --tiebreak=begin --inline-info --layout=reverse-list --preview-window=wrap,border-left" clifm-1.26.3/misc/colors/default-256.clifm000066400000000000000000000443321506632037700201220ustar00rootroot00000000000000# Theme file for Clifm # Theme name: clifm (256 colors version) # Author: L. Abramovich # License: GPL2+ ### How do we define colors? # # The FiletypeColors, InterfaceColors, and ExtColors options take SGR sequences # (excluding the initial escape character and the ending 'm') as color values, # just like the LS_COLORS environment variable. However, shortcuts for 8-bit # (256-colors) and 24-bit (true color) colors are available. For example: # # 31 4-bit # 38;5;160 8-bit # @160 8-bit (short) # 38;2;255;0;0 24-bit # #ff0000 24-bit (short, HEX) # # A single attribute can be added to hex colors, and 256 colors (in the form @NUM), # using a dash and an attribute number (#RRGGBB-[1-9] or @NUM-[1-9]), where 1-9 is: # # 1: Bold or increased intensity # 2: Faint, decreased intensity or dim # 3: Italic (not widely supported) # 4: Underline # 5: Slow blink # 6: Rapid blink # 7: Reverse video or invert # 8: Conceal or hide (not widely supported) # 9: Crossed-out or strike # # For example, for bold red the hex code is #ff0000-1, while the 256-colors code # is @160-1. # # Note: For more information about SGR sequences consult # https://en.wikipedia.org/wiki/ANSI_escape_code ### Use some variables to hold your color codes # # The 'define' keyword allows you to define up to 128 custom color variables. # They can be used for: # FiletypeColors # InterfaceColors # ExtColors # DirIconColor # # For example; # # define BOLD_CYAN=@6-1 # el=BOLD_CYAN # # Here we define 'BOLD_CYAN' as "@6-1", and then we use this color for ELNs, # whose code is 'el' (see below). ### Xterm-like color names are also supported. For example, let's use DarkSeaGreen1 # for ELNs: # # el=DarkSeaGreen1 # # Or, as a definition: # # define Green=DarkSeaGreen1 # el=Green # # Just as with hex colors, a single attribute can be added to color names. # For example, 'DarkSeaGreen1-1' to get the bold version of this color. # # For the complete list of color names consult the manpage. ## Edit the value of the below defintions to change colors. For example, to change # the color of directories to bold red: 'define FTYPE_DIR=@1-1'. #=====================================# # FILE TYPES # #=====================================# define FTYPE_DIR=@4-1 # Directory define FTYPE_EMPTY_DIR=@4-2 # Empty directory define FTYPE_DIR_NO_PERM=@1-1 # Directory with no read permission (1) define FTYPE_REG=0 # Regular file define FTYPE_EMPTY_REG=2 # Empty regular file define FTYPE_REG_NO_PERM= # Regular file with no read permission (1) define FTYPE_EXEC=@2-1 # Executable file define FTYPE_EMPTY_EXEC=@2 # Empty executable file define FTYPE_LINK=@6-1 # Symbolic link define FTYPE_BROKEN_LINK=4;2;36 # Broken symbolic link define FTYPE_MULTI_HLINK=@6-7 # Multi-hardlink file define FTYPE_BLK_DEV=@5-1 # Block device define FTYPE_CHR_DEV=@5 # Char device define FTYPE_FIFO=38;5;5;48;5;238 # FIFO/pipe define FTYPE_SOCK=1;38;5;5;48;5;238 # Socket define FTYPE_CAP=30;41 # File with capabilities define FTYPE_DOOR=@5 # Door (Solaris only) define FTYPE_SUID=37;41 # SUID file define FTYPE_SGID=30;43 # SGID file define FTYPE_OW=48;5;235;38;5;33 # Other-writable define FTYPE_STICKY_NOT_OW=37;44 # Sticky (not other-writable) define FTYPE_STICKY_OW=37;42 # Sticky and other-writable define FTYPE_UNKNOWN=4;31;47 # Unknown file type define FTYPE_NON_STAT=4;2;37 # Non-stat'able file # (1) If unset, the corresponding file type color is used and an # exclamation mark is printed before the file name in the files list # (provided icons are disabled -otherwise the lock icon is used- and # clifm is not running in light mode -in light mode access checks are # not performed). The color used for the exclamation mark is # PROMPT_EXIT_FAILURE (see below). #=====================================# # PROPERTIES / LONG VIEW # #=====================================# define PROP_READ=@228 # Read bit define PROP_WRITE=@197 # Write bit define PROP_EXEC_DIR=@77 # Execute bit (directories) define PROP_EXEC_FILE=@79 # Execute bit (files) define PROP_SPECIAL=@140 # SUID/SGID bit define PROP_UID=@5 # User ID define PROP_GID=@5-2 # Group ID define PROP_SIZE= # Size (1) define PROP_DATE= # Date (1) define PROP_BLKS=@214 # Used blocks define PROP_INODE=@79 # Inode number define PROP_LINKS=@197 # Number of file links define PROP_OCTAL_PERM=@79 # Permissions in octal define PROP_DASH=@242 # Dot separator and dash (unset bit) define PROP_TIME_MARK= # Timestamp identification character (2) # (1) If unset (default), color shades are used instead. # See DateShades and SizeShades below. # (2) If unset (default), a dimmed version of the current timestamp color is used. #=====================================# # INTERFACE # #=====================================# define IFACE_ELN=@6 # ELNs (e.g. "12 myfile") define IFACE_FILES_COUNTER=@247 # Files counter (e.g. "dir/12") define IFACE_DIV_LINE=@243 # Dividing line define IFACE_LINK_IND=@43 # Symbolic link indicator ('@') define IFACE_MISC_IND=@6-1 # Miscellaneous indicator ("->") define IFACE_TABCOMP_PREFIX=@5-4 # Matching prefix (tab completion) define IFACE_WELCOME_MSG=@6-1 # Welcome message define IFACE_TRUNC_CHAR=1;2;36 # Character used to mark truncated filenames ('~') define IFACE_DEF_COLOR=0 # Default color #=====================================# # PROMPT # #=====================================# define PROMPT_TEXT=0 # Command line text color define PROMPT_SEL=@2-1 # Selected files indicator define PROMPT_TRASH=@6-1 # Trashed files indicator define PROMPT_NOTICE=@2-1 # Notice message indicator define PROMPT_WARNING=@228 # Warning message indicator define PROMPT_ERR=@1-1 # Error message indicator define PROMPT_AUTOCMD=@247 # Autocommand notification define PROMPT_READ_ONLY=@4-1 # Read-only indicator define PROMPT_STEALTH=@4-1 # Stealth mode indicator define PROMPT_EXIT_SUCCESS=@2 # Success exit code define PROMPT_EXIT_FAILURE=@1-1 # Error exit code #=====================================# # WORKSPACE NUMBER/NAME # #=====================================# define WORKSPACE_1=@4 define WORKSPACE_2=@1 define WORKSPACE_3=@228 define WORKSPACE_4=@2 define WORKSPACE_5=@43 define WORKSPACE_6=@214 define WORKSPACE_7=@5 define WORKSPACE_8=@246-2 #=====================================# # SUGGESTIONS # #=====================================# define SUG_HIST=@240 # History define SUG_FILE_NAME=4;2;36 # File names define SUG_FILE_NAME_FUZZY=4;2;36 # File names (fuzzy) define SUG_INT_CMD=@2-2 # Internal command names and parameters define SUG_EXT_CMD=@6-2 # External command names define SUG_BUILTIN=@3-2 # Shell builtin names define SUG_INT_CMD_DESC=@240 # Internal commands description (e.g. "c (copy files)") define SUG_POINTER=@239 # Suggestions pointer (e.g. "12 > myfile") #=====================================# # SYNTAX HIGHLIGHTING # #=====================================# define HL_BRACKET=@6 # Brackets: () [] {} define HL_COMMENT=@7-2 # Commented out text (starting with '#') define HL_SLASH=@6 # Slash define HL_EXPANSION=@6 # Expansion characters: * ~ define HL_NUMBER= # Number define HL_PARAM=@6 # Command parameters (e.g. "echo '-e'") define HL_QUOTE=@185 # Quoted text (single and double quotes) define HL_REDIRECT=@1 # Redirection characters: > < define HL_PROC_SEP=@2 # Process separators: | & ; define HL_VAR=@2 # Variable names: $FOO define HL_WHACK=@1 # Backslash (aka whack) # NOTE: Exception made of PROP_SIZE and PROP_DATE, whenever a value is unset, # the default value is used. To force it to use no color, set its value to zero. # Example: # define VAR=0 ### Colors used for file names when listing files FiletypeColors="bd=FTYPE_BLK_DEV:ca=FTYPE_CAP:cd=FTYPE_CHR_DEV:di=FTYPE_DIR:ed=FTYPE_EMPTY_DIR:ee=FTYPE_EMPTY_EXEC:ef=FTYPE_EMPTY_REG:ex=FTYPE_EXEC:fi=FTYPE_REG:ln=FTYPE_LINK:mh=FTYPE_MULTI_HLINK:nd=FTYPE_DIR_NO_PERM:nf=FTYPE_REG_NO_PERM:no=FTYPE_UNKNOWN:oo=FTYPE_DOOR:or=FTYPE_BROKEN_LINK:ow=FTYPE_OW:pi=FTYPE_FIFO:sg=FTYPE_SGID:so=FTYPE_SOCK:st=FTYPE_STICKY_NOT_OW:su=FTYPE_SUID:tw=FTYPE_STICKY_OW:uf=FTYPE_NON_STAT:" ### Colors for Clifm's interface elements InterfaceColors="ac=PROMPT_AUTOCMD:db=PROP_BLKS:dd=PROP_DATE:de=PROP_INODE:df=IFACE_DEF_COLOR:dg=PROP_GID:dk=PROP_LINKS:dl=IFACE_DIV_LINE:dn=PROP_DASH:do=PROP_OCTAL_PERM:dp=PROP_SPECIAL:dr=PROP_READ:dt=PROP_TIME_MARK:du=PROP_UID:dw=PROP_WRITE:dxd=PROP_EXEC_DIR:dxr=PROP_EXEC_FILE:dz=PROP_SIZE:el=IFACE_ELN:em=PROMPT_ERR:fc=IFACE_FILES_COUNTER:hb=HL_BRACKET:hc=HL_COMMENT:hd=HL_SLASH:he=HL_EXPANSION:hn=HL_NUMBER:hp=HL_PARAM:hq=HL_QUOTE:hr=HL_REDIRECT:hs=HL_PROC_SEP:hv=HL_VAR:hw=HL_WHACK:lc=IFACE_LINK_IND:li=PROMPT_SEL:mi=IFACE_MISC_IND:nm=PROMPT_NOTICE:ro=PROMPT_READ_ONLY:si=PROMPT_STEALTH:sb=SUG_BUILTIN:sc=SUG_EXT_CMD:sd=SUG_INT_CMD_DESC:sf=SUG_FILE_NAME:sh=SUG_HIST:sp=SUG_POINTER:sx=SUG_INT_CMD:sz=SUG_FILE_NAME_FUZZY:ti=PROMPT_TRASH:ts=IFACE_TABCOMP_PREFIX:tt=IFACE_TRUNC_CHAR:tx=PROMPT_TEXT:wc=IFACE_WELCOME_MSG:wm=PROMPT_WARNING:ws1=WORKSPACE_1:ws2=WORKSPACE_2:ws3=WORKSPACE_3:ws4=WORKSPACE_4:ws5=WORKSPACE_5:ws6=WORKSPACE_6:ws7=WORKSPACE_7:ws8=WORKSPACE_8:xf=PROMPT_EXIT_FAILURE:xs=PROMPT_EXIT_SUCCESS:" #=====================================# # FILE EXTENSIONS # #=====================================# # NOTE: ExtColors can be used multiple times. # ARCHIVES define ARCHIVE=@1-1 ExtColors="7z=ARCHIVE:ace=ARCHIVE:alz=ARCHIVE:apk=ARCHIVE:arc=ARCHIVE:arj=ARCHIVE:bz=ARCHIVE:bz2=ARCHIVE:cab=ARCHIVE:cpio=ARCHIVE:deb=ARCHIVE:dmg=ARCHIVE:dwm=ARCHIVE:dz=ARCHIVE:ear=ARCHIVE:esd=ARCHIVE:gz=ARCHIVE:img=ARCHIVE:iso=ARCHIVE:jar=ARCHIVE:lha=ARCHIVE:lrz=ARCHIVE:lz=ARCHIVE:lz4=ARCHIVE:lzh=ARCHIVE:lzma=ARCHIVE:lzo=ARCHIVE:qcow=ARCHIVE:qcow2=ARCHIVE:rar=ARCHIVE:rpm=ARCHIVE:rz=ARCHIVE:sar=ARCHIVE:swm=ARCHIVE:t7z=ARCHIVE:tar=ARCHIVE:taz=ARCHIVE:tbz=ARCHIVE:tbz2=ARCHIVE:tgz=ARCHIVE:tlz=ARCHIVE:toast=ARCHIVE:txz=ARCHIVE:tz=ARCHIVE:tzo=ARCHIVE:tzst=ARCHIVE:vcd=ARCHIVE:vdi=ARCHIVE:vhd=ARCHIVE:vhdx=ARCHIVE:vmdk=ARCHIVE:vsix=ARCHIVE:war=ARCHIVE:wim=ARCHIVE:xz=ARCHIVE:z=ARCHIVE:zip=ARCHIVE:zoo=ARCHIVE:zst=ARCHIVE:" # AUDIO FILES define AUDIO=@214 ExtColors="aac=AUDIO:ac3=AUDIO:anx=AUDIO:au=AUDIO:axa=AUDIO:cue=AUDIO:m2a=AUDIO:m4a=AUDIO:mid=AUDIO:midi=AUDIO:mka=AUDIO:mp2=AUDIO:mp3=AUDIO:mpc=AUDIO:mpga=AUDIO:oga=AUDIO:ogg=AUDIO:ogx=AUDIO:opus=AUDIO:ra=AUDIO:ram=AUDIO:snd=AUDIO:spx=AUDIO:wma=AUDIO:" # LOSSLESS AUDIO define LAUDIO=@214-1 ExtColors="aif=LAUDIO:aifc=LAUDIO:aiff=LAUDIO:alac=LAUDIO:ape=LAUDIO:flac=LAUDIO:pcm=LAUDIO:wav=LAUDIO:wm=LAUDIO:wv=LAUDIO:" # SOURCE FILES define CODE=@247-1 ExtColors="applescript=CODE:asm=CODE:awk=CODE:bash=CODE:bat=CODE:c=CODE:c++=CODE:cabal=CODE:cc=CODE:cgi=CODE:clj=CODE:cp=CODE:cpp=CODE:cs=CODE:csx=CODE:cxx=CODE:d=CODE:dart=CODE:di=CODE:dpr=CODE:el=CODE:elm=CODE:erl=CODE:ex=CODE:exs=CODE:f=CODE:f90=CODE:fish=CODE:for=CODE:fs=CODE:fsi=CODE:fsx=CODE:gd=CODE:gleam=CODE:go=CODE:gradle=CODE:groovy=CODE:gv=CODE:gvy=CODE:h=CODE:h++=CODE:hh=CODE:hpp=CODE:hs=CODE:hxx=CODE:inc=CODE:inl=CODE:ipp=CODE:ipynb=CODE:java=CODE:jl=CODE:js=CODE:jsx=CODE:kt=CODE:kts=CODE:lhs=CODE:lisp=CODE:lua=CODE:m=CODE:mat=CODE:ml=CODE:mli=CODE:p=CODE:pas=CODE:php=CODE:pl=CODE:pm=CODE:pp=CODE:pro=CODE:ps1=CODE:psd1=CODE:psm1=CODE:purs=CODE:py=CODE:r=CODE:rb=CODE:rs=CODE:scala=CODE:sh=CODE:swift=CODE:t=CODE:tcl=CODE:tsx=CODE:vb=CODE:zig=CODE:zsh=CODE:" # COMPILER OUTPUT FILES define COMP=33 ExtColors="a=COMP:bundle=COMP:class=COMP:cma=COMP:cmi=COMP:cmo=COMP:cmx=COMP:dll=COMP:dylib=COMP:elc=COMP:ko=COMP:lib=COMP:o=COMP:obj=COMP:pyc=COMP:pyd=COMP:pyo=COMP:so=COMP:zwc=COMP:" # CONFIG FILES define CONFIG=@44 ExtColors="cfg=CONFIG:clifm=CONFIG:conf=CONFIG:desktop=CONFIG:hjson=CONFIG:ini=CONFIG:json=CONFIG:list=CONFIG:rc=CONFIG:tml=CONFIG:toml=CONFIG:yaml=CONFIG:yml=CONFIG:" # DOCUMENTS define DOC=@228 ExtColors="abw=DOC:chm=DOC:csv=DOC:doc=DOC:docm=DOC:docx=DOC:eml=DOC:fodg=DOC:fodp=DOC:fods=DOC:fodt=DOC:gdoc=DOC:key=DOC:keynote=DOC:numbers=DOC:odg=DOC:odp=DOC:ods=DOC:odt=DOC:pages=DOC:pps=DOC:ppt=DOC:pptm=DOC:pptx=DOC:rtf=DOC:sla=DOC:sxi=DOC:sxw=DOC:txt=DOC:xlr=DOC:xls=DOC:xlsm=DOC:xlsx=DOC:" # EBOOKS define EBOOK=@223 ExtColors="azw=EBOOK:azw3=EBOOK:cb7=EBOOK:cba=EBOOK:cbr=EBOOK:cbt=EBOOK:cbz=EBOOK:djv=EBOOK:djvu=EBOOK:epub=EBOOK:fb2=EBOOK:kf8=EBOOK:kfx=EBOOK:mobi=EBOOK:oxps=EBOOK:pdb=EBOOK:pdf=EBOOK:ps=EBOOK:xps=EBOOK:" # IMAGES define IMAGE=@141 ExtColors="ai=IMAGE:avif=IMAGE:bmp=IMAGE:dpx=IMAGE:dvi=IMAGE:eps=IMAGE:exr=IMAGE:ff=IMAGE:fit=IMAGE:fts=IMAGE:hdr=IMAGE:heic=IMAGE:heif=IMAGE:gif=IMAGE:ico=IMAGE:j2c=IMAGE:j2k=IMAGE:jfi=IMAGE:jfif=IMAGE:jif=IMAGE:jp2=IMAGE:jpe=IMAGE:jpeg=IMAGE:jpf=IMAGE:jpg=IMAGE:jps=IMAGE:jpx=IMAGE:jxl=IMAGE:kra=IMAGE:miff=IMAGE:mng=IMAGE:ora=IMAGE:pam=IMAGE:pbm=IMAGE:pcx=IMAGE:pdd=IMAGE:pgm=IMAGE:pict=IMAGE:png=IMAGE:pnm=IMAGE:ppm=IMAGE:psd=IMAGE:pxm=IMAGE:qoi=IMAGE:rgba=IMAGE:sgi=IMAGE:svg=IMAGE:svgz=IMAGE:tga=IMAGE:tif=IMAGE:tiff=IMAGE:webp=IMAGE:wmf=IMAGE:xbm=IMAGE:xcf=IMAGE:xpm=IMAGE:xwd=IMAGE:" # RAW IMAGES # There are plenty of raw image formats out there. This is an incomplete list taken from "https://en.wikipedia.org/wiki/Raw_image_format". # Uncomment to enable. #define RAW=@141 #ExtColors="3fr=RAW:ari=RAW:arw=RAW:bay=RAW:braw=RAW:crw=RAW:cr2=RAW:cr3=RAW:cap=RAW:data=RAW:dcs=RAW:dcr=RAW:dng=RAW:drf=RAW:eip=RAW:erf=RAW:fff=RAW:gpr=RAW:iiq=RAW:k25=RAW:kdc=RAW:mdc=RAW:mef=RAW:mos=RAW:mrw=RAW:nef=RAW:nrw=RAW:obm=RAW:orf=RAW:pef=RAW:ptx=RAW:pxn=RAW:r3d=RAW:raf=RAW:raw=RAW:rwl=RAW:rw2=RAW:rwz=RAW:sr2=RAW:srf=RAW:srw=RAW:x3f=RAW:" # VIDEO FILES define VIDEO=@141-1 ExtColors="3gp=VIDEO:asf=VIDEO:avi=VIDEO:cgm=VIDEO:dl=VIDEO:flc=VIDEO:fli=VIDEO:flv=VIDEO:h264=VIDEO:heics=VIDEO:gl=VIDEO:m2ts=VIDEO:m2v=VIDEO:m4v=VIDEO:mkv=VIDEO:mov=VIDEO:mp4=VIDEO:mp4v=VIDEO:mpeg=VIDEO:mpg=VIDEO:nuv=VIDEO:ogm=VIDEO:ogv=VIDEO:qt=VIDEO:rm=VIDEO:rmvb=VIDEO:vob=VIDEO:webm=VIDEO:wmv=VIDEO:yuv=VIDEO:" # MARKUP FILES define MARKUP=@85 ExtColors="css=MARKUP:htm=MARKUP:html=MARKUP:ltx=MARKUP:markdown=MARKUP:md=MARKUP:mdown=MARKUP:opf=MARKUP:rss=MARKUP:sass=MARKUP:scss=MARKUP:sgml=MARKUP:shtml=MARKUP:tex=MARKUP:xbel=MARKUP:xhtml=MARKUP:xml=MARKUP:xsd=MARKUP:xslt=MARKUP:" # TEMPORARY FILES define TEMP=@247 ExtColors="$$$=TEMP:aux=TEMP:bak=TEMP:bbl=TEMP:bc=TEMP:bk=TEMP:bkp=TEMP:cache=TEMP:git=TEMP:hi=TEMP:idx=TEMP:ilg=TEMP:ind=TEMP:la=TEMP:lo=TEMP:localized=TEMP:lock=TEMP:log=TEMP:orig=TEMP:pid=TEMP:rej=TEMP:rlib=TEMP:swp=TEMP:tmp=TEMP:toc=TEMP:" # DATABASES define DB=@211 ExtColors="cdx=DB:dat=DB:db=DB:dbf=DB:dbi=DB:dbx=DB:fox=DB:mdb=DB:mdn=DB:mdx=DB:msql=DB:mssql=DB:pgsql=DB:sql=DB:sqlite=DB:ssql=DB:" #=====================================# # COLOR SHADES # #=====================================# ### TIMESTAMPS ### # The format is: "COLOR-TYPE,ERROR,SHADE1,SHADE2,SHADE3,SHADE4,SHADE5" # # COLOR-TYPE is one of: 1 (4-bit: 8 colors), 2 (8-bit: 256 colors), 3 (24-bit: truecolor) # ERROR is the color used to print bad values # SHADEn is the color used for the shade N # # The meaning of each date shade is (in order, excluding COLOR-TYPE and ERROR): # hour, day, weak, month, older # # For 4-bit colors (1), valid colors are in the range 30-37 # For 8-bit colors (2), valid colors are in the range 0-255 # For 24-bit colors (3), valid colors have this format: #RRGGBB # # An attribute (0-9) can be added to any color (either ERROR or SHADE) using a dash. # For example: # "34-1" -> "bold blue" (4-bit colors notation) # "226-2" -> "dimmed yellow" (8-bit colors notation) # "#ffaff00-4" -> "underlined orange" (24-bit colors notation) #DateShades="1,31-2,36-1,36,36-2,36-2,36-2" DateShades="2,197-2,231,253,250,247,244" #DateShades="3,#ff005f-2,#ffffff,#dadada,#bcbcbc,#9e9e9e,#808080" ### FILE SIZES ### # The meaning of each size shade is (in order, excluding COLOR-TYPE and ERROR): # byte, Kb, Mb, Gb, bigger #SizeShades="1,31-2,32,33,31,31,31" SizeShades="2,197-2,79,77,228,215,203" #SizeShades="3,#ff005f-2,#5fd7af,#5fd75f,#ffff87,#ffaf5f,#ff5f5f" ### If icons are enabled, use this color for directories icon (only for icons-in-terminal and Nerd-fonts) DirIconColor="Y" #=====================================# # PROMPT STYLE # #=====================================# ### The prompt used by Clifm. Use the 'prompt' command to check for available # prompts. Enter 'prompt --help' for more information. # You can use here either prompt codes (see the prompts.clifm file for details) # or a prompt name defined in the prompts file. Prompt="clifm" # Override prompt values (as defined in the prompts file). #Prompt="" #Notifications= #RightPrompt="" #EnableWarningPrompt= #WarningPrompt="" ### The string used to construct the line dividing the list of files and # the prompt (Unicode is supported). Possible values: # "0": Print an empty line. # "C": C is a single character. This character will be printed up to the end of # the screen. # "CC": 2 or more characters. Only these characters (and no more) will be printed. # "": Print a special line drawn with box-drawing characters (not supported by # all terminals/consoles). # The color of this line is controlled by the 'dl' code in InterfaceColors. DividingLine="-" #=====================================# # FZF # #=====================================# ### If the fzf tab completion mode is enabled, pass these options to fzf: FzfTabOptions="--color='16,prompt:6,fg+:-1,pointer:4,hl:2,hl+:2,gutter:-1,marker:2,border:7:dim' --marker='*' --bind tab:accept,right:accept,left:abort,alt-p:toggle-preview,change:top,alt-up:preview-page-up,alt-down:preview-page-down --tiebreak=begin --inline-info --layout=reverse-list --preview-window=wrap,border-left" # Same options, but colorless #FzfTabOptions="--color='bw' --marker='*' --bind tab:accept,right:accept,left:abort,alt-p:toggle-preview,change:top,alt-up:preview-page-up,alt-down:preview-page-down --tiebreak=begin --inline-info --layout=reverse-list --preview-window=wrap,border-left" # For more information consult the fzf manpage. clifm-1.26.3/misc/colors/default.clifm000066400000000000000000000435031506632037700176070ustar00rootroot00000000000000# Theme file for Clifm # Theme name: clifm (16 colors). Check 'default-256' for a 256 colors version. # Author: L. Abramovich # License: GPL2+ ### How do we define colors? # # The FiletypeColors, InterfaceColors, and ExtColors options take SGR sequences # (excluding the initial escape character and the ending 'm') as color values, # just like the LS_COLORS environment variable. However, shortcuts for 8-bit # (256-colors) and 24-bit (true color) colors are available. For example: # # 31 4-bit # 38;5;160 8-bit # @160 8-bit (short) # 38;2;255;0;0 24-bit # #ff0000 24-bit (short, HEX) # # A single attribute can be added to hex colors, and 256 colors (in the form @NUM), # using a dash and an attribute number (#RRGGBB-[1-9] or @NUM-[1-9]), where 1-9 is: # # 1: Bold or increased intensity # 2: Faint, decreased intensity or dim # 3: Italic (not widely supported) # 4: Underline # 5: Slow blink # 6: Rapid blink # 7: Reverse video or invert # 8: Conceal or hide (not widely supported) # 9: Crossed-out or strike # # For example, for bold red the hex code is #ff0000-1, while the 256-colors code # is @160-1. # # Note: For more information about SGR sequences consult # https://en.wikipedia.org/wiki/ANSI_escape_code ### Use some variables to hold your color codes # # The 'define' keyword allows you to define up to 128 custom color variables. # They can be used for: # FiletypeColors # InterfaceColors # ExtColors # DirIconColor # # For example; # # define BOLD_CYAN=@6-1 # el=BOLD_CYAN # # Here we define 'BOLD_CYAN' as "@6-1", and then we use this color for ELNs, # whose code is 'el' (see below). ### Xterm-like color names are also supported. For example, let's use DarkSeaGreen1 # for ELNs: # # el=DarkSeaGreen1 # # Or, as a definition: # # define Green=DarkSeaGreen1 # el=Green # # Just as with hex colors, a single attribute can be added to color names. # For example, 'DarkSeaGreen1-1' to get the bold version of this color. # # For the complete list of color names consult the manpage. ## Edit the value of the below defintions to change colors. For example, to change # the color of directories to bold red: 'define FTYPE_DIR=@1-1'. #=====================================# # FILE TYPES # #=====================================# define FTYPE_DIR=1;34 # Directory define FTYPE_EMPTY_DIR=2;34 # Empty directory define FTYPE_DIR_NO_PERM=1;31 # Directory with no read permission (1) define FTYPE_REG=0 # Regular file define FTYPE_EMPTY_REG=2 # Empty regular file define FTYPE_REG_NO_PERM= # Regular file with no read permission (1) define FTYPE_EXEC=1;32 # Executable file define FTYPE_EMPTY_EXEC=32 # Empty executable file define FTYPE_LINK=1;36 # Symbolic link define FTYPE_BROKEN_LINK=4;2;36 # Broken symbolic link define FTYPE_MULTI_HLINK=7;36 # Multi-hardlink file define FTYPE_BLK_DEV=1;33 # Block device define FTYPE_CHR_DEV=1 # Char device define FTYPE_FIFO=4;45;37 # FIFO/pipe define FTYPE_SOCK=45;37 # Socket define FTYPE_CAP=30;41 # File with capabilities define FTYPE_DOOR=35 # Door (Solaris only) define FTYPE_SUID=37;41 # SUID file define FTYPE_SGID=30;43 # SGID file define FTYPE_OW=34;40 # Other-writable define FTYPE_STICKY_NOT_OW=37;44 # Sticky (not other-writable) define FTYPE_STICKY_OW=37;42 # Sticky and other-writable define FTYPE_UNKNOWN=4;31;47 # Unknown file type define FTYPE_NON_STAT=4;2;37 # Non-stat'able file # (1) If unset, the corresponding file type color is used and an # exclamation mark is printed before the file name in the files list # (provided icons are disabled -otherwise the lock icon is used- and # clifm is not running in light mode -in light mode access checks are # not performed). The color used for the exclamation mark is # PROMPT_EXIT_FAILURE (see below). #=====================================# # PROPERTIES / LONG VIEW # #=====================================# define PROP_READ=33 # Read bit define PROP_WRITE=31 # Write bit define PROP_EXEC_DIR=36 # Execute bit (directories) define PROP_EXEC_FILE=32 # Execute bit (files) define PROP_SPECIAL=35 # SUID/SGID bit define PROP_UID=35 # User ID define PROP_GID=2;35 # Group ID define PROP_SIZE= # Size (1) define PROP_DATE= # Date (1) define PROP_BLKS=33 # Used blocks define PROP_INODE=36 # Inode number define PROP_LINKS=31 # Number of file links define PROP_OCTAL_PERM=36 # Permissions in octal define PROP_DASH=2;37 # Dot separator and dash (unset bit) define PROP_TIME_MARK= # Timestamp identification character (2) # (1) If unset (default), color shades are used instead. # See DateShades and SizeShades below. # (2) If unset (default), a dimmed version of the current timestamp color is used. #=====================================# # INTERFACE # #=====================================# define IFACE_ELN=36 # ELNs (e.g. "12 myfile") define IFACE_FILES_COUNTER=2;37 # Files counter (e.g. "dir/12") define IFACE_DIV_LINE=2;37 # Dividing line define IFACE_LINK_IND=1;36 # Symbolic link indicator ('@') define IFACE_MISC_IND=1;36 # Miscellaneous indicator ("->") define IFACE_TABCOMP_PREFIX=4;35 # Matching prefix (tab completion) define IFACE_WELCOME_MSG=1;36 # Welcome message define IFACE_TRUNC_CHAR=1;2;36 # Character used to mark truncated filenames ('~') define IFACE_DEF_COLOR=0 # Default color #=====================================# # PROMPT # #=====================================# define PROMPT_TEXT=0 # Command line text color define PROMPT_SEL=1;32 # Selected files indicator define PROMPT_TRASH=1;36 # Trashed files indicator define PROMPT_NOTICE=1;32 # Notice message indicator define PROMPT_WARNING=1;33 # Warning message indicator define PROMPT_ERR=1;31 # Error message indicator define PROMPT_AUTOCMD=2;37 # Autocommand indicator define PROMPT_READ_ONLY=1;34 # Read-only indicator define PROMPT_STEALTH=1;34 # Stealth mode indicator define PROMPT_EXIT_SUCCESS=32 # Success exit code define PROMPT_EXIT_FAILURE=1;31 # Error exit code #=====================================# # WORKSPACE NUMBER/NAME # #=====================================# define WORKSPACE_1=34 define WORKSPACE_2=31 define WORKSPACE_3=33 define WORKSPACE_4=32 define WORKSPACE_5=36 define WORKSPACE_6=36 define WORKSPACE_7=36 define WORKSPACE_8=36 #=====================================# # SUGGESTIONS # #=====================================# define SUG_HIST=2;37 # History define SUG_FILE_NAME=4;2;36 # File names define SUG_FILE_NAME_FUZZY=4;2;36 # File names (fuzzy) define SUG_INT_CMD=2;32 # Internal command names and parameters define SUG_EXT_CMD=2;36 # External command names define SUG_BUILTIN=2;33 # Shell builtin names define SUG_INT_CMD_DESC=2;37 # Internal commands description (e.g. "c (copy files)") define SUG_POINTER=2;31 # Suggestions pointer (e.g. "12 > myfile") #=====================================# # SYNTAX HIGHLIGHTING # #=====================================# define HL_BRACKET=36 # Brackets: () [] {} define HL_COMMENT=2;37 # Commented out text (starting with '#') define HL_SLASH=36 # Slash define HL_EXPANSION=36 # Expansion characters: * ~ define HL_NUMBER= # Number define HL_PARAM=36 # Command parameters (e.g. "echo '-e'") define HL_QUOTE=33 # Quoted text (single and double quotes) define HL_REDIRECT=31 # Redirection characters: > < define HL_PROC_SEP=32 # Process separators: | & ; define HL_VAR=32 # Variable names: $FOO define HL_WHACK=31 # Backslash (aka whack) # NOTE: Exception made of PROP_SIZE and PROP_DATE, whenever a value is unset, # the default value is used. To force it to use no color, set its value to zero. # Example: # define VAR=0 ### Colors used for file names when listing files FiletypeColors="bd=FTYPE_BLK_DEV:ca=FTYPE_CAP:cd=FTYPE_CHR_DEV:di=FTYPE_DIR:ed=FTYPE_EMPTY_DIR:ee=FTYPE_EMPTY_EXEC:ef=FTYPE_EMPTY_REG:ex=FTYPE_EXEC:fi=FTYPE_REG:ln=FTYPE_LINK:mh=FTYPE_MULTI_HLINK:nd=FTYPE_DIR_NO_PERM:nf=FTYPE_REG_NO_PERM:no=FTYPE_UNKNOWN:oo=FTYPE_DOOR:or=FTYPE_BROKEN_LINK:ow=FTYPE_OW:pi=FTYPE_FIFO:sg=FTYPE_SGID:so=FTYPE_SOCK:st=FTYPE_STICKY_NOT_OW:su=FTYPE_SUID:tw=FTYPE_STICKY_OW:uf=FTYPE_NON_STAT:" ### Colors for Clifm's interface elements InterfaceColors="ac=PROMPT_AUTOCMD:db=PROP_BLKS:dd=PROP_DATE:de=PROP_INODE:df=IFACE_DEF_COLOR:dg=PROP_GID:dk=PROP_LINKS:dl=IFACE_DIV_LINE:dn=PROP_DASH:do=PROP_OCTAL_PERM:dp=PROP_SPECIAL:dr=PROP_READ:dt=PROP_TIME_MARK:du=PROP_UID:dw=PROP_WRITE:dxd=PROP_EXEC_DIR:dxr=PROP_EXEC_FILE:dz=PROP_SIZE:el=IFACE_ELN:em=PROMPT_ERR:fc=IFACE_FILES_COUNTER:hb=HL_BRACKET:hc=HL_COMMENT:hd=HL_SLASH:he=HL_EXPANSION:hn=HL_NUMBER:hp=HL_PARAM:hq=HL_QUOTE:hr=HL_REDIRECT:hs=HL_PROC_SEP:hv=HL_VAR:hw=HL_WHACK:lc=IFACE_LINK_IND:li=PROMPT_SEL:mi=IFACE_MISC_IND:nm=PROMPT_NOTICE:ro=PROMPT_READ_ONLY:si=PROMPT_STEALTH:sb=SUG_BUILTIN:sc=SUG_EXT_CMD:sd=SUG_INT_CMD_DESC:sf=SUG_FILE_NAME:sh=SUG_HIST:sp=SUG_POINTER:sx=SUG_INT_CMD:sz=SUG_FILE_NAME_FUZZY:ti=PROMPT_TRASH:ts=IFACE_TABCOMP_PREFIX:tt=IFACE_TRUNC_CHAR:tx=PROMPT_TEXT:wc=IFACE_WELCOME_MSG:wm=PROMPT_WARNING:ws1=WORKSPACE_1:ws2=WORKSPACE_2:ws3=WORKSPACE_3:ws4=WORKSPACE_4:ws5=WORKSPACE_5:ws6=WORKSPACE_6:ws7=WORKSPACE_7:ws8=WORKSPACE_8:xf=PROMPT_EXIT_FAILURE:xs=PROMPT_EXIT_SUCCESS:" #=====================================# # FILE EXTENSIONS # #=====================================# # Colors for specific file extensions (case insensitive). ExtColors can be used multiple times. # ARCHIVES define ARCHIVE=1;31 # Bold red ExtColors="7z=ARCHIVE:ace=ARCHIVE:alz=ARCHIVE:apk=ARCHIVE:arc=ARCHIVE:arj=ARCHIVE:bz=ARCHIVE:bz2=ARCHIVE:cab=ARCHIVE:cpio=ARCHIVE:deb=ARCHIVE:dmg=ARCHIVE:dwm=ARCHIVE:dz=ARCHIVE:ear=ARCHIVE:esd=ARCHIVE:gz=ARCHIVE:img=ARCHIVE:iso=ARCHIVE:jar=ARCHIVE:lha=ARCHIVE:lrz=ARCHIVE:lz=ARCHIVE:lz4=ARCHIVE:lzh=ARCHIVE:lzma=ARCHIVE:lzo=ARCHIVE:qcow=ARCHIVE:qcow2=ARCHIVE:rar=ARCHIVE:rpm=ARCHIVE:rz=ARCHIVE:sar=ARCHIVE:swm=ARCHIVE:t7z=ARCHIVE:tar=ARCHIVE:taz=ARCHIVE:tbz=ARCHIVE:tbz2=ARCHIVE:tgz=ARCHIVE:tlz=ARCHIVE:toast=ARCHIVE:txz=ARCHIVE:tz=ARCHIVE:tzo=ARCHIVE:tzst=ARCHIVE:vcd=ARCHIVE:vdi=ARCHIVE:vhd=ARCHIVE:vhdx=ARCHIVE:vmdk=ARCHIVE:vsix=ARCHIVE:war=ARCHIVE:wim=ARCHIVE:xz=ARCHIVE:z=ARCHIVE:zip=ARCHIVE:zoo=ARCHIVE:zst=ARCHIVE:" # AUDIO FILES define AUDIO=36 # Cyan ExtColors="aac=AUDIO:ac3=AUDIO:aif=AUDIO:aifc=AUDIO:aiff=AUDIO:alac=AUDIO:anx=AUDIO:ape=AUDIO:au=AUDIO:axa=AUDIO:cue=AUDIO:flac=AUDIO:m2a=AUDIO:m4a=AUDIO:mid=AUDIO:midi=AUDIO:mka=AUDIO:mp2=AUDIO:mp3=AUDIO:mpc=AUDIO:mpga=AUDIO:oga=AUDIO:ogg=AUDIO:ogx=AUDIO:opus=AUDIO:pcm=AUDIO:ra=AUDIO:ram=AUDIO:snd=AUDIO:spx=AUDIO:wav=AUDIO:wma=AUDIO:wv=AUDIO:" # SOURCE FILES define CODE=1;33 # Bold yellow ExtColors="applescript=CODE:asm=CODE:awk=CODE:bash=CODE:bat=CODE:c=CODE:c++=CODE:cabal=CODE:cc=CODE:cgi=CODE:clj=CODE:cp=CODE:cpp=CODE:cs=CODE:csx=CODE:cxx=CODE:d=CODE:dart=CODE:di=CODE:el=CODE:elm=CODE:erl=CODE:ex=CODE:exs=CODE:f=CODE:f90=CODE:fish=CODE:for=CODE:fs=CODE:fsi=CODE:fsx=CODE:gd=CODE:gleam=CODE:go=CODE:gradle=CODE:groovy=CODE:gv=CODE:gvy=CODE:h=CODE:h++=CODE:hh=CODE:hpp=CODE:hs=CODE:hxx=CODE:inc=CODE:inl=CODE:ipp=CODE:ipynb=CODE:java=CODE:jl=CODE:js=CODE:jsx=CODE:kt=CODE:kts=CODE:lhs=CODE:lisp=CODE:lua=CODE:m=CODE:mat=CODE:ml=CODE:mli=CODE:p=CODE:pas=CODE:php=CODE:pl=CODE:pm=CODE:pod=CODE:pp=CODE:pro=CODE:ps1=CODE:psd1=CODE:psm1=CODE:purs=CODE:py=CODE:r=CODE:rb=CODE:rs=CODE:scala=CODE:sh=CODE:swift=CODE:t=CODE:tcl=CODE:tsx=CODE:vb=CODE:zig=CODE:zsh=CODE:" # DOCUMENTS define DOC=1 # Bold ExtColors="abw=DOC:chm=DOC:csv=DOC:doc=DOC:docm=DOC:docx=DOC:fodg=DOC:fodp=DOC:fods=DOC:fodt=DOC:odg=DOC:odp=DOC:ods=DOC:odt=DOC:pps=DOC:ppt=DOC:pptm=DOC:pptx=DOC:rtf=DOC:sxi=DOC:sxw=DOC:txt=DOC:xlr=DOC:xls=DOC:xlsm=DOC:xlsx=DOC:" # EBOOKS define EBOOK=1 # Bold ExtColors="azw=EBOOK:azw3=EBOOK:cb7=EBOOK:cba=EBOOK:cbr=EBOOK:cbt=EBOOK:cbz=EBOOK:djv=EBOOK:djvu=EBOOK:epub=EBOOK:fb2=EBOOK:kf8=EBOOK:kfx=EBOOK:mobi=EBOOK:oxps=EBOOK:pdb=EBOOK:pdf=EBOOK:ps=EBOOK:xps=EBOOK:" # IMAGES define IMAGE=35 # Magenta ExtColors="ai=IMAGE:avif=IMAGE:bmp=IMAGE:dpx=IMAGE:dvi=IMAGE:eps=IMAGE:exr=IMAGE:ff=IMAGE:fit=IMAGE:fts=IMAGE:hdr=IMAGE:heic=IMAGE:heif=IMAGE:gif=IMAGE:ico=IMAGE:j2c=IMAGE:j2k=IMAGE:jfi=IMAGE:jfif=IMAGE:jif=IMAGE:jp2=IMAGE:jpe=IMAGE:jpeg=IMAGE:jpf=IMAGE:jpg=IMAGE:jps=IMAGE:jpx=IMAGE:jxl=IMAGE:kra=IMAGE:miff=IMAGE:mng=IMAGE:ora=IMAGE:pam=IMAGE:pbm=IMAGE:pcx=IMAGE:pdd=IMAGE:pgm=IMAGE:pict=IMAGE:png=IMAGE:pnm=IMAGE:ppm=IMAGE:psd=IMAGE:pxm=IMAGE:qoi=IMAGE:rgba=IMAGE:sgi=IMAGE:svg=IMAGE:svgz=IMAGE:tga=IMAGE:tif=IMAGE:tiff=IMAGE:webp=IMAGE:wmf=IMAGE:xbm=IMAGE:xcf=IMAGE:xpm=IMAGE:xwd=IMAGE:" # RAW IMAGES # There are plenty of raw image formats out there. This is an incomplete list taken from "https://en.wikipedia.org/wiki/Raw_image_format". # Uncomment to enable. #define RAW=@141 #ExtColors="3fr=RAW:ari=RAW:arw=RAW:bay=RAW:braw=RAW:crw=RAW:cr2=RAW:cr3=RAW:cap=RAW:data=RAW:dcs=RAW:dcr=RAW:dng=RAW:drf=RAW:eip=RAW:erf=RAW:fff=RAW:gpr=RAW:iiq=RAW:k25=RAW:kdc=RAW:mdc=RAW:mef=RAW:mos=RAW:mrw=RAW:nef=RAW:nrw=RAW:obm=RAW:orf=RAW:pef=RAW:ptx=RAW:pxn=RAW:r3d=RAW:raf=RAW:raw=RAW:rwl=RAW:rw2=RAW:rwz=RAW:sr2=RAW:srf=RAW:srw=RAW:x3f=RAW:" # MARKUP FILES define MARKUP=1;33 # Same as CODE ExtColors="css=MARKUP:htm=MARKUP:html=MARKUP:ltx=MARKUP:markdown=MARKUP:md=MARKUP:mdown=MARKUP:opf=MARKUP:rss=MARKUP:sass=MARKUP:scss=MARKUP:sgml=MARKUP:shtml=MARKUP:tex=MARKUP:xbel=MARKUP:xhtml=MARKUP:xml=MARKUP:xsd=MARKUP:xslt=MARKUP:" # TEMPORARY FILES define TEMP=2;37 # Dimmed white ExtColors="$$$=TEMP:aux=TEMP:bak=TEMP:bbl=TEMP:bc=TEMP:cache=TEMP:class=TEMP:git=TEMP:hi=TEMP:idx=TEMP:ilg=TEMP:ind=TEMP:la=TEMP:lo=TEMP:localized=TEMP:lock=TEMP:log=TEMP:orig=TEMP:pid=TEMP:pyc=TEMP:pyd=TEMP:pyo=TEMP:rej=TEMP:rlib=TEMP:swp=TEMP:tmp=TEMP:toc=TEMP:" # VIDEO FILES define VIDEO=1;35 # Bold magenta ExtColors="3gp=VIDEO:asf=VIDEO:avi=VIDEO:cgm=VIDEO:dl=VIDEO:flc=VIDEO:fli=VIDEO:flv=VIDEO:h264=VIDEO:heics=VIDEO:gl=VIDEO:m2ts=VIDEO:m2v=VIDEO:m4v=VIDEO:mkv=VIDEO:mov=VIDEO:mp4=VIDEO:mp4v=VIDEO:mpeg=VIDEO:mpg=VIDEO:nuv=VIDEO:ogm=VIDEO:ogv=VIDEO:qt=VIDEO:rm=VIDEO:rmvb=VIDEO:vob=VIDEO:webm=VIDEO:wmv=VIDEO:yuv=VIDEO:" #=====================================# # COLOR SHADES # #=====================================# ### TIMESTAMPS ### # The format is: "COLOR-TYPE,ERROR,SHADE1,SHADE2,SHADE3,SHADE4,SHADE5" # # COLOR-TYPE is one of: 1 (4-bit: 8 colors), 2 (8-bit: 256 colors), 3 (24-bit: truecolor) # ERROR is the color used to print bad values # SHADEn is the color used for the shade N # # The meaning of each date shade is (in order, excluding COLOR-TYPE and ERROR): # hour, day, weak, month, older # # For 4-bit colors (1), valid colors are in the range 30-37 # For 8-bit colors (2), valid colors are in the range 0-255 # For 24-bit colors (3), valid colors have this format: #RRGGBB # # An attribute (0-9) can be added to any color (either ERROR or SHADE) using a dash. # For example: # "34-1" -> "bold blue" (4-bit colors notation) # "226-2" -> "dimmed yellow" (8-bit colors notation) # "#ffaff00-4" -> "underlined orange" (24-bit colors notation) DateShades="1,31-2,37,37-2,36-1,36,36-2" #DateShades="2,196-2,231,253,250,247,244" #DateShades="3,#ff0000-2,#ffffff,#dadada,#bcbcbc,#9e9e9e,#808080" #NOTE: For DateShades to work, the 'dd' color code (solid color for dates) needs to be unset (default). ### FILE SIZES ### # The meaning of each size shade is (in order, excluding COLOR-TYPE and ERROR): # byte, Kb, Mb, Gb, bigger SizeShades="1,31-2,36,32,33,31,35" #SizeShades="2,196-2,43,112,227,214,202" #SizeShades="3,#ff0000-2,#00d7af,#87d700,#ffff5f,#ffaf00,#ff5f00" #NOTE: For SizeShades to work, the 'dz' color code (solid color for sizes) needs to be unset (default). # If icons are enabled, use this color for directories icon (only for icons-in-terminal and Nerd-fonts). DirIconColor="Y" #=====================================# # PROMPT STYLE # #=====================================# # The prompt used by Clifm. Use the 'prompt' command to check for available # prompts. Enter 'prompt --help' for more information. # You can use here either prompt codes (see the prompts.clifm file for details) # or a prompt name defined in the prompts file. Prompt="clifm" # Override prompt values (as defined in the prompts file). #Prompt="" #Notifications= #EnableWarningPrompt= #WarningPrompt="" # The string used to construct the line dividing the list of files and # the prompt (Unicode is supported). Possible values: # "0": Print an empty line. # "C": C is a single character. This character will be printed up to the # end of the screen. # "CC": 2 or more chars. Only these characters (and no more) will be printed. # "": Print a special line drawn with box-drawing characters (not supported # by all terminals/consoles). # The color of this line is controlled by the 'dl' code in InterfaceColors. DividingLine="-" #=====================================# # FZF # #=====================================# # If the fzf tab completion mode is enabled, pass these options to fzf: FzfTabOptions="--color='16,prompt:6,fg+:-1,pointer:4,hl:2,hl+:2,gutter:-1,marker:2,border:7:dim' --marker='*' --bind tab:accept,right:accept,left:abort,alt-p:toggle-preview,change:top,alt-up:preview-page-up,alt-down:preview-page-down --tiebreak=begin --inline-info --layout=reverse-list --preview-window=wrap,border-left" # Same options, but colorless. #FzfTabOptions="--color='bw' --marker='*' --bind tab:accept,right:accept,left:abort,alt-p:toggle-preview,change:top,alt-up:preview-page-up,alt-down:preview-page-down --tiebreak=begin --inline-info --layout=reverse-list --preview-window=wrap,border-left" # For more information consult the fzf manpage. clifm-1.26.3/misc/colors/dracula-vivid.clifm000066400000000000000000000155631506632037700207220ustar00rootroot00000000000000# Theme file for Clifm # Theme name: dracula-vivid (based on vivid(1)) # Author: L. Abramovich # License: GPL2+ define D=38;5;253 # Default define BD=1 # Bold (reset foreground color) define R=38;5;203 # Red define BR=1;38;5;203 # Bold red define DR=#ff5f5f-2 # Dimmed red define G=38;5;84 # Green define BG=1;38;5;84 # Bold green define DG=#5fff87-2 # Dimmed green define Y=38;5;228 # Yellow define BY=1;38;5;228 # Bold yellow define DY=#ffff87-2 # Dimmed yellow define Y24=#ffff87 # Yellow (24-bit) define B=38;5;141 # Blue define BB=1;38;5;141 # Bold blue define DB=#af87ff-2 # Dimmed blue define M=38;5;212 # Magenta define BM=1;38;5;212 # Bold Magenta define DM=#ff87d7-2 # Dimmed magenta define UM=4;38;5;212 # Underlined magenta define C=38;5;117 # Cyan define BC=1;38;5;117 # Bold cyan define DC=#87d7ff-2 # Dimmed cyan define RC=7;38;5;117 # Reverse cyan define UDC=4;2;38;2;135;215;255 # Underlined dimmed cyan define BDC=1;2;38;2;135;215;255 # Bold dimmed cyan define O=38;5;215 # Orange define BO=1;38;5;215 # Bold orange define DO=#ffaf5f-2 # Dimmed orange define W=38;5;253 # White define DW=#dadada-2 # Dimmed white define K=38;5;237 # Dark gray define PW=38;5;231 # Pale white define OK=1;38;5;215;48;5;235 # Bold orange on dark gray define YP=38;5;228;48;5;212 # Yellow on Pink define BK=38;5;117;48;5;235 # Blue on dark gray define YG=38;5;228;48;5;84 # Yellow on green define YB=38;5;228;48;5;117 # Yellow on blue define YK=1;38;5;228;48;5;235 # Bold yellow on dark gray define RK=38;5;203;48;5;235 # Red on dark gray define ARCHIVE=1;38;5;141 # Bold blue define AUDIO=38;5;215 # Orange define BOOK=1;38;5;203 # Bold red define CODE=38;5;215 # Orange define DOC=38;5;215 # Orange define IMAGE=38;5;228 # Yellow define MARKUP=38;5;215 # Orange define TEMP=38;5;246 # Dark gray define VIDEO=1;38;5;215 # Bold orange FiletypeColors="bd=OK:ca=0:cd=OK:di=B:do=YK:ed=DB:ee=DG:ef=DW:ex=G:fi=W:ln=C:mh=0:no=PW:or=RK:ow=BK:pi=YK:sg=YP:so=YK:st=YB:su=YP:tw=YG:uf=:" InterfaceColors="ac=:db=O:dd=:de=C:df=W:dg=Y24:dk=R:dl=B:dn=DW:do=C:dp=M:dr=Y:dw=R:dxd=G:dxr=B:dz=:el=O:em=BR:fc=DB:hb=C:hc=DR:hd=C:he=C:hn=W:hp=C:hq=Y:hr=R:hs=G:hv=G:lc=C:li=BG:mi=BC:nm=BG:sb=DY:sc=DR:sf=UDC:sh=DM:si=BB:sp=DR:sx=DG:ti=BC:ts=UM:tt=BDC:tx=W:wc=C:wm=BY:ws1=B:ws2=R:ws3=Y:ws4=G:ws5=C:ws6=C:ws7=C:ws8=C:xs=G:xf=R:" ExtColors="*.7z=ARCHIVE:*.ace=ARCHIVE:*.alz=ARCHIVE:*.apk=ARCHIVE:*.arc=ARCHIVE:*.arj=ARCHIVE:*.bz=ARCHIVE:*.bz2=ARCHIVE:*.cab=ARCHIVE:*.cpio=ARCHIVE:*.deb=ARCHIVE:*.dmg=ARCHIVE:*.dwm=ARCHIVE:*.dz=ARCHIVE:*.ear=ARCHIVE:*.esd=ARCHIVE:*.gz=ARCHIVE:*.img=ARCHIVE:*.iso=ARCHIVE:*.jar=ARCHIVE:*.lha=ARCHIVE:*.lrz=ARCHIVE:*.lz=ARCHIVE:*.lz4=ARCHIVE:*.lzh=ARCHIVE:*.lzma=ARCHIVE:*.lzo=ARCHIVE:*.qcow=ARCHIVE:*.qcow2=ARCHIVE:*.rar=ARCHIVE:*.rpm=ARCHIVE:*.rz=ARCHIVE:*.sar=ARCHIVE:*.swm=ARCHIVE:*.t7z=ARCHIVE:*.tar=ARCHIVE:*.taz=ARCHIVE:*.tbz=ARCHIVE:*.tbz2=ARCHIVE:*.tgz=ARCHIVE:*.tlz=ARCHIVE:*.toast=ARCHIVE:*.txz=ARCHIVE:*.tz=ARCHIVE:*.tzo=ARCHIVE:*.tzst=ARCHIVE:*.vcd=ARCHIVE:*.vdi=ARCHIVE:*.vhd=ARCHIVE:*.vhdx=ARCHIVE:*.vmdk=ARCHIVE:*.vsix=ARCHIVE:*.war=ARCHIVE:*.wim=ARCHIVE:*.xz=ARCHIVE:*.z=ARCHIVE:*.zip=ARCHIVE:*.zoo=ARCHIVE:*.zst=ARCHIVE:*.aac=AUDIO:*.aif=AUDIO:*.aifc=AUDIO:*.aiff=AUDIO:*.alac=AUDIO:*.ape=AUDIO:*.au=AUDIO:*.flac=AUDIO:*.m4a=AUDIO:*.mid=AUDIO:*.midi=AUDIO:*.mka=AUDIO:*.mp3=AUDIO:*.ogg=AUDIO:*.opus=AUDIO:*.pcm=AUDIO:*.spx=AUDIO:*.wav=AUDIO:*.wma=AUDIO:*.wv=AUDIO:*.applescript=CODE:*.as=CODE:*.asa=CODE:*.awk=CODE:*.bash=CODE:*.c=CODE:*.c++=CODE:*.cabal=CODE:*.cc=CODE:*.cgi=CODE:*.clj=CODE:*.cp=CODE:*.cpp=CODE:*.cr=CODE:*.cs=CODE:*.csx=CODE:*.cxx=CODE:*.d=CODE:*.dart=CODE:*.def=CODE:*.di=CODE:*.dpr=CODE:*.el=CODE:*.elm=CODE:*.epp=CODE:*.erl=CODE:*.ex=CODE:*.exs=CODE:*.fish=CODE:*.fs=CODE:*.fsi=CODE:*.fsx=CODE:*.gd=CODE:*.go=CODE:*.gradle=CODE:*.groovy=CODE:*.gv=CODE:*.gvy=CODE:*.h=CODE:*.h++=CODE:*.hgrc=CODE:*.hh=CODE:*.hpp=CODE:*.hs=CODE:*.htc=CODE:*.hxx=CODE:*.inc=CODE:*.inl=CODE:*.ipp=CODE:*.ipynb=CODE:*.java=CODE:*.jl=CODE:*.js=CODE:*.jsx=CODE:*.kt=CODE:*.kts=CODE:*.lhs=CODE:*.lisp=CODE:*.ll=CODE:*.lua=CODE:*.m=CODE:*.matlab=CODE:*.mir=CODE:*.ml=CODE:*.mli=CODE:*.mn=CODE:*.nb=CODE:*.p=CODE:*.pas=CODE:*.php=CODE:*.pl=CODE:*.pm=CODE:*.pod=CODE:*.pp=CODE:*.pro=CODE:*.ps1=CODE:*.psd1=CODE:*.psm1=CODE:*.purs=CODE:*.py=CODE:*.r=CODE:*.rb=CODE:*.rs=CODE:*.sbt=CODE:*.scala=CODE:*.sh=CODE:*.swift=CODE:*.t=CODE:*.tcl=CODE:*.td=CODE:*.ts=CODE:*.tsx=CODE:*.vb=CODE:*.vsh=CODE:*.zig=CODE:*.zsh=CODE:*.abw=DOC:*.doc=DOC:*.docx=DOC:*.fodg:*.fodp=DOC:*.fods=DOC:*.fodt=DOC:*.odg=DOC:*.odp=DOC:*.ods=DOC:*.odt=DOC:*.pps=DOC:*.ppt=DOC:*.pptx=DOC:*.rtf=DOC:*.sxi=DOC:*.sxw=DOC:*.txt=DOC:*.xlr=DOC:*.xls=DOC:*.xlsx=DOC:*.azw=EBOOK:*.azw3=EBOOK:*.cb7=EBOOK:*.cba=EBOOK:*.cbr=EBOOK:*.cbt=EBOOK:*.cbz=EBOOK:*.djvu=EBOOK:*.epub=EBOOK:*.fb2=EBOOK:*.kf8=EBOOK:*.kfx=EBOOK:*.mobi=EBOOK:*.oxps=EBOOK:*.pdb=EBOOK:*.pdf=EBOOK:*.ps=EBOOK:*.xps=EBOOK:*.avif=IMAGE:*.bmp=IMAGE:*.gif=IMAGE:*.ico=IMAGE:*.jpeg=IMAGE:*.jpg=IMAGE:*.jxl=IMAGE:*.mjpeg=IMAGE:*.mjpg=IMAGE:*.mng=IMAGE:*.pbm=IMAGE:*.pcx=IMAGE:*.pgm=IMAGE:*.png=IMAGE:*.ppm=IMAGE:*.psd=IMAGE:*.svg=IMAGE:*.svgz=IMAGE:*.tga=IMAGE:*.tif=IMAGE:*.tiff=IMAGE:*.webp=IMAGE:*.xbm=IMAGE:*.xcf=IMAGE:*.xpm=IMAGE:*.css=MARKUP:*.htm=MARKUP:*.html=MARKUP:*.ltx=MARKUP:*.markdown=MARKUP:*.md=MARKUP:*.mdown=MARKUP:*.opf=MARKUP:*.rss=MARKUP:*.shtml=MARKUP:*.tex=MARKUP:*.xhtml=MARKUP:*.xml=MARKUP:*.aux=TEMP:*.bak=TEMP:*.bbl=TEMP:*.bc=TEMP:*.cache=TEMP:*.class=TEMP:*.git=TEMP:*.hi=TEMP:*.idx=TEMP:*.ilg=TEMP:*.ind=TEMP:*.la=TEMP:*.lo=TEMP:*.localized=TEMP:*.lock=TEMP:*.log=TEMP:*.o=TEMP:*.orig=TEMP:*.out=TEMP:*.pid=TEMP:*.pyc=TEMP:*.pyd=TEMP:*.pyo=TEMP:*.rej=TEMP:*.rlib=TEMP:*.sty=TEMP:*.swp=TEMP:*.tmp=TEMP:*.toc=TEMP:*.3gp=VIDEO:*.asf=VIDEO:*.avi=VIDEO:*.cgm=VIDEO:*.dl=VIDEO:*.emf=VIDEO:*.flc=VIDEO:*.fli=VIDEO:*.flv=VIDEO:*.h264=VIDEO:*.heics=VIDEO:*.gl=VIDEO:*.m2ts=VIDEO:*.m2v=VIDEO:*.m4v=VIDEO:*.mkv=VIDEO:*.mov=VIDEO:*.mp4=VIDEO:*.mp4v=VIDEO:*.mpeg=VIDEO:*.mpg=VIDEO:*.nuv=VIDEO:*.ogm=VIDEO:*.ogv=VIDEO:*.ogx=VIDEO:*.qt=VIDEO:*.rm=VIDEO:*.rmvb=VIDEO:*.vob=VIDEO:*.webm=VIDEO:*.wmv=VIDEO:*.xwd=VIDEO:*.yuv=VIDEO:" DateShades="2,196-2,231,253,250,247,244" SizeShades="3,#ff5f5f-2,#87d7ff,#87ff87,#ffff87,#ffaf5f,#ff5f5f" DirIconColor="Y" Prompt="\[\e[0;38;5;253m\][\S\[\e[0;38;5;253m\]]\l \A \u:\H \[\e[0;38;5;117m\]\w\n\[\e[0;38;5;253m\]<\z\[\e[0;38;5;253m\]> \[\e[0;38;5;141m\]\$ \[\e[0;38;5;253m\]" Notifications=true EnableWarningPrompt=true WarningPrompt="\[\e[0;1;38;2;255;95;95m\](!)\[\e[0;2m\] > " DividingLine="-" FzfTabOptions="--color='16,prompt:#87d7ff,fg+:-1,pointer:#af87ff,hl:#5fff87,hl+:#5fff87,gutter:-1,marker:#5fff87,query:#dadada,info:#dadada:dim,border:8' --marker='*' --bind tab:accept,right:accept,left:abort,alt-p:toggle-preview,change:top,alt-up:preview-page-up,alt-down:preview-page-down --inline-info --tiebreak=begin --layout=reverse-list --preview-window=wrap,border-left" clifm-1.26.3/misc/colors/dracula.clifm000066400000000000000000000161601506632037700175750ustar00rootroot00000000000000# Theme file for Clifm # Theme name: dracula (based on https://github.com/dracula/dracula-theme) # Author: L. Abramovich # License: GPL2+ define D=#f8f8f2 # Default define BD=#f8f8f2-1 # Bold default define R=#ff5555 # Red define BR=#ff5555-1 # Bold red define DR=#ff5555-2 # Dimmed red define G=#50fa7b # Green define BG=#50fa7b-1 # Bold green define DG=#50fa7b-2 # Dimmed green define Y=#f1fa8c # Yellow define BY=#f1fa8c-1 # Bold yellow define DY=#f1fa8c-2 # Dimmed yellow define M=#ff79c6 # Pink define BM=#ff79c6-1 # Bold pink define DM=#ff79c6-2 # Dimmed pink define UM=#ff79c6-4 # Underlined pink define MK=38;2;255;121;198;48;2;68;68;68 define BMK=1;38;2;255;121;198;48;2;68;68;68 define M2=#bd93f9 # Purple define BM2=#bd93f9-1 # Bold purple define DM2=#bd93f9-2 # Dimmed purple define UM2=#bd93f9-4 # Underlined purple define C=#8be9fd # Cyan define BC=#8be9fd-1 # Bold cyan define DC=#8be9fd-2 # Dimmed cyan define RC=#8be9fd-7 # Reverse cyan define UDC=4;2;38;2;139;233;253 # Underlined dimmed cyan define BDC=1;2;38;2;139;233;253 # Bold dimmed cyan define W=#dadada define DW=#f8f8f2-2 # Dimmed white define RW=38;2;255;85;85;48;2;248;248;242 # Red on white define BW=38;2;98;114;164;48;2;248;248;242 # Blue on white define WR=38;2;248;248;242;48;2;255;85;85 # White on red define KY=38;2;40;42;54;48;2;241;250;140 # Black on yellow define KR=38;2;40;42;54;48;2;255;85;85 # Black on red define KG=38;2;40;42;54;48;2;80;250;123 # Black on green define BlGr=38;2;98;114;164;48;2;80;250;123 # Blue on green define WB=38;2;248;248;242;48;2;98;114;164 # White on blue define ARCHIVE=#ff5555-1 # Bold red define AUDIO=#8be9fd # Cyan define CODE=#bd93f9 # Purple define DOC=#ffb86c # Orange define EBOOK=#ffb86c-1 # Bold orange define IMAGE=#ff79c6 # Bold magenta define MARKUP=#f1fa8c # Yellow define TEMP=#f8f8f2-2 # Dimmed white define VIDEO=#ff79c6-1 # Bold magenta FiletypeColors="bd=BY:ca=KR:cd=BD:di=BM2:ed=M2:ee=G:ef=DY:ex=BG:fi=D:ln=BC:mh=RC:nd=BR:nf=:no=RW:or=DC:ow=BlGr:pi=MK:sg=KY:so=BMK:st=WB:su=WR:tw=KG:uf=BW:" InterfaceColors="ac=:db=M2:dd=:de=C:df=W:dg=Y:dk=R:dl=M2:dn=DW:do=C:dp=M2:dr=Y:dw=R:dxd=G:dxr=C:dz=:el=M:em=BR:fc=DW:hb=C:hc=DR:hd=C:he=C:hn=W:hp=C:hq=Y:hr=R:hs=G:hv=G:lc=C:li=BG:mi=BC:nm=BG:sb=DY:sc=DR:sf=UDC:sh=DM2:si=BM2:sp=DR:sx=DG:ti=BC:ts=UM2:tt=BDC:tx=W:wc=BC:wm=BY:ws1=M2:ws2=R:ws3=Y:ws4=G:ws5=C:ws6=C:ws7=C:ws8=C:xf=BR:xs=G:" ExtColors="*.7z=ARCHIVE:*.ace=ARCHIVE:*.alz=ARCHIVE:*.apk=ARCHIVE:*.arc=ARCHIVE:*.arj=ARCHIVE:*.bz=ARCHIVE:*.bz2=ARCHIVE:*.cab=ARCHIVE:*.cpio=ARCHIVE:*.deb=ARCHIVE:*.dmg=ARCHIVE:*.dwm=ARCHIVE:*.dz=ARCHIVE:*.ear=ARCHIVE:*.esd=ARCHIVE:*.gz=ARCHIVE:*.img=ARCHIVE:*.iso=ARCHIVE:*.jar=ARCHIVE:*.lha=ARCHIVE:*.lrz=ARCHIVE:*.lz=ARCHIVE:*.lz4=ARCHIVE:*.lzh=ARCHIVE:*.lzma=ARCHIVE:*.lzo=ARCHIVE:*.qcow=ARCHIVE:*.qcow2=ARCHIVE:*.rar=ARCHIVE:*.rpm=ARCHIVE:*.rz=ARCHIVE:*.sar=ARCHIVE:*.swm=ARCHIVE:*.t7z=ARCHIVE:*.tar=ARCHIVE:*.taz=ARCHIVE:*.tbz=ARCHIVE:*.tbz2=ARCHIVE:*.tgz=ARCHIVE:*.tlz=ARCHIVE:*.toast=ARCHIVE:*.txz=ARCHIVE:*.tz=ARCHIVE:*.tzo=ARCHIVE:*.tzst=ARCHIVE:*.vcd=ARCHIVE:*.vdi=ARCHIVE:*.vhd=ARCHIVE:*.vhdx=ARCHIVE:*.vmdk=ARCHIVE:*.vsix=ARCHIVE:*.war=ARCHIVE:*.wim=ARCHIVE:*.xz=ARCHIVE:*.z=ARCHIVE:*.zip=ARCHIVE:*.zoo=ARCHIVE:*.zst=ARCHIVE:*.aac=AUDIO:*.aif=AUDIO:*.aifc=AUDIO:*.aiff=AUDIO:*.alac=AUDIO:*.ape=AUDIO:*.au=AUDIO:*.flac=AUDIO:*.m4a=AUDIO:*.mid=AUDIO:*.midi=AUDIO:*.mka=AUDIO:*.mp3=AUDIO:*.ogg=AUDIO:*.opus=AUDIO:*.pcm=AUDIO:*.spx=AUDIO:*.wav=AUDIO:*.wma=AUDIO:*.wv=AUDIO:*.applescript=CODE:*.as=CODE:*.asa=CODE:*.awk=CODE:*.bash=CODE:*.c=CODE:*.c++=CODE:*.cabal=CODE:*.cc=CODE:*.cgi=CODE:*.clj=CODE:*.cp=CODE:*.cpp=CODE:*.cr=CODE:*.cs=CODE:*.csx=CODE:*.cxx=CODE:*.d=CODE:*.dart=CODE:*.def=CODE:*.di=CODE:*.dpr=CODE:*.el=CODE:*.elm=CODE:*.epp=CODE:*.erl=CODE:*.ex=CODE:*.exs=CODE:*.fish=CODE:*.fs=CODE:*.fsi=CODE:*.fsx=CODE:*.gd=CODE:*.go=CODE:*.gradle=CODE:*.groovy=CODE:*.gv=CODE:*.gvy=CODE:*.h=CODE:*.h++=CODE:*.hgrc=CODE:*.hh=CODE:*.hpp=CODE:*.hs=CODE:*.htc=CODE:*.hxx=CODE:*.inc=CODE:*.inl=CODE:*.ipp=CODE:*.ipynb=CODE:*.java=CODE:*.jl=CODE:*.js=CODE:*.jsx=CODE:*.kt=CODE:*.kts=CODE:*.lhs=CODE:*.lisp=CODE:*.ll=CODE:*.lua=CODE:*.m=CODE:*.matlab=CODE:*.mir=CODE:*.ml=CODE:*.mli=CODE:*.mn=CODE:*.nb=CODE:*.p=CODE:*.pas=CODE:*.php=CODE:*.pl=CODE:*.pm=CODE:*.pod=CODE:*.pp=CODE:*.pro=CODE:*.ps1=CODE:*.psd1=CODE:*.psm1=CODE:*.purs=CODE:*.py=CODE:*.r=CODE:*.rb=CODE:*.rs=CODE:*.sbt=CODE:*.scala=CODE:*.sh=CODE:*.swift=CODE:*.t=CODE:*.tcl=CODE:*.td=CODE:*.ts=CODE:*.tsx=CODE:*.vb=CODE:*.vsh=CODE:*.zig=CODE:*.zsh=CODE:*.abw=DOC:*.doc=DOC:*.docx=DOC:*.fodg:*.fodp=DOC:*.fods=DOC:*.fodt=DOC:*.odg=DOC:*.odp=DOC:*.ods=DOC:*.odt=DOC:*.pps=DOC:*.ppt=DOC:*.pptx=DOC:*.rtf=DOC:*.sxi=DOC:*.sxw=DOC:*.txt=DOC:*.xlr=DOC:*.xls=DOC:*.xlsx=DOC:*.azw=EBOOK:*.azw3=EBOOK:*.cb7=EBOOK:*.cba=EBOOK:*.cbr=EBOOK:*.cbt=EBOOK:*.cbz=EBOOK:*.djvu=EBOOK:*.epub=EBOOK:*.fb2=EBOOK:*.kf8=EBOOK:*.kfx=EBOOK:*.mobi=EBOOK:*.oxps=EBOOK:*.pdb=EBOOK:*.pdf=EBOOK:*.ps=EBOOK:*.xps=EBOOK:*.avif=IMAGE:*.bmp=IMAGE:*.gif=IMAGE:*.ico=IMAGE:*.jpeg=IMAGE:*.jpg=IMAGE:*.jxl=IMAGE:*.mjpeg=IMAGE:*.mjpg=IMAGE:*.mng=IMAGE:*.pbm=IMAGE:*.pcx=IMAGE:*.pgm=IMAGE:*.png=IMAGE:*.ppm=IMAGE:*.psd=IMAGE:*.svg=IMAGE:*.svgz=IMAGE:*.tga=IMAGE:*.tif=IMAGE:*.tiff=IMAGE:*.webp=IMAGE:*.xbm=IMAGE:*.xcf=IMAGE:*.xpm=IMAGE:*.css=MARKUP:*.htm=MARKUP:*.html=MARKUP:*.ltx=MARKUP:*.markdown=MARKUP:*.md=MARKUP:*.mdown=MARKUP:*.opf=MARKUP:*.rss=MARKUP:*.shtml=MARKUP:*.tex=MARKUP:*.xhtml=MARKUP:*.xml=MARKUP:*.aux=TEMP:*.bak=TEMP:*.bbl=TEMP:*.bc=TEMP:*.cache=TEMP:*.class=TEMP:*.git=TEMP:*.hi=TEMP:*.idx=TEMP:*.ilg=TEMP:*.ind=TEMP:*.la=TEMP:*.lo=TEMP:*.localized=TEMP:*.lock=TEMP:*.log=TEMP:*.o=TEMP:*.orig=TEMP:*.out=TEMP:*.pid=TEMP:*.pyc=TEMP:*.pyd=TEMP:*.pyo=TEMP:*.rej=TEMP:*.rlib=TEMP:*.sty=TEMP:*.swp=TEMP:*.tmp=TEMP:*.toc=TEMP:*.3gp=VIDEO:*.asf=VIDEO:*.avi=VIDEO:*.cgm=VIDEO:*.dl=VIDEO:*.emf=VIDEO:*.flc=VIDEO:*.fli=VIDEO:*.flv=VIDEO:*.h264=VIDEO:*.heics=VIDEO:*.gl=VIDEO:*.m2ts=VIDEO:*.m2v=VIDEO:*.m4v=VIDEO:*.mkv=VIDEO:*.mov=VIDEO:*.mp4=VIDEO:*.mp4v=VIDEO:*.mpeg=VIDEO:*.mpg=VIDEO:*.nuv=VIDEO:*.ogm=VIDEO:*.ogv=VIDEO:*.ogx=VIDEO:*.qt=VIDEO:*.rm=VIDEO:*.rmvb=VIDEO:*.vob=VIDEO:*.webm=VIDEO:*.wmv=VIDEO:*.xwd=VIDEO:*.yuv=VIDEO:" DateShades="3,#ff0000-2,#ffffff,#dadada,#bcbcbc,#9e9e9e,#808080" SizeShades="3,#ff5555-2,#50fa7b,#68da85,#f1fa8c,#ffb86c,#ff5555" DirIconColor="Y" #Prompt="\[\e[0;38;2;248;248;242m\][\S\[\e[0;38;2;248;248;242m\]]\l \A \u:\H \[\e[0;38;2;139;233;253m\]\w\n\[\e[0;38;2;248;248;242m\]<\z\[\e[0;38;2;248;248;242m\]> \[\e[0;38;2;98;114;164m\]\$ \[\e[0m\]" Prompt="\[\e[0;38;5;253m\][\S\[\e[0;38;5;253m\]]\l \A \u:\H \[\e[0;38;2;139;233;253m\]\w\n\[\e[0;38;5;253m\]<\z\[\e[0;38;5;253m\]> \[\e[0;38;2;98;114;164m\]\$ \[\e[0m\]" Notifications=true EnableWarningPrompt=true WarningPrompt="\[\e[0;1;38;2;255;85;85m\](!)\[\e[0;2m\] > " DividingLine="-" FzfTabOptions="--color='dark,prompt:#8be9fd,fg+:-1,pointer:#6272a4,hl:#50fa7b,hl+:#50fa7b,gutter:-1,marker:#50fa7b:bold,query:#f8f8f2,info:#f8f8f2:dim,border:8' --marker='*' --bind tab:accept,right:accept,left:abort,alt-p:toggle-preview,change:top,alt-up:preview-page-up,alt-down:preview-page-down --tiebreak=begin --inline-info --layout=reverse-list --preview-window=wrap,border-left" clifm-1.26.3/misc/colors/gruvbox.clifm000066400000000000000000000201351506632037700176530ustar00rootroot00000000000000# Theme file for Clifm # Theme name: gruvbox (based on https://github.com/morhetz/gruvbox) # Author: L. Abramovich # License: GPL2+ define D=#ebdbb2 # Default define BD=1 # Bold define A=#8ec07c # Aqua define BA=#8ec07c-1 # Bold aqua define DA=#8ec07c-2 # Dimmed aqua define A2=#689d6a # Aqua darker define BA2=#689d6a-1 # Bold aqua darker define R=#fb4934 # Red define BR=#fb4934-1 # Bold red define DR=#fb4934-2 # Dimmed red define BDR=1;2;38;2;251;73;52 # Bold dimmed red define R2=#cc241d # Red darker define BR2=#cc241d-1 # Bold red darker define DR2=#cc241d-2 # Dimmed red darker define G=#b8bb26 # Green define BG=#b8bb26-1 # Bold green define DG=#b8bb26-2 # Dimmed green define Y=#d79921 # Yellow define BY=#d79921-1 # Bold yellow define DY=#d79921-2 # Dimmed yellow define B=#458588 # Blue define BB=#458588-1 # Bold blue define DB=#458588-2 # Dimmed blue define BDB=1;2;38;2;69;133;136 # Bold dimmed blue define M=#b16286 # Magenta define BM=#b16286-1 # Bold magenta define DM=#b16286-2 # Dimmed magenta define UM=#b16286-4 # Underlined magenta define RM=#b16286-7 # Reversemagenta define C=#83a598 # Cyan define BC=#83a598-1 # Bold cyan define DC=#83a598-2 # Dimmed cyan define RC=#83a598-7 # Reverse cyan define UDC=4;02;38;2;131;165;152 # Underlined dimmed cyan define BDC=1;02;38;2;131;165;152 # Bold dimmed cyan define O=#d65d0e # Orange define BO=#d65d0e-1 # Bold orange define DO=#d65d0e-2 # Dimmed orange define BO2=#fe8019-1 # Bold orange (brighter) define Gy=#a89984 # Gray define BGy=#a89984-1 # Bold gray define DGy=#a89984-2 # Dimmed gray define DW=#ebdbb2-2 # Dimmed white define UW=#ebdbb2-4 # Dimmed white define UDW=4;2;38;2;235;219;178 # Underlined dimmed white define KO=38;2;40;40;40;48;2;214;93;14 # Black on orange define WK=38;2;235;219;178;48;2;40;40;40 # White on black define IO=#fabd2f-3 # Italic gold define KR=38;2;40;40;40;48;2;204;36;29 # Black on red define WB=38;2;235;219;178;48;2;69;133;136 # White on blue define WC=38;2;235;219;178;48;2;251;73;52 # White on cyan define WR=38;2;235;219;178;48;2;251;73;52 # White on red define IWB=3;38;2;235;219;178;48;2;69;133;136 # Italic white on blue define GK=38;2;184;187;38;48;2;67;76;94 # Green on black define BGK=1;38;2;184;187;38;48;2;67;76;94 # Bold Green on black define ARCHIVE=#fe8019-1 # Bold orange define AUDIO=#d79921-1 # Bold yellow define CODE=#98971a # Green define DOC=#b16286 # Magenta define EBOOK=#fb4934-1 # Bold red define IMAGE=#b8bb26 # Green define MARKUP=#d79921 # Yellow define TEMP=#ebdbb2-2 # Dimmed white define VIDEO=#b8bb26-1 # Bold green FiletypeColors="bd=BY:ca=KR:cd=IO:di=BA:ed=A:ee=GK:ef=DW:ex=BGK:fi=D:ln=BC:mh=RC:nd=BR:nf=:no=WK:or=C:ow=BG:pi=BM:sg=KO:so=BM:st=WB:su=WR:tw=IWB:uf=UDW:" InterfaceColors="ac=:db=O:dd=:de=C:df=D:dg=Y:dk=R:dl=B:dn=DW:do=C:dp=M:dr=Y:dw=R:dxd=G:dxr=C:dz=:el=BR2:em=BM:fc=DGy:hb=C:hc=DR:hd=C:he=C:hn=D:hp=C:hq=Y:hr=R:hs=G:hv=G:lc=BC:li=BG:mi=BC:nm=BG:sb=DY:sc=DR:sd=:sf=UDC:sh=:si=BB:sp=DR:sx=DG:ti=BC:ts=UM:tt=BDC:tx=D:wc=BC:wm=BY:ws1=B:ws2=R:ws3=Y:ws4=G:ws5=C:ws6=C:ws7=C:ws8=C:xf=BM:xs=G:" ExtColors="*.7z=ARCHIVE:*.ace=ARCHIVE:*.alz=ARCHIVE:*.apk=ARCHIVE:*.arc=ARCHIVE:*.arj=ARCHIVE:*.bz=ARCHIVE:*.bz2=ARCHIVE:*.cab=ARCHIVE:*.cpio=ARCHIVE:*.deb=ARCHIVE:*.dmg=ARCHIVE:*.dwm=ARCHIVE:*.dz=ARCHIVE:*.ear=ARCHIVE:*.esd=ARCHIVE:*.gz=ARCHIVE:*.img=ARCHIVE:*.iso=ARCHIVE:*.jar=ARCHIVE:*.lha=ARCHIVE:*.lrz=ARCHIVE:*.lz=ARCHIVE:*.lz4=ARCHIVE:*.lzh=ARCHIVE:*.lzma=ARCHIVE:*.lzo=ARCHIVE:*.qcow=ARCHIVE:*.qcow2=ARCHIVE:*.rar=ARCHIVE:*.rpm=ARCHIVE:*.rz=ARCHIVE:*.sar=ARCHIVE:*.swm=ARCHIVE:*.t7z=ARCHIVE:*.tar=ARCHIVE:*.taz=ARCHIVE:*.tbz=ARCHIVE:*.tbz2=ARCHIVE:*.tgz=ARCHIVE:*.tlz=ARCHIVE:*.toast=ARCHIVE:*.txz=ARCHIVE:*.tz=ARCHIVE:*.tzo=ARCHIVE:*.tzst=ARCHIVE:*.vcd=ARCHIVE:*.vdi=ARCHIVE:*.vhd=ARCHIVE:*.vhdx=ARCHIVE:*.vmdk=ARCHIVE:*.vsix=ARCHIVE:*.war=ARCHIVE:*.wim=ARCHIVE:*.xz=ARCHIVE:*.z=ARCHIVE:*.zip=ARCHIVE:*.zoo=ARCHIVE:*.zst=ARCHIVE:*.aac=AUDIO:*.aif=AUDIO:*.aifc=AUDIO:*.aiff=AUDIO:*.alac=AUDIO:*.ape=AUDIO:*.au=AUDIO:*.flac=AUDIO:*.m4a=AUDIO:*.mid=AUDIO:*.midi=AUDIO:*.mka=AUDIO:*.mp3=AUDIO:*.ogg=AUDIO:*.opus=AUDIO:*.pcm=AUDIO:*.spx=AUDIO:*.wav=AUDIO:*.wma=AUDIO:*.wv=AUDIO:*.applescript=CODE:*.as=CODE:*.asa=CODE:*.awk=CODE:*.bash=CODE:*.c=CODE:*.c++=CODE:*.cabal=CODE:*.cc=CODE:*.cgi=CODE:*.clj=CODE:*.cp=CODE:*.cpp=CODE:*.cr=CODE:*.cs=CODE:*.csx=CODE:*.cxx=CODE:*.d=CODE:*.dart=CODE:*.def=CODE:*.di=CODE:*.dpr=CODE:*.el=CODE:*.elm=CODE:*.epp=CODE:*.erl=CODE:*.ex=CODE:*.exs=CODE:*.fish=CODE:*.fs=CODE:*.fsi=CODE:*.fsx=CODE:*.gd=CODE:*.go=CODE:*.gradle=CODE:*.groovy=CODE:*.gv=CODE:*.gvy=CODE:*.h=CODE:*.h++=CODE:*.hgrc=CODE:*.hh=CODE:*.hpp=CODE:*.hs=CODE:*.htc=CODE:*.hxx=CODE:*.inc=CODE:*.inl=CODE:*.ipp=CODE:*.ipynb=CODE:*.java=CODE:*.jl=CODE:*.js=CODE:*.jsx=CODE:*.kt=CODE:*.kts=CODE:*.lhs=CODE:*.lisp=CODE:*.ll=CODE:*.lua=CODE:*.m=CODE:*.matlab=CODE:*.mir=CODE:*.ml=CODE:*.mli=CODE:*.mn=CODE:*.nb=CODE:*.p=CODE:*.pas=CODE:*.php=CODE:*.pl=CODE:*.pm=CODE:*.pod=CODE:*.pp=CODE:*.pro=CODE:*.ps1=CODE:*.psd1=CODE:*.psm1=CODE:*.purs=CODE:*.py=CODE:*.r=CODE:*.rb=CODE:*.rs=CODE:*.sbt=CODE:*.scala=CODE:*.sh=CODE:*.swift=CODE:*.t=CODE:*.tcl=CODE:*.td=CODE:*.ts=CODE:*.tsx=CODE:*.vb=CODE:*.vsh=CODE:*.zig=CODE:*.zsh=CODE:*.abw=DOC:*.doc=DOC:*.docx=DOC:*.fodg:*.fodp=DOC:*.fods=DOC:*.fodt=DOC:*.odg=DOC:*.odp=DOC:*.ods=DOC:*.odt=DOC:*.pps=DOC:*.ppt=DOC:*.pptx=DOC:*.rtf=DOC:*.sxi=DOC:*.sxw=DOC:*.txt=DOC:*.xlr=DOC:*.xls=DOC:*.xlsx=DOC:*.azw=EBOOK:*.azw3=EBOOK:*.cb7=EBOOK:*.cba=EBOOK:*.cbr=EBOOK:*.cbt=EBOOK:*.cbz=EBOOK:*.djvu=EBOOK:*.epub=EBOOK:*.fb2=EBOOK:*.kf8=EBOOK:*.kfx=EBOOK:*.mobi=EBOOK:*.oxps=EBOOK:*.pdb=EBOOK:*.pdf=EBOOK:*.ps=EBOOK:*.xps=EBOOK:*.avif=IMAGE:*.bmp=IMAGE:*.gif=IMAGE:*.ico=IMAGE:*.jpeg=IMAGE:*.jpg=IMAGE:*.jxl=IMAGE:*.mjpeg=IMAGE:*.mjpg=IMAGE:*.mng=IMAGE:*.pbm=IMAGE:*.pcx=IMAGE:*.pgm=IMAGE:*.png=IMAGE:*.ppm=IMAGE:*.psd=IMAGE:*.svg=IMAGE:*.svgz=IMAGE:*.tga=IMAGE:*.tif=IMAGE:*.tiff=IMAGE:*.webp=IMAGE:*.xbm=IMAGE:*.xcf=IMAGE:*.xpm=IMAGE:*.css=MARKUP:*.htm=MARKUP:*.html=MARKUP:*.ltx=MARKUP:*.markdown=MARKUP:*.md=MARKUP:*.mdown=MARKUP:*.opf=MARKUP:*.rss=MARKUP:*.shtml=MARKUP:*.tex=MARKUP:*.xhtml=MARKUP:*.xml=MARKUP:*.aux=TEMP:*.bak=TEMP:*.bbl=TEMP:*.bc=TEMP:*.cache=TEMP:*.class=TEMP:*.git=TEMP:*.hi=TEMP:*.idx=TEMP:*.ilg=TEMP:*.ind=TEMP:*.la=TEMP:*.lo=TEMP:*.localized=TEMP:*.lock=TEMP:*.log=TEMP:*.o=TEMP:*.orig=TEMP:*.out=TEMP:*.pid=TEMP:*.pyc=TEMP:*.pyd=TEMP:*.pyo=TEMP:*.rej=TEMP:*.rlib=TEMP:*.sty=TEMP:*.swp=TEMP:*.tmp=TEMP:*.toc=TEMP:*.3gp=VIDEO:*.asf=VIDEO:*.avi=VIDEO:*.cgm=VIDEO:*.dl=VIDEO:*.emf=VIDEO:*.flc=VIDEO:*.fli=VIDEO:*.flv=VIDEO:*.h264=VIDEO:*.heics=VIDEO:*.gl=VIDEO:*.m2ts=VIDEO:*.m2v=VIDEO:*.m4v=VIDEO:*.mkv=VIDEO:*.mov=VIDEO:*.mp4=VIDEO:*.mp4v=VIDEO:*.mpeg=VIDEO:*.mpg=VIDEO:*.nuv=VIDEO:*.ogm=VIDEO:*.ogv=VIDEO:*.ogx=VIDEO:*.qt=VIDEO:*.rm=VIDEO:*.rmvb=VIDEO:*.vob=VIDEO:*.webm=VIDEO:*.wmv=VIDEO:*.xwd=VIDEO:*.yuv=VIDEO: DateShades="3,#ff0000-2,#ffffff,#dadada,#bcbcbc,#9e9e9e,#808080" SizeShades="3,#fb4934-2,#83a598,#9ea136,#d79921,#d65d0e,#fb4934" DirIconColor="Y" Prompt="\[\e[0;38;2;235;219;178m\][\S\[\e[0;38;2;235;219;178m\]]\l \A \u:\H \[\e[1;38;2;142;192;124m\]\w\n\[\e[0;38;2;235;219;178m\]<\z\[\e[0;38;2;235;219;178m\]> \[\e[0;38;2;69;133;136m\]\$ \[\e[0;38;2;235;219;178m\]" Notifications=true EnableWarningPrompt=true WarningPrompt="\[\e[0;1;38;2;251;73;52m\](!)\[\e[0;2;38;2;235;219;178m\] > " DividingLine="-" FzfTabOptions="--color='16,prompt:#83a598,fg+:-1,pointer:#cc241d,hl:#b8bb26,hl+:#b8bb26,gutter:-1,marker:#b8bb26:bold,query:#ebdbb2,border:8' --marker='*' --bind tab:accept,right:accept,left:abort,alt-p:toggle-preview,change:top,alt-up:preview-page-up,alt-down:preview-page-down --inline-info --tiebreak=begin --layout=reverse-list --preview-window=wrap,border-left" clifm-1.26.3/misc/colors/jellybeans-vivid.clifm000066400000000000000000000146571506632037700214420ustar00rootroot00000000000000# Theme file for Clifm # Theme name: jellybeans-vivid (based on vivid(1)) # Author: L. Abramovich # License: GPL2+ define D=0 # Default (reset attributes) define DIM=2 # Dimmed define UD=4;2 # Underlined dimmed define R=31 # Red define BR=1;31 # Bold red define DR=2;31 # Dimmed red define R2=#cf6a4c # Dark red define BR2=#cf6a4c-2 # Dimmed dark red define G=32 # Green define BG=1;32 # Bold green define DG=2;32 # Dimmed green define G2=#799d6a # Pale Green define Y=33 # Yellow define BY=1;33 # Bold yellow define DY=2;33 # Dimmed yellow define Y2=#fad07a # Yellow2 define B=34 # Blue define BB=1;34 # Bold blue define B2=#c6b6ee # Light Blue define DB2=#c6b6ee-2 # Dimmed light blue define M=35 # Magenta define DM=2;35 # Dimmed magenta define UM=4;35 # Underlined magenta define M2=#f0a0c0 # Magenta2 define C=36 # Cyan define BC=1;36 # Bold cyan define UDC=4;02;36 # Underlined dimmed cyan define BDC=1;02;36 # Bold dimmed cyan define C2=#668779 # Cyan2 define DW=2;37 # Dimmed white define BO2=#ffb964-1 # Bold orange2 define DO2=#ffb964-2 # Dimmed orange2 define YR2=38;2;250;208;122;48;2;144;32;32 # Yellow on red define ARCHIVE=#fad07a-4 # Underlined yellow define AUDIO=#dad085 # Pale yellow define CODE=#8197bf # Pale blue define DOC=#668799 # Bluish green define EBOOK=#668779 # Cyan define IMAGE=#dad085 # Pale yellow define TEMP=#888888-3 # Italic gray define VIDEO=#dad085 # Pale yellow FiletypeColors="bd=R2:ca=D:cd=R2:di=B2:do=M2:ed=DB2:ee=DO2:ef=DIM:ex=BO2:fi=D:ln=Y2:mh=D:nd=BR2:nf=:no=D:or=YR2:ow=D:pi=M2:sg=D:so=M2:st=D:su=D:tw=D:" InterfaceColors="ac=:db=M:dd=:de=G2:df=D:dg=B2:dk=R2:dl=B:dn=DW:do=C:dp=:dr=Y2:dw=R2:dxd=G2:dxr=C2:dz=:el=Y:em=BR:fc=DB2:hb=C:hc=DR:hd=C:he=C:hn=D:hp=C:hq=Y:hr=R:hs=G:hv=G:lc=Y2:li=BG:mi=BC:nm=BG:sb=DY:sc=DR:sd=:sf=UDC:sh=:si=BB:sp=DR:sx=DG:ti=BC:ts=UM:tt=BDC:tx=D:wc=BC:wm=BY:ws1=B:ws2=R:ws3=Y:ws4=G:ws5=C:ws6=C:ws7=C:ws8=C:xf=BR:xs=G:" ExtColors="*.7z=ARCHIVE:*.ace=ARCHIVE:*.alz=ARCHIVE:*.apk=ARCHIVE:*.arc=ARCHIVE:*.arj=ARCHIVE:*.bz=ARCHIVE:*.bz2=ARCHIVE:*.cab=ARCHIVE:*.cpio=ARCHIVE:*.deb=ARCHIVE:*.dmg=ARCHIVE:*.dwm=ARCHIVE:*.dz=ARCHIVE:*.ear=ARCHIVE:*.esd=ARCHIVE:*.gz=ARCHIVE:*.img=ARCHIVE:*.iso=ARCHIVE:*.jar=ARCHIVE:*.lha=ARCHIVE:*.lrz=ARCHIVE:*.lz=ARCHIVE:*.lz4=ARCHIVE:*.lzh=ARCHIVE:*.lzma=ARCHIVE:*.lzo=ARCHIVE:*.qcow=ARCHIVE:*.qcow2=ARCHIVE:*.rar=ARCHIVE:*.rpm=ARCHIVE:*.rz=ARCHIVE:*.sar=ARCHIVE:*.swm=ARCHIVE:*.t7z=ARCHIVE:*.tar=ARCHIVE:*.taz=ARCHIVE:*.tbz=ARCHIVE:*.tbz2=ARCHIVE:*.tgz=ARCHIVE:*.tlz=ARCHIVE:*.toast=ARCHIVE:*.txz=ARCHIVE:*.tz=ARCHIVE:*.tzo=ARCHIVE:*.tzst=ARCHIVE:*.vcd=ARCHIVE:*.vdi=ARCHIVE:*.vhd=ARCHIVE:*.vhdx=ARCHIVE:*.vmdk=ARCHIVE:*.vsix=ARCHIVE:*.war=ARCHIVE:*.wim=ARCHIVE:*.xz=ARCHIVE:*.z=ARCHIVE:*.zip=ARCHIVE:*.zoo=ARCHIVE:*.zst=ARCHIVE:*.aac=AUDIO:*.aif=AUDIO:*.aifc=AUDIO:*.aiff=AUDIO:*.alac=AUDIO:*.ape=AUDIO:*.au=AUDIO:*.flac=AUDIO:*.m4a=AUDIO:*.mid=AUDIO:*.midi=AUDIO:*.mka=AUDIO:*.mp3=AUDIO:*.ogg=AUDIO:*.opus=AUDIO:*.pcm=AUDIO:*.spx=AUDIO:*.wav=AUDIO:*.wma=AUDIO:*.wv=AUDIO:*.applescript=CODE:*.as=CODE:*.asa=CODE:*.awk=CODE:*.bash=CODE:*.c=CODE:*.c++=CODE:*.cabal=CODE:*.cc=CODE:*.cgi=CODE:*.clj=CODE:*.cp=CODE:*.cpp=CODE:*.cr=CODE:*.cs=CODE:*.csx=CODE:*.cxx=CODE:*.d=CODE:*.dart=CODE:*.def=CODE:*.di=CODE:*.dpr=CODE:*.el=CODE:*.elm=CODE:*.epp=CODE:*.erl=CODE:*.ex=CODE:*.exs=CODE:*.fish=CODE:*.fs=CODE:*.fsi=CODE:*.fsx=CODE:*.gd=CODE:*.go=CODE:*.gradle=CODE:*.groovy=CODE:*.gv=CODE:*.gvy=CODE:*.h=CODE:*.h++=CODE:*.hgrc=CODE:*.hh=CODE:*.hpp=CODE:*.hs=CODE:*.htc=CODE:*.hxx=CODE:*.inc=CODE:*.inl=CODE:*.ipp=CODE:*.ipynb=CODE:*.java=CODE:*.jl=CODE:*.js=CODE:*.jsx=CODE:*.kt=CODE:*.kts=CODE:*.lhs=CODE:*.lisp=CODE:*.ll=CODE:*.lua=CODE:*.m=CODE:*.matlab=CODE:*.mir=CODE:*.ml=CODE:*.mli=CODE:*.mn=CODE:*.nb=CODE:*.p=CODE:*.pas=CODE:*.php=CODE:*.pl=CODE:*.pm=CODE:*.pod=CODE:*.pp=CODE:*.pro=CODE:*.ps1=CODE:*.psd1=CODE:*.psm1=CODE:*.purs=CODE:*.py=CODE:*.r=CODE:*.rb=CODE:*.rs=CODE:*.sbt=CODE:*.scala=CODE:*.sh=CODE:*.swift=CODE:*.t=CODE:*.tcl=CODE:*.td=CODE:*.ts=CODE:*.tsx=CODE:*.vb=CODE:*.vsh=CODE:*.zig=CODE:*.zsh=CODE:*.abw=DOC:*.doc=DOC:*.docx=DOC:*.fodg:*.fodp=DOC:*.fods=DOC:*.fodt=DOC:*.odg=DOC:*.odp=DOC:*.ods=DOC:*.odt=DOC:*.pps=DOC:*.ppt=DOC:*.pptx=DOC:*.rtf=DOC:*.sxi=DOC:*.sxw=DOC:*.txt=DOC:*.xlr=DOC:*.xls=DOC:*.xlsx=DOC:*.azw=EBOOK:*.azw3=EBOOK:*.cb7=EBOOK:*.cba=EBOOK:*.cbr=EBOOK:*.cbt=EBOOK:*.cbz=EBOOK:*.djvu=EBOOK:*.epub=EBOOK:*.fb2=EBOOK:*.kf8=EBOOK:*.kfx=EBOOK:*.mobi=EBOOK:*.oxps=EBOOK:*.pdb=EBOOK:*.pdf=EBOOK:*.ps=EBOOK:*.xps=EBOOK:*.avif=IMAGE:*.bmp=IMAGE:*.gif=IMAGE:*.ico=IMAGE:*.jpeg=IMAGE:*.jpg=IMAGE:*.jxl=IMAGE:*.mjpeg=IMAGE:*.mjpg=IMAGE:*.mng=IMAGE:*.pbm=IMAGE:*.pcx=IMAGE:*.pgm=IMAGE:*.png=IMAGE:*.ppm=IMAGE:*.psd=IMAGE:*.svg=IMAGE:*.svgz=IMAGE:*.tga=IMAGE:*.tif=IMAGE:*.tiff=IMAGE:*.webp=IMAGE:*.xbm=IMAGE:*.xcf=IMAGE:*.xpm=IMAGE:*.css=MARKUP:*.htm=MARKUP:*.html=MARKUP:*.ltx=MARKUP:*.markdown=MARKUP:*.md=MARKUP:*.mdown=MARKUP:*.opf=MARKUP:*.rss=MARKUP:*.shtml=MARKUP:*.tex=MARKUP:*.xhtml=MARKUP:*.xml=MARKUP:*.aux=TEMP:*.bak=TEMP:*.bbl=TEMP:*.bc=TEMP:*.cache=TEMP:*.class=TEMP:*.git=TEMP:*.hi=TEMP:*.idx=TEMP:*.ilg=TEMP:*.ind=TEMP:*.la=TEMP:*.lo=TEMP:*.localized=TEMP:*.lock=TEMP:*.log=TEMP:*.o=TEMP:*.orig=TEMP:*.out=TEMP:*.pid=TEMP:*.pyc=TEMP:*.pyd=TEMP:*.pyo=TEMP:*.rej=TEMP:*.rlib=TEMP:*.sty=TEMP:*.swp=TEMP:*.tmp=TEMP:*.toc=TEMP:*.3gp=VIDEO:*.asf=VIDEO:*.avi=VIDEO:*.cgm=VIDEO:*.dl=VIDEO:*.emf=VIDEO:*.flc=VIDEO:*.fli=VIDEO:*.flv=VIDEO:*.h264=VIDEO:*.heics=VIDEO:*.gl=VIDEO:*.m2ts=VIDEO:*.m2v=VIDEO:*.m4v=VIDEO:*.mkv=VIDEO:*.mov=VIDEO:*.mp4=VIDEO:*.mp4v=VIDEO:*.mpeg=VIDEO:*.mpg=VIDEO:*.nuv=VIDEO:*.ogm=VIDEO:*.ogv=VIDEO:*.ogx=VIDEO:*.qt=VIDEO:*.rm=VIDEO:*.rmvb=VIDEO:*.vob=VIDEO:*.webm=VIDEO:*.wmv=VIDEO:*.xwd=VIDEO:*.yuv=VIDEO:" DateShades="3,#cf6a4c-2,#ffffff,#dadada,#bcbcbc,#9e9e9e,#808080" SizeShades="3,#cf6a4c-2,#c6b6ee,#799d67,#fad07a,#cf6a4c,#cf6a4c-1" DirIconColor="Y" Prompt="\[\e[0m\][\S\[\e[0m\]]\l \A \u:\H \[\e[0;36m\]\w\n\[\e[0m\]<\z\[\e[0m\]> \[\e[0;34m\]\$ \[\e[0m\]" Notifications=true EnableWarningPrompt=true WarningPrompt="\[\e[0;1;31m\](!)\[\e[0;2m\] > " DividingLine="-" FzfTabOptions="--color='dark,prompt:6,fg+:-1,pointer:4,hl:2,hl+:2,gutter:-1,marker:2:bold,border:8' --marker='*' --bind tab:accept,right:accept,left:abort,alt-p:toggle-preview,change:top,alt-up:preview-page-up,alt-down:preview-page-down --tiebreak=begin --inline-info --layout=reverse-list --preview-window=wrap,border-left" clifm-1.26.3/misc/colors/light.clifm000066400000000000000000000153361506632037700172750ustar00rootroot00000000000000# Theme file for Clifm # Theme name: light # Author: L. Abramovich # License: GPL2+ define D=0 # Default (reset attributes) define BD=1 # Default bold define K=30 # Black define BDK=1;2;30 # Bold dimmed black define R=31 # Red define BR=1;31 # Bold red define DR=2;31 # Dimmed red define UR=4;31 # Underlined red define UBR=1;4;31 # Underlined bold red define R2=91 # Bright red define DR2=2;91 # Dimmed bright red define G=32 # Green define BG=1;32 # Bold green define DG=2;32 # Dimmed green define Y=33 # Yellow define BY=1;33 # Bold yellow define DY=2;33 # Dimmed yellow define BDY=1;2;33 # Bold dimmed yellow define B=34 # Blue define BB=1;34 # Bold blue define DB=2;34 # Dimmed blue define M=35 # Magenta define BM=1;35 # Bold magenta define DM=2;35 # Dimmed magenta define BDM=1;2;35 # Bold dimmed magenta define C=36 # Cyan define BC=1;36 # Bold cyan define DC=2;36 # Dimmed cyan define BDC=1;2;36 # Bold dimmed cyan define UDC=4;2;36 # Underlined dimmed cyan define DW=2;37 # Dimmed white define WR=37;41 # White on red define KY=30;43 # Black on yellow define KR=30;41 # Black on red define KG=30;42 # Black on green define KC=30;46 # Black on cyan define BlGr=34;42 # Blue on green define WB=37;44 # White on blue define URW=4;31;47 # Underlined red on white define URK=4;31;40 # Underlined red on black define ARCHIVE=1;31 # Bold red define AUDIO=2;4;36 # Dimmed underlined cyan define CODE=1 # Default bold define DOC=2;33 # Dimmed yellow define EBOOK=31 # Red define IMAGE=35 # Magenta define MARKUP=2;4;33 # Dimmed underlined yellow define TEMP=2;37 # Dimmed white define VIDEO=1;35 # Bold magenta FiletypeColors="bd=BDY:ca=KR:cd=BDK:di=BB:ed=B:ee=DG:ef=DW:ex=BG:fi=K:ln=BDC:mh=KC:nd=UBR:nf=:no=URW:or=UDC:ow=BlGr:pi=DM:sg=KY:so=M:st=WB:su=WR:tw=KG:uf=URK:" InterfaceColors="ac=:db=K:dd=:de=M:df=K:dg=DG:dk=R:dl=DB:dn=DW:do=C:dp=M:dr=Y:dw=R:dxd=G:dxr=G:dz=:el=DG:em=R:fc=DW:hb=C:hc=DR:hd=C:he=C:hn=D:hp=C:hq=Y:hr=R:hs=G:hv=G:lc=BR:li=G:mi=BDM:nm=G:sb=DY:sc=DR:sf=UDC:sh=DW:si=B:sp=DR:sx=DG:sz=UDC:ti=C:ts=UR:tt=BDC:tx=D:wc=BD:wm=Y:ws1=B:ws2=R:ws3=Y:ws4=G:ws5=C:ws6=C:ws7=C:ws8=C:xf=R:xs=DG:" ExtColors="*.7z=ARCHIVE:*.ace=ARCHIVE:*.alz=ARCHIVE:*.apk=ARCHIVE:*.arc=ARCHIVE:*.arj=ARCHIVE:*.bz=ARCHIVE:*.bz2=ARCHIVE:*.cab=ARCHIVE:*.cpio=ARCHIVE:*.deb=ARCHIVE:*.dmg=ARCHIVE:*.dwm=ARCHIVE:*.dz=ARCHIVE:*.ear=ARCHIVE:*.esd=ARCHIVE:*.gz=ARCHIVE:*.img=ARCHIVE:*.iso=ARCHIVE:*.jar=ARCHIVE:*.lha=ARCHIVE:*.lrz=ARCHIVE:*.lz=ARCHIVE:*.lz4=ARCHIVE:*.lzh=ARCHIVE:*.lzma=ARCHIVE:*.lzo=ARCHIVE:*.qcow=ARCHIVE:*.qcow2=ARCHIVE:*.rar=ARCHIVE:*.rpm=ARCHIVE:*.rz=ARCHIVE:*.sar=ARCHIVE:*.swm=ARCHIVE:*.t7z=ARCHIVE:*.tar=ARCHIVE:*.taz=ARCHIVE:*.tbz=ARCHIVE:*.tbz2=ARCHIVE:*.tgz=ARCHIVE:*.txz=ARCHIVE:*.tlz=ARCHIVE:*.toast=ARCHIVE:*.tz=ARCHIVE:*.tzo=ARCHIVE:*.tzst=ARCHIVE:*.vcd=ARCHIVE:*.vdi=ARCHIVE:*.vhd=ARCHIVE:*.vhdx=ARCHIVE:*.vmdk=ARCHIVE:*.vsix=ARCHIVE:*.war=ARCHIVE:*.wim=ARCHIVE:*.xz=ARCHIVE:*.z=ARCHIVE:*.zip=ARCHIVE:*.zoo=ARCHIVE:*.zst=ARCHIVE:*.aac=AUDIO:*.aif=AUDIO:*.aifc=AUDIO:*.aiff=AUDIO:*.alac=AUDIO:*.ape=AUDIO:*.au=AUDIO:*.flac=AUDIO:*.m4a=AUDIO:*.mid=AUDIO:*.midi=AUDIO:*.mka=AUDIO:*.mp3=AUDIO:*.ogg=AUDIO:*.opus=AUDIO:*.pcm=AUDIO:*.spx=AUDIO:*.wav=AUDIO:*.wma=AUDIO:*.wv=AUDIO:*.applescript=CODE:*.as=CODE:*.asa=CODE:*.awk=CODE:*.bash=CODE:*.c=CODE:*.c++=CODE:*.cabal=CODE:*.cc=CODE:*.cgi=CODE:*.clj=CODE:*.cp=CODE:*.cpp=CODE:*.cr=CODE:*.cs=CODE:*.csx=CODE:*.cxx=CODE:*.d=CODE:*.dart=CODE:*.def=CODE:*.di=CODE:*.dpr=CODE:*.el=CODE:*.elm=CODE:*.epp=CODE:*.erl=CODE:*.ex=CODE:*.exs=CODE:*.fish=CODE:*.fs=CODE:*.fsi=CODE:*.fsx=CODE:*.gd=CODE:*.go=CODE:*.gradle=CODE:*.groovy=CODE:*.gv=CODE:*.gvy=CODE:*.h=CODE:*.h++=CODE:*.hgrc=CODE:*.hh=CODE:*.hpp=CODE:*.hs=CODE:*.htc=CODE:*.hxx=CODE:*.inc=CODE:*.inl=CODE:*.ipp=CODE:*.ipynb=CODE:*.java=CODE:*.jl=CODE:*.js=CODE:*.jsx=CODE:*.kt=CODE:*.kts=CODE:*.lhs=CODE:*.lisp=CODE:*.ll=CODE:*.lua=CODE:*.m=CODE:*.matlab=CODE:*.mir=CODE:*.ml=CODE:*.mli=CODE:*.mn=CODE:*.nb=CODE:*.p=CODE:*.pas=CODE:*.php=CODE:*.pl=CODE:*.pm=CODE:*.pod=CODE:*.pp=CODE:*.pro=CODE:*.ps1=CODE:*.psd1=CODE:*.psm1=CODE:*.purs=CODE:*.py=CODE:*.r=CODE:*.rb=CODE:*.rs=CODE:*.sbt=CODE:*.scala=CODE:*.sh=CODE:*.swift=CODE:*.t=CODE:*.tcl=CODE:*.td=CODE:*.ts=CODE:*.tsx=CODE:*.vb=CODE:*.vsh=CODE:*.zig=CODE:*.zsh=CODE:*.abw=DOC:*.doc=DOC:*.docx=DOC:*.fodg:*.fodp=DOC:*.fods=DOC:*.fodt=DOC:*.odg=DOC:*.odp=DOC:*.ods=DOC:*.odt=DOC:*.pps=DOC:*.ppt=DOC:*.pptx=DOC:*.rtf=DOC:*.sxi=DOC:*.sxw=DOC:*.txt=DOC:*.xlr=DOC:*.xls=DOC:*.xlsx=DOC:*.azw=EBOOK:*.azw3=EBOOK:*.cb7=EBOOK:*.cba=EBOOK:*.cbr=EBOOK:*.cbt=EBOOK:*.cbz=EBOOK:*.djvu=EBOOK:*.epub=EBOOK:*.fb2=EBOOK:*.kf8=EBOOK:*.kfx=EBOOK:*.mobi=EBOOK:*.oxps=EBOOK:*.pdb=EBOOK:*.pdf=EBOOK:*.ps=EBOOK:*.xps=EBOOK:*.avif=IMAGE:*.bmp=IMAGE:*.gif=IMAGE:*.ico=IMAGE:*.jpg=IMAGE:*.jpeg=IMAGE:*.jxl=IMAGE:*.mjpeg=IMAGE:*.mjpg=IMAGE:*.mng=IMAGE:*.pbm=IMAGE:*.pcx=IMAGE:*.pgm=IMAGE:*.png=IMAGE:*.ppm=IMAGE:*.psd=IMAGE:*.svg=IMAGE:*.svgz=IMAGE:*.tga=IMAGE:*.tif=IMAGE:*.tiff=IMAGE:*.webp=IMAGE:*.xbm=IMAGE:*.xcf=IMAGE:*.xpm=IMAGE:*.css=MARKUP:*.htm=MARKUP:*.html=MARKUP:*.ltx=MARKUP:*.markdown=MARKUP:*.md=MARKUP:*.mdown=MARKUP:*.opf=MARKUP:*.rss=MARKUP:*.shtml=MARKUP:*.tex=MARKUP:*.xhtml=MARKUP:*.xml=MARKUP:*.aux=TEMP:*.bak=TEMP:*.bbl=TEMP:*.bc=TEMP:*.cache=TEMP:*.class=TEMP:*.git=TEMP:*.hi=TEMP:*.idx=TEMP:*.ilg=TEMP:*.ind=TEMP:*.la=TEMP:*.lo=TEMP:*.localized=TEMP:*.lock=TEMP:*.log=TEMP:*.o=TEMP:*.orig=TEMP:*.out=TEMP:*.pid=TEMP:*.pyc=TEMP:*.pyd=TEMP:*.pyo=TEMP:*.rej=TEMP:*.rlib=TEMP:*.sty=TEMP:*.swp=TEMP:*.tmp=TEMP:*.toc=TEMP:*.3gp=VIDEO:*.asf=VIDEO:*.avi=VIDEO:*.cgm=VIDEO:*.dl=VIDEO:*.emf=VIDEO:*.flc=VIDEO:*.fli=VIDEO:*.flv=VIDEO:*.heics=VIDEO:*.h264=VIDEO:*.gl=VIDEO:*.m2v=VIDEO:*.m2ts=VIDEO:*.m4v=VIDEO:*.mkv=VIDEO:*.mov=VIDEO:*.mp4=VIDEO:*.mp4v=VIDEO:*.mpg=VIDEO:*.mpeg=VIDEO:*.nuv=VIDEO:*.ogm=VIDEO:*.ogv=VIDEO:*.ogx=VIDEO:*.qt=VIDEO:*.rm=VIDEO:*.rmvb=VIDEO:*.vob=VIDEO:*.webm=VIDEO:*.wmv=VIDEO:*.xwd=VIDEO:*.yuv=VIDEO:" DirIconColor="Y" DateShades="1,31-2,34-1,34,34-2,34-2,34-2" SizeShades="1,31-2,35,32-2,33-2,31,34-1" Prompt="\[\e[0m\][\S\[\e[0m\]]\l \A \u:\H \[\e[0;34m\]\w\n\[\e[0m\]<\z\[\e[0m\]> \[\e[0;34m\]\$ \[\e[0m\]" Notifications=true EnableWarningPrompt=true WarningPrompt="\[\e[0;2;31m\](!) > " DividingLine="-" FzfTabOptions="--color='16,prompt:4,bg+:248,fg+:-1,pointer:4,hl:5:dim,hl+:5:dim:underline,gutter:-1,marker:2,info:248,border:8' --marker='*' --bind tab:accept,right:accept,left:abort,alt-p:toggle-preview,change:top,alt-up:preview-page-up,alt-down:preview-page-down --tiebreak=begin --inline-info --layout=reverse-list --preview-window=wrap,border-left" clifm-1.26.3/misc/colors/molokai.clifm000066400000000000000000000170331506632037700176150ustar00rootroot00000000000000# Theme file for Clifm # Theme name: molokai (based on vivid(1)) # Author: L. Abramovich # License: GPL2+ define D=0 # Default (reset attributes) define BD=1 # Bold define R=#f92672 # Red define BR=#f92672-1 # Bold red define DR=#f92672-2 # Dimmed red define UR=#f92672-4 # Underlined red define RR=#f92672-7 # Reverse red define UBR=4;1;38;2;249;38;114 # Underlined bold red define G=#00ff87 # Green define BG=#00ff87-1 # Bold green define DG=#00ff87-2 # Dimmed green define G2=#a6e22e # Green2 define Y=#e6db74 # Yellow define BY=#e6db74-1 # Bold yellow define DY=#e6db74-2 # Dimmed yellow define Y2=#e2d139 # Brigther yellow define B=#66d9ef # Blue define BB=#66d9ef-1 # Bold blue define DB=#66d9ef-2 # Dimmed blue define UDB=4;2;38;2;102;217;239 # Underlined dimmed blue define M=35 # Magenta (4-bit) define BM=1;35 # Bold Magenta define UM=4;35 # Underlined magenta define C=36 # Cyan (4-bit) define BC=1;36 # Bold cyan define DC=2;36 # Dimmed cyan define RC=7;36 # Reverse cyan define UDC=4;2;36 # Underlined dimmed cyan define BDC=1;2;36 # Bold dimmed cyan define O=#fd971f # Orange define BO=#fd971f-1 # Bold orange define DO=#fd971f-2 # Dimmed orange define DW=2;37 # Dimmed white (4-bit) define KR=38;2;0;0;0;48;2;255;74;68 # Black on red define BK=38;2;102;217;239;48;2;51;51;51 # Blue on black define UKM=4;38;2;0;0;0;48;2;249;38;114 # Underlined black on magenta define MK=38;2;249;38;114;48;2;51;51;51 # Magenta on black define BMK=1;38;2;249;38;114;48;2;51;51;51 # Bold magenta on black define WR=38;2;230;230;230;48;2;255;74;68 # White on red define KY=38;2;0;0;0;48;2;230;219;116 # Black on yellow define KG=38;2;0;0;0;48;2;0;255;135 # Black on green define UBlR=4;38;2;102;217;239;48;2;255;74;68 # Underlined blue on red define RBl=38;2;255;74;68;48;2;102;217;239 # Red on blue define ARCHIVE=38;2;255;74;68;48;2;51;51;51 # Red on black define AUDIO=#fd971f # Orange define CODE=#f92672 # Red define DOC=#e6db74 # Yellow define EBOOK=#e6db74-1 # Bold yellow define IMAGE=#fd971f # Orange define MARKUP=#e2d139 # Yellow2 define TEMP=2;37 # Dimmed white (4-bit) define VIDEO=#fd971f-1 # Bold orange FiletypeColors="bd=BD:ca=KR:cd=BD:di=B:ed=DB:ef=2:ex=BR:fi=0:ln=R:mh=RC:nd=UBR:nf=:no=UBlR:or=UKM:ow=BK:pi=BMK:sg=KY:so=MK:st=KG:su=WR:tw=RBl:uf=UBlR:" InterfaceColors="ac=:db=Y:dd=:de=C:df=D:dg=O:dk=R:dl=DW:dn=DW:do=C:dp=M:dr=Y:dw=R:dxd=G:dxr=C:dz=:el=O:em=BR:fc=DB:hb=C:hc=DR:hd=C:he=C:hn=D:hp=C:hq=Y:hr=R:hs=G:hv=G:hw=R:lc=R:li=BG:mi=BC:nm=BG:sb=DY:sc=DR:sd=:sf=UDC:sh=:si=BB:sp=DR:sx=DG:ti=BC:ts=UM:tt=BDC:tx=D:wc=BC:wm=BY:ws1=B:ws2=R:ws3=Y:ws4=G:ws5=C:ws6=C:ws7=C:ws8=C:xf=BR:xs=G:" ExtColors="*.7z=ARCHIVE:*.ace=ARCHIVE:*.alz=ARCHIVE:*.apk=ARCHIVE:*.arc=ARCHIVE:*.arj=ARCHIVE:*.bz=ARCHIVE:*.bz2=ARCHIVE:*.cab=ARCHIVE:*.cpio=ARCHIVE:*.deb=ARCHIVE:*.dmg=ARCHIVE:*.dwm=ARCHIVE:*.dz=ARCHIVE:*.ear=ARCHIVE:*.esd=ARCHIVE:*.gz=ARCHIVE:*.img=ARCHIVE:*.iso=ARCHIVE:*.jar=ARCHIVE:*.lha=ARCHIVE:*.lrz=ARCHIVE:*.lz=ARCHIVE:*.lz4=ARCHIVE:*.lzh=ARCHIVE:*.lzma=ARCHIVE:*.lzo=ARCHIVE:*.qcow=ARCHIVE:*.qcow2=ARCHIVE:*.rar=ARCHIVE:*.rpm=ARCHIVE:*.rz=ARCHIVE:*.sar=ARCHIVE:*.swm=ARCHIVE:*.t7z=ARCHIVE:*.tar=ARCHIVE:*.taz=ARCHIVE:*.tbz=ARCHIVE:*.tbz2=ARCHIVE:*.tgz=ARCHIVE:*.tlz=ARCHIVE:*.toast=ARCHIVE:*.txz=ARCHIVE:*.tz=ARCHIVE:*.tzo=ARCHIVE:*.tzst=ARCHIVE:*.vcd=ARCHIVE:*.vdi=ARCHIVE:*.vhd=ARCHIVE:*.vhdx=ARCHIVE:*.vmdk=ARCHIVE:*.vsix=ARCHIVE:*.war=ARCHIVE:*.wim=ARCHIVE:*.xz=ARCHIVE:*.z=ARCHIVE:*.zip=ARCHIVE:*.zoo=ARCHIVE:*.zst=ARCHIVE:*.aac=AUDIO:*.aif=AUDIO:*.aifc=AUDIO:*.aiff=AUDIO:*.alac=AUDIO:*.ape=AUDIO:*.au=AUDIO:*.flac=AUDIO:*.m4a=AUDIO:*.mid=AUDIO:*.midi=AUDIO:*.mka=AUDIO:*.mp3=AUDIO:*.ogg=AUDIO:*.opus=AUDIO:*.pcm=AUDIO:*.spx=AUDIO:*.wav=AUDIO:*.wma=AUDIO:*.wv=AUDIO:*.applescript=CODE:*.as=CODE:*.asa=CODE:*.awk=CODE:*.bash=CODE:*.c=CODE:*.c++=CODE:*.cabal=CODE:*.cc=CODE:*.cgi=CODE:*.clj=CODE:*.cp=CODE:*.cpp=CODE:*.cr=CODE:*.cs=CODE:*.csx=CODE:*.cxx=CODE:*.d=CODE:*.dart=CODE:*.def=CODE:*.di=CODE:*.dpr=CODE:*.el=CODE:*.elm=CODE:*.epp=CODE:*.erl=CODE:*.ex=CODE:*.exs=CODE:*.fish=CODE:*.fs=CODE:*.fsi=CODE:*.fsx=CODE:*.gd=CODE:*.go=CODE:*.gradle=CODE:*.groovy=CODE:*.gv=CODE:*.gvy=CODE:*.h=CODE:*.h++=CODE:*.hgrc=CODE:*.hh=CODE:*.hpp=CODE:*.hs=CODE:*.htc=CODE:*.hxx=CODE:*.inc=CODE:*.inl=CODE:*.ipp=CODE:*.ipynb=CODE:*.java=CODE:*.jl=CODE:*.js=CODE:*.jsx=CODE:*.kt=CODE:*.kts=CODE:*.lhs=CODE:*.lisp=CODE:*.ll=CODE:*.lua=CODE:*.m=CODE:*.matlab=CODE:*.mir=CODE:*.ml=CODE:*.mli=CODE:*.mn=CODE:*.nb=CODE:*.p=CODE:*.pas=CODE:*.php=CODE:*.pl=CODE:*.pm=CODE:*.pod=CODE:*.pp=CODE:*.pro=CODE:*.ps1=CODE:*.psd1=CODE:*.psm1=CODE:*.purs=CODE:*.py=CODE:*.r=CODE:*.rb=CODE:*.rs=CODE:*.sbt=CODE:*.scala=CODE:*.sh=CODE:*.swift=CODE:*.t=CODE:*.tcl=CODE:*.td=CODE:*.ts=CODE:*.tsx=CODE:*.vb=CODE:*.vsh=CODE:*.zig=CODE:*.zsh=CODE:*.abw=DOC:*.doc=DOC:*.docx=DOC:*.fodg:*.fodp=DOC:*.fods=DOC:*.fodt=DOC:*.odg=DOC:*.odp=DOC:*.ods=DOC:*.odt=DOC:*.pps=DOC:*.ppt=DOC:*.pptx=DOC:*.rtf=DOC:*.sxi=DOC:*.sxw=DOC:*.txt=DOC:*.xlr=DOC:*.xls=DOC:*.xlsx=DOC:*.azw=EBOOK:*.azw3=EBOOK:*.cb7=EBOOK:*.cba=EBOOK:*.cbr=EBOOK:*.cbt=EBOOK:*.cbz=EBOOK:*.djvu=EBOOK:*.epub=EBOOK:*.fb2=EBOOK:*.kf8=EBOOK:*.kfx=EBOOK:*.mobi=EBOOK:*.oxps=EBOOK:*.pdb=EBOOK:*.pdf=EBOOK:*.ps=EBOOK:*.xps=EBOOK:*.avif=IMAGE:*.bmp=IMAGE:*.gif=IMAGE:*.ico=IMAGE:*.jpeg=IMAGE:*.jpg=IMAGE:*.jxl=IMAGE:*.mjpeg=IMAGE:*.mjpg=IMAGE:*.mng=IMAGE:*.pbm=IMAGE:*.pcx=IMAGE:*.pgm=IMAGE:*.png=IMAGE:*.ppm=IMAGE:*.psd=IMAGE:*.svg=IMAGE:*.svgz=IMAGE:*.tga=IMAGE:*.tif=IMAGE:*.tiff=IMAGE:*.webp=IMAGE:*.xbm=IMAGE:*.xcf=IMAGE:*.xpm=IMAGE:*.css=MARKUP:*.htm=MARKUP:*.html=MARKUP:*.ltx=MARKUP:*.markdown=MARKUP:*.md=MARKUP:*.mdown=MARKUP:*.opf=MARKUP:*.rss=MARKUP:*.shtml=MARKUP:*.tex=MARKUP:*.xhtml=MARKUP:*.xml=MARKUP:*.aux=TEMP:*.bak=TEMP:*.bbl=TEMP:*.bc=TEMP:*.cache=TEMP:*.class=TEMP:*.git=TEMP:*.hi=TEMP:*.idx=TEMP:*.ilg=TEMP:*.ind=TEMP:*.la=TEMP:*.lo=TEMP:*.localized=TEMP:*.lock=TEMP:*.log=TEMP:*.o=TEMP:*.orig=TEMP:*.out=TEMP:*.pid=TEMP:*.pyc=TEMP:*.pyd=TEMP:*.pyo=TEMP:*.rej=TEMP:*.rlib=TEMP:*.sty=TEMP:*.swp=TEMP:*.tmp=TEMP:*.toc=TEMP:*.3gp=VIDEO:*.asf=VIDEO:*.avi=VIDEO:*.cgm=VIDEO:*.dl=VIDEO:*.emf=VIDEO:*.flc=VIDEO:*.fli=VIDEO:*.flv=VIDEO:*.h264=VIDEO:*.heics=VIDEO:*.gl=VIDEO:*.m2ts=VIDEO:*.m2v=VIDEO:*.m4v=VIDEO:*.mkv=VIDEO:*.mov=VIDEO:*.mp4=VIDEO:*.mp4v=VIDEO:*.mpeg=VIDEO:*.mpg=VIDEO:*.nuv=VIDEO:*.ogm=VIDEO:*.ogv=VIDEO:*.ogx=VIDEO:*.qt=VIDEO:*.rm=VIDEO:*.rmvb=VIDEO:*.vob=VIDEO:*.webm=VIDEO:*.wmv=VIDEO:*.xwd=VIDEO:*.yuv=VIDEO:" DateShades="3,#ff0000-2,#ffffff,#dadada,#bcbcbc,#9e9e9e,#808080" SizeShades="3,#f92672-2,#02da74,#00ff87,#e6db74,#fd971f,#f92672" DirIconColor="Y" Prompt="\[\e[0m\][\S\[\e[0m\]]\l \A \u:\H \[\e[0;38;2;102;217;239m\]\w\n\[\e[0m\]<\z\[\e[0m\]> \[\e[0;38;2;0;255;135m\]\$ \[\e[0m\]" Notifications=true EnableWarningPrompt=true WarningPrompt="\[\e[0;1;38;2;249;38;114m\](!)\[\e[0;2m\] > " DividingLine="-" FzfTabOptions="--color='16,prompt:#66d9ef,fg+:-1,pointer:#f92672,hl:#00ff87,hl+:#00ff87,gutter:-1,marker:#00ff87,border:8' --marker='*' --bind tab:accept,right:accept,left:abort,alt-p:toggle-preview,change:top,alt-up:preview-page-up,alt-down:preview-page-down --tiebreak=begin --inline-info --layout=reverse-list --preview-window=wrap,border-left" clifm-1.26.3/misc/colors/nocolor.clifm000066400000000000000000000020321506632037700176260ustar00rootroot00000000000000# Theme file for Clifm # Theme name: nocolor # Author: L. Abramovich # License: GPL2+ FiletypeColors="di=0;1:nd=0;2:ed=0:fi=0:ef=0:nf=:ln=0;1;4:mh=0:or=0;2;4:pi=0:so=0:bd=0:cd=0:su=0:sg=0:ca=0:tw=0:ow=0:st=0:ex=0:ee=0:no=0:uf=0:" InterfaceColors="ac=0:db=0:de=0:df=0:dk=0:dl=0:dd=0:dg=0:dn=0:dr=0:do=0:dp=0:dw=0:dxd=0:dxr=0:dz=0:el=0:em=0:fc=0:hb=0:hc=0:hd=0:he=0:hn=0:hp=0:hq=0:hr=0:hs=0:hv=0:lc=0:li=0:mi=0:nm=0:si=0:sb=0;2:sc=0;2:sd=0;2:sf=0;2:sh=0;2:sp=0;2:sx=0;2:sz=0;2:ti=0:ts=0;4:tt=0:tx=0:wc=0:wm=0:ws1=0:ws2=0:ws3=0:ws4=0:ws5=0:ws6=0:ws7=0:ws8=0:xs=0:xf=0:" ExtColors="*.tar=0" DirIconColor=0 Prompt="clifm-no-color" #Prompt="\[\e[0m\]\I[\S\[\e[0m\]]\l \A \u:\H \w\n<\z> \$ \[\e[0m\]" #Notifications=true #EnableWarningPrompt=true #WarningPrompt="\[\e[0m\](!) > " DividingLine="-" FzfTabOptions="--color='bw' --marker='*' --bind tab:accept,right:accept,left:abort,alt-p:toggle-preview,change:top,alt-up:preview-page-up,alt-down:preview-page-down --tiebreak=begin --inline-info --layout=reverse-list --preview-window=wrap,border-left" clifm-1.26.3/misc/colors/nord.clifm000066400000000000000000000173561506632037700171340ustar00rootroot00000000000000# Theme file for Clifm # Theme name: nord (based on https://github.com/arcticicestudio/nord-xresources) # Author: L. Abramovich # License: GPL2+ define D=#d8dee9 # Default define R=#bf616a # Red define BR=#bf616a-1 # Bold red define DR=#bf616a-2 # Dimmed red define R2=#d08770 # Lighter red define BR2=#d08770-1 # Bold lighter red define G=#a3be8c # Green define BG=#a3be8c-1 # Bold green define DG=#a3be8c-2 # Dimmed green define RG=#a3be8c-7 # Reverse green define Y=#ebcb8b # Yellow define BY=#ebcb8b-1 # Bold yellow define DY=#ebcb8b-2 # Dimmed yellow define B=#81a1c1 # Blue define BB=#81a1c1-1 # Bold blue define DB=#81a1c1-2 # Dimmed blue define B2=#434c5e # Darker blue define M=#b48ead # Magenta define BM=#b48ead-1 # Bold magenta define DM=#b48ead-2 # Dimmed magenta define UM=#b48ead-4 # Underlined magenta define RM=#b48ead-7 # Underlined magenta define C=#8fbcbb # Cyan define BC=#8fbcbb-1 # Bold cyan define DC=#8fbcbb-2 # Dimmed cyan define RC=#8fbcbb-7 # Reverse cyan define UDC=4;02;38;2;143;188;187 # Underlined dimmed cyan define BDC=1;02;38;2;143;188;187 # Bold dimmed cyan define O=38;2;208;135;112 # Orange define BO=1;38;2;208;135;112 # Bold orange define W=#d8dee9 # White define DW=#d8dee9-2 # Dimmed white define BDW=1;38;2;216;222;233 # Bold dimmed white define UDW=4;2;38;2;216;222;233 # Underlined dimmed white define RW=38;2;191;97;106;48;2;216;222;233 # Red on white define BW=38;2;129;161;193;48;2;216;222;233 # Blue on white define WR=38;2;216;222;233;191;97;106 # White on red define KY=38;2;46;52;64;48;2;235;203;139 # Black on yellow define KR=38;2;46;52;64;48;2;191;97;106 # Black on red define WB=38;2;216;222;233;48;2;129;161;193 # White on blue define WG=1;38;2;216;222;233;48;2;163;190;140 # White on green define BlGr=38;2;129;161;193;48;2;67;76;94 # Blue on gray define MK=38;2;180;142;173;48;2;67;76;94 # Magenta on gray define BMK=1;38;2;180;142;173;48;2;67;76;94 # Bold magenta on gray define ARCHIVE=#8fbcbb-1 # Bold cyan define AUDIO=#d08770-1 # Bold orange define CODE=#ebcb8b # Yellow define DOC=1;38;2;235;203;139;48;2;67;76;94 # Yellow on gray define EBOOK=#bf616a-1 # Bold red define IMAGE=#b48ead # Magenta define MARKUP=1;38;2;208;135;112;48;2;67;76;94 # Orange on gray define TEMP=#d8dee9-2 # Dimmed white define VIDEO=#b48ead-1 # Bold magenta FiletypeColors="bd=BY:ca=KR:cd=BDW:di=BB:ed=DB:ee=O:ef=DW:ex=BO:fi=W:ln=BG:mh=RC:nd=BR:nf=:no=RW:or=RG:ow=BlGr:pi=MK:sg=KY:so=BMK:st=WB:su=WR:tw=WG:uf=UDW:" InterfaceColors="ac=:db=Y:dd=:de=C:df=D:dg=M:dk=R:dl=BDC:dn=DW:do=C:dp=M:dr=M:dw=R:dxd=G:dxr=C:dz=:el=BDC:em=BR:fc=DB:hb=C:hc=DR:hd=C:he=C:hn=D:hp=C:hq=Y:hr=R:hs=G:hv=G:hw=R:lc=G:li=BG:mi=BC:nm=BG:sb=DY:sc=DR:sd=:sf=UDC:sh=:si=BB:sp=DR:sx=DG:ti=BC:ts=UM:tt=BDC:tx=D:ws1=B:ws2=R:ws3=Y:ws4=G:ws5=C:ws6=C:ws7=C:ws8=C:wc=BC:wm=BY:xs=G:xf=BR:" ExtColors="*.7z=ARCHIVE:*.ace=ARCHIVE:*.alz=ARCHIVE:*.apk=ARCHIVE:*.arc=ARCHIVE:*.arj=ARCHIVE:*.bz=ARCHIVE:*.bz2=ARCHIVE:*.cab=ARCHIVE:*.cpio=ARCHIVE:*.deb=ARCHIVE:*.dmg=ARCHIVE:*.dwm=ARCHIVE:*.dz=ARCHIVE:*.ear=ARCHIVE:*.esd=ARCHIVE:*.gz=ARCHIVE:*.img=ARCHIVE:*.iso=ARCHIVE:*.jar=ARCHIVE:*.lha=ARCHIVE:*.lrz=ARCHIVE:*.lz=ARCHIVE:*.lz4=ARCHIVE:*.lzh=ARCHIVE:*.lzma=ARCHIVE:*.lzo=ARCHIVE:*.qcow=ARCHIVE:*.qcow2=ARCHIVE:*.rar=ARCHIVE:*.rpm=ARCHIVE:*.rz=ARCHIVE:*.sar=ARCHIVE:*.swm=ARCHIVE:*.t7z=ARCHIVE:*.tar=ARCHIVE:*.taz=ARCHIVE:*.tbz=ARCHIVE:*.tbz2=ARCHIVE:*.tgz=ARCHIVE:*.tlz=ARCHIVE:*.toast=ARCHIVE:*.txz=ARCHIVE:*.tz=ARCHIVE:*.tzo=ARCHIVE:*.tzst=ARCHIVE:*.vcd=ARCHIVE:*.vdi=ARCHIVE:*.vhd=ARCHIVE:*.vhdx=ARCHIVE:*.vmdk=ARCHIVE:*.vsix=ARCHIVE:*.war=ARCHIVE:*.wim=ARCHIVE:*.xz=ARCHIVE:*.z=ARCHIVE:*.zip=ARCHIVE:*.zoo=ARCHIVE:*.zst=ARCHIVE:*.aac=AUDIO:*.aif=AUDIO:*.aifc=AUDIO:*.aiff=AUDIO:*.alac=AUDIO:*.ape=AUDIO:*.au=AUDIO:*.flac=AUDIO:*.m4a=AUDIO:*.mid=AUDIO:*.midi=AUDIO:*.mka=AUDIO:*.mp3=AUDIO:*.ogg=AUDIO:*.opus=AUDIO:*.pcm=AUDIO:*.spx=AUDIO:*.wav=AUDIO:*.wma=AUDIO:*.wv=AUDIO:*.applescript=CODE:*.as=CODE:*.asa=CODE:*.awk=CODE:*.bash=CODE:*.c=CODE:*.c++=CODE:*.cabal=CODE:*.cc=CODE:*.cgi=CODE:*.clj=CODE:*.cp=CODE:*.cpp=CODE:*.cr=CODE:*.cs=CODE:*.csx=CODE:*.cxx=CODE:*.d=CODE:*.dart=CODE:*.def=CODE:*.di=CODE:*.dpr=CODE:*.el=CODE:*.elm=CODE:*.epp=CODE:*.erl=CODE:*.ex=CODE:*.exs=CODE:*.fish=CODE:*.fs=CODE:*.fsi=CODE:*.fsx=CODE:*.gd=CODE:*.go=CODE:*.gradle=CODE:*.groovy=CODE:*.gv=CODE:*.gvy=CODE:*.h=CODE:*.h++=CODE:*.hgrc=CODE:*.hh=CODE:*.hpp=CODE:*.hs=CODE:*.htc=CODE:*.hxx=CODE:*.inc=CODE:*.inl=CODE:*.ipp=CODE:*.ipynb=CODE:*.java=CODE:*.jl=CODE:*.js=CODE:*.jsx=CODE:*.kt=CODE:*.kts=CODE:*.lhs=CODE:*.lisp=CODE:*.ll=CODE:*.lua=CODE:*.m=CODE:*.matlab=CODE:*.mir=CODE:*.ml=CODE:*.mli=CODE:*.mn=CODE:*.nb=CODE:*.p=CODE:*.pas=CODE:*.php=CODE:*.pl=CODE:*.pm=CODE:*.pod=CODE:*.pp=CODE:*.pro=CODE:*.ps1=CODE:*.psd1=CODE:*.psm1=CODE:*.purs=CODE:*.py=CODE:*.r=CODE:*.rb=CODE:*.rs=CODE:*.sbt=CODE:*.scala=CODE:*.sh=CODE:*.swift=CODE:*.t=CODE:*.tcl=CODE:*.td=CODE:*.ts=CODE:*.tsx=CODE:*.vb=CODE:*.vsh=CODE:*.zig=CODE:*.zsh=CODE:*.abw=DOC:*.doc=DOC:*.docx=DOC:*.fodg:*.fodp=DOC:*.fods=DOC:*.fodt=DOC:*.odg=DOC:*.odp=DOC:*.ods=DOC:*.odt=DOC:*.pps=DOC:*.ppt=DOC:*.pptx=DOC:*.rtf=DOC:*.sxi=DOC:*.sxw=DOC:*.txt=DOC:*.xlr=DOC:*.xls=DOC:*.xlsx=DOC:*.azw=EBOOK:*.azw3=EBOOK:*.cb7=EBOOK:*.cba=EBOOK:*.cbr=EBOOK:*.cbt=EBOOK:*.cbz=EBOOK:*.djvu=EBOOK:*.epub=EBOOK:*.fb2=EBOOK:*.kf8=EBOOK:*.kfx=EBOOK:*.mobi=EBOOK:*.oxps=EBOOK:*.pdb=EBOOK:*.pdf=EBOOK:*.ps=EBOOK:*.xps=EBOOK:*.avif=IMAGE:*.bmp=IMAGE:*.gif=IMAGE:*.ico=IMAGE:*.jpeg=IMAGE:*.jpg=IMAGE:*.jxl=IMAGE:*.mjpeg=IMAGE:*.mjpg=IMAGE:*.mng=IMAGE:*.pbm=IMAGE:*.pcx=IMAGE:*.pgm=IMAGE:*.png=IMAGE:*.ppm=IMAGE:*.psd=IMAGE:*.svg=IMAGE:*.svgz=IMAGE:*.tga=IMAGE:*.tif=IMAGE:*.tiff=IMAGE:*.webp=IMAGE:*.xbm=IMAGE:*.xcf=IMAGE:*.xpm=IMAGE:*.css=MARKUP:*.htm=MARKUP:*.html=MARKUP:*.ltx=MARKUP:*.markdown=MARKUP:*.md=MARKUP:*.mdown=MARKUP:*.opf=MARKUP:*.rss=MARKUP:*.shtml=MARKUP:*.tex=MARKUP:*.xhtml=MARKUP:*.xml=MARKUP:*.aux=TEMP:*.bak=TEMP:*.bbl=TEMP:*.bc=TEMP:*.cache=TEMP:*.class=TEMP:*.git=TEMP:*.hi=TEMP:*.idx=TEMP:*.ilg=TEMP:*.ind=TEMP:*.la=TEMP:*.lo=TEMP:*.localized=TEMP:*.lock=TEMP:*.log=TEMP:*.o=TEMP:*.orig=TEMP:*.out=TEMP:*.pid=TEMP:*.pyc=TEMP:*.pyd=TEMP:*.pyo=TEMP:*.rej=TEMP:*.rlib=TEMP:*.sty=TEMP:*.swp=TEMP:*.tmp=TEMP:*.toc=TEMP:*.3gp=VIDEO:*.asf=VIDEO:*.avi=VIDEO:*.cgm=VIDEO:*.dl=VIDEO:*.emf=VIDEO:*.flc=VIDEO:*.fli=VIDEO:*.flv=VIDEO:*.h264=VIDEO:*.heics=VIDEO:*.gl=VIDEO:*.m2ts=VIDEO:*.m2v=VIDEO:*.m4v=VIDEO:*.mkv=VIDEO:*.mov=VIDEO:*.mp4=VIDEO:*.mp4v=VIDEO:*.mpeg=VIDEO:*.mpg=VIDEO:*.nuv=VIDEO:*.ogm=VIDEO:*.ogv=VIDEO:*.ogx=VIDEO:*.qt=VIDEO:*.rm=VIDEO:*.rmvb=VIDEO:*.vob=VIDEO:*.webm=VIDEO:*.wmv=VIDEO:*.xwd=VIDEO:*.yuv=VIDEO:" DateShades="3,#ff0000-2,#ffffff,#dadada,#bcbcbc,#9e9e9e,#808080" SizeShades="3,#bf616a-2,#8fbcbb,#a3be8c,#b48ead,#d08770,#bf616a" DirIconColor="Y" Prompt="\[\e[0;38;2;216;222;233m\][\S\[\e[0;38;2;216;222;233m\]]\l \A \u:\H \[\e[1;38;2;143;188;187m\]\w\n\[\e[0;38;2;216;222;233m\]<\z\[\e[0;38;2;216;222;233m\]> \[\e[0;38;2;163;190;140m\]\$ \[\e[0m\]" Notifications=true EnableWarningPrompt=true WarningPrompt="\[\e[0m\]\[\e[0;2;38;2;191;97;106m\](!) > " DividingLine="-" FzfTabOptions="--color='dark,prompt:#81a1c1,fg+:-1,pointer:#bf616a,hl:#b48ead,hl+:#b48ead,gutter:-1,marker:#a3be8c:bold,query:#e5e9f0,info:#e5e9f0:dim,border:8' --marker='*' --bind tab:accept,right:accept,left:abort,alt-p:toggle-preview,change:top,alt-up:preview-page-up,alt-down:preview-page-down --tiebreak=begin --inline-info --layout=reverse-list --preview-window=wrap,border-left" clifm-1.26.3/misc/colors/one-dark.clifm000066400000000000000000000163151506632037700176640ustar00rootroot00000000000000# Theme file for Clifm # Theme name: one-dark (based on https://github.com/r3tex/one-dark) # Author: L. Abramovich # License: GPL2+ define D=#abb2bf # Default define BD=#abb2bf-1 # Bold default define R=#e06c75 # Red define BR=#e06c75-1 # Bold red define DR=#e06c75-2 # Dimmed red define G=#98c379 # Green define BG=#98c379-1 # Bold green define DG=#98c379-2 # Dimmed green define Y=#e5c07b # Yellow define BY=#e5c07b-1 # Bold yellow define DY=#e5c07b-2 # Dimmed yellow define B=#61afef # Blue define BB=#61afef-1 # Bold blue define DB=#61afef-2 # Dimmed blue define M=#c678dd # Magenta define BM=#c678dd-1 # Bold magenta define DM=#c678dd-2 # Dimmed magenta define UM=#c678dd-4 # Underlined magenta define RM=#c678dd-7 # Reverse magenta define C=#56b6c2 # Cyan define BC=#56b6c2-1 # Bold cyan define DC=#56b6c2-2 # Dimmed cyan define RC=#56b6c2-7 # Reverse cyan define UDC=4;2;38;2;86;182;194 # Underlined dimmed cyan define BDC=1;2;38;2;86;182;194 # Bold dimmed cyan define DW=#abb2bf-2 define RW=38;2;224;108;117;48;2;171;178;191 # Red on white define URK=4;38;2;224;108;117;48;2;40;44;52 # Underlined red on black define WR=38;2;171;178;191;48;2;224;108;117 # White on red define KY=38;2;40;44;52;48;2;229;192;123 # Black on yellow define KR=38;2;40;44;52;48;2;224;108;117 # Black on red define KG=38;2;40;44;52;48;2;152;195;121 # Black on green define BK=38;2;97;175;239;48;2;40;44;52 # Blue on black define KB=38;2;40;44;42;48;2;97;175;239 # Black on blue define MK=38;2;198;120;221;48;2;40;44;52 # Magenta on black define BMK=1;38;2;198;120;221;48;2;40;44;52 # Bold magenta on black define ARCHIVE=#56b6c2-4 # Underlined cyan define AUDIO=#e5c07b-1 # Bold yellow define CODE=#98c379 # Bold white define DOC=#e06c75 # Red define EBOOK=#e06c75-1 # Bold red define IMAGE=#c678dd # Magenta define MARKUP=#e5c07b # Yellow define TEMP=#abb2bf-2 # Dimmed white define VIDEO=#c678dd-1 # Bold magenta FiletypeColors="bd=BY:ca=KR:cd=BD:di=BB:ed=DB:ee=G:ef=DW:ex=BG:fi=D:ln=BC:mh=RC:nd=BR:nf=:no=RW:or=DC:ow=BK:pi=BMK:sg=KY:so=MK:st=KB:su=WR:tw=KG:uf=URK:" InterfaceColors="ac=:de=C:df=D:dk=R:dl=DW:bm=BC:dn=DW:dr=Y:dw=R:dxd=G:dxr=C:dg=Y:dd=:dz=:do=C:dp=M:el=C:em=BR:fc=DB:hb=C:hc=DR:hd=C:he=C:hn=D:hp=C:hq=Y:hr=R:hs=G:hv=G:hw=R:lc=G:li=BG:mi=BC:nm=BG:sb=DY:sc=DR:sd=:sf=UDC:sh=:si=BB:sp=DR:sx=DG:ti=BC:ts=UM:tt=BDC:tx=D:wc=BC:wm=BY:ws1=B:ws2=R:ws3=Y:ws4=G:ws5=C:ws6=C:ws7=C:ws8=C:xf=BR:xs=G:" ExtColors="*.7z=ARCHIVE:*.ace=ARCHIVE:*.alz=ARCHIVE:*.apk=ARCHIVE:*.arc=ARCHIVE:*.arj=ARCHIVE:*.bz=ARCHIVE:*.bz2=ARCHIVE:*.cab=ARCHIVE:*.cpio=ARCHIVE:*.deb=ARCHIVE:*.dmg=ARCHIVE:*.dwm=ARCHIVE:*.dz=ARCHIVE:*.ear=ARCHIVE:*.esd=ARCHIVE:*.gz=ARCHIVE:*.img=ARCHIVE:*.iso=ARCHIVE:*.jar=ARCHIVE:*.lha=ARCHIVE:*.lrz=ARCHIVE:*.lz=ARCHIVE:*.lz4=ARCHIVE:*.lzh=ARCHIVE:*.lzma=ARCHIVE:*.lzo=ARCHIVE:*.qcow=ARCHIVE:*.qcow2=ARCHIVE:*.rar=ARCHIVE:*.rpm=ARCHIVE:*.rz=ARCHIVE:*.sar=ARCHIVE:*.swm=ARCHIVE:*.t7z=ARCHIVE:*.tar=ARCHIVE:*.taz=ARCHIVE:*.tbz=ARCHIVE:*.tbz2=ARCHIVE:*.tgz=ARCHIVE:*.tlz=ARCHIVE:*.toast=ARCHIVE:*.txz=ARCHIVE:*.tz=ARCHIVE:*.tzo=ARCHIVE:*.tzst=ARCHIVE:*.vcd=ARCHIVE:*.vdi=ARCHIVE:*.vhd=ARCHIVE:*.vhdx=ARCHIVE:*.vmdk=ARCHIVE:*.vsix=ARCHIVE:*.war=ARCHIVE:*.wim=ARCHIVE:*.xz=ARCHIVE:*.z=ARCHIVE:*.zip=ARCHIVE:*.zoo=ARCHIVE:*.zst=ARCHIVE:*.aac=AUDIO:*.aif=AUDIO:*.aifc=AUDIO:*.aiff=AUDIO:*.alac=AUDIO:*.ape=AUDIO:*.au=AUDIO:*.flac=AUDIO:*.m4a=AUDIO:*.mid=AUDIO:*.midi=AUDIO:*.mka=AUDIO:*.mp3=AUDIO:*.ogg=AUDIO:*.opus=AUDIO:*.pcm=AUDIO:*.spx=AUDIO:*.wav=AUDIO:*.wma=AUDIO:*.wv=AUDIO:*.applescript=CODE:*.as=CODE:*.asa=CODE:*.awk=CODE:*.bash=CODE:*.c=CODE:*.c++=CODE:*.cabal=CODE:*.cc=CODE:*.cgi=CODE:*.clj=CODE:*.cp=CODE:*.cpp=CODE:*.cr=CODE:*.cs=CODE:*.csx=CODE:*.cxx=CODE:*.d=CODE:*.dart=CODE:*.def=CODE:*.di=CODE:*.dpr=CODE:*.el=CODE:*.elm=CODE:*.epp=CODE:*.erl=CODE:*.ex=CODE:*.exs=CODE:*.fish=CODE:*.fs=CODE:*.fsi=CODE:*.fsx=CODE:*.gd=CODE:*.go=CODE:*.gradle=CODE:*.groovy=CODE:*.gv=CODE:*.gvy=CODE:*.h=CODE:*.h++=CODE:*.hgrc=CODE:*.hh=CODE:*.hpp=CODE:*.hs=CODE:*.htc=CODE:*.hxx=CODE:*.inc=CODE:*.inl=CODE:*.ipp=CODE:*.ipynb=CODE:*.java=CODE:*.jl=CODE:*.js=CODE:*.jsx=CODE:*.kt=CODE:*.kts=CODE:*.lhs=CODE:*.lisp=CODE:*.ll=CODE:*.lua=CODE:*.m=CODE:*.matlab=CODE:*.mir=CODE:*.ml=CODE:*.mli=CODE:*.mn=CODE:*.nb=CODE:*.p=CODE:*.pas=CODE:*.php=CODE:*.pl=CODE:*.pm=CODE:*.pod=CODE:*.pp=CODE:*.pro=CODE:*.ps1=CODE:*.psd1=CODE:*.psm1=CODE:*.purs=CODE:*.py=CODE:*.r=CODE:*.rb=CODE:*.rs=CODE:*.sbt=CODE:*.scala=CODE:*.sh=CODE:*.swift=CODE:*.t=CODE:*.tcl=CODE:*.td=CODE:*.ts=CODE:*.tsx=CODE:*.vb=CODE:*.vsh=CODE:*.zig=CODE:*.zsh=CODE:*.abw=DOC:*.doc=DOC:*.docx=DOC:*.fodg:*.fodp=DOC:*.fods=DOC:*.fodt=DOC:*.odg=DOC:*.odp=DOC:*.ods=DOC:*.odt=DOC:*.pps=DOC:*.ppt=DOC:*.pptx=DOC:*.rtf=DOC:*.sxi=DOC:*.sxw=DOC:*.txt=DOC:*.xlr=DOC:*.xls=DOC:*.xlsx=DOC:*.azw=EBOOK:*.azw3=EBOOK:*.cb7=EBOOK:*.cba=EBOOK:*.cbr=EBOOK:*.cbt=EBOOK:*.cbz=EBOOK:*.djvu=EBOOK:*.epub=EBOOK:*.fb2=EBOOK:*.kf8=EBOOK:*.kfx=EBOOK:*.mobi=EBOOK:*.oxps=EBOOK:*.pdb=EBOOK:*.pdf=EBOOK:*.ps=EBOOK:*.xps=EBOOK:*.avif=IMAGE:*.bmp=IMAGE:*.gif=IMAGE:*.ico=IMAGE:*.jpeg=IMAGE:*.jpg=IMAGE:*.jxl=IMAGE:*.mjpeg=IMAGE:*.mjpg=IMAGE:*.mng=IMAGE:*.pbm=IMAGE:*.pcx=IMAGE:*.pgm=IMAGE:*.png=IMAGE:*.ppm=IMAGE:*.psd=IMAGE:*.svg=IMAGE:*.svgz=IMAGE:*.tga=IMAGE:*.tif=IMAGE:*.tiff=IMAGE:*.webp=IMAGE:*.xbm=IMAGE:*.xcf=IMAGE:*.xpm=IMAGE:*.css=MARKUP:*.htm=MARKUP:*.html=MARKUP:*.ltx=MARKUP:*.markdown=MARKUP:*.md=MARKUP:*.mdown=MARKUP:*.opf=MARKUP:*.rss=MARKUP:*.shtml=MARKUP:*.tex=MARKUP:*.xhtml=MARKUP:*.xml=MARKUP:*.aux=TEMP:*.bak=TEMP:*.bbl=TEMP:*.bc=TEMP:*.cache=TEMP:*.class=TEMP:*.git=TEMP:*.hi=TEMP:*.idx=TEMP:*.ilg=TEMP:*.ind=TEMP:*.la=TEMP:*.lo=TEMP:*.localized=TEMP:*.lock=TEMP:*.log=TEMP:*.o=TEMP:*.orig=TEMP:*.out=TEMP:*.pid=TEMP:*.pyc=TEMP:*.pyd=TEMP:*.pyo=TEMP:*.rej=TEMP:*.rlib=TEMP:*.sty=TEMP:*.swp=TEMP:*.tmp=TEMP:*.toc=TEMP:*.3gp=VIDEO:*.asf=VIDEO:*.avi=VIDEO:*.cgm=VIDEO:*.dl=VIDEO:*.emf=VIDEO:*.flc=VIDEO:*.fli=VIDEO:*.flv=VIDEO:*.h264=VIDEO:*.heics=VIDEO:*.gl=VIDEO:*.m2ts=VIDEO:*.m2v=VIDEO:*.m4v=VIDEO:*.mkv=VIDEO:*.mov=VIDEO:*.mp4=VIDEO:*.mp4v=VIDEO:*.mpeg=VIDEO:*.mpg=VIDEO:*.nuv=VIDEO:*.ogm=VIDEO:*.ogv=VIDEO:*.ogx=VIDEO:*.qt=VIDEO:*.rm=VIDEO:*.rmvb=VIDEO:*.vob=VIDEO:*.webm=VIDEO:*.wmv=VIDEO:*.xwd=VIDEO:*.yuv=VIDEO:" DateShades="3,#ff0000-2,#ffffff,#dadada,#bcbcbc,#9e9e9e,#808080" SizeShades="3,#e06c75-2,#56b6c2,#91b07b,#e5c07b,#d19a66,#e06c75" DirIconColor="Y" Prompt="\[\e[0;38;2;171;178;191m\][\S\[\e[0;38;2;171;178;191m\]]\l \A \u:\H \[\e[0;38;2;86;182;194m\]\w\n\[\e[0;38;2;171;178;191m\]<\z\[\e[0;38;2;171;178;191m\]> \[\e[0;38;2;97;175;239m\]\$ \[\e[0m\]" Notifications=true EnableWarningPrompt=true WarningPrompt="\[\e[0;2;38;2;224;108;117m\](!)\[\e[0;2m\] > " DividingLine="-" FzfTabOptions="--color='dark,prompt:#56b6c2,fg+:-1,pointer:#61afef,hl:#98c379,hl+:#98c379,gutter:-1,marker:#98c379:bold,query:#abb2bf,info:#abb2bf:dim,border:8' --marker='*' --bind tab:accept,right:accept,left:abort,alt-p:toggle-preview,change:top,alt-up:preview-page-up,alt-down:preview-page-down --tiebreak=begin --inline-info --layout=reverse-list --preview-window=wrap,border-left" clifm-1.26.3/misc/colors/solarized.clifm000066400000000000000000000163661506632037700201660ustar00rootroot00000000000000# Theme file for Clifm # Theme name: solarized (based on https://github.com/altercation/solarized) # Author: L. Abramovich # License: GPL2+ define BD=1 # Bold define R=#dc322f # Red define BR=#dc322f-1 # Bold red define DR=#dc322f-2 # Dimmed red define UBR=4;1;38;2;220;50;47 # Underlined bold red define UDR=4;2;38;2;220;50;47 # Underlined dimmed red define G=#859900 # Green define BG=#859900-1 # Bold green define DG=#859900-2 # Dimmed green define Y=#b58900 # Yellow define BY=#b58900-1 # Bold yellow define DY=#b58900-2 # Dimmed yellow define B=#268bd2 # Blue define BB=#268bd2-1 # Bold blue define DB=#268bd2-2 # Dimmed blue define M=#d33682 # Magenta define BM=#d33682-1 # Bold magenta define DM=#d33682-2 # Dimmed magenta define UM=#d33682-4 # Underlined magenta define RM=#d33682-7 # Reverse magenta define C=#2aa198 # Cyan define BC=#2aa198-1 # Bold cyan define DC=#2aa198-2 # Dimmed cyan define RC=#2aa198-7 # Reverse cyan define UDC=4;2;38;2;42;161;152 # Underlined dimmed cyan define BDC=1;2;38;2;42;161;152 # Bold dimmed cyan define W=#eee8d5 # White define DW=#eee8d5-2 # Dimmed white define UBW=4;1;38;2;238;232;213 # Underlined bold white define KR=38;2;7;54;66;48;2;220;50;47 # Black on red define KY=38;2;7;54;66;48;2;181;137;0 # Black on yellow define KG=38;2;7;54;66;48;2;133;153;0 # Black on green define URW=4;38;2;220;50;47;48;2;238;232;213 # Underlined red on white define BlGr=38;2;38;139;210;48;2;133;153;0 # Blue on green define WB=38;2;238;232;213;48;2;38;139;210 # White on blue define WR=37;41 # White on red define ARCHIVE=#dc322f-1 # Red define AUDIO=#d33682 # Magenta define CODE=#eee8d5-1 # Bold light gray define DOC=#b58900 # Yellow define EBOOK=#dc322f # White define IMAGE=#d33682 # Magenta define MARKUP=#eee8d5 # White define TEMP=#eee8d5 # Light gray define VIDEO=#d33682 # Magenta FiletypeColors="bd=BY:ca=KR:cd=BD:di=BB:ed=DB:ee=G:ef=DY:ex=BG:fi=W:ln=BC:mh=RC:nd=UBR:nf=:no=URW:or=UDC:ow=BlGr:pi=BM:so=BM:su=WR:sg=KY:st=WB:tw=KG:uf=UBW:" InterfaceColors="ac=:db=M:dd=:de=C:df=W:dg=Y:dk=R:dl=DW:dn=DW:do=C:dp=M:dr=Y:dw=R:dxd=G:dxr=C:dz=:el=BY:em=BR:fc=DB:hb=C:hc=DR:hd=C:he=C:hn=W:hp=C:hq=Y:hr=R:hs=G:hv=G:hw=R:lc=G:li=BG:mi=BC:nm=BG:si=BB:sb=DY:sc=DR:sd=:sf=UDC:sh=:sp=DR:sx=DG:ti=BC:ts=UM:tt=BDC:tx=W:wc=BC:wm=BY:ws1=B:ws2=R:ws3=Y:ws4=G:ws5=C:ws6=C:ws7=C:ws8=C:xf=BR:xs=G:" ExtColors="*.7z=ARCHIVE:*.ace=ARCHIVE:*.alz=ARCHIVE:*.apk=ARCHIVE:*.arc=ARCHIVE:*.arj=ARCHIVE:*.bz=ARCHIVE:*.bz2=ARCHIVE:*.cab=ARCHIVE:*.cpio=ARCHIVE:*.deb=ARCHIVE:*.dmg=ARCHIVE:*.dwm=ARCHIVE:*.dz=ARCHIVE:*.ear=ARCHIVE:*.esd=ARCHIVE:*.gz=ARCHIVE:*.img=ARCHIVE:*.iso=ARCHIVE:*.jar=ARCHIVE:*.lha=ARCHIVE:*.lrz=ARCHIVE:*.lz=ARCHIVE:*.lz4=ARCHIVE:*.lzh=ARCHIVE:*.lzma=ARCHIVE:*.lzo=ARCHIVE:*.qcow=ARCHIVE:*.qcow2=ARCHIVE:*.rar=ARCHIVE:*.rpm=ARCHIVE:*.rz=ARCHIVE:*.sar=ARCHIVE:*.swm=ARCHIVE:*.t7z=ARCHIVE:*.tar=ARCHIVE:*.taz=ARCHIVE:*.tbz=ARCHIVE:*.tbz2=ARCHIVE:*.tgz=ARCHIVE:*.tlz=ARCHIVE:*.toast=ARCHIVE:*.txz=ARCHIVE:*.tz=ARCHIVE:*.tzo=ARCHIVE:*.tzst=ARCHIVE:*.vcd=ARCHIVE:*.vdi=ARCHIVE:*.vhd=ARCHIVE:*.vhdx=ARCHIVE:*.vmdk=ARCHIVE:*.vsix=ARCHIVE:*.war=ARCHIVE:*.wim=ARCHIVE:*.xz=ARCHIVE:*.z=ARCHIVE:*.zip=ARCHIVE:*.zoo=ARCHIVE:*.zst=ARCHIVE:*.aac=AUDIO:*.aif=AUDIO:*.aifc=AUDIO:*.aiff=AUDIO:*.alac=AUDIO:*.ape=AUDIO:*.au=AUDIO:*.flac=AUDIO:*.m4a=AUDIO:*.mid=AUDIO:*.midi=AUDIO:*.mka=AUDIO:*.mp3=AUDIO:*.ogg=AUDIO:*.opus=AUDIO:*.pcm=AUDIO:*.spx=AUDIO:*.wav=AUDIO:*.wma=AUDIO:*.wv=AUDIO:*.applescript=CODE:*.as=CODE:*.asa=CODE:*.awk=CODE:*.bash=CODE:*.c=CODE:*.c++=CODE:*.cabal=CODE:*.cc=CODE:*.cgi=CODE:*.clj=CODE:*.cp=CODE:*.cpp=CODE:*.cr=CODE:*.cs=CODE:*.csx=CODE:*.cxx=CODE:*.d=CODE:*.dart=CODE:*.def=CODE:*.di=CODE:*.dpr=CODE:*.el=CODE:*.elm=CODE:*.epp=CODE:*.erl=CODE:*.ex=CODE:*.exs=CODE:*.fish=CODE:*.fs=CODE:*.fsi=CODE:*.fsx=CODE:*.gd=CODE:*.go=CODE:*.gradle=CODE:*.groovy=CODE:*.gv=CODE:*.gvy=CODE:*.h=CODE:*.h++=CODE:*.hgrc=CODE:*.hh=CODE:*.hpp=CODE:*.hs=CODE:*.htc=CODE:*.hxx=CODE:*.inc=CODE:*.inl=CODE:*.ipp=CODE:*.ipynb=CODE:*.java=CODE:*.jl=CODE:*.js=CODE:*.jsx=CODE:*.kt=CODE:*.kts=CODE:*.lhs=CODE:*.lisp=CODE:*.ll=CODE:*.lua=CODE:*.m=CODE:*.matlab=CODE:*.mir=CODE:*.ml=CODE:*.mli=CODE:*.mn=CODE:*.nb=CODE:*.p=CODE:*.pas=CODE:*.php=CODE:*.pl=CODE:*.pm=CODE:*.pod=CODE:*.pp=CODE:*.pro=CODE:*.ps1=CODE:*.psd1=CODE:*.psm1=CODE:*.purs=CODE:*.py=CODE:*.r=CODE:*.rb=CODE:*.rs=CODE:*.sbt=CODE:*.scala=CODE:*.sh=CODE:*.swift=CODE:*.t=CODE:*.tcl=CODE:*.td=CODE:*.ts=CODE:*.tsx=CODE:*.vb=CODE:*.vsh=CODE:*.zig=CODE:*.zsh=CODE:*.abw=DOC:*.doc=DOC:*.docx=DOC:*.fodg:*.fodp=DOC:*.fods=DOC:*.fodt=DOC:*.odg=DOC:*.odp=DOC:*.ods=DOC:*.odt=DOC:*.pps=DOC:*.ppt=DOC:*.pptx=DOC:*.rtf=DOC:*.sxi=DOC:*.sxw=DOC:*.txt=DOC:*.xlr=DOC:*.xls=DOC:*.xlsx=DOC:*.azw=EBOOK:*.azw3=EBOOK:*.cb7=EBOOK:*.cba=EBOOK:*.cbr=EBOOK:*.cbt=EBOOK:*.cbz=EBOOK:*.djvu=EBOOK:*.epub=EBOOK:*.fb2=EBOOK:*.kf8=EBOOK:*.kfx=EBOOK:*.mobi=EBOOK:*.oxps=EBOOK:*.pdb=EBOOK:*.pdf=EBOOK:*.ps=EBOOK:*.xps=EBOOK:*.avif=IMAGE:*.bmp=IMAGE:*.gif=IMAGE:*.ico=IMAGE:*.jpeg=IMAGE:*.jpg=IMAGE:*.jxl=IMAGE:*.mjpeg=IMAGE:*.mjpg=IMAGE:*.mng=IMAGE:*.pbm=IMAGE:*.pcx=IMAGE:*.pgm=IMAGE:*.png=IMAGE:*.ppm=IMAGE:*.psd=IMAGE:*.svg=IMAGE:*.svgz=IMAGE:*.tga=IMAGE:*.tif=IMAGE:*.tiff=IMAGE:*.webp=IMAGE:*.xbm=IMAGE:*.xcf=IMAGE:*.xpm=IMAGE:*.css=MARKUP:*.htm=MARKUP:*.html=MARKUP:*.ltx=MARKUP:*.markdown=MARKUP:*.md=MARKUP:*.mdown=MARKUP:*.opf=MARKUP:*.rss=MARKUP:*.shtml=MARKUP:*.tex=MARKUP:*.xhtml=MARKUP:*.xml=MARKUP:*.aux=TEMP:*.bak=TEMP:*.bbl=TEMP:*.bc=TEMP:*.cache=TEMP:*.class=TEMP:*.git=TEMP:*.hi=TEMP:*.idx=TEMP:*.ilg=TEMP:*.ind=TEMP:*.la=TEMP:*.lo=TEMP:*.localized=TEMP:*.lock=TEMP:*.log=TEMP:*.o=TEMP:*.orig=TEMP:*.out=TEMP:*.pid=TEMP:*.pyc=TEMP:*.pyd=TEMP:*.pyo=TEMP:*.rej=TEMP:*.rlib=TEMP:*.sty=TEMP:*.swp=TEMP:*.tmp=TEMP:*.toc=TEMP:*.3gp=VIDEO:*.asf=VIDEO:*.avi=VIDEO:*.cgm=VIDEO:*.dl=VIDEO:*.emf=VIDEO:*.flc=VIDEO:*.fli=VIDEO:*.flv=VIDEO:*.h264=VIDEO:*.heics=VIDEO:*.gl=VIDEO:*.m2ts=VIDEO:*.m2v=VIDEO:*.m4v=VIDEO:*.mkv=VIDEO:*.mov=VIDEO:*.mp4=VIDEO:*.mp4v=VIDEO:*.mpeg=VIDEO:*.mpg=VIDEO:*.nuv=VIDEO:*.ogm=VIDEO:*.ogv=VIDEO:*.ogx=VIDEO:*.qt=VIDEO:*.rm=VIDEO:*.rmvb=VIDEO:*.vob=VIDEO:*.webm=VIDEO:*.wmv=VIDEO:*.xwd=VIDEO:*.yuv=VIDEO:" DateShades="3,#ff0000-2,#ffffff,#dadada,#bcbcbc,#9e9e9e,#808080" SizeShades="3,#dc322f-2,#2aa1a2,#748409,#b58900,#cb4b16,#dc322f" DirIconColor=1;38;2;181;137;0 Prompt="\[\e[0;38;2;238;232;213m\][\S\[\e[0;38;2;238;232;213m\]]\l \A \u:\H \[\e[38;2;42;161;152m\]\w\[\e[0;38;2;238;232;213m\]\n\[\e[0;38;2;238;232;213m\]<\z\[\e[0;38;2;238;232;213m\]> \[\e[38;2;38;139;210m\]\$ \[\e[0m\]" Notifications=true EnableWarningPrompt=true WarningPrompt="\[\e[0;1;38;2;220;50;47m\](!)\[\e[0;2m\] > " DividingLine="-" FzfTabOptions="--color='dark,prompt:#2aa198,fg+:-1,pointer:#268bd2,hl:#d33682,hl+:#d33682,gutter:-1,marker:#859900:bold,query:#eee8d5,info:#eee8d5:dim,border:8' --marker='*' --bind tab:accept,right:accept,left:abort,alt-p:toggle-preview,change:top,alt-up:preview-page-up,alt-down:preview-page-down --tiebreak=begin --inline-info --layout=reverse-list --preview-window=wrap,border-left" clifm-1.26.3/misc/colors/zenburn.clifm000066400000000000000000000163471506632037700176540ustar00rootroot00000000000000# Theme file for Clifm # Theme name: zenburn (based on https://github.com/jnurmine/Zenburn) # Author: L. Abramovich # License: GPL2+ define W=#dcdccc # White define BW=#dcdccc-1 # Bold white define DW=#dcdccc-2 # Dimmed white define R=#dca3a3 # Red define BR=#dca3a3-1 # Bold red define DR=#dca3a3-2 # Dimmed red define UR=#dca3a3-4 # Underlined red define UBR=4;1;38;2;220;163;163 # Underlined bold red define C=#8cd0d3 # Cyan define BC=#8cd0d3-1 # Bold cyan define DC=#8cd0d3-2 # Dimmed cyan define RC=#8cd0d3-7 # Reverse cyan define UC=#8cd0d3-4 # Underlined cyan define Y=#f8f893 # Yellow define BY=#f8f893-1 # Bold yellow define DY=#f8f893-2 # Dimmed yellow define G=#709f7f # Green define BG=#709f7f-1 # Bold green define DG=#709f7f-2 # Dimmed green define BG2=#284f28-1 # Bold dark green define S=#f0cfaf # Salmon define BS=#f0cfaf-1 # Bold salmon define DS=#f0cfaf-2 # Dimmed salmon define M=#9fafaf # Magenta define BM=#9fafaf-1 # Bold magenta define DM=#9fafaf-2 # Dimmed magenta define UM=#9fafaf-4 # Dimmed magenta define V=#af005f # Violet define BV=#af005f-1 # Bold violet define KR=38;2;44;48;45;48;2;220;163;163 # Black on red define KY=38;2;44;48;45;48;2;248;248;147 # Black on yellow define WGr=38;2;255;255;255;48;2;49;60;54 # White on dark green define WR=38;2;255;255;255;48;2;220;163;163 # White on red define UWR=4;38;2;255;255;255;48;2;220;163;163 # Underlined white on red define WC=38;2;255;255;255;48;2;140;208;211 # White on cyan define KW=38;2;47;47;47;48;2;255;255;255 # Black on white define RK=38;2;241;140;150;48;2;70;70;70 # Red on black define ARCHIVE=#dca3a3-1 # Bold red define DOC=#9fafaf # Magenta define AUDIO=38;2;255;204;238;48;2;42;42;42 # Magenta on gray define IMAGE=38;2;255;204;238;48;2;42;42;42 # Magenta on gray define VIDEO=38;2;255;204;238;48;2;42;42;42 # Magenta on gray define EBOOK=#af005f-1 # Bold violet define CODE=#09be77 # Green define TOOL=#87ae86 # Light green define CONFIG=#e8bc92 # Pale blue define MARKUP=#e8bc92 # Pale blue define TEMP=#7e7e7e # Gray FiletypeColors="bd=BW:ca=WGr:cd=BW:di=BS:ed=S:ee=G:ef=DW:ex=BG:fi=W:ln=BC:mh=RC:nd=UBR:nf=:no=KW:or=UC:ow=UWR:pi=BM:sg=KY:so=BV:st=WC:su=KR:tw=WR:uf=RK:" InterfaceColors="ac=:db=Y:dd=:de=C:df=W:dg=R:dk=R:dl=BG2:dn=DW:do=C:dp=M:dr=S:dw=R:dxd=G:dxr=C:dz=:el=BR:em=BV:fc=DS:hb=C:hc=DR:hd=G:he=C:hn=W:hp=C:hq=Y:hr=R:hs=G:hv=G:hw=R:lc=C:li=BG:mi=BC:nm=BG:ro=BC:sb=DY:sc=DR:sd=:sf=UDC:sh=:si=BC:sp=DR:sx=DG:ti=BC:ts=UM:tt=BDC:tx=W:wc=BC:wm=BY:ws1=C:ws2=R:ws3=Y:ws4=G:ws5=C:ws6=C:ws7=C:ws8=C:xs=G:xf=BV:" ExtColors="*.7z=ARCHIVE:*.ace=ARCHIVE:*.alz=ARCHIVE:*.apk=ARCHIVE:*.arc=ARCHIVE:*.arj=ARCHIVE:*.bz=ARCHIVE:*.bz2=ARCHIVE:*.cab=ARCHIVE:*.cpio=ARCHIVE:*.deb=ARCHIVE:*.dmg=ARCHIVE:*.dwm=ARCHIVE:*.dz=ARCHIVE:*.ear=ARCHIVE:*.esd=ARCHIVE:*.gz=ARCHIVE:*.img=ARCHIVE:*.iso=ARCHIVE:*.jar=ARCHIVE:*.lha=ARCHIVE:*.lrz=ARCHIVE:*.lz=ARCHIVE:*.lz4=ARCHIVE:*.lzh=ARCHIVE:*.lzma=ARCHIVE:*.lzo=ARCHIVE:*.qcow=ARCHIVE:*.qcow2=ARCHIVE:*.rar=ARCHIVE:*.rpm=ARCHIVE:*.rz=ARCHIVE:*.sar=ARCHIVE:*.swm=ARCHIVE:*.t7z=ARCHIVE:*.tar=ARCHIVE:*.taz=ARCHIVE:*.tbz=ARCHIVE:*.tbz2=ARCHIVE:*.tgz=ARCHIVE:*.tlz=ARCHIVE:*.toast=ARCHIVE:*.txz=ARCHIVE:*.tz=ARCHIVE:*.tzo=ARCHIVE:*.tzst=ARCHIVE:*.vcd=ARCHIVE:*.vdi=ARCHIVE:*.vhd=ARCHIVE:*.vhdx=ARCHIVE:*.vmdk=ARCHIVE:*.vsix=ARCHIVE:*.war=ARCHIVE:*.wim=ARCHIVE:*.xz=ARCHIVE:*.z=ARCHIVE:*.zip=ARCHIVE:*.zoo=ARCHIVE:*.zst=ARCHIVE:*.aac=AUDIO:*.aif=AUDIO:*.aifc=AUDIO:*.aiff=AUDIO:*.alac=AUDIO:*.ape=AUDIO:*.au=AUDIO:*.flac=AUDIO:*.m4a=AUDIO:*.mid=AUDIO:*.midi=AUDIO:*.mka=AUDIO:*.mp3=AUDIO:*.ogg=AUDIO:*.opus=AUDIO:*.pcm=AUDIO:*.spx=AUDIO:*.wav=AUDIO:*.wma=AUDIO:*.wv=AUDIO:*.applescript=CODE:*.as=CODE:*.asa=CODE:*.awk=CODE:*.bash=CODE:*.c=CODE:*.c++=CODE:*.cabal=CODE:*.cc=CODE:*.cgi=CODE:*.clj=CODE:*.cp=CODE:*.cpp=CODE:*.cr=CODE:*.cs=CODE:*.csx=CODE:*.cxx=CODE:*.d=CODE:*.dart=CODE:*.def=CODE:*.di=CODE:*.dpr=CODE:*.el=CODE:*.elm=CODE:*.epp=CODE:*.erl=CODE:*.ex=CODE:*.exs=CODE:*.fish=CODE:*.fs=CODE:*.fsi=CODE:*.fsx=CODE:*.gd=CODE:*.go=CODE:*.gradle=CODE:*.groovy=CODE:*.gv=CODE:*.gvy=CODE:*.h=CODE:*.h++=CODE:*.hgrc=CODE:*.hh=CODE:*.hpp=CODE:*.hs=CODE:*.htc=CODE:*.hxx=CODE:*.inc=CODE:*.inl=CODE:*.ipp=CODE:*.ipynb=CODE:*.java=CODE:*.jl=CODE:*.js=CODE:*.jsx=CODE:*.kt=CODE:*.kts=CODE:*.lhs=CODE:*.lisp=CODE:*.ll=CODE:*.lua=CODE:*.m=CODE:*.matlab=CODE:*.mir=CODE:*.ml=CODE:*.mli=CODE:*.mn=CODE:*.nb=CODE:*.p=CODE:*.pas=CODE:*.php=CODE:*.pl=CODE:*.pm=CODE:*.pod=CODE:*.pp=CODE:*.pro=CODE:*.ps1=CODE:*.psd1=CODE:*.psm1=CODE:*.purs=CODE:*.py=CODE:*.r=CODE:*.rb=CODE:*.rs=CODE:*.sbt=CODE:*.scala=CODE:*.sh=CODE:*.swift=CODE:*.t=CODE:*.tcl=CODE:*.td=CODE:*.ts=CODE:*.tsx=CODE:*.vb=CODE:*.vsh=CODE:*.zig=CODE:*.zsh=CODE:*.abw=DOC:*.doc=DOC:*.docx=DOC:*.fodg:*.fodp=DOC:*.fods=DOC:*.fodt=DOC:*.odg=DOC:*.odp=DOC:*.ods=DOC:*.odt=DOC:*.pps=DOC:*.ppt=DOC:*.pptx=DOC:*.rtf=DOC:*.sxi=DOC:*.sxw=DOC:*.txt=DOC:*.xlr=DOC:*.xls=DOC:*.xlsx=DOC:*.azw=EBOOK:*.azw3=EBOOK:*.cb7=EBOOK:*.cba=EBOOK:*.cbr=EBOOK:*.cbt=EBOOK:*.cbz=EBOOK:*.djvu=EBOOK:*.epub=EBOOK:*.fb2=EBOOK:*.kf8=EBOOK:*.kfx=EBOOK:*.mobi=EBOOK:*.oxps=EBOOK:*.pdb=EBOOK:*.pdf=EBOOK:*.ps=EBOOK:*.xps=EBOOK:*.avif=IMAGE:*.bmp=IMAGE:*.gif=IMAGE:*.ico=IMAGE:*.jpeg=IMAGE:*.jpg=IMAGE:*.jxl=IMAGE:*.mjpeg=IMAGE:*.mjpg=IMAGE:*.mng=IMAGE:*.pbm=IMAGE:*.pcx=IMAGE:*.pgm=IMAGE:*.png=IMAGE:*.ppm=IMAGE:*.psd=IMAGE:*.svg=IMAGE:*.svgz=IMAGE:*.tga=IMAGE:*.tif=IMAGE:*.tiff=IMAGE:*.webp=IMAGE:*.xbm=IMAGE:*.xcf=IMAGE:*.xpm=IMAGE:*.css=MARKUP:*.htm=MARKUP:*.html=MARKUP:*.ltx=MARKUP:*.markdown=MARKUP:*.md=MARKUP:*.mdown=MARKUP:*.opf=MARKUP:*.rss=MARKUP:*.shtml=MARKUP:*.tex=MARKUP:*.xhtml=MARKUP:*.xml=MARKUP:*.aux=TEMP:*.bak=TEMP:*.bbl=TEMP:*.bc=TEMP:*.cache=TEMP:*.class=TEMP:*.git=TEMP:*.hi=TEMP:*.idx=TEMP:*.ilg=TEMP:*.ind=TEMP:*.la=TEMP:*.lo=TEMP:*.localized=TEMP:*.lock=TEMP:*.log=TEMP:*.o=TEMP:*.orig=TEMP:*.out=TEMP:*.pid=TEMP:*.pyc=TEMP:*.pyd=TEMP:*.pyo=TEMP:*.rej=TEMP:*.rlib=TEMP:*.sty=TEMP:*.swp=TEMP:*.tmp=TEMP:*.toc=TEMP:*.3gp=VIDEO:*.asf=VIDEO:*.avi=VIDEO:*.cgm=VIDEO:*.dl=VIDEO:*.emf=VIDEO:*.flc=VIDEO:*.fli=VIDEO:*.flv=VIDEO:*.h264=VIDEO:*.heics=VIDEO:*.gl=VIDEO:*.m2ts=VIDEO:*.m2v=VIDEO:*.m4v=VIDEO:*.mkv=VIDEO:*.mov=VIDEO:*.mp4=VIDEO:*.mp4v=VIDEO:*.mpeg=VIDEO:*.mpg=VIDEO:*.nuv=VIDEO:*.ogm=VIDEO:*.ogv=VIDEO:*.ogx=VIDEO:*.qt=VIDEO:*.rm=VIDEO:*.rmvb=VIDEO:*.vob=VIDEO:*.webm=VIDEO:*.wmv=VIDEO:*.xwd=VIDEO:*.yuv=VIDEO:" DateShades="3,#ff0000-2,#ffffff,#dadada,#bcbcbc,#9e9e9e,#808080" SizeShades="3,#dca3a3-2,#8cd0d3,#6aae80,#f0cfaf,#709f7f,#dca3a3" DirIconColor="Y" Prompt="\[\e[0;38;2;220;220;204m\][\S\[\e[0;38;2;220;220;204m\]]\l \A \u:\H \[\e[01;38;2;112;159;127m\]\w\n\[\e[0;38;2;220;220;204m\]<\z\[\e[0;38;2;220;220;204m\]> \[\e[0;38;2;140;208;211m\]\$ \[\e[0m\]" Notifications=true EnableWarningPrompt=true WarningPrompt="\[\e[0;1;38;2;220;163;163m\](!)\[\e[0;2m\] > " DividingLine="-" FzfTabOptions="--color='dark,prompt:#8cd0d3,fg+:-1,pointer:#af005f:bold,hl:5,hl+:5,gutter:-1,marker:#f0cfaf:bold,border:8' --marker='*' --bind tab:accept,right:accept,left:abort,alt-p:toggle-preview,change:top,alt-up:preview-page-up,alt-down:preview-page-down --inline-info --layout=reverse-list --tiebreak=begin --preview-window=wrap,border-left" clifm-1.26.3/misc/completions.bash000066400000000000000000000117551506632037700170450ustar00rootroot00000000000000# # Bash completion definition for CliFM # # Author: # L. Abramovich # _clifm () { COMPREPLY=() local IFS=$'\n' local cur=$2 prev=$3 local -a opts opts=( -a --show-hidden -A --no-hidden -b --bookmarks-file -c --config-file -D --config-dir -e --no-eln -E --eln-use-workspace-color -f --dirs-first -F --no-dirs-first -g --pager -G --no-pager -h --help -H --horizontal-list -i --no-case-sensitive -I --case-sensitive -k --keybindings-file -l --long-view -L --follow-symlinks-long -m --dirhist-map -o --autols -O --no-autols -p --path -P --profile -r --no-refresh-on-empty-line -s --splash -S --stealth-mode -t --disk-usage-analyzer -T --trash-dir -v --version -w --workspace -x --no-ext-cmds -y --light-mode -z --sort --bell --case-sens-dirjump --case-sens-path-comp --cd-on-quit --color-scheme --color-links-as-target --cwd-in-title --data-dir --dektop-notifications --disk-usage --full-dir-size --fuzzy-algo --fuzzy-matching --fzfpreview-hidden --fzftab --fzytab --icons --icons-use-file-color --int-vars --kitty-keys --list-and-quit --lscolors --max-dirhist --max-files --mimelist-file --mnt-udisk2 --no-bold --no-cd-auto --no-classify --no-clear-screen --no-color --no-columns --no-file-cap --no-file-ext --no-file-counter --no-follow-symlinks --no-fzfpreview --no-highlight --no-history --no-open-auto --no-refresh-on-resize --no-restore-last-path --no-suggestions --no-tips --no-truncate-names --no-unicode --no-warning-prompt --no-welcome-message --only-dirs --open --opener --pager-view --physical-size --preview --print-sel --ptime-style --readonly --report-cwd --rl-vi-mode --secure-cmds --secure-env --secure-env-full --sel-file --share-selbox --shotgun-file --si --smenutab --sort-reverse --stat --stat-full --stdtab --time-style --trash-as-rm --unicode --virtual-dir --virtual-dir-full-paths --vt100 ) if [[ $prev == "-b" || $prev == "-c" || $prev == "-k" || $prev == "-p" || $prev == "--open" || $prev == "--preview" || $prev == "--shotgun-file" ]]; then COMPREPLY=( $(compgen -f -d -- "$cur") ) elif [[ $prev == "-P" || $prev == "--profile" ]]; then local profiles=$(basename -a $(ls -Ad ~/.config/clifm/profiles/*)) COMPREPLY=( $(compgen -W "$profiles" -- "$cur") ) elif [[ $prev == "--color-scheme" ]]; then local schemes=$(basename -a $(ls -Ad ~/.config/clifm/colors/*) | cut -d"." -f1) COMPREPLY=( $(compgen -W "$schemes" -- "$cur") ) elif [[ $prev == "--fuzzy-algo" ]]; then local args=$(echo -e "1\n2") COMPREPLY=( $(compgen -W "$args" -- "$cur") ) elif [[ $prev == "--time-style" ]]; then local args=$(echo -e "default\nrelative\niso\nlong-iso\nfull-iso") COMPREPLY=( $(compgen -W "$args" -- "$cur") ) elif [[ $prev == "--pager-view" ]]; then local args=$(echo -e "auto\nlong\nshort") COMPREPLY=( $(compgen -W "$args" -- "$cur") ) elif [[ $prev == "--ptime-style" ]]; then local args=$(echo -e "default\niso\nlong-iso\nfull-iso\nfull-iso-nano") COMPREPLY=( $(compgen -W "$args" -- "$cur") ) elif [[ $prev == "-z" || $prev == "--sort" ]]; then local args=$(echo -e "none\nname\nsize\natime\nbtime\nctime\nmtime\nversion\nextension\ninode\nowner\ngroup\nblocks\nlinks\ntype") COMPREPLY=( $(compgen -W "$args" -- "$cur") ) elif [[ $prev == "--bell" ]]; then local args=$(echo -e "0\n1\n2\n3") COMPREPLY=( $(compgen -W "$args" -- "$cur") ) elif [[ $prev == "--opener" ]]; then local apps=$(ls -AG $(echo $PATH | awk -F':' '{ for (i=1; i # complete -c clifm -s a -l show-hidden -d 'Show hidden files' complete -c clifm -s A -l no-hidden -d 'Do not show hidden files' complete -c clifm -s b -l bookmarks-file -r -d 'Set an alternative bookmarks file' complete -c clifm -s c -l config-file -r -d 'Set an alternative configuration file' complete -c clifm -s D -l config-dir -r -d 'Set an alternative configuration directory' complete -c clifm -s e -l no-eln -d 'Do not print ELNs (entry list number)' complete -c clifm -s E -l eln-use-workspace-color -d 'ELNs use the current workspace color' complete -c clifm -s f -l dirs-first -d 'List directories first' complete -c clifm -s F -l no-dirs-first -d 'Do not list directories first' complete -c clifm -s g -l pager -d 'Enable the pager' complete -c clifm -s G -l no-pager -d 'Disable the pager' complete -c clifm -s h -l help -d 'Show help and exit' complete -c clifm -s H -l horizontal-list -d 'List files horizontally' complete -c clifm -s i -l no-case-sensitive -d 'No case-sensitive file listing' complete -c clifm -s I -l case-sensitive -d 'Case-sensitive file listing' complete -c clifm -s k -l keybindings-file -r -d 'Set an alternative keybindings file' complete -c clifm -s l -l long-view -d 'Enable long/detail view mode' complete -c clifm -s L -l follow-symlinks-long -d 'Follow symbolic links in long view' complete -c clifm -s m -l dirhist-map -d 'Enable the directory history map' complete -c clifm -s o -l autols -d 'List files automatically' complete -c clifm -s O -l no-autols -d 'Do not list files automatically' complete -c clifm -s p -l path -r -d 'Set starting path' complete -c clifm -s P -l profile -r -d 'Set profile' -x -a '(ls ~/.config/clifm/profiles/)' complete -c clifm -s r -l no-refresh-on-empty-line -d 'Do not refresh the screen when pressing Enter on an empty line' complete -c clifm -s s -l splash -d 'Enable the splash screen' complete -c clifm -s S -l stealth-mode -d 'Run in incognito/private mode' complete -c clifm -s t -l disk-usage-analyzer -d 'Run in disk usage analyzer mode' complete -c clifm -s T -l trash-dir -r -d 'Set an alternative trash directory' complete -c clifm -s v -l version -d 'Show version details and exit' complete -c clifm -s w -l workspace -r -d 'Set the starting workspace' -x -a '1 2 3 4 5 6 7 8' complete -c clifm -s x -l no-ext-cmds -d 'Disallow the use of external commands' complete -c clifm -s y -l light-mode -d 'Run in light mode' complete -c clifm -s z -l sort -r -d 'Set sort order' -x -a 'none name size atime btime ctime mtime version extension blocks links inode owner group type' complete -c clifm -l bell -r -d 'Set the terminal bell style' -x -a '0 1 2 3' complete -c clifm -l case-sens-dirjump -d 'Do not ignore case when consulting the jump database' complete -c clifm -l case-sens-path-comp -d 'Enable case sensitive path completion' complete -c clifm -l cd-on-quit -d 'Enable cd-on-quit (consult the manpage)' complete -c clifm -l color-scheme -r -d 'Set a color scheme' -x -a '(ls ~/.config/clifm/colors/*.clifm | awk -F\'/\' \'{print $NF}\' | cut -d\'.\' -f1)' complete -c clifm -l color-links-as-target -d 'Color symbolic links using the target file color' complete -c clifm -l cwd-in-title -d 'Print current directory in the window title' complete -c clifm -l data-dir -r -d "Set an alternative data directory" complete -c clifm -l desktop-notifications -d 'Enable desktop notifications' complete -c clifm -l disk-usage -d 'Show disk usage (free/total)' complete -c clifm -l full-dir-size -d 'Display recursive directory sizes (long view)' complete -c clifm -l fuzzy-algo -r -d 'Select the algorithm used for fuzzy matching' -x -a '1 2' complete -c clifm -l fuzzy-matching -d 'Enable fuzzy tab completion/suggestions for filenames and paths' complete -c clifm -l fzfpreview-hidden -d 'Enable file previews (fzf only) with preview window hidden (toggle with Alt-p)' complete -c clifm -l fzftab -d 'Use fzf to display completion matches (default if fzf is found)' complete -c clifm -l fzytab -d 'Use fzy to display completion matches' complete -c clifm -l icons -d 'Enable icons' complete -c clifm -l icons-use-file-color -d 'Icon colors follow file colors' complete -c clifm -l int-vars -d 'Enable internal variables' complete -c clifm -l kitty-keys -d 'Ask the terminal to enable the kitty keyboard protocol' complete -c clifm -l list-and-quit -d 'List files and quit' complete -c clifm -l lscolors -d 'Read file colors from LS_COLORS' complete -c clifm -l max-dirhist -r -d 'Maximum number of visited directories to recall' complete -c clifm -l max-files -r -d 'Set the maximum number of listed files on screen' complete -c clifm -l mimelist-file -r -d 'Set a custom configuration file for Lira' complete -c clifm -l mnt-udisks2 -d 'Use \'udisks2\' instead of \'udevil\' for the \'media\' command' complete -c clifm -l no-bold -d 'Disable bold colors' complete -c clifm -l no-cd-auto -d 'Disable the autocd function' complete -c clifm -l no-classify -d 'Do not append file type indicators' complete -c clifm -l no-clear-screen -d 'Do not clear the screen when listing files' complete -c clifm -l no-color -d 'Disable colors' complete -c clifm -l no-columns -d 'Disable columned file listing' complete -c clifm -l no-file-cap -d 'Do not check file capabilities when listing files' complete -c clifm -l no-file-ext -d 'Do not check file extensions when listing files' complete -c clifm -l no-file-counter -d 'Disable the file counter for directories' complete -c clifm -l no-follow-symlinks -d 'Do not follow symbolic links when listing files' complete -c clifm -l no-fzfpreview -d 'Disable file preview for tab completion (fzf mode only)' complete -c clifm -l no-highlight -d 'Disable syntax highlighting' complete -c clifm -l no-history -d 'Do not write commands into the history file' complete -c clifm -l no-open-auto -d 'Same as no-cd-auto, but for files' complete -c clifm -l no-refresh-on-resize -d 'Do not update the file list upon window\'s resize' complete -c clifm -l no-restore-last-path -d 'Do not record the last visited directory' complete -c clifm -l no-suggestions -d 'Disable auto-suggestions' complete -c clifm -l no-tips -d 'Disable startup tips' complete -c clifm -l no-truncate-names -d 'Do not truncate filenames' complete -c clifm -l no-unicode -d 'Do not use Unicode decorations' complete -c clifm -l no-warning-prompt -d 'Disable the warning prompt' complete -c clifm -l no-welcome-message -d 'Disable the welcome message' complete -c clifm -l only-dirs -d 'List only directories and symbolic links to directories' complete -c clifm -l open -r -d 'Open FILE (via Lira) and exit' complete -c clifm -l opener -r -d 'Use APP as file opener' complete -c clifm -l pager-view -r -d 'How to list files in the pager' -x -a 'auto long short' complete -c clifm -l physical-size -r -d 'Display physical file sizes (disk usage) rather than logical sizes (apparent size)' complete -c clifm -l preview -r -d 'Display a preview of FILE (via shotgun) and exit' complete -c clifm -l print-sel -d 'Keep the list of selected files in sight' complete -c clifm -l ptime-style -d 'Time/date style used by the p/pp command' complete -c clifm -l readonly -d 'Disable internal commands able to modify the filesystem' complete -c clifm -l report-cwd -d 'Report the current directory to the terminal' complete -c clifm -l rl-vi-mode -d 'Set readline to vi editing mode (defaults to emacs mode)' complete -c clifm -l secure-cmds -d 'Filter commands to prevent command injection' complete -c clifm -l secure-env -d 'Run in a sanitized environment (regular mode)' complete -c clifm -l secure-env-full -d 'Run in a sanitized environment (full mode)' complete -c clifm -l sel-file -r -d 'Set a custom selections file' complete -c clifm -l share-selbox -d 'Make the Selection Box common to different profiles' complete -c clifm -l shotgun-file -r -d 'Set a custom configuration file for shotgun' complete -c clifm -l si -d 'Print sizes in powers of 1000 instead of 1024' complete -c clifm -l smenutab -d 'Use smenu to display completion matches' complete -c clifm -l sort-reverse -d 'Sort in reverse order, e.g. z-a instead of a-z' complete -c clifm -l stat -d 'Run the p command on FILE and exit' complete -c clifm -l stat-full -d 'Run the pp command on FILE and exit' complete -c clifm -l stdtab -d 'Force the use of the standard tab completion mode (readline)' complete -c clifm -l time-style -d 'Time/date style used in long view' complete -c clifm -l trash-as-rm -d 'The \'r\' command executes \'trash\' instead of \'rm\' to prevent accidental deletions' complete -c clifm -l unicode -d 'Force the use of Unicode decorations' complete -c clifm -l virtual-dir-full-paths -d 'Files in virtual directories are listed as full paths instead of target basenames' complete -c clifm -l virtual-dir -r -d 'Absolute path to a directory to be used as virtual directory' complete -c clifm -l vt100 -d 'Run in VT100 compatibility mode' clifm-1.26.3/misc/completions.zsh000066400000000000000000000173071506632037700167330ustar00rootroot00000000000000#compdef clifm # # Completion definition for clifm # Author: L. Abramovich # setopt localoptions noshwordsplit noksharrays local -a args args=( {-a,--show-hidden}'[show hidden files]' {-A,--no-hidden}'[do not show hidden files (default)]' {-b+,--bookmarks-file=}'[set an alternative bookmarks file]:filename:_files' {-c+,--config-file=}'[set an alternative configuration file]:filename:_files' {-D+,--config-dir=}'[set an alternative configuration directory]:directory:_directories' {-e,--no-eln}'[do not print ELNs (entry list number) at the left of each filename]' {-E,--eln-use-workspace-color}'[ELNs use the color of the current workspace]' {-f,--dirs-first}'[list directories first (default)]' {-F,--no-dirs-first}'[do not list directories first]' {-g,--pager}'[enable the pager]' {-G,--no-pager}'[disable the pager (default)]' {-h,--help}'[show this help and exit]' {-H,--horizontal-list}'[list files horizontally]' {-i,--no-case-sensitive}'[no case-sensitive file listing (default)]' {-I,--case-sensitive}'[case-sensitive file listing]' {-k+,--keybindings-file=}'[set an alternative keybindings file]:filename:_files' {-l,--long-view}'[enable long/detailed view mode]' {-L,--follow-symlinks-long}'[follow symbolic links in long view]' {-m,--dihist-map}'[enable the directory history map]' {-o,--autols}'[list files automatically (default)]' {-O,--no-autols}'[do not list files automatically]' {-p+,--path=}'[set the starting path]:directory:_directories' {-P+,--profile=}'[use/create PROFILE as profile]:profile:->profiles' {-r,--no-refresh-on-empty-line}'[do not refresh the screen when pressing Enter on empty line]' {-s,--splash}'[print the logo screen at startup]' {-S,--stealth-mode}'[leave no trace on the host system]' {-t,--disk-usage-analyzer}'[run in disk usage analyzer mode]' {-T+,--trash-dir=}'[set an alternative trash directory]:directory:_directories' {-v,--version}'[show version details and exit]' {-w+,--workspace=}'[start in workspace NUM]:workspace:->workspaces' {-x,--no-ext-cmds}'[disallow the use of external commands]' {-y,--light-mode}'[enable the light mode]' {-z+,--sort=}'[sort files by METHOD]:method:->methods' '--bell=[set terminal bell style]:bell:->bells' '--case-sens-dirjump[do not ignore case when querying the jump database]' '--case-sens-path-comp[do not ignore case when completing filenames]' '--cd-on-quit[write last visited path to $XDG_CONFIG_HOME/clifm/.last]' '--color-scheme=[set color scheme]:color:->colorschemes' '--color-links-as-target[color symbolic links using the target file color]' '--cwd-in-title[print current directory in the terminal window title]' '--data-dir=[use PATH as data directory]:directory:_directories' '--desktop-notifications[enable desktop notifications]' '--disk-usage[display disk usage for the filesystem where the current directory resides]' '--full-dir-size[display recursive directory sizes (long view)]' '--fuzzy-algo=[fuzzy matching algorithm]:algo:->algos' '--fuzzy-matching[enable fuzzy matches for filename/path completions and suggestions]' '--fzfpreview-hidden[same as --fzftab, but with the preview window hidden. Toggle it via Alt-p]' '--fzftab[use fzf to display completion matches]' '--fzytab[use fzy to display completion matches]' '--icons[enable icons]' '--icons-use-file-color[icon colors follows file colors]' '--int-vars[enable internal variables]' '--kitty-keys[ask the terminal to enable the kitty keyboard protocol]' '--list-and-quit[list files and quit]' '--lscolors[read file colors from LS_COLORS]' '--max-dirhist=[maximum number of visited directories to remember]:int:' '--max-files=[list only up to NUM files]:int:' '--mimelist-file=[set Lira configuration file to FILE]:filename:_files' '--mnt-udisks2[use udisks2 instead of udevil for the media command]' '--no-bold[disable bold colors]' '--no-cd-auto[force the use of cd to change directories]' '--no-classify[Do not append filetype indicators]' '--no-clear-screen[do not clear the screen when listing directories]' '--no-color[Run without colors]' '--no-columns[disable columned file listing]' '--no-file-cap[do not check file capabilities when listing files]' '--no-file-ext[do not check file extensions when listing files]' '--no-file-counter[disable the file counter for directories]' '--no-follow-symlinks[do not follow symbolic links when listing files]' '--no-fzfpreview[disable file previews for tab completion (fzf mode only)]' '--no-highlight[disable syntax highlighting]' '--no-history[do not write commands into the history file]' '--no-open-auto[same as no-cd-auto, but for files]' '--no-refresh-on-resize[do not update the file list upon window'\''s resize]' '--no-restore-last-path[do not restore last visited directory at startup]' '--no-suggestions[disable auto-suggestions]' '--no-tips[disable startup tips]' '--no-truncate-names[do not truncate filenames]' '--no-unicode[do not use Unicode characters]' '--no-warning-prompt[disable the warning prompt]' '--no-welcome-message[disable the welcome message]' '--only-dirs[list only directories and symbolic links to directories]' '--open=[open FILE and exit]:filename:_files' '--opener=[file opener to use instead of the builtin opener]:opener:_command_names' '--pager-view=[how to list files in the pager]:pager_view:->pager_views' '--physical-size[display physical file sizes (disk usage) rather than logical sizes (apparent size)]' '--preview=[display a preview of FILE and exit]:filename:_files' '--print-sel[always print the list of selected files]' '--ptime-style=[time/date style used by the p/pp command]:pstyle:->pstyles' '--readonly[disable internal commands able to modify the filesystem]' '--report-cwd[report the current directory to the terminal]' '--rl-vi-mode[set readline to vi editing mode (defaults to emacs editing mode)]' '--secure-cmds[filter commands to prevent command injection]' '--secure-env[run in a sanitized environment (regular mode)]' '--secure-env-full[run in a sanitized environment (full mode)]' '--sel-file=[set FILE as selections file]:filename:_files' '--share-selbox[make the Selection Box common to different profiles]' '--shotgun-file=[set shotgun configuration file to FILE]:filename:_files' '--si[display sizes in powers of 1000 instead of 1024]' '--smenutab[use smenu to display completion matches]' '--sort-reverse[sort in reverse order]' '--stat=[run the '\''p'\'' command on FILE and exit]:filename:_files' '--stat-full=[run the '\''pp'\'' command on FILE and exit]:filename:_files' '--stdtab[use standard tab completion]' '--time-style=[time/date style used in long view]:style:->styles' '--trash-as-rm[the '\''r'\'' command executes '\''trash'\'' instead of '\''rm'\'']' '--unicode[force the use of Unicode decorations]' '--virtual-dir=[use PATH as virtual directory]:directory:_directories' '--virtual-dir-full-paths[print full path filenames in virtual directories]' '--vt100[run in VT100 compatibility mode]' '*:filename:_files' ) _arguments -w -s -S $args[@] && ret=0 case "$state" in profiles) local -a prof_files prof_files=( $(basename -a $HOME/.config/clifm/profiles/*) ) _multi_parts / prof_files ;; bells) _values -s , 'bells' 0 1 2 3 ;; pager_views) _values -s , 'pager_views' auto long short ;; algos) _values -s , 'algos' 1 2 ;; colorschemes) local -a color_schemes color_schemes=( $(basename -a $HOME/.config/clifm/colors/* | cut -d. -f1) ) _multi_parts / color_schemes ;; methods) _values -s , 'methods' none name size atime btime mtime version extension inode owner group blocks links type ;; styles) _values -s , 'styles' default relative iso long-iso full-iso ;; pstyles) _values -s , 'pstyles' default iso long-iso full-iso full-iso-nano ;; workspaces) _values -s , 'workspaces' 1 2 3 4 5 6 7 8 ;; esac clifm-1.26.3/misc/cygwin/000077500000000000000000000000001506632037700151415ustar00rootroot00000000000000clifm-1.26.3/misc/cygwin/Makefile000066400000000000000000000062561506632037700166120ustar00rootroot00000000000000############################### # Makefile for clifm - CYGWIN # ############################### BIN ?= clifm BIN_EXE ?= $(BIN).exe PREFIX ?= /usr/local BINDIR ?= $(PREFIX)/bin DATADIR ?= $(PREFIX)/share MANDIR ?= $(PREFIX)/man LOCALEDIR ?= $(DATADIR)/locale DESKTOPPREFIX ?= $(DATADIR)/applications DESKTOPICONPREFIX ?= $(DATADIR)/icons/hicolor PROG_DATADIR ?= $(DATADIR)/$(BIN) SHELL ?= /bin/sh INSTALL ?= install RM ?= rm SRCDIR = src SRC = $(SRCDIR)/*.c HEADERS = $(SRCDIR)/*.h CFLAGS ?= -O3 -fstack-protector-strong LIBS ?= -lreadline -lacl -lmagic -lintl CFLAGS += -Wall -Wextra -DCLIFM_DATADIR=$(DATADIR) $(BIN_EXE): $(SRC) $(HEADERS) $(CC) -o $(BIN_EXE) $(SRC) $(CFLAGS) $(LDFLAGS) $(LIBS) build: $(BIN_EXE) clean: $(RM) -- $(BIN_EXE) $(RM) -f -- $(SRCDIR)/*.o install: $(BIN_EXE) $(INSTALL) -m 0755 -d $(DESTDIR)$(BINDIR) $(INSTALL) -m 0755 $(BIN_EXE) $(DESTDIR)$(BINDIR) $(INSTALL) -m 0755 -d $(DESTDIR)$(PROG_DATADIR) $(INSTALL) -m 0755 -d $(DESTDIR)$(MANDIR)/man1 $(INSTALL) -m 0755 -d $(DESTDIR)$(DATADIR)/bash-completion/completions $(INSTALL) -m 0755 -d $(DESTDIR)$(DATADIR)/zsh/site-functions $(INSTALL) -m 0755 -d $(DESTDIR)$(DATADIR)/fish/vendor_completions.d $(INSTALL) -m 0755 -d $(DESTDIR)$(DESKTOPPREFIX) $(INSTALL) -m 0755 -d $(DESTDIR)$(DESKTOPICONPREFIX)/scalable/apps $(INSTALL) -m 0644 misc/$(BIN).1 $(DESTDIR)$(MANDIR)/man1 $(INSTALL) -m 0644 misc/completions.bash $(DESTDIR)$(DATADIR)/bash-completion/completions/$(BIN) $(INSTALL) -m 0644 misc/completions.zsh $(DESTDIR)$(DATADIR)/zsh/site-functions/_$(BIN) $(INSTALL) -m 0644 misc/completions.fish $(DESTDIR)$(DATADIR)/fish/vendor_completions.d/$(BIN).fish $(INSTALL) -m 0644 misc/$(BIN).desktop $(DESTDIR)$(DESKTOPPREFIX) $(INSTALL) -m 0644 misc/*.clifm $(DESTDIR)$(PROG_DATADIR) $(INSTALL) -m 0644 misc/clifmrc $(DESTDIR)$(PROG_DATADIR) $(INSTALL) -m 0644 misc/logo/$(BIN).svg $(DESTDIR)$(DESKTOPICONPREFIX)/scalable/apps $(INSTALL) -m 0755 -d $(DESTDIR)$(PROG_DATADIR)/plugins $(INSTALL) -m 0755 -d $(DESTDIR)$(PROG_DATADIR)/functions $(INSTALL) -m 0755 -d $(DESTDIR)$(PROG_DATADIR)/colors $(INSTALL) -m 0755 -d $(DESTDIR)$(PROG_DATADIR)/tools $(INSTALL) -m 0755 plugins/* $(DESTDIR)$(PROG_DATADIR)/plugins $(INSTALL) -m 0755 misc/tools/imgprev/clifmrun $(DESTDIR)$(PROG_DATADIR)/plugins $(INSTALL) -m 0755 misc/tools/imgprev/clifmimg $(DESTDIR)$(PROG_DATADIR)/plugins $(INSTALL) -m 0755 misc/tools/*.py $(DESTDIR)$(PROG_DATADIR)/tools chmod 644 $(DESTDIR)$(PROG_DATADIR)/plugins/BFG.cfg chmod 644 $(DESTDIR)$(PROG_DATADIR)/plugins/plugins-helper $(INSTALL) -m 0644 misc/colors/*.clifm $(DESTDIR)$(PROG_DATADIR)/colors $(INSTALL) -m 0644 functions/* $(DESTDIR)$(PROG_DATADIR)/functions @printf "Successfully installed $(BIN)\n" uninstall: $(RM) -- $(DESTDIR)$(BINDIR)/$(BIN_EXE) $(RM) -- $(DESTDIR)$(MANDIR)/man1/$(BIN).1* $(RM) -- $(DESTDIR)$(DATADIR)/bash-completion/completions/$(BIN) $(RM) -- $(DESTDIR)$(DATADIR)/zsh/site-functions/_$(BIN) $(RM) -- $(DESTDIR)$(DATADIR)/fish/vendor_completions.d/$(BIN).fish $(RM) -- $(DESTDIR)$(DESKTOPPREFIX)/$(BIN).desktop $(RM) -r -- $(DESTDIR)$(PROG_DATADIR) $(RM) -- $(DESTDIR)$(DESKTOPICONPREFIX)/scalable/apps/$(BIN).svg @printf "Successfully uninstalled $(BIN)\n" clifm-1.26.3/misc/freebsd/000077500000000000000000000000001506632037700152535ustar00rootroot00000000000000clifm-1.26.3/misc/freebsd/us.clifm.kbd000066400000000000000000000166371506632037700174720ustar00rootroot00000000000000# $FreeBSD$ # alt # scan cntrl alt alt cntrl lock # code base shift cntrl shift alt shift cntrl shift state # ------------------------------------------------------------------ 000 nop nop nop nop nop nop nop nop O 001 esc esc esc esc esc esc debug esc O 002 '1' '!' nop nop '1' '!' nop nop O 003 '2' '@' nul nul '2' '@' nul nul O 004 '3' '#' nop nop '3' '#' nop nop O 005 '4' '$' nop nop '4' '$' nop nop O 006 '5' '%' nop nop '5' '%' nop nop O 007 '6' '^' rs rs '6' '^' rs rs O 008 '7' '&' nop nop '7' '&' nop nop O 009 '8' '*' nop nop '8' '*' nop nop O 010 '9' '(' nop nop '9' '(' nop nop O 011 '0' ')' nop nop '0' ')' nop nop O 012 '-' '_' us us '-' '_' us us O 013 '=' '+' nop nop '=' '+' nop nop O 014 bs bs del del bs bs del del O 015 ht btab nop nop ht btab nop nop O 016 'q' 'Q' dc1 dc1 'q' 'Q' dc1 dc1 C 017 'w' 'W' etb etb 'w' 'W' etb etb C 018 'e' 'E' enq enq 'e' 'E' enq enq C 019 'r' 'R' dc2 dc2 'r' 'R' dc2 dc2 C 020 't' 'T' dc4 dc4 't' 'T' dc4 dc4 C 021 'y' 'Y' em em 'y' 'Y' em em C 022 'u' 'U' nak nak 'u' 'U' nak nak C 023 'i' 'I' ht ht 'i' 'I' ht ht C 024 'o' 'O' si si 'o' 'O' si si C 025 'p' 'P' dle dle 'p' 'P' dle dle C 026 '[' '{' esc esc '[' '{' esc esc O 027 ']' '}' gs gs ']' '}' gs gs O 028 cr cr nl nl cr cr nl nl O 029 lctrl lctrl lctrl lctrl lctrl lctrl lctrl lctrl O 030 'a' 'A' soh soh 'a' 'A' soh soh C 031 's' 'S' dc3 dc3 's' 'S' dc3 dc3 C 032 'd' 'D' eot eot 'd' 'D' eot eot C 033 'f' 'F' ack ack 'f' 'F' ack ack C 034 'g' 'G' bel bel 'g' 'G' bel bel C 035 'h' 'H' bs bs 'h' 'H' bs bs C 036 'j' 'J' nl nl 'j' 'J' nl nl C 037 'k' 'K' vt vt 'k' 'K' vt vt C 038 'l' 'L' ff ff 'l' 'L' ff ff C 039 ';' ':' nop nop ';' ':' nop nop O 040 ''' '"' nop nop ''' '"' nop nop O 041 '`' '~' nop nop '`' '~' nop nop O 042 lshift lshift lshift lshift lshift lshift lshift lshift O 043 '\' '|' fs fs '\' '|' fs fs O 044 'z' 'Z' sub sub 'z' 'Z' sub sub C 045 'x' 'X' can can 'x' 'X' can can C 046 'c' 'C' etx etx 'c' 'C' etx etx C 047 'v' 'V' syn syn 'v' 'V' syn syn C 048 'b' 'B' stx stx 'b' 'B' stx stx C 049 'n' 'N' so so 'n' 'N' so so C 050 'm' 'M' cr cr 'm' 'M' cr cr C 051 ',' '<' nop nop ',' '<' nop nop O 052 '.' '>' nop nop '.' '>' nop nop O 053 '/' '?' nop nop '/' '?' nop nop O 054 rshift rshift rshift rshift rshift rshift rshift rshift O 055 '*' '*' '*' '*' '*' '*' '*' '*' O 056 meta meta meta meta meta meta meta meta O 057 ' ' ' ' nul ' ' ' ' ' ' susp ' ' O 058 clock clock clock clock clock clock clock clock O 059 fkey01 fkey13 fkey25 fkey37 scr01 scr11 scr01 scr11 O 060 fkey02 fkey14 fkey26 fkey38 scr02 scr12 scr02 scr12 O 061 fkey03 fkey15 fkey27 fkey39 scr03 scr13 scr03 scr13 O 062 fkey04 fkey16 fkey28 fkey40 scr04 scr14 scr04 scr14 O 063 fkey05 fkey17 fkey29 fkey41 scr05 scr15 scr05 scr15 O 064 fkey06 fkey18 fkey30 fkey42 scr06 scr16 scr06 scr16 O 065 fkey07 fkey19 fkey31 fkey43 scr07 scr07 scr07 scr07 O 066 fkey08 fkey20 fkey32 fkey44 scr08 scr08 scr08 scr08 O 067 fkey09 fkey21 fkey33 fkey45 scr09 scr09 scr09 scr09 O 068 fkey10 fkey22 fkey34 fkey46 scr10 scr10 scr10 scr10 O 069 nlock nlock nlock nlock nlock nlock nlock nlock O 070 slock slock slock slock slock slock slock slock O 071 fkey49 '7' '7' '7' '7' '7' '7' '7' N 072 fkey50 '8' '8' '8' '8' '8' '8' '8' N 073 fkey51 '9' '9' '9' '9' '9' '9' '9' N 074 fkey52 '-' '-' '-' '-' '-' '-' '-' N 075 fkey53 '4' '4' '4' '4' '4' '4' '4' N 076 fkey54 '5' '5' '5' '5' '5' '5' '5' N 077 fkey55 '6' '6' '6' '6' '6' '6' '6' N 078 fkey56 '+' '+' '+' '+' '+' '+' '+' N 079 fkey57 '1' '1' '1' '1' '1' '1' '1' N 080 fkey58 '2' '2' '2' '2' '2' '2' '2' N 081 fkey59 '3' '3' '3' '3' '3' '3' '3' N 082 fkey60 '0' '0' '0' '0' '0' '0' '0' N 083 del '.' '.' '.' '.' '.' boot boot N 084 nop nop nop nop nop nop nop nop O 085 nop nop nop nop nop nop nop nop O 086 nop nop nop nop nop nop nop nop O 087 fkey11 fkey23 fkey35 fkey47 scr11 scr11 scr11 scr11 O 088 fkey12 fkey24 fkey36 fkey48 scr12 scr12 scr12 scr12 O 089 cr cr nl nl cr cr nl nl O 090 rctrl rctrl rctrl rctrl rctrl rctrl rctrl rctrl O 091 '/' '/' '/' '/' '/' '/' '/' '/' N 092 nscr pscr debug debug nop nop nop nop O 093 meta meta meta meta meta meta meta meta O 094 fkey49 fkey49 fkey49 fkey49 fkey49 fkey49 fkey49 fkey49 O 095 fkey50 fkey50 fkey50 fkey50 fkey50 fkey50 fkey50 fkey50 O 096 fkey51 fkey51 fkey51 fkey51 fkey51 fkey51 fkey51 fkey51 O 097 fkey53 fkey53 fkey53 fkey53 fkey53 fkey53 fkey53 fkey53 O 098 fkey55 fkey55 fkey55 fkey55 fkey55 fkey55 fkey55 fkey55 O 099 fkey57 fkey57 fkey57 fkey57 fkey57 fkey57 fkey57 fkey57 O 100 fkey58 fkey58 fkey58 fkey58 fkey58 fkey58 fkey58 fkey58 O 101 fkey59 fkey59 fkey59 fkey59 fkey59 fkey59 fkey59 fkey59 O 102 fkey60 paste fkey60 fkey60 fkey60 fkey60 fkey60 fkey60 O 103 fkey61 fkey61 fkey61 fkey61 fkey61 fkey61 boot fkey61 O 104 slock saver slock saver susp nop susp nop O 105 lalt lalt lalt lalt lalt lalt lalt lalt O 106 fkey63 fkey63 fkey63 fkey63 fkey63 fkey63 fkey63 fkey63 O 107 fkey64 fkey64 fkey64 fkey64 fkey64 fkey64 fkey64 fkey64 O 108 nop nop nop nop nop nop nop nop O clifm-1.26.3/misc/haiku/000077500000000000000000000000001506632037700147425ustar00rootroot00000000000000clifm-1.26.3/misc/haiku/Makefile000066400000000000000000000062001506632037700164000ustar00rootroot00000000000000############################## # Makefile for clifm (HAIKU) # ############################## BIN ?= clifm PREFIX ?= /boot/system/non-packaged BINDIR ?= $(PREFIX)/bin MANPREFIX ?= $(PREFIX)/documentation/man DATADIR ?= $(PREFIX)/data PROG_DATADIR ?= $(DATADIR)/$(BIN) SHELL ?= /bin/sh INSTALL ?= install RM ?= rm SRCDIR = src OBJS != ls $(SRCDIR)/*.c | sed "s/.c\$$/.o/g" #CFLAGS ?= -O3 -fstack-protector-strong -march=native -Wall LIBS ?= -lreadline ifdef _BE_POSIX LIBS += -D_BE_POSIX endif ifdef _NO_ARCHIVING LIBS += -D_NO_ARCHIVING endif ifdef _NERD LIBS += -D_NERD endif ifdef _NO_GETTEXT LIBS += -D_NO_GETTEXT else LIBS += -lintl endif ifdef _NO_ICONS LIBS += -D_NO_ICONS endif ifdef _NO_LIRA LIBS += -D_NO_LIRA -D_NO_MAGIC endif ifdef _NO_MAGIC LIBS += -D_NO_MAGIC else LIBS += -lmagic endif ifdef _NO_SUGGESTIONS LIBS += -D_NO_SUGGESTIONS endif ifdef _NO_TRASH LIBS += -D_NO_TRASH endif CFLAGS += -DCLIFM_DATADIR=$(DATADIR) build: ${OBJS} $(CC) -o $(BIN) ${OBJS} $(LIBS) $(CFLAGS) clean: $(RM) -- $(BIN) $(RM) -f -- $(SRCDIR)/*.o install: build $(INSTALL) -m 0755 -d $(DESTDIR)$(BINDIR) $(INSTALL) -m 0755 $(BIN) $(DESTDIR)$(BINDIR) $(INSTALL) -m 0755 -d $(DESTDIR)$(PROG_DATADIR) $(INSTALL) -m 0755 -d $(DESTDIR)$(MANPREFIX)/man1 $(INSTALL) -m 0755 -d $(DESTDIR)$(DATADIR)/bash-completion/completions $(INSTALL) -m 0755 -d $(DESTDIR)$(DATADIR)/zsh/site-functions $(INSTALL) -m 0755 -d $(DESTDIR)$(DATADIR)/fish/vendor_completions.d $(INSTALL) -m 0644 misc/$(BIN).1 $(DESTDIR)$(MANPREFIX)/man1 $(INSTALL) -m 0644 misc/completions.bash $(DESTDIR)$(DATADIR)/bash-completion/completions/$(BIN) $(INSTALL) -m 0644 misc/completions.zsh $(DESTDIR)$(DATADIR)/zsh/site-functions/_$(BIN) $(INSTALL) -m 0644 misc/completions.fish $(DESTDIR)$(DATADIR)/fish/vendor_completions.d/$(BIN).fish $(INSTALL) -m 0644 misc/*.clifm $(DESTDIR)$(PROG_DATADIR) $(INSTALL) -m 0644 misc/haiku/*.clifm $(DESTDIR)$(PROG_DATADIR) $(INSTALL) -m 0644 misc/clifmrc $(DESTDIR)$(PROG_DATADIR) $(INSTALL) -m 0755 -d $(DESTDIR)$(PROG_DATADIR)/plugins $(INSTALL) -m 0755 -d $(DESTDIR)$(PROG_DATADIR)/functions $(INSTALL) -m 0755 -d $(DESTDIR)$(PROG_DATADIR)/colors $(INSTALL) -m 0755 -d $(DESTDIR)$(PROG_DATADIR)/tools $(INSTALL) -m 0755 plugins/* $(DESTDIR)$(PROG_DATADIR)/plugins $(INSTALL) -m 0755 misc/tools/imgprev/clifmrun $(DESTDIR)$(PROG_DATADIR)/plugins $(INSTALL) -m 0755 misc/tools/imgprev/clifmimg $(DESTDIR)$(PROG_DATADIR)/plugins $(INSTALL) -m 0755 misc/tools/*.py $(DESTDIR)$(PROG_DATADIR)/tools chmod 644 -- $(DESTDIR)$(PROG_DATADIR)/plugins/BFG.cfg chmod 644 -- $(DESTDIR)$(PROG_DATADIR)/plugins/plugins-helper $(INSTALL) -m 0644 misc/colors/*.clifm $(DESTDIR)$(PROG_DATADIR)/colors $(INSTALL) -m 0644 functions/* $(DESTDIR)$(PROG_DATADIR)/functions @printf "Successfully installed $(BIN)\n" uninstall: $(RM) -- $(DESTDIR)$(BINDIR)/$(BIN) $(RM) -- $(DESTDIR)$(MANPREFIX)/man1/$(BIN).1* $(RM) -- $(DESTDIR)$(DATADIR)/bash-completion/completions/$(BIN) $(RM) -- $(DESTDIR)$(DATADIR)/zsh/site-functions/_$(BIN) $(RM) -- $(DESTDIR)$(DATADIR)/fish/vendor_completions/$(BIN).fish $(RM) -r -- $(DESTDIR)$(PROG_DATADIR) @printf "Successfully uninstalled $(BIN)\n" clifm-1.26.3/misc/haiku/keybindings.clifm000066400000000000000000000040301506632037700202610ustar00rootroot00000000000000 ################################## # Keybindings file for Clifm # ################################## # Empty and commented lines are ignored. # Below is the list of available functions and their default key bindings. # To edit a keybinding use the 'kb bind' command. For example, to bind # the previous-dir function run 'kb bind previous-dir', enter a new # key binding and confirm. # # In case you wan to edit this file manually, use Emacs style key sequences. # For example, use "action:\C-t" to bind the action name 'action' to Ctrl-t, # or "action:\et" to bind it to Alt-t. # Ctrl-j previous-dir:\C-j # Ctrl-left previous-dir2:\eO5D # Ctrl-k next-dir:\C-k next-dir2:\eO5C Page-down first-dir:\e[5~ Page-up last-dir:\e[6~ # Ctrl-u parent-dir:\C-u # Ctrl-up parent-dir2:\eO5A # Home key home-dir2:\eOH # End key root-dir:\eOF pinned-dir:\C-p workspace1:\eOP workspace2:\eOQ workspace3:\eOR workspace4:\eOS # Help # F5-7 show-manpage:\e[15~ show-cmds:\e[17~ show-kbinds:\e[18~ #create-file:\C-n new-instance:\C-x #previous-profile:\C-\M-o #next-profile:\C-\M-p #archive-sel:\C-\M-a #rename-sel:\C-\M-r #remove-sel:\C-\M-d #trash-sel:\C-\M-t #untrash-all:\C-\M-u #move-sel:\C-\M-n #export-sel:\C-\M-e #open-sel:\C-\M-g #bookmark-sel:\C-\M-b #refresh-screen:\C-r #show-dirhist:\C-h Insert key paste-sel:\e[2~ clear-line:\C-e clear-msgs:\C-t toggle-hidden:\C-h toggle-light:\C-y toggle-long:\C-l sort-previous:\C-q sort-next:\C-w bookmarks:\C-b select-all:\C-a selbox:\C-s deselect-all:\C-r #mountpoints:\M-m folders-first:\C-g lock:\C-o # F8-12 edit-color-scheme:\e[19~ open-keybinds:\e[20~ open-config:\e[21~ open-bookmarks:\e[23~ quit:\e[24~ #open-mime:\e[17~ #open-jump-db:\e[18~ #open-preview:\e[18~ # Plugins # 1) Make sure your plugin is in the plugins directory (or use any of the # plugins in there) # 2) Link pluginx to your plugin using the 'actions edit' command. Ex: # "plugin1=myplugin.sh" # 3) Set a keybinding here for pluginx. Ex: "plugin1:\M-7" #plugin1: #plugin2: #plugin3: #plugin4: clifm-1.26.3/misc/haiku/readline.clifm000066400000000000000000000024751506632037700175510ustar00rootroot00000000000000# Readline keybindings for CliFM # For the complete list of Readline options see: # https://www.gnu.org/software/bash/manual/html_node/Readline-Init-File-Syntax.html#Readline-Init-File-Syntax #$include /etc/inputrc # Color files by types set colored-stats on # Append char to indicate type set visible-stats on # Mark symlinked directories set mark-symlinked-directories on # Color the common prefix set colored-completion-prefix on # Color the common prefix in menu-complete set menu-complete-display-prefix on set show-all-if-ambiguous on set completion-ignore-case on #set meta-flag on #set input-meta on #set output-meta on $if mode=emacs # For linux console and RH/Debian xterm #"\e[5C": forward-word #"\e[5D": backward-word #"\e\e[C": forward-word #"\e\e[D": backward-word #"\e[1;5C": forward-word #"\e[1;5D": backward-word # For rxvt #"\x1b\x4f\x64": backward-word #"\x1b\x4f\x63": forward-word #Disable some readline keybinds to prevent conflicts #"\C-i": #"\C-m": "\C-d": "\C-x": "\C-x\C-x": "\C-n": "\C-v": "\C-u": "\C-r": "\ep": # Rebind some keybinds to avoid conflicts with CliFM specific keybinds "\ea": beginning-of-line "\ee": end-of-line "\C-x\C-x": re-read-init-file "\C-p\C-p": exchange-point-and-mark # History completion based on prefix "\eOA": history-search-backward "\eOB": history-search-forward $endif clifm-1.26.3/misc/keybindings.clifm000066400000000000000000000066171506632037700171750ustar00rootroot00000000000000 ################################## # Keybindings File for Clifm # ################################## # Empty and commented lines are ignored. # Below is the list of available functions and their default keybindings. # To edit a keybinding use the 'kb bind' command. For example, to bind # the 'previous-dir' function, run 'kb bind previous-dir', enter a new # keybinding, and confirm. # # In case you want to edit this file manually, use Emacs style key sequences. # For example, use "action:\C-t" to bind the action name 'action' to Ctrl+t, # "action:\et" to bind it to Alt+t, or "action:\e\C-t" to bind it to # Ctrl+Alt+t. # # Multiple keys can be bound to a single action name. For example, the lines # # bookmarks:\eb # bookmarks:\e\C-b # bookmarks:\C-t # # will bind Alt+b, Ctrl+Alt+b, and Ctrl-t to the bookmarks function. # --------------------------- # 1. NAVIGATION # --------------------------- # Alt+j previous-dir:\ej # Shift+Left (rxvt) previous-dir:\e[d # Shift+Left (xterm) previous-dir:\e[1;2D # Shift+Left (others) previous-dir:\e[2D # Alt+k next-dir:\ek # Shift+Right (rxvt) next-dir:\e[c # Shift+Right (xterm) next-dir:\e[1;2C # Shift+Right (others) next-dir:\e[2C # Alt+u parent-dir:\eu # Shift+Up (rxvt) parent-dir:\e[a # Shift+Up (xterm) parent-dir:\e[1;2A # Shift+Up (others) parent-dir:\e[2A # Alt+e home-dir:\ee # Home key (rxvt) #home-dir:\e[7~ # Home key (xterm) #home-dir:\e[H # Home key (Emacs term) #home-dir:\e[1~ # Alt+r root-dir:\er # Alt+/ root-dir:\e/ pinned-dir:\ep workspace1:\e1 workspace2:\e2 workspace3:\e3 workspace4:\e4 bookmarks:\eb mountpoints:\em show-dirhist:\eh launch-view:\e- # --------------------------- # 2. FILE OPERATIONS # --------------------------- archive-sel:\e\C-a copy-sel:\e\C-v create-file:\en export-sel:\e\C-e #move-sel:\e\C-n rename-sel:\e\C-r remove-sel:\e\C-d select-all:\ea deselect-all:\ed selbox:\es #open-sel:\e\C-g trash-sel:\e\C-t #untrash-all:\e\C-u # --------------------------- # 3. SETTINGS # --------------------------- dirs-first:\eg only-dirs:\e, sort-next:\ex sort-previous:\ez toggle-hidden:\ei toggle-hidden:\e. toggle-light:\ey toggle-long:\el toggle-follow-links-long:\e+ toggle-max-name-len:\e\C-l toggle-disk-usage:\e\C-i toggle-virtualdir-full-paths:\ew next-profile:\e\C-p previous-profile:\e\C-o # --------------------------- # 4. MISC # --------------------------- clear-line:\ec clear-msgs:\et #cmd-hist: #lock:\eo new-instance:\e\C-x prepend-sudo:\ev refresh-screen:\C-r run-pager:\e0 toggle-vi-mode:\e\C-j quit:\e[24~ # --------------------------- # 5. CONFIG FILES (F6-F11) # --------------------------- open-mime:\e[17~ open-preview:\e[18~ #open-jump-db:\e[18~ edit-color-scheme:\e[19~ open-keybinds:\e[20~ open-config:\e[21~ open-bookmarks:\e[23~ # --------------------------- # 6. HELP (F1-F3) # --------------------------- show-manpage:\eOP show-manpage:\e[11~ show-cmds:\eOQ show-cmds:\e[12~ show-kbinds:\eOR show-kbinds:\e[13~ # --------------------------- # 7. KEYBINDINGS FOR PLUGINS # --------------------------- # # 1) Make sure your plugin is in the plugins directory (or use any of the # plugins in there) # 2) Link pluginx to your plugin using the 'actions edit' command. E.g.: # "plugin1=myplugin.sh" # 3) Set a keybinding here for pluginx. E.g.: "plugin1:\C-y" # # Note: Up to 16 plugins are supported, i.e. from plugin1 through plugin16. # Bound to the xclip plugin plugin1:\C-y clifm-1.26.3/misc/kitty/000077500000000000000000000000001506632037700150055ustar00rootroot00000000000000clifm-1.26.3/misc/kitty/keybindings.clifm000066400000000000000000000056511506632037700203360ustar00rootroot00000000000000 ################################## # Keybindings File for Clifm # ################################## # Empty and commented lines are ignored. # This file is specially crafted to make use of the kitty keyboard protocol: # https://sw.kovidgoyal.net/kitty/keyboard-protocol/ # Below is the list of available functions and their default key bindings. # To edit a keybinding use the 'kb bind' command. For example, to bind # the previous-dir function run 'kb bind previous-dir', enter a new # key binding, and confirm. # Alt-j previous-dir:\e[106;3u # Shift-left (rxvt) previous-dir2:\e[d # Shift-left (xterm) previous-dir3:\e[1;2D # Shift-left (others) previous-dir4:\e[2D # Alt-k next-dir:\e[107;3u # Shift-right next-dir3:\e[1;2C # Alt-u parent-dir:\e[117;3u # Shift-up parent-dir3:\e[1;2A # Alt-e home-dir:\e[101;3u # Alt-r root-dir:\e[114;3u # Alt-, pinned-dir:\e[112;3u # Alt-1 workspace1:\e[49;3u # Alt-2 workspace2:\e[50;3u # Alt-3 workspace3:\e[51;3u # Alt-4 workspace4:\e[52;3u # Help # F1 show-manpage:\e[P # F2 show-cmds:\e[Q # F3 show-kbinds:\e[13~ # Ctrl-Alt-a archive-sel:\e[97;7u # Alt-b bookmarks:\e[98;3u # Alt-c clear-line:\e[99;3u # Alt-t clear-msgs:\e[116;3u # Ctrl-Alt-v copy-sel:\e[118;7u # Alt-n create-file:\e[110;3u # Alt-d deselect-all:\e[100;3u # Alt-g dirs-first:\e[103;3u # Ctrl-Alt-e export-sel:\e[101;7u # Alt-- launch-view:\e[45;3u # Alt-o #lock:\e[11;3u # Alt-m mountpoints:\e[109;3u # Ctrl-Alt-n #move-sel:\e[110;7u # Ctrl-Alt-x new-instance:\e[120;7u # Ctrl-Alt-p next-profile:\e[112;7u # Alt-, only-dirs:\e[44;3u # Ctrl-Alt-u #open-sel:\e[117;7u # Ctrl-Alt-v #paste-sel:\e[118;7u # Alt-v prepend-sudo:\e[118;3u # Ctrl-Alt-o previous-profile:\e[111;7u # Ctrl-Alt-r rename-sel:\e[114;7u # Ctrl-Alt-d remove-sel:\e[100;7u # Ctrl-r refresh-screen:\e[114;5u # Alt-0 run-pager:\e[48;3u # Alt-s selbox:\e[115;3u # Alt-a select-all:\e[97;3u # Alt-h show-dirhist:\e[104;3u # Alt-z sort-previous:\e[122;3u # Alt-x sort-next:\e[120;3u # Alt-i toggle-hidden:\e[105;3u # Alt-. toggle-hidden2:\e[46;3u # Alt-y toggle-light:\e[121;3u # Alt-l toggle-long:\e[108;3u # Alt-+ toggle-follow-links-long:\e[43;3u # Ctrl-Alt-l toggle-max-name-len:\e[108;7u # Alt-Tab toggle-disk-usage:\e[9;3u # Alt-w toggle-virtualdir-full-paths:\e[119;3u # Ctrl-Alt-t trash-sel:\e[116;7u # Ctrl-Alt-u #untrash-all:\e[117;7u # F6 open-mime:\e[17~ # F7 open-preview:\e[18~ #open-jump-db:\e[18~ # F8 edit-color-scheme:\e[19~ # F9 open-keybinds:\e[20~ # F10 open-config:\e[21~ # F11 open-bookmarks:\e[23~ # F12 quit:\e[24~ # Plugins # 1) Make sure your plugin is in the plugins directory (or use any of the # plugins in there) # 2) Link pluginx to your plugin using the 'actions edit' command. E.g.: # "plugin1=myplugin.sh" # 3) Set a keybinding here for pluginx. E.g.: "plugin1:\M-7" # Bound to the xclip plugin # Ctrl-y plugin1:\e[121;5u # Bound to sort_mtime plugin # Ctrl-r #plugin2:\e[114;5u #plugin2: #plugin3: #plugin4: clifm-1.26.3/misc/logo/000077500000000000000000000000001506632037700146015ustar00rootroot00000000000000clifm-1.26.3/misc/logo/clifm-banner-wide.png000066400000000000000000000706701506632037700206040ustar00rootroot00000000000000PNG  IHDRW( pHYsiitEXtSoftwarewww.inkscape.org< IDATx{}wE@lb%D$Q'6jNծurڸ4bb~X5ml4KhdDAQ1QFf`@n#GgޏZ.e.{?I,2|vĪUF 6؈8ReQ1&",FyޜH!˲=yx=鍿#+5R镈h۹s窉'nMZ3kL\oJY"Y@y%"RTSScƌJ՟~]TΪT*gJM@z9˲E1T*;vAEAzڵJy񹈘IDMMM;vyjAzݺugY8?"NH~?T*wN0aejЃʕ+ 6Y?1?ox:˲["⎖S9nذal__Ey]D?u@A6eYvӠAn=ztg5鎎y͈ˈ슈;#;GqKcՀׯ_t\Y]R$RɲlZ\_ukzgϞ+ %˲=,qmLNjr/raDyJPvDĿwqR׭[wze7Gı[Jo'LhV3t[[afY."7wڵ\*~cS dY ZZZ$oImmmC|mD\yZ*zd#?\T~NP<_^*oiiy1Rj6dY閖_W>HwttqTBkjjcǶUAzewWWטJHrynggj>hk뛑ecëU~AjDnoo`D,Cq9۳,;|ewGG!1=hd?ikkzp0!}]Dp@mhss5tewGGy?xy'Ǐ`?qk׾T**"0 u޽#s̖T*]hF|~~^ng,y~' +Wɲ0F4,˲_x v]TVy> t1ct\ @DZ.|{^vR1蠳,1cƬ~{Y0F<ϛ{}ܻ8!#jeԃJ &|xҗ1T*n'_}Ֆ\,Gݹw RtQxgC.|wt[[@=޽{c9w߱C 9/y7ueً{{E^.;#WvBT*}1컬 Ʒ y?=ԋ<ݷe^nIqBP,;qe.JoRF ysY}-?_+Jgu`Tƍ;vCora*oq^>Y{-ԗ7,"kL___gD4vرJr Y\>5++ze"KGP/< _@|4""[jըCY C>xQaÆh'۵kRR9:u T*]ʲ!ԗJrL)"J@}ɲRecSPwƔ"+;/yn_K]@y_)"I]@V+/Y 1HPuy(RDd+;RAB(AB(AB J/z{{csYPbذa1|:th :4: AijW^kF{{{]6֮]I)ZZZ#G&L'ưaRdym7o˗3</+upbĉ1eʔ:uj|#!CA?p,X ֯_:(cҤIO~isiپ}{<1o޼xRlq)ęgǣ)uPei][[[}G\NԀѣGg] u My Dx;,O$=>|x )/rK<쳩SbĈqyN 4;#>WsdܸqqE'>)0HSŋ_ݩS:p'_cƌI4Ukŵ^O?t 6,.8S M,[,شiSvio|#:xiZqm浢~1~R A+".]:h0C K.$<);0Hs6o_~yZ*u Р,/~/9u  Lׯh ٲeK\~y)g?Yu]30Hzzz/u֥N'?L ͻ9rdP  @!  @!  @!  @!  @!  @!  @! bPqkK3G_~yk…`@1Hɬ_>Rg4 ڎ;R'n ai ai ai ai ai ai ai ai ai ai ai ai ai aRT[GGGٳ'uFR---ܜ:]6*JO*4Pw/"VZ:#LJ>5笳Ί[o?pp 3`B(AB(AB(AB(AB(AB(AB(Ġz{{cӦMq͛7ǦMRĶm"]vE\۷ǰabȐ!1t2dH455avX5~Y%Ј PJ֭իWG[[[Z*V^k֬7FOOO ƍGKKKy~0=8C o1Jr\2yxgbҥjժؽ{wҮ={Ě5kb͚5{}رc㎋?>N<Ębٲe3bСqFsssꔆ`SgT׾g?:Sik֬ Ă G;vN*cѢEhѢ(Jq'>8ST92q%0PYnFA󦍁'+WΨ{,8 {[rA(Acڴi1o޼hkkKDR+VĊ+;8㬳Ί:+8ԉ6lؐ:MfN`Ν1wUݝ:ci؋hmmx饗RԜ={… c…o;&MguV}q 'ٽ{wl۶-uFU͛7/v#FHPϟ? _lܸ1uP ݻwǬY{ŋGRI4`+Vk&N>8{ﭻSD <:Nh(۷oΨzj4⮻;wΩ;J%-Z- &ĩ: Օ: . 6ѣS4ٳgǮ]RgT]:P[77qiCctbҤI3hpz\.ǬYRg4g m۶ؽ{w Nhqeܹsu$kq#FH@ӧOO6o?xm鹲y馛?A]^X&O:z^tiZ*&N:ח:07n#8"uPnٳ'n8So4F'rI'N?9cƌ uޯF 4uiqYg5\===sԂ 6m#)PWWW,Y$uF @Q ԕ 6%\w^Ksސ!CNHu?Y&{uk̙Q.Sg޿Ft ԅGsss \ݝ:p̙3S'  y [Vl۶-ueԩ nvJQ3gF___ꌺ( @Q h .38#Ν:8餓R'@lذ!uB Ψ;3glw @Q{k[omoT;w/r?Ca@u5uݿSgԕ IDATF;  ~ bٲeSx#G|IcX?bĈBjs̉;wưaRԅ^z)^| ŕ (˗/`Q*uuuN7===^ʤttD ah\NH0`̘1#.صkW׏=CQTRg췖 05iӦş韦Ψ fJЯc„ 3:cykzȔ)SR'&;4F;"8S hK. YԴ袋ꫯ6F0NHP+t___<3F;x?45kϞ=կ~5f̘:4z7n\ Z[[S' hyߟ:5o @MڳgOmhꌚ4PmiUGGG\z饑y$FrJL:5N:餘4iR7'nݺ5V^?|,]4{XreM '%۷owv| _HRfϞwNQPmi7ضm[~~0>8c1hPQFŔ)Sbʔ)/9""^xbѢEpxgC?ɍ3&СCS'#[M> \_\ TA~s=#<:_7.<=w=!zjzo|#zzz'Gy$̙&Mj߈#sIAr[=---SjJwwwHQ3|f_tvvW\:p'+_J|3POO?=xٳgի1~4 鷪T*1cƌ SԔxo'NHVJ@c竺,s9'ΝsOqj]Yɓ/ ٳ .{ϛ2eJ?qZ[[S'u @MOQ|31gΜ#HB|g}6n83:;! @1ݯxSgԌxꩧRgԔ_=vؑ:#i W]uUꌪ;ꨣo;#N<998~SO=^z雧QGު+uBM>}zꄚ1s̨T*3jkj2HPoljj~#9眓:'1c7xꩧks=7u{7cƌΝ:PˮDecGGG444$Jẻc͚5c ƍH:*:9ҹڤ_~_P˗GTJ-[Dwww{n4 k׬Y{M˗ܓtnڤzzzL,uuuO~2u Jrliiv׿_|1uq]w]]sm=Poۚ8sbʔ)cUcϐcԨQ ҔoN^}xSώc9s@QHgt~hZr+F}yq饗&HTZ^۽zI~=BV> M! @=#17zʭ>t{.]Z$}so~1%u#G 34}#P3<3RhÆ #짭?wd;+Wg=\q`.*mVvGDtttT)IlܸfkyϚ5kRG襽=?C>&i^S@QH'RHq1u1*˭<;ԄtDORYbEe{gMhhh8cr^ 0 i'H,_|qեTYn+[ZZ>1K,B[cΝcoN=&J! @|rC@)@صkW⋩ceڴi#t9_]}58;C:"b„ UVX ,H~_+:F/LGG;!me70P i+޽{SPΏ6bĈ8cvÇW^Ԏx饗RHJ˱.gB:"#B[رcSG9իWKccc,^ZH[ BGbذacP^z饘9sfI_>R 6K_ַbǎ'={-W^ye(o߾Xvm̙3'ƍWc'LPp1! TRZ)O9r>|x455ئ3gNfʕ#/,?P|'s<4e{SG(B܊rQPx<9"oNqŬY~|{{{i/zG! @r}:cSGȭ8kmm/>ӓev[,]4~|sss1Dyطo_@ SHPZYٝ{@j.JqW2nz{7Le˖99[04e[~}e9#RGmew_ v?3SOO<Ę>}zc!߇=ڢ,;w1>ԨQ9u J3f̈?4r޷cǎ;R?#iӦ,[lI,`hOI\23;3:~cz i`0RHP;4 M۶mݻw~=oҥQ_Z4eQHڸqc۷/uTjewĻk*vJ{ⷿmUzʽ53fLŮMRGjBtwwP;vTY[[[+v:*<̊]Z}7W>}Qssu4eihhH,vJW Wzuҥ^tMO.?SOz0aBwy i`QHPR:BY'B .aÆU~x ʕ+ ~tvvVNH:jBJ!oTYn1nܸ^9fϞ]kVڊ+ PX9n'/4eBzÆ #U~x!;徶{͚5]ȵ}x v͘1#N8ᄊ_T*EKKKů;P iV W_}5ur+*=gϮu%m޼9BzB;˗//9#e˖>p n i2rǾ}R(m nccc,XkWJk{zzbڵ@466W\Qs,[lIA iԔ:BY;G(P)#9nxw*z͇z(֯__kܹs/]{ rF4e3fLe{RG(88c @ر#㎊^3uE0 ^k@mPHPZp4 %]]]cǎ1StDŋ @\b[ob׫5kVuB&"? ^x!uJrlmm-QWWW={Xqyg{dɒ(J#B:@mPHPcTIYғ'O}cc oȵVZUTR5ε@mPHPXG}4uJb!t*{Ϟ=?zNӧO/>!me7 iʒb~ؼys@lذ!u^QH/Z( V}1*wuWlݺB*DU3~,ײ  iHk`hmb.ZZZ رc/.>z=Rk+T*Œ%Kr;vlUހPJP*bܸq53y&.1QcƌHmbƪܫ#bŊ?~=wqwV8\pUofWgHlǏB׿u԰RǠ dX9sDsssl۶j^x!}G?y睱}R߲e˪zx駫zoFwwwJ%|k 9_"vؑ:Pΐf!=lذ+vXrejժ ';wnUYir۷f> C! @&O:Bv/R ۄtkkkUtҪޯV\}z[o]L~ZhQ1looʕkȟBR!ٝ;T޽{c˖-c짚guV[l6ms뭷ݻ J?^tD~SHPZ,{zzR yػwov!]WW/=jŊ}zի J?'OO?uBzӦM#5F! @٦L:Blܸ1}1:  IDAT=n;wLTmٲeQWWW 4e8qb455'k׮M(Ȇ RGgHGD{qiUz?iY]vmϜ.R]]]ttt$ i`PHP8餓RMMrrL5՚4-ʕ+zܪU N7sNuQIk!f o iONOx㍸뮻R c1bewD… T*%w9x7_=֭[WDY|y{1"D9~țB>B:"RG c1֖---qE%w9r!zطo_}QFfqJnɴiRG/z1 mBz1rdLvrX?7W)IyϟcƌI!B:?4}r)$}~TXnXkkkϝ;7կ~ׯ?wG}ʉ-?Bz֭gϞ1OJRvicʕ+K 6'cI3JOOOZ?w2a„9sf:k>QHggyf}w1 mB:ё:!tMzn뺗/_ cd9!kțB>B:"b&u ooviiiI!>4iR3ēO>מ~o(сR8!F! @qQ*R}ŵ^===c! 鈈XtibŊի%9N;-?1"„408(賦^nAWEcƍ#Ⱦ^jU۷/"=8Bzٲe#/ _@_:B]{>u `r,r)O88SS8_=|xG⥗^Jill \ M642k֬ފo~cVv'3潵ݹMGϝ;7ƍ:bԨQcȗB~9c„ cw?OR) ŋGTJnعsgY&u䴮=9NI+PH/uuu1o޼1vwN&s, /hjjJzzzRGO#޶m[ڵ+u F(跺?~__d(pp---#2|AZ5tI1mڴ1(;DDlڴ)uF(KP7xc|N(þ}+Z[[SG8jByNHGX O! L>=N=1*믏c7ߌ1֖:{qGRK,I@SH0`ԧRGk&ۗ: pȷϺl^Z|Wv+r)%KĘ1cRǨn!ݻSG ",וvuGjB3f̠YbE|-[&fԩq);,Ν:!577ǰaRE! K! @E|ṡz(.xGSG> ", 鈈p>|xTWWtC O9cc޼ycT//믿>zzzR"bÆ #{!hѢ(Jcd'ui4P.4ǩ#bqƧ?xWS!/",Ə~Y2eJ~cń4PŤ3K0?K.DZwq` Rͩc|lٲK,9~A! K! @E}k_KP]]]o|#ϟ>`80$VDyeѣSB}}}M9NHwuuΝ;SjB:3K/Mp?x,]4>Oc=: )!֖:BYFK# {nL4)u8!߇C<)А:FUw}1g?֭K'_=n1v]]]c짵5uuvve˖'қ6mJ i*nԩ5&@۷/nXhQ\qq7/B?/<≮kW_M A7ވ1SK̙3c„ c$5jԨ?~}sTJkn-mۖ:JU=ǵ^-ǹUDWWWw}d\r%UJP5!1 ZRC6+r((̕W^9|Qnĉ1s1>_Oe?VvPHPX`AvtwwǺubݺu)OrJL4)&MGqDy}{˖-qxbÆ K/ /_۷W>O=TEOBQr,jie{:::d!ёc&r((_j?H%[]]]q&Mhjj5jT1"FFxw"ߎ۷[o-[ݻyc1lذ6nrKUg>_^~^IW]uB%K__޽{SG=u^r|=QHP/q]wRsv?|}>lL6-u Z,΋{7u>w\6~zq>K@M)J0F: Urm7[ntCCC7.u~H/_:€8!me7P4Uq114Eɭ7n\444/͋QFQÆ 1 9NHwT (O~qWA((BOOOvҵ=G.,u;wn4771 9NHGX |84U?<1(B"l۶-vޝ:~j:kk}]wDm-;O߼6n7oNA&興xEgŅ^:ƀ:!ȋB8qb?ѣGBLIPi9_!XxqZdIJ15MHF! @zjG?or` i*M!] lٲ*T*:F/9.(Hf֬Y?u rlmmMaM'xb8ONbr\odN! @RW^ye|M( 6`XtiX|y99~PȋB䮾w:3޽{S`qsYO<R)-Z:FEjB,|sk6u *hΝ/ YaewDĄ sI., ܁ף>Bl| _~QWW: bm7[UWW---cTLggglٲ*.Ǖݹ.(W_]w] 6,u*@! @%vtsss466Q1Ϗ#GQ1w1*.Bz;癩dL! @v.O~MMM0@O?t {쉭[r~{ƌ^zipA S)y+W>:u4oDOOO,GPGGG|  id뤓N[o5>񏧎B?+Օ:ƍSGeMHGD\pٖ2eJvic=R%'4Y7n\'?~===vP6mJ8!]*bѢEc ˳,m+1Ǝ:F/9>|(^T˿믿>ƍ:}~ߧ`XtiV__?h֎LH[ Bq饗=_|q(s 8!qꩧƉ':F̜93&N:Fr\ȇB?k#FCTB+k!xeٲe#N! 45>/w\pA8|z*zzzRmܸ1u^r,+eҥQ__[¨Qb޼ycn&sLG3jԸ 閖 3q8S/?iA ><.\:FյЋB8RB}}}uYqYgŷXfMY&Nf555E] ,ٳgLj#RG`شiS 3f̈;.Qz;wn477Qu&LH4p0 iԧ>ԧb۶mqwwsOر#u{1gΜKώR TV+R!7:F/Cq]wD i` >9:;;3v֭/xb޽#&7iҤ8sώ3gɓSGz_cc㐜J }jdԨQ755l߾=frP-Ғ%Koo'u?>.18ꨣ{Mܹ3u S i8aÆ̙3c̙=m=P<ǣ>]]]cjqI'3Έs9'볠?x'S`;N>1jȑ#SG8 SSSS5K_R' , L<9uB((BB((BB((BB((BB((BB((BB((BB((BB((BB((BB((BB((BB((BB((BB((BB((BB((BB(vܙ:DD͛SG8 4ӎ;RGظqc i  i  i  i  i  i  i  i  i  i  i  i  i  i  i  i  i V[|'u M6p@ iݻwߟ:dn  i  i  i  i  i  i  i  i  i  i  i  i  i  !.ul*;nC̰aâ!u ,92uTCL]]]1"u ,)C7ZlԨQ#RHA i}TBz7n\Y;vl0('I&Bz:ꨣRGNSS i0HPy !țY ?=zt_!IDATY=<5mڴr)Bz1cF>|xL:5u tCB>}z466Bz:b̘1cd !>>я4C!={#$|0()??:@R\rI444Bz=zt̜93u fϞ: Z !PvƔ)SRAK!=ĝ~qᇧĜ9sRGAM!=544e]:@ >ܶ(B舑#GPUϏcǦB8b޼ycTMCCCtttBXlY466P^ziBhmm9s椎PX|y0$(yߕW^,i`Л7o^L81u Ҽ->OP;,(u 2짳3L:@!>Gsss0d(OCCC|_Q*jڴi1gΜ1`HQHc٩cTLCCC|+_;24/})&M:@E\}Վ%ШQF4660 g}v,]4u G>S跶׾fU7$搖,Y~Yv|ϭt{ogEP؜x˦d(!1SBaNT&6q9`X-Ұ9F4T'Zh{%?>i[{{}=}9>t q+w 89.+Wg?ٜ~Mw]+bfvnᆜr)M|#i:8 ͬuYsi5 xZ-1k֭7ߜNt @~w 5`fNv/si:8RrUW_;OM7ݔ7M'e˖{ަS(;v쨛`q:wuW֯_sx>OdڵM/ Mlڴ)7pCvt 0&&&r5dxx ޽{/|!<@)Y|yLLL4'4}q[nΝ;NE]k&Vj:4}~[/6,BN'W_}u.¦S90Hw[l6,zj.˒%K ͼysw{t9ti|g.Ҝr)M' ͼ۲eKn{fi Iz\~Klٲs1HӘgٸqcl޼`-[,]tQ&&&rfhh$ ,[n͆ qtݦs>Yti?\|y[ޒᦓ>2H<3y?=Pzꩦ9g . oxryeҥMg ͂vOd۶mپ}{vؑ'|2>li!K,h3::Y&guSp3HhMOOg߾}yo߾8p SSSMg+_ʬX"˛%M\ eŊYbE)`0 4}a/ Ah%`T$`4Hsiz$SM0p>{ pիG$jcGܘ8H8p[I5Akjj_#k׮_JR׼~pNպ%%_dQ;uٙWJի>Ϗ:H'I]ןO2*R /M/)SoXښ5k{ϼ $O%9ث(R CCC7sR?& Ů믌l99H'I)/=*gK)> nwuk`|> $=-I~2$u/lvZU:NOH'Iݾ7: ˳YIrkK)^}xx^4Azڵ{| I=kXt$<3~: g=H'IN˵,*=::a.iN~z= |y׵Z^y"`[UՅs>!$cccu}.\y"ctrtk]u`a(|uEL]׭;v^J;Du'Uu]/}@bNztBnKrN/ @=RJNW7 $'WZ%I2::RJv&h[{}~eLnܪ6$3RJ2n7=?!}X<44溮3'گ1: &'' I8.?I21:: :u]V8[{NaN=SSSInVUU]eLu]v񗥔'vRJ=_md޾}R&pi)N~pco߾rG70~PU6yG266o&|T'yjj귛{'''Li`۞䃣iLN;m4\u],3MNN^]_IM,?*||鐙 :nRʇn`{6ɟݻ6F' Lgu$W%Ytq0?566阣YЃakre%M4BUUUU5k}I'zUU7.!E5HSO꺮4əMɮ$_ۑM֢ۼyҕ+Wq)I PM'JߥOOOc|||_As陞~^x?Iry)弦{fên_d7GFF4 3Hv_[Ue?MIZM7t)jt:?n:rirr̺'L$ys_o8 8yO]ccc{꧁_7RT~])emN¿ o꺮R6R{:6ɮ]~gZWWU$$d塏/OPILsIM;ɞ$;K)[ljҥK[j u.͇IENDB`clifm-1.26.3/misc/logo/clifm-banner-wide.svg000066400000000000000000000123511506632037700206070ustar00rootroot00000000000000 CliFM clifm-1.26.3/misc/logo/clifm-banner.png000066400000000000000000000575731506632037700176650ustar00rootroot00000000000000PNG  IHDRKZ pHYsiitEXtSoftwarewww.inkscape.org< IDATxyt^}/ߖ% 6<2f` !aIι!=NޮY3 I. IO6mly61S ͌q%ȳ%G cckxٯZ2;H緳B&Meovtt]SSsfgfYvr"I@߷;˲]yEě+˲J/eY^z7$ @Aety7}qED\g" Έx*">sS V٤I3<2"&Eq=;"޺XjԁHP%ФINy?3"˲{K/@0a¬,>D12 /l0_r .۽{G,8;U<β?a(V\pA޽{??S*?P}: Wj„ eYvGDS}>555|gRt*RXM4itDcWy /FDG0^ˣI&^ʽdYdGG_|թ;e+:묡555Ȳ#y^xkse)&L,~˱>wv}%/&L?,="zmweK>, &,>]5cg_xᅥuJΤIOh=e- /mٲa^V\pOaÆ󼶷 H+{@_rlܸ<ЛEj"">yO*M.ꦰ[6m/\akv۶mKjeY6l+ɲLapׯOeW_}&"N)Ԕ:@=x>ڋj"bhTݻwP|'R%ߺW?PXPi֭[w[(_ jjj|)?y~a +PWW\ <V$5)Z \nݩ +ɲ, 0L)9a@:y V$ePy )I)Hj V$ )IզW 4(O4u#:3bc7x#Rǀ.۸qc|;I_8#˲1ƞ={b˖-c@)J61ȑ#SGnyVЅ{Ya /R}$ )I)HJa@R +RX V$ )I)HJa@R +RX V$ )I)HJa@R +RX V$ )I)HJa@R +RX jS W^y%n1:Scũc?zkv'=ܓ:ݤ:::bǎc$֖:B!WÆ K0V$ )I)HJa@R +RX V$ )I)H6ujoo[Fkkkl߾={رcGy,N8O88cذa1|8+_RXj]6֮]ׯK֒eY 6,bܸq1v;vltI1v8c̘1%_RXٳ'V^O?tZjΝ͑yl۶-m/a_3t?~|uYqgYgw^1Y"P1Z<SOSO=/b%mmmOO?}O9唘qT/}Kc̤I⦛nJZhQ\2u?8cSǀ>Ga޽{'z(.]ooF̟??""jkkcĉq饗ƥ^]tQ%N T;#uJcXUV7oS920`@(xR(Yfg:9 +lw}w,[,}ػwoHVUVww\\tE1uԸcԨQ#QPR#e]:Jr>UVEPXA)^۷o_,]4~ǃ>X5c*aΝq}}g3ό믿>8RjjjJ̙J`ܹ#ܖ-[RG>IaH]wK,;wT^~o38#OӧON:)u4x[_;adɒػwos1`1J9ujR㮻+2>]wݥW^y%!.¸k[Vl۶-u,'bҥc++V͛7Qr}Ѕ"p wc֭9o=_j^:,K ~<3gNp cK,)#z7_j466S8 e<@l۶-:J-J,08[x?U2yO8p@,\0u~aښ:FY 塰k׮;K.;#ۗ:R :0 +(#~|3RXZ}zcqI'g۷/1ʦ%<7J + VZ7xc_*aÆ):(cǎQ:JRX@nݺXzu(ɓ{'u;v(Hب*ŋǁRǨt@ }~UU Ua<*"b…1s禎P1 +(='я~݄ +3όo|ctې!CRGןnر#?:J۲eK<裩cTLNRVy~{~E555q禎믿>u t*cV`HbVPz +CK.Mn?~| :4u ؾ}{thkk^Z`AQS;P*&#ǕUU8@9Aaw޸3;x]vYSO="><z׻\kʕ+g?Y<%tЗL2%.1¯whݻwǒ%Kb驣N{{{,Z(up@(/ū:FE 4(.AY駟~zL6-""6o?pz꩸;cԩQ[{`SN9娥TZSSSؘ:B,[,R( W_cȑ#k_Z,\0.qnquwxST444)S$LzxS( 庁QX@|s1J&˲[c1s>uFg?x|k_?(hmmMpO={Ipn1`Q):;;|%3u׾Æ K:}ȷ:Fa|{ߋ+2u :ͩ" IDAT#֚5kbq禎ܹsSG(hmm#GUH@(իWk555|GYUX#={vIm߾=/_:Fa~4VݻRǝwG/U #?~hѢ8p@PX@b^cxwuW\s5=Pߋ[SSS<裩c$3o޼ %uVP{{{|LW?qL<9uVGؘ:BcQh( $t]wņ R={vL0!u4;Ež}RǨ q]PX@"o|#u:thۿ[?>u9RǨ8H@( $xxS葺{n(@ (fΜ9#T'L\?P +H__RG}sqf]lٲرcG3:PBnwOcccꫯƳ>:FUضm[UOa{;wn6fַ̘uuu%d`X"6nܘ:F͟??uyUOapª/9RJh'Y:;;)+G  qf͊/N8ᄘ:uj(GyQrO?t[.uC;6.9rd( *dڵU5:&>OY ܰaC:F̛7/uú[sQOX  XlY<6n1 (M#Fwqꩧ&Lst}e,`{{{,Z(uC 80nƷ?. ۷ǁRǀ xGSG+7(sw eYL>=a{-u^O~۶mKW]uU 6폏?4iaM +(kSϮhՑ|gW_Mۖ,Y{Mr;~ +VPF>l]vZ}[ #FצN|t_5*8ژ6m;~]a} ʨZ O<1;1 ڿ曩c6hР*̙ye;v숇z(uC\veG|xU(Qر#ߟ:T-ɦMb֭ctɅ^:PaXXeY7|s󣽽=ujnn+Vqn)9#&2Mjx'رcSzhڴiq9Td?_knnN c=9sf?sLKKK)utooɓ VsMvZkGU4=Ғ:T-o:BL81uXpa71u+#Ft3f(tadɒؽ{w 2$uZn]<өcb֬YeY^[ԑE;DaeR-V֛oofwYg+EtM}VԮ]{-͛yq,b]~VԤ}믿:BT7@Tsa5bĈ˘̙:;7o^袋SNzªh'( :;;ccUmmmvic $HwFFD̜9LIJ'?Iq5k?:!nn'VC5QX@455ž}R81cĀR(ڍ>C-Skoo/݊xjȐ!qv=E=aU" ʠZ_5z|rM}}}^?hРʔ48p#k;[) +#VPMMM#tرcSG(*y[f̘Q$O깦W5k֤qYfu=#F(䤀\j2غuk]OEޓ/O> iJ#B+ѣG%\ 0=ػwoPVPRX3&u "V eYtMeHS:gN!"~Q-X uC̚5':sgVP۷oOKh7bС=zoY&}1⩧u֥q3g#G,a+A:SG( ȲG=3s)qҚ3gN1w1eʔ?~|_V +AV JHUoN%̝;7:::w}wɬYz*BaeP-1:@nUjڴiQ[[[4?O裏FSSS.n^QVE Bae֖:B(*ȲVq饗(My 8d{:N<^QVEZ( ߟ:B(* RӧO/Ac޽߷=-ZT}#"F]$QX@8p u.QX@۶mK #F\sMwq%HSmmmlٲ﻾>^- +(j9a5p kmm1ۑkiʧ{q7\g544De%HTZ +AV#yQ23f(:r}+߾}{~]Uquuu1|UJ +AL "L/ =1f̘UŋWlKF[[[늳:+9眒Wı;wݻwUGa%ct Pujjjo.Z2gΜ5o޼UЇJިQJ^UGa%V-"VFbذa%[cӟƦMʾO[[[eߧ;jkkcڴi%]UO2B)Ċw)u1"jjJwr„ 1a„Wj9t={.#Vw(jkkSG貢ʯh7K5W͜9kR%qYJfaQ J%\N{IH/ӦM|Ry⥗^*۶m˗m8@u )Lo*?H@S8a5jԨx{SuKiܹe[{…^{oA|]'PX@ե%7nLH/ 3feR3gNy^8V---#@QX@ 80u.QX@k׮ؽ{w)Wau5Đ!Cʲv)_>x≒+V(qi\PCae0tDaKFg$`Dı˲v466|yEgggYfEeeYc?,kFsssPuVPw\]7UXE,%]h,iӦu"r OaeP-'6mڔ:PAE^K/-3""o?OJo+W,zpEũZ=w{߄SX@TKagϞB5PE,FQ 7|s/ٳglG%[f͚U=x* ʠsɳ>:P!EeYY \tiܹ$km!C+>E"Tcccט;wn ̙3+OQOXUEaePgIԩ3fĀ*WOϦQtvvFkkk/̘1U/*骈YfUl~m$ tP'tRYkkkqJkcۯV\٣SRy… ːLǏ~C-ǢhSX@ :4F:F{qy@qhjN̙3cΜ9ɮT?Q0"_r ,դIb…ɮ2{8w+Xtr)OWEUEe2?~~[fM⋩3ڿڵ+uRV:eUdַ'|2[K1c<d6C. y| _HжmR'%-n6lX҆YfMܹ[zukN+H,˒7[©3X@M6-wիWƍSg%R7Siѱdɒ '?Q?{XfMK};,/8uF>@MԃUDDGGGzG~5˖-K|gX3X@Um#"SO=:(ձ]}1nܸ3֭[oۉjHV, ݻSg@U0X@]qNٟ۟Eooo `oߞ:(ͩ.nǕy|[:;wEG+#y*1 l̙֖:lڴ)/`u|VJpBo-?^o&:uj,X uaEHݒϯz+WN8Gy$m?SeYN% T7TE 0 /ħ>i*E uRV^/ua .ɓ'8BQOX# *`ԨQx77裏)½a^Weʔ)q8W_}5GLpƨKqSc YbEG>=\ -<:E"[ >Ǫ_PD+ÇDzeRg ضm[@(EƌK,IQ:::R' *[oMP?O[o-ԭic+"yK&N}{SgWKKKꄣtwwG3 VPAy{sIQ6lضm[ Vnɒ%1v55}['8vJW eY|HQ27oغuk8x;"0">/_:VZ:ᄊx*_P4+ΨOQ2/Rx8u p E|UDϔڼyb3N'"uEc kjj%o~3u E%!C!uq]tE1eʔٙ:ᤜeBtGGqwƾ}RV9,Kq\Yʕ+SgN}}}X"uI9akp ĹK,IQ?p,_<~򓟤NxUoBj),]4ƍ:㤚 a;vHW\8Cqʦ+n>HgFOOO#466N8SƻR +?cE VȂ +HQ6>:Hݑy#477N8%VJPq5פ8eE|[ ??ٲeKofvm /3JOuT`bŊOQQWW:9Vn 'g.X|yꌊXfM\wu{{_{S'0TG5<*"bرUu:::R'KOXqO… p$"I^-'"0"b̙1wRjǎ='͙b(iӦooW)nݺXn]L81GGGGL:5uVܹ3)֮]k׮=',L,Y$b׮]SLoE%'Ǝ: `p]wţ>Zꔊ{W;;XlY,[,ϟ55wSxg駟z*^x;vwwGwwwU}9ե'i:thxqNI6V\:ߊx*W3XF'CPꔤ6o7o{7bҥp˜7o^s97n?>lKWW ) j߽UVՕW^YDx*W/ݻwN)ݻw~~p744DkkkL4)Z[[c„ 1z設1cD]]]92z{{c޽~׮]G۶m^{-m(7Oo|ɮ_۷o/uƍ/B_[޲رc VTA>nܸ>,ˢ=/NѣGWƏY{%# -<)U㭑+uiI9X0m[n9n) : 2$ƌS;vHV]gSgP!6m Bv8BVӦMyΨj[+' VP@cĉ3Ė-[Rg0񦦦 mժU*fԩ`bc7n\|_!CNr(#UįnWWwfOΠ VCj>aW^yeꌲ˲,Sg XOXk`[[UN`@94G5V\Sp˜2eJ+ _=Rg@a>_:2J T|K}1zeٙ:$xª7zzzRg@a+_J{S(W^y%vڕ:A`UzC믿>uF >}zꌒ?~|ꄣ VPŦO=X̚5+u %඀JonnNPR\rKꄲ(HZįM( TxCT+Jo[F\-J1`bŊeT cƌx ) RqKXre[ti;6uFY_pϗ0X Q[[{aÆ4("lbԨQ33uBաCbΝ3 V0ȴ#<ӦMKB?mٲ%ߟ:A`2nܸ %7|RgƸkRgMOXEDر#u  /0x≸S͛7`( jժ =Rg̈́ R'Se( RÆ O}SWW1f̘9 E|C1uBY\~FN#uBY=. E`AnŊ bÆ 6X544СCSgEMMM3fܹsSg]cec3X9׿mmms8'7x#ݛ:ͩʪ3uBr-*4X xx'bȐ!s87N𦦦 e5cƌ5kVSV[[+WLQE.'5zXlYꌊ) +c3Xq׾Xzu\{Uƒ (ፍ*n bŊ>|xꌊ) ;wơCRg@#\|SOwguV3 (Ɗ8_#GLqB*':z (pLg}v|gy&>%\Y&OsOX3V#Fk6uqM2%,X::$$V:(#FĭzkC?[nM6(455o  G9S+W7y^cرQ__Lr"~Bj+M2%뮸뮻bӦMcO<?|괪2eʔXdI,]4.첨G3Jg۶mܜ:b-Z---;eY\2uFeY---_"u Vp4*Nˌ3bƌя~4^zx'~?s 1.XhQ,^8R'0H8#F#FΨڸ+_J#,\0L:# T0`sNs9>lƢERg1 R?}{\k׹瞛:_/~30lذ jժ V? D G3X%UWW . Fį8ۼysue~yA`ҤI0a–c}&2;1"Ǝ:`_Z;L4),K0X|>X3dȐF ɓS' /gY'G#bsԩSS' y}NMDDeX$pN =iҤNI5kP5Fw^ jC5Z}eMs΍լ/"nkiiyT>&"<R,*1o޼ mmmO'׼,C @1X,ֶÃU> ƻ,nɲP~Ym*}@XtidY:maĉ5ߖ(dY/NPvEĵ'O~t~աCy)ٳcĉ3́hkk{t_gU'˲mmm@^䝷,˾0F +kmm@_jD0@5YjU >0iҤF_UDDKK_GĿErmYg:~uVk׮Ͳ쎈uq&M+WLPToD'{zz.y̙skkkr̙3SbWβeYv(uk5kG,C @ٜuY/~1ZZZRTW{g>=XED̚5E*q @Y :4>ĬYRTe<)"6EĦ,6y"TtZٰagϞݜ(Cٳg$u |O{kjjzvپ}{ :akeYd5gY;ׯRp|5v}[D|T1%yU7*^y}X,QeYv(˲mܸnrK=*˲-7,mԖu;v<qU^z" 6}N]^jD,R6Il̲ 6(uS[aٳ<("f.˲"֯_'u W*"bƌkkkgD|\x CliFM clifm-1.26.3/misc/logo/clifm.png000066400000000000000000000257541506632037700164160ustar00rootroot00000000000000PNG  IHDRM pHYs88tEXtSoftwarewww.inkscape.org< IDATxmg}u&b&sNq(´*P *TjF}Ҿ@m҈JI}赱1^,?ZUoソnzxro3'NzАV5Glc\UuЃV#Uߞ'g׭TO&WF;{PU;F1znY@N?ZUTU?^UpqS_4vonnDUpE>Z'xSNcvU>җ_5Ճnnn-ԯ@fkUap{x_ZBjt:}OUzSe|>tڪժz[t}}v!kOd29Z@U}-譵޷o?=yCTpl6{oU~UcҪ/:tbUՇu t:UG\{}͇r1 t:2ګ:tvXiGfZh{+Col궡罺~Y,ﯪSUƁzw:tӋЃ)[nUOz WF?=zb}2q-o>zHUhUUZNzHUO&ZHUz +g_Uz[,'2K^򒏶WArZUm4SCulm\Vk?\'O>SNnxOЏ?g~km}ox߿{Ƕvƻz~뭷~x__#s}9?ZWٗd2^*snxGz}2i}rWɓ^/轵\mmmy%f?{9[kow_ʛ.}\.9\HZ]bs_ҋ{Zk?xI`f2Rp'lŪ:z`Ze>_ {K:{ً}E=zڃ~+{챛|{E^{o*X=[Ν;/~ /˟+qe<7/譵;4VRO7ПQg2}㼁\.߹{`5F6}ccc<~b'Js@_,o꽯&X-~q]sߺKc`UzΧ?+oTՍV+fٱg~YZۻV֏= +`-g5w曯[[[fU=mwv<ɓOT=k}]s-ϝ;ڧ@_.fo30VVy~h9~ tz[U]7"XAz7W=譵c/z`'۷XS{}9nrj@ff=OcСCFUuSsr<:Xe訪=VrkO? ȨvhZk룪~!0޻@a]?jtZk/UյCU{vTUkC6k^+'0kFU5zUt  @t  @t  @t  @t  @t  @t  @t  @t  @t  @t  @t  @-ol6kkku- =#WzG<ksssp^Kvwԛg즛nzy}c쨃g{k1xug̙35 VPk80 Bmmmՙ3gUx׿;3z{Ͼ}@Z[[z?3s9<:@@:@@:@@:@@:@@:@@:@@:@@:@@:@@:@@:@@:@@:@@:@@%{LJ\SN =CO`@@:@@:@@:@@:@@:@@:@@:@@:@@:@@:@@:@@:@@:@@:@@:`<O/|ak_؃t:CUw  @t  @t  @t  @t  @t  @t  @t  @t  @w"& mIDATt  @tw1r]wfT^PUmzEJ AR  P*DBPhS@*%!UDӪ q\ݮ'5DkqBb=s[m6~Y̝<_3s~_>gF#@AP`(0t :F#n!Pw h""֝NAp3u&K))"麃@圿WDĉ@N(PEJx)rNjt׉"";4cED;4YQEQ;4Y=Ž; 4Tw׮]RDDz4"ԛi,5 4TJለbtqr*+PYAz#"n9PQRJ:+"Z:$oԘ '`,X@- :dllGDD|{#@/5@fD\ݷD0)N'.vEW}OyKsɂ>11qWD<ޗD<ܹK4v۷қ #=/ujӧ?֝ 񅅅OUG92@bvvva5GDl۶펔ңkXDjooЗUOGį%4e|PZF.9heymD>-}9@mqr z>|).9h?w:o\s]#"ϮYجRJUSO=ky6m333:-Z֗#uWʲXmk⾨zDęuBJbi'NFϯgr-3z/)ZD } 6˲!"zd=[ܗT'0l$O,)1==},"~cFR<ޏ;;voט0r)/+K&&&~?"1`,9f?{v+|0"~cx]sȑ'9h_W#":Γ)EB)~N@D3v19"n9tЃoĭ4??پ}{/lx)e`="رq A9Qrlq_,[#ARwΝ3y^#RzGJC & o߿ws t֭[ݲeSJ{1'Ӂ+ƙØl+qرEQܘs?9`RzsÚ0 k%SSS[lrWDU3Swʲע(^s_w6^A_h9yDl; B}3330 zDDr΁-eAVcEn+xYa=)SUUffUp޽SUU튈 FN)}@cCvUU}4tmYOxw9Pw}Qڻwﯧ>{9,;c zDD\s5W"n#bwq㉈/twrDT'}}ޘRzsDLDl;fR }>hJ(qUW`׻:"XUu)k#u /"'@QN>}#~t|||OyOD9(W朷GxYDLD,>\q*t<"NTUubߏEh=k׮c֖v6;RIENDB`clifm-1.26.3/misc/logo/clifm.svg000066400000000000000000000075171506632037700164260ustar00rootroot00000000000000 clifm-1.26.3/misc/mimelist.clifm000066400000000000000000000226141506632037700165050ustar00rootroot00000000000000 ################################### # Configuration File for Lira # # Clifm's File Opener # ################################### #----------------------------- # Description #----------------------------- # This configuration file allows the user to define how different files are # opened by Lira, Clifm's file opener. # Commented and blank lines are ignored. # Lines starting with either '#' or ';' are comments. # The below settings cover the most common filetypes. # It is recommended to edit this file placing your prefered applications # at the beginning of the apps list to speed up the opening process. # The file is read top to bottom and left to right; the first existent # application found will be used. # Applications defined here are NOT desktop files, but commands (arguments # can be used as well). Bear in mind that these commands will be executed # directly without shell features (like pipes, conditions, loops, etc). For # more complex commands, create a script and place its path instead. # For example: # X:^text/.*:~/scripts/my_cool_script.sh # Use 'X' to specify a GUI environment and '!X' for non-GUI environments: # X = GUI only # !X = Non-GUI only (like the kernel console or a SSH session) # # If a line applies to both environments, simply omit the 'X'. For example: # 'text/plain=vi' # Use 'N' to match filenames instead of MIME types. # 'N:.*\.txt$=vi' to open all .txt files with vi (both GUI and non-GUI) # 'X:N:.*\.txt$=geany' (GUI only) # '!X:N:.*\.txt$=vi' (non-GUI only) # Regular expressions are supported for both MIME types and filenames. # Use the '%f' placeholder to specify the position of the filename to be # opened in the command. For example: # 'mpv %f --no-terminal' will expand to 'mpv FILE --no-terminal' # # The '%u' placeholder is expanded to the file URI. For example, if the # filename is '/home/user/this is a test', 'cmd %u' is expanded to # 'cmd file:///home/user/this%20is%20a%20test'. # # If neither %f nor %u is specified, the filename will be appended to the # command. For example: # 'mpv --no-terminal' becomes 'mpv --no-terminal FILE' # # The '%m' placeholder expands to the file's MIME type. # To suppress STDERR and/or STDOUT use !E and !O respectively (they can be # combined). Examples: # Supress STDERR only and run in the foreground: # mpv %f !E # Supress both (STDERR and STDOUT) and run in the background: # mpv %f !EO & # The '%x' flag is a shorthand for "%f !EO &". For example: # mpv %x # # This flag runs the application is in a new session, detached from the # running terminal (via setsid(3)). # # For Ranger users, the '%x' flag is equivalent to "flag f" in rifle.conf. # Running opening applications in the background: # For GUI applications: # APP %x # For terminal applications: # TERM -e APP %x # Replace 'TERM' and 'APP' with the corresponding values. The -e option # might vary depending on the terminal emulator used (TERM). # # Note: This will hide error messages. To display error messages use: # cmd %f !O & # This will run 'cmd' in the background supressing STDOUT only. # Important: If the opening application is already running, the file will # typically open in a new tab, and Clifm will not wait for the file to be # closed (as the procecss already returned). # To ensure a new instance is created, use options like: # geany -i, gedit -s, kate -n, pluma --new-window, etc. # Environment variables can also be used. Example: # X:text/plain=$EDITOR %f &;$VISUAL;nano;vi # Use Ranger's rifle (or your preferred opener) for all files #.*=rifle ################################ # 1. File names/extensions # ################################ # Match a complete filename #X:N:some_filename=cmd # Match all filenames starting with 'str' #X:N:^str.*=cmd # Match filenames with extension '.ext' #X:N:.*\.ext$=cmd #----------------------------- # Clifm config files #----------------------------- X:N:(.*\.clifm$|clifmrc)=$EDITOR;$VISUAL;kak;micro;nvim;vim;vi;mg;emacs;nano;mili;leafpad;mousepad;featherpad;gedit -s;kate -n;pluma --new-window !X:N:(.*\.clifm$|clifmrc)=$EDITOR;$VISUAL;kak;micro;nvim;vim;vi;mg;emacs;nano #----------------------------- # Digital books #----------------------------- X:N:.*\.djvu$=djview %x;zathura %x;xreader %x;evince %x;atril %x X:N:.*\.(fb2|epub)$=mupdf %x;zathura %x;xreader %x;ebook-viewer %x;FBReader %x;foliate %x X:N:.*\.mobi$=mupdf %x;ebook-viewer %x;FBReader %x;foliate %x X:N:.*\.(cbr|cbz|cb7|cbt|cba)$=mcomix %x;xreader %x;YACReader %x;qcomicbook %x;zathura %x;foliate %x;atril %x X:N:.*\.chm$=xchm %x #----------------------------- # Misc #----------------------------- # ABW files are Abiword documents. These are basically XML, but you most # likely want to open them with a word processor. X:N:.*\.abw$=abiword %x;libreoffice %x;soffice %x;ooffice %x # KRA files are Krita image files. These are actually zip files, but you # most likely want to open them with Krita. X:N:.*\.kra$=krita %x # SLA files are Scribus files. These are actually XML files, but you # most likely want to open them with Scribus. X:N:.*\.sla$=scribus %x # ORA files are OpenRaster image files. These are actually ZIP files, # but you most likely want to open them with an image viewer. X:N:.*\.ora$=mypaint %x;krita %x;gimp %x;pinta %x;scribus %x;display %x ################################ # 2. MIME types # ################################ #----------------------------- # Directories #----------------------------- # Only for the open-with command (ow) and the --open command line switch. # In graphical environments directories will be opened in a new window. X:inode/directory=xterm -e clifm %x;xterm -e vifm %x;pcmanfm %x;thunar %x;xterm -e ncdu %x !X:inode/directory=vifm;ranger;nnn;ncdu #----------------------------- # Web content #----------------------------- X:^text/html$=$BROWSER;surf %x;vimprobable %x;vimprobable2 %x;qutebrowser %x;dwb %x;jumanji %x;luakit %x;uzbl %x;uzbl-tabbed %x;uzbl-browser %x;uzbl-core %x;iceweasel %x;midori %x;opera %x;firefox %x;seamonkey %x;brave %x;chromium-browser %x;chromium %x;google-chrome %x;epiphany %x;konqueror %x;elinks;links2;links;lynx;w3m !X:^text/html$=$BROWSER;elinks;links2;links;lynx;w3m #----------------------------- # Text #----------------------------- X:^text/rtf$=libreoffice %x;soffice %x;ooffice %x X:(^text/.*|application/(json|javascript)|inode/x-empty)=$EDITOR;$VISUAL;kak;micro;dte;nvim;vim;vi;mg;emacs;nano;mili;leafpad %x;mousepad %x;featherpad %x;nedit %x;kate %x;gedit %x;pluma %x;io.elementary.code %x;liri-text %x;xed %x;atom %x;nota %x;gobby %x;kwrite %x;xedit %x !X:(^text/.*|application/(json|javascript)|inode/x-empty)=$EDITOR;$VISUAL;kak;micro;dte;nvim;vim;vi;mg;emacs;nano #----------------------------- # Office documents #----------------------------- !X:^application/.*(open|office)document\.spreadsheet.*=sc-im X:^application/(msword|vnd.ms-excel|vnd.ms-powerpoint|.*(open|office)document.*)=libreoffice %x;soffice %x;ooffice %x X:^application/(msword|.*(open|office)document\.wordprocessing.*)=abiword %x;calligrawords %x X:^application/(vnd.ms-excel|.*(open|office)document\.spreadsheet.*)=gnumeric %x;calligrasheets %x X:^application/(vnd.ms-powerpoint|.*(open|office)document\.presentation.*)=calligrastage %x #----------------------------- # Archives #----------------------------- # Note: 'ad' is Clifm's built-in archives utility (based on atool(1)). Remove it if you # prefer another application. X:^application/(gzip|java-archive|vnd.(debian.binary-package|ms-cab-compressed|rar)|x-(7z-compressed|arj|bzip*|compress|iso9660-image|lzip|lzma|lzop|rpm|tar|xz)|zip|zstd)=ad;xarchiver %x;lxqt-archiver %x;ark %x !X:^application/(gzip|java-archive|vnd.(debian.binary-package|ms-cab-compressed|rar)|x-(7z-compressed|arj|bzip*|compress|iso9660-image|lzip|lzma|lzop|rpm|tar|xz)|zip|zstd)=ad #----------------------------- # PDF #----------------------------- X:.*/pdf$=mupdf %x;sioyek %x;llpp %x;lpdf %x;zathura %x;mupdf-x11 %x;apvlv %x;xpdf %x;xreader %x;evince %x;atril %x;okular %x;epdfview %x;qpdfview %x #----------------------------- # Images #----------------------------- X:^image/gif$=animate %x;pqiv %x;sxiv -a %x;nsxiv -a %x;feh %x X:^image/svg$=display %x;inkscape %x X:^image/x-xcf$=gimp %x X:^image/.*=imv %x;nsxiv %x;sxiv %x;pqiv %x;qview %x;qimgv %x;viewnior %x;oculante %x;mirage %x;ristretto %x;xviewer %x;nomacs %x;geeqie %x;gpicview %x;gthumb %x;gwenview %x;shotwell %x;loupe %x;eog %x;eom %x;mcomix %x;feh %x;display %x;gimp %x;krita %x !X:^image/.*=fim;img2txt;cacaview;fbi;fbv #----------------------------- # Video and audio #----------------------------- X:^video/.*=ffplay %x;mplayer %x;mplayer2 %x;mpv %x;vlc %x;gmplayer %x;smplayer %x;celluloid %x;qmplayer2 %x;haruna %x;totem %x X:^audio/.*=gmplayer %x;smplayer %x;vlc %x;totem %x;ffplay %x;audacity %x;mpv --player-operation-mode=pseudo-gui %x;mplayer;mplayer2 !X:^audio/.*=ffplay -nodisp -autoexit -hide_banner %f !EO;mplayer %f !EO;mpv --no-terminal #----------------------------- # Fonts #----------------------------- X:^font/.*|^application/(font.*|.*opentype)=fontforge %x;fontpreview #----------------------------- # Torrent #----------------------------- X:application/x-bittorrent=rtorrent;transimission-gtk %x;transmission-qt %x;deluge-gtk %x;ktorrent %x #----------------------------- # Fallback #----------------------------- # Let's fallback to an external opener as last resource .*=handlr open;mimeopen -n;rifle;mimeo;xdg-open;open; clifm-1.26.3/misc/nets.clifm000066400000000000000000000043001506632037700156230ustar00rootroot00000000000000 ##################################### # Remotes Management File for Clifm # ##################################### # Blank and commented lines are ignored. # The syntax is as follows: # A name for this remote. It will be used by the 'net' command # and will be available for tab completion #[work_smb] # Comment=My work samba server #Mountpoint=/home/user/.config/clifm/mounts/work_smb # Use %m as a placeholder for Mountpoint #MountCmd=mount.cifs //WORK_IP/shared %m -o OPTIONS #UnmountCmd=umount %m # Automatically mount this remote at startup #AutoMount=true # Automatically unmount this remote at exit #AutoUnmount=true # TIP: When mounting a slow file system (say, an FTP server), it # is recommended to set an autocommand for the mount point disabling # some Clifm features that might slow things down. Open the # configuration file ('config' or F10), go to the AUTOCOMMANDS # section and add a new autocommand: # #autocmd ~/mounts/ftp_server/** lm=1,fc=0 # # The light mode (lm) prevents some files processing, and the files # counter (fc) is expensive: disable it. # A few examples # A. Samba share #[samba_share] #Comment=my samba share #Mountpoint="~/.config/clifm/mounts/samba_share" #MountCmd=sudo mount.cifs //192.168.0.26/resource_name %m -o mapchars,credentials=/etc/samba/credentials/samba_share #UnmountCmd=sudo umount %m #AutoUnmount=false #AutoMount=false # B. SSH file system (sshfs) #[my_ssh] #Comment=my ssh #Mountpoint="/media/ssh" #MountCmd=sshfs user@192.168.0.12: %m -C -p 22 #UnmountCmd=fusermount3 -u %m #AutoUnmount=false #AutoMount=false # C. FTP file system #[ftp_server] #Comment=FTP server #Mountpoint="~/mounts/ftp_server" #MountCmd=curlftpfs ftp://ftp.example.org %m #UnmountCmd=fusermount3 -u %m #AutoMount=false #AutoUnmount=false # D. Mounting a local file system #[local] #Comment=Local filesystem #Mountpoint="/media/extra" #MountCmd=sudo mount -U 1232dsd761278... %m #UnmountCmd=sudo umount %m #AutoUnmount=false #AutoMount=true # E. Mounting a removable device #[USB] #Comment=My USB drive #Mountpoint="/media/usb" #MountCmd=sudo mount -o gid=1000,fmask=113,dmask=002 -U 5647-1... %m #UnmountCmd=sudo umount %m #AutoUnmount=true #AutoMount=false clifm-1.26.3/misc/preview.clifm000066400000000000000000000110101506632037700163270ustar00rootroot00000000000000 ###################################### # Configuration File for Shotgun # # Clifm's File Previewer # ###################################### #-------------------------------- # Description #-------------------------------- # This configuration file is used to customize the behavior of Clifm's # file previewer. # Blank and commented out lines are ignored. # Lines starting with '#' or ';' are comments. # To ensure optimal performance, it is recommended to edit this file # setting your preferred applications first. You may also remove any # applications that you do not intend to use. # For detailed syntax and options, consult the mimelist.clifm file # (run 'mm edit' or press F6). # Uncomment this line to use Pistol (or any other previewing application): ;.*=pistol # Uncomment and edit this line to use Ranger's scope script: ;.*=~/.config/ranger/scope.sh %f 120 80 /tmp/clifm/ True #-------------------------------- # Image previews #-------------------------------- # # Uncomment the below lines to enable image previews for the specified file # types. # # Consult the clifmimg script for information on how images are displayed # (supported methods: sixel, ueberzug, kitty, ansi). # If this script is not found under ~/.config/clifm/, you can copy it from # the data directory (usually /usr/share/clifm/plugins/). # ;^text/rtf$|^application/.*(officedocument|msword|ms-excel|ms-powerpoint|opendocument).*=~/.config/clifm/clifmimg doc %f %u; ;^application/pdf$=~/.config/clifm/clifmimg pdf %f %u; ;^application/epub\+zip$=~/.config/clifm/clifmimg epub %f %u; ;^application/x-mobipocket-ebook$=~/.config/clifm/clifmimg mobi %f %u; ;^image/vnd.djvu$=~/.config/clifm/clifmimg djvu %f %u; ;^image/svg\+xml$=~/.config/clifm/clifmimg svg %f %u; # The 'image' method displays images directly, without previous convertion ;^image/(jpeg|png|tiff|webp|x-xwindow-dump)$=~/.config/clifm/clifmimg image %f %u; # The 'gif' method converts images first, and then displays them ;^image/.*|^application/dicom$=~/.config/clifm/clifmimg gif %f %u; # OpenRaster images ;N:.*\.ora$=~/.config/clifm/clifmimg gif %f %u; # Krita images ;N:.*\.(kra|krz)$=~/.config/clifm/clifmimg krita %f %u; ;^video/.*|^application/(mxf|x-shockwave-flash|vnd.rn-realmedia)$=~/.config/clifm/clifmimg video %f %u; ;^audio/.*=~/.config/clifm/clifmimg audio %f %u; ;^application/postscript$=~/.config/clifm/clifmimg postscript %f %u; ;^font/.*|^application/(font.*|.*opentype)=~/.config/clifm/clifmimg font %f %u; ;N:.*\.(cbz|cbr|cbt)$=~/.config/clifm/clifmimg comic %f %u; #-------------------------------- # Directories #-------------------------------- inode/directory=exa -a --tree --level=1;eza -a --tree --level=1;lsd -A --tree --depth=1 --color=always;tree -a -L 1;ls -Ap --color=always --indicator-style=none; #-------------------------------- # Text #-------------------------------- ^text/rtf=catdoc; N:.*\.json$=jq --color-output .;python -m json.tool; N:.*\.md$=glow -s dark;mdcat; ^text/html$=w3m -dump;lynx -dump;elinks -dump;pandoc -s -t markdown; ^text/.*|^application/javascript$=highlight -f --out-format=xterm256 --force;bat --style=plain --color=always;cat; #-------------------------------- # Office documents #-------------------------------- N:.*\.xlsx$=xlsx2csv;file -b; N:.*\.(odt|ods|odp|sxw)$=odt2txt;pandoc -s -t markdown; ^application/(.*wordprocessingml.document|.*epub+zip|x-fictionbook+xml)=pandoc -s -t markdown; ^application/msword=catdoc; ^application/ms-excel=xls2csv; #-------------------------------- # Archives #-------------------------------- N:.*\.rar=unrar lt -p-; application/(zstd|x-rpm|debian.binary-package)=bsdtar --list --file; application/(zip|gzip|x-7z-compressed|x-xz|x-bzip*|x-tar)=atool --list;bsdtar --list --file; #-------------------------------- # PDF #-------------------------------- ^application/pdf$=pdftotext -l 10 -nopgbrk -q -- %f -;mutool draw -F txt -i;exiftool; #-------------------------------- # Image, video, and audio #-------------------------------- ^image/vnd.djvu=djvutxt;exiftool; ^image/.*=exiftool; ^video/.*=mediainfo;exiftool; ^audio/.*=mediainfo;exiftool; #-------------------------------- # Torrent #-------------------------------- application/x-bittorrent=transmission-show; #-------------------------------- # Email #-------------------------------- message/rfc822=mu -q view;cat; #-------------------------------- # Fallback #-------------------------------- .*=file -b; # Add true(1) to silence the 'no application found' warning #.*=file -b;true; clifm-1.26.3/misc/prompts.clifm000066400000000000000000000344451506632037700163730ustar00rootroot00000000000000 ################################## # Prompts File for Clifm # ################################## # This configuration file defines the structure and appearance of the command # prompt in Clifm. # Important: Do not edit this file directly: use the 'prompt edit' command instead. # Empty lines and lines starting with '#' are ignored. # Clifm provides three types of command prompts: # # 1. The regular prompt: This is the prompt you see as soon as you start Clifm. # # 2. The warning prompt: A secondary prompt used to highlight invalid/non-existent # names. When triggered, it replaces the last line of the regular prompt. # # 3. The right prompt: It is just like the regular prompt, but printed on the right # side of the screen. # A few caveats: a) right prompts can only be used with multiline regular prompts; # b) multiple lines are not supported by right prompts (only the first line will be # printed). # # All prompts are built using escape sequences, colors codes, prompt modules, # command substitution, and/or string literals. # 1. ESCAPE SEQUENCES # ------------------- # # Escape sequences allow you to customize the prompt with dynamic information: # # \e: Escape character # \u: The username # \H: The full hostname # \h: The hostname, up to the first dot (.) # \s: The name of the shell (everything after the last slash) currently # used by Clifm # \S: Current workspace number (colored according to wsx code in the color # scheme file) # \l: Print an L if running in light mode # \P: The current profile name # \n: A newline character # \r: A carriage return # \a: A bell character # \d: The date, in abbreviated form (e.g.: Tue May 26) # \t: The time, in 24-hour HH:MM:SS format # \T: The time, in 12-hour HH:MM:SS format # \@: The time, in 12-hour am/pm format # \A: The time, in 24-hour HH:MM format # \w: The full current working directory, with the home directory abbreviated # with a tilde (~). # \W: The basename of the current directory, with $HOME abbreviated with a tilde. # \p: Abbreviate the current working directory only if longer than 40 characters. # To change this value set the CLIFM_P_MAX_PATH to a value greater than zero. # \f: Abbreviate every path component but the last to a single character. # To change the number of characters per path component, set the # CLIFM_PROMPT_F_DIR_LEN environment variable to a value greater than zero # (defaults to 1). To keep some path components unshortened, set the # CLIFM_PROMPT_F_FULL_LEN_DIRS to a value greater than zero (defaults to 1). # \z: Exit code of the last executed command (printed in green in case of # success and in bold red in case of error) # \b: Execution time of the last command in seconds. Use $CLIFM_PROMPT_B_MIN to # print times only if bigger than the specified value (defaults to 0), and # $CLIFM_PROMPT_B_PRECISION to print only the specified value of decimal # places (defaults to 2). # \g: The current sort order name # \j: Octal permissions of the current directory # \y: Print an 'A' if an autocommand was executed in the current directory # \i: The value of CLIFMLVL (number of clifm nested instances) # \I: Same as \i, but formatted as '(n)' (nothing is printed if CLIFMLVL is 1) # \$: #, if the effective user ID is 0 (root), and $ otherwise # \nnn: The character whose ASCII code is the octal value nnn # \\: A literal backslash # \[: Begin a sequence of non-printing characters. This is mostly used to # add color to the prompt line (using full ANSI escape sequences) # \]: End a sequence of non-printing characters # # File statistics escape sequences (for the current directory): # # \D: Number of sub-directories # \R: Number of regular files # \L: Number of symbolic links # \o: Number of broken symbolic links # \Q: Number of regular and special files (1) # \X: Number of executable files # \.: Number of hidden files # \U: Number of SUID files # \G: Number of SGID files # \F: Number of FIFO/pipe files # \K: Number of socket files # \B: Number of block device files # \C: Number of character device files # \x: Number of files with capabilities # \M: Number of multi-link files (hardlinks) # \E: Number of files with extended attributes # \O: Number of other-writable files # \": Number of files with the sticky bit set # \?: Number of files of unknown file type # \!: Number of unstatable files # # (1) This includes: regular files, sockets, FIFO/pipes, block devices and # character devices (i.e. non-directory and non-symlink files). # # Escape codes to control prompt notifications: # # \v: If running in vi editing mode, print '(ins)' or '(cmd)' for insert and # command modes respectively. # \*: An asterisk + number of selected files (e.g. *12) # \%: 'T' + number of trashed files (e.g. T3) # \#: Print an 'R' if running as root # \(: 'E' + number of error messages (e.g. E2) # \): 'W' + number of warning messages (e.g. W2) # \=: 'N' + number of notice messages (e.g. N1) # # NOTE: Except in the case of \#, nothing is printed if the corresponding # number is zero (no selected files, no trashed files, etc). # # Set Notifications to false to prevent the automatic insertion of # root, trash, messages (error, warning, and notice), vi mode, and selected # files indicators at the left of the prompt, in which case the prompt code # can handle itself this data using the appropriate escape sequences. # Unicode characters can be inserted by directly pasting the corresponding # character, or by inserting its hex code: # echo -ne "paste_your_char" | hexdump -C # 2. COLORS # --------- # # Colors are set using one of the two following methods: # 1) ANSI escape codes (e.g. "\[\e[1;31m\]", for bold red) # # 2) The %{COLOR} syntax, where COLOR is: # a) A color/attribute name: # Color names: black, red, green, yellow, blue, magenta, cyan, white. # # To get the full-brightness variant of any of the above colors use the # 'br' prefix followed by the color name. E.g. "brblue" or "brblack". # Note that "brblack" has higher brightness than "black" (close to gray). # # Attribute names: bold, dim, italic, underline, reverse, strike. # # To disable a specific attribute use the 'no' prefix followed by the # attribute name. E.g. "nounderline" or "nobold". # # To disable all previous attributes use the "reset" keyword. # # Example: "%{bold}%{underline}%{brred}text%{nounderline}text%{reset}" # prints "text" twice, first in a bold underlined bright red, and then # in a bold bright red (no underline). # # Use the special "fgreset" and "bgreset" keywords to set the foreground # and background color respectively to the default terminal value. For # example, "%{k:red}%{blue}text%{bgreset}" prints "text" in blue on a # red background, and then resets the background color (keeping the # foreground color). # # b) A number in the range 0-255 (256-colors). E.g. "%{196}" # # c) A '#' followed by a three or six digits hexadecimal number. # E.g. "%{#ff0000}" or "%{f00}" # # Attribute names can be used in all the three cases. E.g., "%{bold}%{red}", # "%{dim}%{196}", or "%{reverse}%{#ff0000}" # # A single attribute can also be added via a character prefix followed by # a colon (':'). Allowed prefixes are: # # b: Bold # d: Dim # i: Italic # k: bacKground # n: Normal/reset # r: Reverse # s: Strike # u: Underline # # For example, "%{d:red}" (dimmed red) or "%{u:#ff0000}" (underlined red). # To specify two or more attributes use the standalone attribute names. # E.g., %{bold}%{u:green} or %{bold}%{underline}%{green} (bold underlined green). # # To specify a background color (instead of foreground), use the "k:" prefix. # E.g., "%{u:red}%{k:blue}" will print underlined red on a blue background. # # Writing a prefix in UPPERCASE turns off the corresponding attribute # (unlike 'n', which turns off ALL attributes). # # E.g.: "%{b:red}%{k:blue}text%{B:red}text" prints "text" twice, first in # bold red on a blue background, and then in red (no bold) keeping the blue # background. Note that 'N' sets the terminal default foreground color, # while 'K' sets the terminal default background color. # 3. PROMPT MODULES AND COMMAND SUBSTITUTION # ------------------------------------------ # # Since escape codes are limited and internal to Clifm, prompt modules and command # substitution are designed to provide external information to the prompt. # # While command substitution works much like in regular shells, i.e. invoking shell # commands (e.g. $(uname -s)), prompt modules are programs/scripts located in the # plugins directory (either local or system-wide). # # To run a prompt module write "${NAME}". For example, to run the git prompt module: # "${m_git_prompt_status}". Clifm will look for this module in the local plugins directory # (~/.config/clifm/plugins), and, if not found, in the data directory (usually, # /usr/local/share/clifm/plugins). Take a look at the "git" prompt for a concrete # usage example. # # Note that you can also run a prompt module using command substitution, in which case # you need to indicate the path to the module. For example: # $(/usr/local/share/clifm/plugins/m_git_prompt_status) # 4. SETTING YOUR PROMPT # ---------------------- # # Use the 'cs' command to temporarily set a prompt. Type 'cs ' to get the list # of available prompts. To set a specific prompt run 'cs PROMPT_NAME'. # # To permanetly set a prompt edit your color scheme file (via the 'cs edit' command), # set Prompt to the appropriate prompt name (e.g., Prompt="classic"), and comment out # the remaining prompt lines. # # NOTE: Since the below prompts are designed for Clifm's default color scheme, you may # want to edit the one you choose manually to make it fit your current color scheme. [clifm] Notifications=true RegularPrompt="%{reset}\I[\S%{reset}]\l \A \u:\H %{cyan}\w%{reset}\n<\z%{reset}> %{blue}\$%{reset} " EnableWarningPrompt=true WarningPrompt="%{reset}%{b:red}(!)%{n:dim} > " [clifm-no-color] Notifications=true RegularPrompt="%{reset}\I[\S%{reset}]\l \A \u:\H \w\n<\z%{reset}> \$%{reset} " EnableWarningPrompt=true WarningPrompt="%{reset}(!) > " [clifm-box-drawing] # Note: The box drawing set used here is not supported by all terminal emulators Notifications=false RegularPrompt="%{n:cyan}\[\e(0\]lq\[\e(B\]%{red}\#%{reset}\I%{red}\(%{yellow}\)%{green}\=%{cyan}\%%{green}\*%{reset}[\S%{reset}]\l \A \u:\H %{cyan}\w%{reset}\n%{cyan}\[\e(0\]mq\[\e(B\]%{reset}<\z%{reset}> %{blue}\$%{reset} " EnableWarningPrompt=true WarningPrompt="%{n:cyan}\[\e(0\]mq\[\e(B\]%{reset}<\z%{reset}> %{b:red}!%{n:dim} " [classic] Notifications=true RegularPrompt="%{reset}\I[%{b:green}\u%{n:cyan}@%{b:green}\H%{reset}] %{b:blue}\w%{reset} \$ " EnableWarningPrompt=true WarningPrompt="%{dim}\I[%{b:green}\u%{n:cyan}%{dim}@%{b:green}\H%{n:dim}] %{b:blue}\w %{b:red}!%{n:dim} " [git] Notifications=true RegularPrompt="%{reset}[\S%{reset}] %{green}\f%{reset} ${m_git_prompt_status}\n<\z%{reset}> %{cyan}\$%{reset} " EnableWarningPrompt=true WarningPrompt="%{reset}%{b:red}(!)%{n:dim} > " [pez] Notifications=true RegularPrompt="%{reset}\I[\S%{reset}]\l %{blue}\f%{reset} <\z%{reset}>\n%{b:red}>%{yellow}>%{green}>%{reset} " EnableWarningPrompt=true WarningPrompt="%{reset}%{b:red}>>>%{n:dim} " [timer] Notifications=true RegularPrompt="%{reset}[\S%{reset}] %{cyan}\w%{reset} <\z%{reset}:%{blue}\b%{reset}s>\n%{green}\$%{reset} " EnableWarningPrompt=true WarningPrompt="%{reset}%{red}\$%{n:dim} " [security-scanner] # Print file statistics about the current directory, including the number of # SUID, SGID, other-writable, and executable files, in this order. Notifications=true RegularPrompt="%{reset}\I[\S%{reset}]\l %{b:red}\U%{reset}:%{b:yellow}\G%{reset}:%{b:blue}\O%{reset}:%{b:green}\X%{reset} \A %{cyan}\w%{reset}\n<\z%{reset}> %{blue}\$%{reset} " EnableWarningPrompt=true WarningPrompt="%{reset}%{b:red}(!)%{n:dim} > " [counter] # Print sort order, current directory permissions, number of directories, # regular files, and links. Notifications=true RegularPrompt="%{reset}\I[\S%{reset}]\l [\g:%{cyan}\j%{reset}:%{blue}\D%{reset}|%{d:white}\Q%{reset}|%{cyan}\L%{reset}] %{cyan}\w%{reset}\n<\z%{reset}> %{blue}\$%{reset} " EnableWarningPrompt=true WarningPrompt="%{reset}%{b:red}(!)%{n:dim} > " [info] Notifications=true RegularPrompt="%{reset}\I[\S%{reset}]\l %{green}\w%{reset}\n%{cyan}\$%{reset} " RightPrompt="%{reset}${m_git_prompt_status} <%{green}\b%{reset}s> %{brblack}\t%{reset}" EnableWarningPrompt=true WarningPrompt="%{reset}%{red}\$%{n:dim} " [curves] Notifications=false RegularPrompt="%{reset}%{b:green}╭─%{reset}\I%{red}\(%{yellow}\)%{green}\=%{cyan}\%%{green}\*%{reset}[\S%{reset}]%{b:green}─%{reset}(\u:\H)%{b:green}─%{reset}[%{cyan}\w%{reset}]\n%{b:green}╰─%{reset}<\z%{reset}> %{blue}λ%{reset} " EnableWarningPrompt=true WarningPrompt="%{reset}%{b:green}╰─%{reset}<\z%{reset}> %{b:red}λ%{n:dim} " # The following prompts require a patched Nerdfont [firestarter] Notifications=false RegularPrompt="%{reset}%{b:124}╭─%{124}%{7}%{k:124}\#%{7}\I\(%{3}\)%{2}\=%{6}\%%{2}\*%{7}%{k:124}[\S%{7}] %{reset}%{k:124}\A %{n:124}%{k:3}%{0} \u:\H %{3}%{k:124}%{7}%{k:124} \w %{n:124}%{reset}\n%{b:124}╰─▶%{reset} " EnableWarningPrompt=true WarningPrompt="%{reset}%{b:124}╰─%{n:124}▶ " [cold-winter] Notifications=false RegularPrompt="%{reset}%{b:1}%{k:237}\#%{n:7}%{k:237}\I%{1}\(%{3}\)%{2}\=%{6}\%%{2}\*%{n:7}%{k:237}[\S%{n:7}%{k:237}] \A %{n:237}%{k:6} %{0}\u:\H %{n:6}%{k:237} %{n:7}%{k:237}\w %{n:237} \n %{b:cyan}%{reset} " EnableWarningPrompt=true WarningPrompt=" %{reset}%{b:1}!%{n:dim} " [spot] Notifications=false RegularPrompt="%{n:7}%{k:53} \I%{160}\#%{160}\(%{178}\)%{41}\=%{6}\%%{41}\*%{7}[\S%{7}] %{53}%{k:178} %{0}\A \u:\H \w %{n:178}\n%{254}%{k:53} \$ %{n:53} %{reset} " EnableWarningPrompt=true WarningPrompt="%{n:7}%{k:124} \x %{n:124} %{n:dim} " [artic-particles] Notifications=false RegularPrompt="%{n:7}%{k:18} \I%{b:160}\#%{160}\(%{3}\)%{2}\=%{6}\%%{2}\*%{n:7}%{k:18}[\S%{n:7}%{k:18}] \A %{n:18}%{k:7} \u:\H %{n:7}%{k:18} \w %{n:18} \n%{n:7}%{k:18} \$ %{n:18} " EnableWarningPrompt=true WarningPrompt="%{reset}%{b:1}%{k:7} \$ %{n:7} %{n:dim}" [green-beret] Notifications=false RegularPrompt="%{reset}╭─%{239}%{15}%{k:239}\I%{160}\#%{160}\(%{3}\)%{76}\=%{6}\%%{76}\*%{15}[\S%{15}]  \A \u %{n:239}%{k:70}%{0} \w %{n:70}%{reset}\n╰─%{70}▶%{reset} " EnableWarningPrompt=true WarningPrompt="%{reset}╰─%{160}▶%{n:dim} " clifm-1.26.3/misc/readline.clifm000066400000000000000000000045031506632037700164420ustar00rootroot00000000000000 ####################################### # Readline Keybindings File for Clifm # ####################################### # For the complete list of Readline options see: # https://www.gnu.org/software/bash/manual/html_node/Readline-Init-File-Syntax.html#Readline-Init-File-Syntax # Important: When setting keybindings, bear in mind that clifm's keybindings take precedence # over readline's. Run 'kb list' for the list of clifm's keybindings. #$include /etc/inputrc # Color files by types set colored-stats on # Append char to indicate type set visible-stats on # Mark symlinked directories set mark-symlinked-directories on # Color the common prefix set colored-completion-prefix on # Color the common prefix in menu-complete set menu-complete-display-prefix on # Enable paste protection set enable-bracketed-paste on set show-all-if-ambiguous on set completion-ignore-case on set meta-flag on set input-meta on set output-meta on $if mode=emacs # For the Linux console and RH/Debian xterm "\e[1~": beginning-of-line "\e[4~": end-of-line "\e[5~": beginning-of-history "\e[6~": end-of-history "\e[7~": beginning-of-line "\e[3~": delete-char "\e[2~": quoted-insert "\e[5C": forward-word "\e[5D": backward-word "\e\e[C": forward-word "\e\e[D": backward-word "\e[1;5C": forward-word "\e[1;5D": backward-word # For rxvt "\e[8~": end-of-line # Ctrl-Left and Ctrl-Right "\x1b\x4f\x64": backward-word "\x1b\x4f\x63": forward-word # For non RH/Debian xterm, can't hurt for RH/DEbian xterm "\eOH": beginning-of-line "\eOF": end-of-line # For the FreeBSD console "\e[H": beginning-of-line "\e[F": end-of-line # These are for terminals supporting the Kitty Keyboard Protocol "\e[117;5u": unix-line-discard "\e[119;5u": unix-word-rubout "\e[116;5u": transpose-chars "\e[54;3u": tilde-expand "\e[126;3u": tilde-expand "\e[121;5u": yank "\e[95;3u": yank-last-arg "\e[107;5u": kill-line "\e[101;5u": end-of-line "\e[97;5u": beginning-of-line "\e[98;5u": backward-char "\e[102;5u": forward-char "\e[106;5u": accept-line "\e[109;5u": accept-line "\e[118;5u": quoted-insert "\e[104;5u": backward-delete-char # Keyboard macros # Ctrl-Alt-w: move the cursor to the end of the line and insert " # macro example" #"\e\C-w": "\C-e # macro example" # Same thing, but for the kitty protocol #"\e[119;7u": "\e[101;5u # macro example" $endif clifm-1.26.3/misc/solaris/000077500000000000000000000000001506632037700153155ustar00rootroot00000000000000clifm-1.26.3/misc/solaris/Makefile000066400000000000000000000065211506632037700167610ustar00rootroot00000000000000######################################## # Makefile for clifm (Solaris/Illumos) # ######################################## BIN ?= clifm PREFIX ?= /usr BINDIR ?= $(PREFIX)/bin DATADIR ?= $(PREFIX)/share MANDIR ?= $(DATADIR)/man LOCALEDIR ?= $(DATADIR)/locale DESKTOPPREFIX ?= $(DATADIR)/applications DESKTOPICONPREFIX ?= $(DATADIR)/icons/hicolor PROG_DATADIR ?= $(DATADIR)/$(BIN) SHELL ?= /bin/sh INSTALL ?= ginstall RM ?= rm SRCDIR = src SRC = $(SRCDIR)/*.c HEADERS = $(SRCDIR)/*.h osver != uname -r | sed -e 's/\.\([0-9]\{1,1\}\)$$/0\1/' -e 's/\.//' CFLAGS ?= -O3 -fstack-protector-strong CFLAGS += -Wall -Wextra CPPFLAGS += -DCLIFM_DATADIR=$(DATADIR) -DSUN_VERSION=$(osver) LIBS ?= -lreadline -ltermcap -lmagic -lnvpair $(BIN): $(SRC) $(HEADERS) $(CC) -o $(BIN) $(SRC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) $(LIBS) build: $(BIN) clean: $(RM) -- $(BIN) $(RM) -f -- $(SRCDIR)/*.o install: $(BIN) $(INSTALL) -m 0755 -d $(DESTDIR)$(BINDIR) $(INSTALL) -m 0755 $(BIN) $(DESTDIR)$(BINDIR) $(INSTALL) -m 0755 -d $(DESTDIR)$(PROG_DATADIR) $(INSTALL) -m 0755 -d $(DESTDIR)$(MANDIR)/man1 $(INSTALL) -m 0755 -d $(DESTDIR)$(DATADIR)/bash-completion/completions $(INSTALL) -m 0755 -d $(DESTDIR)$(DATADIR)/zsh/site-functions $(INSTALL) -m 0755 -d $(DESTDIR)$(DATADIR)/fish/vendor_completions.d $(INSTALL) -m 0755 -d $(DESTDIR)$(DESKTOPPREFIX) $(INSTALL) -m 0755 -d $(DESTDIR)$(DESKTOPICONPREFIX)/scalable/apps $(INSTALL) -m 0644 misc/$(BIN).1 $(DESTDIR)$(MANDIR)/man1 $(INSTALL) -m 0644 misc/completions.bash $(DESTDIR)$(DATADIR)/bash-completion/completions/$(BIN) $(INSTALL) -m 0644 misc/completions.zsh $(DESTDIR)$(DATADIR)/zsh/site-functions/_$(BIN) $(INSTALL) -m 0644 misc/completions.fish $(DESTDIR)$(DATADIR)/fish/vendor_completions.d/$(BIN).fish $(INSTALL) -m 0644 misc/$(BIN).desktop $(DESTDIR)$(DESKTOPPREFIX) $(INSTALL) -m 0644 misc/*.clifm $(DESTDIR)$(PROG_DATADIR) $(INSTALL) -m 0644 misc/solaris/*.clifm $(DESTDIR)$(PROG_DATADIR) $(INSTALL) -m 0644 misc/clifmrc $(DESTDIR)$(PROG_DATADIR) $(INSTALL) -m 0644 misc/logo/$(BIN).svg $(DESTDIR)$(DESKTOPICONPREFIX)/scalable/apps $(INSTALL) -m 0755 -d $(DESTDIR)$(PROG_DATADIR)/plugins $(INSTALL) -m 0755 -d $(DESTDIR)$(PROG_DATADIR)/functions $(INSTALL) -m 0755 -d $(DESTDIR)$(PROG_DATADIR)/colors $(INSTALL) -m 0755 -d $(DESTDIR)$(PROG_DATADIR)/tools $(INSTALL) -m 0755 misc/tools/imgprev/clifmrun $(DESTDIR)$(PROG_DATADIR)/plugins $(INSTALL) -m 0755 misc/tools/imgprev/clifmimg $(DESTDIR)$(PROG_DATADIR)/plugins $(INSTALL) -m 0755 plugins/* $(DESTDIR)$(PROG_DATADIR)/plugins $(INSTALL) -m 0755 misc/tools/*.py $(DESTDIR)$(PROG_DATADIR)/tools chmod 644 $(DESTDIR)$(PROG_DATADIR)/plugins/BFG.cfg chmod 644 $(DESTDIR)$(PROG_DATADIR)/plugins/plugins-helper $(INSTALL) -m 0644 misc/colors/*.clifm $(DESTDIR)$(PROG_DATADIR)/colors $(INSTALL) -m 0644 functions/* $(DESTDIR)$(PROG_DATADIR)/functions @printf "Successfully installed $(BIN)\n" uninstall: $(RM) -- $(DESTDIR)$(BINDIR)/$(BIN) $(RM) -- $(DESTDIR)$(MANDIR)/man1/$(BIN).1* $(RM) -- $(DESTDIR)$(DATADIR)/bash-completion/completions/$(BIN) $(RM) -- $(DESTDIR)$(DATADIR)/zsh/site-functions/_$(BIN) $(RM) -- $(DESTDIR)$(DATADIR)/fish/vendor_completions.d/$(BIN).fish $(RM) -- $(DESTDIR)$(DESKTOPPREFIX)/$(BIN).desktop $(RM) -r -- $(DESTDIR)$(PROG_DATADIR) $(RM) -- $(DESTDIR)$(DESKTOPICONPREFIX)/scalable/apps/$(BIN).svg @printf "Successfully uninstalled $(BIN)\n" clifm-1.26.3/misc/solaris/prompts.clifm000066400000000000000000000215761506632037700200500ustar00rootroot00000000000000 ########################## # Prompts file for CliFM # ########################## # Do not edit this file directly: use the 'prompt edit' command instead. # The regular prompt (just as the warning one, a secondary prompt used # to highlight invalid/non-existent command names) is built using command # substitution ($(cmd)), string literals and/or one or more of the # following escape sequences: # The prompt line is build using command substitution ($(cmd)), string # literals and/or the following escape sequences: # # \e: Escape character # \u: The username # \H: The full hostname # \h: The hostname, up to the first dot (.) # \s: The name of the shell (everything after the last slash) currently # used by CliFM # \S: Current workspace number (colored according to wsx code in the color # scheme file) # \l: Print an L if running in light mode # \P: The current profile name # \n: A newline character # \r: A carriage return # \a: A bell character # \d: The date, in abbreviated form (ex: Tue May 26) # \t: The time, in 24-hour HH:MM:SS format # \T: The time, in 12-hour HH:MM:SS format # \@: The time, in 12-hour am/pm format # \A: The time, in 24-hour HH:MM format # \w: The full current working directory, with $HOME abbreviated with a # tilde # \W: The basename of $PWD, with $HOME abbreviated with a tilde # \p: A mix of the two above, it abbreviates the current working directory # only if longer than PathMax (a value defined in the configuration # file). # \z: Exit code of the last executed command (printed in green in case of # success and in bold red in case of error) # \$: #, if the effective user ID is 0 (root), and $ otherwise # \nnn: The character whose ASCII code is the octal value nnn # \\: A literal backslash # \[: Begin a sequence of non-printing characters. This is mostly used to # add color to the prompt line (using full ANSI escape sequences) # \]: End a sequence of non-printing characters # # The following files statistics escape sequences are available as well: # # \D: Amount of sub-directories in the current directory # \R: Amount of regular files in the current directory # \X: Amount of executable files in the current directory # \.: Amount of hidden files in the current directory # \U: Amount of SUID files in the current directory # \G: Amount of SGID files in the current directory # \F: Amount of FIFO/pipe files in the current directory # \K: Amount of socket files in the current directory # \B: Amount of block device files in the current directory # \C: Amount of character device files in the current directory # \x: Amount of files with capabilities in the current directory # \L: Amount of symbolic links in the current directory # \o: Amount of broken symbolic links in the current directory # \M: Amount of multi-link files in the current directory # \E: Amount of files with extended attributes in the current directory # \O: Amount of other-writable files in the current directory # \": Amount of files with the sticky bit set in the current directory # \?: Amount of files of unknown file type in the current directory # \!: Amount of unstatable files in the current directory # Escape codes to control prompt notifications: # # \*: An asterisk + amount of selected files (e.g. *12) # \%: 'T' + amount of trashed files (e.g. T3) # \#: Print an 'R' if running as root # \(: 'E' + amount of error messages (e.g. E2) # \): 'W' + amount of warning messages (e.g. W2) # \=: 'N' + amount of notice messages (e.g. N1) # # NOTE: Except in the case of \#, nothing is printed if the corresponding # number is zero (no selected files, no trashed files, and so on). # Unicode characters could be inserted by directly pasting the # corresponding char, or by inserting its hex code: # echo -ne "paste_your_char" | hexdump -C # Set Notifications to false to prevent the automatic insertion of # root, trash, messages (error, warning, and notice), and selected files # indicators at the left of the prompt, in which case the prompt code # should handle itself this data using the appropriate escape codes. # To permanetly set any of the below prompts edit your color scheme file # (via the 'cs edit' command), set Prompt to either the prompt code or # the prompt name you want (e.g. Prompt="classic"), and comment out the # remaining prompt lines. # # NOTE: Since the below prompts have been designed for CliFM's default # color scheme, you might need to edit the one you choose manually to # make it fit your current color scheme. # On readline prior to 7.0, colored warning prompts do not work due to # a bug in the rl_redisplay routine. Uncomment the commented out # WarningPrompt options if using a version >= 7.0 [clifm] Notifications=true RegularPrompt="\[\e[0m\][\[\e[0;36m\]\S\[\e[0m\]]\l \A \u:\H \[\e[0;36m\]\w\n\[\e[0m\]<\z\[\e[0m\]> \[\e[0;34m\]\$ \[\e[0m\]" EnableWarningPrompt=true #WarningPrompt="\[\e[00;02;31m\](!) > " WarningPrompt="(!) > " [clifm-box-drawing] # The box drawing set isn't supported by all terminals Notifications=false RegularPrompt="\[\e[0m\]\[\e[0;36m\]\[\e(0\]lq\[\e(B\]\[\e[0;31m\]\#\[\e[32m\]\*\[\e[36m\]\%\[\e[31m\]\(\[\e[33m\]\)\[\e[32m\]\=\[\e[0m\][\S\[\e[0m\]]\l \A \u:\H \[\e[0;36m\]\w\n\[\e[0;36m\]\[\e(0\]mq\[\e(B\]\[\e[0m\]<\z\[\e[0m\]> \[\e[0;34m\]\$ \[\e[0m\]" EnableWarningPrompt=true #WarningPrompt="\[\e[0;36m\]\[\e(0\]mq\[\e(B\]\[\e[0m\]<\z\[\e[0m\]> \[\e[1;31m\]\! \[\e[00;02;31m\]" WarningPrompt="\[\e(0\]mq\[\e(B\]<\z> \! " [classic] Notifications=true RegularPrompt="\[\e[1;32m\][\u@\H] \[\e[1;34m\]\w \[\e[0m\]\$ " EnableWarningPrompt=true #WarningPrompt="\[\e[1;32m\][\u@\H] \[\e[1;34m\]\w \[\e[1;31m\]! \[\e[00;02;31m\]" WarningPrompt="[\u@\H] \w ! " [security-scanner] # Print file statistics about the current directory (-:-:-:-) in this order: # SUID, SGID, other-writable, and executable files Notifications=true RegularPrompt="\[\e[0m\][\[\e[0;36m\]\S\[\e[0m\]]\l \[\e[0m\]\[\e[1;31m\]\U\[\e[0m\]:\[\e[1;33m\]\G\[\e[0m\]:\[\e[1;34m\]\O\[\e[0m\]:\[\e[1;32m\]\X\[\e[0m\] \A \[\e[0;36m\]\w\n\[\e[0m\]<\z\[\e[0m\]> \[\e[0;34m\]\$ \[\e[0m\]" EnableWarningPrompt=true #WarningPrompt="\[\e[00;02;31m\](!) > " WarningPrompt="(!) > " [curves] Notifications=false RegularPrompt="\[\e[00;01;32m\]╭─\[\e[0m\]\[\e[1;32m\]\*\[\e[1;36m\]\%\[\e[1;31m\]\(\[\e[1;33m\]\)\[\e[1;32m\]\=\[\e[0m\][\S\[\e[0m\]]\[\e[01;32m\]─\[\e[0m\](\u:\H)\[\e[01;32m\]─\[\e[0m\][\[\e[00;36m\]\w\[\e[0m\]]\n\[\e[01;32m\]╰─\[\e[1;0m\]<\z\[\e[0m\]> \[\e[34m\]λ\[\e[0m\] " EnableWarningPrompt=true #WarningPrompt="\[\e[0m\]\[\e[01;32m\]╰─\[\e[1;0m\]<\z\[\e[0m\]> \[\e[0;31m\]λ\[\e[00;02;31m\] " WarningPrompt="╰─<\z\> λ " # The prompts below require a patched Nerdfont [firestarter] Notifications=false RegularPrompt="\[\e[01;38;5;124m\]╭─\[\e[38;5;124m\]\[\e[37;48;5;124m\]\[\e[1;37m\]\#\[\e[32m\]\*\[\e[36m\]\%\[\e[37m\]\(\[\e[33m\]\)\[\e[32m\]\=\[\e[00;37;48;5;124m\][\S\[\e[37;48;5;124m\]] \[\e[0;48;5;124m\]\A \[\e[00;38;5;124;43m\]\[\e[00;30;43m\] \u:\H \[\e[00;33;48;5;124m\]\[\e[00;37;48;5;124m\] \w \[\e[00;38;5;124m\]\[\e[0m\]\n\[\e[01;38;5;124m\]╰─▶ \[\e[0m\]" EnableWarningPrompt=true #WarningPrompt="\[\e[00;01;38;5;124m\]╰─\[\e[0;38;5;124m\]▶ \[\e[00;02;31m\]" WarningPrompt="╰─▶ " [cold-winter] Notifications=false RegularPrompt="\[\e[00;37;100m\]\[\e[1;31m\]\#\[\e[32m\]\*\[\e[36m\]\%\[\e[31m\]\(\[\e[33m\]\)\[\e[32m\]\=\[\e[0;37;100m\][\S\[\e[00;37;100m\]] \A \[\e[00;90;46m\] \[\e[0;30;46m\]\u:\H \[\e[0;36;100m\] \[\e[00;37;100m\]\w \[\e[00;90;40m\] \n \[\e[1;90m\]\[\e[0m\] " EnableWarningPrompt=true #WarningPrompt=" \[\e[0m\]\[\e[1;2;31m\] \[\e[00;02;31m\]" WarningPrompt=" " [spot] Notifications=false RegularPrompt="\[\e[00;38;5;0;48;5;53m\] \[\e[31m\]\#\[\e[32m\]\*\[\e[36m\]\%\[\e[31m\]\(\[\e[34m\]\)\[\e[32m\]\=\[\e[00;37;48;5;53m\][\S\[\e[37m\]] \[\e[38;5;53;48;5;178m\] \[\e[00;38;5;0;48;5;178m\]\A \u:\H \w \[\e[00;38;5;178;48;5;0m\]\[\e[0;40m\]\n\[\e[0;38;5;254;48;5;53m\] \$ \[\e[0;38;5;53;48;5;0m\] \[\e[0m\] " EnableWarningPrompt=true #WarningPrompt="\n\[\e[0;37;48;5;124m\] \x \[\e[0;38;5;124;48;5;0m\] \[\e[00;02;31m\] " WarningPrompt="\n \x  " [artic-particles] Notifications=false RegularPrompt="\[\e[00;37;48;5;18m\] \A \[\e[00;38;5;18;47m\] \u:\H \[\e[00;37;48;5;18m\] \w \[\e[00;38;5;18;40m\] \n\[\e[00;37;48;5;18m\] \$ \[\e[00;38;5;18;40m\] " EnableWarningPrompt=true #WarningPrompt="\[\e[00;02;31;47m\] \$ \[\e[00;37;0m\] \[\e[00;02;31m\]" WarningPrompt=" \$  " [green-beret] Notifications=false RegularPrompt="╭─\[\e[0;38;5;239;48;5;0m\]\[\e[0;38;5;15;48;5;239m\]\[\e[31m\]\#\[\e[38;5;76m\]\*\[\e[36m\]\%\[\e[31m\]\(\[\e[33m\]\)\[\e[32m\]\=\[\e[38;5;15m\][\S\[\e[38;5;15m\]]  \A \[\e[0;38;5;239;48;5;70m\]\[\e[0;38;5;0;48;5;70m\] \w \[\e[0;38;5;70;48;5;0m\]\n\[\e[0;40m\]╰─\[\e[0;38;5;70;48;5;0m\]▶\[\e[0;40m\] " EnableWarningPrompt=true #WarningPrompt="\[\e[0;40m\]╰─\[\e[0;38;5;9;48;5;0m\]▶ \[\e[00;02;31m\]" WarningPrompt="╰─▶ " clifm-1.26.3/misc/termux/000077500000000000000000000000001506632037700151655ustar00rootroot00000000000000clifm-1.26.3/misc/termux/Makefile000066400000000000000000000063731506632037700166360ustar00rootroot00000000000000############################### # Makefile for clifm - Termux # ############################### BIN ?= clifm PREFIX ?= /data/data/com.termux/files/usr BINDIR ?= $(PREFIX)/bin DATADIR ?= $(PREFIX)/share MANDIR ?= $(DATADIR)/man LOCALEDIR ?= $(DATADIR)/locale DESKTOPPREFIX ?= $(DATADIR)/applications DESKTOPICONPREFIX ?= $(DATADIR)/icons/hicolor PROG_DATADIR ?= $(DATADIR)/$(BIN) SHELL ?= /bin/sh INSTALL ?= install RM ?= rm SRCDIR = src SRC = $(SRCDIR)/*.c HEADERS = $(SRCDIR)/*.h CFLAGS ?= -O3 -fstack-protector-strong LIBS ?= -lreadline -lacl -lcap -lmagic -landroid-glob CFLAGS += -Wall -Wextra -DCLIFM_DATADIR=$(DATADIR) -D_NO_GETTEXT -D__TERMUX__ $(BIN): $(SRC) $(HEADERS) $(CC) -o $(BIN) $(SRC) $(CFLAGS) $(LDFLAGS) $(LIBS) build: $(BIN) clean: $(RM) -- $(BIN) $(RM) -f -- $(SRCDIR)/*.o install: $(BIN) $(INSTALL) -m 0755 -d $(DESTDIR)$(BINDIR) $(INSTALL) -m 0755 $(BIN) $(DESTDIR)$(BINDIR) $(INSTALL) -m 0755 -d $(DESTDIR)$(PROG_DATADIR) $(INSTALL) -m 0755 -d $(DESTDIR)$(MANDIR)/man1 $(INSTALL) -m 0755 -d $(DESTDIR)$(DATADIR)/bash-completion/completions $(INSTALL) -m 0755 -d $(DESTDIR)$(DATADIR)/zsh/site-functions $(INSTALL) -m 0755 -d $(DESTDIR)$(DATADIR)/fish/vendor_completions.d $(INSTALL) -m 0755 -d $(DESTDIR)$(DESKTOPPREFIX) $(INSTALL) -m 0755 -d $(DESTDIR)$(DESKTOPICONPREFIX)/scalable/apps $(INSTALL) -m 0644 misc/$(BIN).1 $(DESTDIR)$(MANDIR)/man1 $(INSTALL) -m 0644 misc/completions.bash $(DESTDIR)$(DATADIR)/bash-completion/completions/$(BIN) $(INSTALL) -m 0644 misc/completions.zsh $(DESTDIR)$(DATADIR)/zsh/site-functions/_$(BIN) $(INSTALL) -m 0644 misc/completions.fish $(DESTDIR)$(DATADIR)/fish/vendor_completions.d/$(BIN).fish $(INSTALL) -m 0644 misc/$(BIN).desktop $(DESTDIR)$(DESKTOPPREFIX) $(INSTALL) -m 0644 misc/*.clifm $(DESTDIR)$(PROG_DATADIR) $(INSTALL) -m 0644 misc/termux/*.clifm $(DESTDIR)$(PROG_DATADIR) $(INSTALL) -m 0644 misc/clifmrc $(DESTDIR)$(PROG_DATADIR) $(INSTALL) -m 0644 misc/logo/$(BIN).svg $(DESTDIR)$(DESKTOPICONPREFIX)/scalable/apps $(INSTALL) -m 0755 -d $(DESTDIR)$(PROG_DATADIR)/plugins $(INSTALL) -m 0755 -d $(DESTDIR)$(PROG_DATADIR)/functions $(INSTALL) -m 0755 -d $(DESTDIR)$(PROG_DATADIR)/colors $(INSTALL) -m 0755 -d $(DESTDIR)$(PROG_DATADIR)/tools $(INSTALL) -m 0755 plugins/* $(DESTDIR)$(PROG_DATADIR)/plugins $(INSTALL) -m 0755 misc/tools/imgprev/clifmrun $(DESTDIR)$(PROG_DATADIR)/plugins $(INSTALL) -m 0755 misc/tools/imgprev/clifmimg $(DESTDIR)$(PROG_DATADIR)/plugins $(INSTALL) -m 0755 misc/tools/*.py $(DESTDIR)$(PROG_DATADIR)/tools chmod 644 $(DESTDIR)$(PROG_DATADIR)/plugins/BFG.cfg chmod 644 $(DESTDIR)$(PROG_DATADIR)/plugins/plugins-helper $(INSTALL) -m 0644 misc/colors/*.clifm $(DESTDIR)$(PROG_DATADIR)/colors $(INSTALL) -m 0644 functions/* $(DESTDIR)$(PROG_DATADIR)/functions @printf "Successfully installed $(BIN)\n" uninstall: $(RM) -- $(DESTDIR)$(BINDIR)/$(BIN) $(RM) -- $(DESTDIR)$(MANDIR)/man1/$(BIN).1* $(RM) -- $(DESTDIR)$(DATADIR)/bash-completion/completions/$(BIN) $(RM) -- $(DESTDIR)$(DATADIR)/zsh/site-functions/_$(BIN) $(RM) -- $(DESTDIR)$(DATADIR)/fish/vendor_completions/$(BIN).fish $(RM) -- $(DESTDIR)$(DESKTOPPREFIX)/$(BIN).desktop $(RM) -r -- $(DESTDIR)$(PROG_DATADIR) $(RM) -- $(DESTDIR)$(DESKTOPICONPREFIX)/scalable/apps/$(BIN).svg @printf "Successfully uninstalled $(BIN)\n" clifm-1.26.3/misc/termux/mimelist.clifm000066400000000000000000000122671506632037700200340ustar00rootroot00000000000000 ################################### # Configuration file for Lira # # Clifm's file opener # ################################### # Commented and blank lines are omitted # The below settings cover the most common filetypes # It is recommended to edit this file placing your prefered applications # at the beginning of the apps list to speed up the opening process # The file is read top to bottom and left to right; the first existent # application found will be used # Applications defined here are NOT desktop files, but commands (arguments # could be used as well). Write you own handmade scripts to open specific # files if necessary. Ex: X:^text/.*:~/scripts/my_cool_script.sh # Use 'X' to specify a GUI environment and '!X' for non-GUI environments, # like the kernel built-in console or a remote SSH session. # Use 'N' to match file names instead of MIME types. # Regular expressions are allowed for both file types and file names. # Use the %f placeholder to specify the position of the file name to be # opened in the command. Example: # 'mpv %f --terminal=no' -> 'mpv FILE --terminal=no' # If %f is not specified, the file name will be added to the end of the # command. Ex: 'mpv --terminal=no' -> 'mpv --terminal=no FILE' # Running the opening application in the background: # For GUI applications: # APP %f & # For terminal applications: # TERM -e APP %f & # Replace 'TERM' and 'APP' by the corresponding values. The -e option # might vary depending on the terminal emulator used (TERM) # Note on graphical applications: If the opening application is already # running, the file will be opened, usually in a new tab, and CliFM won't # wait for the file to be closed (because the procecss already returned). # To avoid this, instruct the application to run a new instance. For example: # geany -i, gedit -s, kate -n, pluma --new-window, and so on. # To silence STDERR and/or STDOUT use !E and !O respectivelly (they could # be used together). Examples: # Silence STDERR only and run in the foreground: # mpv %f !E # Silence both (STDERR and STDOUT) and run in the background: # mpv %f !EO & # or # mpv %f !E !O & # Environment variables could be used as well. Example: # X:text/plain=$EDITOR %f &;$VISUAL;nano;vi ########################### # File names/extensions # ########################### # Match a full file name #X:N:some_filename=cmd # Match all file names starting with 'str' #X:N:^str.*=cmd # Match files with extension 'ext' #X:N:.*\.ext$=cmd X:N:.*\.djvu$=djview;zathura;evince;atril X:N:.*\.epub$=mupdf;zathura;ebook-viewer X:N:.*\.mobi$=ebook-viewer X:N:.*\.(cbr|cbz)$=zathura X:N:(.*\.clifm$|clifmrc)=$EDITOR;$VISUAL;nano;kak;micro;nvim;vim;vi;mg;emacs;ed;mili;leafpad;mousepad;featherpad;gedit -s;kate -n;pluma --new-window !X:N:(.*\.clifm$|clifmrc)=$EDITOR;$VISUAL;nano;kak;micro;nvim;vim;vi;mg;emacs;ed ################## # MIME types # ################## # Directories - only for the open-with command (ow) and the --open command # line option # In graphical environments directories will be opened in a new window X:inode/directory=xterm -e clifm %f &;xterm -e vifm %f &;pcmanfm %f &;thunar %f &;xterm -e ncdu %f & !X:inode/directory=vifm;ranger;nnn;ncdu # Web content X:^text/html$=$BROWSER;surf;vimprobable;vimprobable2;qutebrowser;dwb;jumanji;luakit;uzbl;uzbl-tabbed;uzbl-browser;uzbl-core;iceweasel;midori;opera;firefox;seamonkey;brave;chromium-browser;chromium;google-chrome;epiphany;konqueror;elinks;links2;links;lynx;w3m !X:^text/html$=$BROWSER;elinks;links2;links;lynx;w3m # Text #X:^text/x-(c|shellscript|perl|script.python|makefile|fortran|java-source|javascript|pascal)$=geany X:(^text/.*|application/json|inode/x-empty)=$EDITOR;$VISUAL;nano;kak;micro;dte;nvim;vim;vi;mg;emacs;ed;mili;leafpad;mousepad;featherpad;nedit;kate;gedit;pluma;io.elementary.code;liri-text;xed;atom;nota;gobby;kwrite;xedit !X:(^text/.*|application/json|inode/x-empty)=$EDITOR;$VISUAL;nano;kak;micro;dte;nvim;vim;vi;mg;emacs;ed # Office documents X:^application/.*(open|office)document.*=libreoffice;soffice;ooffice # Archives # Note: 'ad' is CliFM's built-in archives utility (based on atool). Remove it if you # prefer another application X:^application/(zip|gzip|zstd|x-7z-compressed|x-xz|x-bzip*|x-tar|x-iso9660-image)=ad;xarchiver %f &;lxqt-archiver %f &;ark %f & !X:^application/(zip|gzip|zstd|x-7z-compressed|x-xz|x-bzip*|x-tar|x-iso9660-image)=ad # PDF X:.*/pdf$=mupdf;sioyek;llpp;lpdf;zathura;mupdf-x11;apvlv;xpdf;evince;atril;okular;epdfview;qpdfview # Images X:^image/gif$=animate;pqiv;sxiv -a;nsxiv -a X:^image/.*=fim;display;sxiv;nsxiv;pqiv;gpicview;qview;qimgv;inkscape;mirage;ristretto;eog;eom;xviewer;viewnior;nomacs;geeqie;gwenview;gthumb;gimp !X:^image/*=fim;img2txt;cacaview;fbi;fbv # Video and audio X:^video/.*=ffplay;mplayer;mplayer2;mpv;vlc;gmplayer;smplayer;celluloid;qmplayer2;haruna;totem X:^audio/.*=ffplay -nodisp -autoexit;mplayer;mplayer2;mpv;vlc;gmplayer;smplayer;totem # Fonts X:^font/.*=fontforge;fontpreview # Torrent: X:application/x-bittorrent=rtorrent;transimission-gtk;transmission-qt;deluge-gtk;ktorrent # Fallback to another file opener as last resource .*=xdg-open;mimeo;mimeopen -n;whippet -m;open;linopen; clifm-1.26.3/misc/tools/000077500000000000000000000000001506632037700150015ustar00rootroot00000000000000clifm-1.26.3/misc/tools/deroff.py000077500000000000000000001004521506632037700166250ustar00rootroot00000000000000#!/usr/bin/python3 # -*- coding: utf-8 -*- # This file is part of CliFM # Taken from https://github.com/fish-shell/fish-shell/blob/master/share/tools/deroff.py """ Deroff.py, ported to Python from the venerable deroff.c """ import sys, re, string IS_PY3 = sys.version_info[0] >= 3 class Deroffer: g_specs_specletter = { # Output composed latin1 letters "-D": "\320", "Sd": "\360", "Tp": "\376", "TP": "\336", "AE": "\306", "ae": "\346", "OE": "OE", "oe": "oe", ":a": "\344", ":A": "\304", ":e": "\353", ":E": "\313", ":i": "\357", ":I": "\317", ":o": "\366", ":O": "\326", ":u": "\374", ":U": "\334", ":y": "\377", "ss": "\337", "'A": "\301", "'E": "\311", "'I": "\315", "'O": "\323", "'U": "\332", "'Y": "\335", "'a": "\341", "'e": "\351", "'i": "\355", "'o": "\363", "'u": "\372", "'y": "\375", "^A": "\302", "^E": "\312", "^I": "\316", "^O": "\324", "^U": "\333", "^a": "\342", "^e": "\352", "^i": "\356", "^o": "\364", "^u": "\373", "`A": "\300", "`E": "\310", "`I": "\314", "`O": "\322", "`U": "\331", "`a": "\340", "`e": "\350", "`i": "\354", "`o": "\362", "`u": "\371", "~A": "\303", "~N": "\321", "~O": "\325", "~a": "\343", "~n": "\361", "~o": "\365", ",C": "\307", ",c": "\347", "/l": "/l", "/L": "/L", "/o": "\370", "/O": "\330", "oA": "\305", "oa": "\345", # Ligatures "fi": "fi", "ff": "ff", "fl": "fl", "Fi": "ffi", "Ff": "fff", "Fl": "ffl", } g_specs = { "mi": "-", "en": "-", "hy": "-", "em": "--", "lq": "“", "rq": "”", "Bq": ",,", "oq": "`", "cq": "'", "aq": "'", "dq": '"', "or": "|", "at": "@", "sh": "#", "Eu": "\244", "eu": "\244", "Do": "$", "ct": "\242", "Fo": "\253", "Fc": "\273", "fo": "<", "fc": ">", "r!": "\241", "r?": "\277", "Of": "\252", "Om": "\272", "pc": "\267", "S1": "\271", "S2": "\262", "S3": "\263", "<-": "<-", "->": "->", "<>": "<->", "ua": "^", "da": "v", "lA": "<=", "rA": "=>", "hA": "<=>", "uA": "^^", "dA": "vv", "ba": "|", "bb": "|", "br": "|", "bv": "|", "ru": "_", "ul": "_", "ci": "O", "bu": "o", "co": "\251", "rg": "\256", "tm": "(TM)", "dd": "||", "dg": "|", "ps": "\266", "sc": "\247", "de": "\260", "%0": "0/00", "14": "\274", "12": "\275", "34": "\276", "f/": "/", "sl": "/", "rs": "\\", "sq": "[]", "fm": "'", "ha": "^", "ti": "~", "lB": "[", "rB": "]", "lC": "{", "rC": "}", "la": "<", "ra": ">", "lh": "<=", "rh": "=>", "tf": "therefore", "~~": "~~", "~=": "~=", "!=": "!=", "**": "*", "+-": "\261", "<=": "<=", "==": "==", "=~": "=~", ">=": ">=", "AN": "\\/", "OR": "/\\", "no": "\254", "te": "there exists", "fa": "for all", "Ah": "aleph", "Im": "imaginary", "Re": "real", "if": "infinity", "md": "\267", "mo": "member of", "mu": "\327", "nm": "not member of", "pl": "+", "eq": "=", "pt": "oc", "pp": "perpendicular", "sb": "(=", "sp": "=)", "ib": "(-", "ip": "-)", "ap": "~", "is": "I", "sr": "root", "pd": "d", "c*": "(x)", "c+": "(+)", "ca": "cap", "cu": "U", "di": "\367", "gr": "V", "es": "{}", "CR": "_|", "st": "such that", "/_": "/_", "lz": "<>", "an": "-", # Output Greek "*A": "Alpha", "*B": "Beta", "*C": "Xi", "*D": "Delta", "*E": "Epsilon", "*F": "Phi", "*G": "Gamma", "*H": "Theta", "*I": "Iota", "*K": "Kappa", "*L": "Lambda", "*M": "Mu", "*N": "Nu", "*O": "Omicron", "*P": "Pi", "*Q": "Psi", "*R": "Rho", "*S": "Sigma", "*T": "Tau", "*U": "Upsilon", "*W": "Omega", "*X": "Chi", "*Y": "Eta", "*Z": "Zeta", "*a": "alpha", "*b": "beta", "*c": "xi", "*d": "delta", "*e": "epsilon", "*f": "phi", "+f": "phi", "*g": "gamma", "*h": "theta", "+h": "theta", "*i": "iota", "*k": "kappa", "*l": "lambda", "*m": "\265", "*n": "nu", "*o": "omicron", "*p": "pi", "+p": "omega", "*q": "psi", "*r": "rho", "*s": "sigma", "*t": "tau", "*u": "upsilon", "*w": "omega", "*x": "chi", "*y": "eta", "*z": "zeta", "ts": "sigma", } g_re_word = re.compile(r"[a-zA-Z_]+") # equivalent to the word() method g_re_number = re.compile(r"[+-]?\d+") # equivalent to the number() method g_re_esc_char = re.compile( r"""([a-zA-Z_]) | # Word ([+-]?\d) | # Number \\ # Backslash (for escape seq) """, re.VERBOSE, ) g_re_not_backslash_or_whitespace = re.compile( r"[^ \t\n\r\f\v\\]+" ) # Match a sequence of not backslash or whitespace g_re_newline_collapse = re.compile(r"\n{3,}") g_re_font = re.compile( r"""\\f( # Starts with backslash f (\(\S{2}) | # Open paren, then two printable chars (\[\S*?\]) | # Open bracket, zero or more printable characters, then close bracket \S) # Any printable character """, re.VERBOSE, ) # This gets filled in in __init__ below g_macro_dict = False def __init__(self): self.reg_table = {} self.tr_from = "" self.tr_to = "" self.tr = "" self.nls = 2 self.specletter = False self.refer = False self.macro = 0 self.nobody = False self.inlist = False self.inheader = False self.pic = False self.tbl = False self.tblstate = 0 self.tblTab = "" self.eqn = False self.skipheaders = False self.skiplists = False self.ignore_sonx = False self.output = [] self.name = "" self.OPTIONS = 0 self.FORMAT = 1 self.DATA = 2 # words is uninteresting and should be treated as false if not Deroffer.g_macro_dict: Deroffer.g_macro_dict = { "SH": Deroffer.macro_sh, "SS": Deroffer.macro_ss_ip, "IP": Deroffer.macro_ss_ip, "H ": Deroffer.macro_ss_ip, "I ": Deroffer.macro_i_ir, "IR": Deroffer.macro_i_ir, "IB": Deroffer.macro_i_ir, "B ": Deroffer.macro_i_ir, "BR": Deroffer.macro_i_ir, "BI": Deroffer.macro_i_ir, "R ": Deroffer.macro_i_ir, "RB": Deroffer.macro_i_ir, "RI": Deroffer.macro_i_ir, "AB": Deroffer.macro_i_ir, "Nm": Deroffer.macro_Nm, "] ": Deroffer.macro_close_bracket, "PS": Deroffer.macro_ps, "PE": Deroffer.macro_pe, "TS": Deroffer.macro_ts, "T&": Deroffer.macro_t_and, "TE": Deroffer.macro_te, "EQ": Deroffer.macro_eq, "EN": Deroffer.macro_en, "R1": Deroffer.macro_r1, "R2": Deroffer.macro_r2, "de": Deroffer.macro_de, "BL": Deroffer.macro_bl_vl, "VL": Deroffer.macro_bl_vl, "AL": Deroffer.macro_bl_vl, "LB": Deroffer.macro_bl_vl, "RL": Deroffer.macro_bl_vl, "ML": Deroffer.macro_bl_vl, "DL": Deroffer.macro_bl_vl, "BV": Deroffer.macro_bv, "LE": Deroffer.macro_le, "LP": Deroffer.macro_lp_pp, "PP": Deroffer.macro_lp_pp, "P\n": Deroffer.macro_lp_pp, "ds": Deroffer.macro_ds, "so": Deroffer.macro_so_nx, "nx": Deroffer.macro_so_nx, "tr": Deroffer.macro_tr, "sp": Deroffer.macro_sp, } def flush_output(self, where): if where: where.write(self.get_output()) self.output[:] = [] def get_output(self): res = "".join(self.output) clean_res = Deroffer.g_re_newline_collapse.sub("\n", res) return clean_res def putchar(self, c): self.output.append(c) return c # This gets swapped in in place of condputs the first time tr gets modified def condputs_tr(self, str): special = ( self.pic or self.eqn or self.refer or self.macro or (self.skiplists and self.inlist) or (self.skipheaders and self.inheader) ) if not special: self.output.append(str.translate(self.tr)) def condputs(self, str): special = ( self.pic or self.eqn or self.refer or self.macro or (self.skiplists and self.inlist) or (self.skipheaders and self.inheader) ) if not special: self.output.append(str) def str_at(self, idx): return self.s[idx : idx + 1] def skip_char(self, amt=1): self.s = self.s[amt:] def skip_leading_whitespace(self): self.s = self.s.lstrip() def is_white(self, idx): # Note this returns false for empty strings (idx >= len(self.s)) return self.s[idx : idx + 1].isspace() def str_eq(offset, other, len): return self.s[offset : offset + len] == other[:len] def prch(self, idx): # Note that this return False for the empty string (idx >= len(self.s)) ch = self.s[idx : idx + 1] return ch not in " \t\n" def font(self): match = Deroffer.g_re_font.match(self.s) if not match: return False self.skip_char(match.end()) return True def font2(self): if self.s[0:2] == "\\f": c = self.str_at(2) if c == "(" and self.prch(3) and self.prch(4): self.skip_char(5) return True elif c == "[": self.skip_char(2) while self.prch(0) and self.str_at(0) != "]": self.skip_char() if self.str_at(0) == "]": self.skip_char() elif self.prch(2): self.skip_char(3) return True return False def comment(self): # Here we require that the string start with \" while self.str_at(0) and self.str_at(0) != "\n": self.skip_char() return True def numreq(self): # We require that the string starts with backslash if self.str_at(1) in "hvwud" and self.str_at(2) == "'": self.macro += 1 self.skip_char(3) while self.str_at(0) != "'" and self.esc_char(): pass # Weird if self.str_at(0) == "'": self.skip_char() self.macro -= 1 return True return False def var(self): reg = "" s0s1 = self.s[0:2] if s0s1 == "\\n": if self.s[3:5] == "dy": self.skip_char(5) return True elif self.str_at(2) == "(" and self.prch(3) and self.prch(4): self.skip_char(5) return True elif self.str_at(2) == "[" and self.prch(3): self.skip_char(3) while self.str_at(0) and self.str_at(0) != "]": self.skip_char() return True elif self.prch(2): self.skip_char(3) return True elif s0s1 == "\\*": if self.str_at(2) == "(" and self.prch(3) and self.prch(4): reg = self.s[3:5] self.skip_char(5) elif self.str_at(2) == "[" and self.prch(3): self.skip_char(3) while self.str_at(0) and self.str_at(0) != "]": reg = reg + self.str_at(0) self.skip_char() if self.s[0:1] == "]": self.skip_char() else: return False elif self.prch(2): reg = self.str_at(2) self.skip_char(3) else: return False if reg in self.reg_table: old_s = self.s self.s = self.reg_table[reg] self.text_arg() return True return False def size(self): # We require that the string starts with \s if self.digit(2) or (self.str_at(2) in "-+" and self.digit(3)): self.skip_char(3) while self.digit(0): self.skip_char() return True return False def spec(self): self.specletter = False if self.s[0:2] == "\\(" and self.prch(2) and self.prch(3): key = self.s[2:4] if key in Deroffer.g_specs_specletter: self.condputs(Deroffer.g_specs_specletter[key]) self.specletter = True elif key in Deroffer.g_specs: self.condputs(Deroffer.g_specs[key]) self.skip_char(4) return True elif self.s.startswith("\\%"): self.specletter = True self.skip_char(2) return True else: return False def esc(self): # We require that the string start with backslash c = self.s[1:2] if not c: return False if c in "eE": self.condputs("\\") elif c in "t": self.condputs("\t") elif c in "0~": self.condputs(" ") elif c in "|^&:": pass else: self.condputs(c) self.skip_char(2) return True def word(self): got_something = False while True: match = Deroffer.g_re_word.match(self.s) if not match: break got_something = True self.condputs(match.group(0)) self.skip_char(match.end(0)) # Consume all specials while self.spec(): if not self.specletter: break return got_something def text(self): while True: idx = self.s.find("\\") if idx == -1: self.condputs(self.s) self.s = "" break else: self.condputs(self.s[:idx]) self.skip_char(idx) if not self.esc_char_backslash(): self.condputs(self.str_at(0)) self.skip_char() return True def letter(self, idx): ch = self.str_at(idx) return ch.isalpha() or ch == "_" # underscore is used in C identifiers def digit(self, idx): ch = self.str_at(idx) return ch.isdigit() def number(self): match = Deroffer.g_re_number.match(self.s) if not match: return False else: self.condputs(match.group(0)) self.skip_char(match.end()) return True def esc_char_backslash(self): # Like esc_char, but we know the string starts with a backslash c = self.s[1:2] if c == '"': return self.comment() elif c == "f": return self.font() elif c == "s": return self.size() elif c in "hvwud": return self.numreq() elif c in "n*": return self.var() elif c == "(": return self.spec() else: return self.esc() def esc_char(self): if self.s[0:1] == "\\": return self.esc_char_backslash() return self.word() or self.number() def quoted_arg(self): if self.str_at(0) == '"': self.skip_char() while self.s and self.str_at(0) != '"': if not self.esc_char(): if self.s: self.condputs(self.str_at(0)) self.skip_char() return True else: return False def text_arg(self): # PCA: The deroff.c textArg() disallowed quotes at the start of an argument # I'm not sure if this was a bug or not got_something = False while True: match = Deroffer.g_re_not_backslash_or_whitespace.match(self.s) if match: # Output the characters in the match self.condputs(match.group(0)) self.skip_char(match.end(0)) got_something = True # Next is either an escape, or whitespace, or the end # If it's the whitespace or the end, we're done if not self.s or self.is_white(0): return got_something # Try an escape if not self.esc_char(): # Some busted escape? Just output it self.condputs(self.str_at(0)) self.skip_char() got_something = True def text_arg2(self): if not self.esc_char(): if self.s and not self.is_white(0): self.condputs(self.str_at(0)) self.skip_char() else: return False while True: if not self.esc_char(): if self.s and not self.is_white(0): self.condputs(self.str_at(0)) self.skip_char() else: return True # Macro functions def macro_sh(self): for header_str in [" SYNOPSIS", ' "SYNOPSIS', " ‹BERSICHT", ' "‹BERSICHT']: if self.s[2:].startswith(header_str): self.inheader = True break else: # Did not find a header string self.inheader = False self.nobody = True def macro_ss_ip(self): self.nobody = True return False def macro_i_ir(self): return False def macro_Nm(self): if self.s == "Nm\n": self.condputs(self.name) else: self.name = self.s[3:].strip() + " " return True def macro_close_bracket(self): self.refer = False return False def macro_ps(self): if self.is_white(2): self.pic = True self.condputs("\n") return True def macro_pe(self): if self.is_white(2): self.pic = False self.condputs("\n") return True def macro_ts(self): if self.is_white(2): self.tbl, self.tblstate = True, self.OPTIONS self.condputs("\n") return True def macro_t_and(self): if self.is_white(2): self.tbl, self.tblstate = True, self.FORMAT self.condputs("\n") return True def macro_te(self): if self.is_white(2): self.tbl = False self.condputs("\n") return True def macro_eq(self): if self.is_white(2): self.eqn = True self.condputs("\n") return True def macro_en(self): if self.is_white(2): self.eqn = False self.condputs("\n") return True def macro_r1(self): if self.is_white(2): self.refer2 = True self.condputs("\n") return True def macro_r2(self): if self.is_white(2): self.refer2 = False self.condputs("\n") return True def macro_de(self): macro = True self.condputs("\n") return True def macro_bl_vl(self): if self.is_white(2): self.inlist = True self.condputs("\n") return True def macro_bv(self): if self.str_at(2) == "L" and self.white(self.str_at(3)): self.inlist = True self.condputs("\n") return True def macro_le(self): if self.is_white(2): self.inlist = False self.condputs("\n") return True def macro_lp_pp(self): self.condputs("\n") return True def macro_ds(self): self.skip_char(2) self.skip_leading_whitespace() if self.str_at(0): # Split at whitespace comps = self.s.split(None, 2) if len(comps) == 2: name, value = comps value = value.rstrip() self.reg_table[name] = value self.condputs("\n") return True def macro_so_nx(self): # We always ignore include directives # deroff.c for some reason allowed this to fall through to the 'tr' case # I think that was just a bug so I won't replicate it return True def macro_tr(self): self.skip_char(2) self.skip_leading_whitespace() while self.s and self.str_at(0) != "\n": c = self.str_at(0) ns = self.str_at(1) self.skip_char(2) if not ns or ns == "\n": ns = " " self.tr_from += c self.tr_to += ns # Update our table, then swap in the slower tr-savvy condputs try: # Python2 self.tr = string.maketrans(self.tr_from, self.tr_to) except AttributeError: # Python3 self.tr = "".maketrans(self.tr_from, self.tr_to) self.condputs = self.condputs_tr return True def macro_sp(self): self.condputs("\n") return True def macro_other(self): self.condputs("\n") return True def request_or_macro(self): # s[0] is period or open single quote self.skip_char() s0 = self.s[1:2] if s0 == "\\": if self.str_at(1) == '"': self.condputs("\n") return True else: pass elif s0 == "[": self.refer = True self.condputs("\n") return True elif s0 == "]": self.refer = False self.skip_char() return self.text() elif s0 == ".": self.macro = False self.condputs("\n") return True self.nobody = False s0s1 = self.s[0:2] macro_func = Deroffer.g_macro_dict.get(s0s1, Deroffer.macro_other) if macro_func(self): return True if self.skipheaders and self.nobody: return True self.skip_leading_whitespace() while self.s and not self.is_white(0): self.skip_char() self.skip_leading_whitespace() while True: if not self.quoted_arg() and not self.text_arg(): if self.s: self.condputs(self.str_at(0)) self.skip_char() else: return True def request_or_macro2(self): self.skip_char() s0 = self.s[0:1] if s0 == "\\": if self.str_at(1) == '"': self.condputs("\n") return True else: pass elif s0 == "[": self.refer = True self.condputs("\n") return True elif s0 == "]": self.refer = False self.skip_char() return self.text() elif s0 == ".": self.macro = False self.condputs("\n") return True self.nobody = False s0s1 = self.s[0:2] if s0s1 == "SH": for header_str in [" SYNOPSIS", ' "SYNOPSIS', " ‹BERSICHT", ' "‹BERSICHT']: if self.s[2:].startswith(header_str): self.inheader = True break else: # Did not find a header string self.inheader = False self.nobody = True elif s0s1 in ["SS", "IP", "H "]: self.nobody = True elif s0s1 in ["I ", "IR", "IB", "B ", "BR", "BI", "R ", "RB", "RI", "AB"]: pass elif s0s1 in ["] "]: self.refer = False elif s0s1 in ["PS"]: if self.is_white(2): self.pic = True self.condputs("\n") return True elif s0s1 in ["PE"]: if self.is_white(2): self.pic = False self.condputs("\n") return True elif s0s1 in ["TS"]: if self.is_white(2): self.tbl, self.tblstate = True, self.OPTIONS self.condputs("\n") return True elif s0s1 in ["T&"]: if self.is_white(2): self.tbl, self.tblstate = True, self.FORMAT self.condputs("\n") return True elif s0s1 in ["TE"]: if self.is_white(2): self.tbl = False self.condputs("\n") return True elif s0s1 in ["EQ"]: if self.is_white(2): self.eqn = True self.condputs("\n") return True elif s0s1 in ["EN"]: if self.is_white(2): self.eqn = False self.condputs("\n") return True elif s0s1 in ["R1"]: if self.is_white(2): self.refer2 = True self.condputs("\n") return True elif s0s1 in ["R2"]: if self.is_white(2): self.refer2 = False self.condputs("\n") return True elif s0s1 in ["de"]: macro = True self.condputs("\n") return True elif s0s1 in ["BL", "VL", "AL", "LB", "RL", "ML", "DL"]: if self.is_white(2): self.inlist = True self.condputs("\n") return True elif s0s1 in ["BV"]: if self.str_at(2) == "L" and self.white(self.str_at(3)): self.inlist = True self.condputs("\n") return True elif s0s1 in ["LE"]: if self.is_white(2): self.inlist = False self.condputs("\n") return True elif s0s1 in ["LP", "PP", "P\n"]: self.condputs("\n") return True elif s0s1 in ["ds"]: self.skip_char(2) self.skip_leading_whitespace() if self.str_at(0): # Split at whitespace comps = self.s.split(None, 2) if len(comps) == 2: name, value = comps value = value.rstrip() self.reg_table[name] = value self.condputs("\n") return True elif s0s1 in ["so", "nx"]: # We always ignore include directives # deroff.c for some reason allowed this to fall through to the 'tr' case # I think that was just a bug so I won't replicate it return True elif s0s1 in ["tr"]: self.skip_char(2) self.skip_leading_whitespace() while self.s and self.str_at(0) != "\n": c = self.str_at(0) ns = self.str_at(1) self.skip_char(2) if not ns or ns == "\n": ns = " " self.tr_from += c self.tr_to += ns # Update our table, then swap in the slower tr-savvy condputs try: # Python2 self.tr = string.maketrans(self.tr_from, self.tr_to) except AttributeError: # Python3 self.tr = "".maketrans(self.tr_from, self.tr_to) self.condputs = self.condputs_tr return True elif s0s1 in ["sp"]: self.condputs("\n") return True else: self.condputs("\n") return True if self.skipheaders and self.nobody: return True self.skip_leading_whitespace() while self.s and not self.is_white(0): self.skip_char() self.skip_leading_whitespace() while True: if not self.quoted_arg() and not self.text_arg(): if self.s: self.condputs(self.str_at(0)) self.skip_char() else: return True def do_tbl(self): if self.tblstate == self.OPTIONS: while self.s and self.str_at(0) != ";" and self.str_at(0) != "\n": self.skip_leading_whitespace() if not self.str_at(0).isalpha(): # deroff.c has a bug where it can loop forever here...we try to work around it self.skip_char() else: # Parse option option = self.s arg = "" idx = 0 while option[idx : idx + 1].isalpha(): idx += 1 if option[idx : idx + 1] == "(": option = option[:idx] self.s = self.s[idx + 1 :] arg = self.s else: self.s = "" if arg: idx = arg.find(")") if idx != -1: arg = arg[:idx] self.s = self.s[idx + 1 :] else: # self.skip_char() pass if option.lower() == "tab": self.tblTab = arg[0:1] self.tblstate = self.FORMAT self.condputs("\n") elif self.tblstate == self.FORMAT: while self.s and self.str_at(0) != "." and self.str_at(0) != "\n": self.skip_leading_whitespace() if self.str_at(0): self.skip_char() if self.str_at(0) == ".": self.tblstate = self.DATA self.condputs("\n") elif self.tblstate == self.DATA: if self.tblTab: self.s = self.s.replace(self.tblTab, "\t") self.text() return True def do_line(self): if self.s[0:1] in ".'": if not self.request_or_macro(): return False elif self.tbl: self.do_tbl() else: self.text() return True def deroff(self, str): lines = str.split("\n") for line in lines: self.s = line + "\n" if not self.do_line(): break # self.putchar('\n') def deroff_files(files): for arg in files: sys.stderr.write(arg + "\n") if arg.endswith(".gz"): f = gzip.open(arg, "r") str = f.read() if IS_PY3: str = str.decode("latin-1") else: f = open(arg, "r") str = f.read() d = Deroffer() d.deroff(str) d.flush_output(sys.stdout) f.close() if __name__ == "__main__": import gzip paths = sys.argv[1:] deroff_files(paths) # import cProfile, profile, pstats # profile.run("deroff_files(paths)", "fooprof") # p = pstats.Stats("fooprof") # p.sort_stats("time").print_stats(100) # p.sort_stats('calls').print_callers(.5, 'startswith') clifm-1.26.3/misc/tools/imgprev/000077500000000000000000000000001506632037700164525ustar00rootroot00000000000000clifm-1.26.3/misc/tools/imgprev/README.md000066400000000000000000000317221506632037700177360ustar00rootroot00000000000000# Image previews > Because terminals were built to display text rather than images, making them display images can be problematic. Some solutions work better in some environments than others, but none of them is perfect. ## Table of contents * [Usage](#usage) * [General procedure](#general-procedure) * [Dependencies](#dependencies) * [Troubleshooting](#troubleshooting) ---

Tab completion with image previews

Preview files in full screen (via the view command)

--- ## Usage 1. Run `view edit` (or press F7) to edit [shotgun's](https://github.com/leo-arch/clifm/wiki/Advanced#shotgun) configuration file, and uncomment the following lines from the top of the file: ```sh ... # If the clifmimg script cannot be found under '~/.config/clifm/', you can copy it from the data # directory, usually '/usr/local/share/clifm/plugins/' or '/usr/share/clifm/plugins'. ^text/rtf$|^application/.*(officedocument|msword|ms-excel|ms-powerpoint|opendocument).*=~/.config/clifm/clifmimg doc %f %u; ^application/epub\+zip$=~/.config/clifm/clifmimg epub %f %u; ^application/x-mobipocket-ebook$=~/.config/clifm/clifmimg mobi %f %u; ^application/pdf$=~/.config/clifm/clifmimg pdf %f %u; ^image/vnd.djvu$=~/.config/clifm/clifmimg djvu %f %u; ^image/svg\+xml$=~/.config/clifm/clifmimg svg %f %u; ^image/(jpeg|png|tiff|webp|x-xwindow-dump)$=~/.config/clifm/clifmimg image %f %u; ^image/.*=~/.config/clifm/clifmimg gif %f %u; N:.*\.ora$=~/.config/clifm/clifmimg gif %f %u; N:.*\.(kra|krz)$=~/.config/clifm/clifmimg krita %f %u; ^video/.*|^application/(mxf|x-shockwave-flash|vnd.rn-realmedia)$=~/.config/clifm/clifmimg video %f %u; ^audio/.*=~/.config/clifm/clifmimg audio %f %u; ^application/postscript$=~/.config/clifm/clifmimg postscript %f %u; ^font/.*|^application/(font.*|.*opentype)=~/.config/clifm/clifmimg font %f %u; N:.*\.(cbz|cbr|cbt)$=~/.config/clifm/clifmimg comic %f %u; # Directories ... ``` This instructs **clifm** to use the [clifmimg script](#the-clifmimg-script) to generate previews for the specified file types (both for tab completion (in [fzf mode](https://github.com/leo-arch/clifm/wiki/Specifics#tab-completion)) and via the [`view` command](https://github.com/leo-arch/clifm/wiki/Introduction#view)). Note: In case you don't want image previews for some of these files types, just comment out the corresponding line or change its value to your preferred previewing application. 2. Run **clifm** as usual. > [!NOTE] > If using the [`ueberzug` method](#previewing-methods), you must run **clifm** via the [clifmrun script](https://github.com/leo-arch/clifm/blob/master/misc/tools/imgprev/clifmrun). > You can find this script under `~/.config/clifm/` or `DATADIR/clifm/plugins/` (usually `/usr/local/share/clifm/plugins/` or `/usr/share/clifm/plugins/`). ### Previewing methods The previewing method is controlled by the `method` variable in the [`clifmimg` script](#the-clifmimg-script). By default, this variable is unset, meaning that **clifm** will try to [guess the previewing method](#automatic-method-detection). To manually choose a method, set the `method` variable to any of the available methods: | Method | Description | Observation | Recommended terminal emulator | | -- | -- | --- | --- | | `sixel` | Preview images in full color using the sixel protocol | [**chafa**(1)](https://github.com/hpjansson/chafa) is used to generate sixel images. Note that not all terminal emulators support this protocol. Visit https://www.arewesixelyet.com/ for more information. | XTerm, Wezterm, Mlterm, [st (sixel patch)](https://github.com/bakkeby/st-flexipatch), Contour, Foot | | `ueberzug` | Preview images in full color using [ueberzug](https://github.com/ueber-devel/ueberzug) | Run **clifm** via the `clifmrun` script (see point 2 in the Usage section). | Any (X11 only) | | `kitty` | Preview images in full color using the [kitty image protocol](https://sw.kovidgoyal.net/kitty/graphics-protocol/) | The Kitty terminal is required. | Kitty | | `iterm` | Preview images using the [iTerm2 graphics protocol](https://iterm2.com/documentation-images.html) | | iTerm2, Wezterm | | `ansi` | Preview images using ANSI art (text mode) | Several applications to generate ANSI previews are available: `chafa`, `pixterm`, `img2text`, `viu`, `catimg`, `tiv`, and `timg`. Use the `ansi_method` variable in the [`clifmimg` script](#the-clifmimg-script) to set your preferred application. It defaults to `chafa`. | Any | > [!NOTE] > Since the original `ueberzug` is not maintained anymore, we recommend using this fork instead: https://github.com/ueber-devel/ueberzug. > [!NOTE] > The sixel method works only partially for KDE Konsole: images cannot be cleaned up automatically (see [this bug report](https://bugs.kde.org/show_bug.cgi?id=456354)). [A fix](https://invent.kde.org/utilities/konsole/-/commit/cc4539f6bfd8e5b6beac23ecd13897c666e88eaa) was commited on October 11, 2024, so that the issue might be fixed in the next release. Meanwhile, we recommned using the `ueberzug` method instead. ### Automatic method detection At startup, **clifm** tries to guess the previewing method supported by the running terminal and writes the corresponding value into the **CLIFM_IMG_SUPPORT** environment variable, which is then read by the [clifmimg script](#the-clifmimg-script) to generate previews via the specified method. The procedure is as follows: 1. If **CLIFM_FIFO_UEBERZUG** is set (this vartiable is set by the [clifmrun script](https://github.com/leo-arch/clifm/blob/master/misc/tools/imgprev/clifmrun)), **CLIFM_IMG_SUPPORT** is set to `ueberzug`. 2. If **KITTY_WINDOW_ID** is set, **CLIFM_IMG_SUPPORT** is set to `kitty`. 3. If sixel support is detected1, **CLIFM_IMG_SUPPORT** is set to `sixel`. 4. If **TERM_PROGRAM** is set to `iTerm.app`, **CLIFM_IMG_SUPPORT** is set to `iterm`. 4. Otherwise, **CLIFM_IMG_SUPPORT** is set to `ansi`. Note that if **CLIFM_IMG_SUPPORT** is unset, the `clifmimg` script falls back to the `ansi` method. 1 Note for devs: see the `check_sixel_support()` function in the `term.c` file. > [!NOTE] > If running non-interactively (e.g. as a parameter to other program or through a pipe), **clifm** will not perform the image support checks and will consequently fallback to `ansi`. If you know what kind of image support your terminal provides, set the **CLIFM_IMG_SUPPORT** environment variable to the corresponding value. For example: > ```sh > export CLIFM_IMG_SUPPORT=sixel > ls | fzf --preview 'clifm --preview {}' > ``` > Or you can also set the `$method` variable in the clifmimg script to the desired method, in this case `sixel`. ## General procedure The steps involved in generating image previews are: 1. The `clifmrun` script prepares the environment to generate image previews via `ueberzug` and then launches **clifm**.1 (If not using the [`ueberzug` method](#previewing-methods), this step is ommited). 2. Every time tab completion is invoked for files (if running in [fzf mode](https://github.com/leo-arch/clifm/wiki/Specifics#tab-completion)), or the [view command](https://github.com/leo-arch/clifm/wiki/Introduction#view) is executed, `fzf` is launched. 3. `fzf` calls shotgun (via `clifm --preview`) to generate a preview of the currently hovered file. 4. Shotgun executes `clifmimg`, which takes care of genereting a thumbnail of the corresponding file. 5. Once the thumbnail is generated, `clifmimg` takes care of disaplying the thumbnail via any of the available [previewing methods](#previewing-methods). 1 Parameters passed to `clifmrun` will be passed to **clifm** itself. ### The clifmimg script [This script](https://github.com/leo-arch/clifm/blob/master/misc/tools/imgprev/clifmimg) converts (if necessary) and generates image previews (as thumbnails) for files. For performance reasons, thumbnails are cached (in the directory pointed to by the `CACHE_DIR` variable1) using MD5 hashes as names. The script takes three parameters: the first one tells the type of file to be previewed, the second one is the filename to be previewed, and the third one is the file URI for the filename to be previewed.2 For example: ```sh clifmimg doc %f %u # which expands to something like this: "clifmimg doc /path/to/file.docx file:///path/to/file.docx" ``` generates a thumbnail of `file.docx` using the `doc` method. The first parameter (thumbnailing method) can be any of the following: | Method | Description | Thumbnail generation | | --- | --- | --- | | `image` | Display image directly, without previous convertion | No | | `gif`, `svg`, `krita` | Convert image and display | Yes | | `audio`, `djvu`, `doc`, `epub`, `font`, `mobi`, `pdf`, `postscript`, and `video` | Convert file to image and display | Yes | The `audio` method accepts four modes: `cover`, `wave`, `spectogram`, and `info`. Set the desired mode via the `audio_method` variable (defaults to `cover`, which falls back to `info` if there is no cover image available). > [!TIP] > When changing the `audio` mode, thumbnails for already thumbnailed files will not be regenerated according to the newly set mode. You need to delete the corresponding thumbnails and purge the thumbnails database. Running this in **clifm** should be enough: > ```sh > cd ~/.cache/clifm/thumbnails > rm $(grep -E ".*\.(mp3|ogg|wav)" .thumbs.info | cut -d'@' -f1) > view purge > ``` > Add whatever audio extensions you deem necessary. > 1 By default this directory is `$XDG_CACHE_HOME/clifm/thumbnails` (which usually expands to `~/.cache/clifm/thumbnails`). Note that previous versions of this script used `$XDG_CACHE_HOME/clifm/previews` instead. 2 The third parameter (`%u`) is available since version 1.22.13. Prior to this version, only the first two parameters are recognized. ### The thumbnails database Every time a thumbnail is generated `clifmimg` adds a new entry to the thumbnails database (`.thumbs.info` in the thumbnails directory1). Each entry has this form: **THUMB@PATH**, where **THUMB** is the name of the thumbnail file (an MD5 hash of **PATH** followed by a file extension, either `png` or `jpg`), and **PATH** the file URI for the absolute path to the original file. This database is read by the [`view purge`](https://github.com/leo-arch/clifm/wiki/Introduction#view) command (available since 1.22.12) to keep the thumbnails directory in a clean state.1 1 If running a version prior to 1.22.12, make sure to update your [`clifmimg` script](https://github.com/leo-arch/clifm/blob/master/misc/tools/imgprev/clifmimg): `cp /usr/share/clifm/plugins/clifmimg ~/.config/clifm`. ## Dependencies The following applications are used to generate thumbnails: | Application | File type | Observation | | --- | --- | --- | | `ffmpegthumbnailer` | Video | | | `gnome-epub-thumbnailer` | ePub | | | `gnome-mobi-thumbnailer` | Mobi | | | `pdftoppm` | PDF | Provided by the `poppler` package | | `ddjvu` | DjVu | Provided by the `djvulibre` package | | `ffmpeg` | Audio | | | `fontpreview` | Font | https://github.com/sdushantha/fontpreview | | `libreoffice` | Office documents | | | `librsvg` | SVG image | Required by **magick**(1) to convert SVG files | | | `gs` | Postscript | Provided by the `ghostscript` package | | `magick` | Several image formats | Provided by the `imagemagick` package | | `unzip` | Krita images | | > [!NOTE] > The exact package names providing the above programs may vary depending on your OS/distribution, but they usually have the same name as the corresponding program. ## Troubleshooting ### Image previews are misplaced (ueberzug) This is mostly the case when your terminal emulator is using a menu bar and/or a scrollbar. `Konsole`, for example, displays by default a menu bar and a main toolbar on the top of the window, plus a scrollbar on the right, which is the cause of the image misplacement. To fix this, tweak the `$X` and `$Y` variables in the `display()` function of the [`clifmimg` script](https://github.com/leo-arch/clifm/blob/master/misc/tools/imgprev/clifmimg) as follows: ```sh X=$((CLIFM_TERM_COLUMNS - FZF_PREVIEW_COLUMNS - 1)) # 1 extra column: the scroll bar Y=$((CLIFM_FZF_LINE + 2)) # 2 extra lines: menu bar and main toolbar ``` If the issue persists, bear in mind that **clifm** uses the `CPR` (cursor position report) [escape code](https://www.xfree86.org/current/ctlseqs.html) to get the current position of the cursor on the screen (which then is passed to the `clifmimg` script to generate the preview). If your terminal does not support `CPR` (most do), you are out of look: just try another terminal. ### Image previews are too big (or too small) Go to the beginning of the `display()` function and play around with the variables controlling image dimensions: `$C` (for columns) and `$L` (for lines). For example, to reduce these values two points each: ```sh C="$((C - 2))" L="$((L - 2))" ``` clifm-1.26.3/misc/tools/imgprev/clifmimg000077500000000000000000000370431506632037700201760ustar00rootroot00000000000000#!/bin/sh # clifmimg # Version: 1.4 # Based on https://github.com/cirala/vifmimg, licensed GPL-3.0 # All changes are licensed GPL-2.0+ # Author: L. Abramovich ###################### # DESCRIPTION ###################### # # Convert (if necessary) and generate previews (as thumbnails) for files. # Thumbnails are cached (in $CACHE_DIR) using file name hashes as names. # # The first parameter is the file type to be previewed. Supported types: # image (direct image display) # gif, svg, krita (image format convertion and display) # video, epub, mobi, djvu, pdf, doc, audio, font, and postscript (convertion to image and display) # # The second parameter is the file name to be previewed. # # The third parameter (optional) is the file URI for the file to be previewed. # If unset, the second parameter (the unenconded file name) is used instead. # # Each time a thumbnail is generated, a line is added to $THUMBINFO_FILE with # this format: THUMB@PATH, where THUMB is the name of the thumbnail (an MD5 hash # of PATH followed by a file extension, either jpg or png), and PATH is the # absolute canonical URI for the original file. ###################### # USAGE ###################### # # This script is intended to be used by shotgun, Clifm's built-in previewer, # to generate and display image previews for several file types. # Follow these steps to enable it: # # 1) Edit shotgun's config file (via F7 or "view edit") and uncomment the "clifmimg" # lines at the top of the file (this instructs Clifm to use this this script to generate # previews for the specified file types). # # 2) If using the ueberzug method (see DEFAULT OPTIONS below) run clifm via the # 'clifmrun' script. Otherwise, run clifm as usual. # # NOTE: clifmrun can be found under ~/.config/clifm/ (or /usr/share/clifm/plugins/). ###################### # DEPENDENCIES ###################### # # ueberzug (optional) # kitty terminal (optional) # sixel capable terminal (optional) # iTerm2 terminal (optional) # md5sum/md5 (generate filename hashes) # # The following applications are used to generate thumbnails: # # ffmpegthumbnailer (Video files) # gnome-epub-thumbnailer (ePub files) # gnome-mobi-thumbnailer (Mobi files) # pdftoppm (PDF files - provided by the poppler package) # ffmpeg (Audio files) # fontpreview (Font files) # libreoffice (Office files: odt, docx, xlsx, etc) # ddjvu (DjVu files - provided by the djvulibre package) # librsvg (SVG images) # gs (Postscript files - provided by the ghostscript package) # magick (image format convertion - provided by the imagemagick package) # unzip (Krita image files) # # NOTE: The exact package names providing these programs may vary depending # on your OS/distribution, but ususally they have the same name as the program. #----------------------------- # 1. COMMAND LINE PARAMETERS #----------------------------- type="$1" file="$2" file_URI="${3:-$file}" # FOR FUTURE REFERENCE # $type can be used for multiple MIME types. For example: # # ^image/.*$=~/.config/clifm/clifmimg gif %f %u; # # Here we use the same converting function ('gif') for all subtypes of the type "image". # But we might need (not currently the case though) a different treatement depending # on the subtype (say "bmp", "heif", or whatever). Here's where having the corresponding # MIME type can come in handy. # # NOTE: Make sure to pass the MIME type to this script by adding '%m' to the # corresponding line in the 'preview.clifm' config file. For example: # # ^image/.*$=~/.config/clifm/clifmimg gif %f %u %m; # #mime_type="${4:-unknown}" #----------------------------- # 2. DEFAULT OPTIONS #----------------------------- # Set the method used to generate image previews. # Available methods: sixel, iterm, ueberzug, kitty, ansi (text mode). # # NOTE 1: To use the ueberzug method, run Clifm via the clifmrun script. # NOTE 2: To generate sixel images we use chafa(1). # # If unset, we'll make our best guess. method="" # Set the application used to generate ANSI image previews. # Available applications: chafa, pixterm, img2txt, viu, catimg, tiv, timg ansi_method="chafa" # Set the method used to generate audio previews (cover, wave, spectogram, info). # Defaults to 'cover', which falls back to 'info' if there is no attached image. audio_method="cover" # The maximum size for a thumbnail is, according to the Freedesktop specification # (https://specifications.freedesktop.org/thumbnail-spec/latest/creation.html), # 1024x1024. However, since we display thumbnails in a preview window, sometimes # using half of the screen, we need a higher resolution. DEFAULT_SIZE="1920x1080" # According to the Freedesktop specification, thumbnails should be in PNG format. # However, some of the convertions below, mostly for PDF files, generate truncated # images when converting to PNG (while quickly scrolling through the preview window). # This is why, for the time being, we stick to JPG. THUMB_FORMAT="jpg" # Because of the above observations, we cannot use any of the thumbnails directories # specificied by the Freedesktop specification, but a custom one. CACHE_DIR="$CLIFM_THUMBNAILS_DIR" [ -z "$CACHE_DIR" ] && CACHE_DIR="${XDG_CACHE_HOME:-$HOME/.cache}/clifm/thumbnails" CACHEDIRTAG_FILE="$CACHE_DIR/CACHEDIR.TAG" CACHEDIRTAG_HEADER="Signature: 8a477f597d28d172789f06886806bc55 # This file is a cache directory tag created by Clifm. # For information about cache directory tags, see: # http://www.brynosaurus.com/cachedir/" # This file contains information about generated thumbnails: for the time being, # only the path to the original file (as a file URI). THUMBINFO_FILE="$CACHE_DIR/${CLIFM_THUMBINFO_FILE:-.thumbs.info}" #----------------------------- # 3. SOME AUXILIARY FUNCTIONS #----------------------------- get_preview_method() { if [ -z "$method" ]; then method="$CLIFM_IMG_SUPPORT" [ -z "$method" ] && method="ansi" fi } hash_file() { ! [ -d "$CACHE_DIR" ] && mkdir -p "$CACHE_DIR" ! [ -f "$CACHEDIRTAG_FILE" ] && echo "$CACHEDIRTAG_HEADER" > "$CACHEDIRTAG_FILE" if type md5sum > /dev/null 2>&1; then tmp="$(printf "%s" "$1" | md5sum)" PCACHE="$CACHE_DIR/${tmp%% *}" elif type md5 > /dev/null 2>&1; then PCACHE="$CACHE_DIR/$(md5 -q -s "$1")" else printf "clifm: No hashing application found.\nEither md5sum or md5 \ is required.\n" >&2 exit 1 fi } print_err_msg() { case "$2" in 127) if [ "$3" = "sixel" ]; then echo "${1}: Command not found (required to display sixel images)" else echo "${1}: Command not found (required to generate previews for '${3}' files)" fi ;; *) echo "${1}: Error generating preview (code: ${2})" # The thumbnail exists, but cannot be displayed. Possibly truncated. Regenerate it. [ -f "${PCACHE}.$THUMB_FORMAT" ] && rm -f -- "${PCACHE}.$THUMB_FORMAT" > /dev/null 2>&1 ;; esac return 1 } add_to_info_file() { echo "${1##*/}@$file_URI" >> "$THUMBINFO_FILE" return 0 } #----------------------------- # 4. DISPLAY IMAGES #----------------------------- display() { [ -z "$1" ] && exit 1 if [ -n "$FZF_PREVIEW_LINES" ]; then C=$((FZF_PREVIEW_COLUMNS - 2)) L=$FZF_PREVIEW_LINES else [ -z $COLUMNS ] && COLUMNS="$(tput cols)" [ -z $LINES ] && LINES="$(tput lines)" C=$COLUMNS L=$LINES fi if [ -z "$CLIFM_FZF_LINE" ]; then CLIFM_FZF_LINE=0 CLIFM_TERM_COLUMNS=$COLUMNS fi X=$((CLIFM_TERM_COLUMNS - FZF_PREVIEW_COLUMNS)) Y=$CLIFM_FZF_LINE case "$method" in sixel) chafa -f sixel --view-size "${C}x${L}" "$1" 2>/dev/null && return 0 # img2sixel -w auto -h "$(((L - 1) * 16))" "$1" && return 0 # timg -ps -g "${C}x$((L - 1))" "$1" && return 0 # magick "$1" -dither FloydSteinberg -size ${C}x$((L - 1)) sixel:- 2>/dev/null && return 0 print_err_msg "chafa" "$?" "sixel" ;; iterm) chafa -f iterm --view-size "${C}x${L}" "$1" 2>/dev/null && return 0 print_err_msg "chafa" "$?" "iterm" ;; kitty) kitty icat --loop=0 --place "${C}x$((L - 1))@${X}x${Y}" \ --clear --transfer-mode=memory --unicode-placeholder --stdin=no --align=left "$1" ;; ueberzug) if [ -z "$CLIFM_FIFO_UEBERZUG" ]; then echo "To enable ueberzug previews run clifm via clifmrun" exit 0 fi printf '{"action": "add", "identifier": "clifm-preview", "x": "%s", "y": "%s", "width": "%s", "height": "%s", "scaler" : "contain", "path": "%s"}\n' "$((X - 1))" "$Y" "$COLUMNS" "$((LINES - 1))" "$1" > "$CLIFM_FIFO_UEBERZUG" ;; ansi) case "$ansi_method" in chafa) chafa --view-size "${C}x${L}" "$1" ;; pixterm) pixterm -s 2 -tc "$C" -tr "$L" "$1" ;; img2txt) img2txt -H"$L" -W"$C" "$1" ;; viu) viu -b -h"$L" -w"$C" "$1" ;; catimg) catimg -H"$L" "$1" ;; tiv) tiv -h "$L" -w "$C" "$1" ;; timg) timg -g "${C}x${L}" "$1" ;; esac ;; esac } #----------------------------- # 5. THUMBNAILS GENERATION #----------------------------- gen_audio_preview() { case "$audio_method" in ""|cover) ffmpeg -y -hide_banner -loglevel quiet -i "$1" "$2" && \ add_to_info_file "$2" && return 0 audio_err="$?" if [ "$audio_err" -eq 234 ]; then file -b "$1" 2>/dev/null; return 1 # No image found. Just print file info. fi print_err_msg "ffmpeg" "$audio_err" "audio (cover)" ;; wave) ffmpeg -y -hide_banner -loglevel quiet -i "$1" -f lavfi -i color=c=black:s=640x320 \ -filter_complex "[0:a]showwavespic=s=640x320:colors=white[fg];[1:v][fg]overlay=format=auto" \ -frames:v 1 "$2" && add_to_info_file "$2" && return 0 print_err_msg "ffmpeg" "$?" "audio (wave)" ;; spectogram) ffmpeg -y -hide_banner -loglevel quiet -i "$1" -lavfi "showspectrumpic=s=640x320" -frames:v 1 "$2" \ && add_to_info_file "$2" && return 0 print_err_msg "ffmpeg" "$?" "audio (spectogram)" ;; *) file -b "$1" 2>/dev/null ;; esac } gen_comic_preview() { comicthumb "$1" "$2" "${DEFAULT_SIZE%%x*}" >/dev/null 2>&1 && \ add_to_info_file "$2" && return 0 print_err_msg "comicthumb" "$?" "comic" } gen_djvu_preview() { ddjvu -format=tiff -quality=90 -page=1 -size "$DEFAULT_SIZE" "$1" "$2" >/dev/null 2>&1 && \ add_to_info_file "$2" && return 0 print_err_msg "ddjvu" "$?" "djvu" } gen_doc_preview() { format="$THUMB_FORMAT" if libreoffice --headless --convert-to "$format" "$1" \ --outdir "$CACHE_DIR" >/dev/null 2>&1; then f="${1##*/}" mv "$CACHE_DIR/${f%.*}.$format" "${2}.$format" && \ add_to_info_file "${2}.$format" && return 0 print_err_msg "mv (libreoffice)" "$?" "doc" else print_err_msg "libreoffice" "$?" "doc" fi } gen_epub_preview() { gnome-epub-thumbnailer -s "${DEFAULT_SIZE%%x*}" "$1" "$2" >/dev/null 2>&1 && \ add_to_info_file "$2" && return 0 print_err_msg "gnome-epub-thumbnailer" "$?" "epub" # epub-thumbnailer "$1" "$2" "${DEFAULT_SIZE%%x*}" >/dev/null 2>&1 && \ # add_to_info_file "$2" && return 0 # print_err_msg "epub-thumbnailer" "$?" "epub" } gen_font_preview() { fontpreview -i "$1" -o "$2" >/dev/null 2>&1 && \ add_to_info_file "$2" && return 0 print_err_msg "fontpreview" "$?" "font" } # This function converts image files that cannot be displayed directly (like gif, bmp, # heif, and so on). For the list of formats supported by imagemagick run 'magick -list format'. gen_gif_preview() { magick -define bmp:ignore-filesize=true "$1"[0] -resize "$DEFAULT_SIZE"\> "$2" >/dev/null 2>&1 && \ add_to_info_file "$2" && return 0 print_err_msg "magick" "$?" "image" } # At least up to 7.1.1, magick(1) does not support Krita files. Once it does, this function # can be removed. Issue open since 2019: https://github.com/ImageMagick/ImageMagick/issues/1547 # For the krita format see https://docs.krita.org/en/general_concepts/file_formats/file_kra.html gen_krita_preview() { TMP_DIR="${TMPDIR:-/tmp}/clifm-$USER" ! [ -d "$TMP_DIR" ] && mkdir -p "$TMP_DIR" unzip -oq "$1" "*.png" -d "$TMP_DIR" >/dev/null 2>&1 ret="$?" if [ "$ret" -ne 0 ]; then print_err_msg "unzip" "$ret" "krita" return 1 fi IMG="mergedimage.png" ! [ -f "${TMP_DIR}/$IMG" ] && IMG="preview.png" magick "${TMP_DIR}/$IMG" -resize "$DEFAULT_SIZE"\> "$2" >/dev/null 2>&1 ret="$?" rm -rf -- "${TMP_DIR}/mergedimage.png" "${TMP_DIR}/preview.png" >/dev/null 2>&1 if [ "$ret" -ne 0 ]; then print_err_msg "magick" "$ret" "krita" else add_to_info_file "$2" fi } gen_mobi_preview() { gnome-mobi-thumbnailer -s "${DEFAULT_SIZE%%x*}" "$1" "$2" >/dev/null 2>&1 && \ add_to_info_file "$2" && return 0 print_err_msg "gnome-mobi-thumbnailer" "$?" "mobi" } gen_pdf_preview() { pdftoppm -jpeg -f 1 -singlefile -scale-to "${DEFAULT_SIZE%%x*}" "$1" "$2" >/dev/null 2>&1 && \ add_to_info_file "${2}.$THUMB_FORMAT" && return 0 print_err_msg "pdftoppm" "$?" "pdf" } gen_postscript_preview() { gs -sDEVICE=jpeggray -dNOPAUSE -dBATCH -dSAFER -q -r300 -dFirstPage=1 -dLastPage=1 \ -sOutputFile="$2" "$1" >/dev/null 2>&1 && \ add_to_info_file "$2" && return 0 print_err_msg "gs (ghostscript)" "$?" "postscript" } gen_svg_preview() { magick -background none -size "$DEFAULT_SIZE" "$1" "$2" >/dev/null 2>&1 \ && add_to_info_file "$2" && return 0 print_err_msg "magick (librsvg)" "$?" "svg" } gen_video_preview() { ffmpegthumbnailer -i "$1" -o "$2" -s "${DEFAULT_SIZE%%x*}" -q 5 >/dev/null 2>&1 && \ add_to_info_file "$2" && return 0 print_err_msg "ffmpegthumbnailer" "$?" "video" } #----------------------------- # 6. MAIN #----------------------------- main() { # Set the $method variable, required by the display() function to display # images according to $method. get_preview_method if [ "$type" = "image" ]; then display "$file" exit 0 fi # Set the $PCACHE variable to the file's URI hash, used by the thumbnail # generation functions to uniquely identify files. hash_file "$file_URI" # If the thumbnail already exists, display it. Otherwise, generate it and # display it. case "$type" in "audio") if [ -f "${PCACHE}.$THUMB_FORMAT" ] || gen_audio_preview "$file" "${PCACHE}.$THUMB_FORMAT"; then display "${PCACHE}.$THUMB_FORMAT" fi ;; "comic") if [ -f "${PCACHE}.$THUMB_FORMAT" ] || gen_comic_preview "$file" "${PCACHE}.$THUMB_FORMAT"; then display "${PCACHE}.$THUMB_FORMAT" fi ;; "djvu") if [ -f "${PCACHE}.$THUMB_FORMAT" ] || gen_djvu_preview "$file" "${PCACHE}.$THUMB_FORMAT"; then display "${PCACHE}.$THUMB_FORMAT" fi ;; "doc") if [ -f "${PCACHE}.$THUMB_FORMAT" ] || gen_doc_preview "$file" "$PCACHE"; then display "${PCACHE}.$THUMB_FORMAT" fi ;; "epub") if [ -f "${PCACHE}.$THUMB_FORMAT" ] || gen_epub_preview "$file" "${PCACHE}.$THUMB_FORMAT"; then display "${PCACHE}.$THUMB_FORMAT" fi ;; "font") if [ -f "${PCACHE}.$THUMB_FORMAT" ] || gen_font_preview "$file" "${PCACHE}.$THUMB_FORMAT"; then display "${PCACHE}.$THUMB_FORMAT" fi ;; "gif") if [ -f "${PCACHE}.$THUMB_FORMAT" ] || gen_gif_preview "$file" "${PCACHE}.$THUMB_FORMAT"; then display "${PCACHE}.$THUMB_FORMAT" fi ;; "krita") if [ -f "${PCACHE}.$THUMB_FORMAT" ] || gen_krita_preview "$file" "${PCACHE}.$THUMB_FORMAT"; then display "${PCACHE}.$THUMB_FORMAT" fi ;; "mobi") if [ -f "${PCACHE}.$THUMB_FORMAT" ] || gen_mobi_preview "$file" "${PCACHE}.$THUMB_FORMAT"; then display "${PCACHE}.$THUMB_FORMAT" fi ;; "pdf") if [ -f "${PCACHE}.$THUMB_FORMAT" ] || gen_pdf_preview "$file" "$PCACHE"; then display "${PCACHE}.$THUMB_FORMAT" fi ;; "postscript") if [ -f "${PCACHE}.$THUMB_FORMAT" ] || gen_postscript_preview "$file" "${PCACHE}.$THUMB_FORMAT"; then display "${PCACHE}.$THUMB_FORMAT" fi ;; "svg") if [ -f "${PCACHE}.$THUMB_FORMAT" ] || gen_svg_preview "$file" "${PCACHE}.$THUMB_FORMAT"; then display "${PCACHE}.$THUMB_FORMAT" fi ;; "video") if [ -f "${PCACHE}.$THUMB_FORMAT" ] || gen_video_preview "$file" "${PCACHE}.$THUMB_FORMAT"; then display "${PCACHE}.$THUMB_FORMAT" fi ;; esac } main "$@" clifm-1.26.3/misc/tools/imgprev/clifmrun000077500000000000000000000044531506632037700202250ustar00rootroot00000000000000#!/bin/sh # Based on https://github.com/cirala/vifmimg, licensed under GPL-3.0 # All changes are licensed under GPL-2.0+ # Authors: cirala, L. Abramovich ################### # DESCRIPTION ################### # # Prepare the environment to generate image previews via ueberzug and then launch # Clifm. # The values set here are used by Clifm to display images via the 'clifmimg' script. # Consult this script itself ('~/.config/clifm/clifmimg') for instructions on how to # set up Clifm to generate image previews. # # Previews for tab completion (in fzf mode) are enabled by default. In any case, # check the FzfPreview option in Clifm's main configuration file (run 'config' or # press F10). ################### # DEPENDENCIES ################### # # Ueberzug # # NOTE: Ueberzug needs to run on a graphical environment. Wayland is not supported. # # NOTE 2: Since the original ueberzug is unmaintained, we recommend using this fork # instead: https://github.com/ueber-devel/ueberzug # ueberzug_cleanup() { rm -f -- "$CLIFM_FIFO_UEBERZUG" 2>/dev/null pkill -P $$ >/dev/null } # Prior to ueberzug 18.2.0, we need to silence stderr to avoid printing # garbage on the screen silence_stderr() { str="$(ueberzug version)" major="$(echo "$str" | cut -d'.' -f1)" minor="$(echo "$str" | cut -d'.' -f2)" if [ "$major" -lt 18 ]; then true elif [ "$major" -gt 18 ]; then false elif [ "$minor" -ge 2 ]; then false else true fi } init_ueberzug() { CACHE_DIR="${XDG_CACHE_HOME:-$HOME/.cache}/clifm" PREVIEW_DIR="$CACHE_DIR/previews" ! [ -d "$PREVIEW_DIR" ] && mkdir -p "$PREVIEW_DIR" export CLIFM_FIFO_UEBERZUG="$CACHE_DIR/ueberzug-${$}" mkfifo "$CLIFM_FIFO_UEBERZUG" if silence_stderr; then tail -f "$CLIFM_FIFO_UEBERZUG" | ueberzug layer --silent --parser json > /dev/null 2>&1 & else tail -f "$CLIFM_FIFO_UEBERZUG" | ueberzug layer --silent --parser json & fi } if ! type clifm > /dev/null 2>&1; then printf "clifm: Command not found\n" >&2 exit 127 elif ! type ueberzug >/dev/null 2>&1; then printf "ueberzug: Command not found\n" >&2 exit 127 elif [ -z "$DISPLAY" ] || [ -n "$WAYLAND_DISPLAY" ]; then printf "clifm: Not running on X\n" >&2 exit 1 else trap ueberzug_cleanup EXIT init_ueberzug clifm "$@" printf '{"action": "remove", "identifier": "clifm-preview"}\n' > "$CLIFM_FIFO_UEBERZUG" fi clifm-1.26.3/misc/tools/manpages_comp_gen.py000077500000000000000000001214451506632037700210270ustar00rootroot00000000000000#!/usr/bin/python3 # -*- coding: utf-8 -*- # This file is part of CliFM # Taken from https://github.com/fish-shell/fish-shell/blob/master/share/tools/create_manpage_completions.py # and modified to fit our needs: # 1. Added the ability to generate completion files for single program names instead # of just full man page paths # 2. Modified default destination dir and completion files extension # 3. Commented out some fields in the output (see output_complete_command()) # Run me like this: ./create_manpage_completions.py /usr/share/man/man{1,8}/* # Completions for all available manpages will be created in ~/.local/share/clifm/completions # To create completions for just specific programs: # ./create_manpage_completion.py -k NAME NAME ... # Example: # ./create_manpage_completion.py -k ls which vim # The -k switch prevents the removal of previously generated completion files # Program names having no man page will be ignored """ = Siteshwar Vashisht = 2012 Copyright (c) 2012, Siteshwar Vashisht All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. """ from __future__ import print_function from deroff import Deroffer import argparse import bz2 import codecs import errno import glob import gzip import os import re import string import subprocess import sys import traceback lzma_available = True try: try: import lzma except ImportError: from backports import lzma except ImportError: lzma_available = False try: from subprocess import DEVNULL except ImportError: DEVNULL = open(os.devnull, "wb") # Destination dir suffix (will be appended to XDG_DATA_HOME) DEST_DIR_SUFFIX = "/clifm/completions" # Generated completion files will have this extension COMP_EXT = ".clifm" # Whether we're Python 3 IS_PY3 = sys.version_info[0] >= 3 # This gets set to the name of the command that we are currently executing CMDNAME = "" # Information used to track which of our parsers were successful PARSER_INFO = {} # built_command writes into this global variable, yuck built_command_output = [] # Diagnostic output diagnostic_output = [] diagnostic_indent = 0 # Three diagnostic verbosity levels VERY_VERBOSE, BRIEF_VERBOSE, NOT_VERBOSE = 2, 1, 0 # Pick some reasonable default values for settings VERBOSITY, WRITE_TO_STDOUT, DEROFF_ONLY, KEEP_FILES = NOT_VERBOSE, False, False, False def add_diagnostic(dgn, msg_verbosity=VERY_VERBOSE): # Add a diagnostic message, if msg_verbosity <= VERBOSITY if msg_verbosity <= VERBOSITY: diagnostic_output.append(" " * diagnostic_indent + dgn) def flush_diagnostics(where): if diagnostic_output: output_str = "\n".join(diagnostic_output) print(output_str, file=where) diagnostic_output[:] = [] # Make sure we don't output the same completion multiple times, which can happen # For example, xsubpp.1.gz and xsubpp5.10.1.gz # This maps commands to lists of completions already_output_completions = {} def compile_and_search(regex, input): options_section_regex = re.compile(regex, re.DOTALL) options_section_matched = re.search(options_section_regex, input) return options_section_matched def unquote_double_quotes(data): if len(data) < 2: return data if data[0] == '"' and data[len(data) - 1] == '"': data = data[1 : len(data) - 1] return data def unquote_single_quotes(data): if len(data) < 2: return data if data[0] == "`" and data[len(data) - 1] == "'": data = data[1 : len(data) - 1] return data # Make a string of characters that are deemed safe without needing to be escaped # Note that space is not included g_safe_chars = frozenset(string.ascii_letters + string.digits + "_+-|/:=@~") def escape_single_quote(str): # Escape a string if necessary so that it can be put in single quotes # If it has no non-safe chars, there's nothing to do if g_safe_chars.issuperset(str): return str str = str.replace("\\", "\\\\") # Replace one backslash with two str = str.replace( "'", "\\'" ) # Replace one single quote with a backslash-single-quote return "'" + str + "'" # Make a string Unicode by attempting to decode it as latin-1, or UTF8. See #658 def lossy_unicode(s): # All strings are unicode in Python 3 if IS_PY3 or isinstance(s, unicode): return s try: return s.decode("latin-1") except UnicodeEncodeError: pass try: return s.decode("utf-8") except UnicodeEncodeError: pass return s.decode("latin-1", "ignore") def output_complete_command(cmdname, args, description, output_list): # comps = ["complete -c", cmdname] comps = [cmdname] comps.extend(args) # if description: # comps.append("-d") # comps.append(description) output_list.append(lossy_unicode(" ").join([lossy_unicode(c) for c in comps])) def built_command(options, description): # print "Options are: ", options man_optionlist = re.split(' |,|"|=|[|]', options) prog_options = [] for optionstr in man_optionlist: option = re.sub(r"(\[.*\])", "", optionstr) option = option.strip(" \t\r\n[](){}.,:!") # Skip some problematic cases if option in ["-", "--"]: continue if any(c in "{}()" for c in option): continue if option.startswith("--"): # New style long option (--recursive) prog_options.append("-l " + escape_single_quote(option[2:])) elif option.startswith("-") and len(option) == 2: # New style short option (-r) prog_options.append("-s " + escape_single_quote(option[1:])) elif option.startswith("-") and len(option) > 2: # Old style long option (-recursive) prog_options.append("-o " + escape_single_quote(option[1:])) # Determine which options are new (not already in existing_options) # Then add those to the existing options existing_options = already_output_completions.setdefault(CMDNAME, set()) prog_options = [opt for opt in prog_options if opt not in existing_options] existing_options.update(prog_options) # Maybe it's all for naught if not prog_options: return # Here's what we'll use to truncate if necessary max_description_width = 78 if IS_PY3: truncation_suffix = "…" else: ELLIPSIS_CODE_POINT = 0x2026 truncation_suffix = unichr(ELLIPSIS_CODE_POINT) # Try to include as many whole sentences as will fit # Clean up some probably bogus escapes in the process clean_desc = description.replace("\\'", "'").replace("\\.", ".") sentences = clean_desc.split(".") # Clean up "sentences" that are just whitespace # But don't let it be empty sentences = [x for x in sentences if x.strip()] if not sentences: sentences = [""] udot = lossy_unicode(".") uspace = lossy_unicode(" ") truncated_description = lossy_unicode(sentences[0]) + udot for line in sentences[1:]: if not line: continue proposed_description = ( lossy_unicode(truncated_description) + uspace + lossy_unicode(line) + udot ) if len(proposed_description) <= max_description_width: # It fits truncated_description = proposed_description else: # No fit break # Strip trailing dots truncated_description = truncated_description.strip(udot) # If the first sentence does not fit, truncate if necessary if len(truncated_description) > max_description_width: prefix_len = max_description_width - len(truncation_suffix) truncated_description = truncated_description[:prefix_len] + truncation_suffix # Escape some more things truncated_description = escape_single_quote(truncated_description) escaped_cmd = escape_single_quote(CMDNAME) output_complete_command( escaped_cmd, prog_options, truncated_description, built_command_output ) def remove_groff_formatting(data): data = data.replace("\\fI", "") data = data.replace("\\fP", "") data = data.replace("\\f1", "") data = data.replace("\\fB", "") data = data.replace("\\fR", "") data = data.replace("\\e", "") data = re.sub(".PD( \d+)", "", data) data = data.replace(".BI", "") data = data.replace(".BR", "") data = data.replace("0.5i", "") data = data.replace(".rb", "") data = data.replace("\\^", "") data = data.replace("{ ", "") data = data.replace(" }", "") data = data.replace("\ ", "") data = data.replace("\-", "-") data = data.replace("\&", "") data = data.replace(".B", "") data = data.replace("\-", "-") data = data.replace(".I", "") data = data.replace("\f", "") data = data.replace("\(cq", "'") return data class ManParser(object): def is_my_type(self, manpage): return False def parse_man_page(self, manpage): return False class Type1ManParser(ManParser): def is_my_type(self, manpage): return compile_and_search('\.SH "OPTIONS"(.*?)', manpage) is not None def parse_man_page(self, manpage): options_section_regex = re.compile('\.SH "OPTIONS"(.*?)(\.SH|\Z)', re.DOTALL) options_section = re.search(options_section_regex, manpage).group(1) options_parts_regex = re.compile("\.PP(.*?)\.RE", re.DOTALL) options_matched = re.search(options_parts_regex, options_section) add_diagnostic("Command is %r" % CMDNAME) if options_matched is None: add_diagnostic("Unable to find options") if self.fallback(options_section): return True elif self.fallback2(options_section): return True return False while options_matched is not None: data = options_matched.group(1) last_dotpp_index = data.rfind(".PP") if last_dotpp_index != -1: data = data[last_dotpp_index + 3 :] data = remove_groff_formatting(data) data = data.split(".RS 4") if len(data) > 1: # and len(data[1]) <= 300): optionName = data[0].strip() if optionName.find("-") == -1: add_diagnostic("%r doesn't contain '-' " % optionName) else: optionName = unquote_double_quotes(optionName) optionName = unquote_single_quotes(optionName) optionDescription = data[1].strip().replace("\n", " ") built_command(optionName, optionDescription) else: add_diagnostic("Unable to split option from description") return False options_section = options_section[options_matched.end() - 3 :] options_matched = re.search(options_parts_regex, options_section) def fallback(self, options_section): add_diagnostic("Trying fallback") options_parts_regex = re.compile("\.TP( \d+)?(.*?)\.TP", re.DOTALL) options_matched = re.search(options_parts_regex, options_section) if options_matched is None: add_diagnostic("Still not found") return False while options_matched is not None: data = options_matched.group(2) data = remove_groff_formatting(data) data = data.strip() data = data.split("\n", 1) if len(data) > 1 and len(data[1].strip()) > 0: # and len(data[1])<400): optionName = data[0].strip() if optionName.find("-") == -1: add_diagnostic("%r doesn't contain '-'" % optionName) else: optionName = unquote_double_quotes(optionName) optionName = unquote_single_quotes(optionName) optionDescription = data[1].strip().replace("\n", " ") built_command(optionName, optionDescription) else: add_diagnostic("Unable to split option from description") return False options_section = options_section[options_matched.end() - 3 :] options_matched = re.search(options_parts_regex, options_section) return True def fallback2(self, options_section): add_diagnostic("Trying last chance fallback") ix_remover_regex = re.compile("\.IX.*") trailing_num_regex = re.compile("\\d+$") options_parts_regex = re.compile("\.IP (.*?)\.IP", re.DOTALL) options_section = re.sub(ix_remover_regex, "", options_section) options_matched = re.search(options_parts_regex, options_section) if options_matched is None: add_diagnostic("Still (still!) not found") return False while options_matched is not None: data = options_matched.group(1) data = remove_groff_formatting(data) data = data.strip() data = data.split("\n", 1) if len(data) > 1 and len(data[1].strip()) > 0: # and len(data[1])<400): optionName = re.sub(trailing_num_regex, "", data[0].strip()) if "-" not in optionName: add_diagnostic("%r doesn't contain '-'" % optionName) else: optionName = optionName.strip() optionName = unquote_double_quotes(optionName) optionName = unquote_single_quotes(optionName) optionDescription = data[1].strip().replace("\n", " ") built_command(optionName, optionDescription) else: add_diagnostic("Unable to split option from description") return False options_section = options_section[options_matched.end() - 3 :] options_matched = re.search(options_parts_regex, options_section) return True class Type2ManParser(ManParser): def is_my_type(self, manpage): return compile_and_search("\.SH OPTIONS(.*?)", manpage) is not None def parse_man_page(self, manpage): options_section_regex = re.compile("\.SH OPTIONS(.*?)(\.SH|\Z)", re.DOTALL) options_section = re.search(options_section_regex, manpage).group(1) options_parts_regex = re.compile( "\.[IT]P( \d+(\.\d)?i?)?(.*?)\.([IT]P|UNINDENT|UN|SH)", re.DOTALL ) options_matched = re.search(options_parts_regex, options_section) add_diagnostic("Command is %r" % CMDNAME) if options_matched is None: add_diagnostic("%r: Unable to find options" % self) return False while options_matched is not None: data = options_matched.group(3) data = remove_groff_formatting(data) data = data.strip() data = data.split("\n", 1) if len(data) > 1 and len(data[1].strip()) > 0: # and len(data[1])<400): optionName = data[0].strip() if "-" not in optionName: add_diagnostic("%r doesn't contain '-'" % optionName) else: optionName = unquote_double_quotes(optionName) optionName = unquote_single_quotes(optionName) optionDescription = data[1].strip().replace("\n", " ") built_command(optionName, optionDescription) else: add_diagnostic("Unable to split option from description") options_section = options_section[options_matched.end() - 3 :] options_matched = re.search(options_parts_regex, options_section) class Type3ManParser(ManParser): def is_my_type(self, manpage): return compile_and_search("\.SH DESCRIPTION(.*?)", manpage) != None def parse_man_page(self, manpage): options_section_regex = re.compile("\.SH DESCRIPTION(.*?)(\.SH|\Z)", re.DOTALL) options_section = re.search(options_section_regex, manpage).group(1) options_parts_regex = re.compile("\.TP(.*?)\.TP", re.DOTALL) options_matched = re.search(options_parts_regex, options_section) add_diagnostic("Command is %r" % CMDNAME) if options_matched is None: add_diagnostic("Unable to find options section") return False while options_matched != None: data = options_matched.group(1) data = remove_groff_formatting(data) data = data.strip() data = data.split("\n", 1) if len(data) > 1: # and len(data[1])<400): optionName = data[0].strip() if optionName.find("-") == -1: add_diagnostic("%r doesn't contain '-'" % optionName) else: optionName = unquote_double_quotes(optionName) optionName = unquote_single_quotes(optionName) optionDescription = data[1].strip().replace("\n", " ") built_command(optionName, optionDescription) else: add_diagnostic("Unable to split option from description") return False options_section = options_section[options_matched.end() - 3 :] options_matched = re.search(options_parts_regex, options_section) class Type4ManParser(ManParser): def is_my_type(self, manpage): return compile_and_search("\.SH FUNCTION LETTERS(.*?)", manpage) != None def parse_man_page(self, manpage): options_section_regex = re.compile( "\.SH FUNCTION LETTERS(.*?)(\.SH|\Z)", re.DOTALL ) options_section = re.search(options_section_regex, manpage).group(1) options_parts_regex = re.compile("\.TP(.*?)\.TP", re.DOTALL) options_matched = re.search(options_parts_regex, options_section) add_diagnostic("Command is %r" % CMDNAME) if options_matched is None: print("Unable to find options section", file=sys.stderr) return False while options_matched != None: data = options_matched.group(1) data = remove_groff_formatting(data) data = data.strip() data = data.split("\n", 1) if len(data) > 1: # and len(data[1])<400): optionName = data[0].strip() if optionName.find("-") == -1: add_diagnostic("%r doesn't contain '-' " % optionName) else: optionName = unquote_double_quotes(optionName) optionName = unquote_single_quotes(optionName) optionDescription = data[1].strip().replace("\n", " ") built_command(optionName, optionDescription) else: add_diagnostic("Unable to split option from description") return False options_section = options_section[options_matched.end() - 3 :] options_matched = re.search(options_parts_regex, options_section) class TypeScdocManParser(ManParser): def is_my_type(self, manpage): return ( compile_and_search( r"\.(\\)(\") Generated by scdoc(.*?)\.SH OPTIONS(.*?)", manpage ) != None ) def parse_man_page(self, manpage): options_section_regex = re.compile("\.SH OPTIONS(.*?)\.SH", re.DOTALL) options_section_matched = re.search(options_section_regex, manpage) if options_section_matched is None: return False options_section = options_section_matched.group(1) options_parts_regex = re.compile("(.*?).RE", re.DOTALL) options_matched = re.match(options_parts_regex, options_section) add_diagnostic("Command is %r" % CMDNAME) if options_matched is None: add_diagnostic("%r: Unable to find options" % self) return False while options_matched is not None: # Get first option and move options_section option = options_matched.group(1) options_section = options_section[options_matched.end() : :] options_matched = re.match(options_parts_regex, options_section) option = remove_groff_formatting(option) option = option.split("\n") # Crean option list option_clean = [] for line in option: if line not in ["", ".P", ".RS 4"]: option_clean.append(line) # Shold be at least two lines if len(option_clean) < 2: add_diagnostic("Unable to split option from description") continue # Name and description, others lines are ignored option_name = option_clean[0] option_description = option_clean[1] if "-" not in option_name: add_diagnostic("%r doesn't contain '-'" % option_name) option_name = unquote_double_quotes(option_name) option_name = unquote_single_quotes(option_name) built_command(option_name, option_description) return True class TypeDarwinManParser(ManParser): def is_my_type(self, manpage): return compile_and_search("\.S[hH] DESCRIPTION", manpage) is not None def trim_groff(self, line): # Remove initial period if line.startswith("."): line = line[1:] # Skip leading groff crud while re.match("[A-Z][a-z]\s", line): line = line[3:] # If the line ends with a space and then a period or comma, then erase the space # This hack handles lines of the form '.Ar projectname .' if line.endswith(" ,") or line.endswith(" ."): line = line[:-2] + line[-1] return line def count_argument_dashes(self, line): # Determine how many dashes the line has using the following regex hack # Look for the start of a line, followed by a dot, then a sequence of # one or more dashes ('Fl') result = 0 if line.startswith("."): line = line[4:] while line.startswith("Fl "): result = result + 1 line = line[3:] return result # Replace some groff escapes. There's a lot we don't bother to handle. def groff_replace_escapes(self, line): line = line.replace(".Nm", CMDNAME) line = line.replace("\\ ", " ") line = line.replace("\& ", "") return line def is_option(self, line): return line.startswith(".It Fl") def parse_man_page(self, manpage): got_something = False lines = manpage.splitlines() # Discard lines until we get to ".sh Description" while lines and not ( lines[0].startswith(".Sh DESCRIPTION") or lines[0].startswith(".SH DESCRIPTION") ): lines.pop(0) while lines: # Pop until we get to the next option while lines and not self.is_option(lines[0]): lines.pop(0) if not lines: continue # Get the line and clean it up line = lines.pop(0) # Try to guess how many dashes this argument has dash_count = self.count_argument_dashes(line) line = self.groff_replace_escapes(line) line = self.trim_groff(line) line = line.strip() if not line: continue # Extract the name name = line.split(None, 2)[0] # Extract the description desc_lines = [] while lines and not self.is_option(lines[0]): line = lossy_unicode(lines.pop(0).strip()) # Ignore comments if line.startswith(r".\""): continue if line.startswith("."): line = self.groff_replace_escapes(line) line = self.trim_groff(line).strip() if line: desc_lines.append(line) desc = " ".join(desc_lines) if name == "-": # Skip double -- arguments continue elif len(name) > 1: # Output the command built_command(("-" * dash_count) + name, desc) got_something = True elif len(name) == 1: built_command("-" + name, desc) got_something = True return got_something class TypeDeroffManParser(ManParser): def is_my_type(self, manpage): return True # We're optimists def is_option(self, line): return line.startswith("-") def could_be_description(self, line): return len(line) > 0 and not line.startswith("-") def parse_man_page(self, manpage): d = Deroffer() d.deroff(manpage) output = d.get_output() lines = output.split("\n") got_something = False # Discard lines until we get to DESCRIPTION or OPTIONS while lines and not ( lines[0].startswith("DESCRIPTION") or lines[0].startswith("OPTIONS") or lines[0].startswith("COMMAND OPTIONS") ): lines.pop(0) # Look for BUGS and stop there for idx in range(len(lines)): line = lines[idx] if line.startswith("BUGS"): # Drop remaining elements lines[idx:] = [] break while lines: # Pop until we get to the next option while lines and not self.is_option(lines[0]): line = lines.pop(0) if not lines: continue options = lines.pop(0) # Pop until we get to either an empty line or a line starting with - description = "" while lines and self.could_be_description(lines[0]): if description: description += " " description += lines.pop(0) built_command(options, description) got_something = True return got_something # Return whether the file at the given path is overwritable # Raises IOError if it cannot be opened def file_is_overwritable(path): result = False file = codecs.open(path, "r", encoding="utf-8") for line in file: # Skip leading empty lines line = line.strip() if not line: continue # We look in the initial run of lines that start with # if not line.startswith("#"): break # See if this contains the magic word if "Autogenerated" in line: result = True break file.close() return result # Remove any and all autogenerated completions in the given directory def cleanup_autogenerated_completions_in_directory(dir): try: for filename in os.listdir(dir): # Skip non COMP_EXT files if not filename.endswith(COMP_EXT): continue path = os.path.join(dir, filename) cleanup_autogenerated_file(path) except OSError as err: return False # Delete the file if it is autogenerated def cleanup_autogenerated_file(path): try: if file_is_overwritable(path): os.remove(path) except (OSError, IOError): pass def parse_manpage_at_path(manpage_path, output_directory): # Return if CMDNAME is in 'ignoredcommands' ignoredcommands = [ "cc", "g++", "gcc", "c++", "cpp", "emacs", "gprof", "wget", "ld", "awk", ] if CMDNAME in ignoredcommands: return # Clear diagnostics global diagnostic_indent diagnostic_output[:] = [] diagnostic_indent = 0 # Set up some diagnostics add_diagnostic("Considering " + manpage_path) diagnostic_indent += 1 if manpage_path.endswith(".gz"): fd = gzip.open(manpage_path, "r") manpage = fd.read() if IS_PY3: manpage = manpage.decode("latin-1") elif manpage_path.endswith(".bz2"): fd = bz2.BZ2File(manpage_path, "r") manpage = fd.read() if IS_PY3: manpage = manpage.decode("latin-1") elif manpage_path.endswith(".xz") or manpage_path.endswith(".lzma"): if not lzma_available: return fd = lzma.LZMAFile(str(manpage_path), "r") manpage = fd.read() if IS_PY3: manpage = manpage.decode("latin-1") elif manpage_path.endswith((".1", ".2", ".3", ".4", ".5", ".6", ".7", ".8", ".9")): if IS_PY3: fd = open(manpage_path, "r", encoding="latin-1") else: fd = open(manpage_path, "r") manpage = fd.read() else: return fd.close() manpage = str(manpage) # Ignore perl's gazillion man pages ignored_prefixes = ["perl", "zsh"] for prefix in ignored_prefixes: if CMDNAME.startswith(prefix): return # Ignore the millions of links to BUILTIN(1) if "BUILTIN 1" in manpage or "builtin.1" in manpage: return # Clear the output list built_command_output[:] = [] if DEROFF_ONLY: parsers = [TypeDeroffManParser()] else: parsers = [ TypeScdocManParser(), Type1ManParser(), Type2ManParser(), Type4ManParser(), Type3ManParser(), TypeDarwinManParser(), TypeDeroffManParser(), ] parsersToTry = [p for p in parsers if p.is_my_type(manpage)] success = False for parser in parsersToTry: add_diagnostic("Trying %s" % parser.__class__.__name__) diagnostic_indent += 1 success = parser.parse_man_page(manpage) diagnostic_indent -= 1 # Make sure empty files aren't reported as success if not built_command_output: success = False if success: PARSER_INFO.setdefault(parser.__class__.__name__, []).append(CMDNAME) break if success: if WRITE_TO_STDOUT: output_file = sys.stdout else: fullpath = os.path.join(output_directory, CMDNAME + COMP_EXT) try: output_file = codecs.open(fullpath, "w", encoding="utf-8") except IOError as err: add_diagnostic( "Unable to open file '%s': error(%d): %s" % (fullpath, err.errno, err.strerror) ) return False # Output the magic word Autogenerated so we can tell if we can overwrite this built_command_output.insert( 0, "# " + CMDNAME + "\n# Autogenerated from man page " + manpage_path ) # built_command_output.insert(2, "# using " + parser.__class__.__name__) # XXX MISATTRIBUTES THE CULPABLE PARSER! Was really using Type2 but reporting TypeDeroffManParser for line in built_command_output: output_file.write(line) output_file.write("\n") output_file.write("\n") add_diagnostic(manpage_path + " parsed successfully") if output_file != sys.stdout: output_file.close() else: parser_names = ", ".join(p.__class__.__name__ for p in parsersToTry) # add_diagnostic('%s contains no options or is unparsable' % manpage_path, BRIEF_VERBOSE) add_diagnostic( "%s contains no options or is unparsable (tried parser %s)" % (manpage_path, parser_names), BRIEF_VERBOSE, ) return success def parse_and_output_man_pages(paths, output_directory, show_progress): global diagnostic_indent, CMDNAME paths.sort() total_count = len(paths) successful_count, index = 0, 0 padding_len = len(str(total_count)) last_progress_string_length = 0 if show_progress and not WRITE_TO_STDOUT: print( "Parsing man pages and writing completions to {0}".format(output_directory) ) man_page_suffixes = set([os.path.splitext(m)[1][1:] for m in paths]) lzma_xz_occurs = "xz" in man_page_suffixes or "lzma" in man_page_suffixes if lzma_xz_occurs and not lzma_available: add_diagnostic( 'At least one man page is compressed with lzma or xz, but the "lzma" module is not available.' " Any man page compressed with either will be skipped.", NOT_VERBOSE, ) flush_diagnostics(sys.stderr) for manpage_path in paths: index += 1 # Get the "base" command, e.g. gcc.1.gz -> gcc man_file_name = os.path.basename(manpage_path) CMDNAME = man_file_name.split(".", 1)[0] # Show progress if we're doing that if show_progress: progress_str = " {0} / {1} : {2}".format( (str(index).rjust(padding_len)), total_count, man_file_name ) # Pad on the right with spaces so we overwrite whatever we wrote last time padded_progress_str = progress_str.ljust(last_progress_string_length) last_progress_string_length = len(progress_str) sys.stdout.write("\r{0}\r".format(padded_progress_str)) sys.stdout.flush() try: if parse_manpage_at_path(manpage_path, output_directory): successful_count += 1 except IOError: diagnostic_indent = 0 add_diagnostic("Cannot open " + manpage_path) except (KeyboardInterrupt, SystemExit): raise except: add_diagnostic( "Error parsing %s: %s" % (manpage_path, sys.exc_info()[0]), BRIEF_VERBOSE, ) flush_diagnostics(sys.stderr) traceback.print_exc(file=sys.stderr) flush_diagnostics(sys.stderr) # print("") # Newline after loop add_diagnostic( "Successfully parsed %d / %d pages" % (successful_count, total_count), BRIEF_VERBOSE, ) flush_diagnostics(sys.stderr) return successful_count def get_paths_from_man_locations(prog_name): # If PROG_NAME isn't NULL/None, return any available full manpage path for PROG_NAME # Else, return all the paths to man(1) and man(8) files in the manpath parent_paths = [] # Most (GNU, macOS, Haiku) modern implementations of man support being called with `--path`. # Traditional implementations require a second `manpath` program: examples include FreeBSD and Solaris. # Prefer an external program first because these programs return a superset of the $MANPATH variable. for prog in [["man", "--path"], ["manpath"]]: try: output = subprocess.check_output(prog, stderr=DEVNULL) if IS_PY3: output = output.decode("latin-1") parent_paths = output.strip().split(":") break except (OSError, subprocess.CalledProcessError): continue # If we can't have the OS interpret $MANPATH, just use it as-is (gulp). if not parent_paths and os.getenv("MANPATH"): parent_paths = os.getenv("MANPATH").strip().split(":") # Fallback: With mandoc (OpenBSD, embedded Linux) and NetBSD man, the only way to get the default manpath is by reading /etc. if not parent_paths: try: with open("/etc/man.conf", "r") as file: data = file.read() for key in ["MANPATH", "_default"]: for match in re.findall(r"^%s\s+(.*)$" % key, data, re.I | re.M): parent_paths.append(match) except FileNotFoundError: pass # Fallback: hard-code some common paths. These should be likely for FHS Linux distros, BSDs, and macOS. if not parent_paths: parent_paths = ["/usr/share/man", "/usr/local/man", "/usr/local/share/man"] print( "Unable to get the manpath, falling back to %s." % ":".join(parent_paths), "Explictly set $MANPATH to fix this error.", file=sys.stderr, ) result = [] for parent_path in parent_paths: for section in ["man1", "man6", "man8"]: directory_path = os.path.join(parent_path, section) if prog_name: # Check whether there is a man page available for PROG_NAME p = directory_path + "/" + prog_name + "." + section[3] + "*" for path in (glob.glob(p)): if os.path.exists(path): return path try: names = os.listdir(directory_path) except OSError: names = [] names.sort() for name in names: result.append(os.path.join(directory_path, name)) if prog_name: # No manpage for PROG_NAME found return None return result if __name__ == "__main__": script_name = sys.argv[0] parser = argparse.ArgumentParser( description="create_manpage_completions: Generate completions from manpages" ) parser.add_argument( "-c", "--cleanup-in", type=str, help="Directories to clean up in", action="append", ) parser.add_argument( "-d", "--directory", type=str, help="The directory to save the completions in", ) parser.add_argument( "-k", "--keep", help="Whether to keep files in the target directory", action="store_true", ) parser.add_argument( # Create completion files for all available man pages "-m", "--manpath", help="Whether to use manpath", action="store_true", ) parser.add_argument( "-p", "--progress", help="Whether to show progress", action="store_true", ) parser.add_argument( "-s", "--stdout", help="Write the completions to stdout", action="store_true", ) parser.add_argument( "-v", "--verbose", type=int, choices=[0, 1, 2], help="The level of debug output to show", ) parser.add_argument( "-z", "--deroff-only", help="Whether to just deroff", action="store_true", ) parser.add_argument("file_paths", type=str, nargs="*") args = parser.parse_args() pathsn = len(args.file_paths) if args.verbose: VERBOSITY = args.verbose if args.stdout: WRITE_TO_STDOUT = True if args.deroff_only: DEROFF_ONLY = True if args.keep: KEEP_FILES = True if args.manpath: # Fetch all man1 and man8 files from the manpath or man.conf args.file_paths.extend(get_paths_from_man_locations(None)) # Directories within which we will clean up autogenerated completions if args.cleanup_in: for cleanup_dir in args.cleanup_in: cleanup_autogenerated_completions_in_directory(cleanup_dir) if not args.file_paths: if args.manpath: print("No paths specified and I can't make sense of your MANPATH") print("Please either give paths or set $MANPATH and try again") else: print("No paths specified") sys.exit(1) else: for i in range(pathsn): # Get man path for each argument which does not contain a slash if "/" not in args.file_paths[i]: tmp = get_paths_from_man_locations(args.file_paths[i]) if tmp: args.file_paths[i] = tmp elif pathsn == 1: sys.exit(1) if not args.stdout and not args.directory: # Create destination dir if it doesn't exist xdg_data_home = os.getenv("XDG_DATA_HOME", "~/.local/share") args.directory = os.path.expanduser( xdg_data_home + DEST_DIR_SUFFIX ) try: os.makedirs(args.directory) except OSError as e: if e.errno != errno.EEXIST: raise if not args.stdout and not args.keep: # Remove old generated files cleanup_autogenerated_completions_in_directory(args.directory) ret = parse_and_output_man_pages(args.file_paths, args.directory, args.progress) if pathsn != ret: sys.exit(1) else: sys.exit(0) clifm-1.26.3/plugins/000077500000000000000000000000001506632037700143675ustar00rootroot00000000000000clifm-1.26.3/plugins/BFG.cfg000066400000000000000000000045451506632037700154560ustar00rootroot00000000000000############################################ # Configuration file Clifm's BFG previewer # ############################################ # Commented and blank lines are omitted # GENERAL OPTIONS # Maximum height of the FZF window. Defaults to 80% FZFHEIGHT="80%" # Location of the previwer script. Defaults to # "${XDG_CONFIG_HOME:-$HOME/.config}/clifm/plugins/BFG.sh" BFG_FILE="" # Resource opener to use. Defaults to Lira, Clifm's built-in opener OPENER="clifm" # BFG caches images to speed up the previewing process (only files # that need to be converted into images are cached). Specify where # to store these cached images. Defaults to # "${XDG_CACHE_HOME:-$HOME/.cache}/clifm/previews" PREVIEWDIR="" # Set to 1 to use Ranger's scope.sh file instead of BFG USE_SCOPE=0 # Location of the scope.sh file. Defaults to # "${XDG_CONFIG_HOME:-$HOME/.config}/ranger/scope.sh" SCOPE_FILE="" # Set to 1 to use pistol instead of BFG USE_PISTOL=0 PREVIEW_IMAGES=1 PLAY_MUSIC=1 ANIMATE_GIFS=1 # Try to print file information if no previewing application is found FALLBACK_INFO=1 # FILETYPE DEFINITIONS # Choose previewing applications for file types. Available options # are provided as comments above each line. # Use 'none' to prevent previews of the corresponding file type. # Leave blank to let BFG check for available applications and use # the first one found (the order of this check is the same as the # order in the comments below). Ex: for archives, atool will be # checked first, then bsdtar, and finally tar. # atool (recommended), bsdtar, tar ARCHIVES="" # w3m, linx, elinks, cat BROWSER="" # ddjvu (image preview), ddjvutxt (text preview) DDJVU="" # tree, ls, exa, exa-tree, lsd, lsd-tree DIR="" # libreoffice (image preview), text (text preview) # NOTE: 'text' is not iteself an application. It instructs BFG to # look for an application able to print documents as text. Checks # are made for the following applications: catdoc, odt2txt, xls2csv, # xls2xcsv, and pandoc DOC="" # epub-thumbnailer EPUB="" # exitool FILEINFO="" # fontpreview, fontimage FONTS="" # ueberzug, kitty, viu, catimg, chafa, img2txt, pixterm IMG="" # python, jq, cat JSON="" # glow, mdcat MARKDOWN="" # mediainfo MEDIAINFO="" # ffplay, mplayer, mpv MUSIC="" # pdftoppm (image preview), pdftotext (text preview), mutool PDF="" # bat, highlight, pygmentize, cat TEXT="" # ffmpegthumbailer VIDEO="" clifm-1.26.3/plugins/BFG.sh000077500000000000000000000370641506632037700153360ustar00rootroot00000000000000#!/bin/sh # BFG: This is Clifm's file previewer script. It is called by the fzfnav.sh # plugin for each hovered file. Variables for available applications are # exported by fzfnav to prevent this script from checking the same # applications once and again # Written by L. Abramovich # License: GPL2+ # Previewing dependencies (optional) # atool or bsdtar or tar: archives # magick (imagemagick 7.0+), and ueberzug (recommended) or viu or catimg or img2txt: images # fontpreview or fontimage (fontforge): fonts # libreoffice, catdoc, odt2txt, xls2csv, xls2xcsv, pandoc: office documents # pdftoppm or pdftotext or mutool: PDF files # epub-thumbnailer: epub files # ddjvu (djvulibre) or djvutxt: DjVu files # ghostscript: postscript files (ps) # ffmpegthumbnailer: videos # ffplay (ffmpeg) or mplayer or mpv: audio # w3m or linx or elinks: web content # glow: markdown # bat or highlight or pygmentize: syntax highlighthing for text files # python or jq: json # transmission-cli: torrent files # exiftool or mediainfo or file: file information # Default size for images WIDTH=1920 HEIGHT=1080 calculate_position() { # shellcheck disable=SC2034 # TERM_LINES and TERM_COLS hold the number of lines and columns # of the terminal window respectivelly, while LINES and COLUMNS # refer rather to the preview window's size read -r TERM_LINES TERM_COLS << EOF $( "$FIFO_UEBERZUG" } uz_clear() { printf '{"action": "remove", "identifier": "clifm-preview"}\n' > "$FIFO_UEBERZUG" } kitty_clear() { kitty +kitten icat --clear --transfer-mode=stream --silent } preview_image() { [ -z "$IMG_VIEWER" ] || [ -z "$1" ] && return 1 img="$1" case "$IMG_VIEWER" in kitty) calculate_position kitty +kitten icat --silent --place "$COLUMNS"x"$LINES"@"$X"x"$Y" \ --transfer-mode=stream --align=left "$img" \ && return 0 ;; w3m) calculate_position # WIDTH=200 # HEIGHT=200 # X=360 # Y=15 W3IMG_PATH="/usr/lib/w3m/w3mimgdisplay" # Clear image printf '6;%s;%s;%s;%s\n3;' "$X" "$Y" "$WIDTH" "$HEIGHT" | "$W3IMG_PATH" printf '0;1;%s;%s;%s;%s;;;;;%s\n4;\n3;' "$X" "$Y" "$WIDTH" "$HEIGHT" \ "$img" | "$W3IMG_PATH" && return 0 ;; # terminology) # [ "$TERM_PROGRAM" != "terminology" ] && return 1 # tycat "$img" && return 0 # ;; pixterm) pixterm -s 2 -tc $((COLUMNS - 2)) "$img" && return 0 ;; catimg) catimg -H$LINES "$img" && return 0 ;; img2txt) img2txt -H$LINES -W$((COLUMNS - 2)) "$img" && return 0 ;; chafa) chafa -s "$((COLUMNS - 2))x$LINES" "$img" && return 0 ;; viu) viu -h$LINES -w$((COLUMNS - 2)) "$img" && return 0 ;; *) "$IMG_VIEWER" "$img" && return 0 ;; esac return 1 } file_info() { [ "$FALLBACK_INFO" = 0 ] && exit 0 [ -z "$1" ] && exit 1 entry="$1" if [ "$FILE_OK" = 1 ] && [ "$FILE_HAS_MIME_ENCODING" = 1 ] && [ "$(file -bL --mime-encoding "$entry")" = "binary" ]; then printf -- "--- \e[0;30;47mBinary file\e[0m ---\n" fi if [ "$EXIFTOOL_OK" = 1 ]; then exiftool "$PWD/$entry" 2>/dev/null && exit 0 elif [ "$MEDIAINFO_OK" = 1 ]; then mediainfo "$PWD/$entry" 2>/dev/null && exit 0 elif [ "$FILE_OK" = 1 ]; then file -b "$entry" && exit 0 fi exit 1 } handle_ext() { # Check a few extensions not correctly handled by file(1) entry="$1" ext="${entry##*.}" if [ -n "$ext" ] && [ "$ext" != "$entry" ]; then ext="$(printf "%s" "${ext}" | tr '[:upper:]' '[:lower:]')" case "$ext" in # Direct Stream Digital/Transfer (DSDIFF) and wavpack aren not # detected by file(1). # dff|dsf|wv|wvc) # file_info "$entry" && exit 0 # ;; # Markdown files md) if [ "$GLOW_OK" = 1 ]; then glow -s dark "$PWD/$entry" && exit 0 elif [ "$MDCAT_OK" = 1 ]; then mdcat "$entry" && exit 0 elif [ "$BAT_OK" = 1 ]; then bat "$entry" && exit 0 elif [ "$CAT_OK" = 1 ]; then cat "$entry" && exit 0 fi ;; # XZ Compressed xz) if [ -n "$ARCHIVER_CMD" ]; then "$ARCHIVER_CMD" "$ARCHIVER_OPTS" "$entry" && exit 0 fi ;; # Web html|xhtml|htm) if [ -n "$BROWSER" ]; then "$BROWSER" -dump "$entry" && exit 0 elif [ "$CAT_OK" = 1 ]; then cat "$entry" && exit 0 fi ;; json) if [ "$PYTHON_OK" = 1 ]; then python -m json.tool -- "$entry" && exit 0 elif [ "$JQ_OK" = 1 ]; then jq --color-output . "$PWD/$entry" && exit 0 elif [ "$CAT_OK" = 1 ]; then cat "$entry" && exit 0 fi ;; svg) [ -z "$IMG_VIEWER" ] && return if [ -f "$PREVIEWDIR/${entryhash}.png" ]; then preview_image "$PREVIEWDIR/${entryhash}.png" && exit 0 fi [ -z "$CONVERT_OK" ] && return magick -background none -size "$WIDTH"x"$HEIGHT" "$entry" \ "$PREVIEWDIR/${entryhash}.png" preview_image "${PREVIEWDIR}/${entryhash}.png" && exit 0 ;; torrent) if [ "$TRANSMISSION_OK" = 1 ]; then transmission-show -- "$PWD/$entry" && exit 0 fi ;; # stl|off|dxf|scad|csg) # if [ "$(which openscad 2>/dev/null)" ]; then # openscad "$PWD/$entry" # else # file_info "$entry" # fi # exit 1 # ;; esac fi } handle_mime() { [ -z "$FILE_OK" ] && return entry="$1" mimetype="$(file --brief --dereference --mime-type "$entry")" case "$mimetype" in # Office documents *officedocument*|*msword|*ms-excel|text/rtf|*.opendocument.*) if [ -n "$IMG_VIEWER" ] && [ -z "$DOCASTEXT" ]; then _type="png" if [ -f "$PREVIEWDIR/${entryhash}.$_type" ]; then preview_image "$PREVIEWDIR/${entryhash}.$_type" && exit 0 fi if [ "$LIBREOFFICE_OK" = 1 ]; then libreoffice --headless --convert-to "$_type" "$entry" \ --outdir "$PREVIEWDIR" > /dev/null 2>&1 && \ mv "$PREVIEWDIR/${entry%.*}.$_type" "$PREVIEWDIR/${entryhash}.$_type" && \ preview_image "${PREVIEWDIR}/${entryhash}.$_type" && exit 0 fi fi case "$ext" in odt|ods|odp|sxw) # shellcheck disable=SC2153 if [ "$ODT2TXT_OK" = 1 ]; then odt2txt "$PWD/$entry" && exit 0 elif [ "$PANDOC_OK" = 1 ]; then pandoc -s -t markdown -- "$PWD/$entry" && exit 0 fi ;; xlsx) if [ "$XLSX2CSV_OK" = 1 ]; then xlsx2csv -- "$PWD/$entry" && exit 0 fi ;; xls) if [ "$XLSX2CSV_OK" = 1 ]; then xls2csv -- "$PWD/$entry" && exit 0 fi ;; docx) if [ "$UNZIP_OK" = 1 ]; then unzip -p "$entry" | grep --text '/ /g' | sed 's/<[^<]*>//g' | \ grep -v '^[[:space:]]*$' | sed G && \ exit 0 fi ;; *) if [ -n "$CATDOC_OK" ]; then catdoc "$entry" && exit 0 fi ;; esac ;; # Empty file inode/x-empty) printf -- "--- \033[0;30;47mEmpty file\033[0m ---" ;; # Web content text/html) if [ -n "$BROWSER" ]; then "$BROWSER" -dump "$entry" && exit 0 elif [ "$PANDOC_OK" = 1 ]; then pandoc -s -t markdown -- "$entry" && exit 0 elif [ "$CAT_OK" = 1 ]; then cat "$entry" && exit 0 fi ;; # Plain text files text/*|application/x-setupscript|*/xml) if [ "$BAT_OK" = 1 ]; then bat -pp --color=always "$entry" && exit 0 elif [ "$HIGHLIGHT_OK" = 1 ]; then if [ "$COLORS" = 256 ]; then highlight -O xterm256 "$entry" && exit 0 else highlight -O ansi "$entry" && exit 0 fi elif [ "$PYGMENTIZE_OK" = 1 ]; then if [ "$COLORS" = 256 ]; then pigmentize -f terminal256 "$entry" && exit 0 else pigmentize -f terminal "$entry" && exit 0 fi elif [ "$CAT_OK" = 1 ]; then cat "$entry" && exit 0 fi ;; # DjVu */vnd.djvu) if [ -n "$IMAGE_VIEWER" ] && [ "$DDJVU_OK" = 1 ]; then if [ -f "$PREVIEWDIR/${entryhash}.jpg" ]; then preview_image "$PREVIEWDIR/${entryhash}.jpg" && exit 0 fi ddjvu --format=tiff --page=1 "$entry" "$PREVIEWDIR/${entryhash}.jpg" preview_image "$PREVIEWDIR/${entryhash}.jpg" && exit 0 elif [ "$DJVUTXT_OK" = 1 ]; then djvutxt "$PWD/entry" && exit 0 fi ;; # GIF files */gif) [ -z "$IMG_VIEWER" ] && return if [ "$ANIMATE_GIFS" = 0 ]; then if [ "$IMG_VIEWER" = "kitty" ]; then calculate_position kitty +kitten icat --silent --place "$COLUMNS"x"$LINES"@"$X"x"$Y" \ --transfer-mode=stream --align=left --loop=0 "$PWD/$entry" \ && exit 0 fi if [ -f "$PREVIEWDIR/${entryhash}.jpg" ]; then preview_image "$PREVIEWDIR/${entryhash}.jpg" && exit 0 fi magick "$entry"[0] -resize "$WIDTH"x"$HEIGHT"\> \ "$PREVIEWDIR/$entryhash.jpg" preview_image "$PREVIEWDIR/${entryhash}.jpg" && exit 0 exit 0 fi if [ "$IMG_VIEWER" = "kitty" ] || [ "$IMG_VIEWER" = "catimg" ] \ || [ "$IMG_VIEWER" = "chafa" ]; then preview_image "$PWD/$entry" && exit 0 fi # Break down the gif into frames and show each frame, one each 0.1 secs # printf "\n" filename="$(printf "%s" "$entry" | tr ' ' '_')" if [ ! -d "$PREVIEWDIR/$entryhash" ]; then mkdir -p "$PREVIEWDIR/$entryhash" && \ magick "$entry" -coalesce -resize "$WIDTH"x"$HEIGHT"\> \ "$PREVIEWDIR/$entryhash/${filename%.*}.jpg" fi while true; do for frame in $(find "$PREVIEWDIR/$entryhash"/*.jpg 2>/dev/null \ | sort -V); do preview_image "$frame" sleep 0.1 done done exit 0 ;; # Images image/*) preview_image "$PWD/$entry" && exit 0 ;; # Postscript application/postscript) [ -z "$IMG_VIEWER" ] && return if [ -f "$PREVIEWDIR/${entryhash}.jpg" ]; then preview_image "$PREVIEWDIR/${entryhash}.jpg" && exit 0 fi if [ "$(which gs 2>/dev/null)" ]; then gs -sDEVICE=jpeg -dJPEGQ=100 -dNOPAUSE -dBATCH -dSAFER -r300 \ -sOutputFile="$PREVIEWDIR/${entryhash}.jpg" "$entry" > /dev/null 2>&1 && \ preview_image "$PREVIEWDIR/${entryhash}.jpg" && exit 0 fi ;; # Epub application/epub+zip|application/x-mobipocket-ebook|application/x-fictionbook+xml) [ -z "$IMG_VIEWER" ] && return if [ -f "$PREVIEWDIR/${entryhash}.jpg" ]; then preview_image "$PREVIEWDIR/${entryhash}.jpg" && exit 0 fi if [ -n "$EPUBTHUMB_OK" ]; then epub-thumbnailer "$entry" "$PREVIEWDIR/${entryhash}.jpg" \ "$WIDTH" "$HEIGHT" && \ preview_image "$PREVIEWDIR/${entryhash}.jpg" && exit 0 fi ;; # PDF */pdf) [ -z "$IMG_VIEWER" ] && return if [ -f "$PREVIEWDIR/${entryhash}.jpg" ] && \ [ "$PDFTOPPM_OK" = 1 ]; then preview_image "$PREVIEWDIR/${entryhash}.jpg" && exit 0 fi if [ "$PDFTOPPM_OK" = 1 ]; then pdftoppm -jpeg -f 1 -singlefile "$entry" "$PREVIEWDIR/$entryhash" && \ preview_image "$PREVIEWDIR/${entryhash}.jpg" && exit 0 elif [ "$PDFTOTEXT_OK" = 1 ]; then pdftotext -nopgbrk -layout -- "$entry" - | ${PAGER:=less} && exit 0 elif [ "$MUTOOL_OK" = 1 ]; then mutool draw -F txt -- "$entry" && exit 0 fi ;; # Audio audio/*) # [ -z "$IMG_VIEWER" ] || ! [ "$(which ffmpeg 2>/dev/null)" ] && return # ffmpeg -i "$entry" -lavfi \ # showspectrumpic=s="$WIDTH"x"$HEIGHT":mode=separate:legend=disabled \ # "${PREVIEWDIR}/${entry}.jpg" > /dev/null 2>&1 # uz_image "${PREVIEWDIR}/${entry}.jpg" ;; if [ "$FFPLAY_OK" = 1 ]; then ffplay -nodisp -autoexit "$entry" & elif [ "$MPLAYER_OK" = 1 ]; then mplayer "$entry" & elif [ "$MPV_OK" = 1 ]; then mpv --no-video --quiet "$entry" & fi if [ "$FALLBACK_INFO" = 1 ]; then [ "$MEDIAINFO_OK" = 1 ] && mediainfo "$entry" [ "$EXIFTOOL_OK" = 1 ] && exiftool "$entry" fi exit 0 ;; # Video video/*) [ -z "$IMG_VIEWER" ] && return if [ -f "$PREVIEWDIR/${entryhash}.jpg" ]; then preview_image "$PREVIEWDIR/${entryhash}.jpg" && exit 0 fi if [ "$FFMPEGTHUMB_OK" = 1 ]; then ffmpegthumbnailer -i "$entry" -o "$PREVIEWDIR/${entryhash}.jpg" -s 0 \ -q 5 2>/dev/null && \ preview_image "$PREVIEWDIR/${entryhash}.jpg" && exit 0 fi ;; # Fonts font/*|application/font*|application/*opentype) [ -z "$IMG_VIEWER" ] && return if [ -f "${PREVIEWDIR}/${entryhash}.jpg" ]; then preview_image "${PREVIEWDIR}/${entryhash}.jpg" && exit 0 elif [ -f "${PREVIEWDIR}/${entryhash}.png" ]; then preview_image "${PREVIEWDIR}/${entryhash}.png" && exit 0 fi if [ "$FONTPREVIEW_OK" = 1 ]; then fontpreview -i "$entry" -o "$PREVIEWDIR/${entryhash}.jpg" && \ preview_image "$PREVIEWDIR/${entryhash}.jpg" && exit 0 elif [ "$FONTIMAGE_OK" = 1 ]; then png_file="$PREVIEWDIR/${entryhash}.png" if fontimage -o "$png_file" \ --width "500" --height "290" \ --pixelsize "45" \ --fontname \ --pixelsize "30" \ --text " ABCDEFGHIJKLMNOPQRSTUVWXYZ " \ --text " abcdefghijklmnopqrstuvwxyz " \ --text " 0123456789.:,;(*!?') " \ --text " ff fl fi ffi ffl " \ --text " The quick brown fox jumps over the lazy dog." \ "$PWD/$entry" > /dev/null 2>&1; then preview_image "$png_file" && exit 0 fi fi ;; # Archives application/zip|application/gzip|application/x-7z-compressed|\ application/x-bzip2) if [ -n "$ARCHIVER_CMD" ]; then "$ARCHIVER_CMD" "$ARCHIVER_OPTS" "$entry" && exit 0 fi ;; esac } main() { entry="$1" [ "$entry" = ".." ] && return if [ "$USE_PISTOL" = 1 ]; then pistol "$PWD/$entry" && exit 0 exit 1 fi if [ "$USE_SCOPE" = 1 ] && [ -x "$SCOPE_FILE" ]; then calculate_position "$SCOPE_FILE" "$PWD/$entry" "$X" "$Y" "$PREVIEWDIR" "True" && exit 0 exit 1 fi [ "$UEBERZUG_OK" = 1 ] && uz_clear [ "$IMG_VIEWER" = "kitty" ] && kitty_clear # Symlink if [ -L "$entry" ]; then real_path="$(realpath "$entry")" printf "%s \033[1;36m->\033[0m " "$entry" if [ -e "$real_path" ]; then if [ "$POSIX_LS" = 0 ]; then ls -d --color=always "$real_path" && exit 0 else ls -d "$real_path" && exit 0 fi else printf "%s\n\033[1;37mBroken link\033[0m" "$real_path" && exit 0 fi exit 1 fi # Directory if [ -d "$entry" ]; then path="$(printf "%s" "$(pwd)/$entry" | sed "s;//;/;")" if [ "$DIR_CMD" = "tree" ]; then if [ "$COLORS" = 256 ]; then tree -a "$path" && exit 0 else tree -aA "$path" && exit 0 fi else printf "%s\n" "$path" if [ "$DIR_CMD" = "lsd" ]; then lsd -A --group-dirs=first --color=always "$path" && exit 0 elif [ "$DIR_CMD" = "lsd-tree" ]; then lsd -A --group-dirs=first --depth=1 --tree --color=always "$path" && exit 0 elif [ "$DIR_CMD" = "exa" ]; then exa -G --group-directories-first --color=always "$path" && exit 0 elif [ "$DIR_CMD" = "exa-tree" ]; then exa -G --group-directories-first --color=always --tree --level=1 "$path" && exit 0 else if [ "$POSIX_LS" = 0 ]; then ls -Ap --color=always --indicator-style=none "$path" && exit 0 else ls -Ap "$path" && exit 0 fi fi fi exit 1 fi printf "\n" # Use hashes instead of file names for cached files if type md5sum > /dev/null 2>&1; then entryhash="$(printf "file://%s" "${PWD}/$entry" | md5sum)" entryhash="${entryhash%% *}" elif type md5 > /dev/null 2>&1; then entryhash="$(md5 -q -s "file://${PWD}/$entry")" else printf "clifm: No hashing application found. Either md5sum or md5 \ are required\n" >&2 exit 1 fi # Do not generate previews of previews [ "$PWD" = "${PREVIEWDIR}" ] && entry="${entry%.*}" handle_ext "$entry" handle_mime "$entry" file_info "$entry" # Fallback to file information } #calculate_position main "$@" exit 1 clifm-1.26.3/plugins/batch_copy.sh000077500000000000000000000021041506632037700170360ustar00rootroot00000000000000#!/bin/sh # Clifm plugin to copy file(s) into multiple destinations # Written by L. Abramovich # License: GPL2+ # Description: Copy files passed as arguments to files specified via # a text editor # Dependencies: grep, xargs, text editor if [ -z "$1" ] || [ "$1" = "--help" ]; then name="${CLIFM_PLUGIN_NAME:-$(basename "$0")}" printf "Copy files into multiple directories at once\n" printf "\n\x1b[1mUSAGE\x1b[0m\n %s FILE...\n" "$name" printf "\n\x1b[1mEXAMPLE\x1b[0m\n- Copy file1 and file2 into dir1 and dir2 at once\n\ %s file1 file2\n\n Once in the editor, enter dir1 and dir2, save, and exit.\n" "$name" exit 0 fi DEST=$(mktemp "${TMPDIR:-/tmp}/clifm_bcd.XXXXXX") printf "# Clifm - Copy files in batch\n\ # Write here destinty files/directories, one per line.\n\ # Blank and commented lines are omitted.\n\ # Just quit the editor to cancel the operation.\n" > "$DEST" "${EDITOR-:nano}" "$DEST" if ! grep -qv "^$\|^#" "$DEST"; then rm -f -- "$DEST" exit 0 fi for file in "$@"; do grep -v "^$\|^#" "$DEST" | xargs -n1 cp -v "$file" done rm -f -- "$DEST" exit 0 clifm-1.26.3/plugins/batch_create.sh000077500000000000000000000037521506632037700173410ustar00rootroot00000000000000#!/bin/sh # Clifm plugin to create multiple files and/or dirs at once # Written by L. Abramovich # License: GPL2+ # Dependencies: xargs, text editor if [ "$1" = "-h" ] || [ "$1" = "--help" ]; then name="${CLIFM_PLUGIN_NAME:-$(basename "$0")}" printf "Create files in bulk.\n\nOpen a text editor to add files and/or directories to be created (file names\nending with a slash will be taken as directory names). After saving the file\nand closing the editor, files will be created (via mkdir(1) and/or touch(1)).\n\n" printf "\x1b[1mUSAGE\x1b[0m:\n %s\n" "$name" exit 0 fi if [ -z "$EDITOR" ] && ! type nano >/dev/null 2>&1; then printf "No editor specified. Set the EDITOR environment variable. Ex: export EDITOR=vim\n" >&2 exit 1 fi TMP_DIR="${TMPDIR:-/tmp}" TMP=$(mktemp "$TMP_DIR/clifm_bn_tmp.XXXXXX") FILES=$(mktemp "$TMP_DIR/clifm_bn_files.XXXXXX") DIRS=$(mktemp "$TMP_DIR/clifm_bn_dirs.XXXXXX") dirsn=0 filesn=0 printf "# Clifm - Create files in batch\n\ #\n\ # Write below the file names to be created.\n\ # End file names with a slash to create a directory.\n\ # Empty and commented lines are omitted.\n\ #\n\ # Once you're done, save and exit. # Just quit the editor (without saving) to cancel the operation.\n\n" > "$TMP" "${EDITOR:-nano}" "$TMP" while read -r line; do if [ ${#line} = 0 ] || [ "$(printf "%.1s" "$line")" = '#' ]; then continue fi if [ "$(printf "%s" "$line" | tail -c1)" = "/" ]; then printf "%s\0" "$line" >> "$DIRS" dirsn=$((dirsn + 1)) else printf "%s\0" "$line" >> "$FILES" case "$line" in */*) mkdir -p "${line%/*}" ;; esac filesn=$((filesn + 1)) fi done < "$TMP" reta=0 retb=0 if [ $dirsn -gt 0 ]; then xargs -0 -I{} mkdir -p {} < "$DIRS" reta=$? fi if [ $filesn -gt 0 ]; then xargs -0 -I{} touch {} < "$FILES" retb=$? fi rm -f -- "$TMP" "$FILES" "$DIRS" 2>/dev/null if [ $dirsn -eq 0 ] && [ $filesn -eq 0 ]; then echo "clifm: Nothing to do" exit 0 fi if [ $reta -eq 0 ] && [ $retb -eq 0 ]; then echo "rf" > "$CLIFM_BUS" exit 0 fi exit 1 clifm-1.26.3/plugins/bm_import.sh000077500000000000000000000030161506632037700167160ustar00rootroot00000000000000#!/bin/sh # Clifm plugin to import bookmarks from either Ranger or Midnight Commander # Description: Import Ranger/MC bookmarks from FILE # Author: L. Abramovich # License: GPL2+ if [ -z "$1" ] || [ "$1" = "--help" ] || [ "$1" = "-h" ]; then name="${CLIFM_PLUGIN_NAME:-$(basename "$0")}" printf "Import Ranger or Midnight Commander bookmarks from FILE \x1b[1mUSAGE\x1b[0m\n %s FILE\n" "$name" exit 0 fi file="$(echo "$1" | sed 's/\\//g')" if ! [ -f "$file" ]; then printf "clifm: %s: No such file or directory\n" "$file" >&2 exit 1 fi if [ -z "$CLIFM" ] || ! [ -f "${CLIFM}/bookmarks.clifm" ]; then printf "Bookmarks file for Clifm not found\n" >&2 exit 1 fi clifm_bm="${CLIFM}/bookmarks.clifm" bmn=0 if grep -q ^"ENTRY " "$file"; then fm="mc" else fm="ranger" fi while read -r line; do if [ "$fm" = "mc" ]; then name="$(echo "$line" | awk '{print $2}' | sed 's/\"//g')" path="$(echo "$line" | awk '{print $4}' | sed 's/\"//g')" else name="$(echo "$line" | cut -d':' -f1 2>/dev/null)" path="$(echo "$line" | cut -d':' -f2 2>/dev/null)" fi if [ -z "$name" ] || [ -z "$path" ]; then printf "clifm: %s: Bookmark cannot be imported\n" "$line" >&2 continue fi bmn=$((bmn + 1)) printf "[%s]%s\n" "$name" "$path" >> "$clifm_bm" done < "$file" if [ "$bmn" -gt 0 ]; then printf "clifm: %d bookmark(s) successfully imported\n" "$bmn" if [ -n "$CLIFM_BUS" ]; then echo "bm reload" > "$CLIFM_BUS" else printf "Restart CliFM for changes to take effect\n" fi else printf "clifm: No bookmarks imported\n" fi exit 0 clifm-1.26.3/plugins/clip.sh000077500000000000000000000054651506632037700156670ustar00rootroot00000000000000#!/bin/sh # Clipboard plugin for clifm # Author: L. Abramovich # License: GPL2+ # Dependencies: # xclip | xsel (Linux) # wl-copy/wl-paste (Wayland) # clipboard (Haiku) # clip (Cygwin) # pbcopy/pbget (MacOS) # termux-clipboard-set/termux-clipboard-get (Termux) # cb (cross-platform: https://github.com/Slackadays/Clipboard) # Use the 'e,export' parameter to send selected files to the system clipboard (new line separated list), # and the 'i,import' parameter to import files (new line separated list) in the clipboard to the Selection box get_from_clip() { if type cb >/dev/null 2>&1; then cb | cat 2>/dev/null # slackadays implementation elif [ -n "$WAYLAND_DISPLAY" ]; then wl-paste 2>/dev/null elif type xclip >/dev/null 2>&1; then xclip -sel clip -o 2>/dev/null elif type xsel >/dev/null 2>&1; then xsel -bo 2>/dev/null elif type pbpaste >/dev/null 2>&1; then # MacOS pbpaste 2>/dev/null elif type termux-clipboard-get >/dev/null 2>&1; then termux-clipboard-get 2>/dev/null elif type clipboard >/dev/null 2>&1; then # Haiku clipboard --print 2>/dev/null elif [ -r /dev/clipboard ]; then # Cygwin cat /dev/clipboard fi } send_to_clip() { if type cb >/dev/null 2>&1; then cb --copy < "$CLIFM_SELFILE" # slackadays implementation elif [ -n "$WAYLAND_DISPLAY" ]; then wl-copy < "$CLIFM_SELFILE" elif type xclip >/dev/null 2>&1; then xclip -sel clip "$CLIFM_SELFILE" elif type xsel >/dev/null 2>&1; then xsel -bi < "$CLIFM_SELFILE" elif type pbcopy >/dev/null 2>&1; then # MacOS pbcopy < "$CLIFM_SELFILE" elif type termux-clipboard-set >/dev/null 2>&1; then termux-clipboard-set < "$CLIFM_SELFILE" elif type clipboard >/dev/null 2>&1; then # Haiku clipboard --stdin < "$CLIFM_SELFILE" elif type clip >/dev/null 2>&1; then # Cygwin clip < "$CLIFM_SELFILE" fi } print_help() { name="${CLIFM_PLUGIN_NAME:-$(basename "$0")}" printf "Interact with the system clipboard\n" printf "\n\x1b[1mUSAGE\x1b[0m\n %s [e, export] [i, import]\n" "$name" printf "\nUse the 'e, export' parameter to send selected files to the system clipboard (as a newline separated list of entries), and the 'i, import' parameter to import files (as a newline separated list) from the system clipboard to Clifm's Selection Box\n" } if [ -z "$1" ] || [ "$1" = "--help" ] || [ "$1" = "-h" ] ; then print_help exit 0 fi case $1 in "e"|"export") if ! [ -f "$CLIFM_SELFILE" ]; then printf "clifm: No selected files\n" >&2 exit 0 fi send_to_clip ;; "i"|"import") shift 1 files=$(get_from_clip) if [ -z "$files" ]; then printf "clifm: Empty clipboard\n" 2>&1 exit 0 fi for file in $files; do if ! [ -e "$file" ]; then printf "clifm: %s: No such file or directory\n" "$file" 2>&1 exit 1; fi done printf "%s" "$files" >> "$CLIFM_SELFILE" ;; *) print_help exit 1 ;; esac exit 0 clifm-1.26.3/plugins/colors.sh000077500000000000000000000031271506632037700162320ustar00rootroot00000000000000#!/bin/sh # Terminal colors test script for Clifm # Written by L. Abramovich # License GPL2+ name="${CLIFM_PLUGIN_NAME:-$(basename "$0")}" USAGE="Usage: $name [16, 256, test]" if [ "$1" = "--help" ] || [ "$1" = "-h" ]; then printf "Terminal colors test script for Clifm\n" printf "\n\x1b[1mUSAGE\x1b[0m\n %s [16, 256, test]\n" "$name" exit 1 fi opt="${1:-test}" if [ "$opt" = "256" ]; then printf "256 Colors\n" for fgbg in $(seq 38 48) ; do for color in $(seq 0 256); do #Colors for attr in 0 1 2 4 5 7; do printf "\e[%s;%s;5;%sm%s;%s;5;%s\e[0;39;49m " "${attr}" "${fgbg}" "${color}" "${attr}" "${fgbg}" "${color}" done echo done echo done elif [ "$opt" = "16" ]; then printf "16 colors\n" for clbg in $(seq 40 47) $(seq 100 107) 49 ; do for clfg in $(seq 30 37) $(seq 90 97) 39 ; do for attr in 0 1 2 4 5 7 ; do printf "\e[%s;%s;%sm%s;%s;%s\e[0;39;49m " "${attr}" "${clbg}" "${clfg}" "${attr}" "${clbg}" "${clfg}" done printf "\n" done done elif [ "$opt" = "test" ]; then printf "The word 'test' should be printed in green (using the current terminal background color as background color). If not, then X colors are not supported by this terminal (emulator).\n" printf "8 colors (3-bit)\n" printf "\e[00;32mtest\e[0m\n\n" printf "16 colors (4-bit)\n" printf "\e[00;32mtest\e[0m\n\n" printf "256 colors (8-bit)\n" printf "\e[00;38;5;2mtest\e[0m\n\n" printf "RGB, true colors (24-bit)\n" printf "\e[00;38;2;20;170;0mtest\e[0m\n\n" else printf "%s\n" "$USAGE" >&2 exit 1 fi exit 0 clifm-1.26.3/plugins/cprm.sh000077500000000000000000000066231506632037700156760ustar00rootroot00000000000000#!/bin/sh # Description: Send a regular file or directory to a remote machine # Dependencies: fzf, and one of these: scp, ffsend, croc # Author: L. Abramovich # License: GPL2+ if [ -z "$1" ] || [ "$1" = "--help" ] || [ "$1" = "-h" ]; then name="${CLIFM_PLUGIN_NAME:-$(basename "$0")}" printf "Copy a regular file or directory to a remote machine \x1b[1mUSAGE\x1b[0m\n %s [-e, --edit] [FILE/DIR]\n" "$name" exit 0 fi CONFIG_FILE="${XDG_CONFIG_HOME:-${HOME}/.config}/clifm/plugins/cprm.cfg" if ! [ -f "$CONFIG_FILE" ]; then echo "### cprm configuration file #### # Ex: # See scp(1) for information about scp options #[Desktop machine] #Options=\"-P 1046\" #Target=\"user@192.168.0.23:\" # #[Android phone] #Options=\"-P 2222 -o HostKeyAlgorithms=+ssh-dss\" #Target=\"android@192.168.0.24:/storage/emulated/0/Download\" # #[Termux] #Options=\"-P 8022\" #Target=\"u0_a155@192.168.0.152:\" # # Just install ffsend. You'll get a download link # Do not alter this remote name #[ffsend] #Options=\"--downloads 1 --copy\" #Target=\"\" # # Just install croc. You'll get a download code # Do not alter this remote name #[croc] #Options=\"\" #Target=\"\"" > "$CONFIG_FILE" fi if ! type fzf >/dev/null 2>&1; then printf "clifm: fzf: Command not found\n" >&2 exit 127 fi if [ "$1" = "-e" ] || [ "$1" = "--edit" ]; then if "${EDITOR:-nano}" "$CONFIG_FILE"; then exit 0 fi exit 1 fi if [ -n "$2" ]; then printf "Multiple files are not allowed. To copy more than one file, either archive them (via 'ac') or move them \ to a single directory (then use that directory here).\n" exit 1 fi file="$(echo "$1" | sed 's/\\//g')" is_dir=0 if [ -e "$file" ]; then [ -d "$file" ] && is_dir=1 else printf "%s: No such file or directory\n" "$file" >&2 exit 2 fi # Source our plugins helper if [ -z "$CLIFM_PLUGINS_HELPER" ] || ! [ -f "$CLIFM_PLUGINS_HELPER" ]; then printf "clifm: Unable to find plugins-helper file\n" >&2 exit 1 fi # shellcheck source=/dev/null . "$CLIFM_PLUGINS_HELPER" remotes="$(grep "^\[" "$CONFIG_FILE" | tr -d '[]')" if [ -z "$remotes" ]; then printf "No remotes found. Use the -e option to edit the configuration \ file\n" >&2 exit 1 fi remotes_num="$(echo "$remotes" | grep -c '^')" remotes_num="$((remotes_num + 2))" # shellcheck disable=SC2154 remote="$(printf "%s" "$remotes" | fzf \ --ansi --prompt "$fzf_prompt" \ --reverse --height "$remotes_num" --info=inline \ --header "Choose a remote" \ --bind "tab:accept" --info=inline --color="$(get_fzf_colors)")" [ -z "$remote" ] && exit 0 opts="$(grep -A2 "$remote" "$CONFIG_FILE" | grep ^"Options" \ | cut -d= -f2-10 | sed 's/\"//g')" target="$(grep -A2 "$remote" "$CONFIG_FILE" | grep ^"Target" \ | cut -d= -f2 | sed 's/\"//g')" ##### FFSEND ##### if [ "$remote" = "ffsend" ]; then if ! type ffsend >/dev/null 2>&1; then printf "clifm: ffsend: Command not found\n" >&2 exit 127 else # shellcheck disable=SC2086 ffsend upload $opts "$file" && exit 0 exit 1 fi fi ##### CROC ##### if [ "$remote" = "croc" ]; then if ! type croc >/dev/null 2>&1; then printf "clifm: croc: Command not found\n" >&2 exit 127 else croc send "$file" && exit 0 exit 1 fi fi ##### SCP ##### if ! type scp >/dev/null 2>&1; then printf "clifm: scp: Command not found\n" >&2 exit 127 fi if [ -z "$target" ]; then printf "No target specified\n" >&2; exit 1 fi if [ "$is_dir" -eq 1 ]; then opts="-r $opts" fi # shellcheck disable=SC2086 scp $opts "$file" "$target" && exit 0 exit 1 clifm-1.26.3/plugins/decrypt.sh000077500000000000000000000034321506632037700164020ustar00rootroot00000000000000#!/bin/sh # Files decryption plugin for Clifm # Decrypt a file passed as parameter using gpg(1) # Author: L. Abramovich # License: GPL2+ # Dependencies: gpg, tar, sed, grep if [ -z "$1" ] || [ "$1" = "--help" ] || [ "$1" = "-h" ]; then name="${CLIFM_PLUGIN_NAME:-$(basename "$0")}" printf "Decrypt a GnuPG encrypted file\n" >&2 printf "\n\x1b[1mUSAGE\x1b[0m\n %s FILE\n\n" "$name" >&2 printf "Note: You will be given the options to extract the unencrypted\n\ file (if archived) and then to remove the original encrypted file\n" >&2 exit 0 fi if [ -n "$2" ]; then printf "clifm: Only one file can be decrypted at a time\n" >&2 exit 1 fi # 1. Check deps if ! type gpg >/dev/null 2>&1; then printf "clifm: gpg: Command not found\n" >&2 exit 127 fi if ! type tar >/dev/null 2>&1; then printf "clifm: tar: Command not found\n" >&2 exit 127 fi if ! type sed >/dev/null 2>&1; then printf "clifm: sed: Command not found\n" >&2 exit 127 fi if ! type grep >/dev/null 2>&1; then printf "clifm: grep: Command not found\n" >&2 exit 127 fi # Fix backspace when taking input via read stty erase ^H # 2. Decrypt the file file="$(echo "$1" | sed 's/\\//g')" case "$file" in *".gpg") if ! gpg --decrypt --output "${file}.dec" "$file"; then exit 1 fi if echo "$file" | grep -q "\.tar"; then while [ "$answer" != "y" ] && [ "$answer" != "n" ]; do printf "Extract tar archive? [y/n] " read -r answer done if [ "$answer" = "y" ]; then tar -xf "${file}.dec" rm -f -- "${file}.dec" fi fi ;; *) printf "clifm: %s: Not a GnuPG encrypted file\n" "$file" >&2 exit 1 ;; esac while [ "$answer" != "y" ] && [ "$answer" != "n" ]; do printf "Remove original encrypted file? [y/n] " read -r answer done if [ "$answer" = "y" ]; then rm -rf -- "$file" fi echo "rf" > "$CLIFM_BUS" exit 0 clifm-1.26.3/plugins/disk_analyzer.sh000077500000000000000000000070661506632037700175760ustar00rootroot00000000000000#!/bin/sh # Disk usage analyzer plugin for Clifm # Written by L. Abramovich # License: GPL2+ # Description: Navigate the filesystem with FZF and display directories size. # Dependencies: du, fzf, grep # Usage: # Left: go to parent directory # Right, Enter: cd into hovered directory or open hovered file and exit. # Home/end: go to first/last file # TAB: Select files # Ctrl-s: Confirm selection: send selected files to Clifm's Selbox # Shift+up/down: Move one line up/down in the preview window # Alt+up/down: Move to the beginning/end in the preview window # Press Esc or Ctrl-q to exit. if [ -n "$1" ] && { [ "$1" = "--help" ] || [ "$1" = "-h" ]; }; then name="${CLIFM_PLUGIN_NAME:-$(basename "$0")}" printf "Analiyze disk usage via du and FZF\n" printf "\n\x1b[1mUSAGE\x1b[0m\n %s [DIR]\n" "$name" exit 0 fi if ! type fzf > /dev/null 2>&1; then printf "clifm: fzf: Command not found\n" 2>&1 exit 127 elif ! type du > /dev/null 2>&1; then printf "clifm: du: Command not found\n" 2>&1 exit 127 fi HELP="Usage: Type in the prompt to filter the current list of files. Regular expressions are \ allowed. Keybindings: Left: go to parent directory Right or Enter: cd into hovered directory or open hovered file and exit Home/end: go to first/last file in the files list Shift-up/down: Move one line up/down in the preview window Alt-up/down: Move to the beginning/end in the preview window Esc/Ctrl-q: Exit" fcd() { if [ "$#" -ne 0 ]; then cd "$@" || return fi if type dircolors > /dev/null 2>&1; then dir_color="$(dircolors -c | grep -o "[\':]di=....." | cut -d';' -f2)" fi [ -z "$dir_color" ] && dir_color="34" # Source our plugins helper if [ -z "$CLIFM_PLUGINS_HELPER" ] || ! [ -f "$CLIFM_PLUGINS_HELPER" ]; then printf "clifm: Unable to find plugins-helper file\n" >&2 exit 1 fi # shellcheck source=/dev/null . "$CLIFM_PLUGINS_HELPER" _borders="$(fzf_borders)" _colors="$(get_fzf_colors)" # Keep FZF running until the user presses Esc or C-q while true; do lsd=$(printf "\033[0;%sm..\n" "$dir_color"; ls --color=always --group-directories-first --indicator-style=none -A .) # shellcheck disable=SC2154 file="$(printf "%s\n" "$lsd" | fzf \ --color="$_colors" --height "$fzf_height" \ --bind "right:accept,left:first+accept" \ --bind "insert:clear-query" \ --bind "home:first,end:last" \ --bind "alt-h:preview(printf %s \"$HELP\")" \ --bind "alt-p:toggle-preview" \ --bind "shift-up:preview-up" \ --bind "shift-down:preview-down" \ --bind "alt-up:preview-page-up" \ --bind "alt-down:preview-page-down" \ --bind "esc:abort" \ --bind "ctrl-q:abort" \ --ansi --prompt="$fzf_prompt" --reverse --no-clear \ --no-info --keep-right --multi --header="Press 'Alt-h' for help $PWD $FZF_HEADER" --marker="*" --preview-window=:wrap "$_borders" \ --preview="printf \"Total: \"; du $DU_OPTS1 {} 2>/dev/null | cut -f1; du $DU_OPTS2 {}/* 2>/dev/null | sort $SORT_OPTS")" # If FZF returned no file, exit [ ${#file} -eq 0 ] && return 0 # If the returned file is a directory, just cd into it. Otherwise, exit if [ -d "${PWD}/$file" ]; then cd "$file" || return fi done } main() { if ! type fzf > /dev/null 2>&1; then printf "clifm: fzf: Command not found\n" >&2 exit 127 fi OS="$(uname -s)" if [ "$OS" = "NetBSD" ]; then # NetBSD sort(1) cannot sort human readable sizes (-h) export DU_OPTS1="-s" export DU_OPTS2="-d0" export SORT_OPTS="-nr" else export DU_OPTS1="-hs" export DU_OPTS2="-hd0" export SORT_OPTS="-hr" fi fcd "$@" } main "$@" # Erase the FZF window _lines="${LINES:-100}" printf "\033[%dM" "$_lines" exit 0 clifm-1.26.3/plugins/dragondrop.sh000077500000000000000000000031201506632037700170610ustar00rootroot00000000000000#!/bin/sh # Drag and drop plugin for Clifm # Written by L. Abramovich # License: GPL2+ # Description: # With no arguments, it opens a window to drop files; otherwise, files # passed as arguments are send to the Dragon window to be dragged onto # somewhere else. # # Files dropped remotely are first downloaded via cURL into the CWD and # then sent to the SelBox, whereas files dropped locally are directly # sent to the SelBox. # Dependencies: # dragon (https://github.com/mwh/dragon), grep, sed, curl, xargs, tr if [ -n "$1" ] && { [ "$1" = "--help" ] || [ "$1" = "-h" ]; }; then name="${CLIFM_PLUGIN_NAME:-$(basename "$0")}" printf "Drag and drop files\n" printf "\n\x1b[1mUSAGE\x1b[0m\n %s [FILE... n]\n" "$name" printf "\nWith no arguments, it opens a window to drop files (using dragon). Otherwise, files passed as arguments are sent to the Dragon window to be dragged onto somewhere else.\n" exit 0 fi DRAGON="" if type dragon-drag-and-drop >/dev/null 2>&1; then DRAGON="dragon-drag-and-drop" elif type dragon >/dev/null 2>&1; then DRAGON="dragon" else printf "clifm: Neither dragon nor dragon-drag-and-drop were found. Exiting...\n" >&2 exit 1 fi if [ -z "$1" ]; then ret=$($DRAGON --print-path --target | while read -r r; do if printf "%s\n" "$r" \ | grep -q '^\(https\?\|ftps\?\|s\?ftp\):\/\/'; then curl -LJO "$r" printf "%s\n" "$PWD/$(basename "$r")" >> "$CLIFM_SELFILE" else printf "%s\n" "$r" >> "$CLIFM_SELFILE" fi done) [ "$ret" = 0 ] && exit 0 exit 1 else echo "$@" | sed 's/\\ /\t/g;s/ /\n/g;s/\t/ /g;s/\\//g' | tr \\n \\0 | xargs -0 "$DRAGON" exit "$?" fi clifm-1.26.3/plugins/encrypt.sh000077500000000000000000000071101506632037700164110ustar00rootroot00000000000000#!/bin/sh # Files encryption plugin for Clifm # Encrypt files passed as parameters using gpg(1) # Authors: KlzXS, L. Abramovich # License: GPL2+ # Dependencies: gpg, tar, sed, fzf, awk, xargs if [ -z "$1" ] || [ "$1" = "--help" ] || [ "$1" = "-h" ]; then name="${CLIFM_PLUGIN_NAME:-$(basename "$0")}" printf "Encrypt one or more files and/or directories using GnuPG\n" >&2 printf "\n\x1b[1mUSAGE\x1b[0m\n %s FILE...\n\n" "$name" >&2 printf "Note: Files are first archived into a single file via \x1b[1mtar\x1b[0m(1) and \n\ then encrypted with \x1b[1mgpg\x1b[0m(1), using either a passphrase or a public key.\n\ You will be given the option to remove original files.\n" >&2 exit 0 fi # 1. Check deps if ! type gpg >/dev/null 2>&1; then printf "clifm: gpg: Command not found\n" >&2 exit 127 fi if ! type tar >/dev/null 2>&1; then printf "clifm: tar: Command not found\n" >&2 exit 127 fi if ! type sed >/dev/null 2>&1; then printf "clifm: sed: Command not found\n" >&2 exit 127 fi if ! type xargs >/dev/null 2>&1; then printf "clifm: xargs: Command not found\n" >&2 exit 127 fi # Fix backspace when taking input via read stty erase ^H # 2. Get destination file if [ -n "$2" ]; then while [ "$out_file" = "" ]; do printf "Destiny file ('q' to quit): " >&2 read -r out_file done else out_file="$(echo "$1" | sed 's/\\ /_/g')" fi if [ -z "$out_file" ] || [ "$out_file" = "q" ]; then exit 0 fi file="${out_file}.tar" if [ -e "${file}.gpg" ]; then printf "clifm: %s: File exists\n" "${file}.gpg" >&2 exit 1 fi files="$(echo "$@" | sed 's/\\ /\t/g;s/ /\n/g;s/\t/ /g;s/\\//g')" if ! echo "$files" | xargs -I{} tar -rf "$file" {}; then rm -rf -- "$file" exit 1 fi while [ "$method" != "p" ] && [ "$method" != "k" ] && [ "$method" != "q" ]; do printf "Encrypt with passphrase, key, or quit? [p/k/q] " read -r method done if [ "$method" = "q" ]; then rm -f -- "$file" exit 0 fi # 3. Encrypt if [ "$method" = "p" ]; then # a. Symmetric encryption - Passphrase if gpg --symmetric "$file"; then rm -f -- "$file" fi else # b. Asymmetric encryption - Key if ! type fzf >/dev/null 2>&1; then printf "clifm: fzf: Command not found\n" >&2 exit 127 fi if ! type awk >/dev/null 2>&1; then printf "clifm: awk: Command not found\n" >&2 exit 127 fi # Source our plugins helper if [ -z "$CLIFM_PLUGINS_HELPER" ] || ! [ -f "$CLIFM_PLUGINS_HELPER" ]; then printf "clifm: Unable to find plugins-helper file\n" >&2 exit 1 fi # shellcheck source=/dev/null . "$CLIFM_PLUGINS_HELPER" # The recipient code has been taken from KlzXS (https://github.com/jarun/nnn/blob/master/plugins/gpge) and modified to fit our needs keyids=$(gpg --list-public-keys --with-colons | grep -E "pub:(.*:){10}.*[eE].*:" | awk -F ":" '{print $5}') #shellcheck disable=SC2016 keyuids=$(printf "%s" "$keyids" | xargs -I{} sh -c 'gpg --list-key --with-colons "{}" | grep "uid" | awk -F ":" '\''{printf "%s %s\n", "{}", $10}'\''') l=$(echo "$keyuids" | wc -l) # shellcheck disable=SC2154 recipient=$(printf "%s" "$keyuids" | \ fzf --reverse --info=inline --height $((l + 2)) --color "$(get_fzf_colors)" \ --prompt "$fzf_prompt" --header "Select a key ID" | \ awk '{print $1}') if [ -z "$recipient" ] || [ "$recipient" = "" ]; then rm -f -- "$file" exit 0 fi if ! gpg --encrypt --recipient "$recipient" "$file"; then rm -f -- "$file" exit 1 fi rm -f -- "$file" fi while [ "$answer" != "y" ] && [ "$answer" != "n" ]; do printf "Remove original files? [y/n] " >&2 read -r answer done if [ "$answer" = "y" ]; then printf "%s" "$files" | xargs -I{} rm -rf -- {} fi echo "rf" > "$CLIFM_BUS" exit 0 clifm-1.26.3/plugins/fdups.sh000077500000000000000000000112131506632037700160450ustar00rootroot00000000000000#!/bin/sh # Plugin to find/remove duplicate files for Clifm # # Usage: fdups.sh [DIR] # # Description: List non-empty duplicate files (based on size and followed # by MD5) in DIR (current directory if omitted) and allow the user to remove # one or more of them # # Dependencies: # find md5sum sort uniq xargs sed stat (on Linux/Haiku) # gfind md5 sort guniq xargs sed stat (on BSD/MacOS/SunOS) # # On BSD/MacOS/SunOS you need to install both coreutils (for guniq) # and findutils (for gfind) # # Notes: # If the file size exceeds SIZE_DIGITS digits the file will be misplaced. # (12 digits amount to sizes up to 931GiB) # # Based on https://github.com/jarun/nnn/blob/master/plugins/dups and modified # to fit our needs # # Authors: syssyphus, KlzXS, leo-arch, danfe # License: GPL3 me="clifm" OS="$(uname)" case "$OS" in Linux|Haiku) FIND="find" MD5="md5sum" UNIQ="uniq" STAT="stat -c %Y" ;; FreeBSD|NetBSD|OpenBSD|DragonFly|Darwin|SunOS) FIND="gfind" if [ "$OS" = "NetBSD" ]; then MD5="md5 -n" else MD5="md5 -r" fi UNIQ="guniq" STAT="stat -f %m" ;; *) printf "%s: This plugin is not supported on $OS\n" "$me" >&2 exit 1 esac no_dep=0 if ! type "$FIND" > /dev/null 2>&1; then printf "%s: %s: command not found\n" "$me" "$FIND" >&2; no_dep=1 elif ! type "${MD5%% *}" > /dev/null 2>&1; then printf "%s: %s: command not found\n" "$me" "${MD5%% *}" >&2; no_dep=1 elif ! type sort > /dev/null 2>&1; then printf "%s: sort: command not found\n" "$me" >&2; no_dep=1 elif ! type "$UNIQ" > /dev/null 2>&1; then printf "%s: %s: command not found\n" "$me" "$UNIQ" >&2; no_dep=1 elif ! type xargs > /dev/null 2>&1; then printf "%s: xargs: command not found\n" "$me" >&2; no_dep=1 elif ! type sed > /dev/null 2>&1; then printf "%s: sed: command not found\n" "$me" >&2; no_dep=1 elif ! type "${STAT%% *}" > /dev/null 2>&1; then printf "%s: %s: command not found\n" "$me" "${STAT%% *}" >&2; no_dep=1 fi [ "$no_dep" = 1 ] && exit 127 if [ "$1" = "-h" ] || [ "$1" = "--help" ]; then name="${CLIFM_PLUGIN_NAME:-$(basename "$0")}" printf "List non-empty duplicated files in DIR (current directory \ if omitted) and allow the user to selectively delete them\n" printf "\n\x1b[1mUSAGE\x1b[0m\n %s [DIR]\n" "$name" exit 0 fi if [ -n "$1" ] && ! [ -d "$1" ]; then printf "%s: %s: Not a directory\n" "$me" "$1" >&2 exit 1 fi dir="${1:-.}" # The find command below fails when file names contain single quotes # Let's warn the user SQF="$($FIND "$dir" -type f -name "*'*")" if [ -n "$SQF" ]; then #if $FIND "$dir" -type f -name "*'*"; then printf "Warning: Some files in this directory contain single quotes in their names.\n\ Rename them or they will be ignored.\n\n\ TIP: You can use the 'br' command to rename them in bulk:\n\ s *\\\'*\n\ br sel\n\n\ Ignore these files and continue? [y/N] " read -r answer if [ "$answer" != "y" ] && [ "$answer" != "Y" ]; then exit 0 fi echo "" fi _EDITOR="${EDITOR:-nano}" TMP_DIR="${TMPDIR:-/tmp}" tmp_file=$(mktemp "$TMP_DIR/.${me}XXXXXX") size_digits=12 printf "\ ## This is a list of all duplicates found (if empty, just exit). ## Comment out the files you want to remove (lines starting with double number ## sign (##) are ignored. ## Save and close this file to remove commented files (deletion approval will ## be asked before removing files) ## Files can be removed either forcefully or interactively.\n " > "$tmp_file" # shellcheck disable=SC2016 $FIND "$dir" -size +0 -type f -printf "%${size_digits}s %p\n" | sort -rn | $UNIQ -w"${size_digits}" -D \ | sed -e "s/^ \{0,12\}\([0-9]\{0,12\}\) \(.*\)\$/printf '%s %s\\\n' \"\$($MD5 '\2')\" 'd\1'/" \ | tr '\n' '\0' | xargs -0 -n1 -r sh -c 2>/dev/null | sort | { $UNIQ -w32 --all-repeated=separate; echo; } \ | sed -ne 'h s/^\(.\{32\}\).* d\([0-9]*\)$/## md5sum: \1 size: \2 bytes/p g :loop N /.*\n$/!b loop p' \ | sed -e 's/^.\{32\} *\(.*\) d[0-9]*$/\1/' >> "$tmp_file" time_pre="$($STAT "$tmp_file")" "$_EDITOR" "$tmp_file" time_post="$($STAT "$tmp_file")" if [ "$time_pre" = "$time_post" ]; then printf "%s: Nothing to do\n" "$me" exit 0 fi printf "Note: If you answer is yes, you will be given the option to remove them interactively\n\ Remove commented files? [y/N] " read -r answer if [ "$answer" = "y" ] || [ "$answer" = "Y" ]; then sedcmd="/^##.*/d; /^[^#].*/d; /^$/d; s/^# *\(.*\)$/\1/" else exit 0 fi printf "Remove files forcefully or interactively? [f/I] " read -r force if [ "$force" = "f" ] || [ "$force" = "F" ]; then #shellcheck disable=SC2016 sed -e "$sedcmd" "$tmp_file" | tr '\n' '\0' | xargs -0 -r sh -c 'rm -f "$0" "$@" &2 printf "Select files via Clifm. At exit, selected files are written to STDOUT, or to FILE if specified\n" >&2 exit 0 fi [ -z "$CLIFM_TERM" ] && CLIFM_TERM="xterm" SEL_FILE="$1" [ -z "$SEL_FILE" ] && SEL_FILE=$(mktemp "${TMPDIR:-/tmp}/clifm_sel.XXXXXX") $CLIFM_TERM -e clifm --sel-file="$SEL_FILE" ! [ -f "$SEL_FILE" ] && exit 0 if [ -z "$1" ]; then cat -- "$SEL_FILE" rm -- "$SEL_FILE" fi exit 0 clifm-1.26.3/plugins/finder.sh000077500000000000000000000034551506632037700162040ustar00rootroot00000000000000#!/bin/sh # Clifm plugin to find/open/cd files using FZF/Rofi # Written by L. Abramovich # License GPL2+ # Dependencies: fzf or rofi, and sed SUCCESS=0 ERROR=1 if [ -n "$1" ] && { [ "$1" = "--help" ] || [ "$1" = "-h" ]; }; then name="${CLIFM_PLUGIN_NAME:-$(basename "$0")}" printf "Find/open/cd files using FZF/Rofi. Once found, press Enter to cd/open the desired file.\n" printf "\n\x1b[1mUSAGE\x1b[0m\n %s [DIR]\n" "$name" printf "\nNote: If DIR is not specified, the current directory is assumed\n" exit $SUCCESS fi if type fzf > /dev/null 2>&1; then finder="fzf" elif type rofi > /dev/null 2>&1; then finder="rofi" else printf "clifm: No finder found. Install either FZF or Rofi\n" >&2 exit $ERROR fi OS="$(uname -s)" if [ -z "$OS" ]; then printf "clifm: Unable to detect operating system\n" >&2 exit $ERROR fi # Source our plugins helper if [ -z "$CLIFM_PLUGINS_HELPER" ] || ! [ -f "$CLIFM_PLUGINS_HELPER" ]; then printf "clifm: Unable to find plugins-helper file\n" >&2 exit 1 fi # shellcheck source=/dev/null . "$CLIFM_PLUGINS_HELPER" DIR="." if [ -n "$1" ]; then if [ -d "$1" ]; then DIR="$1"; else printf "clifm: %s: Not a directory\n" "$1" >&2 exit 1 fi fi case "$OS" in Linux) ls_cmd="ls -A --group-directories-first --color=always $DIR" ;; *) ls_cmd="ls -A $DIR" ;; esac if [ "$finder" = "fzf" ]; then # shellcheck disable=SC2012 # shellcheck disable=SC2154 FILE="$($ls_cmd | fzf --ansi --prompt "$fzf_prompt" \ --reverse --height "$fzf_height" --info=inline \ --header "Find files in the current directory" \ --bind "tab:accept" --info=inline --color="$(get_fzf_colors)")" else # shellcheck disable=SC2012 FILE="$(ls -A | rofi -dmenu -p clifm)" fi if [ -n "$FILE" ]; then f="$(echo "$FILE" | sed 's/ /\\ /g')" printf "open %s/%s\n" "$DIR" "$f" > "$CLIFM_BUS" fi exit $SUCCESS clifm-1.26.3/plugins/fzcd.sh000077500000000000000000000020121506632037700156470ustar00rootroot00000000000000#!/bin/sh # Directory change plugin for Clifm # Find and change directory using find and fzf # Author: Docbroke # License: GPL3 # Dependencies: fzf, find if [ "$1" = "-h" ] || [ "$1" = "--help" ]; then name="${CLIFM_PLUGIN_NAME:-$(basename "$0")}" printf "Find and change the current working directory via FZF\n" printf "\n\x1b[1mUSAGE\x1b[0m\n %s\n" "$name" exit 0 fi if ! type fzf > /dev/null 2>&1; then printf "%s" "clifm: fzf: Command not found\n" >&2 exit 127 fi # Source our plugins helper if [ -z "$CLIFM_PLUGINS_HELPER" ] || ! [ -f "$CLIFM_PLUGINS_HELPER" ]; then printf "clifm: Unable to find plugins-helper file\n" >&2 exit 1 fi # shellcheck source=/dev/null . "$CLIFM_PLUGINS_HELPER" # shellcheck disable=SC2154 DIR="$(find / -type d -print0 2> /dev/null | \ fzf --read0 --prompt "$fzf_prompt" \ --reverse --height "$fzf_height" --header "Fuzzy directory changer" \ --bind "tab:accept" --info=inline \ --color="$(get_fzf_colors)")" if [ -n "$DIR" ]; then printf "%s\n" "$DIR" > "$CLIFM_BUS" fi exit 0 clifm-1.26.3/plugins/fzfdesel.sh000077500000000000000000000047351506632037700165410ustar00rootroot00000000000000#!/bin/sh # FZF deselection plugin for Clifm # Description: Deselect currently selected files using FZF # Dependencies: fzf # Written by L. Abramovich # License: GPL2+ if [ -n "$1" ] && { [ "$1" = "--help" ] || [ "$1" = "-h" ]; }; then name="${CLIFM_PLUGIN_NAME:-$(basename "$0")}" printf "Deselect Clifm selected files using FZF\n" printf "\n\x1b[1mUSAGE\x1b[0m\n %s\n" "$name" exit 0 fi if ! [ -f "$CLIFM_SELFILE" ]; then printf "clifm: No selected files\n" >&2 exit 1 fi if ! type fzf > /dev/null 2>&1; then printf "clifm: fzf: Command not found\n" >&2 exit 127 fi # Source our plugins helper if [ -z "$CLIFM_PLUGINS_HELPER" ] || ! [ -f "$CLIFM_PLUGINS_HELPER" ]; then printf "clifm: Unable to find plugins-helper file\n" >&2 exit 1 fi # shellcheck source=/dev/null . "$CLIFM_PLUGINS_HELPER" HELP="Usage: Alt-h: Toggle this help screen TAB, Alt-down: Select + down Alt-up: Select + up Ctrl-s: Select all files Ctrl-d: Deselect all files Ctrl-t: Toggle selection Enter: Confirm and deselect all selected files Esc: Cancel and exit" TMPFILE=$(mktemp "${TMPDIR:-/tmp}/clifm_desel.XXXXXX") # shellcheck disable=SC2154 fzf --multi --marker='*' --info=inline \ --height="$fzf_height" --keep-right \ --bind "alt-down:toggle+down" \ --bind "alt-up:toggle+up" \ --bind "ctrl-s:select-all,ctrl-d:deselect-all,ctrl-t:toggle-all" \ --bind "alt-h:toggle-preview" --preview-window=:wrap \ --preview "printf %s \"$HELP\"" \ --color="$(get_fzf_colors)" \ --header "Deselect selected files" \ --reverse "$(fzf_borders)" --no-sort --ansi --prompt "$fzf_prompt" > "$TMPFILE" \ < "$CLIFM_SELFILE" # If no file was marked for deselection (that is, if TMPFILE is empty), exit if ! [ -s "$TMPFILE" ]; then rm -f -- "$TMPFILE" > /dev/null 2>&1 exit 0 fi # shellcheck disable=SC1007 #while ISF= read -r line; do # safe_line=$(printf '%s\n' "$line" | sed 's/[[\.*_^$/]/\\&/g') # sed "${safe_line}d" "$CLIFM_SELFILE" #done < "$TMPFILE" BK_FILE=$(mktemp "${TMPDIR:-/tmp}/clifm_sel.XXXXXX") # shellcheck disable=SC1007 while IFS= read -r sel_line; do remove=0 # shellcheck disable=SC1007 while ISF= read -r desel_line; do if [ "$sel_line" = "$desel_line" ]; then remove=1 break fi done < "$TMPFILE" if [ "$remove" = 0 ]; then printf "%s\n" "$sel_line" >> "$BK_FILE" fi done < "$CLIFM_SELFILE" rm -f -- "$TMPFILE" > /dev/null 2>&1 cp -u -- "$BK_FILE" "$CLIFM_SELFILE" > /dev/null 2>&1 rm -f -- "$BK_FILE" > /dev/null 2>&1 if [ -z "$DISPLAY" ]; then clear else tput clear fi exit 0 clifm-1.26.3/plugins/fzfhist.sh000077500000000000000000000020321506632037700164000ustar00rootroot00000000000000#!/bin/sh # Commands history plugin for Clifm # Dependencies: fzf, tac, sed, awk # Written by L. Abramovich # License GPL2+ if [ -n "$1" ] && { [ "$1" = "--help" ] || [ "$1" = "-h" ]; }; then name="${CLIFM_PLUGIN_NAME:-$(basename "$0")}" printf "Navigate/execute the Clifm commands history via FZF\n" printf "\n\x1b[1mUSAGE\x1b[0m\n %s\n" "$name" exit 0 fi if ! type fzf > /dev/null 2>&1; then printf "clifm: fzf: Command not found" >&2 exit 127 fi HIST_FILE="${XDG_CONFIG_HOME:=$HOME/.config}/clifm/profiles/$CLIFM_PROFILE/history.clifm" # Source our plugins helper if [ -z "$CLIFM_PLUGINS_HELPER" ] || ! [ -f "$CLIFM_PLUGINS_HELPER" ]; then printf "clifm: Unable to find plugins-helper file\n" >&2 exit 1 fi # shellcheck source=/dev/null . "$CLIFM_PLUGINS_HELPER" # shellcheck disable=SC2154 sed '/^#/d' "$HIST_FILE" | tac | awk '!x[$0]++' | fzf --prompt="$fzf_prompt" \ --reverse --height 15 --info=inline \ --bind "tab:accept" --header "Run a command from history" \ --color="$(get_fzf_colors)" > "$CLIFM_BUS" printf "\n" exit 0 clifm-1.26.3/plugins/fzfnav.sh000077500000000000000000000462741506632037700162350ustar00rootroot00000000000000#!/bin/sh # FZF navigation/previewing/selection plugin for Clifm # Written by L. Abramovich # License: GPL2+ # Description: Navigate the filesystem (including files preview and # selection) with FZF. # Previews are shown by just hovering on the file. Each generated preview, # provided it needs to be converted before (e.g. .gif, .pdf and .docx files), # is cached as image file(s) (using hashes as names) in # $HOME/.cache/clifm/previews to avoid subsequent convertions and speed up # thus the whole process. # A separate script is used for file previewing: # $HOME/.config/clifm/plugins/BFG.sh # A configuration file is available: # $HOME/.config/clifm/plugins/BFG.cfg # or # $XDG_DATA_DIRS/clifm/plugins/BFG.cfg (usually /usr/local/share/clifm/plugins/BFG.cfg) # How the files previewer works? # 1. The config file is read looking for predefined options and previewing # applications. # 2. Options not defined in the config file are set to the default value. # If no opening application for a given file type was defined in the # config file, the system is scanned for available applications. # NOTE: Determining previewing applications is done only once, when # when the fzfnav.sh script starts, instead of each time a file is # hovered, which saves a significant amount of time. # 3. Export this info as environment variables. # 4. Launch FZF using the BFG.sh script to generate files preview using # the information previosuly gathered. This script only takes care of # determining file types and executing the corresponding previewing # application. HELP="USAGE Type in the prompt to filter the current list of files. Regular expressions are \ allowed. Use the --edit command line option to edit the configuration file. KEYBINDINGS * Left: Change to parent directory * Right/Enter: Change to the highlighted directory or open the highlighted file * Home/end: Change to first/last file in the files list * TAB: Select currently highlighted file * Ctrl-s: Select all * Ctrl-d: Deselect all * Ctrl-t: Toggle selection * Alt-s: Confirm selection (do it before changing directory or the current selection will be lost) * Shift-up/down: Move one line up/down in the preview window * Alt-up/down: Move to the beginning/end in the preview window * Ctrl-q/Ctrl-c: Change to the last visited directory and exit * Esc: Cancel and exit" HOME_PLUGINS_DIR="${XDG_CONFIG_HOME:-$HOME/.config}/clifm/plugins" uz_cleanup() { # shellcheck disable=SC2317 rm -- "$FIFO_UEBERZUG" 2>/dev/null # shellcheck disable=SC2317 pkill -P $$ >/dev/null } # Let's get the path to a plugin file, either in home or in data dirs. # Used for both BFG.cfg and BFG.sh get_file() { [ -z "$1" ] && return name="$1" HOME_FILE="${HOME_PLUGINS_DIR}/$name" FILE="$HOME_FILE" if [ -z "$FILE" ] || ! [ -f "$FILE" ]; then FILE="" if [ -n "$XDG_DATA_DIRS" ]; then dirs="$(echo "$XDG_DATA_DIRS" | sed 's/:/ /g')" for dir in $dirs; do if [ -f "$dir/clifm/plugins/$name" ]; then FILE="$dir/clifm/plugins/$name" break fi done fi if [ -z "$FILE" ]; then if [ "$CLIFM_PLUGINS_HELPER" ]; then helper="$(dirname "$CLIFM_PLUGINS_HELPER")" fi if [ "$helper" ] && [ -f "$helper/$name" ]; then FILE="$helper/$name" elif [ -f "/usr/share/clifm/plugins/$name" ]; then FILE="/usr/share/clifm/plugins/$name" elif [ -f "/usr/local/share/clifm/plugins/$name" ]; then FILE="/usr/local/share/clifm/plugins/$name" elif [ -f "/boot/system/data/clifm/plugins/$name" ]; then FILE="/boot/system/data/clifm/plugins/$name" elif [ -f "/boot/system/non-packaged/data/clifm/plugins/$name" ]; then FILE="/boot/system/non-packaged/data/clifm/plugins/$name" elif [ -f "/data/data/com.termux/files/usr/share/clifm/plugins/$name" ]; then FILE="/data/data/com.termux/files/usr/share/clifm/plugins/$name" fi fi fi [ -n "$FILE" ] && printf "%s\n" "$FILE" } start_ueberzug() { mkfifo "$FIFO_UEBERZUG" tail -f "$FIFO_UEBERZUG" \ | ueberzug layer --silent --parser json > /dev/null 2>&1 & } fcd() { if [ "$#" -ne 0 ]; then cd "$@" || return fi if type dircolors > /dev/null 2>&1; then dir_color="$(dircolors -c | grep -o "[\':]di=....." | cut -d';' -f2)" fi [ -z "$dir_color" ] && dir_color="34" # Keep FZF running until the user presses Esc or C-q # shellcheck disable=SC2154 # --header-first isn't available in fzf 0.27 while true; do lsd=$(printf "\033[0;%sm..\033[0m\n" "$dir_color"; $ls_cmd) file="$(printf "%s\n" "$lsd" | fzf \ --height="${fzfheight:-$fzf_height}" \ --color="$(get_fzf_colors)" \ --bind "alt-s:execute(touch $TMP_SEL)+accept" \ --bind "ctrl-s:select-all,ctrl-d:deselect-all,ctrl-t:toggle-all" \ --bind "right:accept,left:top+accept" \ --bind "insert:clear-query" \ --bind "home:top,end:page-down" \ --bind "alt-h:preview(printf '{\"action\": \"remove\", \"identifier\": \"clifm-preview\"}\n' > \"$FIFO_UEBERZUG\"; printf %s \"$HELP\")" \ --bind "alt-p:toggle-preview" \ --bind "shift-up:preview-up" \ --bind "shift-down:preview-down" \ --bind "alt-up:preview-page-up" \ --bind "alt-down:preview-page-down" \ --bind "esc:execute(rm $TMP)+abort" \ --bind "ctrl-q:abort" \ --ansi --prompt="${fzf_prompt}" --reverse --no-clear \ --inline-info --keep-right --multi --header="Press 'Alt-h' for help $PWD $FZF_HEADER" --marker="*" --preview-window=:wrap "$(fzf_borders)" \ --preview "printf \"\033[2J\"; $BFG_FILE {}")" # If FZF returned no file, exit [ ${#file} -eq 0 ] && return 0 # If we have selected files, send them to the Clifm Selbox if [ -f "$TMP_SEL" ]; then echo "$file" > "$TMP_SEL" while read -r line; do if ! grep -q -s "$PWD/$line" "$CLIFM_SELFILE"; then printf "%s/%s\n" "$PWD" "$line" >> "$CLIFM_SELFILE" c=$((c+1)) fi done < "$TMP_SEL" rm -rf -- "$TMP_SEL" export FZF_HEADER="$c selected file(s)" continue fi # If the returned file is a directory, just cd into it. Otherwise, # open it via OPENER if [ -d "${PWD}/$file" ]; then [ -n "$CLIFM" ] && printf "cd %s" "${PWD}/$file" > "$TMP" cd "$file" || return elif [ -f "${PWD}/$file" ]; then if [ "$OPENER" = "clifm" ]; then clifm --open "${PWD}/$file" else "$OPENER" "${PWD}/$file" fi fi done } ###################### # MAIN FUNCTION # ###################### main() { if ! type fzf > /dev/null 2>&1; then printf "clifm: fzf: Command not found\n" >&2 exit 127 fi export TMP_SEL="${TMPDIR:-/tmp}/fzfnav.sel" rm -rf -- "$TMP_SEL" BFG_CFG_FILE="$(get_file BFG.cfg)" if [ -z "$BFG_CFG_FILE" ]; then printf "clifm: BFG.cfg: No such file or directory\n" >&2 exit 2 fi if ! [ -f "${HOME_PLUGINS_DIR}/BFG.cfg" ]; then cp -- "$BFG_CFG_FILE" "${HOME_PLUGINS_DIR}/BFG.cfg" 2>/dev/null BFG_CFG_FILE="${HOME_PLUGINS_DIR}/BFG.cfg" fi # Do we have GNU ls? if ls --version >/dev/null 2>&1; then export ls_cmd="ls -Ap --group-directories-first --color=always --indicator-style=none" export POSIX_LS=0 else export ls_cmd="ls -Ap" export POSIX_LS=1 fi # OpenBSD file(1) version has no --mime-encoding option [ "$(uname)" != "OpenBSD" ] && export FILE_HAS_MIME_ENCODING=1 ################################################# # 1. GET VALUES FROM THE CONFIGURATION FILE # ################################################# PREV_IMGS=1 PLAY_MUSIC=1 export ANIMATE_GIFS=1 export FALLBACK_INFO=1 while read -r LINE; do [ -z "$LINE" ] || [ "$(printf "%s" "$LINE" | cut -c1)" = "#" ] \ && continue option="$(printf "%s" "$LINE" | cut -d= -f1)" value="$(printf "%s" "$LINE" | cut -d= -f2 | tr -d "\"" )" case $option in # CHECK GENERAL OPTIONS FZFHEIGHT) if echo "$value" | grep -qE "[0-9]+"; then export fzfheight="$value" fi ;; BFG_FILE) if [ -z "$value" ]; then BFG_FILE="" else export BFG_FILE="$value" fi ;; CACHEDIR) if [ -z "$value" ]; then CACHEDIR="" else export CACHEDIR="$value" fi ;; PREVIEWDIR) if [ -z "$value" ]; then PREVIEDIR="" else export PREVIEDIR="$value" fi ;; OPENER) if [ -z "$value" ]; then OPENER="" else export OPENER="$value" fi ;; USE_SCOPE) [ "$value" = 1 ] && export USE_SCOPE=1 ;; SCOPE_FILE) if [ -z "$value" ]; then SCOPE_FILE="" else export OPENER="$value" fi ;; USE_PISTOL) [ "$value" = 1 ] && export USE_PISTOL=1 ;; PREVIEW_IMAGES) [ "$value" != 1 ] && PREV_IMGS=0 ;; PLAY_MUSIC) [ "$value" != 1 ] && PLAY_MUSIC=0 ;; ANIMATE_GIFS) [ "$value" != 1 ] && ANIMATE_GIFS=0 ;; FALLBACK_INFO) [ "$value" != 1 ] && FALLBACK_INFO=0 ;; # CHECK FILE TYPES ARCHIVES) ARCHIVES="$value" case "$value" in atool) export ARCHIVER_CMD="atool" export ARCHIVER_OPTS="-l" ;; bsdtar) export ARCHIVER_CMD="bsdtar" export ARCHIVER_OPTS="-tvf" ;; tar) export ARCHIVER_CMD="tar" export ARCHIVER_OPTS="-tvf" ;; none) ;; *) ARCHIVES="" ;; esac ;; BROWSER) case "$value" in w3m) export BROWSER="w3m" ;; elinks) export BROWSER="elinks" ;; linx) export BROWSER="linx" ;; cat) export CAT_OK=1 ;; none) export BROWSER="true";; *) BROWSER="" ;; esac ;; DDJVU) DDJVU="$value" case "$value" in ddjvu) export DDJVU_OK=1 ;; ddjvutxt) export DDJVU_OK=1 ;; none) ;; *) DDJVU="";; esac ;; DIR) case "$value" in tree) export DIR_CMD="tree" ;; ls) export DIR_CMD="ls" ;; exa) export DIR_CMD="exa" ;; exa-tree) export DIR_CMD="exa-tree" ;; lsd) export DIR_CMD="lsd" ;; lsd-tree) export DIR_CMD="lsd-tree" ;; none) export DIR_CMD="true" ;; *) DIR_CMD="" ;; esac ;; DOC) DOC="$value" case "$value" in libreoffice) export LIBREOFFICE_OK=1 ;; text) DOC="" && export DOCASTEXT=1 ;; none) ;; *) DOC="";; esac ;; EPUB) EPUB="$value" case "$value" in epub-thumbnailer) export EPUBTHUMB_OK=1 ;; none) ;; *) EPUB="";; esac ;; FILEINFO) FILEINFO="$value" case "$value" in exiftool) export EXIFTOOL_OK=1 ;; none) ;; *) FILEINFO="";; esac ;; FONTS) FONTS="$value" case "$value" in fontpreview) export FONTPREVIEW_OK=1 ;; fontimage) export FONTIMAGE_OK=1 ;; none) ;; *) FONTS="";; esac ;; IMG) case "$value" in ueberzug) export UEBERZUG_OK=1 ;; w3m|kitty|viu|catimg|img2txt|chafa|pixterm) export IMG_VIEWER="$value" ;; none) export IMG_VIEWER="true" ;; *) IMG_VIEWER="" ;; esac ;; JSON) JSON="$value" case "$value" in python) export PYTHON_OK=1 ;; jq) export JQ_OK=1 ;; cat) export CAT_OK=1 ;; none) ;; *) JSON="" ;; esac ;; MARKDOWN) MARKDOWN="$value" case "$value" in glow) export GLOW_OK=1 ;; mdcat) export MDCAT_OK=1 ;; cat) export CAT_OK=1 ;; none) ;; *) MARKDOWN="" ;; esac ;; MEDIAINFO) MEDIAINFO="$value" case "$value" in mediainfo) export MEDIAINFO_OK=1 ;; none) ;; *) MEDIAINFO="" ;; esac ;; MUSIC) MUSIC="$value" case "$value" in ffplay) export FFPLAY_OK=1 ;; mplayer) export MPLAYER_OK=1 ;; mpv) export MPV_OK=1 ;; none) ;; *) MUSIC="" ;; esac ;; PDF) PDF="$value" case "$value" in pdftoppm) export PDFTOPPM_OK=1 ;; pdftotext) export PDFTOTEXT_OK=1 ;; mutool) export MUTOOL_OK=1 ;; none) ;; *) PDF="" ;; esac ;; TEXT) TEXT="$value" case "$value" in bat) export BAT_OK=1 ;; highlight) export HIGHLIGHT_OK=1 ;; pygmentize) export PYGMENTIZE_OK=1 ;; cat) export CAT_OK=1 ;; none) ;; *) TEXT="" ;; esac ;; VIDEO) VIDEO="$value" case "$value" in ffmpegthumbnailer) export FFMPEGTHUMBN_OK=1 ;; none) ;; *) VIDEO="" ;; esac ;; esac done < "$BFG_CFG_FILE" export COLORS if type tput >/dev/null 2>&1; then COLORS="$(tput colors)" else COLORS="8" fi # if [ -z "$ls_cmd" ]; then # export ls_cmd="ls -Ap --group-directories-first --color=always --indicator-style=none" # fi # This is the previewer script, similar to Ranger's scope.sh if [ -z "$BFG_FILE" ]; then export BFG_FILE BFG_FILE="$(get_file BFG.sh)" if ! [ -f "$BFG_FILE" ]; then printf "clifm: BFG.sh: No such file or directory\n" >&2 exit 2 fi if ! [ -x "$BFG_FILE" ]; then printf "clifm: %s: Not an executable file\n" "$BFG_FILE" >&2 exit 1 fi fi [ -z "$OPENER" ] && export OPENER="clifm" [ -z "$PREVIEWDIR" ] && export PREVIEWDIR="${XDG_CACHE_HOME:-$HOME/.cache}/clifm/previews" ! [ -d "$PREVIEWDIR" ] && mkdir -p "$PREVIEWDIR" CACHEDIRTAG_HEADER="Signature: 8a477f597d28d172789f06886806bc55 # This file is a cache directory tag created by Clifm. # For information about cache directory tags, see: # http://www.brynosaurus.com/cachedir/" ! [ -f "$PREVIEWDIR/CACHEDIR.TAG" ] && echo "$CACHEDIRTAG_HEADER" > "$PREVIEWDIR/CACHEDIR.TAG" if [ "$USE_SCOPE" = 1 ]; then [ -z "$SCOPE_FILE" ] && export SCOPE_FILE="${XDG_CONFIG_HOME:-$HOME/.config}/ranger/scope.sh" fi # If some value was not set in the config file, check for available # applications ############################################### # 2. CHECK INSTALLED APPS # ############################################### # We check here, at startup, for available applications so that we # don't need to do it once and again each time a file is hovered # Directories if [ -z "$DIR_CMD" ]; then if type lsd > /dev/null 2>&1; then export DIR_CMD="lsd-tree" elif type exa > /dev/null 2>&1; then export DIR_CMD="exa-tree" elif type tree > /dev/null 2>&1; then export DIR_CMD="tree" else export DIR_CMD="ls" fi fi # Images if [ "$PREV_IMGS" = 1 ] && [ -z "$IMG_VIEWER" ] && \ [ -n "$DISPLAY" ]; then if [ -z "$WAYLAND_DISPLAY" ] && type ueberzug > /dev/null 2>&1; then export UEBERZUG_OK=1 elif [ "$TERM" = "xterm-kitty" ]; then export IMG_VIEWER="kitty" elif type pixterm > /dev/null 2>&1; then export IMG_VIEWER="pixterm" elif type viu > /dev/null 2>&1; then export IMG_VIEWER="viu" elif type catimg > /dev/null 2>&1; then export IMG_VIEWER="catimg" elif type chafa > /dev/null 2>&1; then export IMG_VIEWER="chafa" elif type img2txt > /dev/null 2>&1; then export IMG_VIEWER="img2txt" fi fi # Überzug is not run directly, but through a function if [ "$PREV_IMGS" = 1 ] && [ "$UEBERZUG_OK" = 1 ]; then export IMG_VIEWER="uz_image" fi # Archives if [ -z "$ARCHIVES" ]; then if type atool > /dev/null 2>&1; then export ARCHIVER_CMD="atool" export ARCHIVER_OPTS="-l" elif type bsdtar > /dev/null 2>&1; then export ARCHIVER_CMD="bsdtar" export ARCHIVER_OPTS="-tvf" elif type tar > /dev/null 2>&1; then export ARCHIVER_CMD="tar" export ARCHIVER_OPTS="-tvf" fi fi # Web if [ -z "$BROWSER" ]; then if type w3m > /dev/null 2>&1; then export BROWSER="w3m" elif type linx > /dev/null 2>&1; then export BROWSER="linx" elif type elinks > /dev/null 2>&1; then export BROWSER="elinks" fi fi # Music if [ "$PLAY_MUSIC" = 1 ] && [ -z "$MUSIC" ]; then if type ffplay > /dev/null 2>&1; then export FFPLAY_OK=1 elif type mplayer > /dev/null 2>&1; then export MPLAYER_OK=1 elif type mpv > /dev/null 2>&1; then export MPV_OK=1 fi fi # Video if [ -z "$VIDEO" ]; then if type ffmpegthumbnailer > /dev/null 2>&1; then export FFMPEGTHUMB_OK=1 fi fi # File information if [ -z "$FILEINFO" ]; then if type exiftool > /dev/null 2>&1; then export EXIFTOOL_CMD=1 else export FILE_OK=1 fi fi if [ -z "$MEDIAINFO" ]; then if type mediainfo > /dev/null 2>&1; then export MEDIAINFO_OK=1 else export FILE_OK=1 fi fi # PDF if [ -z "$PDF" ]; then if type pdftoppm > /dev/null 2>&1; then export PDFTOPPM_OK=1 elif type pdftotext > /dev/null 2>&1; then export PDFTOTEXT_OK=1 elif type mutool > /dev/null 2>&1; then export MUTOOL_CMD=1 fi fi # Office documents if [ -z "$DOC" ]; then if [ -z "$DOCASTEXT" ] && type libreoffice > /dev/null 2>&1; then export LIBREOFFICE_OK=1 else type catdoc > /dev/null 2>&1 && export CATDOC_OK=1 type odt2txt > /dev/null 2>&1 && export ODT2TXT_OK=1 type xlsx2csv > /dev/null 2>&1 && export XLSX2CSV_OK=1 type xls2csv > /dev/null 2>&1 && export XLS2CSV_OK=1 type unzip > /dev/null 2>&1 && export UNZIP_OK=1 fi fi type pandoc > /dev/null 2>&1 && export PANDOC_OK=1 # Syntax highlighting if [ -z "$TEXT" ]; then if type bat > /dev/null 2>&1; then export BAT_OK=1 elif type highlight > /dev/null 2>&1; then export HIGHLIGHT_OK=1 elif type pygmentize > /dev/null 2>&1; then export PYGMENTIZE_OK=1 else export CAT_OK=1 fi fi if [ -z "$JSON" ]; then if type python > /dev/null 2>&1; then export PYTHON_OK=1 elif type jq > /dev/null 2>&1; then export JQ_OK=1 else export CAT_OK=1 fi fi # Ddjvu if [ -z "$DDJVU" ]; then if type ddjvu > /dev/null 2>&1; then export DDJVU_OK=1 elif type djvutxt > /dev/null 2>&1; then export DDJVUTXT_OK=1 fi fi # Fonts if [ -z "$FONTS" ]; then if type fontpreview > /dev/null 2>&1; then export FONTPREVIEW_OK=1 elif type fontimage > /dev/null 2>&1; then export FONTIMAGE_OK=1 fi fi # Markdown if [ -z "$MARKDOWN" ]; then if type glow > /dev/null 2>&1; then export GLOW_OK=1 elif type mdcat > /dev/null 2>&1; then export MDCAT_OK=1 fi fi # Epub if [ -z "$EPUB" ]; then if type epub-thumbnailer > /dev/null 2>&1; then export EPUBTHUMB_OK=1 fi fi # Torrent if type transmission-show > /dev/null 2>&1; then export TRANSMISSION_OK=1 fi # Used to convert some file types to images type convert > /dev/null 2>&1 && export CONVERT_OK=1 # Make sure we have file, use dto get files MIME type type file > /dev/null 2>&1 && export FILE_OK=1 if [ "$UEBERZUG_OK" = 1 ] ; then CACHEDIR="${XDG_CACHE_HOME:-$HOME/.cache}/clifm" ! [ -d "$CACHEDIR" ] && mkdir -p "$CACHEDIR" export FIFO_UEBERZUG="$CACHEDIR/ueberzug-${PPID}" trap uz_cleanup EXIT start_ueberzug else export FIFO_UEBERZUG="/dev/null" fi TMP=$(mktemp "${TMPDIR:-/tmp}/clifm.XXXXXX") ##################################### # 3. RUN FZF, WHICH CALLS BFG # ##################################### fcd "$@" [ -n "$CLIFM" ] && cat "$TMP" 2>/dev/null > "$CLIFM_BUS" rm -f -- "$TMP" 2>/dev/null } ##################### # MAIN # ##################### if [ -n "$1" ] && { [ "$1" = "--help" ] || [ "$1" = "-h" ]; }; then # name="${CLIFM_PLUGIN_NAME:-$(basename "$0")}" printf "Navigate/preview/select files via FZF\n" printf "\n%s\n" "$HELP" exit 0 fi if [ -n "$1" ] && [ "$1" = "--edit" ]; then f="$(get_file BFG.cfg)" if [ -z "$f" ]; then printf "clifm: BFG.cfg: No such file or directory\n" >&2 exit 2 fi if ! [ -f "${HOME_PLUGINS_DIR}/BFG.cfg" ]; then cp -- "$f" "${HOME_PLUGINS_DIR}/BFG.cfg" 2>/dev/null f="${HOME_PLUGINS_DIR}/BFG.cfg" fi "${EDITOR:-VISUAL:-nano}" "$f" && exit 0 exit 1 fi # Source our plugins helper if [ -z "$CLIFM_PLUGINS_HELPER" ] || ! [ -f "$CLIFM_PLUGINS_HELPER" ]; then printf "clifm: Unable to find plugins-helper file\n" >&2 exit 1 fi # shellcheck source=/dev/null . "$CLIFM_PLUGINS_HELPER" main "$@" # Erase the FZF window _lines="${LINES:-100}" printf "\033[%dM" "$_lines" exit 0 clifm-1.26.3/plugins/fzfsel.sh000077500000000000000000000056201506632037700162220ustar00rootroot00000000000000#!/bin/sh # Files selection plugin for Clifm # Dependencies: fzf, find # Author: L. Abramovich # License: GPL2+ if [ "$1" = "-h" ] || [ "$1" = "--help" ]; then name="${CLIFM_PLUGIN_NAME:-$(basename "$0")}" printf "List files in the current directory allowing \ the user to select one or more of them.\n" printf "\n\x1b[1mUSAGE\x1b[0m\n %s [-f, --flat] [\PATTERN] [-h, --help] With the -f or --flat option files are listed recursively \ starting from the current directory (aka flat or branch view). \PATTERN is a glob expression used to filter files. Ex: '-f \*.pdf' \ will recursively list all .pdf files in the current directory. At exit, selected files are sent to Clifm's Selection Box. Dependencies: fzf(1), find(1)\n" "$name" exit 0 fi if ! type fzf > /dev/null 2>&1; then printf "clifm: fzf: Command not found\n" >&2 exit 127 fi TMP_DIR="${TMPDIR:-/tmp}/clifm/$CLIFM_PROFILE" TMPFILE="$TMP_DIR/${CLIFM_PROFILE}.fzfsel" # Source our plugins helper if [ -z "$CLIFM_PLUGINS_HELPER" ] || ! [ -f "$CLIFM_PLUGINS_HELPER" ]; then printf "clifm: Unable to find plugins-helper file\n" >&2 exit 1 fi # shellcheck source=/dev/null . "$CLIFM_PLUGINS_HELPER" ! [ -d "$TMP_DIR" ] && mkdir -p "$TMP_DIR" HELP="Usage: Alt-h: Toggle this help screen TAB, Alt-down: Toggle select down Alt-up: Toggle select up Ctrl-s: Select all files Ctrl-d: Deselect all files Ctrl-t: Invert selection Enter: Confirm selection, exit, and send selected files to Clifm Esc: Cancel and exit" exit_status=0 pattern="" flat_view=0 if [ "$1" = "-f" ] || [ "$1" = "--flat" ]; then flat_view=1 shift fi if [ -n "$1" ]; then if [ "$(printf "%c" "$1")" = "\\" ]; then pattern="$(echo "$1" | cut -c2-)" else pattern="$1" fi fi if [ "$flat_view" -eq 1 ]; then if [ -n "$pattern" ]; then ls_cmd="find . -name \"$pattern\" 2>/dev/null | cut -c3-" else ls_cmd="find . 2>/dev/null | cut -c3-" fi else if ls --version >/dev/null 2>&1; then ls_cmd="ls -Ap --group-directories-first --color=always $pattern" else ls_cmd="ls -Ap $pattern" fi fi # shellcheck disable=SC2012 # shellcheck disable=SC2154 eval "$ls_cmd" | fzf --multi --marker='*' --info=inline --keep-right \ --height "$fzf_height" --header "Select files. Press Alt-h for help" \ --color "$(get_fzf_colors)" \ --bind "alt-down:toggle+down,insert:toggle+down" \ --bind "alt-up:toggle+up" \ --bind "alt-h:toggle-preview" \ --bind "ctrl-s:select-all,ctrl-d:deselect-all,ctrl-t:toggle-all" \ --preview-window=:wrap \ --bind "alt-enter:toggle-all" --reverse "$(fzf_borders)" \ --preview "printf %s \"$HELP\"" \ --no-sort --ansi --prompt "$fzf_prompt" > "$TMPFILE" exit_status=$? [ "$exit_status" -eq 130 ] && exit_status=0 # shellcheck disable=SC1007 while ISF= read -r line; do printf "%s\n" "$PWD/$line" >> "$CLIFM_SELFILE" done < "$TMPFILE" rm -f -- "$TMPFILE" > /dev/null 2>&1 # Erase the FZF window _lines="${LINES:-100}" printf "\033[%dM" "$_lines" exit "$exit_status" clifm-1.26.3/plugins/git_status.sh000077500000000000000000000027111506632037700171150ustar00rootroot00000000000000#!/bin/sh # Git status plugin for Clifm # Written by L. Abramovich # License: GPL2+ # Description: Check if the current directory is inside a git work # tree, and, if true, print status, i.e., branch name and non # commited/tracked files # NOTE: This script is not intended to be used as a normal plugin, # that is, called via an action name, but rather to be executed as # a prompt command (see the configuration file) # Some useful git commands for a more complex output: #am I inside git repo? [ "$(git rev-parse --is-inside-work-tree)" = "true" ] && echo "Yes" #current remote/repo: git rev-parse --abbrev-ref @{upstream} #current repo: git describe --contains --all HEAD #total upstream commits: git rev-list --count @{upstream} #last local commit short hash: git rev-parse --short HEAD #last upstream commit short hash: git rev-parse --short @{upstream} #Is something stashed: git rev-parse --verify --quiet refs/stash #Non-commited/tracked local changes: git status | grep -q "nothing to commit" && echo "No" || echo "Yes" or git status -sb if [ -n "$1" ] && { [ "$1" = "--help" ] || [ "$1" = "-h" ]; }; then printf "Print current git status (if in a git repository). This script is intended to be executed as a prompt command. Add the absolute path to this plugin to the PROMPT COMMANDS section in the configuration file.\n" exit 0 fi if [ -n "$CLIFM_COLORLESS" ]; then git -c color.status=false status -sb 2>/dev/null else git status -sb 2>/dev/null fi exit 0 clifm-1.26.3/plugins/ihelp.sh000077500000000000000000000056421506632037700160360ustar00rootroot00000000000000#!/bin/sh # Interactive help plugin for Clifm # Written by L. Abramovich # License: GPL2+ # Dependencies: man, sed, less, and fzf or rofi if [ -n "$1" ] && { [ "$1" = "--help" ] || [ "$1" = "-h" ]; }; then name="${CLIFM_PLUGIN_NAME:-$(basename "$0")}" printf "Interactively browse the Clifm manpage via FZF or Rofi\n" printf "\n\x1b[1mUSAGE\x1b[0m\n %s\n" "$name" exit 0 fi if ! type man > /dev/null 2>&1; then printf "clifm: man: Command not found\n" >&2 exit 127 fi manpage="$(man -w clifm)" if ! [ -f "$manpage" ]; then printf "clifm: no manpage found\n" >&2 exit 1 fi if type fzf >/dev/null 2>&1; then filter="fzf" elif type rofi >/dev/null 2>&1; then filter="rofi" else printf "clifm: No finder found. Install either fzf or rofi\n" >&2 exit 1 fi tmp="" if [ -n "$MANPAGER" ]; then tmp="$MANPAGER" unset MANPAGER fi # Source our plugins helper if [ -z "$CLIFM_PLUGINS_HELPER" ] || ! [ -f "$CLIFM_PLUGINS_HELPER" ]; then printf "clifm: Unable to find the plugins-helper file\n" >&2 exit 1 fi # shellcheck source=/dev/null . "$CLIFM_PLUGINS_HELPER" CMDS="1. GETTING HELP@ 2. DESCRIPTION@ 3. PARAMETERS@ POSITIONAL PARAMETERS@ OPTIONS@ 4. COMMANDS@ 5. FILE FILTERS@ 6. KEYBOARD SHORTCUTS@ 7. THEMING@ 8. BUILT-IN EXPANSIONS@ 9. TAB COMPLETION@ 10. FILE OPENER@ 11. SHOTGUN@ 12. AUTO-SUGGESTIONS@ 13. SHELL FUNCTIONS@ 14. PLUGINS@ 15. AUTOCOMMANDS@ 16. FILE TAGS@ 17. VIRTUAL DIRECTORIES@ 18. NOTE ON SPEED 19. KANGAROO FRECENCY ALGORITHM@ 20. ENVIRONMENT@ 21. SECURITY@ 22. MISCELLANEOUS NOTES@ 23. FILES@ 24. EXAMPLES@ FILE/DIR@ /PATTERN@ ;\[CMD\], :\[CMD\]@ ac, ad@ acd, autocd@ actions @ alias @ ao, auto-open@ auto @ b, back@ bb, bleach@ bd @ bl @ bm, bookmarks@ br, bulk@ c, l@ colors@ cd @ cl, columns@ cmd, commands@ config @ cs, colorschemes@ d, dup@ ds, desel@ exp @ ext @ f, forth@ fc @ ff, dirs-first@ ft, filter@ fz @ hf, hh, hidden@ history @ icons @ j @ k@ kk@ kb, keybinds@ log @ ll, lv@ lm @ media@ mf @ mm, mime@ mp, mountpoints@ msg, messages@ n, new@ net \[@ o, open@ oc @ opener @ ow @ pc @ pin @ pf, profile@ pg, pager@ p, prop@ prompt@ q, quit, exit, Q@ rl, reload@ rf, refresh@ rr @ s, sel@ sb, selbox@ st, sort@ stats @ t, trash@ tag @ te @ tips @ u, untrash@ unpin @ v, paste@ vv @ view@ ver, version@ ws@ x, X@" a="-" _colors="$(get_fzf_colors)" # shellcheck disable=SC2046 while [ -n "$a" ]; do if [ "$filter" = "fzf" ]; then # shellcheck disable=SC2154 a="$(printf "%s\n" "$CMDS" | sed 's/@//g' | fzf --prompt="$fzf_prompt" --header "Browse Clifm's manpage" --reverse --height="$fzf_height" --info=inline --color="$_colors")" else a="$(printf "%s\n" "$CMDS" | sed 's/@//g' | rofi -dmenu -p "clifm")" fi if [ -n "$a" ]; then if echo "$a" | grep -q '^[1-9,A-Z].*'; then # shellcheck disable=SC2089 export PAGER="less -gp \"$a\"" else # shellcheck disable=SC2090 export PAGER="less -gp \" $a\"" fi man clifm fi done printf "\n" if [ -n "$tmp" ]; then export MANPAGER="$tmp" fi exit 0 clifm-1.26.3/plugins/img_viewer.sh000077500000000000000000000042131506632037700170630ustar00rootroot00000000000000#!/bin/sh # Description: Image thumbnails plugin for Clifm # Dependencies (any of the following): # nsxiv sxiv feh pqiv gthumb ristretto gwenview lsix img2sixel # (or just your preferred image viewer) # xargs # tr # # Author: L. Abramovich # License: GPL2+ # Specify here your preferred image viewer and command line options for it VIEWER="" VIEWER_OPTS="" if [ "$1" = "--help" ] || [ "$1" = "-h" ]; then name="${CLIFM_PLUGIN_NAME:-$(basename "$0")}" printf "Display thumbails of FILE(s) or files in DIR (current \ working directory if omitted). \n\x1b[1mUSAGE\x1b[0m\n %s [FILE... n] [DIR]\n" "$name" exit 0 fi found=0 args="${*:-.}" if [ -n "$VIEWER" ] && [ "$(type "$VIEWER" 2>/dev/null)" ]; then if [ -n "$VIEWER_OPTS" ]; then "$VIEWER" "$VIEWER_OPTS" "$args" else "$VIEWER" "$args" fi exit 0 fi names="$(echo "$args" | sed 's/\\ /\t/g;s/ /\n/g;s/\t/ /g;s/\\//g')" if type nsxiv > /dev/null 2>&1; then (echo "$names" | tr \\n \\0 | xargs -0 nsxiv -aqt) && exit 0 || found=1 elif type sxiv > /dev/null 2>&1; then (echo "$names" | tr \\n \\0 | xargs -0 sxiv -aqt) && exit 0 || found=1 elif type feh > /dev/null 2>&1; then (echo "$names" | tr \\n \\0 | xargs -0 feh -tZ) && exit 0 || found=1 elif type pqiv > /dev/null 2>&1; then (echo "$names" | tr \\n \\0 | xargs -0 pqiv --auto-montage-mode --max-depth=1 --disable-backends="archive,poppler,spectre,wand,webp,libav,archive_cbx") && exit 0 || found=1 elif type gthumb > /dev/null 2>&1; then (echo "$names" | tr \\n \\0 | xargs -0 gthumb) && exit 0 || found=1 elif type ristretto > /dev/null 2>&1; then (echo "$names" | tr \\n \\0 | xargs -0 ristretto) && exit 0 || found=1 elif type gwenview > /dev/null 2>&1; then (echo "$names" | tr \\n \\0 | xargs -0 gwenview) && exit 0 || found=1 elif type lsix > /dev/null 2>&1; then if [ -d "$1" ] || [ -h "$1" ]; then lsix "$1"/*.png "$1"/*.jpg && exit 0 || found=1 else (echo "$names" | tr \\n \\0 | xargs -0 lsix) && exit 0 || found=1 fi elif type img2sixel > /dev/null 2>&1; then (echo "$names" | tr \\n \\0 | xargs -0 img2sixel) && exit 0 || found=1 fi if [ "$found" -eq 0 ]; then printf "clifm: No image viewer found\n" >&2 fi exit 1 clifm-1.26.3/plugins/jumper.sh000077500000000000000000000026221506632037700162320ustar00rootroot00000000000000#!/bin/sh # Clifm plugin to navigate the jump database via fzf/Rofi # Dependencies: fzf or rofi, and grep # Written by L. Abramovich # Lincese GPL2+ if [ -n "$1" ] && { [ "$1" = "--help" ] || [ "$1" = "-h" ]; }; then name="${CLIFM_PLUGIN_NAME:-$(basename "$0")}" printf "Navigate Clifm's jump database via FZF or Rofi. Press Enter to cd into the selected directory\n" printf "\n\x1b[1mUSAGE\x1b[0m\n %s\n" "$name" exit 0 fi if type fzf > /dev/null 2>&1; then finder="fzf" elif type rofi > /dev/null 2>&1; then finder="rofi" else printf "clifm: No finder found. Install either FZF or Rofi\n" >&2 exit 1 fi FILE="${XDG_CONFIG_HOME:-${HOME}/.config}/clifm/profiles/$CLIFM_PROFILE/jump.clifm" if ! [ -f "$FILE" ]; then exit 1 fi if [ "$finder" = "fzf" ]; then # Source our plugins helper if [ -z "$CLIFM_PLUGINS_HELPER" ] || ! [ -f "$CLIFM_PLUGINS_HELPER" ]; then printf "clifm: Unable to find plugins-helper file\n" >&2 exit 1 fi # shellcheck source=/dev/null . "$CLIFM_PLUGINS_HELPER" # shellcheck disable=SC2154 path="$(cut -d ":" -f4 "$FILE" | grep -v ^"@" |\ fzf --reverse --height "$fzf_height" \ --bind "tab:accept" --info=inline \ --color="$(get_fzf_colors)" \ --prompt="$fzf_prompt" --header "Jump to a directory in the jump database")" else path="$(cut -d ":" -f4 "$FILE" | grep -v ^"@" | rofi -dmenu -p clifm)" fi if [ -n "$path" ]; then printf "%s\n" "$path" > "$CLIFM_BUS" fi exit 0 clifm-1.26.3/plugins/m_git_prompt_status000077500000000000000000000030141506632037700204160ustar00rootroot00000000000000#!/bin/sh # Git prompt module for Clifm # Dependencies: git, sed, cut, tr, uniq, tail # Author: L. Abramovich # License: GPL2+ # Usage: # Edit your prompt (via 'prompt edit') and add this code: # # RegularPrompt="... ${m_git_prompt_status} ..." cmd_output="$(git -c color.status=false status -sb 2>/dev/null)" [ -z "$cmd_output" ] && exit 1 header="$(echo "$cmd_output" | sed -n 1p)" files="$(echo "$cmd_output" | tail -n+2 | cut -c1-3 | uniq)" case "$header" in *"/"*) tmp="$(echo "$header" | cut -d'/' -f2)" ;; *) tmp="$(echo "$header" | cut -d' ' -f2-10)" ;; esac branch="$(echo "$tmp" | cut -d' ' -f1)" case "$tmp" in *"["*) ahead_behind="$(echo "$tmp" | cut -d' ' -f2-3 | tr -d '[]')" ;; *) ahead_behind="" ;; esac status="" for i in $files; do case "$i" in ".") status="${status}\e[36m+" ;; "D"*) status="${status}\e[31mD" ;; "M"*) status="${status}\e[32mM" ;; "R"*) status="${status}\e[35mR" ;; "U"*) status="${status}\e[33mU" ;; "A"*) status="${status}\e[32mA" ;; "??"*) status="${status}\e[31m?" ;; esac done branch_color="\e[22;35m" sep_color="\e[2;37m" end_color="\e[22;39m" output="$branch_color$branch$sep_color|" if [ -n "$ahead_behind" ]; then ab_color="\e[22;32m" [ "$(echo "$ahead_behind" | cut -b1)" != "a" ] && ab_color="\e[22;31m" output="$output$ab_color$ahead_behind$end_color" else output="$output\e[22;32m=$end_color" fi [ -n "$status" ] && output="$output$sep_color|$end_color$status$end_color" # FIXME: The POSIX version of echo does not support flags echo -e "($output)" exit 0 clifm-1.26.3/plugins/m_hostname_color000077500000000000000000000007711506632037700176520ustar00rootroot00000000000000#!/bin/sh # Hostname color prompt module for Clifm # Author: L. Abramovich # License: GPL2+ # Description: # Dinamically colorize the hostname string in the prompt depending # on whether we are running on a SSH remote session or not. # Usage: # Edit your prompt (via 'prompt edit') and modify the hostname code # as follows: # # RegularPrompt="... \u:${m_hostname_color}\H%{reset} ..." # # The hostname will be printed in yellow whenever we're on a SSH session. [ -n "$SSH_TTY" ] && printf "\e[0;33m" clifm-1.26.3/plugins/mime_list.sh000077500000000000000000000023241506632037700167110ustar00rootroot00000000000000#!/bin/sh # Plugin to list files in CWD by a given mime type using FZF # Dependencies: fzf, file, grep # Written by L. Abramovich # License GPL2+ # Dependencies: find, file, fzf if [ -n "$1" ] && { [ "$1" = "--help" ] || [ "$1" = "-h" ]; }; then name="${CLIFM_PLUGIN_NAME:-$(basename "$0")}" printf "List files in the current directory by MIME type\n" printf "\n\x1b[1mUSAGE\x1b[0m\n %s\n" "$name" exit 0 fi if ! type fzf > /dev/null 2>&1; then printf "clifm: fzf: Command not found\n" >&2 exit 127 fi mime="" printf "Enter a MIME type or part of it ('q' to quit). Ex: image\n" while [ -z "$mime" ]; do printf "Mime type: " read -r mime done { [ "$mime" = "q" ] || [ "$mime" = "quit" ]; } && exit 0 # Source our plugins helper if [ -z "$CLIFM_PLUGINS_HELPER" ] || ! [ -f "$CLIFM_PLUGINS_HELPER" ]; then printf "clifm: Unable to find plugins-helper file\n" >&2 exit 1 fi # shellcheck source=/dev/null . "$CLIFM_PLUGINS_HELPER" # shellcheck disable=SC2154 find . -maxdepth 1 -mindepth 1 | \ file -F'@' -N -n --mime-type -if- | \ grep "@ .*${mime}" | cut -d"@" -f1 | cut -d"/" -f2-10 | sort | \ fzf --reverse --height="$fzf_height" --exit-0 --header "Choose a file" \ --info=inline --color="$(get_fzf_colors)" exit 0 clifm-1.26.3/plugins/music_player.sh000077500000000000000000000016221506632037700174230ustar00rootroot00000000000000#!/bin/sh # Music player plugin for Clifm # Dependencies: mplayer (default), tr, head, sed # Written by L. Abramovich # License: GPL2+ PLAYER="mplayer" OPTS="-playlist" if [ -z "$1" ] || [ "$1" = "--help" ] || [ "$1" = "-h" ]; then name="${CLIFM_PLUGIN_NAME:-$(basename "$0")}" printf "Create a playlist using FILE(s) and play it\n" printf "\n\x1b[1mUSAGE\x1b[0m\n %s FILE(s)\n" "$name" exit 0 fi if ! type "$PLAYER" >/dev/null 2>&1; then printf "clifm: %s: Command not found\n" "$PLAYER" >&2 exit 127; fi TMP_FILE="${TMPDIR:-/tmp}/clifm/playlist.$(tr -dc A-Za-z0-9 > "$TMP_FILE" else printf "%s\n" "$file" | sed 's/\\//g' >> "$TMP_FILE" fi done "${EDITOR:-nano}" "$TMP_FILE" "$PLAYER" "$OPTS" "$TMP_FILE" rm -rf -- "$TMP_FILE" exit 0 clifm-1.26.3/plugins/pager.sh000077500000000000000000000014701506632037700160260ustar00rootroot00000000000000#!/bin/sh # Description: Print the current list of files through a pager (less) # Dependencies: less, tput # Author: L. Abramovich # License: GPL2+ if [ "$1" = "-h" ] || [ "$1" = "--help" ]; then name="${CLIFM_PLUGIN_NAME:-$(basename "$0")}" printf "List the current list of files through a pager (less)\n" printf "\n\x1b[1mUSAGE\x1b[0m\n %s\n" "$name" exit 0 fi if ! type less >/dev/null 2>&1; then printf "clifm: less: command not found\n" >&2 exit 127 fi if ! type tput >/dev/null 2>&1; then printf "clifm: tput: command not found\n" >&2 exit 127 fi clifm_opts="--ls --no-clear-screen" [ "$CLIFM_LONG_VIEW" = "1" ] && clifm_opts="${clifm_opts} -l" # shellcheck disable=SC2086 CLIFM_COLUMNS="$(tput cols)" CLIFM_LINES="$(tput lines)" clifm $clifm_opts "$PWD" | less -rncs -P"LESS (clifm)\:" --tilde exit 0 clifm-1.26.3/plugins/pdf_viewer.sh000077500000000000000000000012051506632037700170560ustar00rootroot00000000000000#!/bin/sh # A PDF text viewer plugin for Clifm # Dependencies: pdftotext # Written by L. Abramovich # License: GPL2+ if [ -z "$1" ] || [ "$1" = "--help" ] || [ "$1" = "-h" ]; then name="${CLIFM_PLUGIN_NAME:-$(basename "$0")}" printf "Visualize PDF files in the terminal\n" printf "\n\x1b[1mUSAGE\x1b[0m\n %s FILE\n" "$name" exit 0 fi if ! type pdftotext >/dev/null 2>&1; then printf "clifm: pdftotext: Command not found\n" >&2 exit 127 fi file="$(echo "$1" | sed 's/\\//g')" if [ "$(head -c4 "$file")" != "%PDF" ]; then printf "clifm: Not a PDF file\n" >&2 exit 1 fi pdftotext -nopgbrk -layout "$file" - | ${PAGER:=less} exit 0 clifm-1.26.3/plugins/plugins-helper000066400000000000000000000017501506632037700172530ustar00rootroot00000000000000# Some common functions for Clifm plugins # Author: L. Abramovich # License: GPL2+ cmd_exists() { if type "$1" > /dev/null 2>&1; then echo "1"; else echo "0"; fi } # Get the current terminal amount of supported colors: normally 8 or 256 term_colors() { if type tput > /dev/null 2>&1; then echo "$(tput colors)" else echo "8" fi } # Return the appropriate value for FZF --color option, honoring no-color # directives get_fzf_colors() { if [ -n "$CLIFM_NO_COLOR" ] || [ -n "$NO_COLOR" ] \ || [ -n "$CLIFM_COLORLESS" ]; then echo "bw" else echo "16,prompt:6,fg+:-1,pointer:2,marker:2,hl:5,hl+:5,gutter:-1" fi } # Make sure FZF interface won't be messed up when running on an 8 bit # terminal emulator fzf_borders() { if [ "$(term_colors)" -eq 256 ]; then echo "--border=left" else echo "--no-unicode" fi } # A few fixed values to construct the FZF interface fzf_height="${CLIFM_FZF_HEIGHT:-80}%" fzf_prompt="Clifm > " colorize=1 [ -n "$CLIFM_COLORLESS" ] && colorize=0 clifm-1.26.3/plugins/rgfind.sh000077500000000000000000000031451506632037700162020ustar00rootroot00000000000000#!/bin/sh # Plugin to search for files by content for Clifm # Dependencies: rg (Ripgrep), fzf, and sed # Written by L. Abramovich # License: GPL2+ MAX_DEPTH=1 if [ -n "$1" ] && { [ "$1" = "--help" ] || [ "$1" = "-h" ]; }; then name="${CLIFM_PLUGIN_NAME:-$(basename "$0")}" printf "Search files by content via Ripgrep and FZF\n" printf "\n\x1b[1mUSAGE\x1b[0m\n %s STRING|REGEXP\n" "$name" exit 0 fi if ! type rg > /dev/null 2>&1; then printf "clifm: rg: Command not found\nInstall ripgrep to use this plugin\n" >&2 exit 127 fi if ! type fzf > /dev/null 2>&1; then printf "clifm: fzf: Command not found\nInstall fzf to use this plugin\n" >&2 exit 127 fi # Source our plugins helper if [ -z "$CLIFM_PLUGINS_HELPER" ] || ! [ -f "$CLIFM_PLUGINS_HELPER" ]; then printf "clifm: Unable to find plugins-helper file\n" >&2 exit 1 fi # shellcheck source=/dev/null . "$CLIFM_PLUGINS_HELPER" # shellcheck disable=SC2154 fzf_colors="$(get_fzf_colors)" rg_colors="ansi" [ "$fzf_colors" = "bw" ] && rg_colors="never" args="$(echo "$@" | sed 's/\\//g')" while true; do # shellcheck disable=SC2154 file="$(rg --color="$rg_colors" --hidden --heading --line-number \ --trim --ignore-case --max-depth="$MAX_DEPTH" \ -- "$args" 2>/dev/null | \ fzf --ansi --reverse --prompt="$fzf_prompt" \ --height="$fzf_height" --color="$fzf_colors" \ --no-clear --bind "right:accept" --no-unicode \ --header="Select a file name and press Enter or Right to open it")" [ -z "$file" ] && break clifm --open "$PWD/$(printf "%s" "$file" | cut -d: -f1)" done # Erase the FZF window _lines="${LINES:-100}" printf "\033[%dM" "$_lines" exit 0 clifm-1.26.3/plugins/update.sh000077500000000000000000000030621506632037700162110ustar00rootroot00000000000000#!/bin/sh # Description: Check clifm's upstream version # # Dependencies: awk, curl, grep # # Written by L. Abramovich # License GPL2+ if [ -n "$1" ] && { [ "$1" = "--help" ] || [ "$1" = "-h" ]; }; then name="${CLIFM_PLUGIN_NAME:-$(basename "$0")}" printf "Check Clifm's upstream version\n" printf "\n\x1b[1mUSAGE\x1b[0m\n %s\n" "$name" exit 0 fi if ! type clifm >/dev/null 2>&1 ; then printf "Clifm is not installed\n" >&2 exit 1 fi upstream="$(curl -s "https://api.github.com/repos/leo-arch/clifm/releases/latest" | grep tag_name | awk -F'"' '{print $4}')" if [ -z "$upstream" ]; then printf "clifm: Error fetching upstream version" >&2 exit 1 fi cur="$(clifm -v)" if [ "v$cur" = "$upstream" ]; then printf "Clifm is up to date: %s is the latest release\n" "$cur" else printf "%s: New release available (current version is %s)\n" "$upstream" "$cur" OS="$(uname -s)" if [ "$OS" != "Linux" ] && [ "$OS" != "FreeBSD" ] && [ "$OS" != "NetBSD" ] \ && [ "$OS" != "OpenBSD" ] && [ "$OS" != "DragonFly" ] && [ "$OS" != "Darwin" ]; then printf "\nTo manually build the latest release consult the documentation at\n\ https://github.com/leo-arch/clifm/wiki/Introduction#installation\n" exit 0 fi sudo_cmd="sudo" [ "$OS" = "OpenBSD" ] && sudo_cmd="doas" printf "\nIf not provided by your package manager, you can build the latest\n\ release as follows:\n\n\ 1) Clone the latest release:\n\ git clone https://github.com/leo-arch/clifm --depth=1\n\ 2) cd into the clifm directory:\n\ cd clifm\n\ 3) Build and install:\n\ %s make install\n" "$sudo_cmd" fi exit 0 clifm-1.26.3/plugins/vid_viewer.sh000077500000000000000000000031431506632037700170720ustar00rootroot00000000000000#!/bin/sh # Video thumbnails plugin for Clifm # Written by L. Abramovich # License: GPL2+ # Dependencies: sed, tr, head, ffmpegthumbnailer, and sxiv, lsix, or feh is_vid() { if file --mime-type "$1" | grep -q "video/"; then echo "1" else echo "0" fi } if ! type ffmpegthumbnailer >/dev/null 2>&1; then printf "clifm: ffmpegthumbnailer: Command not found\n" >&2 exit 127 fi if [ "$1" = "--help" ] || [ "$1" = "-h" ]; then name="${CLIFM_PLUGIN_NAME:-$(basename "$0")}" printf "Display thumbnails of VIDEO(s) or of videos contained in DIR (current working directory if omitted) \n\x1b[1mUSAGE\x1b[0m\n %s [VIDEO]... [DIR]\n" "$name" exit 0 fi TMP_DIR=".vidthumbs.$(tr -dc A-Za-z0-9 &2 args_tmp="${*:-.}" args="$(echo "$args_tmp" | sed 's/\\ /\t/g;s/ /\n/g;s/\t/ /g;s/\\//g')" echo "$args" | while read -r arg do if [ -d "$arg" ]; then if [ "$(printf "%s" "$arg" | tail -c1)" = '/' ]; then arg="${arg%?}" fi for file in "$arg"/*; do if [ -f "$file" ] && [ "$(is_vid "$file")" = "1" ]; then ffmpegthumbnailer -i "$file" -o \ "$TMP_DIR/$(basename "$file").jpg" 2>/dev/null fi done else if [ "$(is_vid "$arg")" = "1" ]; then ffmpegthumbnailer -i "$arg" -o \ "$TMP_DIR/$(basename "$arg").jpg" 2>/dev/null fi fi done if type sxiv >/dev/null 2>&1; then sxiv -aqtr -- "$TMP_DIR" elif type feh >/dev/null 2>&1; then feh -tZk -- "$TMP_DIR" elif type lsix >/dev/null 2>&1; then lsix "$TMP_DIR"/* else printf "clifm: No thumbails viewer found\n" >&2 rm -rf -- "$TMP_DIR" 2>/dev/null exit 1 fi rm -rf -- "$TMP_DIR" 2>/dev/null exit 0 clifm-1.26.3/plugins/virtualize.sh000077500000000000000000000034711506632037700171310ustar00rootroot00000000000000#!/bin/sh # Virtual directories plugin for Clifm # Dependencies: sed # Author: L. Abramovich # License: GPL2+ # Note: A new instance of Clifm will be spawned on a new terminal window # using $term_cmd, which defaults to 'xterm -e'. Edit this variable to # use your favorite terminal emulator instead, for example: # term_cmd="kitty sh -c" term_cmd="xterm -e" clifm_bin="clifm" clifm_opts="" if [ -z "$1" ] || [ "$1" = "--help" ] || [ "$1" = "-h" ]; then name="${CLIFM_PLUGIN_NAME:-$(basename "$0")}" printf "Create a virtual directory for a set or collection of files \n\x1b[1mUSAGE\x1b[0m\n %s [-d] [FILE...] \n\ \n\x1b[1mEXAMPLES\x1b[0m 'vt sel' Send all selected files to a virtual directory\n\ 'vt file1 file2' Send file1 and file2 to a virtual directory\n\ 'vt -d' If navigating the file system, use the -d option to change back to the virtual directory\n" "$name" >&2 exit 0 fi if ! type sed > /dev/null 2>&1; then printf "clifm: sed: Command not found\n" >&2 exit 127 fi if [ -n "$CLIFM_VT_RUNNING" ]; then if [ -n "$1" ] && [ "$1" = "-d" ]; then if [ -n "$CLIFM_VIRTUAL_DIR" ]; then echo "$CLIFM_VIRTUAL_DIR" > "$CLIFM_BUS" exit 0 fi fi printf "clifm: Only one virtual directory can be created at a time\n" >&2 exit 1 fi if [ -n "$1" ] && [ "$1" = "-d" ]; then printf "clifm: No virtual directory found\n" >&2 exit 1 fi export CLIFM_VT_RUNNING=1 if [ -n "$CLIFM_VIRTUAL_DIR" ]; then clifm_opts="$clifm_opts --virtual-dir=\"$CLIFM_VIRTUAL_DIR\"" fi # 1. Replace escaped spaces by tabs # 2. Replace non-escaped spaces by new line chars # 3. Replace tabs (first step) by spaces # 4. Remove remaining escape chars files="$(echo "$*" | sed 's/\\ /\t/g;s/ /\n/g;s/\t/ /g;s/\\//g')" cmd="$term_cmd 'echo \"$files\" | $clifm_bin $clifm_opts --no-restore-last-path'" eval "$cmd" exit 0 clifm-1.26.3/plugins/wallpaper_setter.sh000077500000000000000000000026301506632037700203040ustar00rootroot00000000000000#!/bin/sh # Wallpaper setter plugin for Clifm # Dependencies: # file, sed, and # feh, xsetbg (xloadimage), hsetroot, or nitrogen (for X) # swww (https://github.com/Horus645/swww) or swaybg (for Wayland) # Written by L. Abramovich # License: GPL2+ if [ -z "$1" ] || [ "$1" = "--help" ] || [ "$1" = "-h" ]; then name="${CLIFM_PLUGIN_NAME:-$(basename "$0")}" printf "Set IMAGE as wallpaper\n" printf "\n\x1b[1mUSAGE\x1b[0m\n %s IMAGE\n" "$name" exit 0 fi if [ -z "$DISPLAY" ]; then printf "clifm: A graphical environment is required\n" >&2 exit 1 fi if ! type file >/dev/null 2>&1; then printf "clifm: file: Command not found\n" >&2 exit 127 fi file="$(echo "$1" | sed 's/\\//g')" if ! file -bi "$file" | grep -q "image/"; then printf "clifm: %s: Not an image file\n" "$file" >&2 exit 1 fi if [ -n "$WAYLAND_DISPLAY" ]; then if type swww >/dev/null 2>&1; then swww img "$file" && exit 0 elif type swaybg >/dev/null 2>&1; then killall swaybg 2>/dev/null swaybg -m fill -i "$file" 2>/dev/null & exit 0 fi else if type feh >/dev/null 2>&1; then feh --no-fehbg --bg-fill "$file" && exit 0 elif type xsetbg >/dev/null 2>&1; then xsetbg -center "$file" && exit 0 elif type hsetroot >/dev/null 2>&1; then hsetroot -center "$file" && exit 0 elif type nitrogen >/dev/null 2>&1; then nitrogen --set-zoom-fill --save "$file" && exit 0 fi fi printf "clifm: Could not set wallpaper\n" >&2 exit 1 clifm-1.26.3/plugins/xclip.sh000077500000000000000000000023421506632037700160460ustar00rootroot00000000000000#!/bin/sh # Description: Copy the contents of the line buffer to the clipboard # Dependencies: # Any of the following: cb, wl-copy, xclip, xsel, pbcopy, termux-clipboard-set, clipboard, or clip # License: GPL2+ # Author: L. Abramovich # Bound by default to Ctrl-y if [ -z "$CLIFM_LINE" ]; then printf "clifm: Empty line buffer\n" 2>&1 exit 1 fi line="$CLIFM_LINE" # Manipulate LINE as you wish here, for example, to get only the last field #line="$(echo "$CLIFM_LINE" | awk '{print $NF}')" if type cb >/dev/null 2>&1; then printf "%s" "$line" | cb --copy elif [ -n "$WAYLAND_DISPLAY" ]; then printf "%s" "$line" | wl-copy elif type xclip >/dev/null 2>&1; then printf "%s" "$line" | xclip -sel clip elif type xsel >/dev/null 2>&1; then printf "%s" "$line" | xsel -bi elif type pbcopy >/dev/null 2>&1; then # MacOS printf "%s" "$line" | pbcopy elif type termux-clipboard-set >/dev/null 2>&1; then printf "%s" "$line" | termux-clipboard-set elif type clipboard >/dev/null 2>&1; then # Haiku printf "%s" "$line" | clipboard --stdin elif type clip >/dev/null 2>&1; then # Cygwin printf "%s" "$line" | clip else printf "clifm: No clipboard application found\n" 2>&1 exit 1 fi printf "\x1b[0mclifm: Line buffer copied to the clipboard\n" clifm-1.26.3/src/000077500000000000000000000000001506632037700134755ustar00rootroot00000000000000clifm-1.26.3/src/.clang-format000066400000000000000000000004561506632037700160550ustar00rootroot00000000000000--- Language: Cpp # Cpp is also used for C BasedOnStyle: LLVM ColumnLimit: 0 BreakBeforeBraces: Linux AlignAfterOpenBracket: DontAlign IndentWidth: 8 UseTab: Always IndentCaseLabels: false AllowShortBlocksOnASingleLine: Empty AlwaysBreakAfterReturnType: TopLevelDefinitions SortIncludes: false --- clifm-1.26.3/src/.clang-tidy000066400000000000000000000030661506632037700155360ustar00rootroot00000000000000--- Checks: > clang-diagnostic-*, clang-analyzer-*, readability-*, modernize-*, bugprone-*, misc-*, google-runtime-int, fuchsia-restrict-system-includes, -misc-unused-parameters, -misc-include-cleaner, -llvm-header-guard, -clang-analyzer-valist.Uninitialized, -clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling, -clang-analyzer-security.insecureAPI.rand, -clang-analyzer-alpha.*, -modernize-macro-to-enum, -readability-magic-numbers, -readability-braces-around-statements, -readability-function-cognitive-complexity, -readability-identifier-length, -readability-isolate-declaration, -readability-suspicious-call-argument, -readability-avoid-nested-conditional-operator, -readability-else-after-return, -bugprone-assignment-in-if-condition, -bugprone-easily-swappable-parameters, -bugprone-narrowing-conversions, -bugprone-reserved-identifier, -bugprone-switch-missing-default-case, -bugprone-inc-dec-in-conditions, -bugprone-multi-level-implicit-pointer-conversion, WarningsAsErrors: '*' HeaderFilterRegex: '.*(?= PARAM_MIN && n <= PARAM_MAX) /* Let's say PARM_MIN = 1 and PARAM_MAX = 10 */ return n; else /* Handle error */ ``` **j)** Keep your functions short (ideally, make them do one thing -and do it well). This helps to make more readable and deduggable code. For the same reason, split code into separate source files whenever possible. **k)** Do not repeat yourself: reuse code. These are just a few advices (most of which I learned the hard way). There are plenty of resources out there on how to write secure/performant code: consult them. ### 2. Portability We do care about portability. If possible, avoid non-portable functions, or, if absolutely required, use it only on the supported platform and use some replacement for the remaining ones. For example, in the case of a glibc-only function: ```c #if !defined(__GLIBC__) portable_func(); #else non_portable_func(); #endif /* !__GLIBC__ */ ``` Also, make sure to write [POSIX.1-2008](https://pubs.opengroup.org/onlinepubs/9699919799.2008edition/basedefs/V1_chap01.html) compliant code. ### 3. Memory Manual memory management is another of the greatest (dis)advantages of C. Use a tool like `valgrind` to make sure your code is not leaking memory. Free `malloc`'ed memory as soon as you do not need it any more. As a plus, compile with `clang` using the following flags to detect undefined behavior and integer overflow at run-time: `-fsanitize=integer -fsanitize=undefined`. ### 4. Static analysis Static analysis tools are an invaluable resource: use them! **Always** check your code via tools like `cppcheck`, GCC's analyzer (`-fanalyzer`),1 Clang's `scan-build`, `flawfinder`, or `splint`. Use them all if necessary. Once done, fix all warnings and errors (provided they are not false positives, of course). This said, we use three online platforms to check our code quality: [Codacy](https://app.codacy.com/gh/leo-arch/clifm/dashboard), [~~Codiga~~](https://app.codiga.io/project/30518/dashboard), and [CodeQL](https://github.com/leo-arch/clifm/actions/workflows/codeql-analysis.yml). 1 On the state of the builtin static analyzer provided by GCC see https://www.reddit.com/r/C_Programming/comments/u1ylub/static_analysis_of_c_code_in_gcc_12/ When it comes to plugins, we mostly use `POSIX shell scripts`. In this case, always use `shellcheck` to check your plugins. ### 5. Compiling Submitted code must be compiled without any warning/error using the following compiler flags: ```sh -O2 -D_FORTIFY_SOURCE=2 -Wall -Wextra -Werror -pedantic -Wshadow -Wformat=2 -Wformat-security -Wconversion -Wsign-conversion -Wunused -Wnull-dereference -fstack-protector-strong -fstack-clash-protection -fcf-protection -Wvla -std=c99 ``` To make sure your structs are properly aligned, add `-Wpadded` to detect misalignments and correct them by adding some padding if necessary. As a plus, make sure to fix all errors/warnings emitted by a security hardened compilation, like the one [recommended by Red Hat](https://developers.redhat.com/blog/2018/03/21/compiler-and-linker-flags-gcc): ```sh gcc -O2 -flto=auto -ffat-lto-objects -fexceptions -g -grecord-gcc-switches -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fstack-protector-strong -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection -Wl,-z,relro -Wl,--as-needed -Wl,-z,now -Wl,--build-id=sha1 ``` Finally, purge the code from unused headers. An execellent tool specifically desinged for this purpose is [include-what-you-use](https://github.com/include-what-you-use/include-what-you-use). ### 6. Comments If not obvious, comment what your code is trying to achieve: there is no good software without good documentation. ## 3) General code structure **Clifm**'s source code consists of multiple C source files, being `main.c` the starting point and `helpers.h` the main header file. In `main.c` you'll find: **A)** Initialization stuff, like loading config files (see `config.c` and `init.c`), command line options (parsed by the `parse_cmdline_args()`, in `args.c`), readline and keybindings initialization (see `readline.c` and `keybindings.c`), bookmarks, workspaces, history, and the like. **B)** Once everything is correctly initialized, an infinite loop (`run_main_loop()`, in `main.c`), structured as a basic shell, takes place: 1) Take input 2) Parse input 3) Execute command And take more input... **C)** The last step above (3) calls the `exec_cmd()` function (`in exec.c`) to find out what needs to be done based on the user's input. The structure of the `exec_cmd` function is a big if-else chain: if the command is internal, that is, one of **clifm**'s builtin commands, the corresponding function will be called and executed; if not, if it is rather an external command, it will be executed by the system shell (via `launch_execl()`, also in `exec.c`).1 1 The shell used to launch external commands is taken from: 1) **CLIFM_SHELL** environment variable, 2) **SHELL** environment variable, or 3) the `password` database (via **getpwuid**(3)), in this order. Note that if running with `--secure-cmds`, `--secure-env`, or `--secure-env-full`, steps 1 and 2 are skipped. **D)** Listing The above describes the basic structure of **clifm**: generally speaking, it is just a shell. In between, however, lots of things happen. Leaving aside the above mentioned functions, the most important one is `list_dir()`, defined in `listing.c`. Everything related to listing files happens here: reading files in the current directory (via **readdir**(3)), getting file information (via the dirent struct returned by **readdir**(3) itself and **stat**(2)), sorting files (via **qsort**(3)), and storing all this information in a global struct (`file_info`) for future access, for example, to get file properties of a given entry. **E)** Whatever happens later, is just some function or operation invoked by the user and happening on top of the steps described above: opening a file or directory (via the `open_function()` and `cd_function()` functions, in `file_operations.c` and `navigation.c` respectivelly), opening a bookmark (`bookmarks.c`), operating on files (`file_operations.c`), switching to a different profile (`profiles.c`), trashing a file (`trash.c`), searching for a file (`search.c`), running a plugin (`actions.c`), and so on. ## 4) Hacking | Target | File(s) | Main function | Observation | | --- | --- | --- | --- | | Initialization | `main.c` | `main` | See also `init.c` and `config.c` | | Default settings | `settings.h` | | See also `messages.h` and the icons header files | | Command line arguments | `args.c` | `parse_cmdline_args` | | | Make our memory management better | `mem.c` | `xnmalloc` `xcalloc`, and `xnrealloc` | | | Add a new command | `exec.c` | `exec_cmd` | Most of the time you want your command to be available for TAB completion and suggestions. See below. | | External commands execution | `exec.c` | `launch_execv` and `launch_execl` | | | Add a new prompt feature | `prompt.c` | `prompt` | | | Tweak how we open files | `mime.c` | `mime_open` | | | Tweak how we bookmark files | `bookmarks.c` | `bookmarks_function` | | | Tweak how we trash files | `trash.c` | `trash_function` | | | Tweak how we select files | `selection.c` | `sel_function` and `deselect` | | | Tweak the quick search function | `search.c` | `search_glob` and `search_regex` | | | Tweak how we handle profiles | `profiles.c` | `profile_function` | | Tweak how we process file properties | `properties.c` | `properties_function` (`p/pp` command) | This file also handles the `pc`, `po`, and `stats` commands | | Modify/add keybindings | `keybindings.c` | `readline_kbinds` | | Icons | `icons.h`, `listing.c` | `list_dir` | Consult the [customizing icons](https://github.com/leo-arch/clifm/wiki/Advanced#customizing-icons) section | | TAB completion (including alternative completers) | `readline.c` and `tabcomp.c` | `my_rl_completion` and `tab_complete` respectively | | | Interface | `listing.c`, `long_view.c` and `colors.c` | `list_dir`, `print_entry_props` and `set_colors` respectively | See also `sort.c` for our files sorting algorithms | | Directory jumper | `jump.c` | `dirjump` | | | Suggestions | `suggestions.c` and `keybinds.c` | `rl_suggestions` and `rl_accept_suggestion` respectively | | | Syntax highlighting | `highlight.c` | `rl_highlight` | See also `readline.c` and `keybinds.c` | | Autocommands | `autocmds.c` | `check_autocmds` | | | Filenames sanitizer(`bleach`) | `name_cleaner.c` and `cleaner_table.h` | `bleach_files` | | | Improve my security | `sanitize.c` | `sanitize_cmd`, `sanitize_cmd_environ`, and `xsecure_env` | | | The tags system | `tags.c` | `tags_function` | | | `mounpoint` and `media` commands | `media.c` | `media_menu` | | | `net` command | `remotes.c` | `remotes_function` | | | Most file operation functions | `file_operations.c` | | | | Navigation stuff | `navigation.c` | | | | History and logs | `history.c` | | | | Plugins | `actions.c` | `run_action` | | | Miscellaneous/auxiliary functions | `aux.c`, `checks.c`,`misc.c`, and `strings.c` | | | ## 5) Compilation **Note**: For the list of dependencies, see the [installation page](https://github.com/leo-arch/clifm/wiki/Introduction#installation). **Clifm** is compiled using `gcc` (or `clang`) as follows: 1) _Linux_: ```sh gcc -O3 -s -fstack-protector-strong -march=native -Wall -o clifm *.c -lreadline -lcap -lacl -lmagic ``` 2) _FreeBSD_ / _DragonFly_: ```sh gcc -I/usr/local/include -L/usr/local/lib -O3 -s -fstack-protector-strong -march=native -Wall -o clifm *.c -lreadline -lintl -lmagic ``` 3) _NetBSD_: ```sh gcc -I/usr/pkg/include -L/usr/pkg/lib -Wl,-R/usr/pkg/lib -O3 -s -fstack-protector-strong -march=native -Wall -o clifm *.c -lintl -lreadline -lmagic -lutil ``` 4) _OpenBSD_: ```sh cc -I/usr/local/include -L/usr/local/lib -O3 -s -fstack-protector-strong -march=native -Wall -o clifm *.c -lereadline -lintl -lmagic ``` 5) _Haiku_: ```sh gcc -o clifm *.c -lreadline -lintl -lmagic ``` 6) _Solaris/Illumos_: ```sh gcc -o clifm *.c -lreadline -ltermcap -lmagic -lnvpair ``` **NOTE 1**: Since compiling in this way only produces a binary file, it is necessary to manually copy the remaining files. See the `install` block of the [Makefile](https://github.com/leo-arch/clifm/blob/master/Makefile). **NOTE 2**: You can drop `-lmagic` if compiling with `_NO_MAGIC`. In the same way, you can drop `-lintl` if compiling with `_NO_GETTEXT`. See below. **NOTE 3**: If running on _Solaris/Illumos_ consult the [troubleshooting section](https://github.com/leo-arch/clifm/wiki/Troubleshooting#warning-prompt) in case of issues with the warning prompt. The `nvpair` library is used to get files creation time. You can drop `-lnvpair`, however, if compiling with `_NO_SUN_BIRTHTIME`. **NOTE 4**: If the binary size is an issue, you can use [upx(1)](https://linux.die.net/man/1/upx) to significantly reduce (50-70%) the size of the executable file (at the expense of some performance): ```sh upx clifm ``` You can also use **strip**(1) as follows: ```sh strip --strip-unneeded --remove-section=.comment --remove-section=.note clifm ``` ### Compiling features in/out **Clifm** allows you to enable or disable some features at compile time. If for whatever reason you do not plan to use a certain feature, it is better to remove this feature from the resulting binary: you will get a (bit) faster and smaller executable. To do this, pass one or more of the following options to the compiler using the `-D` parameter. For example, to get a binary without icons and translation support: ```sh gcc ... -D_NO_GETTEXT -D_NO_ICONS ... ``` You can also use the `CPPFLAGS` variable. For example: ```sh export CPPFLAGS="$CPPFLAGS -D_NO_GETTEXT -D_NO_ICONS" make ``` If using GNU Make you can pass these options directly to **make**(1) via a GNU specific Makefile: ```sh make -f misc/GNU/Makefile _NO_GETTEXT=1 _NO_ICONS=1 ``` | Option | Description | | --- | --- | | `POSIX_STRICT` | Build a `POSIX.1-2008` compliant executable1. Note: combine with `CLIFM_LEGACY` for `POSIX.1-2001` compliance (experimental). | | `CLIFM_SUCKLESS` | Remove all code aimed at parsing config files. Configuration is done either via `settings.h` (and recompilation) or via [environment variables](https://github.com/leo-arch/clifm/wiki/Specifics#environment)2 | | `_ICONS_IN_TERMINAL` | Use icons-in-terminal for [icons](https://github.com/leo-arch/clifm/wiki/Advanced/#icons-smirk) instead of the default (emoji-icons) | | `_NERD` | Use Nerdfonts for [icons](https://github.com/leo-arch/clifm/wiki/Advanced/#icons-smirk) instead of the default (emoji-icons) | | `_NO_ARCHIVING` | Disable [archiving](https://github.com/leo-arch/clifm/wiki/Advanced#archives) support | | `_NO_ARC4RANDOM` | Disable support for [**arc4random**(3)](https://man.openbsd.org/arc4random.3) (**random**(3) will be used instead) | | `_NO_BLEACH` | Disable support for [`Bleach`, the builtin filenames sanitizer](https://github.com/leo-arch/clifm/wiki/Introduction#bb-bleach-elnfile--n) | | `_NO_GETTEXT` | Disable translations support (via `gettext`) | | `_NO_FZF` | Disable support for [alternative TAB completers](https://github.com/leo-arch/clifm/wiki/Specifics#tab-completion) (fzf, fnf, and smenu) | | `_NO_HIGHLIGHT`| Disable [syntax highlighting](https://github.com/leo-arch/clifm/wiki/Specifics#syntax-highlighting) support | | `_NO_ICONS` | Disable [icons](https://github.com/leo-arch/clifm/wiki/Advanced/#icons-smirk) support | | `_NO_LIRA` | Disable [Lira](https://github.com/leo-arch/clifm/wiki/Specifics#resource-opener) support. Implies `_NO_MAGIC` | | `_NO_MAGIC` | Allow compilation without `libmagic` dependency3 | | `NO_MEDIA_FUNC` | Disable the [mountpoints](https://github.com/leo-arch/clifm/wiki/Introduction#mp-mountpoints) and [media](https://github.com/leo-arch/clifm/wiki/Introduction#media) commands. | | `_NO_NETBSD_FFLAGS` | Disable support for BSD file flags (NetBSD only). You can drop the `-lutil` compilation flag. | | `NO_PLEDGE` | Disable support for [**pledge**(2)](https://man.openbsd.org/pledge.2) (OpenBSD only) | | `_NO_SUGGESTIONS` | Disable [suggestions](https://github.com/leo-arch/clifm/wiki/Specifics#auto-suggestions) support | | `_NO_TAGS` | Disable support for [`Etiqueta`, the tags system](https://github.com/leo-arch/clifm/wiki/Common-Operations#tagging-files) | | `_NO_PROFILES` | Disable [user profiles](https://github.com/leo-arch/clifm/wiki/Specifics#profiles) support | | `_NO_SUN_BIRTHTIME` | Compile without files birthtime support (Solaris only). You can drop the `-lnvpair` compilation flag. Use only with the [Solaris-specific Makefile](https://github.com/leo-arch/clifm/blob/master/misc/solaris/Makefile), appending this flag to `CPPFLAGS`. | | `_NO_TRASH` | Disable [trash](https://github.com/leo-arch/clifm/wiki/Common-Operations#trashing-files) support | | `_TOURBIN_QSORT` | Use Alexey Tourbin faster [qsort implementation](https://github.com/svpv/qsort) instead of [qsort(3)](https://www.man7.org/linux/man-pages/man3/qsort.3.html) | | `ALLOW_COREDUMPS` | If running in [secure mode](https://github.com/leo-arch/clifm/wiki/Specifics#security), core dumps are disabled. Compile with this flag to allow them. | | `SECURITY_PARANOID=1-3` | If compiled with this flag, **clifm** runs always in [secure mode](https://github.com/leo-arch/clifm/wiki/Specifics#security). If the value is `1`, the following flags are set: `--secure-cmds --secure-env`; if the value is `2`: `--secure-cmds --secure-env-full`; if the value is `3`: `--secure-cmds --secure-env-full --stealth-mode`. A value of `0` has no effect at all. | | `USE_GENERIC_FS_MONITOR` | Use the generic filesystem events monitor instead of inotify (Linux) or kqueue (BSD) | | `USE_DU1` | Use [**du**(1)](https://www.man7.org/linux/man-pages/man1/du.1.html) instead of our builtin trimmed down implementation ([xdu](https://github.com/leo-arch/clifm/blob/master/src/xdu.c)) | | `VANILLA_READLINE` | Disable all **clifm** specific features added to readline: syntax highlighting, autosuggestions, TAB completion for **clifm** specific features/commands, and alternative TAB completion modes (fzf, fnf, and smenu) | 1 By POSIX-compliance `strict POSIX-1.2008/XSI compliance` is understood: features/fuctions _not_ specified in the POSIX standard are avoided _as much as possible_ (mostly because we still rely heavily on **readline**(3), which is not POSIX). Features/functions disabled in POSIX mode: ACLs, files birth time, capabilities, attributes, and extended attributes, BSD file flags, Solaris doors, non-POSIX options for shell utilities (rm, cp, mv, etc), `inotify`/`kqueue` (replaced by a builtin filesystem events monitor), non-POSIX C functions (like **strcasestr**(3) and **memrchr**(3)) are replaced by builtin functions, and **arc4random**(3) is replaced by the older and less secure **random**(3). For more information about POSIX compliance see https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap02.html#tag_02_01_04. 2 The [stealth mode](https://github.com/leo-arch/clifm/wiki/Specifics#stealth-mode) achieves basically the same functionality: disabling access to config files. However, there is an important difference: if compiled with `CLIFM_SUCKLESS`, functions handling configuration files are directly removed from the source code, resulting in a smaller binary. 3 Without `libmagic`, querying files MIME type implies grabbing the output of the [file(1)](https://www.man7.org/linux/man-pages/man1/file.1.html) command, which of course is not as optimal as directly querying the `libmagic` database itself (we need to run the command, redirect its output to a file, open the file, read it, close it, and then delete it). Though perhaps unnoticiable, this is an important difference. ## 6) Plugins **Clifm**'s plugins, that is, commands or set of commands executed by **clifm**, can be any executable file, be it a shell script, a binary file (C, Python, Go, Rust, or whatever programming language you like). See the [plugins section](https://github.com/leo-arch/clifm/wiki/Advanced#plugins). clifm-1.26.3/src/actions.c000066400000000000000000000277161506632037700153160ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* actions.c -- A few functions for the plugins system */ /* The run_action function is taken from NNN's run_selected_plugin function * (https://github.com/jarun/nnn/blob/master/src/nnn.c), licensed under BSD-2-Clause. * All changes are licensed under GPL-2.0-or-later. */ #include "helpers.h" #include #include #include #include #include "aux.h" #include "checks.h" #include "exec.h" #include "file_operations.h" #include "init.h" #include "messages.h" #include "misc.h" #include "sanitize.h" #include "sort.h" /* num_to_sort_name() */ #include "spawn.h" #include "term.h" /* set_term_title() */ /* Get the executable's path of the action ACTION * Returns this path on success or NULL on error, in which case STATUS * is set to the appropriate error code. */ static char * get_plugin_path(char *action, int *status) { const size_t action_len = strlen(action); /* Remove terminating new line char */ if (action_len > 0 && action[action_len - 1] == '\n') action[action_len - 1] = '\0'; char *cmd = (char *)NULL; int dir_path = 0; size_t cmd_len = 0; if (strchr(action, '/')) { cmd = xnmalloc(action_len + 1, sizeof(char)); xstrsncpy(cmd, action, action_len + 1); dir_path = 1; } else { /* If not a path, PLUGINS_DIR is assumed */ if (!plugins_dir || !*plugins_dir) { xerror("%s\n", _("actions: Plugins directory not defined")); *status = FUNC_FAILURE; return (char *)NULL; } cmd_len = action_len + strlen(plugins_dir) + 2; cmd = xnmalloc(cmd_len, sizeof(char)); snprintf(cmd, cmd_len, "%s/%s", plugins_dir, action); } /* Check if the action file exists and is executable */ if (access(cmd, X_OK) == 0) return cmd; /* Not in local dir. Let's check the system data dir as well */ if (data_dir && dir_path == 0) { cmd_len = action_len + strlen(data_dir) + (sizeof(PROGRAM_NAME) - 1) + 11; cmd = xnrealloc(cmd, cmd_len, sizeof(char)); snprintf(cmd, cmd_len, "%s/%s/plugins/%s", data_dir, PROGRAM_NAME, action); if (access(cmd, X_OK) == 0) return cmd; } free(cmd); *status = ENOENT; xerror("actions: '%s': %s\n", action, strerror(ENOENT)); return (char *)NULL; } static void export_status_values(void) { if (cur_cscheme && *cur_cscheme) setenv("CLIFM_COLOR_SCHEME", cur_cscheme, 1); if (conf.colorize != 1) setenv("CLIFM_COLORLESS", "1", 1); setenv("CLIFM_CUR_WS", xitoa(cur_ws + 1), 1); setenv("CLIFM_DIRS_FIRST", conf.list_dirs_first == 1 ? "1" : "0", 1); setenv("CLIFM_FILES_COUNTER", conf.files_counter == 1 ? "1" : "0", 1); if (filter.str && *filter.str) { setenv("CLIFM_FILES_FILTER", filter.str, 1); setenv("CLIFM_FILTER_REVERSE", filter.rev == 1 ? "1" : "0", 1); } setenv("CLIFM_FOLLOW_LINKS", conf.follow_symlinks == 1 ? "1" : "0", 1); setenv("CLIFM_LIGHT_MODE", conf.light_mode == 1 ? "1" : "0", 1); setenv("CLIFM_LONG_VIEW", conf.long_view == 1 ? "1" : "0", 1); if (conf.max_files >= 0) setenv("CLIFM_MAX_FILES", xitoa(conf.max_files), 1); setenv("CLIFM_ONLY_DIRS", conf.only_dirs == 1 ? "1" : "0", 1); if (plugins_helper_file && *plugins_helper_file) setenv("CLIFM_PLUGINS_HELPER", plugins_helper_file, 1); setenv("CLIFM_PROFILE", alt_profile ? alt_profile : "default", 1); if (sel_file && *sel_file) setenv("CLIFM_SELFILE", sel_file, 1); if (sel_n > 0) setenv("CLIFM_SEL_FILES", xitoa((long long)sel_n), 1); char buf[MAX_INT_STR + 1]; snprintf(buf, sizeof(buf), "%d", conf.show_hidden); setenv("CLIFM_SHOW_HIDDEN", buf, 1); setenv("CLIFM_SORT_REVERSE", conf.sort_reverse == 1 ? "1" : "0", 1); setenv("CLIFM_SORT_STYLE", num_to_sort_name(conf.sort, 0), 1); if (trash_n > 0) setenv("CLIFM_TRASH_FILES", xitoa((long long)trash_n), 1); setenv("CLIFM_TRUNCATE_NAMES", conf.trunc_names == 1 ? "1" : "0", 1); } static void unset_export_values(void) { unsetenv("CLIFM_COLOR_SCHEME"); unsetenv("CLIFM_COLORLESS"); unsetenv("CLIFM_CUR_WS"); unsetenv("CLIFM_DIRS_FIRST"); unsetenv("CLIFM_FILES_COUNTER"); unsetenv("CLIFM_FILES_FILTER"); unsetenv("CLIFM_FILTER_REVERSE"); unsetenv("CLIFM_FOLLOW_LINKS"); unsetenv("CLIFM_LIGHT_MODE"); unsetenv("CLIFM_LONG_VIEW"); unsetenv("CLIFM_MAX_FILES"); unsetenv("CLIFM_ONLY_DIRS"); unsetenv("CLIFM_PLUGINS_HELPER"); unsetenv("CLIFM_PROFILE"); unsetenv("CLIFM_SEL_FILES"); unsetenv("CLIFM_SELFILE"); unsetenv("CLIFM_SHOW_HIDDEN"); unsetenv("CLIFM_SORT_REVERSE"); unsetenv("CLIFM_SORT_STYLE"); unsetenv("CLIFM_TRASH_FILES"); unsetenv("CLIFM_TRUNCATE_NAMES"); } int run_action(char *action, char **args) { if (!action || !*action) return FUNC_FAILURE; if (xargs.secure_cmds == 1) { fprintf(stderr, _("%s: Plugins are not allowed in " "secure-cmds mode\n"), PROGRAM_NAME); return FUNC_FAILURE; } /* ##################################### * # 1) CREATE CMD TO BE EXECUTED # * ##################################### */ /* 1.a Insert plugin's absolute path as command name */ int exit_status = FUNC_FAILURE; char *cmd = get_plugin_path(action, &exit_status); if (!cmd) return exit_status; const size_t cmd_len = strlen(cmd); args[0] = xnrealloc(args[0], cmd_len + 1, sizeof(char)); xstrsncpy(args[0], cmd, cmd_len + 1); free(cmd); /* 1.b Escape non-escaped filenames */ size_t i; for (i = 1; args[i]; i++) { struct stat a; /* If the filename is already escaped, lstat(2) will fail, so that * it won't be reescaped. */ if (!strchr(args[i], ' ') || lstat(args[i], &a) == -1) continue; char *p = escape_str(args[i]); if (p) { free(args[i]); args[i] = p; } } /* ############################## * # 2) CREATE A PIPE FILE # * ############################## */ char *rand_ext = gen_rand_str(RAND_SUFFIX_LEN); if (!rand_ext) return FUNC_FAILURE; char fifo_path[PATH_MAX + 1]; snprintf(fifo_path, sizeof(fifo_path), "%s/.pipe.%s", tmp_dir, rand_ext); free(rand_ext); errno = 0; if (mkfifo(fifo_path, 0600) == -1) { xerror("actions: '%s': %s\n", fifo_path, strerror(errno)); return errno; } export_status_values(); setenv("CLIFM_BUS", fifo_path, 1); if (xargs.cwd_in_title == 1) set_term_title(action); /* ################################################ * # 3) EXEC CMD & LET THE CHILD WRITE TO PIPE # * ################################################ */ pid_t pid = fork(); if (pid == -1) { exit_status = errno; xerror("actions: fork: %s\n", strerror(errno)); goto END; } if (pid == 0) { /* Child: write-only end of the pipe */ const int wfd = open(fifo_path, O_WRONLY | O_CLOEXEC); if (wfd == -1) _exit(EXIT_FAILURE); const int ret = launch_execv(args, FOREGROUND, E_NOFLAG); /* RET will be read later by waitpid(3) to get plugin exit status */ close(wfd); _exit(ret); } /* ######################################## * # 4) LET THE PARENT READ THE PIPE # * ######################################## */ /* Parent: read-only end of the pipe */ int rfd; do { rfd = open(fifo_path, O_RDONLY); } while (rfd == -1 && errno == EINTR); if (rfd == -1) { exit_status = errno; goto END; } char buf[PATH_MAX + 1]; *buf = '\0'; ssize_t buf_len = 0; do { buf_len = read(rfd, buf, sizeof(buf)); /* flawfinder: ignore */ } while (buf_len == -1 && errno == EINTR); buf[buf_len] = '\0'; close(rfd); /* Wait for the child to finish. Otherwise, the child is left as a * zombie process. Store plugin exit status in EXIT_STATUS. */ int status = 0; if (waitpid(pid, &status, 0) > 0) { exit_status = get_exit_code(status, EXEC_FG_PROC); } else { exit_status = errno; xerror("actions: waitpid: %s\n", strerror(errno)); } /* If the pipe is empty */ if (!*buf) goto END; if (buf_len > 0 && buf[buf_len - 1] == '\n') buf[buf_len - 1] = '\0'; struct stat attr; if (lstat(buf, &attr) != -1) { /* If a valid file, open it */ char *o_cmd[] = {"o", buf, NULL}; exit_status = open_function(o_cmd); } else { /* If not a file, take it as a command */ if (xargs.secure_cmds == 1 && sanitize_cmd(buf, SNT_GRAL) != FUNC_SUCCESS) goto END; size_t old_args = args_n; args_n = 0; char **_cmd = parse_input_str(buf); if (_cmd) { char **alias_cmd = check_for_alias(_cmd); if (alias_cmd) { exit_status = exec_cmd_tm(alias_cmd); for (i = 0; alias_cmd[i]; i++) free(alias_cmd[i]); free(alias_cmd); } else { if (!(flags & FAILED_ALIAS)) exit_status = exec_cmd_tm(_cmd); flags &= ~FAILED_ALIAS; for (i = 0; i <= args_n; i++) free(_cmd[i]); free(_cmd); } } args_n = old_args; } END: unlink(fifo_path); if (xargs.cwd_in_title == 1) set_term_title(workspaces[cur_ws].path); unsetenv("CLIFM_BUS"); unset_export_values(); return exit_status; } static int edit_actions(char *app) { if (xargs.stealth_mode == 1) { puts(_("actions: Access to configuration files is not allowed " "in stealth mode")); return FUNC_SUCCESS; } if (!actions_file) return FUNC_FAILURE; /* Get actions file's current modification time */ struct stat attr; if (stat(actions_file, &attr) == -1) { xerror("actions: '%s': %s\n", actions_file, strerror(errno)); return errno; } const time_t mtime_bfr = attr.st_mtime; const int ret = open_config_file(app, actions_file); if (ret != FUNC_SUCCESS) return ret; /* Get modification time after opening the file */ if (stat(actions_file, &attr) == -1) { xerror("actions: '%s': %s\n", actions_file, strerror(errno)); return errno; } if (mtime_bfr == attr.st_mtime) return FUNC_SUCCESS; /* If modification times differ, the file was modified after being opened */ /* Reload the array of available actions */ if (load_actions() != FUNC_SUCCESS) return FUNC_FAILURE; /* Reload PATH commands as well to add new action(s) */ if (bin_commands) { size_t i; for (i = 0; bin_commands[i]; i++) free(bin_commands[i]); free(bin_commands); bin_commands = (char **)NULL; } if (paths) { size_t i; for (i = 0; i < path_n; i++) free(paths[i].path); free(paths); } path_n = get_path_env(1); get_path_programs(); print_reload_msg(NULL, NULL, _("File modified. Actions reloaded.\n")); return FUNC_SUCCESS; } static size_t get_longest_action_name(void) { int i = (int)actions_n; size_t l = 0; while (--i >= 0) { size_t len = strlen(usr_actions[i].name); if (len > l) l = len; } return l; } int actions_function(char **args) { if (!args[1] || strcmp(args[1], "list") == 0) { if (actions_n > 0) { /* Just list available actions */ puts(_("To run a plugin just enter its action name\n" "Example: enter '//' to run the rgfind plugin")); size_t i, longest_name_len = get_longest_action_name(); for (i = 0; i < actions_n; i++) { printf("%-*s %s%s%s %s\n", (int)longest_name_len, usr_actions[i].name, mi_c, SET_MSG_PTR, df_c, usr_actions[i].value); } return FUNC_SUCCESS; } if (xargs.stealth_mode == 1) { fputs(_("actions: Plugins are not allowed in stealth " "mode\n"), stderr); } else { fputs(_("actions: No actions defined. Use the 'actions edit' " "command to add new actions.\n"), stdout); } return FUNC_SUCCESS; } if (strcmp(args[1], "edit") == 0) { return edit_actions(args[2]); } else if (IS_HELP(args[1])) { puts(_(ACTIONS_USAGE)); return FUNC_SUCCESS; } else { fprintf(stderr, "%s\n", _(ACTIONS_USAGE)); return FUNC_FAILURE; } } clifm-1.26.3/src/actions.h000066400000000000000000000020441506632037700153060ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* actions.h */ #ifndef ACTIONS_H #define ACTIONS_H __BEGIN_DECLS int actions_function(char **args); int run_action(char *action, char **args); __END_DECLS #endif /* ACTIONS_H */ clifm-1.26.3/src/archives.c000066400000000000000000000604511506632037700154530ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* archives.c -- archiving functions */ #ifndef _NO_ARCHIVING #include "helpers.h" #include #include #include #if defined(_NO_MAGIC) # if !defined(_BE_POSIX) # include # ifndef _PATH_DEVNULL # define _PATH_DEVNULL "/dev/null" # endif /* _PATH_DEVNULL */ # endif /* !_BE_POSIX */ #endif /* _NO_MAGIC */ #include "aux.h" #include "checks.h" #include "history.h" #include "jump.h" #include "listing.h" #include "mime.h" /* xmagic() */ #include "misc.h" #include "navigation.h" #include "readline.h" #include "spawn.h" #define OP_ISO 1 #define OP_OTHERS 0 static char * ask_user_for_path(void) { const char *m = _("Extraction path ('q' to quit): "); const int poffset_bk = prompt_offset; prompt_offset = (int)strlen(m) + 1; rl_nohist = 1; alt_prompt = FILES_PROMPT; char *ext_path = secondary_prompt(m, NULL); alt_prompt = rl_nohist = 0; prompt_offset = poffset_bk; if (!ext_path) return (char *)NULL; char *p = (char *)NULL; if ((*ext_path == '"' || *ext_path == '\'') && (p = remove_quotes(ext_path))) memmove(ext_path, p, strlen(p) + 1); char *unesc_path = unescape_str(ext_path, 0); if (unesc_path) { free(ext_path); ext_path = unesc_path; } return ext_path; } static char * get_extraction_path(void) { char *ext_path = ask_user_for_path(); if (!ext_path || !*ext_path) { free(ext_path); return (char *)NULL; } if (TOUPPER(*ext_path) == 'Q' && !ext_path[1]) { free(ext_path); return (char *)NULL; } if (*ext_path == '~') { char *p = tilde_expand(ext_path); if (p) { free(ext_path); return p; } } if (*ext_path == '.' || strstr(ext_path, "../")) { char *p = xrealpath(ext_path, NULL); if (p) { free(ext_path); return p; } } return ext_path; } static char get_operation(const int mode) { char sel_op = 0; char *op = (char *)NULL; while (!op) { op = rl_no_hist(_("Operation: "), 0); if (!op) continue; if (!*op || op[1] != '\0') { free(op); op = (char *)NULL; continue; } switch (*op) { case 'e': /* fallthrough */ case 'E': /* fallthrough */ case 'l': /* fallthrough */ case 'm': /* fallthrough */ case 't': /* fallthrough */ case 'r': if (mode == OP_ISO && *op == 'r') { free(op); op = (char *)NULL; break; } if (mode == OP_OTHERS && *op == 't') { free(op); op = (char *)NULL; break; } sel_op = *op; free(op); break; case 'q': /* fallthrough */ case 'Q': free(op); return FUNC_SUCCESS; default: free(op); op = (char *)NULL; break; } if (sel_op) break; } return sel_op; } static int extract_iso(char *file) { int exit_status = FUNC_SUCCESS; /* 7z x -oDIR FILE (use FILE as DIR) */ const size_t flen = strlen(file); char *o_option = xnmalloc(flen + 7, sizeof(char)); snprintf(o_option, flen + 7, "-o%s.dir", file); /* Construct and execute cmd */ char *cmd[] = {"7z", "x", o_option, file, NULL}; if (launch_execv(cmd, FOREGROUND, E_NOFLAG) != FUNC_SUCCESS) exit_status = FUNC_FAILURE; free(o_option); return exit_status; } static int extract_iso_to_dir(char *file) { /* 7z x -oDIR FILE (ask for DIR) */ int exit_status = FUNC_SUCCESS; char *ext_path = get_extraction_path(); if (!ext_path) return FUNC_FAILURE; const size_t len = strlen(ext_path); char *o_option = xnmalloc(len + 3, sizeof(char)); snprintf(o_option, len + 3, "-o%s", ext_path); free(ext_path); /* Construct and execute cmd */ char *cmd[] = {"7z", "x", o_option, file, NULL}; if (launch_execv(cmd, FOREGROUND, E_NOFLAG) != FUNC_SUCCESS) exit_status = FUNC_FAILURE; free(o_option); return exit_status; } static int list_iso_contents(char *file) { int exit_status = FUNC_SUCCESS; /* 7z l FILE */ char *cmd[] = {"7z", "l", file, NULL}; if (launch_execv(cmd, FOREGROUND, E_NOFLAG) != FUNC_SUCCESS) exit_status = FUNC_FAILURE; return exit_status; } static int test_iso(char *file) { int exit_status = FUNC_SUCCESS; /* 7z t FILE */ char *cmd[] = {"7z", "t", file, NULL}; if (launch_execv(cmd, FOREGROUND, E_NOFLAG) != FUNC_SUCCESS) exit_status = FUNC_FAILURE; return exit_status; } /* Create mountpoint for file. Returns the path to the mountpoint in case * of success, or NULL in case of error. */ static char * create_mountpoint(char *file) { char *mountpoint = (char *)NULL; char *p = strrchr(file, '/'); char *tfile = (p && *(++p)) ? p : file; if (xargs.stealth_mode == 1) { const size_t len = strlen(tfile) + P_tmpdir_len + 15; mountpoint = xnmalloc(len, sizeof(char)); snprintf(mountpoint, len, "%s/clifm-mounts/%s", P_tmpdir, tfile); } else { const size_t len = config_dir_len + strlen(tfile) + 9; mountpoint = xnmalloc(len, sizeof(char)); snprintf(mountpoint, len, "%s/mounts/%s", config_dir, tfile); } char *dir_cmd[] = {"mkdir", "-pm700", mountpoint, NULL}; if (launch_execv(dir_cmd, FOREGROUND, E_NOFLAG) != FUNC_SUCCESS) { free(mountpoint); mountpoint = (char *)NULL; } return mountpoint; } #if defined(__linux__) static int cd_to_mountpoint(char *file, char *mountpoint) { if (xchdir(mountpoint, SET_TITLE) == -1) { xerror("archiver: '%s': %s\n", mountpoint, strerror(errno)); return FUNC_FAILURE; } free(workspaces[cur_ws].path); workspaces[cur_ws].path = savestring(mountpoint, strlen(mountpoint)); add_to_jumpdb(workspaces[cur_ws].path); int exit_status = FUNC_SUCCESS; if (conf.autols == 1) { reload_dirlist(); add_to_dirhist(workspaces[cur_ws].path); } else { printf("'%s': Successfully mounted on '%s'\n", file, mountpoint); } return exit_status; } #endif /* __linux__ */ static int mount_iso(char *file) { #if !defined(__linux__) UNUSED(file); xerror("%s\n", _("mount: This feature is available for Linux only.")); return FUNC_SUCCESS; #else char *mountpoint = create_mountpoint(file); if (!mountpoint) return FUNC_FAILURE; /* Construct and execute the cmd */ char *sudo = get_sudo_path(); if (!sudo) { free(mountpoint); return FUNC_FAILURE; } char *cmd[] = {sudo, "mount", "-o", "loop", file, mountpoint, NULL}; if (confirm_sudo_cmd(cmd) == 0) { free(mountpoint); free(sudo); return FUNC_SUCCESS; } if (launch_execv(cmd, FOREGROUND, E_NOFLAG) != FUNC_SUCCESS) { free(mountpoint); free(sudo); return FUNC_FAILURE; } free(sudo); int exit_status = cd_to_mountpoint(file, mountpoint); free(mountpoint); return exit_status; #endif /* __linux__ */ } /* Use 7z to * list (l) * extract (e) * extrat to dir (x -oDIR FILE) * test (t) */ static int handle_iso(char *file) { printf(_("%s[e]%sxtract %s[E]%sxtract-to-dir %s[l]%sist " "%s[t]%sest %s[m]%sount %s[q]%suit\n"), BOLD, df_c, BOLD, df_c, BOLD, df_c, BOLD, df_c, BOLD, df_c, BOLD, df_c); char sel_op = get_operation(OP_ISO); if (strchr(file, '\\')) { char *deq_file = unescape_str(file, 0); if (deq_file) { xstrsncpy(file, deq_file, strlen(deq_file) + 1); free(deq_file); } } switch (sel_op) { case 'e': return extract_iso(file); case 'E': return extract_iso_to_dir(file); case 'l': return list_iso_contents(file); case 'm': return mount_iso(file); case 't': return test_iso(file); default: return FUNC_SUCCESS; } } static int create_iso_from_block_dev(char *in_file, char *out_file) { size_t len = strlen(in_file) + 4; char *if_option = xnmalloc(len, sizeof(char)); snprintf(if_option, len, "if=%s", in_file); len = strlen(out_file) + 4; char *of_option = xnmalloc(len, sizeof(char)); snprintf(of_option, len, "of=%s", out_file); char *sudo = get_sudo_path(); if (!sudo) { free(if_option); free(of_option); return FUNC_FAILURE; } int exit_status = FUNC_SUCCESS; char *cmd[] = {sudo, "dd", if_option, of_option, "bs=64k", "conv=noerror,sync", "status=progress", NULL}; if (confirm_sudo_cmd(cmd) == 1) { if (launch_execv(cmd, FOREGROUND, E_NOFLAG) != FUNC_SUCCESS) exit_status = FUNC_FAILURE; } free(sudo); free(if_option); free(of_option); return exit_status; } static int create_iso(char *in_file, char *out_file) { struct stat attr; if (lstat(in_file, &attr) == -1) { xerror("archiver: '%s': %s\n", in_file, strerror(errno)); return FUNC_FAILURE; } /* If IN_FILE is a directory */ if (S_ISDIR(attr.st_mode)) { char *cmd[] = {"mkisofs", "-R", "-o", out_file, in_file, NULL}; if (launch_execv(cmd, FOREGROUND, E_NOFLAG) != FUNC_SUCCESS) return FUNC_FAILURE; return FUNC_SUCCESS; } /* If IN_FILE is a block device */ if (S_ISBLK(attr.st_mode)) return create_iso_from_block_dev(in_file, out_file); /* If any other file format */ xerror(_("archiver: '%s': Invalid file format. File should be either " "a directory or a block device.\n"), in_file); return FUNC_FAILURE; } /* Check the MIME type of the file named FILE and look for "ISO 9660" in its * output. Returns zero if found, one if not, and -1 in case of error. */ static int check_iso(char *file) { if (!file || !*file) { xerror("%s\n", _("Error querying file type")); return (-1); } int is_iso = 0; char *t = xmagic(file, TEXT_DESC); if (!t) { xerror("%s\n", _("Error querying file type")); return (-1); } if (strstr(t, "ISO 9660")) is_iso = 1; free(t); return (is_iso == 1 ? FUNC_SUCCESS : FUNC_FAILURE); } static int check_compressed(const char *line, const int test_iso) { return (strstr(line, "archive") || strstr(line, "compressed") || strncmp(line, "Debian binary package ", 22) == 0 || strncmp(line, "RPM ", 4) == 0 || (test_iso && strstr(line, "ISO 9660"))); } /* Check the MIME type of the file named FILE and look for "archive" and * "compressed" strings. Returns zero if compressed, one if not, and -1 * in case of error. * test_iso is used to determine if ISO files should be checked as * well: this is the case when called from open_function() or * mime_open(), since both need to check compressed and ISOs as * well (and there is no need to run two functions (is_compressed and * check_iso), when we can run just one). */ int is_compressed(char *file, const int test_iso) { if (!file || !*file) { xerror("%s\n", _("Error querying file type")); return (-1); } char *t = xmagic(file, TEXT_DESC); if (!t) { xerror("%s\n", _("Error querying file type")); return (-1); } const int compressed = check_compressed(t, test_iso); free(t); return (compressed == 1 ? FUNC_SUCCESS : FUNC_FAILURE); } static char * add_default_extension(char *name) { const size_t name_len = strlen(name); char *t = savestring(name, name_len); name = xnrealloc(name, name_len + 8, sizeof(char)); snprintf(name, name_len + 8, "%s.tar.gz", t); free(t); return name; } /* Get archive name/type */ static char * get_archive_filename(void) { puts(_("Use extension to specify archive/compression type " "(defaults to .tar.gz)\nExample: myarchive.xz")); char *name = (char *)NULL; while (!name) { flags |= NO_FIX_RL_POINT; name = rl_no_hist(_("Filename ('q' to quit): "), 0); flags &= ~NO_FIX_RL_POINT; if (!name || !*name) { free(name); name = (char *)NULL; continue; } if (*name == 'q' && name[1] == '\0') { free(name); return (char *)NULL; } char *dot = strrchr(name, '.'); if (!dot) /* If no extension, add the default */ return add_default_extension(name); if (dot == name) { /* Dot is first char */ xerror("%s\n", _("Invalid filename")); free(name); name = (char *)NULL; continue; } } return name; } /* If MODE is 'c', compress IN_FILE producing a zstandard compressed * file named OUT_FILE. If MODE is 'd', extract, test or get * information about IN_FILE. OP is used only for the 'd' mode: it * tells if we have one or multiple file. Returns zero on success and * one on error. */ static int zstandard(char *in_file, char *out_file, const char mode, const char op) { int exit_status = FUNC_SUCCESS; char *deq_file = unescape_str(in_file, 0); if (!deq_file) { xerror(_("archiver: '%s': Error unescaping filename\n"), in_file); return FUNC_FAILURE; } if (mode == 'c') { if (out_file) { char *cmd[] = {"zstd", "-zo", out_file, deq_file, NULL}; if (launch_execv(cmd, FOREGROUND, E_NOFLAG) != FUNC_SUCCESS) exit_status = FUNC_FAILURE; } else { char *cmd[] = {"zstd", "-z", deq_file, NULL}; if (launch_execv(cmd, FOREGROUND, E_NOFLAG) != FUNC_SUCCESS) exit_status = FUNC_FAILURE; } free(deq_file); return exit_status; } /* mode == 'd' */ /* op is non-zero when multiple files, including at least one * zst file, are passed to the archiver function. */ if (op != 0) { char option[3] = ""; switch (op) { case 'e': xstrsncpy(option, "-d", sizeof(option)); break; case 't': xstrsncpy(option, "-t", sizeof(option)); break; case 'i': xstrsncpy(option, "-l", sizeof(option)); break; default: break; } char *cmd[] = {"zstd", option, deq_file, NULL}; exit_status = launch_execv(cmd, FOREGROUND, E_NOFLAG); free(deq_file); if (exit_status != FUNC_SUCCESS) return FUNC_FAILURE; return FUNC_SUCCESS; } printf(_("%s[e]%sxtract %s[t]%sest %s[i]%snfo %s[q]%suit\n"), BOLD, df_c, BOLD, df_c, BOLD, df_c, BOLD, df_c); char *operation = (char *)NULL; while (!operation) { operation = rl_no_hist(_("Operation: "), 0); if (!operation) continue; if (!*operation || operation[1] != '\0') { free(operation); operation = (char *)NULL; continue; } switch (*operation) { case 'e': { char *cmd[] = {"zstd", "-d", deq_file, NULL}; if (launch_execv(cmd, FOREGROUND, E_NOFLAG) != FUNC_SUCCESS) exit_status = FUNC_FAILURE; } break; case 't': { char *cmd[] = {"zstd", "-t", deq_file, NULL}; if (launch_execv(cmd, FOREGROUND, E_NOFLAG) != FUNC_SUCCESS) exit_status = FUNC_FAILURE; } break; case 'i': { char *cmd[] = {"zstd", "-l", deq_file, NULL}; if (launch_execv(cmd, FOREGROUND, E_NOFLAG) != FUNC_SUCCESS) exit_status = FUNC_FAILURE; } break; case 'q': free(operation); free(deq_file); return FUNC_SUCCESS; default: free(operation); operation = (char *)NULL; break; } } free(operation); free(deq_file); return exit_status; } static int compress_zstandard(char *name, char **args) { if (!args[2]) /* Only one file */ return zstandard(args[1], name, 'c', 0); int exit_status = FUNC_SUCCESS; /* Multiple files */ printf(_("\n%sNOTE%s: Zstandard does not support compression of " "multiple files into a single compressed file. Instead, files " "will be compressed into multiple compressed files using their " "original filenames.\n"), BOLD, df_c); size_t i; for (i = 1; args[i]; i++) { if (zstandard(args[i], NULL, 'c', 0) != FUNC_SUCCESS) exit_status = FUNC_FAILURE; } return exit_status; } static int compress_others(char **args, char *name) { size_t n = 0, i; for (i = 1; args[i]; i++); char *ext_ok = strrchr(name, '.'); char **tcmd = xnmalloc(3 + i + 1, sizeof(char *)); tcmd[0] = savestring("atool", 5); tcmd[1] = savestring("-a", 2); const size_t len = strlen(name) + (!ext_ok ? 7 : 0) + 1; tcmd[2] = xnmalloc(len, sizeof(char *)); snprintf(tcmd[2], len, "%s%s", name, !ext_ok ? ".tar.gz" : ""); n += 3; for (i = 1; args[i]; i++) { char *p = unescape_str(args[i], 0); if (!p) continue; tcmd[n] = savestring(p, strlen(p)); free(p); n++; } tcmd[n] = (char *)NULL; const int ret = launch_execv(tcmd, FOREGROUND, E_NOFLAG); for (i = 0; tcmd[i]; i++) free(tcmd[i]); free(tcmd); return ret; } static int compress_files(char **args) { int exit_status = FUNC_SUCCESS; char *name = get_archive_filename(); if (!name) return exit_status; char *ret = strrchr(name, '.'); /* # ZSTANDARD # */ if (ret && strcmp(ret, ".zst") == 0) { exit_status = compress_zstandard(name, args); free(name); return exit_status; } /* # ISO 9660 # */ if (ret && strcmp(ret, ".iso") == 0) { exit_status = create_iso(args[1], name); free(name); return exit_status; } /* # OTHER FORMATS # */ exit_status = compress_others(args, name); free(name); return exit_status; } /* Return one if at least one non-compressed file is found, zero otherwise */ static int check_not_compressed(char **args) { size_t i; for (i = 1; args[i]; i++) { char *deq = (char *)NULL; if (strchr(args[i], '\\')) { deq = unescape_str(args[i], 0); xstrsncpy(args[i], deq, strlen(deq) + 1); free(deq); } if (is_compressed(args[i], 1) != 0) { xerror(_("archiver: '%s': Not an archive/compressed file\n"), args[i]); return 1; } } return 0; } /* Check whether we have at least one Zstandard file */ static size_t check_zstandard(char **args) { size_t zst = 0, i; for (i = 1; args[i]; i++) { char *mime = xmagic(args[i], MIME_TYPE); if (!mime || !*mime) continue; if (*mime == 'a' && strcmp(mime, "application/zstd") == 0) { zst = 1; free(mime); break; } free(mime); } return zst; } static char get_zstandard_operation(void) { printf(_("%sNOTE%s: Using Zstandard\n"), BOLD, df_c); printf(_("%s[e]%sxtract %s[t]%sest %s[i]%snfo %s[q]%suit\n"), BOLD, df_c, BOLD, df_c, BOLD, df_c, BOLD, df_c); char sel_op = 0; char *operation = (char *)NULL; while (!operation) { operation = rl_no_hist(_("Operation: "), 0); if (!operation) continue; if (!*operation || operation[1] != '\0') { free(operation); operation = (char *)NULL; continue; } switch (*operation) { case 'e': /* fallthrough */ case 't': /* fallthrough */ case 'i': sel_op = *operation; break; case 'q': break; default: free(operation); operation = (char *)NULL; continue; } } free(operation); return sel_op; } static int decompress_zstandard(char **args) { int exit_status = FUNC_SUCCESS; size_t files_num = 0, i; for (i = 1; args[i]; i++) files_num++; if (files_num == 1) { if (zstandard(args[1], NULL, 'd', 0) != FUNC_SUCCESS) exit_status = FUNC_FAILURE; return exit_status; } /* Multiple files */ char sel_op = get_zstandard_operation(); if (sel_op == 0) /* quit */ return FUNC_SUCCESS; for (i = 1; args[i]; i++) { if (zstandard(args[i], NULL, 'd', sel_op) != FUNC_SUCCESS) exit_status = FUNC_FAILURE; } return exit_status; } static int list_others(char **args) { int exit_status = FUNC_SUCCESS; size_t i; for (i = 1; args[i]; i++) { printf(_("%s%sFile%s: %s\n"), (i > 1) ? "\n" : "", BOLD, df_c, args[i]); char *cmd[] = {"atool", "-l", args[i], NULL}; if (launch_execv(cmd, FOREGROUND, E_NOFLAG) != FUNC_SUCCESS) exit_status = FUNC_FAILURE; } return exit_status; } static int extract_to_dir_others(char **args) { int exit_status = FUNC_SUCCESS; size_t i; for (i = 1; args[i]; i++) { /* Ask for extraction path */ printf(_("%sFile%s: %s\n"), BOLD, df_c, args[i]); char *ext_path = get_extraction_path(); if (!ext_path) break; /* Construct and execute cmd */ char *cmd[] = {"atool", "-X", ext_path, args[i], NULL}; if (launch_execv(cmd, FOREGROUND, E_NOFLAG) != FUNC_SUCCESS) exit_status = FUNC_FAILURE; free(ext_path); } return exit_status; } static int extract_others(char **args) { char **tcmd = (char **)NULL; size_t n = 0, i; for (i = 1; args[i]; i++); /* Construct the cmd */ tcmd = xnmalloc(3 + i + 1, sizeof(char *)); tcmd[0] = savestring("atool", 5); tcmd[1] = savestring("-x", 2); tcmd[2] = savestring("-e", 2); n += 3; for (i = 1; args[i]; i++) { tcmd[n] = savestring(args[i], strlen(args[i])); n++; } tcmd[n] = (char *)NULL; /* Launch it */ int exit_status = FUNC_SUCCESS; if (launch_execv(tcmd, FOREGROUND, E_NOFLAG) != FUNC_SUCCESS) exit_status = FUNC_FAILURE; for (i = 0; tcmd[i]; i++) free(tcmd[i]); free(tcmd); return exit_status; } static char * get_repack_format(void) { puts(_("Enter 'q' to quit")); char *format = (char *)NULL; while (!format) { format = rl_no_hist(_("New format (e.g.: .tar.xz): "), 0); if (!format) continue; /* Do not allow any of these characters (mitigate command injection) */ const char invalid_c[] = " \t\n\"\\/'`@$><=;|&{([*?!%"; if (!*format || (*format != '.' && *format != 'q') || strpbrk(format, invalid_c)) { free(format); format = (char *)NULL; continue; } if (*format == 'q' && format[1] == '\0') { free(format); return (char *)NULL; } } return format; } static int repack_others(char **args) { /* Ask for new archive/compression format */ char *format = get_repack_format(); if (!format) /* quit */ return FUNC_SUCCESS; /* Construct and execute the cmd */ size_t n = 0, i; for (i = 1; args[i]; i++); char **tcmd = xnmalloc(4 + i + 1, sizeof(char *)); tcmd[0] = savestring("arepack", 7); tcmd[1] = savestring("-F", 2); tcmd[2] = savestring(format, strlen(format)); tcmd[3] = savestring("-e", 2); n += 4; for (i = 1; args[i]; i++) { tcmd[n] = savestring(args[i], strlen(args[i])); n++; } tcmd[n] = (char *)NULL; int exit_status = FUNC_SUCCESS; if (launch_execv(tcmd, FOREGROUND, E_NOFLAG) != FUNC_SUCCESS) exit_status = FUNC_FAILURE; for (i = 0; tcmd[i]; i++) free(tcmd[i]); free(tcmd); free(format); return exit_status; } static int list_mounted_files(char *mountpoint) { if (xchdir(mountpoint, SET_TITLE) == -1) { xerror("archiver: '%s': %s\n", mountpoint, strerror(errno)); return FUNC_FAILURE; } free(workspaces[cur_ws].path); workspaces[cur_ws].path = savestring(mountpoint, strlen(mountpoint)); add_to_jumpdb(workspaces[cur_ws].path); int exit_status = FUNC_SUCCESS; if (conf.autols == 1) { reload_dirlist(); add_to_dirhist(workspaces[cur_ws].path); } return exit_status; } static int mount_others(char **args) { int exit_status = FUNC_SUCCESS; size_t files_num = 0, i; for (i = 1; args[i]; i++) files_num++; for (i = 1; args[i]; i++) { char *mountpoint = create_mountpoint(args[i]); if (!mountpoint) continue; /* Construct and execute cmd */ char *cmd[] = {"archivemount", args[i], mountpoint, NULL}; if (launch_execv(cmd, FOREGROUND, E_NOFLAG) != FUNC_SUCCESS) { free(mountpoint); continue; } /* List content of mountpoint if there is only one archive */ if (files_num > 1) { printf(_("%s%s%s: Succesfully mounted on %s\n"), BOLD, args[i], df_c, mountpoint); free(mountpoint); continue; } if (list_mounted_files(mountpoint) == FUNC_FAILURE) exit_status = FUNC_FAILURE; free(mountpoint); } return exit_status; } static int decompress_others(char **args) { printf(_("%s[e]%sxtract %s[E]%sxtract-to-dir %s[l]%sist " "%s[m]%sount %s[r]%sepack %s[q]%suit\n"), BOLD, df_c, BOLD, df_c, BOLD, df_c, BOLD, df_c, BOLD, df_c, BOLD, df_c); char sel_op = get_operation(OP_OTHERS); switch (sel_op) { case 'e': return extract_others(args); case 'E': return extract_to_dir_others(args); case 'l': return list_others(args); case 'm': return mount_others(args); case 'r': return repack_others(args); default: break; } return FUNC_SUCCESS; } static int decompress_files(char **args) { if (check_not_compressed(args) == 1) return FUNC_FAILURE; /* # ISO 9660 # */ const char *ret = strrchr(args[1], '.'); if ((ret && strcmp(ret, ".iso") == 0) || check_iso(args[1]) == 0) return handle_iso(args[1]); /* Check if we have at least one Zstandard file */ const size_t zst = check_zstandard(args); /* # ZSTANDARD # */ if (zst == 1) return decompress_zstandard(args); /* # OTHER FORMATS # */ return decompress_others(args); } /* Handle archives and/or compressed files (ARGS) according to MODE: * 'c' for archiving/compression, and 'd' for dearchiving/decompression * (including listing, extracting, repacking, and mounting). Returns * zero on success and one on error. Depends on 'zstd' for Zdtandard * files, 'atool' and 'archivemount' for the remaining types. */ int archiver(char **args, const char mode) { if (!args[1]) return FUNC_FAILURE; if (mode == 'c') return compress_files(args); /* Decompression: mode == 'd' */ return decompress_files(args); } #else void *_skip_me_archiving; #endif /* !_NO_ARCHIVING */ clifm-1.26.3/src/archives.h000066400000000000000000000020621506632037700154520ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* archives.h */ #ifndef ARCHIVES_H #define ARCHIVES_H __BEGIN_DECLS int is_compressed(char *file, const int test_iso); int archiver(char **args, char mode); __END_DECLS #endif /* ARCHIVES_H */ clifm-1.26.3/src/args.c000066400000000000000000001555031506632037700146060ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* args.c -- Handle command line arguments */ #include "helpers.h" #include #include #include /* getpwuid() */ #include #include /* tilde_expand() */ #include #include "aux.h" #include "checks.h" #include "config.h" /* set_time_style */ #include "file_operations.h" #include "init.h" #include "mime.h" #include "mimetypes.h" /* load_user_mimetypes() */ #include "misc.h" #include "navigation.h" #include "profiles.h" #include "sanitize.h" #include "spawn.h" #include "strings.h" #if defined(_NO_PROFILES) || defined(_NO_FZF) || defined(_NO_ICONS) \ || defined(_NO_TRASH) || defined(_BE_POSIX) || defined(_NO_LIRA) # include "messages.h" #endif /* _NO_PROFILES || _NO_FZF || _NO_ICONS || _NO_TRASH */ #ifndef _NO_LIRA # define PREVIEW_FILE 1 # define OPEN_FILE 2 #endif /* _NO_LIRA */ /* Macros to be able to consult the value of a macro string */ #ifdef CLIFM_DATADIR # define STRINGIZE_(x) #x # define STRINGIZE(x) STRINGIZE_(x) #endif /* CLIFM_DATADIR */ #ifdef _BE_POSIX # define OPTSTRING ":a::Ab:B:c:CdDeEfFgGhHiI:j:J:k:lLmMnNo:O:p:P:qQrRsSt:TuUvV:w:WxXyYz:Z" #else # ifdef RUN_CMD # define OPTSTRING "+:a::Ab:c:C:D:eEfFgGhHiIk:lLmoOP:rsStT:vw:xyz:" # else # define OPTSTRING "+:a::Ab:c:D:eEfFgGhHiIk:lLmoOP:rsStT:vw:xyz:" # endif /* RUN_CMD */ #endif /* _BE_POSIX */ #ifndef _BE_POSIX /* Macros for long options. Let's use values >= 200 to avoid conflicts * with short options (a-Z == 65-122). */ #define LOPT_NO_CD_AUTO 200 #define LOPT_NO_OPEN_AUTO 201 #define LOPT_NO_RESTORE_LAST_PATH 202 #define LOPT_NO_TIPS 203 #define LOPT_DISK_USAGE 204 #define LOPT_NO_CLASSIFY 205 #define LOPT_SHARE_SELBOX 206 #define LOPT_RL_VI_MODE 207 #define LOPT_MAX_DIRHIST 208 #define LOPT_SORT_REVERSE 209 #define LOPT_NO_FILES_COUNTER 210 #define LOPT_NO_WELCOME_MESSAGE 211 #define LOPT_NO_CLEAR_SCREEN 212 //#define LOPT_ENABLE_LOGS 213 #define LOPT_MAX_PATH 214 #define LOPT_OPENER 215 #define LOPT_ONLY_DIRS 217 #define LOPT_LIST_AND_QUIT 218 #define LOPT_COLOR_SCHEME 219 #define LOPT_CD_ON_QUIT 220 #define LOPT_NO_DIR_JUMPER 221 #define LOPT_ICONS 222 #define LOPT_ICONS_USE_FILE_COLOR 223 #define LOPT_NO_COLUMNS 224 #define LOPT_NO_COLORS 225 #define LOPT_MAX_FILES 226 #define LOPT_TRASH_AS_RM 227 #define LOPT_CASE_SENS_DIRJUMP 228 #define LOPT_CASE_SENS_PATH_COMP 229 #define LOPT_CWD_IN_TITLE 230 #define LOPT_OPEN 231 #define LOPT_PREVIEW 231 /* Same value as LOPT_OPEN is intended */ #define LOPT_PRINT_SEL 232 #define LOPT_NO_SUGGESTIONS 233 //#define LOPT_AUTOJUMP 234 #define LOPT_NO_HIGHLIGHT 235 #define LOPT_NO_FILE_CAP 236 #define LOPT_NO_FILE_EXT 237 #define LOPT_NO_FOLLOW_SYMLINKS 238 #define LOPT_INT_VARS 240 #define LOPT_STDTAB 241 #define LOPT_NO_WARNING_PROMPT 242 #define LOPT_MNT_UDISKS2 243 #define LOPT_SECURE_ENV 244 #define LOPT_SECURE_ENV_FULL 245 #define LOPT_SECURE_CMDS 246 #define LOPT_FULL_DIR_SIZE 247 #define LOPT_NO_APPARENT_SIZE 248 #define LOPT_NO_HISTORY 249 #define LOPT_NO_REFRESH_ON_RESIZE 251 #define LOPT_BELL 252 #define LOPT_FUZZY_MATCHING 253 #define LOPT_SMENUTAB 254 #define LOPT_VIRTUAL_DIR_FULL_PATHS 255 #define LOPT_VIRTUAL_DIR 256 #define LOPT_DESKTOP_NOTIFICATIONS 257 #define LOPT_VT100 258 #define LOPT_NO_FZFPREVIEW 259 #define LOPT_FZFPREVIEW 260 /* legacy: preview is now default */ #define LOPT_FZFPREVIEW_HIDDEN 261 #define LOPT_SHOTGUN_FILE 262 #define LOPT_FZFTAB 263 #define LOPT_SI 264 #define LOPT_DATA_DIR 265 #define LOPT_FUZZY_ALGO 266 #define LOPT_SEL_FILE 267 #define LOPT_NO_TRUNC_NAMES 268 #define LOPT_NO_BOLD 269 #define LOPT_FNFTAB 270 #define LOPT_STAT 271 #define LOPT_STAT_FULL 272 #define LOPT_READONLY 273 #define LOPT_LSCOLORS 274 #define LOPT_PROP_FIELDS 275 #define LOPT_TIME_STYLE 276 #define LOPT_PTIME_STYLE 277 #define LOPT_COLOR_LNK_AS_TARGET 278 #define LOPT_PAGER_VIEW 279 #define LOPT_NO_UNICODE 280 #define LOPT_UNICODE 281 #define LOPT_ALT_MIMEFILE 282 #define LOPT_REPORT_CWD 283 #define LOPT_KITTY_KEYS 284 #define LOPT_TABMODE 285 /* Link long (--option) and short options (-o) for the getopt_long function. */ static struct option const longopts[] = { {"show-hidden", optional_argument, 0, 'a'}, {"no-hidden", no_argument, 0, 'A'}, {"bookmarks-file", required_argument, 0, 'b'}, {"config-file", required_argument, 0, 'c'}, #ifdef RUN_CMD {"cmd", required_argument, 0, 'C'}, #endif /* RUN_CMD */ {"config-dir", required_argument, 0, 'D'}, {"no-eln", no_argument, 0, 'e'}, {"eln-use-workspace-color", no_argument, 0, 'E'}, {"dirs-first", no_argument, 0, 'f'}, {"no-dirs-first", no_argument, 0, 'F'}, {"pager", no_argument, 0, 'g'}, {"no-pager", no_argument, 0, 'G'}, {"help", no_argument, 0, 'h'}, {"horizontal-list", no_argument, 0, 'H'}, {"no-case-sensitive", no_argument, 0, 'i'}, {"case-sensitive", no_argument, 0, 'I'}, {"keybindings-file", required_argument, 0, 'k'}, {"long-view", no_argument, 0, 'l'}, {"follow-symlinks-long", no_argument, 0, 'L'}, {"dirhist-map", no_argument, 0, 'm'}, {"autols", no_argument, 0, 'o'}, {"no-autols", no_argument, 0, 'O'}, {"path", required_argument, 0, 'p'}, {"profile", required_argument, 0, 'P'}, {"no-refresh-on-emtpy-line", no_argument, 0, 'r'}, {"splash", no_argument, 0, 's'}, {"stealth-mode", no_argument, 0, 'S'}, {"disk-usage-analyzer", no_argument, 0, 't'}, {"trash-dir", required_argument, 0, 'T'}, {"version", no_argument, 0, 'v'}, {"workspace", required_argument, 0, 'w'}, {"no-ext-cmds", no_argument, 0, 'x'}, {"light-mode", no_argument, 0, 'y'}, {"sort", required_argument, 0, 'z'}, /* Only-long options */ {"bell", required_argument, 0, LOPT_BELL}, {"case-sens-dirjump", no_argument, 0, LOPT_CASE_SENS_DIRJUMP}, {"case-sens-path-comp", no_argument, 0, LOPT_CASE_SENS_PATH_COMP}, {"cd-on-quit", no_argument, 0, LOPT_CD_ON_QUIT}, {"color-scheme", required_argument, 0, LOPT_COLOR_SCHEME}, {"color-links-as-target", no_argument, 0, LOPT_COLOR_LNK_AS_TARGET}, {"cwd-in-title", no_argument, 0, LOPT_CWD_IN_TITLE}, {"data-dir", required_argument, 0, LOPT_DATA_DIR}, {"desktop-notifications", optional_argument, 0, LOPT_DESKTOP_NOTIFICATIONS}, {"disk-usage", no_argument, 0, LOPT_DISK_USAGE}, {"fnftab", no_argument, 0, LOPT_FNFTAB}, {"full-dir-size", no_argument, 0, LOPT_FULL_DIR_SIZE}, {"fuzzy-matching", no_argument, 0, LOPT_FUZZY_MATCHING}, {"fuzzy-algo", required_argument, 0, LOPT_FUZZY_ALGO}, {"fzfpreview", no_argument, 0, LOPT_FZFPREVIEW}, /* Legacy: is default now */ {"fzfpreview-hidden", no_argument, 0, LOPT_FZFPREVIEW_HIDDEN}, {"fzftab", no_argument, 0, LOPT_FZFTAB}, {"icons", no_argument, 0, LOPT_ICONS}, {"icons-use-file-color", no_argument, 0, LOPT_ICONS_USE_FILE_COLOR}, {"int-vars", no_argument, 0, LOPT_INT_VARS}, {"kitty-keys", no_argument, 0, LOPT_KITTY_KEYS}, {"list-and-quit", no_argument, 0, LOPT_LIST_AND_QUIT}, {"ls", no_argument, 0, LOPT_LIST_AND_QUIT}, {"lscolors", no_argument, 0, LOPT_LSCOLORS}, {"max-dirhist", required_argument, 0, LOPT_MAX_DIRHIST}, {"max-files", required_argument, 0, LOPT_MAX_FILES}, {"max-path", required_argument, 0, LOPT_MAX_PATH}, /* Deprecated */ {"mimelist-file", required_argument, 0, LOPT_ALT_MIMEFILE}, {"mnt-udisks2", no_argument, 0, LOPT_MNT_UDISKS2}, {"no-apparent-size", no_argument, 0, LOPT_NO_APPARENT_SIZE}, {"no-bold", no_argument, 0, LOPT_NO_BOLD}, {"no-cd-auto", no_argument, 0, LOPT_NO_CD_AUTO}, {"no-classify", no_argument, 0, LOPT_NO_CLASSIFY}, {"no-clear-screen", no_argument, 0, LOPT_NO_CLEAR_SCREEN}, {"no-colors", no_argument, 0, LOPT_NO_COLORS}, {"no-columns", no_argument, 0, LOPT_NO_COLUMNS}, {"no-dir-jumper", no_argument, 0, LOPT_NO_DIR_JUMPER}, {"no-file-cap", no_argument, 0, LOPT_NO_FILE_CAP}, {"no-files-counter", no_argument, 0, LOPT_NO_FILES_COUNTER}, /* Deprecated */ {"no-file-counter", no_argument, 0, LOPT_NO_FILES_COUNTER}, {"no-file-ext", no_argument, 0, LOPT_NO_FILE_EXT}, {"no-follow-symlinks", no_argument, 0, LOPT_NO_FOLLOW_SYMLINKS}, {"no-fzfpreview", no_argument, 0, LOPT_NO_FZFPREVIEW}, {"no-highlight", no_argument, 0, LOPT_NO_HIGHLIGHT}, {"no-history", no_argument, 0, LOPT_NO_HISTORY}, {"no-open-auto", no_argument, 0, LOPT_NO_OPEN_AUTO}, {"no-refresh-on-resize", no_argument, 0, LOPT_NO_REFRESH_ON_RESIZE}, {"no-restore-last-path", no_argument, 0, LOPT_NO_RESTORE_LAST_PATH}, {"no-suggestions", no_argument, 0, LOPT_NO_SUGGESTIONS}, {"no-tips", no_argument, 0, LOPT_NO_TIPS}, {"no-trim-names", no_argument, 0, LOPT_NO_TRUNC_NAMES}, /* Deprecated */ {"no-truncate-names", no_argument, 0, LOPT_NO_TRUNC_NAMES}, {"no-unicode", no_argument, 0, LOPT_NO_UNICODE}, {"no-warning-prompt", no_argument, 0, LOPT_NO_WARNING_PROMPT}, {"no-welcome-message", no_argument, 0, LOPT_NO_WELCOME_MESSAGE}, {"only-dirs", no_argument, 0, LOPT_ONLY_DIRS}, {"open", required_argument, 0, LOPT_OPEN}, {"opener", required_argument, 0, LOPT_OPENER}, {"pager-view", required_argument, 0, LOPT_PAGER_VIEW}, {"physical-size", no_argument, 0, LOPT_NO_APPARENT_SIZE}, {"ptime-style", required_argument, 0, LOPT_PTIME_STYLE}, {"preview", required_argument, 0, LOPT_PREVIEW}, {"print-sel", no_argument, 0, LOPT_PRINT_SEL}, {"prop-fields", required_argument, 0, LOPT_PROP_FIELDS}, {"readonly", no_argument, 0, LOPT_READONLY}, {"report-cwd", no_argument, 0, LOPT_REPORT_CWD}, {"rl-vi-mode", no_argument, 0, LOPT_RL_VI_MODE}, {"share-selbox", no_argument, 0, LOPT_SHARE_SELBOX}, {"sort-reverse", no_argument, 0, LOPT_SORT_REVERSE}, {"trash-as-rm", no_argument, 0, LOPT_TRASH_AS_RM}, {"secure-cmds", no_argument, 0, LOPT_SECURE_CMDS}, {"secure-env", no_argument, 0, LOPT_SECURE_ENV}, {"secure-env-full", no_argument, 0, LOPT_SECURE_ENV_FULL}, {"sel-file", required_argument, 0, LOPT_SEL_FILE}, {"shotgun-file", required_argument, 0, LOPT_SHOTGUN_FILE}, {"si", no_argument, 0, LOPT_SI}, {"smenutab", no_argument, 0, LOPT_SMENUTAB}, {"stat", required_argument, 0, LOPT_STAT}, {"stat-full", required_argument, 0, LOPT_STAT_FULL}, {"stdtab", no_argument, 0, LOPT_STDTAB}, {"tabmode", required_argument, 0, LOPT_TABMODE}, {"time-style", required_argument, 0, LOPT_TIME_STYLE}, {"unicode", no_argument, 0, LOPT_UNICODE}, {"virtual-dir", required_argument, 0, LOPT_VIRTUAL_DIR}, {"virtual-dir-full-paths", no_argument, 0, LOPT_VIRTUAL_DIR_FULL_PATHS}, {"vt100", no_argument, 0, LOPT_VT100}, {0, 0, 0, 0} }; #endif /* !_BE_POSIX */ __attribute__ ((noreturn)) static void err_arg_required(const char *arg) { #ifdef _BE_POSIX char *optname = "-h"; #else char *optname = "--help"; #endif /* _BE_POSIX */ fprintf(stderr, _("%s: '%s': Option requires an argument\n" "Try '%s %s' for more information.\n"), PROGRAM_NAME, arg, PROGRAM_NAME, optname); exit(EXIT_FAILURE); } #ifndef _BE_POSIX __attribute__ ((noreturn)) static void err_invalid_opt(const char *arg) { fprintf(stderr, _("%s: '%s': Unrecognized option\n" "Try '%s --help' for more information.\n"), PROGRAM_NAME, arg, PROGRAM_NAME); exit(EXIT_FAILURE); } #endif /* If path was not set (neither in the config file nor via command line nor * via the RestoreLastPath option), set the default (CWD), and if CWD is not * set, use the user's home directory, and if the home dir cannot be found * either, try the root directory, and if we have no access to the root dir * either, exit. */ static void set_cur_workspace(void) { if (workspaces[cur_ws].path) return; char p[PATH_MAX + 1] = ""; char *cwd = get_cwd(p, sizeof(p), 0); if (cwd && *cwd) { workspaces[cur_ws].path = savestring(cwd, strlen(cwd)); return; } if (user.home) { workspaces[cur_ws].path = savestring(user.home, user.home_len); return; } if (access("/", R_OK | X_OK) != -1) { workspaces[cur_ws].path = savestring("/", 1); return; } xerror("%s: '/': %s\n", PROGRAM_NAME, strerror(errno)); exit(EXIT_FAILURE); } int set_start_path(void) { /* Last path is overriden by positional parameters in the command line */ if (conf.restore_last_path == 1) get_last_path(); if (cur_ws == UNSET) cur_ws = DEF_CUR_WS; if (cur_ws > MAX_WS - 1) { cur_ws = DEF_CUR_WS; err('w', PRINT_PROMPT, _("%s: '%zu': Invalid workspace." "\nFalling back to workspace %zu.\n"), PROGRAM_NAME, cur_ws, cur_ws + 1); } prev_ws = cur_ws; set_cur_workspace(); /* Make path the CWD. */ const int ret = xchdir(workspaces[cur_ws].path, NO_TITLE); char tmp[PATH_MAX + 1] = ""; char *pwd = get_cwd(tmp, sizeof(tmp), 0); /* If chdir() fails, set path to PWD, list files and print the * error message. If no access to PWD either, exit. */ if (ret == -1) { err('e', PRINT_PROMPT, "%s: chdir: '%s': %s\n", PROGRAM_NAME, workspaces[cur_ws].path, strerror(errno)); if (!pwd || !*pwd) { err(0, NOPRINT_PROMPT, _("%s: Fatal error! Failure " "retrieving the current working directory.\n"), PROGRAM_NAME); exit(EXIT_FAILURE); } free(workspaces[cur_ws].path); workspaces[cur_ws].path = savestring(pwd, strlen(pwd)); } /* Set OLDPWD. */ if (pwd && *pwd && (!workspaces || !workspaces[cur_ws].path || strcmp(workspaces[cur_ws].path, pwd) != 0)) setenv("OLDPWD", pwd, 1); dir_changed = 1; return FUNC_SUCCESS; } /* Check whether DIR contains the 'clifm/clifmrc' file, in which case we * assume this is clifm's data directory. * Returns a malloc'ed copy of DIR in case of success, or NULL on error. */ static char * try_datadir(const char *dir) { if (!dir || !*dir) return (char *)NULL; struct stat a; char p[PATH_MAX + 5 + ((sizeof(PROGRAM_NAME) - 1) * 2)]; /* Try DIR/clifm/clifmrc */ snprintf(p, sizeof(p), "%s/%s/%src", dir, PROGRAM_NAME, PROGRAM_NAME); if (stat(p, &a) != -1 && S_ISREG(a.st_mode) && a.st_size > 0) return savestring(dir, strlen(dir)); return (char *)NULL; } /* Same as try_datadir(), but performs a few extra checks. */ static char * try_datadir_from_param(const char *dir) { if (!dir || !*dir) return (char *)NULL; /* Remove ending "/bin" from DIR */ char *r = strrchr(dir, '/'); if (r && *(++r) == 'b' && strcmp(r, "bin") == 0) *(r - 1) = '\0'; struct stat a; char p[PATH_MAX + 1]; /* Try DIR/clifmrc */ snprintf(p, sizeof(p), "%s/%src", dir, PROGRAM_NAME); if (stat(p, &a) != -1 && S_ISREG(a.st_mode) && a.st_size > 0) { char *tmp = savestring(dir, strlen(dir)); char *ptr = strrchr(tmp, '/'); if (!ptr) { free(tmp); return (char *)NULL; } *ptr = '\0'; return tmp; } /* Try DIR/clifm/clifmrc */ snprintf(p, sizeof(p), "%s/%s/%src", dir, PROGRAM_NAME, PROGRAM_NAME); if (stat(p, &a) != -1 && S_ISREG(a.st_mode) && a.st_size > 0) return savestring(dir, strlen(dir)); /* Try DIR/share/clifm/clifmrc */ snprintf(p, sizeof(p), "%s/share/%s/%src", dir, PROGRAM_NAME, PROGRAM_NAME); if (stat(p, &a) != -1 && S_ISREG(a.st_mode) && a.st_size > 0) { const size_t len = strlen(dir) + 7; char *q = xnmalloc(len, sizeof(char)); snprintf(q, len, "%s/share", dir); return q; } return (char *)NULL; } /* Let's inspect paths in XDG_DATA_DIRS looking for clifm's data directory. * In case of success, the path is stored in data_dir (global) and FUNC_SUCCESS * is returned. Otherwise, FUNC_FAILURE is returned and data_dir is set to NULL. */ static int try_xdg_data_dirs(void) { char *env = xgetenv("XDG_DATA_DIRS", 1); if (!env || !*env) return FUNC_FAILURE; char *str = strtok(env, ":"); if (!str || !*str) { free(env); return FUNC_FAILURE; } if ((data_dir = try_datadir(str)) != NULL) { free(env); return FUNC_SUCCESS; } while ((str = strtok(NULL, ":")) != NULL) { if ((data_dir = try_datadir(str)) != NULL) { free(env); return FUNC_SUCCESS; } } free(env); return FUNC_FAILURE; } /* Let's find out where the data directory is located trying these * directories (and in this order): * $XDG_DATA_HOME * $XDG_DATA_DIRS * /usr/local/share * /usr/share * /opt/local/share * /opt/share * /opt/clifm/share */ static int try_standard_data_dirs(void) { char home_local[PATH_MAX + 1]; *home_local = '\0'; const int sec_env = (xargs.secure_env == 1 || xargs.secure_env_full == 1); char *env = sec_env != 1 ? getenv("XDG_DATA_HOME") : (char *)NULL; if (env && *env) xstrsncpy(home_local, env, sizeof(home_local)); else if (user.home && *user.home) snprintf(home_local, sizeof(home_local), "%s/.local/share", user.home); if ((data_dir = try_datadir(home_local)) != NULL) return FUNC_SUCCESS; if (sec_env != 1 && try_xdg_data_dirs() == FUNC_SUCCESS) return FUNC_SUCCESS; /* Neither XDG_DATA_HOME nor XDG_DATA_DIRS. Let's try a few standard paths */ char *const data_dirs[] = { "/usr/local/share", "/usr/share", "/opt/local/share", "/opt/share", "/opt/clifm/share", #if defined(__HAIKU__) "/boot/system/non-packaged/data", "/boot/system/data", #endif /* __HAIKU__ */ NULL }; size_t i; for (i = 0; data_dirs[i]; i++) { if ((data_dir = try_datadir(data_dirs[i])) != NULL) return FUNC_SUCCESS; } return FUNC_FAILURE; } static char * resolve_absolute_path(const char *s) { if (!s || !*s) return (char *)NULL; char *p = strrchr(s, '/'); char *t = (char *)NULL; if (p && p != s) *p = '\0'; else t = "/"; return try_datadir_from_param(t ? t : s); } static char * resolve_relative_path(const char *s) { if (!s || !*s) return (char *)NULL; char *p = xrealpath(s, NULL); if (!p) return (char *)NULL; char *q = strrchr(p, '/'); if (q && q != p) *q = '\0'; char *r = try_datadir_from_param(p); free(p); return r; } static char * resolve_basename(const char *s) { if (!s || !*s) return (char *)NULL; char *p = get_cmd_path(s); if (!p) return (char *)NULL; char *q = strrchr(p, '/'); if (q && q != p) *q = '\0'; char *r = try_datadir_from_param(p); free(p); return r; } /* Let's try to get the data directory from the path pointed to by ARG * (either --data-dir=PATH or argv[0]). */ static int get_data_dir_from_path(char *arg) { if (!arg || !*arg) return FUNC_FAILURE; char *datadir = (char *)NULL; char *name = *arg == '~' ? tilde_expand(arg) : arg; if (*name == '/' && (datadir = resolve_absolute_path(name))) goto END; if (strchr(name, '/') && (datadir = resolve_relative_path(name))) goto END; datadir = resolve_basename(name); END: if (name != arg) free(name); if (!datadir) return FUNC_FAILURE; data_dir = datadir; return FUNC_SUCCESS; } /* Get the system data directory (usually /usr/local/share), * Try first CLIFM_DATADIR, defined in the Makefile, then a few standard * paths (like XDG_DATA_DIRS), and finally try to guess based on whatever * argv[0] provides. */ void get_data_dir(void) { if (data_dir != NULL) /* DATA_DIR was set via --data-dir */ return; #ifdef CLIFM_DATADIR struct stat a; char p[PATH_MAX + 1]; snprintf(p, sizeof(p), "%s/%s/%src", STRINGIZE(CLIFM_DATADIR), PROGRAM_NAME, PROGRAM_NAME); if (stat(p, &a) != -1 && S_ISREG(a.st_mode)) { data_dir = savestring(STRINGIZE(CLIFM_DATADIR), strlen(STRINGIZE(CLIFM_DATADIR))); return; } #endif /* CLIFM_DATADIR */ if (try_standard_data_dirs() == FUNC_SUCCESS) return; if (get_data_dir_from_path(argv_bk[0]) == FUNC_SUCCESS) return; err('w', PRINT_PROMPT, _("%s: No data directory found. Data files, " "such as plugins and color schemes, may not be available.\n" "Set a custom data directory via the '--data-dir' option.\n"), PROGRAM_NAME); } static char * get_home_sec_env(void) { struct passwd *pw = (struct passwd *)NULL; uid_t u = geteuid(); pw = getpwuid(u); if (!pw) { err('e', PRINT_PROMPT, "%s: getpwuid: %s\n", PROGRAM_NAME, strerror(errno)); exit(EXIT_FAILURE); } return (pw->pw_dir); } /* Return 1 if the size of the file FILENAME is <= MAX_SIZE (in KiB), * or 0 otherwise. */ static int preview_this_file(const char *filename, const char *max_size) { const long s = strtol(max_size, NULL, 10); if (s == 0) return 0; if (s > 0 && s <= INT_MAX) { struct stat a; /* n >> 10 == n / 1024, i.e. n (which is in bytes) in KiB. */ if (stat(filename, &a) != -1 && (a.st_size >> 10) > (off_t)s) return 0; } return 1; } /* Opener/previewer function: open/preview FILENAME and exit. */ __attribute__ ((noreturn)) static void open_reg_exit(char *filename, const int url, const int preview) { if (!filename) exit(EXIT_FAILURE); char *max_size = (preview == 1 && url == 0 && xargs.secure_env != 1 && xargs.secure_env_full != 1) ? getenv("CLIFM_PREVIEW_MAX_SIZE") : NULL; if (max_size && *max_size && is_number(max_size) && preview_this_file(filename, max_size) == 0) exit(EXIT_SUCCESS); char *homedir = (xargs.secure_env == 1 || xargs.secure_env_full == 1) ? get_home_sec_env() : getenv("HOME"); if (!homedir) { xerror(_("%s: Cannot retrieve the home directory\n"), PROGRAM_NAME); exit(EXIT_FAILURE); } tmp_dir = savestring(P_tmpdir, P_tmpdir_len); const char *env_preview_file = (preview == 1 && !alt_preview_file) ? getenv("CLIFM_ALT_PREVIEW_FILE") : NULL; if (env_preview_file && *env_preview_file) { mime_file = savestring(env_preview_file, strlen(env_preview_file)); } else if (alt_preview_file && preview == 1) { mime_file = savestring(alt_preview_file, strlen(alt_preview_file)); } else { const size_t mime_file_len = strlen(homedir) + (alt_profile ? strlen(alt_profile) : 7) + 40; mime_file = xnmalloc(mime_file_len, sizeof(char)); snprintf(mime_file, mime_file_len, "%s/.config/clifm/profiles/%s/%s.clifm", homedir, alt_profile ? alt_profile : "default", preview == 1 ? "preview" : "mimelist"); } if (path_n == 0) path_n = get_path_env(0); check_term(); #ifndef _NO_LIRA if (url == 1 && mime_open_url(filename) == FUNC_SUCCESS) exit(EXIT_SUCCESS); #else UNUSED(url); #endif /* !_NO_LIRA */ char *p = (*filename == '~') ? tilde_expand(filename) : (char *)NULL; const int ret = open_file(p ? p : filename); free(p); exit(ret); } static int set_sort_by_name(const char *name) { size_t i; for (i = 0; i <= SORT_TYPES; i++) { if (*name == *sort_methods[i].name && strcmp(name, sort_methods[i].name) == 0) return sort_methods[i].num; } fprintf(stderr, _("%s: --sort: '%s': Invalid value\n" "Valid values: atime, btime, ctime, mtime, extension, group, " "inode, name,\n none, owner, size, version, " "blocks, links, type.\n"), PROGRAM_NAME, name); exit(EXIT_FAILURE); } static void set_sort(const char *arg) { const int n = !is_number(arg) ? set_sort_by_name(arg) : atoi(arg); if (n < 0 || n > SORT_TYPES) { fprintf(stderr, _("%s: --sort: '%s': Valid values are 0-%d\n"), PROGRAM_NAME, arg, SORT_TYPES); exit(EXIT_FAILURE); } xargs.sort = conf.sort = n; } #ifndef _NO_LIRA /* Open/preview FILE according to MODE: either PREVIEW_FILE or OPEN_FILE */ __attribute__ ((noreturn)) static void open_preview_file(char *file, const int mode) { if (!file) exit(EXIT_FAILURE); if (xargs.stealth_mode == 1) { fprintf(stderr, _("%s: Running in stealth mode. Access to " "configuration files is not allowed.\n"), PROGRAM_NAME); exit(EXIT_FAILURE); } static char buf[PATH_MAX + 1]; char *fpath = file; int url = 1; const int preview = mode == PREVIEW_FILE ? 1 : 0; const size_t flen = fpath ? strlen(file) : 0; struct stat attr; if (IS_FILE_URI(fpath, flen)) { if (strchr(file + FILE_URI_PREFIX_LEN, '%')) { char *ptr = url_decode(file + FILE_URI_PREFIX_LEN); xstrsncpy(buf, ptr ? ptr : file, sizeof(buf)); free(ptr); fpath = buf; } else { fpath = file + FILE_URI_PREFIX_LEN; } if (stat(fpath, &attr) == -1) { xerror("%s: '%s': %s\n", PROGRAM_NAME, file, strerror(errno)); exit(errno); } url = 0; goto RUN; } if (is_url(fpath) == FUNC_FAILURE) { url = 0; if (*fpath != '~' && stat(fpath, &attr) == -1) { xerror("%s: '%s': %s\n", PROGRAM_NAME, fpath, strerror(errno)); exit(errno); } } RUN: xargs.open = preview == 1 ? 0 : 1; xargs.preview = preview == 1 ? 1 : 0; if (preview == 1) clear_term_img(); load_user_mimetypes(); open_reg_exit(fpath, url, preview); /* noreturn */ } #endif /* !_NO_LIRA */ static int check_alt_dir(char *dir) { if (!dir || !*dir) return EINVAL; struct stat a; if (stat(dir, &a) == -1) { char *tmp_cmd[] = {"mkdir", "-p", "--", dir, NULL}; const int ret = launch_execv(tmp_cmd, FOREGROUND, E_NOSTDERR); if (ret != FUNC_SUCCESS) { fprintf(stderr, _("%s: Cannot create directory '%s' (error %d)\n"), PROGRAM_NAME, dir, ret); return ret; } } else if (!S_ISDIR(a.st_mode)) { fprintf(stderr, _("%s: '%s': Not a directory\n"), PROGRAM_NAME, dir); return ENOTDIR; } if (access(dir, W_OK) == -1) { fprintf(stderr, _("%s: '%s': Directory not writable\n"), PROGRAM_NAME, dir); return EXIT_FAILURE; } return 0; } static void set_alt_dir(char *src, char **dest, const char *err_name) { if (!src || !*src || *src == '-') err_arg_required(err_name); /* noreturn */ char *src_exp = (char *)NULL; if (*src == '~') { src_exp = tilde_expand(src); src = src_exp; } const int ret = check_alt_dir(src); if (ret != 0) { free(src_exp); exit(ret); } *dest = savestring(src, strlen(src)); free(src_exp); } #ifndef _BE_POSIX static void set_vt100(void) { xargs.vt100 = 1; xargs.clear_screen = conf.clear_screen = 0; xargs.unicode = 0; xargs.report_cwd = 0; fzftab = 0; tabmode = STD_TAB; } static void set_fzfpreview(const int optc) { #if !defined(_NO_FZF) && !defined(_NO_LIRA) xargs.fzf_preview = 1; conf.fzf_preview = optc == LOPT_FZFPREVIEW ? 1 : 2; xargs.fzftab = fzftab = 1; tabmode = FZF_TAB; #else UNUSED(optc); fprintf(stderr, "%s: --fzf-preview: %s\n", PROGRAM_NAME, _(NOT_AVAILABLE)); exit(EXIT_FAILURE); #endif /* !_NO_FZF && !_NO_LIRA */ } static void set_datadir(char *opt) { if (!opt || !*opt || *opt == '-') err_arg_required("--data-dir"); /* noreturn */ get_data_dir_from_path(opt); } static void set_fuzzy_algo(const char *opt) { const int a = opt ? atoi(opt) : -1; if (a < 1 || a > FUZZY_ALGO_MAX) { fprintf(stderr, _("%s: '%s': Invalid fuzzy algorithm. Valid " "values are either 1 or 2.\n"), PROGRAM_NAME, opt ? opt : "NULL"); exit(EXIT_FAILURE); } xargs.fuzzy_match_algo = conf.fuzzy_match_algo = a; } static void set_bell_style(const char *opt) { const int a = atoi(opt); if (!is_number(opt) || a < 0 || a > 3) { fprintf(stderr, _("%s: '%s': Invalid bell style. Valid values " "are 0:none, 1:audible, 2:visible (requires readline >= 8.1), " "3:flash. Defaults to 'visible', and, if not possible, 'none'.\n"), PROGRAM_NAME, opt); exit(EXIT_FAILURE); } xargs.bell_style = conf.bell_style = a; } static void set_alt_config_dir(char *dir) { set_alt_dir(dir, &alt_config_dir, "--config-dir"); flags |= ALT_PREVIEW_FILE; } static void set_alt_selfile(char *file) { if (!file || !*file || *file == '-') err_arg_required("--sel-file"); /* noreturn */ struct stat a; char *p = normalize_path(file, strlen(file)); if (p && (stat(p, &a) == -1 || S_ISREG(a.st_mode))) { sel_file = p; xargs.sel_file = 1; return; } free(p); fprintf(stderr, _("%s: '%s': Invalid file format\n"), PROGRAM_NAME, file); exit(EXIT_FAILURE); } #endif /* !_BE_POSIX */ static void set_alt_trash_dir(char *dir) { #ifndef _BE_POSIX set_alt_dir(dir, &alt_trash_dir, "-T"); #else set_alt_dir(dir, &alt_trash_dir, "-i"); #endif /* !_BE_POSIX */ } static void set_alt_file(char *src, char **dest, const char *err_name) { if (!src || !*src || *src == '-') err_arg_required(err_name); /* noreturn */ char *tmp = (char *)NULL; if (*src == '~') { tmp = tilde_expand(src); src = tmp; } struct stat a; if (stat(src, &a) == -1) { fprintf(stderr, "%s: '%s': %s\n", PROGRAM_NAME, src, strerror(errno)); exit(errno); } if (!S_ISREG(a.st_mode)) { fprintf(stderr, _("%s: '%s': Not a regular file\n"), PROGRAM_NAME, src); exit(EXIT_FAILURE); } *dest = savestring(src, strlen(src)); free(tmp); } static char * resolve_path(char *file, const size_t flen) { char *s_path = (char *)NULL; if (IS_FILE_URI(file, flen)) { s_path = url_decode(file + FILE_URI_PREFIX_LEN); if (!s_path) { fprintf(stderr, _("%s: '%s': Error decoding filename\n"), PROGRAM_NAME, file); exit(EXIT_FAILURE); } } else if (*file == '~' || strstr(file, "./")) { s_path = normalize_path(file, strlen(file)); if (!s_path) { fprintf(stderr, "%s: '%s': %s\n", PROGRAM_NAME, file, strerror(errno)); exit(errno); } } else if (*file == '/') { s_path = savestring(file, strlen(file)); } else { char tmp[PATH_MAX + 1] = ""; char *cwd = get_cwd(tmp, sizeof(tmp), 0); if (!cwd || !*cwd) { fprintf(stderr, "%s: '%s': %s\n", PROGRAM_NAME, file, strerror(errno)); exit(errno); } const size_t len = strlen(cwd) + strlen(file) + 2; s_path = xnmalloc(len, sizeof(char)); snprintf(s_path, len, "%s/%s", cwd, file); } return s_path; } static char * resolve_starting_path(char *file) { const size_t len = file ? strlen(file) : 0; char *s_path = file ? resolve_path(file, len) : NULL; if (!s_path) return (char *)NULL; if (!IS_FILE_URI(file, len) && is_url(file) == FUNC_SUCCESS) open_reg_exit(file, 1, 0); /* noreturn */ struct stat a; if (stat(s_path, &a) == -1) { fprintf(stderr, "%s: '%s': %s\n", PROGRAM_NAME, file, strerror(errno)); free(s_path); exit(errno); } if (!S_ISDIR(a.st_mode)) { fprintf(stderr, "%s: '%s': %s\n", PROGRAM_NAME, file, strerror(ENOTDIR)); free(s_path); exit(ENOTDIR); } xargs.path = 1; return s_path; } static void set_starting_path(char *s_path) { if (xchdir(s_path, SET_TITLE) == 0) { if (cur_ws == UNSET) cur_ws = DEF_CUR_WS; free(workspaces[cur_ws].path); workspaces[cur_ws].path = savestring(s_path, strlen(s_path)); } else { /* Error changing directory */ if (xargs.list_and_quit == 1) { xerror("%s: '%s': %s\n", PROGRAM_NAME, s_path, strerror(errno)); exit(EXIT_FAILURE); } err('w', PRINT_PROMPT, "%s: '%s': %s\n", PROGRAM_NAME, s_path, strerror(errno)); } } static void set_opener(const char *str, const char *opt) { if (!str || !*str || *str == '-') err_arg_required(opt); if (*str != '~') { conf.opener = savestring(str, strlen(str)); return; } char *ep = tilde_expand(str); if (ep) { conf.opener = savestring(ep, strlen(ep)); free(ep); } else { err('w', PRINT_PROMPT, _("%s: Error expanding tilde. " "Using default opener.\n"), PROGRAM_NAME); } } static void set_alt_profile(const char *name) { #ifndef _NO_PROFILES free(alt_profile); if (validate_profile_name(name) == FUNC_SUCCESS) { alt_profile = savestring(name, strlen(name)); flags |= ALT_PREVIEW_FILE; return; } fprintf(stderr, _("%s: '%s': Invalid profile name\n"), PROGRAM_NAME, name); exit(EXIT_FAILURE); #else UNUSED(name); fprintf(stderr, "%s: profiles: %s\n", PROGRAM_NAME, NOT_AVAILABLE); exit(EXIT_FAILURE); #endif /* !_NO_PROFILES */ } static void set_virtual_dir(const char *str, const char *optname) { if (!str || *str != '/') { fprintf(stderr, _("%s: '%s': Absolute path is required " "as argument\n"), PROGRAM_NAME, optname); exit(EXIT_FAILURE); } stdin_tmp_dir = savestring(optarg, strlen(optarg)); setenv("CLIFM_VIRTUAL_DIR", stdin_tmp_dir, 1); } static void set_max_value(const char *opt, int *xval, int *intval) { if (!is_number(opt)) return; const int opt_int = atoi(opt); if (opt_int >= 0) *xval = *intval = opt_int; } static void set_workspace(const char *opt) { if (!is_number(opt)) goto ERROR; const int opt_int = atoi(opt); if (opt_int >= 0 && opt_int <= MAX_WS) { cur_ws = opt_int - 1; return; } ERROR: fprintf(stderr, _("%s: '%s': Invalid workspace. Valid " "values are 1-8.\n"), PROGRAM_NAME, opt); exit(EXIT_FAILURE); } static void set_color_scheme(const char *opt, const char *optname) { if (!opt || !*opt || *opt == '-') err_arg_required(optname); /* noreturn */ conf.usr_cscheme = savestring(opt, strlen(opt)); } static void set_no_colors(void) { xargs.colorize = conf.colorize = 0; #ifndef _NO_HIGHLIGHT xargs.highlight = conf.highlight = 0; #endif /* !_NO_HIGHLIGHT */ } static void print_tabmode_deprecation_warning(const char *mode, const char *name) { err('w', PRINT_PROMPT, _("%s: '%s' is deprecated. " "Use '--tabmode=%s' instead.\n"), PROGRAM_NAME, mode, name); } static void set_fnftab(const int deprecation_warning) { #ifndef _NO_FZF xargs.fnftab = 1; fzftab = 1; tabmode = FNF_TAB; #else fprintf(stderr, "%s: fnf-tab: %s\n", PROGRAM_NAME, _(NOT_AVAILABLE)); exit(EXIT_FAILURE); #endif /* _NO_FZF */ if (deprecation_warning == 1) print_tabmode_deprecation_warning("--fnftab", "fnf"); } static void set_fzftab(const int deprecation_warning) { #ifndef _NO_FZF xargs.fzftab = fzftab = 1; tabmode = FZF_TAB; #else fprintf(stderr, "%s: fzf-tab: %s\n", PROGRAM_NAME, _(NOT_AVAILABLE)); exit(EXIT_FAILURE); #endif /* !_NO_FZF */ if (deprecation_warning == 1) print_tabmode_deprecation_warning("--fzftab", "fzf"); } static void set_smenutab(const int deprecation_warning) { #ifndef _NO_FZF xargs.smenutab = 1; fzftab = 1; tabmode = SMENU_TAB; #else fprintf(stderr, "%s: smenu-tab: %s\n", PROGRAM_NAME, _(NOT_AVAILABLE)); exit(EXIT_FAILURE); #endif /* !_NO_FZF */ if (deprecation_warning == 1) print_tabmode_deprecation_warning("--smenutab", "smenu"); } static void set_stdtab(const int deprecation_warning) { #ifndef _NO_FZF xargs.fzftab = 0; #endif /* !_NO_FZF */ fzftab = 0; tabmode = STD_TAB; if (deprecation_warning == 1) print_tabmode_deprecation_warning("--stdtab", "standard"); } static void set_no_suggestions(void) { #ifndef _NO_SUGGESTIONS xargs.suggestions = conf.suggestions = 0; #else return; #endif /* !_NO_SUGGESTIONS */ } static void set_trash_as_rm(void) { #ifndef _NO_TRASH xargs.trasrm = conf.tr_as_rm = 1; #else fprintf(stderr, "%s: trash: %s\n", PROGRAM_NAME, NOT_AVAILABLE); exit(EXIT_FAILURE); #endif /* !_NO_TRASH */ } static void set_stat(const int optc, const char *optval) { if (!optval || !*optval || *optval == '-') #ifndef _BE_POSIX err_arg_required(optc == LOPT_STAT ? "--stat" : "--stat-full"); xargs.stat = (optc == LOPT_STAT ? SIMPLE_STAT : FULL_STAT); #else err_arg_required(optc == 'j' ? "-j" : "-J"); xargs.stat = (optc == 'j' ? SIMPLE_STAT : FULL_STAT); #endif /* !_BE_POSIX */ xargs.restore_last_path = conf.restore_last_path = 0; } static void set_show_hidden(const char *val) { if (!val || !*val || *val == '-') { xargs.show_hidden = conf.show_hidden = HIDDEN_TRUE; return; } if (*val == 't' && strcmp(val, "true") == 0) { xargs.show_hidden = conf.show_hidden = HIDDEN_TRUE; } else if (*val == 'f' && strcmp(val, "false") == 0) { xargs.show_hidden = conf.show_hidden = HIDDEN_FALSE; } else if (*val == 'f' && strcmp(val, "first") == 0) { xargs.show_hidden = conf.show_hidden = HIDDEN_FIRST; } else if (*val == 'l' && strcmp(val, "last") == 0) { xargs.show_hidden = conf.show_hidden = HIDDEN_LAST; } else { #ifndef _BE_POSIX fprintf(stderr, _("%s: '--show-hidden': Valid values " "are 'true','first', 'last', or 'false'.\n"), PROGRAM_NAME); #else fprintf(stderr, _("%s: '-a': Valid values " "are 'true','first', 'last', or 'false'.\n"), PROGRAM_NAME); #endif /* !_BE_POSIX */ exit(EXIT_FAILURE); } } #ifndef _BE_POSIX static void set_tabmode(const char *mode) { if (!mode || !*mode || *mode == '-') err_arg_required("--tabmode"); /* noreturn */ if (*mode == 'f' && strcmp(mode, "fzf") == 0) { set_fzftab(0); } else if (*mode == 'f' && strcmp(mode, "fnf") == 0) { set_fnftab(0); } else if (*mode == 's' && strcmp(mode, "smenu") == 0) { set_smenutab(0); } else if (*mode == 's' && strcmp(mode, "standard") == 0) { set_stdtab(0); } else { fprintf(stderr, _("%s: --tabmode: '%s': Invalid value\n" "Valid values: fzf, fnf, smenu, standard.\n"), PROGRAM_NAME, mode); exit(EXIT_FAILURE); } } static void xset_time_style(char *optval, const int ptime) { if (!optval || !*optval || *optval == '-') err_arg_required(ptime == 0 ? "--time-style" : "--ptime-style"); if (ptime == 1) { xargs.ptime_style = 1; set_time_style(optval, &conf.ptime_str, 1); } else { xargs.time_style = 1; set_time_style(optval, &conf.time_str, 0); } } static void xset_prop_fields(const char *optval) { /* --prop-fields accepts a single dash (-) as argument. */ if (!optval || !*optval || (*optval == '-' && optval[1])) err_arg_required("--prop-fields"); xargs.prop_fields_str = 1; xstrsncpy(prop_fields_str, optval, sizeof(prop_fields_str)); set_prop_fields(prop_fields_str); #ifndef ST_BTIME if (prop_fields.time == PROP_TIME_BIRTH) { fprintf(stderr, _("%s: --prop-fields: 'b': Birth time is not " "available on this platform\n"), PROGRAM_NAME); exit(EXIT_FAILURE); } #endif /* !ST_BTIME*/ } static void set_desktop_notifications(const char *val) { if (!val || !*val || *val == '-') { xargs.desktop_notifications = conf.desktop_notifications = DESKTOP_NOTIF_SYSTEM; return; } if (*val == 'k' && strcmp(val, "kitty") == 0) { xargs.desktop_notifications = conf.desktop_notifications = DESKTOP_NOTIF_KITTY; } else if (*val == 's' && strcmp(val, "system") == 0) { xargs.desktop_notifications = conf.desktop_notifications = DESKTOP_NOTIF_SYSTEM; } else if (*val == 'f' && strcmp(val, "false") == 0) { xargs.desktop_notifications = conf.desktop_notifications = DESKTOP_NOTIF_NONE; } else { fprintf(stderr, _("%s: '--desktop-notifications': Valid values " "are 'kitty','system', or 'false'.\n"), PROGRAM_NAME); exit(EXIT_FAILURE); } } static void xset_pager_view(char *arg) { if (!arg || !*arg || *arg == '-') err_arg_required("--pager-view"); if (*arg == 'a' && strcmp(arg, "auto") == 0) { xargs.pager_view = conf.pager_view = PAGER_AUTO; } else if (*arg == 'l' && strcmp(arg, "long") == 0) { xargs.pager_view = conf.pager_view = PAGER_LONG; } else if (*arg == 's' && strcmp(arg, "short") == 0) { xargs.pager_view = conf.pager_view = PAGER_SHORT; } else { fprintf(stderr, _("%s: --pager-view: '%s': Invalid value.\n" "Valid values are 'auto', 'long', and 'short'.\n"), PROGRAM_NAME, arg); exit(EXIT_FAILURE); } } #endif /* !_BE_POSIX */ #ifdef _BE_POSIX static void set_tab_mode(const char *opt) { if (!opt || !*opt || opt[1]) return; const int n = *opt - '0'; switch (n) { case 0: set_stdtab(0); break; case 1: set_fzftab(0); break; case 2: set_smenutab(0); break; case 3: set_fnftab(0); break; default: fprintf(stderr, _("%s: '%s': Valid values are 0-3\n"), PROGRAM_NAME, opt); exit(EXIT_FAILURE); } } #endif /* _BE_POSIX */ /* Set directories passed as positional parameters. */ static int resolve_and_set_starting_paths(char **dirs) { /* By default, the current workspace is the first one (0), unless * specified otherwise using the -w option. */ int ws_num = cur_ws == UNSET ? DEF_CUR_WS : cur_ws; int start_path_set = 0; size_t i = 0; for (i = 0; dirs[i]; i++) { char *spath = resolve_starting_path(dirs[i]); if (!spath) continue; if (i == 0) { /* The first positional parameters is used as starting path, * in the current workspace. */ set_starting_path(spath); start_path_set = 1; } else { /* Subsequent parameters define subsequent workspaces. */ ws_num++; if (ws_num >= MAX_WS) { free(spath); break; } free(workspaces[ws_num].path); workspaces[ws_num].path = savestring(spath, strlen(spath)); workspaces[ws_num].num = ws_num; free(workspaces[ws_num].name); workspaces[ws_num].name = NULL; } free(spath); } return start_path_set; } /* Evaluate command line arguments, if any, and change initial variables to * their corresponding values. */ #ifdef _BE_POSIX /* POSIX version: getopt(3) is used (instead of getopt_long(3)) and only * short options are provided. */ void parse_cmdline_args(const int argc, char **argv) { opterr = optind = 0; int optc; #ifndef _NO_LIRA int open_prev_mode = 0; char *open_prev_file = (char *)NULL; #endif /* !_NO_LIRA */ while ((optc = getopt(argc, argv, OPTSTRING)) != EOF) { switch (optc) { case 'a': set_show_hidden(optarg); break; case 'A': xargs.show_hidden = conf.show_hidden = 0; break; case 'b': xargs.bm_file = 1; set_alt_file(optarg, &alt_bm_file, "-b"); break; case 'B': set_tab_mode(optarg); break; case 'c': xargs.config = 1; set_alt_file(optarg, &alt_config_file, "-c"); break; case 'C': xargs.clear_screen = conf.clear_screen = 0; break; case 'd': xargs.disk_usage = conf.disk_usage = 1; break; case 'D': xargs.only_dirs = conf.only_dirs = 1; break; case 'e': xargs.auto_open = conf.auto_open = 0; break; case 'E': xargs.autocd = conf.autocd = 0; break; case 'f': xargs.full_dir_size = conf.full_dir_size = 1; break; case 'F': xargs.files_counter = conf.files_counter = 0; break; case 'g': xargs.si = 1; break; case 'G': xargs.apparent_size = conf.apparent_size = 0; break; case 'h': help_function(); break; /* noreturn */ case 'H': #ifndef _NO_HIGHLIGHT xargs.highlight = conf.highlight = 0; #endif /* !_NO_HIGHLIGHT */ break; case 'i': #ifndef _NO_ICONS xargs.icons = conf.icons = 1; break; #else fprintf(stderr, "%s: icons: %s\n", PROGRAM_NAME, NOT_AVAILABLE); exit(EXIT_FAILURE); #endif /* !_NO_ICONS */ case 'I': set_alt_trash_dir(optarg); break; case 'j': set_stat(optc, optarg); break; case 'J': set_stat(optc, optarg); break; case 'k': set_alt_file(optarg, &alt_kbinds_file, "-k"); break; case 'l': xargs.long_view = conf.long_view = 1; break; case 'L': xargs.follow_symlinks_long = conf.follow_symlinks_long = 1; break; case 'm': xargs.fuzzy_match = conf.fuzzy_match = 1; break; case 'M': set_no_colors(); break; case 'n': xargs.history = 0; break; case 'N': xargs.no_bold = 1; break; case 'o': set_opener(optarg, "-o"); break; case 'O': #ifdef _NO_LIRA fprintf(stderr, "%s: open: %s\n", PROGRAM_NAME, NOT_AVAILABLE); exit(EXIT_FAILURE); #else open_prev_file = optarg; open_prev_mode = OPEN_FILE; break; #endif /* _NO_LIRA */ case 'p': set_alt_profile(optarg); break; case 'P': #ifdef _NO_LIRA fprintf(stderr, "%s: preview: %s\n", PROGRAM_NAME, NOT_AVAILABLE); exit(EXIT_FAILURE); #else open_prev_file = optarg; open_prev_mode = PREVIEW_FILE; break; #endif /* _NO_LIRA */ case 'q': xargs.list_and_quit = 1; break; case 'Q': xargs.cd_on_quit = conf.cd_on_quit = 1; break; case 'r': set_trash_as_rm(); break; case 'R': xargs.classify = conf.classify = 0; break; case 's': xargs.stealth_mode = 1; break; case 'S': set_no_suggestions(); break; case 't': set_color_scheme(optarg, "-t"); break; case 'T': xargs.trunc_names = conf.trunc_names = 0; break; case 'u': xargs.disk_usage_analyzer = 1; break; case 'U': xargs.unicode = 0; break; case 'v': version_function(0); break; /* noreturn */ case 'V': set_virtual_dir(optarg, "-V"); break; case 'w': set_workspace(optarg); break; case 'W': xargs.print_selfiles = conf.print_selfiles = 1; break; case 'x': xargs.secure_env = 1; xsecure_env(SECURE_ENV_IMPORT); break; case 'X': xargs.secure_env_full = 1; xsecure_env(SECURE_ENV_FULL); break; case 'y': conf.light_mode = xargs.light_mode = 1; break; case 'Y': xargs.secure_cmds = xargs.secure_env = 1; xsecure_env(SECURE_ENV_IMPORT); break; case 'z': set_sort(optarg); break; case 'Z': set_max_value(optarg, &xargs.max_files, &conf.max_files); break; /* Handle error */ case ':': fprintf(stderr, _("%s: Option '-%c' requires an argument.\n" "Try '%s -h' for more information.\n"), PROGRAM_NAME, optopt, PROGRAM_NAME); exit(EXIT_FAILURE); case '?': fprintf(stderr, _("%s: Unrecognized option: '-%c'\n" "Try '%s -h' for more information.\n"), PROGRAM_NAME, optopt, PROGRAM_NAME); exit(EXIT_FAILURE); default: break; } } #ifndef _NO_LIRA if (open_prev_mode != 0) open_preview_file(open_prev_file, open_prev_mode); /* noreturn */ #endif /* !_NO_LIRA */ if (argv[optind]) { /* Starting paths passed as positional parameters. */ resolve_and_set_starting_paths(argv + optind); } else { if (xargs.list_and_quit == 1) { conf.restore_last_path = 0; set_start_path(); } } } #else /* Non-POSIX version: getopt_long(3) is used and long options are * supported. */ void parse_cmdline_args(const int argc, char **argv) { /* Disable automatic error messages to be able to handle them ourselves * via the '?' and ':' cases in the switch statement. */ opterr = optind = 0; int optc; #ifndef _NO_LIRA int open_prev_mode = 0; char *open_prev_file = (char *)NULL; #endif /* _NO_LIRA */ while ((optc = getopt_long(argc, argv, OPTSTRING, longopts, NULL)) != EOF) { switch (optc) { /* Short options */ case 'a': set_show_hidden(optarg); break; case 'A': xargs.show_hidden = conf.show_hidden = 0; break; case 'b': xargs.bm_file = 1; set_alt_file(optarg, &alt_bm_file, "-b"); break; case 'c': xargs.config = 1; set_alt_file(optarg, &alt_config_file, "-c"); break; #ifdef RUN_CMD case 'C': if (!optarg || !*optarg || *optarg == '-') err_arg_required("--cmd"); /* noreturn */ cmd_line_cmd = savestring(optarg, strlen(optarg)); break; #endif /* RUN_CMD */ case 'D': set_alt_config_dir(optarg); break; case 'e': xargs.no_eln = conf.no_eln = 1; break; case 'E': xargs.eln_use_workspace_color = 1; break; case 'f': xargs.list_dirs_first = conf.list_dirs_first = 1; break; case 'F': xargs.list_dirs_first = conf.list_dirs_first = 0; break; case 'g': xargs.pager = conf.pager = 1; break; case 'G': xargs.pager = conf.pager = 0; break; case 'h': help_function(); break; /* noreturn */ case 'H': xargs.horizontal_list = 1; conf.listing_mode = HORLIST; break; case 'i': xargs.case_sens_list = conf.case_sens_list = 0; break; case 'I': xargs.case_sens_list = conf.case_sens_list = 1; break; case 'k': set_alt_file(optarg, &alt_kbinds_file, "-k"); break; case 'l': xargs.long_view = conf.long_view = 1; break; case 'L': xargs.follow_symlinks_long = conf.follow_symlinks_long = 1; break; case 'm': xargs.dirhist_map = conf.dirhist_map = 1; break; case 'o': xargs.autols = conf.autols = 1; break; case 'O': xargs.autols = conf.autols = 0; break; case 'P': set_alt_profile(optarg); break; case 'r': xargs.refresh_on_empty_line = 0; break; case 's': xargs.splash_screen = conf.splash_screen = 1; break; case 'S': xargs.stealth_mode = 1; break; case 't': xargs.disk_usage_analyzer = 1; break; case 'T': set_alt_trash_dir(optarg); break; case 'v': version_function(0); break; /* noreturn */ case 'w': set_workspace(optarg); break; case 'x': xargs.ext_cmd_ok = conf.ext_cmd_ok = 0; break; case 'y': xargs.light_mode = conf.light_mode = 1; break; case 'z': set_sort(optarg); break; /* Only-long options */ case LOPT_BELL: set_bell_style(optarg); break; case LOPT_CASE_SENS_DIRJUMP: xargs.case_sens_dirjump = conf.case_sens_dirjump = 1; break; case LOPT_CASE_SENS_PATH_COMP: xargs.case_sens_path_comp = conf.case_sens_path_comp = 1; break; case LOPT_CD_ON_QUIT: xargs.cd_on_quit = conf.cd_on_quit = 1; break; case LOPT_COLOR_SCHEME: set_color_scheme(optarg, "--color-scheme"); break; case LOPT_COLOR_LNK_AS_TARGET: xargs.color_lnk_as_target = conf.color_lnk_as_target = 1; break; case LOPT_CWD_IN_TITLE: xargs.cwd_in_title = 1; break; case LOPT_DATA_DIR: set_datadir(optarg); break; case LOPT_DESKTOP_NOTIFICATIONS: set_desktop_notifications(optarg); break; case LOPT_DISK_USAGE: xargs.disk_usage = conf.disk_usage = 1; break; case LOPT_FNFTAB: set_fnftab(1); break; case LOPT_FULL_DIR_SIZE: xargs.full_dir_size = conf.full_dir_size = 1; break; case LOPT_FUZZY_ALGO: set_fuzzy_algo(optarg); break; case LOPT_FUZZY_MATCHING: xargs.fuzzy_match = conf.fuzzy_match = 1; break; case LOPT_FZFPREVIEW: /* fallthrough */ case LOPT_FZFPREVIEW_HIDDEN: set_fzfpreview(optc); break; case LOPT_FZFTAB: set_fzftab(1); break; #ifndef _NO_ICONS case LOPT_ICONS: xargs.icons = conf.icons = 1; break; case LOPT_ICONS_USE_FILE_COLOR: xargs.icons = conf.icons = xargs.icons_use_file_color = 1; break; #else case LOPT_ICONS: /* fallthrough */ case LOPT_ICONS_USE_FILE_COLOR: fprintf(stderr, "%s: icons: %s\n", PROGRAM_NAME, _(NOT_AVAILABLE)); exit(EXIT_FAILURE); break; #endif /* !_NO_ICONS */ case LOPT_INT_VARS: xargs.int_vars = conf.int_vars = 1; break; case LOPT_KITTY_KEYS: xargs.kitty_keys = 1; break; case LOPT_LIST_AND_QUIT: xargs.list_and_quit = 1; xargs.no_dirjump = 1; xargs.restore_last_path = conf.restore_last_path = 0; break; case LOPT_LSCOLORS: xargs.lscolors = 1; break; case LOPT_MAX_DIRHIST: set_max_value(optarg, &xargs.max_dirhist, &conf.max_dirhist); break; case LOPT_MAX_FILES: set_max_value(optarg, &xargs.max_files, &conf.max_files); break; case LOPT_MAX_PATH: set_max_value(optarg, &xargs.prompt_p_max_path, &conf.prompt_p_max_path); break; case LOPT_ALT_MIMEFILE: set_alt_file(optarg, &alt_mimelist_file, "--mimelist-file"); break; case LOPT_MNT_UDISKS2: xargs.mount_cmd = MNT_UDISKS2; break; case LOPT_NO_APPARENT_SIZE: xargs.apparent_size = conf.apparent_size = 0; break; case LOPT_NO_BOLD: xargs.no_bold = 1; break; case LOPT_NO_CD_AUTO: xargs.autocd = conf.autocd = 0; break; case LOPT_NO_CLASSIFY: xargs.classify = conf.classify = 0; break; case LOPT_NO_CLEAR_SCREEN: xargs.clear_screen = conf.clear_screen = 0; break; case LOPT_NO_COLORS: set_no_colors(); break; case LOPT_NO_COLUMNS: xargs.columned = conf.columned = 0; break; case LOPT_NO_DIR_JUMPER: xargs.no_dirjump = 1; break; case LOPT_NO_FILE_CAP: xargs.check_cap = conf.check_cap = 0; break; case LOPT_NO_FILE_EXT: xargs.check_ext = conf.check_ext = 0; break; case LOPT_NO_FILES_COUNTER: xargs.files_counter = conf.files_counter = 0; break; case LOPT_NO_FOLLOW_SYMLINKS: xargs.follow_symlinks = conf.follow_symlinks = 0; break; case LOPT_NO_FZFPREVIEW: xargs.fzf_preview = conf.fzf_preview = 0; break; case LOPT_NO_HIGHLIGHT: #ifndef _NO_HIGHLIGHT xargs.highlight = conf.highlight = 0; #endif /* !_NO_HIGHLIGHT */ break; case LOPT_NO_HISTORY: xargs.history = 0; break; case LOPT_NO_OPEN_AUTO: xargs.auto_open = conf.auto_open = 0; break; case LOPT_NO_REFRESH_ON_RESIZE: xargs.refresh_on_resize = 0; break; case LOPT_REPORT_CWD: xargs.report_cwd = 1; break; case LOPT_NO_RESTORE_LAST_PATH: xargs.restore_last_path = conf.restore_last_path = 0; break; case LOPT_NO_SUGGESTIONS: set_no_suggestions(); break; case LOPT_NO_TIPS: xargs.tips = conf.tips = 0; break; case LOPT_NO_TRUNC_NAMES: xargs.trunc_names = conf.trunc_names = 0; break; case LOPT_NO_UNICODE: xargs.unicode = 0; break; case LOPT_NO_WARNING_PROMPT: xargs.warning_prompt = conf.warning_prompt = 0; break; case LOPT_NO_WELCOME_MESSAGE: xargs.welcome_message = conf.welcome_message = 0; break; case LOPT_ONLY_DIRS: xargs.only_dirs = conf.only_dirs = 1; break; case LOPT_OPEN: /* --open or --preview */ #ifdef _NO_LIRA fprintf(stderr, "%s: --open/--preview: %s\n", PROGRAM_NAME, _(NOT_AVAILABLE)); exit(EXIT_FAILURE); #else { open_prev_file = optarg; int n = *argv[optind - 1] == '-' ? 1 : 2; if (*(argv[optind - n] + 2) == 'p') open_prev_mode = PREVIEW_FILE; /* --preview */ else open_prev_mode = OPEN_FILE; /* --open */ } break; #endif /* _NO_LIRA */ case LOPT_OPENER: set_opener(optarg, "--opener"); break; case LOPT_PAGER_VIEW: xset_pager_view(optarg); break; case LOPT_PRINT_SEL: xargs.print_selfiles = conf.print_selfiles = 1; break; case LOPT_PROP_FIELDS: xset_prop_fields(optarg); break; case LOPT_READONLY: xargs.readonly = conf.readonly = 1; break; case LOPT_RL_VI_MODE: xargs.rl_vi_mode = 1; break; case LOPT_SECURE_CMDS: xargs.secure_cmds = xargs.secure_env = 1; xsecure_env(SECURE_ENV_IMPORT); break; case LOPT_SECURE_ENV: xargs.secure_env = 1; xsecure_env(SECURE_ENV_IMPORT); break; case LOPT_SECURE_ENV_FULL: xargs.secure_env_full = 1; xsecure_env(SECURE_ENV_FULL); break; case LOPT_SEL_FILE: set_alt_selfile(optarg); break; case LOPT_SHARE_SELBOX: xargs.share_selbox = conf.share_selbox = 1; break; case LOPT_SHOTGUN_FILE: #ifdef _NO_LIRA fprintf(stderr, "%s: --shotgun-file: %s\n", PROGRAM_NAME, NOT_AVAILABLE); exit(EXIT_FAILURE); #else set_alt_file(optarg, &alt_preview_file, "--shotgun-file"); flags |= ALT_PREVIEW_FILE; break; #endif /* !_NO_LIRA */ case LOPT_SI: xargs.si = 1; break; case LOPT_SMENUTAB: set_smenutab(1); break; case LOPT_SORT_REVERSE: xargs.sort_reverse = conf.sort_reverse = 1; break; case LOPT_STAT: /* fallthrough */ case LOPT_STAT_FULL: set_stat(optc, optarg); break; case LOPT_STDTAB: set_stdtab(1); break; case LOPT_PTIME_STYLE: xset_time_style(optarg, 1); break; case LOPT_TABMODE: set_tabmode(optarg); break; case LOPT_TIME_STYLE: xset_time_style(optarg, 0); break; case LOPT_TRASH_AS_RM: set_trash_as_rm(); break; case LOPT_UNICODE: xargs.unicode = 1; break; case LOPT_VIRTUAL_DIR: set_virtual_dir(optarg, "--virtual-dir"); break; case LOPT_VIRTUAL_DIR_FULL_PATHS: xargs.virtual_dir_full_paths = 1; break; case LOPT_VT100: set_vt100(); break; /* Handle error */ case ':': err_arg_required(argv[optind - 1]); /* noreturn */ case '?': /* optopt is negative whenever a short option is used with a * Unicode character (e.g., "-µ"). In this case, the problematic * option is not argv[optind - 1], but argv[optind]. */ optind -= ((optopt < 0 && argv[optind]) ? 0 : 1); err_invalid_opt(argv[optind]); /* noreturn */ default: break; } } #ifndef _NO_LIRA if (open_prev_mode != 0) open_preview_file(open_prev_file, open_prev_mode); /* noreturn */ #endif /* !_NO_LIRA */ int start_path_set = 0; if (xargs.stat == 0 && argv[optind]) /* Starting paths passed as positional parameters. */ start_path_set = resolve_and_set_starting_paths(argv + optind); if (start_path_set == 0 && xargs.list_and_quit == 1) { /* Starting path not specified in the command line. Let's use * the current directory. */ conf.restore_last_path = 0; set_start_path(); } } #endif /* _BE_POSIX */ clifm-1.26.3/src/args.h000066400000000000000000000020631506632037700146030ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* args.h */ #ifndef ARGS_H #define ARGS_H __BEGIN_DECLS void parse_cmdline_args(const int argc, char **argv); void get_data_dir(void); int set_start_path(void); __END_DECLS #endif /* ARGS_H */ clifm-1.26.3/src/autocmds.c000066400000000000000000000616441506632037700154730ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* autocmds.c -- run cmds on a per-directory basis */ #include "helpers.h" #include /* fnmatch */ #include #include #include "aux.h" #include "checks.h" /* is_number */ #include "colors.h" /* set_colors */ #include "listing.h" /* reload_dirlist */ #include "messages.h" /* AUTO_USAGE macro */ #include "misc.h" /* xerror (err) */ #include "sanitize.h" /* sanitize_cmd */ #include "sort.h" /* num_to_sort_name */ #include "spawn.h" /* launch_execl */ /* Some options (mf and mn) take UNSET (-1) as a valid value. Let's use * this macro to mark them as unset (no value). */ #define AC_UNSET (-2) /* Size of the buffer used to store the list of autocommand options */ #define AC_BUF_SIZE PATH_MAX /* The opts struct contains option values previous to any autocommand call */ void reset_opts(void) { opts.color_scheme = cur_cscheme; opts.files_counter = conf.files_counter; opts.light_mode = conf.light_mode; opts.max_files = conf.max_files; opts.full_dir_size = conf.full_dir_size; opts.long_view = conf.long_view; opts.show_hidden = conf.show_hidden; opts.max_name_len = conf.max_name_len; opts.only_dirs = conf.only_dirs; opts.pager = conf.pager; opts.sort = conf.sort; opts.sort_reverse = conf.sort_reverse; opts.filter = (struct filter_t){0}; } void update_autocmd_opts(const int opt) { switch (opt) { case AC_COLOR_SCHEME: opts.color_scheme = cur_cscheme; break; case AC_FILES_COUNTER: opts.files_counter = conf.files_counter; break; case AC_FULL_DIR_SIZE: opts.full_dir_size = conf.full_dir_size; break; case AC_LIGHT_MODE: opts.light_mode = conf.light_mode; break; case AC_LONG_VIEW: opts.long_view = conf.long_view; break; case AC_SHOW_HIDDEN: opts.show_hidden = conf.show_hidden; break; case AC_MAX_FILES: opts.max_files = conf.max_files; break; case AC_MAX_NAME_LEN: opts.max_name_len = conf.max_name_len; break; case AC_ONLY_DIRS: opts.only_dirs = conf.only_dirs; break; case AC_SORT: opts.sort = conf.sort; opts.sort_reverse = conf.sort_reverse; break; case AC_PAGER: opts.pager = conf.pager; break; case AC_FILTER: free(opts.filter.str); if (!filter.str) { opts.filter = (struct filter_t){0}; } else { opts.filter.str = savestring(filter.str, strlen(filter.str)); opts.filter.type = filter.type; opts.filter.rev = filter.rev; opts.filter.env = filter.env; } break; default: break; } } static int set_autocmd_regex_filter(const char *pattern) { regfree(®ex_exp); const int ret = regcomp(®ex_exp, pattern, REG_NOSUB | REG_EXTENDED); if (ret != FUNC_SUCCESS) { regfree(®ex_exp); return FUNC_FAILURE; } return FUNC_SUCCESS; } static void copy_current_files_filter(void) { free(opts.filter.str); opts.filter.str = (char *)NULL; if (!filter.str) return; opts.filter.str = savestring(filter.str, strlen(filter.str)); opts.filter.rev = filter.rev; opts.filter.type = filter.type; opts.filter.env = filter.env; } static void install_autocmd_files_filter(const size_t i) { free(filter.str); if (strcmp(autocmds[i].filter.str, "unset") == 0) { filter.str = (char *)NULL; if (filter.type == FILTER_FILE_NAME) regfree(®ex_exp); } else { filter.str = savestring(autocmds[i].filter.str, strlen(autocmds[i].filter.str)); filter.type = autocmds[i].filter.type; filter.rev = autocmds[i].filter.rev; filter.env = autocmds[i].filter.env; if (filter.type == FILTER_FILE_NAME) set_autocmd_regex_filter(filter.str); } } static void save_current_options(void) { opts.light_mode = conf.light_mode; opts.files_counter = conf.files_counter; opts.full_dir_size = conf.full_dir_size; opts.long_view = conf.long_view; opts.max_files = conf.max_files; opts.show_hidden = conf.show_hidden; opts.sort = conf.sort; opts.sort_reverse = conf.sort_reverse; opts.max_name_len = conf.max_name_len; opts.pager = conf.pager; opts.only_dirs = conf.only_dirs; opts.color_scheme = cur_cscheme; copy_current_files_filter(); } static void set_autocmd_options(const size_t i) { if (autocmds[i].light_mode != UNSET) conf.light_mode = autocmds[i].light_mode; if (autocmds[i].files_counter != UNSET) conf.files_counter = autocmds[i].files_counter; if (autocmds[i].full_dir_size != UNSET) conf.full_dir_size = autocmds[i].full_dir_size; if (autocmds[i].long_view != UNSET) conf.long_view = autocmds[i].long_view; if (autocmds[i].show_hidden != UNSET) conf.show_hidden = autocmds[i].show_hidden; if (autocmds[i].only_dirs != UNSET) conf.only_dirs = autocmds[i].only_dirs; if (autocmds[i].pager != UNSET) conf.pager = autocmds[i].pager; if (autocmds[i].sort != UNSET) conf.sort = autocmds[i].sort; if (autocmds[i].sort_reverse != UNSET) conf.sort_reverse = autocmds[i].sort_reverse; if (autocmds[i].max_name_len != AC_UNSET) conf.max_name_len = autocmds[i].max_name_len; if (autocmds[i].max_files != AC_UNSET) conf.max_files = autocmds[i].max_files; if (autocmds[i].cmd) { if (xargs.secure_cmds == 0 || sanitize_cmd(autocmds[i].cmd, SNT_AUTOCMD) == FUNC_SUCCESS) launch_execl(autocmds[i].cmd); } /* Color scheme and files filter will be set later, to avoid * setting them twice if there are multiple autocommands matching * the current directory. */ } static struct autocmds_t gen_common_options(void) { struct autocmds_t a; struct autocmds_t *b = autocmds; size_t i; a.cmd = (char *)NULL; a.color_scheme = (char *)NULL; a.files_counter = UNSET; a.full_dir_size = UNSET; a.light_mode = UNSET; a.long_view = UNSET; a.max_files = AC_UNSET; a.max_name_len = AC_UNSET; a.only_dirs = UNSET; a.pager = UNSET; a.show_hidden = UNSET; a.sort = UNSET; a.sort_reverse = UNSET; a.filter = (struct filter_t){0}; a.temp = 0; for (i = 0; i < autocmds_n; i++) { if (b[i].match == 0) continue; if (b[i].color_scheme) a.color_scheme = b[i].color_scheme; if (b[i].filter.str) { a.filter.str = b[i].filter.str; a.filter.rev = b[i].filter.rev; a.filter.type = b[i].filter.type; } if (b[i].files_counter != UNSET) a.files_counter = b[i].files_counter; if (b[i].full_dir_size != UNSET) a.full_dir_size = b[i].full_dir_size; if (b[i].light_mode != UNSET) a.light_mode = b[i].light_mode; if (b[i].long_view != UNSET) a.long_view = b[i].long_view; if (b[i].max_files != AC_UNSET) a.max_files = b[i].max_files; if (b[i].max_name_len != AC_UNSET) a.max_name_len = b[i].max_name_len; if (b[i].only_dirs != UNSET) a.only_dirs = b[i].only_dirs; if (b[i].pager != UNSET) a.pager = b[i].pager; if (b[i].show_hidden != UNSET) a.show_hidden = autocmds[i].show_hidden; if (b[i].sort != UNSET) a.sort = b[i].sort; if (b[i].sort_reverse != UNSET) a.sort_reverse = b[i].sort_reverse; } return a; } static int gen_opt_entry(char *buf, const char *name, const char *val, size_t *pos, const int long_msg) { const int ret = snprintf(buf, AC_BUF_SIZE, "%s%s%s%s", *pos > 0 ? ", " : "", name, (long_msg == 1 && val) ? "=" : "", (long_msg == 1 && val) ? val : ""); (*pos)++; return (ret > 0 ? ret : 0); } /* Write into BUF the list of autocmd options set in the struct A. */ static int gen_autocmd_options_list(char *buf, struct autocmds_t *a, const int print_filter) { int len = 0; /* Number of bytes currently consumed by buf. */ size_t c = 0; /* Number of procesed options for the current autocommand. */ /* PRINT_FILTER is 1 if coming from the 'auto list' command. */ /* Should we print the message in long mode? */ const int lm = (conf.autocmd_msg != AUTOCMD_MSG_SHORT || print_filter == 1); if (a->color_scheme != NULL) len += gen_opt_entry(buf + len, "cs", a->color_scheme, &c, lm); if (a->files_counter != UNSET) len += gen_opt_entry(buf + len, "fc", xitoa(a->files_counter), &c, lm); if (a->filter.str != NULL) len += gen_opt_entry(buf + len, "ft", print_filter == 1 ? a->filter.str : NULL, &c, lm); if (a->full_dir_size != UNSET) len += gen_opt_entry(buf + len, "fz", xitoa(a->full_dir_size), &c, lm); if (a->show_hidden != UNSET) len += gen_opt_entry(buf + len, "hf", xitoa(a->show_hidden), &c, lm); if (a->light_mode != UNSET) len += gen_opt_entry(buf + len, "lm", xitoa(a->light_mode), &c, lm); if (a->long_view != UNSET) len += gen_opt_entry(buf + len, "lv", xitoa(a->long_view), &c, lm); if (a->max_files != AC_UNSET) len += gen_opt_entry(buf + len, "mf", a->max_files == UNSET ? "unset" : xitoa(a->max_files), &c, lm); if (a->max_name_len != AC_UNSET) len += gen_opt_entry(buf + len, "mn", a->max_name_len == UNSET ? "unset" : xitoa(a->max_name_len), &c, lm); if (a->only_dirs != UNSET) len += gen_opt_entry(buf + len, "od", xitoa(a->only_dirs), &c, lm); if (a->pager != UNSET) len += gen_opt_entry(buf + len, "pg", xitoa(a->pager), &c, lm); if (a->sort != UNSET) len += gen_opt_entry(buf + len, "st", num_to_sort_name(a->sort, 0), &c, lm); if (a->sort_reverse != UNSET) len += gen_opt_entry(buf + len, "sr", xitoa(a->sort_reverse), &c, lm); return len; } static void print_autocmd_options_list_full(void) { size_t i; for (i = 0; i < autocmds_n; i++) { if (autocmds[i].match == 0) continue; char buf[AC_BUF_SIZE]; const int len = gen_autocmd_options_list(buf, &autocmds[i], 0); if (len <= 0) continue; print_reload_msg(NULL, NULL, "Autocmd ["); fputs(buf, stdout); printf("]%s\n", autocmds[i].temp == 1 ? "T" : ""); } } void print_autocmd_msg(void) { if (conf.autocmd_msg == AUTOCMD_MSG_MINI) { print_reload_msg(NULL, NULL, "Autocmd\n"); return; } if (conf.autocmd_msg == AUTOCMD_MSG_FULL) { print_autocmd_options_list_full(); return; } char buf[AC_BUF_SIZE]; struct autocmds_t a = gen_common_options(); const int len = gen_autocmd_options_list(buf, &a, 0); if (len <= 0) /* No autocommand option set. Do not print any message */ return; print_reload_msg(NULL, NULL, "Autocmd ["); fputs(buf, stdout); fputs("]\n", stdout); } static int run_autocmds(const size_t *matches, const size_t matches_n) { save_current_options(); autocmd_set = 1; int cs_last_index = UNSET; int ft_last_index = UNSET; size_t i; for (i = 0; i < matches_n; i++) { autocmds[matches[i]].match = 1; if (autocmds[matches[i]].color_scheme != NULL) cs_last_index = (int)matches[i]; if (autocmds[matches[i]].filter.str != NULL) ft_last_index = (int)matches[i]; set_autocmd_options(matches[i]); } if (cs_last_index != UNSET) set_colors(autocmds[cs_last_index].color_scheme, 0); if (ft_last_index != UNSET) install_autocmd_files_filter((size_t)ft_last_index); return 1; } static void unset_autocmd_matches(void) { size_t i; for (i = 0; i < autocmds_n; i++) autocmds[i].match = 0; } /* Check the current directory for matching autocommands and set options * accordingly. * Returns 1 if at least one matching autocommand is found, or 0 otherwise. */ int check_autocmds(void) { if (!autocmds || autocmds_n == 0) return 0; unset_autocmd_matches(); size_t matches[256]; /* Store indices of matching entries */ size_t matches_n = 0; size_t i; for (i = 0; i < autocmds_n && matches_n < sizeof(matches); i++) { if (!autocmds[i].pattern || !*autocmds[i].pattern) continue; const char *p = autocmds[i].pattern; const int rev = autocmds[i].pattern_rev; int found = 0; /* 1. Temporary autocommands (set via the 'auto' command). */ if (autocmds[i].temp == 1) { found = (strcmp(p, workspaces[cur_ws].path) == 0); goto CHECK_MATCH; } /* 2. Workspaces (@wsN). */ if (*p == '@' && p[1] == 'w' && p[2] == 's' && p[3]) { found = (p[3] - '0' == cur_ws + 1); goto CHECK_MATCH; } /* 3. Double asterisk: match everything starting with PATTERN * (less double asterisk itself and ending slash). */ const size_t plen = strlen(p); if (plen >= 3 && p[plen - 1] == '*' && p[plen - 2] == '*') { size_t n = 2; if (p[plen - 3] == '/') n++; if (plen - n == 0 || strncmp(p, workspaces[cur_ws].path, plen - n) == 0) found = 1; goto CHECK_MATCH; } /* 4. Glob expression or plain text for PATTERN */ found = (fnmatch(p, workspaces[cur_ws].path, 0) == 0); CHECK_MATCH: if ((rev == 0 && found == 0) || (rev == 1 && found == 1)) continue; matches[matches_n] = i; matches_n++; } return (matches_n > 0 ? run_autocmds(matches, matches_n) : 0); } static int set_autocmd_filter_type(const char c) { if (c == '=') return FILTER_FILE_TYPE; if (c == '@') return FILTER_MIME_TYPE; /* UNIMPLEMENTED */ return FILTER_FILE_NAME; } static void revert_files_filter(void) { filter.type = opts.filter.type; filter.rev = opts.filter.rev; filter.env = opts.filter.env; free(filter.str); filter.str = savestring(opts.filter.str, strlen(opts.filter.str)); free(opts.filter.str); opts.filter.str = (char *)NULL; if (filter.type == FILTER_FILE_NAME) set_autocmd_regex_filter(filter.str); } static void remove_files_filter(void) { free(filter.str); filter = (struct filter_t){0}; if (filter.type == FILTER_FILE_NAME) regfree(®ex_exp); } static int set_autocmd_files_filter(const char *pattern, const size_t n) { if (*pattern == 'u' && strcmp(pattern, "unset") == 0) { free(autocmds[n].filter.str); autocmds[n].filter = (struct filter_t){0}; return FUNC_SUCCESS; } autocmds[n].filter.rev = (*pattern == '!'); const char *p = pattern + (*pattern == '!'); free(autocmds[n].filter.str); autocmds[n].filter.str = savestring(p, strlen(p)); autocmds[n].filter.type = set_autocmd_filter_type(*p); autocmds[n].filter.env = 0; return FUNC_SUCCESS; } /* Revert back to options previous to autocommand */ void revert_autocmd_opts(void) { conf.light_mode = opts.light_mode; conf.files_counter = opts.files_counter; conf.full_dir_size = opts.full_dir_size; conf.long_view = opts.long_view; conf.max_files = opts.max_files; conf.show_hidden = opts.show_hidden; conf.max_name_len = opts.max_name_len; conf.pager = opts.pager; conf.sort = opts.sort; conf.only_dirs = opts.only_dirs; conf.sort_reverse = opts.sort_reverse; if (opts.color_scheme && opts.color_scheme != cur_cscheme) set_colors(opts.color_scheme, 0); if (opts.filter.str) { revert_files_filter(); } else { if (filter.str) /* This is an autocmd filter. Remove it. */ remove_files_filter(); } autocmd_set = 0; } static int set_autocmd_color_scheme(const char *name, const size_t n) { if (!name || !*name || cschemes_n == 0) return FUNC_FAILURE; if (*name == 'u' && strcmp(name, "unset") == 0) { autocmds[n].color_scheme = (char *)NULL; return FUNC_SUCCESS; } int i = (int)cschemes_n; while (--i >= 0) { if (*color_schemes[i] == *name && strcmp(color_schemes[i], name) == 0) { autocmds[n].color_scheme = color_schemes[i]; return FUNC_SUCCESS; } } err(ERR_NO_LOG, PRINT_PROMPT, _("autocmd: '%s': Invalid value for 'cs'\n"), name); autocmds[n].color_scheme = (char *)NULL; return FUNC_FAILURE; } static int set_autocmd_sort_by_name(const char *name, const size_t n) { if (*name == 'u' && strcmp(name, "unset") == 0) { autocmds[n].sort = UNSET; return FUNC_SUCCESS; } size_t i; for (i = 0; i <= SORT_TYPES; i++) { if (*name != *sort_methods[i].name || strcmp(name, sort_methods[i].name) != 0) continue; autocmds[n].sort = (conf.light_mode == 1 && !ST_IN_LIGHT_MODE(sort_methods[i].num)) ? conf.sort : sort_methods[i].num; return FUNC_SUCCESS; } return FUNC_FAILURE; } static int set_autocmd_sort(const char *val, const size_t n) { if (!val || !*val) return FUNC_FAILURE; if (!is_number(val)) { if (set_autocmd_sort_by_name(val, n) == FUNC_SUCCESS) return FUNC_SUCCESS; goto ERROR; } const int a = atoi(val); if (a >= 0 && a <= SORT_TYPES) { autocmds[n].sort = a; return FUNC_SUCCESS; } ERROR: err(ERR_NO_LOG, PRINT_PROMPT, _("autocmd: '%s': Invalid value for 'st'\n"), val); return FUNC_FAILURE; } /* Store each autocommand option in OPT in the corresponding field of * the autocommand at index N. */ static int fill_autocmd_opt(char *opt, const size_t n) { if (!opt || !*opt) return FUNC_FAILURE; if (*opt == '!' && *(++opt)) { free(autocmds[n].cmd); autocmds[n].cmd = savestring(opt, strlen(opt)); return FUNC_SUCCESS; } char *p = strchr(opt, '='); if (!p) { err(ERR_NO_LOG, PRINT_PROMPT, _("autocmd: '%s': Invalid option format " " (it must be 'OPTION=VALUE')\n"), opt); return FUNC_FAILURE; } *p = '\0'; p++; /* All option names take exactly two characters. */ if (!*opt || !opt[1] || opt[2]) goto ERR_NAME; /* 'cs', 'ft', and 'st' take strings as values. */ if (*opt == 'c' && opt[1] == 's') return set_autocmd_color_scheme(*p ? p : "unset", n); if (*opt == 'f' && opt[1] == 't') return set_autocmd_files_filter(*p ? p : "unset", n); if (*opt == 's' && opt[1] == 't') return set_autocmd_sort(*p ? p : "unset", n); /* The below options taken only numbers (or 'unset') as values. */ int a = 0; if (!*p) { /* 'OPTION=' amounts to 'OPTION=unset'. */ a = UNSET; } else if (!is_number(p)) { if (*p != 'u' || strcmp(p, "unset") != 0) goto ERR_VAL; a = UNSET; } else { a = atoi(p); } if (*opt == 'm' && opt[1] == 'f') { autocmds[n].max_files = !*p ? AC_UNSET : a; return FUNC_SUCCESS; } if (*opt == 'm' && opt[1] == 'n') { autocmds[n].max_name_len = !*p ? AC_UNSET : a; return FUNC_SUCCESS; } if (a != UNSET && a != 1 && a != 0) goto ERR_VAL; if (*opt == 'f' && opt[1] == 'c') autocmds[n].files_counter = a; else if (*opt == 'f' && opt[1] == 'z') autocmds[n].full_dir_size = a; else if (*opt == 'h' && (opt[1] == 'f' || opt[1] == 'h')) autocmds[n].show_hidden = a; else if (*opt == 'l' && opt[1] == 'm') autocmds[n].light_mode = a; else if (*opt == 'l' && (opt[1] == 'v' || opt[1] == 'l')) autocmds[n].long_view = a; else if (*opt == 'o' && opt[1] == 'd') autocmds[n].only_dirs = a; else if (*opt == 'p' && opt[1] == 'g') autocmds[n].pager = a; else if (*opt == 's' && opt[1] == 'r') autocmds[n].sort_reverse = a; else goto ERR_NAME; return FUNC_SUCCESS; ERR_NAME: err(ERR_NO_LOG, PRINT_PROMPT, _("autocmd: '%s': Invalid option name\n"), opt); return FUNC_FAILURE; ERR_VAL: err(ERR_NO_LOG, PRINT_PROMPT, _("autocmd: '%s': Invalid value for '%s'\n"), p, opt); return FUNC_FAILURE; } static void init_autocmd_opts(const size_t n) { autocmds[n].cmd = (char *)NULL; autocmds[n].color_scheme = (char *)NULL; autocmds[n].files_counter = UNSET; autocmds[n].full_dir_size = UNSET; autocmds[n].light_mode = UNSET; autocmds[n].long_view = UNSET; autocmds[n].max_files = AC_UNSET; autocmds[n].max_name_len = AC_UNSET; autocmds[n].only_dirs = UNSET; autocmds[n].pager = UNSET; autocmds[n].show_hidden = UNSET; autocmds[n].sort = UNSET; autocmds[n].sort_reverse = UNSET; autocmds[n].filter = (struct filter_t){0}; autocmds[n].temp = 0; autocmds[n].match = 0; autocmds[n].pattern_rev = 0; } /* Modify the options of the autocommand whose index number is N * according to the list of parameters found in ARG. */ static int modify_autocmd(char *arg, const size_t n) { char *p = arg; int exit_status = FUNC_FAILURE; while (1) { char *val = (char *)NULL; if (*arg == ',') { *arg = '\0'; arg++; val = p; p = arg; } else if (!*arg) { val = p; } else { arg++; continue; } if (fill_autocmd_opt(val, n) == FUNC_SUCCESS) exit_status = FUNC_SUCCESS; if (!*arg) break; } return exit_status; } static void save_autocmd_pattern(const char *p, const size_t buf_len, const size_t n) { if (*p == '!') { p++; autocmds[n].pattern_rev = 1; } if (*p == '~' && user.home && *user.home) { if (!p[1] || (p[1] == '/' && !p[2])) { autocmds[n].pattern = savestring(user.home, user.home_len); } else if (p[1] == '/') { const size_t len = user.home_len + (strnlen(p, buf_len) - 2) + 2; autocmds[n].pattern = xnmalloc(len, sizeof(char)); snprintf(autocmds[n].pattern, len, "%s/%s", user.home, p + 2); } else { autocmds[n].pattern = savestring(p, strnlen(p, buf_len)); } } else { autocmds[n].pattern = savestring(p, strnlen(p, buf_len)); } } /* Take an autocmd line and store parameters in a struct. */ int parse_autocmd_line(char *cmd, const size_t buflen) { if (!cmd || !*cmd) return FUNC_FAILURE; const size_t clen = strnlen(cmd, buflen); if (clen > 0 && cmd[clen - 1] == '\n') cmd[clen - 1] = '\0'; char *p = strchr(cmd, ' '); if (!p || !p[1]) return FUNC_FAILURE; *p = '\0'; autocmds = xnrealloc(autocmds, autocmds_n + 1, sizeof(struct autocmds_t)); init_autocmd_opts(autocmds_n); save_autocmd_pattern(cmd, buflen, autocmds_n); p++; if (modify_autocmd(p, autocmds_n) == FUNC_FAILURE) { /* No valid option found for this autocmd: remove it. */ free(autocmds[autocmds_n].pattern); if (autocmds_n > 0) { autocmds = xnrealloc(autocmds, autocmds_n, sizeof(struct autocmds_t)); } else { free(autocmds); autocmds = (struct autocmds_t *)NULL; } return FUNC_FAILURE; } autocmds_n++; return FUNC_SUCCESS; } static int unset_tmp_autocmds(void) { size_t found = 0; size_t i; for (i = 0; i < autocmds_n; i++) { if (autocmds[i].temp == 1 && *autocmds[i].pattern == *workspaces[cur_ws].path && strcmp(autocmds[i].pattern, workspaces[cur_ws].path) == 0) { *autocmds[i].pattern = '\0'; found++; } } if (found == 0) { xerror(_("auto: No temporary autocommand defined for " "the current directory\n")); return FUNC_FAILURE; } return FUNC_SUCCESS; } static int autocmd_dirlist_reload(void) { dir_changed = 1; if (conf.autols == 1) reload_dirlist(); return FUNC_SUCCESS; } static size_t get_longest_pattern(void) { size_t i; size_t len = 0; for (i = 0; i < autocmds_n; i++) { if (!autocmds[i].pattern || !*autocmds[i].pattern) continue; const size_t l = strlen(autocmds[i].pattern) + (size_t)autocmds[i].pattern_rev; if (l > len) len = l; } return len; } static int print_autocmds_list(void) { if (autocmds_n == 0) { fputs("auto: No autocommand defined\n", stdout); return FUNC_SUCCESS; } char buf[AC_BUF_SIZE]; size_t i; const int longest_pattern = (int)get_longest_pattern(); for (i = 0; i < autocmds_n; i++) { if (!autocmds[i].pattern || !*autocmds[i].pattern || gen_autocmd_options_list(buf, &autocmds[i], 1) <= 0) continue; printf("%s%s%s%s%-*s %s%s%s %s%s\n", xs_cb, autocmds[i].match == 1 ? SET_MISC_PTR : " ", df_c, autocmds[i].pattern_rev == 1 ? "!" : "", longest_pattern, autocmds[i].pattern, mi_c, SET_MSG_PTR, df_c, buf, autocmds[i].temp == 1 ? " [temp]" : ""); } return FUNC_SUCCESS; } static int reload_dir_ignoring_autocmds(void) { if (autocmds_n == 0) { fputs("auto: No autocommand defined\n", stdout); return FUNC_SUCCESS; } revert_autocmd_opts(); unset_autocmd_matches(); dir_changed = 0; reload_dirlist(); return FUNC_SUCCESS; } /* 'auto' command: add a temporary autocommand for the current directory. */ int add_autocmd(char **args) { if (!args || !args[0] || !*args[0] || IS_HELP(args[0])) { puts(AUTO_USAGE); return FUNC_SUCCESS; } if (*args[0] == 'n' && strcmp(args[0], "none") == 0) return reload_dir_ignoring_autocmds(); if (*args[0] == 'l' && strcmp(args[0], "list") == 0) return print_autocmds_list(); if (!workspaces || !workspaces[cur_ws].path || !*workspaces[cur_ws].path) { xerror(_("auto: The current directory is undefined\n")); return FUNC_FAILURE; } if (*args[0] == 'u' && strcmp(args[0], "unset") == 0) { return (unset_tmp_autocmds() == FUNC_FAILURE ? FUNC_FAILURE : autocmd_dirlist_reload()); } size_t i; for (i = 0; i < autocmds_n; i++) { if (autocmds[i].temp == 1 && strcmp(workspaces[cur_ws].path, autocmds[i].pattern) == 0) { /* Add option to an existing autocmd */ return modify_autocmd(args[0], i) == FUNC_SUCCESS ? autocmd_dirlist_reload() : FUNC_FAILURE; } } /* No autocommand found for this target (current directory). Let's * create a new entry for this autocommand. */ const size_t cwd_len = strlen(workspaces[cur_ws].path); if (cwd_len == 0) return FUNC_FAILURE; const size_t cmd_len = strlen(args[0]); const size_t len = cwd_len + 1 + cmd_len + 1; char *str = xnmalloc(len, sizeof(char)); snprintf(str, len, "%s %s", workspaces[cur_ws].path, args[0]); const int ret = parse_autocmd_line(str, len); free(str); if (ret == FUNC_FAILURE) return FUNC_FAILURE; /* If parse_autocmd_line returns successfully, it is warranted that * autocmds_n will be greater than zero. */ /* Mark the last entry as set via the 'auto' command. */ autocmds[autocmds_n - 1].temp = 1; return autocmd_dirlist_reload(); } clifm-1.26.3/src/autocmds.h000066400000000000000000000023121506632037700154630ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* autocmds.h */ #ifndef AUTOCMDS_H #define AUTOCMDS_H __BEGIN_DECLS int add_autocmd(char **args); void update_autocmd_opts(const int opt); int check_autocmds(void); void parse_autocmd_line(char *cmd, const size_t buflen); void print_autocmd_msg(void); void reset_opts(void); void revert_autocmd_opts(void); __END_DECLS #endif /* AUTOCMDS_H */ clifm-1.26.3/src/aux.c000066400000000000000000001023601506632037700144400ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* aux.c -- functions that do not fit in any other file */ /* These four functions: from_hex, to_hex, url_encode, and * url_decode, are taken from "http://www.geekhideout.com/urlcode.shtml" * (under Public domain) and modified to comform to RFC 2395, as recommended * by the freedesktop trash specification. * All changes are licensed under GPL-2.0-or-later. */ #include "helpers.h" #if defined(__sun) && defined(ST_BTIME) # include /* getattrat, nvlist_lookup_uint64_array, nvlist_free */ #endif /* __sun && ST_BTIME */ #include #include #include #include #include #include #include "aux.h" #include "misc.h" #include "checks.h" /* is_exec_cmd() */ #include "file_operations.h" /* open_file() */ #ifndef _NO_HIGHLIGHT # include "highlight.h" #endif /* !_NO_HIGHLIGHT */ #include "spawn.h" /* launch_execv() */ /* Open the file FILE with APP (if not NULL, or with the default associated * application otherwise). Returns the exit code returned by the opening * application. */ int open_config_file(char *app, char *file) { if (!file || !*file) return FUNC_FAILURE; if (app && *app) { char *cmd[] = {app, file, NULL}; return launch_execv(cmd, FOREGROUND, E_NOFLAG); } open_in_foreground = 1; const int ret = open_file(file); open_in_foreground = 0; return ret; } /* Return the number of bytes in a UTF-8 sequence by inspecting only the * leading byte (C). * Taken from * https://stackoverflow.com/questions/22790900/get-length-of-multibyte-utf-8-sequence */ int utf8_bytes(unsigned char c) { c >>= 4; c &= 7; if (c == 4) return 2; return c - 3; } void press_any_key_to_continue(const int init_newline) { const int saved_errno = errno; HIDE_CURSOR; fprintf(stderr, _("%sPress any key to continue... "), init_newline == 1 ? "\n" : ""); fflush(stderr); xgetchar(); putchar('\n'); UNHIDE_CURSOR; errno = saved_errno; } /* Print the file named FNAME, quoted if it contains a space. * A slash is appended if FNAME is a directory (ISDIR >= 1). */ void print_file_name(char *fname, const int isdir) { char *tmp_name = (char *)NULL; if (wc_xstrlen(fname) == 0) tmp_name = replace_invalid_chars(fname); char *name = tmp_name ? tmp_name : fname; if (detect_space(name) == 1) { if (strchr(name, '\'')) printf("\"%s%s\"\n", name, isdir >= 1 ? "/" : ""); else printf("'%s%s'\n", name, isdir >= 1 ? "/" : ""); } else { fputs(name, stdout); puts(isdir >= 1 ? "/" : ""); } free(tmp_name); } /* Return the value of the environment variable S, allocated via malloc if * ALLOC is 1, or just a pointer to the value if 0. */ char * xgetenv(const char *s, const int alloc) { if (!s || !*s) return (char *)NULL; char *p = getenv(s); if (p && *p) return (alloc == 1 ? strdup(p) : p); return (char *)NULL; } /* Print the regex error ERRCODE (returned by either regcomp(3) or regexec(3)), * whose compiled regular expression is REGEXP and original pattern PATTERN, * in the next prompt if PROMPT_ERR == 1, or immediately otherwise. */ void xregerror(const char *cmd_name, const char *pattern, const int errcode, const regex_t regexp, const int prompt_err) { const size_t err_len = regerror(errcode, ®exp, NULL, 0); char *buf = xnmalloc(err_len + 1, sizeof(char)); regerror(errcode, ®exp, buf, err_len); if (prompt_err == 1) err('w', PRINT_PROMPT, "%s: %s: %s\n", cmd_name, pattern, buf); else xerror("%s: %s: %s\n", cmd_name, pattern, buf); free(buf); } /* Generate a hash of the string STR (case sensitively if CASE_SENTITIVE is * set to 1). * Based on the sdbm algorithm (see http://www.cse.yorku.ca/~oz/hash.html), * released under the public-domain. */ size_t hashme(const char *restrict str, const int case_sensitive) { size_t hash = 0; /* Two while loops, so that we don't need to check CASE_SENSITIVE for * each character in STR. */ if (case_sensitive != 1) { while (*str) { hash = (size_t)TOUPPER(*str) + (hash << 6) + (hash << 16) - hash; str++; } } else { while (*str) { hash = (size_t)*str + (hash << 6) + (hash << 16) - hash; str++; } } return hash; } #if defined(__sun) && defined(ST_BTIME) struct timespec get_birthtime(const char *filename) { struct timespec ts; ts.tv_sec = ts.tv_nsec = (time_t)-1; nvlist_t *response; if (getattrat(XAT_FDCWD, XATTR_VIEW_READWRITE, filename, &response) != 0) return ts; uint64_t *val; uint_t n; if (nvlist_lookup_uint64_array(response, A_CRTIME, &val, &n) == 0 && n >= 2 && val[0] <= LONG_MAX && val[1] < 1000000000 * 2 /* for leap seconds */) { ts.tv_sec = (time_t)val[0]; ts.tv_nsec = (time_t)val[1]; } nvlist_free(response); return ts; } #endif /* __sun && ST_BTIME */ void gen_time_str(char *buf, const size_t size, const time_t curtime) { struct tm t; if (curtime >= 0 && localtime_r(&curtime, &t)) { *buf = '\0'; strftime(buf, size, DEF_TIME_STYLE_LONG, &t); return; } *buf = '-'; buf[1] = '\0'; } /* Store the fzf preview window border style to later fix coordinates if * needed (set_fzf_env_vars() in tabcomp.c) */ void set_fzf_preview_border_type(void) { #ifdef _NO_LIRA return; #endif /* _NO_LIRA */ fzf_preview_border_type = FZF_BORDER_ROUNDED; /* fzf default */ const char *p = (conf.fzftab_options && *conf.fzftab_options) ? strstr(conf.fzftab_options, "border-") : (char *)NULL; if (!p || !p[7]) { const char *q = getenv("FZF_DEFAULT_OPTS"); p = q ? strstr(q, "border-") : (char *)NULL; if (!p || !p[7]) return; } switch (p[7]) { case 'b': if (p[8] == 'o' && p[9] == 't') fzf_preview_border_type = FZF_BORDER_BOTTOM; else if (p[8] == 'l') fzf_preview_border_type = FZF_BORDER_BLOCK; else fzf_preview_border_type = FZF_BORDER_BOLD; break; case 'd': fzf_preview_border_type = FZF_BORDER_DOUBLE; break; case 'h': fzf_preview_border_type = FZF_BORDER_HORIZ; break; case 'l': fzf_preview_border_type = FZF_BORDER_LEFT; break; case 'n': fzf_preview_border_type = FZF_BORDER_NONE; break; case 'r': fzf_preview_border_type = p[8] == 'o' ? FZF_BORDER_ROUNDED : FZF_BORDER_RIGHT; break; case 's': fzf_preview_border_type = FZF_BORDER_SHARP; break; case 't': if (p[8] == 'o') fzf_preview_border_type = FZF_BORDER_TOP; else fzf_preview_border_type = FZF_BORDER_THINBLOCK; break; case 'v': fzf_preview_border_type = FZF_BORDER_VERT; break; default: break; } } /* Remove any image printed by ueberzug. * This function assumes: * 1) That ueberzug was launched using the json parser (default). * 2) That the pipe was created and exported as FIFO_UEBERZUG. * 3) That the identifier string was set to "clifm-preview". */ static void ueberzug_clear(char *file) { int fd = 0; FILE *fp = open_fwrite(file, &fd); if (!fp) return; fprintf(fp, "{\"action\": \"remove\", \"identifier\": \"clifm-preview\"}\n"); fclose(fp); } /* Let's clear images printed on the terminal screen via ueberzug(1). */ void clear_term_img(void) { static char fu[PATH_MAX + 1] = ""; char *p = (char *)NULL; if (!*fu) { p = getenv("CLIFM_FIFO_UEBERZUG"); if (!p || !*p) return; xstrsncpy(fu, p, sizeof(fu)); } ueberzug_clear(fu); } /* Return a pointer to the first digit found in STR or NULL if none is found. */ static char * find_digit(char *str) { if (!str || !*str) return (char *)NULL; while (*str) { if (*str >= '1' && *str <= '9') return str; str++; } return (char *)NULL; } /* Check whether a given command needs ELN's to be expanded/completed/suggested. * Returns 1 if yes or 0 if not. */ int should_expand_eln(const char *text, char *cmd_name) { char *l = cmd_name ? cmd_name : rl_line_buffer; /* Do not expand numbers starting with zero */ if (!l || !*l || *text == '0' || !is_number(text)) return 0; /* Exclude 'ws', 'mf', and 'st/sort' commands. */ if ((*l == 'w' && l[1] == 's' && !l[2]) || (*l == 'm' && l[1] == 'f' && !l[2]) || (*l == 's' && ((l[1] == 't' && !l[2]) || strcmp(l + 1, "ort") == 0))) return 0; const filesn_t a = xatof(text); if (a <= 0 || a > files) /* Only expand numbers matching ELN's */ return 0; if (words_num == 1) { /* First word */ if (file_info[a - 1].dir && conf.autocd == 0) return 0; if (file_info[a - 1].dir == 0 && conf.auto_open == 0) return 0; } char *p = strchr(l, ' '); char t = ' '; if (!p && (p = find_digit(l))) t = *p; if (p) /* Either space of fused ELN. */ *p = '\0'; flags |= STATE_COMPLETING; const int ret = (is_internal_cmd(l, NO_FNAME_NUM, 1, 1)) ? 0 : 1; flags &= ~STATE_COMPLETING; if (p) *p = t; return ret; } #if !defined(_POSIX_C_SOURCE) || _POSIX_C_SOURCE >= 199309L /* Sleep for MSEC milliseconds. */ /* Taken from https://stackoverflow.com/questions/1157209/is-there-an-alternative-sleep-function-in-c-to-milliseconds */ static int msleep(const long msec) { struct timespec ts; int res; if (msec < 0) { errno = EINVAL; return (-1); } ts.tv_sec = msec / 1000; ts.tv_nsec = (msec % 1000) * 1000000; do { res = nanosleep(&ts, &ts); } while (res && errno == EINTR); return res; } #endif /* _POSIX_C_SOURCE >= 199309L */ /* Convert the file named STR (as absolute path) into a more friendly format. * Change absolute paths into: * "./" if file is in CWD * "~" if file is in HOME * The reformated filename is returned if actually reformated, in which case * the returned value should be free'd by the caller. * Otherwise, a pointer to the original string is returned and must not be * free'd by the caller. * Usage example: * char *ret = abbreviate_file_name(str); * ... * if (ret && ret != str) * free(ret); */ char * abbreviate_file_name(char *str) { if (!str || !*str) return (char *)NULL; char *name = (char *)NULL; const size_t len = strlen(str); const size_t wlen = (workspaces && workspaces[cur_ws].path) ? strlen(workspaces[cur_ws].path) : 0; /* If STR is in CWD -> ./STR */ if (workspaces && workspaces[cur_ws].path && wlen > 1 && len > wlen && strncmp(str, workspaces[cur_ws].path, wlen) == 0 && *(str + wlen) == '/') { const size_t name_len = strlen(str + wlen + 1) + 3; name = xnmalloc(name_len, sizeof(char)); snprintf(name, name_len, "./%s", str + wlen + 1); return name; } /* If STR is in HOME, reduce HOME to tilde (~) */ int free_ptr = 0; char *tmp = home_tilde(str, &free_ptr); if (tmp && tmp != str) { name = savestring(tmp, strlen(tmp)); if (free_ptr == 1) free(tmp); return name; } return str; } /* Return the current working directory from any of the following sources and * in this order: * 1 - Path of the current workspace (if CHECK_WORKSPACE is set to 1). * 2 - PWD environment variable (if not --secure-env-full) * 3 - getcwd(3), in which case the value is stored in BUF, whose size is BUFLEN. * */ char * get_cwd(char *buf, const size_t buflen, const int check_workspace) { if (check_workspace == 1 && workspaces && cur_ws >= 0 && workspaces[cur_ws].path) return workspaces[cur_ws].path; char *tmp = xargs.secure_env_full != 1 ? getenv("PWD") : (char *)NULL; if (tmp) return tmp; const char *ret = getcwd(buf, buflen); tmp = (ret && *buf) ? buf : (char *)NULL; return tmp; } void * xmemrchr(const void *s, const int c, size_t n) { #ifdef HAVE_MEMRCHR return memrchr(s, c, n); #else /* OpenBSD implementation of memrchr(), licensed MIT. * Modified code is licensed GPL2+. */ const unsigned char *cp; if (n != 0) { cp = (unsigned char *)s + n; do { if (*(--cp) == (unsigned char)c) return((void *)cp); } while (--n != 0); } return (NULL); #endif /* HAVE_MEMRCHR */ } /* Canonicalize/normalize the path SRC without resolving symlinks. * SRC is unescaped if necessary. * ~/./.. are resolved. * The resolved path is returned and must be free'd by the caller. */ char * normalize_path(char *src, const size_t src_len) { if (!src || !*src) return (char *)NULL; /* Deescape SRC */ char *tmp = (char *)NULL; const int is_escaped = *src == '\\'; if (strchr(src, '\\')) { tmp = unescape_str(src, 0); if (!tmp) { xerror(_("%s: '%s': Error unescaping string\n"), PROGRAM_NAME, src); return (char *)NULL; } const size_t tlen = strlen(tmp); if (tlen > 1 && tmp[tlen - 1] == '/') tmp[tlen - 1] = '\0'; xstrsncpy(src, tmp, tlen + 1); free(tmp); tmp = (char *)NULL; } /* Expand tilde */ if (is_escaped == 0 && *src == '~') { tmp = tilde_expand(src); if (!tmp) { xerror(_("%s: '%s': Error expanding tilde\n"), PROGRAM_NAME, src); return (char *)NULL; } const size_t tlen = strlen(tmp); if (tlen > 1 && tmp[tlen - 1] == '/') tmp[tlen - 1] = '\0'; if (!strstr(tmp, "/..")) return tmp; } char *s = tmp ? tmp : src; const size_t l = tmp ? strlen(tmp) : src_len; /* Resolve references to . and .. */ char *res = (char *)NULL; size_t res_len = 0; if (l == 0 || *s != '/') { /* Relative path */ char p[PATH_MAX + 1]; *p = '\0'; char *cwd = get_cwd(p, sizeof(p), 1); if (!cwd || !*cwd) { xerror(_("%s: Error getting current directory\n"), PROGRAM_NAME); free(tmp); return (char *)NULL; } const size_t pwd_len = strlen(cwd); if (pwd_len == 1 && *cwd == '/') { /* If CWD is root (/) do not copy anything. Just create a buffer * big enough to hold "/dir", which will be appended next */ res = xnmalloc(l + 2, sizeof(char)); res_len = 0; } else { res = xnmalloc(pwd_len + 1 + l + 1, sizeof(char)); memcpy(res, cwd, pwd_len); res_len = pwd_len; } } else { res = xnmalloc(l + 1, sizeof(char)); res_len = 0; } const char *ptr; const char *end = &s[l]; const char *next; for (ptr = s; ptr < end; ptr = next + 1) { next = memchr(ptr, '/', (size_t)(end - ptr)); if (!next) next = end; const size_t len = (size_t)(next - ptr); if (len <= 2) { if (len == 0) continue; if (len == 1 && *ptr == '.') continue; if (len == 2 && *ptr == '.' && ptr[1] == '.') { const char *slash = xmemrchr(res, '/', res_len); if (slash) res_len = (size_t)(slash - res); continue; } } res[res_len] = '/'; res_len++; memcpy(&res[res_len], ptr, len); res_len += len; } if (res_len == 0) { res[res_len] = '/'; res_len++; } res[res_len] = '\0'; if (res_len > 1 && res[res_len - 1] == '/') res[res_len - 1] = '\0'; if (s == tmp) free(s); return res; } /* Ring the terminal bell according to any of the following modes: * AUDIBLE, FLASH, or VISIBLE. */ void rl_ring_bell(void) { switch (conf.bell_style) { case BELL_AUDIBLE: RING_BELL; fflush(stderr); return; #if !defined(_POSIX_C_SOURCE) || _POSIX_C_SOURCE >= 199309L case BELL_FLASH: SET_RVIDEO; fflush(stderr); msleep(VISIBLE_BELL_DELAY); UNSET_RVIDEO; fflush(stderr); return; # ifdef READLINE_HAS_ACTIVATE_MARK /* Readline >= 8.1 */ case BELL_VISIBLE: { int point = rl_point; rl_mark = 0; char *p = get_last_chr(rl_line_buffer, ' ', rl_point); if (p && p != rl_line_buffer && *(++p)) rl_mark = (int)(p - rl_line_buffer); if (rl_end > 1 && rl_line_buffer[rl_end - 1] == ' ') rl_point--; rl_activate_mark(); rl_redisplay(); msleep(VISIBLE_BELL_DELAY); rl_deactivate_mark(); # ifndef _NO_HIGHLIGHT if (conf.highlight && !wrong_cmd) { rl_point = rl_mark; recolorize_line(); } # endif /* !_NO_HIGHLIGHT */ rl_point = point; return; } # endif /* READLINE_HAS_ACTIVATE_MARK */ #endif /* _POSIX_C_SOURCE >= 199309L */ case BELL_NONE: /* fallthrough */ default: return; } } /* Generate a time string (based on the struct tm TM) with this form: * YYYYMMDDHHMMSS. * This function is used mostly by the trash function to generate unique * suffixes for trashed files. */ char * gen_date_suffix(const struct tm tm, const int human) { char *suffix = NULL; if (human == 0) { suffix = xnmalloc(68, sizeof(char)); snprintf(suffix, 67, "%04d%02d%02d%02d%02d%02d", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); } else { char date[18] = ""; const size_t bytes = strftime(date, sizeof(date), "%Y%m%d-%H:%M:%S", &tm); if (bytes > 0) suffix = savestring(date, bytes); } return suffix; } char * gen_backup_file(const char *file, const int human) { time_t rawtime = time(NULL); struct tm t; char *suffix = localtime_r(&rawtime, &t) ? gen_date_suffix(t, human) : NULL; if (!suffix) { xerror(_("kb: Cannot generate time suffix string for " "the backup file\n")); return NULL; } char backup[PATH_MAX + 1]; snprintf(backup, sizeof(backup), "%s-%s", file, suffix); free(suffix); return strdup(backup); } /* Create directory DIR with permissions set to MODE (this latter modified * by a restrictive umask value: 077). */ int xmkdir(const char *dir, const mode_t mode) { const mode_t old_mask = umask(0077); /* flawfinder: ignore */ const int ret = mkdirat(XAT_FDCWD, dir, mode); umask(old_mask); /* flawfinder: ignore */ if (ret == -1) return FUNC_FAILURE; return FUNC_SUCCESS; } /* Same as readlinkat(3), but resolves relative symbolic links and NUL * terminates the returned string (BUF). */ ssize_t xreadlink(const int fd, char *restrict path, char *restrict buf, const size_t bufsize) { buf[0] = '\0'; const ssize_t buf_len = readlinkat(fd, path, buf, bufsize - 1); if (buf_len == -1) return (-1); buf[buf_len] = '\0'; if (buf_len > 1 && buf[buf_len - 1] == '/') buf[buf_len - 1] = '\0'; int rem_slash = 0; size_t path_len = strlen(path); if (path_len > 1 && path[path_len - 1] == '/') { path[path_len - 1] = '\0'; rem_slash = 1; } char *p = (char *)NULL; if (*buf != '/' && (p = strrchr(path, '/'))) { /* Relative link */ *p = '\0'; char *temp = savestring(buf, strlen(buf)); if (p == path) /* Root */ snprintf(buf, bufsize, "/%s", temp); else snprintf(buf, bufsize, "%s/%s", path, temp); *p = '/'; free(temp); } if (rem_slash == 1) path[path_len - 1] = '/'; return buf_len; } /* Open a file for read only. Return a file stream associated to the file * named NAME and updates FD to hold the corresponding file descriptor. * NOTE: As stated here, file streams are to be preferred over file descriptors: * https://www.gnu.org/software/libc/manual/html_node/Streams-and-File-Descriptors.html */ FILE * open_fread(const char *name, int *fd) { errno = 0; if (!name || !*name) { errno = EINVAL; return (FILE *)NULL; } *fd = open(name, O_RDONLY); if (*fd == -1) return (FILE *)NULL; FILE *fp = fdopen(*fd, "r"); if (!fp) { close(*fd); return (FILE *)NULL; } return fp; } /* Create a file for writing (truncating it to zero length if it already exists, * and with permissions 600). * Return a file stream associated to the file named NAME and update FD to hold * the corresponding file descriptor. */ FILE * open_fwrite(const char *name, int *fd) { errno = 0; if (!name || !*name) { errno = EINVAL; return (FILE *)NULL; } *fd = open(name, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); if (*fd == -1) return (FILE *)NULL; FILE *fp = fdopen(*fd, "w"); if (!fp) { close(*fd); return (FILE *)NULL; } return fp; } /* Open a file for appending (using permissions 600). * Return a file stream associated to the file named NAME or NULL in case of * error. */ FILE * open_fappend(const char *name) { errno = 0; if (!name || !*name) { errno = EINVAL; return (FILE *)NULL; } int fd = open(name, O_WRONLY | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR); if (fd == -1) return (FILE *)NULL; FILE *fp = fdopen(fd, "a"); if (!fp) { close(fd); return (FILE *)NULL; } return fp; } /* Transform S_IFXXX (MODE) into the corresponding DT_XXX constant */ inline mode_t get_dt(const mode_t mode) { switch (mode & S_IFMT) { case S_IFREG: return DT_REG; case S_IFDIR: return DT_DIR; case S_IFLNK: return DT_LNK; case S_IFIFO: return DT_FIFO; case S_IFSOCK: return DT_SOCK; case S_IFBLK: return DT_BLK; case S_IFCHR: return DT_CHR; #ifndef _BE_POSIX # ifdef SOLARIS_DOORS case S_IFDOOR: return DT_DOOR; case S_IFPORT: return DT_PORT; # endif /* SOLARIS_DOORS */ # ifdef S_IFWHT case S_IFWHT: return DT_WHT; # endif # ifdef S_ARCH1 case S_ARCH1: return DT_ARCH1; case S_ARCH2: return DT_ARCH2; # endif #endif /* !_BE_POSIX */ default: return DT_UNKNOWN; } } static int hex2int(const char *str) { static const unsigned char hex_chars[256] = { ['0'] = 0, ['1'] = 1, ['2'] = 2, ['3'] = 3, ['4'] = 4, ['5'] = 5, ['6'] = 6, ['7'] = 7, ['8'] = 8, ['9'] = 9, ['a'] = 10, ['b'] = 11, ['c'] = 12, ['d'] = 13, ['e'] = 14, ['f'] = 15, ['A'] = 10, ['B'] = 11, ['C'] = 12, ['D'] = 13, ['E'] = 14, ['F'] = 15 }; /* int << 4 == int * 16 */ return ((hex_chars[(unsigned char)str[0]] << 4) + hex_chars[(unsigned char)str[1]]); } /* Disassemble the hex color HEX into attribute, R, G, and B values. * Based on https://mprog.wordpress.com/c/miscellaneous/convert-hexcolor-to-rgb-decimal */ int get_rgb(const char *hex, int *attr, int *r, int *g, int *b) { if (!hex || !*hex) return (-1); if (*hex == '#') { if (!hex[1]) return (-1); hex++; } const char *h = hex; /* Convert 3-digits HEX to 6-digits */ static char buf[9]; if (h[0] && h[1] && h[2] && (!h[3] || h[3] == '-') ) { buf[0] = buf[1] = h[0]; buf[2] = buf[3] = h[1]; buf[4] = buf[5] = h[2]; if (!h[3] || !h[4]) { buf[6] = '\0'; } else { buf[6] = '-'; buf[7] = h[4]; buf[8] = '\0'; } h = buf; } char tmp[3]; tmp[2] = '\0'; tmp[0] = h[0]; tmp[1] = h[1]; *r = hex2int(tmp); tmp[0] = h[2]; tmp[1] = h[3]; *g = hex2int(tmp); tmp[0] = h[4]; tmp[1] = h[5]; *b = hex2int(tmp); *attr = -1; /* Attribute unset */ if (h[6] == '-' && h[7] >= '0' && h[7] <= '9' && !h[8]) *attr = h[7] - '0'; if (xargs.no_bold == 1 && *attr == 1) *attr = -1; return 0; } /* Convert hex color HEX into RGB format (as a color code) * One color attribute can be added to the hex color as follows: * RRGGBB-[1-9], where 1-9 could be: * 1: Bold or increased intensity * 2: Faint, decreased intensity or dim * 3: Italic (Not widely supported) * 4: Underline * 5: Slow blink * 6: Rapid blink * 7: Reverse video or invert * 8: Conceal or hide (Not widely supported) * 9: Crossed-out or strike * * Example: ffaff00-4 -> 4;38;2;250;255;0 * * At this point we know HEX is a valid hex color code (see is_hex_color() in * colors.c). * If using this function outside Clifm, make sure to validate HEX yourself * */ char * hex2rgb(const char *hex) { int attr = -1, r = 0, g = 0, b = 0; if (get_rgb(hex, &attr, &r, &g, &b) == -1) return (char *)NULL; if (attr == -1) /* No attribute */ snprintf(tmp_color, sizeof(tmp_color), "38;2;%d;%d;%d", r, g, b); else snprintf(tmp_color, sizeof(tmp_color), "%d;38;2;%d;%d;%d", attr, r, g, b); return tmp_color; } /* Count files in the directory DIR, including self and parent. If POP is set * to 1, the function will just check if the directory is populated (it has at * least 3 files, including self and parent). * Returns -1 in case of error or an integer (0-FILESN_MAX) in case of success. */ filesn_t count_dir(const char *dir, const int pop) { if (!dir) return (-1); DIR *p; if ((p = opendir(dir)) == NULL) { if (errno == ENOMEM) exit(ENOMEM); return (-1); } size_t c = 0; if (pop) { while (readdir(p)) { c++; if (c > 2) break; } } else { while (readdir(p)) /* It is extremely unlikely for a directory to have more than * SIZE_MAX entries. Even if it actually happens, c would wrap * around to zero, leading thus to a wrong count (in the * the absolute worst scenario). */ c++; } closedir(p); return (filesn_t)(c > FILESN_MAX ? FILESN_MAX : c); } /* Get the path of the command CMD inspecting all paths in the PATH * environment variable (it basically does the same as which(1)). * Returns the appropriate path or NULL in case of error (in which case * errno is set to either EINVAL or ENOENT). */ char * get_cmd_path(const char *cmd) { errno = 0; if (!cmd || !*cmd) { errno = EINVAL; return (char *)NULL; } char *cmd_path = (char *)NULL; if (*cmd == '~') { char *p = tilde_expand(cmd); if (p && is_exec_cmd(p) == 1) cmd_path = p; return cmd_path; } if (*cmd == '/') { if (is_exec_cmd(cmd) == 1) cmd_path = savestring(cmd, strlen(cmd)); return cmd_path; } cmd_path = xnmalloc(PATH_MAX + 2, sizeof(char)); size_t i; for (i = 0; i < path_n; i++) { /* Check each path in PATH */ if (!paths[i].path || !*paths[i].path) continue; /* Skip '.' (CWD) if running with secure environment */ if ((xargs.secure_env == 1 || xargs.secure_env_full == 1) && *paths[i].path == '.' && !paths[i].path[1]) continue; snprintf(cmd_path, PATH_MAX + 1, "%s/%s", paths[i].path, cmd); if (is_exec_cmd(cmd_path) == 1) return cmd_path; } errno = ENOENT; free(cmd_path); return (char *)NULL; } /* Same thing as get_cmd_path(), but returns 1 in case of success or 0 * otherwise instead of the absolute path to CMD. Unlike get_cmd_path(), * it does not allocate memory in the heap, so that it's faster. */ int is_cmd_in_path(const char *cmd) { errno = 0; if (!cmd || !*cmd) { errno = EINVAL; return 0; } if (*cmd == '~') { char *p = tilde_expand(cmd); const int ret = (p && is_exec_cmd(p) == 1); free(p); return ret; } if (*cmd == '/') return is_exec_cmd(cmd); char cmd_path[PATH_MAX + 1]; const int is_secure_env = (xargs.secure_env == 1 || xargs.secure_env_full == 1); size_t i; for (i = 0; i < path_n; i++) { /* Check each path in PATH. */ if (!paths[i].path || !*paths[i].path) continue; /* Skip '.' (CWD) if running in secure environment mode. */ if (is_secure_env == 1 && *paths[i].path == '.' && !paths[i].path[1]) continue; snprintf(cmd_path, sizeof(cmd_path), "%s/%s", paths[i].path, cmd); if (is_exec_cmd(cmd_path) == 1) return 1; } errno = ENOENT; return 0; } /* Convert SIZE to human readable form (at most 2 decimal places). * Returns a pointer to a string of at most MAX_UNIT_SIZE. * We use KiB, MiB, GiB... suffixes for powers of 1024 * and kB, MB, GB... for power of 1000. */ char * construct_human_size(const off_t size) { static char str[MAX_HUMAN_SIZE + 2]; if (size < 0) return UNKNOWN_STR; const float base = xargs.si == 1 ? 1000 : 1024; static float mult_factor = 0; if (mult_factor == 0) mult_factor = 1.0f / base; size_t n = 0; float s = (float)size; while (s >= base) { s = s * mult_factor; /* == (s = s / base), but faster */ n++; } static const char *const u = "BKMGTPEZYRQ"; /* R: Ronnabyte, Q: Quettabyte. It's highly unlikely to have files of * such huge sizes (and even less) in the near future. Even more, since * our original value is off_t (whose maximum value is INT64_MAX, * i.e. 2^63 - 1), we will never reach even a Zettabyte. */ /* If s == (float)(int)s, then S has no reminder (zero): * We don't want to print the reminder when it is zero. */ snprintf(str, sizeof(str), "%.*f %c%s", s == (float)(int)s ? 0 : 2, (double)s, (u[n] == 'K' && xargs.si == 1) ? 'k' : u[n], u[n] != 'B' ? (xargs.si == 1 ? "B" : "iB") : ""); return str; } /* Return the file type of the file pointed to by LINK, or -1 in case of * error. Possible return values: S_IFDIR: 40000 (octal) / 16384 (decimal, integer) S_IFREG: 100000 / 32768 S_IFLNK: 120000 / 40960 S_IFSOCK: 140000 / 49152 S_IFBLK: 60000 / 24576 S_IFCHR: 20000 / 8192 S_IFIFO: 10000 / 4096 * See the inode manpage. */ int get_link_ref(const char *link) { errno = 0; if (!link || !*link) { errno = EINVAL; return (-1); } struct stat a; if (stat(link, &a) == -1) return (-1); return (int)(a.st_mode & S_IFMT); } /* Transform an integer (N) into a string of chars. * This exists because most operating systems do not provide itoa(3). * It handles integer numbers between 0 and LLONG_MAX. */ const char * xitoa(long long n) { static char const *nums[102] = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "40", "41", "42", "43", "44", "45", "46", "47", "48", "49", "50", "51", "52", "53", "54", "55", "56", "57", "58", "59", "60", "61", "62", "63", "64", "65", "66", "67", "68", "69", "70", "71", "72", "73", "74", "75", "76", "77", "78", "79", "80", "81", "82", "83", "84", "85", "86", "87", "88", "89", "90", "91", "92", "93", "94", "95", "96", "97", "98", "99", "100", NULL }; if (n >= 0 && n <= 100) return nums[n]; static char buf[MAX_INT_STR] = {0}; /* We start writing at the end of the buffer, which has MAX_INT_STR bytes * (32), that is, from index 0 to 31. Index 31 is reserved for the NUL * terminator, so that we must start writing at index 30. */ long long i = MAX_INT_STR - 2; while (n > 0 && i > 0) { long long rem = n / 10; buf[i] = (char)('0' + (n - (rem * 10))); n = rem; --i; } return &buf[i + 1]; } /* Convert the string S into a number in the range of valid ELN's * (1 - FILESN_MAX). Returns this value if valid or -1 in case of error. */ filesn_t xatof(const char *s) { if (!s[1] && *s > '0' && *s <= '9') return (filesn_t)(*s - '0'); errno = 0; const long long ret = strtoll(s, NULL, 10); #if FILESN_MAX < LLONG_MAX /* 1 - FILESN_MAX */ if (ret < 1 || ret > FILESN_MAX) { #elif FILESN_MAX > LLONG_MAX /* 1 - LLONG_MAX-1 */ if (ret < 1 || ret == LLONG_MAX) { #else /* 1 - FILESN_MAX-1 */ if (ret < 1 || ret >= FILESN_MAX) { #endif /* FILESN_MAX < LLONG_MAX */ errno = ERANGE; return (-1); } return (filesn_t)ret; } /* A secure atoi implementation to prevent integer under- and over-flow. * Returns the corresponding integer, if valid, or INT_MIN if invalid, * setting errno to ERANGE. */ int xatoi(const char *s) { if (!s[1] && *s >= '0' && *s <= '9') return (*s - '0'); errno = 0; const long ret = strtol(s, NULL, 10); if (ret < INT_MIN || ret > INT_MAX) { errno = ERANGE; return INT_MIN; } return (int)ret; } /* Unlike getchar(3) this function does not wait for newline ('\n'). https://stackoverflow.com/questions/12710582/how-can-i-capture-a-key-stroke-immediately-in-linux */ char xgetchar(void) { struct termios oldt, newt; char c = 0; if (tcgetattr(STDIN_FILENO, &oldt) == -1) { xerror("%s: tcgetattr: %s\n", PROGRAM_NAME, strerror(errno)); return 0; } newt = oldt; newt.c_lflag &= (tcflag_t)~(ICANON | ECHO); tcsetattr(STDIN_FILENO, TCSANOW, &newt); c = (char)getchar(); /* flawfinder: ignore */ tcsetattr(STDIN_FILENO, TCSANOW, &oldt); return c; } /* Converts a hex char to its integer value. */ char from_hex(const char c) { return (char)(IS_DIGIT(c) ? c - '0' : TOLOWER(c) - 'a' + 10); } /* Converts an integer value to its hex form. */ static char to_hex(const char c) { static const char hex[] = "0123456789ABCDEF"; return hex[c & 15]; } /* Return an URL-encoded version of STR, prefixed with "file://" if * FILE_URI is set to 1. */ char * url_encode(const char *str, const int file_uri) { if (!str || !*str) return (char *)NULL; const size_t len = (strlen(str) * 3) + 1 + (file_uri == 1 ? 7 : 0); char *buf = xnmalloc(len, sizeof(char)); /* The max lenght of our buffer is 3 times the length of STR (plus * 7 (length of "file://") if FILE_URI is set to 1, plus 1 extra byte * for the null byte terminator): each byte in STR will be, if * encoded, %XX (3 chars). */ /* Copies of STR and BUF pointers to be able to increase and/or decrease * them without losing the original memory location. */ const char *pstr = str; char *pbuf = buf; if (file_uri == 1) { buf[0] = 'f'; buf[1] = 'i'; buf[2] = 'l'; buf[3] = 'e'; buf[4] = ':'; buf[5] = '/'; buf[6] = '/'; buf[7] = '\0'; pbuf += 7; } for (; *pstr; pstr++) { if (IS_ALNUM(*pstr) || *pstr == '-' || *pstr == '_' || *pstr == '.' || *pstr == '~' || *pstr == '/') { /* Do not encode any of the above chars. */ *pbuf = *pstr; pbuf++; } else { /* Encode char to URL format. Example: space char to "%20". */ *pbuf = '%'; pbuf++; *pbuf = to_hex(*pstr >> 4); pbuf++; *pbuf = to_hex(*pstr & 15); pbuf++; } } *pbuf = '\0'; return buf; } /* Returns a url-decoded version of STR. */ char * url_decode(const char *str) { if (!str || !*str) return (char *)NULL; char *buf = xnmalloc(strlen(str) + 1, sizeof(char)); /* The decoded string will be at most as long as the encoded string. */ const char *pstr = str; char *pbuf = buf; for (; *pstr; pstr++) { if (*pstr == '%') { if (pstr[1] && pstr[2]) { /* Decode URL code. Example: %20 to space char. */ *pbuf = (char)(from_hex(pstr[1]) << 4 | from_hex(pstr[2])); pbuf++; pstr += 2; } } else { *pbuf = *pstr; pbuf++; } } *pbuf = '\0'; return buf; } /* Convert the octal string STR into the corresponding integer value. */ int octal2int(const char *restrict str) { if (!str || !*str) return (-1); int dec_value = 0; while (*str) { if (*str < '0' || *str > '7') return (-1); dec_value = (dec_value << 3) + (*str - '0'); str++; } return dec_value; } clifm-1.26.3/src/aux.h000066400000000000000000000061401506632037700144440ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* aux.h */ #ifndef AUX_H #define AUX_H #include #include "mem.h" #ifdef RL_READLINE_VERSION # if RL_READLINE_VERSION >= 0x0801 # define READLINE_HAS_ACTIVATE_MARK # endif /* RL_READLINE_VERSION >= 0x0801 */ #endif /* RL_READLINE_VERSION */ __BEGIN_DECLS char *abbreviate_file_name(char *str); void clear_term_img(void); char *construct_human_size(const off_t size); filesn_t count_dir(const char *dir, const int pop); char from_hex(const char c); char *gen_backup_file(const char *file, const int human); char *gen_date_suffix(const struct tm tm, const int human); void gen_time_str(char *buf, const size_t size, const time_t curtime); #if defined(__sun) && defined(ST_BTIME) struct timespec get_birthtime(const char *filename); #endif /* __sun && ST_BTIME */ char *get_cmd_path(const char *cmd); char *get_cwd(char *buf, const size_t buflen, const int check_workspace); mode_t get_dt(const mode_t mode); int get_link_ref(const char *link); int get_rgb(const char *hex, int *attr, int *r, int *g, int *b); size_t hashme(const char *str, const int case_sensitive); char *hex2rgb(const char *hex); int is_cmd_in_path(const char *cmd); char *normalize_path(char *src, const size_t src_len); int octal2int(const char *restrict str); int open_config_file(char *app, char *file); FILE *open_fread(const char *name, int *fd); FILE *open_fwrite(const char *name, int *fd); FILE *open_fappend(const char *name); void press_any_key_to_continue(const int init_newline); void print_file_name(char *fname, const int isdir); void rl_ring_bell(void); void set_fzf_preview_border_type(void); int should_expand_eln(const char *text, char *cmd_name); char *url_encode(const char *str, const int file_uri); char *url_decode(const char *str); int utf8_bytes(unsigned char c); filesn_t xatof(const char *s); int xatoi(const char *s); const char *xitoa(long long n); char xgetchar(void); char *xgetenv(const char *s, const int alloc); void *xmemrchr(const void *s, const int c, size_t n); int xmkdir(const char *dir, const mode_t mode); ssize_t xreadlink(const int fd, char *restrict path, char *restrict buf, const size_t bufsize); void xregerror(const char *cmd_name, const char *pattern, const int errcode, const regex_t regexp, const int prompt_err); __END_DECLS #endif /* AUX_H */ clifm-1.26.3/src/bookmarks.c000066400000000000000000000440201506632037700156310ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* bookmarks.c -- bookmarking functions */ #include "helpers.h" #include #include /* tilde_expand() */ #include #include #include "aux.h" /* xatoi(), normalize_path(), open_fread(), open_fwrite() */ #include "bookmarks.h" /* bookmarks_function() */ #include "checks.h" /* is_number() */ #include "colors.h" /* get_entry_color() */ #include "file_operations.h" /* open_function() */ #include "init.h" /* load_bookmarks() */ #include "messages.h" /* STEALTH_DISABLED */ #include "misc.h" /* err(), xerror() */ #include "listing.h" /* reload_dirlist() */ #include "readline.h" /* rl_no_hist() */ #include "spawn.h" /* launch_execv() */ void free_bookmarks(void) { if (bm_n == 0) return; size_t i; for (i = 0; i < bm_n; i++) { free(bookmarks[i].shortcut); free(bookmarks[i].name); free(bookmarks[i].path); } free(bookmarks); bookmarks = (struct bookmarks_t *)NULL; bm_n = 0; } void reload_bookmarks(void) { free_bookmarks(); load_bookmarks(); } static char ** bm_prompt(const int print_header) { char *bm = (char *)NULL; if (print_header) printf(_("%s%s\nEnter '%c' to edit your bookmarks or '%c' to quit\n" "Select a bookmark (by ELN, shortcut, or name):\n"), NC, df_c, 'e', 'q'); const int prompt_offset_bk = prompt_offset; prompt_offset = 0; alt_prompt = BOOKMARKS_PROMPT; char bm_str[(MAX_COLOR * 2) + 7]; snprintf(bm_str, sizeof(bm_str), "\001%s\002>\001%s\002 ", mi_c, tx_c); while (!bm) bm = rl_no_hist(bm_str, 1); alt_prompt = 0; prompt_offset = prompt_offset_bk; char **cmd = (char **)NULL; /* "e/edit" is the only command that needs to split the input string: * the second field may be an opening application. */ if (*bm == 'e' && (bm[1] == ' ' || strncmp(bm, "edit ", 5) == 0)) { flags |= IN_BOOKMARKS_SCREEN; cmd = split_str(bm, NO_UPDATE_ARGS); flags &= ~IN_BOOKMARKS_SCREEN; free(bm); } else { char *tmp = strchr(bm, '\\') ? unescape_str(bm, 0) : (char *)NULL; cmd = xnmalloc(2, sizeof(char *)); cmd[0] = tmp ? tmp : bm; cmd[1] = (char *)NULL; if (tmp) free(bm); } return cmd; } static int edit_bookmarks(char *cmd, const int flag) { struct stat a; if (stat(bm_file, &a) == -1) { xerror("bookmarks: '%s': %s\n", bm_file, strerror(errno)); return errno; } const time_t prev = a.st_mtime; const int ret = open_config_file(cmd, bm_file); if (ret != FUNC_SUCCESS) { if (!cmd) xerror("%s\n", _("bookmarks: Cannot open the bookmarks file")); return ret; } if (stat(bm_file, &a) == -1) { xerror("bookmarks: '%s': %s\n", bm_file, strerror(errno)); return errno; } if (prev != a.st_mtime) { reload_bookmarks(); if (flag == NO_BM_SCREEN) { reload_dirlist(); print_reload_msg(NULL, NULL, _("File modified. Bookmarks reloaded.\n")); } } return FUNC_SUCCESS; } /* Update LS and LN with the longest shortcut and name entries in the bookmarks * database respectively. */ static void get_longest_entries(size_t *ls, size_t *ln) { *ls = 0; *ln = 0; if (bm_n == 0 || !bookmarks) return; int i = (int)bm_n; while (--i >= 0) { if (bookmarks[i].shortcut && *bookmarks[i].shortcut) { const size_t slen = strlen(bookmarks[i].shortcut); if (slen > *ls) *ls = slen; } if (bookmarks[i].name && *bookmarks[i].name) { const size_t nlen = strlen(bookmarks[i].name); if (nlen > *ln) *ln = nlen; } } } /* Print the list of available bookmarks. */ static void print_bookmarks(void) { HIDE_CURSOR; printf(_("%sBookmark Manager%s\n\n"), BOLD, df_c); struct stat attr; const int eln_pad = DIGINUM(bm_n); size_t ls = 0, ln = 0; size_t i; get_longest_entries(&ls, &ln); /* Print bookmarks, taking into account shortcut, name, and path. */ for (i = 0; i < bm_n; i++) { if (!bookmarks[i].path || !*bookmarks[i].path) continue; const int sc_ok = bookmarks[i].shortcut ? 1 : 0; int sc_pad = (int)ls; if (sc_ok == 0 && ls > 0) sc_pad += 2; // No shortcut. Let's count '[' and ']' if (sc_ok == 1) sc_pad -= (int)strlen(bookmarks[i].shortcut); if (sc_pad < 0) sc_pad = 0; char *color = stat(bookmarks[i].path, &attr) == -1 ? uf_c : get_entry_color(bookmarks[i].path, &attr); printf("%s%s%*zu%s%s%s%s%s%s%s%-*s %s%-*s%s %s%s%s\n", NC, el_c, eln_pad, i + 1, df_c, // ELN ls > 0 ? " " : "", sc_ok == 1 ? "[" : "", sc_ok == 1 ? mi_c : bk_c, // Shortcut sc_ok == 1 ? bookmarks[i].shortcut : "", df_c, sc_ok == 1 ? "]" : "", sc_pad, "", mi_c, (int)ln, bookmarks[i].name ? bookmarks[i].name : "", df_c, color, bookmarks[i].path, df_c); } UNHIDE_CURSOR; } static int edit_bookmarks_func(char **arg) { edit_bookmarks(arg[1], BM_SCREEN); size_t i; for (i = 0; arg[i]; i++) free(arg[i]); free(arg); char *tmp_cmd[] = {"bm", NULL}; bookmarks_function(tmp_cmd); return FUNC_SUCCESS; } /* Return a pointer to the bookmark path (in the bookmarks array) * corresponding to ARG (either an ELN or a string). Otherwise return NULL. * The return value of this function must not be free'd. */ static char * get_bm_path(char *arg) { /* If an ELN */ if (is_number(arg)) { const int num = atoi(arg); if (num <= 0 || (size_t)num > bm_n) { xerror(_("%s: No such ELN\n"), arg); return (char *)NULL; } return bookmarks[num - 1].path; } char *p = remove_quotes(arg); char *name = p ? p : arg; /* If string, check shortcuts and names */ size_t i; for (i = 0; i < bm_n; i++) { if ((bookmarks[i].shortcut && *name == *bookmarks[i].shortcut && strcmp(name, bookmarks[i].shortcut) == 0) || (bookmarks[i].name && *name == *bookmarks[i].name && strcmp(name, bookmarks[i].name) == 0)) { if (bookmarks[i].path) return bookmarks[i].path; xerror(_("'%s': Invalid bookmark\n"), name); return (char *)NULL; } } xerror(_("'%s': No such bookmark\n"), name); return (char *)NULL; } static void free_bm_input(char ***p) { size_t i; for (i = 0; (*p)[i]; i++) free((*p)[i]); free(*p); *p = (char **)NULL; } /* This function takes care of the bookmarks screen. * It prints available bookmarks, gets user input, and opens the appropriate * bookmark. */ int open_bookmark(void) { if (!bookmarks || bm_n == 0) { puts(_(NO_BOOKMARKS)); return FUNC_SUCCESS; } if (conf.clear_screen > 0) CLEAR; int exit_status = FUNC_SUCCESS; int header_printed = 0; int is_dir = 0; print_bookmarks(); char **arg = (char **)NULL; while (!arg) { arg = bm_prompt(header_printed == 1 ? NO_BM_HEADER : PRINT_BM_HEADER); header_printed = 1; if (!arg) continue; if (*arg[0] == 'e' && (!arg[0][1] || strcmp(arg[0], "edit") == 0)) return edit_bookmarks_func(arg); if (*arg[0] == 'q' && (!arg[0][1] || strcmp(arg[0], "quit") == 0)) break; char *tmp_path = get_bm_path(arg[0]); if (!tmp_path) { free_bm_input(&arg); continue; } struct stat a; /* If not a dir, refresh the file list */ if (stat(tmp_path, &a) != -1 && S_ISDIR(a.st_mode)) is_dir = 1; char *tmp_cmd[] = {"o", tmp_path, arg[1], NULL}; exit_status = open_function(tmp_cmd); if (exit_status != FUNC_SUCCESS) { free_bm_input(&arg); continue; } break; } free_bm_input(&arg); if (conf.autols == 1 && is_dir == 0) reload_dirlist(); return FUNC_SUCCESS; } /* Open a bookmark by either shortcut or name. */ static int bm_open(char **cmd) { int exit_status = FUNC_FAILURE; char *p = unescape_str(cmd[1], 0); if (!p) p = cmd[1]; size_t i; for (i = 0; i < bm_n; i++) { if (!(bookmarks[i].shortcut && *p == *bookmarks[i].shortcut && strcmp(p, bookmarks[i].shortcut) == 0) && !(bookmarks[i].name && *p == *bookmarks[i].name && strcmp(p, bookmarks[i].name) == 0)) continue; if (!bookmarks[i].path) { xerror(_("'%s': Invalid bookmark\n"), p); goto END; } char *tmp_cmd[] = {"o", bookmarks[i].path, cmd[2], NULL}; exit_status = open_function(tmp_cmd); goto END; } xerror(_("'%s': No such bookmark\n"), p); END: if (p != cmd[1]) free(p); return exit_status; } /* Check the file FILE against the list of bookmarked paths. * Returns 1 if found, or 0 otherwise. */ static int check_bm_path(char *file) { if (bm_n == 0 || !bookmarks) return 0; char *p = normalize_path(file, strlen(file)); char *new_path = p ? p : file; int i = (int)bm_n; while (--i >= 0) { if (!bookmarks[i].path || strcmp(new_path, bookmarks[i].path) != 0) continue; xerror(_("bookmarks: '%s': Already bookmarked as '%s'\n"), new_path, bookmarks[i].name ? bookmarks[i].name : (bookmarks[i].shortcut ? bookmarks[i].shortcut : _("unnamed")) ); free(p); return 1; } free(p); return 0; } static int name_is_reserved_keyword(const char *name) { if (!name || !*name) return 0; if ( ((*name == 'e' || *name == 'd' || *name == 'a' || *name == 'q') && !name[1]) || strcmp(name, "quit") == 0 || strcmp(name, "edit") == 0 || strcmp(name, "del") == 0 || strcmp(name, "add") == 0 || strcmp(name, "reload") == 0) { xerror(_("bookmarks: '%s': Reserved bookmark keyword\n"), name); return 1; } if (strchr(name, ':') || strchr(name, '[') || strchr(name, ']')) { xerror(_("bookmarks: '%s': Colons and square brackets " "are not allowed\n"), name); return 1; } return 0; } /* Check the name NAME against the list of used bookmark names. * Rerturns the index of the used bookmark (in the bookmarks array) if found, * or -1 otherwise. * If ADD is set to 1, NAME will be compared to reserved bookmark keywords * as well, and a message will be printed if a matching name is found. */ static int check_bm_name(const char *name, const int add) { if (bm_n == 0 || !bookmarks) return (-1); if (add == 1 && name_is_reserved_keyword(name) == 1) return 0; int i = (int)bm_n; while (--i >= 0) { if (!bookmarks[i].name || *name != *bookmarks[i].name || strcmp(name, bookmarks[i].name) != 0) continue; if (add == 1) xerror(_("bookmarks: '%s': Name already in use\n"), name); return i; } return (-1); } /* Same as check_bm_name(), but for shortcuts. */ static int check_bm_shortcut(const char *shortcut, const int add) { if (bm_n == 0 || !bookmarks) return (-1); if (add == 1 && name_is_reserved_keyword(shortcut) == 1) return 0; int i = (int)bm_n; while (--i >= 0) { if (!bookmarks[i].shortcut || *shortcut != *bookmarks[i].shortcut || strcmp(shortcut, bookmarks[i].shortcut) != 0) continue; if (add == 1) xerror(_("bookmarks: '%s': Shortcut already in use\n"), shortcut); return i; } return (-1); } /* Bookmark the file FILE as NAME and shortcut SHORTCUT. * FILE and NAME are guarranteed to be non-NULL. * FILE is already dequoted. */ static int bookmark_add(char *file, char *name, char *shortcut) { if (check_bm_path(file) == 1 && rl_get_y_or_n(_("Continue?"), 0) == 0) return FUNC_SUCCESS; int exit_status = FUNC_FAILURE; char *p = unescape_str(name, 0); char *n = p ? p : name; char *q = (char *)NULL; char *s = (char *)NULL; if (check_bm_name(n, 1) != -1) goto ERROR; if (shortcut) { q = unescape_str(shortcut, 0); s = q ? q : shortcut; if (check_bm_shortcut(s, 1) != -1) goto ERROR; } /* Once we have path, name and (optionally) shortcut, write it to the * bookmarks file. */ FILE *bm_fp = open_fappend(bm_file); if (!bm_fp) { exit_status = errno; xerror("bookmarks: '%s': %s\n", bm_file, strerror(errno)); goto ERROR; } if (fseek(bm_fp, 0L, SEEK_END) == -1) { exit_status = errno; xerror("bookmarks: '%s': %s\n", bm_file, strerror(errno)); fclose(bm_fp); goto ERROR; } char *np = normalize_path(file, strlen(file)); /* Everything is fine: add the new bookmark to the bookmarks file */ if (s) fprintf(bm_fp, "[%s]%s:%s\n", s, n, np ? np : file); else fprintf(bm_fp, "%s:%s\n", n, np ? np : file); fclose(bm_fp); puts(_("File succesfully bookmarked")); if (s) printf("[%s]%s %s%s%s %s\n", s, n, mi_c, SET_MSG_PTR, tx_c, np ? np : file); else printf("%s %s%s%s %s\n", n, mi_c, SET_MSG_PTR, tx_c, np ? np : file); free(np); free(p); free(q); reload_bookmarks(); /* Update bookmarks for tab completion. */ return FUNC_SUCCESS; ERROR: free(p); free(q); return exit_status; } /* Create a new bookmark using the fields provided by CMD: path, name, and * (optionally) shortcut. */ static int add_bookmark(char **cmd) { if (!cmd || !cmd[0] || !cmd[1]) { puts(BM_ADD_NO_PARAM); return FUNC_SUCCESS; } if (bm_n == MAX_BOOKMARKS) { xerror("%s\n", _("bookmarks: Cannot add any more bookmarks")); return FUNC_FAILURE; } char *p = unescape_str(cmd[0], 0); if (!p) { xerror(_("bookmarks: '%s': Error unescaping filename\n"), cmd[0]); return FUNC_FAILURE; } if (access(p, F_OK) != 0) { xerror("bookmarks: '%s': %s\n", p, strerror(errno)); free(p); return FUNC_FAILURE; } int ret = bookmark_add(p, cmd[1], cmd[2]); free(p); return ret; } /* Go through the list of bookmarks and set the first byte of the path of * matching bookmarks to NUL to mark it for deletion. * Used by del_bookmarks() to remove marked bookmarks. */ static size_t mark_bookmarks_for_deletion(char **args, int *exit_status) { *exit_status = FUNC_SUCCESS; size_t i, counter = 0; for (i = 0; args[i]; i++) { char *p = unescape_str(args[i], 0); char *name = p ? p : args[i]; int index = -1; if ( ((index = check_bm_name(name, 0)) != -1 || (index = check_bm_shortcut(name, 0)) != -1) && *bookmarks[index].path) { *bookmarks[index].path = '\0'; printf("'%s'\n", name); counter++; } else { xerror(_("'%s': No such bookmark\n"), name); *exit_status = FUNC_FAILURE; } free(p); } return counter; } /* Extract name and shortcut from the bookmark line LINE and store it in a * bookmarks_t struct. */ static struct bookmarks_t extract_shortcut_and_name(char *line) { struct bookmarks_t bm = {0}; if (!line || !*line) return bm; if (*line == '[') { bm.shortcut = strbtw(line, '[', ']'); bm.name = strbtw(line, ']', ':'); } else { char *p = strchr(line, ':'); if (p) { *p = '\0'; bm.name = savestring(line, strlen(line)); *p = ':'; } } return bm; } /* Return 0 if the bookmarks line LINE contains a bookmark marked for deletion, * in which case del_bookmarks() will remove the line from the bookmarks file. * Otherwise, 1 is returned. */ static int keep_bm_line(char *line) { char *p = (char *)NULL; if (*line == '#' || *line == '\n' || !(p = strchr(line, '/'))) return 1; *p = '\0'; struct bookmarks_t bm = extract_shortcut_and_name(line); int keep = 1; size_t i; for (i = 0; i < bm_n; i++) { if (!bookmarks[i].path || *bookmarks[i].path) /* Not marked for deletion */ continue; if ((bookmarks[i].shortcut && bm.shortcut && strcmp(bookmarks[i].shortcut, bm.shortcut) == 0) || (bookmarks[i].name && bm.name && strcmp(bookmarks[i].name, bm.name) == 0)) { keep = 0; break; } } *p = '/'; free(bm.name); free(bm.shortcut); return keep; } /* Delete bookmarks passed via ARGS. */ static int del_bookmarks(char **args) { if (!bookmarks || bm_n == 0) { puts(NO_BOOKMARKS); return FUNC_SUCCESS; } if (!args || !args[0]) { xerror("%s\n", BM_DEL_NO_PARAM); return FUNC_FAILURE; } char *rstr = gen_rand_str(RAND_SUFFIX_LEN); char tmp_file[PATH_MAX + 2 + RAND_SUFFIX_LEN]; snprintf(tmp_file, sizeof(tmp_file), "%s.%s", bm_file, rstr ? rstr : "gX6&55#0fa"); free(rstr); int fd = 0; FILE *fp = open_fread(bm_file, &fd); if (!fp) { xerror(_("'%s': %s\nbookmarks: Error reading the bookmarks file\n"), bm_file, strerror(errno)); return errno; } int tmp_fd = 0; FILE *tmp_fp = open_fwrite(tmp_file, &tmp_fd); if (!tmp_fp) { const int saved_errno = errno; xerror(_("'%s': %s\nbookmarks: Error creating temporary file\n"), tmp_file, strerror(errno)); fclose(fp); return saved_errno; } int exit_status = FUNC_SUCCESS; const size_t n = mark_bookmarks_for_deletion(args, &exit_status); if (n == 0) { fclose(fp); fclose(tmp_fp); unlink(tmp_file); return exit_status; } size_t removed = 0; char *line = (char *)NULL; size_t line_size = 0; while (getline(&line, &line_size, fp) > 0) { if (keep_bm_line(line) == 1) fprintf(tmp_fp, "%s", line); else removed++; } free(line); fclose(fp); fclose(tmp_fp); if (removed > 0) { if (rename(tmp_file, bm_file) == 0) { print_reload_msg(SET_SUCCESS_PTR, xs_cb, _("Removed %zu bookmark(s)\n"), removed); } else { xerror(_("bookmarks: Error updating bookmarks\nCannot rename " "temporary file '%s': %s\n"), tmp_file, strerror(errno)); return errno; } } else { unlink(tmp_file); } reload_bookmarks(); return exit_status; } /* Handle bookmarks: run the corresponding function according to CMD. */ int bookmarks_function(char **cmd) { if (xargs.stealth_mode == 1) { printf("%s: bookamrks: %s\n", PROGRAM_NAME, STEALTH_DISABLED); return FUNC_SUCCESS; } if (config_ok == 0) { xerror(_("%s: Bookmarks function disabled\n"), PROGRAM_NAME); return FUNC_FAILURE; } if (!cmd[1]) /* No arguments: load the bookmarks screen. */ return open_bookmark(); if (*cmd[1] == 'a' && (!cmd[1][1] || strcmp(cmd[1], "add") == 0)) return add_bookmark(cmd + 2); if (*cmd[1] == 'd' && (!cmd[1][1] || strcmp(cmd[1], "del") == 0)) return del_bookmarks(cmd + 2); if (*cmd[1] == 'e' && (!cmd[1][1] || strcmp(cmd[1], "edit") == 0)) return edit_bookmarks(cmd[2], NO_BM_SCREEN); if (*cmd[1] == 'r' && (!cmd[1][1] || strcmp(cmd[1], "reload") == 0)) { reload_bookmarks(); return FUNC_SUCCESS; } /* Shortcut or bm name: open it. */ return bm_open(cmd); } clifm-1.26.3/src/bookmarks.h000066400000000000000000000031441506632037700156400ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* bookmarks.h */ #ifndef BOOKMARKS_H #define BOOKMARKS_H #define NO_BOOKMARKS "bookmarks: No bookmarks\nUse 'bm add dir/ name' \ to create a bookmark\nTry 'bm --help' for more information" #define BM_ADD_NO_PARAM "bookmarks: A file and a name are required\n\ Example: 'bm add dir/ name'\nTry 'bm --help' for more information" #define BM_DEL_NO_PARAM "bookmarks: A name is required\n\ Example: 'bm del name'\nTry 'bm --help' for more information" #define PRINT_BM_HEADER 1 #define NO_BM_HEADER 0 #define BM_SCREEN 1 /* The edit function is called from the bookmarks screen */ #define NO_BM_SCREEN 0 __BEGIN_DECLS int bookmarks_function(char **cmd); int open_bookmark(void); void free_bookmarks(void); __END_DECLS #endif /* BOOKMARKS_H */ clifm-1.26.3/src/builtins.h000066400000000000000000000144121506632037700155010ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* builtins.h - Built-in commands for several shells */ /* A list of different shells builtins to be recognized as valid command * names. Only useful for the warning prompt */ #ifndef BUILTINS_H #define BUILTINS_H /* Bash */ char *bash_builtins[] = { "{", "case", "continue", "do", "done", "elif", "else", "esac", "fi", "for", "if", "in", "return", "then", "until", "while", "[", "[[", "bg", "bind", "break", "builtin", "caller", "command", "compgen", "compopt", "complete", "contrinue", "coproc", "declare", "dirs", "disown", "echo", "enable", "eval", "exec", "false", "fg", "function", "getopts", "hash", "help", "jobs", "kill", "let", "local", "logout", "mapfile", "popd", "printf", "pushd", "read", "readarray", "readonly", "select", "set", "shift", "shopt", "source", "suspend", "test", "time", "trap", "true", "type", "typeset", "ulimit", "unalias", "unset", "variables", "wait", NULL }; /* Dash */ char *dash_builtins[] = { "case", "continue", "do", "done", "elif", "else", "esac", "fi", "for", "if", "in", "return", "then", "until", "while", "bg", "command", "echo", "eval", "exec", "fg", "getopts", "hash", "read", "readonly", "printf", "set", "shift", "test", "times", "trap", "type", "ulimit", "unalias", "unset", "wait", NULL }; /* Fish */ char *fish_builtins[] = { "{", "case", "continue", "do", "done", "elif", "else", "esac", "fi", "for", "if", "in", "return", "then", "until", "while", "_", "abbr", "and", "argparse", "begin", "bg", "bind", "block", "break", "breakpoint", "builtin", "case", "cdh", "command", "commandline", "complete", "contains", "count", "dirh", "dirs", "disown", "echo", "emit", "end", "eval", "exec", "false", "fg", "fish_add_path", "fish_breakpoint_prompt", "fish_command_not_found", "fish_config", "fish_git_prompt", "fish_greeting", "fish_hg_prompt", "fish_indent", "fish_is_root_user", "fish_key_reader", "fish_mode_prompt", "fish_opt", "fish_prompt", "fish_right_prompt", "fish_status_to_signal", "fish_svn_prompt", "fish_title", "fish_update_completions", "fish_vcs_prompt", "funced", "funcsave", "function", "functions", "isatty", "jobs", "math", "nextd", "not", "open", "or", "popd", "prevd", "printf", "prompt_login", "prompt_pwd", "psub", "pushd", "random", "read", "realpath", "set", "set_color", "source", "status", "string", "string-collect", "string-escape", "string-join", "string-join0", "string-length", "string-lower", "string-match", "string-pad", "string-repeat", "string-replace", "string-split", "string-split0", "string-sub", "string-trim", "string-unescape", "string-upper", "suspend", "switch", "test", "time", "trap", "true", "type", "ulimit", "vared", "wait", NULL }; /* KSH */ char *ksh_builtins[] = { "{", "case", "continue", "do", "done", "elif", "else", "esac", "fi", "for", "if", "in", "return", "then", "until", "while", "bg", "break", "builtin", "command", "disown", "echo", "enum", "eval", "exec", "false", "fg", "getopts", "hist", "jobs", "kill", "let", "newgrp", "print", "printf", "read", "readonly", "set", "shift", "sleep", "times", "trap", "true", "typeset", "ulimit", "unalias", "unset", "wait", "whence", NULL }; /* TCSH */ char *tcsh_builtins[] = { "{", "case", "continue", "do", "done", "elif", "else", "esac", "fi", "for", "if", "in", "return", "then", "until", "while", "alloc", "bg", "bindkey", "bs2cmd", "breaksw", "builtins", "chdir", "complete", "dirs", "echo", "echotc", "endsw", "exec", "fg", "filetest", "foreach", "end", "getspath", "getxvers", "glob", "goto", "hashstat", "hup", "inlib", "jobs", "kill", "limit", "log", "ls-F", "migrate", "newgrp", "nice", "nohup", "notify", "onintr", "popd", "printenv", "pushd", "rehash", "repeat", "rootnode", "sched", "set", "setenv", "setpath", "setspath", "settc", "setty", "setxvers", "shift", "source", "stop", "suspend", "telltc", "termname", "time", "unalias", "uncomplete", "unhash", "universe", "unlimit", "unset", "unsetenv", "ver", "wait", "warp", "watchlog", "where", "which", NULL }; /* ZSH */ char *zsh_builtins[] = { "{", "case", "continue", "do", "done", "elif", "else", "esac", "fi", "for", "if", "in", "return", "then", "until", "while", "autoload", "bg", "bindkey", "break", "builtin", "chdir", "clone", "command", "comparguments", "compcall", "compctl", "compdescribe", "compfiles", "compgroups", "compquote", "comptags", "comptry", "compvalues", "declare", "dirs", "disable", "disown", "echo", "echotc", "echoti", "emulate", "enable", "eval", "exec", "false", "fg", "float", "functions", "getcap", "getln", "getopts", "hash", "integer", "jobs", "kill", "let", "limit", "local", "log", "logout", "noglob", "popd", "print", "printf", "pushd", "pushln", "read", "readonly", "rehash", "sched", "set", "setcap", "setopt", "shift", "source", "stat", "suspend", "test", "times", "trap", "true", "ttyctl", "type", "typeset", "ulimit", "unalias", "unfunction", "unhash", "unlimit", "unset", "unsetopt", "vared", "wait", "whence", "where", "which", "zcompile", "zformat", "zftp", "zle", "zmodload", "zparseopts", "zprof", "zpty", "zregexparse", "zsocket", "zstyle", "ztcp", NULL }; #endif /* BUILTINS_H */ clifm-1.26.3/src/bulk_remove.c000066400000000000000000000265051506632037700161630ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* bulk_remove.c -- bulk remove files */ #include "helpers.h" #include /* scandir() */ #include /* strnlen() */ #include /* (l)stat() */ #include /* unlinkat() */ #include /* unlinkat() */ #include #include "aux.h" /* xnmalloc, open_fwrite(), is_cmd_in_path(), count_dir() */ #include "file_operations.h" // open_file() */ #include "messages.h" /* RR_USAGE */ #include "misc.h" /* xerror() */ #include "spawn.h" /* launch_execv() */ #define BULK_RM_TMP_FILE_HEADER "# Clifm - Remove files in bulk\n\ # Remove the filenames you want to be deleted, save, and quit the\n\ # editor (you will be asked for confirmation).\n\ # Quit the editor without saving to cancel the operation.\n\n" #define IS_RR_COMMENT(s) (*(s) == '#' && (s)[1] == ' ') #define BULK_APP(s) ((*(s) == ':' && (s)[1]) ? (s) + 1 : (s)) static int parse_bulk_remove_params(char *s1, char *s2, char **app, char **target) { if (!s1 || !*s1) { /* No parameters */ /* TARGET defaults to CWD and APP to default associated app */ *target = workspaces[cur_ws].path; return FUNC_SUCCESS; } int ret = 0; struct stat a; if ((ret = stat(s1, &a)) == -1 || !S_ISDIR(a.st_mode)) { if (is_cmd_in_path(BULK_APP(s1)) == 0) { /* S1 is neither a directory nor a valid application */ int ec = (ret == -1 && *s1 == ':') ? E_NOTFOUND : ENOTDIR; if (ec == ENOTDIR) xerror("rr: '%s': %s\n", s1, strerror(ec)); else xerror("rr: '%s': %s\n", BULK_APP(s1), NOTFOUND_MSG); return ec; } /* S1 is an application name. TARGET defaults to CWD */ *target = workspaces[cur_ws].path; *app = BULK_APP(s1); return FUNC_SUCCESS; } /* S1 is a valid directory */ size_t tlen = strlen(s1); if (tlen > 2 && s1[tlen - 1] == '/') s1[tlen - 1] = '\0'; *target = s1; if (!s2 || !*s2) /* No S2. APP defaults to default associated app */ return FUNC_SUCCESS; if (is_cmd_in_path(BULK_APP(s2)) == 1) { /* S2 is a valid application name */ *app = BULK_APP(s2); return FUNC_SUCCESS; } /* S2 is not a valid application name */ xerror("rr: '%s': %s\n", BULK_APP(s2), NOTFOUND_MSG); return E_NOTFOUND; } static int create_tmp_file(char **file, int *fd, struct stat *attr) { size_t tmp_len = strlen(xargs.stealth_mode == 1 ? P_tmpdir : tmp_dir); size_t file_len = tmp_len + (sizeof(TMP_FILENAME) - 1) + 2; *file = xnmalloc(file_len, sizeof(char)); snprintf(*file, file_len, "%s/%s", xargs.stealth_mode == 1 ? P_tmpdir : tmp_dir, TMP_FILENAME); *fd = mkstemp(*file); if (*fd == -1) { xerror("rr: mkstemp: '%s': %s\n", *file, strerror(errno)); free(*file); return FUNC_FAILURE; } if (fstat(*fd, attr) == -1) { xerror("rr: fstat: '%s': %s\n", *file, strerror(errno)); unlinkat(*fd, *file, 0); close(*fd); free(*file); return FUNC_FAILURE; } return FUNC_SUCCESS; } static char get_file_suffix(const mode_t type) { switch (type) { case DT_DIR: return DIR_CHR; case DT_REG: return 0; case DT_LNK: return LINK_CHR; case DT_SOCK: return SOCK_CHR; case DT_FIFO: return FIFO_CHR; #ifdef SOLARIS_DOORS case DT_DOOR: return DOOR_CHR; // case DT_PORT: return 0; #endif /* SOLARIS_DOORS */ #ifdef S_IFWHT case DT_WHT: return WHT_CHR; #endif /* S_IFWHT */ case DT_UNKNOWN: return UNKNOWN_CHR; default: return 0; } } static void write_name(FILE *fp, const char *name, const mode_t type) { #ifndef _DIRENT_HAVE_D_TYPE UNUSED(type); char s = 0; struct stat a; if (lstat(name, &a) != -1) s = get_file_suffix(a.st_mode); #else char s = get_file_suffix(type); #endif /* !_DIRENT_HAVE_D_TYPE */ if (s) fprintf(fp, "%s%c\n", name, s); else fprintf(fp, "%s\n", name); } static int write_files_to_tmp(struct dirent ***a, filesn_t *n, const char *target, char *tmpfile) { int fd = 0; FILE *fp = open_fwrite(tmpfile, &fd); if (!fp) { err('e', PRINT_PROMPT, "rr: fopen: '%s': %s\n", tmpfile, strerror(errno)); return errno; } fprintf(fp, "%s", _(BULK_RM_TMP_FILE_HEADER)); if (target == workspaces[cur_ws].path) { if (files == 0) goto EMPTY_DIR; filesn_t i; for (i = 0; i < files; i++) write_name(fp, file_info[i].name, file_info[i].type); } else { if (count_dir(target, CPOP) <= 2) goto EMPTY_DIR; *n = scandir(target, a, NULL, alphasort); if (*n == -1) { int tmp_err = errno; xerror("rr: '%s': %s", target, strerror(errno)); fclose(fp); return tmp_err; } filesn_t i; for (i = 0; i < *n; i++) { if (SELFORPARENT((*a)[i]->d_name)) continue; #ifndef _DIRENT_HAVE_D_TYPE write_name(fp, (*a)[i]->d_name, 0); #else write_name(fp, (*a)[i]->d_name, (*a)[i]->d_type); #endif /* !_DIRENT_HAVE_D_TYPE */ } } fclose(fp); return FUNC_SUCCESS; EMPTY_DIR: xerror(_("rr: '%s': Directory empty\n"), target); fclose(fp); return FUNC_FAILURE; } static int open_tmp_file(struct dirent ***a, const filesn_t n, char *tmpfile, char *app) { int exit_status = FUNC_SUCCESS; filesn_t i; if (!app || !*app) { open_in_foreground = 1; exit_status = open_file(tmpfile); open_in_foreground = 0; if (exit_status == FUNC_SUCCESS) return FUNC_SUCCESS; xerror(_("rr: '%s': Cannot open file\n"), tmpfile); goto END; } char *cmd[] = {app, tmpfile, NULL}; exit_status = launch_execv(cmd, FOREGROUND, E_NOFLAG); if (exit_status == FUNC_SUCCESS) return FUNC_SUCCESS; END: for (i = 0; i < n && *a && (*a)[i]; i++) free((*a)[i]); free(*a); return exit_status; } static char ** get_files_from_tmp_file(const char *tmpfile, const char *target, const filesn_t n) { size_t nfiles = (target == workspaces[cur_ws].path) ? (size_t)files : (size_t)n; char **tmp_files = xnmalloc(nfiles + 2, sizeof(char *)); FILE *fp = fopen(tmpfile, "r"); if (!fp) return (char **)NULL; size_t i = 0; char line[PATH_MAX + 1]; *line = '\0'; while (fgets(line, (int)sizeof(line), fp)) { if (!*line || IS_RR_COMMENT(line) || *line == '\n') continue; size_t len = strlen(line); if (line[len - 1] == '\n') { line[len - 1] = '\0'; len--; } if (len > 0 && (line[len - 1] == '/' || line[len - 1] == '@' || line[len - 1] == '=' || line[len - 1] == '|' || line[len - 1] == '?') ) { line[len - 1] = '\0'; len--; } tmp_files[i] = savestring(line, len); i++; } tmp_files[i] = (char *)NULL; fclose(fp); return tmp_files; } /* If FILE is not found in LIST, returns one; zero otherwise. */ static int remove_this_file(char *file, char **list) { if (SELFORPARENT(file)) return 0; size_t i; for (i = 0; list[i]; i++) { if (*file == *list[i] && strcmp(file, list[i]) == 0) return 0; } return 1; } static char ** get_remove_files(const char *target, char **tmp_files, struct dirent ***a, const filesn_t n) { size_t i, j = 1; size_t l = (target == workspaces[cur_ws].path) ? (size_t)files : (size_t)n; char **rem_files = xnmalloc(l + 3, sizeof(char *)); rem_files[0] = savestring("rr", 2); if (target == workspaces[cur_ws].path) { for (i = 0; i < (size_t)files; i++) { if (remove_this_file(file_info[i].name, tmp_files) == 1) { rem_files[j] = savestring(file_info[i].name, strlen(file_info[i].name)); j++; } } rem_files[j] = (char *)NULL; return rem_files; } for (i = 0; i < (size_t)n; i++) { if (remove_this_file((*a)[i]->d_name, tmp_files) == 1) { char p[PATH_MAX + NAME_MAX + 3]; if (*target == '/') { snprintf(p, sizeof(p), "%s/%s", target, (*a)[i]->d_name); } else { snprintf(p, sizeof(p), "%s/%s/%s", workspaces[cur_ws].path, target, (*a)[i]->d_name); } rem_files[j] = savestring(p, strnlen(p, sizeof(p))); j++; } free((*a)[i]); } free(*a); rem_files[j] = (char *)NULL; return rem_files; } static int diff_files(char *tmp_file, const filesn_t n) { FILE *fp = fopen(tmp_file, "r"); if (!fp) { xerror("br: '%s': %s\n", tmp_file, strerror(errno)); return 0; } char line[PATH_MAX + 6]; *line = '\0'; filesn_t c = 0; while (fgets(line, (int)sizeof(line), fp)) { if (*line != '\0' && *line != '#' && *line != '\n') c++; } fclose(fp); return (c < n ? 1 : 0); } static void free_dirent(struct dirent ***a, const filesn_t n) { filesn_t i = n; while (--i >= 0) free((*a)[i]); free(*a); } static int nothing_to_do(char **tmp_file, struct dirent ***a, const filesn_t n, const int fd) { puts(_("rr: Nothing to do")); if (unlink(*tmp_file) == 1) xerror("rr: unlink: '%s': %s\n", *tmp_file, strerror(errno)); close(fd); free(*tmp_file); free_dirent(a, n); return FUNC_SUCCESS; } int bulk_remove(char *s1, char *s2) { if (virtual_dir == 1) { xerror(_("%s: rr: Feature not allowed in virtual " "directories\n"), PROGRAM_NAME); return FUNC_SUCCESS; } if (s1 && IS_HELP(s1)) { puts(_(RR_USAGE)); return FUNC_SUCCESS; } char *app = (char *)NULL; char *target = (char *)NULL; int fd = 0, ret = 0, i = 0; filesn_t n = 0; char dpath[PATH_MAX + 1]; *dpath = '\0'; if (s1 && *s1 && *s1 != ':' && strchr(s1, '\\')) { char *tmp = unescape_str(s1, 0); if (tmp) { xstrsncpy(dpath, tmp, sizeof(dpath)); free(tmp); } } ret = parse_bulk_remove_params(*dpath ? dpath : s1, s2, &app, &target); if (ret != FUNC_SUCCESS) return ret; struct stat attr; char *tmp_file = (char *)NULL; if ((ret = create_tmp_file(&tmp_file, &fd, &attr)) != FUNC_SUCCESS) return ret; const time_t old_mtime = attr.st_mtime; const ino_t old_ino = attr.st_ino; const dev_t old_dev = attr.st_dev; struct dirent **a = (struct dirent **)NULL; if ((ret = write_files_to_tmp(&a, &n, target, tmp_file)) != FUNC_SUCCESS) goto END; if ((ret = open_tmp_file(&a, n, tmp_file, app)) != FUNC_SUCCESS) goto END; /* Make sure the tmp file we're about to read is the same as the one * we originally created. */ if (lstat(tmp_file, &attr) == -1 || !S_ISREG(attr.st_mode) || attr.st_ino != old_ino || attr.st_dev != old_dev) { ret = FUNC_FAILURE; xerror("%s\n", _("rr: Temporary file changed on disk! Aborting.")); free_dirent(&a, n); goto END; } const filesn_t num = (target == workspaces[cur_ws].path) ? files : n - 2; if (old_mtime == attr.st_mtime || diff_files(tmp_file, num) == 0) return nothing_to_do(&tmp_file, &a, n, fd); char **rfiles = get_files_from_tmp_file(tmp_file, target, n); if (!rfiles) goto END; char **rem_files = get_remove_files(target, rfiles, &a, n); if (!rem_files) goto FREE_N_EXIT; ret = remove_files(rem_files); for (i = 0; rem_files[i]; i++) free(rem_files[i]); free(rem_files); FREE_N_EXIT: for (i = 0; rfiles[i]; i++) free(rfiles[i]); free(rfiles); END: if (unlinkat(fd, tmp_file, 0) == -1) { err('w', PRINT_PROMPT, "rr: unlink: '%s': %s\n", tmp_file, strerror(errno)); } close(fd); free(tmp_file); return ret; } clifm-1.26.3/src/bulk_remove.h000066400000000000000000000020121506632037700161530ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* bulk_remove.h */ #ifndef BULK_REMOVE_H #define BULK_REMOVE_H __BEGIN_DECLS int bulk_remove(char *s1, char *s2); __END_DECLS #endif /* BULK_REMOVE_H */ clifm-1.26.3/src/bulk_rename.c000066400000000000000000000312031506632037700161240ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* bulk_rename.c -- bulk rename files */ /* The run_action function is taken from NNN's run_selected_plugin function * (https://github.com/jarun/nnn/blob/master/src/nnn.c), licensed under BSD-2-Clause. * All changes are licensed under GPL-2.0-or-later. */ #include "helpers.h" #include #include #include #include #include #if defined(MAC_OS_X_RENAMEAT_SYS_STDIO_H) # include /* renameat(2) */ #endif /* MAC_OS_X_RENAMEAT_SYS_STDIO_H */ #include "aux.h" /* press_any_key_to_continue(), abbreviate_file_name(), open_fread() */ #include "checks.h" /* is_file_in_cwd() */ #include "file_operations.h" /* open_file() */ #include "init.h" /* get_sel_files() */ #include "listing.h" /* reload_dirlist() */ #include "messages.h" /* BULK_RENAME_USAGE */ #include "misc.h" /* xerror(), print_reload_msg() */ #include "readline.h" /* rl_get_y_or_n() */ #include "spawn.h" /* launch_execv() */ #define BULK_RENAME_TMP_FILE_HEADER "# Clifm - Rename files in bulk\n\ # Edit filenames, save, and quit the editor (you will be\n\ # asked for confirmation).\n\ # Quit the editor without saving to cancel the operation.\n\n" #define IS_BR_COMMENT(l) (*(l) == '#' && (l)[1] == ' ') /* Error opening tmp file FILE. Err accordingly. */ static int err_open_tmp_file(const char *file, const int fd) { xerror("br: open: '%s': %s\n", file, strerror(errno)); if (unlinkat(fd, file, 0) == -1) xerror("br: unlink: '%s': %s\n", file, strerror(errno)); close(fd); return FUNC_FAILURE; } /* Rename OLDPATH as NEWPATH. * NEWPATH is checked for existence before renaming, in which case the user * is asked for confirmation. */ static int rename_file(char *oldpath, char *newpath) { /* Some renameat(2) implementations (DragonFly) do not like NEWPATH to * end with a slash (in case of renaming directories). */ size_t nlen = strlen(newpath); if (nlen > 1 && newpath[nlen - 1] == '/') { nlen--; newpath[nlen] = '\0'; } char *npath = normalize_path(newpath, nlen); if (!npath || !*npath) { free(npath); xerror(_("br: '%s': Error normalizing path\n"), newpath); return FUNC_FAILURE; } struct stat a; if (lstat(npath, &a) == 0) { xerror("br: '%s': %s\n", newpath, strerror(EEXIST)); if (rl_get_y_or_n(_("Overwrite this file?"), conf.default_answer.overwrite) == 0) { free(npath); return EEXIST; } } if (renameat(XAT_FDCWD, oldpath, XAT_FDCWD, npath) == 0) { free(npath); return 0; } if (errno != EXDEV) { xerror(_("br: Cannot rename '%s' to '%s': %s\n"), oldpath, newpath, strerror(errno)); free(npath); return errno; } char *cmd[] = {"mv", "--", oldpath, npath, NULL}; const int ret = launch_execv(cmd, FOREGROUND, E_NOFLAG); free(npath); return ret; } /* Write filenames in ARGS into the temporary file TMPFILE, whose file * descriptor is FD. Update WRITTEN to the number of actually written * filenames, and make ATTR hold the stat attributes of the temporary * file after writing into it all filenames. */ static int write_files_to_tmp(char ***args, const char *tmpfile, const int fd, struct stat *attr, size_t *written) { size_t i; FILE *fp = fdopen(fd, "w"); if (!fp) return err_open_tmp_file(tmpfile, fd); fprintf(fp, BULK_RENAME_TMP_FILE_HEADER); /* Copy all files to be renamed into the bulk file */ for (i = 1; (*args)[i]; i++) { /* Dequote filename, if necessary */ if (strchr((*args)[i], '\\')) { char *deq_file = unescape_str((*args)[i], 0); if (!deq_file) { xerror(_("br: '%s': Error unescaping filename\n"), (*args)[i]); press_any_key_to_continue(0); continue; } xstrsncpy((*args)[i], deq_file, strlen(deq_file) + 1); free(deq_file); } /* Resolve "./" and "../" */ if (*(*args)[i] == '.' && ((*args)[i][1] == '/' || ((*args)[i][1] == '.' && (*args)[i][2] == '/') ) ) { char *p = normalize_path((*args)[i], strlen((*args)[i])); if (!p) { xerror(_("br: '%s': Error normalizing path\n"), (*args)[i]); press_any_key_to_continue(0); continue; } free((*args)[i]); (*args)[i] = p; } struct stat a; if (lstat((*args)[i], &a) == -1) { /* Last parameter may be opening app (:APP) */ if (i != args_n || *(*args)[i] != ':') { xerror("br: '%s': %s\n", (*args)[i], strerror(errno)); press_any_key_to_continue(0); } continue; } fprintf(fp, "%s\n", (*args)[i]); (*written)++; } if (*written == 0 || fstat(fd, attr) == -1) { if (unlinkat(fd, tmpfile, 0) == -1) xerror("br: unlink: '%s': %s\n", tmpfile, strerror(errno)); fclose(fp); return FUNC_FAILURE; } fclose(fp); return FUNC_SUCCESS; } static size_t print_and_count_modified_names(char **args, char **new_names) { size_t modified = 0; size_t i; /* Print what would be done */ for (i = 0; new_names[i]; i++) { if (args[i] && strcmp(args[i], new_names[i]) != 0) { char *a = abbreviate_file_name(args[i]); char *b = abbreviate_file_name(new_names[i]); printf("%s %s%s%s %s\n", a ? a : args[i], mi_c, SET_MSG_PTR, df_c, b ? b : new_names[i]); if (a && a != args[i]) free(a); if (b && b != new_names[i]) free(b); modified++; } } if (modified == 0) puts(_("br: Nothing to do")); return modified; } /* Open FILE via APP (default associated application for text files if * omitted). */ static int open_tmpfile(char *app, char *file) { char *application = (char *)NULL; struct stat a; if (app && *app == ':' && app[1] && lstat(app, &a) == -1) application = app + 1; if (application) { char *cmd[] = {application, file, NULL}; const int ret = launch_execv(cmd, FOREGROUND, E_NOFLAG); if (ret != FUNC_SUCCESS) unlink(file); return ret; } open_in_foreground = 1; const int exit_status = open_file(file); open_in_foreground = 0; if (exit_status != FUNC_SUCCESS) { xerror("br: %s\n", errno != 0 ? strerror(errno) : _("Error opening temporary file")); if (unlink(file) == -1) xerror("br: unlink: '%s': %s\n", file, strerror(errno)); return exit_status; } return FUNC_SUCCESS; } /* Rename files in OLD_NAMES to those in NEW_NAMES. */ static int rename_bulk_files(char **old_names, char **new_names, int *is_cwd, size_t *renamed, const size_t modified) { size_t i = 1; int exit_status = FUNC_SUCCESS; for (i = 0; new_names[i]; i++) { if (!old_names[i] || strcmp(old_names[i], new_names[i]) == 0) continue; const int ret = rename_file(old_names[i], new_names[i]); if (ret != 0) { if (ret != EEXIST) exit_status = ret; continue; } if (*is_cwd == 0 && (is_file_in_cwd(old_names[i]) || is_file_in_cwd(new_names[i]))) *is_cwd = 1; (*renamed)++; } if (conf.autols == 1 && exit_status != 0 && modified > 1) press_any_key_to_continue(0); return exit_status; } /* Extract destiny filenames from the file pointed to by FP. * * If the number of destiny filenames does not equal TOTAL (the number of * source filenames) NULL is returned. * * Destiny filenames are checked for duplicates. If one is found, and the user * decides not to continue, NULL is returned. * * Otherwise, an array containing destiny filenames is returned. * * STATUS is set to FUNC_FAILURE in case of error. */ char ** get_new_names(FILE *fp, const size_t total, int *status) { if (!fp) return (char **)NULL; char line[PATH_MAX + 1]; *line = '\0'; size_t n = 0, i = 0; while (fgets(line, (int)sizeof(line), fp)) { if (!*line || *line == '\n' || IS_BR_COMMENT(line)) continue; n++; } fseek(fp, 0L, SEEK_SET); char **fnames = xnmalloc(n + 1, sizeof(char *)); while (fgets(line, (int)sizeof(line), fp)) { if (!*line || *line == '\n' || IS_BR_COMMENT(line)) continue; size_t len = strlen(line); if (line[len - 1] == '\n') { len--; line[len] = '\0'; } fnames[i] = savestring(line, len); i++; } fnames[i] = (char *)NULL; if (i == 0) goto FREE_AND_EXIT; /* Check line mismatch */ if (i != total) { xerror("%s\n", _("br: Line mismatch in temporary file")); *status = FUNC_FAILURE; goto FREE_AND_EXIT; } /* Check for duplicate entries */ size_t dups = 0; for (i = 0; fnames[i]; i++) { for (n = i + 1; fnames[n]; n++) { if (strcmp(fnames[i], fnames[n]) == 0) { dups++; xerror(_("br: '%s' is duplicated\n"), fnames[i]); } } } if (dups > 0 && rl_get_y_or_n(_("Continue?"), conf.default_answer.overwrite) == 0) goto FREE_AND_EXIT; return fnames; FREE_AND_EXIT: for (i = 0; fnames[i]; i++) free(fnames[i]); free(fnames); return (char **)NULL; } static void unlink_and_close_tmpfile(const int fd, FILE *fp, const char *tmpfile, int *status) { if (unlinkat(fd, tmpfile, 0) == -1) { *status = errno; err('w', PRINT_PROMPT, "br: unlink: '%s': %s\n", tmpfile, strerror(errno)); } fclose(fp); } /* Rename a bulk of files (ARGS) at once. * Takes files to be renamed as arguments, and returns zero on success or one * on error. * * RENAMED is updated to the number of renamed files. * If reload_list is set to 1, the list of files is reloaded and a summary * message is displayed. * * The procedure is simple: filenames to be renamed are copied to a * temporary file, which is opened via the mime function and shown to * the user to modify it. Once the filenames have been modified and saved, * modifications are printed on the screen and the user is asked for * confirmation. */ int bulk_rename(char **args, size_t *renamed, const size_t reload_list) { *renamed = 0; if (virtual_dir == 1) { xerror(_("%s: br: Feature not allowed in virtual " "directories\n"), PROGRAM_NAME); return FUNC_SUCCESS; } if (!args || !args[1] || IS_HELP(args[1])) { puts(_(BULK_RENAME_USAGE)); return FUNC_SUCCESS; } int exit_status = FUNC_SUCCESS; struct stat attra; /* Original temp file. */ struct stat attrb; /* Edited temp file. */ char tmpfile[PATH_MAX + 1]; snprintf(tmpfile, sizeof(tmpfile), "%s/%s", xargs.stealth_mode == 1 ? P_tmpdir : tmp_dir, TMP_FILENAME); int fd = mkstemp(tmpfile); if (fd == -1) { xerror("br: mkstemp: '%s': %s\n", tmpfile, strerror(errno)); return FUNC_FAILURE; } /* Write files to be renamed into a tmp file and store stat info in attra. */ size_t written = 0; int ret = write_files_to_tmp(&args, tmpfile, fd, &attra, &written); if (ret != FUNC_SUCCESS) return ret; /* Open the tmp file with the associated text editor. */ if ((ret = open_tmpfile(args[args_n], tmpfile)) != FUNC_SUCCESS) return ret; FILE *fp; if (!(fp = open_fread(tmpfile, &fd))) return err_open_tmp_file(tmpfile, fd); /* Compare the new modification time to the stored one: if they * match, nothing was modified. */ if (fstat(fd, &attrb) == -1) { xerror("br: '%s': %s\n", tmpfile, strerror(errno)); goto CLOSE_AND_EXIT; } if (attra.st_mtime == attrb.st_mtime) { puts(_("br: Nothing to do")); goto CLOSE_AND_EXIT; } /* Load destiny names, checking for line mismatch and duplicates. */ char **new_names = get_new_names(fp, written, &exit_status); unlink_and_close_tmpfile(fd, fp, tmpfile, &exit_status); if (!new_names) return exit_status; char **old_names = args + 1; const size_t modified = print_and_count_modified_names(old_names, new_names); if (modified == 0) goto FREE_AND_EXIT; /* Ask the user for confirmation. */ if (rl_get_y_or_n(_("Continue?"), conf.default_answer.bulk_rename) == 0) goto FREE_AND_EXIT; int is_cwd = 0; if ((ret = rename_bulk_files(old_names, new_names, &is_cwd, renamed, modified)) != FUNC_SUCCESS) exit_status = ret; if (sel_n > 0 && cwd_has_sel_files()) /* Just in case a selected file in the current dir was renamed. */ get_sel_files(); if (reload_list == 1) { if (*renamed > 0 && is_cwd == 1 && conf.autols == 1) reload_dirlist(); print_reload_msg(SET_SUCCESS_PTR, xs_cb, _("%zu file(s) renamed\n"), *renamed); } FREE_AND_EXIT: for (size_t i = 0; new_names[i]; i++) free(new_names[i]); free(new_names); return exit_status; CLOSE_AND_EXIT: unlink_and_close_tmpfile(fd, fp, tmpfile, &exit_status); return exit_status; } clifm-1.26.3/src/bulk_rename.h000066400000000000000000000020561506632037700161350ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* bulk_rename.h */ #ifndef BULK_RENAME_H #define BULK_RENAME_H __BEGIN_DECLS int bulk_rename(char **args, size_t *renamed, const size_t reload_list); __END_DECLS #endif /* BULK_RENAME_H */ clifm-1.26.3/src/checks.c000066400000000000000000000416751506632037700151160ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* checks.c -- misc check functions */ #include "helpers.h" #include #include #include #if defined(MAC_OS_X_RENAMEAT_SYS_STDIO_H) # include /* renameat(2) */ #endif /* MAC_OS_X_RENAMEAT_SYS_STDIO_H */ #if defined(HAVE_FILE_ATTRS) # ifdef __TINYC__ # undef SYNC_FILE_RANGE_WRITE_AND_WAIT /* Silence redefinition error */ # endif #endif /* HAVE_FILE_ATTRS */ #include "aux.h" #include "misc.h" #include "sanitize.h" /* sanitize_cmd() */ /* Check whether parameter S is -f or --force. * Returns 1 if yes, and there is no "-f" or "--force" file in the current * dir, or 0 otherwise. */ int is_force_param(const char *s) { if (!s || !*s || *s != '-') return 0; struct stat a; if ((strcmp(s, "-f") == 0 && lstat("-f", &a) == -1) || (strcmp(s, "--force") == 0 && lstat("--force", &a) == -1)) return 1; return 0; } int check_glob_char(const char *str, const int gflag) { if (!str || !*str) return 0; return strpbrk(str, (gflag == GLOB_ONLY) ? GLOB_CHARS : GLOB_REGEX_CHARS) ? 1 : 0; } int is_file_in_cwd(char *name) { if (!name || !*name || !workspaces[cur_ws].path) return 0; const char *s = strchr(name, '/'); if (!s || !s[1]) /* 'name' or 'name/' */ return 1; char *rpath = normalize_path(name, strlen(name)); if (!rpath) return 0; const char *cwd = workspaces[cur_ws].path; const size_t cwd_len = strlen(cwd); const size_t rpath_len = strlen(rpath); if (rpath_len < cwd_len || strncmp(rpath, cwd, cwd_len) != 0 || (rpath_len > cwd_len && strchr(rpath + cwd_len + 1, '/'))) { free(rpath); return 0; } free(rpath); return 1; } int is_url(const char *url) { if ((*url == 'w' && url[1] == 'w' && url[2] == 'w' && url[3] == '.' && url[4]) || strstr(url, "://") != NULL) return FUNC_SUCCESS; return FUNC_FAILURE; } static void set_mount_cmd(const int udisks2ok, const int udevilok) { if (xargs.mount_cmd == MNT_UDISKS2 && !udisks2ok && udevilok) { err('w', PRINT_PROMPT, _("%s: udisks2: Command not found. Falling " "back to 'udevil'.\n"), PROGRAM_NAME); xargs.mount_cmd = MNT_UDEVIL; return; } if (xargs.mount_cmd != MNT_UDISKS2 && udevilok) xargs.mount_cmd = MNT_UDEVIL; else if (udisks2ok) xargs.mount_cmd = MNT_UDISKS2; else xargs.mount_cmd = UNSET; } #ifndef _NO_FZF static const char * tabmode_to_name(void) { switch (tabmode) { case FZF_TAB: return "fzf"; case FNF_TAB: return "fnf"; case SMENU_TAB: return "smenu"; case STD_TAB: /* fallthrough */ default: return "standard"; } } /* Set tab completion mode based on available binaries. */ void check_completion_mode(void) { /* fzftab is zero only if running with --stdtab */ if (fzftab == 0) { tabmode = STD_TAB; fzftab = 0; return; } /* The user asked for a specific mode, but the binary wasn't found. */ char *err_name = (char *)NULL; if (!(bin_flags & FZF_BIN_OK) && tabmode == FZF_TAB) { err_name = "fzf"; tabmode = STD_TAB; } else if (!(bin_flags & FNF_BIN_OK) && tabmode == FNF_TAB) { err_name = "fnf"; tabmode = STD_TAB; } else if (!(bin_flags & SMENU_BIN_OK) && tabmode == SMENU_TAB) { err_name = "smenu"; tabmode = STD_TAB; } if (tabmode == STD_TAB) { /* If a suitable binary is found, let's run in the corresponding mode. */ if (bin_flags & FZF_BIN_OK) tabmode = FZF_TAB; else if (bin_flags & FNF_BIN_OK) tabmode = FNF_TAB; else if (bin_flags & SMENU_BIN_OK) tabmode = SMENU_TAB; else /* No binary found. Let's run in standard mode. */ fzftab = 0; } if (err_name) err('w', PRINT_PROMPT, _("%s: %s: Command not found. Falling back " "to '%s'.\n"), PROGRAM_NAME, err_name, tabmode_to_name()); } #endif /* !_NO_FZF */ /* Same thing as check_third_party_cmds(), but slower, since we need to run * malloc(3) and access(3) for each checked command. */ static void check_third_party_cmds_alt(void) { int udisks2ok = 0, udevilok = 0; if (is_cmd_in_path("fzf") == 1) { bin_flags |= FZF_BIN_OK; if (fzftab == UNSET) fzftab = 1; } if (is_cmd_in_path("fnf") == 1) { bin_flags |= FNF_BIN_OK; if (fzftab == UNSET) fzftab = 1; } if (is_cmd_in_path("smenu") == 1) { bin_flags |= SMENU_BIN_OK; if (fzftab == UNSET) fzftab = 1; } if (is_cmd_in_path("udiskctl") == 1) udisks2ok = 1; if (is_cmd_in_path("udevil") == 1) udevilok = 1; #if defined(USE_DU1) && !defined(HAVE_GNU_DU) && !defined(_BE_POSIX) if (is_cmd_in_path("gdu") == 1) bin_flags |= GNU_DU_BIN_GDU; #endif /* USE_DU1 && !HAVE_GNU_DU && !_BE_POSIX */ #if defined(CHECK_COREUTILS) if (is_cmd_in_path("grm") == 1) bin_flags |= BSD_HAVE_COREUTILS; #endif /* CHECK_COREUTILS */ set_mount_cmd(udisks2ok, udevilok); } /* Let's check for third-party programs */ void check_third_party_cmds(void) { #if defined(USE_DU1) && defined(HAVE_GNU_DU) bin_flags |= GNU_DU_BIN_DU; #endif /* USE_DU1 && HAVE_GNU_DU */ if (conf.ext_cmd_ok == 0) { /* We haven't loaded system binaries. Let's run an alternative, * though slower, check. */ check_third_party_cmds_alt(); return; } int udisks2ok = 0, udevilok = 0, check_coreutils = 0; #if defined(CHECK_COREUTILS) check_coreutils = 1; #endif /* CHECK_COREUTILS */ int i = (int)path_progsn; while (--i >= 0) { if (*bin_commands[i] != 'u' && *bin_commands[i] != 'f' && *bin_commands[i] != 's' #if defined(USE_DU1) && !defined(HAVE_GNU_DU) && !defined(_BE_POSIX) && *bin_commands[i] != 'g') #else ) #endif /* USE_DU1 && !HAVE_GNU_DU && !_BE_POSIX */ continue; if (*bin_commands[i] == 'f' && strcmp(bin_commands[i], "fzf") == 0) { bin_flags |= FZF_BIN_OK; if (fzftab == UNSET) fzftab = 1; } if (*bin_commands[i] == 'f' && strcmp(bin_commands[i], "fnf") == 0) { bin_flags |= FNF_BIN_OK; if (fzftab == UNSET) fzftab = 1; } if (*bin_commands[i] == 's' && strcmp(bin_commands[i], "smenu") == 0) { bin_flags |= SMENU_BIN_OK; if (fzftab == UNSET) fzftab = 1; } if (*bin_commands[i] == 'u' && strcmp(bin_commands[i], "udisksctl") == 0) udisks2ok = 1; if (*bin_commands[i] == 'u' && strcmp(bin_commands[i], "udevil") == 0) udevilok = 1; #if defined(USE_DU1) && !defined(HAVE_GNU_DU) && !defined(_BE_POSIX) if (*bin_commands[i] == 'g' && strcmp(bin_commands[i] + 1, "du") == 0) bin_flags |= GNU_DU_BIN_GDU; #endif /* USE_DU1 && !HAVE_GNU_DU && !_BE_POSIX */ #if defined(CHECK_COREUTILS) if (*bin_commands[i] == 'g' && strcmp(bin_commands[i] + 1, "rm") == 0) { bin_flags |= BSD_HAVE_COREUTILS; check_coreutils = 0; } #endif /* CHECK_COREUTILS */ if (udevilok == 1 && udisks2ok == 1 && check_coreutils == 0 && (bin_flags & (FZF_BIN_OK & FNF_BIN_OK & SMENU_BIN_OK #if defined(USE_DU1) && !defined(HAVE_GNU_DU) && !defined(_BE_POSIX) & GNU_DU_BIN_GDU))) #else ))) #endif /* USE_DU1 && !HAVE_GNU_DU && !_BE_POSIX */ break; } set_mount_cmd(udisks2ok, udevilok); } /* Return 1 if at least one of the user's groups match the file gid GID. * Otherwise, return 0. */ static int check_user_groups(const gid_t gid) { int i; for (i = 0; i < user.ngroups; i++) { if (user.groups[i] == gid) return 1; } return 0; } /* Return 1 if current user has access (read for files and read/exec for dirs) * to the file with mode MODE, uid UID, and gid GID. Otherwise, 0 is * returned. */ int check_file_access(const mode_t mode, const uid_t uid, const gid_t gid) { if (user.uid == 0) /* We are root */ return 1; const mode_t val = (mode & (mode_t)~S_IFMT); /* Check user permissions */ if ((val & S_IRUSR) && uid == user.uid) { if (!S_ISDIR(mode) || (val & S_IXUSR)) /* Check exec for directories */ return 1; } /* Check group permissions */ if ((val & S_IRGRP) && (gid == user.gid || check_user_groups(gid) == 1)) { if (!S_ISDIR(mode) || (val & S_IXGRP)) /* Check exec for directories */ return 1; } /* Check other permissions */ if ((val & S_IROTH)) { if (!S_ISDIR(mode) || (val & S_IXOTH)) /* Check exec for directories */ return 1; } return 0; } /* Return 1 if the command CMD exists (is found in PATH) and is executable * (and readable) by the current user. Otherwise, return 0. * This code is based on the file_status() function used by which(1). */ int is_exec_cmd(const char *cmd) { if (!cmd || !*cmd) return 0; struct stat a; if (stat(cmd, &a) == -1 || !S_ISREG(a.st_mode)) return 0; /* The file is read/exec by others (world). This is the most common case * for files in PATH. */ if ((a.st_mode & S_IXOTH) && (a.st_mode & S_IROTH)) return 1; /* We're root: we only need the exec bit to be set for any of user, * group, or others. */ if (user.uid == (uid_t)0 && (a.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))) return 1; /* We're the owner of the file. */ if (user.uid == a.st_uid && (a.st_mode & S_IXUSR) && (a.st_mode & S_IRUSR)) return 1; /* We're are in the file's group. */ if (check_user_groups(a.st_gid) == 1 && (a.st_mode & S_IXGRP) && (a.st_mode & S_IRGRP)) return 1; return 0; } char * get_sudo_path(void) { if (!sudo_cmd) { errno = ENOENT; return (char *)NULL; } char *sudo_path = get_cmd_path(sudo_cmd); int ret = errno; if (!sudo_path) { xerror("%s: '%s': %s\n", PROGRAM_NAME, sudo_cmd, strerror(ENOENT)); errno = ret; return (char *)NULL; } return sudo_path; } /* Check whether a given string contains only digits. Returns 1 if true * and 0 if false. It does not work with negative numbers. */ int is_number(const char *restrict str) { for (; *str; str++) if (*str > '9' || *str < '0') return 0; return 1; } /* Check if string STR contains a digit and this digit is not the first * char in STR. Used by is_internal_cmd() to check for fused parameters in * internal commands. * Returns the index of the digit in STR or -1 if no digit is found. */ static int contains_digit(const char *str) { if (!str || !*str || !*(++str)) return (-1); int i = 1; while (*str) { if (*str >= '1' && *str <= '9') return i; str++; i++; } return (-1); } /* Check whether S is an action name. * Returns 1 if true or 0 otherwise. */ int is_action_name(const char *s) { if (actions_n == 0) return 0; int n = (int)actions_n; while (--n >= 0) { if (*s == *usr_actions[n].name && strcmp(s, usr_actions[n].name) == 0) return 1; } return 0; } /* Return 1 if CMD is an internal command matching the flags in FLAG. * Otherwise, return 0. */ int is_internal_cmd(char *cmd, const int flag, const int check_hist, const int check_search) { if (!cmd || !*cmd) return 0; /* Old is_internal_f() function */ if ((flags & STATE_COMPLETING) && (flag & PARAM_FNAME_NUM) && (*cmd == 'w' || (*cmd == 'm' && cmd[1] == 'f') || (*cmd == 's' && (cmd[1] == 't' || cmd[1] == 'o')) ) ) return 0; char c = 0; const int d = contains_digit(cmd); if (d != -1) { c = cmd[d]; cmd[d] = '\0'; } const size_t clen = strlen(cmd); ssize_t i = (ssize_t)internal_cmds_n; int found = 0; while (--i >= 0) { if (((flag & ALL_CMDS) || (internal_cmds[i].flag & flag)) && clen == internal_cmds[i].len && *cmd == *internal_cmds[i].name && strcmp(cmd + 1, internal_cmds[i].name + 1) == 0) { found = 1; break; } } if (d != -1) cmd[d] = c; if (found == 1) return 1; if ((check_search == 1 && (*cmd == '/' && access(cmd, F_OK) != 0)) || (check_hist == 1 && (*cmd == '!' && (IS_DIGIT(cmd[1]) || (cmd[1] == '-' && IS_DIGIT(cmd[2])) || cmd[1] == '!')))) return 1; return 0; } /* Return one if STR is a command in PATH or zero if not. */ int is_bin_cmd(char *str) { char *p = str, *q = str; int index = 0, space_index = -1; while (*p) { if (*p == ' ') { *p = '\0'; space_index = index; break; } p++; index++; } size_t i; for (i = 0; bin_commands[i]; i++) { if (*q == *bin_commands[i] && q[1] == bin_commands[i][1] && strcmp(q, bin_commands[i]) == 0) { if (space_index != -1) q[space_index] = ' '; return 1; } } if (space_index != -1) q[space_index] = ' '; return 0; } int check_regex(const char *str) { if (!str || !*str) return FUNC_FAILURE; int char_found = 0; const char *p = str; while (*p) { /* If STR contains at least one of the following chars */ if (*p == '*' || *p == '?' || *p == '[' || *p == '{' || *p == '^' || *p == '.' || *p == '|' || *p == '+' || *p == '$') { char_found = 1; break; } p++; } /* And if STR is not a filename, take it as a possible regex */ if (char_found == 1 && access(str, F_OK) == -1) return FUNC_SUCCESS; return FUNC_FAILURE; } /* Returns the parsed aliased command in an array of strings if a * matching alias is found, or NULL if not. */ char ** check_for_alias(char **args) { /* Do not expand alias if first word is an ELN or the alias name * starts with a backslash. */ if (aliases_n == 0 || !aliases || !args || flags & FIRST_WORD_IS_ELN || *args[0] == '\\') return (char **)NULL; int i = (int)aliases_n; while (--i >= 0) { if (!aliases[i].name || !aliases[i].cmd || !*aliases[i].name || !*aliases[i].cmd) continue; if (*aliases[i].name != *args[0] || strcmp(args[0], aliases[i].name) != 0) continue; if (xargs.secure_cmds == 1 && sanitize_cmd(aliases[i].cmd, SNT_GRAL) == FUNC_FAILURE) continue; args_n = 0; /* Reset args_n to be used by parse_input_str(). */ char **alias_cmd = parse_input_str(aliases[i].cmd); if (!alias_cmd) { flags |= FAILED_ALIAS; /* Prevent exec_cmd() from being executed. */ return (char **)NULL; } size_t j; /* Add input parameters, if any, to alias_cmd. Expansions for these * parameters were already performed before calling this function. */ if (args[1]) { for (j = 1; args[j]; j++) { alias_cmd = xnrealloc(alias_cmd, ++args_n + 2, sizeof(char *)); alias_cmd[args_n] = savestring(args[j], strlen(args[j])); } } alias_cmd[args_n + 1] = (char *)NULL; /* Free the original command. */ for (j = 0; args[j]; j++) free(args[j]); free(args); return alias_cmd; } return (char **)NULL; } /* Keep only the last MAX records in FILE. * If CHECK_DUPS is 1, skip consecutive equal entries. */ void truncate_file(const char *file, const int max, const int check_dups) { if (config_ok == 0 || !file || !*file) return; char *tmp_name = (char *)NULL; FILE *orig_fp = (FILE *)NULL; struct stat attr; int orig_fd = 0; if (stat(file, &attr) == -1) { /* File doesn't exist: create it and exit. */ orig_fp = open_fwrite(file, &orig_fd); if (!orig_fp) { err('w', PRINT_PROMPT, "%s: '%s': %s\n", PROGRAM_NAME, file, strerror(errno)); } else { fclose(orig_fp); } return; } /* Open the original file for read. */ if (!(orig_fp = open_fread(file, &orig_fd))) { err('w', PRINT_PROMPT, "%s: '%s': %s\n", PROGRAM_NAME, file, strerror(errno)); return; } int n = 0, c; /* Count newline chars to get the number of lines in the file. */ while ((c = fgetc(orig_fp)) != EOF && n < INT_MAX) { /* Flawfinder: ignore */ if (c == '\n') n++; } if (c == EOF && ferror(orig_fp)) { err('w', PRINT_PROMPT, _("%s: '%s': Error reading file\n"), PROGRAM_NAME, file); goto EXIT; } if (n <= max) goto EXIT; /* Set the file pointer to the beginning of the original file. */ fseek(orig_fp, 0, SEEK_SET); const size_t len = config_dir_len + (sizeof(TMP_FILENAME) - 1) + 2; tmp_name = xnmalloc(len, sizeof(char)); snprintf(tmp_name, len, "%s/%s", config_dir, TMP_FILENAME); int tmp_fd = mkstemp(tmp_name); if (tmp_fd == -1) { err('w', PRINT_PROMPT, "%s: '%s': %s", PROGRAM_NAME, tmp_name, strerror(errno)); goto EXIT; } FILE *tmp_fp = fdopen(tmp_fd, "w"); if (!tmp_fp) { unlinkat(tmp_fd, tmp_name, 0); err('w', PRINT_PROMPT, "%s: '%s': %s\n", PROGRAM_NAME, tmp_name, strerror(errno)); close(tmp_fd); goto EXIT; } int i = 1; size_t line_size = 0; char *line = (char *)NULL; ssize_t line_len = 0; char *prev_line = (char *)NULL; ssize_t prev_line_len = 0; while ((line_len = getline(&line, &line_size, orig_fp)) > 0) { /* Skip consecutive equal entries. */ if (check_dups == 1 && prev_line && line_len == prev_line_len && strcmp(line, prev_line) == 0) continue; /* Delete old entries, i.e., copy only new ones. */ if (i >= n - (max - 1)) fputs(line, tmp_fp); i++; if (check_dups == 1) { free(prev_line); prev_line = savestring(line, (size_t)line_len); prev_line_len = line_len; } } free(prev_line); free(line); renameat(tmp_fd, tmp_name, orig_fd, file); fclose(tmp_fp); EXIT: free(tmp_name); fclose(orig_fp); } clifm-1.26.3/src/checks.h000066400000000000000000000033331506632037700151100ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* checks.h */ #ifndef CHECKS_H #define CHECKS_H __BEGIN_DECLS #ifndef _NO_FZF void check_completion_mode(void); #endif /* !_NO_FZF */ int check_file_access(const mode_t mode, const uid_t uid, const gid_t gid); char **check_for_alias(char **args); int check_glob_char(const char *str, const int gflag); int check_regex(const char *str); void check_third_party_cmds(void); void file_cmd_check(void); char *get_sudo_path(void); int is_action_name(const char *s); int is_bin_cmd(char *str); int is_exec_cmd(const char *cmd); int is_file_in_cwd(char *name); int is_force_param(const char *s); int is_internal_cmd(char *cmd, const int flag, const int check_hist, const int check_search); int is_number(const char *restrict str); int is_url(const char *url); void truncate_file(const char *file, const int max, const int check_dups); __END_DECLS #endif /* CHECKS_H */ clifm-1.26.3/src/cleaner_table.h000066400000000000000000000323211506632037700164270ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* cleaner_table.h - A table for characters translation */ #ifndef CLEANER_TABLE_H #define CLEANER_TABLE_H struct utable_t { int key; int pad; char *data; }; /* Let's use a table to convert Unicode chars into ASCII alternatives * This list is based on https://github.com/dharple/detox and * https://en.wikipedia.org/wiki/List_of_Unicode_characters * To get the glyph corresponding to any of the below codepoints use * printf(1) as folows: * $ printf "\UXXXX" # no leading 0x */ struct utable_t unitable[] = { /* Letters */ {0x00c0, 0, "A" }, {0x00c1, 0, "A" }, {0x00c2, 0, "A" }, {0x00c3, 0, "A" }, {0x00c5, 0, "A" }, {0x00c6, 0, "AE" }, {0x00c7, 0, "C" }, {0x00c8, 0, "E" }, {0x00c9, 0, "E" }, {0x00ca, 0, "E" }, {0x00cb, 0, "E" }, {0x00cc, 0, "I" }, {0x00cd, 0, "I" }, {0x00ce, 0, "I" }, {0x00cf, 0, "I" }, {0x00d0, 0, "TH" }, {0x00d1, 0, "N" }, {0x00d2, 0, "O" }, {0x00d3, 0, "O" }, {0x00d4, 0, "O" }, {0x00d5, 0, "O" }, {0x00d7, 0, "x" }, {0x00d8, 0, "O" }, {0x00d9, 0, "U" }, {0x00da, 0, "U" }, {0x00db, 0, "U" }, {0x00dd, 0, "Y" }, {0x00de, 0, "TH" }, {0x00df, 0, "ss" }, {0x00e0, 0, "a" }, {0x00e1, 0, "a" }, {0x00e2, 0, "a" }, {0x00e3, 0, "a" }, {0x00e5, 0, "a" }, {0x00e6, 0, "ae" }, {0x00e7, 0, "c" }, {0x00e8, 0, "e" }, {0x00e9, 0, "e" }, {0x00ea, 0, "e" }, {0x00eb, 0, "e" }, {0x00ec, 0, "i" }, {0x00ed, 0, "i" }, {0x00ee, 0, "i" }, {0x00ef, 0, "i" }, {0x00f0, 0, "th" }, {0x00f1, 0, "n" }, {0x00f2, 0, "o" }, {0x00f3, 0, "o" }, {0x00f4, 0, "o" }, {0x00f5, 0, "o" }, {0x00f8, 0, "o" }, {0x00f9, 0, "u" }, {0x00fa, 0, "u" }, {0x00fb, 0, "u" }, {0x00fd, 0, "y" }, {0x00fe, 0, "th" }, {0x00ff, 0, "y" }, {0x0100, 0, "A" }, {0x0101, 0, "a" }, {0x0102, 0, "A" }, {0x0103, 0, "a" }, {0x0104, 0, "A" }, {0x0105, 0, "a" }, {0x0106, 0, "C" }, {0x0107, 0, "c" }, {0x0108, 0, "C" }, {0x0109, 0, "c" }, {0x010a, 0, "C" }, {0x010b, 0, "c" }, {0x010c, 0, "C" }, {0x010d, 0, "c" }, {0x010e, 0, "D" }, {0x010f, 0, "d" }, {0x0110, 0, "D" }, {0x0111, 0, "d" }, {0x0112, 0, "E" }, {0x0113, 0, "e" }, {0x0114, 0, "E" }, {0x0115, 0, "e" }, {0x0116, 0, "E" }, {0x0117, 0, "e" }, {0x0118, 0, "E" }, {0x0119, 0, "e" }, {0x011a, 0, "E" }, {0x011b, 0, "e" }, {0x011c, 0, "G" }, {0x011d, 0, "g" }, {0x011e, 0, "G" }, {0x011f, 0, "g" }, {0x0120, 0, "G" }, {0x0121, 0, "g" }, {0x0122, 0, "G" }, {0x0123, 0, "g" }, {0x0124, 0, "H" }, {0x0125, 0, "h" }, {0x0126, 0, "H" }, {0x0127, 0, "h" }, {0x0128, 0, "I" }, {0x0129, 0, "i" }, {0x012a, 0, "I" }, {0x012b, 0, "i" }, {0x012c, 0, "I" }, {0x012d, 0, "i" }, {0x012e, 0, "I" }, {0x012f, 0, "i" }, {0x0130, 0, "I" }, {0x0131, 0, "i" }, {0x0132, 0, "IJ" }, {0x0133, 0, "ij" }, {0x0134, 0, "J" }, {0x0135, 0, "j" }, {0x0136, 0, "K" }, {0x0137, 0, "k" }, {0x0138, 0, "q" }, {0x0139, 0, "L" }, {0x013a, 0, "l" }, {0x013b, 0, "L" }, {0x013c, 0, "l" }, {0x013d, 0, "L" }, {0x013e, 0, "l" }, {0x013f, 0, "L" }, {0x0140, 0, "l" }, {0x0141, 0, "L" }, {0x0142, 0, "l" }, {0x0143, 0, "N" }, {0x0144, 0, "n" }, {0x0145, 0, "N" }, {0x0146, 0, "n" }, {0x0147, 0, "N" }, {0x0148, 0, "n" }, {0x0149, 0, "_n" }, {0x014a, 0, "NG" }, {0x014b, 0, "ng" }, {0x014c, 0, "O" }, {0x014d, 0, "o" }, {0x014e, 0, "O" }, {0x014f, 0, "o" }, {0x0150, 0, "O" }, {0x0151, 0, "o" }, {0x0152, 0, "OE" }, {0x0153, 0, "oe" }, {0x0154, 0, "R" }, {0x0155, 0, "r" }, {0x0156, 0, "R" }, {0x0157, 0, "r" }, {0x0158, 0, "R" }, {0x0159, 0, "r" }, {0x015a, 0, "S" }, {0x015b, 0, "s" }, {0x015c, 0, "S" }, {0x015d, 0, "s" }, {0x015e, 0, "S" }, {0x015f, 0, "s" }, {0x0160, 0, "S" }, {0x0161, 0, "s" }, {0x0162, 0, "T" }, {0x0163, 0, "t" }, {0x0164, 0, "T" }, {0x0165, 0, "t" }, {0x0166, 0, "T" }, {0x0167, 0, "t" }, {0x0168, 0, "U" }, {0x0169, 0, "u" }, {0x016a, 0, "U" }, {0x016b, 0, "u" }, {0x016c, 0, "U" }, {0x016d, 0, "u" }, {0x016e, 0, "U" }, {0x016f, 0, "u" }, {0x0170, 0, "U" }, {0x0171, 0, "u" }, {0x0172, 0, "U" }, {0x0173, 0, "u" }, {0x0174, 0, "W" }, {0x0175, 0, "w" }, {0x0176, 0, "Y" }, {0x0177, 0, "y" }, {0x0178, 0, "Y" }, {0x0179, 0, "Z" }, {0x017a, 0, "z" }, {0x017b, 0, "Z" }, {0x017c, 0, "z" }, {0x017d, 0, "Z" }, {0x017e, 0, "z" }, {0x017f, 0, "s" }, {0x0180, 0, "b" }, {0x0181, 0, "B" }, {0x0182, 0, "B" }, {0x0183, 0, "b" }, {0x0184, 0, "B" }, {0x0185, 0, "b" }, {0x0186, 0, "O" }, {0x0187, 0, "C" }, {0x0188, 0, "c" }, {0x0189, 0, "D" }, {0x018a, 0, "D" }, {0x018b, 0, "D" }, {0x018c, 0, "d" }, {0x018d, 0, "z" }, {0x018e, 0, "E" }, {0x018f, 0, "E" }, {0x0190, 0, "E" }, {0x0191, 0, "F" }, {0x0192, 0, "f" }, {0x0193, 0, "G" }, {0x0194, 0, "Y" }, {0x0195, 0, "hv" }, {0x0196, 0, "I" }, {0x0197, 0, "I" }, {0x0198, 0, "K" }, {0x0199, 0, "k" }, {0x019a, 0, "l" }, {0x019b, 0, "l" }, {0x019c, 0, "w" }, {0x019d, 0, "N" }, {0x019e, 0, "n" }, {0x019f, 0, "O" }, {0x01a0, 0, "O" }, {0x01a1, 0, "o" }, {0x01a2, 0, "OI" }, {0x01a3, 0, "oi" }, {0x01a4, 0, "P" }, {0x01a5, 0, "p" }, {0x01a6, 0, "YR" }, {0x01a7, 0, "S" }, {0x01a8, 0, "s" }, {0x01a9, 0, "SH" }, {0x01aa, 0, "sh" }, {0x01ab, 0, "t" }, {0x01ac, 0, "T" }, {0x01ad, 0, "t" }, {0x01ae, 0, "T" }, {0x01af, 0, "U" }, {0x01b0, 0, "u" }, {0x01b1, 0, "Y" }, {0x01b2, 0, "V" }, {0x01b3, 0, "Y" }, {0x01b4, 0, "y" }, {0x01b5, 0, "Z" }, {0x01b6, 0, "z" }, {0x01b7, 0, "ZH" }, {0x01b8, 0, "ZH" }, {0x01b9, 0, "zh" }, {0x01ba, 0, "zh" }, {0x01bb, 0, "dz" }, {0x01bc, 0, "5" }, {0x01bd, 0, "5" }, {0x01be, 0, "ts" }, {0x01bf, 0, "w" }, {0x01c4, 0, "DZ" }, {0x01c5, 0, "Dz" }, {0x01c6, 0, "dz" }, {0x01c7, 0, "LJ" }, {0x01c8, 0, "Lj" }, {0x01c9, 0, "lj" }, {0x01ca, 0, "NJ" }, {0x01cb, 0, "Nj" }, {0x01cc, 0, "nj" }, {0x01cd, 0, "A" }, {0x01ce, 0, "a" }, {0x01cf, 0, "I" }, {0x01d0, 0, "i" }, {0x01d1, 0, "O" }, {0x01d2, 0, "o" }, {0x01d3, 0, "U" }, {0x01d4, 0, "u" }, {0x01d5, 0, "U" }, {0x01d6, 0, "u" }, {0x01d7, 0, "U" }, {0x01d8, 0, "u" }, {0x01d9, 0, "U" }, {0x01da, 0, "u" }, {0x01db, 0, "U" }, {0x01dc, 0, "u" }, {0x01dd, 0, "e" }, {0x01de, 0, "A" }, {0x01df, 0, "a" }, {0x01e0, 0, "A" }, {0x01e1, 0, "a" }, {0x01e2, 0, "AE" }, {0x01e3, 0, "ae" }, {0x01e4, 0, "G" }, {0x01e5, 0, "g" }, {0x01e6, 0, "G" }, {0x01e7, 0, "g" }, {0x01e8, 0, "K" }, {0x01e9, 0, "k" }, {0x01ea, 0, "O" }, {0x01eb, 0, "o" }, {0x01ec, 0, "O" }, {0x01ed, 0, "o" }, {0x01ee, 0, "ZH" }, {0x01ef, 0, "zh" }, {0x01f0, 0, "j" }, {0x01f1, 0, "DZ" }, {0x01f2, 0, "Dz" }, {0x01f3, 0, "dz" }, {0x01f4, 0, "G" }, {0x01f5, 0, "g" }, {0x01f6, 0, "HU" }, {0x01f7, 0, "W" }, {0x01f8, 0, "N" }, {0x01f9, 0, "n" }, {0x01fa, 0, "A" }, {0x01fb, 0, "a" }, {0x01fc, 0, "AE" }, {0x01fd, 0, "ae" }, {0x01fe, 0, "O" }, {0x01ff, 0, "o" }, {0x0200, 0, "A" }, {0x0201, 0, "a" }, {0x0202, 0, "A" }, {0x0203, 0, "a" }, {0x0204, 0, "E" }, {0x0205, 0, "e" }, {0x0206, 0, "E" }, {0x0207, 0, "e" }, {0x0208, 0, "I" }, {0x0209, 0, "i" }, {0x020a, 0, "I" }, {0x020b, 0, "i" }, {0x020c, 0, "O" }, {0x020d, 0, "o" }, {0x020e, 0, "O" }, {0x020f, 0, "o" }, {0x0210, 0, "R" }, {0x0211, 0, "r" }, {0x0212, 0, "R" }, {0x0213, 0, "r" }, {0x0214, 0, "U" }, {0x0215, 0, "u" }, {0x0216, 0, "U" }, {0x0217, 0, "u" }, {0x0218, 0, "S" }, {0x0219, 0, "s" }, {0x021a, 0, "T" }, {0x021b, 0, "t" }, {0x021c, 0, "Y" }, {0x021d, 0, "y" }, {0x021e, 0, "H" }, {0x021f, 0, "h" }, {0x0220, 0, "N" }, {0x0221, 0, "d" }, {0x0222, 0, "OU" }, {0x0223, 0, "ou" }, {0x0224, 0, "Z" }, {0x0225, 0, "z" }, {0x0226, 0, "A" }, {0x0227, 0, "a" }, {0x0228, 0, "E" }, {0x0229, 0, "e" }, {0x022a, 0, "O" }, {0x022b, 0, "o" }, {0x022c, 0, "O" }, {0x022d, 0, "o" }, {0x022e, 0, "O" }, {0x022f, 0, "o" }, {0x0230, 0, "O" }, {0x0231, 0, "o" }, {0x0232, 0, "Y" }, {0x0233, 0, "y" }, {0x0234, 0, "l" }, {0x0235, 0, "n" }, {0x0236, 0, "t" }, {0x0237, 0, "j" }, {0x0238, 0, "db" }, {0x0239, 0, "qp" }, {0x023a, 0, "A" }, {0x023b, 0, "C" }, {0x023c, 0, "c" }, {0x023d, 0, "L" }, {0x023e, 0, "T" }, {0x023f, 0, "s" }, {0x0240, 0, "z" }, {0x0243, 0, "B" }, {0x0244, 0, "U" }, {0x0246, 0, "E" }, {0x0247, 0, "e" }, {0x0248, 0, "J" }, {0x0249, 0, "j" }, {0x024a, 0, "q" }, {0x024b, 0, "q" }, {0x024c, 0, "R" }, {0x024d, 0, "r" }, {0x024e, 0, "Y" }, {0x024f, 0, "y" }, {0x03a1, 0, "P" }, {0x03c1, 0, "p" }, {0x1952, 0, "n" }, {0x1959, 0, "u" }, {0x1963, 0, "l" }, {0x1971, 0, "e" }, {0x1974, 0, "c" }, {0x1e9e, 0, "SS" }, {0x1e02, 0, "B" }, {0x1e03, 0, "b" }, {0x1e0a, 0, "D" }, {0x1e0B, 0, "d" }, {0x1e1e, 0, "F" }, {0x1e1f, 0, "f" }, {0x1e40, 0, "M" }, {0x1e41, 0, "m" }, {0x1e56, 0, "P" }, {0x1e57, 0, "p" }, {0x1e60, 0, "S" }, {0x1e61, 0, "s" }, {0x1e6a, 0, "T" }, {0x1e6b, 0, "t" }, {0x1e80, 0, "W" }, {0x1e81, 0, "w" }, {0x1e82, 0, "W" }, {0x1e83, 0, "w" }, {0x1e84, 0, "W" }, {0x1e85, 0, "w" }, {0x1e9b, 0, "s" }, {0x1ef2, 0, "Y" }, {0x1ef3, 0, "y" }, /* Symbols */ {0x00a1, 0, "_" }, // inverted exclamation mark {0x00a2, 0, "_cent_" }, {0x00a3, 0, "_pound_" }, {0x00a4, 0, "_" }, {0x00a5, 0, "_yen_" }, {0x00a7, 0, "_ss_" }, {0x00a8, 0, "_" }, {0x00a9, 0, "_copy_" }, {0x00aa, 0, "_a_" }, {0x00ab, 0, "_" }, {0x00ad, 0, "-" }, {0x00ae, 0, "_reg_" }, {0x00b0, 0, "_deg_" }, {0x00b2, 0, "-2" }, {0x00b3, 0, "-3" }, {0x00b4, 0, "_" }, // accute accent: ´ {0x00b5, 0, "u" }, {0x00b6, 0, "_pp_" }, {0x00b7, 0, "_" }, {0x00b8, 0, "_" }, {0x00b9, 0, "-1" }, {0x00ba, 0, "_o_" }, {0x00bb, 0, "_" }, {0x00bf, 0, "_" }, {0x02c6, 0, "_" }, // caret {0x02dc, 0, "_" }, // tilde {0x2010, 0, "-" }, {0x2011, 0, "-" }, {0x2012, 0, "-" }, {0x2013, 0, "-" }, {0x2014, 0, "-" }, {0x2015, 0, "-" }, {0x2017, 0, "_" }, {0x2018, 0, "_" }, {0x2019, 0, "_" }, {0x201a, 0, "_" }, {0x201b, 0, "_" }, {0x201c, 0, "_" }, {0x201d, 0, "_" }, {0x201e, 0, "_" }, {0x201f, 0, "_" }, {0x2020, 0, "-" }, {0x2021, 0, "_" }, {0x2022, 0, "_" }, {0x2024, 0, "_" }, {0x2025, 0, "_" }, {0x2026, 0, "_" }, {0x2027, 0, "_" }, {0x2032, 0, "_" }, {0x2033, 0, "_" }, {0x2034, 0, "_" }, {0x2035, 0, "_" }, {0x2036, 0, "_" }, {0x2037, 0, "_" }, {0x2038, 0, "_" }, {0x203d, 0, "_" }, {0x203e, 0, "-" }, {0x203f, 0, "_" }, {0x2040, 0, "-" }, {0x2041, 0, "_" }, {0x2043, 0, "-" }, {0x2044, 0, "_" }, // slash {0x2045, 0, "-" }, {0x2046, 0, "-" }, {0x2047, 0, "_" }, {0x2048, 0, "_" }, {0x2049, 0, "_" }, {0x204a, 0, "_and_" }, {0x204b, 0, "_pp_" }, {0x204f, 0, "_" }, {0x2052, 0, "_" }, {0x2053, 0, "_" }, {0x2054, 0, "_" }, {0x2055, 0, "_" }, {0x2056, 0, "_" }, {0x2057, 0, "_" }, {0x2058, 0, "_" }, {0x2059, 0, "_" }, {0x205a, 0, "_" }, {0x205b, 0, "_" }, {0x205d, 0, "_" }, {0x205e, 0, "_" }, {0x20a0, 0, "ECU" }, {0x20a1, 0, "CL" }, {0x20a2, 0, "Cr" }, {0x20a3, 0, "FF" }, {0x20a4, 0, "L" }, {0x20a5, 0, "mil" }, {0x20a6, 0, "N" }, {0x20a7, 0, "Pts" }, {0x20a8, 0, "Rs" }, {0x20a9, 0, "W" }, {0x20aa, 0, "NS" }, {0x20ab, 0, "D" }, {0x20ac, 0, "EUR" }, {0x20ad, 0, "K" }, {0x20ae, 0, "T" }, {0x20af, 0, "Dr" }, {0x20b1, 0, "s" }, {0x20b2, 0, "C" }, {0x20bb, 0, "M" }, {0x20bf, 0, "_btc_" }, {0x2122, 0, "_tm_" }, {0x10348, 0, "hu" }, {0x1f37a, 0, "_beer_" }, {0x02bc, 0, "_"}, /* German vowels with umlaut */ {0x00f6, 0, "oe" }, {0x00fc, 0, "ue" }, {0x00e4, 0, "ae" }, {0x00dc, 0, "Ue" }, {0x00d6, 0, "Oe" }, {0x00c4, 0, "Ae" }, /* Non-ASCII whitespaces */ {0x2000, 0, "_" }, // en quad {0x2001, 0, "_" }, // em quad {0x2002, 0, "_" }, // en space {0x2003, 0, "_" }, // em space {0x2004, 0, "_" }, // three-per-em space {0x2005, 0, "_" }, // four-per-em space {0x2006, 0, "_" }, // six-per-em space {0x2007, 0, "_" }, // figure space {0x2008, 0, "_" }, // punctuation space {0x2009, 0, "_" }, // thin space {0x200a, 0, "_" }, // hair space {0x200b, 0, "_" }, // zero width space {0x200c, 0, "_" }, // zero width non-joiner {0x200d, 0, "_" }, // zero width joiner {0x2422, 0, "_" }, // blank symbol {0x2800, 0, "_" }, // braille pattern blank {0x3000, 0, "_" }, // ideographic space {0xfeff, 0, "_"}, // zero width non-breaking space {0x3164, 0, "_"}, // hangul filler {0x205f, 0, "_" }, // medium mathematical space {0x2060, 0, "_" }, // word joiner {0x2028, 0, "_" }, // line separator {0x2029, 0, "_" }, // paragraph separator {0x202f, 0, "_" }, // narrow no-break space {0x115f, 0, "_" }, // HANGUL CHOSEONG FILLER {0x1160, 0, "_" }, // HANGUL JUNGSEONG FILLER {0x1680, 0, "_" }, // ogham space mark {0x180e, 0, "_" }, // mongolian vowel separator {0x0085, 0, "_" }, // next line {0x00a0, 0, "_" }, // no-break space {0, 0, NULL}, }; #endif /* CLEANER_TABLE_H */ clifm-1.26.3/src/colors.c000066400000000000000000002625311506632037700151530ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* colors.c -- functions to control interface colors */ #include "helpers.h" #ifdef __linux__ # include #endif /* __linux__ */ #include #include #ifndef CLIFM_SUCKLESS # include /* str(n)casecmp() */ #endif /* CLIFM_SUCKLESS */ /* Only used to check the readline version */ #ifdef __OpenBSD__ typedef char *rl_cpvfunc_t; # include #else # include #endif /* __OpenBSD__ */ #include "aux.h" #include "autocmds.h" /* update_autocmd_opts() */ #include "checks.h" #include "colors.h" #include "config.h" /* set_div_line() */ #include "file_operations.h" #include "listing.h" #include "messages.h" #include "misc.h" #include "prompt.h" /* gen_color() */ #include "properties.h" /* get_color_age(), get_color_size() */ #include "sanitize.h" #include "spawn.h" #ifndef CLIFM_SUCKLESS /* qsort(3) is used only by get_colorschemes(), which is not included * if CLIFM_SUCKLESS is defined */ # include "sort.h" /* compare_string() (used by qsort(3)) */ #endif /* !CLIFM_SUCKLESS */ #define ON_LSCOLORS (xargs.lscolors == LS_COLORS_GNU \ ? _(" (on LS_COLORS)") : (xargs.lscolors == LS_COLORS_BSD \ ? _(" (on LSCOLORS)") : "")) #ifndef CLIFM_SUCKLESS /* A struct to hold color variables */ struct colors_t { char *name; char *value; size_t namelen; }; /* A struct to map color codes to color variables */ struct color_mapping_t { const char *prefix; /* Color code name (e.g. "el") */ char *color; /* Pointer to the color variable (.e.g. el_c) */ int prefix_len; /* Length of prefix */ int printable; /* Either RL_PRINTABLE or RL_NO_PRINTABLE */ }; static struct colors_t *defs; static size_t defs_n = 0; /* Xterm-like color names taken from vifm(1) */ static const struct colors_t color_names[] = { {"Black", "38;5;0", 5}, {"Red", "38;5;1", 3}, {"Green", "38;5;2", 5}, {"Yellow", "38;5;3", 6}, {"Blue", "38;5;4", 4}, {"Magenta", "38;5;5", 7}, {"Cyan", "38;5;6", 4}, {"White", "38;5;7", 5}, {"LightBlack", "38;5;8", 10}, {"LightRed", "38;5;9", 8}, {"LightGreen", "38;5;10", 10}, {"LightYellow", "38;5;11", 11}, {"LightBlue", "38;5;12", 9}, {"LightMagenta", "38;5;13", 12}, {"LightCyan", "38;5;14", 9}, {"LightWhite", "38;5;15", 10}, {"Grey0", "38;5;16", 5}, {"NavyBlue", "38;5;17", 8}, {"DarkBlue", "38;5;18", 8}, {"Blue3", "38;5;19", 5}, {"Blue3_2", "38;5;20", 7}, {"Blue1", "38;5;21", 5}, {"DarkGreen", "38;5;22", 9}, {"DeepSkyBlue4", "38;5;23", 12}, {"DeepSkyBlue4_2", "38;5;24", 14}, {"DeepSkyBlue4_3", "38;5;25", 14}, {"DodgerBlue3", "38;5;26", 11}, {"DodgerBlue2", "38;5;27", 11}, {"Green4", "38;5;28", 6}, {"SpringGreen4", "38;5;29", 12}, {"Turquoise4", "38;5;30", 10}, {"DeepSkyBlue3", "38;5;31", 12}, {"DeepSkyBlue3_2", "38;5;32", 14}, {"DodgerBlue1", "38;5;33", 11}, {"Green3", "38;5;34", 6}, {"SpringGreen3", "38;5;35", 12}, {"DarkCyan", "38;5;36", 8}, {"LightSeaGreen", "38;5;37", 13}, {"DeepSkyBlue2", "38;5;38", 12}, {"DeepSkyBlue1", "38;5;39", 12}, {"Green3_2", "38;5;40", 8}, {"SpringGreen3_2", "38;5;41", 14}, {"SpringGreen2", "38;5;42", 12}, {"Cyan3", "38;5;43", 5}, {"DarkTurquoise", "38;5;44", 13}, {"Turquoise2", "38;5;45", 10}, {"Green1", "38;5;46", 6}, {"SpringGreen2_2", "38;5;47", 14}, {"SpringGreen1", "38;5;48", 12}, {"MediumSpringGreen", "38;5;49", 17}, {"Cyan2", "38;5;50", 5}, {"Cyan1", "38;5;51", 5}, {"DarkRed", "38;5;52", 7}, {"DeepPink4", "38;5;53", 9}, {"Purple4", "38;5;54", 7}, {"Purple4_2", "38;5;55", 9}, {"Purple3", "38;5;56", 7}, {"BlueViolet", "38;5;57", 10}, {"Orange4", "38;5;58", 7}, {"Grey37", "38;5;59", 6}, {"MediumPurple4", "38;5;60", 13}, {"SlateBlue3", "38;5;61", 10}, {"SlateBlue3_2", "38;5;62", 12}, {"RoyalBlue1", "38;5;63", 10}, {"Chartreuse4", "38;5;64", 11}, {"DarkSeaGreen4", "38;5;65", 13}, {"PaleTurquoise4", "38;5;66", 14}, {"SteelBlue", "38;5;67", 9}, {"SteelBlue3", "38;5;68", 10}, {"CornflowerBlue", "38;5;69", 14}, {"Chartreuse3", "38;5;70", 11}, {"DarkSeaGreen4_2", "38;5;71", 15}, {"CadetBlue", "38;5;72", 9}, {"CadetBlue_2", "38;5;73", 11}, {"SkyBlue3", "38;5;74", 8}, {"SteelBlue1", "38;5;75", 10}, {"Chartreuse3_2", "38;5;76", 13}, {"PaleGreen3", "38;5;77", 10}, {"SeaGreen3", "38;5;78", 9}, {"Aquamarine3", "38;5;79", 11}, {"MediumTurquoise", "38;5;80", 15}, {"SteelBlue1_2", "38;5;81", 12}, {"Chartreuse2", "38;5;82", 11}, {"SeaGreen2", "38;5;83", 9}, {"SeaGreen1", "38;5;84", 9}, {"SeaGreen1_2", "38;5;85", 11}, {"Aquamarine1", "38;5;86", 11}, {"DarkSlateGray2", "38;5;87", 14}, {"DarkRed_2", "38;5;88", 9}, {"DeepPink4_2", "38;5;89", 11}, {"DarkMagenta", "38;5;90", 11}, {"DarkMagenta_2", "38;5;91", 13}, {"DarkViolet", "38;5;92", 10}, {"Purple", "38;5;93", 6}, {"Orange4_2", "38;5;94", 9}, {"LightPink4", "38;5;95", 10}, {"Plum4", "38;5;96", 5}, {"MediumPurple3", "38;5;97", 13}, {"MediumPurple3_2", "38;5;98", 15}, {"SlateBlue1", "38;5;99", 10}, {"Yellow4", "38;5;100", 7}, {"Wheat4", "38;5;101", 6}, {"Grey53", "38;5;102", 6}, {"LightSlateGrey", "38;5;103", 14}, {"MediumPurple", "38;5;104", 12}, {"LightSlateBlue", "38;5;105", 14}, {"Yellow4_2", "38;5;106", 9}, {"DarkOliveGreen3", "38;5;107", 15}, {"DarkSeaGreen", "38;5;108", 12}, {"LightSkyBlue3", "38;5;109", 13}, {"LightSkyBlue3_2", "38;5;110", 15}, {"SkyBlue2", "38;5;111", 8}, {"Chartreuse2_2", "38;5;112", 13}, {"DarkOliveGreen3_2", "38;5;113", 17}, {"PaleGreen3_2", "38;5;114", 12}, {"DarkSeaGreen3", "38;5;115", 13}, {"DarkSlateGray3", "38;5;116", 14}, {"SkyBlue1", "38;5;117", 8}, {"Chartreuse1", "38;5;118", 11}, {"LightGreen_2", "38;5;119", 12}, {"LightGreen_3", "38;5;120", 12}, {"PaleGreen1", "38;5;121", 10}, {"Aquamarine1_2", "38;5;122", 13}, {"DarkSlateGray1", "38;5;123", 14}, {"Red3", "38;5;124", 4}, {"DeepPink4_3", "38;5;125", 11}, {"MediumVioletRed", "38;5;126", 15}, {"Magenta3", "38;5;127", 8}, {"DarkViolet_2", "38;5;128", 12}, {"Purple_2", "38;5;129", 8}, {"DarkOrange3", "38;5;130", 11}, {"IndianRed", "38;5;131", 9}, {"HotPink3", "38;5;132", 8}, {"MediumOrchid3", "38;5;133", 13}, {"MediumOrchid", "38;5;134", 12}, {"MediumPurple2", "38;5;135", 13}, {"DarkGoldenrod", "38;5;136", 13}, {"LightSalmon3", "38;5;137", 12}, {"RosyBrown", "38;5;138", 9}, {"Grey63", "38;5;139", 6}, {"MediumPurple2_2", "38;5;140", 15}, {"MediumPurple1", "38;5;141", 13}, {"Gold3", "38;5;142", 5}, {"DarkKhaki", "38;5;143", 9}, {"NavajoWhite3", "38;5;144", 12}, {"Grey69", "38;5;145", 6}, {"LightSteelBlue3", "38;5;146", 15}, {"LightSteelBlue", "38;5;147", 14}, {"Yellow3", "38;5;148", 7}, {"DarkOliveGreen3_3", "38;5;149", 17}, {"DarkSeaGreen3_2", "38;5;150", 15}, {"DarkSeaGreen2", "38;5;151", 13}, {"LightCyan3", "38;5;152", 10}, {"LightSkyBlue1", "38;5;153", 13}, {"GreenYellow", "38;5;154", 11}, {"DarkOliveGreen2", "38;5;155", 15}, {"PaleGreen1_2", "38;5;156", 12}, {"DarkSeaGreen2_2", "38;5;157", 15}, {"DarkSeaGreen1", "38;5;158", 13}, {"PaleTurquoise1", "38;5;159", 14}, {"Red3_2", "38;5;160", 6}, {"DeepPink3", "38;5;161", 9}, {"DeepPink3_2", "38;5;162", 11}, {"Magenta3_2", "38;5;163", 10}, {"Magenta3_3", "38;5;164", 10}, {"Magenta2", "38;5;165", 8}, {"DarkOrange3_2", "38;5;166", 13}, {"IndianRed_2", "38;5;167", 11}, {"HotPink3_2", "38;5;168", 10}, {"HotPink2", "38;5;169", 8}, {"Orchid", "38;5;170", 6}, {"MediumOrchid1", "38;5;171", 13}, {"Orange3", "38;5;172", 7}, {"LightSalmon3_2", "38;5;173", 14}, {"LightPink3", "38;5;174", 10}, {"Pink3", "38;5;175", 5}, {"Plum3", "38;5;176", 5}, {"Violet", "38;5;177", 6}, {"Gold3_2", "38;5;178", 7}, {"LightGoldenrod3", "38;5;179", 15}, {"Tan", "38;5;180", 3}, {"MistyRose3", "38;5;181", 10}, {"Thistle3", "38;5;182", 8}, {"Plum2", "38;5;183", 5}, {"Yellow3_2", "38;5;184", 9}, {"Khaki3", "38;5;185", 6}, {"LightGoldenrod2", "38;5;186", 15}, {"LightYellow3", "38;5;187", 12}, {"Grey84", "38;5;188", 6}, {"LightSteelBlue1", "38;5;189", 15}, {"Yellow2", "38;5;190", 7}, {"DarkOliveGreen1", "38;5;191", 15}, {"DarkOliveGreen1_2", "38;5;192", 17}, {"DarkSeaGreen1_2", "38;5;193", 15}, {"Honeydew2", "38;5;194", 9}, {"LightCyan1", "38;5;195", 10}, {"Red1", "38;5;196", 4}, {"DeepPink2", "38;5;197", 9}, {"DeepPink1", "38;5;198", 9}, {"DeepPink1_2", "38;5;199", 11}, {"Magenta2_2", "38;5;200", 10}, {"Magenta1", "38;5;201", 8}, {"OrangeRed1", "38;5;202", 10}, {"IndianRed1", "38;5;203", 10}, {"IndianRed1_2", "38;5;204", 12}, {"HotPink", "38;5;205", 7}, {"HotPink_2", "38;5;206", 9}, {"MediumOrchid1_2", "38;5;207", 15}, {"DarkOrange", "38;5;208", 10}, {"Salmon1", "38;5;209", 7}, {"LightCoral", "38;5;210", 10}, {"PaleVioletRed1", "38;5;211", 14}, {"Orchid2", "38;5;212", 7}, {"Orchid1", "38;5;213", 7}, {"Orange1", "38;5;214", 7}, {"SandyBrown", "38;5;215", 10}, {"LightSalmon1", "38;5;216", 12}, {"LightPink1", "38;5;217", 10}, {"Pink1", "38;5;218", 5}, {"Plum1", "38;5;219", 5}, {"Gold1", "38;5;220", 5}, {"LightGoldenrod2_2", "38;5;221", 17}, {"LightGoldenrod2_3", "38;5;222", 17}, {"NavajoWhite1", "38;5;223", 12}, {"MistyRose1", "38;5;224", 10}, {"Thistle1", "38;5;225", 8}, {"Yellow1", "38;5;226", 7}, {"LightGoldenrod1", "38;5;227", 15}, {"Khaki1", "38;5;228", 6}, {"Wheat1", "38;5;229", 6}, {"Cornsilk1", "38;5;230", 9}, {"Grey100", "38;5;231", 7}, {"Grey3", "38;5;232", 5}, {"Grey7", "38;5;233", 5}, {"Grey11", "38;5;234", 6}, {"Grey15", "38;5;235", 6}, {"Grey19", "38;5;236", 6}, {"Grey23", "38;5;237", 6}, {"Grey27", "38;5;238", 6}, {"Grey30", "38;5;239", 6}, {"Grey35", "38;5;240", 6}, {"Grey39", "38;5;241", 6}, {"Grey42", "38;5;242", 6}, {"Grey46", "38;5;243", 6}, {"Grey50", "38;5;244", 6}, {"Grey54", "38;5;245", 6}, {"Grey58", "38;5;246", 6}, {"Grey62", "38;5;247", 6}, {"Grey66", "38;5;248", 6}, {"Grey70", "38;5;249", 6}, {"Grey74", "38;5;250", 6}, {"Grey78", "38;5;251", 6}, {"Grey82", "38;5;252", 6}, {"Grey85", "38;5;253", 6}, {"Grey89", "38;5;254", 6}, {"Grey93", "38;5;255", 6}, {NULL, NULL, 0}, }; #endif /* !CLIFM_SUCKLESS */ /* Turn the first or second field of a color code sequence, provided * it is either 1 or 01 (bold attribute), into 0 (regular). * It returns no value: the change is made in place via a pointer. * STR must be a color code with this form: \x1b[xx;xx;xx... * It cannot handle the bold attribute beyond the second field. * Though this is usually enough, it's far from ideal. * * This function is used to print properties strings ('p' command * and long view mode). It takes the user defined color of the * corresponding file type (e.g., dirs) and removes the bold attribute. * Also used when running with --no-bold. */ void remove_bold_attr(char *str) { if (!str || !*str) return; char *p = str, *q = str; size_t c = 0; while (1) { if (*p == '\\' && p[1] == 'x' && p[2] == '1' && p[3] == 'b') { if (p[4]) { p += 4; q = p; continue; } else { break; } } if (*p == '[') { p++; q = p; continue; } /* Skip leading "0;" or "00;" */ if (*p == '0' && (p[1] == ';' || (p[1] == '0' && p[2] == ';'))) { p += p[1] == ';' ? 2 : 3; q = p; } if ( (*q == '0' && q[1] == '1' && (q[2] == ';' || q[2] == 'm')) || (*q == '1' && (q[1] == 'm' || q[1] == ';')) ) { if (*q == '0') q[1] = '0'; else *q = '0'; break; } if (*p == ';' && p[1]) { q = p + 1; c++; } p++; if (!*p || c >= 2) break; } } /* Return the color for the regular file FILENAME, whose attributes are A. * IF the color comes from the file extension, IS_EXT is updated to the length * of the color code (otherwise, it is set to zero). */ char * get_regfile_color(const char *filename, const struct stat *a, size_t *is_ext) { *is_ext = 0; if (conf.colorize == 0) return fi_c; if (*nf_c && check_file_access(a->st_mode, a->st_uid, a->st_gid) == 0) return nf_c; char *color = get_file_color(filename, a); /* get_file_color() is guaranteed to return a non-NULL value. */ if (color != fi_c || conf.check_ext == 0) return color; const char *ext = strrchr(filename, '.'); if (!ext) return color; size_t color_len = 0; char *extcolor = get_ext_color(ext, &color_len); if (!extcolor || color_len == 0 || color_len + 4 > sizeof(tmp_color)) return color; *tmp_color = '\x1b'; tmp_color[1] = '['; memcpy(tmp_color + 2, extcolor, color_len); tmp_color[color_len + 2] = 'm'; tmp_color[color_len + 3] = '\0'; *is_ext = color_len + 3; return tmp_color; } /* Retrieve the color corresponding to dir FILENAME whose attributes are A. * If COUNT > -1, we already know whether the directory is populatoed or not: * use this value for FILES_DIR (do not run count_dir()). */ char * get_dir_color(const char *filename, const struct stat *a, const filesn_t count) { const mode_t mode = a->st_mode; if (*nd_c && check_file_access(mode, a->st_uid, a->st_gid) == 0) return nd_c; const int sticky = (mode & S_ISVTX); const int is_oth_w = (mode & S_IWOTH); const filesn_t links = (filesn_t)a->st_nlink; /* Let's find out whether the directory is populated. A positive value * means that it is actually populated (it has at least one file, * not counting self and parent dirs). */ const filesn_t files_in_dir = count > -1 ? count : (links > 2 ? links : count_dir(filename, CPOP) - 2); if (files_in_dir < 0 && *nd_c) /* count_dir() failed. */ return nd_c; return (sticky ? (is_oth_w ? tw_c : st_c) : is_oth_w ? ow_c : (files_in_dir == 0 ? ed_c : di_c)); } char * get_file_color(const char *filename, const struct stat *a) { const mode_t mode = a->st_mode; #ifdef LINUX_FILE_CAPS cap_t cap; #else UNUSED(filename); #endif /* LINUX_FILE_CAPS */ if (mode & S_ISUID) return su_c; /* SUID */ if (mode & S_ISGID) return sg_c; /* SGID */ #ifdef LINUX_FILE_CAPS if (conf.check_cap == 1 && (cap = cap_get_file(filename))) { cap_free(cap); return ca_c; } #endif /* LINUX_FILE_CAPS */ if ((mode & S_IXUSR) || (mode & S_IXGRP) || (mode & S_IXOTH)) /* Exec */ return FILE_SIZE_PTR(a) == 0 ? ee_c : ex_c; if (a->st_nlink > 1) return mh_c; /* Multi-hardlink */ return FILE_SIZE_PTR(a) == 0 ? ef_c : fi_c; } /* Validate a hex color code string with this format: RRGGBB-[1-9] or RGB-[1-9]. */ static int is_hex_color(const char *restrict str) { if (!str || !*str) return 0; size_t c = 0; while (*str) { c++; if ((c == 7 || c == 4) && *str == '-') return !str[1] ? 0 : IS_DIGIT(str[1]); if (!IS_HEX_DIGIT(*str)) return 0; str++; } return (c == 6 || c == 3); } /* Validate a 256 color code string with this format: [0-255]-[0-9]. */ static int is_256_color(const char *restrict str) { size_t c = 0; while (str[c]) { if ((c == 0 || c == 4) && !IS_DIGIT(str[c])) return 0; if (c <= 3 && !IS_DIGIT(str[c]) && str[c] != '-') return 0; if (c == 5) return 0; c++; } if (c >= 3 && str[0] > '1' && str[1] != '-' && str[2] != '-') { if (str[0] > '2' || str[1] > '5' || (str[1] == '5' && str[2] > '5')) return 0; } return 1; } #define IS_COLOR_DELIM(c) ((c) == ':' || (c) == ';') /* Validate an SGR color sequence. Return 1 if valid or 0 otherwise. */ static int is_sgr_color(const char *restrict str) { size_t digits = 0, semicolon = 0; while (*str) { if (IS_DIGIT(*str)) { digits++; } else if (IS_COLOR_DELIM(*str)) { if (IS_COLOR_DELIM(str[1])) /* Consecutive (semi)colons. */ return 0; digits = 0; semicolon++; } else { if (*str != '\n' /* Allow styled underline (Kitty terminal). */ && !(digits > 0 && *(str - 1) == '4' && *str == ':' && str[1] >= '0' && str[1] <= '5')) /* Neither digit nor semicolon nor styled underline. */ return 0; } str++; } /* No digits at all, ending semicolon, more than 16 fields, or * more than three consecutive digits. */ if (digits == 0 || digits > 3 || semicolon > 15) return 0; /* At this point, we have a (semi)colon separated string of digits (3 * consecutive max) with at most 16 fields. The only thing not * validated here are numbers themselves. */ return 1; } #undef IS_COLOR_DELIM /* Check if STR has the format of a color code string (a number or a * semicolon list (max 16 fields) of numbers of at most 3 digits each). * Hex color codes (#RRGGBB) and 256 colors short (@NUM) are also validated. * Returns 1 if true and 0 if false. */ static int is_color_code(const char *restrict str) { if (!str || !*str) return 0; if (*str == RGB_COLOR_PREFIX) return is_hex_color(str + 1); if (*str == COLOR256_PREFIX) return is_256_color(str + 1); if (IS_DIGIT(*str)) return is_sgr_color(str); return 0; } static void check_rl_version_and_warn(void) { if (rl_readline_version >= 0x0700) return; err('w', PRINT_PROMPT, _("%s: Escape sequence detected in the " "warning prompt string: this might cause a few glichtes in the " "prompt due to some bugs in the current readline library (%s). " "Please consider removing these escape sequences (via either " "'prompt edit' or 'cs edit') or upgrading to a newer version " "of the library (>= 7.0 is recommended).\n"), PROGRAM_NAME, rl_library_version); } /* Same as update_warning_prompt_text_color() but for the new color syntax * (%{color}) */ static void update_warning_prompt_text_color_new_syntax(void) { char *start = strrchr(conf.wprompt_str, '%'); if (!start || start[1] != '{') return; start++; char *color = gen_color(&start); if (!color || !*color) { free(color); return; } /* Remove trailing \002 and leading \001 */ size_t len = strlen(color); color[len - 1] = '\0'; /* LEN is guaranteed to be > 0 */ len--; if (len < sizeof(wp_c)) { memcpy(wp_c, color + 1, len); wp_c[len] = '\0'; } free(color); check_rl_version_and_warn(); } /* Update the wp_c color code to match the last color used in the warning * prompt string. * NOTE: If we don't do this, the text entered in the warning prompt (wp_c) * won't match the warning prompt color. */ void update_warning_prompt_text_color(void) { if (!conf.wprompt_str || !*conf.wprompt_str) return; /* Let's look for the last "\e[" */ char *start = strrchr(conf.wprompt_str, '['); if (!start || start - conf.wprompt_str < 2 || *(start - 1) != 'e' || *(start - 2) != '\\' || !IS_DIGIT(start[1])) { /* Let's check the new color notation (%{color}) as well */ update_warning_prompt_text_color_new_syntax(); return; } start++; char *end = strchr(start, 'm'); if (!end) return; *end = '\0'; if (is_color_code(start)) { snprintf(wp_c, sizeof(wp_c), "\x1b[%sm", start); check_rl_version_and_warn(); } *end = 'm'; } #ifndef CLIFM_SUCKLESS /* If STR is a valid Xterm-like color name, return the value for this name. * If an attribute is appended to the name (e.g.: NAME-1), return value for this * name plus the corresponding attribute. */ static char * check_names(const char *str) { char attr = 0; char *dash = strchr(str, '-'); if (dash && dash[1]) { *dash = '\0'; attr = dash[1]; } int found = -1; const char up_str = TOUPPER(*str); const size_t len = strlen(str); for (size_t i = 0; color_names[i].name; i++) { if (up_str == *color_names[i].name /* All names start with upper case */ && color_names[i].namelen == len && strcasecmp(str + 1, color_names[i].name + 1) == 0) { found = (int)i; break; } } if (found == -1) return (char *)NULL; if (attr == 0) return color_names[found].value; snprintf(tmp_color, sizeof(tmp_color), "%c;%s", attr, color_names[found].value); return tmp_color; } /* If STR is a valid color variable name, return the value of this variable. */ static char * check_defs(const char *str) { if (defs_n == 0 || !str || !*str) return (char *)NULL; int i = (int)defs_n; const size_t slen = strlen(str); while (--i >= 0) { if (!defs[i].name || !defs[i].value || !*defs[i].name || !*defs[i].value) continue; if (*defs[i].name == *str && slen == defs[i].namelen && strcmp(defs[i].name, str) == 0 && is_color_code(defs[i].value) == 1) return defs[i].value; } return check_names(str); } /* Free custom color variables set from the color scheme file. */ static void clear_defs(void) { if (defs_n == 0) goto END; int i = (int)defs_n; while (--i >= 0) { free(defs[i].name); free(defs[i].value); } defs_n = 0; END: free(defs); defs = (struct colors_t *)NULL; } #endif /* !CLIFM_SUCKLESS */ static int bcomp(const void *a, const void *b) { size_t pa = *(size_t *)a; struct ext_t *pb = (struct ext_t *)b; if (pa < pb->hash) return (-1); if (pa > pb->hash) return 1; return 0; } /* Look for the hash HASH in the hash table for filename extensions. * Return a pointer to the corresponding color if found, or NULL. * If VAL_LEN isn't NULL, it is updated with the length of the returned value. */ static char * check_ext_hash(const size_t hash, size_t *val_len) { const struct ext_t *ptr = bsearch(&hash, ext_colors, ext_colors_n, sizeof(struct ext_t), bcomp); if (!ptr || !ptr->value || !*ptr->value) return (char *)NULL; if (val_len) *val_len = ptr->value_len; return ptr->value; } /* Return the color code associated to the file extension EXT, updating * VAL_LEN, if not NULL, to the length of this color code. */ static char * check_ext_string(const char *ext, size_t *val_len) { /* Hold extension names. NAME_MAX should be enough: no filename should * go beyond NAME_MAX, so it's pretty safe to assume that no file extension * will be larger than this. */ static char tmp_ext[NAME_MAX]; char *ptr = tmp_ext; int i; for (i = 0; i < NAME_MAX && ext[i]; i++) tmp_ext[i] = TOLOWER(ext[i]); tmp_ext[i] = '\0'; const size_t len = (size_t)i; i = (int)ext_colors_n; while (--i >= 0) { if (!ext_colors[i].name || !*ext_colors[i].name || ext_colors[i].len != len || *ptr != TOLOWER(*ext_colors[i].name)) continue; char *p = ptr + 1, *q = ext_colors[i].name + 1; size_t match = 1; while (*p) { if (*p != TOLOWER(*q)) { match = 0; break; } p++; q++; } if (match == 0 || *q != '\0') continue; if (val_len) *val_len = ext_colors[i].value_len; return ext_colors[i].value; } return (char *)NULL; } /* Return a pointer to the corresponding color code for the file * extension EXT (updating VAL_LEN to the length of this code). * The hash table is checked first if we have no hash conflicts. Otherwise, * a regular string comparison is performed to resolve it. */ char * get_ext_color(const char *ext, size_t *val_len) { if (!ext || !*ext || !*(++ext) || ext_colors_n == 0) return (char *)NULL; /* If the hash field at index 0 is set to zero, we have hash conflicts. */ if (ext_colors[0].hash != 0) return check_ext_hash(hashme(ext, 0), val_len); return check_ext_string(ext, val_len); } #ifndef CLIFM_SUCKLESS /* Strip color line from the config file, returning the same string * containing only allowed characters. */ static char * strip_color_line(const char *restrict str, const size_t str_len) { if (!str || !*str) return (char *)NULL; char *buf = xnmalloc(str_len + 1, sizeof(char)); size_t len = 0; while (*str) { if (IS_ALNUM(*str) || *str == '=' || *str == ';' || *str == ':' || *str == RGB_COLOR_PREFIX || *str == COLOR256_PREFIX || *str == '-' || *str == '_') { buf[len] = *str; len++; } str++; } if (len == 0 || !*buf) { free(buf); return (char *)NULL; } buf[len] = '\0'; return buf; } #endif /* !CLIFM_SUCKLESS */ void reset_filetype_colors(void) { *bd_c = '\0'; *bk_c = '\0'; *ca_c = '\0'; *cd_c = '\0'; *di_c = '\0'; *ed_c = '\0'; *ee_c = '\0'; *ef_c = '\0'; *ex_c = '\0'; *fi_c = '\0'; *ln_c = '\0'; *mh_c = '\0'; *nd_c = '\0'; *nf_c = '\0'; *no_c = '\0'; #ifdef SOLARIS_DOORS *oo_c = '\0'; #endif /* SOLARIS_DOORS */ *or_c = '\0'; *ow_c = '\0'; *pi_c = '\0'; *sg_c = '\0'; *so_c = '\0'; *st_c = '\0'; *su_c = '\0'; *tw_c = '\0'; *uf_c = '\0'; } void reset_iface_colors(void) { *hb_c = '\0'; *hc_c = '\0'; *hd_c = '\0'; *he_c = '\0'; *hn_c = '\0'; *hp_c = '\0'; *hq_c = '\0'; *hr_c = '\0'; *hs_c = '\0'; *hv_c = '\0'; *hw_c = '\0'; *sb_c = '\0'; *sc_c = '\0'; *sd_c = '\0'; *sf_c = '\0'; *sh_c = '\0'; *sp_c = '\0'; *sx_c = '\0'; *sz_c = '\0'; *ac_c = '\0'; *df_c = '\0'; *dl_c = '\0'; *el_c = '\0'; *em_c = '\0'; *fc_c = '\0'; *li_c = '\0'; *li_cb = '\0'; *mi_c = '\0'; *nm_c = '\0'; *ro_c = '\0'; *si_c = '\0'; *ti_c = '\0'; *tt_c = '\0'; *ts_c = '\0'; *tx_c = '\0'; *wc_c = '\0'; *wm_c = '\0'; *wp_c = '\0'; *xf_c = '\0'; *xf_cb = '\0'; *xs_c = '\0'; *xs_cb = '\0'; *ws1_c = '\0'; *ws2_c = '\0'; *ws3_c = '\0'; *ws4_c = '\0'; *ws5_c = '\0'; *ws6_c = '\0'; *ws7_c = '\0'; *ws8_c = '\0'; *db_c = '\0'; *dd_c = '\0'; *de_c = '\0'; *dg_c = '\0'; *dk_c = '\0'; *dn_c = '\0'; *do_c = '\0'; *dp_c = '\0'; *dr_c = '\0'; *dt_c = '\0'; *du_c = '\0'; *dw_c = '\0'; *dxd_c = '\0'; *dxr_c = '\0'; *dz_c = '\0'; } /* Import the color scheme NAME from DATADIR (usually /usr/local/share). * Return zero on success or one on failure. */ int import_color_scheme(const char *name) { if (!data_dir || !*data_dir || !colors_dir || !*colors_dir || !name || !*name) return FUNC_FAILURE; char dfile[PATH_MAX + 1]; snprintf(dfile, sizeof(dfile), "%s/%s/colors/%s.clifm", data_dir, PROGRAM_NAME, name); struct stat a; if (stat(dfile, &a) == -1 || !S_ISREG(a.st_mode)) return FUNC_FAILURE; char *cmd[] = {"cp", "--", dfile, colors_dir, NULL}; const mode_t old_mask = umask(0077); /* flawfinder: ignore */ const int ret = launch_execv(cmd, FOREGROUND, E_NOFLAG); umask(old_mask); /* flawfinder: ignore */ return ret == FUNC_SUCCESS ? ret : FUNC_FAILURE; } #ifndef CLIFM_SUCKLESS static int list_colorschemes(void) { if (cschemes_n == 0) { puts(_("cs: No color scheme found")); return FUNC_SUCCESS; } const char *ptr = SET_MISC_PTR; size_t i; for (i = 0; color_schemes[i]; i++) { if (cur_cscheme == color_schemes[i]) { printf("%s%s%s %s%s\n", mi_c, ptr, df_c, color_schemes[i], ON_LSCOLORS); } else { printf(" %s\n", color_schemes[i]); } } return FUNC_SUCCESS; } /* Edit the current color scheme file. * If the file is not in the local colors dir, try to copy it from DATADIR. * into the local dir to avoid permission issues. */ static int edit_colorscheme(char *app) { if (!colors_dir) { xerror("%s\n", _("cs: No color scheme found")); return FUNC_FAILURE; } if (!cur_cscheme) { xerror("%s\n", _("cs: Current color scheme is unknown")); return FUNC_FAILURE; } struct stat attr; char file[PATH_MAX + 1]; int ret = 0; snprintf(file, sizeof(file), "%s/%s.clifm", colors_dir, cur_cscheme); if ((ret = stat(file, &attr)) == -1 && import_color_scheme(cur_cscheme) != FUNC_SUCCESS) { xerror(_("cs: '%s': No such color scheme\n"), cur_cscheme); return FUNC_FAILURE; } /* If the file was imported, get its attributes. */ if (ret == -1 && stat(file, &attr) == -1) { xerror("cs: '%s': %s\n", file, strerror(errno)); return errno; } const time_t mtime_bfr = attr.st_mtime; ret = open_config_file(app, file); if (ret != FUNC_SUCCESS) return ret; if (stat(file, &attr) == -1) { xerror("cs: '%s': %s\n", file, strerror(errno)); return errno; } if (mtime_bfr != attr.st_mtime && set_colors(cur_cscheme, 0) == FUNC_SUCCESS) { set_fzf_preview_border_type(); if (conf.autols == 1) reload_dirlist(); } return ret; } static int set_colorscheme(char *arg) { if (!arg || !*arg) return FUNC_FAILURE; char *p = unescape_str(arg, 0); char *q = p ? p : arg; size_t cs_found = 0; for (size_t i = 0; color_schemes[i]; i++) { if (*q != *color_schemes[i] || strcmp(q, color_schemes[i]) != 0) continue; cs_found = 1; if (set_colors(q, 0) != FUNC_SUCCESS) continue; cur_cscheme = color_schemes[i]; switch_cscheme = 1; if (conf.autols == 1) reload_dirlist(); switch_cscheme = 0; free(p); return FUNC_SUCCESS; } if (cs_found == 0) xerror(_("cs: '%s': No such color scheme\n"), p); free(p); return FUNC_FAILURE; } #endif /* !CLIFM_SUCKLESS */ static char * get_color_scheme_name(void) { if (cur_cscheme && *cur_cscheme) return cur_cscheme; if (term_caps.color >= 256) return _("builtin (256 colors)"); return _("builtin (8 colors)"); } static int print_colors_tip(const int stealth) { xerror(_("%s: %s.\nTIP: To edit the " "color scheme use the following environment " "variables: CLIFM_FILE_COLORS, CLIFM_IFACE_COLORS, " "and CLIFM_EXT_COLORS.\nFor example:\n\n" "CLIFM_FILE_COLORS=\"di=31:ln=33:\" CLIFM_IFACE_COLORS=\"el=35:fc=34:\" " "CLIFM_EXT_COLORS=\"*.c=1;33:*.odt=4;35:\" clifm\n\n" "Consult the manpage for more information.\n"), PROGRAM_NAME, stealth == 1 ? STEALTH_DISABLED : NOT_AVAILABLE); return FUNC_FAILURE; } static void print_ext_conflict(const char *a, const char *b) { if (!a || !b) return; if (*a == *b && strcmp(a, b) == 0) printf(_("'%s' has conflicting definitions\n"), a); else printf(_("'%s' conflicts with '%s'\n"), a, b); } /* Make sure hashes for filename extensions do not conflict. * CS_CHECK is 0 when this function is called at startup: if a hash conflict * is found, the hash field at index zero (of the ext_colors struct) is set * to 0 to indicate that we must use regular string comparison (slower). * CS_CHECK is 1 when the function is invoked by the 'cs check-ext' command. * It returns FUNC_FAILURE in case of conflicts, or FUNC_SUCCESS otherwise. */ static int check_ext_color_hash_conflicts(const int cs_check) { size_t conflicts = 0; for (size_t i = 0; i < ext_colors_n; i++) { for (size_t j = i + 1; j < ext_colors_n; j++) { if (ext_colors[i].hash != ext_colors[j].hash) continue; if (ext_colors[i].value_len == ext_colors[j].value_len && strcmp(ext_colors[i].value, ext_colors[j].value) == 0) /* Two extensions with the same hash, but pointing to the * same color. Most likely a duplicate entry: let it be. */ continue; if (cs_check == 1) { print_ext_conflict(ext_colors[i].name, ext_colors[j].name); conflicts++; continue; } ext_colors[0].hash = 0; err('w', PRINT_PROMPT, _("%s: File extension conflicts " "found. Run 'cs check-ext' to see the details.\n"), PROGRAM_NAME); return FUNC_FAILURE; } } if (cs_check == 0) return FUNC_SUCCESS; if (conflicts > 0) { if (xargs.lscolors != LS_COLORS_GNU) puts(_("Run 'cs edit' to fix these conflicts")); return FUNC_FAILURE; } puts(_("cs: No conflicts found")); return FUNC_SUCCESS; } int cschemes_function(char **args) { #ifdef CLIFM_SUCKLESS UNUSED(args); print_colors_tip(0); fputs(_("\nYou can also edit 'settings.h' in the source code and " "recompile.\n"), stderr); return FUNC_FAILURE; #else if (!args) return FUNC_FAILURE; if (args[1] && *args[1] == 'p' && (!args[1][1] || strcmp(args[1], "preview") == 0)) { color_codes(); return FUNC_SUCCESS; } if (args[1] && *args[1] == 'n' && (!args[1][1] || strcmp(args[1], "name") == 0)) { printf(_("Current color scheme: '%s'\n"), get_color_scheme_name()); return FUNC_SUCCESS; } if (args[1] && *args[1] == 'c' && strcmp(args[1], "check-ext") == 0) return check_ext_color_hash_conflicts(1); if (args[1] && IS_HELP(args[1])) { puts(_(CS_USAGE)); return FUNC_SUCCESS; } if (xargs.stealth_mode == 1) return print_colors_tip(1); if (conf.colorize == 0) { printf(_("%s: Colors are disabled\n"), PROGRAM_NAME); return FUNC_FAILURE; } if (!args[1]) return list_colorschemes(); if (*args[1] == 'e' && (!args[1][1] || strcmp(args[1], "edit") == 0)) return edit_colorscheme(args[2]); const int ret = set_colorscheme(args[1]); update_autocmd_opts(AC_COLOR_SCHEME); return ret; #endif /* CLIFM_SUCKLESS */ } /* Convert a @NUM color string to the proper ANSI code representation. * Returns a pointer to the converted string on success or NULL on error. */ static char * color256_to_ansi(char *s) { if (!s || !*s || !s[1]) return (char *)NULL; int attr = -1; char *dash = strchr(s + 1, '-'); if (dash) { *dash = '\0'; if (IS_DIGIT(dash[1]) && !dash[2]) attr = dash[1] - '0'; } char *ret = (char *)NULL; const int n = atoi(s + 1); if (n >= 0 && n <= 255) { if (attr == -1) /* No attribute */ snprintf(tmp_color, sizeof(tmp_color), "38;5;%d", n); else snprintf(tmp_color, sizeof(tmp_color), "%d;38;5;%d", attr, n); ret = tmp_color; } if (dash) *dash = '-'; return ret; } /* Decode the prefixed color string S to the proper ANSI representation. * Returns a pointer to the decoded string on success, or NULL on error. */ static char * decode_color_prefix(char *s) { if (!s || !*s) return (char *)NULL; if (*s == RGB_COLOR_PREFIX) return hex2rgb(s); if (*s == COLOR256_PREFIX) return color256_to_ansi(s); return (char *)NULL; } /* Return a pointer to a statically allocated buffer storing the color code * S with starting \001 and ending \002 removed. */ static char * remove_ctrl_chars(char *s) { if (*s != 001) return s; xstrsncpy(tmp_color, s + 1, sizeof(tmp_color)); const size_t l = strlen(tmp_color); if (l > 0 && tmp_color[l - 1] == 002) tmp_color[l - 1] = '\0'; return tmp_color; } /* Set color variable VAR (static global) to COLOR. * If not printable, add non-printing char flags (\001 and \002). */ static void set_color(char *color, char var[], const int flag) { #ifndef CLIFM_SUCKLESS char *def_color = (char *)NULL; if (is_color_code(color) == 0 && (def_color = check_defs(color)) == NULL) #else if (is_color_code(color) == 0) #endif /* !CLIFM_SUCKLESS */ { /* A NULL color string will be set to the default value by * set_default_colors function. */ *var = '\0'; return; } #ifndef CLIFM_SUCKLESS char *p = def_color ? def_color : color; #else char *p = color; #endif /* !CLIFM_SUCKLESS */ char *s = (char *)NULL; if (IS_COLOR_PREFIX(*p) && !(s = decode_color_prefix(p))) { *var = '\0'; return; } if (flag == RL_NO_PRINTABLE) snprintf(var, MAX_COLOR + 2, "\001\x1b[%sm\002", s ? s : p); else snprintf(var, MAX_COLOR - 1, "\x1b[0;%sm", s ? s : p); } static void set_filetype_colors(char **colors, const size_t num_colors) { if (!colors || num_colors == 0) return; const int p = RL_PRINTABLE; const struct color_mapping_t mappings[] = { {"bd", bd_c, 2, p}, {"ca", ca_c, 2, p}, {"cd", cd_c, 2, p}, {"di", di_c, 2, p}, {"ed", ed_c, 2, p}, {"ee", ee_c, 2, p}, {"ef", ef_c, 2, p}, {"ex", ex_c, 2, p}, {"fi", fi_c, 2, p}, {"ln", ln_c, 2, p}, {"mh", mh_c, 2, p}, {"mi", uf_c, 2, p}, {"nd", nd_c, 2, p}, {"nf", nf_c, 2, p}, {"no", no_c, 2, p}, {"or", or_c, 2, p}, {"ow", ow_c, 2, p}, #ifdef SOLARIS_DOORS {"oo", oo_c, 2, p}, #endif /* SOLARIS_DOORS */ {"pi", pi_c, 2, p}, {"sg", sg_c, 2, p}, {"so", so_c, 2, p}, {"st", st_c, 2, p}, {"su", su_c, 2, p}, {"tw", tw_c, 2, p}, {"uf", uf_c, 2, p}, }; const size_t mappings_n = sizeof(mappings) / sizeof(struct color_mapping_t); for (size_t i = 0; i < num_colors; i++) { if (!colors[i] || !colors[i][1] || colors[i][2] != '=') { free(colors[i]); continue; } char *color_code = colors[i] + 3; for (size_t j = 0; j < mappings_n; j++) { if (*colors[i] == *mappings[j].prefix && colors[i][1] == mappings[j].prefix[1]) { set_color(color_code, mappings[j].color, mappings[j].printable); break; } } free(colors[i]); } free(colors); } static void set_iface_colors(char **colors, const size_t num_colors) { if (!colors || num_colors == 0) return; const int y = RL_PRINTABLE; const int n = RL_NO_PRINTABLE; const struct color_mapping_t mappings[] = { {"ac", ac_c, 2, n}, {"dxd", dxd_c, 3, y}, {"dxr", dxr_c, 3, y}, {"db", db_c, 2, y}, {"dd", dd_c, 2, y}, {"de", de_c, 2, y}, {"df", df_c, 2, y}, {"dg", dg_c, 2, y}, {"dk", dk_c, 2, y}, {"dl", dl_c, 2, y}, {"dn", dn_c, 2, y}, {"do", do_c, 2, y}, {"dp", dp_c, 2, y}, {"dr", dr_c, 2, y}, {"dt", dt_c, 2, y}, {"du", du_c, 2, y}, {"dw", dw_c, 2, y}, {"dz", dz_c, 2, y}, {"el", el_c, 2, y}, {"em", em_c, 2, n}, {"fc", fc_c, 2, y}, {"hb", hb_c, 2, y}, {"hc", hc_c, 2, y}, {"hd", hd_c, 2, y}, {"he", he_c, 2, y}, {"hn", hn_c, 2, y}, {"hp", hp_c, 2, y}, {"hq", hq_c, 2, y}, {"hr", hr_c, 2, y}, {"hs", hs_c, 2, y}, {"hv", hv_c, 2, y}, {"hw", hw_c, 2, y}, {"li", li_c, 2, n}, {"lc", lc_c, 2, y}, {"mi", mi_c, 2, y}, {"nm", nm_c, 2, n}, {"ro", ro_c, 2, n}, {"sb", sb_c, 2, y}, {"sc", sc_c, 2, y}, {"sd", sd_c, 2, y}, {"sh", sh_c, 2, y}, {"si", si_c, 2, n}, {"sf", sf_c, 2, y}, {"sp", sp_c, 2, y}, {"sx", sx_c, 2, y}, {"sz", sz_c, 2, y}, {"ti", ti_c, 2, n}, {"ts", ts_c, 2, y}, {"tt", tt_c, 2, y}, {"tx", tx_c, 2, y}, {"wc", wc_c, 2, y}, {"wm", wm_c, 2, n}, {"wp", wp_c, 2, y}, {"ws1", ws1_c, 3, n}, {"ws2", ws2_c, 3, n}, {"ws3", ws3_c, 3, n}, {"ws4", ws4_c, 3, n}, {"ws5", ws5_c, 3, n}, {"ws6", ws6_c, 3, n}, {"ws7", ws7_c, 3, n}, {"ws8", ws8_c, 3, n}, {"xs", xs_c, 2, n}, {"xf", xf_c, 2, n}, }; const size_t mappings_n = sizeof(mappings) / sizeof(struct color_mapping_t); for (size_t i = 0; i < num_colors; i++) { for (size_t j = 0; j < mappings_n; j++) { if (*colors[i] == *mappings[j].prefix && strncmp(colors[i], mappings[j].prefix, (size_t)mappings[j].prefix_len) == 0 && *(colors[i] + mappings[j].prefix_len) == '=') { set_color(colors[i] + mappings[j].prefix_len + 1, mappings[j].color, mappings[j].printable); break; } } free(colors[i]); } free(colors); /* We need a copy of these colors without \001 and \002 escape codes. */ if (*li_c) { const char *p = remove_ctrl_chars(li_c); xstrsncpy(li_cb, p, sizeof(li_cb)); } if (*xs_c) { const char *p = remove_ctrl_chars(xs_c); xstrsncpy(xs_cb, p, sizeof(xs_cb)); } if (*xf_c) { const char *p = remove_ctrl_chars(xf_c); xstrsncpy(xf_cb, p, sizeof(xf_cb)); } } static void set_shades(char *line, const int type) { char *l = remove_quotes(line); if (!l || !*l) return; char *str = strtok(l, ","); if (!str || !*str) return; int t = *str - '0'; if (t < 0 || t > 3) return; if (type == DATE_SHADES) date_shades.type = (uint8_t)t; else size_shades.type = (uint8_t)t; int c = 0; while ((str = strtok(NULL, ",")) && c < NUM_SHADES) { if (*str == '#') { if (!str[1] || t != SHADE_TYPE_TRUECOLOR) goto NEXT; int a = 0, r = 0, g = 0, b = 0; if (get_rgb(str + 1, &a, &r, &g, &b) == -1) goto NEXT; if (type == DATE_SHADES) { date_shades.shades[c].attr = (uint8_t)a; date_shades.shades[c].R = (uint8_t)r; date_shades.shades[c].G = (uint8_t)g; date_shades.shades[c].B = (uint8_t)b; } else { size_shades.shades[c].attr = (uint8_t)a; size_shades.shades[c].R = (uint8_t)r; size_shades.shades[c].G = (uint8_t)g; size_shades.shades[c].B = (uint8_t)b; } goto NEXT; } if (t == SHADE_TYPE_TRUECOLOR) goto NEXT; char *p = strchr(str, '-'); uint8_t color_attr = 0; if (p) { *p = '\0'; if (p[1] && IS_DIGIT(p[1]) && !p[2]) color_attr = (uint8_t)(p[1] - '0'); } const int n = atoi(str); if (n < 0 || n > 255) goto NEXT; if (type == DATE_SHADES) { date_shades.shades[c].attr = color_attr; date_shades.shades[c].R = (uint8_t)n; } else { size_shades.shades[c].attr = color_attr; size_shades.shades[c].R = (uint8_t)n; } NEXT: c++; } /* Handle old-style 8 color shades (only 3 available) */ if (type == DATE_SHADES) date_shades_old_style = (c - 1 == 3); else size_shades_old_style = (c - 1 == 3); } static void set_default_date_shades(void) { char tmp[NAME_MAX]; snprintf(tmp, sizeof(tmp), "%s", term_caps.color >= 256 ? DEF_DATE_SHADES_256 : DEF_DATE_SHADES_8); set_shades(tmp, DATE_SHADES); } static void set_default_size_shades(void) { char tmp[NAME_MAX]; snprintf(tmp, sizeof(tmp), "%s", term_caps.color >= 256 ? DEF_SIZE_SHADES_256 : DEF_SIZE_SHADES_8); set_shades(tmp, SIZE_SHADES); } /* Check if LINE contains a valid color code, and store it in the * ext_colors global array. * If LINE contains a color variable, expand it, check it, and store it. */ static int store_extension_line(const char *line) { if (!line || !*line) return FUNC_FAILURE; /* If --lscolors, make sure all lines have the form "*.ext" */ if (xargs.lscolors == LS_COLORS_GNU && (*line != '*' || line[1] != '.' || !line[2] || strchr(line + 2, '.'))) return FUNC_FAILURE; /* Remove the leading "*.", if any, from the extension line. */ if (*line == '*' && line[1] == '.') { line += 2; if (!*line) return FUNC_FAILURE; } char *q = strchr(line, '='); if (!q || !q[1] || q == line) return FUNC_FAILURE; *q = '\0'; char *def = (char *)NULL; #ifndef CLIFM_SUCKLESS if (is_color_code(q + 1) == 0 && (def = check_defs(q + 1)) == NULL) #else if (is_color_code(q + 1) == 0) #endif /* !CLIFM_SUCKLESS */ return FUNC_FAILURE; char *tmp = (def && *def) ? def : q + 1; char *code = IS_COLOR_PREFIX(*tmp) ? decode_color_prefix(tmp) : tmp; if (!code || !*code) return FUNC_FAILURE; ext_colors = xnrealloc(ext_colors, ext_colors_n + 2, sizeof(struct ext_t)); const size_t len = (size_t)(q - line); ext_colors[ext_colors_n].len = len; ext_colors[ext_colors_n].name = savestring(line, len); const size_t elen = strlen(code) + 3; ext_colors[ext_colors_n].value = xnmalloc(elen, sizeof(char)); snprintf(ext_colors[ext_colors_n].value, elen, "0;%s", code); ext_colors[ext_colors_n].value_len = elen - 1; ext_colors[ext_colors_n].hash = hashme(line, 0); if (xargs.no_bold == 1) remove_bold_attr(ext_colors[ext_colors_n].value); *q = '='; ext_colors_n++; return FUNC_SUCCESS; } static void free_extension_colors(void) { int i = (int)ext_colors_n; while (--i >= 0) { free(ext_colors[i].name); free(ext_colors[i].value); } free(ext_colors); ext_colors = (struct ext_t *)NULL; ext_colors_n = 0; } static void split_extension_colors(char *extcolors) { char *p = extcolors; char buf[MAX_COLOR + 3 + NAME_MAX]; /* "*.NAME=COLOR" */ *buf = '\0'; size_t len = 0; int eol = 0; free_extension_colors(); while (eol == 0) { switch (*p) { case '\0': /* fallthrough */ case '\n': /* fallthrough */ case ':': if (!*buf) { if (!*p || !p[1]) eol = 1; else p++; break; } buf[len] = '\0'; if (store_extension_line(buf) == FUNC_SUCCESS) *buf = '\0'; if (!*p) eol = 1; len = 0; p++; break; default: if (len >= sizeof(buf)) { p++; break; } buf[len] = *p; len++; p++; break; } } p = (char *)NULL; if (ext_colors) { ext_colors[ext_colors_n].name = (char *)NULL; ext_colors[ext_colors_n].value = (char *)NULL; ext_colors[ext_colors_n].len = 0; ext_colors[ext_colors_n].value_len = 0; ext_colors[ext_colors_n].hash = 0; check_ext_color_hash_conflicts(0); } } #define CVAR(s) (term_caps.color >= 256 ? DEF_ ## s ## _C256 : DEF_ ## s ## _C) /* NOLINT */ /* We're running with --lscolors. Let's disable clifm's specific file type * colors by just using the closest ones provided by LS_COLORS. */ static void set_extra_colors(void) { if (*di_c) { xstrsncpy(ed_c, di_c, sizeof(ed_c)); /* Empty dir */ xstrsncpy(nd_c, di_c, sizeof(nd_c)); /* No perm dir */ } else { xstrsncpy(ed_c, CVAR(DI), sizeof(ed_c)); /* NOLINT */ xstrsncpy(nd_c, CVAR(DI), sizeof(nd_c)); /* NOLINT */ } if (*ex_c) xstrsncpy(ee_c, ex_c, sizeof(ee_c)); /* Empty executable */ else xstrsncpy(ee_c, CVAR(EX), sizeof(ee_c)); /* NOLINT */ if (*fi_c) { xstrsncpy(ef_c, fi_c, sizeof(ef_c)); /* Empty file */ xstrsncpy(nf_c, fi_c, sizeof(nf_c)); /* No perm file */ } else { xstrsncpy(ef_c, CVAR(FI), sizeof(ef_c)); /* NOLINT */ xstrsncpy(nf_c, CVAR(FI), sizeof(nf_c)); /* NOLINT */ } } static int hash_sort(const void *a, const void *b) { struct ext_t *pa = (struct ext_t *)a; struct ext_t *pb = (struct ext_t *)b; if (pa->hash > pb->hash) return 1; if (pa->hash < pb->hash) return -1; return 0; } void set_default_colors(void) { if (size_shades.type == SHADE_TYPE_UNSET) set_default_size_shades(); if (date_shades.type == SHADE_TYPE_UNSET) set_default_date_shades(); if (xargs.lscolors > 0) set_extra_colors(); if (!ext_colors) split_extension_colors(term_caps.color >= 256 ? DEF_EXT_COLORS_256 : DEF_EXT_COLORS); if (ext_colors && ext_colors_n > 0) { qsort(ext_colors, ext_colors_n, sizeof(*ext_colors), (QSFUNC *)hash_sort); } /* If a definition for TEMP exists in the color scheme file, BK_C should * have been set to this color in store_defintions(). If not, let's try * with EF_C (empty file color). Otherwise, fallback to the default * color for empty files (DEF_EF_C). */ if (!*bk_c) xstrsncpy(bk_c, *ef_c ? ef_c : CVAR(EF), sizeof(bk_c)); /* Highlight */ if (!*hb_c) xstrsncpy(hb_c, CVAR(HB), sizeof(hb_c)); if (!*hc_c) xstrsncpy(hc_c, CVAR(HC), sizeof(hc_c)); if (!*hd_c) xstrsncpy(hd_c, CVAR(HD), sizeof(hd_c)); if (!*he_c) xstrsncpy(he_c, CVAR(HE), sizeof(he_c)); if (!*hn_c) xstrsncpy(hn_c, CVAR(HN), sizeof(hn_c)); if (!*hp_c) xstrsncpy(hp_c, CVAR(HP), sizeof(hp_c)); if (!*hq_c) xstrsncpy(hq_c, CVAR(HQ), sizeof(hq_c)); if (!*hr_c) xstrsncpy(hr_c, CVAR(HR), sizeof(hr_c)); if (!*hs_c) xstrsncpy(hs_c, CVAR(HS), sizeof(hs_c)); if (!*hv_c) xstrsncpy(hv_c, CVAR(HV), sizeof(hv_c)); if (!*hw_c) xstrsncpy(hw_c, CVAR(HW), sizeof(hw_c)); /* Suggestions */ if (!*sb_c) xstrsncpy(sb_c, CVAR(SB), sizeof(sb_c)); if (!*sc_c) xstrsncpy(sc_c, CVAR(SC), sizeof(sc_c)); if (!*sd_c) xstrsncpy(sd_c, CVAR(SD), sizeof(sd_c)); if (!*sh_c) xstrsncpy(sh_c, CVAR(SH), sizeof(sh_c)); if (!*sf_c) xstrsncpy(sf_c, CVAR(SF), sizeof(sf_c)); if (!*sx_c) xstrsncpy(sx_c, CVAR(SX), sizeof(sx_c)); if (!*sp_c) xstrsncpy(sp_c, CVAR(SP), sizeof(sp_c)); if (!*sz_c) xstrsncpy(sz_c, CVAR(SZ), sizeof(sz_c)); /* Interface */ if (!*df_c) xstrsncpy(df_c, CVAR(DF), sizeof(df_c)); /* If unset from the config file, use current workspace color */ if (!*dl_c) #ifndef CLIFM_SUCKLESS if (config_ok == 0) xstrsncpy(dl_c, CVAR(DL), sizeof(dl_c)); #else xstrsncpy(dl_c, CVAR(DL), sizeof(dl_c)); #endif /* !CLIFM_SUCKLESS */ if (!*el_c) xstrsncpy(el_c, CVAR(EL), sizeof(el_c)); if (!*em_c) xstrsncpy(em_c, CVAR(EM), sizeof(em_c)); if (!*fc_c) xstrsncpy(fc_c, CVAR(FC), sizeof(fc_c)); if (!*lc_c) xstrsncpy(lc_c, CVAR(LC), sizeof(lc_c)); if (!*li_c) xstrsncpy(li_c, CVAR(LI), sizeof(li_c)); if (!*li_cb) xstrsncpy(li_cb, term_caps.color >= 256 ? DEF_LI_CB256: DEF_LI_CB, sizeof(li_cb)); /* NOLINT */ if (!*mi_c) xstrsncpy(mi_c, CVAR(MI), sizeof(mi_c)); if (!*nm_c) xstrsncpy(nm_c, CVAR(NM), sizeof(nm_c)); if (!*ti_c) xstrsncpy(ti_c, CVAR(TI), sizeof(ti_c)); if (!*tx_c) xstrsncpy(tx_c, CVAR(TX), sizeof(tx_c)); if (!*wm_c) xstrsncpy(wm_c, CVAR(WM), sizeof(wm_c)); if (!*ro_c) xstrsncpy(ro_c, CVAR(RO), sizeof(ro_c)); if (!*si_c) xstrsncpy(si_c, CVAR(SI), sizeof(si_c)); if (!*ts_c) xstrsncpy(ts_c, CVAR(TS), sizeof(ts_c)); if (!*tt_c) xstrsncpy(tt_c, CVAR(TT), sizeof(tt_c)); if (!*wc_c) xstrsncpy(wc_c, CVAR(WC), sizeof(wc_c)); if (!*wp_c) xstrsncpy(wp_c, CVAR(WP), sizeof(wp_c)); if (!*ws1_c) xstrsncpy(ws1_c, CVAR(WS1), sizeof(ws1_c)); if (!*ws2_c) xstrsncpy(ws2_c, CVAR(WS2), sizeof(ws2_c)); if (!*ws3_c) xstrsncpy(ws3_c, CVAR(WS3), sizeof(ws3_c)); if (!*ws4_c) xstrsncpy(ws4_c, CVAR(WS4), sizeof(ws4_c)); if (!*ws5_c) xstrsncpy(ws5_c, CVAR(WS5), sizeof(ws5_c)); if (!*ws6_c) xstrsncpy(ws6_c, CVAR(WS6), sizeof(ws6_c)); if (!*ws7_c) xstrsncpy(ws7_c, CVAR(WS7), sizeof(ws7_c)); if (!*ws8_c) xstrsncpy(ws8_c, CVAR(WS8), sizeof(ws8_c)); if (!*xs_c) xstrsncpy(xs_c, CVAR(XS), sizeof(xs_c)); if (!*xs_cb) xstrsncpy(xs_cb, term_caps.color >= 256 ? DEF_XS_CB256 : DEF_XS_CB, sizeof(xs_cb)); /* NOLINT */ if (!*xf_c) xstrsncpy(xf_c, CVAR(XF), sizeof(xf_c)); if (!*xf_cb) xstrsncpy(xf_cb, term_caps.color >= 256 ? DEF_XF_CB256 : DEF_XF_CB, sizeof(xf_cb)); /* NOLINT */ /* File types */ if (!*bd_c) xstrsncpy(bd_c, CVAR(BD), sizeof(bd_c)); if (!*ca_c) xstrsncpy(ca_c, CVAR(CA), sizeof(ca_c)); if (!*cd_c) xstrsncpy(cd_c, CVAR(CD), sizeof(cd_c)); if (!*di_c) xstrsncpy(di_c, CVAR(DI), sizeof(di_c)); if (!*ed_c) xstrsncpy(ed_c, CVAR(ED), sizeof(ed_c)); if (!*ee_c) xstrsncpy(ee_c, CVAR(EE), sizeof(ee_c)); if (!*ex_c) xstrsncpy(ex_c, CVAR(EX), sizeof(ex_c)); if (!*fi_c) xstrsncpy(fi_c, CVAR(FI), sizeof(fi_c)); if (!*ef_c) xstrsncpy(ef_c, CVAR(EF), sizeof(ef_c)); if (!*ln_c) xstrsncpy(ln_c, CVAR(LN), sizeof(ln_c)); if (!*mh_c) xstrsncpy(mh_c, CVAR(MH), sizeof(mh_c)); /* Both 'nd' and 'nf' codes can be unset */ if (!*no_c) xstrsncpy(no_c, CVAR(NO), sizeof(no_c)); #ifdef SOLARIS_DOORS if (!*oo_c) xstrsncpy(oo_c, CVAR(OO), sizeof(oo_c)); #endif /* SOLARIS_DOORS */ if (!*or_c) xstrsncpy(or_c, CVAR(OR), sizeof(or_c)); if (!*ow_c) xstrsncpy(ow_c, CVAR(OW), sizeof(ow_c)); if (!*pi_c) xstrsncpy(pi_c, CVAR(PI), sizeof(pi_c)); if (!*sg_c) xstrsncpy(sg_c, CVAR(SG), sizeof(sg_c)); if (!*so_c) xstrsncpy(so_c, CVAR(SO), sizeof(so_c)); if (!*st_c) xstrsncpy(st_c, CVAR(ST), sizeof(st_c)); if (!*su_c) xstrsncpy(su_c, CVAR(SU), sizeof(su_c)); if (!*tw_c) xstrsncpy(tw_c, CVAR(TW), sizeof(tw_c)); if (!*uf_c) xstrsncpy(uf_c, CVAR(UF), sizeof(uf_c)); /* Interface */ /* if (!*dd_c) // Date color unset: let's use shades */ if (!*ac_c) xstrsncpy(ac_c, CVAR(AC), sizeof(ac_c)); if (!*db_c) xstrsncpy(db_c, CVAR(DB), sizeof(db_c)); if (!*de_c) xstrsncpy(de_c, CVAR(DE), sizeof(de_c)); if (!*dg_c) xstrsncpy(dg_c, *du_c ? CVAR(DG) : CVAR(DU), sizeof(dg_c)); if (!*dk_c) xstrsncpy(dk_c, CVAR(DK), sizeof(dk_c)); if (!*dn_c) xstrsncpy(dn_c, CVAR(DN), sizeof(dn_c)); if (!*do_c) xstrsncpy(do_c, CVAR(DO), sizeof(do_c)); if (!*dp_c) xstrsncpy(dp_c, CVAR(DP), sizeof(dp_c)); if (!*dr_c) xstrsncpy(dr_c, CVAR(DR), sizeof(dr_c)); if (!*dt_c) /* Unset: dim the current color */ xstrsncpy(dt_c, dim_c, sizeof(dt_c)); if (!*du_c) { /* Before the introduction of the du color code, user IDs were * printed using the dg color code, and group IDs using the same * color but dimmed. If du isn't set, let's keep this old behavior. */ xstrsncpy(du_c, dg_c, sizeof(du_c)); xstrsncpy(dg_c, dim_c, sizeof(dg_c)); } if (!*dw_c) xstrsncpy(dw_c, CVAR(DW), sizeof(dw_c)); if (!*dxd_c) xstrsncpy(dxd_c, CVAR(DXD), sizeof(dxd_c)); if (!*dxr_c) xstrsncpy(dxr_c, CVAR(DXR), sizeof(dxr_c)); /* if (!*dz_c) // Size color unset: let's use shades */ #ifndef _NO_ICONS if (!*dir_ico_c) xstrsncpy(dir_ico_c, CVAR(DIR_ICO), sizeof(dir_ico_c)); #endif /* !_NO_ICONS */ } #undef CVAR /* Set a pointer to the current color scheme */ static int get_cur_colorscheme(const char *colorscheme) { char *def_cscheme = (char *)NULL; int i = (int)cschemes_n; while (--i >= 0) { if (*colorscheme == *color_schemes[i] && strcmp(colorscheme, color_schemes[i]) == 0) { cur_cscheme = color_schemes[i]; break; } if (strcmp(color_schemes[i], term_caps.color < 256 ? DEF_COLOR_SCHEME : DEF_COLOR_SCHEME_256) == 0) def_cscheme = color_schemes[i]; } if (!cur_cscheme) { err('w', PRINT_PROMPT, _("%s: colors: %s: No such color scheme. " "Falling back to default\n"), PROGRAM_NAME, colorscheme); if (def_cscheme) cur_cscheme = def_cscheme; else return FUNC_FAILURE; } return FUNC_SUCCESS; } static const char * bsd_to_ansi_color(char color, const int bg) { char c = color; int up = 0; if (IS_ALPHA_UP(color)) { up = 1; c = (char)TOLOWER(color); } /* An uppercase letter for background sets the underline attribute. * We follow here the FreeBSD implementation of ls(1). */ switch (c) { case 'a': return (bg ? (up ? "4;40" : "40") : (up ? "1;30" : "30")); case 'b': return (bg ? (up ? "4;41" : "41") : (up ? "1;31" : "31")); case 'c': return (bg ? (up ? "4;42" : "42") : (up ? "1;32" : "32")); case 'd': return (bg ? (up ? "4;43" : "43") : (up ? "1;33" : "33")); case 'e': return (bg ? (up ? "4;44" : "44") : (up ? "1;34" : "34")); case 'f': return (bg ? (up ? "4;45" : "45") : (up ? "1;35" : "35")); case 'g': return (bg ? (up ? "4;46" : "46") : (up ? "1;36" : "36")); case 'h': return (bg ? (up ? "4;47" : "47") : (up ? "1;37" : "37")); case 'x': return (bg ? (up ? "4;49" : "49") : "39"); default: return (bg ? "49" : "39"); /* Never reached */ } } static const char * set_filetype(const int c) { static const char *filetypes[] = {"di", "ln", "so", "pi", "ex", "bd", "cd", "su", "sg", "tw", "ow", NULL}; /* C is guaranteed to be < 11 */ return filetypes[c]; } /* If the LSCOLORS environment variable is set, convert its value to a valid * GNU LS_COLORS format. * Returns a pointer to the transformed string, or NULL in case of error. * For information about the format used by LSCOLORS consult * 'https://www.unix.com/man-page/FreeBSD/1/ls'. */ static char * set_lscolors_bsd(void) { char *env = getenv("LSCOLORS"); if (!env) return (char *)NULL; /* 144 bytes are required to hold the largest possible value for LSCOLORS: * 11 file types, 13 chars max each, plus the terminating NUL char. * However, more often than not these kind hard limits fail: let's use * something a bit bigger. */ static char buf[256]; size_t c = 0; int f = 0; int len = 0; #define IS_BSD_COLOR(c) (((c) >= 'a' && (c) <= 'h') \ || ((c) >= 'A' && (c) <= 'H' ) || (c) == 'x' || (c) == 'X') while (env[c] && f < 11) { if (!IS_BSD_COLOR(env[c])) { c++; continue; } if (!env[c + 1]) break; if (!IS_BSD_COLOR(env[c + 1])) { c += 2; continue; } /* At this point, we have a valid "fg" pair. */ const char *ft = set_filetype(f); f++; const int n = snprintf(buf + len, sizeof(buf) - (size_t)len, "%s=%s;%s:", ft, bsd_to_ansi_color(env[c], 0), bsd_to_ansi_color(env[c + 1], 1)); if (n < 0 || n >= (int)sizeof(buf) - len) break; len += n; c += 2; } #undef IS_BSD_COLOR buf[len] = '\0'; return *buf ? buf : (char *)NULL; } /* Inspect LS_COLORS/LSCOLORS variable and assign pointers to ENV_FILECOLORS * and ENV_EXTCOLORS accordingly. */ static void set_lscolors(char **env_filecolors, char **env_extcolors) { static char *ls_colors = (char *)NULL; ls_colors = getenv("LS_COLORS"); if (!ls_colors || !*ls_colors) { ls_colors = set_lscolors_bsd(); if (!ls_colors || !*ls_colors) return; xargs.lscolors = LS_COLORS_BSD; } else { xargs.lscolors = LS_COLORS_GNU; } char *ext_ptr = strchr(ls_colors, '*'); if (ext_ptr) { *env_extcolors = ext_ptr; if (ext_ptr > ls_colors && *(ext_ptr - 1)) *(ext_ptr - 1) = '\0'; } *env_filecolors = ls_colors; } /* Try to retrieve colors from the environment. */ static void get_colors_from_env(char **file, char **ext, char **iface) { char *env_filecolors = (char *)NULL; char *env_extcolors = (char *)NULL; if (xargs.lscolors > 0) { set_lscolors(&env_filecolors, &env_extcolors); } else { env_filecolors = getenv("CLIFM_FILE_COLORS"); env_extcolors = getenv("CLIFM_EXT_COLORS"); } char *env_ifacecolors = getenv("CLIFM_IFACE_COLORS"); char *env_date_shades = getenv("CLIFM_DATE_SHADES"); char *env_size_shades = getenv("CLIFM_SIZE_SHADES"); if (env_date_shades && *env_date_shades) set_shades(env_date_shades, DATE_SHADES); if (env_size_shades && *env_size_shades) set_shades(env_size_shades, SIZE_SHADES); if (env_filecolors && *env_filecolors) *file = strdup(env_filecolors); if (env_extcolors && *env_extcolors) *ext = strdup(env_extcolors); if (env_ifacecolors && *env_ifacecolors) *iface = strdup(env_ifacecolors); } #ifndef CLIFM_SUCKLESS /* Store the color variable STR (in the form VAR=VALUE) in the global * defs struct. */ static void store_definition(const char *str) { if (!str || !*str || *str == '\n' || defs_n > MAX_DEFS) return; const char *name = str; char *value = strchr(name, '='); if (!value || !value[1] || value == name) return; *value = '\0'; value++; defs[defs_n].namelen = (size_t)(value - name - 1); defs[defs_n].name = savestring(name, defs[defs_n].namelen); size_t val_len; char *s = strchr(value, ' '); if (s) { *s = '\0'; val_len = (size_t)(s - value); } else { val_len = strlen(value); } if (IS_ALPHA_LOW(*value) || IS_ALPHA_UP(*value)) { char *ret = check_names(value); if (ret) { value = ret; val_len = strlen(ret); } } defs[defs_n].value = savestring(value, val_len); /* If we find a definition for TEMP, let's use this color for backup files * (bk_c color code). */ if (!*bk_c && *name == 'T' && strcmp(name + 1, "EMP") == 0) { char *v = IS_COLOR_PREFIX(*value) ? decode_color_prefix(value) : value; if (v && *v) snprintf(bk_c, sizeof(bk_c), "\x1b[0;%sm", v); } defs_n++; } /* Initialize the colors_t struct */ static void init_defs(void) { int n = MAX_DEFS; while (--n >= 0) { defs[n].name = (char *)NULL; defs[n].value = (char *)NULL; } } static void set_cs_prompt(char *line) { if (IS_CTRL_CHR(*line)) return; char *p = remove_quotes(line); if (!p || !*p) return; if (expand_prompt_name(p) != FUNC_SUCCESS) { free(conf.encoded_prompt); conf.encoded_prompt = savestring(p, strlen(p)); } } static void set_cs_prompt_noti(const char *line) { if (IS_CTRL_CHR(*line)) return; if (*line == 't' && strcmp(line, "true") == 0) prompt_notif = 1; /* NOLINT */ else if (*line == 'f' && strcmp(line, "false") == 0) prompt_notif = 0; /* NOLINT */ else prompt_notif = DEF_PROMPT_NOTIF; /* NOLINT */ } static void set_cs_enable_warning_prompt(const char *line) { if (IS_CTRL_CHR(*line)) return; if (*line == 't' && strcmp(line, "true") == 0) conf.warning_prompt = 1; /* NOLINT */ else if (*line == 'f' && strcmp(line, "false") == 0) conf.warning_prompt = 0; /* NOLINT */ else conf.warning_prompt = DEF_WARNING_PROMPT; /* NOLINT */ } static void set_cs_warning_prompt_str(char *line) { if (IS_CTRL_CHR(*line)) return; char *p = remove_quotes(line); if (!p) return; free(conf.wprompt_str); conf.wprompt_str = savestring(p, strlen(p)); } static void set_cs_right_prompt_str(char *line) { if (IS_CTRL_CHR(*line)) return; char *p = remove_quotes(line); if (!p) return; free(conf.rprompt_str); conf.rprompt_str = savestring(p, strlen(p)); if (conf.encoded_prompt) conf.prompt_is_multiline = strstr(conf.encoded_prompt, "\\n") ? 1 : 0; } #ifndef _NO_FZF static void set_fzf_opts(const char *line) { free(conf.fzftab_options); conf.fzftab_options = (char *)NULL; if (!line) { char *p = conf.colorize == 1 ? DEF_FZFTAB_OPTIONS : DEF_FZFTAB_OPTIONS_NO_COLOR; conf.fzftab_options = savestring(p, strlen(p)); } else if (*line == 'n' && strcmp(line, "none") == 0) { conf.fzftab_options = xnmalloc(1, sizeof(char)); *conf.fzftab_options = '\0'; } else if (sanitize_cmd(line, SNT_BLACKLIST) == FUNC_SUCCESS) { conf.fzftab_options = savestring(line, strlen(line)); } else { err('w', PRINT_PROMPT, _("%s: FzfTabOptions contains unsafe " "characters (<>|;&$`). Falling back to default values.\n"), PROGRAM_NAME); if (conf.colorize == 1) { conf.fzftab_options = savestring(DEF_FZFTAB_OPTIONS, strlen(DEF_FZFTAB_OPTIONS)); } else { conf.fzftab_options = savestring(DEF_FZFTAB_OPTIONS_NO_COLOR, strlen(DEF_FZFTAB_OPTIONS_NO_COLOR)); } } if (!conf.fzftab_options) return; if (strstr(conf.fzftab_options, "--preview ")) conf.fzf_preview = FZF_EXTERNAL_PREVIEWER; char *b = strstr(conf.fzftab_options, "--height"); if (b) fzf_height_value = get_fzf_height(b + (sizeof("--height") - 1)); b = strstr(conf.fzftab_options, "--border"); if (b) fzf_border_type = get_fzf_border_type(b + (sizeof("--border") - 1)); } static void set_cs_fzftabopts(char *line) { if (IS_CTRL_CHR(*line)) return; char *p = remove_quotes(line); if (!p || !*p) return; set_fzf_opts(p); } #endif /* !_NO_FZF */ static void set_cs_colors(const char *line, char **colors, const size_t line_len) { if (IS_CTRL_CHR(*line)) return; char *color_line = strip_color_line(line, line_len); if (!color_line) return; *colors = color_line; } static void set_cs_extcolors(char *line, char **extcolors, const ssize_t line_len) { char *p = line + 10; /* 10 == "ExtColors=" */ if (IS_CTRL_CHR(*p) || ((*p == '\'' || *p == '"') && !*(++p))) return; ssize_t l = line_len - (p - line); if (l > 0 && (p[l - 1] == '\'' || p[l - 1] == '"')) { p[l - 1] = '\0'; l--; } if (!*extcolors) { /* First ExtColors line. */ *extcolors = savestring(p, (size_t)l); } else { /* Second ExtColors line or more: append it to the first one. */ size_t curlen = strlen(*extcolors); if (curlen > 0 && (*extcolors)[curlen - 1] == ':') { (*extcolors)[curlen - 1] = '\0'; curlen--; } if (*p == ':' && p[1] && l > 0) { p++; l--; } const size_t total_len = curlen + (size_t)l + 1; *extcolors = xnrealloc(*extcolors, total_len + 1, sizeof(char *)); *(*extcolors + curlen) = ':'; memcpy(*extcolors + curlen + 1, p, (size_t)l); (*extcolors)[total_len] = '\0'; } } #ifndef _NO_ICONS static void set_cs_dir_icon_color(char *line, const ssize_t line_len) { char *p = line + 13; /* 13 == "DirIconColor=" */ if (IS_CTRL_CHR(*p) || ((*p == '\'' || *p == '"') && !*(++p))) return; if (line[line_len - 1] == '\'' || line[line_len - 1] == '"') line[line_len - 1] = '\0'; char *c = (char *)NULL; if (is_color_code(p) == 0 && (c = check_defs(p)) == NULL) return; snprintf(dir_ico_c, sizeof(dir_ico_c), "\x1b[%sm", c ? c : p); } #endif /* !_NO_ICONS */ /* Get color lines from the configuration file */ static int read_color_scheme_file(const char *colorscheme, char **filecolors, char **extcolors, char **ifacecolors, const int env) { /* Allocate some memory for custom color variables */ defs = xnmalloc(MAX_DEFS + 1, sizeof(struct colors_t)); defs_n = 0; init_defs(); char colorscheme_file[PATH_MAX + 1]; *colorscheme_file = '\0'; if (config_ok == 1 && colors_dir) { snprintf(colorscheme_file, sizeof(colorscheme_file), "%s/%s.clifm", colors_dir, colorscheme ? colorscheme : "default"); } /* If not in local dir, check system data dir as well */ struct stat attr; if (data_dir && (!*colorscheme_file || stat(colorscheme_file, &attr) == -1)) { snprintf(colorscheme_file, sizeof(colorscheme_file), "%s/%s/colors/%s.clifm", data_dir, PROGRAM_NAME, colorscheme ? colorscheme : "default"); } FILE *fp_colors = fopen(colorscheme_file, "r"); if (!fp_colors) { if (!env) { xerror("%s: colors: '%s': %s\n", PROGRAM_NAME, colorscheme_file, strerror(errno)); return FUNC_FAILURE; } else { err('w', PRINT_PROMPT, _("%s: colors: '%s': No such color scheme. " "Falling back to default\n"), PROGRAM_NAME, colorscheme); return FUNC_SUCCESS; } } /* If called from the color scheme function, reset all color values * before proceeding. */ if (!env) { reset_filetype_colors(); reset_iface_colors(); } char *line = (char *)NULL; size_t line_size = 0; ssize_t line_len = 0; while ((line_len = getline(&line, &line_size, fp_colors)) > 0) { if (SKIP_LINE(*line)) continue; if (line[line_len - 1] == '\n') { line[line_len - 1] = '\0'; line_len--; } if (*line == 'd' && strncmp(line, "define ", 7) == 0) { store_definition(line + 7); } else if (*line == 'P' && strncmp(line, "Prompt=", 7) == 0) { set_cs_prompt(line + 7); } /* The following values override those set via the Prompt line * (provided it was set to a valid prompt name, as defined in the * prompts file). */ else if (*line == 'N' && strncmp(line, "Notifications=", 14) == 0) { set_cs_prompt_noti(line + 14); } else if (xargs.warning_prompt == UNSET && *line == 'E' && strncmp(line, "EnableWarningPrompt=", 20) == 0) { set_cs_enable_warning_prompt(line + 20); } else if (*line == 'W' && strncmp(line, "WarningPrompt=", 14) == 0) { set_cs_warning_prompt_str(line + 14); } else if (*line == 'R' && strncmp(line, "RightPrompt=", 12) == 0) { set_cs_right_prompt_str(line + 12); } #ifndef _NO_FZF else if (*line == 'F' && strncmp(line, "FzfTabOptions=", 14) == 0) { set_cs_fzftabopts(line + 14); } #endif /* !_NO_FZF */ else if (*line == 'D' && strncmp(line, "DividingLine=", 13) == 0) { set_div_line(line + 13); } /* Interface colors */ else if (!*ifacecolors && *line == 'I' && strncmp(line, "InterfaceColors=", 16) == 0) { set_cs_colors(line + 16, ifacecolors, (size_t)line_len - 16); } /* Filetype colors */ else if (!*filecolors && *line == 'F' && strncmp(line, "FiletypeColors=", 15) == 0) { set_cs_colors(line + 15, filecolors, (size_t)line_len - 15); } /* File extension colors */ else if (xargs.lscolors != LS_COLORS_GNU && *line == 'E' && strncmp(line, "ExtColors=", 10) == 0) { set_cs_extcolors(line, extcolors, line_len); } #ifndef _NO_ICONS /* Directory icon color */ else if (*line == 'D' && strncmp(line, "DirIconColor=", 13) == 0) { set_cs_dir_icon_color(line, line_len); } #endif /* !_NO_ICONS */ else if (date_shades.type == SHADE_TYPE_UNSET && *line == 'D' && strncmp(line, "DateShades=", 11) == 0) { set_shades(line + 11, DATE_SHADES); } else if (size_shades.type == SHADE_TYPE_UNSET && *line == 'S' && strncmp(line, "SizeShades=", 11) == 0) { set_shades(line + 11, SIZE_SHADES); } } free(line); fclose(fp_colors); return FUNC_SUCCESS; } #endif /* !CLIFM_SUCKLESS */ /* Split the colors line LINE and set the corresponding colors * according to TYPE (either interface or file type color). */ static void split_color_line(char *line, const int type) { char *p = line; char **colors = (char **)NULL; /* MAX_COLOR is not enough when parsing LS_COLORS lines, where we * usually find extension colors ("*.ext=color"). */ char buf[MAX_COLOR + 3 + NAME_MAX]; *buf = '\0'; size_t len = 0; size_t words = 0; int eol = 0; while (eol == 0) { switch (*p) { case '\0': /* fallthrough */ case '\n': /* fallthrough */ case ':': if (!*buf) { if (!*p || !p[1]) eol = 1; else p++; break; } buf[len] = '\0'; colors = xnrealloc(colors, words + 2, sizeof(char *)); colors[words] = savestring(buf, len); words++; *buf = '\0'; if (*p == '\0') eol = 1; len = 0; p++; break; default: if (len >= sizeof(buf)) { p++; break; } buf[len] = *p; len++; p++; break; } } p = (char *)NULL; if (!colors) return; colors[words] = (char *)NULL; /* Set the color variables. * The colors array is free'd by both of these functions. */ if (type == SPLIT_FILETYPE_COLORS) set_filetype_colors(colors, words); else set_iface_colors(colors, words); } static void disable_bold(void) { /* File types */ remove_bold_attr(bd_c); remove_bold_attr(bk_c); remove_bold_attr(ca_c); remove_bold_attr(cd_c); remove_bold_attr(di_c); remove_bold_attr(ed_c); remove_bold_attr(ee_c); remove_bold_attr(ef_c); remove_bold_attr(ex_c); remove_bold_attr(fi_c); remove_bold_attr(ln_c); remove_bold_attr(mh_c); remove_bold_attr(nd_c); remove_bold_attr(nf_c); remove_bold_attr(no_c); #ifdef SOLARIS_DOORS remove_bold_attr(oo_c); #endif /* SOLARIS_DOORS */ remove_bold_attr(or_c); remove_bold_attr(ow_c); remove_bold_attr(pi_c); remove_bold_attr(sg_c); remove_bold_attr(so_c); remove_bold_attr(st_c); remove_bold_attr(su_c); remove_bold_attr(tw_c); remove_bold_attr(uf_c); /* Interface */ remove_bold_attr(ac_c); remove_bold_attr(df_c); remove_bold_attr(dl_c); remove_bold_attr(el_c); remove_bold_attr(fc_c); remove_bold_attr(lc_c); remove_bold_attr(mi_c); remove_bold_attr(ts_c); remove_bold_attr(tt_c); remove_bold_attr(wc_c); remove_bold_attr(wp_c); /* Suggestions */ remove_bold_attr(sb_c); remove_bold_attr(sc_c); remove_bold_attr(sd_c); remove_bold_attr(sf_c); remove_bold_attr(sh_c); remove_bold_attr(sp_c); remove_bold_attr(sx_c); remove_bold_attr(sz_c); #ifndef _NO_ICONS remove_bold_attr(dir_ico_c); #endif /* !_NO_ICONS */ /* Syntax highlighting */ remove_bold_attr(hb_c); remove_bold_attr(hc_c); remove_bold_attr(hd_c); remove_bold_attr(he_c); remove_bold_attr(hn_c); remove_bold_attr(hp_c); remove_bold_attr(hq_c); remove_bold_attr(hr_c); remove_bold_attr(hs_c); remove_bold_attr(hv_c); remove_bold_attr(hw_c); /* File properties */ remove_bold_attr(db_c); remove_bold_attr(dd_c); remove_bold_attr(de_c); remove_bold_attr(dg_c); remove_bold_attr(dk_c); remove_bold_attr(dn_c); remove_bold_attr(do_c); remove_bold_attr(dp_c); remove_bold_attr(dr_c); remove_bold_attr(dt_c); remove_bold_attr(du_c); remove_bold_attr(dw_c); remove_bold_attr(dxd_c); remove_bold_attr(dxr_c); remove_bold_attr(dz_c); /* Workspaces */ remove_bold_attr(ws1_c); remove_bold_attr(ws2_c); remove_bold_attr(ws3_c); remove_bold_attr(ws4_c); remove_bold_attr(ws5_c); remove_bold_attr(ws6_c); remove_bold_attr(ws7_c); remove_bold_attr(ws8_c); /* Prompt indicators */ remove_bold_attr(em_c); remove_bold_attr(li_c); remove_bold_attr(li_cb); remove_bold_attr(nm_c); remove_bold_attr(ro_c); remove_bold_attr(si_c); remove_bold_attr(ti_c); remove_bold_attr(tx_c); remove_bold_attr(xs_c); remove_bold_attr(xs_cb); remove_bold_attr(xf_c); remove_bold_attr(xf_cb); remove_bold_attr(wm_c); } /* Get color code values from either the environment or the config file * and set colors accordingly. If some value is not found or is a wrong * value, the default is set. */ int set_colors(const char *colorscheme, const int check_env) { char *filecolors = (char *)NULL; char *extcolors = (char *)NULL; char *ifacecolors = (char *)NULL; date_shades.type = SHADE_TYPE_UNSET; size_shades.type = SHADE_TYPE_UNSET; #ifndef _NO_ICONS *dir_ico_c = '\0'; #endif /* !_NO_ICONS */ int ret = FUNC_SUCCESS; if (colorscheme && *colorscheme && color_schemes) ret = get_cur_colorscheme(colorscheme); /* CHECK_ENV is true only when this function is called from * check_colors() (config.c) */ if (ret == FUNC_SUCCESS && check_env == 1) get_colors_from_env(&filecolors, &extcolors, &ifacecolors); #ifndef CLIFM_SUCKLESS if (ret == FUNC_SUCCESS && xargs.stealth_mode != 1 && config_ok != 0) { if (read_color_scheme_file(cur_cscheme, &filecolors, &extcolors, &ifacecolors, check_env) == FUNC_FAILURE) { clear_defs(); return FUNC_FAILURE; } } #endif /* CLIFM_SUCKLESS */ /* Split the color lines into substrings (one per color) */ if (!extcolors) { /* Unload current extension colors */ if (ext_colors_n > 0) free_extension_colors(); } else { split_extension_colors(extcolors); free(extcolors); } if (!ifacecolors) { reset_iface_colors(); } else { split_color_line(ifacecolors, SPLIT_INTERFACE_COLORS); free(ifacecolors); } if (!filecolors) { reset_filetype_colors(); } else { split_color_line(filecolors, SPLIT_FILETYPE_COLORS); free(filecolors); } #ifndef CLIFM_SUCKLESS clear_defs(); #endif /* CLIFM_SUCKLESS */ /* If some color is unset or is a wrong color code, set the default value */ set_default_colors(); update_warning_prompt_text_color(); if (xargs.no_bold == 1) disable_bold(); return FUNC_SUCCESS; } /* If completing trashed files (regular only) we need to remove the trash * extension in order to correctly determine the file color (according to * its actual extension). * Remove this extension (setting the initial dot to NULL) and return a * pointer to this character, so that we can later reinsert the dot. * * NOTE: We append a time suffix (via gen_time_suffix()) to the trashed file * name in order to make it unique. Now, since other trash implementations do * not do this, we need to check the extension name (otherwise, we might end * up removing the original file extension). * The time suffix is "YYYYMMDDHHMMSS". So we need to check whether we have an * extension name of at least 14 digits, being the first one '2' (the time * suffix starts by the year, so that it's quite safe to assume the first * one will be '2' (at least until the year 3000!)). Not perfect, but it * works most of the time. */ char * remove_trash_ext(char **ent) { if (!(flags & STATE_COMPLETING) || (cur_comp_type != TCMP_UNTRASH && cur_comp_type != TCMP_TRASHDEL)) return (char *)NULL; char *d = strrchr(*ent, '.'); if (d && d != *ent && d[1] == '2' && strlen(d + 1) == 14 && is_number(d + 1)) *d = '\0'; return d; } char * get_entry_color(char *ent, const struct stat *a) { char *color = (char *)NULL; switch (a->st_mode & S_IFMT) { case S_IFREG: { size_t ext = 0; char *d = remove_trash_ext(&ent); color = get_regfile_color(ent, a, &ext); if (d) *d = '.'; } break; case S_IFDIR: color = conf.colorize == 0 ? di_c : get_dir_color(ent, a, -1); break; case S_IFLNK: { if (conf.colorize == 0) { color = ln_c; } else { char *linkname = xrealpath(ent, NULL); color = linkname ? ln_c : or_c; free(linkname); } } break; case S_IFIFO: color = pi_c; break; case S_IFBLK: color = bd_c; break; case S_IFCHR: color = cd_c; break; #ifdef SOLARIS_DOORS case S_IFPORT: /* fallthrough */ case S_IFDOOR: color = oo_c; break; #endif /* SOLARIS_DOORS */ case S_IFSOCK: color = so_c; break; default: color = no_c; break; } return color; } /* Print the entry ENT using color codes and ELN as ELN, right padding PAD * chars and terminate ENT with or without a new line char (NEW_LINE * 1 or 0 respectively). * ELN could be: * > 0: The ELN of a file in CWD * -1: Error getting ELN * 0: ELN should not be printed. E.g., when listing files not in CWD */ void colors_list(char *ent, const int eln, const int pad, const int new_line) { char index[MAX_INT_STR + 1]; *index = '\0'; if (eln > 0) snprintf(index, sizeof(index), "%d ", eln); else if (eln == -1) snprintf(index, sizeof(index), "? "); else index[0] = '\0'; struct stat attr; char *p = ent, *q = ent, t[PATH_MAX + 1]; char *eln_color = *index == '?' ? mi_c : el_c; if (*q == '~') { if (!q[1] || (q[1] == '/' && !q[2])) xstrsncpy(t, user.home, sizeof(t) - 1); else snprintf(t, sizeof(t), "%s/%s", user.home, q + 2); p = t; } size_t len = strlen(p); int rem_slash = 0; /* Remove the ending slash: lstat(3) won't take a symlink to dir as * a symlink (but as a dir), if the filename ends with a slash. */ if (len > 1 && p[len - 1] == '/') { p[len - 1] = '\0'; rem_slash = 1; } char vt_file[PATH_MAX + 1]; *vt_file = '\0'; if (virtual_dir == 1 && is_file_in_cwd(p)) xreadlink(XAT_FDCWD, p, vt_file, sizeof(vt_file)); const int ret = lstat(*vt_file ? vt_file : p, &attr); if (rem_slash == 1) p[len - 1] = '/'; char *wname = (char *)NULL; const size_t wlen = wc_xstrlen(ent); if (wlen == 0) /* Invalid chars found. */ wname = replace_invalid_chars(ent); char *color = ret == -1 ? uf_c : get_entry_color(ent, &attr); char *name = wname ? wname : ent; char *tmp = (flags & IN_SELBOX_SCREEN) ? abbreviate_file_name(name) : name; printf("%s%s%s%s%s%s%s%-*s", eln_color, index, df_c, color, tmp + tab_offset, df_c, new_line ? "\n" : "", pad, ""); free(wname); if ((flags & IN_SELBOX_SCREEN) && tmp != name) free(tmp); } #ifndef CLIFM_SUCKLESS /* Returns 1 if the file named NAME is a valid color scheme name, or 0 otherwise. * If true, NAME is truncated to its last dot (the file extension is removed). */ static int is_valid_colorscheme_name(char *name) { if (SELFORPARENT(name)) return 0; char *ret = strrchr(name, '.'); if (!ret || ret == name || strcmp(ret, ".clifm") != 0) return 0; *ret = '\0'; return 1; } /* Returns 1 if the color scheme name NAME already exists in the current * list of color schemes, which contains TOTAL entries. */ static int is_duplicate_colorscheme_name(const char *name, const size_t total) { size_t i; for (i = 0; i < total; i++) { if (*color_schemes[i] == *name && strcmp(name, color_schemes[i]) == 0) return 1; } return 0; } size_t get_colorschemes(void) { if (color_schemes && cschemes_n > 0) return cschemes_n; int schemes_total = 0; struct dirent *ent; DIR *dir_p; size_t i = 0; if (colors_dir && (schemes_total = (int)count_dir(colors_dir, NO_CPOP) - 2) > 0 && (dir_p = opendir(colors_dir)) != NULL) { color_schemes = xnrealloc(color_schemes, (size_t)schemes_total + 2, sizeof(char *)); while ((ent = readdir(dir_p)) != NULL && i < (size_t)schemes_total) { if (is_valid_colorscheme_name(ent->d_name) == 0) continue; color_schemes[i] = savestring(ent->d_name, strlen(ent->d_name)); i++; } closedir(dir_p); color_schemes[i] = (char *)NULL; } if (!data_dir || !*data_dir) goto END; if (schemes_total < 0) /* count_dir() failed */ schemes_total = 0; char sys_colors_dir[PATH_MAX + 1]; snprintf(sys_colors_dir, sizeof(sys_colors_dir), "%s/%s/colors", data_dir, PROGRAM_NAME); const int n = (int)count_dir(sys_colors_dir, NO_CPOP) - 2; if (n <= 0) goto END; schemes_total += n; if (!(dir_p = opendir(sys_colors_dir))) goto END; color_schemes = xnrealloc(color_schemes, (size_t)schemes_total + 2, sizeof(char *)); const size_t i_tmp = i; while ((ent = readdir(dir_p)) != NULL && i < (size_t)schemes_total) { if (is_valid_colorscheme_name(ent->d_name) == 0 || is_duplicate_colorscheme_name(ent->d_name, i_tmp) == 1) continue; color_schemes[i] = savestring(ent->d_name, strlen(ent->d_name)); i++; } closedir(dir_p); color_schemes[i] = (char *)NULL; END: if (color_schemes) qsort(color_schemes, i, sizeof(char *), (QSFUNC *)compare_strings); return i; } #endif /* CLIFM_SUCKLESS */ static size_t get_longest_ext_name(void) { size_t l = 0; for (size_t i = 0; i < ext_colors_n; i++) if (ext_colors[i].len > l) l = ext_colors[i].len; return l; } static int color_sort(const void *a, const void *b) { struct ext_t *pa = (struct ext_t *)a; struct ext_t *pb = (struct ext_t *)b; const int ret = strcmp(pa->value, pb->value); if (ret != 0) return ret; return conf.case_sens_list == 1 ? strcmp(pa->name, pb->name) : strcasecmp(pa->name, pb->name); } static void print_ext_colors(void) { printf(_("\n%sFile extensions%s\n\n"), BOLD, df_c); const int l = (int)get_longest_ext_name() + 2; /* +2 == ".*" */ int cols = term_cols / (l + 2); /* +2 == 2 ending spaces */ if (cols <= 0) cols = 1; /* The ext_colors array is sorted by name hashes (to perform binary * searches for file extension colors). But here we want to group * extensions by color. */ qsort(ext_colors, ext_colors_n, sizeof(*ext_colors), (QSFUNC *)color_sort); int n = 1; for (size_t i = 0; i < ext_colors_n; i++) { const int pad = l - (int)ext_colors[i].len; printf("\x1b[%sm*.%s%s%*s", ext_colors[i].value, ext_colors[i].name, NC, pad, ""); if (n == cols) { n = 1; putchar('\n'); } else { n++; } } printf("%s\n", df_c); qsort(ext_colors, ext_colors_n, sizeof(*ext_colors), (QSFUNC *)hash_sort); } static void print_color_blocks(void) { UNSET_LINE_WRAP; const int pad = (term_cols - 24) / 2; printf("\x1b[%dC\x1b[0;40m \x1b[0m\x1b[0;41m \x1b[0m\x1b[0;42m " "\x1b[0m\x1b[0;43m \x1b[0m\x1b[0;44m \x1b[0m\x1b[0;45m " "\x1b[0m\x1b[0;46m \x1b[0m\x1b[0;47m \x1b[0m\n", pad); printf("\x1b[%dC\x1b[0m\x1b[0;100m \x1b[0m\x1b[0;101m " "\x1b[0m\x1b[0;102m \x1b[0m\x1b[0;103m \x1b[0m\x1b[0;104m " "\x1b[0m\x1b[0;105m \x1b[0m\x1b[0;106m \x1b[0m\x1b[0;107m " "\x1b[0m\n\n", pad); SET_LINE_WRAP; } static void print_file_type_colors(void) { printf(_("%sFile types%s\n\n"), BOLD, df_c); printf(_("%sColor%s (di) Directory\n"), di_c, df_c); printf(_("%sColor%s (ed) Empty directory\n"), ed_c, df_c); if (*nd_c) printf(_("%sColor%s (nd) Directory with no read/exec permission\n"), nd_c, df_c); printf(_("%sColor%s (fi) Regular file\n"), fi_c, df_c); printf(_("%sColor%s (ef) Empty file\n"), ef_c, df_c); if (*nf_c) printf(_("%sColor%s (nf) File with no read permission\n"), nf_c, df_c); printf(_("%sColor%s (ex) Executable file\n"), ex_c, df_c); printf(_("%sColor%s (ee) Empty executable file\n"), ee_c, df_c); printf(_("%sColor%s (ln) Symbolic link\n"), ln_c, df_c); printf(_("%sColor%s (or) Broken symbolic link\n"), or_c, df_c); printf(_("%sColor%s (mh) Multi-hardlink\n"), mh_c, df_c); printf(_("%sColor%s (bd) Block device\n"), bd_c, df_c); printf(_("%sColor%s (cd) Character device\n"), cd_c, df_c); printf(_("%sColor%s (so) Socket file\n"), so_c, df_c); printf(_("%sColor%s (pi) Pipe or FIFO special file\n"), pi_c, df_c); #ifdef SOLARIS_DOORS printf(_("%sColor%s (oo) Door/Port file\n"), oo_c, df_c); #endif // SOLARIS_DOORS printf(_("%sColor%s (su) SUID file\n"), su_c, df_c); printf(_("%sColor%s (sg) SGID file\n"), sg_c, df_c); printf(_("%sColor%s (ca) File with capabilities\n"), ca_c, df_c); printf(_("%sColor%s (st) Sticky and NOT other-writable " "directory\n"), st_c, df_c); printf(_("%sColor%s (tw) Sticky and other-writable directory\n"), tw_c, df_c); printf(_("%sColor%s (ow) Other-writable and NOT sticky directory\n"), ow_c, df_c); printf(_("%sColor%s (no) Unknown file type\n"), no_c, df_c); printf(_("%sColor%s (uf) Inaccessible (non-statable) file\n"), uf_c, df_c); } static void print_size_shades(void) { fputs(_(" (dz) Size (unset: using shades)\n "), stdout); char tstr[MAX_SHADE_LEN]; *tstr = '\0'; get_color_size((off_t)1, tstr, sizeof(tstr)); printf("%sbytes%s ", tstr, df_c); get_color_size((off_t)1024, tstr, sizeof(tstr)); printf("%sKb%s ", tstr, df_c); get_color_size((off_t)1024 * 1024, tstr, sizeof(tstr)); printf("%sMb%s ", tstr, df_c); get_color_size((off_t)1024 * 1024 * 1024, tstr, sizeof(tstr)); printf("%sGb%s ", tstr, df_c); get_color_size((off_t)1024 * 1024 * 1024 * 1024, tstr, sizeof(tstr)); printf(_("%sbigger%s\n"), tstr, df_c); } static void print_date_shades(const time_t t) { fputs(_(" (dd) Date (unset: using shades)\n "), stdout); char tstr[MAX_SHADE_LEN]; *tstr = '\0'; get_color_age(t - (60LL*60), tstr, sizeof(tstr)); printf(_("%shour%s "), tstr, df_c); get_color_age(t - (24LL*60*60), tstr, sizeof(tstr)); printf(_("%sday%s "), tstr, df_c); get_color_age(t - (7LL*24*60*60), tstr, sizeof(tstr)); printf(_("%sweek%s "), tstr, df_c); get_color_age(t - (4LL*7*24*60*60), tstr, sizeof(tstr)); printf(_("%smonth%s "), tstr, df_c); get_color_age(t - (4LL*7*24*60*60+1), tstr, sizeof(tstr)); printf(_("%solder%s\n"), tstr, df_c); } static void print_date_colors(void) { const time_t t = time(NULL); props_now = t; if (*dd_c) { printf(_("%sColor%s (dd) Date (e.g. %sJul 9 08:12%s)\n"), dd_c, df_c, dd_c, df_c); } else { print_date_shades(t); } char tstr[MAX_SHADE_LEN]; *tstr = '\0'; get_color_age(t - (24LL*60*60), tstr, sizeof(tstr)); printf(_("%s%sColor%s (dt) Timestamp mark (e.g. %sMay 25 22:08%sm%s)\n"), tstr, dt_c, df_c, tstr, dt_c, df_c); } static void print_prop_colors(void) { printf(_("\n%sProperties / Long view%s\n\n"), BOLD, df_c); printf(_("%sColor%s (dr) Read bit (%sr%s)\n"), dr_c, df_c, dr_c, df_c); printf(_("%sColor%s (dw) Write bit (%sw%s)\n"), dw_c, df_c, dw_c, df_c); printf(_("%sColor%s (dxd) Execute bit - directory (%sx%s)\n"), dxd_c, df_c, dxd_c, df_c); printf(_("%sColor%s (dxr) Execute bit - file (%sx%s)\n"), dxr_c, df_c, dxr_c, df_c); printf(_("%sColor%s (dp) SUID/SGID bit (e.g. %ss%s)\n"), dp_c, df_c, dp_c, df_c); printf(_("%sColor%s (du) User ID (e.g. %sjane%s)\n"), du_c, df_c, du_c, df_c); printf(_("%s%sColor%s (dg) Group ID (e.g. %s%swheel%s)\n"), du_c, dg_c, df_c, du_c, dg_c, df_c); if (*dz_c) { printf(_("%sColor%s (dz) Size (e.g. %s12.69k%s)\n"), dz_c, df_c, dz_c, df_c); } else { print_size_shades(); } print_date_colors(); printf(_("%sColor%s (db) Used blocks (e.g. %s1576%s)\n"), db_c, df_c, db_c, df_c); printf(_("%sColor%s (dk) Links number (e.g. %s92%s)\n"), dk_c, df_c, dk_c, df_c); printf(_("%sColor%s (de) Inode number (e.g. %s802721%s)\n"), de_c, df_c, de_c, df_c); printf(_("%sColor%s (do) Octal permissions (e.g. %s0640%s)\n"), do_c, df_c, do_c, df_c); printf(_("%sColor%s (dn) Dot/dash (e.g. %sr%sw%s-.%sr%s--.--%s)\n"), dn_c, df_c, dr_c, dw_c, dn_c, dr_c, dn_c, df_c); } static void print_interface_colors(void) { printf(_("\n%sInterface%s\n\n"), BOLD, df_c); printf(_("%sColor%s (el) ELN's (e.g. %s12%s filename)\n"), el_c, df_c, el_c, df_c); printf(_("%sColor%s (fc) File counter (e.g. dir%s/24%s)\n"), fc_c, df_c, fc_c, df_c); printf(_("%sColor%s (lc) Symbolic link indicator (e.g. %s36%s" "%s%s%ssymlink) (%s1%s)\n"), lc_c, df_c, el_c, df_c, lc_c, term_caps.unicode == 1 ? LINK_STR_U : LINK_STR, df_c, BOLD, df_c); printf(_("%sColor%s (li) Selected file indicator (e.g. %s12%s" "%s%s%sfilename)\n"), li_cb, df_c, el_c, df_c, li_cb, term_caps.unicode == 1 ? SELFILE_STR_U : SELFILE_STR, df_c); printf(_("%sColor%s (tt) Truncated filenames mark (e.g. " "filenam%s%c%s.odt)\n"), tt_c, df_c, tt_c, TRUNC_FILE_CHR, df_c); printf(_("%sColor%s (dl) Dividing line (e.g. %s------>%s)\n"), dl_c, df_c, dl_c, df_c); printf(_("%sColor%s (mi) Miscellaneous indicator (%s%s%s) (%s2%s)\n"), mi_c, df_c, mi_c, MSG_PTR_STR, df_c, BOLD, df_c); printf(_("%sColor%s (ts) Matching completion prefix (e.g. " "%sfile%sname) (%s3%s)\n"), ts_c, df_c, ts_c, df_c, BOLD, df_c); printf(_("%sColor%s (df) Default color\n"), df_c, df_c); printf(_("\n(%s1%s) Used only when ColorLinksAsTarget is " "enabled\n"), BOLD, df_c); printf(_("(%s2%s) Also used for miscellaneous names (like bookmarks " "and color schemes) in tab completion\n"), BOLD, df_c); printf(_("(%s3%s) Used only for the standard tab completion " "mode\n"), BOLD, df_c); } static void print_workspace_colors(void) { printf(_("\n%sWorkspaces%s\n\n"), BOLD, df_c); char *p = remove_ctrl_chars(ws1_c); printf(_("%sColor%s (ws1) Workspace [%s1%s]\n"), p, df_c, p, df_c); p = remove_ctrl_chars(ws2_c); printf(_("%sColor%s (ws2) Workspace [%s2%s]\n"), p, df_c, p, df_c); p = remove_ctrl_chars(ws3_c); printf(_("%sColor%s (ws3) Workspace [%s3%s]\n"), p, df_c, p, df_c); p = remove_ctrl_chars(ws4_c); printf(_("%sColor%s (ws4) Workspace [%s4%s]\n"), p, df_c, p, df_c); p = remove_ctrl_chars(ws5_c); printf(_("%sColor%s (ws5) Workspace [%s5%s]\n"), p, df_c, p, df_c); p = remove_ctrl_chars(ws6_c); printf(_("%sColor%s (ws6) Workspace [%s6%s]\n"), p, df_c, p, df_c); p = remove_ctrl_chars(ws7_c); printf(_("%sColor%s (ws7) Workspace [%s7%s]\n"), p, df_c, p, df_c); p = remove_ctrl_chars(ws8_c); printf(_("%sColor%s (ws8) Workspace [%s8%s]\n"), p, df_c, p, df_c); } static void print_prompt_colors(void) { printf(_("\n%sPrompt%s\n\n"), BOLD, df_c); printf(_("%sColor%s (tx) Input text (e.g. \x1b[1m$\x1b[0m " "%sls%s %s-l%s %sfilename.zst%s)\n"), tx_c, df_c, tx_c, df_c, hp_c, df_c, tx_c, df_c); char *p = remove_ctrl_chars(ac_c); printf(_("%sColor%s (ac) Autocommand indicator (%sA%s)\n"), p, df_c, p, df_c); printf(_("%sColor%s (li) Selected files indicator (%s%c%s)\n"), li_cb, df_c, li_cb, SELFILE_CHR, df_c); p = remove_ctrl_chars(ti_c); printf(_("%sColor%s (ti) Trashed files indicator (%sT%s)\n"), p, df_c, p, df_c); p = remove_ctrl_chars(xs_c); printf(_("%sColor%s (xs) Success exit code (<%s0%s>)\n"), p, df_c, p, df_c); p = remove_ctrl_chars(xf_c); printf(_("%sColor%s (xf) Error exit code (e.g. <%s1%s>)\n"), p, df_c, p, df_c); p = remove_ctrl_chars(nm_c); printf(_("%sColor%s (nm) Notice message indicator (%sN%s)\n"), p, df_c, p, df_c); p = remove_ctrl_chars(wm_c); printf(_("%sColor%s (wm) Warning message indicator (%sW%s)\n"), p, df_c, p, df_c); p = remove_ctrl_chars(em_c); printf(_("%sColor%s (em) Error message indicator (%sE%s)\n"), p, df_c, p, df_c); p = remove_ctrl_chars(ro_c); printf(_("%sColor%s (ro) Read-only mode indicator (%sRO%s)\n"), p, df_c, p, df_c); p = remove_ctrl_chars(si_c); printf(_("%sColor%s (si) Stealth mode indicator (%sS%s)\n"), p, df_c, p, df_c); } static void print_suggestion_colors(void) { #ifndef _NO_SUGGESTIONS printf("\n%sSuggestions%s\n\n", BOLD, df_c); printf("%sColor%s (sh) History (e.g. sud%so vim clifmrc%s)\n", sh_c, df_c, sh_c, df_c); printf("%sColor%s (sf) Filenames (e.g. thi%ss_filename%s)\n", sf_c, df_c, sf_c, df_c); printf("%sColor%s (sz) Filenames (fuzzy) (e.g. dwn %s%c%s " "%sDownloads%s)\n", sz_c, df_c, sp_c, SUG_POINTER, df_c, sz_c, df_c); printf("%sColor%s (sx) Internal command names and parameters " "(e.g. boo%skmarks%s)\n", sx_c, df_c, sx_c, df_c); printf("%sColor%s (sc) External command names (e.g. lib%sreoffice%s)\n", sc_c, df_c, sc_c, df_c); printf("%sColor%s (sb) Shell builtin names (e.g. ex%sport%s)\n", sb_c, df_c, sb_c, df_c); printf("%sColor%s (sd) Internal commands description (e.g. " "br %s(batch rename files)%s)\n", sd_c, df_c, sd_c, df_c); printf("%sColor%s (sp) Pointer (e.g. %s48%s %s%c%s %sfilename%s)\n", sp_c, df_c, hn_c, df_c, sp_c, SUG_POINTER, df_c, sf_c, df_c); #else return; #endif /* !_NO_SUGGESTIONS */ } static void print_highlight_colors(void) { #ifndef _NO_HIGHLIGHT printf(_("\n%sSyntax highlighting%s\n\n"), BOLD, df_c); printf(_("%sColor%s (hb) Brackets: %s(){}[]%s\n"), hb_c, df_c, hb_c, df_c); printf(_("%sColor%s (hc) Commented out text (e.g. some text " "%s#comment%s)\n"), hc_c, df_c, hc_c, df_c); printf(_("%sColor%s (hd) Slash (e.g. dir%s/%sfile)\n"), hd_c, df_c, hd_c, df_c); printf(_("%sColor%s (he) Expansion characters: %s~*%s\n"), he_c, df_c, he_c, df_c); printf(_("%sColor%s (hn) Number (e.g. pp %s12%s)\n"), hn_c, df_c, hn_c, df_c); printf(_("%sColor%s (hp) Command parameter (e.g. cmd %s--param%s)\n"), hp_c, df_c, hp_c, df_c); printf(_("%sColor%s (hq) Quoted text (e.g. %s\"some text\"%s)\n"), hq_c, df_c, hq_c, df_c); printf(_("%sColor%s (hr) Redirection characters: %s><%s\n"), hr_c, df_c, hr_c, df_c); printf(_("%sColor%s (hs) Process separator characters: %s|;&%s \n"), hs_c, df_c, hs_c, df_c); printf(_("%sColor%s (hv) Variable name (e.g. %s$FOO%s)\n"), hv_c, df_c, hv_c, df_c); printf(_("%sColor%s (hw) Backslash (e.g. sel this%s\\%s file%s\\%s " "name)\n"), hw_c, df_c, hw_c, df_c, hw_c, df_c); #else return; #endif /* !_NO_HIGHLIGHT */ } static void print_color_scheme_name(void) { printf(_("%sColor scheme: %s%s%s\n\n"), BOLD, get_color_scheme_name(), df_c, ON_LSCOLORS); } /* List color codes for file types used by the program. */ void color_codes(void) { if (conf.colorize == 0) { printf(_("%s: Running without colors\n"), PROGRAM_NAME); return; } print_color_scheme_name(); print_file_type_colors(); print_ext_colors(); print_prop_colors(); print_interface_colors(); print_workspace_colors(); print_prompt_colors(); print_highlight_colors(); print_suggestion_colors(); puts(_("\nThe codes in parentheses are used to modify the color of " "the corresponding elements in the color scheme file.\n\n")); print_color_blocks(); } clifm-1.26.3/src/colors.h000066400000000000000000000052131506632037700151500ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* colors.h */ #ifndef COLORS_H #define COLORS_H #define RL_PRINTABLE 1 #define RL_NO_PRINTABLE 0 /* Add non-printing flags (\001 and \002)*/ /* Tell split_color_line wether we're dealing with interface or file * type colors. */ #define SPLIT_INTERFACE_COLORS 0 #define SPLIT_FILETYPE_COLORS 1 /* Max number of custom color variables in the color scheme file. */ #define MAX_DEFS 128 /* Macros for the set_shades function. */ #define DATE_SHADES 0 #define SIZE_SHADES 1 /* Special colors (#RRGGBB and @NUM) need to be expanded into codes the * terminal emulator can understand. For example, "#FF0000" will be expanded * to "\x1b[38;2;255;0;0m", and "@160" to "\x1b[38;5;160m". */ #define RGB_COLOR_PREFIX '#' #define COLOR256_PREFIX '@' #define IS_COLOR_PREFIX(c) ((c) == RGB_COLOR_PREFIX || (c) == COLOR256_PREFIX) #define LS_COLORS_GNU 1 #define LS_COLORS_BSD 2 __BEGIN_DECLS void color_codes(void); void colors_list(char *ent, const int eln, const int pad, const int new_line); int cschemes_function(char **args); #ifndef CLIFM_SUCKLESS size_t get_colorschemes(void); #endif /* CLIFM_SUCKLESS */ char *get_dir_color(const char *filename, const struct stat *a, const filesn_t count); char *get_entry_color(char *ent, const struct stat *a); char *get_ext_color(const char *ext, size_t *val_len); char *get_file_color(const char *filename, const struct stat *a); char *get_regfile_color(const char *filename, const struct stat *a, size_t *is_ext); int import_color_scheme(const char *name); void update_warning_prompt_text_color(void); void remove_bold_attr(char *str); char *remove_trash_ext(char **ent); void reset_filetype_colors(void); void reset_iface_colors(void); int set_colors(const char *colorscheme, const int check_env); void set_default_colors(void); __END_DECLS #endif /* COLORS_H */ clifm-1.26.3/src/compat.c000066400000000000000000000237651506632037700151410ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* compat.c -- compatibility layer for legacy systems (before POSIX-1.2008) */ #if defined(CLIFM_LEGACY) #include "helpers.h" #include #include #include #include /* -------------------- *AT functions -------------------------- */ /* Replacement for fstatat(2) */ int old_stat(int fd, const char *restrict path, struct stat *sb, int flag) { UNUSED(fd); if (flag == AT_SYMLINK_NOFOLLOW) return lstat(path, sb); return stat(path, sb); } /* Replacement for fchmodat(2) */ int old_chmod(int fd, const char *path, mode_t mode, int flag) { UNUSED(fd); UNUSED(flag); return chmod(path, mode); /* flawfinder: ignore */ } /* Replacement for renameat(2) */ int old_rename(int olddirfd, const char *oldpath, int newdirfd, const char *newpath) { UNUSED(olddirfd); UNUSED(newdirfd); return rename(oldpath, newpath); /* flawfinder: ignore */ } /* Replacement for mkdirat(2) */ int old_mkdir(int dirfd, const char *pathname, mode_t mode) { UNUSED(dirfd); return mkdir(pathname, mode); /* flawfinder: ignore */ } /* Replacement for readlinkat(2) */ ssize_t old_readlink(int dirfd, const char *restrict pathname, char *restrict buf, size_t bufsiz) { UNUSED(dirfd); return readlink(pathname, buf, bufsiz); /* flawfinder: ignore */ } /* Replacement for symlinkat(2) */ int old_symlink(const char *target, int newdirfd, const char *linkpath) { UNUSED(newdirfd); return symlink(target, linkpath); /* flawfinder: ignore */ } /* Replacement for unlinkat(2) */ int old_unlink(int dirfd, const char *pathname, int lflags) { UNUSED(dirfd); UNUSED(lflags); return unlink(pathname); /* flawfinder: ignore */ } /* Replacement for fchownat(2) */ int old_chown(int fd, const char *path, uid_t owner, gid_t group, int flag) { UNUSED(fd); UNUSED(flag); return chown(path, owner, group); /* flawfinder: ignore */ } /* ----------------- strnlen ------------------------ */ /* strnlen(3) is not specified in POSIX-1.2001 */ size_t x_strnlen(const char *s, size_t len) { size_t i; for (i = 0; i < len && s[i]; i++); return i; } /* ----------------- realpath ------------------------ */ /* According to POSIX-1.2001, realpath(3) does not support RESOLVED_PATH * to be NULL. So, if it is NULL, lets allocate memory ourselves. */ char * old_realpath(const char *restrict path, char *restrict resolved_path) { if (resolved_path != NULL) return realpath(path, resolved_path); char *ptr = malloc(PATH_MAX + 1); if (!ptr) return (char *)NULL; char *ret = realpath(path, ptr); if (!ret) free(ptr); return ret; } /* ------------------------- scandir ------------------------ */ /* Taken from glibc 2.34, licensed GPL2.1+. * Modified code is licensed GPL2+. */ #ifndef _D_ALLOC_NAMLEN # ifdef _DIRENT_HAVE_D_NAMLEN # define _D_EXACT_NAMLEN(d) ((d)->d_namlen) # define _D_ALLOC_NAMLEN(d) (_D_EXACT_NAMLEN(d) + 1) # else # define _D_EXACT_NAMLEN(d) (strlen((d)->d_name)) # ifdef _DIRENT_HAVE_D_RECLEN # define _D_ALLOC_NAMLEN(d) (((char *)(d) + (d)->d_reclen) - &(d)->d_name[0]) # else # define _D_ALLOC_NAMLEN(d) (sizeof(d)->d_name > 1 ? sizeof(d)->d_name \ : _D_EXACT_NAMLEN(d) + 1) # endif /* _DIRENT_HAVE_RECLEN */ # endif /* _DIRENT_HAVE_D_TYPE */ #endif /* !_D_ALLOC_NAMLEN */ struct scandir_cancel_struct { DIR *dp; void *v; size_t cnt; }; /* Replacement for alphasort(3) */ int x_alphasort(const struct dirent **a, const struct dirent **b) { return strcoll((*a)->d_name, (*b)->d_name); } static void scandir_cancel_handler(void *arg) { struct scandir_cancel_struct *cp = arg; void **v = cp->v; for (size_t i = 0; i < cp->cnt; ++i) free(v[i]); free(v); closedir(cp->dp); } /* Replacement for scandir(3) */ int x_scandir(const char *dir, struct dirent ***namelist, int (*select)(const struct dirent *), int (*cmp)(const struct dirent **, const struct dirent **)) { if (!dir || !*dir) return (-1); DIR *dp = opendir(dir); if (dp == NULL) return (-1); struct dirent **v = NULL; size_t vsize = 0; struct dirent *d; struct scandir_cancel_struct c = { .dp = dp }; int result = 0; int save = errno; errno = 0; while ((d = readdir(dp)) != NULL) { if (select != NULL) { int selected = (*select)(d); errno = 0; if (!selected) continue; } if (c.cnt == vsize) { if (vsize == 0) vsize = 10; else vsize *= 2; struct dirent **new = realloc(v, vsize * sizeof(*v)); if (new == NULL) break; c.v = v = new; } size_t dsize = (size_t)(&d->d_name[_D_ALLOC_NAMLEN(d)] - (char *)d); struct dirent *vnew = malloc(dsize); if (vnew == NULL) break; v[c.cnt] = (struct dirent *)memcpy(vnew, d, dsize); c.cnt++; errno = 0; } if (errno == 0) { closedir(dp); if (cmp != NULL && v != NULL) qsort(v, c.cnt, sizeof(*v), (int (*)(const void *, const void *))cmp); *namelist = v; result = (int)c.cnt; } else { scandir_cancel_handler(&c); result = -1; } if (result > 0) errno = save; return result; } /* ------------------------ getline ------------------------ */ /* Code originally written by Michael Burr, and released into the public domain * https://stackoverflow.com/questions/12167946/how-do-i-read-an-arbitrarily-long-line-in-c/12169132#12169132 * * All changes are licensed under GPL-2.0-or-later. */ /* Figure out an appropriate new allocation size that's not too small or * too big. * These numbers seem to work pretty well for most text files. * The function returns the input value if it decides that new allocation * block would be just too big (the caller should handle this as an error). */ static size_t nx_getdelim_get_realloc_size(size_t current_size) { const size_t k_min_realloc_inc = 32; const size_t k_max_realloc_inc = 1024; if (SSIZE_MAX < current_size) return current_size; if (current_size <= k_min_realloc_inc) return current_size + k_min_realloc_inc; if (current_size >= k_max_realloc_inc) return current_size + k_max_realloc_inc; return current_size * 2; } /* Adds a new character to the buffer (LINEPTR), reallocating as necessary * to ensure the character and a following null terminator can fit. */ static int nx_getdelim_append(char **lineptr, size_t *bufsize, size_t count, char ch) { char *tmp = (char *)NULL; size_t tmp_size = 0; if (!lineptr || !bufsize) return (-1); if (count >= (((size_t)SSIZE_MAX) + 1)) /* Writing more than SSIZE_MAX to the buffer isn't supported */ return (-1); tmp = *lineptr; tmp_size = tmp ? *bufsize : 0; /* Make room for the current character (plus the null byte) */ if ((count + 2) > tmp_size) { tmp_size = nx_getdelim_get_realloc_size(tmp_size); tmp = realloc(tmp, tmp_size); if (!tmp) return (-1); } *lineptr = tmp; *bufsize = tmp_size; /* Remember, the reallocation size calculation might not have * changed the block size, so we have to check again. */ if (tmp && ((count + 2) <= tmp_size)) { tmp[count] = ch; count++; tmp[count] = 0; return 1; } return (-1); } #ifdef __HAIKU__ /* Haiku complains about -ENOMEM overflowing int. */ # define XENOMEM 1 #else # define XENOMEM ENOMEM #endif /* __HAIKU__ */ /* Read data into a dynamically resizable buffer until EOF or until a * delimiter character is found. The returned data will be null terminated * (unless there's an error allocating memory that prevents it). * * Returns the number of characters placed in the returned buffer, including * the delimiter character, but not including the terminating null byte. */ static ssize_t nx_getdelim(char **lineptr, size_t *n, int delim, FILE *stream) { char *line = (char *)NULL; size_t size = 0; size_t count = 0; int err = 0; if (!lineptr || !n) return -EINVAL; line = *lineptr; size = *n; for (;;) { int ch = fgetc(stream); /* flawfinder: ignore */ if (ch == EOF) break; ssize_t result = nx_getdelim_append(&line, &size, count, (char)ch); /* Check for error adding to the buffer (ie., out of memory) */ if (result < 0) { err = -XENOMEM; break; } ++count; /* Check if we're done because we've found the delimiter */ if ((unsigned char)ch == (unsigned char)delim) break; /* Check if we're passing the maximum supported buffer size */ if (count > SSIZE_MAX) { err = -EOVERFLOW; break; } } /* Update the caller's data */ *lineptr = line; *n = size; /* Check for various error returns */ if (err != 0) return err; if (ferror(stream)) return 0; /* if (feof(stream) && (count == 0)) { if (nx_getdelim_append(&line, &size, count, 0) < 0) return -XENOMEM; } */ /* Compilers, at least GCC and Clang, emit a warning here about a * possible memory leak. That's true, but according to getline(3), * which we are emulating here, it's the caller responsibility to * free the line pointer (LINEPTR) passed to the function. So, the * "leak" is intended. */ return (ssize_t)count; } static ssize_t x_getdelim(char **lineptr, size_t *n, char delim, FILE *stream) { ssize_t retval = nx_getdelim(lineptr, n, delim, stream); if (retval < 0) { errno = -(int)retval; retval = -1; } if (retval == 0) retval = -1; return retval; } /* Implementation of getline(3) */ ssize_t x_getline(char **lineptr, size_t *n, FILE *stream) { return x_getdelim(lineptr, n, '\n', stream); } #else void *skip_me_compat; #endif /* CLIFM_LEGACY */ clifm-1.26.3/src/compat.h000066400000000000000000000056521506632037700151410ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* compat.h */ #ifndef CLIFM_COMPAT_H #define CLIFM_COMPAT_H #include /* FILE */ /* Let's fake the following macros: we won't use them anyway. */ #ifndef AT_FDCWD # define AT_FDCWD (-100) #endif /* !AT_FDCWD */ #ifndef AT_SYMLINK_NOFOLLOW # define AT_SYMLINK_NOFOLLOW 0x100 #endif /* !AT_SYMLINK_NOFOLLOW */ #ifndef O_CLOEXEC # define O_CLOEXEC 0 #endif /* O_CLOEXEC */ #ifdef dirfd /* Just in case: on some systems (like NetBSD) dirfd is a macro (defined in * dirent.h) */ # undef dirfd #endif /* dirfd */ /* A dummy value, since we're not using file descriptors. Functions using * them are replaced by functions using plain filenames instead. */ #define dirfd(d) (0) #define alphasort x_alphasort #define fchownat old_chown #define fchmodat old_chmod #define fstatat old_stat #define getline x_getline #define mkdirat old_mkdir #define readlinkat old_readlink #define renameat old_rename #define scandir x_scandir #define strnlen x_strnlen #define symlinkat old_symlink #define unlinkat old_unlink __BEGIN_DECLS int old_chmod(int fd, const char *path, mode_t mode, int flag); int old_chown(int fd, const char *path, uid_t owner, gid_t group, int flag); int old_mkdir(int dirfd, const char *pathname, mode_t mode); ssize_t old_readlink(int dirfd, const char *restrict pathname, char *restrict buf, size_t bufsiz); char *old_realpath(const char *restrict path, char *restrict resolved_path); int old_rename(int olddirfd, const char *oldpath, int newdirfd, const char *newpath); int old_stat(int fd, const char *restrict path, struct stat *sb, int flag); int old_symlink(const char *target, int newdirfd, const char *linkpath); int old_unlink(int dirfd, const char *pathname, int lflags); int x_alphasort(const struct dirent **a, const struct dirent **b); ssize_t x_getline(char **lineptr, size_t *n, FILE *stream); int x_scandir(const char *dir, struct dirent ***namelist, int (*select)(const struct dirent *), int (*cmp)(const struct dirent **, const struct dirent **)); size_t x_strnlen(const char *s, size_t max); __END_DECLS #endif /* CLIFM_COMPAT_H */ clifm-1.26.3/src/config.c000066400000000000000000003721621506632037700151210ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* config.c -- functions to define, create, and set configuration files */ #include "helpers.h" #include #include #include #include #include #if defined(MAC_OS_X_RENAMEAT_SYS_STDIO_H) # include /* renameat(2) */ #endif /* MAC_OS_X_RENAMEAT_SYS_STDIO_H */ #include "autocmds.h" #include "aux.h" #include "checks.h" #include "colors.h" #include "config.h" #include "file_operations.h" #include "init.h" #include "listing.h" #include "messages.h" #include "misc.h" #include "navigation.h" #include "sort.h" /* num_to_sort_name() */ #include "spawn.h" /* Predefined time styles */ #define ISO_TIME "%Y-%m-%d" #define LONG_ISO_TIME "%Y-%m-%d %H:%M" #define FULL_ISO_TIME "%Y-%m-%d %H:%M:%S %z" #define FULL_ISO_NANO_TIME "%Y-%m-%d %H:%M:%S.%N %z" /* Regenerate the configuration file and create a back up of the old one. */ static int regen_config(void) { int config_found = 1; struct stat attr; if (stat(config_file, &attr) == -1) { puts(_("Configuration file not found")); config_found = 0; } if (config_found == 1) { char *backup = gen_backup_file(config_file, 1); if (!backup) return FUNC_FAILURE; if (renameat(XAT_FDCWD, config_file, XAT_FDCWD, backup) == -1) { xerror(_("Cannot rename '%s' to '%s': %s\n"), config_file, backup, strerror(errno)); free(backup); return errno; } char *abbrev = abbreviate_file_name(backup); printf(_("Old configuration file saved as '%s'\n"), abbrev ? abbrev : backup); free(backup); free(abbrev); } if (create_main_config_file(config_file) != FUNC_SUCCESS) return FUNC_FAILURE; printf(_("New configuration file written to '%s'\n"), config_file); reload_config(); return FUNC_SUCCESS; } static void print_config_value(const char *option, void *cur_value, void *def_value, const int type) { const char *ptr = SET_MISC_PTR; if (type == DUMP_CONFIG_STR) { char *cv = (char *)cur_value; char *dv = (char *)def_value; if (!cv || (dv && strcmp(cv, dv) == 0)) printf(" %s: \"%s\"\n", option, dv); else printf("%s%s%s %s%s: \"%s\" [\"%s\"]%s\n", mi_c, ptr, df_c, BOLD, option, cv, dv, df_c); } else if (type == DUMP_CONFIG_BOOL) { int cv = *((int *)cur_value), dv = *((int *)def_value); if (cv == dv) printf(" %s: %s\n", option, cv == 1 ? "true" : "false"); else printf("%s%s%s %s%s: %s [%s]%s\n", mi_c, ptr, df_c, BOLD, option, cv == 1 ? "true" : "false", dv == 1 ? "true" : "false", df_c); } else if (type == DUMP_CONFIG_CHR) { char cv = *((char *)cur_value), dv = *((char *)def_value); if (cv == dv) printf(" %s: '%c'\n", option, cv); else printf("%s%s%s %s%s: '%c' ['%c']%s\n", mi_c, ptr, df_c, BOLD, option, cv, dv, df_c); } else { /* CONFIG_BOOL_INT */ int cv = *((int *)cur_value), dv = *((int *)def_value); if (cv == dv) printf(" %s: %d\n", option, cv); else printf("%s%s%s %s%s: %d [%d]%s\n", mi_c, ptr, df_c, BOLD, option, cv, dv, df_c); } } /* Return a string representing the value for TabCompletionMode in * the config file. */ static char * get_tab_comp_mode_str(void) { switch (tabmode) { case FZF_TAB: return "fzf"; case FNF_TAB: return "fnf"; case SMENU_TAB: return "smenu"; case STD_TAB: /* fallthrough */ default: return "standard"; } } static void get_start_path_and_ws_names(char **sp, char **ws) { if (config_ok == 0 || !config_file) return; int fd; FILE *fp = open_fread(config_file, &fd); if (!fp) return; char line[PATH_MAX + 16]; *line = '\0'; while (fgets(line, (int)sizeof(line), fp)) { if (*line == 'W' && strncmp(line, "WorkspaceNames=", 15) == 0 && *(line + 15)) { char *tmp = remove_quotes(line + 15); if (!tmp || !*tmp) continue; *ws = savestring(tmp, strlen(tmp)); } if (*line == 'S' && strncmp(line, "StartingPath=", 13) == 0 && *(line + 13)) { char *tmp = remove_quotes(line + 13); if (!tmp || !*tmp) continue; *sp = savestring(tmp, strlen(tmp)); } } fclose(fp); } static char * get_quoting_style(const int style) { switch (style) { case QUOTING_STYLE_BACKSLASH: return "backslash"; case QUOTING_STYLE_DOUBLE_QUOTES: return "double"; case QUOTING_STYLE_SINGLE_QUOTES: return "single"; default: return "backslash"; } } static char * get_link_creat_mode(const int mode) { switch (mode) { case LNK_CREAT_ABS: return "absolute"; case LNK_CREAT_REL: return "relative"; case LNK_CREAT_REG: /* fallthrough */ default: return "literal"; } } static char * get_ia_value_str(const int val) { switch (val) { case AUTOCMD_MSG_FULL: return "full"; case AUTOCMD_MSG_SHORT: return "short"; case AUTOCMD_MSG_LONG: return "long"; case AUTOCMD_MSG_PROMPT: return "prompt"; case AUTOCMD_MSG_NONE: return "none"; default: return "prompt"; } } static char * gen_default_answer_value_str(const int cfg) { char val_d = cfg ? conf.default_answer.default_ : DEF_ANSWER_DEFAULT; char val_D = cfg ? conf.default_answer.default_all : DEF_ANSWER_DEFAULT_ALL; char val_o = cfg ? conf.default_answer.overwrite : DEF_ANSWER_OVERWRITE; char val_r = cfg ? conf.default_answer.remove : DEF_ANSWER_REMOVE; char val_R = cfg ? conf.default_answer.bulk_rename : DEF_ANSWER_BULK_RENAME; char val_t = cfg ? conf.default_answer.trash : DEF_ANSWER_TRASH; #define DA_BUFSIZE 32 static char bufa[DA_BUFSIZE]; static char bufb[DA_BUFSIZE]; char *p = cfg ? bufa : bufb; int l = 0; memset(p, '\0', DA_BUFSIZE); l += snprintf(p + l, DA_BUFSIZE - (size_t)l, "d:%c,", val_d ? val_d : '-'); l += snprintf(p + l, DA_BUFSIZE - (size_t)l, "D:%c,", val_D ? val_D : '-'); l += snprintf(p + l, DA_BUFSIZE - (size_t)l, "o:%c,", val_o ? val_o : '-'); l += snprintf(p + l, DA_BUFSIZE - (size_t)l, "r:%c,", val_r ? val_r : '-'); l += snprintf(p + l, DA_BUFSIZE - (size_t)l, "R:%c,", val_R ? val_R : '-'); l += snprintf(p + l, DA_BUFSIZE - (size_t)l, "t:%c,", val_t ? val_t : '-'); #undef DA_BUFSIZE if (l > 0 && p[l - 1] == ',') p[l - 1] = '\0'; return p; } static char * gen_desktop_notif_str(const int value) { switch (value) { case DESKTOP_NOTIF_NONE: return "false"; case DESKTOP_NOTIF_SYSTEM: return "system"; case DESKTOP_NOTIF_KITTY: return "kitty"; default: return "unknown"; } } /* Dump current value of config options (as defined in the config file), * highlighting those that differ from default values. * Note that values displayed here represent the CURRENT status of the * corresponding option, and not necessarily that of the config file: * some of these options can be changed on the fly via commands */ static int dump_config(void) { puts(_("The following is the list of options (as defined in the configuration " "file) and their current values. Whenever a value differs from the " "default, the entry is highlighted and the default value is displayed " "in square brackets.\n")); char *start_path = (char *)NULL, *ws_names = (char *)NULL; get_start_path_and_ws_names(&start_path, &ws_names); char *s = (char *)NULL; int n = 0; n = DEF_APPARENT_SIZE; print_config_value("ApparentSize", &conf.apparent_size, &n, DUMP_CONFIG_BOOL); n = DEF_AUTOCD; print_config_value("Autocd", &conf.autocd, &n, DUMP_CONFIG_BOOL); n = DEF_AUTOLS; print_config_value("AutoLs", &conf.autols, &n, DUMP_CONFIG_BOOL); n = DEF_AUTO_OPEN; print_config_value("AutoOpen", &conf.auto_open, &n, DUMP_CONFIG_BOOL); #ifndef _NO_SUGGESTIONS n = DEF_SUGGESTIONS; print_config_value("AutoSuggestions", &conf.suggestions, &n, DUMP_CONFIG_BOOL); #endif /* !_NO_SUGGESTIONS */ n = DEF_CASE_SENS_DIRJUMP; print_config_value("CaseSensitiveDirjump", &conf.case_sens_dirjump, &n, DUMP_CONFIG_BOOL); n = DEF_CASE_SENS_LIST; print_config_value("CaseSensitiveList", &conf.case_sens_list, &n, DUMP_CONFIG_BOOL); n = DEF_CASE_SENS_PATH_COMP; print_config_value("CaseSensitivePathComp", &conf.case_sens_path_comp, &n, DUMP_CONFIG_BOOL); n = DEF_CASE_SENS_SEARCH; print_config_value("CaseSensitiveSearch", &conf.case_sens_search, &n, DUMP_CONFIG_BOOL); n = DEF_CD_ON_QUIT; print_config_value("CdOnQuit", &conf.cd_on_quit, &n, DUMP_CONFIG_BOOL); n = DEF_CLASSIFY; print_config_value("Classify", &conf.classify, &n, DUMP_CONFIG_BOOL); n = DEF_CLEAR_SCREEN; print_config_value("ClearScreen", &conf.clear_screen, &n, DUMP_CONFIG_BOOL); n = DEF_COLOR_LNK_AS_TARGET; print_config_value("ColorLinksAsTarget", &conf.color_lnk_as_target, &n, DUMP_CONFIG_BOOL); s = term_caps.color < 256 ? DEF_COLOR_SCHEME : DEF_COLOR_SCHEME_256; print_config_value("ColorScheme", cur_cscheme, s, DUMP_CONFIG_STR); n = DEF_CP_CMD; print_config_value("cpCmd", &conf.cp_cmd, &n, DUMP_CONFIG_INT); s = gen_default_answer_value_str(0); char *cur_da_value = gen_default_answer_value_str(1); print_config_value("DefaultAnswer", cur_da_value, s, DUMP_CONFIG_STR); print_config_value("DesktopNotifications", gen_desktop_notif_str(conf.desktop_notifications), gen_desktop_notif_str(DEF_DESKTOP_NOTIFICATIONS), DUMP_CONFIG_STR); s = ""; print_config_value("DirhistIgnore", &conf.dirhistignore_regex, s, DUMP_CONFIG_STR); n = DEF_DIRHIST_MAP; print_config_value("DirhistMap", &conf.dirhist_map, &n, DUMP_CONFIG_BOOL); n = DEF_DISK_USAGE; print_config_value("DiskUsage", &conf.disk_usage, &n, DUMP_CONFIG_BOOL); n = DEF_EXT_CMD_OK; print_config_value("ExternalCommands", &conf.ext_cmd_ok, &n, DUMP_CONFIG_BOOL); n = DEF_FILES_COUNTER; print_config_value("FilesCounter", &conf.files_counter, &n, DUMP_CONFIG_BOOL); s = ""; print_config_value("Filter", filter.str, s, DUMP_CONFIG_STR); n = DEF_FULL_DIR_SIZE; print_config_value("FullDirSize", &conf.full_dir_size, &n, DUMP_CONFIG_BOOL); #ifndef _NO_FZF n = DEF_FUZZY_MATCH; print_config_value("FuzzyMatching", &conf.fuzzy_match, &n, DUMP_CONFIG_BOOL); n = DEF_FUZZY_MATCH_ALGO; print_config_value("FuzzyAlgorithm", &conf.fuzzy_match_algo, &n, DUMP_CONFIG_INT); n = DEF_FZF_PREVIEW; print_config_value("FzfPreview", &conf.fzf_preview, &n, DUMP_CONFIG_BOOL); #endif /* !_NO_FZF */ s = DEF_HISTIGNORE; print_config_value("HistIgnore", conf.histignore_regex, s, DUMP_CONFIG_STR); #ifndef _NO_ICONS n = DEF_ICONS; print_config_value("Icons", &conf.icons, &n, DUMP_CONFIG_BOOL); n = DEF_ICONS_GAP; print_config_value("IconsGap", &conf.icons_gap, &n, DUMP_CONFIG_INT); #endif /* !_NO_ICONS */ print_config_value("InformAutocmd", get_ia_value_str(conf.autocmd_msg), get_ia_value_str(DEF_AUTOCMD_MSG), DUMP_CONFIG_STR); n = DEF_LIGHT_MODE; print_config_value("LightMode", &conf.light_mode, &n, DUMP_CONFIG_BOOL); print_config_value("LinkCreationMode", get_link_creat_mode(conf.link_creat_mode), get_link_creat_mode(DEF_LINK_CREATION_MODE), DUMP_CONFIG_STR); n = DEF_LIST_DIRS_FIRST; print_config_value("ListDirsFirst", &conf.list_dirs_first, &n, DUMP_CONFIG_BOOL); n = DEF_LISTING_MODE; print_config_value("ListingMode", &conf.listing_mode, &n, DUMP_CONFIG_INT); n = DEF_LOG_CMDS; print_config_value("LogCmds", &conf.log_cmds, &n, DUMP_CONFIG_BOOL); n = DEF_LOG_MSGS; print_config_value("LogMsgs", &conf.log_msgs, &n, DUMP_CONFIG_BOOL); n = DEF_LONG_VIEW; print_config_value("LongViewMode", &conf.long_view, &n, DUMP_CONFIG_BOOL); n = DEF_MAX_DIRHIST; print_config_value("MaxDirhist", &conf.max_dirhist, &n, DUMP_CONFIG_INT); n = DEF_MAX_NAME_LEN; print_config_value("MaxFilenameLen", &conf.max_name_len, &n, DUMP_CONFIG_INT); n = DEF_MAX_HIST; print_config_value("MaxHistory", &conf.max_hist, &n, DUMP_CONFIG_INT); n = DEF_MAX_JUMP_TOTAL_RANK; print_config_value("MaxJumpTotalRank", &conf.max_jump_total_rank, &n, DUMP_CONFIG_INT); n = DEF_MAX_LOG; print_config_value("MaxLog", &conf.max_log, &n, DUMP_CONFIG_INT); n = DEF_PROMPT_P_MAX_PATH; print_config_value("MaxPath", &conf.prompt_p_max_path, &n, DUMP_CONFIG_INT); n = DEF_MAX_PRINTSEL; print_config_value("MaxPrintSelfiles", &conf.max_printselfiles, &n, DUMP_CONFIG_INT); n = DEF_MIN_NAME_TRUNC; print_config_value("MinNameTruncate", &conf.min_name_trunc, &n, DUMP_CONFIG_INT); n = DEF_MIN_JUMP_RANK; print_config_value("MinJumpRank", &conf.min_jump_rank, &n, DUMP_CONFIG_INT); n = DEF_MV_CMD; print_config_value("mvCmd", &conf.mv_cmd, &n, DUMP_CONFIG_INT); s = ""; print_config_value("Opener", conf.opener, s, DUMP_CONFIG_STR); n = DEF_PAGER; print_config_value("Pager", &conf.pager, &n, conf.pager > 1 ? DUMP_CONFIG_INT : DUMP_CONFIG_BOOL); n = DEF_PREVIEW_MAX_SIZE; print_config_value("PreviewMaxSize (in KiB)", &conf.preview_max_size, &n, DUMP_CONFIG_INT); n = DEF_PRINT_DIR_CMDS; print_config_value("PrintDirCmds", &conf.print_dir_cmds, &n, DUMP_CONFIG_BOOL); n = DEF_PRINTSEL; print_config_value("PrintSelfiles", &conf.print_selfiles, &n, DUMP_CONFIG_BOOL); s = DEF_PRIORITY_SORT_CHAR; print_config_value("PrioritySortChar", conf.priority_sort_char, s, DUMP_CONFIG_STR); n = DEF_PRIVATE_WS_SETTINGS; print_config_value("PrivateWorkspaceSettings", &conf.private_ws_settings, &n, DUMP_CONFIG_BOOL); s = DEF_PROP_FIELDS; print_config_value("PropFields", prop_fields_str, s, DUMP_CONFIG_STR); n = DEF_PROP_FIELDS_GAP; print_config_value("PropFieldsGap", &conf.prop_fields_gap, &n, DUMP_CONFIG_INT); s = ""; print_config_value("PTimeStyle", conf.ptime_str, s, DUMP_CONFIG_STR); n = DEF_PURGE_JUMPDB; print_config_value("PurgeJumpDB", &conf.purge_jumpdb, &n, DUMP_CONFIG_BOOL); print_config_value("QuotingStyle", get_quoting_style(conf.quoting_style), get_quoting_style(DEF_QUOTING_STYLE), DUMP_CONFIG_STR); n = DEF_READ_AUTOCMD_FILES; print_config_value("ReadAutocmdFiles", &conf.read_autocmd_files, &n, DUMP_CONFIG_BOOL); n = DEF_READ_DOTHIDDEN; print_config_value("ReadDotHidden", &conf.read_dothidden, &n, DUMP_CONFIG_BOOL); n = DEF_RESTORE_LAST_PATH; print_config_value("RestoreLastPath", &conf.restore_last_path, &n, DUMP_CONFIG_BOOL); n = DEF_RL_EDIT_MODE; print_config_value("RlEditMode", &rl_editing_mode, &n, DUMP_CONFIG_INT); n = DEF_RM_FORCE; print_config_value("rmForce", &conf.rm_force, &n, DUMP_CONFIG_BOOL); n = DEF_SEARCH_STRATEGY; print_config_value("SearchStrategy", &conf.search_strategy, &n, DUMP_CONFIG_INT); n = DEF_SHARE_SELBOX; print_config_value("ShareSelbox", &conf.share_selbox, &n, DUMP_CONFIG_BOOL); n = DEF_SHOW_HIDDEN; print_config_value("ShowHiddenFiles", &conf.show_hidden, &n, DUMP_CONFIG_BOOL); n = DEF_SKIP_NON_ALNUM_PREFIX; print_config_value("SkipNonAlnumPrefix", &conf.skip_non_alnum_prefix, &n, DUMP_CONFIG_BOOL); print_config_value("Sort", num_to_sort_name(conf.sort, 0), num_to_sort_name(DEF_SORT, 0), DUMP_CONFIG_STR); n = DEF_SORT_REVERSE; print_config_value("SortReverse", &conf.sort_reverse, &n, DUMP_CONFIG_BOOL); n = DEF_SPLASH_SCREEN; print_config_value("SplashScreen", &conf.splash_screen, &n, DUMP_CONFIG_BOOL); s = ""; print_config_value("StartingPath", start_path, s, DUMP_CONFIG_STR); free(start_path); #ifndef _NO_SUGGESTIONS n = DEF_CMD_DESC_SUG; print_config_value("SuggestCmdDesc", &conf.cmd_desc_sug, &n, DUMP_CONFIG_BOOL); n = DEF_SUG_FILETYPE_COLOR; print_config_value("SuggestFiletypeColor", &conf.suggest_filetype_color, &n, DUMP_CONFIG_BOOL); s = DEF_SUG_STRATEGY; print_config_value("SuggestionStrategy", conf.suggestion_strategy, s, DUMP_CONFIG_STR); #endif /* !_NO_SUGGESTIONS */ #ifndef _NO_HIGHLIGHT n = DEF_HIGHLIGHT; print_config_value("SyntaxHighlighting", &conf.highlight, &n, DUMP_CONFIG_BOOL); #endif /* !_NO_HIGHLIGHT */ char *ss = get_tab_comp_mode_str(); print_config_value("TabCompletionMode", ss, #ifndef _NO_FZF (bin_flags & FZF_BIN_OK) ? "fzf" : "standard", #else "standard", #endif /* !_NO_FZF */ DUMP_CONFIG_STR); s = DEF_TERM_CMD; print_config_value("TerminalCmd", conf.term, s, DUMP_CONFIG_STR); n = DEF_TIME_FOLLOWS_SORT; print_config_value("TimeFollowsSort", &conf.time_follows_sort, &n, DUMP_CONFIG_BOOL); n = DEF_TIMESTAMP_MARK; print_config_value("TimestampMark", &conf.timestamp_mark, &n, DUMP_CONFIG_BOOL); s = ""; print_config_value("TimeStyle", conf.time_str, s, DUMP_CONFIG_STR); n = DEF_TIPS; print_config_value("Tips", &conf.tips, &n, DUMP_CONFIG_BOOL); #ifndef _NO_TRASH n = DEF_TRASRM; print_config_value("TrashAsRm", &conf.tr_as_rm, &n, DUMP_CONFIG_BOOL); n = DEF_TRASH_FORCE; print_config_value("TrashForce", &conf.trash_force, &n, DUMP_CONFIG_BOOL); #endif /* !_NO_TRASH */ n = DEF_TRUNC_NAMES; print_config_value("TruncateNames", &conf.trunc_names, &n, DUMP_CONFIG_BOOL); n = DEF_WELCOME_MESSAGE; print_config_value("WelcomeMessage", &conf.welcome_message, &n, DUMP_CONFIG_BOOL); s = DEF_WELCOME_MESSAGE_STR; print_config_value("WelcomeMessageStr", conf.welcome_message_str, s, DUMP_CONFIG_STR); s = ""; print_config_value("WorkspaceNames", ws_names, s, DUMP_CONFIG_STR); free(ws_names); return FUNC_SUCCESS; } /* Edit the config file, either via the mime function or via the first * passed argument (e.g.: 'edit nano'). The 'reset' option regenerates * the configuration file and creates a back up of the old one. */ int config_edit(char **args) { if (xargs.stealth_mode == 1) { printf("%s: %s\n", PROGRAM_NAME, STEALTH_DISABLED); return FUNC_SUCCESS; } if (args[1] && IS_HELP(args[1])) { printf("%s\n", CONFIG_USAGE); return FUNC_SUCCESS; } if (args[1] && *args[1] == 'd' && strcmp(args[1], "dump") == 0) return dump_config(); if (args[1] && *args[1] == 'r' && strcmp(args[1], "reload") == 0) return config_reload(args[2]); if (args[1] && *args[1] == 'r' && strcmp(args[1], "reset") == 0) return regen_config(); if (config_ok == 0) { xerror(_("%s: Cannot access the configuration file\n"), PROGRAM_NAME); return FUNC_FAILURE; } char *opening_app = (args[1] && strcmp(args[1], "edit") == 0) ? args[2] : args[1]; /* Get modification time of the config file before opening it */ struct stat attr; /* If, for some reason (like someone erasing the file while the program * is running) clifmrc doesn't exist, recreate the configuration file. * Then run 'stat' again to reread the attributes of the file. */ if (stat(config_file, &attr) == -1) { create_main_config_file(config_file); if (stat(config_file, &attr) == -1) { xerror("%s: '%s': %s\n", PROGRAM_NAME, config_file, strerror(errno)); return errno; } } const time_t prev_mtime = attr.st_mtime; const int ret = open_config_file(opening_app, config_file); if (ret != FUNC_SUCCESS) return ret; /* Get modification time after opening the config file */ if (stat(config_file, &attr) == -1) { xerror("%s: %s: %s\n", PROGRAM_NAME, config_file, strerror(errno)); return errno; } /* If modification times differ, the file was modified after being opened */ if (prev_mtime != attr.st_mtime) { /* Reload configuration only if the config file was modified */ reload_config(); if (conf.autols == 1) reload_dirlist(); print_reload_msg(NULL, NULL, _(CONFIG_FILE_UPDATED)); } return ret; } int config_reload(const char *arg) { if (arg && IS_HELP(arg)) { puts(RELOAD_USAGE); return FUNC_SUCCESS; } const int exit_status = reload_config(); conf.welcome_message = 0; if (conf.autols == 1) reload_dirlist(); print_reload_msg(NULL, NULL, "Configuration file reloaded\n"); return exit_status; } /* Find the plugins-helper file and store its path in the PLUGINS_HELPER_FILE * global variable. It will used to set CLIFM_PLUGINS_HELPER environment * variable when running a plugin. * Returns zero on success or one on error. * 1. Try first the plugins directory. * 2. If not there, try the data dir. * 3. Else, try some standard locations. */ static int set_plugins_helper_file(void) { if (getenv("CLIFM_PLUGINS_HELPER")) return FUNC_SUCCESS; struct stat attr; if (plugins_dir && *plugins_dir) { char helper_path[PATH_MAX + 1]; snprintf(helper_path, sizeof(helper_path), "%s/plugins-helper", plugins_dir); if (stat(helper_path, &attr) != -1) { plugins_helper_file = savestring(helper_path, strlen(helper_path)); return FUNC_SUCCESS; } } if (data_dir && *data_dir) { char helper_path[PATH_MAX + 1]; snprintf(helper_path, sizeof(helper_path), "%s/%s/plugins/plugins-helper", data_dir, PROGRAM_NAME); if (stat(helper_path, &attr) != -1) { plugins_helper_file = savestring(helper_path, strlen(helper_path)); return FUNC_SUCCESS; } } char home_local[PATH_MAX + 1]; *home_local = '\0'; if (user.home && *user.home) { snprintf(home_local, sizeof(home_local), "%s/.local/share/clifm/plugins/plugins-helper", user.home); } const char *const std_paths[] = { home_local, #if defined(__HAIKU__) "/boot/system/non-packaged/data/clifm/plugins/plugins-helper", "/boot/system/data/clifm/plugins/plugins-helper", #elif defined(__TERMUX__) "/data/data/com.termux/files/usr/share/clifm/plugins/plugins-helper", "/data/data/com.termux/files/usr/local/share/clifm/plugins/plugins-helper", #else "/usr/share/clifm/plugins/plugins-helper", "/usr/local/share/clifm/plugins/plugins-helper", "/opt/local/share/clifm/plugins/plugins-helper", "/opt/share/clifm/plugins/plugins-helper", #endif /* __HAIKU__ */ NULL}; size_t i; for (i = 0; std_paths[i]; i++) { if (stat(std_paths[i], &attr) != -1) { plugins_helper_file = savestring(std_paths[i], strlen(std_paths[i])); return FUNC_SUCCESS; } } return FUNC_FAILURE; } static void set_shell_level(void) { char *shlvl = getenv("SHLVL"); int shlvl_n = shlvl ? atoi(shlvl) : -1; if (shlvl_n > 0 && shlvl_n < MAX_SHELL_LEVEL) shlvl_n++; else shlvl_n = 1; char tmp[MAX_INT_STR]; snprintf(tmp, sizeof(tmp), "%d", shlvl_n); setenv("SHLVL", tmp, 1); char *lvl = getenv("CLIFMLVL"); if (!lvl) { setenv("CLIFMLVL", "1", 1); return; } int lvl_n = atoi(lvl); if (lvl_n > 0 && lvl_n < (MAX_SHELL_LEVEL - shlvl_n)) lvl_n++; else lvl_n = 1; nesting_level = lvl_n; snprintf(tmp, sizeof(tmp), "%d", lvl_n); setenv("CLIFMLVL", tmp, 1); } /* Set a few environment variables. */ void set_env(const int reload) { if (xargs.stealth_mode == 1) return; setenv("CLIFM", (config_dir && *config_dir) ? config_dir : "1", 1); if (config_file && *config_file) setenv("CLIFMRC", config_file, 1); setenv("CLIFM_PID", xitoa((long long)own_pid), 1); setenv("CLIFM_VERSION", VERSION, 1); set_plugins_helper_file(); if (reload == 0) set_shell_level(); } /* Define the file for the Selection Box */ void set_sel_file(void) { if (xargs.sel_file == 1) /* Already set via --sel-file flag */ return; if (sel_file) { free(sel_file); sel_file = (char *)NULL; } if (!config_dir) return; size_t len = 0; if (conf.share_selbox == 0) { /* Private selection box is stored in the profile directory */ len = config_dir_len + 14; sel_file = xnmalloc(len, sizeof(char)); snprintf(sel_file, len, "%s/selbox.clifm", config_dir); } else { /* Shared selection box is stored in the general config dir */ len = config_dir_len + 23; sel_file = xnmalloc(len, sizeof(char)); snprintf(sel_file, len, "%s/.config/%s/selbox.clifm", user.home, PROGRAM_NAME); } } /* Copy the file SRC_FILENAME from the data directory (DATA_DIR) to the * directory DEST, and make DEST executable if EXEC is set to 1. * The original file will be copied into DEST with AT MOST * 600 permissions (via umask(3)), making sure the user has read/write * permissions (via xchmod()), just in case the original file has no such * permissions. */ static int import_from_data_dir(const char *src_filename, char *dest, const int exec) { if (!data_dir || !src_filename || !dest || !*data_dir || !*src_filename || !*dest) return FUNC_FAILURE; struct stat a; char sys_file[PATH_MAX + 1]; snprintf(sys_file, sizeof(sys_file), "%s/%s/%s", data_dir, PROGRAM_NAME, src_filename); if (stat(sys_file, &a) == -1) return FUNC_FAILURE; const mode_t old_umask = umask(exec == 1 ? 0077 : 0177); /* flawfinder: ignore */ char *cmd[] = {"cp", "--", sys_file, dest, NULL}; const int ret = launch_execv(cmd, FOREGROUND, E_NOSTDERR); umask(old_umask); /* flawfinder: ignore */ if (ret == FUNC_SUCCESS) { #ifndef __MSYS__ /* chmod(2) does not work on MSYS2. See * https://github.com/msys2/MSYS2-packages/issues/2612 */ xchmod(dest, exec == 1 ? "0700" : "0600", 1); #endif /* __MSYS__ */ return FUNC_SUCCESS; } return FUNC_FAILURE; } /* Create the keybindings file. */ int create_kbinds_file(void) { if (config_ok == 0 || !kbinds_file) return FUNC_FAILURE; struct stat attr; /* If the file already exists, do nothing */ if (stat(kbinds_file, &attr) == FUNC_SUCCESS) return FUNC_SUCCESS; /* If not, try to import it from DATADIR */ if (import_from_data_dir("keybindings.clifm", kbinds_file, 0) == FUNC_SUCCESS) return FUNC_SUCCESS; /* Else, create it */ int fd = 0; FILE *fp = open_fwrite(kbinds_file, &fd); if (!fp) { err('e', PRINT_PROMPT, "%s: Cannot create keybindings file " "'%s': %s\n", PROGRAM_NAME, kbinds_file, strerror(errno)); return FUNC_FAILURE; } fprintf(fp, "# Keybindings file for %s\n\n\ # Do not edit this file directly. Use the 'kb bind' command instead.\n\ \n\ # Alt+j\n\ previous-dir:\\ej\n\ # Shift+Left (rxvt)\n\ previous-dir:\\e[d\n\ # Shift+Left (xterm)\n\ previous-dir:\\e[1;2D\n\ # Shift+Left (others)\n\ previous-dir:\\e[2D\n\ \n\ # Alt+k\n\ next-dir:\\ek\n\ # Shift+Right (rxvt)\n\ next-dir:\\e[c\n\ # Shift+Right (xterm)\n\ next-dir:\\e[1;2C\n\ # Shift+Right (others)\n\ next-dir:\\e[2C\n\ first-dir:\\e\\C-j\n\ last-dir:\\e\\C-k\n\ \n\ # Alt+u\n\ parent-dir:\\eu\n\ # Shift+Up (rxvt)\n\ parent-dir:\\e[a\n\ # Shift+Up (xterm)\n\ parent-dir:\\e[1;2A\n\ # Shift+Up (others)\n\ parent-dir:\\e[2A\n\ \n\ # Alt+e\n\ home-dir:\\ee\n\ # Home key (rxvt)\n\ #home-dir:\\e[7~\n\ # Home key (xterm)\n\ #home-dir:\\e[H\n\ # Home key (Emacs term)\n\ #home-dir:\\e[1~\n\ \n\ # Alt+r\n\ root-dir:\\er\n\ # Alt+/\n\ root-dir:\\e/\n\ \n\ pinned-dir:\\ep\n\ workspace1:\\e1\n\ workspace2:\\e2\n\ workspace3:\\e3\n\ workspace4:\\e4\n\ \n\ # Help\n\ # F1-F3\n\ show-manpage:\\eOP\n\ show-manpage:\\e[11~\n\ show-cmds:\\eOQ\n\ show-cmds:\\e[12~\n\ show-kbinds:\\eOR\n\ show-kbinds:\\e[13~\n\n\ archive-sel:\\e\\C-a\n\ bookmarks:\\eb\n\ clear-line:\\ec\n\ clear-msgs:\\et\n\ #cmd-hist:\n\ copy-sel:\\e\\C-v\n\ create-file:\\en\n\ deselect-all:\\ed\n\ export-sel:\\e\\C-e\n\ dirs-first:\\eg\n\ launch-view:\\e-\n\ #lock:\\eo\n\ mountpoints:\\em\n\ #move-sel:\\e\\C-n\n\ new-instance:\\e\\C-x\n\ next-profile:\\e\\C-p\n\ only-dirs:\\e,\n\ #open-sel:\\e\\C-g\n\ prepend-sudo:\\ev\n\ previous-profile:\\e\\C-o\n\ rename-sel:\\e\\C-r\n\ remove-sel:\\e\\C-d\n\ refresh-screen:\\C-r\n\ run-pager:\\e0\n\ selbox:\\es\n\ select-all:\\ea\n\ show-dirhist:\\eh\n\ sort-previous:\\ez\n\ sort-next:\\ex\n\ toggle-hidden:\\ei\n\ toggle-hidden:\\e.\n\ toggle-light:\\ey\n\ toggle-long:\\el\n\ toggle-follow-links-long:\\e+\n\ toggle-max-name-len:\\e\\C-l\n\ toggle-disk-usage:\\e\\C-i\n\ toggle-virtualdir-full-paths:\\ew\n\ toggle-vi-mode:\\e\\C-j\n\ trash-sel:\\e\\C-t\n\ #untrash-all:\\e\\C-u\n\n\ # F6-F12\n\ open-mime:\\e[17~\n\ open-preview:\\e[18~\n\ #open-jump-db:\\e[18~\n\ edit-color-scheme:\\e[19~\n\ open-keybinds:\\e[20~\n\ open-config:\\e[21~\n\ open-bookmarks:\\e[23~\n\ quit:\\e[24~\n\ \n\ # Keybindings for plugins\n\ # 1) Make sure your plugin is in the plugins directory (or use any of the\n\ # plugins in there)\n\ # 2) Link pluginx to your plugin using the 'actions edit' command. E.g.:\n\ # \"plugin1=myplugin.sh\"\n\ # 3) Set a keybinding here for pluginx. E.g.: \"plugin1:\\C-y\"\n\n\ # Note: Up to 16 plugins are supported, i.e. from plugin1 through plugin16\n\n\ \n\ # Bound to the xclip plugin\n\ plugin1:\\C-y\n", PROGRAM_NAME); fclose(fp); return FUNC_SUCCESS; } /* Create the preview.clifm file. If possible, it is imported from the * data directory. */ static int create_preview_file(void) { char file[PATH_MAX + 1]; snprintf(file, sizeof(file), "%s/preview.clifm", config_dir); struct stat attr; if (stat(file, &attr) == FUNC_SUCCESS) return FUNC_SUCCESS; #if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__) \ && !defined(__DragonFly__) && !defined(__APPLE__) if (import_from_data_dir("preview.clifm", file, 0) == FUNC_SUCCESS) return FUNC_SUCCESS; #endif /* !BSD */ int fd = 0; FILE *fp = open_fwrite(file, &fd); if (!fp) { err('e', PRINT_PROMPT, "%s: Cannot create preview file " "'%s': %s\n", PROGRAM_NAME, file, strerror(errno)); return FUNC_FAILURE; } #if defined(_BE_POSIX) char lscmd[] = "ls -Ap;"; #elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) \ || defined(__DragonFly__) || defined(__sun) || defined(__APPLE__) char lscmd[] = "gls -Ap --color=always --indicator-style=none;ls -Ap;"; #else char lscmd[] = "ls -Ap --color=always --indicator-style=none;"; #endif /* !BSD */ fprintf(fp, " ######################################\n\ # Configuration file for Shotgun #\n\ # Clifm's file previewer #\n\ ######################################\n\ \n\ # Commented and blank lines are ignored\n\ \n\ # It is recommended to edit this file setting your preferred applications\n\ # first: the previewing process will be smoother and faster this way\n\ # You can even remove whatever applications you don't use\n\ \n\ # For syntax details consult the mimelist.clifm file\n\ \n\ # Uncomment this line to use pistol (or any other previewing program)\n\ #.*=pistol\n\ \n\ # Uncomment and edit this line to use Ranger's scope script:\n\ #.*=~/.config/ranger/scope.sh %%f 120 80 /tmp/clifm/ True\n\ \n\ # Uncomment to enable image previews for the corresponding file types:\n\ ;^text/rtf$|^application/.*(officedocument|msword|ms-excel|ms-powerpoint|opendocument).*=~/.config/clifm/clifmimg doc %%f %%u;\n\ ;^application/epub\\+zip$=~/.config/clifm/clifmimg epub %%f %%u;\n\ ;^application/x-mobipocket-ebook$=~/.config/clifm/clifmimg mobi %%f %%u;\n\ ;^application/pdf$=~/.config/clifm/clifmimg pdf %%f %%u;\n\ ;^image/vnd.djvu$=~/.config/clifm/clifmimg djvu %%f %%u;\n\ ;^image/svg\\+xml$=~/.config/clifm/clifmimg svg %%f %%u;\n\n\ # Display images directly via the 'image' method\n\ ;^image/(jpeg|png|tiff|webp|x-xwindow-dump)$=~/.config/clifm/clifmimg image %%f %%u;\n\ # Convert and display via the 'gif' method\n\ ;^image/.*=~/.config/clifm/clifmimg gif %%f %%u;\n\ ;N:.*\\.ora$=~/.config/clifm/clifmimg gif %%f %%u;\n\ ;N:.*\\.(kra|krz)$=~/.config/clifm/clifmimg krita %%f %%u;\n\n\ ;^video/.*|^application/(mxf|x-shockwave-flash|vnd.rn-realmedia)$=~/.config/clifm/clifmimg video %%f %%u;\n\ ;^audio/.*=~/.config/clifm/clifmimg audio %%f %%u;\n\ ;^application/postscript$=~/.config/clifm/clifmimg postscript %%f %%u;\n\ ;^font/.*|^application/(font.*|.*opentype)=~/.config/clifm/clifmimg font %%f %%u;\n\ ;N:.*\\.(cbz|cbr|cbt)$=~/.config/clifm/clifmimg comic %%f %%u;\n\ \n\ # Directories\n\ inode/directory=exa -a --tree --level=1;lsd -A --tree --depth=1 --color=always;tree -a -L 1;%s\n\ \n\ # Web content\n\ ^text/html$=w3m -dump;lynx -dump;elinks -dump;pandoc -s -t markdown;\n\ \n\ # Text\n\ ^text/rtf=catdoc;\n\ N:.*\\.json$=jq --color-output . ;python -m json.tool;\n\ N:.*\\.md$=glow -s dark;mdcat;\n\ ^text/.*|^application/javascript$=highlight -f --out-format=xterm256 --force;bat --style=plain --color=always;cat;\n\ \n\ # Office documents\n\ N:.*\\.xlsx$=xlsx2csv;file -b;\n\ N:.*\\.(odt|ods|odp|sxw)$=odt2txt;pandoc -s -t markdown;\n\ ^application/(.*wordprocessingml.document|.*epub+zip|x-fictionbook+xml)=pandoc -s -t markdown;\n\ ^application/msword=catdoc;\n\ ^application/ms-excel=xls2csv;\n\ \n\ # Archives\n\ N:.*\\.rar=unrar lt -p-;\n\ application/(zstd|x-rpm|debian.binary-package)=bsdtar --list --file;\n\ application/(zip|gzip|x-7z-compressed|x-xz|x-bzip*|x-tar)=atool --list;bsdtar --list --file;\n\ \n\ # PDF\n\ ^application/pdf$=pdftotext -l 10 -nopgbrk -q -- %%f -;mutool draw -F txt -i;exiftool;\n\ \n\ # Image, video, and audio\n\ ^image/vnd.djvu=djvutxt;exiftool;\n\ ^image/.*=exiftool;\n\ ^video/.*=mediainfo;exiftool;\n\ ^audio/.*=mediainfo;exiftool;\n\ \n\ # Torrent:\n\ application/x-bittorrent=transmission-show;\n\ \n\ # Fallback\n\ .*=file -b;\n", lscmd); fclose(fp); return FUNC_SUCCESS; } static int create_actions_file(char *file) { struct stat attr; /* If the file already exists, do nothing */ if (stat(file, &attr) == FUNC_SUCCESS) return FUNC_SUCCESS; /* If not, try to import it from DATADIR */ if (import_from_data_dir("actions.clifm", file, 0) == FUNC_SUCCESS) return FUNC_SUCCESS; /* Else, create it */ int fd = 0; FILE *fp = open_fwrite(file, &fd); if (!fp) { err('e', PRINT_PROMPT, "%s: Cannot create actions file " "'%s': %s\n", PROGRAM_NAME, file, strerror(errno)); return FUNC_FAILURE; } fprintf(fp, "######################\n" "# Actions file for %s #\n" "######################\n\n" "# Define here your custom actions. Actions are " "custom command names\n" "# bound to an executable file located either in " "DATADIR/clifm/plugins\n" "# (usually /usr/local/share/clifm/plugins) or in " "$XDG_CONFIG_HOME/clifm/plugins (usually ~/.config/clifm/plugins).\n" "# Actions can be executed directly from " "%s command line, as if they\n" "# were any other command, and the associated " "file will be executed\n" "# instead. All parameters passed to the action " "command will be passed\n" "# to the corresponding plugin as well.\n\n" "+=finder.sh\n" "++=jumper.sh\n" "-=fzfnav.sh\n" "*=fzfsel.sh\n" "**=fzfdesel.sh\n" "//=rgfind.sh\n" "_=fzcd.sh\n" "bcp=batch_copy.sh\n" "bmi=bm_import.sh\n" "bn=batch_create.sh\n" "clip=clip.sh\n" "cr=cprm.sh\n" "da=disk_analyzer.sh\n" "dr=dragondrop.sh\n" "fdups=fdups.sh\n" "gg=pager.sh\n" "h=fzfhist.sh\n" "i=img_viewer.sh\n" "ih=ihelp.sh\n" "kd=decrypt.sh\n" "ke=encrypt.sh\n" "music=music_player.sh\n" "ml=mime_list.sh\n" "plugin1=xclip.sh\n" "ptot=pdf_viewer.sh\n" "update=update.sh\n" "vid=vid_viewer.sh\n" "vt=virtualize.sh\n" "wall=wallpaper_setter.sh\n", PROGRAM_NAME, PROGRAM_NAME); fclose(fp); return FUNC_SUCCESS; } static char * define_tmp_rootdir(int *from_env) { char *temp = (char *)NULL; *from_env = 1; if (xargs.secure_env != 1 && xargs.secure_env_full != 1) { temp = getenv("CLIFM_TMPDIR"); if (!temp || !*temp) temp = getenv("TMPDIR"); } if (!temp || !*temp) { *from_env = 0; temp = P_tmpdir; } char *p = temp; if (*temp != '/') { p = normalize_path(temp, strlen(temp)); if (!p) p = temp; } size_t len = strlen(p); char *tmp_root_dir = savestring(p, len); if (p != temp) free(p); if (len > 1 && tmp_root_dir[len - 1] == '/') tmp_root_dir[len - 1] = '\0'; return tmp_root_dir; } /* Define and create the root of our temporary directory. Checks are made in * this order: CLIFM_TMPDIR, TMPDIR, P_tmpdir, and /tmp */ static char * create_tmp_rootdir(void) { int from_env = 0; char *tmp_root_dir = define_tmp_rootdir(&from_env); if (!tmp_root_dir || !*tmp_root_dir) goto END; struct stat a; if (stat(tmp_root_dir, &a) != -1) return tmp_root_dir; int ret = FUNC_SUCCESS; char *cmd[] = {"mkdir", "-p", "--", tmp_root_dir, NULL}; if ((ret = launch_execv(cmd, FOREGROUND, E_NOSTDERR)) == FUNC_SUCCESS) return tmp_root_dir; if (from_env == 0) /* Error creating P_tmpdir */ goto END; err('w', PRINT_PROMPT, _("%s: '%s': %s.\n" "Cannot create temporary directory. Falling back to '%s'.\n"), PROGRAM_NAME, tmp_root_dir, strerror(ret), P_tmpdir); free(tmp_root_dir); tmp_root_dir = savestring(P_tmpdir, P_tmpdir_len); if (stat(tmp_root_dir, &a) != -1) return tmp_root_dir; char *cmd2[] = {"mkdir", "-p", "--", tmp_root_dir, NULL}; if (launch_execv(cmd2, FOREGROUND, E_NOSTDERR) == FUNC_SUCCESS) return tmp_root_dir; END: /* If everything fails, fallback to /tmp */ free(tmp_root_dir); return savestring("/tmp", 4); } static void define_selfile(void) { /* SEL_FILE should have been set before by set_sel_file(). If not, * we do not have access to the config dir, in which case we use TMP_DIR. */ if (sel_file) return; const size_t tmpdir_len = strlen(tmp_dir); size_t len = 0; /* If the config directory isn't available, define an alternative * selection file in TMP_ROOTDIR (if available). */ if (conf.share_selbox == 0) { size_t prof_len = alt_profile ? strlen(alt_profile) : 7; /* 7 == lenght of "default" */ len = tmpdir_len + prof_len + 15; sel_file = xnmalloc(len, sizeof(char)); snprintf(sel_file, len, "%s/selbox_%s.clifm", tmp_dir, alt_profile ? alt_profile : "default"); } else { len = tmpdir_len + 14; sel_file = xnmalloc(len, sizeof(char)); snprintf(sel_file, len, "%s/selbox.clifm", tmp_dir); } err('w', PRINT_PROMPT, _("%s: %s: Using a temporary directory for " "the Selection Box. Selected files will not be persistent across " "reboots.\n"), PROGRAM_NAME, tmp_dir); } void create_tmp_files(void) { if (xargs.stealth_mode == 1) return; free(tmp_rootdir); /* In case we come from reload_config() */ tmp_rootdir = create_tmp_rootdir(); const size_t tmp_rootdir_len = strlen(tmp_rootdir); const size_t pnl_len = sizeof(PROGRAM_NAME) - 1; const size_t user_len = user.name ? strlen(user.name) : 7; /* 7: len of "unknown" */ #define MAX_TRIES 100 const size_t tmp_len = tmp_rootdir_len + pnl_len + user_len + 3 + DIGINUM(MAX_TRIES) + 1; tmp_dir = xnmalloc(tmp_len, sizeof(char)); snprintf(tmp_dir, tmp_len, "%s/%s-%s", tmp_rootdir, PROGRAM_NAME, user.name ? user.name : "unknown"); int suffix = 0; struct stat a; /* Loop until we get a valid tmp directory or MAX_TRIES is reached. */ while (1) { const int ret = lstat(tmp_dir, &a); if (ret == 0 && S_ISDIR(a.st_mode) && check_file_access(a.st_mode, a.st_uid, a.st_uid) == 1) break; if (ret == -1 && xmkdir(tmp_dir, S_IRWXU) == FUNC_SUCCESS) break; suffix++; if (suffix > MAX_TRIES) { snprintf(tmp_dir, tmp_len, "%s", tmp_rootdir); err('e', PRINT_PROMPT, _("%s: Cannot create temporary directory. " "Falling back to '%s'.\n"), PROGRAM_NAME, tmp_rootdir); break; } /* Append suffix and try again. */ snprintf(tmp_dir, tmp_len, "%s/%s-%s.%d", tmp_rootdir, PROGRAM_NAME, user.name ? user.name : "unknown", suffix); } #undef MAX_TRIES define_selfile(); } /* Set the main configuration directory. Three sources are examined: * 1. Alternative config dir, as set via -D,--config-dir. * 2. XDG_CONFIG_HOME/clifm (if not secure-env). * 3. user.home/.config/clifm: $HOME if not secure-env or pw_dir from the * passwd database. */ static void set_main_config_dir(const int secure_mode) { if (alt_config_dir && *alt_config_dir) { config_dir_gral = savestring(alt_config_dir, strlen(alt_config_dir)); return; } char *env = secure_mode == 0 ? getenv("XDG_CONFIG_HOME") : (char *)NULL; char *home_env = (env && *env) ? normalize_path(env, strlen(env)) : (char *)NULL; if (home_env && *home_env) { const size_t len = strlen(home_env) + (sizeof(PROGRAM_NAME) - 1) + 2; config_dir_gral = xnmalloc(len, sizeof(char)); snprintf(config_dir_gral, len, "%s/%s", home_env, PROGRAM_NAME); free(home_env); return; } free(home_env); const size_t len = user.home_len + (sizeof(PROGRAM_NAME) - 1) + 10; config_dir_gral = xnmalloc(len, sizeof(char)); snprintf(config_dir_gral, len, "%s/.config/%s", user.home, PROGRAM_NAME); } /* Set the profile directory. Two sources are examined: * 1. CONFIG_DIR/profiles/PROF (if PROF is set via -P,--profile) * 2. CONFIG_DIR/profiles/default * CONFIG_DIR is set by set_main_config_dir() */ static void set_profile_dir(const size_t config_gral_len) { /* alt_profile will not be NULL whenever the -P option is used * to run clifm under an alternative profile. */ if (alt_profile && *alt_profile) { const size_t len = config_gral_len + strlen(alt_profile) + 11; config_dir = xnmalloc(len, sizeof(char)); snprintf(config_dir, len, "%s/profiles/%s", config_dir_gral, alt_profile); } else { const size_t len = config_gral_len + 18; config_dir = xnmalloc(len, sizeof(char)); snprintf(config_dir, len, "%s/profiles/default", config_dir_gral); } config_dir_len = strlen(config_dir); } /* Set the main configuration file. Two sources are examined: * 1. Alternative config file, from the command line (-c,--config-file). * 3. PROFILE_DIR/clifmrc: PROFILE_DIR is set by set_profile_dir() */ static void set_main_config_file(void) { if (alt_config_file && *alt_config_file) { config_file = savestring(alt_config_file, strlen(alt_config_file)); return; } const size_t len = config_dir_len + (sizeof(PROGRAM_NAME) - 1) + 4; config_file = xnmalloc(len, sizeof(char)); snprintf(config_file, len, "%s/%src", config_dir, PROGRAM_NAME); } /* Set the history file, as defined in CLIFM_HISTFILE environment variable * or, if unset, using the main configuration directory. */ static void set_hist_file(const int secure_mode, const size_t tmp_len) { char *env_val = secure_mode == 0 ? getenv("CLIFM_HISTFILE") : (char *)NULL; char *hist_env = (env_val && *env_val) ? normalize_path(env_val, strlen(env_val)) : (char *)NULL; const size_t hist_len = (hist_env && *hist_env) ? strlen(hist_env) + 1 : tmp_len; hist_file = xnmalloc(hist_len, sizeof(char)); if (hist_env && *hist_env) xstrsncpy(hist_file, hist_env, hist_len); else snprintf(hist_file, hist_len, "%s/history.clifm", config_dir); free(hist_env); } static void check_file_safety(const char *name) { int safe = 1; struct stat a; if (!name || !*name || lstat(name, &a) == -1) return; else if (S_ISLNK(a.st_mode)) { err('w', PRINT_PROMPT, _("%s: Is a symbolic link\n"), name); safe = 0; } else if (!S_ISREG(a.st_mode)) { err('w', PRINT_PROMPT, _("%s: Is not a regular file\n"), name); safe = 0; } else if (a.st_nlink > 1) { err('w', PRINT_PROMPT, _("%s: There is another name hard linked " "to this file\n"), name); safe = 0; } if (safe == 0) err('w', PRINT_PROMPT, _("%s: File may be unsafe\n"), name); } static void check_config_files_integrity(void) { check_file_safety(config_file); check_file_safety(hist_file); check_file_safety(kbinds_file); check_file_safety(dirhist_file); check_file_safety(bm_file); check_file_safety(msgs_log_file); check_file_safety(cmds_log_file); check_file_safety(profile_file); check_file_safety(mime_file); check_file_safety(actions_file); check_file_safety(remotes_file); check_file_safety(prompts_file); char jump_file[PATH_MAX + 1]; snprintf(jump_file, sizeof(jump_file), "%s/jump.clifm", config_dir); check_file_safety(jump_file); char preview_file[PATH_MAX + 1]; snprintf(preview_file, sizeof(preview_file), "%s/preview.clifm", config_dir); check_file_safety(preview_file); } static void set_thumbnails_dir(void) { if (thumbnails_dir) return; const int se = (xargs.secure_env == 1 || xargs.secure_env_full == 1); const char *p = se == 0 ? getenv("XDG_CACHE_HOME") : (char *)NULL; if ((!p || !*p) && (!user.home || !*user.home)) return; if (p && *p) { const size_t len = strlen(p) + sizeof(PROGRAM_NAME) + 30; thumbnails_dir = xnmalloc(len, sizeof(char)); snprintf(thumbnails_dir, len, "%s/%s/thumbnails", p, PROGRAM_NAME); } else { const size_t len = user.home_len + sizeof(PROGRAM_NAME) + 26; thumbnails_dir = xnmalloc(len, sizeof(char)); snprintf(thumbnails_dir, len, "%s/.cache/%s/thumbnails", user.home, PROGRAM_NAME); } } static void define_config_file_names(void) { size_t tmp_len = 0; const int secure_mode = (xargs.secure_env == 1 || xargs.secure_env_full == 1); set_main_config_dir(secure_mode); /* config_dir_gral is set here. */ const size_t config_gral_len = strlen(config_dir_gral); set_profile_dir(config_gral_len); /* config_dir is set here */ set_main_config_file(); tmp_len = config_dir_len + 6; tags_dir = xnmalloc(tmp_len, sizeof(char)); snprintf(tags_dir, tmp_len, "%s/tags", config_dir); if (alt_kbinds_file) { kbinds_file = savestring(alt_kbinds_file, strlen(alt_kbinds_file)); } else { /* Keybindings per user, not per profile. */ tmp_len = config_gral_len + 19; kbinds_file = xnmalloc(tmp_len, sizeof(char)); snprintf(kbinds_file, tmp_len, "%s/keybindings.clifm", config_dir_gral); } tmp_len = config_gral_len + 8; colors_dir = xnmalloc(tmp_len, sizeof(char)); snprintf(colors_dir, tmp_len, "%s/colors", config_dir_gral); tmp_len = config_gral_len + 9; plugins_dir = xnmalloc(tmp_len, sizeof(char)); snprintf(plugins_dir, tmp_len, "%s/plugins", config_dir_gral); tmp_len = config_dir_len + 15; dirhist_file = xnmalloc(tmp_len, sizeof(char)); snprintf(dirhist_file, tmp_len, "%s/dirhist.clifm", config_dir); if (!alt_bm_file) { tmp_len = config_dir_len + 17; bm_file = xnmalloc(tmp_len, sizeof(char)); snprintf(bm_file, tmp_len, "%s/bookmarks.clifm", config_dir); } else { bm_file = savestring(alt_bm_file, strlen(alt_bm_file)); } if (!alt_mimelist_file) { tmp_len = config_dir_len + 16; mime_file = xnmalloc(tmp_len, sizeof(char)); snprintf(mime_file, tmp_len, "%s/mimelist.clifm", config_dir); } else { mime_file = savestring(alt_mimelist_file, strlen(alt_mimelist_file)); } tmp_len = config_dir_len + 15; msgs_log_file = xnmalloc(tmp_len, sizeof(char)); snprintf(msgs_log_file, tmp_len, "%s/msglogs.clifm", config_dir); cmds_log_file = xnmalloc(tmp_len, sizeof(char)); snprintf(cmds_log_file, tmp_len, "%s/cmdlogs.clifm", config_dir); set_hist_file(secure_mode, tmp_len); set_thumbnails_dir(); tmp_len = config_dir_len + 15; profile_file = xnmalloc(tmp_len, sizeof(char)); snprintf(profile_file, tmp_len, "%s/profile.clifm", config_dir); tmp_len = config_dir_len + 15; actions_file = xnmalloc(tmp_len, sizeof(char)); snprintf(actions_file, tmp_len, "%s/actions.clifm", config_dir); tmp_len = config_dir_len + 12; remotes_file = xnmalloc(tmp_len, sizeof(char)); snprintf(remotes_file, tmp_len, "%s/nets.clifm", config_dir); } static int import_data_file(const char *src, const char *dst, const int exec) { if (!data_dir || !config_dir_gral || !src || !dst) return FUNC_FAILURE; char dest_file[PATH_MAX + 1]; snprintf(dest_file, sizeof(dest_file), "%s/%s", config_dir_gral, dst); struct stat a; if (lstat(dest_file, &a) == 0) return FUNC_SUCCESS; return import_from_data_dir(src, dest_file, exec); } /* Create the main configuration file and save it into FILE. */ int create_main_config_file(char *file) { /* First, try to import it from DATADIR */ char src_filename[NAME_MAX]; snprintf(src_filename, sizeof(src_filename), "%src", PROGRAM_NAME); if (import_from_data_dir(src_filename, file, 0) == FUNC_SUCCESS) return FUNC_SUCCESS; /* If not found, create it */ int fd; FILE *config_fp = open_fwrite(file, &fd); if (!config_fp) { err('e', PRINT_PROMPT, "%s: Cannot create configuration " "file '%s': %s\nFalling back to default values\n", PROGRAM_NAME, file, strerror(errno)); return FUNC_FAILURE; } fprintf(config_fp, "\t\t###########################################\n\ \t\t# CLIFM #\n\ \t\t# The Command Line File Manager #\n\ \t\t###########################################\n\n" "# This is the configuration file for Clifm\n\n" "# Lines starting with '#' or ';' are commented out (ignored).\n\ # Uncomment an option to override the default value.\n\n" "# Set the color scheme.\n\ ;ColorScheme=%s\n\n" "# Display number of files contained by directories when listing files.\n\ ;FilesCounter=%s\n\n" "# How to list files: 0 = vertically (like ls(1) would), 1 = horizontally.\n\ ;ListingMode=%d\n\n" "# List files automatically after changing the current directory.\n\ ;AutoLs=%s\n\n" "# Display errors, warnings, and notices using desktop notifications ('kitty', 'system', or 'false')\n\ ;DesktopNotifications=%s\n\n" "# Print a map of the current position in the directory\n\ # history list, showing previous, current, and next entries.\n\ ;DirhistMap=%s\n\n" "# Use a regex expression to filter filenames when listing files.\n\ # Run 'help file-filters' for more information.\n\ ;Filter=""\n\n" "# Set the default copy command. Available options are:\n\ # 0: 'cp -Rp', 1: 'cp -Rp' (force), 2: 'advcp -gRp', 3: 'advcp -gRp' (force),\n\ # 4: 'wcp', and 5: 'rsync -avP'\n\ # Note: 2-5 include a progress bar\n\ ;cpCmd=%d\n\n" "# Set the default move command. Available options are:\n\ # 0: 'mv', 1: 'mv' (force), 2: 'advmv -g', and 3: 'advmv -g' (force)\n\ # Note: 2 and 3 include a progress bar\n\ ;mvCmd=%d\n\n" "# If set to true, the 'r' command will never prompt before removals.\n\ ;rmForce=%s\n\n", "# Default answers for specific confirmation prompts:\n\ ;DefaultAnswer=\"\"\n\n" DEF_COLOR_SCHEME, DEF_FILES_COUNTER == 1 ? "true" : "false", DEF_LISTING_MODE, DEF_AUTOLS == 1 ? "true" : "false", DEF_DESKTOP_NOTIFICATIONS == DESKTOP_NOTIF_SYSTEM ? "system" : (DEF_DESKTOP_NOTIFICATIONS == DESKTOP_NOTIF_KITTY ? "kitty" : "false"), DEF_DIRHIST_MAP == 1 ? "true" : "false", DEF_CP_CMD, DEF_MV_CMD, DEF_RM_FORCE == 1 ? "true" : "false"); fprintf(config_fp, "# How 'l' creates symlinks (absolute, relative, literal).\n\ ;LinkCreationMode=%s\n\n" "# Enable fuzzy matching for filename/path completions and suggestions.\n\ ;FuzzyMatching=%s\n\n" "# Fuzzy matching algorithm: 1 (faster, non-Unicode), 2 (slower, Unicode).\n\ ;FuzzyAlgorithm=%d\n\n" "# letion mode: 'standard', 'fzf', 'fnf', or 'smenu'. Defaults to\n\ # 'fzf' if the binary is found in PATH. Otherwise, the standard mode is used.\n\ ;TabCompletionMode=\n\n" "# File previews for tab completion (fzf mode only). Possible values:\n\ # true, false, hidden (enabled, but hidden; toggle it with Alt+p)\n\ ;FzfPreview=%s\n\n" "# Do not preview files larger than this value (-1 for unlimited).\n\ ;PreviewMaxSize=%d\n\n" ";WelcomeMessage=%s\n\ ;WelcomeMessageStr=\"\"\n\n\ # Print %s's logo screen at startup.\n\ ;SplashScreen=%s\n\n\ # Show hidden files (true, false, first, last)\n\ ;ShowHiddenFiles=%s\n\n\ # Display extended file metadata next to filenames (long listing format).\n\ ;LongViewMode=%s\n\ # Properties fields to be printed in long view mode.\n\ # f = file counter for directories\n\ # B = file allocated blocks\n\ # d = inode number\n\ # l = number of hard links\n\ # p|n = permissions: either symbolic (p) or numeric/octal (n)\n\ # i|I = user/group IDs: as number (i) or name (I)\n\ # G = if i|I is set, don't print group\n\ # a|b|m|c = last (a)ccess, (b)irth, (m)odification, or status (c)hange time\n\ # s|S = size (either human readable (s) or bytes (S))\n\ # x = extended attributes/ACL/capabilities (marked as '@') (requires p|n)\n\ # A single dash (\'-\') disables all fields\n\ ;PropFields=\"%s\"\n\ # Append a mark to timestamps in long view to identify the kind of timestamp.\n\ ;TimestampMark=%s\n\ # Make time field in long view follow sort if sorting by time.\n\ ;TimeFollowsSort=%s\n\ # Number of spaces between fields in long view (1-2).\n\ ;PropFieldsGap=%d\n\ # Format used to print timestamps in long view. Available options:\n\ # default, relative, iso, long-iso, full-iso, +FORMAT (see strftime(3))\n\ ;TimeStyle=\"\"\n\ # Same as TimeStyle, but for the 'p/pp' command (relative time not supported)\n\ ;PTimeStyle=\"\"\n\ # Print files apparent size instead of actual device usage\n\ ;ApparentSize=%s\n\ # If running in long view, print directories total size\n\ ;FullDirSize=%s\n\n\ # Log errors and warnings\n\ ;LogMsgs=%s\n\ # Log commands entered in the command line\n\ ;LogCmds=%s\n\n" "# Minimum length at which a filename can be truncated in long view mode.\n\ # If running in long mode, this setting overrides MaxFilenameLen whenever\n\ # this latter is smaller than MINNAMETRUNCATE.\n\ ;MinNameTruncate=%d\n\n" "# When a directory rank in the jump database is below MinJumpRank, it\n\ # is removed. If set to 0, directories are kept indefinitely.\n\ ;MinJumpRank=%d\n\n" "# When the sum of all ranks in the jump database reaches MaxJumpTotalRank,\n\ # all ranks will be reduced using a dynamic factor so that the total sum falls\n\ # below MaxJumpTotalRank again. Those entries falling below MinJumpRank will\n\ # be deleted.\n\ ;MaxJumpTotalRank=%d\n\n" "# Automatically purge the jump database from non-existing directories.\n\ ;PurgeJumpDB=%s\n\n" "# Should Clifm be allowed to run external, shell commands?\n\ ;ExternalCommands=%s\n\n" "# Write the last visited directory to ~/.config/clifm/.last to be\n\ # later accessed by the corresponding shell function at program exit.\n\ # To enable this feature consult the manpage.\n\ ;CdOnQuit=%s\n\n", DEF_LINK_CREATION_MODE == LNK_CREAT_ABS ? "absolute" : (DEF_LINK_CREATION_MODE == LNK_CREAT_REL ? "relative" : "literal"), DEF_FUZZY_MATCH == 1 ? "true" : "false", DEF_FUZZY_MATCH_ALGO, DEF_FZF_PREVIEW == 1 ? "true" : "false", DEF_PREVIEW_MAX_SIZE, DEF_WELCOME_MESSAGE == 1 ? "true" : "false", PROGRAM_NAME, DEF_SPLASH_SCREEN == 1 ? "true" : "false", DEF_SHOW_HIDDEN == 1 ? "true" : "false", DEF_LONG_VIEW == 1 ? "true" : "false", DEF_PROP_FIELDS, DEF_TIMESTAMP_MARK == 1 ? "true" : "false", DEF_TIME_FOLLOWS_SORT == 1 ? "true" : "false", DEF_PROP_FIELDS_GAP, DEF_APPARENT_SIZE == 1 ? "true" : "false", DEF_FULL_DIR_SIZE == 1 ? "true" : "false", DEF_LOG_MSGS == 1 ? "true" : "false", DEF_LOG_CMDS == 1 ? "true" : "false", DEF_MIN_NAME_TRUNC, DEF_MIN_JUMP_RANK, DEF_MAX_JUMP_TOTAL_RANK, DEF_PURGE_JUMPDB == 1 ? "true" : "false", DEF_EXT_CMD_OK == 1 ? "true" : "false", DEF_CD_ON_QUIT == 1 ? "true" : "false" ); fprintf(config_fp, "# If set to true, a command name that is the name of a directory or a\n\ # file is executed as if it were the argument to the the 'cd' or the \n\ # 'open' commands respectively: 'cd DIR' works the same as just 'DIR'\n\ # and 'open FILE' works the same as just 'FILE'.\n\ ;Autocd=%s\n\ ;AutoOpen=%s\n\n" "# Enable autocommand files (.cfm.in and .cfm.out).\n\ ;ReadAutocmdFiles=%s\n\n" "# How to display autocommand notifications (none, mini, short, long,\n\ # full, prompt)\n\ ;InformAutocmd=prompt\n\n" "# Read .hidden files.\n\ ;ReadDotHidden=%s\n\n" "# Enable auto-suggestions.\n\ ;AutoSuggestions=%s\n\n" "# The following checks will be performed in the order specified\n\ # by SuggestionStrategy. Available checks:\n\ # a = Aliases names\n\ # c = Path completion\n\ # e = ELN's\n\ # f = Filenames in current directory\n\ # h = Commands history\n\ # j = Jump database\n\ ;SuggestionStrategy=%s\n\n" "# Suggest filenames using the corresponding file type color\n\ # (set via the color scheme file).\n\ ;SuggestFiletypeColor=%s\n\n" "# Suggest a brief decription for internal commands.\n\ ;SuggestCmdDesc=%s\n\n" ";SyntaxHighlighting=%s\n\n" "# How to quote expanded ELN's (regular files only): backslash, single, double.\n\ ;QuotingStyle=%s\n\n" "# We have three search strategies: 0 = glob-only, 1 = regex-only,\n\ # and 2 = glob-regex.\n\ ;SearchStrategy=%d\n\n", DEF_AUTOCD == 1 ? "true" : "false", DEF_AUTO_OPEN == 1 ? "true" : "false", DEF_READ_AUTOCMD_FILES == 1 ? "true" : "false", DEF_READ_DOTHIDDEN == 1 ? "true" : "false", DEF_SUGGESTIONS == 1 ? "true" : "false", DEF_SUG_STRATEGY, DEF_SUG_FILETYPE_COLOR == 1 ? "true" : "false", DEF_CMD_DESC_SUG == 1 ? "true" : "false", DEF_HIGHLIGHT == 1 ? "true" : "false", DEF_QUOTING_STYLE == QUOTING_STYLE_BACKSLASH ? "backslash" : (DEF_QUOTING_STYLE == QUOTING_STYLE_DOUBLE_QUOTES ? "double" : "single"), DEF_SEARCH_STRATEGY ); fprintf(config_fp, "# In light mode, extra file type checks (except those provided by\n\ # the d_type field of the dirent structure (see readdir(3))\n\ # are disabled to speed up the listing process. Because of this, we cannot\n\ # know in advance if a file is readable by the current user, if it is executable,\n\ # SUID, SGID, if a symlink is broken, and so on. The file extension check is\n\ # ignored as well, so that the color per extension feature is disabled.\n\ ;LightMode=%s\n\n" "# If running with colors, append directory indicator\n\ # to directories. If running without colors (via the --no-color option),\n\ # append file type indicator at the end of filenames.\n\ ;Classify=%s\n\n" "# Color links as target filename.\n\ ;ColorLinksAsTarget=%s\n\n" "# Should the Selection Box be shared among different profiles?\n\ ;ShareSelbox=%s\n\n" "# Choose the file opener for opening files with their default associated\n\ # application. If not set, Lira (Clifm's builtin opener) is used.\n\ ;Opener=\n\n" "# Only used when opening a directory via a new Clifm instance (with the 'x'\n\ # command), this option specifies the command to be used to launch a\n\ # terminal emulator to run Clifm on it.\n\ ;TerminalCmd='%s'\n\n" "# How to sort files: none, name, size, atime, btime, ctime, mtime,\n\ # version, extension, inode, owner, group, blocks, links, type.\n\ ;Sort=version\n\ # Sort in reverse order\n\ ;SortReverse=%s\n\ # Files starting with PrioritySortChar are listed at top of the file list.\n\ ;PrioritySortChar:%s\n\n" "# If set to true, settings changed in the current workspace (only via\n\ # the command line or keyboard shortcuts) are kept private to that workspace\n\ # and made persistent (for the current session only), even when switching\n\ # workspaces.\n\ ;PrivateWorkspaceSettings=%s\n\n" "# A comma separated list of workspace names in the form NUM=NAME\n\ # Example: \"1=MAIN,2=EXTRA,3=GIT,4=WORK\" or \"1=α,2=β,3=γ,4=δ\".\n\ ;WorkspaceNames=\"\"\n\n" "# Print a usage tip at startup.\n\ ;Tips=%s\n\n\ ;ListDirsFirst=%s\n\n\ # Enable case sensitive listing for files in the current directory.\n\ ;CaseSensitiveList=%s\n\n\ # Enable case sensitive lookups for the directory jumper function (via \n\ # the 'j' command).\n\ ;CaseSensitiveDirJump=%s\n\n\ # Enable case sensitive completion for filenames.\n\ ;CaseSensitivePathComp=%s\n\n\ # Enable case sensitive search.\n\ ;CaseSensitiveSearch=%s\n\ # Skip non-alphanumeric characters when sorting files ('version' or 'name').\n\ ;SkipNonAlnumPrefix=%s\n\n\ # Mas, the file list pager. Possible values are:\n\ # 0/false: Disable the pager\n\ # 1/true: Run the pager whenever the list of files does not fit on the screen\n\ # >1: Run the pager whenever the number of files in the current directory is\n\ # greater than or equal to this value (e.g., 1000)\n\ ;Pager=%s\n\ # Define how to list files in the pager: auto (default), short, long\n\ ;PagerView=%s\n\n" "# Maximum filename length for listed files. If TruncateNames is set to\n\ # true, names larger than MAXFILENAMELEN will be truncated at MAXFILENAMELEN\n\ # using a tilde.\n\ # Set it to -1 (or leave empty) to remove this limit.\n\ # When running in long mode, this setting is overriden by MinNameTruncate\n\ # whenever MAXFILENAMELEN is smaller than MINNAMETRUNCATE.\n\ ;MaxFilenameLen=%d\n\n\ # Truncate filenames longer than MAXFILENAMELEN.\n\ ;TruncateNames=%s\n\n", DEF_LIGHT_MODE == 1 ? "true" : "false", DEF_CLASSIFY == 1 ? "true" : "false", DEF_COLOR_LNK_AS_TARGET == 1 ? "true" : "false", DEF_SHARE_SELBOX == 1 ? "true" : "false", DEF_TERM_CMD, DEF_SORT_REVERSE == 1 ? "true" : "false", DEF_PRIORITY_SORT_CHAR, DEF_PRIVATE_WS_SETTINGS == 1 ? "true" : "false", DEF_TIPS == 1 ? "true" : "false", DEF_LIST_DIRS_FIRST == 1 ? "true" : "false", DEF_CASE_SENS_LIST == 1 ? "true" : "false", DEF_CASE_SENS_DIRJUMP == 1 ? "true" : "false", DEF_CASE_SENS_PATH_COMP == 1 ? "true" : "false", DEF_CASE_SENS_SEARCH == 1 ? "true" : "false", DEF_SKIP_NON_ALNUM_PREFIX == 1 ? "true" : "false", DEF_PAGER == 1 ? "true" : "false", DEF_PAGER_VIEW == PAGER_AUTO ? "auto" : (DEF_PAGER_VIEW == PAGER_LONG ? "long" : "short"), DEF_MAX_NAME_LEN, DEF_TRUNC_NAMES == 1 ? "true" : "false" ); fprintf(config_fp, ";MaxHistory=%d\n\ ;MaxDirhist=%d\n\ ;MaxLog=%d\n\ ;HistIgnore=%s\n\ ;DirhistIgnore=\"\"\n\ ;Icons=%s\n\ ;IconPad=%d\n\ ;Umask=077\n\ ;DiskUsage=%s\n\n" "# Print the list of selected files. You can limit the number of printed \n\ # entries using the MaxPrintSelfiles option (-1 = no limit, 0 = auto (never\n\ # print more than half terminal height), or any custom value).\n\ ;PrintSelfiles=%s\n\ ;MaxPrintSelfiles=%d\n\n" "# Clear the screen before listing files.\n\ ;ClearScreen=%s\n\n" "# If not specified, StartingPath defaults to the current working\n\ # directory. If set, it overrides RestoreLastPath.\n\ ;StartingPath=\n\n" "# If set to true, start Clifm in the last visited directory (and in the\n\ # last used workspace). This option is overriden by StartingPath (if set).\n\ ;RestoreLastPath=%s\n\n" "# If set to true, the 'r' command executes 'trash' instead of 'rm' to\n\ # prevent accidental deletions.\n\ ;TrashAsRm=%s\n\n" "# If set to true, do not ask for confirmation before trashing files.\n\ ;TrashForce=%s\n\n" "# Set readline editing mode: 0 for vi and 1 for emacs (default).\n\ ;RlEditMode=%d\n\n", DEF_MAX_HIST, DEF_MAX_DIRHIST, DEF_MAX_LOG, DEF_HISTIGNORE, DEF_ICONS == 1 ? "true" : "false", DEF_ICONS_GAP, DEF_DISK_USAGE == 1 ? "true" : "false", DEF_PRINTSEL == 1 ? "true" : "false", DEF_MAX_PRINTSEL, DEF_CLEAR_SCREEN == 1 ? "true" : "false", DEF_RESTORE_LAST_PATH == 1 ? "true" : "false", DEF_TRASRM == 1 ? "true" : "false", DEF_TRASH_FORCE == 1 ? "true" : "false", DEF_RL_EDIT_MODE ); fputs( "# ALIASES\n\ #alias ls='ls --color=auto -A'\n\n" "# PROMPT COMMANDS\n\ # Write below the commands you want to be executed before the prompt. E.g.:\n\ #promptcmd /usr/share/clifm/plugins/git_status.sh\n\ #promptcmd date | awk '{print $1\", \"$2,$3\", \"$4}'\n\n" "# AUTOCOMMANDS\n\ # Control Clifm settings on a per directory basis. For more information\n\ # consult the manpage.\n\ #autocmd /media/remotes/** lm=1,fc=0\n\ #autocmd @ws3 lv=1\n\ #autocmd ~/important !printf \"Keep your fingers outta here!\\n\" && read -n1\n\ #autocmd ~/Downloads !/usr/share/clifm/plugins/fzfnav.sh\n\n", config_fp); fclose(config_fp); return FUNC_SUCCESS; } static int create_def_color_scheme256(void) { char cscheme_file[PATH_MAX + 1]; snprintf(cscheme_file, sizeof(cscheme_file), "%s/%s.clifm", colors_dir, DEF_COLOR_SCHEME_256); /* If the file already exists, do nothing */ struct stat attr; if (stat(cscheme_file, &attr) != -1) return FUNC_SUCCESS; /* Try to import it from data dir */ if (import_color_scheme(DEF_COLOR_SCHEME_256) == FUNC_SUCCESS) return FUNC_SUCCESS; return FUNC_FAILURE; } static void create_def_color_scheme(void) { if (!colors_dir || !*colors_dir) return; if (term_caps.color >= 256) create_def_color_scheme256(); char cscheme_file[PATH_MAX + 1]; snprintf(cscheme_file, sizeof(cscheme_file), "%s/%s.clifm", colors_dir, DEF_COLOR_SCHEME); /* If the file already exists, do nothing */ struct stat attr; if (stat(cscheme_file, &attr) != -1) return; /* Try to import it from data dir */ if (import_color_scheme(DEF_COLOR_SCHEME) == FUNC_SUCCESS) return; /* If cannot be imported either, create it with default values */ int fd; FILE *fp = open_fwrite(cscheme_file, &fd); if (!fp) { err('w', PRINT_PROMPT, "%s: Cannot create default color scheme " "file: '%s' : %s\n", PROGRAM_NAME, cscheme_file, strerror(errno)); return; } fprintf(fp, "# Default color scheme for %s\n\n\ # FiletypeColors defines the color used for file types when listing files,\n\ # just as InterfaceColors defines colors for Clifm's interface and ExtColors\n\ # for file extensions. They all make use of the same format used by the\n\ # LS_COLORS environment variable. Thus, \"di=1;34\" means that (non-empty)\n\ # directories will be listed in bold blue.\n\ # Color codes are traditional ANSI escape sequences less the escape char and\n\ # the final 'm'. 8 bit, 256 colors, RGB, and hex (#rrggbb) colors are supported.\n\ # A detailed explanation of all these codes can be found in the manpage.\n\n" "FiletypeColors=\"%s\"\n\n" "InterfaceColors=\"%s\"\n\n" "# Same as FiletypeColors, but for file extensions. The format is always\n\ # *.EXT=COLOR (extensions are case insensitive)\n" "ExtColors=\"%s\"\n\n" "# Color shades used to colorize timestamps and file sizes. Consult the\n\ # manpage for more information\n" "DateShades=\"%s\"\n" "SizeShades=\"%s\"\n\n" "DirIconColor=\"00;33\"\n\n" "DividingLine=\"%s\"\n\n" "# If set to 'true', automatically print notifications at the left\n\ # of the prompt. If set to 'false', let the prompt string handle these notifications\n\ # itself via escape codes. See the manpage for more information.\n" "Notifications=\"%s\"\n\n" "Prompt=\"%s\"\n\n" "# An alternative prompt to warn the user about invalid command names\n" "EnableWarningPrompt=\"%s\"\n\n" "WarningPrompt=\"%s\"\n\n" "FzfTabOptions=\"%s\"\n\n", PROGRAM_NAME, term_caps.color >= 256 ? DEF_FILE_COLORS_256 : DEF_FILE_COLORS, term_caps.color >= 256 ? DEF_IFACE_COLORS_256 : DEF_IFACE_COLORS, term_caps.color >= 256 ? DEF_EXT_COLORS_256 : DEF_EXT_COLORS, term_caps.color >= 256 ? DEF_DATE_SHADES_256 : DEF_DATE_SHADES_8, term_caps.color >= 256 ? DEF_SIZE_SHADES_256 : DEF_SIZE_SHADES_8, DEF_DIV_LINE, DEF_PROMPT_NOTIF == 1 ? "true" : "false", DEFAULT_PROMPT, DEF_WARNING_PROMPT == 1 ? "true" : "false", DEF_WPROMPT_STR, DEF_FZFTAB_OPTIONS); fclose(fp); } static int create_remotes_file(void) { if (!remotes_file || !*remotes_file) return FUNC_FAILURE; struct stat attr; /* If the file already exists, do nothing */ if (stat(remotes_file, &attr) == FUNC_SUCCESS) return FUNC_SUCCESS; /* Let's try to copy the file from DATADIR */ if (import_from_data_dir("nets.clifm", remotes_file, 0) == FUNC_SUCCESS) return FUNC_SUCCESS; /* If not in DATADIR, let's create a minimal file here */ int fd = 0; FILE *fp = open_fwrite(remotes_file, &fd); if (!fp) { err('e', PRINT_PROMPT, "%s: Cannot create remotes file " "'%s': %s\n", PROGRAM_NAME, remotes_file, strerror(errno)); return FUNC_FAILURE; } fprintf(fp, "#####################################\n" "# Remotes management file for %s #\n" "#####################################\n\n" "# Blank and commented lines are omitted\n\n" "# Example:\n" "# A name for this remote. It will be used by the 'net' command\n" "# and will be available for tab completion\n" "# [work_smb]\n\n" "# Comment=My work samba server\n" "# Mountpoint=/home/user/.config/clifm/mounts/work_smb\n\n" "# Use %%m as a placeholder for Mountpoint\n" "# MountCmd=mount.cifs //WORK_IP/shared %%m -o OPTIONS\n" "# UnmountCmd=umount %%m\n\n" "# Automatically mount this remote at startup\n" "# AutoMount=true\n\n" "# Automatically unmount this remote at exit\n" "# AutoUnmount=true\n\n", PROGRAM_NAME); fclose(fp); return FUNC_SUCCESS; } static int create_main_config_dir(void) { /* Use mkdir(1) to let it handle parent directories. */ char *tmp_cmd[] = {"mkdir", "-p", "--", config_dir, NULL}; if (launch_execv(tmp_cmd, FOREGROUND, E_NOSTDERR) != FUNC_SUCCESS) { config_ok = 0; err('e', PRINT_PROMPT, _("%s: Cannot create configuration " "directory '%s': Bookmarks, commands logs, and " "command history are disabled. Program messages will not be " "persistent. Falling back to default settings.\n"), PROGRAM_NAME, config_dir); return FUNC_FAILURE; } return FUNC_SUCCESS; } static void create_profile_file(void) { int fd = 0; FILE *profile_fp = open_fwrite(profile_file, &fd); if (!profile_fp) { err('e', PRINT_PROMPT, "%s: Cannot create profile file " "'%s': %s\n", PROGRAM_NAME, profile_file, strerror(errno)); } else { fprintf(profile_fp, "# This is %s's profile file\n#\n" "# Write here the commands you want to be executed at startup.\n" "# E.g.:\n#echo \"%s, the command line file manager\"; read -r\n#\n" "# Uncommented, non-empty lines are executed line by line. If you\n" "# want a multi-line command, just write a script for it:\n" "#sh /path/to/my/script.sh\n", PROGRAM_NAME_UPPERCASE, PROGRAM_NAME_UPPERCASE); fclose(profile_fp); } } static void create_config_files(const int just_listing) { struct stat attr; if (stat(config_dir, &attr) == -1 && create_main_config_dir() == FUNC_FAILURE) { config_ok = 0; return; } if (access(config_dir, W_OK) == -1) { config_ok = 0; err('e', PRINT_PROMPT, _("%s: '%s': Directory not writable. Bookmarks, " "commands logs, and commands history are disabled. Program messages " "will not be persistent. Falling back to default settings.\n"), PROGRAM_NAME, config_dir); return; } if (stat(config_file, &attr) == -1) config_ok = create_main_config_file(config_file) == FUNC_SUCCESS ? 1 : 0; if (config_ok == 0) return; if (stat(profile_file, &attr) == -1) create_profile_file(); if (stat(colors_dir, &attr) == -1 && xmkdir(colors_dir, S_IRWXU) == FUNC_FAILURE) err('w', PRINT_PROMPT, _("%s: Cannot create colors " "directory '%s': Falling back to the default color scheme\n"), PROGRAM_NAME, colors_dir); create_def_color_scheme(); if (just_listing == 1) return; if (stat(tags_dir, &attr) == -1 && xmkdir(tags_dir, S_IRWXU) == FUNC_FAILURE) err('w', PRINT_PROMPT, _("%s: %s: Cannot create tags directory. " "Tag function disabled\n"), PROGRAM_NAME, tags_dir); if (stat(plugins_dir, &attr) == -1 && xmkdir(plugins_dir, S_IRWXU) == FUNC_FAILURE) err('e', PRINT_PROMPT, _("%s: Cannot create plugins " "directory '%s': The actions function is disabled\n"), PROGRAM_NAME, plugins_dir); import_data_file("readline.clifm", "readline.clifm", 0); import_data_file("plugins/clifmimg", "clifmimg", 1); import_data_file("plugins/clifmrun", "clifmrun", 1); create_actions_file(actions_file); create_mime_file(mime_file, 0); create_preview_file(); create_remotes_file(); } /* Create a completely new mimelist file and store it in FILE. */ static int create_mime_file_anew(const char *file) { int fd; FILE *fp = open_fwrite(file, &fd); if (!fp) { err('e', PRINT_PROMPT, "%s: Cannot create mimelist file " "'%s': %s\n", PROGRAM_NAME, file, strerror(errno)); return FUNC_FAILURE; } fprintf(fp, " ###################################\n\ # Configuration File for Lira #\n\ # Clifm's File Opener #\n\ ###################################\n\ \n\ # Commented and blank lines are ignored.\n\ \n\ # The below settings cover the most common filetypes.\n\ # It is recommended to edit this file placing your prefered applications\n\ # at the beginning of the apps list to speed up the opening process.\n\ \n\ # The file is read top to bottom and left to right; the first existent\n\ # application found will be used.\n\ \n\ # Applications defined here are NOT desktop files, but commands (arguments\n\ # can be used as well). Bear in mind that these commands will be executed\n\ # directly without shell intervention, so that no shell goodies (like pipes,\n\ # conditions, loops, etc) are available. In case you need something more\n\ # complex than a single command (including shell capabilities) write your\n\ # own script and place the path to the script in place of the command.\n\ # For example: X:^text/.*:~/scripts/my_cool_script.sh\n\ \n\ # Use 'X' to specify a GUI environment and '!X' for non-GUI environments,\n\ # like the kernel builtin console or a remote SSH session.\n\ \n\ # Use 'N' to match filenames instead of MIME types.\n\ \n\ # Regular expressions are allowed for both file types and filenames.\n\ \n\ # Use the %%f placeholder to specify the position of the filename to be\n\ # opened in the command. Example:\n\ # 'mpv %%f --terminal=no' -> 'mpv FILE --terminal=no'\n\ #\n\ # The %%u placeholder is expanded to the file URI for the original file.\n\ #\n\ # If neither %%f nor %%u are specified, the filename will be appended to the\n\ # end of the command. E.g.: 'mpv --terminal=no' -> 'mpv --terminal=no FILE'\n\ #\n\ # The %%m placeholder is expanded to the file's MIME type.\n\ \n\ # To silence STDERR and/or STDOUT use !E and !O respectively (they can\n\ # be used together). Examples:\n\ # Silence STDERR only and run in the foreground:\n\ # mpv %%f !E\n\ # Silence both (STDERR and STDOUT) and run in the background:\n\ # mpv %%f !EO &\n\ # or\n\ # mpv %%f !E !O &\n\ # For Ranger users, \"!EO\" is equivalent to \"flag f\" in rifle.conf\n\ \n\ # The '%%x' flag can be used as a shorthand for \"%%f !EO &\". Example:\n\ # mpv %%x\n\ \n\ # Running the opening application in the background:\n\ # For GUI applications:\n\ # APP %%x\n\ # For terminal applications:\n\ # TERM -e APP %%x\n\ # Replace 'TERM' and 'APP' by the corresponding values. The -e option\n\ # might vary depending on the terminal emulator used (TERM).\n\ \n\ # Note on graphical applications: If the opening application is already running\n\ # the file might be opened in a tab, and Clifm will not wait for the file to be\n\ # closed (because the process already returned). To avoid this, instruct the\n\ # application to run a new instance: e.g.: geany -i, gedit -s, kate -n,\n\ # pluma --new-window, and so on.\n\ \n\ # Environment variables can be used as well. Example:\n\ # X:text/plain=$EDITOR %%f &;$VISUAL;nano;vi\n\ \n\ # Use Ranger's rifle (or whatever opener you prefer) to open all files\n\ #.*=rifle\n\ \n\ ###########################\n\ # File names/extensions #\n\ ###########################\n\ \n\ # Match a full filename\n\ #X:N:some_filename=cmd\n\ \n\ # Match all filenames starting with 'str'\n\ #X:N:^str.*=cmd\n\ \n\ # Match files with extension 'ext'\n\ #X:N:.*\\.ext$=cmd\n\ \n\ X:N:.*\\.djvu$=djview %%x;zathura %%x;xreader %%x;evince %%x;atril %%x\n\ X:N:.*\\.(fb2|epub)$=mupdf %%x;zathura %%x;xreader %%x;ebook-viewer %%x;FBReader %%x;foliate %%x\n\ X:N:.*\\.mobi$=mupdf %%x;ebook-viewer %%x;FBReader %%x;foliate %%x\n\ X:N:.*\\.(cbr|cbz|cb7|cbt|cba)$=mcomix %%x;xreader %%x;YACReader %%x;qcomicbook %%x;zathura %%x;foliate %%x\n\ X:N:.*\\.chm$=xchm %%x\n\ X:N:.*\\.abw$=abiword %%x;libreoffice %%x;soffice %%x;ooffice %%x\n\ X:N:.*\\.kra$=krita %%x\n\ X:N:.*\\.sla$=scribus %%x\n\ X:N:.*\\.ora$=mypaint %%x;krita %%x;gimp %%x;pinta %%x;scribus %%x;display %%x\n\ X:N:(.*\\.clifm$|clifmrc)=$EDITOR;$VISUAL;kak;micro;nvim;vim;vi;mg;emacs;nano;mili;leafpad;mousepad;featherpad;gedit;kate;pluma\n\ !X:N:(.*\\.clifm$|clifmrc)=$EDITOR;$VISUAL;kak;micro;nvim;vim;vi;mg;emacs;nano\n\ \n\n"); fprintf(fp, "##################\n\ # MIME types #\n\ ##################\n\ \n\ # Directories - only for the open-with (ow) command and the --open command\n\ # line switch\n\ # In graphical environments directories will be opened in a new window\n\ X:inode/directory=xterm -e clifm %%x;xterm -e vifm %%x;pcmanfm %%x;thunar %%x;xterm -e ncdu %%x\n\ !X:inode/directory=vifm;ranger;nnn;ncdu\n\ \n\ # Web content\n\ X:^text/html$=$BROWSER;surf %%x;vimprobable %%x;vimprobable2 %%x;qutebrowser %%x;dwb %%x;jumanji %%x;luakit %%x;uzbl %%x;uzbl-tabbed %%x;uzbl-browser %%x;uzbl-core %%x;iceweasel %%x;midori %%x;opera %%x;firefox %%x;seamonkey %%x;brave %%x;chromium-browser %%x;chromium %%x;google-chrome %%x;epiphany %%x;konqueror %%x;elinks;links2;links;lynx;w3m\n\ !X:^text/html$=$BROWSER;elinks;links2;links;lynx;w3m\n\ \n\ # Text\n\ X:^text/rtf$=libreoffice %%x;soffice %%x;ooffice %%x\n\ X:(^text/.*|application/(json|javascript)|inode/x-empty)=$EDITOR;$VISUAL;kak;micro;dte;nvim;vim;vi;mg;emacs;nano;mili;leafpad %%x;mousepad %%x;featherpad %%x;nedit %%x;kate %%x;gedit %%x;pluma %%x;io.elementary.code %%x;liri-text %%x;xed %%x;atom %%x;nota %%x;gobby %%x;kwrite %%x;xedit %%x\n\ !X:(^text/.*|application/(json|javascript)|inode/x-empty)=$EDITOR;$VISUAL;kak;micro;dte;nvim;vim;vi;mg;emacs;nano\n\ \n\ # Office documents\n\ ^application/.*(open|office)document\\.spreadsheet.*=sc-im\n\ X:^application/(msword|vnd.ms-excel|vnd.ms-powerpoint|.*(open|office)document.*)=libreoffice %%x;soffice %%x;ooffice %%x\n\ \n\ # Archives\n\ # Note: 'ad' is Clifm's builtin archives utility (based on atool). Remove it if you\n\ # prefer another application.\n\ X:^application/(gzip|java-archive|vnd.(debian.binary-package|ms-cab-compressed|rar)|x-(7z-compressed|arj|bzip*|compress|iso9660-image|lzip|lzma|lzop|rpm|tar|xz)|zip|zstd)=ad;xarchiver %%x;lxqt-archiver %%x;ark %%x\n\ !X:^application/(gzip|java-archive|vnd.(debian.binary-package|ms-cab-compressed|rar)|x-(7z-compressed|arj|bzip*|compress|iso9660-image|lzip|lzma|lzop|rpm|tar|xz)|zip|zstd)=ad\n\ \n\ # PDF\n\ X:.*/pdf$=mupdf %%x;sioyek %%x;llpp %%x;lpdf %%x;zathura %%x;mupdf-x11 %%x;apvlv %%x;xpdf %%x;xreader %%x;evince %%x;atril %%x;okular %%x;epdfview %%x;qpdfview %%x\n\ \n\ # Images\n\ X:^image/gif$=animate %%x;pqiv %%x;sxiv -a %%x;nsxiv -a %%x;feh %%x\n\ X:^image/svg$=display;inkscape %%x\n\ X:^image/x-xcf$=gimp %%x\n\ X:^image/.*=imv %%x;nsxiv %%x;sxiv %%x;pqiv %%x;qview %%x;qimgv %%x;viewnior %%x;oculante %%x;mirage %%x;ristretto %%x;xviewer %%x;nomacs %%x;geeqie %%x;gpicview %%x;gthumb %%x;gwenview %%x;shotwell %%x;loupe %%x;eog %%x;eom %%x;mcomix %%x;feh %%x;display %%x;gimp %%x;krita %%x\n\ !X:^image/.*=fim;img2txt;cacaview;fbi;fbv\n\ \n\ # Video and audio\n\ X:^video/.*=ffplay %%x;mplayer %%x;mplayer2 %%x;mpv %%x;vlc %%x;gmplayer %%x;smplayer %%x;celluloid %%x;qmplayer2 %%x;haruna %%x;totem %%x\n\ X:^audio/.*=mpv %%x;gmplayer %%x;smplayer %%x;vlc %%x;totem %%x;ffplay %%x;mplayer;mplayer2\n\ !X:^audio/.*=ffplay -nodisp -autoexit %%f !EO;mplayer %%f !EO;mpv --no-terminal\n\ \n\ # Fonts\n\ X:^font/.*|^application/(font.*|.*opentype)=fontforge;fontpreview\n\ \n\ # Torrent:\n\ X:application/x-bittorrent=rtorrent;transimission-gtk %%x;transmission-qt %%x;deluge-gtk %%x;ktorrent %%x\n\ \n\ # Fallback to an external opener as last resource\n\ .*=handlr open;mimeopen -n;rifle;mimeo;xdg-open;open;\n"); fclose(fp); return FUNC_SUCCESS; } int create_mime_file(char *file, const int new_prof) { /* This variable was used to print a notice message when running for the * first time. Too much information: removed. */ UNUSED(new_prof); if (!file || !*file) return FUNC_FAILURE; struct stat attr; if (stat(file, &attr) == FUNC_SUCCESS) return FUNC_SUCCESS; int ret = import_from_data_dir("mimelist.clifm", file, 0); if (ret != FUNC_SUCCESS) ret = create_mime_file_anew(file); return ret; } int create_bm_file(void) { if (!bm_file) return FUNC_FAILURE; struct stat attr; if (stat(bm_file, &attr) != -1) return FUNC_SUCCESS; int fd = 0; FILE *fp = open_fwrite(bm_file, &fd); if (!fp) { err('e', PRINT_PROMPT, "%s: Cannot create bookmarks file " "'%s': %s\n", PROGRAM_NAME, bm_file, strerror(errno)); return FUNC_FAILURE; } fprintf(fp, "### This is the bookmarks file for %s ###\n\n" "# Empty and commented lines are ignored.\n" "# Make your changes, save, and exit.\n" "# To remove a bookmark, delete the corresponding line, save, and exit\n" "# Changes are applied automatically at exit (to cancel just quit the editor).\n\n" "# The bookmarks syntax is: name:path\n" "# Example:\n" "clifm:%s\n", PROGRAM_NAME, config_dir ? config_dir : "/path/to/file"); fclose(fp); return FUNC_SUCCESS; } static char * get_line_value(char *line) { if (!line || *line < ' ') /* Skip non-printable chars */ return (char *)NULL; return remove_quotes(line); } /* Read time format from LINE and store the appropriate value in STR. * PTIME specifies whether we're dealing with PTimeStyle or just TimeStyle * options (the former does not support relative times). */ void set_time_style(char *line, char **str, const int ptime) { if (!line || !*line) return; char *tmp = get_line_value(line); if (!tmp) return; free(*str); *str = (char *)NULL; if (*tmp == 'r' && strcmp(tmp + 1, "elative") == 0) { if (ptime == 0) conf.relative_time = 1; } else if (*tmp == 'd' && strcmp(tmp + 1, "efault") == 0) { return; } else if (*tmp == 'i' && strcmp(tmp + 1, "so") == 0) { *str = savestring(ISO_TIME, sizeof(ISO_TIME) - 1); } else if (*tmp == 'f' && strcmp(tmp + 1, "ull-iso") == 0) { *str = savestring(FULL_ISO_TIME, sizeof(FULL_ISO_TIME) - 1); } else if (ptime == 1 && *tmp == 'f' && strcmp(tmp + 1, "ull-iso-nano") == 0) { *str = savestring(FULL_ISO_NANO_TIME, sizeof(FULL_ISO_NANO_TIME) - 1); } else if (*tmp == 'l' && strcmp(tmp + 1, "ong-iso") == 0) { *str = savestring(LONG_ISO_TIME, sizeof(LONG_ISO_TIME) - 1); } else if (*tmp == '+') { if (*(++tmp)) { /* We don't support FORMAT1FORMAT2, like ls(1) does. */ char *n = strchr(tmp, '\n'); if (n) *n = '\0'; *str = savestring(tmp, strlen(tmp)); } } else { char *n = strchr(tmp, '\n'); if (n) *n = '\0'; *str = savestring(tmp, strlen(tmp)); } } static void set_time_style_env(void) { if (xargs.secure_env == 1 || xargs.secure_env_full == 1) return; char *p = getenv("CLIFM_TIME_STYLE"); if (!p || !*p) p = getenv("TIME_STYLE"); if (!p || !*p) return; set_time_style(p, &conf.time_str, 0); } static void set_ptime_style_env(void) { if (xargs.secure_env == 1 || xargs.secure_env_full == 1) return; char *p = getenv("PTIME_STYLE"); if (!p || !*p) return; set_time_style(p, &conf.ptime_str, 1); } #ifndef CLIFM_SUCKLESS static int set_fzf_preview_value(const char *line, int *var) { #ifdef _NO_LIRA UNUSED(line); *var = 0; #endif /* _NO_LIRA */ if (!line || !*line) return (-1); if (*line == 't' && strncmp(line, "true\n", 5) == 0) { *var = 1; } else if (*line == 'h' && strncmp(line, "hidden\n", 7) == 0) { *var = 2; } else { if (*line == 'f' && strncmp(line, "false\n", 6) == 0) *var = 0; } return FUNC_SUCCESS; } static void set_pager_value(char *line, int *var, const size_t buflen) { char *p = line; if (!p || *p < '0') return; if (*p >= '0' && *p <= '9') { const size_t l = strnlen(p, buflen); if (l > 0 && p[l - 1] == '\n') p[l - 1] = '\0'; int n = atoi(p); if (n == INT_MIN) return; *var = n; return; } if (*p == 't' && strncmp(p, "true\n", 5) == 0) { *var = 1; } else { if (*p == 'f' && strncmp(p, "false\n", 6) == 0) *var = 0; } } static void set_pager_view_value(char *line) { if (!line || !*line) return; char *p = remove_quotes(line); if (!p) return; if (*p == 'a' && strcmp(p, "auto") == 0) conf.pager_view = PAGER_AUTO; else if (*p == 'l' && strcmp(p, "long") == 0) conf.pager_view = PAGER_LONG; else if (*p == 's' && strcmp(p, "short") == 0) conf.pager_view = PAGER_SHORT; } /* Get boolean value from LINE and set VAR accordingly. */ static void set_config_bool_value(char *line, int *var) { char *p = line; if (!p || !*p || *p < 'f') return; if (*p == 't' && strncmp(p, "true\n", 5) == 0) { *var = 1; } else { if (*p == 'f' && strncmp(p, "false\n", 6) == 0) *var = 0; } } /* Get an integer (between MIN and MAX inclusively) from LINE and store * it in VAR. In case of error or out of range integer, VAR is left * unchanged. */ static void set_config_int_value(char *line, int *var, const int min, const int max) { if (!line || !*line) return; int num = 0; const int ret = sscanf(line, "%d\n", &num); if (ret > 0 && num >= min && num <= max) *var = num; } static void set_colorscheme(char *line) { if (!line || *line < ' ') return; char *p = remove_quotes(line); if (!p) return; free(conf.usr_cscheme); conf.usr_cscheme = savestring(p, strlen(p)); } void set_div_line(char *line) { if (!line || *line < ' ') { *div_line = *DEF_DIV_LINE; return; } char *tmp = remove_quotes(line); if (!tmp) { *div_line = '\0'; return; } xstrsncpy(div_line, tmp, sizeof(div_line)); } static int set_files_filter(const char *line) { char *p = strchr(line, '='); if (!p || !*(++p)) return (-1); char *q = remove_quotes(p); if (!q) return (-1); size_t l = strlen(q); if (l > 0 && q[l - 1] == '\n') { q[l - 1] = '\0'; l--; } if (*q == '!') { filter.rev = 1; q++; l--; } else { filter.rev = 0; } set_filter_type(*q); free(filter.str); filter.str = savestring(q, l); return FUNC_SUCCESS; } static void set_listing_mode(char *line) { if (!line || !*line) return; line[1] = '\0'; const int n = atoi(line); if (n == INT_MIN) goto END; switch (n) { case VERTLIST: conf.listing_mode = VERTLIST; return; case HORLIST: conf.listing_mode = HORLIST; return; default: break; } END: conf.listing_mode = DEF_LISTING_MODE; } static void set_search_strategy(const char *line) { if (!line || *line < '0' || *line > '2') return; switch (*line) { case '0': conf.search_strategy = GLOB_ONLY; break; case '1': conf.search_strategy = REGEX_ONLY; break; case '2': conf.search_strategy = GLOB_REGEX; break; default: break; } } static void free_workspaces_names(void) { if (workspaces) { int i = MAX_WS; while (--i >= 0) { free(workspaces[i].name); workspaces[i].name = (char *)NULL; } } } /* Get workspaces names from the WorkspacesNames line in the configuration * file and store them in the workspaces array. */ void set_workspace_names(char *line) { char *e = (char *)NULL; char *t = remove_quotes(line); if (!t || !*t) return; char *p = (char *)NULL; while (*t) { p = strchr(t, ','); if (p) *p = '\0'; else p = t; e = strchr(t, '='); if (!e || !*(e + 1)) goto CONT; *e = '\0'; if (!is_number(t)) goto CONT; const int a = atoi(t); if (a <= 0 || a > MAX_WS) goto CONT; free(workspaces[a - 1].name); workspaces[a - 1].name = savestring(e + 1, strlen(e + 1)); CONT: t = p + 1; } } #ifndef _NO_SUGGESTIONS static void set_sug_strat(char *line) { char *tmp = remove_quotes(line); if (!tmp) return; const size_t len = strlen(tmp); if (len > SUG_STRATS) tmp[SUG_STRATS] = '\0'; free(conf.suggestion_strategy); conf.suggestion_strategy = savestring(tmp, strlen(tmp)); } #endif /* _NO_SUGGESTIONS */ #ifndef _NO_FZF static void set_tabcomp_mode(char *line) { if (!line || !*line) return; char *tmp = remove_quotes(line); if (!tmp) return; if (strcmp(tmp, "standard") == 0) { fzftab = 0; tabmode = STD_TAB; } else if (strcmp(tmp, "fzf") == 0) { fzftab = 1; tabmode = FZF_TAB; } else if (strcmp(tmp, "fnf") == 0) { fzftab = 1; tabmode = FNF_TAB; } else if (strcmp(tmp, "smenu") == 0) { fzftab = 1; tabmode = SMENU_TAB; } } #endif /* !_NO_FZF */ static void set_starting_path(char *line) { char *tmp = get_line_value(line); if (!tmp) return; /* If starting path is not NULL, and exists, and is a directory, and the * user has appropriate permissions, set path to starting path. If any of * these conditions is false, path will be set to default, that is, CWD */ if (xchdir(tmp, SET_TITLE) == 0) { if (cur_ws < 0) cur_ws = 0; free(workspaces[cur_ws].path); workspaces[cur_ws].path = savestring(tmp, strlen(tmp)); return; } err('w', PRINT_PROMPT, _("%s: chdir: '%s': %s. Using the " "current working directory as starting path\n"), PROGRAM_NAME, tmp, strerror(errno)); } static void set_quoting_style(char *str) { conf.quoting_style = DEF_QUOTING_STYLE; if (!str || !*str) return; char *val = get_line_value(str); if (!val) return; if (*val == 'b' && strcmp(val + 1, "ackslash") == 0) conf.quoting_style = QUOTING_STYLE_BACKSLASH; else if (*val == 's' && strcmp(val + 1, "ingle") == 0) conf.quoting_style = QUOTING_STYLE_SINGLE_QUOTES; else if(*val == 'd' && strcmp(val + 1, "ouble") == 0) conf.quoting_style = QUOTING_STYLE_DOUBLE_QUOTES; else return; } static void set_histignore_pattern(char *str) { if (!str || !*str) return; char *pattern = get_line_value(str); if (!pattern) { conf.histignore_regex = savestring("", 0); return; } if (conf.histignore_regex) { regfree(®ex_hist); free(conf.histignore_regex); conf.histignore_regex = (char *)NULL; } int ret = regcomp(®ex_hist, pattern, REG_NOSUB | REG_EXTENDED); if (ret != FUNC_SUCCESS) { xregerror("histignore", pattern, ret, regex_hist, 1); regfree(®ex_hist); return; } conf.histignore_regex = savestring(pattern, strlen(pattern)); } static void set_dirhistignore_pattern(char *str) { if (!str || !*str) return; char *pattern = get_line_value(str); if (!pattern) { conf.dirhistignore_regex = savestring("", 0); return; } if (conf.dirhistignore_regex) { regfree(®ex_dirhist); free(conf.dirhistignore_regex); conf.dirhistignore_regex = (char *)NULL; } int ret = regcomp(®ex_dirhist, pattern, REG_NOSUB | REG_EXTENDED); if (ret != FUNC_SUCCESS) { xregerror("dirhistignore", pattern, ret, regex_dirhist, 1); regfree(®ex_dirhist); return; } conf.dirhistignore_regex = savestring(pattern, strlen(pattern)); } static void set_sort_name(char *line) { const char *name = get_line_value(line); if (!name || !*name) return; size_t i; for (i = 0; i <= SORT_TYPES; i++) { if (*name == *sort_methods[i].name && strcmp(name, sort_methods[i].name) == 0) { conf.sort = sort_methods[i].num; return; } } } static void set_clear_screen(char *line) { if (*line == 'i' && strncmp(line, "internal\n", 9) == 0) conf.clear_screen = CLEAR_INTERNAL_CMD_ONLY; else set_config_bool_value(line, &conf.clear_screen); } static void set_link_creation_mode(const char *val) { if (!val || !*val) { conf.link_creat_mode = DEF_LINK_CREATION_MODE; return; } if (*val == 'a' && strncmp(val, "absolute\n", 9) == 0) conf.link_creat_mode = LNK_CREAT_ABS; else if (*val == 'r' && strncmp(val, "relative\n", 9) == 0) conf.link_creat_mode = LNK_CREAT_REL; else conf.link_creat_mode = DEF_LINK_CREATION_MODE; } static void set_autocmd_msg_value(const char *val) { if (!val || !*val) return; if (*val == 'n' && strncmp(val, "none\n", 5) == 0) conf.autocmd_msg = AUTOCMD_MSG_NONE; else if (*val == 'm' && strncmp(val, "mini\n", 5) == 0) conf.autocmd_msg = AUTOCMD_MSG_MINI; else if (*val == 's' && strncmp(val, "short\n", 6) == 0) conf.autocmd_msg = AUTOCMD_MSG_SHORT; else if (*val == 'l' && strncmp(val, "long\n", 5) == 0) conf.autocmd_msg = AUTOCMD_MSG_LONG; else if (*val == 'f' && strncmp(val, "full\n", 5) == 0) conf.autocmd_msg = AUTOCMD_MSG_FULL; else if (*val == 'p' && strncmp(val, "prompt\n", 7) == 0) conf.autocmd_msg = AUTOCMD_MSG_PROMPT; else conf.autocmd_msg = DEF_AUTOCMD_MSG; } static char * get_term_env(const char *cmd) { if (!cmd || !*cmd) return (char *)NULL; char *s = strchr(cmd, ' '); if (s) *s = '\0'; char *env = getenv(cmd); if (s) *s = ' '; char *buf = (char *)NULL; if (env && *env) { const size_t len = strlen(env) + (s ? strlen(s) : 0) + 1; buf = xnmalloc(len, sizeof(char)); snprintf(buf, len, "%s%s", env, s ? s : ""); } return buf; } static void set_term_cmd(char *cmd) { if (!cmd || !*cmd) return; char *tmp = remove_quotes(cmd); if (!tmp) return; char *val = tmp; char *buf = (char *)NULL; if (*tmp == '$' && tmp[1] && xargs.secure_env != 1 && xargs.secure_env_full != 1) { buf = get_term_env(tmp + 1); if (buf) val = buf; } free(conf.term); conf.term = savestring(val, strlen(val)); free(buf); } static void set_default_answers_to_default(void) { conf.default_answer.remove = DEF_ANSWER_REMOVE; conf.default_answer.trash = DEF_ANSWER_TRASH; conf.default_answer.bulk_rename = DEF_ANSWER_BULK_RENAME; conf.default_answer.overwrite = DEF_ANSWER_OVERWRITE; conf.default_answer.default_ = DEF_ANSWER_DEFAULT; conf.default_answer.default_all = DEF_ANSWER_DEFAULT_ALL; } static void set_default_answer(const char *str) { if (!str || !*str || str[1] != ':' || (str[2] != 'y' && str[2] != 'n' && str[2] != 'u')) return; switch (*str) { case 'd': conf.default_answer.default_ = str[2]; break; case 'D': conf.default_answer.default_all = str[2]; break; case 'o': conf.default_answer.overwrite = str[2]; break; case 'r': conf.default_answer.remove = str[2]; break; case 'R': conf.default_answer.bulk_rename = str[2]; break; case 't': conf.default_answer.trash = str[2]; break; default: break; } } static void set_default_answers(char *val) { if (!val || !*val) return; char *v = remove_quotes(val); if (!v || !*v) return; char *str = strtok(v, ","); if (!str || !*str) return; set_default_answer(str); while ((str = strtok(NULL, ",")) != NULL) set_default_answer(str); } static void set_rl_edit_mode(const char *val) { if (val && ((*val == '0' && val[1] == '\n') || (*val == 'v' && val[1] == 'i' && val[2] == '\n')) ) rl_vi_editing_mode(1, 0); else rl_emacs_editing_mode(1, 0); } static void set_preview_max_size(char *val) { char *tmp; if (!val || !*val || !(tmp = remove_quotes(val))) return; const size_t l = strlen(tmp); if (l > 1 && tmp[l - 1] == '\n') tmp[l - 1] = '\0'; char *u = tmp; while (*u && IS_DIGIT(*u)) u++; char unit = 'B'; /* If no unit is specified, we fallback to bytes. */ if (*u && u != tmp) { unit = (char)TOUPPER(*u); *u = '\0'; } const long n = strtol(tmp, NULL, 10); if (n < 0 || n > INT_MAX) return; /* Transform the given value to KiB. */ switch (unit) { case 'B': conf.preview_max_size = n <= 1024 ? 1 : (int)n / 1024; break; case 'K': conf.preview_max_size = (int)n; break; case 'M': conf.preview_max_size = (int)n * 1024; break; case 'G': conf.preview_max_size = (int)n * 1048576; break; case 'T': conf.preview_max_size = (int)n * 1073741824; break; default: err('w', PRINT_PROMPT, _("PreviewMaxSize: '%c': Invalid unit.\n"), unit); return; } if (conf.preview_max_size < 0) { err('w', PRINT_PROMPT, _("PreviewMaxSize: Value too large " "(max %dGiB).\n"), INT_MAX / 1048576); conf.preview_max_size = INT_MAX; /* Max supported size (in KiB). */ } } static void set_show_hidden_files(const char *val) { if (!val || !*val) return; if (*val == 't' && strncmp(val, "true\n", 5) == 0) { conf.show_hidden = HIDDEN_TRUE; } else if (*val == 'f') { if (strncmp(val, "false\n", 6) == 0) { conf.show_hidden = HIDDEN_FALSE; } else { if (strncmp(val, "first\n", 6) == 0) conf.show_hidden = HIDDEN_FIRST; } } else { if (*val == 'l' && strncmp(val, "last\n", 5) == 0) conf.show_hidden = HIDDEN_LAST; } } static void set_priority_sort_char(char *val) { char *v; if (!val || !*val || !(v = remove_quotes(val))) return; const size_t l = strlen(v); if (l > 1 && v[l - 1] == '\n') v[l - 1] = '\0'; char *buf = xnmalloc(l + 1, sizeof(char)); char *ptr = buf; while (*v) { if (*v >= ' ' && *v <= '~') { /* Same as isprint(c) */ *ptr = *v; ptr++; } v++; } *ptr = '\0'; if (buf && *buf) conf.priority_sort_char = buf; else free(buf); } static void set_desktop_notis(char *val) { char *v; if (!val || !*val || !(v = remove_quotes(val))) return; const size_t l = strlen(v); if (l > 1 && v[l - 1] == '\n') v[l - 1] = '\0'; if (*v == 'k' && strcmp(v, "kitty") == 0) { conf.desktop_notifications = DESKTOP_NOTIF_KITTY; } else if ((*v == 's' && strcmp(v, "system") == 0) || (*v == 't' && strcmp(v, "true") == 0)) { conf.desktop_notifications = DESKTOP_NOTIF_SYSTEM; } else { if (*v == 'f' && strcmp(v, "false") == 0) conf.desktop_notifications = DESKTOP_NOTIF_NONE; } } /* Read the main configuration file and set options accordingly */ static void read_config(void) { int fd; FILE *config_fp = open_fread(config_file, &fd); if (!config_fp) { err('e', PRINT_PROMPT, _("%s: '%s': %s. Using default " "values.\n"), PROGRAM_NAME, config_file, strerror(errno)); return; } free_workspaces_names(); if (xargs.rl_vi_mode == 1) rl_vi_editing_mode(1, 0); int default_answers_set = 0; int ret = -1; conf.max_name_len = DEF_MAX_NAME_LEN; *div_line = *DEF_DIV_LINE; /* The longest possible line in the config file is StartingPath="PATH" */ char line[PATH_MAX + 16]; *line = '\0'; if (xargs.prop_fields_str != 1) *prop_fields_str = '\0'; while (fgets(line, (int)sizeof(line), config_fp)) { if (*line < 'A' || *line > 'z') continue; if (xargs.apparent_size == UNSET && *line == 'A' && strncmp(line, "ApparentSize=", 13) == 0) { set_config_bool_value(line + 13, &conf.apparent_size); } else if (*line == 'a' && strncmp(line, "autocmd ", 8) == 0) { parse_autocmd_line(line + 8, sizeof(line) - 8); } else if (xargs.autocd == UNSET && *line == 'A' && strncmp(line, "Autocd=", 7) == 0) { set_config_bool_value(line + 7, &conf.autocd); } else if (xargs.autols == UNSET && *line == 'A' && strncmp(line, "AutoLs=", 7) == 0) { set_config_bool_value(line + 7, &conf.autols); } else if (xargs.auto_open == UNSET && *line == 'A' && strncmp(line, "AutoOpen=", 9) == 0) { set_config_bool_value(line + 9, &conf.auto_open); } #ifndef _NO_SUGGESTIONS else if (xargs.suggestions == UNSET && *line == 'A' && strncmp(line, "AutoSuggestions=", 16) == 0) { set_config_bool_value(line + 16, &conf.suggestions); } #endif /* !_NO_SUGGESTIONS */ else if (xargs.case_sens_dirjump == UNSET && *line == 'C' && strncmp(line, "CaseSensitiveDirJump=", 21) == 0) { set_config_bool_value(line + 21, &conf.case_sens_dirjump); } else if (*line == 'C' && strncmp(line, "CaseSensitiveSearch=", 20) == 0) { set_config_bool_value(line + 20, &conf.case_sens_search); } else if (xargs.case_sens_list == UNSET && *line == 'C' && strncmp(line, "CaseSensitiveList=", 18) == 0) { set_config_bool_value(line + 18, &conf.case_sens_list); } else if (xargs.case_sens_path_comp == UNSET && *line == 'C' && strncmp(line, "CaseSensitivePathComp=", 22) == 0) { set_config_bool_value(line + 22, &conf.case_sens_path_comp); } else if (xargs.cd_on_quit == UNSET && *line == 'C' && strncmp(line, "CdOnQuit=", 9) == 0) { set_config_bool_value(line + 9, &conf.cd_on_quit); } else if (xargs.classify == UNSET && *line == 'C' && strncmp(line, "Classify=", 9) == 0) { set_config_bool_value(line + 9, &conf.classify); } else if (xargs.clear_screen == UNSET && *line == 'C' && strncmp(line, "ClearScreen=", 12) == 0) { set_clear_screen(line + 12); } else if (xargs.color_lnk_as_target == UNSET && *line == 'C' && strncmp(line, "ColorLinksAsTarget=", 19) == 0) { set_config_bool_value(line + 19, &conf.color_lnk_as_target); } else if (!conf.usr_cscheme && *line == 'C' && strncmp(line, "ColorScheme=", 12) == 0) { set_colorscheme(line + 12); } else if (*line == 'c' && strncmp(line, "cpCmd=", 6) == 0) { set_config_int_value(line + 6, &conf.cp_cmd, 0, CP_CMD_AVAILABLE - 1); } else if (*line == 'D' && strncmp(line, "DefaultAnswer=", 14) == 0) { default_answers_set = 1; set_default_answers(line + 14); } else if (xargs.desktop_notifications == UNSET && *line == 'D' && strncmp(line, "DesktopNotifications=", 21) == 0) { set_desktop_notis(line + 21); } else if (xargs.dirhist_map == UNSET && *line == 'D' && strncmp(line, "DirhistMap=", 11) == 0) { set_config_bool_value(line + 11, &conf.dirhist_map); } else if (*line == 'D' && strncmp(line, "DirhistIgnore=", 14) == 0) { set_dirhistignore_pattern(line + 14); } else if (xargs.disk_usage == UNSET && *line == 'D' && strncmp(line, "DiskUsage=", 10) == 0) { set_config_bool_value(line + 10, &conf.disk_usage); } else if (*line == 'D' && strncmp(line, "DividingLine=", 13) == 0) { set_div_line(line + 13); } else if (xargs.ext_cmd_ok == UNSET && *line == 'E' && strncmp(line, "ExternalCommands=", 17) == 0) { set_config_bool_value(line + 17, &conf.ext_cmd_ok); } else if (xargs.files_counter == UNSET && *line == 'F' && strncmp(line, "FilesCounter=", 13) == 0) { set_config_bool_value(line + 13, &conf.files_counter); } else if (!filter.str && *line == 'F' && strncmp(line, "Filter=", 7) == 0) { if (set_files_filter(line) == -1) continue; } else if (xargs.full_dir_size == UNSET && *line == 'F' && strncmp(line, "FullDirSize=", 12) == 0) { set_config_bool_value(line + 12, &conf.full_dir_size); } else if (xargs.fuzzy_match_algo == UNSET && *line == 'F' && strncmp(line, "FuzzyAlgorithm=", 15) == 0) { set_config_int_value(line + 15, &conf.fuzzy_match_algo, 1, FUZZY_ALGO_MAX); } else if (xargs.fuzzy_match == UNSET && *line == 'F' && strncmp(line, "FuzzyMatching=", 14) == 0) { set_config_bool_value(line + 14, &conf.fuzzy_match); } else if (xargs.fzf_preview == UNSET && *line == 'F' && strncmp(line, "FzfPreview=", 11) == 0) { if (set_fzf_preview_value(line + 11, &conf.fzf_preview) == -1) continue; } else if (*line == 'H' && strncmp(line, "HistIgnore=", 11) == 0) { set_histignore_pattern(line + 11); } #ifndef _NO_ICONS else if (xargs.icons == UNSET && *line == 'I' && strncmp(line, "Icons=", 6) == 0) { set_config_bool_value(line + 6, &conf.icons); } else if (*line == 'I' && strncmp(line, "IconsGap=", 9) == 0) { set_config_int_value(line + 9, &conf.icons_gap, 0, 2); } #endif /* !_NO_ICONS */ else if (*line == 'I' && strncmp(line, "InformAutocmd=", 14) == 0) { set_autocmd_msg_value(line + 14); } else if (xargs.light_mode == UNSET && *line == 'L' && strncmp(line, "LightMode=", 10) == 0) { set_config_bool_value(line + 10, &conf.light_mode); } else if (*line == 'L' && strncmp(line, "LinkCreationMode=", 17) == 0) { set_link_creation_mode(line + 17); } else if (xargs.list_dirs_first == UNSET && *line == 'L' && strncmp(line, "ListDirsFirst=", 14) == 0) { set_config_bool_value(line + 14, &conf.list_dirs_first); } else if (xargs.horizontal_list == UNSET && *line == 'L' && strncmp(line, "ListingMode=", 12) == 0) { set_listing_mode(line + 12); } else if (xargs.long_view == UNSET && *line == 'L' && strncmp(line, "LongViewMode=", 13) == 0) { set_config_bool_value(line + 13, &conf.long_view); } else if (*line == 'L' && strncmp(line, "LogMsgs=", 8) == 0) { set_config_bool_value(line + 8, &conf.log_msgs); } else if (*line == 'L' && strncmp(line, "LogCmds=", 8) == 0) { set_config_bool_value(line + 8, &conf.log_cmds); } else if (xargs.max_dirhist == UNSET && *line == 'M' && strncmp(line, "MaxDirhist=", 11) == 0) { set_config_int_value(line + 11, &conf.max_dirhist, 0, INT_MAX); } else if (*line == 'M' && strncmp(line, "MaxFilenameLen=", 15) == 0) { if (line[15] == '\n' && !line[16]) /* Empty == -1 == UNSET */ conf.max_name_len = UNSET; else set_config_int_value(line + 15, &conf.max_name_len, -1, NAME_BUF_SIZE); } else if (*line == 'M' && strncmp(line, "MaxHistory=", 11) == 0) { set_config_int_value(line + 11, &conf.max_hist, 1, INT_MAX); } else if (*line == 'M' && strncmp(line, "MaxJumpTotalRank=", 17) == 0) { set_config_int_value(line + 17, &conf.max_jump_total_rank, 1, INT_MAX); } else if (*line == 'M' && strncmp(line, "MaxLog=", 7) == 0) { set_config_int_value(line + 7, &conf.max_log, 1, INT_MAX); } else if (xargs.prompt_p_max_path == UNSET && *line == 'M' && strncmp(line, "MaxPath=", 8) == 0) { err('n', PRINT_PROMPT, _("%s: MaxPath: This option is " "deprecated. Use the CLIFM_PROMPT_P_MAX_PATH environment " "variable instead.\n"), PROGRAM_NAME); set_config_int_value(line + 8, &conf.prompt_p_max_path, 1, INT_MAX); } else if (*line == 'M' && strncmp(line, "MaxPrintSelfiles=", 17) == 0) { set_config_int_value(line + 17, &conf.max_printselfiles, -1, INT_MAX); } else if (*line == 'M' && strncmp(line, "MinFilenameTrim=", 16) == 0) { err('n', PRINT_PROMPT, _("%s: MinFilenameTrim: This option is " "deprecated. Use MinNameTruncate instead.\n"), PROGRAM_NAME); set_config_int_value(line + 16, &conf.min_name_trunc, 1, INT_MAX); } else if (*line == 'M' && strncmp(line, "MinNameTruncate=", 16) == 0) { set_config_int_value(line + 16, &conf.min_name_trunc, 1, INT_MAX); } else if (*line == 'M' && strncmp(line, "MinJumpRank=", 12) == 0) { set_config_int_value(line + 12, &conf.min_jump_rank, -1, INT_MAX); } else if (*line == 'm' && strncmp(line, "mvCmd=", 6) == 0) { set_config_int_value(line + 6, &conf.mv_cmd, 0, MV_CMD_AVAILABLE - 1); } else if (!conf.opener && *line == 'O' && strncmp(line, "Opener=", 7) == 0) { char *tmp = get_line_value(line + 7); if (!tmp) continue; free(conf.opener); conf.opener = savestring(tmp, strlen(tmp)); } else if (xargs.pager == UNSET && *line == 'P' && strncmp(line, "Pager=", 6) == 0) { set_pager_value(line + 6, &conf.pager, sizeof(line) - 6); } else if (xargs.pager_view == UNSET && *line == 'P' && strncmp(line, "PagerView=", 10) == 0) { set_pager_view_value(line + 10); } else if (*line == 'P' && strncmp(line, "PreviewMaxSize=", 15) == 0) { set_preview_max_size(line + 15); } else if (*line == 'P' && strncmp(line, "PrintDirCmds=", 13) == 0) { set_config_bool_value(line + 13, &conf.print_dir_cmds); } else if (xargs.print_selfiles == UNSET && *line == 'P' && strncmp(line, "PrintSelfiles=", 14) == 0) { set_config_bool_value(line + 14, &conf.print_selfiles); } else if (*line == 'P' && strncmp(line, "PrioritySortChar=", 17) == 0) { set_priority_sort_char(line + 17); } else if (*line == 'P' && strncmp(line, "PrivateWorkspaceSettings=", 25) == 0) { set_config_bool_value(line + 25, &conf.private_ws_settings); } else if (!*prop_fields_str && *line == 'P' && strncmp(line, "PropFields=", 11) == 0) { char *tmp = get_line_value(line + 11); if (tmp) xstrsncpy(prop_fields_str, tmp, sizeof(prop_fields_str)); } else if (*line == 'P' && strncmp(line, "PropFieldsGap=", 14) == 0) { set_config_int_value(line + 14, &conf.prop_fields_gap, 1, 2); } else if (xargs.ptime_style == UNSET && *line == 'P' && strncmp(line, "PTimeStyle=", 11) == 0) { set_time_style(line + 11, &conf.ptime_str, 1); } else if (*line == 'P' && strncmp(line, "PurgeJumpDB=", 12) == 0) { set_config_bool_value(line + 12, &conf.purge_jumpdb); } else if (*line == 'Q' && strncmp(line, "QuotingStyle=", 13) == 0) { set_quoting_style(line + 13); } else if (*line == 'R' && strncmp(line, "ReadAutocmdFiles=", 17) == 0) { set_config_bool_value(line + 17, &conf.read_autocmd_files); } else if (*line == 'R' && strncmp(line, "ReadDotHidden=", 14) == 0) { set_config_bool_value(line + 14, &conf.read_dothidden); } else if (xargs.readonly == UNSET && *line == 'R' && strncmp(line, "Readonly=", 9) == 0) { set_config_bool_value(line + 9, &conf.readonly); } else if (xargs.restore_last_path == UNSET && *line == 'R' && strncmp(line, "RestoreLastPath=", 16) == 0) { set_config_bool_value(line + 16, &conf.restore_last_path); } else if (xargs.rl_vi_mode == UNSET && *line == 'R' && strncmp(line, "RlEditMode=", 11) == 0) { set_rl_edit_mode(line + 11); } else if (*line == 'r' && strncmp(line, "rmForce=", 8) == 0) { set_config_bool_value(line + 8, &conf.rm_force); } else if (*line == 'S' && strncmp(line, "SearchStrategy=", 15) == 0) { set_search_strategy(line + 15); } else if (xargs.share_selbox == UNSET && *line == 'S' && strncmp(line, "ShareSelbox=", 12) == 0) { set_config_bool_value(line + 12, &conf.share_selbox); } else if (xargs.show_hidden == UNSET && *line == 'S' && strncmp(line, "ShowHiddenFiles=", 16) == 0) { set_show_hidden_files(line + 16); } else if (*line == 'S' && strncmp(line, "SkipNonAlnumPrefix=", 19) == 0) { set_config_bool_value(line + 19, &conf.skip_non_alnum_prefix); } else if (xargs.sort == UNSET && *line == 'S' && strncmp(line, "Sort=", 5) == 0) { if (!IS_DIGIT(line[5])) set_sort_name(line + 5); else set_config_int_value(line + 5, &conf.sort, 0, SORT_TYPES); } else if (xargs.sort_reverse == UNSET && *line == 'S' && strncmp(line, "SortReverse=", 12) == 0) { set_config_bool_value(line + 12, &conf.sort_reverse); } else if (xargs.splash_screen == UNSET && *line == 'S' && strncmp(line, "SplashScreen=", 13) == 0) { set_config_bool_value(line + 13, &conf.splash_screen); } else if (xargs.path == UNSET && cur_ws == UNSET && *line == 'S' && strncmp(line, "StartingPath=", 13) == 0) { set_starting_path(line + 13); } #ifndef _NO_SUGGESTIONS else if (*line == 'S' && strncmp(line, "SuggestCmdDesc=", 15) == 0) { set_config_bool_value(line + 15, &conf.cmd_desc_sug); } else if (*line == 'S' && strncmp(line, "SuggestFiletypeColor=", 21) == 0) { set_config_bool_value(line + 21, &conf.suggest_filetype_color); } else if (*line == 'S' && strncmp(line, "SuggestionStrategy=", 19) == 0) { set_sug_strat(line + 19); } #endif /* !_NO_SUGGESTIONS */ #ifndef _NO_HIGHLIGHT else if (xargs.highlight == UNSET && *line == 'S' && strncmp(line, "SyntaxHighlighting=", 19) == 0) { set_config_bool_value(line + 19, &conf.highlight); } #endif /* !_NO_HIGHLIGHT */ #ifndef _NO_FZF else if (xargs.fzftab == UNSET && xargs.fnftab == UNSET && xargs.smenutab == UNSET && *line == 'T' && strncmp(line, "TabCompletionMode=", 18) == 0) { set_tabcomp_mode(line + 18); } #endif /* !_NO_FZF */ else if (*line == 'T' && strncmp(line, "TerminalCmd=", 12) == 0) { set_term_cmd(line + 12); } else if (*line == 'T' && strncmp(line, "TimeFollowsSort=", 16) == 0) { set_config_bool_value(line + 16, &conf.time_follows_sort); } else if (*line == 'T' && strncmp(line, "TimestampMark=", 14) == 0) { set_config_bool_value(line + 14, &conf.timestamp_mark); } else if (xargs.time_style == UNSET && *line == 'T' && strncmp(line, "TimeStyle=", 10) == 0) { set_time_style(line + 10, &conf.time_str, 0); } else if (xargs.tips == UNSET && *line == 'T' && strncmp(line, "Tips=", 5) == 0) { set_config_bool_value(line + 5, &conf.tips); } #ifndef _NO_TRASH else if (xargs.trasrm == UNSET && *line == 'T' && strncmp(line, "TrashAsRm=", 10) == 0) { set_config_bool_value(line + 10, &conf.tr_as_rm); } else if (*line == 'T' && strncmp(line, "TrashForce=", 11) == 0) { set_config_bool_value(line + 11, &conf.trash_force); } #endif /* !_NO_TRASH */ else if (xargs.trunc_names == UNSET && *line == 'T' && strncmp(line, "TrimNames=", 10) == 0) { err('n', PRINT_PROMPT, _("%s: TrimNames: This option is " "deprecated. Use TruncateNames instead.\n"), PROGRAM_NAME); set_config_bool_value(line + 10, &conf.trunc_names); } else if (xargs.trunc_names == UNSET && *line == 'T' && strncmp(line, "TruncateNames=", 14) == 0) { set_config_bool_value(line + 14, &conf.trunc_names); } else if (xargs.secure_env != 1 && xargs.secure_env_full != 1 && *line == 'U' && strncmp(line, "Umask=", 6) == 0) { unsigned int opt_num = MAX_UMASK + 1; ret = sscanf(line + 6, "%o\n", &opt_num); if (ret == -1 || opt_num > MAX_UMASK) continue; umask((mode_t)opt_num); /* flawfinder: ignore */ } else if (xargs.welcome_message == UNSET && *line == 'W' && strncmp(line, "WelcomeMessage=", 15) == 0) { set_config_bool_value(line + 15, &conf.welcome_message); } else if (*line == 'W' && strncmp(line, "WelcomeMessageStr=", 18) == 0) { char *tmp = get_line_value(line + 18); if (!tmp) continue; free(conf.welcome_message_str); conf.welcome_message_str = savestring(tmp, strlen(tmp)); } else { if (*line == 'W' && strncmp(line, "WorkspaceNames=", 15) == 0) set_workspace_names(line + 15); } } fclose(config_fp); if (default_answers_set == 0) set_default_answers_to_default(); if (xargs.disk_usage_analyzer == 1) { conf.sort = STSIZE; conf.long_view = conf.full_dir_size = 1; conf.list_dirs_first = conf.welcome_message = 0; } if (filter.str && filter.type == FILTER_FILE_NAME) { regfree(®ex_exp); ret = regcomp(®ex_exp, filter.str, REG_NOSUB | REG_EXTENDED); if (ret != FUNC_SUCCESS) { err('w', PRINT_PROMPT, _("%s: '%s': Invalid regular " "expression\n"), PROGRAM_NAME, filter.str); free(filter.str); filter.str = (char *)NULL; regfree(®ex_exp); } } } #endif /* CLIFM_SUCKLESS */ static int set_force_color(const char *val) { const int fallback = 8; if (!val || !*val) return fallback; if ((*val == '2' && strcmp(val + 1, "4bit") == 0) || (*val == 't' && strcmp(val + 1, "ruecolor") == 0)) return TRUECOLOR_NUM; if (!is_number(val)) return fallback; const int n = atoi(val); if (n == 8 || n == 16 || n == 256 || n == TRUECOLOR_NUM) return n; return fallback; } static void check_colors(void) { char *nc = getenv("NO_COLOR"); char *cnc = getenv("CLIFM_NO_COLOR"); char *ccf = getenv("CLICOLOR_FORCE"); /* See https://bixense.com/clicolors */ char *cfc = getenv("CLIFM_FORCE_COLOR"); if (xargs.colorize == UNSET && !nc && !cnc && (ccf || cfc)) { if (term_caps.color == 0) /* The user is forcing the use of colors even when the terminal * reports no color capability. */ term_caps.color = cfc ? set_force_color(cfc) : 8; conf.colorize = 1; } else if (xargs.colorize == 0 || term_caps.color == 0 || nc || cnc) { conf.colorize = 0; } else { conf.colorize = xargs.colorize == 1 ? 1 : DEF_COLORS; /* NOLINT */ } if (conf.colorize == 1) { set_colors(conf.usr_cscheme ? conf.usr_cscheme : (term_caps.color >= 256 ? DEF_COLOR_SCHEME_256 : DEF_COLOR_SCHEME), 1); cur_color = tx_c; return; } reset_filetype_colors(); reset_iface_colors(); cur_color = tx_c; } #ifndef _NO_FZF static char first_non_blank(const char *line) { if (!line || !*line) return 0; while (*line) { if (*line > ' ') return *line; line++; } return 0; } /* Return a macro describing the border type set for the '--border' option * in a fzf command (either FZF_DEFAULT_OPTS or FzfTabOptions). */ static int get_fzf_border(const char *line) { if (!line || !*line || (*line != ' ' && *line != '=')) /* No value for "--border". It defaults to "rounded". */ return FZF_BORDER_ROUNDED; line++; const char *p = line + (*line == '\'' || *line == '"'); char c = first_non_blank(p); if (!*p || *p == '-' || c == '-' || c == '\0') return FZF_BORDER_ROUNDED; if (*p == 'b') { if (strncmp(p, "block", 5) == 0) return FZF_BORDER_BLOCK; if (strncmp(p, "bold", 4) == 0) return FZF_BORDER_BOLD; if (strncmp(p, "bottom", 6) == 0) return FZF_BORDER_BOTTOM; } if (*p == 'd' && strncmp(p, "double", 6) == 0) return FZF_BORDER_DOUBLE; if (*p == 'l' && strncmp(p, "left", 4) == 0) return FZF_BORDER_LEFT; if (*p == 'n' && strncmp(p, "none", 4) == 0) return FZF_BORDER_NONE; if (*p == 'r') { if (strncmp(p, "right", 5) == 0) return FZF_BORDER_RIGHT; if (strncmp(p, "rounded", 7) == 0) return FZF_BORDER_ROUNDED; } if (*p == 's' && strncmp(p, "sharp", 5) == 0) return FZF_BORDER_SHARP; if (*p == 't') { if (strncmp(p, "top", 3) == 0) return FZF_BORDER_TOP; if (strncmp(p, "thinblock", 9) == 0) return FZF_BORDER_THINBLOCK; } if (*p == 'v' && strncmp(p, "vertical", 8) == 0) return FZF_BORDER_VERT; /* return FZF_BORDER_ROUNDED; */ return FZF_BORDER_NONE; /* == 0 */ } /* Set fzf_border_type (global) to a value describing the value of fzf * --border option: 0 (no vertical border), 1 (left or right border), * or 2 (left and right border). We need this value to properly calculate * the width of the fzf preview window (get_preview_win_width(), in tabcomp.c). */ int get_fzf_border_type(const char *line) { fzf_ext_border = get_fzf_border(line); switch (fzf_ext_border) { case FZF_BORDER_ROUNDED: /* fallthrough */ case FZF_BORDER_SHARP: /* fallthrough */ case FZF_BORDER_BOLD: /* fallthrough */ case FZF_BORDER_DOUBLE: /* fallthrough */ case FZF_BORDER_BLOCK: /* fallthrough */ case FZF_BORDER_THINBLOCK: case FZF_BORDER_VERT: return 2; case FZF_BORDER_LEFT: /* fallthrough */ case FZF_BORDER_RIGHT: return 1; default: return 0; } } int get_fzf_height(char *line) { /* For the time being, the '~' prefix is not supported for "--height" */ if (!line || !*line || !*(++line) || *line == '~') return 0; int val = 0; int percent = 0; size_t len = 0; get_term_size(); char *s = strchr(line, ' '); if (s) *s = '\0'; if (*line == '-') { const int n = atoi(line + 1); if (n >= 0 && n < term_lines) val = term_lines - n; goto END; } len = strlen(line); if (len > 1 && line[len - 1] == '%') { line[len - 1] = '\0'; percent = 1; } if (!is_number(line)) goto END; if (percent == 0) { val = atoi(line); goto END; } else { line[len - 1] = '\0'; const int n = atoi(line); if (n > 0 && n <= 100) val = n * term_lines / 100; } END: if (s) *s = ' '; if (percent == 1) line[len - 1] = '%'; return val; } /* Just check if --height, --border, and --preview are set in FZF_DEFAULT_OPTS. */ static void get_fzf_win_height_and_preview(void) { const char *p = xargs.secure_env_full == 1 ? NULL : getenv("FZF_DEFAULT_OPTS"); if (!p || !*p) return; if (conf.fzf_preview == UNSET && strstr(p, "--preview ")) conf.fzf_preview = FZF_EXTERNAL_PREVIEWER; char *b = (char *)NULL; if ((b = strstr(p, "--height")) != NULL) fzf_height_value = get_fzf_height(b + (sizeof("--height") - 1)); if (fzf_border_type == UNSET && (b = strstr(p, "--border")) != NULL) fzf_border_type = get_fzf_border_type(b + (sizeof("--border") - 1)); } #endif /* !_NO_FZF */ #ifndef _NO_TRASH static void create_trash_dirs(void) { struct stat a; if (stat(trash_files_dir, &a) != -1 && S_ISDIR(a.st_mode) && stat(trash_info_dir, &a) != -1 && S_ISDIR(a.st_mode)) return; if (xargs.stealth_mode == 1) { err('w', PRINT_PROMPT, _("%s: '%s': %s. Trash function disabled. " "If needed, create the directories manually and restart %s.\n" "E.g.: mkdir -p ~/.local/share/Trash/{files,info}\n"), PROGRAM_NAME, trash_dir, strerror(errno), PROGRAM_NAME); trash_ok = 0; return; } char *cmd[] = {"mkdir", "-p", "--", trash_files_dir, trash_info_dir, NULL}; const int ret = launch_execv(cmd, FOREGROUND, E_NOSTDERR); if (ret != FUNC_SUCCESS) { trash_ok = 0; err('w', PRINT_PROMPT, _("%s: '%s': Cannot create the trash " "directory (or one of its subdirectories: 'files' and 'info').\n" "Try creating them manually and restart %s.\n" "E.g.: mkdir -p ~/.local/share/Trash/{files,info}\n"), PROGRAM_NAME, trash_dir, PROGRAM_NAME); return; } } static void set_trash_dirs(void) { size_t len = 0; if (alt_trash_dir) { len = strlen(alt_trash_dir); trash_dir = savestring(alt_trash_dir, len); } else { if (!user.home) { trash_ok = 0; return; } char *env = (char *)NULL; char *data_home = (char *)NULL; if (xargs.secure_env != 1 && xargs.secure_env_full != 1 && (env = getenv("XDG_DATA_HOME")) && *env && (data_home = normalize_path(env, strlen(env))) && *data_home) { len = strlen(data_home) + 7; trash_dir = xnmalloc(len, sizeof(char)); snprintf(trash_dir, len, "%s/Trash", data_home); free(data_home); } else { free(data_home); /* In case it is not NULL, but starts with NUL. */ len = user.home_len + 20; trash_dir = xnmalloc(len, sizeof(char)); snprintf(trash_dir, len, "%s/.local/share/Trash", user.home); } } const size_t trash_len = strlen(trash_dir); len = trash_len + 7; trash_files_dir = xnmalloc(len, sizeof(char)); snprintf(trash_files_dir, len, "%s/files", trash_dir); len = trash_len + 6; trash_info_dir = xnmalloc(len, sizeof(char)); snprintf(trash_info_dir, len, "%s/info", trash_dir); create_trash_dirs(); } #endif /* _NO_TRASH */ static void undef_config_file_names(void) { free(config_dir_gral); config_dir_gral = (char *)NULL; free(config_dir); config_dir = (char *)NULL; free(tags_dir); tags_dir = (char *)NULL; free(kbinds_file); kbinds_file = (char *)NULL; free(colors_dir); colors_dir = (char *)NULL; free(plugins_dir); plugins_dir = (char *)NULL; free(dirhist_file); dirhist_file = (char *)NULL; free(bm_file); bm_file = (char *)NULL; free(msgs_log_file); msgs_log_file = (char *)NULL; free(cmds_log_file); cmds_log_file = (char *)NULL; free(hist_file); hist_file = (char *)NULL; free(config_file); config_file = (char *)NULL; free(profile_file); profile_file = (char *)NULL; free(mime_file); mime_file = (char *)NULL; free(actions_file); actions_file = (char *)NULL; free(remotes_file); remotes_file = (char *)NULL; } /* Set up Clifm directories and config files. Load the user's * configuration from the 'clifmrc' file. */ void init_config(void) { /* If just listing (--list-and-quit or --stat(-full)), we only need to * load the main config file and colors. */ const int just_listing = (xargs.stat > 0 || xargs.list_and_quit == 1); #ifndef _NO_TRASH if (just_listing == 0) set_trash_dirs(); #endif /* _NO_TRASH */ #ifdef LINUX_FSINFO if (just_listing == 0) get_ext_mountpoints(); #endif /* LINUX_FSINFO */ if (xargs.stealth_mode == 1) { err(ERR_NO_LOG, PRINT_PROMPT, _("%s: Running in stealth mode: " "persistent selection, bookmarks, jump database and directory " "history, just as plugins, logs and configuration files, are " "disabled.\n"), PROGRAM_NAME); config_ok = 0; check_colors(); return; } if (home_ok == 0) { check_colors(); return; } define_config_file_names(); create_config_files(just_listing); if (config_ok == 0) { undef_config_file_names(); check_colors(); return; } #ifndef CLIFM_SUCKLESS cschemes_n = get_colorschemes(); read_config(); #else xstrsncpy(div_line, DEF_DIV_LINE, sizeof(div_line)); #endif /* !CLIFM_SUCKLESS */ if (!conf.time_str) set_time_style_env(); if (!conf.ptime_str) set_ptime_style_env(); if (just_listing == 0) load_prompts(); check_colors(); if (xargs.secure_env == 1 || xargs.secure_env_full == 1) check_config_files_integrity(); #ifndef _NO_FZF /* If FZF win height was not defined in the config file, * check whether it is present in FZF_DEFAULT_OPTS. Same thing for * the previewer (--preview option). */ if (fzftab && just_listing == 0) get_fzf_win_height_and_preview(); #endif /* !_NO_FZF */ if (just_listing == 1) return; char *t = getenv("TERM"); if (t && *t == 'x' && strncmp(t, "xterm", 5) == 0) /* If running Xterm, instruct it to send an escape code (27) for * Meta (Alt) key sequences. Otherwise, Alt keybindings won't work. */ META_SENDS_ESC; } static void free_regex_filters(void) { if (filter.str && filter.env == 0) { regfree(®ex_exp); free(filter.str); filter.str = (char *)NULL; filter.rev = 0; filter.type = FILTER_NONE; } if (conf.histignore_regex) { regfree(®ex_hist); free(conf.histignore_regex); conf.histignore_regex = (char *)NULL; } if (conf.dirhistignore_regex) { regfree(®ex_dirhist); free(conf.dirhistignore_regex); conf.dirhistignore_regex = (char *)NULL; } } static void free_msgs(void) { size_t i; for (i = 0; i < msgs_n; i++) free(messages[i].text); msgs_n = msgs.error = msgs.warning = msgs.notice = 0; pmsg = NOMSG; } static void reset_variables(void) { /* Free everything */ free(conf.time_str); free(conf.ptime_str); free(conf.priority_sort_char); conf.time_str = conf.ptime_str = conf.priority_sort_char = (char *)NULL; free(conf.usr_cscheme); conf.usr_cscheme = (char *)NULL; free(config_dir_gral); free(config_dir); config_dir = config_dir_gral = (char *)NULL; #ifndef _NO_TRASH free(trash_dir); free(trash_files_dir); free(trash_info_dir); trash_dir = trash_files_dir = trash_info_dir = (char *)NULL; #endif /* !_NO_TRASH */ free(bm_file); free(msgs_log_file); free(cmds_log_file); bm_file = msgs_log_file = cmds_log_file = (char *)NULL; free(hist_file); free(dirhist_file); hist_file = dirhist_file = (char *)NULL; free(config_file); free(profile_file); config_file = profile_file = (char *)NULL; free(mime_file); free(plugins_dir); free(actions_file); free(kbinds_file); mime_file = plugins_dir = actions_file = kbinds_file = (char *)NULL; free(plugins_helper_file); plugins_helper_file = (char *)NULL; free(colors_dir); free(tmp_dir); free(sel_file); free(remotes_file); tmp_dir = colors_dir = sel_file = remotes_file = (char *)NULL; #ifndef _NO_SUGGESTIONS free(suggestion_buf); free(conf.suggestion_strategy); suggestion_buf = conf.suggestion_strategy = (char *)NULL; #endif /* !_NO_SUGGESTIONS */ free(conf.fzftab_options); free(tags_dir); free(conf.wprompt_str); conf.fzftab_options = tags_dir = conf.wprompt_str = (char *)NULL; free(conf.welcome_message_str); conf.welcome_message_str = (char *)NULL; free_autocmds(1); free_tags(); free_remotes(0); free_regex_filters(); free_msgs(); free(conf.opener); free(conf.encoded_prompt); free(conf.term); conf.opener = conf.encoded_prompt = conf.term = (char *)NULL; init_conf_struct(); free_workspaces_filters(); #ifndef _NO_FZF fzftab = UNSET; #endif /* !_NO_FZF */ hist_status = UNSET; print_removed_files = UNSET; prompt_offset = UNSET; prompt_notif = UNSET; dir_changed = 0; dequoted = 0; internal_cmd = 0; is_sel = 0; kbind_busy = 0; no_log = 0; print_msg = 0; recur_perm_error_flag = 0; sel_is_last = 0; shell_is_interactive = 0; shell_terminal = 0; conf.sort_reverse = 0; sort_switch = 0; config_ok = 1; home_ok = 1; selfile_ok = 1; #ifndef _NO_TRASH trash_ok = 1; #endif /* !_NO_TRASH */ pmsg = NOMSG; } #ifndef _NO_FZF static void update_finder_binaries_status(void) { if (!(bin_flags & FZF_BIN_OK) && is_cmd_in_path("fzf") == 1) bin_flags |= FZF_BIN_OK; if (!(bin_flags & FNF_BIN_OK) && is_cmd_in_path("fnf") == 1) bin_flags |= FNF_BIN_OK; if (!(bin_flags & SMENU_BIN_OK) && is_cmd_in_path("smenu") == 1) bin_flags |= SMENU_BIN_OK; } #endif /* !_NO_FZF */ int reload_config(void) { #ifndef _NO_FZF enum tab_mode tabmode_bk = tabmode; #endif /* !_NO_FZF */ reset_variables(); /* Set up config files and options */ init_config(); /* If some option was not set, set it to the default value */ check_options(); set_sel_file(); create_tmp_files(); #ifndef _NO_FZF if (tabmode_bk != tabmode) update_finder_binaries_status(); check_completion_mode(); #endif /* !_NO_FZF */ /* Free the aliases and prompt_cmds arrays to be allocated again */ int i = dirhist_total_index; while (--i >= 0) free(old_pwd[i]); free(old_pwd); old_pwd = (char **)NULL; if (jump_db) { for (i = 0; jump_db[i].path; i++) free(jump_db[i].path); free(jump_db); jump_db = (struct jump_t *)NULL; } jump_n = 0; i = (int)aliases_n; while (--i >= 0) { free(aliases[i].name); free(aliases[i].cmd); } free(aliases); aliases = (struct alias_t *)NULL; aliases_n = 0; i = (int)prompt_cmds_n; while (--i >= 0) free(prompt_cmds[i]); dirhist_total_index = 0; prompt_cmds_n = 0; get_aliases(); get_prompt_cmds(); load_dirhist(); load_jumpdb(); load_tags(); load_remotes(); init_workspaces_opts(); /* Set the current position of the dirhist index to the last entry. */ dirhist_cur_index = dirhist_total_index - 1; set_env(1); dir_changed = (autocmds_n > 0); return FUNC_SUCCESS; } clifm-1.26.3/src/config.h000066400000000000000000000031651506632037700151200ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* config.h */ #ifndef CONFIG_H #define CONFIG_H #define DUMP_CONFIG_STR 0 #define DUMP_CONFIG_INT 1 #define DUMP_CONFIG_BOOL 2 #define DUMP_CONFIG_CHR 3 __BEGIN_DECLS int config_edit(char **args); int create_bm_file(void); int create_kbinds_file(void); int create_main_config_file(char *file); int create_mime_file(char *file, const int new_prof); void create_tmp_files(void); void init_config(void); int reload_config(void); int config_reload(const char *arg); void set_div_line(char *line); void set_env(const int reload); #ifndef _NO_FZF int get_fzf_border_type(const char *line); int get_fzf_height(char *line); #endif /* !_NO_FZF */ void set_sel_file(void); void set_time_style(char *line, char **str, const int ptime); __END_DECLS #endif /* CONFIG_H */ clifm-1.26.3/src/dothidden.c000066400000000000000000000075641506632037700156170ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* dothidden.c * * DESCRIPTION: files named in a .hidden file in the current directory * are hidden when dotfiles are not shown (ShowHiddenFiles is set to false). * This feature is supported by most major GUI file managers, like Dolphin * and Nautilus (though haven't seen it in any terminal file manager). * Our implementation, however, does support wildcards. */ #include "helpers.h" #include /* strcmp, strlen */ #include "aux.h" /* xnmalloc, open_fread */ #include "checks.h" /* check_glob_char */ #include "dothidden.h" /* dothidden_t, DOTHIDDEN_FILE */ #include "strings.h" /* savestring */ /* Read .hidden file in the current directory and return a struct containing * the names of the files listed in it, expanding wildcards, if any. * Empty lines and lines containing a slash are ignored. * The length of each entry is stored in the "len" field of the struct. */ struct dothidden_t * load_dothidden(void) { struct dothidden_t *h = (struct dothidden_t *)NULL; FILE *fp; int fd = 0; struct stat a; if (lstat(DOTHIDDEN_FILE, &a) == -1 || !S_ISREG(a.st_mode) || a.st_size == 0 || !(fp = open_fread(DOTHIDDEN_FILE, &fd))) return h; char line[NAME_MAX + 1]; size_t lines = 0; while (fgets(line, 2, fp) != NULL) lines++; if (lines == 0) { fclose(fp); return h; } fseek(fp, 0L, SEEK_SET); h = xnmalloc(lines + 1, sizeof(struct dothidden_t)); size_t counter = 0; while (fgets(line, sizeof(line), fp) != NULL) { if (!*line || *line == '\n' || strchr(line, '/')) continue; size_t len = strlen(line); if (len > 0 && line[len - 1] == '\n') { line[len - 1] = '\0'; len--; } if (check_glob_char(line, GLOB_ONLY) == 0) { h[counter].name = savestring(line, len); h[counter].len = len; counter++; continue; } /* We have wildcards. Expand it. */ glob_t gbuf; if (glob(line, GLOB_BRACE, NULL, &gbuf) != 0) { globfree(&gbuf); continue; } lines += gbuf.gl_pathc; h = xnrealloc(h, lines, sizeof(struct dothidden_t)); size_t i; for (i = 0; i < gbuf.gl_pathc; i++) { /* Exclude self and parent dirs, just as dot-files */ if (!gbuf.gl_pathv[i] || !*gbuf.gl_pathv[i] || *gbuf.gl_pathv[i] == '.') continue; len = strlen(gbuf.gl_pathv[i]); h[counter].name = savestring(gbuf.gl_pathv[i], len); h[counter].len = len; counter++; } globfree(&gbuf); } h[counter].name = (char *)NULL; h[counter].len = 0; fclose(fp); return h; } /* Return 1 if the file named NAME is contained in the list of dot-hidden * files H. Otherwise, return 0. */ int check_dothidden(const char *restrict name, struct dothidden_t **h) { if (!name || !*name || !*h) return 0; const size_t namelen = strlen(name); size_t i; for (i = 0; (*h)[i].name; i++) { if (*name == *(*h)[i].name && namelen == (*h)[i].len && strcmp(name, (*h)[i].name) == 0) return 1; } return 0; } /* Free the dothidden_t struct H */ void free_dothidden(struct dothidden_t **h) { if (!*h) return; size_t i; for (i = 0; (*h)[i].name; i++) free((*h)[i].name); free(*h); } clifm-1.26.3/src/dothidden.h000066400000000000000000000024071506632037700156130ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* dothidden.h */ #ifndef DOTHIDDEN_H #define DOTHIDDEN_H /* File containing the list of files to be hidden */ #define DOTHIDDEN_FILE ".hidden" struct dothidden_t { char *name; size_t len; }; __BEGIN_DECLS struct dothidden_t *load_dothidden(void); int check_dothidden(const char *restrict name, struct dothidden_t **h); void free_dothidden(struct dothidden_t **h); __END_DECLS #endif /* DOTHIDDEN_H */ clifm-1.26.3/src/exec.c000066400000000000000000002006711506632037700145730ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* exec.c -- functions controlling the execution of programs */ #include "helpers.h" #include #include #include /* access() */ #include /* waitpid() */ #include /* tcgetattr(), tcsetattr() */ #include /* clock_gettime() */ #ifdef __OpenBSD__ typedef char *rl_cpvfunc_t; # include #else # include #endif /* __OpenBSD__ */ #ifdef __TINYC__ # undef CHAR_MAX /* Silence redefinition error */ #endif /* __TINYC__ */ #include "actions.h" #ifndef _NO_ARCHIVING # include "archives.h" #endif /* !_NO_ARCHIVING */ #include "autocmds.h" /* add_autocmd() */ #include "aux.h" #include "bookmarks.h" #include "checks.h" #include "colors.h" #include "config.h" #include "exec.h" #include "file_operations.h" #include "history.h" #include "init.h" #include "jump.h" #include "keybinds.h" #include "listing.h" #include "messages.h" #ifndef NO_MEDIA_FUNC # include "media.h" #endif /* NO_MEDIA_FUNC */ #include "mime.h" #include "misc.h" #ifndef _NO_BLEACH # include "name_cleaner.h" #endif /* !_NO_BLEACH */ #include "navigation.h" #ifndef _NO_PROFILES # include "profiles.h" #endif /* !_NO_PROFILES */ #include "prompt.h" #include "properties.h" #include "readline.h" #include "remotes.h" #include "search.h" #include "selection.h" #include "sort.h" #ifndef _NO_TRASH # include "trash.h" #endif /* !_NO_TRASH */ #include "sanitize.h" #include "spawn.h" #include "tags.h" #ifndef _NO_LIRA # include "view.h" /* preview_function */ #endif /* !_NO_LIRA */ #if !defined(__CYGWIN__) /* Get current modification time for each path in PATH and compare it to * the cached time (in paths[n].mtime). * Return 1 if at least one timestamp differs, or 0 otherwise. */ static int check_paths_timestamps(void) { if (path_n == 0) return FUNC_SUCCESS; struct stat a; int i = (int)path_n; int status = FUNC_SUCCESS; while (--i >= 0) { if (paths[i].path && *paths[i].path && stat(paths[i].path, &a) != -1 && a.st_mtime != paths[i].mtime) { paths[i].mtime = a.st_mtime; status = FUNC_FAILURE; } } return status; } /* Reload the list of available commands in PATH for tab completion. * Why? If this list is not updated, whenever some new program is * installed, renamed, or removed from some of the paths in PATH * while in CliFM, this latter needs to be restarted in order * to be able to recognize the new program for tab completion */ static void reload_binaries(void) { if (check_paths_timestamps() == FUNC_SUCCESS) return; if (bin_commands) { int j = (int)path_progsn; while (--j >= 0) free(bin_commands[j]); free(bin_commands); bin_commands = (char **)NULL; } if (paths) { int j = (int)path_n; while (--j >= 0) free(paths[j].path); free(paths); } path_n = get_path_env(1); get_path_programs(); } #endif /* !__CYGWIN__ */ /* Little export implementation. What it lacks? Command substitution * Export variables in ARG, in the form "VAR=VALUE", to the environment */ static int export_var_function(char **args) { if (!args || !args[0] || !*args[0]) { xerror("%s\n", _("export: A parameter, in the form VAR=VALUE, " "is required")); return FUNC_FAILURE; } if (IS_HELP(args[0])) { puts(EXPORT_VAR_USAGE); return FUNC_SUCCESS; } int status = FUNC_SUCCESS; size_t i; for (i = 0; args[i]; i++) { /* ARG might have been escaped by parse_input_str(), in the command * and parameter substitution block. Let's deescape it. */ char *ds = unescape_str(args[i], 0); if (!ds) { xerror("%s\n", _("export: Error unescaping argument")); status = FUNC_FAILURE; continue; } char *p = strchr(ds, '='); if (!p || !p[1]) { xerror(_("export: %s: Empty assignement\n"), ds); free(ds); status = FUNC_FAILURE; continue; } errno = 0; *p = '\0'; if (setenv(ds, p + 1, 1) == -1) { status = errno; xerror("export: %s\n", strerror(errno)); } *p = '='; free(ds); } return status; } static char * construct_shell_cmd(char **args) { if (!args || !args[0]) return (char *)NULL; /* If the command starts with either ':' or ';', it has bypassed all clifm * expansions. At this point we don't care about it: skip this char. */ const int bypass = (*args[0] == ';' || *args[0] == ':'); size_t i; size_t total_len = bg_proc == 1 ? 2 : 0; /* 2 == '&' + NUL byte */ size_t cmd_len = 0; for (i = 0; args[i]; i++) total_len += strlen(args[i]) + 1; /* 1 == space */ char *cmd = xnmalloc(total_len + 1, sizeof(char)); for (i = 0; args[i]; i++) { const char *src = (i == 0 && bypass == 1) ? args[i] + 1 : args[i]; xstrsncpy(cmd + cmd_len, src, total_len + 1); cmd_len += strlen(src) + 1; cmd[cmd_len - 1] = ' '; cmd[cmd_len] = '\0'; } if (bg_proc == 1) { cmd[cmd_len] = '&'; cmd[cmd_len + 1] = '\0'; } else { cmd[cmd_len - 1] = '\0'; /* Remove trailing space */ } return cmd; } static int check_shell_cmd_conditions(char **args) { if (!args || !args[0]) return FUNC_FAILURE; /* No command name ends with a slash */ const size_t len = (args && args[0]) ? strlen(args[0]) : 0; if (len > 0 && args[0][len - 1] == '/') { xerror("%s: '%s': %s\n", conf.autocd == 1 ? "cd" : "open", args[0], strerror(ENOENT)); return conf.autocd == 1 ? FUNC_FAILURE : E_NOTFOUND; } if (conf.ext_cmd_ok == 0) { xerror(_("%s: External commands are currently disabled. " "To enable them, run 'ext on'.\n"), PROGRAM_NAME); return FUNC_FAILURE; } return FUNC_SUCCESS; } static int run_shell_cmd(char **args) { const int ret = check_shell_cmd_conditions(args); if (ret != FUNC_SUCCESS) return ret; char *cmd = construct_shell_cmd(args); struct termios orig_termios; tcgetattr(STDIN_FILENO, &orig_termios); /* Calling the system shell is vulnerable to command injection, true. * But it is the user here who is directly running the command: this * should not be taken as an untrusted source. */ const int exit_status = launch_execl(cmd); tcsetattr(STDIN_FILENO, TCSAFLUSH, &orig_termios); free(cmd); /* For the time being, this is too slow on Cygwin. */ #if !defined(__CYGWIN__) reload_binaries(); #endif /* !__CYGWIN__ */ return exit_status; } /* Free everything and exit the program */ static void quit_func(char **args, const int exit_status) { if (!args || !args[0]) return; if (args[1] && IS_HELP(args[1])) { puts(QUIT_HELP); return; } int i = (int)args_n + 1; while (--i >= 0) free(args[i]); free(args); exit(exit_status); } static int set_max_files(char **args) { if (!args[1]) { /* Inform about the current value */ if (conf.max_files == UNSET) puts(_("Max files: unset")); else printf(_("Max files: %d\n"), conf.max_files); goto SUCCESS; } if (IS_HELP(args[1])) { puts(_(MF_USAGE)); return FUNC_SUCCESS; } if (*args[1] == 'u' && strcmp(args[1], "unset") == 0) { conf.max_files = UNSET; if (conf.autols == 1) reload_dirlist(); print_reload_msg(NULL, NULL, _("Max files unset\n")); goto SUCCESS; } if (*args[1] == '0' && !args[1][1]) { conf.max_files = 0; if (conf.autols == 1) reload_dirlist(); print_reload_msg(NULL, NULL, _("Max files set to %d\n"), conf.max_files); goto SUCCESS; } const long inum = strtol(args[1], NULL, 10); if (inum == LONG_MAX || inum == LONG_MIN || inum <= 0) { xerror(_("%s: %s: Invalid number\n"), PROGRAM_NAME, args[1]); return (exit_code = FUNC_FAILURE); } conf.max_files = (int)inum; if (conf.autols == 1) reload_dirlist(); print_reload_msg(NULL, NULL, _("Max files set to %d\n"), conf.max_files); SUCCESS: update_autocmd_opts(AC_MAX_FILES); return FUNC_SUCCESS; } static int dirs_first_function(const char *arg) { if (conf.autols == 0) return FUNC_SUCCESS; if (!arg) return rl_toggle_dirs_first(0, 0); if (IS_HELP(arg)) { puts(_(FF_USAGE)); return FUNC_SUCCESS; } if (*arg == 's' && strcmp(arg, "status") == 0) { printf(_("Directories first is %s\n"), conf.list_dirs_first == 1 ? _("on") : _("off")); } else if (*arg == 'o' && strcmp(arg, "on") == 0) { conf.list_dirs_first = 1; if (conf.autols == 1) reload_dirlist(); print_reload_msg(NULL, NULL, _("Directories first: on\n")); } else if (*arg == 'o' && strcmp(arg, "off") == 0) { conf.list_dirs_first = 0; if (conf.autols == 1) reload_dirlist(); print_reload_msg(NULL, NULL, _("Directories first: off\n")); } return FUNC_SUCCESS; } static int file_counter_function(const char *arg) { if (!arg) { conf.files_counter = !conf.files_counter; update_autocmd_opts(AC_FILES_COUNTER); if (conf.autols == 1) reload_dirlist(); print_reload_msg(NULL, NULL, _("File counter: %s\n"), conf.files_counter == 1 ? _("on") : _("off")); return FUNC_SUCCESS; } if (IS_HELP(arg)) { puts(_(FC_USAGE)); return FUNC_SUCCESS; } if (*arg == 'o' && strcmp(arg, "on") == 0) { conf.files_counter = 1; update_autocmd_opts(AC_FILES_COUNTER); if (conf.autols == 1) reload_dirlist(); print_reload_msg(NULL, NULL, _("File counter: on\n")); return FUNC_SUCCESS; } if (*arg == 'o' && strcmp(arg, "off") == 0) { conf.files_counter = 0; update_autocmd_opts(AC_FILES_COUNTER); if (conf.autols == 1) reload_dirlist(); print_reload_msg(NULL, NULL, _("File counter: off\n")); return FUNC_SUCCESS; } if (*arg == 's' && strcmp(arg, "status") == 0) { if (conf.files_counter == 1) puts(_("The file counter is on")); else puts(_("The file counter is off")); return FUNC_SUCCESS; } fprintf(stderr, "%s\n", _(FC_USAGE)); return FUNC_FAILURE; } static int pager_function(const char *arg) { if (!arg || (*arg == 'o' && strcmp(arg, "once") == 0)) { const int pg_bk = conf.pager; conf.pager = 1; conf.pager_once = 1; if (conf.autols == 1) reload_dirlist(); if (!arg) /* pg (no parameter) */ conf.pager = pg_bk; return FUNC_SUCCESS; } if (IS_HELP(arg)) { puts(_(PAGER_USAGE)); return FUNC_SUCCESS; } if (*arg == 's' && strcmp(arg, "status") == 0) { switch (conf.pager) { case 0: puts(_("The pager is off")); break; case 1: puts(_("The pager is on")); break; default: printf(_("The pager is set to %d\n"), conf.pager); break; } return FUNC_SUCCESS; } if (is_number(arg)) { const int n = atoi(arg); if (n == INT_MIN) { xerror("%s\n", _("pg: xatoi: Error converting to integer")); return FUNC_FAILURE; } conf.pager = n; printf(_("Pager set to %d\n"), n); goto SUCCESS; } if (*arg == 'o' && strcmp(arg, "off") == 0) { conf.pager = 0; puts(_("Pager: off")); goto SUCCESS; } if (*arg == 'o' && strcmp(arg, "on") == 0) { conf.pager = 1; if (conf.autols == 1) reload_dirlist(); else puts(_("Pager: on")); goto SUCCESS; } fprintf(stderr, "%s\n", _(PAGER_USAGE)); return FUNC_FAILURE; SUCCESS: update_autocmd_opts(AC_PAGER); return FUNC_SUCCESS; } static int ext_cmds_function(const char *arg) { if (!arg || IS_HELP(arg)) { puts(_(EXT_USAGE)); return FUNC_SUCCESS; } int exit_status = FUNC_SUCCESS; if (*arg == 's' && strcmp(arg, "status") == 0) { printf(_("External commands are %s\n"), conf.ext_cmd_ok ? _("allowed") : _("not allowed")); } else if (*arg == 'o' && strcmp(arg, "on") == 0) { conf.ext_cmd_ok = 1; puts(_("External commands: on")); } else if (*arg == 'o' && strcmp(arg, "off") == 0) { conf.ext_cmd_ok = 0; puts(_("External commands: off")); } else { fprintf(stderr, "%s\n", _(EXT_USAGE)); exit_status = FUNC_FAILURE; } return exit_status; } static int autocd_function(const char *arg) { if (!arg) { fprintf(stderr, "%s\n", _(AUTOCD_USAGE)); return FUNC_FAILURE; } if (strcmp(arg, "on") == 0) { conf.autocd = 1; puts(_("Autocd: on")); } else if (strcmp(arg, "off") == 0) { conf.autocd = 0; puts(_("Autocd: off")); } else if (strcmp(arg, "status") == 0) { printf(_("Autocd is %s\n"), conf.autocd == 1 ? _("on") : _("off")); } else if (IS_HELP(arg)) { puts(_(AUTOCD_USAGE)); } else { fprintf(stderr, "%s\n", _(AUTOCD_USAGE)); return FUNC_FAILURE; } return FUNC_SUCCESS; } static int auto_open_function(const char *arg) { if (!arg) { fprintf(stderr, "%s\n", _(AUTO_OPEN_USAGE)); return FUNC_FAILURE; } if (strcmp(arg, "on") == 0) { conf.auto_open = 1; puts(_("Auto-open: on")); } else if (strcmp(arg, "off") == 0) { conf.auto_open = 0; puts(_("Auto-open: off")); } else if (strcmp(arg, "status") == 0) { printf(_("Auto-open is %s\n"), conf.auto_open == 1 ? _("on") : _("off")); } else if (IS_HELP(arg)) { puts(_(AUTO_OPEN_USAGE)); } else { fprintf(stderr, "%s\n", _(AUTO_OPEN_USAGE)); return FUNC_FAILURE; } return FUNC_SUCCESS; } static int columns_function(const char *arg) { if (!arg) { conf.columned = !conf.columned; if (conf.autols == 1) reload_dirlist(); print_reload_msg(NULL, NULL, _("Columns: %s\n"), conf.columned == 1 ? _("on") : _("off")); return FUNC_SUCCESS; } if (IS_HELP(arg)) { puts(_(COLUMNS_USAGE)); return FUNC_SUCCESS; } if (*arg == 'o' && arg[1] == 'n' && !arg[2]) { conf.columned = 1; if (conf.autols == 1) reload_dirlist(); print_reload_msg(NULL, NULL, _("Columns: on\n")); } else if (*arg == 'o' && strcmp(arg, "off") == 0) { conf.columned = 0; if (conf.autols == 1) reload_dirlist(); print_reload_msg(NULL, NULL, _("Columns: off\n")); } else { fprintf(stderr, "%s\n", _(COLUMNS_USAGE)); return FUNC_FAILURE; } return FUNC_SUCCESS; } static int icons_function(const char *arg) { #ifdef _NO_ICONS UNUSED(arg); xerror(_("%s: icons: %s\n"), PROGRAM_NAME, _(NOT_AVAILABLE)); return FUNC_SUCCESS; #else if (!arg || !*arg) { conf.icons = !conf.icons; if (conf.autols == 1) reload_dirlist(); print_reload_msg(NULL, NULL, _("Icons: %s\n"), conf.icons == 1 ? _("on") : _("off")); return FUNC_SUCCESS; } if (IS_HELP(arg)) { puts(_(ICONS_USAGE)); return FUNC_SUCCESS; } if (*arg == 'o' && arg[1] == 'n' && !arg[2]) { conf.icons = 1; if (conf.autols == 1) reload_dirlist(); print_reload_msg(NULL, NULL, _("Icons: on\n")); return FUNC_SUCCESS; } else if (*arg == 'o' && strcmp(arg, "off") == 0) { conf.icons = 0; if (conf.autols == 1) reload_dirlist(); print_reload_msg(NULL, NULL, _("Icons: off\n")); return FUNC_SUCCESS; } else { fprintf(stderr, "%s\n", _(ICONS_USAGE)); return FUNC_FAILURE; } return FUNC_SUCCESS; #endif /* _NO_ICONS */ } static int clear_msgs(void) { if (msgs_n == 0) { printf(_("%s: No messages\n"), PROGRAM_NAME); return FUNC_SUCCESS; } size_t i; for (i = 0; i < msgs_n; i++) free(messages[i].text); if (conf.autols == 1) reload_dirlist(); print_reload_msg(NULL, NULL, _("Messages cleared\n")); msgs_n = msgs.error = msgs.warning = msgs.notice = 0; pmsg = NOMSG; return FUNC_SUCCESS; } static int print_msgs(void) { size_t i; for (i = 0; i < msgs_n; i++) { if (i > 0 && strcmp(messages[i].text, messages[i - 1].text) == 0) continue; printf("%s", messages[i].text); } return FUNC_SUCCESS; } static int msgs_function(const char *arg) { if (arg && IS_HELP(arg)) { puts(_(MSG_USAGE)); return FUNC_SUCCESS; } if (arg && strcmp(arg, "clear") == 0) return clear_msgs(); if (msgs_n > 0) return print_msgs(); printf(_("%s: No messages\n"), PROGRAM_NAME); return FUNC_SUCCESS; } static int opener_function(const char *arg) { if (!arg) { printf("opener: %s\n", conf.opener ? conf.opener : "lira (builtin)"); return FUNC_SUCCESS; } if (IS_HELP(arg)) { puts(_(OPENER_USAGE)); return FUNC_SUCCESS; } free(conf.opener); conf.opener = (char *)NULL; if (strcmp(arg, "default") != 0 && strcmp(arg, "lira") != 0) conf.opener = savestring(arg, strlen(arg)); printf(_("Opener set to '%s'\n"), conf.opener ? conf.opener : "lira (builtin)"); return FUNC_SUCCESS; } static int lightmode_function(const char *arg) { if (!arg) return rl_toggle_light_mode(0, 0); if (IS_HELP(arg)) { puts(LM_USAGE); return FUNC_SUCCESS; } if (*arg == 'o' && strcmp(arg, "on") == 0) { conf.light_mode = 1; update_autocmd_opts(AC_LIGHT_MODE); if (conf.autols == 1) reload_dirlist(); print_reload_msg(NULL, NULL, _("Light mode: on\n")); } else if (*arg == 'o' && strcmp(arg, "off") == 0) { conf.light_mode = 0; update_autocmd_opts(AC_LIGHT_MODE); if (conf.autols == 1) reload_dirlist(); print_reload_msg(NULL, NULL, _("Light mode: off\n")); } else { puts(LM_USAGE); } return FUNC_SUCCESS; } static size_t get_longest_alias_name(void) { int i = (int)aliases_n; size_t l = 0; while (--i >= 0) { const size_t len = strlen(aliases[i].name); if (len > l) l = len; } return l; } static int list_aliases(void) { if (aliases_n == 0) { printf(_("%s: No aliases found\n"), PROGRAM_NAME); return FUNC_SUCCESS; } size_t i; const size_t longest_name_len = get_longest_alias_name(); for (i = 0; i < aliases_n; i++) { printf("%-*s %s%s%s %s\n", (int)longest_name_len, aliases[i].name, mi_c, SET_MSG_PTR, df_c, aliases[i].cmd); } return FUNC_SUCCESS; } static int print_alias(const char *name) { if (!name || !*name) return FUNC_FAILURE; if (aliases_n == 0) { printf(_("%s: No aliases found\n"), PROGRAM_NAME); return FUNC_SUCCESS; } int i = (int)aliases_n; while (--i >= 0) { if (aliases[i].name && *name == *aliases[i].name && strcmp(name, aliases[i].name) == 0) { printf("alias %s='%s'\n", aliases[i].name, aliases[i].cmd ? aliases[i].cmd : ""); return FUNC_SUCCESS; } } xerror(_("%s: '%s': No such alias\n"), PROGRAM_NAME, name); return FUNC_FAILURE; } static int alias_function(char **args) { if (!args[1]) { list_aliases(); return FUNC_SUCCESS; } if (IS_HELP(args[1])) { puts(_(ALIAS_USAGE)); return FUNC_SUCCESS; } if (*args[1] == 'i' && strcmp(args[1], "import") == 0) { if (!args[2]) { puts(_(ALIAS_USAGE)); return FUNC_SUCCESS; } return alias_import(args[2]); } if (*args[1] == 'l' && (strcmp(args[1], "ls") == 0 || strcmp(args[1], "list") == 0)) return list_aliases(); return print_alias(args[1]); } static const char * gen_hidden_status(void) { switch (conf.show_hidden) { case HIDDEN_FALSE: return _("off"); case HIDDEN_FIRST: return _("on (list first)"); case HIDDEN_LAST: return _("on (list last)"); case HIDDEN_TRUE: /* fallthrough */ default: return _("on"); } } static int hidden_files_function(const char *arg) { if (!arg) return rl_toggle_hidden_files(0, 0); if (IS_HELP(arg)) { puts(_(HF_USAGE)); return FUNC_SUCCESS; } if (strcmp(arg, "status") == 0) { printf(_("Show-hidden-files is %s\n"), gen_hidden_status()); } else if (strcmp(arg, "first") == 0) { conf.show_hidden = HIDDEN_FIRST; if (conf.autols == 1) reload_dirlist(); print_reload_msg(NULL, NULL, _("Hidden files: on (list first)\n")); } else if (strcmp(arg, "last") == 0) { conf.show_hidden = HIDDEN_LAST; if (conf.autols == 1) reload_dirlist(); print_reload_msg(NULL, NULL, _("Hidden files: on (list last)\n")); } else if (strcmp(arg, "off") == 0) { conf.show_hidden = HIDDEN_FALSE; if (conf.autols == 1) reload_dirlist(); print_reload_msg(NULL, NULL, _("Hidden files: off\n")); } else if (strcmp(arg, "on") == 0) { conf.show_hidden = HIDDEN_TRUE; if (conf.autols == 1) reload_dirlist(); print_reload_msg(NULL, NULL, _("Hidden files: on\n")); } update_autocmd_opts(AC_SHOW_HIDDEN); return FUNC_SUCCESS; } static int toggle_exec_func(char **args) { if (!args[1] || IS_HELP(args[1])) { puts(_(TE_USAGE)); return FUNC_SUCCESS; } int exit_status = FUNC_SUCCESS; size_t i, n = 0; for (i = 1; args[i]; i++) { struct stat attr; if (strchr(args[i], '\\')) { char *tmp = unescape_str(args[i], 0); if (tmp) { xstrsncpy(args[i], tmp, strlen(tmp) + 1); free(tmp); } } if (lstat(args[i], &attr) == -1) { xerror("stat: '%s': %s\n", args[i], strerror(errno)); exit_status = FUNC_FAILURE; continue; } if (toggle_exec(args[i], attr.st_mode) == FUNC_FAILURE) exit_status = FUNC_FAILURE; else n++; } if (n > 0) { if (conf.autols == 1 && exit_status == FUNC_SUCCESS) reload_dirlist(); print_reload_msg(SET_SUCCESS_PTR, xs_cb, _("Toggled executable bit on %zu %s\n"), n, n > 1 ? _("files") : _("file")); } return exit_status; } static int pin_function(char *arg) { if (arg) { if (IS_HELP(arg)) { puts(PIN_USAGE); return FUNC_SUCCESS; } return pin_directory(arg); } if (pinned_dir) printf(_("Pinned file: '%s'\n"), pinned_dir); else puts(_("pin: No pinned file")); return FUNC_SUCCESS; } static int props_function(char **args) { if (!args[1] || IS_HELP(args[1])) { fprintf(stderr, "%s\n", _(PROP_USAGE)); return FUNC_SUCCESS; } const int full_dirsize = args[0][1] == 'p'; /* Command is 'pp' */ return properties_function(args + 1, full_dirsize); } static int open_with_function(char **args) { #ifndef _NO_LIRA if (args[1]) { if (IS_HELP(args[1])) { puts(_(OW_USAGE)); return FUNC_SUCCESS; } return mime_open_with(args[1], args[2] ? args + 2 : NULL); } puts(_(OW_USAGE)); return FUNC_SUCCESS; #else UNUSED(args); xerror("%s: %s\n", PROGRAM_NAME, _(NOT_AVAILABLE)); return FUNC_FAILURE; #endif /* !_NO_LIRA */ } static int refresh_function(const int old_exit_code) { refresh_screen(); return old_exit_code; } static int export_files_function(char **args) { if (args[1] && IS_HELP(args[1])) { puts(_(EXPORT_FILES_USAGE)); return FUNC_SUCCESS; } char *ret = export_files(args, 1); if (ret) { printf(_("Filenames exported to '%s'\n"), ret); free(ret); return FUNC_SUCCESS; } return FUNC_FAILURE; } static int bookmarks_func(char **args) { if (args[1] && IS_HELP(args[1])) { puts(_(BOOKMARKS_USAGE)); return FUNC_SUCCESS; } /* Disable keyboard shortcuts. Otherwise, the function will * still be waiting for input while the screen have been taken * by another function. */ kbind_busy = 1; const int exit_status = bookmarks_function(args); /* Reenable keyboard shortcuts */ kbind_busy = 0; return exit_status; } static int desel_function(char **args) { if (args[1] && IS_HELP(args[1])) { puts(_(DESEL_USAGE)); return FUNC_SUCCESS; } kbind_busy = 1; rl_attempted_completion_function = NULL; const int exit_status = deselect(args); rl_attempted_completion_function = my_rl_completion; kbind_busy = 0; return exit_status; } static int new_instance_function(char **args) { int exit_status = FUNC_SUCCESS; if (args[1]) { if (IS_HELP(args[1])) { puts(_(X_USAGE)); return FUNC_SUCCESS; } else if (*args[0] == 'x') { exit_status = new_instance(args[1], 0); } else { /* Run as root */ exit_status = new_instance(args[1], 1); } } else { /* Run new instance in CWD */ if (*args[0] == 'x') exit_status = new_instance(workspaces[cur_ws].path, 0); else exit_status = new_instance(workspaces[cur_ws].path, 1); } return exit_status; } #ifndef NO_MEDIA_FUNC /* MODE could be either MEDIA_LIST (mp command) or MEDIA_MOUNT (media command) */ static int media_function(char *arg, const int mode) { if (arg && IS_HELP(arg)) { if (mode == MEDIA_LIST) puts(_(MOUNTPOINTS_USAGE)); else puts(_(MEDIA_USAGE)); return FUNC_SUCCESS; } kbind_busy = 1; rl_attempted_completion_function = NULL; const int exit_status = media_menu(mode); rl_attempted_completion_function = my_rl_completion; kbind_busy = 0; return exit_status; } #endif /* NO_MEDIA_FUNC */ static int chdir_function(char *arg) { if (arg && IS_HELP(arg)) { puts(_(CD_USAGE)); return FUNC_SUCCESS; } return cd_function(arg, CD_PRINT_ERROR); } static int sort_func(char **args) { if (args[1] && IS_HELP(args[1])) { puts(_(SORT_USAGE)); return FUNC_SUCCESS; } return sort_function(args); } static int check_pinned_file(char **args) { int i = (int)args_n + 1; while (--i >= 0) { if (*args[i] == ',' && !args[i][1]) { xerror(_("%s: No pinned file\n"), PROGRAM_NAME); return FUNC_FAILURE; } } return FUNC_SUCCESS; } static int check_actions(char **args) { if (actions_n == 0) return (-1); int i = (int)actions_n; while (--i >= 0) { if (*args[0] == *usr_actions[i].name && strcmp(args[0], usr_actions[i].name) == 0) { setenv("CLIFM_PLUGIN_NAME", usr_actions[i].name, 1); const int ret = run_action(usr_actions[i].value, args); unsetenv("CLIFM_PLUGIN_NAME"); return ret; } } return (-1); } static int launch_shell(const char *arg) { if (!arg[1]) { /* If just ":" or ";", launch the default shell */ char *cmd[] = {user.shell, NULL}; return launch_execv(cmd, FOREGROUND, E_NOFLAG); } if (arg[1] == ';' || arg[1] == ':') { /* If double semi colon or colon (or ";:" or ":;") */ xerror(_("%s: '%s': Syntax error\n"), PROGRAM_NAME, arg); return FUNC_FAILURE; } return (-1); } static void expand_and_deescape(char **arg, char **deq_str) { if (*(*arg) == '~') { char *exp_path = tilde_expand(*arg); if (exp_path) { free(*arg); *arg = exp_path; } } /* Deescape the string (only if filename) */ if (strchr(*arg, '\\')) *deq_str = unescape_str(*arg, 0); } static int open_file_func(char **args, const filesn_t i) { if (conf.autocd && (file_info[i].type == DT_DIR || file_info[i].dir == 1)) return cd_function(args[0], CD_PRINT_ERROR); if (conf.auto_open && (file_info[i].type == DT_REG || file_info[i].type == DT_LNK)) { char *cmd[] = {"open", args[0], args[1], NULL}; return open_function(cmd); } return (-1); } /* Try to autocd or auto-open dir/file. * Only autocd or auto-open here if not absolute path and if there * is no second argument or if second argument is "&" * If just 'edit' or 'config', do not try to open a file named 'edit' or * 'config': always run the 'edit/config' command. */ static int check_auto_first(char **args) { if (!args || !args[0] || !*args[0]) return (-1); if (*args[0] == '/' || (conf.autocd == 0 && conf.auto_open == 0) || (args[1] && (*args[1] != '&' || args[1][1]))) return (-1); if (!(flags & FIRST_WORD_IS_ELN) && is_internal_cmd(args[0], ALL_CMDS, 1, 1)) return (-1); char *deq_str = (char *)NULL; if (conf.autocd == 1 || conf.auto_open == 1) expand_and_deescape(&args[0], &deq_str); char *tmp = deq_str ? deq_str : args[0]; const size_t len = strlen(tmp); int rem_slash = 0; if (len > 0 && tmp[len - 1] == '/') { rem_slash = 1; tmp[len - 1] = '\0'; } if (conf.autocd == 1 && cdpath_n > 0 && !args[1] && cd_function(tmp, CD_NO_PRINT_ERROR) == FUNC_SUCCESS) { free(deq_str); return FUNC_SUCCESS; } filesn_t i = files; while (--i >= 0) { if (*tmp != *file_info[i].name || strcmp(tmp, file_info[i].name) != 0) continue; free(deq_str); deq_str = (char *)NULL; const int ret = open_file_func(args, i); if (ret != -1) return ret; break; } if (rem_slash == 1) tmp[len - 1] = '/'; free(deq_str); return (-1); } static int auto_open_file(char **args, char *tmp) { char *cmd[] = {"open", tmp, args_n >= 1 ? args[1] : NULL, args_n >= 2 ? args[2] : NULL, NULL}; args_n++; const int ret = open_function(cmd); args_n--; free(tmp); return ret; } static int autocd_dir(char *tmp) { int ret = FUNC_SUCCESS; if (conf.autocd) { ret = cd_function(tmp, CD_PRINT_ERROR); } else { xerror(_("%s: cd: '%s': Is a directory\n"), PROGRAM_NAME, tmp); ret = EISDIR; } free(tmp); return ret; } /* Try to autocd or auto-open */ /* If there is a second word (parameter, ARGS[1]) and this word starts * with a dash, do not take the first word (ARGS[0]) as a file to be * opened, but as a command to be executed. */ static int check_auto_second(char **args) { if (args[1] && *args[1] == '-') return (-1); char *tmp = savestring(args[0], strlen(args[0])); if (!tmp) return (-1); if (strchr(tmp, '\\')) { char *dstr = unescape_str(tmp, 0); if (dstr) { free(tmp); tmp = dstr; } } if (conf.autocd == 1 && cdpath_n > 0 && !args[1]) { const int ret = cd_function(tmp, CD_NO_PRINT_ERROR); if (ret == FUNC_SUCCESS) { free(tmp); return FUNC_SUCCESS; } } struct stat attr; if (stat(tmp, &attr) != 0) { free(tmp); return (-1); } if (conf.autocd == 1 && S_ISDIR(attr.st_mode) && !args[1]) return autocd_dir(tmp); /* Regular, non-executable file, or exec file not in PATH, * not ./file, and not /path/to/file */ if (conf.auto_open == 1 && S_ISREG(attr.st_mode) && (!(attr.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) || (!is_bin_cmd(tmp) && !(*tmp == '.' && *(tmp + 1) == '/') && *tmp != '/' ) ) ) return auto_open_file(args, tmp); free(tmp); return (-1); } static int colors_function(char *arg) { if (arg && IS_HELP(arg)) puts(_(COLORS_USAGE)); else color_codes(); return FUNC_SUCCESS; } static int ls_function(void) { free_dirlist(); const int ret = list_dir(); get_sel_files(); return ret; } static int lira_function(char **args) { #ifndef _NO_LIRA return mime_open(args); #else UNUSED(args); xerror("%s: lira: %s\n", PROGRAM_NAME, _(NOT_AVAILABLE)); return FUNC_FAILURE; #endif /* !_NO_LIRA */ } static int check_comments(char *name) { const int maybe_comment = ((*name == '\\' && name[1] == '#') || *name == '#'); if (maybe_comment == 0) return FUNC_FAILURE; char *p = (*name == '\\' || strchr(name + 1, '\\')) ? unescape_str(name, 0) : (char *)NULL; char * n = p ? p : name; /* Skip lines starting with '#' if there is no such filename * in the current directory. This implies that no command starting * with '#' will be executed */ struct stat a; const int ret = lstat(n, &a); free(p); if (ret == -1) return FUNC_SUCCESS; if (conf.autocd == 1 && S_ISDIR(a.st_mode)) return FUNC_FAILURE; if (conf.auto_open == 1 && !S_ISDIR(a.st_mode)) return FUNC_FAILURE; return FUNC_SUCCESS; } static int print_stats(void) { if (conf.light_mode == 1) puts(_("Running in light mode: Some files statistics are not available\n")); char dir_empty[MAX_INT_STR + 10]; *dir_empty = '\0'; char reg_empty[MAX_INT_STR + 10]; *reg_empty = '\0'; char lnk_broken[MAX_INT_STR + 10]; *lnk_broken = '\0'; if (stats.empty_dir > 0) snprintf(dir_empty, sizeof(dir_empty), " (%zu empty)", stats.empty_dir); if (stats.empty_reg > 0) snprintf(reg_empty, sizeof(reg_empty), " (%zu empty)", stats.empty_reg); if (stats.broken_link > 0) snprintf(lnk_broken, sizeof(lnk_broken), " (%zu broken)", stats.broken_link); printf(_("Total files: %jd\n\ Directories: %zu%s\n\ Regular files: %zu%s\n\ Executable files: %zu\n\ Hidden files: %zu\n\ SUID files: %zu\n\ SGID files: %zu\n\ Files w/capabilities: %zu\n\ FIFO/pipes: %zu\n\ Sockets: %zu\n\ Block devices: %zu\n\ Character devices: %zu\n\ Symbolic links: %zu%s\n\ Multi-link files: %zu\n\ Files w/extended attributes: %zu\n\ Other-writable files: %zu\n\ Sticky files: %zu\n\ Unknown file types: %zu\n\ Inaccessible files: %zu\n\ "), (intmax_t)files, stats.dir, dir_empty, stats.reg, reg_empty, stats.exec, stats.hidden, stats.suid, stats.sgid, stats.caps, stats.fifo, stats.socket, stats.block_dev, stats.char_dev, stats.link, lnk_broken, stats.multi_link, stats.extended, stats.other_writable, stats.sticky, stats.unknown, stats.unstat); #ifndef _BE_POSIX # ifdef SOLARIS_DOORS printf(_("Doors: %zu\n"), stats.door); printf(_("Ports: %zu\n"), stats.port); # endif /* SOLARIS_DOORS */ # ifdef S_ARCH1 printf(_("Archive state 1: %zu\n"), stats.arch1); printf(_("Archive state 2: %zu\n"), stats.arch2); # endif /* S_ARCH1 */ # ifdef S_IFWHT printf(_("Whiteout: %zu\n"), stats.whiteout); # endif /* S_IFWHT */ #endif /* _BE_POSIX */ return FUNC_SUCCESS; } static int trash_func(char **args, int *_cont) { #ifndef _NO_TRASH if (args[1] && IS_HELP(args[1])) { puts(_(TRASH_USAGE)); *_cont = 0; return FUNC_SUCCESS; } int exit_status = trash_function(args); if (is_sel && sel_n > 0) { /* If 'tr sel', deselect everything */ int i = (int)sel_n; while (--i >= 0) free(sel_elements[i].name); sel_n = 0; if (save_sel() != 0) exit_status = FUNC_FAILURE; } return exit_status; #else UNUSED(args); xerror(_("%s: trash: %s\n"), PROGRAM_NAME, _(NOT_AVAILABLE)); *_cont = 0; return FUNC_FAILURE; #endif /* !_NO_TRASH */ } static int untrash_func(char **args, int *_cont) { #ifndef _NO_TRASH if (args[1] && IS_HELP(args[1])) { puts(_(UNTRASH_USAGE)); *_cont = 0; return FUNC_SUCCESS; } kbind_busy = 1; rl_attempted_completion_function = NULL; const int exit_status = untrash_function(args); rl_attempted_completion_function = my_rl_completion; kbind_busy = 0; return exit_status; #else UNUSED(args); xerror("%s: trash: %s\n", PROGRAM_NAME, _(NOT_AVAILABLE)); *_cont = 0; return FUNC_FAILURE; #endif /* !_NO_TRASH */ } static int toggle_full_dir_size(const char *arg) { if (!arg || !*arg || IS_HELP(arg)) { puts(_(FZ_USAGE)); return FUNC_SUCCESS; } if (*arg != 'o') { xerror(_("%s: '%s': Invalid argument. Try 'fz -h'\n"), PROGRAM_NAME, arg); return FUNC_FAILURE; } if (arg[1] == 'n' && !arg[2]) { conf.full_dir_size = 1; update_autocmd_opts(AC_FULL_DIR_SIZE); if (conf.autols == 1) reload_dirlist(); print_reload_msg(NULL, NULL, _("Full directory size: on\n")); return FUNC_SUCCESS; } if (arg[1] == 'f' && arg[2] == 'f' && !arg[3]) { conf.full_dir_size = 0; update_autocmd_opts(AC_FULL_DIR_SIZE); if (conf.autols == 1) reload_dirlist(); print_reload_msg(NULL, NULL, _("Full directory size: off\n")); return FUNC_SUCCESS; } xerror(_("%s: '%s': Invalid argument. Try 'fz -h'\n"), PROGRAM_NAME, arg); return FUNC_FAILURE; } static void set_cp_cmd(char **cmd, int *cp_force) { const int bk_cp_cmd = conf.cp_cmd; if (*cp_force == 1) { if (conf.cp_cmd == CP_ADVCP) conf.cp_cmd = CP_ADVCP_FORCE; else if (conf.cp_cmd == CP_CP) conf.cp_cmd = CP_CP_FORCE; } char *n = (char *)NULL; switch (conf.cp_cmd) { case CP_ADVCP: n = DEFAULT_ADVCP_CMD; break; case CP_ADVCP_FORCE: n = DEFAULT_ADVCP_CMD_FORCE; *cp_force = 1; break; case CP_WCP: n = DEFAULT_WCP_CMD; break; case CP_RSYNC: n = DEFAULT_RSYNC_CMD; break; case CP_CP_FORCE: n = DEFAULT_CP_CMD_FORCE; *cp_force = 1; break; case CP_CP: /* fallthrough */ default: n = DEFAULT_CP_CMD; break; } const size_t len = strlen(n) + 1; *cmd = xnrealloc(*cmd, len, sizeof(char)); xstrsncpy(*cmd, n, len); conf.cp_cmd = bk_cp_cmd; } static void set_mv_cmd(char **cmd, int *mv_force) { int bk_mv_cmd = conf.mv_cmd; if (*mv_force == 1) { if (conf.mv_cmd == MV_ADVMV) conf.mv_cmd = MV_ADVMV_FORCE; else if (conf.mv_cmd == MV_MV) conf.mv_cmd = MV_MV_FORCE; } char *n = (char *)NULL; switch (conf.mv_cmd) { case MV_ADVMV: n = DEFAULT_ADVMV_CMD; break; case MV_ADVMV_FORCE: n = DEFAULT_ADVMV_CMD_FORCE; *mv_force = 1; break; case MV_MV_FORCE: n = DEFAULT_MV_CMD_FORCE; *mv_force = 1; break; case MV_MV: /* fallthrough */ default: n = DEFAULT_MV_CMD; break; } const size_t len = strlen(n) + 1; *cmd = xnrealloc(*cmd, len, sizeof(char)); xstrsncpy(*cmd, n, len); conf.mv_cmd = bk_mv_cmd; } /* Let's check we have not left any zombie process behind. This happens * whenever we run a process in the background via launch_execv. */ static void check_zombies(void) { int status = 0; if (waitpid(-1, &status, WNOHANG) > 0) zombies--; } /* Return 1 if STR is a path, zero otherwise. */ static int is_path(char *str) { if (!str || !*str) return 0; if (strchr(str, '\\')) { char *p = unescape_str(str, 0); if (!p) return 0; const int ret = access(p, F_OK); free(p); if (ret != 0) return 0; } else { if (access(str, F_OK) != 0) return 0; } return 1; } /* Replace "\S" by "S" in the memory address pointed to by s */ static void remove_backslash(char **s) { if (!*s || !*(*s)) return; char *p = *s; while (*(*s)) { *(*s) = *(*s + 1); (*s)++; } *(*s) = '\0'; *s = p; } static int dirhist_function(char *dir) { if (!dir || !*dir) { print_dirhist(NULL); return FUNC_SUCCESS; } if (IS_HELP(dir)) { puts(DH_USAGE); return FUNC_SUCCESS; } if (*dir == '!' && is_number(dir + 1)) { int n = atoi(dir + 1); if (n <= 0 || n > dirhist_total_index) { xerror(_("dh: '%d': No such entry number\n"), n); return FUNC_FAILURE; } n--; if (!old_pwd[n] || *old_pwd[n] == KEY_ESC) { xerror("%s\n", _("dh: Invalid history entry")); return FUNC_FAILURE; } return cd_function(old_pwd[n], CD_PRINT_ERROR); } if (*dir != '/' || !strchr(dir + 1, '/')) { print_dirhist(dir); return FUNC_SUCCESS; } return cd_function(dir, CD_PRINT_ERROR); } static int long_view_function(const char *arg) { if (!arg) return rl_toggle_long_view(0, 0); if (IS_HELP(arg) || (strcmp(arg, "on") != 0 && strcmp(arg, "off") != 0)) { puts(LL_USAGE); return FUNC_SUCCESS; } conf.long_view = arg[1] == 'n' ? 1 : 0; update_autocmd_opts(AC_LONG_VIEW); if (conf.autols == 1) reload_dirlist(); print_reload_msg(NULL, NULL, _("Long view: %s\n"), arg[1] == 'n' ? _("on") : _("off")); return FUNC_SUCCESS; } /* Remove variables specificied in VAR from the environment */ static int unset_function(char **var) { if (!var || !var[0]) { puts(_("unset: A variable name is required")); return FUNC_SUCCESS; } if (IS_HELP(var[0])) { puts(UNSET_USAGE); return FUNC_SUCCESS; } int status = FUNC_SUCCESS; size_t i; for (i = 0; var[i]; i++) { if (unsetenv(var[i]) == -1) { status = errno; xerror("unset: '%s': %s\n", var[i], strerror(errno)); } } return status; } static int run_log_cmd(char **args) { if (config_ok == 0) { xerror(_("%s: Log function disabled\n"), PROGRAM_NAME); return FUNC_FAILURE; } if (!args[0] || IS_HELP(args[0])) { puts(LOG_USAGE); return FUNC_SUCCESS; } if (*args[0] == 'c' && strcmp(args[0], "cmd") == 0) { if (!args[1] || strcmp(args[1], "list") == 0) return print_logs(CMD_LOGS); if (*args[1] == 's' && strcmp(args[1], "status") == 0) { printf(_("log: Command logs are %s\n"), (conf.log_cmds == 1) ? _("enabled") : _("disabled")); return FUNC_SUCCESS; } if (*args[1] == 'o' && strcmp(args[1], "on") == 0) { conf.log_cmds = 1; puts(_("log: Command logs enabled")); return FUNC_SUCCESS; } if (*args[1] == 'o' && strcmp(args[1], "off") == 0) { conf.log_cmds = 0; puts(_("log: Command logs disabled")); return FUNC_SUCCESS; } if (*args[1] == 'c' && strcmp(args[1], "clear") == 0) { int ret = clear_logs(CMD_LOGS); if (ret == FUNC_SUCCESS) puts(_("log: Command logs cleared")); return ret; } } if (*args[0] == 'm' && strcmp(args[0], "msg") == 0) { if (!args[1] || strcmp(args[1], "list") == 0) return print_logs(MSG_LOGS); if (*args[1] == 's' && strcmp(args[1], "status") == 0) { printf(_("log: Message logs are %s\n"), (conf.log_msgs == 1) ? _("enabled") : _("disabled")); return FUNC_SUCCESS; } if (*args[1] == 'o' && strcmp(args[1], "on") == 0) { conf.log_msgs = 1; puts(_("log: Message logs enabled")); return FUNC_SUCCESS; } if (*args[1] == 'o' && strcmp(args[1], "off") == 0) { conf.log_msgs = 0; puts(_("log: Message logs disabled")); return FUNC_SUCCESS; } if (*args[1] == 'c' && strcmp(args[1], "clear") == 0) { int ret = clear_logs(MSG_LOGS); if (ret == FUNC_SUCCESS) puts(_("log: Message logs cleared")); return ret; } } fprintf(stderr, "%s\n", LOG_USAGE); return FUNC_FAILURE; } #ifdef GENERIC_FS_MONITOR /* Update the current list of files if the modification time of the current * directory changed and if the number of files differ. Sometimes, processes * create temporary files (changing modification time) that are immediately * deleted (resulting in the same number of files), in which case there is no * need to update the list of files (this happens for example with 'git pull', * or with a command along the lines of 'touch file && rm file'). */ static void check_fs_changes(void) { if (!workspaces || cur_ws < 0 || cur_ws >= MAX_WS || !workspaces[cur_ws].path) return; const filesn_t cur_files = count_dir(workspaces[cur_ws].path, 0) - 2; struct stat a; if (curdir_mtime != 0 && stat(workspaces[cur_ws].path, &a) != -1 && curdir_mtime != a.st_mtime && cur_files >= 0 && files != cur_files) reload_dirlist(); } #endif /* GENERIC_FS_MONITOR */ /* Check the command CMD against a list of commands able to modify the * filesystem. Return 1 if CMD is found in the list or zero otherwise. */ static int is_write_cmd(const char *cmd) { static struct nameslist_t const wcmds[] = { /* Internal commands */ {"ac", 2}, {"ad", 2}, {"bl", 2}, {"bb", 2}, {"bleach", 6}, {"br", 2}, {"bulk", 4}, {"c", 1}, {"dup", 3}, {"l", 1}, {"le", 2}, {"m", 1}, {"md", 2}, {"n", 1}, {"new", 3}, {"oc", 2}, {"paste", 5}, {"pc", 2}, {"r", 1}, {"rr", 2}, {"t", 1}, {"ta", 2}, {"td", 2}, {"tm", 2}, {"tn", 2}, {"tu", 2}, {"ty", 2}, {"tag", 3}, {"te", 2}, {"trash", 5}, {"u", 1}, {"undel", 5}, {"untrash", 7}, {"vv", 2}, /* Shell commands */ {"cp", 2}, {"rm", 2}, {"mv", 2}, {"mkdir", 5}, {"rmdir", 5}, {"ln", 2}, {"link", 4}, {"unlink", 6}, #ifdef CHECK_COREUTILS /* Mostly BSD */ {"gcp", 3}, {"grm", 3}, {"gmv", 3}, {"gmkdir", 6}, {"grmdir", 6}, {"gln", 3}, {"glink", 5}, {"gunlink", 7}, #endif /* CHECK_COREUTILS */ {NULL, 0} }; if (!cmd || !*cmd) return 0; static size_t wcmds_n = 0; if (wcmds_n == 0) wcmds_n = (sizeof(wcmds) / sizeof(wcmds[0])) - 1; const size_t clen = strlen(cmd); int i = (int)wcmds_n; while (--i >= 0) { if (clen == wcmds[i].len && *cmd == *wcmds[i].name && strcmp(cmd + 1, wcmds[i].name + 1) == 0) { xerror(_("%s: %s: Command not allowed in read-only mode\n"), PROGRAM_NAME, cmd); return 1; } } return 0; } static int toggle_max_filename_len(const char *arg) { if (arg && IS_HELP(arg)) { puts(KK_USAGE); return FUNC_SUCCESS; } return rl_toggle_max_filename_len(0, 0); } static int toggle_follow_links(const char *arg) { if (arg && IS_HELP(arg)) { puts(K_USAGE); return FUNC_SUCCESS; } if (conf.long_view == 0) { puts(_("k: Not in long view")); return FUNC_SUCCESS; } if (conf.light_mode == 1) { puts(_("k: Feature not available in light mode")); return FUNC_SUCCESS; } conf.follow_symlinks_long = conf.follow_symlinks_long == 1 ? 0 : 1; if (conf.autols == 1) reload_dirlist(); print_reload_msg(NULL, NULL, _("Follow links: %s\n"), conf.follow_symlinks_long == 1 ? _("on") : _("off")); return FUNC_SUCCESS; } /* Handle one of c, m, vv, or paste commands. * Returns -1 if we should not continue, or 0 otherwise. */ static int handle_copy_move_cmds(char ***cmd) { char **args = *cmd; if (!args || !args[0]) return (-1); int copy_and_rename = 0; int use_force = args[1] ? is_force_param(args[1]) : 0; if (args[1] && IS_HELP(args[1])) { puts(args[0][1] == 'v' ? _(VV_USAGE) : _(WRAPPERS_USAGE)); return (-1); } if (args[0][0] != 'm') { /* Either c, vv, or paste commands. */ copy_and_rename = (args[0][1] == 'v'); /* vv command. */ set_cp_cmd(&args[0], &use_force); } else { /* The m command. */ if (sel_is_last == 0 && args[1] && !args[2]) alt_prompt = FILES_PROMPT; /* Interactive rename. */ set_mv_cmd(&args[0], &use_force); } kbind_busy = 1; exit_code = cp_mv_file(args, copy_and_rename, use_force); kbind_busy = 0; return 0; } /* Take the command entered by the user, already splitted into substrings * by parse_input_str(), and call the corresponding function. Return zero * in case of success and one in case of error. * Exit status: EXIT_CODE is zero (success) by default. In case of error * in any of the functions below, it will be set to one (failure). * This will be the value returned by this function. Used by the \z * escape code in the prompt to print the exit status of the last * executed command. */ static int exec_cmd(char **args) { if (zombies > 0) check_zombies(); fputs(df_c, stdout); if (conf.readonly == 1 && is_write_cmd( ((*args[0] == 's' && strcmp(args[0] + 1, "udo") == 0) || (*args[0] == 'd' && strcmp(args[0] + 1, "oas") == 0)) ? args[1] : args[0]) == 1) return FUNC_FAILURE; const int old_exit_code = exit_code; exit_code = FUNC_SUCCESS; int is_internal_command = 1; if (dir_cmds.first_cmd_in_dir == UNSET && dir_cmds.last_cmd_ignored == 0) dir_cmds.first_cmd_in_dir = (int)current_hist_n; /* Remove backslash in front of command names: used to bypass alias names */ if (*args[0] == '\\' && *(args[0] + 1)) remove_backslash(&args[0]); /* Skip comments */ if (check_comments(args[0]) == FUNC_SUCCESS) return FUNC_SUCCESS; /* Warn when using the ',' keyword and there's no pinned file */ if (check_pinned_file(args) == FUNC_FAILURE) return (exit_code = FUNC_FAILURE); /* User defined actions (plugins) */ if ((exit_code = check_actions(args)) != -1) return exit_code; /* User defined variables */ if (flags & IS_USRVAR_DEF) { flags &= ~IS_USRVAR_DEF; return (exit_code = create_usr_var(args[0])); } /* Check if we need to send input directly to the system shell. */ if (*args[0] == ';' || *args[0] == ':') if ((exit_code = launch_shell(args[0])) != -1) return exit_code; /* # AUTOCD & AUTO-OPEN (1) # */ /* rl_dispatching is set to 1 if coming from a keybind: we have a * command, not a filename. So, skip this check. */ if (rl_dispatching == 0 && (exit_code = check_auto_first(args)) != -1) return exit_code; exit_code = FUNC_SUCCESS; /* The more often a function is used, the more on top should it be * in this if...else chain. It will be found faster this way. */ /* #################################################### * # BUILTIN COMMANDS # * ####################################################*/ /* ############### CD ################## */ if (*args[0] == 'c' && args[0][1] == 'd' && !args[0][2]) return (exit_code = chdir_function(args[1])); /* ############### OPEN ################## */ else if (*args[0] == 'o' && (!args[0][1] || strcmp(args[0], "open") == 0)) return (exit_code = open_function(args)); /* ############## BACKDIR ################## */ else if (*args[0] == 'b' && args[0][1] == 'd' && !args[0][2]) return (exit_code = backdir(args[1])); /* ################ OPEN WITH ################## */ else if (*args[0] == 'o' && args[0][1] == 'w' && !args[0][2]) return (exit_code = open_with_function(args)); /* ################ DIRECTORY JUMPER ################## */ else if (*args[0] == 'j' && (!args[0][1] || ((args[0][1] == 'c' || args[0][1] == 'p' || args[0][1] == 'e' || args[0][1] == 'l') && !args[0][2]))) return (exit_code = dirjump(args, NO_SUG_JUMP)); /* ############### REFRESH ################## */ else if (*args[0] == 'r' && ((args[0][1] == 'f' && !args[0][2]) || strcmp(args[0], "refresh") == 0)) return (exit_code = refresh_function(old_exit_code)); /* ################# BOOKMARKS ################## */ else if (*args[0] == 'b' && ((args[0][1] == 'm' && !args[0][2]) || strcmp(args[0], "bookmarks") == 0)) return (exit_code = bookmarks_func(args)); /* ############# BACK, FORTH, and DH (dirhist) ################## */ else if (*args[0] == 'b' && (!args[0][1] || strcmp(args[0], "back") == 0)) return (exit_code = back_function(args)); else if (*args[0] == 'f' && (!args[0][1] || strcmp(args[0], "forth") == 0)) return (exit_code = forth_function(args)); else if (*args[0] == 'd' && args[0][1] == 'h' && !args[0][2]) return (exit_code = dirhist_function(args[1])); /* ############### BULK REMOVE ################## */ else if (*args[0] == 'r' && args[0][1] == 'r' && !args[0][2]) exit_code = bulk_remove(args[1], args[1] ? args[2] : NULL); /* ################# TAGS ################## */ else if (*args[0] == 't' && (((args[0][1] == 'a' || args[0][1] == 'd' || args[0][1] == 'l' || args[0][1] == 'm' || args[0][1] == 'n' || args[0][1] == 'u' || args[0][1] == 'y') && !args[0][2]) || strcmp(args[0], "tag") == 0)) #ifndef _NO_TAGS exit_code = tags_function(args); #else { xerror("%s: tag: %s\n", PROGRAM_NAME, NOT_AVAILABLE); return FUNC_FAILURE; } #endif /* !_NO_TAGS */ /* ################# NEW FILE ###################### */ else if (*args[0] == 'n' && (!args[0][1] || strcmp(args[0], "new") == 0)) exit_code = create_files(args + 1, 0); /* ############### DUPLICATE FILE ################## */ else if (*args[0] == 'd' && (!args[0][1] || strcmp(args[0], "dup") == 0)) exit_code = dup_file(args); /* ################ REMOVE FILES ################### */ else if (*args[0] == 'r' && !args[0][1]) { /* This help is only for c, m, and r commands */ if (args[1] && IS_HELP(args[1])) { puts(_(WRAPPERS_USAGE)); return FUNC_SUCCESS; } exit_code = remove_files(args); } /* ############## CREATE DIRECTORIES ################ */ else if (*args[0] == 'm' && args[0][1] == 'd' && !args[0][2]) { exit_code = create_dirs(args + 1); } /* ############### COPY AND MOVE ################## */ /* Handle c, m, vv, and paste commands */ else if (strcmp(args[0], "c") == 0 || strcmp(args[0], "m") == 0 || strcmp(args[0], "vv") == 0 || strcmp(args[0], "paste") == 0) { if (handle_copy_move_cmds(&args) != 0) return FUNC_SUCCESS; } /* ############# (UN)TRASH ################## */ else if (*args[0] == 't' && (!args[0][1] || strcmp(args[0], "trash") == 0)) { int _cont = 1; exit_code = trash_func(args, &_cont); if (_cont == 0) return exit_code; } else if (*args[0] == 'u' && (!args[0][1] || strcmp(args[0], "undel") == 0 || strcmp(args[0], "untrash") == 0)) { int _cont = 1; /* Tells whether to continue or return right here */ exit_code = untrash_func(args, &_cont); if (_cont == 0) return exit_code; } /* ############### SELECTION ################## */ else if (*args[0] == 's' && (!args[0][1] || strcmp(args[0], "sel") == 0)) { return (exit_code = sel_function(args)); } else if (*args[0] == 's' && (strcmp(args[0], "sb") == 0 || strcmp(args[0], "selbox") == 0)) { list_selected_files(); return FUNC_SUCCESS; } else if (*args[0] == 'd' && (strcmp(args[0], "ds") == 0 || strcmp(args[0], "desel") == 0)) return (exit_code = desel_function(args)); /* ############# CREATE SYMLINK ############### */ else if (*args[0] == 'l' && !args[0][1]) { exit_code = symlink_file(args + 1); goto CHECK_EVENTS; } else if (*args[0] == 'l' && args[0][1] == 'e' && !args[0][2]) { exit_code = edit_link(args[1]); goto CHECK_EVENTS; } /* ########### TOGGLE LONG VIEW ################## */ else if (*args[0] == 'l' && (args[0][1] == 'v' || args[0][1] == 'l') && !args[0][2]) return (exit_code = long_view_function(args[1])); else if (*args[0] == 'k' && args[0][1] == 'k' && !args[0][2]) return (exit_code = toggle_max_filename_len(args[1])); else if (*args[0] == 'k' && !args[0][1]) { return (exit_code = toggle_follow_links(args[1])); } /* ############# PREVIEW FILES ################## */ else if (*args[0] == 'v' && strcmp(args[0], "view") == 0) { #ifndef _NO_LIRA return (exit_code = preview_function(args + 1)); #else fprintf(stderr, "view: %s\n", _(NOT_AVAILABLE)); return FUNC_FAILURE; #endif /* !_NO_LIRA */ } /* ############## TOGGLE EXEC ################## */ else if (*args[0] == 't' && args[0][1] == 'e' && !args[0][2]) return (exit_code = toggle_exec_func(args)); /* ########### OWNERSHIP CHANGER ############### */ else if (*args[0] == 'o' && args[0][1] == 'c' && !args[0][2]) return (exit_code = set_file_owner(args)); /* ########### PERMISSIONS CHANGER ############### */ else if (*args[0] == 'p' && args[0][1] == 'c' && !args[0][2]) return (exit_code = set_file_perms(args)); /* ############### (UN)PIN FILE ################## */ else if (*args[0] == 'p' && strcmp(args[0], "pin") == 0) return (exit_code = pin_function(args[1])); else if (*args[0] == 'u' && strcmp(args[0], "unpin") == 0) return (exit_code = unpin_dir()); /* ############### PROMPT #################### */ else if (*args[0] == 'p' && strcmp(args[0], "prompt") == 0) return (exit_code = prompt_function(args + 1)); /* ############# PROPERTIES ################## */ else if (*args[0] == 'p' && (!args[0][1] || strcmp(args[0], "prop") == 0 || strcmp(args[0], "pp") == 0)) return (exit_code = props_function(args)); /* ############### SEARCH ################## */ else if ( (*args[0] == '/' && is_path(args[0]) == 0) || (*args[0] == '/' && !args[0][1] && args[1] && IS_HELP(args[1])) ) return (exit_code = search_function(args)); /* ############### BATCH LINK ################## */ else if (*args[0] == 'b' && args[0][1] == 'l' && !args[0][2]) exit_code = batch_link(args + 1); /* ############### BULK RENAME ################## */ else if (*args[0] == 'b' && ((args[0][1] == 'r' && !args[0][2]) || strcmp(args[0], "bulk") == 0)) { size_t renamed = 0; exit_code = bulk_rename(args, &renamed, 1); } /* ################ SORT ################## */ else if (*args[0] == 's' && ((args[0][1] == 't' && !args[0][2]) || strcmp(args[0], "sort") == 0)) return (exit_code = sort_func(args)); /* ############ FILENAMES SANITIZER ############## */ else if (*args[0] == 'b' && ((args[0][1] == 'b' && !args[0][2]) || strcmp(args[0], "bleach") == 0)) { #ifndef _NO_BLEACH exit_code = bleach_files(args); #else xerror("%s: bleach: %s\n", PROGRAM_NAME, NOT_AVAILABLE); return FUNC_FAILURE; #endif /* !_NO_BLEACH */ } /* ################ ARCHIVER ################## */ else if (*args[0] == 'a' && ((args[0][1] == 'c' || args[0][1] == 'd') && !args[0][2])) { #ifndef _NO_ARCHIVING if (!args[1] || IS_HELP(args[1])) { puts(_(ARCHIVE_USAGE)); return FUNC_SUCCESS; } /* Either 'c' or 'd' */ exit_code = archiver(args, args[0][1]); #else xerror("%s: archiver: %s\n", PROGRAM_NAME, _(NOT_AVAILABLE)); return FUNC_FAILURE; #endif /* !_NO_ARCHIVING */ } /* ################################################## * # MINOR FUNCTIONS # * ##################################################*/ else if (*args[0] == 'w' && args[0][1] == 's' && !args[0][2]) return (exit_code = handle_workspaces(args + 1)); else if (*args[0] == 's' && strcmp(args[0], "stats") == 0) return (exit_code = print_stats()); else if (*args[0] == 'f' && ((args[0][1] == 't' && !args[0][2]) || strcmp(args[0], "filter") == 0)) return (exit_code = filter_function(args[1])); else if (*args[0] == 'a' && strcmp(args[0], "auto") == 0) return (exit_code = add_autocmd(args + 1)); else if (*args[0] == 'f' && args[0][1] == 'z' && !args[0][2]) return (exit_code = toggle_full_dir_size(args[1])); else if (*args[0] == 'c' && ((args[0][1] == 'l' && !args[0][2]) || strcmp(args[0], "columns") == 0)) return (exit_code = columns_function(args[1])); else if (*args[0] == 'i' && strcmp(args[0], "icons") == 0) return (exit_code = icons_function(args[1])); else if (*args[0] == 'c' && ((args[0][1] == 's' && !args[0][2]) || strcmp(args[0], "colorschemes") == 0)) return (exit_code = cschemes_function(args)); else if (*args[0] == 'k' && ((args[0][1] == 'b' && !args[0][2]) || strcmp(args[0], "keybinds") == 0)) return (exit_code = kbinds_function(args)); else if (*args[0] == 'e' && strcmp(args[0], "exp") == 0) return (exit_code = export_files_function(args)); else if (*args[0] == 'o' && strcmp(args[0], "opener") == 0) return (exit_code = opener_function(args[1])); else if (*args[0] == 't' && strcmp(args[0], "tips") == 0) { print_tips(1); return FUNC_SUCCESS; } else if (*args[0] == 'a' && strcmp(args[0], "actions") == 0) return (exit_code = actions_function(args)); else if (*args[0] == 'l' && args[0][1] == 'm' && !args[0][2]) return (exit_code = lightmode_function(args[1])); else if (*args[0] == 'r' && ((args[0][1] == 'l' && !args[0][2]) || strcmp(args[0], "reload") == 0)) return (exit_code = config_reload(args[1])); /* #### NEW INSTANCE #### */ else if ((*args[0] == 'x' || *args[0] == 'X') && !args[0][1]) return (exit_code = new_instance_function(args)); /* #### NET #### */ else if (*args[0] == 'n' && (strcmp(args[0], "net") == 0)) return (exit_code = remotes_function(args)); /* #### MIME #### */ else if (*args[0] == 'm' && ((args[0][1] == 'm' && !args[0][2]) || strcmp(args[0], "mime") == 0)) return (exit_code = lira_function(args)); else if (conf.autols == 0 && *args[0] == 'l' && args[0][1] == 's' && !args[0][2]) return (exit_code = ls_function()); /* #### PROFILE #### */ else if (*args[0] == 'p' && ((args[0][1] == 'f' && !args[0][2]) || strcmp(args[0], "profile") == 0)) #ifndef _NO_PROFILES return (exit_code = profile_function(args)); #else { xerror("%s: profiles: %s\n", PROGRAM_NAME, NOT_AVAILABLE); return FUNC_FAILURE; } #endif /* !_NO_PROFILES */ /* #### MOUNTPOINTS #### */ else if (*args[0] == 'm' && ((args[0][1] == 'p' && !args[0][2]) || strcmp(args[0], "mountpoints") == 0)) { #ifndef NO_MEDIA_FUNC return (exit_code = media_function(args[1], MEDIA_LIST)); #else fputs(_("mountpoints: Function not available\n"), stderr); return FUNC_FAILURE; #endif /* NO_MEDIA_FUNC */ } /* #### MEDIA #### */ else if (*args[0] == 'm' && strcmp(args[0], "media") == 0) { #ifndef NO_MEDIA_FUNC return (exit_code = media_function(args[1], MEDIA_MOUNT)); #else fputs(_("media: Function not available\n"), stderr); return FUNC_FAILURE; #endif /* NO_MEDIA_FUNC */ } /* #### MAX FILES #### */ else if (*args[0] == 'm' && args[0][1] == 'f' && !args[0][2]) return set_max_files(args); /* #### EXT #### */ else if (*args[0] == 'e' && args[0][1] == 'x' && args[0][2] == 't' && !args[0][3]) return (exit_code = ext_cmds_function(args[1])); /* #### PAGER #### */ else if (*args[0] == 'p' && ((args[0][1] == 'g' && !args[0][2]) || strcmp(args[0], "pager") == 0)) return (exit_code = pager_function(args[1])); /* #### FILE COUNTER #### */ else if (*args[0] == 'f' && ((args[0][1] == 'c' && !args[0][2]) || strcmp(args[0], "filecounter") == 0)) return (exit_code = file_counter_function(args[1])); /* #### DIRECTORIES FIRST #### */ else if ((*args[0] == 'f' && args[0][1] == 'f' && !args[0][2]) || (*args[0] == 'd' && strcmp(args[0], "dirs-first") == 0)) return (exit_code = dirs_first_function(args[1])); /* #### LOG #### */ else if (*args[0] == 'l' && strcmp(args[0], "log") == 0) return (exit_code = run_log_cmd(args + 1)); /* #### MESSAGES #### */ else if (*args[0] == 'm' && (strcmp(args[0], "msg") == 0 || strcmp(args[0], "messages") == 0)) return (exit_code = msgs_function(args[1])); /* #### ALIASES #### */ else if (*args[0] == 'a' && strcmp(args[0], "alias") == 0) return (exit_code = alias_function(args)); /* #### CONFIG #### */ else if (*args[0] == 'c' && strcmp(args[0], "config") == 0) return (exit_code = config_edit(args)); /* #### HISTORY #### */ else if (*args[0] == 'h' && strcmp(args[0], "history") == 0) return (exit_code = history_function(args)); /* #### HIDDEN FILES #### */ else if (*args[0] == 'h' && (((args[0][1] == 'f' || args[0][1] == 'h') && !args[0][2]) || strcmp(args[0], "hidden") == 0)) return (exit_code = hidden_files_function(args[1])); /* #### AUTOCD #### */ else if (*args[0] == 'a' && (strcmp(args[0], "acd") == 0 || strcmp(args[0], "autocd") == 0)) return (exit_code = autocd_function(args[1])); /* #### AUTO-OPEN #### */ else if (*args[0] == 'a' && ((args[0][1] == 'o' && !args[0][2]) || strcmp(args[0], "auto-open") == 0)) return (exit_code = auto_open_function(args[1])); /* #### COMMANDS #### */ else if (*args[0] == 'c' && (strcmp(args[0], "cmd") == 0 || strcmp(args[0], "commands") == 0)) return (exit_code = list_commands()); /* #### PATH, CWD #### */ else if ((*args[0] == 'p' && (strcmp(args[0], "pwd") == 0 || strcmp(args[0], "path") == 0)) || strcmp(args[0], "cwd") == 0) { return (exit_code = pwd_function(args[1])); } /* #### HELP #### */ else if ((*args[0] == '?' && !args[0][1]) || strcmp(args[0], "help") == 0) { return (exit_code = quick_help(args[1])); } /* #### EXPORT #### */ else if (*args[0] == 'e' && strcmp(args[0], "export") == 0) { return (exit_code = export_var_function(args + 1)); } /* #### UMASK #### */ else if (*args[0] == 'u' && strcmp(args[0], "umask") == 0) { return (exit_code = umask_function(args[1])); } /* #### UNSET #### */ else if (*args[0] == 'u' && strcmp(args[0], "unset") == 0) { return (exit_code = unset_function(args + 1)); } /* These functions just print stuff, so that the value of exit_code * is always zero, that is to say, success. */ else if (*args[0] == 'c' && strcmp(args[0], "colors") == 0) { colors_function(args[1]); return FUNC_SUCCESS; } else if (*args[0] == 'v' && (strcmp(args[0], "ver") == 0 || strcmp(args[0], "version") == 0)) { version_function(1); return FUNC_SUCCESS; } else if (*args[0] == 'b' && strcmp(args[0], "bonus") == 0) { bonus_function(); return FUNC_SUCCESS; } /* #### QUIT #### */ else if ((*args[0] == 'q' && (!args[0][1] || strcmp(args[0], "quit") == 0)) || (*args[0] == 'e' && strcmp(args[0], "exit") == 0)) quit_func(args, old_exit_code); else { /* # AUTOCD & AUTO-OPEN (2) # */ if ((exit_code = check_auto_second(args)) != -1) return exit_code; /* # EXTERNAL/SHELL COMMANDS # */ if ((exit_code = run_shell_cmd(args)) == FUNC_FAILURE) return FUNC_FAILURE; else is_internal_command = 0; } CHECK_EVENTS: if (conf.autols == 0 || (is_internal_command == 0 && conf.clear_screen == CLEAR_INTERNAL_CMD_ONLY)) return exit_code; #if defined(LINUX_INOTIFY) if (watch) read_inotify(); #elif defined(BSD_KQUEUE) if (watch && event_fd >= 0) read_kqueue(); #elif defined(GENERIC_FS_MONITOR) check_fs_changes(); #endif /* LINUX_INOTIFY */ return exit_code; } /* Run the command CMD and, if the '\b' prompt code is used, store execution * time in last_cmd_time (global). */ int exec_cmd_tm(char **cmd) { struct timespec begin, end; int reta = -1; if (conf.prompt_b_is_set == 1) reta = clock_gettime(CLOCK_REALTIME, &begin); const int ret = exec_cmd(cmd); if (conf.prompt_b_is_set == 1) { const int retb = clock_gettime(CLOCK_REALTIME, &end); if (reta == -1 || retb == -1) { last_cmd_time = 0.0; return ret; } last_cmd_time = (double)(end.tv_nsec - begin.tv_nsec) / 1000000000.0 + (double)(end.tv_sec - begin.tv_sec); } return ret; } static void run_chained_cmd(char **cmd, size_t *err_code) { size_t i; char **alias_cmd = check_for_alias(cmd); if (alias_cmd) { if (exec_cmd_tm(alias_cmd) != 0) *err_code = 1; for (i = 0; alias_cmd[i]; i++) free(alias_cmd[i]); free(alias_cmd); } else { if ((flags & FAILED_ALIAS) || exec_cmd_tm(cmd) != 0) *err_code = 1; flags &= ~FAILED_ALIAS; for (i = 0; i <= args_n; i++) free(cmd[i]); free(cmd); } } /* Execute chained commands (cmd1;cmd2 and/or cmd1 && cmd2). The function * is called by parse_input_str() if some non-quoted double ampersand or * semicolon is found in the input string AND at least one of these * chained commands is internal */ void exec_chained_cmds(char *cmd) { if (!cmd) return; size_t i = 0; const size_t cmd_len = strlen(cmd); for (i = 0; i < cmd_len; i++) { char *str = (char *)NULL; size_t len = 0, cond_exec = 0, error_code = 0; /* Get command */ str = xcalloc(strlen(cmd) + 1, sizeof(char)); while (cmd[i] && cmd[i] != '&' && cmd[i] != ';') { str[len] = cmd[i]; len++; i++; } if (!*str) { free(str); continue; } if (cmd[i] == '&') cond_exec = 1; char **tmp_cmd = parse_input_str((*str == ' ') ? str + 1 : str); free(str); if (!tmp_cmd) continue; run_chained_cmd(tmp_cmd, &error_code); /* Do not continue if the execution was condtional and * the previous command failed. */ if (cond_exec == 1 && error_code == 1) break; } } static void run_profile_line(char *cmd) { if (xargs.secure_cmds == 1 && sanitize_cmd(cmd, SNT_PROFILE) != FUNC_SUCCESS) return; args_n = 0; char **cmds = parse_input_str(cmd); if (!cmds) return; no_log = 1; exec_cmd(cmds); no_log = 0; int i = (int)args_n + 1; while (--i >= 0) free(cmds[i]); free(cmds); args_n = 0; } void exec_profile(void) { if (config_ok == 0 || !profile_file) return; FILE *fp = fopen(profile_file, "r"); if (!fp) return; size_t line_size = 0; char *line = (char *)NULL; ssize_t line_len = 0; while ((line_len = getline(&line, &line_size, fp)) > 0) { if (!*line || *line == '\n' || *line == '#') continue; if (line[line_len - 1] == '\n') line[line_len - 1] = '\0'; if (conf.int_vars == 1 && strchr(line, '=') && !IS_DIGIT(*line)) create_usr_var(line); else run_profile_line(line); } free(line); fclose(fp); } clifm-1.26.3/src/exec.h000066400000000000000000000020431506632037700145710ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* exec.h */ #ifndef EXEC_H #define EXEC_H __BEGIN_DECLS int exec_cmd_tm(char **cmd); void exec_chained_cmds(char *cmd); void exec_profile(void); __END_DECLS #endif /* EXEC_H */ clifm-1.26.3/src/file_operations.c000066400000000000000000001532551506632037700170360ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* file_operations.c -- control multiple file operations */ /* path_common_prefix(), append_to_buf(), and relpath() were taken from * GNU coreutils (2024), licensed GPL3+, and modified to fit our needs. * Modified code is licensed GPL2+. */ #include "helpers.h" #include #include #include #include #ifdef __TINYC__ # undef CHAR_MAX /* Silence redefinition error */ #endif /* __TINYC__ */ #include "aux.h" /* gen_default_answer() */ #include "checks.h" #include "colors.h" #include "file_operations.h" #include "history.h" #include "init.h" /* get_sel_files() */ #include "listing.h" #include "messages.h" #include "mime.h" #include "misc.h" #include "navigation.h" #include "readline.h" #include "selection.h" #include "spawn.h" /* Struct to store information about files to be removed via the 'r' command. */ struct rm_info { char *name; nlink_t links; #if defined(__sun) || defined(__OpenBSD__) || defined(__DragonFly__) \ || defined(__NetBSD__) || defined(__HAIKU__) int pad0; #endif /* __sun || __OpenBSD__ || __DragonFly__ || __NetBSD__ || __HAIKU__ */ time_t mtime; ino_t ino; dev_t dev; int dir; int exists; #if defined(__OpenBSD__) || defined(__DragonFly__) || defined(__HAIKU__) int pad1; #endif /* __OpenBSD__ || __DragonFly__ || __HAIKU__ */ }; static char *const unsafe_name_msgs[] = { "Starts with a dash (-): command option flags collision", "Reserved (internal: MIME/file type expansion)", "Reserved (internal: ELN/range expansion)", "Reserved (internal: fastback expansion)", "Reserved (internal: bookmarks, tags, and selected files constructs)", "Reserved shell/system keyword", "Contains control characters", "Contains shell meta-characters", "Too long", "Contains characters not in the Portable Filename Character Set" }; #ifdef _BE_POSIX # define PORTABLE_CHARSET "abcdefghijklmnopqrstuvwxyz\ ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-_" /* Return 0 if NAME is a portable filename. Otherwise, return 1. */ static int is_portable_filename(const char *name, const size_t len) { return len > strspn(name, PORTABLE_CHARSET); } #endif /* _BE_POSIX */ /* Print/set the file creation mode mask (umask). */ int umask_function(const char *arg) { if (!arg) { const mode_t old_umask = umask(0); /* flawfinder: ignore */ /* umask is set to zero, and then changed back, only to get the * current value. */ printf("%04o\n", old_umask); umask(old_umask); /* flawfinder: ignore */ return FUNC_SUCCESS; } if (IS_HELP(arg)) { puts(UMASK_USAGE); return FUNC_SUCCESS; } if (!IS_DIGIT(*arg) || !is_number(arg)) goto ERROR; int new_umask = octal2int(arg); if (new_umask < 0 || new_umask > MAX_UMASK) goto ERROR; umask((mode_t)new_umask); /* flawfinder: ignore */ printf(_("File-creation mask set to '%04o'\n"), new_umask); return FUNC_SUCCESS; ERROR: xerror(_("umask: %s: Out of range (valid values are 000-777)\n"), arg); return FUNC_FAILURE; } #ifndef _NO_LIRA static int run_mime(char *file) { if (!file || !*file) return FUNC_FAILURE; if (xargs.preview == 1 || xargs.open == 1) goto RUN; char *p = rl_line_buffer ? rl_line_buffer : (char *)NULL; /* Convert ELN into filename (rl_line_buffer) */ if (p && *p >= '1' && *p <= '9') { const filesn_t a = xatof(p); if (a > 0 && a <= files && file_info[a - 1].name) p = file_info[a - 1].name; } if (p && ( (*p == 'i' && (strncmp(p, "import", 6) == 0 || strncmp(p, "info", 4) == 0)) || (*p == 'o' && (p[1] == ' ' || strncmp(p, "open", 4) == 0)) ) ) { char *cmd[] = {"mm", "open", file, NULL}; return mime_open(cmd); } RUN: { char *cmd[] = {"mm", file, NULL}; return mime_open(cmd); } } #endif /* _NO_LIRA */ /* Open a file via OPENER, if set, or via LIRA. If not compiled with * Lira support, fallback to open (Haiku), or xdg-open. Returns zero * on success or one on failure. */ int open_file(char *file) { if (!file || !*file) return FUNC_FAILURE; int ret = FUNC_SUCCESS; if (conf.opener) { if (*conf.opener == 'g' && strcmp(conf.opener, "gio") == 0) { char *cmd[] = {"gio", "open", file, NULL}; ret = launch_execv(cmd, FOREGROUND, E_NOFLAG); } else { char *cmd[] = {conf.opener, file, NULL}; ret = launch_execv(cmd, FOREGROUND, E_NOFLAG); } } else { #ifndef _NO_LIRA ret = run_mime(file); #else /* Fallback to (xdg-)open */ # if defined(__HAIKU__) char *cmd[] = {"open", file, NULL}; # elif defined(__APPLE__) char *cmd[] = {"/usr/bin/open", file, NULL}; # else char *cmd[] = {"xdg-open", file, NULL}; # endif /* __HAIKU__ */ ret = launch_execv(cmd, FOREGROUND, E_NOFLAG); #endif /* _NO_LIRA */ } return ret; } int xchmod(const char *file, const char *mode_str, const int flag) { if (!file || !*file) { err(flag == 1 ? 'e' : 0, flag == 1 ? PRINT_PROMPT : NOPRINT_PROMPT, _("xchmod: Empty buffer for filename\n")); return FUNC_FAILURE; } if (!mode_str || !*mode_str) { err(flag == 1 ? 'e' : 0, flag == 1 ? PRINT_PROMPT : NOPRINT_PROMPT, _("xchmod: Empty buffer for mode\n")); return FUNC_FAILURE; } const int fd = open(file, O_RDONLY); if (fd == -1) { err(flag == 1 ? 'e' : 0, flag == 1 ? PRINT_PROMPT : NOPRINT_PROMPT, "xchmod: '%s': %s\n", file, strerror(errno)); return errno; } const mode_t mode = (mode_t)strtol(mode_str, 0, 8); if (fchmod(fd, mode) == -1) { close(fd); err(flag == 1 ? 'e' : 0, flag == 1 ? PRINT_PROMPT : NOPRINT_PROMPT, "xchmod: '%s': %s\n", file, strerror(errno)); return errno; } close(fd); return FUNC_SUCCESS; } /* Toggle executable bits on the file named FILE. */ int toggle_exec(const char *file, mode_t mode) { /* Set it only for owner, unset it for every one else. */ (0100 & mode) ? (mode &= (mode_t)~0111) : (mode |= 0100); if (fchmodat(XAT_FDCWD, file, mode, 0) == -1) { xerror(_("te: Changing permissions of '%s': %s\n"), file, strerror(errno)); return FUNC_FAILURE; } return FUNC_SUCCESS; } static char * get_dup_file_dest_dir(void) { char *dir = (char *)NULL; puts(_("Enter destination directory (Ctrl+d to quit)\n" "Tip: \".\" for the current directory")); char n_prompt[NAME_MAX]; snprintf(n_prompt, sizeof(n_prompt), "\001%s\002>\001%s\002 ", mi_c, tx_c); while (!dir) { int quoted = 0; dir = get_newname(n_prompt, (char *)NULL, "ed); UNUSED(quoted); if (!dir) /* The user pressed ctrl+d */ return (char *)NULL; /* Expand ELN */ if (IS_DIGIT(*dir) && is_number(dir)) { const int n = atoi(dir); if (n > 0 && (filesn_t)n <= files) { free(dir); char *name = file_info[n - 1].name; dir = savestring(name, strlen(name)); } } else if (*dir == '~') { /* Expand tilde */ char *tmp = tilde_expand(dir); if (tmp) { free(dir); dir = tmp; } } /* Check if file exists, is a directory, and user has access */ struct stat a; errno = 0; if (stat(dir, &a) == -1) { goto ERROR; } else if (!S_ISDIR(a.st_mode)) { errno = ENOTDIR; goto ERROR; } else if (check_file_access(a.st_mode, a.st_uid, a.st_gid) == 0) { errno = EACCES; goto ERROR; } break; ERROR: xerror("dup: '%s': %s\n", dir, strerror(errno)); free(dir); dir = (char *)NULL; } return dir; } int dup_file(char **cmd) { if (!cmd[1] || IS_HELP(cmd[1])) { puts(_(DUP_USAGE)); return FUNC_SUCCESS; } char *dest_dir = get_dup_file_dest_dir(); if (!dest_dir) return FUNC_SUCCESS; size_t dlen = strlen(dest_dir); if (dlen > 1 && dest_dir[dlen - 1] == '/') { dest_dir[dlen - 1] = '\0'; dlen--; } const int rsync_ok = is_cmd_in_path("rsync"); int exit_status = FUNC_SUCCESS; size_t i; for (i = 1; cmd[i]; i++) { if (!cmd[i] || !*cmd[i]) continue; /* 1. Construct filenames. */ char *source = cmd[i]; if (strchr(source, '\\')) { char *deq_str = unescape_str(source, 0); if (!deq_str) { xerror(_("dup: '%s': Error unescaping filename\n"), source); continue; } xstrsncpy(source, deq_str, strlen(deq_str) + 1); free(deq_str); } /* Use source as destination filename: source.copy, and, if already * exists, source.copy-n, where N is an integer greater than zero. */ const size_t source_len = strlen(source); int rem_slash = 0; if (strcmp(source, "/") != 0 && source_len > 0 && source[source_len - 1] == '/') { source[source_len - 1] = '\0'; rem_slash = 1; } char *tmp = strrchr(source, '/'); char *source_name; source_name = (tmp && *(tmp + 1)) ? tmp + 1 : source; char tmp_dest[PATH_MAX + 1]; if (*dest_dir == '/' && !dest_dir[1]) /* Root dir */ snprintf(tmp_dest, sizeof(tmp_dest), "/%s.copy", source_name); else snprintf(tmp_dest, sizeof(tmp_dest), "%s/%s.copy", dest_dir, source_name); char bk[PATH_MAX + 11]; xstrsncpy(bk, tmp_dest, sizeof(bk)); struct stat attr; size_t suffix = 1; while (stat(bk, &attr) == FUNC_SUCCESS) { snprintf(bk, sizeof(bk), "%s-%zu", tmp_dest, suffix); suffix++; } char *dest = savestring(bk, strnlen(bk, sizeof(bk))); if (rem_slash == 1) source[source_len - 1] = '/'; /* 2. Run command. */ if (rsync_ok == 1) { char *dup_cmd[] = {"rsync", "-aczvAXHS", "--progress", "--", source, dest, NULL}; if (launch_execv(dup_cmd, FOREGROUND, E_NOFLAG) != FUNC_SUCCESS) exit_status = FUNC_FAILURE; } else { #ifdef _BE_POSIX char *dup_cmd[] = {"cp", "--", source, dest, NULL}; #elif defined(__sun) int g = (bin_flags & BSD_HAVE_COREUTILS); char *name = g ? "gcp" : "cp"; char *opt = g ? "-a" : "--"; char *dup_cmd[] = {name, opt, g ? "--" : source, g ? source : dest, g ? dest : NULL, NULL}; #else char *dup_cmd[] = {"cp", "-a", "--", source, dest, NULL}; #endif /* _BE_POSIX */ if (launch_execv(dup_cmd, FOREGROUND, E_NOFLAG) != FUNC_SUCCESS) exit_status = FUNC_FAILURE; } free(dest); } free(dest_dir); return exit_status; } static int err_file_exists(char *name, const int multi, const int is_md) { char *n = abbreviate_file_name(name); char *p = n ? n : name; xerror("%s: '%s': %s\n", is_md ? "md" : "new", (*p == '.' && p[1] == '/' && p[2]) ? p + 2 : p, strerror(EEXIST)); if (n && n != name) free(n); if (multi == 1) press_any_key_to_continue(0); return FUNC_FAILURE; } static char * extract_template_name_from_filename(char *basename, int *t_auto) { /* Explicit template name: file@template */ char *tname = strrchr(basename, '@'); if (tname && tname != basename && tname[1]) { *t_auto = 0; return tname + 1; } /* Automatic template (taken from file extension). */ *t_auto = 1; tname = strrchr(basename, '.'); if (tname && tname != basename && tname[1]) return tname + 1; return (char *)NULL; } /* Return 1 if the template NAME is found in the templates list, * or 0 otherwise. */ static int find_template(const char *name) { if (!file_templates) return 0; filesn_t i; for (i = 0; file_templates[i]; i++) { if (*name == *file_templates[i] && strcmp(name, file_templates[i]) == 0) return 1; } return 0; } /* Create the file show absolute path is ABS_PATH, and whose basename is * BASENAME, from the corresponing template. * Returns 1 in case of success, 0 in there's no template for this file * (or cp(1) fails), or -1 in case of error. */ static int create_from_template(char *abs_path, char *basename) { if (!file_templates || !templates_dir || !*templates_dir || !abs_path || !*abs_path || !basename || !*basename) return 0; int t_auto = 1; const char *t_name = extract_template_name_from_filename(basename, &t_auto); if (!t_name) return 0; if (find_template(t_name) == 0) { if (t_auto == 0) { xerror(_("new: '%s': No such template\n"), t_name); return (-1); } return 0; } if (t_auto == 0) { /* src_file@template: Remove template name from source filename. */ char *p = strrchr(abs_path, '@'); if (p) *p = '\0'; } char template_file[PATH_MAX + 1]; snprintf(template_file, sizeof(template_file), "%s/%s", templates_dir, t_name); struct stat a; if (lstat(template_file, &a) == -1 || !S_ISREG(a.st_mode)) return 0; if (lstat(abs_path, &a) != -1) { err_file_exists(abs_path, 0, 0); return (-1); } char *cmd[] = {"cp", "--", template_file, abs_path, NULL}; /* Let's copy the template file. STDERR and STDOUT are silenced: in case * of error, we'll try to create a plain empty regular file via open(2) * and print the error message in case of failure. */ const int ret = launch_execv(cmd, FOREGROUND, E_MUTE); return (ret == 0); } /* Create the file named NAME, as a directory, if ending wit a slash, or as * a regular file otherwise. * Parent directories are created if they do not exist. * Returns FUNC_SUCCESS on success or FUNC_FAILURE on error. */ static int create_file(char *name, const int is_md) { struct stat a; char *ret = (char *)NULL; char *n = name; char *errname = is_md == 1 ? "md" : "new"; int status = FUNC_SUCCESS; /* Dir creation mode (777, or 700 if running in secure-mode). mkdir(3) will * modify this according to the current umask value. */ mode_t mode = (xargs.secure_env == 1 || xargs.secure_env_full == 1) ? S_IRWXU : S_IRWXU | S_IRWXG | S_IRWXO; if (*n == '/') /* Skip root dir. */ n++; /* Recursively create parent dirs (and dir itself if basename is a dir). */ while ((ret = strchr(n, '/'))) { *ret = '\0'; if (lstat(name, &a) != -1) /* dir exists */ goto CONT; errno = 0; if (mkdirat(XAT_FDCWD, name, mode) == -1) { xerror("%s: '%s': %s\n", errname, name, strerror(errno)); status = FUNC_FAILURE; break; } CONT: *ret = '/'; n = ret + 1; } if (*n && status != FUNC_FAILURE) { /* Regular file */ const int retval = create_from_template(name, n); if (retval != 0) { if (retval == -1) // file@template: No such template, or destination file exists status = FUNC_FAILURE; goto END; } /* Regular file creation mode (666, or 600 in secure-mode). open(2) * will modify this according to the current umask value. */ if (xargs.secure_env == 1 || xargs.secure_env_full == 1) mode = S_IRUSR | S_IWUSR; else mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; const int fd = open(name, O_WRONLY | O_CREAT | O_EXCL, mode); if (fd == -1) { xerror("%s: '%s': %s\n", errname, name, strerror(errno)); status = FUNC_FAILURE; } else { close(fd); } } END: return status; } static void list_created_files(char **nfiles, const filesn_t nfiles_n) { size_t i; int file_in_cwd = 0; filesn_t n = workspaces[cur_ws].path ? count_dir(workspaces[cur_ws].path, NO_CPOP) - 2 : 0; if (n > 0 && n > files) file_in_cwd = 1; if (conf.autols == 1 && file_in_cwd == 1) reload_dirlist(); for (i = 0; nfiles[i]; i++) { char *f = abbreviate_file_name(nfiles[i]); char *p = f ? f : nfiles[i]; puts((*p == '.' && p[1] == '/' && p[2]) ? p + 2 : p); if (f && f != nfiles[i]) free(f); } print_reload_msg(SET_SUCCESS_PTR, xs_cb, _("%zu file(s) created\n"), (size_t)nfiles_n); } static int is_range(const char *str) { if (!str || !*str) return 0; char *dash = strchr(str, '-'); if (!dash) return 0; *dash = '\0'; if (is_number(str) && (!dash[1] || is_number(dash + 1))) { *dash = '-'; return 1; } *dash = '-'; return 0; } static int print_val_err(const char *name, const int msg_type) { printf("%s: %s\n", name, unsafe_name_msgs[msg_type]); return 0; } /* Return 1 if NAME is a safe filename, or 0 if not. * See https://dwheeler.com/essays/fixing-unix-linux-filenames.html */ static int is_valid_filename(const char *name) { const char *n = name; /* Trailing spaces were already removed (by get_newname()) */ /* Starting with dash */ if (*n == '-') return print_val_err(name, UNSAFE_DASH); /* Reserved keyword (internal: MIME type and file type expansions) */ if ((*n == '=' && n[1] >= 'a' && n[1] <= 'z' && !n[2]) || *n == '@') return print_val_err(name, UNSAFE_MIME); /* Reserved keyword (internal: bookmarks, tags, workspaces, and * selected files constructs) */ if (((*n == 'b' || *n == 's') && n[1] == ':') || strcmp(n, "sel") == 0) return print_val_err(name, UNSAFE_BTS_CONST); if ((*n == 't' || *n == 'w') && n[1] == ':' && n[2]) return print_val_err(name, UNSAFE_BTS_CONST); /* Reserved (internal: ELN/range expansion) */ if ((*n > '0' && is_number(n)) || is_range(n)) return print_val_err(name, UNSAFE_ELN); /* "~" or ".": Reserved keyword */ if ((*n == '~' || *n == '.') && !n[1]) return print_val_err(name, UNSAFE_SYS_KEY); /* ".." or "./": Reserved keyword */ if (*n == '.' && (n[1] == '.' || n[1] == '/') && !n[2]) return print_val_err(name, UNSAFE_SYS_KEY); int only_dots = 1; const char *s = name; while (*s) { /* Contains control characters (being not UTF-8 bytes) */ if (*s < ' ' && !IS_UTF8_CHAR(*s)) return print_val_err(name, UNSAFE_CONTROL); /* Contains shell meta-characters */ if (strchr("*?[]<>|(){}&=`^!\\;$", *s)) return print_val_err(name, UNSAFE_META); /* Only dots: Reserved keyword (internal: fastback expansion) */ if (*s != '.') only_dots = 0; s++; } if (only_dots == 1) return print_val_err(name, UNSAFE_FASTBACK); /* Name too long */ if (s - name >= NAME_MAX) return print_val_err(name, UNSAFE_TOO_LONG); #ifdef _BE_POSIX if (is_portable_filename(name, (size_t)(s - name)) != FUNC_SUCCESS) return print_val_err(name, UNSAFE_NOT_PORTABLE); #endif /* _BE_POSIX */ return 1; } /* Return 0 if the file path NAME (or any component in it) does not exist and * is an invalid name. Otherwise, it returns 1. * If NAME is escaped, it is replaced by the unescaped name. */ static int validate_filename(char **name, const int is_md) { if (!*name || !*(*name)) return 0; char *deq = unescape_str(*name, 0); if (!deq) { xerror(_("%s: '%s': Error unescaping filename\n"), is_md ? "md" : "new", *name); return 0; } free(*name); *name = deq; /* Skip initial slash and "~/" */ char *tmp = *deq != '/' ? deq : deq + 1; if (*tmp == '~' && tmp[1] == '/' && tmp[2]) tmp += 2; char *p = tmp, *q = tmp; struct stat a; int ret = 1; while (1) { if (!*q) { /* Basename */ if (lstat(deq, &a) == -1) ret = is_valid_filename(p); break; } if (*q != '/') goto NEXT; /* Path component */ *q = '\0'; if (lstat(deq, &a) == -1 && (ret = is_valid_filename(p)) == 0) { *q = '/'; break; } *q = '/'; if (!q[1]) break; p = q + 1; NEXT: ++q; } return ret; } static int format_new_filename(char **name) { char *p = *name; if (*(*name) == '\'' || *(*name) == '"') p = remove_quotes(*name); if (!p || !*p) return FUNC_FAILURE; const size_t flen = strlen(p); const int is_dir = (flen > 1 && p[flen - 1] == '/'); if (is_dir == 1) p[flen - 1 ] = '\0'; /* Remove ending slash */ char *npath = (char *)NULL; if (p == *name) { char *tilde = *p == '~' ? tilde_expand(p) : NULL; const size_t len = tilde ? strlen(tilde) : flen; npath = normalize_path(tilde ? tilde : p, len); free(tilde); } else { /* Quoted string. Copy it verbatim. */ npath = savestring(p, flen); } if (!npath) return FUNC_FAILURE; const size_t name_len = strlen(npath) + 2; *name = xnrealloc(*name, name_len, sizeof(char)); snprintf(*name, name_len, "%s%c", npath, is_dir == 1 ? '/' : 0); free(npath); return FUNC_SUCCESS; } /* Ask the user for a new filename and create the file. */ static int ask_and_create_file(void) { puts(_("Enter new filename (Ctrl+d to quit)\n" "Tip: End name with a slash to create a directory")); char n_prompt[NAME_MAX]; snprintf(n_prompt, sizeof(n_prompt), "\001%s\002>\001%s\002 ", mi_c, tx_c); int quoted = 0; char *filename = get_newname(n_prompt, (char *)NULL, "ed); if (!filename) /* The user pressed Ctrl+d */ return FUNC_SUCCESS; if (validate_filename(&filename, 0) == 0) { xerror(_("new: '%s': Unsafe filename\n"), filename); if (rl_get_y_or_n(_("Continue?"), 0) == 0) { free(filename); return FUNC_SUCCESS; } } int exit_status = quoted == 0 ? format_new_filename(&filename) : FUNC_SUCCESS; if (exit_status != FUNC_SUCCESS) goto ERROR; struct stat a; if (lstat(filename, &a) == 0) { exit_status = err_file_exists(filename, 0, 0); goto ERROR; } exit_status = create_file(filename, 0); if (exit_status == FUNC_SUCCESS) { char *args[] = { filename, (char *)NULL }; list_created_files(args, 1); } ERROR: free(filename); return exit_status; } /* (l)stat(2), just as access(2), sees "file" and "file/" as different * filenames. So, let's check the existence of the file FILE ignoring the * trailing slash, if any. */ static int check_file_existence(char *file) { int s = 0; const size_t l = strlen(file); if (l > 1 && file[l - 1] == '/') { file[l - 1] = '\0'; s = 1; } struct stat a; const int ret = lstat(file, &a); if (s == 1) file[l - 1] = '/'; return ret; } /* Create files as specified in ARGS: as directories (if ending with slash) * or as regular files otherwise. If coming from 'md' command, IS_MD is set to * 1 (so that we can fail as such). */ int create_files(char **args, const int is_md) { if (args[0] && IS_HELP(args[0])) { puts(_(NEW_USAGE)); return FUNC_SUCCESS; } int exit_status = FUNC_SUCCESS; size_t i; /* If no argument provided, ask the user for a filename, create it and exit. */ if (!args[0]) /* This function is never executed by 'md', but always by 'n'. */ return ask_and_create_file(); size_t argsn; for (argsn = 0; args[argsn]; argsn++); /* Store pointers to actually created files in a pointers array. * We'll use this later to print the names of actually created files. */ char **new_files = xnmalloc(argsn + 1, sizeof(char *)); filesn_t new_files_n = 0; for (i = 0; args[i]; i++) { if (validate_filename(&args[i], is_md) == 0) { xerror(_("%s: '%s': Unsafe filename\n"), is_md ? "md" : "new", args[i]); if (rl_get_y_or_n(_("Continue?"), 0) == 0) continue; } /* Properly format filename. */ if (format_new_filename(&args[i]) == FUNC_FAILURE) { exit_status = FUNC_FAILURE; continue; } /* Skip existent files. */ if (check_file_existence(args[i]) == 0) { exit_status = err_file_exists(args[i], 0, is_md); continue; } const int ret = create_file(args[i], is_md); if (ret == FUNC_SUCCESS) { new_files[new_files_n] = args[i]; new_files_n++; } else { exit_status = ret; } } new_files[new_files_n] = (char *)NULL; if (new_files_n > 0) { if (exit_status != FUNC_SUCCESS && conf.autols == 1) press_any_key_to_continue(0); list_created_files(new_files, new_files_n); } free(new_files); return exit_status; } /* Create one directory for each name specified in ARGS. Parent dirs are * created if required. */ int create_dirs(char **args) { if (!args[0] || IS_HELP(args[0])) { puts(_(MD_USAGE)); return FUNC_SUCCESS; } /* Append an ending slash to all names, so that create_files() will create * them all as directories. */ size_t i; for (i = 0; args[i]; i++) { const size_t len = strlen(args[i]); if (len > 0 && args[i][len - 1] == '/') continue; char *tmp = savestring(args[i], len); args[i] = xnrealloc(args[i], len + 2, sizeof(char)); snprintf(args[i], len + 2, "%s/", tmp); free(tmp); } return create_files(args, 1); } /* FILE is a broken symbolic link (stat(2) failed). Err appropriately. */ static int err_no_link(const char *file) { const int saved_errno = errno; char target[PATH_MAX + 1]; *target = '\0'; const ssize_t tlen = readlinkat(XAT_FDCWD, file, target, sizeof(target) - 1); if (tlen != -1) target[tlen] = '\0'; xerror(_("open: '%s': Broken symbolic link to '%s'\n"), file, *target ? target : "???"); return saved_errno; } int open_function(char **cmd) { if (!cmd) return FUNC_FAILURE; if (!cmd[1] || IS_HELP(cmd[1])) { puts(_(OPEN_USAGE)); return FUNC_SUCCESS; } const char *const errname = "open"; if (*cmd[0] == 'o' && (!cmd[0][1] || strcmp(cmd[0], "open") == 0)) { if (strchr(cmd[1], '\\')) { char *deq_path = unescape_str(cmd[1], 0); if (!deq_path) { xerror(_("%s: '%s': Error unescaping filename\n"), errname, cmd[1]); return FUNC_FAILURE; } xstrsncpy(cmd[1], deq_path, strlen(deq_path) + 1); free(deq_path); } } char *file = cmd[1]; /* Check file existence. */ struct stat attr; errno = 0; if (lstat(file, &attr) == -1) { xerror("%s: '%s': %s\n", errname, cmd[1], strerror(errno)); return errno; } /* Check file type: only directories, symlinks, and regular files * will be opened. */ char no_open_file = 1; const char *file_type = (char *)NULL; const char *const types[] = { "block device", "character device", "socket", "FIFO/pipe", "unknown file type", #ifdef __sun "door", #endif /* __sun */ NULL}; switch ((attr.st_mode & S_IFMT)) { /* Store file type to compose and print the error message, if necessary. */ case S_IFBLK: file_type = types[OPEN_BLK]; break; case S_IFCHR: file_type = types[OPEN_CHR]; break; case S_IFSOCK: file_type = types[OPEN_SOCK]; break; case S_IFIFO: file_type = types[OPEN_FIFO]; break; #ifdef __sun case S_IFDOOR: file_type = types[OPEN_DOOR]; break; #endif /* __sun */ case S_IFDIR: return cd_function(file, CD_PRINT_ERROR); case S_IFLNK: switch (get_link_ref(file)) { case -1: return err_no_link(file); case S_IFDIR: return cd_function(file, CD_PRINT_ERROR); case S_IFREG: no_open_file = 0; break; case S_IFBLK: file_type = types[OPEN_BLK]; break; case S_IFCHR: file_type = types[OPEN_CHR]; break; case S_IFSOCK: file_type = types[OPEN_SOCK]; break; case S_IFIFO: file_type = types[OPEN_FIFO]; break; #ifdef __sun case S_IFDOOR: file_type = types[OPEN_DOOR]; break; #endif /* __sun */ default: file_type = types[OPEN_UNKNOWN]; break; } break; case S_IFREG: no_open_file = 0; break; default: file_type = types[OPEN_UNKNOWN]; break; } /* If neither directory nor regular file nor symlink (to directory * or regular file), print the corresponding error message and exit. */ if (no_open_file == 1) { xerror(_("%s: '%s' (%s): Cannot open file\nTry " "'APP FILE' or 'open FILE APP'\n"), errname, cmd[1], file_type); return FUNC_FAILURE; } /* At this point we know that the file to be openend is either a regular * file or a symlink to a regular file. So, just open the file. */ if (!cmd[2] || (*cmd[2] == '&' && !cmd[2][1])) return open_file(file); /* Some application was specified to open the file. Use it. */ char *tmp_cmd[] = {cmd[2], file, NULL}; const int ret = launch_execv(tmp_cmd, bg_proc ? BACKGROUND : FOREGROUND, E_NOSTDERR); if (ret == FUNC_SUCCESS) return FUNC_SUCCESS; if (ret == E_NOEXEC) /* EACCESS && ENOEXEC */ xerror("%s: %s: %s\n", errname, cmd[2], NOEXEC_MSG); else if (ret == E_NOTFOUND) /* ENOENT */ xerror("%s: %s: %s\n", errname, cmd[2], NOTFOUND_MSG); else xerror("%s: %s: %s\n", errname, cmd[2], strerror(errno)); return ret; } static char * get_new_link_target(char *cur_target) { puts(_("Edit target (Ctrl+d to quit)")); char n_prompt[NAME_MAX]; snprintf(n_prompt, sizeof(n_prompt), "\001%s\002>\001%s\002 ", mi_c, tx_c); char *new_target = (char *)NULL; while (!new_target) { int quoted = 0; new_target = get_newname(n_prompt, cur_target, "ed); UNUSED(quoted); if (!new_target) /* The user pressed Ctrl+d */ return (char *)NULL; } char *tmp = (char *)NULL; if (*new_target == '~' && (tmp = tilde_expand(new_target))) { free(new_target); new_target = tmp; } size_t l = strlen(new_target); if (l > 0 && new_target[l - 1] == ' ') { l--; new_target[l] = '\0'; } return new_target; } static void print_current_target(char *target) { printf(_("Current target %s%s%s "), dn_c, SET_MSG_PTR, df_c); struct stat a; if (lstat(target, &a) != -1) { colors_list(target, NO_ELN, NO_PAD, PRINT_NEWLINE); } else if (*target) { printf(_("%s%s%s (broken link)\n"), uf_c, target, df_c); } else { puts(_("??? (broken link)")); } } /* Relink the symbolic link LINK to a new target. */ int edit_link(char *link) { if (!link || !*link || IS_HELP(link)) { puts(LE_USAGE); return FUNC_SUCCESS; } /* Dequote the filename, if necessary. */ if (strchr(link, '\\')) { char *tmp = unescape_str(link, 0); if (!tmp) { xerror(_("le: '%s': Error unescaping filename\n"), link); return FUNC_FAILURE; } xstrsncpy(link, tmp, strlen(tmp) + 1); free(tmp); } const size_t len = strlen(link); if (len > 0 && link[len - 1] == '/') link[len - 1] = '\0'; /* Check if we have a valid symbolic link */ struct stat attr; if (lstat(link, &attr) == -1) { xerror("le: '%s': %s\n", link, strerror(errno)); return FUNC_FAILURE; } if (!S_ISLNK(attr.st_mode)) { xerror(_("le: '%s': Not a symbolic link\n"), link); return FUNC_FAILURE; } /* Get file pointed to by symlink and report to the user */ char target[PATH_MAX + 1]; *target = '\0'; const ssize_t tlen = readlinkat(XAT_FDCWD, link, target, sizeof(target) - 1); if (tlen != -1) target[tlen] = '\0'; print_current_target(target); char *new_path = get_new_link_target(target); if (new_path && strcmp(new_path, target) == 0) { free(new_path); puts(_("le: Nothing to do")); return (FUNC_SUCCESS); } if (!new_path) /* The user pressed C-d */ return FUNC_SUCCESS; /* Check new_path existence and warn the user if it does not exist. */ if (lstat(new_path, &attr) == -1) { xerror("'%s': %s\n", new_path, strerror(errno)); if (rl_get_y_or_n(_("Relink as broken symbolic link?"), 0) == 0) { free(new_path); return FUNC_SUCCESS; } } /* Finally, remove the link and recreate it as link to new_path. */ if (unlinkat(XAT_FDCWD, link, 0) == -1 || symlinkat(new_path, XAT_FDCWD, link) == -1) { free(new_path); xerror(_("le: Cannot relink symbolic link '%s': %s\n"), link, strerror(errno)); return FUNC_FAILURE; } printf(_("'%s' relinked to "), link); fflush(stdout); colors_list(new_path, NO_ELN, NO_PAD, PRINT_NEWLINE); free(new_path); return FUNC_SUCCESS; } /* Return the length of the longest common prefix of canonical PATH1 * and PATH2, ensuring only full path components are matched. * Return 0 on no match. */ static int path_common_prefix(char const *path1, char const *path2) { int i = 0; int ret = 0; /* We already know path1[0] and path2[0] are '/'. Special case '//', * which is only present in a canonical name on platforms where it * is distinct. */ if ((path1[1] == '/') != (path2[1] == '/')) return 0; while (*path1 && *path2) { if (*path1 != *path2) break; if (*path1 == '/') ret = i + 1; path1++; path2++; i++; } if ((!*path1 && !*path2) || (!*path1 && *path2 == '/') || (!*path2 && *path1 == '/')) ret = i; return ret; } /* If PBUF is not NULL, append STR to PBUF, update PBUF to point to the * end of the buffer, and adjust PLEN to reflect the remaining space. * Return 0 on success and 1 on failure (no remaining space). */ static int append_to_buf(char const *str, char **pbuf, size_t *plen) { if (*pbuf) { const size_t slen = strlen(str); if (slen >= *plen) return 1; memcpy(*pbuf, str, slen + 1); *pbuf += slen; *plen -= slen; } return 0; } /* Generate a link target for TARGET relative to LINK_NAME and copy it into * BUF, whose size is LEN. * Rerturn 0 on success and 1 on failure. */ static int relpath(const char *target, const char *link_name, char *buf, size_t len) { int buf_err = 0; /* Skip the prefix common to LINK_NAME and TARGET. */ int common_index = path_common_prefix(link_name, target); if (common_index == 0) return 0; const char *link_suffix = link_name + common_index; const char *target_suffix = target + common_index; /* Skip over extraneous '/'. */ if (*link_suffix == '/') link_suffix++; if (*target_suffix == '/') target_suffix++; /* Replace remaining components of LINK_NAME with '..', to get to a common directory. Then append the remainder of TARGET. */ if (*link_suffix) { buf_err |= append_to_buf("..", &buf, &len); for (; *link_suffix; ++link_suffix) { if (*link_suffix == '/') buf_err |= append_to_buf("/..", &buf, &len); } if (*target_suffix) { buf_err |= append_to_buf("/", &buf, &len); buf_err |= append_to_buf(target_suffix, &buf, &len); } } else { buf_err |= append_to_buf(*target_suffix ? target_suffix : ".", &buf, &len); } if (buf_err == 1) { xerror(_("link: Error generating relative path: %s\n"), strerror(ENAMETOOLONG)); } return buf_err; } static char * gen_relative_target(char *link_name, char *target) { char *norm_link = normalize_path(link_name, strlen(link_name)); if (!norm_link) { xerror(_("link: '%s': Error normalizing path\n"), link_name); return (char *)NULL; } char *p = strrchr(norm_link, '/'); if (p) *p = '\0'; char *norm_target = normalize_path(target, strlen(target)); if (!norm_target) { free(norm_link); xerror(_("link: '%s': Error normalizing path\n"), target); return (char *)NULL; } char *resolved_target = xnmalloc(PATH_MAX + 1, sizeof(char)); const int ret = relpath(norm_target, norm_link, resolved_target, PATH_MAX + 1); free(norm_link); free(norm_target); if (ret != 0) { free(resolved_target); return (char *)NULL; } return resolved_target; } /* Create a symbolic link to ARGS[0] named ARGS[1]. If args[1] is not specified, * the link is created as target_basename.link. * Returns 0 in case of success, or 1 otherwise. */ int symlink_file(char **args) { if (!args[0] || !*args[0] || IS_HELP(args[0])) { puts(LINK_USAGE); return FUNC_SUCCESS; } size_t len = strlen(args[0]); if (len > 1 && args[0][len - 1] == '/') args[0][len - 1] = '\0'; if (strchr(args[0], '\\')) { char *deq = unescape_str(args[0], 0); if (deq) { free(args[0]); args[0] = deq; } } if (args[1] && strchr(args[1], '\\')) { char *deq = unescape_str(args[1], 0); if (deq) { free(args[1]); args[1] = deq; } } char *target = args[0]; char *link_name = args[1]; char tmp[PATH_MAX + 1]; struct stat a; if (!link_name || !*link_name) { char *p = strrchr(target, '/'); snprintf(tmp, sizeof(tmp), "%s.link", (p && p[1]) ? p + 1 : target); int suffix = 1; while (lstat(tmp, &a) == 0 && suffix < INT_MAX) { snprintf(tmp, sizeof(tmp), "%s.link-%d", (p && p[1]) ? p + 1 : target, suffix); suffix++; } link_name = tmp; } len = strlen(link_name); if (len > 1 && link_name[len - 1] == '/') link_name[len - 1] = '\0'; if (lstat(target, &a) == -1) { printf("link: '%s': %s\n", target, strerror(errno)); if (rl_get_y_or_n(_("Create broken symbolic link?"), 0) == 0) return FUNC_SUCCESS; } if (lstat(link_name, &a) != -1 && S_ISLNK(a.st_mode)) { printf("link: '%s': %s\n", link_name, strerror(EEXIST)); if (rl_get_y_or_n(_("Overwrite this file?"), conf.default_answer.overwrite) == 0) { return FUNC_SUCCESS; } if (unlinkat(XAT_FDCWD, link_name, 0) == -1) { xerror(_("link: Cannot unlink '%s': %s\n"), link_name, strerror(errno)); return FUNC_FAILURE; } } char *resolved_target = target; switch (conf.link_creat_mode) { case LNK_CREAT_ABS: resolved_target = normalize_path(target, strlen(target)); break; case LNK_CREAT_REL: resolved_target = gen_relative_target(link_name, target); break; default: break; } if (!resolved_target) return FUNC_FAILURE; const int ret = symlinkat(resolved_target, XAT_FDCWD, link_name); if (resolved_target != target) free(resolved_target); if (ret == -1) { xerror(_("link: Cannot create symbolic link '%s': %s\n"), link_name, strerror(errno)); return FUNC_FAILURE; } return FUNC_SUCCESS; } static int vv_rename_files(char **args, const size_t copied) { char **tmp = xnmalloc(args_n + 2, sizeof(char *)); tmp[0] = savestring("br", 2); size_t i, l = strlen(args[args_n]), c = 1; if (l > 0 && args[args_n][l - 1] == '/') args[args_n][l - 1] = '\0'; char *dest = sel_is_last == 1 ? "." : args[args_n]; const size_t n = args_n + (sel_is_last == 1); for (i = 1; i < n && args[i]; i++) { if (!*args[i]) continue; l = strlen(args[i]); if (l > 0 && args[i][l - 1] == '/') args[i][l - 1] = '\0'; char p[PATH_MAX + 1]; char *s = strrchr(args[i], '/'); snprintf(p, sizeof(p), "%s/%s", dest, (s && *(++s)) ? s : args[i]); tmp[c] = savestring(p, strnlen(p, sizeof(p))); c++; } tmp[c] = (char *)NULL; size_t renamed = 0; const int ret = bulk_rename(tmp, &renamed, 0); if (conf.autols == 1) reload_dirlist(); print_reload_msg(SET_SUCCESS_PTR, xs_cb, _("%zu file(s) copied\n"), copied); if (renamed > 0) { print_reload_msg(SET_SUCCESS_PTR, xs_cb, _("%zu file(s) renamed\n"), renamed); } else { print_reload_msg(NULL, NULL, _("%zu file(s) renamed\n"), renamed); } for (i = 0; tmp[i]; i++) free(tmp[i]); free(tmp); return ret; } static int vv_create_new_dir(const char *dir) { fprintf(stderr, _("vv: '%s': directory does not exist.\n"), dir); if (rl_get_y_or_n(_("Create it?"), 0) == 0) return (-1); char tmp[PATH_MAX + 1]; snprintf(tmp, sizeof(tmp), "%s/", dir); return create_file(tmp, 1); } static int validate_vv_dest_dir(const char *file) { if (args_n == 0) { fprintf(stderr, "%s\n", VV_USAGE); return (-1); } struct stat a; if (stat(file, &a) == -1) { if (errno == ENOENT) { return vv_create_new_dir(file); } else { xerror("vv: '%s': %s\n", file, strerror(errno)); return FUNC_FAILURE; } } if (!S_ISDIR(a.st_mode) && sel_is_last == 0) { xerror("vv: '%s': %s\n", file, strerror(ENOTDIR)); return FUNC_FAILURE; } return FUNC_SUCCESS; } static char * get_new_filename(char *cur_name) { char n_prompt[NAME_MAX]; snprintf(n_prompt, sizeof(n_prompt), _("Enter new name (Ctrl+d to quit)\n" "\001%s\002>\001%s\002 "), mi_c, tx_c); char *new_name = (char *)NULL; while (!new_name) { int quoted = 0; new_name = get_newname(n_prompt, cur_name, "ed); UNUSED(quoted); if (!new_name) /* The user pressed Ctrl+d */ return (char *)NULL; if (is_blank_name(new_name) == 1) { free(new_name); new_name = (char *)NULL; } } size_t len = strlen(new_name); if (len > 0 && new_name[len - 1] == ' ') { len--; new_name[len] = '\0'; } char *n = normalize_path(new_name, len); free(new_name); return n; } /* Return 1 if at least one file is selected in the current directory. * Otherwise, 0 is returned. */ int cwd_has_sel_files(void) { filesn_t i = files; while (--i >= 0) { if (file_info[i].sel == 1) return 1; } return 0; } #define IS_MVCMD(s) (*(s) == 'm' || (*(s) == 'a' \ && strncmp((s), "advmv", 5) == 0)) static int print_cp_mv_summary_msg(const char *c, const size_t n, const int cwd) { if (conf.autols == 1 && cwd == 1) reload_dirlist(); if (IS_MVCMD(c)) print_reload_msg(SET_SUCCESS_PTR, xs_cb, _("%zu file(s) moved\n"), n); else print_reload_msg(SET_SUCCESS_PTR, xs_cb, _("%zu file(s) copied\n"), n); return FUNC_SUCCESS; } static char * get_rename_dest_filename(char *name, int *status) { if (!name || !*name) { *status = EINVAL; return (char *)NULL; } /* Check source file existence. */ struct stat a; char *p = unescape_str(name, 0); const int ret = lstat(p ? p : name, &a); free(p); if (ret == -1) { *status = errno; alt_prompt = 0; xerror("m: '%s': %s\n", name, strerror(errno)); return (char *)NULL; } /* Get destination filename. */ char *new_name = get_new_filename(name); if (!new_name) { /* The user pressed Ctrl+d */ *status = FUNC_SUCCESS; return (char *)NULL; } return new_name; } static char ** construct_cp_mv_cmd(char **cmd, char *new_name, int *cwd, const size_t force) { size_t n = 0; char **tcmd = xnmalloc(3 + args_n + 2, sizeof(char *)); char *p = strchr(cmd[0], ' '); if (p && p[1]) { *p = '\0'; p++; tcmd[0] = savestring(cmd[0], strlen(cmd[0])); tcmd[1] = savestring(p, strlen(p)); n += 2; } else { tcmd[0] = savestring(cmd[0], strlen(cmd[0])); n++; } /* wcp(1) does not support end of options (--). */ if (*tcmd[0] != 'w' || strcmp(tcmd[0], "wcp") != 0) { tcmd[n] = savestring("--", 2); n++; } /* The -f,--force parameter is internal. Skip it. * It instructs cp/mv to skip confirmation prompts. */ size_t i = force == 1 ? 2 : 1; for (; cmd[i]; i++) { if (!*cmd[i] /* File skipped by the user in the confirmation prompt. */ || !(p = unescape_str(cmd[i], 0))) continue; tcmd[n] = savestring(p, strlen(p)); free(p); if (*cwd == 0) *cwd = is_file_in_cwd(tcmd[n]); n++; } /* Append extra parameters as required. */ if (is_sel == 1 && sel_is_last == 1) { /* E.g., "m sel" */ tcmd[n] = savestring(".", 1); *cwd = 1; n++; } else if (new_name) { /* Interactive rename: "m FILE" */ tcmd[n] = new_name; if (*cwd == 0) *cwd = is_file_in_cwd(tcmd[n]); n++; } tcmd[n] = (char *)NULL; return tcmd; } static int handle_nodir_overwrite(char *arg, const char *cmd_name) { char *file = unescape_str(arg, 0); if (!file) return 0; struct stat a; if (lstat(file, &a) != -1) { char msg[PATH_MAX + 28]; snprintf(msg, sizeof(msg), _("%s: '%s': Overwrite this file?"), cmd_name, file); if (rl_get_y_or_n(msg, conf.default_answer.overwrite) == 0) { free(file); return 0; } } free(file); return 1; } static int check_overwrite(char **args, const int force, size_t *skipped) { const int append_curdir = (sel_is_last == 1 && sel_n > 0); const size_t files_num = args_n + (append_curdir == 1); if (!args || files_num <= 1 || force == 1) return 1; const char *cmd_name = IS_MVCMD(args[0]) ? "m" : "c"; const char *dest = append_curdir == 1 ? "." : args[args_n]; struct stat a; if (!dest || stat(dest, &a) == -1) return 1; if (!S_ISDIR(a.st_mode)) return handle_nodir_overwrite(args[2], cmd_name); char msg[PATH_MAX + 28]; char buf[PATH_MAX + 1]; size_t i; const size_t dest_len = strlen(dest); const int ends_with_slash = (dest_len > 1 && dest[dest_len - 1] == '/'); for (i = 1; i < files_num; i++) { char *p = unescape_str(args[i], 0); if (!p) continue; const char *s = strrchr(p, '/'); const char *basename = (s && s[1]) ? s + 1 : p; if (ends_with_slash == 0) snprintf(buf, sizeof(buf), "%s/%s", dest, basename); else snprintf(buf, sizeof(buf), "%s%s", dest, basename); free(p); if (lstat(buf, &a) == -1) continue; snprintf(msg, sizeof(msg), _("%s: '%s': Overwrite this file?"), cmd_name, buf); if (rl_get_y_or_n(msg, conf.default_answer.overwrite) == 0) { /* Nullify this entry. It will be skipped later. */ *args[i] = '\0'; (*skipped)++; } } /* If skipped == files_num - 1, there are no source files left, only * the destination file. There's nothing to do. */ return (*skipped < files_num - 1); } /* Remove trainling slashes from source files in ARGS. */ static void remove_dirslash_from_source(char **args) { if (args_n <= 1) return; size_t i; for (i = 1; i < args_n; i++) { if (!args[i]) break; if (!*args[i]) continue; const size_t len = strlen(args[i]); if (len > 1 && args[i][len - 1] == '/') args[i][len - 1] = '\0'; } } /* Launch the command associated to 'c' (also 'v' and 'vv') or 'm' * internal commands. */ int cp_mv_file(char **args, const int copy_and_rename, const int force) { int ret = 0; size_t skipped = 0; if (!args || !args[0]) return FUNC_FAILURE; if (check_overwrite(args, force, &skipped) == 0) return FUNC_SUCCESS; /* vv command */ if (copy_and_rename == 1 && (ret = validate_vv_dest_dir(args[args_n])) != FUNC_SUCCESS) return ret == -1 ? FUNC_SUCCESS : FUNC_FAILURE; /* m command */ char *new_name = (char *)NULL; if (IS_MVCMD(args[0]) && args[1]) { const size_t len = strlen(args[1]); if (len > 0 && args[1][len - 1] == '/') args[1][len - 1] = '\0'; if (alt_prompt == FILES_PROMPT) { /* Interactive rename. */ int status = 0; if (!(new_name = get_rename_dest_filename(args[1], &status))) return status; } } /* rsync(1) won't copy directories with a trailing slash. Remove it. */ if (*args[0] == 'r' && args[1]) remove_dirslash_from_source(args); /* Number of files to operate on. */ /* In case of 'm FILE' (interactive rename), args_n is 1, and 1 is * the number we want. */ const size_t force_param = (args[1] && is_force_param(args[1])); const size_t files_num = args_n - (args_n > 1 && sel_is_last == 0) - skipped - force_param; int cwd = 0; char **tcmd = construct_cp_mv_cmd(args, new_name, &cwd, force_param); if (!tcmd) return FUNC_FAILURE; ret = launch_execv(tcmd, FOREGROUND, E_NOFLAG); size_t i; for (i = 0; tcmd[i]; i++) free(tcmd[i]); free(tcmd); if (ret != FUNC_SUCCESS) return ret; if (copy_and_rename == 1) /* vv command */ return vv_rename_files(args, files_num); if (sel_n > 0 && IS_MVCMD(args[0])) { if (is_sel == 1) /* If 'mv sel' and command is successful deselect everything: * selected files are not there anymore. */ deselect_all(); else if (cwd_has_sel_files()) /* Just in case a selected file in the current dir was renamed. */ get_sel_files(); } return print_cp_mv_summary_msg(args[0], files_num, cwd); } #undef IS_MVCMD static void print_removed_file_info(const struct rm_info info) { char *p = abbreviate_file_name(info.name); print_file_name(p ? p : info.name, info.dir); /* Name removed, but file is still linked to another name (hardlink) */ if (info.dir == 0 && info.links > 1) { const nlink_t l = info.links - 1; xerror(_("r: '%s': File may still exist (%jd more " "%s linked to this file before this operation)\n"), info.name, (intmax_t)l, l > 1 ? _("names were") : _("name was")); } if (p && p != info.name) free(p); } /* Print the list of files removed via the most recent call to the 'r' command */ static void list_removed_files(struct rm_info *info, const size_t start, const int cwd) { size_t i, c = 0; struct stat a; for (i = start; info[i].name; i++) { if (lstat(info[i].name, &a) == -1 && errno == ENOENT) { info[i].exists = 0; c++; } } if (c == 0) /* No file was removed */ return; if (conf.autols == 1 && cwd == 1) reload_dirlist(); if (print_removed_files == 1) { for (i = start; info[i].name; i++) { if (!info[i].name || !*info[i].name || info[i].exists == 1) continue; print_removed_file_info(info[i]); } } print_reload_msg(SET_SUCCESS_PTR, xs_cb, _("%zu file(s) removed\n"), c); } /* Print files to be removed and ask the user for confirmation. * Returns 0 if no or 1 if yes. */ static int rm_confirm(const struct rm_info *info, const size_t start, const int have_dirs) { printf(_("File(s) to be removed%s:\n"), have_dirs == 1 ? _(" (recursively)") : ""); size_t i; for (i = start; info[i].name; i++) print_file_name(info[i].name, info[i].dir); return rl_get_y_or_n(_("Continue?"), conf.default_answer.remove); } static int check_rm_files(const struct rm_info *info, const size_t start, const char *errname) { struct stat a; size_t i; int ret = FUNC_SUCCESS; for (i = start; info[i].name; i++) { if (lstat(info[i].name, &a) == -1) continue; if (info[i].mtime != a.st_mtime || info[i].dev != a.st_dev || info[i].ino != a.st_ino) { xerror(_("%s: '%s': File changed on disk!\n"), errname, info[i].name); ret = FUNC_FAILURE; } } if (ret == FUNC_FAILURE) { return (rl_get_y_or_n(_("Remove files anyway?"), conf.default_answer.remove) == 0 ? FUNC_FAILURE : FUNC_SUCCESS); } return ret; } static struct rm_info fill_rm_info_struct(char **filename, struct stat *a) { struct rm_info info; info.name = *filename; info.dir = (S_ISDIR(a->st_mode)); info.links = a->st_nlink; info.mtime = a->st_mtime; info.dev = a->st_dev; info.ino = a->st_ino; info.exists = 1; return info; } int remove_files(char **args) { int cwd = 0, exit_status = FUNC_SUCCESS, errs = 0; char *err_name = (args[0] && *args[0] == 'r' && args[0][1] == 'r') ? "rr" : "r"; int i; for (i = 0; args[i]; i++); const size_t num = i > 0 ? (size_t)i - 1 : (size_t)i; struct stat a; char **rm_cmd = xnmalloc(num + 4, sizeof(char *)); /* Let's keep information about files to be removed. */ struct rm_info *info = xnmalloc(num + 4, sizeof(struct rm_info)); int j, have_dirs = 0; int rm_force = conf.rm_force == 1 ? 1 : 0; i = (is_force_param(args[1]) == 1) ? 2 : 1; if (i == 2) rm_force = 1; for (j = 3; args[i]; i++) { /* Let's start storing filenames in 3: 0 is for 'rm', and 1 * and 2 for parameters, including end of parameters (--). */ /* If we have a symlink to dir ending with a slash, stat(2) takes it * as a directory, and then rm(1) complains that cannot remove it, * because "Is a directory". So, let's remove the ending slash: * stat(2) will take it as the symlink it is and rm(1) will remove * the symlink (not the target) without complains. */ const size_t len = strlen(args[i]); if (len > 1 && args[i][len - 1] == '/') args[i][len - 1] = '\0'; /* Check if at least one file is in the current directory. If not, * there is no need to refresh the screen. */ if (cwd == 0) cwd = is_file_in_cwd(args[i]); char *tmp = unescape_str(args[i], 0); if (!tmp) { xerror(_("%s: '%s': Error unescaping filename\n"), err_name, args[i]); continue; } if (lstat(tmp, &a) != -1) { rm_cmd[j] = savestring(tmp, strlen(tmp)); info[j] = fill_rm_info_struct(&rm_cmd[j], &a); if (info[j].dir == 1) have_dirs++; j++; } else { xerror("%s: '%s': %s\n", err_name, tmp, strerror(errno)); errs++; } free(tmp); } rm_cmd[j] = info[j].name = (char *)NULL; if (j == 3) { /* No file to be deleted */ free(rm_cmd); free(info); return FUNC_FAILURE; } if (rm_force == 1 && errs > 0 && j > 3 && conf.autols == 1) press_any_key_to_continue(0); if (rm_force == 0 && rm_confirm(info, 3, have_dirs) == 0) goto END; /* Make sure that files to be removed have not changed between the * beginning of the operation and the user confirmation. */ if (check_rm_files(info, 3, err_name) == FUNC_FAILURE) goto END; rm_cmd[0] = "rm"; rm_cmd[1] = have_dirs >= 1 ? "-rf" : "-f"; rm_cmd[2] = "--"; exit_status = launch_execv(rm_cmd, FOREGROUND, E_NOFLAG); if (exit_status != FUNC_SUCCESS) { #ifndef BSD_KQUEUE if (num > 1 && conf.autols == 1) /* Only if we have multiple files */ #else /* Kqueue refreshes the screen even if there was only one file * to be modified and it failed. */ if (conf.autols == 1) #endif /* !BSD_KQUEUE */ press_any_key_to_continue(0); } if (is_sel && exit_status == FUNC_SUCCESS) deselect_all(); list_removed_files(info, 3, cwd); END: for (i = 3; rm_cmd[i]; i++) free(rm_cmd[i]); free(rm_cmd); free(info); return exit_status; } /* Export files in CWD (if FILENAMES is NULL), or files in FILENAMES, * to a temporary file. Return the address of this empty file if * success (it must be freed) or NULL in case of error. */ char * export_files(char **filenames, const int open) { const size_t len = strlen(tmp_dir) + (sizeof(TMP_FILENAME) - 1) + 2; char *tmp_file = xnmalloc(len, sizeof(char)); snprintf(tmp_file, len, "%s/%s", tmp_dir, TMP_FILENAME); const int fd = mkstemp(tmp_file); if (fd == -1) { xerror("exp: '%s': %s\n", tmp_file, strerror(errno)); free(tmp_file); return (char *)NULL; } size_t i; FILE *fp = fdopen(fd, "w"); if (!fp) { xerror("exp: '%s': %s\n", tmp_file, strerror(errno)); if (unlinkat(fd, tmp_file, 0) == -1) xerror("exp: unlink: '%s': %s\n", tmp_file, strerror(errno)); close(fd); free(tmp_file); return (char *)NULL; } /* If no argument, export files in CWD. */ if (!filenames[1]) { char buf[PATH_MAX + 1]; for (i = 0; file_info[i].name; i++) { char *name = file_info[i].name; if (virtual_dir == 1) { *buf = '\0'; if (xreadlink(XAT_FDCWD, name, buf, sizeof(buf)) == -1 || !*buf) continue; name = buf; } if (!name || !*name) continue; fprintf(fp, "%s\n", name); } } else { for (i = 1; filenames[i]; i++) { if (SELFORPARENT(filenames[i])) continue; fprintf(fp, "%s\n", filenames[i]); } } fclose(fp); if (open == 0) return tmp_file; const int ret = open_file(tmp_file); if (ret == FUNC_SUCCESS) return tmp_file; if (unlink(tmp_file) == -1) xerror("exp: unlink: '%s': %s\n", tmp_file, strerror(errno)); free(tmp_file); return (char *)NULL; } /* Create a symlink in CWD for each filename in ARGS. * If the destination file exists, a positive integer suffix is appended to * make the filename unique. */ int batch_link(char **args) { if (!args || !args[0] || IS_HELP(args[0])) { puts(_(BL_USAGE)); return FUNC_SUCCESS; } size_t i; size_t symlinked = 0; int exit_status = FUNC_SUCCESS; for (i = 0; args[i]; i++) { char *filename = unescape_str(args[i], 0); if (!filename) { exit_status = FUNC_FAILURE; xerror(_("bl: '%s': Error unescaping name\n"), args[i]); continue; } /* Remove ending slash */ const size_t l = strlen(filename); if (l > 1 && filename[l - 1] == '/') filename[l - 1] = '\0'; struct stat a; if (lstat(filename, &a) == -1) { exit_status = errno; xerror("bl: '%s': %s\n", filename, strerror(errno)); free(filename); continue; } char *s = strrchr(filename, '/'); char *basename = s && *(++s) ? s : filename; /* + 64 = Make some room for suffix */ const size_t tmp_len = strlen(basename) + 64; char *tmp = xnmalloc(tmp_len, sizeof(char)); xstrsncpy(tmp, basename, tmp_len); size_t suffix = 1; while (lstat(tmp, &a) != -1) { snprintf(tmp, tmp_len, "%s-%zu", basename, suffix); suffix++; } if (symlinkat(filename, XAT_FDCWD, tmp) == -1) { exit_status = errno; xerror(_("bl: Cannot create symbolic link '%s': %s\n"), tmp, strerror(errno)); } else { symlinked++; } free(filename); free(tmp); } if (conf.autols == 1 && symlinked > 0) { if (exit_status != FUNC_SUCCESS) press_any_key_to_continue(0); reload_dirlist(); } print_reload_msg(SET_SUCCESS_PTR, xs_cb, _("%zu symbolic link(s) created\n"), symlinked); return exit_status; } clifm-1.26.3/src/file_operations.h000066400000000000000000000043641506632037700170370ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* file_operations.h */ #ifndef FILE_OPERATIONS_H #define FILE_OPERATIONS_H #include "bulk_rename.h" #include "bulk_remove.h" /* Macros and array used to print unsafe names description messages. * Used by validate_filename(). */ #define UNSAFE_DASH 0 #define UNSAFE_MIME 1 #define UNSAFE_ELN 2 #define UNSAFE_FASTBACK 3 #define UNSAFE_BTS_CONST 4 #define UNSAFE_SYS_KEY 5 #define UNSAFE_CONTROL 6 #define UNSAFE_META 7 #define UNSAFE_TOO_LONG 8 #ifdef _BE_POSIX # define UNSAFE_NOT_PORTABLE 9 #endif /* Macros for open_function */ #define OPEN_BLK 0 #define OPEN_CHR 1 #define OPEN_SOCK 2 #define OPEN_FIFO 3 #define OPEN_UNKNOWN 4 #ifdef __sun # define OPEN_DOOR 5 #endif /* */ __BEGIN_DECLS int batch_link(char **args); void clear_selbox(void); int cp_mv_file(char **args, const int copy_and_rename, const int force); int create_files(char **args, const int is_md); int create_dirs(char **args); int cwd_has_sel_files(void); int dup_file(char **cmd); int edit_link(char *link); char *export_files(char **filenames, const int open); int open_file(char *file); int open_function(char **cmd); int remove_files(char **args); int symlink_file(char **args); int toggle_exec(const char *file, mode_t mode); int umask_function(const char *arg); int xchmod(const char *file, const char *mode_str, const int flag); __END_DECLS #endif /* FILE_OPERATIONS_H */ clifm-1.26.3/src/fsinfo.c000066400000000000000000000313061506632037700151300ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* fsinfo.c - Get filesystem information */ #include "helpers.h" #if defined(LINUX_FSINFO) # include /* strnlen(3), strncmp(3) */ # include /* xxxmntent(), used by get_remote_fs_name() */ # include /* statfs(2) */ # include /* major() and minor(), used by get_dev_name() */ # include "aux.h" /* open_fread() */ # include "linuxfs.h" /* FS_MAGIC macros for filesystem types */ #elif defined(HAVE_STATFS) # include /* statfs(2) */ #elif defined(__sun) # include /* getmntent() */ # include /* strstr() */ #endif /* LINUX_FSINFO */ #if defined(LINUX_FSINFO) # if defined(__ANDROID__) /* Bionic versions from between 2014-01-09 and 2015-01-08 define MOUNTED to * an incorrect value; older Bionic versions don't define it at all. */ # undef MOUNTED # define MOUNTED "/proc/mounts" # elif !defined(MOUNTED) # if defined(_PATH_MOUNTED) /* GNU libc */ # define MOUNTED _PATH_MOUNTED # else # define MOUNTED "/etc/mtab" # endif /* _PATH_MOUNTED */ # endif /* __ANDROID__ */ /* Given an ext filesystem, tell whether it is version 2, 3, or 4. * Returns a pointer to a constant string with the proper name. If none is * found, a generic "ext2/3/4" is returned. * * This function just checks information gathered at startup, which is way * faster than performing the whole thing each time it is needed. However, * Filesystems mounted in the current session won't be checked here. */ static char * get_ext_fs_type(const char *file) { char *type = "ext2/3/4"; if (!ext_mnt || !file || !*file) return type; size_t mnt_longest = 0; int i, index = -1; for (i = 0; ext_mnt[i].mnt_point; i++) { char *ptr = strstr(file, ext_mnt[i].mnt_point); if (!ptr || ptr != file) continue; size_t l = strlen(ext_mnt[i].mnt_point); if (l > mnt_longest) { mnt_longest = l; index = i; } } if (index == -1) return type; switch (ext_mnt[index].type) { case EXT2_FSTYPE: type = "ext2"; break; case EXT3_FSTYPE: type = "ext3"; break; case EXT4_FSTYPE: type = "ext4"; break; default: type = "ext?"; break; } return type; } /* Return a pointer to a constant string with the name of the filesystem * where the file FILE resides. REMOTE is set to 1 if the corresponding * filesystem is a remote one. */ char * get_fs_type_name(const char *file, int *remote) { struct statfs a; if (!file || !*file || statfs(file, &a) == -1) return UNKNOWN_STR; switch (a.f_type) { case T_AAFS_MAGIC: return "aafs"; case T_ACFS_MAGIC: *remote = 1; return "acfs"; case T_ADFS_MAGIC: return "adfs"; case T_AFFS_MAGIC: return "affs"; case T_AFS_FS_MAGIC: *remote = 1; return "k-afs"; case T_AFS_MAGIC: *remote = 1; return "afs"; case T_ANON_INODE_FS_MAGIC: return "anon-inode-fs"; case T_AUFS_MAGIC: *remote = 1; return "aufs"; case T_AUTOFS_MAGIC: return "autofs"; case T_BALLONFS_MAGIC: return "ballon-kvm-fs"; case T_BEFS_MAGIC: return "befs"; case T_BDEVFS_MAGIC: return "bdevfs"; case T_BFS_MAGIC: return "bfs"; case T_BINDERFS_MAGIC: return "binderfs"; case T_BINFMTFS_MAGIC: return "binfmt_misc"; case T_BPF_FS_MAGIC: return "bps_fs"; case T_BTRFS_MAGIC: return "btrfs"; case T_BTRFS_TEST_MAGIC: return "btrfs_test"; case T_CEPH_MAGIC: *remote = 1; return "ceph"; case T_CGROUP_MAGIC: return "cgroupfs"; case T_CGROUP2_MAGIC: return "cgroup2fs"; case T_CIFS_MAGIC: *remote = 1; return "cifs"; case T_CODA_MAGIC: *remote = 1; return "coda"; case T_COH_MAGIC: return "coh"; case T_CONFIGFS_MAGIC: return "configfs"; case T_CRAMFS_MAGIC: return "cramfs"; case T_CRAMFS_MAGIC_WEND: return "cramfs-wend"; case T_DAXFS_MAGIC: return "daxfs"; case T_DEBUGFS_MAGIC: return "debugfs"; case T_DEVFS_MAGIC: return "devfs"; /* Linux 2.6.17 and earlier */ case T_DEVMEM_MAGIC: return "devmem"; case T_DEVPTS_MAGIC: return "devpts"; case T_DMA_BUF_MAGIC: return "dma-buf-fs"; case T_ECRYPTFS_MAGIC: return "ecryptfs"; case T_EFIVARFS_MAGIC: return "efivarfs"; case T_EFS_MAGIC: return "efs"; case T_EROFS_MAGIC_V1: return "erofs"; case T_EXFAT_MAGIC: return "exfat"; case T_EXT_MAGIC: return "ext"; /* Linux 2.0 and earlier */ case T_EXT2_OLD_MAGIC: return "ext2"; /* case T_EXT2_MAGIC: // ext2/3/4 have the same magic number case T_EXT3_MAGIC: */ case T_EXT4_MAGIC: return get_ext_fs_type(file); case T_F2FS_MAGIC: return "f2fs"; case T_FAT_MAGIC: return "fat"; case T_FHGFS_MAGIC: *remote = 1; return "fhgfs"; case T_FUSE_MAGIC: *remote = 1; return "fuseblk"; case T_FUSECTL_MAGIC: *remote = 1; return "fusectl"; case T_FUTEXFS_MAGIC: return "futexfs"; case T_GFS2_MAGIC: *remote = 1; return "gfs/gfs2"; case T_GPFS_MAGIC: *remote = 1; return "gpfs"; case T_HFS_MAGIC: return "hfs"; case T_HFS_PLUS_MAGIC: return "hfs+"; case T_HFSX_MAGIC: return "hfsx"; case T_HOSTFS_MAGIC: return "hostfs"; case T_HPFS_MAGIC: return "hpfs"; case T_HUGETLBFS_MAGIC: return "hugetlbfs"; case T_IBRIX_MAGIC: *remote = 1; return "ibrix"; case T_INOTIFYFS_MAGIC: return "inotifyfs"; case T_ISOFS_MAGIC: /* fallthrough */ case T_ISOFS_R_WIN_MAGIC: /* fallthrough */ case T_ISOFS_WIN_MAGIC: return "isofs"; case T_JFFS_MAGIC: return "jffs"; case T_JFFS2_MAGIC: return "jffs2"; case T_JFS_MAGIC: return "jfs"; case T_LOGFS_MAGIC: return "logfs"; case T_LUSTRE_MAGIC: *remote = 1; return "lustre"; case T_M1FS_MAGIC: return "m1fs"; case T_MINIX_MAGIC: return "minix"; case T_MINIX_MAGIC2: return "minix (30 char.)"; case T_MINIX2_MAGIC: return "minix v2"; case T_MINIX2_MAGIC2: return "minix v2 (30 char.)"; case T_MINIX3_MAGIC: return "minix3"; case T_MQUEUE_MAGIC: return "mqueue"; case T_MSDOS_MAGIC: return "vfat"; case T_MTD_INODE_FS_MAGIC: return "inodefs"; case T_NCP_MAGIC: *remote = 1; return "novell"; case T_NFS_MAGIC: *remote = 1; return "nfs"; case T_NFSD_MAGIC: *remote = 1; return "nfsd"; case T_NILFS_MAGIC: return "nilfs"; case T_NSFS_MAGIC: return "nsfs"; case T_NTFS_CG_MAGIC: /* fallthrough */ /* Cygwin */ case T_NTFS_MAGIC: return "ntfs"; case T_OCFS2_MAGIC: *remote = 1; return "ocfs2"; case T_OPENPROM_MAGIC: return "openprom"; case T_OVERLAYFS_MAGIC: *remote = 1; return "overlayfs"; case T_PANFS_MAGIC: *remote = 1; return "panfs"; case T_PID_FS_MAGIC: return "pidfs"; case T_PIPEFS_MAGIC: *remote = 1; return "pipefs"; case T_PPC_CMM_FS_MAGIC: return "ppc-cmm-fs"; case T_PRL_FS_MAGIC: *remote = 1; return "prl_fs"; case T_PROC_MAGIC: return "procfs"; case T_PSTOREFS_MAGIC: return "pstorefs"; case T_QNX4_MAGIC: return "qnx4"; case T_QNX6_MAGIC: return "qnx6"; case T_RAMFS_MAGIC: return "ramfs"; case T_RDTGROUP_MAGIC: return "rdt"; case T_REISERFS_MAGIC: return "reiserfs"; case T_RPC_PIPEFS_MAGIC: return "rpc_pipefs"; case T_SDCARDFS_MAGIC: return "sdcardfs"; case T_SECRETMEM_MAGIC: return "secretmem"; case T_SECURITYFS_MAGIC: return "securityfs"; case T_SELINUX_MAGIC: return "selinux"; case T_SMACK_MAGIC: return "smackfs"; case T_SMB_MAGIC: *remote = 1; return "smb"; case T_SMB2_MAGIC: *remote = 1; return "smb2"; case T_SNFS_MAGIC: *remote = 1; return "snfs"; case T_SOCKFS_MAGIC: return "sockfs"; case T_SQUASHFS_MAGIC: return "squashfs"; case T_STACK_END_MAGIC: return "stack-end"; case T_SYSFS_MAGIC: return "sysfs"; case T_SYSV2_MAGIC: return "sysv2"; case T_SYSV4_MAGIC: return "sysv4"; case T_TMPFS_MAGIC: return "tmpfs"; case T_TRACEFS_MAGIC: return "tracefs"; case T_UBIFS_MAGIC: return "ubifs"; case T_UDF_MAGIC: return "udf"; case T_UFS_MAGIC: return "ufs"; case T_USBDEVICE_MAGIC: return "usbdevfs"; case T_V9FS_MAGIC: return "v9fs"; case T_VBOXSF_MAGIC: *remote = 1; return "vboxsf"; case T_VFAT_MAGIC: return "vfat"; /* Cygwin */ case T_VMHGFS_MAGIC: *remote = 1; return "vmhgfs"; case T_VXFS_MAGIC: *remote = 1; return "vxfs"; case T_VZFS_MAGIC: return "vzfs"; case T_WSLFS_MAGIC: return "wslfs"; case T_XENFS_MAGIC: return "xenfs"; case T_XENIX_MAGIC: return "xenix"; case T_XFS_MAGIC: return "xfs"; case T_XIA_MAGIC: return "xia"; /* Linux 2.0 and earlier */ case T_Z3FOLD_MAGIC: return "z3fold"; case T_ZFS_MAGIC: return "zfs"; case T_ZONEFS_MAGIC: return "zonefs"; case T_ZSMALLOCFS_MAGIC: return "zsmallocfs"; default: return "unknown"; } } /* Return a pointer to the name of the device where the file FILE resides * (e.g.: "/dev/sda2" or "//192.168.10.27/share"). * * NOTE: It performs the same function as get_dev_name(), but it's 3X slower, * so that we use it only when the major device number is zero, in which case * it cannot be found in /sys/dev/block (as done by get_dev_name()). */ char * get_dev_name_mntent(const char *file) { if (!file || !*file) return DEV_NO_NAME; FILE *fp = setmntent(MOUNTED, "r"); if (!fp) return DEV_NO_NAME; size_t mnt_longest = 0; static char name[PATH_MAX + 1]; *name = '\0'; struct mntent *ent; while ((ent = getmntent(fp)) != NULL) { char *ptr = strstr(file, ent->mnt_dir); if (!ptr || ptr != file) continue; const size_t l = strlen(ent->mnt_dir); if (l > mnt_longest) { mnt_longest = l; xstrsncpy(name, ent->mnt_fsname, sizeof(name)); } } endmntent(fp); return (*name ? name : DEV_NO_NAME); } #if !defined(__CYGWIN__) && !defined(__ANDROID__) #define MAX_DEVNAMES 64 #define MAX_DEVNAME_LEN 32 struct devs_t { char name[MAX_DEVNAME_LEN]; dev_t dev; }; /* Struct to store cached device names. We can cache 64 entries, totaling 2Kb. */ static struct devs_t devnames[MAX_DEVNAMES]; static size_t devnames_count = 0; static char * get_dev_name_cached(const dev_t dev) { if (devnames_count == 0) return NULL; size_t i; for (i = 0; i < devnames_count; i++) if (dev == devnames[i].dev && *devnames[i].name) return devnames[i].name; return NULL; } /* Return a pointer to the name of the block device whose ID is DEV. */ char * get_dev_name(const dev_t dev) { char *dname = get_dev_name_cached(dev); if (dname) return dname; const unsigned int maj = major(dev); if (maj == 0) /* special devices (tmp, dev, sys, proc, etc) */ return DEV_NO_NAME; const unsigned int min = minor(dev); char dev_path[PATH_MAX + 1]; snprintf(dev_path, sizeof(dev_path), "/sys/dev/block/%u:%u/uevent", maj, min); int fd; FILE *fp = open_fread(dev_path, &fd); if (!fp) return DEV_NO_NAME; static char name[NAME_MAX + 1]; *name = '\0'; char line[NAME_MAX]; *line = '\0'; while (fgets(line, (int)sizeof(line), fp)) { if (*line != 'D' || strncmp(line + 1, "EVNAME=", 7) != 0) continue; const int len = snprintf(name, sizeof(name), "/dev/%s", line + 8); if (len > 1) /* Remove ending new line char */ name[len - 1] = '\0'; /* Cache the result (provided it fits in our cache buffer). */ if (len < MAX_DEVNAME_LEN && devnames_count < MAX_DEVNAMES) { devnames[devnames_count].dev = dev; xstrsncpy(devnames[devnames_count].name, name, sizeof(devnames[devnames_count].name)); devnames_count++; } break; } fclose(fp); return (*name ? name : DEV_NO_NAME); } #undef MAX_DEVNAMES #undef MAX_DEVNAME_LEN #endif /* !__CYGWIN__ && !__ANDROID__ */ #elif defined(HAVE_STATFS) /* Update DEVNAME and DEVTYPE to make it point to the device name and device * type of the filesystem where the file FILE resides. */ void get_dev_info(const char *file, char **devname, char **devtype) { static struct statfs a; if (!file || !*file || statfs(file, &a) == -1) { *devname = DEV_NO_NAME; *devtype = DEV_NO_NAME; return; } *devname = a.f_mntfromname; *devtype = a.f_fstypename; } #elif defined(__sun) char * get_dev_mountpoint(const char *file) { if (!file || !*file) return DEV_NO_NAME; FILE *fp = fopen(MNTTAB, "r"); if (!fp) return DEV_NO_NAME; size_t mnt_longest = 0; static char name[PATH_MAX + 1]; *name = '\0'; struct mnttab ent; while (getmntent(fp, &ent) == 0) { char *ptr = strstr(file, ent.mnt_mountp); if (!ptr || ptr != file) continue; const size_t l = strlen(ent.mnt_mountp); if (l > mnt_longest) { mnt_longest = l; xstrsncpy(name, ent.mnt_mountp, sizeof(name)); } } fclose(fp); return (*name ? name : DEV_NO_NAME); } #else void *_skip_me_fsinfo; #endif /* LINUX_FSINFO */ clifm-1.26.3/src/fsinfo.h000066400000000000000000000026111506632037700151320ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* fsinfo.h */ #ifndef FSINFO_H #define FSINFO_H __BEGIN_DECLS #if defined(LINUX_FSINFO) char *get_fs_type_name(const char *file, int *remote); #if !defined(__CYGWIN__) && !defined(__ANDROID__) char *get_dev_name(const dev_t dev); #endif /* !__CYGWIN__ && !__ANDROID__ */ char *get_dev_name_mntent(const char *file); #elif defined(HAVE_STATFS) void get_dev_info(const char *file, char **devname, char **devtype); #elif defined(__sun) char *get_dev_mountpoint(const char *file); #endif /* LINUX_FSINFO */ __END_DECLS #endif /* FS_INFO */ clifm-1.26.3/src/fuzzy_match.c000066400000000000000000000143331506632037700162100ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* fuzzy_match.c */ /* This file contains two fuzzy matchers: * (1) fuzzy_match_fzy: slower than (2), but more accurate * (2) fuzzy_match: faster than (1), but less accurate in some cases */ /* The algorithm used by fuzzy_match_fzy() is taken from * https://github.com/jhawthorn/fzy, licensed MIT * Modifications are licensed GPL2+ */ #include "helpers.h" #include #include "fuzzy_match.h" #include "utf8.h" /* Three functions added to the utf8.h library */ /* Return the number of bytes needed to advance to the character next to S. */ static int utf8nextcodepoint(const char *s) { if (0xf0 == (0xf8 & *s)) { /* 4-byte utf8 code point (began with 0b11110xxx) */ return 4; } else if (0xe0 == (0xf0 & *s)) { /* 3-byte utf8 code point (began with 0b1110xxxx) */ return 3; } else if (0xc0 == (0xe0 & *s)) { /* 2-byte utf8 code point (began with 0b110xxxxx) */ return 2; } else { /* (0x00 == (0x80 & *s)) { */ /* 1-byte ascii (began with 0b0xxxxxxx) */ return 1; } } /* A Unicode aware version of xstrcasechr (in strings.c)*/ static char * utf8casechr(char *s, char *c) { if (!s || !*s || !c || !*c) return (char *)NULL; utf8_int32_t cps = 0, cpc = 0, cp = 0; char *ret = (char *)NULL; utf8codepoint(c, &cpc); cp = utf8uprcodepoint(cpc); while (*s) { ret = utf8codepoint(s, &cps); if (utf8uprcodepoint(cps) != cp) { s = ret; continue; } return s; } return (char *)NULL; } /* Check whether the string S contains at least one UTF8 codepoint. * Returns 1 if true or 0 if false. */ int contains_utf8(const char *s) { if (!s || !*s) return 0; while (*s) { if (IS_UTF8_LEAD_BYTE(*s)) return 1; s++; } return 0; } /* Same as fuzzy_match(), but: * 1: Not Unicode aware * 2: Much faster */ static int fuzzy_match_v1(char *s1, char *s2, const size_t s1_len) { const int cs = conf.case_sens_path_comp; int included = 0; char *p = (char *)NULL; if (cs == 1 ? (p = strstr(s2, s1)) : (p = xstrcasestr(s2, s1))) { if (p == s2) { if (!*(s2 + s1_len)) return EXACT_MATCH_BONUS; return TARGET_BEGINNING_BONUS; } included = 1; } int word_beginning = 0; int consecutive_chars = 0; const int first_char = cs == 1 ? (*s1 == *s2) : (TOUPPER(*s1) == TOUPPER(*s2)); size_t l = 0; char *hs = s2; while (*s1) { char *m = cs == 1 ? strchr(hs, *s1) : xstrcasechr(hs, *s1); if (!m) break; if (s1[1] && m[1] && (cs == 1 ? s1[1] == m[1] : TOUPPER(s1[1]) == TOUPPER(m[1]) )) consecutive_chars++; if (l > 0 && (!IS_ALPHA_CASE(*(m - 1)) || IS_CAMEL_CASE(*m, *(m - 1)) ) ) word_beginning++; m++; hs = m; s1++; l++; } if (*s1) return 0; int score = 0; score += (word_beginning * WORD_BEGINNING_BONUS); score += (first_char * FIRST_CHAR_BONUS); score += (included * INCLUDED_BONUS); score += (consecutive_chars * CONSECUTIVE_CHAR_BONUS); score += ((int)l * SINGLE_CHAR_MATCH_BONUS); return score; } /* A basic fuzzy matcher. It returns a score based on how much the * pattern (S1) matches the item (S2), taking into account: * * Initial character * Word beginnings * Consecutive characters * * fuzzy_match_v1() will be used whenever the pattern contains no UTF8 char * * The caller can decide whether the returned score is enough. If not, * a new item must be inspected until we get the desired score. Previous * values should be stored in case the desired score is never reached. * * What this fuzzy matcher lacks: * 1. Taking gap (distance) between matched chars into account */ int fuzzy_match(char *s1, char *s2, const size_t s1_len, const int type) { if (!s1 || !*s1 || !s2 || !*s2) return 0; if (type == FUZZY_FILES_ASCII || type == FUZZY_FILES_UTF8) { if ((*s1 == '.' && s1[1] == '.') || *s1 == '-') return 0; } if (type == FUZZY_FILES_ASCII || conf.fuzzy_match_algo == 1) return fuzzy_match_v1(s1, s2, s1_len); const int cs = conf.case_sens_path_comp; int included = 0; char *p = (char *)NULL; if (cs == 1 ? (p = utf8str(s2, s1)) : (p = utf8casestr(s2, s1))) { if (p == s2) { if (!*(s2 + s1_len)) return EXACT_MATCH_BONUS; return TARGET_BEGINNING_BONUS; } included = 1; } utf8_int32_t cp1 = 0, cp2 = 0; utf8codepoint(s1, &cp1); utf8codepoint(s2, &cp2); int word_beginning = 0; int consecutive_chars = 0; const int first_char = (cs == 1) ? (cp1 == cp2) : (utf8uprcodepoint(cp1) == utf8uprcodepoint(cp2)); size_t l = 0; char *hs = s2; while (*s1) { char *m = (char *)NULL; if (cs == 1) { utf8codepoint(s1, &cp1); m = utf8chr(hs, cp1); } else { m = utf8casechr(hs, s1); } if (!m) break; int a = utf8nextcodepoint(s1); int b = utf8nextcodepoint(m); cp1 = 0; cp2 = 0; utf8codepoint(s1 + a, &cp1); utf8codepoint(m + b, &cp2); if (*(s1 + a) && *(m + b) && (cs == 1 ? (cp1 == cp2) : (utf8uprcodepoint(cp1) == utf8uprcodepoint(cp2)) ) ) consecutive_chars++; const char *bc = l > 0 ? utf8rcodepoint(m, &cp1) : (char *)NULL; if (bc) { if (IS_WORD_SEPARATOR(*bc)) { word_beginning++; } else { utf8codepoint(bc, &cp2); if (utf8isupper(cp2) != 1 && utf8isupper(cp1) == 1) word_beginning++; } } hs = m + b; s1 += a; l++; } if (*s1) return 0; int score = 0; score += (word_beginning * WORD_BEGINNING_BONUS); score += (first_char * FIRST_CHAR_BONUS); score += (included * INCLUDED_BONUS); score += (consecutive_chars * CONSECUTIVE_CHAR_BONUS); score += ((int)l * SINGLE_CHAR_MATCH_BONUS); return score; } clifm-1.26.3/src/fuzzy_match.h000066400000000000000000000037051506632037700162160ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* fuzzy_match.h */ /* Taken from https://github.com/jhawthorn/fzy, licensed MIT * Modifications are licensed GPL2+ */ #ifndef FUZZY_MATCH_H #define FUZZY_MATCH_H /* Macros for our native fuzzy matcher: fuzzy_match() */ #define IS_WORD_SEPARATOR(c) ((c) == '-' || (c) == '_' || (c) == ' ' \ || (c) == '.' || (c) == ',' || (c) == ';' || (c) == ':' || (c) == '@' \ || (c) == '=' || (c) == '+' || (c) == '*' || (c) == '&') #define IS_ALPHA_CASE(c) (IS_ALPHA_LOW((c)) || IS_ALPHA_UP((c))) #define IS_CAMEL_CASE(c, p) (IS_ALPHA_UP((c)) && IS_ALPHA_LOW((p))) #define TARGET_BEGINNING_BONUS (NAME_MAX * 10) #define FIRST_CHAR_BONUS 10 #define INCLUDED_BONUS 8 #define WORD_BEGINNING_BONUS 5 #define CONSECUTIVE_CHAR_BONUS 4 #define SINGLE_CHAR_MATCH_BONUS 2 /* When suggesting filenames, an exact match doesn't provide anything * else for suggesting, so that it isn't useful */ #define EXACT_MATCH_BONUS 1 __BEGIN_DECLS int fuzzy_match(char *s1, char *s2, const size_t s1_len, const int type); int contains_utf8(const char *s); __END_DECLS #endif /* FUZZY_MATCH_H */ clifm-1.26.3/src/help.c000066400000000000000000000464321506632037700146020ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* help.c -- home of clifm's help system */ #include "helpers.h" #include /* errno */ #include #include /* unlink */ #include "aux.h" /* get_cmd_path */ #include "listing.h" /* reload_dirlist */ #include "messages.h" /* USAGE macros */ #include "misc.h" /* xerror */ #include "spawn.h" /* launch_exec */ #include "strings.h" /* savestring */ /* Instead of recreating here the commands description, just jump to the * corresponding section in the manpage. */ int list_commands(void) { char cmd[PATH_MAX]; snprintf(cmd, sizeof(cmd), "export PAGER=\"less -p '^[0-9]+\\.[[:space:]]COMMANDS'\"; man %s\n", PROGRAM_NAME); if (launch_execl(cmd) != FUNC_SUCCESS) return FUNC_FAILURE; return FUNC_SUCCESS; } /* Print either all tips (if ALL == 1) or just a random one (ALL == 0) */ void print_tips(const int all) { const char *TIPS[] = { #ifndef _BE_POSIX "Add a new entry to the mimelist file: 'mm edit' or F6", "Get mime information for a file. E.g.: 'mm info file'", "Manage default associated applications with the 'mime' command", "Customize previewing applications: 'view edit' or F7", "List mountpoints: 'mp' or Alt+m", "Compress files with 'ac' and decompress with 'ad'. E.g.: 'ac sel' or 'ad file.zip'", "Disallow the use of shell commands with the -x option: 'clifm -x'", "Don't like ELNs? Disable them using the -e command line switch", "Disable file previews in fzf mode with --no-fzfpreview", # ifdef __linux__ "Manage removable devices with the 'media' command", # endif /* __linux__ */ #endif /* _BE_POSIX */ #ifndef _BE_POSIX "Create a new profile: 'pf add PROFILE' or 'clifm -P PROFILE'", "Enable incognito/private mode with -S or --stealth-mode", "Run in read-only mode via --readonly", "Use --secure-env and --secure-cmds for secure operation in untrusted environments", "Run in disk usage analyzer mode using the -t command line switch", "Fuzzy suggestions are supported. E.g.: 'dwn > Downloads'. Enable them via --fuzzy-matching, or FuzzyMatching in the configuration file", "Miss LS_COLORS? Run with --lscolors", #else "Create a new profile: 'pf add PROFILE' or 'clifm -p PROFILE'", "Enable incognito/private mode with the -s flag", "Running in an untrusted environment? Try the -x, -X, and -Y flags", "Run in disk usage analyzer mode using the -u flag", "Fuzzy suggestions are supported (e.g.: 'dwn > Downloads'). Enable them via the -m flag (or FuzzyMatching in the configuration file)", #endif /* _BE_POSIX */ "Clear the screen: 'rf', '.', Enter (on empty line), or Ctrl+l", "Try the autocd and auto-open functions: run 'FILE' instead " "of 'cd FILE' or 'open FILE'", "Do not forget to take a look at the manpage", "Need more speed? Try the light mode ('lm' or Alt+y)", "The Selection Box is shared among different instances of Clifm", "Use the 's' command to select files here and there: 's FILE...'", "Use wildcards and regular expressions to select files. E.g.: " "'s *.c' or 's .*\\.c$'", "Operate on selected files. E.g.: 'p sel' or 'p s:'", "List selected files: 'sb' or s:", "Use ELNs and 'sel' with shell commands, like 'ls -ld 1 sel'", "Press TAB to automatically expand an ELN. E.g.: 's 2' -> 's FILENAME'", "Use ranges (ELN-ELN) to easily move multiple files. E.g.: 'm 3-12 dir/'", "Trash files with a simple 't FILE'", "Too many files? Run the pager: 'pg' or Alt+0", "Toggle the long-view: 'll' or Alt+l", "Search for files using the slash command. E.g.: '/*.png'", "The search function supports regular expressions. E.g.: '/^c'", "Add a new bookmark: 'bm add FILENAME BM_NAME'", "Use c, l, m, md, and r instead of cp, ln, mv, mkdir, and rm", "Access a remote filesystem using the 'net' command", "Move back and forth in the directory history with Alt+j and Alt+k " "(also Shift-Left and Shift-Right)", "Run a new instance of Clifm: 'x DIR'", "Send a command directly to the system shell. E.g.: ';ls -l *'", "Run the last executed command: '!!'", "Access the command history list: '!'", "Exclude commands from history using the HistIgnore option in the configuration file (F10)", "Access the directory history list: 'dh '", "List previously used search patterns: '/*'", "Import aliases from file: 'alias import FILE'", "List available aliases: 'alias'", "Create aliases to easily run your preferred commands (F10)", "Get a brief description for each Clifm command: 'cmd'", "Preview the current color scheme: 'cs preview'", "Toggle hidden files: 'hh' or Alt+.", "Toggle follow-links (long view only): 'k' or Alt++", "Change to the root directory: Alt+r", "Change to the home directory: Alt+e (or just 'cd')", "Open and edit the current color scheme file: F8 (or 'cs edit')", "Open and edit the keybindings file: F9 (or 'kb edit')", "Open and edit the main configuration file: F10 (or 'config')", "Open and edit the bookmarks file: F11 (or 'bm edit')", "Open and edit the MIME list file: F6 (or 'mm edit')", "Set the starting path. E.g.: 'clifm ~/media'", "Use the 'o' command to open files and directories. E.g.: 'o 12'", "Open a file or directory by just entering its ELN or filename", "Bypass the file opener by specifying an application. E.g.: '12 leafpad'", "Open a file in the background. E.g.: '24&'", "Create a custom prompt by editing the prompts file ('prompt edit')", "Customize your color scheme: 'cs edit' or F8", "Launch the bookmark manager: 'bm' or Alt+b", "Quickly list your bookmarks: 'b:'", "Change to a bookmark: 'bm NAME' or 'b:NAME'", "Chain commands using ';' and '&&'. E.g.: 's 2 7-10; r sel'", "Add emojis to your prompt by copying them to the prompt line ('prompt edit')", "Switch profiles: 'pf set PROFILE'", "Delete a profile: 'pf del PROFILE'", "Rename a profile: 'pf rename PROFILE'", "Use 'p ELN' to print file properties for ELN", "Deselect all selected files: 'ds *' or Alt+d", "Select all files in the current directory: 's *' or Alt+a", "Jump to the Selection Box: 'sb' or Alt+s", "Selectively restore trashed files using the 'u' command", "Empty the trash can: 't empty'", "Toggle list-directories-first: 'ff' or Alt+g", "Set the file counter on/off: 'fc'", "Take a look at the splash screen with the 'splash' command", "Have some fun trying the 'bonus' command", "Launch the default system shell in CWD using ':' or ';'", "Cycle through file sort orders: Alt+z and Alt+x", "Reverse the file sort order: 'st rev'", "Rename multiple files at once. E.g.: 'br *.txt'", "Need no more tips? Disable this feature in the configuration file", "Need root privileges? Launch a new instance of Clifm as root " "running the 'X' command (note the uppercase)", "Create a fresh configuration file: 'config reset'", "Use 'ln edit' (or 'le') to edit symbolic links", "Change default keyboard shortcuts: F9 (or 'kb edit')", "Keep in sight previous and next visited directories enabling the " "DirhistMap option in the configuration file (F10)", "Pin a file via the 'pin' command and then use it with the " "period keyword (,). E.g.: 'pin DIR' and then 'cd ,'", "Switch color schemes using the 'cs' command", "Try the 'j' command to quickly jump to any visited directory", "Switch workspaces by pressing Alt+[1-4]", "Use the 'ws' command to list available workspaces", "Take a look at available plugins using the 'actions' command", "Space is not required. E.g.: 'p12' instead of 'p 12'", "When searching or selecting files, use the exclamation mark " "to negate a pattern. E.g.: 's !*.pdf'", "Enable the TrashAsRm option to always send removed files to the trash can", "Use the 'n' command to create multiple files/directories. E.g.: 'n file dir/'", "Add prompt commands via the 'promptcmd' keyword: 'config' (F10)", "Need git integration? Consult the manpage", "Accept a given suggestion by pressing the Right arrow key", "Accept only the first suggested word by pressing Alt+f or Alt+Right", "Enter 'c sel' to copy selected files into the current directory", "Press Alt+q to delete the last entered word", "Check ELN ranges by pressing TAB. E.g.: '1-12'", "Operate on specific selected files. E.g.: 'p sel' or 'p s:'", "Use the 'ow' command to open a file using a specific application", "Limit the number of files listed on the screen via the 'mf' command", "Set a maximum filename length for listed files via the MaxFilenameLen " "option in the configuration file (F10)", "Use the 'm' command to interactively rename a file. E.g.: 'm 12'", "Set options on a per-directory basis via the autocommands function. Try 'help autocommands'", "Sanitize non-ASCII filenames using the 'bleach' command", "Get help for internal commands using the -h or --help parameters: 'p -h'", "Enable icons with 'icons on' (or --icons)", "Quickly change to any parent directory using the 'bd' command", "Use 'stats' to print statistics on files in the current directory", "Customize the warning prompt by setting WarningPrompt in the prompts file ('prompt edit')", "Create multiple links at once using the 'bl' command", "Organize your files using tags. Try 'tag --help'", "Remove files in bulk using a text editor with 'rr'", "Easily send files to a remote location with the 'cr' command", "Quickly switch prompts via 'prompt NAME' (or 'prompt set ')", "Press Alt+Tab to toggle the disk usage analyzer mode", "Press Ctrl+Alt+l to toggle max filename length", "Wildcards can be expanded with the TAB key. E.g.: 's *.c'", "Try help topics: 'help '", "List clifm commands, together with a brief description: 'cmd'", "List symlinks in the current directory: '=l'. Try 'help file-filters' for more information", "Use PropFields in the configuration file to customize fields in long view", "Preview files in the current directory using the 'view' command (requires fzf)", "Press Alt+- to launch the file previewer (requires fzf)", "Interactively select files (requires fzf, fnf, or smenu). E.g.: 's /dir/*'", "Change file permissions/ownership using the 'pc' and 'oc' commands respectively", "Set a custom shell to run external commands. E.g.: 'CLIFM_SHELL=/bin/dash clifm'", "Print all tips: 'tips'", "Create files from a template. Run 'n --help' for details.", NULL}; const size_t tipsn = (sizeof(TIPS) / sizeof(TIPS[0])) - 1; if (all == 1) { size_t i; const int l = DIGINUM(tipsn); for (i = 0; i < tipsn; i++) { printf("%s%sTIP %*zu%s: %s\n", conf.colorize == 1 ? df_c : "", conf.colorize == 1 ? BOLD : "", l, i, conf.colorize == 1 ? df_c : "", TIPS[i]); } return; } #ifndef HAVE_ARC4RANDOM srandom((unsigned int)time(NULL)); const long tip_num = random() % (int)tipsn; #else const uint32_t tip_num = arc4random_uniform((uint32_t)tipsn); #endif /* !HAVE_ARC4RANDOM */ printf("%s%sTIP%s: %s\n", conf.colorize == 1 ? df_c : "", conf.colorize == 1 ? BOLD : "", conf.colorize == 1 ? df_c : "", TIPS[tip_num]); } /* Retrieve pager path, first from PAGER, then try less(1), and finally * more(1). If none is found return NULL. */ static char * get_pager(void) { char *pager_cmd = (char *)NULL; char *p = getenv("PAGER"); if (p) { char *s = strchr(p, ' '); if (s) *s = '\0'; pager_cmd = savestring(p, strlen(p)); return pager_cmd; } p = get_cmd_path("less"); if (p) { pager_cmd = savestring(p, strlen(p)); free(p); return pager_cmd; } p = get_cmd_path("more"); if (p) { pager_cmd = savestring(p, strlen(p)); free(p); return pager_cmd; } return (char *)NULL; } /* Help topics */ static void print_more_info(void) { puts(_("For more information consult the manpage and/or the Wiki:\n" "https://github.com/leo-arch/clifm/wiki")); } static int print_archives_topic(void) { puts(ARCHIVE_USAGE); return FUNC_SUCCESS; } static int print_autocmds_topic(void) { puts(AUTOCMDS_USAGE); putchar('\n'); print_more_info(); return FUNC_SUCCESS; } static int print_basics_topic(void) { printf(_("Run '?' or 'help' to get started with %s\n"), PROGRAM_NAME); return FUNC_SUCCESS; } static int print_bookmarks_topic(void) { puts(BOOKMARKS_USAGE); return FUNC_SUCCESS; } static int print_commands_topic(void) { printf("%s%s", CLIFM_COMMANDS_HEADER, CLIFM_COMMANDS); return FUNC_SUCCESS; } static int print_desktop_notifications_topic(void) { puts(DESKTOP_NOTIFICATIONS_USAGE); return FUNC_SUCCESS; } static int print_dir_jumper_topic(void) { puts(JUMP_USAGE); return FUNC_SUCCESS; } static int print_file_tags_topic(void) { puts(TAG_USAGE); return FUNC_SUCCESS; } static int print_file_attributes_topic(void) { puts(FILE_DETAILS); putchar('\n'); puts(FILE_SIZE_USAGE); putchar('\n'); puts(FILTER_USAGE); return FUNC_SUCCESS; } static int print_file_filters_topic(void) { puts(FILTER_USAGE); return FUNC_SUCCESS; } static int print_file_previews_topic(const int image_prevs) { puts(image_prevs == 1 ? IMAGE_PREVIEWS : FILE_PREVIEWS); putchar('\n'); print_more_info(); return FUNC_SUCCESS; } static int print_navigation_topic(void) { puts(_("Run '?' and consult the NAVIGATION section")); return FUNC_SUCCESS; } static int print_plugins_topic(void) { puts(ACTIONS_USAGE); putchar('\n'); print_more_info(); return FUNC_SUCCESS; } static int print_profiles_topic(void) { puts(PROFILES_USAGE); return FUNC_SUCCESS; } static int print_remotes_topic(void) { puts(NET_USAGE); return FUNC_SUCCESS; } static int print_resource_opener_topic(void) { puts(MIME_USAGE); return FUNC_SUCCESS; } static int print_security_topic(void) { puts(SECURITY_USAGE); putchar('\n'); print_more_info(); return FUNC_SUCCESS; } static int print_selection_topic(void) { puts(SEL_USAGE); return FUNC_SUCCESS; } static int print_search_topic(void) { puts(SEARCH_USAGE); return FUNC_SUCCESS; } static int print_theming_topic(void) { puts(_("Take a look at the 'colorschemes', 'prompt', and 'config' commands")); print_more_info(); return FUNC_SUCCESS; } static int print_trash_topic(void) { puts(TRASH_USAGE); return FUNC_SUCCESS; } static int run_help_topic(const char *topic) { if (IS_HELP(topic)) { puts(HELP_USAGE); return FUNC_SUCCESS; } if (*topic == 'a' && strcmp(topic, "archives") == 0) return print_archives_topic(); if (*topic == 'a' && strcmp(topic, "autocommands") == 0) return print_autocmds_topic(); if (*topic == 'b' && strcmp(topic, "basics") == 0) return print_basics_topic(); if (*topic == 'b' && strcmp(topic, "bookmarks") == 0) return print_bookmarks_topic(); if (*topic == 'c' && strcmp(topic, "commands") == 0) return print_commands_topic(); if (*topic == 'd' && strcmp(topic, "desktop-notifications") == 0) return print_desktop_notifications_topic(); if (*topic == 'd' && strcmp(topic, "dir-jumper") == 0) return print_dir_jumper_topic(); if (*topic == 'f' && strcmp(topic, "file-details") == 0) return print_file_attributes_topic(); if (*topic == 'f' && strcmp(topic, "file-filters") == 0) return print_file_filters_topic(); if (*topic == 'f' && strcmp(topic, "file-previews") == 0) return print_file_previews_topic(0); if (*topic == 'i' && strcmp(topic, "image-previews") == 0) return print_file_previews_topic(1); if (*topic == 'f' && strcmp(topic, "file-tags") == 0) return print_file_tags_topic(); if (*topic == 'n' && strcmp(topic, "navigation") == 0) return print_navigation_topic(); if (*topic == 'p' && strcmp(topic, "plugins") == 0) return print_plugins_topic(); if (*topic == 'p' && strcmp(topic, "profiles") == 0) return print_profiles_topic(); if (*topic == 'r' && strcmp(topic, "remotes") == 0) return print_remotes_topic(); if (*topic == 'r' && strcmp(topic, "resource-opener") == 0) return print_resource_opener_topic(); if (*topic == 's' && strcmp(topic, "security") == 0) return print_security_topic(); if (*topic == 's' && strcmp(topic, "selection") == 0) return print_selection_topic(); if (*topic == 's' && strcmp(topic, "search") == 0) return print_search_topic(); if (*topic == 't' && strcmp(topic, "theming") == 0) return print_theming_topic(); if (*topic == 't' && strcmp(topic, "trash") == 0) return print_trash_topic(); xerror("%s: help: '%s': No such help topic\n", PROGRAM_NAME, topic); return FUNC_FAILURE; } int quick_help(const char *topic) { if (topic && *topic) return run_help_topic(topic); char *pager_app = (char *)NULL; if (xargs.stealth_mode == 1 || !(pager_app = get_pager())) { printf("%s %s\n\n%s\n\n%s", ASCII_LOGO, PROGRAM_NAME_UPPERCASE, QUICK_HELP_HEADER, QUICK_HELP_NAVIGATION); printf("\n\n%s\n\n%s\n", QUICK_HELP_BASIC_OPERATIONS, QUICK_HELP_MISC); return FUNC_SUCCESS; } char tmp_file[PATH_MAX + 1]; snprintf(tmp_file, sizeof(tmp_file), "%s/%s", xargs.stealth_mode == 1 ? P_tmpdir : tmp_dir, TMP_FILENAME); int fd = mkstemp(tmp_file); if (fd == -1) { xerror("%s: Error creating temporary file '%s': %s\n", PROGRAM_NAME, tmp_file, strerror(errno)); free(pager_app); return FUNC_FAILURE; } FILE *fp = fdopen(fd, "w"); if (!fp) { xerror("%s: '%s': %s\n", PROGRAM_NAME, tmp_file, strerror(errno)); free(pager_app); if (unlinkat(fd, tmp_file, 0) == -1) xerror("%s: '%s': %s\n", PROGRAM_NAME, tmp_file, strerror(errno)); return FUNC_FAILURE; } fprintf(fp, "%s %s\n\n%s\n\n%s", ASCII_LOGO, PROGRAM_NAME_UPPERCASE, QUICK_HELP_HEADER, QUICK_HELP_NAVIGATION); fprintf(fp, "\n\n%s\n\n%s", QUICK_HELP_BASIC_OPERATIONS, QUICK_HELP_MISC); fclose(fp); int ret = 0; char *s = strrchr(pager_app, '/'); char *p = (s && *(++s)) ? s : pager_app; if (*p == 'l' && strcmp(p, "less") == 0) { char *cmd[] = {pager_app, "-FIRXP?e\\(END\\):CLIFM", tmp_file, NULL}; ret = launch_execv(cmd, FOREGROUND, E_NOFLAG); } else { char *cmd[] = {pager_app, tmp_file, NULL}; ret = launch_execv(cmd, FOREGROUND, E_NOFLAG); } free(pager_app); if (unlink(tmp_file) == -1) err('w', PRINT_PROMPT, "help: '%s': %s\n", tmp_file, strerror(errno)); if (ret != FUNC_SUCCESS) return ret; if (conf.autols == 1) reload_dirlist(); return FUNC_SUCCESS; } __attribute__ ((noreturn)) void help_function(void) { fputs(NC, stdout); printf("%s\n", ASCII_LOGO); printf(_("%s %s (%s), by %s\n"), PROGRAM_NAME, VERSION, DATE, AUTHOR); #ifdef _BE_POSIX printf("\nUSAGE: %s %s\n%s\n", PROGRAM_NAME, GRAL_USAGE, _(OPTIONS_LIST)); #else printf("\nUSAGE: %s %s\n%s%s%s", PROGRAM_NAME, GRAL_USAGE, _(SHORT_OPTIONS), _(LONG_OPTIONS_A), _(LONG_OPTIONS_B)); #endif /* _BE_POSIX */ puts("\nBUILT-IN COMMANDS:\n"); puts(_(CLIFM_COMMANDS_HEADER)); puts(_(CLIFM_COMMANDS)); puts(_(CLIFM_KEYBOARD_SHORTCUTS)); puts(_(HELP_END_NOTE)); exit(FUNC_SUCCESS); } clifm-1.26.3/src/help.h000066400000000000000000000021011506632037700145700ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* help.h */ #ifndef HELP_H #define HELP_H __BEGIN_DECLS int list_commands(void); void print_tips(const int all); int quick_help(const char *topic); void help_function(void); __END_DECLS #endif /* HELP_H */ clifm-1.26.3/src/helpers.h000066400000000000000000001672011506632037700153170ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* helpers.h -- main header file */ #ifndef HELPERS_H #define HELPERS_H #define PROGRAM_NAME_UPPERCASE "Clifm" #define PROGRAM_NAME "clifm" #define PROGRAM_DESC "The command line file manager" #define VERSION "1.26.3" #define DATE "Sep 28, 2025" #define AUTHOR "L. Abramovich" #define CONTACT "https://github.com/leo-arch/clifm" #define LICENSE "GPL2+" #define COLORS_REPO "https://github.com/leo-arch/clifm-colors" /* POSIX_STRICT: A more descriptive name for _BE_POSIX */ #if defined(POSIX_STRICT) || defined(_POSIX_C_SOURCE) || defined(_XOPEN_SOURCE) # define _BE_POSIX #endif /* POSIX_STRICT || _POSIX_C_SOURCE || _XOPEN_SOURCE */ #ifdef _BE_POSIX # ifndef _POSIX_C_SOURCE # define _POSIX_C_SOURCE 200809L # endif /* !_POSIX_C_SOURCE */ # ifndef _XOPEN_SOURCE # define _XOPEN_SOURCE 700 # endif /* !_XOPEN_SOURCE */ # if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) \ || defined(__DragonFly__) || defined(__APPLE__) typedef unsigned char u_char; typedef unsigned short u_short; typedef unsigned int u_int; typedef unsigned long u_long; # ifdef __NetBSD__ /* scandir, alphasort, and dirfd are POSIX (not even XSI extensions). Why * hidden behind _NETBSD_SOURCE? */ # define _NETBSD_SOURCE # endif /* __NetBSD__ */ # elif defined(__sun) # define __EXTENSIONS__ # endif /* BSD */ #else /* !POSIX */ # if defined(__linux__) || defined(__CYGWIN__) # define _GNU_SOURCE # elif defined(__APPLE__) # define _DARWIN_C_SOURCE # endif /* __linux__ || __CYGWIN__ */ #endif /* _BE_POSIX */ #ifndef __BEGIN_DECLS # ifdef __cpluplus # define __BEGIN_DECLS extern "C" { # else # define __BEGIN_DECLS # endif /* __cplusplus */ #endif /* !__BEGIN_DECLS */ #ifndef __END_DECLS # ifdef __cpluplus # define __END_DECLS } # else # define __END_DECLS # endif /* __cplusplus */ #endif /* !__END_DECLS */ #ifdef __TINYC__ # define __STDC_NO_VLA__ 1 //# include #endif /* __TINYC__ */ #define _FILE_OFFSET_BITS 64 /* Support large files */ #define _TIME_BITS 64 /* Address Y2038 problem in 32-bit machines */ #define xstrcasestr strcasestr #ifdef _BE_POSIX # undef xstrcasestr # define xstrcasestr x_strcasestr # ifndef _NO_GETTEXT # define _NO_GETTEXT # endif /* !_NO_GETTEXT */ # ifndef _NO_MAGIC # define _NO_MAGIC # endif /* !_NO_MAGIC */ #endif /* _BE_POSIX */ /* _NO_LIRA implies _NO_MAGIC */ #if defined(_NO_LIRA) && !defined(_NO_MAGIC) # define _NO_MAGIC #endif /* _NO_LIRA && !_NO_MAGIC */ #if defined(USE_DU1) # if (defined(__linux__) || defined(__CYGWIN__) || defined(__HAIKU__)) \ && !defined(_BE_POSIX) /* du(1) can report sizes in bytes, apparent sizes, and take custom block sizes */ # define HAVE_GNU_DU # endif /* (__linux__ || __CYGWIN__ || __HAIKU__) && !_BE_POSIX */ #endif /* USE_DU1 */ #ifndef _NO_GETTEXT # include #endif /* !_NO_GETTEXT*/ #include #include #include #include #include #include /* S_BLKSIZE */ #include /* ssize_t */ #include /* AT_* constants (like AT_FDCWD) */ /* Included here to test _DIRENT_HAVE_D_TYPE and DT macros. */ #include #if !defined(__GLIBC__) && !defined(_DIRENT_HAVE_D_TPYE) # if !defined(__sun) && !defined(__HAIKU__) # define _DIRENT_HAVE_D_TYPE # endif /* !__sun && !__HAIKU__ */ #endif /* !__GLIBC__ && !_DIRENT_HAVE_D_TYPE */ #if defined(_BE_POSIX) && defined(_DIRENT_HAVE_D_TYPE) # undef _DIRENT_HAVE_D_TYPE #endif /* _BE_POSIX && _DIRENT_HAVE_D_TYPE */ #if !defined(TIGHT_COLUMNS) && !defined(NO_TIGHT_COLUMNS) # define TIGHT_COLUMNS #endif /* !TIGHT_COLUMNS && !NO_TIGHT_COLUMNS */ #ifdef CLIFM_LEGACY /* Replace functions not available before POSIX-1.2008. More precisely, * let's try to be POSIX-1.2001 compliant. This is still experimental: * a crash was reported due to x_scandir(), the scandir(3) replacement * (see https://github.com/leo-arch/clifm/discussions/254). */ # include "compat.h" # define xrealpath old_realpath #else # define xrealpath realpath #endif /* CLIFM_LEGACY */ #ifdef __sun /* Solaris/Illumos defines AT_FDCWD as 0xffd19553 (-3041965); without the int * cast, the value gets interpreted as uint (4291925331), which throws compiler * warnings. See https://github.com/python/cpython/issues/60169 */ # define XAT_FDCWD (int)AT_FDCWD # ifndef _BE_POSIX # define SOLARIS_DOORS # endif /* !_BE_POSIX */ #else # define XAT_FDCWD AT_FDCWD /* defined in fcntl.h */ #endif /* __sun */ #if !defined(_DIRENT_HAVE_D_TYPE) || !defined(DT_DIR) /* Systems not providing a d_type member for the stat struct do not provide * these macros either. We use them to convert an st_mode value to the * appropriate d_type value (via get_dt()). */ # define DT_UNKNOWN 0 # define DT_FIFO 1 # define DT_CHR 2 # define DT_DIR 4 # define DT_BLK 6 # define DT_REG 8 # define DT_LNK 10 # define DT_SOCK 12 # define DT_WHT 14 # ifdef __sun # define DT_DOOR 16 # define DT_PORT 18 /* Event port */ # endif /* __sun */ #endif /* !_DIRENT_HAVE_D_TYPE || !DT_DIR */ /* Some extra file types */ #define DT_SHM 100 /* Shared memory object file */ #define DT_SEM 102 /* Semaphore file */ #define DT_MQ 104 /* Message queue file */ #define DT_TPO 106 /* Typed memory object file */ #ifdef S_ARCH1 # define DT_ARCH1 108 /* Archive state 1 (NetBSD) */ # define DT_ARCH2 110 /* Archive state 2 (NetBSD) */ #endif /* S_ARCH1 */ #ifndef DT_WHT # define DT_WHT 14 /* Whiteout (FreeBSD/NetBSD/DragonFly/MacOS)*/ #endif /* DT_WHT */ /* If any of these file type checks isn't available, fake it */ #ifndef S_TYPEISMQ # define S_TYPEISMQ(s) (0) #endif /* !S_TYPEISMQ */ #ifndef S_TYPEISSEM # define S_TYPEISSEM(s) (0) #endif /* !S_TYPEISSEM */ #ifndef S_TYPEISSHM # define S_TYPEISSHM(s) (0) #endif /* !S_TYPEISSHM */ #ifndef S_TYPEISTMO # define S_TYPEISTMO(s) (0) #endif /* !S_TYPEISTMO */ /* About these extra file types see * https://pubs.opengroup.org/onlinepubs/007904875/basedefs/sys/stat.h.html * NOTE: On Linux/Solaris, all these macros always evaluate to zero (false). * They don't seem to be present on BSD systems either. * However, the following coreutils programs perform checks for these * file types (mostly S_TYPEISSHM): split(1), sort(1), shred(1), dd(1), * du(1), head(1), tail(1), truncate(1), od(1), wc(1), and shuf(1). */ /* ASCII representation of these file types: * 'F': semaphore * 'Q': message queue * 'S': Shared memory object * 'T': Typed memory object */ /* Other non-standard file types: if (S_ISCTG(mode)) return 'C'; high performance (contiguous data) file if (S_ISMPB(mode) || S_ISMPC (bits) || S_ISMPX (bits)) return 'm'; // V7 if (S_ISNWK(mode)) return 'n'; // HP/UX: network special file * S_IFNAM // Solaris/XENIX: special named file * S_INSEM // Solaris/XENIX: semaphore subtype of IFNAM * S_INSHD // Solaris/XENIX: shared data subtype of IFNAM * S_IFDB // DragonFly: Database record file (DT_DBF). Recognized by neither ls nor find * * For a quite comphensive list of non-standard file types see: * https://github.com/python/cpython/issues/55225#issuecomment-1093532804 */ /* Setting GLOB_BRACE to ZERO disables support for GLOB_BRACE if not * available on current platform. Same for GLOB_TILDE. */ #ifndef GLOB_BRACE # define GLOB_BRACE 0 #endif /* GLOB_BRACE */ #ifndef GLOB_TILDE # define GLOB_TILDE 0 #endif /* GLOB_TILDE */ #if defined(__linux__) # include # include # if !defined(__GLIBC__) || (__GLIBC__ > 2 \ || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 9)) \ && LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) # define HAVE_INOTIFY # endif /* GLIBC >= 2.9 && linux >= 2.6.27 */ #elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) \ || defined(__DragonFly__) || defined(__APPLE__) # include # include # include # if defined(__FreeBSD__) && __FreeBSD_version >= 410000 # define HAVE_KQUEUE # elif defined(__NetBSD__) # if __NetBSD_Prereq__(2,0,0) # define HAVE_KQUEUE # endif /* NetBSD >= 2.0 */ # elif defined(__OpenBSD__) && OpenBSD >= 200106 /* version 2.9 */ # define HAVE_KQUEUE # elif defined(__DragonFly__) && __DragonFly_version >= 200800 /* At least 2.8*/ # define HAVE_KQUEUE # elif defined(__APPLE__) # define HAVE_KQUEUE # endif /* FreeBSD >= 4.1 */ #elif defined(__sun) || defined(__CYGWIN__) # include #elif defined(__HAIKU__) # include /* uint8_t */ #endif /* __linux__ */ #if !defined(_BE_POSIX) # if defined(__GLIBC__) \ || (defined(__FreeBSD__) && __FreeBSD_version >= 604000) \ || (defined(__OpenBSD__) && OpenBSD >= 200805) \ || (defined(__sun) && defined(SUN_VERSION) && SUN_VERSION >= 511) # define HAVE_MEMRCHR /* OpenBSD 200805 == version 4.3 */ # elif defined(__NetBSD__) # if __NetBSD_Prereq__(6,0,0) # define HAVE_MEMRCHR # endif # endif /* __GLIBC__ */ #endif /* !_BE_POSIX */ #if defined(__OpenBSD__) || defined(__NetBSD__) \ || defined(__FreeBSD__) || defined(__APPLE__) # include /* uintmax_t, intmax_t */ #endif /* BSD */ /* Filesystem event monitors (inotify and kqueue) are OS-specific. * Let's fallback to our own generic monitor. */ #if defined(_BE_POSIX) && !defined(USE_GENERIC_FS_MONITOR) # define USE_GENERIC_FS_MONITOR #endif /* _BE_POSIX && !USE_GENERIC_FS_MONITOR */ #if defined(__linux__) # if defined(HAVE_INOTIFY) && !defined(USE_GENERIC_FS_MONITOR) # include # define LINUX_INOTIFY # else # include /* uint8_t */ # endif /* HAVE_INOTIFY && !USE_GENERIC_FS_MONITOR */ #endif /* __linux__ */ #if defined(HAVE_KQUEUE) && !defined(USE_GENERIC_FS_MONITOR) # include # define BSD_KQUEUE #endif /* HAVE_KQUEUE && !USE_GENERIC_FS_MONITOR */ /* Before MacOS X 10.10, renameat(2) is declared in sys/stdio.h */ #if defined(__APPLE__) && !defined(CLIFM_LEGACY) # include # if MAC_OS_X_VERSION_MIN_REQUIRED < 101000 # define MAC_OS_X_RENAMEAT_SYS_STDIO_H # endif /* MACOS_X < 10.10 */ #endif /* __APPLE__ */ #include "strings.h" #include "settings.h" #include "term.h" /* General exit codes for functions */ #define FUNC_SUCCESS 0 /* True/success */ #define FUNC_FAILURE 1 /* False/error */ #ifndef PATH_MAX # ifdef __linux__ # define PATH_MAX 4096 # else # ifdef MAXPATHLEN # define PATH_MAX MAXPATHLEN # else # define PATH_MAX 1024 # endif /* MAXPATHLEN */ # endif /* __linux__ */ #endif /* !PATH_MAX */ #ifndef HOST_NAME_MAX # if defined(__ANDROID__) # define HOST_NAME_MAX 255 # else # define HOST_NAME_MAX 64 # endif /* __ANDROID__ */ #endif /* !HOST_NAME_MAX */ #ifndef NAME_MAX # define NAME_MAX 255 #endif /* !NAME_MAX */ /* Used by FILE_SIZE and FILE_SIZE_PTR macros to calculate file sizes */ #ifndef S_BLKSIZE /* Not defined in Termux/Solaris */ # include # ifdef DEV_BSIZE # define S_BLKSIZE DEV_BSIZE # else # define S_BLKSIZE 512 # endif /* DEV_BSIZE */ #endif /* !S_BLKSIZE */ /* Linux-glibc/FreeBSD/NetBSD/OpenBSD: S_BLKSIZE/DEV_BSIZE = 512. * CYGWIN: S_BLKSIZE/DEV_BSIZE = 1024. * Solaris/Termux/Linux-musl: S_BLKSIZE is unset, DEV_BSIZE = 512. * DragonFly/MacOS/Haiku: S_BLKSIZE = 512 (DEV_BSIZE is unset). */ #ifndef ARG_MAX # ifdef __linux__ # define ARG_MAX (128 * 1024) # else # define ARG_MAX (512 * 1024) # endif /* __linux__ */ #endif /* !ARG_MAX */ #if defined(__linux__) && !defined(_BE_POSIX) # if defined(STATX_TYPE) && (!defined(__ANDROID__) || __ANDROID_API__ >= 30) # define LINUX_STATX # endif /* STATX_TYPE */ # if !defined(__GLIBC__) || (__GLIBC__ > 2 \ || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 3)) # if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) # define LINUX_FILE_XATTRS # endif /* LINUX_VERSION (2.4) */ # endif /* !__GLIBC__ || __GLIBC__ >= 2.3 */ # if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24) # define LINUX_FILE_CAPS # endif /* LINUX_VERSION (2.6.24)*/ # ifndef __TERMUX__ # define LINUX_FILE_ATTRS # endif /* !__TERMUX__ */ #endif /* __linux__ && !_BE_POSIX */ /* Do we have files birth time? If yes, define ST_BTIME. */ /* ST_BTIME is the timespec struct for files creation time. Valid fields are * tv_sec and tv_nsec. */ #ifndef _BE_POSIX # ifdef LINUX_STATX # define ST_BTIME stx_btime /* OpenBSD defines the interface (see sys/stat.h), but the filesystem doesn't * actually store creation times: the value of __st_birthtim is always zero. #elif defined(__OpenBSD__) # define ST_BTIME __st_birthtim */ # elif defined(__NetBSD__) # define ST_BTIME st_birthtimespec # elif defined(__APPLE__) # include # if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060 # define ST_BTIME st_birthtimespec # endif # elif defined(__FreeBSD__) || defined(__CYGWIN__) # define ST_BTIME st_birthtim # elif defined(__HAIKU__) # define ST_BTIME st_crtim # elif defined(__sun) && !defined(_NO_SUN_BIRTHTIME) /* In the case of Solaris, ST_BTIME is just a flag telling we should run * get_birthtime() to get files creation time. */ # define ST_BTIME # endif /* LINUX_STATX */ #endif /* !_BE_POSIX */ /* Do we have birth time when running in long view AND light mode? Only if * the timestamp is provided directly by stat(2). * For the time being, we need an extra call (statx(2)) on Linux. This should * be fixed. */ #if defined(ST_BTIME) && !defined(LINUX_STATX) && !defined(__sun) # define ST_BTIME_LIGHT #endif /* ST_BTIME && !LINUX_STATX && !__sun */ /* Filesystem events handling */ #if defined(LINUX_INOTIFY) # define NUM_EVENT_SLOTS 32 /* Make room for 32 events */ # define EVENT_SIZE (sizeof(struct inotify_event)) # define EVENT_BUF_LEN (EVENT_SIZE * NUM_EVENT_SLOTS) extern int inotify_fd, inotify_wd; extern unsigned int INOTIFY_MASK; extern int watch; #elif defined(BSD_KQUEUE) # define NUM_EVENT_SLOTS 10 # define NUM_EVENT_FDS 10 extern int kq, event_fd; extern struct kevent events_to_monitor[]; extern unsigned int KQUEUE_FFLAGS; extern struct timespec timeout; extern int watch; #else # define GENERIC_FS_MONITOR extern time_t curdir_mtime; #endif /* LINUX_INOTIFY */ /* Do we have arc4random_uniform(3). If not, fallback to random(3). */ #if !defined(_NO_ARC4RANDOM) && !defined(_BE_POSIX) && !defined(__HAIKU__) # if defined(__FreeBSD__) && __FreeBSD_version >= 800041 # define HAVE_ARC4RANDOM # elif defined(__NetBSD__) # if __NetBSD_Prereq__(6,0,0) # define HAVE_ARC4RANDOM # endif /* NetBSD >= 6.0 */ # elif defined(__OpenBSD__) && OpenBSD >= 200806 /* version 4.4 */ # define HAVE_ARC4RANDOM # elif defined(__DragonFly__) && __DragonFly_version >= 400600 /* At least since 4.6 (Sep 2016). See https://gitweb.dragonflybsd.org/dragonfly.git/commitdiff/a2cdfb90273ff84696f4103580173cce21c12e2b * It might be less though. */ # define HAVE_ARC4RANDOM # elif defined(__sun) && defined(SUN_VERSION) && SUN_VERSION >= 511 /* 5.11 at least: it might be less. */ # define HAVE_ARC4RANDOM # elif defined(__linux__) && defined(__GLIBC__) && (__GLIBC__ > 2 \ || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 36)) # define HAVE_ARC4RANDOM # elif defined(__CYGWIN__) || (defined(__linux__) && defined(__ANDROID__)) # define HAVE_ARC4RANDOM # endif /* __FreeBSD__ */ #endif /* !_NO_ARC4RANDOM && !_BE_POSIX && !__HAIKU__ */ #if !defined(_BE_POSIX) && (defined(__FreeBSD__) || defined(__OpenBSD__) \ || defined(__DragonFly__) || defined(__APPLE__)) # define HAVE_STATFS #endif #if !defined(_BE_POSIX) && !defined(NO_PLEDGE) \ && defined(__OpenBSD__) && OpenBSD >= 201603 /* 5.9? CHECK! */ # define HAVE_PLEDGE #endif #if !defined(_BE_POSIX) && (defined(__linux__) || defined(__CYGWIN__)) # define LINUX_FSINFO #endif #define DEV_NO_NAME "-" /* String used when no filesystem name/type is found */ #define TRUECOLOR_NUM 16777216 /* This is a more or less arbitrary value, but better than some huge value * like INT_MAX (which most likely will cause problems long before reaching * this value). */ #define MAX_SHELL_LEVEL 1000 /* This is the value used by bash 5.2 */ #define MAX_UMASK 0777 #define MAX_SEL INT_MAX #define MAX_TRASH INT_MAX #define MAX_BOOKMARKS INT_MAX /* Max length of a file size in human format */ #define MAX_HUMAN_SIZE 10 /* "1023.99YB\0" */ /* The following flags are used via an integer (FLAGS). If an integer has * 4 bytes, then we can use a total of 32 flags (0-31) * 4 * 8 == 32 bits == (1 << 31) * NOTE: setting (1 << 31) gives a negative value: DON'T USE * NOTE 2: What if int size isn't 4 bytes or more, but 2 (16 bits)? In this * case, if we want to support old 16 bit machines, we shouldn't use more than * 16 bits per flag, that is (1 << 15) */ /* Internal flags */ #define GUI (1 << 0) #define IS_USRVAR_DEF (1 << 1) /* Used by the refresh on resize feature */ #define DELAYED_REFRESH (1 << 2) #define FIRST_WORD_IS_ELN (1 << 3) #define IN_BOOKMARKS_SCREEN (1 << 4) #define STATE_COMPLETING (1 << 5) /* Instead of a completion for the current query, a BAEJ suggestion points to * a possible completion as follows: QUERY > COMPLETION */ #define BAEJ_SUGGESTION (1 << 6) #define STATE_SUGGESTING (1 << 7) #define IN_SELBOX_SCREEN (1 << 8) #define MULTI_SEL (1 << 9) #define PREVIEWER (1 << 10) #define NO_FIX_RL_POINT (1 << 11) #define FAILED_ALIAS (1 << 12) #define ALT_PREVIEW_FILE (1 << 13) #define UEBERZUG_IMG_PREV (1 << 14) /* Flags for third party binaries */ #define FZF_BIN_OK (1 << 0) #define FNF_BIN_OK (1 << 1) #define SMENU_BIN_OK (1 << 2) #ifdef USE_DU1 #define GNU_DU_BIN_DU (1 << 3) /* 'gdu' is the GNU version of 'du' used by BSD systems */ #define GNU_DU_BIN_GDU (1 << 4) #endif /* USE_DU1 */ /* In BSD/Solaris systems, GNU utilities are provided as gcp, gmv, grm, * gdu, etc. * NOTE: Both FreeBSD and DragonFly native utilities provide all the * functionalities we need, so that there's no need to check for the * GNU versions. */ #define BSD_HAVE_COREUTILS (1 << 5) #if (defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__) \ || defined(__sun)) && !defined(_BE_POSIX) # define CHECK_COREUTILS #endif /* (__OpenBSD__ || __NetBSD__ || __APPLE__ || __sun) && !_BE_POSIX */ /* Flag to control the search function behavior */ #define NO_GLOB_CHAR (1 << 0) /* Control show hidden files mode (true, false, first, last) */ #define HIDDEN_FALSE 0 #define HIDDEN_TRUE 1 #define HIDDEN_FIRST 2 #define HIDDEN_LAST 3 #define DESKTOP_NOTIF_NONE 0 #define DESKTOP_NOTIF_SYSTEM 1 #define DESKTOP_NOTIF_KITTY 2 /* Search strategy */ #define GLOB_ONLY 0 #define REGEX_ONLY 1 #define GLOB_REGEX 2 #define GLOB_CHARS "*?[{" #define GLOB_REGEX_CHARS "*?[{|^+$." /* Possible values for PagerView (conf.pager_view) */ #define PAGER_AUTO 0 #define PAGER_LONG 1 #define PAGER_SHORT 2 /* ClearScreen=internal: clear screen only if command is internal */ #define CLEAR_INTERNAL_CMD_ONLY 2 /* Used by log_msg() to know wether to tell prompt() to print messages or not */ #define PRINT_PROMPT 1 #define NOPRINT_PROMPT 0 /* Terminal columns taken by the last line of the default prompt */ #define FALLBACK_PROMPT_OFFSET 6 /* A few macros for the err function */ #define ERR_NO_LOG (-1) /* err prints but doesn't log */ #define ERR_NO_STORE (-2) /* err prints and logs, but doesn't store the msg into the messages array */ /* Macros for xchdir (for setting term title or not) */ #define SET_TITLE 1 #define NO_TITLE 0 /* Macros for cd_function */ #define CD_PRINT_ERROR 1 #define CD_NO_PRINT_ERROR 0 /* Macros for the count_dir function. CPOP tells the function to only * check if a given directory is populated (it has at least 3 files) */ #define CPOP 1 #define NO_CPOP 0 #define BACKGROUND 1 #define FOREGROUND 0 #define EXEC_BG_PROC 0 #define EXEC_FG_PROC 1 #define E_NOEXEC 126 #define E_NOTFOUND 127 #define E_SIGINT 128 #define NOTFOUND_MSG "Command not found" #define NOEXEC_MSG "Permission denied" /* A few fixed colors */ #define BOLD ((xargs.no_bold != 1 && conf.colorize == 1) ? "\x1b[1m" : "") /* NC: Reset color attributes to terminal defaults */ #define NC (conf.colorize == 1 ? "\x1b[0m" : "") /* \001 and \002 tell readline that color codes between them are * non-printing chars. This is specially useful for the prompt, i.e., * when passing color codes to readline. */ #define RL_NC "\001\x1b[0m\002" #define SET_MSG_PTR (term_caps.unicode == 1 ? MSG_PTR_STR_U : MSG_PTR_STR) #define SET_SUCCESS_PTR (term_caps.unicode == 1 ? SUCCESS_PTR_STR_U : SUCCESS_PTR_STR) #define SET_MISC_PTR (term_caps.unicode == 1 ? MISC_PTR_U : MISC_PTR) /* Unused #define SET_ERROR_PTR (term_caps.unicode == 1 ? ERROR_PTR_STR_U : ERROR_PTR_STR) */ #define UNSET (-1) /* Macros for the update_autocmd_opts() function */ #define AC_COLOR_SCHEME 0 #define AC_FILES_COUNTER 1 #define AC_FILTER 2 #define AC_FULL_DIR_SIZE 3 #define AC_LIGHT_MODE 4 #define AC_LONG_VIEW 5 #define AC_MAX_FILES 6 #define AC_MAX_NAME_LEN 7 #define AC_ONLY_DIRS 8 #define AC_PAGER 9 #define AC_SHOW_HIDDEN 10 #define AC_SORT 11 /* Macros for the cp and mv cmds */ #define CP_CP 0 /* cp -Rp */ #define CP_CP_FORCE 1 /* cp -Rp */ #define CP_ADVCP 2 /* advcp -gRp */ #define CP_ADVCP_FORCE 3 /* advcp -gRp */ #define CP_WCP 4 /* wcp */ #define CP_RSYNC 5 /* rsync -avP */ #define CP_CMD_AVAILABLE 6 #define MV_MV 0 /* mv */ #define MV_MV_FORCE 1 /* mv */ #define MV_ADVMV 2 /* advmv -g */ #define MV_ADVMV_FORCE 3 /* advmv -g */ #define MV_CMD_AVAILABLE 4 /* Macros for LinkCreationMode */ #define LNK_CREAT_REG 0 /* Like ln -s */ #define LNK_CREAT_REL 1 /* Like ln -rs */ #define LNK_CREAT_ABS 2 /* Create absolute target */ /* Macros for listing_mode */ #define VERTLIST 0 /* ls-like listing mode */ #define HORLIST 1 /* Sort macros */ #define SNONE 0 #define SNAME 1 #define STSIZE 2 #define SATIME 3 #define SBTIME 4 #define SCTIME 5 #define SMTIME 6 #define SVER 7 #define SEXT 8 #define SINO 9 #define SOWN 10 #define SGRP 11 #define SBLK 12 #define SLNK 13 #define STYPE 14 #define SORT_TYPES 14 /* Macros for the colors_list function */ #define NO_ELN 0 #define NO_NEWLINE 0 #define NO_PAD 0 #define PRINT_NEWLINE 1 /* A few key macros used by the auto-suggestions system */ #define KEY_ESC 27 #define KEY_TAB 9 #define KEY_BACKSPACE 8 #define KEY_DELETE 127 #define KEY_ENTER 13 /* Macros to specify suggestions type */ #define NO_SUG 0 #define HIST_SUG 1 #define FILE_SUG 2 #define CMD_SUG 3 #define INT_CMD 4 #define COMP_SUG 5 #define BOOKMARK_SUG 6 #define ALIAS_SUG 7 #define ELN_SUG 8 #define FIRST_WORD 9 #define JCMD_SUG 10 /*#define JCMD_SUG_NOACD 11 // No auto-cd */ #define VAR_SUG 12 #define SEL_SUG 13 #define BACKDIR_SUG 14 #define TAGT_SUG 15 /* t:TAG (expand tag TAG) */ #define TAGC_SUG 16 /* :TAG (param to tag command) */ #define TAGS_SUG 17 /* TAG (param to tag command) */ #define BM_NAME_SUG 18 /* Bookmark names */ #define SORT_SUG 19 #define PROMPT_SUG 20 #define USER_SUG 21 #define WS_NUM_SUG 22 /* Workspace number */ #define WS_NAME_SUG 23 /* Workspace name */ #define FASTBACK_SUG 24 #define FUZZY_FILENAME 25 #define CMD_DESC_SUG 26 #define NET_SUG 27 #define CSCHEME_SUG 28 #define INT_HELP_SUG 29 #define PROFILE_SUG 30 #define BM_PREFIX_SUG 31 /* Bookmark name (b:NAME) */ #define DIRHIST_SUG 32 #define WS_PREFIX_SUG 33 /* Workspace name (w:NAME) */ #define WS_NUM_PREFIX_SUG 34 /* Macros to control file descriptors in exec functions. */ #define E_NOFLAG 0 #define E_NOSTDIN (1 << 1) #define E_NOSTDOUT (1 << 2) #define E_NOSTDERR (1 << 3) #define E_SETSID (1 << 4) #define E_MUTE (E_NOSTDOUT | E_NOSTDERR) /* Number of available suggestion strategies (a,b,c,e,f,h,j). * 'b' is deprecated (kept only for compatibility with old versions) */ #define SUG_STRATS 7 #define FZF_INTERNAL_PREVIEWER 1 /* clifm itself */ /* --preview is set either from FzfOpts in the color scheme file or from * FZF_DEFAULT_OPTS environment variable. */ #define FZF_EXTERNAL_PREVIEWER 3 /* Macros for the backdir (bd) function */ #define BD_TAB 1 #define BD_NO_TAB 0 /* Macros for the clear_suggestion function */ #define CS_FREEBUF 1 #define CS_KEEPBUF 0 /* Macros for the get_file_type function */ #define MIME_TYPE 1 #define TEXT_DESC 0 /* Macros for the dirjump function */ #define SUG_JUMP 0 #define NO_SUG_JUMP 1 /* Macros for the media_menu function */ #define MEDIA_LIST 0 #define MEDIA_MOUNT 1 /* Macros for the rl_highlight function */ #define SET_COLOR 1 #define INFORM_COLOR 0 /* Are we truncating a filename with an extension? */ #define TRUNC_NO_EXT 1 #define TRUNC_EXT 2 /* OpenBSD recommends the use of 10 trailing X's. See mkstemp(3). */ #if defined(__OpenBSD__) # define TMP_FILENAME ".tempXXXXXXXXXX" #else # define TMP_FILENAME ".tempXXXXXX" #endif /* __OpenBSD__ */ #ifndef P_tmpdir # define P_tmpdir "/tmp" #endif /* P_tmpdir */ /* Length of random suffix appended to temp files. Used by gen_rand_str(). */ #define RAND_SUFFIX_LEN 10 /* Macros for the get_sys_shell function. */ #define SHELL_NONE 0 #define SHELL_BASH 1 #define SHELL_DASH 2 #define SHELL_FISH 3 #define SHELL_KSH 4 #define SHELL_TCSH 5 #define SHELL_ZSH 6 #define SHELL_POSIX SHELL_DASH #define BELL_NONE 0 #define BELL_AUDIBLE 1 #define BELL_VISIBLE 2 #define BELL_FLASH 3 #define SECURE_ENV_FULL 1 #define SECURE_ENV_IMPORT 0 /* Macros for the sanitization function. */ /* Commands send to the system shell and taken from an untrusted source, * mostly config files, need to be sanitized first. */ #define SNT_MIME 0 #define SNT_PROMPT 1 #define SNT_PROFILE 2 #define SNT_AUTOCMD 3 #define SNT_NET 4 #define SNT_GRAL 5 #define SNT_DISPLAY 6 /* Sanitize DISPLAY environment variable */ #define SNT_MISC 7 /* Used to sanitize a few environment variables */ #define SNT_NONE 8 /* Trusted command: do not sanitize */ #define SNT_BLACKLIST 9 /* Macros for the TYPE field of the filter_t struct. */ #define FILTER_NONE 0 #define FILTER_FILE_NAME 1 /* Regex */ #define FILTER_FILE_TYPE 2 /* =x */ #define FILTER_MIME_TYPE 3 /* @query */ /* Macros for properties string fields in long view. */ #define PROP_FIELDS_SIZE 10 /* Ten available fields */ #define PERM_SYMBOLIC 1 #define PERM_NUMERIC 2 #define PROP_ID_NUM 1 #if defined(__ANDROID__) # define PROP_ID_NAME PROP_ID_NUM #else # define PROP_ID_NAME 2 #endif /* __ANDROID__ */ #define PROP_TIME_ACCESS 1 #define PROP_TIME_MOD 2 #define PROP_TIME_CHANGE 3 #define PROP_TIME_BIRTH 4 #define PROP_SIZE_BYTES 1 #define PROP_SIZE_HUMAN 2 /* Macros for fzf_preview_border_type. */ #define FZF_BORDER_BOLD 0 #define FZF_BORDER_BOTTOM 1 #define FZF_BORDER_DOUBLE 2 #define FZF_BORDER_HORIZ 3 #define FZF_BORDER_LEFT 4 #define FZF_BORDER_NONE 5 #define FZF_BORDER_ROUNDED 6 #define FZF_BORDER_SHARP 7 #define FZF_BORDER_TOP 8 #define FZF_BORDER_VERT 9 #define FZF_BORDER_BLOCK 10 #define FZF_BORDER_THINBLOCK 11 #define FZF_BORDER_RIGHT 12 /* Flags to skip fuzzy matching based on what we're comparing. */ #define FUZZY_FILES_ASCII 0 #define FUZZY_FILES_UTF8 1 /*#define FUZZY_BM_NAMES 2 */ #define FUZZY_HISTORY 3 #define FUZZY_ALGO_MAX 2 /* We have two fuzzy algorithms */ #define JUMP_ENTRY_PURGED (-1) #define JUMP_ENTRY_PERMANENT 2 #define JUMP_ENTRY_PERMANENT_CHR '+' #define MAX_TIME_STR 256 #define SHADE_TYPE_UNSET 0 #define SHADE_TYPE_8COLORS 1 #define SHADE_TYPE_256COLORS 2 #define SHADE_TYPE_TRUECOLOR 3 #define NUM_SHADES 6 #define QUOTING_STYLE_BACKSLASH 0 #define QUOTING_STYLE_SINGLE_QUOTES 1 #define QUOTING_STYLE_DOUBLE_QUOTES 2 /* Macros used for the --stat and --stat-full command line options. */ #define SIMPLE_STAT 1 #define FULL_STAT 2 /* Length to be added to a filename length if icons are enabled. */ #define ICON_LEN (2 + conf.icons_gap) /* Fixed icon width + gap */ /* Macros for alternative prompts (alt_prompt) */ #define FILES_PROMPT 1 /* Allow filenames completion */ #define PERMISSIONS_PROMPT 2 /* pc command */ #define OWNERSHIP_PROMPT 3 /* oc command */ #define BOOKMARKS_PROMPT 4 /* bookmarks screen */ #define AUTOCMD_MSG_NONE 0 #define AUTOCMD_MSG_MINI 1 #define AUTOCMD_MSG_SHORT 2 #define AUTOCMD_MSG_LONG 3 #define AUTOCMD_MSG_FULL 4 #define AUTOCMD_MSG_PROMPT 5 /* Function macros */ #define atoi xatoi /* xatoi is just a secure atoi */ #ifndef _NO_GETTEXT # define _(str) gettext(str) #else # define _(str) str #endif /* !_GETTEXT */ /* Log the message and print it to STDERR, but do not store it into the * messages array. */ #define xerror(...) err(ERR_NO_STORE, NOPRINT_PROMPT, __VA_ARGS__) /* Macros to calculate file sizes */ /* Directories, regular files, and symbolic links report meaningful sizes * (when the st_size or st_blocks field of the corresponding stat struct is * queried). Other file types, like sockets, block/character devices, etc, * should always report a size of zero. However, this is not guarranteed: * in Solaris, for example, the value of the st_size field for block devices * is unspecified (it might be a big number). * See https://docs.oracle.com/cd/E36784_01/html/E36872/stat-2.html * * Let's use this macro to make sure we report file sizes only for the * appropriate file types. * NOTE: In case of directories themselves (excluding their content), their * apparent size is always zero as well (see 'info du'). */ #define FILE_TYPE_NON_ZERO_SIZE(m) (S_ISDIR((m)) || S_ISREG((m)) \ || S_ISLNK((m))) /* du(1) also checks for * S_TYPEISSHM(struct stat *) // shared memory objects * S_TYPEISTMO(struct stat *) // typed memory objects */ #define FILE_SIZE_PTR(s) (conf.apparent_size == 1 ? (s)->st_size \ : (s)->st_blocks * S_BLKSIZE) #define FILE_SIZE(s) (conf.apparent_size == 1 ? (s).st_size \ : (s).st_blocks * S_BLKSIZE) /* Do we have the sort method S in light mode? */ #define ST_IN_LIGHT_MODE(s) ((s) == SNAME || (s) == SVER || (s) == SINO \ || (s) == SEXT || (s) == SNONE || (s) == STYPE) #define UNUSED(x) (void)(x) /* Just silence the compiler's warning */ /* A yottabyte takes 26 digits, 28 if we count the negative sign and the NULL * terminator, so that 32 bytes is more than enough to represent any given * integer as a string. */ #define MAX_INT_STR 32 /* Bytes required to transform an integer of type TYPE into a string, * including the ending NULL char and the negative sign. */ /* (CHAR_BIT is defined in limits.h). */ /*#define INT_STR_SIZE(type) (((CHAR_BIT * sizeof(type) - 1) * 10 / 33) + 3) */ /* INT_STR_SIZE() is much more accurate than MAX_INT_STR (which is just a * big number) but not fully tested. */ /* UINT_MAX is 4294967295 == 10 digits */ #define DIGINUM(n) (((n) < 10) ? 1 \ : ((n) < 100) ? 2 \ : ((n) < 1000) ? 3 \ : ((n) < 10000) ? 4 \ : ((n) < 100000) ? 5 \ : ((n) < 1000000) ? 6 \ : ((n) < 10000000) ? 7 \ : ((n) < 100000000) ? 8 \ : ((n) < 1000000000) ? 9 \ : 10) /* SIZE_MAX == 18446744073709551615 == 20 digits */ #define DIGINUM_BIG(n) (((n) < 10) ? 1 \ : ((n) < 100) ? 2 \ : ((n) < 1000) ? 3 \ : ((n) < 10000) ? 4 \ : ((n) < 100000) ? 5 \ : ((n) < 1000000) ? 6 \ : ((n) < 10000000) ? 7 \ : ((n) < 100000000) ? 8 \ : ((n) < 1000000000) ? 9 \ : ((off_t)(n) < 10000000000) ? 10 \ : ((off_t)(n) < 100000000000) ? 11 \ : ((off_t)(n) < 1000000000000) ? 12 \ : ((off_t)(n) < 10000000000000) ? 13 \ : ((off_t)(n) < 100000000000000) ? 14 \ : ((off_t)(n) < 1000000000000000) ? 15 \ : ((off_t)(n) < 10000000000000000) ? 16 \ : ((off_t)(n) < 100000000000000000) ? 17 \ : ((off_t)(n) < 1000000000000000000) ? 18 \ : 19) #define IS_DIGIT(c) ((unsigned int)(c) >= '0' && (unsigned int)(c) <= '9') #define IS_ALPHA_LOW(c) ((unsigned int)(c) >= 'a' && (unsigned int)(c) <= 'z') #define IS_ALPHA_UP(c) ((unsigned int)(c) >= 'A' && (unsigned int)(c) <= 'Z') #define IS_ALNUM(c) (IS_ALPHA_LOW((c)) || IS_ALPHA_UP((c)) || IS_DIGIT((c))) #define IS_HEX_DIGIT(c) (IS_DIGIT((c)) || ((c) >= 'a' && (c) <= 'f') \ || ((c) >= 'A' && (c) <= 'F')) #define TOUPPER(c) (IS_ALPHA_LOW((c)) ? ((c) & ~0x20) : (c)) #define TOLOWER(c) (IS_ALPHA_UP((c)) ? ((c) | 0x20) : (c)) #define IS_UTF8_LEAD_BYTE(c) (((c) & 0xc0) == 0xc0) #define IS_UTF8_CONT_BYTE(c) (((c) & 0xc0) == 0x80) #define IS_UTF8_CHAR(c) (IS_UTF8_LEAD_BYTE((c)) || IS_UTF8_CONT_BYTE((c))) #define IS_COMMENT(c) ((unsigned int)(c) == '#' || (unsigned int)(c) == ';') #define IS_CTRL_CHR(c) ((unsigned int)(c) < ' ') #define IS_NEWLINE(c) ((unsigned int)(c) == '\n') #define SKIP_LINE(c) (IS_COMMENT((c)) || IS_NEWLINE((c)) || IS_CTRL_CHR((c))) #define SELFORPARENT(s) (*(s) == '.' && (!(s)[1] || ((s)[1] == '.' && !(s)[2]))) #define FILE_URI_PREFIX_LEN 7 #define IS_FILE_URI(file, len) ((len) > FILE_URI_PREFIX_LEN \ && (file)[4] == ':' && (file)[FILE_URI_PREFIX_LEN] \ && strncmp((file), "file://", FILE_URI_PREFIX_LEN) == 0) #define IS_HELP(s) (*(s) == '-' && (((s)[1] == 'h' && !(s)[2]) \ || strcmp((s), "--help") == 0)) /* Get the maximum value for a given data type. * Taken from coreutils (https://github.com/coreutils/gnulib/blob/master/lib/intprops.h) */ /* #include // CHAR_BIT #define TYPE_SIGNED(t) (!((t)0 < (t)-1)) #define TYPE_WIDTH(t) (sizeof(t) * CHAR_BIT) #define TYPE_MAXIMUM(t) \ ((t)(!TYPE_SIGNED(t) \ ? (t)-1 \ : ((((t)1 << (TYPE_WIDTH(t) - 2)) - 1) * 2 + 1))) // Safely cast the number N to the type T. The type T is never overflowed: // if N is bigger than what T can hold, the maximum value T can hold is // returned. What about underflow? #define SAFECAST(n, t) ((t)(n) < 0 ? TYPE_MAXIMUM(t) : (t)(n)) */ /* // See https://bestasciitable.com #define __CTRL(n) ((n) & ~(1 << 6)) // Just unset (set to zero) the seventh bit #define ___CTRL(n) ((n) & 0x3f) // Same as __CTRL #define _SHIFT(n) ((n) & ~(1 << 5)) // Unset the sixth bit // As defined by readline. Explanation: // 0x1ff == 0011111 // So, this bitwise AND operation: 'n & 0x1f', means: set to zero whatever // bits in N that are zero in 0x1f, that is, the sixth and seventh bits #define _CTRL(n) ((n) & 0x1f) // As defined by readline: set to one the eight bit in N #define _META(n) ((n) | 0x80) // E.g.: 'A' == 01000001 // ('A' | 0x80) == 11000001 == 193 == Á */ /** ######################### * # GLOBAL VARIABLES # * ######################### */ /* filesn_t: Let's use this to count files */ /* ssize_t is a quite convenient data type: * 1. Unlike intmax_t, it's never bigger than size_t (in 32-bit/ARM machines, * INTMAX_MAX is bigger than SIZE_MAX). * 2. Can be safely casted to both intmax_t and size_t (something * we do sometimes). * 3. It's signed; at least one negative number (-1) (something we need for * decrementing loops). * * 32-bit/ARM: INT_MAX == LONG_MAX == SSIZE_MAX < SIZE_MAX < INTMAX_MAX == LLONG_MAX * 64-bit: INT_MAX < LONG_MAX == LLONG_MAX == INTMAX_MAX == SSIZE_MAX < SIZE_MAX */ #define FILESN_MAX SSIZE_MAX typedef ssize_t filesn_t; extern filesn_t files; struct default_answer_t { char remove; char trash; char bulk_rename; char overwrite; char default_; char default_all; char pad[2]; }; /* User settings (mostly from the config file) */ struct config_t { char *opener; char *dirhistignore_regex; char *histignore_regex; char *encoded_prompt; char *term; char *time_str; char *priority_sort_char; char *ptime_str; char *rprompt_str; char *welcome_message_str; char *wprompt_str; #ifndef _NO_SUGGESTIONS char *suggestion_strategy; #else char *pad0; /* Keep the struct alignment */ #endif /* !_NO_SUGGESTIONS */ char *usr_cscheme; char *fzftab_options; struct default_answer_t default_answer; int apparent_size; int auto_open; int autocd; int autocmd_msg; int autols; int bell_style; int case_sens_dirjump; int case_sens_path_comp; int case_sens_search; int case_sens_list; /* File list */ int cd_on_quit; int check_cap; int check_ext; int classify; int clear_screen; int cmd_desc_sug; int colorize; int color_lnk_as_target; int columned; int cp_cmd; int desktop_notifications; int dirhist_map; int disk_usage; int ext_cmd_ok; int files_counter; int follow_symlinks; int follow_symlinks_long; int full_dir_size; int fuzzy_match; int fuzzy_match_algo; int fzf_preview; int highlight; int icons; int icons_gap; int int_vars; int light_mode; int link_creat_mode; int list_dirs_first; int listing_mode; int log_cmds; int log_msgs; int long_view; int max_dirhist; int max_hist; int max_jump_total_rank; int max_files; int max_log; int max_name_len; int max_name_len_bk; int max_printselfiles; int min_jump_rank; int min_name_trunc; int mv_cmd; int no_eln; int only_dirs; int pager; int pager_once; int pager_view; int purge_jumpdb; int preview_max_size; int print_dir_cmds; int print_selfiles; int private_ws_settings; int prompt_b_is_set; int prompt_b_min; int prompt_b_precision; int prompt_f_dir_len; int prompt_f_full_len_dirs; int prompt_p_max_path; int prompt_is_multiline; int prop_fields_gap; int quoting_style; int read_autocmd_files; int read_dothidden; int readonly; int relative_time; int restore_last_path; int rm_force; int search_strategy; int share_selbox; int show_hidden; int skip_non_alnum_prefix; int sort; int sort_reverse; int splash_screen; int suggest_filetype_color; int suggestions; int time_follows_sort; int timestamp_mark; int tips; int trunc_names; #ifndef _NO_TRASH int tr_as_rm; int trash_force; #else int pad1; /* Keep the struct alignment */ int pad2; #endif /* !_NO_TRASH */ int warning_prompt; int welcome_message; int pad3; }; extern struct config_t conf; /* Store information about the current files filter */ struct filter_t { char *str; int rev; int type; int env; int pad0; }; extern struct filter_t filter; /* Struct to store information about the current user. */ struct user_t { char *home; char *name; char *shell; char *shell_basename; size_t home_len; uid_t uid; gid_t gid; /* Primary user group */ gid_t *groups; /* Secondary groups ID's */ int ngroups; /* Number of secondary groups */ int pad0; }; extern struct user_t user; /* Struct to store user defined variables */ struct usrvar_t { char *name; char *value; }; extern struct usrvar_t *usr_var; /* Struct to store user defined actions */ struct actions_t { char *name; char *value; }; extern struct actions_t *usr_actions; /* Workspaces information */ struct ws_t { char *path; char *name; int num; int pad0; }; extern struct ws_t *workspaces; /* Struct to store user defined keybindings */ struct kbinds_t { char *function; char *key; }; extern struct kbinds_t *kbinds; /* Struct to store the dirjump database values */ struct jump_t { char *path; #if defined(__arm__) && !defined(__ANDROID__) char *pad0; #endif /* __arm__ && !__ANDROID__ */ size_t len; size_t visits; time_t first_visit; time_t last_visit; int keep; int rank; }; extern struct jump_t *jump_db; /* Struct to store bookmarks */ struct bookmarks_t { char *shortcut; char *name; char *path; }; extern struct bookmarks_t *bookmarks; struct alias_t { char *name; char *cmd; }; extern struct alias_t *aliases; struct groups_t { char *name; size_t namlen; gid_t id; int pad0; }; extern struct groups_t *sys_users; extern struct groups_t *sys_groups; struct human_size_t { char str[MAX_HUMAN_SIZE + 6]; size_t len; int unit; int pad0; }; /* Struct to store files information */ struct fileinfo { struct human_size_t human_size; struct groups_t uid_i; struct groups_t gid_i; char *color; char *ext_color; char *ext_name; char *icon; char *icon_color; char *name; filesn_t filesn; blkcnt_t blocks; size_t len; /* Filename len (columns needed to display filename) */ size_t bytes; /* Bytes consumed by filename */ #ifdef TIGHT_COLUMNS size_t total_entry_len; #endif time_t ltime; /* For long view mode */ time_t time; ino_t inode; off_t size; nlink_t linkn; /* 4 bytes on Solaris/BSD/HAIKU; 8 on Linux */ uid_t uid; gid_t gid; mode_t mode; /* Store st_mode (for long view mode) */ mode_t type; /* Store d_type value */ int dir; int eln_n; /* Number of digits in ELN */ int exec; int user_access; /* Read-exec for dirs and read for files */ int symlink; int sel; int xattr; int du_status; /* Exit status of du(1) for dir full sizes */ int utf8; /* Name contains at least one UTF-8 character */ int stat_err; /* stat(2) failed for this entry */ #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) \ || defined(__APPLE__) || defined(__sun) || defined(__HAIKU__) \ || (defined(__arm__) && !defined(__ANDROID__)) int pad0; #endif }; extern struct fileinfo *file_info; /* Struct to store the length of the longest values in the current list of * files (needed to properly construct columns in long view). */ struct maxes_t { int id_group; int id_user; int inode; int files_counter; int links; int name; int size; int blocks; }; struct devino_t { ino_t ino; dev_t dev; /* 4 bytes on OpenBSD, DragonFly, and Haiku */ char mark; char pad0[3]; #if !defined(__OpenBSD__) && !defined(__DragonFly__) && !defined(__HAIKU__) int pad1; #endif /* !__OpenBSD__ && !__DragonFly__ && !__HAIKU__ */ }; extern struct devino_t *sel_devino; struct autocmds_t { struct filter_t filter; char *pattern; char *color_scheme; char *cmd; int files_counter; int full_dir_size; int long_view; int light_mode; int match; int max_files; int max_name_len; int only_dirs; int pager; int pattern_rev; int show_hidden; int sort; int sort_reverse; int temp; }; extern struct autocmds_t *autocmds; struct opts_t { struct filter_t filter; char *color_scheme; int files_counter; int full_dir_size; int light_mode; int list_dirs_first; int long_view; int max_files; int max_name_len; int only_dirs; int pager; int show_hidden; int sort; int sort_reverse; }; extern struct opts_t opts; extern struct opts_t workspace_opts[MAX_WS]; /* Struct to specify which parameters have been set from the command * line, to avoid overriding them with init_config(). While no command * line parameter will be overriden, the user still can modifiy on the * fly (editing the config file) any option not specified in the command * line. */ struct param_t { int apparent_size; int auto_open; int autocd; int autols; int bell_style; int bm_file; int case_sens_dirjump; int case_sens_path_comp; int case_sens_list; int clear_screen; int color_lnk_as_target; int colorize; int columned; int config; int cwd_in_title; int desktop_notifications; int dirhist_map; int disk_usage; int cd_on_quit; int check_cap; int check_ext; int classify; int color_scheme; int disk_usage_analyzer; int eln_use_workspace_color; int ext_cmd_ok; int files_counter; int follow_symlinks; int follow_symlinks_long; int full_dir_size; int fuzzy_match; int fuzzy_match_algo; int fzf_preview; #ifndef _NO_FZF int fzftab; int fnftab; int smenutab; #endif /* !_NO_FZF */ #ifndef _NO_HIGHLIGHT int highlight; #endif /* !_NO_HIGHLIGHT */ int history; int horizontal_list; #ifndef _NO_ICONS int icons; #endif /* !_NO_ICONS */ int icons_use_file_color; int int_vars; int kitty_keys; /* kitty keyboard protocol */ int list_and_quit; int light_mode; int list_dirs_first; int long_view; int lscolors; int max_dirhist; int max_files; int mount_cmd; int no_bold; int no_dirjump; int no_eln; int only_dirs; int open; int pager; int pager_view; int path; int preview; int print_selfiles; int prompt_p_max_path; int prop_fields_str; int ptime_style; int readonly; int refresh_on_empty_line; int refresh_on_resize; int report_cwd; int restore_last_path; int rl_vi_mode; int secure_cmds; int secure_env; int secure_env_full; int sel_file; int share_selbox; int show_hidden; int si; /* Sizes in powers of 1000 instead of 1024 */ int sort; int sort_reverse; int splash_screen; int stat; int stealth_mode; #ifndef _NO_SUGGESTIONS int suggestions; #endif /* !_NO_SUGGESTIONS */ int time_style; int tips; #ifndef _NO_TRASH int trasrm; #endif /* !_NO_TRASH */ int trunc_names; int unicode; int virtual_dir_full_paths; int vt100; int welcome_message; int warning_prompt; }; extern struct param_t xargs; /* Struct to store remotes information */ struct remote_t { char *desc; char *name; char *mount_cmd; char *mountpoint; char *unmount_cmd; int auto_mount; int auto_unmount; int mounted; int pad0; }; extern struct remote_t *remotes; /* Store information about the current suggestion */ struct suggestions_t { char *color; size_t full_line_len; size_t nlines; int filetype; int printed; int type; int offset; }; extern struct suggestions_t suggestion; /* Hold information about selected files */ struct sel_t { char *name; #ifdef __arm__ char *pad0; #endif /* __arm__ */ off_t size; }; extern struct sel_t *sel_elements; /* File statistics for the current directory. Used by the 'stats' command */ struct stats_t { size_t dir; size_t empty_dir; size_t reg; size_t empty_reg; size_t exec; size_t hidden; size_t suid; size_t sgid; size_t fifo; size_t socket; size_t block_dev; size_t char_dev; size_t caps; size_t link; size_t broken_link; size_t multi_link; size_t other_writable; size_t sticky; size_t extended; size_t unknown; size_t unstat; /* Non-statable file */ size_t excluded; /* Files not displayed */ #ifdef __sun size_t door; size_t port; #endif /* __sun */ #ifdef S_ARCH1 size_t arch1; size_t arch2; #endif /* S_ARCH1 */ #ifdef S_IFWHT size_t whiteout; #endif /* S_IFWHT */ }; extern struct stats_t stats; struct sort_t { const char *name; int num; int pad0; }; extern const struct sort_t sort_methods[]; /* Prompts and prompt settings */ struct prompts_t { char *name; char *regular; char *warning; char *right; int notifications; int warning_prompt_enabled; int multiline; /* Regular prompt is multiline */ int pad0; }; extern struct prompts_t *prompts; /* System messages */ struct msgs_t { size_t error; size_t warning; size_t notice; }; extern struct msgs_t msgs; /* A few termcap values to know whether we can use some terminal features */ struct termcaps_t { int color; int suggestions; int pager; int hide_cursor; int home; /* Move cursor to line 1, column 1 */ int clear; /* ED (erase display) */ int del_scrollback; /* E3 */ int req_cur_pos; /* CPR (cursor position request) */ int req_dev_attrs; /* Primary DA (device attributes request) */ int unicode; }; extern struct termcaps_t term_caps; /* Data to be displayed in the properties string in long mode */ struct props_t { int counter; /* File counter */ int ids; /* User/group IDs: either NUMBER or NAME */ int inode; /* File inode number */ int len; /* Approx len of the entire properties string taking into account * all fields and their length. */ int links; /* File links */ int blocks; int no_group; /* Should we display group if IDS is set? */ int perm; /* File permissions: either NUMERIC or SYMBOLIC */ int size; /* File size: either HUMAN or BYTES */ int time; /* Time: either ACCESS, MOD, CHANGE, or BIRTH */ int xattr; /* Extended attributes */ int pad0; }; extern struct props_t prop_fields; #define ALL_CMDS (1 << 0) // Check all commands (ignore parameters) #define NO_PARAM (1 << 1) // Command takes no parameter #define PARAM_STR (1 << 2) // Command takes a string (not filename) #define PARAM_FNAME (1 << 3) // Command takes filenames #define PARAM_NUM (1 << 4) // Command takes numbers #define NO_FNAME_NUM (NO_PARAM | PARAM_STR) // Neither filename nor number #define PARAM_FNAME_NUM (PARAM_FNAME | PARAM_NUM) // Either filename or number struct cmdslist_t { char *name; size_t len; int flag; int pad; }; extern const struct cmdslist_t internal_cmds[]; struct nameslist_t { char *name; size_t len; }; extern const struct nameslist_t param_str[]; extern const struct nameslist_t kb_cmds[]; extern size_t internal_cmds_n; struct history_t { char *cmd; size_t len; time_t date; }; extern struct history_t *history; /* Structs to hold color info for size and date fields in file properties */ struct rgb_t { uint8_t attr; uint8_t R; uint8_t G; uint8_t B; }; struct shades_t { uint8_t type; struct rgb_t shades[NUM_SHADES]; }; extern struct shades_t date_shades; extern struct shades_t size_shades; struct paths_t { char *path; #ifdef __arm__ char *pad0; #endif /* __arm__ */ time_t mtime; }; extern struct paths_t *paths; struct ext_t { char *name; char *value; size_t len; /* Name length */ size_t value_len; size_t hash; }; extern struct ext_t *ext_colors; #ifdef LINUX_FSINFO #define EXT2_FSTYPE 0x002 #define EXT3_FSTYPE 0x003 #define EXT4_FSTYPE 0x004 struct ext_mnt_t { char *mnt_point; int type; /* One of EXTN_FSTYPE macros */ int pad0; }; extern struct ext_mnt_t *ext_mnt; #endif /* LINUX_FSINFO */ /* State info for the PrintDirCmds function. */ struct dircmds_t { int first_cmd_in_dir; /* History index of first cmd exec'ed in the cur dir */ int last_cmd_ignored; /* Ignored cmd (via HistIgnore) */ }; extern struct dircmds_t dir_cmds; struct pmsgs_t { char *text; int read; int pad0; }; extern struct pmsgs_t *messages; struct dir_info_t { unsigned long long dirs; unsigned long long files; unsigned long long links; off_t size; blkcnt_t blocks; int status; int pad0; }; /* Store user defined mimetypes */ struct mime_t { char *ext; char *mimetype; size_t ext_hash; }; extern struct mime_t *user_mimetypes; enum tab_mode { STD_TAB = 0, FZF_TAB = 1, FNF_TAB = 2, SMENU_TAB = 3 }; extern enum tab_mode tabmode; /* A list of possible program messages. Each value tells the prompt what * to do with error messages: either to print an E, W, or N char at the * beginning of the prompt, or nothing (nomsg) */ enum prog_msg { NOMSG = 0, ERROR = 1, WARNING = 2, NOTICE = 4 }; /* pmsg holds the current program message type */ extern enum prog_msg pmsg; /* Enumeration for the dirjump function options */ enum jump { NONE = 0, JPARENT = 1, JCHILD = 2, JORDER = 4, JLIST = 8 }; enum comp_type { TCMP_BOOKMARK = 0, TCMP_CMD = 1, TCMP_CSCHEME = 2, TCMP_DESEL = 3, TCMP_ELN = 4, TCMP_HIST = 5, TCMP_JUMP = 6, TCMP_NET = 7, TCMP_NONE = 8, TCMP_OPENWITH = 9, TCMP_PATH = 10, TCMP_PROF = 11, TCMP_RANGES = 12, TCMP_SEL = 13, TCMP_SORT = 14, TCMP_TRASHDEL = 15, TCMP_UNTRASH = 16, TCMP_BACKDIR = 17, TCMP_ENVIRON = 18, TCMP_TAGS_T = 19, /* T keyword: 't:TAG' */ TCMP_TAGS_C = 20, /* Colon: 'tag file :TAG' */ TCMP_TAGS_S = 21, /* Simple completion: 'tag rm TAG' */ TCMP_TAGS_F = 22, /* Tagged files completion: 't:FULL_TAG_NAME' */ TCMP_TAGS_U = 23, /* Tagged files for the untag function */ TCMP_ALIAS = 24, TCMP_PROMPTS = 25, TCMP_USERS = 26, TCMP_GLOB = 27, TCMP_FILE_TYPES_OPTS = 28, TCMP_FILE_TYPES_FILES = 29, TCMP_WORKSPACES = 30, TCMP_BM_PATHS = 31, /* 'b:FULLNAME' keyword expansion */ TCMP_BM_PREFIX = 32, /* 'b:' keyword expansion */ TCMP_CMD_DESC = 33, TCMP_OWNERSHIP = 34, TCMP_DIRHIST = 35, TCMP_MIME_LIST = 36, TCMP_WS_PREFIX = 37, /* 'w:' keyword expansion */ TCMP_MIME_FILES = TCMP_FILE_TYPES_FILES, /* Same behavior */ TCMP_FILE_TEMPLATES = 38 }; extern enum comp_type cur_comp_type; /* Bit flag holders */ extern int flags, bin_flags, search_flags; extern int date_shades_old_style, size_shades_old_style; /* Internal state flags */ extern int alt_prompt, /* We're running a secondary prompt */ argc_bk, /* A copy of argc taken from main() */ autocmd_set, bg_proc, cmdhist_flag, config_ok, cur_ws, curcol, dequoted, dir_changed, /* flag to know if dir was changed: used by autocmds */ dirhist_cur_index, dirhist_total_index, exit_code, fzftab, fzf_ext_border, fzf_border_type, fzf_height_value, fzf_preview_border_type, hist_status, home_ok, internal_cmd, is_sel, is_cdpath, jump_total_rank, kbind_busy, nesting_level, /* Is this a nested instance? */ no_log, open_in_foreground, /* Overrides mimelist file value: used by mime_open */ prev_ws, print_msg, print_removed_files, prompt_offset, prompt_notif, recur_perm_error_flag, rl_nohist, rl_notab, sel_is_last, selfile_ok, shell, shell_is_interactive, shell_terminal, sort_switch, switch_cscheme, #ifndef _NO_TRASH trash_ok, #endif /* !_NO_TRASH */ virtual_dir, wrong_cmd; extern unsigned short term_cols, term_lines; extern double last_cmd_time; extern size_t actions_n, aliases_n, args_n, autocmds_n, bm_n, cdpath_n, config_dir_len, cschemes_n, current_hist_n, curhistindex, ext_colors_n, jump_n, kbinds_n, msgs_n, P_tmpdir_len, path_n, path_progsn, prompt_cmds_n, prompts_n, remotes_n, sel_n, tab_offset, tags_n, trash_n, usrvar_n, words_num, zombies; #ifndef _NO_ICONS extern size_t *name_icons_hashes; extern size_t *dir_icons_hashes; extern size_t *ext_icons_hashes; #endif /* !_NO_ICONS */ extern pid_t own_pid; extern time_t props_now; extern char cur_prompt_name[NAME_MAX + 1], div_line[NAME_MAX + 1], hostname[HOST_NAME_MAX + 1], fz_match[PATH_MAX + 1], /* First regular match if fuzzy matching is enabled */ prop_fields_str[PROP_FIELDS_SIZE + 1], invalid_time_str[MAX_TIME_STR], #ifdef RUN_CMD *cmd_line_cmd, #endif /* RUN_CMD */ *actions_file, *alt_config_dir, *alt_trash_dir, *alt_bm_file, *alt_config_file, *alt_kbinds_file, *alt_mimelist_file, *alt_preview_file, *alt_profile, *bm_file, *cmds_log_file, *colors_dir, *config_dir, *config_dir_gral, *config_file, *cur_color, *cur_tag, *data_dir, *cur_cscheme, *dirhist_file, *file_cmd_path, *hist_file, *kbinds_file, *jump_suggestion, *last_cmd, *mime_file, *msgs_log_file, *pinned_dir, *plugins_dir, *plugins_helper_file, *profile_file, *prompts_file, *quote_chars, *rl_callback_handler_input, *remotes_file, *sel_file, *smenutab_options_env, *stdin_tmp_dir, *sudo_cmd, #ifndef _NO_SUGGESTIONS *suggestion_buf, #endif /* !_NO_SUGGESTIONS */ *tags_dir, *templates_dir, *thumbnails_dir, *tmp_rootdir, *tmp_dir, #ifndef _NO_TRASH *trash_dir, *trash_files_dir, *trash_info_dir, #endif /* !_NO_TRASH */ **argv_bk, **bin_commands, **cdpaths, **color_schemes, **file_templates, **old_pwd, **profile_names, **prompt_cmds, **tags; extern regex_t regex_exp; /* Files list */ extern regex_t regex_hist; /* Commands history */ extern regex_t regex_dirhist; /* Directory history */ extern char **environ; /* A buffer to store filenames to be displayed (wide string) */ #define NAME_BUF_SIZE (NAME_MAX + 1) extern char name_buf[NAME_BUF_SIZE * sizeof(wchar_t)]; /* Longest supported color: * \x1b[4:4;38;2;000;000;000;48;2;000;000;000;58;2;000;000;000m\0 * This is a complete SGR sequence, with 24bit colors: foreground, background, * and underline (kitty). */ #define MAX_COLOR 64 /* For the almost 100 color variables we use, we need more or less 6Kb. * It's not much, but it could be less if we'd use dynamically allocated * arrays for them (which, on the other side, would make the whole thing * slower and more tedious). */ /* Colors */ extern char /* File types */ bd_c[MAX_COLOR], /* Block device */ bk_c[MAX_COLOR], /* Backup/temp files */ ca_c[MAX_COLOR], /* Cap file */ cd_c[MAX_COLOR], /* Char device */ di_c[MAX_COLOR], /* Directory */ ed_c[MAX_COLOR], /* Empty dir */ ee_c[MAX_COLOR], /* Empty executable */ ex_c[MAX_COLOR], /* Executable */ ef_c[MAX_COLOR], /* Empty reg file */ fi_c[MAX_COLOR], /* Reg file */ ln_c[MAX_COLOR], /* Symlink */ mh_c[MAX_COLOR], /* Multi-hardlink file */ nd_c[MAX_COLOR], /* No read directory */ nf_c[MAX_COLOR], /* No read file */ no_c[MAX_COLOR], /* Unknown */ #ifdef __sun oo_c[MAX_COLOR], /* Solaris door/port */ #endif /* __sun */ or_c[MAX_COLOR], /* Broken symlink */ ow_c[MAX_COLOR], /* Other writable */ pi_c[MAX_COLOR], /* FIFO, pipe */ sg_c[MAX_COLOR], /* SGID file */ so_c[MAX_COLOR], /* Socket */ st_c[MAX_COLOR], /* Sticky (not ow)*/ su_c[MAX_COLOR], /* SUID file */ tw_c[MAX_COLOR], /* Sticky other writable */ uf_c[MAX_COLOR], /* Non-'stat'able file */ /* Interface */ ac_c[MAX_COLOR + 2], /* Autocmd indicator */ df_c[MAX_COLOR], /* Default color */ dl_c[MAX_COLOR], /* Dividing line */ el_c[MAX_COLOR], /* ELN color */ fc_c[MAX_COLOR], /* File counter */ lc_c[MAX_COLOR], /* Symlink character (ColorLinkAsTarget only) */ mi_c[MAX_COLOR], /* Misc indicators */ ts_c[MAX_COLOR], /* Tab completion suffix */ tt_c[MAX_COLOR], /* Tilde for truncated filenames */ wc_c[MAX_COLOR], /* Welcome message */ wp_c[MAX_COLOR], /* Warning prompt */ /* Suggestions */ sb_c[MAX_COLOR], /* Auto-suggestions: shell builtins */ sc_c[MAX_COLOR], /* Auto-suggestions: external commands and aliases */ sd_c[MAX_COLOR], /* Auto-suggestions: internal commands description */ sf_c[MAX_COLOR], /* Auto-suggestions: filenames */ sh_c[MAX_COLOR], /* Auto-suggestions: history */ sp_c[MAX_COLOR], /* Auto-suggestions: BAEJ suggestions pointer */ sx_c[MAX_COLOR], /* Auto-suggestions: internal commands and parameters */ sz_c[MAX_COLOR], /* Auto-suggestions: filenames (fuzzy) */ #ifndef _NO_ICONS dir_ico_c[MAX_COLOR], /* Directories icon color */ #endif /* !_NO_ICONS */ /* Syntax highlighting */ hb_c[MAX_COLOR], /* Brackets () [] {} */ hc_c[MAX_COLOR], /* Comments */ hd_c[MAX_COLOR], /* Paths (slashes) */ he_c[MAX_COLOR], /* Expansion operators: * ~ */ hn_c[MAX_COLOR], /* Numbers */ hp_c[MAX_COLOR], /* Parameters: - */ hq_c[MAX_COLOR], /* Quoted strings */ hr_c[MAX_COLOR], /* Redirection > */ hs_c[MAX_COLOR], /* Process separators | & ; */ hv_c[MAX_COLOR], /* Variables $ */ hw_c[MAX_COLOR], /* Backslash (aka whack) */ /* File properties */ db_c[MAX_COLOR], /* File allocated blocks */ dd_c[MAX_COLOR], /* Date (fixed color: no shading) */ de_c[MAX_COLOR], /* Inode number */ dg_c[MAX_COLOR], /* Group ID */ dk_c[MAX_COLOR], /* Number of links */ dn_c[MAX_COLOR], /* dash (none) */ do_c[MAX_COLOR], /* Octal perms */ dp_c[MAX_COLOR], /* Special files (SUID, SGID, etc) */ dr_c[MAX_COLOR], /* Read */ dt_c[MAX_COLOR], /* Timestamp mark */ du_c[MAX_COLOR], /* User ID */ dw_c[MAX_COLOR], /* Write */ dxd_c[MAX_COLOR], /* Execute (dirs) */ dxr_c[MAX_COLOR], /* Execute (reg files) */ dz_c[MAX_COLOR], /* Size (dirs) */ /* Colors used in the prompt, so that \001 and \002 needs to * be added. This is why MAX_COLOR + 2 */ /* Workspaces */ ws1_c[MAX_COLOR + 2], ws2_c[MAX_COLOR + 2], ws3_c[MAX_COLOR + 2], ws4_c[MAX_COLOR + 2], ws5_c[MAX_COLOR + 2], ws6_c[MAX_COLOR + 2], ws7_c[MAX_COLOR + 2], ws8_c[MAX_COLOR + 2], em_c[MAX_COLOR + 2], /* Error msg */ li_c[MAX_COLOR + 2], /* Sel indicator */ li_cb[MAX_COLOR], /* Sel indicator (for the file list) */ nm_c[MAX_COLOR + 2], /* Notice msg */ ti_c[MAX_COLOR + 2], /* Trash indicator */ tx_c[MAX_COLOR + 2], /* Text */ ro_c[MAX_COLOR + 2], /* Read-only indicator */ si_c[MAX_COLOR + 2], /* Stealth indicator */ wm_c[MAX_COLOR + 2], /* Warning msg */ xs_c[MAX_COLOR + 2], /* Exit code: success */ xs_cb[MAX_COLOR], /* Exit code: success (Unicode success indicator) */ xf_c[MAX_COLOR + 2], /* Exit code: failure */ xf_cb[MAX_COLOR], /* Exit code: failure (dir read) */ tmp_color[MAX_COLOR + 2], /* A temp buffer to store color codes */ dim_c[5]; /* Dimming code: not supported by all terminals */ #endif /* HELPERS_H */ clifm-1.26.3/src/highlight.c000066400000000000000000000164041506632037700156150ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* highlight.c -- a simple function to perform syntax highlighting */ #include "helpers.h" #ifdef __OpenBSD__ typedef char *rl_cpvfunc_t; #include #else #include #endif /* __OpenBSD__ */ #include "checks.h" /* Macros for single and double quotes */ #define Q_SINGLE 0 #define Q_DOUBLE 1 /* Change the color of the word _LAST_WORD, at offset OFFSET, to COLOR * in the current input string */ /*void change_word_color(const char *_last_word, const int offset, const char *color) { UNUSED(_last_word); fputs("\x1b[?25l", stdout); char *p = rl_copy_text(offset, rl_end); rl_delete_text(offset, rl_end); rl_point = rl_end = offset; rl_redisplay(); fputs(color, stdout); rl_insert_text(p); rl_redisplay(); free(p); fputs(tx_c, stdout); fputs("\x1b[?25h", stdout); } */ /* Get the appropriate color for the character at position POS in the string * STR and print the color if SET_COLOR is set to 1 (in which case NULL is * returned); otherwise, just return a pointer to the corresponding color. * This function is used to colorize input, history entries, and accepted * suggestions. */ char * rl_highlight(const char *str, const size_t pos, const int flag) { char *cl = (char *)NULL; /* PREV is 0 when there is no previous char (STR[POS] is the first one) */ char prev = pos > 0 ? str[pos - 1] : 0; char c = *(str + pos); if (wrong_cmd == 1 && cur_color == wp_c && rl_end == 0) { fputs(tx_c, stdout); fflush(stdout); rl_redisplay(); } if ((rl_end == 0 && c == KEY_BACKSPACE) || prev == '\\') { if (prev == '\\') goto END; cl = tx_c; goto END; } if (cur_color == hc_c) goto END; char *sp = strchr(rl_line_buffer, ' '); if (cur_color == wp_c && !sp) goto END; /* if (*rl_line_buffer != ';' && *rl_line_buffer != ':' && cur_color != hq_c && c >= '0' && c <= '9') { if (prev == ' ' || prev == 0 || cur_color == hn_c || rl_end == 1) { char *a = strchr(str + pos, ' '); if (a) { *a = '\0'; if (is_number(str + pos)) cl = hn_c; *a = ' '; } else { cl = hn_c; } goto END; } else { char cc = c; *(str + pos) = '\0'; int ret = is_internal_cmd(str, PARAM_FNAME_NUM, 0, 0); *(str + pos) = cc; if (ret) { cl = hn_c; goto END; } } } */ size_t quote[2] = {0}; size_t i; for (i = 0; i < (size_t)rl_point; i++) { if (rl_line_buffer[i] == '\'') { if (quote[Q_DOUBLE] == 1 || (i > 0 && rl_line_buffer[i - 1] == '\\')) continue; quote[Q_SINGLE]++; if (quote[Q_SINGLE] > 2) quote[Q_SINGLE] = 1; } else { if (rl_line_buffer[i] == '"') { if (quote[Q_SINGLE] == 1 || (i > 0 && rl_line_buffer[i - 1] == '\\')) continue; quote[Q_DOUBLE]++; if (quote[Q_DOUBLE] > 2) quote[Q_DOUBLE] = 1; } } } if (prev != 0) { switch (prev) { case ')': /* fallthrough */ case ']': /* fallthrough */ case '}': cl = tx_c; break; case '\'': if (cur_color == hq_c && quote[Q_SINGLE] == 2) cl = tx_c; break; case '"': if (cur_color == hq_c && quote[Q_DOUBLE] == 2) cl = tx_c; break; default: break; } } switch (c) { case '0': /* fallthrough */ case '1': /* fallthrough */ case '2': /* fallthrough */ case '3': /* fallthrough */ case '4': /* fallthrough */ case '5': /* fallthrough */ case '6': /* fallthrough */ case '7': /* fallthrough */ case '8': /* fallthrough */ case '9': if (cur_color != hq_c) cl = hn_c; break; case ' ': if (cur_color != hq_c && cur_color != hc_c) cl = tx_c; break; case '/': cl = (cur_color != hq_c) ? hd_c : cl; break; case '\'': /* fallthrough */ case '"': cl = hq_c; break; case KEY_ENTER: cl = tx_c; break; case '~': /* fallthrough */ case '*': cl = (cur_color != hq_c) ? he_c : cl; break; case '=': /* fallthrough */ case '(': /* fallthrough */ case ')': /* fallthrough */ case '[': /* fallthrough */ case ']': /* fallthrough */ case '{': /* fallthrough */ case '}': cl = (cur_color != hq_c) ? hb_c : cl; break; case '|': /* fallthrough */ case '&': /* fallthrough */ case ';': cl = (cur_color != hq_c) ? hs_c : cl; break; case '\\': cl = (cur_color != hq_c) ? hw_c : cl; break; case '<': /* fallthrough */ case '>': cl = (cur_color != hq_c) ? hr_c : cl; break; case '$': cl = (cur_color != hq_c) ? hv_c : cl; break; case '-': if (prev == ' ' || prev == 0) cl = (cur_color != hq_c) ? hp_c : (char *)NULL; break; case '#': if (prev == ' ' || prev == 0) cl = (cur_color != hq_c) ? hc_c : (char *)NULL; else cl = tx_c; break; default: if (cur_color != hq_c && cur_color != hc_c && cur_color != hv_c && cur_color != hp_c) cl = tx_c; break; } if (cur_color == hq_c) { if (quote[Q_SINGLE] == 1 || quote[Q_DOUBLE] == 1) cl = (char *)NULL; } END: if (flag == SET_COLOR) { if (cl && cl != cur_color) { cur_color = cl; fputs(cl, stdout); } return (char *)NULL; } if (!cl) return cur_color; return cl; } /* Recolorize current input line starting from rl_point */ void recolorize_line(void) { /* Hide the cursor to minimize flickering */ HIDE_CURSOR; /* Set text color to default */ if (cur_color != tx_c && cur_color != wp_c && cur_color != hn_c) { cur_color = tx_c; fputs(tx_c, stdout); } int bk_point = rl_point; if (rl_point > 0 && rl_point != rl_end) rl_point--; /* Get the current color up to the current cursor position */ size_t i; char *cl = (char *)NULL; for (i = 0; i < (size_t)rl_point; i++) { cl = rl_highlight(rl_line_buffer, i, INFORM_COLOR); if (cl) cur_color = cl; } if (cl) fputs(cl, stdout); if (rl_point == 0 && rl_end == 0) { UNHIDE_CURSOR; return; } int end_bk = rl_end; int start = rl_point > 0 ? rl_point - 1 : 0; char *ss = rl_copy_text(start, rl_end); rl_delete_text(start, rl_end); rl_point = rl_end = start; if (start == 0 && end_bk >= 1) /* First char of a non-empty recolored line (recovering from wrong cmd) */ rl_redisplay(); i = 0; size_t l = 0; if (!ss || !*ss) goto EXIT; /* Loop through each char from cursor position onward and colorize it. */ char t[PATH_MAX + 1]; for (;ss[i]; i++) { rl_highlight(ss, i, SET_COLOR); /* Redisplay the current char with the appropriate color */ if ((signed char)ss[i] < 0) { t[l] = ss[i]; l++; if ((signed char)ss[i + 1] >= 0) { t[l] = '\0'; l = 0; rl_insert_text(t); rl_redisplay(); } continue; } t[0] = ss[i]; t[1] = '\0'; rl_insert_text(t); rl_redisplay(); } EXIT: free(ss); rl_point = bk_point; UNHIDE_CURSOR; } clifm-1.26.3/src/highlight.h000066400000000000000000000020721506632037700156160ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* highlight.h */ #ifndef HIGHLIGHT_H #define HIGHLIGHT_H __BEGIN_DECLS char *rl_highlight(char *str, const size_t pos, const int flag); void recolorize_line(void); __END_DECLS #endif /* HIGHLIGHT_H */ clifm-1.26.3/src/history.c000066400000000000000000000437121506632037700153510ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* history.c -- functions for the history system */ #include "helpers.h" #include #include #include #include #include "aux.h" #include "checks.h" #include "file_operations.h" #include "history.h" #include "init.h" #include "messages.h" #include "misc.h" #include "readline.h" /* rl_get_y_or_n */ #include "spawn.h" /* Return a string with the current date. * Used to compose log entries. */ static char * get_date(void) { const time_t rawtime = time(NULL); struct tm t; if (!localtime_r(&rawtime, &t)) return (char *)NULL; const size_t date_max = MAX_TIME_STR; char *date = xnmalloc(date_max + 1, sizeof(char)); *date = '\0'; strftime(date, date_max, "%Y-%m-%dT%T%z", &t); return date; } /* Print available logs, for messages, if FLAG is MSG_LOGS, or for * commands otherwise. */ int print_logs(const int flag) { char *file = flag == MSG_LOGS ? msgs_log_file : cmds_log_file; FILE *log_fp = fopen(file, "r"); if (!log_fp) { err(0, NOPRINT_PROMPT, "log: '%s': %s\n", file, strerror(errno)); return FUNC_FAILURE; } size_t line_size = 0; char *line_buff = (char *)NULL; while (getline(&line_buff, &line_size, log_fp) > 0) fputs(line_buff, stdout); free(line_buff); fclose(log_fp); return FUNC_SUCCESS; } static int gen_file(const char *file) { int fd = 0; FILE *fp = open_fwrite(file, &fd); if (!fp) return FUNC_FAILURE; fclose(fp); return FUNC_SUCCESS; } /* Clear logs (the message logs if FLAG is CLR_MSG_LOGS, or the command logs * otherwise). * Delete the file, recreate it, and write the last command ("log msg/cmd clear") * into the command logs file. */ int clear_logs(const int flag) { char *file = flag == MSG_LOGS ? msgs_log_file : cmds_log_file; if (!file || !*file) return FUNC_SUCCESS; if (remove(file) == -1) { xerror("log: '%s': %s\n", file, strerror(errno)); return errno; } const int ret = gen_file(file); if (ret != FUNC_SUCCESS) return FUNC_FAILURE; free(last_cmd); last_cmd = savestring(flag == MSG_LOGS ? "log msg clear" : "log cmd clear", 13); const int bk = conf.log_cmds; conf.log_cmds = 1; log_cmd(); conf.log_cmds = bk; return FUNC_SUCCESS; } /* Log LAST_CMD (global) into LOG_FILE */ int log_cmd(void) { if (xargs.stealth_mode == 1 || !last_cmd || conf.log_cmds == 0) { free(last_cmd); last_cmd = (char *)NULL; return FUNC_SUCCESS; } if (config_ok == 0 || !cmds_log_file) return FUNC_FAILURE; /* Construct the log line */ char *date = get_date(); const size_t log_len = strlen(date ? date : "unknown") + (workspaces[cur_ws].path ? strlen(workspaces[cur_ws].path) : 2) + strlen(last_cmd) + 6; char *full_log = xnmalloc(log_len, sizeof(char)); snprintf(full_log, log_len, "[%s] %s:%s\n", date ? date : "unknown", workspaces[cur_ws].path ? workspaces[cur_ws].path : "?", last_cmd); free(date); free(last_cmd); last_cmd = (char *)NULL; /* Write the log into LOG_FILE */ FILE *log_fp = open_fappend(cmds_log_file); if (!log_fp) { err('e', PRINT_PROMPT, "log: '%s': %s\n", cmds_log_file, strerror(errno)); free(full_log); return FUNC_FAILURE; } fputs(full_log, log_fp); free(full_log); fclose(log_fp); return FUNC_SUCCESS; } /* Write _MSG into the log file: [date] _MSG */ static void write_msg_into_logfile(const char *msg_str) { if (!msg_str || !*msg_str || !msgs_log_file || !*msgs_log_file) return; FILE *fp = open_fappend(msgs_log_file); if (!fp) { /* Do not log this error: We might enter into an infinite loop * trying to access a file that cannot be accessed. Just warn the user * and print the error to STDERR. */ fprintf(stderr, "%s: '%s': %s\n", PROGRAM_NAME, msgs_log_file, strerror(errno)); press_any_key_to_continue(0); return; } char *date = get_date(); fprintf(fp, "[%s] %s", date ? date : "unknown", msg_str); fclose(fp); free(date); } static void send_kitty_notification(const char *msg) { static int kitty_msg_id = 1; const int urgency = pmsg == ERROR ? 2 : (pmsg == WARNING ? 1 : 0); printf("\x1b]99;i=%d:d=0:p=title;%s\x1b\\", kitty_msg_id, PROGRAM_NAME); printf("\x1b]99;i=%d:d=1:n=file-manager:f=%s:u=%d:p=body;%s\x1b\\", kitty_msg_id, PROGRAM_NAME, urgency, msg); fflush(stdout); if (kitty_msg_id < INT_MAX) kitty_msg_id++; } /* Let's send a desktop notification */ static void send_desktop_notification(char *msg) { if (!msg || !*msg || *msg == '\n') return; size_t mlen = strlen(msg); if (msg[mlen - 1] == '\n') { msg[mlen - 1] = '\0'; mlen--; } /* Some messages are written in the form "PROGRAM_NAME: MSG". We only * want the MSG part. */ int ret = 0; const size_t s = sizeof(PROGRAM_NAME) - 1; char *p = msg; if (strncmp(msg, PROGRAM_NAME, s) == 0 && msg[s] == ':' && msg[s + 1] == ' ') { p += s + 2; if (!*p) return; } if (conf.desktop_notifications == DESKTOP_NOTIF_KITTY) { send_kitty_notification(p); return; } char type[12]; *type = '\0'; switch (pmsg) { #if defined(__HAIKU__) case ERROR: snprintf(type, sizeof(type), "error"); break; case WARNING: snprintf(type, sizeof(type), "important"); break; case NOTICE: /* fallthrough */ default: snprintf(type, sizeof(type), "information"); break; #elif defined(__APPLE__) case ERROR: snprintf(type, sizeof(type), "Error"); break; case WARNING: snprintf(type, sizeof(type), "Warning"); break; case NOTICE: /* fallthrough */ default: snprintf(type, sizeof(type), "Notice"); break; #else case ERROR: snprintf(type, sizeof(type), "critical"); break; case WARNING: snprintf(type, sizeof(type), "normal"); break; case NOTICE: /* fallthrough */ default: snprintf(type, sizeof(type), "low"); break; #endif /* __HAIKU__ */ } #if defined(__HAIKU__) char *cmd[] = {"notify", "--type", type, "--title", PROGRAM_NAME, p, NULL}; ret = launch_execv(cmd, FOREGROUND, E_MUTE); #elif defined(__APPLE__) size_t msg_len = strlen(msg) + strlen(type) + (sizeof(PROGRAM_NAME) - 1) + 60; char *tmp_msg = xnmalloc(msg_len, sizeof(char)); snprintf(tmp_msg, msg_len, "'display notification \"%s\" subtitle \"%s\" with title \"%s\"'", msg, type, PROGRAM_NAME); char *cmd[] = {"osascript", "-e", tmp_msg, NULL}; ret = launch_execv(cmd, FOREGROUND, E_MUTE); free(tmp_msg); #else char *cmd[] = {"notify-send", "-u", type, PROGRAM_NAME, p, NULL}; ret = launch_execv(cmd, FOREGROUND, E_MUTE); #endif /* __HAIKU__ */ if (ret == FUNC_SUCCESS) return; /* Error: warn and print the original message */ xerror(_("%s: Notification daemon error: %s\n" "Disable desktop notifications (run 'help desktop-notifications' " "for details) or %s to silence this " "warning (original message printed below)\n"), PROGRAM_NAME, strerror(ret), ret == ENOENT ? _("install a notification daemon") : _("fix the error (consult your daemon's documentation)")); xerror("%s\n", msg); } /* Handle the error message MSG. * * If ADD_TO_MSGS_LIST is 1, store MSG into the messages array: MSG will be * accessible to the user via the 'msg' command. * * If PRINT_PROMPT is 1, either raise a flag to tell the next prompt to print * the message itself, or, if desktop notifications are enabled and LOGME is * not zero (ERR_NO_LOG), send the notification to the notification daemon. * NOTE: if not zero, LOGME could be either 1 (error/warning) or -1 (notice). * * If PRINT_PROMPT is not 1, MSG is printed directly here. * * Finally, if logs are enabled and LOGME is 1, write the message into the log * file as follows: "m:[date] msg", where 'date' is YYYY-MM-DDTHH:MM:SS. * */ void log_msg(char *msg_str, const int print_prompt, const int logme, const int add_to_msgs_list) { if (!msg_str) return; const size_t msg_len = strlen(msg_str); if (msg_len == 0) return; if (add_to_msgs_list == 1) { msgs_n++; messages = xnrealloc(messages, (size_t)(msgs_n + 1), sizeof(struct pmsgs_t)); messages[msgs_n - 1].text = savestring(msg_str, msg_len); messages[msgs_n - 1].read = 0; messages[msgs_n].text = (char *)NULL; messages[msgs_n].read = 0; } if (print_prompt == 1) { if (conf.desktop_notifications > 0 && logme != 0) send_desktop_notification(msg_str); else print_msg = 1; } else { fputs(msg_str, stderr); } if (xargs.stealth_mode == 1 || config_ok == 0 || !msgs_log_file || !*msgs_log_file || logme != 1 || conf.log_msgs == 0) return; write_msg_into_logfile(msg_str); } static void append_to_dirhist_file(const char *dir_path) { if (!dirhist_file || !dir_path || !*dir_path || xargs.stealth_mode == 1) return; FILE *fp = open_fappend(dirhist_file); if (!fp) { xerror(_("%s: '%s': Error saving directory entry: %s\n"), PROGRAM_NAME, dir_path, strerror(errno)); return; } fprintf(fp, "%s\n", dir_path); fclose(fp); } /* Add DIR_PATH to visited directory history (old_pwd) */ void add_to_dirhist(const char *dir_path) { /* If already at the end of dirhist, add new entry */ if (dirhist_cur_index + 1 >= dirhist_total_index) { /* Do not add anything if new path equals last entry in * directory history */ if ((dirhist_total_index - 1) >= 0 && old_pwd[dirhist_total_index - 1] && *(dir_path + 1) == *(old_pwd[dirhist_total_index - 1] + 1) && strcmp(dir_path, old_pwd[dirhist_total_index - 1]) == 0) return; old_pwd = xnrealloc(old_pwd, (size_t)dirhist_total_index + 2, sizeof(char *)); dirhist_cur_index = dirhist_total_index; old_pwd[dirhist_total_index] = savestring(dir_path, strlen(dir_path)); append_to_dirhist_file(dir_path); dirhist_total_index++; old_pwd[dirhist_total_index] = (char *)NULL; } /* If not at the end of dirhist, add previous AND new entry */ else { old_pwd = xnrealloc(old_pwd, (size_t)dirhist_total_index + 3, sizeof(char *)); old_pwd[dirhist_total_index] = savestring( old_pwd[dirhist_cur_index], strlen(old_pwd[dirhist_cur_index])); dirhist_total_index++; dirhist_cur_index = dirhist_total_index; old_pwd[dirhist_total_index] = savestring(dir_path, strlen(dir_path)); dirhist_total_index++; old_pwd[dirhist_total_index] = (char *)NULL; } } static int reload_history(void) { clear_history(); read_history(hist_file); history_truncate_file(hist_file, conf.max_hist); /* Update the history array */ const int ret = get_history(); return ret; } static int edit_history(char **args) { struct stat attr; if (stat(hist_file, &attr) == -1) { xerror("history: '%s': %s\n", hist_file, strerror(errno)); return errno; } const time_t mtime_bfr = attr.st_mtime; int ret = open_config_file(args[2], hist_file); if (ret != FUNC_SUCCESS) return ret; /* Get modification time after opening the config file. */ if (stat(hist_file, &attr) == -1) { xerror("history: '%s': %s\n", hist_file, strerror(errno)); return errno; } /* If modification times differ, the file was modified after being * opened. */ if (mtime_bfr != attr.st_mtime) { ret = reload_history(); print_reload_msg(NULL, NULL, _("File modified. History entries reloaded.\n")); return ret; } return FUNC_SUCCESS; } static int clear_history_func(char **args) { if (rl_get_y_or_n(_("Clear history?"), conf.default_answer.remove) == 0) return FUNC_SUCCESS; /* Let's overwrite whatever was there. */ int fd = 0; FILE *hist_fp = open_fwrite(hist_file, &fd); if (!hist_fp) { err(0, NOPRINT_PROMPT, "history: '%s': %s\n", hist_file, strerror(errno)); return FUNC_FAILURE; } /* Do not create an empty file */ fprintf(hist_fp, "%s %s\n", args[0], args[1]); fclose(hist_fp); /* Reset readline history */ return reload_history(); } static int print_history_list(const int timestamp) { int n = DIGINUM(current_hist_n); size_t i; for (i = 0; i < current_hist_n; i++) { if (timestamp == 1 && history[i].date != -1) { char tdate[MAX_TIME_STR]; gen_time_str(tdate, sizeof(tdate), history[i].date); printf(" %s%-*zu%s %s%s%s %s\n", el_c, n, i + 1, df_c, conf.colorize == 1 ? "\x1b[0;2m" : "", tdate, "\x1b[0m", history[i].cmd); } else { printf(" %s%-*zu%s %s\n", el_c, n, i + 1, df_c, history[i].cmd); } } return FUNC_SUCCESS; } static int print_last_items(const char *str, const int timestamp) { int num = atoi(str); if (num < 0 || num > (int)current_hist_n) num = (int)current_hist_n; int n = DIGINUM(current_hist_n); size_t i; for (i = current_hist_n - (size_t)num; i < current_hist_n; i++) { if (timestamp == 1 && history[i].date != -1) { char tdate[MAX_TIME_STR]; gen_time_str(tdate, sizeof(tdate), history[i].date); printf(" %s# %s%s\n", "\x1b[0;2m", tdate, "\x1b[0m"); } printf(" %s%-*zu%s %s\n", el_c, n, i + 1, df_c, history[i].cmd); } return FUNC_SUCCESS; } static int print_hist_status(void) { printf(_("History is %s\n"), hist_status == 1 ? "enabled" : "disabled"); return FUNC_SUCCESS; } static int toggle_history(const char *arg) { if (!arg || !*arg) return FUNC_FAILURE; switch (*arg) { case 'o': hist_status = (arg[1] == 'n' ? 1 : 0); return print_hist_status(); case 's': return print_hist_status(); default: puts(_(HISTORY_USAGE)); return FUNC_FAILURE; } } int history_function(char **args) { if (xargs.stealth_mode == 1) { printf(_("%s: history: %s\n"), PROGRAM_NAME, STEALTH_DISABLED); return FUNC_SUCCESS; } if (config_ok == 0) { xerror(_("%s: History function disabled\n"), PROGRAM_NAME); return FUNC_FAILURE; } /* If no arguments, print the history list */ if (!args[1] || (strcmp(args[1], "show-time") == 0 && !args[2])) return print_history_list(args[1] ? HIST_TIME : NO_HIST_TIME); if (*args[1] == 'e' && strcmp(args[1], "edit") == 0) return edit_history(args); if (*args[1] == 'c' && strcmp(args[1], "clear") == 0) return clear_history_func(args); /* If "history -n [show-time]", print the last -n elements */ if (*args[1] == '-' && is_number(args[1] + 1)) return print_last_items(args[1] + 1, (args[2] && strcmp(args[2], "show-time") == 0) ? HIST_TIME : NO_HIST_TIME); /* If "history show-time -n" */ if ((*args[1] == 's' && strcmp(args[1], "show-time") == 0) && args[2] && *args[2] == '-' && is_number(args[2] + 1)) return print_last_items(args[2] + 1, HIST_TIME); if ((*args[1] == 'o' || *args[1] == 's') && (strcmp(args[1], "on") == 0 || strcmp(args[1], "off") == 0 || strcmp(args[1], "status") == 0)) return toggle_history(args[1]); /* None of the above */ puts(_(HISTORY_USAGE)); return FUNC_SUCCESS; } int get_history(void) { if (config_ok == 0 || !hist_file) return FUNC_FAILURE; if (current_hist_n == 0) { /* Coming from main() */ history = xcalloc(1, sizeof(struct history_t)); } else { /* Only true when comming from 'history clear' */ size_t i; for (i = 0; history[i].cmd; i++) free(history[i].cmd); history = xnrealloc(history, 1, sizeof(struct history_t)); current_hist_n = 0; } FILE *hist_fp = fopen(hist_file, "r"); if (!hist_fp) { err('e', PRINT_PROMPT, "history: '%s': %s\n", hist_file, strerror(errno)); return FUNC_FAILURE; } size_t line_size = 0; char *line_buff = (char *)NULL; ssize_t line_len = 0; time_t tdate = -1; while ((line_len = getline(&line_buff, &line_size, hist_fp)) > 0) { line_buff[line_len - 1] = '\0'; if (!*line_buff) continue; /* Store the command timestamp and continue: the next line is * the cmd itself. */ if (*line_buff == history_comment_char && *(line_buff + 1) && is_number(line_buff + 1)) { int d = atoi(line_buff + 1); tdate = d == INT_MIN ? -1 : (time_t)d; continue; } history = xnrealloc(history, current_hist_n + 2, sizeof(struct history_t)); history[current_hist_n].cmd = savestring(line_buff, (size_t)line_len); history[current_hist_n].len = (size_t)line_len; history[current_hist_n].date = tdate; tdate = -1; current_hist_n++; } curhistindex = current_hist_n ? current_hist_n - 1 : 0; history[current_hist_n].cmd = (char *)NULL; history[current_hist_n].len = 0; history[current_hist_n].date = -1; free(line_buff); fclose(hist_fp); return FUNC_SUCCESS; } void add_to_cmdhist(char *cmd) { if (!cmd) return; /* Remove trailing spaces from CMD */ size_t cmd_len = strlen(cmd); int i = (int)cmd_len; while (--i >= 0 && cmd[i] == ' ') { cmd[i] = '\0'; cmd_len--; } if (cmd_len == 0) return; /* For readline */ add_history(cmd); if (config_ok == 1 && hist_status == 1 && hist_file) append_history(1, hist_file); /* For us */ /* Add the new input to the history array */ const time_t tdate = time(NULL); history = xnrealloc(history, (size_t)(current_hist_n + 2), sizeof(struct history_t)); history[current_hist_n].cmd = savestring(cmd, cmd_len); history[current_hist_n].len = cmd_len; history[current_hist_n].date = tdate; current_hist_n++; history[current_hist_n].cmd = (char *)NULL; history[current_hist_n].len = 0; history[current_hist_n].date = -1; } /* Returns 1 if INPUT should be saved on history or 0 if not. */ int record_cmd(const char *input) { if (!input || !*input) return 0; dir_cmds.last_cmd_ignored = 0; /* Ignore entries matching HistIgnore */ if (conf.histignore_regex && *conf.histignore_regex && regexec(®ex_hist, input, 0, NULL, 0) == FUNC_SUCCESS) { dir_cmds.last_cmd_ignored = 1; return 0; } /* Consequtively equal commands in history */ if (history && current_hist_n > 0 && history[current_hist_n - 1].cmd && *input == *history[current_hist_n - 1].cmd && strcmp(input, history[current_hist_n - 1].cmd) == 0) { /* Update timestamp */ history[current_hist_n - 1].date = time(NULL); return 0; } return 1; } clifm-1.26.3/src/history.h000066400000000000000000000027421506632037700153540ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* history.h */ #ifndef HISTORY_H #define HISTORY_H /* Macros for history_function() */ #define NO_HIST_TIME 0 #define HIST_TIME 1 /* Macros for clear_logs() and print_logs() */ #define MSG_LOGS 1 #define CMD_LOGS 0 __BEGIN_DECLS void add_to_cmdhist(char *cmd); void add_to_dirhist(const char *dir_path); int clear_logs(const int flag); int get_history(void); int history_function(char **args); int log_cmd(void); void log_msg(char *msg_str, const int print_prompt, const int logme, const int add_to_msgs_list); int print_logs(const int flag); int record_cmd(const char *input); __END_DECLS #endif /* HISTORY_H */ clifm-1.26.3/src/icons-emoji.h000066400000000000000000000103631506632037700160650ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* icons-emoji.h - Icon definitions for Clifm */ /* Taken from * https://github.com/jarun/nnn, licensed under BSD-2-Clause. * All changes are licensed under GPL-2.0-or-later. */ /* For a list of emojis consult: * https://unicode.org/Public/emoji/5.0/emoji-test.txt */ /* For Arch based systems you need noto-fonts-emoji, for Debian-based * fonts-noto-color-emoji, and for RedHat-based google-noto-emoji-fonts * Once installed, test emojis on your terminal issuing this command: * wget https://unicode.org/Public/emoji/5.0/emoji-test.txt -qO - | less */ /* Most emojis here are two chars wide. If using one char wide emojis, add * a space to get consistent padding. E.g., "X ", or to the left: " X" */ #ifndef ICONS_EMOJI #define ICONS_EMOJI #define EMOJI_ARCHIVE "📦" #define EMOJI_ASM EMOJI_CODE #define EMOJI_AUDIO "🎵" #define EMOJI_BINARY "📓" #define EMOJI_BOOK_OPEN "📖" #define EMOJI_BRIEFCASE "💼" #define EMOJI_C "🇨 " #define EMOJI_CLOJURE EMOJI_CODE #define EMOJI_CODE "📑" #define EMOJI_CHANGELOG "🔺" #define EMOJI_CHESS "♟️ " #define EMOJI_CONF "🔧" #define EMOJI_COFFEE EMOJI_JAVA #define EMOJI_CPP EMOJI_C #define EMOJI_CSHARP EMOJI_CODE #define EMOJI_CSS "🦋" #define EMOJI_DATABASE EMOJI_FILE #define EMOJI_DESKTOP "💻" #define EMOJI_DART EMOJI_CODE #define EMOJI_DIFF "📋" #define EMOJI_DISK "💿" #define EMOJI_DOCKER "🐋" #define EMOJI_DOWNLOAD "📥" #define EMOJI_ELECTRON "⚛ " #define EMOJI_ELIXIR "💧" #define EMOJI_ELM EMOJI_CODE #define EMOJI_ENCRYPTED "🔒" #define EMOJI_ERLANG EMOJI_CODE #define EMOJI_EXEC "⚙️ " #define EMOJI_FILE "📄" #define EMOJI_FOLDER "📂" #define EMOJI_FONT "🔤" #define EMOJI_FSHARP EMOJI_CODE #define EMOJI_HASKELL EMOJI_CODE #define EMOJI_GAMES "🎮" #define EMOJI_GIT "🌱" #define EMOJI_GO "🐹" #define EMOJI_HOME "🏠" #define EMOJI_IMAGE "🎨" #define EMOJI_JAVA "☕" #define EMOJI_JAVASCRIPT EMOJI_CODE #define EMOJI_JULIA EMOJI_CODE #define EMOJI_JSON EMOJI_CONF #define EMOJI_KEY "🔑" #define EMOJI_KOTLIN "🇰 " #define EMOJI_LICENSE "⚖️ " #define EMOJI_LINK "🔗" #define EMOJI_LINUX "🐧" #define EMOJI_LIST "✅" #define EMOJI_LOCK "🔐" #define EMOJI_LUA "🌘" #define EMOJI_MAKE "🛠 " #define EMOJI_MANUAL "❔" #define EMOJI_MARKDOWN "⬇ " #define EMOJI_MATLAB EMOJI_CODE #define EMOJI_MOVIE "🎬" #define EMOJI_MUSIC "🎧" #define EMOJI_NOTE "📝" #define EMOJI_OCAML "🐫" #define EMOJI_PATCH "🩹" #define EMOJI_PDF "🔖" #define EMOJI_PERL "🐪" #define EMOJI_PHOTO "📸" #define EMOJI_PHOTOSHOP "🖌️ " #define EMOJI_PICTURE "📷" #define EMOJI_PLAYLIST EMOJI_MUSIC #define EMOJI_POSTSCRIPT EMOJI_PDF #define EMOJI_PRESENTATION "📙" #define EMOJI_PUBLIC "👁 " #define EMOJI_PYTHON "🐍" #define EMOJI_R "🇷 " #define EMOJI_RSS "📡" #define EMOJI_RUBY "💎" #define EMOJI_RUST "🦀" #define EMOJI_SASS EMOJI_CODE #define EMOJI_SCALA EMOJI_CODE #define EMOJI_SCRIPT "📜" #define EMOJI_SHARE "🖇 " #define EMOJI_STEAM EMOJI_GAMES #define EMOJI_STYLESHEET "📗" #define EMOJI_SUBTITLES "💬" #define EMOJI_SWIFT EMOJI_CODE #define EMOJI_TEMPLATE "📎" #define EMOJI_TEX EMOJI_FILE #define EMOJI_TEXT EMOJI_FILE #define EMOJI_TYPESCRIPT EMOJI_CODE #define EMOJI_TRASH EMOJI_FOLDER #define EMOJI_VIDEOS "📽 " #define EMOJI_VIM EMOJI_TEXT #define EMOJI_VISUALSTUDIO EMOJI_CODE #define EMOJI_WEB "🌐" #define EMOJI_WINDOWS "🪟" #define EMOJI_WORD "📘" #endif /* ICONS_EMOJI */ clifm-1.26.3/src/icons-in-terminal.h000066400000000000000000003735501506632037700172130ustar00rootroot00000000000000/* icons-in-terminal.h - Icon definitions for Clifm */ /* Taken from * https://github.com/sebastiencs/icons-in-terminal/blob/master/build/icons-in-terminal.h, * licensed MIT */ #ifndef ICONS_IN_TERMINAL #define ICONS_IN_TERMINAL #define POWERLINE_BRANCH "\ue0a0" #define POWERLINE_LINE_NUMBER "\ue0a1" #define POWERLINE_READONLY "\ue0a2" #define POWERLINE_EXTRA_COLUMN_NUMBER "\ue0a3" #define POWERLINE_LEFT_HARD_DIVIDER "\ue0b0" #define POWERLINE_LEFT_SOFT_DIVIDER "\ue0b1" #define POWERLINE_RIGHT_HARD_DIVIDER "\ue0b2" #define POWERLINE_RIGHT_SOFT_DIVIDER "\ue0b3" #define POWERLINE_EXTRA_RIGHT_HALF_CIRCLE_THICK "\ue0b4" #define POWERLINE_EXTRA_RIGHT_HALF_CIRCLE_THIN "\ue0b5" #define POWERLINE_EXTRA_LEFT_HALF_CIRCLE_THICK "\ue0b6" #define POWERLINE_EXTRA_LEFT_HALF_CIRCLE_THIN "\ue0b7" #define POWERLINE_EXTRA_LOWER_LEFT_TRIANGLE "\ue0b8" #define POWERLINE_EXTRA_BACKSLASH_SEPARATOR "\ue0b9" #define POWERLINE_EXTRA_LOWER_RIGHT_TRIANGLE "\ue0ba" #define POWERLINE_EXTRA_FORWARDSLASH_SEPARATOR "\ue0bb" #define POWERLINE_EXTRA_UPPER_LEFT_TRIANGLE "\ue0bc" #define POWERLINE_EXTRA_FORWARDSLASH_SEPARATOR_REDUNDANT "\ue0bd" #define POWERLINE_EXTRA_UPPER_RIGHT_TRIANGLE "\ue0be" #define POWERLINE_EXTRA_BACKSLASH_SEPARATOR_REDUNDANT "\ue0bf" #define POWERLINE_EXTRA_FLAME_THICK "\ue0c0" #define POWERLINE_EXTRA_FLAME_THIN "\ue0c1" #define POWERLINE_EXTRA_FLAME_THICK_MIRRORED "\ue0c2" #define POWERLINE_EXTRA_FLAME_THIN_MIRRORED "\ue0c3" #define POWERLINE_EXTRA_PIXELATED_SQUARES_SMALL "\ue0c4" #define POWERLINE_EXTRA_PIXELATED_SQUARES_SMALL_MIRRORED "\ue0c5" #define POWERLINE_EXTRA_PIXELATED_SQUARES_BIG "\ue0c6" #define POWERLINE_EXTRA_PIXELATED_SQUARES_BIG_MIRRORED "\ue0c7" #define POWERLINE_EXTRA_ICE_WAVEFORM "\ue0c8" #define POWERLINE_EXTRA_ICE_WAVEFORM_MIRRORED "\ue0ca" #define POWERLINE_EXTRA_HONEYCOMB "\ue0cc" #define POWERLINE_EXTRA_HONEYCOMB_OUTLINE "\ue0cd" #define POWERLINE_EXTRA_LEGO_SEPARATOR "\ue0ce" #define POWERLINE_EXTRA_LEGO_SEPARATOR_THIN "\ue0cf" #define POWERLINE_EXTRA_LEGO_BLOCK_FACING "\ue0d0" #define POWERLINE_EXTRA_LEGO_BLOCK_SIDEWAYS "\ue0d1" #define POWERLINE_EXTRA_TRAPEZOID_TOP_BOTTOM "\ue0d2" #define POWERLINE_EXTRA_TRAPEZOID_TOP_BOTTOM_MIRRORED "\ue0d4" #define OCT_HEART "\ue000" #define OCT_ZAP "\ue001" #define OCT_LIGHT_BULB "\ue002" #define OCT_REPO "\ue003" #define OCT_REPO_FORKED "\ue004" #define OCT_REPO_PUSH "\ue005" #define OCT_REPO_PULL "\ue006" #define OCT_BOOK "\ue007" #define OCT_OCTOFACE "\ue008" #define OCT_GIT_PULL_REQUEST "\ue009" #define OCT_MARK_GITHUB "\ue00a" #define OCT_CLOUD_DOWNLOAD "\ue00b" #define OCT_CLOUD_UPLOAD "\ue00c" #define OCT_KEYBOARD "\ue00d" #define OCT_GIST "\ue00e" #define OCT_FILE_CODE "\ue00f" #define OCT_FILE_TEXT "\ue010" #define OCT_FILE_MEDIA "\ue011" #define OCT_FILE_ZIP "\ue012" #define OCT_FILE_PDF "\ue013" #define OCT_TAG "\ue014" #define OCT_FILE_DIRECTORY "\ue015" #define OCT_FILE_SUBMODULE "\ue016" #define OCT_PERSON "\ue017" #define OCT_JERSEY "\ue018" #define OCT_GIT_COMMIT "\ue019" #define OCT_GIT_BRANCH "\ue01a" #define OCT_GIT_MERGE "\ue01b" #define OCT_MIRROR "\ue01c" #define OCT_ISSUE_OPENED "\ue01d" #define OCT_ISSUE_REOPENED "\ue01e" #define OCT_ISSUE_CLOSED "\ue01f" #define OCT_STAR "\ue020" #define OCT_COMMENT "\ue021" #define OCT_QUESTION "\ue022" #define OCT_ALERT "\ue023" #define OCT_SEARCH "\ue024" #define OCT_GEAR "\ue025" #define OCT_RADIO_TOWER "\ue026" #define OCT_TOOLS "\ue027" #define OCT_SIGN_OUT "\ue028" #define OCT_ROCKET "\ue029" #define OCT_RSS "\ue02a" #define OCT_CLIPPY "\ue02b" #define OCT_SIGN_IN "\ue02c" #define OCT_ORGANIZATION "\ue02d" #define OCT_DEVICE_MOBILE "\ue02e" #define OCT_UNFOLD "\ue02f" #define OCT_CHECK "\ue030" #define OCT_MAIL "\ue031" #define OCT_MAIL_READ "\ue032" #define OCT_ARROW_UP "\ue033" #define OCT_ARROW_RIGHT "\ue034" #define OCT_ARROW_DOWN "\ue035" #define OCT_ARROW_LEFT "\ue036" #define OCT_PIN "\ue037" #define OCT_GIFT "\ue038" #define OCT_GRAPH "\ue039" #define OCT_TRIANGLE_LEFT "\ue03a" #define OCT_CREDIT_CARD "\ue03b" #define OCT_CLOCK "\ue03c" #define OCT_RUBY "\ue03d" #define OCT_BROADCAST "\ue03e" #define OCT_KEY "\ue03f" #define OCT_REPO_FORCE_PUSH "\ue040" #define OCT_REPO_CLONE "\ue041" #define OCT_DIFF "\ue042" #define OCT_EYE "\ue043" #define OCT_COMMENT_DISCUSSION "\ue044" #define OCT_MAIL_REPLY "\ue045" #define OCT_PRIMITIVE_DOT "\ue046" #define OCT_PRIMITIVE_SQUARE "\ue047" #define OCT_DEVICE_CAMERA "\ue048" #define OCT_DEVICE_CAMERA_VIDEO "\ue049" #define OCT_PENCIL "\ue04a" #define OCT_INFO "\ue04b" #define OCT_TRIANGLE_RIGHT "\ue04c" #define OCT_TRIANGLE_DOWN "\ue04d" #define OCT_LINK "\ue04e" #define OCT_PLUS "\ue04f" #define OCT_THREE_BARS "\ue050" #define OCT_CODE "\ue051" #define OCT_LOCATION "\ue052" #define OCT_LIST_UNORDERED "\ue053" #define OCT_LIST_ORDERED "\ue054" #define OCT_QUOTE "\ue055" #define OCT_VERSIONS "\ue056" #define OCT_CALENDAR "\ue057" #define OCT_LOCK "\ue058" #define OCT_DIFF_ADDED "\ue059" #define OCT_DIFF_REMOVED "\ue05a" #define OCT_DIFF_MODIFIED "\ue05b" #define OCT_DIFF_RENAMED "\ue05c" #define OCT_HORIZONTAL_RULE "\ue05d" #define OCT_ARROW_SMALL_RIGHT "\ue05e" #define OCT_MILESTONE "\ue05f" #define OCT_CHECKLIST "\ue060" #define OCT_MEGAPHONE "\ue061" #define OCT_CHEVRON_RIGHT "\ue062" #define OCT_BOOKMARK "\ue063" #define OCT_SETTINGS "\ue064" #define OCT_DASHBOARD "\ue065" #define OCT_HISTORY "\ue066" #define OCT_LINK_EXTERNAL "\ue067" #define OCT_MUTE "\ue068" #define OCT_X "\ue069" #define OCT_CIRCLE_SLASH "\ue06a" #define OCT_PULSE "\ue06b" #define OCT_SYNC "\ue06c" #define OCT_TELESCOPE "\ue06d" #define OCT_GIST_SECRET "\ue06e" #define OCT_HOME "\ue06f" #define OCT_STOP "\ue070" #define OCT_BUG "\ue071" #define OCT_LOGO_GITHUB "\ue072" #define OCT_FILE_BINARY "\ue073" #define OCT_DATABASE "\ue074" #define OCT_SERVER "\ue075" #define OCT_DIFF_IGNORED "\ue076" #define OCT_ELLIPSIS "\ue077" #define OCT_NO_NEWLINE "\ue078" #define OCT_HUBOT "\ue079" #define OCT_ARROW_SMALL_UP "\ue07a" #define OCT_ARROW_SMALL_DOWN "\ue07b" #define OCT_ARROW_SMALL_LEFT "\ue07c" #define OCT_CHEVRON_UP "\ue07d" #define OCT_CHEVRON_DOWN "\ue07e" #define OCT_CHEVRON_LEFT "\ue07f" #define OCT_TRIANGLE_UP "\ue080" #define OCT_GIT_COMPARE "\ue081" #define OCT_LOGO_GIST "\ue082" #define OCT_FILE_SYMLINK_FILE "\ue083" #define OCT_FILE_SYMLINK_DIRECTORY "\ue084" #define OCT_SQUIRREL "\ue085" #define OCT_GLOBE "\ue086" #define OCT_UNMUTE "\ue087" #define OCT_MENTION "\ue088" #define OCT_PACKAGE "\ue089" #define OCT_BROWSER "\ue08a" #define OCT_TERMINAL "\ue08b" #define OCT_MARKDOWN "\ue08c" #define OCT_DASH "\ue08d" #define OCT_FOLD "\ue08e" #define OCT_INBOX "\ue08f" #define OCT_TRASHCAN "\ue090" #define OCT_PAINTCAN "\ue091" #define OCT_FLAME "\ue092" #define OCT_BRIEFCASE "\ue093" #define OCT_PLUG "\ue094" #define OCT_CIRCUIT_BOARD "\ue095" #define OCT_MORTAR_BOARD "\ue096" #define OCT_LAW "\ue097" #define OCT_THUMBSUP "\ue098" #define OCT_THUMBSDOWN "\ue099" #define OCT_DESKTOP_DOWNLOAD "\ue09a" #define OCT_BEAKER "\ue09b" #define OCT_BELL "\ue09c" #define OCT_WATCH "\ue09d" #define OCT_SHIELD "\ue09e" #define OCT_BOLD "\ue09f" #define OCT_TEXT_SIZE "\ue0d5" #define OCT_ITALIC "\ue0d6" #define OCT_TASKLIST "\ue0d7" #define OCT_VERIFIED "\ue0d8" #define OCT_SMILEY "\ue0d9" #define OCT_UNVERIFIED "\ue0da" #define OCT_ELLIPSES "\ue0db" #define OCT_FILE "\ue0dc" #define OCT_GRABBER "\ue0dd" #define OCT_PLUS_SMALL "\ue0de" #define OCT_REPLY "\ue0df" #define OCT_DEVICE_DESKTOP "\ue0e0" #define FA_GLASS "\ue0e1" #define FA_MUSIC "\ue0e2" #define FA_SEARCH "\ue0e3" #define FA_ENVELOPE_O "\ue0e4" #define FA_HEART "\ue0e5" #define FA_STAR "\ue0e6" #define FA_STAR_O "\ue0e7" #define FA_USER "\ue0e8" #define FA_FILM "\ue0e9" #define FA_TH_LARGE "\ue0ea" #define FA_TH "\ue0eb" #define FA_TH_LIST "\ue0ec" #define FA_CHECK "\ue0ed" #define FA_CLOSE "\ue0ee" #define FA_SEARCH_PLUS "\ue0ef" #define FA_SEARCH_MINUS "\ue0f0" #define FA_POWER_OFF "\ue0f1" #define FA_SIGNAL "\ue0f2" #define FA_COG "\ue0f3" #define FA_TRASH_O "\ue0f4" #define FA_HOME "\ue0f5" #define FA_FILE_O "\ue0f6" #define FA_CLOCK_O "\ue0f7" #define FA_ROAD "\ue0f8" #define FA_DOWNLOAD "\ue0f9" #define FA_ARROW_CIRCLE_O_DOWN "\ue0fa" #define FA_ARROW_CIRCLE_O_UP "\ue0fb" #define FA_INBOX "\ue0fc" #define FA_PLAY_CIRCLE_O "\ue0fd" #define FA_REPEAT "\ue0fe" #define FA_REFRESH "\ue0ff" #define FA_LIST_ALT "\ue100" #define FA_LOCK "\ue101" #define FA_FLAG "\ue102" #define FA_HEADPHONES "\ue103" #define FA_VOLUME_OFF "\ue104" #define FA_VOLUME_DOWN "\ue105" #define FA_VOLUME_UP "\ue106" #define FA_QRCODE "\ue107" #define FA_BARCODE "\ue108" #define FA_TAG "\ue109" #define FA_TAGS "\ue10a" #define FA_BOOK "\ue10b" #define FA_BOOKMARK "\ue10c" #define FA_PRINT "\ue10d" #define FA_CAMERA "\ue10e" #define FA_FONT "\ue10f" #define FA_BOLD "\ue110" #define FA_ITALIC "\ue111" #define FA_TEXT_HEIGHT "\ue112" #define FA_TEXT_WIDTH "\ue113" #define FA_ALIGN_LEFT "\ue114" #define FA_ALIGN_CENTER "\ue115" #define FA_ALIGN_RIGHT "\ue116" #define FA_ALIGN_JUSTIFY "\ue117" #define FA_LIST "\ue118" #define FA_DEDENT "\ue119" #define FA_INDENT "\ue11a" #define FA_VIDEO_CAMERA "\ue11b" #define FA_IMAGE "\ue11c" #define FA_PENCIL "\ue11d" #define FA_MAP_MARKER "\ue11e" #define FA_ADJUST "\ue11f" #define FA_TINT "\ue120" #define FA_EDIT "\ue121" #define FA_SHARE_SQUARE_O "\ue122" #define FA_CHECK_SQUARE_O "\ue123" #define FA_ARROWS "\ue124" #define FA_STEP_BACKWARD "\ue125" #define FA_FAST_BACKWARD "\ue126" #define FA_BACKWARD "\ue127" #define FA_PLAY "\ue128" #define FA_PAUSE "\ue129" #define FA_STOP "\ue12a" #define FA_FORWARD "\ue12b" #define FA_FAST_FORWARD "\ue12c" #define FA_STEP_FORWARD "\ue12d" #define FA_EJECT "\ue12e" #define FA_CHEVRON_LEFT "\ue12f" #define FA_CHEVRON_RIGHT "\ue130" #define FA_PLUS_CIRCLE "\ue131" #define FA_MINUS_CIRCLE "\ue132" #define FA_TIMES_CIRCLE "\ue133" #define FA_CHECK_CIRCLE "\ue134" #define FA_QUESTION_CIRCLE "\ue135" #define FA_INFO_CIRCLE "\ue136" #define FA_CROSSHAIRS "\ue137" #define FA_TIMES_CIRCLE_O "\ue138" #define FA_CHECK_CIRCLE_O "\ue139" #define FA_BAN "\ue13a" #define FA_ARROW_LEFT "\ue13b" #define FA_ARROW_RIGHT "\ue13c" #define FA_ARROW_UP "\ue13d" #define FA_ARROW_DOWN "\ue13e" #define FA_MAIL_FORWARD "\ue13f" #define FA_EXPAND "\ue140" #define FA_COMPRESS "\ue141" #define FA_PLUS "\ue142" #define FA_MINUS "\ue143" #define FA_ASTERISK "\ue144" #define FA_EXCLAMATION_CIRCLE "\ue145" #define FA_GIFT "\ue146" #define FA_LEAF "\ue147" #define FA_FIRE "\ue148" #define FA_EYE "\ue149" #define FA_EYE_SLASH "\ue14a" #define FA_EXCLAMATION_TRIANGLE "\ue14b" #define FA_PLANE "\ue14c" #define FA_CALENDAR "\ue14d" #define FA_RANDOM "\ue14e" #define FA_COMMENT "\ue14f" #define FA_MAGNET "\ue150" #define FA_CHEVRON_UP "\ue151" #define FA_CHEVRON_DOWN "\ue152" #define FA_RETWEET "\ue153" #define FA_SHOPPING_CART "\ue154" #define FA_FOLDER "\ue155" #define FA_FOLDER_OPEN "\ue156" #define FA_ARROWS_V "\ue157" #define FA_ARROWS_H "\ue158" #define FA_BAR_CHART "\ue159" #define FA_TWITTER_SQUARE "\ue15a" #define FA_FACEBOOK_SQUARE "\ue15b" #define FA_CAMERA_RETRO "\ue15c" #define FA_KEY "\ue15d" #define FA_COGS "\ue15e" #define FA_COMMENTS "\ue15f" #define FA_THUMBS_O_UP "\ue160" #define FA_THUMBS_O_DOWN "\ue161" #define FA_STAR_HALF "\ue162" #define FA_HEART_O "\ue163" #define FA_SIGN_OUT "\ue164" #define FA_LINKEDIN_SQUARE "\ue165" #define FA_THUMB_TACK "\ue166" #define FA_EXTERNAL_LINK "\ue167" #define FA_SIGN_IN "\ue168" #define FA_TROPHY "\ue169" #define FA_GITHUB_SQUARE "\ue16a" #define FA_UPLOAD "\ue16b" #define FA_LEMON_O "\ue16c" #define FA_PHONE "\ue16d" #define FA_SQUARE_O "\ue16e" #define FA_BOOKMARK_O "\ue16f" #define FA_PHONE_SQUARE "\ue170" #define FA_TWITTER "\ue171" #define FA_FACEBOOK "\ue172" #define FA_GITHUB "\ue173" #define FA_UNLOCK "\ue174" #define FA_CREDIT_CARD "\ue175" #define FA_FEED "\ue176" #define FA_HDD_O "\ue177" #define FA_BULLHORN "\ue178" #define FA_BELL_O "\ue179" #define FA_CERTIFICATE "\ue17a" #define FA_HAND_O_RIGHT "\ue17b" #define FA_HAND_O_LEFT "\ue17c" #define FA_HAND_O_UP "\ue17d" #define FA_HAND_O_DOWN "\ue17e" #define FA_ARROW_CIRCLE_LEFT "\ue17f" #define FA_ARROW_CIRCLE_RIGHT "\ue180" #define FA_ARROW_CIRCLE_UP "\ue181" #define FA_ARROW_CIRCLE_DOWN "\ue182" #define FA_GLOBE "\ue183" #define FA_WRENCH "\ue184" #define FA_TASKS "\ue185" #define FA_FILTER "\ue186" #define FA_BRIEFCASE "\ue187" #define FA_ARROWS_ALT "\ue188" #define FA_GROUP "\ue189" #define FA_CHAIN "\ue18a" #define FA_CLOUD "\ue18b" #define FA_FLASK "\ue18c" #define FA_CUT "\ue18d" #define FA_COPY "\ue18e" #define FA_PAPERCLIP "\ue18f" #define FA_FLOPPY_O "\ue190" #define FA_SQUARE "\ue191" #define FA_BARS "\ue192" #define FA_LIST_UL "\ue193" #define FA_LIST_OL "\ue194" #define FA_STRIKETHROUGH "\ue195" #define FA_UNDERLINE "\ue196" #define FA_TABLE "\ue197" #define FA_MAGIC "\ue198" #define FA_TRUCK "\ue199" #define FA_PINTEREST "\ue19a" #define FA_PINTEREST_SQUARE "\ue19b" #define FA_GOOGLE_PLUS_SQUARE "\ue19c" #define FA_GOOGLE_PLUS "\ue19d" #define FA_MONEY "\ue19e" #define FA_CARET_DOWN "\ue19f" #define FA_CARET_UP "\ue1a0" #define FA_CARET_LEFT "\ue1a1" #define FA_CARET_RIGHT "\ue1a2" #define FA_COLUMNS "\ue1a3" #define FA_SORT "\ue1a4" #define FA_SORT_DESC "\ue1a5" #define FA_SORT_ASC "\ue1a6" #define FA_ENVELOPE "\ue1a7" #define FA_LINKEDIN "\ue1a8" #define FA_ROTATE_LEFT "\ue1a9" #define FA_GAVEL "\ue1aa" #define FA_DASHBOARD "\ue1ab" #define FA_COMMENT_O "\ue1ac" #define FA_COMMENTS_O "\ue1ad" #define FA_BOLT "\ue1ae" #define FA_SITEMAP "\ue1af" #define FA_UMBRELLA "\ue1b0" #define FA_CLIPBOARD "\ue1b1" #define FA_LIGHTBULB_O "\ue1b2" #define FA_EXCHANGE "\ue1b3" #define FA_CLOUD_DOWNLOAD "\ue1b4" #define FA_CLOUD_UPLOAD "\ue1b5" #define FA_USER_MD "\ue1b6" #define FA_STETHOSCOPE "\ue1b7" #define FA_SUITCASE "\ue1b8" #define FA_BELL "\ue1b9" #define FA_COFFEE "\ue1ba" #define FA_CUTLERY "\ue1bb" #define FA_FILE_TEXT_O "\ue1bc" #define FA_BUILDING_O "\ue1bd" #define FA_HOSPITAL_O "\ue1be" #define FA_AMBULANCE "\ue1bf" #define FA_MEDKIT "\ue1c0" #define FA_FIGHTER_JET "\ue1c1" #define FA_BEER "\ue1c2" #define FA_H_SQUARE "\ue1c3" #define FA_PLUS_SQUARE "\ue1c4" #define FA_ANGLE_DOUBLE_LEFT "\ue1c5" #define FA_ANGLE_DOUBLE_RIGHT "\ue1c6" #define FA_ANGLE_DOUBLE_UP "\ue1c7" #define FA_ANGLE_DOUBLE_DOWN "\ue1c8" #define FA_ANGLE_LEFT "\ue1c9" #define FA_ANGLE_RIGHT "\ue1ca" #define FA_ANGLE_UP "\ue1cb" #define FA_ANGLE_DOWN "\ue1cc" #define FA_DESKTOP "\ue1cd" #define FA_LAPTOP "\ue1ce" #define FA_TABLET "\ue1cf" #define FA_MOBILE "\ue1d0" #define FA_CIRCLE_O "\ue1d1" #define FA_QUOTE_LEFT "\ue1d2" #define FA_QUOTE_RIGHT "\ue1d3" #define FA_SPINNER "\ue1d4" #define FA_CIRCLE "\ue1d5" #define FA_MAIL_REPLY "\ue1d6" #define FA_GITHUB_ALT "\ue1d7" #define FA_FOLDER_O "\ue1d8" #define FA_FOLDER_OPEN_O "\ue1d9" #define FA_EXPAND_ALT "\ue1da" #define FA_COLLAPSE_ALT "\ue1db" #define FA_SMILE_O "\ue1dc" #define FA_FROWN_O "\ue1dd" #define FA_MEH_O "\ue1de" #define FA_GAMEPAD "\ue1df" #define FA_KEYBOARD_O "\ue1e0" #define FA_FLAG_O "\ue1e1" #define FA_FLAG_CHECKERED "\ue1e2" #define FA_TERMINAL "\ue1e3" #define FA_CODE "\ue1e4" #define FA_MAIL_REPLY_ALL "\ue1e5" #define FA_STAR_HALF_EMPTY "\ue1e6" #define FA_LOCATION_ARROW "\ue1e7" #define FA_CROP "\ue1e8" #define FA_CODE_FORK "\ue1e9" #define FA_CHAIN_BROKEN "\ue1ea" #define FA_QUESTION "\ue1eb" #define FA_INFO "\ue1ec" #define FA_EXCLAMATION "\ue1ed" #define FA_SUPERSCRIPT "\ue1ee" #define FA_SUBSCRIPT "\ue1ef" #define FA_ERASER "\ue1f0" #define FA_PUZZLE_PIECE "\ue1f1" #define FA_MICROPHONE "\ue1f2" #define FA_MICROPHONE_SLASH "\ue1f3" #define FA_SHIELD "\ue1f4" #define FA_CALENDAR_O "\ue1f5" #define FA_FIRE_EXTINGUISHER "\ue1f6" #define FA_ROCKET "\ue1f7" #define FA_MAXCDN "\ue1f8" #define FA_CHEVRON_CIRCLE_LEFT "\ue1f9" #define FA_CHEVRON_CIRCLE_RIGHT "\ue1fa" #define FA_CHEVRON_CIRCLE_UP "\ue1fb" #define FA_CHEVRON_CIRCLE_DOWN "\ue1fc" #define FA_HTML5 "\ue1fd" #define FA_CSS3 "\ue1fe" #define FA_ANCHOR "\ue1ff" #define FA_UNLOCK_ALT "\ue200" #define FA_BULLSEYE "\ue201" #define FA_ELLIPSIS_H "\ue202" #define FA_ELLIPSIS_V "\ue203" #define FA_RSS_SQUARE "\ue204" #define FA_PLAY_CIRCLE "\ue205" #define FA_TICKET "\ue206" #define FA_MINUS_SQUARE "\ue207" #define FA_MINUS_SQUARE_O "\ue208" #define FA_LEVEL_UP "\ue209" #define FA_LEVEL_DOWN "\ue20a" #define FA_CHECK_SQUARE "\ue20b" #define FA_PENCIL_SQUARE "\ue20c" #define FA_EXTERNAL_LINK_SQUARE "\ue20d" #define FA_SHARE_SQUARE "\ue20e" #define FA_COMPASS "\ue20f" #define FA_CARET_SQUARE_O_DOWN "\ue210" #define FA_CARET_SQUARE_O_UP "\ue211" #define FA_CARET_SQUARE_O_RIGHT "\ue212" #define FA_EUR "\ue213" #define FA_GBP "\ue214" #define FA_DOLLAR "\ue215" #define FA_INR "\ue216" #define FA_CNY "\ue217" #define FA_ROUBLE "\ue218" #define FA_KRW "\ue219" #define FA_BITCOIN "\ue21a" #define FA_FILE "\ue21b" #define FA_FILE_TEXT "\ue21c" #define FA_SORT_ALPHA_ASC "\ue21d" #define FA_SORT_ALPHA_DESC "\ue21e" #define FA_SORT_AMOUNT_ASC "\ue21f" #define FA_SORT_AMOUNT_DESC "\ue220" #define FA_SORT_NUMERIC_ASC "\ue221" #define FA_SORT_NUMERIC_DESC "\ue222" #define FA_THUMBS_UP "\ue223" #define FA_THUMBS_DOWN "\ue224" #define FA_YOUTUBE_SQUARE "\ue225" #define FA_YOUTUBE "\ue226" #define FA_XING "\ue227" #define FA_XING_SQUARE "\ue228" #define FA_YOUTUBE_PLAY "\ue229" #define FA_DROPBOX "\ue22a" #define FA_STACK_OVERFLOW "\ue22b" #define FA_INSTAGRAM "\ue22c" #define FA_FLICKR "\ue22d" #define FA_ADN "\ue22e" #define FA_BITBUCKET "\ue22f" #define FA_BITBUCKET_SQUARE "\ue230" #define FA_TUMBLR "\ue231" #define FA_TUMBLR_SQUARE "\ue232" #define FA_LONG_ARROW_DOWN "\ue233" #define FA_LONG_ARROW_UP "\ue234" #define FA_LONG_ARROW_LEFT "\ue235" #define FA_LONG_ARROW_RIGHT "\ue236" #define FA_APPLE "\ue237" #define FA_WINDOWS "\ue238" #define FA_ANDROID "\ue239" #define FA_LINUX "\ue23a" #define FA_DRIBBBLE "\ue23b" #define FA_SKYPE "\ue23c" #define FA_FOURSQUARE "\ue23d" #define FA_TRELLO "\ue23e" #define FA_FEMALE "\ue23f" #define FA_MALE "\ue240" #define FA_GITTIP "\ue241" #define FA_SUN_O "\ue242" #define FA_MOON_O "\ue243" #define FA_ARCHIVE "\ue244" #define FA_BUG "\ue245" #define FA_VK "\ue246" #define FA_WEIBO "\ue247" #define FA_RENREN "\ue248" #define FA_PAGELINES "\ue249" #define FA_STACK_EXCHANGE "\ue24a" #define FA_ARROW_CIRCLE_O_RIGHT "\ue24b" #define FA_ARROW_CIRCLE_O_LEFT "\ue24c" #define FA_CARET_SQUARE_O_LEFT "\ue24d" #define FA_DOT_CIRCLE_O "\ue24e" #define FA_WHEELCHAIR "\ue24f" #define FA_VIMEO_SQUARE "\ue250" #define FA_TRY "\ue251" #define FA_PLUS_SQUARE_O "\ue252" #define FA_SPACE_SHUTTLE "\ue253" #define FA_SLACK "\ue254" #define FA_ENVELOPE_SQUARE "\ue255" #define FA_WORDPRESS "\ue256" #define FA_OPENID "\ue257" #define FA_BANK "\ue258" #define FA_GRADUATION_CAP "\ue259" #define FA_YAHOO "\ue25a" #define FA_GOOGLE "\ue25b" #define FA_REDDIT "\ue25c" #define FA_REDDIT_SQUARE "\ue25d" #define FA_STUMBLEUPON_CIRCLE "\ue25e" #define FA_STUMBLEUPON "\ue25f" #define FA_DELICIOUS "\ue260" #define FA_DIGG "\ue261" #define FA_PIED_PIPER_PP "\ue262" #define FA_PIED_PIPER_ALT "\ue263" #define FA_DRUPAL "\ue264" #define FA_JOOMLA "\ue265" #define FA_LANGUAGE "\ue266" #define FA_FAX "\ue267" #define FA_BUILDING "\ue268" #define FA_CHILD "\ue269" #define FA_PAW "\ue26a" #define FA_SPOON "\ue26b" #define FA_CUBE "\ue26c" #define FA_CUBES "\ue26d" #define FA_BEHANCE "\ue26e" #define FA_BEHANCE_SQUARE "\ue26f" #define FA_STEAM "\ue270" #define FA_STEAM_SQUARE "\ue271" #define FA_RECYCLE "\ue272" #define FA_AUTOMOBILE "\ue273" #define FA_CAB "\ue274" #define FA_TREE "\ue275" #define FA_SPOTIFY "\ue276" #define FA_DEVIANTART "\ue277" #define FA_SOUNDCLOUD "\ue278" #define FA_DATABASE "\ue279" #define FA_FILE_PDF_O "\ue27a" #define FA_FILE_WORD_O "\ue27b" #define FA_FILE_EXCEL_O "\ue27c" #define FA_FILE_POWERPOINT_O "\ue27d" #define FA_FILE_IMAGE_O "\ue27e" #define FA_FILE_ARCHIVE_O "\ue27f" #define FA_FILE_AUDIO_O "\ue280" #define FA_FILE_MOVIE_O "\ue281" #define FA_FILE_CODE_O "\ue282" #define FA_VINE "\ue283" #define FA_CODEPEN "\ue284" #define FA_JSFIDDLE "\ue285" #define FA_LIFE_BOUY "\ue286" #define FA_CIRCLE_O_NOTCH "\ue287" #define FA_RA "\ue288" #define FA_EMPIRE "\ue289" #define FA_GIT_SQUARE "\ue28a" #define FA_GIT "\ue28b" #define FA_HACKER_NEWS "\ue28c" #define FA_TENCENT_WEIBO "\ue28d" #define FA_QQ "\ue28e" #define FA_WECHAT "\ue28f" #define FA_PAPER_PLANE "\ue290" #define FA_PAPER_PLANE_O "\ue291" #define FA_HISTORY "\ue292" #define FA_CIRCLE_THIN "\ue293" #define FA_HEADER "\ue294" #define FA_PARAGRAPH "\ue295" #define FA_SLIDERS "\ue296" #define FA_SHARE_ALT "\ue297" #define FA_SHARE_ALT_SQUARE "\ue298" #define FA_BOMB "\ue299" #define FA_FUTBOL_O "\ue29a" #define FA_TTY "\ue29b" #define FA_BINOCULARS "\ue29c" #define FA_PLUG "\ue29d" #define FA_SLIDESHARE "\ue29e" #define FA_TWITCH "\ue29f" #define FA_YELP "\ue2a0" #define FA_NEWSPAPER_O "\ue2a1" #define FA_WIFI "\ue2a2" #define FA_CALCULATOR "\ue2a3" #define FA_PAYPAL "\ue2a4" #define FA_GOOGLE_WALLET "\ue2a5" #define FA_CC_VISA "\ue2a6" #define FA_CC_MASTERCARD "\ue2a7" #define FA_CC_DISCOVER "\ue2a8" #define FA_CC_AMEX "\ue2a9" #define FA_CC_PAYPAL "\ue2aa" #define FA_CC_STRIPE "\ue2ab" #define FA_BELL_SLASH "\ue2ac" #define FA_BELL_SLASH_O "\ue2ad" #define FA_TRASH "\ue2ae" #define FA_COPYRIGHT "\ue2af" #define FA_AT "\ue2b0" #define FA_EYEDROPPER "\ue2b1" #define FA_PAINT_BRUSH "\ue2b2" #define FA_BIRTHDAY_CAKE "\ue2b3" #define FA_AREA_CHART "\ue2b4" #define FA_PIE_CHART "\ue2b5" #define FA_LINE_CHART "\ue2b6" #define FA_LASTFM "\ue2b7" #define FA_LASTFM_SQUARE "\ue2b8" #define FA_TOGGLE_OFF "\ue2b9" #define FA_TOGGLE_ON "\ue2ba" #define FA_BICYCLE "\ue2bb" #define FA_BUS "\ue2bc" #define FA_IOXHOST "\ue2bd" #define FA_ANGELLIST "\ue2be" #define FA_CC "\ue2bf" #define FA_ILS "\ue2c0" #define FA_MEANPATH "\ue2c1" #define FA_BUYSELLADS "\ue2c2" #define FA_CONNECTDEVELOP "\ue2c3" #define FA_DASHCUBE "\ue2c4" #define FA_FORUMBEE "\ue2c5" #define FA_LEANPUB "\ue2c6" #define FA_SELLSY "\ue2c7" #define FA_SHIRTSINBULK "\ue2c8" #define FA_SIMPLYBUILT "\ue2c9" #define FA_SKYATLAS "\ue2ca" #define FA_CART_PLUS "\ue2cb" #define FA_CART_ARROW_DOWN "\ue2cc" #define FA_DIAMOND "\ue2cd" #define FA_SHIP "\ue2ce" #define FA_USER_SECRET "\ue2cf" #define FA_MOTORCYCLE "\ue2d0" #define FA_STREET_VIEW "\ue2d1" #define FA_HEARTBEAT "\ue2d2" #define FA_VENUS "\ue2d3" #define FA_MARS "\ue2d4" #define FA_MERCURY "\ue2d5" #define FA_INTERSEX "\ue2d6" #define FA_TRANSGENDER_ALT "\ue2d7" #define FA_VENUS_DOUBLE "\ue2d8" #define FA_MARS_DOUBLE "\ue2d9" #define FA_VENUS_MARS "\ue2da" #define FA_MARS_STROKE "\ue2db" #define FA_MARS_STROKE_V "\ue2dc" #define FA_MARS_STROKE_H "\ue2dd" #define FA_NEUTER "\ue2de" #define FA_GENDERLESS "\ue2df" #define FA__523 "\ue2e0" #define FA__524 "\ue2e1" #define FA_FACEBOOK_OFFICIAL "\ue2e2" #define FA_PINTEREST_P "\ue2e3" #define FA_WHATSAPP "\ue2e4" #define FA_SERVER "\ue2e5" #define FA_USER_PLUS "\ue2e6" #define FA_USER_TIMES "\ue2e7" #define FA_BED "\ue2e8" #define FA_VIACOIN "\ue2e9" #define FA_TRAIN "\ue2ea" #define FA_SUBWAY "\ue2eb" #define FA_MEDIUM "\ue2ec" #define FA_Y_COMBINATOR "\ue2ed" #define FA_OPTIN_MONSTER "\ue2ee" #define FA_OPENCART "\ue2ef" #define FA_EXPEDITEDSSL "\ue2f0" #define FA_BATTERY "\ue2f1" #define FA_BATTERY_3 "\ue2f2" #define FA_BATTERY_2 "\ue2f3" #define FA_BATTERY_1 "\ue2f4" #define FA_BATTERY_0 "\ue2f5" #define FA_MOUSE_POINTER "\ue2f6" #define FA_I_CURSOR "\ue2f7" #define FA_OBJECT_GROUP "\ue2f8" #define FA_OBJECT_UNGROUP "\ue2f9" #define FA_STICKY_NOTE "\ue2fa" #define FA_STICKY_NOTE_O "\ue2fb" #define FA_CC_JCB "\ue2fc" #define FA_CC_DINERS_CLUB "\ue2fd" #define FA_CLONE "\ue2fe" #define FA_BALANCE_SCALE "\ue2ff" #define FA_HOURGLASS_O "\ue300" #define FA_HOURGLASS_1 "\ue301" #define FA_HOURGLASS_2 "\ue302" #define FA_HOURGLASS_3 "\ue303" #define FA_HOURGLASS "\ue304" #define FA_HAND_GRAB_O "\ue305" #define FA_HAND_PAPER_O "\ue306" #define FA_HAND_SCISSORS_O "\ue307" #define FA_HAND_LIZARD_O "\ue308" #define FA_HAND_SPOCK_O "\ue309" #define FA_HAND_POINTER_O "\ue30a" #define FA_HAND_PEACE_O "\ue30b" #define FA_TRADEMARK "\ue30c" #define FA_REGISTERED "\ue30d" #define FA_CREATIVE_COMMONS "\ue30e" #define FA_GG "\ue30f" #define FA_GG_CIRCLE "\ue310" #define FA_TRIPADVISOR "\ue311" #define FA_ODNOKLASSNIKI "\ue312" #define FA_ODNOKLASSNIKI_SQUARE "\ue313" #define FA_GET_POCKET "\ue314" #define FA_WIKIPEDIA_W "\ue315" #define FA_SAFARI "\ue316" #define FA_CHROME "\ue317" #define FA_FIREFOX "\ue318" #define FA_OPERA "\ue319" #define FA_INTERNET_EXPLORER "\ue31a" #define FA_TELEVISION "\ue31b" #define FA_CONTAO "\ue31c" #define FA_500PX "\ue31d" #define FA_AMAZON "\ue31e" #define FA_CALENDAR_PLUS_O "\ue31f" #define FA_CALENDAR_MINUS_O "\ue320" #define FA_CALENDAR_TIMES_O "\ue321" #define FA_CALENDAR_CHECK_O "\ue322" #define FA_INDUSTRY "\ue323" #define FA_MAP_PIN "\ue324" #define FA_MAP_SIGNS "\ue325" #define FA_MAP_O "\ue326" #define FA_MAP "\ue327" #define FA_COMMENTING "\ue328" #define FA_COMMENTING_O "\ue329" #define FA_HOUZZ "\ue32a" #define FA_VIMEO "\ue32b" #define FA_BLACK_TIE "\ue32c" #define FA_FONTICONS "\ue32d" #define FA_REDDIT_ALIEN "\ue32e" #define FA_EDGE "\ue32f" #define FA_CREDIT_CARD_ALT "\ue330" #define FA_CODIEPIE "\ue331" #define FA_MODX "\ue332" #define FA_FORT_AWESOME "\ue333" #define FA_USB "\ue334" #define FA_PRODUCT_HUNT "\ue335" #define FA_MIXCLOUD "\ue336" #define FA_SCRIBD "\ue337" #define FA_PAUSE_CIRCLE "\ue338" #define FA_PAUSE_CIRCLE_O "\ue339" #define FA_STOP_CIRCLE "\ue33a" #define FA_STOP_CIRCLE_O "\ue33b" #define FA_SHOPPING_BAG "\ue33c" #define FA_SHOPPING_BASKET "\ue33d" #define FA_HASHTAG "\ue33e" #define FA_BLUETOOTH "\ue33f" #define FA_BLUETOOTH_B "\ue340" #define FA_PERCENT "\ue341" #define FA_GITLAB "\ue342" #define FA_WPBEGINNER "\ue343" #define FA_WPFORMS "\ue344" #define FA_ENVIRA "\ue345" #define FA_UNIVERSAL_ACCESS "\ue346" #define FA_WHEELCHAIR_ALT "\ue347" #define FA_QUESTION_CIRCLE_O "\ue348" #define FA_BLIND "\ue349" #define FA_AUDIO_DESCRIPTION "\ue34a" #define FA_VOLUME_CONTROL_PHONE "\ue34b" #define FA_BRAILLE "\ue34c" #define FA_ASSISTIVE_LISTENING_SYSTEMS "\ue34d" #define FA_AMERICAN_SIGN_LANGUAGE_INTERPRETING "\ue34e" #define FA_DEAF "\ue34f" #define FA_GLIDE "\ue350" #define FA_GLIDE_G "\ue351" #define FA_SIGN_LANGUAGE "\ue352" #define FA_LOW_VISION "\ue353" #define FA_VIADEO "\ue354" #define FA_VIADEO_SQUARE "\ue355" #define FA_SNAPCHAT "\ue356" #define FA_SNAPCHAT_GHOST "\ue357" #define FA_SNAPCHAT_SQUARE "\ue358" #define FA_PIED_PIPER "\ue359" #define FA_FIRST_ORDER "\ue35a" #define FA_YOAST "\ue35b" #define FA_THEMEISLE "\ue35c" #define FA_GOOGLE_PLUS_CIRCLE "\ue35d" #define FA_FA "\ue35e" #define FA_HANDSHAKE_O "\ue35f" #define FA_ENVELOPE_OPEN "\ue360" #define FA_ENVELOPE_OPEN_O "\ue361" #define FA_LINODE "\ue362" #define FA_ADDRESS_BOOK "\ue363" #define FA_ADDRESS_BOOK_O "\ue364" #define FA_ADDRESS_CARD "\ue365" #define FA_ADDRESS_CARD_O "\ue366" #define FA_USER_CIRCLE "\ue367" #define FA_USER_CIRCLE_O "\ue368" #define FA_USER_O "\ue369" #define FA_ID_BADGE "\ue36a" #define FA_DRIVERS_LICENSE "\ue36b" #define FA_DRIVERS_LICENSE_O "\ue36c" #define FA_QUORA "\ue36d" #define FA_FREE_CODE_CAMP "\ue36e" #define FA_TELEGRAM "\ue36f" #define FA_THERMOMETER "\ue370" #define FA_THERMOMETER_3 "\ue371" #define FA_THERMOMETER_2 "\ue372" #define FA_THERMOMETER_1 "\ue373" #define FA_THERMOMETER_0 "\ue374" #define FA_SHOWER "\ue375" #define FA_BATH "\ue376" #define FA_PODCAST "\ue377" #define FA_WINDOW_MAXIMIZE "\ue378" #define FA_WINDOW_MINIMIZE "\ue379" #define FA_WINDOW_RESTORE "\ue37a" #define FA_TIMES_RECTANGLE "\ue37b" #define FA_TIMES_RECTANGLE_O "\ue37c" #define FA_BANDCAMP "\ue37d" #define FA_GRAV "\ue37e" #define FA_ETSY "\ue37f" #define FA_IMDB "\ue380" #define FA_RAVELRY "\ue381" #define FA_EERCAST "\ue382" #define FA_MICROCHIP "\ue383" #define FA_SNOWFLAKE_O "\ue384" #define FA_SUPERPOWERS "\ue385" #define FA_WPEXPLORER "\ue386" #define FA_MEETUP "\ue387" #define MD_ERROR "\ue388" #define MD_ERROR_OUTLINE "\ue389" #define MD_WARNING "\ue38a" #define MD_ADD_ALERT "\ue38b" #define MD_ALBUM "\ue38c" #define MD_AV_TIMER "\ue38d" #define MD_CLOSED_CAPTION "\ue38e" #define MD_EQUALIZER "\ue38f" #define MD_EXPLICIT "\ue390" #define MD_FAST_FORWARD "\ue391" #define MD_FAST_REWIND "\ue392" #define MD_GAMES "\ue393" #define MD_HEARING "\ue394" #define MD_HIGH_QUALITY "\ue395" #define MD_LOOP "\ue396" #define MD_MIC "\ue397" #define MD_MIC_NONE "\ue398" #define MD_MIC_OFF "\ue399" #define MD_MOVIE "\ue39a" #define MD_LIBRARY_ADD "\ue39b" #define MD_LIBRARY_BOOKS "\ue39c" #define MD_LIBRARY_MUSIC "\ue39d" #define MD_NEW_RELEASES "\ue39e" #define MD_NOT_INTERESTED "\ue39f" #define MD_PAUSE "\ue3a0" #define MD_PAUSE_CIRCLE_FILLED "\ue3a1" #define MD_PAUSE_CIRCLE_OUTLINE "\ue3a2" #define MD_PLAY_ARROW "\ue3a3" #define MD_PLAY_CIRCLE_FILLED "\ue3a4" #define MD_PLAY_CIRCLE_OUTLINE "\ue3a5" #define MD_PLAYLIST_ADD "\ue3a6" #define MD_QUEUE "\ue3a7" #define MD_QUEUE_MUSIC "\ue3a8" #define MD_RADIO "\ue3a9" #define MD_RECENT_ACTORS "\ue3aa" #define MD_REPEAT "\ue3ab" #define MD_REPEAT_ONE "\ue3ac" #define MD_REPLAY "\ue3ad" #define MD_SHUFFLE "\ue3ae" #define MD_SKIP_NEXT "\ue3af" #define MD_SKIP_PREVIOUS "\ue3b0" #define MD_SNOOZE "\ue3b1" #define MD_STOP "\ue3b2" #define MD_SUBTITLES "\ue3b3" #define MD_SURROUND_SOUND "\ue3b4" #define MD_VIDEO_LIBRARY "\ue3b5" #define MD_VIDEOCAM "\ue3b6" #define MD_VIDEOCAM_OFF "\ue3b7" #define MD_VOLUME_DOWN "\ue3b8" #define MD_VOLUME_MUTE "\ue3b9" #define MD_VOLUME_OFF "\ue3ba" #define MD_VOLUME_UP "\ue3bb" #define MD_WEB "\ue3bc" #define MD_HD "\ue3bd" #define MD_SORT_BY_ALPHA "\ue3be" #define MD_AIRPLAY "\ue3bf" #define MD_FORWARD_10 "\ue3c0" #define MD_FORWARD_30 "\ue3c1" #define MD_FORWARD_5 "\ue3c2" #define MD_REPLAY_10 "\ue3c3" #define MD_REPLAY_30 "\ue3c4" #define MD_REPLAY_5 "\ue3c5" #define MD_ADD_TO_QUEUE "\ue3c6" #define MD_FIBER_DVR "\ue3c7" #define MD_FIBER_NEW "\ue3c8" #define MD_PLAYLIST_PLAY "\ue3c9" #define MD_ART_TRACK "\ue3ca" #define MD_FIBER_MANUAL_RECORD "\ue3cb" #define MD_FIBER_SMART_RECORD "\ue3cc" #define MD_MUSIC_VIDEO "\ue3cd" #define MD_SUBSCRIPTIONS "\ue3ce" #define MD_PLAYLIST_ADD_CHECK "\ue3cf" #define MD_QUEUE_PLAY_NEXT "\ue3d0" #define MD_REMOVE_FROM_QUEUE "\ue3d1" #define MD_SLOW_MOTION_VIDEO "\ue3d2" #define MD_WEB_ASSET "\ue3d3" #define MD_FIBER_PIN "\ue3d4" #define MD_BRANDING_WATERMARK "\ue3d5" #define MD_CALL_TO_ACTION "\ue3d6" #define MD_FEATURED_PLAY_LIST "\ue3d7" #define MD_FEATURED_VIDEO "\ue3d8" #define MD_NOTE "\ue3d9" #define MD_VIDEO_CALL "\ue3da" #define MD_VIDEO_LABEL "\ue3db" #define MD_BUSINESS "\ue3dc" #define MD_CALL "\ue3dd" #define MD_CALL_END "\ue3de" #define MD_CALL_MADE "\ue3df" #define MD_CALL_MERGE "\ue3e0" #define MD_CALL_MISSED "\ue3e1" #define MD_CALL_RECEIVED "\ue3e2" #define MD_CALL_SPLIT "\ue3e3" #define MD_CHAT "\ue3e4" #define MD_CLEAR_ALL "\ue3e5" #define MD_COMMENT "\ue3e6" #define MD_CONTACTS "\ue3e7" #define MD_DIALER_SIP "\ue3e8" #define MD_DIALPAD "\ue3e9" #define MD_EMAIL "\ue3ea" #define MD_FORUM "\ue3eb" #define MD_IMPORT_EXPORT "\ue3ec" #define MD_INVERT_COLORS_OFF "\ue3ed" #define MD_LIVE_HELP "\ue3ee" #define MD_LOCATION_OFF "\ue3ef" #define MD_LOCATION_ON "\ue3f0" #define MD_MESSAGE "\ue3f1" #define MD_CHAT_BUBBLE "\ue3f2" #define MD_CHAT_BUBBLE_OUTLINE "\ue3f3" #define MD_NO_SIM "\ue3f4" #define MD_PHONE "\ue3f5" #define MD_PORTABLE_WIFI_OFF "\ue3f6" #define MD_CONTACT_PHONE "\ue3f7" #define MD_CONTACT_MAIL "\ue3f8" #define MD_RING_VOLUME "\ue3f9" #define MD_SPEAKER_PHONE "\ue3fa" #define MD_STAY_CURRENT_LANDSCAPE "\ue3fb" #define MD_STAY_CURRENT_PORTRAIT "\ue3fc" #define MD_STAY_PRIMARY_LANDSCAPE "\ue3fd" #define MD_STAY_PRIMARY_PORTRAIT "\ue3fe" #define MD_SWAP_CALLS "\ue3ff" #define MD_TEXTSMS "\ue400" #define MD_VOICEMAIL "\ue401" #define MD_VPN_KEY "\ue402" #define MD_PHONELINK_ERASE "\ue403" #define MD_PHONELINK_LOCK "\ue404" #define MD_PHONELINK_RING "\ue405" #define MD_PHONELINK_SETUP "\ue406" #define MD_PRESENT_TO_ALL "\ue407" #define MD_IMPORT_CONTACTS "\ue408" #define MD_MAIL_OUTLINE "\ue409" #define MD_SCREEN_SHARE "\ue40a" #define MD_STOP_SCREEN_SHARE "\ue40b" #define MD_CALL_MISSED_OUTGOING "\ue40c" #define MD_RSS_FEED "\ue40d" #define MD_ADD "\ue40e" #define MD_ADD_BOX "\ue40f" #define MD_ADD_CIRCLE "\ue410" #define MD_ADD_CIRCLE_OUTLINE "\ue411" #define MD_ARCHIVE "\ue412" #define MD_BACKSPACE "\ue413" #define MD_BLOCK "\ue414" #define MD_CLEAR "\ue415" #define MD_CONTENT_COPY "\ue416" #define MD_CONTENT_CUT "\ue417" #define MD_CONTENT_PASTE "\ue418" #define MD_CREATE "\ue419" #define MD_DRAFTS "\ue41a" #define MD_FILTER_LIST "\ue41b" #define MD_FLAG "\ue41c" #define MD_FORWARD "\ue41d" #define MD_GESTURE "\ue41e" #define MD_INBOX "\ue41f" #define MD_LINK "\ue420" #define MD_MAIL "\ue421" #define MD_MARKUNREAD "\ue422" #define MD_REDO "\ue423" #define MD_REMOVE "\ue424" #define MD_REMOVE_CIRCLE "\ue425" #define MD_REMOVE_CIRCLE_OUTLINE "\ue426" #define MD_REPLY "\ue427" #define MD_REPLY_ALL "\ue428" #define MD_REPORT "\ue429" #define MD_SAVE "\ue42a" #define MD_SELECT_ALL "\ue42b" #define MD_SEND "\ue42c" #define MD_SORT "\ue42d" #define MD_TEXT_FORMAT "\ue42e" #define MD_UNDO "\ue42f" #define MD_FONT_DOWNLOAD "\ue430" #define MD_MOVE_TO_INBOX "\ue431" #define MD_UNARCHIVE "\ue432" #define MD_NEXT_WEEK "\ue433" #define MD_WEEKEND "\ue434" #define MD_DELETE_SWEEP "\ue435" #define MD_LOW_PRIORITY "\ue436" #define MD_ACCESS_ALARM "\ue437" #define MD_ACCESS_ALARMS "\ue438" #define MD_ACCESS_TIME "\ue439" #define MD_ADD_ALARM "\ue43a" #define MD_AIRPLANEMODE_INACTIVE "\ue43b" #define MD_AIRPLANEMODE_ACTIVE "\ue43c" #define MD_BATTERY_ALERT "\ue43d" #define MD_BATTERY_CHARGING_FULL "\ue43e" #define MD_BATTERY_FULL "\ue43f" #define MD_BATTERY_STD "\ue440" #define MD_BATTERY_UNKNOWN "\ue441" #define MD_BLUETOOTH "\ue442" #define MD_BLUETOOTH_CONNECTED "\ue443" #define MD_BLUETOOTH_DISABLED "\ue444" #define MD_BLUETOOTH_SEARCHING "\ue445" #define MD_BRIGHTNESS_AUTO "\ue446" #define MD_BRIGHTNESS_HIGH "\ue447" #define MD_BRIGHTNESS_LOW "\ue448" #define MD_BRIGHTNESS_MEDIUM "\ue449" #define MD_DATA_USAGE "\ue44a" #define MD_DEVELOPER_MODE "\ue44b" #define MD_DEVICES "\ue44c" #define MD_DVR "\ue44d" #define MD_GPS_FIXED "\ue44e" #define MD_GPS_NOT_FIXED "\ue44f" #define MD_GPS_OFF "\ue450" #define MD_LOCATION_DISABLED "\ue451" #define MD_LOCATION_SEARCHING "\ue452" #define MD_GRAPHIC_EQ "\ue453" #define MD_NETWORK_CELL "\ue454" #define MD_NETWORK_WIFI "\ue455" #define MD_NFC "\ue456" #define MD_WALLPAPER "\ue457" #define MD_WIDGETS "\ue458" #define MD_SCREEN_LOCK_LANDSCAPE "\ue459" #define MD_SCREEN_LOCK_PORTRAIT "\ue45a" #define MD_SCREEN_LOCK_ROTATION "\ue45b" #define MD_SCREEN_ROTATION "\ue45c" #define MD_SD_STORAGE "\ue45d" #define MD_SETTINGS_SYSTEM_DAYDREAM "\ue45e" #define MD_SIGNAL_CELLULAR_4_BAR "\ue45f" #define MD_SIGNAL_CELLULAR_CONNECTED_NO_INTERNET_4_BAR "\ue460" #define MD_SIGNAL_CELLULAR_NO_SIM "\ue461" #define MD_SIGNAL_CELLULAR_NULL "\ue462" #define MD_SIGNAL_CELLULAR_OFF "\ue463" #define MD_SIGNAL_WIFI_4_BAR "\ue464" #define MD_SIGNAL_WIFI_4_BAR_LOCK "\ue465" #define MD_SIGNAL_WIFI_OFF "\ue466" #define MD_STORAGE "\ue467" #define MD_USB "\ue468" #define MD_WIFI_LOCK "\ue469" #define MD_WIFI_TETHERING "\ue46a" #define MD_ATTACH_FILE "\ue46b" #define MD_ATTACH_MONEY "\ue46c" #define MD_BORDER_ALL "\ue46d" #define MD_BORDER_BOTTOM "\ue46e" #define MD_BORDER_CLEAR "\ue46f" #define MD_BORDER_COLOR "\ue470" #define MD_BORDER_HORIZONTAL "\ue471" #define MD_BORDER_INNER "\ue472" #define MD_BORDER_LEFT "\ue473" #define MD_BORDER_OUTER "\ue474" #define MD_BORDER_RIGHT "\ue475" #define MD_BORDER_STYLE "\ue476" #define MD_BORDER_TOP "\ue477" #define MD_BORDER_VERTICAL "\ue478" #define MD_FORMAT_ALIGN_CENTER "\ue479" #define MD_FORMAT_ALIGN_JUSTIFY "\ue47a" #define MD_FORMAT_ALIGN_LEFT "\ue47b" #define MD_FORMAT_ALIGN_RIGHT "\ue47c" #define MD_FORMAT_BOLD "\ue47d" #define MD_FORMAT_CLEAR "\ue47e" #define MD_FORMAT_COLOR_FILL "\ue47f" #define MD_FORMAT_COLOR_RESET "\ue480" #define MD_FORMAT_COLOR_TEXT "\ue481" #define MD_FORMAT_INDENT_DECREASE "\ue482" #define MD_FORMAT_INDENT_INCREASE "\ue483" #define MD_FORMAT_ITALIC "\ue484" #define MD_FORMAT_LINE_SPACING "\ue485" #define MD_FORMAT_LIST_BULLETED "\ue486" #define MD_FORMAT_LIST_NUMBERED "\ue487" #define MD_FORMAT_PAINT "\ue488" #define MD_FORMAT_QUOTE "\ue489" #define MD_FORMAT_SIZE "\ue48a" #define MD_FORMAT_STRIKETHROUGH "\ue48b" #define MD_FORMAT_TEXTDIRECTION_L_TO_R "\ue48c" #define MD_FORMAT_TEXTDIRECTION_R_TO_L "\ue48d" #define MD_FORMAT_UNDERLINED "\ue48e" #define MD_FUNCTIONS "\ue48f" #define MD_INSERT_CHART "\ue490" #define MD_INSERT_COMMENT "\ue491" #define MD_INSERT_DRIVE_FILE "\ue492" #define MD_INSERT_EMOTICON "\ue493" #define MD_INSERT_INVITATION "\ue494" #define MD_INSERT_LINK "\ue495" #define MD_INSERT_PHOTO "\ue496" #define MD_MERGE_TYPE "\ue497" #define MD_MODE_COMMENT "\ue498" #define MD_MODE_EDIT "\ue499" #define MD_PUBLISH "\ue49a" #define MD_SPACE_BAR "\ue49b" #define MD_STRIKETHROUGH_S "\ue49c" #define MD_VERTICAL_ALIGN_BOTTOM "\ue49d" #define MD_VERTICAL_ALIGN_CENTER "\ue49e" #define MD_VERTICAL_ALIGN_TOP "\ue49f" #define MD_WRAP_TEXT "\ue4a0" #define MD_MONEY_OFF "\ue4a1" #define MD_DRAG_HANDLE "\ue4a2" #define MD_FORMAT_SHAPES "\ue4a3" #define MD_HIGHLIGHT "\ue4a4" #define MD_LINEAR_SCALE "\ue4a5" #define MD_SHORT_TEXT "\ue4a6" #define MD_TEXT_FIELDS "\ue4a7" #define MD_MONETIZATION_ON "\ue4a8" #define MD_TITLE "\ue4a9" #define MD_ATTACHMENT "\ue4aa" #define MD_CLOUD "\ue4ab" #define MD_CLOUD_CIRCLE "\ue4ac" #define MD_CLOUD_DONE "\ue4ad" #define MD_CLOUD_DOWNLOAD "\ue4ae" #define MD_CLOUD_OFF "\ue4af" #define MD_CLOUD_QUEUE "\ue4b0" #define MD_CLOUD_UPLOAD "\ue4b1" #define MD_FILE_DOWNLOAD "\ue4b2" #define MD_FILE_UPLOAD "\ue4b3" #define MD_FOLDER "\ue4b4" #define MD_FOLDER_OPEN "\ue4b5" #define MD_FOLDER_SHARED "\ue4b6" #define MD_CREATE_NEW_FOLDER "\ue4b7" #define MD_CAST "\ue4b8" #define MD_CAST_CONNECTED "\ue4b9" #define MD_COMPUTER "\ue4ba" #define MD_DESKTOP_MAC "\ue4bb" #define MD_DESKTOP_WINDOWS "\ue4bc" #define MD_DEVELOPER_BOARD "\ue4bd" #define MD_DOCK "\ue4be" #define MD_GAMEPAD "\ue4bf" #define MD_HEADSET "\ue4c0" #define MD_HEADSET_MIC "\ue4c1" #define MD_KEYBOARD "\ue4c2" #define MD_KEYBOARD_ARROW_DOWN "\ue4c3" #define MD_KEYBOARD_ARROW_LEFT "\ue4c4" #define MD_KEYBOARD_ARROW_RIGHT "\ue4c5" #define MD_KEYBOARD_ARROW_UP "\ue4c6" #define MD_KEYBOARD_BACKSPACE "\ue4c7" #define MD_KEYBOARD_CAPSLOCK "\ue4c8" #define MD_KEYBOARD_HIDE "\ue4c9" #define MD_KEYBOARD_RETURN "\ue4ca" #define MD_KEYBOARD_TAB "\ue4cb" #define MD_KEYBOARD_VOICE "\ue4cc" #define MD_LAPTOP "\ue4cd" #define MD_LAPTOP_CHROMEBOOK "\ue4ce" #define MD_LAPTOP_MAC "\ue4cf" #define MD_LAPTOP_WINDOWS "\ue4d0" #define MD_MEMORY "\ue4d1" #define MD_MOUSE "\ue4d2" #define MD_PHONE_ANDROID "\ue4d3" #define MD_PHONE_IPHONE "\ue4d4" #define MD_PHONELINK "\ue4d5" #define MD_PHONELINK_OFF "\ue4d6" #define MD_ROUTER "\ue4d7" #define MD_SCANNER "\ue4d8" #define MD_SECURITY "\ue4d9" #define MD_SIM_CARD "\ue4da" #define MD_SMARTPHONE "\ue4db" #define MD_SPEAKER "\ue4dc" #define MD_SPEAKER_GROUP "\ue4dd" #define MD_TABLET "\ue4de" #define MD_TABLET_ANDROID "\ue4df" #define MD_TABLET_MAC "\ue4e0" #define MD_TOYS "\ue4e1" #define MD_TV "\ue4e2" #define MD_WATCH "\ue4e3" #define MD_DEVICE_HUB "\ue4e4" #define MD_POWER_INPUT "\ue4e5" #define MD_DEVICES_OTHER "\ue4e6" #define MD_VIDEOGAME_ASSET "\ue4e7" #define MD_ADD_TO_PHOTOS "\ue4e8" #define MD_ADJUST "\ue4e9" #define MD_ASSISTANT "\ue4ea" #define MD_ASSISTANT_PHOTO "\ue4eb" #define MD_AUDIOTRACK "\ue4ec" #define MD_BLUR_CIRCULAR "\ue4ed" #define MD_BLUR_LINEAR "\ue4ee" #define MD_BLUR_OFF "\ue4ef" #define MD_BLUR_ON "\ue4f0" #define MD_BRIGHTNESS_1 "\ue4f1" #define MD_BRIGHTNESS_2 "\ue4f2" #define MD_BRIGHTNESS_3 "\ue4f3" #define MD_BRIGHTNESS_4 "\ue4f4" #define MD_BRIGHTNESS_5 "\ue4f5" #define MD_BRIGHTNESS_6 "\ue4f6" #define MD_BRIGHTNESS_7 "\ue4f7" #define MD_BROKEN_IMAGE "\ue4f8" #define MD_BRUSH "\ue4f9" #define MD_CAMERA "\ue4fa" #define MD_CAMERA_ALT "\ue4fb" #define MD_CAMERA_FRONT "\ue4fc" #define MD_CAMERA_REAR "\ue4fd" #define MD_CAMERA_ROLL "\ue4fe" #define MD_CENTER_FOCUS_STRONG "\ue4ff" #define MD_CENTER_FOCUS_WEAK "\ue500" #define MD_COLLECTIONS "\ue501" #define MD_COLOR_LENS "\ue502" #define MD_COLORIZE "\ue503" #define MD_COMPARE "\ue504" #define MD_CONTROL_POINT "\ue505" #define MD_CONTROL_POINT_DUPLICATE "\ue506" #define MD_CROP_16_9 "\ue507" #define MD_CROP_3_2 "\ue508" #define MD_CROP "\ue509" #define MD_CROP_5_4 "\ue50a" #define MD_CROP_7_5 "\ue50b" #define MD_CROP_DIN "\ue50c" #define MD_CROP_FREE "\ue50d" #define MD_CROP_LANDSCAPE "\ue50e" #define MD_CROP_ORIGINAL "\ue50f" #define MD_CROP_PORTRAIT "\ue510" #define MD_CROP_SQUARE "\ue511" #define MD_DEHAZE "\ue512" #define MD_DETAILS "\ue513" #define MD_EDIT "\ue514" #define MD_EXPOSURE "\ue515" #define MD_EXPOSURE_NEG_1 "\ue516" #define MD_EXPOSURE_NEG_2 "\ue517" #define MD_EXPOSURE_PLUS_1 "\ue518" #define MD_EXPOSURE_PLUS_2 "\ue519" #define MD_EXPOSURE_ZERO "\ue51a" #define MD_FILTER_1 "\ue51b" #define MD_FILTER_2 "\ue51c" #define MD_FILTER_3 "\ue51d" #define MD_FILTER "\ue51e" #define MD_FILTER_4 "\ue51f" #define MD_FILTER_5 "\ue520" #define MD_FILTER_6 "\ue521" #define MD_FILTER_7 "\ue522" #define MD_FILTER_8 "\ue523" #define MD_FILTER_9 "\ue524" #define MD_FILTER_9_PLUS "\ue525" #define MD_FILTER_B_AND_W "\ue526" #define MD_FILTER_CENTER_FOCUS "\ue527" #define MD_FILTER_DRAMA "\ue528" #define MD_FILTER_FRAMES "\ue529" #define MD_FILTER_HDR "\ue52a" #define MD_FILTER_NONE "\ue52b" #define MD_FILTER_TILT_SHIFT "\ue52c" #define MD_FILTER_VINTAGE "\ue52d" #define MD_FLARE "\ue52e" #define MD_FLASH_AUTO "\ue52f" #define MD_FLASH_OFF "\ue530" #define MD_FLASH_ON "\ue531" #define MD_FLIP "\ue532" #define MD_GRADIENT "\ue533" #define MD_GRAIN "\ue534" #define MD_GRID_OFF "\ue535" #define MD_GRID_ON "\ue536" #define MD_HDR_OFF "\ue537" #define MD_HDR_ON "\ue538" #define MD_HDR_STRONG "\ue539" #define MD_HDR_WEAK "\ue53a" #define MD_HEALING "\ue53b" #define MD_IMAGE "\ue53c" #define MD_IMAGE_ASPECT_RATIO "\ue53d" #define MD_ISO "\ue53e" #define MD_LANDSCAPE "\ue53f" #define MD_LEAK_ADD "\ue540" #define MD_LEAK_REMOVE "\ue541" #define MD_LENS "\ue542" #define MD_LOOKS_3 "\ue543" #define MD_LOOKS "\ue544" #define MD_LOOKS_4 "\ue545" #define MD_LOOKS_5 "\ue546" #define MD_LOOKS_6 "\ue547" #define MD_LOOKS_ONE "\ue548" #define MD_LOOKS_TWO "\ue549" #define MD_LOUPE "\ue54a" #define MD_MONOCHROME_PHOTOS "\ue54b" #define MD_MOVIE_CREATION "\ue54c" #define MD_MUSIC_NOTE "\ue54d" #define MD_NATURE "\ue54e" #define MD_NATURE_PEOPLE "\ue54f" #define MD_NAVIGATE_BEFORE "\ue550" #define MD_NAVIGATE_NEXT "\ue551" #define MD_PALETTE "\ue552" #define MD_PANORAMA "\ue553" #define MD_PANORAMA_FISH_EYE "\ue554" #define MD_PANORAMA_HORIZONTAL "\ue555" #define MD_PANORAMA_VERTICAL "\ue556" #define MD_PANORAMA_WIDE_ANGLE "\ue557" #define MD_PHOTO "\ue558" #define MD_PHOTO_ALBUM "\ue559" #define MD_PHOTO_CAMERA "\ue55a" #define MD_PHOTO_LIBRARY "\ue55b" #define MD_PICTURE_AS_PDF "\ue55c" #define MD_PORTRAIT "\ue55d" #define MD_REMOVE_RED_EYE "\ue55e" #define MD_ROTATE_90_DEGREES_CCW "\ue55f" #define MD_ROTATE_LEFT "\ue560" #define MD_ROTATE_RIGHT "\ue561" #define MD_SLIDESHOW "\ue562" #define MD_STRAIGHTEN "\ue563" #define MD_STYLE "\ue564" #define MD_SWITCH_CAMERA "\ue565" #define MD_SWITCH_VIDEO "\ue566" #define MD_TAG_FACES "\ue567" #define MD_TEXTURE "\ue568" #define MD_TIMELAPSE "\ue569" #define MD_TIMER_10 "\ue56a" #define MD_TIMER_3 "\ue56b" #define MD_TIMER "\ue56c" #define MD_TIMER_OFF "\ue56d" #define MD_TONALITY "\ue56e" #define MD_TRANSFORM "\ue56f" #define MD_TUNE "\ue570" #define MD_VIEW_COMFY "\ue571" #define MD_VIEW_COMPACT "\ue572" #define MD_WB_AUTO "\ue573" #define MD_WB_CLOUDY "\ue574" #define MD_WB_INCANDESCENT "\ue575" #define MD_WB_SUNNY "\ue576" #define MD_COLLECTIONS_BOOKMARK "\ue577" #define MD_PHOTO_SIZE_SELECT_ACTUAL "\ue578" #define MD_PHOTO_SIZE_SELECT_LARGE "\ue579" #define MD_PHOTO_SIZE_SELECT_SMALL "\ue57a" #define MD_VIGNETTE "\ue57b" #define MD_WB_IRIDESCENT "\ue57c" #define MD_CROP_ROTATE "\ue57d" #define MD_LINKED_CAMERA "\ue57e" #define MD_ADD_A_PHOTO "\ue57f" #define MD_MOVIE_FILTER "\ue580" #define MD_PHOTO_FILTER "\ue581" #define MD_BURST_MODE "\ue582" #define MD_BEENHERE "\ue583" #define MD_DIRECTIONS "\ue584" #define MD_DIRECTIONS_BIKE "\ue585" #define MD_DIRECTIONS_BUS "\ue586" #define MD_DIRECTIONS_CAR "\ue587" #define MD_DIRECTIONS_BOAT "\ue588" #define MD_DIRECTIONS_SUBWAY "\ue589" #define MD_DIRECTIONS_RAILWAY "\ue58a" #define MD_DIRECTIONS_TRANSIT "\ue58b" #define MD_DIRECTIONS_WALK "\ue58c" #define MD_FLIGHT "\ue58d" #define MD_HOTEL "\ue58e" #define MD_LAYERS "\ue58f" #define MD_LAYERS_CLEAR "\ue590" #define MD_LOCAL_AIRPORT "\ue591" #define MD_LOCAL_ATM "\ue592" #define MD_LOCAL_ACTIVITY "\ue593" #define MD_LOCAL_BAR "\ue594" #define MD_LOCAL_CAFE "\ue595" #define MD_LOCAL_CAR_WASH "\ue596" #define MD_LOCAL_CONVENIENCE_STORE "\ue597" #define MD_LOCAL_DRINK "\ue598" #define MD_LOCAL_FLORIST "\ue599" #define MD_LOCAL_GAS_STATION "\ue59a" #define MD_LOCAL_GROCERY_STORE "\ue59b" #define MD_LOCAL_HOSPITAL "\ue59c" #define MD_LOCAL_HOTEL "\ue59d" #define MD_LOCAL_LAUNDRY_SERVICE "\ue59e" #define MD_LOCAL_LIBRARY "\ue59f" #define MD_LOCAL_MALL "\ue5a0" #define MD_LOCAL_MOVIES "\ue5a1" #define MD_LOCAL_OFFER "\ue5a2" #define MD_LOCAL_PARKING "\ue5a3" #define MD_LOCAL_PHARMACY "\ue5a4" #define MD_LOCAL_PHONE "\ue5a5" #define MD_LOCAL_PIZZA "\ue5a6" #define MD_LOCAL_PLAY "\ue5a7" #define MD_LOCAL_POST_OFFICE "\ue5a8" #define MD_LOCAL_PRINTSHOP "\ue5a9" #define MD_LOCAL_DINING "\ue5aa" #define MD_LOCAL_SEE "\ue5ab" #define MD_LOCAL_SHIPPING "\ue5ac" #define MD_LOCAL_TAXI "\ue5ad" #define MD_PERSON_PIN "\ue5ae" #define MD_MAP "\ue5af" #define MD_MY_LOCATION "\ue5b0" #define MD_NAVIGATION "\ue5b1" #define MD_PIN_DROP "\ue5b2" #define MD_PLACE "\ue5b3" #define MD_RATE_REVIEW "\ue5b4" #define MD_RESTAURANT_MENU "\ue5b5" #define MD_SATELLITE "\ue5b6" #define MD_STORE_MALL_DIRECTORY "\ue5b7" #define MD_TERRAIN "\ue5b8" #define MD_TRAFFIC "\ue5b9" #define MD_DIRECTIONS_RUN "\ue5ba" #define MD_ADD_LOCATION "\ue5bb" #define MD_EDIT_LOCATION "\ue5bc" #define MD_NEAR_ME "\ue5bd" #define MD_PERSON_PIN_CIRCLE "\ue5be" #define MD_ZOOM_OUT_MAP "\ue5bf" #define MD_RESTAURANT "\ue5c0" #define MD_EV_STATION "\ue5c1" #define MD_STREETVIEW "\ue5c2" #define MD_SUBWAY "\ue5c3" #define MD_TRAIN "\ue5c4" #define MD_TRAM "\ue5c5" #define MD_TRANSFER_WITHIN_A_STATION "\ue5c6" #define MD_APPS "\ue5c7" #define MD_ARROW_BACK "\ue5c8" #define MD_ARROW_DROP_DOWN "\ue5c9" #define MD_ARROW_DROP_DOWN_CIRCLE "\ue5ca" #define MD_ARROW_DROP_UP "\ue5cb" #define MD_ARROW_FORWARD "\ue5cc" #define MD_CANCEL "\ue5cd" #define MD_CHECK "\ue5ce" #define MD_CHEVRON_LEFT "\ue5cf" #define MD_CHEVRON_RIGHT "\ue5d0" #define MD_CLOSE "\ue5d1" #define MD_EXPAND_LESS "\ue5d2" #define MD_EXPAND_MORE "\ue5d3" #define MD_FULLSCREEN "\ue5d4" #define MD_FULLSCREEN_EXIT "\ue5d5" #define MD_MENU "\ue5d6" #define MD_MORE_HORIZ "\ue5d7" #define MD_MORE_VERT "\ue5d8" #define MD_REFRESH "\ue5d9" #define MD_UNFOLD_LESS "\ue5da" #define MD_UNFOLD_MORE "\ue5db" #define MD_ARROW_UPWARD "\ue5dc" #define MD_SUBDIRECTORY_ARROW_LEFT "\ue5dd" #define MD_SUBDIRECTORY_ARROW_RIGHT "\ue5de" #define MD_ARROW_DOWNWARD "\ue5df" #define MD_FIRST_PAGE "\ue5e0" #define MD_LAST_PAGE "\ue5e1" #define MD_ADB "\ue5e2" #define MD_BLUETOOTH_AUDIO "\ue5e3" #define MD_DISC_FULL "\ue5e4" #define MD_DO_NOT_DISTURB_ALT "\ue5e5" #define MD_DO_NOT_DISTURB "\ue5e6" #define MD_DRIVE_ETA "\ue5e7" #define MD_EVENT_AVAILABLE "\ue5e8" #define MD_EVENT_BUSY "\ue5e9" #define MD_EVENT_NOTE "\ue5ea" #define MD_FOLDER_SPECIAL "\ue5eb" #define MD_MMS "\ue5ec" #define MD_MORE "\ue5ed" #define MD_NETWORK_LOCKED "\ue5ee" #define MD_PHONE_BLUETOOTH_SPEAKER "\ue5ef" #define MD_PHONE_FORWARDED "\ue5f0" #define MD_PHONE_IN_TALK "\ue5f1" #define MD_PHONE_LOCKED "\ue5f2" #define MD_PHONE_MISSED "\ue5f3" #define MD_PHONE_PAUSED "\ue5f4" #define MD_SD_CARD "\ue5f5" #define MD_SIM_CARD_ALERT "\ue5f6" #define MD_SMS "\ue5f7" #define MD_SMS_FAILED "\ue5f8" #define MD_SYNC "\ue5f9" #define MD_SYNC_DISABLED "\ue5fa" #define MD_SYNC_PROBLEM "\ue5fb" #define MD_SYSTEM_UPDATE "\ue5fc" #define MD_TAP_AND_PLAY "\ue5fd" #define MD_TIME_TO_LEAVE "\ue5fe" #define MD_VIBRATION "\ue5ff" #define MD_VOICE_CHAT "\ue600" #define MD_VPN_LOCK "\ue601" #define MD_AIRLINE_SEAT_FLAT "\ue602" #define MD_AIRLINE_SEAT_FLAT_ANGLED "\ue603" #define MD_AIRLINE_SEAT_INDIVIDUAL_SUITE "\ue604" #define MD_AIRLINE_SEAT_LEGROOM_EXTRA "\ue605" #define MD_AIRLINE_SEAT_LEGROOM_NORMAL "\ue606" #define MD_AIRLINE_SEAT_LEGROOM_REDUCED "\ue607" #define MD_AIRLINE_SEAT_RECLINE_EXTRA "\ue608" #define MD_AIRLINE_SEAT_RECLINE_NORMAL "\ue609" #define MD_CONFIRMATION_NUMBER "\ue60a" #define MD_LIVE_TV "\ue60b" #define MD_ONDEMAND_VIDEO "\ue60c" #define MD_PERSONAL_VIDEO "\ue60d" #define MD_POWER "\ue60e" #define MD_WC "\ue60f" #define MD_WIFI "\ue610" #define MD_ENHANCED_ENCRYPTION "\ue611" #define MD_NETWORK_CHECK "\ue612" #define MD_NO_ENCRYPTION "\ue613" #define MD_RV_HOOKUP "\ue614" #define MD_DO_NOT_DISTURB_OFF "\ue615" #define MD_DO_NOT_DISTURB_ON "\ue616" #define MD_PRIORITY_HIGH "\ue617" #define MD_PIE_CHART "\ue618" #define MD_PIE_CHART_OUTLINED "\ue619" #define MD_BUBBLE_CHART "\ue61a" #define MD_MULTILINE_CHART "\ue61b" #define MD_SHOW_CHART "\ue61c" #define MD_CAKE "\ue61d" #define MD_DOMAIN "\ue61e" #define MD_GROUP "\ue61f" #define MD_GROUP_ADD "\ue620" #define MD_LOCATION_CITY "\ue621" #define MD_MOOD "\ue622" #define MD_MOOD_BAD "\ue623" #define MD_NOTIFICATIONS "\ue624" #define MD_NOTIFICATIONS_NONE "\ue625" #define MD_NOTIFICATIONS_OFF "\ue626" #define MD_NOTIFICATIONS_ACTIVE "\ue627" #define MD_NOTIFICATIONS_PAUSED "\ue628" #define MD_PAGES "\ue629" #define MD_PARTY_MODE "\ue62a" #define MD_PEOPLE "\ue62b" #define MD_PEOPLE_OUTLINE "\ue62c" #define MD_PERSON "\ue62d" #define MD_PERSON_ADD "\ue62e" #define MD_PERSON_OUTLINE "\ue62f" #define MD_PLUS_ONE "\ue630" #define MD_POLL "\ue631" #define MD_PUBLIC "\ue632" #define MD_SCHOOL "\ue633" #define MD_SHARE "\ue634" #define MD_WHATSHOT "\ue635" #define MD_SENTIMENT_DISSATISFIED "\ue636" #define MD_SENTIMENT_NEUTRAL "\ue637" #define MD_SENTIMENT_SATISFIED "\ue638" #define MD_SENTIMENT_VERY_DISSATISFIED "\ue639" #define MD_SENTIMENT_VERY_SATISFIED "\ue63a" #define MD_CHECK_BOX "\ue63b" #define MD_CHECK_BOX_OUTLINE_BLANK "\ue63c" #define MD_RADIO_BUTTON_UNCHECKED "\ue63d" #define MD_RADIO_BUTTON_CHECKED "\ue63e" #define MD_STAR "\ue63f" #define MD_STAR_HALF "\ue640" #define MD_STAR_BORDER "\ue641" #define MD_3D_ROTATION "\ue642" #define MD_ACCESSIBILITY "\ue643" #define MD_ACCOUNT_BALANCE "\ue644" #define MD_ACCOUNT_BALANCE_WALLET "\ue645" #define MD_ACCOUNT_BOX "\ue646" #define MD_ACCOUNT_CIRCLE "\ue647" #define MD_ADD_SHOPPING_CART "\ue648" #define MD_ALARM "\ue649" #define MD_ALARM_ADD "\ue64a" #define MD_ALARM_OFF "\ue64b" #define MD_ALARM_ON "\ue64c" #define MD_ANDROID "\ue64d" #define MD_ANNOUNCEMENT "\ue64e" #define MD_ASPECT_RATIO "\ue64f" #define MD_ASSESSMENT "\ue650" #define MD_ASSIGNMENT "\ue651" #define MD_ASSIGNMENT_IND "\ue652" #define MD_ASSIGNMENT_LATE "\ue653" #define MD_ASSIGNMENT_RETURN "\ue654" #define MD_ASSIGNMENT_RETURNED "\ue655" #define MD_ASSIGNMENT_TURNED_IN "\ue656" #define MD_AUTORENEW "\ue657" #define MD_BACKUP "\ue658" #define MD_BOOK "\ue659" #define MD_BOOKMARK "\ue65a" #define MD_BOOKMARK_BORDER "\ue65b" #define MD_BUG_REPORT "\ue65c" #define MD_BUILD "\ue65d" #define MD_CACHED "\ue65e" #define MD_CHANGE_HISTORY "\ue65f" #define MD_CHECK_CIRCLE "\ue660" #define MD_CHROME_READER_MODE "\ue661" #define MD_CLASS "\ue662" #define MD_CODE "\ue663" #define MD_CREDIT_CARD "\ue664" #define MD_DASHBOARD "\ue665" #define MD_DELETE "\ue666" #define MD_DESCRIPTION "\ue667" #define MD_DNS "\ue668" #define MD_DONE "\ue669" #define MD_DONE_ALL "\ue66a" #define MD_EVENT "\ue66b" #define MD_EXIT_TO_APP "\ue66c" #define MD_EXPLORE "\ue66d" #define MD_EXTENSION "\ue66e" #define MD_FACE "\ue66f" #define MD_FAVORITE "\ue670" #define MD_FAVORITE_BORDER "\ue671" #define MD_FEEDBACK "\ue672" #define MD_FIND_IN_PAGE "\ue673" #define MD_FIND_REPLACE "\ue674" #define MD_FLIP_TO_BACK "\ue675" #define MD_FLIP_TO_FRONT "\ue676" #define MD_GET_APP "\ue677" #define MD_GRADE "\ue678" #define MD_GROUP_WORK "\ue679" #define MD_HELP "\ue67a" #define MD_HIGHLIGHT_OFF "\ue67b" #define MD_HISTORY "\ue67c" #define MD_HOME "\ue67d" #define MD_HOURGLASS_EMPTY "\ue67e" #define MD_HOURGLASS_FULL "\ue67f" #define MD_HTTPS "\ue680" #define MD_INFO "\ue681" #define MD_INFO_OUTLINE "\ue682" #define MD_INPUT "\ue683" #define MD_INVERT_COLORS "\ue684" #define MD_LABEL "\ue685" #define MD_LABEL_OUTLINE "\ue686" #define MD_LANGUAGE "\ue687" #define MD_LAUNCH "\ue688" #define MD_LIST "\ue689" #define MD_LOCK "\ue68a" #define MD_LOCK_OPEN "\ue68b" #define MD_LOCK_OUTLINE "\ue68c" #define MD_LOYALTY "\ue68d" #define MD_MARKUNREAD_MAILBOX "\ue68e" #define MD_NOTE_ADD "\ue68f" #define MD_OPEN_IN_BROWSER "\ue690" #define MD_OPEN_IN_NEW "\ue691" #define MD_OPEN_WITH "\ue692" #define MD_PAGEVIEW "\ue693" #define MD_PAYMENT "\ue694" #define MD_PERM_CAMERA_MIC "\ue695" #define MD_PERM_CONTACT_CALENDAR "\ue696" #define MD_PERM_DATA_SETTING "\ue697" #define MD_PERM_DEVICE_INFORMATION "\ue698" #define MD_PERM_IDENTITY "\ue699" #define MD_PERM_MEDIA "\ue69a" #define MD_PERM_PHONE_MSG "\ue69b" #define MD_PERM_SCAN_WIFI "\ue69c" #define MD_PICTURE_IN_PICTURE "\ue69d" #define MD_POLYMER "\ue69e" #define MD_POWER_SETTINGS_NEW "\ue69f" #define MD_PRINT "\ue6a0" #define MD_QUERY_BUILDER "\ue6a1" #define MD_QUESTION_ANSWER "\ue6a2" #define MD_RECEIPT "\ue6a3" #define MD_REDEEM "\ue6a4" #define MD_REPORT_PROBLEM "\ue6a5" #define MD_RESTORE "\ue6a6" #define MD_ROOM "\ue6a7" #define MD_SCHEDULE "\ue6a8" #define MD_SEARCH "\ue6a9" #define MD_SETTINGS "\ue6aa" #define MD_SETTINGS_APPLICATIONS "\ue6ab" #define MD_SETTINGS_BACKUP_RESTORE "\ue6ac" #define MD_SETTINGS_BLUETOOTH "\ue6ad" #define MD_SETTINGS_CELL "\ue6ae" #define MD_SETTINGS_BRIGHTNESS "\ue6af" #define MD_SETTINGS_ETHERNET "\ue6b0" #define MD_SETTINGS_INPUT_ANTENNA "\ue6b1" #define MD_SETTINGS_INPUT_COMPONENT "\ue6b2" #define MD_SETTINGS_INPUT_COMPOSITE "\ue6b3" #define MD_SETTINGS_INPUT_HDMI "\ue6b4" #define MD_SETTINGS_INPUT_SVIDEO "\ue6b5" #define MD_SETTINGS_OVERSCAN "\ue6b6" #define MD_SETTINGS_PHONE "\ue6b7" #define MD_SETTINGS_POWER "\ue6b8" #define MD_SETTINGS_REMOTE "\ue6b9" #define MD_SETTINGS_VOICE "\ue6ba" #define MD_SHOP "\ue6bb" #define MD_SHOP_TWO "\ue6bc" #define MD_SHOPPING_BASKET "\ue6bd" #define MD_SHOPPING_CART "\ue6be" #define MD_SPEAKER_NOTES "\ue6bf" #define MD_SPELLCHECK "\ue6c0" #define MD_STARS "\ue6c1" #define MD_STORE "\ue6c2" #define MD_SUBJECT "\ue6c3" #define MD_SUPERVISOR_ACCOUNT "\ue6c4" #define MD_SWAP_HORIZ "\ue6c5" #define MD_SWAP_VERT "\ue6c6" #define MD_SWAP_VERTICAL_CIRCLE "\ue6c7" #define MD_SYSTEM_UPDATE_ALT "\ue6c8" #define MD_TAB "\ue6c9" #define MD_TAB_UNSELECTED "\ue6ca" #define MD_THEATERS "\ue6cb" #define MD_THUMB_DOWN "\ue6cc" #define MD_THUMB_UP "\ue6cd" #define MD_THUMBS_UP_DOWN "\ue6ce" #define MD_TOC "\ue6cf" #define MD_TODAY "\ue6d0" #define MD_TOLL "\ue6d1" #define MD_TRACK_CHANGES "\ue6d2" #define MD_TRANSLATE "\ue6d3" #define MD_TRENDING_DOWN "\ue6d4" #define MD_TRENDING_FLAT "\ue6d5" #define MD_TRENDING_UP "\ue6d6" #define MD_TURNED_IN "\ue6d7" #define MD_TURNED_IN_NOT "\ue6d8" #define MD_VERIFIED_USER "\ue6d9" #define MD_VIEW_AGENDA "\ue6da" #define MD_VIEW_ARRAY "\ue6db" #define MD_VIEW_CAROUSEL "\ue6dc" #define MD_VIEW_COLUMN "\ue6dd" #define MD_VIEW_DAY "\ue6de" #define MD_VIEW_HEADLINE "\ue6df" #define MD_VIEW_LIST "\ue6e0" #define MD_VIEW_MODULE "\ue6e1" #define MD_VIEW_QUILT "\ue6e2" #define MD_VIEW_STREAM "\ue6e3" #define MD_VIEW_WEEK "\ue6e4" #define MD_VISIBILITY "\ue6e5" #define MD_VISIBILITY_OFF "\ue6e6" #define MD_CARD_GIFTCARD "\ue6e7" #define MD_CARD_MEMBERSHIP "\ue6e8" #define MD_CARD_TRAVEL "\ue6e9" #define MD_WORK "\ue6ea" #define MD_YOUTUBE_SEARCHED_FOR "\ue6eb" #define MD_EJECT "\ue6ec" #define MD_CAMERA_ENHANCE "\ue6ed" #define MD_HELP_OUTLINE "\ue6ee" #define MD_REORDER "\ue6ef" #define MD_ZOOM_IN "\ue6f0" #define MD_ZOOM_OUT "\ue6f1" #define MD_HTTP "\ue6f2" #define MD_EVENT_SEAT "\ue6f3" #define MD_FLIGHT_LAND "\ue6f4" #define MD_FLIGHT_TAKEOFF "\ue6f5" #define MD_PLAY_FOR_WORK "\ue6f6" #define MD_GIF "\ue6f7" #define MD_INDETERMINATE_CHECK_BOX "\ue6f8" #define MD_OFFLINE_PIN "\ue6f9" #define MD_ALL_OUT "\ue6fa" #define MD_COPYRIGHT "\ue6fb" #define MD_FINGERPRINT "\ue6fc" #define MD_GAVEL "\ue6fd" #define MD_LIGHTBULB_OUTLINE "\ue6fe" #define MD_PICTURE_IN_PICTURE_ALT "\ue6ff" #define MD_IMPORTANT_DEVICES "\ue700" #define MD_TOUCH_APP "\ue701" #define MD_ACCESSIBLE "\ue702" #define MD_COMPARE_ARROWS "\ue703" #define MD_DATE_RANGE "\ue704" #define MD_DONUT_LARGE "\ue705" #define MD_DONUT_SMALL "\ue706" #define MD_LINE_STYLE "\ue707" #define MD_LINE_WEIGHT "\ue708" #define MD_MOTORCYCLE "\ue709" #define MD_OPACITY "\ue70a" #define MD_PETS "\ue70b" #define MD_PREGNANT_WOMAN "\ue70c" #define MD_RECORD_VOICE_OVER "\ue70d" #define MD_ROUNDED_CORNER "\ue70e" #define MD_ROWING "\ue70f" #define MD_TIMELINE "\ue710" #define MD_UPDATE "\ue711" #define MD_WATCH_LATER "\ue712" #define MD_PAN_TOOL "\ue713" #define MD_EURO_SYMBOL "\ue714" #define MD_G_TRANSLATE "\ue715" #define MD_REMOVE_SHOPPING_CART "\ue716" #define MD_RESTORE_PAGE "\ue717" #define MD_SPEAKER_NOTES_OFF "\ue718" #define MD_DELETE_FOREVER "\ue719" #define MD_AC_UNIT "\ue71a" #define MD_AIRPORT_SHUTTLE "\ue71b" #define MD_ALL_INCLUSIVE "\ue71c" #define MD_BEACH_ACCESS "\ue71d" #define MD_BUSINESS_CENTER "\ue71e" #define MD_CASINO "\ue71f" #define MD_CHILD_CARE "\ue720" #define MD_CHILD_FRIENDLY "\ue721" #define MD_FITNESS_CENTER "\ue722" #define MD_FREE_BREAKFAST "\ue723" #define MD_GOLF_COURSE "\ue724" #define MD_HOT_TUB "\ue725" #define MD_KITCHEN "\ue726" #define MD_POOL "\ue727" #define MD_ROOM_SERVICE "\ue728" #define MD_SMOKE_FREE "\ue729" #define MD_SMOKING_ROOMS "\ue72a" #define MD_SPA "\ue72b" #define MD_U10FFFD "\ue72c" #define FILE_REGEX "\ue72d" #define FILE_ARCH_LINUX "\ue72e" #define FILE_E "\ue72f" #define FILE_GLYPHS "\ue730" #define FILE_KNOCKOUT "\ue731" #define FILE_LEAN "\ue732" #define FILE_METAL "\ue733" #define FILE_POVRAY "\ue734" #define FILE_S "\ue735" #define FILE_TT "\ue736" #define FILE_VAGRANT "\ue737" #define FILE_XMOS "\ue738" #define FILE_A "\ue739" #define FILE_CHAI "\ue73a" #define FILE_STYLUS "\ue73b" #define FILE_TEXTILE "\ue73c" #define FILE_UNREAL "\ue73d" #define FILE_PUREBASIC "\ue73e" #define FILE_TS "\ue73f" #define FILE_SCHEME "\ue740" #define FILE_TEXTMATE "\ue741" #define FILE_X10 "\ue742" #define FILE_APL "\ue743" #define FILE_ANSIBLE "\ue744" #define FILE_ARTTEXT "\ue745" #define FILE_ANTWAR "\ue746" #define FILE_OPA "\ue747" #define FILE_CODECOV "\ue748" #define FILE_YANG "\ue749" #define FILE_PM2 "\ue74a" #define FILE_HG "\ue74b" #define FILE_PAWN "\ue74c" #define FILE_JULIA "\ue74d" #define FILE_SHIPIT "\ue74e" #define FILE_MOCHA "\ue74f" #define FILE_NIB "\ue750" #define FILE_SHURIKEN "\ue751" #define FILE_ALEX "\ue752" #define FILE_TWIG "\ue753" #define FILE_1C "\ue754" #define FILE_TEX "\ue755" #define FILE_BIBTEX "\ue756" #define FILE_MUSTACHE "\ue757" #define FILE_GULP "\ue758" #define FILE_GRUNT "\ue759" #define FILE_EMBER "\ue75a" #define FILE_GO "\ue75b" #define FILE_JENKINS "\ue75c" #define FILE_GNU "\ue75d" #define FILE_COMPOSER "\ue75e" #define FILE_METEOR "\ue75f" #define FILE_AI "\ue760" #define FILE_PSD "\ue761" #define FILE_SILVERSTRIPE "\ue762" #define FILE_MAXSCRIPT "\ue763" #define FILE_KIVY "\ue764" #define FILE_CRYSTAL "\ue765" #define FILE_GRADLE "\ue766" #define FILE_GROOVY "\ue767" #define FILE_R "\ue768" #define FILE_VUE "\ue769" #define FILE_HAXE "\ue76a" #define FILE_LISP "\ue76b" #define FILE_E909 "\ue76c" #define FILE_FORTRAN "\ue76d" #define FILE_ADA "\ue76e" #define FILE_DYALOG "\ue76f" #define FILE_JADE "\ue770" #define FILE_E90E "\ue771" #define FILE_FONT "\ue772" #define FILE_POSTCSS "\ue773" #define FILE_SCAD "\ue774" #define FILE_E912 "\ue775" #define FILE_RAML "\ue776" #define FILE_LS "\ue777" #define FILE_SALTSTACK "\ue778" #define FILE_TERRAFORM "\ue779" #define FILE_ORG "\ue77a" #define FILE_ASCIIDOC "\ue77b" #define FILE_RIOT "\ue77c" #define FILE_OCAML "\ue77d" #define FILE_LUA "\ue77e" #define FILE_NPM "\ue77f" #define FILE_LLVM "\ue780" #define FILE_E91E "\ue781" #define FILE_BABEL "\ue782" #define FILE_MARKO "\ue783" #define FILE_FLOW "\ue784" #define FILE_BROCCOLI "\ue785" #define FILE_APPVEYOR "\ue786" #define FILE_CAKEFILE "\ue787" #define FILE_APPLE "\ue788" #define FILE_EMACS "\ue789" #define FILE_SKETCH "\ue78a" #define FILE_DOXYGEN "\ue78b" #define FILE_CF "\ue78c" #define FILE_PASCAL "\ue78d" #define FILE_ABAP "\ue78e" #define FILE_ANTLR "\ue78f" #define FILE_API "\ue790" #define FILE_AS "\ue791" #define FILE_ARC "\ue792" #define FILE_ARDUINO "\ue793" #define FILE_AUGEAS "\ue794" #define FILE_AHK "\ue795" #define FILE_AUTOIT "\ue796" #define FILE_ATS "\ue797" #define FILE_ALLOY "\ue798" #define FILE_MANPAGE "\ue799" #define FILE_J "\ue79a" #define FILE_GLADE "\ue79b" #define FILE_BOO "\ue79c" #define FILE_BRAIN "\ue79d" #define FILE_BRO "\ue79e" #define FILE_BLUESPEC "\ue79f" #define FILE_STYLELINT "\ue7a0" #define FILE_ANT "\ue7a1" #define FILE_CMAKE "\ue7a2" #define FILE_CLIPS "\ue7a3" #define FILE_MAPBOX "\ue7a4" #define FILE_CP "\ue7a5" #define FILE_CHUCK "\ue7a6" #define FILE_JINJA "\ue7a7" #define FILE_ISABELLE "\ue7a8" #define FILE_DOGE "\ue7a9" #define FILE_IDL "\ue7aa" #define FILE_JAKE "\ue7ab" #define FILE_VERILOG "\ue7ac" #define FILE_PHALCON "\ue7ad" #define FILE_FABFILE "\ue7ae" #define FILE_LFE "\ue7af" #define FILE_NMAP "\ue7b0" #define FILE_AMPL "\ue7b1" #define FILE_CEYLON "\ue7b2" #define FILE_CHAPEL "\ue7b3" #define FILE_CIRRU "\ue7b4" #define FILE_CLARION "\ue7b5" #define FILE_NUNJUCKS "\ue7b6" #define FILE_MEDIAWIKI "\ue7b7" #define FILE_POSTSCRIPT "\ue7b8" #define FILE_TCL "\ue7b9" #define FILE_OWL "\ue7ba" #define FILE_JSONLD "\ue7bb" #define FILE_SPARQL "\ue7bc" #define FILE_SAS "\ue7bd" #define FILE_CLEAN "\ue7be" #define FILE_CLICK "\ue7bf" #define FILE_NVIDIA "\ue7c0" #define FILE_CREOLE "\ue7c1" #define FILE_COQ "\ue7c2" #define FILE_DIFF "\ue7c3" #define FILE_PATCH "\ue7c4" #define FILE_BYOND "\ue7c5" #define FILE_CYTHON "\ue7c6" #define FILE_DARCS "\ue7c7" #define FILE_EAGLE "\ue7c8" #define FILE_ECERE "\ue7c9" #define FILE_EIFFEL "\ue7ca" #define FILE_EM "\ue7cb" #define FILE_FLUX "\ue7cc" #define FILE_FACTOR "\ue7cd" #define FILE_FANCY "\ue7ce" #define FILE_PERL6 "\ue7cf" #define FILE_GENTOO "\ue7d0" #define FILE_FREGE "\ue7d1" #define FILE_FANTOM "\ue7d2" #define FILE_FREEMARKER "\ue7d3" #define FILE_GAP "\ue7d4" #define FILE_CL "\ue7d5" #define FILE_GAMS "\ue7d6" #define FILE_GODOT "\ue7d7" #define FILE_GML "\ue7d8" #define FILE_GENSHI "\ue7d9" #define FILE_POINTWISE "\ue7da" #define FILE_GF "\ue7db" #define FILE_GOLO "\ue7dc" #define FILE_GOSU "\ue7dd" #define FILE_HARBOUR "\ue7de" #define FILE_GRAPHQL "\ue7df" #define FILE_GRAPHVIZ "\ue7e0" #define FILE_HASHICORP "\ue7e1" #define FILE_HY "\ue7e2" #define FILE_IGORPRO "\ue7e3" #define FILE_IO "\ue7e4" #define FILE_IOKE "\ue7e5" #define FILE_IDRIS "\ue7e6" #define FILE_INFORM7 "\ue7e7" #define FILE_INNO "\ue7e8" #define FILE_SUBLIME "\ue7e9" #define FILE_JUPYTER "\ue7ea" #define FILE_KRL "\ue7eb" #define FILE_KOTLIN "\ue7ec" #define FILE_LABVIEW "\ue7ed" #define FILE_LSL "\ue7ee" #define FILE_LASSO "\ue7ef" #define FILE_LOGTALK "\ue7f0" #define FILE_LOOKML "\ue7f1" #define FILE_MAKO "\ue7f2" #define FILE_MATHEMATICA "\ue7f3" #define FILE_MATLAB "\ue7f4" #define FILE_E992 "\ue7f5" #define FILE_MAX "\ue7f6" #define FILE_MERCURY "\ue7f7" #define FILE_MIRAH "\ue7f8" #define FILE_MODULA2 "\ue7f9" #define FILE_MONKEY "\ue7fa" #define FILE_NIMROD "\ue7fb" #define FILE_NIT "\ue7fc" #define FILE_NIX "\ue7fd" #define FILE_AMX "\ue7fe" #define FILE_NETLOGO "\ue7ff" #define FILE_NUMPY "\ue800" #define FILE_OBJJ "\ue801" #define FILE_OPENCL "\ue802" #define FILE_PROCESSING "\ue803" #define FILE_OX "\ue804" #define FILE_SCD "\ue805" #define FILE_STATA "\ue806" #define FILE_STAN "\ue807" #define FILE_SQF "\ue808" #define FILE_SLASH "\ue809" #define FILE_SHEN "\ue80a" #define FILE_SELF "\ue80b" #define FILE_SCILAB "\ue80c" #define FILE_VHDL "\ue80d" #define FILE_SAGE "\ue80e" #define FILE_ROBOT "\ue80f" #define FILE_RED "\ue810" #define FILE_REBOL "\ue811" #define FILE_XOJO "\ue812" #define FILE_RDOC "\ue813" #define FILE_RACKET "\ue814" #define FILE_PURESCRIPT "\ue815" #define FILE_UNO "\ue816" #define FILE_VARNISH "\ue817" #define FILE_PROPELLER "\ue818" #define FILE_TURING "\ue819" #define FILE_PONY "\ue81a" #define FILE_POGO "\ue81b" #define FILE_PIKE "\ue81c" #define FILE_URWEB "\ue81d" #define FILE_PARROT "\ue81e" #define FILE_PAPYRUS "\ue81f" #define FILE_PAN "\ue820" #define FILE_OZ "\ue821" #define FILE_OXYGENE "\ue822" #define FILE_PROGRESS "\ue823" #define FILE_TXL "\ue824" #define FILE_CABAL "\ue825" #define FILE_SYSVERILOG "\ue826" #define FILE_PICKLE "\ue827" #define FILE_XPAGES "\ue828" #define FILE_XTEND "\ue829" #define FILE_ZEPHIR "\ue82a" #define FILE_ZIMPL "\ue82b" #define FILE_EC "\ue82c" #define FILE_MUPAD "\ue82d" #define FILE_OOC "\ue82e" #define FILE_RST "\ue82f" #define FILE_KARMA "\ue830" #define FILE_HACK "\ue831" #define FILE_SHOPIFY "\ue832" #define FILE_PUG_ALT "\ue833" #define FILE_E9D1 "\ue834" #define FILE_SBT "\ue835" #define FILE_E9D3 "\ue836" #define FILE_SCRUTINIZER "\ue837" #define FILE_CC "\ue838" #define FILE_BRAKEMAN "\ue839" #define FILE_NEWRELIC "\ue83a" #define FILE_THOR "\ue83b" #define FILE_NUGET "\ue83c" #define FILE_POWERSHELL "\ue83d" #define FILE_SF "\ue83e" #define FILE_MINECRAFT "\ue83f" #define FILE_SQLITE "\ue840" #define FILE_PROTRACTOR "\ue841" #define FILE_TYPINGS "\ue842" #define FILE_STRINGS "\ue843" #define FILE_NANT "\ue844" #define FILE_CSSCRIPT "\ue845" #define FILE_CAKE "\ue846" #define FILE_OPENOFFICE "\ue847" #define FILE_KEYNOTE "\ue848" #define FILE_JSX "\ue849" #define FILE_TSX "\ue84a" #define FILE_MODEL "\ue84b" #define FILE_FINDER "\ue84c" #define FILE_ACCESS "\ue84d" #define FILE_ONENOTE "\ue84e" #define FILE_POWERPOINT "\ue84f" #define FILE_WORD "\ue850" #define FILE_EXCEL "\ue851" #define FILE_STORYIST "\ue852" #define FILE_CSOUND "\ue853" #define FILE_DBASE "\ue854" #define FILE_ZBRUSH "\ue855" #define FILE_AE "\ue856" #define FILE_INDESIGN "\ue857" #define FILE_PREMIERE "\ue858" #define FILE_MAYA "\ue859" #define FILE_E9F7 "\ue85a" #define FILE_KHRONOS "\ue85b" #define FILE_AUDACITY "\ue85c" #define FILE_BLENDER "\ue85d" #define FILE_LIGHTWAVE "\ue85e" #define FILE_FBX "\ue85f" #define FILE_E9FD "\ue860" #define FILE_TYPEDOC "\ue861" #define FILE_ALPINE "\ue862" #define FILE_YUI "\ue863" #define FILE_EA01 "\ue864" #define FILE_EA02 "\ue865" #define FILE_EA03 "\ue866" #define FILE_NORMALIZE "\ue867" #define FILE_NEKO "\ue868" #define FILE_MATHJAX "\ue869" #define FILE_LEAFLET "\ue86a" #define FILE_GDB "\ue86b" #define FILE_FUELUX "\ue86c" #define FILE_EQ "\ue86d" #define FILE_CHARTJS "\ue86e" #define FILE_EA0C "\ue86f" #define FILE_EA0D "\ue870" #define FILE_EA0E "\ue871" #define FILE_ESLINT "\ue872" #define FILE_D3 "\ue873" #define FILE_CORDOVA "\ue874" #define FILE_CIRCLECI "\ue875" #define FILE_PUG "\ue876" #define FILE_POWERBUILDER "\ue877" #define FILE_DYLIB "\ue878" #define FILE_REXX "\ue879" #define FILE_SVN "\ue87a" #define FILE_MRUBY "\ue87b" #define FILE_WERCKER "\ue87c" #define FILE_YARN "\ue87d" #define FILE_EDITORCONFIG "\ue87e" #define FILE_SNYK "\ue87f" #define FILE_REASON "\ue880" #define FILE_NSIS "\ue881" #define FILE_V8 "\ue882" #define FILE_ROLLUP "\ue883" #define FILE_EA21 "\ue884" #define FILE_EA22 "\ue885" #define FILE_EA23 "\ue886" #define FILE_RASCAL "\ue887" #define FILE_GN "\ue888" #define FILE_NODEMON "\ue889" #define FILE_ELECTRON "\ue88a" #define FILE_1C_ALT "\ue88b" #define FILE_SWAGGER "\ue88c" #define FILE_BITHOUND "\ue88d" #define FILE_POLYMER "\ue88e" #define FILE_PLATFORMIO "\ue88f" #define FILE_SHIPPABLE "\ue890" #define FILE_EA2E "\ue891" #define FILE_SEQUELIZE "\ue892" #define FILE_REDUX "\ue893" #define FILE_RSPEC "\ue894" #define FILE_PHPUNIT "\ue895" #define FILE_OCTAVE "\ue896" #define FILE_NUCLIDE "\ue897" #define FILE_INFOPATH "\ue898" #define FILE_LIME "\ue899" #define FILE_LERNA "\ue89a" #define FILE_KITCHENCI "\ue89b" #define FILE_JEST "\ue89c" #define FILE_JASMINE "\ue89d" #define FILE_HAXEDEVELOP "\ue89e" #define FILE_GITLAB "\ue89f" #define FILE_DRONE "\ue8a0" #define FILE_VIRTUALBOX "\ue8a1" #define FILE_DOCLETS "\ue8a2" #define FILE_DELPHI "\ue8a3" #define FILE_CODEKIT "\ue8a4" #define FILE_CHEF "\ue8a5" #define FILE_CAKEPHP "\ue8a6" #define FILE_COBOL "\ue8a7" #define FILE_BUNDLER "\ue8a8" #define FILE_BUCK "\ue8a9" #define FILE_BRUNCH "\ue8aa" #define FILE_AURELIA "\ue8ab" #define FILE_VMWARE "\ue8ac" #define FILE_RHINO "\ue8ad" #define FILE_EJS "\ue8ae" #define FILE_KICAD "\ue8af" #define FILE_HOPLON "\ue8b0" #define FILE_ABIF "\ue8b1" #define FILE_WATCHMAN "\ue8b2" #define FILE_P4 "\ue8b3" #define FILE_NANOC "\ue8b4" #define FILE_MIRANDA "\ue8b5" #define FILE_MINIZINC "\ue8b6" #define FILE_MESON "\ue8b7" #define FILE_JISON "\ue8b8" #define FILE_FRANCA "\ue8b9" #define FILE_DEVICETREE "\ue8ba" #define FILE_CADDY "\ue8bb" #define FILE_BEM "\ue8bc" #define FILE_BAZEL "\ue8bd" #define FILE_ANGELSCRIPT "\ue8be" #define FILE_ESDOC "\ue8bf" #define FILE_TWINE "\ue8c0" #define FILE_SQUARESPACE "\ue8c1" #define FILE_PHOENIX "\ue8c2" #define FILE_TEST_DIR "\ue8c3" #define FILE_WEBPACK "\ue8c4" #define FILE_TEST_COFFEE "\ue8c5" #define FILE_TEST_GENERIC "\ue8c6" #define FILE_TEST_JS "\ue8c7" #define FILE_TEST_PERL "\ue8c8" #define FILE_TEST_PYTHON "\ue8c9" #define FILE_TEST_REACT "\ue8ca" #define FILE_TEST_RUBY "\ue8cb" #define FILE_TEST_TS "\ue8cc" #define FILE_CODESHIP "\ue8cd" #define FILE_NXC "\ue8ce" #define FILE_BROTLI "\ue8cf" #define FILE_PROSELINT "\ue8d0" #define FILE_BINTRAY "\ue8d1" #define FILE_MJML "\ue8d2" #define FILE_WASM "\ue8d3" #define FILE_EA71 "\ue8d4" #define FILE_NASM "\ue8d5" #define FILE_EA73 "\ue8d6" #define FILE_PEG "\ue8d7" #define FILE_JOLIE "\ue8d8" #define FILE_NANO "\ue8d9" #define FILE_XAMARIN "\ue8da" #define FILE_F012 "\ue8db" #define FILE_TAG "\ue8dc" #define FILE_CUCUMBER "\ue8dd" #define FILE_VIDEO "\ue8de" #define FILE_CONFIG "\ue8df" #define FILE_DASHBOARD "\ue8e0" #define FILE_PUPPET "\ue8e1" #define FILE_TERMINAL "\ue8e2" #define FILE_MARKDOWNLINT "\ue8e3" #define FILE_REACT "\ue8e4" #define FILE_F101 "\ue8e5" #define FILE_ELM "\ue8e6" #define FILE_BOOT "\ue8e7" #define FILE_CLJS "\ue8e8" #define FILE_LEIN "\ue8e9" #define FILE_DOCKER "\ue8ea" #define FILE_PHP "\ue8eb" #define FILE_IONIC "\ue8ec" #define FILE_HAML "\ue8ed" #define FILE_F17B "\ue8ee" #define FILE_FF "\ue8ef" #define FILE_U1F3C1 "\ue8f0" #define FILE_TERN "\ue8f1" #define FILE_DEFAULT "\ue8f2" #define FILE_SIGILS "\ue8f3" #define FILE_NGINX "\ue8f4" #define WEATHER_DAY_CLOUDY_GUSTS "\ue8f5" #define WEATHER_DAY_CLOUDY_WINDY "\ue8f6" #define WEATHER_DAY_CLOUDY "\ue8f7" #define WEATHER_DAY_FOG "\ue8f8" #define WEATHER_DAY_HAIL "\ue8f9" #define WEATHER_DAY_LIGHTNING "\ue8fa" #define WEATHER_DAY_RAIN_MIX "\ue8fb" #define WEATHER_DAY_RAIN_WIND "\ue8fc" #define WEATHER_DAY_RAIN "\ue8fd" #define WEATHER_DAY_SHOWERS "\ue8fe" #define WEATHER_DAY_SNOW "\ue8ff" #define WEATHER_DAY_SPRINKLE "\ue900" #define WEATHER_DAY_SUNNY_OVERCAST "\ue901" #define WEATHER_DAY_SUNNY "\ue902" #define WEATHER_DAY_STORM_SHOWERS "\ue903" #define WEATHER_DAY_THUNDERSTORM "\ue904" #define WEATHER_CLOUDY_GUSTS "\ue905" #define WEATHER_CLOUDY_WINDY "\ue906" #define WEATHER_CLOUDY "\ue907" #define WEATHER_FOG "\ue908" #define WEATHER_HAIL "\ue909" #define WEATHER_LIGHTNING "\ue90a" #define WEATHER_RAIN_MIX "\ue90b" #define WEATHER_RAIN_WIND "\ue90c" #define WEATHER_RAIN "\ue90d" #define WEATHER_SHOWERS "\ue90e" #define WEATHER_SNOW "\ue90f" #define WEATHER_SPRINKLE "\ue910" #define WEATHER_STORM_SHOWERS "\ue911" #define WEATHER_THUNDERSTORM "\ue912" #define WEATHER_WINDY "\ue913" #define WEATHER_NIGHT_ALT_CLOUDY_GUSTS "\ue914" #define WEATHER_NIGHT_ALT_CLOUDY_WINDY "\ue915" #define WEATHER_NIGHT_ALT_HAIL "\ue916" #define WEATHER_NIGHT_ALT_LIGHTNING "\ue917" #define WEATHER_NIGHT_ALT_RAIN_MIX "\ue918" #define WEATHER_NIGHT_ALT_RAIN_WIND "\ue919" #define WEATHER_NIGHT_ALT_RAIN "\ue91a" #define WEATHER_NIGHT_ALT_SHOWERS "\ue91b" #define WEATHER_NIGHT_ALT_SNOW "\ue91c" #define WEATHER_NIGHT_ALT_SPRINKLE "\ue91d" #define WEATHER_NIGHT_ALT_STORM_SHOWERS "\ue91e" #define WEATHER_NIGHT_ALT_THUNDERSTORM "\ue91f" #define WEATHER_NIGHT_CLEAR "\ue920" #define WEATHER_NIGHT_CLOUDY_GUSTS "\ue921" #define WEATHER_NIGHT_CLOUDY_WINDY "\ue922" #define WEATHER_NIGHT_CLOUDY "\ue923" #define WEATHER_NIGHT_HAIL "\ue924" #define WEATHER_NIGHT_LIGHTNING "\ue925" #define WEATHER_NIGHT_RAIN_MIX "\ue926" #define WEATHER_NIGHT_RAIN_WIND "\ue927" #define WEATHER_NIGHT_RAIN "\ue928" #define WEATHER_NIGHT_SHOWERS "\ue929" #define WEATHER_NIGHT_SNOW "\ue92a" #define WEATHER_NIGHT_SPRINKLE "\ue92b" #define WEATHER_NIGHT_STORM_SHOWERS "\ue92c" #define WEATHER_NIGHT_THUNDERSTORM "\ue92d" #define WEATHER_CELSIUS "\ue92e" #define WEATHER_CLOUD_DOWN "\ue92f" #define WEATHER_CLOUD_REFRESH "\ue930" #define WEATHER_CLOUD_UP "\ue931" #define WEATHER_CLOUD "\ue932" #define WEATHER_DEGREES "\ue933" #define WEATHER_DIRECTION_DOWN_LEFT "\ue934" #define WEATHER_DIRECTION_DOWN "\ue935" #define WEATHER_FAHRENHEIT "\ue936" #define WEATHER_HORIZON_ALT "\ue937" #define WEATHER_HORIZON "\ue938" #define WEATHER_DIRECTION_LEFT "\ue939" #define WEATHER_F049 "\ue93a" #define WEATHER_NIGHT_FOG "\ue93b" #define WEATHER_REFRESH_ALT "\ue93c" #define WEATHER_REFRESH "\ue93d" #define WEATHER_DIRECTION_RIGHT "\ue93e" #define WEATHER_RAINDROPS "\ue93f" #define WEATHER_STRONG_WIND "\ue940" #define WEATHER_SUNRISE "\ue941" #define WEATHER_SUNSET "\ue942" #define WEATHER_THERMOMETER_EXTERIOR "\ue943" #define WEATHER_THERMOMETER_INTERNAL "\ue944" #define WEATHER_THERMOMETER "\ue945" #define WEATHER_TORNADO "\ue946" #define WEATHER_DIRECTION_UP_RIGHT "\ue947" #define WEATHER_DIRECTION_UP "\ue948" #define WEATHER_F059 "\ue949" #define WEATHER_F05A "\ue94a" #define WEATHER_F05B "\ue94b" #define WEATHER_F05C "\ue94c" #define WEATHER_F05D "\ue94d" #define WEATHER_F05E "\ue94e" #define WEATHER_F060 "\ue94f" #define WEATHER_F061 "\ue950" #define WEATHER_SMOKE "\ue951" #define WEATHER_DUST "\ue952" #define WEATHER_SNOW_WIND "\ue953" #define WEATHER_DAY_SNOW_WIND "\ue954" #define WEATHER_NIGHT_SNOW_WIND "\ue955" #define WEATHER_NIGHT_ALT_SNOW_WIND "\ue956" #define WEATHER_DAY_SLEET_STORM "\ue957" #define WEATHER_NIGHT_SLEET_STORM "\ue958" #define WEATHER_NIGHT_ALT_SLEET_STORM "\ue959" #define WEATHER_DAY_SNOW_THUNDERSTORM "\ue95a" #define WEATHER_NIGHT_SNOW_THUNDERSTORM "\ue95b" #define WEATHER_NIGHT_ALT_SNOW_THUNDERSTORM "\ue95c" #define WEATHER_SOLAR_ECLIPSE "\ue95d" #define WEATHER_LUNAR_ECLIPSE "\ue95e" #define WEATHER_METEOR "\ue95f" #define WEATHER_HOT "\ue960" #define WEATHER_HURRICANE "\ue961" #define WEATHER_SMOG "\ue962" #define WEATHER_ALIEN "\ue963" #define WEATHER_SNOWFLAKE_COLD "\ue964" #define WEATHER_STARS "\ue965" #define WEATHER_RAINDROP "\ue966" #define WEATHER_BAROMETER "\ue967" #define WEATHER_HUMIDITY "\ue968" #define WEATHER_NA "\ue969" #define WEATHER_FLOOD "\ue96a" #define WEATHER_DAY_CLOUDY_HIGH "\ue96b" #define WEATHER_NIGHT_ALT_CLOUDY_HIGH "\ue96c" #define WEATHER_NIGHT_CLOUDY_HIGH "\ue96d" #define WEATHER_NIGHT_ALT_PARTLY_CLOUDY "\ue96e" #define WEATHER_SANDSTORM "\ue96f" #define WEATHER_NIGHT_PARTLY_CLOUDY "\ue970" #define WEATHER_UMBRELLA "\ue971" #define WEATHER_DAY_WINDY "\ue972" #define WEATHER_NIGHT_ALT_CLOUDY "\ue973" #define WEATHER_DIRECTION_UP_LEFT "\ue974" #define WEATHER_DIRECTION_DOWN_RIGHT "\ue975" #define WEATHER_TIME_12 "\ue976" #define WEATHER_TIME_1 "\ue977" #define WEATHER_TIME_2 "\ue978" #define WEATHER_TIME_3 "\ue979" #define WEATHER_TIME_4 "\ue97a" #define WEATHER_TIME_5 "\ue97b" #define WEATHER_TIME_6 "\ue97c" #define WEATHER_TIME_7 "\ue97d" #define WEATHER_TIME_8 "\ue97e" #define WEATHER_TIME_9 "\ue97f" #define WEATHER_TIME_10 "\ue980" #define WEATHER_TIME_11 "\ue981" #define WEATHER_MOON_NEW "\ue982" #define WEATHER_MOON_WAXING_CRESCENT_1 "\ue983" #define WEATHER_MOON_WAXING_CRESCENT_2 "\ue984" #define WEATHER_MOON_WAXING_CRESCENT_3 "\ue985" #define WEATHER_MOON_WAXING_CRESCENT_4 "\ue986" #define WEATHER_MOON_WAXING_CRESCENT_5 "\ue987" #define WEATHER_MOON_WAXING_CRESCENT_6 "\ue988" #define WEATHER_MOON_FIRST_QUARTER "\ue989" #define WEATHER_MOON_WAXING_GIBBOUS_1 "\ue98a" #define WEATHER_MOON_WAXING_GIBBOUS_2 "\ue98b" #define WEATHER_MOON_WAXING_GIBBOUS_3 "\ue98c" #define WEATHER_MOON_WAXING_GIBBOUS_4 "\ue98d" #define WEATHER_MOON_WAXING_GIBBOUS_5 "\ue98e" #define WEATHER_MOON_WAXING_GIBBOUS_6 "\ue98f" #define WEATHER_MOON_FULL "\ue990" #define WEATHER_MOON_WANING_GIBBOUS_1 "\ue991" #define WEATHER_MOON_WANING_GIBBOUS_2 "\ue992" #define WEATHER_MOON_WANING_GIBBOUS_3 "\ue993" #define WEATHER_MOON_WANING_GIBBOUS_4 "\ue994" #define WEATHER_MOON_WANING_GIBBOUS_5 "\ue995" #define WEATHER_MOON_WANING_GIBBOUS_6 "\ue996" #define WEATHER_MOON_THIRD_QUARTER "\ue997" #define WEATHER_MOON_WANING_CRESCENT_1 "\ue998" #define WEATHER_MOON_WANING_CRESCENT_2 "\ue999" #define WEATHER_MOON_WANING_CRESCENT_3 "\ue99a" #define WEATHER_MOON_WANING_CRESCENT_4 "\ue99b" #define WEATHER_MOON_WANING_CRESCENT_5 "\ue99c" #define WEATHER_MOON_WANING_CRESCENT_6 "\ue99d" #define WEATHER_WIND_DIRECTION "\ue99e" #define WEATHER_DAY_SLEET "\ue99f" #define WEATHER_NIGHT_SLEET "\ue9a0" #define WEATHER_NIGHT_ALT_SLEET "\ue9a1" #define WEATHER_SLEET "\ue9a2" #define WEATHER_DAY_HAZE "\ue9a3" #define WEATHER_WIND_BEAUFORT_0 "\ue9a4" #define WEATHER_WIND_BEAUFORT_1 "\ue9a5" #define WEATHER_WIND_BEAUFORT_2 "\ue9a6" #define WEATHER_WIND_BEAUFORT_3 "\ue9a7" #define WEATHER_WIND_BEAUFORT_4 "\ue9a8" #define WEATHER_WIND_BEAUFORT_5 "\ue9a9" #define WEATHER_WIND_BEAUFORT_6 "\ue9aa" #define WEATHER_WIND_BEAUFORT_7 "\ue9ab" #define WEATHER_WIND_BEAUFORT_8 "\ue9ac" #define WEATHER_WIND_BEAUFORT_9 "\ue9ad" #define WEATHER_WIND_BEAUFORT_10 "\ue9ae" #define WEATHER_WIND_BEAUFORT_11 "\ue9af" #define WEATHER_WIND_BEAUFORT_12 "\ue9b0" #define WEATHER_DAY_LIGHT_WIND "\ue9b1" #define WEATHER_TSUNAMI "\ue9b2" #define WEATHER_EARTHQUAKE "\ue9b3" #define WEATHER_FIRE "\ue9b4" #define WEATHER_VOLCANO "\ue9b5" #define WEATHER_MOONRISE "\ue9b6" #define WEATHER_MOONSET "\ue9b7" #define WEATHER_TRAIN "\ue9b8" #define WEATHER_SMALL_CRAFT_ADVISORY "\ue9b9" #define WEATHER_GALE_WARNING "\ue9ba" #define WEATHER_STORM_WARNING "\ue9bb" #define WEATHER_HURRICANE_WARNING "\ue9bc" #define WEATHER_MOON_ALT_WAXING_CRESCENT_1 "\ue9bd" #define WEATHER_MOON_ALT_WAXING_CRESCENT_2 "\ue9be" #define WEATHER_MOON_ALT_WAXING_CRESCENT_3 "\ue9bf" #define WEATHER_MOON_ALT_WAXING_CRESCENT_4 "\ue9c0" #define WEATHER_MOON_ALT_WAXING_CRESCENT_5 "\ue9c1" #define WEATHER_MOON_ALT_WAXING_CRESCENT_6 "\ue9c2" #define WEATHER_MOON_ALT_FIRST_QUARTER "\ue9c3" #define WEATHER_MOON_ALT_WAXING_GIBBOUS_1 "\ue9c4" #define WEATHER_MOON_ALT_WAXING_GIBBOUS_2 "\ue9c5" #define WEATHER_MOON_ALT_WAXING_GIBBOUS_3 "\ue9c6" #define WEATHER_MOON_ALT_WAXING_GIBBOUS_4 "\ue9c7" #define WEATHER_MOON_ALT_WAXING_GIBBOUS_5 "\ue9c8" #define WEATHER_MOON_ALT_WAXING_GIBBOUS_6 "\ue9c9" #define WEATHER_MOON_ALT_FULL "\ue9ca" #define WEATHER_MOON_ALT_WANING_GIBBOUS_1 "\ue9cb" #define WEATHER_MOON_ALT_WANING_GIBBOUS_2 "\ue9cc" #define WEATHER_MOON_ALT_WANING_GIBBOUS_3 "\ue9cd" #define WEATHER_MOON_ALT_WANING_GIBBOUS_4 "\ue9ce" #define WEATHER_MOON_ALT_WANING_GIBBOUS_5 "\ue9cf" #define WEATHER_MOON_ALT_WANING_GIBBOUS_6 "\ue9d0" #define WEATHER_MOON_ALT_THIRD_QUARTER "\ue9d1" #define WEATHER_MOON_ALT_WANING_CRESCENT_1 "\ue9d2" #define WEATHER_MOON_ALT_WANING_CRESCENT_2 "\ue9d3" #define WEATHER_MOON_ALT_WANING_CRESCENT_3 "\ue9d4" #define WEATHER_MOON_ALT_WANING_CRESCENT_4 "\ue9d5" #define WEATHER_MOON_ALT_WANING_CRESCENT_5 "\ue9d6" #define WEATHER_MOON_ALT_WANING_CRESCENT_6 "\ue9d7" #define WEATHER_MOON_ALT_NEW "\ue9d8" #define LINUX_ARCHLINUX "\ue9d9" #define LINUX_CENTOS "\ue9da" #define LINUX_DEBIAN "\ue9db" #define LINUX_FEDORA "\ue9dc" #define LINUX_LINUXMINT "\ue9dd" #define LINUX_LINUXMINT_INVERSE "\ue9de" #define LINUX_MAGEIA "\ue9df" #define LINUX_MANDRIVA "\ue9e0" #define LINUX_OPENSUSE "\ue9e1" #define LINUX_REDHAT "\ue9e2" #define LINUX_SLACKWARE "\ue9e3" #define LINUX_SLACKWARE_INVERSE "\ue9e4" #define LINUX_UBUNTU "\ue9e5" #define LINUX_UBUNTU_INVERSE "\ue9e6" #define LINUX_FREEBSD "\ue9e7" #define LINUX_COREOS "\ue9e8" #define LINUX_GENTOO "\ue9e9" #define LINUX_ELEMENTARY "\ue9ea" #define LINUX_FEDORA_INVERSE "\ue9eb" #define LINUX_SABAYON "\ue9ec" #define LINUX_AOSC "\ue9ed" #define LINUX_NIXOS "\ue9ee" #define LINUX_TUX "\ue9ef" #define LINUX_RASPBERRY_PI "\ue9f0" #define LINUX_MANJARO "\ue9f1" #define LINUX_APPLE "\ue9f2" #define LINUX_DOCKER "\ue9f3" #define LINUX_ALPINE "\ue9f4" #define MYICONS_0001 "\ue9f5" #define MYICONS_0002 "\ue9f6" #define MYICONS_0003 "\ue9f7" #define MYICONS_0004 "\ue9f8" #define MYICONS_0005 "\ue9f9" #define MYICONS_0006 "\ue9fa" #define MYICONS_0007 "\ue9fb" #define MYICONS_0008 "\ue9fc" #define MYICONS_0009 "\ue9fd" #define MYICONS_000A "\ue9fe" #define MYICONS_000B "\ue9ff" #define MYICONS_000D "\uea00" #define MYICONS_000E "\uea01" #define MYICONS_0010 "\uea02" #define MYICONS_0011 "\uea03" #define MYICONS_0013 "\uea04" #define MYICONS_0014 "\uea05" #define MYICONS_ARCH_LINUX_ARROW "\uea06" #define DEV_BING_SMALL "\uea07" #define DEV_CSS_TRICKS "\uea08" #define DEV_GIT "\uea09" #define DEV_BITBUCKET "\uea0a" #define DEV_MYSQL "\uea0b" #define DEV_STREAMLINE "\uea0c" #define DEV_DATABASE "\uea0d" #define DEV_DROPBOX "\uea0e" #define DEV_GITHUB_ALT "\uea0f" #define DEV_GITHUB_BADGE "\uea10" #define DEV_GITHUB "\uea11" #define DEV_WORDPRESS "\uea12" #define DEV_VISUALSTUDIO "\uea13" #define DEV_JEKYLL_SMALL "\uea14" #define DEV_ANDROID "\uea15" #define DEV_WINDOWS "\uea16" #define DEV_STACKOVERFLOW "\uea17" #define DEV_APPLE "\uea18" #define DEV_LINUX "\uea19" #define DEV_APPSTORE "\uea1a" #define DEV_GHOST_SMALL "\uea1b" #define DEV_YAHOO "\uea1c" #define DEV_CODEPEN "\uea1d" #define DEV_GITHUB_FULL "\uea1e" #define DEV_NODEJS_SMALL "\uea1f" #define DEV_NODEJS "\uea20" #define DEV_HACKERNEWS "\uea21" #define DEV_EMBER "\uea22" #define DEV_DOJO "\uea23" #define DEV_DJANGO "\uea24" #define DEV_NPM "\uea25" #define DEV_GHOST "\uea26" #define DEV_MODERNIZR "\uea27" #define DEV_UNITY_SMALL "\uea28" #define DEV_RASPBERRY_PI "\uea29" #define DEV_BLACKBERRY "\uea2a" #define DEV_GO "\uea2b" #define DEV_GIT_BRANCH "\uea2c" #define DEV_GIT_PULL_REQUEST "\uea2d" #define DEV_GIT_MERGE "\uea2e" #define DEV_GIT_COMPARE "\uea2f" #define DEV_GIT_COMMIT "\uea30" #define DEV_CSSDECK "\uea31" #define DEV_YAHOO_SMALL "\uea32" #define DEV_TECHCRUNCH "\uea33" #define DEV_SMASHING_MAGAZINE "\uea34" #define DEV_NETMAGAZINE "\uea35" #define DEV_CODROPS "\uea36" #define DEV_PHONEGAP "\uea37" #define DEV_GOOGLE_DRIVE "\uea38" #define DEV_HTML5_MULTIMEDIA "\uea39" #define DEV_HTML5_DEVICE_ACCESS "\uea3a" #define DEV_HTML5_CONNECTIVITY "\uea3b" #define DEV_HTML5_3D_EFFECTS "\uea3c" #define DEV_HTML5 "\uea3d" #define DEV_SCALA "\uea3e" #define DEV_JAVA "\uea3f" #define DEV_RUBY "\uea40" #define DEV_UBUNTU "\uea41" #define DEV_RUBY_ON_RAILS "\uea42" #define DEV_PYTHON "\uea43" #define DEV_PHP "\uea44" #define DEV_MARKDOWN "\uea45" #define DEV_LARAVEL "\uea46" #define DEV_MAGENTO "\uea47" #define DEV_JOOMLA "\uea48" #define DEV_DRUPAL "\uea49" #define DEV_CHROME "\uea4a" #define DEV_IE "\uea4b" #define DEV_FIREFOX "\uea4c" #define DEV_OPERA "\uea4d" #define DEV_BOOTSTRAP "\uea4e" #define DEV_SAFARI "\uea4f" #define DEV_CSS3 "\uea50" #define DEV_CSS3_FULL "\uea51" #define DEV_SASS "\uea52" #define DEV_GRUNT "\uea53" #define DEV_BOWER "\uea54" #define DEV_JAVASCRIPT "\uea55" #define DEV_JAVASCRIPT_SHIELD "\uea56" #define DEV_JQUERY "\uea57" #define DEV_COFFEESCRIPT "\uea58" #define DEV_BACKBONE "\uea59" #define DEV_ANGULAR "\uea5a" #define DEV_JQUERY_UI "\uea5b" #define DEV_SWIFT "\uea5c" #define DEV_SYMFONY "\uea5d" #define DEV_SYMFONY_BADGE "\uea5e" #define DEV_LESS "\uea5f" #define DEV_STYLUS "\uea60" #define DEV_TRELLO "\uea61" #define DEV_ATLASSIAN "\uea62" #define DEV_JIRA "\uea63" #define DEV_ENVATO "\uea64" #define DEV_SNAP_SVG "\uea65" #define DEV_RAPHAEL "\uea66" #define DEV_GOOGLE_ANALYTICS "\uea67" #define DEV_COMPASS "\uea68" #define DEV_ONEDRIVE "\uea69" #define DEV_GULP "\uea6a" #define DEV_ATOM "\uea6b" #define DEV_CISCO "\uea6c" #define DEV_NANCY "\uea6d" #define DEV_JENKINS "\uea6e" #define DEV_CLOJURE "\uea6f" #define DEV_PERL "\uea70" #define DEV_CLOJURE_ALT "\uea71" #define DEV_CELLULOID "\uea72" #define DEV_W3C "\uea73" #define DEV_REDIS "\uea74" #define DEV_POSTGRESQL "\uea75" #define DEV_WEBPLATFORM "\uea76" #define DEV_REQUIREJS "\uea77" #define DEV_OPENSOURCE "\uea78" #define DEV_TYPO3 "\uea79" #define DEV_UIKIT "\uea7a" #define DEV_DOCTRINE "\uea7b" #define DEV_GROOVY "\uea7c" #define DEV_NGINX "\uea7d" #define DEV_HASKELL "\uea7e" #define DEV_ZEND "\uea7f" #define DEV_GNU "\uea80" #define DEV_YEOMAN "\uea81" #define DEV_HEROKU "\uea82" #define DEV_MSQL_SERVER "\uea83" #define DEV_DEBIAN "\uea84" #define DEV_TRAVIS "\uea85" #define DEV_DOTNET "\uea86" #define DEV_CODEIGNITER "\uea87" #define DEV_JAVASCRIPT_BADGE "\uea88" #define DEV_YII "\uea89" #define DEV_COMPOSER "\uea8a" #define DEV_KRAKENJS_BADGE "\uea8b" #define DEV_KRAKENJS "\uea8c" #define DEV_MOZILLA "\uea8d" #define DEV_FIREBASE "\uea8e" #define DEV_SIZZLEJS "\uea8f" #define DEV_CREATIVECOMMONS "\uea90" #define DEV_CREATIVECOMMONS_BADGE "\uea91" #define DEV_MITLICENCE "\uea92" #define DEV_SENCHATOUCH "\uea93" #define DEV_BUGSENSE "\uea94" #define DEV_EXTJS "\uea95" #define DEV_MOOTOOLS_BADGE "\uea96" #define DEV_MOOTOOLS "\uea97" #define DEV_RUBY_ROUGH "\uea98" #define DEV_KOMODO "\uea99" #define DEV_CODA "\uea9a" #define DEV_BINTRAY "\uea9b" #define DEV_TERMINAL "\uea9c" #define DEV_CODE "\uea9d" #define DEV_RESPONSIVE "\uea9e" #define DEV_DART "\uea9f" #define DEV_APTANA "\ueaa0" #define DEV_MAILCHIMP "\ueaa1" #define DEV_NETBEANS "\ueaa2" #define DEV_DREAMWEAVER "\ueaa3" #define DEV_BRACKETS "\ueaa4" #define DEV_ECLIPSE "\ueaa5" #define DEV_CLOUD9 "\ueaa6" #define DEV_SCRUM "\ueaa7" #define DEV_PROLOG "\ueaa8" #define DEV_TERMINAL_BADGE "\ueaa9" #define DEV_CODE_BADGE "\ueaaa" #define DEV_MONGODB "\ueaab" #define DEV_METEOR "\ueaac" #define DEV_METEORFULL "\ueaad" #define DEV_FSHARP "\ueaae" #define DEV_RUST "\ueaaf" #define DEV_IONIC "\ueab0" #define DEV_SUBLIME "\ueab1" #define DEV_APPCELERATOR "\ueab2" #define DEV_ASTERISK "\ueab3" #define DEV_AWS "\ueab4" #define DEV_DIGITAL_OCEAN "\ueab5" #define DEV_DLANG "\ueab6" #define DEV_DOCKER "\ueab7" #define DEV_ERLANG "\ueab8" #define DEV_GOOGLE_CLOUD_PLATFORM "\ueab9" #define DEV_GRAILS "\ueaba" #define DEV_ILLUSTRATOR "\ueabb" #define DEV_INTELLIJ "\ueabc" #define DEV_MATERIALIZECSS "\ueabd" #define DEV_OPENSHIFT "\ueabe" #define DEV_PHOTOSHOP "\ueabf" #define DEV_RACKSPACE "\ueac0" #define DEV_REACT "\ueac1" #define DEV_REDHAT "\ueac2" #define DEV_SCRIPTCS "\ueac3" #define DEV_E6BD "\ueac4" #define DEV_E6BE "\ueac5" #define DEV_E6BF "\ueac6" #define DEV_E6C0 "\ueac7" #define DEV_E6C1 "\ueac8" #define DEV_E6C2 "\ueac9" #define DEV_E6C3 "\ueaca" #define DEV_SQLLITE "\ueacb" #define DEV_VIM "\ueacc" #define POM_CLEAN_CODE "\ueacd" #define POM_POMODORO_DONE "\ueace" #define POM_POMODORO_ESTIMATED "\ueacf" #define POM_POMODORO_TICKING "\uead0" #define POM_POMODORO_SQUASHED "\uead1" #define POM_SHORT_PAUSE "\uead2" #define POM_LONG_PAUSE "\uead3" #define POM_AWAY "\uead4" #define POM_PAIR_PROGRAMMING "\uead5" #define POM_INTERNAL_INTERRUPTION "\uead6" #define POM_EXTERNAL_INTERRUPTION "\uead7" #define LINEA_ARROWS_ANTICLOCKWISE "\uead8" #define LINEA_ARROWS_ANTICLOCKWISE_DASHED "\uead9" #define LINEA_ARROWS_BUTTON_DOWN "\ueada" #define LINEA_ARROWS_BUTTON_OFF "\ueadb" #define LINEA_ARROWS_BUTTON_ON "\ueadc" #define LINEA_ARROWS_BUTTON_UP "\ueadd" #define LINEA_ARROWS_CHECK "\ueade" #define LINEA_ARROWS_CIRCLE_CHECK "\ueadf" #define LINEA_ARROWS_CIRCLE_DOWN "\ueae0" #define LINEA_ARROWS_CIRCLE_DOWNLEFT "\ueae1" #define LINEA_ARROWS_CIRCLE_DOWNRIGHT "\ueae2" #define LINEA_ARROWS_CIRCLE_LEFT "\ueae3" #define LINEA_ARROWS_CIRCLE_MINUS "\ueae4" #define LINEA_ARROWS_CIRCLE_PLUS "\ueae5" #define LINEA_ARROWS_CIRCLE_REMOVE "\ueae6" #define LINEA_ARROWS_CIRCLE_RIGHT "\ueae7" #define LINEA_ARROWS_CIRCLE_UP "\ueae8" #define LINEA_ARROWS_CIRCLE_UPLEFT "\ueae9" #define LINEA_ARROWS_CIRCLE_UPRIGHT "\ueaea" #define LINEA_ARROWS_CLOCKWISE "\ueaeb" #define LINEA_ARROWS_CLOCKWISE_DASHED "\ueaec" #define LINEA_ARROWS_COMPRESS "\ueaed" #define LINEA_ARROWS_DENY "\ueaee" #define LINEA_ARROWS_DIAGONAL "\ueaef" #define LINEA_ARROWS_DIAGONAL2 "\ueaf0" #define LINEA_ARROWS_DOWN "\ueaf1" #define LINEA_ARROWS_DOWN_DOUBLE "\ueaf2" #define LINEA_ARROWS_DOWNLEFT "\ueaf3" #define LINEA_ARROWS_DOWNRIGHT "\ueaf4" #define LINEA_ARROWS_DRAG_DOWN "\ueaf5" #define LINEA_ARROWS_DRAG_DOWN_DASHED "\ueaf6" #define LINEA_ARROWS_DRAG_HORIZ "\ueaf7" #define LINEA_ARROWS_DRAG_LEFT "\ueaf8" #define LINEA_ARROWS_DRAG_LEFT_DASHED "\ueaf9" #define LINEA_ARROWS_DRAG_RIGHT "\ueafa" #define LINEA_ARROWS_DRAG_RIGHT_DASHED "\ueafb" #define LINEA_ARROWS_DRAG_UP "\ueafc" #define LINEA_ARROWS_DRAG_UP_DASHED "\ueafd" #define LINEA_ARROWS_DRAG_VERT "\ueafe" #define LINEA_ARROWS_EXCLAMATION "\ueaff" #define LINEA_ARROWS_EXPAND "\ueb00" #define LINEA_ARROWS_EXPAND_DIAGONAL1 "\ueb01" #define LINEA_ARROWS_EXPAND_HORIZONTAL1 "\ueb02" #define LINEA_ARROWS_EXPAND_VERTICAL1 "\ueb03" #define LINEA_ARROWS_FIT_HORIZONTAL "\ueb04" #define LINEA_ARROWS_FIT_VERTICAL "\ueb05" #define LINEA_ARROWS_GLIDE "\ueb06" #define LINEA_ARROWS_GLIDE_HORIZONTAL "\ueb07" #define LINEA_ARROWS_GLIDE_VERTICAL "\ueb08" #define LINEA_ARROWS_HAMBURGER1 "\ueb09" #define LINEA_ARROWS_HAMBURGER_2 "\ueb0a" #define LINEA_ARROWS_HORIZONTAL "\ueb0b" #define LINEA_ARROWS_INFO "\ueb0c" #define LINEA_ARROWS_KEYBOARD_ALT "\ueb0d" #define LINEA_ARROWS_KEYBOARD_CMD "\ueb0e" #define LINEA_ARROWS_KEYBOARD_DELETE "\ueb0f" #define LINEA_ARROWS_KEYBOARD_DOWN "\ueb10" #define LINEA_ARROWS_KEYBOARD_LEFT "\ueb11" #define LINEA_ARROWS_KEYBOARD_RETURN "\ueb12" #define LINEA_ARROWS_KEYBOARD_RIGHT "\ueb13" #define LINEA_ARROWS_KEYBOARD_SHIFT "\ueb14" #define LINEA_ARROWS_KEYBOARD_TAB "\ueb15" #define LINEA_ARROWS_KEYBOARD_UP "\ueb16" #define LINEA_ARROWS_LEFT "\ueb17" #define LINEA_ARROWS_LEFT_DOUBLE_32 "\ueb18" #define LINEA_ARROWS_MINUS "\ueb19" #define LINEA_ARROWS_MOVE "\ueb1a" #define LINEA_ARROWS_MOVE2 "\ueb1b" #define LINEA_ARROWS_MOVE_BOTTOM "\ueb1c" #define LINEA_ARROWS_MOVE_LEFT "\ueb1d" #define LINEA_ARROWS_MOVE_RIGHT "\ueb1e" #define LINEA_ARROWS_MOVE_TOP "\ueb1f" #define LINEA_ARROWS_PLUS "\ueb20" #define LINEA_ARROWS_QUESTION "\ueb21" #define LINEA_ARROWS_REMOVE "\ueb22" #define LINEA_ARROWS_RIGHT "\ueb23" #define LINEA_ARROWS_RIGHT_DOUBLE "\ueb24" #define LINEA_ARROWS_ROTATE "\ueb25" #define LINEA_ARROWS_ROTATE_ANTI "\ueb26" #define LINEA_ARROWS_ROTATE_ANTI_DASHED "\ueb27" #define LINEA_ARROWS_ROTATE_DASHED "\ueb28" #define LINEA_ARROWS_SHRINK "\ueb29" #define LINEA_ARROWS_SHRINK_DIAGONAL1 "\ueb2a" #define LINEA_ARROWS_SHRINK_DIAGONAL2 "\ueb2b" #define LINEA_ARROWS_SHRINK_HORIZONAL2 "\ueb2c" #define LINEA_ARROWS_SHRINK_HORIZONTAL1 "\ueb2d" #define LINEA_ARROWS_SHRINK_VERTICAL1 "\ueb2e" #define LINEA_ARROWS_SHRINK_VERTICAL2 "\ueb2f" #define LINEA_ARROWS_SIGN_DOWN "\ueb30" #define LINEA_ARROWS_SIGN_LEFT "\ueb31" #define LINEA_ARROWS_SIGN_RIGHT "\ueb32" #define LINEA_ARROWS_SIGN_UP "\ueb33" #define LINEA_ARROWS_SLIDE_DOWN1 "\ueb34" #define LINEA_ARROWS_SLIDE_DOWN2 "\ueb35" #define LINEA_ARROWS_SLIDE_LEFT1 "\ueb36" #define LINEA_ARROWS_SLIDE_LEFT2 "\ueb37" #define LINEA_ARROWS_SLIDE_RIGHT1 "\ueb38" #define LINEA_ARROWS_SLIDE_RIGHT2 "\ueb39" #define LINEA_ARROWS_SLIDE_UP1 "\ueb3a" #define LINEA_ARROWS_SLIDE_UP2 "\ueb3b" #define LINEA_ARROWS_SLIM_DOWN "\ueb3c" #define LINEA_ARROWS_SLIM_DOWN_DASHED "\ueb3d" #define LINEA_ARROWS_SLIM_LEFT "\ueb3e" #define LINEA_ARROWS_SLIM_LEFT_DASHED "\ueb3f" #define LINEA_ARROWS_SLIM_RIGHT "\ueb40" #define LINEA_ARROWS_SLIM_RIGHT_DASHED "\ueb41" #define LINEA_ARROWS_SLIM_UP "\ueb42" #define LINEA_ARROWS_SLIM_UP_DASHED "\ueb43" #define LINEA_ARROWS_SQUARE_CHECK "\ueb44" #define LINEA_ARROWS_SQUARE_DOWN "\ueb45" #define LINEA_ARROWS_SQUARE_DOWNLEFT "\ueb46" #define LINEA_ARROWS_SQUARE_DOWNRIGHT "\ueb47" #define LINEA_ARROWS_SQUARE_LEFT "\ueb48" #define LINEA_ARROWS_SQUARE_MINUS "\ueb49" #define LINEA_ARROWS_SQUARE_PLUS "\ueb4a" #define LINEA_ARROWS_SQUARE_REMOVE "\ueb4b" #define LINEA_ARROWS_SQUARE_RIGHT "\ueb4c" #define LINEA_ARROWS_SQUARE_UP "\ueb4d" #define LINEA_ARROWS_SQUARE_UPLEFT "\ueb4e" #define LINEA_ARROWS_SQUARE_UPRIGHT "\ueb4f" #define LINEA_ARROWS_SQUARES "\ueb50" #define LINEA_ARROWS_STRETCH_DIAGONAL1 "\ueb51" #define LINEA_ARROWS_STRETCH_DIAGONAL2 "\ueb52" #define LINEA_ARROWS_STRETCH_DIAGONAL3 "\ueb53" #define LINEA_ARROWS_STRETCH_DIAGONAL4 "\ueb54" #define LINEA_ARROWS_STRETCH_HORIZONTAL1 "\ueb55" #define LINEA_ARROWS_STRETCH_HORIZONTAL2 "\ueb56" #define LINEA_ARROWS_STRETCH_VERTICAL1 "\ueb57" #define LINEA_ARROWS_STRETCH_VERTICAL2 "\ueb58" #define LINEA_ARROWS_SWITCH_HORIZONTAL "\ueb59" #define LINEA_ARROWS_SWITCH_VERTICAL "\ueb5a" #define LINEA_ARROWS_UP "\ueb5b" #define LINEA_ARROWS_UP_DOUBLE_33 "\ueb5c" #define LINEA_ARROWS_UPLEFT "\ueb5d" #define LINEA_ARROWS_UPRIGHT "\ueb5e" #define LINEA_ARROWS_VERTICAL "\ueb5f" #define LINEA_BASIC_LOCK_OPEN "\ueb60" #define LINEA_BASIC_MAGIC_MOUSE "\ueb61" #define LINEA_BASIC_MAGNIFIER "\ueb62" #define LINEA_BASIC_MAGNIFIER_MINUS "\ueb63" #define LINEA_BASIC_MAGNIFIER_PLUS "\ueb64" #define LINEA_BASIC_MAIL "\ueb65" #define LINEA_BASIC_MAIL_MULTIPLE "\ueb66" #define LINEA_BASIC_MAIL_OPEN "\ueb67" #define LINEA_BASIC_MAIL_OPEN_TEXT "\ueb68" #define LINEA_BASIC_MALE "\ueb69" #define LINEA_BASIC_MAP "\ueb6a" #define LINEA_BASIC_MESSAGE "\ueb6b" #define LINEA_BASIC_MESSAGE_MULTIPLE "\ueb6c" #define LINEA_BASIC_MESSAGE_TXT "\ueb6d" #define LINEA_BASIC_MIXER2 "\ueb6e" #define LINEA_BASIC_INFO "\ueb6f" #define LINEA_BASIC_IPOD "\ueb70" #define LINEA_BASIC_JOYPAD "\ueb71" #define LINEA_BASIC_KEY "\ueb72" #define LINEA_BASIC_KEYBOARD "\ueb73" #define LINEA_BASIC_LAPTOP "\ueb74" #define LINEA_BASIC_LIFE_BUOY "\ueb75" #define LINEA_BASIC_LIGHTBULB "\ueb76" #define LINEA_BASIC_LINK "\ueb77" #define LINEA_BASIC_LOCK "\ueb78" #define LINEA_BASIC_MOUSE "\ueb79" #define LINEA_BASIC_NOTEBOOK "\ueb7a" #define LINEA_BASIC_NOTEBOOK_PEN "\ueb7b" #define LINEA_BASIC_NOTEBOOK_PENCIL "\ueb7c" #define LINEA_BASIC_PAPERPLANE "\ueb7d" #define LINEA_BASIC_PENCIL_RULER "\ueb7e" #define LINEA_BASIC_PENCIL_RULER_PEN "\ueb7f" #define LINEA_BASIC_CLUBS "\ueb80" #define LINEA_BASIC_COMPASS "\ueb81" #define LINEA_BASIC_CUP "\ueb82" #define LINEA_BASIC_DIAMONDS "\ueb83" #define LINEA_BASIC_DISPLAY "\ueb84" #define LINEA_BASIC_DOWNLOAD "\ueb85" #define LINEA_BASIC_EXCLAMATION "\ueb86" #define LINEA_BASIC_EYE "\ueb87" #define LINEA_BASIC_EYE_CLOSED "\ueb88" #define LINEA_BASIC_FEMALE "\ueb89" #define LINEA_BASIC_FLAG1 "\ueb8a" #define LINEA_BASIC_FLAG2 "\ueb8b" #define LINEA_BASIC_FLOPPYDISK "\ueb8c" #define LINEA_BASIC_FOLDER "\ueb8d" #define LINEA_BASIC_FOLDER_MULTIPLE "\ueb8e" #define LINEA_BASIC_GEAR "\ueb8f" #define LINEA_BASIC_GEOLOCALIZE_01 "\ueb90" #define LINEA_BASIC_GEOLOCALIZE_05 "\ueb91" #define LINEA_BASIC_GLOBE "\ueb92" #define LINEA_BASIC_GUNSIGHT "\ueb93" #define LINEA_BASIC_HAMMER "\ueb94" #define LINEA_BASIC_HEADSET "\ueb95" #define LINEA_BASIC_HEART "\ueb96" #define LINEA_BASIC_HEART_BROKEN "\ueb97" #define LINEA_BASIC_HELM "\ueb98" #define LINEA_BASIC_HOME "\ueb99" #define LINEA_BASIC_PHOTO "\ueb9a" #define LINEA_BASIC_RSS "\ueb9b" #define LINEA_BASIC_PICTURE "\ueb9c" #define LINEA_BASIC_PICTURE_MULTIPLE "\ueb9d" #define LINEA_BASIC_PIN1 "\ueb9e" #define LINEA_BASIC_PIN2 "\ueb9f" #define LINEA_BASIC_ACCELERATOR "\ueba0" #define LINEA_BASIC_ALARM "\ueba1" #define LINEA_BASIC_ANCHOR "\ueba2" #define LINEA_BASIC_ANTICLOCKWISE "\ueba3" #define LINEA_BASIC_ARCHIVE "\ueba4" #define LINEA_BASIC_ARCHIVE_FULL "\ueba5" #define LINEA_BASIC_BAN "\ueba6" #define LINEA_BASIC_BATTERY_CHARGE "\ueba7" #define LINEA_BASIC_BATTERY_EMPTY "\ueba8" #define LINEA_BASIC_BATTERY_FULL "\ueba9" #define LINEA_BASIC_BATTERY_HALF "\uebaa" #define LINEA_BASIC_BOLT "\uebab" #define LINEA_BASIC_BOOK "\uebac" #define LINEA_BASIC_BOOK_PEN "\uebad" #define LINEA_BASIC_BOOK_PENCIL "\uebae" #define LINEA_BASIC_BOOKMARK "\uebaf" #define LINEA_BASIC_CALCULATOR "\uebb0" #define LINEA_BASIC_CALENDAR "\uebb1" #define LINEA_BASIC_CARDS_DIAMONDS "\uebb2" #define LINEA_BASIC_CARDS_HEARTS "\uebb3" #define LINEA_BASIC_CASE "\uebb4" #define LINEA_BASIC_CHRONOMETER "\uebb5" #define LINEA_BASIC_CLESSIDRE "\uebb6" #define LINEA_BASIC_CLOCK "\uebb7" #define LINEA_BASIC_CLOCKWISE "\uebb8" #define LINEA_BASIC_CLOUD "\uebb9" #define LINEA_BASIC_POSTCARD "\uebba" #define LINEA_BASIC_POSTCARD_MULTIPLE "\uebbb" #define LINEA_BASIC_PRINTER "\uebbc" #define LINEA_BASIC_QUESTION "\uebbd" #define LINEA_BASIC_SERVER "\uebbe" #define LINEA_BASIC_SERVER2 "\uebbf" #define LINEA_BASIC_SERVER_CLOUD "\uebc0" #define LINEA_BASIC_SERVER_DOWNLOAD "\uebc1" #define LINEA_BASIC_SERVER_UPLOAD "\uebc2" #define LINEA_BASIC_SETTINGS "\uebc3" #define LINEA_BASIC_SHARE "\uebc4" #define LINEA_BASIC_SHEET "\uebc5" #define LINEA_BASIC_SHEET_MULTIPLE "\uebc6" #define LINEA_BASIC_SHEET_PEN "\uebc7" #define LINEA_BASIC_SHEET_PENCIL "\uebc8" #define LINEA_BASIC_SHEET_TXT "\uebc9" #define LINEA_BASIC_SIGNS "\uebca" #define LINEA_BASIC_SMARTPHONE "\uebcb" #define LINEA_BASIC_SPADES "\uebcc" #define LINEA_BASIC_SPREAD "\uebcd" #define LINEA_BASIC_SPREAD_BOOKMARK "\uebce" #define LINEA_BASIC_SPREAD_TEXT "\uebcf" #define LINEA_BASIC_SPREAD_TEXT_BOOKMARK "\uebd0" #define LINEA_BASIC_STAR "\uebd1" #define LINEA_BASIC_TABLET "\uebd2" #define LINEA_BASIC_TARGET "\uebd3" #define LINEA_BASIC_TODO "\uebd4" #define LINEA_BASIC_TODO_PEN "\uebd5" #define LINEA_BASIC_TODO_PENCIL "\uebd6" #define LINEA_BASIC_TODO_TXT "\uebd7" #define LINEA_BASIC_TODOLIST_PEN "\uebd8" #define LINEA_BASIC_TODOLIST_PENCIL "\uebd9" #define LINEA_BASIC_TRASHCAN "\uebda" #define LINEA_BASIC_TRASHCAN_FULL "\uebdb" #define LINEA_BASIC_TRASHCAN_REFRESH "\uebdc" #define LINEA_BASIC_TRASHCAN_REMOVE "\uebdd" #define LINEA_BASIC_UPLOAD "\uebde" #define LINEA_BASIC_USB "\uebdf" #define LINEA_BASIC_VIDEO "\uebe0" #define LINEA_BASIC_WATCH "\uebe1" #define LINEA_BASIC_WEBPAGE "\uebe2" #define LINEA_BASIC_WEBPAGE_IMG_TXT "\uebe3" #define LINEA_BASIC_WEBPAGE_MULTIPLE "\uebe4" #define LINEA_BASIC_WEBPAGE_TXT "\uebe5" #define LINEA_BASIC_WORLD "\uebe6" #define LINEA_ELABORATION_DOCUMENT_PREVIOUS "\uebe7" #define LINEA_ELABORATION_DOCUMENT_REFRESH "\uebe8" #define LINEA_ELABORATION_DOCUMENT_REMOVE "\uebe9" #define LINEA_ELABORATION_DOCUMENT_SEARCH "\uebea" #define LINEA_ELABORATION_DOCUMENT_STAR "\uebeb" #define LINEA_ELABORATION_DOCUMENT_UPLOAD "\uebec" #define LINEA_ELABORATION_FOLDER_CHECK "\uebed" #define LINEA_ELABORATION_FOLDER_CLOUD "\uebee" #define LINEA_ELABORATION_FOLDER_DOCUMENT "\uebef" #define LINEA_ELABORATION_FOLDER_DOWNLOAD "\uebf0" #define LINEA_ELABORATION_FOLDER_FLAGGED "\uebf1" #define LINEA_ELABORATION_FOLDER_GRAPH "\uebf2" #define LINEA_ELABORATION_FOLDER_HEART "\uebf3" #define LINEA_ELABORATION_FOLDER_MINUS "\uebf4" #define LINEA_ELABORATION_FOLDER_NEXT "\uebf5" #define LINEA_ELABORATION_DOCUMENT_FLAGGED "\uebf6" #define LINEA_ELABORATION_DOCUMENT_GRAPH "\uebf7" #define LINEA_ELABORATION_DOCUMENT_HEART "\uebf8" #define LINEA_ELABORATION_DOCUMENT_MINUS "\uebf9" #define LINEA_ELABORATION_DOCUMENT_NEXT "\uebfa" #define LINEA_ELABORATION_DOCUMENT_NOACCESS "\uebfb" #define LINEA_ELABORATION_DOCUMENT_NOTE "\uebfc" #define LINEA_ELABORATION_DOCUMENT_PENCIL "\uebfd" #define LINEA_ELABORATION_DOCUMENT_PICTURE "\uebfe" #define LINEA_ELABORATION_DOCUMENT_PLUS "\uebff" #define LINEA_ELABORATION_FOLDER_NOACCESS "\uec00" #define LINEA_ELABORATION_FOLDER_NOTE "\uec01" #define LINEA_ELABORATION_FOLDER_PENCIL "\uec02" #define LINEA_ELABORATION_FOLDER_PICTURE "\uec03" #define LINEA_ELABORATION_FOLDER_PLUS "\uec04" #define LINEA_ELABORATION_FOLDER_PREVIOUS "\uec05" #define LINEA_ELABORATION_FOLDER_REFRESH "\uec06" #define LINEA_ELABORATION_CALENDAR_EMPTY "\uec07" #define LINEA_ELABORATION_CALENDAR_FLAGGED "\uec08" #define LINEA_ELABORATION_CALENDAR_HEART "\uec09" #define LINEA_ELABORATION_CALENDAR_MINUS "\uec0a" #define LINEA_ELABORATION_CALENDAR_NEXT "\uec0b" #define LINEA_ELABORATION_CALENDAR_NOACCESS "\uec0c" #define LINEA_ELABORATION_CALENDAR_PENCIL "\uec0d" #define LINEA_ELABORATION_CALENDAR_PLUS "\uec0e" #define LINEA_ELABORATION_CALENDAR_PREVIOUS "\uec0f" #define LINEA_ELABORATION_CALENDAR_REFRESH "\uec10" #define LINEA_ELABORATION_CALENDAR_REMOVE "\uec11" #define LINEA_ELABORATION_CALENDAR_SEARCH "\uec12" #define LINEA_ELABORATION_CALENDAR_STAR "\uec13" #define LINEA_ELABORATION_CALENDAR_UPLOAD "\uec14" #define LINEA_ELABORATION_CLOUD_CHECK "\uec15" #define LINEA_ELABORATION_CLOUD_DOWNLOAD "\uec16" #define LINEA_ELABORATION_CLOUD_MINUS "\uec17" #define LINEA_ELABORATION_CLOUD_NOACCESS "\uec18" #define LINEA_ELABORATION_CLOUD_PLUS "\uec19" #define LINEA_ELABORATION_CLOUD_REFRESH "\uec1a" #define LINEA_ELABORATION_CLOUD_REMOVE "\uec1b" #define LINEA_ELABORATION_CLOUD_SEARCH "\uec1c" #define LINEA_ELABORATION_CLOUD_UPLOAD "\uec1d" #define LINEA_ELABORATION_DOCUMENT_CHECK "\uec1e" #define LINEA_ELABORATION_DOCUMENT_CLOUD "\uec1f" #define LINEA_ELABORATION_DOCUMENT_DOWNLOAD "\uec20" #define LINEA_ELABORATION_FOLDER_REMOVE "\uec21" #define LINEA_ELABORATION_MAIL_HEART "\uec22" #define LINEA_ELABORATION_FOLDER_SEARCH "\uec23" #define LINEA_ELABORATION_FOLDER_STAR "\uec24" #define LINEA_ELABORATION_FOLDER_UPLOAD "\uec25" #define LINEA_ELABORATION_MAIL_CHECK "\uec26" #define LINEA_ELABORATION_BOOKMARK_CHECCK "\uec27" #define LINEA_ELABORATION_BOOKMARK_MINUS "\uec28" #define LINEA_ELABORATION_BOOKMARK_PLUS "\uec29" #define LINEA_ELABORATION_BOOKMARK_REMOVE "\uec2a" #define LINEA_ELABORATION_BRIEFCASE_CHECK "\uec2b" #define LINEA_ELABORATION_BRIEFCASE_DOWNLOAD "\uec2c" #define LINEA_ELABORATION_BRIEFCASE_FLAGGED "\uec2d" #define LINEA_ELABORATION_BRIEFCASE_MINUS "\uec2e" #define LINEA_ELABORATION_BRIEFCASE_PLUS "\uec2f" #define LINEA_ELABORATION_BRIEFCASE_REFRESH "\uec30" #define LINEA_ELABORATION_BRIEFCASE_REMOVE "\uec31" #define LINEA_ELABORATION_BRIEFCASE_SEARCH "\uec32" #define LINEA_ELABORATION_BRIEFCASE_STAR "\uec33" #define LINEA_ELABORATION_BRIEFCASE_UPLOAD "\uec34" #define LINEA_ELABORATION_BROWSER_CHECK "\uec35" #define LINEA_ELABORATION_BROWSER_DOWNLOAD "\uec36" #define LINEA_ELABORATION_BROWSER_MINUS "\uec37" #define LINEA_ELABORATION_BROWSER_PLUS "\uec38" #define LINEA_ELABORATION_BROWSER_REFRESH "\uec39" #define LINEA_ELABORATION_BROWSER_REMOVE "\uec3a" #define LINEA_ELABORATION_BROWSER_SEARCH "\uec3b" #define LINEA_ELABORATION_BROWSER_STAR "\uec3c" #define LINEA_ELABORATION_BROWSER_UPLOAD "\uec3d" #define LINEA_ELABORATION_CALENDAR_CHECK "\uec3e" #define LINEA_ELABORATION_CALENDAR_CLOUD "\uec3f" #define LINEA_ELABORATION_CALENDAR_DOWNLOAD "\uec40" #define LINEA_ELABORATION_MAIL_CLOUD "\uec41" #define LINEA_ELABORATION_MAIL_DOCUMENT "\uec42" #define LINEA_ELABORATION_MAIL_DOWNLOAD "\uec43" #define LINEA_ELABORATION_MAIL_FLAGGED "\uec44" #define LINEA_ELABORATION_MAIL_NEXT "\uec45" #define LINEA_ELABORATION_MAIL_NOACCESS "\uec46" #define LINEA_ELABORATION_MAIL_NOTE "\uec47" #define LINEA_ELABORATION_MAIL_PENCIL "\uec48" #define LINEA_ELABORATION_MAIL_PICTURE "\uec49" #define LINEA_ELABORATION_MAIL_PREVIOUS "\uec4a" #define LINEA_ELABORATION_MAIL_REFRESH "\uec4b" #define LINEA_ELABORATION_MAIL_REMOVE "\uec4c" #define LINEA_ELABORATION_MAIL_SEARCH "\uec4d" #define LINEA_ELABORATION_MAIL_STAR "\uec4e" #define LINEA_ELABORATION_MAIL_UPLOAD "\uec4f" #define LINEA_ELABORATION_MESSAGE_CHECK "\uec50" #define LINEA_ELABORATION_MESSAGE_DOTS "\uec51" #define LINEA_ELABORATION_MESSAGE_HAPPY "\uec52" #define LINEA_ELABORATION_MESSAGE_HEART "\uec53" #define LINEA_ELABORATION_MESSAGE_MINUS "\uec54" #define LINEA_ELABORATION_MESSAGE_NOTE "\uec55" #define LINEA_ELABORATION_MESSAGE_PLUS "\uec56" #define LINEA_ELABORATION_MESSAGE_REFRESH "\uec57" #define LINEA_ELABORATION_MESSAGE_REMOVE "\uec58" #define LINEA_ELABORATION_MESSAGE_SAD "\uec59" #define LINEA_ELABORATION_SMARTPHONE_CLOUD "\uec5a" #define LINEA_ELABORATION_SMARTPHONE_HEART "\uec5b" #define LINEA_ELABORATION_SMARTPHONE_NOACCESS "\uec5c" #define LINEA_ELABORATION_SMARTPHONE_NOTE "\uec5d" #define LINEA_ELABORATION_SMARTPHONE_PENCIL "\uec5e" #define LINEA_ELABORATION_SMARTPHONE_PICTURE "\uec5f" #define LINEA_ELABORATION_SMARTPHONE_REFRESH "\uec60" #define LINEA_ELABORATION_SMARTPHONE_SEARCH "\uec61" #define LINEA_ELABORATION_TABLET_CLOUD "\uec62" #define LINEA_ELABORATION_TABLET_HEART "\uec63" #define LINEA_ELABORATION_TABLET_NOACCESS "\uec64" #define LINEA_ELABORATION_TABLET_NOTE "\uec65" #define LINEA_ELABORATION_TABLET_PENCIL "\uec66" #define LINEA_ELABORATION_TABLET_PICTURE "\uec67" #define LINEA_ELABORATION_TABLET_REFRESH "\uec68" #define LINEA_ELABORATION_TABLET_SEARCH "\uec69" #define LINEA_ELABORATION_TODOLIST_2 "\uec6a" #define LINEA_ELABORATION_TODOLIST_CHECK "\uec6b" #define LINEA_ELABORATION_TODOLIST_CLOUD "\uec6c" #define LINEA_ELABORATION_TODOLIST_DOWNLOAD "\uec6d" #define LINEA_ELABORATION_TODOLIST_FLAGGED "\uec6e" #define LINEA_ELABORATION_TODOLIST_MINUS "\uec6f" #define LINEA_ELABORATION_TODOLIST_NOACCESS "\uec70" #define LINEA_ELABORATION_TODOLIST_PENCIL "\uec71" #define LINEA_ELABORATION_TODOLIST_PLUS "\uec72" #define LINEA_ELABORATION_TODOLIST_REFRESH "\uec73" #define LINEA_ELABORATION_TODOLIST_REMOVE "\uec74" #define LINEA_ELABORATION_TODOLIST_SEARCH "\uec75" #define LINEA_ELABORATION_TODOLIST_STAR "\uec76" #define LINEA_ELABORATION_TODOLIST_UPLOAD "\uec77" #define LINEA_ECOMMERCE_RECEIPT_KIPS "\uec78" #define LINEA_ECOMMERCE_RECEIPT_LIRA "\uec79" #define LINEA_ECOMMERCE_RECEIPT_NAIRA "\uec7a" #define LINEA_ECOMMERCE_RECEIPT_PESOS "\uec7b" #define LINEA_ECOMMERCE_RECEIPT_POUND "\uec7c" #define LINEA_ECOMMERCE_RECEIPT_RUBLO "\uec7d" #define LINEA_ECOMMERCE_RECEIPT_RUPEE "\uec7e" #define LINEA_ECOMMERCE_RECEIPT_TUGRIK "\uec7f" #define LINEA_ECOMMERCE_RECEIPT_WON "\uec80" #define LINEA_ECOMMERCE_RECEIPT_YEN "\uec81" #define LINEA_ECOMMERCE_RECEIPT_YEN2 "\uec82" #define LINEA_ECOMMERCE_RECEPT_COLON "\uec83" #define LINEA_ECOMMERCE_RUBLO "\uec84" #define LINEA_ECOMMERCE_RUPEE "\uec85" #define LINEA_ECOMMERCE_SAFE "\uec86" #define LINEA_ECOMMERCE_NAIRA "\uec87" #define LINEA_ECOMMERCE_PESOS "\uec88" #define LINEA_ECOMMERCE_POUND "\uec89" #define LINEA_ECOMMERCE_RECEIPT "\uec8a" #define LINEA_ECOMMERCE_RECEIPT_BATH "\uec8b" #define LINEA_ECOMMERCE_RECEIPT_CENT "\uec8c" #define LINEA_ECOMMERCE_RECEIPT_DOLLAR "\uec8d" #define LINEA_ECOMMERCE_RECEIPT_EURO "\uec8e" #define LINEA_ECOMMERCE_RECEIPT_FRANC "\uec8f" #define LINEA_ECOMMERCE_RECEIPT_GUARANI "\uec90" #define LINEA_ECOMMERCE_SALE "\uec91" #define LINEA_ECOMMERCE_SALES "\uec92" #define LINEA_ECOMMERCE_TICKET "\uec93" #define LINEA_ECOMMERCE_TUGRIKS "\uec94" #define LINEA_ECOMMERCE_WALLET "\uec95" #define LINEA_ECOMMERCE_WON "\uec96" #define LINEA_ECOMMERCE_YEN "\uec97" #define LINEA_ECOMMERCE_CART_CONTENT "\uec98" #define LINEA_ECOMMERCE_CART_DOWNLOAD "\uec99" #define LINEA_ECOMMERCE_CART_MINUS "\uec9a" #define LINEA_ECOMMERCE_CART_PLUS "\uec9b" #define LINEA_ECOMMERCE_CART_REFRESH "\uec9c" #define LINEA_ECOMMERCE_CART_REMOVE "\uec9d" #define LINEA_ECOMMERCE_CART_SEARCH "\uec9e" #define LINEA_ECOMMERCE_CART_UPLOAD "\uec9f" #define LINEA_ECOMMERCE_CENT "\ueca0" #define LINEA_ECOMMERCE_COLON "\ueca1" #define LINEA_ECOMMERCE_CREDITCARD "\ueca2" #define LINEA_ECOMMERCE_DIAMOND "\ueca3" #define LINEA_ECOMMERCE_DOLLAR "\ueca4" #define LINEA_ECOMMERCE_EURO "\ueca5" #define LINEA_ECOMMERCE_FRANC "\ueca6" #define LINEA_ECOMMERCE_GIFT "\ueca7" #define LINEA_ECOMMERCE_GRAPH1 "\ueca8" #define LINEA_ECOMMERCE_GRAPH2 "\ueca9" #define LINEA_ECOMMERCE_GRAPH3 "\uecaa" #define LINEA_ECOMMERCE_GRAPH_DECREASE "\uecab" #define LINEA_ECOMMERCE_GRAPH_INCREASE "\uecac" #define LINEA_ECOMMERCE_GUARANI "\uecad" #define LINEA_ECOMMERCE_KIPS "\uecae" #define LINEA_ECOMMERCE_LIRA "\uecaf" #define LINEA_ECOMMERCE_MEGAPHONE "\uecb0" #define LINEA_ECOMMERCE_MONEY "\uecb1" #define LINEA_ECOMMERCE_YEN2 "\uecb2" #define LINEA_ECOMMERCE_BAG "\uecb3" #define LINEA_ECOMMERCE_BAG_CHECK "\uecb4" #define LINEA_ECOMMERCE_BAG_CLOUD "\uecb5" #define LINEA_ECOMMERCE_BAG_DOWNLOAD "\uecb6" #define LINEA_ECOMMERCE_BAG_MINUS "\uecb7" #define LINEA_ECOMMERCE_BAG_PLUS "\uecb8" #define LINEA_ECOMMERCE_BAG_REFRESH "\uecb9" #define LINEA_ECOMMERCE_BAG_REMOVE "\uecba" #define LINEA_ECOMMERCE_BAG_SEARCH "\uecbb" #define LINEA_ECOMMERCE_BAG_UPLOAD "\uecbc" #define LINEA_ECOMMERCE_BANKNOTE "\uecbd" #define LINEA_ECOMMERCE_BANKNOTES "\uecbe" #define LINEA_ECOMMERCE_BASKET "\uecbf" #define LINEA_ECOMMERCE_BASKET_CHECK "\uecc0" #define LINEA_ECOMMERCE_BASKET_CLOUD "\uecc1" #define LINEA_ECOMMERCE_BASKET_DOWNLOAD "\uecc2" #define LINEA_ECOMMERCE_BASKET_MINUS "\uecc3" #define LINEA_ECOMMERCE_BASKET_PLUS "\uecc4" #define LINEA_ECOMMERCE_BASKET_REFRESH "\uecc5" #define LINEA_ECOMMERCE_BASKET_REMOVE "\uecc6" #define LINEA_ECOMMERCE_BASKET_SEARCH "\uecc7" #define LINEA_ECOMMERCE_BASKET_UPLOAD "\uecc8" #define LINEA_ECOMMERCE_BATH "\uecc9" #define LINEA_ECOMMERCE_CART "\uecca" #define LINEA_ECOMMERCE_CART_CHECK "\ueccb" #define LINEA_ECOMMERCE_CART_CLOUD "\ueccc" #define LINEA_MUSIC_STOP_BUTTON "\ueccd" #define LINEA_MUSIC_TAPE "\uecce" #define LINEA_MUSIC_VOLUME_DOWN "\ueccf" #define LINEA_MUSIC_VOLUME_UP "\uecd0" #define LINEA_MUSIC_BEGINNING_BUTTON "\uecd1" #define LINEA_MUSIC_BELL "\uecd2" #define LINEA_MUSIC_CD "\uecd3" #define LINEA_MUSIC_DIAPASON "\uecd4" #define LINEA_MUSIC_EJECT_BUTTON "\uecd5" #define LINEA_MUSIC_END_BUTTON "\uecd6" #define LINEA_MUSIC_FASTFORWARD_BUTTON "\uecd7" #define LINEA_MUSIC_HEADPHONES "\uecd8" #define LINEA_MUSIC_IPOD "\uecd9" #define LINEA_MUSIC_LOUDSPEAKER "\uecda" #define LINEA_MUSIC_MICROPHONE "\uecdb" #define LINEA_MUSIC_MICROPHONE_OLD "\uecdc" #define LINEA_MUSIC_MIXER "\uecdd" #define LINEA_MUSIC_MUTE "\uecde" #define LINEA_MUSIC_NOTE_MULTIPLE "\uecdf" #define LINEA_MUSIC_NOTE_SINGLE "\uece0" #define LINEA_MUSIC_PAUSE_BUTTON "\uece1" #define LINEA_MUSIC_PLAY_BUTTON "\uece2" #define LINEA_MUSIC_PLAYLIST "\uece3" #define LINEA_MUSIC_RADIO_GHETTOBLASTER "\uece4" #define LINEA_MUSIC_RADIO_PORTABLE "\uece5" #define LINEA_MUSIC_RECORD "\uece6" #define LINEA_MUSIC_RECORDPLAYER "\uece7" #define LINEA_MUSIC_REPEAT_BUTTON "\uece8" #define LINEA_MUSIC_REWIND_BUTTON "\uece9" #define LINEA_MUSIC_SHUFFLE_BUTTON "\uecea" #define LINEA_SOFTWARE_PARAGRAPH_JUSTIFY_CENTER "\ueceb" #define LINEA_SOFTWARE_PARAGRAPH_JUSTIFY_LEFT "\uecec" #define LINEA_SOFTWARE_PARAGRAPH_JUSTIFY_RIGHT "\ueced" #define LINEA_SOFTWARE_PARAGRAPH_SPACE_AFTER "\uecee" #define LINEA_SOFTWARE_PARAGRAPH_SPACE_BEFORE "\uecef" #define LINEA_SOFTWARE_PATHFINDER_EXCLUDE "\uecf0" #define LINEA_SOFTWARE_PATHFINDER_INTERSECT "\uecf1" #define LINEA_SOFTWARE_PATHFINDER_SUBTRACT "\uecf2" #define LINEA_SOFTWARE_PATHFINDER_UNITE "\uecf3" #define LINEA_SOFTWARE_PEN "\uecf4" #define LINEA_SOFTWARE_PEN_ADD "\uecf5" #define LINEA_SOFTWARE_PEN_REMOVE "\uecf6" #define LINEA_SOFTWARE_PENCIL "\uecf7" #define LINEA_SOFTWARE_POLYGONALLASSO "\uecf8" #define LINEA_SOFTWARE_REFLECT_HORIZONTAL "\uecf9" #define LINEA_SOFTWARE_MAGNETE "\uecfa" #define LINEA_SOFTWARE_PAGES "\uecfb" #define LINEA_SOFTWARE_PAINTBRUSH "\uecfc" #define LINEA_SOFTWARE_PAINTBUCKET "\uecfd" #define LINEA_SOFTWARE_PAINTROLLER "\uecfe" #define LINEA_SOFTWARE_PARAGRAPH "\uecff" #define LINEA_SOFTWARE_PARAGRAPH_ALIGN_LEFT "\ued00" #define LINEA_SOFTWARE_PARAGRAPH_ALIGN_RIGHT "\ued01" #define LINEA_SOFTWARE_PARAGRAPH_CENTER "\ued02" #define LINEA_SOFTWARE_PARAGRAPH_JUSTIFY_ALL "\ued03" #define LINEA_SOFTWARE_REFLECT_VERTICAL "\ued04" #define LINEA_SOFTWARE_REMOVE_VECTORPOINT "\ued05" #define LINEA_SOFTWARE_SCALE_EXPAND "\ued06" #define LINEA_SOFTWARE_SCALE_REDUCE "\ued07" #define LINEA_SOFTWARE_SELECTION_OVAL "\ued08" #define LINEA_SOFTWARE_SELECTION_POLYGON "\ued09" #define LINEA_SOFTWARE_SELECTION_RECTANGLE "\ued0a" #define LINEA_SOFTWARE_INDENT_FIRSTLINE "\ued0b" #define LINEA_SOFTWARE_INDENT_LEFT "\ued0c" #define LINEA_SOFTWARE_INDENT_RIGHT "\ued0d" #define LINEA_SOFTWARE_LASSO "\ued0e" #define LINEA_SOFTWARE_LAYERS1 "\ued0f" #define LINEA_SOFTWARE_LAYERS2 "\ued10" #define LINEA_SOFTWARE_LAYOUT "\ued11" #define LINEA_SOFTWARE_LAYOUT_2COLUMNS "\ued12" #define LINEA_SOFTWARE_LAYOUT_3COLUMNS "\ued13" #define LINEA_SOFTWARE_LAYOUT_4BOXES "\ued14" #define LINEA_SOFTWARE_LAYOUT_4COLUMNS "\ued15" #define LINEA_SOFTWARE_LAYOUT_4LINES "\ued16" #define LINEA_SOFTWARE_LAYOUT_8BOXES "\ued17" #define LINEA_SOFTWARE_LAYOUT_HEADER "\ued18" #define LINEA_SOFTWARE_LAYOUT_HEADER_2COLUMNS "\ued19" #define LINEA_SOFTWARE_LAYOUT_HEADER_3COLUMNS "\ued1a" #define LINEA_SOFTWARE_LAYOUT_HEADER_4BOXES "\ued1b" #define LINEA_SOFTWARE_LAYOUT_HEADER_4COLUMNS "\ued1c" #define LINEA_SOFTWARE_LAYOUT_HEADER_COMPLEX "\ued1d" #define LINEA_SOFTWARE_LAYOUT_HEADER_COMPLEX2 "\ued1e" #define LINEA_SOFTWARE_LAYOUT_HEADER_COMPLEX3 "\ued1f" #define LINEA_SOFTWARE_LAYOUT_HEADER_COMPLEX4 "\ued20" #define LINEA_SOFTWARE_LAYOUT_HEADER_SIDELEFT "\ued21" #define LINEA_SOFTWARE_LAYOUT_HEADER_SIDERIGHT "\ued22" #define LINEA_SOFTWARE_LAYOUT_SIDEBAR_LEFT "\ued23" #define LINEA_SOFTWARE_LAYOUT_SIDEBAR_RIGHT "\ued24" #define LINEA_SOFTWARE_SELECTION_ROUNDEDRECTANGLE "\ued25" #define LINEA_SOFTWARE_VECTOR_LINE "\ued26" #define LINEA_SOFTWARE_SHAPE_OVAL "\ued27" #define LINEA_SOFTWARE_SHAPE_POLYGON "\ued28" #define LINEA_SOFTWARE_SHAPE_RECTANGLE "\ued29" #define LINEA_SOFTWARE_SHAPE_ROUNDEDRECTANGLE "\ued2a" #define LINEA_SOFTWARE_ADD_VECTORPOINT "\ued2b" #define LINEA_SOFTWARE_BOX_OVAL "\ued2c" #define LINEA_SOFTWARE_BOX_POLYGON "\ued2d" #define LINEA_SOFTWARE_BOX_RECTANGLE "\ued2e" #define LINEA_SOFTWARE_BOX_ROUNDEDRECTANGLE "\ued2f" #define LINEA_SOFTWARE_CHARACTER "\ued30" #define LINEA_SOFTWARE_CROP "\ued31" #define LINEA_SOFTWARE_EYEDROPPER "\ued32" #define LINEA_SOFTWARE_FONT_ALLCAPS "\ued33" #define LINEA_SOFTWARE_FONT_BASELINE_SHIFT "\ued34" #define LINEA_SOFTWARE_FONT_HORIZONTAL_SCALE "\ued35" #define LINEA_SOFTWARE_FONT_KERNING "\ued36" #define LINEA_SOFTWARE_FONT_LEADING "\ued37" #define LINEA_SOFTWARE_FONT_SIZE "\ued38" #define LINEA_SOFTWARE_FONT_SMALLCAPITAL "\ued39" #define LINEA_SOFTWARE_FONT_SMALLCAPS "\ued3a" #define LINEA_SOFTWARE_FONT_STRIKETHROUGH "\ued3b" #define LINEA_SOFTWARE_FONT_TRACKING "\ued3c" #define LINEA_SOFTWARE_FONT_UNDERLINE "\ued3d" #define LINEA_SOFTWARE_FONT_VERTICAL_SCALE "\ued3e" #define LINEA_SOFTWARE_HORIZONTAL_ALIGN_CENTER "\ued3f" #define LINEA_SOFTWARE_HORIZONTAL_ALIGN_LEFT "\ued40" #define LINEA_SOFTWARE_HORIZONTAL_ALIGN_RIGHT "\ued41" #define LINEA_SOFTWARE_HORIZONTAL_DISTRIBUTE_CENTER "\ued42" #define LINEA_SOFTWARE_HORIZONTAL_DISTRIBUTE_LEFT "\ued43" #define LINEA_SOFTWARE_HORIZONTAL_DISTRIBUTE_RIGHT "\ued44" #define LINEA_SOFTWARE_SLICE "\ued45" #define LINEA_SOFTWARE_TRANSFORM_BEZIER "\ued46" #define LINEA_SOFTWARE_VECTOR_BOX "\ued47" #define LINEA_SOFTWARE_VECTOR_COMPOSITE "\ued48" #define LINEA_SOFTWARE_VERTICAL_ALIGN_BOTTOM "\ued49" #define LINEA_SOFTWARE_VERTICAL_ALIGN_CENTER "\ued4a" #define LINEA_SOFTWARE_VERTICAL_ALIGN_TOP "\ued4b" #define LINEA_SOFTWARE_VERTICAL_DISTRIBUTE_BOTTOM "\ued4c" #define LINEA_SOFTWARE_VERTICAL_DISTRIBUTE_CENTER "\ued4d" #define LINEA_SOFTWARE_VERTICAL_DISTRIBUTE_TOP "\ued4e" #define LINEA_WEATHER_AQUARIUS "\ued4f" #define LINEA_WEATHER_ARIES "\ued50" #define LINEA_WEATHER_CANCER "\ued51" #define LINEA_WEATHER_CAPRICORN "\ued52" #define LINEA_WEATHER_CLOUD "\ued53" #define LINEA_WEATHER_CLOUD_DROP "\ued54" #define LINEA_WEATHER_CLOUD_LIGHTNING "\ued55" #define LINEA_WEATHER_CLOUD_SNOWFLAKE "\ued56" #define LINEA_WEATHER_DOWNPOUR_FULLMOON "\ued57" #define LINEA_WEATHER_DOWNPOUR_HALFMOON "\ued58" #define LINEA_WEATHER_DOWNPOUR_SUN "\ued59" #define LINEA_WEATHER_DROP "\ued5a" #define LINEA_WEATHER_FIRST_QUARTER "\ued5b" #define LINEA_WEATHER_FOG "\ued5c" #define LINEA_WEATHER_FOG_FULLMOON "\ued5d" #define LINEA_WEATHER_FOG_HALFMOON "\ued5e" #define LINEA_WEATHER_FOG_SUN "\ued5f" #define LINEA_WEATHER_FULLMOON "\ued60" #define LINEA_WEATHER_GEMINI "\ued61" #define LINEA_WEATHER_HAIL "\ued62" #define LINEA_WEATHER_HAIL_FULLMOON "\ued63" #define LINEA_WEATHER_HAIL_HALFMOON "\ued64" #define LINEA_WEATHER_HAIL_SUN "\ued65" #define LINEA_WEATHER_LAST_QUARTER "\ued66" #define LINEA_WEATHER_LEO "\ued67" #define LINEA_WEATHER_LIBRA "\ued68" #define LINEA_WEATHER_LIGHTNING "\ued69" #define LINEA_WEATHER_MISTYRAIN "\ued6a" #define LINEA_WEATHER_MISTYRAIN_FULLMOON "\ued6b" #define LINEA_WEATHER_MISTYRAIN_HALFMOON "\ued6c" #define LINEA_WEATHER_MISTYRAIN_SUN "\ued6d" #define LINEA_WEATHER_MOON "\ued6e" #define LINEA_WEATHER_MOONDOWN_FULL "\ued6f" #define LINEA_WEATHER_MOONDOWN_HALF "\ued70" #define LINEA_WEATHER_MOONSET_FULL "\ued71" #define LINEA_WEATHER_MOONSET_HALF "\ued72" #define LINEA_WEATHER_MOVE2 "\ued73" #define LINEA_WEATHER_NEWMOON "\ued74" #define LINEA_WEATHER_PISCES "\ued75" #define LINEA_WEATHER_RAIN "\ued76" #define LINEA_WEATHER_RAIN_FULLMOON "\ued77" #define LINEA_WEATHER_RAIN_HALFMOON "\ued78" #define LINEA_WEATHER_RAIN_SUN "\ued79" #define LINEA_WEATHER_SAGITTARIUS "\ued7a" #define LINEA_WEATHER_SCORPIO "\ued7b" #define LINEA_WEATHER_SNOW "\ued7c" #define LINEA_WEATHER_SNOW_FULLMOON "\ued7d" #define LINEA_WEATHER_SNOW_HALFMOON "\ued7e" #define LINEA_WEATHER_SNOW_SUN "\ued7f" #define LINEA_WEATHER_SNOWFLAKE "\ued80" #define LINEA_WEATHER_STAR "\ued81" #define LINEA_WEATHER_STORM_11 "\ued82" #define LINEA_WEATHER_STORM_32 "\ued83" #define LINEA_WEATHER_STORM_FULLMOON "\ued84" #define LINEA_WEATHER_STORM_HALFMOON "\ued85" #define LINEA_WEATHER_STORM_SUN "\ued86" #define LINEA_WEATHER_SUN "\ued87" #define LINEA_WEATHER_SUNDOWN "\ued88" #define LINEA_WEATHER_SUNSET "\ued89" #define LINEA_WEATHER_TAURUS "\ued8a" #define LINEA_WEATHER_TEMPEST "\ued8b" #define LINEA_WEATHER_TEMPEST_FULLMOON "\ued8c" #define LINEA_WEATHER_TEMPEST_HALFMOON "\ued8d" #define LINEA_WEATHER_TEMPEST_SUN "\ued8e" #define LINEA_WEATHER_VARIABLE_FULLMOON "\ued8f" #define LINEA_WEATHER_VARIABLE_HALFMOON "\ued90" #define LINEA_WEATHER_VARIABLE_SUN "\ued91" #define LINEA_WEATHER_VIRGO "\ued92" #define LINEA_WEATHER_WANING_CRESENT "\ued93" #define LINEA_WEATHER_WANING_GIBBOUS "\ued94" #define LINEA_WEATHER_WAXING_CRESENT "\ued95" #define LINEA_WEATHER_WAXING_GIBBOUS "\ued96" #define LINEA_WEATHER_WIND "\ued97" #define LINEA_WEATHER_WIND_E "\ued98" #define LINEA_WEATHER_WIND_FULLMOON "\ued99" #define LINEA_WEATHER_WIND_HALFMOON "\ued9a" #define LINEA_WEATHER_WIND_N "\ued9b" #define LINEA_WEATHER_WIND_NE "\ued9c" #define LINEA_WEATHER_WIND_NW "\ued9d" #define LINEA_WEATHER_WIND_S "\ued9e" #define LINEA_WEATHER_WIND_SE "\ued9f" #define LINEA_WEATHER_WIND_SUN "\ueda0" #define LINEA_WEATHER_WIND_SW "\ueda1" #define LINEA_WEATHER_WIND_W "\ueda2" #define LINEA_WEATHER_WINDGUST "\ueda3" #define MFIZZ_3DPRINT "\ueda4" #define MFIZZ_ALPINELINUX "\ueda5" #define MFIZZ_ANGULAR "\ueda6" #define MFIZZ_ANGULAR_ALT "\ueda7" #define MFIZZ_ANTENNA "\ueda8" #define MFIZZ_APACHE "\ueda9" #define MFIZZ_ARCHLINUX "\uedaa" #define MFIZZ_AWS "\uedab" #define MFIZZ_AZURE "\uedac" #define MFIZZ_BACKBONE "\uedad" #define MFIZZ_BLACKBERRY "\uedae" #define MFIZZ_BOMB "\uedaf" #define MFIZZ_BOOTSTRAP "\uedb0" #define MFIZZ_C "\uedb1" #define MFIZZ_CASSANDRA "\uedb2" #define MFIZZ_CENTOS "\uedb3" #define MFIZZ_CLOJURE "\uedb4" #define MFIZZ_CODEIGNITER "\uedb5" #define MFIZZ_CODEPEN "\uedb6" #define MFIZZ_COFFEE_BEAN "\uedb7" #define MFIZZ_CPLUSPLUS "\uedb8" #define MFIZZ_CSHARP "\uedb9" #define MFIZZ_CSS "\uedba" #define MFIZZ_CSS3 "\uedbb" #define MFIZZ_CSS3_ALT "\uedbc" #define MFIZZ_D3 "\uedbd" #define MFIZZ_DATABASE "\uedbe" #define MFIZZ_DATABASE_ALT "\uedbf" #define MFIZZ_DATABASE_ALT2 "\uedc0" #define MFIZZ_DEBIAN "\uedc1" #define MFIZZ_DOCKER "\uedc2" #define MFIZZ_DREAMHOST "\uedc3" #define MFIZZ_ELIXIR "\uedc4" #define MFIZZ_ELM "\uedc5" #define MFIZZ_ERLANG "\uedc6" #define MFIZZ_EXHERBO "\uedc7" #define MFIZZ_FEDORA "\uedc8" #define MFIZZ_FIRE_ALT "\uedc9" #define MFIZZ_FREEBSD "\uedca" #define MFIZZ_FREECODECAMP "\uedcb" #define MFIZZ_GENTOO "\uedcc" #define MFIZZ_GHOST "\uedcd" #define MFIZZ_GIT "\uedce" #define MFIZZ_GNOME "\uedcf" #define MFIZZ_GO "\uedd0" #define MFIZZ_GO_ALT "\uedd1" #define MFIZZ_GOOGLE "\uedd2" #define MFIZZ_GOOGLE_ALT "\uedd3" #define MFIZZ_GOOGLE_CODE "\uedd4" #define MFIZZ_GOOGLE_DEVELOPERS "\uedd5" #define MFIZZ_GRADLE "\uedd6" #define MFIZZ_GRAILS "\uedd7" #define MFIZZ_GRAILS_ALT "\uedd8" #define MFIZZ_GRUNT "\uedd9" #define MFIZZ_GULP "\uedda" #define MFIZZ_GULP_ALT "\ueddb" #define MFIZZ_HADOOP "\ueddc" #define MFIZZ_HASKELL "\ueddd" #define MFIZZ_HEROKU "\uedde" #define MFIZZ_HTML "\ueddf" #define MFIZZ_HTML5 "\uede0" #define MFIZZ_HTML5_ALT "\uede1" #define MFIZZ_IPHONE "\uede2" #define MFIZZ_JAVA "\uede3" #define MFIZZ_JAVA_BOLD "\uede4" #define MFIZZ_JAVA_DUKE "\uede5" #define MFIZZ_JAVASCRIPT "\uede6" #define MFIZZ_JAVASCRIPT_ALT "\uede7" #define MFIZZ_JETTY "\uede8" #define MFIZZ_JQUERY "\uede9" #define MFIZZ_KDE "\uedea" #define MFIZZ_LARAVEL "\uedeb" #define MFIZZ_LINE_GRAPH "\uedec" #define MFIZZ_LINUX_MINT "\ueded" #define MFIZZ_LOOKING "\uedee" #define MFIZZ_MAGENTO "\uedef" #define MFIZZ_MARIADB "\uedf0" #define MFIZZ_MAVEN "\uedf1" #define MFIZZ_MICROSCOPE "\uedf2" #define MFIZZ_MOBILE_DEVICE "\uedf3" #define MFIZZ_MOBILE_PHONE_ALT "\uedf4" #define MFIZZ_MOBILE_PHONE_BROADCAST "\uedf5" #define MFIZZ_MONGODB "\uedf6" #define MFIZZ_MSSQL "\uedf7" #define MFIZZ_MYSQL "\uedf8" #define MFIZZ_MYSQL_ALT "\uedf9" #define MFIZZ_NETBSD "\uedfa" #define MFIZZ_NGINX "\uedfb" #define MFIZZ_NGINX_ALT "\uedfc" #define MFIZZ_NGINX_ALT2 "\uedfd" #define MFIZZ_NODEJS "\uedfe" #define MFIZZ_NPM "\uedff" #define MFIZZ_OBJC "\uee00" #define MFIZZ_OPENSHIFT "\uee01" #define MFIZZ_ORACLE "\uee02" #define MFIZZ_ORACLE_ALT "\uee03" #define MFIZZ_OSX "\uee04" #define MFIZZ_PERL "\uee05" #define MFIZZ_PHONE_ALT "\uee06" #define MFIZZ_PHONE_GAP "\uee07" #define MFIZZ_PHONE_RETRO "\uee08" #define MFIZZ_PHP "\uee09" #define MFIZZ_PHP_ALT "\uee0a" #define MFIZZ_PLAYFRAMEWORK "\uee0b" #define MFIZZ_PLAYFRAMEWORK_ALT "\uee0c" #define MFIZZ_PLONE "\uee0d" #define MFIZZ_POSTGRES "\uee0e" #define MFIZZ_POSTGRES_ALT "\uee0f" #define MFIZZ_PYTHON "\uee10" #define MFIZZ_RASPBERRYPI "\uee11" #define MFIZZ_REACTJS "\uee12" #define MFIZZ_REDHAT "\uee13" #define MFIZZ_REDIS "\uee14" #define MFIZZ_RUBY "\uee15" #define MFIZZ_RUBY_ON_RAILS "\uee16" #define MFIZZ_RUBY_ON_RAILS_ALT "\uee17" #define MFIZZ_RUST "\uee18" #define MFIZZ_SASS "\uee19" #define MFIZZ_SATELLITE "\uee1a" #define MFIZZ_SCALA "\uee1b" #define MFIZZ_SCALA_ALT "\uee1c" #define MFIZZ_SCRIPT "\uee1d" #define MFIZZ_SCRIPT_ALT "\uee1e" #define MFIZZ_SHELL "\uee1f" #define MFIZZ_SITEFINITY "\uee20" #define MFIZZ_SOLARIS "\uee21" #define MFIZZ_SPLATTER "\uee22" #define MFIZZ_SPRING "\uee23" #define MFIZZ_SUSE "\uee24" #define MFIZZ_SVG "\uee25" #define MFIZZ_SYMFONY "\uee26" #define MFIZZ_TOMCAT "\uee27" #define MFIZZ_UBUNTU "\uee28" #define MFIZZ_UNITY "\uee29" #define MFIZZ_WIRELESS "\uee2a" #define MFIZZ_WORDPRESS "\uee2b" #define MFIZZ_X11 "\uee2c" #define FIRACODE_ASTERISK "\uee2d" #define FIRACODE_PLUS "\uee2e" #define FIRACODE_HYPHEN "\uee2f" #define FIRACODE_SAD "\uee30" #define FIRACODE_W_W_W "\uee31" #define FIRACODE_ASTERISK_ASTERISK "\uee32" #define FIRACODE_ASTERISK_ASTERISK_ASTERISK "\uee33" #define FIRACODE_ASTERISK_ASTERISK_SLASH "\uee34" #define FIRACODE_ASTERISK_GREATER "\uee35" #define FIRACODE_ASTERISK_SLASH "\uee36" #define FIRACODE_BACKSLASH_BACKSLASH "\uee37" #define FIRACODE_BBB "\uee38" #define FIRACODE_BRACELEFT_HYPHEN "\uee39" #define FIRACODE_BRACKETLEFT_BRACKETRIGHT "\uee3a" #define FIRACODE_COLON_COLON "\uee3b" #define FIRACODE_COLON_COLON_COLON "\uee3c" #define FIRACODE_COLON_EQUAL "\uee3d" #define FIRACODE_EXCLAM_EXCLAM "\uee3e" #define FIRACODE_EXCLAM_EQUAL "\uee3f" #define FIRACODE_EXCLAM_EQUAL_EQUAL "\uee40" #define FIRACODE_HYPHEN_BRACERIGHT "\uee41" #define FIRACODE_HYPHEN_HYPHEN "\uee42" #define FIRACODE_HYPHEN_HYPHEN_HYPHEN "\uee43" #define FIRACODE_HYPHEN_HYPHEN_GREATER "\uee44" #define FIRACODE_HYPHEN_GREATER "\uee45" #define FIRACODE_HYPHEN_GREATER_GREATER "\uee46" #define FIRACODE_HYPHEN_LESS "\uee47" #define FIRACODE_HYPHEN_LESS_LESS "\uee48" #define FIRACODE_HYPHEN_ASCIITILDE "\uee49" #define FIRACODE_NUMBERSIGN_BRACELEFT "\uee4a" #define FIRACODE_NUMBERSIGN_BRACKETLEFT "\uee4b" #define FIRACODE_NUMBERSIGN_NUMBERSIGN "\uee4c" #define FIRACODE_NNN "\uee4d" #define FIRACODE_NNNN "\uee4e" #define FIRACODE_NUMBERSIGN_PARENLEFT "\uee4f" #define FIRACODE_NUMBERSIGN_QUESTION "\uee50" #define FIRACODE_NUMBERSIGN_UNDERSCORE "\uee51" #define FIRACODE_NUP "\uee52" #define FIRACODE_PERIOD_HYPHEN "\uee53" #define FIRACODE_PERIOD_EQUAL "\uee54" #define FIRACODE_PERIOD_PERIOD "\uee55" #define FIRACODE_PERIOD_PERIOD_LESS "\uee56" #define FIRACODE_PERIOD_PERIOD_PERIOD "\uee57" #define FIRACODE_QUESTION_EQUAL "\uee58" #define FIRACODE_QUESTION_QUESTION "\uee59" #define FIRACODE_SEMICOLON_SEMICOLON "\uee5a" #define FIRACODE_SLASH_ASTERISK "\uee5b" #define FIRACODE_SLASH_ASTERISK_ASTERISK "\uee5c" #define FIRACODE_SLASH_EQUAL "\uee5d" #define FIRACODE_SLASH_EQUAL_EQUAL "\uee5e" #define FIRACODE_SLASH_GREATER "\uee5f" #define FIRACODE_SLASH_SLASH "\uee60" #define FIRACODE_SLASH_SLASH_SLASH "\uee61" #define FIRACODE_AMPERSAND_AMPERSAND "\uee62" #define FIRACODE_BAR_BAR "\uee63" #define FIRACODE_BAR_BAR_EQUAL "\uee64" #define FIRACODE_BAR_EQUAL "\uee65" #define FIRACODE_BAR_GREATER "\uee66" #define FIRACODE_ASCIICIRCUM_EQUAL "\uee67" #define FIRACODE_DOLLAR_GREATER "\uee68" #define FIRACODE_PLUS_PLUS "\uee69" #define FIRACODE_PLUS_PLUS_PLUS "\uee6a" #define FIRACODE_PLUS_GREATER "\uee6b" #define FIRACODE_EQUAL_COLON_EQUAL "\uee6c" #define FIRACODE_EQUAL_EQUAL "\uee6d" #define FIRACODE_EQUAL_EQUAL_EQUAL "\uee6e" #define FIRACODE_EQUAL_EQUAL_GREATER "\uee6f" #define FIRACODE_EQUAL_GREATER "\uee70" #define FIRACODE_EQUAL_GREATER_GREATER "\uee71" #define FIRACODE_EQUAL_LESS "\uee72" #define FIRACODE_EQUAL_LESS_LESS "\uee73" #define FIRACODE_EQUAL_SLASH_EQUAL "\uee74" #define FIRACODE_GREATER_HYPHEN "\uee75" #define FIRACODE_GREATER_EQUAL "\uee76" #define FIRACODE_GREATER_EQUAL_GREATER "\uee77" #define FIRACODE_GREATER_GREATER "\uee78" #define FIRACODE_GREATER_GREATER_HYPHEN "\uee79" #define FIRACODE_GREATER_GREATER_EQUAL "\uee7a" #define FIRACODE_GREATER_GREATER_GREATER "\uee7b" #define FIRACODE_LESS_ASTERISK "\uee7c" #define FIRACODE_LESS_ASTERISK_GREATER "\uee7d" #define FIRACODE_LESS_BAR "\uee7e" #define FIRACODE_LESS_BAR_GREATER "\uee7f" #define FIRACODE_LESS_DOLLAR "\uee80" #define FIRACODE_LESS_DOLLAR_GREATER "\uee81" #define FIRACODE_LESS_EXCLAM_HYPHEN_HYPHEN "\uee82" #define FIRACODE_LESS_HYPHEN "\uee83" #define FIRACODE_LESS_HYPHEN_HYPHEN "\uee84" #define FIRACODE_LESS_HYPHEN_GREATER "\uee85" #define FIRACODE_LESS_PLUS "\uee86" #define FIRACODE_LESS_PLUS_GREATER "\uee87" #define FIRACODE_LESS_EQUAL "\uee88" #define FIRACODE_LESS_EQUAL_EQUAL "\uee89" #define FIRACODE_LESS_EQUAL_GREATER "\uee8a" #define FIRACODE_LESS_EQUAL_LESS "\uee8b" #define FIRACODE_LESS_GREATER "\uee8c" #define FIRACODE_LESS_LESS "\uee8d" #define FIRACODE_LESS_LESS_HYPHEN "\uee8e" #define FIRACODE_LESS_LESS_EQUAL "\uee8f" #define FIRACODE_LESS_LESS_LESS "\uee90" #define FIRACODE_LESS_ASCIITILDE "\uee91" #define FIRACODE_LESS_ASCIITILDE_ASCIITILDE "\uee92" #define FIRACODE_LESS_SLASH "\uee93" #define FIRACODE_LESS_SLASH_GREATER "\uee94" #define FIRACODE_ASCIITILDE_AT "\uee95" #define FIRACODE_ASCIITILDE_HYPHEN "\uee96" #define FIRACODE_ASCIITILDE_EQUAL "\uee97" #define FIRACODE_ASCIITILDE_GREATER "\uee98" #define FIRACODE_ASCIITILDE_ASCIITILDE "\uee99" #define FIRACODE_AAG "\uee9a" #define FIRACODE_PERCENT_PERCENT "\uee9b" #define FIRACODE_X_MULTIPLY "\uee9c" #define FIRACODE_COLON_UC "\uee9d" #define FIRACODE_PLUS_LC "\uee9e" #define FIRACODE_PLUS_TOSF2 "\uee9f" #define FIRACODE_NAMEME_1114119 "\ueea0" #endif /* ICONS_IN_TERMINAL */ clifm-1.26.3/src/icons-nerdfont.h000066400000000000000000000113111506632037700165730ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* icons-nerdfont.h - Icon defintions for Clifm */ /* Taken from * https://github.com/jarun/nnn, licensed under BSD-2-Clause. * All changes are licensed under GPL-2.0-or-later. */ /* For more codepoints see https://www.nerdfonts.com/cheat-sheet */ #ifndef ICONS_NERDFONT #define ICONS_NERDFONT /* Arrows */ #define MD_ARROW_UPWARD "" #define MD_ARROW_FORWARD "" #define MD_ARROW_DOWNWARD "" /* Generics */ #define NERD_DIRECTORY "" #define NERD_FILE "" #define NERD_EXEC "" #define NERD_MANUAL "󱓷" #define NERD_LINK "" /* Top level and common icons */ #define NERD_ARCHIVE "" #define NERD_BINARY "" #define NERD_BRIEFCASE "󱒔" #define NERD_CHANGELOG "" #define NERD_CONFIGURE "" #define NERD_DESKTOP "󰟀" #define NERD_DOCUMENT NERD_FILE #define NERD_DOWNLOADS "󰇚" #define NERD_FAV "" #define NERD_GAMES "󱤙" #define NERD_GIT "󰊢" #define NERD_HOME "󰋜" #define NERD_LICENSE "󰈙" #define NERD_MAKEFILE "" #define NERD_MUSIC "󰋋" #define NERD_MUSICFILE "󰝚" #define NERD_PICTURES "󰄀" #define NERD_PICTUREFILE "󱅬" #define NERD_PUBLIC "" #define NERD_SCRIPT "" #define NERD_TEMPLATES "" #define NERD_TRASH "" #define NERD_VIDEOS "󰕧" #define NERD_VIDEOFILE "󰈰" #define NERD_ASM "" #define NERD_C "" #define NERD_CHESS "󰡘" #define NERD_CLOJURE "" #define NERD_COFFEE "" #define NERD_CPLUSPLUS "" #define NERD_CSHARP "󰌛" #define NERD_CSS3 "" #define NERD_DART "" #define NERD_DATABASE "" #define NERD_DIFF "" #define NERD_DOCKER "" #define NERD_ELECTRON "󱀤" #define NERD_ELIXIR "" #define NERD_ELM "" #define NERD_EMACS "" #define NERD_ERLANG "" #define NERD_FSHARP "" #define NERD_GO "" #define NERD_HASKELL "" #define NERD_HTML "󰗀" #define NERD_JAVA "󰬷" #define NERD_JAVASCRIPT "" #define NERD_JSON "" #define NERD_JULIA "" #define NERD_KOTLIN "󱈙" #define NERD_LINUX "" #define NERD_LUA "" #define NERD_MARKDOWN "" #define NERD_MATLAB "" #define NERD_MYSQL "" #define NERD_NIX "" #define NERD_OCAML "" #define NERD_OPTICALDISK "󰗮" #define NERD_PATCH "󰶯" #define NERD_PDF "" #define NERD_PERL "" #define NERD_PHP "󰌟" #define NERD_PLAYLIST "󰲸" #define NERD_PYTHON "" #define NERD_R "󰟔" #define NERD_REACT "" #define NERD_ROM "" #define NERD_RSS "" #define NERD_RUBY "" #define NERD_RUST "" #define NERD_SASS "" #define NERD_SCALA "" #define NERD_SHARE "" #define NERD_SWIFT "󰛥" #define NERD_TEX "" #define NERD_TS "󰛦" #define NERD_TXT "" #define NERD_VIM "" #define NERD_ZIG "" #define NERD_LOCK "" #define NERD_EXCELDOC "󰈜" #define NERD_PPTDOC "󰈨" #define NERD_WORDDOC "󰈭" #define NERD_WINDOWS "" #define NERD_PHOTOSHOP "" #define NERD_HISTORY "󰋚" #define NERD_COPYRIGHT "" #define NERD_KEY "󰌆" #define NERD_FONT "" #define NERD_BOOK "" #define NERD_CHECKLIST "" #define NERD_COMMENTS "" #define NERD_VISUALSTUDIO "󰨞" #define NERD_DROPBOX "󰇣" #define NERD_STEAM "" #define NERD_ARCHLINUX "" #define NERD_DEBIAN "" #define NERD_REDHAT "󱄛" #endif /* ICONS_NERDFONT */ clifm-1.26.3/src/icons.h000066400000000000000000000556541506632037700150000ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* icons.h - Icon definitions for CliFM */ /* Taken from * https://github.com/jarun/nnn, licensed under BSD-2-Clause. * All changes are licensed under GPL-2.0-or-later. */ #ifndef ICONS_H #define ICONS_H #if defined(_NERD) # include "icons-nerdfont.h" #elif defined(_ICONS_IN_TERMINAL) # include "icons-in-terminal.h" #else # include "icons-emoji.h" #endif /* _NERD */ struct icons_t { char *name; char *icon; char *color; }; /* Icon macros are defined in icons-in-terminal.h (provided by the * 'icons-in-terminal' project), icons-nerdfont.h, and icons-emoji.h */ char #if defined(_NERD) /* File types */ ICON_DIR[] = NERD_DIRECTORY, ICON_EXEC[] = NERD_EXEC, ICON_LOCK[] = NERD_LOCK, ICON_LINK[] = NERD_LINK, ICON_REG[] = NERD_FILE, /* Extensions */ ICON_ACCESS[] = NERD_FILE, ICON_ARCHIVE[] = NERD_ARCHIVE, ICON_AUDIO[] = NERD_MUSICFILE, ICON_BINARY[] = NERD_BINARY, ICON_BOOK[] = NERD_BOOK, ICON_C[] = NERD_C, ICON_CD[] = NERD_OPTICALDISK, ICON_CHESS[] = NERD_CHESS, ICON_CLOJURE[] = NERD_CLOJURE, ICON_CMAKE[] = NERD_FILE, ICON_CODE[] = NERD_FILE, ICON_COFFEE[] = NERD_COFFEE, ICON_COMMENTS[] = NERD_COMMENTS, ICON_CONF[] = NERD_CONFIGURE, ICON_CONFIGURE[] = NERD_CONFIGURE, ICON_COPYRIGHT[] = NERD_COPYRIGHT, ICON_CPP[] = NERD_CPLUSPLUS, ICON_CSHARP[] = NERD_CSHARP, ICON_CSS[] = NERD_CSS3, ICON_DART[] = NERD_DART, ICON_DATABASE[] = NERD_DATABASE, ICON_DIFF[] = NERD_DIFF, ICON_DOCKER[] = NERD_DOCKER, ICON_ELECTRON[] = NERD_ELECTRON, ICON_ELF[] = NERD_BINARY, ICON_ELM[] = NERD_ELM, ICON_ELIXIR[] = NERD_ELIXIR, ICON_EMACS[] = NERD_EMACS, ICON_ERLANG[] = NERD_ERLANG, ICON_EXCEL[] = NERD_EXCELDOC, ICON_FONT[] = NERD_FONT, ICON_FSHARP[] = NERD_FSHARP, ICON_GO[] = NERD_GO, ICON_HASKELL[] = NERD_HASKELL, ICON_HISTORY[] = NERD_HISTORY, ICON_HTML[] = NERD_HTML, ICON_IMG[] = NERD_PICTUREFILE, ICON_JAVA[] = NERD_JAVA, ICON_JAVASCRIPT[] = NERD_JAVASCRIPT, ICON_JSON[] = NERD_JSON, ICON_JULIA[] = NERD_JULIA, ICON_KEY[] = NERD_KEY, ICON_KOTLIN[] = NERD_KOTLIN, ICON_LIST[] = NERD_CHECKLIST, ICON_LUA[] = NERD_LUA, ICON_MAKEFILE[] = NERD_MAKEFILE, ICON_MANPAGE[] = NERD_MANUAL, ICON_MARKDOWN[] = NERD_MARKDOWN, ICON_MATLAB[] = NERD_MATLAB, ICON_MYSQL[] = NERD_MYSQL, ICON_ASM[] = NERD_ASM, ICON_OCAML[] = NERD_OCAML, ICON_OPENOFFICE_P[] = NERD_PPTDOC, ICON_OPENOFFICE_S[] = NERD_EXCELDOC, ICON_OPENOFFICE_T[] = NERD_WORDDOC, ICON_PATCH[] = NERD_PATCH, ICON_PDF[] = NERD_PDF, ICON_PERL[] = NERD_PERL, ICON_PHOTOSHOP[] = NERD_PHOTOSHOP, ICON_PHP[] = NERD_PHP, ICON_POSTSCRIPT[] = NERD_FILE, ICON_POWERPOINT[] = NERD_PPTDOC, ICON_PYTHON[] = NERD_PYTHON, ICON_R[] = NERD_R, ICON_REACT[] = NERD_REACT, ICON_README[] = NERD_BOOK, ICON_ROM[] = NERD_ROM, ICON_RSS[] = NERD_RSS, ICON_RUBY[] = NERD_RUBY, ICON_RUST[] = NERD_RUST, ICON_SASS[] = NERD_SASS, ICON_SCALA[] = NERD_SCALA, ICON_SCRIPT[] = NERD_SCRIPT, ICON_SHARE[] = NERD_SHARE, ICON_SQLITE[] = NERD_FILE, ICON_SWIFT[] = NERD_SWIFT, ICON_TEX[] = NERD_TEX, ICON_TS[] = NERD_TS, ICON_TXT[] = NERD_TXT, ICON_VID[] = NERD_VIDEOFILE, ICON_VIM[] = NERD_VIM, ICON_VISUALSTUDIO[] = NERD_VISUALSTUDIO, ICON_WINDOWS[] = NERD_WINDOWS, ICON_WORD[] = NERD_WORDDOC, ICON_ZIG[] = NERD_ZIG, ICON_ARCH[] = NERD_ARCHLINUX, ICON_DEBIAN[] = NERD_DEBIAN, ICON_NIX[] = NERD_NIX, ICON_REDHAT[] = NERD_REDHAT, /* Dir names */ ICON_DESKTOP[] = NERD_DESKTOP, ICON_DOCUMENTS[] = NERD_BRIEFCASE, ICON_DOTGIT[] = NERD_GIT, ICON_DOWNLOADS[] = NERD_DOWNLOADS, ICON_DROPBOX[] = NERD_DROPBOX, ICON_FAV[] = NERD_FAV, ICON_HOME[] = NERD_HOME, ICON_GAMES[] = NERD_GAMES, ICON_MUSIC[] = NERD_MUSIC, ICON_PLAYLIST[] = NERD_PLAYLIST, ICON_TRASH[] = NERD_TRASH, ICON_PICTURES[] = NERD_PICTURES, ICON_PUBLIC[] = NERD_PUBLIC, ICON_STEAM[] = NERD_STEAM, ICON_TEMPLATES[] = NERD_TEMPLATES, ICON_VIDEOS[] = NERD_VIDEOS; #elif defined(_ICONS_IN_TERMINAL) /* File types */ ICON_DIR[] = FA_FOLDER, ICON_EXEC[] = FA_COG, ICON_LINK[] = FA_CHAIN, ICON_LOCK[] = FA_LOCK, ICON_REG[] = FA_FILE_O, /* Extensions */ ICON_ACCESS[] = FILE_ACCESS, ICON_ARCHIVE[] = FA_ARCHIVE, ICON_AUDIO[] = FA_FILE_AUDIO_O, ICON_BINARY[] = OCT_FILE_BINARY, ICON_BOOK[] = OCT_BOOK, ICON_C[] = MFIZZ_C, ICON_CD[] = LINEA_MUSIC_CD, ICON_CHESS[] = FA_FILE_O, ICON_CLOJURE[] = MFIZZ_CLOJURE, ICON_CMAKE[] = FILE_CMAKE, ICON_CODE[] = FA_FILE_CODE_O, ICON_COFFEE[] = DEV_COFFEESCRIPT, ICON_COMMENTS[] = FA_COMMENTS, ICON_CONF[] = FA_SLIDERS, ICON_CONFIGURE[] = FA_SLIDERS, ICON_COPYRIGHT[] = OCT_LAW, ICON_CPP[] = MFIZZ_CPLUSPLUS, ICON_CSHARP[] = MFIZZ_CSHARP, ICON_CSS[] = MFIZZ_CSS3_ALT, ICON_DART[] = DEV_DART, ICON_DATABASE[] = FA_DATABASE, ICON_DIFF[] = FILE_DIFF, ICON_DOCKER[] = MFIZZ_DOCKER, ICON_ELECTRON[] = FILE_ELECTRON, ICON_ELF[] = OCT_FILE_BINARY, ICON_ELIXIR[] = MFIZZ_ELIXIR, ICON_ELM[] = MFIZZ_ELM, ICON_EMACS[] = FILE_EMACS, ICON_ERLANG[] = DEV_ERLANG, ICON_EXCEL[] = FILE_EXCEL, ICON_FONT[] = FILE_FONT, ICON_FSHARP[] = DEV_FSHARP, ICON_GO[] = FILE_GO, ICON_HASKELL[] = MFIZZ_HASKELL, ICON_HISTORY[] = FA_HISTORY, ICON_HTML[] = FA_FILE_CODE_O, ICON_IMG[] = FA_FILE_IMAGE_O, ICON_JAVA[] = MFIZZ_JAVA, ICON_JAVASCRIPT[] = DEV_JAVASCRIPT, ICON_JSON[] = FILE_SWAGGER, ICON_JULIA[] = FILE_JULIA, ICON_KEY[] = MD_VPN_KEY, ICON_KOTLIN[] = FILE_KOTLIN, ICON_LIST[] = FA_CHECK_SQUARE_O, ICON_LUA[] = FILE_LUA, ICON_MANPAGE[] = FILE_MANPAGE, ICON_MAKEFILE[] = FILE_MAPBOX, ICON_MATLAB[] = FILE_MATLAB, ICON_MARKDOWN[] = OCT_MARKDOWN, ICON_MYSQL[] = MFIZZ_MYSQL, ICON_ASM[] = FILE_NASM, ICON_OCAML[] = FILE_OCAML, ICON_OPENOFFICE_P[] = FILE_OPENOFFICE, ICON_OPENOFFICE_S[] = FILE_OPENOFFICE, ICON_OPENOFFICE_T[] = FILE_OPENOFFICE, ICON_PATCH[] = FILE_PATCH, ICON_PDF[] = FA_FILE_PDF_O, ICON_PERL[] = MFIZZ_PERL, ICON_PHP[] = MFIZZ_PHP_ALT, ICON_PHOTOSHOP[] = DEV_PHOTOSHOP, ICON_POSTSCRIPT[] = FILE_POSTSCRIPT, ICON_POWERPOINT[] = FILE_POWERPOINT, ICON_PYTHON[] = MFIZZ_PYTHON, ICON_R[] = FILE_R, ICON_REACT[] = FILE_REACT, ICON_README[] = OCT_BOOK, ICON_ROM[] = FILE_VERILOG, ICON_RSS[] = MD_RSS_FEED, ICON_RUBY[] = MFIZZ_RUBY, ICON_RUST[] = MFIZZ_RUST, ICON_SASS[] = MFIZZ_SASS, ICON_SCALA[] = MFIZZ_SCALA, ICON_SCRIPT[] = OCT_TERMINAL, ICON_SHARE[] = MD_SHARE, ICON_SQLITE[] = FILE_SQLITE, ICON_SWIFT[] = DEV_SWIFT, ICON_TEX[] = FILE_TEX, ICON_TS[] = FILE_TS, ICON_TXT[] = MD_FORMAT_ALIGN_LEFT, ICON_VID[] = FA_FILE_MOVIE_O, ICON_VIM[] = DEV_VIM, ICON_VISUALSTUDIO[] = DEV_VISUALSTUDIO, ICON_WINDOWS[] = DEV_WINDOWS, ICON_WORD[] = FILE_WORD, ICON_ZIG[] = FA_FILE_O, ICON_ARCH[] = MFIZZ_ARCHLINUX, ICON_DEBIAN[] = MFIZZ_DEBIAN, ICON_NIX[] = LINUX_NIXOS, ICON_REDHAT[] = LINUX_REDHAT, /* Dir names */ ICON_DESKTOP[] = FA_DESKTOP, ICON_DOCUMENTS[] = FA_BRIEFCASE, ICON_DOTGIT[] = MFIZZ_GIT, ICON_DOWNLOADS[] = MD_FILE_DOWNLOAD, ICON_DROPBOX[] = FA_DROPBOX, ICON_FAV[] = FA_STAR_O, ICON_GAMES[] = MD_GAMES, ICON_HOME[] = FA_HOME, ICON_MUSIC[] = FA_MUSIC, ICON_PLAYLIST[] = MD_QUEUE_MUSIC, ICON_PICTURES[] = MD_CAMERA_ALT, ICON_PUBLIC[] = FA_INBOX, ICON_STEAM[] = FA_STEAM, ICON_TEMPLATES[] = FA_PAPERCLIP, ICON_TRASH[] = FA_TRASH, ICON_VIDEOS[] = FA_FILM; #else /* emoji-icons */ /* File types */ ICON_DIR[] = EMOJI_FOLDER, ICON_EXEC[] = EMOJI_EXEC, ICON_LINK[] = EMOJI_LINK, ICON_LOCK[] = EMOJI_LOCK, ICON_REG[] = EMOJI_FILE, /* Extensions */ ICON_ACCESS[] = EMOJI_PRESENTATION, ICON_ARCHIVE[] = EMOJI_ARCHIVE, ICON_AUDIO[] = EMOJI_AUDIO, ICON_BINARY[] = EMOJI_BINARY, ICON_BOOK[] = EMOJI_BOOK_OPEN, ICON_C[] = EMOJI_C, ICON_CD[] = EMOJI_DISK, ICON_CHESS[] = EMOJI_CHESS, ICON_CLOJURE[] = EMOJI_CLOJURE, ICON_CMAKE[] = EMOJI_MAKE, ICON_CODE[] = EMOJI_CODE, ICON_COFFEE[] = EMOJI_COFFEE, ICON_COMMENTS[] = EMOJI_SUBTITLES, ICON_CONF[] = EMOJI_CONF, ICON_CONFIGURE[] = EMOJI_CONF, ICON_COPYRIGHT[] = EMOJI_LICENSE, ICON_CPP[] = EMOJI_CPP, ICON_CSHARP[] = EMOJI_CSHARP, ICON_CSS[] = EMOJI_CSS, ICON_DART[] = EMOJI_DART, ICON_DATABASE[] = EMOJI_DATABASE, ICON_DIFF[] = EMOJI_DIFF, ICON_DOCKER[] = EMOJI_DOCKER, ICON_ELECTRON[] = EMOJI_ELECTRON, ICON_ELF[] = EMOJI_BINARY, ICON_ELIXIR[] = EMOJI_ELIXIR, ICON_ELM[] = EMOJI_ELM, ICON_EMACS[] = EMOJI_SCRIPT, ICON_ERLANG[] = EMOJI_ERLANG, ICON_EXCEL[] = EMOJI_STYLESHEET, ICON_FONT[] = EMOJI_FONT, ICON_FSHARP[] = EMOJI_FSHARP, ICON_GO[] = EMOJI_GO, ICON_HASKELL[] = EMOJI_HASKELL, ICON_HISTORY[] = EMOJI_CHANGELOG, ICON_HTML[] = EMOJI_WEB, ICON_IMG[] = EMOJI_IMAGE, ICON_JAVA[] = EMOJI_JAVA, ICON_JAVASCRIPT[] = EMOJI_JAVASCRIPT, ICON_JSON[] = EMOJI_JSON, ICON_JULIA[] = EMOJI_JULIA, ICON_KEY[] = EMOJI_KEY, ICON_KOTLIN[] = EMOJI_KOTLIN, ICON_LIST[] = EMOJI_LIST, ICON_LUA[] = EMOJI_LUA, ICON_MAKEFILE[] = EMOJI_MAKE, ICON_MANPAGE[] = EMOJI_MANUAL, ICON_MARKDOWN[] = EMOJI_MARKDOWN, ICON_MATLAB[] = EMOJI_MATLAB, ICON_MYSQL[] = EMOJI_DATABASE, ICON_ASM[] = EMOJI_ASM, ICON_OCAML[] = EMOJI_OCAML, ICON_OPENOFFICE_P[] = EMOJI_PRESENTATION, ICON_OPENOFFICE_S[] = EMOJI_STYLESHEET, ICON_OPENOFFICE_T[] = EMOJI_WORD, ICON_PATCH[] = EMOJI_PATCH, ICON_PDF[] = EMOJI_PDF, ICON_PERL[] = EMOJI_PERL, ICON_PHOTOSHOP[] = EMOJI_PHOTOSHOP, ICON_PHP[] = EMOJI_WEB, ICON_POSTSCRIPT[] = EMOJI_POSTSCRIPT, ICON_POWERPOINT[] = EMOJI_PRESENTATION, ICON_PYTHON[] = EMOJI_PYTHON, ICON_R[] = EMOJI_R, ICON_REACT[] = EMOJI_ELECTRON, ICON_README[] = EMOJI_TEXT, ICON_ROM[] = EMOJI_FILE, ICON_RSS[] = EMOJI_RSS, ICON_RUBY[] = EMOJI_RUBY, ICON_RUST[] = EMOJI_RUST, ICON_SASS[] = EMOJI_SASS, ICON_SCALA[] = EMOJI_SCALA, ICON_SCRIPT[] = EMOJI_SCRIPT, ICON_SHARE[] = EMOJI_SHARE, ICON_SQLITE[] = EMOJI_DATABASE, ICON_SWIFT[] = EMOJI_SWIFT, ICON_TEX[] = EMOJI_TEX, ICON_TS[] = EMOJI_TYPESCRIPT, ICON_TXT[] = EMOJI_NOTE, ICON_VIM[] = EMOJI_VIM, ICON_VID[] = EMOJI_MOVIE, ICON_VISUALSTUDIO[] = EMOJI_VISUALSTUDIO, ICON_WINDOWS[] = EMOJI_WINDOWS, ICON_WORD[] = EMOJI_WORD, ICON_ZIG[] = EMOJI_FILE, ICON_ARCH[] = EMOJI_MAKE, ICON_REDHAT[] = EMOJI_ARCHIVE, ICON_NIX[] = EMOJI_SCRIPT, ICON_DEBIAN[] = EMOJI_ARCHIVE, /* Dir names */ ICON_DESKTOP[] = EMOJI_DESKTOP, ICON_DOCUMENTS[] = EMOJI_BRIEFCASE, ICON_DOTGIT[] = EMOJI_GIT, ICON_DOWNLOADS[] = EMOJI_DOWNLOAD, ICON_DROPBOX[] = EMOJI_FOLDER, ICON_FAV[] = EMOJI_FOLDER, ICON_GAMES[] = EMOJI_GAMES, ICON_HOME[] = EMOJI_HOME, ICON_MUSIC[] = EMOJI_MUSIC, ICON_PLAYLIST[] = EMOJI_PLAYLIST, ICON_PICTURES[] = EMOJI_PICTURE, ICON_PUBLIC[] = EMOJI_PUBLIC, ICON_STEAM[] = EMOJI_STEAM, ICON_TEMPLATES[] = EMOJI_TEMPLATE, ICON_TRASH[] = EMOJI_TRASH, ICON_VIDEOS[] = EMOJI_VIDEOS; #endif /* _NERD */ #if defined(_NERD) || defined(_ICONS_IN_TERMINAL) # define BLUE "\x1b[0;34m" # define B_BLUE "\x1b[1;34m" # define WHITE "\x1b[0;37m" # define B_WHITE "\x1b[1;37m" # define YELLOW "\x1b[0;33m" # define GREEN "\x1b[0;32m" # define B_GREEN "\x1b[1;32m" # define CYAN "\x1b[0;36m" # define MAGENTA "\x1b[0;35m" # define RED "\x1b[0;31m" #else # define EMPTY_STR "" # define BLUE EMPTY_STR # define B_BLUE EMPTY_STR # define WHITE EMPTY_STR # define B_WHITE EMPTY_STR # define YELLOW EMPTY_STR # define GREEN EMPTY_STR # define B_GREEN EMPTY_STR # define CYAN EMPTY_STR # define MAGENTA EMPTY_STR # define RED EMPTY_STR #endif /* _NERD || _ICONS_IN_TERMINAL */ /* Default icons and colors */ #define DEF_DIR_ICON ICON_DIR /* Directory */ #define DEF_DIR_ICON_COLOR YELLOW #define DEF_LINK_ICON ICON_LINK /* Symbolic link */ #define DEF_LINK_ICON_COLOR CYAN #define DEF_EXEC_ICON ICON_EXEC /* Executable file */ #define DEF_EXEC_ICON_COLOR WHITE #define DEF_NOPERM_ICON ICON_LOCK /* File without access permission */ #define DEF_NOPERM_ICON_COLOR YELLOW #define DEF_FILE_ICON ICON_REG /* None of the above */ #define DEF_FILE_ICON_COLOR WHITE /* Per file extension icons */ struct icons_t const icon_ext[] = { {"7z", ICON_ARCHIVE, YELLOW}, {"3gp", ICON_VID, BLUE}, {"a", ICON_ARCHIVE, YELLOW}, {"apk", ICON_ARCHIVE, YELLOW}, {"asm", ICON_ASM, WHITE}, {"aup", ICON_AUDIO, YELLOW}, {"avi", ICON_VID, BLUE}, {"awk", ICON_SCRIPT, WHITE}, {"azw", ICON_BOOK, B_WHITE}, {"azw3", ICON_BOOK, B_WHITE}, {"bash", ICON_SCRIPT, WHITE}, {"bat", ICON_SCRIPT, WHITE}, #if defined(_ICONS_IN_TERMINAL) {"bib", FILE_BIBTEX, B_WHITE}, #endif /* _ICONS_IN_TERMINAL */ {"bin", ICON_BINARY, WHITE}, {"bmp", ICON_IMG, GREEN}, {"bz2", ICON_ARCHIVE, YELLOW}, {"c", ICON_C, BLUE}, {"c++", ICON_CPP, WHITE}, {"cabal", ICON_HASKELL, BLUE}, {"cab", ICON_ARCHIVE, YELLOW}, {"cb7", ICON_ARCHIVE, YELLOW}, {"cba", ICON_ARCHIVE, YELLOW}, {"cbr", ICON_ARCHIVE, YELLOW}, {"cbz", ICON_ARCHIVE, YELLOW}, {"cc", ICON_CPP, WHITE}, {"cfg", ICON_CONF, WHITE}, {"clifm", ICON_CONF, WHITE}, {"class", ICON_JAVA, B_WHITE}, {"clj", ICON_CLOJURE, GREEN}, {"cljc", ICON_CLOJURE, GREEN}, {"cljs", ICON_CLOJURE, GREEN}, {"cls", ICON_TEX, B_WHITE}, {"cmake", ICON_CMAKE, WHITE}, {"coffee", ICON_COFFEE, WHITE}, {"conf", ICON_CONF, WHITE}, {"cpio", ICON_ARCHIVE, YELLOW}, {"cpp", ICON_CPP, WHITE}, {"csh", ICON_SCRIPT, WHITE}, {"css", ICON_CSS, BLUE}, {"cue", ICON_PLAYLIST, YELLOW}, {"cvs", ICON_CONF, WHITE}, {"cxx", ICON_CPP, WHITE}, {"dat", ICON_BINARY, WHITE}, {"dart", ICON_DART, BLUE}, {"db", ICON_DATABASE, WHITE}, {"deb", ICON_DEBIAN, RED}, {"diff", ICON_DIFF, WHITE}, {"djvu", ICON_BOOK, B_WHITE}, {"dll", ICON_SHARE, BLUE}, {"doc", ICON_WORD, BLUE}, {"docx", ICON_WORD, BLUE}, {"eex", ICON_ELIXIR, BLUE}, {"ejs", ICON_JAVASCRIPT, WHITE}, {"el", ICON_EMACS, BLUE}, {"elf", ICON_ELF, WHITE}, {"elm", ICON_ELM, GREEN}, {"epub", ICON_BOOK, B_WHITE}, {"erb", ICON_RUBY, RED}, {"erl", ICON_ERLANG, RED}, {"ex", ICON_ELIXIR, BLUE}, {"exe", ICON_WINDOWS, BLUE}, {"exs", ICON_ELIXIR, BLUE}, {"f#", ICON_FSHARP, WHITE}, {"fen", ICON_CHESS, WHITE}, {"fish", ICON_SCRIPT, WHITE}, {"flac", ICON_AUDIO, YELLOW}, {"flv", ICON_VID, BLUE}, {"fodp", ICON_OPENOFFICE_P, YELLOW}, {"fods", ICON_OPENOFFICE_S, GREEN}, {"fodt", ICON_OPENOFFICE_T, BLUE}, {"fs", ICON_FSHARP, WHITE}, {"fsi", ICON_FSHARP, WHITE}, {"fsscript", ICON_FSHARP, WHITE}, {"fsx", ICON_FSHARP, WHITE}, {"gem", ICON_ARCHIVE, YELLOW}, {"gif", ICON_IMG, GREEN}, {"gpg", ICON_LOCK, YELLOW}, {"go", ICON_GO, YELLOW}, {"gz", ICON_ARCHIVE, YELLOW}, {"gzip", ICON_ARCHIVE, YELLOW}, {"h", ICON_C, BLUE}, {"haml", ICON_CODE, WHITE}, {"heex", ICON_ELIXIR, BLUE}, {"hh", ICON_CPP, WHITE}, {"hpp", ICON_CPP, WHITE}, {"htaccess", ICON_CONF, WHITE}, {"htpasswd", ICON_CONF, WHITE}, {"hrl", ICON_ERLANG, RED}, {"hs", ICON_HASKELL, BLUE}, {"htm", ICON_HTML, WHITE}, {"html", ICON_HTML, WHITE}, {"hxx", ICON_CPP, WHITE}, {"ico", ICON_IMG, GREEN}, {"img", ICON_CD, B_WHITE}, {"ini", ICON_CONF, WHITE}, {"iso", ICON_CD, B_WHITE}, {"jar", ICON_JAVA, B_WHITE}, {"java", ICON_JAVA, B_WHITE}, {"jl", ICON_JULIA, BLUE}, {"jpeg", ICON_IMG, GREEN}, {"jpg", ICON_IMG, GREEN}, {"js", ICON_JAVASCRIPT, WHITE}, {"json", ICON_JSON, WHITE}, {"jsx", ICON_ELECTRON, B_GREEN}, {"jxl", ICON_IMG, GREEN}, {"key", ICON_KEY, YELLOW}, {"kf8", ICON_BOOK, B_WHITE}, {"kfx", ICON_BOOK, B_WHITE}, {"ko", ICON_BINARY, WHITE}, {"kt", ICON_KOTLIN, BLUE}, {"kts", ICON_KOTLIN, BLUE}, {"ksh", ICON_SCRIPT, WHITE}, {"lha", ICON_ARCHIVE, YELLOW}, {"lhs", ICON_HASKELL, BLUE}, {"log", ICON_TXT, WHITE}, {"lua", ICON_LUA, WHITE}, {"lz", ICON_ARCHIVE, YELLOW}, {"lz4", ICON_ARCHIVE, YELLOW}, {"lzh", ICON_ARCHIVE, YELLOW}, {"lzma", ICON_ARCHIVE, YELLOW}, {"m", ICON_MATLAB, YELLOW}, {"m4a", ICON_AUDIO, YELLOW}, {"m4v", ICON_VID, BLUE}, {"markdown", ICON_MARKDOWN, WHITE}, {"mat", ICON_MATLAB, YELLOW}, {"md", ICON_MARKDOWN, WHITE}, {"mk", ICON_MAKEFILE, WHITE}, {"mkv", ICON_VID, BLUE}, {"ml", ICON_OCAML, WHITE}, {"mli", ICON_OCAML, WHITE}, {"mov", ICON_VID, BLUE}, {"mp3", ICON_AUDIO, YELLOW}, {"mp4", ICON_VID, BLUE}, {"mpeg", ICON_VID, BLUE}, {"mpg", ICON_VID, BLUE}, {"msi", ICON_WINDOWS, BLUE}, {"nix", ICON_NIX, BLUE}, {"o", ICON_BINARY, WHITE}, {"odp", ICON_OPENOFFICE_P, YELLOW}, {"ods", ICON_OPENOFFICE_S, GREEN}, {"odt", ICON_OPENOFFICE_T, BLUE}, {"ogg", ICON_AUDIO, YELLOW}, {"ogv", ICON_VID, BLUE}, {"opdownload", ICON_DOWNLOADS, WHITE}, {"opus", ICON_AUDIO, YELLOW}, {"otf", ICON_FONT, WHITE}, {"out", ICON_ELF, WHITE}, {"part", ICON_DOWNLOADS, WHITE}, {"patch", ICON_PATCH, WHITE}, {"pem", ICON_KEY, YELLOW}, {"pdf", ICON_PDF, RED}, {"pgn", ICON_CHESS, WHITE}, {"php", ICON_PHP, WHITE}, {"pl", ICON_PERL, YELLOW}, {"plx", ICON_PERL, YELLOW}, {"pm", ICON_PERL, YELLOW}, {"png", ICON_IMG, GREEN}, {"pod", ICON_PERL, WHITE}, {"ppt", ICON_POWERPOINT, YELLOW}, {"pptx", ICON_POWERPOINT, YELLOW}, {"ps", ICON_POSTSCRIPT, RED}, {"psb", ICON_PHOTOSHOP, WHITE}, {"psv", ICON_PHOTOSHOP, WHITE}, {"psd", ICON_PHOTOSHOP, WHITE}, {"py", ICON_PYTHON, GREEN}, {"pyc", ICON_PYTHON, GREEN}, {"pyd", ICON_PYTHON, GREEN}, {"pyo", ICON_PYTHON, GREEN}, {"qcow", ICON_CD, B_WHITE}, {"qcow2", ICON_CD, B_WHITE}, {"r", ICON_R, WHITE}, {"rda", ICON_R, WHITE}, {"rdata", ICON_R, WHITE}, {"rar", ICON_ARCHIVE, YELLOW}, {"rb", ICON_RUBY, RED}, {"rc", ICON_CONF, WHITE}, {"rlib", ICON_RUST, WHITE}, {"rom", ICON_ROM, WHITE}, {"rpm", ICON_REDHAT, RED}, {"rs", ICON_RUST, WHITE}, {"rss", ICON_RSS, BLUE}, {"rtf", ICON_PDF, RED}, {"sass", ICON_SASS, B_BLUE}, {"scala", ICON_SCALA, WHITE}, {"service", ICON_SCRIPT, WHITE}, {"sh", ICON_SCRIPT, WHITE}, {"slim", ICON_CODE, WHITE}, {"sln", ICON_VISUALSTUDIO, BLUE}, {"so", ICON_BINARY, WHITE}, {"sql", ICON_MYSQL, B_WHITE}, {"sqlite", ICON_SQLITE, WHITE}, {"srt", ICON_COMMENTS, WHITE}, {"sub", ICON_COMMENTS, WHITE}, {"svg", ICON_IMG, GREEN}, {"swift", ICON_SWIFT, GREEN}, {"t", ICON_PERL, YELLOW}, {"tar", ICON_ARCHIVE, YELLOW}, {"tbz2", ICON_ARCHIVE, YELLOW}, {"tex", ICON_TEX, B_WHITE}, {"tgz", ICON_ARCHIVE, YELLOW}, {"tiff", ICON_IMG, GREEN}, {"toml", ICON_CONF, WHITE}, {"torrent", ICON_DOWNLOADS, WHITE}, {"ts", ICON_TS, BLUE}, {"tsx", ICON_REACT, B_BLUE}, {"ttf", ICON_FONT, WHITE}, {"txt", ICON_TXT, WHITE}, {"txz", ICON_ARCHIVE, YELLOW}, {"vdi", ICON_CD, B_WHITE}, {"vhd", ICON_CD, B_WHITE}, {"vhdx", ICON_CD, B_WHITE}, {"vmdk", ICON_CD, B_WHITE}, {"vid", ICON_VID, BLUE}, {"vim", ICON_VIM, GREEN}, {"vimrc", ICON_VIM, GREEN}, {"vtt", ICON_COMMENTS, WHITE}, {"wav", ICON_AUDIO, YELLOW}, {"webm", ICON_VID, BLUE}, {"webp", ICON_IMG, GREEN}, {"wma", ICON_AUDIO, YELLOW}, {"wmv", ICON_VID, BLUE}, {"xbps", ICON_ARCHIVE, YELLOW}, {"xcf", ICON_IMG, GREEN}, {"xthml", ICON_HTML, WHITE}, {"xls", ICON_EXCEL, GREEN}, {"xlsx", ICON_EXCEL, GREEN}, {"xml", ICON_CODE, WHITE}, {"xs", ICON_PERL, YELLOW}, {"xz", ICON_ARCHIVE, RED}, {"yaml", ICON_CONF, WHITE}, {"yml", ICON_CONF, WHITE}, {"zig", ICON_ZIG, YELLOW}, {"zip", ICON_ARCHIVE, YELLOW}, {"zsh", ICON_SCRIPT, WHITE}, {"zst", ICON_ARCHIVE, YELLOW}, }; /* Icons for some specific dir names */ struct icons_t const icon_dirnames[] = { /* Translated version for these dirs should be added here * See https://github.com/alexanderjeurissen/ranger_devicons/blob/main/devicons.py*/ {"home", ICON_HOME, DEF_DIR_ICON_COLOR}, {".git", ICON_DOTGIT, DEF_DIR_ICON_COLOR}, {".config", ICON_CONFIGURE, DEF_DIR_ICON_COLOR}, {"Desktop", ICON_DESKTOP, DEF_DIR_ICON_COLOR}, {"Documents", ICON_DOCUMENTS, DEF_DIR_ICON_COLOR}, {"Downloads", ICON_DOWNLOADS, DEF_DIR_ICON_COLOR}, {"Dropbox", ICON_DROPBOX, DEF_DIR_ICON_COLOR}, {"games", ICON_GAMES, DEF_DIR_ICON_COLOR}, {"Music", ICON_MUSIC, DEF_DIR_ICON_COLOR}, {"Pictures", ICON_PICTURES, DEF_DIR_ICON_COLOR}, {"Public", ICON_PUBLIC, DEF_DIR_ICON_COLOR}, {"Steam", ICON_STEAM, DEF_DIR_ICON_COLOR}, {"Templates", ICON_TEMPLATES, DEF_DIR_ICON_COLOR}, {"Videos", ICON_VIDEOS, DEF_DIR_ICON_COLOR}, }; /* Icons for some specific filenames */ struct icons_t const icon_filenames[] = { /* More specific filenames from here https://github.com/alexanderjeurissen/ranger_devicons/blob/main/devicons.py */ {".bash_history", ICON_CONF, WHITE}, {".bash_logout", ICON_CONF, WHITE}, {".bash_profile", ICON_CONF, WHITE}, {".bashrc", ICON_CONF, WHITE}, {".gitconfig", ICON_CONF, WHITE}, {".gitignore", ICON_CONF, WHITE}, {".inputrc", ICON_CONF, WHITE}, {".vimrc", ICON_CONF, WHITE}, {".Xdefaults", ICON_CONF, WHITE}, {".xinitrc", ICON_CONF, WHITE}, {".Xresources", ICON_CONF, WHITE}, {".zshrc", ICON_CONF, WHITE}, {"CHANGELOG", ICON_HISTORY, DEF_FILE_ICON_COLOR}, {"clifmrc", ICON_CONF, WHITE}, {"CMakeLists.txt", ICON_CMAKE, WHITE}, {"configure", ICON_CONFIGURE, DEF_FILE_ICON_COLOR}, {"Dockerfile", ICON_DOCKER, BLUE}, {"License", ICON_COPYRIGHT, DEF_FILE_ICON_COLOR}, {"Makefile", ICON_MAKEFILE, DEF_FILE_ICON_COLOR}, {"PKGBUILD", ICON_ARCH, CYAN}, {"README", ICON_README, YELLOW}, {"TODO", ICON_LIST, WHITE}, }; #endif /* ICONS_H */ clifm-1.26.3/src/init.c000066400000000000000000002153531506632037700146150ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* init.c -- functions controlling the program initialization */ #include "helpers.h" #include #include /* getgrouplist(), getgrent(), setgrent(), endgrent() */ #include /* getpwent(), setpwent(), endpwent() */ #include #include #include #include /* tilde_expand() */ #if defined(__OpenBSD__) # include /* history_write_timestamps */ #else # include #endif /* __OpenBSD__ */ #if defined(__NetBSD__) # include #endif /* __NetBSD__ */ #ifndef _BE_POSIX # include /* _PATH_STDPATH */ #endif /* _BE_POSIX */ #ifdef LINUX_FSINFO # include /* xxxmntent functions, used by get_ext_mountpoints() */ #endif /* LINUX_FSINFO */ #include "autocmds.h" /* reset_opts() */ #include "aux.h" #include "checks.h" /* truncate_file(), is_number() */ #include "config.h" #include "jump.h" /* add_to_jumpdb() */ #include "misc.h" #include "navigation.h" #include "prompt.h" /* set_prompt_options() */ #include "sanitize.h" #include "selection.h" #include "sort.h" #include "spawn.h" /* We need this for get_user_groups() */ #if !defined(NGROUPS_MAX) # if defined(__linux__) # if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,4) # define NGROUPS_MAX 65536 # else # define NGROUPS_MAX 32 # endif /* linux >= 2.6.4 */ # else # define NGROUPS_MAX 1024 # endif /* __linux__ */ #endif /* !NGROUPS_MAX */ #ifdef LINUX_FSINFO # ifndef _PATH_MOUNTED # define _PATH_MOUNTED "/proc/mounts" # endif /* !_PATH_MOUNTED */ void get_ext_mountpoints(void) { if (ext_mnt) { int i; for (i = 0; ext_mnt[i].mnt_point; i++) free(ext_mnt[i].mnt_point); free(ext_mnt); ext_mnt = (struct ext_mnt_t *)NULL; } FILE *fp = setmntent(_PATH_MOUNTED, "r"); if (!fp) return; size_t n = 0; struct mntent *ent; while ((ent = getmntent(fp)) != NULL) { char *t = ent->mnt_type; if (*t != 'e' || t[1] != 'x' || t[2] != 't' || !t[3] || t[4]) continue; ext_mnt = xnrealloc(ext_mnt, n + 2, sizeof(struct ext_mnt_t)); ext_mnt[n].mnt_point = savestring(ent->mnt_dir, strlen(ent->mnt_dir)); switch (t[3]) { case '2': ext_mnt[n].type = EXT2_FSTYPE; break; case '3': ext_mnt[n].type = EXT3_FSTYPE; break; case '4': ext_mnt[n].type = EXT4_FSTYPE; break; default: ext_mnt[n].type = -1; break; } n++; } if (n > 0) { ext_mnt[n].mnt_point = (char *)NULL; ext_mnt[n].type = -1; } endmntent(fp); } #endif /* LINUX_FSINFO */ void init_workspaces_opts(void) { size_t i; for (i = 0; i < MAX_WS; i++) { workspace_opts[i].color_scheme = cur_cscheme; workspace_opts[i].files_counter = conf.files_counter; workspace_opts[i].filter.str = filter.str ? savestring(filter.str, strlen(filter.str)) : (char *)NULL; workspace_opts[i].filter.rev = filter.rev; workspace_opts[i].filter.type = filter.type; workspace_opts[i].filter.env = filter.env; workspace_opts[i].light_mode = conf.light_mode; workspace_opts[i].list_dirs_first = conf.list_dirs_first; workspace_opts[i].long_view = conf.long_view; workspace_opts[i].max_files = conf.max_files; workspace_opts[i].max_name_len = conf.max_name_len; workspace_opts[i].only_dirs = conf.only_dirs; workspace_opts[i].pager = conf.pager; workspace_opts[i].show_hidden = conf.show_hidden; workspace_opts[i].sort = conf.sort; workspace_opts[i].sort_reverse = conf.sort_reverse; } } static void init_shades(void) { date_shades.type = SHADE_TYPE_UNSET; size_shades.type = SHADE_TYPE_UNSET; int i = NUM_SHADES; while (--i >= 0) { date_shades.shades[i] = (struct rgb_t){0}; size_shades.shades[i] = (struct rgb_t){0}; } } void init_conf_struct(void) { conf.apparent_size = UNSET; conf.auto_open = UNSET; conf.autocd = UNSET; conf.autocmd_msg = DEF_AUTOCMD_MSG; conf.autols = UNSET; conf.bell_style = DEF_BELL_STYLE; conf.case_sens_dirjump = UNSET; conf.case_sens_path_comp = UNSET; conf.case_sens_search = DEF_CASE_SENS_SEARCH; conf.case_sens_list = UNSET; conf.check_cap = DEF_CHECK_CAP; conf.check_ext = DEF_CHECK_EXT; conf.cd_on_quit = UNSET; conf.classify = UNSET; conf.clear_screen = UNSET; conf.cmd_desc_sug = DEF_CMD_DESC_SUG; conf.colorize = UNSET; conf.color_lnk_as_target = UNSET; conf.columned = DEF_COLUMNS; conf.cp_cmd = DEF_CP_CMD; conf.default_answer = (struct default_answer_t){0}; conf.desktop_notifications = UNSET; conf.dirhist_map = UNSET; conf.disk_usage = UNSET; conf.ext_cmd_ok = UNSET; conf.files_counter = UNSET; conf.follow_symlinks = DEF_FOLLOW_SYMLINKS; conf.follow_symlinks_long = DEF_FOLLOW_SYMLINKS_LONG; conf.full_dir_size = UNSET; conf.fuzzy_match = UNSET; conf.fuzzy_match_algo = UNSET; conf.fzf_preview = UNSET; #ifndef _NO_HIGHLIGHT conf.highlight = UNSET; #else conf.highlight = 0; #endif /* !_NO_HIGHLIGHT */ #ifndef _NO_ICONS conf.icons = UNSET; #else conf.icons = 0; #endif /* !_NO_ICONS */ conf.icons_gap = DEF_ICONS_GAP; conf.int_vars = DEF_INT_VARS; conf.light_mode = UNSET; conf.link_creat_mode = DEF_LINK_CREATION_MODE; conf.list_dirs_first = UNSET; conf.listing_mode = UNSET; conf.log_cmds = DEF_LOG_CMDS; conf.log_msgs = DEF_LOG_MSGS; conf.long_view = UNSET; conf.max_dirhist = UNSET; conf.max_files = DEF_MAX_FILES; conf.max_hist = DEF_MAX_HIST; conf.max_log = DEF_MAX_LOG; conf.max_jump_total_rank = DEF_MAX_JUMP_TOTAL_RANK; conf.max_name_len = DEF_MAX_NAME_LEN; conf.max_name_len_bk = 0; conf.max_printselfiles = DEF_MAX_PRINTSEL; conf.min_jump_rank = DEF_MIN_JUMP_RANK; conf.min_name_trunc = DEF_MIN_NAME_TRUNC; conf.mv_cmd = DEF_MV_CMD; conf.no_eln = UNSET; conf.only_dirs = UNSET; conf.pager = UNSET; conf.pager_once = 0; conf.pager_view = UNSET; conf.preview_max_size = DEF_PREVIEW_MAX_SIZE; conf.print_dir_cmds = DEF_PRINT_DIR_CMDS; conf.print_selfiles = UNSET; conf.private_ws_settings = DEF_PRIVATE_WS_SETTINGS; conf.prompt_b_is_set = 0; conf.prompt_b_min = DEF_PROMPT_B_MIN; conf.prompt_b_precision = DEF_PROMPT_B_PRECISION; conf.prompt_f_dir_len = DEF_PROMPT_F_DIR_LEN; conf.prompt_f_full_len_dirs = DEF_PROMPT_F_FULL_LEN_DIRS; conf.prompt_p_max_path = UNSET; conf.prompt_is_multiline = 0; conf.prop_fields_gap = DEF_PROP_FIELDS_GAP; conf.purge_jumpdb = DEF_PURGE_JUMPDB; conf.quoting_style = DEF_QUOTING_STYLE; conf.read_autocmd_files = DEF_READ_AUTOCMD_FILES; conf.read_dothidden = DEF_READ_DOTHIDDEN; conf.readonly = DEF_READONLY; conf.relative_time = DEF_RELATIVE_TIME; conf.restore_last_path = UNSET; conf.rm_force = DEF_RM_FORCE; conf.search_strategy = DEF_SEARCH_STRATEGY; conf.share_selbox = UNSET; conf.show_hidden = UNSET; conf.skip_non_alnum_prefix = DEF_SKIP_NON_ALNUM_PREFIX; conf.sort = UNSET; conf.sort_reverse = 0; conf.splash_screen = UNSET; conf.suggest_filetype_color = DEF_SUG_FILETYPE_COLOR; conf.suggestions = UNSET; conf.time_follows_sort = DEF_TIME_FOLLOWS_SORT; conf.timestamp_mark = DEF_TIMESTAMP_MARK; conf.tips = UNSET; conf.trunc_names = UNSET; #ifndef _NO_TRASH conf.tr_as_rm = UNSET; conf.trash_force = DEF_TRASH_FORCE; #endif /* !_NO_TRASH */ conf.warning_prompt = UNSET; conf.welcome_message = UNSET; conf.encoded_prompt = (char *)NULL; conf.fzftab_options = (char *)NULL; conf.histignore_regex = (char *)NULL; conf.opener = (char *)NULL; #ifndef _NO_SUGGESTIONS conf.suggestion_strategy = (char *)NULL; #endif /* !_NO_SUGGESTIONS */ conf.term = (char *)NULL; conf.time_str = (char *)NULL; conf.priority_sort_char = (char *)NULL; conf.ptime_str = (char *)NULL; conf.rprompt_str = (char *)NULL; conf.usr_cscheme = (char *)NULL; conf.wprompt_str = (char *)NULL; conf.welcome_message_str = (char *)NULL; init_shades(); } static void get_sysusers(void) { if (sys_users || xargs.stat > 0 || prop_fields.ids != PROP_ID_NAME || (xargs.list_and_quit == 1 && conf.long_view != 1)) return; #if defined(__ANDROID__) return; #else /* It may happen (for example on DragonFly) that the passwd database * is not properly rewound (for whatever reason). Let's make sure it is. */ setpwent(); size_t n = 0; while (getpwent()) n++; if (n == 0) { endpwent(); sys_users = (struct groups_t *)NULL; return; } setpwent(); sys_users = xnmalloc(n + 1, sizeof(struct groups_t)); struct passwd *p; n = 0; while ((p = getpwent())) { #ifndef __HAIKU__ /* Some systems (BSD) may have multiple UIDs 0 (e.g.: "root" and "toor"). * This is known as a root alias. Let's always use "root" for UID 0 * (this is what stat(1), ls(1), and most file managers do). */ const char *name = p->pw_uid == 0 ? "root" : p->pw_name; #else const char *name = p->pw_name; #endif /* !__HAIKU__ */ const size_t namlen = strlen(name); sys_users[n].name = savestring(name, namlen); sys_users[n].namlen = namlen; sys_users[n].id = p->pw_uid; n++; } endpwent(); sys_users[n].name = (char *)NULL; sys_users[n].namlen = 0; sys_users[n].id = 0; #endif /* __ANDROID__ */ } static void get_sysgroups(void) { if (sys_groups || prop_fields.ids != PROP_ID_NAME || prop_fields.no_group == 1 || xargs.stat > 0 || (xargs.list_and_quit == 1 && conf.long_view != 1)) return; setgrent(); size_t n = 0; while (getgrent()) n++; if (n == 0) { endgrent(); sys_groups = (struct groups_t *)NULL; return; } setgrent(); sys_groups = xnmalloc(n + 1, sizeof(struct groups_t)); struct group *g; n = 0; while ((g = getgrent())) { const size_t namlen = strlen(g->gr_name); sys_groups[n].name = savestring(g->gr_name, namlen); sys_groups[n].namlen = namlen; sys_groups[n].id = g->gr_gid; n++; } endgrent(); sys_groups[n].name = (char *)NULL; sys_groups[n].namlen = 0; sys_groups[n].id = 0; } void set_prop_fields(const char *line) { if (!line || !*line) return; prop_fields = (struct props_t){0}; prop_fields.len = 2; /* Two spaces between filename and props string */ size_t i; for (i = 0; i < PROP_FIELDS_SIZE && line[i]; i++) { switch (line[i]) { case 'B': prop_fields.blocks = 1; break; case 'f': prop_fields.counter = 1; break; case 'G': prop_fields.no_group = 1; break; case 'd': prop_fields.inode = 1; break; case 'l': prop_fields.links = 1; break; case 'p': prop_fields.perm = PERM_SYMBOLIC; break; case 'n': prop_fields.perm = PERM_NUMERIC; break; case 'i': prop_fields.ids = PROP_ID_NUM; break; case 'I': prop_fields.ids = PROP_ID_NAME; break; case 'a': prop_fields.time = PROP_TIME_ACCESS; break; case 'b': prop_fields.time = PROP_TIME_BIRTH; break; case 'c': prop_fields.time = PROP_TIME_CHANGE; break; case 'm': prop_fields.time = PROP_TIME_MOD; break; case 's': prop_fields.size = PROP_SIZE_HUMAN; break; case 'S': prop_fields.size = PROP_SIZE_BYTES; break; #if defined(LINUX_FILE_XATTRS) case 'x': prop_fields.xattr = 1; break; #endif /* LINUX_FILE_XATTRS */ default: break; } } /* How much space needs to be reserved to print enabled fields? * Only fixed values are counted: dynamic values are calculated * and added in place: for these values we only count here the space * that follows each of them, if enabled. */ /* Static lengths */ if (prop_fields.perm != 0) prop_fields.len += ((prop_fields.perm == PERM_NUMERIC ? 4 : 13) + conf.prop_fields_gap); /* Dynamic lengths */ if (prop_fields.size != 0) prop_fields.len += conf.prop_fields_gap; if (prop_fields.blocks != 0) prop_fields.len += conf.prop_fields_gap; if (prop_fields.counter != 0) prop_fields.len += conf.prop_fields_gap; if (prop_fields.inode != 0) prop_fields.len += conf.prop_fields_gap; if (prop_fields.links != 0) prop_fields.len += conf.prop_fields_gap; if (prop_fields.ids != 0) { prop_fields.len += conf.prop_fields_gap + (prop_fields.no_group == 0); /* Space between user and group */ if (prop_fields.ids == PROP_ID_NAME) { get_sysusers(); get_sysgroups(); } } /* The length of the date field is calculated by check_time_str() */ } int get_sys_shell(void) { if (!user.shell) return SHELL_POSIX; char tmp[PATH_MAX + 1]; *tmp = '\0'; char *ret = xrealpath(user.shell, tmp); if (!ret || !*tmp) return SHELL_POSIX; ret = strrchr(tmp, '/'); if (!ret || !*(ret + 1)) return SHELL_POSIX; char *s = ret + 1; user.shell_basename = savestring(s, strlen(s)); if (*s == 'b' && strcmp(s, "bash") == 0) return SHELL_BASH; if (*s == 'd' && strcmp(s, "dash") == 0) return SHELL_DASH; if (*s == 'f' && strcmp(s, "fish") == 0) return SHELL_FISH; if (*s == 'z' && strcmp(s, "zsh") == 0) return SHELL_ZSH; return SHELL_POSIX; } #ifndef _NO_GETTEXT /* Initialize gettext for translations support */ int init_gettext(void) { char locale_dir[PATH_MAX + 1]; snprintf(locale_dir, sizeof(locale_dir), "%s/locale", data_dir ? data_dir : "/usr/local/share"); bindtextdomain(PROGRAM_NAME, locale_dir); textdomain(PROGRAM_NAME); return FUNC_SUCCESS; } #endif /* !_NO_GETTEXT */ void backup_argv(const int argc, char **argv) { argc_bk = argc; argv_bk = argv; } void init_workspaces(void) { workspaces = xnmalloc(MAX_WS, sizeof(struct ws_t)); int i = MAX_WS; while (--i >= 0) { workspaces[i].path = (char *)NULL; workspaces[i].name = (char *)NULL; } } int get_home(void) { if (!user.home || access(user.home, W_OK) == -1) { /* If no user's home, or if it's not writable, there won't be * any config directory. These flags are used to prevent functions * from trying to access any of these directories. */ home_ok = config_ok = 0; err('e', PRINT_PROMPT, _("%s: Cannot access the home directory. " "Bookmarks, commands logs, and commands history are " "disabled. Program messages, selected files, and the jump database " "will not be persistent. Using default settings.\n"), PROGRAM_NAME); return FUNC_FAILURE; } return FUNC_SUCCESS; } int init_history(void) { /* Shrink the log and the directory history files */ if (msgs_log_file) truncate_file(msgs_log_file, conf.max_log, 0); if (cmds_log_file) truncate_file(cmds_log_file, conf.max_log, 0); if (!hist_file) return FUNC_FAILURE; /* Get history */ history_comment_char = '#'; history_write_timestamps = 1; struct stat attr; if (stat(hist_file, &attr) == 0 && FILE_SIZE(attr) != 0) { /* If the size condition is not included, and in case of a zero * size file, read_history() produces malloc errors */ /* Recover history from the history file */ read_history(hist_file); /* This line adds more leaks to readline */ /* Limit the size of the history file to max_hist lines */ history_truncate_file(hist_file, conf.max_hist); } else { /* If the history file doesn't exist, create it */ int fd = 0; FILE *hist_fp = open_fwrite(hist_file, &fd); if (!hist_fp) { err('w', PRINT_PROMPT, "%s: fopen: '%s': %s\n", PROGRAM_NAME, hist_file, strerror(errno)); } else { /* To avoid malloc errors in read_history(), do not * create an empty file. */ fputs("edit\n", hist_fp); /* There is no need to run read_history() here, since * the history file is still empty. */ fclose(hist_fp); } } return FUNC_SUCCESS; } void check_env_filter(void) { if (filter.str) return; char *p = getenv("CLIFM_FILTER"); if (!p) return; if (*p == '!' || (*p == '\\' && *(p + 1) == '!')) { filter.rev = 1; if (*p == '\\') p++; p++; } else { filter.rev = 0; } filter.env = 1; set_filter_type(*p); filter.str = savestring(p, strlen(p)); } /* Return 1 is secure-env is enabled. Otherwise, return 0. * Used only at an early stage, where command line options haven't been * parsed yet. */ static int is_secure_env(void) { if (!argv_bk) return 0; size_t i; for (i = 0; argv_bk[i]; i++) { if (*argv_bk[i] == '-' #ifndef _BE_POSIX && (strncmp(argv_bk[i], "--secure-", 9) == 0)) #else && strcspn(argv_bk[i], "xXY") != strlen(argv_bk[i])) #endif /* !_BE_POSIX */ return 1; } return 0; } /* Retrieve user groups. * Return an array with the ID's of groups to which the user belongs. * NGROUPS is set to the number of groups. * NOTE: getgroups(2) does not include the user's main group. * We use getgroups(2) on TERMUX because getgrouplist(3) always returns * zero groups. */ static gid_t * get_user_groups(const char *name, const gid_t gid, int *ngroups) { int n = *ngroups; #if defined(__TERMUX__) || defined(_BE_POSIX) UNUSED(name); UNUSED(gid); gid_t *g = xnmalloc(NGROUPS_MAX, sizeof(g)); if ((n = getgroups(NGROUPS_MAX, g)) == -1) { err('e', PRINT_PROMPT, "%s: getgroups: %s\n", PROGRAM_NAME, strerror(errno)); free(g); return (gid_t *)NULL; } if (NGROUPS_MAX > n) /* Reduce array to actual number of groups (N) */ g = xnrealloc(g, (size_t)n, sizeof(g)); #elif defined(__linux__) n = 0; getgrouplist(name, gid, NULL, &n); gid_t *g = xnmalloc((size_t)n, sizeof(g)); getgrouplist(name, gid, g, &n); #else n = NGROUPS_MAX; gid_t *g = xnmalloc((size_t)n, sizeof(g)); # if defined(__APPLE__) getgrouplist(name, (int)gid, (int *)g, &n); # else getgrouplist(name, gid, g, &n); # endif /* __APPLE__ */ if (NGROUPS_MAX > n) g = xnrealloc(g, (size_t)n, sizeof(g)); #endif /* __TERMUX__ || _BE_POSIX */ *ngroups = n; return g; } /* The user specified a custom shell via the CLIFM_SHELL environment variable. * Since this will be used to run shell commands, it's better to make sure * we have a valid shell, that is, one of the shells specified in * '/etc/shells'. * Return FUNC_SUCCESS if found or FUNC_FAILURE if not. */ static int check_etc_shells(const char *file, const char *shells_file, int *tmp_errno) { int fd; FILE *fp = open_fread(shells_file, &fd); if (!fp) { *tmp_errno = errno; return FUNC_FAILURE; } int ret = FUNC_FAILURE; char line[PATH_MAX + 1]; *line = '\0'; while (fgets(line, (int)sizeof(line), fp)) { if (*line != '/') continue; size_t len = strnlen(line, sizeof(line)); if (len > 0 && line[len - 1] == '\n') line[len - 1] = '\0'; if (strcmp(line, file) == 0) { ret = FUNC_SUCCESS; break; } } fclose(fp); return ret; } /* Make sure clifm is not used for $SHELL. This will brake programs using * SHELL to run shell commands. For example, "fzf --preview". */ static void validate_shell(void) { const char *p = xgetenv("SHELL", 0); if (!p) return; #ifdef _PATH_BSHELL const char *def_shell = _PATH_BSHELL; #else const char *def_shell = "/bin/sh"; #endif /* _PATH_BSHELL */ char *q = strrchr(p, '/'); if ((!q && strcmp(p, PROGRAM_NAME) == 0) || (q && q[1] && strcmp(q + 1, PROGRAM_NAME) == 0)) { err('w', PRINT_PROMPT, _("%s: '%s' is not a shell. " "Setting SHELL to '%s'.\n"), PROGRAM_NAME, p, def_shell); unsetenv("SHELL"); setenv("SHELL", def_shell, 1); } } static void validate_custom_shell(char **file) { int tmp_errno = 0; errno = 0; #ifdef _PATH_SHELLS const char *shells_file = _PATH_SHELLS; #else const char *shells_file = "/etc/shells"; #endif /* _PATH_SHELLS */ #ifdef _PATH_BSHELL const char *def_shell = _PATH_BSHELL; #else const char *def_shell = "/bin/sh"; #endif /* _PATH_BSHELL */ if (*file && check_etc_shells(*file, shells_file, &tmp_errno) == FUNC_SUCCESS) return; /* check_etc_shells() sets errno to a positive value only if /etc/shells * couldn't be found/accessed. */ if (tmp_errno == 0) { err('w', PRINT_PROMPT, _("%s: '%s': Invalid shell. Falling back to " "'%s'.\nCheck '%s' for a list of valid shells.\n"), PROGRAM_NAME, *file ? *file : "NULL", def_shell, shells_file); } else { err('w', PRINT_PROMPT, _("%s: '%s': %s.\nCannot validate shell. " "Falling back to '%s'.\n"), PROGRAM_NAME, shells_file, strerror(tmp_errno), def_shell); } free(*file); *file = savestring(def_shell, strlen(def_shell)); } /* Get user data from environment variables. Used only in case getpwuid() failed */ static struct user_t get_user_data_env(void) { struct user_t tmp_user = {0}; /* If secure-env, do not fallback to environment variables */ const int sec_env = is_secure_env(); char *t = sec_env == 0 ? xgetenv("HOME", 0) : (char *)NULL; if (t) { char *p = xrealpath(t, NULL); char *h = p ? p : t; tmp_user.home = savestring(h, strlen(h)); free(p); } struct stat a; if (!tmp_user.home || !*tmp_user.home || stat(tmp_user.home, &a) == -1 || !S_ISDIR(a.st_mode)) { free(tmp_user.home); xerror("%s: Home directory not found. Exiting.\n", PROGRAM_NAME); exit(FUNC_FAILURE); } tmp_user.home_len = strlen(tmp_user.home); t = sec_env == 0 ? xgetenv("USER", 0) : (char *)NULL; tmp_user.name = t ? savestring(t, strlen(t)) : (char *)NULL; tmp_user.gid = getgid(); tmp_user.ngroups = 0; if (tmp_user.name && tmp_user.gid != (gid_t)-1) { tmp_user.groups = get_user_groups(tmp_user.name, tmp_user.gid, &tmp_user.ngroups); } else { tmp_user.groups = (gid_t *)NULL; } char *p = xgetenv("CLIFM_SHELL", 0); t = sec_env == 0 ? (p ? p : xgetenv("SHELL", 0)) : (char *)NULL; tmp_user.shell = t ? savestring(t, strlen(t)) : (char *)NULL; tmp_user.shell_basename = (char *)NULL; if (p && t == p) /* CLIFM_SHELL */ validate_custom_shell(&tmp_user.shell); validate_shell(); return tmp_user; } /* Retrieve user information and store it in a user_t struct for later access */ struct user_t get_user_data(void) { struct passwd *pw = (struct passwd *)NULL; struct user_t tmp_user = {0}; errno = 0; tmp_user.uid = geteuid(); pw = getpwuid(tmp_user.uid); if (!pw) { /* Fallback to environment variables (if not secure-env) */ err('e', PRINT_PROMPT, "%s: getpwuid: %s\n", PROGRAM_NAME, strerror(errno)); return get_user_data_env(); } tmp_user.uid = pw->pw_uid; tmp_user.gid = pw->pw_gid; tmp_user.ngroups = 0; tmp_user.groups = get_user_groups(pw->pw_name, pw->pw_gid, &tmp_user.ngroups); int is_custom_shell = 0; struct stat a; char *homedir = (char *)NULL; if (is_secure_env() == 0) { char *p = xgetenv("USER", 1); tmp_user.name = p ? p : savestring(pw->pw_name, strlen(pw->pw_name)); char *custom_shell = xgetenv("CLIFM_SHELL", 1); p = custom_shell ? custom_shell : xgetenv("SHELL", 1); if (custom_shell) is_custom_shell = 1; tmp_user.shell = p ? p : savestring(pw->pw_shell, strlen(pw->pw_shell)); p = xgetenv("HOME", 0); homedir = p ? p : pw->pw_dir; if (homedir == p && p && (stat(p, &a) == -1 || !S_ISDIR(a.st_mode))) { err('e', PRINT_PROMPT, _("%s: '%s': Home directory not found\n" "Falling back to '%s'\n"), PROGRAM_NAME, p, pw->pw_dir); homedir = pw->pw_dir; } } else { tmp_user.name = savestring(pw->pw_name, strlen(pw->pw_name)); tmp_user.shell = savestring(pw->pw_shell, strlen(pw->pw_shell)); homedir = pw->pw_dir; } if (homedir == pw->pw_dir && (!homedir || stat(homedir, &a) == -1 || !S_ISDIR(a.st_mode))) { xerror(_("%s: '%s': Invalid home directory in the password " "database.\nSomething is really wrong! Exiting.\n"), PROGRAM_NAME, homedir ? homedir : "?"); exit(errno); } if (!homedir) { xerror(_("%s: Home directory not found.\n" "Something is really wrong! Exiting.\n"), PROGRAM_NAME); exit(errno); } /* Sometimes (FreeBSD for example) the home directory, as returned by the * passwd struct, is a symlink, in which case we want to resolve it. * See https://lists.freebsd.org/pipermail/freebsd-arm/2016-July/014404.html */ char *r = xrealpath(homedir, NULL); if (r) { tmp_user.home_len = strlen(r); tmp_user.home = savestring(r, tmp_user.home_len); free(r); } else { tmp_user.home_len = strlen(homedir); tmp_user.home = savestring(homedir, tmp_user.home_len); } tmp_user.shell_basename = (char *)NULL; if (is_custom_shell == 1) validate_custom_shell(&tmp_user.shell); validate_shell(); return tmp_user; } #ifndef _DIRENT_HAVE_D_TYPE static int check_tag(const char *name) { if (!name || !*name) return FUNC_FAILURE; char dir[PATH_MAX + 1]; snprintf(dir, sizeof(dir), "%s/%s", tags_dir, name); struct stat a; if (stat(dir, &a) == -1 || !S_ISDIR(a.st_mode)) return FUNC_FAILURE; return FUNC_SUCCESS; } #endif /* _DIRENT_HAVE_D_TYPE */ void load_tags(void) { if (!tags_dir || !*tags_dir) return; struct dirent **t = (struct dirent **)NULL; int i; const int n = scandir(tags_dir, &t, NULL, alphasort); if (n == -1) return; if (n <= 2) { for (i = 0; i < n; i++) free(t[i]); free(t); return; } tags_n = 0; tags = xnmalloc((size_t)n + 2, sizeof(char **)); for (i = 0; i < n; i++) { #ifdef _DIRENT_HAVE_D_TYPE if (t[i]->d_type != DT_DIR) { free(t[i]); continue; } #else if (check_tag(t[i]->d_name) == FUNC_FAILURE) continue; #endif /* _DIRENT_HAVE_D_TYPE */ if (SELFORPARENT(t[i]->d_name)) { free(t[i]); continue; } tags[tags_n] = savestring(t[i]->d_name, strlen(t[i]->d_name)); tags_n++; free(t[i]); } free(t); tags[tags_n] = (char *)NULL; } /* Make sure no entry in the directory history is absent in the jump database. * * Why do we need this? * Jump entries are stored IN MEMORY and written to disk ONLY AT EXIT, where * the ENTIRE database is rewritten with values taken from this memory, which * is private to the current instance. So, whatever jump entry was added from a * second instance (provided this second instance was closed before the first * one) will be lost. * * One of the drawbacks of this approach is that IT ONLY RETRIEVES NEW ENTRIES * BUT WON'T UPDATE EXISTING ONES with values coming from the second instance: * they're lost. * */ static void sync_jumpdb_with_dirhist(void) { if (!old_pwd) return; int i = dirhist_total_index; size_t j = 0; while (--i >= 0) { if (!old_pwd[i] || !*old_pwd[i]) continue; const size_t old_pwd_len = strlen(old_pwd[i]); int found = 0; for (j = 0; j < jump_n; j++) { if (!jump_db[j].path || !*jump_db[j].path || old_pwd[i][1] != jump_db[j].path[1] || old_pwd_len != jump_db[j].len || old_pwd[i][old_pwd_len - 1] != jump_db[j].path[jump_db[j].len - 1]) continue; if (strcmp(old_pwd[i] + 1, jump_db[j].path + 1) == 0) { found = 1; break; } } if (found == 0) add_to_jumpdb(old_pwd[i]); } } /* Reconstruct the jump database from the database file. */ void load_jumpdb(void) { if (xargs.no_dirjump == 1 || config_ok == 0 || !config_dir) return; char *jump_file = xnmalloc(config_dir_len + 12, sizeof(char)); snprintf(jump_file, config_dir_len + 12, "%s/jump.clifm", config_dir); int fd; FILE *fp = open_fread(jump_file, &fd); if (!fp) { free(jump_file); return; } char tmp_line[PATH_MAX + 32]; *tmp_line = '\0'; size_t jump_lines = 0; while (fgets(tmp_line, (int)sizeof(tmp_line), fp)) { if (*tmp_line == JUMP_ENTRY_PERMANENT_CHR || (*tmp_line >= '0' && *tmp_line <= '9')) jump_lines++; } if (jump_lines == 0) { free(jump_file); fclose(fp); return; } jump_db = xnmalloc(jump_lines + 2, sizeof(struct jump_t)); fseek(fp, 0L, SEEK_SET); size_t line_size = 0; char *line = (char *)NULL; ssize_t line_len = 0; while ((line_len = getline(&line, &line_size, fp)) > 0) { if (*line < '0' && *line != JUMP_ENTRY_PERMANENT_CHR) continue; if (line[line_len - 1] == '\n') line[line_len - 1] = '\0'; if (*line == '@') { if (is_number(line + 1)) { const int a = atoi(line + 1); jump_total_rank = a == INT_MIN ? 0 : a; } continue; } const int keep = *line == JUMP_ENTRY_PERMANENT_CHR ? JUMP_ENTRY_PERMANENT : 0; /* Advance the line pointer one char if marked as permanent, i.e. * starting with '+' */ char *kline = line + (keep > 0); if (*kline < '0' || *kline > '9') continue; char *tmp = strchr(kline, ':'); if (!tmp) continue; *tmp = '\0'; if (!*(++tmp)) continue; int visits = 1; if (is_number(kline)) { visits = atoi(kline); if (visits == INT_MIN) visits = 0; } char *tmpb = strchr(tmp, ':'); if (!tmpb) continue; *tmpb = '\0'; if (!*(++tmpb)) continue; time_t first = 0; if (is_number(tmp)) { const int a = atoi(tmp); first = a == INT_MIN ? 0 : (time_t)a; } char *tmpc = strchr(tmpb, ':'); if (!tmpc) continue; *tmpc = '\0'; if (!*(++tmpc)) continue; /* Purge the database from non-existent directories */ if (conf.purge_jumpdb == 1 && access(tmpc, F_OK) == -1) continue; jump_db[jump_n].visits = (size_t)visits; jump_db[jump_n].first_visit = first; if (is_number(tmpb)) { const int a = atoi(tmpb); jump_db[jump_n].last_visit = a == INT_MIN ? 0 : (time_t)a; } else { jump_db[jump_n].last_visit = 0; /* UNIX Epoch */ } jump_db[jump_n].keep = keep; jump_db[jump_n].rank = 0; jump_db[jump_n].len = strlen(tmpc); jump_db[jump_n].path = savestring(tmpc, jump_db[jump_n].len); jump_n++; } fclose(fp); free(line); free(jump_file); if (jump_n == 0) { free(jump_db); jump_db = (struct jump_t *)NULL; return; } jump_db[jump_n].path = (char *)NULL; jump_db[jump_n].len = 0; jump_db[jump_n].rank = 0; jump_db[jump_n].keep = 0; jump_db[jump_n].visits = 0; jump_db[jump_n].first_visit = -1; sync_jumpdb_with_dirhist(); } static char * save_bm_path(char *file) { if (!file || !*file) return (char *)NULL; char *p = *file != '/' ? normalize_path(file, strlen(file)) : (char *)NULL; return p ? p : savestring(file, strlen(file)); } /* Load bookmarks from the bookmarks file */ int load_bookmarks(void) { if (create_bm_file() == FUNC_FAILURE) return FUNC_FAILURE; if (!bm_file) return FUNC_FAILURE; int fd; FILE *fp = open_fread(bm_file, &fd); if (!fp) return FUNC_FAILURE; size_t bm_total = 0; /* A bookmark line looks like this: [shortcut]name:path * In case this line is longer than PATH_MAX + 64, fgets will count an * extra line, and we'll allocate more memory than necessary, which * doesn't hurt. */ char tmp_line[PATH_MAX + 64]; *tmp_line = '\0'; while (fgets(tmp_line, (int)sizeof(tmp_line), fp)) { if (!*tmp_line || *tmp_line == '#' || *tmp_line == '\n') continue; bm_total++; } if (bm_total == 0) { fclose(fp); return FUNC_SUCCESS; } fseek(fp, 0L, SEEK_SET); bookmarks = xnmalloc(bm_total + 1, sizeof(struct bookmarks_t)); size_t line_size = 0; char *line = (char *)NULL; ssize_t line_len = 0; while ((line_len = getline(&line, &line_size, fp)) > 0) { if (!*line || *line == '\n' || *line == '#') continue; if (line[line_len - 1] == '\n') line[line_len - 1] = '\0'; /* Neither hotkey nor name, but only a path */ if (*line == '/') { bookmarks[bm_n].shortcut = (char *)NULL; bookmarks[bm_n].name = (char *)NULL; bookmarks[bm_n].path = savestring(line, strlen(line)); bm_n++; continue; } if (*line == '[') { char *p = line; p++; char *tmp = strchr(line, ']'); if (!tmp) { bookmarks[bm_n].shortcut = (char *)NULL; bookmarks[bm_n].name = (char *)NULL; bookmarks[bm_n].path = (char *)NULL; bm_n++; continue; } *tmp = '\0'; bookmarks[bm_n].shortcut = savestring(p, strlen(p)); tmp++; p = tmp; tmp = strchr(p, ':'); if (!tmp) { bookmarks[bm_n].name = (char *)NULL; bookmarks[bm_n].path = save_bm_path(p); bm_n++; continue; } *tmp = '\0'; bookmarks[bm_n].name = savestring(p, strlen(p)); if (!*(++tmp)) { bookmarks[bm_n].path = (char *)NULL; bm_n++; continue; } bookmarks[bm_n].path = save_bm_path(tmp); bm_n++; continue; } /* No shortcut. Let's try with name */ bookmarks[bm_n].shortcut = (char *)NULL; char *tmp = strchr(line, ':'); /* No name either */ if (!tmp) { bookmarks[bm_n].name = (char *)NULL; bookmarks[bm_n].path = (char *)NULL; bm_n++; continue; } *tmp = '\0'; bookmarks[bm_n].name = savestring(line, strlen(line)); if (!*(++tmp)) { bookmarks[bm_n].path = (char *)NULL; bm_n++; continue; } else { bookmarks[bm_n].path = save_bm_path(tmp); bm_n++; } } free(line); fclose(fp); if (bm_n == 0) { free(bookmarks); bookmarks = (struct bookmarks_t *)NULL; return FUNC_SUCCESS; } bookmarks[bm_n].name = (char *)NULL; bookmarks[bm_n].path = (char *)NULL; bookmarks[bm_n].shortcut = (char *)NULL; return FUNC_SUCCESS; } /* Load actions from the actions file */ int load_actions(void) { if (config_ok == 0 || !actions_file) return FUNC_FAILURE; /* Free the actions struct array */ if (actions_n > 0) { int i = (int)actions_n; while (--i >= 0) { free(usr_actions[i].name); free(usr_actions[i].value); } free(usr_actions); usr_actions = xnmalloc(1, sizeof(struct actions_t)); actions_n = 0; } /* Open the actions file */ int fd; FILE *fp = open_fread(actions_file, &fd); if (!fp) return FUNC_FAILURE; size_t line_size = 0; char *line = (char *)NULL; ssize_t line_len = 0; while ((line_len = getline(&line, &line_size, fp)) > 0) { if (!line || !*line || *line == '#' || *line == '\n') continue; if (line[line_len - 1] == '\n') line[line_len - 1] = '\0'; char *tmp = strrchr(line, '='); if (!tmp) continue; /* Now copy left and right value of each action into the actions struct */ usr_actions = xnrealloc(usr_actions, (size_t)(actions_n + 1), sizeof(struct actions_t)); usr_actions[actions_n].value = savestring(tmp + 1, strlen(tmp + 1)); *tmp = '\0'; usr_actions[actions_n].name = savestring(line, strlen(line)); actions_n++; } free(line); fclose(fp); return FUNC_SUCCESS; } /* Load remotes information from REMOTES_FILE. */ int load_remotes(void) { if (!remotes_file || !*remotes_file || config_ok == 0) return FUNC_FAILURE; int fd; FILE *fp = open_fread(remotes_file, &fd); if (!fp) { xerror("'%s': %s\n", remotes_file, strerror(errno)); return FUNC_FAILURE; } size_t n = 0; remotes = xnmalloc(n + 1, sizeof(struct remote_t)); remotes[n] = (struct remote_t){0}; size_t line_sz = 0; char *line = (char *)NULL; while (getline(&line, &line_sz, fp) > 0) { if (!*line || *line == '#' || *line == '\n') continue; if (*line == '[') { if (remotes[n].name) n++; remotes = xnrealloc(remotes, n + 2, sizeof(struct remote_t)); remotes[n] = (struct remote_t){0}; char *name = strbtw(line, '[', ']'); if (!name) continue; if (!*name) { free(name); name = (char *)NULL; continue; } const size_t name_len = strlen(name); remotes[n].name = xnrealloc(remotes[n].name, name_len + 1, sizeof(char)); xstrsncpy(remotes[n].name, name, name_len + 1); free(name); name = (char *)NULL; } if (!remotes[n].name) continue; char *ret = strchr(line, '='); if (!ret) continue; if (!*(++ret)) continue; size_t ret_len = strlen(ret); if (ret_len > 0 && ret[ret_len - 1] == '\n') { ret_len--; ret[ret_len] = '\0'; } char *deq_str = remove_quotes(ret); if (deq_str) ret = deq_str; if (strncmp(line, "Comment=", 8) == 0) { remotes[n].desc = xnrealloc(remotes[n].desc, ret_len + 1, sizeof(char)); xstrsncpy(remotes[n].desc, ret, ret_len + 1); } else if (strncmp(line, "Mountpoint=", 11) == 0) { char *tmp = (char *)NULL; if (*ret == '~') tmp = tilde_expand(ret); size_t mnt_len = tmp ? strlen(tmp) : ret_len; remotes[n].mountpoint = xnrealloc(remotes[n].mountpoint, mnt_len + 1, sizeof(char)); xstrsncpy(remotes[n].mountpoint, tmp ? tmp : ret, mnt_len + 1); free(tmp); if (count_dir(remotes[n].mountpoint, CPOP) > 2) remotes[n].mounted = 1; } else if (strncmp(line, "MountCmd=", 9) == 0) { int replaced = 0; if (remotes[n].mountpoint) { char *rep = replace_substr(ret, "%m", remotes[n].mountpoint); if (rep) { size_t rep_len = strlen(rep); remotes[n].mount_cmd = xnrealloc( remotes[n].mount_cmd, rep_len + 1, sizeof(char)); xstrsncpy(remotes[n].mount_cmd, rep, rep_len + 1); free(rep); replaced = 1; } } if (!replaced) { remotes[n].mount_cmd = xnrealloc(remotes[n].mount_cmd, ret_len + 1, sizeof(char)); xstrsncpy(remotes[n].mount_cmd, ret, ret_len + 1); } } else if (strncmp(line, "UnmountCmd=", 11) == 0) { int replaced = 0; if (remotes[n].mountpoint) { char *rep = replace_substr(ret, "%m", remotes[n].mountpoint); if (rep) { size_t rep_len = strlen(rep); remotes[n].unmount_cmd = xnrealloc( remotes[n].unmount_cmd, rep_len + 1, sizeof(char)); xstrsncpy(remotes[n].unmount_cmd, rep, rep_len + 1); free(rep); replaced = 1; } } if (!replaced) { remotes[n].unmount_cmd = xnrealloc(remotes[n].unmount_cmd, ret_len + 1, sizeof(char)); xstrsncpy(remotes[n].unmount_cmd, ret, ret_len + 1); } } else if (strncmp(line, "AutoUnmount=", 12) == 0) { if (strcmp(ret, "true") == 0) remotes[n].auto_unmount = 1; } else { if (strncmp(line, "AutoMount=", 10) == 0) { if (strcmp(ret, "true") == 0) remotes[n].auto_mount = 1; } } } free(line); fclose(fp); if (remotes[n].name) { ++n; remotes[n].name = (char *)NULL; } remotes_n = n; return FUNC_SUCCESS; } static void unset_prompt_values(const size_t n) { prompts[n] = (struct prompts_t){0}; prompts[n].notifications = DEF_PROMPT_NOTIF; prompts[n].warning_prompt_enabled = DEF_WARNING_PROMPT; } static char * set_prompts_file(void) { if (!config_dir_gral || !*config_dir_gral) return (char *)NULL; struct stat a; size_t len = strlen(config_dir_gral) + 15; char *f = xnmalloc(len, sizeof(char)); snprintf(f, len, "%s/prompts.clifm", config_dir_gral); if (stat(f, &a) != -1 && S_ISREG(a.st_mode)) return f; if (!data_dir || !*data_dir) goto ERROR; char t[PATH_MAX + 1]; snprintf(t, sizeof(t), "%s/%s/prompts.clifm", data_dir, PROGRAM_NAME); if (stat(t, &a) == -1 || !S_ISREG(a.st_mode)) goto ERROR; char *cmd[] = {"cp", "--", t, f, NULL}; int ret = launch_execv(cmd, FOREGROUND, E_NOFLAG); if (ret == FUNC_SUCCESS) return f; ERROR: free(f); return (char *)NULL; } static char * set_templates_dir(void) { char *buf = (char *)NULL; const int se = (xargs.secure_env == 1 || xargs.secure_env_full == 1); char *p = se == 0 ? getenv("CLIFM_TEMPLATES_DIR") : (char *)NULL; if (p && *p) { buf = savestring(p, strlen(p)); } else if (se == 0 && (p = getenv("XDG_TEMPLATES_DIR")) && *p) { buf = savestring(p, strlen(p)); } else if (user.home != NULL) { const size_t len = strlen(user.home) + 11; buf = xnmalloc(len, sizeof(char)); snprintf(buf, len, "%s/Templates", user.home); } if (buf && *buf == '~') { p = tilde_expand(buf); free(buf); return p; } return buf; } void load_file_templates(void) { templates_dir = set_templates_dir(); if (!templates_dir || !*templates_dir) return; filesn_t n = 0; struct stat a; if (lstat(templates_dir, &a) == -1 || !S_ISDIR(a.st_mode) || (n = count_dir(templates_dir, NO_CPOP)) <= 2) return; DIR *dir; struct dirent *ent; if ((dir = opendir(templates_dir)) == NULL) return; file_templates = xnmalloc((size_t)n - 1, sizeof(char *)); n = 0; while ((ent = readdir(dir))) { const char *ename = ent->d_name; if (SELFORPARENT(ename)) continue; #ifndef _DIRENT_HAVE_D_TYPE char buf[PATH_MAX + NAME_MAX + 2]; snprintf(buf, sizeof(buf), "%s/%s", templates_dir, ename); if (stat(buf, &a) == -1 || !S_ISREG(a.st_mode)) #else if (ent->d_type != DT_REG) #endif /* !_DIRENT_HAVE_D_TYPE */ continue; file_templates[n] = savestring(ename, strlen(ename)); n++; } closedir(dir); if (n == 0) { free(file_templates); file_templates = (char **)NULL; return; } file_templates[n] = (char *)NULL; } /* Load prompts from PROMPTS_FILE. */ int load_prompts(void) { free_prompts(); free(prompts_file); prompts_file = set_prompts_file(); if (!prompts_file || !*prompts_file) return FUNC_FAILURE; int fd; FILE *fp = open_fread(prompts_file, &fd); if (!fp) { xerror("'%s': %s\n", prompts_file, strerror(errno)); return FUNC_FAILURE; } size_t n = 0; prompts = xnmalloc(n + 1, sizeof(struct prompts_t)); unset_prompt_values(n); size_t line_sz = 0; char *line = (char *)NULL; while (getline(&line, &line_sz, fp) > 0) { if (SKIP_LINE(*line)) continue; if (*line == '[') { if (prompts[n].name) n++; prompts = xnrealloc(prompts, n + 2, sizeof(struct prompts_t)); unset_prompt_values(n); char *name = strbtw(line, '[', ']'); if (!name) continue; if (!*name) { free(name); name = (char *)NULL; continue; } size_t name_len = strlen(name); prompts[n].name = xnrealloc(prompts[n].name, name_len + 1, sizeof(char)); xstrsncpy(prompts[n].name, name, name_len + 1); free(name); name = (char *)NULL; } if (!prompts[n].name) continue; char *ret = strchr(line, '='); if (!ret || !*(++ret)) continue; size_t ret_len = strlen(ret); if (ret_len > 0 && ret[ret_len - 1] == '\n') { ret_len--; ret[ret_len] = '\0'; } if (*line == 'N' && strncmp(line, "Notifications=", 14) == 0) { if (*ret == 't' && strcmp(ret, "true") == 0) prompts[n].notifications = 1; /* NOLINT */ else if (*ret == 'f' && strcmp(ret, "false") == 0) prompts[n].notifications = 0; /* NOLINT */ else prompts[n].notifications = DEF_PROMPT_NOTIF; /* NOLINT */ continue; } char *deq_str = remove_quotes(ret); if (deq_str) ret = deq_str; if (strncmp(line, "RegularPrompt=", 14) == 0) { prompts[n].regular = xnrealloc(prompts[n].regular, ret_len + 1, sizeof(char)); xstrsncpy(prompts[n].regular, ret, ret_len + 1); continue; } if (strncmp(line, "EnableWarningPrompt=", 20) == 0) { if (*ret == 't' && strcmp(ret, "true") == 0) prompts[n].warning_prompt_enabled = 1; /* NOLINT */ else if (*ret == 'f' && strcmp(ret, "false") == 0) prompts[n].warning_prompt_enabled = 0; /* NOLINT */ else prompts[n].warning_prompt_enabled = DEF_WARNING_PROMPT; /* NOLINT */ continue; } if (strncmp(line, "WarningPrompt=", 14) == 0) { prompts[n].warning = xnrealloc(prompts[n].warning, ret_len + 1, sizeof(char)); xstrsncpy(prompts[n].warning, ret, ret_len + 1); } if (strncmp(line, "RightPrompt=", 12) == 0) { prompts[n].right = xnrealloc(prompts[n].right, ret_len + 1, sizeof(char)); xstrsncpy(prompts[n].right, ret, ret_len + 1); if (prompts[n].regular) prompts[n].multiline = strstr(prompts[n].regular, "\\n") ? 1 : 0; } } free(line); fclose(fp); if (prompts[n].name) { n++; prompts[n].name = (char *)NULL; } prompts_n = n; if (conf.encoded_prompt) expand_prompt_name(conf.encoded_prompt); return FUNC_SUCCESS; } void unset_xargs(void) { memset(&xargs, UNSET, sizeof(xargs)); xargs.stat = 0; } /* Store device and inode number of each selected file to identify them * later and mark them as selected in the file list. */ static int set_sel_devino(void) { free(sel_devino); sel_devino = xnmalloc(sel_n + 1, sizeof(struct devino_t)); size_t i; struct stat a; for (i = 0; i < sel_n; i++) { const char *name = sel_elements[i].name; if (fstatat(XAT_FDCWD, name, &a, AT_SYMLINK_NOFOLLOW) == -1) continue; sel_devino[i].ino = a.st_ino; sel_devino[i].dev = a.st_dev; } return FUNC_SUCCESS; } /* Get current entries in the Selection Box, if any. */ int get_sel_files(void) { if (xargs.stealth_mode == 1 && sel_n > 0) return set_sel_devino(); if (selfile_ok == 0 || config_ok == 0 || !sel_file) return FUNC_FAILURE; const size_t selnbk = sel_n; /* First, clear the sel array, in case it was already used. */ if (sel_n > 0) { int i = (int)sel_n; while (--i >= 0) free(sel_elements[i].name); } sel_n = 0; /* Open the tmp sel file and load its contents into the sel array. */ int fd; FILE *fp = open_fread(sel_file, &fd); /* sel_elements = xcalloc(1, sizeof(char *)); */ if (!fp) return FUNC_FAILURE; struct stat a; /* Since this file contains only paths, PATH_MAX should be enough. */ char line[PATH_MAX + 1]; *line = '\0'; while (fgets(line, (int)sizeof(line), fp) != NULL) { size_t len = *line ? strnlen(line, sizeof(line)) : 0; if (len == 0) continue; if (line[len - 1] == '\n') { len--; line[len] = '\0'; } /* Remove the ending slash: fstatat() won't take a symlink to dir as * a symlink (but as a dir), if the filename ends with a slash. */ if (len > 1 && line[len - 1] == '/') { len--; line[len] = '\0'; } if (!*line || *line == '#' || len == 0) continue; if (fstatat(XAT_FDCWD, line, &a, AT_SYMLINK_NOFOLLOW) == -1) continue; sel_elements = xnrealloc(sel_elements, sel_n + 2, sizeof(struct sel_t)); sel_elements[sel_n].name = savestring(line, len); sel_elements[sel_n].size = (off_t)UNSET; sel_n++; sel_elements[sel_n].name = (char *)NULL; sel_elements[sel_n].size = (off_t)UNSET; } fclose(fp); if (sel_n > 0) set_sel_devino(); /* If previous and current number of sel files don't match (mostly * because some selected files were removed), recreate the selections * file to reflect the current state. */ if (selnbk != sel_n) save_sel(); return FUNC_SUCCESS; } /* Store each path in CDPATH env variable in an array (CDPATHS). * Returns the number of paths found or zero if none. */ size_t get_cdpath(void) { if (xargs.secure_env == 1 || xargs.secure_env_full == 1 || xargs.secure_cmds == 1) return 0; const char *p = getenv("CDPATH"); if (!p || !*p) return 0; char *t = strdup(p); if (!t) return 0; /* Get each path in CDPATH */ size_t i, n = 0, len = 0; for (i = 0; t[i]; i++) { /* Store path in CDPATH in a tmp buffer */ char buf[PATH_MAX + 1]; while (t[i] && t[i] != ':' && len < sizeof(buf) - 1) { buf[len] = t[i]; len++; i++; } buf[len] = '\0'; /* Make room in cdpaths for a new path */ cdpaths = xnrealloc(cdpaths, n + 2, sizeof(char *)); /* Dump the buffer into the global cdpaths array */ cdpaths[n] = savestring(buf, len); n++; len = 0; if (!t[i]) break; } cdpaths[n] = (char *)NULL; free(t); return n; } static void get_paths_timestamps(const size_t n) { if (n == 0) return; struct stat a; int i = (int)n; while (--i >= 0) { if (paths[i].path && *paths[i].path && stat(paths[i].path, &a) != -1) paths[i].mtime = a.st_mtime; else paths[i].mtime = 0; } } /* Store all paths in the PATH environment variable in the path field of * the paths_t struct paths, skipping duplicates. * If CHECK_TIMESTAMPS is set to 1, modification time for each path in PATH * is stored in the mtime field of the paths struct. * Returns the number of stored paths. */ size_t get_path_env(const int check_timestamps) { char *ptr = (char *)NULL; int malloced_ptr = 0; /* If running on a sanitized environment, or PATH cannot be retrieved for * whatever reason, get PATH value from a secure source. */ if (xargs.secure_cmds == 1 || xargs.secure_env == 1 || xargs.secure_env_full == 1 || !(ptr = getenv("PATH")) || !*ptr) { malloced_ptr = 1; #if defined(_PATH_STDPATH) ptr = savestring(_PATH_STDPATH, sizeof(_PATH_STDPATH) - 1); #elif defined(_CS_PATH) size_t s = confstr(_CS_PATH, NULL, 0); /* Get value's size */ char *p = xnmalloc(s, sizeof(char)); /* Allocate space */ confstr(_CS_PATH, p, s); /* Get value */ ptr = p; #endif /* _PATH_STDPATH */ } if (!ptr) return 0; if (!*ptr) { if (malloced_ptr == 1) free(ptr); return 0; } char *path_tmp = malloced_ptr == 1 ? ptr : strdup(ptr); if (!path_tmp || !*path_tmp) { free(path_tmp); return 0; } size_t c = count_chars(path_tmp, ':') + 1; paths = xnmalloc(c + 1, sizeof(struct paths_t)); /* Get each path in PATH */ size_t n = 0; char *p = path_tmp, *q = p; while (1) { if (*q && *q != ':' && *(++q)) continue; char d = *q; *q = '\0'; if (*p && (q - p) > 0) { size_t len = (size_t)(q - p); if (len > 1 && p[len - 1] == '/') { p[len - 1] = '\0'; len--; } /* Skip duplicate entries */ size_t i; for (i = 0; i < n; i++) { if (strcmp(paths[i].path, p) == 0) goto CONT; } paths[n].path = savestring(p, len); n++; } CONT: if (!d || n == c) break; p = ++q; } paths[n].path = (char *)NULL; free(path_tmp); if (check_timestamps == 1) get_paths_timestamps(n); return n; } static int validate_line(char *line, char **p, const size_t buflen) { char *s = line; if (!*s || !strchr(s, '/')) return (-1); if (!strchr(s, ':')) return (-1); size_t len = strnlen(s, buflen); if (len > 0 && s[len - 1] == '\n') s[len - 1] = '\0'; int cur = 0; if (*s == '*') { if (!*(++s)) { *p = s; return (-1); } cur = 1; } *p = s; return cur; } /* Set PATH to last visited directory and CUR_WS to last used workspace. */ int get_last_path(void) { if (!config_dir) return FUNC_FAILURE; char *last_file = xnmalloc(config_dir_len + 7, sizeof(char)); snprintf(last_file, config_dir_len + 7, "%s/.last", config_dir); int fd; FILE *fp = open_fread(last_file, &fd); if (!fp) { free(last_file); return FUNC_FAILURE; } /* A line in .last has this form: *WS_NUM:PATH, where WS_NUM is a number * between 0 and 7 (eight workspaces). */ char line[PATH_MAX + 4]; *line = '\0'; while (fgets(line, (int)sizeof(line), fp) != NULL) { char *p = (char *)NULL; const int cur = validate_line(line, &p, sizeof(line)); if (cur == -1) continue; const int ws_n = *p - '0'; if (cur && cur_ws == UNSET) cur_ws = ws_n; if (ws_n >= 0 && ws_n < MAX_WS && !workspaces[ws_n].path) { workspaces[ws_n].path = savestring(p + 2, strnlen(p + 2, sizeof(line) - 2)); } } fclose(fp); free(last_file); return FUNC_SUCCESS; } /* Restore pinned dir from file */ int load_pinned_dir(void) { if (config_ok == 0 || !config_dir) return FUNC_FAILURE; char *pin_file = xnmalloc(config_dir_len + 6, sizeof(char)); snprintf(pin_file, config_dir_len + 6, "%s/.pin", config_dir); int fd; FILE *fp = open_fread(pin_file, &fd); if (!fp) { free(pin_file); return FUNC_FAILURE; } char line[PATH_MAX + 1]; *line = '\0'; if (fgets(line, (int)sizeof(line), fp) == NULL) { free(pin_file); fclose(fp); return FUNC_FAILURE; } if (!*line || !strchr(line, '/')) { free(pin_file); fclose(fp); return FUNC_FAILURE; } if (pinned_dir) { free(pinned_dir); pinned_dir = (char *)NULL; } pinned_dir = savestring(line, strlen(line)); fclose(fp); free(pin_file); return FUNC_SUCCESS; } #if defined(__CYGWIN__) static int check_cmd_ext(const char *s) { if (!s || !*s) return 1; switch (TOUPPER(*s)) { case 'B': // bat return (TOUPPER(s[1]) == 'A' && TOUPPER(s[2]) == 'T' && !s[3]) ? 0 : 1; case 'C': // cmd return (TOUPPER(s[1]) == 'M' && TOUPPER(s[2]) == 'D' && !s[3]) ? 0 : 1; case 'E': // exe return (TOUPPER(s[1]) == 'X' && TOUPPER(s[2]) == 'E' && !s[3]) ? 0 : 1; case 'J': // js, jse return (TOUPPER(s[1]) == 'S' && (!s[2] || (TOUPPER(s[2]) == 'E' && !s[3]) ) ) ? 0 : 1; case 'M': // msc return (TOUPPER(s[1]) == 'S' && TOUPPER(s[2]) == 'C' && !s[3]) ? 0 : 1; case 'V': // vbs, vbe return (TOUPPER(s[1]) == 'B' && (TOUPPER(s[2]) == 'S' || TOUPPER(s[2]) == 'E') && !s[3]) ? 0 : 1; case 'W': // wsf, wsh return (TOUPPER(s[1]) == 'S' && (TOUPPER(s[2]) == 'F' || TOUPPER(s[2]) == 'H') && !s[3]) ? 0 : 1; default: return 1; } } /* Keep only files with executable extension. * Returns 1 if the file named NAME must be excluded or 0 otherwise */ static int cygwin_exclude_file(char *name) { if (!name || !*name) return 1; char *p = strrchr(name, '.'); if (!p || !p[1] || p == name) return 0; *p = '\0'; return check_cmd_ext(p + 1); } #endif /* __CYGWIN__ */ /* Check whether the path NAME is a symbolic link to any other path specified * in PATH. Returns 1 if true or 0 otherwise. * Used to avoid scanning paths which are symlinks to another path, for example, * /bin and /sbin, which are usually symlinks to /usr/bin and /usr/sbin * respectively. */ static int skip_this_path(const char *name) { if (!name || !*name) return 1; struct stat a; if (lstat(name, &a) == -1) return 1; if (!S_ISLNK(a.st_mode)) return 0; char *rpath = xrealpath(name, NULL); if (!rpath) return 1; size_t i; for (i = 0; paths[i].path; i++) { if (*paths[i].path && strcmp(paths[i].path, rpath) == 0) { free(rpath); return 1; } } free(rpath); return 0; } /* Get the list of files in PATH, plus CliFM internal commands, aliases, and * action names, and store them in an array (bin_commands) to be read by * my_rl_completion(). */ void get_path_programs(void) { if (xargs.list_and_quit == 1) return; int i, l = 0, total_cmd = 0; int *cmd_n = (int *)0; struct dirent ***commands_bin = (struct dirent ***)NULL; if (conf.ext_cmd_ok == 1) { commands_bin = xnmalloc(path_n, sizeof(struct dirent)); cmd_n = xnmalloc(path_n, sizeof(int)); i = (int)path_n; while (--i >= 0) { cmd_n[i] = 0; commands_bin[i] = (struct dirent **)NULL; if (!paths[i].path || !*paths[i].path || skip_this_path(paths[i].path) == 1) continue; cmd_n[i] = scandir(paths[i].path, &commands_bin[i], NULL, xalphasort); /* If paths[i] directory is empty, 2 is returned. If it does not * exist, scandir returns -1. * Fedora, for example, adds HOME/bin and HOME/.local/bin to * PATH disregarding if they exist or not. */ if (cmd_n[i] > 2) total_cmd += cmd_n[i] - 2; } } /* Add internal commands */ for (internal_cmds_n = 0; internal_cmds[internal_cmds_n].name; internal_cmds_n++); bin_commands = xnmalloc((size_t)total_cmd + internal_cmds_n + aliases_n + actions_n + 2, sizeof(char *)); i = (int)internal_cmds_n; while (--i >= 0) { bin_commands[l] = savestring(internal_cmds[i].name, internal_cmds[i].len); l++; } /* Now add aliases, if any */ if (aliases_n > 0) { i = (int)aliases_n; while (--i >= 0) { bin_commands[l] = savestring(aliases[i].name, strlen(aliases[i].name)); l++; } } /* And user defined actions too, if any */ if (actions_n > 0) { i = (int)actions_n; while (--i >= 0) { bin_commands[l] = savestring(usr_actions[i].name, strlen(usr_actions[i].name)); l++; } } if (total_cmd > 0) { /* And finally, add commands in PATH */ i = (int)path_n; while (--i >= 0) { if (cmd_n[i] <= 0 || !commands_bin[i]) continue; int j = cmd_n[i]; while (--j >= 0) { #ifdef _DIRENT_HAVE_D_TYPE if (SELFORPARENT(commands_bin[i][j]->d_name) || (commands_bin[i][j]->d_type != DT_REG && commands_bin[i][j]->d_type != DT_LNK)) { #else if (SELFORPARENT(commands_bin[i][j]->d_name)) { #endif /* _DIRENT_HAVE_D_TYPE */ free(commands_bin[i][j]); continue; } #ifdef __CYGWIN__ if (cygwin_exclude_file(commands_bin[i][j]->d_name) == 1) { free(commands_bin[i][j]); continue; } #endif /* __CYGWIN__ */ bin_commands[l] = savestring(commands_bin[i][j]->d_name, strlen(commands_bin[i][j]->d_name)); l++; free(commands_bin[i][j]); } free(commands_bin[i]); } } free(commands_bin); free(cmd_n); path_progsn = (size_t)l; bin_commands[l] = (char *)NULL; } static void free_aliases(void) { int i = (int)aliases_n; while (--i >= 0) { free(aliases[i].name); free(aliases[i].cmd); } free(aliases); aliases = xnmalloc(1, sizeof(struct alias_t)); aliases_n = 0; } static void write_alias(const char *s, char *p) { aliases = xnrealloc(aliases, aliases_n + 2, sizeof(struct alias_t)); aliases[aliases_n].name = savestring(s, strlen(s)); int add = 0; if (*p == '\'') { aliases[aliases_n].cmd = strbtw(p, '\'', '\''); aliases_n++; add = 1; } else { if (*p == '"') { aliases[aliases_n].cmd = strbtw(p, '"', '"'); aliases_n++; add = 1; } } if (add == 1) { aliases[aliases_n].name = (char *)NULL; aliases[aliases_n].cmd = (char *)NULL; } } static int alias_exists(const char *s) { int i = (int)aliases_n; while (--i >= 0) { if (!aliases[i].name) continue; if (*s == *aliases[i].name && strcmp(s, aliases[i].name) == 0) return 1; } return 0; } void get_aliases(void) { if (config_ok == 0 || !config_file) return; int fd; FILE *fp = open_fread(config_file, &fd); if (!fp) { err('e', PRINT_PROMPT, "%s: alias: '%s': %s\n", PROGRAM_NAME, config_file, strerror(errno)); return; } if (aliases_n > 0) free_aliases(); char *line = (char *)NULL; size_t line_size = 0; while (getline(&line, &line_size, fp) > 0) { if (*line == 'a' && strncmp(line, "alias ", 6) == 0) { char *s = strchr(line, ' '); if (!s || !*(++s)) continue; char *p = strchr(s, '='); if (!p || !*(p + 1)) continue; *p = '\0'; p++; if (alias_exists(s) == 1) continue; write_alias(s, p); } } free(line); fclose(fp); } static void write_dirhist(char *line, ssize_t len) { if (!line || !*line || *line == '\n') return; if (len > 0 && line[len - 1] == '\n') { line[len - 1] = '\0'; len--; } old_pwd[dirhist_total_index] = xnmalloc((size_t)len + 1, sizeof(char)); xstrsncpy(old_pwd[dirhist_total_index], line, (size_t)len + 1); dirhist_total_index++; } int load_dirhist(void) { if (config_ok == 0 || !dirhist_file) return FUNC_FAILURE; truncate_file(dirhist_file, conf.max_dirhist, 1); int fd; FILE *fp = open_fread(dirhist_file, &fd); if (!fp) return FUNC_FAILURE; size_t dirs = 0; /* A dirhist line is just a path, so that PATH_MAX should be enough */ char tmp_line[PATH_MAX + 1]; *tmp_line = '\0'; while (fgets(tmp_line, (int)sizeof(tmp_line), fp)) dirs++; if (dirs == 0) { fclose(fp); return FUNC_SUCCESS; } old_pwd = xnmalloc(dirs + 2, sizeof(char *)); fseek(fp, 0L, SEEK_SET); size_t line_size = 0; char *line = (char *)NULL; ssize_t line_len = 0; dirhist_total_index = 0; while ((line_len = getline(&line, &line_size, fp)) > 0) write_dirhist(line, line_len); fclose(fp); old_pwd[dirhist_total_index] = (char *)NULL; free(line); dirhist_cur_index = dirhist_total_index - 1; return FUNC_SUCCESS; } static void free_prompt_cmds(void) { size_t i; for (i = 0; i < prompt_cmds_n; i++) free(prompt_cmds[i]); free(prompt_cmds); prompt_cmds = (char **)NULL; prompt_cmds_n = 0; } void get_prompt_cmds(void) { if (config_ok == 0 || !config_file) return; int fd; FILE *fp = open_fread(config_file, &fd); if (!fp) { err('e', PRINT_PROMPT, "%s: prompt: '%s': %s\n", PROGRAM_NAME, config_file, strerror(errno)); return; } if (prompt_cmds_n) free_prompt_cmds(); char *line = (char *)NULL; size_t line_size = 0; ssize_t line_len = 0; while ((line_len = getline(&line, &line_size, fp)) > 0) { if (*line != 'p' || strncmp(line, "promptcmd ", 10) != 0) continue; if (line[line_len - 1] == '\n') line[line_len - 1] = '\0'; if (!(*line + 10)) continue; prompt_cmds = xnrealloc(prompt_cmds, prompt_cmds_n + 1, sizeof(char *)); prompt_cmds[prompt_cmds_n] = savestring( line + 10, (size_t)line_len - 10); prompt_cmds_n++; } free(line); fclose(fp); } /* Get the length of the current time format. * We need this to construct the time string in case of invalid timestamp (0), * and to calculate the space left to print filenames in long view. */ /* GCC (not clang though) complains about tfmt being not a string literal. * Let's silence this warning until we find a better approach. * This shouldn't be a problem, however, since the use of non string literals * for the format string is documented in the strftime manpage itself. */ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wformat-nonliteral" static void check_time_str(void) { if (prop_fields.time == 0) return; if (conf.relative_time == 1) { /* +1 = extra space to avoid hitting the screen right edge in long view. */ prop_fields.len += (7 + 1) + (conf.timestamp_mark == 1 ? 1 : 0); xstrsncpy(invalid_time_str, " - ", sizeof(invalid_time_str)); return; } /* Get length of the current time format. */ struct tm tm; time_t t = time(NULL); char tim[MAX_TIME_STR]; char *tfmt = conf.time_str ? conf.time_str : DEF_TIME_STYLE_OLDER; size_t l = localtime_r(&t, &tm) ? strftime(tim, sizeof(tim), tfmt, &tm) : 0; /* Construct the invalid time format string (used when we get an * invalid file timestamp). */ if (l > MAX_TIME_STR) l = MAX_TIME_STR; size_t i; *invalid_time_str = '-'; for (i = 1; i < l; i++) invalid_time_str[i] = ' '; invalid_time_str[i] = '\0'; /* Append the time string length to the properties total length, so that * we can better calculate how much space left we have to print filenames. */ prop_fields.len += (int)(l + 1) + (conf.timestamp_mark == 1 ? 1 : 0); } #pragma GCC diagnostic pop static void set_sudo_cmd(void) { if (sudo_cmd) return; sudo_cmd = (xargs.secure_env != 1 && xargs.secure_env_full != 1 && xargs.secure_cmds != 1) ? getenv("CLIFM_SUDO_CMD") : (char *)NULL; if (!sudo_cmd || !*sudo_cmd) { sudo_cmd = DEF_SUDO_CMD; return; } char *sudo_path = get_cmd_path(sudo_cmd); if (sudo_path) { free(sudo_path); return; } err('w', PRINT_PROMPT, _("%s: %s: %s\nInvalid authentication program " "(falling back to '%s')\n"), PROGRAM_NAME, sudo_cmd, strerror(errno), DEF_SUDO_CMD); sudo_cmd = DEF_SUDO_CMD; } #ifndef _NO_FZF static void set_fzftab_options(void) { if (fzftab == UNSET) { if (xargs.fzftab == UNSET) { /* This flag will be true only when reloading the config file, * because the check for the fzf binary is made at startup AFTER * reading the config file (check_third_party_cmds() in checks.c). */ if (bin_flags & FZF_BIN_OK) fzftab = 1; } else { fzftab = xargs.fzftab; } if (xargs.fnftab == 1) tabmode = FNF_TAB; else if (xargs.fzftab == 1) tabmode = FZF_TAB; else if (xargs.smenutab == 1) tabmode = SMENU_TAB; else tabmode = STD_TAB; } if (!conf.fzftab_options) { if (conf.colorize == 1 || !getenv("FZF_DEFAULT_OPTS")) { if (conf.colorize == 1) { conf.fzftab_options = savestring(DEF_FZFTAB_OPTIONS, sizeof(DEF_FZFTAB_OPTIONS) - 1); } else { conf.fzftab_options = savestring(DEF_FZFTAB_OPTIONS_NO_COLOR, sizeof(DEF_FZFTAB_OPTIONS_NO_COLOR) - 1); } } else { conf.fzftab_options = savestring("", 1); } } set_fzf_preview_border_type(); smenutab_options_env = (xargs.secure_env_full != 1 && tabmode == SMENU_TAB) ? getenv("CLIFM_SMENU_OPTIONS") : (char *)NULL; if (smenutab_options_env && sanitize_cmd(smenutab_options_env, SNT_BLACKLIST) != 0) { err('w', PRINT_PROMPT, "%s: CLIFM_SMENU_OPTIONS contains unsafe " "characters (<>|;&$`). Falling back to default values.\n", PROGRAM_NAME); smenutab_options_env = (char *)NULL; } } #endif /* !_NO_FZF */ static void set_encoded_prompt(void) { free(conf.encoded_prompt); if (conf.colorize == 1) { conf.encoded_prompt = savestring(DEFAULT_PROMPT, sizeof(DEFAULT_PROMPT) - 1); } else { conf.encoded_prompt = savestring(DEFAULT_PROMPT_NO_COLOR, sizeof(DEFAULT_PROMPT_NO_COLOR) - 1); } } static char * set_warning_prompt_str(void) { return (conf.colorize == 1 ? savestring(DEF_WPROMPT_STR, sizeof(DEF_WPROMPT_STR) - 1) : savestring(DEF_WPROMPT_STR_NO_COLOR, sizeof(DEF_WPROMPT_STR_NO_COLOR) - 1)); } #define SETOPT(cmd_line, def) ((cmd_line) == UNSET ? (def) : (cmd_line)) /* If some option was not set, set it to the default value. */ void check_options(void) { set_sudo_cmd(); if (xargs.secure_env == 1 || xargs.secure_env_full == 1) conf.read_autocmd_files = 0; if (!conf.histignore_regex && regcomp(®ex_hist, DEF_HISTIGNORE, REG_NOSUB | REG_EXTENDED) == 0) { conf.histignore_regex = savestring(DEF_HISTIGNORE, sizeof(DEF_HISTIGNORE) - 1); } if (conf.pager_view == UNSET) conf.pager_view = SETOPT(xargs.pager_view, DEF_PAGER_VIEW); if (conf.color_lnk_as_target == UNSET) conf.color_lnk_as_target = SETOPT(xargs.color_lnk_as_target, DEF_COLOR_LNK_AS_TARGET); if (conf.trunc_names == UNSET) conf.trunc_names = SETOPT(xargs.trunc_names, DEF_TRUNC_NAMES); conf.max_name_len_bk = conf.max_name_len; if (conf.trunc_names == 0) conf.max_name_len = UNSET; if (conf.fuzzy_match == UNSET) conf.fuzzy_match = SETOPT(xargs.fuzzy_match, DEF_FUZZY_MATCH); if (conf.fuzzy_match_algo == UNSET) conf.fuzzy_match_algo = SETOPT(xargs.fuzzy_match_algo, DEF_FUZZY_MATCH_ALGO); if (conf.desktop_notifications == UNSET) conf.desktop_notifications = SETOPT(xargs.desktop_notifications, DEF_DESKTOP_NOTIFICATIONS); if (!*prop_fields_str) xstrsncpy(prop_fields_str, DEF_PROP_FIELDS, sizeof(prop_fields_str)); set_prop_fields(prop_fields_str); check_time_str(); if (xargs.eln_use_workspace_color == UNSET) xargs.eln_use_workspace_color = DEF_ELN_USE_WORKSPACE_COLOR; if (xargs.refresh_on_empty_line == UNSET) xargs.refresh_on_empty_line = DEF_REFRESH_ON_EMPTY_LINE; if (print_removed_files == UNSET) print_removed_files = DEF_PRINT_REMOVED_FILES; if (xargs.refresh_on_resize == UNSET) xargs.refresh_on_resize = DEF_REFRESH_ON_RESIZE; if (xargs.si == UNSET) xargs.si = DEF_SI; if (hist_status == UNSET) hist_status = SETOPT(xargs.history, DEF_HIST_STATUS); /* Do no override command line options */ if (xargs.cwd_in_title == UNSET) xargs.cwd_in_title = DEF_CWD_IN_TITLE; if (xargs.report_cwd == UNSET) xargs.report_cwd = DEF_REPORT_CWD; if (xargs.secure_cmds == UNSET) xargs.secure_cmds = DEF_SECURE_CMDS; if (xargs.secure_env == UNSET) xargs.secure_env = DEF_SECURE_ENV; if (xargs.secure_env_full == UNSET) xargs.secure_env_full = DEF_SECURE_ENV_FULL; if (conf.no_eln == UNSET) conf.no_eln = SETOPT(xargs.no_eln, DEF_NOELN); if (prompt_notif == UNSET) prompt_notif = DEF_PROMPT_NOTIF; #ifndef _NO_HIGHLIGHT if (conf.highlight == UNSET) conf.highlight = SETOPT(xargs.highlight, DEF_HIGHLIGHT); #endif /* !_NO_HIGHLIGHT */ if (conf.apparent_size == UNSET) conf.apparent_size = SETOPT(xargs.apparent_size, DEF_APPARENT_SIZE); if (conf.full_dir_size == UNSET) conf.full_dir_size = SETOPT(xargs.full_dir_size, DEF_FULL_DIR_SIZE); if (conf.warning_prompt == UNSET) conf.warning_prompt = SETOPT(xargs.warning_prompt, DEF_WARNING_PROMPT); if (conf.listing_mode == UNSET) { if (xargs.horizontal_list == UNSET) conf.listing_mode = DEF_LISTING_MODE; else conf.listing_mode = xargs.horizontal_list ? 1 : 0; } #ifndef _NO_FZF set_fzftab_options(); #else tabmode = STD_TAB; #endif /* !_NO_FZF */ #ifndef _NO_LIRA if (xargs.stealth_mode == 1) { xargs.fzf_preview = conf.fzf_preview = 0; } else if (conf.fzf_preview == UNSET) { conf.fzf_preview = SETOPT(xargs.fzf_preview, DEF_FZF_PREVIEW); } #else if (conf.fzf_preview == UNSET) xargs.fzf_preview = conf.fzf_preview = 0; #endif /* !_NO_LIRA */ #ifndef _NO_ICONS if (conf.icons == UNSET) conf.icons = SETOPT(xargs.icons, DEF_ICONS); #endif /* _NO_ICONS */ #ifndef _NO_SUGGESTIONS if (conf.suggestions == UNSET) conf.suggestions = SETOPT(xargs.suggestions, DEF_SUGGESTIONS); if (!conf.suggestion_strategy) conf.suggestion_strategy = savestring(DEF_SUG_STRATEGY, SUG_STRATS); #endif /* _NO_SUGGESTIONS */ if (conf.print_selfiles == UNSET) conf.print_selfiles = SETOPT(xargs.print_selfiles, DEF_PRINTSEL); if (conf.case_sens_list == UNSET) conf.case_sens_list = SETOPT(xargs.case_sens_list, DEF_CASE_SENS_LIST); if (conf.case_sens_dirjump == UNSET) conf.case_sens_dirjump = SETOPT(xargs.case_sens_dirjump, DEF_CASE_SENS_DIRJUMP); if (conf.case_sens_path_comp == UNSET) conf.case_sens_path_comp = SETOPT(xargs.case_sens_path_comp, DEF_CASE_SENS_PATH_COMP); #ifndef _NO_TRASH if (conf.tr_as_rm == UNSET) conf.tr_as_rm = SETOPT(xargs.trasrm, DEF_TRASRM); #endif /* _NO_TRASH */ if (conf.only_dirs == UNSET) conf.only_dirs = SETOPT(xargs.only_dirs, DEF_ONLY_DIRS); if (conf.splash_screen == UNSET) conf.splash_screen = SETOPT(xargs.splash_screen, DEF_SPLASH_SCREEN); if (conf.welcome_message == UNSET) conf.welcome_message = SETOPT(xargs.welcome_message, DEF_WELCOME_MESSAGE); if (conf.show_hidden == UNSET) conf.show_hidden = SETOPT(xargs.show_hidden, DEF_SHOW_HIDDEN); if (conf.files_counter == UNSET) conf.files_counter = SETOPT(xargs.files_counter, DEF_FILES_COUNTER); if (conf.long_view == UNSET) conf.long_view = SETOPT(xargs.long_view, DEF_LONG_VIEW); if (conf.ext_cmd_ok == UNSET) conf.ext_cmd_ok = SETOPT(xargs.ext_cmd_ok, DEF_EXT_CMD_OK); if (conf.pager == UNSET) conf.pager = SETOPT(xargs.pager, DEF_PAGER); if (conf.max_dirhist == UNSET) conf.max_dirhist = SETOPT(xargs.max_dirhist, DEF_MAX_DIRHIST); if (conf.clear_screen == UNSET) conf.clear_screen = SETOPT(xargs.clear_screen, DEF_CLEAR_SCREEN); if (conf.list_dirs_first == UNSET) conf.list_dirs_first = SETOPT(xargs.list_dirs_first, DEF_LIST_DIRS_FIRST); if (conf.autols == UNSET) conf.autols = SETOPT(xargs.autols, DEF_AUTOLS); if (xargs.prompt_p_max_path != UNSET) err('n', PRINT_PROMPT, "%s: --max-path: This option is " "deprecated. Use the CLIFM_PROMPT_P_MAX_PATH environment " "variable instead.\n", PROGRAM_NAME); if (conf.prompt_p_max_path == UNSET) conf.prompt_p_max_path = SETOPT(xargs.prompt_p_max_path, DEF_PROMPT_P_MAX_PATH); if (conf.light_mode == UNSET) conf.light_mode = SETOPT(xargs.light_mode, DEF_LIGHT_MODE); if (conf.classify == UNSET) conf.classify = SETOPT(xargs.classify, DEF_CLASSIFY); if (conf.share_selbox == UNSET) conf.share_selbox = SETOPT(xargs.share_selbox, DEF_SHARE_SELBOX); if (conf.sort == UNSET) conf.sort = SETOPT(xargs.sort, DEF_SORT); if (conf.sort_reverse == UNSET) conf.sort_reverse = SETOPT(xargs.sort_reverse, DEF_SORT_REVERSE); if (conf.tips == UNSET) conf.tips = SETOPT(xargs.tips, DEF_TIPS); if (conf.autocd == UNSET) conf.autocd = SETOPT(xargs.autocd, DEF_AUTOCD); if (conf.auto_open == UNSET) conf.auto_open = SETOPT(xargs.auto_open, DEF_AUTO_OPEN); if (conf.cd_on_quit == UNSET) conf.cd_on_quit = SETOPT(xargs.cd_on_quit, DEF_CD_ON_QUIT); if (conf.dirhist_map == UNSET) conf.dirhist_map = SETOPT(xargs.dirhist_map, DEF_DIRHIST_MAP); if (conf.disk_usage == UNSET) conf.disk_usage = SETOPT(xargs.disk_usage, DEF_DISK_USAGE); if (conf.restore_last_path == UNSET) conf.restore_last_path = SETOPT(xargs.restore_last_path, DEF_RESTORE_LAST_PATH); if (!conf.term) conf.term = savestring(DEF_TERM_CMD, sizeof(DEF_TERM_CMD) - 1); if (conf.colorize == 0) expand_prompt_name(DEF_PROMPT_NO_COLOR_NAME); if (!conf.encoded_prompt || !*conf.encoded_prompt) set_encoded_prompt(); set_prompt_options(); if (!conf.wprompt_str) conf.wprompt_str = set_warning_prompt_str(); if ((xargs.stealth_mode == 1 || home_ok == 0 || config_ok == 0 || !config_file) && !*div_line) { xstrsncpy(div_line, term_caps.unicode == 1 ? DEF_DIV_LINE_U : DEF_DIV_LINE, sizeof(div_line)); } if (xargs.stealth_mode == 1 && !conf.opener) { /* Since in stealth mode we have no access to the config file, we cannot * use Lira, since it relays on a file. Set it thus to FALLBACK_OPENER, * if not already set via command line. */ conf.opener = savestring(FALLBACK_OPENER, sizeof(FALLBACK_OPENER) - 1); } #ifndef _NO_SUGGESTIONS if (term_caps.suggestions == 0) xargs.suggestions = conf.suggestions = 0; #endif /* !_NO_SUGGESTIONS */ if (term_caps.color == 0) xargs.colorize = conf.colorize = 0; if (term_caps.pager == 0) xargs.pager = conf.pager = 0; #ifndef ST_BTIME # define BTIME_NOT_AVAIL "Birth time is not available on this platform. \ Falling back to modification time." if (conf.sort == SBTIME) { err('w', PRINT_PROMPT, "Sort: %s\n", BTIME_NOT_AVAIL); conf.sort = SMTIME; } if (prop_fields.time == PROP_TIME_BIRTH) { err('w', PRINT_PROMPT, "PropFields: %s\n", BTIME_NOT_AVAIL); prop_fields.time = PROP_TIME_MOD; } #endif /* !ST_BTIME */ reset_opts(); } #undef SETOPT clifm-1.26.3/src/init.h000066400000000000000000000036051506632037700146150ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* init.h */ #ifndef INIT_H #define INIT_H __BEGIN_DECLS void backup_argv(const int argc, char **argv); void check_env_filter(void); void check_options(void); void get_aliases(void); size_t get_cdpath(void); #ifdef LINUX_FSINFO void get_ext_mountpoints(void); #endif /* LINUX_FSINFO */ int get_home(void); int get_last_path(void); size_t get_path_env(const int check_timestamps); void get_path_programs(void); void get_prompt_cmds(void); int get_sel_files(void); int get_sys_shell(void); struct user_t get_user_data(void); void init_conf_struct(void); int init_gettext(void); int init_history(void); void init_shell(void); void init_workspaces(void); void init_workspaces_opts(void); int load_actions(void); int load_bookmarks(void); int load_dirhist(void); void load_file_templates(void); void load_jumpdb(void); int load_pinned_dir(void); int load_prompts(void); int load_remotes(void); void load_tags(void); int restore_shell(void); void set_prop_fields(const char *line); void unset_xargs(void); __END_DECLS #endif /* INIT_H */ clifm-1.26.3/src/jump.c000066400000000000000000000613401506632037700146200ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* jump.c -- functions for Kangaroo, the directory jumper function */ #include "helpers.h" #include #include #include #include /* unlink(3) */ #if defined(__OpenBSD__) || defined(__NetBSD__) \ || defined(__FreeBSD__) || defined(__APPLE__) || defined(__HAIKU__) # include /* intmax_t */ #endif /* BSD || __HAIKU__ */ #include "aux.h" #include "checks.h" #include "colors.h" /* get_dir_color() */ #include "file_operations.h" #include "init.h" #include "messages.h" #include "misc.h" #include "navigation.h" #include "spawn.h" /* Macros to calculate directories rank extra points */ #define BASENAME_BONUS 300 #define BOOKMARK_BONUS 500 #define PERMANENT_BONUS 300 #define PINNED_BONUS 1000 #define WORKSPACE_BONUS 300 #define VISIT_BONUS 200 /* Calculate last directory access credit */ #define JHOUR(n) ((n) *= 4) /* Within last hour */ #define JDAY(n) ((n) *= 2) /* Within last day */ #define JWEEK(n) ((n) / 2) /* Within last week */ #define JOLDER(n) ((n) / 4) /* More than a week */ #define IS_VALID_JUMP_ENTRY(n) ((!jump_db[(n)].path || !*jump_db[(n)].path \ || jump_db[(n)].rank == JUMP_ENTRY_PURGED) ? 0 : 1) struct jump_entry_t { char *match; char *needle; size_t keep; size_t visits; time_t first; time_t last; }; #define FIRST_SEGMENT (1 << 0) #define LAST_SEGMENT (1 << 1) /* Getting the total rank of an entry: * 1) rank = calculate_base_credit() * 2) rank += calculate_bonus_credit() */ /* Calcualte the base credit for a directory based on time data * (DAYS_SINCE_FIRST and HOURS_SINCE_LAST) and number of visits (VISITS). * If the directory has been visited within the last day, KEEP will be * set to 1, so that it won't be removed from the database, no matter * its current rank. */ static int calculate_base_credit(const int days_since_first, const int hours_since_last, const int visits, int *keep) { int rank = days_since_first > 1 ? ((int)visits * VISIT_BONUS) / days_since_first : ((int)visits * VISIT_BONUS); /* Credit or penalty based on last directory access. */ int tmp_rank = rank; if (hours_since_last == 0) { /* Last hour */ *keep = 1; rank = JHOUR(tmp_rank); } else if (hours_since_last <= 24) { /* Last day */ *keep = 1; rank = JDAY(tmp_rank); } else if (hours_since_last <= 168) { /* Last week */ rank = JWEEK(tmp_rank); } else { /* More than a week */ rank = JOLDER(tmp_rank); } return rank; } /* Calculate bonus credit for the entry ENTRY. * Matches in directory basename, bookmarked and pinned directories, * just as directories currently in a workspace, have bonus credit. */ static int calculate_bonus_credit(const char *entry, const char *query, int *keep) { if (!entry || !*entry) return 0; int bonus = 0; const char *tmp = query ? strrchr(entry, '/') : (char *)NULL; if (tmp && *(++tmp)) { if (strstr(tmp, query)) bonus += BASENAME_BONUS; } int i = (int)bm_n; while (--i >= 0) { if (bookmarks[i].path && *bookmarks[i].path && bookmarks[i].path[1] == entry[1] && strcmp(bookmarks[i].path, entry) == 0) { *keep = 1; bonus += BOOKMARK_BONUS; break; } } if (pinned_dir && *pinned_dir && pinned_dir[1] == entry[1] && strcmp(pinned_dir, entry) == 0) { *keep = 1; bonus += PINNED_BONUS; } i = MAX_WS; while (--i >= 0) { if (workspaces[i].path && *workspaces[i].path && workspaces[i].path[1] == entry[1] && strcmp(workspaces[i].path, entry) == 0) { *keep = 1; bonus += WORKSPACE_BONUS; break; } } return bonus; } /* Calculate the rank as frecency. The algorithm is based * on Mozilla, zoxide, and z.lua. See: * "https://wiki.mozilla.org/User:Mconnor/Past/PlacesFrecency" * "https://github.com/ajeetdsouza/zoxide/wiki/Algorithm#aging" * "https://github.com/skywind3000/z.lua#aging" */ static int rank_entry(const int i, const time_t now, int *days_since_first, int *hours_since_last) { /* 86400 = 60 secs / 60 mins / 24 hours */ *days_since_first = (int)(now - jump_db[i].first_visit) / 86400; /* 3600 = 60 secs / 60 mins */ *hours_since_last = (int)(now - jump_db[i].last_visit) / 3600; int keep = 0; int rank = calculate_base_credit(*days_since_first, *hours_since_last, (int)jump_db[i].visits, &keep); rank += calculate_bonus_credit(jump_db[i].path, (char *)NULL, &keep); if (jump_db[i].keep == JUMP_ENTRY_PERMANENT) rank += PERMANENT_BONUS; else jump_db[i].keep = keep; return rank; } static void free_jump_database(void) { int i = (int)jump_n; while (--i >= 0) free(jump_db[i].path); free(jump_db); jump_db = (struct jump_t *)NULL; jump_n = 0; } static int add_new_jump_entry(const char *dir, const size_t dir_len) { jump_db = xnrealloc(jump_db, jump_n + 2, sizeof(struct jump_t)); jump_db[jump_n].visits = 1; const time_t now = time(NULL); jump_db[jump_n].first_visit = now; jump_db[jump_n].last_visit = now; jump_db[jump_n].rank = 0; jump_db[jump_n].keep = 0; jump_db[jump_n].len = dir_len; jump_db[jump_n].path = savestring(dir, dir_len); jump_n++; jump_db[jump_n].path = (char *)NULL; jump_db[jump_n].len = 0; jump_db[jump_n].visits = 0; jump_db[jump_n].rank = 0; jump_db[jump_n].keep = 0; jump_db[jump_n].first_visit = -1; jump_db[jump_n].last_visit = -1; return FUNC_SUCCESS; } /* Add DIR to the jump database. If already there, just update the number of * visits and the last visit time. */ int add_to_jumpdb(char *dir) { if (xargs.no_dirjump == 1 || !dir || !*dir) return FUNC_FAILURE; size_t dir_len = strlen(dir); if (dir_len > 1 && dir[dir_len - 1] == '/') { dir[dir_len - 1] = '\0'; dir_len--; } if (!jump_db) { jump_db = xnmalloc(1, sizeof(struct jump_t)); jump_n = 0; } int i = (int)jump_n, new_entry = 1; while (--i >= 0) { /* Jump entries are all absolute paths, so that they all start with * a slash. Let's start comparing them from the second char. */ if (!IS_VALID_JUMP_ENTRY(i) || dir_len != jump_db[i].len || dir[1] != jump_db[i].path[1]) continue; if (strcmp(jump_db[i].path, dir) == 0) { jump_db[i].visits++; jump_db[i].last_visit = time(NULL); new_entry = 0; break; } } if (new_entry == 0) return FUNC_SUCCESS; return add_new_jump_entry(dir, dir_len); } /* Save the jump database into a file. */ void save_jumpdb(void) { if (xargs.no_dirjump == 1 || config_ok == 0 || !config_dir || !jump_db || jump_n == 0) return; char jump_file[PATH_MAX + 1]; snprintf(jump_file, sizeof(jump_file), "%s/jump.clifm", config_dir); int fd = 0; FILE *fp = open_fwrite(jump_file, &fd); if (!fp) return; int i, reduce = 0, total_rank = 0; const time_t now = time(NULL); /* Calculate both total rank sum, and rank for each entry. */ i = (int)jump_n; while (--i >= 0) { if (!IS_VALID_JUMP_ENTRY(i)) continue; int days_since_first = 0, hours_since_last = 0; const int rank = rank_entry(i, now, &days_since_first, &hours_since_last); UNUSED(days_since_first); UNUSED(hours_since_last); jump_db[i].rank = rank; total_rank += rank; } /* Once we have the total rank, check if we need to reduce ranks, * and then write entries into the database. */ if (total_rank > conf.max_jump_total_rank && conf.max_jump_total_rank > 0) reduce = (total_rank / conf.max_jump_total_rank) + 1; char perm_chr_str[2] = ""; for (i = 0; i < (int)jump_n; i++) { if (total_rank > conf.max_jump_total_rank) { if (reduce) { int tmp_rank = jump_db[i].rank; jump_db[i].rank = tmp_rank / reduce; } } /* Forget directories ranked below MIN_JUMP_RANK. */ if (jump_db[i].keep < 1 && jump_db[i].rank < conf.min_jump_rank) { /* Discount from TOTAL_RANK the rank of the now forgotten * directory to keep this total up to date. */ total_rank -= jump_db[i].rank; continue; } perm_chr_str[0] = jump_db[i].keep == JUMP_ENTRY_PERMANENT ? JUMP_ENTRY_PERMANENT_CHR : '\0'; fprintf(fp, "%s%zu:%jd:%jd:%s\n", perm_chr_str, jump_db[i].visits, (intmax_t)jump_db[i].first_visit, (intmax_t)jump_db[i].last_visit, jump_db[i].path); } fprintf(fp, "@%d\n", total_rank); fclose(fp); } int edit_jumpdb(char *app) { if (config_ok == 0 || !config_dir) { xerror(_("je: Configuration directory not found\n")); return FUNC_FAILURE; } save_jumpdb(); char jump_file[PATH_MAX + 1]; snprintf(jump_file, sizeof(jump_file), "%s/jump.clifm", config_dir); struct stat attr; if (stat(jump_file, &attr) == -1) { xerror("jump: '%s': %s\n", jump_file, strerror(errno)); return errno; } const time_t mtime_bfr = attr.st_mtime; const int ret = open_config_file(app, jump_file); if (ret != FUNC_SUCCESS) return ret; if (stat(jump_file, &attr) == -1) { xerror("jump: '%s': %s\n", jump_file, strerror(errno)); return errno; } if (mtime_bfr == (time_t)attr.st_mtime) return FUNC_SUCCESS; if (jump_db) free_jump_database(); load_jumpdb(); return FUNC_SUCCESS; } /* Save jump entry into the suggestions buffer. */ static int save_jump_suggestion(const char *str) { if (!str || !*str) return FUNC_FAILURE; free(jump_suggestion); const size_t len = strlen(str); const int slash = (len > 0 && str[len - 1] == '/'); const size_t jump_sug_len = len + (slash == 1 ? 1 : 2); jump_suggestion = xnmalloc(jump_sug_len, sizeof(char)); if (slash == 0) snprintf(jump_suggestion, jump_sug_len, "%s/", str); else xstrsncpy(jump_suggestion, str, jump_sug_len); return FUNC_SUCCESS; } static char * get_directory_color(const char *filename, const struct stat *a) { if (S_ISLNK(a->st_mode)) { char *linkname = xrealpath(filename, NULL); if (linkname) { free(linkname); return ln_c; } return or_c; } return get_dir_color(filename, a, -1); } /* Compare ranks A and B (used to sort jump entries by rank). */ int rank_cmp(const void *a, const void *b) { struct jump_t *pa = (struct jump_t *)a; struct jump_t *pb = (struct jump_t *)b; if (!pa->path) return 0; if (!pb->path) return 1; return (pa->rank > pb->rank); } static void print_jump_table_header(void) { char item[10]; /* BOLD and NC are 4 bytes each */ snprintf(item, sizeof(item), "%s*%s", conf.colorize == 1 ? BOLD : "", NC); printf(_("%s First time access is displayed in days, while last " "time access is displayed in hours.\n"), item); printf(_("%s An asterisk next rank values means that the " "corresponding directory will not be removed despite its rank, " "either because it was visited in the last 24 hours, or because " "it is bookmarked, pinned, or currently active in some " "workspace.\n"), item); printf(_("%s A plus sign next rank values means that the " "corresponding directory is marked as permanent (it will not be " "removed).\n"), item); if (conf.min_jump_rank <= 0) { printf(_("%s MinJumpRank is set to %d: entries will not be removed " "from the database (no matter their rank).\n"), item, conf.min_jump_rank); } else { printf(_("%s Entries ranked below MinJumpRank (currently %d) will be " "removed at program exit.\n"), item, conf.min_jump_rank); } printf(_("\n %sOrder\tVisits\tFirst\tLast\tRank\tDirectory%s\n"), conf.colorize == 1 ? BOLD : "", NC); } /* Print the jump database, field by field, incuding the current rank. * If REDUCE is greater than zero, each rank is divided by this value to keep * the total database rank below MaxJumpTotalRank. * NOW is the current time in seconds since epoch, and is used to calculate * each rank. * It always returns FUNC_SUCESS. */ static int print_jump_table(const int reduce, const time_t now) { if (jump_n == 0) { puts(_("jump: Database still empty")); return FUNC_SUCCESS; } HIDE_CURSOR; print_jump_table_header(); size_t i; int ranks_sum = 0, visits_sum = 0; int max_rank = 0, max_visits = 0, max_first = 0, max_last = 0; const int max_order = DIGINUM(jump_n); struct jump_t *tmp_jump = xnmalloc(jump_n + 1, sizeof(struct jump_t)); for (i = 0; i < jump_n; i++) { if (!IS_VALID_JUMP_ENTRY(i)) { tmp_jump[i].path = (char *)NULL; continue; } int days_since_first = 0, hours_since_last = 0; int rank = rank_entry((int)i, now, &days_since_first, &hours_since_last); if (reduce) { const int tmp_rank = rank; rank = tmp_rank / reduce; } ranks_sum += rank; visits_sum += (int)jump_db[i].visits; tmp_jump[i].path = jump_db[i].path; tmp_jump[i].keep = jump_db[i].keep; tmp_jump[i].rank = rank; tmp_jump[i].len = jump_db[i].len; tmp_jump[i].visits = jump_db[i].visits; tmp_jump[i].first_visit = (time_t)days_since_first; tmp_jump[i].last_visit = (time_t)hours_since_last; /* Get longest item for each field to correctly calculate padding. */ int n = DIGINUM(rank); if (n > max_rank) max_rank = n; n = DIGINUM(tmp_jump[i].visits); if (n > max_visits) max_visits = n; n = DIGINUM(tmp_jump[i].first_visit); if (n > max_first) max_first = n; n = DIGINUM(tmp_jump[i].last_visit); if (n > max_last) max_last = n; } /* Sort entries by rank (from less to more). */ qsort(tmp_jump, jump_n, sizeof(*tmp_jump), rank_cmp); for (i = 0; i < jump_n; i++) { if (!tmp_jump[i].path) continue; const char *color = (workspaces[cur_ws].path && workspaces[cur_ws].path[1] == tmp_jump[i].path[1] && strcmp(workspaces[cur_ws].path, tmp_jump[i].path) == 0) ? mi_c : df_c; struct stat a; if (lstat(tmp_jump[i].path, &a) == -1) color = uf_c; const char *dir_color = color == uf_c ? uf_c : get_directory_color(tmp_jump[i].path, &a); const int keep = tmp_jump[i].keep; const char keep_char = keep == 1 ? '*' : ((keep == JUMP_ENTRY_PERMANENT) ? JUMP_ENTRY_PERMANENT_CHR : 0); printf(" %s%*zu\t%*zu\t%*d\t%*d\t%s%*d%s%s%c%s\t%c%s%s%s\n", color != uf_c ? color : df_c, max_order, i + 1, max_visits, tmp_jump[i].visits, max_first, (int)tmp_jump[i].first_visit, max_last, (int)tmp_jump[i].last_visit, conf.colorize == 1 ? BOLD : "", max_rank, tmp_jump[i].rank, color != uf_c ? color : "", keep == 1 ? li_c : (keep == 2 ? mi_c : ""), keep > 0 ? keep_char : 0, (keep > 0 && color != uf_c) ? color : "", (conf.colorize == 0 && color == uf_c) ? '!' : 0, dir_color, tmp_jump[i].path, df_c); } free(tmp_jump); printf(_("\nTotal rank: %d/%d\nTotal visits: %d\n"), ranks_sum, conf.max_jump_total_rank, visits_sum); UNHIDE_CURSOR; return FUNC_SUCCESS; } static int purge_invalid_entries(void) { int i = (int)jump_n; int c = 0; struct stat a; while (--i >= 0) { if (!IS_VALID_JUMP_ENTRY(i)) continue; if (jump_db[i].keep == JUMP_ENTRY_PERMANENT) continue; if (stat(jump_db[i].path, &a) == -1) { printf("%s%s%s %s%s%s\n", mi_c, SET_MSG_PTR, df_c, uf_c, jump_db[i].path, df_c); jump_db[i].rank = JUMP_ENTRY_PURGED; c++; } } if (c == 0) puts(_("jump: No invalid entries")); else printf(_("\njump: Purged %d invalid %s\n"), c, c == 1 ? _("entry") : _("entries")); return FUNC_SUCCESS; } static int purge_low_ranked_entries(const int limit) { int i = (int)jump_n; int c = 0; const time_t now = time(NULL); while (--i >= 0) { if (!IS_VALID_JUMP_ENTRY(i)) continue; if (jump_db[i].keep == JUMP_ENTRY_PERMANENT) continue; int days_since_first = 0, hours_since_last = 0; const int rank = rank_entry(i, now, &days_since_first, &hours_since_last); UNUSED(days_since_first); UNUSED(hours_since_last); if (rank < limit) { if (jump_db[i].keep == 1) { jump_db[i].keep = 0; continue; } jump_db[i].keep = 0; printf("%s%s%s %s (%d)\n", mi_c, SET_MSG_PTR, df_c, jump_db[i].path, rank); jump_db[i].rank = JUMP_ENTRY_PURGED; c++; } } if (c == 0) printf(_("jump: No entry ranked below %d\n"), limit); else printf(_("\njump: Purged %d %s\n"), c, c == 1 ? _("entry") : _("entries")); return FUNC_SUCCESS; } static int purge_jump_database(const char *arg) { if (!arg || !*arg) return purge_invalid_entries(); if (!is_number(arg)) { puts(JUMP_USAGE); return FUNC_FAILURE; } const int n = atoi(arg); if (n < 0) { xerror(_("jump: '%s': Invalid value\n"), arg); return FUNC_FAILURE; } return purge_low_ranked_entries(n); } static int check_jump_params(char **args, const time_t now, const int reduce) { if (args[0][1] == 'e') return edit_jumpdb(args[1]); if (!args[1]) return print_jump_table(reduce, now); if (IS_HELP(args[1])) { puts(_(JUMP_USAGE)); return FUNC_SUCCESS; } if (*args[1] == '-' && strcmp(args[1], "--edit") == 0) return edit_jumpdb(args[2]); if (*args[1] == '-' && strcmp(args[1], "--purge") == 0) return purge_jump_database(args[2]); return (-1); } static int mark_target_segment(char *str) { const size_t len = strlen(str); int segment = 0; if (len > 0 && str[len - 1] == '/') { str[len - 1] = '\0'; segment |= LAST_SEGMENT; } else if (len > 0 && str[len - 1] == '\\') { str[len - 1] = '\0'; segment |= FIRST_SEGMENT; } return segment; } /* Return a pointer to the beggining of the string QUERY in the path NEEDLE. * If used for the first time (checking the first query string), NEEDLE is * the same as MATCH. Otherwise, NEEDLE points to a char in MATCH. * SEGMENT is a flag: LAST_SEGMENT or FIRST_SEGMENT. In both cases the * resulting string will be checked to match for the first or last segment * of the full match (MATCH). If not NULL is returned. */ static char * get_needle(const char *needle, const char *match, const char *query, const int segment) { char *ret = conf.case_sens_dirjump == 1 ? strstr(needle, query) #ifdef _BE_POSIX /* xstrcasestr() calls x_strcasestr(), which does not take consts. */ : xstrcasestr((char *)needle, (char *)query); #else : xstrcasestr(needle, query); #endif /* _BE_POSIX */ if (!ret || ((segment & LAST_SEGMENT) && strchr(ret, '/'))) return (char *)NULL; if (segment & FIRST_SEGMENT) { const char p = *ret; *ret = '\0'; if (strrchr(match, '/') != match) { *ret = p; return (char *)NULL; } *ret = p; } return ret; } static int rank_tmp_entry(const struct jump_entry_t *entry, const time_t now, const int reduce, const char *query) { /* 86400 = 60 secs / 60 misc / 24 hours */ const int days_since_first = (int)(now - entry->first) / 86400; /* 3600 = 60 secs / 60 mins */ const int hours_since_last = (int)(now - entry->last) / 3600; int keep = 0; int rank = calculate_base_credit(days_since_first, hours_since_last, (int)entry->visits, &keep); rank += calculate_bonus_credit(entry->match, query, &keep); if (entry->keep == JUMP_ENTRY_PERMANENT) rank += PERMANENT_BONUS; UNUSED(keep); if (reduce > 0) { const int tmp_rank = rank; rank = tmp_rank / reduce; } return rank; } static int check_dir(char *param, const int mode, int *ret) { char *dir = (mode == NO_SUG_JUMP && strchr(param, '\\')) ? unescape_str(param, 0) : param; struct stat a; if (lstat(dir, &a) == -1) { if (dir != param) free(dir); return 0; } *ret = mode == NO_SUG_JUMP ? cd_function(dir, CD_NO_PRINT_ERROR) : save_jump_suggestion(param); if (dir != param) free(dir); return 1; } /* Found the best ranked directory matching query strings in ARGS. * * The rank is calculated as frecency. The algorithm is based on Mozilla, * zoxide, and z.lua. See: * https://wiki.mozilla.org/User:Mconnor/Past/PlacesFrecency * https://github.com/ajeetdsouza/zoxide/wiki/Algorithm#aging * https://github.com/skywind3000/z.lua#aging * * If MODE is NO_SUG_JUMP, we're running the 'j' command (or any of its * variants [je, jc, jp, --edit or --purge]), in which case matches are * handled according to the specific command. * * Otherwise, the function has been called from the suggestions system, in * which case the best ranked directory is stored in the suggestions * buffer (jump_suggestion) to be suggested by the suggestions system. * * Returns 1 (if matches are found) or 0. */ int dirjump(char **args, const int mode) { if (xargs.no_dirjump == 1 && mode == NO_SUG_JUMP) { printf(_("%s: Directory jumper function disabled\n"), PROGRAM_NAME); return FUNC_FAILURE; } const time_t now = time(NULL); int reduce = 0; /* If the sum total of ranks is greater than max, divide each entry * to make the sum total less than or equal to max. */ if (jump_total_rank > conf.max_jump_total_rank && conf.max_jump_total_rank > 0) reduce = (jump_total_rank / conf.max_jump_total_rank) + 1; if (mode == NO_SUG_JUMP) { const int ret = check_jump_params(args, now, reduce); if (ret != -1) return ret; } enum jump jump_opt = NONE; switch (args[0][1]) { case 'c': jump_opt = JCHILD; break; case 'p': jump_opt = JPARENT; break; case 'l': jump_opt = JLIST; break; case '\0': jump_opt = NONE; break; default: xerror(_("jump: '%c': Invalid option\n"), args[0][1]); fprintf(stderr, "%s\n", _(JUMP_USAGE)); return FUNC_FAILURE; } /* If ARG is an actual directory, just change to it. */ int ret = 0; if (args[1] && !args[2] && check_dir(args[1], mode, &ret) == 1) return ret; /* Find the best ranked directory using ARGS as filter(s). */ size_t i; int j, match = 0; struct jump_entry_t *entry = xnmalloc(jump_n + 1, sizeof(struct jump_entry_t)); for (i = 1; args[i]; i++) { /* 1) Using the first parameter, get a list of matches in the * database. */ /* If the query string ends with a slash, we want this query * string to match only the LAST segment of the path, and if it ends * with a backslash instead, we want this query to match only the * FIRST segment of the path. */ const int segment = mark_target_segment(args[i]); if (match == 0) { j = (int)jump_n; while (--j >= 0) { if (!IS_VALID_JUMP_ENTRY(j)) continue; /* Exclude CWD */ if (workspaces[cur_ws].path && jump_db[j].path[1] == workspaces[cur_ws].path[1] && strcmp(jump_db[j].path, workspaces[cur_ws].path) == 0) continue; /* Pointer to the beginning of the search str in the * jump entry. Used to search for subsequent search * strings starting from this position in the entry * and not before. */ char *needle = get_needle(jump_db[j].path, jump_db[j].path, args[i], segment); if (!needle) continue; int exclude = 0; /* Filter matches according to parent or child options. */ switch (jump_opt) { case JPARENT: if (workspaces[cur_ws].path && !strstr(workspaces[cur_ws].path, jump_db[j].path)) exclude = 1; break; case JCHILD: if (workspaces[cur_ws].path && !strstr(jump_db[j].path, workspaces[cur_ws].path)) exclude = 1; break; case NONE: /* fallthrough */ default: break; } if (exclude == 1) continue; entry[match].visits = jump_db[j].visits; entry[match].first = jump_db[j].first_visit; entry[match].last = jump_db[j].last_visit; entry[match].needle = needle; entry[match].match = jump_db[j].path; entry[match].keep = (size_t)jump_db[j].keep; match++; } } /* 2) Once we have the list of matches, perform a reverse * matching process, that is, excluding non-matches, * using subsequent parameters. */ else { j = match; while (--j >= 0) { if (!entry[j].match || !*entry[j].match) { entry[j].match = (char *)NULL; continue; } char *needle = get_needle(entry[j].needle + 1, entry[j].match, args[i], segment); if (!needle) { entry[j].match = (char *)NULL; continue; } entry[j].needle = needle; } } } /* If something remains, we have at least one match. */ /* 3) Further filter the list of matches by frecency, so that only * the best ranked directory will be returned. */ int found = 0, exit_status = FUNC_FAILURE, max = -1; char *best_ranked = (char *)NULL; j = match; while (--j >= 0) { if (!entry[j].match) continue; found = 1; if (jump_opt == JLIST) { colors_list(entry[j].match, 0, 0 , 1); continue; } const int rank = rank_tmp_entry(&entry[j], now, reduce, args[args_n]); if (rank > max) { max = rank; best_ranked = entry[j].match; } } if (found == 0) { if (mode == NO_SUG_JUMP) puts(_("jump: No matches found")); exit_status = FUNC_FAILURE; goto END; } if (jump_opt == JLIST) { exit_status = FUNC_SUCCESS; goto END; } if (mode == NO_SUG_JUMP) exit_status = cd_function(best_ranked, CD_PRINT_ERROR); else exit_status = save_jump_suggestion(best_ranked); END: free(entry); return exit_status; } clifm-1.26.3/src/jump.h000066400000000000000000000020451506632037700146220ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* jump.h */ #ifndef JUMP_H #define JUMP_H __BEGIN_DECLS int add_to_jumpdb(char *dir); void save_jumpdb(void); int dirjump(char **args, int mode); __END_DECLS #endif /* JUMP_H */ clifm-1.26.3/src/keybinds.c000066400000000000000000002144501506632037700154570ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* keybinds.c -- handle keybindings */ #include "helpers.h" #ifdef __OpenBSD__ typedef char *rl_cpvfunc_t; # include #else # include #endif /* __OpenBSD__ */ #ifdef __TINYC__ /* Silence a tcc warning. We don't use CTRL anyway */ # undef CTRL #endif /* __TINYC */ #include #ifdef __NetBSD__ # include #endif /* __NetBSD__ */ #include #if defined(MAC_OS_X_RENAMEAT_SYS_STDIO_H) # include /* renameat(2) */ #endif /* MAC_OS_X_RENAMEAT_SYS_STDIO_H */ #include "aux.h" #include "autocmds.h" /* update_autocmd_opts() */ #include "config.h" #include "exec.h" #include "file_operations.h" #include "keybinds.h" #include "listing.h" #include "messages.h" #include "misc.h" #include "profiles.h" #include "prompt.h" #include "readline.h" #include "sort.h" /* QSFUNC macro for qsort(3) */ #include "spawn.h" #include "tabcomp.h" /* tab_complete() */ #include "translate_key.h" /* translate_key() */ #ifndef _NO_SUGGESTIONS # include "suggestions.h" #endif /* !_NO_SUGGESTIONS */ #ifndef _NO_HIGHLIGHT # include "highlight.h" #endif /* !_NO_HIGHLIGHT */ #include "strings.h" /* quote_str() */ #ifndef _NO_SUGGESTIONS static int accept_first_word = 0; #endif /* !_NO_SUGGESTIONS */ /* This is just an ugly workaround. You've been warned! * Long story short: prompt commands are executed after SOME keybindings, but * not after others. I'm not sure why, and this irregularity is what is wrong * in the first place. * In the second case, when prompt commands are not executed, we sometimes do * want to run them (mostly when changing directories): in this case, we set * exec_prompt_cmds to 1. */ static int exec_prompt_cmds = 0; static void xrl_reset_line_state(void) { UNHIDE_CURSOR; rl_reset_line_state(); } static int append_str(char *buf, const int buf_size, size_t *len, const char *str) { const size_t length = strlen(str); if (length >= (size_t)buf_size - *len) return (-1); /* Buffer overflow */ xstrsncpy(buf + *len, str, (size_t)buf_size - *len); *len += length; return 0; } #define KBUF_SIZE 256 /* This should be enough to handle most keybindings. */ #define END_KEYSEQ_CHAR ',' static const char * translate_emacs_style_keyseq(const char *key) { if (!key || !*key || *key != '\\') return NULL; if (key[1] == 'e' && (key[2] == CSI_INTRODUCER || key[2] == SS3_INTRODUCER)) return NULL; static char buf[KBUF_SIZE] = {0}; size_t buf_len = 0; while (*key) { if (*key == '\\') { if (key[1] == 'e' || (key[1] == 'M' && key[2] == '-')) { if (append_str(buf, KBUF_SIZE, &buf_len, "Alt+") == -1) return NULL; /* If "\M-" we want to advance 3 bytes, not 2. */ key += 2 + (key[1] == 'M'); if (!*key) /* Incomplete sequence: Alt without modified key. */ return NULL; continue; } if (key[1] == 'C' && key[2] == '-') { if (append_str(buf, KBUF_SIZE, &buf_len, "Ctrl+") == -1) return NULL; key += 3; if (!*key) /* Incomplete sequence: Ctrl without modified key. */ return NULL; continue; } // Additional escape sequences: // https://www.gnu.org/software/bash/manual/html_node/Readline-Init-File-Syntax.html /* Unrecognized escape sequence */ return NULL; } if (!*key || buf_len >= sizeof(buf) - 2 /* No keybinding starts with a non-modifier key. Skip it. */ || buf_len == 0) return NULL; /* Let's try to skip non-keyboard related escape sequences: * CSI, OSC, DCS, APC, and PM escape sequences, plus * character set switching sequences (e.g. "\e(A". */ if ((*key == '[' || *key == ']' || *key == 'P' || *key == '_' || *key == '^' || *key == '(' || *key == ')') && key[1] && key[1] != '\\') return NULL; /* Append single character to the buffer. */ buf[buf_len] = *key; buf_len++; key++; /* A character that is not a modifier key marks the end of the * key sequence. Append an ',' in this case, provided it is * not the end of the string. */ if (*key) { buf[buf_len] = END_KEYSEQ_CHAR; buf_len++; } } buf[buf_len] = '\0'; if (*buf == 'A' && strncmp(buf, "Alt+Ctrl+", 9) == 0) memcpy(buf, "Ctrl+Alt+", 9); return *buf ? buf : NULL; } #undef END_KEYSEQ_CHAR /* Translate the raw escape code KEY (sent by the terminal upon a key press) * into a human-readable format. * Return the translation, if found, or the original sequence (KEY) otherwise. */ static const char * xtranslate_key(const char *key) { if (!key || !*key) return NULL; if (*key == '-' && !key[1]) return _("not bound"); const char *t = (strstr(key, "C-") || strstr(key, "M-")) ? translate_emacs_style_keyseq(key) : NULL; if (t) return t; const char *key_ptr = key; static char buf[KBUF_SIZE] = ""; int c = 0; while (*key_ptr) { if (*key_ptr == '\\' && key_ptr[1] == 'e') { buf[c++] = KEY_ESC; key_ptr += 2; } else { buf[c++] = *key_ptr++; } } buf[c] = '\0'; char *translation = translate_key(buf, 0); if (translation) { xstrsncpy(buf, translation, sizeof(buf)); free(translation); return buf; } return key; } static int backup_and_create_kbinds_file(void) { char *backup = gen_backup_file(kbinds_file, 1); if (!backup) return FUNC_FAILURE; if (renameat(XAT_FDCWD, kbinds_file, XAT_FDCWD, backup) != 0) { xerror(_("kb: Cannot rename '%s' to '%s': %s\n"), kbinds_file, backup, strerror(errno)); free(backup); return FUNC_FAILURE; } char *abbrev = abbreviate_file_name(backup); printf(_("Old keybindings file saved as '%s'\n"), abbrev ? abbrev : backup); free(backup); free(abbrev); return create_kbinds_file(); } int kbinds_reset(void) { int exit_status = FUNC_SUCCESS; struct stat attr; if (!kbinds_file || !*kbinds_file) { xerror(_("kb: No keybindings file found\n")); return FUNC_FAILURE; } if (stat(kbinds_file, &attr) == -1) exit_status = create_kbinds_file(); else exit_status = backup_and_create_kbinds_file(); if (exit_status == FUNC_SUCCESS) err('n', PRINT_PROMPT, _("kb: Restart %s for changes " "to take effect\n"), PROGRAM_NAME); return exit_status; } static int kbinds_edit(char *app) { if (xargs.stealth_mode == 1) { printf("%s: kb: %s\n", PROGRAM_NAME, STEALTH_DISABLED); return FUNC_SUCCESS; } if (!kbinds_file) { xerror(_("kb: No keybindings file found\n")); return FUNC_FAILURE; } struct stat attr; if (stat(kbinds_file, &attr) == -1) { create_kbinds_file(); stat(kbinds_file, &attr); } const time_t mtime_bfr = attr.st_mtime; const int ret = open_config_file(app, kbinds_file); if (ret != FUNC_SUCCESS) return ret; stat(kbinds_file, &attr); if (mtime_bfr == attr.st_mtime) return FUNC_SUCCESS; err('n', PRINT_PROMPT, _("kb: Restart %s for changes to " "take effect\n"), PROGRAM_NAME); return FUNC_SUCCESS; } /* FUNC_NAME is not NULL when invokd by 'kb conflict' (in which case we're * check a readline key sequence). Otherwise, if invoked by 'kb bind', * FUNC_NAME isn't set. * We display different messages depending on the invoking command. * Returns the number of conflicts found. */ static int check_clifm_kb(const char *kb, const char *func_name) { int conflicts = 0; size_t i; for (i = 0; i < kbinds_n; i++) { if (!kbinds[i].key || strcmp(kb, kbinds[i].key) != 0) continue; if (func_name != NULL) { fprintf(stderr, _("kb: '%s' conflicts with '%s' (readline)\n"), kbinds[i].function ? kbinds[i].function : "unnamed", func_name); } else { const char *func = kbinds[i].function ? kbinds[i].function : "unnamed"; const char *t = xtranslate_key(kbinds[i].key); fprintf(stderr, _("kb: %s: Key already in use by '%s'.\n"), t ? t : kbinds[i].key, func); } conflicts++; } return conflicts; } /* Check all readline key sequences against the key sequence KB, if not NULL * (this is the case when validating a key entered via 'kb bind'). * Otherwise the check is made against all clifm key sequences (i.e., when * the invoking command is 'kb conflict'). * Returns the number of conflicts found. */ static int check_rl_kbinds(const char *kb) { size_t i, j; char *name = (char *)NULL; char **names = (char **)rl_funmap_names(); int conflicts = 0; if (!names) return FUNC_SUCCESS; for (i = 0; (name = names[i]); i++) { rl_command_func_t *function = rl_named_function(name); char **keys = rl_invoking_keyseqs(function); if (!keys) continue; for (j = 0; keys[j]; j++) { if (kb == NULL) { conflicts += check_clifm_kb(keys[j], name); } else { if (strcmp(kb, keys[j]) == 0) { const char *t = xtranslate_key(kb); fprintf(stderr, _("kb: %s: Key already in use by '%s' " "(readline)\n"), t ? t : kb, name); conflicts++; } } free(keys[j]); } free(keys); } free(names); return conflicts; } static int check_kbinds_conflict(void) { if (kbinds_n == 0) { puts(_("kb: No keybindings defined")); return FUNC_SUCCESS; } int ret = FUNC_SUCCESS; size_t i, j; for (i = 0; i < kbinds_n; i++) { for (j = i + 1; j < kbinds_n; j++) { if (strcmp(kbinds[i].key, kbinds[j].key) == 0) { fprintf(stderr, _("kb: '%s' conflicts with '%s'\n"), kbinds[i].function, kbinds[j].function); ret = FUNC_FAILURE; } } } if (check_rl_kbinds(NULL) > 0) ret = FUNC_FAILURE; return ret; } /* Retrieve the key sequence associated to FUNCTION */ static char * find_key(const char *function) { if (kbinds_n == 0) return (char *)NULL; int n = (int)kbinds_n; while (--n >= 0) { if (*function != *kbinds[n].function) continue; if (strcmp(function, kbinds[n].function) == 0) return kbinds[n].key; } return (char *)NULL; } /* Read a key sequence from STDIN and return its value (memory to hold this * value is allocated via malloc(2)). */ static char * get_new_keybind(void) { char buf[64]; size_t len = 0; int ret = 0; int result = 0; int ch = 0; int prev = 0; buf[0] = '\0'; putchar(':'); fflush(stdout); if (enable_raw_mode(STDIN_FILENO) == -1) { UNHIDE_CURSOR; return (char *)NULL; } while (1) { result = (int)read(STDIN_FILENO, &ch, sizeof(unsigned char)); /* flawfinder: ignore */ if (result <= 0 || len >= sizeof(buf) - 1) { buf[len] = '\0'; break; } if (result != sizeof(unsigned char)) continue; const unsigned char c = (unsigned char)ch; if (prev != KEY_ESC) { if (c == KEY_ENTER) break; if (c == CTRL('D')) { buf[0] = '\0'; break; } if (c == CTRL('C')) { putchar('\r'); MOVE_CURSOR_RIGHT(1); ERASE_TO_RIGHT; fflush(stdout); buf[0] = '\0'; len = 0; continue; } } const size_t remaining = sizeof(buf) - len - 1; if (c == KEY_ESC) { ret = snprintf(buf + len, remaining, "\\e"); } else if (isprint(c) && c != ' ') { ret = snprintf(buf + len, remaining, "%c", c); } else if (c <= 31) { ret = snprintf(buf + len, remaining, "\\C-%c", c + '@' - 'A' + 'a'); } else { ret = snprintf(buf + len, remaining, "\\x%x", c); } prev = ch; if (ret < 0 || (size_t)ret >= remaining) continue; /* Kitty keyboard protocol */ if (*buf && strstr(buf, "\\e[100;5u")) { /* Ctrl+d */ MOVE_CURSOR_LEFT(8); ERASE_TO_RIGHT; fflush(stdout); buf[0] = '\0'; break; } if (*buf && strstr(buf, "\\e[99;5u")) { /* Ctrl+c */ putchar('\r'); MOVE_CURSOR_RIGHT(1); ERASE_TO_RIGHT; fflush(stdout); buf[0] = '\0'; len = 0; continue; } if (*buf) { fputs(buf + len, stdout); fflush(stdout); } len += (size_t)ret; } disable_raw_mode(STDIN_FILENO); putchar('\n'); if (!*buf) return (char *)NULL; return savestring(buf, strlen(buf)); } /* Append the key sequence KB associated to the function name FUNC_NAME * to the keybingins file. */ static int append_kb_to_file(const char *func_name, const char *kb) { FILE *fp = open_fappend(kbinds_file); if (!fp) { xerror(_("kb: Cannot open '%s': %s\n"), kbinds_file, strerror(errno)); return FUNC_FAILURE; } fprintf(fp, "\n%s:%s\n", func_name, kb); fclose(fp); return FUNC_SUCCESS; } /* Edit the keybindings file and update the key sequence bound to FUNC_NAME * with the key sequence KB. */ static int rebind_kb(const char *func_name, const char *kb) { int orig_fd = 0; FILE *orig_fp = open_fread(kbinds_file, &orig_fd); if (!orig_fp) { xerror(_("kb: Cannot open '%s': %s\n"), kbinds_file, strerror(errno)); return FUNC_FAILURE; } const size_t len = strlen(config_dir_gral) + (sizeof(TMP_FILENAME) - 1) + 2; char *tmp_name = xnmalloc(len, sizeof(char)); snprintf(tmp_name, len, "%s/%s", config_dir_gral, TMP_FILENAME); const int tmp_fd = mkstemp(tmp_name); if (tmp_fd == -1) { xerror(_("kb: Error creating temporary file: %s\n"), strerror(errno)); goto ERROR; } FILE *tmp_fp = fdopen(tmp_fd, "w"); if (!tmp_fp) { xerror(_("kb: Cannot open temporary file: %s\n"), strerror(errno)); unlinkat(tmp_fd, tmp_name, 0); close(tmp_fd); goto ERROR; } int found = 0; const size_t func_len = strlen(func_name); char line[NAME_MAX]; while (fgets(line, sizeof(line), orig_fp) != NULL) { if (found == 0 && strncmp(line, func_name, func_len) == 0 && line[func_len] == ':') { fprintf(tmp_fp, "%s:%s\n", func_name, kb); found = 1; } else { fputs(line, tmp_fp); } } if (found == 1) { if (renameat(tmp_fd, tmp_name, orig_fd, kbinds_file) == -1) xerror(_("kb: Cannot rename '%s' to '%s': %s\n"), tmp_name, kbinds_file, strerror(errno)); } else { unlinkat(tmp_fd, tmp_name, 0); } fclose(orig_fp); fclose(tmp_fp); free(tmp_name); if (found == 0) return append_kb_to_file(func_name, kb); return FUNC_SUCCESS; ERROR: free(tmp_name); fclose(orig_fp); return FUNC_FAILURE; } /* Check the key sequence KB against the list of clifm's key sequences. * Return FUNC_FAILURE in case of conflict, or FUNC_SUCCESS. */ static int check_func_name(const char *func_name) { const size_t len = strlen(func_name); for (size_t i = 0; kb_cmds[i].name; i++) { if (len == kb_cmds[i].len && *kb_cmds[i].name == *func_name && strcmp(kb_cmds[i].name, func_name) == 0) return FUNC_SUCCESS; } return FUNC_FAILURE; } /* Check the key sequence KB against both clifm and readline key sequences. * Return the number of conflicts found. */ static int check_kb_conflicts(const char *kb) { if (!strchr(kb, '\\') && strcmp(kb, "-") != 0) { fprintf(stderr, _("kb: Invalid keybinding\n")); return FUNC_FAILURE; } if (*kb == '-' && !kb[1]) return FUNC_SUCCESS; int conflicts = 0; conflicts += check_clifm_kb(kb, NULL); conflicts += check_rl_kbinds(kb); return conflicts; } /* Bind the function FUNC_NAME to a new key sequence. */ static int bind_kb_func(const char *func_name) { if (xargs.stealth_mode == 1) { printf("%s: kb: %s\n", PROGRAM_NAME, STEALTH_DISABLED); return FUNC_SUCCESS; } if (!kbinds_file || !*kbinds_file) { xerror(_("kb: No keybindings file found\n")); return FUNC_FAILURE; } if (!func_name || !*func_name) { puts(KB_USAGE); return FUNC_SUCCESS; } if (check_func_name(func_name) == FUNC_FAILURE) { xerror(_("kb: '%s': Invalid function name\nType 'kb bind ' " "to list available function names\n"), func_name); return FUNC_FAILURE; } struct stat a; if (stat(kbinds_file, &a) == -1 && create_kbinds_file() == FUNC_FAILURE) return FUNC_FAILURE; const char *func_key = find_key(func_name); const char *translated_key = func_key ? xtranslate_key(func_key) : "unset"; /* translated_key can only be NULL if func_key is not NULL. */ const char *cur_key = translated_key ? translated_key : func_key; printf(_("Enter a keybinding for %s%s%s (current: %s%s%s)\n"), BOLD, func_name, df_c, BOLD, cur_key, df_c); puts(_("(Enter:accept, Ctrl+d:abort, Ctrl+c:clear-line)")); puts(_("To unset the function enter '-'")); char *kb = get_new_keybind(); if (kb == NULL) return FUNC_SUCCESS; const int unset_key = (*kb == '-' && !kb[1]); if (unset_key == 0 && check_kb_conflicts(kb) == 0) { /* If any conflict was found (check_kb_conflicts() is greater than * zero), the function already displayed the keybinding translation. */ const char *translation = xtranslate_key(kb); printf(_("New key: %s\n"), translation ? translation : kb); } const char *msg = unset_key == 1 ? _("Unset this function?") : _("Bind function to this new key?"); if (rl_get_y_or_n(msg, 0) == 0) { free(kb); return FUNC_SUCCESS; } const int ret = rebind_kb(func_name, kb); free(kb); if (ret == FUNC_SUCCESS) { err('n', PRINT_PROMPT, _("kb: Restart %s for changes to " "take effect\n"), PROGRAM_NAME); } return ret; } static int list_kbinds(void) { if (kbinds_n == 0) { puts(_("kb: No keybindings defined\n")); return FUNC_SUCCESS; } size_t flen = 0; size_t i; for (i = 0; i < kbinds_n; i++) { const size_t l = kbinds[i].function ? strlen(kbinds[i].function) : 0; if (l > flen) flen = l; } for (i = 0; i < kbinds_n; i++) { if (!kbinds[i].key || !kbinds[i].function) continue; const char *translation = xtranslate_key(kbinds[i].key); printf("%-*s (%s)\n", (int)flen, kbinds[i].function, translation ? translation : kbinds[i].key); } return FUNC_SUCCESS; } /* Print the list of readline functions and associated keys. */ static int list_rl_kbinds(void) { size_t i, j; char *name = (char *)NULL; char **names = (char **)rl_funmap_names(); if (!names) return FUNC_SUCCESS; size_t flen = 0; for (i = 0; (name = names[i]); i++) { rl_command_func_t *function = rl_named_function(name); char **keys = rl_invoking_keyseqs(function); if (!keys) continue; for (j = 0; keys[j]; j++) free(keys[j]); free(keys); const size_t l = strlen(name); if (l > flen) flen = l; } char prev[KBUF_SIZE] = ""; for (i = 0; (name = names[i]); i++) { if ((*name == 's' && strcmp(name, "self-insert") == 0) || (*name == 'd' && strcmp(name, "do-lowercase-version") == 0)) continue; rl_command_func_t *function = rl_named_function(name); char **keys = rl_invoking_keyseqs(function); if (!keys) continue; printf("%-*s ", (int)flen, name); for (j = 0; keys[j]; j++) { const char *t = xtranslate_key(keys[j]); /* Skip consecutive duplicates. */ if (t && *prev == *t && strcmp(prev, t) == 0) { free(keys[j]); continue; } printf("(%s) ", t ? t : keys[j]); if (t) xstrsncpy(prev, t, sizeof(prev)); free(keys[j]); } putchar('\n'); free(keys); } free(names); puts(_("\nNote: Bear in mind that clifm's keybindings take precedence " "over readline's.\nTo modify readline's keybindings edit " "~/.config/clifm/readline.clifm")); return FUNC_SUCCESS; } #undef KBUF_SIZE int kbinds_function(char **args) { if (!args) return FUNC_FAILURE; if (!args[1] || strcmp(args[1], "list") == 0) return list_kbinds(); if (IS_HELP(args[1])) { puts(_(KB_USAGE)); return FUNC_SUCCESS; } if (*args[1] == 'b' && strcmp(args[1], "bind") == 0) return bind_kb_func(args[2]); if (*args[1] == 'c' && strcmp(args[1], "conflict") == 0) return check_kbinds_conflict(); if (*args[1] == 'e' && strcmp(args[1], "edit") == 0) return kbinds_edit(args[2] ? args[2] : NULL); if (*args[1] == 'r' && strcmp(args[1], "reset") == 0) return kbinds_reset(); if (*args[1] == 'r' && strcmp(args[1], "readline") == 0) return list_rl_kbinds(); fprintf(stderr, "%s\n", _(KB_USAGE)); return FUNC_FAILURE; } /* Store keybinds from the keybinds file in a struct. */ int load_keybinds(void) { if (config_ok == 0 || !kbinds_file) return FUNC_FAILURE; /* Free the keybinds struct array */ if (kbinds_n > 0) { int i = (int)kbinds_n; while (--i >= 0) { free(kbinds[i].function); free(kbinds[i].key); } free(kbinds); kbinds = xnmalloc(1, sizeof(struct kbinds_t)); kbinds_n = 0; } /* Open the keybinds file */ FILE *fp = fopen(kbinds_file, "r"); if (!fp) return FUNC_FAILURE; size_t line_size = 0; char *line = (char *)NULL; ssize_t line_len = 0; while ((line_len = getline(&line, &line_size, fp)) > 0) { if (!line || !*line || *line == '#' || *line == '\n') continue; if (line[line_len - 1] == '\n') line[line_len - 1] = '\0'; char *tmp = (char *)NULL; tmp = strchr(line, ':'); if (!tmp || !*(tmp + 1)) continue; /* Now copy left and right values of each keybinding to the * kbinds struct. */ kbinds = xnrealloc(kbinds, kbinds_n + 1, sizeof(struct kbinds_t)); kbinds[kbinds_n].key = savestring(tmp + 1, strlen(tmp + 1)); *tmp = '\0'; kbinds[kbinds_n].function = savestring(line, strlen(line)); kbinds_n++; } fclose(fp); free(line); if (kbinds_n > 1) qsort(kbinds, kbinds_n, sizeof(*kbinds), (QSFUNC *)compare_strings); return FUNC_SUCCESS; } /* This call to prompt() just updates the prompt in case it was modified by * a keybinding, for example, chdir, files selection, trash, and so on. * The screen is not refreshed in any way. */ static void rl_update_prompt(void) { if (rl_line_buffer) { memset(rl_line_buffer, '\0', (size_t)rl_end); rl_point = rl_end = 0; } prompt(exec_prompt_cmds ? PROMPT_UPDATE_RUN_CMDS : PROMPT_UPDATE, PROMPT_NO_SCREEN_REFRESH); exec_prompt_cmds = 0; UNHIDE_CURSOR; } #if defined(__HAIKU__) || !defined(_NO_PROFILES) /* Old version of rl_update_prompt(). Used only by rl_profile_previous() and * rl_profile_next(): if any of these functions use rl_update_prompt() instead, * no prompt is printed (not sure why). FIX. */ static void rl_update_prompt_old(void) { HIDE_CURSOR; char *input = prompt(PROMPT_SHOW, PROMPT_NO_SCREEN_REFRESH); free(input); } #endif /* __HAIKU__ || !_NO_PROFILES */ static void xrl_update_prompt(void) { #ifdef __HAIKU__ rl_update_prompt_old(); #else rl_update_prompt(); #endif /* __HAIKU__ */ } /* Run any command recognized by Clifm via a keybind. Example: * keybind_exec_cmd("sel *") */ int keybind_exec_cmd(char *str) { const size_t old_args = args_n; args_n = 0; #ifndef _NO_SUGGESTIONS if (suggestion.printed == 1 && suggestion_buf) clear_suggestion(CS_FREEBUF); #endif /* !_NO_SUGGESTIONS */ int exit_status = FUNC_FAILURE; char **cmd = parse_input_str(str); putchar('\n'); if (cmd) { exit_status = exec_cmd_tm(cmd); /* While in the bookmarks or mountpoints screen, the kbind_busy * flag will be set to 1 and no keybinding will work. Once the * corresponding function exited, set the kbind_busy flag to zero, * so that keybindings work again. */ if (kbind_busy == 1) kbind_busy = 0; int i = (int)args_n + 1; while (--i >= 0) free(cmd[i]); free(cmd); xrl_update_prompt(); } args_n = old_args; return exit_status; } static int run_kb_cmd(char *cmd, const int ignore_empty_line) { if (!cmd || !*cmd) return FUNC_FAILURE; if (kbind_busy == 1) return FUNC_SUCCESS; #ifndef _NO_SUGGESTIONS if (conf.colorize == 1 && wrong_cmd == 1) recover_from_wrong_cmd(); #endif /* _NO_SUGGESTIONS */ const int exit_code_bk = exit_code; keybind_exec_cmd(cmd); rl_reset_line_state(); if (exit_code != exit_code_bk) /* The exit code was changed by the executed command. Force the * input taking function (my_rl_getc) to update the value of * prompt_offset to correctly calculate the cursor position. */ prompt_offset = UNSET; g_prompt_ignore_empty_line = ignore_empty_line; return FUNC_SUCCESS; } int rl_toggle_max_filename_len(int count, int key) { UNUSED(count); UNUSED(key); if (kbind_busy == 1) return FUNC_SUCCESS; static int mnl_bk = 0, flag = 0; if (flag == 0 || conf.trunc_names == 0) { mnl_bk = conf.max_name_len_bk; flag = 1; } if (conf.max_name_len == UNSET) { conf.max_name_len = mnl_bk; mnl_bk = UNSET; } else { mnl_bk = conf.max_name_len; conf.max_name_len = UNSET; } update_autocmd_opts(AC_MAX_NAME_LEN); if (conf.autols == 1) { if (conf.clear_screen == 0) putchar('\n'); reload_dirlist(); } if (conf.max_name_len == UNSET) { print_reload_msg(NULL, NULL, _("Max name length unset\n")); } else { print_reload_msg(NULL, NULL, _("Max name length set to %d\n"), conf.max_name_len); } xrl_reset_line_state(); return FUNC_SUCCESS; } /* Prepend authentication program name (typically sudo or doas) to the current * input string. */ static int rl_prepend_sudo(int count, int key) { UNUSED(count); UNUSED(key); if (kbind_busy == 1) return FUNC_SUCCESS; #ifndef _NO_SUGGESTIONS if (suggestion.printed && suggestion_buf) { clear_suggestion(CS_FREEBUF); fputs(df_c, stdout); } #endif /* !_NO_SUGGESTIONS */ int free_s = 1; size_t len = 0; char *t = sudo_cmd; char *s = (char *)NULL; if (t) { len = strlen(t); if (len > 0 && t[len - 1] != ' ') { s = xnmalloc(len + 2, sizeof(char)); snprintf(s, len + 2, "%s ", t); len++; } else { s = t; free_s = 0; } } else { len = strlen(DEF_SUDO_CMD) + 1; s = xnmalloc(len + 1, sizeof(char)); snprintf(s, len + 1, "%s ", DEF_SUDO_CMD); } char *c = (char *)NULL; if (conf.highlight == 1 && conf.colorize == 1 && cur_color && cur_color != tx_c) { c = cur_color; fputs(tx_c, stdout); } const int p = rl_point; if (*rl_line_buffer == *s && strncmp(rl_line_buffer, s, len) == 0) { rl_delete_text(0, (int)len); rl_point = p - (int)len; } else { rl_point = 0; rl_insert_text(s); rl_point = p + (int)len; if (c) rl_redisplay(); } if (c) fputs(c, stdout); if (free_s) free(s); #ifndef _NO_SUGGESTIONS if (suggestion.offset == 0 && suggestion_buf) { int r = rl_point; rl_point = rl_end; clear_suggestion(CS_FREEBUF); rl_point = r; } #endif /* !_NO_SUGGESTIONS */ #ifndef _NO_HIGHLIGHT if (conf.highlight == 1) { int r = rl_point; rl_point = 0; recolorize_line(); rl_point = r; } #endif /* !_NO_HIGHLIGHT */ return FUNC_SUCCESS; } static int rl_create_file(int count, int key) { UNUSED(count); UNUSED(key); return run_kb_cmd("n", 1); } #ifndef _NO_SUGGESTIONS /* Insert the accepted suggestion into the current input line * (highlighting words and special chars if syntax highlighting is enabled) */ static void my_insert_text(char *text, char *s, const char _s) { #ifdef _NO_HIGHLIGHT UNUSED(s); UNUSED(_s); #endif /* !_NO_HIGHLIGHT */ if (!text || !*text) return; { if (wrong_cmd == 1 || cur_color == hq_c) goto INSERT_TEXT; #ifndef _NO_HIGHLIGHT if (conf.highlight == 1) { /* Hide the cursor to minimize flickering */ HIDE_CURSOR; /* Set text color to default */ fputs(tx_c, stdout); cur_color = tx_c; char *t = text; size_t i; /* We only need to redisplay first suggested word if it contains * a highlighting char and it is not preceded by a space */ int redisplay = 0; if (accept_first_word == 1) { for (i = 0; t[i]; i++) { if (t[i] >= '0' && t[i] <= '9') { if (i == 0 || t[i - 1] != ' ') { redisplay = 1; break; } } switch (t[i]) { case '/': /* fallthrough */ case '"': /* fallthrough */ case '\'': /* fallthrough */ case '&': /* fallthrough */ case '|': /* fallthrough */ case ';': /* fallthrough */ case '>': /* fallthrough */ case '(': /* fallthrough */ case '[': /* fallthrough */ case '{': /* fallthrough */ case ')': /* fallthrough */ case ']': /* fallthrough */ case '}': /* fallthrough */ case '$': /* fallthrough */ case '-': /* fallthrough */ case '~': /* fallthrough */ case '*': /* fallthrough */ case '#': if (i == 0 || t[i - 1] != ' ') redisplay = 1; break; default: break; } if (redisplay == 1) break; } } char q[PATH_MAX + 1]; int l = 0; for (i = 0; t[i]; i++) { rl_highlight(t, i, SET_COLOR); if ((signed char)t[i] < 0) { q[l] = t[i]; l++; if ((signed char)t[i + 1] >= 0) { q[l] = '\0'; l = 0; rl_insert_text(q); } continue; } q[0] = t[i]; q[1] = '\0'; rl_insert_text(q); if (accept_first_word == 0 || redisplay == 1) rl_redisplay(); } if (s && redisplay == 1) { /* 1) rl_redisplay removes the suggestion from the current line * 2) We need rl_redisplay to correctly print highlighting colors * 3) We need to keep the suggestion when accepting only * the first suggested word. * In other words, if we correctly print colors, we lose the * suggestion. * As a workaround, let's reprint the suggestion */ size_t slen = strlen(suggestion_buf); *s = _s ? _s : ' '; print_suggestion(suggestion_buf, slen, suggestion.color); *s = '\0'; } UNHIDE_CURSOR; } else #endif /* !_NO_HIGHLIGHT */ INSERT_TEXT: { rl_insert_text(text); } } } static int rl_accept_suggestion(int count, int key) { UNUSED(count); UNUSED(key); if (kbind_busy == 1) { /* If not at the end of the typed string, just move the cursor * forward one column */ if (rl_point < rl_end) rl_point++; return FUNC_SUCCESS; } if (wrong_cmd == 0 && cur_color != hq_c) { cur_color = tx_c; fputs(tx_c, stdout); } /* Only accept the current suggestion if the cursor is at the end * of the line typed so far */ if (!conf.suggestions || rl_point != rl_end || !suggestion_buf || suggestion.type == CMD_DESC_SUG) { if (rl_point < rl_end) { /* Just move the cursor forward one character */ const int mlen = mblen(rl_line_buffer + rl_point, MB_CUR_MAX); rl_point += mlen; } return FUNC_SUCCESS; } /* If accepting the first suggested word, accept only up to next * word delimiter. */ char *s = (char *)NULL, truncated_char = 0; int truncated = 0, accept_first_word_last = 0; if (accept_first_word == 1) { char *p = suggestion_buf + (rl_point - suggestion.offset); /* Skip leading spaces */ while (*p == ' ') p++; /* Skip all consecutive word delimiters from the beginning of the * suggestion (P), except for slash and space. */ while ((s = strpbrk(p, WORD_DELIMITERS)) == p && *s != '/' && *s != ' ') p++; if (s && s != p && *(s - 1) == ' ') s = strpbrk(p, WORD_DELIMITERS); while (s && IS_UTF8_CHAR(*s)) s = strpbrk(s + 1, WORD_DELIMITERS); if (s && s[1]) { /* Truncate suggestion after word delimiter */ if (*s == '/') ++s; truncated_char = *s; *s = '\0'; truncated = 1; } else { /* Last word: No word delimiter */ const size_t len = strlen(suggestion_buf); if (len > 0 && suggestion_buf[len - 1] != '/' && suggestion_buf[len - 1] != ' ') suggestion.type = NO_SUG; accept_first_word_last = 1; s = (char *)NULL; } } const int bypass_alias = (rl_line_buffer && *rl_line_buffer == '\\' && rl_line_buffer[1]); rl_delete_text(suggestion.offset, rl_end); rl_point = suggestion.offset; if (conf.highlight == 1 && accept_first_word == 0 && cur_color != hq_c) { cur_color = tx_c; rl_redisplay(); } if (accept_first_word_last == 1) accept_first_word = 0; if (accept_first_word == 0 && (flags & BAEJ_SUGGESTION)) clear_suggestion(CS_KEEPBUF); /* Complete according to the suggestion type */ switch (suggestion.type) { case BACKDIR_SUG: /* fallthrough */ case JCMD_SUG: /* fallthrough */ case BOOKMARK_SUG: /* fallthrough */ case COMP_SUG: /* fallthrough */ case ELN_SUG: /* fallthrough */ case FASTBACK_SUG: /* fallthrough */ case FUZZY_FILENAME: /* fallthrough */ case FILE_SUG: { char *tmp = (char *)NULL; size_t i, isquote = 0, backslash = 0; for (i = 0; suggestion_buf[i]; i++) { if (is_quote_char(suggestion_buf[i])) isquote = 1; if (suggestion_buf[i] == '\\') { backslash = 1; break; } } if (isquote == 1 && backslash == 0) { if (suggestion.type == ELN_SUG && suggestion.filetype == DT_REG && conf.quoting_style != QUOTING_STYLE_BACKSLASH) tmp = quote_str(suggestion_buf); else tmp = escape_str(suggestion_buf); } my_insert_text(tmp ? tmp : suggestion_buf, NULL, 0); free(tmp); if (suggestion.type == FASTBACK_SUG) { if (conf.highlight == 0) { rl_insert_text("/"); } else if (*suggestion_buf != '/' || suggestion_buf[1]) { fputs(hd_c, stdout); rl_insert_text("/"); rl_redisplay(); fputs(df_c, stdout); } } else if (suggestion.filetype != DT_DIR && suggestion.type != BOOKMARK_SUG && suggestion.type != BACKDIR_SUG) { rl_stuff_char(' '); } suggestion.type = NO_SUG; } break; case FIRST_WORD: my_insert_text(suggestion_buf, s, truncated_char); break; case SEL_SUG: /* fallthrough */ case HIST_SUG: /* fallthrough */ case BM_NAME_SUG: /* fallthrough */ case PROMPT_SUG: /* fallthrough */ case NET_SUG: /* fallthrough */ case CSCHEME_SUG: /* fallthrough */ case WS_NAME_SUG: /* fallthrough */ case INT_HELP_SUG: /* fallthrough */ case PROFILE_SUG: /* fallthrough */ case DIRHIST_SUG: my_insert_text(suggestion_buf, NULL, 0); break; #ifndef _NO_TAGS case TAGT_SUG: /* fallthrough */ case TAGC_SUG: /* fallthrough */ case TAGS_SUG: /* fallthrough */ case WS_PREFIX_SUG: /* fallthrough */ case WS_NUM_PREFIX_SUG: case BM_PREFIX_SUG: { char prefix[3]; prefix[0] = '\0'; if (suggestion.type == TAGC_SUG) { prefix[0] = ':'; prefix[1] = '\0'; } else if (suggestion.type == TAGT_SUG) { prefix[0] = 't'; prefix[1] = ':'; prefix[2] = '\0'; } else if (suggestion.type == BM_PREFIX_SUG) { prefix[0] = 'b'; prefix[1] = ':'; prefix[2] = '\0'; } else if (suggestion.type == WS_PREFIX_SUG || suggestion.type == WS_NUM_PREFIX_SUG) { prefix[0] = 'w'; prefix[1] = ':'; prefix[2] = '\0'; } rl_insert_text(prefix); char *p = (suggestion.type != BM_PREFIX_SUG && suggestion.type != WS_PREFIX_SUG) ? escape_str(suggestion_buf) : (char *)NULL; my_insert_text(p ? p : suggestion_buf, NULL, 0); if (suggestion.type != BM_PREFIX_SUG && (fzftab != 1 || (suggestion.type != TAGT_SUG))) rl_stuff_char(' '); free(p); } break; #endif /* _NO_TAGS */ case WS_NUM_SUG: /* fallthrough */ case USER_SUG: { char *p = escape_str(suggestion_buf); my_insert_text(p ? p : suggestion_buf, NULL, 0); if (suggestion.type == USER_SUG) rl_stuff_char('/'); free(p); break; } default: if (bypass_alias == 1) rl_insert_text("\\"); my_insert_text(suggestion_buf, NULL, 0); rl_stuff_char(' '); break; } /* Move the cursor to the end of the line. */ rl_point = rl_end; if (accept_first_word == 0) { suggestion.printed = 0; free(suggestion_buf); suggestion_buf = (char *)NULL; } else { if (s && truncated == 1) /* Reinsert the char we removed to print only the first word. */ *s = truncated_char; accept_first_word = 0; } flags &= ~BAEJ_SUGGESTION; return FUNC_SUCCESS; } static int rl_accept_first_word(int count, int key) { if (rl_point < rl_end) return rl_forward_word(1, 0); /* Accepting the first suggested word is not supported for ELN's, * bookmark and alias names. */ const int t = suggestion.type; if (t != ELN_SUG && t != BOOKMARK_SUG && t != ALIAS_SUG && t != JCMD_SUG && t != FUZZY_FILENAME && t != CMD_DESC_SUG && t != BM_NAME_SUG && t != INT_HELP_SUG && t != TAGT_SUG && t != BM_PREFIX_SUG) { accept_first_word = 1; suggestion.type = FIRST_WORD; } return rl_accept_suggestion(count, key); } #endif /* !_NO_SUGGESTIONS */ static int rl_refresh(int count, int key) { UNUSED(count); UNUSED(key); exec_prompt_cmds = 1; return run_kb_cmd("rf", 0); } static int rl_dir_parent(int count, int key) { UNUSED(count); UNUSED(key); /* If already root dir, do nothing */ if (*workspaces[cur_ws].path == '/' && !workspaces[cur_ws].path[1]) return FUNC_SUCCESS; exec_prompt_cmds = 1; return run_kb_cmd("cd ..", 0); } static int rl_dir_root(int count, int key) { UNUSED(count); UNUSED(key); /* If already root dir, do nothing */ if (*workspaces[cur_ws].path == '/' && !workspaces[cur_ws].path[1]) return FUNC_SUCCESS; return run_kb_cmd("cd /", 0); } static int rl_dir_home(int count, int key) { UNUSED(count); UNUSED(key); /* If already in home, do nothing */ if (*workspaces[cur_ws].path == *user.home && strcmp(workspaces[cur_ws].path, user.home) == 0) return FUNC_SUCCESS; exec_prompt_cmds = 1; return run_kb_cmd("cd", 0); } static int rl_dir_previous(int count, int key) { UNUSED(count); UNUSED(key); /* If already at the beginning of dir hist, do nothing */ if (dirhist_cur_index == 0) return FUNC_SUCCESS; exec_prompt_cmds = 1; return run_kb_cmd("b", 0); } static int rl_dir_next(int count, int key) { UNUSED(count); UNUSED(key); /* If already at the end of dir hist, do nothing */ if (dirhist_cur_index + 1 == dirhist_total_index) return FUNC_SUCCESS; exec_prompt_cmds = 1; return run_kb_cmd("f", 0); } int rl_toggle_long_view(int count, int key) { UNUSED(count); UNUSED(key); if (kbind_busy == 1 || xargs.disk_usage_analyzer == 1) return FUNC_SUCCESS; #ifndef _NO_SUGGESTIONS if (suggestion.printed && suggestion_buf) free_suggestion(); #endif /* !_NO_SUGGESTIONS */ conf.long_view = !conf.long_view; update_autocmd_opts(AC_LONG_VIEW); if (conf.autols == 1) { if (conf.clear_screen == 0) /* Without this putchar(), the first entries of the directories * list are printed in the prompt line. */ putchar('\n'); reload_dirlist(); } print_reload_msg(NULL, NULL, _("Long view: %s\n"), conf.long_view == 1 ? _("on") : _("off")); xrl_reset_line_state(); return FUNC_SUCCESS; } int rl_toggle_follow_link_long(int count, int key) { UNUSED(count); UNUSED(key); if (kbind_busy == 1 || conf.long_view == 0 || conf.light_mode == 1) return FUNC_SUCCESS; #ifndef _NO_SUGGESTIONS if (suggestion.printed && suggestion_buf) free_suggestion(); #endif /* !_NO_SUGGESTIONS */ conf.follow_symlinks_long = !conf.follow_symlinks_long; if (conf.autols == 1) { if (conf.clear_screen == 0) /* Without this putchar(), the first entries of the directories * list are printed in the prompt line. */ putchar('\n'); reload_dirlist(); } print_reload_msg(NULL, NULL, _("Follow links: %s\n"), conf.follow_symlinks_long == 1 ? _("on") : _("off")); xrl_reset_line_state(); return FUNC_SUCCESS; } int rl_toggle_dirs_first(int count, int key) { UNUSED(count); UNUSED(key); if (kbind_busy == 1) return FUNC_SUCCESS; #ifndef _NO_SUGGESTIONS if (suggestion.printed && suggestion_buf) free_suggestion(); #endif /* !_NO_SUGGESTIONS */ conf.list_dirs_first = !conf.list_dirs_first; if (conf.autols == 1) { if (conf.clear_screen == 0) putchar('\n'); reload_dirlist(); } print_reload_msg(NULL, NULL, _("Directories first: %s\n"), conf.list_dirs_first ? _("on") : _("off")); xrl_reset_line_state(); return FUNC_SUCCESS; } int rl_toggle_light_mode(int count, int key) { UNUSED(count); UNUSED(key); if (kbind_busy == 1) return FUNC_SUCCESS; #ifndef _NO_SUGGESTIONS if (suggestion.printed && suggestion_buf) free_suggestion(); #endif /* !_NO_SUGGESTIONS */ conf.light_mode = !conf.light_mode; update_autocmd_opts(AC_LIGHT_MODE); if (conf.autols == 1) { if (conf.clear_screen == 0) putchar('\n'); reload_dirlist(); } print_reload_msg(NULL, NULL, _("Light mode: %s\n"), conf.light_mode == 1 ? _("on") : _("off")); xrl_reset_line_state(); /* RL_DISPATCHING is zero when called from lightmode_function(), * in exec.c. Otherwise, it is called from a keybinding and * rl_update_prompt() must be executed. */ if (rl_dispatching == 1) rl_update_prompt(); return FUNC_SUCCESS; } int rl_toggle_hidden_files(int count, int key) { UNUSED(count); UNUSED(key); if (kbind_busy == 1) return FUNC_SUCCESS; #ifndef _NO_SUGGESTIONS if (suggestion.printed && suggestion_buf) free_suggestion(); #endif /* !_NO_SUGGESTIONS */ static int hidden_bk = 0; if (conf.show_hidden != 0) { hidden_bk = conf.show_hidden; } else { if (hidden_bk == 0) hidden_bk = 1; } conf.show_hidden = conf.show_hidden > 0 ? 0 : hidden_bk; update_autocmd_opts(AC_SHOW_HIDDEN); if (conf.autols == 1) { if (conf.clear_screen == 0) putchar('\n'); reload_dirlist(); } print_reload_msg(NULL, NULL, _("Hidden files: %s\n"), (conf.show_hidden > 0) ? _("on") : _("off")); xrl_reset_line_state(); return FUNC_SUCCESS; } static int rl_open_config(int count, int key) { UNUSED(count); UNUSED(key); return run_kb_cmd("config", 0); } static int rl_open_keybinds(int count, int key) { UNUSED(count); UNUSED(key); return run_kb_cmd("kb edit", 0); } static int rl_open_cscheme(int count, int key) { UNUSED(count); UNUSED(key); return run_kb_cmd("cs edit", 0); } static int rl_open_bm_file(int count, int key) { UNUSED(count); UNUSED(key); return run_kb_cmd("bm edit", 0); } static int rl_open_jump_db(int count, int key) { UNUSED(count); UNUSED(key); return run_kb_cmd("je", 0); } static int rl_open_preview(int count, int key) { UNUSED(count); UNUSED(key); if (!config_dir || kbind_busy == 1) return FUNC_FAILURE; char *file = xnmalloc(config_dir_len + 15, sizeof(char)); snprintf(file, config_dir_len + 15, "%s/preview.clifm", config_dir); const int ret = open_file(file); free(file); rl_on_new_line(); return ret; } static int rl_open_mime(int count, int key) { UNUSED(count); UNUSED(key); return run_kb_cmd("mm edit", 0); } static int rl_mountpoints(int count, int key) { UNUSED(count); UNUSED(key); return run_kb_cmd("mp", 1); } static int rl_select_all(int count, int key) { UNUSED(count); UNUSED(key); exec_prompt_cmds = 1; return run_kb_cmd("s ^", 0); } static int rl_deselect_all(int count, int key) { UNUSED(count); UNUSED(key); exec_prompt_cmds = 1; return run_kb_cmd("ds *", 0); } static int rl_bookmarks(int count, int key) { UNUSED(count); UNUSED(key); return run_kb_cmd("bm", 1); } static int rl_selbox(int count, int key) { UNUSED(count); UNUSED(key); return run_kb_cmd("ds", 1); } static int rl_clear_line(int count, int key) { UNUSED(count); UNUSED(key); if (kbind_busy == 1 && alt_prompt == 0) return FUNC_SUCCESS; words_num = 0; #ifndef _NO_HIGHLIGHT if (cur_color != tx_c) { cur_color = tx_c; fputs(cur_color, stdout); } #endif /* !_NO_HIGHLIGHT */ #ifndef _NO_SUGGESTIONS if (wrong_cmd) { if (!recover_from_wrong_cmd()) rl_point = 0; } if (suggestion.nlines > term_lines) { rl_on_new_line(); return FUNC_SUCCESS; } if (suggestion_buf) { clear_suggestion(CS_FREEBUF); suggestion.printed = 0; suggestion.nlines = 0; } #endif /* !_NO_SUGGESTIONS */ curhistindex = current_hist_n; rl_kill_text(0, rl_end); rl_point = rl_end = 0; return FUNC_SUCCESS; } static int rl_sort_next(int count, int key) { UNUSED(count); UNUSED(key); if (kbind_busy == 1) return FUNC_SUCCESS; #ifndef _NO_SUGGESTIONS if (suggestion.printed && suggestion_buf) free_suggestion(); #endif /* !_NO_SUGGESTIONS */ #ifndef ST_BTIME if (conf.sort + 1 == SBTIME) conf.sort++; #endif /* !ST_BTIME */ if (conf.light_mode == 1) while (!ST_IN_LIGHT_MODE(conf.sort + 1) && conf.sort + 1 <= SORT_TYPES) conf.sort++; conf.sort++; if (conf.sort > SORT_TYPES) conf.sort = 0; if (conf.autols == 1) { sort_switch = 1; if (conf.clear_screen == 0) putchar('\n'); reload_dirlist(); sort_switch = 0; } xrl_update_prompt(); update_autocmd_opts(AC_SORT); xrl_reset_line_state(); return FUNC_SUCCESS; } static int rl_sort_previous(int count, int key) { UNUSED(count); UNUSED(key); if (kbind_busy == 1) return FUNC_SUCCESS; #ifndef _NO_SUGGESTIONS if (suggestion.printed && suggestion_buf) free_suggestion(); #endif /* !_NO_SUGGESTIONS */ #ifndef ST_BTIME if (conf.sort - 1 == SBTIME) conf.sort--; #endif /* !ST_BTIME */ if (conf.light_mode == 1) while (!ST_IN_LIGHT_MODE(conf.sort - 1) && conf.sort - 1 >= 0) conf.sort--; conf.sort--; if (conf.sort < 0) conf.sort = conf.light_mode == 1 ? SINO : SORT_TYPES; if (conf.autols == 1) { sort_switch = 1; if (conf.clear_screen == 0) putchar('\n'); reload_dirlist(); sort_switch = 0; } xrl_update_prompt(); update_autocmd_opts(AC_SORT); xrl_reset_line_state(); return FUNC_SUCCESS; } static int rl_lock(int count, int key) { UNUSED(count); UNUSED(key); int ret = FUNC_SUCCESS; #ifndef _NO_SUGGESTIONS if (suggestion.printed && suggestion_buf) free_suggestion(); #endif /* !_NO_SUGGESTIONS */ rl_deprep_terminal(); #if defined(__APPLE__) char *cmd[] = {"bashlock", NULL}; /* See https://github.com/acornejo/bashlock */ #elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) \ || defined(__DragonFly__) char *cmd[] = {"lock", "-p", NULL}; #elif defined(__HAIKU__) char *cmd[] = {"peaclock", NULL}; #else char *cmd[] = {"vlock", NULL}; #endif /* __APPLE__ */ ret = launch_execv(cmd, FOREGROUND, E_NOFLAG); rl_prep_terminal(0); xrl_reset_line_state(); if (ret != FUNC_SUCCESS) return FUNC_FAILURE; return FUNC_SUCCESS; } static int handle_no_sel(const char *func) { #ifndef _NO_SUGGESTIONS if (conf.colorize == 1 && wrong_cmd == 1) recover_from_wrong_cmd(); if (suggestion.printed == 1 && suggestion_buf) clear_suggestion(CS_FREEBUF); #endif /* !_NO_SUGGESTIONS */ if (rl_end > 0) { rl_delete_text(0, rl_end); rl_point = rl_end = 0; } printf(_("\n%s: No selected files\n"), func); rl_reset_line_state(); return FUNC_SUCCESS; } static int rl_archive_sel(int count, int key) { UNUSED(count); UNUSED(key); if (kbind_busy == 1) return FUNC_SUCCESS; if (sel_n == 0) return handle_no_sel("ac"); fputs(_("\nReady to archive/compress selected files."), stdout); return run_kb_cmd("ac sel", 1); } static int rl_remove_sel(int count, int key) { UNUSED(count); UNUSED(key); if (kbind_busy == 1) return FUNC_SUCCESS; if (sel_n == 0) return handle_no_sel("r"); rl_deprep_terminal(); char cmd[] = "r sel"; keybind_exec_cmd(cmd); g_prompt_ignore_empty_line = 1; rl_prep_terminal(0); rl_reset_line_state(); return FUNC_SUCCESS; } static int rl_export_sel(int count, int key) { UNUSED(count); UNUSED(key); if (kbind_busy == 1) return FUNC_SUCCESS; if (sel_n == 0) return handle_no_sel("exp"); fputs(_("\nReady to export selected filenames"), stdout); return run_kb_cmd("exp sel", 0); } static int rl_move_sel(int count, int key) { UNUSED(count); UNUSED(key); if (sel_n == 0) return handle_no_sel("m"); exec_prompt_cmds = 1; return run_kb_cmd("m sel", 0); } static int rl_rename_sel(int count, int key) { UNUSED(count); UNUSED(key); if (sel_n == 0) return handle_no_sel("br"); exec_prompt_cmds = 1; return run_kb_cmd("br sel", 0); } static int rl_paste_sel(int count, int key) { UNUSED(count); UNUSED(key); if (kbind_busy == 1) return FUNC_SUCCESS; if (sel_n == 0) return handle_no_sel("c"); exec_prompt_cmds = 1; rl_deprep_terminal(); char cmd[] = "c sel"; keybind_exec_cmd(cmd); rl_prep_terminal(0); rl_reset_line_state(); return FUNC_SUCCESS; } int rl_quit(int count, int key) { UNUSED(count); UNUSED(key); puts("\n"); /* Reset terminal attributes before exiting. */ rl_deprep_terminal(); exit(FUNC_SUCCESS); } #ifndef _NO_PROFILES /* Get current profile and total number of profiles and store this info * in pointers CUR and TOTAL. */ static void get_cur_prof(int *cur, int *total) { int i; for (i = 0; profile_names[i]; i++) { (*total)++; if (!alt_profile) { if (*profile_names[i] == 'd' && strcmp(profile_names[i], "default") == 0) *cur = i; } else { if (*alt_profile == *profile_names[i] && strcmp(alt_profile, profile_names[i]) == 0) *cur = i; } } } static int rl_profile_previous(int count, int key) { UNUSED(count); UNUSED(key); if (kbind_busy == 1) return FUNC_SUCCESS; #ifndef _NO_SUGGESTIONS if (suggestion.printed && suggestion_buf) free_suggestion(); #endif /* !_NO_SUGGESTIONS */ int prev_prof, cur_prof = -1, total_profs = 0; get_cur_prof(&cur_prof, &total_profs); if (cur_prof == -1 || !profile_names[cur_prof] || total_profs <= 1) return FUNC_FAILURE; prev_prof = cur_prof - 1; total_profs--; if (prev_prof < 0 || !profile_names[prev_prof]) prev_prof = total_profs; if (conf.clear_screen) { CLEAR; } else { putchar('\n'); } profile_set(profile_names[prev_prof]); rl_update_prompt_old(); return FUNC_SUCCESS; } static int rl_profile_next(int count, int key) { UNUSED(count); UNUSED(key); if (kbind_busy == 1) return FUNC_SUCCESS; #ifndef _NO_SUGGESTIONS if (suggestion.printed && suggestion_buf) free_suggestion(); #endif /* !_NO_SUGGESTIONS */ int next_prof, cur_prof = -1, total_profs = 0; get_cur_prof(&cur_prof, &total_profs); if (cur_prof == -1 || !profile_names[cur_prof] || total_profs <= 1) return FUNC_FAILURE; next_prof = cur_prof + 1; total_profs--; if (next_prof > total_profs || !profile_names[next_prof] || total_profs <= 1) next_prof = 0; if (conf.clear_screen) { CLEAR; } else { putchar('\n'); } profile_set(profile_names[next_prof]); rl_update_prompt_old(); return FUNC_SUCCESS; } #endif /* _NO_PROFILES */ static int rl_dirhist(int count, int key) { UNUSED(count); UNUSED(key); return run_kb_cmd("dh", 0); } static int rl_new_instance(int count, int key) { UNUSED(count); UNUSED(key); exec_prompt_cmds = 1; return run_kb_cmd("x .", 0); } static int rl_clear_msgs(int count, int key) { UNUSED(count); UNUSED(key); exec_prompt_cmds = 1; return run_kb_cmd("msg clear", 0); } static int rl_trash_sel(int count, int key) { UNUSED(count); UNUSED(key); if (sel_n == 0) return handle_no_sel("trash"); exec_prompt_cmds = 1; return run_kb_cmd("t sel", 1); } static int rl_untrash_all(int count, int key) { UNUSED(count); UNUSED(key); exec_prompt_cmds = 1; return run_kb_cmd("u *", 0); } static int rl_open_sel(int count, int key) { UNUSED(count); UNUSED(key); if (sel_n == 0) return handle_no_sel("open"); char cmd[PATH_MAX + 4]; snprintf(cmd, sizeof(cmd), "o %s", sel_elements[sel_n - 1].name); return run_kb_cmd(cmd, 0); } static int run_man_cmd(char *str) { char *mp = (char *)NULL; const char *p = getenv("MANPAGER"); if (p) { const size_t len = strlen(p); mp = xnmalloc(len + 1, sizeof(char *)); xstrsncpy(mp, p, len + 1); unsetenv("MANPAGER"); } const int ret = launch_execl(str) != FUNC_SUCCESS; if (mp) { setenv("MANPAGER", mp, 1); free(mp); } if (ret != 0) /* Restore prompt in case of failure. */ rl_reset_line_state(); return ret; } static int rl_kbinds_help(int count, int key) { if (kbind_busy == 1) return FUNC_SUCCESS; UNUSED(count); UNUSED(key); #ifndef _NO_SUGGESTIONS if (suggestion.printed && suggestion_buf) free_suggestion(); #endif /* !_NO_SUGGESTIONS */ char cmd[PATH_MAX]; snprintf(cmd, sizeof(cmd), "export PAGER=\"less -p ^[0-9]+\\.[[:space:]]KEYBOARD[[:space:]]SHORTCUTS\"; man %s\n", PROGRAM_NAME); const int ret = run_man_cmd(cmd); if (!ret) return FUNC_FAILURE; return FUNC_SUCCESS; } static int rl_cmds_help(int count, int key) { if (kbind_busy == 1) return FUNC_SUCCESS; UNUSED(count); UNUSED(key); #ifndef _NO_SUGGESTIONS if (suggestion.printed && suggestion_buf) free_suggestion(); #endif /* !_NO_SUGGESTIONS */ char cmd[PATH_MAX]; snprintf(cmd, sizeof(cmd), "export PAGER=\"less -p ^[0-9]+\\.[[:space:]]COMMANDS\"; man %s\n", PROGRAM_NAME); const int ret = run_man_cmd(cmd); if (!ret) return FUNC_FAILURE; return FUNC_SUCCESS; } static int rl_manpage(int count, int key) { if (kbind_busy == 1) return FUNC_SUCCESS; UNUSED(count); UNUSED(key); #ifndef _NO_SUGGESTIONS if (suggestion.printed && suggestion_buf) free_suggestion(); #endif /* !_NO_SUGGESTIONS */ char *cmd[] = {"man", PROGRAM_NAME, NULL}; if (launch_execv(cmd, FOREGROUND, E_NOFLAG) != FUNC_SUCCESS) { rl_reset_line_state(); return FUNC_FAILURE; } return FUNC_SUCCESS; } static int rl_dir_pinned(int count, int key) { UNUSED(count); UNUSED(key); if (pinned_dir == NULL) { printf(_("\n%s: No pinned file\n"), PROGRAM_NAME); rl_reset_line_state(); return FUNC_SUCCESS; } return run_kb_cmd(",", 0); } /* Switch to workspace N. */ static int rl_switch_workspace(const int n) { if (kbind_busy == 1) return FUNC_SUCCESS; if (rl_line_buffer && *rl_line_buffer) rl_delete_text(0, rl_end); char t[MAX_INT_STR + 4]; exec_prompt_cmds = 1; if (cur_ws == (n - 1)) { /* If the user attempts to switch to the same workspace they're * currently in, switch rather to the previous workspace. */ if (prev_ws != cur_ws) { snprintf(t, sizeof(t), "ws %d", prev_ws + 1); return run_kb_cmd(t, 0); } return FUNC_SUCCESS; } snprintf(t, sizeof(t), "ws %d", n); return run_kb_cmd(t, 0); } static int rl_ws1(int count, int key) { UNUSED(count); UNUSED(key); return rl_switch_workspace(1); } static int rl_ws2(int count, int key) { UNUSED(count); UNUSED(key); return rl_switch_workspace(2); } static int rl_ws3(int count, int key) { UNUSED(count); UNUSED(key); return rl_switch_workspace(3); } static int rl_ws4(int count, int key) { UNUSED(count); UNUSED(key); return rl_switch_workspace(4); } static int run_plugin(const int num) { if (kbind_busy == 1) return FUNC_SUCCESS; if (rl_line_buffer && *rl_line_buffer) setenv("CLIFM_LINE", rl_line_buffer, 1); char cmd[MAX_INT_STR + 7]; snprintf(cmd, sizeof(cmd), "plugin%d", num); const int ret = run_kb_cmd(cmd, 0); unsetenv("CLIFM_LINE"); return ret; } static int rl_plugin1(int count, int key) { UNUSED(count); UNUSED(key); return run_plugin(1); } static int rl_plugin2(int count, int key) { UNUSED(count); UNUSED(key); return run_plugin(2); } static int rl_plugin3(int count, int key) { UNUSED(count); UNUSED(key); return run_plugin(3); } static int rl_plugin4(int count, int key) { UNUSED(count); UNUSED(key); return run_plugin(4); } static int rl_plugin5(int count, int key) { UNUSED(count); UNUSED(key); return run_plugin(5); } static int rl_plugin6(int count, int key) { UNUSED(count); UNUSED(key); return run_plugin(6); } static int rl_plugin7(int count, int key) { UNUSED(count); UNUSED(key); return run_plugin(7); } static int rl_plugin8(int count, int key) { UNUSED(count); UNUSED(key); return run_plugin(8); } static int rl_plugin9(int count, int key) { UNUSED(count); UNUSED(key); return run_plugin(9); } static int rl_plugin10(int count, int key) { UNUSED(count); UNUSED(key); return run_plugin(10); } static int rl_plugin11(int count, int key) { UNUSED(count); UNUSED(key); return run_plugin(11); } static int rl_plugin12(int count, int key) { UNUSED(count); UNUSED(key); return run_plugin(12); } static int rl_plugin13(int count, int key) { UNUSED(count); UNUSED(key); return run_plugin(13); } static int rl_plugin14(int count, int key) { UNUSED(count); UNUSED(key); return run_plugin(14); } static int rl_plugin15(int count, int key) { UNUSED(count); UNUSED(key); return run_plugin(15); } static int rl_plugin16(int count, int key) { UNUSED(count); UNUSED(key); return run_plugin(16); } static int rl_launch_view(int count, int key) { UNUSED(count); UNUSED(key); exec_prompt_cmds = 1; return run_kb_cmd("view", 0); } static int rl_toggle_only_dirs(int count, int key) { UNUSED(count); UNUSED(key); if (kbind_busy == 1) return FUNC_SUCCESS; conf.only_dirs = !conf.only_dirs; update_autocmd_opts(AC_ONLY_DIRS); const int exit_status = exit_code; if (conf.autols == 1) { if (conf.clear_screen == 0) putchar('\n'); reload_dirlist(); } print_reload_msg(NULL, NULL, _("Only directories: %s\n"), conf.only_dirs > 0 ? _("on") : _("off")); xrl_reset_line_state(); return exit_status; } #ifndef _NO_HIGHLIGHT static void print_highlight_string(char *s, const int insert_point) { if (!s || !*s) return; size_t i, l = 0; rl_delete_text(insert_point, rl_end); rl_point = rl_end = insert_point; fputs(tx_c, stdout); cur_color = tx_c; char q[PATH_MAX + 1]; for (i = 0; s[i]; i++) { rl_highlight(s, i, SET_COLOR); if ((signed char)s[i] < 0) { q[l] = s[i]; l++; if ((signed char)s[i + 1] >= 0) { q[l] = '\0'; l = 0; rl_insert_text(q); rl_redisplay(); } continue; } q[0] = s[i]; q[1] = '\0'; rl_insert_text(q); rl_redisplay(); } } #endif /* !_NO_HIGHLIGHT */ static int print_cmdhist_line(int n, int beg_line) { #ifndef _NO_SUGGESTIONS if (wrong_cmd == 1) recover_from_wrong_cmd(); #endif /* !_NO_SUGGESTIONS */ curhistindex = (size_t)n; HIDE_CURSOR; int rl_point_bk = rl_point; #ifndef _NO_HIGHLIGHT if (conf.highlight == 1) print_highlight_string(history[n].cmd, 0); else #endif /* !_NO_HIGHLIGHT */ { rl_replace_line(history[n].cmd, 1); } UNHIDE_CURSOR; rl_point = (beg_line == 1) ? rl_end : rl_point_bk; cur_color = df_c; fputs(df_c, stdout); return FUNC_SUCCESS; } static inline int handle_cmdhist_beginning(int key) { int p = (int)curhistindex; cmdhist_flag = 1; if (key == 65) { /* Up arrow key */ if (--p < 0) return FUNC_FAILURE; } else { /* Down arrow key */ if (rl_end == 0) return FUNC_SUCCESS; if (++p >= (int)current_hist_n) { rl_replace_line("", 1); curhistindex++; return FUNC_SUCCESS; } } if (!history[p].cmd) return FUNC_FAILURE; curhistindex = (size_t)p; return print_cmdhist_line(p, 1); } static inline int handle_cmdhist_middle(int key) { int found = 0, p = (int)curhistindex; if (key == 65) { /* Up arrow key */ if (--p < 0) return FUNC_FAILURE; while (p >= 0 && history[p].cmd) { if (strncmp(rl_line_buffer, history[p].cmd, (size_t)rl_point) == 0 && strcmp(rl_line_buffer, history[p].cmd) != 0) { found = 1; break; } p--; } } else { /* Down arrow key */ if (++p >= (int)current_hist_n) return FUNC_FAILURE; while (history[p].cmd) { if (strncmp(rl_line_buffer, history[p].cmd, (size_t)rl_point) == 0 && strcmp(rl_line_buffer, history[p].cmd) != 0) { found = 1; break; } p++; } } if (found == 0) { rl_ring_bell(); return FUNC_FAILURE; } return print_cmdhist_line(p, 0); } /* Handle keybinds for the cmds history: UP/C-p and DOWN/C-n */ static int rl_cmdhist(int count, int key) { UNUSED(count); if (rl_nohist == 1) return FUNC_SUCCESS; #ifndef _NO_SUGGESTIONS if (suggestion_buf) { free(suggestion_buf); suggestion_buf = (char *)NULL; } #endif /* !_NO_SUGGESTIONS */ if (key == 16) /* C-p */ key = 65; /* Up */ if (key == 14) /* C-n */ key = 66; /* Down */ if (key != 65 && key != 66) return FUNC_FAILURE; /* If the cursor is at the beginning of the line */ if (rl_point == 0 || cmdhist_flag == 1) return handle_cmdhist_beginning(key); return handle_cmdhist_middle(key); } static int rl_toggle_disk_usage(int count, int key) { UNUSED(count); UNUSED(key); if (kbind_busy == 1) return FUNC_SUCCESS; /* Default values */ static int dsort = DEF_SORT, dlong = DEF_LONG_VIEW, ddirsize = DEF_FULL_DIR_SIZE, ddf = DEF_LIST_DIRS_FIRST; if (xargs.disk_usage_analyzer == 1) { xargs.disk_usage_analyzer = 0; conf.sort = dsort; conf.long_view = dlong; conf.full_dir_size = ddirsize; conf.list_dirs_first = ddf; } else { xargs.disk_usage_analyzer = 1; dsort = conf.sort; dlong = conf.long_view; ddirsize = conf.full_dir_size; ddf = conf.list_dirs_first; conf.sort = STSIZE; conf.long_view = conf.full_dir_size = 1; conf.list_dirs_first = 0; } const int exit_status = exit_code; if (conf.autols == 1) { if (conf.clear_screen == 0) putchar('\n'); reload_dirlist(); } print_reload_msg(NULL, NULL, _("Disk usage analyzer: %s\n"), xargs.disk_usage_analyzer == 1 ? _("on") : _("off")); xrl_reset_line_state(); return exit_status; } static int rl_tab_comp(int count, int key) { #ifndef _NO_SUGGESTIONS if (suggestion.printed && suggestion_buf) clear_suggestion(CS_FREEBUF); #endif /* !_NO_SUGGESTIONS */ UNUSED(count); UNUSED(key); tab_complete('!'); return FUNC_SUCCESS; } static int rl_del_last_word(int count, int key) { #ifndef _NO_SUGGESTIONS if (suggestion.printed && suggestion_buf) clear_suggestion(CS_FREEBUF); #endif /* !_NO_SUGGESTIONS */ UNUSED(count); UNUSED(key); if (rl_point == 0) return FUNC_SUCCESS; char *end_buf = (char *)NULL; if (rl_point < rl_end) { /* Somewhere before the end of the line */ end_buf = rl_copy_text(rl_point, rl_end); rl_delete_text(rl_point, rl_end); } char *b = rl_line_buffer; if (b[rl_point - 1] == '/' || b[rl_point - 1] == ' ') { --rl_point; b[rl_point] = '\0'; --rl_end; } int n = 0; char *p = xstrrpbrk(b, WORD_DELIMITERS); if (p) n = (int)(p - b) + (*(p + 1) ? 1 : 0); rl_begin_undo_group(); rl_delete_text(n, rl_end); rl_end_undo_group(); rl_point = rl_end = n; if (end_buf) { rl_insert_text(end_buf); rl_point = n; free(end_buf); } rl_redisplay(); #ifndef _NO_SUGGESTIONS if (conf.suggestions == 1 && n == 0 && wrong_cmd) recover_from_wrong_cmd(); #endif /* !_NO_SUGGESTIONS */ return FUNC_SUCCESS; } static int rl_toggle_virtualdir_full_paths(int count, int key) { UNUSED(count); UNUSED(key); if (!stdin_tmp_dir || strcmp(stdin_tmp_dir, workspaces[cur_ws].path) != 0) return FUNC_SUCCESS; xchmod(stdin_tmp_dir, "0700", 1); xargs.virtual_dir_full_paths = !xargs.virtual_dir_full_paths; filesn_t i = files; while (--i >= 0) { char *rp = xrealpath(file_info[i].name, NULL); if (!rp) continue; char *p = (char *)NULL; if (xargs.virtual_dir_full_paths != 1) { if ((p = strrchr(rp, '/')) && p[1]) ++p; } else { p = replace_slashes(rp, ':'); } if (!p || !*p) continue; if (renameat(XAT_FDCWD, file_info[i].name, XAT_FDCWD, p) == -1) err('w', PRINT_PROMPT, "renameat: %s: %s\n", file_info[i].name, strerror(errno)); if (xargs.virtual_dir_full_paths == 1) free(p); free(rp); } xchmod(stdin_tmp_dir, "0500", 1); if (conf.clear_screen == 0) putchar('\n'); reload_dirlist(); print_reload_msg(NULL, NULL, _("Switched to %s names\n"), xargs.virtual_dir_full_paths == 1 ? _("long") : _("short")); xrl_reset_line_state(); return FUNC_SUCCESS; } static int rl_run_pager(int count, int key) { UNUSED(count); UNUSED(key); if (kbind_busy == 1 || conf.pager == 1) return FUNC_SUCCESS; return run_kb_cmd("pg", 0); } /* Run "!" to display the command history via finder. */ static int rl_cmdhist_tab(int count, int key) { UNUSED(count); UNUSED(key); rl_insert_text("!"); rl_point = rl_end; #ifndef _NO_SUGGESTIONS if (suggestion_buf) clear_suggestion(CS_FREEBUF); #endif /* _NO_SUGGESTIONS */ tab_complete('!'); if (rl_end > 0 && rl_line_buffer[rl_end - 1] == '!') { rl_end--; rl_point--; } return FUNC_SUCCESS; } static int rl_toggle_vi_mode(int count, int key) { UNUSED(count); UNUSED(key); Keymap keymap = rl_get_keymap(); if (keymap == vi_insertion_keymap) { keymap = rl_get_keymap_by_name("emacs-standard"); rl_set_keymap(keymap); rl_editing_mode = RL_EMACS_MODE; } else if (keymap == emacs_standard_keymap) { keymap = rl_get_keymap_by_name("vi-insert"); rl_set_keymap(keymap); rl_editing_mode = RL_VI_MODE; } else { return FUNC_SUCCESS; } const size_t n = rl_prompt ? count_chars(rl_prompt, '\n') : 0; if (n > 0 && n <= INT_MAX) MOVE_CURSOR_UP((int)n); putchar('\r'); ERASE_TO_RIGHT_AND_BELOW; fflush(stdout); xrl_reset_line_state(); rl_update_prompt(); return FUNC_SUCCESS; } /* Used to disable keybindings. */ static int do_nothing(int count, int key) { UNUSED(count); UNUSED(key); return FUNC_SUCCESS; } /* Hold kebinding names and associated functions. */ struct keyfuncs_t { const char *name; int (*func)(int, int); }; /* Return a pointer to the function associated to the keybinding name NAME. */ static int (*get_function(struct keyfuncs_t *s, const char *name))(int, int) { while (s->name) { if (*name == *s->name && strncmp(name, s->name, strlen(s->name)) == 0) return s->func; s++; } return NULL; } static void set_keybinds_from_file(void) { struct keyfuncs_t keys[] = { {"show-manpage", rl_manpage}, {"show-cmds", rl_cmds_help}, {"show-kbinds", rl_kbinds_help}, {"parent-dir", rl_dir_parent}, {"previous-dir", rl_dir_previous}, {"next-dir", rl_dir_next}, {"home-dir", rl_dir_home}, {"root-dir", rl_dir_root}, {"workspace1", rl_ws1}, {"workspace2", rl_ws2}, {"workspace3", rl_ws3}, {"workspace4", rl_ws4}, {"create-file", rl_create_file}, {"archive-sel", rl_archive_sel}, {"open-sel", rl_open_sel}, {"export-sel", rl_export_sel}, {"move-sel", rl_move_sel}, {"rename-sel", rl_rename_sel}, {"remove-sel", rl_remove_sel}, {"trash-sel", rl_trash_sel}, {"untrash-all", rl_untrash_all}, {"paste-sel", rl_paste_sel}, {"copy-sel", rl_paste_sel}, {"select-all", rl_select_all}, {"deselect-all", rl_deselect_all}, {"open-mime", rl_open_mime}, {"open-jump-db", rl_open_jump_db}, {"open-preview", rl_open_preview}, {"open-config", rl_open_config}, {"edit-color-scheme", rl_open_cscheme}, {"open-keybinds", rl_open_keybinds}, {"open-bookmarks", rl_open_bm_file}, {"toggle-virtualdir-full-paths", rl_toggle_virtualdir_full_paths}, {"clear-msgs", rl_clear_msgs}, #ifndef _NO_PROFILES {"next-profile", rl_profile_next}, {"previous-profile", rl_profile_previous}, #endif // _NO_PROFILES {"quit", rl_quit}, {"lock", rl_lock}, {"refresh-screen", rl_refresh}, {"clear-line", rl_clear_line}, {"toggle-hidden", rl_toggle_hidden_files}, {"toggle-long", rl_toggle_long_view}, {"toggle-follow-links-long", rl_toggle_follow_link_long}, {"toggle-light", rl_toggle_light_mode}, {"dirs-first", rl_toggle_dirs_first}, {"sort-previous", rl_sort_previous}, {"sort-next", rl_sort_next}, {"only-dirs", rl_toggle_only_dirs}, {"run-pager", rl_run_pager}, {"launch-view", rl_launch_view}, {"new-instance", rl_new_instance}, {"show-dirhist", rl_dirhist}, {"bookmarks", rl_bookmarks}, {"mountpoints", rl_mountpoints}, {"selbox", rl_selbox}, {"prepend-sudo", rl_prepend_sudo}, {"toggle-disk-usage", rl_toggle_disk_usage}, {"toggle-max-name-len", rl_toggle_max_filename_len}, {"cmd-hist", rl_cmdhist_tab}, {"plugin1", rl_plugin1}, {"plugin2", rl_plugin2}, {"plugin3", rl_plugin3}, {"plugin4", rl_plugin4}, {"plugin5", rl_plugin5}, {"plugin6", rl_plugin6}, {"plugin7", rl_plugin7}, {"plugin8", rl_plugin8}, {"plugin9", rl_plugin9}, {"plugin10", rl_plugin10}, {"plugin11", rl_plugin11}, {"plugin12", rl_plugin12}, {"plugin13", rl_plugin13}, {"plugin14", rl_plugin14}, {"plugin15", rl_plugin15}, {"plugin16", rl_plugin16}, {NULL, NULL} }; for (size_t i = 0; i < kbinds_n; i++) rl_bind_keyseq(kbinds[i].key, get_function(keys, kbinds[i].function)); const char *vi_mode_keyseq = find_key("toggle-vi-mode"); if (vi_mode_keyseq) { rl_bind_keyseq(vi_mode_keyseq, rl_toggle_vi_mode); Keymap keymap = rl_get_keymap_by_name("vi-insert"); if (keymap) rl_bind_keyseq_in_map(vi_mode_keyseq, rl_toggle_vi_mode, keymap); } } static void set_default_keybinds(void) { struct keyfuncs_t keys[] = { /* Help */ {"\\eOP", rl_manpage}, {"\\e[11~", rl_manpage}, {"\\eOQ", rl_cmds_help}, {"\\e[12~", rl_cmds_help}, {"\\eOR", rl_kbinds_help}, {"\\e[13~", rl_kbinds_help}, /* Navigation */ {"\\M-u", rl_dir_parent}, {"\\e[a", rl_dir_parent}, {"\\e[2A", rl_dir_parent}, {"\\e[1;2A", rl_dir_parent}, {"\\M-j", rl_dir_previous}, {"\\e[d", rl_dir_previous}, {"\\e[2D", rl_dir_previous}, {"\\e[1;2D", rl_dir_previous}, {"\\M-k", rl_dir_next}, {"\\e[c", rl_dir_next}, {"\\e[2C", rl_dir_next}, {"\\e[1;2C", rl_dir_next}, {"\\M-e", rl_dir_home}, {"\\e[1~", rl_dir_home}, {"\\e[7~", rl_dir_home}, {"\\e[H", rl_dir_home}, {"\\M-r", rl_dir_root}, {"\\e/", rl_dir_root}, {"\\M-p", rl_dir_pinned}, {"\\M-1", rl_ws1}, {"\\M-2", rl_ws2}, {"\\M-3", rl_ws3}, {"\\M-4", rl_ws4}, /* Operations on files */ {"\\M-n", rl_create_file}, {"\\C-\\M-a", rl_archive_sel}, {"\\C-\\M-e", rl_export_sel}, {"\\C-\\M-r", rl_rename_sel}, {"\\C-\\M-d", rl_remove_sel}, {"\\C-\\M-t", rl_trash_sel}, {"\\C-\\M-v", rl_paste_sel}, {"\\M-a", rl_select_all}, {"\\M-d", rl_deselect_all}, {"\\M-v", rl_prepend_sudo}, /* Config files */ {"\\e[17~", rl_open_mime}, {"\\e[18~", rl_open_preview}, {"\\e[19~", rl_open_cscheme}, {"\\e[20~", rl_open_keybinds}, {"\\e[21~", rl_open_config}, {"\\e[23~", rl_open_bm_file}, /* Settings */ {"\\M-w", rl_toggle_virtualdir_full_paths}, {"\\M-t", rl_clear_msgs}, {"\\M-o", rl_lock}, {"\\C-r", rl_refresh}, {"\\M-c", rl_clear_line}, {"\\M-i", rl_toggle_hidden_files}, {"\\M-.", rl_toggle_hidden_files}, {"\\M-l", rl_toggle_long_view}, {"\\M-+", rl_toggle_follow_link_long}, {"\\M-y", rl_toggle_light_mode}, {"\\M-g", rl_toggle_dirs_first}, {"\\M-z", rl_sort_previous}, {"\\M-x", rl_sort_next}, {"\\M-,", rl_toggle_only_dirs}, {"\\M-0", rl_run_pager}, /* Misc */ {"\\M--", rl_launch_view}, {"\\C-\\M-x", rl_new_instance}, {"\\M-h", rl_dirhist}, {"\\M-b", rl_bookmarks}, {"\\M-m", rl_mountpoints}, {"\\M-s", rl_selbox}, {"\\C-\\M-l", rl_toggle_max_filename_len}, {"\\C-\\M-i", rl_toggle_disk_usage}, {"\\e[24~", rl_quit}, /* {"\\C-\\M-g", rl_open_sel}, // Disabled by default {"\\C-\\M-n", rl_move_sel}, // Disabled by default {"\\C-\\M-u", rl_untrash_all}, // Disabled by default {"\\e[18~", rl_open_jump_db}, // Disabled by default */ {NULL, NULL} }; for (size_t i = 0; keys[i].name; i++) rl_bind_keyseq(keys[i].name, keys[i].func); rl_bind_keyseq("\\C-\\M-j", rl_toggle_vi_mode); Keymap keymap = rl_get_keymap_by_name("vi-insert"); if (keymap) rl_bind_keyseq_in_map("\\C-\\M-j", rl_toggle_vi_mode, keymap); } static void set_hardcoded_keybinds(void) { struct keyfuncs_t keys[] = { {"\\M-*", do_nothing}, {"\x1b[42;3u", do_nothing}, #ifndef __HAIKU__ {"\\C-l", rl_refresh}, {"\x1b[108;5u", rl_refresh}, {"\\C-p", rl_cmdhist}, {"\\C-n", rl_cmdhist}, #endif /* !__HAIKU__ */ {"\x1b[A", rl_cmdhist}, {"\x1b[B", rl_cmdhist}, {"\\M-q", rl_del_last_word}, {"\x1b[113;3u", rl_del_last_word}, #ifndef _NO_SUGGESTIONS # ifndef __HAIKU__ {"\x1b[102;5u", rl_accept_suggestion}, {"\\C-f", rl_accept_suggestion}, {"\x1b[C", rl_accept_suggestion}, {"\x1bOC", rl_accept_suggestion}, {"\x1b[102;3u", rl_accept_first_word}, {"\\M-f", rl_accept_first_word}, {"\x1b[3C", rl_accept_first_word}, {"\x1b\x1b[C", rl_accept_first_word}, {"\x1b[1;3C", rl_accept_first_word}, # else {"\x1bOC", rl_accept_suggestion}, {"\\C-f", rl_accept_first_word}, # endif /* !__HAIKU__ */ #endif /* !_NO_SUGGESTIONS */ {NULL, NULL} }; for (size_t i = 0; keys[i].name; i++) rl_bind_keyseq(keys[i].name, keys[i].func); rl_bind_key('\t', rl_tab_comp); } /* Disable readline keybindings conflicting with clifm's. * This function is called before reading the readline config file (by * default ~/.inputrc), so that the user can rebind them using any of config * files (either readline.clifm or keybindings.clifm). */ void disable_rl_conflicting_kbinds(void) { const char *const keys[] = {"\\x1b\\xd", "\\C-x(", "\\C-x\\C-u", "\\C-x\\C-x", "\\C-x\\C-g", "\\C-x\\C-?","\\C-x\\C-r", "\\C-xe", "\\C-x", "\\C-q", "\\C-d", "\\C-]", "\\e\\C-]", "\\e\\C-i", "\\e\\", "\\e\\e", "\\eb", "\\e.", "\\et", "\\ey", "\\e-", "\\eu", "\\M-5", "\\M-6", "\\M-7", "\\M-8", "\\M-9", NULL}; size_t i; for (i = 0; keys[i]; i++) rl_bind_keyseq(keys[i], do_nothing); } void readline_kbinds(void) { if (kbinds_file) set_keybinds_from_file(); else set_default_keybinds(); set_hardcoded_keybinds(); } clifm-1.26.3/src/keybinds.h000066400000000000000000000030631506632037700154600ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* keybinds.h */ #ifndef KEYBINDS_H #define KEYBINDS_H /* Let's use these word delimiters to print first suggested word * and to delete last typed word */ #define WORD_DELIMITERS " /.-_=,:;@+*&$#<>%~|({[]})¿?¡!" __BEGIN_DECLS void disable_rl_conflicting_kbinds(void); int keybind_exec_cmd(char *str); int kbinds_function(char **args); int load_keybinds(void); void readline_kbinds(void); int rl_quit(int count, int key); int rl_toggle_dirs_first(int count, int key); int rl_toggle_hidden_files(int count, int key); int rl_toggle_light_mode(int count, int key); int rl_toggle_long_view(int count, int key); int rl_toggle_max_filename_len(int count, int key); __END_DECLS #endif /* KEYBINDS_H */ clifm-1.26.3/src/linuxfs.h000066400000000000000000000166321506632037700153460ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* linuxfs.h - Macros for filesystem magic numbers */ #ifndef LINUXFS_H #define LINUXFS_H /* These macros are taken from linux/magic.h, statfs(2), and coreutils stat.c * (see https://github.com/coreutils/coreutils/blob/master/src/stat.c). */ #define T_AAFS_MAGIC 0x5a3c69f0 #define T_ACFS_MAGIC 0x61636673 /* remote */ #define T_ADFS_MAGIC 0xadf5 #define T_AFFS_MAGIC 0xadff #define T_AFS_FS_MAGIC 0x6b414653 /* k-afs: remote */ #define T_AFS_MAGIC 0x5346414f /* remote */ #define T_ANON_INODE_FS_MAGIC 0x09041934 #define T_AUFS_MAGIC 0x61756673 /* remote */ #define T_AUTOFS_MAGIC 0x0187 /* pseudo FS */ #define T_BALLONFS_MAGIC 0x13661366 #define T_BDEVFS_MAGIC 0x62646576 /* pseudo FS */ #define T_BEFS_MAGIC 0x42465331 #define T_BFS_MAGIC 0x1badface #define T_BINDERFS_MAGIC 0x6c6f6f70 #define T_BINFMTFS_MAGIC 0x42494e4d /* pseudo FS */ #define T_BPF_FS_MAGIC 0xcafe4a11 #define T_BTRFS_MAGIC 0x9123683e #define T_BTRFS_TEST_MAGIC 0x73727279 #define T_CEPH_MAGIC 0x00c36400 /* remote */ #define T_CGROUP_MAGIC 0x27e0eb /* pseudo FS */ #define T_CGROUP2_MAGIC 0x63677270 #define T_CIFS_MAGIC 0xff534D42 /* remote */ #define T_CODA_MAGIC 0x73757245 /* remote */ #define T_COH_MAGIC 0x012ff7b7 #define T_CONFIGFS_MAGIC 0x62656570 /* pseudo FS */ #define T_CRAMFS_MAGIC 0x28cd3d45 #define T_CRAMFS_MAGIC_WEND 0x453dcd28 #define T_DAXFS_MAGIC 0x64646178 #define T_DEBUGFS_MAGIC 0x64626720 /* pseudo FS */ #define T_DEVMEM_MAGIC 0x454d444d #define T_DEVFS_MAGIC 0x1373 /* Linux 2.6.17 and earlier */ /* pseudo FS */ #define T_DEVPTS_MAGIC 0x1cd1 /* pseudo FS */ #define T_DMA_BUF_MAGIC 0x444d4142 #define T_ECRYPTFS_MAGIC 0xf15f #define T_EFIVARFS_MAGIC 0xde5e81e4 #define T_EFS_MAGIC 0x414a53 #define T_EROFS_MAGIC_V1 0xe0f5e1e2 #define T_EXFAT_MAGIC 0x2011bab0 #define T_EXT_MAGIC 0x137d /* Linux 2.0 and earlier */ #define T_EXT2_OLD_MAGIC 0xef51 /* Old ext2 */ /*#define T_EXT2_MAGIC 0xef53 #define T_EXT3_MAGIC 0xef53 */ #define T_EXT4_MAGIC 0xef53 #define T_F2FS_MAGIC 0xf2f52010 #define T_FAT_MAGIC 0x4006 #define T_FHGFS_MAGIC 0x19830326 /* remote */ #define T_FUSE_MAGIC 0x65735546 /* remote */ /* pseudo FS */ #define T_FUSECTL_MAGIC 0x65735543 /* remote */ #define T_FUTEXFS_MAGIC 0xbad1dea #define T_GFS2_MAGIC 0x01161970 /* remote */ #define T_GPFS_MAGIC 0x47504653 /* remote */ #define T_HFS_MAGIC 0x4244 #define T_HFS_PLUS_MAGIC 0x482b #define T_HFSX_MAGIC 0x4858 #define T_HOSTFS_MAGIC 0x00c0ffee #define T_HPFS_MAGIC 0xf995e849 #define T_HUGETLBFS_MAGIC 0x958458f6 /* pseudo FS */ #define T_IBRIX_MAGIC 0x013111a8 /* remote */ #define T_INOTIFYFS_MAGIC 0x2bad1dea #define T_ISOFS_MAGIC 0x9660 #define T_ISOFS_R_WIN_MAGIC 0x4004 /* ISOFS_R_WIN */ #define T_ISOFS_WIN_MAGIC 0x4000 /* ISOFS_WIN */ #define T_JFFS_MAGIC 0x07c0 #define T_JFFS2_MAGIC 0x72b6 #define T_JFS_MAGIC 0x3153464a #define T_LOGFS_MAGIC 0xc97e8168 #define T_LUSTRE_MAGIC 0x0bd00bd0 /* remote */ #define T_M1FS_MAGIC 0x5346314d #define T_MINIX_MAGIC 0x137f /* minix v1 fs, 14 char names */ #define T_MINIX_MAGIC2 0x138f /* minix v1 fs, 30 char names */ #define T_MINIX2_MAGIC 0x2468 /* minix v2 fs, 14 char names */ #define T_MINIX2_MAGIC2 0x2478 /* minix v2 fs, 30 char names */ #define T_MINIX3_MAGIC 0x4d5a /* minix v3 fs, 60 char names */ #define T_MQUEUE_MAGIC 0x19800202 /* pseudo FS */ #define T_MSDOS_MAGIC 0x4d44 #define T_MTD_INODE_FS_MAGIC 0x11307854 #define T_NCP_MAGIC 0x564c /* remote */ #define T_NFS_MAGIC 0x6969 /* remote */ #define T_NFSD_MAGIC 0x6e667364 /* remote */ #define T_NILFS_MAGIC 0x3434 #define T_NSFS_MAGIC 0x6e736673 #define T_NTFS_CG_MAGIC 0x3e706ff /* Cygwin */ #define T_NTFS_MAGIC 0x5346544e #define T_OCFS2_MAGIC 0x7461636f /* remote */ #define T_OPENPROM_MAGIC 0x9fa1 #define T_OVERLAYFS_MAGIC 0x794c7630 /* remote */ #define T_PANFS_MAGIC 0xaad7aaea /* remote */ #define T_PID_FS_MAGIC 0x50494446 #define T_PIPEFS_MAGIC 0x50495045 /* remote */ /* pseudo FS */ #define T_PPC_CMM_FS_MAGIC 0xc7571590 #define T_PRL_FS_MAGIC 0x7c7c6673 /* remote */ #define T_PROC_MAGIC 0x9fa0 /* pseudo FS */ #define T_PSTOREFS_MAGIC 0x6165676c #define T_QNX4_MAGIC 0x002f #define T_QNX6_MAGIC 0x68191122 #define T_RAMFS_MAGIC 0x858458f6 #define T_RDTGROUP_MAGIC 0x7655821 #define T_REISERFS_MAGIC 0x52654973 #define T_RPC_PIPEFS_MAGIC 0x67596969 #define T_SDCARDFS_MAGIC 0x5dca2df5 #define T_SECRETMEM_MAGIC 0x5345434d #define T_SECURITYFS_MAGIC 0x73636673 /* pseudo FS */ #define T_SELINUX_MAGIC 0xf97cff8c /* pseudo FS */ #define T_SMACK_MAGIC 0x43415d53 #define T_SMB_MAGIC 0x517b /* remote */ #define T_SMB2_MAGIC 0xfe534d42 /* remote */ #define T_SNFS_MAGIC 0xbeefdead /* remote */ #define T_SOCKFS_MAGIC 0x534f434b #define T_SQUASHFS_MAGIC 0x73717368 #define T_STACK_END_MAGIC 0x57ac6e9d #define T_SYSV2_MAGIC 0x012ff7b6 #define T_SYSV4_MAGIC 0x012ff7b5 #define T_SYSFS_MAGIC 0x62656572 /* pseudo FS */ #define T_TMPFS_MAGIC 0x01021994 /* pseudo FS */ #define T_TRACEFS_MAGIC 0x74726163 #define T_UBIFS_MAGIC 0x24051905 #define T_UDF_MAGIC 0x15013346 #define T_UFS_MAGIC 0x00011954 #define T_USBDEVICE_MAGIC 0x9fa2 #define T_V9FS_MAGIC 0x01021997 #define T_VBOXSF_MAGIC 0x786f4256 /* remote */ #define T_VFAT_MAGIC 0x20206 /* Cygwin */ #define T_VMHGFS_MAGIC 0xbacbacbc /* remote */ #define T_VXFS_MAGIC 0xa501fcf5 /* remote */ #define T_VZFS_MAGIC 0x565a4653 #define T_WSLFS_MAGIC 0x53464846 #define T_XENFS_MAGIC 0xabba1974 #define T_XENIX_MAGIC 0x012ff7b4 #define T_XIA_MAGIC 0x012fd16d /* Linux 2.0 and earlier */ #define T_XFS_MAGIC 0x58465342 #define T_Z3FOLD_MAGIC 0x0033 #define T_ZFS_MAGIC 0x2fc12fc1 #define T_ZONEFS_MAGIC 0x5a4f4653 #define T_ZSMALLOCFS_MAGIC 0x58295829 #endif /* LINUXFS_H */ clifm-1.26.3/src/listing.c000066400000000000000000003131371506632037700153220ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* listing.c -- functions controlling what is listed on the screen */ #include "helpers.h" #include #include /* open(2), readlinkat(2) */ #include #include #if defined(__OpenBSD__) # include # include /* uintmax_t */ #endif /* __OpenBSD__ */ #if defined(LINUX_FILE_CAPS) # include #endif /* LINUX_FILE_CAPS */ #if defined(LINUX_FILE_XATTRS) # include #endif /* LINUX_FILE_XATTRS */ #if defined(LINUX_FSINFO) || defined(HAVE_STATFS) || defined(__sun) # include "fsinfo.h" #endif /* LINUX_FSINFO || HAVE_STATFS || __sun */ #if defined(LIST_SPEED_TEST) # include #endif /* LIST_SPEED_TEST */ #if defined(LINUX_FSINFO) # include /* major() macro */ #endif /* LINUX_FSINFO */ #if defined(TOURBIN_QSORT) # include "qsort.h" # define ENTLESS(i, j) (entrycmp(file_info + (i), file_info + (j)) < 0) # define ENTSWAP(i, j) (swap_ent((i), (j))) # define ENTSORT(file_info, n, entrycmp) QSORT((n), ENTLESS, ENTSWAP) #else # define ENTSORT(file_info, n, entrycmp) qsort((file_info), (n), sizeof(*(file_info)), (entrycmp)) #endif /* TOURBIN_QSORT */ /* Check for temporary files: * 1. "*~" Gral purpose temp files (mostly used by text editors) * 2. "#*#" Emacs auto-save temp files * 3. ".~*#" Libreoffice lock files * 4. "~$*" MS Office temp files * NOTE: MC seems to take only "*~" and "#*" as temp files. */ #define IS_TEMP_FILE(n, l) ( (l) > 0 \ && ((n)[(l) - 1] == '~' \ || ((*(n) == '#' || (*(n) == '.' \ && (n)[1] == '~')) && (n)[(l) - 1] == '#') \ || (*(n) == '~' && (n)[1] == '$') ) ) #define IS_EXEC(m) (((m) & S_IXUSR) || ((m) & S_IXGRP) || ((m) & S_IXOTH)) #include "autocmds.h" #include "aux.h" #include "checks.h" #include "colors.h" #include "dothidden.h" /* load_dothidden, check_dothidden, free_dothidden */ #ifndef _NO_ICONS # include "icons.h" #endif /* !_NO_ICONS */ #include "messages.h" #include "misc.h" #include "properties.h" /* print_analysis_stats() */ #include "long_view.h" /* print_entry_props() */ #include "sanitize.h" #include "sort.h" #include "spawn.h" #include "xdu.h" /* dir_size() */ /* In case we want to try some faster printf implementation */ /*#if defined(_PALAND_PRINTF) # include "printf.h" # define xprintf printf_ #else # define xprintf printf #endif // _PALAND_PRINTF */ #define xprintf printf /* Macros for run_dir_cmd function */ #define AUTOCMD_DIR_IN 0 #define AUTOCMD_DIR_OUT 1 #define AUTOCMD_DIR_IN_FILE ".cfm.in" #define AUTOCMD_DIR_OUT_FILE ".cfm.out" #define ENTRY_N 64 #ifdef TIGHT_COLUMNS # define COLUMNS_GAP 2 #endif #define ICONS_ELN 0 #define ICONS_NO_ELN 1 #define NO_ICONS_ELN 2 #define NO_ICONS_NO_ELN 3 /* Information about the longest filename in the curent list of files. */ struct longest_t { size_t fc_len; /* Length of the file counter (if a directory). */ size_t name_len; /* Length of the longest name. */ }; static struct longest_t longest; struct checks_t { char *icons_gap; int autocmd_files; int birthtime; int classify; int files_counter; int filter_name; int filter_type; int icons_use_file_color; int id_names; int lnk_char; int min_name_trunc; int scanning; int time_follows_sort; int xattr; int list_format; }; static struct checks_t checks; /* Struct to store information about truncated filenames. */ struct wtrunc_t { char *wname; /* Address to store filename with replaced control chars */ int type; /* Truncation type: with or without file extension. */ int diff; /* */ }; /* Hold default values for the fileinfo struct. */ static struct fileinfo default_file_info; static int pager_bk = 0; static int dir_out = 0; static int pager_quit = 0; static int pager_help = 0; static int long_view_bk = UNSET; /* A version of the loop-unswitching optimization: move loop-invariant * conditions out of the loop to reduce the number of conditions in each * loop pass. * In this case, instead of checking multiple loop-invariant conditions * in each pass of the main file listing loop (in list_dir()), we check * only one (i.e. the appropriate member of the checks struct). * The most important here is checks.lnk_char: instead of checking 4 * conditions per listed file, we check only one. Thus, if we have 100 files, * this saves 300 condition checks! */ static void init_checks_struct(void) { checks.autocmd_files = (conf.read_autocmd_files == 1 && dir_changed == 1); checks.birthtime = (conf.sort == SBTIME || (conf.long_view == 1 && prop_fields.time == PROP_TIME_BIRTH)); checks.classify = (conf.long_view == 0 && conf.classify == 1); checks.files_counter = (conf.files_counter == 1 && ((conf.long_view == 1 && prop_fields.counter == 1) || (conf.long_view == 0 && conf.classify == 1))); checks.filter_name = (filter.str && filter.type == FILTER_FILE_NAME); checks.filter_type = (filter.str && filter.type == FILTER_FILE_TYPE); checks.icons_gap = conf.icons_gap <= 0 ? "" : ((conf.icons_gap == 1) ? " " : " "); checks.icons_use_file_color = #ifndef _NO_ICONS (xargs.icons_use_file_color == 1 && conf.icons == 1); #else 0; #endif /* !_NO_ICONS */ checks.id_names = (prop_fields.ids == PROP_ID_NAME && (conf.long_view == 1 || conf.sort == SOWN || conf.sort == SGRP)); checks.lnk_char = (conf.color_lnk_as_target == 1 && conf.follow_symlinks == 1 && conf.icons == 0 && conf.light_mode == 0 && conf.colorize == 1); checks.min_name_trunc = (conf.long_view == 1 && conf.max_name_len != UNSET && conf.min_name_trunc > conf.max_name_len); checks.scanning = (xargs.disk_usage_analyzer == 1 || (conf.long_view == 1 && conf.full_dir_size == 1)); checks.time_follows_sort = (conf.time_follows_sort == 1 && conf.sort >= SATIME && conf.sort <= SMTIME); checks.xattr = (conf.long_view == 1 && prop_fields.xattr == 1); if (conf.icons == 1) checks.list_format = conf.no_eln == 1 ? ICONS_NO_ELN : ICONS_ELN; else checks.list_format = conf.no_eln == 1 ? NO_ICONS_NO_ELN : NO_ICONS_ELN; } #if !defined(_NO_ICONS) static void set_icon_names_hashes(void) { int i = (int)(sizeof(icon_filenames) / sizeof(icon_filenames[0])); name_icons_hashes = xnmalloc((size_t)i + 1, sizeof(size_t)); while (--i >= 0) name_icons_hashes[i] = hashme(icon_filenames[i].name, 0); } static void set_dir_names_hashes(void) { int i = (int)(sizeof(icon_dirnames) / sizeof(icon_dirnames[0])); dir_icons_hashes = xnmalloc((size_t)i + 1, sizeof(size_t)); while (--i >= 0) dir_icons_hashes[i] = hashme(icon_dirnames[i].name, 0); } static void set_ext_names_hashes(void) { int i = (int)(sizeof(icon_ext) / sizeof(icon_ext[0])); ext_icons_hashes = xnmalloc((size_t)i + 1, sizeof(size_t)); while (--i >= 0) ext_icons_hashes[i] = hashme(icon_ext[i].name, 0); } void init_icons_hashes(void) { set_icon_names_hashes(); set_dir_names_hashes(); set_ext_names_hashes(); } #endif /* !_NO_ICONS */ #if defined(TOURBIN_QSORT) static inline void swap_ent(const size_t id1, const size_t id2) { struct fileinfo _dent, *pdent1 = &file_info[id1], *pdent2 = &file_info[id2]; *(&_dent) = *pdent1; *pdent1 = *pdent2; *pdent2 = *(&_dent); } #endif /* TOURBIN_QSORT */ /* Return 1 if NAME contains at least one UTF8/control character, or 0 * otherwise. BYTES is updated to the number of bytes needed to read the * entire name (excluding the terminating NUL char). EXT_INDEX, if not NULL, * is updated to the index of the last dot character in NAME, provided it is * neither the first nor the last character in NAME (we assume this is a * file extension). * * This check is performed over filenames to be listed. If the filename is * not UTF8, we get its visible length from BYTES, instead of running * wc_xstrlen(). This gives us a little performance improvement: 3% faster * over 100,000 files. */ static uint8_t is_utf8_name(const char *filename, size_t *bytes, size_t *ext_index) { static const unsigned char utf8_chars[256] = { /* Control characters */ [0] = 1, [1] = 1, [2] = 1, [3] = 1, [4] = 1, [5] = 1, [6] = 1, [7] = 1, [8] = 1, [9] = 1, [10] = 1, [11] = 1, [12] = 1, [13] = 1, [14] = 1, [15] = 1, [16] = 1, [17] = 1, [18] = 1, [19] = 1, [20] = 1, [21] = 1, [22] = 1, [23] = 1, [24] = 1, [25] = 1, [26] = 1, [27] = 1, [28] = 1, [29] = 1, [30] = 1, [31] = 1, /* Delete, non-breaking space (NBSP), and soft hyphen (SHY) */ [127] = 1, [160] = 1, [173] = 1, /* UTF-8 */ [192] = 1, [193] = 1, [194] = 1, [195] = 1, [196] = 1, [197] = 1, [198] = 1, [199] = 1, [200] = 1, [201] = 1, [202] = 1, [203] = 1, [204] = 1, [205] = 1, [206] = 1, [207] = 1, [208] = 1, [209] = 1, [210] = 1, [211] = 1, [212] = 1, [213] = 1, [214] = 1, [215] = 1, [216] = 1, [217] = 1, [218] = 1, [219] = 1, [220] = 1, [221] = 1, [222] = 1, [223] = 1, [224] = 1, [225] = 1, [226] = 1, [227] = 1, [228] = 1, [229] = 1, [230] = 1, [231] = 1, [232] = 1, [233] = 1, [234] = 1, [235] = 1, [236] = 1, [237] = 1, [238] = 1, [239] = 1, [240] = 1, [241] = 1, [242] = 1, [243] = 1, [244] = 1, [245] = 1, [246] = 1, [247] = 1, [248] = 1, [249] = 1, [250] = 1, [251] = 1, [252] = 1, [253] = 1, [254] = 1, [255] = 1 }; uint8_t is_utf8 = 0; const unsigned char *start = (const unsigned char *)filename; const unsigned char *name = start; const unsigned char *ext = NULL; while (*name) { if (utf8_chars[*name]) { is_utf8 = 1; } else { if (*name == '.') ext = name; } name++; } if (ext && ext != start && ext[1] && ext_index) *ext_index = (size_t)(ext - start); *bytes = (size_t)(name - start); return is_utf8; } /* Return the number of ASCII/UTF-8 characters in the string S. */ static size_t count_utf8_chars(const char *s) { size_t count = 0; for (; *s; s++) count += !IS_UTF8_CONT_BYTE(*s); return count; } /* Set the color of the dividing line: DL, if the color code is set, * or the color of the current workspace if not. */ static void set_div_line_color(void) { if (*dl_c) { fputs(dl_c, stdout); return; } const char *def_color = term_caps.color >= 256 ? DEF_DL_C256 : DEF_DL_C; /* If div line color isn't set, use the current workspace color. */ switch (cur_ws) { case 0: fputs(*ws1_c ? ws1_c : def_color, stdout); break; case 1: fputs(*ws2_c ? ws2_c : def_color, stdout); break; case 2: fputs(*ws3_c ? ws3_c : def_color, stdout); break; case 3: fputs(*ws4_c ? ws4_c : def_color, stdout); break; case 4: fputs(*ws5_c ? ws5_c : def_color, stdout); break; case 5: fputs(*ws6_c ? ws6_c : def_color, stdout); break; case 6: fputs(*ws7_c ? ws7_c : def_color, stdout); break; case 7: fputs(*ws8_c ? ws8_c : def_color, stdout); break; default: fputs(def_color, stdout); break; } } static inline void print_bow_drawing_line(void) { fputs("\x1b(0m", stdout); int i; const int cols = (int)term_cols - 2; for (i = 0; i < cols; i++) putchar('q'); fputs("\x1b(0j\x1b(B", stdout); putchar('\n'); } static inline void print_extended_line(void) { const size_t c = count_utf8_chars(div_line); if (c > 1) { puts(div_line); return; } const char *dl = (*div_line == '-' && !div_line[1] && term_caps.unicode == 1) ? DEF_DIV_LINE_U : div_line; /* Extend DIV_LINE to the end of the screen - 1. * We subtract 1 to prevent an extra empty line after the * dividing line on some terminals (e.g. cons25). */ const size_t len = !dl[1] ? 1 : wc_xstrlen(dl); int cols = c > 0 ? (int)(term_cols / (len > 0 ? len : 1)) : 0; for (; cols > 1; cols--) fputs(dl, stdout); putchar('\n'); } /* Print the line dividing files and prompt using DIV_LINE. * If DIV_LINE is unset, draw a line using box-drawing characters. * If it contains exactly one character, print DIV_LINE up to the * right screen edge. * If it contains more than one character, print exactly the * content of DIV_LINE. * If it is "0", print an empty line. */ static void print_div_line(void) { #ifdef RUN_CMD if (cmd_line_cmd) return; #endif /* RUN_CMD */ if (conf.colorize == 1) set_div_line_color(); if (!*div_line) print_bow_drawing_line(); else if (*div_line == '0' && !div_line[1]) putchar('\n'); /* Empty line. */ else print_extended_line(); fputs(df_c, stdout); fflush(stdout); } #ifdef LINUX_FSINFO static char * get_devname(const char *file) { struct stat b; if (stat(file, &b) == -1) return DEV_NO_NAME; #if defined(__CYGWIN__) || defined(__ANDROID__) /* There's no sys filesystem on Cygwin/Termux (used by get_dev_name()), * so let's try with the proc filesystem. */ return get_dev_name_mntent(file); #else if (major(b.st_dev) == 0) return get_dev_name_mntent(file); return get_dev_name(b.st_dev); #endif /* __CYGWIN__ || __ANDROID__ */ } #endif /* LINUX_FSINFO */ /* Print free/total space for the filesystem where the current directory * resides, plus device name and filesystem type name if available. */ static void print_disk_usage(void) { if (!workspaces || !workspaces[cur_ws].path || !*workspaces[cur_ws].path) return; struct statvfs a; if (statvfs(workspaces[cur_ws].path, &a) != FUNC_SUCCESS) { err('w', PRINT_PROMPT, "statvfs: %s\n", strerror(errno)); return; } const off_t free_s = (off_t)a.f_bavail * (off_t)a.f_frsize; const off_t total = (off_t)a.f_blocks * (off_t)a.f_frsize; /* if (total == 0) return; // This is what MC does */ char *p_free_space = construct_human_size(free_s); char *free_space = savestring(p_free_space, strlen(p_free_space)); char *size = construct_human_size(total); const int free_percentage = (int)((free_s * 100) / (total > 0 ? total : 1)); char *devname = (char *)NULL; char *fstype = (char *)NULL; #ifdef _BE_POSIX fstype = DEV_NO_NAME; devname = DEV_NO_NAME; #elif defined(__NetBSD__) fstype = a.f_fstypename; devname = a.f_mntfromname; #elif defined(__sun) fstype = a.f_basetype; devname = get_dev_mountpoint(workspaces[cur_ws].path); #elif defined(LINUX_FSINFO) int remote = 0; fstype = get_fs_type_name(workspaces[cur_ws].path, &remote); devname = get_devname(workspaces[cur_ws].path); #elif defined(HAVE_STATFS) get_dev_info(workspaces[cur_ws].path, &devname, &fstype); #else fstype = DEV_NO_NAME; devname = DEV_NO_NAME; #endif /* _BE_POSIX */ print_reload_msg(NULL, NULL, _("%d%% free (%s/%s) %s %s\n"), free_percentage, free_space ? free_space : "?", size ? size : "?", fstype, devname); /* NOTE: If the f_blocks, f_bfree, f_files, f_ffree, f_bavail, and f_favail * fields of the statvfs struct are all zero, the filesystem is likely * virtual (for example, /proc, /sys, or /dev/pts). */ free(free_space); } static void print_sel_files(const unsigned short t_rows) { int limit = conf.max_printselfiles; if (conf.max_printselfiles == 0) { /* Never take more than half terminal height */ limit = (t_rows / 2) - 4; /* 4 = 2 div lines, 2 prompt lines */ if (limit <= 0) limit = 1; } if (limit > (int)sel_n) limit = (int)sel_n; int i; for (i = 0; i < (conf.max_printselfiles != UNSET ? limit : (int)sel_n) && sel_elements[i].name; i++) { char *p = abbreviate_file_name(sel_elements[i].name); if (!p) continue; colors_list(p, 0, NO_PAD, PRINT_NEWLINE); if (p != sel_elements[i].name) free(p); } if (conf.max_printselfiles != UNSET && limit < (int)sel_n) printf("... (%d/%zu)\n", i, sel_n); print_div_line(); } static void print_dirhist_map(void) { const int i = dirhist_cur_index; if (i < 0 || i >= dirhist_total_index) return; const int pad = DIGINUM(1 + (dirhist_cur_index + 1 < dirhist_total_index ? dirhist_cur_index + 1 : dirhist_cur_index)); if (i > 0 && old_pwd[i - 1]) printf("%s%*d%s %s\n", el_c, pad, i, df_c, old_pwd[i - 1]); printf("%s%*d%s %s%s%s\n", el_c, pad, i + 1, df_c, mi_c, old_pwd[i], df_c); if (i + 1 < dirhist_total_index && old_pwd[i + 1]) printf("%s%*d%s %s\n", el_c, pad, i + 2, df_c, old_pwd[i + 1]); } #ifndef _NO_ICONS /* Set the icon field to the corresponding icon for the file file_info[N].name */ static int get_name_icon(const filesn_t n) { if (!file_info[n].name) return 0; const size_t name_hash = hashme(file_info[n].name, 0); /* This division will be replaced by a constant integer at compile * time, so that it won't even be executed at runtime. */ int i = (int)(sizeof(icon_filenames) / sizeof(icon_filenames[0])); while (--i >= 0) { if (name_hash != name_icons_hashes[i]) continue; file_info[n].icon = icon_filenames[i].icon; file_info[n].icon_color = icon_filenames[i].color; return 1; } return 0; } /* Set the icon field to the corresponding icon for the directory * file_info[N].name. If not found, set the default icon. */ static void get_dir_icon(const filesn_t n) { if (file_info[n].user_access == 0) /* Icon already set by load_file_gral_info() */ return; /* Default values for directories */ file_info[n].icon = DEF_DIR_ICON; /* DIR_ICO_C is set from the color scheme file */ file_info[n].icon_color = *dir_ico_c ? dir_ico_c : DEF_DIR_ICON_COLOR; if (!file_info[n].name) return; const size_t dir_hash = hashme(file_info[n].name, 0); int i = (int)(sizeof(icon_dirnames) / sizeof(icon_dirnames[0])); while (--i >= 0) { if (dir_hash != dir_icons_hashes[i]) continue; file_info[n].icon = icon_dirnames[i].icon; file_info[n].icon_color = icon_dirnames[i].color; return; } } /* Set the icon field to the corresponding icon for EXT. If not found, * set the default icon. */ static void get_ext_icon(const char *restrict ext, const filesn_t n) { if (!file_info[n].icon) { file_info[n].icon = DEF_FILE_ICON; file_info[n].icon_color = DEF_FILE_ICON_COLOR; } if (!ext || !*(++ext)) return; const size_t ext_hash = hashme(ext, 0); int i = (int)(sizeof(icon_ext) / sizeof(icon_ext[0])); while (--i >= 0) { if (ext_hash != ext_icons_hashes[i]) continue; file_info[n].icon = icon_ext[i].icon; file_info[n].icon_color = icon_ext[i].color; return; } } #endif /* _NO_ICONS */ static void print_cdpath(void) { if (workspaces && workspaces[cur_ws].path && *workspaces[cur_ws].path) print_reload_msg(NULL, NULL, "cdpath: %s\n", workspaces[cur_ws].path); is_cdpath = 0; } /* Restore the original value of long-view (taken from LONG_VIEW_BK) * after switching mode for the pager (according to PagerView). */ static void restore_pager_view(void) { if (long_view_bk != UNSET) { conf.long_view = long_view_bk; long_view_bk = UNSET; } } /* If running the pager, set long-view according to the value of PagerView in * the config file. The original value of long-view will be restored after * list_dir() by restore_pager_view() according to the value of LONG_VIEW_BK. */ static void set_pager_view(const filesn_t columns_n) { if (conf.pager <= 0 || conf.pager_view == PAGER_AUTO) return; const filesn_t lines = (filesn_t)term_lines - 2; /* This is not perfect: COLUMNS_N may be modified after this function * by get_longest_per_col() in list_files_vertical(), modifying thus * whether the pager will be executed or not. */ const int pager_will_run = (files > ((conf.long_view == 1 || conf.pager_view == PAGER_LONG) ? lines : (columns_n * lines))); if (pager_will_run == 0) return; if (conf.pager == 1 || files >= (filesn_t)conf.pager) { long_view_bk = conf.long_view; conf.long_view = (conf.pager_view == PAGER_LONG); } } static void print_dir_cmds(void) { if (!history || dir_cmds.first_cmd_in_dir > (int)current_hist_n) return; const char *ptr = term_caps.unicode ? DIR_CMD_PTR_U : DIR_CMD_PTR; int i = dir_cmds.first_cmd_in_dir - (dir_cmds.first_cmd_in_dir > 0 ? 1 : 0); for (; history[i].cmd; i++) printf("%s%s%s %s\n", dn_c, ptr, df_c, history[i].cmd); } static int post_listing(DIR *dir, const int reset_pager, const int autocmd_ret) { restore_pager_view(); if (dir && closedir(dir) == -1) return FUNC_FAILURE; if (xargs.list_and_quit == 1) exit(exit_code); if (conf.pager_once == 0) { if (reset_pager == 1 && (conf.pager < 2 || files < (filesn_t)conf.pager)) conf.pager = pager_bk; } else { conf.pager_once = 0; conf.pager = 0; } const size_t s_files = (size_t)files; if (pager_quit == 0 && conf.max_files != UNSET && files > (filesn_t)conf.max_files) printf("... (%d/%zu)\n", conf.max_files, s_files); print_div_line(); if (conf.dirhist_map == 1) { /* Print current, previous, and next entries */ print_dirhist_map(); print_div_line(); } if (sel_n > 0 && conf.print_selfiles == 1) print_sel_files(term_lines); if (is_cdpath == 1) print_cdpath(); if (conf.disk_usage == 1) print_disk_usage(); if (sort_switch == 1) { print_reload_msg(NULL, NULL, _("Sorted by ")); print_sort_method(); } if (switch_cscheme == 1) print_reload_msg(NULL, NULL, _("Color scheme: %s%s%s\n"), BOLD, cur_cscheme, df_c); if (virtual_dir == 1) print_reload_msg(NULL, NULL, _("Virtual directory\n")); if (stats.excluded > 0) print_reload_msg(NULL, NULL, _("Showing %zu/%zu files\n"), s_files, s_files + stats.excluded); if (filter.str && *filter.str) print_reload_msg(NULL, NULL, _("Active filter: %s%s%s%s\n"), BOLD, filter.rev == 1 ? "!" : "", filter.str, df_c); if (autocmd_ret == 1 && conf.autocmd_msg != AUTOCMD_MSG_NONE && conf.autocmd_msg != AUTOCMD_MSG_PROMPT) print_autocmd_msg(); if (dir_changed == 1) { dir_cmds.first_cmd_in_dir = UNSET; dir_changed = 0; } if (conf.print_dir_cmds == 1 && dir_cmds.first_cmd_in_dir != UNSET) print_dir_cmds(); return FUNC_SUCCESS; } /* A basic pager for directories containing large number of files. * What's missing? It only goes downwards. To go backwards, use the * terminal scrollback function */ static int run_pager(const int columns_n, int *reset_pager, filesn_t *i, size_t *counter) { fputs(PAGER_LABEL, stdout); switch (xgetchar()) { /* Advance one line at a time */ case 66: /* fallthrough */ /* Down arrow */ case 10: /* fallthrough */ /* Enter (LF) */ case 13: /* fallthrough */ /* Enter (CR) */ case ' ': break; /* Advance one page at a time */ case 126: /* Page Down */ *counter = 0; break; /* h: Print pager help */ case '?': /* fallthrough */ case 'h': { CLEAR; fputs(_(PAGER_HELP), stdout); int l = (int)term_lines - 6; MOVE_CURSOR_DOWN(l); fputs(PAGER_LABEL, stdout); xgetchar(); CLEAR; pager_help = conf.long_view == 0; if (columns_n == -1) { /* Long view */ *i = 0; } else { /* Normal view */ if (conf.listing_mode == HORLIST) *i = 0; else return (-2); } *counter = 0; if (*i < 0) *i = 0; } break; /* Stop paging (and set a flag to reenable the pager later) */ case 'c': /* fallthrough */ case 'p': /* fallthrough */ case 'Q': pager_bk = conf.pager; conf.pager = 0; *reset_pager = 1; break; case 'q': pager_bk = conf.pager; conf.pager = 0; *reset_pager = 1; putchar('\r'); ERASE_TO_RIGHT; if (conf.long_view == 0 && conf.columned == 1 && conf.max_name_len != UNSET) MOVE_CURSOR_UP(1); return (-3); /* If another key is pressed, go back one position. * Otherwise, some filenames won't be listed.*/ default: putchar('\r'); ERASE_TO_RIGHT; return (-1); } putchar('\r'); ERASE_TO_RIGHT; return 0; } static void set_events_checker(void) { if (xargs.list_and_quit == 1) return; #if defined(LINUX_INOTIFY) reset_inotify(); #elif defined(BSD_KQUEUE) if (event_fd >= 0) { close(event_fd); event_fd = -1; watch = 0; } # if defined(O_EVTONLY) event_fd = open(workspaces[cur_ws].path, O_EVTONLY); # else event_fd = open(workspaces[cur_ws].path, O_RDONLY); # endif /* O_EVTONLY */ if (event_fd >= 0) { /* Prepare for events */ EV_SET(&events_to_monitor[0], (uintptr_t)event_fd, EVFILT_VNODE, EV_ADD | EV_CLEAR, KQUEUE_FFLAGS, 0, workspaces[cur_ws].path); watch = 1; /* Register events */ kevent(kq, events_to_monitor, NUM_EVENT_SLOTS, NULL, 0, NULL); } #elif defined(GENERIC_FS_MONITOR) struct stat a; if (stat(workspaces[cur_ws].path, &a) != -1) curdir_mtime = a.st_mtime; else curdir_mtime = 0; #endif /* LINUX_INOTIFY */ } static int has_file_type_char(const filesn_t i) { switch (file_info[i].type) { case DT_REG: return (file_info[i].exec == 1); case DT_BLK: /* fallthrough */ case DT_CHR: /* fallthrough */ #ifdef SOLARIS_DOORS case DT_DOOR: /* fallthrough */ case DT_PORT: /* fallthrough */ #endif /* SOLARIS_DOORS */ case DT_LNK: /* fallthrough */ case DT_SOCK: /* fallthrough */ case DT_FIFO: /* fallthrough */ case DT_UNKNOWN: return 1; default: return 0; } } static void get_longest_filename(const filesn_t n, const size_t eln_len) { const int conf_no_eln = conf.no_eln; const int checks_classify = checks.classify; const int conf_files_counter = conf.files_counter; const int conf_colorize = conf.colorize; const int conf_listing_mode = conf.listing_mode; const int conf_max_files = conf.max_files; const filesn_t c_max_files = (filesn_t)conf_max_files; filesn_t i = (conf_max_files != UNSET && c_max_files < n) ? c_max_files : n; filesn_t longest_index = -1; const size_t max = checks.min_name_trunc == 1 ? (size_t)conf.min_name_trunc : (size_t)conf.max_name_len; while (--i >= 0) { file_info[i].eln_n = conf_no_eln == 1 ? -1 : DIGINUM(i + 1); size_t file_len = file_info[i].len; if (file_len == 0) { /* Invalid chars found. Reconstruct and recalculate length. */ char *wname = replace_invalid_chars(file_info[i].name); file_len = wname ? wc_xstrlen(wname) : 0; free(wname); } if (file_len > max) file_len = max; size_t total_len = eln_len + 1 + file_len; if (checks_classify == 1) { if (file_info[i].filesn > 0 && conf_files_counter == 1) total_len += DIGINUM(file_info[i].filesn); if (file_info[i].dir == 1 || (conf_colorize == 0 && has_file_type_char(i))) total_len++; } if (total_len > longest.name_len) { longest_index = i; if (conf_listing_mode == VERTLIST || conf_max_files == UNSET || i < c_max_files) longest.name_len = total_len; } } if (conf.icons == 1 && conf.long_view == 0 && conf.columned == 1) longest.name_len += (size_t)ICON_LEN; /* LONGEST.FC_LEN stores the number of digits taken by the file counter of * the longest filename, provided it is a directory. * We use this to truncate filenames up to MAX_NAME_LEN + LONGEST.FC_LEN, * so that we can make use of the space taken by the file counter. * Example: * longest_dirname/13 * very_long_file_na~ * instead of * longest_dirname/13 * very_long_file_~ * */ longest.fc_len = 0; if (file_info[longest_index].dir == 1 && file_info[longest_index].filesn > 0 && conf.max_name_len != UNSET && longest_index != -1 && conf.files_counter == 1) { longest.fc_len = DIGINUM(file_info[longest_index].filesn) + 1; const size_t t = eln_len + (size_t)conf.max_name_len + 1 + longest.fc_len; if (t > longest.name_len) longest.fc_len -= t - longest.name_len; if ((int)longest.fc_len < 0) longest.fc_len = 0; } } /* Set a few extra properties needed for long view mode */ static void set_long_attribs(const filesn_t n, const struct stat *a) { if (conf.light_mode == 1) { switch (prop_fields.time) { case PROP_TIME_ACCESS: file_info[n].ltime = a->st_atime; break; case PROP_TIME_CHANGE: file_info[n].ltime = a->st_ctime; break; case PROP_TIME_MOD: file_info[n].ltime = a->st_mtime; break; /* NOLINT */ case PROP_TIME_BIRTH: #ifdef ST_BTIME_LIGHT file_info[n].ltime = a->ST_BTIME.tv_sec; break; #else file_info[n].ltime = a->st_mtime; break; #endif /* ST_BTIME_LIGHT */ default: file_info[n].ltime = a->st_mtime; break; /* NOLINT */ } file_info[n].blocks = a->st_blocks; file_info[n].linkn = a->st_nlink; file_info[n].mode = a->st_mode; file_info[n].uid = a->st_uid; file_info[n].gid = a->st_gid; } if (conf.full_dir_size == 1 && file_info[n].dir == 1 && file_info[n].type == DT_DIR) { file_info[n].size = dir_size(file_info[n].name, 1, &file_info[n].du_status); } else { file_info[n].size = FILE_SIZE_PTR(a); } } /* Return a pointer to the indicator char color and update IND_CHR to the * corresponding indicator character for the file whose index is INDEX. */ static inline char * get_ind_char(const filesn_t index, char **ind_chr) { if (file_info[index].sel == 1) { *ind_chr = term_caps.unicode == 1 ? SELFILE_STR_U : SELFILE_STR; return li_cb; } if (file_info[index].symlink == 1 && checks.lnk_char == 1) { *ind_chr = term_caps.unicode == 1 ? LINK_STR_U : LINK_STR; return lc_c; } if (file_info[index].user_access == 0 && conf.icons == 0) { if ((file_info[index].type != DT_DIR && !*nf_c) || (file_info[index].type == DT_DIR && !*nd_c)) { *ind_chr = NO_PERM_STR; return xf_cb; } } *ind_chr = " "; return ""; } /* Return a struct maxes_t with the following information: the longest file * counter, user ID, group ID, file size, inode, and file links in the * current list of files. * This information is required to build the properties line for each entry * based on each field's length. */ static struct maxes_t compute_maxes(void) { struct maxes_t maxes = {0}; filesn_t i = xargs.max_files > 0 ? (filesn_t)xargs.max_files : (conf.max_files > 0 ? conf.max_files : files); const int conf_files_counter = conf.files_counter; const int prop_fields_size = prop_fields.size; const int prop_fields_ids = prop_fields.ids; const int prop_fields_inode = prop_fields.inode; const int prop_fields_links = prop_fields.links; const int prop_fields_blocks = prop_fields.blocks; if (i > files) i = files; while (--i >= 0) { int t = 0; if (file_info[i].dir == 1 && conf_files_counter == 1) { t = DIGINUM_BIG(file_info[i].filesn); if (t > maxes.files_counter) maxes.files_counter = t; } if (prop_fields_size == PROP_SIZE_BYTES) { t = DIGINUM_BIG(file_info[i].size); if (t > maxes.size) maxes.size = t; } else if (prop_fields_size == PROP_SIZE_HUMAN) { t = (int)file_info[i].human_size.len; if (t > maxes.size) maxes.size = t; } if (prop_fields_ids == PROP_ID_NUM) { const int u = DIGINUM(file_info[i].uid); const int g = DIGINUM(file_info[i].gid); if (g > maxes.id_group) maxes.id_group = g; if (u > maxes.id_user) maxes.id_user = u; } else if (prop_fields_ids == PROP_ID_NAME) { const int g = file_info[i].gid_i.name ? (int)file_info[i].gid_i.namlen : DIGINUM(file_info[i].gid); if (g > maxes.id_group) maxes.id_group = g; const int u = file_info[i].uid_i.name ? (int)file_info[i].uid_i.namlen : DIGINUM(file_info[i].uid); if (u > maxes.id_user) maxes.id_user = u; } if (prop_fields_inode == 1) { t = DIGINUM(file_info[i].inode); if (t > maxes.inode) maxes.inode = t; } if (prop_fields_links == 1) { t = DIGINUM((unsigned int)file_info[i].linkn); if (t > maxes.links) maxes.links = t; } if (prop_fields_blocks == 1) { t = DIGINUM_BIG(file_info[i].blocks); if (t > maxes.blocks) maxes.blocks = t; } } if (conf.full_dir_size != 1 || prop_fields_size == PROP_SIZE_HUMAN) return maxes; /* If at least one directory size length equals the maximum size lenght * in the current directory, and we have a du(1) error for this directory, * we need to make room for the du error char (!). */ i = files; while (--i >= 0) { if (file_info[i].du_status == 0) continue; const int t = prop_fields_size == PROP_SIZE_BYTES ? DIGINUM_BIG(file_info[i].size) : (int)file_info[i].human_size.len; if (t == maxes.size) { maxes.size++; break; } } return maxes; } static void print_long_mode(size_t *counter, int *reset_pager, const int eln_len) { struct maxes_t maxes = compute_maxes(); const int have_xattr = (stats.extended > 0 && prop_fields.xattr != 0); /* Available space (term cols) to print the filename. */ int space_left = (int)term_cols - (prop_fields.len + have_xattr + maxes.files_counter + maxes.size + maxes.links + maxes.inode + maxes.id_user + (prop_fields.no_group == 0 ? maxes.id_group : 0) + maxes.blocks + (conf.icons == 1 ? ICON_LEN : 0)); if (space_left < conf.min_name_trunc) space_left = conf.min_name_trunc; if (conf.min_name_trunc != UNSET && longest.name_len > (size_t)space_left) longest.name_len = (size_t)space_left; if (longest.name_len < (size_t)space_left) space_left = (int)longest.name_len; maxes.name = space_left + (conf.icons == 1 ? ICON_LEN : 0); pager_quit = pager_help = 0; /* Cache conf struct values for faster access. */ const filesn_t conf_max_files = conf.max_files; const filesn_t conf_pager = (filesn_t)conf.pager; const int conf_no_eln = conf.no_eln; filesn_t i; const filesn_t f = files; /* Cache global variable. */ const size_t s_term_lines = term_lines > 2 ? (size_t)(term_lines - 2) : 0; for (i = 0; i < f; i++) { if (conf_max_files != UNSET && i == conf_max_files) break; if (conf_pager == 1 || (*reset_pager == 0 && conf_pager > 1 && files >= conf_pager)) { if (*counter > s_term_lines) { const int ret = run_pager(-1, reset_pager, &i, counter); if (ret == -3) { pager_quit = 1; break; } if (ret == -1 || ret == -2) { --i; if (ret == -2) *counter = 0; continue; } } ++(*counter); } char *ind_chr = (char *)NULL; const char *ind_chr_color = get_ind_char(i, &ind_chr); if (conf_no_eln == 0) { printf("%s%*zd%s%s%s%s", el_c, eln_len, i + 1, df_c, ind_chr_color, ind_chr, df_c); } else { printf("%s%s%s", ind_chr_color, ind_chr, df_c); } /* Print the remaining part of the entry. */ print_entry_props(&file_info[i], &maxes, have_xattr); } if (pager_quit == 1) printf("... (%zd/%zd)\n", i, files); } /* Return the minimal number of columns we can use for the current list * of files. If possible, this number will be increased later by the * get_longest_per_col() function. */ static size_t get_columns(void) { /* LONGEST.NAME_LEN is size_t: it will never be less than zero. */ #ifdef TIGHT_COLUMNS size_t n = (size_t)term_cols / (longest.name_len + COLUMNS_GAP); #else size_t n = (size_t)term_cols / (longest.name_len + 1); #endif /* +1 for the space between filenames. */ /* If LONGEST.NAME_LEN is larger than the number of terminal columns, * N will zero. To avoid this: */ if (n < 1) n = 1; /* If we have only three files, we don't want four columns. */ if (n > (size_t)files) n = (size_t)files > 0 ? (size_t)files : 1; return n; } static size_t get_ext_info(const filesn_t i, int *trunc_type) { *trunc_type = TRUNC_EXT; size_t ext_len = 0; size_t bytes = 0; const char *ext = file_info[i].ext_name; if (file_info[i].utf8 == 0) { /* Extension names are usually short. Let's call strlen(2) only * when it is longer than 6 (including the initial dot). */ ext_len = !ext[1] ? 1 : !ext[2] ? 2 : !ext[3] ? 3 : !ext[4] ? 4 : !ext[5] ? 5 : !ext[6] ? 6 : strlen(ext); } else if (is_utf8_name(ext, &bytes, NULL) == 0) { ext_len = bytes; } else { ext_len = wc_xstrlen(ext); } if ((int)ext_len >= conf.max_name_len - 1 || (int)ext_len <= 0) { ext_len = 0; *trunc_type = TRUNC_NO_EXT; } return ext_len; } /* Construct the filename to be displayed. * The filename is truncated if longer than MAX_NAMELEN (if conf.max_name_len * is set). */ static char * construct_filename(const filesn_t i, struct wtrunc_t *wtrunc, const int max_namelen) { /* When quitting the help screen of the pager, the list of files is * reprinted from the first entry. Now, when printing the list for the * first time the LEN field of the file_info struct is set to the displayed * length, which, if the name is truncated, is the same as MAX_NAME_LEN * (causing thus subsequent prints of the list to never truncate long file * names, because the value is already <= MAX_NAME_LEN). * Because of this, we need to recalculate the length of the current entry * whenever we're coming from the pager help screen, in order to know * whether we should truncate the name or not. */ size_t namelen = pager_help == 1 ? (file_info[i].utf8 == 1 ? wc_xstrlen(file_info[i].name) : file_info[i].bytes) : file_info[i].len; char *name = file_info[i].name; /* file_info[i].len is zero whenever an invalid character was found in * the filename. Let's recalculate the name length. */ if (namelen == 0) { wtrunc->wname = replace_invalid_chars(file_info[i].name); namelen = file_info[i].len = wc_xstrlen(wtrunc->wname); name = wtrunc->wname; } if ((int)namelen <= max_namelen || conf.max_name_len == UNSET || conf.long_view != 0 || files <= 1) return name; /* Let's truncate the filename (at MAX_NAMELEN, in this example, 11). * A. If no file extension, just truncate at 11: "long_filen~" * B. If we have an extension, keep it: "long_f~.ext" * * This is the place to implement an alternative truncation procedure, say, * to truncate names at the middle, like MC does: "long_~ename" * or, if we have an extension: "long_~e.ext" * * We only need a function similar to get_ext_info(), say, get_suffix_info() * wtrunc->trunc should be set to TRUNC_EXT * ext_len to the length of the suffix (either "ename" or "e.ext", i.e. 5) * file_info[i].ext_name should be a pointer to the beggining of SUFFIX * in file_info[i].name (this might impact on some later operation!) */ size_t ext_len = 0; if (!file_info[i].ext_name) wtrunc->type = TRUNC_NO_EXT; else ext_len = get_ext_info(i, &wtrunc->type); const int trunc_len = max_namelen - 1 - (int)ext_len; if (file_info[i].utf8 == 1) { if (wtrunc->wname) xstrsncpy(name_buf, wtrunc->wname, sizeof(name_buf)); else /* memcpy is faster: use it whenever possible. */ memcpy(name_buf, file_info[i].name, file_info[i].bytes + 1); wtrunc->diff = u8truncstr(name_buf, (size_t)trunc_len); } else { /* If not UTF-8, let's avoid u8truncstr(). It's a bit faster this way. */ const char c = name[trunc_len]; name[trunc_len] = '\0'; mbstowcs((wchar_t *)name_buf, name, NAME_BUF_SIZE); name[trunc_len] = c; } file_info[i].len = (size_t)max_namelen; /* At this point we have truncated name. "~" and ".ext" will be appended * later by one of the print_entry functions. */ return name_buf; } static void print_entry_color(int *ind_char, const filesn_t i, const int pad, const int max_namelen) { *ind_char = 0; const char *end_color = (file_info[i].dir == 1 && conf.classify == 1) ? fc_c : df_c; struct wtrunc_t wtrunc = (struct wtrunc_t){0}; const char *n = construct_filename(i, &wtrunc, max_namelen); const char *trunc_diff = wtrunc.diff > 0 ? gen_diff_str(wtrunc.diff) : ""; char *ind_chr = (char *)NULL; const char *ind_chr_color = get_ind_char(i, &ind_chr); switch (checks.list_format) { #ifndef _NO_ICONS case ICONS_NO_ELN: if (wtrunc.type > 0) { xprintf("%s%s%s%s%s%s%s%ls%s\x1b[0m%s%c\x1b[0m%s%s%s", ind_chr_color, ind_chr, df_c, file_info[i].icon_color, file_info[i].icon, checks.icons_gap, file_info[i].color, (wchar_t *)n, trunc_diff, tt_c, TRUNC_FILE_CHR, wtrunc.type == TRUNC_EXT ? file_info[i].color : "", wtrunc.type == TRUNC_EXT ? file_info[i].ext_name : "", end_color); } else { xprintf("%s%s%s%s%s%s%s%s%s", ind_chr_color, ind_chr, df_c, file_info[i].icon_color, file_info[i].icon, checks.icons_gap, file_info[i].color, n, end_color); } break; case ICONS_ELN: if (wtrunc.type > 0) { xprintf("%s%*jd%s%s%s%s%s%s%s%s%ls%s\x1b[0m%s%c\x1b[0m%s%s%s", el_c, pad, (intmax_t)i + 1, df_c, ind_chr_color, ind_chr, df_c, file_info[i].icon_color, file_info[i].icon, checks.icons_gap, file_info[i].color, (wchar_t *)n, trunc_diff, tt_c, TRUNC_FILE_CHR, wtrunc.type == TRUNC_EXT ? file_info[i].color : "", wtrunc.type == TRUNC_EXT ? file_info[i].ext_name : "", end_color); } else { xprintf("%s%*jd%s%s%s%s%s%s%s%s%s%s", el_c, pad, (intmax_t)i + 1, df_c, ind_chr_color, ind_chr, df_c, file_info[i].icon_color, file_info[i].icon, checks.icons_gap, file_info[i].color, n, end_color); } break; #endif /* !_NO_ICONS */ case NO_ICONS_NO_ELN: if (wtrunc.type > 0) { xprintf("%s%s%s%s%ls%s\x1b[0m%s%c\x1b[0m%s%s%s", ind_chr_color, ind_chr, df_c, file_info[i].color, (wchar_t *)n, trunc_diff, tt_c, TRUNC_FILE_CHR, wtrunc.type == TRUNC_EXT ? file_info[i].color : "", wtrunc.type == TRUNC_EXT ? file_info[i].ext_name : "", end_color); } else { xprintf("%s%s%s%s%s%s", ind_chr_color, ind_chr, df_c, file_info[i].color, n, end_color); } break; case NO_ICONS_ELN: if (wtrunc.type > 0) { xprintf("%s%*jd%s%s%s%s%s%ls%s\x1b[0m%s%c\x1b[0m%s%s%s", el_c, pad, (intmax_t)i + 1, df_c, ind_chr_color, ind_chr, df_c, file_info[i].color, (wchar_t *)n, trunc_diff, tt_c, TRUNC_FILE_CHR, wtrunc.type == TRUNC_EXT ? file_info[i].color : "", wtrunc.type == TRUNC_EXT ? file_info[i].ext_name : "", end_color); } else { xprintf("%s%*jd%s%s%s%s%s%s%s", el_c, pad, (intmax_t)i + 1, df_c, ind_chr_color, ind_chr, df_c, file_info[i].color, n, end_color); } break; default: break; } if (end_color == fc_c) { /* We have a directory and classification is on: append directory * indicator and file counter. */ putchar(DIR_CHR); if (file_info[i].filesn > 0 && conf.files_counter == 1) fputs(xitoa(file_info[i].filesn), stdout); fputs(df_c, stdout); } if (wtrunc.wname) /* This is NULL most of the time. */ free(wtrunc.wname); } static void print_entry_nocolor(int *ind_char, const filesn_t i, const int pad, const int max_namelen) { struct wtrunc_t wtrunc = (struct wtrunc_t){0}; const char *n = construct_filename(i, &wtrunc, max_namelen); const char *trunc_diff = wtrunc.diff > 0 ? gen_diff_str(wtrunc.diff) : ""; char *ind_chr = (char *)NULL; (void)get_ind_char(i, &ind_chr); switch (checks.list_format) { #ifndef _NO_ICONS case ICONS_NO_ELN: if (wtrunc.type > 0) { xprintf("%s%s%s%ls%s%c%s", ind_chr, file_info[i].icon, checks.icons_gap, (wchar_t *)n, trunc_diff, TRUNC_FILE_CHR, wtrunc.type == TRUNC_EXT ? file_info[i].ext_name : ""); } else { xprintf("%s%s%s%s", ind_chr, file_info[i].icon, checks.icons_gap, n); } break; case ICONS_ELN: if (wtrunc.type > 0) { xprintf("%s%*jd%s%s%s%s%ls%s%c%s", el_c, pad, (intmax_t)i + 1, df_c, ind_chr, file_info[i].icon, checks.icons_gap, (wchar_t *)n, trunc_diff, TRUNC_FILE_CHR, wtrunc.type == TRUNC_EXT ? file_info[i].ext_name : ""); } else { xprintf("%s%*jd%s%s%s%s%s", el_c, pad, (intmax_t)i + 1, df_c, ind_chr, file_info[i].icon, checks.icons_gap, n); } break; #endif /* !_NO_ICONS */ case NO_ICONS_NO_ELN: if (wtrunc.type > 0) { xprintf("%s%ls%s%c%s", ind_chr, (wchar_t *)n, trunc_diff, TRUNC_FILE_CHR, wtrunc.type == TRUNC_EXT ? file_info[i].ext_name : ""); } else { xprintf("%s%s", ind_chr, n); } break; case NO_ICONS_ELN: if (wtrunc.type > 0) { xprintf("%s%*jd%s%s%ls%s%c%s", el_c, pad, (intmax_t)i + 1, df_c, ind_chr, (wchar_t *)n, trunc_diff, TRUNC_FILE_CHR, wtrunc.type == TRUNC_EXT ? file_info[i].ext_name : ""); } else { xprintf("%s%*jd%s%s%s", el_c, pad, (intmax_t)i + 1, df_c, ind_chr, n); } break; default: break; } if (conf.classify == 1) { /* Append file type indicator */ switch (file_info[i].type) { case DT_DIR: *ind_char = 0; putchar(DIR_CHR); if (file_info[i].filesn > 0 && conf.files_counter == 1) fputs(xitoa(file_info[i].filesn), stdout); break; case DT_LNK: if (file_info[i].color == or_c) { putchar(BRK_LNK_CHR); } else if (file_info[i].dir == 1) { *ind_char = 0; putchar(DIR_CHR); if (file_info[i].filesn > 0 && conf.files_counter == 1) fputs(xitoa(file_info[i].filesn), stdout); } else { putchar(LINK_CHR); } break; case DT_REG: if (file_info[i].exec == 1) putchar(EXEC_CHR); else *ind_char = 0; break; case DT_BLK: putchar(BLK_CHR); break; case DT_CHR: putchar(CHR_CHR); break; #ifdef SOLARIS_DOORS case DT_DOOR: putchar(DOOR_CHR); break; // case DT_PORT: break; #endif /* SOLARIS_DOORS */ case DT_FIFO: putchar(FIFO_CHR); break; case DT_SOCK: putchar(SOCK_CHR); break; #ifdef S_IFWHT case DT_WHT: putchar(WHT_CHR); break; #endif /* S_IFWHT */ case DT_UNKNOWN: putchar(UNK_CHR); break; default: *ind_char = 0; } } if (wtrunc.wname) /* This is NULL most of the time. */ free(wtrunc.wname); } static void print_entry_color_light(int *ind_char, const filesn_t i, const int pad, const int max_namelen) { *ind_char = 0; const char *end_color = file_info[i].dir == 1 ? fc_c : df_c; struct wtrunc_t wtrunc = (struct wtrunc_t){0}; const char *n = construct_filename(i, &wtrunc, max_namelen); const char *trunc_diff = wtrunc.diff > 0 ? gen_diff_str(wtrunc.diff) : ""; switch (checks.list_format) { #ifndef _NO_ICONS case ICONS_NO_ELN: if (wtrunc.type > 0) { xprintf("%s%s%s%s%ls%s\x1b[0m%s%c\x1b[0m%s%s%s", file_info[i].icon_color, file_info[i].icon, checks.icons_gap, file_info[i].color, (wchar_t *)n, trunc_diff, tt_c, TRUNC_FILE_CHR, wtrunc.type == TRUNC_EXT ? file_info[i].color : "", wtrunc.type == TRUNC_EXT ? file_info[i].ext_name : "", end_color); } else { xprintf("%s%s%s%s%s%s", file_info[i].icon_color, file_info[i].icon, checks.icons_gap, file_info[i].color, n, end_color); } break; case ICONS_ELN: if (wtrunc.type > 0) { xprintf("%s%*jd%s %s%s%s%s%ls%s\x1b[0m%s%c\x1b[0m%s%s%s", el_c, pad, (intmax_t)i + 1, df_c, file_info[i].icon_color, file_info[i].icon, checks.icons_gap, file_info[i].color, (wchar_t *)n, trunc_diff, tt_c, TRUNC_FILE_CHR, wtrunc.type == TRUNC_EXT ? file_info[i].color : "", wtrunc.type == TRUNC_EXT ? file_info[i].ext_name : "", end_color); } else { xprintf("%s%*jd%s %s%s%s%s%s%s", el_c, pad, (intmax_t)i + 1, df_c, file_info[i].icon_color, file_info[i].icon, checks.icons_gap, file_info[i].color, n, end_color); } break; #endif /* !_NO_ICONS */ case NO_ICONS_NO_ELN: if (wtrunc.type > 0) { xprintf("%s%ls%s\x1b[0m%s%c\x1b[0m%s%s%s", file_info[i].color, (wchar_t *)n, trunc_diff, tt_c, TRUNC_FILE_CHR, wtrunc.type == TRUNC_EXT ? file_info[i].color : "", wtrunc.type == TRUNC_EXT ? file_info[i].ext_name : "", end_color); } else { xprintf("%s%s%s", file_info[i].color, n, end_color); } break; case NO_ICONS_ELN: if (wtrunc.type > 0) { xprintf("%s%*jd%s %s%ls%s\x1b[0m%s%c\x1b[0m%s%s%s", el_c, pad, (intmax_t)i + 1, df_c, file_info[i].color, (wchar_t *)n, trunc_diff, tt_c, TRUNC_FILE_CHR, wtrunc.type == TRUNC_EXT ? file_info[i].color : "", wtrunc.type == TRUNC_EXT ? file_info[i].ext_name : "", end_color); } else { xprintf("%s%*jd%s %s%s%s", el_c, pad, (intmax_t)i + 1, df_c, file_info[i].color, n, end_color); } break; default: break; } if (file_info[i].dir == 1 && conf.classify == 1) { putchar(DIR_CHR); if (file_info[i].filesn > 0 && conf.files_counter == 1) fputs(xitoa(file_info[i].filesn), stdout); } if (end_color == fc_c) fputs(df_c, stdout); if (wtrunc.wname) /* This is NULL most of the time. */ free(wtrunc.wname); } static void print_entry_nocolor_light(int *ind_char, const filesn_t i, const int pad, const int max_namelen) { struct wtrunc_t wtrunc = (struct wtrunc_t){0}; const char *n = construct_filename(i, &wtrunc, max_namelen); const char *trunc_diff = wtrunc.diff > 0 ? gen_diff_str(wtrunc.diff) : ""; switch (checks.list_format) { #ifndef _NO_ICONS case ICONS_NO_ELN: if (wtrunc.type > 0) { xprintf("%s%s%ls%s%c%s", file_info[i].icon, checks.icons_gap, (wchar_t *)n, trunc_diff, TRUNC_FILE_CHR, wtrunc.type == TRUNC_EXT ? file_info[i].ext_name : ""); } else { xprintf("%s%s%s", file_info[i].icon, checks.icons_gap, n); } break; case ICONS_ELN: if (wtrunc.type > 0) { xprintf("%s%*jd%s %s%s%ls%s%c%s", el_c, pad, (intmax_t)i + 1, df_c, file_info[i].icon, checks.icons_gap, (wchar_t *)n, trunc_diff, TRUNC_FILE_CHR, wtrunc.type == TRUNC_EXT ? file_info[i].ext_name : ""); } else { xprintf("%s%*jd%s %s%s%s", el_c, pad, (intmax_t)i + 1, df_c, file_info[i].icon, checks.icons_gap, n); } break; #endif /* !_NO_ICONS */ case NO_ICONS_NO_ELN: if (wtrunc.type > 0) { xprintf("%ls%s%c%s", (wchar_t *)n, trunc_diff, TRUNC_FILE_CHR, wtrunc.type == TRUNC_EXT ? file_info[i].ext_name : ""); } else { fputs(file_info[i].name, stdout); } break; case NO_ICONS_ELN: if (wtrunc.type > 0) { xprintf("%s%*jd%s %ls%s%c%s", el_c, pad, (intmax_t)i + 1, df_c, (wchar_t *)n, trunc_diff, TRUNC_FILE_CHR, wtrunc.type == TRUNC_EXT ? file_info[i].ext_name : ""); } else { xprintf("%s%*jd%s %s", el_c, pad, (intmax_t)i + 1, df_c, n); } break; default: break; } if (conf.classify == 1) { switch (file_info[i].type) { case DT_DIR: *ind_char = 0; putchar(DIR_CHR); if (file_info[i].filesn > 0 && conf.files_counter == 1) fputs(xitoa(file_info[i].filesn), stdout); break; case DT_BLK: putchar(BLK_CHR); break; case DT_CHR: putchar(CHR_CHR); break; #ifdef SOLARIS_DOORS case DT_DOOR: putchar(DOOR_CHR); break; // case DT_DOOR: break; #endif /* SOLARIS_DOORS */ case DT_FIFO: putchar(FIFO_CHR); break; case DT_LNK: putchar(LINK_CHR); break; case DT_SOCK: putchar(SOCK_CHR); break; #ifdef S_IFWHT case DT_WHT: putchar(WHT_CHR); break; #endif /* S_IFWHT */ case DT_UNKNOWN: putchar(UNKNOWN_CHR); break; default: *ind_char = 0; break; } } if (wtrunc.wname) /* This is NULL most of the time. */ free(wtrunc.wname); } #ifdef TIGHT_COLUMNS static size_t calc_item_length(const int eln_len, const int icon_len, const filesn_t i) { size_t file_len = file_info[i].len; if (file_len == 0) { /* Invalid chars found. Reconstruct and recalculate length. */ char *wname = replace_invalid_chars(file_info[i].name); file_len = wname ? wc_xstrlen(wname) : 0; free(wname); } const size_t max_namelen = (size_t)conf.max_name_len + (file_info[i].dir != 1 ? longest.fc_len : 0); const size_t name_len = (max_namelen > 0 && file_len > max_namelen) ? max_namelen : file_len; int item_len = eln_len + 1 + (int)name_len + icon_len; if (conf.classify != 1) return (size_t)item_len; if (file_info[i].dir == 1) { item_len++; if (file_info[i].filesn > 0 && conf.files_counter == 1 && file_info[i].user_access == 1) item_len += DIGINUM((int)file_info[i].filesn); } else if (conf.colorize == 0 && has_file_type_char(i) == 1) { item_len++; } return (size_t)item_len; } static size_t * get_longest_per_col(size_t *columns_n, filesn_t *rows, const filesn_t files_n) { if (conf.columned == 0) { *columns_n = 1; *rows = files; size_t *longest_per_col = xnmalloc(2, sizeof(size_t)); longest_per_col[0] = term_cols; return longest_per_col; } size_t used_cols = 0; size_t longest_index = 0; if (*columns_n == 0) *columns_n = 1; if (*rows <= 0) *rows = 1; /* Make enough room to hold columns information. We'll never get more * columns for the current file list than the number of terminal columns. */ size_t *longest_per_col = xnmalloc((size_t)term_cols + 1, sizeof(size_t)); /* Hold info about the previous columns state */ size_t *prev_longest_per_col = (size_t *)NULL; filesn_t prev_rows = *rows; const int longest_eln = conf.no_eln != 1 ? DIGINUM(files_n + 1) : 1; const int icon_len = (conf.icons == 1 ? ICON_LEN : 0); #define LONGEST_PLUS_GAP (longest_per_col[longest_index] + COLUMNS_GAP) while (1) { /* Calculate the number of rows that will be in each column except * possibly for a short column on the right. */ *rows = files_n / (filesn_t)*columns_n + (files_n % (filesn_t)*columns_n != 0); /* Get longest filename per column */ filesn_t i; filesn_t counter = 1; size_t longest_name_len = 0; /* Cache the value referenced by the pointer once here instead of * dereferencing it hundreds of times in the below for-loop. */ const filesn_t cached_rows = *rows; for (i = 0; i < files_n; i++) { size_t len = 0; if (file_info[i].total_entry_len > 0) { len = file_info[i].total_entry_len; } else { len = file_info[i].total_entry_len = calc_item_length(longest_eln, icon_len, i); } if (len > longest_name_len) longest_name_len = len; if (counter == cached_rows) { counter = 1; longest_per_col[longest_index] = longest_name_len; used_cols += LONGEST_PLUS_GAP; longest_index++; longest_name_len = 0; } else { counter++; } } /* Count last column as well: If the number of files in the last * column is less than the number of rows (in which case * LONGEST_NAME_LEN is bigger than zero), the longest name in this * column isn't taken into account: let's do it here. */ if (longest_name_len > 0) { longest_per_col[longest_index] = longest_name_len; used_cols += LONGEST_PLUS_GAP; } else { if (longest_index > 0) longest_index--; else break; } const int rest = (int)term_cols - (int)used_cols; if ((*rows == 1 && (filesn_t)*columns_n + 1 >= files_n) || rest < (int)LONGEST_PLUS_GAP) { if (rest < 0 && *columns_n > 1) { if (!prev_longest_per_col) return longest_per_col; (*columns_n)--; *rows = prev_rows; free(longest_per_col); return prev_longest_per_col; } else { break; } } /* Keep a copy of the current state, in case the next iteration * returns too many columns, in which case the current state is * what we want. */ prev_rows = *rows; free(prev_longest_per_col); prev_longest_per_col = xnmalloc(*columns_n + 1, sizeof(size_t)); memcpy(prev_longest_per_col, longest_per_col, (*columns_n + 1) * sizeof(size_t)); /* There is space left for one more column: increase columns_n. */ (*columns_n)++; longest_index = 0; used_cols = 0; } #undef LONGEST_PLUS_GAP free(prev_longest_per_col); return longest_per_col; } static void pad_filename_new(const filesn_t i, const int termcap_move_right, const size_t longest_in_col) { const int diff = ((int)longest_in_col + COLUMNS_GAP) - ((int)file_info[i].total_entry_len + (conf.no_eln == 1)); if (termcap_move_right == 1) { MOVE_CURSOR_RIGHT(diff); } else { int j = diff; while (--j >= 0) putchar(' '); } } #endif /* TIGHT_COLUMNS */ /* Right pad the current filename (adding spaces) to equate the longest * filename length. */ static void pad_filename(const int ind_char, const filesn_t i, const int eln_len, const int termcap_move_right) { int cur_len = eln_len + 1 + (conf.icons == 1 ? ICON_LEN : 0) + (int)file_info[i].len + (ind_char ? 1 : 0); if (file_info[i].dir == 1 && conf.classify == 1) { cur_len++; if (file_info[i].filesn > 0 && conf.files_counter == 1 && file_info[i].user_access == 1) cur_len += DIGINUM((int)file_info[i].filesn); } const int diff = (int)longest.name_len - cur_len; if (termcap_move_right == 1) { MOVE_CURSOR_RIGHT(diff + 1); } else { int j = diff + 1; while (--j >= 0) putchar(' '); } } /* List files horizontally: * 1 AAA 2 AAB 3 AAC * 4 AAD 5 AAE 6 AAF */ static void list_files_horizontal(size_t *counter, int *reset_pager, const int eln_len, size_t columns_n) { const filesn_t nn = (conf.max_files != UNSET && (filesn_t)conf.max_files < files) ? (filesn_t)conf.max_files : files; /* size_t *longest_per_col = get_longest_per_col(&columns_n, nn); size_t cur_col = 0; */ void (*print_entry_function)(int *, const filesn_t, const int, const int); if (conf.colorize == 1) print_entry_function = conf.light_mode == 1 ? print_entry_color_light : print_entry_color; else print_entry_function = conf.light_mode == 1 ? print_entry_nocolor_light : print_entry_nocolor; const int termcap_move_right = (xargs.list_and_quit == 1 || term_caps.suggestions == 0) ? 0 : 1; const int int_longest_fc_len = (int)longest.fc_len; size_t cur_cols = 0; filesn_t i; int last_column = 0; int backup_last_column = last_column; pager_quit = pager_help = 0; for (i = 0; i < nn; i++) { /* If current entry is in the last column, we need to print a * new line char. */ size_t bcur_cols = cur_cols; if (++cur_cols != columns_n) { last_column = 0; } else { cur_cols = 0; last_column = 1; } int ind_char = (conf.classify != 0); /* ########################## * # MAS: A SIMPLE PAGER # * ########################## */ if (conf.pager == 1 || (*reset_pager == 0 && conf.pager > 1 && files >= (filesn_t)conf.pager)) { /* Run the pager only once all columns and rows fitting in * the screen are filled with the corresponding filenames */ int ret = 0; filesn_t backup_i = i; if (backup_last_column && *counter > columns_n * ((size_t)term_lines - 2)) ret = run_pager((int)columns_n, reset_pager, &i, counter); if (ret == -3) { pager_quit = 1; goto END; } if (ret == -1) { i = backup_i ? backup_i - 1 : backup_i; cur_cols = bcur_cols; last_column = backup_last_column; continue; } (*counter)++; } backup_last_column = last_column; /* ################################# * # PRINT THE CURRENT ENTRY # * ################################# */ const int fc = file_info[i].dir != 1 ? int_longest_fc_len : 0; /* Displayed filename will be truncated to MAX_NAME_LEN. */ const int max_namelen = conf.max_name_len + fc; file_info[i].eln_n = conf.no_eln == 1 ? -1 : DIGINUM(i + 1); print_entry_function(&ind_char, i, eln_len, max_namelen); if (last_column == 0) { /* pad_filename_new(i, termcap_move_right, longest_per_col[cur_col]); cur_col++; */ pad_filename(ind_char, i, eln_len, termcap_move_right); } else { putchar('\n'); // cur_col = 0; } } END: // free(longest_per_col); if (last_column == 0) putchar('\n'); if (pager_quit == 1) printf("... (%zd/%zd)\n", i, files); } /* List files vertically, like ls(1) would * 1 AAA 3 AAC 5 AAE * 2 AAB 4 AAD 6 AAF */ static void list_files_vertical(size_t *counter, int *reset_pager, const int eln_len, size_t num_columns) { /* Total number of files to be listed. */ const filesn_t total_files = (conf.max_files != UNSET && (filesn_t)conf.max_files < files) ? (filesn_t)conf.max_files : files; #ifdef TIGHT_COLUMNS filesn_t num_rows = 0; size_t *longest_per_col = get_longest_per_col(&num_columns, &num_rows, total_files); size_t cur_col = 0; #else /* How many lines (rows) do we need to print TOTAL_FILES files? */ /* Division/modulo is slow, true. But the compiler will make a much * better job than us at optimizing this code. */ /* NUM_COLUMNS is guarranteed to be >0 by get_columns() */ filesn_t num_rows = total_files / (filesn_t)num_columns; if (total_files % (filesn_t)num_columns > 0) ++num_rows; #endif int last_column = 0; /* The previous value of LAST_COLUMN. We need this value to run the pager. */ int backup_last_column = last_column; void (*print_entry_function)(int *, const filesn_t, const int, const int); if (conf.colorize == 1) print_entry_function = conf.light_mode == 1 ? print_entry_color_light : print_entry_color; else print_entry_function = conf.light_mode == 1 ? print_entry_nocolor_light : print_entry_nocolor; const int termcap_move_right = (xargs.list_and_quit == 1 || term_caps.suggestions == 0) ? 0 : 1; const int int_longest_fc_len = (int)longest.fc_len; size_t column_count = num_columns; // Current column number filesn_t file_index = 0; // Index of the file to be actually printed filesn_t row_index = 0; // Current line number filesn_t i = 0; // Index of the current entry being analyzed const int conf_max_name_len = conf.max_name_len; const int conf_pager = conf.pager; const int conf_no_eln = conf.no_eln; const int conf_classify = conf.classify; pager_quit = pager_help = 0; for ( ; ; i++) { /* Copy current values to restore them if necessary. */ filesn_t backup_row_index = row_index; filesn_t backup_file_index = file_index; size_t backup_column_count = column_count; if (column_count != num_columns) { file_index += num_rows; column_count++; } else { file_index = row_index; row_index++; column_count = 1; } if (row_index > num_rows) break; /* If current entry is in the last column, print a new line char */ last_column = (column_count == num_columns); int ind_char = (conf_classify != 0); if (file_index >= total_files || !file_info[file_index].name) { if (last_column == 1) { /* Last column is empty. E.g.: * 1 file 3 file3 5 file5 * 2 file2 4 file4 HERE * ... */ putchar('\n'); #ifdef TIGHT_COLUMNS cur_col = 0; #endif } continue; } /* ########################## * # MAS: A SIMPLE PAGER # * ########################## */ if (conf_pager == 1 || (*reset_pager == 0 && conf_pager > 1 && files >= (filesn_t)conf_pager)) { int ret = 0; filesn_t backup_i = i; /* Run the pager only once all columns and rows fitting in * the screen are filled with the corresponding filenames. */ if (backup_last_column && *counter > num_columns * ((size_t)term_lines - 2)) ret = run_pager((int)num_columns, reset_pager, &file_index, counter); if (ret == -3) { pager_quit = 1; goto END; } if (ret == -1) { /* Restore previous values */ i = backup_i ? backup_i - 1: backup_i; file_index = backup_file_index; row_index = backup_row_index; column_count = backup_column_count; continue; } else { if (ret == -2) { i = file_index = row_index = 0; last_column = backup_last_column = 0; *counter = 0; column_count = num_columns; continue; } } (*counter)++; } backup_last_column = last_column; /* ################################# * # PRINT THE CURRENT ENTRY # * ################################# */ const int fc = file_info[file_index].dir != 1 ? int_longest_fc_len : 0; /* Displayed filename will be truncated to MAX_NAMELEN. */ const int max_namelen = conf_max_name_len + fc; file_info[file_index].eln_n = conf_no_eln == 1 ? -1 : DIGINUM(file_index + 1); print_entry_function(&ind_char, file_index, eln_len, max_namelen); if (last_column == 0) { #ifdef TIGHT_COLUMNS pad_filename_new(file_index, termcap_move_right, longest_per_col[cur_col]); cur_col++; #else pad_filename(ind_char, file_index, eln_len, termcap_move_right); #endif } else { /* Last column is populated. Example: * 1 file 3 file3 5 file5HERE * 2 file2 4 file4 6 file6HERE * ... */ putchar('\n'); #ifdef TIGHT_COLUMNS cur_col = 0; #endif } } END: #ifdef TIGHT_COLUMNS free(longest_per_col); #endif if (last_column == 0) putchar('\n'); if (pager_quit == 1) printf("... (%zd/%zd)\n", i, files); } /* Execute commands in either AUTOCMD_DIR_IN_FILE or AUTOCMD_DIR_OUT_FILE files. * MODE (either AUTOCMD_DIR_IN or AUTOCMD_DIR_OUT) tells the function * whether to check for AUTOCMD_DIR_IN_FILE or AUTOCMD_DIR_OUT_FILE files. * DIR holds the absolute path to the .cfm.in file whenever we come from * check_autocmd_in_file(). Otherwise, it must be NULL. */ static void run_dir_cmd(const int mode, const char *dir) { char dpath[PATH_MAX + 1]; const char *path = (char *)NULL; if (mode == AUTOCMD_DIR_IN) { if (!dir || !*dir) return; path = dir; } else { /* AUTOCMD_DIR_OUT */ if (dirhist_cur_index <= 0 || !old_pwd || !old_pwd[dirhist_cur_index - 1]) return; snprintf(dpath, sizeof(dpath), "%s/%s", old_pwd[dirhist_cur_index - 1], AUTOCMD_DIR_OUT_FILE); path = dpath; } int fd = 0; FILE *fp = open_fread(path, &fd); if (!fp) return; char buf[PATH_MAX + 1]; *buf = '\0'; char *ret = fgets(buf, sizeof(buf), fp); size_t buf_len = *buf ? strnlen(buf, sizeof(buf)) : 0; if (buf_len > 0 && buf[buf_len - 1] == '\n') { buf[buf_len - 1] = '\0'; buf_len--; } if (!ret || buf_len == 0 || memchr(buf, '\0', buf_len)) { /* Empty line, or it contains a NUL byte (probably binary): reject it. */ fclose(fp); return; } fclose(fp); if (xargs.secure_cmds == 0 || sanitize_cmd(buf, SNT_AUTOCMD) == FUNC_SUCCESS) launch_execl(buf); } /* If the file at offset I is largest than SIZE, store information about this * file in NAME and COLOR, and update SIZE to the size of the new largest file. * Also, TOTAL is increased with the size of the file under analysis. */ static void get_largest_file_info(const filesn_t i, off_t *size, char **name, char **color, off_t *total) { /* Only directories and regular files should be counted. */ if (file_info[i].type != DT_DIR && file_info[i].type != DT_REG && (file_info[i].type != DT_LNK || conf.apparent_size != 1)) return; if (file_info[i].size > *size) { *size = file_info[i].size; *name = file_info[i].name; *color = file_info[i].color; } /* Do not recount hardlinks in the same directory. */ if (file_info[i].linkn > 1 && i > 0) { filesn_t j = i; while (--j >= 0) { if (file_info[i].inode == file_info[j].inode) return; } } *total += file_info[i].size; } static int exclude_file_type_light(const unsigned char type) { if (!filter.str[1]) return FUNC_FAILURE; int match = 0; switch (filter.str[1]) { case 'd': if (type == DT_DIR) match = 1; break; case 'f': if (type == DT_REG) match = 1; break; case 'l': if (type == DT_LNK) match = 1; break; case 's': if (type == DT_SOCK) match = 1; break; case 'c': if (type == DT_CHR) match = 1; break; case 'b': if (type == DT_BLK) match = 1; break; case 'p': if (type == DT_FIFO) match = 1; break; #ifdef SOLARIS_DOORS case 'O': if (type == DT_DOOR) match = 1; break; case 'P': if (type == DT_PORT) match = 1; break; #endif /* SOLARIS_DOORS */ default: return FUNC_FAILURE; } if (match == 1) return filter.rev == 1 ? FUNC_SUCCESS : FUNC_FAILURE; else return filter.rev == 1 ? FUNC_FAILURE : FUNC_SUCCESS; } /* Returns FUNC_SUCCESS if the file with mode MODE and LINKS number * of links must be excluded from the file list, or FUNC_FAILURE. */ static int exclude_file_type(const char *restrict name, const mode_t mode, const nlink_t links, const off_t size) { /* ADD: C = Files with capabilities */ if (!filter.str[1]) return FUNC_FAILURE; struct stat a; int match = 0; switch (filter.str[1]) { case 'b': if (S_ISBLK(mode)) match = 1; break; case 'd': if (S_ISDIR(mode)) match = 1; break; case 'D': if (S_ISDIR(mode) && links <= 2 && count_dir(name, CPOP) <= 2) match = 1; break; case 'c': if (S_ISCHR(mode)) match = 1; break; case 'f': if (S_ISREG(mode)) match = 1; break; case 'F': if (S_ISREG(mode) && size == 0) match = 1; break; case 'l': if (S_ISLNK(mode)) match = 1; break; case 'L': if (S_ISLNK(mode) && stat(name, &a) == -1) match = 1; break; #ifdef SOLARIS_DOORS case 'O': if (S_ISDOOR(mode)) match = 1; break; case 'P': if (S_ISPORT(mode)) match = 1; break; #endif /* SOLARIS_DOORS */ case 'p': if (S_ISFIFO(mode)) match = 1; break; case 's': if (S_ISSOCK(mode)) match = 1; break; case 'g': if (mode & S_ISGID) match = 1; break; /* SGID */ case 'h': if (links > 1 && !S_ISDIR(mode)) match = 1; break; case 'o': if (mode & S_IWOTH) match = 1; break; /* Other writable */ case 't': if (mode & S_ISVTX) match = 1; break; /* Sticky */ case 'u': if (mode & S_ISUID) match = 1; break; /* SUID */ case 'x': if (S_ISREG(mode) && IS_EXEC(mode)) match = 1; break; /* Exec */ default: return FUNC_FAILURE; } if (match == 1) return filter.rev == 1 ? FUNC_SUCCESS : FUNC_FAILURE; else return filter.rev == 1 ? FUNC_FAILURE : FUNC_SUCCESS; } /* Initialize the file_info struct with default values. */ static void init_default_file_info(void) { static int set = 0; if (set == 1) /* Initialize the struct only once. */ return; set = 1; default_file_info = (struct fileinfo){0}; default_file_info.color = df_c; #ifdef _NO_ICONS default_file_info.icon_color = df_c; #else default_file_info.icon = DEF_FILE_ICON; default_file_info.icon_color = DEF_FILE_ICON_COLOR; #endif /* _NO_ICONS */ default_file_info.linkn = 1; default_file_info.user_access = 1; default_file_info.size = 1; } static inline void get_id_names(const filesn_t n) { size_t i; if (sys_users) { for (i = 0; sys_users[i].name; i++) { if (file_info[n].uid != sys_users[i].id) continue; file_info[n].uid_i.name = sys_users[i].name; file_info[n].uid_i.namlen = sys_users[i].namlen; } } if (sys_groups) { for (i = 0; sys_groups[i].name; i++) { if (file_info[n].gid != sys_groups[i].id) continue; file_info[n].gid_i.name = sys_groups[i].name; file_info[n].gid_i.namlen = sys_groups[i].namlen; } } } /* Construct human readable sizes for all files in the current directory * and store them in the human_size struct field of the file_info struct. The * length of each human size is stored in the human_size.len field of the * same struct. */ static void construct_human_sizes(void) { const off_t ibase = xargs.si == 1 ? 1000 : 1024; const float base = (float)ibase; /* R: Ronnabyte, Q: Quettabyte. It's highly unlikely to have files of * such huge sizes (and even less) in the near future, but anyway... */ static const char *const u_iec = "BKMGTPEZYRQ"; /* Let's follow du(1) in using 'k' (lowercase) instead of 'K' * (uppercase) when using powers of 1000 (--si). */ static const char *const u_si = "BkMGTPEZYRQ"; const char *units = xargs.si == 1 ? u_si : u_iec; static float mult_factor = 0; if (mult_factor == 0) mult_factor = 1.0f / base; filesn_t i = files; while (--i >= 0) { if (file_info[i].size < ibase) { /* This includes negative values */ const int ret = snprintf(file_info[i].human_size.str, MAX_HUMAN_SIZE, "%jd", (intmax_t)file_info[i].size); file_info[i].human_size.len = ret > 0 ? (size_t)ret : 0; file_info[i].human_size.unit = units[0]; continue; } size_t n = 0; float s = (float)file_info[i].size; while (s >= base) { s = s * mult_factor; /* == (s = s / base), but faster */ n++; } /* If s == (float)(int)s, then S has no reminder (zero): * We don't want to print the reminder when it is zero. */ const int ret = snprintf(file_info[i].human_size.str, MAX_HUMAN_SIZE, "%.*f", s == (float)(int)s ? 0 : 2, (double)s); file_info[i].human_size.len = ret > 0 ? (size_t)ret : 0; file_info[i].human_size.unit = units[n]; } } #define LIST_SCANNING_MSG "Scanning... " static void print_scanning_message(void) { UNHIDE_CURSOR; fputs(LIST_SCANNING_MSG, stdout); fflush(stdout); if (xargs.list_and_quit != 1) HIDE_CURSOR; } static void print_scanned_file(const char *name) { printf("\r\x1b[%zuC\x1b[0K%s%s%s/", sizeof(LIST_SCANNING_MSG) - 1, di_c, name, df_c); fflush(stdout); } #undef LIST_SCANNING_MSG static void erase_scanning_message(void) { fputs("\r\x1b[0K", stdout); fflush(stdout); } static void check_autocmd_files(void) { struct stat a; char buf[PATH_MAX + 1]; snprintf(buf, sizeof(buf), "%s/%s", workspaces[cur_ws].path, AUTOCMD_DIR_IN_FILE); /* Non-regular files, empty regular files, or bigger than PATH_MAX bytes, * are rejected. */ if (lstat(buf, &a) != -1 && S_ISREG(a.st_mode) && a.st_size > 0 && a.st_size <= PATH_MAX) run_dir_cmd(AUTOCMD_DIR_IN, buf); snprintf(buf, sizeof(buf), "%s/%s", workspaces[cur_ws].path, AUTOCMD_DIR_OUT_FILE); if (lstat(buf, &a) != -1 && S_ISREG(a.st_mode) && a.st_size > 0 && a.st_size <= PATH_MAX) dir_out = 1; } /* List files in the current working directory (global variable 'path'). * Unlike list_dir(), however, this function uses no color and runs * neither stat() nor count_dir(), which makes it quite faster. Return * zero on success and one on error */ static int list_dir_light(const int autocmd_ret) { #ifdef LIST_SPEED_TEST clock_t start = clock(); #endif /* LIST_SPEED_TEST */ struct dothidden_t *hidden_list = (conf.read_dothidden == 1 && conf.show_hidden == 0) ? load_dothidden() : NULL; DIR *dir; struct dirent *ent; int reset_pager = 0; int close_dir = 1; /* Let's store information about the largest file in the list for the * disk usage analyzer mode. */ off_t largest_name_size = 0, total_size = 0; char *largest_name = (char *)NULL, *largest_color = (char *)NULL; if ((dir = opendir(workspaces[cur_ws].path)) == NULL) { xerror("%s: %s: %s\n", PROGRAM_NAME, workspaces[cur_ws].path, strerror(errno)); close_dir = 0; goto END; } #ifdef POSIX_FADV_SEQUENTIAL const int fd = dirfd(dir); if (fd == -1) { xerror(_("%s: Error getting file descriptor for the current " "directory: %s\n"), PROGRAM_NAME, workspaces[cur_ws].path, strerror(errno)); goto END; } posix_fadvise(fd, 0, 0, POSIX_FADV_SEQUENTIAL); #endif /* POSIX_FADV_SEQUENTIAL */ if (checks.autocmd_files == 1) check_autocmd_files(); set_events_checker(); errno = 0; longest.name_len = 0; filesn_t n = 0, count = 0; size_t total_dents = 0; file_info = xnmalloc(ENTRY_N + 2, sizeof(struct fileinfo)); while ((ent = readdir(dir))) { const char *ename = ent->d_name; /* Skip self and parent directories */ if (SELFORPARENT(ename)) continue; /* Skip files according to a regex filter */ if (checks.filter_name == 1) { if (regexec(®ex_exp, ename, 0, NULL, 0) == FUNC_SUCCESS) { if (filter.rev == 1) { stats.excluded++; continue; } } else if (filter.rev == 0) { stats.excluded++; continue; } } if (*ename == '.') { if (conf.show_hidden == 0) { stats.excluded++; continue; } stats.hidden++; } if (hidden_list && check_dothidden(ename, &hidden_list) == 1) { stats.excluded++; continue; } #ifndef _DIRENT_HAVE_D_TYPE struct stat attr; if (lstat(ename, &attr) == -1) continue; if (conf.only_dirs == 1 && !S_ISDIR(attr.st_mode)) #else if (conf.only_dirs == 1 && ent->d_type != DT_DIR) #endif /* !_DIRENT_HAVE_D_TYPE */ { if (*ename == '.' && stats.hidden > 0) stats.hidden--; stats.excluded++; continue; } /* Filter files according to file type */ if (checks.filter_type == 1 #ifndef _DIRENT_HAVE_D_TYPE && exclude_file_type_light((unsigned char)get_dt(attr.st_mode)) == FUNC_SUCCESS) #else && exclude_file_type_light(ent->d_type) == FUNC_SUCCESS) #endif /* !_DIRENT_HAVE_D_TYPE */ { if (*ename == '.' && stats.hidden > 0) stats.hidden--; stats.excluded++; continue; } if (count > ENTRY_N) { count = 0; total_dents = (size_t)n + ENTRY_N; file_info = xnrealloc(file_info, total_dents + 2, sizeof(struct fileinfo)); } file_info[n] = default_file_info; size_t ext_index = 0; file_info[n].utf8 = is_utf8_name(ename, &file_info[n].bytes, &ext_index); file_info[n].name = xnmalloc(file_info[n].bytes + 1, sizeof(char)); memcpy(file_info[n].name, ename, file_info[n].bytes + 1); file_info[n].len = file_info[n].utf8 == 0 ? file_info[n].bytes : wc_xstrlen(ename); file_info[n].ext_name = ext_index > 0 ? file_info[n].name + ext_index : NULL; /* ################ */ #ifndef _DIRENT_HAVE_D_TYPE file_info[n].type = get_dt(attr.st_mode); #else /* If type is unknown, we might be facing a filesystem not * supporting d_type, for example, loop devices. In this case, * try falling back to lstat(2). */ if (ent->d_type != DT_UNKNOWN) { file_info[n].type = ent->d_type; } else { struct stat a; if (lstat(ename, &a) == -1) continue; file_info[n].type = get_dt(a.st_mode); } #endif /* !_DIRENT_HAVE_D_TYPE */ file_info[n].dir = (file_info[n].type == DT_DIR); file_info[n].symlink = (file_info[n].type == DT_LNK); file_info[n].inode = ent->d_ino; if (checks.scanning == 1 && file_info[n].dir == 1) print_scanned_file(file_info[n].name); switch (file_info[n].type) { case DT_DIR: #ifndef _NO_ICONS if (conf.icons == 1) { file_info[n].icon = DEF_DIR_ICON; file_info[n].icon_color = DEF_DIR_ICON_COLOR; /* If set from the color scheme file */ if (*dir_ico_c) file_info[n].icon_color = dir_ico_c; } #endif /* !_NO_ICONS */ stats.dir++; if (conf.files_counter == 1) file_info[n].filesn = count_dir(ename, NO_CPOP) - 2; else file_info[n].filesn = 1; if (file_info[n].filesn > 0) { file_info[n].color = di_c; } else if (file_info[n].filesn == 0) { file_info[n].color = ed_c; } else { file_info[n].color = *nd_c ? nd_c : di_c; #ifndef _NO_ICONS file_info[n].icon = ICON_LOCK; file_info[n].icon_color = YELLOW; #endif /* !_NO_ICONS */ } break; case DT_LNK: #ifndef _NO_ICONS file_info[n].icon = ICON_LINK; #endif /* !_NO_ICONS */ file_info[n].color = ln_c; stats.link++; break; case DT_REG: file_info[n].color = fi_c; stats.reg++; break; case DT_SOCK: file_info[n].color = so_c; stats.socket++; break; case DT_FIFO: file_info[n].color = pi_c; stats.fifo++; break; case DT_BLK: file_info[n].color = bd_c; stats.block_dev++; break; case DT_CHR: file_info[n].color = cd_c; stats.char_dev++; break; #ifndef _BE_POSIX # ifdef SOLARIS_DOORS case DT_DOOR: file_info[n].color = oo_c; stats.door++; break; case DT_PORT: file_info[n].color = oo_c; stats.port++; break; # endif /* SOLARIS_DOORS */ # ifdef S_ARCH1 case DT_ARCH1: file_info[n].color = fi_c; stats.arch1++; break; case DT_ARCH2: file_info[n].color = fi_c; stats.arch2++; break; # endif /* S_ARCH1 */ # ifdef S_IFWHT case DT_WHT: file_info[n].color = fi_c; stats.whiteout++; break; # endif /* DT_WHT */ #endif /* !_BE_POSIX */ case DT_UNKNOWN: file_info[n].color = no_c; stats.unknown++; break; default: file_info[n].color = df_c; break; } #ifndef _NO_ICONS if (checks.icons_use_file_color == 1) file_info[n].icon_color = file_info[n].color; #endif /* !_NO_ICONS */ if (conf.long_view == 1) { #ifndef _DIRENT_HAVE_D_TYPE set_long_attribs(n, &attr); #else struct stat a; if (lstat(file_info[n].name, &a) != -1) set_long_attribs(n, &a); else file_info[n].stat_err = 1; #endif /* !_DIRENT_HAVE_D_TYPE */ if (prop_fields.ids == PROP_ID_NAME && file_info[n].stat_err == 0) get_id_names(n); } if (xargs.disk_usage_analyzer == 1) { get_largest_file_info(n, &largest_name_size, &largest_name, &largest_color, &total_size); } n++; if (n > FILESN_MAX - 1) { err('w', PRINT_PROMPT, _("%s: Integer overflow detected " "(showing only %jd files)\n"), PROGRAM_NAME, (intmax_t)n); break; } count++; } file_info[n].name = (char *)NULL; files = n; if (checks.scanning == 1) erase_scanning_message(); if (n == 0) { printf("%s. ..%s\n", di_c, df_c); free(file_info); goto END; } const int eln_len = conf.no_eln == 1 ? 0 : ((conf.max_files != UNSET && files > (filesn_t)conf.max_files) ? DIGINUM(conf.max_files) : DIGINUM(files)); if (conf.sort != SNONE) ENTSORT(file_info, (size_t)n, entrycmp); size_t counter = 0; size_t columns_n = 1; /* Get the longest filename */ if (conf.columned == 1 || conf.long_view == 1) get_longest_filename(n, (size_t)eln_len); /* Get possible number of columns for the dirlist screen */ columns_n = (conf.pager_view == PAGER_AUTO && (conf.columned == 0 || conf.long_view == 1)) ? 1 : get_columns(); set_pager_view((filesn_t)columns_n); /* ######################## * # LONG VIEW MODE # * ######################## */ if (conf.long_view == 1) { if (prop_fields.size == PROP_SIZE_HUMAN) construct_human_sizes(); print_long_mode(&counter, &reset_pager, eln_len); goto END; } /* ######################## * # NORMAL VIEW MODE # * ######################## */ if (conf.listing_mode == VERTLIST) /* ls(1)-like listing */ list_files_vertical(&counter, &reset_pager, eln_len, columns_n); else list_files_horizontal(&counter, &reset_pager, eln_len, columns_n); END: if (hidden_list) free_dothidden(&hidden_list); exit_code = post_listing(close_dir == 1 ? dir : NULL, reset_pager, autocmd_ret); #ifndef ST_BTIME_LIGHT if (conf.long_view == 1 && prop_fields.time == PROP_TIME_BIRTH) print_reload_msg(NULL, NULL, _("Long view: Birth time not available " "in light mode. Using %smodification time%s.\n"), BOLD, NC); #endif /* !ST_BTIME_LIGHT */ if (xargs.disk_usage_analyzer == 1 && conf.long_view == 1 && conf.full_dir_size == 1) { print_analysis_stats(total_size, largest_name_size, largest_color, largest_name); } #ifdef LIST_SPEED_TEST clock_t end = clock(); printf("list_dir time: %f\n", (double)(end - start) / CLOCKS_PER_SEC); #endif /* LIST_SPEED_TEST */ return exit_code; } /* Check whether the file in the device DEV with inode INO is selected. * Used to mark selected files in the file list. */ static int check_seltag(const dev_t dev, const ino_t ino, const nlink_t links, const filesn_t index) { if (sel_n == 0 || !sel_devino) return 0; filesn_t j = (filesn_t)sel_n; while (--j >= 0) { if (sel_devino[j].dev != dev || sel_devino[j].ino != ino) continue; /* Only check hardlinks in case of regular files */ if (file_info[index].type != DT_DIR && links > 1) { const char *p = strrchr(sel_elements[j].name, '/'); if (!p || !*(++p)) continue; if (*p == *file_info[index].name && strcmp(p, file_info[index].name) == 0) return 1; } else { return 1; } } return 0; } /* Get the color of a link target NAME, whose file attributes are ATTR, * and write the result into the file_info array at index I. */ static inline void set_link_target_color(const char *name, const struct stat *attr, const filesn_t i) { switch (attr->st_mode & S_IFMT) { case S_IFSOCK: file_info[i].color = so_c; break; case S_IFIFO: file_info[i].color = pi_c; break; case S_IFBLK: file_info[i].color = bd_c; break; case S_IFCHR: file_info[i].color = cd_c; break; #ifndef _BE_POSIX # ifdef SOLARIS_DOORS case S_IFDOOR: file_info[i].color = oo_c; break; case S_IFPORT: file_info[i].color = oo_c; break; # endif /* SOLARIS_DOORS */ # ifdef S_ARCH1 case S_ARCH1: file_info[i].color = fi_c; break; case S_ARCH2: file_info[i].color = fi_c; break; # endif /* S_ARCH1 */ # ifdef S_IFWHT case S_IFWHT: file_info[i].color = fi_c; break; # endif /* S_IFWHT */ #endif /* !_BE_POSIX */ case S_IFREG: { size_t clen = 0; char *color = get_regfile_color(name, attr, &clen); if (!color) { file_info[i].color = fi_c; } else if (clen > 0) { /* We have an extension color */ file_info[i].ext_color = savestring(color, clen); file_info[i].color = file_info[i].ext_color; } else { file_info[i].color = color; } } break; default: file_info[i].color = df_c; break; } } static inline void check_extra_file_types(mode_t *mode, const struct stat *a) { /* If all the below macros are originally undefined, they all expand to * zero, in which case A is never used. Let's avoid a compiler warning. */ UNUSED(a); if (S_TYPEISMQ(a)) *mode = DT_MQ; else if (S_TYPEISSEM(a)) *mode = DT_SEM; else if (S_TYPEISSHM(a)) *mode = DT_SHM; else if (S_TYPEISTMO(a)) *mode = DT_TPO; } static inline void load_file_gral_info(const struct stat *a, const filesn_t n) { if (check_file_access(a->st_mode, a->st_uid, a->st_gid) == 0) { file_info[n].user_access = 0; #ifndef _NO_ICONS file_info[n].icon = DEF_NOPERM_ICON; file_info[n].icon_color = DEF_NOPERM_ICON_COLOR; #endif /* !_NO_ICONS */ } switch (a->st_mode & S_IFMT) { case S_IFREG: file_info[n].type = DT_REG; stats.reg++; break; case S_IFDIR: file_info[n].type = DT_DIR; stats.dir++; break; case S_IFLNK: file_info[n].type = DT_LNK; stats.link++; break; case S_IFIFO: file_info[n].type = DT_FIFO; stats.fifo++; break; case S_IFSOCK: file_info[n].type = DT_SOCK; stats.socket++; break; case S_IFBLK: file_info[n].type = DT_BLK; stats.block_dev++; break; case S_IFCHR: file_info[n].type = DT_CHR; stats.char_dev++; break; #ifndef _BE_POSIX # ifdef SOLARIS_DOORS case S_IFDOOR: file_info[n].type = DT_DOOR; stats.door++; break; case S_IFPORT: file_info[n].type = DT_PORT; stats.port++; break; # endif /* SOLARIS_DOORS */ # ifdef S_ARCH1 case S_ARCH1: file_info[n].type = DT_ARCH1; stats.arch1++; break; case S_ARCH2: file_info[n].type = DT_ARCH2; stats.arch2++; break; # endif /* S_ARCH1 */ # ifdef S_IFWHT case S_IFWHT: file_info[n].type = DT_WHT; stats.whiteout++; break; # endif /* S_IFWHT */ #endif /* !_BE_POSIX */ default: file_info[n].type = DT_UNKNOWN; stats.unknown++; break; } check_extra_file_types(&file_info[n].type, a); file_info[n].blocks = a->st_blocks; file_info[n].inode = a->st_ino; file_info[n].linkn = a->st_nlink; file_info[n].mode = a->st_mode; file_info[n].sel = check_seltag(a->st_dev, a->st_ino, a->st_nlink, n); file_info[n].size = FILE_TYPE_NON_ZERO_SIZE(a->st_mode) ? FILE_SIZE(*a) : 0; file_info[n].uid = a->st_uid; file_info[n].gid = a->st_gid; if (checks.id_names == 1) get_id_names(n); #if defined(LINUX_FILE_XATTRS) if (file_info[n].type != DT_LNK && (checks.xattr == 1 || conf.check_cap == 1) && listxattr(file_info[n].name, NULL, 0) > 0) { file_info[n].xattr = 1; stats.extended++; } #endif /* LINUX_FILE_XATTRS */ time_t btime = (time_t)-1; if (checks.birthtime == 1) { #if defined(ST_BTIME) # ifdef LINUX_STATX struct statx attx; if (statx(AT_FDCWD, file_info[n].name, AT_SYMLINK_NOFOLLOW, STATX_BTIME, &attx) == 0 && (attx.stx_mask & STATX_BTIME)) btime = attx.ST_BTIME.tv_sec; # elif defined(__sun) struct timespec birthtim = get_birthtime(file_info[n].name); btime = birthtim.tv_sec; # else btime = a->ST_BTIME.tv_sec; # endif /* LINUX_STATX */ #endif /* ST_BTIME */ } if (conf.long_view == 1) { if (checks.time_follows_sort == 1) { switch (conf.sort) { case SATIME: file_info[n].ltime = a->st_atime; break; case SBTIME: file_info[n].ltime = btime; break; case SCTIME: file_info[n].ltime = a->st_ctime; break; case SMTIME: /* fallthrough */ default: file_info[n].ltime = a->st_mtime; break; } } else { switch (prop_fields.time) { case PROP_TIME_ACCESS: file_info[n].ltime = a->st_atime; break; case PROP_TIME_CHANGE: file_info[n].ltime = a->st_ctime; break; case PROP_TIME_MOD: file_info[n].ltime = a->st_mtime; break; case PROP_TIME_BIRTH: file_info[n].ltime = btime; break; default: file_info[n].ltime = a->st_mtime; break; } } } switch (conf.sort) { case SATIME: file_info[n].time = a->st_atime; break; case SBTIME: file_info[n].time = btime; break; case SCTIME: file_info[n].time = a->st_ctime; break; case SMTIME: file_info[n].time = a->st_mtime; break; default: file_info[n].time = 0; break; } } static inline void load_dir_info(const mode_t mode, const filesn_t n) { file_info[n].dir = 1; #ifndef _NO_ICONS if (conf.icons == 1) get_dir_icon(n); #endif /* !_NO_ICONS */ if (checks.files_counter == 1) { /* Avoid count_dir() if we have no access to the current directory. */ file_info[n].filesn = file_info[n].user_access == 0 ? -1 : count_dir(file_info[n].name, NO_CPOP) - 2; } else { file_info[n].filesn = 1; } if (*nd_c && (file_info[n].user_access == 0 || file_info[n].filesn < 0)) { file_info[n].color = nd_c; } else { file_info[n].color = mode != 0 ? ((mode & S_ISVTX) ? ((mode & S_IWOTH) ? tw_c : st_c) : ((mode & S_IWOTH) ? ow_c : (file_info[n].filesn == 0 ? ed_c : di_c))) : uf_c; /* stat error. */ } stats.empty_dir += (file_info[n].filesn == 0); /* Let's gather some file statistics based on the file type color */ if (file_info[n].color == tw_c) { stats.other_writable++; stats.sticky++; } else if (file_info[n].color == ow_c) { stats.other_writable++; } else { if (file_info[n].color == st_c) stats.sticky++; } } static inline void load_link_info(const int fd, const filesn_t n) { file_info[n].symlink = 1; #ifndef _NO_ICONS file_info[n].icon = DEF_LINK_ICON; file_info[n].icon_color = conf.color_lnk_as_target == 1 ? DEF_LINK_ICON_COLOR : DEF_FILE_ICON_COLOR; #endif /* !_NO_ICONS */ if (conf.follow_symlinks == 0) { file_info[n].color = ln_c; return; } struct stat a; if (fstatat(fd, file_info[n].name, &a, 0) == -1) { file_info[n].color = or_c; file_info[n].xattr = 0; stats.broken_link++; return; } /* We only need the symlink target name provided the target is not a * directory, because set_link_target_color() will check the filename * extension. get_dir_color() only needs this name to run count_dir(), * but we have already executed this function. */ static char tmp[PATH_MAX + 1]; *tmp = '\0'; const ssize_t ret = (conf.color_lnk_as_target == 1 && !S_ISDIR(a.st_mode)) ? readlinkat(XAT_FDCWD, file_info[n].name, tmp, sizeof(tmp) - 1) : 0; if (ret > 0) tmp[ret] = '\0'; const char *lname = *tmp ? tmp : file_info[n].name; if (!S_ISDIR(a.st_mode)) { if (conf.color_lnk_as_target == 1) set_link_target_color(lname, &a, n); else file_info[n].color = ln_c; } else { file_info[n].dir = 1; file_info[n].filesn = conf.files_counter == 1 ? count_dir(file_info[n].name, NO_CPOP) - 2 : 1; const filesn_t files_in_dir = conf.files_counter == 1 ? (file_info[n].filesn > 0 ? 3 : file_info[n].filesn) : 3; /* 3 == populated (we don't care how many files the directory * actually contains). */ if (files_in_dir < 0 && *nd_c) { /* count_dir() failed. */ file_info[n].color = conf.color_lnk_as_target == 1 ? nd_c : ln_c; } else { file_info[n].color = conf.color_lnk_as_target == 1 ? get_dir_color(lname, &a, files_in_dir) : ln_c; } } } static inline void load_regfile_info(const mode_t mode, const filesn_t n) { #ifdef LINUX_FILE_CAPS cap_t cap; #endif /* !LINUX_FILE_CAPS */ if (file_info[n].user_access == 0 && *nf_c) { file_info[n].color = nf_c; } else if (mode & S_ISUID) { file_info[n].exec = 1; stats.exec++; stats.suid++; file_info[n].color = su_c; } else if (mode & S_ISGID) { file_info[n].exec = 1; stats.exec++; stats.sgid++; file_info[n].color = sg_c; } #ifdef LINUX_FILE_CAPS /* Capabilities are stored by the system as extended attributes. * No xattrs, no caps. */ else if (file_info[n].xattr == 1 && (cap = cap_get_file(file_info[n].name))) { file_info[n].color = ca_c; stats.caps++; cap_free(cap); if (IS_EXEC(mode)) { file_info[n].exec = 1; stats.exec++; } } #endif /* LINUX_FILE_CAPS */ else if (IS_EXEC(mode)) { file_info[n].exec = 1; stats.exec++; file_info[n].color = file_info[n].size == 0 ? ee_c : ex_c; } else if (file_info[n].linkn > 1) { /* Multi-hardlink */ file_info[n].color = mh_c; stats.multi_link++; } else if (file_info[n].size == 0) { file_info[n].color = ef_c; stats.empty_reg++; } else { /* Regular file */ file_info[n].color = fi_c; } #ifndef _NO_ICONS if (file_info[n].exec == 1) { file_info[n].icon = DEF_EXEC_ICON; file_info[n].icon_color = DEF_EXEC_ICON_COLOR; } #endif /* !_NO_ICONS */ /* Try temp and extension color only provided the file is a non-empty * regular file. */ const int override_color = (file_info[n].color == fi_c); if (override_color == 1 && IS_TEMP_FILE(file_info[n].name, file_info[n].bytes)) { file_info[n].color = bk_c; return; } #ifndef _NO_ICONS /* The icons check precedence order is this: * 1. filename or filename.extension * 2. extension * 3. file type */ /* Check icons for specific filenames */ const int name_icon_found = conf.icons == 1 ? get_name_icon(n) : 0; #endif /* !_NO_ICONS */ if (!file_info[n].ext_name || override_color == 0 || conf.check_ext == 0) return; /* Check file extension */ char *ext = file_info[n].ext_name; #ifndef _NO_ICONS if (conf.icons == 1 && name_icon_found == 0) get_ext_icon(ext, n); #endif /* !_NO_ICONS */ size_t color_len = 0; const char *extcolor = get_ext_color(ext, &color_len); if (!extcolor) return; char *t = xnmalloc(color_len + 4, sizeof(char)); *t = '\x1b'; t[1] = '['; memcpy(t + 2, extcolor, color_len); t[color_len + 2] = 'm'; t[color_len + 3] = '\0'; file_info[n].ext_color = file_info[n].color = t; } static int vt_stat(const int fd, char *restrict path, struct stat *attr) { static char buf[PATH_MAX + 1]; *buf = '\0'; if (xreadlink(fd, path, buf, sizeof(buf)) == -1) return (-1); if (!*buf || fstatat(fd, buf, attr, AT_SYMLINK_NOFOLLOW) == -1) return (-1); return 0; } /* List files in the current working directory. Uses file type colors * and columns. Return 0 on success or 1 on error. */ int list_dir(void) { #ifdef LIST_SPEED_TEST clock_t start = clock(); #endif /* LIST_SPEED_TEST */ if (conf.clear_screen > 0) { CLEAR; fflush(stdout); } /* Hide the cursor to minimize flickering: it will be unhidden immediately * before printing the next prompt (prompt.c) */ if (xargs.list_and_quit != 1) HIDE_CURSOR; int autocmd_ret = 0; if (autocmds_n > 0 && dir_changed == 1) { if (autocmd_set == 1) revert_autocmd_opts(); autocmd_ret = check_autocmds(); } if (dir_changed == 1 && dir_out == 1) { run_dir_cmd(AUTOCMD_DIR_OUT, NULL); dir_out = 0; } if (conf.clear_screen > 0) { /* For some reason we need to clear the screen twice to prevent * a garbage first line when scrolling up. */ CLEAR; fflush(stdout); } get_term_size(); virtual_dir = (stdin_tmp_dir && strcmp(stdin_tmp_dir, workspaces[cur_ws].path) == 0); stats = (struct stats_t){0}; /* Reset the stats struct */ init_checks_struct(); init_default_file_info(); if (checks.scanning == 1) print_scanning_message(); if (conf.long_view == 1) props_now = time(NULL); if (conf.light_mode == 1) return list_dir_light(autocmd_ret); struct dothidden_t *hidden_list = (conf.read_dothidden == 1 && conf.show_hidden == 0) ? load_dothidden() : NULL; DIR *dir; struct dirent *ent; struct stat attr; int reset_pager = 0; int close_dir = 1; /* Let's store information about the largest file in the list for the * disk usage analyzer mode. */ off_t largest_name_size = 0, total_size = 0; char *largest_name = (char *)NULL; char *largest_color = (char *)NULL; if ((dir = opendir(workspaces[cur_ws].path)) == NULL) { xerror("%s: %s: %s\n", PROGRAM_NAME, workspaces[cur_ws].path, strerror(errno)); close_dir = 0; goto END; } set_events_checker(); const int fd = dirfd(dir); if (fd == -1) { xerror(_("%s: Error getting file descriptor for the current " "directory: %s\n"), PROGRAM_NAME, workspaces[cur_ws].path, strerror(errno)); goto END; } #ifdef POSIX_FADV_SEQUENTIAL /* A hint to the kernel to optimize current dir for reading */ posix_fadvise(fd, 0, 0, POSIX_FADV_SEQUENTIAL); #endif /* POSIX_FADV_SEQUENTIAL */ if (checks.autocmd_files == 1) check_autocmd_files(); /* ########################################## * # GATHER AND STORE FILE INFORMATION # * ########################################## */ errno = 0; longest.name_len = 0; filesn_t n = 0, count = 0; size_t total_dents = 0; file_info = xnmalloc(ENTRY_N + 2, sizeof(struct fileinfo)); /* Cache used values in local variables for faster access. */ const int checks_filter_name = checks.filter_name; const int checks_filter_type = checks.filter_type; const int checks_scanning = checks.scanning; #ifndef _NO_ICONS const int checks_icons_use_file_color = checks.icons_use_file_color; #endif /* !_NO_ICONS */ const int conf_only_dirs = conf.only_dirs; const int conf_show_hidden = conf.show_hidden; const int conf_follow_symlinks = conf.follow_symlinks; const int conf_long_view = conf.long_view; const int xargs_disk_usage_analyzer = xargs.disk_usage_analyzer; const int stat_flag = (conf.follow_symlinks == 1 && conf.long_view == 1 && conf.follow_symlinks_long == 1) ? 0 : AT_SYMLINK_NOFOLLOW; while ((ent = readdir(dir))) { const char *ename = ent->d_name; /* Skip self and parent directories */ if (SELFORPARENT(ename)) continue; /* Filter files according to a regex filter */ if (checks_filter_name == 1) { if (regexec(®ex_exp, ename, 0, NULL, 0) == 0) { if (filter.rev == 1) { stats.excluded++; continue; } } else if (filter.rev == 0) { stats.excluded++; continue; } } if (*ename == '.') { if (conf_show_hidden == 0) { stats.excluded++; continue; } stats.hidden++; } if (hidden_list && check_dothidden(ename, &hidden_list) == 1) { stats.excluded++; continue; } const int stat_ok = ((virtual_dir == 1 ? vt_stat(fd, ent->d_name, &attr) : fstatat(fd, ename, &attr, stat_flag)) == 0); if (stat_ok == 0) { if (virtual_dir == 1) continue; } else { /* Filter files according to file type. */ if ((checks_filter_type == 1 && exclude_file_type(ename, attr.st_mode, attr.st_nlink, attr.st_size) == FUNC_SUCCESS) /* Filter non-directory files. */ || (conf_only_dirs == 1 && !S_ISDIR(attr.st_mode) && (conf_follow_symlinks == 0 || !S_ISLNK(attr.st_mode) || get_link_ref(ename) != S_IFDIR))) { /* Decrease the counter: the file won't be displayed. */ if (*ename == '.' && stats.hidden > 0) stats.hidden--; stats.excluded++; continue; } } if (count > ENTRY_N) { count = 0; total_dents = (size_t)n + ENTRY_N; file_info = xnrealloc(file_info, total_dents + 2, sizeof(struct fileinfo)); } file_info[n] = default_file_info; /* Both is_utf8_name() and wc_xstrlen() calculate the number of * columns needed to display the current filename on the screen * (the former for ASCII names, where 1 char = 1 byte = 1 column, and * the latter for UTF-8 names, i.e. containing at least one non-ASCII * character). * Now, since is_utf8_name() is ~8 times faster than wc_xstrlen() * (10,000 entries, optimization O3), we only run wc_xstrlen() in * case of an UTF-8 name. * However, since is_utf8_name() will be executed anyway, this ends * up being actually slower whenever the current directory contains * more UTF-8 than ASCII names. The assumption here is that ASCII * names are far more common than UTF-8 names. */ size_t ext_index = 0; file_info[n].utf8 = is_utf8_name(ename, &file_info[n].bytes, &ext_index); file_info[n].name = xnmalloc(file_info[n].bytes + 1, sizeof(char)); memcpy(file_info[n].name, ename, file_info[n].bytes + 1); /* Columns needed to display filename */ file_info[n].len = file_info[n].utf8 == 0 ? file_info[n].bytes : wc_xstrlen(ename); file_info[n].ext_name = ext_index == 0 ? NULL : file_info[n].name + ext_index; if (stat_ok == 1) { load_file_gral_info(&attr, n); } else { file_info[n].type = DT_UNKNOWN; file_info[n].stat_err = 1; attr.st_mode = 0; stats.unknown++; stats.unstat++; } switch (file_info[n].type) { case DT_DIR: load_dir_info(attr.st_mode, n); break; case DT_LNK: load_link_info(fd, n); break; case DT_REG: load_regfile_info(attr.st_mode, n); break; case DT_SOCK: file_info[n].color = so_c; break; case DT_FIFO: file_info[n].color = pi_c; break; case DT_BLK: file_info[n].color = bd_c; break; case DT_CHR: file_info[n].color = cd_c; break; #ifdef SOLARIS_DOORS case DT_DOOR: file_info[n].color = oo_c; break; case DT_PORT: file_info[n].color = oo_c; break; #endif /* SOLARIS_DOORS */ case DT_UNKNOWN: file_info[n].color = no_c; break; default: file_info[n].color = df_c; break; /* For the time being, we have no specific colors for DT_ARCH1, * DT_ARCH2, and DT_WHT. */ } if (checks_scanning == 1 && file_info[n].dir == 1) print_scanned_file(file_info[n].name); #ifndef _NO_ICONS if (checks_icons_use_file_color == 1) file_info[n].icon_color = file_info[n].color; #endif /* !_NO_ICONS */ if (conf_long_view == 1 && stat_ok == 1) set_long_attribs(n, &attr); if (xargs_disk_usage_analyzer == 1) { get_largest_file_info(n, &largest_name_size, &largest_name, &largest_color, &total_size); } n++; if (n > FILESN_MAX - 1) { err('w', PRINT_PROMPT, _("%s: Integer overflow detected " "(showing only %jd files)\n"), PROGRAM_NAME, (intmax_t)n); break; } count++; } /* Since we allocate memory by chunks, we probably allocated more * than required. Let's free unused memory. * Up to 18Kb can be freed this way. */ /* filesn_t tdents = total_dents > 0 ? (filesn_t)total_dents : ENTRY_N + 2; if (tdents > n) file_info = xnrealloc(file_info, (size_t)n + 1, sizeof(struct fileinfo)); */ file_info[n].name = (char *)NULL; files = n; if (checks.scanning == 1) erase_scanning_message(); if (n == 0) { printf("%s. ..%s\n", di_c, df_c); free(file_info); goto END; } const int eln_len = conf.no_eln == 1 ? 0 : ((conf.max_files != UNSET && files > (filesn_t)conf.max_files) ? DIGINUM(conf.max_files) : DIGINUM(files)); /* ############################################# * # SORT FILES ACCORDING TO SORT METHOD # * ############################################# */ if (conf.sort != SNONE) ENTSORT(file_info, (size_t)n, entrycmp); /* ########################################## * # GET INFO TO PRINT COLUMNED OUTPUT # * ########################################## */ size_t counter = 0; /* Get the longest filename. */ if (conf.columned == 1 || conf.long_view == 1 || conf.pager_view != PAGER_AUTO) get_longest_filename(n, (size_t)eln_len); /* Get the number of columns required to print all filenames. */ const size_t columns_n = (conf.pager_view == PAGER_AUTO && (conf.columned == 0 || conf.long_view == 1)) ? 1 : get_columns(); set_pager_view((filesn_t)columns_n); /* ######################## * # LONG VIEW MODE # * ######################## */ if (conf.long_view == 1) { if (prop_fields.size == PROP_SIZE_HUMAN) construct_human_sizes(); print_long_mode(&counter, &reset_pager, eln_len); goto END; } /* ######################## * # NORMAL VIEW MODE # * ######################## */ if (conf.listing_mode == VERTLIST) /* ls(1) like listing */ list_files_vertical(&counter, &reset_pager, eln_len, columns_n); else list_files_horizontal(&counter, &reset_pager, eln_len, columns_n); /* ######################### * # POST LISTING STUFF # * ######################### */ END: if (hidden_list) free_dothidden(&hidden_list); exit_code = post_listing(close_dir == 1 ? dir : NULL, reset_pager, autocmd_ret); if (xargs.disk_usage_analyzer == 1 && conf.long_view == 1 && conf.full_dir_size == 1) { print_analysis_stats(total_size, largest_name_size, largest_color, largest_name); } #ifdef LIST_SPEED_TEST clock_t end = clock(); printf("list_dir time: %f\n", (double)(end - start) / CLOCKS_PER_SEC); #endif /* LIST_SPEED_TEST */ return exit_code; } void free_dirlist(void) { if (!file_info || files == 0) return; filesn_t i = files; while (--i >= 0) { free(file_info[i].name); free(file_info[i].ext_color); } free(file_info); file_info = (struct fileinfo *)NULL; } void reload_dirlist(void) { #ifdef RUN_CMD if (cmd_line_cmd) return; #endif /* RUN_CMD */ free_dirlist(); const int bk = exit_code; list_dir(); exit_code = bk; } void refresh_screen(void) { if (conf.autols == 0) { CLEAR; return; } const int bk = conf.clear_screen; conf.clear_screen = 1; reload_dirlist(); conf.clear_screen = bk; } clifm-1.26.3/src/listing.h000066400000000000000000000022021506632037700153130ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* listing.h */ #ifndef LISTING_H #define LISTING_H __BEGIN_DECLS void free_dirlist(void); int list_dir(void); void reload_dirlist(void); void refresh_screen(void); #ifndef _NO_ICONS void init_icons_hashes(void); #endif /* !_NO_ICONS */ __END_DECLS #endif /* LISTING_H */ clifm-1.26.3/src/long_view.c000066400000000000000000000471261506632037700156440ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* long_view.c -- Construct entries in long view mode */ #include "helpers.h" #include /* memcpy(3), strrchr(3) */ #include /* strftime(3) */ #include "aux.h" /* xitoa() */ #include "checks.h" /* check_file_access() */ #include "colors.h" /* remove_bold_attr() */ #include "long_view.h" /* macros */ #include "misc.h" /* gen_diff_str() */ #include "properties.h" /* get_color_age, get_color_size, get_file_perms */ /* Remaining space in the properties string buffer. */ static size_t buf_rem_space = 0; /* Precomputed colors without the bold attribute for the file type field * in the permissions string. */ static char bd_nb[MAX_COLOR]; static char cd_nb[MAX_COLOR]; static char df_nb[MAX_COLOR]; static char di_nb[MAX_COLOR]; static char dn_nb[MAX_COLOR]; static char fi_nb[MAX_COLOR]; static char ln_nb[MAX_COLOR]; #ifdef SOLARIS_DOORS static char oo_nb[MAX_COLOR]; #endif /* SOLARIS_DOORS */ static char pi_nb[MAX_COLOR]; static char so_nb[MAX_COLOR]; static char * get_ext_info_long(const struct fileinfo *props, const size_t name_len, int *trunc, size_t *ext_len) { /* At this point, TRUNC is set to TRUNC_NO_EXT and EXT_LEN to zero. */ if (!props->ext_name) return (char *)NULL; if (props->utf8 == 0) *ext_len = name_len - (size_t)(props->ext_name - props->name); else *ext_len = wc_xstrlen(props->ext_name); if ((int)*ext_len >= conf.max_name_len || (int)*ext_len <= 0) *ext_len = 0; else *trunc = TRUNC_EXT; return props->ext_name; } /* Calculate the relative time of AGE, which is the difference between * NOW and the corresponding file time. */ static void calc_relative_time(const time_t age, char *s) { if (age < 0L) /* Future (AGE, however, is guaranteed to be positive) */ snprintf(s, MAX_TIME_STR, " - "); else if (age < RT_MINUTE) snprintf(s, MAX_TIME_STR, "%*ju sec", 2, (uintmax_t)age); else if (age < RT_HOUR) snprintf(s, MAX_TIME_STR, "%*ju min", 2, (uintmax_t)(age / RT_MINUTE)); else if (age < RT_DAY) snprintf(s, MAX_TIME_STR, "%*ju hour", 2, (uintmax_t)(age / RT_HOUR)); else if (age < RT_WEEK) snprintf(s, MAX_TIME_STR, "%*ju day", 2, (uintmax_t)(age / RT_DAY)); else if (age < RT_MONTH) { /* RT_MONTH is 30 days. But since Feb has only 28, we get 4 weeks * in some cases, which is weird. Always make 4 weeks into 1 month */ const long long n = age / RT_WEEK; if (n == 4) snprintf(s, MAX_TIME_STR, " 1 mon"); else snprintf(s, MAX_TIME_STR, "%*ju week", 2, (uintmax_t)n); } else if (age < RT_YEAR) { const long long n = age / RT_MONTH; if (n == 12) snprintf(s, MAX_TIME_STR, " 1 year"); else snprintf(s, MAX_TIME_STR, "%*ju mon", 2, (uintmax_t)n); } else { snprintf(s, MAX_TIME_STR, "%*ju year", 2, (uintmax_t)(age / RT_YEAR)); } } static void construct_and_print_filename(const struct fileinfo *props, const int max_namelen) { /* If the filename length is greater than MAX_NAMELEN, truncate it to * MAX_NAMELEN (later a tilde (~) will be appended to let the user know * the filename was truncated). */ int trunc = 0; /* Handle filenames with embedded control characters. */ size_t plen = props->len; char *wname = (char *)NULL; if (plen == 0) { wname = replace_invalid_chars(props->name); plen = wc_xstrlen(wname); } const filesn_t n = (conf.max_files > UNSET && files > (filesn_t)conf.max_files) ? (filesn_t)conf.max_files : files; size_t cur_len = (size_t)DIGINUM(n) + 1 + plen + (conf.icons == 1 ? (size_t)ICON_LEN : 0); int diff = 0; char *name = wname ? wname : props->name; char *ext_name = (char *)NULL; if (cur_len > (size_t)max_namelen) { const int rest = (int)cur_len - max_namelen; trunc = TRUNC_NO_EXT; size_t ext_len = 0; ext_name = get_ext_info_long(props, plen, &trunc, &ext_len); int trunc_point = (int)plen - rest - 1 - (int)ext_len; if (trunc_point <= 0) { trunc_point = (int)plen - rest - 1; trunc = TRUNC_NO_EXT; } if (props->utf8 == 1) { if (wname) xstrsncpy(name_buf, name, sizeof(name_buf)); else /* memcpy is faster: use it whenever possible. */ memcpy(name_buf, name, props->bytes + 1); diff = u8truncstr(name_buf, (size_t)trunc_point); } else { /* Let's avoid u8truncstr() to get some extra speed. */ const char c = name[trunc_point]; name[trunc_point] = '\0'; mbstowcs((wchar_t *)name_buf, name, NAME_BUF_SIZE); name[trunc_point] = c; } cur_len -= (size_t)rest; } else { mbstowcs((wchar_t *)name_buf, name, NAME_BUF_SIZE); } free(wname); /* Calculate pad for each filename */ int pad = max_namelen - (int)cur_len; if (pad < 0) pad = 0; const char *trunc_diff = diff > 0 ? gen_diff_str(diff) : ""; static char trunc_s[2] = {0}; *trunc_s = trunc > 0 ? TRUNC_FILE_CHR : 0; printf("%s%s%s%s%s%ls%s%s%-*s%s\x1b[0m%s%s\x1b[0m%s%s%s ", (conf.colorize == 1 && conf.icons == 1) ? props->icon_color : "", conf.icons == 1 ? props->icon : "", conf.icons == 1 ? " " : "", df_c, conf.colorize == 1 ? props->color : "", (wchar_t *)name_buf, trunc_diff, conf.light_mode == 1 ? "\x1b[0m" : df_c, pad, "", df_c, trunc ? tt_c : "", trunc_s, trunc == TRUNC_EXT ? props->color : "", trunc == TRUNC_EXT ? ext_name : "", trunc == TRUNC_EXT ? df_c : ""); } static size_t gen_size(const struct fileinfo *props, char *size_str, const int size_max, const int file_perm) { if (prop_fields.size == 0) { *size_str = '\0'; return 0; } int bytes = 0; if (props->stat_err == 1) { bytes = snprintf(size_str, buf_rem_space, "%*s", size_max + (prop_fields.size == PROP_SIZE_HUMAN), UNKNOWN_STR); return bytes > 0 ? (size_t)bytes : 0; } const int no_dir_access = (file_perm == 0 && props->dir == 1 && conf.full_dir_size == 1); if (S_ISCHR(props->mode) || S_ISBLK(props->mode) || no_dir_access == 1) { bytes = snprintf(size_str, buf_rem_space, "%s%*c%s", dn_c, size_max + (prop_fields.size == PROP_SIZE_HUMAN), no_dir_access == 1 ? UNKNOWN_CHR : '-', df_c); return bytes > 0 ? (size_t)bytes : 0; } const off_t size = (FILE_TYPE_NON_ZERO_SIZE(props->mode) || props->type == DT_SHM || props->type == DT_TPO) ? props->size : 0; /* Let's construct the color for the current file size */ char *csize = dz_c; static char sf[MAX_SHADE_LEN]; if (!*dz_c && conf.colorize == 1) { get_color_size(size, sf, sizeof(sf)); csize = sf; } if (prop_fields.size != PROP_SIZE_HUMAN) { char err_char[2] = {0}; err_char[0] = props->du_status != 0 ? DU_ERR_CHAR : 0; bytes = snprintf(size_str, buf_rem_space, "%s%*jd%s%s", csize, (props->du_status != 0 && size_max > 0) ? size_max - 1 : size_max, (intmax_t)size, df_c, err_char); return bytes > 0 ? (size_t)bytes : 0; } const int du_err = (props->du_status != 0 && props->dir == 1 && conf.full_dir_size == 1); const char *unit_color = conf.colorize == 1 ? (du_err == 1 ? xf_cb : dim_c) : ((du_err == 1 && xargs.no_bold != 1) ? "\x1b[1m" : ""); bytes = snprintf(size_str, buf_rem_space, "%s%*s%s%c\x1b[0m%s", csize, size_max, *props->human_size.str ? props->human_size.str : UNKNOWN_STR, unit_color, props->human_size.unit, df_c); return bytes > 0 ? (size_t)bytes : 0; } static size_t gen_perms(const mode_t mode, char *perm_str, const char file_type, const char *ctype) { int bytes = 0; if (prop_fields.perm == PERM_SYMBOLIC) { const struct perms_t perms = get_file_perms(mode); bytes = snprintf(perm_str, buf_rem_space, "%s%c%s/%s%c%s%c%s%c%s.%s%c%s%c%s%c%s.%s%c%s%c%s%c%s", ctype, file_type, dn_c, perms.cur, perms.ur, perms.cuw, perms.uw, perms.cux, perms.ux, dn_c, perms.cgr, perms.gr, perms.cgw, perms.gw, perms.cgx, perms.gx, dn_c, perms.cor, perms.or, perms.cow, perms.ow, perms.cox, perms.ox, df_c); } else /* PERM_NUMERIC */ { bytes = snprintf(perm_str, PERM_STR_LEN, "%s%04o%s", do_c, mode & 07777, df_c); } return bytes > 0 ? (size_t)bytes : 0; } static const char * get_time_char(void) { if (conf.time_follows_sort == 1) { switch (conf.sort) { case SATIME: return conf.relative_time == 1 ? "A" : "a"; case SBTIME: return conf.relative_time == 1 ? "B" : "b"; case SCTIME: return conf.relative_time == 1 ? "C" : "c"; case SMTIME: /* fallthrough */ default: return conf.relative_time == 1 ? "M" : "m"; } } switch (prop_fields.time) { case PROP_TIME_ACCESS: return conf.relative_time == 1 ? "A" : "a"; case PROP_TIME_BIRTH: return conf.relative_time == 1 ? "B" : "b"; case PROP_TIME_CHANGE: return conf.relative_time == 1 ? "C" : "c"; case PROP_TIME_MOD: /* fallthrough */ default: return conf.relative_time == 1 ? "M" : "m"; } } /* GCC (not clang) complains about tfmt being not a string literal. Let's * silence this warning until we find a better approach. */ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wformat-nonliteral" static size_t gen_time(char *time_str, const struct fileinfo *props) { const time_t t = props->ltime; /* Let's construct the color for the current timestamp. */ char *cdate = dd_c; static char df[MAX_SHADE_LEN]; if (conf.colorize == 1 && !*dd_c) { get_color_age(t, df, sizeof(df)); cdate = df; } static char file_time[MAX_TIME_STR]; struct tm tm; if (props->stat_err == 1) { /* Let' use the same string we use for invalid times, but * replace '-' by '?'. */ xstrsncpy(file_time, invalid_time_str, sizeof(file_time)); const int index = conf.relative_time == 1 ? 1 : 0; file_time[index] = UNKNOWN_CHR; cdate = df_c; } else if (t >= 0 && t != (time_t)-1) { /* PROPS_NOW (global) is set by list_dir(), in listing.c before * calling print_entry_props(), which calls this function. */ const time_t age = props_now - t; /* AGE is negative if file time is in the future. */ if (conf.relative_time == 1) { calc_relative_time(age < 0 ? -age : age, file_time); } else if (localtime_r(&t, &tm)) { /* If not user defined, let's mimic ls(1) behavior: a file is * considered recent if it is within the past six months. */ const int recent = age >= 0 && age < 14515200LL; /* 14515200 == 6*4*7*24*60*60 == six months */ const char *tfmt = conf.time_str ? conf.time_str : (recent ? DEF_TIME_STYLE_RECENT : DEF_TIME_STYLE_OLDER); strftime(file_time, sizeof(file_time), tfmt, &tm); } else { xstrsncpy(file_time, invalid_time_str, sizeof(file_time)); } } else { /* INVALID_TIME_STR (global) is generated at startup by * check_time_str(), in init.c. */ xstrsncpy(file_time, invalid_time_str, sizeof(file_time)); } const int bytes = snprintf(time_str, buf_rem_space, "%s%s%s%s%s", cdate, *file_time ? file_time : UNKNOWN_STR, dt_c, conf.timestamp_mark == 1 ? get_time_char() : "", df_c); return bytes > 0 ? (size_t)bytes : 0; } #pragma GCC diagnostic pop static size_t gen_id(const struct fileinfo *props, char *id_str, const struct maxes_t *maxes, const int file_perm) { int bytes = 0; const char *uid_color = (file_perm == 1 && conf.colorize == 1) ? du_c : df_c; #define USER_NAME props->uid_i.name ? props->uid_i.name \ : (props->stat_err == 1 ? UNKNOWN_STR : xitoa(props->uid)) #define GROUP_NAME props->gid_i.name ? props->gid_i.name \ : (props->stat_err == 1 ? UNKNOWN_STR : xitoa(props->gid)) if (prop_fields.no_group == 1) { if (prop_fields.ids == PROP_ID_NUM) { if (props->stat_err == 1) { bytes = snprintf(id_str, buf_rem_space, "%s%*s%s", uid_color, maxes->id_user, UNKNOWN_STR, df_c); } else { bytes = snprintf(id_str, buf_rem_space, "%s%*u%s", uid_color, maxes->id_user, props->uid, df_c); } } else { /* PROPS_ID_NAME */ bytes = snprintf(id_str, buf_rem_space, "%s%-*s%s", uid_color, maxes->id_user, USER_NAME, df_c); } return bytes > 0 ? (size_t)bytes : 0; } const char *gid_color = conf.colorize == 0 ? "" : (file_perm == 1 ? dg_c : dim_c); if (prop_fields.ids == PROP_ID_NUM) { if (props->stat_err == 1) { bytes = snprintf(id_str, buf_rem_space, "%s%*c %*c", df_c, maxes->id_user, UNKNOWN_CHR, maxes->id_group, UNKNOWN_CHR); } else { bytes = snprintf(id_str, buf_rem_space, "%s%*u %s%*u%s", uid_color, maxes->id_user, props->uid, gid_color, maxes->id_group, props->gid, df_c); } } else { /* PROPS_ID_NAME */ bytes = snprintf(id_str, buf_rem_space, "%s%-*s %s%-*s%s", uid_color, maxes->id_user, USER_NAME, props->stat_err == 1 ? "" : gid_color, maxes->id_group, GROUP_NAME, df_c); } #undef USER_NAME #undef GROUP_NAME return bytes > 0 ? (size_t)bytes : 0; } static size_t gen_filecounter(const struct fileinfo *props, char *fc_str, const int max) { int bytes = 0; if (props->filesn > 0) { bytes = snprintf(fc_str, buf_rem_space, "%s%*zu%s", fc_c, max, props->filesn, df_c); } else { bytes = snprintf(fc_str, buf_rem_space, "%s%*c%s", dn_c, max, props->filesn < 0 ? UNKNOWN_CHR /* Dir with no read permission */ : (props->dir == 1 ? '0' : '-'), df_c); } return bytes > 0 ? (size_t)bytes : 0; } static size_t gen_inode(const struct fileinfo *props, char *ino_str, const int max) { int bytes = 0; if (props->stat_err == 1) { bytes = snprintf(ino_str, buf_rem_space, "\x1b[0m%*s%s", max, UNKNOWN_STR, df_c); } else { bytes = snprintf(ino_str, buf_rem_space, "\x1b[0m%s%*ju%s", de_c, max, (uintmax_t)props->inode, df_c); } return bytes > 0 ? (size_t)bytes : 0; } static size_t gen_links(const struct fileinfo *props, char *links_str, const int max) { int bytes = 0; if (props->stat_err == 1) { bytes = snprintf(links_str, buf_rem_space, "\x1b[0m%*s%s", max, UNKNOWN_STR, df_c); } else { bytes = snprintf(links_str, buf_rem_space, "\x1b[0m%s%s%*ju%s", dk_c, props->linkn > 1 ? BOLD : "", max, (uintmax_t)props->linkn, df_c); } return bytes > 0 ? (size_t)bytes : 0; } static size_t gen_blocks(const struct fileinfo *props, char *blk_str, const int max) { int bytes = 0; if (props->stat_err == 1) { bytes = snprintf(blk_str, buf_rem_space, "\x1b[0m%*s%s", max, UNKNOWN_STR, df_c); } else { bytes = snprintf(blk_str, buf_rem_space, "\x1b[0m%s%*jd%s", db_c, max, (intmax_t)props->blocks, df_c); } return bytes > 0 ? (size_t)bytes : 0; } static void set_no_bold_colors(void) { xstrsncpy(bd_nb, bd_c, sizeof(bd_nb)); remove_bold_attr(bd_nb); xstrsncpy(cd_nb, cd_c, sizeof(cd_nb)); remove_bold_attr(cd_nb); xstrsncpy(df_nb, df_c, sizeof(df_nb)); remove_bold_attr(df_nb); xstrsncpy(di_nb, di_c, sizeof(di_nb)); remove_bold_attr(di_nb); xstrsncpy(dn_nb, dn_c, sizeof(dn_nb)); remove_bold_attr(dn_nb); xstrsncpy(fi_nb, fi_c, sizeof(fi_nb)); remove_bold_attr(fi_nb); xstrsncpy(ln_nb, ln_c, sizeof(ln_nb)); remove_bold_attr(ln_nb); #ifdef SOLARIS_DOORS xstrsncpy(oo_nb, oo_c, sizeof(oo_nb)); remove_bold_attr(oo_nb); #endif /* SOLARIS_DOORS */ xstrsncpy(pi_nb, pi_c, sizeof(pi_nb)); remove_bold_attr(pi_nb); xstrsncpy(so_nb, so_c, sizeof(so_nb)); remove_bold_attr(so_nb); } static char set_file_type_and_color(const struct fileinfo *props, char **color) { /* Precompute file type colors without the bold attribute for the * file type field in the permissions string. Let's do this only once, * and each time the color scheme is switched. */ static char *cscheme_bk = NULL; if (!cscheme_bk || cscheme_bk != cur_cscheme) { set_no_bold_colors(); cscheme_bk = cur_cscheme; } struct stat a; if (props->stat_err == 1 && conf.follow_symlinks_long == 1 && conf.long_view == 1 && conf.follow_symlinks == 1 && lstat(props->name, &a) == 0 && S_ISLNK(a.st_mode)) { *color = conf.colorize == 1 ? ln_nb : df_nb; return LNK_PCHR; } char type = 0; switch (props->mode & S_IFMT) { case S_IFREG: type = REG_PCHR; *color = dn_nb; break; case S_IFDIR: type = DIR_PCHR; *color = di_nb; break; case S_IFLNK: type = LNK_PCHR; *color = ln_nb; break; case S_IFIFO: type = FIFO_PCHR; *color = pi_nb; break; case S_IFSOCK: type = SOCK_PCHR; *color = so_nb; break; case S_IFBLK: type = BLKDEV_PCHR; *color = bd_nb; break; case S_IFCHR: type = CHARDEV_PCHR; *color = cd_nb; break; #ifndef _BE_POSIX # ifdef S_ARCH1 case S_ARCH1: type = ARCH1_PCHR; *color = fi_nb; break; case S_ARCH2: type = ARCH2_PCHR; *color = fi_nb; break; # endif /* S_ARCH1 */ # ifdef SOLARIS_DOORS case S_IFDOOR: type = DOOR_PCHR; *color = oo_nb; break; case S_IFPORT: type = PORT_PCHR; *color = oo_nb; break; # endif /* SOLARIS_DOORS */ # ifdef S_IFWHT case S_IFWHT: type = WHT_PCHR; *color = fi_nb; break; # endif /* S_IFWHT */ #endif /* !_BE_POSIX */ default: type = UNK_PCHR; *color = dn_nb; break; } if (conf.colorize == 0) *color = df_nb; return type; } /* Compose the properties line for the current filename. * This function is called by list_dir(), in listing.c, for each filename * in the current directory when running in long view mode (after * printing the corresponding ELN). */ int print_entry_props(const struct fileinfo *props, const struct maxes_t *maxes, const int have_xattr) { static char buf[MAX_PROP_STR + 1]; /* Store generated fields */ size_t len = 0; /* Bytes written into buf so far. */ char *ctype = NULL; /* Color for the file type indicator */ const char file_type = set_file_type_and_color(props, &ctype); const int file_perm = conf.light_mode == 1 ? check_file_access(props->mode, props->uid, props->gid) : (props->stat_err != 1 && props->user_access != 0); const char xattr_char = have_xattr == 1 ? (props->xattr == 1 ? XATTR_CHAR : ' ') : 0; const size_t prop_fields_gap = (size_t)conf.prop_fields_gap; const int file_counter = (conf.files_counter != 0 && maxes->files_counter != 0); construct_and_print_filename(props, maxes->name); /* Let's print fields according to the value of PropFields in the * config file (prop_fields_str). */ for (size_t i = 0; i < PROP_FIELDS_SIZE && prop_fields_str[i]; i++) { if (len >= sizeof(buf) - 1) break; buf_rem_space = sizeof(buf) - len; switch (prop_fields_str[i]) { case 'B': len += gen_blocks(props, buf + len, maxes->blocks); break; case 'f': if (file_counter == 1) len += gen_filecounter(props, buf + len, maxes->files_counter); break; case 'd': len += gen_inode(props, buf + len, maxes->inode); break; case 'p': /* fallthrough */ case 'n': len += gen_perms(props->mode, buf + len, file_type, ctype); if (xattr_char != 0) buf[len++] = xattr_char; break; case 'i': /* fallthrough */ case 'I': len += gen_id(props, buf + len, maxes, file_perm); break; case 'l': len += gen_links(props, buf + len, maxes->links); break; case 'a': /* fallthrough */ case 'b': /* fallthrough */ case 'm': /* fallthrough */ case 'c': len += gen_time(buf + len, props); break; case 's': /* fallthrough */ case 'S': len += gen_size(props, buf + len, maxes->size, file_perm); break; default: continue; /* Unknown option character. Skip it. */ } /* If not the last field, add some space to separate the current * field from the next one. */ const int last_field = prop_fields_str[i + 1] == '\0'; if (last_field == 1 || (sizeof(buf) - len) <= prop_fields_gap) break; buf[len++] = ' '; if (conf.prop_fields_gap > 1) /* PropFieldsGap is at most 2. */ buf[len++] = ' '; } buf[len] = '\0'; fputs(buf, stdout); putchar('\n'); return FUNC_SUCCESS; } clifm-1.26.3/src/long_view.h000066400000000000000000000055771506632037700156550ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* long_view.h */ #ifndef LONG_VIEW_H #define LONG_VIEW_H /* These macros define the max length for each properties field. * These lengths are made based on how each field is built (i.e. displayed). * We first construct and store (in the stack, to avoid expensive heap * allocation) the appropeiate value, and then print them all * (print_entry_props()). */ /* 14 colors + 15 single chars + NUL byte */ #define PERM_STR_LEN ((MAX_COLOR * 14) + 16) /* construct_file_perms() */ #define TIME_STR_LEN (MAX_TIME_STR + (MAX_COLOR * 4) + 2 + 1) /* construct_timestamp() */ /* construct_human_size() returns a string of at most MAX_HUMAN_SIZE chars (helpers.h) */ #define SIZE_STR_LEN (MAX_HUMAN_SIZE + (MAX_COLOR * 3) + 10) /* construct_file_size() */ /* 2 colors + 2 names + (space + NUL byte) + DIM */ #define ID_STR_LEN ((MAX_COLOR * 2) + (NAME_MAX * 2) + 2 + 4) /* Max inode number able to hold: 999 billions! Padding could be as long * as max inode lenght - 1 */ #define INO_STR_LEN ((MAX_COLOR * 2) + ((12 + 1) * 2) + 4) #define LINKS_STR_LEN ((MAX_COLOR * 2) + 32) /* File counter */ #define FC_STR_LEN ((MAX_COLOR * 2) + 32) /* File allocated blocks */ #define BLK_STR_LEN ((MAX_COLOR * 2) + 32) #define MAX_PROP_STR (PERM_STR_LEN + TIME_STR_LEN + SIZE_STR_LEN \ + ID_STR_LEN + INO_STR_LEN + LINKS_STR_LEN + FC_STR_LEN + BLK_STR_LEN + 16) /* Since PropFieldsGap is at most 2, we need at most two characters per field, * except the last one, totaling 14 bytes, leaving enough room for the NUL * terminating character as well. */ /* Macros to calculate relative timestamps (used by calc_relative_time()) */ #define RT_SECOND 1 #define RT_MINUTE (time_t)(60 * RT_SECOND) #define RT_HOUR (time_t)(60 * RT_MINUTE) #define RT_DAY (time_t)(24 * RT_HOUR) #define RT_WEEK (time_t)(7 * RT_DAY) #define RT_MONTH (time_t)(30 * RT_DAY) #define RT_YEAR (time_t)(365 * RT_DAY) __BEGIN_DECLS int print_entry_props(const struct fileinfo *props, const struct maxes_t *maxes, const int have_xattr); __END_DECLS #endif /* LONG_VIEW_H */ clifm-1.26.3/src/main.c000066400000000000000000001051671506632037700145770ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* main.c -- Main file for Clifm */ #include "helpers.h" #include #include /* nl_langinfo() */ #include #include #include #include #include "args.h" #include "aux.h" #include "checks.h" #include "config.h" #include "exec.h" #include "history.h" #include "init.h" #include "jump.h" #include "keybinds.h" #include "listing.h" #include "mimetypes.h" /* load_user_mimetypes() */ #include "misc.h" #ifndef _NO_PROFILES # include "profiles.h" #endif /* !_NO_PROFILES */ #include "prompt.h" #include "properties.h" /* do_stat_and_exit() */ #include "readline.h" #include "remotes.h" #ifdef SECURITY_PARANOID # include "sanitize.h" #endif /* SECURITY_PARANOID */ #include "term.h" /* set_term_title() */ /* Globals */ struct usrvar_t *usr_var = (struct usrvar_t *)NULL; struct actions_t *usr_actions = (struct actions_t *)NULL; struct ws_t *workspaces = (struct ws_t *)NULL; struct kbinds_t *kbinds = (struct kbinds_t *)NULL; struct jump_t *jump_db = (struct jump_t *)NULL; struct bookmarks_t *bookmarks = (struct bookmarks_t *)NULL; struct fileinfo *file_info = (struct fileinfo *)NULL; struct remote_t *remotes = (struct remote_t *)NULL; struct alias_t *aliases = (struct alias_t *)NULL; struct user_t user = {0}; /* Store device and inode number of selected files */ struct devino_t *sel_devino = (struct devino_t *)NULL; #ifndef _NO_SUGGESTIONS struct suggestions_t suggestion = {0}; #endif /* !_NO_SUGGESTIONS */ struct stats_t stats = {0}; struct autocmds_t *autocmds = (struct autocmds_t *)NULL; struct opts_t opts = {0}; struct opts_t workspace_opts[MAX_WS]; struct sel_t *sel_elements = (struct sel_t *)NULL; struct prompts_t *prompts = (struct prompts_t *)NULL; struct history_t *history = (struct history_t *)NULL; struct msgs_t msgs = {0}; struct props_t prop_fields = {0}; struct termcaps_t term_caps = {0}; struct filter_t filter = {0}; struct config_t conf = {0}; struct shades_t date_shades = {0}; struct shades_t size_shades = {0}; struct paths_t *paths = (struct paths_t *)NULL; struct ext_t *ext_colors = (struct ext_t *)NULL; #ifdef LINUX_FSINFO struct ext_mnt_t *ext_mnt = (struct ext_mnt_t *)NULL; #endif /* LINUX_FSINFO */ struct groups_t *sys_users = (struct groups_t *)NULL; struct groups_t *sys_groups = (struct groups_t *)NULL; struct dircmds_t dir_cmds = {UNSET, 0}; struct pmsgs_t *messages = (struct pmsgs_t *)NULL; struct mime_t *user_mimetypes = (struct mime_t *)NULL; const struct sort_t sort_methods[] = { {"none", 0, 0}, {"name", 1, 0}, {"size", 2, 0}, {"atime", 3, 0}, {"btime", 4, 0}, {"ctime", 5, 0}, {"mtime", 6, 0}, {"version", 7, 0}, {"extension", 8, 0}, {"inode", 9, 0}, {"owner", 10, 0}, {"group", 11, 0}, {"blocks", 12, 0}, {"links", 13, 0}, {"type", 14, 0}, {NULL, 15, 0}, }; /* pmsg holds the current program message type */ enum prog_msg pmsg = NOMSG; enum comp_type cur_comp_type = TCMP_NONE; enum tab_mode tabmode = STD_TAB; struct param_t xargs = {0}; unsigned short term_cols; double last_cmd_time = 0; /* Bit flag holders */ int flags = 0, bin_flags = 0, search_flags = 0; int date_shades_old_style = 0, size_shades_old_style = 0; pid_t own_pid = 0; time_t props_now = 0; unsigned short term_cols = 0, term_lines = 0; regex_t regex_exp; regex_t regex_hist; regex_t regex_dirhist; /* Internal status flags */ int alt_prompt = 0, argc_bk = 0, autocmd_set = 0, bg_proc = 0, cmdhist_flag = 0, config_ok = 1, cur_ws = UNSET, curcol = 0, dequoted = 0, dir_changed = 0, dirhist_cur_index = 0, dirhist_total_index = 0, exit_code = 0, fzftab = UNSET, fzf_ext_border = UNSET, fzf_border_type = UNSET, fzf_height_value = 0, fzf_preview_border_type = 0, hist_status = UNSET, home_ok = 1, internal_cmd = 0, is_sel = 0, is_cdpath = 0, jump_total_rank = 0, kbind_busy = 0, nesting_level = 0, no_log = 0, open_in_foreground = 0, prev_ws = UNSET, print_msg = 0, print_removed_files = UNSET, prompt_offset = UNSET, prompt_notif = UNSET, recur_perm_error_flag = 0, rl_nohist = 0, rl_notab = 0, sel_is_last = 0, selfile_ok = 1, shell = SHELL_NONE, shell_is_interactive = 0, shell_terminal = 0, sort_switch = 0, switch_cscheme = 0, #ifndef _NO_TRASH trash_ok = 1, #endif /* !_NO_TRASH */ virtual_dir = 0, wrong_cmd = 0; filesn_t files = 0; size_t actions_n = 0, aliases_n = 0, args_n = 0, autocmds_n = 0, bm_n = 0, cdpath_n = 0, config_dir_len = 0, cschemes_n = 0, current_hist_n = 0, curhistindex = 0, ext_colors_n = 0, jump_n = 0, kbinds_n = 0, msgs_n = 0, P_tmpdir_len = 0, path_n = 0, path_progsn = 0, prompt_cmds_n = 0, prompts_n = 0, remotes_n = 0, sel_n = 0, tab_offset = 0, tags_n = 0, trash_n = 0, usrvar_n = 0, words_num = 0, zombies = 0; #if !defined(_NO_ICONS) size_t *name_icons_hashes = (size_t *)0; size_t *dir_icons_hashes = (size_t *)0; size_t *ext_icons_hashes = (size_t *)0; #endif /* !_NO_ICONS */ char cur_prompt_name[NAME_MAX + 1] = "", div_line[NAME_MAX + 1], hostname[HOST_NAME_MAX + 1], fz_match[PATH_MAX + 1], prop_fields_str[PROP_FIELDS_SIZE + 1] = "", invalid_time_str[MAX_TIME_STR] = "", #ifdef RUN_CMD *cmd_line_cmd = (char *)NULL, #endif /* RUN_CMD */ *actions_file = (char *)NULL, *alt_bm_file = (char *)NULL, *alt_config_dir = (char *)NULL, *alt_trash_dir = (char *)NULL, *alt_config_file = (char *)NULL, *alt_kbinds_file = (char *)NULL, *alt_mimelist_file = (char *)NULL, *alt_preview_file = (char *)NULL, *alt_profile = (char *)NULL, *bm_file = (char *)NULL, *cmds_log_file = (char *)NULL, *colors_dir = (char *)NULL, *config_dir = (char *)NULL, *config_dir_gral = (char *)NULL, *config_file = (char *)NULL, *cur_color = (char *)NULL, *cur_tag = (char *)NULL, *data_dir = (char *)NULL, *cur_cscheme = (char *)NULL, *dirhist_file = (char *)NULL, *file_cmd_path = (char *)NULL, *hist_file = (char *)NULL, *jump_suggestion = (char *)NULL, *kbinds_file = (char *)NULL, *last_cmd = (char *)NULL, *mime_file = (char *)NULL, *msgs_log_file = (char *)NULL, *pinned_dir = (char *)NULL, *plugins_dir = (char *)NULL, *plugins_helper_file = (char *)NULL, *profile_file = (char *)NULL, *prompts_file = (char *)NULL, *quote_chars = (char *)NULL, *rl_callback_handler_input = (char *)NULL, *remotes_file = (char *)NULL, *sel_file = (char *)NULL, *smenutab_options_env = (char *)NULL, *stdin_tmp_dir = (char *)NULL, *sudo_cmd = (char *)NULL, #ifndef _NO_SUGGESTIONS *suggestion_buf = (char *)NULL, #endif /* !_NO_SUGGESTIONS */ *sys_shell = (char *)NULL, *tags_dir = (char *)NULL, *templates_dir = (char *)NULL, *thumbnails_dir = (char *)NULL, *tmp_rootdir = (char *)NULL, *tmp_dir = (char *)NULL, #ifndef _NO_TRASH *trash_dir = (char *)NULL, *trash_files_dir = (char *)NULL, *trash_info_dir = (char *)NULL, #endif /* !_NO_TRASH */ **argv_bk = (char **)NULL, **bin_commands = (char **)NULL, **cdpaths = (char **)NULL, **color_schemes = (char **)NULL, **file_templates = (char **)NULL, **old_pwd = (char **)NULL, **profile_names = (char **)NULL, **prompt_cmds = (char **)NULL, **tags = (char **)NULL; /* Colors */ char /* File types */ bd_c[MAX_COLOR], /* Block device */ bk_c[MAX_COLOR], /* Backup/temp files */ ca_c[MAX_COLOR], /* Cap file */ cd_c[MAX_COLOR], /* Char device */ di_c[MAX_COLOR], /* Directory */ ed_c[MAX_COLOR], /* Empty dir */ ee_c[MAX_COLOR], /* Empty executable */ ef_c[MAX_COLOR], /* Empty reg file */ ex_c[MAX_COLOR], /* Executable */ fi_c[MAX_COLOR], /* Reg file */ ln_c[MAX_COLOR], /* Symlink */ mh_c[MAX_COLOR], /* Multi-hardlink file */ nd_c[MAX_COLOR], /* No read directory */ nf_c[MAX_COLOR], /* No read file */ no_c[MAX_COLOR], /* Unknown */ #ifdef SOLARIS_DOORS oo_c[MAX_COLOR], /* Solaris door/port */ #endif /* SOLARIS_DOORS */ or_c[MAX_COLOR], /* Broken symlink */ ow_c[MAX_COLOR], /* Other writable */ pi_c[MAX_COLOR], /* FIFO, pipe */ sg_c[MAX_COLOR], /* SGID file */ so_c[MAX_COLOR], /* Socket */ st_c[MAX_COLOR], /* Sticky (not ow)*/ su_c[MAX_COLOR], /* SUID file */ tw_c[MAX_COLOR], /* Sticky other writable */ uf_c[MAX_COLOR], /* Non-'stat'able file */ /* Interface */ ac_c[MAX_COLOR + 2], /* Autocmd indicator */ df_c[MAX_COLOR], /* Default color */ dl_c[MAX_COLOR], /* Dividing line index */ el_c[MAX_COLOR], /* ELN */ fc_c[MAX_COLOR], /* File counter */ lc_c[MAX_COLOR], /* Symlink character (ColorLinkAsTarget only) */ mi_c[MAX_COLOR], /* Misc indicators */ ts_c[MAX_COLOR], /* Tab completion suffix */ wc_c[MAX_COLOR], /* Welcome message color */ wp_c[MAX_COLOR], /* Warning prompt */ tt_c[MAX_COLOR], /* Character to mark truncated filenames */ /* Suggestions */ sb_c[MAX_COLOR], /* Auto-suggestions: shell builtins */ sc_c[MAX_COLOR], /* Auto-suggestions: external commands */ sd_c[MAX_COLOR], /* Auto-suggestions: internal commands description */ sh_c[MAX_COLOR], /* Auto-suggestions: history */ sf_c[MAX_COLOR], /* Auto-suggestions: filenames */ sx_c[MAX_COLOR], /* Auto-suggestions: internal commands and params */ sp_c[MAX_COLOR], /* Auto-suggestions: suggestions pointer */ sz_c[MAX_COLOR], /* Auto-suggestions: filenames (fuzzy) */ #ifndef _NO_ICONS dir_ico_c[MAX_COLOR], /* Directories icon color */ #endif /* !_NO_ICONS */ /* Syntax highlighting */ hb_c[MAX_COLOR], /* Brackets: () [] {} */ hc_c[MAX_COLOR], /* Comments */ hd_c[MAX_COLOR], /* Paths (slashes) */ he_c[MAX_COLOR], /* Expansion operators: * ~ */ hn_c[MAX_COLOR], /* Numbers */ hp_c[MAX_COLOR], /* Parameters: - */ hq_c[MAX_COLOR], /* Quoted strings */ hr_c[MAX_COLOR], /* Redirection: > */ hs_c[MAX_COLOR], /* Process separators: | & ; */ hv_c[MAX_COLOR], /* Variables: $ */ hw_c[MAX_COLOR], /* Backslash (aka whack) */ db_c[MAX_COLOR], /* File allocated blocks */ dd_c[MAX_COLOR], /* Date (fixed color: no shading) */ de_c[MAX_COLOR], /* Inode number */ dg_c[MAX_COLOR], /* Group ID */ dk_c[MAX_COLOR], /* Number of links */ dn_c[MAX_COLOR], /* dash (none) */ do_c[MAX_COLOR], /* Octal perms */ dp_c[MAX_COLOR], /* Special files (SUID, SGID, etc) */ dr_c[MAX_COLOR], /* Read */ dt_c[MAX_COLOR], /* Timestamp mark */ du_c[MAX_COLOR], /* User ID */ dw_c[MAX_COLOR], /* Write */ dxd_c[MAX_COLOR], /* Execute (dirs) */ dxr_c[MAX_COLOR], /* Execute (reg files) */ dz_c[MAX_COLOR], /* Size (dirs) */ /* Colors used in the prompt, so that \001 and \002 needs to * be added. This is why MAX_COLOR + 2 */ /* Workspaces */ ws1_c[MAX_COLOR + 2], ws2_c[MAX_COLOR + 2], ws3_c[MAX_COLOR + 2], ws4_c[MAX_COLOR + 2], ws5_c[MAX_COLOR + 2], ws6_c[MAX_COLOR + 2], ws7_c[MAX_COLOR + 2], ws8_c[MAX_COLOR + 2], em_c[MAX_COLOR + 2], /* Error msg color */ li_c[MAX_COLOR + 2], /* Sel indicator color */ li_cb[MAX_COLOR], /* Sel indicator color (for the file list) */ nm_c[MAX_COLOR + 2], /* Notice msg color */ wm_c[MAX_COLOR + 2], /* Warning msg color */ ro_c[MAX_COLOR + 2], /* read-only indicator color */ si_c[MAX_COLOR + 2], /* stealth-mode indicator color */ ti_c[MAX_COLOR + 2], /* Trash indicator color */ tx_c[MAX_COLOR + 2], /* Text color */ xs_c[MAX_COLOR + 2], /* Exit code: success */ xs_cb[MAX_COLOR], /* Exit code: success (Unicode success indicator) */ xf_c[MAX_COLOR + 2], /* Exit code: failure */ xf_cb[MAX_COLOR], /* Exit code: failure (dir read) */ tmp_color[MAX_COLOR + 2], /* A temp buffer to store color codes */ dim_c[] = "\x1b[2m"; /* A buffer to store filenames to be displayed (wide string) */ char name_buf[NAME_BUF_SIZE * sizeof(wchar_t)]; /* A list of all internal commands, including command name, name length, * and parameter type (as a bit flag). Used by is_internal_cmd(), in checks.c. */ const struct cmdslist_t internal_cmds[] = { {",", 1, NO_PARAM, 0}, {"?", 1, NO_PARAM, 0}, {"help", 4, NO_PARAM, 0}, {"ac", 2, PARAM_FNAME, 0}, {"ad", 2, PARAM_FNAME, 0}, {"acd", 3, PARAM_STR, 0}, {"auto", 4, PARAM_STR, 0}, {"autocd", 6, PARAM_STR, 0}, {"actions", 7, PARAM_STR, 0}, {"alias", 5, PARAM_FNAME, 0}, // diff (old 0110, new 1110) // 'alias import' takes filenames {"ao", 2, PARAM_STR, 0}, {"auto-open", 9, PARAM_STR, 0}, {"b", 1, PARAM_STR, 0}, {"back", 4, PARAM_STR, 0}, {"bb", 2, PARAM_FNAME, 0}, {"bleach", 6, PARAM_FNAME, 0}, {"bd", 2, PARAM_STR, 0}, {"dh", 2, PARAM_FNAME, 0}, // diff (old 0110, new 1110) {"bl", 2, PARAM_FNAME, 0}, {"bm", 2, PARAM_FNAME, 0}, {"bookmarks", 9, PARAM_FNAME, 0}, {"br", 2, PARAM_FNAME, 0}, {"bulk", 4, PARAM_FNAME, 0}, {"c", 1, PARAM_FNAME, 0}, //"cp", {"colors", 6, NO_PARAM, 0}, {"cd", 2, PARAM_FNAME, 0}, {"cl", 2, PARAM_STR, 0}, {"columns", 7, PARAM_STR, 0}, {"cmd", 3, NO_PARAM, 0}, {"commands", 8, NO_PARAM, 0}, {"cs", 2, PARAM_STR, 0}, {"colorschemes", 12, PARAM_STR, 0}, {"cwd", 3, NO_PARAM, 0}, // deprecate this one, just as 'path' {"d", 1, PARAM_FNAME, 0}, {"dup", 3, PARAM_FNAME, 0}, {"ds", 2, PARAM_FNAME, 0}, // diff (old 0110, new 1110) {"desel", 5, PARAM_FNAME, 0}, // diff (old 0110, new 1110) {"config", 6, PARAM_STR, 0}, {"exp", 3, PARAM_FNAME, 0}, {"export", 6, PARAM_FNAME | PARAM_STR, 0}, // diff (old 1101, new 1111) {"ext", 3, PARAM_STR, 0}, {"f", 1, PARAM_STR, 0}, {"forth", 5, PARAM_STR, 0}, {"fc", 2, PARAM_STR, 0}, {"ff", 2, PARAM_STR, 0}, {"dirs-first", 10, PARAM_STR, 0}, {"ft", 2, PARAM_STR, 0}, {"filter", 6, PARAM_STR, 0}, {"fz", 2, PARAM_STR, 0}, {"hh", 2, PARAM_STR, 0}, {"hf", 2, PARAM_STR, 0}, {"hidden", 6, PARAM_STR, 0}, {"history", 7, PARAM_STR, 0}, {"icons", 5, PARAM_STR, 0}, {"j", 1, PARAM_STR, 0}, {"jump", 4, PARAM_STR, 0}, {"je", 2, PARAM_STR, 0}, {"jc", 2, PARAM_STR, 0}, // diff (old 1101, new 0101) {"jl", 2, PARAM_STR, 0}, {"jp", 2, PARAM_STR, 0}, // diff (old 1101, new 0101) {"k", 1, NO_PARAM, 0}, {"kk", 2, NO_PARAM, 0}, {"kb", 2, PARAM_STR, 0}, {"keybinds", 8, PARAM_STR, 0}, {"l", 1, PARAM_FNAME, 0}, {"le", 2, PARAM_FNAME, 0}, {"lm", 2, PARAM_STR, 0}, {"log", 3, PARAM_STR, 0}, {"ll", 2, PARAM_STR, 0}, {"lv", 2, PARAM_STR, 0}, {"m", 1, PARAM_FNAME, 0}, {"md", 2, PARAM_FNAME, 0}, // diff (old 0110, 1110) {"media", 5, NO_PARAM, 0}, {"mf", 2, PARAM_NUM, 0}, {"mm", 2, PARAM_FNAME, 0}, {"mime", 4, PARAM_FNAME, 0}, {"mp", 2, NO_PARAM, 0}, {"mountpoints", 11, NO_PARAM, 0}, {"msg", 3, PARAM_STR, 0}, {"messages", 8, PARAM_STR, 0}, {"n", 1, PARAM_FNAME, 0}, {"new", 3, PARAM_FNAME, 0}, {"net", 3, PARAM_STR, 0}, {"o", 1, PARAM_FNAME, 0}, {"oc", 2, PARAM_FNAME, 0}, {"open", 4, PARAM_FNAME, 0}, {"ow", 2, PARAM_FNAME, 0}, // diff (old 0110, new 1110) {"opener", 6, PARAM_STR, 0}, {"p", 1, PARAM_FNAME, 0}, {"pc", 2, PARAM_FNAME, 0}, {"pp", 2, PARAM_FNAME, 0}, {"pr", 2, PARAM_FNAME, 0}, {"prop", 4, PARAM_FNAME, 0}, {"path", 4, NO_PARAM, 0}, // deprecate this one, just as 'cwd' {"paste", 5, PARAM_FNAME, 0}, {"pf", 2, PARAM_STR, 0}, {"prof", 4, PARAM_STR, 0}, {"profile", 7, PARAM_STR, 0}, {"pg", 2, PARAM_STR, 0}, {"pager", 5, PARAM_STR, 0}, {"pin", 3, PARAM_FNAME, 0}, {"unpin", 5, NO_PARAM, 0}, {"prompt", 6, PARAM_STR, 0}, {"pwd", 3, PARAM_STR, 0}, {"q", 1, NO_PARAM, 0}, {"quit", 4, NO_PARAM, 0}, {"exit", 4, NO_PARAM, 0}, {"r", 1, PARAM_FNAME, 0}, //"rm", {"rf", 2, NO_PARAM, 0}, {"refresh", 7, NO_PARAM, 0}, {"rl", 2, NO_PARAM, 0}, {"reload", 6, NO_PARAM, 0}, {"rr", 2, PARAM_FNAME, 0}, {"s", 1, PARAM_FNAME, 0}, {"sel", 3, PARAM_FNAME, 0}, {"sb", 2, NO_PARAM, 0}, {"selbox", 6, NO_PARAM, 0}, {"st", 2, PARAM_NUM, 0}, {"sort", 4, PARAM_NUM, 0}, {"stats", 5, NO_PARAM, 0}, {"t", 1, PARAM_FNAME, 0}, {"tr", 2, PARAM_FNAME, 0}, {"trash", 5, PARAM_FNAME, 0}, {"tag", 3, PARAM_FNAME, 0}, {"ta", 2, PARAM_FNAME, 0}, {"td", 2, PARAM_STR, 0}, {"tl", 2, PARAM_STR, 0}, // diff (old 0110, new 0101) {"tm", 2, PARAM_STR, 0}, {"tn", 2, PARAM_STR, 0}, {"tu", 2, PARAM_STR, 0}, {"ty", 2, PARAM_STR, 0}, {"te", 2, PARAM_FNAME, 0}, {"tips", 4, NO_PARAM, 0}, {"u", 1, PARAM_STR, 0}, {"undel", 5, PARAM_STR, 0}, {"unset", 5, PARAM_STR, 0}, {"untrash", 7, PARAM_STR, 0}, {"umask", 5, PARAM_STR, 0}, {"vv", 2, PARAM_FNAME, 0}, {"ver", 3, NO_PARAM, 0}, {"version", 7, NO_PARAM, 0}, {"view", 4, PARAM_STR, 0}, {"ws", 2, PARAM_NUM, 0}, {"x", 1, PARAM_FNAME, 0}, // diff (old 0110, new 1110) {"X", 1, PARAM_FNAME, 0}, // diff (old 0110, new 1110) {NULL, 0, 0, 0} }; size_t internal_cmds_n = 0; /* A list of internal commands and fixed parameters for the auto-suggestions * system. */ const struct nameslist_t param_str[] = { {"actions edit", 12}, {"actions list", 12}, {"auto unset", 10}, {"auto list", 9}, {"auto none", 9}, {"autocd on", 9}, {"acd on", 6}, {"autocd off", 10}, {"acd off", 7}, {"autocd status", 13}, {"acd status", 10}, {"alias import", 12}, {"alias list", 10}, {"ao on", 5}, {"auto-open on", 12}, {"ao off", 6}, {"auto-open off", 13}, {"ao status", 9}, {"auto-open status", 16}, {"b hist", 6}, {"b clear", 7}, {"back hist", 9}, {"back clear", 10}, {"bm add", 6}, {"bm del", 6}, {"bm edit", 7}, {"bookmarks add", 13}, {"bookmarks del", 13}, {"bookmarks edit", 14}, {"c -f", 4}, {"c --force", 9}, {"cs check-ext", 12}, {"colorschemes check-ext", 22}, {"colorschemes edit", 17}, {"cs edit", 7}, {"colorschemes preview", 20}, {"cs preview", 10}, {"desel all", 9}, {"ds all", 6}, {"config", 6}, {"config edit", 11}, {"config dump", 11}, {"config reload", 13}, {"config reset", 12}, {"ext on", 6}, {"ext off", 7}, {"ext status", 10}, {"f hist", 6}, {"f clear", 7}, {"forth hist", 10}, {"forth clear", 11}, {"fc on", 5}, {"fc off", 6}, {"fc status", 9}, {"ff on", 5}, {"dirs-first on", 13}, {"ff off", 6}, {"dirs-first off", 14}, {"ff status", 9}, {"dirs-first status", 17}, {"ft unset", 8}, {"filter unset", 12}, {"fz on", 5}, {"fz off", 6}, {"help archives", 13}, {"help autocommands", 17}, {"help basics", 11}, {"help bookmarks", 14}, {"help commands", 13}, {"help desktop-notifications", 26}, {"help dir-jumper", 15}, {"help file-details", 17}, {"help file-filters", 17}, {"help file-previews", 18}, {"help image-previews", 19}, {"help file-tags", 14}, {"help navigation", 15}, {"help plugins", 12}, {"help profiles", 13}, {"help remotes", 12}, {"help resource-opener", 20}, {"help search", 11}, {"help security", 13}, {"help selection", 14}, {"help theming", 12}, {"help trash", 10}, {"hf on", 5}, {"hf off", 6}, {"hf first", 8}, {"hf last", 7}, {"hf status", 9}, {"hh on", 5}, {"hh off", 6}, {"hh status", 9}, {"hh last", 7}, {"hh status", 9}, {"hidden on", 9}, {"hidden off", 10}, {"hidden status", 13}, {"hidden last", 11}, {"hidden first", 12}, {"history clear", 13}, {"history edit", 12}, {"history on", 10}, {"history off", 11}, {"history status", 14}, {"history show-time", 17}, {"icons on", 8}, {"icons off", 9}, {"j --purge", 9}, {"j --edit", 8}, {"kb bind", 7}, {"keybinds bind", 13}, {"kb conflict", 11}, {"keybinds conflict", 17}, {"kb edit", 7}, {"keybinds edit", 13}, {"kb list", 7}, {"keybinds list", 13}, {"kb reset", 8}, {"keybinds reset", 14}, {"kb readline", 11}, {"keybinds readline", 17}, {"l edit", 6}, {"lm on", 5}, {"lm off", 6}, {"ll on", 5}, {"ll off", 6}, {"lv on", 5}, {"lv off", 6}, {"log cmd list", 12}, {"log cmd on", 10}, {"log cmd off", 11}, {"log cmd status", 14}, {"log cmd clear", 13}, {"log msg list", 12}, {"log msg on", 10}, {"log msg off", 11}, {"log msg status", 14}, {"log msg clear", 13}, {"m -f", 4}, {"m --force", 9}, {"mf unset", 8}, {"mm info", 7}, {"mm edit", 7}, {"mm import", 9}, {"mime info", 9}, {"mime edit", 9}, {"mime import", 11}, {"msg clear", 9}, {"messages clear", 14}, {"net list", 8}, {"net edit", 8}, {"net mount", 9}, {"net unmount", 11}, {"opener default", 14}, {"pg on", 5}, {"pager on", 8}, {"pg off", 6}, {"pager off", 9}, {"pg once", 7}, {"pager once", 10}, {"pg status", 9}, {"pager status", 12}, {"pf set", 6}, {"pf add", 6}, {"pf del", 6}, {"pf list", 7}, {"pf rename", 9}, {"profile set", 11}, {"profile add", 11}, {"profile del", 11}, {"profile list", 12}, {"profile rename", 14}, {"prompt edit", 11}, {"prompt list", 11}, {"prompt reload", 13}, {"prompt set", 10}, {"prompt unset", 12}, {"r -f", 4}, {"r --force", 9}, {"st none", 7}, {"st name", 7}, {"st size", 7}, {"st blocks", 9}, {"st links", 8}, {"st atime", 8}, {"st btime", 8}, {"st ctime", 8}, {"st mtime", 8}, {"st owner", 8}, {"st group", 8}, {"st extension", 12}, {"st inode", 8}, {"st version", 10}, {"st type", 7}, {"sort none", 9}, {"sort name", 9}, {"sort blocks", 11}, {"sort size", 9}, {"sort links", 10}, {"sort atime", 10}, {"sort btime", 10}, {"sort ctime", 10}, {"sort mtime", 10}, {"sort owner", 10}, {"sort group", 10}, {"sort extension", 14}, {"sort inode", 10}, {"sort version", 12}, {"sort type", 9}, {"st rev", 6}, {"sort rev", 8}, {"t list", 6}, {"t clear", 7}, {"t empty", 7}, {"t del", 5}, {"trash list", 10}, {"trash clear", 11}, {"trash empty", 11}, {"trash del", 9}, {"tag add", 7}, {"tag del", 7}, {"tag list", 8}, {"tag list-full", 13}, {"tag merge", 9}, {"tag new", 7}, {"tag rename", 10}, {"tag untag", 9}, {"u all", 5}, {"undel all", 9}, {"untrash all", 11}, {"view edit", 9}, {"view purge", 10}, {NULL, 0} }; const struct nameslist_t kb_cmds[] = { {"archive-sel", 11}, {"bookmarks", 9}, {"cmd-hist", 8}, {"clear-line", 10}, {"clear-msgs", 10}, {"create-file", 11}, {"deselect-all", 12}, {"dirs-first", 10}, {"edit-color-scheme", 17}, {"export-sel", 10}, {"home-dir", 8}, {"launch-view", 11}, {"lock", 4}, {"mountpoints", 11}, {"move-sel", 8}, {"new-instance", 12}, {"next-dir", 8}, {"next-profile", 12}, {"only-dirs", 9}, {"open-bookmarks", 14}, {"open-config", 11}, {"open-jump-db", 12}, {"open-keybinds", 13}, {"open-mime", 9}, {"open-preview", 12}, {"open-sel", 8}, {"parent-dir", 10}, {"pinned-dir", 10}, {"plugin1", 7}, {"plugin2", 7}, {"plugin3", 7}, {"plugin4", 7}, {"plugin5", 7}, {"plugin6", 7}, {"plugin7", 7}, {"plugin8", 7}, {"plugin9", 7}, {"plugin10", 8}, {"plugin11", 8}, {"plugin12", 8}, {"plugin13", 8}, {"plugin14", 8}, {"plugin15", 8}, {"plugin16", 8}, {"paste-sel", 10}, {"prepend-sudo", 12}, {"previous-dir", 12}, {"previous-profile", 16}, {"quit", 4}, {"refresh-screen", 14}, {"remove-sel", 10}, {"rename-sel", 10}, {"root-dir", 8}, {"run-pager", 9}, {"selbox", 6}, {"select-all", 10}, {"show-dirhist", 12}, {"sort-previous", 13}, {"sort-next", 9}, {"show-manpage", 12}, {"show-cmds", 9}, {"show-kbinds", 11}, {"toggle-disk-usage", 17}, {"toggle-follow-links-long", 24}, {"toggle-hidden", 13}, {"toggle-light", 12}, {"toggle-long", 11}, {"toggle-max-name-len", 19}, {"toggle-virtualdir-full-paths", 28}, {"trash-sel", 9}, {"untrash-sel", 11}, {"workspace1", 10}, {"workspace2", 10}, {"workspace3", 10}, {"workspace4", 10}, {NULL, 0} }; #if defined(LINUX_INOTIFY) int inotify_fd = UNSET, inotify_wd = UNSET; int watch = UNSET; unsigned int INOTIFY_MASK = IN_CREATE | IN_DELETE | IN_DELETE_SELF | IN_MOVE | IN_MOVE_SELF # if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 15) | IN_DONT_FOLLOW | IN_ONLYDIR # endif /* LINUX >= 2.6.15 */ # if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36) | IN_EXCL_UNLINK # endif /* LINUX >= 2.6.36 */ ; #elif defined(BSD_KQUEUE) int kq, event_fd = UNSET; int watch = UNSET; struct kevent events_to_monitor[NUM_EVENT_FDS]; unsigned int KQUEUE_FFLAGS = NOTE_DELETE | NOTE_EXTEND | NOTE_LINK | NOTE_RENAME | NOTE_REVOKE | NOTE_WRITE; struct timespec timeout; #elif defined(GENERIC_FS_MONITOR) time_t curdir_mtime = 0; #endif /* LINUX_INOTIFY */ #ifdef RUN_CMD # ifndef _NO_TRASH static inline void init_trash(void) { if (trash_ok == 1) { const filesn_t ret = count_dir(trash_files_dir, NO_CPOP); trash_n = ret <= 2 ? 0 : (size_t)ret - 2; } } # endif /* _NO_TRASH */ /* Run the command passed via --cmd and exit */ static void run_and_exit(void) { # ifndef _NO_TRASH init_trash(); # endif /* !_NO_TRASH */ /* 1) Parse input string. */ int i = 0; char **cmd = parse_input_str(cmd_line_cmd); if (!cmd) exit(EXIT_FAILURE); /* 2) Execute input string. */ char **alias_cmd = check_for_alias(cmd); if (alias_cmd) { /* If an alias is found, check_for_alias() frees CMD and returns * ALIAS_CMD in its place to be executed by exec_cmd_tm(). */ exec_cmd_tm(alias_cmd); for (i = 0; alias_cmd[i]; i++) free(alias_cmd[i]); free(alias_cmd); exit(exit_code); } if (!(flags & FAILED_ALIAS)) exec_cmd_tm(cmd); flags &= ~FAILED_ALIAS; for (i = 0; cmd[i]; i++) free(cmd[i]); free(cmd); UNHIDE_CURSOR; exit(exit_code); } #endif /* RUN_CMD */ /* This is the main structure of a basic shell (a REPL) 1 - Grab user input 2 - Parse user input 3 - Execute command 4 - Grab user input again See https://brennan.io/2015/01/16/write-a-shell-in-c/ */ __attribute__ ((noreturn)) static void run_main_loop(void) { #ifdef RUN_CMD if (cmd_line_cmd != NULL) run_and_exit(); /* No return */ #endif /* RUN_CMD */ int i; /* 1) Infinite loop to keep the program running. */ while (1) { /* 2) Grab the input string from the command prompt. */ char *input = prompt(PROMPT_SHOW, PROMPT_SCREEN_REFRESH); if (!input) continue; /* 3) Parse the input string. */ char **cmd = parse_input_str(input); free(input); if (!cmd) continue; /* 4) Execute the command. */ char **alias_cmd = check_for_alias(cmd); if (alias_cmd) { /* If an alias is found, check_for_alias() frees CMD and returns * ALIAS_CMD in its place to be executed by exec_cmd_tm(). */ exec_cmd_tm(alias_cmd); for (i = 0; alias_cmd[i]; i++) free(alias_cmd[i]); free(alias_cmd); continue; } if (!(flags & FAILED_ALIAS)) exec_cmd_tm(cmd); flags &= ~FAILED_ALIAS; i = (int)args_n + 1; while (--i >= 0) free(cmd[i]); free(cmd); } } static inline void set_root_indicator(void) { if (user.uid == 0) { const char *bold_red = conf.colorize == 1 ? "\x1b[1;31m" : ""; err(ERR_NO_LOG, PRINT_PROMPT, _("%s%s%s Running as root%s\n"), conf.colorize == 1 ? mi_c : "", SET_MSG_PTR, bold_red, conf.colorize == 1 ? df_c : ""); } } static inline void list_files(void) { #ifdef RUN_CMD if (cmd_line_cmd != NULL) return; #endif /* RUN_CMD */ if (conf.autols == 1 && isatty(STDIN_FILENO)) { if (xargs.list_and_quit == 1) goto LIST; #ifdef LINUX_INOTIFY /* Initialize inotify */ inotify_fd = inotify_init1(IN_NONBLOCK); if (inotify_fd < 0) { err('w', PRINT_PROMPT, "%s: inotify: %s\n", PROGRAM_NAME, strerror(errno)); } #elif defined(BSD_KQUEUE) kq = kqueue(); if (kq < 0) { err('w', PRINT_PROMPT, "%s: kqueue: %s\n", PROGRAM_NAME, strerror(errno)); } #endif /* LINUX_INOTIFY */ LIST: if (conf.colorize == 1 && xargs.eln_use_workspace_color == 1) set_eln_color(); list_dir(); } } static inline void print_splash_screen(void) { if (conf.splash_screen == 1) { splash(); conf.splash_screen = 0; CLEAR; } } /* Set terminal window title */ static inline void set_term_win_title(void) { if ((flags & GUI) && xargs.list_and_quit != 1 && xargs.vt100 != 1) set_term_title(xargs.cwd_in_title == 1 ? workspaces[cur_ws].path : (char *)NULL); } static inline void check_working_directory(void) { if (workspaces == (struct ws_t *)NULL || !workspaces[cur_ws].path || !*workspaces[cur_ws].path) { err(0, NOPRINT_PROMPT, _("%s: Fatal error! Failure " "retrieving the current working directory\n"), PROGRAM_NAME); exit(EXIT_FAILURE); } } static inline void get_hostname(void) { if (gethostname(hostname, sizeof(hostname)) == -1) { hostname[0] = UNKNOWN_CHR; hostname[1] = '\0'; err('e', PRINT_PROMPT, _("%s: Error getting hostname\n"), PROGRAM_NAME); } } /* Initialize the file filter struct */ static inline void init_filter(void) { filter.str = (char *)NULL; filter.rev = 0; filter.env = 0; filter.type = FILTER_NONE; } /* Initialize the msgs struct */ static inline void init_msgs(void) { msgs.error = msgs.notice = msgs.warning = 0; } static inline void set_locale(void) { /* Use the locale specified by the environment */ setlocale(LC_ALL, ""); if (strcmp(nl_langinfo(CODESET), "UTF-8") != 0) { err('w', PRINT_PROMPT, _("%s: Locale is not UTF-8. To avoid " "encoding issues you might want to set an UTF-8 locale. For " "example: 'export LANG=es_AR.UTF-8'.\n"), PROGRAM_NAME); } } static inline void check_gui(void) { /* Running on a graphical environment? */ #if !defined(__HAIKU__) && !defined(__CYGWIN__) if (getenv("DISPLAY") || getenv("WAYLAND_DISPLAY")) #endif /* !__HAIKU__ && !__CYGWIN__ */ { flags |= GUI; } } #ifdef SECURITY_PARANOID static void set_security_paranoid_mode(void) { # if SECURITY_PARANOID <= 0 return; # elif SECURITY_PARANOID == 1 if (xargs.secure_env != 1 && xargs.secure_env_full != 1) { xsecure_env(SECURE_ENV_IMPORT); xargs.secure_env = 1; } xargs.secure_cmds = 1; # else if (xargs.secure_env_full != 1) xsecure_env(SECURE_ENV_FULL); xargs.secure_cmds = xargs.secure_env_full = 1; xargs.secure_env = UNSET; # if SECURITY_PARANOID > 2 xargs.stealth_mode = 1; # endif /* SECURITY_PARANOID > 2 */ # endif /* SECURITY_PARANOID <= 0 */ } #endif /* SECURITY_PARANOID */ #ifdef HAVE_PLEDGE static inline void set_pledge(void) { if (pledge("stdio rpath wpath cpath dpath tmppath fattr " "chown flock getpw tty proc exec", NULL) == -1) { fprintf(stderr, "%s: pledge: %s\n", PROGRAM_NAME, strerror(errno)); exit(errno); } } #endif /* HAVE_PLEDGE */ __attribute__ ((noreturn)) static void list_files_and_quit(void) { if (conf.light_mode == 1) { if (conf.long_view == 1 && prop_fields.time == PROP_TIME_BIRTH) { fprintf(stderr, _("%s: PropFields: 'b': Birth time is not " "allowed in light mode\n"), PROGRAM_NAME); exit(EXIT_FAILURE); } const int s = conf.sort; if (s != SNONE && s != SNAME && s != SEXT && s != SVER && s != SINO) { fprintf(stderr, _("%s: Invalid sort value: only none, " "name, extension, version, and inode are allowed in " "light mode\n"), PROGRAM_NAME); exit(EXIT_FAILURE); } } if (xargs.full_dir_size == 1) tmp_dir = savestring(P_tmpdir, P_tmpdir_len); list_files(); exit(EXIT_SUCCESS); /* Never reached. */ } /** * ############################# * # MAIN # * ############################# * */ /* 1. Initialize stuff. * 2. Run the main program loop. */ int main(int argc, char *argv[]) { #ifdef HAVE_PLEDGE set_pledge(); #endif /* HAVE_PLEDGE */ /* Quite unlikely to happen, but one never knows. See * https://lwn.net/SubscriberLink/882799/cb8f313c57c6d8a6/ * and * https://stackoverflow.com/questions/49817316/can-argc-be-zero-on-a-posix-system */ if (argc == 0) { fprintf(stderr, "%s: %s\n", PROGRAM_NAME, strerror(EINVAL)); exit(EINVAL); } /* Make sure all initialization is made with restrictive permissions. */ const mode_t old_mask = umask(0077); /* flawfinder: ignore */ /* # 1. INITIALIZE EVERYTHING WE NEED # */ init_conf_struct(); init_filter(); init_msgs(); #ifndef _NO_ICONS init_icons_hashes(); #endif /* !_NO_ICONS */ set_locale(); /* Store external arguments to be able to rerun parse_cmdline_args() * in case the user edits the config file, in which case the program * must rerun init_config(), get_aliases(), get_prompt_cmds(), and * then parse_cmdline_args(). */ backup_argv(argc, argv); atexit(free_stuff); /* free_stuff does some cleaning. */ user = get_user_data(); get_home(); check_gui(); P_tmpdir_len = sizeof(P_tmpdir) - 1; init_workspaces(); /* Set all external arguments flags to uninitialized state. */ unset_xargs(); /* Manage external arguments. * Command line arguments will override initialization values (init_config). */ if (argc > 1) parse_cmdline_args(argc, argv); /* parse_cmdline_args is executed before init_config() because, if * specified (-P option), it sets the value of alt_profile, which * is then checked by init_config(). */ #ifdef SECURITY_PARANOID set_security_paranoid_mode(); #endif /* SECURITY_PARANOID */ check_term(); /* Let's check terminal capabilities. */ /* Get paths from PATH environment variable. These paths will be * used later by get_path_programs (for the autocomplete function) * and get_cmd_path(). */ path_n = get_path_env(1); cdpath_n = get_cdpath(); check_env_filter(); get_data_dir(); /* Initialize program paths and files, set options from the config * file, if they were not already set via external arguments, and * load sel elements, if any. All these configurations are made * per user basis. */ init_config(); check_options(); if (xargs.stat > 0) /* Running with --stat(-full). Print and exit. */ do_stat_and_exit(xargs.stat == FULL_STAT ? 1 : 0); if (xargs.list_and_quit == 1) list_files_and_quit(); /* No return. */ set_sel_file(); create_tmp_files(); load_actions(); get_aliases(); /* Get the list of available programs in PATH to be used by the * custom TAB-completion function (tab_complete(), in tabcomp.c). */ get_path_programs(); /* Check third-party programs availability: finders (fzf, fnf, smenu), * udevil, and udisks2. */ check_third_party_cmds(); #ifndef _NO_FZF check_completion_mode(); #endif /* _NO_FZF */ /* Initialize gettext() for translations. */ #ifndef _NO_GETTEXT init_gettext(); #endif /* !_NO_GETTEXT */ fputs(df_c, stdout); fflush(stdout); #ifndef __HAIKU__ /* No need for this warning on Haiku: it runs as root by default. */ set_root_indicator(); #endif /* !__HAIKU__ */ load_remotes(); automount_remotes(); print_splash_screen(); set_start_path(); check_working_directory(); set_term_win_title(); exec_profile(); load_dirhist(); add_to_dirhist(workspaces[cur_ws].path); get_sel_files(); /* Start listing as soon as possible to speed up startup time. */ list_files(); shell = get_sys_shell(); create_kbinds_file(); load_file_templates(); load_bookmarks(); load_keybinds(); load_tags(); load_jumpdb(); if (!jump_db || xargs.path == 1) add_to_jumpdb(workspaces[cur_ws].path); init_shell(); initialize_readline(); get_prompt_cmds(); get_hostname(); set_env(0); if (config_ok == 1) init_history(); /* Store history in an array to be able to manipulate it. */ get_history(); #ifndef _NO_PROFILES get_profile_names(); #endif /* !_NO_PROFILES */ load_pinned_dir(); init_workspaces_opts(); load_user_mimetypes(); /* Restore user umask */ umask(old_mask); /* flawfinder: ignore */ /* # 2. MAIN PROGRAM LOOP # */ run_main_loop(); } clifm-1.26.3/src/media.c000066400000000000000000000415511506632037700147260ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* media.c -- functions to manage local filesystems */ #ifndef NO_MEDIA_FUNC #include "helpers.h" #include #include #include #if defined(__linux__) || defined(__CYGWIN__) # include # define HAVE_PROC_MOUNTS # define DISK_LABELS_PATH "/dev/disk/by-label" # ifndef _PATH_MOUNTED # define _PATH_MOUNTED "/etc/mtab" # endif #elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) \ || defined(__DragonFly__) # include # include #elif defined(__APPLE__) # include # include # include #elif defined(__sun) # include /* getmntent() */ # ifndef MNTTAB # define MNTTAB "/etc/mnttab" # endif /* MNTTAB */ #endif /* __linux__ || __CYGWIN__ */ #include "aux.h" #include "colors.h" /* get_dir_color() */ #include "history.h" #include "jump.h" #include "listing.h" #include "misc.h" #include "navigation.h" #include "readline.h" #include "spawn.h" /* Information about devices */ struct mnt_t { char *mnt; /* Mountpoint */ char *dev; /* Device name (e.g.: /dev/sda1) */ char *label; /* Device label */ }; static struct mnt_t *media = (struct mnt_t *)NULL; static size_t mp_n = 0; #ifdef HAVE_PROC_MOUNTS static char ** get_block_devices(void) { struct dirent **blockdev = (struct dirent **)NULL; int block_n = scandir("/dev", &blockdev, NULL, alphasort); if (block_n == - 1) return (char **)NULL; char **bd = (char **)NULL; size_t i, n = 0; for (i = 0; (int)i < block_n; i++) { # ifndef _DIRENT_HAVE_D_TYPE char bpath[PATH_MAX + 1]; snprintf(bpath, sizeof(bpath), "/dev/%s", blockdev[i]->d_name); struct stat a; if (stat(bpath, &a) == -1) { free(blockdev[i]); continue; } if (!S_ISBLK(a.st_mode)) { # else if (blockdev[i]->d_type != DT_BLK) { # endif /* !_DIRENT_HAVE_D_TYPE */ free(blockdev[i]); continue; } char *name = blockdev[i]->d_name; /* Skip /dev/ram and /dev/loop devices */ if ((*name == 'l' && strncmp(name, "loop", 4) == 0) || (*name == 'r' && strncmp(name, "ram", 3) == 0)) { free(blockdev[i]); continue; } /* Get only partition names, normally ending with a number */ const size_t blen = strlen(name); if (blen > 0 && (name[blen - 1] < '1' || name[blen - 1] > '9')) { free(blockdev[i]); continue; } bd = xnrealloc(bd, n + 2, sizeof(char *)); bd[n] = xnmalloc(blen + 6, sizeof(char *)); snprintf(bd[n], blen + 6, "/dev/%s", name); n++; bd[n] = (char *)NULL; free(blockdev[i]); } free(blockdev); return bd; } static int unmount_dev(const size_t i, const int n) { if (xargs.mount_cmd == UNSET) { xerror(_("%s: No mount application found. Install either " "udevil or udisks2.\n"), PROGRAM_NAME); return FUNC_FAILURE; } if ((unsigned int)n + (unsigned int)1 < (unsigned int)1 || n + 1 > (int)i) { xerror(_("%s: %d: Invalid ELN\n"), PROGRAM_NAME, n + 1); return FUNC_FAILURE; } char *mnt = media[n].mnt; int exit_status = FUNC_SUCCESS; /* Get out of mountpoint before unmounting */ const size_t mlen = strlen(mnt); if (strncmp(mnt, workspaces[cur_ws].path, mlen) == 0) { char *cmd[] = {"b", NULL}; if (back_function(cmd) == FUNC_FAILURE) cd_function(NULL, CD_PRINT_ERROR); exit_status = (-1); } char *cmd[] = {xargs.mount_cmd == MNT_UDISKS2 ? "udisksctl" : "udevil", "unmount", "-b", media[n].dev, NULL}; if (launch_execv(cmd, FOREGROUND, E_NOFLAG) != FUNC_SUCCESS) exit_status = FUNC_FAILURE; if (exit_status != FUNC_FAILURE && xargs.mount_cmd == MNT_UDEVIL) printf(_("%s: Unmounted %s\n"), PROGRAM_NAME, media[n].dev); return exit_status; } static char * get_dev_label(void) { const size_t n = mp_n; struct dirent **labels = (struct dirent **)NULL; const int ln = scandir(DISK_LABELS_PATH, &labels, NULL, alphasort); if (ln == - 1) return (char *)NULL; char *label = (char *)NULL; int i; for (i = 0; i < ln; i++) { if (label) { free(labels[i]); continue; } const char *name = labels[i]->d_name; char lpath[PATH_MAX + 1]; snprintf(lpath, sizeof(lpath), "%s/%s", DISK_LABELS_PATH, name); char *rpath = xrealpath(lpath, NULL); if (!rpath) { free(labels[i]); continue; } const int ret = strcmp(rpath, media[n].dev); free(rpath); if (ret == 0) { /* Device label is encoded using hex. Let's decode it */ char *p = strchr(name, '\\'); if (p && *(p + 1) == 'x') { char pp = 0; pp = (char)(from_hex(*(p + 2)) << 4 | from_hex(*(p + 3))); *p = pp; xstrsncpy(p + 1, p + 4, strlen(p + 4) + 1); } label = savestring(name, strlen(name)); } free(labels[i]); } free(labels); return label; } static void list_unmounted_devs(void) { int i; const size_t mp_n_bk = mp_n; char **unm_devs = get_block_devices(); if (!unm_devs) return; printf(_("\n%sUnmounted devices%s\n\n"), BOLD, df_c); for (i = 0; unm_devs[i]; i++) { int skip = 0; size_t j; /* Skip already mounted devices */ for (j = 0; j < mp_n_bk; j++) { if (strcmp(media[j].dev, unm_devs[i]) == 0) skip = 1; } if (skip == 1) { free(unm_devs[i]); continue; } media = xnrealloc(media, mp_n + 2, sizeof(struct mnt_t)); media[mp_n].dev = savestring(unm_devs[i], strlen(unm_devs[i])); media[mp_n].mnt = (char *)NULL; media[mp_n].label = get_dev_label(); if (media[mp_n].label) printf("%s%zu %s%s [%s%s%s]\n", el_c, mp_n + 1, df_c, media[mp_n].dev, mi_c, media[mp_n].label, df_c); else printf("%s%zu %s%s\n", el_c, mp_n + 1, df_c, media[mp_n].dev); mp_n++; free(unm_devs[i]); } free(unm_devs); media[mp_n].dev = (char *)NULL; media[mp_n].mnt = (char *)NULL; media[mp_n].label = (char *)NULL; } static int list_mounted_devs(const int mode) { struct mntent *ent; FILE *fp = setmntent(_PATH_MOUNTED, "r"); if (!fp) { xerror("mp: setmntent: %s: %s\n", _PATH_MOUNTED, strerror(errno)); return FUNC_FAILURE; } while ((ent = getmntent(fp)) != NULL) { if (strncmp(ent->mnt_fsname, "/dev/", 5) != 0) continue; struct stat a; if (stat(ent->mnt_dir, &a) == -1 || !S_ISDIR(a.st_mode)) continue; const char *dir_color = get_dir_color(ent->mnt_dir, &a, -1); if (mode == MEDIA_LIST) { printf("%s%zu%s %s%s%s [%s]\n", el_c, mp_n + 1, df_c, dir_color, ent->mnt_dir, df_c, ent->mnt_fsname); } else { printf("%s%zu%s %s [%s%s%s]\n", el_c, mp_n + 1, df_c, ent->mnt_fsname, dir_color, ent->mnt_dir, df_c); } media = xnrealloc(media, mp_n + 2, sizeof(struct mnt_t)); media[mp_n].mnt = savestring(ent->mnt_dir, strlen(ent->mnt_dir)); media[mp_n].dev = savestring(ent->mnt_fsname, strlen(ent->mnt_fsname)); media[mp_n].label = (char *)NULL; mp_n++; } endmntent(fp); media[mp_n].dev = (char *)NULL; media[mp_n].mnt = (char *)NULL; media[mp_n].label = (char *)NULL; return FUNC_SUCCESS; } /* Mount device and store mountpoint (at media[N]). */ static int mount_dev(const int n) { if (xargs.mount_cmd == UNSET) { xerror(_("%s: No mount application found. Install either " "udevil or udisks2.\n"), PROGRAM_NAME); return FUNC_FAILURE; } char file[PATH_MAX + 1]; snprintf(file, sizeof(file), "%s/%s", xargs.stealth_mode == 1 ? P_tmpdir : tmp_dir, TMP_FILENAME); int fd = mkstemp(file); if (fd == -1) return FUNC_FAILURE; int stdout_bk = dup(STDOUT_FILENO); /* Save original stdout */ if (stdout_bk == -1) { unlinkat(fd, file, 0); return FUNC_FAILURE; } dup2(fd, STDOUT_FILENO); /* Redirect stdout to the desired file */ close(fd); if (xargs.mount_cmd == MNT_UDISKS2) { char *cmd[] = {"udisksctl", "mount", "-b", media[n].dev, NULL}; launch_execv(cmd, FOREGROUND, E_NOFLAG); } else { char *cmd[] = {"udevil", "mount", media[n].dev, NULL}; launch_execv(cmd, FOREGROUND, E_NOFLAG); } dup2(stdout_bk, STDOUT_FILENO); /* Restore original stdout */ close(stdout_bk); FILE *fp = open_fread(file, &fd); if (!fp) { unlink(file); return FUNC_FAILURE; } char out_line[PATH_MAX + 1]; *out_line = '\0'; if (fgets(out_line, (int)sizeof(out_line), fp) == NULL) { /* Error is printed by the mount command itself */ unlinkat(fd, file, 0); fclose(fp); return FUNC_FAILURE; } unlinkat(fd, file, 0); fclose(fp); /* Recover the mountpoint used by the mounting command. */ char *p = strstr(out_line, " at "); if (!p || !p[1] || !p[2] || !p[3] || p[4] != '/') { xerror(_("%s: Error retrieving mountpoint\n"), PROGRAM_NAME); return FUNC_FAILURE; } p += 4; /* Using strnlen() here avoids a Redhat hardened compilation warning. */ size_t plen = strnlen(p, sizeof(out_line) - 4); if (plen > 0 && p[plen - 1] == '\n') { plen--; p[plen] = '\0'; } media[n].mnt = savestring(p, plen); return FUNC_SUCCESS; } #endif /* HAVE_PROC_MOUNTS */ static void free_media(void) { int i = (int)mp_n; while (--i >= 0) { free(media[i].mnt); free(media[i].dev); free(media[i].label); } free(media); media = (struct mnt_t *)NULL; } /* Get device information via external application */ static int print_dev_info(const int n) { if (!media[n].dev || xargs.mount_cmd == UNSET) return FUNC_FAILURE; int exit_status = FUNC_SUCCESS; if (xargs.mount_cmd == MNT_UDEVIL) { char *cmd[] = {"udevil", "info", media[n].dev, NULL}; if (launch_execv(cmd, FOREGROUND, E_NOFLAG) != FUNC_SUCCESS) exit_status = FUNC_FAILURE; } else { char *cmd[] = {"udisksctl", "info", "-b", media[n].dev, NULL}; if (launch_execv(cmd, FOREGROUND, E_NOFLAG) != FUNC_SUCCESS) exit_status = FUNC_FAILURE; } return exit_status; } #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) \ || defined(__DragonFly__) || defined(__APPLE__) static size_t # ifdef __NetBSD__ list_mountpoints_bsd(struct statvfs *fslist) # else list_mountpoints_bsd(struct statfs *fslist) # endif /* __NetBSD__ */ { size_t i, j = 0; for (i = 0; i < mp_n; i++) { /* Do not list all mountpoints, but only those corresponding * to a block device (/dev) */ if (strncmp(fslist[i].f_mntfromname, "/dev/", 5) != 0) continue; struct stat a; if (stat(fslist[i].f_mntonname, &a) == -1 || !S_ISDIR(a.st_mode)) continue; const char *dir_color = get_dir_color(fslist[i].f_mntonname, &a, -1); printf("%s%zu%s %s%s%s (%s)\n", el_c, j + 1, df_c, dir_color, fslist[i].f_mntonname, df_c, fslist[i].f_mntfromname); /* Store the mountpoint in the mounpoints struct */ media = xnrealloc(media, j + 2, sizeof(struct mnt_t)); media[j].mnt = savestring(fslist[i].f_mntonname, strlen(fslist[i].f_mntonname)); media[j].label = (char *)NULL; media[j].dev = (char *)NULL; j++; } media[j].dev = (char *)NULL; media[j].mnt = (char *)NULL; media[j].label = (char *)NULL; return j; } #endif /* BSD || APPLE */ static int get_mnt_input(const int mode, int *info) { int n = -1; puts(_("Enter 'q' to quit")); if (xargs.mount_cmd != UNSET) puts(_("Enter 'iELN' for device information. E.g.: i4")); char *input = (char *)NULL; while (!input) { #ifdef HAVE_PROC_MOUNTS if (mode == MEDIA_LIST) input = rl_no_hist(_("Select a mountpoint (by ELN): "), 0); else input = rl_no_hist(_("Select a mountpoint/device (by ELN): "), 0); #else UNUSED(mode); input = rl_no_hist(_("Select a mountpoint (by ELN): "), 0); #endif /* HAVE_PROC_MOUNTS */ if (!input || !*input) { free(input); input = (char *)NULL; continue; } if (*input == 'q' && !input[1]) { if (conf.autols == 1) reload_dirlist(); free(input); return (-1); } char *p = input; if (*p == 'i') { *info = 1; ++p; } const int atoi_num = atoi(p); if (atoi_num <= 0 || atoi_num > (int)mp_n) { xerror(_("%s: %s: Invalid ELN\n"), PROGRAM_NAME, input); free(input); input = (char *)NULL; continue; } n = atoi_num - 1; } free(input); return n; } static int print_mnt_info(const int n) { const int exit_status = print_dev_info(n); if (exit_status == FUNC_SUCCESS) press_any_key_to_continue(1); free_media(); return exit_status; } #ifdef __sun /* Get and list available mountpoints (dirs only). * Returns the number of mounpoints found. */ static size_t xgetmntinfo_sun(void) { FILE *fp = fopen(MNTTAB, "r"); if (!fp) return 0; size_t n = 0; struct mnttab ent; while (getmntent(fp, &ent) != -1) { char *mp = ent.mnt_mountp; if (!mp || !*mp) continue; struct stat a; if (stat(mp, &a) == -1 || !S_ISDIR(a.st_mode)) continue; const char *dir_color = get_dir_color(mp, &a, -1); printf("%s%zu%s %s%s%s [%s]\n", el_c, n + 1, df_c, dir_color, mp, df_c, ent.mnt_special); media = xnrealloc(media, n + 2, sizeof(struct mnt_t)); media[n].mnt = savestring(mp, strlen(mp)); media[n].label = (char *)NULL; media[n].dev = (char *)NULL; n++; } fclose(fp); media[n].mnt = (char *)NULL; media[n].label = (char *)NULL; media[n].dev = (char *)NULL; return n; } #endif /* __sun */ /* If MODE is MEDIA_MOUNT (used by the 'media' command) list mounted and * unmounted devices allowing the user to mount or unmount any of them. * If MODE is rather MEDIA_LIST (used by the 'mp' command), just list * available mountpoints and allow the user to cd into the selected one. */ int media_menu(const int mode) { #if defined(__HAIKU__) xerror(_("%s: This feature is not available on Haiku\n"), mode == MEDIA_LIST ? _("mountpoints") : _("media")); return FUNC_FAILURE; #endif /* __HAIKU__ */ #ifndef HAVE_PROC_MOUNTS if (mode == MEDIA_MOUNT) { xerror("%s\n", _("media: Function only available on Linux systems")); return FUNC_FAILURE; } #endif /* HAVE_PROC_MOUNTS */ if (mode == MEDIA_MOUNT && xargs.mount_cmd == UNSET) { xerror("%s\n", _("media: No mount application found. Install either " "udevil or udisks2.")); return FUNC_FAILURE; } if (conf.clear_screen > 0) CLEAR; #ifdef HAVE_PROC_MOUNTS printf("%s%s%s\n\n", BOLD, mode == MEDIA_LIST ? _("Mountpoints") : _("Mounted devices"), df_c); #else printf(_("%sMountpoints%s\n\n"), BOLD, df_c); #endif /* HAVE_PROC_MOUNTS */ media = xnmalloc(1, sizeof(struct mnt_t)); mp_n = 0; #ifdef HAVE_PROC_MOUNTS if (list_mounted_devs(mode) == FUNC_FAILURE) { free(media); media = (struct mnt_t *)NULL; return FUNC_FAILURE; } const size_t mp_n_bk = mp_n; if (mode == MEDIA_MOUNT) list_unmounted_devs(); #elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__APPLE__) \ || defined(__DragonFly__) struct statfs *fslist; mp_n = (size_t)getmntinfo(&fslist, MNT_NOWAIT); #elif defined(__NetBSD__) struct statvfs *fslist; mp_n = (size_t)getmntinfo(&fslist, MNT_NOWAIT); #elif defined(__sun) mp_n = xgetmntinfo_sun(); #endif /* HAVE_PROC_MOUNTS */ /* This should never happen: There should always be a mountpoint, * at least "/" */ // cppcheck-suppress knownConditionTrueFalse if (mp_n == 0) { #ifdef HAVE_PROC_MOUNTS printf(_("%s: There are no available %s\n"), mode == MEDIA_LIST ? "mp" : "media", mode == MEDIA_LIST ? _("mountpoints") : _("devices")); #else fputs(_("mp: There are no available mountpoints\n"), stdout); #endif /* HAVE_PROC_MOUNTS */ return FUNC_SUCCESS; } #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) \ || defined(__APPLE__) || defined(__DragonFly__) mp_n = list_mountpoints_bsd(fslist); #endif /* BSD || APPLE */ putchar('\n'); int info = 0; const int n = get_mnt_input(mode, &info); int exit_status = FUNC_SUCCESS; if (n == -1) goto EXIT; if (info == 1) { exit_status = print_mnt_info(n); media_menu(mode); return exit_status; } #ifdef HAVE_PROC_MOUNTS if (mode == MEDIA_MOUNT) { if (!media[n].mnt) { /* The device is unmounted: mount it */ if (mount_dev(n) == FUNC_FAILURE) { exit_status = FUNC_FAILURE; goto EXIT; } } else { /* The device is mounted: unmount it */ int ret = unmount_dev(mp_n_bk, n); if (ret == FUNC_FAILURE) exit_status = FUNC_FAILURE; goto EXIT; } } #endif /* HAVE_PROC_MOUNTS */ if (xchdir(media[n].mnt, SET_TITLE) != FUNC_SUCCESS) { xerror("%s: '%s': %s\n", PROGRAM_NAME, media[n].mnt, strerror(errno)); exit_status = FUNC_FAILURE; goto EXIT; } free(workspaces[cur_ws].path); workspaces[cur_ws].path = savestring(media[n].mnt, strlen(media[n].mnt)); if (conf.autols == 1) reload_dirlist(); add_to_dirhist(workspaces[cur_ws].path); add_to_jumpdb(workspaces[cur_ws].path); EXIT: free_media(); return exit_status; } #else void *_skip_me_media; #endif /* !NO_MEDIA_FUNC */ clifm-1.26.3/src/media.h000066400000000000000000000017551506632037700147350ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* media.h */ #ifndef MEDIA_H #define MEDIA_H __BEGIN_DECLS int media_menu(const int mode); __END_DECLS #endif /* MEDIA_H */ clifm-1.26.3/src/mem.c000066400000000000000000000050131506632037700144160ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* mem.c -- Some memory wrapper functions */ #include "helpers.h" #include /* ENOMEM */ #include /* malloc(), calloc(), realloc() */ #if defined(__has_builtin) && !defined(NO_BUILTIN_MUL_OVERFLOW) # if __has_builtin(__builtin_mul_overflow) # define HAVE_BUILTIN_MUL_OVERFLOW # endif #endif void * xnrealloc(void *ptr, const size_t nmemb, const size_t size) { #ifdef HAVE_BUILTIN_MUL_OVERFLOW /* This is what reallocarray(3) does: if nmemb*size overflows, err. */ size_t r; if (__builtin_mul_overflow(nmemb, size, &r)) r = SIZE_MAX; void *p = r == SIZE_MAX ? NULL : realloc(ptr, r); #else void *p = realloc(ptr, nmemb * size); #endif /* HAVE_BUILTIN_MUL_OVERFLOW */ if (!p) { fprintf(stderr, _("%s: %s failed to allocate %zux%zu bytes\n"), PROGRAM_NAME, __func__, nmemb, size); exit(ENOMEM); } return p; } void * xcalloc(const size_t nmemb, const size_t size) { /* Most modern calloc implementations, at least Glibc and OpenBSD, * use __builtin_mul_overflow internally, so that we don't need to * do it here manually. */ void *p = calloc(nmemb, size); if (!p) { fprintf(stderr, _("%s: %s failed to allocate %zux%zu bytes\n"), PROGRAM_NAME, __func__, nmemb, size); exit(ENOMEM); } return p; } void * xnmalloc(const size_t nmemb, const size_t size) { #ifdef HAVE_BUILTIN_MUL_OVERFLOW size_t r; if (__builtin_mul_overflow(nmemb, size, &r)) r = SIZE_MAX; void *p = r == SIZE_MAX ? NULL : malloc(r); #else void *p = malloc(nmemb * size); #endif /* HAVE_BUILTIN_MUL_OVERFLOW */ if (!p) { fprintf(stderr, _("%s: %s failed to allocate %zux%zu bytes\n"), PROGRAM_NAME, __func__, nmemb, size); exit(ENOMEM); } return p; } clifm-1.26.3/src/mem.h000066400000000000000000000022551506632037700144300ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* mem.h */ /* This file is included by aux.h */ #ifndef CLIFM_MEM_H #define CLIFM_MEM_H __BEGIN_DECLS void *xnrealloc(void *ptr, const size_t nmemb, const size_t size); void *xcalloc(const size_t nmemb, const size_t size); void *xnmalloc(const size_t nmemb, const size_t size); __END_DECLS #endif /* CLIFM_MEM_H */ clifm-1.26.3/src/messages.h000066400000000000000000002456571506632037700155000ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* messages.h - Usage and help messages for Clifm */ #ifndef MESSAGES_H #define MESSAGES_H /* Usage messages */ # define GRAL_USAGE "[OPTION]... [DIR]..." #define ACTIONS_USAGE "List or edit actions/plugins\n\n\ \x1b[1mUSAGE\x1b[22m\n\ actions [list | edit [APP]]\n\n\ \x1b[1mEXAMPLES\x1b[22m\n\ - List available actions/plugins\n\ actions list\n\ Note: Since 'list' is the default action, it can be omitted.\n\ - Open/edit the actions configuration file with nano\n\ actions edit nano\n\ - Open/edit the actions configuration file with the default application\n\ actions edit\n\n\ Actions are just names for plugins.\n\ An action definition has the following form: \"NAME=plugin\", for example:\n\ \"//=rgfind.sh\".\n\ To run a plugin enter the action name. For example, to run the rgfind.sh plugin,\n\ enter \"//\".\n\ Some plugins accept parameters. To get information about a specific plugin\n\ use the -h,--help flag. Example: \"- --help\"." #define ALIAS_USAGE "List, print, or import aliases\n\n\ \x1b[1mUSAGE\x1b[22m\n\ alias [import FILE | list | NAME]\n\n\ \x1b[1mEXAMPLES\x1b[22m\n\ - List available aliases\n\ alias\n\ or\n\ alias list (or 'alias ')\n\ - Print a specific alias definition\n\ alias my_alias\n\ - Import aliases from ~/.bashrc\n\ alias import ~/.bashrc\n\ Note: Only aliases following the POSIX specification (NAME=\"STR\")\n\ will be imported.\n\ - Add a new alias\n\ Run 'config', go to the aliases section, and write:\n\ alias myalias=\"mycommand\"\n\ Save and quit the editor." #define ARCHIVE_USAGE "Compress/archive files\n\n\ \x1b[1mUSAGE\x1b[22m\n\ ac, ad FILE...\n\n\ \x1b[1mEXAMPLES\x1b[22m\n\ - Compress/archive all selected files\n\ ac sel\n\ - Compress/archive a range of files\n\ ac 12-24\n\ or\n\ 'ac ' to select from a list (multi-selection is allowed)\n\ - Decompress/dearchive a file\n\ ad file.tar.gz\n\ or just open the file (the appropriate menu will be displayed)\n\ o file.tar.gz (or just 'file.tar.gz')\n\n\ \x1b[1mDEPENDENCIES\x1b[22m\n\ zstd(1) Everything related to Zstandard\n\ mkisofs(1) Create ISO 9660 files\n\ 7z(1) / mount(1) Operate on ISO 9660 files\n\ archivemount(1) Mount archives\n\ atool(1) Extraction/decompression, listing, and repacking of archives" #define AUTOCD_USAGE "Turn autocd on/off\n\ \x1b[1mUSAGE\x1b[22m\n\ acd, autocd [on | off | status]" #define AUTO_USAGE "Set a temporary autocommand for the current directory\n\n\ \x1b[1mUSAGE\x1b[22m\n\ auto [list | none | unset | OPTION=VALUE,...]\n\n\ Unlike permanent autocommands (defined in the configuration file),\n\ options set via the 'auto' command are temporary, i.e. valid only for the\n\ current directory and the current session.\n\n\ Options set via this command take precedence over both permament autocommands\n\ and regular options (set via either the command line or the configuration file).\n\n\ \x1b[1mEXAMPLES\x1b[22m\n\ - Print the list of available autocommands\n\ auto list\n\ - List files in the current directory in long view\n\ auto lv=1\n\ - List only PDF files, set the color scheme to nord, and sort files by size\n\ auto ft=.*\\.pdf$,cs=nord,st=size\n\ - Same as above, but sequentially (previous values are preserved)\n\ auto ft=.*\\.pdf$\n\ auto cs=nord\n\ auto st=size\n\ - Unset the file filter and the color scheme, and change sort to blocks\n\ auto ft=,cs=,st=blocks\n\ - Unset all temporary options previously set for the current directory\n\ auto unset\n\ - Reload the current directory ignoring all autocommands (includes permanent autocommands)\n\ auto none\n\n\ For the list of available option codes enter 'help autocommands'." #define AUTOCMDS_USAGE "Tweak settings or run custom commands on a per-directory basis\n\n\ There are two ways to set autocommands:\n\ 1) Via the 'autocmd' keyword in the configuration file\n\ 2) Via specifically named files in the corresponding directory\n\n\ 1) Example using the first method:\n\n\ Edit the configuration file ('config' or F10) and add the following line:\n\n\ autocmd /media/remotes/** fc=0,lm=1\n\n\ This instructs Clifm to always disable the file counter and to run in\n\ light mode whenever you enter the '/media/remotes' directory (or any\n\ subdirectory).\n\n\ Note: To match only '/media/remotes' write \"/media/remotes\" instead,\n\ and to match all subdirectories (excluding the parent directory itself),\n\ write \"/media/remotes/*\".\n\n\ The following codes are used to control Clifm's settings:\n\n\ Code | Description | Example\n\ cs Color scheme cs=nord\n\ fc File counter fc=0\n\ ft File filter ft=.*\\.pdf$\n\ fz Full dir size fz=1\n\ hf,hh Hidden files hf=0\n\ lm Light mode lm=1\n\ lv,ll Long view lv=1\n\ mf Max files mf=100\n\ mn Max name length mn=30\n\ od Only directories od=1\n\ pg Pager pg=0\n\ st Sort method st=size\n\ sr Sort reverse sr=1\n\n\ To run a shell command or a script use the '!CMD' expression. For example:\n\n\ autcomd ~/important !printf \"Get outta here!\" && read -n1\n\ autcomd ~/Documents !~/my_script.sh\n\ \n\ Autocommand notifications are controlled by the InformAutocmd option in the\n\ configuration file.\n\ \n\ 2) Example using the second method:\n\n\ a. Set 'ReadAutocmdFiles' to 'true' in the configuration file.\n\ b. Create a '.cfm.in' file in the '~/Important' directory with the following\n\ content:\n\n\ echo \"Please keep me in sync with work files\" && read -n1\n\n\ This little reminder will be displayed every time you enter the 'Important'\n\ directory.\n\n\ If the file is named rather '.cfm.out', the command will be executed when\n\ leaving, instead of entering, the directory.\n\n\ Note 1: Only single-line commands are allowed. If you need more elaborated\n\ stuff, set here the path to a script doing whatever needs to be done.\n\n\ Note 2: Codes to modify Clifm's settings (as described in the first method)\n\ are not available here.\n\n\ Note 3: To set a temporary autocommand for the current directory use the\n\ 'auto' command. Run 'auto --help' for details." #define AUTO_OPEN_USAGE "Toggle auto-open\n\n\ \x1b[1mUSAGE\x1b[22m\n\ ao, auto-open [on | off | status]" #define BACK_USAGE "Change to the previously visited directory\n\n\ \x1b[1mUSAGE\x1b[22m\n\ b, back [h, hist | clear | !ELN]\n\n\ \x1b[1mEXAMPLES\x1b[22m\n\ - Just change to the previously visited directory\n\ b (also Alt+j or Shift+Left)\n\ - Print the directory history list\n\ b hist (or 'dh')\n\ - Change to the directory whose ELN in the list is 24\n\ b !24\n\ - Use the 'f' command to go forward\n\ f (also Alt+k or Shift+Right)" #define BD_USAGE "Change to a parent directory matching NAME. If \ NAME is not specified, print the list of all parent directories\n\n\ \x1b[1mUSAGE\x1b[22m\n\ bd [NAME]\n\n\ \x1b[1mEXAMPLE\x1b[22m\n\ - Supposing you are in ~/Documents/misc/some/deep/dir, change to\n\ ~/Documents/misc\n\ bd mi (or 'bd ' to select from a list)" #define BL_USAGE "Create multiple symbolic links at once\n\n\ \x1b[1mUSAGE\x1b[22m\n\ bl FILE...\n\n\ \x1b[1mEXAMPLE\x1b[22m\n\ - Symlink files 'file1', 'file2', 'file3', and 'file4' at once\n\ bl file* (or 'bl ' to select from a list - multi-selection is\n\ allowed)\n\ - Create symbolic links in the directory 'dir' for all .png files\n\ s *.png\n\ cd dir\n\ bl sel\n\n\ Note: Links are always created in the current directory." #define BLEACH_USAGE "Sanitize filenames by removing or converting non-ASCII characters\n\n\ \x1b[1mUSAGE\x1b[22m\n\ bb, bleach FILE...\n\n\ \x1b[1mEXAMPLE\x1b[22m\n\ - Sanitize filenames in your Downloads directory\n\ bb ~/Downloads/*" #define BOOKMARKS_USAGE "Manage bookmarks\n\n\ \x1b[1mUSAGE\x1b[22m\n\ bm, bookmarks [a, add FILENAME NAME | d, del NAME | e, edit [APP] | NAME]\n\n\ \x1b[1mEXAMPLES\x1b[22m\n\ - List bookmarks\n\ bm (also Alt+b, 'bm ' or 'b:')\n\ - Bookmark the directory '/media/mount' as 'mnt'\n\ bm add /media/mount mnt\n\ Note: Regular files can also be bookmarked\n\ - Access the bookmark named 'mnt'\n\ bm mnt (also 'b:mnt', 'b:' or 'bm ' to select from a list)\n\ - Remove the bookmark named 'mnt'\n\ bm del mnt (or 'bm del ' to select from a list)\n\ - Edit the bookmarks file\n\ bm edit (or F11)\n\ - Edit the bookmarks file using vi\n\ bm edit vi\n\ - Print file properties of specific bookmarks using the 'b:' construct\n\ p b: (multi-selection is allowed)\n\ - Select all bookmarks at once\n\ s b:" #define BULK_RENAME_USAGE "Rename files in bulk\n\n\ \x1b[1mUSAGE\x1b[22m\n\ br, bulk FILE... [:EDITOR]\n\n\ The list of files to be renamed is opened via EDITOR (default associated\n\ application for text files if omitted). Edit filenames as desired, rename,\n\ save changes, and quit the editor (quit without saving to cancel the operation).\n\n\ \x1b[1mEXAMPLES\x1b[22m\n\ - Bulk rename all files ending with .pdf in the current directory\n\ br *.pdf\n\ or\n\ 'br ' to select from a list (mutli-selection is allowed)\n\ - Bulk rename all selected files\n\ br sel\n\ or, using vi:\n\ br sel :vi" #define CD_USAGE "Change the current working directory\n\n\ \x1b[1mUSAGE\x1b[22m\n\ cd [DIR]\n\n\ \x1b[1mEXAMPLE\x1b[22m\n\ - Change to /var\n\ cd /var\n\ or, if autocd is enabled (default)\n\ /var" #define COLORS_USAGE "Preview the current color scheme\n\n\ \x1b[1mUSAGE\x1b[22m\n\ colors\n\n\ Note: 'cs preview' can be used as well." #define COLUMNS_USAGE "Toggle columned file listing\n\n\ \x1b[1mUSAGE\x1b[22m\n\ cl, columns [on | off]" #define CS_USAGE "Switch color schemes\n\n\ \x1b[1mUSAGE\x1b[22m\n\ cs, colorschemes [COLORSCHEME | edit [APP] | preview | check-ext | name]\n\n\ \x1b[1mEXAMPLES\x1b[22m\n\ - Print the name of the current color scheme\n\ cs name (or 'cs n')\n\ - List available color schemes\n\ cs (or 'cs ')\n\ - Preview the current color scheme\n\ cs preview (or 'cs p')\n\ - Check for file extension conflicts\n\ cs check-ext\n\ - Edit the current color scheme\n\ cs edit\n\ - Edit the current color scheme using vi\n\ cs edit vi\n\ - Switch to the color scheme named 'mytheme'\n\ cs mytheme\n\n\ Tip: Theming via LS_COLORS is also possible. To enable this feature,\n\ run with the --lscolors option. Consult the Wiki for more information:\n\ https://github.com/leo-arch/clifm/wiki/Customization#ls_colors-support" #define DESEL_USAGE "Deselect files\n\n\ \x1b[1mUSAGE\x1b[22m\n\ ds, desel [*, a, all]\n\n\ \x1b[1mEXAMPLES\x1b[22m\n\ - Deselect all files\n\ ds * (or Alt+d)\n\ - Deselect files from a menu\n\ ds (or 'ds ' to select from a list - multi-selection is allowed)" #define DESKTOP_NOTIFICATIONS_USAGE "Errors, warnings, and notices are displayed \ using desktop notifications instead of\n\ being printed immediately before the next prompt.\n\n\ To enable this feature use the --desktop-notifications command line flag or\n\ the DesktopNotifications option in the configuration file (F10). Supported values\n\ are: 'kitty', 'system', or 'false'.\n\n\ If set to 'kitty', notifications are displayed using the Kitty Notifications\n\ Protocol (requires the Kitty terminal or a terminal supporting this protocol).\n\n\ If set to 'system', notifications are displayed using one of the following commands:\n\n\ Linux/BSD: notify-send -u \"TYPE\" \"TITLE\" \"MSG\"\n\ MacOS: osascript -e 'display notification \"MSG\" subtitle \"TYPE\" with title \"TITLE\"'\n\ Haiku: notify --type \"TYPE\" --title \"TITLE\" \"MSG\"\n\n\ Note: It is the notifications daemon itself who takes care of actually displaying\n\ notifications on your screen. For troubleshoting, consult your \ daemon's documentation.\n\n\ Tip: You can always check notifications using the 'msg' command." #define DH_USAGE "Query the directory history list\n\n\ \x1b[1mUSAGE\x1b[22m\n\ dh [STRING] [PATH] [!ELN]\n\n\ \x1b[1mEXAMPLES\x1b[22m\n\ - Print the directory history list\n\ dh (also 'dh ')\n\ - Print directory history entries matching \"query\"\n\ dh query (also 'dh query')\n\ - Change to the entry number (ELN) 12\n\ dh !12\n\ Note: Entry numbers are not displayed when using tab completion.\n\n\ Note: If the first argument is an absolute path, 'dh' works just like 'cd'.\n\ Tip: Take a look at the 'j' command as well." #define DIRHIST_USAGE "List or access entries in the directory history list\n\n\ \x1b[1mUSAGE\x1b[22m\n\ b/f [hist | clear | !ELN]\n\n\ \x1b[1mEXAMPLES\x1b[22m\n\ - Print the directory history list\n\ b hist\n\ - Change to the directory whose ELN is 12 in the directory history list\n\ b !12\n\ - Remove all entries from the directory history list\n\ b clear\n\n\ Tip: See also the 'dh' and 'j' commands." #define DUP_USAGE "Duplicate files via rsync(1) (cp(1) if rsync is not found)\n\n\ \x1b[1mUSAGE\x1b[22m\n\ d, dup FILE...\n\n\ \x1b[1mEXAMPLE\x1b[22m\n\ - Duplicate files whose ELNs are 12 through 20\n\ d 12-20\n\n\ You will be prompted to enter a destination directory.\n\ Duplicated files are created as SRC.copy, and, if SRC.copy exists, as \n\ SRC.copy-n, where n is an positive integer (starting at 1).\n\n\ Parameters passed to rsync: --aczvAXHS --progress\n\n\ Parameters passed to cp: -a" #define CONFIG_USAGE "Edit the main configuration file\n\n\ \x1b[1mUSAGE\x1b[22m\n\ config [reload | reset | dump | APPLICATION]\n\n\ \x1b[1mEXAMPLES\x1b[22m\n\ - Open/edit the configuration file\n\ config (or F10)\n\ - Open/edit the configuration file using nano\n\ config nano\n\ - Print current values, highlighting those deviating from default values\n\ config dump\n\ - Reload the main configuration file and update settings accordingly\n\ config reload\n\ - Reset the configuration file to its default state (keeping a backup of the existing file)\n\ config reset" #define EXT_USAGE "Turn on/off the use of external commands\n\n\ \x1b[1mUSAGE\x1b[22m\n\ ext [on, off, status]" #define EXPORT_FILES_USAGE "Export filenames to a temporary file\n\n\ \x1b[1mUSAGE\x1b[22m\n\ exp [FILE...]\n\n\ \x1b[1mEXAMPLES\x1b[22m\n\ - Export all selected files\n\ exp sel\n\ - Export all PDF files in the current directory\n\ exp *.pdf" #define EXPORT_VAR_USAGE "Add variables to the environment\n\n\ \x1b[1mUSAGE\x1b[22m\n\ export NAME=VALUE..." #define FC_USAGE "Toggle the file counter for directories\n\n\ \x1b[1mUSAGE\x1b[22m\n\ fc [on | off | status]" #define FILE_DETAILS "List file details\n\n\ \x1b[1mEXAMPLES\x1b[22m\n\ - Toggle the long view\n\ ll (also Alt+l)\n\ Note: Use PropFields in the configuration file to customize output\n\ fields (and TimeStyle for custom timestamp formats).\n\ - Print file properties of the file whose ELN is 4\n\ p4\n\ - Print file properties, using recursive directory sizes\n\ pp DIR\n\n\ Note: An exclamation mark (!) before directory sizes means that an\n\ error ocurred while reading a subdirectory (most of the time due to\n\ insufficient permissions), so that sizes may not be accurate.\n\n\ Note 2: Unlike 'p', 'pp' always dereferences symbolic links." #define FILE_SIZE_USAGE "File sizes/disk usage\n\n\ \x1b[1mEXAMPLES\x1b[22m\n\ - Enable recursive directory sizes (long view)\n\ fz on (or --full-dir-size)\n\ - Toggle the disk usage analyzer mode\n\ Alt+Tab (or -t,--disk-usage-analyzer)\n\ - Display physical file sizes (disk usage) instead of logical sizes (apparent size)\n\ Run with --physical-size or set ApparentSize to false in the\n\ configuration file.\n\ - Display file sizes in SI units (powers of 1000) instead of IEC units (powers of 1024)\n\ Run with --si" #define FF_USAGE "Turn list-directories-first on/off\n\n\ \x1b[1mUSAGE\x1b[22m\n\ ff, dirs-first [on | off | status]\n\ \x1b[1mEXAMPLE\x1b[22m\n\ - Disable list-directories-first\n\ ff off\n\ Note: Toggle list-directories-first by pressing Alt+g." #define FILE_PREVIEWS "\ File previews are enabled by default if running in fzf mode.\n\n\ To disable this feature, run with '--no-fzfpreview' or set 'FzfPreview' to\n\ false in the configuration file.\n\n\ Clifm operates in fzf mode if the fzf binary is found in your $PATH.\n\ You can also use '--fzftab' or 'TabCompletionMode' in the configuration file.\n\n\ File previews are generated using a configuration file, which can be edited to\n\ your liking by running 'view edit' (or pressing F7).\n\n\ Use the 'view' command to preview files in the current directory in full screen.\n\n\ To prevent large files from generating a preview, use the PreviewMaxSize option\n\ in the configuration file. For example: 'PreviewMaxSize=100M' (supported size\n\ units: K, M, G, T; supported range: 1K-2047G). By default, there is no limit.\n\n\ To learn how to enable image previews run 'help image-previews'." #define IMAGE_PREVIEWS "\x1b[1mENABLING IMAGE PREVIEWS\x1b[22m\n\ \n\ Edit shotgun's configuration file ('view edit' or F7) and uncomment the\n\ 'clifmimg' lines at the top of the file.\n\ \n\ This instructs Clifm to use the 'clifmimg' script (~/.config/clifm/clifmimg)\n\ to generate image previews (for both tab completion in fzf mode and the\n\ 'view' command).\n\ \n\ By default, Clifm will try to guess the most suitable method. However, you\n\ can edit the 'clifmimg' script and set the 'method' variable to any of the\n\ available previewing methods: sixel, iterm, ueberzug, kitty, ansi (text mode).\n\ \n\ If using the 'ueberzug' method, you must start Clifm via the 'clifmrun' script\n\ (~/.config/clifm/clifmrun)" #define FILTER_USAGE "Set a filter for the file list\n\n\ \x1b[1mUSAGE\x1b[22m\n\ ft, filter [unset | [!]REGEX,=FILE-TYPE-CHAR]\n\n\ \x1b[1mEXAMPLES\x1b[22m\n\ - Print the current filter, if any\n\ ft\n\ - Do not list hidden files\n\ ft !^\\.\n\ - List only files ending with \".pdf\"\n\ ft .*\\.pdf$\n\ - List only symbolic links\n\ ft =l\n\ - Do not list socket files\n\ ft !=s\n\ Note: See below for the list of available file type characters.\n\ - Unset the current filter\n\ ft unset\n\n\ You can also filter files in the current directory using tab\n\ completion via wildcards and the file type filter:\n\ - List PDF files\n\ /*.pdf\n\ - List executable files\n\ =x\n\n\ Available file type characters:\n\ b: Block devices\n\ c: Character devices\n\ d: Directories\n\ D: Empty directories (2)\n\ f: Regular files\n\ F: Empty regular files (2)\n\ h: Multi-hardlink files (2)\n\ l: Symbolic links\n\ L: Broken symbolic links (2)\n\ p: FIFO/pipes\n\ s: Sockets\n\ C: Files with capabilities (1)(2)\n\ o: Other-writable files (2)\n\ O: Doors (Solaris only)\n\ P: Port (Solaris only)\n\ t: Files with the sticky bit set (2)\n\ u: SUID files (2)\n\ g: SGID files (2)\n\ x: Executable files (2)\n\n\ (1) Only via tab completion\n\ (2) Not available in light mode\n\n\ Type '=' to get the list of available file type filters.\n\n\ Other ways of filtering files in the current directory:\n\n\ * @ List all MIME types found\n\ * @query MIME type filter. E.g.: @pdf to list all PDF files\n\ * /query Quick search function: consult the 'search' help topic\n\ * Alt+. Toggle hidden files\n\ * Alt+, Toggle list-only-dirs\n\ * Just press TAB (fzf/fnf mode) and perform a fuzzy search\n\n\ You can also operate on files filtered by file type and/or MIME type as\n\ follows:\n\n\ CMD =file-type-char @query\n\n\ For example, to select all executable files, symbolic links, and image\n\ files in the current directory:\n\n\ s =x =l @image" #define FORTH_USAGE "Change to the next visited directory\n\n\ \x1b[1mUSAGE\x1b[22m\n\ f, forth [h, hist | clear | !ELN]\n\n\ \x1b[1mEXAMPLES\x1b[22m\n\ - Just change to the next visited directory\n\ f (also Alt+k or Shift+Right)\n\ - Print the directory history list\n\ f hist (or 'dh')\n\ - Change to the directory whose ELN in the list is 24\n\ f !24\n\ - Use the 'b' command to change to the previously visited directory\n\ b (also Alt+j or Shift+Left)" #define FZ_USAGE "Toggle recursive directory sizes (long view only)\n\n\ \x1b[1mUSAGE\x1b[22m\n\ fz [on, off]" #define HELP_USAGE "Get help\n\n\ \x1b[1mUSAGE\x1b[22m\n\ help [TOPIC]\n\n\ \x1b[1mEXAMPLES\x1b[22m\n\ - Print the help screen\n\ help\n\ - Get help about the 'bookmarks' topic\n\ help bookmarks\n\ - Print the list of available help topics\n\ help " #define HF_USAGE "Turn hidden files on/off\n\n\ \x1b[1mUSAGE\x1b[22m\n\ hf, hh, hidden [on | off | first | last | status]\n\n\ \x1b[1mEXAMPLE\x1b[22m\n\ - Show hidden files\n\ hh on\n\ Note: Use first/last to sort hidden files before/after non-hidden files.\n\ - Toggle hidden files\n\ hh (or Alt+.)" #define HISTEXEC_USAGE "Access command history entries\n\n\ \x1b[1mUSAGE\x1b[22m\n\ history or !: List available commands\n\ !!: Execute the last command\n\ !n: Execute the command number 'n' in the history list\n\ !-n: Execute the last - n command in the history list" #define HISTORY_USAGE "List or access command history entries\n\n\ \x1b[1mUSAGE\x1b[22m\n\ history [edit [APP] | clear | -N | on | off | status | show-time [-N]]\n\n\ \x1b[1mEXAMPLES\x1b[22m\n\ - Print the complete list of commands in history\n\ history\n\ - Print the complete list of commands in history (with timestamps)\n\ history show-time\n\ - Print the last 4 commands in history\n\ history -4\n\ Note: 'history show-time -4' to add timestamps.\n\ - Prevent subsequent commands from being written to the history file\n\ history off (then reenable it via 'history on')\n\ Note: Starting a command by a space prevent it from being added to history.\n\ - Edit the commands history list\n\ history edit\n\ - Edit the commands history list using vi\n\ history edit vi\n\ - Clear the history list\n\ history clear\n\n\ You can also access the command history via the exclamation mark (!).\n\ - List available commands\n\ !\n\ - List all history entries matching 'sudo'\n\ !sudo\n\ - Execute the last command\n\ !!\n\ - Execute the command number 'n' in the history list\n\ !n\n\ - Execute the 'last - n' command in the history list\n\ !-n\n\n\ Tip: Use HistIgnore in the configuration file to exclude command lines\n\ from the history list." #define ICONS_USAGE "Toggle icons\n\n\ \x1b[1mUSAGE\x1b[22m\n\ icons [on | off]\n\n\ Note: Depending on how the terminal renders icons, the apparent space\n\ between icons and filenames may not be optimal. This space can be adjusted\n\ using the IconsGap option in the configuration file (valid values: 0, 1, or 2)." #define JUMP_USAGE "Change to a directory in the jump database (visited directories)\n\n\ \x1b[1mUSAGE\x1b[22m\n\ j [--purge [NUM] | --edit [APP]], jc, jp, jl [STRING]..., je\n\n\ For information about the matching algorithm consult the manpage\n\n\ \x1b[1mEXAMPLES\x1b[22m\n\ - Print the list of entries in the jump database\n\ j (or jl)\n\ - List all entries matching \"str\"\n\ jl str\n\ - Jump (cd) to the best-ranked directory matching \"bui\"\n\ j bui\n\ Note: Hit TAB to get a list of possible matches: 'j bui'.\n\ - If not enough, use multiple query strings\n\ j ho bui\n\ Note: Most likey, this will take you to '/home/build'\n\ - Jump to the best-ranked PARENT directory matching \"str\"\n\ jp str\n\ - Jump to the best-ranked CHILD directory matching \"str\"\n\ jc str\n\ - Mark an entry as permanent\n\ You can accomplish this in two different ways:\n\ a. Bookmark it.\n\ b. Edit the database (see below) and prepend a plus sign (+) to the\n\ corresponding entry.\n\ - Open/edit the jump database\n\ je (also 'j --edit')\n\ - Open/edit the jump database using vim\n\ j --edit vim\n\ - Purge the database of non-existent directories\n\ j --purge\n\ Note: To automatically purge the database of non-existent directories\n\ at startup, set PurgeJumpDB to true in the configuration file.\n\ - Purge the database of entries ranked below 100\n\ j --purge 100\n\ Note: To remove a specific entry, delete the corresponding line\n\ from the database ('je' or 'j --edit'). Note that if the directory\n\ is in the directory history, it will not be removed from the database." #define K_USAGE "Toggle follow-links (long view)\n\n\ \x1b[1mUSAGE\x1b[22m\n\ k\n\n\ When enabled, the long view displays information about the file a symbolic\n\ link points to, rather than the link itself." #define KK_USAGE "Toggle max-filename-len\n\n\ \x1b[1mUSAGE\x1b[22m\n\ kk" #define KB_USAGE "Manage keybindings\n\n\ \x1b[1mUSAGE\x1b[22m\n\ kb, keybinds [list | bind FUNC | edit [APP] | conflict | reset | readline]\n\n\ \x1b[1mEXAMPLES\x1b[22m\n\ - List the current keybindings\n\ kb (or 'kb list')\n\ - List available function names\n\ kb bind \n\ - Bind toggle-hidden to a key\n\ kb bind toggle-hidden\n\ - Open/edit the keybindings file\n\ kb edit\n\ - Open/edit the keybindings file using mousepad\n\ kb edit mousepad\n\ - Unbind a function\n\ Method 1: run 'kb bind FUNC' and bind it to '-'\n\ Method 2: Run 'kb edit' and comment out the corresponding entry\n\ - Detect keybinding conflicts\n\ kb conflict\n\ - List the current keybindings for readline specific functions\n\ kb readline\n\ - Reset the keybindings file to its default state (keeping a backup of the\n\ existing file)\n\ kb reset" #define LE_USAGE "Edit a symbolic link\n\n\ \x1b[1mUSAGE\x1b[22m\n\ le SYMLINK\n\n\ The user is prompted to enter a new link target using the current\n\ target as template.\n\n\ \x1b[1mEXAMPLE\x1b[22m\n\ - Edit the symbolic link named 'file.link'\n\ le file.link" #define LINK_USAGE "Create a symbolic link\n\n\ \x1b[1mUSAGE\x1b[22m\n\ l TARGET [LINK_NAME]\n\n\ If LINK_NAME is omitted, it is created as TARGET_BASENAME.link in\n\ the current directory.\n\n\ \x1b[1mEXAMPLE\x1b[22m\n\ - Create a symbolic link to 'file.zst' named 'mylink'\n\ l file.zst mylink\n\n\ Note: The link creation mode (by default 'literal', like 'ln -s')\n\ can be set in the configuration file via the LinkCreationMode option\n\ (available modes are: absolute, literal, relative).\n\n\ Tip: Use the 'le' command to edit a symbolic link. Try 'le --help'." #define LL_USAGE "Toggle the long view\n\n\ \x1b[1mUSAGE\x1b[22m\n\ ll, lv [on | off]\n\n\ \x1b[1mEXAMPLES\x1b[22m\n\ - Switch to long view\n\ ll on\n\ - Toggle long view\n\ ll (or Alt+l)" #define LM_USAGE "Turn the light mode on/off\n\n\ \x1b[1mUSAGE\x1b[22m\n\ lm [on, off]" #define LOG_USAGE "Manage clifm logs\n\n\ \x1b[1mUSAGE\x1b[22m\n\ log [cmd | msg] [list | on | off | status | clear]\n\n\ \x1b[1mEXAMPLES\x1b[22m\n\ - Print message logs\n\ log msg list (or just 'log msg')\n\ - Enable command logs\n\ log cmd on\n\ - Disable message logs\n\ log msg off\n\ - Clear message logs\n\ log msg clear" #define MD_USAGE "Create directories\n\ (parent directories are created if they do not exist)\n\n\ \x1b[1mUSAGE\x1b[22m\n\ md DIR...\n\n\ \x1b[1mEXAMPLE\x1b[22m\n\ md dir1 dir2 dir3/subdir\n\n\ Note: Use the 'n' command to create both files and directories.\n\ Try 'n --help' for more details." #define MEDIA_USAGE "List, mount, and unmount storage devices\n\n\ Note: udevil(1) or udisks2(1) is required\n\n\ \x1b[1mUSAGE\x1b[22m\n\ media\n\n\ The list of mounted and unmounted devices will be displayed.\n\ Select a device using ELNs (Entry List Numbers).\n\n\ If the device is mounted, it will be unmounted, and, if unmounted,\n\ it will be mounted. Clifm will automatically change to the\n\ mountpoint after mounting.\n\n\ To get information about a device, enter 'i' followed by the ELN.\n\ For example: 'i12'." #define MF_USAGE "Limit the number of listed files to NUM \ (valid range: >= 0). Use 'unset' to remove the file limit.\n\n\ \x1b[1mUSAGE\x1b[22m\n\ mf [NUM | unset]" #define MIME_USAGE "Manage opening applications\n\n\ \x1b[1mUSAGE\x1b[22m\n\ mm, mime [open FILE | info FILE | edit [APP] | import]\n\n\ \x1b[1mEXAMPLES\x1b[22m\n\ - Open the file 'book.pdf' with the default opening application\n\ mm open book.pdf\n\ Note: Since 'open' is the default action, it can be omitted: 'mm book.pdf'.\n\ This command is the same as 'open book.pdf' or just 'book.pdf'.\n\ - Get MIME information for the file whose ELN is 12\n\ mm info 12\n\ - Open/edit the MIME configuration file\n\ mm edit (or F6)\n\ - Open/edit the MIME configuration file using vim\n\ mm edit vim\n\ - Try to import MIME file associations from the system\n\ mm import\n\ - Add/modify the default opening application for 'myfile'\n\ 1) Determine the MIME type (or filename) of the file\n\ mm info myfile\n\ 2) Edit the mimelist file\n\ mm edit (or F6)\n\ Once in the file, find the appropriate entry and add/modify\n\ the desired opening application.\n\ For more information consult the manpage." #define MSG_USAGE "List available program messages\n\n\ \x1b[1mUSAGE\x1b[22m\n\ msg, messages [clear]\n\n\ \x1b[1mEXAMPLES\x1b[22m\n\ - List available messages\n\ msg\n\ - Clear the current list of messages\n\ msg clear (or Alt+t)" #define MOUNTPOINTS_USAGE "List and change to a mountpoint\n\n\ \x1b[1mUSAGE\x1b[22m\n\ mp, mountpoints\n\n\ \x1b[1mEXAMPLES\x1b[22m\n\ - List available mountpoints\n\ mp (or Alt+m)\n\ Once there, select the mountpoint you want to change to\n\ (clifm will automatically change to the mountpoint)." #define NET_USAGE "Manage remote resources\n\n\ \x1b[1mUSAGE\x1b[22m\n\ net [NAME] [list | edit [APP] | m, mount NAME | u, unmount NAME]\n\n\ \x1b[1mEXAMPLES\x1b[22m\n\ - List available remote resources (like SSHFS or samba)\n\ net (or 'net list')\n\ - Mount the remote resource named 'work'\n\ net mount work (also 'net m work' or 'net m ')\n\ Note: Since 'mount' is the default action, it can be omitted: 'net work'.\n\ - Unmount the remote resource named 'work'\n\ net unmount work (or 'net u work' or 'net u ')\n\ - Open/edit the net configuration file\n\ net edit\n\ - Open/edit the net configuration file using nano\n\ net edit nano\n\ - Copy a file to a remote location using the 'cr' plugin\n\ cr FILE (run 'cr --edit' before to set up your remotes)\n\n\ Note: This command can also be used to (un)mount storage devices, such as\n\ disk partitions or external drives. Run 'net edit' and consult the examples\n\ section for more information." #define NEW_USAGE "Create new files and/or directories\n\n\ \x1b[1mUSAGE\x1b[22m\n\ n, new [FILE[@TEMPLATE]...] [DIR/...]\n\n\ \x1b[1mEXAMPLES\x1b[22m\n\ - Create two files named 'file1' and 'file2'\n\ n file1 file2\n\ - Create two directories named 'dir1' and 'dir2'\n\ n dir1/ dir2/\n\ Note: Be sure to include the ending slashes.\n\ - Create both files and directories at once:\n\ n file1 file2 dir1/ dir2/\n\ - Create a file from a template (see below for more information)\n\ n file1@my_template\n\n\ Parent directories will be created as needed. For example, if you run\n\ n dir/subdir/file\n\ both the 'dir' and 'subdir' directories will be created if they do not\n\ already exist.\n\n\ \x1b[1mFILE TEMPLATES\x1b[22m\n\n\ \x1b[1m1. Automatic templates\x1b[22m\n\n\ New regular files can be created from a template file if:\n\n\ a. The file to be created has a filename extension (e.g., 'file.html').\n\ b. A file named like this extension (in this case 'html') exists in the\n\ templates directory (1).\n\n\ If both conditions are satisfied, running 'n file.html' will create a new file\n\ named 'file.html' which is a copy of the 'html' file in the templates\n\ directory.\n\n\ Note that template names are not restricted to actual file extensions: you\n\ can name your templates as you wish (with any content you desire) as long as\n\ new files are created using the template name as the extension. E.g.:\n\ 'n file.my_super_cool_template'.\n\n\ \x1b[1m2. Explicit templates\x1b[22m\n\n\ If a filename is followed by '@TEMPLATE', where TEMPLATE is any regular\n\ file found in the templates directory (1), the file will be created as a\n\ copy of the specified template. E.g.: 'n file.sh@my_script.sh'.\n\n\ Tab completion is available for explicit templates: simply type 'n file@'.\n\n\ (1) The templates directory is $CLIFM_TEMPLATES_DIR, $XDG_TEMPLATES_DIR,\n\ or ~/Templates, in this precedence order." #define OC_USAGE "Edit file ownership\n\n\ \x1b[1mUSAGE\x1b[22m\n\ oc FILE...\n\n\ \x1b[1mEXAMPLES\x1b[22m\n\ - Change ownership of selected files\n\ oc sel\n\ - Change ownership of all .iso files\n\ oc *.iso\n\n\ \x1b[1mNOTES\x1b[22m\n\ A template is presented to the user to edit the ownership information.\n\n\ Only user and primary group common to all specified files are set in\n\ the ownership template.\n\n\ The new ownership (both user and primary group, if specified) will be\n\ applied to each specified file.\n\n\ Both names and ID numbers are allowed (tab completion is available).\n\n\ If only a name/number is entered, it is taken as user.\n\n\ \x1b[1mEXAMPLES\x1b[22m\n\ - Change user to root\n\ root (or \"0\")\n\ - Change primary group to video\n\ :video (or \":981\")\n\ - Change user to peter and primary group to audio\n\ peter:audio (or \"1000:986\" or \"peter:986\" or \"1000:audio\")\n\n\ Tip: Use the 'pc' command to edit file permissions." #define OPEN_USAGE "Open a file\n\n\ \x1b[1mUSAGE\x1b[22m\n\ o, open FILE [APPLICATION]\n\n\ \x1b[1mEXAMPLES\x1b[22m\n\ - Open the file whose ELN is 12 with the default associated application\n\ (see the 'mime' command)\n\ o 12\n\ - Open the file whose ELN is 12 with vi\n\ o 12 vi\n\ Note: If auto-open is enabled (default), 'o' can be omitted\n\ 12\n\ 12 vi" #define OPENER_USAGE "Set the file opener\n\n\ \x1b[1mUSAGE\x1b[22m\n\ opener APPLICATION\n\n\ \x1b[1mEXAMPLES\x1b[22m\n\ - Set the file opener to xdg-open (instead of the default, Lira)\n\ opener xdg-open\n\ - Set the file opener back to the default\n\ opener default" #define OW_USAGE "Open a file using a specific application\n\n\ \x1b[1mUSAGE\x1b[22m\n\ ow FILE [APP]\n\n\ \x1b[1mEXAMPLES\x1b[22m\n\ - Select the opening application for the file 'test.c' from a menu\n\ ow test.c\n\ or\n\ 'ow test.c ' (to get a list of available applications)\n\ Note: Available applications are taken from the mimelist file (see the\n\ 'mime' command), and only valid and installed applications are listed.\n\ - Open the file 'test.c' with geany\n\ ow test.c geany" #define PAGER_USAGE "Toggle/run the file list pager\n\n\ \x1b[1mUSAGE\x1b[22m\n\ pg, pager [on | off | once | status | NUM]\n\n\ With no parameter, just run the pager.\n\n\ If set to 'on', run the pager whenever the list of files does no fit on\n\ the screen.\n\n\ If set to a positive integer greater than 1, run the pager whenever\n\ the number of files in the current directory is greater than or equal to\n\ that value (e.g., 1000). A value of 1 is equivalent to 'on', while 0 means 'off'.\n\n\ Set it to 'once' to run the pager only a single time.\n\n\ While paging, the following keys are available:\n\n\ ?, h: Help\n\ Down arrow, Enter, Space: Advance one line\n\ Page down: Advance one page\n\ q: Stop paging (without printing remaining files)\n\ c: Stop paging (printing remaining files)\n\n\ Note: For upward scrolling, use the scrolling options available in your\n\ terminal emulator (e.g., mouse scrolling or specific keybindings)\n\n\ By default, the pager lists files using the current listing mode (long\n\ or short). You can specify a particular mode using the PagerView option in the\n\ configuration file or the --pager-view command line option. Possibles values:\n\n\ 'auto': Use the current listing mode (default)\n\ 'long': List files in long view\n\ 'short': List files in short view\n\n\ Note: You can also try the 'gg' plugin (just enter 'gg')." #define PC_USAGE "Edit file permissions\n\n\ \x1b[1mUSAGE\x1b[22m\n\ pc FILE...\n\n\ \x1b[1mEXAMPLES\x1b[22m\n\ - Edit permissions of the file named 'file.txt'\n\ pc file.txt\n\ - Edit permissions of all selected files at once\n\ pc sel\n\n\ When editing multiple files with different permissions at once, only\n\ shared permission bits will be set in the permissions template.\n\n\ The new permissions set will be applied to each specified file.\n\n\ Both symbolic and octal notation for the new permissions set are\n\ allowed.\n\n\ Note: Use the 'oc' command to edit file ownership." #define PIN_USAGE "Pin a file or directory\n\n\ \x1b[1mUSAGE\x1b[22m\n\ pin FILE/DIR\n\n\ \x1b[1mEXAMPLES\x1b[22m\n\ - Pin the directory '~/my_important_dir'\n\ pin ~/my_important_dir\n\ - Change to the pinned directory\n\ , (yes, just a comma)\n\ - Unpin the currently pinned directory\n\ unpin" #define PROFILES_USAGE "Manage profiles\n\n\ \x1b[1mUSAGE\x1b[22m\n\ pf, profile [list | set, add, del PROFILE | rename PROFILE NEW_NAME]\n\n\ \x1b[1mEXAMPLES\x1b[22m\n\ - Print the current profile name\n\ pf\n\ - List available profiles\n\ pf list\n\ - Switch to the profile 'myprofile'\n\ pf set myprofile (or 'pf set ' to select from a list)\n\ - Add a new profile named new_profile\n\ pf add new_profile\n\ - Remove the profile 'myprofile'\n\ pf del myprofile (or 'pf del ' to select from a list)\n\ - Rename the profile 'myprofile' as 'cool_name'\n\ pf rename myprofile cool_name" #define PROMPT_USAGE "Change the current prompt\n\n\ \x1b[1mUSAGE\x1b[22m\n\ prompt [set NAME | list | unset | edit [APP] | reload]\n\n\ \x1b[1mEXAMPLES\x1b[22m\n\ - List available prompts\n\ prompt list (or 'prompt set ' to select from a list)\n\ - Change prompt to the prompt named MYPROMPT\n\ prompt set MYPROMPT\n\ Since 'set' is the default action, it can be omitted: 'prompt MYPROMPT'\n\ - Edit the prompts file\n\ prompt edit\n\ - Edit the prompts file with vi\n\ prompt edit vi\n\ - Set the default prompt\n\ prompt unset\n\ - Reload available prompts\n\ prompt reload\n\n\ Note: To permanently set a new prompt edit the current\n\ color scheme file ('cs edit'), and set the Prompt field to\n\ whatever prompt you like." #define PROP_USAGE "Print file properties\n\n\ \x1b[1mUSAGE\x1b[22m\n\ p, pp, prop FILE...\n\n\ \x1b[1mEXAMPLES\x1b[22m\n\ - Print the properties of the file whose ELN is 12\n\ p 12 (or 'p ' to select from a list)\n\ - Print the properties of all selected files\n\ p sel\n\ - Print the properties of the directory 'dir' (including recursive size)\n\ pp dir\n\n\ Note that, in case of symbolic links to directories, the 'p' command displays\n\ information about the link target if the provided filename ends with a slash.\n\ Otherwise, information about the link itself is displayed.\n\ Unlike 'p', however, 'pp' always dereferences symbolic links." #define PWD_DESC "Print the name of the current working directory\n\n\ \x1b[1mUSAGE\x1b[22m\n\ pwd [-L | -P]\n\n\ \x1b[1mEXAMPLES\x1b[22m\n\ - Print the logical working directory (do not resolve symlinks)\n\ pwd (or 'pwd -L')\n\ - Print the physical working directory (resolve all symlinks)\n\ pwd -P" #define QUIT_HELP "Exit Clifm\n\n\ \x1b[1mUSAGE\x1b[22m\n\ q, quit, exit\n\n\ To enable the cd-on-quit function consult the manpage." #define RELOAD_USAGE "Reload the main configuration file and update settings accordingly\n\n\ \x1b[1mUSAGE\x1b[22m\n\ rl, reload (or 'config reload')" #define RR_USAGE "Remove files in bulk using a text editor\n\n\ \x1b[1mUSAGE\x1b[22m\n\ rr [DIR] [:EDITOR]\n\n\ The list of files in DIR (current directory if omitted) is opened via\n\ EDITOR (default associated application for text files if omitted). Remove\n\ the lines corresponding to the files you want to delete, save, and quit\n\ the editor (quit without saving to cancel the operation).\n\n\ \x1b[1mEXAMPLES\x1b[22m\n\ - Bulk remove files/dirs in the current directory using the default editor\n\ rr\n\ - Bulk remove files/dirs in the current directory using nano\n\ rr :nano\n\ - Bulk remove files/dirs in the directory 'mydir' using vi\n\ rr mydir :vi" #define SEARCH_USAGE "Search for files using either glob or regular expressions\n\n\ \x1b[1mUSAGE\x1b[22m\n\ /PATTERN [-filetype] [-x] [DIR]\n\n\ \x1b[1mEXAMPLES\x1b[22m\n\ - List all PDF files in the current directory\n\ /*.pdf (or, as a regular expression, '/.*\\.pdf$')\n\ - List all files starting with 'A' in the directory whose ELN is 7\n\ /A* 7\n\ - List all .conf files in the directory '/etc'\n\ /*.conf /etc\n\n\ You can further filter the search using a file type filter:\n\ -b block device\n\ -c character device\n\ -d directory\n\ -f regular file\n\ -l symlink\n\ -p FIFO/pipe\n\ -s socket\n\ - For example, to list all directories containing a dot or a dash and ending \ with 'd' in the directory named 'Documents'\n\ /[.-].*d$ -d Documents/\n\n\ To perform a recursive search, use the -x modifier (file types not allowed)\n\ /str -x /boot\n\n\ To search for files by content instead of names, use the rgfind plugin, bound\n\ by default to the \"//\" action name. For example:\n\ // content I\\'m looking for\n\n\ Note: This plugin requires fzf and rg (ripgrep)." #define SECURITY_USAGE "Clifm offers three distinct security mechanisms:\n\n\ 1. Stealth Mode (Incognito/Private Mode): In this mode, no files are read\n\ from or written to the filesystem unless explicitly requested by the user\n\ through a command.\n\ Default values are used.\n\ You can enable this mode using the -S or --stealth-mode command line switch.\n\n\ 2. Secure Environment: Clifm operates within a sanitized environment where most\n\ environment variables are cleared, and a select few are set to secure defaults.\n\ This mode can be activated with the --secure-env or --secure-env-full command\n\ line switches.\n\n\ 3. Secure Commands: Automatically executed shell commands (such as autocommands,\n\ (un)mounting, and opening applications) are sanitized prior to execution. A\n\ secure environment is established, and commands are validated against a\n\ whitelist to prevent unexpected or insecure behavior, as well as command\n\ injection. To enable this mode, use the --secure-cmds command line switch." #define SEL_USAGE "Select one or multiple files\n\n\ \x1b[1mUSAGE\x1b[22m\n\ s, sel FILE... [[!]PATTERN] [-FILETYPE] [:PATH]\n\n\ Recognized file types: (d)irectory, regular (f)ile, symbolic (l)ink,\n\ (s)ocket, fifo/(p)ipe, (b)lock device, (c)haracter device\n\n\ \x1b[1mEXAMPLES\x1b[22m\n\ - Select the file whose ELN is 12\n\ s 12 (or 's ' to select from a list - multi-selection is allowed)\n\ - Select all files ending with .odt:\n\ s *.odt\n\ - Select multiple files at once\n\ s 12 15-21 *.pdf\n\ - Select all regular files in the directory '/etc' starting with 'd'\n\ s ^d.* -f :/etc\n\ - Select all files in the current directory (including hidden files)\n\ s * .* (or Alt+a)\n\ - Interactively select files in '/media' (requires fzf, fnf, or smenu\n\ tab completion modes)\n\ s /media/*\n\ - List currently selected files\n\ sb\n\ - Copy selected files to the current directory:\n\ c sel\n\ - Move selected files to the directory whose ELN is 24\n\ m sel 24\n\ - Deselect all files\n\ ds * (or Alt+d)\n\ - Deselect files selectively\n\ ds (multi-selection is allowed)" #define SORT_USAGE "Change file sort preferences\n\n\ \x1b[1mUSAGE\x1b[22m\n\ st [METHOD] [rev]\n\n\ Available methods: 0=none, 1=name, 2=size, 3=atime, 4=btime,\n\ 5=ctime, 6=mtime, 7=version, 8=extension, 9=inode, 10=owner,\n\ 11=group, 12=blocks, 13=links, and 14=type.\n\n\ \x1b[1mEXAMPLES\x1b[22m\n\ - List files by size\n\ st size (or 'st ' to select from a list)\n\ Numbers can be used as well (e.g. 'st 2')\n\ - Revert the current sort order (e.g. z-a instead of a-z)\n\ st rev\n\ - Both of the above at once\n\ st size rev\n\n\ Tip: Take a look at the configuration file for extra sort\n\ options (ListDirsFirst, PrioritySortChar, ShowHiddenFiles)." #define TAG_USAGE "(Un)tag files and/or directories\n\n\ \x1b[1mUSAGE\x1b[22m\n\ tag [add | del | list | list-full | merge | new | rename | untag]\n\ [FILE...] [[:]TAG]\n\n\ Instead of the long format described above, you can use any of the\n\ following shortcuts as well:\n\n\ ta: Tag files as ... (same as 'tag add')\n\ td: Delete tag(s) (same as 'tag del')\n\ tl: List tags/tagged files (same as 'tag list')\n\ tm: Rename tag (same as 'tag rename')\n\ tn: Create new tag(s) (same as 'tag new')\n\ tu: Untag file(s) (same as 'tag untag')\n\ ty: Merge two tags (same as 'tag merge')\n\n\ \x1b[1mEXAMPLES\x1b[22m\n\ - List available tags\n\ tag list (or 't:')\n\ - List available tags and each tagged file\n\ tag list-full\n\ - List files tagged as 'pdf'\n\ tag list pdf (or 't:pdf')'\n\ - List tags applied to the file 'file.txt'\n\ tag list file.txt\n\ - Tag all .PNG files in the current directory as both 'images' and 'png'\n\ tag add *.png :images :png\n\ Note: Tags are created if they do not exist.\n\ Note 2: Since 'add' is the default action, it can be omitted.\n\ - Tag all selected files as 'special'\n\ tag add sel :special\n\ - Rename tag 'documents' to 'docs'\n\ tag rename documents docs\n\ - Merge tag 'png' into 'images'\n\ tag merge png images\n\ Note: All files tagged as 'png' will be now tagged as 'images',\n\ and the 'png' tag will be removed.\n\ - Remove the tag 'images' (untag all files tagged as 'images')\n\ tag del images\n\ - Untag a few files from the 'work' tag\n\ tag untag :work file1 image.png dir2\n\ or\n\ tag untag : (and then TAB again to select tagged files)\n\n\ Operating on tagged files (t:TAG)\n\ - Print the file properties of all files tagged as 'docs'\n\ p t:docs (or 'p t:' to select from a list)\n\ - Remove all files tagged as 'images'\n\ r t:images\n\ - Run stat(1) over all files tagged as 'work' and all files tagged as\n\ 'docs'\n\ stat t:work t:docs\n\n\ To operate only on some tagged files use TAB as follows:\n\ t:TAG (multi-selection is allowed)\n\ Mark the files you need via TAB and then press Enter or Right." #define TE_USAGE "Toggle the executable bit on files\n\n\ \x1b[1mUSAGE\x1b[22m\n\ te FILE...\n\ or\n\ 'te ' to select from a list (multi-selection is allowed)\n\n\ \x1b[1mEXAMPLES\x1b[22m\n\ - Set the executable bit on all shell scripts in the current directory\n\ te *.sh\n\ - Set the executable bit on all selected files\n\ te sel" #define TRASH_USAGE "Move files to the trash can\n\n\ \x1b[1mUSAGE\x1b[22m\n\ t, trash [FILE... | del [FILE]... | empty | list]\n\n\ \x1b[1mEXAMPLES\x1b[22m\n\ - Trash the file whose ELN is 12\n\ t 12\n\ or\n\ 't ' to select from a list (multi-selection is allowed)\n\ - Trash all files ending with .sh\n\ t *.sh\n\ - List currently trashed files\n\ t (or 't list', or 't ')\n\ - Remove/delete trashed files using a menu (permanent removal)\n\ t del (or 't del ')\n\ - Remove/delete all files from the trash can (permanent removal)\n\ t empty\n\ - Restore all trashed files (to their original location)\n\ u *\n\ - Restore trashed files selectively using a menu\n\ u\n\ or\n\ 'u ' to select from a list (multi-selection is allowed)\n\n\ Note: For more information try 'u --help'." #define UMASK_USAGE "Get/set the file mode creation mask\n\n\ \x1b[1mUSAGE\x1b[22m\n\ umask [MODE]\n\n\ Note: MODE is an octal value from 000 to 777.\n\n\ \x1b[1mEXAMPLES\x1b[22m\n\ - Get the current value\n\ umask\n\ - Set mask to 077\n\ umask 077\n\n\ Note: To permanently set the umask, use the Umask option in the config file." #define UNSET_USAGE "Delete variables from the environment\n\n\ \x1b[1mUSAGE\x1b[22m\n\ unset NAME..." #define UNTRASH_USAGE "Restore files from the trash can\n\n\ \x1b[1mUSAGE\x1b[22m\n\ u, untrash [FILE... | *, a, all]\n\n\ \x1b[1mEXAMPLES\x1b[22m\n\ - Restore all trashed files (to their original location)\n\ u *\n\ - Restore trashed files selectively using a menu\n\ u\n\ or\n\ 'u ' to select from a list (multi-selection is allowed)\n\n\ Note: Use the 'trash' command to trash files. Try 'trash --help'." #define VV_USAGE "Copy files to a directory and bulk rename them at once\n\n\ \x1b[1mUSAGE\x1b[22m\n\ vv FILE... DIR\n\n\ \x1b[1mEXAMPLES\x1b[22m\n\ - Copy selected files to 'mydir' and rename them\n\ vv sel mydir\n\ - Copy all PDF files to the directory whose ELN is 4 and rename them\n\ vv *.pdf 4\n\n\ Note: If DIR does not exist, it will be created." #define VIEW_USAGE "Preview files in the current directory (requires fzf)\n\n\ \x1b[1mUSAGE\x1b[22m\n\ view [edit [APP] | purge]\n\n\ \x1b[1mEXAMPLES\x1b[22m\n\ - Just run the previewer\n\ view (or Alt+-)\n\ Note: Select files using the TAB key.\n\ - Edit the configuration file\n\ view edit (or F7)\n\ - Edit the configuration file using vi\n\ view edit vi\n\ - Purge the thumbnails directory(1) of dangling thumbnails\n\ view purge\n\ - Add/modify the default previewing application for 'myfile'\n\ 1) Determine the MIME type (or filename) of the file\n\ mm info myfile\n\ 2) Edit the mimelist file\n\ view edit (or F7)\n\ Once in the file, find the appropriate entry and add/modify\n\ the desired previewing application.\n\ For more information consult the manpage.\n\n\ (1) $XDG_CACHE_HOME/clifm/thumbnails\n\n\ Enter 'help file-previews' for more information." #define WRAPPERS_USAGE "c, m, and r commands are wrappers for \ cp(1), mv(1), and rm(1) shell\ncommands, respectively.\n\n\ \x1b[1mUSAGE\x1b[22m\n\ c -> cp -iRp\n\ m -> mv -i\n\ r -> rm ('rm -r' for directories) (1)\n\n\ (1) By default, the user will asked for confirmation (set rmForce to true\n\ in the configuration file to disable the confirmation prompt).\n\n\ The 'paste' command is equivalent to 'c' and exists only for semantic\n\ reasons: if you want to copy selected files to the current directory, it\n\ makes sense to write 'paste sel'.\n\n\ By default, both the 'c' and 'm' commands run cp(1)/mv(1) interactively\n\ (-i), i.e. prompting before overwriting a file. To run non-interactively\n\ instead, use the -f, --force parameter (see the examples below). You can\n\ also permanently run in non-interactive mode using the cpCmd/mvCmd options\n\ in the configuration file ('config' or F10).\n\n\ Just as 'c' and 'm', the 'r' command accepts -f, --force as paramater to\n\ prevent 'r' from prompting before removals. Set rmForce to true in the\n\ configuration file to make this option permanent.\n\n\ To use different parameters, run the corresponding utility as usual.\n\ For example: cp -abf ...\n\n\ \x1b[1mEXAMPLES\x1b[22m\n\ - Create a copy of 'file1' named 'file2'\n\ c file1 file2\n\ - Create a copy of 'file1' in the directory 'dir1' named 'file2'\n\ c file1 dir1/file2\n\ - Copy all selected files to the current directory\n\ c sel\n\ Note: If destination directory is omitted, the current directory is assumed.\n\ - Copy all selected files to the current directory (non-interactively):\n\ c -f sel\n\ - Move all selected files to the directory named 'testdir'\n\ m sel testdir\n\ - Rename 'file1' as 'file_test'\n\ m file1 file_test\n\ - Interactively rename 'file1'\n\ m file1\n\ Note: The user is prompted to enter a new name using the old name as\n\ template.\n\ - Move all selected files to the current directory (non-interactively)\n\ m -f sel\n\ - Remove all selected files\n\ r sel\n\ - Remove all selected files (non-interactively)\n\ r -f sel\n\ Note: Use the 't' command to move files to the trash can. Try 't --help'.\n\n\ To create files and directories, you can use the 'md' and 'n' commands.\n\ Try 'md --help' and 'n --help' for more details.\n\n\ Use the 'vv' command to copy files to a directory and bulk rename them\n\ at once. Try 'vv --help'.\n\n\ Use the 'cr' plugin to copy a file to a remote location:\n\ cr FILE (run 'cr --edit' before to set up your remotes)\n\n\ Use the 'l' command to create symbolic links, and 'le' to edit them." #define WS_USAGE "Switch workspaces\n\n\ \x1b[1mUSAGE\x1b[22m\n\ ws [NUM/NAME [unset] | + | -]\n\n\ \x1b[1mEXAMPLES\x1b[22m\n\ - List available workspaces\n\ ws (or 'ws ')\n\ - Switch to the first workspace\n\ ws 1 (or Alt+1)\n\ - Switch to the workspace named 'main'\n\ ws main\n\ - Switch to the next workspace\n\ ws +\n\ - Switch to the previous workspace\n\ ws -\n\ - Unset the workspace number 2\n\ ws 2 unset\n\n\ Note: Use the WorkspaceNames option in the configuration file to name\n\ your workspaces." #define X_USAGE "Launch a new instance of Clifm in a new terminal window\n\n\ \x1b[1mUSAGE\x1b[22m\n\ x, X [DIR]\n\n\ \x1b[1mEXAMPLES\x1b[22m\n\ - Launch a new instance in the current directory\n\ x\n\ - Open the directory 'mydir' in a new instance\n\ x mydir\n\ - Launch a new instance as root\n\ X\n\n\ Note: By default, xterm is used. Set your preferred terminal\n\ emulator using the TerminalCmd option in the configuration file." /* Misc messages */ #define PAGER_HELP "? / h: Display this help message\n\ Down arrow / Enter / Space: Advance one line\n\ Page Down: Advance one page\n\ q: Quit paging (without printing remaining files)\n\ c: Quit paging (printing remaining files)\n" #define PAGER_LABEL "\x1b[7m--Mas-- (press 'h' for help)\x1b[0m" #define NOT_AVAILABLE "This feature has been disabled at compile time" #define STEALTH_DISABLED "Access to configuration files is not allowed in stealth mode" #define CONFIG_FILE_UPDATED "File modified. Settings updated.\n" #ifndef __HAIKU__ # define HELP_MESSAGE "Enter '?' or press F1-F3 for help" #else # define HELP_MESSAGE "Enter '?' or press F5-F7 for help" #endif /* !__HAIKU__ */ #ifdef _BE_POSIX #define OPTIONS_LIST "\ \n -a[VAL] List hidden files ('first', 'last', 'true', or 'false')\ \n -A Do not list hidden files\ \n -b FILE Set an alternative bookmarks file\ \n -B NUM Set TAB-completion mode (NUM=[0-3])\ \n -c FILE Set an alternative main configuration file\ \n -C Do not clear the screen when changing directories\ \n -d Print disk usage (free/total)\ \n -D List directories only\ \n -e Force the use of the 'o/open' command to open files\ \n -E Force the use of 'cd' to change directories\ \n -f Display recursive directories sizes (long view only)\ \n -F Disable the file counter (directories)\ \n -g Display file sizes in SI units (powers of 1000) instead of 1024\ \n -G Display physical file sizes (disk usage) instead of logical sizes (apparent size)\ \n -h Print this help and exit\ \n -H Disable syntax-highlighting\ \n -i Enable icons\ \n -I DIR Set an alternative trash directory\ \n -j FILE Run the 'p' command on FILE and exit\ \n -J FILE Run the 'pp' command on FILE and exit\ \n -k FILE Set an alternative keybindings file\ \n -l Display extended file metadata (long view)\ \n -L Follow symbolic links when running in long view\ \n -m Enable fuzzy matching\ \n -M Disable colors\ \n -n Disable the command history\ \n -N Disable bold colors\ \n -o PATH Set a custom file opener (instead of the builtin Lira)\ \n -O FILE Open FILE (via Lira) and exit\ \n -p NAME Set/create the profile NAME\ \n -P FILE Generate a preview of FILE and exit\ \n -q List files and quit\ \n -Q Enable cd-on-quit (consult the manpage)\ \n -r Files removed via the 'r' command are sent to the trash can\ \n -R Do not append file type indicators\ \n -s Run in stealth mode (incognito)\ \n -S Disable suggestions\ \n -t NAME Use the color scheme NAME\ \n -T Do not truncate filenames\ \n -u Run in disk usage analyzer mode\ \n -U Disable Unicode decorations\ \n -v Print version information and exit\ \n -V DIR Set a custom virtual directory\ \n -w NUM Start in workspace NUM (1-8)\ \n -W Keep the list of selected files in sight\ \n -x Run in secure-environment mode\ \n -X Run in secure-environment mode (paranoid)\ \n -y Run in light mode\ \n -Y Run in secure-commands mode\ \n -z NUM Set a file sort order (1-13)\ \n -Z NUM List only up to NUM files" #else #define SHORT_OPTIONS "\ \n -a, --show-hidden[=VAL]\t Show hidden files ('first', 'last', 'true', or 'false')\ \n -A, --no-hidden\t\t Do not show hidden files\ \n -b, --bookmarks-file=FILE\t Set an alternative bookmarks file\ \n -c, --config-file=FILE\t Set an alternative configuration file\ \n -D, --config-dir=DIR\t\t Set an alternative configuration directory\ \n -e, --no-eln\t\t\t Do not print ELNs (Entry List Numbers)\ \n -E, --eln-use-workspace-color\t ELNs use the current workspace color\ \n -f, --dirs-first\t\t List directories first (default)\ \n -F, --no-dirs-first\t\t Do not list directories first\ \n -g, --pager\t\t\t Enable the pager\ \n -G, --no-pager\t\t Disable the pager (default)\ \n -h, --help\t\t\t Show this help and exit\ \n -H, --horizontal-list\t\t List files horizontally\ \n -i, --no-case-sensitive\t Ignore case distinctions when listing files (default)\ \n -I, --case-sensitive\t\t Do not ignore case distinctions when listing files\ \n -k, --keybindings-file=FILE\t Set an alternative keybindings file\ \n -l, --long-view\t\t Display extended file metadata (long view)\ \n -L, --follow-symlinks-long\t Follow symbolic links when running in long view\ \n -m, --dirhist-map\t\t Enable the directory history map\ \n -o, --autols\t\t\t List files automatically (default)\ \n -O, --no-autols\t\t Do not list files automatically\ \n -P, --profile=NAME\t\t Use (or create) NAME as profile\ \n -r, --no-refresh-on-empty-line Do not refresh the list of files when pressing Enter \ on an empty line\ \n -s, --splash\t\t\t Enable the splash screen\ \n -S, --stealth-mode\t\t Run in incognito/private mode\ \n -t, --disk-usage-analyzer\t Run in disk usage analyzer mode\ \n -T, --trash-dir=DIR\t\t Set an alternative trash directory\ \n -v, --version\t\t\t Show version details and exit\ \n -w, --workspace=NUM\t\t Start in the workspace NUM\ \n -x, --no-ext-cmds\t\t Disallow the use of external commands\ \n -y, --light-mode\t\t Run in light mode\ \n -z, --sort=METHOD\t\t Sort files by METHOD (for available methods see the manpage)" #define LONG_OPTIONS_A "\ \n --bell=STYLE\t\t Set terminal bell style to: 0 (none), 1 (audible), 2 (visible), 3 (flash)\ \n --case-sens-dirjump\t Do not ignore case when consulting the jump \ database (via the 'j' command)\ \n --case-sens-path-comp\t Enable case sensitive path completion\ \n --cd-on-quit\t\t Enable cd-on-quit functionality (see the manpage)\ \n --color-scheme=NAME\t Use the color scheme NAME\ \n --color-links-as-target\t Colorize symbolic links according to the target file\ \n --cwd-in-title\t\t Print the current directory in the terminal window title\ \n --data-dir=PATH\t\t Use PATH as data directory (e.g.: /usr/local/share)\ \n --desktop-notifications\t Set the desktop notifications style: 'kitty', 'system', or 'false' (default)\ \n --disk-usage\t\t Show disk usage (FREE/TOTAL (FREE %) TYPE DEVICE)\ \n --full-dir-size\t\t Display recursive directory sizes (long view only)\ \n --fuzzy-algo=NUM\t\t Set fuzzy algorithm for fuzzy matching (1 or 2)\ \n --fuzzy-matching\t\t Enable fuzzy tab completion/suggestions for filenames \ and paths\ \n --fzfpreview-hidden\t Enable file previews for tab completion (fzf mode only) with the preview window hidden (toggle with Alt+p)\ \n --icons\t\t\t Enable icons\ \n --icons-use-file-color\t Icon colors follow file colors\ \n --int-vars\t\t Enable the use internal variables\ \n --kitty-keys\t\t Ask the terminal to enable the kitty keyboard protocol\ \n --list-and-quit\t\t List files and quit\ \n --ls\t\t\t Short for --list-and-quit\ \n --lscolors\t\t Read file colors from LS_COLORS or LSCOLORS (FreeBSD style)\ \n --max-dirhist=NUM\t\t Maximum number of visited directories to recall\ \n --max-files=NUM\t\t List only up to NUM files\ \n --mimelist-file=FILE\t Set FILE as Lira's configuration file\ \n --mnt-udisks2\t\t Use udisks2(1) instead of udevil(1) for the 'media' command\ \n --no-bold\t\t\t Disable bold colors (applies to all color schemes)\ \n --no-cd-auto\t\t Disable the autocd function\ \n --no-classify\t\t Do not append file type indicators\ \n --no-clear-screen\t\t Do not clear the screen when listing files\ \n --no-color\t\t Disable colors \ \n --no-columns\t\t Disable columned file listing\ \n --no-file-cap\t\t Do not check file capabilities when listing files\ \n --no-file-ext\t\t Do not check file extensions when listing files\ \n --no-file-counter\t\t Disable the file counter for directories\ \n --no-follow-symlink\t Do not follow symbolic links when listing files (overrides -L and --color-links-as-target)\ \n --no-fzfpreview\t\t Disable file previews for tab completion (fzf mode only)\ \n --no-highlight\t\t Disable syntax highlighting\ \n --no-history\t\t Do not write commands to the history file\ \n --no-open-auto\t\t Same as no-cd-auto, but for files\ \n --no-refresh-on-resize\t Do not attempt to refresh the file list upon window's resize\ \n --no-restore-last-path\t Do not record the last visited directory\ \n --no-suggestions\t\t Disable auto-suggestions\ \n --no-tips\t\t\t Disable startup tips\ \n --no-truncate-names\t Do not truncate filenames\ \n --no-unicode\t\t Disable Unicode decorations\ \n --no-warning-prompt\t Disable the warning prompt\ \n --no-welcome-message\t Disable the welcome message\ \n --only-dirs\t\t List only directories and symbolic links to directories\ \n --open=FILE\t\t Open FILE (using Lira) and exit\ \n --opener=APPLICATION\t Use APPLICATION as file opener (instead of Lira, \ the builtin opener)\ \n --pager-view=MODE\t\t How to list files in the pager (auto, long, short)\ \n --physical-size\t\t Display physical file sizes (disk usage) rather than logical sizes (apparent size)\ \n --preview=FILE\t\t Display a preview of FILE (via Shotgun) and exit\ \n --print-sel\t\t Keep the list of selected files in sight\n" #define LONG_OPTIONS_B "\ --prop-fields=FORMAT\t Set a custom format string for the long view (see \ PropFields in the config file)\ \n --ptime-style=STYLE\t Time/date style used by the 'p/pp' command (see PTimeStyle in the config file)\ \n --readonly\t\t Disable internal commands able to modify the filesystem\ \n --report-cwd\t\t Report the current directory to the terminal (OSC-7)\ \n --rl-vi-mode\t\t Set readline to vi editing mode (defaults to emacs mode)\ \n --secure-cmds\t\t Sanitize commands to prevent command injection\ \n --secure-env\t\t Run in a sanitized environment (regular mode)\ \n --secure-env-full\t\t Run in a sanitized environment (full mode)\ \n --sel-file=FILE\t\t Set FILE as custom selections file\ \n --share-selbox\t\t Make the Selection Box common to different profiles\ \n --shotgun-file=FILE\t Set FILE as shotgun's configuration file\ \n --si\t\t\t Display file sizes in SI units (powers of 1000) instead of 1024\ \n --sort-reverse\t\t Sort in reverse order, e.g., z-a instead of a-z\ \n --stat FILE...\t\t Run the 'p' command on FILE(s) and exit\ \n --stat-full FILE...\t Run the 'pp' command on FILE(s) and exit\ \n --tabmode=MODE\t\t Set tab completion mode to one of 'fzf', 'fnf', 'smenu', or 'standard'\ \n --time-style=STYLE\t Time/date style used in long view (see TimeStyle in the config file)\ \n --trash-as-rm\t\t The 'r' command moves files to the trash instead of removing them\ \n --unicode\t\t\t Force the use of Unicode decorations\ \n --virtual-dir-full-paths\t Files in virtual directories are listed as full paths instead of target base names\ \n --virtual-dir=DIR\t\t Absolute path to a directory to be used as virtual directory\ \n --vt100\t\t\t Run in vt100 compatibility mode\n" #endif /* _BE_POSIX */ #define CLIFM_COMMANDS_HEADER "\ For a complete description of the below \ commands run 'cmd' (or press F2) or consult the manpage (F1).\n\ You can also try the interactive help plugin (it depends on FZF): just \ enter 'ih', that's it.\n\ Help topics are available as well. Type 'help ' to get a list of topics.\n\n\ The following is just a list of available commands and a brief description.\n\ For more information about a specific command run 'CMD -h' or 'CMD --help'.\n" #define CLIFM_COMMANDS "\ ELN/FILE/DIR Auto-open/autocd files/directories\n\ /PATTERN Search for files\n\ ;[CMD], :[CMD] Run CMD using the system shell\n\ ac, ad (De)archive files\n\ acd, autocd Turn auto-cd on/off\n\ actions Manage actions/plugins\n\ alias Manage aliases\n\ ao, auto-open Turn auto-open on/off\n\ auto Set an autocommand for the current directory\n\ b, back Change to the previously visited directory\n\ bb, bleach Sanitize non-ASCII filenames\n\ bd Change to a parent directory\n\ bl Create symbolic links in bulk\n\ bm, bookmarks Manage bookmarks\n\ br, bulk Rename files in bulk\n\ c, l, m, md, r Copy, link, move, makedir, and remove\n\ colors Preview the current color scheme\n\ cd Change directory\n\ cl, columns Toggle columns\n\ cmd, commands Jump to the COMMANDS section in the manpage\n\ config Open/edit the main configuration file\n\ cs, colorscheme Switch/edit color schemes\n\ d, dup Duplicate files\n\ dh Access the directory history list\n\ ds, desel Deselect files\n\ exp Export filenames to a temporary file\n\ ext Turn external/shell commands on/off\n\ f, forth Change to the next visited directory\n\ fc Toggle the file-counter\n\ ff, dirs-first Toggle list-directories-first\n\ ft, filter Set a file filter\n\ fz Display recursive directory sizes (long view only)\n\ hh, hidden Toggle hidden files\n\ history Manage the commands history\n\ icons Toggle icons\n\ k Toggle follow-links (long view only)\n\ kk Toggle max-filename-len\n\ j Jump to a visited directory\n\ kb, keybinds Manage keybindings\n\ le Edit symbolic link target\n\ ll, lv Toggle the long-view\n\ lm Toggle the light-mode\n\ log Manage your logs\n\ media (Un)mount storage devices\n\ mf Limit the number of listed files\n\ mm, mime Manage default opening applications\n\ mp, mountpoints Change to a mountpoint\n\ msg, messages Print system messages\n\ n, new Create new files/directories\n\ net Manage network/remote resources\n\ o, open Open a file\n\ oc Change ownership of files interactively\n\ ow Open a file with ...\n\ opener Set a custom file opener\n\ p, pp, prop Print file properties\n\ pc Change permissions of files interactively\n\ pf, profile Manage profiles\n\ pg, pager Turn the file pager on/off\n\ pin Pin a directory\n\ prompt Switch/edit the prompt\n\ q, quit, exit Quit Clifm\n\ rf, refresh Refresh/clear the screen\n\ rl, reload Reload the main configuration file\n\ rr Remove files in bulk\n\ s, sel Select files\n\ sb, selbox Access the Selection Box\n\ st, sort Change file sort order\n\ stats Print file statistics\n\ t, trash Move files to the trash can\n\ tag Tag files\n\ te Toggle the executable bit on files\n\ tips Print tips\n\ u, untrash Restore trashed files (using a menu)\n\ unpin Unpin the pinned directory\n\ vv Copy and rename files at once\n\ ver, version Print version information\n\ view Preview files in the current directory\n\ ws Switch workspaces\n\ x, X Launch a new instance of Clifm (as root if 'X')\n\n\ Shell-builtin implementations\n\ export Export variables to the environment\n\ pwd Print the current working directory\n\ umask Get/set umask\n\ unset Remove variables from the environment\n" #define CLIFM_KEYBOARD_SHORTCUTS "DEFAULT KEYBOARD SHORTCUTS:\n\n\ Right, Ctrl+f Accept the entire suggestion\n\ Alt+Right, Alt+f Accept the first suggested word\n\ Alt+c Clear the current command line buffer\n\ Alt+q Delete the last entered word\n\ Alt+g Toggle list-directories-first\n\ Alt+l Toggle long-view\n\ Alt++ Toggle follow-links (long view only)\n\ Alt+. Toggle hidden-files\n\ Alt+, Toggle list-only-directories\n\ Alt+- Preview files in the current directory (requires fzf)\n\ Alt+m List mountpoints\n\ Alt+h Show directory history\n\ Alt+t Clear messages\n\ Ctrl+l Clear the screen\n\ Ctrl+y Copy the current line buffer to the clipboard\n\ Alt+s Open the Selection Box\n\ Alt+a Select all files in the current directory\n\ Alt+d Deselect all files\n\ Alt+r Change to the root directory\n\ Alt+e, Home Change to the home directory\n\ Alt+u, Shift+Up Change to the parent directory\n\ Alt+j, Shift+Left Change to previously visited directory\n\ Alt+k, Shift+Right Change to next visited directory\n\ Alt+p Change to the pinned directory\n\ Alt+v Toggle prepend sudo\n\ Alt+0 Run the file pager\n\ Alt+[1-4] Switch to workspace 1-4\n\ Ctrl+Alt+o Switch to previous profile\n\ Ctrl+Alt+p Switch to next profile\n\ Ctrl+Alt+a Archive selected files\n\ Ctrl+Alt+e Export selected files\n\ Ctrl+Alt+r Rename selected files\n\ Ctrl+Alt+d Remove selected files\n\ Ctrl+Alt+t Trash selected files\n\ Ctrl+Alt+n Move selected files to the current directory\n\ Ctrl+Alt+v Copy selected files to the current directory\n\ Ctrl+Alt+l Toggle max-name-length\n\ Alt+y Toggle light-mode\n\ Alt+z Switch to the previous sort method\n\ Alt+x Switch to the next sort method\n\ Ctrl+Alt+x Launch a new instance\n\ F1 Manual page\n\ F2 Commands help\n\ F3 Keybindings help\n\ F6 Open the mimelist file\n\ F7 Open the shotgun configuration file\n\ F8 Open the current color scheme file\n\ F9 Open the keybindings file\n\ F10 Open the configuration file\n\ F11 Open the bookmarks file\n\ F12 Quit\n" #define HELP_END_NOTE "For a full description consult the manpage and/or the \ Wiki (https://github.com/leo-arch/clifm/wiki)." #define ASCII_LOGO "\ _______ _ \n\ | ,---, | | |\n\ | | | | | |\n\ | | | | | |\n\ | | | | | |\n\ | !___! !___! |\n\ `-------------'\n" #define QUICK_HELP_HEADER "\ This is only a quick start guide. For more information and advanced tricks \n\ consult the manpage and/or the Wiki (https://github.com/leo-arch/clifm/wiki)\n\ For a brief description of available commands type 'cmd'\n\ Help topics are also available: 'help '" #define QUICK_HELP_NAVIGATION "\ NAVIGATION\n\ ----------\n\ /etc Change the current directory to '/etc'\n\ 5 Change to the directory whose ELN is 5\n\ b | Shift+left | Alt+j Change to the previously visited directory\n\ f | Shift+right | Alt+k Change to the next visited directory\n\ .. | Shift+up | Alt+u Change to the parent directory\n\ bd media Change to the parent directory matching 'media'\n\ j | dh Browse the directory history list\n\ j xproj Jump to the best ranked directory matching 'xproj'\n\ bm | b: | Alt+b List bookmarks\n\ bm mybm | b:mybm Change to the bookmark named 'mybm'\n\ ws2 | Alt+2 Switch to the second workspace\n\ mp Change to a mountpoint\n\ pin mydir Pin the directory 'mydir'\n\ , Change to the pinned directory\n\ x Run new instance in the current directory\n\ /*.pdf File-name filter: List all PDF files in the current directory\n\ =x File-type filter: List all executable files in the current directory (1)\n\ @gzip MIME-type filter: List all gzip files in the current directory (1)\n\ view | Alt+- Preview files in the current directory (requires fzf)\n\n\ (1) Run 'help file-filters' for more information" #define QUICK_HELP_BASIC_OPERATIONS "\ BASIC FILE OPERATIONS\n\ ---------------------\n\ myfile.txt Open 'myfile.txt' with the default associated application\n\ myfile.txt vi Open 'myfile.txt' with vi (also 'vi myfile.txt')\n\ 12 Open the file whose ELN is 12\n\ 12& Open the file whose ELN is 12 in the background\n\ ow 10 | ow 10 Select opening application for the file whose ELN is 10\n\ p 4 Print file properties of the file whose ELN is 4\n\ /*.png Search for files ending with .png in the current directory\n\ s *.c Select all C files\n\ s 1-4 8 19-26 Select multiple files by ELN\n\ sb | s: List currently selected files\n\ ds | ds Deselect a few files\n\ ds * | Alt+d Deselect all files\n\ bm add mydir mybm Bookmark the directory named 'mydir' as 'mybm'\n\ bm del mybm Remove the bookmark named 'mybm'\n\ tag --help Learn about file tags\n\ n myfile Create a new file named 'myfile'\n\ n mydir/ Create a new directory named 'mydir'\n\ c sel Copy selected files to the current directory (1)\n\ r sel Remove all selected files (1)\n\ br sel Bulk rename selected files (1)\n\ c 34 file_copy Copy the file whose ELN is 34 to 'file_copy'\n\ cr myfile Copy 'myfile' to a remote location\n\ m 45 3 Move the file whose ELN is 45 to the dir whose ELN is 3\n\ m myfile.txt Interactively rename 'myfile.txt'\n\ l myfile mylink Create a symbolic link named 'mylink' pointing to 'myfile'\n\ le mylink Edit the symbolic link 'mylink'\n\ oc myfile Edit ownership of the file 'myfile'\n\ pc myfile Edit permissions of the file 'myfile'\n\ te *.sh Toggle the executable bit on all .sh files\n\ t 12-18 Move files whose ELNs are 12-18 to the trash can\n\ t del | t del Permanently remove trashed files using a menu\n\ t empty Empty the trash can\n\ u | u Untrash files using a menu\n\ ac sel Compress/archive selected files (1)\n\n\ (1) 's:' can be used instead of the 'sel' keyword" #define QUICK_HELP_MISC "\ MISC\n\ ----\n\ CMD --help Get help for the command CMD\n\ help List available help topics\n\ F1 Open the manpage\n\ ih Run the interactive help plugin (requires fzf)\n\ ll | Alt+l Toggle long view\n\ hh | Alt+. Toggle hidden files\n\ rf | Ctrl+l Clear the screen (also Enter on empty line)\n\ pg | Alt+0 Run the pager (builtin)\n\ gg Run the pager (plugin)\n\ auto Add an autocommand to the current directory\n\ config | F10 View/edit the configuration file\n\ mm edit | F6 Change default opening applications\n\ view edit | F7 Change default previewing applications\n\ kb bind List available functions for binding\n\ kb bind FUNC Bind FUNC to a new key sequence\n\ kb edit | F9 Manually edit the keybindings file\n\ mm info 12 Get MIME information for the file whose ELN is 12\n\ Alt+Tab Toggle the disk usage analyzer mode\n\ cs Manage color schemes\n\ Right Accept the entire suggestion\n\ Alt+f Accept the first/next word of the current suggestion\n\ pf set test Change to the profile named 'test'\n\ st size rev Sort files by size in reverse order\n\ Alt+x | Alt+z Switch to next/previous sort order\n\ media (Un)mount storage devices\n\ net work Mount the network resource named 'work'\n\ actions List available actions/plugins\n\ icons on Enable icons\n\ q | F12 I'm tired, quit" #define ASCII_LOGO_BIG "\ .okkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkd. \n\ 'kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkc\n\ xkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk\n\ xkkkkkc::::::::::::::::::dkkkkkkc:::::kkkkkk\n\ xkkkkk'..................okkkkkk'.....kkkkkk\n\ xkkkkk'..................okkkkkk'.....kkkkkk\n\ xkkkkk'.....okkkkkk,.....okkkkkk'.....kkkkkk\n\ xkkkkk'.....dkkkkkk;.....okkkkkk'.....kkkkkk\n\ xkkkkk'.....dkkkkkk;.....okkkkkk'.....kkkkkk\n\ xkkkkk'.....dkkkkkk;.....okkkkkk'.....kkkkkk\n\ xkkkkk'.....dkkkkkk;.....okkkkkk'.....kkkkkk\n\ xkkkkk'.....dkkkkkk;.....okkkkkk'.....kkkkkk\n\ xkkkkk'.....dkkkkkk;.....okkkkkk'.....kkkkkk\n\ xkkkkk'.....dkkkkkk;.....okkkkkk'.....kkkkkk\n\ xkkkkk'.....dkkkkkk;.....okkkkkk'.....kkkkkk\n\ xkkkkk'.....coooooo'.....:llllll......kkkkkk\n\ xkkkkk'...............................kkkkkk\n\ xkkkkk'...............................kkkkkk\n\ xkkkkklccccccccccccccccccccccccccccccckkkkkk\n\ lkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkx\n\ ;kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkc \n\ :c::::::::::::::::::::::::::::::::::." /* Brief commands description */ #define AC_DESC " (archive/compress files)" #define ACD_DESC " (toggle autocd)" #define ACTIONS_DESC " (manage actions/plugins)" #define AD_DESC " (dearchive/decompress files)" #define ALIAS_DESC " (list aliases)" #define AO_DESC " (toggle auto-open)" #define AUTO_DESC " (set a temporary autocommand)" #define B_DESC " (change to the previously visited directory)" #define BD_DESC " (change to a parent directory)" #define BL_DESC " (create symbolic links in bulk)" #define BB_DESC " (sanitize non-ASCII filenames)" #define BM_DESC " (manage bookmarks)" #define BR_DESC " (rename files in bulk)" #define C_DESC " (copy files)" #define CD_DESC " (change directory)" #define CL_DESC " (toggle columns)" #define CMD_DESC " (jump to the COMMANDS section in the manpage)" #define COLORS_DESC " (preview the current color scheme)" #define CONFIG_DESC " (edit the main configuration file)" #define CS_DESC " (manage color schemes)" #define CWD_DESC " (print the current directory)" #define D_DESC " (duplicate files)" #define DH_DESC " (query the directory history list)" #define DS_DESC " (deselect files)" #define EXP_DESC " (export filenames to a temporary file)" #define EXT_DESC " (turn external/shell commands on/off)" #define F_DESC " (change to the next visited directory)" #define FC_DESC " (toggle the file-counter)" #define FF_DESC " (toggle list-directories-first)" #define FT_DESC " (set a file filter)" #define FZ_DESC " (display recursive directory sizes - long view only)" #define HF_DESC " (toggle hidden files)" #define HIST_DESC " (manage the command history)" #define ICONS_DESC " (toggle icons)" #define J_DESC " (jump to a visited directory)" #define K_DESC " (toggle follow-links - long view only)" #define KK_DESC " (toggle max-filename-len)" #define KB_DESC " (manage keybindings)" #define L_DESC " (create a symbolic link)" #define LE_DESC " (edit a symbolic link)" #define LL_DESC " (toggle the long-view)" #define LM_DESC " (toggle the light-mode)" #define LOG_DESC " (manage logs)" #define M_DESC " (move/rename files)" #define MD_DESC " (create directories)" #define MEDIA_DESC " (mount/unmount storage devices)" #define MF_DESC " (limit the number of listed files)" #define MM_DESC " (manage opening applications)" #define MP_DESC " (change to a mountpoint)" #define MSG_DESC " (print program messages)" #define N_DESC " (create files)" #define NET_DESC " (manage remote resources)" #define O_DESC " (open file)" #define OC_DESC " (change file ownership)" #define OPENER_DESC " (set a custom file opener)" #define OW_DESC " (open file with...)" #define P_DESC " (print file properties)" #define PC_DESC " (change file permissions)" #define PF_DESC " (manage user profiles)" #define PG_DESC " (toggle/run the file pager)" #define PIN_DESC " (pin a directory)" #define PP_DESC " (print file properties - follow links/total dir size)" #define PROMPT_DESC " (switch/edit the command prompt)" #define Q_DESC " (quit)" #define R_DESC " (remove files)" #define RF_DESC " (refresh/clear the screen)" #define RL_DESC " (reload the configuration file)" #define RR_DESC " (remove files in bulk)" #define SB_DESC " (access the selection box)" #define SEL_DESC " (select files)" #define ST_DESC " (change file sort order)" #define STATS_DESC " (print file statistics)" #define TAG_DESC " (manage file tags)" #define TA_DESC " (tag files as ...)" #define TD_DESC " (delete tags)" #define TE_DESC " (toggle the executable bit on files)" #define TIPS_DESC " (print tips)" #define TL_DESC " (list tags or tagged files)" #define TM_DESC " (rename tags)" #define TN_DESC " (create tags)" #define TU_DESC " (untag files)" #define TY_DESC " (merge tags)" #define TRASH_DESC " (trash files)" #define U_DESC " (restore trashed files using a menu)" #define UNPIN_DESC " (unpin the pinned directory)" #define VER_DESC " (print version information)" #define VIEW_DESC " (preview files in the current directory)" #define VV_DESC " (copy and rename files in bulk at once)" #define WS_DESC " (switch workspaces)" #define X_DESC " (launch a new instance of Clifm)" #define XU_DESC " (launch a new instance of Clifm as root)" #endif /* MESSAGES_H */ clifm-1.26.3/src/mime.c000066400000000000000000001205501506632037700145730ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* mime.c -- functions controlling Lira, the file opener */ #include "helpers.h" #ifndef _NO_MAGIC # include #else # if !defined(_BE_POSIX) # include # endif /* !_BE_POSIX */ # ifndef _PATH_DEVNULL # define _PATH_DEVNULL "/dev/null" # endif /* _PATH_DEVNULL */ #endif /* !_NO_MAGIC */ #ifndef _NO_LIRA # include # include # include # include # ifndef _NO_ARCHIVING # include "archives.h" # endif /* !_NO_ARCHIVING */ # include "aux.h" # include "checks.h" # include "config.h" # include "listing.h" # include "messages.h" # include "mime.h" # include "misc.h" # include "readline.h" # include "sanitize.h" # include "spawn.h" #else # include # include # include "aux.h" /* open_f* functions */ # include "spawn.h" /* launch_execv() */ #endif /* !_NO_LIRA */ #ifndef _NO_LIRA static char *err_name = (char *)NULL; static int g_mime_match = 0; static char *g_mime_type = (char *)NULL; #endif /* !_NO_LIRA */ /* Return the MIME type associated to the current file based on its extension. * Associations are taken from ~/.mime.types (or $CLIFM_MIMETYPES_FILE) and * stored in the user_mimetypes struct by load_user_mimetypes() (mimetypes.c). */ static char * check_user_mimetypes(const char *file) { char *ext = strrchr(file, '.'); if (!ext || ext == file || !*(++ext)) return (char *)NULL; const size_t hash = hashme(ext, conf.case_sens_list); static filesn_t n = 0; if (n == 0) for (n = 0; user_mimetypes[n].mimetype; n++); filesn_t i = n; while (--i >= 0) /* An extension name starting with NUL byte is duplicated. Skip it. */ if (hash == user_mimetypes[i].ext_hash && *user_mimetypes[i].ext) return user_mimetypes[i].mimetype; return (char *)NULL; } #ifndef _NO_MAGIC /* Get FILE's type using the libmagic library. * Return the MIME type if QUERY_MIME is set to 1, or a text description * otherwise. * NULL is returned in case of error. */ char * xmagic(const char *file, const int query_mime) { if (!file || !*file) return (char *)NULL; if (query_mime == 1 && user_mimetypes) { const char *mime = check_user_mimetypes(file); if (mime) return strdup(mime); } magic_t cookie = magic_open(query_mime ? (MAGIC_MIME_TYPE | MAGIC_ERROR) : MAGIC_ERROR); if (!cookie) return (char *)NULL; magic_load(cookie, NULL); const char *mime = magic_file(cookie, file); char *str = mime ? savestring(mime, strlen(mime)) : (char *)NULL; magic_close(cookie); return str; } #else /* _NO_MAGIC */ /* Get FILE's type using file(1). * Return the MIME type if QUERY_MIME is set to 1, or a text description * otherwise. * NULL is returned in case of error. */ char * xmagic(const char *file, const int query_mime) { if (!file || !*file) return (char *)NULL; if (query_mime == 1 && user_mimetypes) { const char *mime = check_user_mimetypes(file); if (mime) return strdup(mime); } char *mime_type = (char *)NULL; char *rand_ext = gen_rand_str(RAND_SUFFIX_LEN); char tmp_file[PATH_MAX + 1]; snprintf(tmp_file, sizeof(tmp_file), "%s/mime.%s", tmp_dir, rand_ext ? rand_ext : "Hu?+6545jk"); free(rand_ext); int fd = 0; FILE *fp_out = open_fwrite(tmp_file, &fd); if (!fp_out) return (char *)NULL; FILE *fp_err = fopen(_PATH_DEVNULL, "w"); if (!fp_err) goto END; int stdout_bk = dup(STDOUT_FILENO); /* Store original stdout */ int stderr_bk = dup(STDERR_FILENO); /* Store original stderr */ if (stdout_bk == -1 || stderr_bk == -1) goto ERROR; /* Redirect stdout to the desired file */ if (dup2(fileno(fp_out), STDOUT_FILENO) == -1) goto ERROR; /* Redirect stderr to /dev/null */ if (dup2(fileno(fp_err), STDERR_FILENO) == -1) goto ERROR; fclose(fp_out); fclose(fp_err); /* --mime-type is only available since file 4.24 (Mar, 2008), while the -i * flag (-I in MacOS) is supported since 3.30 (Apr, 2000). * NOTE: the -i flag in the POSIX file(1) specification is a completely * different thing. */ #ifdef __APPLE__ char *cmd[] = {"file", query_mime ? "-bI" : "-b", (char *)file, NULL}; #else char *cmd[] = {"file", query_mime ? "-bi" : "-b", (char *)file, NULL}; #endif /* __APPLE__ */ int ret = launch_execv(cmd, FOREGROUND, E_NOFLAG); dup2(stdout_bk, STDOUT_FILENO); /* Restore original stdout */ dup2(stderr_bk, STDERR_FILENO); /* Restore original stderr */ close(stdout_bk); close(stderr_bk); if (ret != FUNC_SUCCESS || (fp_out = fopen(tmp_file, "r")) == NULL) { unlink(tmp_file); return (char *)NULL; } /* According to the RFC-4288, both type and subtype of a MIME type cannot * be longer than 127 characters each, So adding the separating slash, we * get a max of 255 characters. * See https://datatracker.ietf.org/doc/html/rfc4288#section-4.2 */ char line[NAME_MAX + 1]; *line = '\0'; if (fgets(line, (int)sizeof(line), fp_out) == NULL) goto END; char *s = query_mime ? strrchr(line, ';') : (char *)NULL; if (s) *s = '\0'; size_t len = strlen(line); if (len > 0 && line[len - 1] == '\n') { line[len - 1] = '\0'; len--; } mime_type = len > 0 ? savestring(line, len) : (char *)NULL; END: fclose(fp_out); unlink(tmp_file); return mime_type; ERROR: fclose(fp_out); fclose(fp_err); unlink(tmp_file); close(stdout_bk); close(stderr_bk); return (char *)NULL; } #endif /* !_NO_MAGIC */ #ifndef _NO_LIRA /* Expand all environment variables in the string S. * Returns the expanded string or NULL on error. */ static char * expand_env(char *s) { char *p = strchr(s, '$'); if (!p) return (char *)NULL; const int buf_size = PATH_MAX; p = xnmalloc((size_t)buf_size, sizeof(char)); char *ret = p; while (*s) { if (*s != '$') { *p = *s; p++; s++; continue; } char *env = (char *)NULL; char *r = strchr(s, ' '); if (r) *r = '\0'; env = getenv(s + 1); if (r) *r = ' '; if (!env) { free(ret); return (char *)NULL; } const size_t env_len = strlen(env); const int rem = buf_size - (int)(p - ret) - 1; if (rem >= (int)env_len) { memccpy(p, env, 0, (size_t)rem); p += env_len; } else { break; } if (r) *r = '\0'; s += strlen(s); if (r) *r = ' '; } *p = '\0'; return ret; } /* Move the pointer in LINE immediately after prefix (X or !X) * Returns NULL if there's nothing after prefix, if prefix is "!X" and we * are in a graphical environment, or if prefix is "X" and we're not in * a graphical environment. Otherwise, it returns the corresponding pointer */ static char * skip_line_prefix(char *line) { if (!line || !*line) return (char *)NULL; char *p = line; if (!(flags & GUI)) { if (*p == 'X' && p[1] == ':') return (char *)NULL; if (*p == '!' && p[1] == 'X' && p[2] == ':') p += 3; } else { if (*p == '!' && p[1] == 'X') return (char *)NULL; if (*p == 'X' && p[1] == ':') p += 2; } return p; } /* Should we skip the line LINE? * Returns 1 if true and 0 otherwise * If true, the pointer PATTERN will point to the beginning of the * null terminated pattern, and the pointer CMDS will point to the * beginnning of the list of opening applications */ static int skip_line(char *line, char **pattern, char **cmds) { if (SKIP_LINE(*line) || *line == '[') return 1; *pattern = skip_line_prefix(line); if (!*pattern) return 1; /* PATTERN points now to the beginning of the pattern */ *cmds = strchr(*pattern, '='); if (!*cmds || !*(*cmds + 1)) return 1; /* Truncate line in '=' to get only the name/mimetype pattern */ *(*cmds) = '\0'; (*cmds)++; /* CMDS points now to the beginning of the list of opening cmds */ return 0; } /* Test PATTERN against either FILENAME or the mime-type MIME. * Returns zero in case of a match, and 1 otherwise. */ static int test_pattern(const char *pattern, const char *filename, const char *mime) { int ret = FUNC_FAILURE; regex_t regex; if (filename && (*pattern == 'N' || *pattern == 'E') && pattern[1] == ':') { if (regcomp(®ex, pattern + 2, REG_NOSUB | REG_EXTENDED | REG_ICASE) == 0 && regexec(®ex, filename, 0, NULL, 0) == 0) ret = FUNC_SUCCESS; } else { if (regcomp(®ex, pattern, REG_NOSUB | REG_EXTENDED) == 0 && regexec(®ex, mime, 0, NULL, 0) == 0) { g_mime_match = 1; ret = FUNC_SUCCESS; } } regfree(®ex); return ret; } /* Return 1 if APP is a valid and existent application (2 if it's located in * the home directory), or 0 otherwise. */ static int check_app_existence(char **app, const char *params, const size_t params_len) { if (*(*app) == 'a' && *(*app + 1) == 'd' && !*(*app + 2)) /* No need to check: 'ad' is an internal command. */ return 1; /* Expand tilde */ if (*(*app) == '~' && *(*app + 1) == '/' && *(*app + 2)) { size_t len = user.home_len + strlen(*app); const size_t cmd_len = len > 0 ? len - 1 : 0; len += params ? params_len + 1 : 0; char *tmp_cmd = xnmalloc(len, sizeof(char)); snprintf(tmp_cmd, len, "%s/%s", user.home, *app + 2); if (access(tmp_cmd, X_OK) == -1) { free(tmp_cmd); return 0; } if (params) { /* Append command paramters */ tmp_cmd[cmd_len] = ' '; memcpy(tmp_cmd + cmd_len + 1, params, params_len + 1); } free(*app); *app = tmp_cmd; return 2; } /* Either a command name or an absolute path */ return is_cmd_in_path(*app); } /* Return a copy the first cmd found in LINE (NULL terminated) or NULL. * LINE is modified to point past the end of the returned cmd name. * Example: if LINE is "cmd1;cmd2", "cmd1" is returned and LINE points now * to ";cmd2". */ static char * get_cmd_from_line(char **line) { char *l = *line; char tmp[PATH_MAX]; size_t len = 0; /* Get the first field in LINE */ while (*l != '\0' && *l != ';' && *l != '\n' && *l != '\'' && *l != '"' && len < sizeof(tmp) - 1) { tmp[len] = *l; len++; l++; } tmp[len] = '\0'; *line = l; return len > 0 ? savestring(tmp, len) : NULL; } /* Return the first valid and existent opening application in LINE or NULL */ static char * retrieve_app(char *line) { while (*line) { char *app = get_cmd_from_line(&line); if (!app) { line++; /* LINE points now to the next app field */ continue; } if (strchr(app, '$')) { /* Environment variable */ char *t = expand_env(app); if (t) { free(app); app = t; } } if (xargs.secure_cmds == 1 && sanitize_cmd(app, SNT_MIME) != FUNC_SUCCESS) { free(app); continue; } /* If app contains spaces, the command to check is the string * before the first space. */ char *ret = strchr(app, ' '); if (ret) *ret = '\0'; const size_t param_len = (ret && ret[1]) ? strlen(ret + 1) : 0; char *params = (char *)NULL; if (*app == '~' && param_len > 0) params = savestring(ret + 1, param_len); const int exists = check_app_existence(&app, params, param_len); free(params); if (exists != 2 && ret) /* App not in HOME */ *ret = ' '; if (exists == 0) { free(app); continue; } return app; /* Valid app. Return it */ } return (char *)NULL; /* No app was found */ } /* Get application associated to a given MIME type or filename. * Returns the first matching line in the MIME file or NULL if none is * found. */ static char * get_app(const char *mime, const char *filename) { if (!mime || !mime_file || !*mime_file) return (char *)NULL; int fd = 0; FILE *fp = open_fread(mime_file, &fd); if (!fp) { xerror("%s: '%s': %s\n", err_name, mime_file, strerror(errno)); return (char *)NULL; } size_t line_size = 0; char *line = (char *)NULL; char *app = (char *)NULL; /* Each line has this form: prefix:pattern=cmd;cmd;cmd... */ while (getline(&line, &line_size, fp) > 0) { char *pattern = (char *)NULL; char *cmds = (char *)NULL; if (skip_line(line, &pattern, &cmds) == 1) continue; /* PATTERN points now to the beginning of the null terminated pattern, * while CMDS points to the beginning of the list of opening cmds. */ g_mime_match = 0; /* Global. Are we matching a MIME type? It will be set by test_pattern. */ if (test_pattern(pattern, filename, mime) == FUNC_FAILURE) continue; if ((app = retrieve_app(cmds))) break; } free(line); fclose(fp); return app; } /* Import MIME associations from the system and save them into FILE. * Returns the number of associations found, if any, or -1 in case of error * or no association found */ static int mime_import(char *file) { #if defined(__HAIKU__) xerror("%s: Importing MIME associations is not supported " "on Haiku\n", err_name); return (-1); #elif defined(__APPLE__) xerror("%s: Importing MIME associations is not supported " "on MacOS\n", err_name); return (-1); #endif /* __HAIKU__ */ if (!(flags & GUI)) { /* Not in X, exit */ xerror(_("%s: Nothing was imported. No graphical " "environment found.\n"), err_name); return (-1); } if (!user.home) { xerror(_("%s: Error getting the home directory\n"), err_name); return (-1); } /* Open the new mimelist file */ int fd = 0; FILE *mime_fp = open_fwrite(file, &fd); if (!mime_fp) { xerror("%s: fopen: '%s': %s\n", err_name, file, strerror(errno)); return (-1); } /* Create a list of possible paths for the 'mimeapps.list' file as * specified by the Freedesktop specification */ const size_t home_len = strlen(user.home); char *config_path = (char *)NULL, *local_path = (char *)NULL; config_path = xnmalloc(home_len + 23, sizeof(char)); local_path = xnmalloc(home_len + 41, sizeof(char)); /* xnmalloc will exit in case of error. However, GCC-13's analyzer * complains about both vars not being checked for NULL. So, let's add * the corresponding checks to silence the warning. */ if (!config_path || !local_path) { free(config_path); free(local_path); fclose(mime_fp); return (-1); } snprintf(config_path, home_len + 23, "%s/.config/mimeapps.list", user.home); snprintf(local_path, home_len + 41, "%s/.local/share/applications/mimeapps.list", user.home); const char *const mime_paths[] = {config_path, local_path, "/usr/local/share/applications/mimeapps.list", "/usr/share/applications/mimeapps.list", "/etc/xdg/mimeapps.list", NULL}; /* Check each mimeapps.list file and save its associations into FILE */ size_t i; int mime_defs = 0; for (i = 0; mime_paths[i]; i++) { printf("Checking %s ...\n", mime_paths[i]); FILE *sys_mime_fp = fopen(mime_paths[i], "r"); if (!sys_mime_fp) continue; size_t line_size = 0; char *line = (char *)NULL; /* Only store associations in the "Default Applications" section */ int header_found = 0; while (getline(&line, &line_size, sys_mime_fp) > 0) { if (header_found == 0 && (strncmp(line, "[Default Applications]", 22) == 0 || strncmp(line, "[Added Associations]", 20) == 0)) { header_found = 1; continue; } if (header_found == 1) { if (*line == '[') break; if (*line == '#' || *line == '\n') continue; char *a = strchr(line, '='); if (!a || !a[1] || a == line) continue; char *ret = strchr(a + 1, '.'); if (ret) *ret = '\0'; fprintf(mime_fp, "%s\n", line); mime_defs++; } } free(line); line = (char *)NULL; fclose(sys_mime_fp); } free(config_path); free(local_path); if (mime_defs == 0) xerror(_("%s: Nothing was imported. No MIME association " "found.\n"), err_name); fclose(mime_fp); return mime_defs; } static int mime_edit(char **args) { if (xargs.stealth_mode == 1) { printf("%s: mime: %s\n", PROGRAM_NAME, STEALTH_DISABLED); return FUNC_SUCCESS; } if (!mime_file || !*mime_file) { xerror("%s: The mimelist filename is undefined\n", err_name); return FUNC_FAILURE; } int exit_status = FUNC_SUCCESS; struct stat a; if (stat(mime_file, &a) == -1) { if (create_mime_file(mime_file, 1) != FUNC_SUCCESS) { xerror("%s: Cannot access the mimelist file: %s\n", err_name, strerror(ENOENT)); return ENOENT; } if (stat(mime_file, &a) == -1) { xerror("%s: '%s': %s\n", err_name, mime_file, strerror(errno)); return errno; } } const time_t prev = a.st_mtime; if (!args[2]) { char *cmd[] = {"mime", mime_file, NULL}; open_in_foreground = 1; if (mime_open(cmd) != 0) { fputs(_("Try 'mm edit APPLICATION'\n"), stderr); exit_status = FUNC_FAILURE; } open_in_foreground = 0; } else { char *cmd[] = {args[2], mime_file, NULL}; exit_status = launch_execv(cmd, FOREGROUND, E_NOFLAG); if (exit_status != FUNC_SUCCESS) return exit_status; } if (stat(mime_file, &a) != -1 && a.st_mtime != prev) { reload_dirlist(); print_reload_msg(NULL, NULL, _(CONFIG_FILE_UPDATED)); } return exit_status; } static char * get_basename(char *file_path) { char *f = strrchr(file_path, '/'); if (f && *(++f)) return f; return (char *)NULL; } /* Get user input for the 'open with' function. * NUM is a pointer to an integer storing the item selected by the user. * MAX is the number of available items. */ static int get_user_input(const size_t max) { char *input = (char *)NULL; while (!input) { input = rl_no_hist(_("Select an application ('q' to quit): "), 0); if (!input || !*input) { free(input); input = (char *)NULL; continue; } if (*input == 'q' && !input[1]) { free(input); return (-1); } if (!is_number(input)) { free(input); input = (char *)NULL; continue; } int num = atoi(input); if (num <= 0 || num > (int)max) { free(input); input = (char *)NULL; continue; } free(input); return num; } return (-1); } static void set_exec_flags(const char *str, int *exec_flags) { if (*str == 'E') { *exec_flags |= E_NOSTDERR; if (str[1] == 'O') *exec_flags |= E_NOSTDOUT; } else if (*str == 'O') { *exec_flags |= E_NOSTDOUT; if (str[1] == 'E') *exec_flags |= E_NOSTDERR; } } static void copy_field(char **dst, const char *src) { const size_t src_len = strlen(src); *dst = xnrealloc(*dst, src_len + 1, sizeof(char)); xstrsncpy(*dst, src, src_len + 1); } /* Expand %[f|m|u|x] placeholders, stderr/stdout flags, and environment * variables in the opening application line. */ static size_t expand_app_fields(char ***cmd, size_t *n, char *fpath, int *exec_flags) { size_t f = 0, i; char **a = *cmd; *exec_flags = E_NOFLAG; for (i = 0; a[i]; i++) { /* "%x" is short for "%f !EO &". It must be the last field in the * command entry (subsequent fields will be ignored). */ if (*a[i] == '%' && a[i][1] == 'x') { copy_field(&a[i], fpath); f = 1; set_exec_flags("EO", exec_flags); *exec_flags |= E_SETSID; bg_proc = 1; i++; break; } /* Expand %f placeholder to the file's absolute path */ if (*a[i] == '%' && a[i][1] == 'f') { copy_field(&a[i], fpath); f = 1; continue; } /* Expand %m placeholder to the file's MIME type */ if (*a[i] == '%' && a[i][1] == 'm' && g_mime_type) { copy_field(&a[i], g_mime_type); continue; } /* Expand %u to the file URI for the original filename */ if (*a[i] == '%' && a[i][1] == 'u') { char *p = url_encode(fpath, 1); if (p) { copy_field(&a[i], p); free(p); f = 1; } continue; } /* Set execution flags */ if (*a[i] == '!' && (a[i][1] == 'E' || a[i][1] == 'O')) { set_exec_flags(a[i] + 1, exec_flags); free(a[i]); a[i] = (char *)NULL; continue; } /* Expand environment variable */ if (*a[i] == '$' && a[i][1] >= 'A' && a[i][1] <= 'Z') { char *p = expand_env(a[i]); if (p) { copy_field(&a[i], p); free(p); } continue; } /* Check if the command needs to be backgrounded */ if (*a[i] == '&') { bg_proc = 1; free(a[i]); a[i] = (char *)NULL; } } *n = i; return f; } /* Open the file named FILE using the application APP, splitting APP and * expanding fields to the appropriate values. */ static int run_mime_app(char *app, char *file) { char **cmd = split_str(app, NO_UPDATE_ARGS); if (!cmd) return FUNC_FAILURE; int exec_flags = E_NOFLAG; size_t i = 0; const size_t f = expand_app_fields(&cmd, &i, file, &exec_flags); /* If no %f placeholder was found, append filename. */ if (f == 0) { cmd = xnrealloc(cmd, i + 2, sizeof(char *)); cmd[i] = savestring(file, strlen(file)); cmd[i + 1] = (char *)NULL; } const int ret = launch_execv(cmd, (bg_proc && !open_in_foreground) ? BACKGROUND : FOREGROUND, exec_flags); for (i = 0; cmd[i]; i++) free(cmd[i]); free(cmd); return ret; } /* Open the file named FILE using the application APP. * No field expansion is made on APP, since it must be just an application * name. If expansion is required, use run_mime_app() instead. */ static int run_cmd(char *app, char *file) { #ifndef _NO_ARCHIVING if (*app == 'a' && app[1] == 'd' && !app[2]) { /* 'ad' is the internal archiver command */ char *cmd[] = {"ad", file, NULL}; return archiver(cmd, 'd'); } #endif /* !_NO_ARCHIVING */ char *env = (char *)NULL; if (*app == '$' && app[1] >= 'A' && app[1] <= 'Z') env = expand_env(app); char *cmd[] = {env ? env : app, file, NULL}; const int ret = launch_execv(cmd, bg_proc ? BACKGROUND : FOREGROUND, bg_proc ? E_NOSTDERR : E_NOFLAG); free(env); return ret; } static int mime_list_open(char **apps, char *file) { if (!apps || !file) return FUNC_FAILURE; size_t i; for (i = 0; apps[i]; i++); const int pad = DIGINUM(i + 1); for (i = 0; apps[i]; i++) printf("%s%*zu%s %s\n", el_c, pad, i + 1, df_c, apps[i]); const int n = get_user_input(i); if (n == -1) /* 'q' or Ctrl+d */ return FUNC_SUCCESS; char *app = apps[n - 1]; if (!app) return FUNC_FAILURE; int ret = FUNC_FAILURE; if (strchr(app, ' ')) ret = run_mime_app(app, file); else /* We have just a command name: no parameter nor placeholder. */ ret = run_cmd(app, file); return ret; } static int is_dup_entry(const char *prefix, char **apps, const char *app) { for (size_t i = prefix ? 1 : 0; apps && apps[i]; i++) { if (*app == *apps[i] && strcmp(app, apps[i]) == 0) return 1; } return 0; } /* Return the list of opening apps for FILE_NAME, whose MIME type is MIME, * reading the file whose file pointer is FP. * If PREFIX is not NULL, we're tab completing. * If ONLY_NAMES is 1, we're tab completing for 'edit' subcommands (in which * case we want only command names, not parameters). */ static char ** get_apps_from_file(FILE *fp, char *file_name, const char *mime, const char *prefix, const int only_names) { size_t line_size = 0; char *line = (char *)NULL; char *app = (char *)NULL; char **apps = (char **)NULL; size_t appsn = prefix != NULL ? 1 : 0; const size_t prefix_len = prefix ? strlen(prefix) : 0; const char *base_name = get_basename(file_name); while (getline(&line, &line_size, fp) > 0) { if (*line == '#' || *line == '[' || *line == '\n') continue; const char *p = skip_line_prefix(line); if (!p) continue; char *tmp = strchr(p, '='); if (!tmp || !tmp[1]) continue; /* Truncate line in '=' to get only the ext/mimetype pattern/string */ *tmp = '\0'; if (test_pattern(p, base_name, mime) != 0) continue; tmp++; /* We don't want the '=' char */ app = xnrealloc(app, strlen(tmp) + 1, sizeof(char)); while (*tmp) { size_t app_len = 0; /* Split the applications line into substrings, if any */ while (*tmp != '\0' && *tmp != ';' && *tmp != '\n' && *tmp != '\'' && *tmp != '"') { app[app_len] = *tmp; app_len++; tmp++; } while (*tmp == ' ') /* Remove leading spaces */ tmp++; if (app_len == 0) { tmp++; continue; } app[app_len] = '\0'; if (prefix_len > 0 && strncmp(prefix, app, prefix_len) != 0) continue; /* Do not list duplicated entries */ if (is_dup_entry(prefix, apps, app) == 1) continue; /* Check each application existence */ char *file_path = (char *)NULL; /* Expand environment variables */ char *appb = (char *)NULL; if (strchr(app, '$')) { char *t = expand_env(app); if (!t) continue; /* appb: A copy of the original string: let's display * the env var name itself instead of its expanded value. */ appb = savestring(app, strlen(app)); /* app: the expanded value. */ const size_t tlen = strlen(t); app = xnrealloc(app, app_len + tlen + 2, sizeof(char)); xstrsncpy(app, t, app_len + tlen + 1); free(t); } /* If app contains spaces, the command to check is * the string before the first space. */ char *ret = strchr(app, ' '); if (ret) *ret = '\0'; if (*app == '~') { file_path = tilde_expand(app); if (file_path && access(file_path, X_OK) != 0) { free(file_path); file_path = (char *)NULL; } } /* If running in stealth mode, do not allow APP to be plain * "clifm", since nested executions of clifm are not allowed. */ else if (xargs.stealth_mode == 1 && *app == PROGRAM_NAME[0] && strcmp(app, PROGRAM_NAME) == 0) { ; } else if (*app == '/') { if (access(app, X_OK) == 0) { file_path = app; } } else if (*app == 'a' && app[1] == 'd' && !app[2]) { file_path = savestring("ad", 2); } else { file_path = get_cmd_path(app); } if (ret && only_names == 0) *ret = ' '; if (!file_path) { free(appb); continue; } /* If the app exists, store it in the APPS array */ if (*app != '/') { free(file_path); file_path = (char *)NULL; } apps = xnrealloc(apps, appsn + 2, sizeof(char *)); /* appb is not NULL if we have an environment variable. */ if (appb) { apps[appsn] = savestring(appb, strlen(appb)); free(appb); } else { apps[appsn] = savestring(app, strlen(app)); } appsn++; apps[appsn] = (char *)NULL; tmp++; } } free(line); free(app); return apps; } static char * construct_filename(char *filename) { char *name = (char *)NULL; if (*filename == '~') { char *tmp = tilde_expand(filename); if (!tmp) return (char *)NULL; name = tmp; } else { if (*filename == '\'' || *filename == '"') { char *tmp = savestring(filename + 1, strlen(filename + 1)); name = remove_quotes(tmp); } } if (strchr(name ? name : filename, '\\')) { char *deq_file = unescape_str(name ? name : filename, 0); if (!deq_file) { free(name); return (char *)NULL; } free(name); name = xrealpath(deq_file, NULL); free(deq_file); } if (!name) { name = xrealpath(filename, NULL); if (!name) return (char *)NULL; } return name; } /* "ow FILENAME " or "CMD edit " * Return available applications, taken from the mimelist file, to open * the file FILENAME, where PREFIX is the partially entered word. * If ONLY_NAMES is set to 1 (which is the case when completing opening * applications for the 'edit' subcommand), only command names are returned * (not parameters). */ char ** mime_open_with_tab(char *filename, const char *prefix, const int only_names) { if (!filename || !mime_file) return (char **)NULL; char *name = construct_filename(filename); if (!name) return (char **)NULL; char *mime = xmagic(name, MIME_TYPE); if (!mime) { free(name); return (char **)NULL; } FILE *fp = fopen(mime_file, "r"); if (!fp) { free(name); free(mime); return (char **)NULL; } /* Do not let PREFIX be NULL, so that get_apps_from_file() knows * we're tab completing. */ char **apps = get_apps_from_file(fp, name, mime, prefix ? prefix : "", only_names); fclose(fp); free(mime); free(name); /* The first element in the matches array must contain the * already matched string. */ if (!apps) { apps = xnmalloc(2, sizeof(char *)); apps[1] = (char *)NULL; } if (prefix) { apps[0] = savestring(prefix, strlen(prefix)); } else { apps[0] = xnmalloc(1, sizeof(char)); *apps[0] = '\0'; } size_t appsn; for (appsn = 0; apps[appsn]; appsn++); /* If only one match */ if (appsn == 2) { const size_t src_len = strlen(apps[1]); apps[0] = xnrealloc(apps[0], src_len + 1, sizeof(char)); xstrsncpy(apps[0], apps[1], src_len + 1); free(apps[1]); apps[1] = (char *)NULL; } return apps; } static int run_cmd_noargs(char *arg, char *name) { errno = 0; char *cmd[] = {arg, name, NULL}; int ret = FUNC_SUCCESS; #ifndef _NO_ARCHIVING if (*arg == 'a' && arg[1] == 'd' && !arg[2]) ret = archiver(cmd, 'd'); else ret = launch_execv(cmd, bg_proc ? BACKGROUND : FOREGROUND, E_NOSTDERR); #else ret = launch_execv(cmd, bg_proc ? BACKGROUND : FOREGROUND, E_NOSTDERR); #endif /* !_NO_ARCHIVING */ if (ret == FUNC_SUCCESS) return FUNC_SUCCESS; xerror("%s: %s: %s\n", err_name, arg, ret == E_NOTFOUND ? NOTFOUND_MSG : (ret == E_NOEXEC ? NOEXEC_MSG : strerror(ret))); return ret; } static void append_params(char **args, char *name, char ***cmd, int *exec_flags) { size_t i, n = 1, f = 0; for (i = 1; args[i]; i++) { /* "%x" is short for "%f !EO &". It must be the last field in the * command entry (subsequent fields will be ignored). */ if (*args[i] == '%' && args[i][1] == 'x') { (*cmd)[n] = savestring(name, strlen(name)); f = 1; set_exec_flags("EO", exec_flags); *exec_flags |= E_SETSID; bg_proc = 1; n++; break; } if (*args[i] == '%' && args[i][1] == 'f' && !args[i][2]) { f = 1; (*cmd)[n] = savestring(name, strlen(name)); n++; continue; } if (*args[i] == '!' && (args[i][1] == 'E' || args[i][1] == 'O')) { set_exec_flags(args[i] + 1, exec_flags); continue; } /* Expand %m placeholder to the file's MIME type */ if (*args[i] == '%' && args[i][1] == 'm') { char *mime = xmagic(name, MIME_TYPE); if (mime) { (*cmd)[n] = mime; n++; } continue; } /* Expand %u to the file URI for the original filename */ if (*args[i] == '%' && args[i][1] == 'u') { char *p = url_encode(name, 1); if (p) { (*cmd)[n] = p; n++; f = 1; } continue; } if (*args[i] == '$' && IS_ALPHA_UP(args[i][1])) { char *env = expand_env(args[i]); if (env) { (*cmd)[n] = savestring(env, strlen(env)); n++; } continue; } if (*args[i] == '&') { bg_proc = 1; } else { (*cmd)[n] = savestring(args[i], strlen(args[i])); n++; } } if (f == 0) { (*cmd)[n] = savestring(name, strlen(name)); n++; } (*cmd)[n] = (char *)NULL; } static int run_cmd_plus_args(char **args, char *name) { if (!args || !args[0]) return FUNC_FAILURE; size_t i; for (i = 0; args[i]; i++); char **cmd = xnmalloc(i + 2, sizeof(char *)); cmd[0] = savestring(args[0], strlen(args[0])); int exec_flags = E_NOFLAG; append_params(args, name, &cmd, &exec_flags); const int ret = launch_execv(cmd, bg_proc ? BACKGROUND : FOREGROUND, exec_flags); for (i = 0; cmd[i]; i++) free(cmd[i]); free(cmd); return ret; } static int join_and_run(char **args, char *name) { /* Application name plus parameters (array): 'ow FILE CMD ARG...' */ if (args[1]) return run_cmd_plus_args(args, name); /* Just an application name: 'ow FILE CMD' */ if (!strchr(args[0], ' ')) return run_cmd_noargs(args[0], name); /* Command is a quoted string: 'ow FILE "CMD ARG ARG..."' */ char *deq_str = unescape_str(args[0], 0); char **ss = split_str(deq_str ? deq_str : args[0], NO_UPDATE_ARGS); free(deq_str); if (!ss) return FUNC_FAILURE; const int ret = run_cmd_plus_args(ss, name); size_t i; for (i = 0; ss[i]; i++) free(ss[i]); free(ss); return ret; } /* "ow FILE [APP]" command (open-with). * Display available opening applications for FILENAME, get user input, * and open the file. */ int mime_open_with(char *filename, char **args) { if (!filename || !mime_file) return FUNC_FAILURE; err_name = "open"; char *deq = unescape_str(filename, 0); if (!deq) return FUNC_FAILURE; char *name = xrealpath(deq, NULL); if (!name) { xerror("%s: '%s': %s\n", err_name, deq, strerror(errno)); free(deq); return errno; } free(deq); /* ow FILE APP [ARGS] * We already have the opening app. Just join the app, option * parameters, and filename, and execute the command. */ if (args && args[0]) { const int ret = join_and_run(args, name); free(name); return ret; } /* Find out the appropriate opening application via either mime type * or filename. */ char *mime = xmagic(name, MIME_TYPE); if (!mime) { xerror(_("%s: Error getting MIME type\n"), err_name); goto FAIL; } FILE *fp = fopen(mime_file, "r"); if (!fp) { xerror("%s: '%s': %s\n", err_name, mime_file, strerror(errno)); goto FAIL; } char **apps = get_apps_from_file(fp, name, mime, NULL, 0); fclose(fp); if (!apps) { xerror(_("%s: No opening application found\n" "Tip: Run 'APP FILE', or 'mm edit' to add an opening " "application\n"), err_name); free(name); free(mime); return FUNC_FAILURE; } g_mime_type = mime; const int ret = mime_list_open(apps, name); g_mime_type = (char *)NULL; free(mime); size_t i; for (i = 0; apps[i]; i++) free(apps[i]); free(apps); free(name); return ret; FAIL: free(mime); free(name); return FUNC_FAILURE; } /* Open URL using the application associated to text/html MIME-type in * the mimelist file. Returns zero on success and >0 on error. * For the time being, this function is only executed via --open or --preview. */ int mime_open_url(char *url) { if (!url || !*url) return FUNC_FAILURE; err_name = (xargs.open == 1 || xargs.preview == 1) ? PROGRAM_NAME : "lira"; char *app = get_app("text/html", 0); if (!app) /* The error message may not be printed by get_app(). Fix. */ return FUNC_FAILURE; char *p = strchr(app, ' '); if (p) *p = '\0'; char *cmd[] = {app, url, NULL}; const int ret = launch_execv(cmd, FOREGROUND, E_NOFLAG); free(app); return ret; } static int import_mime(void) { char *suffix = gen_rand_str(RAND_SUFFIX_LEN); char new[PATH_MAX + 1]; snprintf(new, sizeof(new), "%s.%s", mime_file, suffix ? suffix : "5i0TM#r3j&"); free(suffix); const int mime_defs = mime_import(new); if (mime_defs > 0) { printf(_("%d MIME association(s) imported from the system.\n" "File saved as '%s'\nAdd these new associations to your mimelist " "file by running 'mm edit'.\n"), mime_defs, new); return FUNC_SUCCESS; } return FUNC_FAILURE; } static int check_mime_info_file(char *arg, char **fpath) { if (!arg) { fprintf(stderr, "%s\n", _(MIME_USAGE)); return FUNC_FAILURE; } if (strchr(arg, '\\')) { char *deq = unescape_str(arg, 0); *fpath = xrealpath(deq, NULL); free(deq); } else { *fpath = xrealpath(arg, NULL); } if (!*fpath) { const int isnum = is_number(arg); xerror("%s: '%s': %s\n", err_name, arg, isnum == 1 ? _("No such ELN") : strerror(errno)); return isnum == 1 ? FUNC_FAILURE : errno; } return FUNC_SUCCESS; } /* Get the full path of the file to be opened by mime * Returns 0 on success and 1 on error */ static int get_open_file_path(char **args, char **fpath) { char *f = (char *)NULL; if (*args[1] == 'o' && strcmp(args[1], "open") == 0 && args[2]) f = args[2]; else f = args[1]; /* Only dequote the filename if coming from the mime command. */ if (*args[0] == 'm' && strchr(f, '\\')) { char *deq = unescape_str(f, 0); *fpath = xrealpath(deq, NULL); free(deq); } if (!*fpath) { *fpath = xrealpath(f, NULL); if (!*fpath) { xerror("%s: '%s': %s\n", err_name, f, strerror(errno)); return errno; } } return FUNC_SUCCESS; } /* Handle mime when no opening app has been found */ static int handle_no_app(const int info, char **fpath, char **mime, const char *arg) { if (xargs.preview == 1) { /* When running the previewer, MIME_FILE points to the path to * preview.clifm file. */ free(*fpath); free(*mime); xerror(_("%s: '%s': No associated application found\n" "Fix this in the configuration file:\n%s\n" "(run 'view edit' if running %s)\n"), PROGRAM_NAME, arg, mime_file, PROGRAM_NAME); return FUNC_FAILURE; } if (info) { fputs(_("Associated application: None\n"), stderr); } else { #ifndef _NO_ARCHIVING /* If an archive/compressed file, run the archiver function */ if (is_compressed(*fpath, 1) == 0) { char *tmp_cmd[] = {"ad", *fpath, NULL}; const int ret = archiver(tmp_cmd, 'd'); free(*fpath); free(*mime); return ret; } else { xerror(_("%s: '%s': No associated application found\n"), err_name, arg); } #else xerror(_("%s: '%s': No associated application found\n"), err_name, arg); #endif /* !_NO_ARCHIVING */ } free(*fpath); free(*mime); return FUNC_FAILURE; } static int print_error_no_mime(char **fpath) { xerror(_("%s: Error getting MIME type\n"), err_name); free(*fpath); return FUNC_FAILURE; } static void print_info_name_mime(const char *filename, const char *mime) { printf(_("Name: %s\n"), filename ? filename : _("None")); printf(_("MIME type: %s\n"), mime ? mime : _("unknown")); } static int print_mime_info(char **app, char **fpath, char **mime) { if (*(*app) == 'a' && (*app)[1] == 'd' && !(*app)[2]) { printf(_("Opening application: ad [builtin] [%s]\n"), g_mime_match ? "MIME" : "FILENAME"); } else { printf(_("Opening application: '%s' [%s]\n"), *app, g_mime_match ? "MIME" : "FILENAME"); } if (!config_dir || !*config_dir) goto END; char *mime_file_ptr = mime_file; char buf[PATH_MAX + 1]; if (alt_preview_file && *alt_preview_file) { mime_file = alt_preview_file; } else { snprintf(buf, sizeof(buf), "%s/preview.clifm", config_dir); mime_file = buf; } char *preview_app = get_app(*mime, *fpath); printf(_("Previewing application: '%s' %s\n"), (preview_app && *preview_app) ? preview_app : "None", (preview_app && *preview_app) ? (g_mime_match ? "[MIME]" : "[FILENAME]") : ""); mime_file = mime_file_ptr; free(preview_app); END: free(*fpath); free(*mime); free(*app); return FUNC_SUCCESS; } #ifndef _NO_ARCHIVING static int run_archiver(char **fpath, char **app, char **mime_type) { char *cmd[] = {"ad", *fpath, NULL}; const int exit_status = archiver(cmd, 'd'); free(*fpath); free(*app); free(*mime_type); return exit_status; } #endif /* _NO_ARCHIVING */ static int print_mime_help(void) { puts(_(MIME_USAGE)); return FUNC_SUCCESS; } /* Open a file according to the application associated to its MIME type * or extension. It also accepts the 'info' and 'edit' arguments, the * former providing MIME info about the corresponding file and the * latter opening the MIME list file. */ int mime_open(char **args) { if (!args[1] || IS_HELP(args[1])) return print_mime_help(); err_name = (xargs.open == 1 || xargs.preview == 1) ? PROGRAM_NAME : "lira"; if (*args[1] == 'i' && strcmp(args[1], "import") == 0) return import_mime(); if (*args[1] == 'e' && strcmp(args[1], "edit") == 0) return mime_edit(args); char *file_path = (char *)NULL; const int info = (*args[1] == 'i' && strcmp(args[1], "info") == 0); const int file_index = info == 1 ? 2 : 1; if (info == 1) { const int ret = check_mime_info_file(args[2], &file_path); if (ret != FUNC_SUCCESS) return ret; } else { const int ret = get_open_file_path(args, &file_path); if (ret != FUNC_SUCCESS) return ret; } if (!file_path) { xerror("%s: %s\n", args[file_index], strerror(errno)); return FUNC_FAILURE; } /* Get file's MIME type */ char *mime = xmagic(file_path, MIME_TYPE); if (!mime) return print_error_no_mime(&file_path); const char *filename = get_basename(file_path); if (info == 1) print_info_name_mime(filename, mime); /* Get default application for MIME or filename */ char *app = get_app(mime, filename); if (!app) return handle_no_app(info, &file_path, &mime, args[1]); if (info == 1) return print_mime_info(&app, &file_path, &mime); /* Construct and execute the command */ #ifndef _NO_ARCHIVING if (*app == 'a' && app[1] == 'd' && !app[2]) return run_archiver(&file_path, &app, &mime); #endif /* !_NO_ARCHIVING */ g_mime_type = mime; #ifdef __CYGWIN__ /* Some Windows programs, like Word and Powerpoint (but not Excel!!), do * not like absolute paths when the filename contains spaces. So, let's * pass the filename as it was passed to this function, without * expanding it to an absolute path. * This hack must be removed as soon as the real cause is discovered: * why Word/Powerpoint fails to open absolute paths when the filename * contains spaces? */ const int ret = run_mime_app(app, args[file_index]); #else const int ret = run_mime_app(app, file_path); #endif /* __CYGWIN__ */ free(mime); g_mime_type = (char *)NULL; free(app); free(file_path); return ret; } #endif /* !_NO_LIRA */ clifm-1.26.3/src/mime.h000066400000000000000000000023031506632037700145730ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* mime.h */ #ifndef MIME_H #define MIME_H __BEGIN_DECLS int mime_open(char **args); int mime_open_url(char *url); int mime_open_with(char *filename, char **args); char **mime_open_with_tab(char *filename, const char *prefix, const int only_names); char *xmagic(const char *file, const int query_mime); __END_DECLS #endif /* MIME_H */ clifm-1.26.3/src/mimetypes.c000066400000000000000000000064201506632037700156570ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* mimetypes.c -- read, parse, and store info from mime.types files */ #include "helpers.h" #include /* strdup, strlen, strchr, strtok */ #include "aux.h" /* hashme() */ #define INIT_BUF_SIZE 1024 static void check_hash_conflicts(void) { size_t i, j; for (i = 0; user_mimetypes[i].mimetype; i++) for (j = i + 1; user_mimetypes[j].mimetype; j++) if (user_mimetypes[i].ext_hash == user_mimetypes[j].ext_hash) *user_mimetypes[i].ext = '\0'; } static char * get_mimetypes_file(void) { char *p = (char *)NULL; if (xargs.secure_env != 1 && xargs.secure_env_full != 1) { p = getenv("CLIFM_MIMETYPES_FILE"); if (p && *p) return strdup(p); } if (!user.home || !*user.home) return (char *)NULL; const size_t len = user.home_len + 13; p = xnmalloc(len, sizeof(char)); snprintf(p, len, "%s/.mime.types", user.home); return p; } int load_user_mimetypes(void) { char *mimetypes_file = get_mimetypes_file(); if (!mimetypes_file) return FUNC_FAILURE; struct stat a; int fd = 0; FILE *fp = open_fread(mimetypes_file, &fd); if (!fp || fstatat(fd, mimetypes_file, &a, 0) == -1 || !S_ISREG(a.st_mode)) { if (fp) fclose(fp); free(mimetypes_file); return FUNC_FAILURE; } free(mimetypes_file); size_t buf_size = INIT_BUF_SIZE; size_t n = 0; char line[PATH_MAX]; *line = '\0'; user_mimetypes = xnmalloc(buf_size, sizeof(struct mime_t)); while (fgets(line, (int)sizeof(line), fp)) { if (!*line || *line <= '0') continue; char *p = strchr(line, '\n'); if (p) *p = '\0'; const char *mimetype = strtok(line, " \t"); if (!mimetype) continue; const size_t mime_len = strlen(mimetype); char *ext = (char *)NULL; while ((ext = strtok(NULL, " \t")) != NULL) { if (n == buf_size) { buf_size *= 2; user_mimetypes = xnrealloc(user_mimetypes, buf_size, sizeof(struct mime_t)); } user_mimetypes[n].ext = savestring(ext, strlen(ext)); user_mimetypes[n].ext_hash = hashme(ext, conf.case_sens_list); user_mimetypes[n].mimetype = savestring(mimetype, mime_len); n++; } } fclose(fp); if (n == 0) { free(user_mimetypes); user_mimetypes = (struct mime_t *)NULL; return FUNC_SUCCESS; } user_mimetypes[n].mimetype = (char *)NULL; user_mimetypes[n].ext = (char *)NULL; user_mimetypes[n].ext_hash = 0; check_hash_conflicts(); if (n != buf_size) { user_mimetypes = realloc(user_mimetypes, (n + 1) * sizeof(struct mime_t)); } return FUNC_SUCCESS; } clifm-1.26.3/src/mimetypes.h000066400000000000000000000020171506632037700156620ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* mimetypes.h */ #ifndef CLIFM_MIMETYPES_H # define CLIFM_MIMETYPES_H __BEGIN_DECLS int load_user_mimetypes(void); __END_DECLS #endif /* CLIFM_MIMETYPES_H */ clifm-1.26.3/src/misc.c000066400000000000000000001437751506632037700146150ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* misc.c -- functions that do not fit in any other file */ /* The err function is based on littlstar's asprintf implementation * (https://github.com/littlstar/asprintf.c/blob/master/asprintf.c), * licensed under MIT. * All changes are licensed under GPL-2.0-or-later. */ #include "helpers.h" #include #include #include #include #include #include /* tcsetattr */ #ifdef __sun # include /* TIOCGWINSZ */ #endif /* __sun */ #if defined(__NetBSD__) || defined(__FreeBSD__) # include # include #endif /* __NetBSD__ || __FreeBSD__ */ #ifdef __OpenBSD__ typedef char *rl_cpvfunc_t; # include #else # include #endif /* __OpenBSD__ */ #include #include #ifdef LINUX_INOTIFY # include #endif /* LINUX_INOTIFY */ #include "aux.h" #include "autocmds.h" /* update_autocmd_opts() */ #include "bookmarks.h" #include "checks.h" #include "file_operations.h" #include "history.h" #include "init.h" #include "jump.h" #include "listing.h" #include "messages.h" #include "navigation.h" #include "readline.h" #include "remotes.h" #include "spawn.h" char * gen_diff_str(const int diff) { if (diff == 1) return "\x1b[1C"; if (diff == 2) return "\x1b[2C"; if (diff == 3) return "\x1b[3C"; static char diff_str[14]; snprintf(diff_str, sizeof(diff_str), "\x1b[%dC", diff); return diff_str; } int is_blank_name(const char *s) { if (!s || !*s) return 1; int blank = 1; while (*s) { if (*s != ' ' && *s != '\n' && *s != '\t') { blank = 0; break; } s++; } return blank; } /* Prompt for a new name using MSG as prompt. * If OLD_NAME is not NULL, it will be used as template for the new name. * If the entered name is quoted, it will be returned verbatim (without quotes), * and QUOTED will be set to 1 (the caller should not perform expansions on * this name). */ char * get_newname(const char *msg, char *old_name, int *quoted) { rl_nohist = 1; alt_prompt = FILES_PROMPT; int poffset_bk = prompt_offset; prompt_offset = 3; char *n = (old_name && *old_name) ? unescape_str(old_name, 0) : (char *)NULL; char *input = secondary_prompt((msg && *msg) ? msg : "> ", n ? n : (char *)NULL); free(n); char *new_name = (char *)NULL; if (!input) goto END; char *p = remove_quotes(input); if (!p || !*p) /* Input was "" (empty string) */ goto END; if (p != input) { /* Quoted: copy input verbatim (without quotes) */ *quoted = 1; new_name = savestring(p, strlen(p)); goto END; } char *deq = unescape_str(p, 0); char *tmp = deq ? deq : p; size_t len = strlen(tmp); int i = len > 1 ? (int)len - 1 : 0; while (tmp[i] == ' ') { tmp[i] = '\0'; i--; } new_name = savestring(tmp, (size_t)i + 1); free(deq); END: free(input); alt_prompt = rl_nohist = 0; prompt_offset = poffset_bk; return new_name; } /* Set ELN color according to the current workspace. */ void set_eln_color(void) { char *cl = (char *)NULL; switch (cur_ws) { case 0: cl = ws1_c; break; case 1: cl = ws2_c; break; case 2: cl = ws3_c; break; case 3: cl = ws4_c; break; case 4: cl = ws5_c; break; case 5: cl = ws6_c; break; case 6: cl = ws7_c; break; case 7: cl = ws8_c; break; default: break; } if (!cl || !*cl) { xstrsncpy(el_c, term_caps.color >= 256 ? DEF_EL_C256 : DEF_EL_C, sizeof(el_c)); return; } /* Remove leading and trailing control characters (\001 and \002). */ size_t cl_len = 0; if (*cl == 001) { cl++; cl_len = strlen(cl); if (cl_len > 0 && cl[cl_len - 1] == 002) cl[cl_len - 1] = '\0'; } xstrsncpy(el_c, cl, sizeof(el_c)); if (cl_len > 0) cl[cl_len - 1] = 002; } /* Custom POSIX implementation of GNU asprintf() modified to log program * messages. * * MSG_TYPE is one of: 'e', 'f', 'w', 'n', zero (meaning this * latter that no message mark (E, W, or N) will be added to the prompt). * If MSG_TYPE is 'n' the message is not not logged. * 'f' means that the message must be printed forcefully, even if identical * to the previous one, without printing any message mark. * MSG_TYPE also accepts ERR_NO_LOG (-1) and ERR_NO_STORE (-2) as values: * ERR_NO_LOG: Print the message but do not log it. * ERR_NO_STORE: Log but do not store the message in the messages array. * * PROMPT_FLAG tells whether to print the message immediately before the next * prompt or rather in place. * * This function guarantees not to modify the value of errno, usually passed * as part of the format string to print error messages. * */ __attribute__((__format__(__printf__, 3, 0))) /* We use __attribute__ here to silence clang warning: "format string is * not a string literal" */ int err(const int msg_type, const int prompt_flag, const char *format, ...) { const int saved_errno = errno; va_list arglist; va_start(arglist, format); int size = vsnprintf((char *)NULL, 0, format, arglist); va_end(arglist); if (size < 0) goto ERROR; const size_t n = (size_t)size + 1; char *buf = xnmalloc(n, sizeof(char)); va_start(arglist, format); size = vsnprintf(buf, n, format, arglist); va_end(arglist); if (size < 0 || !buf || !*buf) {free(buf); goto ERROR;} /* If the new message is the same as the last message, skip it. */ if (msgs_n > 0 && msg_type != 'f' && *messages[msgs_n - 1].text == *buf && strcmp(messages[msgs_n - 1].text, buf) == 0) {free(buf); goto ERROR;} if (msg_type >= 'e') { switch (msg_type) { case 'e': pmsg = ERROR; msgs.error++; break; case 'w': pmsg = WARNING; msgs.warning++; break; case 'n': pmsg = NOTICE; msgs.notice++; break; default: pmsg = NOMSG; break; } } int logme = msg_type == ERR_NO_LOG ? 0 : (msg_type == 'n' ? -1 : 1); int add_to_msgs_list = 1; if (msg_type == ERR_NO_STORE) { add_to_msgs_list = 0; logme = 1; /* if (prompt_flag == NOPRINT_PROMPT && term_caps.unicode == 1) { // Invoked as xerror() printf("%s%s%s ", xf_c, ERROR_PTR_STR_U, df_c); fflush(stdout); } */ } log_msg(buf, prompt_flag, logme, add_to_msgs_list); free(buf); errno = saved_errno; return FUNC_SUCCESS; ERROR: errno = saved_errno; return FUNC_FAILURE; } /* Print format string MSG, as "> MSG" (colored), if autols is on, or just * as "MSG" if off. * Use PTR as pointer, or ">" if PTR is NULL. * Use COLOR as pointer color, or mi_c if COLOR is NULL. * This function is used to inform the user about changes that require a * a file list reload (either upon files or interface modifications). */ __attribute__((__format__(__printf__, 3, 4))) int print_reload_msg(const char *ptr, const char *color, const char *msg, ...) { va_list arglist; va_start(arglist, msg); const int size = vsnprintf((char *)NULL, 0, msg, arglist); va_end(arglist); if (size < 0) return FUNC_FAILURE; if (conf.autols == 1) printf("%s%s%s ", color ? color : mi_c, ptr ? ptr : SET_MSG_PTR, df_c); char *buf = xnmalloc((size_t)size + 1, sizeof(char)); va_start(arglist, msg); vsnprintf(buf, (size_t)size + 1, msg, arglist); va_end(arglist); fputs(buf, stdout); free(buf); return FUNC_SUCCESS; } #ifdef LINUX_INOTIFY void reset_inotify(void) { watch = 0; if (inotify_wd >= 0) { inotify_rm_watch(inotify_fd, inotify_wd); inotify_wd = -1; } if (inotify_fd != UNSET) close(inotify_fd); inotify_fd = inotify_init1(IN_NONBLOCK); if (inotify_fd < 0) { err('w', PRINT_PROMPT, "%s: inotify: %s\n", PROGRAM_NAME, strerror(errno)); return; } /* If CWD is a symlink to a directory and it does not end with a slash, * inotify_add_watch(3) fails with ENOTDIR. */ char rpath[PATH_MAX + 1]; snprintf(rpath, sizeof(rpath), "%s/", workspaces[cur_ws].path); inotify_wd = inotify_add_watch(inotify_fd, rpath, INOTIFY_MASK); if (inotify_wd > 0) watch = 1; else err('w', PRINT_PROMPT, "%s: inotify: '%s': %s\n", PROGRAM_NAME, rpath, strerror(errno)); } void read_inotify(void) { if (inotify_fd == UNSET) return; int i; struct inotify_event *event; char inotify_buf[EVENT_BUF_LEN]; memset((void *)inotify_buf, '\0', sizeof(inotify_buf)); i = (int)read(inotify_fd, inotify_buf, sizeof(inotify_buf)); /* flawfinder: ignore */ if (i <= 0) { # ifdef INOTIFY_DEBUG puts("INOTIFY_RETURN"); # endif /* INOTIFY_DEBUG */ return; } int ignore_event = 0; int refresh = 0; for (char *ptr = inotify_buf; ptr + ((struct inotify_event *)ptr)->len < inotify_buf + i; ptr += sizeof(struct inotify_event) + event->len) { event = (struct inotify_event *)ptr; # ifdef INOTIFY_DEBUG printf("%s (%u:%d): ", *event->name ? event->name : NULL, event->len, event->wd); # endif /* INOTIFY_DEBUG */ if (!event->wd) { # ifdef INOTIFY_DEBUG puts("INOTIFY_BREAK"); # endif /* INOTIFY_DEBUG */ break; } if (event->mask & IN_CREATE) { # ifdef INOTIFY_DEBUG puts("IN_CREATE"); # endif /* INOTIFY_DEBUG */ struct stat a; if (event->len && lstat(event->name, &a) != 0) { /* The file was created, but doesn't exist anymore */ ignore_event = 1; } } /* A file was renamed */ if (event->mask & IN_MOVED_TO) { # ifdef INOTIFY_DEBUG puts("IN_MOVED_TO"); # endif /* INOTIFY_DEBUG */ filesn_t j = files; while (--j >= 0) { if (*file_info[j].name == *event->name && strcmp(file_info[j].name, event->name) == 0) break; } /* If destiny filename is already in the file list (j >= 0), * ignore this event. */ ignore_event = (j < 0) ? 0 : 1; } if (event->mask & IN_DELETE) { # ifdef INOTIFY_DEBUG puts("IN_DELETE"); # endif /* INOTIFY_DEBUG */ struct stat a; if (event->len && lstat(event->name, &a) == 0) /* The file was removed, but is still there (recreated) */ ignore_event = 1; } # ifdef INOTIFY_DEBUG if (event->mask & IN_DELETE_SELF) puts("IN_DELETE_SELF"); if (event->mask & IN_MOVE_SELF) puts("IN_MOVE_SELF"); if (event->mask & IN_MOVED_FROM) puts("IN_MOVED_FROM"); if (event->mask & IN_MOVED_TO) puts("IN_MOVED_TO"); if (event->mask & IN_IGNORED) puts("IN_IGNORED"); # endif /* INOTIFY_DEBUG */ if (ignore_event == 0 && (event->mask & INOTIFY_MASK)) refresh = 1; } if (refresh == 1 && exit_code == FUNC_SUCCESS) { # ifdef INOTIFY_DEBUG puts("INOTIFY_REFRESH"); # endif /* INOTIFY_DEBUG */ reload_dirlist(); } else { # ifdef INOTIFY_DEBUG puts("INOTIFY_RESET"); # endif /* INOTIFY_DEBUG */ /* Reset the inotify watch list */ reset_inotify(); } } #elif defined(BSD_KQUEUE) /* Insert the following lines in the for loop to debug kqueue: if (event_data[i].fflags & NOTE_DELETE) puts("NOTE_DELETE"); if (event_data[i].fflags & NOTE_WRITE) puts("NOTE_WRITE"); if (event_data[i].fflags & NOTE_EXTEND) puts("NOTE_EXTEND"); if (event_data[i].fflags & NOTE_ATTRIB) puts("NOTE_ATTRIB"); if (event_data[i].fflags & NOTE_LINK) puts("NOTE_LINK"); if (event_data[i].fflags & NOTE_RENAME) puts("NOTE_RENAME"); if (event_data[i].fflags & NOTE_REVOKE) puts("NOTE_REVOKE"); */ void read_kqueue(void) { struct kevent event_data[NUM_EVENT_SLOTS]; memset((void *)event_data, '\0', sizeof(struct kevent) * NUM_EVENT_SLOTS); int i; const int count = kevent(kq, NULL, 0, event_data, 4096, &timeout); for (i = 0; i < count; i++) { if (event_data[i].fflags & KQUEUE_FFLAGS) { reload_dirlist(); return; } } } #endif /* LINUX_INOTIFY */ void set_filter_type(const char c) { if (c == '=') filter.type = FILTER_FILE_TYPE; else if (c == '@') filter.type = FILTER_MIME_TYPE; /* UNIMPLEMENTED */ else filter.type = FILTER_FILE_NAME; } static int unset_filter(void) { if (!filter.str) { puts(_("ft: No filter set")); return FUNC_SUCCESS; } free(filter.str); filter.str = (char *)NULL; filter.rev = 0; filter.type = FILTER_NONE; regfree(®ex_exp); if (conf.autols == 1) reload_dirlist(); print_reload_msg(NULL, NULL, _("Filter unset\n")); return FUNC_SUCCESS; } static int validate_file_type_filter(void) { if (!filter.str || !*filter.str || *filter.str != '=' || !filter.str[1] || filter.str[2]) return FUNC_FAILURE; const char c = filter.str[1]; if (c == 'b' || c == 'c' || c == 'd' || c == 'f' #ifdef SOLARIS_DOORS || c == 'l' || c == 'p' || c == 's' || c == 'O' || c == 'P') #else || c == 'l' || c == 'p' || c == 's') #endif /* SOLARIS_DOORS */ return FUNC_SUCCESS; if (conf.light_mode == 1) return FUNC_FAILURE; if (c == 'g' || c == 'h' || c == 'o' || c == 't' || c == 'u' || c == 'x' || c == 'D' || c == 'F' || c == 'L') return FUNC_SUCCESS; return FUNC_FAILURE; } static int compile_filter(void) { if (filter.type == FILTER_FILE_NAME) { const int ret = regcomp(®ex_exp, filter.str, REG_NOSUB | REG_EXTENDED); if (ret != FUNC_SUCCESS) { xregerror("ft", filter.str, ret, regex_exp, 0); regfree(®ex_exp); goto ERR; } } else if (filter.type == FILTER_FILE_TYPE) { if (validate_file_type_filter() != FUNC_SUCCESS) { xerror("%s\n", _("ft: Invalid file type filter")); goto ERR; } } else { xerror("%s\n", _("ft: Invalid filter")); goto ERR; } if (conf.autols == 1) reload_dirlist(); return FUNC_SUCCESS; ERR: free(filter.str); filter.str = (char *)NULL; filter.type = FILTER_NONE; return FUNC_FAILURE; } int filter_function(char *arg) { if (!arg) { printf(_("Current filter: %c%s\n"), filter.rev == 1 ? '!' : 0, filter.str ? filter.str : _("none")); return FUNC_SUCCESS; } if (IS_HELP(arg)) { puts(_(FILTER_USAGE)); return FUNC_SUCCESS; } if (*arg == 'u' && strcmp(arg, "unset") == 0) { const int ret = unset_filter(); update_autocmd_opts(AC_FILTER); return ret; } free(filter.str); regfree(®ex_exp); if (*arg == '!') { filter.rev = 1; arg++; } else { filter.rev = 0; } char *p = arg; if (*arg == '\'' || *arg == '"') { p = remove_quotes(arg); if (!p) { xerror("%s\n", _("ft: Error removing quotes: Filter unset")); return FUNC_FAILURE; } } set_filter_type(*p); filter.str = savestring(p, strlen(p)); update_autocmd_opts(AC_FILTER); return compile_filter(); } /* Check whether the conditions to run the new_instance function are * fulfilled */ static int check_new_instance_init_conditions(void) { if (!(flags & GUI)) { xerror(_("%s: Function only available for graphical " "environments\n"), PROGRAM_NAME); return FUNC_FAILURE; } if (!conf.term || !*conf.term) { xerror(_("%s: Default terminal not set. Use the " "configuration file (F10) to set it.\n"), PROGRAM_NAME); return FUNC_FAILURE; } /* Check command existence. */ char *s = strchr(conf.term, ' '); if (s) *s = '\0'; if (is_cmd_in_path(conf.term) == 0) { xerror("%s: %s: %s\n", PROGRAM_NAME, conf.term, NOTFOUND_MSG); if (s) *s = ' '; return E_NOTFOUND; } if (s) *s = ' '; return FUNC_SUCCESS; } /* Just check if DIR exists and it is a directory. */ static int check_dir(char **dir) { int ret = FUNC_SUCCESS; struct stat attr; if (stat(*dir, &attr) == -1) { xerror("%s: '%s': %s\n", PROGRAM_NAME, *dir, strerror(errno)); return errno; } if (!S_ISDIR(attr.st_mode)) { xerror(_("%s: '%s': Not a directory\n"), PROGRAM_NAME, *dir); return ENOTDIR; } return ret; } /* Construct absolute path for DIR */ static char * get_path_dir(char **dir) { char *path_dir = (char *)NULL; if (*(*dir) != '/') { const size_t len = strlen(workspaces[cur_ws].path) + strlen(*dir) + 2; path_dir = xnmalloc(len, sizeof(char)); snprintf(path_dir, len, "%s/%s", workspaces[cur_ws].path, *dir); free(*dir); *dir = (char *)NULL; } else { path_dir = *dir; } return path_dir; } /* Get command to be executed by the new_instance function, only if * CONF.TERM (global) contains spaces. Otherwise, new_instance will try * "CONF.TERM clifm". */ static char ** get_cmd(char *dir, char *_sudo, char *self, const int sudo) { if (!conf.term || !strchr(conf.term, ' ')) return (char **)NULL; char **tmp_term = get_substr(conf.term, ' ', 0); if (!tmp_term) return (char **)NULL; int i; for (i = 0; tmp_term[i]; i++); int num = i; char **cmd = xnmalloc((size_t)i + (sudo == 1 ? 4 : 3), sizeof(char *)); for (i = 0; tmp_term[i]; i++) { cmd[i] = savestring(tmp_term[i], strlen(tmp_term[i])); free(tmp_term[i]); } free(tmp_term); i = num - 1; int plus = 1; size_t len = 0; if (sudo == 1) { len = strlen(self); cmd[i + plus] = xnmalloc(len + 1, sizeof(char)); xstrsncpy(cmd[i + plus], _sudo, len + 1); plus++; } len = strlen(self); cmd[i + plus] = xnmalloc(len + 1, sizeof(char)); xstrsncpy(cmd[i + plus], self, len + 1); plus++; len = strlen(dir); cmd[i + plus] = xnmalloc(len + 1, sizeof(char)); xstrsncpy(cmd[i + plus], dir, len + 1); plus++; cmd[i + plus] = (char *)NULL; return cmd; } /* Print the command CMD and ask the user for confirmation. * Returns 1 if yes or 0 if no. */ int confirm_sudo_cmd(char **cmd) { if (!cmd) return 0; size_t i; for (i = 0; cmd[i]; i++) { fputs(cmd[i], stdout); putchar(' '); } if (i > 0) putchar('\n'); return rl_get_y_or_n(_("Run command?"), 0); } /* Launch a new instance using CMD. If CMD is NULL, try "CONF.TERM clifm". * Returns the exit status of the executed command. */ static int launch_new_instance_cmd(char ***cmd, char **self, char **sudo_prog, char **dir, int sudo) { int ret = 0; #if defined(__HAIKU__) sudo = 0; #endif /* __HAIKU__ */ if (*cmd) { ret = (sudo == 0 || confirm_sudo_cmd(*cmd) == 1) ? launch_execv(*cmd, BACKGROUND, E_SETSID) : FUNC_SUCCESS; for (size_t i = 0; (*cmd)[i]; i++) free((*cmd)[i]); free(*cmd); } else { if (sudo == 1) { char *tcmd[] = {conf.term, *sudo_prog, *self, *dir, NULL}; ret = (confirm_sudo_cmd(tcmd) == 1) ? launch_execv(tcmd, BACKGROUND, E_SETSID) : FUNC_SUCCESS; } else { char *tcmd[] = {conf.term, *self, *dir, NULL}; ret = launch_execv(tcmd, BACKGROUND, E_SETSID); } } free(*sudo_prog); free(*self); free(*dir); return ret; } /* After the last line of new_instance */ // cppcheck-suppress syntaxError /* Open DIR in a new instance of the program (using TERM, set in the config * file, as terminal emulator). */ int new_instance(char *dir, int sudo) { int ret = check_new_instance_init_conditions(); if (ret != FUNC_SUCCESS) return ret; if (!dir) return EINVAL; /* Do not run with sudo if already root */ if (user.uid == 0) sudo = 0; char *sudo_prog = (char *)NULL; #ifndef __HAIKU__ if (sudo == 1 && !(sudo_prog = get_sudo_path())) return errno; #endif /* !__HAIKU__ */ char *deq_dir = unescape_str(dir, 0); if (!deq_dir) { free(sudo_prog); xerror(_("%s: '%s': Cannot escape filename\n"), PROGRAM_NAME, dir); return FUNC_FAILURE; } char *self = get_cmd_path(PROGRAM_NAME); if (!self) { free(sudo_prog); free(deq_dir); xerror("%s: %s: %s\n", PROGRAM_NAME, PROGRAM_NAME, strerror(errno)); return errno; } ret = check_dir(&deq_dir); if (ret != FUNC_SUCCESS) { free(deq_dir); free(self); free(sudo_prog); return ret; } char *path_dir = get_path_dir(&deq_dir); char **cmd = get_cmd(path_dir, sudo_prog, self, sudo); return launch_new_instance_cmd(&cmd, &self, &sudo_prog, &path_dir, sudo); } /* Import (copy to main config file) aliases from the file named FILE. * Returns 0 on success or >0 on error. */ int alias_import(char *file) { if (xargs.stealth_mode == 1) { printf("%s: alias: %s\n", PROGRAM_NAME, STEALTH_DISABLED); return FUNC_SUCCESS; } if (!file) return FUNC_FAILURE; char *npath = normalize_path(file, strlen(file)); if (!npath) { xerror(_("alias: '%s': Error normalizing filename\n"), file); return FUNC_FAILURE; } char rfile[PATH_MAX + 1]; *rfile = '\0'; xstrsncpy(rfile, npath, sizeof(rfile)); free(npath); /* Open the file to import aliases from. */ int fd; FILE *fp = open_fread(rfile, &fd); if (!fp) { xerror("alias: '%s': %s\n", rfile, strerror(errno)); return errno; } /* Open clifm's config file as well. */ FILE *config_fp = open_fappend(config_file); if (!config_fp) { xerror("alias: '%s': %s\n", config_file, strerror(errno)); fclose(fp); return errno; } size_t line_size = 0, i; char *line = (char *)NULL; size_t alias_found = 0, alias_imported = 0; int first = 1; while (getline(&line, &line_size, fp) > 0) { if (*line != 'a' || strncmp(line, "alias ", 6) != 0) continue; alias_found++; /* If alias name conflicts with some internal command, skip it. */ char *alias_name = strbtw(line, ' ', '='); if (!alias_name) continue; if (is_internal_cmd(alias_name, ALL_CMDS, 1, 1)) { xerror(_("'%s': Alias conflicts with internal " "command\n"), alias_name); free(alias_name); continue; } char *p = line + 6; /* p points now to the beginning of the alias name * (because "alias " == 6). */ char *tmp = strchr(p, '='); if (!tmp || !tmp[1] || (tmp[1] != '\'' && tmp[1] != '"')) { free(alias_name); continue; } *tmp = '\0'; /* If the alias name already exists, skip it too. */ int exists = 0; for (i = 0; i < aliases_n; i++) { if (*p == *aliases[i].name && strcmp(aliases[i].name, p) == 0) { exists = 1; break; } } *tmp = '='; if (exists == 0) { if (first == 1) { first = 0; fputs("\n\n", config_fp); } alias_imported++; /* Write the new alias into CliFM's config file */ fputs(line, config_fp); } else { xerror(_("'%s': Alias already exists\n"), alias_name); } free(alias_name); } free(line); fclose(fp); fclose(config_fp); /* No alias was found in FILE */ if (alias_found == 0) { xerror(_("alias: No alias found in '%s'\n"), rfile); return FUNC_FAILURE; } /* Aliases were found in FILE, but none was imported (either because * they conflicted with internal commands or the alias already * existed). */ if (alias_imported == 0) { xerror(_("alias: No alias imported\n")); return FUNC_FAILURE; } /* If some alias was found and imported, print the corresponding * message and update the aliases array. */ printf(_("alias: %zu alias(es) imported\n"), alias_imported); /* Add new aliases to the internal list of aliases. */ get_aliases(); /* Add new aliases to the commands list for tab completion. */ if (bin_commands) { for (i = 0; bin_commands[i]; i++) free(bin_commands[i]); free(bin_commands); bin_commands = (char **)NULL; } get_path_programs(); return FUNC_SUCCESS; } char * parse_usrvar_value(const char *str, const char c) { if (c == '\0' || !str) return (char *)NULL; /* Get whatever comes after c */ char *tmp = strchr(str, c); if (!tmp || !*(++tmp)) return (char *)NULL; /* Remove leading quotes */ if (*tmp == '"' || *tmp == '\'') tmp++; /* Remove trailing spaces, tabs, new line chars, and quotes */ const size_t tmp_len = strlen(tmp); for (size_t i = tmp_len - 1; tmp[i] && i > 0; i--) { if (tmp[i] != ' ' && tmp[i] != '\t' && tmp[i] != '"' && tmp[i] != '\'' && tmp[i] != '\n') break; else tmp[i] = '\0'; } if (!*tmp) return (char *)NULL; char *buf = savestring(tmp, strlen(tmp)); return buf; } int create_usr_var(const char *str) { if (!str || !*str) return FUNC_FAILURE; char *p = strchr(str, '='); if (!p || p == str) return FUNC_FAILURE; *p = '\0'; const size_t len = (size_t)(p - str); char *name = xnmalloc(len + 1, sizeof(char)); xstrsncpy(name, str, len + 1); *p = '='; char *value = parse_usrvar_value(str, '='); if (!value) { free(name); xerror(_("%s: Error getting variable value\n"), PROGRAM_NAME); return FUNC_FAILURE; } usr_var = xnrealloc(usr_var, (size_t)(usrvar_n + 2), sizeof(struct usrvar_t)); usr_var[usrvar_n].name = savestring(name, strlen(name)); usr_var[usrvar_n].value = savestring(value, strlen(value)); usrvar_n++; usr_var[usrvar_n].name = (char *)NULL; usr_var[usrvar_n].value = (char *)NULL; free(name); free(value); return FUNC_SUCCESS; } /* // Resize the autocmds array leaving only temporary autocommands. static void keep_temp_autocmds(void) { size_t i; size_t c = 0; struct autocmds_t *a = (struct autocmds_t *)NULL; for (i = 0; i < autocmds_n; i++) { if (autocmds[i].temp == 1) { a = xnrealloc(a, c + 2, sizeof(struct autocmds_t)); memmove(a + c, autocmds + i, sizeof(struct autocmds_t)); c++; a[c] = (struct autocmds_t){0}; } free(autocmds[i].pattern); free(autocmds[i].cmd); free(autocmds[i].filter.str); autocmds[i] = (struct autocmds_t){0}; } autocmds_n = c; free(autocmds); autocmds = a; // autocmds = xnrealloc(autocmds, autocmds_n, sizeof(struct autocmds_t)); } */ void free_autocmds(const int keep_temp) { UNUSED(keep_temp); /* int i = (int)autocmds_n; if (keep_temp == 1) { while (--i >= 0) { if (autocmds[i].temp == 1) { keep_temp_autocmds(); return; } } } */ int i = (int)autocmds_n; while (--i >= 0) { free(autocmds[i].pattern); free(autocmds[i].cmd); free(autocmds[i].filter.str); autocmds[i].color_scheme = (char *)NULL; } free(autocmds); autocmds = (struct autocmds_t *)NULL; autocmds_n = 0; autocmd_set = 0; } void free_tags(void) { int i = (int)tags_n; while (--i >= 0) free(tags[i]); free(tags); tags = (char **)NULL; tags_n = 0; } int free_remotes(const int exit) { if (exit) autounmount_remotes(); for (size_t i = 0; i < remotes_n; i++) { free(remotes[i].name); free(remotes[i].desc); free(remotes[i].mountpoint); free(remotes[i].mount_cmd); free(remotes[i].unmount_cmd); } free(remotes); remotes_n = 0; return FUNC_SUCCESS; } /* Load both regular and warning prompt, if enabled, from the prompt name NAME. * Return FUNC_SUCCESS if found or FUNC_FAILURE if not. */ int expand_prompt_name(char *name) { if (!name || !*name || prompts_n == 0) return FUNC_FAILURE; char *p = remove_quotes(name); if (!p || !*p || strchr(p, '\\')) /* Exclude prompt codes. */ return FUNC_FAILURE; int i = (int)prompts_n; while (--i >= 0) { if (*p != *prompts[i].name || strcmp(p, prompts[i].name) != 0) continue; if (prompts[i].regular) { free(conf.encoded_prompt); conf.encoded_prompt = savestring(prompts[i].regular, strlen(prompts[i].regular)); } if (prompts[i].warning) { free(conf.wprompt_str); conf.wprompt_str = savestring(prompts[i].warning, strlen(prompts[i].warning)); } if (prompts[i].right) { free(conf.rprompt_str); conf.rprompt_str = savestring(prompts[i].right, strlen(prompts[i].right)); if (prompts[i].regular) conf.prompt_is_multiline = strstr(prompts[i].regular, "\\n") ? 1 : 0; } prompt_notif = prompts[i].notifications; if (xargs.warning_prompt != 0) conf.warning_prompt = prompts[i].warning_prompt_enabled; xstrsncpy(cur_prompt_name, prompts[i].name, sizeof(cur_prompt_name)); return FUNC_SUCCESS; } return FUNC_FAILURE; } void free_prompts(void) { int i = (int)prompts_n; while (--i >= 0) { free(prompts[i].name); free(prompts[i].regular); free(prompts[i].warning); free(prompts[i].right); } free(prompts); prompts = (struct prompts_t *)NULL; prompts_n = 0; } static void remove_virtual_dir(void) { struct stat a; if (stdin_tmp_dir && stat(stdin_tmp_dir, &a) != -1) { xchmod(stdin_tmp_dir, "0700", 1); char *rm_cmd[] = {"rm", "-r", "--", stdin_tmp_dir, NULL}; const int ret = launch_execv(rm_cmd, FOREGROUND, E_NOFLAG); if (ret != FUNC_SUCCESS) exit_code = ret; free(stdin_tmp_dir); } unsetenv("CLIFM_VIRTUAL_DIR"); } /* #if defined(__clang__) // Free the storage associated with MAP static void xrl_discard_keymap(Keymap map) { if (map == 0) return; int i; for (i = 0; i < KEYMAP_SIZE; i++) { switch (map[i].type) { case ISFUNC: break; case ISKMAP: // GCC (but not clang) complains about this if compiled with -pedantic // See discussion here: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83584 xrl_discard_keymap((Keymap)map[i].function); break; case ISMACR: // GCC (not clang) complains about this one too free((char *)map[i].function); break; } } } #endif // __clang__ */ void free_workspaces_filters(void) { for (size_t i = 0; i < MAX_WS; i++) { free(workspace_opts[i].filter.str); workspace_opts[i].filter.str = (char *)NULL; workspace_opts[i].filter.rev = 0; workspace_opts[i].filter.type = FILTER_NONE; } } void save_last_path(char *last_path_tmp) { if (config_ok == 0 || !config_dir || !config_dir_gral) return; char *last_path = xnmalloc(config_dir_len + 7, sizeof(char)); snprintf(last_path, config_dir_len + 7, "%s/.last", config_dir); int fd = 0; FILE *last_fp = open_fwrite(last_path, &fd); if (!last_fp) { xerror(_("%s: Error saving last visited directory: %s\n"), PROGRAM_NAME, strerror(errno)); free(last_path); return; } for (size_t i = 0; i < MAX_WS; i++) { if (!workspaces[i].path) continue; if ((size_t)cur_ws == i) fprintf(last_fp, "*%zu:%s\n", i, workspaces[i].path); else fprintf(last_fp, "%zu:%s\n", i, workspaces[i].path); } fclose(last_fp); /* Last visited path is stored in the profile directory, but the * cd-on-quit script cannot know what our profile was. So, let's * symlink the .last file in our profile directory to the clifm * gral config dir, so that the script knows where to look for. */ if (conf.cd_on_quit == 1 && last_path_tmp && symlinkat(last_path, XAT_FDCWD, last_path_tmp) == -1) { xerror(_("%s: cd-on-quit: Cannot create symbolic link '%s': %s\n"), PROGRAM_NAME, last_path_tmp, strerror(errno)); } free(last_path); } /* Store last visited directory for the restore-last-path and the * cd-on-quit functions. Current workspace/path will be marked with an * asterisk. It will be read at startup by get_last_path() and at exit by * cd_on_quit.sh, if enabled. */ static void handle_last_path(void) { if (!config_dir_gral) /* NULL if running with --open or --preview */ return; /* The cd_on_quit.sh function changes the shell current directory to the * directory specifcied in ~/.config/clifm/.last if this file is found (it * is actually a symlink to ~/.config/clifm/profiles/PROFILE/.last). * Remove the file to prevent the function from changing the directory * if cd-on-quit is disabled. If necessary, it will be recreated by} * save_last_path() below. */ const size_t len = strlen(config_dir_gral) + 7; char *last_path_tmp = xnmalloc(len, sizeof(char)); snprintf(last_path_tmp, len, "%s/.last", config_dir_gral); struct stat a; if (lstat(last_path_tmp, &a) != -1 && unlinkat(XAT_FDCWD, last_path_tmp, 0) == -1) xerror("unlink: '%s': %s\n", last_path_tmp, strerror(errno)); if (conf.restore_last_path == 1 || conf.cd_on_quit == 1) save_last_path(last_path_tmp); free(last_path_tmp); } static void free_file_templates(void) { if (!file_templates) return; filesn_t i; for (i = 0; file_templates[i]; i++) free(file_templates[i]); free(file_templates); file_templates = (char **)NULL; } /* This function is called by atexit() to clear whatever is there at exit * time and avoid thus memory leaks */ void free_stuff(void) { int i = 0; free(alt_config_dir); free(alt_trash_dir); free(alt_config_file); free(alt_bm_file); free(alt_kbinds_file); free(alt_mimelist_file); free(alt_preview_file); free(alt_profile); if (user_mimetypes) { for (i = 0; user_mimetypes[i].mimetype; i++) { free(user_mimetypes[i].ext); free(user_mimetypes[i].mimetype); } free(user_mimetypes); } if (sys_users) { for (i = 0; sys_users[i].name; i++) free(sys_users[i].name); free(sys_users); } if (sys_groups) { for (i = 0; sys_groups[i].name; i++) free(sys_groups[i].name); free(sys_groups); } #ifdef LINUX_FSINFO if (ext_mnt) { for (i = 0; ext_mnt[i].mnt_point; i++) free(ext_mnt[i].mnt_point); free(ext_mnt); } #endif /* LINUX_FSINFO */ #ifdef RUN_CMD free(cmd_line_cmd); #endif /* RUN_CMD */ #if !defined(_NO_ICONS) free(name_icons_hashes); free(dir_icons_hashes); free(ext_icons_hashes); #endif /* !_NO_ICONS */ free(conf.time_str); free(conf.ptime_str); free(conf.priority_sort_char); #ifdef LINUX_INOTIFY /* Shutdown inotify */ if (inotify_wd >= 0) inotify_rm_watch(inotify_fd, inotify_wd); if (inotify_fd != UNSET) close(inotify_fd); #elif defined(BSD_KQUEUE) if (event_fd >= 0) close(event_fd); if (kq != UNSET) close(kq); #endif /* LINUX_INOTIFY */ free_prompts(); free(prompts_file); free_autocmds(0); free_tags(); free_remotes(1); free_file_templates(); if (xargs.stealth_mode != 1) save_jumpdb(); handle_last_path(); free_bookmarks(); free(conf.encoded_prompt); free_dirlist(); free(conf.opener); free(conf.rprompt_str); free(conf.wprompt_str); free(conf.fzftab_options); free(conf.welcome_message_str); remove_virtual_dir(); i = (int)cschemes_n; while (i-- > 0) free(color_schemes[i]); free(color_schemes); free(conf.usr_cscheme); if (jump_db) { i = (int)jump_n; while (--i >= 0) free(jump_db[i].path); free(jump_db); } free(pinned_dir); // ADD FILTER TYPE CHECK! if (filter.str) { regfree(®ex_exp); free(filter.str); } if (conf.histignore_regex) { regfree(®ex_hist); free(conf.histignore_regex); } if (conf.dirhistignore_regex) { regfree(®ex_dirhist); free(conf.dirhistignore_regex); } free_workspaces_filters(); if (profile_names) { for (i = 0; profile_names[i]; i++) free(profile_names[i]); free(profile_names); } if (sel_n > 0) { i = (int)sel_n; while (--i >= 0) free(sel_elements[i].name); free(sel_elements); } free(sel_devino); if (bin_commands) { i = (int)path_progsn; while (--i >= 0) free(bin_commands[i]); free(bin_commands); } if (paths) { i = (int)path_n; while (--i >= 0) free(paths[i].path); free(paths); } if (cdpaths) { i = (int)cdpath_n; while (--i >= 0) free(cdpaths[i]); free(cdpaths); } if (history) { i = (int)current_hist_n; while (--i >= 0) free(history[i].cmd); free(history); } if (dirhist_total_index) { i = dirhist_total_index; while (--i >= 0) free(old_pwd[i]); free(old_pwd); } i = (int)aliases_n; while (--i >= 0) { free(aliases[i].name); free(aliases[i].cmd); } free(aliases); i = (int)kbinds_n; while (--i >= 0) { free(kbinds[i].function); free(kbinds[i].key); } free(kbinds); i = (int)usrvar_n; while (--i >= 0) { free(usr_var[i].name); free(usr_var[i].value); } free(usr_var); i = (int)actions_n; while (--i >= 0) { free(usr_actions[i].name); free(usr_actions[i].value); } free(usr_actions); i = (int)prompt_cmds_n; while (--i >= 0) free(prompt_cmds[i]); free(prompt_cmds); if (msgs_n > 0) { i = (int)msgs_n; while (--i >= 0) free(messages[i].text); free(messages); } if (ext_colors_n) { i = (int)ext_colors_n; while (--i >= 0) { free(ext_colors[i].name); free(ext_colors[i].value); } free(ext_colors); } if (workspaces && workspaces[0].path) { i = MAX_WS; while (--i >= 0) { free(workspaces[i].path); free(workspaces[i].name); } free(workspaces); } free(actions_file); free(bm_file); free(data_dir); free(colors_dir); free(config_dir_gral); free(config_dir); free(config_file); free(dirhist_file); free(hist_file); free(kbinds_file); free(msgs_log_file); free(cmds_log_file); free(mime_file); free(plugins_dir); free(plugins_helper_file); free(profile_file); free(remotes_file); #ifndef _NO_SUGGESTIONS free(suggestion_buf); free(conf.suggestion_strategy); #endif /* !_NO_SUGGESTIONS */ free(sel_file); free(templates_dir); free(thumbnails_dir); free(tmp_rootdir); free(tmp_dir); free(user.name); free(user.home); free(user.shell); free(user.shell_basename); free(user.groups); #ifndef _NO_TRASH free(trash_dir); free(trash_files_dir); free(trash_info_dir); #endif /* !_NO_TRASH */ free(tags_dir); free(conf.term); free(quote_chars); rl_clear_history(); rl_free_undo_list(); rl_clear_pending_input(); /* #if defined(__clang__) Keymap km = rl_get_keymap(); xrl_discard_keymap(km); #endif // __clang__ */ #ifdef CLIFM_TEST_INPUT if (rl_instream) fclose(rl_instream); #endif /* CLIFM_TEST_INPUT */ /* Restore the color of the running terminal */ if (conf.colorize == 1 && xargs.list_and_quit != 1) RESTORE_COLOR; if (xargs.kitty_keys == 1) UNSET_KITTY_KEYS; } /* Get current terminal dimensions and store them in TERM_COLS and * TERM_LINES (globals). These values will be updated upon SIGWINCH. * In case of error, we fallback to 80x24. */ void get_term_size(void) { struct winsize w; if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &w) == -1) { term_cols = 80; term_lines = 24; } else { term_cols = w.ws_col > 0 ? w.ws_col : 80; term_lines = w.ws_row > 0 ? w.ws_row : 24; } if (xargs.secure_env == 1 || xargs.secure_env_full == 1) return; char *env = getenv("CLIFM_COLUMNS"); int value = env ? atoi(env) : -1; if (value > 0 && value <= USHRT_MAX) term_cols = (unsigned short)value; env = getenv("CLIFM_LINES"); value = env ? atoi(env) : -1; if (value > 0 && value <= USHRT_MAX) term_lines = (unsigned short)value; } static int create_virtual_dir(const int user_provided) { if (!stdin_tmp_dir || !*stdin_tmp_dir) { if (user_provided == 1) { err('e', PRINT_PROMPT, _("%s: Empty buffer for virtual " "directory name. Trying with default value\n"), PROGRAM_NAME); } else { err('e', PRINT_PROMPT, _("%s: Empty buffer for virtual " "directory name\n"), PROGRAM_NAME); } return FUNC_FAILURE; } char *cmd[] = {"mkdir", "-p", "--", stdin_tmp_dir, NULL}; int ret = 0; if ((ret = launch_execv(cmd, FOREGROUND, E_MUTE)) != FUNC_SUCCESS) { char *errmsg = (ret == E_NOTFOUND ? NOTFOUND_MSG : (ret == E_NOEXEC ? NOEXEC_MSG : (char *)NULL)); if (user_provided == 1) { err('e', PRINT_PROMPT, _("%s: mkdir: '%s': %s. Trying with " "default value\n"), PROGRAM_NAME, stdin_tmp_dir, errmsg ? errmsg : strerror(ret)); } else { err('e', PRINT_PROMPT, "%s: mkdir: '%s': %s\n", PROGRAM_NAME, stdin_tmp_dir, errmsg ? errmsg : strerror(ret)); } return ret; } return FUNC_SUCCESS; } static char * construct_name(char *file, const size_t flen) { char *name = (char *)NULL; /* Should we construct destiny file as full path or using only the * last path component (the file's basename)? */ if (xargs.virtual_dir_full_paths != 1) { const char *p = strrchr(file, '/'); if (!p || !*(++p)) name = savestring(file, flen); else name = savestring(p, strlen(p)); } else { name = replace_slashes(file, ':'); } if (!name || !*name) { free(name); err('w', PRINT_PROMPT, _("%s: '%s': Error constructing " "filename\n"), PROGRAM_NAME, file); return (char *)NULL; } /* Prohibited names */ if (*name == '/' && !name[1]) { name = xnrealloc(name, 5, sizeof(char)); xstrsncpy(name, "root", 5); } else if (*name == '.' && !name[1]) { name = xnrealloc(name, 5, sizeof(char)); xstrsncpy(name, "self", 5); } else { if (*name == '.' && name[1] == '.' && !name[2]) { name = xnrealloc(name, 7, sizeof(char)); xstrsncpy(name, "parent", 7); } } return name; } static size_t gen_symlink(char *file, const char *cwd) { if (SELFORPARENT(file)) return 0; struct stat attr; if (lstat(file, &attr) == -1) { /* "~" fails here. No need to check in construct_name(). */ err('w', PRINT_PROMPT, "%s: '%s': %s\n", PROGRAM_NAME, file, strerror(errno)); return 0; } /* Construct source and destiny files. */ /* symlink(3) doesn't like filenames ending with slash. */ size_t file_len = strlen(file); if (file_len > 1 && file[file_len - 1] == '/') { file[file_len - 1] = '\0'; file_len--; } char source[PATH_MAX + 1]; if (*file != '/') snprintf(source, sizeof(source), "%s/%s", cwd, file); else xstrsncpy(source, file, sizeof(source)); char *name = construct_name(file, file_len); if (!name) return 0; char dest[PATH_MAX + 32]; snprintf(dest, sizeof(dest), "%s/%s", stdin_tmp_dir, name); int suffix = 0; while (1) { errno = 0; if (symlink(source, dest) == 0) break; if (errno != EEXIST) { err('w', PRINT_PROMPT, _("%s: Cannot create symbolic " "link '%s': %s\n"), PROGRAM_NAME, dest, strerror(errno)); free(name); return 0; } suffix++; if (suffix == INT_MAX) { free(name); return 0; } snprintf(dest, sizeof(dest), "%s/%s-%d", stdin_tmp_dir, name, suffix); } free(name); return 1; } int handle_stdin(void) { /* If files are passed via stdin, we need to disable restore- * last-path in order to correctly understand relative paths. */ conf.restore_last_path = 0; /* In light mode, stat(2) is not executed, so that we cannot dereference * symlinks created in virtual directories. */ if (conf.light_mode == 1) err('n', PRINT_PROMPT, _("%s: Light mode is not supported " "in virtual directories\n"), PROGRAM_NAME); conf.light_mode = 0; int exit_status = FUNC_SUCCESS; /* Max input size: 512 * (512 * 1024) * 512 chunks of 524288 bytes (512KiB) each * == (65535 * PATH_MAX) * == 262MiB of data ((65535 * PATH_MAX) / 1024). */ const size_t chunk = (size_t)512 * 1024; const size_t max_chunks = 512; size_t chunks_n = 1; size_t total_len = 0; ssize_t input_len = 0; /* Initial buffer allocation == 1 chunk */ char *buf = xnmalloc(chunk, sizeof(char)); while (chunks_n < max_chunks) { input_len = read(STDIN_FILENO, buf + total_len, chunk); /* flawfinder: ignore */ /* Error */ if (input_len < 0) { free(buf); return FUNC_FAILURE; } /* Nothing else to be read */ if (input_len == 0) break; total_len += (size_t)input_len; chunks_n++; /* Append a new chunk of memory to the buffer */ buf = xnrealloc(buf, chunks_n + 1, chunk); } if (total_len == 0) { free(buf); fprintf(stderr, _("%s: No entries\n"), PROGRAM_NAME); exit(EXIT_FAILURE); } /* Null terminate the input buffer */ buf[total_len] = '\0'; /* Create tmp dir to store links to files */ char *suffix = (char *)NULL; if (!stdin_tmp_dir || (exit_status = create_virtual_dir(1)) != FUNC_SUCCESS) { free(stdin_tmp_dir); suffix = gen_rand_str(RAND_SUFFIX_LEN); char *temp = tmp_dir ? tmp_dir : P_tmpdir; const size_t tmp_len = strlen(temp) + 13; stdin_tmp_dir = xnmalloc(tmp_len, sizeof(char)); snprintf(stdin_tmp_dir, tmp_len, "%s/vdir.%s", temp, suffix ? suffix : "nTmp0B9&54"); free(suffix); if ((exit_status = create_virtual_dir(0)) != FUNC_SUCCESS) goto FREE_N_EXIT; } if (xargs.stealth_mode != 1) setenv("CLIFM_VIRTUAL_DIR", stdin_tmp_dir, 1); /* Get CWD: we need it to prepend it to relative paths. */ char t[PATH_MAX + 1] = ""; char *cwd = get_cwd(t, sizeof(t), 0); if (!cwd || !*cwd) { exit_status = errno; goto FREE_N_EXIT; } /* Get substrings from buf */ char *p = buf, *q = buf; size_t links_counter = 0; while (*p) { if (!*p || *p == '\n') { *p = '\0'; /* Create symlinks (in tmp dir) to each valid file in the buffer */ links_counter += gen_symlink(q, cwd); q = p + 1; } p++; } if (links_counter == 0) { /* No symlink was created. Exit */ dup2(STDOUT_FILENO, STDIN_FILENO); xerror(_("%s: Empty filenames buffer. Nothing to do\n"), PROGRAM_NAME); if (getenv("CLIFM_VT_RUNNING")) press_any_key_to_continue(0); free(buf); exit(FUNC_FAILURE); } /* Make the virtual dir read only */ xchmod(stdin_tmp_dir, "0500", 1); /* chdir to tmp dir and update path var */ if (xchdir(stdin_tmp_dir, SET_TITLE) == -1) { exit_status = errno; xerror("cd: '%s': %s\n", stdin_tmp_dir, strerror(errno)); xchmod(stdin_tmp_dir, "0700", 1); char *rm_cmd[] = {"rm", "-r", "--", stdin_tmp_dir, NULL}; const int ret = launch_execv(rm_cmd, FOREGROUND, E_NOFLAG); if (ret != FUNC_SUCCESS) exit_status = ret; free(cwd); goto FREE_N_EXIT; } free(workspaces[cur_ws].path); workspaces[cur_ws].path = savestring(stdin_tmp_dir, strlen(stdin_tmp_dir)); FREE_N_EXIT: free(buf); /* Go back to tty */ dup2(STDOUT_FILENO, STDIN_FILENO); if (conf.autols == 1) { reload_dirlist(); add_to_dirhist(workspaces[cur_ws].path); } return exit_status; } /* Save pinned directory into a file. */ static int save_pinned_dir(void) { if (!pinned_dir || config_ok == 0) return FUNC_FAILURE; char *pin_file = xnmalloc(config_dir_len + 7, sizeof(char)); snprintf(pin_file, config_dir_len + 7, "%s/.pin", config_dir); int fd = 0; FILE *fp = open_fwrite(pin_file, &fd); if (!fp) { xerror(_("pin: Error saving pinned directory: %s\n"), strerror(errno)); } else { fprintf(fp, "%s", pinned_dir); fclose(fp); } free(pin_file); return FUNC_SUCCESS; } int pin_directory(char *dir) { if (!dir || !*dir) return FUNC_FAILURE; char *d = unescape_str(dir, 0); if (!d) return FUNC_FAILURE; struct stat a; if (lstat(d, &a) == -1) { xerror("pin: '%s': %s\n", d, strerror(errno)); free(d); return FUNC_FAILURE; } if (pinned_dir) { free(pinned_dir); pinned_dir = (char *)NULL; } const size_t dir_len = strlen(d); /* If absolute path */ if (*dir == '/') { pinned_dir = savestring(d, dir_len); } else { /* If relative path */ if (strcmp(workspaces[cur_ws].path, "/") == 0) { pinned_dir = xnmalloc(dir_len + 2, sizeof(char)); snprintf(pinned_dir, dir_len + 2, "/%s", d); } else { const size_t plen = dir_len + strlen(workspaces[cur_ws].path) + 2; pinned_dir = xnmalloc(plen, sizeof(char)); snprintf(pinned_dir, plen, "%s/%s", workspaces[cur_ws].path, d); } } if (xargs.stealth_mode == 1 || save_pinned_dir() == FUNC_SUCCESS) { printf(_("pin: Succesfully pinned '%s'\n"), d); free(d); return FUNC_SUCCESS; } else { free(d); free(pinned_dir); pinned_dir = (char *)NULL; return FUNC_FAILURE; } } int unpin_dir(void) { if (!pinned_dir) { puts(_("unpin: No pinned file")); return FUNC_SUCCESS; } if (config_dir && xargs.stealth_mode != 1) { int cmd_error = 0; char *pin_file = xnmalloc(config_dir_len + 7, sizeof(char)); snprintf(pin_file, config_dir_len + 7, "%s/.pin", config_dir); if (unlink(pin_file) == -1) { xerror("pin: '%s': %s\n", pin_file, strerror(errno)); cmd_error = 1; } free(pin_file); if (cmd_error == 1) return FUNC_FAILURE; } printf(_("unpin: Succesfully unpinned '%s'\n"), pinned_dir); free(pinned_dir); pinned_dir = (char *)NULL; return FUNC_SUCCESS; } void version_function(const int full) { char *posix = ""; char *legacy = ""; char *suckless = ""; char *paranoid = ""; #ifdef _BE_POSIX posix = "-POSIX"; #endif /* _BE_POSIX */ #ifdef CLIFM_LEGACY legacy = "-LEGACY"; #endif /* CLIFM_LEGACY */ #ifdef CLIFM_SUCKLESS suckless = "-SUCKLESS"; #endif /* CLIFM_SUCKLESS */ #ifdef SECURITY_PARANOID # if SECURITY_PARANOID > 0 paranoid = "-PARANOID"; # endif #endif /* SECURITY_PARANOID */ if (full == 1) { /* Running from within clifm (as 'ver')*/ printf(_("%s %s%s%s%s%s (%s)\n%s\nLicense %s\nWritten by %s\n"), PROGRAM_NAME, VERSION, posix, legacy, suckless, paranoid, DATE, CONTACT, LICENSE, AUTHOR); } else { /* Running as --version (or -v) */ printf("%s%s%s%s%s\n", VERSION, posix, legacy, suckless, paranoid); exit(EXIT_SUCCESS); } } void splash(void) { const char *reg_cyan = conf.colorize == 1 ? "\x1b[0;36m" : ""; printf("\n%s%s\n\n%s%s\t\t %s%s\n %s\n", reg_cyan, ASCII_LOGO_BIG, df_c, BOLD, df_c, PROGRAM_NAME_UPPERCASE, PROGRAM_DESC); HIDE_CURSOR; if (conf.splash_screen) { printf("\n "); fflush(stdout); press_any_key_to_continue(0); } else { putchar('\n'); } UNHIDE_CURSOR; } void bonus_function(void) { char *phrases[] = { "\"Vamos Boca Juniors Carajo!\" (La mitad + 1)", "\"Hey! Look behind you! A three-headed monkey! (G. Threepweed)", "\"Free as in free speech, not as in free beer\" (R. M. S)", "\"Nothing great has been made in the world without passion\" (G. W. F. Hegel)", "\"Simplicity is the ultimate sophistication\" (Leo Da Vinci)", "\"Yo vendí semillas de alambre de púa, al contado, y me lo agradecieron\" (Marquitos, 9 Reinas)", "\"I'm so happy, because today I've found my friends, they're in my head\" (K. D. Cobain)", "\"The best code is written with the delete key\" (Someone, somewhere, sometime)", "\"I'm selling these fine leather jackets\" (Indy)", "\"If you've been feeling increasingly stupid lately, you're not alone\" (Zak McKracken)", "\"I pray to God to make me free of God\" (Meister Eckhart)", "¡Truco y quiero retruco mierda!", "\"The are no facts, only interpretations\" (F. Nietzsche)", "\"This is a lie\" (The liar paradox)", "\"There are two ways to write error-free programs; only the third one works\" (Alan J. Perlis)", "The man who sold the world was later sold by the big G", "A programmer is always one year older than themself", "A smartphone is anything but smart", "And he did it: he killed the man who killed him", ">++('>", ":(){:|:&};:", "Keep it simple, stupid", "If ain't broken, brake it", "\"I only know that I know nothing\" (Socrates)", "(Learned) Ignorance is the true outcome of wisdom (Nicholas " /* NOLINT */ "of Cusa)", "True intelligence is about questions, not answers", "Humanity is just an arrow released towards God", "Buzz is right: infinity is our only and ultimate aim", "That stain will never ever be erased (La 12)", "\"Una obra de arte no se termina, se abandona\" (L. J. Guerrero)", "At the beginning, software was hardware; but today hardware is " "being absorbed by software", "\"Juremos con gloria morir\"", "\"Given enough eyeballs, all bugs are shallow.\" (E. Raymond)", "\"We're gonna need a bigger boat.\" (Caleb)", "\"Ein Verletzter, Alarm, Alarm!\"", "\"There is not knowledge that is not power\"", "idkfa", "This is the second best file manager I've ever seen!", "Winners don't use TUIs", "\"La inmortalidad es baladí\" (J. L. Borges)", "\"Computer updated [...] Establish communications, priority alpha\"", "\"Step one: find plans, step two: save world, step three: get out of my house!\" (Dr. Fred)", "\"Leave my loneliness unbroken!, quit the bust above my door! Quoth the raven: Nevermore.\" (E. A. Poe)", NULL}; const size_t num = (sizeof(phrases) / sizeof(phrases[0])) - 1; #ifndef HAVE_ARC4RANDOM srandom((unsigned int)time(NULL)); puts(phrases[random() % (int)num]); #else puts(phrases[arc4random_uniform((uint32_t)num)]); #endif /* !HAVE_ARC4RANDOM */ } clifm-1.26.3/src/misc.h000066400000000000000000000041431506632037700146030ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* misc.h */ #ifndef MISC_H #define MISC_H #include "help.h" __BEGIN_DECLS int err(const int msg_type, const int prompt_flag, const char *format, ...); int alias_import(char *file); void bonus_function(void); int confirm_sudo_cmd(char **cmd); int create_usr_var(const char *str); int expand_prompt_name(char *name); int filter_function(char *arg); void free_autocmds(const int keep_temp); void free_prompts(void); void free_stuff(void); int free_remotes(const int exit); void free_tags(void); void free_workspaces_filters(void); char *gen_diff_str(const int diff); char *get_newname(const char *_prompt, char *old_name, int *quoted); void get_term_size(void); int handle_stdin(void); int is_blank_name(const char *s); int list_mountpoints(void); int new_instance(char *, int); int print_reload_msg(const char *ptr, const char *color, const char *msg, ...); int pin_directory(char *dir); void save_last_path(char *last_path_tmp); void set_eln_color(void); void set_filter_type(const char c); void splash(void); int unpin_dir(void); void version_function(const int full); #ifdef LINUX_INOTIFY void read_inotify(void); void reset_inotify(void); #elif defined(BSD_KQUEUE) void read_kqueue(void); #endif /* LINUX_INOTIFY */ __END_DECLS #endif /* MISC_H */ clifm-1.26.3/src/name_cleaner.c000066400000000000000000000421541506632037700162600ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* name_cleaner.c -- functions to sanitize filenames */ /* check_width, unpack_start, and unpack_cont macros, just * as get_utf_8_width and get_uft8_dec_value functions are taken from * https://github.com/dharple/detox/blob/main/src/clean_utf_8.c, licensed * under BSD-3-Clause. * All changes are licensed under GPL-2.0-or-later. */ #ifndef _NO_BLEACH #include "helpers.h" #include #include #include #include #if defined(MAC_OS_X_RENAMEAT_SYS_STDIO_H) # include /* renameat(2) */ #endif /* MAC_OS_X_RENAMEAT_SYS_STDIO_H */ #include "aux.h" #include "cleaner_table.h" #include "file_operations.h" #include "history.h" #include "listing.h" /* reload_dirlist() */ #include "messages.h" #include "misc.h" #include "readline.h" #include "selection.h" #define FUNC_NAME "bleach" #define DEFAULT_TRANSLATION '_' #define BRACKETS_TRANSLATION '-' #define UTF_8_ENCODED_MASK 0xC0 #define UTF_8_ENCODED_START 0xC0 #define UTF_8_ENCODED_CONT 0x80 #define UTF_8_ENCODED_6_BYTES_MASK 0xFE #define UTF_8_ENCODED_6_BYTES 0xFC #define UTF_8_ENCODED_5_BYTES_MASK 0xFC #define UTF_8_ENCODED_5_BYTES 0xF8 #define UTF_8_ENCODED_4_BYTES_MASK 0xF8 #define UTF_8_ENCODED_4_BYTES 0xF0 #define UTF_8_ENCODED_3_BYTES_MASK 0xF0 #define UTF_8_ENCODED_3_BYTES 0xE0 #define UTF_8_ENCODED_2_BYTES_MASK 0xE0 #define UTF_8_ENCODED_2_BYTES 0xC0 #define BLEACH_TMP_HEADER "# Clifm - Bleach\n\ # Edit replacement filenames as you wish, save, and close the editor.\n\ # You will be asked for confirmation at exit.\n\n" #define check_width(chr, size) if (((chr) & UTF_8_ENCODED_ ## size ## _BYTES_MASK) == UTF_8_ENCODED_ ## size ## _BYTES) { return size; } #define unpack_start(chr, size) ((unsigned char)(chr) & ~UTF_8_ENCODED_ ## size ## _BYTES_MASK) #define unpack_cont(chr) ((unsigned char)(chr) & ~UTF_8_ENCODED_MASK) struct bleach_t { char *original; char *replacement; }; static int get_utf_8_width(const char c) { if ((c & UTF_8_ENCODED_MASK) == UTF_8_ENCODED_START) { /* UTF-8 leading byte */ check_width(c, 2); check_width(c, 3); check_width(c, 4); check_width(c, 5); check_width(c, 6); } if ((c & UTF_8_ENCODED_MASK) == UTF_8_ENCODED_CONT) /* UTF-8 continuation byte */ return -1; return 1; } /* Replace unsafe characters by safe, portable ones. * a-zA-Z0-9._- (Portable Filename Character Set) are kept. * {[()]} are replaced by a dash (-). * Everything else is replaced by an underscore (_). */ static int translate_unsafe_char(const unsigned char c) { unsigned char t = 0; if (IS_ALNUM(c) || c == '.' || c == '_' || c == '-') t = c; else if (c == '(' || c == ')' || c == '[' || c == ']' || c == '{' || c == '}') t = BRACKETS_TRANSLATION; else t = DEFAULT_TRANSLATION; return t; } static int get_uft8_dec_value(size_t *i, const char *str) { unsigned char c = (unsigned char)str[*i]; int new_value = 0; const int utf8_width = get_utf_8_width((char)c); switch (utf8_width) { case 1: new_value = (unsigned char)str[0]; break; case 2: new_value = unpack_start(c, 2); break; case 3: new_value = unpack_start(c, 3); break; case 4: new_value = unpack_start(c, 4); break; case 5: new_value = unpack_start(c, 5); break; case 6: new_value = unpack_start(c, 6); break; default: return (-1); } int expected_chars = utf8_width - 1; int failed = 0; while (expected_chars > 0) { (*i)++; if (str[*i] == '\0') { failed = 1; break; } if ((str[*i] & UTF_8_ENCODED_MASK) != UTF_8_ENCODED_CONT) { /* Not a UTF-8 continuation byte */ failed = 1; break; } new_value <<= 6; new_value += unpack_cont(str[*i]); expected_chars--; } return failed == 1 ? (-2) : new_value; } /* Clean up NAME either by removing those (extended-ASCII/Unicode) characters * without an ASCII alternative/similar character, or by translating (based * on the unitable table (in cleaner_table.h)) extended-ASCII/Unicode characters * into an alternative ASCII character based on familiarity/similarity. Disallowed * characters (NUL and slash) will be simply removed. The filename length will * be trimmed to NAME_MAX (usually 255). If the replacement filename is * only one character long, "bleach" will be appended to avoid too short * filenames. * * @parameter: the filename to be sanitized. If it contains a slash, only * the string after the slash will be taken a the actual filename * * @return: the sanitized filename or NULL in case of error. If the translated * filename is empty, it will be replaced by "bleach.YYYYMMDDHHMMS" * */ static char * clean_file_name(char *restrict name) { if (!name || !*name) return (char *)NULL; char *p = xcalloc(NAME_MAX + 1, sizeof(char)); char *q = p; size_t i = 0, cur_len = 0, too_long = 0; char *s = strrchr(name, '/'); i = s ? (size_t)(s - name) + 1 : 0; unsigned char n = 0; for (; (n = (unsigned char)name[i]); i++) { if (cur_len > NAME_MAX) { too_long = 1; break; } /* ASCII chars */ if (n == 38) { /* & */ if (q == p || *(q - 1) != DEFAULT_TRANSLATION) { xstrncat(q, strlen(q), "_and_", NAME_MAX + 1); q += 5; cur_len += 5; } else { snprintf(q - 1, NAME_MAX, "_and_"); q += 4; cur_len += 4; } continue; } if (n <= 127) { const int ret = translate_unsafe_char(n); if (ret == -1) continue; if (ret == BRACKETS_TRANSLATION) { if (q == p || (*(q - 1) != BRACKETS_TRANSLATION && *(q - 1) != DEFAULT_TRANSLATION)) { *q = (char)ret; q++; cur_len++; } else { if (*(q - 1) == DEFAULT_TRANSLATION) { q--; *q = (char)ret; } } } else if (ret == DEFAULT_TRANSLATION && (q == p || (*(q - 1) != DEFAULT_TRANSLATION && *(q - 1) != BRACKETS_TRANSLATION))) { *q = (char)ret; q++; cur_len++; } else { if (ret != BRACKETS_TRANSLATION && ret != DEFAULT_TRANSLATION) { *q = (char)ret; q++; cur_len++; } } continue; } /* Extended ASCII and Unicode chars */ const int dec_value = get_uft8_dec_value(&i, name); if (!name[i]) break; if (dec_value == -1) continue; if (dec_value == -2) { if (q != p && *(q - 1) != DEFAULT_TRANSLATION) { *q = DEFAULT_TRANSLATION; q++; cur_len++; } continue; } int j = (int)(sizeof(unitable) / sizeof(struct utable_t)); char *t = (char *)NULL; while (--j >= 0) { if (dec_value == unitable[j].key && unitable[j].data) t = unitable[j].data; } if (!t) continue; size_t tlen = strlen(t); if (q == p || *(q - 1) != DEFAULT_TRANSLATION) { xstrncat(q, strlen(q), t, NAME_MAX + 1); q += tlen; cur_len += tlen; } else { snprintf(q - 1, NAME_MAX, "%s", t); q += (tlen > 0 ? tlen - 1 : 0); cur_len += (tlen > 0 ? tlen - 1 : 0); } } *q = '\0'; if (too_long) p[NAME_MAX] = '\0'; /* Handle some filenames that should be avoided */ if (!*p) { /* Empty filename */ time_t rawtime = time(NULL); struct tm t; char *suffix = localtime_r(&rawtime, &t) ? gen_date_suffix(t, 0) : (char *)NULL; if (!suffix) { free(p); return (char *)NULL; } snprintf(p, NAME_MAX, "%s.%s", FUNC_NAME, suffix); free(suffix); } else { if (!p[1]) { /* Avoid one character long filenames. Specially because files * named with a single dot should be avoided */ char c = *p; snprintf(p, NAME_MAX, "%c.%s", c, FUNC_NAME); } } /* Do not make hidden a file that wasn't */ if (*name != '.' && *p == '.') *p = DEFAULT_TRANSLATION; /* Filenames shouldn't start with a dash/hyphen (reserved for command options)*/ if (*p == '-') *p = DEFAULT_TRANSLATION; /* No filename should be named dot-dot (..) */ if (cur_len == 3 && *p == '.' && *(p + 1) == '.' && !*(p + 2)) *(p + 1) = DEFAULT_TRANSLATION; return p; } /* Let the user edit replacement filenames via a text editor and return * a new array with the updated filenames. If the temp file is not modified * the original list of files is returned instead. In case of error * returns NULL */ static struct bleach_t * edit_replacements(struct bleach_t *bfiles, size_t *n, int *edited_names) { if (!bfiles || !bfiles[0].original) return (struct bleach_t *)NULL; *edited_names = 1; char f[PATH_MAX + 1]; snprintf(f, sizeof(f), "%s/%s", (xargs.stealth_mode == 1) ? P_tmpdir : tmp_dir, TMP_FILENAME); int fd = mkstemp(f); if (fd == -1) goto ERROR; FILE *fp = fdopen(fd, "w"); if (!fp) goto ERROR; fprintf(fp, BLEACH_TMP_HEADER); size_t i; /* Copy all files to be renamed to the temp file */ for (i = 0; i < *n; i++) { fprintf(fp, "original: %s\nreplacement: %s\n\n", bfiles[i].original, bfiles[i].replacement); } size_t total_files = i; struct stat attr; if (fstat(fd, &attr) == -1) goto ERROR_CLOSE; const time_t mtime_bfr = attr.st_mtime; fclose(fp); /* Open the temp file */ open_in_foreground = 1; const int exit_status = open_file(f); open_in_foreground = 0; if (exit_status != FUNC_SUCCESS) goto ERROR; fp = open_fread(f, &fd); if (!fp) goto ERROR; /* Compare the new modification time to the stored one: if they * match, nothing has been modified. */ if (fstat(fd, &attr) == -1) goto ERROR_CLOSE; if (mtime_bfr == attr.st_mtime) { fclose(fp); if (unlinkat(fd, f, 0) == -1) err('w', PRINT_PROMPT, "bleach: Cannot remove '%s': %s\n", f, strerror(errno)); *edited_names = 0; return bfiles; /* Return the original list of files */ } /* Free the original list of files */ for (i = 0; i < *n; i++) { free(bfiles[i].original); free(bfiles[i].replacement); } /* Allocate memory for the new list */ free(bfiles); bfiles = (struct bleach_t *)xnmalloc(total_files + 1, sizeof(struct bleach_t)); /* Initialize all values */ for (i = 0; i < total_files; i++) { bfiles[i].original = (char *)NULL; bfiles[i].replacement = (char *)NULL; } size_t line_size = 0; char *line = (char *)NULL; ssize_t line_len = 0; i = 0; /* Read the temp file and store the new values */ while ((line_len = getline(&line, &line_size, fp)) > 0) { if (i >= total_files) break; if (line[line_len - 1] == '\n') line[line_len - 1] = '\0'; if (*line != 'o' && *line != 'r') continue; char *p = strchr(line, ' '); if (!p || !*(++p)) continue; if (strncmp(line, "original: ", 10) == 0) { if (bfiles[i].original) { free(bfiles[i].original); bfiles[i].original = (char *)NULL; } bfiles[i].original = savestring(p, strlen(p)); /* Do not store the replacement filename is there is no original */ } else if (strncmp(line, "replacement: ", 13) == 0 && bfiles[i].original) { bfiles[i].replacement = savestring(p, strlen(p)); printf("%s %s%s%s %s\n", bfiles[i].original, mi_c, SET_MSG_PTR, df_c, bfiles[i].replacement); i++; } else { continue; } } /* Make sure no field of the struct is empty/NULL*/ size_t j = 0; for (i = 0; i < total_files; i++) { if (!bfiles[i].original || !*bfiles[i].original || !bfiles[i].replacement || !*bfiles[i].replacement) { free(bfiles[i].original); free(bfiles[i].replacement); bfiles[i].original = (char *)NULL; bfiles[i].replacement = (char *)NULL; } else { j++; } } *n = j; free(line); if (unlinkat(fd, f, 0) == -1) err('w', PRINT_PROMPT, "bleach: Cannot remove '%s': %s\n", f, strerror(errno)); fclose(fp); return bfiles; ERROR_CLOSE: fclose(fp); ERROR: *edited_names = -1; xerror("bleach: '%s': %s\n", f, strerror(errno)); if (unlink(f) == -1) xerror("bleach: Cannot remove '%s': %s\n", f, strerror(errno)); return bfiles; } /* Clean up the list of filenames (NAMES), print the list of the sanitized * filenames (allowing the user to edit this list), and finally * rename the original filenames into the clean ones */ int bleach_files(char **names) { if (!names || !names[1] || IS_HELP(names[1])) { puts(_(BLEACH_USAGE)); return FUNC_SUCCESS; } int do_edit = 0, edited_names = 0; struct bleach_t *bfiles = (struct bleach_t *)NULL; size_t f = 0, i = 1; for (; names[i]; i++) { char *dstr = unescape_str(names[i], 0); if (!dstr) { xerror(_("bleach: '%s': Error unescaping filename\n"), names[i]); continue; } xstrsncpy(names[i], dstr, strlen(dstr) + 1); free(dstr); size_t nlen = strlen(names[i]); if (names[i][nlen - 1] == '/') { names[i][nlen - 1] = '\0'; nlen--; } char *sl = strrchr(names[i], '/'); char *p = clean_file_name((sl && *(sl + 1)) ? sl + 1 : names[i]); if (!p) continue; /* Nothing to clean. Skip this one */ char *n = (sl && *(sl + 1)) ? sl + 1 : names[i]; if (*n == *p && strcmp(n, p) == 0) { free(p); continue; } bfiles = xnrealloc(bfiles, f + 1, sizeof(struct bleach_t)); bfiles[f].original = savestring(names[i], nlen); if (sl) { *sl = '\0'; const size_t len = nlen + strlen(p) + 2; bfiles[f].replacement = xnmalloc(len, sizeof(char)); snprintf(bfiles[f].replacement, len, "%s/%s", names[i], p); *sl = '/'; } else { bfiles[f].replacement = savestring(p, strlen(p)); } printf("%s %s%s%s %s\n", bfiles[f].original, mi_c, SET_MSG_PTR, df_c, bfiles[f].replacement); f++; free(p); } if (f == 0 || !bfiles) { printf(_("%s: Nothing to do\n"), FUNC_NAME); return FUNC_SUCCESS; } int rename = 0, quit_func = 0; char *input = (char *)NULL; CONFIRM: while (!input) { input = rl_no_hist(_("Is this OK? [y/n/(e)dit] "), 0); if (!input) continue; if (strcmp(input, "yes") == 0 || strcmp(input, "no") == 0 || strcmp(input, "edit") == 0) input[1] = '\0'; if (input[1] || !strchr("yYnNeEq", *input)) { free(input); input = (char *)NULL; continue; } switch (*input) { case 'y': /* fallthrough */ case 'Y': rename = 1; break; case 'q': /* fallthrough */ case 'n': /* fallthrough */ case 'N': quit_func = 1; break; case 'e': do_edit = 1; bfiles = edit_replacements(bfiles, &f, &edited_names); if (!bfiles || edited_names == -1) break; if (edited_names == 1 && f > 0) { free(input); input = (char *)NULL; goto CONFIRM; } else { rename = 1; } break; default: break; } } free(input); if (f == 0) { /* Just in case either the original or the replacement filename * was removed from the list by the user, leaving only one of the two. */ if (bfiles) { free(bfiles[0].original); free(bfiles[0].replacement); } free(bfiles); printf(_("%s: Nothing to do\n"), FUNC_NAME); return FUNC_SUCCESS; } if (edited_names == -1 || quit_func == 1) { /* ERROR or quit */ if (bfiles) { for (i = 0; i < f; i++) { free(bfiles[i].original); free(bfiles[i].replacement); } } free(bfiles); return (quit_func == 1 ? FUNC_SUCCESS : FUNC_FAILURE); } /* The user entered 'e' to edit the file, but nothing was modified * Ask for confirmation in case the user just wanted to see what would * be done. */ if (do_edit == 1) { printf(_("%zu filename(s) will be bleached\n"), f); if (rl_get_y_or_n(_("Continue?"), 0) != 1) { if (bfiles) { for (i = 0; i < f; i++) { free(bfiles[i].original); free(bfiles[i].replacement); } } free(bfiles); return FUNC_SUCCESS; } } /* If renaming all selected files, deselect them */ if (rename == 1 && is_sel) deselect_all(); int total_rename = rename == 1 ? (int)f : 0; size_t rep_suffix = 1; int exit_status = FUNC_SUCCESS; for (i = 0; i < f; i++) { char *o = (bfiles && bfiles[i].original) ? bfiles[i].original : (char *)NULL; char *r = (bfiles && bfiles[i].replacement) ? bfiles[i].replacement : (char *)NULL; if (o && *o && r && *r && rename) { /* Make sure the replacement filename does not exist. If * it does, append REP_SUFFIX and try again. */ struct stat a; while (lstat(r, &a) == 0) { char tmp[PATH_MAX + 1]; xstrsncpy(tmp, r, sizeof(tmp)); const size_t len = PATH_MAX + MAX_INT_STR + 2; r = xnrealloc(r, len, sizeof(char)); snprintf(r, len, "%s-%zu", tmp, rep_suffix); rep_suffix++; } if (renameat(XAT_FDCWD, o, XAT_FDCWD, r) == -1) { xerror(_("bleach: Cannot rename '%s' to '%s': %s\n"), o, r, strerror(errno)); total_rename--; exit_status = FUNC_FAILURE; } } free(o); free(r); } free(bfiles); if (exit_status == FUNC_FAILURE || total_rename == 0) { printf(_("%s: %d filenames(s) bleached\n"), FUNC_NAME, total_rename); } else { if (conf.autols == 1) reload_dirlist(); print_reload_msg(SET_SUCCESS_PTR, xs_cb, _("%d filename(s) bleached\n"), total_rename); } return exit_status; } #else void *_skip_me_bleach; #endif /* !_NO_BLEACH */ clifm-1.26.3/src/name_cleaner.h000066400000000000000000000020111506632037700162510ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* name_cleaner.h */ #ifndef NAME_CLEANER_H #define NAME_CLEANER_H __BEGIN_DECLS int bleach_files(char **names); __END_DECLS #endif /* NAME_CLEANER_H */ clifm-1.26.3/src/navigation.c000066400000000000000000000444361506632037700160130ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* navigation.c -- functions to control the navigation system */ #include "helpers.h" #include #include #include #include #include "aux.h" /* mem.h, normalize_path, get_cwd */ #include "checks.h" /* is_number */ #include "fuzzy_match.h" /* fuzzy_match, contains_utf8 */ #include "history.h" /* add_to_dirhist */ #include "jump.h" /* add_to_jumpdb */ #include "listing.h" /* reload_dirlist */ #include "messages.h" /* description and usage messages */ #include "misc.h" /* xerror */ #include "navigation.h" #include "readline.h" /* rl_no_hist */ #include "term.h" /* report_cwd(), set_term_title() */ #define BD_CONTINUE 2 /* Builtin version of pwd(1). Print the current working directory. * Try first our own internal representation (workspaces array). If something * goes wrong, fallback to $PWD/getcwd(3) (via get_cwd()). */ int pwd_function(const char *arg) { int resolve_links = 0; char *pwd = (char *)NULL; if (arg && *arg == '-') { if (arg[1] == 'P') { resolve_links = 1; } else if (IS_HELP(arg)) { puts(PWD_DESC); return FUNC_SUCCESS; } else if (arg[1] != 'L') { xerror(_("pwd: '%s': Invalid option\nUsage: pwd [-LP]\n"), arg); return FUNC_FAILURE; } } if (workspaces && workspaces[cur_ws].path) { pwd = workspaces[cur_ws].path; } else { char p[PATH_MAX + 1]; *p = '\0'; pwd = get_cwd(p, sizeof(p), 0); } if (!pwd || !*pwd) { xerror(_("%s: Error getting the current working directory\n"), PROGRAM_NAME); return FUNC_FAILURE; } if (resolve_links == 0) { puts(pwd); return FUNC_SUCCESS; } char p[PATH_MAX + 1]; *p = '\0'; const char *real_path = xrealpath(pwd, p); if (!real_path) { xerror("pwd: '%s': %s\n", pwd, strerror(errno)); return errno; } puts(p); return FUNC_SUCCESS; } /* Return the list of paths in CWD matching STR. */ char ** get_bd_matches(const char *str, int *n, const int mode) { if (*workspaces[cur_ws].path == '/' && !workspaces[cur_ws].path[1]) return (char **)NULL; char *cwd = workspaces[cur_ws].path; char **matches = (char **)NULL; if (mode == BD_TAB) { /* matches will be passed to readline for tab completion, so that * we need to reserve the first slot to hold the query string. */ *n = 1; matches = xnmalloc(2, sizeof(char *)); } while (1) { char *p = (char *)NULL; if (str && *str) { /* Non-empty query string. */ p = conf.case_sens_path_comp ? strstr(cwd, str) : xstrcasestr(cwd, (char *)str); if (!p) break; } char *q = strchr(p ? p : cwd, '/'); if (!q) { if (!*(++cwd)) break; continue; } *q = '\0'; matches = xnrealloc(matches, (size_t)*n + 2, sizeof(char *)); if (mode == BD_TAB) { /* Print only the path base name. */ char *ss = strrchr(workspaces[cur_ws].path, '/'); if (ss && *(++ss)) matches[*n] = savestring(ss, strlen(ss)); else /* Last slash is the first and only char: we have the root dir. */ matches[*n] = savestring("/", 1); (*n)++; } else { if (!*workspaces[cur_ws].path) { matches[*n] = savestring("/", 1); } else { matches[*n] = savestring(workspaces[cur_ws].path, strlen(workspaces[cur_ws].path)); } (*n)++; } *q = '/'; cwd = q + 1; if (!*cwd) break; } if (mode == BD_TAB) { if (*n == 1) { /* No matches. */ free(matches); return (char **)NULL; } else if (*n == 2) { /* One match. */ char *p = escape_str(matches[1]); if (!p) { free(matches[1]); free(matches); return (char **)NULL; } matches[0] = p; free(matches[1]); matches[1] = (char *)NULL; } else { /* Multiple matches. */ matches[0] = savestring(str, strlen(str)); matches[*n] = (char *)NULL; } } else { if (*n > 0) matches[*n] = (char *)NULL; } return matches; } static int grab_bd_input(const int n) { char *input = (char *)NULL; putchar('\n'); while (!input) { input = rl_no_hist(_("Select a directory ('q' to quit): "), 0); if (!input || !*input) { free(input); input = (char *)NULL; continue; } if (is_number(input)) { const int a = atoi(input); if (a > 0 && a <= n) { free(input); return a - 1; } else { free(input); input = (char *)NULL; continue; } } else if (*input == 'q' && !input[1]) { free(input); return (-1); } else { free(input); input = (char *)NULL; continue; } } return (-1); /* Never reached. */ } static int backdir_directory(char *dir, const char *str) { if (!dir) { xerror(_("bd: '%s': Error unescaping string\n"), str); return FUNC_FAILURE; } if (*dir == '~') { char *exp_path = tilde_expand(dir); if (!exp_path) { xerror(_("bd: '%s': Error expanding tilde\n"), dir); return FUNC_FAILURE; } dir = exp_path; } /* If STR is a directory, just change to it. */ struct stat a; if (stat(dir, &a) == 0 && S_ISDIR(a.st_mode)) return cd_function(dir, CD_PRINT_ERROR); return BD_CONTINUE; } /* If multiple matches, print a menu to select from. */ static int backdir_menu(char **matches) { int i; for (i = 0; matches[i]; i++) { char *sl = strrchr(matches[i], '/'); int flag = 0; if (sl && sl[1]) { *sl = '\0'; sl++; flag = 1; } printf("%s%d%s %s%s%s\n", el_c, i + 1, df_c, di_c, sl ? sl : "/", df_c); if (flag == 1) { sl--; *sl = '/'; } } const int choice = grab_bd_input(i); if (choice != -1) return cd_function(matches[choice], CD_PRINT_ERROR); return FUNC_SUCCESS; } static int help_or_root(const char *str) { if (str && IS_HELP(str)) { puts(_(BD_USAGE)); return FUNC_SUCCESS; } if (*workspaces[cur_ws].path == '/' && !workspaces[cur_ws].path[1]) { puts(_("bd: '/': No parent directory")); return FUNC_SUCCESS; } return FUNC_FAILURE; } /* Change to parent directory matching STR. */ int backdir(char *str) { if (help_or_root(str) == FUNC_SUCCESS) return FUNC_SUCCESS; char *deq_str = str ? unescape_str(str, 0) : (char *)NULL; if (str) { const int ret = backdir_directory(deq_str, str); if (ret != BD_CONTINUE) { free(deq_str); return ret; } } if (!workspaces[cur_ws].path) { free(deq_str); return FUNC_FAILURE; } int n = 0; char **matches = get_bd_matches(deq_str ? deq_str : str, &n, BD_NO_TAB); free(deq_str); if (n == 0) { xerror(_("bd: %s: No matches found\n"), str); return FUNC_FAILURE; } int exit_status = FUNC_SUCCESS; if (n == 1) /* Just one match: change to it. */ exit_status = cd_function(matches[0], CD_PRINT_ERROR); else /* Multiple matches: print a menu to select from. */ exit_status = backdir_menu(matches); int i = n; while (--i >= 0) free(matches[i]); free(matches); return exit_status; } /* Change the current directory. * * Make sure DIR exists, it is actually a directory and is readable. * Only then change directory. * * CD_FLAG is either SET_TITLE or NO_TITLE. In the latter case we have just a * temporary directory change that should not be registered nor informed to * the user. For example, when checking trahsed files we change to the Trash * dir, check files, and immediately return to the directory we came from). * * PWD and OLDPWD are updated only if CD_FLAG is SET_TITLE, that is, when the * current directory is explicitly changed by the user. The terminal window * title is changed accordingly as well, provided cwd_in_title is enabled. */ int xchdir(char *dir, const int cd_flag) { if (!dir || !*dir) { errno = ENOENT; return (-1); } DIR *dirp = opendir(dir); if (!dirp) return (-1); closedir(dirp); const int ret = chdir(dir); if (ret == 0 && cd_flag == SET_TITLE) { char tmp[PATH_MAX + 1]; *tmp = '\0'; const char *p = get_cwd(tmp, sizeof(tmp), 0); /* Do not set OLDPWD if changing to the same directory ("cd ." * and similar commands). */ if (p && *p && strcmp(p, dir) != 0) setenv("OLDPWD", p, 1); setenv("PWD", dir, 1); if (xargs.vt100 != 1) { /* --vt100 */ if (xargs.report_cwd != 0) /* --no-report-cwd */ report_cwd(dir); /* OSC-7 escape sequence */ if (xargs.cwd_in_title == 1) set_term_title(dir); /* --cwd-in-title */ } } return ret; } static char * check_cdpath(const char *name) { if (!name || !*name) return (char *)NULL; if (*name == '/' || (*name == '.' && name[1] == '/') || (*name == '.' && name[1] == '.' && name[2] == '/')) return (char *)NULL; const size_t namelen = strlen(name); char *p = (char *)NULL; struct stat a; for (size_t i = 0; cdpaths[i]; i++) { const size_t len = strlen(cdpaths[i]); const size_t tmp_len = len + namelen + 2; char *tmp = xnmalloc(tmp_len, sizeof(char)); if (len > 0 && cdpaths[i][len - 1] == '/') snprintf(tmp, tmp_len, "%s%s", cdpaths[i], name); else snprintf(tmp, tmp_len, "%s/%s", cdpaths[i], name); char *exp_path = (char *)NULL; if (*tmp == '~') exp_path = tilde_expand(tmp); const char *dir = exp_path ? exp_path : tmp; if (stat(dir, &a) != -1 && S_ISDIR(a.st_mode)) { p = savestring(dir, strlen(dir)); free(tmp); free(exp_path); break; } free(tmp); free(exp_path); } /* Print message (post_listing(), in listing.c) to let the user * know they changed to a dir in CDPATH. */ if (p) is_cdpath = 1; return p; } /* Change the current directory to the home directory. */ static int change_to_home_dir(const int cd_flag) { if (!user.home) { if (cd_flag == CD_PRINT_ERROR) xerror("%s\n", _("cd: Home directory not found")); return ENOENT; } if (xchdir(user.home, SET_TITLE) != FUNC_SUCCESS) { if (cd_flag == CD_PRINT_ERROR) xerror("cd: '%s': %s\n", user.home, strerror(errno)); return errno; } if (workspaces) { free(workspaces[cur_ws].path); workspaces[cur_ws].path = savestring(user.home, user.home_len); } return FUNC_SUCCESS; } /* Change current directory to NEW_PATH. */ static int change_to_path(char *new_path, const int cd_flag) { if (!new_path || !*new_path) { xerror("%s\n", _("cd: Path is NULL or empty")); return EINVAL; } if (strchr(new_path, '\\')) { char *deq_path = unescape_str(new_path, 0); if (deq_path) { /* deq_path is guaranteed to be shorter than new_path. */ xstrsncpy(new_path, deq_path, strlen(deq_path) + 1); free(deq_path); } } char *cdpath_path = cdpath_n > 0 ? check_cdpath(new_path) : NULL; errno = 0; char *tmp = cdpath_path ? cdpath_path : new_path; char *dest_dir = normalize_path(tmp, strlen(tmp)); free(cdpath_path); if (!dest_dir) { if (cd_flag == CD_PRINT_ERROR) xerror(_("cd: '%s': Error normalizing path\n"), new_path); return FUNC_FAILURE; } if (xchdir(dest_dir, SET_TITLE) != FUNC_SUCCESS) { if (cd_flag == CD_PRINT_ERROR) xerror("cd: '%s': %s\n", new_path, strerror(errno)); free(dest_dir); /* Most shells return 1 in case of EACCESS/ENOENT error. However, 1, as * a general error code, is not quite informative. Why not to return the * actual error code returned by chdir(3)? Note that POSIX only requires * for cd to return >0 in case of error (see cd(1p)). */ return (errno == EACCES || errno == ENOENT) ? 1 : errno; } if (workspaces) { free(workspaces[cur_ws].path); workspaces[cur_ws].path = savestring(dest_dir, strlen(dest_dir)); } free(dest_dir); return FUNC_SUCCESS; } /* Implementation of the shell 'cd -' command. */ static int change_to_previous_dir(void) { static int state = 0; char *cmd[] = { state == 0 ? "b" : "f", NULL }; state = !state; return *cmd[0] == 'b' ? back_function(cmd) : forth_function(cmd); } static inline int skip_directory(const char *dir) { return (conf.dirhistignore_regex && *conf.dirhistignore_regex && regexec(®ex_dirhist, dir, 0, NULL, 0) == FUNC_SUCCESS); } /* Change current directory to NEW_PATH, or to HOME if new_path is NULL. * Errors are printed only if CD_FLAG is set to CD_PRINT_ERROR (1) */ int cd_function(char *new_path, const int cd_flag) { /* If no argument, change to home. */ int ret = FUNC_SUCCESS; if (!new_path || !*new_path) { if ((ret = change_to_home_dir(cd_flag)) != FUNC_SUCCESS) return ret; } else if (*new_path == '-' && !new_path[1]) { return change_to_previous_dir(); } else { if ((ret = change_to_path(new_path, cd_flag)) != FUNC_SUCCESS) return ret; } const int skip = skip_directory(workspaces[cur_ws].path); if (skip == 0) add_to_dirhist(workspaces[cur_ws].path); dir_changed = 1; if (conf.autols == 1) reload_dirlist(); if (skip == 0) add_to_jumpdb(workspaces[cur_ws].path); return ret; } /* Return a pointer to the first occurrence in the string STR of a byte that * is not C. Otherwise, if only C is found, NULL is returned. */ static const char * xstrcpbrk(const char *restrict str, const char c) { if (!str || !*str) return (char *)NULL; while (*str) { if (*str != c) return str; str++; } return (char *)NULL; } /* Convert "... n" into "../.. n" * and "../.. n" into the corresponding path. */ char * fastback(const char *str) { if (!str || !*str || xstrcpbrk(str, '.')) return (char *)NULL; /* At this point we know STR contains only dots. */ const size_t dots = strlen(str); if (dots <= 2) return dots == 2 ? normalize_path("..", 2) : NULL; char dir[PATH_MAX + 1]; dir[0] = '.'; dir[1] = '.'; /* Replace each dot after ".." by "/.." */ size_t i, c = 2; for (i = 2; c < dots;) { dir[i] = '/'; i++; dir[i] = '.'; i++; dir[i] = '.'; i++; c++; } dir[i] = '\0'; return normalize_path(dir, i); } void print_dirhist(char *query) { const int n = DIGINUM(dirhist_total_index); const size_t len = (query && conf.fuzzy_match == 1) ? strlen(query) : 0; const int fuzzy_str_type = (len > 0 && contains_utf8(query) == 1) ? FUZZY_FILES_UTF8 : FUZZY_FILES_ASCII; for (int i = 0; i < dirhist_total_index; i++) { if (!old_pwd[i] || *old_pwd[i] == KEY_ESC) continue; if (query && (conf.fuzzy_match == 1 ? fuzzy_match(query, old_pwd[i], len, fuzzy_str_type) == 0 : !strstr(old_pwd[i], query) ) ) continue; if (i == dirhist_cur_index) printf(" %s%-*d%s %s%s%s\n", el_c, n, i + 1, df_c, mi_c, old_pwd[i], df_c); else printf(" %s%-*d%s %s%s%s\n", el_c, n, i + 1, df_c, di_c, old_pwd[i], df_c); } } static int clear_dirhist(void) { int i = dirhist_total_index; while (--i >= 0) free(old_pwd[i]); dirhist_cur_index = dirhist_total_index = 0; add_to_dirhist(workspaces[cur_ws].path); printf(_("%s: Directory history cleared\n"), PROGRAM_NAME); return FUNC_SUCCESS; } /* Change to the specified directory number (N) in the directory * history list. */ static int change_to_dirhist_num(int n) { if (n <= 0 || n > dirhist_total_index) { xerror(_("history: %d: No such ELN\n"), n); return FUNC_FAILURE; } n--; if (!old_pwd[n] || *old_pwd[n] == KEY_ESC) { xerror("%s\n", _("history: Invalid history entry")); return FUNC_FAILURE; } int ret = xchdir(old_pwd[n], SET_TITLE); if (ret != 0) { xerror("history: '%s': %s\n", old_pwd[n], strerror(errno)); return FUNC_FAILURE; } free(workspaces[cur_ws].path); workspaces[cur_ws].path = savestring(old_pwd[n], strlen(old_pwd[n])); dirhist_cur_index = n; ret = FUNC_SUCCESS; if (conf.autols == 1) reload_dirlist(); return ret; } static int surf_hist(char **args) { if (*args[1] == 'h' && (!args[1][1] || strcmp(args[1], "hist") == 0)) { print_dirhist(NULL); return FUNC_SUCCESS; } if (*args[1] == 'c' && strcmp(args[1], "clear") == 0) return clear_dirhist(); if (*args[1] != '!' || is_number(args[1] + 1) != 1) { fprintf(stderr, "%s\n", _(DIRHIST_USAGE)); return FUNC_FAILURE; } const int n = atoi(args[1] + 1); return change_to_dirhist_num(n); } /* Set the path of the current workspace to NEW_PATH. */ static int set_path(const char *new_path) { free(workspaces[cur_ws].path); workspaces[cur_ws].path = savestring(new_path, strlen(new_path)); if (!workspaces[cur_ws].path) return FUNC_FAILURE; add_to_jumpdb(workspaces[cur_ws].path); dir_changed = 1; if (conf.autols == 1) reload_dirlist(); return FUNC_SUCCESS; } /* Go back one entry in dirhist. */ int back_function(char **args) { if (!args) return FUNC_FAILURE; if (args[1]) { if (!IS_HELP(args[1])) return surf_hist(args); puts(_(BACK_USAGE)); return FUNC_SUCCESS; } /* Find the previous non-consecutive equal and valid entry. */ int i = dirhist_cur_index; while (--i >= 0) { if (old_pwd[i] && *old_pwd[i] != KEY_ESC && (!workspaces[cur_ws].path || strcmp(workspaces[cur_ws].path, old_pwd[i]) != 0)) break; } if (i < 0) return FUNC_SUCCESS; dirhist_cur_index = i; if (xchdir(old_pwd[dirhist_cur_index], SET_TITLE) == FUNC_SUCCESS) return set_path(old_pwd[dirhist_cur_index]); xerror("cd: '%s': %s\n", old_pwd[dirhist_cur_index], strerror(errno)); /* Invalidate this entry. */ *old_pwd[dirhist_cur_index] = KEY_ESC; if (dirhist_cur_index > 0) dirhist_cur_index--; return FUNC_FAILURE; } /* Go forth one entry in dirhist. */ int forth_function(char **args) { if (!args) return FUNC_FAILURE; if (args[1]) { if (!IS_HELP(args[1])) return surf_hist(args); puts(_(FORTH_USAGE)); return FUNC_SUCCESS; } /* Find the next valid entry. */ int i = dirhist_cur_index; while (++i <= dirhist_total_index) { if (old_pwd[i] && (*old_pwd[i] != KEY_ESC && (!workspaces[cur_ws].path || strcmp(workspaces[cur_ws].path, old_pwd[i]) != 0))) break; } if (i > dirhist_total_index) return FUNC_SUCCESS; dirhist_cur_index = i; if (xchdir(old_pwd[dirhist_cur_index], SET_TITLE) == FUNC_SUCCESS) return set_path(old_pwd[dirhist_cur_index]); xerror("cd: '%s': %s\n", old_pwd[dirhist_cur_index], strerror(errno)); /* Invalidate this entry. */ *old_pwd[dirhist_cur_index] = KEY_ESC; if (dirhist_cur_index < dirhist_total_index && old_pwd[dirhist_cur_index + 1]) dirhist_cur_index++; return FUNC_FAILURE; } clifm-1.26.3/src/navigation.h000066400000000000000000000025341506632037700160110ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* navigation.h */ #ifndef NAVIGATION_H #define NAVIGATION_H #include "workspaces.h" __BEGIN_DECLS int back_function(char **args); int backdir(char *str); int cd_function(char *new_path, const int cd_flag); char *fastback(const char *str); int forth_function(char **args); char **get_bd_matches(const char *str, int *n, const int mode); void print_dirhist(char *query); int pwd_function(const char *arg); int xchdir(char *dir, const int cd_flag); __END_DECLS #endif /* NAVIGATION_H */ clifm-1.26.3/src/profiles.c000066400000000000000000000352001506632037700154640ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* profiles.c -- functions for manipulating user profiles */ #ifndef _NO_PROFILES #include "helpers.h" #include #include #include #include #if defined(MAC_OS_X_RENAMEAT_SYS_STDIO_H) # include /* renameat(2) */ #endif /* MAC_OS_X_RENAMEAT_SYS_STDIO_H */ #include "aux.h" #include "bookmarks.h" #include "checks.h" #include "config.h" #include "exec.h" // exec_profile #include "history.h" #include "init.h" #include "listing.h" #include "messages.h" #include "misc.h" #include "navigation.h" #include "profiles.h" #include "sort.h" #include "spawn.h" /* Get the list of all available profile names and store them in the * profile_names global array. Returns zero on success, one otherwise. */ int get_profile_names(void) { if (!config_dir_gral) return FUNC_FAILURE; const size_t len = strlen(config_dir_gral) + 10; char *pf_dir = xnmalloc(len, sizeof(char)); snprintf(pf_dir, len, "%s/profiles", config_dir_gral); struct dirent **profs = (struct dirent **)NULL; const int files_n = scandir(pf_dir, &profs, NULL, xalphasort); if (files_n == -1) { free(pf_dir); return FUNC_FAILURE; } size_t i, pf_n = 0; #if !defined(_DIRENT_HAVE_D_TYPE) struct stat attr; #endif /* !_DIRENT_HAVE_D_TYPE */ for (i = 0; i < (size_t)files_n; i++) { #if !defined(_DIRENT_HAVE_D_TYPE) char tmp[PATH_MAX + 1]; snprintf(tmp, sizeof(tmp), "%s/%s", pf_dir, profs[i]->d_name); if (lstat(tmp, &attr) == -1) continue; if (S_ISDIR(attr.st_mode) #else if (profs[i]->d_type == DT_DIR #endif /* !_DIRENT_HAVE_D_TYPE */ /* Discard ".", "..", and hidden dirs */ && *profs[i]->d_name != '.') { profile_names = xnrealloc(profile_names, pf_n + 1, sizeof(char *)); profile_names[pf_n] = savestring(profs[i]->d_name, strlen(profs[i]->d_name)); pf_n++; } free(profs[i]); } free(pf_dir); free(profs); profile_names = xnrealloc(profile_names, pf_n + 1, sizeof(char *)); profile_names[pf_n] = (char *)NULL; return FUNC_SUCCESS; } /* Check if NAME is an existing profile name. * If true, returns the index of the profile in the PROFILE_NAMES array. * Otherwise, returns -1. */ static int check_profile(const char *name) { for (int i = 0; profile_names[i]; i++) { if (*name == *profile_names[i] && strcmp(name, profile_names[i]) == 0) return i; } return (-1); } /* Switch profile to PROF */ int profile_set(const char *prof) { if (xargs.stealth_mode == 1) { printf("%s: profiles: %s\n", PROGRAM_NAME, STEALTH_DISABLED); return FUNC_SUCCESS; } if (!prof) return FUNC_FAILURE; dir_cmds.first_cmd_in_dir = UNSET; /* Check if prof is a valid profile */ int found = check_profile(prof); if (found == -1) { xerror(_("pf: '%s': No such profile\nTo add a new " "profile enter 'pf add PROFILE'\n"), prof); return FUNC_FAILURE; } /* If changing to the current profile, do nothing */ if ((!alt_profile && *prof == 'd' && strcmp(prof, "default") == 0) || (alt_profile && *prof == *alt_profile && strcmp(prof, alt_profile) == 0)) { printf(_("pf: '%s' is the current profile\n"), prof); return FUNC_SUCCESS; } int i; if (conf.restore_last_path == 1) save_last_path(NULL); if (alt_profile) { free(alt_profile); alt_profile = (char *)NULL; } /* Set the new profile value */ /* Default profile == (alt_profile == NULL) */ if (*prof != 'd' || strcmp(prof, "default") != 0) alt_profile = savestring(prof, strlen(prof)); i = MAX_WS; while (--i >= 0) { free(workspaces[i].path); workspaces[i].path = (char *)NULL; free(workspaces[i].name); workspaces[i].name = (char *)NULL; } cur_ws = UNSET; /* Reset everything */ reload_config(); i = (int)usrvar_n; while (--i >= 0) { free(usr_var[i].name); free(usr_var[i].value); } usrvar_n = 0; i = (int)actions_n; while (--i >= 0) { free(usr_actions[i].name); free(usr_actions[i].value); } actions_n = 0; exec_profile(); if (config_ok == 1) { /* Shrink the log file if needed */ truncate_file(msgs_log_file, conf.max_log, 0); truncate_file(cmds_log_file, conf.max_log, 0); /* Reset history */ if (access(hist_file, F_OK | W_OK) == 0) { clear_history(); /* This is for readline */ read_history(hist_file); history_truncate_file(hist_file, conf.max_hist); } else { int fd = 0; FILE *hist_fp = open_fwrite(hist_file, &fd); if (hist_fp) { fputs("edit\n", hist_fp); fclose(hist_fp); } else { err('w', PRINT_PROMPT, _("pf: Error opening the " "history file\n")); } } get_history(); /* This is only for us */ } free_bookmarks(); load_bookmarks(); load_actions(); /* Reload PATH commands (actions are profile specific) */ if (bin_commands) { for (i = 0; bin_commands[i]; i++) free(bin_commands[i]); free(bin_commands); bin_commands = (char **)NULL; } if (paths) { i = (int)path_n; while (--i >= 0) free(paths[i].path); free(paths); } path_n = get_path_env(1); get_path_programs(); if (conf.restore_last_path == 1) get_last_path(); if (cur_ws == UNSET) cur_ws = DEF_CUR_WS; if (!workspaces[cur_ws].path) { char tmp[PATH_MAX + 1] = ""; char *cwd = get_cwd(tmp, sizeof(tmp), 0); if (!cwd || !*cwd) { xerror("pf: %s\n", strerror(errno)); exit(FUNC_FAILURE); } workspaces[cur_ws].path = savestring(cwd, strlen(cwd)); } if (xchdir(workspaces[cur_ws].path, SET_TITLE) == -1) { xerror("pf: '%s': %s\n", workspaces[cur_ws].path, strerror(errno)); return FUNC_FAILURE; } if (conf.autols == 1) reload_dirlist(); print_reload_msg(NULL, NULL, _("Switched to profile %s%s%s\n"), BOLD, prof, NC); return FUNC_SUCCESS; } /* Add a new profile named PROF */ static int profile_add(const char *prof) { if (!prof) return FUNC_FAILURE; const int found = check_profile(prof); if (found != -1) { xerror(_("pf: '%s': Profile already exists\n"), prof); return FUNC_FAILURE; } if (!home_ok) { xerror(_("pf: '%s': Cannot create profile: Home directory " "not found\n"), prof); return FUNC_FAILURE; } const size_t pnl_len = strlen(PROGRAM_NAME); size_t tmp_len = strlen(config_dir_gral) + strlen(prof) + 11; /* ### GENERATE PROGRAM'S CONFIG DIRECTORY NAME ### */ char *nconfig_dir = xnmalloc(tmp_len, sizeof(char)); snprintf(nconfig_dir, tmp_len, "%s/profiles/%s", config_dir_gral, prof); /* #### CREATE THE CONFIG DIR #### */ char *tmp_cmd[] = {"mkdir", "-p", nconfig_dir, NULL}; if (launch_execv(tmp_cmd, FOREGROUND, E_NOFLAG) != FUNC_SUCCESS) { xerror(_("pf: mkdir: '%s': Error creating " "configuration directory\n"), nconfig_dir); free(nconfig_dir); return FUNC_FAILURE; } /* If the config dir is fine, generate config filenames */ int exit_status = FUNC_SUCCESS; const size_t config_len = strlen(nconfig_dir); tmp_len = config_len + pnl_len + 4; char *nconfig_file = xnmalloc(tmp_len, sizeof(char)); snprintf(nconfig_file, tmp_len, "%s/%src", nconfig_dir, PROGRAM_NAME); tmp_len = config_len + 15; char *nhist_file = xnmalloc(tmp_len, sizeof(char)); snprintf(nhist_file, tmp_len, "%s/history.clifm", nconfig_dir); tmp_len = config_len + 16; char *nmime_file = xnmalloc(tmp_len, sizeof(char)); snprintf(nmime_file, tmp_len, "%s/mimelist.clifm", nconfig_dir); /* Create config files */ /* #### CREATE THE HISTORY FILE #### */ int fd = 0; FILE *hist_fp = open_fwrite(nhist_file, &fd); if (!hist_fp) { xerror("pf: fopen: %s: %s\n", nhist_file, strerror(errno)); exit_status = FUNC_FAILURE; } else { /* To avoid malloc errors in read_history(), do not create * an empty file */ fputs("edit\n", hist_fp); fclose(hist_fp); } /* #### CREATE THE MIME CONFIG FILE #### */ if (create_mime_file(nmime_file, 1) != FUNC_SUCCESS) exit_status = FUNC_FAILURE; /* #### CREATE THE MAIN CONFIG FILE #### */ if (create_main_config_file(nconfig_file) != FUNC_SUCCESS) exit_status = FUNC_FAILURE; /* Free stuff */ free(nconfig_dir); free(nconfig_file); free(nhist_file); free(nmime_file); if (exit_status == FUNC_SUCCESS) { printf(_("Succesfully created profile %s%s%s\n"), BOLD, prof, df_c); size_t i; for (i = 0; profile_names[i]; i++) free(profile_names[i]); get_profile_names(); } else { xerror(_("pf: 's': Error creating profile\n"), prof); } return exit_status; } /* Delete the profile PROF */ static int profile_del(const char *prof) { if (xargs.stealth_mode == 1) { printf("%s: profiles: %s\n", PROGRAM_NAME, STEALTH_DISABLED); return FUNC_SUCCESS; } if (!prof) return FUNC_FAILURE; /* Check if prof is a valid profile */ const int found = check_profile(prof); if (found == -1) { xerror(_("pf: '%s': No such profile\n"), prof); return FUNC_FAILURE; } const size_t len = strlen(config_dir_gral) + strlen(prof) + 11; char *tmp = xnmalloc(len, sizeof(char)); snprintf(tmp, len, "%s/profiles/%s", config_dir_gral, prof); char *cmd[] = {"rm", "-r", "--", tmp, NULL}; const int ret = launch_execv(cmd, FOREGROUND, E_NOFLAG); free(tmp); if (ret != FUNC_SUCCESS) { xerror(_("pf: '%s': Error removing profile\n"), prof); return ret; } printf(_("Successfully removed profile %s%s%s\n"), BOLD, prof, df_c); size_t i; for (i = 0; profile_names[i]; i++) free(profile_names[i]); get_profile_names(); return FUNC_SUCCESS; } static int print_profiles(void) { size_t i; const char *cur_prof = alt_profile ? alt_profile : "default"; const char *ptr = SET_MISC_PTR; for (i = 0; profile_names[i]; i++) { if (*cur_prof == *profile_names[i] && strcmp(cur_prof, profile_names[i]) == 0) printf("%s%s%s %s\n", mi_c, ptr, df_c, profile_names[i]); else printf(" %s\n", profile_names[i]); } return FUNC_SUCCESS; } static int print_current_profile(void) { printf("Current profile: %s%s%s\n", BOLD, alt_profile ? alt_profile : "default", df_c); return FUNC_SUCCESS; } int validate_profile_name(const char *name) { if (!name || !*name || *name == '.' || *name == '~' || *name == '$' || strchr(name, '/')) return FUNC_FAILURE; return FUNC_SUCCESS; } static int create_profile(const char *name) { if (name) { if (validate_profile_name(name) == FUNC_SUCCESS) return profile_add(name); xerror(_("pf: '%s': Invalid profile name\n"), name); return FUNC_FAILURE; } fprintf(stderr, "%s\n", PROFILES_USAGE); return FUNC_FAILURE; } static int delete_profile(const char *name) { if (name) return profile_del(name); fprintf(stderr, "%s\n", PROFILES_USAGE); return FUNC_FAILURE; } static int switch_profile(const char *name) { if (name) return profile_set(name); fprintf(stderr, "%s\n", PROFILES_USAGE); return FUNC_FAILURE; } /* Rename profile named ARG[0] to ARG[1]. * The corresponding profile file is renamed, just as the corresponding * entry in the PROFILE_NAMES array. */ static int rename_profile(char **args) { if (!args || !args[0] || !args[1]) { fprintf(stderr, "%s\n", PROFILES_USAGE); return FUNC_FAILURE; } if (!config_dir_gral) { xerror(_("pf: Configuration directory is not set\n")); return FUNC_FAILURE; } if (validate_profile_name(args[1]) != FUNC_SUCCESS) { xerror(_("pf: '%s': Invalid profile name\n"), args[1]); return FUNC_FAILURE; } if (*args[0] == *args[1] && strcmp(args[0], args[1]) == 0) { puts(_("pf: Nothing to do. Source and destination names are the same.")); return FUNC_FAILURE; } char *p = unescape_str(args[0], 0); if (p) { free(args[0]); args[0] = p; } int src_pf_index = check_profile(args[0]); if (src_pf_index == -1) { xerror(_("pf: '%s': No such profile\n"), args[0]); return FUNC_FAILURE; } if (strcmp(args[0], alt_profile ? alt_profile : "default") == 0) { xerror(_("pf: '%s': Is the current profile\n"), args[0]); return FUNC_FAILURE; } char src_pf_name[PATH_MAX + NAME_MAX + 11]; snprintf(src_pf_name, sizeof(src_pf_name), "%s/profiles/%s", config_dir_gral, args[0]); DIR *dir = opendir(src_pf_name); if (!dir) { xerror("pf: '%s': %s\n", src_pf_name, strerror(errno)); return errno; } const int fd = dirfd(dir); if (fd == -1) { xerror("pf: '%s': %s\n", src_pf_name, strerror(errno)); closedir(dir); return errno; } p = unescape_str(args[1], 0); if (p) { free(args[1]); args[1] = p; } char dst_pf_name[PATH_MAX + NAME_MAX + 11]; snprintf(dst_pf_name, sizeof(dst_pf_name), "%s/profiles/%s", config_dir_gral, args[1]); const int ret = renameat(fd, src_pf_name, XAT_FDCWD, dst_pf_name); closedir(dir); if (ret == -1) { xerror(_("pf: Cannot rename profile '%s': %s\n"), args[0], strerror(errno)); return errno; } const size_t len = strlen(args[1]); profile_names[src_pf_index] = xnrealloc(profile_names[src_pf_index], len + 1, sizeof(char)); xstrsncpy(profile_names[src_pf_index], args[1], len + 1); printf(_("pf: '%s': Profile successfully renamed to %s%s%s\n"), args[0], BOLD, args[1], df_c); return FUNC_SUCCESS; } /* Main profiles function. Call the operation specified by the first * argument option: list, add, set, or delete */ int profile_function(char **args) { if (xargs.stealth_mode == 1) { printf("%s: profiles: %s\n", PROGRAM_NAME, STEALTH_DISABLED); return FUNC_SUCCESS; } if (!args[1]) return print_current_profile(); if (IS_HELP(args[1])) { puts(_(PROFILES_USAGE)); return FUNC_SUCCESS; } /* List profiles */ if (*args[1] == 'l' && (strcmp(args[1], "ls") == 0 || strcmp(args[1], "list") == 0)) return print_profiles(); if (args[2]) { char *p = unescape_str(args[2], 0); if (p) { free(args[2]); args[2] = p; } } /* Create a new profile */ if (*args[1] == 'a' && strcmp(args[1], "add") == 0) return create_profile(args[2]); /* Delete a profile */ if (*args[1] == 'd' && strcmp(args[1], "del") == 0) return delete_profile(args[2]); /* Rename a profile */ if (*args[1] == 'r' && strcmp(args[1], "rename") == 0) return rename_profile(args + 2); /* Switch to another profile */ if (*args[1] == 's' && strcmp(args[1], "set") == 0) return switch_profile(args[2]); fprintf(stderr, "%s\n", PROFILES_USAGE); return FUNC_FAILURE; } #else void *_skip_me_prof; #endif /* !_NO_PROFILES */ clifm-1.26.3/src/profiles.h000066400000000000000000000021511506632037700154700ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* profiles.h */ #ifndef PROFILES_H #define PROFILES_H __BEGIN_DECLS int get_profile_names(void); int profile_function(char **args); int profile_set(const char *prof); int validate_profile_name(const char *name); __END_DECLS #endif /* PROFILES_H */ clifm-1.26.3/src/prompt.c000066400000000000000000001344551506632037700151760ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* prompt.c -- functions controlling the appearance and behavior of the prompt */ /* The decode_prompt function is taken from Bash (1.14.7), licensed under * GPL-2.0-or-later, and modified to fit our needs. */ #include "helpers.h" #include #if !defined(__HAIKU__) && !defined(__OpenBSD__) && !defined(__ANDROID__) # include #endif /* !__HAIKU__ && !__OpenBSD__ && !__ANDROID__ */ #include #include /* history_expand() */ #include #include /* mbstowcs, wcschr, wcwidth */ #include "aux.h" #include "checks.h" /* is_number() */ #include "colors.h" /* update_warning_prompt_text_color() */ #include "file_operations.h" #include "history.h" #include "init.h" #include "listing.h" #include "messages.h" #include "misc.h" #include "navigation.h" #include "prompt.h" #include "properties.h" /* get_file_perms() */ #include "sanitize.h" #include "sort.h" /* num_to_sort_name() */ #include "spawn.h" #ifndef _NO_SUGGESTIONS # include "suggestions.h" #endif /* !_NO_SUGGESTIONS */ #if defined(__HAIKU__) || defined(__OpenBSD__) || defined(__ANDROID__) # define NO_WORDEXP #else # define MAX_PMOD_PATHS 8 static size_t p_mod_paths_n = 0; struct p_mod_paths_t { char path[PATH_MAX]; char *name; }; static struct p_mod_paths_t p_mod_paths[MAX_PMOD_PATHS]; #endif /* __HAIKU__ || __OpenBSD__ || __ANDROID__ */ int g_prompt_ignore_empty_line = 0; static char * gen_time(const int c) { char *temp = (char *)NULL; const time_t rawtime = time(NULL); struct tm tm; if (!localtime_r(&rawtime, &tm)) { temp = savestring(UNKNOWN_STR, sizeof(UNKNOWN_STR) - 1); } else if (c == 't') { char time[9] = ""; strftime(time, sizeof(time), "%H:%M:%S", &tm); temp = savestring(time, sizeof(time)); } else if (c == 'T') { char time[9] = ""; strftime(time, sizeof(time), "%I:%M:%S", &tm); temp = savestring(time, sizeof(time)); } else if (c == 'A') { char time[6] = ""; strftime(time, sizeof(time), "%H:%M", &tm); temp = savestring(time, sizeof(time)); } else if (c == '@') { char time[12] = ""; strftime(time, sizeof(time), "%I:%M:%S %p", &tm); temp = savestring(time, sizeof(time)); } else { /* c == 'd' */ char time[12] = ""; strftime(time, sizeof(time), "%a %b %d", &tm); temp = savestring(time, sizeof(time)); } return temp; } static char * gen_rl_vi_mode(const int alloc) { if (rl_editing_mode == RL_EMACS_MODE /*"Ignore if running in vi mode and notifications are enabled: the * notification will be printed by the prompt itself. */ || (alloc == 1 && prompt_notif == 1)) { if (alloc == 0) return ""; char *tmp = xnmalloc(1, sizeof(char)); *tmp = '\0'; return tmp; } Keymap keymap = rl_get_keymap(); if (keymap == vi_insertion_keymap) { return alloc == 1 ? savestring(RL_VI_INS_MODESTR, RL_VI_INS_MODESTR_LEN) : RL_VI_INS_MODESTR; } return alloc == 1 ? savestring(RL_VI_CMD_MODESTR, RL_VI_CMD_MODESTR_LEN) : RL_VI_CMD_MODESTR; } static char * get_dir_basename(const char *str) { /* If not root dir (/), get last path component */ const char *ret = (*str == '/' && !str[1]) ? (char *)NULL : strrchr(str, '/'); if (!ret || !ret[1]) return savestring(str, strlen(str)); return savestring(ret + 1, strlen(ret + 1)); } static char * reduce_path(const char *str) { char *temp = (char *)NULL; const size_t slen = strlen(str); if (slen > (size_t)conf.prompt_p_max_path) { char *ret = strrchr(str, '/'); if (!ret || !ret[1]) temp = savestring(str, slen); else temp = savestring(ret + 1, (size_t)(str + slen - ret - 1)); } else { temp = savestring(str, slen); } return temp; } static size_t copy_char(char *buf, char *s) { const int bytes = IS_UTF8_CHAR(*s) ? utf8_bytes((unsigned char)*s) : 1; if (bytes == 1) { *buf = *s; return 1; } int c = 0; while (c < bytes) { buf[c] = *s; c++; s++; } return (size_t)c; } static char * reduce_path_fish(char *str) { if ((*str == '~' || *str == '/') && !str[1]) return savestring(*str == '~' ? "~" : "/", 1); if (conf.prompt_f_dir_len == 0) return savestring(str, strlen(str)); char *s = str; size_t total_comps = (*s == '~'); while (*s) { if (*s == '/') total_comps++; s++; } if (conf.prompt_f_full_len_dirs > 1 && total_comps > (size_t)conf.prompt_f_full_len_dirs - 1) total_comps -= (size_t)conf.prompt_f_full_len_dirs - 1; size_t slen = (size_t)(s - str); s = str; char *buf = xnmalloc(slen + 1, sizeof(char)); size_t i = 0; size_t cur_comps = 0; if (*s == '~') { buf[i++] = *s; cur_comps++; } while (*s) { if (*s != '/') { s++; continue; } buf[i++] = '/'; cur_comps++; s++; if (cur_comps >= total_comps) { xstrsncpy(buf + i, s, slen - i + 1); break; } if (*s == '.') { buf[i++] = *s; s++; } if (conf.prompt_f_dir_len == 1) { const size_t bytes = copy_char(buf + i, s); i += bytes; s += bytes; continue; } size_t q = 0; while (*s && *s != '/' && q < (size_t)conf.prompt_f_dir_len) { const size_t bytes = copy_char(buf + i, s); i += bytes; s += bytes; q++; } } return buf; } static char * gen_pwd(const int c) { char *temp = (char *)NULL; char *tmp_path = (char *)NULL; int free_tmp_path = 0; if (user.home && strncmp(workspaces[cur_ws].path, user.home, user.home_len) == 0) tmp_path = home_tilde(workspaces[cur_ws].path, &free_tmp_path); if (!tmp_path) tmp_path = workspaces[cur_ws].path; if (c == 'W') temp = get_dir_basename(tmp_path); else if (c == 'p') temp = reduce_path(tmp_path); else if (c == 'f') temp = reduce_path_fish(tmp_path); else /* If c == 'w' */ temp = savestring(tmp_path, strlen(tmp_path)); if (free_tmp_path == 1) free(tmp_path); return temp; } static char * gen_workspace(void) { /* An int (or workspace name) + workspaces color + NUL byte */ char s[NAME_MAX + sizeof(ws1_c) + 1]; char *cl = df_c; if (conf.colorize == 1) { switch (cur_ws + 1) { case 1: cl = *ws1_c ? ws1_c : DEF_WS1_C; break; case 2: cl = *ws2_c ? ws2_c : DEF_WS2_C; break; case 3: cl = *ws3_c ? ws3_c : DEF_WS3_C; break; case 4: cl = *ws4_c ? ws4_c : DEF_WS4_C; break; case 5: cl = *ws5_c ? ws5_c : DEF_WS5_C; break; case 6: cl = *ws6_c ? ws6_c : DEF_WS6_C; break; case 7: cl = *ws7_c ? ws7_c : DEF_WS7_C; break; case 8: cl = *ws8_c ? ws8_c : DEF_WS8_C; break; default: break; } } if (workspaces[cur_ws].name) snprintf(s, sizeof(s), "%s%s", cl, workspaces[cur_ws].name); else snprintf(s, sizeof(s), "%s%d", cl, cur_ws + 1); /* Using strnlen() here avoids a Redhat hardened compilation warning. */ return savestring(s, strnlen(s, sizeof(s))); } static char * gen_exit_status(void) { const size_t code_len = (size_t)DIGINUM(exit_code); const size_t len = code_len + 3 + ((size_t)MAX_COLOR * 2); char *temp = xnmalloc(len, sizeof(char)); snprintf(temp, len, "%s%d\001%s\002", (exit_code == 0) ? (conf.colorize == 1 ? xs_c : "") : (conf.colorize == 1 ? xf_c : ""), exit_code, df_c); return temp; } static char * gen_escape_char(char **line, int *c) { (*line)++; *c = 0; /* 27 (dec) == 033 (octal) == 0x1b (hex) == \e */ char *temp = xnmalloc(2, sizeof(char)); *temp = '\033'; temp[1] = '\0'; return temp; } static char * gen_octal(char **line, int *c) { char octal_string[4]; xstrsncpy(octal_string, *line, sizeof(octal_string)); int n = octal2int(octal_string); #ifdef CHAR_MAX /* Max octal number: 0177 (char is signed) or 0377 (char is unsigned). */ if (n > CHAR_MAX) n = CHAR_MAX; #else if (n > 127) n = 127; #endif /* CHAR_MAX */ char *temp = xnmalloc(3, sizeof(char)); if (n == CTLESC || n == CTLNUL) { *line += 3; temp[0] = CTLESC; temp[1] = (char)n; temp[2] = '\0'; } else if (n == -1) { temp[0] = '\\'; temp[1] = '\0'; } else { *line += 3; temp[0] = (char)n; temp[1] = '\0'; } *c = 0; return temp; } static char * gen_profile(void) { if (!alt_profile) return savestring("default", 7); return savestring(alt_profile, strlen(alt_profile)); } static char * gen_user_name(void) { if (!user.name) return savestring(UNKNOWN_STR, sizeof(UNKNOWN_STR) - 1); return savestring(user.name, strlen(user.name)); } static char * gen_sort_name(void) { return strdup(num_to_sort_name(conf.sort, 1)); } static char * gen_hostname(const int c) { /* Using strnlen() here avoids a Redhat hardened compilation warning. */ char *temp = savestring(hostname, strnlen(hostname, sizeof(hostname))); if (c != 'h') return temp; char *ret = strchr(temp, '.'); if (ret) *ret = '\0'; return temp; } static char * gen_user_flag(void) { char *temp = xnmalloc(2, sizeof(char)); *temp = user.uid == 0 ? ROOT_USR_CHAR : NON_ROOT_USR_CHAR; temp[1] = '\0'; return temp; } static char * gen_mode(void) { char *temp = xnmalloc(2, sizeof(char)); *temp = conf.light_mode == 1 ? LIGHT_MODE_CHAR : '\0'; temp[1] = '\0'; return temp; } static char * gen_misc(const int c) { char *temp = xnmalloc(2, sizeof(char)); if (c == 'n') *temp = '\n'; else if (c == 'r') *temp = '\r'; else *temp = '\a'; temp[1] = '\0'; return temp; } static char * gen_non_print_sequence(const int c) { char *temp = xnmalloc(2, sizeof(char)); *temp = c == '[' ? RL_PROMPT_START_IGNORE : RL_PROMPT_END_IGNORE; temp[1] = '\0'; return temp; } static char * gen_shell_name(void) { if (user.shell && user.shell_basename) return savestring(user.shell_basename, strlen(user.shell_basename)); return savestring("unknown", 7); } static void add_string(char **tmp, const int c, char **line, char **res, size_t *len) { if (!*tmp) return; if (c) (*line)++; *len += strlen(*tmp); const size_t l = *len + 2 + (wrong_cmd ? (MAX_COLOR + 6) : 0); if (!*res) { *res = xnmalloc(l + 1, sizeof(char)); *(*res) = '\0'; } else { *res = xnrealloc(*res, l + 1, sizeof(char)); } xstrncat(*res, strlen(*res), *tmp, l + 1); free(*tmp); } #ifndef NO_WORDEXP static void reset_ifs(const char *value) { if (value) setenv("IFS", value, 1); else unsetenv("IFS"); } static void substitute_cmd(char **line, char **res, size_t *len) { char *p = strchr(*line, ')'); if (!p) return; /* No ending bracket */ /* Extract the command to be executed */ const char c = p[1]; p[1] = '\0'; const size_t cmd_len = strlen(*line) + 2; char *cmd = xnmalloc(cmd_len, sizeof(char)); snprintf(cmd, cmd_len, "$%s", *line); /* Reinsert leading '$' */ p[1] = c; /* Set LINE after the ending bracket to continue processing */ *line = p + 1; char *old_value = xgetenv("IFS", 1); setenv("IFS", "", 1); wordexp_t wordbuf; const int ret = wordexp(cmd, &wordbuf, 0); reset_ifs(old_value); free(old_value); free(cmd); if (ret != 0) return; if (wordbuf.we_wordc == 0) goto END; for (size_t j = 0; j < wordbuf.we_wordc; j++) { *len += strlen(wordbuf.we_wordv[j]); if (!*res) { *res = xnmalloc(*len + 2, sizeof(char)); *(*res) = '\0'; } else { *res = xnrealloc(*res, *len + 2, sizeof(char)); } xstrncat(*res, strlen(*res), wordbuf.we_wordv[j], *len + 2); } END: wordfree(&wordbuf); } #endif /* !NO_WORDEXP */ static char * gen_emergency_prompt(void) { static int f = 0; if (f == 0) { f = 1; xerror("%s: %s\n", PROGRAM_NAME, EMERGENCY_PROMPT_MSG); } return savestring(EMERGENCY_PROMPT, sizeof(EMERGENCY_PROMPT) - 1); } static char * gen_stats_str(const int flag) { size_t val = 0; switch (flag) { case STATS_BLK: val = stats.block_dev; break; case STATS_BROKEN_L: val = stats.broken_link; break; case STATS_CAP: val = stats.caps; break; case STATS_CHR: val = stats.char_dev; break; case STATS_DIR: val = stats.dir; break; #ifdef SOLARIS_DOORS case STATS_DOOR: val = stats.door; break; case STATS_PORT: val = stats.port; break; #endif /* SOLARIS_DOORS */ case STATS_EXE: val = stats.exec; break; case STATS_EXTENDED: val = stats.extended; break; case STATS_FIFO: val = stats.fifo; break; case STATS_HIDDEN: val = stats.hidden; break; case STATS_LNK: val = stats.link; break; case STATS_MULTI_L: val = stats.multi_link; break; case STATS_OTHER_W: val = stats.other_writable; break; case STATS_REG: val = stats.reg; break; case STATS_SUID: val = stats.suid; break; case STATS_SGID: val = stats.sgid; break; case STATS_SOCK: val = stats.socket; break; case STATS_STICKY: val = stats.sticky; break; case STATS_UNKNOWN: val = stats.unknown; break; case STATS_UNSTAT: val = stats.unstat; break; case STATS_NON_DIR: val = stats.reg + stats.block_dev + stats.char_dev + stats.socket + stats.fifo; break; default: break; } char *p = (char *)NULL; if (val != 0) { p = xnmalloc(MAX_INT_STR, sizeof(char)); snprintf(p, MAX_INT_STR, "%zu", val); } else { p = xnmalloc(2, sizeof(char)); *p = '-'; p[1] = '\0'; } return p; } static size_t count_autocmd_matches(void) { if (autocmds_n == 0) return 0; size_t c = 0; ssize_t i = (ssize_t)autocmds_n; while (--i >= 0) c += (autocmds[i].match == 1); return c; } static char * gen_notification(const int flag) { const size_t len = MAX_INT_STR + 2; char *p = xnmalloc(len, sizeof(char)); *p = '\0'; switch (flag) { case NOTIF_AUTOCMD: if (count_autocmd_matches() > 0) { *p = 'A'; p[1] = '\0'; } break; case NOTIF_ERROR: if (msgs.error > 0) snprintf(p, len, "E%zu", msgs.error); break; case NOTIF_NOTICE: if (msgs.notice > 0) snprintf(p, len, "N%zu", msgs.notice); break; case NOTIF_WARNING: if (msgs.warning > 0) snprintf(p, len, "W%zu", msgs.warning); break; case NOTIF_ROOT: if (user.uid == 0) { *p = 'R'; p[1] = '\0'; } break; case NOTIF_SEL: if (sel_n > 0) snprintf(p, len, "%c%zu", SELFILE_CHR, sel_n); break; case NOTIF_TRASH: if (trash_n > 0) snprintf(p, len, "T%zu", trash_n); break; default: break; } return p; } static char * gen_nesting_level(const int mode) { char *p = (char *)NULL; if (mode == 'i') { p = xnmalloc(MAX_INT_STR, sizeof(char)); snprintf(p, MAX_INT_STR, "%d", nesting_level); return p; } /* I == full mode (nothing if first level) */ if (nesting_level <= 1) { p = xnmalloc(1, sizeof(char)); *p = '\0'; return p; } const size_t len = MAX_INT_STR + 3; p = xnmalloc(len, sizeof(char)); snprintf(p, len, "(%d)", nesting_level); return p; } static const char * get_color_attribute(const char *line) { if (!line || !line[0] || line[1] != ':') return (char *)NULL; switch (line[0]) { case 'b': return "1;"; /* Bold */ case 'd': return "2;"; /* Dim */ case 'i': return "3;"; /* Italic */ case 'n': return "0;"; /* Normal/reset */ case 'r': return "7;"; /* Reverse */ case 's': return "9;"; /* Strikethrough */ case 'u': return "4;"; /* Underline */ case 'B': /* fallthrough */ case 'D': return "22;"; /* Disable bold/dim: normal intensity */ case 'I': return "23;"; /* Disable italic */ case 'R': return "27;"; /* Disable reverse */ case 'S': return "29;"; /* Disable strikethrough */ case 'U': return "24;"; /* Disable underline */ case 'K': return "49;"; /* Disable background (terminal default) */ case 'N': return "39;"; /* Disable foreground (terminal default) */ default: return (char *)NULL; } } /* Return 1 if the string S is valid hex color, or 0 otherwise. */ static int is_valid_hex(const char *s) { if (!s || !*s) return 0; size_t i; for (i = 0; s[i]; i++) { if (!IS_HEX_DIGIT(s[i])) return 0; } return (i == 3 || i == 6); } /* Convert a color notation ("%{color}") into an actual color escape * sequence. Return this latter on success or NULL on error (invalid * color notation). */ char * gen_color(char **line) { if (!*line || !*(*line)) return (char *)NULL; /* At this point LINE is "{color}" */ char *l = (*line) + 1; /* L is now "color}" */ const int bg = (l[0] == 'k' && l[1] == ':' && l[2]); const char *attr = bg == 0 ? get_color_attribute(l) : (char *)NULL; if (bg == 1 || attr) l += 2; /* Remove background/attribute prefix ("x:") */ /* Is color bright? */ const int br = (l[0] == 'b' && l[1] == 'r' && l[2]); if (br == 1) l += 2; /* Disable attribute? */ const int attr_off = (l[0] == 'n' && l[1] == 'o' && l[2]); if (attr_off == 1) l += 2; char *p = strchr(l, '}'); if (!p) return (char *)NULL; *p = '\0'; /* Remove trailing '}': now we have "color" */ #define C_START RL_PROMPT_START_IGNORE #define C_END RL_PROMPT_END_IGNORE #define C_ESC 0x1b #define C_LEN 25 /* 25 == max color length (rgb) */ #define GEN_COLOR(s1, s2) (snprintf(temp, C_LEN, "%c%c[%s%sm%c", C_START, \ C_ESC, attr ? attr : "", bg == 1 ? (s1) : (s2), C_END)); #define GEN_ATTR(s) (snprintf(temp, C_LEN, "%c%c[%s%sm%c", C_START, C_ESC, \ attr ? attr : "", (s), C_END)) char *temp = xnmalloc(C_LEN, sizeof(char)); int n = -1; /* 'bold' and 'blue' are used more often than 'black': check them first. */ if (l[0] == 'b' && strcmp(l, "bold") == 0) { GEN_ATTR(attr_off ? "22" : "1"); } else if (l[0] == 'b' && strcmp(l, "blue") == 0) { GEN_COLOR(br ? "104" : "44", br ? "94" : "34"); } else if (l[0] == 'b' && strcmp(l, "black") == 0) { GEN_COLOR(br ? "100" : "40", br ? "90" : "30"); /* 'reset' is used more often than 'red' and 'reverse': check it first. */ } else if (l[0] == 'r' && strcmp(l, "reset") == 0) { GEN_ATTR("0"); } else if (l[0] == 'r' && strcmp(l, "red") == 0) { GEN_COLOR(br ? "101" : "41", br ? "91" : "31"); } else if (l[0] == 'r' && strcmp(l, "reverse") == 0) { GEN_ATTR(attr_off ? "27" : "7"); } else if (l[0] == 'g' && strcmp(l, "green") == 0) { GEN_COLOR(br ? "102" : "42", br ? "92" : "32"); } else if (l[0] == 'y' && strcmp(l, "yellow") == 0) { GEN_COLOR(br ? "103" : "43", br ? "93" : "33"); } else if (l[0] == 'm' && strcmp(l, "magenta") == 0) { GEN_COLOR(br ? "105" : "45", br ? "95" : "35"); } else if (l[0] == 'c' && strcmp(l, "cyan") == 0) { GEN_COLOR(br ? "106" : "46", br ? "96" : "36"); } else if (l[0] == 'w' && strcmp(l, "white") == 0) { GEN_COLOR(br ? "107" : "47", br ? "97" : "37"); } else if (l[0] == 'd' && strcmp(l, "dim") == 0) { GEN_ATTR(attr_off ? "22" : "2"); } else if (l[0] == 'i' && strcmp(l, "italic") == 0) { GEN_ATTR(attr_off ? "23" : "3"); } else if (l[0] == 'u' && strcmp(l, "underline") == 0) { GEN_ATTR(attr_off ? "24" : "4"); } else if (l[0] == 's' && strcmp(l, "strike") == 0) { GEN_ATTR(attr_off ? "29" : "9"); } else if (l[0] == 'f' && l[1] == 'g' && strcmp(l + 2, "reset") == 0) { GEN_ATTR("39"); } else if (l[0] == 'b' && l[1] == 'g' && strcmp(l + 2, "reset") == 0) { GEN_ATTR("49"); } else if (IS_DIGIT(l[0]) && (!l[1] || (is_number(l + 1) && (n = atoi(l)) <= 255))) { if (!l[1]) n = l[0] - '0'; snprintf(temp, C_LEN, "%c%c[%s%s;5;%dm%c", C_START, C_ESC, attr ? attr : "", bg == 1 ? "48" : "38", n, C_END); } else if (l[0] == '#' && is_valid_hex(l + 1)) { /* Fallback values in case get_rgb() returns prematurely (error) */ int a = -1, r = 100, g = 100, b = 100; get_rgb(l + 1, &a, &r, &g, &b); snprintf(temp, C_LEN, "%c%c[%s%s;2;%d;%d;%dm%c", C_START, C_ESC, attr ? attr : "", bg == 1 ? "48" : "38", r, g, b, C_END); } else { *p = '}'; /* Restore the trailing '}' */ free(temp); return (char *)NULL; } *p = '}'; /* Restore the trailing '}' */ *line = p; /* Set LINE to the end of the color notation */ return temp; #undef GEN_COLOR #undef GEN_ATTR #undef C_START #undef C_END #undef C_ESC #undef C_LEN } #ifndef NO_WORDEXP static char * check_mod_paths_cache(const char *name) { size_t i = 0; static int init = 0; if (init == 0) { /* Initialize the cache */ init = 1; for (i = 0; i < MAX_PMOD_PATHS; i++) { p_mod_paths[i].path[0] = '\0'; p_mod_paths[i].name = (char *)NULL; } } for (i = 0; i < MAX_PMOD_PATHS && p_mod_paths[i].name; i++) { if (*name == *p_mod_paths[i].name && strcmp(name + 1, p_mod_paths[i].name + 1) == 0) return &p_mod_paths[i].path[0]; } return (char *)NULL; } static void cache_pmod_path(const char *mod_path) { if (!mod_path || !*mod_path || p_mod_paths_n == MAX_PMOD_PATHS) return; xstrsncpy(p_mod_paths[p_mod_paths_n].path, mod_path, strlen(mod_path) + 1); char *p = strrchr(p_mod_paths[p_mod_paths_n].path, '/'); if (p && p[1]) p_mod_paths[p_mod_paths_n].name = p + 1; p_mod_paths_n++; } static char * get_prompt_module_path(const char *name) { char *cached_path = check_mod_paths_cache(name); if (cached_path) return cached_path; struct stat a; static char m_path[PATH_MAX]; if (plugins_dir && *plugins_dir) { snprintf(m_path, sizeof(m_path), "%s/%s", plugins_dir, name); if (stat(m_path, &a) != -1) { cache_pmod_path(m_path); return &m_path[0]; } } if (data_dir && *data_dir) { snprintf(m_path, sizeof(m_path), "%s/%s/plugins/%s", data_dir, PROGRAM_NAME, name); if (stat(m_path, &a) != -1) { cache_pmod_path(m_path); return &m_path[0]; } } return (char *)NULL; } static void run_prompt_module(char **line, char **res, size_t *len) { char *p = strchr(*line, '}'); if (!p) return; *p = '\0'; const char *p_path = get_prompt_module_path(*line + 1); if (p_path) { char cmd[PATH_MAX + 3]; snprintf(cmd, sizeof(cmd), "(%s)", p_path); char *ptr = &cmd[0]; substitute_cmd(&ptr, res, len); } *p = '}'; *line = p + 1; } #endif /* !NO_WORDEXP */ static char * gen_last_cmd_time(char **line) { if (last_cmd_time < (double)conf.prompt_b_min) goto END; const int precision = conf.prompt_b_precision; const int len = snprintf(NULL, 0, "%.*f", precision, last_cmd_time); if (len < 0) goto END; char *temp = xnmalloc((size_t)len + 1, sizeof(char)); snprintf(temp, (size_t)len + 1, "%.*f", precision, last_cmd_time); return temp; END: (*line)++; return (char *)NULL; } static char * gen_cwd_perms(void) { struct stat a; if (!workspaces || !workspaces[cur_ws].path || stat(workspaces[cur_ws].path, &a) == -1) return savestring(UNKNOWN_STR, sizeof(UNKNOWN_STR) - 1); char *buf = xnmalloc(5, sizeof(char)); snprintf(buf, 5, "%04o", a.st_mode & 07777); return buf; } /* Decode the prompt string (encoded_prompt global variable) taken from * the configuration file. */ char * decode_prompt(char *line) { if (!line) return (char *)NULL; char *temp = (char *)NULL; char *result = (char *)NULL; size_t result_len = 0; int c; while ((c = (int)*line++)) { /* Color notation: "%{color}" */ if (c == '%' && *line == '{' && line[1]) { temp = gen_color(&line); if (temp) add_string(&temp, c, &line, &result, &result_len); } /* We have an escape char */ else if (c == '\\') { /* Now move on to the next char */ c = (int)*line; switch (c) { /* File statistics */ case 'B': temp = gen_stats_str(STATS_BLK); goto ADD_STRING; case 'C': temp = gen_stats_str(STATS_CHR); goto ADD_STRING; case 'D': temp = gen_stats_str(STATS_DIR); goto ADD_STRING; case 'E': temp = gen_stats_str(STATS_EXTENDED); goto ADD_STRING; case 'F': temp = gen_stats_str(STATS_FIFO); goto ADD_STRING; case 'G': temp = gen_stats_str(STATS_SGID); goto ADD_STRING; case 'K': temp = gen_stats_str(STATS_SOCK); goto ADD_STRING; case 'L': temp = gen_stats_str(STATS_LNK); goto ADD_STRING; case 'M': temp = gen_stats_str(STATS_MULTI_L); goto ADD_STRING; case 'o': temp = gen_stats_str(STATS_BROKEN_L); goto ADD_STRING; case 'O': temp = gen_stats_str(STATS_OTHER_W); goto ADD_STRING; case 'Q': temp = gen_stats_str(STATS_NON_DIR); goto ADD_STRING; case 'R': temp = gen_stats_str(STATS_REG); goto ADD_STRING; case 'U': temp = gen_stats_str(STATS_SUID); goto ADD_STRING; case 'x': temp = gen_stats_str(STATS_CAP); goto ADD_STRING; case 'X': temp = gen_stats_str(STATS_EXE); goto ADD_STRING; case '.': temp = gen_stats_str(STATS_HIDDEN); goto ADD_STRING; case '"': temp = gen_stats_str(STATS_STICKY); goto ADD_STRING; case '?': temp = gen_stats_str(STATS_UNKNOWN); goto ADD_STRING; case '!': temp = gen_stats_str(STATS_UNSTAT); goto ADD_STRING; #ifdef SOLARIS_DOORS case '>': temp = gen_stats_str(STATS_DOOR); goto ADD_STRING; case '<': temp = gen_stats_str(STATS_PORT); goto ADD_STRING; #endif /* SOLARIS_DOORS */ case '*': temp = gen_notification(NOTIF_SEL); goto ADD_STRING; case '%': temp = gen_notification(NOTIF_TRASH); goto ADD_STRING; case '#': temp = gen_notification(NOTIF_ROOT); goto ADD_STRING; case ')': temp = gen_notification(NOTIF_WARNING); goto ADD_STRING; case '(': temp = gen_notification(NOTIF_ERROR); goto ADD_STRING; case '=': temp = gen_notification(NOTIF_NOTICE); goto ADD_STRING; case 'v': temp = gen_rl_vi_mode(1); goto ADD_STRING; case 'y': temp = gen_notification(NOTIF_AUTOCMD); goto ADD_STRING; case 'z': /* Exit status of last executed command */ temp = gen_exit_status(); goto ADD_STRING; case 'e': /* Escape char */ temp = gen_escape_char(&line, &c); goto ADD_STRING; case 'j': temp = gen_cwd_perms(); goto ADD_STRING; case '0': /* fallthrough */ /* Octal char */ case '1': /* fallthrough */ case '2': /* fallthrough */ case '3': /* fallthrough */ case '4': /* fallthrough */ case '5': /* fallthrough */ case '6': /* fallthrough */ case '7': temp = gen_octal(&line, &c); goto ADD_STRING; case 'c': /* Program name */ temp = savestring(PROGRAM_NAME, sizeof(PROGRAM_NAME) - 1); goto ADD_STRING; case 'b': temp = gen_last_cmd_time(&line); goto ADD_STRING; case 'P': /* Current profile name */ temp = gen_profile(); goto ADD_STRING; case 't': /* fallthrough */ /* Time: 24-hour HH:MM:SS format */ case 'T': /* fallthrough */ /* 12-hour HH:MM:SS format */ case 'A': /* fallthrough */ /* 24-hour HH:MM format */ case '@': /* fallthrough */ /* 12-hour HH:MM:SS am/pm format */ case 'd': /* Date: abrev_weak_day, abrev_month_day month_num */ temp = gen_time(c); goto ADD_STRING; case 'u': /* User name */ temp = gen_user_name(); goto ADD_STRING; case 'g': temp = gen_sort_name(); goto ADD_STRING; case 'h': /* fallthrough */ /* Hostname up to first '.' */ case 'H': /* Full hostname */ temp = gen_hostname(c); goto ADD_STRING; case 'i': /* fallthrough */ /* Nest level (number only) */ case 'I': /* Nest level (full format) */ temp = gen_nesting_level(c); goto ADD_STRING; case 's': /* Shell name (after last slash)*/ if (!user.shell) { line++; break; } temp = gen_shell_name(); goto ADD_STRING; case 'S': /* Current workspace */ temp = gen_workspace(); goto ADD_STRING; case 'l': /* Current mode */ temp = gen_mode(); goto ADD_STRING; case 'p': /* fallthrough */ /* Abbreviated if longer than PathMax */ case 'f': /* fallthrough */ /* Abbreviated, fish-like */ case 'w': /* fallthrough */ /* Full PWD */ case 'W': /* Short PWD */ if (!workspaces[cur_ws].path) { line++; break; } temp = gen_pwd(c); goto ADD_STRING; case '$': /* '$' or '#' for normal and root user */ temp = gen_user_flag(); goto ADD_STRING; case 'a': /* fallthrough */ /* Bell character */ case 'r': /* fallthrough */ /* Carriage return */ case 'n': /* fallthrough */ /* New line char */ temp = gen_misc(c); goto ADD_STRING; case '[': /* fallthrough */ /* Begin a sequence of non-printing characters */ case ']': /* End the sequence */ temp = gen_non_print_sequence(c); goto ADD_STRING; case '\\': /* Literal backslash */ temp = savestring("\\", 1); goto ADD_STRING; default: temp = savestring("\\ ", 2); temp[1] = (char)c; ADD_STRING: add_string(&temp, c, &line, &result, &result_len); break; } } /* If not an escape code, check for command substitution, and if not, * just add whatever char is there. */ else { /* Remove non-escaped quotes */ if (c == '\'' || c == '"') continue; #ifndef NO_WORDEXP /* Command substitution */ if (c == '$' && *line == '(') { substitute_cmd(&line, &result, &result_len); continue; } if (c == '$' && *line == '{') { run_prompt_module(&line, &result, &result_len); continue; } #endif /* !NO_WORDEXP */ const size_t new_len = result_len + 2 + (wrong_cmd ? (MAX_COLOR + 6) : 0); result = xnrealloc(result, new_len, sizeof(char)); result[result_len] = (char)c; result_len++; result[result_len] = '\0'; } } /* Remove trailing new line char, if any */ if (result && result_len > 0 && result[result_len - 1] == '\n') result[result_len - 1] = '\0'; /* Emergency prompt, just in case something went wrong */ if (!result) result = gen_emergency_prompt(); return result; } /* Make sure CWD exists; if not, go up to the parent, and so on */ static void check_cwd(void) { int cwd_change = 0; while (xchdir(workspaces[cur_ws].path, SET_TITLE) != FUNC_SUCCESS) { char *ret = strrchr(workspaces[cur_ws].path, '/'); if (ret && ret != workspaces[cur_ws].path) { *ret = '\0'; cwd_change = 1; } else { break; } } if (cwd_change == 1 && conf.autols == 1) refresh_screen(); } /* Remove all final slash(es) from path, if any */ static void trim_final_slashes(void) { const size_t path_len = strlen(workspaces[cur_ws].path); for (size_t i = path_len - 1; workspaces[cur_ws].path[i] && i > 0; i--) { if (workspaces[cur_ws].path[i] != '/') break; else workspaces[cur_ws].path[i] = '\0'; } } static void print_user_message(void) { char *s = conf.welcome_message_str; if (!strchr(s, '\\')) { printf("%s%s%s\n", wc_c, s, df_c); return; } int c = 0; char *tmp = (char *)NULL; fputs(wc_c, stdout); while (*s) { if (*s == '\\' && *(s + 1)) { s++; if (*s >= '0' && *s <= '7' && (tmp = gen_octal(&s, &c))) { /* NOLINT */ fputs(tmp, stdout); free(tmp); } else if (*s == 'e' && (tmp = gen_escape_char(&s, &c))) { fputs(tmp, stdout); free(tmp); } else if (*s == 'n') { putchar('\n'); s++; } else { putchar(*s); s++; } } else { putchar(*s); s++; } } putchar('\n'); fputs(df_c, stdout); } static void print_welcome_msg(void) { static int message_shown = 0; if (message_shown == 1 || conf.welcome_message == 0) return; if (conf.welcome_message_str != NULL) print_user_message(); else printf("%s%s\n%s", wc_c, DEF_WELCOME_MESSAGE_STR, df_c); printf("%s\n", _(HELP_MESSAGE)); message_shown = 1; } static void print_tips_func(void) { if (conf.tips == 0) return; static int first_run = 1; if (first_run == 1) { print_tips(0); first_run = 0; } } static void run_prompt_cmds(void) { if (conf.ext_cmd_ok == 0 || prompt_cmds_n == 0) return; const int tflags = flags; flags &= ~DELAYED_REFRESH; for (size_t i = 0; i < prompt_cmds_n; i++) { if (xargs.secure_cmds == 0 || sanitize_cmd(prompt_cmds[i], SNT_PROMPT) == FUNC_SUCCESS) launch_execl(prompt_cmds[i]); } flags = tflags; } #ifndef _NO_TRASH static void update_trash_indicator(void) { static time_t trash_files_dir_mtime = 0; if (trash_ok == 0) return; struct stat a; if (stat(trash_files_dir, &a) == -1) return; if (trash_files_dir_mtime == a.st_mtime) return; trash_files_dir_mtime = a.st_mtime; const filesn_t n = count_dir(trash_files_dir, NO_CPOP); trash_n = n <= 2 ? 0 : (size_t)n - 2; } #endif /* !_NO_TRASH */ static void setenv_prompt(void) { if (prompt_notif == 1) return; /* Set environment variables with clifm state information * (sel files, trash, stealth mode, messages, workspace, and last exit * code) to be handled by the prompt itself. */ setenv("CLIFM_STAT_SEL", xitoa((long long)sel_n), 1); #ifndef _NO_TRASH setenv("CLIFM_STAT_TRASH", xitoa((long long)trash_n), 1); #endif /* !_NO_TRASH */ setenv("CLIFM_STAT_ERROR_MSGS", xitoa((long long)msgs.error), 1); setenv("CLIFM_STAT_WARNING_MSGS", xitoa((long long)msgs.warning), 1); setenv("CLIFM_STAT_NOTICE_MSGS", xitoa((long long)msgs.notice), 1); setenv("CLIFM_STAT_WS", xitoa((long long)cur_ws + 1), 1); setenv("CLIFM_STAT_EXIT", xitoa((long long)exit_code), 1); setenv("CLIFM_STAT_ROOT", user.uid == 0 ? "1" : "0", 1); setenv("CLIFM_STAT_STEALTH", (xargs.stealth_mode == 1) ? "1" : "0", 1); } static size_t set_prompt_length(const size_t decoded_prompt_len, const size_t ac_matches) { size_t len = 0; if (prompt_notif == 1) { len = (size_t)(decoded_prompt_len + (ac_matches > 0 ? N_IND : 0) + (xargs.stealth_mode == 1 ? STEALTH_IND_SIZE : 0) + (user.uid == 0 ? ROOT_IND_SIZE : 0) + (conf.readonly == 1 ? RDONLY_IND_SIZE : 0) + (sel_n > 0 ? N_IND : 0) + (trash_n > 0 ? N_IND : 0) + (msgs.error > 0 ? N_IND : 0) + (msgs.warning > 0 ? N_IND : 0) + (msgs.notice > 0 ? N_IND : 0) + 6 + sizeof(tx_c) + 1 + 2); } else { len = (size_t)(decoded_prompt_len + 6 + sizeof(tx_c) + 1); } return len; } static char * construct_prompt(const char *decoded_prompt) { char *rl_vi_mode = (char *)NULL; /* Construct indicators: MSGS (ERR, WARN, and NOTICE), SEL, and TRASH */ char err_ind[N_IND], warn_ind[N_IND], notice_ind[N_IND], trash_ind[N_IND], sel_ind[N_IND], acmd_ind[N_IND]; *err_ind = *warn_ind = *notice_ind = *trash_ind = *sel_ind = '\0'; *acmd_ind = '\0'; size_t ac_matches = 0; if (prompt_notif == 1) { if (rl_editing_mode == RL_VI_MODE) rl_vi_mode = gen_rl_vi_mode(0); if (conf.autocmd_msg == AUTOCMD_MSG_PROMPT && (ac_matches = count_autocmd_matches()) > 0) snprintf(acmd_ind, N_IND, "%sA%s", ac_c, RL_NC); if (msgs.error > 0) snprintf(err_ind, N_IND, "%sE%zu%s", em_c, msgs.error, RL_NC); if (msgs.warning > 0) snprintf(warn_ind, N_IND, "%sW%zu%s", wm_c, msgs.warning, RL_NC); if (msgs.notice > 0) snprintf(notice_ind, N_IND, "%sN%zu%s", nm_c, msgs.notice, RL_NC); if (trash_n > 0) snprintf(trash_ind, N_IND, "%sT%zu%s", ti_c, trash_n, RL_NC); if (sel_n > 0) snprintf(sel_ind, N_IND, "%s%c%zu%s", li_c, SELFILE_CHR, sel_n, RL_NC); } const size_t prompt_len = (rl_vi_mode ? strlen(rl_vi_mode) : 0) + set_prompt_length(strlen(decoded_prompt), ac_matches); char *the_prompt = xnmalloc(prompt_len, sizeof(char)); if (prompt_notif == 1) { snprintf(the_prompt, prompt_len, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s\001%s\002", rl_vi_mode ? rl_vi_mode : "", ac_matches > 0 ? acmd_ind : "", (user.uid == 0) ? (conf.colorize == 1 ? ROOT_IND : ROOT_IND_NO_COLOR) : "", (conf.readonly == 1) ? ro_c : "", (conf.readonly == 1) ? RDONLY_IND : "", (msgs.error > 0) ? err_ind : "", (msgs.warning > 0) ? warn_ind : "", (msgs.notice > 0) ? notice_ind : "", (xargs.stealth_mode == 1) ? si_c : "", (xargs.stealth_mode == 1) ? STEALTH_IND : "", (trash_n > 0) ? trash_ind : "", (sel_n > 0) ? sel_ind : "", decoded_prompt, RL_NC, tx_c); } else { snprintf(the_prompt, prompt_len, "%s%s\001%s\002", decoded_prompt, RL_NC, tx_c); } return the_prompt; } static void print_prompt_messages(void) { for (size_t i = 0; i < msgs_n; i++) { if (messages[i].read == 1) continue; fputs(messages[i].text, stderr); messages[i].read = 1; } print_msg = 0; } static void initialize_prompt_data(const int prompt_flag) { check_cwd(); trim_final_slashes(); print_welcome_msg(); print_tips_func(); /* If autols is disabled, and since terminal dimensions are gathered * in list_dir() via get_term_size(), let's get terminal dimensions * here. We need them to print suggestions. */ if (conf.autols == 0 && conf.suggestions == 1) get_term_size(); /* Set foreground color to default. */ fputs(df_c, stdout); fflush(stdout); /* If just updating the prompt, there's no need to run prompt commands. */ if (prompt_flag != PROMPT_UPDATE) run_prompt_cmds(); #ifndef _NO_TRASH update_trash_indicator(); #endif /* !_NO_TRASH */ get_sel_files(); setenv_prompt(); args_n = 0; curhistindex = current_hist_n; #ifndef _NO_SUGGESTIONS if (wrong_cmd == 1) { rl_delete_text(0, rl_end); rl_point = rl_end = 0; recover_from_wrong_cmd(); } #endif /* !_NO_SUGGESTIONS */ if (print_msg == 1 && msgs_n > 0) print_prompt_messages(); } static void log_and_record(char *input) { if (conf.log_cmds == 1) { free(last_cmd); last_cmd = savestring(input, strlen(input)); log_cmd(); } if (record_cmd(input) == 1) add_to_cmdhist(input); } /* UTF-8 version of get_prompt_len(). */ static int get_rprompt_len_utf8(char *rprompt) { if (!rprompt || !*rprompt) return 0; char *nl = strchr(rprompt, '\n'); if (nl) *nl = '\0'; static wchar_t buf[NAME_MAX]; *buf = L'\0'; if (mbstowcs(buf, rprompt, NAME_MAX) == (size_t)-1) return 0; size_t i = 0; int len = 0; while (buf[i]) { if (buf[i] == '\x1b' && buf[i + 1] == '[') { wchar_t *tmp = wcschr(buf + i + 1, L'm'); if (tmp) i += (size_t)(tmp - (buf + i) + 1); } else if (buf[i] == 001) { wchar_t *tmp = wcschr(buf + i, L'\002'); if (tmp) i += (size_t)(tmp - (buf + i) + 1); } else { len += wcwidth(buf[i]); i++; } } return len; } /* Return the printable length of the string RPROMPT. Zero is returned on error. */ static int get_rprompt_len(char *rprompt) { char *p = rprompt; while (*p) { if (IS_UTF8_CHAR(*p)) return get_rprompt_len_utf8(rprompt); p++; } p = rprompt; int len = 0; while (*p) { if (*p == '\n') { *p = '\0'; break; } else if (*p == '\x1b' && p[1] == '[') { char *tmp = strchr(p, 'm'); if (tmp) p = tmp + 1; } else if (*p == 001) { char *tmp = strchr(p, '\002'); if (tmp) p = tmp + 1; } else { len++; p++; } } return len; } static void print_right_prompt(void) { char *rprompt = decode_prompt(conf.rprompt_str); const int len = rprompt ? get_rprompt_len(rprompt) : 0; if (len <= 0 || len >= term_cols) { free(rprompt); return; } MOVE_CURSOR_RIGHT(term_cols); MOVE_CURSOR_LEFT(len); fputs(rprompt, stdout); MOVE_CURSOR_LEFT(term_cols); free(rprompt); } /* Some commands take '!' as parameter modifier: quick search, 'filter', * and 'sel', in which case history expansion must not be performed. * Return 1 if we have one of these commands or 0 otherwise. */ static int exclude_from_history(const char *s) { if (*s == '/' || (*s == 's' && (s[1] == ' ' || strncmp(s + 1, "el ", 3) == 0)) || (*s == 'f' && ((s[1] == 't' && s[2] == ' ') || strncmp(s + 1, "ilter ", 6) == 0)) || (*s == 'd' && s[1] == 'h' && s[2] == ' ') || (*s == 'b' && s[1] == ' ')) return 1; return 0; } /* Replace history expressions ("!*") in the string INPUT by the corresponding * history entry. */ static int expand_history(char **input) { /* history_expansion_char defaults to '!' */ char *hist_c = strchr(*input, history_expansion_char); if (!hist_c || (hist_c != *input && *(hist_c - 1) != ' ') || exclude_from_history(*input) == 1) return FUNC_SUCCESS; char *exp_input = (char *)NULL; const int ret = history_expand(*input, &exp_input); if (ret == -1) { /* Error in expansion */ xerror("%s: %s\n", PROGRAM_NAME, exp_input); free(*input); free(exp_input); return FUNC_FAILURE; } if (ret == 0) { /* No expansion took place */ free(exp_input); return FUNC_SUCCESS; } printf("%s\n", exp_input); free(*input); if (ret == 2) { /* Display but do not execute the expanded command (:p) */ free(exp_input); return (-1); } /* (ret == 1) Display and execute */ *input = exp_input; return FUNC_SUCCESS; } static char * handle_empty_line(const int screen_refresh) { if (conf.autols == 1 && ((flags & DELAYED_REFRESH) || xargs.refresh_on_empty_line == 1) && screen_refresh == PROMPT_SCREEN_REFRESH && g_prompt_ignore_empty_line == 0) refresh_screen(); g_prompt_ignore_empty_line = 0; flags &= ~DELAYED_REFRESH; return (char *)NULL; } /* Print the prompt and return the string entered by the user, to be * parsed later by parse_input_str() */ char * prompt(const int prompt_flag, const int screen_refresh) { initialize_prompt_data(prompt_flag); /* Generate the prompt string using the prompt line in the config * file (stored in encoded_prompt at startup). */ char *decoded_prompt = decode_prompt(conf.encoded_prompt); char *the_prompt = construct_prompt(decoded_prompt ? decoded_prompt : EMERGENCY_PROMPT); free(decoded_prompt); if (conf.rprompt_str && *conf.rprompt_str && conf.prompt_is_multiline == 1 && term_caps.suggestions == 1) print_right_prompt(); if (prompt_flag == PROMPT_UPDATE || prompt_flag == PROMPT_UPDATE_RUN_CMDS) { rl_set_prompt(the_prompt); free(the_prompt); return (char *)NULL; } /* Tell my_rl_getc() (readline.c) to recalculate the length * of the last prompt line, needed to calculate the finder's offset * and the current cursor column. This length might vary if the * prompt contains dynamic values. */ prompt_offset = UNSET; UNHIDE_CURSOR; /* Print the prompt and get user input */ char *input = readline(the_prompt); free(the_prompt); if (!input || !*input || rl_end == 0) { free(input); return handle_empty_line(screen_refresh); } g_prompt_ignore_empty_line = 0; flags &= ~DELAYED_REFRESH; if (expand_history(&input) != FUNC_SUCCESS) return (char *)NULL; log_and_record(input); return input; } static int list_prompts(void) { if (prompts_n == 0) { puts(_("prompt: No extra prompts found. Using the default prompt.")); return FUNC_SUCCESS; } const char *ptr = SET_MISC_PTR; for (size_t i = 0; i < prompts_n; i++) { if (!prompts[i].name) continue; if (*cur_prompt_name == *prompts[i].name && strcmp(cur_prompt_name, prompts[i].name) == 0) printf("%s%s%s %s\n", mi_c, ptr, df_c, prompts[i].name); else printf(" %s\n", prompts[i].name); } return FUNC_SUCCESS; } static int switch_prompt(const size_t n) { free(conf.encoded_prompt); free(conf.wprompt_str); free(conf.rprompt_str); conf.encoded_prompt = conf.wprompt_str = conf.rprompt_str = (char *)NULL; if (prompts[n].regular) conf.encoded_prompt = savestring(prompts[n].regular, strlen(prompts[n].regular)); if (prompts[n].warning) conf.wprompt_str = savestring(prompts[n].warning, strlen(prompts[n].warning)); if (prompts[n].right) { conf.rprompt_str = savestring(prompts[n].right, strlen(prompts[n].right)); conf.prompt_is_multiline = prompts[n].multiline; } prompt_notif = prompts[n].notifications; set_prompt_options(); if (xargs.warning_prompt == 0) return FUNC_SUCCESS; conf.warning_prompt = prompts[n].warning_prompt_enabled; update_warning_prompt_text_color(); return FUNC_SUCCESS; } static int set_prompt(char *name) { if (!name || !*name) return FUNC_FAILURE; if (prompts_n == 0) { xerror("%s\n", _("prompt: No extra prompts defined. Using the " "default prompt")); return FUNC_FAILURE; } char *p = unescape_str(name, 0); if (!p) { xerror(_("prompt: %s: Error unescaping string\n"), name); return FUNC_FAILURE; } int i = (int)prompts_n; while (--i >= 0) { if (*p != *prompts[i].name || strcmp(p, prompts[i].name) != 0) continue; free(p); xstrsncpy(cur_prompt_name, prompts[i].name, sizeof(cur_prompt_name)); return switch_prompt((size_t)i); } xerror(_("prompt: %s: No such prompt\n"), p); free(p); return FUNC_FAILURE; } static int set_default_prompt(void) { free(conf.encoded_prompt); conf.encoded_prompt = savestring(DEFAULT_PROMPT, sizeof(DEFAULT_PROMPT) - 1); free(conf.wprompt_str); conf.wprompt_str = savestring(DEF_WPROMPT_STR, sizeof(DEF_WPROMPT_STR) - 1); *cur_prompt_name = '\0'; prompt_notif = DEF_PROMPT_NOTIF; return FUNC_SUCCESS; } /* Read environment variables controlling options for the '\b', '\f', and * '\p' prompt escape codes, and set the appropriate values. */ void set_prompt_options(void) { char *val = (char *)NULL; int n = 0; const char *np = conf.encoded_prompt; /* Normal/Regular prompt */ const char *wp = conf.wprompt_str; /* Warning prompt */ const char *rp = conf.rprompt_str; /* Right prompt */ #define CHECK_PROMPT_OPT(s) ((np && *np && strstr(np, (s)) != NULL) \ || (wp && *wp && strstr(wp, (s)) != NULL) \ || (rp && *rp && strstr(rp, (s)) != NULL)) const int b_is_set = CHECK_PROMPT_OPT("\\b"); const int f_is_set = CHECK_PROMPT_OPT("\\f"); const int p_is_set = CHECK_PROMPT_OPT("\\p"); #undef CHECK_PROMPT_OPT conf.prompt_b_is_set = b_is_set; if (f_is_set == 1) { val = getenv("CLIFM_PROMPT_F_DIR_LEN"); if (val && is_number(val) && (n = atoi(val)) > 0 && n < INT_MAX) conf.prompt_f_dir_len = n; val = getenv("CLIFM_PROMPT_F_FULL_LEN_DIRS"); if (val && is_number(val) && (n = atoi(val)) > 0 && n < INT_MAX) conf.prompt_f_full_len_dirs = n; } if (b_is_set == 1) { val = getenv("CLIFM_PROMPT_B_PRECISION"); if (val && IS_DIGIT(*val) && !val[1]) conf.prompt_b_precision = *val - '0'; val = getenv("CLIFM_PROMPT_B_MIN"); if (val && is_number(val) && (n = atoi(val)) < INT_MAX) conf.prompt_b_min = n; } if (conf.prompt_p_max_path == UNSET && p_is_set == 1) { val = getenv("CLIFM_PROMPT_P_MAX_PATH"); if (val && is_number(val) && (n = atoi(val)) > 0 && n < INT_MAX) conf.prompt_p_max_path = n; } } static int edit_prompts_file(char *app) { if (xargs.stealth_mode == 1) { printf("%s: prompt: %s\n", PROGRAM_NAME, STEALTH_DISABLED); return FUNC_SUCCESS; } if (!prompts_file || !*prompts_file) { xerror("%s\n", _("prompt: Prompts file not found")); return FUNC_FAILURE; } struct stat a; if (stat(prompts_file, &a) == -1) { xerror("prompt: '%s': %s\n", prompts_file, strerror(errno)); return errno; } const time_t old_time = a.st_mtime; int ret = open_config_file(app, prompts_file); if (ret != FUNC_SUCCESS) return ret; if (stat(prompts_file, &a) == -1) { xerror("prompt: '%s': %s\n", prompts_file, strerror(errno)); return errno; } if (old_time == a.st_mtime) return FUNC_SUCCESS; if (conf.autols == 1) reload_dirlist(); ret = load_prompts(); print_reload_msg(NULL, NULL, _("File modified. Prompts reloaded.\n")); if (*cur_prompt_name) set_prompt(cur_prompt_name); return ret; } int prompt_function(char **args) { if (!args[0] || !*args[0] || (*args[0] == 'l' && strcmp(args[0], "list") == 0)) return list_prompts(); if (IS_HELP(args[0])) { puts(PROMPT_USAGE); return FUNC_SUCCESS; } if (*args[0] == 'u' && strcmp(args[0], "unset") == 0) return set_default_prompt(); if (*args[0] == 'e' && strcmp(args[0], "edit") == 0) return edit_prompts_file(args[1]); if (*args[0] == 'r' && strcmp(args[0], "reload") == 0) { const int ret = load_prompts(); if (ret == FUNC_SUCCESS) { printf(_("%s: Prompts successfully reloaded\n"), PROGRAM_NAME); return FUNC_SUCCESS; } return ret; } if (*args[0] == 's' && strcmp(args[0], "set") == 0) return set_prompt(args[1]); return set_prompt(args[0]); } clifm-1.26.3/src/prompt.h000066400000000000000000000071051506632037700151720ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* prompt.h */ #ifndef PROMPT_H #define PROMPT_H /* Mode macros for the prompt() function */ /* First parameter */ #define PROMPT_UPDATE 0 #define PROMPT_SHOW 1 #define PROMPT_UPDATE_RUN_CMDS 2 /* Second parameter */ #define PROMPT_NO_SCREEN_REFRESH 0 #define PROMPT_SCREEN_REFRESH 1 #define CTLESC '\001' #define CTLNUL '\177' #ifdef __HAIKU__ /* No need for a root indicator on Haiku: it always runs as root. */ # define ROOT_IND "" # define ROOT_IND_NO_COLOR "" #else # define ROOT_IND "\001\x1b[1;31m\002R\001\x1b[0m\002" # define ROOT_IND_NO_COLOR "R" #endif /* __HAIKU__ */ #define ROOT_IND_SIZE sizeof(ROOT_IND) #define RDONLY_IND "RO\001\x1b[0m\002" #define RDONLY_IND_SIZE (MAX_COLOR + sizeof(RDONLY_IND)) #define STEALTH_IND "S\001\x1b[0m\002" #define STEALTH_IND_SIZE (MAX_COLOR + sizeof(STEALTH_IND)) #define EMERGENCY_PROMPT_MSG "Error decoding prompt line. Using an \ emergency prompt." #define EMERGENCY_PROMPT "\001\x1b[0m\002> " /* Flag macros to generate files statistic string for the prompt */ #define STATS_DIR 0 #define STATS_REG 1 #define STATS_EXE 2 #define STATS_HIDDEN 3 #define STATS_SUID 4 #define STATS_SGID 5 #define STATS_FIFO 6 #define STATS_SOCK 7 #define STATS_BLK 8 #define STATS_CHR 9 #define STATS_CAP 10 #define STATS_LNK 11 #define STATS_BROKEN_L 12 /* Broken link */ #define STATS_MULTI_L 13 /* Multi-link */ #define STATS_OTHER_W 14 /* Other writable */ #define STATS_STICKY 15 #define STATS_EXTENDED 16 /* Extended attributes (acl) */ #define STATS_UNKNOWN 17 #define STATS_UNSTAT 18 #ifdef SOLARIS_DOORS # define STATS_DOOR 19 # define STATS_PORT 20 #endif /* SOLARIS_DOORS */ #define STATS_NON_DIR 21 #define NOTIF_SEL 0 #define NOTIF_TRASH 1 #define NOTIF_WARNING 2 #define NOTIF_ERROR 3 #define NOTIF_NOTICE 4 #define NOTIF_ROOT 5 #define NOTIF_AUTOCMD 6 #define RL_EMACS_MODE 1 #define RL_VI_MODE 0 #define RL_VI_INS_MODESTR "(ins)" #define RL_VI_INS_MODESTR_LEN (sizeof(RL_VI_INS_MODESTR) - 1) #define RL_VI_CMD_MODESTR "(cmd)" #define RL_VI_CMD_MODESTR_LEN (sizeof(RL_VI_CMD_MODESTR) - 1) /* Size of the indicator for msgs, trash, and sel. */ #define N_IND (MAX_COLOR + 1 + 21 + (sizeof(RL_NC) - 1) + 1) /* Color + 1 letter + plus unsigned integer (20 digits max) * + RL_NC length + nul char. */ /* Set this variable to 1 to prevent an extra screen refresh, for example, * after running a keybinding. See handle_empty_line(). */ extern int g_prompt_ignore_empty_line; __BEGIN_DECLS char *prompt(const int prompt_flag, const int screen_refresh); char *decode_prompt(char *line); int prompt_function(char **args); char *gen_color(char **line); void set_prompt_options(void); __END_DECLS #endif /* PROMPT_H */ clifm-1.26.3/src/properties.c000066400000000000000000001543001506632037700160400ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* properties.c -- Home of the p/pp, pc, oc, and stats commands */ /* These four functions: get_color_size, get_color_size256, get_color_age, * and get_color_age256 are based on https://github.com/leahneukirchen/lr * (licenced MIT) and modified to fit our needs. * All changes are licensed under GPL-2.0-or-later. */ /* get_birthtime() was taken from GNU stat.c, licensed under GPL-3.0-or-later: * All changes are licensed under GPL-2.0-or-later. */ #include "helpers.h" #include #include #include #include #include #include #if defined(__linux__) || defined(__CYGWIN__) # include /* minor(), major() */ #elif defined(__sun) # include /* minor(), major() */ /* For BSD systems, we need sys/types.h, already included in helpers.h */ #endif /* __linux__ || __CYGWIN__ */ #include #ifdef LINUX_FILE_ATTRS # include /* ioctl(2) */ # ifdef __TINYC__ # undef SYNC_FILE_RANGE_WRITE_AND_WAIT /* Silence redefinition error */ # endif /* __TINYC__ */ # include /* FS_IOC_GETFLAGS */ # include "properties.h" /* XFS_?????_FL flags */ #endif /* LINUX_FILE_ATTRS */ #ifdef LINUX_FILE_XATTRS # include #endif /* LINUX_FILE_XATTRS */ #ifdef LINUX_FILE_CAPS # include #endif /* LINUX_FILE_CAPS */ /* Do we have BSD file flags support? */ #ifndef _BE_POSIX # if defined(__FreeBSD__) || (defined(__NetBSD__) && !defined(_NO_NETBSD_FFLAGS)) \ || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__APPLE__) # define HAVE_BSD_FFLAGS # ifdef __NetBSD__ # include /* flags_to_string() */ # define FLAGSTOSTR_FUNC(f) flags_to_string((f), "-") # else # define FLAGSTOSTR_FUNC(f) fflagstostr((f)) /* Provided by unistd.h */ # endif /* __NetBSD__ */ # endif /* BSD */ #endif /* !_BE_POSIX */ #ifndef _BE_POSIX # ifdef __linux__ # if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,46) # define HAVE_ACL # include /* acl_get_file(), acl_get_entry() */ # include /* acl_extended_file_nofollow(), acl_to_any_text() */ # endif /* Linux >= 2.5.46 */ # endif /* __linux__ */ #endif /* !_BE_POSIX */ #include "aux.h" #include "checks.h" /* check_file_access(), is_number() */ #include "colors.h" /* get_dir_color(), get_regfile_color() */ #include "messages.h" # include "mime.h" /* xmagic() */ #include "misc.h" #include "properties.h" #include "readline.h" /* Required by the 'pc' command */ #include "xdu.h" /* dir_info(), dir_size() */ /* A few macros for nano-second precision. * Used to print timestamps with the 'p/pp' command. */ #ifndef CLIFM_LEGACY # define NANO_SEC_MAX 999999999 # if defined(__NetBSD__) || defined(__APPLE__) # define ATIMNSEC st_atimespec.tv_nsec # define CTIMNSEC st_ctimespec.tv_nsec # define MTIMNSEC st_mtimespec.tv_nsec # else # define ATIMNSEC st_atim.tv_nsec # define CTIMNSEC st_ctim.tv_nsec # define MTIMNSEC st_mtim.tv_nsec # endif /* __NetBSD__ || __APPLE__ */ #else /* Let's use any valid value: it won't be used anyway */ # define ATIMNSEC st_atime # define CTIMNSEC st_ctime # define MTIMNSEC st_mtime #endif /* CLIFM_LEGACY */ #ifndef major /* Not defined in Haiku */ # define major(x) ((x >> 8) & 0x7F) #endif /* major */ #ifndef minor /* Not defined in Haiku */ # define minor(x) (x & 0xFF) #endif /* minor */ #if defined(LINUX_FILE_ATTRS) /* Print file attributes as lsattr(1) would. * Bits order as listed by lsattr(1): suSDiadAcEjItTeCxFNPVm * See https://git.kernel.org/pub/scm/fs/ext2/e2fsprogs.git/tree/lib/e2p/pf.c */ static int print_file_attrs(const int aflags) { if (aflags == -1) { puts(_("unavailable")); return FUNC_FAILURE; } const char c = '-'; char bits[23]; bits[0] = (aflags & XFS_SECRM_FL) ? 's' : c; bits[1] = (aflags & XFS_UNRM_FL) ? 'u' : c; bits[2] = (aflags & XFS_SYNC_FL) ? 'S' : c; bits[3] = (aflags & XFS_DIRSYNC_FL) ? 'D' : c; bits[4] = (aflags & XFS_IMMUTABLE_FL) ? 'i' : c; bits[5] = (aflags & XFS_APPEND_FL) ? 'a' : c; bits[6] = (aflags & XFS_NODUMP_FL) ? 'd' : c; bits[7] = (aflags & XFS_NOATIME_FL) ? 'A' : c; bits[8] = (aflags & XFS_COMPR_FL) ? 'c' : c; bits[9] = (aflags & XFS_ENCRYPT_FL) ? 'E' : c; bits[10] = (aflags & XFS_JOURNAL_DATA_FL) ? 'j' : c; bits[11] = (aflags & XFS_INDEX_FL) ? 'I' : c; bits[12] = (aflags & XFS_NOTAIL_FL) ? 't' : c; bits[13] = (aflags & XFS_TOPDIR_FL) ? 'T' : c; bits[14] = (aflags & XFS_EXTENT_FL) ? 'e' : c; bits[15] = (aflags & XFS_NOCOW_FL) ? 'C' : c; bits[16] = (aflags & XFS_DAX_FL) ? 'x' : c; bits[17] = (aflags & XFS_CASEFOLD_FL) ? 'F' : c; bits[18] = (aflags & XFS_INLINE_DATA_FL) ? 'N' : c; bits[19] = (aflags & XFS_PROJINHERIT_FL) ? 'P' : c; bits[20] = (aflags & XFS_VERITY_FL) ? 'V' : c; bits[21] = (aflags & XFS_NOCOMP_FL) ? 'm' : c; bits[22] = '\0'; puts(bits); return FUNC_SUCCESS; } static int get_file_attrs(const char *file) { # if !defined(FS_IOC_GETFLAGS) UNUSED(file); return (-1); # else int attr; const int fd = open(file, O_RDONLY); if (fd == -1) return (-1); const int ret = ioctl(fd, FS_IOC_GETFLAGS, &attr); close(fd); return (ret == -1 ? -1 : attr); # endif /* !FS_IOC_GETFLAGS */ } #endif /* LINUX_FILE_ATTRS */ static char * get_link_color(const char *name) { struct stat a; char *color = no_c; if (lstat(name, &a) == -1) return color; if (S_ISDIR(a.st_mode)) { color = get_dir_color(name, &a, -1); } else { switch (a.st_mode & S_IFMT) { case S_IFLNK: color = stat(name, &a) == -1 ? or_c : ln_c; break; case S_IFSOCK: color = so_c; break; case S_IFIFO: color = pi_c; break; case S_IFBLK: color = bd_c; break; case S_IFCHR: color = cd_c; break; #ifdef SOLARIS_DOORS case S_IFDOOR: color = oo_c; break; case S_IFPORT: color = oo_c; break; #endif /* SOLARIS_DOORS */ case S_IFREG: { size_t ext = 0; color = get_regfile_color(name, &a, &ext); } break; default: color = df_c; break; } } return color; } static struct perms_t set_invalid_file_perms(void) { struct perms_t p = {0}; p.ur = p.uw = p.ux = UNKNOWN_CHR; p.gr = p.gw = p.gx = UNKNOWN_CHR; p.or = p.ow = p.ox = UNKNOWN_CHR; p.cur = p.cuw = p.cux = df_c; p.cgr = p.cgw = p.cgx = df_c; p.cor = p.cow = p.cox = df_c; return p; } /* Returns a struct perms_t with the symbolic value and color for each * properties field of a file with mode MODE */ struct perms_t get_file_perms(const mode_t mode) { struct perms_t p = {0}; if (mode == 0) /* stat(2) err */ return set_invalid_file_perms(); p.cur = p.cuw = p.cux = dn_c; p.cgr = p.cgw = p.cgx = dn_c; p.cor = p.cow = p.cox = dn_c; p.ur = p.uw = p.ux = '-'; p.gr = p.gw = p.gx = '-'; p.or = p.ow = p.ox = '-'; const mode_t val = (mode & (mode_t)~S_IFMT); if (val & S_IRUSR) { p.ur = 'r'; p.cur = dr_c; } if (val & S_IWUSR) { p.uw = 'w'; p.cuw = dw_c; } if (val & S_IXUSR) { p.ux = 'x'; p.cux = S_ISDIR(mode) ? dxd_c : dxr_c; } if (val & S_IRGRP) { p.gr = 'r'; p.cgr = dr_c; } if (val & S_IWGRP) { p.gw = 'w'; p.cgw = dw_c; } if (val & S_IXGRP) { p.gx = 'x'; p.cgx = S_ISDIR(mode) ? dxd_c : dxr_c; } if (val & S_IROTH) { p.or = 'r'; p.cor = dr_c; } if (val & S_IWOTH) { p.ow = 'w'; p.cow = dw_c; } if (val & S_IXOTH) { p.ox = 'x'; p.cox = S_ISDIR(mode) ? dxd_c : dxr_c; } if (mode & S_ISUID) { p.ux = (val & S_IXUSR) ? 's' : 'S'; p.cux = dp_c; } if (mode & S_ISGID) { p.gx = (val & S_IXGRP) ? 's' : 'S'; p.cgx = dp_c; } if (mode & S_ISVTX) { p.ox = (val & S_IXOTH) ? 't' : 'T'; p.cox = dp_c; } if (conf.colorize == 0) { p.cur = p.cuw = p.cux = df_c; p.cgr = p.cgw = p.cgx = df_c; p.cor = p.cow = p.cox = df_c; } return p; } /* Returns FUNC_SUCCESS if the permissions string S (in octal notation) * is a valid permissions string, or FUNC_FAILURE otherwise. */ static int validate_octal_perms(const char *s, const size_t l) { if (l > 4 || l < 3) { xerror(_("pc: %s digits. Either 3 or 4 are " "expected\n"), l > 4 ? _("Too many") : _("Too few")); return FUNC_FAILURE; } size_t i; for (i = 0; s[i]; i++) { if (s[i] < '0' || s[i] > '7') { xerror(_("pc: '%c': Invalid digit. Values in the range 0-7 " "are expected for each field\n"), s[i]); return FUNC_FAILURE; } } return FUNC_SUCCESS; } /* Validate each field of a symbolic permissions string. * Returns FUNC_SUCCESS on success and FUNC_FAILURE on error. */ static int validate_symbolic_perms(const char *s) { size_t i; for (i = 0; i < 9; i++) { switch (i) { case 0: /* fallthrough */ case 3: /* fallthrough */ case 6: if (s[i] != '-' && s[i] != 'r') { xerror(_("pc: Invalid character in field %zu: " "%s-r%s are expected\n"), i + 1, BOLD, NC); return FUNC_FAILURE; } break; case 1: /* fallthrough */ case 4: /* fallthrough */ case 7: if (s[i] != '-' && s[i] != 'w') { xerror(_("pc: Invalid character in field %zu: " "%s-w%s are expected\n"), i + 1, BOLD, NC); return FUNC_FAILURE; } break; case 2: /* fallthrough */ case 5: if (s[i] != '-' && s[i] != 'x' && TOUPPER(s[i]) != 'S') { xerror(_("pc: Invalid character in field %zu: " "%s-xsS%s are expected\n"), i + 1, BOLD, NC); return FUNC_FAILURE; } break; case 8: if (s[i] != '-' && s[i] != 'x' && TOUPPER(s[i]) != 'T') { xerror(_("pc: Invalid character in field %zu: " "%s-xtT%s are expected\n"), i + 1, BOLD, NC); return FUNC_FAILURE; } break; default: return FUNC_FAILURE; } } return FUNC_SUCCESS; } /* Returns FUNC_SUCCESS if the permissions string S is a valid permissions * string, or FUNC_FAILURE otherwise. */ static int validate_new_perms(const char *s) { const size_t l = strlen(s); if (IS_DIGIT(*s)) return validate_octal_perms(s, l); if (l != 9) { xerror(_("pc: %s characters: 9 are expected\n"), l < 9 ? _("Too few") : _("Too many")); return FUNC_FAILURE; } return validate_symbolic_perms(s); } /* Convert permissions in symbolic notation given by S into octal notation * and return it as a string. */ static char * perm2octal(const char *s) { int a, b, c, d; a = b = c = d = 0; if (s[0] != '-') b += 4; if (s[1] != '-') b += 2; if (s[2] != '-' && s[2] != 'S') b += 1; if (s[3] != '-') c += 4; if (s[4] != '-') c += 2; if (s[5] != '-' && s[5] != 'S') c += 1; if (s[6] != '-') d += 4; if (s[7] != '-') d += 2; if (s[8] != '-' && s[8] != 'T') d += 1; if (TOUPPER(s[2]) == 'S') a += 4; if (TOUPPER(s[5]) == 'S') a += 2; if (TOUPPER(s[8]) == 'T') a += 1; char *p = xnmalloc(64, sizeof(char)); snprintf(p, 64, "%d%d%d%d", a, b, c, d); return p; } /* Ask the user to edit permissions given by STR and return the edited string. * If DIFF is set to 0, we are editing a single file or multiple files with the * same set of permissions. Otherwise, we have multiple files with different * sets of permissions. */ static char * get_new_perms(const char *str, const int diff) { const int poffset_bk = prompt_offset; prompt_offset = 3; alt_prompt = PERMISSIONS_PROMPT; rl_nohist = 1; if (diff == 1) { printf(_("%sFiles with different sets of permissions\n" "Only shared permission bits are set in the template\n"), tx_c); } printf(_("%sEdit file permissions (Ctrl+d to quit)\n" "Both symbolic and numeric notation are supported\n"), tx_c); char m[(MAX_COLOR * 2) + 7]; snprintf(m, sizeof(m), "\001%s\002>\001%s\002 ", mi_c, tx_c); char *new_perms = secondary_prompt(m, str); alt_prompt = rl_nohist = 0; prompt_offset = poffset_bk; if (diff == 0 && new_perms && *str == *new_perms && strcmp(str, new_perms) == 0) { fputs(_("pc: Nothing to do\n"), stderr); free(new_perms); new_perms = (char *)NULL; } return new_perms; } /* Returns a struct perms_t with only those permission bits shared by * all files in S set. DIFF is set to 1 in case files in S have different * permission sets. Otherwise, it is set to 0. */ static struct perms_t get_common_perms(char **s, int *diff) { *diff = 0; struct stat a, b; struct perms_t p = {0}; p.ur = p.gr = p.or = 'r'; p.uw = p.gw = p.ow = 'w'; p.ux = p.gx = p.ox = 'x'; int suid = 1, sgid = 1, sticky = 1; int i, stat_ready = 0; for (i = 0; s[i]; i++) { if (stat(s[i], &a) == -1) continue; if (stat_ready == 1 && a.st_mode != b.st_mode) *diff = 1; const mode_t val = (a.st_mode & (mode_t)~S_IFMT); if (!(val & S_IRUSR)) p.ur = '-'; if (!(val & S_IWUSR)) p.uw = '-'; if (!(val & S_IXUSR)) p.ux = '-'; if (!(val & S_IRGRP)) p.gr = '-'; if (!(val & S_IWGRP)) p.gw = '-'; if (!(val & S_IXGRP)) p.gx = '-'; if (!(val & S_IROTH)) p.or = '-'; if (!(val & S_IWOTH)) p.ow = '-'; if (!(val & S_IXOTH)) p.ox = '-'; if (!(a.st_mode & S_ISUID)) suid = 0; if (!(a.st_mode & S_ISGID)) sgid = 0; if (!(a.st_mode & S_ISVTX)) sticky = 0; stat_ready = 1; b = a; } if (suid == 1) p.ux = p.ux == 'x' ? 's' : 'S'; if (sgid == 1) p.gx = p.gx == 'x' ? 's' : 'S'; if (sticky == 1) p.ox = p.ox == 'x' ? 't' : 'T'; return p; } /* Returns the permissions string of files passed as arguments (S). * If only a single file or multiple files with the same set of permissions, * the actual permissions are returned. Otherwise, only shared permissions * bits are set in the permissions template. * DIFF is set to 1 if files in S have different permission sets. Otherwise, * it is set to 0. */ static char * get_perm_str(char **s, int *diff) { char *ptr = xnmalloc(10, sizeof(char)); *diff = 0; if (s[1]) { /* Multiple files */ struct perms_t p = get_common_perms(s, diff); snprintf(ptr, 10, "%c%c%c%c%c%c%c%c%c", p.ur, p.uw, p.ux, p.gr, p.gw, p.gx, p.or, p.ow, p.ox); return ptr; } /* Single file */ struct stat a; if (stat(s[0], &a) == -1) { xerror("stat: '%s': %s\n", s[0], strerror(errno)); free(ptr); return (char *)NULL; } struct perms_t p = get_file_perms(a.st_mode); snprintf(ptr, 10, "%c%c%c%c%c%c%c%c%c", p.ur, p.uw, p.ux, p.gr, p.gw, p.gx, p.or, p.ow, p.ox); return ptr; } /* Interactively change permissions of files passed via ARGS. */ int set_file_perms(char **args) { if (!args || !args[1] || IS_HELP(args[1])) { puts(PC_USAGE); return FUNC_SUCCESS; } size_t i; for (i = 1; args[i]; i++) { if (!strchr(args[i], '\\')) continue; char *t = unescape_str(args[i], 0); if (t) { free(args[i]); args[i] = t; } } int diff = 0; /* Either a single file o multiple files with same perms */ char *pstr = get_perm_str(args + 1, &diff); if (!pstr) return errno; char *new_perms = get_new_perms(pstr, diff); free(pstr); if (!new_perms) return FUNC_SUCCESS; if (validate_new_perms(new_perms) != FUNC_SUCCESS) { free(new_perms); return FUNC_FAILURE; } char *octal_str = IS_DIGIT(*new_perms) ? new_perms : perm2octal(new_perms); int ret = FUNC_SUCCESS; size_t n = 0; const mode_t mode = (mode_t)strtol(octal_str, 0, 8); for (i = 1; args[i]; i++) { if (fchmodat(XAT_FDCWD, args[i], mode, 0) == FUNC_SUCCESS) { n++; } else { xerror(_("pc: Changing permissions of '%s': %s\n"), args[i], strerror(errno)); ret = errno; } fflush(stdout); } if (n > 0) printf(_("pc: Applied new permissions to %zu file(s)\n"), n); free(new_perms); if (octal_str != new_perms) free(octal_str); return ret; } static char * get_new_ownership(const char *str, const int diff) { const int poffset_bk = prompt_offset; prompt_offset = 3; alt_prompt = OWNERSHIP_PROMPT; rl_nohist = 1; if (diff == 1) { printf(_("%sFiles with different owners\n" "Only common owners are set in the template\n"), tx_c); } printf(_("%sEdit file ownership (Ctrl+d to quit)\n" "Both ID numbers and names are supported\n"), tx_c); char m[(MAX_COLOR * 2) + 7]; snprintf(m, sizeof(m), "\001%s\002>\001%s\002 ", mi_c, tx_c); char *new_own = secondary_prompt(m, str); alt_prompt = rl_nohist = 0; prompt_offset = poffset_bk; if (diff == 0 && new_own && *str == *new_own && strcmp(str, new_own) == 0) { fputs(_("oc: Nothing to do\n"), stderr); free(new_own); new_own = (char *)NULL; } return new_own; } static char * get_common_ownership(char **args, int *exit_status, int *diff) { if (!args || !args[0]) return (char *)NULL; *exit_status = FUNC_SUCCESS; struct stat a; if (stat(args[0], &a) == -1) { xerror("oc: '%s': %s\n", args[0], strerror(errno)); *exit_status = errno; return (char *)NULL; } int common_uid = 1, common_gid = 1; struct stat b; size_t i; for (i = 1; args[i]; i++) { if (stat(args[i], &b) == -1) { xerror("oc: '%s': %s\n", args[i], strerror(errno)); *exit_status = errno; continue; } if (b.st_uid != a.st_uid) { common_uid = 0; *diff = 1; } if (b.st_gid != a.st_gid) { common_gid = 0; *diff = 1; } if (common_gid == 0 && common_uid == 0) return savestring(":", 1); } struct passwd *owner = getpwuid(a.st_uid); struct group *group = getgrgid(a.st_gid); const size_t owner_len = (common_uid > 0 && owner && owner->pw_name) ? wc_xstrlen(owner->pw_name) : 0; const size_t group_len = (common_gid > 0 && group && group->gr_name) ? wc_xstrlen(group->gr_name) : 0; if (owner_len + group_len == 0) return (char *)NULL; const size_t len = owner_len + group_len + 2; char *p = xnmalloc(len, sizeof(char)); snprintf(p, len, "%s%c%s", owner_len > 0 ? owner->pw_name : "", group_len > 0 ? ':' : 0, group_len > 0 ? group->gr_name : ""); return p; } int set_file_owner(char **args) { if (!args || !args[1] || IS_HELP(args[1])) { puts(OC_USAGE); return FUNC_SUCCESS; } int exit_status = FUNC_SUCCESS; int diff = 0; char *own = get_common_ownership(args + 1, &exit_status, &diff); if (!own) return exit_status; /* Neither owners nor primary groups are common */ if (*own == ':' && !own[1]) *own = '\0'; char *new_own = get_new_ownership(own, diff); free(own); if (!new_own || !*new_own) { free(new_own); return FUNC_SUCCESS; } char *new_group = (strchr(new_own, ':')); if (new_group) { *new_group = '\0'; if (!new_group[1]) new_group = (char *)NULL; } struct passwd *owner = (struct passwd *)NULL; struct group *group = (struct group *)NULL; /* Validate new ownership */ if (*new_own) { /* NEW_OWN is null in case of ":group" or ":gid" */ if (is_number(new_own)) owner = getpwuid((uid_t)atoi(new_own)); else owner = getpwnam(new_own); if (!owner || !owner->pw_name) { xerror(_("oc: '%s': Invalid user\n"), new_own); free(new_own); return FUNC_FAILURE; } } if (new_group && *(++new_group)) { if (is_number(new_group)) group = getgrgid((gid_t)atoi(new_group)); else group = getgrnam(new_group); if (!group || !group->gr_name) { xerror(_("oc: '%s': Invalid group\n"), new_group); free(new_own); return FUNC_FAILURE; } } /* Change ownership */ struct stat a; size_t new_o = 0, new_g = 0, i; for (i = 1; args[i]; i++) { if (stat(args[i], &a) == -1) { xerror("stat: '%s': %s\n", args[i], strerror(errno)); free(new_own); return errno; } if (fchownat(XAT_FDCWD, args[i], *new_own ? owner->pw_uid : a.st_uid, new_group ? group->gr_gid : a.st_gid, 0) == -1) { xerror("chown: '%s': %s\n", args[i], strerror(errno)); exit_status = errno; continue; } if (*new_own && owner->pw_uid != a.st_uid) { printf(_("%s%s%s %s: User set to %d (%s%s%s)\n"), mi_c, SET_MSG_PTR, NC, args[i], owner->pw_uid, BOLD, owner->pw_name, NC); new_o++; } if (new_group && group->gr_gid != a.st_gid) { printf(_("%s%s%s %s: Primary group set to %d (%s%s%s)\n"), mi_c, SET_MSG_PTR, NC, args[i], group->gr_gid, BOLD, group->gr_name, NC); new_g++; } } if (new_o + new_g == 0) { if (exit_status == 0) puts(_("oc: Nothing to do")); } else { printf(_("New ownership set for %zu file(s)\n"), new_o + new_g); } free(new_own); return exit_status; } /* Get color shade based on file size. */ void get_color_size(const off_t s, char *str, const size_t len) { const long long base = xargs.si == 1 ? 1000 : 1024; int n = 0; /* Keep compatibility with old-style config, which only accepted 3 shades * for 8 color shades type. This check should be removed in the future. */ if (size_shades_old_style == 1) { if (s < base*base) n = 1; /* Byte and Kb */ else if (s < base*base*base) n = 2; /* Mb */ else n = 3; /* Larger */ } else { if (s < base) n = 1; /* Bytes */ else if (s < base*base) n = 2; /* Kb */ else if (s < base*base*base) n = 3; /* Mb */ else if (s < base*base*base*base) n = 4; /* Gb */ else n = 5; /* Larger */ } switch (size_shades.type) { case SHADE_TYPE_8COLORS: snprintf(str, len, "\x1b[0;%d;%dm", size_shades.shades[n].attr, size_shades.shades[n].R); break; case SHADE_TYPE_256COLORS: snprintf(str, len, "\x1b[0;%d;38;5;%dm", size_shades.shades[n].attr, size_shades.shades[n].R); break; case SHADE_TYPE_TRUECOLOR: snprintf(str, len, "\x1b[0;%d;38;2;%d;%d;%dm", size_shades.shades[n].attr, size_shades.shades[n].R, size_shades.shades[n].G, size_shades.shades[n].B); break; default: break; } } /* Get color shade based on file time. */ void get_color_age(const time_t t, char *str, const size_t len) { const time_t age = props_now - t; int n; /* Keep compatibility with old-style config, which only accepted 3 shades * for 8 color shades type. This check should be removed in the future. */ if (date_shades_old_style == 1) { if (age < 0LL) n = 0; else if (age <= 60LL*60) n = 1; /* One hour or less */ else if (age <= 24LL*60*60) n = 2; /* One day or less */ else n = 3; /* Older */ } else { if (age < 0LL) n = 0; else if (age <= 60LL*60) n = 1; /* One hour or less */ else if (age <= 24LL*60*60) n = 2; /* One day or less */ else if (age <= 7LL*24*60*60) n = 3; /* One weak or less */ else if (age <= 4LL*7*24*60*60) n = 4; /* One month or less */ else n = 5; /* Older */ } switch (date_shades.type) { case SHADE_TYPE_8COLORS: snprintf(str, len, "\x1b[0;%d;%dm", date_shades.shades[n].attr, date_shades.shades[n].R); break; case SHADE_TYPE_256COLORS: snprintf(str, len, "\x1b[0;%d;38;5;%dm", date_shades.shades[n].attr, date_shades.shades[n].R); break; case SHADE_TYPE_TRUECOLOR: snprintf(str, len, "\x1b[0;%d;38;2;%d;%d;%dm", date_shades.shades[n].attr, date_shades.shades[n].R, date_shades.shades[n].G, date_shades.shades[n].B); break; default: break; } } #if defined(LINUX_FILE_XATTRS) static int xattr_val_is_printable(const char *val, const size_t len) { size_t i; for (i = 0; i < len; i++) if (val[len] < ' ') /* Control char (== non-printable) */ return 0; return 1; } static int print_extended_attributes(char *s, const mode_t mode, const int xattr) { if (xattr == 0 || S_ISLNK(mode)) { puts(S_ISLNK(mode) ? _("unavailable") : _("none")); return FUNC_SUCCESS; } ssize_t buflen = 0, keylen = 0, vallen = 0; char *buf = (char *)NULL, *key = (char *)NULL, *val = (char *)NULL; /* Determine the length of the buffer needed */ buflen = listxattr(s, NULL, 0); if (buflen == -1) { printf("error: %s\n", strerror(errno)); return FUNC_FAILURE; } if (buflen == 0) { puts(_("none")); return FUNC_SUCCESS; } /* Allocate the buffer */ buf = xnmalloc((size_t)buflen, sizeof(char)); /* Copy the list of attribute keys to the buffer */ buflen = listxattr(s, buf, (size_t)buflen); if (buflen == -1) { xerror("%s\n", strerror(errno)); free(buf); return FUNC_FAILURE; } /* Loop over the list of zero terminated strings with the * attribute keys. Use the remaining buffer length to determine * the end of the list. */ key = buf; size_t count = 0; while (buflen > 0) { /* Output attribute key */ if (count == 0) printf("%s: ", key); else printf(" %s: ", key); count++; /* Determine length of the value */ vallen = getxattr(s, key, NULL, 0); if (vallen == -1) { printf("%s\n", strerror(errno)); } else if (vallen > 0) { /* Output attribute value */ val = xnmalloc((size_t)vallen + 1, sizeof(char)); vallen = getxattr(s, key, val, (size_t)vallen); if (vallen == -1) { printf("%s\n", strerror(errno)); } else { val[vallen] = '\0'; if (xattr_val_is_printable(val, (size_t)vallen) == 1) printf("%s\n", val); else putchar('\n'); } free(val); } else { /* vallen == 0 */ puts(_("")); } /* Forward to next attribute key */ keylen = (ssize_t)strlen(key) + 1; buflen -= keylen; key += keylen; } free(buf); return FUNC_SUCCESS; } #endif /* LINUX_FILE_XATTRS */ static char * get_file_type_and_color(const char *filename, const struct stat *attr, char *file_type, char **ctype) { char *color = fi_c; switch (attr->st_mode & S_IFMT) { case S_IFREG: *file_type = REG_PCHR; if (conf.colorize == 1) { size_t ext = 0; color = get_regfile_color(filename, attr, &ext); } break; case S_IFDIR: *file_type = DIR_PCHR; *ctype = di_c; if (conf.colorize == 0) break; color = get_dir_color(filename, attr, -1); break; case S_IFLNK: { *file_type = LNK_PCHR; struct stat a; *ctype = ln_c; color = stat(filename, &a) == -1 ? or_c : ln_c; break; } case S_IFIFO: *file_type = FIFO_PCHR; color = *ctype = pi_c; break; case S_IFSOCK: *file_type = SOCK_PCHR; color = *ctype = so_c; break; case S_IFBLK: *file_type = BLKDEV_PCHR; color = *ctype = bd_c; break; case S_IFCHR: *file_type = CHARDEV_PCHR; color = *ctype = cd_c; break; #ifndef _BE_POSIX # ifdef S_ARCH1 case S_ARCH1: *file_type = ARCH1_PCHR; color = *ctype = fi_c; break; case S_ARCH2: *file_type = ARCH2_PCHR; color = *ctype = fi_c; break; # endif /* S_ARCH1 */ # ifdef SOLARIS_DOORS case S_IFDOOR: *file_type = DOOR_PCHR; color = *ctype = oo_c; break; case S_IFPORT: *file_type = PORT_PCHR; color = *ctype = oo_c; break; # endif /* SOLARIS_DOORS */ # ifdef S_IFWHT case S_IFWHT: *file_type = WHT_PCHR; color = *ctype = fi_c; break; # endif /* S_IFWHT */ #endif /* !_BE_POSIX */ default: *file_type = UNK_PCHR; color = no_c; break; } if (conf.colorize == 0) color = *ctype = df_c; return color; } static void print_file_perms(const struct stat *attr, const char file_type_char, const char *file_type_char_color, const int xattr) { char tmp_file_type_char_color[MAX_COLOR + 1]; xstrsncpy(tmp_file_type_char_color, file_type_char_color, sizeof(tmp_file_type_char_color)); if (xargs.no_bold != 1) remove_bold_attr(tmp_file_type_char_color); struct perms_t perms = get_file_perms(attr->st_mode); printf(_("(%s%04o%s)%s%c%s/%s%c%s%c%s%c%s.%s%c%s%c%s%c%s.%s%c%s%c%s%c%s%s " "Links: %s%zu%s "), do_c, attr->st_mode & 07777, df_c, tmp_file_type_char_color, file_type_char, dn_c, perms.cur, perms.ur, perms.cuw, perms.uw, perms.cux, perms.ux, dn_c, perms.cgr, perms.gr, perms.cgw, perms.gw, perms.cgx, perms.gx, dn_c, perms.cor, perms.or, perms.cow, perms.ow, perms.cox, perms.ox, df_c, xattr == 1 ? XATTR_STR : "", BOLD, (size_t)attr->st_nlink, df_c); } static void print_filename(char *filename, const char *color, const int follow_link, const mode_t mode, char *link_target) { char *wname = wc_xstrlen(filename) == 0 ? replace_invalid_chars(filename) : (char *)NULL; char name[(NAME_MAX * sizeof(wchar_t)) + 3]; *name = '\0'; if (detect_space(wname ? wname : filename) == 1) snprintf(name, sizeof(name), "'%s'", wname ? wname : filename); char *n = *name ? name : (wname ? wname : filename); if (follow_link == 1) { /* 'pp' command */ if (link_target && *link_target) { char t[PATH_MAX * sizeof(wchar_t) + 3]; *t = '\0'; if (detect_space(link_target) == 1) snprintf(t, sizeof(t), "'%s'", link_target); printf(_("\tName: %s%s%s %s%s%s %s%s%s\n"), color, *t ? t : link_target, df_c, dn_c, term_caps.unicode == 1 ? MSG_PTR_STR_LEFT_U : MSG_PTR_STR_LEFT, df_c, ln_c, n, df_c); } else { printf(_("\tName: %s%s%s\n"), color, n, df_c); } free(wname); return; } /* 'p' command */ if (!S_ISLNK(mode)) { printf(_("\tName: %s%s%s\n"), color, n, df_c); free(wname); return; } char target[PATH_MAX + 1]; const ssize_t tlen = xreadlink(XAT_FDCWD, filename, target, sizeof(target)); char t[PATH_MAX * sizeof(wchar_t) + 3]; *t = '\0'; if (tlen != -1 && *target && detect_space(target) == 1) snprintf(t, sizeof(t), "'%s'", target); struct stat a; if (tlen != -1 && *target && lstat(target, &a) != -1) { char *link_color = get_link_color(target); printf(_("\tName: %s%s%s %s%s%s %s%s%s\n"), ln_c, n, df_c, dn_c, SET_MSG_PTR, df_c, link_color, *t ? t : target, df_c); } else { /* Broken link */ if (tlen != -1 && *target) { printf(_("\tName: %s%s%s %s%s%s %s%s%s (broken link)\n"), or_c, n, df_c, dn_c, SET_MSG_PTR, df_c, uf_c, *t ? t : target, df_c); } else { printf(_("\tName: %s%s%s %s%s ???%s\n"), or_c, n, df_c, dn_c, SET_MSG_PTR, df_c); } } free(wname); } #ifdef LINUX_FILE_CAPS static void print_capabilities(const char *filename, const int xattr) { cap_t cap = xattr == 1 ? cap_get_file(filename) : NULL; if (!cap) { puts(_("none")); return; } char *str = cap_to_text(cap, NULL); if (str) { printf("%s\n", str); cap_free(str); } else { printf("%s\n", strerror(errno)); } cap_free(cap); } #endif /* LINUX_FILE_CAPS */ #if defined(HAVE_ACL) && defined(__linux__) static void list_acl(acl_t acl, int *found, const acl_type_t type) { acl_entry_t entry; int entryid; int num = 0; int f = *found; for (entryid = ACL_FIRST_ENTRY; ; entryid = ACL_NEXT_ENTRY) { if (acl_get_entry(acl, entryid, &entry) != 1) break; /* We don't care about base ACL entries (owner, group, and others), * that is, entries 0, 1, and 2. */ if (num == 3) { /* acl_to_any_text() is Linux-specific */ char *val = acl_to_any_text(acl, type == ACL_TYPE_DEFAULT ? "default:" : (char *)NULL, ',', TEXT_ABBREVIATE); if (val) { printf("%s%s\n", f > 0 ? "\t\t" : "", val); f++; acl_free(val); } break; } num++; } *found = f; } #endif /* HAVE_ACL && __linux__ */ #ifdef HAVE_ACL /* Print ACLs for FILE, whose mode is MODE. * If FILE is a directory, default ACLs are checked besides access ACLs. */ static void print_file_acl(char *file, const mode_t mode, const int xattr) { #ifndef __linux__ UNUSED(file); UNUSED(mode); puts(_("unavailable")); return; #else if (S_ISLNK(mode)) { puts(_("unavailable")); return; } acl_t acl = (acl_t)NULL; int found = 0; if (!file || !*file || xattr == 0) goto END; acl = acl_get_file(file, ACL_TYPE_ACCESS); if (!acl) goto END; if ((found = acl_valid(acl)) == -1) goto END; list_acl(acl, &found, ACL_TYPE_ACCESS); if (!S_ISDIR(mode)) goto END; /* Only directories have default ACLs */ acl_free(acl); acl = acl_get_file(file, ACL_TYPE_DEFAULT); if (!acl) goto END; list_acl(acl, &found, ACL_TYPE_DEFAULT); END: if (found <= 0) puts(found == 0 ? _("none") : _("invalid ACL")); acl_free(acl); #endif /* !__linux__ */ } #endif /* HAVE_ACL */ static void print_file_details(char *filename, const struct stat *attr, const char file_type, const int file_perm, const int xattr) { #if !defined(LINUX_FILE_ATTRS) && !defined(LINUX_FILE_XATTRS) \ && !defined(HAVE_ACL) && !defined(LINUX_FILE_CAPS) UNUSED(filename); #endif #if !defined(LINUX_FILE_XATTRS) && !defined(HAVE_ACL) \ && !defined(LINUX_FILE_CAPS) UNUSED(xattr); #endif struct passwd *owner = getpwuid(attr->st_uid); struct group *group = getgrgid(attr->st_gid); const char *gid_color = conf.colorize == 0 ? "" : (file_perm == 1 ? dg_c : BOLD); const char *uid_color = conf.colorize == 0 ? "" : (file_perm == 1 ? du_c : BOLD); const char *cend = conf.colorize == 1 ? df_c : ""; if (conf.colorize == 1) fputs(BOLD, stdout); switch (file_type) { case REG_PCHR: fputs(_("Regular file"), stdout); break; case DIR_PCHR: fputs(_("Directory"), stdout); break; case LNK_PCHR: fputs(_("Symbolic link"), stdout); break; case FIFO_PCHR: fputs(_("Fifo "), stdout); break; case SOCK_PCHR: fputs(_("Socket "), stdout); break; case BLKDEV_PCHR: fputs(_("Block special file"), stdout); break; case CHARDEV_PCHR: fputs(_("Character special file"), stdout); break; #ifndef _BE_POSIX # ifdef S_ARCH1 case ARCH1_PCHR: fputs(_("Archive state 1"), stdout); break; case ARCH2_PCHR: fputs(_("Archive state 2"), stdout); break; # endif /* S_ARCH1 */ # ifdef SOLARIS_DOORS case DOOR_PCHR: fputs(_("Door "), stdout); break; case PORT_PCHR: fputs(_("Port "), stdout); break; # endif /* SOLARIS_DOORS */ # ifdef S_IFWHT case WHT_PCHR: fputs(_("Whiteout"), stdout); break; # endif /* S_IFWHT */ #endif /* !_BE_POSIX */ default: break; } if (conf.colorize == 1) fputs(cend, stdout); printf(_("\tBlocks: %s%jd%s"), BOLD, (intmax_t)attr->st_blocks, cend); printf(_(" Block size: %s%d%s"), BOLD, S_BLKSIZE, cend); printf(_(" IO Block: %s%jd%s\n"), BOLD, (intmax_t)attr->st_blksize, cend); printf(_("Device: %s%ju,%ju%s"), BOLD, (uintmax_t)major(attr->st_dev), (uintmax_t)minor(attr->st_dev), cend); printf(_("\tInode: %s%ju%s"), BOLD, (uintmax_t)attr->st_ino, cend); printf(_(" Uid: %s%u (%s)%s"), uid_color, attr->st_uid, !owner ? _("UNKNOWN") : owner->pw_name, cend); printf(_(" Gid: %s%u (%s)%s"), gid_color, attr->st_gid, !group ? _("UNKNOWN") : group->gr_name, cend); if (S_ISCHR(attr->st_mode) || S_ISBLK(attr->st_mode)) { printf(_(" Device type: %s%ju,%ju%s\n"), BOLD, (uintmax_t)major(attr->st_rdev), (uintmax_t)minor(attr->st_rdev), cend); } else { putchar('\n'); } #if defined(LINUX_FILE_ATTRS) fputs(_("Attributes: \t"), stdout); if (S_ISDIR(attr->st_mode) || S_ISREG(attr->st_mode)) print_file_attrs(get_file_attrs(filename)); else puts(_("unavailable")); #elif defined(HAVE_BSD_FFLAGS) fputs(_("Flags: \t\t"), stdout); char *fflags = (!S_ISDIR(attr->st_mode) && !S_ISLNK(attr->st_mode)) ? FLAGSTOSTR_FUNC(attr->st_flags) : (char *)NULL; printf("%s\n", (!fflags || !*fflags) ? "-" : fflags); free(fflags); #endif /* LINUX_FILE_ATTRS */ #if defined(LINUX_FILE_XATTRS) fputs(_("Xattributes:\t"), stdout); print_extended_attributes(filename, attr->st_mode, xattr); #endif /* LINUX_FILE_XATTRS */ #if defined(HAVE_ACL) fputs(_("ACL-extended:\t"), stdout); print_file_acl(filename, attr->st_mode, xattr); #endif /* HAVE_ACL */ #if defined(LINUX_FILE_CAPS) fputs(_("Capabilities:\t"), stdout); if (S_ISREG(attr->st_mode)) print_capabilities(filename, xattr); else puts(_("unavailable")); #endif /* LINUX_FILE_CAPS */ } /* Return a pointer to the beginning of the %N modifier in the format * string FMT. If not found, NULL is returned. */ static char * has_nsec_modifier(char *fmt) { if (!fmt || !*fmt) return (char *)NULL; while (*fmt) { if (*fmt == '%' && fmt[1] == 'N') return fmt; ++fmt; } return (char *)NULL; } #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wformat-nonliteral" static void gen_user_time_str(char *buf, size_t buf_size, struct tm *t, const size_t nsec) { char *ptr = has_nsec_modifier(conf.ptime_str); if (!ptr) { /* GCC (not clang) complains about format being not a string literal. * Let's silence this warning until we find a better approach. */ strftime(buf, buf_size, conf.ptime_str, t); return; } /* Let's insert nano-seconds in the time format string supplied by the * user (conf.ptime_str). Note that this is not a full-blown expansion, * but rather a hack, and as such it's limited: only the first appearance * of %N (PTR) in the format string will be replaced by the corresponding * nano-seconds. */ size_t len = 0; *ptr = '\0'; if (ptr != conf.ptime_str) len = strftime(buf, buf_size, conf.ptime_str, t); *ptr = '%'; if (len == 0 && ptr != conf.ptime_str) /* Error or exhausted space in BUF. */ return; len += (size_t)snprintf(buf + len, buf_size - len, "%09zu", nsec); if (len >= buf_size) /* Error or exhausted space in BUF. */ return; ptr += 2; /* Move past the %N modifier in format string. */ if (!*ptr) return; strftime(buf + len, buf_size - len, ptr, t); } #pragma GCC diagnostic pop /* Write into BUF, whose size is SIZE, the timestamp TIM, with nanoseconds NSEC, * in human readable format. * NSEC must be a tv_nsec member of a timespec struct, which, according to the * GNU docs (https://www.gnu.org/software/libc/manual/html_node/Time-Types.html), * is guarranted to be 0-999999999, so that it should fit into a size_t type. * See also https://en.cppreference.com/w/c/chrono/timespec * NOTE: coreutils stat.c uses an int to hold a tv_nsec value. */ static void xgen_time_str(char *buf, const size_t buf_size, const time_t tim, const size_t nsec) { if (buf_size == 0) return; struct tm t; #ifndef CLIFM_LEGACY if (nsec > NANO_SEC_MAX || tim < 0 || !localtime_r(&tim, &t)) #else UNUSED(nsec); if (tim < 0 || !localtime_r(&tim, &t)) #endif /* CLIFM_LEGACY */ goto END; *buf = '\0'; if (conf.ptime_str) { /* User-defined time format. */ gen_user_time_str(buf, buf_size, &t, nsec); return; } /* Default value. */ size_t len = strftime(buf, buf_size, "%F %T", &t); if (len == 0) /* Error or exhausted space in BUF. */ return; #ifndef CLIFM_LEGACY len += (size_t)snprintf(buf + len, buf_size - len, ".%09zu ", nsec); #else *(buf + len) = ' '; len++; #endif /* CLIFM_LEGACY */ if (len >= buf_size) /* Error or exhausted space in BUF. */ return; strftime(buf + len, buf_size - len, "%z", &t); return; END: if (buf_size > 1) { *buf = '-'; buf[1] = '\0'; } else { *buf = '\0'; } } static void print_timestamps(char *filename, const struct stat *attr) { #if !defined(ST_BTIME) || (!defined(LINUX_STATX) && !defined(__sun)) UNUSED(filename); #endif /* !ST_BIME || (!LINUX_STAT && !__sun) */ const char *cdate = conf.colorize == 1 ? dd_c : ""; const char *cend = conf.colorize == 1 ? df_c : ""; char access_time[MAX_TIME_STR]; char change_time[MAX_TIME_STR]; char mod_time[MAX_TIME_STR]; xgen_time_str(access_time, sizeof(access_time), attr->st_atime, (size_t)attr->ATIMNSEC); xgen_time_str(change_time, sizeof(change_time), attr->st_ctime, (size_t)attr->CTIMNSEC); xgen_time_str(mod_time, sizeof(mod_time), attr->st_mtime, (size_t)attr->MTIMNSEC); const char *cadate = cdate; const char *ccdate = cdate; const char *cmdate = cdate; char atf[MAX_SHADE_LEN], mtf[MAX_SHADE_LEN], ctf[MAX_SHADE_LEN]; *atf = *mtf = *ctf = '\0'; if (conf.colorize == 1 && !*dd_c) { props_now = time(NULL); get_color_age(attr->st_atime, atf, sizeof(atf)); cadate = atf; get_color_age(attr->st_mtime, mtf, sizeof(mtf)); cmdate = mtf; get_color_age(attr->st_ctime, ctf, sizeof(ctf)); ccdate = ctf; } printf(_("Access: \t%s%s%s\n"), cadate, access_time, cend); printf(_("Modify: \t%s%s%s\n"), cmdate, mod_time, cend); printf(_("Change: \t%s%s%s\n"), ccdate, change_time, cend); #ifdef ST_BTIME const char *cbdate = cdate; char btf[MAX_SHADE_LEN]; *btf = '\0'; char creation_time[MAX_TIME_STR]; time_t bt = 0; # ifdef LINUX_STATX struct statx attrx; const int ret = statx(AT_FDCWD, filename, AT_SYMLINK_NOFOLLOW, STATX_BTIME, &attrx); if (ret == 0 && attrx.stx_mask & STATX_BTIME) { xgen_time_str(creation_time, sizeof(creation_time), attrx.ST_BTIME.tv_sec, (size_t)attrx.ST_BTIME.tv_nsec); bt = attrx.ST_BTIME.tv_sec; } else { /* Birthtime is not available. */ *creation_time = '-'; creation_time[1] = '\0'; } # elif defined(__sun) struct timespec birthtim = get_birthtime(filename); if (birthtim.tv_sec == (time_t)-1) { /* Error. */ *creation_time = '-'; creation_time[1] = '\0'; } else { xgen_time_str(creation_time, sizeof(creation_time), birthtim.tv_sec, (size_t)birthtim.tv_nsec); bt = birthtim.tv_sec; } # else xgen_time_str(creation_time, sizeof(creation_time), attr->ST_BTIME.tv_sec, (size_t)attr->ST_BTIME.tv_nsec); bt = attr->ST_BTIME.tv_sec; # endif /* LINUX_STATX */ if (conf.colorize == 1 && !*dd_c) { get_color_age(bt, btf, sizeof(btf)); cbdate = btf; } printf(_("Birth: \t\t%s%s%s\n"), cbdate, creation_time, cend); #elif !defined(_BE_POSIX) /* Birthtime is not supported. */ printf(_("Birth: \t\t%s-%s\n"), dn_c, cend); #endif /* ST_BTIME */ } static int err_no_file(const char *filename, const char *target, const int errnum) { char *errname = xargs.stat > 0 ? PROGRAM_NAME : "prop"; if (*target) { xerror(_("%s: %s %s%s%s %s: Broken symbolic link\n"), errname, filename, mi_c, SET_MSG_PTR, df_c, target); } else { xerror("%s: '%s': %s\n", errname, filename, strerror(errnum)); } return errnum; } static void print_file_mime(const char *name) { fputs("MIME type:\t", stdout); char *n = xmagic(name, MIME_TYPE); if (n) { printf("%s\n", n); free(n); } else { printf("%s%c%s\n", dn_c, UNKNOWN_CHR, df_c); } } #ifdef USE_DU1 static off_t get_total_size(char *filename, int *status) { off_t total_size = 0; char _path[PATH_MAX + 1]; *_path = '\0'; snprintf(_path, sizeof(_path), "%s/", filename); fputs(_("Total size: \t"), stdout); #define SCANNING_MSG "Scanning..." if (term_caps.suggestions == 1) { HIDE_CURSOR; fputs(dn_c, stdout); fputs(SCANNING_MSG, stdout); fflush(stdout); } fflush(stdout); total_size = dir_size(*_path ? _path : filename, 1, status); if (term_caps.suggestions == 1) { MOVE_CURSOR_LEFT((int)sizeof(SCANNING_MSG) - 1); ERASE_TO_RIGHT; UNHIDE_CURSOR; fputs(df_c, stdout); fflush(stdout); } return total_size; } static void print_file_size(char *filename, const struct stat *attr, const int file_perm, const int full_dirsize) { const off_t size = (FILE_TYPE_NON_ZERO_SIZE(attr->st_mode) || S_TYPEISSHM(attr) || S_TYPEISTMO(attr)) ? FILE_SIZE_PTR(attr) : 0; char *size_unit = construct_human_size(size); char *csize = dz_c; const char *cend = conf.colorize == 1 ? df_c : ""; char sf[MAX_SHADE_LEN]; *sf = '\0'; if (conf.colorize == 1 && !*dz_c && !S_ISDIR(attr->st_mode)) { get_color_size(size, sf, sizeof(sf)); csize = sf; } if (!S_ISDIR(attr->st_mode)) { printf(_("Size: \t\t%s%s%s"), csize, size_unit ? size_unit : "?", cend); const int bigger_than_bytes = size > (xargs.si == 1 ? 1000 : 1024); if (bigger_than_bytes == 1) printf(" / %s%jd B%s", csize, (intmax_t)size, cend); const int is_sparse = (S_ISREG(attr->st_mode) && (intmax_t)(attr->st_blocks * S_BLKSIZE) < (intmax_t)attr->st_size && attr->st_blocks > 0); printf(" (%s%s%s)\n", conf.apparent_size == 1 ? _("apparent") : _("disk usage"), (xargs.si == 1 && bigger_than_bytes == 1) ? ",si" : "", is_sparse == 1 ? ",sparse" : ""); return; } if (full_dirsize == 0) /* We're running 'p', not 'pp'. */ return; int du_status = 0; const off_t total_size = file_perm == 1 ? get_total_size(filename, &du_status) : (-2); if (total_size < 0) { if (total_size == -2) /* No access. */ printf(_("Total size: \t%s%c%s\n"), dn_c, UNKNOWN_CHR, cend); else /* get_total_size returned error (-1). */ puts(UNKNOWN_STR); return; } const int size_mult_factor = xargs.si == 1 ? 1000 : 1024; if (!*dz_c) { get_color_size(total_size, sf, sizeof(sf)); csize = sf; } const char *human_size = construct_human_size(total_size); if (!human_size) { puts(UNKNOWN_STR); return; } if (bin_flags & (GNU_DU_BIN_DU | GNU_DU_BIN_GDU)) { char err[sizeof(xf_cb) + 6]; *err = '\0'; if (du_status != 0) snprintf(err, sizeof(err), "%s%c%s", xf_cb, DU_ERR_CHAR, NC); printf("%s%s%s%s ", err, csize, human_size, cend); if (total_size > size_mult_factor) printf("/ %s%jd B%s ", csize, (intmax_t)total_size, cend); printf("(%s%s)\n", conf.apparent_size == 1 ? _("apparent") : _("disk usage"), xargs.si == 1 ? ",si" : ""); } else { printf("%s%s%s\n", csize, human_size, cend); } } static void print_dir_items(const char *dir, const int file_perm) { fputs("Items:\t\t", stdout); if (file_perm == 0) { printf("%s%c%s\n", dn_c, UNKNOWN_CHR, NC); return; } struct dir_info_t info = {0}; #define COUNTING_MSG "Counting..." if (term_caps.suggestions == 1) { HIDE_CURSOR; fputs(dn_c, stdout); fputs(COUNTING_MSG, stdout); } fflush(stdout); dir_info(dir, 1, &info); if (term_caps.suggestions == 1) { MOVE_CURSOR_LEFT((int)sizeof(COUNTING_MSG) - 1); ERASE_TO_RIGHT; UNHIDE_CURSOR; fputs(df_c, stdout); fflush(stdout); } char read_err[5 + (MAX_COLOR * 2)]; *read_err = '\0'; if (info.status != 0) snprintf(read_err, sizeof(read_err), "%s%c%s", xf_cb, DU_ERR_CHAR, df_c); printf("%s%s%llu%s (%s%llu%s %s, %s%llu%s %s, %s%llu%s %s)\n", read_err, BOLD, info.dirs + info.files + info.links, df_c, BOLD, info.dirs, df_c, info.dirs == 1 ? _("directory") : _("directories"), BOLD, info.files, df_c, info.files == 1 ? _("file") : _("files"), BOLD, info.links, df_c, info.links == 1 ? _("link") : _("links")); } #else /* !USE_DU1 */ static void print_size(const struct stat *attr, const int apparent) { const off_t size = (FILE_TYPE_NON_ZERO_SIZE(attr->st_mode) || S_TYPEISSHM(attr) || S_TYPEISTMO(attr)) ? (apparent == 1 ? attr->st_size : attr->st_blocks * S_BLKSIZE) : 0; char *size_unit = construct_human_size(size); char *csize = dz_c; char *cend = conf.colorize == 1 ? df_c : ""; char sf[MAX_SHADE_LEN]; *sf = '\0'; if (conf.colorize == 1 && !*dz_c) { get_color_size(size, sf, sizeof(sf)); csize = sf; } printf("%s%s%s", csize, size_unit ? size_unit : "?", cend); const int bigger_than_bytes = size >= (xargs.si == 1 ? 1000 : 1024); const int is_sparse = (S_ISREG(attr->st_mode) && attr->st_blocks > 0 && (intmax_t)(attr->st_blocks * S_BLKSIZE) < (intmax_t)attr->st_size); if (bigger_than_bytes == 1) printf(" / %s%jd B%s", csize, (intmax_t)size, cend); printf(" (%s%s%s)\n", apparent == 1 ? _("apparent") : _("on disk"), (xargs.si == 1 && bigger_than_bytes == 1) ? ",si" : "", is_sparse == 1 ? ",sparse" : ""); } static void print_file_size(const struct stat *attr) { fputs(_("Size:\t\t"), stdout); print_size(attr, 1); /* Apparent size */ fputs("\t\t", stdout); print_size(attr, 0); /* Physical size */ } static void print_dir_size(const off_t dir_size, const int apparent, const char *read_err) { char *cend = conf.colorize == 1 ? df_c : ""; char *size_color = dz_c; char sf[MAX_SHADE_LEN]; *sf = '\0'; if (conf.colorize == 1 && !*dz_c) { get_color_size(dir_size, sf, sizeof(sf)); size_color = sf; } char *size = construct_human_size(dir_size); if (size) { printf("%s%s%s%s ", read_err, size_color, size, cend); const int size_mult_factor = xargs.si == 1 ? 1000 : 1024; if (dir_size > size_mult_factor) printf("/ %s%jd B%s ", size_color, (intmax_t)dir_size, cend); printf("(%s%s)\n", apparent == 1 ? _("apparent") : _("on disk"), xargs.si == 1 ? ",si" : ""); } else { puts(UNKNOWN_STR); } } static void print_dir_info(const char *dir, const int file_perm) { if (file_perm == 0) { printf(_("Total size: \t%s%c%s\n"), dn_c, UNKNOWN_CHR, NC); printf(_("Items:\t\t%s%c%s\n"), dn_c, UNKNOWN_CHR, NC); return; } struct dir_info_t info = {0}; fputs(_("Total size:\t"), stdout); #define SCANNING_MSG "Scanning..." if (term_caps.suggestions == 1) { HIDE_CURSOR; fputs(dn_c, stdout); fputs(SCANNING_MSG, stdout); } fflush(stdout); dir_info(dir, 1, &info); if (term_caps.suggestions == 1) { MOVE_CURSOR_LEFT((int)sizeof(SCANNING_MSG) - 1); ERASE_TO_RIGHT; UNHIDE_CURSOR; fputs(df_c, stdout); fflush(stdout); } #undef SCANNING_MSG char read_err[5 + (MAX_COLOR * 2)]; *read_err = '\0'; if (info.status != 0) snprintf(read_err, sizeof(read_err), "%s%c%s", xf_cb, DU_ERR_CHAR, df_c); print_dir_size(info.size, 1, read_err); /* Apparent */ fputs("\t\t", stdout); print_dir_size(info.blocks * S_BLKSIZE, 0, read_err); /* Physical */ printf(_("Items:\t\t%s%s%llu%s (%s%llu%s %s, %s%llu%s %s, %s%llu%s %s)\n"), read_err, BOLD, info.dirs + info.files + info.links, df_c, BOLD, info.dirs, df_c, info.dirs == 1 ? _("directory") : _("directories"), BOLD, info.files, df_c, info.files == 1 ? _("file") : _("files"), BOLD, info.links, df_c, info.links == 1 ? _("link") : _("links")); } #endif /* USE_DU1 */ /* Retrieve information for the file named FILENAME in a stat(1)-like fashion. * If FOLLOW_LINK is set to 1, in which case we're running the 'pp' command * instead of just 'p', symbolic links are followed and directories size is * calculated recursively. */ static int do_stat(char *filename, const int follow_link) { if (!filename || !*filename) return FUNC_FAILURE; /* Remove leading "./" */ if (*filename == '.' && filename[1] == '/' && filename[2]) filename += 2; /* Check file existence. */ struct stat attr; int ret = lstat(filename, &attr); char link_target[PATH_MAX + 1]; *link_target = '\0'; if (follow_link == 1 && ret != -1 && S_ISLNK(attr.st_mode)) { /* pp: In case of a symlink we want both the symlink name (FILENAME) * and the target name (LINK_TARGET): the Name field in the output * will be printed as follows: "Name: target <- link_name". */ const ssize_t tlen = xreadlink(XAT_FDCWD, filename, link_target, sizeof(link_target)); if (tlen != -1) ret = lstat(link_target, &attr); else ret = -1; } if (ret == -1) return err_no_file(filename, link_target, errno); char file_type = 0; /* File type char indicator. */ char *ctype = dn_c; /* Color for file type char. */ const int file_perm = #ifndef __CYGWIN__ check_file_access(attr.st_mode, attr.st_uid, attr.st_gid); #else /* check_file_access() checks Unix-style permissions, which does * not make much sense on Windows filesystems (particularly, on * system directories). */ 1; #endif /* !__CYGWIN__ */ char *color = get_file_type_and_color(*link_target ? link_target : filename, &attr, &file_type, &ctype); #if defined(LINUX_FILE_XATTRS) const int xattr = llistxattr(*link_target ? link_target : filename, NULL, 0) > 0; #else const int xattr = 0; #endif /* LINUX_FILE_XATTRS */ print_file_perms(&attr, file_type, ctype, xattr); print_filename(filename, color, follow_link, attr.st_mode, link_target); print_file_details(filename, &attr, file_type, file_perm, xattr); print_file_mime(*link_target ? link_target : filename); print_timestamps(*link_target ? link_target : filename, &attr); #ifdef USE_DU1 print_file_size(filename, &attr, file_perm, follow_link); if (S_ISDIR(attr.st_mode) && follow_link == 1) print_dir_items(*link_target ? link_target : filename, file_perm); #else if (S_ISDIR(attr.st_mode)) { if (follow_link == 1) print_dir_info(*link_target ? link_target : filename, file_perm); } else { print_file_size(&attr); } #endif /* USE_DU1 */ return FUNC_SUCCESS; } /* Print file properties (in a stat(1) fashion) for all files passed via ARGS. */ int properties_function(char **args, const int follow_link) { if (!args) return FUNC_FAILURE; size_t i; int exit_status = FUNC_SUCCESS; for (i = 0; args[i]; i++) { if (strchr(args[i], '\\')) { char *deq_file = unescape_str(args[i], 0); if (!deq_file) { xerror(_("p: '%s': Cannot unescape filename\n"), args[i]); exit_status = FUNC_FAILURE; continue; } free(args[i]); args[i] = deq_file; } if (do_stat(args[i], follow_link) != 0) exit_status = FUNC_FAILURE; } return exit_status; } /* Print properties of the files passed from the command line. * If FULL_STAT is set to 1, run with 'pp'. Otherwise use 'p' instead. * Used when running with either --stat or --stat-full. */ __attribute__ ((noreturn)) void do_stat_and_exit(const int full_stat) { /* This function is called very early from main(), immediately after loading * settings, so that we need to set up a few things required to run the * properties function (do_stat). Namely: * 1. du(1) binary (or xdu). * 2. tmp dir (if not xdu). * 3. Current directory. */ #ifdef USE_DU1 # if defined(HAVE_GNU_DU) bin_flags |= GNU_DU_BIN_DU; # elif !defined(_BE_POSIX) if (is_cmd_in_path("gdu") == 1) bin_flags |= GNU_DU_BIN_GDU; # endif /* HAVE_GNU_DU */ if (!tmp_dir) tmp_dir = savestring(P_tmpdir, P_tmpdir_len); #endif /* USE_DU1 */ fputs(df_c, stdout); cur_ws = 0; char tmp[PATH_MAX + 1] = ""; char *cwd = get_cwd(tmp, sizeof(tmp), 0); if (cwd) workspaces[cur_ws].path = savestring(cwd, strlen(cwd)); int status = 0; int start = -1; int i; for (i = 0; i < argc_bk; i++) { if (argv_bk[i] && strncmp(argv_bk[i], "--stat", 6) == 0 && argv_bk[i + 1] && *argv_bk[i + 1]) { start = i + 1; break; } } if (start <= 0) { fprintf(stderr, _("%s: '--stat': Option requires an argument\n" "Try '%s --help' for more information.\n"), PROGRAM_NAME, PROGRAM_NAME); exit(EXIT_FAILURE); } for (i = start; i < argc_bk; i++) { char *norm_path = *argv_bk[i] == '~' ? tilde_expand(argv_bk[i]) : (char *)NULL; const int ret = do_stat(norm_path ? norm_path : argv_bk[i], full_stat); if (ret != 0) status = ret; free(norm_path); } exit(status); } /* Print final stats for the disk usage analyzer mode: total and largest file. */ void print_analysis_stats(const off_t total, const off_t largest, const char *color, const char *name) { char *t = (char *)NULL; char *l = (char *)NULL; if (prop_fields.size == PROP_SIZE_HUMAN) { const char *p_total = construct_human_size(total); t = savestring(p_total, strlen(p_total)); if (conf.sort != STSIZE) { const char *p_largest = construct_human_size(largest); l = savestring(p_largest, strlen(p_largest)); } } else { t = xnmalloc(MAX_INT_STR, sizeof(char)); snprintf(t, MAX_INT_STR, "%ju", (uintmax_t)total); if (conf.sort != STSIZE) { l = xnmalloc(MAX_INT_STR, sizeof(char)); snprintf(l, MAX_INT_STR, "%ju", (uintmax_t)largest); } } char *tsize = dz_c, *lsize = dz_c; char ts[MAX_SHADE_LEN], ls[MAX_SHADE_LEN]; if (!*dz_c) { get_color_size(total, ts, sizeof(ts)); tsize = ts; if (conf.sort != STSIZE) { get_color_size(largest, ls, sizeof(ls)); lsize = ls; } } printf(_("Total size: %s%s%s%s\n"), conf.sort != STSIZE ? " " : "", conf.colorize == 1 ? tsize : "" , t ? t : UNKNOWN_STR, conf.colorize == 1 ? tx_c : ""); if (conf.sort != STSIZE) { printf(_("Largest file: %s%s%s %s%s%s%s%s\n"), conf.colorize == 1 ? lsize : "" , l ? l : UNKNOWN_STR, conf.colorize == 1 ? tx_c : "", name ? "[" : "", (conf.colorize == 1 && color) ? color : "", name ? name : "", tx_c, name ? "]" : ""); } free(t); free(l); } clifm-1.26.3/src/properties.h000066400000000000000000000070231506632037700160440ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* properties.h */ #ifndef PROPERTIES_H #define PROPERTIES_H #ifdef LINUX_FILE_ATTRS /* On some Linux distros, some of these flags are not defined (in linux/fs.h). * On Debian, for example, FS_DAX_FL, FS_CASEFOLD_FL, and FS_VERITY_FL are undefined. * Let's define them ourselves. */ # define XFS_SECRM_FL 0x00000001 /* Secure deletion */ # define XFS_UNRM_FL 0x00000002 /* Undelete */ # define XFS_COMPR_FL 0x00000004 /* Compress file */ # define XFS_SYNC_FL 0x00000008 /* Synchronous updates */ # define XFS_IMMUTABLE_FL 0x00000010 /* Immutable file */ # define XFS_APPEND_FL 0x00000020 /* writes to file may only append */ # define XFS_NODUMP_FL 0x00000040 /* do not dump file */ # define XFS_NOATIME_FL 0x00000080 /* do not update atime */ # define XFS_NOCOMP_FL 0x00000400 /* Don't compress */ # define XFS_ENCRYPT_FL 0x00000800 /* Encrypted file */ # define XFS_INDEX_FL 0x00001000 /* hash-indexed directory */ # define XFS_JOURNAL_DATA_FL 0x00004000 /* Reserved for ext3 */ # define XFS_NOTAIL_FL 0x00008000 /* file tail should not be merged */ # define XFS_DIRSYNC_FL 0x00010000 /* dirsync behaviour (directories only) */ # define XFS_TOPDIR_FL 0x00020000 /* Top of directory hierarchies*/ # define XFS_EXTENT_FL 0x00080000 /* Extents */ # define XFS_VERITY_FL 0x00100000 /* Verity protected inode */ # define XFS_NOCOW_FL 0x00800000 /* Do not cow file */ # define XFS_DAX_FL 0x02000000 /* Inode is DAX */ # define XFS_INLINE_DATA_FL 0x10000000 /* Reserved for ext4 */ # define XFS_PROJINHERIT_FL 0x20000000 /* Create with parents projid */ # define XFS_CASEFOLD_FL 0x40000000 /* Folder is case insensitive */ #endif /* LINUX_FILE_ATTRS */ /* Max size for a file size color (used by get_color_size()) */ #define MAX_SHADE_LEN 26 /* "\x1b[0;x;38;2;xxx;xxx;xxxm\0" */ /* Struct used by get_file_perms() */ struct perms_t { /* Field colors */ char *cur; char *cuw; char *cux; char *cgr; char *cgw; char *cgx; char *cor; char *cow; char *cox; /* Field values */ char ur; char uw; char ux; char gr; char gw; char gx; char or; char ow; char ox; char pad[7]; }; __BEGIN_DECLS void do_stat_and_exit(const int full_stat); void get_color_age(const time_t t, char *str, const size_t len); void get_color_size(const off_t s, char *str, const size_t len); struct perms_t get_file_perms(const mode_t mode); int properties_function(char **args, const int follow_link); void print_analysis_stats(const off_t total, const off_t largest, const char *color, const char *name); int set_file_perms(char **args); int set_file_owner(char **args); __END_DECLS #endif /* PROPERTIES_H */ clifm-1.26.3/src/qsort.h000066400000000000000000000164061506632037700150250ustar00rootroot00000000000000/* * Copyright (c) 2013, 2017 Alexey Tourbin * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ /* * This is a traditional Quicksort implementation which mostly follows * [Sedgewick 1978]. Sorting is performed entirely on array indices, * while actual access to the array elements is abstracted out with the * user-defined `LESS` and `SWAP` primitives. * * Synopsis: * QSORT(N, LESS, SWAP); * where * N - the number of elements in A[]; * LESS(i, j) - compares A[i] to A[j]; * SWAP(i, j) - exchanges A[i] with A[j]. */ #ifndef QSORT_H #define QSORT_H /* Sort 3 elements. */ #define Q_SORT3(q_a1, q_a2, q_a3, Q_LESS, Q_SWAP) \ do { \ if (Q_LESS(q_a2, q_a1)) { \ if (Q_LESS(q_a3, q_a2)) \ Q_SWAP(q_a1, q_a3); \ else { \ Q_SWAP(q_a1, q_a2); \ if (Q_LESS(q_a3, q_a2)) \ Q_SWAP(q_a2, q_a3); \ } \ } \ else if (Q_LESS(q_a3, q_a2)) { \ Q_SWAP(q_a2, q_a3); \ if (Q_LESS(q_a2, q_a1)) \ Q_SWAP(q_a1, q_a2); \ } \ } while (0) /* Partition [q_l,q_r] around a pivot. After partitioning, * [q_l,q_j] are the elements that are less than or equal to the pivot, * while [q_i,q_r] are the elements greater than or equal to the pivot. */ #define Q_PARTITION(q_l, q_r, q_i, q_j, Q_UINT, Q_LESS, Q_SWAP) \ do { \ /* The middle element, not to be confused with the median. */ \ Q_UINT q_m = (q_l) + (((q_r) - (q_l)) >> 1); \ /* Reorder the second, the middle, and the last items. \ * As [Edelkamp Weiss 2016] explain, using the second element \ * instead of the first one helps avoid bad behaviour for \ * decreasingly sorted arrays. This method is used in recent \ * versions of gcc's std::sort, see gcc bug 58437#c13, although \ * the details are somewhat different (cf. #c14). */ \ Q_SORT3((q_l) + 1, q_m, q_r, Q_LESS, Q_SWAP); \ /* Place the median at the beginning. */ \ Q_SWAP(q_l, q_m); \ /* Partition [q_l+2, q_r-1] around the median which is in q_l. \ * q_i and q_j are initially off by one, they get decremented \ * in the do-while loops. */ \ (q_i) = (q_l) + 1; (q_j) = q_r; \ while (1) { \ do (q_i)++; while (Q_LESS(q_i, q_l)); \ do (q_j)--; while (Q_LESS(q_l, q_j)); \ if ((q_i) >= (q_j)) break; /* Sedgewick says "until j < i" */ \ Q_SWAP(q_i, q_j); \ } \ /* Compensate for the i==j case. */ \ (q_i) = (q_j) + 1; \ /* Put the median to its final place. */ \ Q_SWAP(q_l, q_j); \ /* The median is not part of the left subfile. */ \ (q_j)--; \ } while (0) /* Insertion sort is applied to small subfiles - this is contrary to * Sedgewick's suggestion to run a separate insertion sort pass after * the partitioning is done. The reason I don't like a separate pass * is that it triggers extra comparisons, because it can't see that the * medians are already in their final positions and need not be rechecked. * Since I do not assume that comparisons are cheap, I also do not try * to eliminate the (q_j > q_l) boundary check. */ #define Q_INSERTION_SORT(q_l, q_r, Q_UINT, Q_LESS, Q_SWAP) \ do { \ Q_UINT q_i, q_j; \ /* For each item starting with the second... */ \ for (q_i = (q_l) + 1; q_i <= (q_r); q_i++) \ /* move it down the array so that the first part is sorted. */ \ for (q_j = q_i; q_j > (q_l) && (Q_LESS(q_j, q_j - 1)); q_j--) \ Q_SWAP(q_j, q_j - 1); \ } while (0) /* When the size of [q_l,q_r], i.e. q_r-q_l+1, is greater than or equal to * Q_THRESH, the algorithm performs recursive partitioning. When the size * drops below Q_THRESH, the algorithm switches to insertion sort. * The minimum valid value is probably 5 (with 5 items, the second and * the middle items, the middle itself being rounded down, are distinct). */ #define Q_THRESH 16 /* The main loop. */ #define Q_LOOP(Q_UINT, Q_N, Q_LESS, Q_SWAP) \ do { \ Q_UINT q_l = 0; \ Q_UINT q_r = (Q_N) - 1; \ Q_UINT q_sp = 0; /* the number of frames pushed to the stack */ \ struct { Q_UINT q_l, q_r; } \ /* On 32-bit platforms, to sort a "char[3GB+]" array, \ * it may take full 32 stack frames. On 64-bit CPUs, \ * though, the address space is limited to 48 bits. \ * The usage is further reduced if Q_N has a 32-bit type. */ \ q_st[sizeof(Q_UINT) > 4 && sizeof(Q_N) > 4 ? 48 : 32]; \ while (1) { \ if (q_r - q_l + 1 >= Q_THRESH) { \ Q_UINT q_i, q_j; \ Q_PARTITION(q_l, q_r, q_i, q_j, Q_UINT, Q_LESS, Q_SWAP); \ /* Now have two subfiles: [q_l,q_j] and [q_i,q_r]. \ * Dealing with them depends on which one is bigger. */ \ if (q_j - q_l >= q_r - q_i) \ Q_SUBFILES(q_l, q_j, q_i, q_r); \ else \ Q_SUBFILES(q_i, q_r, q_l, q_j); \ } \ else { \ Q_INSERTION_SORT(q_l, q_r, Q_UINT, Q_LESS, Q_SWAP); \ /* Pop subfiles from the stack, until it gets empty. */ \ if (q_sp == 0) break; \ q_sp--; \ q_l = q_st[q_sp].q_l; \ q_r = q_st[q_sp].q_r; \ } \ } \ } while (0) /* The missing part: dealing with subfiles. * Assumes that the first subfile is not smaller than the second. */ #define Q_SUBFILES(q_l1, q_r1, q_l2, q_r2) \ do { \ /* If the second subfile is only a single element, it needs \ * no further processing. The first subfile will be processed \ * on the next iteration (both subfiles cannot be only a single \ * element, due to Q_THRESH). */ \ if ((q_l2) == (q_r2)) { \ q_l = q_l1; \ q_r = q_r1; \ } \ else { \ /* Otherwise, both subfiles need processing. \ * Push the larger subfile onto the stack. */ \ q_st[q_sp].q_l = q_l1; \ q_st[q_sp].q_r = q_r1; \ q_sp++; \ /* Process the smaller subfile on the next iteration. */ \ q_l = q_l2; \ q_r = q_r2; \ } \ } while (0) /* And now, ladies and gentlemen, may I proudly present to you... */ #define QSORT(Q_N, Q_LESS, Q_SWAP) \ do { \ if ((Q_N) > 1) \ /* We could check sizeof(Q_N) and use "unsigned", but at least \ * on x86_64, this has the performance penalty of up to 5%. */ \ Q_LOOP(unsigned long, Q_N, Q_LESS, Q_SWAP); \ } while (0) #endif /* ex:set ts=8 sts=4 sw=4 noet: */ clifm-1.26.3/src/readline.c000066400000000000000000003261151506632037700154340ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* readline.c -- functions to control the behavior of readline, * specially completions. It also introduces both the syntax highlighting * and the suggestions system (via my_rl_getc) */ /* The following functions are taken from Bash (1.14.7), licensed under * GPL-1.0-or-later: * my_rl_getc * my_rl_path_completion * All changes are licensed under GPL-2.0-or-later. */ #include "helpers.h" #include #include /* str(n)casecmp() */ #include #include #include #include /* Needed by groups_generator(): getgrent(3) */ #ifdef __OpenBSD__ typedef char *rl_cpvfunc_t; # include #else # include #endif /* __OpenBSD__ */ #include "misc.h" #include "aux.h" #include "checks.h" #include "fuzzy_match.h" #ifndef _NO_HIGHLIGHT # include "highlight.h" #endif /* !_NO_HIGHLIGHT */ #include "keybinds.h" #include "mime.h" /* xmagic() */ #include "navigation.h" #include "readline.h" #include "sort.h" /* compare_strings() */ #include "spawn.h" #ifndef _NO_SUGGESTIONS # include "suggestions.h" #endif /* !_NO_SUGGESTIONS */ #include "tabcomp.h" #include "tags.h" #define DEL_EMPTY_LINE 1 #define DEL_NON_EMPTY_LINE 2 /* The maximum number of bytes we need to contain any Unicode code point * as a C string: 4 bytes plus a trailing nul byte. */ #define UTF8_MAX_LEN 5 #define RL_VI_MODE 0 #define SUGGEST_ONLY 0 #define RL_INSERT_CHAR 1 #ifndef _NO_SUGGESTIONS # define SKIP_CHAR 2 #endif /* !_NO_SUGGESTIONS */ #define SKIP_CHAR_NO_REDISPLAY 3 #define MAX_EXT_OPTS NAME_MAX #define MAX_EXT_OPTS_LEN NAME_MAX static char ext_opts[MAX_EXT_OPTS][MAX_EXT_OPTS_LEN]; #ifndef _NO_TAGS static struct dirent **tagged_files = (struct dirent **)NULL; static int tagged_files_n = 0; #endif /* !_NO_TAGS */ static int cb_running = 0; static char rl_default_answer = 0; static const char * gen_y_n_str(const char def_answer) { switch (def_answer) { case 'y': return "[Y/n]"; case 'n': return "[y/N]"; case 'u': /* fallthrough */ default: return "[y/n]"; } } static char set_default_answer(const char default_answer) { if (conf.default_answer.default_all != 0) return conf.default_answer.default_all; if (default_answer == 0) return conf.default_answer.default_; return default_answer; } /* Get user input (y/n, uppercase is allowed) using MSG_STR as prompt message. * If DEFAULT_ANSWER isn't zero, it will be used in case the user just * presses Enter on an empty line. * Returns 1 if 'y' or 0 if 'n'. */ int rl_get_y_or_n(const char *msg_str, char default_answer) { rl_default_answer = set_default_answer(default_answer); const char *yes_no_str = gen_y_n_str(rl_default_answer); const size_t msg_len = strlen(msg_str) + strlen(yes_no_str) + 3; char *msg = xnmalloc(msg_len, sizeof(char)); snprintf(msg, msg_len, "%s %s ", msg_str, yes_no_str); int ret = 0; char *answer = (char *)NULL; while (!answer) { answer = rl_no_hist(msg, 0); if (!answer) continue; if (!*answer) { free(answer); answer = (char *)NULL; continue; } switch (*answer) { case 'y': /* fallthrough */ case 'Y': if (!answer[1] || strcmp(answer + 1, "es") == 0) { free(answer); ret = 1; break; } else { free(answer); answer = (char *)NULL; continue; } case 'n': /* fallthrough */ case 'N': if (!answer[1] || (answer[1] == 'o' && !answer[2])) { free(answer); ret = 0; break; } else { free(answer); answer = (char *)NULL; continue; } default: free(answer); answer = (char *)NULL; continue; } } free(msg); return ret; } /* Delete key implementation */ static void xdelete(void) { #ifndef _NO_SUGGESTIONS if (suggestion.printed && suggestion_buf) clear_suggestion(CS_FREEBUF); #endif /* !_NO_SUGGESTIONS */ rl_delete(1, 0); } /* Backspace implementation */ static void xbackspace(void) { #ifndef _NO_SUGGESTIONS if (suggestion.printed && suggestion_buf) clear_suggestion(CS_FREEBUF); #endif /* !_NO_SUGGESTIONS */ rl_rubout(1, 0); } #ifndef _NO_SUGGESTIONS static void leftmost_bell(void) { if (conf.bell_style == BELL_VISIBLE) { rl_extend_line_buffer(2); *rl_line_buffer = ' '; *(rl_line_buffer + 1) = '\0'; rl_end = rl_point = 1; } rl_ring_bell(); if (conf.bell_style == BELL_VISIBLE) { rl_delete_text(0, rl_end); rl_end = rl_point = 0; } } #endif /* !_NO_SUGGESTIONS */ /* Construct a wide-char (UTF8) byte by byte. * This function is called multiple times until we get a full wide-char. * Each byte (C), in each subsequent call, is appended to a string (WC_STR), * until we have a complete multi-byte char (WC_BYTES were copied into WC_STR), * in which case we insert the character into the readline buffer (my_rl_getc * will then trigger the suggestions system using the updated input buffer). */ static int construct_utf8_char(unsigned char c) { static char wc_str[UTF8_MAX_LEN] = ""; static size_t wc_len = 0; static int wc_bytes = 0; if (wc_len == 0) wc_bytes = utf8_bytes(c); /* utf8_bytes returns -1 in case of error, and a zero bytes wide-char * should never happen. */ if (wc_bytes < 1) return SKIP_CHAR_NO_REDISPLAY; if (wc_len < (size_t)wc_bytes - 1) { wc_str[wc_len] = (char)c; wc_len++; /* Incomplete wide char: do not trigger suggestions. */ return SKIP_CHAR_NO_REDISPLAY; } wc_str[wc_len] = (char)c; wc_len++; wc_str[wc_len] = '\0'; if (conf.highlight == 1 && cur_color != tx_c && cur_color != hv_c && cur_color != hc_c && cur_color != hp_c && cur_color != hq_c) { cur_color = wrong_cmd == 1 ? wp_c : tx_c; fputs(cur_color, stdout); } rl_insert_text(wc_str); rl_redisplay(); wc_len = 0; wc_bytes = 0; memset(wc_str, '\0', UTF8_MAX_LEN); return SUGGEST_ONLY; } /* Handle the input char C and sepcify what to do next based on this char * Return values: * SUGGEST_ONLY = Do not insert char (already inserted here). Make suggestions. * RL_INSERT_CHAR = Let readline insert the char. Do not suggest. * SKIP_CHAR = Do not insert char. Do not suggest. * SKIP_CHAR_NO_REDISPLAY = Same as SKIP_CHAR, but do not call rl_redisplay(). */ static int rl_exclude_input(const unsigned char c, const unsigned char prev) { /* Delete or backspace keys. */ int del_key = 0; int space = 0; char *ptr = (char *)NULL; /* Disable suggestions while in vi mode. */ if (rl_editing_mode == RL_VI_MODE) { #ifndef _NO_SUGGESTIONS if (suggestion.printed) clear_suggestion(CS_FREEBUF); #endif /* !_NO_SUGGESTIONS */ return RL_INSERT_CHAR; } /* Skip escape sequences, mostly arrow keys. */ if (rl_readline_state & RL_STATE_MOREINPUT) { if (c == '~') { /* This should be the delete key. */ #ifndef _NO_SUGGESTIONS if (suggestion.printed) clear_suggestion(CS_FREEBUF); #endif /* !_NO_SUGGESTIONS */ } else if (prev == '[' && c == '3' && rl_point < rl_end) { xdelete(); del_key = DEL_NON_EMPTY_LINE; goto END; } /* Handle history events. If a suggestion has been printed and * a history event is triggered (usually via the Up and Down arrow * keys), the suggestion buffer won't be freed. Let's do it here. */ #ifndef _NO_SUGGESTIONS else if ((c == 'A' || c == 'B') && suggestion_buf) { clear_suggestion(CS_FREEBUF); } #endif /* !_NO_SUGGESTIONS */ else { if (c == 'C' || c == 'D') cmdhist_flag = 0; } return RL_INSERT_CHAR; } if (c == CTRL('D') && rl_point < rl_end) { xdelete(); del_key = DEL_NON_EMPTY_LINE; goto END; } if (c == CTRL('U')) { /* Kill line */ #ifndef _NO_SUGGESTIONS if (wrong_cmd == 1) recover_from_wrong_cmd(); #endif /* !_NO_SUGGESTIONS */ return RL_INSERT_CHAR; } /* Skip control characters (0 - 31) except backspace (8), tab(9), * enter (13), and escape (27). */ if (c < ' ' && c != KEY_BACKSPACE && c != KEY_TAB && c != KEY_ENTER && c != KEY_ESC) return RL_INSERT_CHAR; if (IS_UTF8_CHAR(c)) return construct_utf8_char(c); if (c != KEY_ESC) cmdhist_flag = 0; /* Skip ESC, del/backspace, Enter, and TAB keys. */ switch (c) { case KEY_DELETE: /* fallthrough */ case KEY_BACKSPACE: del_key = (rl_point == 0 && rl_end == 0) ? DEL_EMPTY_LINE : DEL_NON_EMPTY_LINE; xbackspace(); if (rl_end == 0 && cur_color != tx_c) { cur_color = tx_c; fputs(tx_c, stdout); } goto END; case KEY_ENTER: #ifndef _NO_SUGGESTIONS if (suggestion_buf != NULL) clear_suggestion(CS_FREEBUF); #endif /* !_NO_SUGGESTIONS */ cur_color = tx_c; fputs(tx_c, stdout); return RL_INSERT_CHAR; case KEY_ESC: return RL_INSERT_CHAR; case KEY_TAB: #ifndef _NO_SUGGESTIONS if (suggestion.printed) { if (suggestion.nlines >= 2 || suggestion.type == ELN_SUG || suggestion.type == BOOKMARK_SUG || suggestion.type == ALIAS_SUG || suggestion.type == JCMD_SUG) clear_suggestion(CS_FREEBUF); } #endif /* !_NO_SUGGESTIONS */ return RL_INSERT_CHAR; default: break; } char t[2]; t[0] = (char)c; t[1] = '\0'; rl_insert_text(t); END: #ifndef _NO_SUGGESTIONS ptr = strrchr(rl_line_buffer, ' '); space = ptr ? (int)(ptr - rl_line_buffer) : -1; /* Do not take into account ending spaces. */ if (space >= 0 && !rl_line_buffer[space + 1]) space = -1; if (rl_point != rl_end && c != KEY_ESC) { if (rl_point < space) { if (suggestion.printed) clear_suggestion(CS_FREEBUF); } if (wrong_cmd == 1) { /* Wrong cmd and we are on the first word. */ char *fs = strchr(rl_line_buffer, ' '); if (fs && rl_line_buffer + rl_point <= fs) space = -1; } } #else UNUSED(space); UNUSED(ptr); #endif /* !_NO_SUGGESTIONS */ #ifndef _NO_HIGHLIGHT if (wrong_cmd == 0 && conf.highlight == 1) recolorize_line(); #endif /* !_NO_HIGHLIGHT */ if (del_key <= 0) return SUGGEST_ONLY; #ifndef _NO_SUGGESTIONS /* Since we have removed a char, let's check if there is * a suggestion available using the modified input line. */ if (wrong_cmd == 1 && space == -1 && rl_end > 0) { /* If a suggestion is found, the normal prompt will be * restored and wrong_cmd will be set to zero. */ rl_suggestions((unsigned char)rl_line_buffer[rl_end - 1]); return SKIP_CHAR; } if (rl_point == 0 && rl_end == 0) { if (wrong_cmd == 1) recover_from_wrong_cmd(); if (del_key == DEL_EMPTY_LINE) leftmost_bell(); } #endif /* !_NO_SUGGESTIONS */ #ifdef NO_BACKWARD_SUGGEST return SKIP_CHAR; #else return SUGGEST_ONLY; #endif /* NO_BACKWARD_SUGGEST */ } /* Unicode aware implementation of readline's rl_expand_prompt() * Returns the number of terminal columns taken by the last prompt line, * 0 if STR is NULL or empty, and FALLBACK_PROMPT_OFFSET in case of error * (malformed prompt: either RL_PROMPT_START_IGNORE or RL_PROMPT_END_IGNORE * is missing). */ static int xrl_expand_prompt(char *str) { if (!str || !*str) return 0; int count = 0; while (*str) { char *start = strchr(str, RL_PROMPT_START_IGNORE); if (!start) { char *end = strchr(str, RL_PROMPT_END_IGNORE); if (end) { err('w', PRINT_PROMPT, "%s: Malformed prompt: " "RL_PROMPT_END_IGNORE (\\%d) without " "RL_PROMPT_START_IGNORE (\\%d)\n", PROGRAM_NAME, RL_PROMPT_END_IGNORE, RL_PROMPT_START_IGNORE); return FALLBACK_PROMPT_OFFSET; } /* No ignore characters found */ return (int)wc_xstrlen(str); } if (start != str) { char c = *start; *start = '\0'; count += (int)wc_xstrlen(str); *start = c; } char *end = strchr(start, RL_PROMPT_END_IGNORE); if (!end) { err('w', PRINT_PROMPT, "%s: Malformed prompt: " "RL_PROMPT_START_IGNORE (\\%d) without " "RL_PROMPT_END_IGNORE (\\%d)\n", PROGRAM_NAME, RL_PROMPT_START_IGNORE, RL_PROMPT_END_IGNORE); return FALLBACK_PROMPT_OFFSET; } if (*(++end)) str = end; else break; } return count; } /* Get the number of visible chars in the last line of the prompt (STR). */ static int get_prompt_offset(char *str) { if (!str || !*str) return 0; char *newline = strrchr(str, '\n'); return xrl_expand_prompt((newline && *(++newline)) ? newline : str) + 1; } /* Whenever we are on a secondary prompt, multi-byte chars are present, and * we press Right on such char, rl_point gets the wrong cursor offset. * This function corrects this offset. * NOTE: This is just a workaround. No correction should be made because * nothing should be corrected in the first place. The question is: why is * rl_point wrong here, and why does this happen only in secondary prompts? */ static void fix_rl_point(const unsigned char c) { if (!RL_ISSTATE(RL_STATE_MOREINPUT) || c != 'C') return; const char point = rl_line_buffer[rl_point]; /* Continue only in case of leading or continuation multi-byte. */ if (!IS_UTF8_CHAR(point)) return; const int mlen = mblen(rl_line_buffer + rl_point, MB_CUR_MAX); rl_point += mlen > 0 ? mlen - 1 : 0; } /* Custom implementation of readline's rl_getc() hacked to introduce * suggestions, alternative tab completion, and syntax highlighting. * This function is automatically called by readline() to handle input. */ static int my_rl_getc(FILE *stream) { int result; unsigned char c; static unsigned char prev = 0; if (prompt_offset == UNSET) prompt_offset = get_prompt_offset(rl_prompt); while (1) { result = (int)read(fileno(stream), &c, sizeof(unsigned char)); /* flawfinder: ignore */ if (result == sizeof(unsigned char)) { /* Ctrl+d (empty command line only). Let's check that the previous * char wasn't ESC to prevent Ctrl+Alt+d to be taken as Ctrl+d */ if (c == CTRL('D') && prev != KEY_ESC && rl_nohist == 0 && (!rl_line_buffer || !*rl_line_buffer)) rl_quit(0, 0); if (rl_end == 0) { if (conf.highlight == 1) rl_redisplay(); } /* Syntax highlighting is made from here */ const int ret = rl_exclude_input(c, prev); prev = c; if (ret == RL_INSERT_CHAR) { if (rl_nohist == 1 && !(flags & NO_FIX_RL_POINT)) fix_rl_point(c); return c; } #ifndef _NO_SUGGESTIONS if (ret == SUGGEST_ONLY && conf.suggestions == 1) rl_suggestions(c); #endif /* !_NO_SUGGESTIONS */ if (ret != SKIP_CHAR_NO_REDISPLAY) rl_redisplay(); continue; } /* If zero characters are returned, then the file that we are reading from is empty! Return EOF in that case. */ if (result == 0) return (EOF); /* read(3) either failed (returned -1) or is > sizeof(unsigned char) */ #if defined(EWOULDBLOCK) && defined(O_NDELAY) if (errno == EWOULDBLOCK) { int xflags; if ((xflags = fcntl(fileno(stream), F_GETFL, 0)) < 0) return (EOF); if (xflags & O_NDELAY) { /* xflags &= ~O_NDELAY; */ fcntl(fileno(stream), F_SETFL, flags); continue; } continue; } #endif /* EWOULDBLOCK && O_NDELAY */ #if defined(_POSIX_VERSION) && defined(EAGAIN) && defined(O_NONBLOCK) if (errno == EAGAIN) { int xflags; if ((xflags = fcntl(fileno(stream), F_GETFL, 0)) < 0) return (EOF); if (xflags & O_NONBLOCK) { /* xflags &= ~O_NONBLOCK; */ fcntl(fileno(stream), F_SETFL, flags); continue; } } #endif /* _POSIX_VERSION && EAGAIN && O_NONBLOCK */ if (errno != EINTR) return (EOF); /* If the error that we received was SIGINT, then try again, this is simply an interrupted system call to read(). Otherwise, some error ocurred, also signifying EOF. */ } } /* Alternative taking input function used by alt_rl_prompt(), our readline * alternative interface. */ static int alt_rl_getc(FILE *stream) { int result; unsigned char c; static unsigned char prev = 0; while (1) { result = (int)read(fileno(stream), &c, sizeof(unsigned char)); /* flawfinder: ignore */ if (result == sizeof(unsigned char)) { if ((c == CTRL('D') || c == CTRL('X')) && prev != KEY_ESC) { MOVE_CURSOR_UP(1); return (EOF); } prev = c; fix_rl_point(c); return c; } /* If zero characters are returned, then the file that we are reading from is empty! Return EOF in that case. */ if (result == 0) return (EOF); /* read(3) either failed (returned -1) or is > sizeof(unsigned char) */ #if defined(EWOULDBLOCK) && defined(O_NDELAY) if (errno == EWOULDBLOCK) { int xflags; if ((xflags = fcntl(fileno(stream), F_GETFL, 0)) < 0) return (EOF); if (xflags & O_NDELAY) { /* xflags &= ~O_NDELAY; */ fcntl(fileno(stream), F_SETFL, flags); continue; } continue; } #endif /* EWOULDBLOCK && O_NDELAY */ #if defined(_POSIX_VERSION) && defined(EAGAIN) && defined(O_NONBLOCK) if (errno == EAGAIN) { int xflags; if ((xflags = fcntl(fileno(stream), F_GETFL, 0)) < 0) return (EOF); if (xflags & O_NONBLOCK) { /* xflags &= ~O_NONBLOCK; */ fcntl(fileno(stream), F_SETFL, flags); continue; } } #endif /* _POSIX_VERSION && EAGAIN && O_NONBLOCK */ if (errno != EINTR) return (EOF); /* If the error that we received was SIGINT, then try again, this is simply an interrupted system call to read(). Otherwise, some error occurred, also signifying EOF. */ } } /* Callback function called for each line when accept-line executed, EOF * seen, or EOF character read. This sets a flag and returns; it could * also call exit(3). */ static void cb_linehandler(char *line) { /* alt_rl_getc returns EOF in case of Ctrl+d and Ctrl+x, in which case * LINE is NULL. */ if (line == NULL) { if (line == 0) putchar('\n'); free(line); rl_callback_handler_remove(); cb_running = 0; } else { if (*line) { /* Write input into a global variable */ rl_callback_handler_input = savestring(line, strlen(line)); rl_callback_handler_remove(); cb_running = 0; } else { /* Enter on empty line. If we have a default answer (set via * rl_get_y_or_n()), let's return this answer. */ if (rl_default_answer != 0) { rl_callback_handler_input = xnmalloc(2, sizeof(char)); *rl_callback_handler_input = rl_default_answer; rl_callback_handler_input[1] = '\0'; rl_callback_handler_remove(); cb_running = 0; } } free(line); } rl_default_answer = 0; } static int alt_rl_prompt(const char *prompt_str, const char *line) { cb_running = 1; kbind_busy = 1; rl_getc_function = alt_rl_getc; const int highlight_bk = conf.highlight; conf.highlight = 0; /* Install the line handler */ rl_callback_handler_install(prompt_str, cb_linehandler); /* Set the initial line content, if any */ if (line) { rl_insert_text(line); rl_redisplay(); } /* Take input */ while (cb_running == 1) rl_callback_read_char(); conf.highlight = highlight_bk; kbind_busy = 0; rl_getc_function = my_rl_getc; return FUNC_SUCCESS; } char * secondary_prompt(const char *prompt_str, const char *line) { alt_rl_prompt(prompt_str, line); if (!rl_callback_handler_input) return (char *)NULL; char *input = savestring(rl_callback_handler_input, strlen(rl_callback_handler_input)); free(rl_callback_handler_input); rl_callback_handler_input = (char *)NULL; return input; } /* Simply check a single chartacter (c) against the quoting characters * list defined in the quote_chars global array (which takes its values from * rl_filename_quote_characters. */ int is_quote_char(const char c) { if (c == '\0' || !quote_chars) return (-1); char *p = quote_chars; while (*p) { if (c == *p) return 1; p++; } return 0; } char * rl_no_hist(const char *prompt_str, const int tabcomp) { rl_notab = (tabcomp == 0); rl_nohist = 1; char *input = secondary_prompt(prompt_str, NULL); rl_nohist = rl_notab = 0; if (!input) /* Ctrl+d */ return savestring("q", 1); if (!*input) { free(input); return (char *)NULL; } /* Do we have some non-blank char? */ int blank = 1; char *p = input; while (*p) { if (*p != ' ' && *p != '\n' && *p != '\t') { blank = 0; break; } p++; } if (blank == 1) { free(input); return (char *)NULL; } return input; } /* Used by readline to check if a char in the string being completed is * quoted or not */ static int quote_detector(char *line, int index) { if (index > 0 && line[index - 1] == '\\' && !quote_detector(line, index - 1)) return 1; return 0; } /* Performs bash-style filename quoting for readline (put a backslash * before any char listed in rl_filename_quote_characters. * Modified version of: * https://utcc.utoronto.ca/~cks/space/blog/programming/ReadlineQuotingExample*/ static char * my_rl_quote(char *text, int mt, char *qp) /* NOLINT */ { /* NOTE: mt and qp arguments are not used here, but are required by * rl_filename_quoting_function */ UNUSED(mt); UNUSED(qp); /* How it works: P and R are pointers to the same memory location * initialized (malloced) twice as big as the line that needs to be * quoted (in case all chars in the line need to be quoted); TP is a * pointer to TEXT, which contains the string to be quoted. We move * through TP to find all chars that need to be quoted ("a's" becomes * "a\'s", for example). At this point we cannot return P, since this * pointer is at the end of the string, so that we return R instead, * which is at the beginning of the same string pointed to by P. */ char *r = (char *)NULL, *p = (char *)NULL, *tp = (char *)NULL; size_t text_len = strlen(text); /* Worst case: every character of text needs to be escaped. In this * case we need 2x text's bytes plus the NULL byte. */ p = xnmalloc((text_len * 2) + 1, sizeof(char)); r = p; if (r == NULL) return (char *)NULL; /* Escape whatever char that needs to be escaped */ for (tp = text; *tp; tp++) { if (is_quote_char(*tp)) { *p = '\\'; p++; } *p = *tp; p++; } /* Add a final null byte to the string */ *p = '\0'; return r; } static inline int filter_cd_cmd(const char *dirname, const char *d_name, char *buf, mode_t type) { if (type == DT_DIR) return 1; if (type != DT_LNK) return 0; if (*dirname == '.' && !dirname[1]) return (get_link_ref(d_name) == S_IFDIR); snprintf(buf, PATH_MAX + 1, "%s%s", dirname, d_name); return (get_link_ref(buf) == S_IFDIR); } static inline int filter_open_cmd(const char *dirname, const char *d_name, char *buf, mode_t type) { if (type == DT_REG || type == DT_DIR) return 1; if (type != DT_LNK) return 0; int ret = -1; if (*dirname == '.' && !dirname[1]) { ret = get_link_ref(d_name); } else { snprintf(buf, PATH_MAX + 1, "%s%s", dirname, d_name); ret = get_link_ref(buf); } return (ret == S_IFDIR || ret == S_IFREG); } /* Compare the strings S1 to S2. Return 1 if they match or 0 otherwise. */ static inline int check_match(const char *s1, const char *s2, const size_t s1_len) { if (conf.case_sens_path_comp == 0) { return TOUPPER(*s1) != TOUPPER(*s2) ? 0 : (strncasecmp(s1, s2, s1_len) == 0); } return *s1 != *s2 ? 0 : (strncmp(s1, s2, s1_len) == 0); } static inline int get_best_fuzzy_match(char *filename, const char *dirname, char *d_name, const size_t flen, const int fuzzy_str_type, int *best_fz_score) { const int score = fuzzy_match(filename, d_name, flen, fuzzy_str_type); if (score <= *best_fz_score) return 0; /* Best score so far. Keep a copy the best ranked entry. * FZ_MATCH is global. */ if (!dirname || (*dirname == '.' && !dirname[1])) { xstrsncpy(fz_match, d_name, sizeof(fz_match)); } else { snprintf(fz_match, sizeof(fz_match), "%s%s", dirname, d_name); } /* If the current score isn't the best possible one, let's keep looking * for the best one. */ if (score != TARGET_BEGINNING_BONUS) { *best_fz_score = score; return 0; } return 1; } static inline int skip_first_word(const mode_t type, const int line_buffer_has_space) { return (((conf.suggestions == 1 && words_num == 1) || line_buffer_has_space == 0) && ((type == DT_DIR && conf.autocd == 0) || (type != DT_DIR && conf.auto_open == 0))); } static inline int do_regular_matching(const char *filename) { return (rl_point < rl_end || conf.fuzzy_match == 0 || (*filename == '.' && filename[1] == '.') || *filename == '-' || (tabmode == STD_TAB && !(flags & STATE_SUGGESTING))); } /* This is the filename_completion_function() function of an old Bash * release (1.14.7) modified to fit Clifm's needs */ /* state is zero before completion, and 1 ... n after getting * possible completions. Example: * cd Do[TAB] -> state 0 * cuments/ -> state 1 * wnloads/ -> state 2 * */ char * my_rl_path_completion(const char *text, int state) { /* Tab complete only for regular prompt (0) and FILES_PROMPT (1). */ if (!text || !*text || alt_prompt > 1) return (char *)NULL; static DIR *directory; static char *filename = (char *)NULL; static char *dirname = (char *)NULL; static char *users_dirname = (char *)NULL; static size_t filename_len; static int match; struct dirent *ent = (struct dirent *)NULL; static char tmp[PATH_MAX + 1]; static char *tmp_text = (char *)NULL; static int is_cd_cmd = 0; static int is_open_cmd = 0; static int is_trash_cmd = 0; static int line_buffer_has_space = 0; static int conf_suggestions = 0; static int conf_fuzzy_match = 0; /* Dequote string to be completed (text), if necessary. */ if (strchr(text, '\\')) { char *p = savestring(text, strlen(text)); tmp_text = unescape_str(p, 0); free(p); if (!tmp_text) return (char *)NULL; } /* If we don't have any state, then do some initialization. */ if (state == 0) { if (rl_line_buffer) { is_cd_cmd = (*rl_line_buffer == 'c' && rl_line_buffer[1] == 'd' && rl_line_buffer[2] == ' '); is_open_cmd = (*rl_line_buffer == 'o' && (strncmp(rl_line_buffer, "o ", 2) == 0 || strncmp(rl_line_buffer, "open ", 5) == 0)); is_trash_cmd = (*rl_line_buffer == 't' && (strncmp(rl_line_buffer, "t ", 2) == 0 || strncmp(rl_line_buffer, "trash ", 6) == 0)); line_buffer_has_space = strchr(rl_line_buffer, ' ') != NULL; } else { is_cd_cmd = is_open_cmd = is_trash_cmd = line_buffer_has_space = 0; } conf_suggestions = conf.suggestions; conf_fuzzy_match = conf.fuzzy_match; free(dirname); free(filename); free(users_dirname); /* tmp_text is not NULL whenever text was dequoted. */ const char *p = tmp_text ? tmp_text : text; size_t text_len = filename_len = strlen(p); if (text_len > 0) { filename = savestring(p, text_len); dirname = savestring(p, text_len); } else { filename = savestring("", 1); dirname = savestring("", 1); } /* Get everything after the last slash. */ char *base_name = strrchr(dirname, '/'); if (base_name) { /* At this point, FILENAME has been allocated with FILENAME_LEN bytes. */ xstrsncpy(filename, ++base_name, filename_len + 1); filename_len -= (size_t)(base_name - dirname); *base_name = '\0'; } else { /* No slash. DIR is the current directory. */ *dirname = '.'; dirname[1] = '\0'; } /* Save the version of the directory that the user typed. */ users_dirname = savestring(dirname, strlen(dirname)); char *temp_dirname = tilde_expand(dirname); if (temp_dirname) { free(dirname); dirname = temp_dirname; } char *dir_name = dirname; if (IS_FILE_URI(p, text_len)) dir_name = dirname + FILE_URI_PREFIX_LEN; /* Resolve special expressions in the resulting directory. */ char *norm_path = dir_name; if ((*dir_name == '.' && dir_name[1] == '.' && dir_name[2] == '/') || strstr(dir_name, "/..")) norm_path = normalize_path(dir_name, strlen(dir_name)); directory = opendir(norm_path); if (norm_path != dir_name) free(norm_path); rl_filename_completion_desired = 1; } free(tmp_text); tmp_text = (char *)NULL; /* Now that we have some state, we can read the directory. If we found * a match among files in dir, break the loop and print the match */ match = 0; /* ############### COMPLETION FILTER ################## */ /* # This is the heart of the function # * #################################################### */ mode_t type; const int fuzzy_str_type = (conf.fuzzy_match == 1 && contains_utf8(filename) == 1) ? FUZZY_FILES_UTF8 : FUZZY_FILES_ASCII; int best_fz_score = 0; while (directory && (ent = readdir(directory))) { char *ename = ent->d_name; #if !defined(_DIRENT_HAVE_D_TYPE) struct stat attr; if (*dirname == '.' && !dirname[1]) xstrsncpy(tmp, ename, sizeof(tmp)); else snprintf(tmp, sizeof(tmp), "%s%s", dirname, ename); if (lstat(tmp, &attr) == -1) continue; type = get_dt(attr.st_mode); #else type = ent->d_type; #endif /* !_DIRENT_HAVE_D_TYPE */ /* First word: skip dirs if autocd is off, and non-dirs if * auto-open is off. */ if (skip_first_word(type, line_buffer_has_space) == 1) continue; /* Only dir names for cd */ if ((conf_suggestions == 0 || words_num > 1) && conf_fuzzy_match == 1 && is_cd_cmd == 1 && type != DT_DIR) continue; /* If the user entered nothing before TAB (e.g., "cd [TAB]") */ if (filename_len == 0) { /* Exclude "." and ".." as possible completions */ if (SELFORPARENT(ename)) continue; /* If 'cd', match only dirs or symlinks to dir */ if (is_cd_cmd == 1) match = filter_cd_cmd(dirname, ename, tmp, type); /* If 'open', allow only reg files, dirs, and symlinks */ else if (is_open_cmd == 1) match = filter_open_cmd(dirname, ename, tmp, type); /* If 'trash', skip block and character devices. */ else if (is_trash_cmd == 1) match = (type != DT_BLK && type != DT_CHR); /* No filter for everything else. Just print whatever is there. */ else match = 1; } /* There is at least one char to complete (e.g., "cd .[TAB]") */ else { if (do_regular_matching(filename) == 1) { if (check_match(filename, ename, filename_len) == 0) continue; } else { /* Fuzzy matching. */ if (flags & STATE_SUGGESTING) { if (get_best_fuzzy_match(filename, dirname, ename, filename_len, fuzzy_str_type, &best_fz_score) == 0) continue; } else { /* This is for tab completion: accept all matches. */ if (fuzzy_match(filename, ename, filename_len, fuzzy_str_type) == 0) continue; } } if (is_cd_cmd == 1) match = filter_cd_cmd(dirname, ename, tmp, type); else if (is_open_cmd == 1) match = filter_open_cmd(dirname, ename, tmp, type); else if (is_trash_cmd == 1) match = (type != DT_BLK && type != DT_CHR); else match = 1; } if (match == 1) break; } char *cur_match = (char *)NULL; /* readdir() returns NULL on reaching the end of the directory stream. * So that if ENT is not NULL, we have a match. */ if (ent) { /* Same as match == 1 */ cur_comp_type = TCMP_PATH; if (dirname && (dirname[0] != '.' || dirname[1])) { size_t len = strlen(users_dirname) + strlen(ent->d_name) + 1; cur_match = xnmalloc(len, sizeof(char)); snprintf(cur_match, len, "%s%s", users_dirname, ent->d_name); } else { cur_match = savestring(ent->d_name, strlen(ent->d_name)); } } /* Clear state. */ if ((flags & STATE_SUGGESTING) || !ent) { if (directory) { closedir(directory); directory = (DIR *)NULL; } free(dirname); dirname = (char *)NULL; free(filename); filename = (char *)NULL; free(users_dirname); users_dirname = (char *)NULL; } return cur_match; } /* Used by bookmarks completion */ static char * bookmarks_generator(const char *text, int state) { if (!bookmarks || bm_n == 0) return (char *)NULL; static int i; static size_t len; static int prefix; if (state == 0) { i = 0; prefix = (*text == 'b' && text[1] == ':') ? 2 : 0; len = strlen(text + prefix); } /* Look for bookmarks in bookmark names for a match */ while ((size_t)i < bm_n) { const char *name = bookmarks[i++].name; if (!name || !*name) continue; if ((conf.case_sens_list == 1 ? strncmp(name, text + prefix, len) : strncasecmp(name, text + prefix, len)) != 0) continue; if (prefix == 2) { char t[NAME_MAX + 3]; snprintf(t, sizeof(t), "b:%s", name); return strdup(t); } else { return strdup(name); } } return (char *)NULL; } /* Generate a list of internal commands and a brief description * for cmd */ static char * int_cmds_generator(const char *text, int state) { UNUSED(text); static int i; if (state == 0) i = 0; static char *const cmd_desc[] = { "/ (search for files)", "ac (archive/compress files)", "acd (toggle autocd)", "actions (manage actions-plugins)", "ad (dearchive/decompress files)", "alias (list aliases)", "ao (toggle auto-open)", "auto (set a temporary autocommand)", "b (change to the previously visited directory)", "bd (change to a parent directory)", "bl (create symbolic links in bulk)", "bb (sanitize non-ASCII filenames)", "bm (manage bookmarks)", "br (bulk-rename files)", "c (copy files)", "cd (change directory)", "cl (toggle columns)", "cmd (jump to the COMMANDS section in the manpage)", "colors (preview the current color scheme)", "config (edit the main configuration file)", "cs (manage color schemes)", "dup (duplicate files)", "ds (deselect files)", "exp (export filenames to a temporary file)", "ext (turn external/shell commands on/off)", "f (change to the next visited directory)", "fc (toggle the file-counter)", "ff (toggle list-directories-first)", "ft (set a file filter)", "fz (print directories full size - long view only)", "hh (toggle hidden files)", "history (manage the commands history)", "icons (toggle icons)", "j (jump to a visited directory)", "k (toggle follow-links - long view only)", "kk (toggle max-filename-len)", "kb (manage keybindings)", "l (create a symbolic link)", "le (edit a symbolic link)", "ll (toggle the long-view)", "lm (toggle the light-mode)", "log (manage logs)", "m (move/rename files)", "md (create directories)", "media (mount/unmount storage devices)", "mf (limit the number of listed files)", "mm (manage opening applications)", "mp (change to a mountpoint)", "msg (print program messages)", "n (create files/directories)", "net (manage remote resources)", "o (open file)", "oc (change ownership of files)", "opener (set a custom file opener)", "ow (open file with...)", "p (print file properties)", "pc (change permissions of files)", "pf (manage profiles)", "pg (run the file-pager)", "pin (pin a directory)", "pp (print file properties - follow links/full dir size)", "prompt (switch/edit prompt)", "q (quit)", "r (remove files)", "rf (refresh/clear the screen)", "rl (reload the configuration file)", "rr (remove files in bulk)", "sb (access the selection box)", "s (select files)", "st (change file sort order)", "stats (print file statistics)", "tag (tag files)", "te (toggle the executable bit on files)", "tips (print tips)", "t (trash files)", "u (restore trashed files using a menu)", "unpin (unpin the pinned directory)", "ver (print version information)", "view (preview files in the current directory)", "vv (copy and bulk-rename files at once)", "ws (switch workspaces)", "x (launch a new instance of clifm)", "X (launch a new instance of clifm as root)", NULL }; char *name; while ((name = cmd_desc[i++])) return strdup(name); return (char *)NULL; } /* Generate completions for command CMD using a modified version of * fish's manpages parser. */ static int gen_shell_cmd_comp(char *cmd) { if (!cmd || !*cmd || !data_dir || !*data_dir) return FUNC_FAILURE; char manpage_parser_file[PATH_MAX + 1]; snprintf(manpage_parser_file, sizeof(manpage_parser_file), "%s/%s/tools/manpages_comp_gen.py", data_dir, PROGRAM_NAME); char *c[] = {manpage_parser_file, "-k", cmd, NULL}; return launch_execv(c, FOREGROUND, E_MUTE); } /* Get short and long options for command CMD, store them in the EXT_OPTS * array and return the number of options found. */ static int get_shell_cmd_opts(char *cmd) { *ext_opts[0] = '\0'; if (!cmd || !*cmd || !user.home || (conf.suggestions == 1 && wrong_cmd == 1)) return FUNC_FAILURE; char p[PATH_MAX + 1]; snprintf(p, sizeof(p), "%s/.local/share/%s/completions/%s.clifm", user.home, PROGRAM_NAME, cmd); struct stat a; if (stat(p, &a) == -1) { /* Comp file does not exist. Try to generate via manpages_comp_gen.py */ if (gen_shell_cmd_comp(cmd) != FUNC_SUCCESS || stat(p, &a) == -1) return FUNC_FAILURE; } int fd; FILE *fp = open_fread(p, &fd); if (!fp) return FUNC_FAILURE; int n = 0; char line[NAME_MAX]; *line = '\0'; while (fgets(line, (int)sizeof(line), fp)) { if (n >= MAX_EXT_OPTS) break; if (!*line || *line == '#' || *line == '\n') continue; size_t l = strnlen(line, sizeof(line)); if (l > 0) { while (line[l - 1] == '\n') line[l - 1] = '\0'; } /* Get short option */ char *opt_str = strstr(line, "-s "); char *opt_end = (char *)NULL; if (opt_str && opt_str[1] && opt_str[2] && opt_str[3]) { opt_end = strchr(opt_str + 3, ' '); if (opt_end) *opt_end = '\0'; snprintf(ext_opts[n], MAX_EXT_OPTS_LEN, "-%s", opt_str + 3); if (opt_end) *opt_end = ' '; n++; } /* Get long option (-OPT or --OPT) */ char *long_str = strstr((opt_end && opt_end[1]) ? opt_end + 1 : line, "-l "); if (!long_str) long_str = strstr((opt_end && opt_end[1]) ? opt_end + 1 : line, "-o "); if (long_str && long_str[1] && long_str[2] && long_str[3]) { char *long_end = strchr(long_str + 3, ' '); if (long_end) *long_end = '\0'; /* Some long opts are written as optOPT: remove OPT */ /* long_str + 3 is the beginning of the option name, so that OPT could * begin at long_str + 4, but not before. */ char *t = long_str[4] ? long_str + 4 : (char *)NULL; while (t && *t) { if (*t >= 'A' && *t <= 'Z') { *t = '\0'; break; } t++; } if (long_str[1] == 'o') snprintf(ext_opts[n], MAX_EXT_OPTS_LEN, "-%s", long_str + 3); else snprintf(ext_opts[n], MAX_EXT_OPTS_LEN, "--%s", long_str + 3); if (long_end) *long_end = ' '; n++; } } *ext_opts[n] = '\0'; /* Mark the end of the options array */ fclose(fp); return n; } /* Used for history and search pattern completion */ static char * hist_generator(const char *text, int state) { if (!history) return (char *)NULL; static int i; static size_t len; char *name; if (state == 0) { i = 0; len = strlen(*text == '!' ? text + 1 : text); } while ((name = history[i++].cmd) != NULL) { if (*text == '!') { if (len == 0 || (*name == text[1] && strncmp(name, text + 1, len) == 0) || (conf.fuzzy_match == 1 && tabmode != STD_TAB && fuzzy_match((char *)(text + 1), name, len, FUZZY_HISTORY) > 0)) return strdup(name); } else { /* Restrict the search to what seems to be a pattern: * The string before the first slash or space (not counting the initial * slash, used to fire up the search function) must contain a pattern * metacharacter */ if (!*name || !name[1]) continue; char *ret = strpbrk(name + 1, conf.search_strategy == GLOB_ONLY ? " /*?[{" : " /*?[{|^+$."); if (!ret || *ret == ' ' || *ret == '/') continue; return strdup(name); } } return (char *)NULL; } /* Returns the path corresponding to be bookmark name TEXT */ static char * bm_paths_generator(const char *text, int state) { if (!bookmarks || bm_n == 0) return (char *)NULL; static int i; char *bname, *bpath; if (state == 0) i = 0; while (i < (int)bm_n) { bname = bookmarks[i].name; bpath = bookmarks[i].path; i++; if (!bname || !bpath || (conf.case_sens_list == 1 ? strcmp(bname, text) : strcasecmp(bname, text)) != 0) continue; const size_t plen = strlen(bpath); if (plen > 1 && bpath[plen - 1] == '/') bpath[plen - 1] = '\0'; char *p = abbreviate_file_name(bpath); char *ret = strdup(p ? p : bpath); if (p && p != bpath) free(p); return ret; } return (char *)NULL; } /* Used for the 'unset' command */ static char * env_vars_generator(const char *text, int state) { if (!environ) return (char *)NULL; static int i; static size_t len; const char *name; if (state == 0) { i = 0; len = strlen(text); } while ((name = environ[i++]) != NULL) { if (conf.case_sens_path_comp ? strncmp(name, text, len) == 0 : strncasecmp(name, text, len) == 0) { char *p = strchr(name, '='); if (!p) continue; *p = '\0'; char *q = strdup(name); *p = '='; return q; } } return (char *)NULL; } /* Complete environment variables ($VAR) */ static char * environ_generator(const char *text, int state) { if (!environ) return (char *)NULL; static int i; static size_t len; const char *name; if (state == 0) { i = 0; len = strlen(text + 1); } while ((name = environ[i++]) != NULL) { if (conf.case_sens_path_comp ? strncmp(name, text + 1, len) == 0 : strncasecmp(name, text + 1, len) == 0) { char *p = strrchr(name, '='); if (!p) continue; *p = '\0'; char tmp[NAME_MAX]; snprintf(tmp, sizeof(tmp), "$%s", name); char *q = strdup(tmp); *p = '='; return q; } } return (char *)NULL; } /* Expand string into matching path in the jump database. Used by * j, jc, and jp commands */ static char * jump_generator(const char *text, int state) { static int i; #ifndef _BE_POSIX const char *name; #else char *name; #endif /* !_BE_POSIX */ if (state == 0) i = 0; if (!jump_db) return (char *)NULL; /* Look for matches in the dirhist list */ while ((name = jump_db[i++].path) != NULL) { if (i > 0 && jump_db[i - 1].rank == JUMP_ENTRY_PURGED) continue; /* Exclude CWD */ if (name[1] == workspaces[cur_ws].path[1] && strcmp(name, workspaces[cur_ws].path) == 0) continue; /* Filter by parent */ if (rl_line_buffer[1] == 'p') { if ((conf.case_sens_dirjump == 1 ? strstr(workspaces[cur_ws].path, name) : xstrcasestr(workspaces[cur_ws].path, name)) == NULL) continue; } /* Filter by child */ else if (rl_line_buffer[1] == 'c') { if ((conf.case_sens_dirjump == 1 ? strstr(name, workspaces[cur_ws].path) : xstrcasestr(name, workspaces[cur_ws].path)) == NULL) continue; } if ((conf.case_sens_dirjump == 1 ? strstr(name, text) : xstrcasestr(name, (char *)text)) != NULL) return strdup(name); } return (char *)NULL; } static char * cschemes_generator(const char *text, int state) { if (!color_schemes) return (char *)NULL; static int i; static size_t len; const char *name; if (state == 0) { i = 0; len = strlen(text); } while ((name = color_schemes[i++]) != NULL) { if (strncmp(name, text, len) == 0) return strdup(name); } return (char *)NULL; } #ifndef _NO_PROFILES /* Used by profiles completion */ static char * profiles_generator(const char *text, int state) { if (!profile_names) return (char *)NULL; static int i; static size_t len; const char *name; if (state == 0) { i = 0; len = strlen(text); } while ((name = profile_names[i++]) != NULL) { if (strncmp(name, text, len) == 0) return strdup(name); } return (char *)NULL; } #endif /* !_NO_PROFILES */ static char * filenames_gen_text(const char *text, int state) { static filesn_t i; static size_t len = 0; static int fuzzy_str_type = 0; static int line_has_space = 0; static int is_cd_cmd = 0; static int (*cmp_func)(const char *, const char *, size_t) = strncmp; char *name; rl_filename_completion_desired = 1; if (state == 0) { i = 0; len = strlen(text); cmp_func = conf.case_sens_path_comp == 1 ? strncmp : strncasecmp; fuzzy_str_type = (conf.fuzzy_match == 1 && contains_utf8(text) == 1) ? FUZZY_FILES_UTF8 : FUZZY_FILES_ASCII; if (rl_line_buffer) { line_has_space = (strchr(rl_line_buffer, ' ') != NULL); is_cd_cmd = (*rl_line_buffer == 'c' && rl_line_buffer[1] == 'd' && rl_line_buffer[2] == ' '); } else { line_has_space = is_cd_cmd = 0; } } /* Check list of currently displayed files for a match */ while (i < files && (name = file_info[i].name) != NULL) { i++; /* If first word, filter files according to autocd and auto-open values. */ if (((conf.suggestions == 1 && words_num == 1) || line_has_space == 0) && ( (file_info[i - 1].dir == 1 && conf.autocd == 0) || (file_info[i - 1].dir == 0 && conf.auto_open == 0) )) continue; /* If cd, list only directories. */ if (is_cd_cmd == 1 && file_info[i - 1].dir == 0) continue; if (cmp_func(name, text, len) == 0) return strdup(name); if (conf.fuzzy_match == 0 || tabmode == STD_TAB || rl_point < rl_end) continue; if (len == 0 || fuzzy_match((char *)text, name, len, fuzzy_str_type) > 0) return strdup(name); } return (char *)NULL; } static char * dirhist_generator(const char *text, int state) { if (!old_pwd || dirhist_total_index == 0) return (char *)NULL; static int i; static size_t len; static int fuzzy_str_type; char *name; if (state == 0) { i = 0; len = strlen(text); fuzzy_str_type = (conf.fuzzy_match == 1 && contains_utf8(text) == 1) ? FUZZY_FILES_UTF8 : FUZZY_FILES_ASCII; } while ((name = old_pwd[i++]) != NULL) { if (*name == KEY_ESC) continue; if (!text || !*text) return strdup(name); if (conf.fuzzy_match == 1) { if (fuzzy_match((char *)text, name, len, fuzzy_str_type) > 0) return strdup(name); } else { if ((conf.case_sens_path_comp == 1 ? strstr(name, text) #if defined(_BE_POSIX) : xstrcasestr(name, (char *)text)) != NULL) #else : xstrcasestr(name, text)) != NULL) #endif /* _BE_POSIX */ return strdup(name); } } return (char *)NULL; } /* Used by commands completion (external commands only) */ static char * bin_cmd_generator_ext(const char *text, int state) { if (!bin_commands) return (char *)NULL; static int i; static size_t len; char *name; if (state == 0) { i = 0; len = strlen(text); } while ((name = bin_commands[i++]) != NULL) { if (is_internal_cmd(name, ALL_CMDS, 1, 1) == 1) continue; if (!text || !*text || (*text == *name && strncmp(name, text, len) == 0)) return strdup(name); } return (char *)NULL; } /* Used by commands completion */ static char * bin_cmd_generator(const char *text, int state) { if (!bin_commands) return (char *)NULL; static int i; static size_t len; const char *name; if (state == 0) { i = 0; len = strlen(text); } while ((name = bin_commands[i++]) != NULL) { if (!text || !*text) return strdup(name); if (*text == *name && strncmp(name, text, len) == 0) return strdup(name); } return (char *)NULL; } static char * sort_num_generator(const char *text, int state) { static size_t i; const char *name; if (state == 0) i = 0; const int num_text = atoi(text); if (num_text == INT_MIN || (conf.light_mode == 1 && !ST_IN_LIGHT_MODE(num_text))) return (char *)NULL; static const char *const sorts[] = { "none", "name", "size", "atime", "btime", "ctime", "mtime", "version", "extension", "inode", "owner", "group", "blocks", "links", "type", NULL }; while (i <= SORT_TYPES && (name = sorts[i++]) != NULL) { if (*name == *sorts[num_text] && strcmp(name, sorts[num_text]) == 0) return strdup(name); } return (char *)NULL; } static char * aliases_generator(const char *text, int state) { if (aliases_n == 0) return (char *)NULL; static int i; static size_t len; const char *name; if (state == 0) { i = 0; len = strlen(text); } while ((name = aliases[i++].name) != NULL) { if (strncmp(name, text, len) == 0) return strdup(name); } return (char *)NULL; } static char * kb_func_names_gen(const char *text, int state) { static int i; static size_t len; const char *name; if (state == 0) { i = 0; len = strlen(text); } while ((name = kb_cmds[i++].name) != NULL) { if (strncmp(name, text, len) == 0) return strdup(name); } return (char *)NULL; } static char * file_templates_generator(const char *text, int state) { static int i; static size_t len; const char *name; if (state == 0) { i = 0; len = strlen(text); } while ((name = file_templates[i++]) != NULL) { if (conf.case_sens_path_comp ? strncmp(name, text, len) == 0 : strncasecmp(name, text, len) == 0) return strdup(name); } return (char *)NULL; } static char * nets_generator(const char *text, int state) { if (!remotes) return (char *)NULL; static int i; static int is_unmount, is_mount; static size_t len; const char *name; if (state == 0) { i = 0; len = strlen(text); /* Let's find out whether we have a 'mount' or 'unmount' subcommands */ if (rl_line_buffer[4] == 'u' && (rl_line_buffer[5] == ' ' || strncmp(rl_line_buffer + 5, "nmount ", 7) == 0)) is_unmount = 1; else is_unmount = 0; if (rl_line_buffer[4] == 'm' && (rl_line_buffer[5] == ' ' || strncmp(rl_line_buffer + 5, "ount ", 5) == 0)) is_mount = 1; else is_mount = 0; } while ((name = remotes[i++].name) != NULL) { if ((conf.case_sens_path_comp ? strncmp(name, text, len) : strncasecmp(name, text, len)) == 0) { if (is_unmount == 1) { /* List only mounted resources */ if (i > 0 && remotes[i - 1].mounted == 1) return strdup(name); } else if (is_mount == 1) { /* List only unmounted resources */ if (i > 0 && remotes[i - 1].mounted == 0) return strdup(name); } else { return strdup(name); } } } return (char *)NULL; } static char * sort_name_generator(const char *text, int state) { static int i; static size_t len; const char *name; if (state == 0) { i = 0; len = strlen(text); } while ((name = sort_methods[i++].name) != NULL) { if (conf.light_mode == 1 && i > 0 && !ST_IN_LIGHT_MODE(sort_methods[i - 1].num)) continue; if (strncmp(name, text, len) == 0) return strdup(name); } return (char *)NULL; } static char * workspaces_generator(const char *text, int state) { static int i; static size_t len; if (state == 0) { i = 0; len = text ? strlen(text) : 0; } if (text && *text >= '1' && *text <= MAX_WS + '0' && !*(text + 1)) return (char *)NULL; while (i < MAX_WS) { if (cur_comp_type == TCMP_WS_PREFIX && !workspaces[i].path) { i++; /* If 'w:', skip unset workspaces */ continue; } if (!workspaces[i].name) { if (len == 0) { char t[MAX_INT_STR + 3]; snprintf(t, sizeof(t), "%d", i + 1); i++; return strdup(t); } } else { if (len == 0 || (TOUPPER(*workspaces[i].name) == TOUPPER(*text) && strncasecmp(workspaces[i].name, text, len) == 0)) { char *ret = strdup(workspaces[i].name); i++; return ret; } } i++; } return (char *)NULL; } static char * sel_entries_generator(const char *text, int state) { static int i; static size_t len; char *name; if (state == 0) { i = 0; len = strlen(text); } while (i < (int)sel_n && (name = sel_elements[i++].name) != NULL) { if (strncmp(name, text, len) == 0) { char *p = abbreviate_file_name(name); char *ret = strdup(p ? p : name); if (p && p != name) free(p); return ret; } } return (char *)NULL; } static char * prompts_generator(const char *text, int state) { if (prompts_n == 0) return (char *)NULL; static int i; static size_t len; const char *name; if (state == 0) { i = 0; len = strlen(text); } while (i < (int)prompts_n && (name = prompts[i++].name) != NULL) { if ((conf.case_sens_list == 1 ? strncmp(name, text, len) : strncasecmp(name, text, len)) == 0) return strdup(name); } return (char *)NULL; } /* Expand tilde and resolve dot expressions in the glob expression TEXT */ static char * expand_tilde_glob(char *text) { if (!text || !*text || (*text != '~' && !strstr(text, "/.."))) return (char *)NULL; char *ls = strrchr(text, '/'); if (!ls) return (char *)NULL; *ls = '\0'; char *q = normalize_path(text, strlen(text)); *ls = '/'; if (!q) return (char *)NULL; const char *g = ls[1] ? ls + 1 : (char *)NULL; size_t len = strlen(q) + 2 + (g ? strlen(g) : 0); char *tmp = xnmalloc(len, sizeof(char)); snprintf(tmp, len, "%s/%s", q, g); free(q); return tmp; } static char ** rl_mime_list(void) { #define WAIT_MSG " [wait...]" if (term_caps.suggestions != 0) { HIDE_CURSOR; fputs(WAIT_MSG, stdout); fflush(stdout); } char **t = xnmalloc((size_t)files + 2, sizeof(char *)); t[0] = xnmalloc(1, sizeof(char)); *t[0] = '\0'; t[1] = (char *)NULL; char buf[PATH_MAX + 1]; size_t n = 1; filesn_t i = files; while (--i >= 0) { if (file_info[i].user_access == 0 && file_info[i].type == DT_REG) continue; char *name = file_info[i].name; if (virtual_dir == 1) { *buf = '\0'; if (xreadlink(XAT_FDCWD, file_info[i].name, buf, sizeof(buf)) == -1 || !*buf) continue; name = buf; } char *m = (name && *name) ? xmagic(name, MIME_TYPE) : (char *)NULL; if (!m) continue; size_t j, found = 0; for (j = 1; j < n; j++) { if (*t[j] == *m && strcmp(t[j], m) == 0) { found = 1; break; } } if (found == 1) { free(m); continue; } else { t[n] = savestring(m, strlen(m)); free(m); n++; t[n] = (char *)NULL; } } if (term_caps.suggestions != 0) { MOVE_CURSOR_LEFT((int)sizeof(WAIT_MSG) - 1); ERASE_TO_RIGHT; UNHIDE_CURSOR; } if (n == 1) { free(t[0]); free(t); return (char **)NULL; } t = xnrealloc(t, n + 1, sizeof(char *)); if (rl_sort_completion_matches == 1) qsort(t, n, sizeof(*t), (QSFUNC *)compare_strings); #undef WAIT_MSG return t; } /* Returns the list of files in the current directory whose MIME type * contains the string TEXT. */ static char ** rl_mime_files(const char *text) { if (!text || !*text) return (char **)NULL; if (term_caps.suggestions != 0) { HIDE_CURSOR; fputs(" [wait...]", stdout); fflush(stdout); } char **t = xnmalloc((size_t)files + 2, sizeof(char *)); t[0] = xnmalloc(1, sizeof(char)); *t[0] = '\0'; char buf[PATH_MAX + 1]; filesn_t i, n = 1; for (i = 0; i < files; i++) { char *name = file_info[i].name; if (virtual_dir == 1) { *buf = '\0'; if (xreadlink(XAT_FDCWD, file_info[i].name, buf, sizeof(buf)) == -1 || !*buf) continue; name = buf; } char *m = (name && *name) ? xmagic(name, MIME_TYPE) : (char *)NULL; if (!m) continue; char *p = strstr(m, text); free(m); if (!p) continue; t[n] = savestring(name, strlen(name)); n++; } t[n] = (char *)NULL; if (term_caps.suggestions != 0) { MOVE_CURSOR_LEFT(10); ERASE_TO_RIGHT; UNHIDE_CURSOR; } if (n == 1) { free(t[0]); free(t); return (char **)NULL; } t = xnrealloc(t, (size_t)n + 1, sizeof(char *)); return t; } /* Return the list of matches for the glob expression TEXT or NULL if * there are no matches. */ static char ** rl_glob(char *text) { char *tmp = expand_tilde_glob(text); glob_t globbuf; if (glob(tmp ? tmp : text, 0, NULL, &globbuf) != FUNC_SUCCESS) { globfree(&globbuf); free(tmp); return (char **)NULL; } free(tmp); if (globbuf.gl_pathc == 1) { char **matches = xnmalloc(globbuf.gl_pathc + 2, sizeof(char *)); char *basename = strrchr(globbuf.gl_pathv[0], '/'); if (basename && *(++basename)) { const char c = *basename; *basename = '\0'; matches[0] = savestring(globbuf.gl_pathv[0], strlen(globbuf.gl_pathv[0])); *basename = c; matches[1] = savestring(basename, strlen(basename)); matches[2] = (char *)NULL; } else { matches[0] = savestring(globbuf.gl_pathv[0], strlen(globbuf.gl_pathv[0])); matches[1] = (char *)NULL; } globfree(&globbuf); return matches; } size_t i, j = 1; char **matches = xnmalloc(globbuf.gl_pathc + 3, sizeof(char *)); /* If /path/to/dir/GLOB, /path/to/dir goes to slot 0 */ char *last_word = get_last_chr(rl_line_buffer, ' ', rl_point); if (last_word) last_word++; else last_word = rl_line_buffer; char *str = (last_word && *last_word) ? unescape_str(last_word, 0) : (char *)NULL; char *word = str ? str : (char *)NULL; int char_copy = -1; char *basename = (char *)NULL; if (word && word[1]) { basename = strrchr(word, '/'); if (basename && *(++basename)) { char_copy = (int)*basename; *basename = '\0'; } } if (char_copy != -1) { matches[0] = savestring(word, strlen(word)); *basename = (char)char_copy; } else { matches[0] = xnmalloc(1, sizeof(char)); *matches[0] = '\0'; } free(str); for (i = 0; i < globbuf.gl_pathc; i++) { if (SELFORPARENT(globbuf.gl_pathv[i])) continue; matches[j] = savestring(globbuf.gl_pathv[i], strlen(globbuf.gl_pathv[i])); j++; } matches[j] = (char *)NULL; globfree(&globbuf); return matches; } #ifndef _NO_TRASH /* Return the list of currently trashed files matching TEXT, or NULL. */ static char ** rl_trashed_files(const char *text) { if (!trash_files_dir || !*trash_files_dir) return (char **)NULL; if (xchdir(trash_files_dir, NO_TITLE) == -1) return (char **)NULL; struct dirent **t = (struct dirent **)NULL; const int n = scandir(trash_files_dir, &t, NULL, alphasort); xchdir(workspaces[cur_ws].path, NO_TITLE); if (n == - 1) return (char **)NULL; if (n == 2) { free(t[0]); free(t[1]); free(t); return (char **)NULL; } char *p = unescape_str((char *)text, 0); char *f = p ? p : (char *)text; char **tfiles = xnmalloc((size_t)n + 2, sizeof(char *)); if (f) { tfiles[0] = savestring(f, strlen(f)); } else { tfiles[0] = xnmalloc(1, sizeof(char)); *tfiles[0] = '\0'; } int nn = 1, i; size_t tlen = f ? strlen(f) : 0; for (i = 0; i < n; i++) { char *name = t[i]->d_name; if (SELFORPARENT(name) || !f || strncmp(f, name, tlen) != 0) { free(t[i]); continue; } tfiles[nn] = savestring(name, strlen(name)); nn++; free(t[i]); } free(t); tfiles[nn] = (char *)NULL; /* If only one match */ if (nn == 2) { char *d = escape_str(tfiles[1]); free(tfiles[1]); tfiles[1] = (char *)NULL; if (d) { size_t len = strlen(d); tfiles[0] = xnrealloc(tfiles[0], len + 1, sizeof(char)); xstrsncpy(tfiles[0], d, len + 1); free(d); } } free(p); return tfiles; } #endif /* _NO_TRASH */ #ifndef _NO_TAGS static char * tags_generator(const char *text, int state) { if (tags_n == 0 || !tags) return (char *)NULL; static int i; static size_t len, p = 0; const char *name; if (state == 0) { i = 0; if (cur_comp_type == TCMP_TAGS_T) p = 2; else if (cur_comp_type == TCMP_TAGS_C) p = 1; else p = 0; len = *(text + p) ? strlen(text + p) : 0; } while ((name = tags[i++]) != NULL) { if (strncmp(name, text + p, len) != 0) continue; if (cur_comp_type == TCMP_TAGS_C) { char tmp[NAME_MAX]; snprintf(tmp, NAME_MAX, ":%s", name); return strdup(tmp); } else if (cur_comp_type == TCMP_TAGS_T) { char tmp[NAME_MAX]; snprintf(tmp, NAME_MAX, "t:%s", name); return strdup(tmp); } else { return strdup(name); } } return (char *)NULL; } static char * tag_entries_generator(const char *text, int state) { UNUSED(text); static int i; char *name; if (state == 0) i = 0; if (!tagged_files) return (char *)NULL; while (i < tagged_files_n && (name = tagged_files[i++]->d_name) != NULL) { if (SELFORPARENT(name)) continue; char *p = (char *)NULL, *q = name; if (strchr(name, '\\')) { p = unescape_str(name, 0); q = p; } reinsert_slashes(q); char tmp[PATH_MAX + 1], *r = (char *)NULL; snprintf(tmp, sizeof(tmp), "/%s", q); int free_tmp = 0; r = home_tilde(tmp, &free_tmp); q = strdup(r ? r : tmp); size_t len = q ? strlen(q) : 0; if (len > 1 && q[len - 1] == '/') q[len - 1] = '\0'; free(p); if (free_tmp == 1) free(r); return q; } return (char *)NULL; } static char ** check_tagged_files(char *tag) { if (!is_tag(tag)) return (char **)NULL; tagged_files_n = 0; char dir[PATH_MAX + 1]; snprintf(dir, sizeof(dir), "%s/%s", tags_dir, tag); int n = scandir(dir, &tagged_files, NULL, alphasort); if (n == -1) return (char **)NULL; if (n == 2) { free(tagged_files[0]); free(tagged_files[1]); free(tagged_files); tagged_files = (struct dirent **)NULL; return (char **)NULL; } tagged_files_n = n; char **matches = rl_completion_matches("", &tag_entries_generator); while (--n >= 0) free(tagged_files[n]); free(tagged_files); tagged_files = (struct dirent **)NULL; tagged_files_n = 0; return matches; } static char * get_cur_tag(void) { char *p = strrchr(rl_line_buffer, ':'); if (!p || !*(++p)) return (char *)NULL; char *q = p; while (*q) { if (*q == ' ' && (q != p || *(q - 1) != '\\')) { *q = '\0'; char *tag = savestring(p, strlen(p)); *q = ' '; if (is_tag(tag)) return tag; free(tag); } q++; } return (char *)NULL; } #endif /* _NO_TAGS */ /* Generate possible arguments for a shell command. Arguments should have * been previously loaded by get_ext_options() and stored in ext_opts array. */ static char * ext_options_generator(const char *text, int state) { static int i; static size_t len; const char *name; if (state == 0) { i = 0; len = strlen(text); } while (*(name = ext_opts[i++])) { if (strncmp(name, text, len) == 0) return strdup(name); } return (char *)NULL; } static size_t rl_count_words(char **w, char **start) { size_t start_word = 0; size_t full_word = 0; size_t n = count_words(&start_word, &full_word); char *lb = rl_line_buffer; static char first_word[NAME_MAX]; *first_word = '\0'; *w = (char *)NULL; if (full_word != 0) { lb[full_word] = '\0'; const char *q = lb + start_word; xstrsncpy(first_word, q, sizeof(first_word)); lb[full_word] = ' '; *w = first_word; if (lb && rl_end > 0 && lb[rl_end - 1] == ' ') n++; } *start = lb ? lb + start_word : (char *)NULL; return n; } /* Readline returned a single match: let's swap the first and second fields * of the returned array (A), so that the match is listed instead of * automatically inserted into the command line (by tab_complete() in tabcomp.c) */ static void rl_swap_fields(char ***a) { *a = xnrealloc(*a, 3, sizeof(char *)); (*a)[1] = strdup((*a)[0]); *(*a)[0] = '\0'; (*a)[2] = (char *)NULL; } /* Return a list of options for the command named CMD_NAME. */ static char ** fill_opts(const char *cmd_name, const char *word_start, const size_t w) { #define MAX_OPTS 23 struct cmd_opts_t { const char *cmd; char *opts[MAX_OPTS]; }; static struct cmd_opts_t cmd_opts[] = { {"acd", {"on", "off", "status", NULL}}, {"ao", {"on", "off", "status", NULL}}, {"ext", {"on", "off", "status", NULL}}, {"ff", {"on", "off", "status", NULL}}, {"hf", {"on", "off", "first", "last", "status", NULL}}, {"hh", {"on", "off", "first", "last", "status", NULL}}, {"hidden", {"on", "off", "first", "last", "status", NULL}}, {"pg", {"on", "off", "once", "status", NULL}}, {"pager", {"on", "off", "once", "status", NULL}}, {"cl", {"on", "off", NULL}}, {"icons", {"on", "off", NULL}}, {"ll", {"on", "off", NULL}}, {"lv", {"on", "off", NULL}}, {"lm", {"on", "off", NULL}}, {"fz", {"on", "off", NULL}}, {"config", {"edit", "dump", "reload", "reset", NULL}}, {"actions", {"list", "edit", NULL}}, {"log", {"cmd", "msg", NULL}}, {"mm", {"open", "info", "edit", "import", NULL}}, {"mime", {"open", "info", "edit", "import", NULL}}, {"pf", {"set", "list", "add", "del", "rename", NULL}}, {"profile", {"set", "list", "add", "del", "rename", NULL}}, {"prompt", {"set", "list", "unset", "edit", "reload", NULL}}, {"pwd", {"-L", "-P", NULL}}, {"tag", {"add", "del", "list", "list-full", "merge", "new", "rename", "untag", NULL}}, {"view", {"edit", "purge", NULL}}, {"net", {"mount", "unmount", "list", "edit", NULL}}, {"history", {"edit", "clear", "on", "off", "status", "show-time", NULL}}, {"help", {"archives", "autocommands", "basics", "bookmarks", "commands", "desktop-notifications", "dir-jumper", "file-details", "file-filters", "file-previews", "image-previews", "file-tags", "navigation", "plugins", "profiles", "remotes", "resource-opener", "search", "security", "selection", "theming", "trash", NULL}}, {"b", {"hist", "clear", NULL}}, {"f", {"hist", "clear", NULL}}, {"kb", {"list", "bind", "edit", "conflict", "reset", "readline", NULL}}, {"keybinds", {"list", "bind", "edit", "conflict", "reset", "readline", NULL}}, }; static char *c_opts[MAX_OPTS]; /* Clear c_opts. */ memset(c_opts, 0, sizeof(c_opts)); if (w == 2) { const size_t cmd_count = sizeof(cmd_opts) / sizeof(cmd_opts[0]); for (size_t i = 0; i < cmd_count; i++) { if (*cmd_name != *cmd_opts[i].cmd || strcmp(cmd_name, cmd_opts[i].cmd) != 0) continue; size_t j; for (j = 0; j < MAX_OPTS && cmd_opts[i].opts[j] != NULL; j++) c_opts[j] = cmd_opts[i].opts[j]; break; } } else if (w == 3 && word_start && (strncmp(word_start, "log msg ", 8) == 0 || strncmp(word_start, "log cmd ", 8) == 0)) { c_opts[0] = "list"; c_opts[1] = "on"; c_opts[2] = "off"; c_opts[3] = "status"; c_opts[4] = "clear"; c_opts[5] = NULL; } #undef MAX_OPTS return !c_opts[0] ? (char **)NULL : c_opts; } /* Return the common initial prefix for all strings in MATCHES. */ static char * get_common_prefix(char **matches) { if (!matches || !matches[0]) return strdup(""); const char *first_str = matches[0]; size_t prefix_len = strlen(first_str); for (size_t i = 1; matches[i]; i++) { size_t j = 0; while (j < prefix_len && matches[i][j] == first_str[j]) j++; if (j == 0) return strdup(""); prefix_len = j; } return savestring(first_str, prefix_len); } /* Return an array of options, matching TEXT, for the command CMD_NAME. */ static char ** complete_options(const char *text, const char *cmd_name, const char *cmd_start, const size_t words_n) { if (!cmd_name || !cmd_start) return (char **)NULL; char **c_opts = fill_opts(cmd_name, cmd_start, words_n); if (!c_opts || !c_opts[0]) return (char **)NULL; size_t n; for (n = 0; c_opts[n]; n++); char **matches = xnmalloc(n + 2, sizeof(char *)); const size_t len = (!text || !*text) ? 0 : strlen(text); const char *name; n = 1; size_t i = 0; while ((name = c_opts[i++]) != NULL) { if (len == 0 || strncmp(name, text, len) == 0) matches[n++] = strdup(name); } if (n == 1) { /* No matches. */ free(matches); return (char **)NULL; } if (n == 2) { /* A single match. */ matches[0] = matches[1]; matches[1] = (char *)NULL; } else { /* Multiple matches. */ matches[n] = (char *)NULL; matches[0] = get_common_prefix(matches + 1); } return matches; } static char * groups_generator(const char *text, int state) { #if defined(__ANDROID__) UNUSED(text); UNUSED(state); return (char *)NULL; #else static size_t len; const struct group *p; if (state == 0) len = text[1] ? wc_xstrlen(text + 1) : 0; while ((p = getgrent())) { if (!p->gr_name) break; if (len == 0 || strncmp(p->gr_name, text + 1, len) == 0) return strdup(p->gr_name); } return (char *)NULL; #endif /* __ANDROID__ */ } static char * owners_generator(const char *text, int state) { #if defined(__ANDROID__) UNUSED(text); UNUSED(state); return (char *)NULL; #else static size_t len; const struct passwd *p; if (state == 0) len = wc_xstrlen(text); while ((p = getpwent())) { if (!p->pw_name) break; if (len == 0 || strncmp(p->pw_name, text, len) == 0) return strdup(p->pw_name); } return (char *)NULL; #endif /* __ANDROID__ */ } static char * users_generator(const char *text, int state) { #if defined(__ANDROID__) UNUSED(text); UNUSED(state); return (char *)NULL; #else static size_t len; const struct passwd *p; if (state == 0) len = strlen(text); while ((p = getpwent())) { if (!p->pw_name) break; if (len == 0 || strncmp(p->pw_name, text, len) == 0) { char t[NAME_MAX]; snprintf(t, sizeof(t), "~%s", p->pw_name); return strdup(t); } } return (char *)NULL; #endif /* __ANDROID__ */ } #ifndef _NO_TAGS static int tag_complete(const char *text, char *start) { char *l = start; int comp = 0; if (l[1] && l[2] == ' ') { switch (l[1]) { case 'a': /* fallthough */ case 'u': if (text && *text == ':') { /* We have a tag name */ comp = 1; cur_comp_type = TCMP_TAGS_C; } else if (l[1] == 'u') { /* We have a tagged file */ comp = 2; } break; case 'd': /* fallthough */ case 'l': /* fallthough */ case 'm': /* fallthough */ // case 'n': /* Just a new tag name: no completion */ case 'y': if (l[1] == 'd' || l[1] == 'l') flags |= MULTI_SEL; comp = 1; cur_comp_type = TCMP_TAGS_S; break; default: break; } } else { /* MATCH LONG OPTIONS */ if (strncmp(l, "tag ", 4) != 0) { return comp; } char *p = l + 4; if (!*p || strncmp(p, "untag ", 6) == 0) { if (text && *text == ':') { /* We have a tag name */ comp = 1; cur_comp_type = TCMP_TAGS_C; } else if (*p == 'u') { /* We have a tagged file */ comp = 2; } } else if (strncmp(p, "del ", 4) == 0 || strncmp(p, "list ", 5) == 0 /*|| strncmp(p, "new ", 4) == 0 */ || strncmp(p, "rename ", 7) == 0 || strncmp(p, "merge ", 6) == 0) { if (*p == 'd' || *p == 'r' || *p == 'l') flags |= MULTI_SEL; comp = 1; cur_comp_type = TCMP_TAGS_S; } else if (text && *text == ':') { comp = 1; cur_comp_type = TCMP_TAGS_C; } } return comp; } #endif /* !_NO_TAGS */ static int check_file_type_opts(const char c) { switch (c) { case 'b': return stats.block_dev > 0; case 'c': return stats.char_dev > 0; case 'd': return stats.dir > 0; case 'D': return stats.empty_dir > 0; #ifdef SOLARIS_DOORS case 'O': return stats.door > 0; case 'P': return stats.port > 0; #endif /* SOLARIS_DOORS */ case 'f': return stats.reg > 0; case 'F': return stats.empty_reg > 0; case 'h': return stats.multi_link > 0; case 'l': return stats.link > 0; case 'L': return stats.broken_link > 0; case 'p': return stats.fifo > 0; case 's': return stats.socket > 0; case 'x': return stats.exec > 0; case 'o': return stats.other_writable > 0; case 't': return stats.sticky > 0; case 'u': return stats.suid > 0; case 'g': return stats.sgid > 0; case 'C': return stats.caps > 0; default: return 0; } } static char * file_types_opts_generator(const char *text, int state) { UNUSED(text); static int i; if (state == 0) i = 0; static char *const ft_opts[] = { "b (Block device)", "c (Character device)", "d (Directory)", "D (Empty directory)", #ifdef SOLARIS_DOORS "O (Door)", "P (Port)", #endif /* SOLARIS_DOORS */ "f (Regular file)", "F (Empty regular file)", "h (Multi-hardlink file)", "l (Symbolic link)", "L (Broken symbolic link)", "p (FIFO-pipe)", "s (Socket)", "x (Executable)", "o (Other writable)", "t (Sticky)", "u (SUID)", "g (SGID)", "C (Capabilities)", NULL }; const char *name; while ((name = ft_opts[i++])) { if (check_file_type_opts(*name) == 1) return strdup(name); } return (char *)NULL; } static char * file_types_generator(const char *text, int state) { static filesn_t i; const char *name; if (state == 0) i = 0; char *ret = (char *)NULL; while (i < files && (name = file_info[i].name)) { switch (*text) { case 'b': if (file_info[i].type == DT_BLK) ret = strdup(name); break; case 'c': if (file_info[i].type == DT_CHR) ret = strdup(name); break; case 'C': if (file_info[i].color == ca_c) ret = strdup(name); break; case 'd': if (file_info[i].dir == 1) ret = strdup(name); break; case 'D': if (file_info[i].color == ed_c) ret = strdup(name); break; #ifdef SOLARIS_DOORS case 'O': if (file_info[i].type == DT_DOOR) ret = strdup(name); break; case 'P': if (file_info[i].type == DT_PORT) ret = strdup(name); break; #endif /* SOLARIS_DOORS */ case 'f': if (file_info[i].type == DT_REG) ret = strdup(name); break; case 'F': if (file_info[i].color == ef_c) ret = strdup(name); break; case 'h': if (file_info[i].dir == 0 && file_info[i].linkn > 1) ret = strdup(name); break; case 'l': if (file_info[i].type == DT_LNK) ret = strdup(name); break; case 'L': if (file_info[i].color == or_c) ret = strdup(name); break; case 'o': if (file_info[i].color == tw_c || file_info[i].color == ow_c) ret = strdup(name); break; case 't': if (file_info[i].color == tw_c || file_info[i].color == st_c) ret = strdup(name); break; case 'p': if (file_info[i].type == DT_FIFO) ret = strdup(name); break; case 's': if (file_info[i].type == DT_SOCK) ret = strdup(name); break; case 'x': if (file_info[i].exec == 1) ret = strdup(name); break; case 'u': if (file_info[i].color == su_c) ret = strdup(name); break; case 'g': if (file_info[i].color == sg_c) ret = strdup(name); break; default: break; } i++; if (ret) return ret; } return (char *)NULL; } static char ** rl_fastback(const char *s) { if (!s || !*s) return (char **)NULL; char *p = fastback(s); if (!p) return (char **)NULL; if (!*p) { free(p); return (char **)NULL; } char **matches = xnmalloc(2, sizeof(char *)); matches[0] = savestring(p, strlen(p)); matches[1] = (char *)NULL; free(p); return matches; } #ifndef _NO_LIRA /* Return 1 if the command STR accepts 'edit' as subcommand. Otherwise, * return 0. */ static int cmd_takes_edit(const char *str) { static char *const cmds[] = { "actions", "bm", "bookmarks", "config", "cs", "colorschemes", "history", "kb", "keybinds", "mm", "mime", "net", "prompt", "view", NULL }; size_t i; for (i = 0; cmds[i]; i++) if (*str == *cmds[i] && strcmp(str + 1, cmds[i] + 1) == 0) return 1; return 0; } /* Return 1 if command in STR is an internal command and takes a text editor as * parameter. Otherwise, return 0. */ static int is_edit(const char *str, const size_t words_n) { if (!str || !*str) return 0; if (words_n > 2 && *str == 'r' && str[1] == 'r' && str[2] == ' ') return 1; char *space = strchr(str, ' '); if (!space || space[1] != 'e' || !space[2]) return 0; *space = '\0'; if (cmd_takes_edit(str) != 1) { *space = ' '; return 0; } *space = ' '; if (strncmp(space + 2, "dit ", 4) != 0) return 0; return 1; } #endif /* !_NO_LIRA */ static char ** complete_bookmark_names(char *text, const size_t words_n, int *exit_status) { *exit_status = FUNC_SUCCESS; /* rl_line_buffer is either "bm " or "bookmarks " */ const char *arg = rl_line_buffer + (rl_line_buffer[1] == 'o' ? 9 : 2); if (arg && arg[1] == 'a' && (arg[2] == ' ' || strncmp(arg + 1, "add ", 4) == 0)) { if (words_n > 3) /* Do not complete anything after "bm add FILE" */ rl_attempted_completion_over = 1; else /* 'bm add': complete with path completion */ *exit_status = FUNC_FAILURE; return (char **)NULL; } /* If not 'bm add' complete with bookmarks */ #ifndef _NO_SUGGESTIONS if (suggestion.type != FILE_SUG) rl_attempted_completion_over = 1; #endif /* !_NO_SUGGESTIONS */ char *p = unescape_str(text, 0); char **matches = rl_completion_matches(p ? p : text, &bookmarks_generator); free(p); if (!matches) return (char **)NULL; cur_comp_type = TCMP_BOOKMARK; return matches; } static char ** complete_ranges(const char *text) { char *dash = strchr(text, '-'); if (!dash || dash[1] < '0' || dash[1] > '9') return (char **)NULL; *dash = '\0'; if (!is_number(text) || !is_number(dash + 1)) { *dash = '-'; return (char **)NULL; } const int a = atoi(text) - 1; const int b = atoi(dash + 1) - 1; *dash = '-'; if (a < 0 || b < 0 || a >= b || (filesn_t)b >= files) return (char **)NULL; char **matches = xnmalloc((size_t)(b - a) + 3, sizeof(char *)); matches[0] = savestring("", 1); size_t j = 1; for (int i = a; i <= b; i++) matches[j++] = savestring(file_info[i].name, file_info[i].bytes); matches[j] = NULL; cur_comp_type = TCMP_RANGES; return matches; } #ifndef _NO_LIRA static char ** complete_open_with(char *text, char *start) { char *arg = start + 3; /* "ow " */ char *space = strrchr(arg, ' '); if (space) *space = '\0'; char **matches = mime_open_with_tab(arg, text, 0); if (space) *space = ' '; if (!matches) return (char **)NULL; cur_comp_type = TCMP_OPENWITH; return matches; } #endif /* !_NO_LIRA */ static char ** complete_file_type_filter(const char *text) { char **matches = (char **)NULL; if (!text[1]) { matches = rl_completion_matches(text, &file_types_opts_generator); if (!matches) return (char **)NULL; if (!matches[1]) rl_swap_fields(&matches); cur_comp_type = TCMP_FILE_TYPES_OPTS; return matches; } if (text[2]) return (char **)NULL; matches = rl_completion_matches(text + 1, &file_types_generator); if (!matches) return (char **)NULL; if (!matches[1]) rl_swap_fields(&matches); else flags |= MULTI_SEL; cur_comp_type = TCMP_FILE_TYPES_FILES; return matches; } static char ** complete_mime_type_filter(const char *text) { char **matches = (char **)NULL; if (text[1]) { if ((matches = rl_mime_files(text + 1)) == NULL) return (char **)NULL; cur_comp_type = TCMP_MIME_FILES; /* Same as TCMP_FILE_TYPES_FILES */ rl_filename_completion_desired = 1; flags |= MULTI_SEL; return matches; } if ((matches = rl_mime_list()) == NULL) return (char **)NULL; cur_comp_type = TCMP_MIME_LIST; return matches; } static char ** complete_glob(char *text) { char **matches = (char **)NULL; char *p = (*rl_line_buffer == '/' && rl_end > 1 && !strchr(rl_line_buffer + 1, ' ') && !strchr(rl_line_buffer + 1, '/')) ? (text + 1) : text; if ((matches = rl_glob(p)) == NULL) return (char **)NULL; #ifndef _NO_SUGGESTIONS if (conf.suggestions == 1 && wrong_cmd == 1) recover_from_wrong_cmd(); #endif /* !_NO_SUGGESTIONS */ if (!matches[1]) rl_swap_fields(&matches); cur_comp_type = TCMP_GLOB; rl_filename_completion_desired = 1; if (words_num > 1) flags |= MULTI_SEL; return matches; } /* Return a pointer to the beginning of the last name in the current * command line. */ static char * get_cmd_name(void) { if (!rl_line_buffer || !*rl_line_buffer) return (char *)NULL; char *lb = rl_line_buffer; char *opt = (char *)NULL; char *name = (char *)NULL; /* Truncate the command line before the first option word (starting * with a dash): "sudo cmd --opt" -> "sudo cmd" */ while (*lb) { if (*lb == ' ' && lb[1] == '-') { *lb = '\0'; opt = lb; break; } lb++; } /* Get a pointer to the beginning of the last name in the truncated * command line. */ lb = rl_line_buffer; while (*lb) { if (!name && *lb != ' ') { name = lb; } else { if (*lb == ' ' && lb[1] != ' ') name = lb + 1; } lb++; } if (opt) *opt = ' '; return name; } static char ** complete_shell_cmd_opts(const char *text) { char cmd[NAME_MAX + 1]; *cmd = '\0'; char *name = get_cmd_name(); if (!name) return (char **)NULL; char *space = strchr(name, ' '); if (space) { *space = '\0'; xstrsncpy(cmd, name, sizeof(cmd)); *space = ' '; } if (*cmd && get_shell_cmd_opts(cmd) > 0) return rl_completion_matches(text, &ext_options_generator); return (char **)NULL; } #ifndef _NO_TAGS static char ** complete_tag_names(const char *text, char *start) { char **matches = (char **)NULL; int comp = tag_complete(text, start); if (comp != 1 && comp != 2) return (char **)NULL; if (comp == 1) { matches = rl_completion_matches(text, &tags_generator); if (!matches) { cur_comp_type = TCMP_NONE; return (char **)NULL; } return matches; } /* comp == 2 * Let's match tagged files for the untag function. */ char *c_tag = get_cur_tag(); matches = check_tagged_files(c_tag); free(c_tag); if (!matches) return (char **)NULL; cur_comp_type = TCMP_TAGS_F; return matches; } static char ** complete_tag_names_t(char *text) { cur_comp_type = TCMP_TAGS_T; char *p = unescape_str(text, 0); char **matches = rl_completion_matches(p ? p : text, &tags_generator); free(p); if (!matches) { cur_comp_type = TCMP_NONE; return (char **)NULL; } flags |= MULTI_SEL; return matches; } static char ** complete_tags(char *text) { if (!text[2]) return complete_tag_names_t(text); free(cur_tag); cur_tag = savestring(text + 2, strlen(text + 2)); char **matches = check_tagged_files(cur_tag); if (!matches) { free(cur_tag); cur_tag = (char *)NULL; return (char **)NULL; } if (!matches[1]) rl_swap_fields(&matches); cur_comp_type = TCMP_TAGS_F; return matches; } #endif /* !_NO_TAGS */ static char ** complete_bookmark_paths(char *text) { char *p = unescape_str(text, 0); char **matches = rl_completion_matches(p ? p : text, &bm_paths_generator); free(p); if (!matches) return (char **)NULL; if (!matches[1]) rl_swap_fields(&matches); cur_comp_type = TCMP_BM_PATHS; return matches; } static char ** complete_bookmark_names_b(char *text) { char *p = unescape_str(text, 0); char **matches = rl_completion_matches(p ? p : text, &bookmarks_generator); free(p); if (!matches) return (char **)NULL; flags |= MULTI_SEL; cur_comp_type = TCMP_BM_PREFIX; return matches; } static char ** complete_bookmarks(char *text, const size_t words_n) { if (text[2]) { char **matches = complete_bookmark_paths(text + 2); if (matches) return matches; } if (words_n > 0 || conf.autocd == 1 || conf.auto_open == 1) return complete_bookmark_names_b(text); return (char **)NULL; } static char ** complete_ownership(const char *text) { char **matches = (char **)NULL; rl_attempted_completion_over = 1; char *sc = strchr(text, ':'); if (!sc) { matches = rl_completion_matches(text, &owners_generator); endpwent(); } else { matches = rl_completion_matches(sc, &groups_generator); endgrent(); } if (matches) { cur_comp_type = TCMP_OWNERSHIP; return matches; } return (char **)NULL; } static char ** complete_dirhist(char *text, const size_t words_n) { rl_attempted_completion_over = 1; if (words_n > 2) return (char **)NULL; char *p = unescape_str(text, 0); char **matches = rl_completion_matches(p ? p : text, &dirhist_generator); free(p); if (!matches) return (char **)NULL; if (!matches[1]) rl_swap_fields(&matches); cur_comp_type = TCMP_DIRHIST; return matches; } static char ** complete_backdir(char *text, const size_t words_n) { rl_attempted_completion_over = 1; if (words_n != 2) return (char **)NULL; int n = 0; char *p = unescape_str(text, 0); char **matches = get_bd_matches(p ? p : text, &n, BD_TAB); free(p); if (!matches) return (char **)NULL; cur_comp_type = TCMP_BACKDIR; return matches; } static char ** complete_workspaces(char *text) { rl_attempted_completion_over = 1; if (words_num > 2) return (char **)NULL; rl_sort_completion_matches = 0; char *t = (*text == 'w' && text[1] == ':') ? text + 2 : text; char *p = unescape_str(t, 0); const enum comp_type ct = cur_comp_type; cur_comp_type = t != text ? TCMP_WS_PREFIX : TCMP_WORKSPACES; char **matches = rl_completion_matches(p ? p : t, &workspaces_generator); free(p); if (matches) return matches; cur_comp_type = ct; rl_sort_completion_matches = 1; return (char **)NULL; } static int int_cmd_no_filename(char *start) { char *line = start; char *space = strchr(line, ' '); if (!space) return 0; *space = '\0'; flags |= STATE_COMPLETING; if (is_internal_cmd(line, NO_FNAME_NUM, 1, 1)) { rl_attempted_completion_over = 1; *space = ' '; flags &= ~STATE_COMPLETING; return 1; } flags &= ~STATE_COMPLETING; *space = ' '; return 0; } static char ** complete_net(char *text) { rl_attempted_completion_over = 1; char *p = unescape_str(text, 0); char **matches = rl_completion_matches(p ? p : text, &nets_generator); free(p); if (!matches) return (char **)NULL; cur_comp_type = TCMP_NET; return matches; } static char ** complete_sort_num(const char *text, const size_t words_n) { rl_attempted_completion_over = 1; if (words_n != 2) return (char **)NULL; const int n = atoi(text); if (n < 0 || n > SORT_TYPES) return (char **)NULL; char **matches = rl_completion_matches(text, &sort_num_generator); if (!matches) return (char **)NULL; cur_comp_type = TCMP_SORT; return matches; } static char ** complete_sort(const char *text, const size_t words_n) { rl_attempted_completion_over = 1; if (words_n > 2) return (char **)NULL; if (text && *text && is_number(text)) return complete_sort_num(text, words_n); char **matches = rl_completion_matches(text, &sort_name_generator); if (!matches) return (char **)NULL; cur_comp_type = TCMP_SORT; return matches; } #ifndef _NO_PROFILES static char ** complete_profiles(char *text, const size_t words_n) { rl_attempted_completion_over = 1; if (words_n > 3) return (char **)NULL; const char *lb = rl_line_buffer; if (strncmp(lb, "pf add ", 7) == 0 || strncmp(lb, "pf list ", 8) == 0 || strncmp(lb, "profile add ", 12) == 0 || strncmp(lb, "profile list ", 13) == 0) return (char **)NULL; char *p = unescape_str(text, 0); char **matches = rl_completion_matches(p ? p : text, &profiles_generator); free(p); if (!matches) return (char **)NULL; cur_comp_type = TCMP_PROF; return matches; } #endif /* !_NO_PROFILES */ static char ** complete_colorschemes(char *text, const size_t words_n) { rl_attempted_completion_over = 1; if (words_n != 2) return (char **)NULL; char *p = unescape_str(text, 0); char **matches = rl_completion_matches(p ? p : text, &cschemes_generator); free(p); if (!matches) return (char **)NULL; cur_comp_type = TCMP_CSCHEME; return matches; } static char ** complete_file_templates(char *text) { rl_attempted_completion_over = 1; char *p = unescape_str(text, 0); char **matches = rl_completion_matches(p ? p : text, &file_templates_generator); free(p); if (!matches) return (char **)NULL; cur_comp_type = TCMP_FILE_TEMPLATES; return matches; } static char ** complete_desel(const char *text) { rl_attempted_completion_over = 1; char **matches = sel_n > 0 ? rl_completion_matches(text, &sel_entries_generator) : NULL; if (!matches) return (char **)NULL; cur_comp_type = TCMP_DESEL; return matches; } #ifndef _NO_TRASH static char ** complete_trashed_files(const char *text, const enum comp_type flag) { rl_attempted_completion_over = 1; char **matches = trash_n > 0 ? rl_trashed_files(text) : NULL; if (!matches) return (char **)NULL; if (tabmode == STD_TAB && conf.colorize == 1) /* Only used to remove trash extension from files so * that we can correctly set file color by extension. */ flags |= STATE_COMPLETING; cur_comp_type = flag; return matches; } #endif /* !_NO_TRASH */ static char ** complete_prompt_names(char *text, const size_t words_n) { rl_attempted_completion_over = 1; if (words_n > 3) return (char **)NULL; char *p = unescape_str(text, 0); char **matches = rl_completion_matches(p ? p : text, &prompts_generator); free(p); if (!matches) return (char **)NULL; cur_comp_type = TCMP_PROMPTS; return matches; } static char ** complete_kb_func_names(const char *text, const size_t words_n) { rl_attempted_completion_over = 1; if (words_n != 3) return (char **)NULL; char **matches = rl_completion_matches(text, &kb_func_names_gen); if (!matches) return (char **)NULL; cur_comp_type = TCMP_NET; /* Same behavior */ return matches; } static char ** complete_alias_names(const char *text, const size_t words_n) { rl_attempted_completion_over = 1; if (words_n > 2 || aliases_n == 0) return (char **)NULL; char **matches = rl_completion_matches(text, &aliases_generator); if (!matches) return (char **)NULL; cur_comp_type = TCMP_ALIAS; return matches; } static char ** complete_jump(const char *text) { char **matches = rl_completion_matches(text, &jump_generator); if (!matches) return (char **)NULL; if (!matches[1]) rl_swap_fields(&matches); cur_comp_type = TCMP_JUMP; return matches; } static char ** complete_sel_keyword(const char *text, const size_t words_n) { if (words_n == 1 && text[1] != ':') /* Only "s:" is allowed as first word */ return (char **)NULL; char **matches = rl_completion_matches("", &sel_entries_generator); if (!matches) return (char **)NULL; if (!matches[1]) rl_swap_fields(&matches); cur_comp_type = TCMP_SEL; return matches; } static char ** get_filename_by_eln(const filesn_t n) { const int is_cd_cmd = (rl_line_buffer && *rl_line_buffer == 'c' && rl_line_buffer[1] == 'd' && rl_line_buffer[2] == ' '); if (!file_info[n].name || !*file_info[n].name || (is_cd_cmd == 1 && file_info[n].dir == 0)) return (char **)NULL; char **matches = xnmalloc(2, sizeof(char *)); matches[0] = savestring(file_info[n].name, file_info[n].bytes); matches[1] = NULL; #ifndef _NO_SUGGESTIONS if (suggestion_buf) clear_suggestion(CS_FREEBUF); #endif /* !_NO_SUGGESTIONS */ return matches; } static char ** complete_eln(const char *text, const size_t words_n, char *cmd_name) { filesn_t n = 0; if (!is_number(text) || (n = xatof(text)) < 1 || n > files) return (char **)NULL; if (words_n == 1) { /* First word */ if ((alt_prompt != 0 && alt_prompt != FILES_PROMPT) || (file_info[n - 1].dir == 1 && conf.autocd == 0) || (file_info[n - 1].dir == 0 && conf.auto_open == 0)) return (char **)NULL; } else { /* Second word or more */ if (alt_prompt != 0 || should_expand_eln(text, cmd_name) == 0) return (char **)NULL; } char **matches = get_filename_by_eln(n - 1); if (!matches) return (char **)NULL; rl_filename_completion_desired = 1; cur_comp_type = TCMP_ELN; return matches; } static char ** complete_history(char *text) { char *p = unescape_str(text, 0); char **matches = rl_completion_matches(p ? p : text, &hist_generator); free(p); if (matches) cur_comp_type = TCMP_HIST; return matches; } static char ** complete_bookmarks_prompt(const char *text) { rl_attempted_completion_over = 1; char **matches = (char **)NULL; if (text && *text && is_number(text)) { const int n = atoi(text); if (n < 1 || (size_t)n > bm_n) goto CHECK_NAME; matches = xnmalloc(2, sizeof(char *)); const char *name = bookmarks[n - 1].name; matches[0] = savestring(name, strlen(name)); matches[1] = (char *)NULL; cur_comp_type = TCMP_NET; /* Same behavior as 'net'. */ return matches; } CHECK_NAME: matches = rl_completion_matches(text, &bookmarks_generator); if (matches) cur_comp_type = TCMP_NET; return matches; } static char ** complete_cmd_desc(const char *text) { char **matches = rl_completion_matches(text, &int_cmds_generator); if (matches) cur_comp_type = TCMP_CMD_DESC; return matches; } static char ** complete_fastback(const char *text) { char **matches = rl_fastback(text); if (!matches) return (char **)NULL; if (*matches[0] != '/' || matches[0][1]) rl_filename_completion_desired = 1; cur_comp_type = TCMP_PATH; return matches; } static char ** complete_users(const char *text) { char **matches = rl_completion_matches(text, &users_generator); endpwent(); if (matches) { rl_filename_completion_desired = 1; cur_comp_type = TCMP_USERS; } return matches; } static char ** complete_environ(const char *text) { char **matches = rl_completion_matches(text, &environ_generator); if (matches) cur_comp_type = TCMP_ENVIRON; return matches; } /* Handle tab completion. * * This function has three main blocks: * 1) General expansions: These expansions can be performed in any part of * the current input string (mostly special expansions, like ELNs, * bookmarks, sel keyword, tags, and so on). * 2) First word only (mostly command names). * 3) Second word or more (mostly command parameters). * * If the function returns NULL, readline will attempt to perform path * completion (via my_rl_path_completion()). * */ char ** my_rl_completion(const char *text, const int start, const int end) { /* 0. First, we need some initialization. */ UNUSED(end); cur_comp_type = TCMP_NONE; flags &= ~MULTI_SEL; char **matches = (char **)NULL; char *cmd_name = (char *)NULL; char *cmd_start = (char *)NULL; const size_t words_n = rl_count_words(&cmd_name, &cmd_start); char *s = cmd_start; static size_t sudo_len = 0; if (sudo_len == 0) sudo_len = (sudo_cmd && *sudo_cmd) ? strlen(sudo_cmd) : 0; #ifndef _NO_HIGHLIGHT if (conf.highlight == 1 && rl_point < rl_end) /* Prevent the inserted word from being printed using the current color, * say, options or quotes color. * Drawback: whatever comes next to our word will be decolorized as well. * But no color is better than wrong (and partially) colored word. */ cur_color = (char *)NULL; #endif /* !_NO_HIGHLIGHT */ /* Do not complete when the cursor is on a word. E.g., dir/_ilename */ if (rl_point < rl_end && rl_line_buffer[rl_point] != ' ') { rl_attempted_completion_over = 1; return (char **)NULL; } /* ########################## * # 1. GENERAL EXPANSIONS # * ########################## */ /* These expansions are made no matter the word position in the cmd line. */ /* ##### ELN EXPANSION ##### */ /* We allow ELN expansion in some alternative prompts (FILES_PROMPT), * mostly those taking filenames, such as 'n' and 'm' (interactive). * The check for alternative prompts is made in complete_eln() itself. */ if (*text >= '1' && *text <= '9' && (matches = complete_eln(text, words_n, cmd_name))) return matches; /* alt_prompt is set (non-zero) whenever we are using an alternative prompt. */ if (alt_prompt != 0) goto FIRST_WORD_COMP; /* #### FILE TYPE EXPANSION #### */ if (*text == '=' && (matches = complete_file_type_filter(text))) return matches; /* #### MIME TYPE EXPANSION #### */ if (*text == '@' && (matches = complete_mime_type_filter(text))) return matches; /* #### FASTBACK EXPANSION #### */ if (*text == '.' && text[1] == '.' && text[2] == '.' && (matches = complete_fastback(text))) return matches; /* #### WILDCARDS EXPANSION #### */ const char *g = strpbrk(text, GLOB_CHARS); /* Expand only glob expressions in the last path component */ if (g && !(rl_end == 2 && *rl_line_buffer == '/' && rl_line_buffer[1] == '*') && !strchr(g, '/') && access(text, F_OK) != 0) { if ((matches = complete_glob((char *)text))) return matches; } /* #### USERS EXPANSION (~) #### */ if (*text == '~' && text[1] != '/' && (matches = complete_users(text + 1))) return matches; /* ##### ENVIRONMENT VARIABLES ##### */ if (*text == '$' && text[1] != '(' && (matches = complete_environ(text))) return matches; #ifndef _NO_TAGS /* ##### TAGS (t:) ##### */ if (tags_n > 0 && *text == 't' && text[1] == ':' && (matches = complete_tags((char *)text))) return matches; #endif /* !_NO_TAGS */ /* #### BOOKMARKS (b:) #### */ if (*text == 'b' && text[1] == ':' && (matches = complete_bookmarks((char *)text, words_n))) return matches; /* ##### WORKSPACES (w:) ##### */ if ((words_n > 1 || conf.autocd == 1) && *text == 'w' && text[1] == ':' && (matches = complete_workspaces((char *)text))) return matches; /* ##### SEL KEYWORD (both "sel" and "s:") ##### */ if (sel_n > 0 && *text == 's' && (text[1] == ':' || strcmp(text, "sel") == 0) && (matches = complete_sel_keyword(text, words_n))) return matches; /* ##### HISTORY COMPLETION ("!") ##### */ if (*text == '!' && (matches = complete_history((char *)text))) return matches; FIRST_WORD_COMP: if (start == 0) { /* ####################### * # 2. FIRST WORD ONLY # * ####################### */ /* #### OWNERSHIP EXPANSION #### * Used only by the 'oc' command to edit files ownership. */ if (alt_prompt == OWNERSHIP_PROMPT) return complete_ownership(text); /* Bookmarks screen: expand bookmark names */ if (alt_prompt == BOOKMARKS_PROMPT) return complete_bookmarks_prompt(text); /* #### CMD #### */ if (alt_prompt == 0 && ((*text == 'c' && text[1] == 'm' && text[2] == 'd' && !text[3]) || strcmp(text, "commands") == 0)) return complete_cmd_desc(text); /* SEARCH PATTERNS COMPLETION */ if (alt_prompt == 0 && *text == '/' && text[1] == '*' && (matches = complete_history((char *)text))) return matches; /* Complete with files in CWD */ if ((conf.autocd == 1 || conf.auto_open == 1) && (alt_prompt == 0 || alt_prompt == FILES_PROMPT) && *text != '/' && (matches = rl_completion_matches(text, &filenames_gen_text))) { cur_comp_type = TCMP_PATH; return matches; } /* If neither autocd nor auto-open, try to complete with command names, * except when TEXT is "/" */ if (alt_prompt == 0 && (conf.autocd == 0 || *text != '/' || text[1]) && (matches = rl_completion_matches(text, &bin_cmd_generator))) { cur_comp_type = TCMP_CMD; return matches; } return (char **)NULL; } /* ########################## * # 3. SECOND WORD OR MORE # * ########################## */ if (alt_prompt != 0) /* Disable completion for alternative prompts. */ return (char **)NULL; /* Complete options for internal commands. */ if ((matches = complete_options(text, cmd_name, cmd_start, words_n))) return matches; /* Command names completion for words after process separator: ; | && */ if (words_n == 1 && rl_end > 0 && rl_line_buffer[rl_end - 1] != ' ' /* No command name contains slashes. */ && (*text != '/' || !strchr(text, '/'))) { if ((matches = rl_completion_matches(text, &bin_cmd_generator))) { cur_comp_type = TCMP_CMD; return matches; } } /* #### SUDO COMPLETION (e.g., "sudo ") #### */ if (sudo_len > 0 && words_n == 2 && s && strncmp(s, sudo_cmd, sudo_len) == 0 && s[sudo_len] == ' ') { if ((matches = rl_completion_matches(text, &bin_cmd_generator_ext))) { cur_comp_type = TCMP_CMD; return matches; } } #ifndef _NO_TAGS /* #### TAG NAMES COMPLETION #### */ /* 't? TAG' and 't? :tag' */ if (tags_n > 0 && s && *s == 't' && rl_end > 2 && (matches = complete_tag_names((char *)text, s))) return matches; #endif /* !_NO_TAGS */ /* #### DIRECTORY HISTORY COMPLETION (dh) #### */ if (s && *s == 'd' && s[1] == 'h' && s[2] == ' ' && !strchr(text, '/')) return complete_dirhist((char *)text, words_n); /* #### BACKDIR COMPLETION (bd) #### */ if (*text != '/' && s && *s == 'b' && s[1] == 'd' && s[2] == ' ') return complete_backdir((char *)text, words_n); #ifndef _NO_LIRA /* #### OPENING APPS FOR INTERNAL CMDS TAKING 'EDIT' AS SUBCOMMAND */ if (s && is_edit(s, words_n) == 1 && config_file) { /* mime_open_with_tab needs a filename to match against the * mimelist file and get the list of opening applications. * Now, since here we are listing apps to open config files, * i.e. text files, any config file will do the trick, in this * case, the main config file (CONFIG_FILE). */ if ((matches = mime_open_with_tab(config_file, text, 1))) { cur_comp_type = TCMP_OPENWITH; return matches; } } /* #### OPEN WITH #### */ if (rl_end > 4 && s && *s == 'o' && s[1] == 'w' && s[2] == ' ' && s[3] && s[3] != ' ' && words_n >= 3) return complete_open_with((char *)text, s); #endif /* _NO_LIRA */ /* #### PROMPT (only for 'prompt set') #### */ if (s && *s == 'p' && s[1] == 'r' && strncmp(s, "prompt set " , 11) == 0) return complete_prompt_names((char *)text, words_n); #ifndef _NO_TRASH /* ### UNTRASH ### */ if (s && *s == 'u' && (s[1] == ' ' || (s[1] == 'n' && (strncmp(s, "untrash ", 8) == 0 || strncmp(s, "undel ", 6) == 0)))) return complete_trashed_files(text, TCMP_UNTRASH); /* ### TRASH DEL ### */ if (s && *s == 't' && (s[1] == ' ' || s[1] == 'r') && (strncmp(s, "t del ", 6) == 0 || strncmp(s, "trash del ", 10) == 0)) return complete_trashed_files(text, TCMP_TRASHDEL); #endif /* !_NO_TRASH */ /* ### DESELECT COMPLETION (ds, desel) ### */ if (s && *s == 'd' && (strncmp(s, "ds ", 3) == 0 || strncmp(s, "desel ", 6) == 0)) return complete_desel(text); /* ### DIRJUMP COMPLETION ### */ /* j, jc, jp commands */ if (s && *s == 'j' && (s[1] == ' ' || ((s[1] == 'c' || s[1] == 'p') && s[2] == ' '))) return complete_jump(text); /* ### BOOKMARKS COMPLETION ### */ if (s && *s == 'b' && (s[1] == 'm' || s[1] == 'o') && (strncmp(s, "bm ", 3) == 0 || strncmp(s, "bookmarks ", 10) == 0)) { int exit_status = FUNC_SUCCESS; matches = complete_bookmark_names((char *)text, words_n, &exit_status); if (exit_status == FUNC_SUCCESS) return matches; } /* ### FILE TEMPLATES COMPLETION ('n/new' command) ### */ if (file_templates && s && *s == 'n' && (s[1] == ' ' || (s[1] == 'e' && s[2] == 'w' && s[3] == ' '))) { char *p = strrchr(text, '@'); if (p) return complete_file_templates(p + 1); } /* ### ALIASES COMPLETION ### */ if (s && *s == 'a' && strncmp(s, "alias ", 6) == 0 && strncmp(s + 6, "import ", 7) != 0) return complete_alias_names(text, words_n); /* ### KEYBIND FUNCS COMPLETION ### */ if (s && *s == 'k' && strncmp(s, "kb bind ", 8) == 0) return complete_kb_func_names(text, words_n); /* ### COLOR SCHEMES COMPLETION ### */ if (conf.colorize == 1 && s && *s == 'c' && ((s[1] == 's' && s[2] == ' ') || strncmp(s, "colorschemes ", 13) == 0)) return complete_colorschemes((char *)text, words_n); #ifndef _NO_PROFILES /* ### PROFILES COMPLETION ### */ if (s && *s == 'p' && (strncmp(s, "pf ", 3) == 0 || strncmp(s, "profile ", 8) == 0)) return complete_profiles((char *)text, words_n); #endif /* !_NO_PROFILES */ /* ### SORT COMMAND COMPLETION ### */ if (s && *s == 's' && (strncmp(s, "st ", 3) == 0 || strncmp(s, "sort ", 5) == 0)) return complete_sort(text, words_n); /* ### WORKSPACES COMPLETION ### */ if (s && *s == 'w' && strncmp(s, "ws ", 3) == 0) return complete_workspaces((char *)text); /* ### COMPLETIONS FOR THE 'UNSET' COMMAND ### */ if (s && *s == 'u' && strncmp(s, "unset ", 6) == 0) return rl_completion_matches(text, &env_vars_generator); /* ### NET COMMAND COMPLETION ### */ if (s && *s == 'n' && strncmp(s, "net ", 4) == 0) return complete_net((char *)text); /* If we have an internal command not dealing with filenames, * do not perform any further completion. */ if (s && int_cmd_no_filename(s) == 1) return (char **)NULL; /* Arguments for shell commands. */ if (*text == '-' && (matches = complete_shell_cmd_opts(text))) return matches; /* ELN ranges */ if (*text >= '0' && *text <= '9' && (matches = complete_ranges(text))) return matches; /* Finally, try to complete with filenames in CWD. */ if ((matches = rl_completion_matches(text, &filenames_gen_text))) { cur_comp_type = TCMP_PATH; return matches; } /* ### PATH COMPLETION ### */ /* If none of the above, readline will attempt path completion * instead via my_rl_path_completion(). */ return (char **)NULL; } /* Load readline initialization file (inputrc) * Check order: * 1) INPUTRC environment variable * 2) ~/.config/clifm/readline.clifm * 3) ~/.inputrc * 4) /etc/inputrc * If neither 1 nor 2 exist, readline will try to read 3 and 4 by default) */ static void set_rl_init_file(void) { struct stat a; char *p = getenv("INPUTRC"); if (xargs.secure_env != 1 && xargs.secure_env_full != 1 && p && stat(p, &a) != -1) { rl_read_init_file(p); return; } if (!config_dir_gral || !*config_dir_gral) return; size_t len = strlen(config_dir_gral) + 16; char *rl_file = xnmalloc(len, sizeof(char)); snprintf(rl_file, len, "%s/readline.clifm", config_dir_gral); /* This file should have been imported by import_rl_file (config.c). * In case it wasn't, let's create here a skeleton: if not found, * readline refuses to colorize history lines. */ if (stat(rl_file, &a) == -1) { int fd; FILE *fp = open_fwrite(rl_file, &fd); if (!fp) { err('w', PRINT_PROMPT, "%s: fopen: %s: %s\n", PROGRAM_NAME, rl_file, strerror(errno)); free(rl_file); return; } fprintf(fp, "# This is readline's configuration file for %s\n", PROGRAM_NAME_UPPERCASE); fclose(fp); } rl_read_init_file(rl_file); free(rl_file); } #ifdef CLIFM_TEST_INPUT /* Use the file specified by CLIFM_TEST_INPUT_FILE environment variable as an * alternative input source instead of stdin. * Each line in this file will be executed as if it were entered in the * command line. */ static void set_rl_input_file(void) { char *input_file = getenv("CLIFM_TEST_INPUT_FILE"); if (!input_file || !*input_file) { xerror(_("%s: An input file must be provided via the " "CLIFM_TEST_INPUT_FILE environment variable\n"), PROGRAM_NAME); UNHIDE_CURSOR; exit(FUNC_FAILURE); } FILE *fstream = fopen(input_file, "r"); if (!fstream) { xerror("%s: '%s': %s\n", PROGRAM_NAME, input_file, strerror(errno)); UNHIDE_CURSOR; exit(FUNC_FAILURE); } rl_instream = fstream; } #endif /* CLIFM_TEST_INPUT */ int initialize_readline(void) { #ifdef CLIFM_TEST_INPUT set_rl_input_file(); #endif /* CLIFM_TEST_INPUT */ #ifdef VANILLA_READLINE return FUNC_SUCCESS; #endif /* VANILLA_READLINE */ /* Set the name of the program using readline. Mostly used for * conditional constructs in the inputrc file. */ rl_readline_name = PROGRAM_NAME; disable_rl_conflicting_kbinds(); set_rl_init_file(); /* The character that introduces a history event. Defaults to '!'. * Setting this to 0 inhibits history expansion. */ // history_expansion_char = '!'; /* Enable tab auto-completion for commands (in PATH) in case of * first entered string (if autocd and/or auto-open are enabled, check * for paths as well). The second and later entered strings will * be autocompleted with paths instead, just like in Bash, or with * completion for custom commands. I use a custom completion * function to add custom completions, since readline's internal * completer only performs path completion */ /* Define a function for path completion. * NULL means to use filename_entry_function (), the default * filename completer. */ rl_completion_entry_function = my_rl_path_completion; /* Pointer to alternative function to create matches. * Function is called with TEXT, START, and END. * START and END are indices in RL_LINE_BUFFER saying what the * boundaries of TEXT are. * If this function exists and returns NULL then call the value of * rl_completion_entry_function to try to match, otherwise use the * array of strings returned. */ rl_attempted_completion_function = my_rl_completion; rl_ignore_completion_duplicates = 1; /* I'm using here a custom quoting function. If not specified, * readline uses the default internal function. */ rl_filename_quoting_function = my_rl_quote; /* Tell readline what char to use for quoting. This is only the * readline internal quoting function, and for custom ones, like the * one I use above. However, custom quoting functions, though they * need to define their own quoting chars, won't be called at all * if this variable isn't set. */ rl_completer_quote_characters = "\"'"; rl_completer_word_break_characters = " "; /* Whenever readline finds any of the following chars, it will call * the quoting function. */ rl_filename_quote_characters = " \t\n\"\\'`@$><=,;|&{[()]}?!*^#"; /* According to readline documentation, the following string is * the default and the one used by Bash: " \t\n\"\\'`@$><=;|&{(". */ /* Executed immediately before calling the completer function, it * tells readline if a space char, which is a word break character * (see the above rl_completer_word_break_characters variable) is * quoted or not. If it is, readline then passes the whole string * to the completer function (e.g., "user\ file"), and if not, only * wathever it found after the space char (e.g., "file"). * Thanks to George Brocklehurst for pointing out this function: * https://thoughtbot.com/blog/tab-completion-in-gnu-readline. */ rl_char_is_quoted_p = quote_detector; /* Define a function to handle suggestions and syntax highlighting. */ rl_getc_function = my_rl_getc; /* This function is executed inmediately before path completion. So, * if the string to be completed is, for instance, "user\ file" (see * the above comment), this function should return the dequoted * string so it won't conflict with system filenames: you want * "user file", because "user\ file" does not exist, and, in this * latter case, readline won't find any matches. */ rl_filename_dequoting_function = unescape_str; /* Initialize the keyboard bindings function. */ readline_kbinds(); /* Copy the list of quote chars to a global variable to be used * later by some of the program functions like split_str(), * my_rl_quote(), is_quote_char(), and my_rl_dequote(). */ quote_chars = savestring(rl_filename_quote_characters, strlen(rl_filename_quote_characters)); return FUNC_SUCCESS; } clifm-1.26.3/src/readline.h000066400000000000000000000025211506632037700154310ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* readline.h */ #ifndef READLINE_H #define READLINE_H __BEGIN_DECLS int initialize_readline(void); int is_quote_char(const char c); char **my_rl_completion(const char *text, int start, int end); char *my_rl_path_completion(const char *text, int state); int rl_get_y_or_n(const char *msg_str, char default_answer); char *rl_no_hist(const char *prompt_str, const int tabcomp); char *secondary_prompt(const char *prompt_str, const char *line); __END_DECLS #endif /* READLINE_H */ clifm-1.26.3/src/remotes.c000066400000000000000000000243451506632037700153270ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* remote.c -- functions to manage remotes */ #include "helpers.h" #include #include #include "aux.h" #include "file_operations.h" #include "history.h" #include "init.h" #include "jump.h" #include "listing.h" #include "messages.h" #include "misc.h" #include "navigation.h" #include "sanitize.h" #include "spawn.h" static int remotes_list(void) { if (remotes_n == 0) { printf(_("%s: No remotes defined. Run 'net edit' to add one.\n"), PROGRAM_NAME); return FUNC_SUCCESS; } size_t i; for (i = 0; i < remotes_n; i++) { if (!remotes[i].name) continue; printf(_("Name: %s%s%s\n"), BOLD, remotes[i].name, df_c); if (remotes[i].desc) printf(_(" Comment: %s\n"), remotes[i].desc); if (remotes[i].mountpoint) printf(_(" Mountpoint: %s\n"), remotes[i].mountpoint); if (remotes[i].mount_cmd) printf(_(" Mount command: %s\n"), remotes[i].mount_cmd); if (remotes[i].unmount_cmd) printf(_(" Unmount command: %s\n"), remotes[i].unmount_cmd); printf(_(" Auto-unmount: %s\n"), (remotes[i].auto_unmount == 0) ? _("false") : _("true")); printf(_(" Auto-mount: %s\n"), (remotes[i].auto_mount == 0) ? _("false") : _("true")); printf(_(" Mounted: %s%s%s\n"), BOLD, (remotes[i].mounted == 0) ? _("No") : _("Yes"), df_c); if (i < remotes_n - 1) puts(""); } return FUNC_SUCCESS; } static int dequote_remote_name(char *name) { char *deq = (char *)NULL; if (strchr(name, '\\')) { deq = unescape_str(name, 0); if (deq) { xstrsncpy(name, deq, strlen(deq) + 1); free(deq); } else { xerror("net: %s: Error unescaping resource name\n", name); return FUNC_FAILURE; } } return FUNC_SUCCESS; } /* Get the index of the remote named NAME from the remotes list. Returns * this index in case of success or -1 in case of error */ static int get_remote(char *name) { if (!name || !*name) return (-1); if (dequote_remote_name(name) == FUNC_FAILURE) return (-1); int i = (int)remotes_n, found = 0; while (--i >= 0) { if (*name == *remotes[i].name && strcmp(name, remotes[i].name) == 0) { found = 1; break; } } if (found == 0) { xerror(_("net: '%s': No such remote\n"), name); return (-1); } if (!remotes[i].mountpoint) { xerror(_("net: No mountpoint specified for '%s'\n"), remotes[i].name); return (-1); } return i; } static int create_mountpoint(const int i) { char *cmd[] = {"mkdir", "-p", remotes[i].mountpoint, NULL}; if (launch_execv(cmd, FOREGROUND, E_NOFLAG) != FUNC_SUCCESS) { xerror("net: '%s': %s\n", remotes[i].mountpoint, strerror(errno)); return FUNC_FAILURE; } return FUNC_SUCCESS; } static int cd_to_mountpoint(const int i) { free(workspaces[cur_ws].path); workspaces[cur_ws].path = savestring(remotes[i].mountpoint, strlen(remotes[i].mountpoint)); add_to_jumpdb(workspaces[cur_ws].path); add_to_dirhist(workspaces[cur_ws].path); dir_changed = 1; reload_dirlist(); return FUNC_SUCCESS; } static int print_cd_error(const int i) { xerror("net: '%s': %s\n", remotes[i].mountpoint, strerror(errno)); return FUNC_FAILURE; } static int print_no_mount_cmd_error(const int i) { xerror(_("net: No mount command specified for '%s'\n"), remotes[i].name); return FUNC_FAILURE; } static int remotes_mount(char *name) { int i = get_remote(name); if (i == -1) return FUNC_FAILURE; if (!remotes[i].mount_cmd) return print_no_mount_cmd_error(i); if (xargs.secure_cmds == 1 && sanitize_cmd(remotes[i].mount_cmd, SNT_NET) != FUNC_SUCCESS) return FUNC_FAILURE; /* If mountpoint doesn't exist, create it */ struct stat attr; if (stat(remotes[i].mountpoint, &attr) == -1 && create_mountpoint(i) == FUNC_FAILURE) return FUNC_FAILURE; /* Make sure mountpoint is not populated and run the mount command */ if (count_dir(remotes[i].mountpoint, CPOP) <= 2 && launch_execl(remotes[i].mount_cmd) != FUNC_SUCCESS) return FUNC_FAILURE; if (xchdir(remotes[i].mountpoint, SET_TITLE) == -1) return print_cd_error(i); int exit_status = FUNC_SUCCESS; if (conf.autols == 1) { exit_status = cd_to_mountpoint(i); } else { printf(_("net: '%s': Changed to mountpoint (%s)\n"), remotes[i].name, remotes[i].mountpoint); } remotes[i].mounted = 1; return exit_status; } static int remotes_unmount(char *name) { int i = get_remote(name); if (i == -1) return FUNC_FAILURE; if (remotes[i].mounted == 0) { xerror(_("net: '%s': Not mounted\n"), remotes[i].name); return FUNC_FAILURE; } if (!remotes[i].mountpoint) { xerror(_("net: Error getting mountpoint for '%s'\n"), remotes[i].name); return FUNC_FAILURE; } if (!remotes[i].unmount_cmd) { xerror(_("net: No unmount command for '%s'\n"), remotes[i].name); return FUNC_FAILURE; } if (xargs.secure_cmds == 1 && sanitize_cmd(remotes[i].unmount_cmd, SNT_NET) != FUNC_SUCCESS) return FUNC_FAILURE; /* Get out of mountpoint before unmounting */ int reload_files = 0; size_t mlen = strlen(remotes[i].mountpoint); if (strncmp(remotes[i].mountpoint, workspaces[cur_ws].path, mlen) == 0) { if (mlen > 0 && remotes[i].mountpoint[mlen - 1] == '/') { mlen--; remotes[i].mountpoint[mlen] = '\0'; } char *p = strrchr(remotes[i].mountpoint, '/'); if (!p) { xerror(_("net: '%s': Error getting parent directory\n"), remotes[i].mountpoint); return FUNC_FAILURE; } *p = '\0'; errno = 0; if (xchdir(remotes[i].mountpoint, SET_TITLE) == FUNC_FAILURE) { *p = '/'; xerror("net: '%s': %s\n", remotes[i].mountpoint, strerror(errno)); return FUNC_FAILURE; } free(workspaces[cur_ws].path); workspaces[cur_ws].path = savestring(remotes[i].mountpoint, strlen(remotes[i].mountpoint)); *p = '/'; if (conf.autols == 1) reload_files = 1; } if (launch_execl(remotes[i].unmount_cmd) != FUNC_SUCCESS) return FUNC_FAILURE; if (reload_files == 1) reload_dirlist(); remotes[i].mounted = 0; return FUNC_SUCCESS; } static int remotes_edit(char *app) { if (!remotes_file) { xerror(_("net: Remotes file is undefined\n")); return FUNC_FAILURE; } struct stat attr; if (stat(remotes_file, &attr) == -1) { xerror("net: '%s': %s\n", remotes_file, strerror(errno)); return errno; } const time_t mtime_bfr = attr.st_mtime; const int ret = open_config_file(app, remotes_file); if (ret != FUNC_SUCCESS) return ret; if (stat(remotes_file, &attr) == -1) { xerror("net: '%s': %s\n", remotes_file, strerror(errno)); return errno; } if (mtime_bfr != attr.st_mtime) { free_remotes(0); load_remotes(); print_reload_msg(NULL, NULL, _("File modified. Remotes reloaded.\n")); } return FUNC_SUCCESS; } int remotes_function(char **args) { if (xargs.stealth_mode == 1) { printf("%s: net: %s\n", PROGRAM_NAME, STEALTH_DISABLED); return FUNC_SUCCESS; } if (!args[1] || (*args[1] == 'l' && strcmp(args[1], "list") == 0)) return remotes_list(); if (IS_HELP(args[1])) { puts(_(NET_USAGE)); return FUNC_SUCCESS; } if (*args[1] == 'e' && strcmp(args[1], "edit") == 0) return remotes_edit(args[2]); if (*args[1] == 'u' && (!*(args[1] + 1) || strcmp(args[1], "unmount") == 0)) { if (!args[2]) { fprintf(stderr, "%s\n", _(NET_USAGE)); return FUNC_FAILURE; } return remotes_unmount(args[2]); } if (*args[1] == 'm' && (!*(args[1] + 1) || strcmp(args[1], "mount") == 0)) { if (!args[2]) { fprintf(stderr, "%s\n", _(NET_USAGE)); return FUNC_FAILURE; } return remotes_mount(args[2]); } return remotes_mount(args[1]); } int automount_remotes(void) { if (remotes_n == 0) return FUNC_SUCCESS; int i = (int)remotes_n; int exit_status = FUNC_SUCCESS; while (--i >= 0) { if (remotes[i].name && remotes[i].auto_mount == 1 && remotes[i].mountpoint && remotes[i].mount_cmd) { if (xargs.secure_cmds == 1 && sanitize_cmd(remotes[i].mount_cmd, SNT_NET) != FUNC_SUCCESS) continue; struct stat attr; if (stat(remotes[i].mountpoint, &attr) == -1) { char *cmd[] = {"mkdir", "-p", remotes[i].mountpoint, NULL}; if (launch_execv(cmd, FOREGROUND, E_NOFLAG) != FUNC_SUCCESS) continue; } else { if (count_dir(remotes[i].mountpoint, CPOP) > 2) continue; } int ret = 0; printf(_("%s: net: %s: Mounting remote...\n"), PROGRAM_NAME, remotes[i].name); if ((ret = launch_execl(remotes[i].mount_cmd)) != FUNC_SUCCESS) { err('w', PRINT_PROMPT, _("net: '%s': Mount command failed with " "error code %d\n"), remotes[i].name, ret); exit_status = FUNC_FAILURE; } else { remotes[i].mounted = 1; } } } return exit_status; } int autounmount_remotes(void) { if (remotes_n == 0) return FUNC_SUCCESS; int i = (int)remotes_n, exit_status = FUNC_SUCCESS; while (--i >= 0) { if (remotes[i].name && remotes[i].auto_unmount == 1 && remotes[i].mountpoint && remotes[i].unmount_cmd) { if (xargs.secure_cmds == 1 && sanitize_cmd(remotes[i].unmount_cmd, SNT_NET) != FUNC_SUCCESS) continue; if (count_dir(remotes[i].mountpoint, CPOP) <= 2) continue; int dir_change = 0; if (*workspaces[cur_ws].path == *remotes[i].mountpoint && strcmp(remotes[i].mountpoint, workspaces[cur_ws].path) == 0) { xchdir("/", NO_TITLE); dir_change = 1; } int ret = 0; printf(_("%s: net: %s: Unmounting remote...\n"), PROGRAM_NAME, remotes[i].name); if ((ret = launch_execl(remotes[i].unmount_cmd)) != FUNC_SUCCESS) { xerror(_("%s: net: %s: Unmount command failed with " "error code %d\n"), PROGRAM_NAME, remotes[i].name, ret); exit_status = FUNC_FAILURE; } if (dir_change == 1) xchdir(workspaces[cur_ws].path, NO_TITLE); } } return exit_status; } clifm-1.26.3/src/remotes.h000066400000000000000000000020641506632037700153260ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* remotes.h */ #ifndef REMOTES_H #define REMOTES_H __BEGIN_DECLS int remotes_function(char **args); int automount_remotes(void); int autounmount_remotes(void); __END_DECLS #endif /* REMOTES_H */ clifm-1.26.3/src/sanitize.c000066400000000000000000000252761506632037700155030ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* sanitize.c -- functions for commands and environment sanitization */ #include "helpers.h" #include #ifndef _BE_POSIX # include /* _PATH_STDPATH */ #endif /* _BE_POSIX */ #include #include /* getrlimit(3), setrlimit(3) */ #include /* close(2), sysconf(3) */ #include "aux.h" #include "checks.h" /* is_number() */ #include "misc.h" #include "sanitize.h" #define UNSAFE_CMD "Unsafe command. Consult the manpage for more information" /* If PATH cannot be retrieved from any other source, let's use this value. */ #if !defined(_PATH_STDPATH) && !defined(_CS_PATH) # define MINIMAL_PATH "/usr/local/bin:/bin:/usr/bin:/sbin:/usr/sbin" #endif /* Unset environ: little implementation of clearenv(3), not available * on some systems (not POSIX). */ static void xclearenv(void) { #if !defined(__NetBSD__) && !defined(__HAIKU__) && !defined(__APPLE__) \ && !defined(__TERMUX__) /* This seems to be enough (it is it according to the Linux/FreeBSD * manpage for clearenv(3)). */ environ = NULL; #else static char *namebuf = NULL; static size_t lastlen = 0; while (environ != NULL && environ[0] != NULL) { size_t len = strcspn(environ[0], "="); if (len == 0) { /* Handle empty variable name (corrupted environ[]) */ continue; } if (len > lastlen) { namebuf = xnrealloc(namebuf, len + 1, sizeof(char)); lastlen = len; } memcpy(namebuf, environ[0], len); namebuf[len] = '\0'; if (unsetenv(namebuf) == -1) { xerror("%s: unsetenv: '%s': %s\n", PROGRAM_NAME, namebuf, strerror(errno)); exit(FUNC_FAILURE); } } #endif /* !__NetBSD__ && !__HAIKU__ && !__APPLE__ && !__TERMUX__ */ } static void set_path_env(void) { int ret = -1; #if defined(_PATH_STDPATH) ret = setenv("PATH", _PATH_STDPATH, 1); #elif defined(_CS_PATH) char *p = (char *)NULL; size_t n = confstr(_CS_PATH, NULL, 0); /* Get value's size */ p = xnmalloc(n, sizeof(char)); /* Allocate space */ confstr(_CS_PATH, p, n); /* Get value */ ret = setenv("PATH", p, 1); /* Set it */ free(p); #else ret = setenv("PATH", MINIMAL_PATH, 1); #endif /* _PATH_STDPATH */ if (ret == -1) { xerror("%s: setenv: PATH: %s\n", PROGRAM_NAME, strerror(errno)); exit(FUNC_FAILURE); } } static void xsetenv(const char *name, const char *value) { if (setenv(name, value, 1) == -1) xerror("%s: setenv: '%s': %s\n", PROGRAM_NAME, name, strerror(errno)); } /* See https://www.oreilly.com/library/view/secure-programming-cookbook/0596003943/ch01s09.html */ static void disable_coredumps(void) { #if defined(ALLOW_COREDUMPS) return; #endif /* ALLOW_COREDUMPS */ struct rlimit rlim; rlim.rlim_cur = rlim.rlim_max = 0; if (setrlimit(RLIMIT_CORE, &rlim) == -1) xerror("setrlimit: Cannot set RLIMIT_CORE: %s\n", strerror(errno)); } /* Return the maximum number of files a process can have open. */ static int get_open_max(void) { #ifdef _SC_OPEN_MAX return (int)sysconf(_SC_OPEN_MAX); #else /* This is what getdtablesize(3) does. */ struct rlimit rlim; if (getrlimit(RLIMIT_NOFILE, &rlim) != -1) return (int)rlim.rlim_cur; #endif /* _SC_OPEN_MAX */ #ifdef OPEN_MAX /* Not defined in Linux. */ return OPEN_MAX; #elif defined(__linux__) && defined(NR_OPEN) return NR_OPEN; #else return 256; /* Let's fallback to a sane default. */ #endif /* OPEN_MAX */ } /* Close all non-standard file descriptors (> 2) to avoid FD exhaustion. */ static void sanitize_file_descriptors(void) { int fd = 0, fds = get_open_max(); for (fd = 3; fd < fds; fd++) close(fd); } static int sanitize_shell_level(char *str) { if (!str || !*str || !is_number(str)) return FUNC_FAILURE; const int a = atoi(str); if (a < 1 || a > MAX_SHELL_LEVEL) return FUNC_FAILURE; return FUNC_SUCCESS; } /* Drop SUID/SGID privileges, if set. */ static void drop_privs(void) { const uid_t ruid = getuid(); const uid_t euid = geteuid(); const gid_t rgid = getgid(); const gid_t egid = getegid(); if (rgid != egid) { int err = 0; #ifndef __linux__ setegid(rgid); if (setgid(rgid) == -1) err = 1; #else if (setregid(rgid, rgid) == -1) err = 1; #endif /* __linux__ */ if (err == 1 || setegid(egid) != -1 || getegid() != rgid) { fprintf(stderr, _("%s: Error dropping group privileges. " "Aborting.\n"), PROGRAM_NAME); exit(FUNC_FAILURE); } } if (ruid != euid) { int err = 0; #ifndef __linux__ seteuid(ruid); if (setuid(ruid) == -1) err = 1; #else if (setreuid(ruid, ruid) == -1) err = 1; #endif /* __linux__ */ if (err == 1 || seteuid(euid) != -1 || geteuid() != ruid) { fprintf(stderr, _("%s: Error dropping user privileges. " "Aborting.\n"), PROGRAM_NAME); exit(FUNC_FAILURE); } } } /* Sanitize the environment: set environ to NULL and then set a few * environment variables to get a minimally working environment. * Non-standard file descriptors are closed. * Core dumps are disabled. * SUID/SGID privileges, if any, are dropped. * Umask is set to the most restrictive value: 0077. */ int xsecure_env(const int mode) { sanitize_file_descriptors(); disable_coredumps(); drop_privs(); umask(0077); /* flawfinder: ignore */ char *display = (char *)NULL; char *wayland_display = (char *)NULL; char *term_env = (char *)NULL; char *tz = (char *)NULL; char *lang = (char *)NULL; char *fzfopts = (char *)NULL; char *clifm_level = (char *)NULL; clifm_level = xgetenv("CLIFMLVL", 1); if (mode != SECURE_ENV_FULL) { /* Let's keep these values from the current environment. */ display = xgetenv("DISPLAY", 1); if (!display) wayland_display = xgetenv("WAYLAND_DISPLAY", 1); term_env = xgetenv("TERM", 1); tz = xgetenv("TZ", 1); lang = xgetenv("LANG", 1); if (fzftab) fzfopts = xgetenv("FZF_DEFAULT_OPTS", 1); } else { if (clifm_level) nesting_level = 2; /* This is a nested instance. */ } xclearenv(); set_path_env(); xsetenv("IFS", " \t\n"); if (user.name) xsetenv("USER", user.name); if (user.home) xsetenv("HOME", user.home); if (user.shell) xsetenv("SHELL", user.shell); if (mode == SECURE_ENV_FULL) goto END; if (display && sanitize_cmd(display, SNT_DISPLAY) == FUNC_SUCCESS) { xsetenv("DISPLAY", display); } else { if (wayland_display) xsetenv("WAYLAND_DISPLAY", wayland_display); } if (clifm_level && sanitize_shell_level(clifm_level) == FUNC_SUCCESS) xsetenv("CLIFMLVL", clifm_level); if (term_env && sanitize_cmd(term_env, SNT_MISC) == FUNC_SUCCESS) xsetenv("TERM", term_env); if (tz && sanitize_cmd(tz, SNT_MISC) == FUNC_SUCCESS) xsetenv("TZ", tz); if (lang && sanitize_cmd(lang, SNT_MISC) == FUNC_SUCCESS) { xsetenv("LANG", lang); xsetenv("LC_ALL", lang); } else { xsetenv("LC_ALL", "C"); } if (fzfopts) xsetenv("FZF_DEFAULT_OPTS", fzfopts); END: free(display); free(wayland_display); free(clifm_level); free(term_env); free(tz); free(lang); free(fzfopts); return FUNC_SUCCESS; } /* Sanitize cmd string coming from the mimelist file. */ static int sanitize_mime(const char *cmd) { const char *p = cmd; while (*p) { /* Only %[fxum] is allowed. */ if (*p == '%' && p[1] != 'f' && p[1] != 'x' && p[1] != 'u' && p[1] != 'm') return FUNC_FAILURE; /* Disallow double ampersand. */ if (*p == '&' && p[1] == '&') return FUNC_FAILURE; p++; } const size_t cmd_len = (size_t)(p - cmd); if (cmd_len > strspn(cmd, ALLOWED_CHARS_MIME)) return FUNC_FAILURE; return FUNC_SUCCESS; } /* Sanitize the string CMD using WHITELIST as whitelist. */ static int sanitize_whitelist(const char *cmd, const char *whitelist) { if (strlen(cmd) > strspn(cmd, whitelist)) return FUNC_FAILURE; return FUNC_SUCCESS; } /* Return FUNC_SUCCESS if at least one character in CMD is a non-escaped * blacklisted char (<>|;&$). Oterwise, return FUNC_FAILURE. */ static int sanitize_blacklist(const char *cmd) { if (!cmd || !*cmd) return FUNC_SUCCESS; size_t i; for (i = 0; cmd[i]; i++) { switch (cmd[i]) { case '<': /* fallthrough */ case '>': /* fallthrough */ case '|': /* fallthrough */ case ';': /* fallthrough */ case '&': /* fallthrough */ case '$': /* fallthrough */ case '`': if (i == 0 || cmd[i - 1] != '\\') return FUNC_FAILURE; break; default: break; } } return FUNC_SUCCESS; } /* Check if command name in STR contains slashes. Return 1 if found, * zero otherwise. This means: do not allow custom scripts or binaries, * but only whatever can be found in the sanitized PATH variable. */ static int clean_cmd(const char *str) { if (!str || !*str) return FUNC_FAILURE; char *p = strchr(str, ' '); if (p) *p = '\0'; const char *q = strchr(str, '/'); if (p) *p = ' '; if (q) { err('w', PRINT_PROMPT, _("%s: '%s': Only command base names " "are allowed. E.g.: 'nano' instead of '/usr/bin/nano'\n"), PROGRAM_NAME, str); return FUNC_FAILURE; } return FUNC_SUCCESS; } /* Sanitize CMD according to TYPE. Returns FUNC_SUCCESS if command is safe or * FUNC_FAILURE if not. */ int sanitize_cmd(const char *str, const int type) { if (!str || !*str) return FUNC_FAILURE; int exit_status = FUNC_FAILURE; switch (type) { case SNT_MIME: if (clean_cmd(str) != FUNC_SUCCESS) /* Error message already printed by clean_cmd() */ return FUNC_FAILURE; exit_status = sanitize_mime(str); break; case SNT_NET: exit_status = sanitize_whitelist(str, ALLOWED_CHARS_NET); break; case SNT_DISPLAY: return sanitize_whitelist(str, ALLOWED_CHARS_DISPLAY); case SNT_MISC: return sanitize_whitelist(str, ALLOWED_CHARS_MISC); case SNT_PROFILE: /* fallthrough */ case SNT_PROMPT: /* fallthrough */ case SNT_AUTOCMD: /* fallthrough */ case SNT_GRAL: if (clean_cmd(str) != FUNC_SUCCESS) return FUNC_FAILURE; exit_status = sanitize_whitelist(str, ALLOWED_CHARS_GRAL); break; case SNT_BLACKLIST: return sanitize_blacklist(str); case SNT_NONE: /* fallthrough */ default: return FUNC_SUCCESS; } if (exit_status == FUNC_FAILURE) { err('w', PRINT_PROMPT, "%s: '%s': %s\n", PROGRAM_NAME, str, _(UNSAFE_CMD)); return FUNC_FAILURE; } return FUNC_SUCCESS; } clifm-1.26.3/src/sanitize.h000066400000000000000000000037321506632037700155010ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* sanitize.h */ #ifndef SANITIZE_H #define SANITIZE_H #define ALLOWED_CHARS_NET "abcdefghijklmnopqrstuvwxyz\ ABCDEFGHIJKLMNOPQRSTUVWXYZ\ 0123456789 -_.,/=" #define ALLOWED_CHARS_MIME "abcdefghijklmnopqrstuvwxyz\ ABCDEFGHIJKLMNOPQRSTUVWXYZ\ 0123456789 -_.,%&" /* Used to sanitize DISPLAY env variable */ #define ALLOWED_CHARS_DISPLAY "abcdefghijklmnopqrstuvwxyz\ ABCDEFGHIJKLMNOPQRSTUVWXYZ\ 0123456789-_.,:" /* Used to sanitize TZ, LANG, and TERM env variables */ #define ALLOWED_CHARS_MISC "abcdefghijklmnopqrstuvwxyz\ ABCDEFGHIJKLMNOPQRSTUVWXYZ\ 0123456789-_.," /* Used to sanitize commands in gral */ #define ALLOWED_CHARS_GRAL "abcdefghijklmnopqrstuvwxyz\ ABCDEFGHIJKLMNOPQRSTUVWXYZ\ 0123456789 -_.,/'\"" /* Used to sanitize commands based on a blacklist * Let's reject the following shell features: * <>: Input/output redirection * |: Pipes/OR list * &: AND list * $`: Command substitution/environment variables * ;: Sequential execution */ //#define BLACKLISTED_CHARS "<>|;&$`" __BEGIN_DECLS int sanitize_cmd(const char *str, const int type); int xsecure_env(const int mode); __END_DECLS #endif /* SANITIZE_H */ clifm-1.26.3/src/search.c000066400000000000000000000644251506632037700151210ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* search.c -- functions for the search system */ #include "helpers.h" #include #include #include #include #ifdef __sun # include /* TIOCGWINSZ */ #endif /* __sun */ /* We need rl_line_buffer in case of no matches and no metacharacter */ #include #include "aux.h" #include "checks.h" #include "colors.h" #include "messages.h" #include "misc.h" #include "navigation.h" #include "sort.h" #include "spawn.h" #define ERR_SKIP_REGEX 2 #if (defined(__OpenBSD__) || defined(__sun)) && !defined(_BE_POSIX) /* OpenBSD/Solaris find(1) has neither -regex nor -iregex. We'll try to use * gfind(1) instead.*/ # define FIND_HAS_NO_REGEX #endif /* __OpenBSD__ || __sun */ struct search_t { char *name; size_t len; int eln; int pad; }; static int exec_find(char *name, char *_path, char *method, char *pattern) { if (conf.follow_symlinks == 1) { char *cmd[] = {name, "-L", _path, method, pattern, NULL}; return launch_execv(cmd, FOREGROUND, E_NOSTDERR); } char *cmd[] = {name, _path, method, pattern, NULL}; return launch_execv(cmd, FOREGROUND, E_NOSTDERR); } #ifdef FIND_HAS_NO_REGEX static char * define_find_name(void) { static int check = 1; static int have_gfind = 0; /* Let's run this only once. */ if (check == 1) { check = 0; if (is_cmd_in_path("gfind") == 1) have_gfind = 1; } return (have_gfind == 1 ? "gfind" : "find"); } #endif /* FIND_HAS_NO_REGEX */ static int run_find(char *search_path, char *arg) { char *_path = (search_path && *search_path) ? search_path : "."; char *name = "find"; #if defined(_BE_POSIX) /* POSIX find(1) only supports -name */ char *method = "-name"; #else char *method = conf.search_strategy == REGEX_ONLY ? (conf.case_sens_search == 1 ? "-regex" : "-iregex") : (conf.case_sens_search == 1 ? "-name" : "-iname"); # if defined(FIND_HAS_NO_REGEX) name = define_find_name(); if (*name != 'g') /* GNU find (gfind) not found */ method = conf.case_sens_search == 1 ? "-name" : "-iname"; # endif /* FIND_HAS_NO_REGEX */ #endif /* _BE_POSIX */ const int glob_char = check_glob_char(arg + 1, GLOB_REGEX); if (glob_char == 1) return exec_find(name, _path, method, arg + 1); const size_t pattern_len = strlen(arg + 1) + 5; char *pattern = xnmalloc(pattern_len, sizeof(char)); #if !defined(_BE_POSIX) if (conf.search_strategy == REGEX_ONLY) { # if !defined(FIND_HAS_NO_REGEX) snprintf(pattern, pattern_len, ".*%s.*", arg + 1); # else if (*name == 'g') /* We have GNU find (gfind) */ snprintf(pattern, pattern_len, ".*%s.*", arg + 1); else snprintf(pattern, pattern_len, "*%s*", arg + 1); # endif /* FIND_HAS_NO_REGEX */ } else { snprintf(pattern, pattern_len, "*%s*", arg + 1); } #else snprintf(pattern, pattern_len, "*%s*", arg + 1); #endif /* !_BE_POSIX */ const int ret = exec_find(name, _path, method, pattern); free(pattern); return ret; } static int set_file_type_and_search_path(char **args, mode_t *file_type, char **search_path, const int invert) { /* If there are two arguments, the one starting with '-' is the * file type and the other is the path. */ if (args[1] && args[2]) { if (*args[1] == '-') { *file_type = (mode_t)args[1][1]; *search_path = args[2]; } else if (*args[2] == '-') { *file_type = (mode_t)args[2][1]; *search_path = args[1]; } else { *search_path = args[1]; } } else { /* If just one argument, '-' indicates file type. Else, we have a path. */ if (args[1]) { if (*args[1] == '-') *file_type = (mode_t)args[1][1]; else *search_path = args[1]; } } if (*file_type == 0) return FUNC_SUCCESS; /* Convert file type into a macro that can be decoded by stat(). If * file type is specified, matches will be checked against this value. */ switch (*file_type) { case 'b': *file_type = invert == 1 ? DT_BLK : S_IFBLK; break; case 'c': *file_type = invert == 1 ? DT_CHR : S_IFCHR; break; case 'd': *file_type = invert == 1 ? DT_DIR : S_IFDIR; break; #ifdef SOLARIS_DOORS case 'O': *file_type = invert == 1 ? DT_DOOR : S_IFDOOR; break; case 'P': *file_type = invert == 1 ? DT_PORT : S_IFPORT; break; #endif /* SOLARIS_DOORS */ case 'f': *file_type = invert == 1 ? DT_REG : S_IFREG; break; case 'l': *file_type = invert == 1 ? DT_LNK : S_IFLNK; break; case 'p': *file_type = invert == 1 ? DT_FIFO : S_IFIFO; break; case 's': *file_type = invert == 1 ? DT_SOCK : S_IFSOCK; break; case 'x': run_find(*search_path, args[0]); return FUNC_SUCCESS; default: fprintf(stderr, _("search: '%c': Unrecognized file " "type\n"), (char)*file_type); break; } return FUNC_SUCCESS; } static int chdir_search_path(char **search_path, const char *arg) { if (strchr(*search_path, '\\')) { char *deq_dir = unescape_str(*search_path, 0); if (!deq_dir) { xerror(_("search: %s: Error unescaping filename\n"), arg); return FUNC_FAILURE; } xstrsncpy(*search_path, deq_dir, strlen(deq_dir) + 1); free(deq_dir); } const size_t path_len = strlen(*search_path); if (path_len > 1 && (*search_path)[path_len - 1] == '/') (*search_path)[path_len - 1] = '\0'; /* If search path is the current directory. */ if ((*(*search_path) == '.' && !(*search_path)[1]) || ((*search_path)[1] == workspaces[cur_ws].path[1] && strcmp(*search_path, workspaces[cur_ws].path) == 0)) { *search_path = (char *)NULL; } else { if (xchdir(*search_path, NO_TITLE) == -1) { xerror("search: '%s': %s\n", *search_path, strerror(errno)); return FUNC_FAILURE; } } return FUNC_SUCCESS; } static char ** glob_sort_dirs(glob_t *globbed_files, size_t *g) { int *dirs = xnmalloc(globbed_files->gl_pathc + 1, sizeof(int)); char **gfiles = xnmalloc(globbed_files->gl_pathc + 1, sizeof(char *)); struct stat attr; size_t i, n = 0; for (i = 0; globbed_files->gl_pathv[i]; i++) { if (stat(globbed_files->gl_pathv[i], &attr) != -1 && S_ISDIR(attr.st_mode)) dirs[i] = 1; else dirs[i] = 0; } for (i = 0; globbed_files->gl_pathv[i]; i++) { if (dirs[i] == 1) { gfiles[n] = globbed_files->gl_pathv[i]; n++; } } for (i = 0; globbed_files->gl_pathv[i]; i++) { if (dirs[i] == 0) { gfiles[n] = globbed_files->gl_pathv[i]; n++; } } free(dirs); gfiles[n] = (char *)NULL; *g = n; return gfiles; } static struct search_t * get_glob_matches(char **gfiles, const char *search_path, const mode_t file_type, const size_t g) { struct search_t *matches = xnmalloc(g + 1, sizeof(struct search_t)); size_t i; int n = 0; struct stat attr; for (i = 0; gfiles[i]; i++) { if (SELFORPARENT(gfiles[i])) continue; if (file_type != 0) { /* Simply skip all files not matching file_type. */ if (lstat(gfiles[i], &attr) == -1 || (attr.st_mode & S_IFMT) != file_type) continue; } matches[n].name = savestring(gfiles[i], strlen(gfiles[i])); /* Get the longest filename in the list. */ /* If not in CWD, we only need to know the file's length (no ELN) */ if (search_path) { /* This will be passed to colors_list(): -1 means no ELN */ matches[n].eln = -1; matches[n].len = wc_xstrlen(matches[n].name); n++; continue; } /* No search_path */ /* If searching in CWD, take into account the file's ELN * when calculating its length. */ size_t j, f = 0; for (j = 0; file_info[j].name; j++) { if (!matches[n].name || *matches[n].name != *file_info[j].name || strcmp(matches[n].name, file_info[j].name) != 0) continue; f = 1; matches[n].eln = (int)(j + 1); matches[n].len = wc_xstrlen(file_info[j].name) + (size_t)file_info[j].eln_n + 1; } if (f == 0) { matches[n].eln = -1; matches[n].len = 0; } n++; } matches[n].name = (char *)NULL; return matches; } static struct search_t * get_non_matches_from_search_path(const char *search_path, char **gfiles, const mode_t file_type) { struct dirent **ent = (struct dirent **)NULL; int dir_entries = scandir(search_path, &ent, skip_files, xalphasort); if (dir_entries == -1) return (struct search_t *)NULL; int i, j, n = 0; struct search_t *matches = xnmalloc((size_t)dir_entries + 1, sizeof(struct search_t)); for (i = 0; i < dir_entries; i++) { int f = 0; for (j = 0; gfiles[j]; j++) { if (*ent[i]->d_name == *gfiles[j] && strcmp(ent[i]->d_name, gfiles[j]) == 0) { f = 1; break; } } if (f == 1) continue; #if !defined(_DIRENT_HAVE_D_TYPE) struct stat attr; if (lstat(ent[i]->d_name, &attr) == -1) continue; const mode_t type = get_dt(attr.st_mode); if (file_type && type != file_type) #else if (file_type && ent[i]->d_type != file_type) #endif /* !_DIRENT_HAVE_D_TYPE */ continue; matches[n].eln = -1; matches[n].len = wc_xstrlen(ent[i]->d_name); matches[n].name = strdup(ent[i]->d_name); n++; } i = dir_entries; while (--i >= 0) free(ent[i]); free(ent); matches[n].name = (char *)NULL; return matches; } static struct search_t * get_glob_matches_invert(char **gfiles, const char *search_path, const mode_t file_type) { if (search_path) return get_non_matches_from_search_path(search_path, gfiles, file_type); filesn_t i, j, n = 0; struct search_t *matches = xnmalloc((size_t)files + 1, sizeof(struct search_t)); for (i = 0; file_info[i].name; i++) { int f = 0; for (j = 0; gfiles[j]; j++) { if (*gfiles[j] == *file_info[i].name && strcmp(gfiles[j], file_info[i].name) == 0) { f = 1; break; } } if (f == 1 || (file_type && file_info[i].type != file_type)) continue; matches[n].eln = (int)(i + 1); matches[n].len = wc_xstrlen(file_info[i].name) + (size_t)file_info[i].eln_n + 1; matches[n].name = strdup(file_info[i].name); n++; } matches[n].name = (char *)NULL; return matches; } static void get_glob_longest(struct search_t *matches, int *longest_eln, size_t *longest_match, int *eln_pad) { int search_path = (*eln_pad == -1); size_t i; for (i = 0; matches[i].name; i++) { if (matches[i].len <= *longest_match) continue; *longest_match = matches[i].len; *longest_eln = matches[i].eln; } if (search_path == 1) { *longest_eln = -1; return; } if (conf.icons == 1) *longest_match += (size_t)ICON_LEN; int longest_name = 0; for (i = 0; matches[i].name; i++) { if (matches[i].eln > longest_name) longest_name = matches[i].eln; } *eln_pad = DIGINUM(longest_name); *longest_match += (size_t)(*eln_pad - DIGINUM(*longest_eln)); } /* Original string is either "/QUERY" or "/!QUERY". Let's extract QUERY. * If the query string contains no metacharacters, change it to "*QUERY*" */ static char * construct_glob_query(char **arg, const int invert) { search_flags &= ~NO_GLOB_CHAR; char *query = *arg + (invert == 1 ? 2 : 1); /* If the query string already contains metacharacters, return it as is. */ if (check_glob_char(query, GLOB_REGEX) == 1) return query; search_flags |= NO_GLOB_CHAR; if (conf.search_strategy != GLOB_ONLY) { /* Let's return here to perform a regex search. */ return (char *)NULL; } /* Search strategy is glob-only */ const size_t len = strlen(*arg); char *q = savestring(query, len - (invert == 1 ? 2 : 1)); *arg = xnrealloc(*arg, (len + 3), sizeof(char)); snprintf((*arg) + 1, len + 2, "*%s*", q); free(q); return (*arg) + 1; } static int calculate_glob_output_columns(const size_t flongest, const int found) { int columns_n = 0; struct winsize w; ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); unsigned short tcols = w.ws_col; if (flongest == 0 || flongest > tcols) columns_n = 1; else columns_n = (int)(tcols / (flongest + 1)); if (columns_n > found) columns_n = found; return columns_n; } static int print_glob_matches(struct search_t *matches, const char *search_path) { int found = 0; for (found = 0; matches && matches[found].name; found++); if (found == 0) return 0; int eln_pad = search_path ? -1 : 0; int longest_eln = -1; size_t flongest = 0; get_glob_longest(matches, &longest_eln, &flongest, &eln_pad); int columns_n = calculate_glob_output_columns(flongest, found); /* colors_list() makes use of TAB_OFFSET. We don't want it here. */ const size_t tab_offset_bk = tab_offset; tab_offset = 0; int last_column = 0, i; for (i = 0; matches[i].name; i++) { if ((i + 1) % columns_n == 0) last_column = 1; else last_column = 0; if (!search_path) { /* Print ELN, file indicator, and icon. */ int index = matches[i].eln - 1; char ind_chr = file_info[index].sel == 1 ? SELFILE_CHR : ' '; char *ind_chr_color = file_info[index].sel == 1 ? li_cb : ""; printf("%s%*d%s%s%c%s%s%s%s%c", el_c, eln_pad, matches[i].eln, df_c, ind_chr_color, ind_chr, df_c, conf.icons == 1 ? file_info[index].icon_color : "", conf.icons == 1 ? file_info[index].icon : "", df_c, conf.icons == 1 ? ' ' : 0); } /* Print filename. */ int name_pad = (last_column == 1 || i == (found - 1)) ? NO_PAD : (int)(flongest - matches[i].len - ( search_path ? 0 : (size_t)(eln_pad - DIGINUM(matches[i].eln)) ) + 1); if (name_pad < 0) name_pad = 0; colors_list(matches[i].name, NO_ELN, name_pad, (last_column == 1 || i == found - 1) ? 1 : NO_NEWLINE); } tab_offset = tab_offset_bk; print_reload_msg(SET_SUCCESS_PTR, xs_cb, _("Matches found: %d%s\n"), found, conf.search_strategy != GLOB_ONLY ? " (glob)" : ""); return found; } /* List matching filenames in the specified directory. */ static int search_glob(char **args) { if (!args || !args[0]) return FUNC_FAILURE; int invert = (args[0][1] == '!'); char *search_query = (char *)NULL, *search_path = (char *)NULL; mode_t file_type = 0; if (set_file_type_and_search_path(args, &file_type, &search_path, invert) == FUNC_FAILURE) { return ERR_SKIP_REGEX; } if (file_type == 'x') /* Recursive search via find(1) */ return FUNC_SUCCESS; /* If we have a path ("/str /path"), chdir into it, since glob(3) * works on CWD. */ if (search_path && *search_path && chdir_search_path(&search_path, args[1]) == FUNC_FAILURE) return ERR_SKIP_REGEX; search_query = construct_glob_query(&args[0], invert); if (!search_query && conf.search_strategy != GLOB_ONLY) return FUNC_FAILURE; /* Get matches, if any. */ glob_t globbed_files; int ret = glob(search_query, GLOB_BRACE, NULL, &globbed_files); if (ret != 0) { globfree(&globbed_files); /* Go back to the directory we came from */ if (search_path && xchdir(workspaces[cur_ws].path, NO_TITLE) == -1) xerror("search: '%s': %s\n", workspaces[cur_ws].path, strerror(errno)); return FUNC_FAILURE; } /* We have matches */ char **gfiles = globbed_files.gl_pathv; size_t g = globbed_files.gl_pathc; /* glob(3) doesn't sort directories first. Let's do it ourselves */ if (conf.list_dirs_first == 1) gfiles = glob_sort_dirs(&globbed_files, &g); /* We need to store pointers to matching filenames in array of pointers, * just as the filename length (to construct the columned output), and, * if searching in CWD, its index (ELN) in the dirlist array as well. */ struct search_t *list = (struct search_t *)NULL; if (invert == 0) list = get_glob_matches(gfiles, search_path, file_type, g); else list = get_glob_matches_invert(gfiles, search_path, file_type); globfree(&globbed_files); int matches = print_glob_matches(list, search_path); /* Free stuff */ if (list) { size_t i; for (i = 0; list[i].name; i++) free(list[i].name); free(list); } if (conf.list_dirs_first == 1) free(gfiles); /* If needed, go back to the directory we came from */ if (search_path && xchdir(workspaces[cur_ws].path, NO_TITLE) == -1) { xerror("search: '%s': %s\n", workspaces[cur_ws].path, strerror(errno)); return FUNC_FAILURE; } return (matches == 0 ? FUNC_FAILURE : FUNC_SUCCESS); } /* Original string is either "/QUERY" or "/!QUERY". Let's extract QUERY. * If the query string contains no metacharacters, change it to ".*QUERY.*" */ static char * construct_regex_query(char **arg, const int invert, int *regex_found) { char *query = *arg + (invert == 1 ? 2 : 1); *regex_found = check_regex(query); if (*regex_found == FUNC_SUCCESS) return query; const size_t len = strlen(*arg); char *q = savestring(query, len - (invert == 1 ? 2 : 1)); *arg = xnrealloc(*arg, (len + 5), sizeof(char)); snprintf(*arg + 1, len + 4, ".*%s.*", q); free(q); return *arg + 1; } static void err_regex_no_match(const int regex_found, const char *arg) { char *input = (conf.autocd == 1 && !arg && (regex_found == FUNC_FAILURE || (search_flags & NO_GLOB_CHAR)) && rl_line_buffer) ? strrchr(rl_line_buffer, '/') : (char *)NULL; if (input && input != rl_line_buffer) { /* Input string contains at least two slashes. It looks like a path: * let's err like it was. */ char *p = unescape_str(rl_line_buffer, 0); xerror("cd: '%s': %s\n", p ? p : rl_line_buffer, strerror(ENOENT)); free(p); } else if (search_flags & NO_GLOB_CHAR) { fputs(_("search: No matches found\n"), stderr); } else { fputs(_("No matches found\n"), stderr); } search_flags &= ~NO_GLOB_CHAR; } static void free_regex_dirlist(struct dirent ***dirlist, const int tmp_files) { if (!dirlist) return; int i = tmp_files; while (--i >= 0) free((*dirlist)[i]); free(*dirlist); if (xchdir(workspaces[cur_ws].path, NO_TITLE) == -1) xerror("search: '%s': %s\n", workspaces[cur_ws].path, strerror(errno)); } static int check_regex_file_type(struct dirent **reg_dirlist, const int index, const mode_t file_type) { if (reg_dirlist) { /* A search path has been provided. */ #if !defined(_DIRENT_HAVE_D_TYPE) mode_t type; struct stat attr; if (lstat(reg_dirlist[index]->d_name, &attr) == -1) return FUNC_FAILURE; switch (attr.st_mode & S_IFMT) { case S_IFBLK: type = DT_BLK; break; case S_IFCHR: type = DT_CHR; break; case S_IFDIR: type = DT_DIR; break; # ifdef SOLARIS_DOORS case S_IFDOOR: type = DT_DOOR; break; case S_IFPORT: type = DT_PORT; break; # endif /* SOLARIS_DOORS */ case S_IFIFO: type = DT_FIFO; break; case S_IFLNK: type = DT_LNK; break; case S_IFREG: type = DT_REG; break; case S_IFSOCK: type = DT_SOCK; break; default: type = DT_UNKNOWN; break; } if (type != file_type) #else if (reg_dirlist[index]->d_type != file_type) #endif /* !_DIRENT_HAVE_D_TYPE */ return FUNC_FAILURE; } else { /* Searching in CWD. */ if (file_info[index].type != file_type) return FUNC_FAILURE; } return FUNC_SUCCESS; } static struct search_t load_entry_info(struct dirent **reg_dirlist, const int index) { char *name = reg_dirlist ? reg_dirlist[index]->d_name : file_info[index].name; struct search_t list; list.name = name; list.eln = reg_dirlist ? -1 : index + 1; list.len = wc_xstrlen(name); list.len += (!reg_dirlist && conf.icons == 1) ? (size_t)ICON_LEN : 0; list.len += reg_dirlist ? 0 : (size_t)(DIGINUM(list.eln) + 1); return list; } /* Return the length of the longest entry in the file list LIST. */ static size_t get_regex_longest(struct search_t *list, const int total, int *elnpad) { int i = total; size_t longest_file_len = 0; int longest_file_eln = -1; int longest_eln = -1; while (--i >= 0) { if (list[i].len > longest_file_len) { longest_file_len = list[i].len; longest_file_eln = list[i].eln; } if (list[i].eln != -1 && list[i].eln > longest_eln) longest_eln = list[i].eln; } *elnpad = DIGINUM(longest_eln); longest_file_len += (size_t)(*elnpad - DIGINUM(longest_file_eln)); return longest_file_len; } static size_t calc_columns(const size_t longest_file_len, const size_t matches) { struct winsize w; ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); unsigned short termcols = w.ws_col > 0 ? w.ws_col : 80; size_t columns; if (longest_file_len == 0 || longest_file_len > termcols) columns = 1; else columns = (size_t)termcols / (longest_file_len + 1); if (columns > matches) columns = matches; return columns; } static void print_regex_entry(struct search_t list, const int namepad, const int elnpad, const int newline) { if (list.eln != -1) { /* Print ELN, file indicator, and icon. */ int index = list.eln - 1; char ind_chr = file_info[index].sel == 1 ? SELFILE_CHR : ' '; char *ind_chr_color = file_info[index].sel == 1 ? li_cb : ""; printf("%s%*d%s%s%c%s%s%s%s%c", el_c, elnpad, list.eln, df_c, ind_chr_color, ind_chr, df_c, conf.icons == 1 ? file_info[index].icon_color : "", conf.icons == 1 ? file_info[index].icon : "", df_c, conf.icons == 1 ? ' ' : 0); } colors_list(list.name, NO_ELN, namepad, newline); } static size_t print_regex_matches(const mode_t file_type, struct dirent **reg_dirlist, const int *regex_index) { /* colors_list() makes use of TAB_OFFSET. We don't need it here. */ const size_t tab_offset_bk = tab_offset; tab_offset = 0; size_t total; /* Total number of matches (without file type filter) */ for (total = 0; regex_index[total] > -1; total++); struct search_t *list = xnmalloc(total + 1, sizeof(struct search_t)); size_t matches = 0; /* Number of filtered matches */ int i = (int)total; while (--i >= 0) { int index = regex_index[i]; if (file_type != 0 && check_regex_file_type(reg_dirlist, index, file_type) == FUNC_FAILURE) continue; list[matches] = load_entry_info(reg_dirlist, index); matches++; } size_t count = 0; if (matches == 0) { fputs(_("search: No matches found\n"), stderr); goto END; } int eln_pad = -1; const size_t longest_len = get_regex_longest(list, (int)matches, &eln_pad); const size_t columns = calc_columns(longest_len, matches); size_t last_col = 0, cur_col = 0; i = (int)matches; while (--i >= 0) { cur_col++; count++; if (cur_col == columns) { last_col = 1; cur_col = 0; } else { last_col = 0; } /* Calculate how much right pad we need for the current entry */ int name_pad = (last_col == 1 || count == matches) ? NO_PAD : (int)(longest_len - list[i].len - (list[i].eln == -1 ? 0 : (size_t)(eln_pad - DIGINUM(list[i].eln))) + 1); if (name_pad < 0) name_pad = 0; int newline = (last_col == 1 || count == matches); print_regex_entry(list[i], name_pad, eln_pad, newline); } print_reload_msg(SET_SUCCESS_PTR, xs_cb, _("Matches found: %zu\n"), count); END: free(list); tab_offset = tab_offset_bk; return count; } /* List matching (or non-matching if INVERT is set to 1) filenames * in the specified directory. */ static int search_regex(char **args) { if (!args || !args[0]) return FUNC_FAILURE; int invert = (args[0][1] == '!'); char *search_query = (char *)NULL, *search_path = (char *)NULL; mode_t file_type = 0; if (set_file_type_and_search_path(args, &file_type, &search_path, 1) == FUNC_FAILURE) return FUNC_FAILURE; if (file_type == 'x') /* Recursive search via find(1) */ return FUNC_SUCCESS; struct dirent **reg_dirlist = (struct dirent **)NULL; int tmp_files = - 1; if (search_path && *search_path) { if (chdir_search_path(&search_path, args[1]) == FUNC_FAILURE) return FUNC_FAILURE; tmp_files = scandir(".", ®_dirlist, skip_files, xalphasort); if (tmp_files == -1) { xerror("search: '%s': %s\n", search_path, strerror(errno)); if (xchdir(workspaces[cur_ws].path, NO_TITLE) == -1) xerror("search: '%s': %s\n", workspaces[cur_ws].path, strerror(errno)); return FUNC_FAILURE; } } int regex_found = 0; search_query = construct_regex_query(&args[0], invert, ®ex_found); /* Get matches */ size_t i; regex_t regex_files; int reg_flags = conf.case_sens_search == 1 ? (REG_NOSUB | REG_EXTENDED) : (REG_NOSUB | REG_EXTENDED | REG_ICASE); int ret = regcomp(®ex_files, search_query, reg_flags); if (ret != FUNC_SUCCESS) { xerror(_("'%s': Invalid regular expression\n"), search_query); regfree(®ex_files); free_regex_dirlist(®_dirlist, tmp_files); return FUNC_FAILURE; } size_t found = 0; int *regex_index = xnmalloc((search_path ? (size_t)tmp_files : (size_t)files) + 2, sizeof(int)); const size_t max = (search_path && *search_path) ? (size_t)tmp_files : (size_t)files; for (i = 0; i < max; i++) { char *name = (search_path && *search_path) ? reg_dirlist[i]->d_name : file_info[i].name; if (regexec(®ex_files, name, 0, NULL, 0) == FUNC_SUCCESS) { if (invert == 0) { regex_index[found] = (int)i; found++; } } else { if (invert == 1) { regex_index[found] = (int)i; found++; } } } regex_index[found] = -1; /* Mark end of array */ regfree(®ex_files); if (found == 0) { err_regex_no_match(regex_found, args[1]); free(regex_index); free_regex_dirlist(®_dirlist, tmp_files); return FUNC_FAILURE; } /* We have matches: print them. */ const size_t matches = print_regex_matches(file_type, reg_dirlist, regex_index); free(regex_index); free_regex_dirlist(®_dirlist, tmp_files); return matches == 0 ? FUNC_FAILURE : FUNC_SUCCESS; } static int err_glob_no_match(const char *arg) { char *input = (conf.autocd == 1 && !arg && (search_flags & NO_GLOB_CHAR) && rl_line_buffer) ? strrchr(rl_line_buffer, '/') : (char *)NULL; if (input && input != rl_line_buffer) { /* Input string contains two slashes: it looks like a path, so let's * err like it was. */ char *p = unescape_str(rl_line_buffer, 0); xerror("cd: '%s': %s\n", p ? p : rl_line_buffer, strerror(ENOENT)); free(p); return FUNC_FAILURE; } fputs(_("search: No matches found\n"), stderr); return FUNC_FAILURE; } /* We provide three search strategies: * 1 - Only glob * 2 - Only regex * 3 - Glob-regex */ int search_function(char **args) { if (args[1] && IS_HELP(args[1])) { puts(SEARCH_USAGE); return FUNC_SUCCESS; } if (conf.search_strategy == REGEX_ONLY) return search_regex(args); const int ret = search_glob(args); if (ret != FUNC_FAILURE) return (ret == ERR_SKIP_REGEX ? 1 : ret); if (conf.search_strategy == GLOB_ONLY) return err_glob_no_match(args[1]); if (!(search_flags & NO_GLOB_CHAR)) fputs(_("Glob: No matches found. Trying regex...\n"), stderr); return search_regex(args); } clifm-1.26.3/src/search.h000066400000000000000000000017631506632037700151220ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* search.h */ #ifndef SEARCH_H #define SEARCH_H __BEGIN_DECLS int search_function(char **args); __END_DECLS #endif /* SEARCH_H */ clifm-1.26.3/src/selection.c000066400000000000000000000726751506632037700156470ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* selection.c -- files selection functions */ #include "helpers.h" #include #include #include #include #if defined(__linux__) || defined(__HAIKU__) || defined(__APPLE__) \ || defined(__sun) || defined(__CYGWIN__) # ifdef __TINYC__ /* Silence a tcc warning. We don't use CTRL anyway */ # undef CTRL # endif /* __TINYC__ */ # include #endif /* __linux__ || __HAIKU__ || __APPLE__ || __sun || __CYGWIN__ */ #ifdef __sun # include /* TIOCGWINSZ */ #endif /* __sun */ #include "aux.h" #include "checks.h" #include "colors.h" #include "file_operations.h" #include "init.h" #include "listing.h" #include "messages.h" #include "misc.h" #include "navigation.h" #include "properties.h" /* get_size_color() */ #include "readline.h" #include "selection.h" #include "sort.h" #include "xdu.h" /* dir_size() */ /* Save selected elements into a tmp file. Returns 1 on success or 0 * on error. This function allows the user to work with multiple * instances of the program: they can select some files in the * first instance and then execute a second one to operate on those * files as they wish. */ int save_sel(void) { if (selfile_ok == 0 || !sel_file) return (xargs.stealth_mode == 1 ? FUNC_SUCCESS : FUNC_FAILURE); if (sel_n == 0) { if (unlink(sel_file) == -1) { xerror("sel: '%s': %s\n", sel_file, strerror(errno)); return FUNC_FAILURE; } return FUNC_SUCCESS; } int fd = 0; FILE *fp = open_fwrite(sel_file, &fd); if (!fp) { xerror("sel: '%s': %s\n", sel_file, strerror(errno)); return FUNC_FAILURE; } size_t i; for (i = 0; i < sel_n; i++) { fputs(sel_elements[i].name, fp); fputc('\n', fp); } fclose(fp); return FUNC_SUCCESS; } int select_file(char *file) { if (!file || !*file) return 0; if (sel_n == MAX_SEL) { xerror(_("sel: Cannot select any more files")); return 0; } static char buf[PATH_MAX + 1]; char *tfile = file; struct stat a; int exists = 0, new_sel = 0; const size_t flen = strlen(file); if (flen > 1 && file[flen - 1] == '/') file[flen - 1] = '\0'; /* If we are in a virtual directory, dereference symlinks */ if (virtual_dir == 1 && lstat(file, &a) == 0 && S_ISLNK(a.st_mode) && is_file_in_cwd(file)) { *buf = '\0'; const ssize_t ret = xreadlink(XAT_FDCWD, file, buf, sizeof(buf)); if (ret == -1) { xerror(_("sel: Cannot select file '%s': %s\n"), file, strerror(errno)); return 0; } tfile = buf; } /* Check if FILE is already in the selection box */ filesn_t j = (filesn_t)sel_n; while (--j >= 0) { if (*tfile == *sel_elements[j].name && strcmp(sel_elements[j].name, tfile) == 0) { exists = 1; break; } } if (exists == 0) { sel_elements = xnrealloc(sel_elements, sel_n + 2, sizeof(struct sel_t)); sel_elements[sel_n].name = savestring(tfile, strlen(tfile)); sel_elements[sel_n].size = (off_t)UNSET; sel_n++; sel_elements[sel_n].name = (char *)NULL; sel_elements[sel_n].size = (off_t)UNSET; new_sel++; } else { xerror(_("sel: '%s': Already selected\n"), tfile); } return new_sel; } static char ** load_matches_invert_cwd(glob_t *gbuf, const mode_t filetype, int *matches) { char **list = xnmalloc((size_t)files + 2, sizeof(char *)); filesn_t i = files; while (--i >= 0) { if (filetype != 0 && file_info[i].type != filetype) continue; filesn_t j = (filesn_t)gbuf->gl_pathc; while (--j >= 0) { if (*file_info[i].name == *gbuf->gl_pathv[j] && strcmp(file_info[i].name, gbuf->gl_pathv[j]) == 0) break; } if (j == -1) { list[*matches] = file_info[i].name; (*matches)++; } } return list; } static char ** load_matches_invert_nocwd(glob_t *gbuf, struct dirent **ent, const mode_t filetype, int *matches, const int ret) { char **list = xnmalloc((size_t)ret + 2, sizeof(char *)); int i = ret; while (--i >= 0) { #if !defined(_DIRENT_HAVE_D_TYPE) struct stat attr; if (lstat(ent[i]->d_name, &attr) == -1) continue; const mode_t type = get_dt(attr.st_mode); if (filetype != 0 && type != filetype) #else if (filetype != 0 && ent[i]->d_type != filetype) #endif /* !_DIRENT_HAVE_D_TYPE */ continue; int j = (int)gbuf->gl_pathc; while (--j >= 0) { if (*ent[i]->d_name == *gbuf->gl_pathv[j] && strcmp(ent[i]->d_name, gbuf->gl_pathv[j]) == 0) break; } if (j == -1) { list[*matches] = ent[i]->d_name; (*matches)++; } } return list; } static mode_t convert_filetype_mask(const mode_t filetype) { switch (filetype) { case DT_DIR: return S_IFDIR; case DT_REG: return S_IFREG; case DT_LNK: return S_IFLNK; case DT_SOCK: return S_IFSOCK; case DT_FIFO: return S_IFIFO; case DT_BLK: return S_IFBLK; case DT_CHR: return S_IFCHR; default: return 0; } } static char ** load_matches(glob_t *gbuf, const mode_t filetype, int *matches) { char **list = xnmalloc(gbuf->gl_pathc + 2, sizeof(char *)); const mode_t type = convert_filetype_mask(filetype); int i = (int)gbuf->gl_pathc; while (--i >= 0) { char *basename = strrchr(gbuf->gl_pathv[i], '/'); if (!basename && SELFORPARENT(gbuf->gl_pathv[i])) continue; if (basename && basename[1] && SELFORPARENT(basename + 1)) continue; if (filetype != 0) { struct stat attr; if (lstat(gbuf->gl_pathv[i], &attr) == -1 || (attr.st_mode & S_IFMT) != type) continue; } list[*matches] = gbuf->gl_pathv[i]; (*matches)++; } return list; } static int select_matches(char **list, const char *sel_path, const int matches) { int i = matches; int new_sel = 0; while (--i >= 0) { if (!list[i]) continue; if (sel_path) { const size_t tmp_len = strlen(sel_path) + strlen(list[i]) + 2; char *tmp = xnmalloc(tmp_len, sizeof(char)); snprintf(tmp, tmp_len, "%s/%s", sel_path, list[i]); new_sel += select_file(tmp); free(tmp); continue; } /* CWD */ if (*list[i] == '/') { /* Absolute path */ new_sel += select_file(list[i]); continue; } /* Relative path */ char *tmp = (char *)NULL; if (*workspaces[cur_ws].path == '/' && !*(workspaces[cur_ws].path + 1)) { /* CWD is root */ const size_t tmp_len = strlen(list[i]) + 2; tmp = xnmalloc(tmp_len, sizeof(char)); snprintf(tmp, tmp_len, "/%s", list[i]); } else { const size_t tmp_len = strlen(workspaces[cur_ws].path) + strlen(list[i]) + 2; tmp = xnmalloc(tmp_len, sizeof(char)); snprintf(tmp, tmp_len, "%s/%s", workspaces[cur_ws].path, list[i]); } new_sel += select_file(tmp); free(tmp); } return new_sel; } static int sel_glob(char *str, const char *sel_path, const mode_t filetype) { if (!str || !*str) return (-1); glob_t gbuf; char *pattern = str; int invert = 0; if (*pattern == '!') { pattern++; invert = 1; } int ret = glob(pattern, GLOB_BRACE, NULL, &gbuf); if (ret != FUNC_SUCCESS) { globfree(&gbuf); return (-1); } char **list = (char **)NULL; int matches = 0; struct dirent **ent = (struct dirent **)NULL; if (invert == 1) { if (!sel_path) { list = load_matches_invert_cwd(&gbuf, filetype, &matches); } else { ret = scandir(sel_path, &ent, skip_files, xalphasort); if (ret == -1) { xerror("sel: '%s': %s\n", sel_path, strerror(errno)); globfree(&gbuf); return (-1); } list = load_matches_invert_nocwd(&gbuf, ent, filetype, &matches, ret); } } else { list = load_matches(&gbuf, filetype, &matches); } list[matches] = (char *)NULL; int new_sel = select_matches(list, sel_path, matches); free(list); globfree(&gbuf); if (invert == 1 && sel_path) { int i = ret; while (--i >= 0) free(ent[i]); free(ent); } return new_sel; } static int sel_regex_cwd(regex_t regex, const mode_t filetype, const int invert) { int new_sel = 0; filesn_t i = files; while (--i >= 0) { if (filetype != 0 && file_info[i].type != filetype) continue; char tmp_path[PATH_MAX + 1]; if (*workspaces[cur_ws].path == '/' && !*(workspaces[cur_ws].path + 1)) { snprintf(tmp_path, sizeof(tmp_path), "/%s", file_info[i].name); } else { snprintf(tmp_path, sizeof(tmp_path), "%s/%s", workspaces[cur_ws].path, file_info[i].name); } if (regexec(®ex, file_info[i].name, 0, NULL, 0) == FUNC_SUCCESS) { if (invert == 0) new_sel += select_file(tmp_path); } else if (invert == 1) { new_sel += select_file(tmp_path); } } return new_sel; } static int sel_regex_nocwd(regex_t regex, const char *sel_path, const mode_t filetype, const int invert) { int new_sel = 0; struct dirent **list = (struct dirent **)NULL; const int filesn = scandir(sel_path, &list, skip_files, xalphasort); if (filesn == -1) { xerror("sel: '%s': %s\n", sel_path, strerror(errno)); return (-1); } const mode_t type = convert_filetype_mask(filetype); int i = (int)filesn; while (--i >= 0) { if (filetype != 0) { struct stat attr; if (lstat(list[i]->d_name, &attr) != -1 && (attr.st_mode & S_IFMT) != type) { free(list[i]); continue; } } const size_t tmp_len = strlen(sel_path) + strlen(list[i]->d_name) + 2; char *tmp_path = xnmalloc(tmp_len, sizeof(char)); snprintf(tmp_path, tmp_len, "%s/%s", sel_path, list[i]->d_name); if (regexec(®ex, list[i]->d_name, 0, NULL, 0) == FUNC_SUCCESS) { if (invert == 0) new_sel += select_file(tmp_path); } else if (invert == 1) { new_sel += select_file(tmp_path); } free(tmp_path); free(list[i]); } free(list); return new_sel; } static int sel_regex(char *str, const char *sel_path, const mode_t filetype) { if (!str || !*str) return (-1); regex_t regex; char *pattern = str; int invert = 0; int new_sel = 0; if (*pattern == '!') { pattern++; invert = 1; } int reg_flags = conf.case_sens_list == 1 ? (REG_NOSUB | REG_EXTENDED) : (REG_NOSUB | REG_EXTENDED | REG_ICASE); if (regcomp(®ex, pattern, reg_flags) != FUNC_SUCCESS) { xerror(_("sel: %s: Invalid regular expression\n"), str); regfree(®ex); return (-1); } if (!sel_path) { /* Check pattern (STR) against files in CWD */ new_sel = sel_regex_cwd(regex, filetype, invert); } else { /* Check pattern against files in SEL_PATH */ new_sel = sel_regex_nocwd(regex, sel_path, filetype, invert); if (new_sel == -1) return (-1); } regfree(®ex); return new_sel; } /* Convert file type into a macro that can be decoded by stat(3). * If file type is specified, matches will be checked against * this value. */ static mode_t convert_filetype(mode_t *filetype) { switch (*filetype) { case 'b': *filetype = DT_BLK; break; case 'c': *filetype = DT_CHR; break; case 'd': *filetype = DT_DIR; break; case 'f': *filetype = DT_REG; break; case 'l': *filetype = DT_LNK; break; case 's': *filetype = DT_SOCK; break; case 'p': *filetype = DT_FIFO; break; default: xerror(_("sel: '%c': Unrecognized file type.\n" "Try 'sel --help' for more information.\n"), (char)*filetype); return FUNC_FAILURE; } return FUNC_SUCCESS; } static char * parse_sel_params(char ***args, int *ifiletype, mode_t *filetype, int *isel_path) { char *sel_path = (char *)NULL; int i; for (i = 1; (*args)[i]; i++) { if (*(*args)[i] == '-' && (*args)[i][1] && !(*args)[i][2]) { *ifiletype = i; *filetype = (mode_t)*((*args)[i] + 1); } if (*(*args)[i] == ':') { *isel_path = i; sel_path = (*args)[i] + 1; } if (*(*args)[i] == '~') { char *exp_path = tilde_expand((*args)[i]); if (!exp_path) { xerror("sel: '%s': Cannot expand tilde\n", (*args)[i]); *filetype = (mode_t)-1; return (char *)NULL; } free((*args)[i]); (*args)[i] = exp_path; } } if (*filetype != 0 && convert_filetype(filetype) == FUNC_FAILURE) { *filetype = (mode_t)-1; return (char *)NULL; } return sel_path; } static char * construct_sel_path(char *sel_path) { char tmpdir[PATH_MAX + 1]; xstrsncpy(tmpdir, sel_path, sizeof(tmpdir)); if (*sel_path == '.' && xrealpath(sel_path, tmpdir) == NULL) { xerror("sel: '%s': %s\n", sel_path, strerror(errno)); return (char *)NULL; } if (*sel_path == '~') { char *exp_path = tilde_expand(sel_path); if (!exp_path) { xerror("%s\n", _("sel: Error expanding path")); errno = 1; return (char *)NULL; } xstrsncpy(tmpdir, exp_path, sizeof(tmpdir)); free(exp_path); } char *dir = (char *)NULL; if (*tmpdir != '/') { const size_t dir_len = strlen(workspaces[cur_ws].path) + strnlen(tmpdir, sizeof(tmpdir)) + 2; dir = xnmalloc(dir_len, sizeof(char)); snprintf(dir, dir_len, "%s/%s", workspaces[cur_ws].path, tmpdir); } else { dir = savestring(tmpdir, strnlen(tmpdir, sizeof(tmpdir))); } return dir; } static char * check_sel_path(char **sel_path) { const size_t len = strlen(*sel_path); if (len > 0 && (*sel_path)[len - 1] == '/') (*sel_path)[len - 1] = '\0'; if (strchr(*sel_path, '\\')) { char *deq = unescape_str(*sel_path, 0); if (deq) { xstrsncpy(*sel_path, deq, strlen(deq) + 1); free(deq); } } errno = 0; char *dir = construct_sel_path(*sel_path); if (!dir) return (char *)NULL; if (xchdir(dir, NO_TITLE) == -1) { xerror("sel: '%s': %s\n", dir, strerror(errno)); free(dir); return (char *)NULL; } return dir; } static off_t get_sel_file_size(const size_t i, int *status) { *status = 0; if (sel_elements[i].size != (off_t)UNSET) return sel_elements[i].size; struct stat attr; if (lstat(sel_elements[i].name, &attr) == -1) return (off_t)-1; if (S_ISDIR(attr.st_mode)) { fputs(dn_c, stdout); fputs(_("Calculating file size... "), stdout); fflush(stdout); fputs(df_c, stdout); #ifdef USE_DU1 sel_elements[i].size = (off_t)(dir_size(sel_elements[i].name, 0, status) * (xargs.si == 1 ? 1000 : 1024)); #else sel_elements[i].size = dir_size(sel_elements[i].name, 0, status); #endif /* USE_DU1 */ putchar('\r'); ERASE_TO_RIGHT; fflush(stdout); } else { sel_elements[i].size = (off_t)FILE_SIZE(attr); } return sel_elements[i].size; } static int print_sel_results(const int new_sel, const char *sel_path, const char *pattern, const int error) { if (new_sel > 0 && xargs.stealth_mode != 1 && sel_file && save_sel() != FUNC_SUCCESS) { err('e', PRINT_PROMPT, _("sel: Error writing files " "into the selections file\n")); return FUNC_FAILURE; } if (sel_path && xchdir(workspaces[cur_ws].path, NO_TITLE) == -1) { xerror("sel: '%s': %s\n", workspaces[cur_ws].path, strerror(errno)); return FUNC_FAILURE; } if (new_sel <= 0) { if (pattern && error == 0) fputs(_("sel: No matches found\n"), stderr); return FUNC_FAILURE; } get_sel_files(); if (sel_n == 0) { fputs(_("sel: No matches found\n"), stderr); return FUNC_FAILURE; } if (conf.autols == 1 && error == 0) reload_dirlist(); print_reload_msg(SET_SUCCESS_PTR, xs_cb, _("%d file(s) selected\n"), new_sel); print_reload_msg(NULL, NULL, _("%zu total selected file(s)\n"), sel_n); return FUNC_SUCCESS; } static char * construct_sel_filename(const char *dir, const char *name) { char *f = (char *)NULL; size_t flen = 0; if (!dir) { if (*workspaces[cur_ws].path == '/' && !*(workspaces[cur_ws].path + 1)) { flen = strlen(name) + 2; f = xnmalloc(flen, sizeof(char)); snprintf(f, flen, "/%s", name); return f; } flen = strlen(workspaces[cur_ws].path) + strlen(name) + 2; f = xnmalloc(flen, sizeof(char)); snprintf(f, flen, "%s/%s", workspaces[cur_ws].path, name); return f; } flen = strlen(dir) + strlen(name) + 2; f = xnmalloc(flen, sizeof(char)); snprintf(f, flen, "%s/%s", dir, name); return f; } static int select_filename(char *arg, char *dir, int *errors) { int new_sel = 0; if (strchr(arg, '\\')) { char *deq_str = unescape_str(arg, 0); if (deq_str) { xstrsncpy(arg, deq_str, strlen(deq_str) + 1); free(deq_str); } } char *name = arg; if (*name == '.' && *(name + 1) == '/') name += 2; if (*arg != '/') { char *tmp = construct_sel_filename(dir, name); struct stat attr; if (lstat(tmp, &attr) == -1) { xerror("sel: '%s': %s\n", arg, strerror(errno)); (*errors)++; } else { const int r = select_file(tmp); new_sel += r; if (r == 0) (*errors)++; } free(tmp); return new_sel; } struct stat a; if (lstat(arg, &a) == -1) { xerror("sel: '%s': %s\n", name, strerror(errno)); (*errors)++; } else { const int r = select_file(name); new_sel += r; if (r == 0) (*errors)++; } return new_sel; } static int not_just_star(const char *s) { while (*s) { if (*s == '?' || *s == '[' || *s == '{' || *s == '^' || *s == '.' || *s == '|' || *s == '+' || *s == '$') return 1; s++; } return 0; } static int select_pattern(char *arg, const char *dir, const mode_t filetype, int *err) { int ret = sel_glob(arg, dir, filetype); /* Glob failed. Try REGEX (if at least one regex metacharacter not being * asterisk is found). */ if (ret == -1) ret = not_just_star(arg) == 1 ? sel_regex(arg, dir, filetype) : 0; if (ret == -1) (*err)++; return ret; } int sel_function(char **args) { if (!args) return FUNC_FAILURE; if (!args[1] || IS_HELP(args[1])) { puts(_(SEL_USAGE)); return FUNC_SUCCESS; } mode_t filetype = 0; int i, ifiletype = 0, isel_path = 0, new_sel = 0, err = 0, f = 0; char *dir = (char *)NULL, *pattern = (char *)NULL; char *sel_path = parse_sel_params(&args, &ifiletype, &filetype, &isel_path); if (sel_path) { dir = check_sel_path(&sel_path); if (!dir || !*dir) { free(dir); return errno; } } else if (filetype == (mode_t)-1) { /* parse_sel_params() error */ free(dir); return FUNC_FAILURE; } for (i = 1; args[i]; i++) { if (i == ifiletype || i == isel_path) continue; f++; pattern = (char *)NULL; if (check_regex(args[i]) == FUNC_SUCCESS) { pattern = args[i]; if (*pattern == '!') pattern++; } if (!pattern) new_sel += select_filename(args[i], dir, &err); else new_sel += select_pattern(args[i], dir, filetype, &err); } if (f == 0) fputs(_("Missing parameter. Try 's --help'\n"), stderr); free(dir); return print_sel_results(new_sel, sel_path, pattern, err); } void list_selected_files(void) { if (sel_n == 0) { puts(_("sel: No selected files")); return; } if (conf.clear_screen > 0) CLEAR; if (conf.pager == 0) HIDE_CURSOR; printf(_("%s%sSelection Box%s\n"), df_c, BOLD, df_c); int reset_pager = 0; putchar('\n'); struct winsize w; if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &w) == -1) w.ws_row = 24; int t_lines = w.ws_row > 0 ? (int)w.ws_row : 24; t_lines -= 2; size_t counter = 0; size_t i; off_t total = 0; const size_t t = tab_offset; tab_offset = 0; const uint8_t epad = DIGINUM(sel_n); int status = 0; flags |= IN_SELBOX_SCREEN; for (i = 0; i < sel_n; i++) { /* if (pager && counter > (term_lines-2)) { */ if (conf.pager && counter > (size_t)t_lines) { switch (xgetchar()) { /* Advance one line at a time */ case 66: /* fallthrough */ /* Down arrow */ case 10: /* fallthrough */ /* Enter */ case 32: /* Space */ break; /* Advance one page at a time */ case 126: counter = 0; /* Page Down */ break; /* Stop paging (and set a flag to reenable the pager * later) */ case 99: /* fallthrough */ /* 'c' */ case 112: /* fallthrough */ /* 'p' */ case 113: conf.pager = 0; reset_pager = 1; /* 'q' */ break; /* If another key is pressed, go back one position. * Otherwise, some filenames won't be listed.*/ default: i--; continue; } } counter++; printf("%s%*zu%s ", el_c, epad, i + 1, df_c); colors_list(sel_elements[i].name, NO_ELN, NO_PAD, PRINT_NEWLINE); int ret = 0; const off_t s = get_sel_file_size(i, &ret); if (ret != 0) status = ret; if (s != (off_t)-1) total += s; } flags &= ~IN_SELBOX_SCREEN; tab_offset = t; char *human_size = construct_human_size(total); char err[sizeof(xf_cb) + 6]; *err = '\0'; if (status != 0) snprintf(err, sizeof(err), "%s%c%s", xf_cb, DU_ERR_CHAR, NC); char s[MAX_SHADE_LEN]; *s = '\0'; if (conf.colorize == 1) get_color_size(total, s, sizeof(s)); printf(_("\n%sTotal size: %s%s%s%s\n"), df_c, err, s, human_size, df_c); if (conf.pager == 0) UNHIDE_CURSOR; if (reset_pager == 1) conf.pager = 1; } static int edit_selfile(void) { if (!sel_file || !*sel_file || sel_n == 0) return FUNC_FAILURE; struct stat attr; if (stat(sel_file, &attr) == -1) goto ERROR; const time_t prev_mtime = attr.st_mtime; if (open_file(sel_file) != FUNC_SUCCESS) { xerror("%s\n", _("sel: Cannot open the selections file")); return FUNC_FAILURE; } /* Compare new and old modification times: if they match, nothing was modified */ if (stat(sel_file, &attr) == -1) goto ERROR; if (prev_mtime == attr.st_mtime) return FUNC_SUCCESS; const int ret = get_sel_files(); if (conf.autols == 1) reload_dirlist(); print_reload_msg(SET_SUCCESS_PTR, xs_cb, _("%zu file(s) selected\n"), sel_n); return ret; ERROR: xerror("sel: '%s': %s\n", sel_file, strerror(errno)); return FUNC_FAILURE; } static int deselect_entries(char **desel_path, const size_t desel_n, int *error, const int desel_screen) { int dn = (int)desel_n; int i = (int)desel_n; while (--i >= 0) { int j, k, desel_index = -1; if (!desel_path[i]) continue; /* Search the sel array for the path of the entry to be deselected and * store its index. */ k = (int)sel_n; while (--k >= 0) { if (strcmp(sel_elements[k].name, desel_path[i]) == 0) { desel_index = k; break; } } if (desel_index == -1) { dn--; *error = 1; if (desel_screen == 0) { xerror(_("%s: '%s': No such selected file\n"), PROGRAM_NAME, desel_path[i]); } continue; } /* Once the index was found, rearrange the sel array removing the * deselected element (actually, moving each string after it to * the previous position). */ for (j = desel_index; j < (int)(sel_n - 1); j++) { const size_t len = strlen(sel_elements[j + 1].name); sel_elements[j].name = xnrealloc(sel_elements[j].name, len + 1, sizeof(char)); xstrsncpy(sel_elements[j].name, sel_elements[j + 1].name, len + 1); sel_elements[j].size = sel_elements[j + 1].size; } } /* Free the last DN entries from the old sel array. They won't * be used anymore, since they contain the same value as the last * non-deselected element due to the above array rearrangement. */ for (i = 1; i <= dn; i++) { const int sel_index = (int)sel_n - i; if (sel_index >= 0 && sel_elements[sel_index].name) { free(sel_elements[sel_index].name); sel_elements[sel_index].size = (off_t)UNSET; } } return dn; } static int desel_entries(char **desel_elements, const size_t desel_n, const int desel_screen) { char **desel_path = (char **)NULL; int i = (int)desel_n; /* Get entries to be deselected */ if (desel_screen == 1) { /* Coming from the deselect screen */ desel_path = xnmalloc(desel_n, sizeof(char *)); while (--i >= 0) { const int desel_int = atoi(desel_elements[i]); if (desel_int == INT_MIN) { desel_path[i] = (char *)NULL; continue; } desel_path[i] = savestring(sel_elements[desel_int - 1].name, strlen(sel_elements[desel_int - 1].name)); } } else { desel_path = desel_elements; } int err = 0; const int dn = deselect_entries(desel_path, desel_n, &err, desel_screen); /* Update the number of selected files according to the number of * deselected files. */ sel_n = (sel_n - (size_t)dn); if ((int)sel_n < 0) sel_n = 0; if (sel_n > 0) sel_elements = xnrealloc(sel_elements, sel_n, sizeof(struct sel_t)); /* Deallocate local arrays. */ i = (int)desel_n; while (--i >= 0) { if (desel_screen == 1) free(desel_path[i]); free(desel_elements[i]); } if (desel_screen == 1) { free(desel_path); } else if (err == 1) { print_reload_msg(SET_SUCCESS_PTR, xs_cb, _("%d file(s) deselected\n"), dn); print_reload_msg(NULL, NULL, _("%zu total selected file(s)\n"), sel_n); } free(desel_elements); if (err == 1) { save_sel(); return FUNC_FAILURE; } return FUNC_SUCCESS; } /* Deselect all selected files */ int deselect_all(void) { int i = (int)sel_n; while (--i >= 0) { free(sel_elements[i].name); sel_elements[i].name = (char *)NULL; sel_elements[i].size = (off_t)UNSET; } sel_n = 0; return save_sel(); } /* Deselect files passed as parameters to the desel command * Returns zero on success or 1 on error. */ static int deselect_from_args(char **args) { char **ds = xnmalloc(args_n + 1, sizeof(char *)); size_t i, j = 0; for (i = 1; i <= args_n; i++) { char *ptr = normalize_path(args[i], strlen(args[i])); if (!ptr) continue; ds[j] = savestring(ptr, strlen(ptr)); j++; free(ptr); } ds[j] = (char *)NULL; return (desel_entries(ds, j, 0) == FUNC_FAILURE ? FUNC_FAILURE : FUNC_SUCCESS); } /* Desel screen: take user input and return an array of input substrings, * updating N to the number of substrings. */ static char ** get_desel_input(size_t *n) { printf(_("\n%sEnter 'q' to quit or 'e' to edit the selections file\n" "File(s) to be deselected (e.g.: 1 2-6, or *):\n"), df_c); char dp[(MAX_COLOR * 2) + 7]; snprintf(dp, sizeof(dp), "\001%s\002>\001%s\002 ", mi_c, tx_c); char *line = NULL; while (!line) line = rl_no_hist(dp, 0); /* get_substr() will try to expand ranges, in which case a range with * no second field is expanded from the value of the first field to the * ELN of the last listed file in the CWD (value taken from the global * variable FILES). But, since we are deselecting files, FILES must be the * number of selected files (SEL_N), and not that of listed files in * the CWD. */ const filesn_t files_bk = files; files = (filesn_t)sel_n; char **entries = get_substr(line, ' ', 1); files = files_bk; free(line); if (!entries) return (char **)NULL; for (*n = 0; entries[*n]; (*n)++); return entries; } static inline void free_desel_elements(const size_t desel_n, char ***desel_elements) { int i = (int)desel_n; while (--i >= 0) free((*desel_elements)[i]); free(*desel_elements); } static int handle_alpha_entry(const int i, const size_t desel_n, char **desel_elements) { if (*desel_elements[i] == 'e' && !desel_elements[i][1]) { free_desel_elements(desel_n, &desel_elements); return edit_selfile(); } if (*desel_elements[i] == 'q' && !desel_elements[i][1]) { free_desel_elements(desel_n, &desel_elements); if (conf.autols == 1) reload_dirlist(); return FUNC_SUCCESS; } if (*desel_elements[i] == '*' && !desel_elements[i][1]) { free_desel_elements(desel_n, &desel_elements); const int exit_status = deselect_all(); if (conf.autols == 1) reload_dirlist(); return exit_status; } printf(_("desel: '%s': Invalid entry\n"), desel_elements[i]); free_desel_elements(desel_n, &desel_elements); return FUNC_FAILURE; } static int valid_desel_eln(const int i, const size_t desel_n, char **desel_elements) { const int n = atoi(desel_elements[i]); if (n <= 0 || (size_t)n > sel_n) { printf(_("desel: %s: Invalid ELN\n"), desel_elements[i]); free_desel_elements(desel_n, &desel_elements); return FUNC_FAILURE; } return FUNC_SUCCESS; } static int end_deselect(const int err, char ***args) { int exit_status = FUNC_SUCCESS; const size_t argsbk = args_n; size_t desel_files = 0; if (args_n > 0) { size_t i; for (i = 1; i <= args_n; i++) { free((*args)[i]); (*args)[i] = (char *)NULL; desel_files++; } args_n = 0; } if (!err && save_sel() != 0) exit_status = FUNC_FAILURE; get_sel_files(); /* There is still some selected file and we are in the desel * screen: reload this screen. */ if (sel_n > 0 && argsbk == 0) return deselect(*args); if (err) return FUNC_FAILURE; if (conf.autols == 1 && exit_status == FUNC_SUCCESS) reload_dirlist(); if (argsbk > 0) { print_reload_msg(SET_SUCCESS_PTR, xs_cb, _("%zu file(s) deselected\n"), desel_files); print_reload_msg(NULL, NULL, _("%zu total selected file(s)\n"), sel_n); } else { print_reload_msg(NULL, NULL, _("%zu selected file(s)\n"), sel_n); } return exit_status; } static int handle_desel_args(char **args) { if (strcmp(args[1], "*") == 0 || strcmp(args[1], "a") == 0 || strcmp(args[1], "all") == 0) { const size_t n = sel_n; const int ret = deselect_all(); if (conf.autols == 1) reload_dirlist(); if (ret == FUNC_SUCCESS) { print_reload_msg(SET_SUCCESS_PTR, xs_cb, _("%zu file(s) deselected\n"), n); print_reload_msg(NULL, NULL, _("0 total selected file(s)\n")); } return ret; } else { const int err = deselect_from_args(args); return end_deselect(err, &args); } } int deselect(char **args) { if (!args) return FUNC_FAILURE; if (sel_n == 0) { puts(_("desel: No selected files")); return FUNC_SUCCESS; } if (args[1] && *args[1]) return handle_desel_args(args); /* No arguments: print the deselection screen. */ list_selected_files(); size_t desel_n = 0; char **desel_elements = get_desel_input(&desel_n); int i = (int)desel_n; while (--i >= 0) { if (!is_number(desel_elements[i])) /* Only for 'q', 'e', and '*' */ return handle_alpha_entry(i, desel_n, desel_elements); if (valid_desel_eln(i, desel_n, desel_elements) == FUNC_FAILURE) return FUNC_FAILURE; } desel_entries(desel_elements, desel_n, 1); return end_deselect(0, &args); } clifm-1.26.3/src/selection.h000066400000000000000000000024241506632037700156350ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* selection.h */ #ifndef SELECTION_H #define SELECTION_H #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) \ || defined(__DragonFly__) # include #endif /* BSD */ __BEGIN_DECLS int deselect(char **args); void list_selected_files(void); int sel_function(char **args); int select_file(char *file); int save_sel(void); int deselect_all(void); __END_DECLS #endif /* _SELECTION_H */ clifm-1.26.3/src/settings.h000066400000000000000000000750531506632037700155200ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* settings.h - User settings default values */ #ifndef SETTINGS_H #define SETTINGS_H /* User settings */ /* We provide 2 default color schemes: 16 and 256 colors. The 256 colors * version is used if supported by the running terminal. */ /* ############################################ * # 1. Default color definitions (16 colors) # * ############################################ */ /* DEF_FILE_COLORS and DEF_IFACE_COLORS are only used to construct the * default color scheme file in case it can be found neither in the local dir * (usually $HOME/.config/clifm/colors/) nor in the data dir, (usually * /usr/local/share/clifm/colors/). */ #define DEF_FILE_COLORS "bd=1;33:ca=30;41:cd=1:di=1;34:ed=2;34:\ ee=32:ef=2:ex=1;32:fi=0:ln=1;36:mh=30;46:nd=4;1;31:nf=:\ no=31;47:or=2;4;36:ow=34;40:pi=4;45;37:so=45;37:su=37;41:sg=30;43:st=37;44:\ tw=37;42:uf=2;4;37:" #define DEF_IFACE_COLORS "ac=:db=:dd=:de=:df=0:dg=2;35:dk=:dl=2;37:\ dn=2;37:do=:dp=:dr=:dt=:du=35:dw=:dxd=:dxr=:dz=:\ el=36:em=1;31:fc=2;37:hb=36:hc=2;31:lc=:\ hd=36:he=0;36:hn=0:hp=36:hq=33:hr=31:hs=32:hv=32:\ li=1;32:mi=1;36:nm=1;32:ro=:sb=2;33:sc=2;36:sd=2;37:\ sf=4;2;36:sh=2;37:si=1;34:sp=2;31:sx=2;32:sz=4;2;36:\ ti=1;36:ts=4;35:tt=2;1;36:tx=0:\ wc=1;36:wm=1;33:ws1=34:ws2=31:ws3=33:ws4=32:ws5=36:ws6=36:ws7=36:ws8=36:\ xf=1;31:xs=32:" /* If ExtColors is not defined in the color scheme file (or if this file isn't * found), DEF_EXT_COLORS is used instead. */ /* Definitions order: archive, image, video, sound, document, code, uninmportant */ #define DEF_EXT_COLORS "*.tar=1;31:*.tgz=1;31:*.arc=1;31:*.arj=1;31:\ *.taz=1;31:*.lha=1;31:*.lz4=1;31:*.lzh=1;31:*.lzma=1;31:*.tlz=1;31:\ *.txz=1;31:*.tzo=1;31:*.t7z=1;31:*.zip=1;31:*.z=1;31:*.dz=1;31:\ *.gz=1;31:*.lrz=1;31:*.lz=1;31:*.lzo=1;31:*.xz=1;31:*.zst=1;31:\ *.tzst=1;31:*.bz2=1;31:*.bz=1;31:*.tbz=1;31:*.tbz2=1;31:*.tz=1;31:\ *.deb=1;31:*.rpm=1;31:*.jar=1;31:*.war=1;31:*.ear=1;31:*.sar=1;31:\ *.rar=1;31:*.alz=1;31:*.ace=1;31:*.zoo=1;31:*.cpio=1;31:*.7z=1;31:\ *.rz=1;31:*.cab=1;31:*.wim=1;31:*.swm=1;31:*.dwm=1;31:*.esd=1;31:\ *.apk=1;31:\ *.avif=35:*.jpg=35:*.jpeg=35:*.jxl=35:*.mjpg=35:*.mjpeg=35:\ *.gif=35:*.bmp=35:*.xbm=35:*.xpm=35:*.png=35:*.svg=35:*.svgz=35:*.pcx=35:\ *.pbm=35:*.pgm=35:*.ppm=35:*.tga=35:*.tif=35:*.tiff=35:*.mng=35:\ *.mov=1;35:*.mpg=1;35:*.mpeg=1;35:*.m2v=1;35:*.mkv=1;35:*.webm=1;35:\ *.webp=1;35:*.ogm=1;35:*.mp4=1;35:*.m4v=1;35:*.mp4v=1;35:*.vob=1;35:\ *.qt=1;35:*.nuv=1;35:*.wmv=1;35:*.asf=1;35:*.rm=1;35:*.rmvb=1;35:\ *.flc=1;35:*.avi=1;35:*.fli=1;35:*.flv=1;35:*.gl=1;35:*.dl=1;35:\ *.xcf=1;35:*.xwd=1;35:*.yuv=1;35:*.cgm=1;35:*.emf=1;35:*.ogv=1;35:\ *.ogx=1;35:\ *.aac=36:*.au=36:*.m4a=36:*.mid=36:*.midi=36:*.mp3=36:*.mka=36:*.ogg=36:\ *.opus=36:*.spx=36:*.wma=36:*.wv=36:*.wav=36:*.flac=36:*.aif=36:\ *.pdf=1:*.djvu=1:*.epub=1:*.fb2=1:*.mobi=1:*.cbr=1:*.cbz=1:*.ps=1:*.sxw=1:\ *.doc=1:*.docx=1:*.xls=1:*.xlsx=1:*.xlr=1:*.sxi=1:*.ppt=1:*.pptx=1:\ *.odt=1:*.ods=1:*.odp=1:*.rtf=1:\ *.c=1;33:*.c++=1;33:*.h=1;33:*.cc=1;33:*.cpp=1;33:*.h++=1;33:\ *.hh=1;33:*.go=1;33:*.java=1;33:*.js=1;33:*.lua=1;33:*.rb=1;33:*.rs=1;33:\ *.kt=1;33:*.kts=1;33:*.hs=1;33:*.pl=1;33:*.vb=1;33:*.html=01;33:*.htm=1;33:\ *.shtml=1;33:xhtml=1;33:*.xml=1;33:*.php=1;33:*.tex=1;33:*.ltx=1;33:\ *.md=1;33:\ *.cache=2;37:*.tmp=2;37:*.temp=2;37:*.log=2;37:*.bak=2;37:*.bk=2;37:\ *.in=2;37:*.out=2;37:*.part=2;37:*.aux=2;37:*.old=2;37:*.orig=2;37:\ *.rej=2;37:*.swp=2;37:*.pid=2;37:" /* If some color is not defined, one of the below colors will be used instead. * You most likely want to modify this instead of DEF_FILE_COLORS and * DEF_IFACE_COLORS above. */ /* File types */ #define DEF_BD_C "\x1b[1;33m" /* Block device */ #define DEF_CA_C "\x1b[30;41m" /* File with capabilities */ #define DEF_CD_C "\x1b[0;1m" /* Character device */ #define DEF_DI_C "\x1b[1;34m" /* Dir */ #define DEF_ED_C "\x1b[2;34m" /* Empty dir */ #define DEF_EE_C "\x1b[0;32m" /* Empty executable file */ #define DEF_EF_C "\x1b[0;2m" /* Empty regular file */ #define DEF_EX_C "\x1b[1;32m" /* Executable file */ #define DEF_FI_C "\x1b[0m" /* Regular file */ #define DEF_LN_C "\x1b[1;36m" /* Symbolic link */ #define DEF_MH_C "\x1b[30;46m" /* Multi-link */ #define DEF_ND_C "\x1b[1;31m" /* Unaccessible dir */ #define DEF_NF_C "" /* Unaccessible file */ #define DEF_NO_C "\x1b[0;31;47m" /* Unknown file type */ #ifdef __sun #define DEF_OO_C "\x1b[0;35m" /* Solaris door/port (ls default is 1;35) */ #endif /* __sun */ #define DEF_OR_C "\x1b[2;4;36m" /* Orphaned/broken symlink */ #define DEF_OW_C "\x1b[34;40m" /* Other-writable */ #define DEF_PI_C "\x1b[4;45;37m" /* FIFO/pipe */ #define DEF_SG_C "\x1b[30;43m" /* SGID file */ #define DEF_SO_C "\x1b[45;37m" /* Socket */ #define DEF_ST_C "\x1b[37;44m" /* Sticky bit set */ #define DEF_SU_C "\x1b[37;41m" /* SUID file */ #define DEF_TW_C "\x1b[37;42m" /* Sticky and other-writable */ #define DEF_UF_C "\x1b[2;4;37m" /* Un'stat'able file */ /* Interface */ #define DEF_AC_C "\001\x1b[2;37m\002" /* Autocmd indicator */ #define DEF_DF_C "\x1b[0m" /* Reset attributes: default terminal color */ #define DEF_DL_C "\x1b[2;37m" /* Dividing line */ #define DEF_EL_C "\x1b[0;36m" /* ELN's */ #define DEF_EM_C "\001\x1b[1;31m\002" /* Error msg indicator */ #define DEF_FC_C "\x1b[0;2;37m" /* File counter */ #define DEF_LI_C "\001\x1b[1;32m\002" /* Sel files indicator (prompt) */ #define DEF_LI_CB "\x1b[1;32m" /* Sel files indicator (files list) */ #define DEF_MI_C "\x1b[1;36m" /* Misc */ #define DEF_NM_C "\001\x1b[1;32m\002" /* Notice msg indicator */ #define DEF_RO_C "\001\x1b[1;34m\002" /* Read-only mode indicator */ #define DEF_SI_C "\001\x1b[1;34m\002" /* Stealth mode indicator */ #define DEF_TI_C "\001\x1b[1;36m\002" /* Trash indicator */ #define DEF_TX_C "\x1b[0m" /* Input text */ #define DEF_WC_C "\x1b[1;36m" /* Welcome message */ #define DEF_WM_C "\001\x1b[1;33m\002" /* Warning msg indicator */ /* Symlink char indicator (for ColorLinksAsTarget only) */ #define DEF_LC_C "\x1b[1;36m" #define DEF_TS_C "\x1b[4;35m" /* Matching prefix for tab completed possible entries */ #define DEF_TT_C "\x1b[1;2;36m" /* Tilde for truncated filenames */ #define DEF_WP_C "\x1b[0;2;31m" /* Warning prompt input text */ #define DEF_XS_C "\001\x1b[32m\002" /* Exit code: success */ #define DEF_XS_CB "\x1b[32m" /* Exit code: Unicode success indicator */ #define DEF_XF_C "\001\x1b[1;31m\002" /* Exit code: failure */ #define DEF_XF_CB "\x1b[1;31m" /* Exit code: failure (dir read) */ /* Workspaces */ #define DEF_WS1_C "\001\x1b[34m\002" #define DEF_WS2_C "\001\x1b[31m\002" #define DEF_WS3_C "\001\x1b[33m\002" #define DEF_WS4_C "\001\x1b[32m\002" #define DEF_WS5_C "\001\x1b[36m\002" #define DEF_WS6_C "\001\x1b[36m\002" #define DEF_WS7_C "\001\x1b[36m\002" #define DEF_WS8_C "\001\x1b[36m\002" /* Suggestions */ #define DEF_SB_C "\x1b[2;33m" /* Shell builtins */ #define DEF_SC_C "\x1b[2;36m" /* Aliases and binaries in PATH */ #define DEF_SD_C "\x1b[2;37m" /* Internal commands description */ #define DEF_SH_C "\x1b[2;37m" /* Commands history */ #define DEF_SF_C "\x1b[2;4;36m" /* ELN's, bookmark, file, and directory names */ #define DEF_SP_C "\x1b[2;31m" /* Suggestions pointer (12 > filename) */ #define DEF_SX_C "\x1b[2;32m" /* Internal commands and parameters */ #define DEF_SZ_C "\x1b[2;4;36m" /* Filenames (fuzzy) */ /* Highlight */ #define DEF_HB_C "\x1b[0;36m" /* Parenthesis, Brackets ( {[()]} ) */ #define DEF_HC_C "\x1b[2;37m" /* Comments (#comment) */ #define DEF_HD_C "\x1b[0;36m" /* Slashes (for paths) */ #define DEF_HE_C "\x1b[0;36m" /* Expansion operators (* ~) */ #define DEF_HN_C "\x1b[0m" /* Numbers (including ELN's) */ #define DEF_HP_C "\x1b[0;36m" /* Parameters (e.g. -h --help) */ #define DEF_HQ_C "\x1b[0;33m" /* Quotes (single and double) */ #define DEF_HR_C "\x1b[0;31m" /* Redirection operator (>) */ #define DEF_HS_C "\x1b[0;32m" /* Process separators (; & |)*/ #define DEF_HV_C "\x1b[0;32m" /* Variables ($VAR) */ #define DEF_HW_C "\x1b[1;31m" /* Backslash (aka whack) */ /* Colors for the properties and long/detail view functions */ #define DEF_DB_C "\x1b[0;33m" /* File allocated blocks */ #define DEF_DD_C "\x1b[0;36m" /* Modification date */ #define DEF_DE_C "\x1b[0;36m" /* Inode number (long view only) */ #define DEF_DG_C "\x1b[0;2;35m" /* Group ID */ #define DEF_DK_C "\x1b[0;31m" /* Number of links (long view only) */ #define DEF_DN_C "\x1b[0;2;37m" /* Dash (no attribute) */ #define DEF_DO_C "\x1b[0;36m" /* Perms in octal */ #define DEF_DP_C "\x1b[0;35m" /* SUID, SGID, Sticky */ #define DEF_DR_C "\x1b[0;33m" /* Read perm */ #define DEF_DU_C "\x1b[0;35m" /* User ID */ #define DEF_DW_C "\x1b[0;31m" /* Write perm */ #define DEF_DXD_C "\x1b[0;32m" /* Execute perm (dirs) */ #define DEF_DXR_C "\x1b[0;36m" /* Execute perm (reg files) */ /* Default color shades for date field in file properties */ #define DEF_DATE_SHADES_8 "1,31-2,37-1,37,37-2,36,36-2" /* Default color shades for size field in file properties */ #define DEF_SIZE_SHADES_8 "1,31-2,36,32,33,31,35" #define DEF_DIR_ICO_C "\x1b[0;33m" /* ############################################# * # 2. Default color definitions (256 colors) # * ############################################# */ #define DEF_FILE_COLORS_256 "bd=1;38;5;229:ca=30;41:cd=1;38;5;214:di=1;34:\ ed=2;34:ee=32:ef=2:ex=1;32:fi=0:ln=1;36:mh=7;36:nd=1;31:nf=:no=4;31;47:\ or=4;2;36:ow=48;5;235;38;5;33:pi=38;5;5;48;5;238:sg=30;43:so=1;38;5;5;48;5;238:\ st=37;44:su=37;41:tw=37;42:uf=4;2;37:" #define DEF_IFACE_COLORS_256 "ac=:db=:dd=:de=:df=0:dg=2;35:dk=:dl=38;5;243:dn=:\ do=:dp=:dr=:dt=:du=35:dw=:dxd=:dxr=:dz=:el=36:em=1;31:fc=38;5;246:hb=36:hc=2;37:\ hd=36:he=36:hn=:hp=36:hq=LY:hr=31:hs=32:hv=32:lc=38;5;43:li=1;32:mi=1;36:\ nm=1;32:ro=:si=1;34:sb=2;33:sc=2;36:sd=38;5;240:sf=4;2;36:sh=38;5;240:sp=38;5;239:\ sx=2;32:sz=4;2;36:ti=1;36:ts=4;35:tt=1;2;36:tx=0:wc=1;36:wm=38;5;228:ws1=34:\ ws2=31:ws3=38;5;228:ws4=32:ws5=36:ws6=38;5;214:ws7=35:ws8=2;37:xf=1;31:xs=32:" #define DEF_EXT_COLORS_256 "*.tar=1;31:*.tgz=1;31:*.arc=1;31:*.arj=1;31:\ *.taz=1;31:*.lha=1;31:*.lz4=1;31:*.lzh=1;31:*.lzma=1;31:*.tlz=1;31:*.txz=1;31:\ *.tzo=1;31:*.t7z=1;31:*.zip=1;31:*.z=1;31:*.dz=1;31:*.gz=1;31:*.lrz=1;31:\ *.lz=1;31:*.lzo=1;31:*.xz=1;31:*.zst=1;31:*.tzst=1;31:*.bz2=1;31:*.bz=1;31:\ *.tbz=1;31:*.tbz2=1;31:*.tz=1;31:*.deb=1;31:*.rpm=1;31:*.jar=1;31:*.war=1;31:\ *.ear=1;31:*.sar=1;31:*.rar=1;31:*.alz=1;31:*.ace=1;31:*.zoo=1;31:*.cpio=1;31:\ *.7z=1;31:*.rz=1;31:*.cab=1;31:*.wim=1;31:*.swm=1;31:*.dwm=1;31:*.esd=1;31:\ *.apk=1;31:*.iso=1;31:*.img=1;31:\ *.avif=35:*.jpg=35:*.jpeg=35:*.jxl=35:*.mjpg=35:*.mjpeg=35:*.gif=35:*.bmp=35:\ *.xbm=35:*.xpm=35:*.png=35:*.svg=35:*.svgz=35:*.pcx=35:*.pbm=35:*.pgm=35:\ *.ppm=35:*.tga=35:*.tif=35:*.tiff=35:*.mng=35:\ *.mov=1;35:*.mpg=1;35:*.mpeg=1;35:*.m2v=1;35:*.mkv=1;35:*.webm=1;35:\ *.ogm=1;35:*.mp4=1;35:*.m4v=1;35:*.mp4v=1;35:*.vob=1;35:*.qt=1;35:\ *.nuv=1;35:*.wmv=1;35:*.asf=1;35:*.rm=1;35:*.rmvb=1;35:*.flc=1;35:*.avi=1;35:\ *.fli=1;35:*.flv=1;35:*.gl=1;35:*.dl=1;35:*.xcf=1;35:*.xwd=1;35:*.yuv=1;35:\ *.cgm=1;35:*.emf=1;35:*.ogv=1;35:*.ogx=1;35:*.webp=1;35:\ *.aac=38;5;214:*.au=38;5;214:*.m4a=38;5;214:*.mid=38;5;214:*.midi=38;5;214:\ *.mp3=38;5;214:*.mka=38;5;214:*.ogg=38;5;214:*.opus=38;5;214:*.spx=38;5;214:\ *.wma=38;5;214:*.wv=38;5;214:*.wav=38;5;214:*.flac=38;5;214:*.aif=38;5;214:\ *.pdf=38;5;223:*.djvu=38;5;223:*.epub=38;5;223:*.mobi=38;5;223:*.cbr=38;5;223:\ *.cbz=38;5;223:*.fb2=38;5;223:\ *.ps=38;5;228:*.sxw=38;5;228:*.doc=38;5;228:*.docx=38;5;228:*.xls=38;5;228:\ *.xlsx=38;5;228:*.xlr=38;5;228:*.sxi=38;5;228:*.ppt=38;5;228:*.pptx=38;5;228:\ *.odt=38;5;228:*.ods=38;5;228:*.odp=38;5;228:*.odg=38;5;228:*.rtf=38;5;228:\ *.c=1;38;5;247:*.c++=1;38;5;247:*.cc=1;38;5;247:*.cpp=1;38;5;247:\ *.h=1;38;5;247:*.h++=1;38;5;247:*.hh=1;38;5;247:*.go=1;38;5;247:\ *.java=1;38;5;247:*.js=1;38;5;247:*.lua=1;38;5;247:*.php=1;38;5;247:\ *.py=1;38;5;247:*.rb=1;38;5;247:*.rs=1;38;5;247:*.kt=1;38;5;247:\ *.kts=1;38;5;247:*.hs=1;38;5;247:*.pl=1;38;5;247:*.vb=1;38;5;247:\ *.html=38;5;85:*.htm=38;5;85:*.shtml=38;5;85:*.xhtml=38;5;85:*.xml=38;5;85:\ *.rss=38;5;85:*.css=38;5;85:*.tex=38;5;85:*.ltx=38;5;85:*.md=38;5;85:\ *.opf=38;5;85:\ *.cache=38;5;247:*.tmp=38;5;247:*.temp=38;5;247:*.log=38;5;247:*.bak=38;5;247:\ *.bk=38;5;247:*.in=38;5;247:*.out=38;5;247:*.part=38;5;247:*.aux=38;5;247:\ *.old=38;5;247:*.orig=38;5;247:*.rej=38;5;247:*.swp=38;5;247:*.pid=38;5;247:" /* File types */ #define DEF_BD_C256 "\x1b[1;38;5;229m" /* Block device */ #define DEF_CA_C256 "\x1b[30;41m" /* File with capabilities */ #define DEF_CD_C256 "\x1b[1;38;5;214m" /* Character device */ #define DEF_DI_C256 "\x1b[1;34m" /* Dir */ #define DEF_ED_C256 "\x1b[2;34m" /* Empty dir */ #define DEF_EE_C256 "\x1b[0;32m" /* Empty executable file */ #define DEF_EF_C256 "\x1b[0;2m" /* Empty regular file */ #define DEF_EX_C256 "\x1b[1;32m" /* Executable file */ #define DEF_FI_C256 "\x1b[0m" /* Regular file */ #define DEF_LN_C256 "\x1b[1;36m" /* Symbolic link */ #define DEF_MH_C256 "\x1b[7;36m" /* Multi-link */ #define DEF_ND_C256 "\x1b[1;31m" /* Unaccessible dir */ #define DEF_NF_C256 "" /* Unaccessible file */ #define DEF_NO_C256 "\x1b[4;31;47m" /* Unknown file type */ #ifdef __sun #define DEF_OO_C256 "\x1b[0;35m" /* Solaris door/port (ls default is 1;35) */ #endif /* __sun */ #define DEF_OR_C256 "\x1b[2;4;36m" /* Orphaned/broken symlink */ #define DEF_OW_C256 "\x1b[48;5;235;38;5;33m" /* Other-writable */ #define DEF_PI_C256 "\x1b[38;5;5;48;5;238m" /* FIFO/pipe */ #define DEF_SG_C256 "\x1b[30;43m" /* SGID file */ #define DEF_SO_C256 "\x1b[1;38;5;5;48;5;238m" /* Socket */ #define DEF_ST_C256 "\x1b[37;44m" /* Sticky bit set */ #define DEF_SU_C256 "\x1b[37;41m" /* SUID file */ #define DEF_TW_C256 "\x1b[37;42m" /* Sticky and other-writable */ #define DEF_UF_C256 "\x1b[2;4;37m" /* Un'stat'able file */ /* Interface */ #define DEF_AC_C256 "\001\x1b[38;5;247m\002" /* Autocmd indicator */ #define DEF_DF_C256 "\x1b[0m" /* Reset attributes: default terminal color */ #define DEF_DL_C256 "\x1b[38;5;243m" /* Dividing line */ #define DEF_EL_C256 "\x1b[0;36m" /* ELN's */ #define DEF_EM_C256 "\001\x1b[1;31m\002" /* Error msg indicator */ #define DEF_FC_C256 "\x1b[0;38;5;247m" /* File counter */ #define DEF_LI_C256 "\001\x1b[1;32m\002" /* Sel files indicator (prompt) */ #define DEF_LI_CB256 "\x1b[1;32m" /* Sel files indicator (file list) */ #define DEF_MI_C256 "\x1b[1;36m" /* Misc */ #define DEF_NM_C256 "\001\x1b[1;32m\002" /* Notice msg indicator */ #define DEF_RO_C256 "\001\x1b[1;34m\002" /* Read-only mode indicator */ #define DEF_SI_C256 "\001\x1b[1;34m\002" /* Stealth mode indicator */ #define DEF_TI_C256 "\001\x1b[1;36m\002" /* Trash indicator */ #define DEF_TX_C256 "\x1b[0m" /* Input text */ #define DEF_WC_C256 "\x1b[1;36m" /* Welcome message */ #define DEF_WM_C256 "\001\x1b[38;5;228m\002" /* Warning msg indicator */ /* Symlink char indicator (for ColorLinksAsTarget only) */ #define DEF_LC_C256 "\x1b[0;38;5;43m" #define DEF_TS_C256 "\x1b[4;35m" /* Matching prefix for tab completed possible entries */ #define DEF_TT_C256 "\x1b[1;2;36m" /* Tilde for truncated filenames */ #define DEF_WP_C256 "\x1b[0;2;31m" /* Warning prompt input text */ #define DEF_XS_C256 "\001\x1b[32m\002" /* Exit code: success */ #define DEF_XS_CB256 "\x1b[32m" /* Exit code: Unicode success indicator */ #define DEF_XF_C256 "\001\x1b[1;31m\002" /* Exit code: failure */ #define DEF_XF_CB256 "\x1b[1;31m" /* Exit code: failure (dir read) */ /* Workspaces */ #define DEF_WS1_C256 "\001\x1b[34m\002" #define DEF_WS2_C256 "\001\x1b[31m\002" #define DEF_WS3_C256 "\001\x1b[38;5;228m\002" #define DEF_WS4_C256 "\001\x1b[32m\002" #define DEF_WS5_C256 "\001\x1b[36m\002" #define DEF_WS6_C256 "\001\x1b[38;5;214m\002" #define DEF_WS7_C256 "\001\x1b[35m\002" #define DEF_WS8_C256 "\001\x1b[2;37m\002" /* Suggestions */ #define DEF_SB_C256 "\x1b[2;33m" /* Shell builtins */ #define DEF_SC_C256 "\x1b[2;36m" /* Aliases and binaries in PATH */ #define DEF_SD_C256 "\x1b[38;5;240m" /* Internal commands description */ #define DEF_SH_C256 "\x1b[38;5;240m" /* Commands history */ #define DEF_SF_C256 "\x1b[2;4;36m" /* ELN's, bookmark, file, and directory names */ #define DEF_SP_C256 "\x1b[38;5;239m" /* Suggestions pointer (12 > filename) */ #define DEF_SX_C256 "\x1b[2;32m" /* Internal commands and parameters */ #define DEF_SZ_C256 "\x1b[2;4;36m" /* Filenames (fuzzy) */ /* Highlight */ #define DEF_HB_C256 "\x1b[0;36m" /* Parenthesis, Brackets ( {[()]} ) */ #define DEF_HC_C256 "\x1b[2;37m" /* Comments (#comment) */ #define DEF_HD_C256 "\x1b[0;36m" /* Slashes (for paths) */ #define DEF_HE_C256 "\x1b[0;36m" /* Expansion operators (* ~) */ #define DEF_HN_C256 "\x1b[0m" /* Numbers (including ELN's) */ #define DEF_HP_C256 "\x1b[0;36m" /* Parameters (e.g. -h --help) */ #define DEF_HQ_C256 "\x1b[0;38;5;185m" /* Quotes (single and double) */ #define DEF_HR_C256 "\x1b[0;31m" /* Redirection operator (>) */ #define DEF_HS_C256 "\x1b[0;32m" /* Process separators (; & |)*/ #define DEF_HV_C256 "\x1b[0;32m" /* Variables ($VAR) */ #define DEF_HW_C256 "\x1b[1;31m" /* Backslash (aka whack) */ /* Colors for the properties and long/detail view functions */ #define DEF_DB_C256 "\x1b[0;38;5;214m" /* File allocated blocks */ #define DEF_DD_C256 "\x1b[0;36m" /* Modification date */ #define DEF_DE_C256 "\x1b[0;38;5;79m" /* Inode number (long view only) */ #define DEF_DG_C256 "\x1b[0;2;35m" /* Group ID */ #define DEF_DK_C256 "\x1b[0;38;5;197m" /* Number of links (long view only) */ #define DEF_DN_C256 "\x1b[0;2;37m" /* Dash (no attribute) */ #define DEF_DO_C256 "\x1b[0;38;5;79m" /* Perms in octal */ #define DEF_DP_C256 "\x1b[0;38;5;140m" /* SUID, SGID, Sticky */ #define DEF_DR_C256 "\x1b[0;38;5;228m" /* Read perm */ #define DEF_DU_C256 "\x1b[0;35m" /* User ID */ #define DEF_DW_C256 "\x1b[0;38;5;197m" /* Write perm */ #define DEF_DXD_C256 "\x1b[0;38;5;77m" /* Execute perm (dirs) */ #define DEF_DXR_C256 "\x1b[0;38;5;79m" /* Execute perm (reg files) */ /* Default color shades for date field in file properties */ #define DEF_DATE_SHADES_256 "2,197-2,231,253,250,247,244" /* Default color shades for size field in file properties */ #define DEF_SIZE_SHADES_256 "2,197-2,79,77,228,215,203" #define DEF_DIR_ICO_C256 "\x1b[0;33m" /* Character used to print unkonwn/wrong values */ #define UNKNOWN_CHR '?' /* Same as UNKNOWN_CHR, but as a string */ #define UNKNOWN_STR "?" /* Characters used to classify files when running colorless (and classify * is enabled) */ #define CHR_CHR '-' #define BLK_CHR '+' #define BRK_LNK_CHR '!' #define DIR_CHR '/' #define DOOR_CHR '>' /* Solaris only */ #define EXEC_CHR '*' #define FIFO_CHR '|' #define LINK_CHR '@' #define SOCK_CHR '=' #define WHT_CHR '%' /* BSD whiteout */ #define UNK_CHR UNKNOWN_CHR /* Characters used to represent file types in the permissions string * (long view and p/pp command) */ #define DIR_PCHR 'd' #define REG_PCHR '.' #define SOCK_PCHR 's' #define BLKDEV_PCHR 'b' #define CHARDEV_PCHR 'c' #define FIFO_PCHR 'p' #define LNK_PCHR 'l' #define WHT_PCHR 'w' /* Whiteout (BSD) */ #define ARCH1_PCHR 'a' /* Archive state 1 (NetBSD) */ #define ARCH2_PCHR 'A' /* Archive state 2 (NetBSD) */ #define DOOR_PCHR 'D' /* Door (Solaris) */ #define PORT_PCHR 'P' /* Event port (Solaris) */ #define UNK_PCHR UNKNOWN_CHR /* When any of 'nf' or 'nd' color codes is unset, prepend this character * (a single one) to unaccessible files or directories in the file list * (only if not running in light mode and icons are disabled). */ #define NO_PERM_STR "!" #define SELFILE_CHR 'S' /* Prompt indicator */ #define SELFILE_STR "*" /* Selected file mark for file list (ASCII) */ #define SELFILE_STR_U "┃" /* Unicode alternative */ /* Symbolic link mark for listed files (if ColorLinksAsTarget is enabled). */ #define LINK_STR "@" /* ASCII */ #define LINK_STR_U "@" /* Unicode alternative */ #define TRUNC_FILE_CHR '~' /* Character used to mark files with extended attributes (long view) */ #define XATTR_CHAR '@' #define XATTR_STR "@" /* Character used to mark dir sizes for which du(1) reported an error. */ #define DU_ERR_CHAR '!' /* Character used to replace invalid characters (either a control char or an * invalid UTF-8 char) in filenames. */ #define INVALID_CHR '^' /* A few identifiers used in the prompt */ #define ROOT_USR_CHAR '#' #define NON_ROOT_USR_CHAR '$' #define LIGHT_MODE_CHAR 'L' /* String used for the messages pointer (e.g.: "-> 2 file(s) removed") * Note: The color used for this string is 'mi' (in the color scheme file). */ #define MSG_PTR_STR "->" #define MSG_PTR_STR_U "→" /* Unicode alternative */ /* Used only by the 'pp' command on a symbolic link */ #define MSG_PTR_STR_LEFT "<-" #define MSG_PTR_STR_LEFT_U "←" /* Pointer used for successful operations (color used is 'xs')*/ #define SUCCESS_PTR_STR_U "✔" #define SUCCESS_PTR_STR "->" //#define ERROR_PTR_STR_U "✗" //#define ERROR_PTR_STR "->" /* Used in multiple places, e.g., when listing prompts, color schemes, profiles, * and workspaces ('config dump' as well). */ #define MISC_PTR ">" #define MISC_PTR_U "┃" /* If PrintDirCmds is enabled */ #define DIR_CMD_PTR ">" #define DIR_CMD_PTR_U DIR_CMD_PTR /* Character used to print non-matching suggestions, e.g. "12 > filename". */ #define SUG_POINTER '>' #define MNT_UDEVIL 0 #define MNT_UDISKS2 1 /* Default options */ /* Default answers for confirmation prompts: 0 or 'u' (unset), 'y', or 'n' */ #define DEF_ANSWER_BULK_RENAME 'n' /* 'br' command */ #define DEF_ANSWER_OVERWRITE 'n' /* 'c' and 'm' commands mostly */ #define DEF_ANSWER_REMOVE 'n' /* 'r' command */ #define DEF_ANSWER_TRASH 'y' /* 't' command */ #define DEF_ANSWER_DEFAULT 'y' /* Remaining prompts */ #define DEF_ANSWER_DEFAULT_ALL 0 /* All prompts (overrides the above ones) */ #define DEF_APPARENT_SIZE 1 #define DEF_AUTOCD 1 /* InformAutocmd values: * AUTOCMD_MSG_NONE, AUTOCMD_MSG_MINI, AUTOCMD_MSG_SHORT, AUTOCMD_MSG_LONG */ #define DEF_AUTOCMD_MSG AUTOCMD_MSG_PROMPT #define DEF_AUTO_OPEN 1 #define DEF_AUTOLS 1 #define DEF_CASE_SENS_LIST 0 #define DEF_CASE_SENS_DIRJUMP 0 #define DEF_CASE_SENS_PATH_COMP 0 #define DEF_CASE_SENS_SEARCH 0 #define DEF_CD_ON_QUIT 0 #define DEF_CHECK_CAP 1 /* Check files capabilities */ #define DEF_CHECK_EXT 1 /* Check filenames extension (for color) */ #define DEF_CLASSIFY 1 #define DEF_CLEAR_SCREEN 1 #define DEF_CMD_DESC_SUG 1 #define DEF_COLOR_SCHEME "default" #define DEF_COLOR_SCHEME_256 "default-256" #define DEF_COLORS 1 #define DEF_COLOR_LNK_AS_TARGET 0 #define DEF_COLUMNS 1 #define DEF_CP_CMD CP_CP #define DEF_CUR_WS 0 /* First workspace */ #define DEF_CWD_IN_TITLE 0 #define DEF_DESKTOP_NOTIFICATIONS 0 #define DEF_DIRHIST_MAP 0 #define DEF_DISK_USAGE 0 #define DEF_DIV_LINE "-" #define DEF_DIV_LINE_U "─" /* Unicode alternative */ #define DEF_ELN_USE_WORKSPACE_COLOR 0 /* Available styles: QUOTING_STYLE_BACKSLASH, QUOTING_STYLE_SINGLE_QUOTES, * and QUOTING_STYLE_DOUBLE_QUOTES */ #define DEF_QUOTING_STYLE QUOTING_STYLE_BACKSLASH #define DEF_EXT_CMD_OK 1 #define DEF_FILES_COUNTER 1 #define DEF_FOLLOW_SYMLINKS 1 #define DEF_FOLLOW_SYMLINKS_LONG 0 #define DEF_FULL_DIR_SIZE 0 #define DEF_FUZZY_MATCH 0 #define DEF_FUZZY_MATCH_ALGO 2 /* 1 or 2. 2 is Unicode aware, but slower than 1 */ #define DEF_FZF_WIN_HEIGHT 40 /* Max screen percentage taken by FZF */ #define DEF_FZF_PREVIEW 1 #define DEF_HIGHLIGHT 1 #define DEF_HIST_STATUS 1 #define DEF_HISTIGNORE "^[q,Q]$|^quit$|^exit$|^ .*|^#.*|^[0-9]+$|^\\.+$" #define DEF_ICONS 0 #define DEF_ICONS_GAP 1 /* Number of spaces between icons and filenames */ #define DEF_INT_VARS 0 #define DEF_KITTY_KEYS 0 /* Kitty keyboard protocol */ #define DEF_LIGHT_MODE 0 /* Possible values: LNK_CREAT_REG, LNK_CREAT_ABS, and LNK_CREAT_REL */ #define DEF_LINK_CREATION_MODE LNK_CREAT_REG #define DEF_LIST_DIRS_FIRST 1 #define DEF_LISTING_MODE VERTLIST #define DEF_LOG_MSGS 0 #define DEF_LOG_CMDS 0 #define DEF_LONG_VIEW 0 #define DEF_MAX_DIRHIST 100 #define DEF_MAX_FILES UNSET #define DEF_MAX_NAME_LEN 20 #define DEF_MAX_HIST 1000 #define DEF_MAX_JUMP_TOTAL_RANK 100000 #define DEF_MAX_LOG 1000 #define DEF_MAX_PRINTSEL 0 #define DEF_MIN_JUMP_RANK 10 #define DEF_MIN_NAME_TRUNC 20 #define DEF_MOUNT_CMD MNT_UDEVIL #define DEF_MV_CMD MV_MV #define DEF_NOELN 0 #define DEF_ONLY_DIRS 0 #define DEF_PAGER 0 /* Possible values: PAGER_AUTO, PAGER_LONG, and PAGER_SHORT */ #define DEF_PAGER_VIEW PAGER_AUTO #define DEF_PREVIEW_MAX_SIZE -1 /* Max size in KiB. -1 == unlimited */ #define DEF_PRINT_DIR_CMDS 0 #define DEF_PRINTSEL 0 #define DEF_PRINT_REMOVED_FILES 0 #define DEF_PRIORITY_SORT_CHAR "" #define DEF_PRIVATE_WS_SETTINGS 0 #define DEF_PROMPT_B_MIN 0 #define DEF_PROMPT_B_PRECISION 2 #define DEF_PROMPT_F_DIR_LEN 1 #define DEF_PROMPT_F_FULL_LEN_DIRS 1 #define DEF_PROMPT_P_MAX_PATH 40 /* "xfpIsm" = * xattrs/caps/ACLs, file counter, perms, owner/grp names, size (human), mtime */ #define DEF_PROP_FIELDS "xfpIsm" #define DEF_PROP_FIELDS_GAP 1 /* Spaces between columns in long view */ #define DEF_PURGE_JUMPDB 0 #define DEF_READ_AUTOCMD_FILES 0 #define DEF_READ_DOTHIDDEN 0 #define DEF_READONLY 0 #define DEF_REFRESH_ON_EMPTY_LINE 1 #define DEF_REFRESH_ON_RESIZE 1 #define DEF_RELATIVE_TIME 0 #define DEF_REPORT_CWD 0 /* Report CWD to terminal via OSC-7 escape sequence */ #define DEF_RESTORE_LAST_PATH 1 #define DEF_RL_EDIT_MODE 1 #define DEF_SECURE_CMDS 0 #define DEF_SECURE_ENV 0 #define DEF_SECURE_ENV_FULL 0 #define DEF_SHARE_SELBOX 0 /* Supported values: HIDDEN_FALSE, HIDDEN_TRUE, HIDDEN_FIRST, and HIDDEN_LAST */ #define DEF_SHOW_HIDDEN HIDDEN_FALSE #define DEF_SHOW_BACKUP_FILES 1 #define DEF_SKIP_NON_ALNUM_PREFIX 1 #define DEF_SI 0 /* If 1, compute sizes in powers of 1000 instead of 1024 */ /* Supported sort options: * SNONE, SNAME, STSIZE, SATIME, SBTIME, SCTIME, SMTIME * SVER, SEXT, SINO, SOWN, and SGRP */ #define DEF_SORT SVER #define DEF_SORT_REVERSE 0 #define DEF_SPLASH_SCREEN 0 #ifdef __OpenBSD__ # define DEF_SUDO_CMD "doas" #else # define DEF_SUDO_CMD "sudo" #endif /* __OpenBSD__ */ #define DEF_SUG_FILETYPE_COLOR 0 #define DEF_SUG_STRATEGY "ehfjac" #define DEF_SUGGESTIONS 1 #define DEF_TIME_FOLLOWS_SORT 1 #define DEF_TIME_STYLE_RECENT "%b %e %H:%M" /* Timestamps in long view mode */ #define DEF_TIME_STYLE_OLDER "%b %e %Y" #define DEF_TIME_STYLE_LONG "%a %b %d %T %Y %z" /* Used by history and trash */ #define DEF_TIMESTAMP_MARK 0 #define DEF_TIPS 1 #define DEF_TRASRM 0 #define DEF_TRASH_FORCE 0 #define DEF_TRUNC_NAMES 1 #define DEF_WELCOME_MESSAGE 1 /* This expands to "CliFM > The command line file manager" */ #define DEF_WELCOME_MESSAGE_STR PROGRAM_NAME_UPPERCASE " > " PROGRAM_DESC /* We have three search strategies: GLOB_ONLY, REGEX_ONLY, GLOB_REGEX */ #define DEF_SEARCH_STRATEGY GLOB_REGEX /* Four bell styles: BELL_NONE, BELL_AUDIBLE, BELL_VISIBLE, BELL_FLASH */ #define DEF_BELL_STYLE BELL_VISIBLE #define VISIBLE_BELL_DELAY 30 /* Milliseconds */ /* cp and mv commands * All options used for cp(1) and mv(1) are POSIX. No need to check. */ #define DEFAULT_CP_CMD "cp -Rp" #define DEFAULT_CP_CMD_FORCE "cp -Rp" #define DEFAULT_ADVCP_CMD "advcp -gRp" #define DEFAULT_ADVCP_CMD_FORCE "advcp -gRp" #define DEFAULT_WCP_CMD "wcp" #define DEFAULT_RSYNC_CMD "rsync -avP" #define DEFAULT_MV_CMD "mv" #define DEFAULT_MV_CMD_FORCE "mv" #define DEFAULT_ADVMV_CMD "advmv -g" #define DEFAULT_ADVMV_CMD_FORCE "advmv -g" #define DEF_RM_FORCE 0 #define MAX_WS 8 #define MIN_SCREEN_WIDTH 20 #define MIN_SCREEN_HEIGHT 5 /* If running colorless, let's try to use this prompt. If not available, * fallback to DEFAULT_PROMPT_NO_COLOR. */ #define DEF_PROMPT_NO_COLOR_NAME "clifm-no-color" #define DEF_PROMPT_NOTIF 1 #define DEFAULT_PROMPT "\\[\\e[0m\\]\\I[\\S\\[\\e[0m\\]]\\l \ \\A \\u:\\H \\[\\e[0;36m\\]\\w\\n\\[\\e[0m\\]<\\z\\[\\e[0m\\]\ >\\[\\e[0;34m\\] \\$\\[\\e[0m\\] " #define DEFAULT_PROMPT_NO_COLOR "\\I[\\S]\\l \\A \\u:\\H \\w\\n<\\z> \\$ " #define DEF_WARNING_PROMPT 1 #define DEF_WPROMPT_STR_NO_COLOR "(!) > " #if defined(RL_READLINE_VERSION) && RL_READLINE_VERSION < 0x0700 # define DEF_WPROMPT_STR DEF_WPROMPT_STR_NO_COLOR #else # define DEF_WPROMPT_STR "\\[\\e[0;1;31m\\](!)\\[\\e[0;2m\\] > " #endif /* READLINE < 7.0 */ /* These options, except --preview-window=border-left (fzf 0.27), work with at * least fzf 0.18.0 (Mar 31, 2018) */ #define DEF_FZFTAB_OPTIONS "--color=16,prompt:6,fg+:-1,pointer:4,\ hl:2,hl+:2,gutter:-1,marker:2,border:7:dim --bind tab:accept,right:accept,\ left:abort,alt-p:toggle-preview,change:top,alt-up:preview-page-up,\ alt-down:preview-page-down --tiebreak=begin --inline-info --layout=reverse-list \ --preview-window=wrap,border-left" // --preview-window=noborder (0.19, Nov 15, 2019) #define DEF_FZFTAB_OPTIONS_NO_COLOR "--color=bw --bind tab:accept,\ right:accept,left:abort,alt-p:toggle-preview,change:top,alt-up:preview-page-up,\ alt-down:preview-page-down --tiebreak=begin --inline-info --layout=reverse-list \ --preview-window=wrap,border-left" #define DEF_SMENU_OPTIONS "-a t:2,b b:4 c:r ct:2,r sf:6,r st:5,r mt:5,b" /* Name of the file to store thumbnails original paths. * Each line in this file has this format: THUMB_FILE@FILE_URI, * where THUMB_FILE is the name of the thumbnail file (MD5 hash of FILE_URI), * and FILE_URI is the file URI for the absolute path to the original filename. * This file is located in $XDG_CACHE_HOME/clifm/thumbnails */ #define THUMBNAILS_INFO_FILE ".thumbs.info" /* Should we add __APPLE__ here too? */ #if defined(__HAIKU__) # define DEF_TERM_CMD "Terminal" #else # define DEF_TERM_CMD "xterm -e" #endif /* __HAIKU__ */ #define FALLBACK_SHELL "/bin/sh" #if defined(__APPLE__) # define FALLBACK_OPENER "/usr/bin/open" #elif defined(__CYGWIN__) # define FALLBACK_OPENER "cygstart" #elif defined(__HAIKU__) # define FALLBACK_OPENER "open" #else # define FALLBACK_OPENER "xdg-open" #endif /* __APPLE__ */ #endif /* SETTINGS_H */ clifm-1.26.3/src/sort.c000066400000000000000000000261061506632037700146350ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* sort.c -- functions used to sort files */ #include "helpers.h" #include #include #include /* str(n)casecmp() */ #include "autocmds.h" /* update_autocmd_opts() */ #include "aux.h" /* xatoi */ #include "checks.h" #include "listing.h" #include "messages.h" /* SORT_USAGE */ #define F_SORT(a, b) ((a) == (b) ? 0 : ((a) > (b) ? 1 : -1)) #define F_SORT_DIRS(a, b) ((a) == (b) ? 0 : ((a) < (b) ? 1 : -1)) int skip_files(const struct dirent *ent) { /* In case a directory isn't reacheable, like a failed * mountpoint... */ /* struct stat a; if (lstat(ent->d_name, &a) == -1) { fprintf(stderr, _("lstat: cannot access '%s': %s\n"), ent->d_name, strerror(errno)); return 0; } */ if (SELFORPARENT(ent->d_name)) return 0; /* Skip files matching FILTER */ // ADD FILTER TYPE CHECK! if (filter.str && regexec(®ex_exp, ent->d_name, 0, NULL, 0) == FUNC_SUCCESS) return 0; /* If not hidden files */ if (conf.show_hidden == 0 && *ent->d_name == '.') return 0; return 1; } /* Return a pointer to the first alphanumeric character in NAME, or to the * first character if no alphanumeric character is found. * This function is not UTF8 aware, meaning that UTF8 non-alphanemeric * characters are not supported. */ static inline void skip_name_prefixes(char **name) { char *s = *name; while (*s) { if (IS_ALNUM(*s) || IS_UTF8_LEAD_BYTE(*s)) break; s++; } if (!*s) s = *name; *name = s; } /* Simple comparison routine for qsort()ing strings */ int compare_strings(char **s1, char **s2) { #if defined(HAVE_STRCOLL) return strcoll(*s1, *s2); #else const int ret = **s1 - **s2; return ret == 0 ? strcmp(*s1, *s2) : ret; #endif /* HAVE_STRCOLL */ } static inline int check_hidden_file(const char c1, const char c2) { const int ret = ((c1 == '.' && c2 != '.') ? -1 : ((c1 != '.' && c2 == '.') ? 1 : 0)); return (ret == 0 ? 0 : (conf.show_hidden == HIDDEN_FIRST ? ret : -ret)); } static int check_priority_sort_char(const char c1, const char c2) { const char *psch = conf.priority_sort_char; if (!psch[1]) { /* Single char */ return ((c1 == *psch && c2 != *psch) ? -1 : ((c1 != *psch && c2 == *psch) ? 1 : 0)); } while (*psch) { if (c1 == *psch && c2 != *psch) return -1; if (c1 != *psch && c2 == *psch) return 1; psch++; } return 0; } static int namecmp(char *s1, char *s2) { if (conf.skip_non_alnum_prefix == 1) { skip_name_prefixes(&s1); skip_name_prefixes(&s2); } if (!IS_UTF8_LEAD_BYTE(*s1) && !IS_UTF8_LEAD_BYTE(*s2)) { /* None of the strings begins with a unicode char: compare the first * byte of both strings. */ char ac = *s1, bc = *s2; if (conf.case_sens_list == 0) { ac = (char)TOLOWER(*s1); bc = (char)TOLOWER(*s2); } if (bc > ac) return -1; if (bc < ac) return 1; } if (conf.case_sens_list == 0) return strcoll(s1, s2); return strcmp(s1, s2); } static inline int sort_by_extension(struct fileinfo *pa, struct fileinfo *pb) { const char *e1 = (pa->dir == 0 && pa->ext_name) ? pa->ext_name + (pa->ext_name[1] != '\0') : NULL; const char *e2 = (pb->dir == 0 && pb->ext_name) ? pb->ext_name + (pb->ext_name[1] != '\0') : NULL; if (e1 || e2) { if (!e1) return (-1); if (!e2) return 1; return conf.case_sens_list == 1 ? strcmp(e1, e2) : strcasecmp(e1, e2); } return 0; } static inline int sort_by_owner(struct fileinfo *pa, struct fileinfo *pb) { if (pa->uid_i.name && pb->uid_i.name) return namecmp(pa->uid_i.name, pb->uid_i.name); return F_SORT(pa->uid, pb->uid); } static inline int sort_by_group(struct fileinfo *pa, struct fileinfo *pb) { if (pa->gid_i.name && pb->gid_i.name) return namecmp(pa->gid_i.name, pb->gid_i.name); return F_SORT(pa->gid, pb->gid); } static inline int sort_by_type(struct fileinfo *pa, struct fileinfo *pb) { const mode_t m1 = pa->type; const mode_t m2 = pb->type; const int e1 = (pa->type == DT_REG && pa->exec == 1); const int e2 = (pb->type == DT_REG && pb->exec == 1); if (e1 > e2) return 1; if (e2 > e1) return (-1); if (m1 > m2) return 1; if (m2 > m1) return (-1); return sort_by_extension(pa, pb); } static int sort_by_version(char *s1, char *s2, const int have_utf8) { if (have_utf8 == 1) return namecmp(s1, s2); /* xstrverscmp is not UTF-8 aware. */ if (conf.skip_non_alnum_prefix == 1) { skip_name_prefixes(&s1); skip_name_prefixes(&s2); } return xstrverscmp(s1, s2); } int entrycmp(const void *a, const void *b) { struct fileinfo *pa = (struct fileinfo *)a; struct fileinfo *pb = (struct fileinfo *)b; int st = conf.sort; int ret = conf.list_dirs_first == 1 ? F_SORT_DIRS(pa->dir, pb->dir) : 0; if (ret != 0) return ret; ret = (conf.priority_sort_char && *conf.priority_sort_char) ? check_priority_sort_char(*pa->name, *pb->name) : 0; if (ret != 0) return ret; /* > 1 = Either HIDDEN_FIRST or HIDDEN_LAST */ ret = conf.show_hidden > 1 ? check_hidden_file(*pa->name, *pb->name) : 0; if (ret != 0) return ret; if (conf.light_mode == 1 && !ST_IN_LIGHT_MODE(st)) st = SNAME; const int have_utf8 = (pa->utf8 == 1 || pb->utf8 == 1); switch (st) { case STSIZE: ret = F_SORT(pa->size, pb->size); break; case SATIME: /* fallthrough */ case SBTIME: /* fallthrough */ case SCTIME: /* fallthrough */ case SMTIME: ret = F_SORT(pa->time, pb->time); break; case SVER: ret = sort_by_version(pa->name, pb->name, have_utf8); break; case SEXT: ret = sort_by_extension(pa, pb); break; case SINO: ret = F_SORT(pa->inode, pb->inode); break; case SOWN: ret = sort_by_owner(pa, pb); break; case SGRP: ret = sort_by_group(pa, pb); break; case SBLK: ret = F_SORT(pa->blocks, pb->blocks); break; case SLNK: ret = F_SORT(pa->linkn, pb->linkn); break; case STYPE: ret = sort_by_type(pa, pb); break; default: break; } if (ret == 0) ret = namecmp(pa->name, pb->name); return conf.sort_reverse == 0 ? ret : -ret; } /* Same as alphasort, but is uses strcmp instead of sctroll, which is * slower. However, bear in mind that, unlike strcmp(), strcoll() is locale * aware. Use only with C and english locales */ int xalphasort(const struct dirent **a, const struct dirent **b) { int ret = 0; /* The if statements prevent strcmp from running in every * call to the function (it will be called only if the first * character of the two strings is the same), which makes the * function faster */ if ((*a)->d_name[0] > (*b)->d_name[0]) ret = 1; else if ((*a)->d_name[0] < (*b)->d_name[0]) ret = -1; else ret = strcmp((*a)->d_name, (*b)->d_name); return conf.sort_reverse == 0 ? ret : -ret; } /* This is a modification of the alphasort function that makes it case * insensitive. It also sorts without taking the initial dot of hidden * files into account. Note that strcasecmp() isn't locale aware. Use * only with C and english locales */ int alphasort_insensitive(const struct dirent **a, const struct dirent **b) { const int ret = strcasecmp(((*a)->d_name[0] == '.') ? (*a)->d_name + 1 : (*a)->d_name, ((*b)->d_name[0] == '.') ? (*b)->d_name + 1 : (*b)->d_name); return conf.sort_reverse == 0 ? ret : -ret; } char * num_to_sort_name(const int n, const int abbrev) { switch (n) { case SNONE: return "none"; case SNAME: return "name"; case STSIZE: return "size"; case SATIME: return "atime"; case SBTIME: return "btime"; case SCTIME: return "ctime"; case SMTIME: return "mtime"; case SVER: return abbrev ? "ver" : "version"; case SEXT: return abbrev ? "ext" : "extension"; case SINO: return abbrev ? "ino" : "inode"; case SOWN: return abbrev ? "own" : "owner"; case SGRP: return abbrev ? "grp" : "group"; case SBLK: return abbrev ? "blk" : "blocks"; case SLNK: return abbrev ? "lnk" : "links"; case STYPE: return "type"; default: return abbrev ? "unk" : "unknown"; } } void print_sort_method(void) { char *name = num_to_sort_name(conf.sort, 0); printf("%s%s%s%s", BOLD, name, NC, (conf.sort_reverse == 1) ? " [rev]" : ""); if (conf.light_mode == 1 && !ST_IN_LIGHT_MODE(conf.sort)) printf(_(" (not available in light mode: using %sname%s)\n"), BOLD, NC); else putchar('\n'); } static inline int re_sort_files_list(void) { if (conf.autols == 0) return FUNC_SUCCESS; /* sort_switch just tells list_dir() to print a line with the current * sort order at the end of the file list. */ sort_switch = 1; free_dirlist(); const int ret = list_dir(); sort_switch = 0; return ret; } /* If ARG is a string, write the corresponding integer to ARG itself. * Return zero if ARG corresponds to a valid sort method or one * otherwise. */ static inline int set_sort_by_name(char **arg) { size_t i; for (i = 0; i <= SORT_TYPES; i++) { if (*(*arg) == *sort_methods[i].name && strcmp(*arg, sort_methods[i].name) == 0) { if (conf.light_mode == 1 && !ST_IN_LIGHT_MODE(sort_methods[i].num)) { fprintf(stderr, _("st: '%s': Not available in light mode\n"), sort_methods[i].name); return FUNC_FAILURE; } *arg = xnrealloc(*arg, MAX_INT_STR, sizeof(char)); snprintf(*arg, MAX_INT_STR, "%d", sort_methods[i].num); return FUNC_SUCCESS; } } fprintf(stdout, _("st: %s: No such sort order\n"), *arg); return FUNC_FAILURE; } int sort_function(char **arg) { /* No argument: Just print the current sort order. */ if (!arg[1]) { fputs(_("Sorted by "), stdout); print_sort_method(); return FUNC_SUCCESS; } /* Argument is an alphanumerical string */ if (!is_number(arg[1])) { if (*arg[1] == 'r' && strcmp(arg[1], "rev") == 0) { conf.sort_reverse = !conf.sort_reverse; return re_sort_files_list(); } if (set_sort_by_name(&arg[1]) == FUNC_FAILURE) return FUNC_FAILURE; } /* Argument is a number */ const int n = atoi(arg[1]); if (conf.light_mode == 1 && !ST_IN_LIGHT_MODE(n)) { fprintf(stderr, _("st: %d (%s): Not available in light mode\n"), n, num_to_sort_name(n, 0)); return FUNC_FAILURE; } #ifndef ST_BTIME if (n == SBTIME) { fputs(_("st: Birth time is not available on this platform"), stderr); return FUNC_FAILURE; } #endif /* !ST_BTIME */ if (n >= 0 && n <= SORT_TYPES) { conf.sort = n; if (arg[2] && *arg[2] == 'r' && strcmp(arg[2], "rev") == 0) conf.sort_reverse = !conf.sort_reverse; update_autocmd_opts(AC_SORT); return re_sort_files_list(); } /* If arg1 is a number but is not in the range 0-SORT_TYPES, err. */ fprintf(stderr, "%s\n", _(SORT_USAGE)); return FUNC_FAILURE; } clifm-1.26.3/src/sort.h000066400000000000000000000027141506632037700146410ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* sort.h */ #ifndef SORT_H #define SORT_H /* Needed by qsort(3) to use compare_string() as comparison function */ typedef int QSFUNC(const void *, const void *); __BEGIN_DECLS int alphasort_insensitive(const struct dirent **a, const struct dirent **b); int compare_strings(char **s1, char **s2); int entrycmp(const void *a, const void *b); char *num_to_sort_name(const int n, const int abbrev); void print_sort_method(void); int skip_files(const struct dirent *ent); int sort_function(char **arg); int xalphasort(const struct dirent **a, const struct dirent **b); __END_DECLS #endif /* SORT_H */ clifm-1.26.3/src/spawn.c000066400000000000000000000146361506632037700150030ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* spawn.c -- Execute system commands */ #include "helpers.h" #include /* errno */ #ifndef _BE_POSIX # include # ifndef _PATH_DEVNULL # define _PATH_DEVNULL "/dev/null" # endif /* _PATH_DEVNULL */ #else # define _PATH_DEVNULL "/dev/null" #endif /* !_BE_POSIX */ #include /* sigaction */ #include /* strerror */ #include /* fork, execl, execvp, dup2, close, _exit */ #include /* waitpid */ #include "listing.h" /* reload_dirlist */ #include "misc.h" /* xerror */ int get_exit_code(const int status, const int exec_flag) { if (WIFSIGNALED(status)) /* As required by exit(1p), we return a value greater than 128 (E_SIGINT) */ return (E_SIGINT + WTERMSIG(status)); if (WIFEXITED(status)) return WEXITSTATUS(status); return exec_flag == EXEC_BG_PROC ? FUNC_SUCCESS : FUNC_FAILURE; } static int run_in_foreground(const pid_t pid) { int status = 0; /* The parent process calls waitpid() on the child */ if (waitpid(pid, &status, 0) > 0) return get_exit_code(status, EXEC_FG_PROC); /* waitpid() failed */ const int ret = errno; xerror("%s: waitpid: %s\n", PROGRAM_NAME, strerror(errno)); return ret; } static int run_in_background(const pid_t pid) { int status = 0; if (waitpid(pid, &status, WNOHANG) == -1) { const int ret = errno; xerror("%s: waitpid: %s\n", PROGRAM_NAME, strerror(errno)); return ret; } zombies++; return get_exit_code(status, EXEC_BG_PROC); } /* Enable/disable signals for external commands. * Used by launch_execl() and launch_execv(). */ static void set_cmd_signals(void) { struct sigaction sa; memset(&sa, 0, sizeof(sa)); sigemptyset(&sa.sa_mask); sa.sa_flags = 0; sa.sa_handler = SIG_DFL; sigaction(SIGHUP, &sa, NULL); sigaction(SIGINT, &sa, NULL); sigaction(SIGQUIT, &sa, NULL); sigaction(SIGTERM, &sa, NULL); sa.sa_handler = SIG_IGN; sigaction(SIGTSTP, &sa, NULL); } /* Implementation of system(3). * Unlike system(3), which runs a command using '/bin/sh' as the executing * shell, xsystem() uses a custom shell (user.shell) specified via CLIFM_SHELL * or SHELL, falling back to '/bin/sh' only if none of these variables is set. */ static int xsystem(const char *cmd) { char *shell_path = user.shell; char *shell_name = user.shell_basename; if (!shell_path || !*shell_path || !shell_name || !*shell_name) { shell_path = "/bin/sh"; shell_name = "sh"; } int status = 0; pid_t pid = fork(); if (pid < 0) { return (-1); } else if (pid == 0) { set_cmd_signals(); execl(shell_path, shell_name, "-c", cmd, (char *)NULL); _exit(errno); } else { if (waitpid(pid, &status, 0) == pid) return status; return (-1); } } /* Execute a command using the system shell. * * The shell to be used is specified via CLIFM_SHELL or SHELL environment * variables (in this order). If none is set, '/bin/sh' is used instead. * * The shell takes care of special functions such as pipes and stream redirection, * special chars like wildcards, quotes, and escape sequences. * * Use only when the shell is needed; otherwise, launch_execv() should be * used instead. */ int launch_execl(const char *cmd) { if (!cmd || !*cmd) return EINVAL; const int status = xsystem(cmd); const int exit_status = get_exit_code(status, EXEC_FG_PROC); if (flags & DELAYED_REFRESH) { flags &= ~DELAYED_REFRESH; reload_dirlist(); } return exit_status; } /* Execute a command and return the corresponding exit status. The exit * status could be: zero, if everything went fine, or a non-zero value * in case of error. The function takes as first argument an array of * strings containing the command name to be executed and its arguments * (cmd), an integer (bg) specifying if the command should be * backgrounded (1) or not (0), and a flag to control file descriptors. */ int launch_execv(char **cmd, const int bg, const int xflags) { if (!cmd) return EINVAL; int status = 0; pid_t pid = fork(); if (pid < 0) { xerror("%s: fork: %s\n", PROGRAM_NAME, strerror(errno)); return errno; } if (pid == 0) { if (bg == 0) { /* If the program runs in the foreground, reenable signals only * for the child, in case they were disabled for the parent. */ set_cmd_signals(); } if (xflags) { int fd = open(_PATH_DEVNULL, O_WRONLY, 0200); if (fd == -1) { xerror("%s: '%s': %s\n", PROGRAM_NAME, _PATH_DEVNULL, strerror(errno)); _exit(errno); } if (xflags & E_NOSTDIN) dup2(fd, STDIN_FILENO); if (xflags & E_NOSTDOUT) dup2(fd, STDOUT_FILENO); if (xflags & E_NOSTDERR) dup2(fd, STDERR_FILENO); if ((xflags & E_SETSID) && setsid() == (pid_t)-1) { xerror("%s: setsid: %s\n", PROGRAM_NAME, strerror(errno)); close(fd); _exit(errno); } close(fd); } execvp(cmd[0], cmd); /* These error messages will be printed only if E_NOSTDERR is unset. * Otherwise, the caller should print the error messages itself. */ if (errno == ENOENT) { xerror("%s: %s: %s\n", PROGRAM_NAME, cmd[0], NOTFOUND_MSG); _exit(E_NOTFOUND); /* 127, as required by exit(1p). */ } else { xerror("%s: %s: %s\n", PROGRAM_NAME, cmd[0], strerror(errno)); if (errno == EACCES || errno == ENOEXEC) _exit(E_NOEXEC); /* 126, as required by exit(1p). */ else _exit(errno); } } /* Get command status (pid > 0) */ else { if (bg == 1) { status = run_in_background(pid); } else { status = run_in_foreground(pid); if ((flags & DELAYED_REFRESH) && xargs.open != 1) { flags &= ~DELAYED_REFRESH; reload_dirlist(); } } } if (bg == 1 && status == FUNC_SUCCESS && xargs.open != 1) reload_dirlist(); return status; } clifm-1.26.3/src/spawn.h000066400000000000000000000021501506632037700147740ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* spawn.h */ #ifndef SPAWN_H #define SPAWN_H __BEGIN_DECLS int get_exit_code(const int status, const int exec_flag); int launch_execl(const char *cmd); int launch_execv(char **cmd, const int bg, const int xflags); __END_DECLS #endif /* SPAWN_H */ clifm-1.26.3/src/strings.c000066400000000000000000002457211506632037700153450ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* strings.c -- misc string manipulation functions */ /* The xstrsncpy function is taken from https://github.com/jarun/nnn/blob/master/src/nnn.c, * licensed under BSD-2-clause. * All changes are licensed under GPL-2.0-or-later. */ /* The xstrverscmp is taken from https://elixir.bootlin.com/uclibc-ng/latest/source/libc/string/strverscmp.c * (licensed under GPL2.1+). * All changes are licensed under GPL-2.0-or-later. */ #include "helpers.h" #if defined(__HAIKU__) # include #endif /* __HAIKU__ */ #include #ifndef HAVE_ARC4RANDOM # include /* time(2) */ #endif /* !HAVE_ARC4RANDOM */ #include #if !defined(__HAIKU__) && !defined(__OpenBSD__) && !defined(__ANDROID__) # define HAVE_WORDEXP # include #endif /* !__HAIKU__ && !__OpenBSD && !__ANDROID */ #include #if defined(__OpenBSD__) typedef char *rl_cpvfunc_t; # include #else # include #endif /* __OpenBSD__ */ #include "aux.h" #include "checks.h" #include "exec.h" /* exec_chained_cmds */ #ifndef _NO_MAGIC # include "mime.h" /* MIME-type filter expansion */ #endif /* _NO_MAGIC */ #include "misc.h" #include "navigation.h" #include "readline.h" #include "sort.h" #include "tags.h" /* Macros for xstrverscmp() */ /* states: S_N: normal, S_I: comparing integral part, S_F: comparing fractionnal parts, S_Z: idem but with leading Zeroes only */ #define S_N 0x0 #define S_I 0x3 #define S_F 0x6 #define S_Z 0x9 /* result_type: VCMP: return diff; VLEN: compare using len_diff/diff */ #define VCMP 2 #define VLEN 3 #define INT_ARRAY_MAX 256 #ifdef SOLARIS_DOORS # define IS_FILE_TYPE_FILTER(x) ((x) == 'b' || (x) == 'c' || (x) == 'C' \ || (x) == 'd' || (x) == 'D' || (x) == 'f' || (x) == 'F' || (x) == 'g' \ || (x) == 'h' || (x) == 'l' || (x) == 'L' || (x) == 'o' || (x) == 'p' \ || (x) == 's' || (x) == 't' || (x) == 'u' || (x) == 'x' || (x) == 'O' \ || (x) == 'P') #else # define IS_FILE_TYPE_FILTER(x) ((x) == 'b' || (x) == 'c' || (x) == 'C' \ || (x) == 'd' || (x) == 'D' || (x) == 'f' || (x) == 'F' || (x) == 'g' \ || (x) == 'h' || (x) == 'l' || (x) == 'L' || (x) == 'o' || (x) == 'p' \ || (x) == 's' || (x) == 't' || (x) == 'u' || (x) == 'x') #endif /* SOLARIS_DOORS */ #define IS_GLOB(x, y) (((x) == '*' || (x) == '?' || (x) == '{' ) && (y) != ' ') #define IS_WORD(x, y) (((x) == '$' && ((y) == '(' || (y) == '{')) \ || ((x) == '`' && (y) != ' ') || (x) == '~' || (x) == '$') /* QUOTED_WORDS stores indices of words quoted in the command line so that we * can keep track of them and prevent expanding them when spliting the * input string (in parse_input_str()). */ static int quoted_words[INT_ARRAY_MAX]; #define QWORDS_ARRAY_LEN (sizeof(quoted_words) / sizeof(int)) /* Quote the string STR according to conf.quoting_style, that is, using either * single or double quotes. */ char * quote_str(const char *str) { if (!str || !*str || conf.quoting_style == QUOTING_STYLE_BACKSLASH) return (char *)NULL; const size_t len = strlen(str) + 3; char *p = xnmalloc(len, sizeof(char)); const char quote_char = conf.quoting_style == QUOTING_STYLE_DOUBLE_QUOTES ? '"' : '\''; snprintf(p, len, "%c%s%c", quote_char, str, quote_char); return p; } /* Return the number of times the character C is found in the string S. */ size_t count_chars(const char *restrict s, const char c) { if (!s || !*s) return 0; size_t n = 0; while (*s) { if (*s == c) n++; s++; } return n; } /* Return the number of words found in the current readline buffer. */ size_t count_words(size_t *start_word, size_t *full_word) { size_t words = 0, i = 0, first_non_space = 0; char quote = 0; char *b = rl_line_buffer; for (; b[i]; i++) { /* Keep track of open quotes. */ if (b[i] == '\'' || b[i] == '"') quote = quote == b[i] ? 0 : b[i]; if (first_non_space == 0 && b[i] != ' ') { words = first_non_space = 1; *start_word = i; continue; } if (i > 0 && b[i] == ' ' && b[i - 1] != '\\') { if (!*full_word && b[i - 1] != '|' && b[i - 1] != ';' && b[i - 1] != '&') *full_word = i; /* Index of the end of the first full word (cmd). */ if (b[i + 1] && b[i + 1] != ' ') words++; } /* If a process separator char is found, reset variables so that we * can start counting again for the new command. */ if (quote == 0 && cur_color != hq_c && i > 0 && b[i - 1] != '\\' && ((b[i] == '&' && b[i - 1] == '&') || b[i] == '|' || b[i] == ';')) words = first_non_space = *full_word = 0; } return words; } /* Get the last occurrence of the (non-escaped) character C in STR (whose * length is LEN). Return a pointer to it if found or NULL if not. */ char * get_last_chr(char *str, const char c, const int len) { if (!str || !*str) return (char *)NULL; int i = len; while (--i >= 0) { if ((i > 0 && str[i] == c && str[i - 1] != '\\') || (i == 0 && str[i] == c)) return str + i; } return (char *)NULL; } /* Replace all slashes in STR by the character C. */ char * replace_slashes(char *str, const char c) { if (!str || !*str) return (char *)NULL; if (*str == '/') str++; char *p = savestring(str, strlen(str)); char *q = p; while (q && *q) { if (*q == '/' && (q == p || *(q - 1) != '\\')) *q = c; q++; } return p; } /* Find the character C in the string S ignoring case. * Returns a pointer to the matching char in S if C was found, or NULL * otherwise. */ char * xstrcasechr(char *s, char c) { if (!s || !*s) return (char *)NULL; const char uc = (char)TOUPPER(c); while (*s) { if (TOUPPER(*s) == uc) return s; s++; } return (char *)NULL; } /* A reverse strpbrk(3): returns a pointer to the LAST char in S matching * a char in ACCEPT, or NULL if no match is found. */ char * xstrrpbrk(char *s, const char *accept) { if (!s || !*s || !accept || !*accept) return (char *)NULL; const size_t l = strlen(s); int i = (int)l, j; while (--i >= 0) { for (j = 0; accept[j]; j++) { if (s[i] == accept[j]) return s + i; } } return (char *)NULL; } #ifdef _BE_POSIX /* strcasestr(3) is a not POSIX function: let's use this as replacement. * Find the first occurrence of the string B in the string A, ignoring case. */ char * x_strcasestr(char *a, char *b) { if (!a || !b) return (char *)NULL; size_t f = 0; char *p = (char *)NULL, *bb = b; while (*a && *b) { if (TOUPPER(*a) != TOUPPER(*b)) { if (f == 1) { b = bb; f = 0; } else { ++a; } continue; } if (f == 0) p = a; f = 1; ++a; ++b; } return (!*b && f == 1) ? p : (char *)NULL; } #endif /* _BE_POSIX */ /* Modified version of strlcpy(3) using memccpy(3), as suggested here: * https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2349.htm * * Copy at most (N - 1) bytes of SRC into DST and return the number of bytes * copied (excluding the terminating null byte), all at once. * Note that N must be the total size of the buffer DST, including the * terminating NUL byte. * Unlike strncpy(3), it always NULL terminates the destination string (DST), * even if no NUL char is found in the first N characters of SRC. * Returns the number of bytes copied, including the terminating NUL byte. */ size_t xstrsncpy(char *restrict dst, const char *restrict src, size_t n) { char *end = memccpy(dst, src, '\0', n); if (!end) { dst[n - 1] = '\0'; end = dst + n; } return (size_t)(end - dst); } /* A safe strcat(3). Append the string SRC to the buffer DST, always null * terminating DST. */ char * xstrncat(char *restrict dst, const size_t dst_len, const char *restrict src, const size_t dst_size) { xstrsncpy(dst + dst_len, src, dst_size - dst_len); return dst; } /* strverscmp() is a GNU extension, and as such not available on some systems. * This function is a modified version of the GLIBC and uClibc strverscmp() * taken from here: * https://elixir.bootlin.com/uclibc-ng/latest/source/libc/string/strverscmp.c */ /* Compare S1 and S2 as strings holding indices/version numbers, * returning less than, equal to or greater than zero if S1 is less than, * equal to or greater than S2 (for more info, see the texinfo doc). * This function is not UTF8 aware. */ int xstrverscmp(const char *s1, const char *s2) { const unsigned char *p1 = (const unsigned char *)s1; const unsigned char *p2 = (const unsigned char *)s2; /* Symbol(s) 0 [1-9] others Transition (10) 0 (01) d (00) x */ static const uint8_t next_state[] = { /* state x d 0 */ /* S_N */ S_N, S_I, S_Z, /* S_I */ S_N, S_I, S_I, /* S_F */ S_N, S_F, S_F, /* S_Z */ S_N, S_F, S_Z }; static const int8_t result_type[] __attribute__ ((aligned)) = { /* state x/x x/d x/0 d/x d/d d/0 0/x 0/d 0/0 */ /* S_N */ VCMP, VCMP, VCMP, VCMP, VLEN, VCMP, VCMP, VCMP, VCMP, /* S_I */ VCMP, -1, -1, 1, VLEN, VLEN, 1, VLEN, VLEN, /* S_F */ VCMP, VCMP, VCMP, VCMP, VCMP, VCMP, VCMP, VCMP, VCMP, /* S_Z */ VCMP, 1, 1, -1, VCMP, VCMP, -1, VCMP, VCMP }; unsigned char c1, c2; int state, diff; if (p1 == p2) return 0; if (!conf.case_sens_list) { c1 = (unsigned char)TOLOWER(*p1); ++p1; c2 = (unsigned char)TOLOWER(*p2); ++p2; } else { c1 = *p1; c2 = *p2; ++p1; ++p2; } /* Hint: '0' is a digit too */ state = S_N + ((c1 == '0') + (IS_DIGIT(c1) != 0)); while ((diff = c1 - c2) == 0) { if (c1 == '\0') return diff; state = next_state[state]; if (!conf.case_sens_list) { c1 = (unsigned char)TOLOWER(*p1); ++p1; c2 = (unsigned char)TOLOWER(*p2); ++p2; } else { c1 = *p1; c2 = *p2; ++p1; ++p2; } state += (c1 == '0') + (IS_DIGIT(c1) != 0); } state = (int)result_type[state * 3 + (((c2 == '0') + (IS_DIGIT(c2) != 0)))]; switch (state) { case VCMP: return diff; case VLEN: while (*p1 && IS_DIGIT(*p1)) { ++p1; if (!*p2 || !IS_DIGIT(*p2)) return 1; ++p2; } return (*p2 && IS_DIGIT(*p2)) ? -1 : diff; default: return state; } } /* A strlen implementation able to handle wide chars. * Returns the number of columns needed to print the string STR (instead * of the number of bytes needed to store STR). */ size_t wc_xstrlen(const char *restrict str) { /* Convert multi-byte to wide char */ /* Most of the time we use this function to get the number of characters * in names: in this case a buffer of NAME_MAX + 1 is enough. However, we * sometimes use this function to get the number of characters in the * current command line (rl_line_buffer), which has no size limit beyond * what an int can hold (INT_MAX), which is huge. ARG_MAX (128k or more), * though much smaller than INT_MAX, should be enough most of the time. * Even PATH_MAX, usually 4096, is still too narrow to hold a complete * command line: a history entry involving several paths might easily be * longer than PATH_MAX. */ static wchar_t wbuf[ARG_MAX]; const size_t len = mbstowcs(wbuf, str, (size_t)ARG_MAX); if (len == (size_t)-1) /* Invalid multi-byte sequence found */ return 0; const int width = wcswidth(wbuf, len); if (width != -1) return (size_t)width; /* A non-printable wide char was found */ return 0; } /* Truncate an UTF-8 string at width MAX. * Returns the difference beetween MAX and the point at which STR was actually * truncated (this difference should be added to STR as spaces to equate MAX * and get a correct length). * Since a wide char could take two o more columns to be drawn, and since * you might want to truncate the name in the middle of a wide char, this * function won't store the last wide char to avoid taking more columns * than MAX. In this case, the programmer should take care of filling the * empty spaces (usually no more than one) theyself. */ int u8truncstr(char *restrict str, const size_t max) { int len = 0; static wchar_t buf[NAME_BUF_SIZE]; *buf = L'\0'; if (mbstowcs(buf, str, NAME_BUF_SIZE) == (size_t)-1) return 0; int i, bmax = (int)max; if (bmax < 0) bmax = conf.max_name_len; for (i = 0; buf[i]; i++) { int l = wcwidth(buf[i]); if (len + l > bmax) { buf[i] = L'\0'; break; } len += l; } wcsncpy((wchar_t *)str, buf, NAME_BUF_SIZE); /* flawfinder: ignore */ return bmax - len; } /* Return 1 if the string S contains at least one whitespace char (ASCII or * Unicode), or 0 otherwise. * The list of available whitespaces is taken from: * https://en.wikipedia.org/wiki/Whitespace_character */ int detect_space(char *s) { if (!s || !*s) return 0; unsigned char s0, s1, s2; while (*s) { s0 = (unsigned char)*s; if (s0 == ' ' || s0 == '\t') return 1; if (s0 != 0xc2 && (s0 < 0xe1 || s0 > 0xe3)) goto CONT; if ((s1 = (unsigned char)s[1]) == '\0') return 0; if (s0 == 0xc2 && (s1 == 0x85 || s1 == 0xa0)) return 1; /* Unnamed control char or NO-BREAK SPACE. */ if ((s2 = (unsigned char)s[2]) == '\0') return 0; if (s0 == 0xe1) { if (s1 == 0x9a && s2 == 0x80) return 1; /* OGHAM SPACE MARK. */ if (s1 == 0xa0 && s2 == 0x8e) return 1; /* MONGOLIAN VOWEL SEPARATOR. */ } if (s0 == 0xe3 && s1 == 0x80 && s2 == 0x80) return 1; /* IDEOGRAPHIC SPACE. */ if (s0 != 0xe2) goto CONT; if (s1 == 0x81 && s2 == 0x9f) return 1; /* MEDIUM MATHEMATICAL SPACE. */ if (s1 != 0x80) goto CONT; switch (s2) { case 0x80: /* fallthrough */ /* EN QUAD. */ case 0x81: /* fallthrough */ /* EM QUAD. */ case 0x82: /* fallthrough */ /* EN SPACE. */ case 0x83: /* fallthrough */ /* EM SPACE. */ case 0x84: /* fallthrough */ /* THREE-PER-EM SPACE. */ case 0x85: /* fallthrough */ /* FOUR-PER-EM SPACE. */ case 0x86: /* fallthrough */ /* SIX-PER-EM SPACE. */ case 0x87: /* fallthrough */ /* FIGURE SPACE. */ case 0x88: /* fallthrough */ /* PUNCTUATION SPACE. */ case 0x89: /* fallthrough */ /* THIN SPACE. */ case 0x8a: /* fallthrough */ /* HAIR SPACE. */ case 0xa8: /* fallthrough */ /* LINE SEPARATOR. */ case 0xa9: /* fallthrough */ /* PARAGRAPH SEPARATOR. */ case 0xaf: /* NARROW NO-BREAK SPACE. */ return 1; } CONT: s++; } return 0; } /* Check whether the string S begins with a control character. * Return 0 if not, or the number of bytes of the control character. */ static int check_control_char(const unsigned char *s) { if (*s < ' ' || *s == 127) return 1; /* C0 control characters and DEL char */ if (*s == 0xc2 && s[1] >= 0x80 && s[1] <= 0x9f) return 2; /* C1 controls characters */ if (*s == 0xe2 && s[1] == 0x80 && (s[2] == 0xa8 || s[2] == 0xa9)) return 3; /* Line separator (xa8) / Paragraph separator (xa9) */ if (*s == 0xf3 && s[1] == 0xa9 && s[2] == 0x80 && s[3] == 0x81) return 4; /* Language tag */ return 0; } /* Replace invalid characters in NAME by INVALID_CHAR ('^'). * This function is called only if wc_xstrlen() returns zero, in which case * we have either a non-printable char or an invalid multi-byte sequence. */ char * replace_invalid_chars(const char *name) { size_t len = strlen(name); char *n = xnmalloc(len + 1, sizeof(char)); char *p = n; mbstate_t mbstate = {0}; char *q = (char *)name; char *qlimit = q + len; while (*q) { if (*q >= ' ' && *q < 127) { /* Printable ASCII char */ *n = *q; n++; q++; continue; } const int ret = check_control_char((unsigned char *)q); if (ret > 0) { *n = INVALID_CHR; n++; q += ret; continue; } do { wchar_t wc; size_t bytes = mbrtowc(&wc, q, (size_t)(qlimit - q), &mbstate); if (bytes == (size_t)-1 || bytes == (size_t)-2) { *n = INVALID_CHR; /* Invalid UTF-8 */ n++; q++; } else { /* Valid UTF-8 */ for (; bytes > 0; --bytes) { *n = *q; n++; q++; } } if (!*q) break; } while (mbsinit(&mbstate) == 0); } *n = '\0'; return p; } /* Returns the index of the first appearance of c in str, if any, and * -1 if c was not found or if no str. NOTE: Same thing as strchr(), * except that returns an index, not a pointer. */ int strcntchr(const char *str, const char c) { if (!str) return (-1); int i = 0; while (*str) { if (*str == c) return i; i++; str++; } return (-1); } /* Get substring in STR before the last appearance of C. Returns * substring if C is found and NULL if not (or if C was the first * char in STR). */ char * strbfrlst(char *str, const char c) { if (!str || !*str || !c) return (char *)NULL; char *p = str, *q = (char *)NULL; while (*p) { if (*p == c) q = p; p++; } if (!q || q == str) return (char *)NULL; *q = '\0'; const size_t buf_len = (size_t)(q - str); char *buf = malloc(buf_len + 1); if (!buf) { *q = c; return (char *)NULL; } xstrsncpy(buf, str, buf_len + 1); *q = c; return buf; } /* Returns the string between first ocurrence of A and the first * ocurrence of B in STR, or NULL if: there is nothing between A and * B, or A and/or B are not found. */ char * strbtw(char *str, const char a, const char b) { if (!str || !*str || !a || !b) return (char *)NULL; char *p = str, *pa = (char *)NULL, *pb = (char *)NULL; while (*p) { if (!pa) { if (*p == a) pa = p; } else if (*p == b) { pb = p; break; } p++; } if (!pb) return (char *)NULL; *pb = '\0'; const size_t buf_len = (size_t)(pb - pa); char *buf = malloc(buf_len + 1); if (!buf) { *pb = b; return (char *)NULL; } xstrsncpy(buf, pa + 1, buf_len + 1); *pb = b; return buf; } /* Replace the first occurrence of NEEDLE in HAYSTACK by REP. */ char * replace_substr(const char *haystack, const char *needle, char *rep) { if (!haystack || !*haystack || !needle || !*needle || !rep) return (char *)NULL; char *ret = strstr(haystack, needle); if (!ret) return (char *)NULL; char *needle_end = ret + strlen(needle); *ret = '\0'; size_t new_str_len = 0; if (*needle_end) { const size_t rem_len = strlen(needle_end); char *rem = xnmalloc(rem_len + 1, sizeof(char)); xstrsncpy(rem, needle_end, rem_len + 1); new_str_len = strlen(haystack) + strlen(rep) + rem_len + 1; char *new_str = xnmalloc(new_str_len, sizeof(char)); snprintf(new_str, new_str_len, "%s%s%s", haystack, rep, rem); free(rem); return new_str; } new_str_len = strlen(haystack) + strlen(rep) + 1; char *new_str = xnmalloc(new_str_len, sizeof(char)); snprintf(new_str, new_str_len, "%s%s", haystack, rep); return new_str; } /* Generate a random string of LEN bytes using characters from CHARSET. */ char * gen_rand_str(const size_t len) { static const char charset[] = "0123456789#%-_" "abcdefghijklmnopqrstuvwxyz" "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; #ifndef HAVE_ARC4RANDOM srandom((unsigned int)time(NULL)); #endif /* !HAVE_ARC4RANDOM */ char *p = xnmalloc(len + 1, sizeof(char)); char *str = p; int x = (int)len; while (x--) { #ifndef HAVE_ARC4RANDOM const long i = random() % (int)(sizeof(charset) - 1); #else const uint32_t i = arc4random_uniform(sizeof(charset) - 1); #endif /* !HAVE_ARC4RANDOM */ *p = charset[i]; p++; } *p = '\0'; return str; } /* Removes end of line char and quotes (single and double) from STR. * Returns a pointer to the modified STR if the result is non-blank, * or NULL. */ char * remove_quotes(char *str) { if (!str || !*str) return (char *)NULL; char *p = str; size_t len = strlen(p); if (len > 0 && p[len - 1] == '\n') { p[len - 1] = '\0'; len--; } if (len > 0 && (p[len - 1] == '\'' || p[len - 1] == '"')) p[len - 1] = '\0'; if (*p == '\'' || *p == '"') p++; if (!*p) return (char *)NULL; char *q = p; int blank = 1; while (*q) { if (*q != ' ' && *q != '\n' && *q != '\t') { blank = 0; break; } q++; } if (blank == 0) return p; return (char *)NULL; } /* Set all slots in the QUOTED_WORDS array to -1 to mark uninitialized slots. * QUOTED_WORDS is used to keep track (by array index) of all quoted words * in the command line. */ static void init_quoted_words(void) { size_t i; for (i = 0; i < QWORDS_ARRAY_LEN; i++) quoted_words[i] = -1; } /* After expanding multiple fields from an expandable expression, say 'sel', * we lost track of quoted words, because the old indices point now to * expanded fields. * E.g.: 'p sel "12"' -> the quoted word index is originally 2, but after the * expansion of the 'sel' keyword, the index 2 points now to a selected file. * * This function updates quoted word indices taking into account the starting * point, i.e. the word after the expandable expression (START), and the number * of actually expanded fields (N). */ static void update_quoted_words_index(const size_t start, const size_t added_items) { const size_t s = start + 1; const size_t n = added_items - (added_items > 0 ? 1 : 0); size_t i; for (i = 0; i < QWORDS_ARRAY_LEN; i++) if (quoted_words[i] > -1 && (size_t)quoted_words[i] >= s) quoted_words[i] += (int)n; } /* Return 1 if the word at index INDEX is quoted, or zero otherwise. */ static int is_quoted_word(const size_t index) { size_t i; for (i = 0; i < QWORDS_ARRAY_LEN; i++) if (index == (size_t)quoted_words[i]) return 1; return 0; } /* Some commands need quotes to be preserved (they'll handle quotes themselves * later). Return 1 if true or 0 otherwise. */ int cmd_keeps_quotes(char *str) { if (rl_dispatching == 1) return 0; if (flags & IN_BOOKMARKS_SCREEN) return 0; if (*str == '\'' || *str == '"') /* Quoted first word */ return 0; char *p = strchr(str, ' '); if (p) { *p = '\0'; const int ret = is_internal_cmd(str, ALL_CMDS, 1, 1); *p = ' '; /* Let's keep quotes for external commands */ if (ret == 0) return 1; } return (strncmp(str, "ft ", 3) == 0 || strncmp(str, "filter ", 7) == 0); } /* This function takes a string as argument and splits it into substrings * taking tab, new line char, and space as word delimiters, except when * they are preceded by a quote char (single or double quotes) or in * case of command substitution ($(cmd) or `cmd`), in which case * eveything before the corresponding closing char is taken as a single * string. It also escapes special chars. It returns an array of * split strings (without leading and terminating spaces) or NULL if * str is NULL or if no substring was found, i.e., if str contains * only spaces. */ char ** split_str(char *str, const int update_args) { if (!str) return (char **)NULL; init_quoted_words(); size_t buf_len = 0, words = 0, str_len = 0; char *buf = xnmalloc(1, sizeof(char)); char close = 0; char **substr = (char **)NULL; int keep_quotes = cmd_keeps_quotes(str); while (*str) { switch (*str) { /* Command substitution */ case '$': /* fallthrough */ case '`': /* Define the closing char: If "$(" then ')', else '`' */ if (*str == '$') { /* If escaped, it has no special meaning */ if ((str_len && *(str - 1) == '\\') || *(str + 1) != '(') { buf = xnrealloc(buf, buf_len + 1, sizeof(char *)); buf[buf_len] = *str; buf_len++; break; } else { close = ')'; } } else { /* If escaped, it has no special meaning */ if (str_len && *(str - 1) == '\\') { buf = xnrealloc(buf, buf_len + 1, sizeof(char *)); buf[buf_len] = *str; buf_len++; break; } else { /* If '`' advance one char. Otherwise the while * below will stop at first char, which is not * what we want. */ close = *str; str++; buf = xnrealloc(buf, buf_len + 1, sizeof(char *)); buf[buf_len] = '`'; buf_len++; } } /* Copy everything until null byte or closing char. */ while (*str && *str != close) { buf = xnrealloc(buf, buf_len + 1, sizeof(char *)); buf[buf_len] = *str; buf_len++; str++; } /* If the while loop stopped with a null byte, there was * no ending close (either ')' or '`'). */ if (!*str) { xerror(_("%s: Missing '%c'\n"), PROGRAM_NAME, close); free(buf); buf = (char *)NULL; int i = (int)words; while (--i >= 0) free(substr[i]); free(substr); return (char **)NULL; } /* Copy the closing char and add an space: this function * takes space as word breaking char, so that everything * in the buffer will be copied as one single word. */ buf = xnrealloc(buf, buf_len + 2, sizeof(char *)); buf[buf_len] = *str; buf_len++; buf[buf_len] = ' '; break; case '\'': /* fallthrough */ case '"': { if (str_len > 0 && *(str - 1) == '\\') { buf = xnrealloc(buf, buf_len + 1, sizeof(char *)); buf[buf_len] = *str; buf_len++; break; } const int is_quoted = (keep_quotes == 1 || (str_len > 0 && *(str - 1) == '\\')); /* If the quote is escaped, keep it. */ if (is_quoted == 1) { buf = xnrealloc(buf, buf_len + 1, sizeof(char *)); buf[buf_len] = *str; buf_len++; } const char quote = *str; /* A copy of the opening quote. */ str++; /* Move on to the next char. */ /* Copy into the buffer whatever is after the first quote up * to the last quote or NULL. */ while (*str && *str != quote) { /* If char has special meaning, escape it. */ if (!(flags & IN_BOOKMARKS_SCREEN) && is_quoted == 0 && (is_quote_char(*str) || *str == '.')) { /* Escape '.' to prevent realpath expansions. */ buf = xnrealloc(buf, buf_len + 1, sizeof(char *)); buf[buf_len] = '\\'; buf_len++; } buf = xnrealloc(buf, buf_len + 1, sizeof(char *)); buf[buf_len] = *str; buf_len++; str++; } /* The above while breaks with NULL or quote, so that if * *STR is a null byte there was not ending quote. */ if (!*str) { xerror(_("%s: Missing closing quote: '%c'\n"), PROGRAM_NAME, quote); /* Free stuff and return. */ free(buf); buf = (char *)NULL; int i = (int)words; while (--i >= 0) free(substr[i]); free(substr); return (char **)NULL; } if (is_quoted == 1) { /* Add closing quote. */ buf = xnrealloc(buf, buf_len + 1, sizeof(char *)); buf[buf_len] = (char)quote; buf_len++; } /* If coming from parse_input_str (main command line), mark * quoted words: no expansion will be made on these words. */ if (update_args == 1 && words < QWORDS_ARRAY_LEN) quoted_words[words] = (int)words; } break; /* TAB, new line char, and space are taken as word breaking characters. */ case '\t': /* fallthrough */ case '\n': /* fallthrough */ case ' ': /* If escaped, just copy it into the buffer. */ if (str_len && *(str - 1) == '\\') { buf = xnrealloc(buf, buf_len + 1, sizeof(char *)); buf[buf_len] = *str; buf_len++; } else { /* If not escaped, break the string. */ /* Add a terminating null byte to the buffer, and, if not empty, * dump the buffer into the substrings array. */ buf[buf_len] = '\0'; if (buf_len > 0) { substr = xnrealloc(substr, words + 1, sizeof(char *)); substr[words] = savestring(buf, buf_len); words++; } /* Clear the buffer to get a new string. */ memset(buf, '\0', buf_len); buf_len = 0; } break; /* If neither a quote nor a breaking word char nor command substitution, * just dump it into the buffer. */ default: if (*str == '\\' && (flags & IN_BOOKMARKS_SCREEN)) break; buf = xnrealloc(buf, buf_len + 1, sizeof(char *)); buf[buf_len] = *str; buf_len++; break; } str++; str_len++; } /* The while loop stops when the null byte is reached, so that the last * substring is not printed, but still stored in the buffer. Therefore, * we need to add it, if not empty, to our substrings array. */ buf[buf_len] = '\0'; if (buf_len > 0) { if (words == 0) substr = xcalloc(words + 1, sizeof(char *)); else substr = xnrealloc(substr, words + 1, sizeof(char *)); substr[words] = savestring(buf, buf_len); words++; } free(buf); buf = (char *)NULL; if (words > 0) { /* Add a final null string to the array. */ substr = xnrealloc(substr, words + 1, sizeof(char *)); substr[words] = (char *)NULL; if (update_args == 1) args_n = words - 1; return substr; } else { if (update_args == 1) args_n = 0; /* Just in case, but I think it's not required. */ return (char **)NULL; } } /* Return 1 if STR contains only numbers or a range of numbers, or 0 if not. */ static int check_fused_param(char *str) { char *p = str; size_t c = 0, i = 0; int ok = 1; while (*p) { if (i > 0 && *p == '-' && *(p - 1) >= '1' && *(p - 1) <= '9') { c++; } else if (*p == ' ') { break; } else if (*p < '0' || *p > '9') { ok = 0; break; } p++; i++; } return (ok == 1 && c <= 1); } static char * split_fused_param(char *str) { if (!str || !*str || *str == ';' || *str == ':' || *str == '\\') return (char *)NULL; const char *space = strchr(str, ' '); const char *slash = strchr(str, '/'); if (!space && slash) /* If "/some/path/" */ return (char *)NULL; if (space && slash && slash < space) /* If "/some/string something" */ return (char *)NULL; /* The buffer size is the double of STR, just in case each subtr * needs to be splitted. */ char *buf = xnmalloc(((strlen(str) * 2) + 2), sizeof(char)); size_t c = 0; /* Bytes counter */ char *p = str, *pp = str; /* Pointers to original string */ char *b = buf; /* Pointer to our buffer */ size_t words = 1; /* Number of words in str */ while (*p) { switch (*p) { case ' ': /* We only allow splitting the first command word */ if (c && *(p - 1) != ' ' && *(p - 1) != '|' && *(p - 1) != '&' && *(p - 1) != ';') words++; if (p[1]) pp = p + 1; break; case '&': /* fallthrough */ case '|': /* fallthrough */ case ';': words = 1; if (p[1]) pp = p + 1; break; default: break; } if (words == 1 && c && *p >= '1' && *p <= '9' && (*(p - 1) < '0' || *(p - 1) > '9') && check_fused_param(p)) { char t = *p; *p = '\0'; const size_t plen = strlen(pp); if (plen > 0 && pp[plen - 1] != '-' && is_internal_cmd(pp, PARAM_FNAME_NUM, 0, 0)) { *b = ' '; b++; } *p = t; } *b = *p; b++; p++; c++; } *b = '\0'; /* Readjust the buffer size */ const size_t len = strlen(buf); buf = xnrealloc(buf, len + 1, sizeof(char)); return buf; } static int check_shell_functions(const char *str) { if (!str || !*str) return 0; if (conf.int_vars == 0) { /* Take assignements as shell functions */ const char *s = strchr(str, ' '); const char *e = strchr(str, '='); if (!s && e) return 1; if (s && e && e < s) return 1; } /* char **b = (char **)NULL; switch (shell) { case SHELL_NONE: return 0; case SHELL_BASH: b = bash_builtins; break; case SHELL_DASH: b = dash_builtins; break; case SHELL_KSH: b = ksh_builtins; break; case SHELL_TCSH: b = tcsh_builtins; break; case SHELL_ZSH: b = zsh_builtins; break; default: return 0; } */ const char *const funcs[] = { "for ", "for(", "do ", "do(", "while ", "while(", "until ", "until(", "if ", "if(", "[ ", "[[ ", "test ", "case ", "case(", "declare ", "(( ", "set ", "source ", ". ", NULL }; size_t i; for (i = 0; funcs[i]; i++) { const size_t f_len = strlen(funcs[i]); if (*str == *funcs[i] && strncmp(str, funcs[i], f_len) == 0) return 1; } return 0; } /* Check whether STR is an internal command with a fused parameter (CMDNUMBER). * Returns FUNC_SUCCESS if true or FUNC_FAILURE otherwise. */ static int is_fused_param(char *str) { if (!str || !*str || !str[1]) return FUNC_FAILURE; char *p = str, *q = (char *)NULL; int d = 0; while (*p && *p != ' ') { if (d == 0 && p != str && IS_DIGIT(*p) && IS_ALPHA_LOW(*(p - 1))) { q = p; d = 1; } if (d == 1 && IS_ALPHA_LOW(*p)) return FUNC_FAILURE; p++; } if (d == 0) return FUNC_FAILURE; if (!q) return FUNC_FAILURE; const char c = *q; *q = '\0'; const int ret = is_internal_cmd(str, PARAM_FNAME_NUM, 0, 0); *q = c; return (ret == 0 ? FUNC_FAILURE : FUNC_SUCCESS); } #ifndef _NO_TAGS /* Expand "t:TAG" into the corresponding tagged files. * ARGS is an array with the current input substrings, and TAG_INDEX * is the index of the tag expresion (t:) in this array. * The expansion is performed in ARGS array itself. * Returns the number of files tagged as ARGS[TAG_INDEX] or zero on error. */ static size_t expand_tag(char ***args, const int tag_index) { char **s = *args; if (!s) return 0; char *tag = (s[tag_index] && *(s[tag_index] + 1) && *(s[tag_index] + 2)) ? s[tag_index] + 2 : (char *)NULL; if (!tag || !*tag || !tags_dir || is_tag(tag) == 0) return 0; char dir[PATH_MAX + 1]; snprintf(dir, sizeof(dir), "%s/%s", tags_dir, tag); struct dirent **t = (struct dirent **)NULL; const int n = scandir(dir, &t, NULL, conf.case_sens_list ? xalphasort : alphasort_insensitive); if (n == -1) return 0; size_t i, j = 0; if (n <= 2) { /* Empty dir: only self and parent */ for (i = 0; i < (size_t)n; i++) free(t[i]); free(t); return 0; } const size_t len = args_n + 1 + ((size_t)n - 2) + 1; char **p = xnmalloc(len, sizeof(char *)); /* Copy whatever is before the tag expression */ for (i = 0; i < (size_t)tag_index; i++) { p[j] = savestring(s[i], strlen(s[i])); j++; } p[j] = (char *)NULL; /* Append all filenames pointed to by the tag expression */ for (i = 0; i < (size_t)n; i++) { if (SELFORPARENT(t[i]->d_name)) continue; char filename[PATH_MAX + NAME_MAX + 2]; snprintf(filename, sizeof(filename), "%s/%s", dir, t[i]->d_name); char rpath[PATH_MAX + 1]; *rpath = '\0'; char *ret = xrealpath(filename, rpath); if (!ret || !*rpath) { /* This tagged file points to a non-existent file. Just copy * the tag path. */ xstrsncpy(rpath, filename, sizeof(rpath)); } char *esc_str = escape_str(rpath); char *q = esc_str ? esc_str : rpath; p[j] = savestring(q, strlen(q)); j++; free(esc_str); } p[j] = (char *)NULL; /* Append whatever is after the tag expression */ for (i = (size_t)tag_index + 1; i <= args_n; i++) { if (!s[i]) continue; p[j] = savestring(s[i], strlen(s[i])); j++; } p[j] = (char *)NULL; /* Free the dirent struct */ for (i = 0; i < (size_t)n; i++) free(t[i]); free(t); /* Free the original array (ARGS) and make it point to the new * array with the expanded tag expression */ for (i = 0; i <= args_n; i++) free(s[i]); free(s); /* ARGS will be later free'd by run_main_loop(). This is why the leak * warning emitted by GCC(12.1) analyzer is a false positive */ *args = p; args_n = (j > 0) ? j - 1 : 0; /* Do not count self and parent dirs */ return (size_t)n - 2; } static void expand_tags(char ***substr) { size_t ntags = 0, i; int *tag_index = (int *)NULL; struct stat a; for (i = 0; (*substr)[i]; i++) { if (*(*substr)[i] == 't' && *((*substr)[i] + 1) == ':' && lstat((*substr)[i], &a) == -1) { tag_index = xnrealloc(tag_index, ntags + 2, sizeof(int)); tag_index[ntags] = (int)i; ntags++; tag_index[ntags] = -1; } } if (ntags == 0) return; for (i = 0; i < ntags; i++) { const size_t tn = expand_tag(substr, tag_index[i]); /* TN is the number of files tagged as SUBSTR[TAG_INDEX[I]] * Let's update the index of the next tag expression using this * value: if the next tag expression was at index 2, and if * the current tag expression was expanded to 3 files, * the new index of the next tag expression is 4 (the space * occupied by the first expanded file is the same used * by the current tag expression, so that it doesn't count) */ if (tn > 0 && tag_index[i + 1] != -1) tag_index[i + 1] += ((int)tn - 1); } free(tag_index); } #endif /* NO_TAGS */ #ifndef _NO_MAGIC static char ** expand_mime_type_filter(const char *pattern) { if (!pattern || !*pattern) return (char **)NULL; char **t = xnmalloc((size_t)files + 1, sizeof(char *)); char buf[PATH_MAX + 1]; filesn_t i, n = 0; for (i = 0; i < files; i++) { char *name = file_info[i].name; if (virtual_dir == 1) { *buf = '\0'; if (xreadlink(XAT_FDCWD, file_info[i].name, buf, sizeof(buf)) == -1 || !*buf) continue; name = buf; } char *m = (name && *name) ? xmagic(name, MIME_TYPE) : (char *)NULL; if (!m) continue; char *p = strstr(m, pattern); free(m); if (!p) continue; t[n] = savestring(name, strlen(name)); n++; } t[n] = (char *)NULL; if (n == 0) { free(t); return (char **)NULL; } t = xnrealloc(t, (size_t)n + 1, sizeof(char *)); return t; } #endif /* !_NO_MAGIC */ /* Return an array of filenames matching the file type T or NULL if no * match is found. */ static char ** expand_file_type_filter(const char t) { if (files == 0) return (char **)NULL; filesn_t i = 0, c = 0; char **f = xnmalloc((size_t)files + 1, sizeof(char *)); char buf[PATH_MAX + 1]; while (i < files) { char *n = file_info[i].name; if (virtual_dir == 1) { *buf = '\0'; if (xreadlink(XAT_FDCWD, file_info[i].name, buf, sizeof(buf)) == -1 || !*buf) continue; n = buf; } if (!n || !*n) continue; switch (t) { case 'b': if (file_info[i].type == DT_BLK) f[c++] = strdup(n); break; case 'c': if (file_info[i].type == DT_CHR) f[c++] = strdup(n); break; case 'C': if (file_info[i].color == ca_c) f[c++] = strdup(n); break; case 'd': if (file_info[i].dir == 1) f[c++] = strdup(n); break; case 'D': if (file_info[i].color == ed_c) f[c++] = strdup(n); break; #ifdef SOLARIS_DOORS case 'O': if (file_info[i].type == DT_DOOR) f[c++] = strdup(n); break; case 'P': if (file_info[i].type == DT_PORT) f[c++] = strdup(n); break; #endif /* SOLARIS_DOORS */ case 'f': if (file_info[i].type == DT_REG) f[c++] = strdup(n); break; case 'F': if (file_info[i].color == ef_c) f[c++] = strdup(n); break; case 'h': if (file_info[i].dir == 0 && file_info[i].linkn > 1) f[c++] = strdup(n); break; case 'l': if (file_info[i].type == DT_LNK) f[c++] = strdup(n); break; case 'L': if (file_info[i].color == or_c) f[c++] = strdup(n); break; case 'o': if (file_info[i].mode & S_IWOTH) f[c++] = strdup(n); break; case 't': if (file_info[i].mode & S_ISVTX) f[c++] = strdup(n); break; case 'p': if (file_info[i].type == DT_FIFO) f[c++] = strdup(n); break; case 's': if (file_info[i].type == DT_SOCK) f[c++] = strdup(n); break; case 'x': if (file_info[i].exec == 1) f[c++] = strdup(n); break; case 'u': if (file_info[i].mode & S_ISUID) f[c++] = strdup(n); break; case 'g': if (file_info[i].mode & S_ISGID) f[c++] = strdup(n); break; default: break; } i++; } if (c == 0) { free(f); return (char **)NULL; } f[c] = (char *)NULL; f = xnrealloc(f, (size_t)c + 1, sizeof(char *)); return f; } static char ** get_bm_paths(void) { if (bm_n == 0) return (char **)NULL; char **b = xnmalloc(bm_n + 1, sizeof(char *)); size_t i; for (i = 0; i < bm_n && bookmarks[i].path; i++) b[i] = bookmarks[i].path; b[i] = (char *)NULL; return b; } /* Reconstruct the array DST inserting all fields in the array SRC at * index I in DST. NUM is updated to the number of inserted fields. */ static char ** insert_fields(char ***dst, char ***src, const size_t i, size_t *num) { if (!*dst || !*src) return (char **)NULL; char **s = *src; /* 1. Get number of fields in SRC */ size_t sn; for (sn = 0; s[sn]; sn++); if (sn == 0) return (char **)NULL; update_quoted_words_index(i, sn); /* 2. Store fields in DST after the field to be expanded (I) */ char **tail = args_n > i /* Substraction must be bigger than zero */ ? xnmalloc(args_n - i + 1, sizeof(char *)) : (char **)NULL; size_t t, n = 0; if (tail) { for (t = i + 1; (*dst)[t]; t++) tail[n++] = strdup((*dst)[t]); tail[n] = (char *)NULL; } /* 3. Append SRC fields, plus TAIL fields, to DST */ char **d = xnmalloc(args_n + sn + 1, sizeof(char *)); size_t c; for (c = 0; c < i; c++) d[c] = strdup((*dst)[c]); for (n = 0; s[n]; n++) { char *p = escape_str(s[n]); d[c++] = strdup(p ? p : s[n]); free(p); } if (tail) { for (n = 0; tail[n]; n++) { d[c++] = strdup(tail[n]); free(tail[n]); } free(tail); } *num = sn; d[c] = (char *)NULL; return d; } /* Expand the ELN at SUBSTR[I] into the corresponding filename, which is * quoted, if necessary, according to the value of conf.quoting_style. */ static void eln_expand(char ***substr, const size_t i) { const filesn_t num = xatof((*substr)[i]); if (num == -1) return; /* Because of should_expand_eln(), which is called immediately before this * function, it is guaranteed that NUM won't over/under-flow: * NUM is > 0 and <= the number of listed files (and this latter is * never bigger than FILESN_MAX). */ const filesn_t j = num - 1; /* If filename starts with a dash, and the command is external, * use the absolute path to the filename, to prevent the command from * taking the filename as a command option. */ char *abs_path = (char *)NULL; if (file_info[j].name && *file_info[j].name == '-' && !is_internal_cmd((*substr)[0], ALL_CMDS, 1, 1)) abs_path = xrealpath(file_info[j].name, NULL); char *esc_str = (char *)NULL; if (conf.quoting_style == QUOTING_STYLE_BACKSLASH || is_internal_cmd((*substr)[0], ALL_CMDS, 1, 1) || is_number((*substr)[0])) esc_str = escape_str(abs_path ? abs_path : file_info[j].name); else esc_str = quote_str(abs_path ? abs_path : file_info[j].name); free(abs_path); if (!esc_str) return; if (i == 0) flags |= FIRST_WORD_IS_ELN; /* Replace the ELN by the corresponding escaped filename */ struct stat a; if (file_info[j].type == DT_DIR && file_info[j].name[file_info[j].len > 0 ? file_info[j].len - 1 : 0] != '/' /* If running with --follow-links-long, do not expand symlink to dir: we * don't want to operate on the link target, but on the link itself * (despite the fact that we're showing information about the target). */ && (conf.long_view == 0 || xargs.follow_symlinks_long != 1 || (lstat(file_info[j].name, &a) == 0 && !S_ISLNK(a.st_mode)) ) ) { const size_t len = strlen(esc_str) + 2; (*substr)[i] = xnrealloc((*substr)[i], len, sizeof(char)); snprintf((*substr)[i], len, "%s/", esc_str); free(esc_str); } else { free((*substr)[i]); (*substr)[i] = esc_str; } } static void expand_sel(char ***substr) { size_t i = 0; if (sel_n == 0) return; size_t j = 0; char **sel_array = xnmalloc(args_n + sel_n + 2, sizeof(char *)); /* 1. Copy all words before 'sel' */ for (i = 0; i < (size_t)is_sel; i++) { if (!(*substr)[i]) continue; sel_array[j] = savestring((*substr)[i], strlen((*substr)[i])); j++; } update_quoted_words_index((size_t)is_sel, sel_n); /* 2. Add all selected files (in place of 'sel') */ for (i = 0; i < sel_n; i++) { /* Escape selected filenames and copy them into tmp array */ char *esc_str = escape_str(sel_elements[i].name); if (!esc_str) continue; sel_array[j] = esc_str; j++; } /* 3. Add words after 'sel' as well */ for (i = (size_t)is_sel + 1; i <= args_n; i++) { sel_array[j] = savestring((*substr)[i], strlen((*substr)[i])); j++; } sel_array[j] = (char *)NULL; /* 4. Free the original input string and replace by the new sel_array */ for (i = 0; i <= args_n; i++) free((*substr)[i]); free(*substr); (*substr) = sel_array; args_n = j - 1; } /* Expand the 'sel' keyword (or 's:') in SUBSTR to all selected files */ static void expand_sel_keyword(char ***substr) { if (!(*substr) || !(*substr)[0]) return; struct stat a; size_t i; for (i = 1; (*substr)[i]; i++) { if (*(*substr)[i] != 's') continue; if ( ( ((*substr)[i][1] == ':' && !(*substr)[i][2]) || strcmp((*substr)[i], "sel") == 0) && lstat((*substr)[i], &a) == -1) { is_sel = (int)i; if ((size_t)is_sel == args_n) sel_is_last = 1; expand_sel(substr); } } /* If "sel" is last, and there are selected elements, and the command * is either "cp" or "mv", emulate "c" or "m" respectivelly: later, * and final "." will be added to the command, so that we avoid * overwriting files. */ if (sel_n == 0 || is_sel == 0 || sel_is_last == 0) return; if (strcmp((*substr)[0], "cp") == 0 || strcmp((*substr)[0], "mv") == 0) (*substr)[0][1] = '\0'; } static int expand_workspace(char **name) { char *ws_name = *name + 2; if (is_number(ws_name)) { const int n = MAX_WS > 9 ? atoi(ws_name) : *ws_name - '0'; if (n <= 0 || n > MAX_WS || !workspaces[n - 1].path) return FUNC_FAILURE; char *q = escape_str(workspaces[n - 1].path); char *tmp = q ? q : workspaces[n - 1].path; const size_t tmp_len = strlen(tmp); *name = xnrealloc(*name, tmp_len + 1, sizeof(char)); xstrsncpy(*name, tmp, tmp_len + 1); free(q); return FUNC_SUCCESS; } char *deq_str = unescape_str(ws_name, 0); char *tmp_name = deq_str ? deq_str : ws_name; size_t i = 0; for (i = 0; i < MAX_WS; i++) { if (!workspaces[i].path || !workspaces[i].name || *tmp_name != *workspaces[i].name || strcmp(tmp_name, workspaces[i].name) != 0) continue; char *q = escape_str(workspaces[i].path); char *tmp = q ? q : workspaces[i].path; const size_t tmp_len = strlen(tmp); *name = xnrealloc(*name, tmp_len + 1, sizeof(char)); xstrsncpy(*name, tmp, tmp_len + 1); free(q); free(deq_str); return FUNC_SUCCESS; } free(deq_str); return FUNC_FAILURE; } /* Expand the bookmark NAME into the corresponding bookmark path. * Returns FUNC_SUCCESS if the expansion took place or FUNC_FAILURE otherwise */ static int expand_bm_name(char **name) { size_t j; int bm_exp = FUNC_FAILURE; char *p = unescape_str(*name + 2, 0); char *n = p ? p : *name + 2; for (j = 0; j < bm_n; j++) { if (!bookmarks[j].name || *n != *bookmarks[j].name || strcmp(n, bookmarks[j].name) != 0) continue; char *q = escape_str(bookmarks[j].path); char *tmp = q ? q : bookmarks[j].path; const size_t tmp_len = strlen(tmp); *name = xnrealloc(*name, tmp_len + 1, sizeof(char)); xstrsncpy(*name, tmp, tmp_len + 1); free(q); bm_exp = FUNC_SUCCESS; break; } free(p); return bm_exp; } /* Expand the internal variable NAME into its right value. */ static void expand_int_var(char **name) { char *var_name = (*name) + 1; int j = (int)usrvar_n; while (--j >= 0) { if (*var_name != *usr_var[j].name || strcmp(var_name, usr_var[j].name) != 0 || !usr_var[j].value) continue; const size_t val_len = strlen(usr_var[j].value); *name = xnrealloc(*name, val_len + 1, sizeof(char)); xstrsncpy(*name, usr_var[j].value, val_len + 1); break; } } static void expand_file_type(char ***substr) { /* Do not expand file type filter for the 'ft' command. It handles * filters itself (filter_function() in misc.c). */ if (!*substr || ((*substr)[0][0] == 'f' && (*substr)[0][1] == 't' && !(*substr)[0][2])) return; size_t i = 0; struct stat a; int *file_type_array = xnmalloc(INT_ARRAY_MAX, sizeof(int)); size_t file_type_n = 0; for (i = 0; (*substr)[i] && file_type_n < INT_ARRAY_MAX; i++) { if (*(*substr)[i] != '=' || !(*substr)[i][1]) continue; if (IS_FILE_TYPE_FILTER((*substr)[i][1])) { if (lstat((*substr)[i], &a) == -1) { file_type_array[file_type_n] = (int)i; file_type_n++; } continue; } xerror(_("%s: '%c': Invalid file type filter. Run 'help " "file-filters' for more information\n"), PROGRAM_NAME, (*substr)[i][1]); } size_t old_ft = 0; for (i = 0; i < file_type_n; i++) { int index = file_type_array[i] + (int)old_ft; char **p = (*substr)[index][1] ? expand_file_type_filter((*substr)[index][1]) : (char **)NULL; size_t c = 0; if (p) { char **ret = insert_fields(substr, &p, (size_t)index, &c); size_t n; for (n = 0; p[n]; n++) free(p[n]); free(p); if (ret) { for (n = 0; n <= args_n; n++) free((*substr)[n]); free((*substr)); (*substr) = ret; ret = (char **)NULL; args_n += (c > 0 ? c - 1 : 0); } } old_ft += (c > 0 ? c - 1 : 0); } free(file_type_array); } #ifndef _NO_MAGIC static void expand_mime_type(char ***substr) { size_t i = 0; int *mime_type_array = xnmalloc(INT_ARRAY_MAX, sizeof(int)); size_t mime_type_n = 0; struct stat a; for (i = 0; (*substr)[i] && mime_type_n < INT_ARRAY_MAX; i++) { if (*(*substr)[i] == '@' && *((*substr)[i] + 1) && lstat((*substr)[i], &a) == -1) { mime_type_array[mime_type_n] = (int)i; mime_type_n++; } } if (mime_type_n > 0) { fputs(_("Querying MIME types... "), stdout); fflush(stdout); } size_t old_mt = 0; for (i = 0; i < mime_type_n; i++) { int index = mime_type_array[i] + (int)old_mt; char **p = *((*substr)[index] + 1) ? expand_mime_type_filter((*substr)[index] + 1) : (char **)NULL; size_t c = 0; if (p) { char **ret = insert_fields(substr, &p, (size_t)index, &c); size_t n; for (n = 0; p[n]; n++) free(p[n]); free(p); if (ret) { for (n = 0; n <= args_n; n++) free((*substr)[n]); free((*substr)); (*substr) = ret; ret = (char **)NULL; args_n += (c > 0 ? c - 1 : 0); } } old_mt += (c > 0 ? c - 1 : 0); } if (mime_type_n > 0) { putchar('\r'); ERASE_TO_RIGHT; fflush(stdout); } free(mime_type_array); } #endif /* !_NO_MAGIC */ static void expand_bookmarks(char ***substr) { size_t i = 0; struct stat a; int *bm_array = xnmalloc(INT_ARRAY_MAX, sizeof(int)); size_t bn = 0; for (i = 0; (*substr)[i] && bn < INT_ARRAY_MAX; i++) { if (*(*substr)[i] == 'b' && *((*substr)[i] + 1) == ':' && !*((*substr)[i] + 2) && lstat((*substr)[i], &a) == -1) { bm_array[bn] = (int)i; bn++; } } size_t old_bm = 0; for (i = 0; i < bn; i++) { int index = bm_array[i] + (int)old_bm; char **p = get_bm_paths(); size_t c = 0; if (p) { char **ret = insert_fields(substr, &p, (size_t)index, &c); free(p); if (ret) { size_t n; for (n = 0; n <= args_n; n++) free((*substr)[n]); free((*substr)); (*substr) = ret; ret = (char **)NULL; args_n += (c > 0 ? c - 1 : 0); } } old_bm += (c > 0 ? c - 1 : 0); } free(bm_array); } static int expand_glob(char ***substr, const int *glob_array, const size_t glob_n) { size_t old_pathc = 0; size_t i = 0; size_t g = 0; for (g = 0; g < (size_t)glob_n; g++) { glob_t globbuf; if (is_quoted_word((size_t)glob_array[g] + old_pathc)) continue; if (glob((*substr)[glob_array[g] + (int)old_pathc], GLOB_BRACE | GLOB_TILDE, NULL, &globbuf) != FUNC_SUCCESS) { globfree(&globbuf); continue; } if (globbuf.gl_pathc == 0) goto CONT; size_t j = 0; char **glob_cmd = (char **)NULL; glob_cmd = xcalloc(args_n + globbuf.gl_pathc + 1, sizeof(char *)); for (i = 0; i < ((size_t)glob_array[g] + old_pathc); i++) { glob_cmd[j] = savestring((*substr)[i], strlen((*substr)[i])); j++; } for (i = 0; i < globbuf.gl_pathc; i++) { if (SELFORPARENT(globbuf.gl_pathv[i])) continue; char *esc_str = (char *)NULL; /* Escape the globbed filename and copy it */ if (virtual_dir == 1 && is_file_in_cwd(globbuf.gl_pathv[i])) { char buf[PATH_MAX + 1]; *buf = '\0'; if (xreadlink(XAT_FDCWD, globbuf.gl_pathv[i], buf, sizeof(buf)) == -1 || !*buf) continue; esc_str = escape_str(buf); } else { esc_str = escape_str(globbuf.gl_pathv[i]); } if (esc_str) { glob_cmd[j] = esc_str; j++; } else { xerror(_("%s: '%s': Error quoting filename\n"), PROGRAM_NAME, globbuf.gl_pathv[i]); continue; } } for (i = (size_t)glob_array[g] + old_pathc + 1; i <= args_n; i++) { glob_cmd[j] = savestring((*substr)[i], strlen((*substr)[i])); j++; } glob_cmd[j] = (char *)NULL; for (i = 0; i <= args_n; i++) free((*substr)[i]); free((*substr)); (*substr) = glob_cmd; glob_cmd = (char **)NULL; args_n = j - 1; CONT: old_pathc += (globbuf.gl_pathc - 1); globfree(&globbuf); } return 0; } #ifdef HAVE_WORDEXP static int expand_word(char ***substr, const int *word_array, const size_t word_n) { size_t old_pathc = 0; size_t w = 0, i = 0; const int is_sel_cmd = (strcmp((*substr)[0], "s") == 0 || strcmp((*substr)[0], "sel") == 0); for (w = 0; w < word_n; w++) { if (is_sel_cmd == 1) { /* If the command is 'sel', perform only command substitution * and environment variables expansion. Otherwise, wordexp(3) * modifies the input string and breaks other expansions made * by the sel function, mostly regex expansion. */ char *p = strchr((*substr)[word_array[w] + (int)old_pathc], '$'); if (p && *(p + 1) != '(' && (*(p + 1) < 'A' || *(p + 1) > 'Z')) continue; } wordexp_t wordbuf; if (wordexp((*substr)[word_array[w] + (int)old_pathc], &wordbuf, 0) != FUNC_SUCCESS) { wordfree(&wordbuf); continue; } if (wordbuf.we_wordc) { size_t j = 0; char **word_cmd = xcalloc(args_n + wordbuf.we_wordc + 1, sizeof(char *)); for (i = 0; i < ((size_t)word_array[w] + old_pathc); i++) { word_cmd[j] = savestring((*substr)[i], strlen((*substr)[i])); j++; } for (i = 0; i < wordbuf.we_wordc; i++) { /* Escape the globbed filename and copy it */ char *esc_str = escape_str(wordbuf.we_wordv[i]); if (esc_str) { word_cmd[j] = esc_str; j++; } else { xerror(_("%s: '%s': Error quoting filename\n"), PROGRAM_NAME, wordbuf.we_wordv[i]); size_t k = 0; for (k = 0; k < j; k++) free(word_cmd[k]); free(word_cmd); word_cmd = (char **)NULL; for (k = 0; k <= args_n; k++) free((*substr)[k]); free((*substr)); return (-1); } } for (i = (size_t)word_array[w] + old_pathc + 1; i <= args_n; i++) { word_cmd[j] = savestring((*substr)[i], strlen((*substr)[i])); j++; } word_cmd[j] = (char *)NULL; for (i = 0; i <= args_n; i++) free((*substr)[i]); free((*substr)); (*substr) = word_cmd; word_cmd = (char **)NULL; args_n = j - 1; } old_pathc += (wordbuf.we_wordc - 1); wordfree(&wordbuf); } return 0; } #endif /* HAVE_WORDEXP */ static size_t check_ranges(char ***substr, int **range_array) { size_t i = 0, j = 0, n = 0; struct stat a; for (i = 0; i <= args_n; i++) { if (!(*substr)[i] || is_quoted_word(i) || lstat((*substr)[i], &a) != -1) continue; const size_t len = strlen((*substr)[i]); for (j = 0; (*substr)[i][j]; j++) { /* If some alphabetic char, besides '-', is found in the * string, we have no range. */ if ((*substr)[i][j] != '-' && !IS_DIGIT((*substr)[i][j])) break; /* If a range is found, store its index. */ if (j > 0 && j < len && (*substr)[i][j] == '-' && IS_DIGIT((*substr)[i][j - 1])) { if (n >= INT_ARRAY_MAX) break; (*range_array)[n] = (int)i; n++; } } } return n; } /* Expand a range of numbers given by STR. It will expand the range * provided that both extremes are numbers, bigger than zero, equal or * smaller than the number of files currently listed on the screen, and * the second (right) extreme is bigger than the first (left). Returns * an array of int's with the expanded range or NULL if one of the * above conditions is not met. */ static filesn_t * expand_range(char *str, int listdir) { if (!str || !*str) return (filesn_t *)NULL; struct stat a; if (lstat(str, &a) != -1) return (filesn_t *)NULL; char *p = strchr(str, '-'); if (!p || p == str || *(p - 1) < '0' || *(p - 1) > '9') return (filesn_t *)NULL; *p = '\0'; const int ret = is_number(str); *p = '-'; if (!ret) return (filesn_t *)NULL; const filesn_t afirst = xatof(str); ++p; filesn_t asecond = 0; if (!*p) { /* No second field: assume last listed file */ asecond = files; } else { if (!is_number(p)) return (filesn_t *)NULL; asecond = xatof(p); } if (afirst == -1 || asecond == -1) return (filesn_t *)NULL; if (listdir) { if (afirst <= 0 || afirst > files || asecond <= 0 || asecond > files || afirst >= asecond) return (filesn_t *)NULL; } else { if (afirst >= asecond) return (filesn_t *)NULL; } filesn_t *buf = xcalloc((size_t)(asecond - afirst) + 2, sizeof(filesn_t)); filesn_t i, j = 0; for (i = afirst; i <= asecond; i++) { buf[j] = i; j++; } return buf; } static void expand_ranges(char ***substr) { size_t i = 0, j = 0; int *range_array = xnmalloc(INT_ARRAY_MAX, sizeof(int)); const size_t ranges_ok = check_ranges(substr, &range_array); if (ranges_ok == 0) { free(range_array); return; } size_t old_ranges_n = 0; size_t r = 0; for (r = 0; r < ranges_ok; r++) { size_t ranges_n = 0; filesn_t *ranges = expand_range((*substr)[range_array[r] + (int)old_ranges_n], 1); if (ranges) { j = 0; for (ranges_n = 0; ranges[ranges_n]; ranges_n++); update_quoted_words_index((size_t)range_array[r] + old_ranges_n, ranges_n); char **ranges_cmd = (char **)NULL; ranges_cmd = xcalloc(args_n + ranges_n + 2, sizeof(char *)); for (i = 0; i < (size_t)range_array[r] + old_ranges_n; i++) { if (!(*substr)[i]) continue; ranges_cmd[j] = savestring((*substr)[i], strlen((*substr)[i])); j++; } for (i = 0; i < ranges_n; i++) { const size_t len = (size_t)DIGINUM(ranges[i]) + 1; ranges_cmd[j] = xnmalloc(len, sizeof(int)); snprintf(ranges_cmd[j], len, "%zd", ranges[i]); j++; } for (i = (size_t)range_array[r] + old_ranges_n + 1; i <= args_n; i++) { if (!(*substr)[i]) continue; ranges_cmd[j] = savestring((*substr)[i], strlen((*substr)[i])); j++; } ranges_cmd[j] = (char *)NULL; free(ranges); for (i = 0; i <= args_n; i++) free((*substr)[i]); free((*substr)); (*substr) = ranges_cmd; args_n = j - 1; } old_ranges_n += (ranges_n - 1); } free(range_array); } static void expand_regex(char ***substr) { /* Let's store all strings currently in substr plus REGEX expanded * files, if any, in a temporary array. */ char **tmp = xnmalloc((size_t)files + args_n + 2, sizeof(char *)); filesn_t i, j; size_t n = 0; regex_t regex; /* int reg_flags = conf.case_sens_list == 1 ? (REG_NOSUB | REG_EXTENDED) : (REG_NOSUB | REG_EXTENDED | REG_ICASE); */ const int reg_flags = (REG_NOSUB | REG_EXTENDED); for (i = 0; (*substr)[i]; i++) { if (n > ((size_t)files + args_n)) break; /* Ignore the first string of the search function: it will be * expanded by the search function itself. * Also, ignore quoted words and existent filenames. */ struct stat a; if (*(*substr)[0] == '/' || is_quoted_word((size_t)i) || lstat((*substr)[i], &a) != -1) { tmp[n] = (*substr)[i]; n++; continue; } /* At this point, all filenames are escaped. But check_regex() * needs unescaped filenames. So, let's deescape it. */ char *p = strchr((*substr)[i], '\\'); char *dstr = (char *)NULL; if (p) dstr = unescape_str((*substr)[i], 0); char *t = dstr ? dstr : (*substr)[i]; /* Prepend an initial '^' and append and ending '$' to prevent * accidental file expansions. For example, a file named file.txt * must not be expanded given the pattern "ile.t". In other words, * we force the use of ".*PATTERN.*" instead of just "PATTERN". */ const size_t l = strlen(t) + 3; char *rstr = xnmalloc(l, sizeof(char)); snprintf(rstr, l, "^%s$", t); free(dstr); const int ret = check_regex(rstr); if (ret != FUNC_SUCCESS || regcomp(®ex, rstr, reg_flags) != FUNC_SUCCESS) { if (ret == FUNC_SUCCESS) regfree(®ex); free(rstr); tmp[n] = (*substr)[i]; n++; continue; } free(rstr); int reg_found = 0; for (j = 0; j < files; j++) { if (regexec(®ex, file_info[j].name, 0, NULL, 0) != FUNC_SUCCESS) continue; /* Make sure the matching filename is not already in the tmp array */ filesn_t m = (filesn_t)n, found = 0; while (--m >= 0) { if (*file_info[j].name == *tmp[m] && strcmp(file_info[j].name, tmp[m]) == 0) found = 1; } if (found == 1) continue; tmp[n] = file_info[j].name; n++; reg_found = 1; } if (reg_found == 0) { tmp[n] = (*substr)[i]; n++; } regfree(®ex); } if (n > 0) { tmp[n] = (char *)NULL; char **tmp_files = xnmalloc(n + 2, sizeof(char *)); size_t k = 0; for (j = 0; tmp[j]; j++) { struct stat a; if (virtual_dir == 1 && lstat(tmp[j], &a) == 0 && S_ISLNK(a.st_mode) && is_file_in_cwd(tmp[j])) { char buf[PATH_MAX]; *buf = '\0'; const ssize_t buf_len = xreadlink(XAT_FDCWD, tmp[j], buf, sizeof(buf)); if (buf_len == -1 || !*buf) continue; tmp_files[k] = savestring(buf, (size_t)buf_len); } else { tmp_files[k] = savestring(tmp[j], strlen(tmp[j])); } k++; } tmp_files[k] = (char *)NULL; for (j = 0; (*substr)[j]; j++) free((*substr)[j]); free((*substr)); (*substr) = tmp_files; args_n = (k > 0 ? k - 1 : k); } free(tmp); } static int expand_symlink(char **substr) { struct stat a; char *name = strchr(*substr, '\\') ? unescape_str(*substr, 0) : *substr; if (!name) return 0; const size_t l = strlen(name); if (l > 0 && name[l - 1] == '/') name[l - 1] = '\0'; const int ret = lstat(name, &a); const int link_ok = (ret != -1 && S_ISLNK(a.st_mode)); if (link_ok == 0) { if (name != *substr) free(name); return 0; } char target[PATH_MAX + 1]; *target = '\0'; if (xreadlink(XAT_FDCWD, name, target, sizeof(target)) == -1) { xerror("realpath: '%s': %s\n", name, strerror(errno)); if (name != *substr) free(name); return (-1); } if (name != *substr) free(name); char *estr = escape_str(target); name = estr ? estr : target; const size_t rp_len = strlen(name); *substr = xnrealloc(*substr, rp_len + 1, sizeof(char)); xstrsncpy(*substr, name, rp_len + 1); free(estr); return 0; } /* Return 1 if glob expansion should be performed for the current command, * or 0 otherwise. */ static int glob_expand(char **cmd) { if (!cmd || !cmd[0] || !*cmd[0]) return 0; /* In case of 'desel', allow glob expansion only if the first parameter * is not "*", in which case the deselect function itself takes care of * deselecting all files. */ if (sel_n > 0 && cmd[1] && *cmd[1] && (strcmp(cmd[0], "ds") == 0 || strcmp(cmd[0], "desel") == 0)) { if (*cmd[1] == '*' && !cmd[1][1]) return 0; return (check_glob_char(cmd[1], GLOB_REGEX)); } /* Do not expand if command is sel or untrash, just to allow the use * of "*" for desel and untrash ("ds *" and "u *"), and to let the * sel function handle glob patterns itself. */ if (strcmp(cmd[0], "s") != 0 && strcmp(cmd[0], "sel") != 0 && strcmp(cmd[0], "u") != 0 && strcmp(cmd[0], "undel") != 0 && strcmp(cmd[0], "untrash") != 0 && !( *cmd[0] == 't' && (!cmd[0][1] || strcmp(cmd[0], "tr") == 0 || strcmp(cmd[0], "trash") == 0) && cmd[1] && *cmd[1] == 'd' && strcmp(cmd[1], "del") == 0 ) ) return 1; return 0; } /* Return 1 if CMD should be regex expanded, or 0 otherwise. */ static int regex_expand(const char *cmd) { if (!cmd || !*cmd) return 0; if (strcmp(cmd, "ds") == 0 || strcmp(cmd, "desel") == 0 || strcmp(cmd, "u") == 0 || strcmp(cmd, "undel") == 0 || strcmp(cmd, "untrash") == 0 || strcmp(cmd, "s") == 0 || strcmp(cmd, "sel") == 0) return 0; return 1; } static char ** gen_full_line(char **str, const int fusedcmd_ok) { /* Remove leading spaces */ char *p = *str; while (*p == ' ' || *p == '\t') p++; args_n = 0; char **cmd = xnmalloc(2, sizeof(char *)); cmd[0] = savestring(p, strlen(p)); cmd[1] = (char *)NULL; if (fusedcmd_ok == 1) free(*str); /* If ";cmd" or ":cmd" the whole input line will be send to * exec_cmd() and will be executed by the system shell via * execl(). Since we don't run split_str() here, dequoting * and unescaping is performed directly by the system shell. */ return cmd; } static int check_int_var(char *str) { /* Remove leading spaces. This: ' a="test"' should be * taken as a valid variable declaration */ char *p = str; while (*p == ' ' || *p == '\t') p++; /* If first non-space is a number, it's not a variable name */ if (IS_DIGIT(*p)) return 0; int space_found = 0; /* If there are no spaces before '=', take it as a * variable. This check is done in order to avoid * taking as a variable things "ls --color=auto" */ while (*p != '=') { if (*(p++) == ' ') space_found = 1; } if (space_found == 0) return 1; return 0; } static int check_chained_cmds(char *str) { /* If the user wants to create a file containing either '|' or ';' in the * name, they should be allowed. The filename will be later validated by * the 'new' function itself. */ if (str && (strncmp(str, "n ", 2) == 0 || strncmp(str, "new ", 4) == 0)) return 0; /* User defined variables are always internal, so that there is * no need to check whatever else is in the command string */ if (flags & IS_USRVAR_DEF) { exec_chained_cmds(str); return 1; } size_t i = 0; const size_t str_len = strlen(str); size_t len = 0, internal_ok = 0; char *buf = (char *)NULL; /* Get each word (cmd) in STR */ buf = xnmalloc(str_len + 1, sizeof(char)); for (i = 0; i < str_len; i++) { while (str[i] && str[i] != ' ' && str[i] != ';' && str[i] != '&') { buf[len] = str[i]; len++; i++; } buf[len] = '\0'; if (strcmp(buf, "&&") != 0) { if (is_internal_cmd(buf, ALL_CMDS, 1, 1)) { internal_ok = 1; break; } } memset(buf, '\0', len); len = 0; } free(buf); if (internal_ok == 1) { exec_chained_cmds(str); return 1; } return 0; } /* * This function is one of the keys of clifm. It will perform a series of * actions: * 1) Take the string stored by readline and get its substrings without * leading and trailing spaces (dequoting/unescaping if necessary). * 2) In case of user defined variables (var=value), it will pass the * whole string to exec_cmd(), which will take care of storing the * variable; * 3) If the input string begins with ';' or ':' the whole string is * sent to exec_cmd(), where it will be directly executed by the system * shell. * 4) The following expansions (especific to clifm) are performed here: * ELN's, "sel" keyword, ranges of numbers (ELN's), tags, pinned dir, * bookmark names, environment variables, file types (=x), mime types (@...), * path normalization, fastback, and, for internal commands only, tilde, * braces, wildcards, command and paramenter substitution, and regex. */ char ** parse_input_str(char *str) { if (!str) return (char **)NULL; size_t i = 0; int fusedcmd_ok = 0; flags &= ~FIRST_WORD_IS_ELN; flags &= ~IS_USRVAR_DEF; /* If internal command plus fused parameter, split it. */ if (is_fused_param(str) == FUNC_SUCCESS) { char *p = split_fused_param(str); if (p) { fusedcmd_ok = 1; str = p; } } /* ######################################## * # 0) CHECK FOR SPECIAL FUNCTIONS # * ########################################*/ int chaining = 0, cond_cmd = 0, send_shell = 0; /* ########################### * # 0.1) RUN AS EXTERNAL # * ###########################*/ /* If invoking a command via ';' or ':', set the send_shell flag to * true and send the whole string to exec_cmd(), in which case no * expansion is made: the command is send to the system shell as is. */ if (*str == ';' || *str == ':' || check_shell_functions(str) == 1) send_shell = 1; if (send_shell == 0) { for (i = 0; str[i]; i++) { /* ################################## * # 0.2) CONDITIONAL EXECUTION # * ##################################*/ /* Check for chained commands (cmd1;cmd2). */ if (chaining == 0 && str[i] == ';' && i > 0 && str[i - 1] != '\\') chaining = 1; /* Check for conditional execution (cmd1 && cmd 2). */ if (cond_cmd == 0 && str[i] == '&' && i > 0 && str[i - 1] != '\\' && str[i + 1] == '&') cond_cmd = 1; /* ################################## * # 0.3) USER DEFINED VARIABLE # * ##################################*/ /* If user defined variable, send the whole string to * exec_cmd(), which will take care of storing the variable. */ if (!(flags & IS_USRVAR_DEF) && conf.int_vars == 1 && str[i] == '=' && i > 0 && str[i - 1] != '\\' && str[0] != '=' && check_int_var(str) == 1) flags |= IS_USRVAR_DEF; } } /* If chained commands, check each of them. If at least one of them * is internal, take care of the job (the system shell does not know * our internal commands and therefore cannot execute them); else, * if no internal command is found, leave it to the system shell. */ if ((chaining == 1 || cond_cmd == 1) && check_chained_cmds(str) == 1) { if (fusedcmd_ok == 1) free(str); return (char **)NULL; } if ((flags & IS_USRVAR_DEF) || send_shell == 1) return gen_full_line(&str, fusedcmd_ok); /* ################################################ * # 1) SPLIT INPUT STRING INTO SUBSTRINGS # * ################################################ */ /* split_str() returns an array of strings without leading, * terminating and double spaces. */ char **substr = split_str(str, UPDATE_ARGS); if (fusedcmd_ok == 1) /* Just in case split_fusedcmd returned NULL. */ free(str); if (!substr) return (char **)NULL; /* Do not perform expansions for the 'n/new' command. */ if (*substr[0] == 'n' && (!substr[0][1] || strcmp(substr[0], "new") == 0)) return substr; /* Handle background/foreground process. */ bg_proc = 0; if (args_n > 0 && *substr[args_n] == '&' && !*(substr[args_n] + 1)) { bg_proc = 1; free(substr[args_n]); substr[args_n] = (char *)NULL; args_n--; } else { const size_t len = strlen(substr[args_n]); if (len > 0 && substr[args_n][len - 1] == '&' && !substr[args_n][len]) { substr[args_n][len - 1] = '\0'; bg_proc = 1; } } /* ###################### * # TRASH AS RM # * ###################### */ #ifndef _NO_TRASH if (conf.tr_as_rm == 1 && substr[0] && *substr[0] == 'r' && !substr[0][1]) *substr[0] = 't'; #endif /* !_NO_TRASH*/ /* ############################## * # 2) BUILTIN EXPANSIONS # * ############################## * Ranges, sel, ELN, pinned dirs, bookmarks, and internal variables. * These expansions are specific to clifm. To be able to use them * even with external commands, they must be expanded here, before * sending the input string (in case the command is external) to * the system shell. */ is_sel = 0; sel_is_last = 0; const int stdin_dir_ok = (stdin_tmp_dir && strcmp(workspaces[cur_ws].path, stdin_tmp_dir) == 0); const int is_int_cmd = is_internal_cmd(substr[0], PARAM_FNAME, 0, 1); /* Let's expand ranges first: the numbers resulting from the expanded range * will be expanded into the corresponding filenames by eln_expand() below. */ expand_ranges(&substr); for (i = 0; i <= args_n; i++) { if (!substr[i] || (is_quoted_word(i) && (virtual_dir == 0 || is_file_in_cwd(substr[i]) == 0))) continue; /* The following expansions expand to a SINGLE field. */ /* ################################### * # 2.1) USER DEFINED VARIABLES # * ###################################*/ if (conf.int_vars == 1 && usrvar_n > 0 && substr[i][0] == '$' && substr[i][1] && substr[i][1] != '(' && substr[i][1] != '{') expand_int_var(&substr[i]); /* ########################## * # 2.2) ELN EXPANSION # * ########################## */ /* should_expand_eln() will check rl_line_buffer looking for the * command name. Now, if the command name has a fused ELN plus space * and at least a second parameter (E.g.: CMD1 2), should_expand_eln() * will fail. Let's redirect rl_line_buffer to the buffered command * name (CMD) so that the check will be properly performed. */ char *lb_tmp = rl_line_buffer; if (rl_dispatching == 0 && fusedcmd_ok == 1) rl_line_buffer = substr[0]; if (should_expand_eln(substr[i], substr[0]) == 1) eln_expand(&substr, i); rl_line_buffer = lb_tmp; /* ################################ * # 2.3) ENVIRONEMNT VARIABLES # * ###############################*/ if (*substr[i] == '$') { char *p = xgetenv(substr[i] + 1, 1); if (p) { free(substr[i]); substr[i] = p; } } /* ################################ * # 2.4) TILDE: ~user and home # * ################################ */ if (*substr[i] == '~') { char *p = tilde_expand(substr[i]); if (p) { free(substr[i]); substr[i] = p; } } /* ################################## * # 2.5) URI file scheme # * ################################## */ /* file:///some/file -> /some/file */ size_t slen = strlen(substr[i]); if (IS_FILE_URI(substr[i], slen)) { char *ptr = url_decode(substr[i] + FILE_URI_PREFIX_LEN); if (ptr && *ptr) xstrsncpy(substr[i], ptr, slen + 1); free(ptr); } /* ############################### * # 2.6) "." and ".." # * ############################### */ if ((*substr[i] == '.' && (!substr[i][1] || (substr[i][1] == '.' && (!substr[i][2] || substr[i][2] == '/')))) || strstr(substr[i], "/..")) { char *tmp = (is_int_cmd == 1 && (*substr[0] != 'l' || substr[0][1])) /* Exclude 'l' command. */ ? normalize_path(substr[i], strlen(substr[i])) : NULL; if (tmp) { free(substr[i]); substr[i] = tmp; } } /* ###################################### * # 2.7) FASTBACK EXPANSION # * ###################################### */ if (*substr[i] == '.' && substr[i][1] == '.' && substr[i][2] == '.') { char *tmp = fastback(substr[i]); if (tmp) { free(substr[i]); substr[i] = tmp; } } /* ###################################### * # 2.8) PINNED DIR EXPANSION # * ###################################### */ if (*substr[i] == ',' && !substr[i][1] && pinned_dir) { const size_t plen = strlen(pinned_dir); substr[i] = xnrealloc(substr[i], plen + 1, sizeof(char)); xstrsncpy(substr[i], pinned_dir, plen + 1); } /* ###################################### * # 2.9) BOOKMARK NAMES EXPANSION # * ###################################### */ /* Expand bookmark name (b:NAME) into the corresponding path. */ if (*substr[i] == 'b' && substr[i][1] == ':' && substr[i][2] && expand_bm_name(&substr[i]) == FUNC_SUCCESS) continue; /* ###################################### * # 2.10) WORKSPACE EXPANSION # * ###################################### */ if (*substr[i] == 'w' && substr[i][1] == ':' && substr[i][2] && expand_workspace(&substr[i]) == FUNC_SUCCESS) continue; /* ################################### * # 2.11) SYMLINKS IN VIRTUAL DIR # * ################################### */ /* We are in STDIN_TMP_DIR: Expand symlinks to target. */ if (stdin_dir_ok == 1 && expand_symlink(&substr[i]) == -1) { for (i = 0; i <= args_n; i++) free(substr[i]); free(substr); return (char **)NULL; } } /* The following expansions expand to MULTIPLE fields. */ /* ########################### * # 2.12) SEL EXPANSION # * ########################### */ expand_sel_keyword(&substr); /* ################################# * # 2.13) TAGS EXPANSION # * ################################# */ #ifndef _NO_TAGS expand_tags(&substr); #endif /* _NO_TAGS */ /* ################################ * # 2.14) FILE TYPE (=CHAR) # * ################################ */ expand_file_type(&substr); /* ################################## * # 2.15) MIME TYPE (@PATTERN) # * ################################## */ #ifndef _NO_MAGIC expand_mime_type(&substr); #endif /* !_NO_MAGIC */ /* ############################### * # 2.16) BOOKMARKS (b:) # * ############################### */ expand_bookmarks(&substr); /* #### NULL TERMINATE THE INPUT STRING ARRAY #### */ substr = xnrealloc(substr, args_n + 2, sizeof(char *)); substr[args_n + 1] = (char *)NULL; const int is_action = is_action_name(substr[0]); if (is_int_cmd == 0 && is_action == 0) return substr; /* #################################################### * # 3) SHELL-LIKE EXPANSIONS # * # Only for internal commands and plugins # * #################################################### */ /* Most clifm functions are purely internal, that is, they are not * wrappers of a shell command and do not call the system shell at all. * For this reason, some expansions normally made by the system shell * (wildcards, regular expressions, and command substitution) must be * made here (in the lobby [got it?]) in order to be able to understand * these expansions at all. */ /* Let's first mark substrings containing special expansions made by either * glob(3) and wordexp(3). */ int *glob_array = xnmalloc(INT_ARRAY_MAX, sizeof(int)); size_t glob_n = 0; #ifdef HAVE_WORDEXP int *word_array = xnmalloc(INT_ARRAY_MAX, sizeof(int)); size_t word_n = 0; #endif /* HAVE_WORDEXP */ for (i = 0; substr[i]; i++) { if ((is_action == 1 && i == 0) || is_quoted_word(i)) continue; /* Do not perform any of the expansions below for selected * elements: they are full path filenames that, as such, do not * need any expansion. */ if (is_sel > 0) { /* is_sel is true only for the current input and if there was some "sel" keyword in it. */ /* Strings between is_sel and sel_n are selected filenames. * Skip them. */ if (i >= (size_t)is_sel && i <= sel_n) continue; } /* Ignore the first word of the search function: it will be * expanded by the search function itself. */ if (substr[0][0] == '/' && i == 0) continue; /* Ignore existent filenames as well. */ struct stat a; if (lstat(substr[i], &a) != -1) continue; #ifdef HAVE_WORDEXP /* Let's make wordexp(3) ignore escaped words. */ const int is_escaped = strchr(substr[i], '\\') ? 1 : 0; #endif /* HAVE_WORDEXP */ size_t j = 0; for (j = 0; substr[i][j]; j++) { /* Brace and wildcard expansion is made by glob(3). */ if (IS_GLOB(substr[i][j], substr[i][j + 1])) { /* Strings containing these characters are taken as wildacard * patterns and are expanded by the glob function. See glob(7). */ if (glob_n < INT_ARRAY_MAX) { glob_array[glob_n] = (int)i; glob_n++; } } #ifdef HAVE_WORDEXP /* Command substitution, tilde, and environment variables * expansion is made by wordexp(3). */ if (is_escaped == 0 && IS_WORD(substr[i][j], substr[i][j + 1])) { /* Unlike glob() and tilde_expand(), wordexp() can expand tilde * and env vars even in the middle of a string. E.g.: * '$HOME/Downloads'. */ if (word_n < INT_ARRAY_MAX) { word_array[word_n] = (int)i; word_n++; } } #endif /* HAVE_WORDEXP */ } } /* ########################################## * # 3.1) WILDCARDS AND BRACE EXPANSION # * ########################################## */ if (glob_n > 0 && glob_expand(substr) == 1 && expand_glob(&substr, glob_array, glob_n) == -1) return (char **)NULL; free(glob_array); /* ############################################### * # 3.2) COMMAND & PARAMETER SUBSTITUTION # * ############################################### */ #ifdef HAVE_WORDEXP if (word_n > 0 && expand_word(&substr, word_array, word_n) == -1) return (char **)NULL; free(word_array); #endif /* HAVE_WORDEXP */ /* ####################################### * # 3.3) REGEX EXPANSION # * ####################################### */ if (regex_expand(substr[0]) == 1) expand_regex(&substr); /* #### NULL TERMINATE THE INPUT STRING ARRAY (again) #### */ substr = xnrealloc(substr, args_n + 2, sizeof(char *)); substr[args_n + 1] = (char *)NULL; return substr; } /* Reduce "$HOME" to tilde ("~"). * If NEW_PATH isn't in home, NEW_PATH is returned without allocating new * memory, in which case FREE_BUF is set to zero. * Otherwise, the reduced path is copied into malloc'ed memory. */ char * home_tilde(char *new_path, int *free_buf) { *free_buf = 0; if (home_ok == 0 || !new_path || !*new_path || !user.home) return (char *)NULL; /* If new_path == HOME */ if (new_path[1] && user.home[1] && new_path[1] == user.home[1] && strcmp(new_path, user.home) == 0) { char *path_tilde = xnmalloc(2, sizeof(char)); path_tilde[0] = '~'; path_tilde[1] = '\0'; *free_buf = 1; return path_tilde; } if (new_path[1] && user.home[1] && new_path[1] == user.home[1] && strncmp(new_path, user.home, user.home_len) == 0 /* Avoid names like these: "HOMEfile". It should always be rather "HOME/file" */ && (user.home[user.home_len - 1] == '/' || *(new_path + user.home_len) == '/') ) { /* If new_path == HOME/file */ const size_t len = strlen(new_path + user.home_len + 1) + 3; char *path_tilde = xnmalloc(len, sizeof(char)); snprintf(path_tilde, len, "~/%s", new_path + user.home_len + 1); *free_buf = 1; return path_tilde; } return new_path; } /* Returns a pointer to a copy of the string STR, malloc'ed with size SIZE, or * NULL on error. */ char * savestring(const char *restrict str, const size_t size) { if (!str) return (char *)NULL; char *ptr = malloc((size + 1) * sizeof(char)); if (!ptr) return (char *)NULL; const char *ret = memccpy(ptr, str, '\0', size + 1); if (!ret) ptr[size] = '\0'; return ptr; } /* Take a string and returns the same string escaped. * If there is nothing to be escaped, the original string is returned. In * either cases, the returned string must be free'd by the caller. */ char * escape_str(const char *str) { if (!str) return (char *)NULL; size_t len = 0; char *buf = (char *)NULL; buf = xnmalloc(strlen(str) * 2 + 1, sizeof(char)); while (*str) { if (is_quote_char(*str)) { buf[len] = '\\'; len++; } buf[len] = *str; len++; str++; } buf[len] = '\0'; return buf; } /* Get all substrings in STR using IFS as substring separator. * If FPROC is set to 1, some further processing is performed: ranges * are expanded and duplicates removed. * Returns an array containing all substrings in STR. */ char ** get_substr(char *str, const char ifs, const int fproc) { if (!str || !*str) return (char **)NULL; /* a. SPLIT THE STRING */ char **substr = (char **)NULL; size_t len = 0; size_t substr_n = 0; const size_t str_len = strlen(str); char *buf = xnmalloc(str_len + 1, sizeof(char)); while (*str) { while (*str != ifs && *str != '\0' && len < (str_len + 1)) { buf[len] = *str; len++; str++; } if (len > 0) { buf[len] = '\0'; substr = xnrealloc(substr, substr_n + 2, sizeof(char *)); substr[substr_n] = savestring(buf, len); substr_n++; len = 0; } else { str++; } } free(buf); if (substr_n == 0) return (char **)NULL; substr[substr_n] = (char *)NULL; if (fproc == 0) return substr; /* b. EXPAND RANGES */ const size_t argsbk = args_n; args_n = substr_n; expand_ranges(&substr); args_n = argsbk; /* c. REMOVE DUPLICATES */ for (substr_n = 0; substr[substr_n]; substr_n++); if (substr_n == 0) { free(substr); return (char **)NULL; } char **dstr = (char **)NULL; size_t i, j; size_t n = 0; for (i = 0; i < substr_n; i++) { int dup = 0; for (j = (i + 1); j < substr_n; j++) { if (*substr[i] == *substr[j] && strcmp(substr[i], substr[j]) == 0) { dup = 1; break; } } if (dup == 0) { dstr = xnrealloc(dstr, n + 2, sizeof(char *)); dstr[n] = savestring(substr[i], strlen(substr[i])); n++; } free(substr[i]); } free(substr); dstr[n] = (char *)NULL; return dstr; } /* This function simply unescapes whatever escaped chars it founds in * TEXT. Returns a string containing TEXT without escape sequences. */ char * unescape_str(char *text, int mt) { UNUSED(mt); if (!text || !*text) return (char *)NULL; /* At most, we need as many bytes as in TEXT (in case no escape * sequence is found). */ char *buf = xnmalloc(strlen(text) + 1, sizeof(char)); size_t len = 0; while (*text) { if (*text == '\\') { ++text; buf[len] = *text; len++; } else { buf[len] = *text; len++; } if (!*text) break; text++; } buf[len] = '\0'; return buf; } clifm-1.26.3/src/strings.h000066400000000000000000000047251506632037700153470ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* strings.h */ #ifndef STRINGS_H #define STRINGS_H /* Macros for the split_str function */ #define UPDATE_ARGS 1 #define NO_UPDATE_ARGS 0 __BEGIN_DECLS int detect_space(char *s); size_t count_chars(const char *s, const char c); size_t count_words(size_t *start_word, size_t *full_word); char *escape_str(const char *str); char *gen_rand_str(const size_t len); char *get_last_chr(char *str, const char c, const int len); char **get_substr(char *str, const char ifs, const int fproc); char *home_tilde(char *new_path, int *free_buf); char **parse_input_str(char *str); char *quote_str(const char *str); char *remove_quotes(char *str); char *replace_invalid_chars(const char *name); char *replace_slashes(char *str, const char c); char *replace_substr(const char *haystack, const char *needle, char *rep); char *savestring(const char *restrict str, const size_t size); char **split_str(char *str, const int update_args); char *strbfrlst(char *str, const char c); char *strbtw(char *str, const char a, const char b); int strcntchr(const char *str, const char c); int u8truncstr(char *restrict str, size_t max); char *unescape_str(char *text, int mt); size_t wc_xstrlen(const char *restrict str); char *xstrrpbrk(char *s, const char *accept); #if defined(_BE_POSIX) char *x_strcasestr(char *a, char *b); #endif /* _BE_POSIX */ char * xstrcasechr(char *s, char c); size_t xstrsncpy(char *restrict dst, const char *restrict src, size_t n); char * xstrncat(char *restrict dst, const size_t dst_len, const char *restrict src, const size_t dst_size); int xstrverscmp(const char *s1, const char *s2); __END_DECLS #endif /* STRINGS_H */ clifm-1.26.3/src/suggestions.c000066400000000000000000001747511506632037700162320ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* suggestions.c -- functions to manage the suggestions system */ #ifndef _NO_SUGGESTIONS #include "helpers.h" #include #include /* str(n)casecmp() */ #include #include #if defined(__linux__) # include #endif /* __linux__ */ #if defined(__OpenBSD__) typedef char *rl_cpvfunc_t; # include #else # include #endif /* __OpenBSD__ */ #include "aux.h" #include "builtins.h" #include "checks.h" #include "colors.h" #include "fuzzy_match.h" #ifndef _NO_HIGHLIGHT # include "highlight.h" #endif /* !_NO_HIGHLIGHT */ #include "jump.h" #include "messages.h" #include "navigation.h" /* fastback() */ #include "prompt.h" #include "readline.h" #define NO_MATCH 0 #define PARTIAL_MATCH 1 #define FULL_MATCH 2 #define CHECK_MATCH 0 #define PRINT_MATCH 1 #define BAEJ_OFFSET 1 #define IS_BAEJ_SUG(t) ((t) == BOOKMARK_SUG || (t) == ALIAS_SUG \ || (t) == ELN_SUG || (t) == JCMD_SUG || (t) == BACKDIR_SUG \ || (t) == SORT_SUG || (t) == WS_NUM_SUG \ || (t) == FUZZY_FILENAME || (t) == DIRHIST_SUG \ || (t) == FASTBACK_SUG || (t) == WS_NUM_PREFIX_SUG \ || ((t) == COMP_SUG && (flags & BAEJ_SUGGESTION))) static char *last_word = (char *)NULL; static int last_word_offset = 0; static int point_is_first_word = 0; /* A buffer big enough to hold temporary data. */ static char tmp_buf[PATH_MAX + 2]; /* #ifndef _NO_HIGHLIGHT // Change the color of the word _LAST_WORD, at offset OFFSET, to COLOR // in the current input string static void change_word_color(const char *_last_word, const int offset, const char *color) { int bk = rl_point; fputs("\x1b[?25l", stdout); rl_delete_text(offset, rl_end); rl_point = rl_end = offset; rl_redisplay(); fputs(color, stdout); rl_insert_text(_last_word); rl_point = bk; fputs("\x1b[?25h", stdout); } #endif // !_NO_HIGHLIGHT */ /* Return a brief description for the command S, whose length is L. */ static char * check_int_cmd_desc(const char *s, const size_t l) { if (!s || !*s) return (char *)NULL; if (l == 1) { switch (*s) { case 'b': return B_DESC; case 'c': return C_DESC; case 'd': return D_DESC; case 'f': return F_DESC; case 'j': return J_DESC; case 'k': return K_DESC; case 'l': return L_DESC; case 'm': return M_DESC; case 'n': return N_DESC; case 'o': return O_DESC; case 'p': return P_DESC; case 'q': return Q_DESC; case 'r': return R_DESC; case 's': return SEL_DESC; case 't': return TRASH_DESC; case 'u': return U_DESC; case 'x': return X_DESC; case 'X': return XU_DESC; default: return (char *)NULL; } } else if (l == 2) { if (*s == 'a') { if (s[1] == 'c') return AC_DESC; if (s[1] == 'd') return AD_DESC; if (s[1] == 'o') return AO_DESC; } else if (*s == 'b') { if (s[1] == 'b') return BB_DESC; if (s[1] == 'd') return BD_DESC; if (s[1] == 'l') return BL_DESC; if (s[1] == 'm') return BM_DESC; if (s[1] == 'r') return BR_DESC; } else if (*s == 'c') { if (s[1] == 'd') return CD_DESC; if (s[1] == 'l') return CL_DESC; if (s[1] == 's') return CS_DESC; } else if (*s == 'd') { if (s[1] == 's') return DS_DESC; if (s[1] == 'h') return DH_DESC; } else if (*s == 'f') { if (s[1] == 'c') return FC_DESC; if (s[1] == 'f') return FF_DESC; if (s[1] == 't') return FT_DESC; if (s[1] == 'z') return FZ_DESC; } else if (*s == 'h' && (s[1] == 'f' || s[1] == 'h')) return HF_DESC; else if (*s == 'k') { if (s[1] == 'b') return KB_DESC; if (s[1] == 'k') return KK_DESC; } else if (*s == 'l') { if (s[1] == 'e') return LE_DESC; if (s[1] == 'l' || s[1] == 'v') return LL_DESC; if (s[1] == 'm') return LM_DESC; } else if (*s == 'm') { if (s[1] == 'd') return MD_DESC; if (s[1] == 'f') return MF_DESC; if (s[1] == 'm') return MM_DESC; if (s[1] == 'p') return MP_DESC; } else if (*s == 'o') { if (s[1] == 'c') return OC_DESC; if (s[1] == 'w') return OW_DESC; } else if (*s == 'p') { if (s[1] == 'c') return PC_DESC; if (s[1] == 'f') return PF_DESC; if (s[1] == 'g') return PG_DESC; if (s[1] == 'p') return PP_DESC; } else if (*s == 'r') { if (s[1] == 'f') return RF_DESC; if (s[1] == 'l') return RL_DESC; if (s[1] == 'r') return RR_DESC; } else if (*s == 's') { if (s[1] == 'b') return SB_DESC; if (s[1] == 't') return ST_DESC; } else if (*s == 't') { if (s[1] == 'a') return TA_DESC; if (s[1] == 'd') return TD_DESC; if (s[1] == 'e') return TE_DESC; if (s[1] == 'l') return TL_DESC; if (s[1] == 'm') return TM_DESC; if (s[1] == 'n') return TN_DESC; if (s[1] == 'u') return TU_DESC; if (s[1] == 'y') return TY_DESC; } else if (*s == 'v' && s[1] == 'v') return VV_DESC; else if (*s == 'w') { if (s[1] == 's') return WS_DESC; } } else if (l == 3) { if (*s == 'a' && s[1] == 'c' && s[2] == 'd') return ACD_DESC; if (*s == 'c' && s[1] == 'm' && s[2] == 'd') return CMD_DESC; if (*s == 'd' && s[1] == 'u' && s[2] == 'p') return D_DESC; if (*s == 'e' && s[1] == 'x') { if (s[2] == 'p') return EXP_DESC; if (s[2] == 't') return EXT_DESC; } if (*s == 'l' && s[1] == 'o' && s[2] == 'g') return LOG_DESC; if (*s == 'm' && s[1] == 's' && s[2] == 'g') return MSG_DESC; if (*s == 'n' && s[1] == 'e') { if (s[2] == 't') return NET_DESC; if (s[2] == 'w') return N_DESC; } if (*s == 'p' && s[1] == 'i' && s[2] == 'n') return PIN_DESC; if (*s == 's' && s[1] == 'e' && s[2] == 'l') return SEL_DESC; if (*s == 't' && s[1] == 'a' && s[2] == 'g') return TAG_DESC; if (*s == 'v' && s[1] == 'e' && s[2] == 'r') return VER_DESC; } else if (l == 4) { if (*s == 'a' && strcmp(s + 1, "uto") == 0) return AUTO_DESC; if (*s == 'b' && strcmp(s + 1, "ack") == 0) return B_DESC; if (*s == 'b' && strcmp(s + 1, "ulk") == 0) return BR_DESC; if (*s == 'm' && strcmp(s + 1, "ime") == 0) return MM_DESC; if (*s == 'o' && strcmp(s + 1, "pen") == 0) return O_DESC; if (*s == 'p' && strcmp(s + 1, "rop") == 0) return P_DESC; if (*s == 's' && strcmp(s + 1, "ort") == 0) return ST_DESC; if (*s == 't' && strcmp(s + 1, "ips") == 0) return TIPS_DESC; if (*s == 'v' && strcmp(s + 1, "iew") == 0) return VIEW_DESC; } else if (l == 5) { if (*s == 'a' && strcmp(s + 1, "lias") == 0) return ALIAS_DESC; if (*s == 'd' && strcmp(s + 1, "esel") == 0) return DS_DESC; if (*s == 'f' && strcmp(s + 1, "orth") == 0) return F_DESC; if (*s == 'i' && strcmp(s + 1, "cons") == 0) return ICONS_DESC; if (*s == 'm' && strcmp(s + 1, "edia") == 0) return MEDIA_DESC; if (*s == 'p' && strcmp(s + 1, "ager") == 0) return PG_DESC; if (*s == 's' && strcmp(s + 1, "tats") == 0) return STATS_DESC; if (*s == 't' && strcmp(s + 1, "rash") == 0) return TRASH_DESC; if (*s == 'u' && strcmp(s + 1, "ndel") == 0) return U_DESC; if (*s == 'u' && strcmp(s + 1, "npin") == 0) return UNPIN_DESC; } else if (l == 6) { if (*s == 'a' && strcmp(s + 1, "utocd") == 0) return ACD_DESC; if (*s == 'b' && strcmp(s + 1, "leach") == 0) return BB_DESC; if (*s == 'c' && strcmp(s + 1, "olors") == 0) return COLORS_DESC; if (*s == 'c' && strcmp(s + 1, "onfig") == 0) return CONFIG_DESC; if (*s == 'f' && strcmp(s + 1, "ilter") == 0) return FT_DESC; if (*s == 'h' && strcmp(s + 1, "idden") == 0) return HF_DESC; if (*s == 'o' && strcmp(s + 1, "pener") == 0) return OPENER_DESC; if (*s == 'p' && strcmp(s + 1, "rompt") == 0) return PROMPT_DESC; if (*s == 'r' && strcmp(s + 1, "eload") == 0) return RL_DESC; if (*s == 's' && strcmp(s + 1, "elbox") == 0) return SB_DESC; } else if (l == 7) { if (*s == 'a' && strcmp(s + 1, "ctions") == 0) return ACTIONS_DESC; if (*s == 'c' && strcmp(s + 1, "olumns") == 0) return CL_DESC; if (*s == 'h' && strcmp(s + 1, "istory") == 0) return HIST_DESC; if (*s == 'p' && strcmp(s + 1, "rofile") == 0) return PF_DESC; if (*s == 'r' && strcmp(s + 1, "efresh") == 0) return RF_DESC; if (*s == 'u' && strcmp(s + 1, "ntrash") == 0) return U_DESC; if (*s == 'v' && strcmp(s + 1, "ersion") == 0) return VER_DESC; } else if (l == 8) { if (*s == 'c' && strcmp(s + 1, "ommands") == 0) return CMD_DESC; if (*s == 'k' && strcmp(s + 1, "eybinds") == 0) return KB_DESC; if (*s == 'm' && strcmp(s + 1, "essages") == 0) return MSG_DESC; } else if (l == 9) { if (*s == 'a' && strcmp(s + 1, "uto-open") == 0) return AO_DESC; if (*s == 'b' && strcmp(s + 1, "ookmarks") == 0) return BM_DESC; } else if (l == 10 && *s == 'd' && strcmp(s + 1, "irs-first") == 0) return FF_DESC; else if (l == 11 && *s == 'm' && strcmp(s + 1, "ountpoints") == 0) return MP_DESC; else if (l == 12 && *s == 'c' && strcmp(s + 1, "olorschemes") == 0) return CS_DESC; return (char *)NULL; } int recover_from_wrong_cmd(void) { /* Check rl_dispathing to know whether we are called from a keybind, * in which case we should skip this check. */ if (rl_line_buffer && (rl_dispatching == 0 || (words_num > 1 && point_is_first_word == 0))) { const char *p = (strrchr(rl_line_buffer, ' ')); if (p && p != rl_line_buffer && *(p - 1) != '\\' && p[1] != ' ') return FUNC_FAILURE; } fputs(NC, stdout); cur_color = (char *)NULL; rl_restore_prompt(); rl_clear_message(); #ifndef _NO_HIGHLIGHT if (conf.highlight == 1) { const int p = rl_point; rl_point = 0; recolorize_line(); rl_point = p; } #endif /* !_NO_HIGHLIGHT */ wrong_cmd = 0; return FUNC_SUCCESS; } /* This function is only used before running a keybind command. We don't * want the suggestion buffer after running a keybind. */ void free_suggestion(void) { free(suggestion_buf); suggestion_buf = (char *)NULL; suggestion.printed = 0; suggestion.nlines = 0; } void clear_suggestion(const int sflag) { if (rl_end > rl_point) { MOVE_CURSOR_RIGHT(rl_end - rl_point); fflush(stdout); } ERASE_TO_RIGHT_AND_BELOW; if (rl_end > rl_point) { MOVE_CURSOR_LEFT(rl_end - rl_point); fflush(stdout); } suggestion.printed = 0; if (sflag == CS_FREEBUF) { free(suggestion_buf); suggestion_buf = (char *)NULL; } } static inline void restore_cursor_position(const size_t slines) { if (slines > 1) MOVE_CURSOR_UP((int)slines - 1); MOVE_CURSOR_LEFT(term_cols); if (conf.highlight == 0 && rl_point < rl_end) curcol -= (rl_end - rl_point); MOVE_CURSOR_RIGHT(curcol > 0 ? curcol - 1 : curcol); } static inline size_t calculate_suggestion_lines(int *baej, const size_t suggestion_len) { size_t cuc = (size_t)curcol; /* Current cursor column position. */ if (IS_BAEJ_SUG(suggestion.type)) { cuc += 3; /* 3 = 1 (one char forward) + 2 (" >") */ flags |= BAEJ_SUGGESTION; *baej = 1; } size_t cucs = cuc + suggestion_len; if (conf.highlight == 0 && rl_point < rl_end) cucs += (size_t)(rl_end - rl_point - 1); /* slines: number of lines we need to print the suggestion, including * the current line. */ size_t slines = 1; if (cucs > term_cols && term_cols > 0) { slines = cucs / (size_t)term_cols; const size_t cucs_rem = cucs % (size_t)term_cols; if (cucs_rem > 0) slines++; } return slines; } static inline char * truncate_name(const char *str) { char *wname = (char *)NULL; if (suggestion.type == ELN_SUG || suggestion.type == COMP_SUG || suggestion.type == FILE_SUG) { const size_t wlen = wc_xstrlen(str); if (wlen == 0) wname = replace_invalid_chars(str); } return wname; } static inline void set_cursor_position(const int baej) { /* If not at the end of the line, move the cursor there */ /* rl_end and rl_point are not updated: they do not include * the last typed char. However, since we only care here about * the difference between them, it doesn't matter: the result * is the same (7 - 4 == 6 - 3 == 3). */ if (rl_end > rl_point && conf.highlight == 0) { MOVE_CURSOR_RIGHT(rl_end - rl_point); fflush(stdout); } ERASE_TO_RIGHT; if (baej == 1) SUGGEST_BAEJ(BAEJ_OFFSET, sp_c); } static inline int check_conditions(const size_t offset, const size_t wlen, int *baej, size_t *slines) { if (offset > wlen) return FUNC_FAILURE; /* Do not print suggestions bigger than what the current terminal * window size can hold. If length is zero (invalid wide char), or if * it equals ARG_MAX, in which case we most probably have a truncated * suggestion (mbstowcs will convert only up to ARG_MAX chars), exit. */ const size_t suggestion_len = wlen - offset; if (suggestion_len == 0 || suggestion_len == (size_t)ARG_MAX || (int)suggestion_len > (term_cols * term_lines) - curcol) return FUNC_FAILURE; *slines = calculate_suggestion_lines(baej, suggestion_len - 1); if (*slines > (size_t)term_lines || (xargs.vt100 == 1 && *slines > 1)) return FUNC_FAILURE; return FUNC_SUCCESS; } static inline void make_suggestion(const char *str, const size_t offset, const char *color) { if (suggestion.type == FUZZY_FILENAME || (suggestion.type == COMP_SUG && (flags & BAEJ_SUGGESTION))) color = sz_c; char *wname = truncate_name(str); fputs(color, stdout); fputs((wname ? wname : str) + offset, stdout); fflush(stdout); free(wname); } /* Clear the line, print the suggestion (STR) at OFFSET in COLOR, and * move the cursor back to the original position. * OFFSET marks the point in STR that is already typed: the suggestion * will be printed starting from this point. */ void print_suggestion(const char *str, size_t offset, char *color) { if (!str || !*str) return; if (wrong_cmd == 1) { if (words_num > 1) return; recover_from_wrong_cmd(); } if (words_num == 1 && rl_end > 0 && rl_line_buffer && rl_line_buffer[rl_end - 1] == ' ' && (rl_end == 1 || rl_line_buffer[rl_end - 2] != '\\') && suggestion.type != HIST_SUG) { /* We have "cmd " (with one or more trailing spaces). */ suggestion.printed = 0; if (suggestion_buf) clear_suggestion(CS_FREEBUF); return; } HIDE_CURSOR; if (suggestion.printed && str != suggestion_buf) clear_suggestion(CS_FREEBUF); int baej = 0; /* Bookmark/backdir, alias, ELN, or jump (and fuzzy matches). */ flags &= ~BAEJ_SUGGESTION; /* Let's check for baej suggestions, mostly in case of fuzzy matches. */ const size_t wlen = last_word ? strlen(last_word) : 0; /* An alias name can be the same as the beginning of the alias definition, * so that this check must always be true in case of aliases. */ if (suggestion.type == ALIAS_SUG || (last_word && cur_comp_type == TCMP_PATH && (conf.case_sens_path_comp ? strncmp(last_word, str, wlen) : strncasecmp(last_word, str, wlen)) != 0) ) { flags |= BAEJ_SUGGESTION; baej = 1; offset = 0; } if (conf.highlight == 0) rl_redisplay(); curcol = prompt_offset + (rl_line_buffer ? (int)wc_xstrlen(rl_line_buffer) : 0); if (term_cols > 0) { while (curcol > term_cols) curcol -= term_cols; } const size_t str_len = wc_xstrlen(str); size_t slines = 0; if (check_conditions(offset, str_len, &baej, &slines) == FUNC_FAILURE) { UNHIDE_CURSOR; return; } else { if (baej == 1) { flags |= BAEJ_SUGGESTION; offset = 0; } } /* In some cases (accepting first suggested word), we might want to * reprint the suggestion buffer, in which case it would be already stored. */ if (str != suggestion_buf) { /* Store the suggestion (used later by rl_accept_suggestion (keybinds.c). */ free(suggestion_buf); suggestion_buf = savestring(str, strlen(str)); } set_cursor_position(baej); make_suggestion(str, offset, color); restore_cursor_position(slines); /* Store the number of lines taken by the current command line (plus the * suggestion's length) to be able to correctly remove it later (via the * clear_suggestion function). */ suggestion.nlines = slines; /* Store the suggestion color, in case we need to reprint it. */ suggestion.color = color; UNHIDE_CURSOR; } static inline char * get_reg_file_color(const char *filename, const struct stat *attr, int *free_color) { if (conf.light_mode == 1) return fi_c; if (*nf_c && access(filename, R_OK) == -1) return nf_c; if (attr->st_mode & S_ISUID) return su_c; if (attr->st_mode & S_ISGID) return sg_c; #ifdef LINUX_FILE_CAPS cap_t cap = cap_get_file(filename); if (cap) { cap_free(cap); return ca_c; } #endif /* LINUX_FILE_CAPS */ if (attr->st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) return (FILE_SIZE_PTR(attr) == 0) ? ee_c : ex_c; if (FILE_SIZE_PTR(attr) == 0) return ef_c; if (attr->st_nlink > 1) return mh_c; const char *ext = conf.check_ext == 1 ? strrchr(filename, '.') : (char *)NULL; if (!ext || ext == filename) return fi_c; size_t color_len = 0; char *extcolor = get_ext_color(ext, &color_len); if (!extcolor) return fi_c; color_len += 4; char *ext_color = xnmalloc(color_len, sizeof(char)); snprintf(ext_color, color_len, "\x1b[%sm", extcolor); *free_color = 1; return ext_color; } /* Used by the check_completions function to get filenames color * according to file type. */ static char * get_comp_color(const char *filename, const struct stat *attr, int *free_color) { switch (attr->st_mode & S_IFMT) { case S_IFDIR: return conf.light_mode == 1 ? di_c : get_dir_color(filename, attr, -1); case S_IFREG: return get_reg_file_color(filename, attr, free_color); case S_IFLNK: { if (conf.light_mode == 1) return ln_c; char *linkname = xrealpath(filename, NULL); if (linkname) { free(linkname); return ln_c; } return or_c; } case S_IFSOCK: return so_c; case S_IFBLK: return bd_c; case S_IFCHR: return cd_c; case S_IFIFO: return pi_c; default: return no_c; } } static inline int skip_leading_dot_slash(char **str, size_t *len) { int dot_slash = 0; if (*len >= 2 && *(*str) == '.' && *(*str + 1) == '/') { dot_slash = 1; (*str) += 2; (*len) -= 2; } return dot_slash; } static inline int remove_trailing_slash(char **str, size_t *len) { if (*len == 0) return 0; if ((*str)[*len - 1] == '/') { (*len)--; (*str)[*len] = '\0'; return 1; } return 0; } static inline void skip_trailing_spaces(char **str, size_t *len) { while (*len > 0 && (*str)[*len - 1] == ' ' && (*len == 1 || (*str)[*len - 2] != '\\') ) { (*len)--; (*str)[*len] = '\0'; } } static inline void skip_leading_backslashes(char **str, size_t *len) { if (*len == 0) return; while (*(*str) == '\\') { ++(*str); --(*len); } } static void match_print(char *match, const size_t len, char *color, const int append_slash) { *tmp_buf = '\0'; if (append_slash == 1) snprintf(tmp_buf, sizeof(tmp_buf), "%s/", match); char *tmp = escape_str(*tmp_buf ? tmp_buf : match); if (!tmp || !*tmp) { print_suggestion(match, len, color); return; } char *q; if (cur_comp_type == TCMP_PATH && *tmp == '\\' && tmp[1] == '~') q = tmp + 1; else q = tmp; print_suggestion(q, len, color); free(tmp); } static inline int print_match(char *match, const size_t len) { int append_slash = 0, free_color = 0; char *p = (char *)NULL, *temp_color = (char *)NULL; char *color = (conf.suggest_filetype_color == 1) ? no_c : sf_c; if (*match == '~') p = tilde_expand(match); struct stat attr; if (lstat(p ? p : match, &attr) != -1) { if (S_ISDIR(attr.st_mode) || (S_ISLNK(attr.st_mode) && get_link_ref(p ? p : match) == S_IFDIR)) { /* Do not append slash if suggesting the root dir. */ append_slash = (*match == '/' && !match[1]) ? 0 : 1; suggestion.filetype = DT_DIR; } if (conf.suggest_filetype_color == 1) { temp_color = get_comp_color(p ? p : match, &attr, &free_color); if (temp_color) color = temp_color; else free_color = 0; } } else { suggestion.filetype = DT_DIR; } free(p); suggestion.type = COMP_SUG; match_print(match, len, color, append_slash); if (free_color == 1) free(color); return PARTIAL_MATCH; } static int get_print_status(const char *str, const char *match, const size_t len) { if (suggestion.printed && suggestion_buf) clear_suggestion(CS_FREEBUF); if ((len > 0 && str[len - 1] == '/') || strlen(match) == len) return FULL_MATCH; return PARTIAL_MATCH; } static int check_completions(char *str, size_t len, const int print) { if (!str || !*str) return NO_MATCH; skip_trailing_spaces(&str, &len); skip_leading_backslashes(&str, &len); if (len == 0) return NO_MATCH; if (conf.fuzzy_match != 0 && words_num == 1 && *str != '/' && is_internal_cmd(str, ALL_CMDS, 1, 1)) return NO_MATCH; int printed = NO_MATCH; suggestion.filetype = DT_REG; cur_comp_type = TCMP_NONE; if (print == 0 && words_num == 1) { /* First (and only) word followed by a space. */ struct stat a; if (lstat(str, &a) == 0) { cur_comp_type = TCMP_PATH; return FULL_MATCH; } return NO_MATCH; } *fz_match = '\0'; flags |= STATE_SUGGESTING; char *match = my_rl_path_completion(str, 0); flags &= ~STATE_SUGGESTING; if (!match && !*fz_match) return NO_MATCH; if (print == 0 && match) { int ret = get_print_status(str, match, len); free(match); cur_comp_type = TCMP_PATH; return ret; } cur_comp_type = TCMP_PATH; /* Required by print_match() */ printed = print_match(match ? match : fz_match, len); *fz_match = '\0'; cur_comp_type = printed == NO_MATCH ? TCMP_NONE : TCMP_PATH; free(match); return printed; } static inline void print_directory_suggestion(const filesn_t i, const size_t len, char *color) { if (conf.suggest_filetype_color == 1) color = file_info[i].color; suggestion.filetype = DT_DIR; *tmp_buf = '\0'; snprintf(tmp_buf, sizeof(tmp_buf), "%s/", file_info[i].name); char *tmp = escape_str(tmp_buf); if (tmp) { print_suggestion(tmp, len, color); free(tmp); return; } print_suggestion(tmp_buf, len, color); } static inline void print_reg_file_suggestion(char *str, const filesn_t i, size_t len, char *color, const int dot_slash) { if (conf.suggest_filetype_color) color = file_info[i].color; suggestion.filetype = DT_REG; char *tmp = escape_str(file_info[i].name); if (tmp) { char *s = str; while (*s) { if (is_quote_char(*s)) len++; s++; } if (dot_slash == 1) { /* Reinsert './', removed to check filename. */ *tmp_buf = '\0'; snprintf(tmp_buf, sizeof(tmp_buf), "./%s", tmp); print_suggestion(tmp_buf, len + 2, color); } else { print_suggestion(tmp, len, color); } free(tmp); return; } if (dot_slash == 1) { *tmp_buf = '\0'; snprintf(tmp_buf, sizeof(tmp_buf), "./%s", file_info[i].name); print_suggestion(tmp_buf, len + 2, color); return; } print_suggestion(file_info[i].name, len, color); } static int check_filenames(char *str, size_t len, const int first_word, const size_t full_word) { char *color = (conf.suggest_filetype_color == 1) ? no_c : sf_c; skip_leading_backslashes(&str, &len); const int dot_slash = skip_leading_dot_slash(&str, &len); skip_trailing_spaces(&str, &len); const int removed_slash = remove_trailing_slash(&str, &len); filesn_t fuzzy_index = -1; const int fuzzy_str_type = (conf.fuzzy_match == 1 && contains_utf8(str) == 1) ? FUZZY_FILES_UTF8 : FUZZY_FILES_ASCII; int best_fz_score = 0; filesn_t i; for (i = 0; i < files; i++) { if (!file_info[i].name) continue; if (removed_slash == 1 && (file_info[i].dir != 1 || len != file_info[i].len)) continue; if (full_word == 1) { if ((conf.case_sens_path_comp ? strcmp(str, file_info[i].name) : strcasecmp(str, file_info[i].name)) == 0) return FULL_MATCH; continue; } if (len == 0) continue; if (first_word == 1 && ( (file_info[i].dir == 1 && conf.autocd == 0) || (file_info[i].dir == 0 && conf.auto_open == 0) ) ) continue; if (words_num > 1 && rl_line_buffer && *rl_line_buffer == 'c' && rl_line_buffer[1] == 'd' && rl_line_buffer[2] == ' ' && file_info[i].dir == 0) continue; /* No fuzzy matching if not at the end of the line. */ if (conf.fuzzy_match == 0 || rl_point < rl_end) { if (conf.case_sens_path_comp ? (*str == *file_info[i].name && strncmp(str, file_info[i].name, len) == 0) : (TOUPPER(*str) == TOUPPER(*file_info[i].name) && strncasecmp(str, file_info[i].name, len) == 0)) { if (file_info[i].len == len) return FULL_MATCH; suggestion.type = FILE_SUG; if (file_info[i].dir) print_directory_suggestion(i, len, color); else print_reg_file_suggestion(str, i, len, color, dot_slash); return PARTIAL_MATCH; } } /* ############### FUZZY MATCHING ################## */ else { const int s = fuzzy_match(str, file_info[i].name, len, fuzzy_str_type); if (s > best_fz_score) { fuzzy_index = i; if (s == TARGET_BEGINNING_BONUS) break; best_fz_score = s; } } } if (fuzzy_index > -1) { /* We have a fuzzy match. */ cur_comp_type = TCMP_PATH; /* i < files == we have a full match (TARGET_BEGINNING_BONUS). */ suggestion.type = i < files ? FILE_SUG : FUZZY_FILENAME; if (file_info[fuzzy_index].dir) print_directory_suggestion(fuzzy_index, len, color); else print_reg_file_suggestion(str, fuzzy_index, len, color, dot_slash); return PARTIAL_MATCH; } if (removed_slash == 1) /* We removed the final slash: reinsert it. */ str[len] = '/'; return NO_MATCH; } static int check_history(const char *str, const size_t len) { if (!history || !str || !*str || len == 0) return NO_MATCH; int i = (int)current_hist_n; while (--i >= 0) { if (!history[i].cmd || TOUPPER(*str) != TOUPPER(*history[i].cmd)) continue; if (len > 1 && history[i].cmd[1] && TOUPPER(str[1]) != TOUPPER(history[i].cmd[1])) continue; if ((conf.case_sens_path_comp ? strncmp(str, history[i].cmd, len) : strncasecmp(str, history[i].cmd, len)) == 0) { if (history[i].len > len) { suggestion.type = HIST_SUG; print_suggestion(history[i].cmd, len, sh_c); return PARTIAL_MATCH; } return FULL_MATCH; } } return NO_MATCH; } static int check_builtins(const char *str, const size_t len, const int print) { char **b = (char **)NULL; switch (shell) { case SHELL_NONE: return NO_MATCH; case SHELL_BASH: b = bash_builtins; break; case SHELL_DASH: b = dash_builtins; break; case SHELL_FISH: b = fish_builtins; break; case SHELL_KSH: b = ksh_builtins; break; case SHELL_TCSH: b = tcsh_builtins; break; case SHELL_ZSH: b = zsh_builtins; break; default: return NO_MATCH; } size_t i; for (i = 0; b[i]; i++) { if (*str != *b[i]) continue; if (!print) { if (strcmp(str, b[i]) == 0) return FULL_MATCH; continue; } if (strncmp(b[i], str, len) != 0) continue; const size_t blen = strlen(b[i]); if (blen > len) { suggestion.type = CMD_SUG; print_suggestion(b[i], len, sb_c); return PARTIAL_MATCH; } return FULL_MATCH; } return NO_MATCH; } static inline int print_cmd_suggestion(const size_t i, const size_t len) { if (is_internal_cmd(bin_commands[i], ALL_CMDS, 1, 1)) { if (strlen(bin_commands[i]) > len) { suggestion.type = CMD_SUG; print_suggestion(bin_commands[i], len, sx_c); return PARTIAL_MATCH; } return FULL_MATCH; } if (conf.ext_cmd_ok == 1) { if (strlen(bin_commands[i]) > len) { suggestion.type = CMD_SUG; print_suggestion(bin_commands[i], len, sc_c); return PARTIAL_MATCH; } return FULL_MATCH; } return NO_MATCH; } static inline int print_internal_cmd_suggestion(char *str, const size_t len, const int print) { /* Check internal command with fused parameter. */ char *p = (char *)NULL; size_t j; for (j = 0; str[j]; j++) { if (str[j] >= '1' && str[j] <= '9') { p = str + j; break; } } if (!p || p == str) return check_builtins(str, len, print); *p = '\0'; if (!is_internal_cmd(str, ALL_CMDS, 1, 1)) return NO_MATCH; return FULL_MATCH; } /* Check STR against a list of command names, both internal and in PATH. */ static int check_cmds(char *str, size_t len, const int print) { if (len == 0 || !str || !*str) return NO_MATCH; char *cmd = str; if (*cmd == '\\' && cmd[1]) { cmd++; len--; } size_t i; for (i = 0; bin_commands[i]; i++) { if (!bin_commands[i] || *cmd != *bin_commands[i]) continue; if (print == 0) { if (strcmp(cmd, bin_commands[i]) == 0) return FULL_MATCH; continue; } /* Let's check the 2nd char as well before calling strcmp(). */ if (len > 1 && bin_commands[i][1] && cmd[1] != bin_commands[i][1]) continue; if (strncmp(cmd, bin_commands[i], len) != 0) continue; const int ret = print_cmd_suggestion(i, len); if (ret == NO_MATCH) continue; return ret; } return print_internal_cmd_suggestion(cmd, len, print); } static int check_jumpdb(const char *str, const size_t len, const int print) { char *color = (conf.suggest_filetype_color == 1) ? di_c : sf_c; int i = (int)jump_n; while (--i >= 0) { if (!jump_db[i].path || TOUPPER(*str) != TOUPPER(*jump_db[i].path) || jump_db[i].rank == JUMP_ENTRY_PURGED) continue; if (len > 1 && jump_db[i].path[1] && TOUPPER(str[1]) != TOUPPER(jump_db[i].path[1])) continue; if (print == 0) { if ((conf.case_sens_path_comp ? strcmp(str, jump_db[i].path) : strcasecmp(str, jump_db[i].path)) == 0) return FULL_MATCH; continue; } if (len > 0 && (conf.case_sens_path_comp ? strncmp(str, jump_db[i].path, len) : strncasecmp(str, jump_db[i].path, len)) == 0) { if (jump_db[i].len <= len) return FULL_MATCH; suggestion.type = FILE_SUG; suggestion.filetype = DT_DIR; *tmp_buf = '\0'; if (jump_db[i].len > 0 && jump_db[i].path[jump_db[i].len - 1] != '/') snprintf(tmp_buf, sizeof(tmp_buf), "%s/", jump_db[i].path); print_suggestion(*tmp_buf ? tmp_buf : jump_db[i].path, len, color); return PARTIAL_MATCH; } } return NO_MATCH; } static int check_int_params(const char *str, const size_t len) { if (len == 0) return NO_MATCH; size_t i; for (i = 0; param_str[i].name; i++) { if (*str == *param_str[i].name && param_str[i].len > len && strncmp(str, param_str[i].name, len) == 0) { suggestion.type = INT_CMD; print_suggestion(param_str[i].name, len, sx_c); return PARTIAL_MATCH; } } return NO_MATCH; } static int check_eln(const char *str, const int print) { if (!str || !*str) return NO_MATCH; filesn_t n = xatof(str); if ( n < 1 || n > files || !file_info[n - 1].name || ( words_num == 1 && ( (file_info[n - 1].dir == 1 && conf.autocd == 0) || (file_info[n - 1].dir == 0 && conf.auto_open == 0) ) ) ) return NO_MATCH; if (print == 0) return FULL_MATCH; n--; char *color = sf_c; if (conf.suggest_filetype_color == 1) color = file_info[n].color; suggestion.type = ELN_SUG; *tmp_buf = '\0'; if (file_info[n].dir == 1) { snprintf(tmp_buf, sizeof(tmp_buf), "%s/", file_info[n].name); suggestion.filetype = DT_DIR; } else { suggestion.filetype = DT_REG; } print_suggestion(*tmp_buf ? tmp_buf : file_info[n].name, 0, color); return PARTIAL_MATCH; } static int check_aliases(const char *str, const size_t len, const int print) { if (!aliases_n) return NO_MATCH; char *color = sc_c; int i = (int)aliases_n; while (--i >= 0) { if (!aliases[i].name) continue; char *p = aliases[i].name; if (TOUPPER(*p) != TOUPPER(*str)) continue; if (print == 0) { if ((conf.case_sens_path_comp ? strcmp(p, str) : strcasecmp(p, str)) == 0) return FULL_MATCH; continue; } if ((conf.case_sens_path_comp ? strncmp(p, str, len) : strncasecmp(p, str, len)) != 0) continue; if (!aliases[i].cmd || !*aliases[i].cmd) continue; suggestion.type = ALIAS_SUG; print_suggestion(aliases[i].cmd, 0, color); return PARTIAL_MATCH; } return NO_MATCH; } /* Get a match from the jump database and print the suggestion. */ static int check_jcmd(char *line) { if (suggestion_buf) clear_suggestion(CS_FREEBUF); /* Split line into an array of substrings. */ char **substr = line ? get_substr(line, ' ', 0) : (char **)NULL; if (!substr) return NO_MATCH; /* Check the jump database for a match. If a match is found, it will * be stored in jump_suggestion (global). */ dirjump(substr, SUG_JUMP); size_t i; for (i = 0; substr[i]; i++) free(substr[i]); free(substr); if (!jump_suggestion) return NO_MATCH; suggestion.type = JCMD_SUG; suggestion.filetype = DT_DIR; print_suggestion(jump_suggestion, 0, conf.suggest_filetype_color ? di_c : sf_c); free(jump_suggestion); jump_suggestion = (char *)NULL; return PARTIAL_MATCH; } /* Check if we must suggest --help for internal commands. */ static int check_help(char *full_line, const char *_last_word) { size_t len = strlen(_last_word); if (strncmp(_last_word, "--help", len) != 0) return NO_MATCH; char *ret = strchr(full_line, ' '); if (!ret) return NO_MATCH; *ret = '\0'; const int retval = is_internal_cmd(full_line, ALL_CMDS, 1, 1); *ret = ' '; if (retval == 0) return NO_MATCH; suggestion.type = INT_HELP_SUG; print_suggestion("--help", len, sx_c); return PARTIAL_MATCH; } static int check_users(const char *str, const size_t len) { #if defined(__ANDROID__) UNUSED(str); UNUSED(len); return NO_MATCH; #else struct passwd *p; while ((p = getpwent())) { if (!p->pw_name) break; if (len == 0 || (*str == *p->pw_name && strncmp(str, p->pw_name, len) == 0)) { suggestion.type = USER_SUG; *tmp_buf = '\0'; snprintf(tmp_buf, sizeof(tmp_buf), "~%s", p->pw_name); print_suggestion(tmp_buf, len + 1, sf_c); endpwent(); return PARTIAL_MATCH; } } endpwent(); return NO_MATCH; #endif /* __ANDROID__ */ } static int check_variables(const char *str, const size_t len) { size_t i; for (i = 0; environ[i]; i++) { if (TOUPPER(*environ[i]) != TOUPPER(*str) || strncasecmp(str, environ[i], len) != 0) continue; char *ret = strchr(environ[i], '='); if (!ret) continue; *ret = '\0'; suggestion.type = VAR_SUG; *tmp_buf = '\0'; snprintf(tmp_buf, sizeof(tmp_buf), "$%s", environ[i]); print_suggestion(tmp_buf, len + 1, sh_c); *ret = '='; return PARTIAL_MATCH; } if (usrvar_n == 0) return NO_MATCH; for (i = 0; usr_var[i].name; i++) { if (TOUPPER(*str) != TOUPPER(*usr_var[i].name) || strncasecmp(str, usr_var[i].name, len) != 0) continue; suggestion.type = CMD_SUG; *tmp_buf = '\0'; snprintf(tmp_buf, sizeof(tmp_buf), "$%s", usr_var[i].name); print_suggestion(tmp_buf, len + 1, sh_c); return PARTIAL_MATCH; } return NO_MATCH; } static int is_last_word(void) { int lw = 1; if (rl_point >= rl_end) return lw; char *p = strchr(rl_line_buffer + rl_point, ' '); if (!p) return lw; while (*(++p)) { if (*p != ' ') { lw = 0; break; } } return lw; } static void turn_it_wrong(void) { char *b = rl_copy_text(0, rl_end); if (!b) return; fputs(wp_c, stdout); fflush(stdout); cur_color = wp_c; int bk = rl_point; rl_delete_text(0, rl_end); rl_point = rl_end = 0; rl_redisplay(); rl_insert_text(b); free(b); rl_point = bk; } /* Switch to the warning prompt. * FC is first char and LC last char. */ static void print_warning_prompt(const char fc, const unsigned char lc) { if (conf.warning_prompt == 0 || wrong_cmd == 1 || fc == ';' || fc == ':' || fc == '#' || fc == '@' || fc == '$' || fc == '\'' || fc == '"') return; if (suggestion.printed || suggestion_buf) clear_suggestion(CS_FREEBUF); wrong_cmd = 1; rl_save_prompt(); char *decoded_prompt = decode_prompt(conf.wprompt_str); rl_set_prompt(decoded_prompt); free(decoded_prompt); /* if (conf.highlight == 1 && ( (rl_point < rl_end && words_num > 1) || (lc == ' ' && words_num == 1) ) ) turn_it_wrong(); */ UNUSED(lc); if (conf.highlight == 1 && ((rl_point < rl_end && words_num > 1) || words_num == 1)) turn_it_wrong(); } #ifndef _NO_TAGS static inline int check_tags(const char *str, const size_t len, const int type) { if (!str || !*str || len == 0 || tags_n == 0 || !tags) return NO_MATCH; size_t i; for (i = 0; tags[i]; i++) { if (*str != *tags[i] || strncmp(str, tags[i], len) != 0) continue; suggestion.type = type; print_suggestion(tags[i], len, sf_c); return PARTIAL_MATCH; } return NO_MATCH; } #endif /* !_NO_TAGS */ static int check_sort_methods(const char *str, const size_t len) { if (len == 0) { if (suggestion.printed) clear_suggestion(CS_FREEBUF); return NO_MATCH; } const int a = atoi(str); if (a < 0 || a > SORT_TYPES || (conf.light_mode == 1 && !ST_IN_LIGHT_MODE(a))) { if (suggestion.printed) clear_suggestion(CS_FREEBUF); return NO_MATCH; } suggestion.type = SORT_SUG; print_suggestion(sort_methods[a].name, 0, sf_c); return PARTIAL_MATCH; } static int check_prompts(char *word, const size_t len) { int i = (int)prompts_n; char *q = (char *)NULL, *w = word; size_t l = len; if (strchr(word, '\\')) { q = unescape_str(word, 0); w = q ? q : word; l = w == q ? strlen(w) : len; } while (--i >= 0) { if (TOUPPER(*w) == TOUPPER(*prompts[i].name) && (conf.case_sens_list ? strncmp(prompts[i].name, w, l) : strncasecmp(prompts[i].name, w, l)) == 0) { suggestion.type = PROMPT_SUG; char *p = escape_str(prompts[i].name); print_suggestion(p ? p : prompts[i].name, len, sx_c); free(p); free(q); return PARTIAL_MATCH; } } free(q); return NO_MATCH; } /* Get the word after LAST_SPACE (last non-escaped space in rl_line_buffer, * returned by get_last_space()), store it in LAST_WORD (global), and * set LAST_WORD_OFFSET (global) to the index of the beginning of this last * word in rl_line_buffer. */ static void get_last_word(const char *last_space) { const char *tmp = (last_space && last_space[1]) ? last_space + 1 : (rl_line_buffer ? rl_line_buffer : (char *)NULL); if (tmp) { const size_t len = strlen(tmp); last_word = xnrealloc(last_word, len + 1, sizeof(char)); xstrsncpy(last_word, tmp, len + 1); } else { last_word = xnrealloc(last_word, 1, sizeof(char)); *last_word = '\0'; } last_word_offset = (last_space && last_space[1] && rl_line_buffer) ? (int)((last_space + 1) - rl_line_buffer) : 0; } static int check_workspaces(char *word, size_t wlen, const int type) { if (!word || !*word || !workspaces) return NO_MATCH; if (*word >= '1' && *word <= MAX_WS + '0' && !word[1]) { const int a = atoi(word); if (a > 0 && workspaces[a - 1].name) { suggestion.type = type == WS_PREFIX_SUG ? WS_NUM_PREFIX_SUG : WS_NUM_SUG; print_suggestion(workspaces[a - 1].name, 0, sf_c); return PARTIAL_MATCH; } return NO_MATCH; } char *q = (char *)NULL, *w = word; size_t l = wlen; if (strchr(word, '\\')) { q = unescape_str(word, 0); w = q ? q : word; l = w == q ? strlen(w) : wlen; } int i = MAX_WS; while (--i >= 0) { if (!workspaces[i].name) continue; if (TOUPPER(*w) == TOUPPER(*workspaces[i].name) && strncasecmp(w, workspaces[i].name, l) == 0) { suggestion.type = type; char *p = escape_str(workspaces[i].name); print_suggestion(p ? p : workspaces[i].name, wlen, sf_c); free(p); free(q); return PARTIAL_MATCH; } } free(q); return NO_MATCH; } static int check_fastback(const char *w) { if (!w || !*w) return NO_MATCH; char *f = fastback(w); if (!f) return NO_MATCH; if (!*f) { free(f); return NO_MATCH; } suggestion.type = FASTBACK_SUG; suggestion.filetype = DT_DIR; cur_comp_type = TCMP_PATH; char *e = escape_str(f); print_suggestion(e, 0, sf_c); free(f); free(e); return PARTIAL_MATCH; } #ifndef _NO_PROFILES static int check_profiles(char *word, const size_t len) { if (!word || !*word || !profile_names) return NO_MATCH; char *q = (char *)NULL, *w = word; size_t l = len; if (strchr(word, '\\')) { q = unescape_str(word, 0); w = q ? q : word; l = w == q ? strlen(w) : len; } size_t i; for (i = 0; profile_names[i]; i++) { if (conf.case_sens_list == 0 ? (TOUPPER(*w) == TOUPPER(*profile_names[i]) && strncasecmp(w, profile_names[i], l) == 0) : (*w == *profile_names[i] && strncmp(w, profile_names[i], l) == 0)) { suggestion.type = PROFILE_SUG; char *p = escape_str(profile_names[i]); print_suggestion(p ? p : profile_names[i], len, sx_c); free(p); free(q); return PARTIAL_MATCH; } } free(q); return NO_MATCH; } #endif /* !_NO_PROFILES */ static int check_kb_func_names(char *word, const size_t len) { if (!word || !*word || len == 0 || kbinds_n == 0 || !kbinds) return NO_MATCH; size_t i; for (i = 0; i < kbinds_n; i++) { if (!kbinds[i].function || *word != *kbinds[i].function || strncmp(word, kbinds[i].function, len) != 0) continue; suggestion.type = NET_SUG; /* Same behavior */ print_suggestion(kbinds[i].function, len, sx_c); return PARTIAL_MATCH; } return NO_MATCH; } static int check_remotes(char *word, const size_t len) { if (!word || !*word || !remotes) return NO_MATCH; char *q = (char *)NULL, *w = word; size_t l = len; if (strchr(word, '\\')) { q = unescape_str(word, 0); w = q ? q : word; l = w == q ? strlen(w) : len; } size_t i; for (i = 0; remotes[i].name; i++) { if (conf.case_sens_list == 0 ? (TOUPPER(*w) == TOUPPER(*remotes[i].name) && strncasecmp(w, remotes[i].name, l) == 0) : (*w == *remotes[i].name && strncmp(w, remotes[i].name, l) == 0)) { suggestion.type = NET_SUG; char *p = escape_str(remotes[i].name); print_suggestion(p ? p : remotes[i].name, len, sx_c); free(p); free(q); return PARTIAL_MATCH; } } free(q); return NO_MATCH; } static int check_color_schemes(char *word, const size_t len) { if (!word || !*word || !color_schemes) return NO_MATCH; char *q = (char *)NULL, *w = word; size_t l = len; if (strchr(word, '\\')) { q = unescape_str(word, 0); w = q ? q : word; l = w == q ? strlen(w) : len; } size_t i; for (i = 0; color_schemes[i]; i++) { if (conf.case_sens_list == 0 ? (TOUPPER(*w) == TOUPPER(*color_schemes[i]) && strncasecmp(w, color_schemes[i], l) == 0) : (*w == *color_schemes[i] && strncmp(w, color_schemes[i], l) == 0)) { suggestion.type = CSCHEME_SUG; char *p = escape_str(color_schemes[i]); print_suggestion(p ? p : color_schemes[i], len, sx_c); free(p); free(q); return PARTIAL_MATCH; } } free(q); return NO_MATCH; } static int check_bookmark_names(char *word, const size_t len) { if (!word || !*word || !bookmarks) return NO_MATCH; const size_t prefix = (*word == 'b' && word[1] == ':') ? 2 : 0; char *q = (char *)NULL, *w = word + prefix; size_t l = len - prefix; if (strchr(word + prefix, '\\')) { q = unescape_str(word + prefix, 0); w = q ? q : word + prefix; l = w == q ? strlen(w) : len; } size_t i; for (i = 0; i < bm_n; i++) { if (!bookmarks[i].name || !*bookmarks[i].name) continue; if (conf.case_sens_list == 0 ? (TOUPPER(*w) == TOUPPER(*bookmarks[i].name) && strncasecmp(w, bookmarks[i].name, l) == 0) : (*w == *bookmarks[i].name && strncmp(w, bookmarks[i].name, l) == 0)) { if (prefix == 2 && !*(bookmarks[i].name + l)) /* Full match */ break; char *p = escape_str(bookmarks[i].name); suggestion.type = prefix == 2 ? BM_PREFIX_SUG : BM_NAME_SUG; print_suggestion(p ? p : bookmarks[i].name, len - prefix, sx_c); free(p); free(q); return PARTIAL_MATCH; } } free(q); return NO_MATCH; } static int check_backdir(char *start) { if (!workspaces || !workspaces[cur_ws].path) return NO_MATCH; /* Remove the last component of the current path name (CWD): * we want to match only PARENT directories. */ char bk_cwd[PATH_MAX + 1]; xstrsncpy(bk_cwd, workspaces[cur_ws].path, sizeof(bk_cwd)); char *q = strrchr(bk_cwd, '/'); if (q) *q = '\0'; char *lb = start + 3; char *ds = strchr(lb, '\\') ? unescape_str(lb, 0) : lb; /* Find the query string in the list of parent directories. */ char *p = conf.case_sens_path_comp == 1 ? strstr(bk_cwd, ds) : xstrcasestr(bk_cwd, ds); if (p) { char *pp = strchr(p, '/'); if (pp) *pp = '\0'; suggestion.type = BACKDIR_SUG; print_suggestion(bk_cwd, 0, sf_c); if (ds && ds != lb) free(ds); return PARTIAL_MATCH; } if (ds && ds != lb) free(ds); return NO_MATCH; } static int check_dirhist(char *word, const size_t len) { const int fuzzy_str_type = (conf.fuzzy_match == 1 && contains_utf8(word) == 1) ? FUZZY_FILES_UTF8 : FUZZY_FILES_ASCII; int best_fz_score = 0, fuzzy_index = -1; int i = dirhist_total_index; while (--i >= 0) { if (!old_pwd[i] || !*old_pwd[i] || *old_pwd[i] == KEY_ESC) continue; if (conf.fuzzy_match == 0 || rl_point < rl_end) { if (strstr(old_pwd[i], word)) { suggestion.type = DIRHIST_SUG; print_suggestion(old_pwd[i], 0, sf_c); return PARTIAL_MATCH; } } else { int s = fuzzy_match(word, old_pwd[i], len, fuzzy_str_type); if (s > best_fz_score) { fuzzy_index = i; if (s == TARGET_BEGINNING_BONUS) break; best_fz_score = s; } } } if (fuzzy_index == -1) return NO_MATCH; cur_comp_type = TCMP_DIRHIST; suggestion.type = DIRHIST_SUG; print_suggestion(old_pwd[fuzzy_index], 0, sf_c); return PARTIAL_MATCH; } /* Check for available suggestions. Returns zero if true, one if not, * and -1 if C was inserted before the end of the current line. * If a suggestion is found, it will be printed by print_suggestion(). */ int rl_suggestions(const unsigned char c) { if (*rl_line_buffer == '#' || cur_color == hc_c) { /* No suggestion at all if comment. */ if (suggestion.printed) clear_suggestion(CS_FREEBUF); return FUNC_SUCCESS; } int printed = 0, zero_offset = 0; last_word_offset = 0; cur_comp_type = TCMP_NONE; if (rl_end == 0 && rl_point == 0) { free(suggestion_buf); suggestion_buf = (char *)NULL; if (wrong_cmd) recover_from_wrong_cmd(); return FUNC_SUCCESS; } suggestion.full_line_len = (size_t)rl_end + 1; char *last_space = get_last_chr(rl_line_buffer, ' ', rl_end); /* Reset the wrong cmd flag whenever we have a new word or a new line. */ if (rl_end == 0 || c == '\n') { if (wrong_cmd) recover_from_wrong_cmd(); } /* We need a copy of the complete line. */ char *full_line = rl_line_buffer; const char *lb = rl_line_buffer; /* A copy of the last entered word. */ get_last_word(last_space); /* Count words */ size_t full_word = 0, start_word = 0; words_num = count_words(&start_word, &full_word); /* And a copy of the first word as well. */ char *first_word = (char *)NULL; if (full_word) { rl_line_buffer[full_word] = '\0'; char *q = rl_line_buffer + start_word; first_word = savestring(q, strlen(q)); rl_line_buffer[full_word] = ' '; } /* A pointer to the beginning of the last word (command name) */ char *s = rl_line_buffer + start_word; char *word = (words_num == 1 && c != ' ' && first_word) ? first_word : last_word; size_t wlen = strlen(word); /* If more than one word and the cursor is on the first word, * jump to the check command name section. */ point_is_first_word = 0; if (words_num >= 2 && rl_point <= (int)full_word + 1) { point_is_first_word = 1; goto CHECK_FIRST_WORD; } /* If not on the first word and not at the end of the last word, do nothing. */ const int lw = is_last_word(); if (!lw) { if (suggestion.printed == 1 && suggestion.nlines > 1) clear_suggestion(CS_FREEBUF); goto SUCCESS; } /* First word is an assignment. */ if (c == '=' && words_num == 1 && wrong_cmd == 1) { recover_from_wrong_cmd(); goto SUCCESS; } /* '~' or '~/' */ if (*word == '~' && (!word[1] || (word[1] == '/' && !word[2]))) { if (wrong_cmd) recover_from_wrong_cmd(); if (suggestion.printed == 1 && suggestion_buf && suggestion.type == HIST_SUG && (!rl_line_buffer || strncmp(suggestion_buf, rl_line_buffer, (size_t)rl_point) != 0)) clear_suggestion(CS_FREEBUF); printed = PARTIAL_MATCH; zero_offset = 1; goto SUCCESS; } /* ###################################### * # Search for suggestions # * ######################################*/ /* Fastback */ if (*word == '.' && word[1] == '.' && (!word[2] || word[2] == '.') && (printed = check_fastback(word)) != NO_MATCH) goto SUCCESS; /* 3.a) Internal command description */ char *cdesc = (char *)NULL; if (conf.cmd_desc_sug == 1 && c != ' ' && words_num == 1 && (!rl_line_buffer || (rl_end > 0 && rl_line_buffer[rl_end - 1] != ' ')) && (cdesc = check_int_cmd_desc(word, wlen)) != NULL) { suggestion.type = CMD_DESC_SUG; print_suggestion(cdesc, 0, sd_c); printed = PARTIAL_MATCH; goto SUCCESS; } /* 3.b) Check already suggested string */ if (suggestion_buf && suggestion.printed && !(flags & BAEJ_SUGGESTION) && !IS_DIGIT(c)) { if (suggestion.type == HIST_SUG || suggestion.type == INT_CMD) { /* Skip the j cmd: we always want the BAEJ suggestion here. */ if (full_line && *full_line == 'j' && full_line[1] == ' ') { ; } else if (full_line && *full_line == *suggestion_buf && strncmp(full_line, suggestion_buf, (size_t)rl_end) == 0) { printed = PARTIAL_MATCH; zero_offset = 1; goto SUCCESS; } /* An alias name could be the same as the beginning of the alias * defintion, so that this test must always be skipped in case * of aliases. */ } else if (suggestion.type != ALIAS_SUG && c != ' ' && (conf.case_sens_path_comp ? (*word == *suggestion_buf && strncmp(word, suggestion_buf, wlen) == 0) : (TOUPPER(*word) == TOUPPER(*suggestion_buf) && strncasecmp(word, suggestion_buf, wlen) == 0) ) ) { printed = PARTIAL_MATCH; goto SUCCESS; } } /* 3.c) Internal commands fixed parameters */ if (words_num > 1) { /* 3.c.1) Suggest the sel keyword only if not first word */ if (sel_n > 0 && *word == 's' && strncmp(word, "sel", wlen) == 0) { suggestion.type = SEL_SUG; printed = 1; print_suggestion("sel", wlen, sx_c); goto SUCCESS; } /* 3.c.2) Check commands fixed parameters */ printed = check_int_params(full_line, (size_t)rl_end); if (printed != NO_MATCH) { zero_offset = 1; goto SUCCESS; } /* 3.c.3) Let's suggest --help for internal commands */ if (*word == '-') { if ((printed = check_help(full_line, word)) != NO_MATCH) goto SUCCESS; } } /* 3.d) Let's suggest non-fixed parameters for internal commands * Only if second word or more (first word is the command name). */ switch (words_num > 1 ? *s : '\0') { case 'b': /* Bookmark names */ if (bm_n > 0 && s[1] == 'm' && s[2] == ' ') { if (!(s[3] == 'a' && s[4] == ' ') && strncmp(s + 3, "add", 3) != 0) { if ((printed = check_bookmark_names(word, wlen)) != NO_MATCH) { goto SUCCESS; } else { if (suggestion.printed) clear_suggestion(CS_FREEBUF); if (s[3] != '-') /* Might be --help, let it continue. */ goto FAIL; } } else if (words_num > 5) { /* 5 == 'bm add dir/ name shortcut'*/ goto FAIL; } } /* Backdir function (bd) */ else if (s[1] == 'd' && s[2] == ' ' && s[3]) { if (s[3] == '/' && !s[4]) /* The query string is a single slash: do nothing. */ goto FAIL; if ((printed = check_backdir(s)) != NO_MATCH) goto SUCCESS; } break; case 'c': /* Color schemes */ if (conf.colorize == 1 && color_schemes && s[1] == 's' && s[2] == ' ') { if ((printed = check_color_schemes(word, wlen)) != NO_MATCH) goto SUCCESS; } break; case 'd': /* Dirhist command (dh) */ if (words_num == 2 && old_pwd && dirhist_total_index > 0 && wlen > 0 && s[1] == 'h' && s[2] == ' ' && !strchr(word, '/')) { if ((printed = check_dirhist(word, wlen)) != NO_MATCH) goto SUCCESS; else goto FAIL; } break; case 'j': /* j command */ if (s[1] == ' ' || ((s[1] == 'c' || s[1] == 'p') && s[2] == ' ')) { if ((printed = check_jcmd(s)) != NO_MATCH) goto SUCCESS; else goto FAIL; } break; case 'k': /* 'kb bind' command */ if (s[1] == 'b' && s[2] == ' ' && s[3] && strncmp(s + 3, "bind ", 5) == 0) { if ((printed = check_kb_func_names(word, wlen)) != NO_MATCH) goto SUCCESS; } break; case 'n': /* 'net' command: remotes */ if (remotes && s[1] == 'e' && s[2] == 't' && s[3] == ' ') { if ((printed = check_remotes(word, wlen)) != NO_MATCH) goto SUCCESS; } break; case 'p': /* Profiles */ #ifndef _NO_PROFILES if (profile_names && words_num == 3 && s[1] == 'f' && s[2] == ' ' && (strncmp(s + 3, "set ", 4) == 0 || strncmp(s + 3, "del ", 4) == 0 || strncmp(s + 3, "rename ", 7) == 0)) { if ((printed = check_profiles(word, wlen)) != NO_MATCH) goto SUCCESS; else goto FAIL; } #endif /* !_NO_PROFILES */ if (s[1] == 'r' && strncmp(s, "prompt set ", 11) == 0) { if (words_num != 3) goto FAIL; printed = check_prompts(word, wlen); if (prompts_n > 0 && printed != NO_MATCH) goto SUCCESS; } break; case 's': /* Sort */ if (((s[1] == 't' && s[2] == ' ') || strncmp(s, "sort ", 5) == 0) && is_number(word)) { if (words_num > 2) goto FAIL; if ((printed = check_sort_methods(word, wlen)) != NO_MATCH) goto SUCCESS; goto FAIL; } break; #ifndef _NO_TAGS case 't': /* Tag command */ if ((s[1] == 'a' || s[1] == 'u') && s[2] == ' ') { if (*word == ':' && word[1] && (printed = check_tags(word + 1, wlen - 1, TAGC_SUG)) != NO_MATCH) goto SUCCESS; } else if ((s[1] == 'l' || s[1] == 'm' || s[1] == 'n' || s[1] == 'r' || s[1] == 'y') && s[2] == ' ') { printed = check_tags(word, wlen, TAGS_SUG); if (*word && printed != NO_MATCH) goto SUCCESS; } break; #endif /* _NO_TAGS */ case 'w': /* Workspaces */ if (s[1] == 's' && s[2] == ' ') { if (words_num > 2) goto FAIL; if ((printed = check_workspaces(word, wlen, WS_NAME_SUG)) != NO_MATCH) goto SUCCESS; } break; default: break; } /* 3.d.1) Variable names, both environment and internal. */ if (*word == '$') { if ((printed = check_variables(word + 1, wlen - 1)) != NO_MATCH) goto SUCCESS; } /* 3.d.2) ~usernames */ if (*word == '~' && word[1] != '/') { if ((printed = check_users(word + 1, wlen - 1)) != NO_MATCH) goto SUCCESS; } /* 3.d.3) Bookmark names (b:) */ if (*word == 'b' && word[1] == ':' && word[2]) { if ((printed = check_bookmark_names(word, wlen)) != NO_MATCH) goto SUCCESS; } /* Workspaces (w:) */ if (*word == 'w' && word[1] == ':' && word[2]) { if ((printed = check_workspaces(word + 2, wlen - 2, WS_PREFIX_SUG)) != NO_MATCH) goto SUCCESS; } #ifndef _NO_TAGS /* 3.d.4) Tag names (t:) */ if (*lb != ';' && *lb != ':' && *word == 't' && word[1] == ':' && word[2]) { if ((printed = check_tags(word + 2, wlen - 2, TAGT_SUG)) != NO_MATCH) goto SUCCESS; } #endif /* _NO_TAGS */ /* 3.e) Execute the following checks in the order specified by * suggestion_strategy (the value is taken from the configuration file). */ size_t st; int flag = 0; /* Let's find out whether the last entered character is escaped. */ const int escaped = (wlen > 1 && word[wlen - 2] == '\\'); for (st = 0; conf.suggestion_strategy[st]; st++) { switch (conf.suggestion_strategy[st]) { case 'a': /* 3.e.1) Aliases */ flag = c == ' ' ? CHECK_MATCH : PRINT_MATCH; if (flag == CHECK_MATCH && suggestion.printed) clear_suggestion(CS_FREEBUF); if ((printed = check_aliases(word, wlen, flag)) != NO_MATCH) goto SUCCESS; break; case 'c': /* 3.e.2) Path completion */ if (rl_point < rl_end && c == '/') goto NO_SUGGESTION; /* First word and neither autocd nor auto-open. */ if (!last_space && conf.autocd == 0 && conf.auto_open == 0) break; /* Skip internal commands not dealing with filenames. */ if (first_word) { flags |= STATE_COMPLETING; if (is_internal_cmd(first_word, NO_FNAME_NUM, 1, 1)) { flags &= ~STATE_COMPLETING; goto NO_SUGGESTION; } flags &= ~STATE_COMPLETING; } if (words_num == 1) { word = first_word ? first_word : last_word; wlen = strlen(word); } if (wlen > 0 && word[wlen - 1] == ' ' && escaped == 0) word[wlen - 1] = '\0'; flag = (c == ' ' && escaped == 0) ? CHECK_MATCH : PRINT_MATCH; char *d = word; if (IS_FILE_URI(word, wlen)) { d += FILE_URI_PREFIX_LEN; wlen -= FILE_URI_PREFIX_LEN; last_word_offset += FILE_URI_PREFIX_LEN; } printed = check_completions(d, wlen, flag); if (printed != NO_MATCH) { if (flag == CHECK_MATCH) { if (printed == FULL_MATCH) goto SUCCESS; } else { goto SUCCESS; } } break; case 'e': /* 3.e.3) ELN's */ if (words_num == 1 && first_word) { word = first_word; wlen = strlen(word); } if (wlen == 0) break; int nlen = (int)wlen; while (nlen > 0 && word[nlen - 1] == ' ' && escaped == 0) { nlen--; word[nlen] = '\0'; } /* If ELN&, remove ending '&' to check the ELN. */ if (nlen > 0 && word[nlen - 1] == '&') { nlen--; word[nlen] = '\0'; } flag = c == ' ' ? CHECK_MATCH : PRINT_MATCH; if (flag == CHECK_MATCH && suggestion.printed) clear_suggestion(CS_FREEBUF); if (*lb != ';' && *lb != ':' && *word >= '1' && *word <= '9') { if (should_expand_eln(word, first_word) == 1 && (printed = check_eln(word, flag)) > 0) goto SUCCESS; } break; case 'f': /* 3.e.4) Filenames in CWD */ /* Do not check dirs and filenames if first word and * neither autocd nor auto-open are enabled. */ if (!last_space && conf.autocd == 0 && conf.auto_open == 0) break; if (words_num == 1) { word = (first_word && *first_word) ? first_word : last_word; if (*word == '/') /* Absolute path: nothing to do here. */ break; wlen = strlen(word); } else { if (*word == '/') break; } /* If "./FILE" check only "FILE" */ if (wlen > 2 && *word == '.' && word[1] == '/') { word += 2; wlen -= 2; last_word_offset += 2; } /* If we have a slash, we're not looking for files in the CWD. */ char *p = strchr(word, '/'); if (p && p[1]) break; /* Skip internal commands not dealing with filenames. */ if (first_word) { flags |= STATE_COMPLETING; if (is_internal_cmd(first_word, NO_FNAME_NUM, 1, 1)) { flags &= ~STATE_COMPLETING; goto NO_SUGGESTION; } flags &= ~STATE_COMPLETING; } if (wlen > 0 && word[wlen - 1] == ' ' && escaped == 0) word[wlen - 1] = '\0'; if (c == ' ' && escaped == 0 && suggestion.printed) clear_suggestion(CS_FREEBUF); printed = check_filenames(word, wlen, last_space ? 0 : 1, c == ' ' ? 1 : 0); if (printed != NO_MATCH) goto SUCCESS; break; case 'h': /* 3.e.5) Commands history */ printed = check_history(full_line, (size_t)rl_end); if (printed != NO_MATCH) { zero_offset = 1; goto SUCCESS; } break; case 'j': /* 3.e.6) Jump database */ /* We don't care about auto-open here: the jump function * deals with directories only. */ if (!last_space && conf.autocd == 0) break; if (words_num == 1) { word = (first_word && *first_word) ? first_word : last_word; wlen = strlen(word); } if (wlen > 0 && word[wlen - 1] == ' ' && escaped == 0) word[wlen - 1] = '\0'; flag = (c == ' ' || full_word) ? CHECK_MATCH : PRINT_MATCH; if (flag == CHECK_MATCH && suggestion.printed) clear_suggestion(CS_FREEBUF); if ((printed = check_jumpdb(word, wlen, flag)) != NO_MATCH) goto SUCCESS; break; default: break; } } /* 3.f) Cmds in PATH and CliFM internals cmds, but only for the first word. */ if (words_num > 1) { if (suggestion_buf) clear_suggestion(CS_FREEBUF); goto NO_SUGGESTION; } CHECK_FIRST_WORD: word = first_word ? first_word : last_word; /* Skip 'b:' (bookmarks), 's:' (sel files) 't:' (tags) and 'w:' * (workspaces) constructs. */ if ((*word == 'b' || *word == 's' || *word == 't' || *word == 'w') && word[1] == ':') goto NO_SUGGESTION; if (!*word || (c == ' ' && (*word == '\'' || *word == '"' || *word == '$' || *word == '#')) || *word == '<' || *word == '>' || *word == '!' || *word == '{' || *word == '[' || *word == '(' || strchr(word, '=') || *rl_line_buffer == ' ' || *word == '|' || *word == ';' || *word == '&') { if (suggestion.printed && suggestion_buf) clear_suggestion(CS_FREEBUF); goto SUCCESS; } wlen = strlen(word); /* If absolute path */ if (point_is_first_word && *word == '/' && access(word, X_OK) == 0) { printed = 1; } else if (point_is_first_word && rl_point < rl_end && *word >= '1' && *word <= '9' && is_number(word)) { const filesn_t a = xatof(word); if (a > 0 && a <= files) printed = PARTIAL_MATCH; } else if (point_is_first_word && rl_point < rl_end && (printed = check_completions(word, wlen, CHECK_MATCH)) != NO_MATCH) { if (c == ' ' && printed != FULL_MATCH) /* We have a partial match for a filename. If not a command * name, let's return NO_MATCH. */ printed = check_cmds(word, wlen, CHECK_MATCH); } else { if (wlen > 0 && word[wlen - 1] == ' ') word[wlen - 1] = '\0'; flag = (c == ' ' || full_word) ? CHECK_MATCH : PRINT_MATCH; printed = check_cmds(word, wlen, flag); } if (printed != NO_MATCH) { if (wrong_cmd && (words_num == 1 || point_is_first_word)) { rl_dispatching = 1; recover_from_wrong_cmd(); rl_dispatching = 0; } goto SUCCESS; /* Let's assume that two slashes do not constitue a search expression. */ } else { /* There's no suggestion nor any command name matching the first entered * word. So, we assume we have an invalid command name. Switch to the * warning prompt to warn the user. */ if (*word != '/' || strchr(word + 1, '/')) print_warning_prompt(*word, c); } NO_SUGGESTION: /* Clear current suggestion, if any, only if no escape char is contained * in the current input sequence. This is mainly to avoid erasing * the suggestion if moving thought the text via the arrow keys. */ if (suggestion.printed) { if (!strchr(word, KEY_ESC)) { goto FAIL; } else { /* Go to SUCCESS to avoid removing the suggestion buffer. */ printed = PARTIAL_MATCH; goto SUCCESS; } } SUCCESS: if (printed != NO_MATCH) { suggestion.offset = zero_offset ? 0 : last_word_offset; if (printed == FULL_MATCH && suggestion_buf) clear_suggestion(CS_FREEBUF); suggestion.printed = rl_point < rl_end ? 0 : 1; if (wrong_cmd == 1 && words_num == 1) { rl_dispatching = 1; recover_from_wrong_cmd(); rl_dispatching = 0; /* recover_from_wrong_cmd() removes the suggestion. * Let's reprint it. */ if (rl_point < rl_end && suggestion_buf && rl_line_buffer && *rl_line_buffer) { print_suggestion(suggestion_buf, wc_xstrlen(rl_line_buffer), suggestion.color); suggestion.printed = 1; } } fputs(NC, stdout); /* Restore color. */ if (wrong_cmd == 0) { fputs(cur_color ? cur_color : tx_c, stdout); } else { fputs(wp_c, stdout); } } else { if (wrong_cmd == 1) { fputs(NC, stdout); fputs(wp_c, stdout); } suggestion.printed = 0; } free(first_word); free(last_word); last_word = (char *)NULL; return FUNC_SUCCESS; FAIL: if (suggestion.printed == 1) clear_suggestion(CS_FREEBUF); free(first_word); free(last_word); last_word = (char *)NULL; return FUNC_FAILURE; } #else void *_skip_me_suggestions; #endif /* _NO_SUGGESTIONS */ clifm-1.26.3/src/suggestions.h000066400000000000000000000022661506632037700162260ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* suggestions.h */ #ifndef SUGGESTIONS_H #define SUGGESTIONS_H __BEGIN_DECLS void clear_suggestion(const int sflag); void free_suggestion(void); void print_suggestion(char *str, size_t offset, char *color); int recover_from_wrong_cmd(void); int rl_suggestions(const unsigned char c); __END_DECLS #endif /* SUGGESTIONS_H */ clifm-1.26.3/src/tabcomp.c000066400000000000000000002273301506632037700152750ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* tabcomp.c -- functions for tab completion */ /* The following functions are taken from Bash (1.14.7), licensed GPL-1.0-or-later, * and modified as required: * stat_char * get_y_or_n * print_filename * printable_part * rl_strpbrk * compare_strings * tab_complete * All changes are licensed GPL-2.0-or-later. */ #include "helpers.h" #include #ifdef __OpenBSD__ typedef char *rl_cpvfunc_t; # include #else # include #endif /* __OpenBSD__ */ #include #include "aux.h" #include "checks.h" #include "colors.h" #ifndef _NO_HIGHLIGHT # include "highlight.h" #endif /* !_NO_HIGHLIGHT */ #include "misc.h" #include "navigation.h" #include "readline.h" #include "selection.h" #include "sort.h" #include "spawn.h" #include "strings.h" /* quote_str() */ #ifndef _NO_SUGGESTIONS # include "suggestions.h" #endif /* !_NO_SUGGESTIONS */ #ifndef _NO_FZF # define SHOW_PREVIEWS(c) ((c) == TCMP_PATH || (c) == TCMP_SEL \ || (c) == TCMP_RANGES || (c) == TCMP_DESEL || (c) == TCMP_JUMP \ || (c) == TCMP_TAGS_F || (c) == TCMP_GLOB || (c) == TCMP_FILE_TYPES_FILES \ || (c) == TCMP_BM_PATHS || (c) == TCMP_UNTRASH || (c) == TCMP_TRASHDEL) static char finder_in_file[PATH_MAX + 1]; static char finder_out_file[PATH_MAX + 1]; /* We need to know the longest entry (if previewing files) to correctly * calculate the width of the preview window. */ static size_t longest_prev_entry; #endif /* _NO_FZF */ /* The following three functions are used to get current cursor position * (both vertical and horizontal), needed by tab completion in fzf mode * with previews enabled */ /* Return the character which best describes FILENAME. `@' for symbolic links `/' for directories `*' for executables `=' for sockets */ static int stat_char(const char *filename) { struct stat attr; int r; #ifdef S_ISLNK r = lstat(filename, &attr); #else r = stat(filename, &attr); #endif /* S_ISLNK */ if (r == -1) return 0; int c = 0; if (S_ISDIR(attr.st_mode)) { c = DIR_CHR; #ifdef S_ISLNK } else if (S_ISLNK(attr.st_mode)) { c = LINK_CHR; #endif /* S_ISLNK */ #ifdef S_ISSOCK } else if (S_ISSOCK(attr.st_mode)) { c = SOCK_CHR; #endif /* S_ISSOCK */ } else if (S_ISREG(attr.st_mode)) { if (access(filename, X_OK) == 0) c = EXEC_CHR; } else if (S_ISBLK(attr.st_mode)) { c = BLK_CHR; } else if (S_ISCHR(attr.st_mode)) { c = CHR_CHR; #ifdef SOLARIS_DOORS } else if (S_ISDOOR(attr.st_mode)) { c = DOOR_CHR; #endif /* SOLARIS_DOORS */ #ifdef S_ISWHT } else if (S_ISWHT(attr.st_mode)) { c = WHT_CHR; #endif /* S_IFWHT */ #ifdef S_ISFIFO } else { if (S_ISFIFO(attr.st_mode)) c = FIFO_CHR; #endif /* S_ISFIFO */ } return c; } /* The user must press "y" or "n". Non-zero return means "y" pressed. */ static int get_y_or_n(void) { for (;;) { const int c = fgetc(stdin); /* Flawfinder: ignore */ if (c == 'y' || c == 'Y' || c == ' ') return (1); if (c == 'n' || c == 'N' || c == RUBOUT || c == EOF) { putchar('\n'); return (0); } if (c == ABORT_CHAR) /* Defined by readline as CTRL('G') */ rl_abort(0, 0); rl_ding(); } } static int print_filename(char *to_print, char *full_pathname) { char *s; const enum comp_type t = cur_comp_type; if (conf.colorize == 1 && (t == TCMP_PATH || t == TCMP_SEL || t == TCMP_DESEL || t == TCMP_RANGES || t == TCMP_TAGS_F || t == TCMP_FILE_TYPES_FILES || t == TCMP_MIME_LIST || t == TCMP_BM_PATHS || t == TCMP_GLOB || t == TCMP_UNTRASH || t == TCMP_TRASHDEL || t == TCMP_FILE_TEMPLATES)) { colors_list(to_print, NO_ELN, NO_PAD, NO_NEWLINE); } else { for (s = to_print + tab_offset; *s; s++) putchar(*s); } if (rl_filename_completion_desired && conf.colorize == 0) { if (t == TCMP_CMD) { putc('*', rl_outstream); return 1; } /* If to_print != full_pathname, to_print is the basename of the * path passed. In this case, we try to expand the directory * name before checking for the stat character. */ int extension_char = 0; if (to_print != full_pathname) { /* Terminate the directory name */ const char c = to_print[-1]; to_print[-1] = '\0'; s = tilde_expand(full_pathname); if (rl_directory_completion_hook) (*rl_directory_completion_hook)(&s); const size_t slen = strlen(s); const size_t tlen = strlen(to_print); char *new_full_pathname = xnmalloc(slen + tlen + 2, sizeof(char)); snprintf(new_full_pathname, slen + tlen + 2, "%s/%s", s, to_print); extension_char = stat_char(new_full_pathname); free(new_full_pathname); to_print[-1] = c; } else { s = tilde_expand(full_pathname); extension_char = stat_char(s); } free(s); if (extension_char) putc(extension_char, rl_outstream); return (extension_char != 0); } else { return 0; } } /* Return the portion of PATHNAME that should be output when listing * possible completions. If we are hacking filename completion, we * are only interested in the basename, the portion following the * final slash. Otherwise, we return what we were passed. */ static char * printable_part(char *pathname) { char *temp = (char *)NULL; if (rl_filename_completion_desired) temp = strrchr(pathname, '/'); if (!temp) return (pathname); else return (++temp); } /* Find the first occurrence in STRING1 of any character from STRING2. * Return a pointer to the character in STRING1. */ static char * rl_strpbrk(char *s1, char *s2) { register char *scan; for (; *s1; s1++) { for (scan = s2; *scan; scan++) { if (*s1 == *scan) { return (s1); } } } return (char *)NULL; } void reinsert_slashes(char *str) { if (!str || !*str) return; char *p = str; while (*p) { if (*p == ':') *p = '/'; p++; } } #ifndef _NO_FZF static char * fzftab_color(char *filename, const struct stat *attr) { if (conf.colorize == 0) return df_c; struct stat a; switch (attr->st_mode & S_IFMT) { case S_IFDIR: return get_dir_color(filename, attr, -1); case S_IFREG: { if (*nf_c && check_file_access(attr->st_mode, attr->st_uid, attr->st_gid) == 0) return nf_c; char *cl = get_file_color(filename, attr); if (conf.check_ext == 0 || cl != fi_c) return (cl ? cl : fi_c); /* If trashed file, remove the trash extension, so we can get the * color according to the actual file extension. */ char *te = (char *)NULL; if (cur_comp_type == TCMP_UNTRASH || cur_comp_type == TCMP_TRASHDEL) { flags |= STATE_COMPLETING; te = remove_trash_ext(&filename); flags &= ~STATE_COMPLETING; } char *ext_cl = (char *)NULL; char *ext = strrchr(filename, '.'); if (ext && ext != filename) ext_cl = get_ext_color(ext, NULL); if (te) *te = '.'; return ext_cl ? ext_cl : (cl ? cl : fi_c); } case S_IFSOCK: return so_c; case S_IFIFO: return pi_c; case S_IFBLK: return bd_c; case S_IFCHR: return cd_c; case S_IFLNK: return stat(filename, &a) == -1 ? or_c : ln_c; default: return uf_c; } } static char * get_comp_entry_color(char *entry, const char *norm_prefix) { if (conf.colorize == 0) return (char *)NULL; char vt_file[PATH_MAX + 1]; *vt_file = '\0'; if (virtual_dir == 1 && is_file_in_cwd(entry)) xreadlink(XAT_FDCWD, entry, vt_file, sizeof(vt_file)); struct stat attr; /* Normalize URI file scheme */ const size_t len = strlen(entry); if (IS_FILE_URI(entry, len)) entry += FILE_URI_PREFIX_LEN; if (norm_prefix && !*vt_file) { char *s = strrchr(entry, '/'); char tmp[PATH_MAX + 1]; snprintf(tmp, sizeof(tmp), "%s/%s", norm_prefix, (s && *(++s)) ? s : entry); if (lstat(tmp, &attr) != -1) return fzftab_color(tmp, &attr); return uf_c; } const enum comp_type t = cur_comp_type; /* Absolute path (/FILE) or file in CWD (./FILE) */ if ( (*entry == '/' || (*entry == '.' && entry[1] == '/') ) && (t == TCMP_PATH || t == TCMP_SEL || t == TCMP_DESEL || t == TCMP_BM_PATHS || t == TCMP_DIRHIST || t == TCMP_JUMP) ) { char *f = *vt_file ? vt_file : entry; if (lstat(f, &attr) != -1) return fzftab_color(f, &attr); return uf_c; } /* Tilde */ if (*entry == '~' && (t == TCMP_PATH || t == TCMP_TAGS_F || t == TCMP_BM_PATHS || t == TCMP_SEL || t == TCMP_DESEL) ) { char *exp_path = tilde_expand(entry); if (exp_path) { char *color = uf_c; if (lstat(exp_path, &attr) != -1) color = fzftab_color(exp_path, &attr); free(exp_path); return color; } } if (t == TCMP_PATH || t == TCMP_RANGES) { if (*vt_file) { if (lstat(vt_file, &attr) != -1) return fzftab_color(vt_file, &attr); } else { char tmp[PATH_MAX + 1]; snprintf(tmp, sizeof(tmp), "%s/%s", workspaces[cur_ws].path, entry); if (lstat(tmp, &attr) != -1) return fzftab_color(tmp, &attr); } return uf_c; } if (t == TCMP_UNTRASH || t == TCMP_TRASHDEL || t == TCMP_GLOB || t == TCMP_TAGS_F || t == TCMP_FILE_TYPES_FILES) { char *f = (t == TCMP_GLOB && *vt_file) ? vt_file : entry; char p[PATH_MAX + 2]; *p = '\0'; if (t == TCMP_GLOB && *f != '/') { snprintf(p, sizeof(p), "%s/%s", workspaces[cur_ws].path, f); f = p; } return (lstat(f, &attr) != -1) ? fzftab_color(f, &attr) : uf_c; } if (t == TCMP_FILE_TEMPLATES && templates_dir) { char tmp[PATH_MAX + 1]; snprintf(tmp, sizeof(tmp), "%s/%s", templates_dir, entry); if (lstat(tmp, &attr) != -1) return fzftab_color(tmp, &attr); } if (t == TCMP_CMD && is_internal_cmd(entry, ALL_CMDS, 1, 1)) return hv_c; return df_c; } /* Return a pointer to the word after the last non-escaped space in the input * buffer. If no space is found, apointer to the entire command line * (rl_line_buffer) is returned. */ static char * get_last_input_word(void) { if (!rl_line_buffer) return (char *)NULL; char *lb = rl_line_buffer + 1; char *lastword = rl_line_buffer; while (*lb) { if (*lb == ' ' && *(lb - 1) != '\\' && lb[1] != ' ') lastword = lb + 1; lb++; } return lastword; } /* Store the unescaped string STR in the buffer BUF (only up to MAX bytes). * Returns the number of copied bytes. */ static size_t unescape_word(char *str, char *buf, const size_t max) { size_t i = 0; char *p = str; while (*p && i < max) { if (*p != '\\') { buf[i] = *p; i++; } p++; } buf[i] = '\0'; return i; } /* Append slash for dirs and space for non-dirs to the current completion. */ static void append_ending_char(const enum comp_type ct) { /* We only want the portion of the line before the cursor position. */ const char cur_char = rl_line_buffer[rl_point]; rl_line_buffer[rl_point] = '\0'; char *lastword = get_last_input_word(); if (!lastword) return; char deq_str[PATH_MAX]; *deq_str = '\0'; /* Clang static analysis complains that tmp[4] (deq_str[4]) is a garbage * value. Initialize only this exact value to get rid of the warning. */ deq_str[4] = '\0'; size_t deq_str_len = 0; if (strchr(lastword, '\\')) deq_str_len = unescape_word(lastword, deq_str, sizeof(deq_str) - 1); char *tmp = *deq_str ? deq_str : lastword; const size_t len = tmp == deq_str ? deq_str_len : strlen(tmp); size_t is_file_uri = 0; if (*tmp == 'f' && tmp[1] == 'i' && IS_FILE_URI(tmp, len)) is_file_uri = 1; char *name = tmp; char *p = is_file_uri == 0 ? normalize_path(tmp, len) : (char *)NULL; if (p) name = p; if (is_file_uri == 1) name += FILE_URI_PREFIX_LEN; struct stat attr; if (stat(name, &attr) != -1 && S_ISDIR(attr.st_mode)) { /* If not the root directory, append a slash. */ if ((*name != '/' || name[1] || ct == TCMP_USERS)) rl_insert_text("/"); } else { if (rl_end == rl_point && ct != TCMP_OPENWITH && ct != TCMP_TAGS_T && ct != TCMP_FILE_TYPES_OPTS && ct != TCMP_MIME_LIST) rl_stuff_char(' '); } /* Restore the character we removed to truncate the line at cursor position. */ rl_line_buffer[rl_point] = cur_char; if (name == p) free(p); } /* Write the text BUF, at offset OFFSET, into STDOUT. */ static void write_completion(char *buf, const size_t offset, const int multi) { if (cur_comp_type == TCMP_TAGS_F) /* Needed in case the replacement string is shorter than the query * string. Tagged files (TCMP_TAGS_F) is a possible case. We might * need to consider other completion types as well. */ ERASE_TO_RIGHT; const enum comp_type t = cur_comp_type; /* Remove ending new line char */ char *n = strchr(buf, '\n'); if (n) *n = '\0'; if (t == TCMP_GLOB) { const size_t blen = strlen(buf); if (blen > 0 && buf[blen - 1] == '/') buf[blen - 1] = '\0'; if (rl_line_buffer && *rl_line_buffer == '/' && rl_end > 0 && !strchr(rl_line_buffer + 1, '/') && !strchr(rl_line_buffer + 1, ' ')) { rl_delete_text(0, rl_end); rl_end = rl_point = 0; } } if (t == TCMP_ENVIRON || t == TCMP_USERS) { /* Skip the leading dollar sign (env vars) and tilde (users) */ rl_insert_text(buf + 1 + offset); } else if (t == TCMP_PATH && multi == 0) { char *esc_buf = escape_str(buf); if (esc_buf) { rl_insert_text(esc_buf + offset); free(esc_buf); } else { rl_insert_text(buf + offset); } } else if (t == TCMP_FILE_TYPES_OPTS || t == TCMP_MIME_LIST || t == TCMP_BOOKMARK || t == TCMP_WORKSPACES || t == TCMP_NET || t == TCMP_CSCHEME || t == TCMP_PROMPTS || t == TCMP_HIST || t == TCMP_BACKDIR || t == TCMP_PROF || t == TCMP_BM_PREFIX || t == TCMP_TAGS_T) { rl_insert_text(buf + offset); return; } else if (t == TCMP_OWNERSHIP) { rl_insert_text(buf + offset); if (rl_line_buffer && !strchr(rl_line_buffer, ':')) rl_stuff_char(':'); return; } else { rl_insert_text(buf + offset); } append_ending_char(t); } /* Return a pointer to the beginning of the word right after the last * non-escaped slash in STR, or STR if none is found. */ static char * get_last_word(char *str, const int original_query) { char *ptr = str; char *word = (char *)NULL; while (*ptr) { if (ptr == str) { if (*ptr == '/') word = ptr; } else { if (*ptr == '/' && *(ptr - 1) != '\\') word = ptr; } ptr++; } char *w = !word ? str : (*word == '/' ? word + 1 : word); /* Remove ending backslash to avoid finder (fzf) error: no ending '"' */ if (original_query == 1 && w) { char *bs = strrchr(w, '\\'); if (bs && !bs[1]) *bs = '\0'; } return w; } /* We have an alternative preview file (set either via --shotgun-file, * --config-dir, or --profile). * Let's write the filename into an environment variable * (CLIFM_ALT_PREVIEW_FILE), so that the clifm instance invoked by fzf * can handle it. */ static void setenv_fzf_alt_preview_file(void) { static char buf[PATH_MAX + 1] = ""; if (!*buf) { if (alt_preview_file && *alt_preview_file) snprintf(buf, sizeof(buf), "%s", alt_preview_file); else if (config_dir && *config_dir) snprintf(buf, sizeof(buf), "%s/preview.clifm", config_dir); else return; } setenv("CLIFM_ALT_PREVIEW_FILE", buf, 1); } static void fix_x_y_values(int *x, int *y) { switch (fzf_ext_border) { case FZF_BORDER_ROUNDED: /* fallthrough */ case FZF_BORDER_SHARP: /* fallthrough */ case FZF_BORDER_BOLD: /* fallthrough */ case FZF_BORDER_DOUBLE: /* fallthrough */ case FZF_BORDER_BLOCK: /* fallthrough */ case FZF_BORDER_THINBLOCK: /* fallthrough */ case FZF_BORDER_HORIZ: /* fallthrough */ case FZF_BORDER_TOP: (*x)--; (*y)++; break; case FZF_BORDER_RIGHT: /* fallthrough */ case FZF_BORDER_VERT: (*x)--; break; /* case FZF_BORDER_BOTTOM: // No coordinates correction required case FZF_BORDER_NONE: case FZF_BORDER_LEFT: */ default: break; } } static void set_fzf_env_vars(const int height) { int col = 0; int line = 0; if (!(flags & PREVIEWER) && term_caps.req_cur_pos == 1) { get_cursor_position(&col, &line); if (line + height - 1 > term_lines) line -= ((line + height - 1) - term_lines); } /* Let's correct image coordinates on the screen based on the preview * window style. */ int x = term_cols; int y = line; switch (fzf_preview_border_type) { case FZF_BORDER_BOTTOM: /* fallthrough */ case FZF_BORDER_NONE: /* fallthrough */ case FZF_BORDER_LEFT: /* fallthrough */ case FZF_BORDER_RIGHT: break; case FZF_BORDER_TOP: /* fallthrough */ case FZF_BORDER_HORIZ: y += (flags & PREVIEWER) ? 2 : 1; break; case FZF_BORDER_BLOCK: /* fallthrough */ case FZF_BORDER_BOLD: /* fallthrough */ case FZF_BORDER_DOUBLE: /* fallthrough */ case FZF_BORDER_ROUNDED: /* fallthrough */ case FZF_BORDER_THINBLOCK: /* fallthrough */ case FZF_BORDER_SHARP: y += (flags & PREVIEWER) ? 2 : 1; x -= 2; break; case FZF_BORDER_VERT: x -= 2; break; default: break; } if (flags & UEBERZUG_IMG_PREV) fix_x_y_values(&x, &y); char p[MAX_INT_STR]; snprintf(p, sizeof(p), "%d", y > 0 ? y - 1 : 0); setenv("CLIFM_FZF_LINE", p, 1); snprintf(p, sizeof(p), "%d", x > 0 ? x : 0); setenv("CLIFM_TERM_COLUMNS", p, 1); snprintf(p, sizeof(p), "%d", term_lines); setenv("CLIFM_TERM_LINES", p, 1); if (thumbnails_dir && *thumbnails_dir) { setenv("CLIFM_THUMBNAILS_DIR", thumbnails_dir, 1); setenv("CLIFM_THUMBINFO_FILE", THUMBNAILS_INFO_FILE, 1); } if (conf.preview_max_size != UNSET) { snprintf(p, sizeof(p), "%d", conf.preview_max_size); setenv("CLIFM_PREVIEW_MAX_SIZE", p, 1); } if (flags & ALT_PREVIEW_FILE) setenv_fzf_alt_preview_file(); } static void clear_fzf(void) { clear_term_img(); unsetenv("CLIFM_FZF_LINE"); unsetenv("CLIFM_TERM_COLUMNS"); unsetenv("CLIFM_TERM_LINES"); unsetenv("CLIFM_THUMBNAILS_DIR"); unsetenv("CLIFM_THUMBINFO_FILE"); if (conf.preview_max_size != UNSET) unsetenv("CLIFM_PREVIEW_MAX_SIZE"); if (flags & ALT_PREVIEW_FILE) unsetenv("CLIFM_ALT_PREVIEW_FILE"); } /* Calculate the available space for the fzf preview window based on * the main window width, terminal columns, and longest entry (including the * border type). * Return (size_t)-1 if the space is less than 50% of total space. */ static size_t get_preview_win_width(const int offset) { size_t w = 0; const size_t l = longest_prev_entry + 8 + (fzf_border_type <= 0 ? 0 /* fzf_border_type == 1 (right or left): this takes 2 extra columns. * fzf_border_type == 2 (rounded, sharp, bold, block, thinblock, * double, or vertical): this takes 4 extra columns. */ : (fzf_border_type == 1 ? 2 : 4)); const int total_win_width = term_cols - offset; if (l < (size_t)total_win_width) w = (size_t)total_win_width - l; if (w > (size_t)total_win_width / 2) return w; return (size_t)-1; } /* Change to the trash directory so that we can generate file previews. * Only for the 'u' and 't del' commands. */ static int cd_trashdir(const int prev) { #ifndef _NO_TRASH return (prev == 1 && (cur_comp_type == TCMP_UNTRASH || cur_comp_type == TCMP_TRASHDEL) && trash_files_dir && *trash_files_dir && trash_n > 0 && workspaces && cur_ws >= 0 && workspaces[cur_ws].path && xchdir(trash_files_dir, NO_TITLE) == 0); #else UNUSED(prev); return 0; #endif /* !_NO_TRASH */ } static void warn_fzf_error(void) { fprintf(stderr, _("%s: Fzf failed. Check the FzfTabOptions " "line by running 'cs edit'\n(some option may not " "be supported by your fzf version).\n"), PROGRAM_NAME); press_any_key_to_continue(0); if (term_caps.suggestions == 1) { MOVE_CURSOR_UP(3); ERASE_TO_RIGHT_AND_BELOW; MOVE_CURSOR_DOWN(1); } } static int run_finder(const size_t height, const int offset, const char *lw, const int multi) { int prev = (conf.fzf_preview > 0 && SHOW_PREVIEWS(cur_comp_type) == 1) ? FZF_INTERNAL_PREVIEWER : 0; const int restore_cwd = cd_trashdir(prev); const int prev_hidden = conf.fzf_preview == 2 ? 1 : 0; if (conf.fzf_preview == FZF_EXTERNAL_PREVIEWER) prev = FZF_EXTERNAL_PREVIEWER; /* Some shells, like xonsh (the only one to my knowledge), have problems * parsing the command constructed below. Let's force launch_execl() to * use "/bin/sh" to avoid this issue. */ char *shell_bk = user.shell; user.shell = (char *)NULL; char height_str[10 + MAX_INT_STR]; snprintf(height_str, sizeof(height_str), "--height=%zu", height); char cmd[(PATH_MAX * 2) + (NAME_MAX * 2)]; if (tabmode == FNF_TAB) { snprintf(cmd, sizeof(cmd), "fnf " "--read-null --pad=%d --query='%s' --reverse " "--tab-accepts --right-accepts --left-aborts " "--lines=%zu %s %s < %s > %s", offset, lw ? lw : "", height, conf.colorize == 0 ? "--no-color" : "", multi == 1 ? "--multi" : "", finder_in_file, finder_out_file); } else if (tabmode == SMENU_TAB) { snprintf(cmd, sizeof(cmd), "smenu %s " "-t -d -n%zu -limits l:%d -W$'\n' %s < %s > %s", smenutab_options_env ? smenutab_options_env : DEF_SMENU_OPTIONS, height, PATH_MAX, multi == 1 ? "-P$'\n'" : "", finder_in_file, finder_out_file); } else { /* FZF */ /* All fixed parameters are compatible with at least fzf 0.18.0 (Mar 31, 2019) */ char prev_opts[18 + MAX_INT_STR]; *prev_opts = '\0'; const char prev_str[] = "--preview \"clifm --preview {}\""; if (prev > 0) { /* Either internal of external previewer */ set_fzf_env_vars((int)height); const size_t s = get_preview_win_width(offset); if (s != (size_t)-1) snprintf(prev_opts, sizeof(prev_opts), "--preview-window=%zu", s); } snprintf(cmd, sizeof(cmd), "fzf %s %s " "%s --margin=0,0,0,%d " "%s --read0 --ansi " "--query='%s' %s %s %s %s %s " "< %s > %s", conf.fzftab_options, term_caps.unicode == 0 ? "--no-unicode" : "", *height_str ? height_str : "", offset, conf.case_sens_path_comp == 1 ? "+i" : "-i", lw ? lw : "", conf.colorize == 0 ? "--color=bw" : "", multi == 1 ? "--multi --bind tab:toggle+down,ctrl-s:select-all,\ ctrl-d:deselect-all,ctrl-t:toggle-all" : "", prev == FZF_INTERNAL_PREVIEWER ? prev_str : "", (prev == FZF_INTERNAL_PREVIEWER && prev_hidden == 1) ? "--preview-window=hidden --bind alt-p:toggle-preview" : "", *prev_opts ? prev_opts : "", finder_in_file, finder_out_file); /* Skim is a nice alternative, but it currently (0.10.4) fails * clearing the screen when --height is set, which makes it unusable * for us. The issue has been reported, but there was no response. * See https://github.com/lotabout/skim/issues/494 * As a workaround, run with --no-clear-start */ /* snprintf(cmd, sizeof(cmd), "sk %s " // skim "%s %s --margin=0,0,0,%d " "--read0 --ansi " "--query=\"%s\" %s %s %s %s %s " "< %s > %s", conf.fzftab_options, *height_str ? height_str : "", *height_str ? "--no-clear-start" : "", offset, lw ? lw : "", conf.colorize == 0 ? "--no-color" : "", multi == 1 ? "--multi --bind tab:toggle+down,ctrl-s:select-all,\ ctrl-d:deselect-all,ctrl-t:toggle-all" : "", prev == 1 ? prev_str : "", (prev == 1 && prev_hidden == 1) ? "--preview-window=hidden --bind alt-p:toggle-preview" : "", *prev_opts ? prev_opts : "", finder_in_file, finder_out_file); */ } const int dr = (flags & DELAYED_REFRESH) ? 1 : 0; flags &= ~DELAYED_REFRESH; const mode_t old_mask = umask(0077); /* flawfinder: ignore */ const int ret = launch_execl(cmd); umask(old_mask); /* flawfinder: ignore */ if (restore_cwd == 1) xchdir(workspaces[cur_ws].path, NO_TITLE); /* Restore the user's shell to its original value. */ user.shell = shell_bk; if (prev == FZF_INTERNAL_PREVIEWER) clear_fzf(); if (dr == 1) flags |= DELAYED_REFRESH; if (ret == 2 && tabmode == FZF_TAB) warn_fzf_error(); return ret; } /* Set FZF window's max height. No more than MAX HEIGHT entries will * be listed at once. */ static inline size_t set_fzf_max_win_height(void) { /* On some terminals, like lxterminal, urxvt, and vte, the number * of terminal lines is not properly detected when first running * the finder. So, let's update this value. */ static int first_run = 0; if (first_run == 0) { get_term_size(); first_run = 1; } return (size_t)(DEF_FZF_WIN_HEIGHT * term_lines / 100); } /* FILENAME is just a symlink name from the tags dir. * Let's get the target path. */ static char * get_tagged_file_target(char *filename) { if (!filename || !*filename) return (char *)NULL; char dir[PATH_MAX]; char *p = (char *)NULL; if (strchr(filename, '\\')) p = unescape_str(filename, 0); snprintf(dir, sizeof(dir), "%s/%s/%s", tags_dir, cur_tag, p ? p : filename); free(p); char *rpath = xrealpath(dir, NULL); char *s = rpath ? rpath : filename; int free_tmp = 0; char *q = home_tilde(s, &free_tmp); if (q && free_tmp == 1 && s == rpath) free(s); return q ? q : s; } static char * print_no_finder_file(void) { err('e', PRINT_PROMPT, "%s: %s: %s\n", PROGRAM_NAME, finder_out_file, strerror(errno)); return (char *)NULL; } /* If we are completing a path whose last component is a glob expression, * return the selected match for this expression (STR) preceded by * the initial portion of the path (everything before the glob expression): * INITIAL_PATH. We need to do this because, in case of PATH/GLOB, glob(3) * does not return the full path, but only the expanded glob expression * Ex (underscore is an asterisk): * downloads/_.pdf -> downloads/file.pdf * _.pdf -> file.pdf */ static char * get_glob_file_target(char *str, const char *initial_path) { if (!str || !*str) return (char *)NULL; if (*str == '/' || !initial_path) return str; const size_t len = strlen(initial_path) + strlen(str) + 1; char *p = xnmalloc(len, sizeof(char)); snprintf(p, len, "%s%s", initial_path, str); return p; } /* Recover finder (fzf/fnf/smenu) output from FINDER_OUT_FILE file. * Return this output (reformatted if needed) or NULL in case of error. * FINDER_OUT_FILE is removed immediately after use. */ static char * get_finder_output(const int multi, char *base) { int fd = 0; FILE *fp = open_fread(finder_out_file, &fd); if (!fp) { unlink(finder_out_file); return print_no_finder_file(); } char *buf = xnmalloc(1, sizeof(char)); *buf = '\0'; const char *initial_path = (cur_comp_type == TCMP_GLOB) ? base : (char *)NULL; char *line = (char *)NULL; size_t bsize = 0, line_size = 0; ssize_t line_len = 0; while ((line_len = getline(&line, &line_size, fp)) > 0) { if (line[line_len - 1] == '\n') { line_len--; line[line_len] = '\0'; } if (cur_comp_type == TCMP_FILE_TYPES_OPTS && *line && *(line + 1)) { *(line + 1) = '\0'; line_len = 1; } if (cur_comp_type == TCMP_CMD_DESC && *line) { char *p = strchr(line, ' '); if (p) { *p = '\0'; line_len = (ssize_t)strlen(line); } } char *q = line; if (multi == 1) { char *s = line; if ((flags & PREVIEWER) && workspaces[cur_ws].path) { char f[PATH_MAX]; snprintf(f, sizeof(f), "%s/%s", workspaces[cur_ws].path, s); select_file(f); continue; } else if (cur_comp_type == TCMP_GLOB) { s = get_glob_file_target(line, initial_path); } else if (cur_comp_type == TCMP_TAGS_F && tags_dir && cur_tag) { s = get_tagged_file_target(line); } else if (cur_comp_type == TCMP_BM_PREFIX) { const size_t len = strlen(line) + 3; s = xnmalloc(len, sizeof(char)); snprintf(s, len, "b:%s", line); } else if (cur_comp_type == TCMP_TAGS_T) { const size_t len = strlen(line) + 3; s = xnmalloc(len, sizeof(char)); snprintf(s, len, "t:%s", line); } q = escape_str(s); if (s != line) free(s); if (!q) continue; } /* We don't want to quote the initial tilde */ char *r = q; if (*r == '\\' && *(r + 1) == '~') r++; const size_t qlen = (r != line) ? strlen(r) : (size_t)line_len; bsize += qlen + 3; buf = xnrealloc(buf, bsize, sizeof(char)); xstrncat(buf, strlen(buf), r, bsize); if (multi == 1) { const size_t l = strlen(buf); buf[l] = ' '; buf[l + 1] = '\0'; free(q); } } free(line); unlinkat(fd, finder_out_file, 0); close(fd); if (*buf == '\0') { free(buf); buf = (char *)NULL; } return buf; } /* Return a normalized (absolute) path for the query string PREFIX. * E.g., "./b" -> /parent/dir * The partially typed basename, here 'b', is excluded, since it will be added * later using the list of matches passed to store_completions(). */ static char * normalize_prefix(char *prefix) { char *s = strrchr(prefix, '/'); if (s && s != prefix && s[1]) *s = '\0'; char *norm_prefix = normalize_path(prefix, strlen(prefix)); if (s) *s = '/'; return norm_prefix; } /* Store possible completions (MATCHES) in FINDER_IN_FILE to pass them to the * finder, either FZF or FNF. * Return the number of stored matches. */ static size_t store_completions(char **matches) { int fd = 0; FILE *fp = open_fwrite(finder_in_file, &fd); if (!fp) { err('e', PRINT_PROMPT, "%s: %s: %s\n", PROGRAM_NAME, finder_in_file, strerror(errno)); return (size_t)-1; } const enum comp_type ct = cur_comp_type; const int no_file_comp = (ct == TCMP_TAGS_S || ct == TCMP_TAGS_U || ct == TCMP_SORT || ct == TCMP_BOOKMARK || ct == TCMP_CSCHEME || ct == TCMP_NET || ct == TCMP_PROF || ct == TCMP_PROMPTS || ct == TCMP_BM_PREFIX || ct == TCMP_WS_PREFIX || ct == TCMP_WORKSPACES); /* We're not completing filenames. */ char *norm_prefix = (char *)NULL; /* "./_", "../_", and "_/.._" */ if (ct == TCMP_PATH && ((*matches[0] == '.' && (matches[0][1] == '/' || (matches[0][1] == '.' && matches[0][2] == '/'))) || strstr(matches[0], "/.."))) norm_prefix = normalize_prefix(matches[0]); size_t i; /* 'view' cmd with only one match: matches[0]. */ const size_t start = ((flags & PREVIEWER) && !matches[1]) ? 0 : 1; const int prev = (conf.fzf_preview > 0 && SHOW_PREVIEWS(ct) == 1); const char end_char = tabmode == SMENU_TAB ? '\n' : '\0'; longest_prev_entry = 0; #ifndef _NO_TRASH /* Change to the trash dir so we can correctly get trashed files color. */ if (conf.colorize == 1 && (ct == TCMP_TRASHDEL || ct == TCMP_UNTRASH) && trash_files_dir) xchdir(trash_files_dir, NO_TITLE); #endif /* _NO_TRASH */ for (i = start; matches[i]; i++) { if (!matches[i] || !*matches[i] || SELFORPARENT(matches[i])) continue; char *color = df_c, *entry = matches[i]; if (prev == 1) { const int get_base_name = ((ct == TCMP_PATH || ct == TCMP_GLOB) && !(flags & PREVIEWER)); char *p = get_base_name == 1 ? strrchr(entry, '/') : (char *)NULL; const size_t len = strlen((p && p[1]) ? p + 1 : entry); if (len > longest_prev_entry) longest_prev_entry = len; } if (ct == TCMP_BACKDIR) { color = di_c; } else if (ct == TCMP_TAGS_T || ct == TCMP_BM_PREFIX) { color = mi_c; if (entry[2]) entry += 2; } else if (ct == TCMP_TAGS_C) { color = mi_c; if (entry[1]) entry += 1; } else if (no_file_comp == 1) { color = mi_c; } else if (ct != TCMP_HIST && ct != TCMP_FILE_TYPES_OPTS && ct != TCMP_MIME_LIST && ct != TCMP_CMD_DESC) { char *cl = get_comp_entry_color(entry, norm_prefix); *tmp_color = '\0'; /* If color does not start with escape, then we have a color * for a file extension. In this case, we need to properly * construct the color code. */ if (cl && *cl != KEY_ESC) snprintf(tmp_color, sizeof(tmp_color), "\x1b[%sm", cl); color = *tmp_color ? tmp_color : (cl ? cl : ""); if (ct != TCMP_SEL && ct != TCMP_DESEL && ct != TCMP_BM_PATHS && ct != TCMP_DIRHIST && ct != TCMP_OPENWITH && ct != TCMP_JUMP && ct != TCMP_TAGS_F) { char *ptr = strrchr(entry, '/'); entry = (ptr && *(++ptr)) ? ptr : entry; } } if (*entry) fprintf(fp, "%s%s%s%c", color, entry, NC, end_char); } #ifndef _NO_TRASH /* We changed to the trash dir. Change back to the current dir. */ if (conf.colorize == 1 && (ct == TCMP_TRASHDEL || ct == TCMP_UNTRASH) && workspaces && workspaces[cur_ws].path) xchdir(workspaces[cur_ws].path, NO_TITLE); #endif /* _NO_TRASH */ fclose(fp); free(norm_prefix); return i; } static char * get_query_str(char *lw) { char *query = (char *)NULL; char *lb = rl_line_buffer; char *tmp = (char *)NULL; switch (cur_comp_type) { /* These completions take an empty query string */ case TCMP_RANGES: /* fallthrough */ case TCMP_SEL: /* fallthrough */ case TCMP_BM_PATHS: /* fallthrough */ case TCMP_GLOB: /* fallthrough */ case TCMP_CMD_DESC: /* fallthrough */ case TCMP_FILE_TYPES_OPTS: /* fallthrough */ case TCMP_FILE_TYPES_FILES: /* fallthrough */ case TCMP_MIME_LIST: /* fallthrough */ case TCMP_TAGS_F: break; case TCMP_TAGS_T: /* fallthrough */ case TCMP_WS_PREFIX: /* fallthrough */ case TCMP_BM_PREFIX: query = (lw && *lw && lw[1] && lw[2]) ? lw + 2 : (char *)NULL; break; case TCMP_FILE_TEMPLATES: /* fallthrough */ case TCMP_DESEL: tmp = lb ? strrchr(lb, cur_comp_type == TCMP_DESEL ? ' ' : '@') : (char *)NULL; query = (!tmp || !*(tmp++)) ? (char *)NULL : tmp; break; case TCMP_TAGS_C: query = (lw && *lw && lw[1]) ? lw + 1 : (char *)NULL; break; case TCMP_DIRHIST: if (lb && *lb && lb[1] && lb[2] && lb[3]) query = lb + 3; break; case TCMP_OWNERSHIP: tmp = lb ? strchr(lb, ':') : (char *)NULL; query = !tmp ? lb : ((*tmp && tmp[1]) ? tmp + 1 : (char *)NULL); break; case TCMP_HIST: if (lb && *lb == '/' && lb[1] == '*') { /* Search history */ query = lb + 1; } else { /* Commands history */ tmp = lb ? strrchr(lb, '!') : (char *)NULL; query = (!tmp || !*(tmp++)) ? (char *)NULL : tmp; } break; case TCMP_JUMP: if (lb && *lb == 'j' && lb[1] == ' ') { query = lb[2] ? lb + 2 : (char *)NULL; } else { tmp = lb ? strstr(lb, "j ") : (char *)NULL; query = (tmp && *tmp && tmp[1] && tmp[2]) ? tmp + 2 : (char *)NULL; } break; default: query = lw; break; } return query; } /* Return the number of characters that need to be quoted/escaped in the * string STR, whose length is LEN. */ static size_t count_quote_chars(const char *str, const size_t len) { size_t n = 0; int i = (int)len; while (--i >= 0) { if (is_quote_char(str[i])) n++; } return n; } /* Calculate the length of the matching prefix to insert into the line * buffer only the non-matched part of the string returned by the finder. */ static size_t calculate_prefix_len(const char *str, const char *query, const char *lw) { const enum comp_type ct = cur_comp_type; if (ct == TCMP_FILE_TYPES_OPTS || ct == TCMP_SEL || ct == TCMP_RANGES || ct == TCMP_TAGS_T || ct == TCMP_BM_PREFIX || ct == TCMP_HIST || ct == TCMP_JUMP || ct == TCMP_BM_PATHS || ct == TCMP_TAGS_F || ct == TCMP_GLOB || ct == TCMP_DIRHIST || ct == TCMP_FILE_TYPES_FILES || ct == TCMP_CMD_DESC) /* None of these completions produces a partial match (prefix) */ return 0; if (ct == TCMP_FILE_TEMPLATES) /* Insert the entire match (to honor case insensitive query) */ return 0; size_t prefix_len = 0; const size_t len = strlen(str); if (len == 0 || str[len - 1] == '/') { if (ct != TCMP_DESEL) return 0; } if (ct == TCMP_DESEL) return strlen(query ? query : (lw ? lw : "")); if (ct == TCMP_OWNERSHIP) { char *p = rl_line_buffer ? strchr(rl_line_buffer, ':') : (char *)NULL; if (p) return (*(++p) ? wc_xstrlen(p) : 0); return (rl_line_buffer ? wc_xstrlen(rl_line_buffer) : 0); } char *q = strrchr(str, '/'); if (q) { const size_t qlen = strlen(q); if (ct == TCMP_PATH) { /* Add backslashes to the length of the match: every quoted char * will be escaped later by write_completion(), so that backslashes * should be counted as well to get the right offset. */ prefix_len = qlen - 1 + count_quote_chars(q, qlen); } else { prefix_len = qlen + 1; } } else { /* We have just a name, no slash. */ if (ct == TCMP_PATH || ct == TCMP_WORKSPACES || ct == TCMP_CSCHEME || ct == TCMP_NET || ct == TCMP_PROMPTS || ct == TCMP_BOOKMARK) { prefix_len = len + count_quote_chars(str, len); } else if (ct == TCMP_TAGS_C) { prefix_len = len - 1; } else { prefix_len = len; } } return prefix_len; } /* Let's define whether we have a case which allows multi-selection * Returns 1 if true or zero if false. */ static int is_multi_sel(void) { const enum comp_type t = cur_comp_type; if (t == TCMP_SEL || t == TCMP_DESEL || t == TCMP_RANGES || t == TCMP_TRASHDEL || t == TCMP_UNTRASH || t == TCMP_TAGS_F || t == TCMP_TAGS_U || (flags & MULTI_SEL)) return 1; if (!rl_line_buffer) return 0; char *l = rl_line_buffer; char *lws = get_last_chr(rl_line_buffer, ' ', rl_point); /* Do not allow multi-sel if we have a path, only filenames */ if (t == TCMP_PATH && *l != '/' && (!lws || !strchr(lws, '/'))) { if ( /* Select */ (*l == 's' && (l[1] == ' ' || strncmp(l, "sel ", 4) == 0)) /* Trash */ || (*l == 't' && (l[1] == ' ' || strncmp(l, "trash ", 6) == 0)) /* ac and ad */ || (*l == 'a' && ((l[1] == 'c' || l[1] == 'd') && l[2] == ' ')) /* bb, bl, and br */ || (*l == 'b' && ((l[1] == 'b' || l[1] == 'l' || l[1] == 'r') && l[2] == ' ')) /* r */ || (*l == 'r' && l[1] == ' ') /* d/dup */ || (*l == 'd' && (l[1] == ' ' || strncmp(l, "dup ", 4) == 0)) /* Properties */ || (*l == 'p' && (l[1] == ' ' || strncmp (l, "prop ", 5) == 0)) /* te */ || (*l == 't' && l[1] == 'e' && l[2] == ' ') ) { return 1; } else { return 0; } } else { return 0; } } /* Clean the input buffer in case the user cancelled the completion pressing ESC. * If all possible completions share a common prefix, this prefix is * automatically appended to the query string. However, the user cancelled * here the completion (pressing ESC), so that we need to remove this prefix * by reinserting the original query string. */ static int clean_rl_buffer(const char *text) { if (!text || !*text) return FUNC_FAILURE; if (rl_point != rl_end) return FUNC_SUCCESS; const char *lb = rl_line_buffer; /* If the previous char is not space, then a common prefix was appended: * remove it. */ if ((rl_end > 0 && lb && lb[rl_end - 1] != ' ') || (rl_end >= 2 && lb && lb[rl_end - 2] == '\\')) { /* Find the last non-escaped space. */ int i = rl_end, sp = -1; while (--i >= 0) { if (lb[i] == ' ' && i > 0 && lb[i - 1] != '\\') { sp = i; break; } } if (sp != -1) { /* If found, remove the content of the input line starting * exactly one char after the last space. */ rl_delete_text(sp + 1, rl_end); rl_point = rl_end = sp + 1; } else { /* No space: delete the entire line. */ rl_delete_text(0, rl_end); rl_point = rl_end = 0; } ERASE_TO_RIGHT_AND_BELOW; } rl_insert_text(text); return FUNC_FAILURE; } /* Calculate the offset (left padding) of the finder's window based on * the cursor position, the current query string, and the completion type. */ static int get_finder_offset(const char *query, const char *text, char **matches, const char *lw, size_t *height, int *total_line_len) { const enum comp_type ct = cur_comp_type; char *lb = rl_line_buffer; int finder_offset = 0; /* We don't want to place the finder's window too much to the right, * making its contents unreadable: let's make sure we have at least * 20 chars (40 if previews are enabled) for the finder's window. */ const int fspace = (tabmode == FZF_TAB && conf.fzf_preview == 1 && SHOW_PREVIEWS(ct) == 1) ? 40 : 20; /* If showing previews, let's reserve at least a quarter of the * terminal height. */ const int min_prev_height = term_lines / 4; if (fspace == 40 && (int)*height < min_prev_height && min_prev_height > 0 && fzf_height_value == 0) /* fspace == 40: We're previewing files. */ *height = (size_t)min_prev_height; const int max_finder_offset = term_cols > fspace ? term_cols - fspace : 0; int diff = 0; if (rl_end > rl_point) diff = (int)wc_xstrlen(lb + rl_point); const int cur_line_len = lb ? (int)wc_xstrlen(lb) - diff : 0; *total_line_len = cur_line_len + prompt_offset; int last_line_len = cur_line_len; while (last_line_len > term_cols) last_line_len -= term_cols; finder_offset = last_line_len + prompt_offset < max_finder_offset ? (last_line_len + prompt_offset - 4) : 0; /* PROMPT_OFFSET (the space used by the prompt in the current line) * is calculated the first time we print the prompt (in my_rl_getc() * (readline.c)). */ if (text && conf.fuzzy_match == 1 && ct != TCMP_TAGS_F && ct != TCMP_DIRHIST) { /* TEXT is not NULL whenever a common prefix was added, replacing * the original query string. */ const size_t bslashes = count_chars(text, '\\'); finder_offset -= (int)(wc_xstrlen(matches[0]) - wc_xstrlen(text) + bslashes); } if (!lw) { finder_offset++; } else { const size_t lw_len = wc_xstrlen(lw); if (lw_len > 1) { finder_offset -= (int)(lw_len - 1); if (finder_offset < 0) finder_offset = 0; } } if (ct == TCMP_OWNERSHIP && query) { if (lb && query == lb) finder_offset = (int)wc_xstrlen(lb) - 3; else finder_offset = lb ? (int)(query - lb) : 0; } else if ((ct == TCMP_DESEL || ct == TCMP_FILE_TEMPLATES) && query) { finder_offset = prompt_offset + (int)(query - lb) - 3; if (!*query && finder_offset > 0) finder_offset--; } else if (ct == TCMP_HIST) { if (lb && *lb == '/' && lb[1] == '*') { /* Search history */ finder_offset = 1 + prompt_offset - ((query && *query) ? 3 : 4); } else { /* Commands history */ const char *sp = lb ? get_last_chr(lb, '!', rl_point) : NULL; finder_offset = prompt_offset + (sp ? (int)(sp - lb) - ((query && *query) ? 2 : 3) : -1); } } else if (ct == TCMP_JUMP) { if (query) { if (lb && *lb == 'j' && lb[1] == ' ') { /* The command is "j" */ finder_offset = prompt_offset - 1; } else { /* The command is "jump" */ finder_offset = prompt_offset + 2; } } else { finder_offset = prompt_offset + ((lb && *lb) ? (lb[1] == ' ' ? -2 : 1) : -2); } } else if (ct == TCMP_TAGS_F) { if (rl_end > 0 && lb && *lb == 't' && lb[1] == 'u' && lb[rl_end - 1] == ' ') { /* Coming from untag ('tu :TAG ') */ finder_offset++; } else { /* Coming from tag expression ('t:FULL_TAG') */ const char *sp = lb ? get_last_chr(lb, ' ', rl_point) : NULL; finder_offset = prompt_offset + (sp ? (int)(sp - lb): -1); } } else if (ct == TCMP_DIRHIST) { finder_offset = prompt_offset; } else if (ct == TCMP_FILE_TYPES_OPTS || ct == TCMP_MIME_LIST) { finder_offset++; } else if (ct == TCMP_FILE_TYPES_FILES) { const char *sp = lb ? get_last_chr(lb, ' ', rl_point) : NULL; if (sp) /* Expression is second or more word: "text =FILE_TYPE" */ finder_offset = prompt_offset + (int)(sp - lb) - 1; else /* Expression is first word: "=FILE_TYPE" */ finder_offset = prompt_offset - 2; } else if (ct == TCMP_SEL || ct == TCMP_RANGES) { const char *sp = lb ? get_last_chr(lb, ' ', rl_point) : NULL; finder_offset = prompt_offset + (sp ? (int)(sp - lb) - 2 : -(rl_end + 1)); } else if (ct == TCMP_BM_PATHS) { const char *sp = lb ? get_last_chr(lb, ' ', rl_point) : NULL; finder_offset = prompt_offset + (sp ? (int)(sp - lb) - 2 : -3); } else if (ct == TCMP_TAGS_C) { const char *sp = lb ? strrchr(lb, ' ') : NULL; finder_offset = prompt_offset + (sp ? (int)(sp - lb) - 1 : 0); } else if (ct == TCMP_BM_PREFIX || ct == TCMP_TAGS_T) { const char *sp = lb ? get_last_chr(lb, ' ', rl_point) : NULL; finder_offset = prompt_offset + (sp ? (int)(sp - lb): -1); } else if (ct == TCMP_GLOB) { const char *sl = lb ? get_last_chr(lb, '/', rl_point) : NULL; const char *sp = lb ? get_last_chr(lb, ' ', rl_point) : NULL; if (!sl) { if (sp) finder_offset = prompt_offset + (int)(sp - lb) - 2; else /* Neither space nor slash == first word */ finder_offset = prompt_offset - 3; } else { if (sp && sp > sl) finder_offset = prompt_offset + (int)(sp - lb) - 2; else finder_offset = prompt_offset + (int)(sl - lb) - 2; } } if ((!query || !*query) && ct != TCMP_RANGES && ct != TCMP_SEL && ct != TCMP_BM_PATHS && ct != TCMP_BM_PREFIX && ct != TCMP_GLOB && ct != TCMP_CMD_DESC && ct != TCMP_FILE_TYPES_OPTS && ct != TCMP_FILE_TYPES_FILES && ct != TCMP_MIME_LIST && ct != TCMP_TAGS_F && ct != TCMP_TAGS_T && ct != TCMP_TAGS_C && ct != TCMP_DIRHIST && ct != TCMP_WS_PREFIX) finder_offset++; /* Last char is space */ while (finder_offset > term_cols) finder_offset -= term_cols; if (finder_offset > max_finder_offset || finder_offset < 0) finder_offset = 0; if (finder_offset == 0) { /* Not enough space to align the window with the last word. Let's * try to align it with the prompt. If not enough space either, send * the window to the leftmost side of the screen. */ finder_offset = prompt_offset >= 3 ? prompt_offset - 3 : prompt_offset; if (finder_offset > max_finder_offset) finder_offset = 0; } return finder_offset; } /* Depending on the completion type, either the typed text (input buffer), or * the text to be inserted, needs to be modified. Let's do this here. */ static void do_some_cleanup(char **buf, char **matches, const char *query, size_t *prefix_len) { const enum comp_type ct = cur_comp_type; char *lb = rl_line_buffer; /* TCMP_HIST may be either search or command history */ const int cmd_hist = (ct == TCMP_HIST && rl_line_buffer && (*lb != '/' || lb[1] != '*')); if (rl_point < rl_end && ct != TCMP_PATH && ct != TCMP_CMD) { const char *s = lb ? get_last_chr(lb, ' ', rl_point) : (char *)NULL; const int start = s ? (int)(s - lb + 1) : 0; rl_delete_text(start, rl_point); rl_point = start; } else if (ct == TCMP_OPENWITH && strchr(*buf, ' ')) { /* We have multiple words ("CMD ARG..."): quote the string. */ const size_t len = strlen(*buf) + 3; char *tmp = xnmalloc(len, sizeof(char)); snprintf(tmp, len, "\"%s\"", *buf); free(*buf); *buf = tmp; } else if (ct == TCMP_HIST && cmd_hist == 0) { rl_delete_text(0, rl_end); rl_point = rl_end = 0; } else if (ct == TCMP_JUMP) { if (*lb == 'j' && lb[1] == ' ' && lb[2]) { rl_delete_text(2, rl_end); rl_point = rl_end = 2; } else { const char *tmp = strstr(lb, "j "); if (tmp && tmp[1] && tmp[2]) { rl_point = (int)(tmp - lb + 2); rl_delete_text(rl_point, rl_end); rl_end = rl_point; } } } else if (cmd_hist == 1 || ct == TCMP_RANGES || ct == TCMP_SEL || ct == TCMP_TAGS_F || ct == TCMP_GLOB || ct == TCMP_BM_PATHS || ct == TCMP_BM_PREFIX || ct == TCMP_TAGS_T || ct == TCMP_DIRHIST) { const char *s = lb ? get_last_chr(lb, (ct == TCMP_GLOB && words_num == 1) ? '/' : ' ', rl_end) : (char *)NULL; if (s) { rl_point = (int)(s - lb + 1); rl_delete_text(rl_point, rl_end); rl_end = rl_point; } else if (cmd_hist == 1 || ct == TCMP_BM_PATHS || ct == TCMP_TAGS_F || ct == TCMP_BM_PREFIX || ct == TCMP_TAGS_T || ct == TCMP_SEL || ct == TCMP_DIRHIST || ct == TCMP_GLOB) { rl_delete_text(0, rl_end); rl_end = rl_point = 0; } } else if (ct == TCMP_FILE_TYPES_FILES || ct == TCMP_CMD_DESC || ct == TCMP_FILE_TEMPLATES) { const char *s = lb ? get_last_chr(lb, ct == TCMP_FILE_TEMPLATES ? '@' : ' ', rl_end) : (char *)NULL; rl_point = !s ? 0 : (int)(s - lb + 1); rl_delete_text(rl_point, rl_end); rl_end = rl_point; ERASE_TO_RIGHT; fflush(stdout); } else if (ct == TCMP_USERS) { const size_t l = strlen(*buf); char *p = savestring(*buf, l); *buf = xnrealloc(*buf, (l + 2), sizeof(char)); snprintf(*buf, l + 2, "~%s", p); free(p); } else { /* Honor case insensitive completion/fuzzy matches. */ if ((conf.case_sens_path_comp == 0 || conf.fuzzy_match == 1) && query && strncmp(matches[0], *buf, *prefix_len) != 0) { const int bk = rl_point; rl_delete_text(bk - (int)*prefix_len, rl_end); rl_point = rl_end = bk - (int)*prefix_len; *prefix_len = 0; } } } static int do_completion(char *buf, const size_t prefix_len, const int multi) { /* Some further buffer clean up: remove new line char and ending spaces. */ const size_t blen = strlen(buf); int j = (int)blen; if (j > 0 && buf[j - 1] == '\n') { j--; buf[j] = '\0'; } while (--j >= 0 && buf[j] == ' ') buf[j] = '\0'; char *p = (char *)NULL; if (cur_comp_type != TCMP_OPENWITH && cur_comp_type != TCMP_PATH && cur_comp_type != TCMP_HIST && !multi) { p = escape_str(buf); if (!p) return FUNC_FAILURE; } else { p = savestring(buf, blen); } write_completion(p, prefix_len, multi); free(p); return FUNC_SUCCESS; } /* Calculate currently used lines to go back to the correct cursor * position after quitting the finder. */ static void move_cursor_up(const int total_line_len) { int lines = 1; if (total_line_len > term_cols && term_cols > 0) { lines = total_line_len / term_cols; const int rem = (int)total_line_len % term_cols; if (rem > 0) lines++; } MOVE_CURSOR_UP(lines); } /* Determine input and output files to be used by the fuzzy finder (either * fzf or fnf). * Let's do this even if fzftab is not enabled at startup, because this feature * can be enabled in place by editing the config file. * * NOTE: Why do the random file extensions have different lengths? If * compiled in POSIX mode, gen_rand_ext() uses srandom(3) and random(3) to * generate the string, but since both extensions are generated at the same * time, they happen to be the same, resulting in both filenames being * identical. As a workaround, we use different lengths for both extensions. * * These files are created immediately after this function returns by * store_completions() with permissions 600 (in a directory to which only the * current user has read/write access). These files are then immediately read * by the finder application, and deleted as soon as this latter returns. */ static void set_finder_paths(void) { const int sm = (xargs.stealth_mode == 1); const char *p = sm ? P_tmpdir : tmp_dir; char *rand_ext = gen_rand_str(RAND_SUFFIX_LEN + (sm ? 6 : 0)); snprintf(finder_in_file, sizeof(finder_in_file), "%s/.temp%s", p, rand_ext ? rand_ext : "a3_2yu!d43"); free(rand_ext); rand_ext = gen_rand_str(RAND_SUFFIX_LEN + (sm ? 10 : 4)); snprintf(finder_out_file, sizeof(finder_out_file), "%s/.temp%s", p, rand_ext ? rand_ext : "0rNkds7++@"); free(rand_ext); } /* Display possible completions using the corresponding finder. If one of these * possible completions is selected, insert it into the current line buffer. * * What is ORIGINAL_QUERY and why do we need it? * MATCHES[0] is supposed to hold the common prefix among all possible * completions. This common prefix should be the same as the query string when * performing regular matches. But it might not be the same as the * original query string when performing fuzzy match: then, we need a copy of * this original query string (ORIGINAL_QUERY) to later be passed to FZF. * Example: * Query string: '.f' * Returned matches (fuzzy): * .file * .this_file * .beef * Common preffix: '.' (not '.f') * */ static int finder_tabcomp(char **matches, const char *text, char *original_query) { /* Set random filenames for both FINDER_IN_FILE and FINDER_OUT_FILE. */ set_finder_paths(); /* Store possible completions in FINDER_IN_FILE to pass them to the finder. */ const size_t num_matches = store_completions(matches); if (num_matches == (size_t)-1) return FUNC_FAILURE; /* Set a pointer to the last word in the query string. We use this to * highlight the matching prefix in the list of matches. */ char *lw = get_last_word(original_query ? original_query : matches[0], original_query ? 1 : 0); char *query = get_query_str(lw); /* If not already defined (environment or config file), calculate the * height of the finder's window based on the number of entries. This * specifies how many entries will be displayed at once. */ size_t height = 0; if (fzf_height_value > 0) { /* Height was set either in FZF_DEFAULT_OPTS or in the color scheme * file. Let's respect this value. */ height = (size_t)fzf_height_value; } else { const size_t max_height = set_fzf_max_win_height(); height = (num_matches + 1 > max_height) ? max_height : num_matches; } int total_line_len = 0; int finder_offset = get_finder_offset(query, text, matches, lw, &height, &total_line_len); /* Tab completion cases allowing multi-selection. */ int multi = is_multi_sel(); char *q = query; if (flags & PREVIEWER) { height = term_lines; finder_offset = 0; multi = 1; q = (char *)NULL; } char *deq = q ? (strchr(q, '\\') ? unescape_str(q, 0) : q) : (char *)NULL; /* Run the finder application and store the ouput in FINDER_OUT_FILE. */ const int ret = run_finder(height, finder_offset, deq, multi); if (deq && deq != q) free(deq); unlink(finder_in_file); if (!(flags & PREVIEWER)) move_cursor_up(total_line_len); /* No results (the user pressed ESC or the Left arrow key). */ if (ret != FUNC_SUCCESS) { unlink(finder_out_file); return clean_rl_buffer(text); } /* Retrieve finder's output from FINDER_OUT_FILE. */ char *buf = get_finder_output(multi, matches[0]); if (!buf) return FUNC_FAILURE; /* Calculate the length of the matching prefix to insert into the * line buffer only the non-matched part of the string returned by the * finder. */ size_t prefix_len = calculate_prefix_len(matches[0], query, lw); do_some_cleanup(&buf, matches, query, &prefix_len); /* Let's insert the selected match(es): BUF. */ if (buf && *buf && do_completion(buf, prefix_len, multi) == FUNC_FAILURE) { free(buf); return FUNC_FAILURE; } free(buf); #ifndef _NO_SUGGESTIONS if (conf.suggestions && words_num == 1 && wrong_cmd == 1) { fputs(NC, stdout); fflush(stdout); rl_restore_prompt(); wrong_cmd = 0; } #endif /* !_NO_SUGGESTIONS */ return FUNC_SUCCESS; } #endif /* !_NO_FZF */ static char * gen_quoted_str(const char *str) { struct stat a; if (conf.quoting_style == QUOTING_STYLE_BACKSLASH || cur_comp_type != TCMP_ELN || (stat(str, &a) != -1 && S_ISDIR(a.st_mode))) return escape_str(str); return quote_str(str); } /* Complete the word at or before point. WHAT_TO_DO says what to do with the completion. `?' means list the possible completions. TAB means do standard completion. `*' means insert all of the possible completions. `!' means to do standard completion, and list all possible completions if there is more than one. */ int tab_complete(const int what_to_do) { if (rl_notab == 1) return FUNC_SUCCESS; if (*rl_line_buffer == '#' || cur_color == hc_c) { /* No completion at all if comment */ #ifndef _NO_SUGGESTIONS if (suggestion.printed) clear_suggestion(CS_FREEBUF); #endif /* _NO_SUGGESTIONS */ return FUNC_SUCCESS; } rl_compentry_func_t *our_func = rl_completion_entry_function; /* Only the completion entry function can change these. */ rl_filename_completion_desired = 0; rl_filename_quoting_desired = 1; rl_sort_completion_matches = 1; int end = rl_point, delimiter = 0; char quote_char = '\0'; /* We now look backwards for the start of a filename/variable word. */ if (rl_point) { int scan = 0; if (rl_completer_quote_characters) { /* We have a list of characters which can be used in pairs to * quote substrings for the completer. Try to find the start * of an unclosed quoted substring. */ /* FOUND_QUOTE is set so we know what kind of quotes we found. */ int pass_next; //found_quote = 0; for (scan = pass_next = 0; scan < end; scan++) { if (pass_next) { pass_next = 0; continue; } if (rl_line_buffer[scan] == '\\') { pass_next = 1; continue; } if (quote_char != '\0') { /* Ignore everything until the matching close quote char. */ if (rl_line_buffer[scan] == quote_char) { /* Found matching close. Abandon this substring. */ quote_char = '\0'; rl_point = end; } } else if (strchr(rl_completer_quote_characters, rl_line_buffer[scan])) { /* Found start of a quoted substring. */ quote_char = rl_line_buffer[scan]; rl_point = scan + 1; } } } if (rl_point == end && quote_char == '\0') { /* We didn't find an unclosed quoted substring upon which to do * completion, so use the word break characters to find the * substring on which to complete. */ while (--rl_point) { scan = (int)rl_line_buffer[rl_point]; if (strchr(rl_completer_word_break_characters, scan) == 0 || (scan == ' ' && rl_point && rl_line_buffer[rl_point - 1] == '\\')) continue; /* Convoluted code, but it avoids an n^2 algorithm with * calls to char_is_quoted. */ break; } } /* If we are at an unquoted word break, then advance past it. */ scan = (int)rl_line_buffer[rl_point]; if (strchr(rl_completer_word_break_characters, scan)) { /* If the character that caused the word break was a quoting * character, then remember it as the delimiter. */ if (strchr("\"'", scan) && (end - rl_point) > 1) delimiter = scan; /* If the character isn't needed to determine something special * about what kind of completion to perform, then advance past it. */ if (!rl_special_prefixes || strchr(rl_special_prefixes, scan) == 0) rl_point++; } } int directory_changed = 0; int start = rl_point; rl_point = end; char *text = rl_copy_text(start, end); char **matches = (char **)NULL; /* At this point, we know we have an open quote if quote_char != '\0'. */ /* If the user wants to TRY to complete, but then wants to give * up and use the default completion function, they set the * variable rl_attempted_completion_function. */ if (rl_attempted_completion_function) { matches = (*rl_attempted_completion_function) (text, start, end); if (matches || rl_attempted_completion_over) { rl_attempted_completion_over = 0; our_func = (rl_compentry_func_t *)NULL; goto AFTER_USUAL_COMPLETION; } } matches = rl_completion_matches(text, our_func); AFTER_USUAL_COMPLETION: if (!matches || !matches[0]) { rl_ring_bell(); free(text); return FUNC_FAILURE; } #ifndef _NO_FZF /* Common prefix for multiple matches is appended to the input query. * Let's rise a flag to know if we should reinsert the original query * in case the user cancels the completion (pressing ESC). */ const int common_prefix_added = (fzftab == 1 && matches[1] && strcmp(matches[0], text) != 0); // (fzftab == 1 && matches[1] && strlen(matches[0]) > strlen(text)); #endif /* _NO_FZF */ size_t i; int should_quote; /* It seems to me that in all the cases we handle we would like * to ignore duplicate possiblilities. Scan for the text to * insert being identical to the other completions. */ if (rl_ignore_completion_duplicates == 1) { char *lowest_common; size_t j; size_t newlen = 0; char dead_slot; char **temp_array; if (cur_comp_type == TCMP_HIST) { /* Sort the array without matches[0]: we need it to stay in * place no matter what. */ for (i = 0; matches[i]; i++); if (i > 0) qsort(matches + 1, i - 1, sizeof(char *), (QSFUNC *)compare_strings); } /* Remember the lowest common denominator: it may be unique. */ lowest_common = savestring(matches[0], strlen(matches[0])); for (i = 0; matches[i + 1]; i++) { if (strcmp(matches[i], matches[i + 1]) == 0) { free(matches[i]); matches[i] = &dead_slot; } else { newlen++; } } /* We have marked all the dead slots with (char *)&dead_slot * Copy all the non-dead entries into a new array. */ temp_array = xnmalloc(3 + newlen, sizeof (char *)); for (i = j = 1; matches[i]; i++) { if (matches[i] != &dead_slot) { temp_array[j] = matches[i]; j++; } } temp_array[j] = (char *)NULL; if (matches[0] != &dead_slot) free(matches[0]); free(matches); matches = temp_array; /* Place the lowest common denominator back in [0]. */ matches[0] = lowest_common; /* If there is one string left, and it is identical to the lowest * common denominator (LCD), then the LCD is the string to insert. */ if (j == 2 && strcmp(matches[0], matches[1]) == 0) { free(matches[1]); matches[1] = (char *)NULL; } } int len = 0, count = 0, limit = 0, max = 0; switch (what_to_do) { case '!': /* If we are matching filenames, then here is our chance to * do clever processing by re-examining the list. Call the * ignore function with the array as a parameter. It can * munge the array, deleting matches as it desires. */ if (rl_ignore_some_completions_function && our_func == rl_completion_entry_function) { (void)(*rl_ignore_some_completions_function)(matches); if (matches == 0 || matches[0] == 0) { free(matches); free(text); rl_ding(); return 0; } } /* If we are doing completion on quoted substrings, and any matches * contain any of the completer_word_break_characters, then * automatically prepend the substring with a quote character * (just pick the first one from the list of such) if it does not * already begin with a quote string. FIXME: Need to remove any such * automatically inserted quote character when it no longer is necessary, * such as if we change the string we are completing on and the new * set of matches don't require a quoted substring. */ char *replacement = matches[0]; should_quote = matches[0] && rl_completer_quote_characters && rl_filename_completion_desired && rl_filename_quoting_desired; ////////// /* WORKAROUND: If 'ds' and the replacement string needs to be * quoted, the completion does not work as expected. */ if (cur_comp_type == TCMP_DESEL && matches[0] && rl_strpbrk(matches[0], quote_chars)) replacement = NULL; ////////// if (should_quote) should_quote = (should_quote && !quote_char); if (should_quote) { int do_replace = NO_MATCH; /* If there is a single match, see if we need to quote it. This also checks whether the common prefix of several matches needs to be quoted. If the common prefix should not be checked, add !matches[1] to the if clause. */ should_quote = (rl_strpbrk(matches[0], quote_chars) != 0); if (should_quote) do_replace = matches[1] ? MULT_MATCH : SINGLE_MATCH; if (do_replace != NO_MATCH) { /* Found an embedded word break character in a potential match, so we need to prepend a quote character if we are replacing the completion string. */ replacement = gen_quoted_str(matches[0]); } } /* Handle replacement string */ if (replacement && (cur_comp_type != TCMP_HIST || !matches[1]) && cur_comp_type != TCMP_FILE_TYPES_OPTS && cur_comp_type != TCMP_MIME_LIST && (cur_comp_type != TCMP_FILE_TEMPLATES || !matches[1]) && (cur_comp_type != TCMP_FILE_TYPES_FILES || !matches[1]) && (cur_comp_type != TCMP_GLOB || !matches[1]) && cur_comp_type != TCMP_JUMP && cur_comp_type != TCMP_RANGES && cur_comp_type != TCMP_SEL && cur_comp_type != TCMP_CMD_DESC && cur_comp_type != TCMP_OWNERSHIP && cur_comp_type != TCMP_DIRHIST && (cur_comp_type != TCMP_WS_PREFIX || !matches[1]) && (cur_comp_type != TCMP_BM_PATHS || !matches[1]) && (cur_comp_type != TCMP_TAGS_F || !matches[1])) { enum comp_type c = cur_comp_type; if ((c == TCMP_DESEL || c == TCMP_NET || c == TCMP_BM_PATHS || c == TCMP_PROF || c == TCMP_FILE_TEMPLATES || c == TCMP_TAGS_C || c == TCMP_TAGS_S || c == TCMP_TAGS_T || c == TCMP_TAGS_U || c == TCMP_BOOKMARK || c == TCMP_GLOB || c == TCMP_PROMPTS || c == TCMP_CSCHEME || c == TCMP_WORKSPACES || c == TCMP_BM_PREFIX) && !strchr(replacement, '\\')) { char *r = escape_str(replacement); if (!r) { if (replacement != matches[0]) free(replacement); break; } if (replacement != matches[0]) free(replacement); replacement = r; } /* Let's keep the backslash, used to bypass alias names. */ if (c == TCMP_CMD && text && *text == '\\' && *(text + 1)) start++; else if (c == TCMP_WS_PREFIX) start += 2; else if (c == TCMP_FILE_TEMPLATES) { char *p = strrchr(text, '@'); if (p && p[1]) start = rl_point - (int)strlen(p + 1); } rl_begin_undo_group(); rl_delete_text(start, rl_point); rl_point = start; #ifndef _NO_HIGHLIGHT if (conf.highlight && !wrong_cmd) { size_t k, l = 0; size_t _start = (*replacement == '\\' && *(replacement + 1) == '~') ? 1 : 0; char *cc = cur_color; HIDE_CURSOR; fputs(tx_c, stdout); char t[PATH_MAX]; for (k = _start; replacement[k]; k++) { rl_highlight(replacement, k, SET_COLOR); if ((signed char)replacement[k] < 0) { t[l] = replacement[k]; l++; if ((signed char)replacement[k + 1] >= 0) { t[l] = '\0'; l = 0; rl_insert_text(t); rl_redisplay(); } continue; } t[0] = replacement[k]; t[1] = '\0'; rl_insert_text(t); /* WORKAROUND: If we are not at the end of the line, * redisplay only up to the cursor position, to prevent * whatever is after it from being printed using the * last printed color. * Drawback: there will be no color after the cursor * position (no color however is better than a wrong color). */ if (!replacement[k + 1] && rl_point < rl_end && cur_color != tx_c) { int _end = rl_end; rl_end = rl_point; rl_redisplay(); rl_end = _end; fputs(tx_c, stdout); fflush(stdout); } rl_redisplay(); if (cur_color == hv_c || cur_color == hq_c || cur_color == hp_c) { fputs(cur_color, stdout); fflush(stdout); } } UNHIDE_CURSOR; cur_color = cc; if (cur_color) fputs(cur_color, stdout); } else { char *q = (*replacement == '\\' && *(replacement + 1) == '~') ? replacement + 1 : replacement; rl_insert_text(q); rl_redisplay(); } #else char *q = (*replacement == '\\' && *(replacement + 1) == '~') ? replacement + 1 : replacement; rl_insert_text(q); rl_redisplay(); #endif /* !_NO_HIGHLIGHT */ rl_end_undo_group(); } if (replacement != matches[0]) free(replacement); /* If there are more matches, ring the bell to indicate. If this was * the only match, and we are hacking files, check the file to see if * it was a directory. If so, add a '/' to the name. If not, and we * are at the end of the line, then add a space. */ if (matches[1]) { if (what_to_do == '!') { goto DISPLAY_MATCHES; } else { if (rl_editing_mode != 0) /* vi_mode */ rl_ding(); /* There are other matches remaining. */ } } else { /* Just one match */ if (cur_comp_type == TCMP_TAGS_T || cur_comp_type == TCMP_BOOKMARK || cur_comp_type == TCMP_PROMPTS || cur_comp_type == TCMP_NET || cur_comp_type == TCMP_CSCHEME || cur_comp_type == TCMP_WORKSPACES || cur_comp_type == TCMP_HIST || cur_comp_type == TCMP_BACKDIR || cur_comp_type == TCMP_PROF || cur_comp_type == TCMP_BM_PREFIX) break; /* Let's append an ending character to the inserted match. */ if (cur_comp_type == TCMP_OWNERSHIP) { char *sc = rl_line_buffer ? strchr(rl_line_buffer, ':') : (char *)NULL; size_t l = wc_xstrlen(sc ? sc + 1 : (rl_line_buffer ? rl_line_buffer : "")); rl_insert_text(matches[0] + l); if (!sc) rl_stuff_char(':'); break; } char temp_string[4]; int temp_string_index = 0; if (quote_char) { temp_string[temp_string_index] = quote_char; temp_string_index++; } temp_string[temp_string_index] = (char)(delimiter ? delimiter : ' '); temp_string_index++; temp_string[temp_string_index] = '\0'; if (rl_filename_completion_desired) { struct stat finfo; char *filename = matches[0] ? normalize_path(matches[0], strlen(matches[0])) : (char *)NULL; char *d = filename; if (filename && *filename == 'f' && filename[1] == 'i') { size_t flen = strlen(filename); if (IS_FILE_URI(filename, flen)) d = filename + FILE_URI_PREFIX_LEN; } if (d && stat(d, &finfo) == 0 && S_ISDIR(finfo.st_mode)) { if (rl_line_buffer[rl_point] != '/') { #ifndef _NO_HIGHLIGHT if (conf.highlight && !wrong_cmd) { char *cc = cur_color; fputs(hd_c, stdout); rl_insert_text("/"); /* WORKAROUND: If we are not at the end of the line, * redisplay only up to the cursor position, to prevent * whatever is after it from being printed using the * last printed color. * Drawback: there will be no color after the cursor * position (no color however is better than a wrong color). */ if (rl_point < rl_end) { int _end = rl_end; rl_end = rl_point; fputs(tx_c, stdout); fflush(stdout); rl_redisplay(); rl_end = _end; } else { rl_redisplay(); } fputs(rl_point < rl_end ? tx_c : (cc ? cc : ""), stdout); } else { rl_insert_text("/"); } #else rl_insert_text("/"); #endif /* !_NO_HIGHLIGHT */ } } else { if (rl_point == rl_end) rl_insert_text(temp_string); } free(filename); } else { if (rl_point == rl_end) rl_insert_text(temp_string); } } break; case '?': { int j = 0, k = 0, l = 0; if (flags & PREVIEWER) goto CALC_OFFSET; /* Handle simple case first. Just one match. */ if (!matches[1]) { char *temp; temp = printable_part(matches[0]); rl_crlf(); print_filename(temp, matches[0]); rl_crlf(); goto RESTART; } /* There is more than one match. Find out how many there are, and * find out what the maximum printed length of a single entry is. */ DISPLAY_MATCHES: #ifndef _NO_FZF if (fzftab != 1) #endif /* !_NO_FZF */ { max = 0; for (i = 1; matches[i]; i++) { char *temp; size_t name_length; temp = printable_part(matches[i]); name_length = wc_xstrlen(temp); if ((int)name_length > max) max = (int)name_length; } len = (int)i - 1; /* If there are multiple items, ask the user if they really * wants to see them all. */ if (len >= rl_completion_query_items) { putchar('\n'); #ifndef _NO_HIGHLIGHT if (conf.highlight && cur_color != tx_c && !wrong_cmd) { cur_color = tx_c; fputs(tx_c, stdout); } #endif /* !_NO_HIGHLIGHT */ fprintf(rl_outstream, "Display all %d possibilities? " "[y/n] ", len); fflush(rl_outstream); if (!get_y_or_n()) goto RESTART; } /* How many items of MAX length can we fit in the screen window? */ max += 2; limit = term_cols / max; if (limit != 1 && (limit * max == term_cols)) limit--; if (limit <= 0) limit = 1; /* How many iterations of the printing loop? */ count = (len + (limit - 1)) / limit; } putchar('\n'); #ifndef _NO_HIGHLIGHT if (conf.highlight && cur_color != tx_c && !wrong_cmd) { cur_color = tx_c; fputs(tx_c, stdout); } #endif /* !_NO_HIGHLIGHT */ if (cur_comp_type != TCMP_PATH && cur_comp_type != TCMP_GLOB) goto CALC_OFFSET; /* If /path/to/dir/ or /path/to/dir/GLOB, let's temporarily * change to /path/to/dir, so that the finder knows where we are. */ if (*matches[0] == '~') { char *exp_path = tilde_expand(matches[0]); if (exp_path) { xchdir(exp_path, NO_TITLE); free(exp_path); directory_changed = 1; } } else { char *dir = matches[0]; size_t dir_len = strlen(dir); if (IS_FILE_URI(dir, dir_len)) dir += FILE_URI_PREFIX_LEN; char *last_slash = strrchr(dir, '/'); if (!last_slash) goto CALC_OFFSET; char *norm_dir = (char *)NULL; /* MATCHES[0] SHOULD BE DIR!! */ if (strstr(matches[0], "/..")) { norm_dir = normalize_path(matches[0], strlen(matches[0])); if (norm_dir) { size_t norm_dir_len = strlen(norm_dir) + 2; char *ptr = xnmalloc(norm_dir_len, sizeof(char *)); snprintf(ptr, norm_dir_len, "%s/", norm_dir); free(norm_dir); norm_dir = ptr; } } dir = norm_dir ? norm_dir : matches[0]; directory_changed = 1; if (last_slash == dir) { if (last_slash[1]) { char c = last_slash[1]; *(last_slash + 1) = '\0'; xchdir(dir, NO_TITLE); *(last_slash + 1) = c; } else { /* We have the root dir */ xchdir(dir, NO_TITLE); } } else { *last_slash = '\0'; xchdir(dir, NO_TITLE); *last_slash = '/'; } if (dir != matches[0]) free(dir); } CALC_OFFSET: #ifndef _NO_FZF /* Alternative tab completion: fzf, fnf, smenu. */ if (fzftab == 1) { char *t = text ? text : (char *)NULL; if (finder_tabcomp(matches, common_prefix_added == 1 ? t : NULL, conf.fuzzy_match == 1 ? t : NULL) == -1) goto RESTART; goto RESET_PATH; } #else if (1) {} /* This just silences a warning. */ #endif /* !_NO_FZF */ /* Standard tab completion. */ char *ptr = matches[0]; /* Skip leading backslashes. */ while (*ptr) { if (*ptr != '\\') break; ptr++; } char *qq = (cur_comp_type == TCMP_DESEL || cur_comp_type == TCMP_SEL || cur_comp_type == TCMP_HIST) ? ptr : strrchr(ptr, '/'); if (qq && qq != ptr) { if (*(++qq)) { tab_offset = strlen(qq); } else { if (cur_comp_type == TCMP_DESEL) { tab_offset = strlen(matches[0]); qq = matches[0]; } } } else { int add = (cur_comp_type == TCMP_PATH && *ptr == '/') ? 1 : 0; tab_offset = strlen(ptr + add); } if (cur_comp_type == TCMP_OWNERSHIP && *ptr == ':' && !ptr[1]) { ptr = (char *)NULL; tab_offset = 0; } if (cur_comp_type == TCMP_RANGES || cur_comp_type == TCMP_BACKDIR || cur_comp_type == TCMP_FILE_TYPES_FILES || cur_comp_type == TCMP_FILE_TYPES_OPTS || cur_comp_type == TCMP_BM_PATHS || cur_comp_type == TCMP_MIME_LIST || cur_comp_type == TCMP_CMD_DESC || cur_comp_type == TCMP_SEL || cur_comp_type == TCMP_FILE_TEMPLATES || cur_comp_type == TCMP_DIRHIST || (tabmode == STD_TAB && (cur_comp_type == TCMP_JUMP || cur_comp_type == TCMP_TAGS_F) ) ) /* We don't want to highlight the matching part. */ tab_offset = 0; if (cur_comp_type == TCMP_HIST && ptr && *ptr == '!' && tab_offset > 0) { if (conf.fuzzy_match == 1) tab_offset = 0; else tab_offset--; } #ifndef _NO_TRASH /* If printing trashed files, let's change to the trash dir * to allow files colorization. */ if ((cur_comp_type == TCMP_UNTRASH || cur_comp_type == TCMP_TRASHDEL) && conf.colorize == 1 && trash_files_dir) { directory_changed = 1; xchdir(trash_files_dir, NO_TITLE); } #endif /* _NO_TRASH */ ERASE_TO_RIGHT_AND_BELOW; for (i = 1; i <= (size_t)count; i++) { if (i >= term_lines) { /* A little pager */ fputs("\x1b[7m--Mas--\x1b[0m", stdout); char c = 0; while ((c = xgetchar()) == KEY_ESC); if (c == 'q') { /* Delete the --Mas-- label */ fputs("\x1b[7D\x1b[7X\x1b[1A\n", stdout); break; } fputs("\x1b[7D\x1b[0K", stdout); } l = (int)i; for (j = 0; j < limit; j++) { if (l > len || !matches[l] || !*matches[l]) { break; } else { if (tab_offset) { /* Print the matching part of the match. */ printf("\x1b[0m%s%s\x1b[0m%s", ts_c, qq ? qq : matches[0], (cur_comp_type == TCMP_CMD) ? (conf.colorize ? ex_c : "") : fc_c); } /* Now print the non-matching part of the match. */ char *temp = printable_part(matches[l]); int printed_length = (int)wc_xstrlen(temp); printed_length += print_filename(temp, matches[l]); if (j + 1 < limit) { for (k = 0; k < max - printed_length; k++) putc(' ', rl_outstream); } } l += count; } putchar('\n'); } tab_offset = 0; if (!wrong_cmd && conf.colorize && cur_comp_type == TCMP_CMD) fputs(tx_c, stdout); rl_reset_line_state(); #ifndef _NO_FZF RESET_PATH: #endif /* !_NO_FZF */ RESTART: flags &= ~STATE_COMPLETING; if (directory_changed == 1 && workspaces && workspaces[cur_ws].path) xchdir(workspaces[cur_ws].path, NO_TITLE); rl_on_new_line(); #ifndef _NO_HIGHLIGHT if (conf.highlight == 1 && wrong_cmd == 0) { int bk = rl_point; HIDE_CURSOR; char *ss = rl_copy_text(0, rl_end); rl_delete_text(0, rl_end); rl_redisplay(); rl_point = rl_end = 0; l = 0; char t[PATH_MAX]; for (k = 0; ss[k]; k++) { rl_highlight(ss, (size_t)k, SET_COLOR); if ((signed char)ss[k] < 0) { t[l] = ss[k]; l++; if ((signed char)ss[k + 1] >= 0) { t[l] = '\0'; l = 0; rl_insert_text(t); rl_redisplay(); } continue; } t[0] = ss[k]; t[1] = '\0'; rl_insert_text(t); rl_redisplay(); } UNHIDE_CURSOR; rl_point = bk; free(ss); } #endif /* !_NO_HIGHLIGHT */ } break; default: xerror("\r\nreadline: %c: Bad value for what_to_do " "in tab_complete\n", what_to_do); exit(FUNC_FAILURE); } for (i = 0; matches[i]; i++) free(matches[i]); free(matches); free(text); return FUNC_SUCCESS; } clifm-1.26.3/src/tabcomp.h000066400000000000000000000020401506632037700152670ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* tabcomp.h */ #ifndef TABCOMP_H #define TABCOMP_H __BEGIN_DECLS int tab_complete(const int what_to_do); void reinsert_slashes(char *str); __END_DECLS #endif /* TABCOMP_H */ clifm-1.26.3/src/tags.c000066400000000000000000000456551506632037700146160ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* tags.c -- functions to handle the file tagging system */ #ifndef _NO_TAGS #include "helpers.h" #include #include #include #include #include "aux.h" #include "colors.h" /* colors_list() */ #include "init.h" #include "messages.h" #include "misc.h" #include "sort.h" #include "spawn.h" /* A few printing functions */ static int print_tag_creation_error(const char *link, const mode_t mode) { if (S_ISLNK(mode)) xerror(_("tag: '%s': File already tagged\n"), link); else xerror(_("tag: '%s': Cannot create tag: file already exists\n"), link); return FUNC_FAILURE; } static int print_symlink_error(const char *name) { xerror("tag: '%s': %s\n", name, strerror(errno)); return errno; } static int print_no_tags(void) { printf(_("%s: No tags found. Use 'tag new' to create new " "tags.\n"), PROGRAM_NAME); return FUNC_SUCCESS; } static int print_no_such_tag(const char *name) { xerror(_("tag: '%s': No such tag\n"), name); return FUNC_FAILURE; } static int print_usage(const int retval) { puts(TAG_USAGE); return retval; } #ifndef _DIRENT_HAVE_D_TPYE /* Check whether NAME is actually tagged as TAG. * Returns 1 if true or 0 otherwise. */ static int check_tagged_file(const char *tag, const char *name) { struct stat a; char tmp[PATH_MAX + 1]; snprintf(tmp, sizeof(tmp), "%s/%s/%s", tags_dir, tag, name); if (SELFORPARENT(name) || lstat(tmp, &a) == -1 || !S_ISLNK(a.st_mode)) return 0; return 1; } #endif /* _DIRENT_HAVE_D_TPYE */ /* Print the tagged file named NAME tagged as TAG. */ static void print_tagged_file(char *name, const char *tag) { char dir[PATH_MAX + 1]; char tmp[PATH_MAX + 1]; *tmp = '\0'; snprintf(dir, sizeof(dir), "%s/%s/%s", tags_dir, tag, name); char *ret = xrealpath(dir, tmp); if (!ret) return; if (!*tmp) { printf(_("%s (error resolving link target)\n"), name); return; } int free_name = 0; char *q = tmp; if (strncmp(tmp, user.home, strlen(user.home)) == 0) q = home_tilde(tmp, &free_name); if (strchr(name, '\\')) { char *d = unescape_str(name, 0); if (d) { xstrsncpy(name, d, strlen(d) + 1); free(d); } } putchar(' '); char *abbr_name = abbreviate_file_name(tmp); colors_list(abbr_name ? abbr_name : tmp, 0, 0, 1); if (abbr_name != tmp) free(abbr_name); if (free_name == 1) free(q); } /* Print the list of all files tagged as NAME. */ static int list_files_in_tag(char *name) { if (strchr(name, '\\')) { char *p = unescape_str(name, 0); if (p) { xstrsncpy(name, p, strlen(p) + 1); free(p); } } char tmp[PATH_MAX + 1]; snprintf(tmp, sizeof(tmp), "%s/%s", tags_dir, name); struct dirent **t = (struct dirent **)NULL; const int n = scandir(tmp, &t, NULL, conf.case_sens_list ? xalphasort : alphasort_insensitive); if (n == -1) { xerror("tag: '%s': %s\n", tmp, strerror(errno)); return errno; } size_t i; if (n <= 2) { for (i = 0; i < (size_t)n; i++) free(t[i]); free(t); return FUNC_SUCCESS; } for (i = 0; i < (size_t)n; i++) { #ifndef _DIRENT_HAVE_D_TPYE if (check_tagged_file(name, t[i]->d_name) == 0) { #else if (SELFORPARENT(t[i]->d_name) || t[i]->d_type != DT_LNK) { #endif /* !_DIRENT_HAVE_D_TYPE */ free(t[i]); continue; } print_tagged_file(t[i]->d_name, name); free(t[i]); } free(t); return FUNC_SUCCESS; } /* Return the length of longest tag name. * Used to pad the output of the 'tag list' command. */ static size_t get_longest_tag(void) { size_t i, longest_tag = 0; for (i = 0; i < tags_n; i++) { const size_t l = strlen(tags[i]); if (l > longest_tag) longest_tag = l; } return longest_tag; } /* List all tags applied to the file whose device ID is DEV and inode number * is INO. */ static void list_tags_having_file(const dev_t dev, const ino_t ino) { if (!tags_dir || !tags) return; size_t i; for (i = 0; tags[i]; i++) { char tmp[PATH_MAX + 1]; snprintf(tmp, sizeof(tmp), "%s/%s", tags_dir, tags[i]); DIR *dir = opendir(tmp); if (dir == NULL) continue; struct dirent *ent; while ((ent = readdir(dir))) { char full_name[PATH_MAX + NAME_MAX + 2]; snprintf(full_name, sizeof(full_name), "%s/%s", tmp, ent->d_name); struct stat a; if (stat(full_name, &a) == -1) continue; if (a.st_dev == dev && a.st_ino == ino) { printf(" %s%s%s\n", mi_c, tags[i], NC); break; } } closedir(dir); } } /* Check whether NAME is a valid and existent tag name. * Returns 1 if true or zero otherwise. */ int is_tag(char *name) { if (!name || !*name) return 0; if (strchr(name, '\\')) { char *deq = unescape_str(name, 0); if (deq) { xstrsncpy(name, deq, strlen(deq) + 1); free(deq); } } int i = (int)tags_n; while (--i >= 0) { if (*name == *tags[i] && strcmp(name, tags[i]) == 0) return 1; } return 0; } /* Print the list of available tags and all files tagged as each tag. */ static int list_tags_full(void) { if (tags_n == 0) { puts(_("tag: No tags")); return FUNC_SUCCESS; } size_t i; int exit_status = FUNC_SUCCESS; for (i = 0; tags[i]; i++) { printf(_("Files tagged as %s%s%s:\n"), conf.colorize == 1 ? BOLD : "'", tags[i], conf.colorize == 1 ? NC : "'"); if (list_files_in_tag(tags[i]) != FUNC_SUCCESS) exit_status = FUNC_FAILURE; if (tags[i + 1]) putchar('\n'); } return exit_status; } static int list_tags(char **args) { if (tags_n == 0) return print_no_tags(); size_t i; int exit_status = FUNC_SUCCESS; if (!args || !args[0] || !args[1] || !args[2]) { /* 'tag list': list all tags */ const int pad = (int)get_longest_tag(); for (i = 0; tags[i]; i++) { char p[PATH_MAX + 1]; snprintf(p, sizeof(p), "%s/%s", tags_dir, tags[i]); const filesn_t n = count_dir(p, NO_CPOP); if (n > 2) printf("%-*s [%s%jd%s]\n", pad, tags[i], mi_c, (intmax_t)n - 2, df_c); else printf("%-*s -\n", pad, tags[i]); } return FUNC_SUCCESS; } for (i = 2; args[i]; i++) { if (!is_tag(args[i])) { /* 'tag list FILENAME' */ char *p = unescape_str(args[i], 0); struct stat a; if (lstat(p ? p : args[i], &a) == -1) { exit_status = errno; xerror("%s: %s\n", p ? p : args[i], strerror(errno)); free(p); continue; } printf(_("%s%s%s is tagged as:\n"), conf.colorize == 1 ? BOLD : "'", p ? p : args[i], conf.colorize == 1 ? NC : "'"); free(p); list_tags_having_file(a.st_dev, a.st_ino); } else { /* 'tag list TAG' */ printf(_("Files tagged as %s%s%s%s:\n"), conf.colorize == 1 ? BOLD : "'", args[i], conf.colorize == 1 ? BOLD : "'", conf.colorize == 1 ? NC : "'"); if (list_files_in_tag(args[i]) == FUNC_FAILURE) exit_status = FUNC_FAILURE; } if (args[i + 1]) putchar('\n'); } return exit_status; } static void reload_tags(void) { free_tags(); load_tags(); } /* Create tags according to ARGS + 2. */ static int create_tags(char **args) { if (!args || !args[1] || !args[2]) return print_usage(FUNC_FAILURE); size_t i; int exit_status = FUNC_SUCCESS; for (i = 2; args[i]; i++) { char dir[PATH_MAX + 1]; char *p = strchr(args[i], '\\'); if (p) { char *deq = unescape_str(args[i], 0); if (deq) { free(args[i]); args[i] = deq; } } snprintf(dir, sizeof(dir), "%s/%s", tags_dir, args[i]); struct stat a; if (lstat(dir, &a) != -1) { xerror(_("tag: '%s': Tag already exists\n"), args[i]); exit_status = FUNC_FAILURE; continue; } if (xmkdir(dir, S_IRWXU) == FUNC_FAILURE) { xerror(_("tag: '%s': Error creating tag: %s\n"), args[i], strerror(errno)); exit_status = FUNC_FAILURE; continue; } printf(_("%s: Successfully created tag\n"), args[i]); } reload_tags(); return exit_status; } /* Remove those tags specified in ARGS + 2. */ static int remove_tags(char **args) { if (tags_n == 0) return print_no_tags(); int exit_status = FUNC_SUCCESS; size_t i; for (i = 2; args[i]; i++) { char *p = strchr(args[i], '\\'); if (p) { char *deq = unescape_str(args[i], 0); if (deq) { free(args[i]); args[i] = deq; } } char dir[PATH_MAX + 1]; snprintf(dir, sizeof(dir), "%s/%s", tags_dir, args[i]); struct stat a; if (stat(dir, &a) == -1 || !S_ISDIR(a.st_mode)) return print_no_such_tag(args[i]); char *cmd[] = {"rm", "-r", "--", dir, NULL}; if (launch_execv(cmd, FOREGROUND, E_NOFLAG) == FUNC_SUCCESS) { printf(_("'%s': Successfully removed tag\n"), args[i]); reload_tags(); } else { exit_status = FUNC_FAILURE; } } return exit_status; } /* Tag the file named NAME as TAG. */ static int tag_file(char *name, char *tag) { struct stat a; if (lstat(name, &a) == -1) { xerror("tag: '%s': %s\n", name, strerror(errno)); return FUNC_FAILURE; } int new_tag = 0; char *p = (char *)NULL; if (strchr(tag, '\\')) p = unescape_str(tag, 0); char dir[PATH_MAX + 1]; snprintf(dir, sizeof(dir), "%s/%s", tags_dir, p ? p : tag); if (stat(dir, &a) == -1) { if (xmkdir(dir, S_IRWXU) != FUNC_SUCCESS) { xerror(_("tag: '%s': Cannot create tag: %s\n"), p ? p : tag, strerror(errno)); free(p); return FUNC_FAILURE; } new_tag = 1; } if (new_tag == 1) { printf(_("Created new tag %s%s%s\n"), conf.colorize ? BOLD : "", p ? p : tag, df_c); reload_tags(); } free(p); char name_path[PATH_MAX + 1]; *name_path = '\0'; if (*name != '/') { snprintf(name_path, sizeof(name_path), "%s/%s", workspaces[cur_ws].path, name); } char link[PATH_MAX + NAME_MAX], *q = (char *)NULL; char *link_path = replace_slashes(*name_path ? name_path : name, ':'); snprintf(link, sizeof(link), "%s/%s", dir, link_path); free(link_path); if (lstat(link, &a) != -1) return print_tag_creation_error((q && *(++q)) ? q : name, a.st_mode); if (symlink(*name_path ? name_path : name, link) == -1) return print_symlink_error(name); return FUNC_SUCCESS; } /* Return an array with indices of tag names (:TAG) found in the ARGS array. * The indices array is terminated by a -1. * Returns NULL if no index was found .*/ static int * get_tags(char **args) { int n, i, c = 0; for (n = 0; args[n]; n++); int *t = xnmalloc((size_t)n + 1, sizeof(int)); for (i = 0; i < n; i++) { if (*args[i] == ':' && *(args[i] + 1)) { t[c] = i; c++; } } if (c == 0) { free(t); t = (int *)NULL; } else { t[c] = -1; } return t; } /* Tag filenames found in ARGS as all tags (:TAG) found in ARGS. */ static int tag_files(char **args) { int *tag_names = get_tags(args); if (!tag_names || tag_names[0] == -1) { free(tag_names); xerror("%s\n", _("tag: No tag specified. Specify a tag via :TAG. " "E.g. 'tag add FILE1 FILE2 :TAG'")); return FUNC_FAILURE; } size_t i, j, n = 0; const size_t start = (args[1] && strcmp(args[1], "add") == 0) ? 2 : 1; for (i = start; args[i]; i++) { if (*args[i] != ':') n++; } for (i = 0; tag_names[i] != -1; i++) { for (j = start; args[j]; j++) { if (*args[j] == ':') continue; char *p = (char *)NULL; if (strchr(args[j], '\\')) p = unescape_str(args[j], 0); if (tag_file(p ? p : args[j], args[tag_names[i]] + 1) != FUNC_SUCCESS) if (n > 0) --n; free(p); } } free(tag_names); if (n > 0) printf(_("Successfully tagged %zu file(s)\n"), n); return FUNC_SUCCESS; } /* Untag filenames found in ARGS tagged as ARGS[N]. */ static int untag(char **args, const size_t n, size_t *t) { if (!args || !args[1]) return FUNC_FAILURE; int exit_status = FUNC_SUCCESS; size_t i; for (i = 2; args[i]; i++) { if (i == n || (*args[i] == ':' && *(args[1] + 1))) continue; char *ds = unescape_str(args[n] + 1, 0); char dir[PATH_MAX + 1]; snprintf(dir, sizeof(dir), "%s/%s", tags_dir, ds ? ds : args[n] + 1); free(ds); struct stat a; if (lstat(dir, &a) == -1 || !S_ISDIR(a.st_mode)) return print_no_such_tag(args[n] + 1); char f[PATH_MAX + NAME_MAX]; char *deq = unescape_str(args[i], 0); char *p = deq ? deq : args[i]; char *exp = (char *)NULL; if (*p == '~') exp = tilde_expand(p); char *q = exp ? exp : p; char *r = replace_slashes(q, ':'); snprintf(f, sizeof(f), "%s/%s", dir, r ? r : q); free(deq); free(exp); free(r); if (lstat(f, &a) != -1 && S_ISLNK(a.st_mode)) { errno = 0; if (unlinkat(XAT_FDCWD, f, 0) == -1) { exit_status = errno; xerror("tag: '%s': %s\n", args[i], strerror(errno)); } else { (*t)++; } } else { xerror(_("tag: '%s': File not tagged as %s%s%s\n"), args[i], conf.colorize ? BOLD : "", args[n] + 1, df_c); continue; } } return exit_status; } /* Untag filenames found in ARGS as all tags (:TAG) found in ARGS. */ static int untag_files(char **args) { int exit_status = FUNC_SUCCESS; size_t i, n = 0; for (i = 1; args[i]; i++) { if (*args[i] == ':' && *(args[i] + 1) && untag(args, i, &n) == FUNC_FAILURE) exit_status = FUNC_FAILURE; } if (n > 0) printf(_("Successfully untagged %zu file(s)\n"), n); return exit_status; } /* Rename tag ARGS[2] as ARGS[3]. */ static int rename_tag(char **args) { if (!args || !args[1] || !args[2] || !args[3]) return print_usage(FUNC_FAILURE); char *old = args[2], *new = args[3]; if (!is_tag(old)) return print_no_such_tag(old); if (*old == *new && strcmp(old, new) == 0) { xerror("%s\n", _("tag: New and old filenames are the same")); return FUNC_FAILURE; } char old_dir[PATH_MAX + 1]; snprintf(old_dir, sizeof(old_dir), "%s/%s", tags_dir, old); char new_dir[PATH_MAX + 1]; snprintf(new_dir, sizeof(new_dir), "%s/%s", tags_dir, new); if (rename(old_dir, new_dir) == -1) { xerror("tag: %s\n", strerror(errno)); return errno; } puts(_("Successfully renamed tag")); reload_tags(); return FUNC_SUCCESS; } /* Move all (tagged) files (symlinks) in SRC into DST. * Returns zero if success or the appropriate ERRNO in case of error. */ static int recursive_mv_tags(const char *src, const char *dst) { int i, n, exit_status = FUNC_SUCCESS, ret; char src_dir[PATH_MAX + 1]; char dst_dir[PATH_MAX + 1]; struct dirent **a = (struct dirent **)NULL; snprintf(src_dir, sizeof(src_dir), "%s/%s", tags_dir, src); n = scandir(src_dir, &a, NULL, alphasort); if (n == -1) { xerror("tag: '%s': %s\n", src_dir, strerror(errno)); return errno; } snprintf(dst_dir, sizeof(dst_dir), "%s/%s", tags_dir, dst); for (i = 0; i < n; i++) { if (SELFORPARENT(a[i]->d_name)) { free(a[i]); continue; } char src_file[PATH_MAX + NAME_MAX + 2]; snprintf(src_file, sizeof(src_file), "%s/%s", src_dir, a[i]->d_name); char *cmd[] = {"mv", "--", src_file, dst_dir, NULL}; if ((ret = launch_execv(cmd, FOREGROUND, E_NOFLAG)) != FUNC_SUCCESS) exit_status = ret; free(a[i]); } free(a); return exit_status; } /* Merge tags ARGS[2] and ARGS[3]. */ static int merge_tags(char **args) { if (!args || !args[1] || !args[2] || !args[3]) return print_usage(FUNC_FAILURE); if (!is_tag(args[2])) return print_no_such_tag(args[2]); if (!is_tag(args[3])) return print_no_such_tag(args[3]); char *src = args[2], *dst = args[3]; if (strcmp(src, dst) == 0) { xerror("%s\n", _("tag: Source and destination are the same tag")); return FUNC_FAILURE; } errno = 0; int exit_status = recursive_mv_tags(src, dst); if (exit_status != FUNC_SUCCESS) { xerror("%s\n", _("tag: Cannot merge tags: error moving tagged files")); return exit_status; } char src_dir[PATH_MAX + 1]; snprintf(src_dir, sizeof(src_dir), "%s/%s", tags_dir, src); if (rmdir(src_dir) == -1) { xerror("tag: '%s': %s\n", src_dir, strerror(errno)); return errno; } reload_tags(); printf(_("Successfully merged %s%s%s into %s%s%s\n"), conf.colorize == 1 ? BOLD : "", src, df_c, conf.colorize == 1 ? BOLD : "", dst, df_c); return FUNC_SUCCESS; } /* Perform the following expansions: * ta -> tag add * td -> tag del * tl -> tag list * tm -> tag rename * tn -> tag new * tu -> tag untag * ty -> tag merge * The first string in ARGS must always be one of the left values * Returns an array with the expanded values. */ static char ** reconstruct_input(char **args) { size_t n = 0, c; for (n = 0; args[n]; n++); char **a = xnmalloc(n + 2, sizeof(char *)); a[0] = savestring("tag", 3); switch (args[0][1]) { case 'a': a[1] = savestring("add", 3); c = 2; break; case 'd': a[1] = savestring("del", 3); c = 2; break; case 'l': a[1] = savestring("list", 4); c = 2; break; case 'm': a[1] = savestring("rename", 6); c = 2; break; case 'n': a[1] = savestring("new", 3); c = 2; break; case 'u': a[1] = savestring("untag", 5); c = 2; break; case 'y': a[1] = savestring("merge", 5); c = 2; break; default: a[1] = savestring("-h", 2); c = 2; break; } for (n = 1; args[n]; n++) { a[c] = savestring(args[n], strlen(args[n])); c++; } a[c] = (char *)NULL; return a; } /* Free stuff in A (if needed) and exit the tag function. */ static int end_tag_function(const int exit_status, char **a, const int free_args) { if (free_args == 0) return exit_status; size_t i; for (i = 0; a[i]; i++) free(a[i]); free(a); return exit_status; } /* Check whether we should print help message or not. */ static int is_tag_help(char **args) { int first_is_help = (args[1] && IS_HELP(args[1])); if (strcmp(args[0], "tl") == 0) return first_is_help; return (!args[1] || first_is_help || (args[2] && IS_HELP(args[2]))); } /* Handle tag actions according to ARGS. */ int tags_function(char **args) { int exit_status = FUNC_SUCCESS, free_args = 0; char **a = args; if (is_tag_help(a)) { puts(_(TAG_USAGE)); goto END; } char b[] = "adlmnuy"; if (strcmp(a[0], "tag") != 0 && strspn(a[0] + 1, b)) { a = reconstruct_input(args); free_args = 1; } if (*a[1] == 'l' && strcmp(a[1], "list") == 0) { exit_status = list_tags(a); goto END; } if (*a[1] == 'l' && strcmp(a[1], "list-full") == 0) { exit_status = list_tags_full(); goto END; } if (*a[1] == 'm' && strcmp(a[1], "merge") == 0) { exit_status = merge_tags(a); goto END; } if (*a[1] == 'n' && strcmp(a[1], "new") == 0) { exit_status = create_tags(a); goto END; } if (*a[1] == 'd' && strcmp(a[1], "del") == 0) { exit_status = remove_tags(a); goto END; } if (*a[1] == 'r' && strcmp(a[1], "rename") == 0) { exit_status = rename_tag(a); goto END; } if (*a[1] == 'u' && strcmp(a[1], "untag") == 0) { exit_status = untag_files(a); goto END; } /* Either 'tag FILE :TAG' or 'tag add FILE :TAG' */ exit_status = tag_files(a); END: return end_tag_function(exit_status, a, free_args); } #else void *_skip_me_tags; #endif /* !_NO_TAGS */ clifm-1.26.3/src/tags.h000066400000000000000000000020011506632037700145750ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* tags.h */ #ifndef TAGS_H #define TAGS_H __BEGIN_DECLS int is_tag(char *name); int tags_function(char **args); __END_DECLS #endif /* TAGS_H */ clifm-1.26.3/src/term.c000066400000000000000000000320021506632037700146050ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* term.c -- terminal management functions */ /* enable_raw_mode, disable_raw_mode, and get_cursor_position functions are * taken from https://github.com/antirez/linenoise/blob/master/linenoise.c, licensed * under BSD-2-Clause. * All changes are licenced under GPL-2.0-or-later. */ #include "helpers.h" #include /* poll */ #include /* signal */ #include /* getenv */ #include /* strchr */ #include #include /* isatty */ #include #include "aux.h" /* xatoi */ #include "misc.h" /* set_signals_to_ignore, handle_stdin */ #include "term_info.h" static struct termios bk_term_attrs; /* Set the terminal title using the OSC-2 escape sequence. */ void set_term_title(char *dir) { int free_tmp = 0; char *tmp = (dir && *dir) ? home_tilde(dir, &free_tmp) : (char *)NULL; if (!tmp) printf("\x1b]2;%s\x1b\\", PROGRAM_NAME); else printf("\x1b]2;%s - %s\x1b\\", PROGRAM_NAME, tmp); fflush(stdout); if (free_tmp == 1) free(tmp); } /* Inform the underlying terminal about the new working directory using * the OSC-7 escape sequence. For more info see * https://midnight-commander.org/ticket/3088 * See also https://github.com/MidnightCommander/mc/commit/6b44fce839b5c2e85fdfb8e1d4e5052c7f1c1c3a * for the Midnight Commander implementation (added recently, in version 4.8.32). * Opinions are quite divided reagarding this escape code, mostly from the * side of terminal emulators: whether to support it or not, and if yes, * how to implement it. We, as a client of the terminal, just emit the code, * and it's up to the terminal to decide what to do with it. */ void report_cwd(const char *dir) { if (!dir || !*dir) return; char *uri = url_encode(dir, 0); if (!uri || !*uri) { free(uri); return; } printf("\x1b]7;file://%s%s\x1b\\", *hostname ? hostname : "", uri); fflush(stdout); free(uri); } static pid_t get_own_pid(void) { const pid_t pid = getpid(); return (pid < 0) ? 0 : pid; } #ifndef _BE_POSIX /* Get new window size and update/refresh the screen accordingly. */ static void sigwinch_handler(int sig) { UNUSED(sig); if (xargs.refresh_on_resize == 0 || conf.pager == 1 || kbind_busy == 1) return; get_term_size(); flags |= DELAYED_REFRESH; } #endif /* !_BE_POSIX */ static void set_signals_to_ignore(void) { struct sigaction sa; memset(&sa, 0, sizeof(sa)); sigemptyset(&sa.sa_mask); sa.sa_flags = SA_RESTART; sa.sa_handler = SIG_IGN; sigaction(SIGINT, &sa, NULL); sigaction(SIGQUIT, &sa, NULL); sigaction(SIGTSTP, &sa, NULL); sigaction(SIGTERM, &sa, NULL); sigaction(SIGTTIN, &sa, NULL); sigaction(SIGTTOU, &sa, NULL); #ifndef _BE_POSIX sa.sa_handler = sigwinch_handler; sigaction(SIGWINCH, &sa, NULL); #endif /* !_BE_POSIX */ } /* Keep track of attributes of the shell. Make sure the shell is running * interactively as the foreground job before proceeding. * Based on https://www.gnu.org/software/libc/manual/html_node/Initializing-the-Shell.html#Initializing-the-Shell * */ void init_shell(void) { if (isatty(STDIN_FILENO) == 0) { /* Shell is not interactive */ errno = 0; exit_code = handle_stdin(); return; } own_pid = get_own_pid(); set_signals_to_ignore(); } /* Set the terminal into raw mode. Return 0 on success and -1 on error */ int enable_raw_mode(const int fd) { struct termios raw; if (isatty(STDIN_FILENO) == 0) goto FAIL; if (tcgetattr(fd, &bk_term_attrs) == -1) goto FAIL; raw = bk_term_attrs; /* modify the original mode */ /* input modes: no break, no CR to NL, no parity check, no strip char, * no start/stop output control. */ raw.c_iflag &= (tcflag_t)~(BRKINT | ICRNL | INPCK | ISTRIP | IXON); /* output modes - disable post processing */ raw.c_oflag &= (tcflag_t)~(OPOST); /* control modes - set 8 bit chars */ raw.c_cflag |= (CS8); /* local modes - echoing off, canonical off, no extended functions, * no signal chars (^Z,^C) */ raw.c_lflag &= (tcflag_t)~(ECHO | ICANON | IEXTEN | ISIG); /* control chars - set return condition: min number of bytes and timer. */ /* We want read to return every single byte, without timeout. */ raw.c_cc[VMIN] = 1; raw.c_cc[VTIME] = 0; /* 1 byte, no timer */ /* Put terminal in raw mode after flushing */ if (tcsetattr(fd, TCSAFLUSH, &raw) < 0) goto FAIL; return 0; FAIL: errno = ENOTTY; return (-1); } int disable_raw_mode(const int fd) { return tcsetattr(fd, TCSAFLUSH, &bk_term_attrs) == -1 ? FUNC_FAILURE : FUNC_SUCCESS; } static int read_timeout(struct pollfd *pfd, const int timeout) { pfd->fd = STDIN_FILENO; pfd->events = POLLIN; if (poll(pfd, 1, timeout) == -1) return (-1); if (!(pfd->revents & POLLIN)) /* Time out, no input received. */ return 0; return 1; } /* Use the "ESC [6n" escape sequence to query the cursor position (both * vertical and horizontal) and store both values in C (columns) and L (lines). * Returns 0 on success or 1 on error. */ int get_cursor_position(int *c, int *l) { char buf[32]; unsigned int i = 0; struct pollfd pfd; if (enable_raw_mode(STDIN_FILENO) == -1) return FUNC_FAILURE; /* 1. Ask the terminal about cursor position */ const size_t cpr_len = sizeof(CPR_CODE) - 1; if (write(STDOUT_FILENO, CPR_CODE, cpr_len) != (ssize_t)cpr_len) { disable_raw_mode(STDIN_FILENO); return FUNC_FAILURE; } /* 2. Read the response: "ESC [ rows ; cols R" */ int read_err = 0; while (i < sizeof(buf) - 1) { if (read_timeout(&pfd, DEF_READ_TIMEOUT) != 1 || read(STDIN_FILENO, buf + i, 1) != 1) { // flawfinder: ignore read_err = 1; break; } if (buf[i] == 'R') break; i++; } buf[i] = '\0'; if (disable_raw_mode(STDIN_FILENO) == -1 || read_err == 1) return FUNC_FAILURE; /* 3. Parse the response */ if (*buf != KEY_ESC || buf[1] != '[' || !buf[2]) return FUNC_FAILURE; char *p = strchr(buf + 2, ';'); if (!p || !p[1]) return FUNC_FAILURE; *p = '\0'; *l = atoi(buf + 2); *c = atoi(p + 1); if (*l == INT_MIN || *c == INT_MIN) return FUNC_FAILURE; return FUNC_SUCCESS; } /* Return 1 if the running terminal is sixel capable, 0 if not, or -1 on error. */ static int check_sixel_support(void) { char buf[64]; unsigned int i = 0; struct pollfd pfd; if (enable_raw_mode(STDIN_FILENO) == -1) return (-1); /* 1. Ask the terminal for device attributes (primary DA) */ if (write(STDOUT_FILENO, "\x1b[c", 3) != 3) { disable_raw_mode(STDIN_FILENO); return (-1); } /* 2. Read the response: "n;n;n;...c" */ int read_err = 0; while (i < sizeof(buf) - 1) { if (read_timeout(&pfd, DEF_READ_TIMEOUT) != 1 || read(STDIN_FILENO, buf + i, 1) != 1) { // flawfinder: ignore read_err = 1; break; } if (buf[i] == 'c') break; i++; } buf[i] = '\0'; if (disable_raw_mode(STDIN_FILENO) == -1 || read_err == 1) return (-1); /* 3. Parse the response. We're looking for sixel support (4). * See https://vt100.net/docs/vt510-rm/DA1.html */ i = 0; while (buf[i]) { if ((i == 0 || buf[i - 1] == ';') && buf[i] == '4' && (!buf[i + 1] || buf[i + 1] == ';')) return 1; i++; } return 0; } /* Return 1 if the running terminal supports Unicode, 0 if not, or -1 on error. * Based on https://unix.stackexchange.com/questions/184345/detect-how-much-of-unicode-my-terminal-supports-even-through-screen*/ static int check_unicode_support(void) { char buf[64]; unsigned int i = 0; struct pollfd pfd; if (enable_raw_mode(STDIN_FILENO) == -1) return (-1); /* 1. Ask the terminal to print a 3-byte Unicode character that takes * 1 terminal column, then request the cursor position, and finally * clear the line. */ if (write(STDOUT_FILENO, "\r\xe2\x88\xb4\x1b[6n\x1b[1K\r", 13) != 13) { disable_raw_mode(STDIN_FILENO); return (-1); } /* 2. Read the response: "...;nR" */ int read_err = 0; while (i < sizeof(buf) - 1) { if (read_timeout(&pfd, DEF_READ_TIMEOUT) != 1 || read(STDIN_FILENO, buf + i, 1) != 1) { // flawfinder: ignore read_err = 1; break; } if (buf[i] == 'R') break; i++; } buf[i] = '\0'; if (disable_raw_mode(STDIN_FILENO) == -1 || read_err == 1) return (-1); /* 3. Parse the response. If we get 2, we have Unicode support. */ const char *p = strchr(buf, ';'); if (p && p[1] == '2' && !p[2]) return 1; return 0; } /* See https://github.com/termstandard/colors#truecolor-detection */ static int check_truecolor(void) { const char *c = getenv("COLORTERM"); if (c && ((*c == 't' && strcmp(c + 1, "ruecolor") == 0) || (*c == '2' && strcmp(c + 1, "4bit") == 0) ) ) return 1; return 0; } static void set_term_caps(const int i) { const int true_color = check_truecolor(); term_caps.unicode = 0; if (i == -1) { /* TERM not found in our terminfo database */ term_caps.color = true_color == 1 ? TRUECOLOR_NUM : 0; if (term_caps.color <= 8) memset(dim_c, '\0', sizeof(dim_c)); /* All fields of the term_caps struct are already set to zero */ return; } term_caps.home = TERM_INFO[i].home; term_caps.hide_cursor = TERM_INFO[i].hide_cursor; term_caps.clear = TERM_INFO[i].ed; term_caps.del_scrollback = TERM_INFO[i].del_scrollback; term_caps.req_cur_pos = TERM_INFO[i].req_cur_pos; term_caps.req_dev_attrs = TERM_INFO[i].req_dev_attrs; term_caps.color = true_color == 1 ? TRUECOLOR_NUM : (TERM_INFO[i].color > 0 ? TERM_INFO[i].color : 0); if (term_caps.color <= 8) memset(dim_c, '\0', sizeof(dim_c)); term_caps.suggestions = (TERM_INFO[i].cub == 1 && TERM_INFO[i].ed == 1 && TERM_INFO[i].el == 1) ? 1 : 0; term_caps.pager = (TERM_INFO[i].cub == 0 || TERM_INFO[i].el == 0) ? 0 : 1; } /* Check whether current terminal (ENV_TERM) supports colors and requesting * cursor position (needed to print suggestions). If not, disable the * feature accordingly. */ static void check_term_support(const char *env_term) { if (!env_term || !*env_term) { set_term_caps(-1); return; } const size_t len = strlen(env_term); int index = -1; for (size_t i = 0; TERM_INFO[i].name; i++) { if (*env_term != *TERM_INFO[i].name || len != TERM_INFO[i].len || strcmp(env_term, TERM_INFO[i].name) != 0) continue; index = (int)i; break; } if (index == -1) { err('w', PRINT_PROMPT, _("%s: '%s': Terminal type not supported. " "Limited functionality is expected.\n"), PROGRAM_NAME, env_term); } set_term_caps(index); } /* Try to detect what kind of image capability the running terminal supports * (sixel, ueberzug, iterm, kitty protocol, and ansi). * Write the result into the CLIFM_IMG_SUPPORT environment variable. * This variable will be read by the clifmimg script to generate images using * the specified method. */ static void check_img_support(const char *env_term) { if (getenv("CLIFM_FIFO_UEBERZUG")) { /* Variable set by the clifmrun script */ setenv("CLIFM_IMG_SUPPORT", "ueberzug", 1); flags |= UEBERZUG_IMG_PREV; } else if (getenv("KITTY_WINDOW_ID")) { /* KITTY_WINDOW_ID is guaranteed to be defined if running on the * kitty terminal. See https://github.com/kovidgoyal/kitty/issues/957 */ setenv("CLIFM_IMG_SUPPORT", "kitty", 1); } else if ((term_caps.req_dev_attrs == 1 && check_sixel_support() == 1) /* Yaft supports sixel (and DA request), but does not report it. */ || (*env_term == 'y' && strcmp(env_term, "yaft-256color") == 0)) { setenv("CLIFM_IMG_SUPPORT", "sixel", 1); } else { #ifdef __APPLE__ char *p = getenv("TERM_PROGRAM"); if (p && *p == 'i' && strcmp(p, "iTerm.app") == 0) { setenv("CLIFM_IMG_SUPPORT", "iterm", 1); return; } #endif /* __APPLE__ */ setenv("CLIFM_IMG_SUPPORT", "ansi", 1); } } void check_term(void) { const char *t = getenv("TERM"); if (!t || !*t) { t = "xterm"; err('w', PRINT_PROMPT, _("%s: TERM variable unset. Running in xterm " "compatibility mode.\n"), PROGRAM_NAME); } check_term_support(t); /* Skip below checks if STDOUT is not interactive (this includes running * Clifm from 'fzf --preview', i.e. tab completion), or if not required * (--ls, --stat, --stat-full, and --open). */ if (xargs.list_and_quit == 1 || xargs.stat > 0 || xargs.open == 1 || isatty(STDOUT_FILENO) == 0) return; #ifdef __FreeBSD__ if (!(flags & GUI)) return; #endif /* __FreeBSD__ */ check_img_support(t); if (xargs.kitty_keys == 1) SET_KITTY_KEYS; /* At this point, term_caps.unicode is zero */ if (xargs.unicode == 1 || (xargs.unicode == UNSET && term_caps.req_cur_pos == 1 && check_unicode_support() == 1)) term_caps.unicode = 1; } clifm-1.26.3/src/term.h000066400000000000000000000063641506632037700146260ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* term.h */ #ifndef CLIFM_TERM_H #define CLIFM_TERM_H /* TERMINAL ESCAPE CODES */ #define CLEAR \ if (term_caps.home == 1 && term_caps.clear == 1) { \ if (term_caps.del_scrollback == 1) \ fputs("\x1b[H\x1b[2J\x1b[3J", stdout); \ else if (term_caps.del_scrollback == 2) \ fputs("\033c", stdout); \ else \ fputs("\x1b[H\x1b[J", stdout); \ } #define MOVE_CURSOR_DOWN(n) printf("\x1b[%dB", (n)) /* CUD */ /* ######## Escape sequences used by the suggestions system */ #define MOVE_CURSOR_UP(n) printf("\x1b[%dA", (n)) /* CUU */ #define MOVE_CURSOR_RIGHT(n) printf("\x1b[%dC", (n)) /* CUF */ #define MOVE_CURSOR_LEFT(n) printf("\x1b[%dD", (n)) /* CUB */ #define ERASE_TO_RIGHT fputs("\x1b[0K", stdout) /* EL0 */ #define ERASE_TO_LEFT fputs("\x1b[1K", stdout) /* EL1 */ #define ERASE_TO_RIGHT_AND_BELOW fputs("\x1b[J", stdout) /* ED0 */ #define SUGGEST_BAEJ(offset, color) printf("\x1b[%dC%s%c\x1b[0m ", \ (offset), (color), SUG_POINTER) /* ######## */ /* Sequences used by the pad_filename function (listing.c): * MOVE_CURSOR_RIGHT() */ /* Sequences used by the pager (listing.c): * MOVE_CURSOR_DOWN(n) * ERASE_TO_RIGHT */ #define META_SENDS_ESC fputs("\x1b[?1036h", stdout) #define HIDE_CURSOR fputs(term_caps.hide_cursor == 1 ? "\x1b[?25l" : "", stdout) /* DECTCEM */ #define UNHIDE_CURSOR fputs(term_caps.hide_cursor == 1 ? "\x1b[?25h" : "", stdout) #define RESTORE_COLOR fputs("\x1b[0;39;49m", stdout) #define SET_RVIDEO fputs("\x1b[?5h", stderr) /* DECSCNM: Enable reverse video */ #define UNSET_RVIDEO fputs("\x1b[?5l", stderr) #define SET_LINE_WRAP fputs("\x1b[?7h", stderr) /* DECAWM */ #define UNSET_LINE_WRAP fputs("\x1b[?7l", stderr) #define RING_BELL fputs("\007", stderr) #define CPR_CODE "\x1b[6n" /* Cursor position report */ /* Kitty keyboard protocol */ #define SET_KITTY_KEYS fputs("\x1b[>1u", stdout) #define UNSET_KITTY_KEYS fputs("\x1b[ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* term_info.h - A list of terminals and a few capabilities */ #ifndef TERM_INFO_H #define TERM_INFO_H struct terms_t { char *name; /* Terminal name as found in $TERM and the terminfo database */ /* Let's hardcode the length of each terminal name to prevent unnecessary * calls to strlen(3): comparing the first byte and this length to those * of the current terminal is most of the time enough */ size_t len; int color; /* -1 means no color support */ int cub; /* Move cursor backward */ int el; /* Erase line */ int ed; /* Erase display */ int hide_cursor; int del_scrollback; int home; int req_cur_pos; int req_dev_attrs; int pad0; }; const struct terms_t TERM_INFO[] = { {"386at", 5, 8, 1, 1, 1, 1, 0, 1, 0, 0, 0}, {"3b1", 3, -1, 1, 1, 1, 1, 0, 1, 0, 0, 0}, {"5630-24", 7, -1, 1, 1, 1, 0, 0, 1, 1, 0, 0}, {"5630DMD-24", 10, -1, 1, 1, 1, 0, 0, 1, 1, 0, 0}, {"630MTG-24", 9, -1, 1, 1, 1, 0, 0, 1, 1, 0, 0}, {"730MTG-24", 9, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"730MTG-41", 9, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"730MTG-41r", 10, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"730MTGr", 7, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"730MTGr-24", 10, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"aaa", 3, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"aaa-18", 6, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"aaa-18-rv", 9, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"aaa-20", 6, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"aaa-22", 6, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"aaa-24", 6, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"aaa-24-rv", 9, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"aaa-26", 6, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"aaa-28", 6, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"aaa-30", 6, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"aaa-30-ctxt", 11, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"aaa-30-rv", 9, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"aaa-30-rv-ctxt", 14, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"aaa-30-s", 8, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"aaa-30-s-ctxt", 13, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"aaa-30-s-rv", 11, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"aaa-30-s-rv-ct", 14, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"aaa-36", 6, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"aaa-36-rv", 9, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"aaa-40", 6, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"aaa-40-rv", 9, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"aaa-48", 6, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"aaa-48-rv", 9, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"aaa-60", 6, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"aaa-60-dec-rv", 13, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"aaa-60-rv", 9, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"aaa-60-s", 8, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"aaa-60-s-rv", 11, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"aaa-ctxt", 8, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"aaa-db", 6, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"aaa-rv", 6, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"aaa-rv-ctxt", 11, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"aaa-s", 5, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"aaa-s-ctxt", 10, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"aaa-s-rv", 8, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"aaa-s-rv-ctxt", 13, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"aaa+unk", 7, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"aaa-unk", 7, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"absolute", 8, 256, 1, 1, 1, 1, 1, 1, 1, 1, 0}, {"adm36", 5, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"aixterm", 7, 8, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"aixterm-16color", 15, 16, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"aixterm-m", 9, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"aixterm-m-old", 13, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"alacritty", 9, 256, 1, 1, 1, 1, 1, 1, 1, 1, 0}, {"alacritty+common", 16, 8, 1, 1, 1, 1, 1, 1, 1, 1, 0}, {"alacritty-direct", 16, 16777216, 1, 1, 1, 1, 1, 1, 1, 1, 0}, {"ambas", 5, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"ambassador", 10, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"amiga", 5, -1, 1, 1, 1, 1, 2, 1, 0, 0, 0}, {"amiga-8bit", 10, -1, 1, 1, 1, 1, 2, 1, 0, 0, 0}, {"amiga-h", 7, -1, 1, 1, 1, 1, 2, 1, 0, 0, 0}, {"amiga-vnc", 9, 16, 1, 1, 1, 1, 2, 0, 0, 0, 0}, {"ansi", 4, 8, 1, 1, 1, 0, 0, 1, 1, 1, 0}, {"ansi80x25", 9, 8, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"ansi80x25-mono", 14, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"ansi80x25-raw", 13, 8, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"ansi80x30", 9, 8, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"ansi80x30-mono", 14, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"ansi80x43", 9, 8, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"ansi80x43-mono", 14, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"ansi80x50", 9, 8, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"ansi80x50-mono", 14, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"ansi80x60", 9, 8, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"ansi80x60-mono", 14, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"ansi-color-2-emx", 16, 8, 0, 1, 1, 1, 2, 1, 1, 1, 0}, {"ansi-color-3-emx", 16, 8, 0, 1, 1, 1, 2, 1, 1, 1, 0}, {"ansi-emx", 8, 8, 0, 1, 1, 1, 2, 1, 1, 1, 0}, {"ansi-generic", 12, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"ansil", 5, 8, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"ansil-mono", 10, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"ansi-m", 6, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"ansi-mono", 9, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"ansis", 5, 8, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"ansis-mono", 10, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"ansi.sys", 8, 8, 0, 1, 0, 0, 0, 1, 1, 0, 0}, {"ansi.sysk", 9, 8, 0, 1, 0, 0, 0, 1, 1, 0, 0}, {"ansisysk", 8, 8, 0, 1, 0, 0, 0, 1, 1, 0, 0}, {"ansi.sys-old", 12, 8, 0, 1, 0, 0, 0, 1, 1, 0, 0}, {"ansiterm", 8, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"ansiw", 5, 8, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"apollo_15P", 10, -1, 1, 1, 1, 0, 0, 1, 1, 0, 0}, {"apollo_19L", 10, -1, 1, 1, 1, 0, 0, 1, 1, 0, 0}, {"apollo_color", 12, -1, 1, 1, 1, 0, 0, 1, 1, 0, 0}, {"apollo+vt132", 12, -1, 1, 1, 1, 0, 0, 1, 1, 0, 0}, {"Apple_Terminal", 14, 256, 1, 1, 1, 1, 0, 1, 1, 1, 0}, {"arm100", 6, 8, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"arm100-am", 9, 8, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"arm100-w", 8, 8, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"arm100-wam", 10, 8, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"at386", 5, 8, 1, 1, 1, 1, 0, 1, 0, 0, 0}, {"atari-color", 11, 16, 0, 1, 1, 1, 0, 1, 0, 0, 0}, {"atari_st-color", 14, 16, 0, 1, 1, 1, 0, 1, 0, 0, 0}, {"at-color", 8, 16, 0, 1, 1, 1, 0, 1, 0, 0, 0}, {"aterm", 5, 8, 1, 1, 1, 1, 0, 1, 1, 1, 0}, {"att2300", 7, -1, 1, 1, 1, 0, 0, 1, 1, 0, 0}, {"att2350", 7, -1, 1, 1, 1, 0, 0, 1, 1, 0, 0}, {"att4415", 7, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"att4415-nl", 10, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"att4415-rv", 10, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"att4415-rv-nl", 13, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"att4415-w", 9, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"att4415-w-nl", 12, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"att4415-w-rv", 12, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"att4415-w-rv-n", 14, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"att4418", 7, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"att4418-w", 9, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"att4424", 7, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"att4424-1", 9, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"att4425", 7, -1, 1, 1, 1, 0, 0, 1, 1, 0, 0}, {"att4425-nl", 10, -1, 1, 1, 1, 0, 0, 1, 1, 0, 0}, {"att4425-w", 9, -1, 1, 1, 1, 0, 0, 1, 1, 0, 0}, {"att4426", 7, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"att500", 6, -1, 1, 1, 1, 0, 0, 1, 1, 0, 0}, {"att505", 6, -1, 1, 1, 1, 0, 2, 1, 1, 0, 0}, {"att505-22", 9, -1, 1, 1, 1, 0, 2, 1, 1, 0, 0}, {"att505-24", 9, -1, 1, 1, 1, 0, 2, 1, 1, 0, 0}, {"att510a", 7, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"att510d", 7, -1, 1, 1, 1, 0, 0, 1, 1, 0, 0}, {"att513", 6, -1, 1, 1, 1, 0, 0, 1, 1, 0, 0}, {"att5418", 7, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"att5418-w", 9, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"att5420", 7, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"att5420_2", 9, -1, 1, 1, 1, 0, 0, 1, 1, 0, 0}, {"att5420_2-w", 11, -1, 1, 1, 1, 0, 0, 1, 1, 0, 0}, {"att5420-nl", 10, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"att5420-rv", 10, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"att5420-rv-nl", 13, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"att5420-w", 9, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"att5420-w-nl", 12, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"att5420-w-rv", 12, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"att5420-w-rv-n", 14, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"att5425", 7, -1, 1, 1, 1, 0, 0, 1, 1, 0, 0}, {"att5425-nl", 10, -1, 1, 1, 1, 0, 0, 1, 1, 0, 0}, {"att5425-w", 9, -1, 1, 1, 1, 0, 0, 1, 1, 0, 0}, {"att5430", 7, -1, 1, 1, 1, 0, 2, 1, 1, 0, 0}, {"att610", 6, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"att610-103k", 11, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"att610-103k-w", 13, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"att610-w", 8, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"att615", 6, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"att615-103k", 11, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"att615-103k-w", 13, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"att615-w", 8, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"att620", 6, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"att620-103k", 11, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"att620-103k-w", 13, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"att620-w", 8, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"att630", 6, -1, 1, 1, 1, 0, 0, 1, 1, 0, 0}, {"att630-24", 9, -1, 1, 1, 1, 0, 0, 1, 1, 0, 0}, {"att6386", 7, 8, 1, 1, 1, 1, 0, 1, 0, 0, 0}, {"att700", 6, -1, 1, 1, 1, 1, 2, 1, 1, 0, 0}, {"att730", 6, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"att7300", 7, -1, 1, 1, 1, 1, 0, 1, 0, 0, 0}, {"att730-24", 9, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"att730-41", 9, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"att730r", 7, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"att730r-24", 10, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"att730r-41", 10, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"avt", 3, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"avt-ns", 6, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"avt-rv", 6, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"avt-rv-ns", 9, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"avt-rv-s", 8, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"avt-s", 5, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"avt-w", 5, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"avt-w-ns", 8, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"avt-w-rv", 8, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"avt-w-rv-ns", 11, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"avt-w-rv-s", 10, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"avt-w-s", 7, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"bct510a", 7, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"bct510d", 7, -1, 1, 1, 1, 0, 0, 1, 1, 0, 0}, {"beterm", 6, 8, 1, 1, 1, 0, 2, 1, 1, 0, 0}, {"bq300", 5, -1, 1, 1, 1, 1, 0, 1, 1, 1, 0}, {"bq300-8", 7, -1, 1, 1, 1, 1, 0, 1, 0, 0, 0}, {"bq300-8-pc", 10, -1, 1, 1, 1, 1, 0, 1, 0, 0, 0}, {"bq300-8-pc-rv", 13, -1, 1, 1, 1, 1, 0, 1, 0, 0, 0}, {"bq300-8-pc-w", 12, -1, 1, 1, 1, 1, 0, 1, 0, 0, 0}, {"bq300-8-pc-w-rv", 15, -1, 1, 1, 1, 1, 0, 1, 0, 0, 0}, {"bq300-8rv", 9, -1, 1, 1, 1, 1, 0, 1, 0, 0, 0}, {"bq300-8w", 8, -1, 1, 1, 1, 1, 0, 1, 0, 0, 0}, {"bq300-pc", 8, -1, 1, 1, 1, 1, 0, 1, 1, 1, 0}, {"bq300-pc-rv", 11, -1, 1, 1, 1, 1, 0, 1, 1, 1, 0}, {"bq300-pc-w", 10, -1, 1, 1, 1, 1, 0, 1, 1, 1, 0}, {"bq300-pc-w-rv", 13, -1, 1, 1, 1, 1, 0, 1, 1, 1, 0}, {"bq300-rv", 8, -1, 1, 1, 1, 1, 0, 1, 1, 1, 0}, {"bq300-w", 7, -1, 1, 1, 1, 1, 0, 1, 1, 1, 0}, {"bq300-w-8rv", 11, -1, 1, 1, 1, 1, 0, 1, 0, 0, 0}, {"bq300-w-rv", 10, -1, 1, 1, 1, 1, 0, 1, 1, 1, 0}, {"bsdos-pc", 8, 8, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"bsdos-pc-m", 10, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"bsdos-pc-mono", 13, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"bsdos-pc-nobold", 15, 8, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"bsdos-ppc", 9, 8, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"bterm", 5, 8, 0, 1, 1, 1, 0, 1, 0, 0, 0}, {"cit101e-rv", 10, -1, 1, 1, 1, 1, 2, 1, 1, 1, 0}, {"cit500", 6, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"color_xterm", 11, 8, 1, 1, 1, 0, 0, 1, 1, 0, 0}, {"concept-avt", 11, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"cons25", 6, 8, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"cons25-debian", 13, 8, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"cons25-iso8859", 14, 8, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"cons25-iso-m", 12, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"cons25-koi8-r", 13, 8, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"cons25-koi8r-m", 14, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"cons25l1", 8, 8, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"cons25l1-m", 10, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"cons25-m", 8, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"cons25r", 7, 8, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"cons25r-m", 9, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"cons25w", 7, 8, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"cons30", 6, 8, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"cons30-m", 8, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"cons43", 6, 8, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"cons43-m", 8, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"cons50", 6, 8, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"cons50-iso8859", 14, 8, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"cons50-iso-m", 12, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"cons50-koi8r", 12, 8, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"cons50-koi8r-m", 14, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"cons50l1", 8, 8, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"cons50l1-m", 10, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"cons50-m", 8, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"cons50r", 7, 8, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"cons50r-m", 9, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"cons60", 6, 8, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"cons60-iso", 10, 8, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"cons60-iso-m", 12, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"cons60-koi8r", 12, 8, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"cons60-koi8r-m", 14, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"cons60l1", 8, 8, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"cons60l1-m", 10, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"cons60-m", 8, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"cons60r", 7, 8, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"cons60r-m", 9, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"contour", 7, 256, 1, 1, 1, 1, 1, 1, 0, 0, 0}, {"contour-direct", 14, 16777216, 1, 1, 1, 1, 1, 1, 0, 0, 0}, {"contour-latest", 14, 256, 1, 1, 1, 1, 1, 1, 0, 0, 0}, {"crt", 3, 8, 1, 1, 1, 0, 0, 1, 1, 1, 0}, {"crt-vt220", 9, 8, 1, 1, 1, 0, 0, 1, 1, 1, 0}, {"ctrm", 4, 8, 0, 1, 1, 0, 0, 0, 0, 0, 0}, {"cx", 2, 8, 1, 1, 1, 0, 0, 1, 1, 0, 0}, {"cx100", 5, 8, 1, 1, 1, 0, 0, 1, 1, 0, 0}, {"cygwin", 6, 8, 1, 1, 1, 0, 2, 1, 1, 1, 0}, {"cygwinB19", 9, 8, 0, 1, 0, 0, 0, 1, 1, 0, 0}, {"cygwinDBG", 9, 8, 1, 1, 1, 1, 2, 1, 1, 1, 0}, {"d210", 4, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"d211", 4, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"d211-7b", 7, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"d214", 4, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"d215", 4, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"d215-7b", 7, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"d220", 4, 8, 1, 1, 1, 1, 2, 1, 0, 0, 0}, {"d220-7b", 7, 8, 1, 1, 1, 1, 2, 1, 0, 0, 0}, {"d220-dg", 7, 8, 0, 1, 1, 1, 0, 0, 0, 0, 0}, {"d230", 4, 8, 1, 1, 1, 1, 2, 1, 0, 0, 0}, {"d230c", 5, 8, 1, 1, 1, 1, 2, 1, 0, 0, 0}, {"d230c-dg", 8, 8, 0, 1, 1, 1, 0, 0, 0, 0, 0}, {"d230-dg", 7, 8, 0, 1, 1, 1, 0, 0, 0, 0, 0}, {"d410", 4, -1, 1, 1, 1, 1, 2, 1, 0, 0, 0}, {"d410-7b", 7, -1, 1, 1, 1, 1, 2, 1, 0, 0, 0}, {"d410-7b-w", 9, -1, 1, 1, 1, 1, 2, 1, 0, 0, 0}, {"d410-w", 6, -1, 1, 1, 1, 1, 2, 1, 0, 0, 0}, {"d411", 4, -1, 1, 1, 1, 1, 2, 1, 0, 0, 0}, {"d411-7b", 7, -1, 1, 1, 1, 1, 2, 1, 0, 0, 0}, {"d411-7b-w", 9, -1, 1, 1, 1, 1, 2, 1, 0, 0, 0}, {"d411-w", 6, -1, 1, 1, 1, 1, 2, 1, 0, 0, 0}, {"d430c-dg", 8, 16, 0, 1, 1, 1, 0, 1, 0, 0, 0}, {"d430c-dg-ccc", 12, 52, 0, 1, 1, 1, 0, 1, 0, 0, 0}, {"d430c-unix", 10, 16, 0, 1, 1, 1, 0, 1, 0, 0, 0}, {"d430c-unix-25", 13, 16, 0, 1, 1, 1, 0, 1, 0, 0, 0}, {"d430c-unix-25-ccc", 17, 52, 0, 1, 1, 1, 0, 1, 0, 0, 0}, {"d430c-unix-ccc", 14, 52, 0, 1, 1, 1, 0, 1, 0, 0, 0}, {"d430c-unix-s", 12, 16, 0, 1, 1, 1, 0, 1, 0, 0, 0}, {"d430c-unix-s-ccc", 16, 52, 0, 1, 1, 1, 0, 1, 0, 0, 0}, {"d430c-unix-sr", 13, 16, 0, 1, 1, 1, 0, 1, 0, 0, 0}, {"d430c-unix-sr-ccc", 17, 52, 0, 1, 1, 1, 0, 1, 0, 0, 0}, {"d430c-unix-w", 12, 16, 0, 1, 1, 1, 0, 1, 0, 0, 0}, {"d430c-unix-w-ccc", 16, 52, 0, 1, 1, 1, 0, 1, 0, 0, 0}, {"d430-dg", 7, 16, 0, 1, 1, 1, 0, 1, 0, 0, 0}, {"d430-dg-ccc", 11, 52, 0, 1, 1, 1, 0, 1, 0, 0, 0}, {"d430-unix", 9, 16, 0, 1, 1, 1, 0, 1, 0, 0, 0}, {"d430-unix-25", 12, 16, 0, 1, 1, 1, 0, 1, 0, 0, 0}, {"d430-unix-25-ccc", 16, 52, 0, 1, 1, 1, 0, 1, 0, 0, 0}, {"d430-unix-ccc", 13, 52, 0, 1, 1, 1, 0, 1, 0, 0, 0}, {"d430-unix-s", 11, 16, 0, 1, 1, 1, 0, 1, 0, 0, 0}, {"d430-unix-s-ccc", 15, 52, 0, 1, 1, 1, 0, 1, 0, 0, 0}, {"d430-unix-sr", 12, 16, 0, 1, 1, 1, 0, 1, 0, 0, 0}, {"d430-unix-sr-ccc", 16, 52, 0, 1, 1, 1, 0, 1, 0, 0, 0}, {"d430-unix-w", 11, 16, 0, 1, 1, 1, 0, 1, 0, 0, 0}, {"d430-unix-w-ccc", 15, 52, 0, 1, 1, 1, 0, 1, 0, 0, 0}, {"d460", 4, -1, 1, 1, 1, 1, 2, 1, 0, 0, 0}, {"d460-7b", 7, -1, 1, 1, 1, 1, 2, 1, 0, 0, 0}, {"d460-7b-w", 9, -1, 1, 1, 1, 1, 2, 1, 0, 0, 0}, {"d460-w", 6, -1, 1, 1, 1, 1, 2, 1, 0, 0, 0}, {"d461", 4, -1, 1, 1, 1, 1, 2, 1, 0, 0, 0}, {"d461-7b", 7, -1, 1, 1, 1, 1, 2, 1, 0, 0, 0}, {"d461-7b-w", 9, -1, 1, 1, 1, 1, 2, 1, 0, 0, 0}, {"d461-w", 6, -1, 1, 1, 1, 1, 2, 1, 0, 0, 0}, {"d470", 4, 16, 1, 1, 1, 1, 2, 1, 0, 0, 0}, {"d470-7b", 7, 16, 1, 1, 1, 1, 2, 1, 0, 0, 0}, {"d470c", 5, 16, 1, 1, 1, 1, 2, 1, 0, 0, 0}, {"d470c-7b", 8, 16, 1, 1, 1, 1, 2, 1, 0, 0, 0}, {"d470c-dg", 8, 16, 0, 1, 1, 1, 0, 1, 0, 0, 0}, {"d470-dg", 7, 16, 0, 1, 1, 1, 0, 1, 0, 0, 0}, {"d555", 4, -1, 1, 1, 1, 1, 2, 1, 0, 0, 0}, {"d555-7b", 7, -1, 1, 1, 1, 1, 2, 1, 0, 0, 0}, {"d555-7b-w", 9, -1, 1, 1, 1, 1, 2, 1, 0, 0, 0}, {"d555-w", 6, -1, 1, 1, 1, 1, 2, 1, 0, 0, 0}, {"d577", 4, -1, 1, 1, 1, 1, 2, 1, 0, 0, 0}, {"d577-7b", 7, -1, 1, 1, 1, 1, 2, 1, 0, 0, 0}, {"d577-7b-w", 9, -1, 1, 1, 1, 1, 2, 1, 0, 0, 0}, {"d577-w", 6, -1, 1, 1, 1, 1, 2, 1, 0, 0, 0}, {"d578", 4, -1, 1, 1, 1, 1, 2, 1, 0, 0, 0}, {"d578-7b", 7, -1, 1, 1, 1, 1, 2, 1, 0, 0, 0}, {"darwin", 6, 8, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"darwin-100x37", 13, 8, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"darwin-100x37-m", 15, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"darwin-112x37", 13, 8, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"darwin-112x37-m", 15, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"darwin-128x40", 13, 8, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"darwin-128x40-m", 15, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"darwin-128x48", 13, 8, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"darwin-128x48-m", 15, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"darwin-144x48", 13, 8, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"darwin-144x48-m", 15, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"darwin-160x64", 13, 8, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"darwin-160x64-m", 15, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"darwin-200x64", 13, 8, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"darwin-200x64-m", 15, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"darwin-200x75", 13, 8, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"darwin-200x75-m", 15, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"darwin-256x96", 13, 8, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"darwin-256x96-m", 15, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"darwin-80x25", 12, 8, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"darwin-80x25-m", 14, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"darwin-80x30", 12, 8, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"darwin-80x30-m", 14, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"darwin-90x30", 12, 8, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"darwin-90x30-m", 14, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"darwin-b", 8, 8, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"darwin-f", 8, 8, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"darwin-f2", 9, 8, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"darwin-m", 8, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"darwin-m-b", 10, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"darwin-m-f", 10, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"darwin-m-f2", 11, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"decansi", 7, 8, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"dec-vt100", 9, -1, 1, 1, 1, 0, 0, 1, 1, 0, 0}, {"dec-vt220", 9, -1, 1, 1, 1, 1, 0, 1, 1, 1, 0}, {"dec-vt330", 9, -1, 1, 1, 1, 1, 0, 1, 0, 0, 0}, {"dec-vt340", 9, -1, 1, 1, 1, 1, 0, 1, 0, 0, 0}, {"dec-vt400", 9, -1, 1, 1, 1, 1, 0, 1, 0, 0, 0}, {"dg+ccc", 6, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {"dg+color", 8, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {"dg+color8", 9, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {"dg+fixed", 8, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {"dgmode+color", 12, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {"dgmode+color8", 13, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {"dgunix+ccc", 10, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {"dgunix+fixed", 12, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {"djgpp", 5, 8, 1, 1, 1, 1, 0, 1, 0, 0, 0}, {"djgpp204", 8, 8, 1, 1, 1, 1, 0, 1, 0, 0, 0}, {"dku7102", 7, -1, 1, 1, 1, 1, 0, 1, 0, 0, 0}, {"dku7102-old", 11, -1, 1, 1, 1, 1, 0, 1, 0, 0, 0}, {"dku7102-sna", 11, -1, 1, 1, 1, 1, 0, 1, 0, 0, 0}, {"dku7103-sna", 11, -1, 1, 1, 1, 1, 0, 1, 0, 0, 0}, {"dku7202", 7, -1, 1, 1, 1, 1, 0, 1, 0, 0, 0}, {"dm80", 4, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"dm80w", 5, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"dmdt80", 6, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"dmdt80w", 7, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"domterm", 7, 256, 1, 1, 1, 1, 1, 1, 1, 1, 0}, {"dt80", 4, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"dt80w", 5, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"dtterm", 6, 8, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"dumb-emacs-ansi", 15, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {"dvtm", 4, 8, 1, 1, 1, 1, 0, 1, 0, 0, 0}, {"dvtm-256color", 13, 256, 1, 1, 1, 1, 0, 1, 0, 0, 0}, {"ecma+color", 10, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {"emots", 5, 8, 1, 1, 1, 0, 2, 1, 0, 0, 0}, {"emu", 3, 15, 1, 1, 1, 1, 0, 1, 0, 0, 0}, {"emu-220", 7, -1, 1, 1, 1, 1, 0, 1, 0, 0, 0}, {"emx-base", 8, 8, 0, 1, 0, 0, 0, 1, 1, 0, 0}, {"env230", 6, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"envision230", 11, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"eterm", 5, -1, 1, 1, 1, 0, 0, 1, 1, 0, 0}, {"Eterm", 5, 8, 1, 1, 1, 1, 2, 1, 1, 0, 0}, {"Eterm-256color", 14, 256, 1, 1, 1, 1, 2, 1, 1, 0, 0}, {"Eterm-88color", 13, 88, 1, 1, 1, 1, 2, 1, 1, 0, 0}, {"eterm-color", 11, 8, 1, 1, 1, 0, 2, 1, 1, 0, 0}, {"Eterm-color", 11, 8, 1, 1, 1, 1, 2, 1, 1, 0, 0}, {"excel62", 7, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"excel62-rv", 10, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"excel62-w", 9, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"excel64", 7, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"excel64-rv", 10, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"excel64-w", 9, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"fbterm", 6, 256, 1, 1, 1, 1, 1, 1, 1, 1, 0}, {"fenix", 5, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"fenixw", 6, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"foot", 4, 256, 1, 1, 1, 1, 1, 1, 1, 1, 0}, {"foot+base", 9, -1, 1, 1, 1, 1, 1, 1, 1, 1, 0}, {"foot-direct", 11, 16777216, 1, 1, 1, 1, 1, 1, 1, 1, 0}, {"foot-extra", 10, 256, 1, 1, 1, 1, 1, 1, 1, 1, 0}, {"foot-extra-direct", 17, 16777216, 1, 1, 1, 1, 1, 1, 1, 1, 0}, {"ghostty", 7, 256, 1, 1, 1, 1, 1, 1, 1, 1, 0}, {"gigi", 4, -1, 1, 1, 1, 0, 0, 0, 0, 0, 0}, {"gnome", 5, 8, 1, 1, 1, 1, 2, 1, 1, 1, 0}, {"gnome-2007", 10, 8, 1, 1, 1, 1, 2, 1, 1, 1, 0}, {"gnome-2008", 10, 8, 1, 1, 1, 1, 2, 1, 1, 1, 0}, {"gnome-2012", 10, 8, 1, 1, 1, 1, 2, 1, 1, 1, 0}, {"gnome-256color", 14, 256, 1, 1, 1, 1, 2, 1, 1, 1, 0}, {"gnome-fc5", 9, 8, 1, 1, 1, 1, 2, 1, 1, 1, 0}, {"gnome-rh62", 10, 8, 1, 1, 1, 0, 0, 1, 1, 1, 0}, {"gnome-rh72", 10, 8, 1, 1, 1, 1, 0, 1, 1, 1, 0}, {"gnome-rh80", 10, 8, 1, 1, 1, 1, 0, 1, 1, 1, 0}, {"gnome-rh90", 10, 8, 1, 1, 1, 1, 0, 1, 1, 1, 0}, {"graphos", 7, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"graphos-30", 10, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"gs5430", 6, -1, 1, 1, 1, 0, 2, 1, 1, 0, 0}, {"gs5430-22", 9, -1, 1, 1, 1, 0, 2, 1, 1, 0, 0}, {"gs5430-24", 9, -1, 1, 1, 1, 0, 2, 1, 1, 0, 0}, {"gs6300", 6, 8, 1, 1, 1, 0, 2, 1, 0, 0, 0}, {"guru", 4, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"guru-24", 7, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"guru-33", 7, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"guru-33-rv", 10, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"guru-33-s", 9, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"guru-44", 7, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"guru-44-s", 9, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"guru-76", 7, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"guru-76-lp", 10, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"guru-76-s", 9, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"guru-76-w", 9, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"guru-76-wm", 10, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"guru-76-w-s", 11, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"guru-lp", 7, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"guru-nctxt", 10, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"guru-rv", 7, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"guru-s", 6, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"guru+unk", 8, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"h29a-kc-bc", 10, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"h29a-kc-uc", 10, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"h29a-nkc-bc", 11, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"h29a-nkc-uc", 11, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"hds200", 6, -1, 1, 1, 1, 1, 0, 1, 0, 0, 0}, {"hft", 3, 8, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"hft-c", 5, 8, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"hft-c-old", 9, 8, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"hft-old", 7, 8, 0, 1, 1, 0, 0, 1, 0, 0, 0}, {"hirez100", 8, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"hirez100-w", 10, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"hp150", 5, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"hp2382", 6, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"hp2382a", 7, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"hp2397", 6, 16, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"hp2397a", 7, 16, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"hp2622", 6, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"hp2622a", 7, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"hp2623", 6, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"hp2623a", 7, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"hp2624", 6, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"hp2624-10p", 10, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"hp2624a", 7, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"hp2624a-10p", 11, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"hp2624b", 7, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"hp2624b-10p", 11, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"hp2624b-10p-p", 13, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"hp2624b-4p", 10, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"hp2624b-4p-p", 12, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"hp2624b-p", 9, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"hp2626", 6, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"hp2626-12", 9, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"hp2626-12-s", 11, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"hp2626-12x40", 12, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"hp2626a", 7, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"hp2626-ns", 9, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"hp2626p", 7, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"hp2626-s", 8, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"hp2626-x40", 10, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"hp98550a-color", 14, 8, 0, 1, 1, 0, 0, 1, 0, 0, 0}, {"hp98550-color", 13, 8, 0, 1, 1, 0, 0, 1, 0, 0, 0}, {"hp+color", 8, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {"hpterm-color", 12, 64, 0, 1, 1, 0, 0, 1, 0, 0, 0}, {"hpterm-color2", 13, 8, 0, 1, 1, 0, 0, 1, 0, 0, 0}, {"hterm", 5, 8, 1, 1, 1, 1, 1, 1, 1, 1, 0}, {"hterm-256color", 14, 256, 1, 1, 1, 1, 1, 1, 1, 1, 0}, {"hurd", 4, 8, 1, 1, 1, 1, 0, 1, 0, 0, 0}, {"i3164", 5, 8, 0, 1, 1, 0, 0, 1, 0, 0, 0}, {"ibm+16color", 11, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {"ibm3164", 7, 8, 0, 1, 1, 0, 0, 1, 0, 0, 0}, {"ibm5081", 7, 8, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"ibm5151", 7, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"ibm5154", 7, 8, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"ibm6153", 7, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"ibm6153-40", 10, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"ibm6153-90", 10, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"ibm6154", 7, 8, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"ibm6155", 7, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"ibm8503", 7, 8, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"ibm8507", 7, 8, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"ibm8512", 7, 8, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"ibm8513", 7, 8, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"ibm8514", 7, 8, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"ibm8604", 7, 8, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"ibm+color", 9, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {"ibmpc", 5, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"ibmpc3", 6, 8, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"ibmpc3r", 7, 8, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"ibmpc3r-mono", 12, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"interix", 7, 8, 1, 1, 1, 0, 2, 1, 0, 0, 0}, {"interix-nti", 11, 8, 1, 1, 1, 0, 2, 1, 0, 0, 0}, {"iris-ansi", 9, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"iris-ansi-ap", 12, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"iris-ansi-net", 13, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"iris-color", 10, 8, 1, 1, 1, 0, 2, 1, 1, 1, 0}, {"iterm", 5, 256, 1, 1, 1, 1, 0, 1, 1, 1, 0}, {"iterm2", 6, 256, 1, 1, 1, 1, 0, 1, 1, 1, 0}, {"iTerm2.app", 10, 256, 1, 1, 1, 1, 0, 1, 1, 1, 0}, {"iterm2-direct", 13, 16777216, 1, 1, 1, 1, 0, 1, 1, 1, 0}, {"iTerm.app", 9, 256, 1, 1, 1, 1, 0, 1, 1, 1, 0}, {"jaixterm", 8, 8, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"jaixterm-m", 10, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"jfbterm", 7, 8, 1, 1, 1, 1, 2, 1, 1, 1, 0}, {"kitty", 5, 256, 1, 1, 1, 1, 1, 1, 1, 1, 0}, {"kitty+common", 12, -1, 1, 1, 1, 1, 1, 1, 1, 1, 0}, {"kitty-direct", 12, 16777216, 1, 1, 1, 1, 1, 1, 1, 1, 0}, {"klone+color", 11, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {"kon", 3, 8, 1, 1, 1, 1, 2, 1, 1, 1, 0}, {"kon2", 4, 8, 1, 1, 1, 1, 2, 1, 1, 1, 0}, {"konsole", 7, 8, 1, 1, 1, 1, 2, 1, 1, 1, 0}, {"konsole-16color", 15, 16, 1, 1, 1, 1, 2, 1, 1, 1, 0}, {"konsole-256color", 16, 256, 1, 1, 1, 1, 2, 1, 1, 1, 0}, {"konsole-base", 12, 8, 1, 1, 1, 1, 2, 1, 1, 1, 0}, {"konsole-direct", 14, 16777216, 1, 1, 1, 1, 2, 1, 1, 1, 0}, {"konsole-linux", 13, 8, 1, 1, 1, 1, 2, 1, 1, 1, 0}, {"konsole-solaris", 15, 8, 1, 1, 1, 1, 2, 1, 1, 1, 0}, {"konsole-vt100", 13, 8, 1, 1, 1, 1, 2, 1, 1, 1, 0}, {"konsole-vt420pc", 15, 8, 1, 1, 1, 1, 2, 1, 1, 1, 0}, {"konsole-xf3x", 12, 8, 1, 1, 1, 1, 2, 1, 1, 1, 0}, {"konsole-xf4x", 12, 8, 1, 1, 1, 1, 2, 1, 1, 1, 0}, {"kterm", 5, 8, 1, 1, 1, 0, 0, 1, 1, 1, 0}, {"kterm-co", 8, 8, 1, 1, 1, 0, 0, 1, 1, 1, 0}, {"kterm-color", 11, 8, 1, 1, 1, 0, 0, 1, 1, 1, 0}, {"kvt", 3, 8, 1, 1, 1, 0, 0, 1, 1, 1, 0}, {"lft", 3, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"lft-pc850", 9, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"LFT-PC850", 9, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"linux", 5, 8, 1, 1, 1, 1, 1, 1, 1, 1, 0}, {"linux-16color", 13, 16, 1, 1, 1, 1, 1, 1, 1, 1, 0}, {"linux2.2", 8, 8, 1, 1, 1, 1, 2, 1, 1, 1, 0}, {"linux2.6", 8, 8, 1, 1, 1, 1, 2, 1, 1, 1, 0}, {"linux2.6.26", 11, 8, 1, 1, 1, 1, 2, 1, 1, 1, 0}, {"linux3.0", 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 0}, {"linux-basic", 11, 8, 1, 1, 1, 0, 2, 1, 1, 1, 0}, {"linux-c", 7, 8, 1, 1, 1, 0, 2, 1, 1, 1, 0}, {"linux-c-nc", 10, 8, 1, 1, 1, 0, 2, 1, 1, 1, 0}, {"linux-koi8", 10, 8, 1, 1, 1, 1, 1, 1, 1, 1, 0}, {"linux-koi8r", 11, 8, 1, 1, 1, 1, 1, 1, 1, 1, 0}, {"linux-lat", 9, 8, 1, 1, 1, 1, 1, 1, 1, 1, 0}, {"linux-m", 7, -1, 1, 1, 1, 1, 1, 1, 1, 1, 0}, {"linux-m1", 8, 8, 0, 1, 1, 1, 1, 1, 1, 0, 0}, {"linux-nic", 9, 8, 1, 1, 1, 1, 1, 1, 1, 1, 0}, {"linux-s", 7, 8, 1, 1, 0, 1, 1, 1, 1, 1, 0}, {"linux-vt", 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 0}, {"lisaterm", 8, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"lisaterm-w", 10, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"m2-nam", 6, -1, 1, 1, 1, 1, 2, 1, 1, 0, 0}, {"mach", 4, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"mach-bold", 9, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"mach-color", 10, 8, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"mach-gnu", 8, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"mach-gnu-color", 14, 8, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"memhp", 5, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"mgt", 3, 8, 1, 1, 1, 1, 2, 1, 1, 1, 0}, {"mgterm", 6, 8, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"minitel", 7, -1, 1, 1, 1, 1, 2, 1, 1, 0, 0}, {"minitel1", 8, 8, 0, 1, 0, 1, 0, 1, 0, 0, 0}, {"minitel12-80", 12, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"minitel1b", 9, 8, 1, 1, 1, 1, 0, 1, 0, 0, 0}, {"minitel1b-80", 12, -1, 1, 1, 1, 1, 0, 1, 0, 0, 0}, {"minitel1b-nb", 12, -1, 1, 1, 1, 1, 0, 1, 0, 0, 0}, {"minitel-2", 9, -1, 1, 1, 1, 1, 2, 1, 1, 0, 0}, {"minitel2-80", 11, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"minitel-2-nam", 13, -1, 1, 1, 1, 1, 2, 1, 1, 0, 0}, {"minix", 5, 8, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"minix-1.5", 9, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"minix-1.7", 9, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"minix-3.0", 9, 8, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"minix-old", 9, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"minix-old-am", 12, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"mintty", 6, 256, 1, 1, 1, 1, 1, 1, 1, 1, 0}, {"mintty+common", 13, 8, 1, 1, 1, 1, 1, 1, 1, 1, 0}, {"mintty-direct", 13, 16777216, 1, 1, 1, 1, 1, 1, 1, 1, 0}, {"mlterm", 6, 8, 1, 1, 1, 1, 2, 1, 1, 1, 0}, {"mlterm2", 7, 8, 1, 1, 1, 1, 2, 1, 1, 1, 0}, {"mlterm-256color", 15, 256, 1, 1, 1, 1, 2, 1, 1, 1, 0}, {"mlterm3", 7, 8, 1, 1, 1, 1, 2, 1, 1, 1, 0}, {"mlterm-direct", 13, 16777216, 1, 1, 1, 1, 2, 1, 1, 1, 0}, {"mod24", 5, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"modgraph", 8, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"morphos", 7, -1, 1, 1, 1, 1, 2, 1, 0, 0, 0}, {"mosh", 4, 8, 1, 1, 1, 1, 2, 1, 1, 1, 0}, {"mosh-256color", 13, 256, 1, 1, 1, 1, 2, 1, 1, 1, 0}, {"mostlike", 8, -1, 1, 1, 1, 0, 0, 1, 1, 1, 0}, {"mrxvt", 5, 8, 1, 1, 1, 1, 2, 1, 1, 1, 0}, {"mrxvt-256color", 14, 256, 1, 1, 1, 1, 2, 1, 1, 1, 0}, {"ms-terminal", 11, 256, 1, 1, 1, 1, 1, 1, 1, 1, 0}, {"ms-vt100", 8, -1, 1, 1, 1, 0, 0, 1, 1, 1, 0}, {"ms-vt100+", 9, 8, 1, 1, 1, 0, 0, 1, 1, 1, 0}, {"ms-vt100-16color", 16, 16, 1, 1, 1, 1, 0, 1, 1, 1, 0}, {"ms-vt100-color", 14, 8, 1, 1, 1, 0, 0, 1, 1, 1, 0}, {"ms-vt-utf8", 10, 8, 1, 1, 1, 0, 0, 1, 1, 1, 0}, {"mt4520-rv", 9, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"mterm-ansi", 10, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"mvterm", 6, 8, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"nansi.sys", 9, 8, 0, 1, 0, 0, 0, 1, 1, 0, 0}, {"nansisys", 8, 8, 0, 1, 0, 0, 0, 1, 1, 0, 0}, {"nansi.sysk", 10, 8, 0, 1, 0, 0, 0, 1, 1, 0, 0}, {"nansisysk", 9, 8, 0, 1, 0, 0, 0, 1, 1, 0, 0}, {"ncr160vt100an", 13, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"ncr160vt100pp", 13, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"ncr160vt100wan", 14, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"ncr160vt100wpp", 14, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"ncr160vt200an", 13, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"ncr160vt200pp", 13, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"ncr160vt200wan", 14, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"ncr160vt200wpp", 14, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"ncr160vt300an", 13, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"ncr160vt300pp", 13, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"ncr160vt300wan", 14, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"ncr160vt300wpp", 14, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"ncr260intan", 11, 8, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"ncr260intpp", 11, 8, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"ncr260intwan", 12, 8, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"ncr260intwpp", 12, 8, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"ncr260vt100an", 13, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"ncr260vt100pp", 13, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"ncr260vt100wan", 14, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"ncr260vt100wpp", 14, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"ncr260vt200an", 13, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"ncr260vt200pp", 13, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"ncr260vt200wan", 14, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"ncr260vt200wpp", 14, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"ncr260vt300an", 13, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"ncr260vt300pp", 13, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"ncr260vt300wan", 14, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"ncr260vt300wpp", 14, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"NCR260VT300WPP", 14, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"ncr260wy325pp", 13, 16, 0, 1, 1, 1, 0, 1, 0, 0, 0}, {"ncr260wy325wpp", 14, 16, 0, 1, 1, 1, 0, 1, 0, 0, 0}, {"ncr260wy350pp", 13, 16, 0, 1, 1, 1, 0, 1, 0, 0, 0}, {"ncr260wy350wpp", 14, 16, 0, 1, 1, 1, 0, 1, 0, 0, 0}, {"ncrvt100an", 10, -1, 1, 1, 1, 0, 0, 1, 1, 0, 0}, {"ncrvt100pp", 10, -1, 1, 1, 1, 0, 0, 1, 1, 0, 0}, {"ncrvt100wan", 11, -1, 1, 1, 1, 0, 0, 1, 1, 0, 0}, {"ncrvt100wpp", 11, -1, 1, 1, 1, 0, 0, 1, 1, 0, 0}, {"NCRVT100WPP", 11, -1, 1, 1, 1, 0, 0, 1, 1, 0, 0}, {"ncsa", 4, 8, 1, 1, 1, 1, 0, 1, 1, 1, 0}, {"ncsa-m", 6, -1, 1, 1, 1, 1, 0, 1, 1, 1, 0}, {"ncsa-m-ns", 9, -1, 1, 1, 1, 1, 0, 1, 1, 1, 0}, {"ncsa-ns", 7, 8, 1, 1, 1, 1, 0, 1, 1, 1, 0}, {"ncsa-vt220", 10, 8, 1, 1, 1, 1, 0, 1, 1, 1, 0}, {"ncsa-vt220-8", 12, -1, 1, 1, 1, 1, 0, 1, 1, 1, 0}, {"netbsd6", 7, 8, 1, 1, 1, 1, 2, 1, 1, 1, 0}, {"nsterm", 6, 256, 1, 1, 1, 1, 0, 1, 1, 1, 0}, {"nsterm-16color", 14, 16, 1, 1, 1, 1, 0, 1, 1, 1, 0}, {"nsterm-256color", 15, 256, 1, 1, 1, 1, 0, 1, 1, 1, 0}, {"nsterm+7", 8, -1, 1, 1, 1, 0, 0, 1, 1, 1, 0}, {"nsterm-7", 8, 8, 1, 1, 1, 0, 0, 1, 1, 1, 0}, {"nsterm-7-c", 10, 16, 1, 1, 1, 0, 0, 1, 1, 1, 0}, {"nsterm-7-c-s", 12, 16, 1, 1, 1, 0, 0, 1, 1, 1, 0}, {"nsterm-7-m", 10, -1, 1, 1, 1, 0, 0, 1, 1, 1, 0}, {"nsterm-7-m-s", 12, -1, 1, 1, 1, 0, 0, 1, 1, 1, 0}, {"nsterm-7-s", 10, 8, 1, 1, 1, 0, 0, 1, 1, 1, 0}, {"nsterm+acs", 10, -1, 1, 1, 1, 0, 0, 1, 1, 1, 0}, {"nsterm-acs", 10, 8, 1, 1, 1, 0, 0, 1, 1, 1, 0}, {"nsterm-acs-c", 12, 16, 1, 1, 1, 0, 0, 1, 1, 1, 0}, {"nsterm-acs-c-s", 14, 16, 1, 1, 1, 0, 0, 1, 1, 1, 0}, {"nsterm-acs-m", 12, -1, 1, 1, 1, 0, 0, 1, 1, 1, 0}, {"nsterm-acs-m-s", 14, -1, 1, 1, 1, 0, 0, 1, 1, 1, 0}, {"nsterm-acs-s", 12, 8, 1, 1, 1, 0, 0, 1, 1, 1, 0}, {"nsterm-bce", 10, 16, 1, 1, 1, 1, 0, 1, 1, 1, 0}, {"nsterm-build309", 15, 256, 1, 1, 1, 1, 0, 1, 1, 1, 0}, {"nsterm-build326", 15, 256, 1, 1, 1, 1, 0, 1, 1, 1, 0}, {"nsterm-build343", 15, 256, 1, 1, 1, 1, 0, 1, 1, 1, 0}, {"nsterm-build361", 15, 256, 1, 1, 1, 1, 0, 1, 1, 1, 0}, {"nsterm-build400", 15, 256, 1, 1, 1, 1, 0, 1, 1, 1, 0}, {"nsterm-build440", 15, 256, 1, 1, 1, 1, 0, 1, 1, 1, 0}, {"nsterm+c", 8, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {"nsterm-c", 8, 16, 1, 1, 1, 0, 0, 1, 1, 1, 0}, {"nsterm+c41", 10, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {"nsterm-c-7", 10, 16, 1, 1, 1, 0, 0, 1, 1, 1, 0}, {"nsterm-c-acs", 12, 16, 1, 1, 1, 0, 0, 1, 1, 1, 0}, {"nsterm-c-s", 10, 16, 1, 1, 1, 0, 0, 1, 1, 1, 0}, {"nsterm-c-s-7", 12, 16, 1, 1, 1, 0, 0, 1, 1, 1, 0}, {"nsterm-c-s-acs", 14, 16, 1, 1, 1, 0, 0, 1, 1, 1, 0}, {"nsterm-direct", 13, 16777216, 1, 1, 1, 1, 0, 1, 1, 1, 0}, {"nsterm-m", 8, -1, 1, 1, 1, 0, 0, 1, 1, 1, 0}, {"nsterm-m-7", 10, -1, 1, 1, 1, 0, 0, 1, 1, 1, 0}, {"nsterm+mac", 10, -1, 1, 1, 1, 0, 0, 1, 1, 1, 0}, {"nsterm-m-acs", 12, -1, 1, 1, 1, 0, 0, 1, 1, 1, 0}, {"nsterm-m-s", 10, -1, 1, 1, 1, 0, 0, 1, 1, 1, 0}, {"nsterm-m-s-7", 12, -1, 1, 1, 1, 0, 0, 1, 1, 1, 0}, {"nsterm-m-s-acs", 14, -1, 1, 1, 1, 0, 0, 1, 1, 1, 0}, {"nsterm-old", 10, 8, 1, 1, 1, 0, 0, 1, 1, 1, 0}, {"nsterm-s", 8, 8, 1, 1, 1, 0, 0, 1, 1, 1, 0}, {"nsterm-s-7", 10, 8, 1, 1, 1, 0, 0, 1, 1, 1, 0}, {"nsterm-s-acs", 12, 8, 1, 1, 1, 0, 0, 1, 1, 1, 0}, {"ntconsole", 9, 8, 1, 1, 1, 0, 2, 1, 0, 0, 0}, {"ntconsole-100", 13, 8, 1, 1, 1, 0, 2, 1, 0, 0, 0}, {"ntconsole-100-nti", 17, 8, 1, 1, 1, 0, 2, 1, 0, 0, 0}, {"ntconsole-25", 12, 8, 1, 1, 1, 0, 2, 1, 0, 0, 0}, {"ntconsole-25-nti", 16, 8, 1, 1, 1, 0, 2, 1, 0, 0, 0}, {"ntconsole-25-w", 14, 8, 1, 1, 1, 0, 2, 1, 0, 0, 0}, {"ntconsole-25-w-vt", 17, 8, 1, 1, 1, 0, 2, 1, 0, 0, 0}, {"ntconsole-35", 12, 8, 1, 1, 1, 0, 2, 1, 0, 0, 0}, {"ntconsole-35-nti", 16, 8, 1, 1, 1, 0, 2, 1, 0, 0, 0}, {"ntconsole-35-w", 14, 8, 1, 1, 1, 0, 2, 1, 0, 0, 0}, {"ntconsole-50", 12, 8, 1, 1, 1, 0, 2, 1, 0, 0, 0}, {"ntconsole-50-nti", 16, 8, 1, 1, 1, 0, 2, 1, 0, 0, 0}, {"ntconsole-50-w", 14, 8, 1, 1, 1, 0, 2, 1, 0, 0, 0}, {"ntconsole-60", 12, 8, 1, 1, 1, 0, 2, 1, 0, 0, 0}, {"ntconsole-60-nti", 16, 8, 1, 1, 1, 0, 2, 1, 0, 0, 0}, {"ntconsole-60-w", 14, 8, 1, 1, 1, 0, 2, 1, 0, 0, 0}, {"ntconsole-w", 11, 8, 1, 1, 1, 0, 2, 1, 0, 0, 0}, {"ntconsole-w-vt", 14, 8, 1, 1, 1, 0, 2, 1, 0, 0, 0}, {"nwp-517", 7, -1, 1, 1, 1, 0, 0, 1, 1, 1, 0}, {"nwp517", 6, -1, 1, 1, 1, 0, 0, 1, 1, 1, 0}, {"nwp-517-w", 9, -1, 1, 1, 1, 0, 0, 1, 1, 1, 0}, {"nwp517-w", 8, -1, 1, 1, 1, 0, 0, 1, 1, 1, 0}, {"nxterm", 6, 8, 1, 1, 1, 0, 0, 1, 1, 1, 0}, {"ofcons", 6, -1, 1, 1, 1, 0, 0, 0, 0, 0, 0}, {"old-st", 6, 8, 0, 1, 1, 1, 0, 1, 0, 0, 0}, {"opennt", 6, 8, 1, 1, 1, 0, 2, 1, 0, 0, 0}, {"opennt-100", 10, 8, 1, 1, 1, 0, 2, 1, 0, 0, 0}, {"opennt-100-nti", 14, 8, 1, 1, 1, 0, 2, 1, 0, 0, 0}, {"opennt-25", 9, 8, 1, 1, 1, 0, 2, 1, 0, 0, 0}, {"opennt-25-nti", 13, 8, 1, 1, 1, 0, 2, 1, 0, 0, 0}, {"opennt-25-w", 11, 8, 1, 1, 1, 0, 2, 1, 0, 0, 0}, {"opennt-25-w-vt", 14, 8, 1, 1, 1, 0, 2, 1, 0, 0, 0}, {"opennt-35", 9, 8, 1, 1, 1, 0, 2, 1, 0, 0, 0}, {"opennt-35-nti", 13, 8, 1, 1, 1, 0, 2, 1, 0, 0, 0}, {"opennt-35-w", 11, 8, 1, 1, 1, 0, 2, 1, 0, 0, 0}, {"opennt-50", 9, 8, 1, 1, 1, 0, 2, 1, 0, 0, 0}, {"opennt-50-nti", 13, 8, 1, 1, 1, 0, 2, 1, 0, 0, 0}, {"opennt-50-w", 11, 8, 1, 1, 1, 0, 2, 1, 0, 0, 0}, {"opennt-60", 9, 8, 1, 1, 1, 0, 2, 1, 0, 0, 0}, {"opennt-60-nti", 13, 8, 1, 1, 1, 0, 2, 1, 0, 0, 0}, {"opennt-60-w", 11, 8, 1, 1, 1, 0, 2, 1, 0, 0, 0}, {"opennt-nti", 10, 8, 1, 1, 1, 0, 2, 1, 0, 0, 0}, {"opennt-w", 8, 8, 1, 1, 1, 0, 2, 1, 0, 0, 0}, {"opennt-w-vt", 11, 8, 1, 1, 1, 0, 2, 1, 0, 0, 0}, {"p12", 3, -1, 1, 1, 1, 1, 0, 1, 0, 0, 0}, {"P12", 3, -1, 1, 1, 1, 1, 0, 1, 0, 0, 0}, {"p12-w", 5, -1, 1, 1, 1, 1, 0, 1, 0, 0, 0}, {"P12-W", 5, -1, 1, 1, 1, 1, 0, 1, 0, 0, 0}, {"p14", 3, -1, 1, 1, 1, 1, 0, 1, 0, 0, 0}, {"P14", 3, -1, 1, 1, 1, 1, 0, 1, 0, 0, 0}, {"p14-w", 5, -1, 1, 1, 1, 1, 0, 1, 0, 0, 0}, {"P14-W", 5, -1, 1, 1, 1, 1, 0, 1, 0, 0, 0}, {"p9", 2, -1, 1, 1, 1, 1, 0, 1, 0, 0, 0}, {"P9", 2, -1, 1, 1, 1, 1, 0, 1, 0, 0, 0}, {"p9-w", 4, -1, 1, 1, 1, 1, 0, 1, 0, 0, 0}, {"P9-W", 4, -1, 1, 1, 1, 1, 0, 1, 0, 0, 0}, {"pc3", 3, 8, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"pc3-bold", 8, 8, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"pc3r", 4, 8, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"pc3r-m", 6, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"pc7300", 6, -1, 1, 1, 1, 1, 0, 1, 0, 0, 0}, {"pcansi", 6, 8, 0, 1, 1, 0, 0, 1, 0, 0, 0}, {"pcansi-25", 9, 8, 0, 1, 1, 0, 0, 1, 0, 0, 0}, {"pcansi25", 8, 8, 0, 1, 1, 0, 0, 1, 0, 0, 0}, {"pcansi-33", 9, 8, 0, 1, 1, 0, 0, 1, 0, 0, 0}, {"pcansi33", 8, 8, 0, 1, 1, 0, 0, 1, 0, 0, 0}, {"pcansi-43", 9, 8, 0, 1, 1, 0, 0, 1, 0, 0, 0}, {"pcansi43", 8, 8, 0, 1, 1, 0, 0, 1, 0, 0, 0}, {"pccon", 5, 8, 1, 1, 1, 1, 0, 1, 1, 1, 0}, {"pccon0", 6, 8, 1, 1, 1, 0, 0, 1, 1, 0, 0}, {"pccon0-m", 8, -1, 1, 1, 1, 0, 0, 1, 1, 0, 0}, {"pccon+base", 10, -1, 1, 1, 1, 0, 0, 1, 1, 0, 0}, {"pccon+colors", 12, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {"pccon-m", 7, -1, 1, 1, 1, 1, 0, 1, 1, 1, 0}, {"pc-minix", 8, 8, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"pcplot", 6, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"pcvt25", 6, -1, 1, 1, 1, 1, 2, 1, 1, 0, 0}, {"pcvt25-color", 12, 8, 1, 1, 1, 1, 2, 1, 1, 0, 0}, {"pcvt25w", 7, -1, 1, 1, 1, 1, 2, 1, 1, 0, 0}, {"pcvt28", 6, -1, 1, 1, 1, 1, 2, 1, 1, 0, 0}, {"pcvt28w", 7, -1, 1, 1, 1, 1, 2, 1, 1, 0, 0}, {"pcvt35", 6, -1, 1, 1, 1, 1, 2, 1, 1, 0, 0}, {"pcvt35w", 7, -1, 1, 1, 1, 1, 2, 1, 1, 0, 0}, {"pcvt40", 6, -1, 1, 1, 1, 1, 2, 1, 1, 0, 0}, {"pcvt40w", 7, -1, 1, 1, 1, 1, 2, 1, 1, 0, 0}, {"pcvt43", 6, -1, 1, 1, 1, 1, 2, 1, 1, 0, 0}, {"pcvt43w", 7, -1, 1, 1, 1, 1, 2, 1, 1, 0, 0}, {"pcvt50", 6, -1, 1, 1, 1, 1, 2, 1, 1, 0, 0}, {"pcvt50w", 7, -1, 1, 1, 1, 1, 2, 1, 1, 0, 0}, {"pcvtXX", 6, -1, 1, 1, 1, 1, 2, 1, 1, 0, 0}, {"prism12", 7, -1, 1, 1, 1, 1, 0, 1, 0, 0, 0}, {"prism12-w", 9, -1, 1, 1, 1, 1, 0, 1, 0, 0, 0}, {"prism14", 7, -1, 1, 1, 1, 1, 0, 1, 0, 0, 0}, {"prism14-w", 9, -1, 1, 1, 1, 1, 0, 1, 0, 0, 0}, {"prism9", 6, -1, 1, 1, 1, 1, 0, 1, 0, 0, 0}, {"prism9-w", 8, -1, 1, 1, 1, 1, 0, 1, 0, 0, 0}, {"ps300", 5, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"pt100", 5, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"pt100w", 6, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"pt200", 5, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"pt200w", 6, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"pt250", 5, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"pt250w", 6, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"pt505", 5, -1, 1, 1, 1, 0, 2, 1, 1, 0, 0}, {"pt505-22", 8, -1, 1, 1, 1, 0, 2, 1, 1, 0, 0}, {"pt505-24", 8, -1, 1, 1, 1, 0, 2, 1, 1, 0, 0}, {"putty", 5, 8, 1, 1, 1, 1, 1, 1, 1, 1, 0}, {"putty-256color", 14, 256, 1, 1, 1, 1, 1, 1, 1, 1, 0}, {"putty-m1", 8, 8, 0, 1, 1, 1, 1, 1, 1, 0, 0}, {"putty-noapp", 11, 8, 1, 1, 1, 1, 1, 1, 1, 1, 0}, {"putty-sco", 9, 8, 1, 1, 1, 1, 1, 1, 1, 1, 0}, {"putty-screen", 12, 8, 1, 1, 1, 1, 1, 1, 1, 1, 0}, {"putty-vt100", 11, 8, 1, 1, 1, 1, 1, 1, 1, 1, 0}, {"Q306-8-pc", 9, -1, 1, 1, 1, 1, 0, 1, 0, 0, 0}, {"qansi", 5, 8, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"qansi-g", 7, 8, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"qansi-m", 7, 8, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"qansi-t", 7, 8, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"qansi-w", 7, 8, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"qnx", 3, 8, 0, 1, 1, 1, 0, 1, 0, 0, 0}, {"qnx4", 4, 8, 0, 1, 1, 1, 0, 1, 0, 0, 0}, {"qnxm", 4, 8, 0, 1, 1, 1, 0, 1, 0, 0, 0}, {"qnxt", 4, 8, 0, 1, 1, 1, 0, 1, 0, 0, 0}, {"qnxt2", 5, 8, 0, 1, 1, 0, 0, 1, 0, 0, 0}, {"qnxt4", 5, 8, 0, 1, 1, 1, 0, 1, 0, 0, 0}, {"qnxw", 4, 8, 0, 1, 1, 1, 0, 1, 0, 0, 0}, {"qvt103", 6, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"qvt103-w", 8, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"qvt203", 6, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"qvt203+", 7, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"qvt203-25", 9, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"qvt203-25-w", 11, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"qvt203-w", 8, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"qvt203-w-am", 11, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"rcons-color", 11, 8, 0, 1, 1, 0, 0, 0, 0, 0, 0}, {"rio", 3, 256, 1, 1, 1, 1, 1, 1, 1, 1, 0}, {"rio+base", 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 0}, {"rio-direct", 10, 16777216, 1, 1, 1, 1, 1, 1, 1, 1, 0}, {"rt6221", 6, -1, 1, 1, 1, 1, 0, 1, 0, 0, 0}, {"rt6221-w", 8, -1, 1, 1, 1, 1, 0, 1, 0, 0, 0}, {"rxvt", 4, 8, 1, 1, 1, 1, 2, 1, 1, 1, 0}, {"rxvt-16color", 12, 16, 1, 1, 1, 1, 2, 1, 1, 1, 0}, {"rxvt-256color", 13, 256, 1, 1, 1, 1, 2, 1, 1, 1, 0}, {"rxvt-88color", 12, 88, 1, 1, 1, 1, 2, 1, 1, 1, 0}, {"rxvt-basic", 10, -1, 1, 1, 1, 1, 2, 1, 1, 1, 0}, {"rxvt-color", 10, 8, 1, 1, 1, 1, 2, 1, 1, 1, 0}, {"rxvt-cygwin", 11, 8, 1, 1, 1, 1, 2, 1, 1, 1, 0}, {"rxvt-cygwin-native", 18, 8, 1, 1, 1, 1, 2, 1, 1, 1, 0}, {"rxvt-unicode", 12, 88, 1, 1, 1, 1, 2, 1, 1, 1, 0}, {"rxvt-unicode-256color", 21, 256, 1, 1, 1, 1, 2, 1, 1, 1, 0}, {"rxvt-xpm", 8, 8, 1, 1, 1, 1, 2, 1, 1, 1, 0}, {"s4", 2, -1, 1, 1, 1, 1, 0, 1, 0, 0, 0}, {"scoansi", 7, 8, 1, 1, 1, 1, 0, 1, 0, 0, 0}, {"scoansi-new", 11, 8, 1, 1, 1, 1, 0, 1, 0, 0, 0}, {"scoansi-old", 11, 8, 1, 1, 1, 1, 0, 1, 0, 0, 0}, {"screen", 6, 8, 1, 1, 1, 1, 0, 1, 1, 1, 0}, {"screen-16color", 14, 16, 1, 1, 1, 1, 0, 1, 1, 1, 0}, {"screen-16color-bce", 18, 16, 1, 1, 1, 1, 0, 1, 1, 1, 0}, {"screen-16color-bce-s", 20, 16, 1, 1, 1, 1, 0, 1, 1, 1, 0}, {"screen-16color-s", 16, 16, 1, 1, 1, 1, 0, 1, 1, 1, 0}, {"screen2", 7, -1, 1, 1, 1, 0, 2, 0, 0, 0, 0}, {"screen-256color", 15, 256, 1, 1, 1, 1, 0, 1, 1, 1, 0}, {"screen-256color-bce", 19, 256, 1, 1, 1, 1, 0, 1, 1, 1, 0}, {"screen-256color-bce-s", 21, 256, 1, 1, 1, 1, 0, 1, 1, 1, 0}, {"screen-256color-s", 17, 256, 1, 1, 1, 1, 0, 1, 1, 1, 0}, {"screen3", 7, -1, 1, 1, 1, 0, 2, 1, 0, 0, 0}, {"screen4", 7, 8, 1, 1, 1, 1, 0, 1, 1, 1, 0}, {"screen5", 7, 8, 1, 1, 1, 1, 0, 1, 1, 1, 0}, {"screen-base", 11, 8, 1, 1, 1, 1, 0, 1, 1, 1, 0}, {"screen-bce", 10, 8, 1, 1, 1, 1, 0, 1, 1, 1, 0}, {"screen-bce.Eterm", 16, 8, 1, 1, 1, 1, 2, 1, 1, 0, 0}, {"screen-bce.gnome", 16, 8, 1, 1, 1, 1, 2, 1, 1, 1, 0}, {"screen-bce.konsole", 18, 8, 1, 1, 1, 1, 2, 1, 1, 1, 0}, {"screen-bce.linux", 16, 8, 1, 1, 1, 1, 0, 1, 1, 1, 0}, {"screen-bce.mrxvt", 16, 8, 1, 1, 1, 1, 2, 1, 1, 1, 0}, {"screen-bce.rxvt", 15, 8, 1, 1, 1, 1, 2, 1, 1, 1, 0}, {"screen-bce.xterm-new", 20, 8, 1, 1, 1, 1, 2, 1, 1, 1, 0}, {"screen.Eterm", 12, 8, 1, 1, 1, 1, 2, 1, 1, 0, 0}, {"screen.gnome", 12, 8, 1, 1, 1, 1, 2, 1, 1, 1, 0}, {"screen.konsole", 14, 8, 1, 1, 1, 1, 2, 1, 1, 1, 0}, {"screen.konsole-256color", 23, 256, 1, 1, 1, 1, 2, 1, 1, 1, 0}, {"screen.linux", 12, 8, 1, 1, 1, 1, 0, 1, 1, 1, 0}, {"screen.linux-m1", 15, 8, 1, 1, 1, 1, 1, 1, 1, 0, 0}, {"screen.linux-m1b", 16, -1, 1, 1, 1, 1, 1, 1, 1, 0, 0}, {"screen.linux-m2", 15, -1, 1, 1, 1, 1, 1, 1, 1, 0, 0}, {"screen.linux-s", 14, 8, 1, 1, 1, 1, 0, 1, 1, 1, 0}, {"screen.minitel1", 15, 8, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"screen.minitel12-80", 19, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"screen.minitel1b", 16, 8, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"screen.minitel1b-80", 19, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"screen.minitel1b-nb", 19, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"screen.minitel1-nb", 18, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"screen.minitel2-80", 18, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"screen.mlterm", 13, 8, 1, 1, 1, 1, 2, 1, 1, 1, 0}, {"screen.mlterm-256color", 22, 256, 1, 1, 1, 1, 2, 1, 1, 1, 0}, {"screen.mrxvt", 12, 8, 1, 1, 1, 1, 2, 1, 1, 1, 0}, {"screen.putty", 12, 8, 1, 1, 1, 1, 1, 1, 1, 1, 0}, {"screen.putty-256color", 21, 256, 1, 1, 1, 1, 1, 1, 1, 1, 0}, {"screen.putty-m1", 15, 8, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"screen.putty-m1b", 16, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"screen.putty-m2", 15, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"screen.rxvt", 11, 8, 1, 1, 1, 1, 2, 1, 1, 1, 0}, {"screen-s", 8, 8, 1, 1, 1, 1, 0, 1, 1, 1, 0}, {"screen.teraterm", 15, 8, 1, 1, 1, 1, 0, 1, 1, 1, 0}, {"screen.vte", 10, 8, 1, 1, 1, 1, 1, 1, 1, 1, 0}, {"screen.vte-256color", 19, 256, 1, 1, 1, 1, 1, 1, 1, 1, 0}, {"screen-w", 8, 8, 1, 1, 1, 1, 0, 1, 1, 1, 0}, {"screen.xterm-256color", 21, 256, 1, 1, 1, 1, 2, 1, 1, 1, 0}, {"screen.xterm-new", 16, 8, 1, 1, 1, 1, 2, 1, 1, 1, 0}, {"screen.xterm-r6", 15, -1, 1, 1, 1, 0, 0, 1, 1, 1, 0}, {"screen.xterm-xfree86", 20, 8, 1, 1, 1, 1, 2, 1, 1, 1, 0}, {"scrhp", 5, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"scrt", 4, 256, 1, 1, 1, 1, 1, 1, 1, 1, 0}, {"securecrt", 9, 256, 1, 1, 1, 1, 1, 1, 1, 1, 0}, {"simpleterm", 10, 8, 0, 1, 1, 1, 0, 1, 0, 0, 0}, {"st", 2, 8, 1, 1, 1, 1, 2, 1, 1, 1, 0}, {"st-0.6", 6, 8, 1, 1, 1, 1, 2, 1, 1, 1, 0}, {"st-0.7", 6, 8, 1, 1, 1, 1, 2, 1, 1, 1, 0}, {"st-0.8", 6, 8, 1, 1, 1, 1, 2, 1, 1, 1, 0}, {"st-16color", 10, 16, 1, 1, 1, 1, 2, 1, 1, 1, 0}, {"st-256color", 11, 256, 1, 1, 1, 1, 2, 1, 1, 1, 0}, {"st52-color", 10, 16, 0, 1, 1, 1, 0, 1, 0, 0, 0}, {"st-direct", 9, 16777216, 1, 1, 1, 1, 2, 1, 1, 1, 0}, {"stterm", 6, 8, 1, 1, 1, 1, 2, 1, 1, 1, 0}, {"stterm-16color", 14, 16, 1, 1, 1, 1, 2, 1, 1, 1, 0}, {"stterm-256color", 15, 256, 1, 1, 1, 1, 2, 1, 1, 1, 0}, {"sun-color", 9, 8, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"sv80", 4, -1, 1, 1, 1, 0, 0, 1, 1, 0, 0}, {"tab", 3, -1, 1, 1, 1, 0, 0, 1, 1, 0, 0}, {"tab132", 6, -1, 1, 1, 1, 0, 0, 1, 1, 0, 0}, {"tab132-15", 9, -1, 1, 1, 1, 0, 0, 1, 1, 0, 0}, {"tab132-rv", 9, -1, 1, 1, 1, 0, 0, 1, 1, 0, 0}, {"tab132-w", 8, -1, 1, 1, 1, 0, 0, 1, 1, 0, 0}, {"tab132-w-rv", 11, -1, 1, 1, 1, 0, 0, 1, 1, 0, 0}, {"tek4105-30", 10, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"tek4105a", 8, -1, 1, 1, 1, 1, 0, 1, 0, 0, 0}, {"tek4106brl", 10, -1, 1, 1, 1, 1, 0, 1, 0, 0, 0}, {"tek4107brl", 10, -1, 1, 1, 1, 1, 0, 1, 0, 0, 0}, {"tek4109brl", 10, -1, 1, 1, 1, 1, 0, 1, 0, 0, 0}, {"tek4115", 7, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"tek4125", 7, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"tek4205", 7, 8, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"teken", 5, 8, 1, 1, 1, 1, 0, 1, 0, 0, 0}, {"teken-16color", 13, 16, 1, 1, 1, 1, 0, 1, 0, 0, 0}, {"teken-2018", 10, 8, 1, 1, 1, 1, 0, 1, 0, 0, 0}, {"teken-2022", 10, 8, 1, 1, 1, 1, 0, 1, 0, 0, 0}, {"teken-sc", 8, 8, 1, 1, 1, 1, 0, 1, 0, 0, 0}, {"teken-vt", 8, 8, 1, 1, 1, 1, 0, 1, 0, 0, 0}, {"teraterm", 8, 8, 1, 1, 1, 1, 0, 1, 1, 1, 0}, {"teraterm2.3", 11, 8, 1, 1, 1, 1, 0, 1, 1, 1, 0}, {"teraterm-256color", 17, 256, 1, 1, 1, 1, 0, 1, 1, 1, 0}, {"teraterm4.59", 12, 8, 1, 1, 1, 1, 0, 1, 1, 1, 0}, {"teraterm4.97", 12, 8, 1, 1, 1, 1, 0, 1, 1, 1, 0}, {"terminator", 10, 256, 1, 1, 1, 1, 2, 1, 1, 1, 0}, {"terminology", 11, 256, 1, 1, 1, 1, 1, 1, 1, 1, 0}, {"terminology-0.6.1", 17, 256, 1, 0, 0, 0, 0, 1, 1, 1, 0}, {"terminology-1.0.0", 17, 256, 1, 0, 0, 1, 0, 1, 1, 1, 0}, {"terminology-1.8.1", 17, 256, 1, 1, 1, 1, 1, 1, 1, 1, 0}, {"termite", 7, 256, 1, 1, 1, 1, 2, 1, 1, 1, 0}, {"ti916", 5, -1, 1, 1, 1, 1, 0, 1, 1, 1, 0}, {"ti916-132", 9, -1, 1, 1, 1, 1, 0, 1, 1, 1, 0}, {"ti916-220-7", 11, -1, 1, 1, 1, 1, 0, 1, 1, 1, 0}, {"ti916-220-8", 11, -1, 1, 1, 1, 1, 0, 1, 1, 1, 0}, {"ti916-8", 7, -1, 1, 1, 1, 1, 0, 1, 1, 1, 0}, {"ti916-8-132", 11, -1, 1, 1, 1, 1, 0, 1, 1, 1, 0}, {"ti928", 5, 8, 0, 1, 1, 0, 0, 1, 0, 0, 0}, {"ti928-8", 7, 8, 0, 1, 1, 0, 0, 1, 0, 0, 0}, {"ti_ansi", 7, 8, 0, 1, 1, 0, 0, 1, 0, 0, 0}, {"tmux", 4, 8, 1, 1, 1, 1, 1, 1, 1, 1, 0}, {"tmux-256color", 13, 256, 1, 1, 1, 1, 1, 1, 1, 1, 0}, {"tmux-direct", 11, 16777216, 1, 1, 1, 1, 1, 1, 1, 1, 0}, {"ts100", 5, -1, 1, 1, 1, 0, 0, 1, 1, 0, 0}, {"ts100-ctxt", 10, -1, 1, 1, 1, 0, 0, 1, 1, 0, 0}, {"ts100-sp", 8, -1, 1, 1, 1, 0, 0, 1, 1, 0, 0}, {"tt52", 4, 16, 0, 1, 1, 1, 0, 1, 0, 0, 0}, {"tty4424", 7, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"tty4424-1", 9, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"tty4426", 7, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"tty5420", 7, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"tty5420-nl", 10, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"tty5420-rv", 10, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"tty5420-rv-nl", 13, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"tty5420-w", 9, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"tty5420-w-nl", 12, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"tty5420-w-rv", 12, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"tty5420-w-rv-n", 14, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"tty5425", 7, -1, 1, 1, 1, 0, 0, 1, 1, 0, 0}, {"tty5425-nl", 10, -1, 1, 1, 1, 0, 0, 1, 1, 0, 0}, {"tty5425-w", 9, -1, 1, 1, 1, 0, 0, 1, 1, 0, 0}, {"tvi9065", 7, -1, 1, 1, 1, 1, 0, 1, 0, 0, 0}, {"tw100", 5, 8, 1, 1, 1, 1, 0, 1, 0, 0, 0}, {"tw52", 4, 16, 0, 1, 1, 1, 0, 1, 0, 0, 0}, {"tw52-color", 10, 16, 0, 1, 1, 1, 0, 1, 0, 0, 0}, {"tws2102-sna", 11, -1, 1, 1, 1, 1, 0, 1, 0, 0, 0}, {"tws2103", 7, -1, 1, 1, 1, 1, 0, 1, 0, 0, 0}, {"tws2103-sna", 11, -1, 1, 1, 1, 1, 0, 1, 0, 0, 0}, {"tws-generic", 11, -1, 1, 1, 1, 1, 0, 1, 0, 0, 0}, {"uniterm", 7, -1, 1, 1, 1, 0, 0, 1, 1, 1, 0}, {"uniterm49", 9, -1, 1, 1, 1, 0, 0, 1, 1, 1, 0}, {"unixpc", 6, -1, 1, 1, 1, 1, 0, 1, 0, 0, 0}, {"uts30", 5, -1, 1, 1, 1, 1, 0, 1, 0, 0, 0}, {"uwin", 4, 8, 0, 1, 1, 1, 2, 1, 1, 0, 0}, {"v200-nam", 8, -1, 1, 1, 1, 1, 0, 1, 1, 1, 0}, {"v320n", 5, -1, 1, 1, 1, 0, 0, 1, 1, 1, 0}, {"vi603", 5, -1, 1, 1, 1, 0, 0, 1, 1, 0, 0}, {"visa50", 6, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"visual603", 9, -1, 1, 1, 1, 0, 0, 1, 1, 0, 0}, {"vk100", 5, -1, 1, 1, 1, 0, 0, 0, 0, 0, 0}, {"vs100", 5, -1, 1, 1, 1, 0, 0, 1, 1, 1, 0}, {"vscode", 6, 256, 1, 1, 1, 1, 1, 1, 1, 1, 0}, {"vscode-direct", 13, 16777216, 1, 1, 1, 1, 1, 1, 1, 1, 0}, {"vt100", 5, -1, 1, 1, 1, 0, 0, 1, 1, 0, 0}, {"vt100+", 6, 8, 1, 1, 1, 0, 0, 1, 1, 1, 0}, {"vt100+4bsd", 10, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"vt100-am", 8, -1, 1, 1, 1, 0, 0, 1, 1, 0, 0}, {"vt100-bot-s", 11, -1, 1, 1, 1, 0, 0, 1, 1, 0, 0}, {"vt100-nam", 9, -1, 1, 1, 1, 0, 0, 1, 1, 0, 0}, {"vt100nam", 8, -1, 1, 1, 1, 0, 0, 1, 1, 0, 0}, {"vt100-nam-w", 11, -1, 1, 1, 1, 0, 0, 1, 1, 0, 0}, {"vt100-nav", 9, -1, 1, 1, 1, 0, 0, 1, 1, 0, 0}, {"vt100-nav-w", 11, -1, 1, 1, 1, 0, 0, 1, 1, 0, 0}, {"vt100-putty", 11, -1, 1, 1, 1, 0, 0, 1, 1, 0, 0}, {"vt100-s", 7, -1, 1, 1, 1, 0, 0, 1, 1, 0, 0}, {"vt100-s-bot", 11, -1, 1, 1, 1, 0, 0, 1, 1, 0, 0}, {"vt100-s-top", 11, -1, 1, 1, 1, 0, 0, 1, 1, 0, 0}, {"vt100-top-s", 11, -1, 1, 1, 1, 0, 0, 1, 1, 0, 0}, {"vt100-vb", 8, -1, 1, 1, 1, 0, 0, 1, 1, 0, 0}, {"vt100-w", 7, -1, 1, 1, 1, 0, 0, 1, 1, 0, 0}, {"vt100-w-am", 10, -1, 1, 1, 1, 0, 0, 1, 1, 0, 0}, {"vt100-w-nam", 11, -1, 1, 1, 1, 0, 0, 1, 1, 0, 0}, {"vt100-w-nav", 11, -1, 1, 1, 1, 0, 0, 1, 1, 0, 0}, {"vt102", 5, -1, 1, 1, 1, 0, 0, 1, 1, 0, 0}, {"vt102-nsgr", 10, -1, 1, 1, 1, 0, 0, 1, 1, 0, 0}, {"vt102-w", 7, -1, 1, 1, 1, 0, 0, 1, 1, 0, 0}, {"vt125", 5, -1, 1, 1, 1, 0, 0, 1, 1, 0, 0}, {"vt132", 5, -1, 1, 1, 1, 0, 0, 1, 1, 0, 0}, {"vt200", 5, -1, 1, 1, 1, 1, 0, 1, 1, 1, 0}, {"vt200-8", 7, -1, 1, 1, 1, 1, 0, 1, 0, 0, 0}, {"vt200-8bit", 10, -1, 1, 1, 1, 1, 0, 1, 0, 0, 0}, {"vt200-w", 7, -1, 1, 1, 1, 1, 0, 1, 1, 1, 0}, {"vt220", 5, -1, 1, 1, 1, 1, 0, 1, 1, 1, 0}, {"vt220-8", 7, -1, 1, 1, 1, 1, 0, 1, 0, 0, 0}, {"vt220-8bit", 10, -1, 1, 1, 1, 1, 0, 1, 0, 0, 0}, {"vt220-base", 10, -1, 1, 1, 1, 0, 0, 1, 1, 1, 0}, {"vt220-nam", 9, -1, 1, 1, 1, 1, 0, 1, 1, 1, 0}, {"vt220-w", 7, -1, 1, 1, 1, 1, 0, 1, 1, 1, 0}, {"vt300", 5, -1, 1, 1, 1, 1, 0, 1, 1, 1, 0}, {"vt300-nam", 9, -1, 1, 1, 1, 1, 0, 1, 1, 1, 0}, {"vt300-w", 7, -1, 1, 1, 1, 1, 0, 1, 1, 1, 0}, {"vt300-w-nam", 11, -1, 1, 1, 1, 1, 0, 1, 1, 1, 0}, {"vt320", 5, -1, 1, 1, 1, 1, 0, 1, 1, 1, 0}, {"vt320-k3", 8, -1, 1, 1, 1, 1, 0, 1, 0, 0, 0}, {"vt320-k311", 10, -1, 1, 1, 1, 1, 0, 1, 0, 0, 0}, {"vt320-nam", 9, -1, 1, 1, 1, 1, 0, 1, 1, 1, 0}, {"vt320nam", 8, -1, 1, 1, 1, 0, 0, 1, 1, 1, 0}, {"vt320-w", 7, -1, 1, 1, 1, 1, 0, 1, 1, 1, 0}, {"vt320-w-nam", 11, -1, 1, 1, 1, 1, 0, 1, 1, 1, 0}, {"vt330", 5, -1, 1, 1, 1, 1, 0, 1, 0, 0, 0}, {"vt340", 5, -1, 1, 1, 1, 1, 0, 1, 0, 0, 0}, {"vt400", 5, -1, 1, 1, 1, 1, 0, 1, 0, 0, 0}, {"vt400-24", 8, -1, 1, 1, 1, 1, 0, 1, 0, 0, 0}, {"vt420", 5, -1, 1, 1, 1, 1, 0, 1, 1, 1, 0}, {"vt420f", 6, -1, 1, 1, 1, 1, 0, 1, 1, 1, 0}, {"vt420pc", 7, -1, 1, 1, 1, 1, 0, 1, 1, 1, 0}, {"vt420pcdos", 10, -1, 1, 1, 1, 1, 0, 1, 1, 1, 0}, {"vt510", 5, -1, 1, 1, 1, 1, 0, 1, 1, 1, 0}, {"vt510pc", 7, -1, 1, 1, 1, 1, 0, 1, 1, 1, 0}, {"vt510pcdos", 10, -1, 1, 1, 1, 1, 0, 1, 1, 1, 0}, {"vt520", 5, -1, 1, 1, 1, 1, 0, 1, 1, 1, 0}, {"vt520ansi", 9, -1, 1, 1, 1, 1, 0, 1, 1, 1, 0}, {"vt525", 5, -1, 1, 1, 1, 1, 0, 1, 1, 1, 0}, {"vte", 3, 8, 1, 1, 1, 1, 1, 1, 1, 1, 0}, {"vte-2007", 8, 8, 1, 1, 1, 1, 2, 1, 1, 1, 0}, {"vte-2008", 8, 8, 1, 1, 1, 1, 2, 1, 1, 1, 0}, {"vte-2012", 8, 8, 1, 1, 1, 1, 2, 1, 1, 1, 0}, {"vte-2014", 8, 8, 1, 1, 1, 1, 2, 1, 1, 1, 0}, {"vte-2017", 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 0}, {"vte-2018", 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 0}, {"vte-256color", 12, 256, 1, 1, 1, 1, 1, 1, 1, 1, 0}, {"vte-direct", 10, 16777216, 1, 1, 1, 1, 1, 1, 1, 1, 0}, {"vtnt", 4, 8, 1, 1, 1, 0, 0, 1, 1, 1, 0}, {"vt-utf8", 7, 8, 1, 1, 1, 0, 0, 1, 1, 1, 0}, {"vv100", 5, 8, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"vwmterm", 7, 8, 1, 1, 1, 1, 0, 1, 0, 0, 0}, {"wezterm", 7, 256, 1, 1, 1, 1, 1, 1, 1, 1, 0}, {"winconsole", 10, 8, 1, 1, 1, 1, 0, 1, 0, 0, 0}, {"wren", 4, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"wrenw", 5, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"wsvt25", 6, 8, 1, 1, 1, 1, 2, 1, 1, 1, 0}, {"wsvt25m", 7, 8, 1, 1, 1, 1, 2, 1, 1, 1, 0}, {"wy185", 5, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"wy185-24", 8, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"wy185-vb", 8, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"wy185-w", 7, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"wy185-wvb", 9, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"wy350", 5, 8, 0, 1, 1, 1, 0, 1, 0, 0, 0}, {"wy350-vb", 8, 8, 0, 1, 1, 1, 0, 1, 0, 0, 0}, {"wy350-w", 7, 8, 0, 1, 1, 1, 0, 1, 0, 0, 0}, {"wy350-wvb", 9, 8, 0, 1, 1, 1, 0, 1, 0, 0, 0}, {"wy370", 5, 64, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"wy370-101k", 10, 64, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"wy370-105k", 10, 64, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"wy370-EPC", 9, 64, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"wy370-nk", 8, 64, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"wy370-rv", 8, 64, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"wy370-vb", 8, 64, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"wy370-w", 7, 64, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"wy370-wvb", 9, 64, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"wy520", 5, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"wy520-24", 8, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"wy520-36", 8, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"wy520-36pc", 10, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"wy520-36w", 9, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"wy520-36wpc", 11, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"wy520-48", 8, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"wy520-48pc", 10, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"wy520-48w", 9, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"wy520-48wpc", 11, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"wy520-epc", 9, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"wy520-epc-24", 12, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"wy520-epc-vb", 12, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"wy520-epc-w", 11, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"wy520-epc-wvb", 13, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"wy520-vb", 8, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"wy520-w", 7, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"wy520-wvb", 9, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"wy60-AT", 7, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"wy60-PC", 7, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"wy75", 4, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"wy-75ap", 7, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"wy75ap", 6, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"wy75-mc", 7, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"wy75-vb", 7, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"wy75-w", 6, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"wy75-wvb", 8, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"wy85", 4, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"wy85-8bit", 9, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"wy85-vb", 7, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"wy85-w", 6, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"wy85-wvb", 8, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"wy99a-ansi", 10, -1, 1, 1, 1, 1, 0, 1, 0, 0, 0}, {"wy99-ansi", 9, -1, 1, 1, 1, 1, 0, 1, 0, 0, 0}, {"wyse185", 7, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"wyse185-24", 10, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"wyse185-vb", 10, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"wyse185-w", 9, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"wyse185-wvb", 11, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"wyse350", 7, 8, 0, 1, 1, 1, 0, 1, 0, 0, 0}, {"wyse350-vb", 10, 8, 0, 1, 1, 1, 0, 1, 0, 0, 0}, {"wyse350-w", 9, 8, 0, 1, 1, 1, 0, 1, 0, 0, 0}, {"wyse350-wvb", 11, 8, 0, 1, 1, 1, 0, 1, 0, 0, 0}, {"wyse370", 7, 64, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"wyse520", 7, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"wyse520-24", 10, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"wyse520-36", 10, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"wyse520-36pc", 12, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"wyse520-36w", 11, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"wyse520-36wpc", 13, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"wyse520-48", 10, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"wyse520-48pc", 12, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"wyse520-48w", 11, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"wyse520-48wpc", 13, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"wyse520-epc", 11, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"wyse520-epc-w", 13, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"wyse520-pc-24", 13, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"wyse520-pc-vb", 13, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"wyse520-p-wvb", 13, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"wyse520-vb", 10, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"wyse520-w", 9, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"wyse520-wvb", 11, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"wyse60-AT", 9, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"wyse60-PC", 9, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"wyse75", 6, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"wyse-75ap", 9, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"wyse75ap", 8, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"wyse75-mc", 9, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"wyse75-vb", 9, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"wyse75-w", 8, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"wyse75-wvb", 10, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"wyse85", 6, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"wyse85-8bit", 11, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"wyse85-vb", 9, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"wyse85-w", 8, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"wyse85-wvb", 10, -1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"x68k", 4, -1, 1, 1, 1, 0, 0, 1, 1, 1, 0}, {"x68k-ite", 8, -1, 1, 1, 1, 0, 0, 1, 1, 1, 0}, {"xdku", 4, -1, 1, 1, 1, 1, 0, 1, 0, 0, 0}, {"xfce", 4, 8, 1, 1, 1, 1, 2, 1, 1, 1, 0}, {"xgterm", 6, -1, 1, 1, 1, 0, 0, 1, 1, 1, 0}, {"X-hpterm-color2", 15, 8, 0, 1, 1, 0, 0, 1, 0, 0, 0}, {"xiterm", 6, 8, 1, 1, 1, 0, 0, 1, 1, 1, 0}, {"xnuppc", 6, 8, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"xnuppc-100x37", 13, 8, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"xnuppc-100x37-m", 15, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"xnuppc-112x37", 13, 8, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"xnuppc-112x37-m", 15, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"xnuppc-128x40", 13, 8, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"xnuppc-128x40-m", 15, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"xnuppc-128x48", 13, 8, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"xnuppc-128x48-m", 15, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"xnuppc-144x48", 13, 8, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"xnuppc-144x48-m", 15, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"xnuppc-160x64", 13, 8, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"xnuppc-160x64-m", 15, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"xnuppc-200x64", 13, 8, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"xnuppc-200x64-m", 15, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"xnuppc-200x75", 13, 8, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"xnuppc-200x75-m", 15, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"xnuppc-256x96", 13, 8, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"xnuppc-256x96-m", 15, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"xnuppc-80x25", 12, 8, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"xnuppc-80x25-m", 14, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"xnuppc-80x30", 12, 8, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"xnuppc-80x30-m", 14, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"xnuppc-90x30", 12, 8, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"xnuppc-90x30-m", 14, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"xnuppc+b", 8, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"xnuppc-b", 8, 8, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"xnuppc+basic", 12, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"xnuppc+c", 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {"xnuppc+f", 8, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"xnuppc-f", 8, 8, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"xnuppc+f2", 9, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"xnuppc-f2", 9, 8, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"xnuppc-m", 8, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"xnuppc-m-b", 10, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"xnuppc-m-f", 10, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"xnuppc-m-f2", 11, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"xtalk", 5, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"xterm", 5, 8, 1, 1, 1, 1, 1, 1, 1, 1, 0}, {"xterm1", 6, 8, 1, 1, 1, 1, 1, 1, 1, 1, 0}, {"xterm-1002", 10, 8, 1, 1, 1, 1, 1, 1, 1, 1, 0}, {"xterm-1003", 10, 8, 1, 1, 1, 1, 1, 1, 1, 1, 0}, {"xterm-1005", 10, 8, 1, 1, 1, 1, 1, 1, 1, 1, 0}, {"xterm-1006", 10, 8, 1, 1, 1, 1, 1, 1, 1, 1, 0}, {"xterm-16color", 13, 16, 1, 1, 1, 1, 1, 1, 1, 1, 0}, {"xterm-24", 8, -1, 1, 1, 1, 0, 0, 1, 1, 1, 0}, {"xterm+256color", 14, 256, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {"xterm-256color", 14, 256, 1, 1, 1, 1, 1, 1, 1, 1, 0}, {"xterm+256color2", 15, 256, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {"xterm+256setaf", 14, 256, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {"xterm+88color", 13, 88, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {"xterm-88color", 13, 88, 1, 1, 1, 1, 1, 1, 1, 1, 0}, {"xterm+88color2", 14, 88, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {"xterm-8bit", 10, 8, 1, 1, 1, 1, 2, 1, 1, 1, 0}, {"xterm-basic", 11, 8, 1, 1, 1, 1, 1, 1, 1, 1, 0}, {"xterm-bold", 10, -1, 1, 1, 1, 0, 0, 1, 1, 1, 0}, {"xtermc", 6, 8, 1, 1, 1, 0, 0, 1, 1, 0, 0}, {"xterm-color", 11, 8, 1, 1, 1, 0, 0, 1, 1, 1, 0}, {"xterm+direct", 12, 16777216, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {"xterm-direct", 12, 16777216, 1, 1, 1, 1, 1, 1, 1, 1, 0}, {"xterm+direct16", 14, 16777216, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {"xterm-direct16", 14, 16777216, 1, 1, 1, 1, 1, 1, 1, 1, 0}, {"xterm+direct2", 13, 16777216, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {"xterm-direct2", 13, 16777216, 1, 1, 1, 1, 1, 1, 1, 1, 0}, {"xterm+direct256", 15, 16777216, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {"xterm-direct256", 15, 16777216, 1, 1, 1, 1, 1, 1, 1, 1, 0}, {"xterm-ghostty", 13, 256, 1, 1, 1, 1, 1, 1, 1, 1, 0}, {"xterm-hp", 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 0}, {"xterm+indirect", 14, 16777216, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {"xterm.js", 8, 256, 1, 1, 1, 1, 1, 1, 1, 1, 0}, {"xterm-kitty", 11, 256, 1, 1, 1, 1, 1, 1, 1, 1, 0}, {"xtermm", 6, -1, 1, 1, 1, 0, 0, 1, 1, 0, 0}, {"xterm-mono", 10, -1, 1, 1, 1, 0, 0, 1, 1, 1, 0}, {"xterm-new", 9, 8, 1, 1, 1, 1, 1, 1, 1, 1, 0}, {"xterm-nic", 9, 8, 1, 1, 1, 1, 1, 1, 1, 1, 0}, {"xterm-noapp", 11, 8, 1, 1, 1, 1, 1, 1, 1, 1, 0}, {"xterm+nofkeys", 13, 8, 1, 1, 1, 1, 1, 1, 1, 1, 0}, {"xterm-old", 9, -1, 1, 1, 1, 0, 0, 1, 1, 1, 0}, {"xterm-p370", 10, 8, 1, 1, 1, 1, 1, 1, 1, 1, 0}, {"xterm-p371", 10, 8, 1, 1, 1, 1, 1, 1, 1, 1, 0}, {"xterm-pcolor", 12, -1, 1, 1, 1, 0, 0, 1, 1, 1, 0}, {"xterm-r5", 8, -1, 1, 1, 1, 0, 0, 1, 1, 1, 0}, {"xterm-r6", 8, -1, 1, 1, 1, 0, 0, 1, 1, 1, 0}, {"xterms", 6, -1, 1, 1, 1, 0, 0, 1, 1, 1, 0}, {"xterm-sco", 9, 8, 1, 1, 1, 1, 1, 1, 1, 1, 0}, {"xterms-sun", 10, 8, 1, 1, 1, 1, 1, 1, 1, 1, 0}, {"xterm-sun", 9, 8, 1, 1, 1, 1, 1, 1, 1, 1, 0}, {"xterm-utf8", 10, 8, 1, 1, 1, 1, 1, 1, 1, 1, 0}, {"xterm-vt220", 11, 8, 1, 1, 1, 1, 1, 1, 1, 1, 0}, {"xterm-x10mouse", 14, 8, 1, 1, 1, 1, 1, 1, 1, 1, 0}, {"xterm-x11hilite", 15, 8, 1, 1, 1, 1, 1, 1, 1, 1, 0}, {"xterm-x11mouse", 14, 8, 1, 1, 1, 1, 1, 1, 1, 1, 0}, {"xterm-xf86-v32", 14, 8, 1, 1, 1, 1, 0, 1, 1, 1, 0}, {"xterm-xf86-v33", 14, 8, 1, 1, 1, 1, 0, 1, 1, 1, 0}, {"xterm-xf86-v333", 15, 8, 1, 1, 1, 1, 2, 1, 1, 1, 0}, {"xterm-xf86-v40", 14, 8, 1, 1, 1, 1, 2, 1, 1, 1, 0}, {"xterm-xf86-v43", 14, 8, 1, 1, 1, 1, 2, 1, 1, 1, 0}, {"xterm-xf86-v44", 14, 8, 1, 1, 1, 1, 2, 1, 1, 1, 0}, {"xterm-xfree86", 13, 8, 1, 1, 1, 1, 2, 1, 1, 1, 0}, {"xterm-xi", 8, 8, 1, 1, 1, 1, 0, 1, 1, 1, 0}, {"xwsh", 4, 8, 1, 1, 1, 0, 2, 1, 1, 1, 0}, {"yaft-256color", 13, 256, 1, 1, 1, 1, 0, 1, 1, 0, 0}, {"z29a", 4, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"z29a-kc-bc", 10, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"z29a-kc-uc", 10, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"z29a-nkc-bc", 11, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"z29a-nkc-uc", 11, -1, 1, 1, 1, 0, 0, 1, 0, 0, 0}, {"z340", 4, -1, 1, 1, 1, 1, 0, 1, 1, 1, 0}, {"z340-nam", 8, -1, 1, 1, 1, 1, 0, 1, 1, 1, 0}, {"z39-a", 5, -1, 1, 1, 1, 1, 0, 1, 0, 0, 0}, {"z39a", 4, -1, 1, 1, 1, 1, 0, 1, 0, 0, 0}, {"zenith39-a", 10, -1, 1, 1, 1, 1, 0, 1, 0, 0, 0}, {"zenith39-ansi", 13, -1, 1, 1, 1, 1, 0, 1, 0, 0, 0}, {NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, }; #endif /* TERM_INFO_H */ clifm-1.26.3/src/translate_key.c000066400000000000000000000714651506632037700165230ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* translate_key.c -- Translate keyboard escape sequences into text form */ #include /* malloc, free, strtol */ #include /* snprintf */ #include /* strlen, strcmp, strchr, memcpy, memset */ #include /* INT_MIN, INT_MAX */ #include /* toupper() */ #include /* ENOMEM */ #include "translate_key.h" /* See https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-PC-Style-Function-Keys */ /* When it comes to keyboard escape sequences, we have three kind of * terminating characters: * * 1. Defining the keycode. E.g. 'CSI 1;2D', where 'D' means the key pressed, * (Left), and '2' the modifier key (Shift). * * 2. Defining the modifier key. E.g.: 'CSI 11^', where '^' means the * modifier key (Control) and '11' the key pressed (F1). * * 3. Raw sequence terminator. E.g. 'CSI 15;3~', where '~' simply * ends the sequence, '15' is the pressed key (F5), and '3' the modifier * key (Alt). Under this category we also find Xterm's MOK (modifyOtherKeys) * and the Kitty keyboard protocol. */ /* This translation module supports the following encoding schemes: * 1. SCO (legacy) * 2. HP (legacy) * 3. Sun (CSI-z) * 4. Xterm * 5. Xterm (modifyOtherKeys) * 6. Rxvt * 7. Fixterms (CSI-u) * 8. Kitty (extended CSI-u) * 9. Foot (extended CSI-u) * * Also, it can handle quirks/execeptions via the exceptions struct. */ #define IS_DIGIT(c) ((c) >= '0' && (c) <= '9') #define IS_UTF8_LEAD_BYTE(c) (((c) & 0xc0) == 0xc0) #define IS_LOWER_ARROW_CHAR(c) ((c) >= 'a' && (c) <= 'd') #define IS_UPPER_ARROW_CHAR(c) ((c) >= 'A' && (c) <= 'D') #define IS_ARROW_CHAR(c) (IS_LOWER_ARROW_CHAR((c)) || IS_UPPER_ARROW_CHAR((c))) /* Xterm, with modifyOtherKeys resource enabled */ #define IS_XTERM_MOK_SEQ(s, end) (*(s) == '2' && (s)[1] == '7' \ && (s)[2] == ';' && (end) == '~') /* The kitty keyboard protocol */ #define IS_KITTY_END_CHAR(c) ((c) == 'u') #define IS_MODKEY_END_CHAR(c) ((c) == '^' || (c) == '$' || (c) == '@') /* ~: Xterm & others, z: SUN. */ #define IS_GENERIC_END_CHAR(c) ((c) == '~' || (c) == 'z') #define IS_KEYCODE_END_CHAR(c) ( \ IS_ARROW_CHAR((c)) || \ ((c) >= 'E' && (c) <= 'I') || \ ((c) >= 'P' && (c) <= 'S') || \ ((c) >= 'j' && (c) <= 'y') || \ (c) == 'M' || (c) == 'X') #define ESC_KEY 0x1b /* Values for modifier keys. * See https://en.wikipedia.org/wiki/ANSI_escape_code */ #define MOD_SHIFT 1 #define MOD_ALT 2 #define MOD_CTRL 4 /* Unused #define MOD_SUPER 8 #define MOD_HYPER 16 #define MOD_META 32 */ /* Some names for control keys. */ static const char *ctrl_keys[256] = { [0x7f] = "Delete", [0x0d] = "Return", [0x08] = "Backspace", [0x09] = "Tab", [0x20] = "Space", [0x1b] = "Escape" }; /* VT100/SCO sequences predates ANSI X3.64 and ECMA-48, just as Xterm and Rxvrt * standardized sequences. They're emitted by the FreeBSD console, cons25 * (DragonFly, for example), and Xterm in SCO keyboard mode ('xterm -kt sco'). * * The format is: "CSI n", where n is a single byte. * * Modifier keys are not encoded in any way. Instead, the final CSI byte * represents both the key and the modifier. * * See https://github.com/freebsd/freebsd-src/blob/fb37e38fbe99039a479520b4b596f4bfc04e2a88/usr.sbin/kbdcontrol/kbdcontrol.c * https://vt100.net/docs/vt510-rm/chapter6.html * https://www.invisible-island.net/xterm/xterm-function-keys.html * and keyboard(4) in FreeBSD/Dragonfly. */ static const char *key_map_sco[256] = { ['A'] = "Up", ['B'] = "Down", ['C'] = "Right", ['D'] = "Left", ['E'] = "Begin", ['F'] = "End", ['G'] = "PageDown", ['H'] = "Home", ['I'] = "PageUp", ['L'] = "Insert", ['J'] = "LSuper", ['~'] = "RSuper", ['}'] = "Menu", ['M'] = "F1", ['N'] = "F2", ['O'] = "F3", ['P'] = "F4", ['Q'] = "F5", ['R'] = "F6", ['S'] = "F7", ['T'] = "F8", ['U'] = "F9", ['V'] = "F10", ['W'] = "F11", ['X'] = "F12", ['Y'] = "Shift+F1", ['Z'] = "Shift+F2", ['a'] = "Shift+F3", ['b'] = "Shift+F4", ['c'] = "Shift+F5", ['d'] = "Shift+F6", ['e'] = "Shift+F7", ['f'] = "Shift+F8", ['g'] = "Shift+F9", ['h'] = "Shift+F10", ['i'] = "Shift+F11", ['j'] = "Shift+F12", ['k'] = "Ctrl+F1", ['l'] = "Ctrl+F2", ['m'] = "Ctrl+F3", ['n'] = "Ctrl+F4", ['o'] = "Ctrl+F5", ['p'] = "Ctrl+F6", ['q'] = "Ctrl+F7", ['r'] = "Ctrl+F8", ['s'] = "Ctrl+F9", ['t'] = "Ctrl+F10", ['u'] = "Ctrl+F11", ['v'] = "Ctrl+F12", ['w'] = "Ctrl+Shift+F1", ['x'] = "Ctrl+Shift+F2", ['y'] = "Ctrl+Shift+F3", ['z'] = "Ctrl+Shift+F4", ['@'] = "Ctrl+Shift+F5", ['['] = "Ctrl+Shift+F6", ['\\'] = "Ctrl+Shift+F7", [']'] = "Ctrl+Shift+F8", ['^'] = "Ctrl+Shift+F9", ['_'] = "Ctrl+Shift+F10", ['`'] = "Ctrl+Shift+F11", ['{'] = "Ctrl+Shift+F12" }; static const char *key_map_hp[256] = { ['h'] = "Home", ['p'] = "F1", ['q'] = "F2", ['r'] = "F3", ['s'] = "F4", ['t'] = "F5", ['u'] = "F6", ['v'] = "F7", ['w'] = "F8", ['A'] = "Up", ['B'] = "Down", ['C'] = "Right", ['D'] = "Left", ['F'] = "End", ['J'] = "Clear", ['P'] = "Delete", ['Q'] = "Insert", ['S'] = "PageDown", ['T'] = "PageUp" }; static const char *key_map_generic[256] = { /* According to Rxvt docs: 1:Find, 3:Execute (but also Delete), 4:Select * However, 4 is End and 1 is Home in the Linux console and * cygwin/tmux/screen. */ [1] = "Home", [4] = "End", [2] = "Insert", [3] = "Delete", [5] = "PageUp", [6] = "PageDown", [7] = "Home", [8] = "End", /* 9 and 10 are normally not used. Some mappings found (on rare/old terms): 9: F0, F3, F33, F34, and Clear 10: F4, F10, F34, and F35 */ [11] = "F1", [12] = "F2", [13] = "F3", [14] = "F4", [15] = "F5", [17] = "F6", [18] = "F7", [19] = "F8", [20] = "F9", [21] = "F10", /* In Rxvt, Shift+[F1,F2] generates the same sequence as F11-F12. * There's nothing we can do about it. */ [23]= "F11", [24] = "F12", /* In Rxvt, these integers are mapped to either a function key above * F12, or to the shifted number - 10. E.g., 25 is both F13 and Shift+F3. * See https://pod.tst.eu/http://cvs.schmorp.de/rxvt-unicode/doc/rxvt.7.pod#Key_Codes * We chose the Shift approach, since Shift+F3 is much more intuitive than * F13. */ [25] = "Shift+F3", [26] = "Shift+F4", [28] = "Shift+F5", [31] = "Shift+F7", [32] = "Shift+F8", [33] = "Shift+F9", [34] = "Shift+F10", [29]= "Menu", /* In Rxvt, Shift+F6 and Menu generate the same sequence. Again, there's * nothing we can do about it. */ [42] = "F21", [43] = "F22", [44] = "F23", [45] = "F24", [46] = "F25", [47] = "F26", [48] = "F27", [49] = "F28", [50] = "F29", [51] = "F30", [52] = "F31", [53] = "F32", [54] = "F33", [55] = "F34", [56] = "F35", [57] = "F36", [58] = "F37", [59] = "F38", [60] = "F39", [61] = "F40", [62] = "F41", [63] = "F42", /* See https://invisible-island.net/ncurses/terminfo.src.html#tic-xterm-new */ ['A'] = "Up", ['B'] = "Down", ['C'] = "Right", ['D'] = "Left", /* Rxvt */ /* See https://cvs.schmorp.de/rxvt-unicode/doc/rxvt.7.pod */ ['a'] = "Up", ['b'] = "Down", ['c'] = "Right", ['d'] = "Left", ['j'] = "KP_Multiply", ['k'] = "KP_Add", ['l'] = "KP_Separator", ['m'] = "KP_Subtract", ['M'] = "KP_Enter", ['n'] = "KP_Delete", ['o'] = "KP_Divide", ['p'] = "KP_Insert", ['q'] = "KP_End", ['r'] = "KP_Down", ['s'] = "KP_PageDown", ['t'] = "KP_Left", ['u'] = "KP_Begin", ['v'] = "KP_Right", ['w'] = "KP_Home", ['x'] = "KP_Up", ['y'] = "KP_PageUp", ['X'] = "KP_Equal", /* Found in old VT keyboards (VT52, VT220) */ ['I'] = "KP_Tab", /* Xterm */ ['E'] = "Begin", ['F'] = "End", ['H'] = "Home", ['P'] = "F1", ['Q'] = "F2", ['R'] = "F3", ['S'] = "F4", /* Linux console */ ['G'] = "Begin", /* Sun/Solaris */ [192] = "F11", [193] = "F12", [194] = "F13", [195] = "F14", [196] = "F15", [198] = "F17", [199] = "F18", [200] = "F19", [201] = "F20", [208] = "F31", [209] = "F32", [210] = "F33", [211] = "F34", [212] = "F35", [213] = "F36", [215] = "F38", [217] = "F40", [219] = "F42", [221] = "F44", [234] = "F46", [235] = "F47", /* According to terminfo, kcpy is "CSI 197z", while kf16 is "CSI 29~" */ [197] = "Menu", /* These ones conflict with the above function keys * [195] = "Undo", [196] = "Help", [200] = "Find", */ [214] = "Home", [216] = "PageUp", [218] = "Begin", [220] = "End", [222] = "PageDown", [224] = "F1", [225] = "F2", [226] = "F3", [227] = "F4", [228] = "F5", [229] = "F6", [230] = "F7", [231] = "F8", [232] = "F9", [233] = "F10" }; struct ext_keymap_t { const char *name; int code; }; /* An extended list of key symbols and their corresponding key codes. * This includes control characters, just as XTerm, Kitty, and Foot * extended keys. */ static const struct ext_keymap_t ext_keymap[] = { {"NULL", 0}, {"SOH", 1}, {"STX", 2}, {"ETX", 3}, {"EOT", 4}, {"ENQ", 5}, {"ACK", 6}, {"BELL", 7}, {"Backspace", 8}, {"Tab", 9}, {"LF", 10}, {"VT", 11}, {"FF", 12}, {"Return", 13}, {"SO", 14}, {"SI", 15}, {"DLE", 16}, {"DC1", 17}, {"DC2", 18}, {"DC3", 19}, {"DC4", 20}, {"NAK", 21}, {"SYN", 22}, {"ETB", 23}, {"CAN", 24}, {"EM", 25}, {"SUB", 26}, {"Escape", 27}, {"FS", 28}, {"GS", 29}, {"RS", 30}, {"US", 31}, {"Space", 32}, {"Delete", 127}, {"NBSP", 160}, {"SHY", 173}, /* Xterm special keys */ {"AudioLowerVolume", 24849}, {"AudioRaiseVolume", 24851}, {"AudioMute", 24850}, {"AudioStop", 24853}, {"AudioPrev", 24854}, {"AudioPlay", 24852}, {"AudioNext", 24855}, {"Tools", 24961}, {"Mail", 24857}, {"HomePage", 24856}, {"Search", 24859}, {"Calculator", 24861}, {"Tab", 57632}, {"Left", 57937}, {"Up", 57938}, {"Right", 57939}, {"Down", 57940}, {"Insert", 57955}, {"Home", 57936}, {"End", 57943}, {"PageUp", 57941}, {"PageDown", 57942}, {"Menu", 57959}, {"PrintScreen", 57953}, {"KP_Enter", 57997}, {"KP_0", 58014}, {"KP_Decimal", 58015}, {"KP_1", 58012}, {"KP_2", 58009}, {"KP_3", 58011}, {"KP_4", 58006}, {"KP_5", 58013}, {"KP_6", 58008}, {"KP_7", 58005}, {"KP_8", 58007}, {"KP_9", 58010}, {"KP_Insert", 58032}, {"KP_Delete", 58030}, {"KP_End", 58033}, {"KP_Down", 58034}, {"KP_PageDown", 58035}, {"KP_Left", 58036}, {"KP_Begin", 58037}, {"KP_Right", 58038}, {"KP_Home", 58039}, {"KP_Up", 58040}, {"KP_PageUp", 58041}, {"KP_Divide", 58031}, {"KP_Multiply", 58026}, {"KP_Subtract", 58029}, {"KP_Add", 58027}, {"F1", 58046}, {"F2", 58047}, {"F3", 58048}, {"F4", 58049}, {"F5", 58050}, {"F6", 58051}, {"F7", 58052}, {"F8", 58053}, {"F9", 58054}, {"F10", 58055}, {"F11", 58056}, {"F12", 58057}, /* Kitty CSI u extended keys */ {"CapsLock", 57358}, {"ScrollLock", 57359}, {"NumLock", 57360}, {"PrintScreen", 57361}, {"Pause", 57362}, {"Menu", 57363}, {"F13", 57376}, {"F14", 57377}, {"F15", 57378}, {"F16", 57379}, {"F17", 57380}, {"F18", 57381}, {"F19", 57382}, {"F20", 57383}, {"F21", 57384}, {"F22", 57385}, {"F23", 57386}, {"F24", 57387}, {"F25", 57388}, {"F26", 57389}, {"F27", 57390}, {"F28", 57391}, {"F29", 57392}, {"F30", 57393}, {"F31", 57394}, {"F32", 57395}, {"F33", 57396}, {"F34", 57397}, {"F35", 57398}, {"KP_0", 57399}, {"KP_1", 57400}, {"KP_2", 57401}, {"KP_3", 57402}, {"KP_4", 57403}, {"KP_5", 57404}, {"KP_6", 57405}, {"KP_7", 57406}, {"KP_8", 57407}, {"KP_9", 57408}, {"KP_Decimal", 57409}, {"KP_Divide", 57410}, {"KP_Multiply", 57411}, {"KP_Subtract", 57412}, {"KP_Add", 57413}, {"KP_Enter", 57414}, {"KP_Equal", 57415}, {"KP_Separator", 57416}, {"KP_Left", 57417}, {"KP_Right", 57418}, {"KP_Up", 57419}, {"KP_Down", 57420}, {"KP_PageUp", 57421}, {"KP_PageDown", 57422}, {"KP_Home", 57423}, {"KP_End", 57424}, {"KP_Insert", 57425}, {"KP_Delete", 57426}, {"KP_Begin", 57427}, {"AudioPlay", 57428}, {"MediaPause", 57429}, {"MediaPlayPause", 57430}, {"MediaReverse", 57431}, {"AudioStop", 57432}, {"MediaFastForward", 57433}, {"MediaRewind", 57434}, {"AudioNext", 57435}, {"AudioPrev", 57436}, {"MediaRecord", 57437}, {"AudioLowerVolume", 57438}, {"AudioRaiseVolume", 57439}, {"AudioMute", 57440}, {"LShift", 57441}, {"LControl", 57442}, {"LAlt", 57443}, {"LSuper", 57444}, {"LHyper", 57445}, {"LMeta", 57446}, {"RShift", 57447}, {"RControl", 57448}, {"RAlt", 57449}, {"RSuper", 57450}, {"RHyper", 57451}, {"RMeta", 57452}, {"ISO_Level3_Shift", 57453}, {"ISO_Level5_Shift", 57454}, /* Foot (modifyOtherKeys extensions) */ {"KP_Enter", 65421}, {"KP_Multiply", 65450}, {"KP_Add", 65451}, {"KP_Separator", 65452}, {"KP_Subtract", 65453}, {"KP_Delete", 65454}, {"KP_Divide", 65455}, {"KP_Insert", 65456}, {"KP_End", 65457}, {"KP_Down", 65458}, {"KP_PageDown", 65459}, {"KP_Left", 65460}, {"KP_Begin", 65461}, {"KP_Right", 65462}, {"KP_Home", 65463}, {"KP_Up", 65464}, {"KP_PageUp", 65465}, {NULL, 0} }; struct exceptions_t { const char *key; const char *name; }; /* A list of escape sequences missed by our identifying algorithms, mostly * because they do not seem to follow any recognizable pattern. */ static const struct exceptions_t exceptions[] = { /* The Linux console uses CSI final bytes A-E for F1-F5, when A-D * is almost universally used for arrow keys. */ {"\x1b[[A", "F1"}, {"\x1b[[B", "F2"}, {"\x1b[[C", "F3"}, {"\x1b[[D", "F4"}, {"\x1b[[E", "F5"}, /* St * Keycodes and modifiers are not used consistently. For example, * "CSI 2J" is Shift+Home: '2' for Shift and 'J' for Home. But, * "CSI J" is Ctrl+End: no modifier (it should be '5') and 'J' is not * Home anymore, but Del. * Also, while "CSI P", is Del, "CSI 2K" is Shift+Del and "CSI K" is Shift+End. * Also, while "CSI L" is Ctrl+Ins, "CSI 4l" is Shift+Ins. */ {"\x1b[4h", "Insert"}, {"\x1b[M", "Ctrl+Delete"}, {"\x1b[L", "Ctrl+Insert"}, {"\x1b[2J", "Shift+Home"}, {"\x1b[K", "Shift+End"}, {"\x1b[2K", "Shift+Delete"}, {"\x1b[J", "Ctrl+End"}, {"\x1b[4l", "Shift+Insert"}, {"\x1b[P", "Delete"}, {NULL, NULL} }; /* The linux console uses CSI [25-33]~ for Shift+[F1-F8]: this conflicts with * rxvt, which uses the same codes for Shift+[F3-F10]. */ static const char * fix_linux_func_keys(const int keycode, const int mod_key, const char *key) { if (mod_key != 0) return key; switch (keycode) { case 25: return "Shift+F1"; case 26: return "Shift+F2"; case 28: return "Shift+F3"; case 29: return "Shift+F4"; case 31: return "Shift+F5"; case 32: return "Shift+F6"; case 33: return "Shift+F7"; case 34: return "Shift+F8"; default: return key; } } /* A safe atoi */ static int xatoi(const char *str) { if (!str || !*str) return 0; char *endptr = NULL; const long n = strtol(str, &endptr, 10); if (endptr == str) return 0; if (n > INT_MAX) return INT_MAX; if (n < INT_MIN) return INT_MIN; return (int)n; } /* Return the translated key for the escape sequence STR looking in the * exceptions list. If none is found, NULL is returned. */ static char * check_exceptions(const char *str, const int term_type) { if (term_type == TK_TERM_LEGACY_SCO || term_type == TK_TERM_LEGACY_HP) return NULL; /* Fix conflict with st: 'CSI P' is F1 in Kitty and Del in st. */ if (term_type == TK_TERM_KITTY && *str == ESC_KEY && str[1] == CSI_INTRODUCER && str[2] == 'P' && !str[3]) return NULL; for (size_t i = 0; exceptions[i].key; i++) { if (strcmp(exceptions[i].key, str) == 0) { const size_t len = strlen(exceptions[i].name); /* flawfinder: ignore */ char *p = malloc((len + 1) * sizeof(char)); if (!p) return NULL; memcpy(p, exceptions[i].name, len + 1); return p; } } return NULL; } /* Return 1 if the byte C ends a keyboard escape sequence, or 0 otherwise. */ int is_end_seq_char(unsigned char c) { return (c != 0x1b /* First byte of an escape sequence */ && c != CSI_INTRODUCER && c != SS3_INTRODUCER && ((c >= 0x40 && c <= 0x7e) /* ECMA-48 terminating bytes */ || c == '$')); /* Rxvt uses this (E.g. "CSI 24$" for Shift+F12) */ } static int is_sco_seq(const int csi_seq, const char *seq, const size_t end) { return (csi_seq == 1 && seq[end] != '~'); } static int is_hp_seq(const unsigned char c) { return ((c == 'h' || (c >= 'p' && c <= 'w') || (c >= 'A' && c <= 'D') || c == 'F' || c == 'J' || c == 'P' || c == 'Q' || c == 'S' || c == 'T')); } /* Rxvt uses '$', '^', and '@' to indicate the modifier key. */ static void set_end_char_is_mod_key(char *str, const size_t end, int *keycode, int *mod_key) { const char end_char = str[end]; if (*str == ESC_KEY) { *mod_key += MOD_ALT; str += 2; /* Skip "ESC [" */ } str[end] = '\0'; *keycode = xatoi(str); /* Rxvt function keys F13-F20 (integers 25-34), excluding the Menu key * (or F16, integer 29). */ const char is_func_key = (*keycode >= 25 && *keycode <= 34 && *keycode != 29); if (end_char == '$') *mod_key += (!is_func_key ? MOD_SHIFT : 0); else /* Either '^' (Ctrl) or '@' (Ctrl+Shift) */ *mod_key += MOD_CTRL + ((end_char == '@' && !is_func_key) ? MOD_SHIFT : 0); } /* The terminating character just terminates the string. Mostly '~', but * also 'z' is Sun/Solaris terminals. In this case, the pressed key and * the modifier key are defined as parameters in the sequence. */ static void set_end_char_is_generic(char *str, const size_t end, int *keycode, int *mod_key) { str[end] = '\0'; char *s = strchr(str, ';'); if (*str == ESC_KEY) { if (!s) { /* Rxvt */ *mod_key += MOD_ALT; *keycode = xatoi(str + 2); return; } /* Skip 0x1b and '[' (if any) */ str += str[1] == CSI_INTRODUCER ? 2 : 1; } if (s) *s = '\0'; /* "CSI >1;key;mod~" = Xterm with modifyFunctionKeys:3 */ *keycode = xatoi(str + (*str == '>')); *mod_key += (s && s[1]) ? xatoi(s + 1) - 1 : 0; } static void set_end_char_is_keycode_no_arrow(char *str, const size_t end, int *keycode, int *mod_key) { *keycode = str[end]; char *s = strchr(str, ';'); str[end] = '\0'; if (s) { *mod_key += s[1] ? xatoi(s + 1) - 1 : 0; } else { if (*str == ESC_KEY) { /* Rxvt */ *mod_key += MOD_ALT; str++; } if (*str == SS3_INTRODUCER) /* Contour (SS3 mod key) */ str++; *mod_key += *str ? xatoi(str) - 1 : 0; } } /* The terminating character desginates the key pressed. Mostly arrow keys * (e.g. CSI D) for the Left key. * Note: When set to application mode (CSI ?1h - DECCKM) arrow keys are * transmitted as SS3 sequences (otherwise, as CSI sequences, most of the time). * However, we don't care about this: we can parse both sequences equally well. */ static void set_end_char_is_keycode(char *str, size_t end, int *keycode, int *mod_key) { if (!IS_ARROW_CHAR(str[end])) { set_end_char_is_keycode_no_arrow(str, end, keycode, mod_key); return; } *keycode = str[end]; char *s = strchr(str, ';'); if (*str == ESC_KEY && !s) { /* Rxvt */ *mod_key += MOD_ALT; str++; end--; } if (s) { str[end] = '\0'; *mod_key += (s && s[1]) ? xatoi(s + 1) - 1 : 0; } else if (IS_LOWER_ARROW_CHAR(str[end])) { /* Rxvt */ if (*str == SS3_INTRODUCER) *mod_key += MOD_CTRL; else *mod_key += MOD_SHIFT; } else if (IS_UPPER_ARROW_CHAR(str[end])) { str[end] = '\0'; if (*str == SS3_INTRODUCER) str++; if (IS_DIGIT(*str)) *mod_key += xatoi(str) - 1; } } /* Translate the modifier number MOD_KEY into human-readable form. */ static const char * get_mod_symbol(const int mod_key) { if (mod_key <= 0) return NULL; /* The biggest value mod_key can take is 255 (since * 1 + 2 + 4 + 8 + 16 + 32 + 64 + 128 = 255). In this case, the modifier * string would be "Shift+Alt+Ctrl+Super+Hyper+Meta+CapsLock+NumLock-", * which is 50 bytes long, including the terminating NUL byte. */ static char mod[64]; memset(mod, '\0', sizeof(mod)); const int m = mod_key; const size_t s = sizeof(mod); int l = 0; if (m & 128) l += snprintf(mod + l, s - (size_t)l, "NumLock+"); if (m & 64) l += snprintf(mod + l, s - (size_t)l, "CapsLock+"); if (m & 32) l += snprintf(mod + l, s - (size_t)l, "Meta+"); if (m & 16) l += snprintf(mod + l, s - (size_t)l, "Hyper+"); if (m & 8) l += snprintf(mod + l, s - (size_t)l, "Super+"); if (m & 4) l += snprintf(mod + l, s - (size_t)l, "Ctrl+"); if (m & 2) l += snprintf(mod + l, s - (size_t)l, "Alt+"); if (m & 1) snprintf(mod + l, s - (size_t)l, "Shift+"); return mod; } /* Max output string length */ #define MAX_BUF 256 #define SYM(n) (get_mod_symbol((n))) static char * print_non_esc_seq(const char *str) { char *buf = malloc(MAX_BUF * sizeof(char)); if (!buf) return NULL; if (!str || !*str) { free(buf); return NULL; } const unsigned char *s = (const unsigned char *)str; if (s[1]) { snprintf(buf, MAX_BUF, "%s", s); /* A string, not a byte */ } else if (ctrl_keys[*s]) { /* Backspace, Tab, Return, Space, Del */ snprintf(buf, MAX_BUF, "%s", ctrl_keys[*s]); } else if (*s < 0x20) { /* Control characters */ snprintf(buf, MAX_BUF, "%s%c", SYM(MOD_CTRL), *s + '@' + 0x20); } else { free(buf); return NULL; } return buf; } static char * check_single_key(char *str, const int csi_seq, const int term_type) { char *buf = malloc(MAX_BUF * sizeof(char)); if (!buf) return NULL; while (*str == ESC_KEY) /* Skip extra leading 0x1b */ str++; if (!*str) { snprintf(buf, MAX_BUF, "%s", ctrl_keys[(unsigned char)ESC_KEY]); return buf; } /* Alt+UTF-8 */ if (IS_UTF8_LEAD_BYTE(*str) && csi_seq == 0) { snprintf(buf, MAX_BUF, "%s%s", SYM(MOD_ALT), (unsigned char *)str); return buf; } if (str[1]) { /* More than 1 byte after ESC */ free(buf); return NULL; } if (*str == 'Z' && csi_seq == 1 && term_type != TK_TERM_LEGACY_SCO && term_type != TK_TERM_LEGACY_HP) { snprintf(buf, MAX_BUF, "%sTab", SYM(MOD_SHIFT)); return buf; } if (csi_seq == 0) { unsigned char *s = (unsigned char *)str; if (ctrl_keys[*s]) /* Backspace, Tab, Return, Space, Del */ snprintf(buf, MAX_BUF, "%s%s", SYM(MOD_ALT), ctrl_keys[*s]); else if (*s < 0x20) snprintf(buf, MAX_BUF, "%s%c", SYM(MOD_CTRL + MOD_ALT), *s + '@' + 0x20); else if (term_type != TK_TERM_LEGACY_HP || !is_hp_seq(*s)) snprintf(buf, MAX_BUF, "%s%c", SYM(MOD_ALT), *s); else return NULL; return buf; } free(buf); return NULL; } #undef MAX_BUF #undef SYM static const char * get_ext_key_symbol(const int keycode, const int term_type) { /* These are directly printable */ if (keycode > 32 && keycode <= 126) { static char keysym_str[2] = {0}; keysym_str[0] = (char)keycode; return keysym_str; } if (term_type == TK_TERM_XTERM && (keycode == 19 || keycode == 20)) return keycode == 20 ? "ScrollLock" : "Pause"; /* Linear search through ext_keymap */ for (size_t i = 0; ext_keymap[i].name != NULL; i++) { if (ext_keymap[i].code == keycode) return ext_keymap[i].name; } /* Transform a UTF-8 codepoint into a string of bytes. */ static char str[5] = ""; memset(str, 0, sizeof(str)); if (keycode <= 0x7ff) { str[0] = (char)(0xc0 | (keycode >> 6)); str[1] = (char)(0x80 | (keycode & 0x3f)); } else if (keycode <= 0x7fff) { str[0] = (char)(0xe0 | (keycode >> 12)); str[1] = (char)(0x80 | ((keycode >> 6) & 0x3f)); str[2] = (char)(0x80 | (keycode & 0x3f)); } else if (keycode <= 0x10ffff) { str[0] = (char)(0xf0 | (keycode >> 18)); str[1] = (char)(0x80 | ((keycode >> 12) & 0x3f)); str[2] = (char)(0x80 | ((keycode >> 6) & 0x3f)); str[3] = (char)(0x80 | (keycode & 0x3f)); } else { return "Unknown"; } return str; } static char * write_kitty_keys(char *str, const size_t end, const int term_type) { str[end] = '\0'; int keycode = -1; int mod_key = 0; char *delim = strchr(str, ';'); if (delim) { *delim = '\0'; keycode = xatoi(str); mod_key = delim[1] ? xatoi(delim + 1) - 1 : 0; } else { keycode = xatoi(str); } const char *k = keycode != -1 ? get_ext_key_symbol(keycode, term_type) : NULL; const char *m = mod_key != 0 ? get_mod_symbol(mod_key) : NULL; if (!k) return NULL; const size_t buf_len = strlen(k) + (m ? strlen(m) : 0) + 1; /* flawfinder: ignore */ char *buf = malloc(buf_len * sizeof(char)); if (!buf) return NULL; snprintf(buf, buf_len, "%s%s", m ? m : "", k); return buf; } /* An Xterm MOK (modifyOtherKeys) sequence is "CSI 27;mod;key~" * Note that, if formatOtherKeys is set to 1, "CSI u" sequences are used * instead, in which case they are covered by the kitty functions. * See https://xterm.dev/manpage-xterm/#VT100-Widget-Resources:modifyOtherKeys */ static char * write_xterm_mok_seq(char *str, const size_t end, const int term_type) { str[end] = '\0'; str += 3; /* Skip "27;" */ char *s = strchr(str, ';'); if (!s) return NULL; *s = '\0'; const int mod_key = xatoi(str) - 1; const int keycode = xatoi(s + 1); const char *k = get_ext_key_symbol(keycode, term_type); const char *m = (mod_key >= 0 && mod_key <= 255) ? get_mod_symbol((int)mod_key) : NULL; const size_t len = (m ? strlen(m) : 0) + (k ? strlen(k) : 0) + 2; /* flawfinder: ignore */ char *buf = malloc(len * sizeof(char)); if (!buf) return NULL; snprintf(buf, len, "%s%s", m ? m : "", k); return buf; } static const char ** get_keymap(const int term_type) { switch (term_type) { case TK_TERM_LEGACY_SCO: return key_map_sco; case TK_TERM_LEGACY_HP: return key_map_hp; case TK_TERM_GENERIC: /* fallthrough */ default: return key_map_generic; } } static char * write_translation(const int keycode, const int mod_key, const int term_type) { const char **keymap = get_keymap(term_type); const char *k = (keycode >= 0 && keycode <= 255) ? keymap[(unsigned char)keycode] : NULL; const char *m = (mod_key >= 0 && mod_key <= 255) ? get_mod_symbol((int)mod_key) : NULL; if (!k) return NULL; if (term_type == TK_TERM_LINUX) k = fix_linux_func_keys(keycode, mod_key, k); const size_t len = (m ? strlen(m) : 0) + strlen(k) + 1; /* flawfinder: ignore */ char *buf = malloc(len * sizeof(char)); if (!buf) return NULL; if (m) snprintf(buf, len, "%s%s", m, k); else snprintf(buf, len, "%s", k); return buf; } static int normalize_seq(char **seq, const int term_type) { char *s = *seq; const int csi_seq = (s[1] == CSI_INTRODUCER || (unsigned char)*s == ALT_CSI); s += s[1] == CSI_INTRODUCER ? 2 : 1; while ((unsigned char)*s == ALT_CSI) /* Skip extra 0x9b */ s++; /* Skip extra '['. The Linux console, for example, is known to emit * a double CSI introducer for function keys (e.g. "ESC [[A" for F1). */ while ((unsigned char)*s == CSI_INTRODUCER && term_type != TK_TERM_LEGACY_SCO) s++; *seq = s; return csi_seq; } /* Legacy mode: either SCO or HP keyboard mode. */ static char * write_legacy_keys(char *seq, const size_t end, const int term_type) { char *s = strchr(seq, ';'); const int mod_key = (s && s[1]) ? xatoi(s + 1) - 1 : 0; return write_translation(seq[end], mod_key, term_type); } /* Translate the escape sequence STR into the corresponding symbolic value. * E.g. "\x1b[1;7D" will return "Ctrl+Alt+Left". If no symbolic value is * found, NULL is returned. * The returned value, if not NULL, is dinamically allocated and must be * free'd by the caller. * * TERM_TYPE is one of the TK_TERM values (defined in translate_key.h). * It defines how SEQ will be translated. * * NOTE: This function assumes STR comes directly from the terminal, i.e. by * reading terminal input in raw mode. User suplied input, therefore, will * return false positives. */ char * translate_key(char *seq, const int term_type) { if (!seq || !*seq) return NULL; if (*seq != ESC_KEY && (unsigned char)*seq != ALT_CSI) return print_non_esc_seq(seq); char *buf = check_exceptions(seq, term_type); if (buf) return buf; const int csi_seq = normalize_seq(&seq, term_type); buf = check_single_key(seq, csi_seq, term_type); if (buf) return buf; int keycode = -1; int mod_key = 0; const size_t len = strlen(seq); /* flawfinder: ignore */ const size_t end = len > 0 ? len - 1 : len; const char end_char = seq[end]; if (term_type == TK_TERM_LEGACY_HP && end_char != '~') return write_legacy_keys(seq, end, term_type); if (term_type == TK_TERM_LEGACY_SCO && is_sco_seq(csi_seq, seq, end)) return write_legacy_keys(seq, end, term_type); if (IS_KITTY_END_CHAR(end_char) && csi_seq == 1) return write_kitty_keys(seq, end, term_type); if (IS_XTERM_MOK_SEQ(seq, end_char) && csi_seq == 1) return write_xterm_mok_seq(seq, end, term_type); else if (IS_MODKEY_END_CHAR(end_char)) set_end_char_is_mod_key(seq, end, &keycode, &mod_key); else if (IS_KEYCODE_END_CHAR(end_char)) set_end_char_is_keycode(seq, end, &keycode, &mod_key); else if (IS_GENERIC_END_CHAR(end_char)) set_end_char_is_generic(seq, end, &keycode, &mod_key); else return NULL; const int tt = (term_type == TK_TERM_LEGACY_HP || term_type == TK_TERM_LEGACY_SCO) ? TK_TERM_GENERIC : term_type; return write_translation(keycode, mod_key, tt); } clifm-1.26.3/src/translate_key.h000066400000000000000000000030611506632037700165130ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* translate_key.h */ #ifndef TRANSLATE_KEY_H #define TRANSLATE_KEY_H /* Terminal types */ #define TK_TERM_GENERIC 0 #define TK_TERM_LEGACY_SCO (1 << 0) #define TK_TERM_LEGACY_HP (1 << 1) #define TK_TERM_KITTY (1 << 2) #define TK_TERM_LINUX (1 << 3) /* For the time being, these ones are unused */ #define TK_TERM_XTERM (1 << 4) #define TK_TERM_RXVT (1 << 5) #define TK_TERM_ST (1 << 6) #define ALT_CSI 0x9b /* 8-bit CSI (alternate sequence) */ #define CSI_INTRODUCER 0x5b /* [ */ #define SS3_INTRODUCER 0x4f /* O */ __BEGIN_DECLS char *translate_key(char *str, const int term_type); int is_end_seq_char(unsigned char c); __END_DECLS #endif /* TRANSLATE_KEY_H */ clifm-1.26.3/src/trash.c000066400000000000000000000761771506632037700150040ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* trash.c -- functions to manage the trash system */ #ifndef _NO_TRASH #include "helpers.h" #include #include #include /* access, unlinkat */ /* , required by time(2) and localtime_r(2), is included by "aux.h" */ #if defined(MAC_OS_X_RENAMEAT_SYS_STDIO_H) # include /* renameat(2) */ #endif /* MAC_OS_X_RENAMEAT_SYS_STDIO_H */ #include "aux.h" /* gen_date_suffix, count_dir, open_fwrite, open_fread, xatoi, url_encode, xnmalloc, print_file_name */ #include "checks.h" /* is_file_in_cwd, is_number */ #include "colors.h" /* colors_list */ #include "listing.h" /* reload_dirlist */ #include "misc.h" /* xerror, print_reload_msg */ #include "navigation.h" /* xchdir */ #include "properties.h" /* get_color_size */ #include "readline.h" /* rl_no_hist, rl_get_y_or_n */ #include "sort.h" /* skip_files, xalphasort, alphasort_insensitive */ #include "spawn.h" /* launch_execv */ #include "xdu.h" /* dir_size */ /* Return the number of currently trashed files. */ static size_t count_trashed_files(void) { size_t n = 0; if (trash_ok == 1 && trash_files_dir != NULL) { filesn_t ret = count_dir(trash_files_dir, NO_CPOP); n = ret <= 2 ? 0 : (size_t)ret - 2; } return n; } /* Confirm the removal of N files from the trash can. * Return 1 if yes or 0 if not. */ static int confirm_removal(const size_t n) { if (conf.rm_force == 1) return 1; /* Yes */ char msg[256]; /* Big enough, in case of translations. */ snprintf(msg, sizeof(msg), _("Remove %zu file(s)?"), n); return rl_get_y_or_n(msg, conf.default_answer.remove); } /* We have removed N files from the trash can. Print the results. */ static void print_removal_result(const size_t n) { if (conf.autols == 1) reload_dirlist(); const size_t cur = (n <= trash_n ? (trash_n - n) : 0); if (cur == 0) { print_reload_msg(SET_SUCCESS_PTR, xs_cb, _("Trash can emptied: %zu file(s) removed\n"), n); } else { print_reload_msg(SET_SUCCESS_PTR, xs_cb, _("%zu file(s) removed from the trash can\n"), n); print_reload_msg(NULL, NULL, _("%zu total trashed file(s)\n"), cur); } } /* Remove the file named NAME and the corresponding .trashinfo file from * the trash can. * Returns 0 on success or >0 on error. */ static int remove_file_from_trash(const char *name) { size_t len = strlen(name) + 11; char *info_file = xnmalloc(len, sizeof(char)); snprintf(info_file, len, "%s.trashinfo", name); len = strlen(trash_files_dir) + strlen(name) + 2; char *file1 = xnmalloc(len, sizeof(char)); snprintf(file1, len, "%s/%s", trash_files_dir, name); len = strlen(trash_info_dir) + strlen(info_file) + 2; char *file2 = xnmalloc(len, sizeof(char)); snprintf(file2, len, "%s/%s", trash_info_dir, info_file); char *cmd[] = {"rm", "-rf", "--", file1, file2, NULL}; int ret = launch_execv(cmd, FOREGROUND, E_NOFLAG); free(file1); free(file2); free(info_file); return ret; } /* Empty the trash can. */ static int trash_clear(void) { if (trash_n == 0) { puts(_("trash: No trashed files")); return FUNC_SUCCESS; } if (confirm_removal(trash_n) == 0) return FUNC_SUCCESS; DIR *dir = opendir(trash_files_dir); if (!dir) { xerror("trash: '%s': %s\n", trash_files_dir, strerror(errno)); return errno; } int exit_status = FUNC_SUCCESS; size_t n = 0; size_t removed = 0; struct dirent *ent; while ((ent = readdir(dir))) { if (SELFORPARENT(ent->d_name)) continue; const int ret = remove_file_from_trash(ent->d_name); if (ret != FUNC_SUCCESS) exit_status = ret; else removed++; n++; } closedir(dir); if (n == 0) { puts(_("trash: No trashed files")); } else { if (exit_status != FUNC_SUCCESS && conf.autols == 1) press_any_key_to_continue(0); print_removal_result(removed); } return exit_status; } static int gen_trashinfo_file(char *file, const char *suffix, const struct tm *tm) { /* Encode path to URL format (RF 2396) */ char *url_str = url_encode(file, 0); if (!url_str) { xerror(_("trash: '%s': Error encoding path\n"), file); return FUNC_FAILURE; } const size_t len = strlen(trash_info_dir) + strlen(suffix) + 12; char *info_file = xnmalloc(len, sizeof(char)); snprintf(info_file, len, "%s/%s.trashinfo", trash_info_dir, suffix); int fd = open(info_file, O_WRONLY | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR); FILE *fp; if (fd == -1 || !(fp = fdopen(fd, "w"))) { const int saved_errno = errno; if (fd != -1) close(fd); xerror("trash: '%s': %s\n", info_file, strerror(saved_errno)); free(info_file); free(url_str); return saved_errno; } fprintf(fp, "[Trash Info]\nPath=%s\nDeletionDate=%d-%02d-%02dT%02d:%02d:%02d\n", url_str, tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); free(url_str); free(info_file); fclose(fp); return FUNC_SUCCESS; } static void remove_trashinfo_file(const char *name) { const size_t len = strlen(trash_info_dir) + strlen(name) + 12; char *info_file = xnmalloc(len, sizeof(char)); snprintf(info_file, len, "%s/%s.trashinfo", trash_info_dir, name); if (unlink(info_file) == -1) { err('w', PRINT_PROMPT, "trash: Cannot remove info file '%s': %s\n", info_file, strerror(errno)); } free(info_file); } /* Create the trashed filename: orig_filename.suffix, where SUFFIX is * the current date and time (plus an integer in case of dups). * Returns the absolute path to this file and updates FILE_SUFFIX to * its basename. */ static char * gen_dest_file(const char *file, const char *suffix, char **file_suffix) { char *filename = strrchr(file, '/'); if (!filename || !*(++filename)) { xerror(_("trash: '%s': Error getting file base name\n"), file); return (char *)NULL; } /* If the length of the trashed filename (orig_filename.suffix) is * longer than NAME_MAX (255), trim the original filename, so that * (original_filename_len + 1 (dot) + suffix_len) won't be longer * than NAME_MAX. */ const size_t filename_len = strlen(filename); const size_t suffix_len = strlen(suffix); const int size = (int)(filename_len + suffix_len + 11) - NAME_MAX; /* len = filename.suffix.trashinfo */ if (size > 0) { /* THIS IS NOT UNICODE AWARE */ /* If SIZE is a positive value, that is, the trashed filename * exceeds NAME_MAX by SIZE bytes, reduce the original filename * SIZE bytes. Terminate the original filename (FILENAME) with * a tilde (~), to let the user know it was trimmed. */ filename[filename_len - (size_t)size - 1] = '~'; filename[filename_len - (size_t)size] = '\0'; } const size_t slen = filename_len + suffix_len + 2 + 16; *file_suffix = xnmalloc(slen, sizeof(char)); snprintf(*file_suffix, slen, "%s.%s", filename, suffix); /* NOTE: It is guaranteed (by check_trash_file(), called before from * trash_file_args()) that FILE does not end with a slash. */ const size_t dlen = strlen(trash_files_dir) + strlen(*file_suffix) + 2 + 16; char *dest = xnmalloc(dlen, sizeof(char)); snprintf(dest, dlen, "%s/%s", trash_files_dir, *file_suffix); /* If the destination file exists (there's already a trashed file with * this name), append an integer until it is made unique. */ struct stat a; int inc = 1; while (lstat(dest, &a) == 0 && inc > 0) { snprintf(*file_suffix, slen, "%s.%s-%d", filename, suffix, inc); snprintf(dest, dlen, "%s/%s", trash_files_dir, *file_suffix); inc++; } return dest; } static int trash_file(const char *suffix, const struct tm *tm, char *file) { struct stat attr; if (lstat(file, &attr) == -1) { xerror(_("trash: Cannot trash '%s': %s\n"), file, strerror(errno)); return errno; } char *tmpfile = file; char full_path[PATH_MAX + 1]; if (*file != '/') { /* If relative path, make it absolute. */ if (!workspaces[cur_ws].path) return FUNC_FAILURE; if (*workspaces[cur_ws].path == '/' && !workspaces[cur_ws].path[1]) { /* We're in the root dir */ snprintf(full_path, sizeof(full_path), "/%s", file); } else { snprintf(full_path, sizeof(full_path), "%s/%s", workspaces[cur_ws].path, file); } tmpfile = full_path; } char *file_suffix = (char *)NULL; char *dest = gen_dest_file(tmpfile, suffix, &file_suffix); /* As per the FreeDesktop specification, generate the info file first. */ if (!dest || !file_suffix || gen_trashinfo_file(tmpfile, file_suffix, tm) != FUNC_SUCCESS) { free(dest); free(file_suffix); return FUNC_FAILURE; } /* Move the original file into the trash directory. */ int mvcmd = 0; int ret = renameat(XAT_FDCWD, file, XAT_FDCWD, dest); if (ret != FUNC_SUCCESS && errno == EXDEV) { /* Destination file is on a different filesystem, which is why * renameat(2) fails: let's try with mv(1). */ char *tmp_cmd[] = {"mv", "--", file, dest, NULL}; ret = launch_execv(tmp_cmd, FOREGROUND, E_NOFLAG); mvcmd = 1; } free(dest); if (ret != FUNC_SUCCESS) { remove_trashinfo_file(file_suffix); free(file_suffix); if (mvcmd == 0) xerror(_("trash: Cannot trash '%s': %s\n"), file, strerror(errno)); return (mvcmd == 1 ? ret : errno); } free(file_suffix); return ret; } /* 't del FILE...' */ static int remove_from_trash_params(char **args) { size_t rem_files = 0; size_t i; int exit_status = FUNC_SUCCESS; int all = 0; for (i = 0; args[i]; i++) { if (*args[i] == '*' && !args[i][1]) { all = 1; break; } } if (all == 1) return trash_clear(); if (i > 0 && confirm_removal(i) == 0) return FUNC_SUCCESS; for (i = 0; args[i]; i++) { char *d = (char *)NULL; if (strchr(args[i], '\\')) d = unescape_str(args[i], 0); const int ret = remove_file_from_trash(d ? d : args[i]); if (ret != FUNC_SUCCESS) exit_status = ret; else rem_files++; free(d); } if (exit_status != FUNC_SUCCESS && conf.autols == 1) press_any_key_to_continue(0); print_removal_result(rem_files); return exit_status; } static int print_trashfiles(struct dirent ***ent, const int files_n) { /* Let's change to the trash dir to get the correct file colors */ if (xchdir(trash_files_dir, NO_TITLE) == -1) { xerror("trash: '%s': %s\n", trash_files_dir, strerror(errno)); return FUNC_FAILURE; } printf(_("%s%sTrashed files%s\n\n"), df_c, BOLD, df_c); /* Enable trash suffix removal in colors_list() to get correct file * color by extension. */ flags |= STATE_COMPLETING; cur_comp_type = TCMP_UNTRASH; const uint8_t tpad = DIGINUM(files_n); size_t i; for (i = 0; i < (size_t)files_n; i++) { printf("%s%*zu%s ", el_c, tpad, i + 1, df_c); colors_list((*ent)[i]->d_name, NO_ELN, NO_PAD, PRINT_NEWLINE); } flags &= ~STATE_COMPLETING; cur_comp_type = TCMP_NONE; if (xchdir(workspaces[cur_ws].path, NO_TITLE) == -1) { xerror("trash: '%s': %s\n", workspaces[cur_ws].path, strerror(errno)); return FUNC_FAILURE; } return FUNC_SUCCESS; } static char ** list_and_get_input(struct dirent ***trash_files, const int files_n, const int is_untrash) { if (conf.clear_screen > 0) CLEAR; const int ret = print_trashfiles(trash_files, files_n); if (ret != FUNC_SUCCESS) return (char **)NULL; /* Get input */ printf(_("\n%sEnter 'q' to quit\n" "File(s) to be %s (e.g.: 1 2-6, or *):\n"), df_c, is_untrash == 1 ? _("restored") : _("removed")); char *line = (char *)NULL; char tprompt[(MAX_COLOR * 2) + 7]; snprintf(tprompt, sizeof(tprompt), "\001%s\002>\001%s\002 ", mi_c, tx_c); while (!line) line = rl_no_hist(tprompt, 0); const filesn_t tfiles = files; files = (filesn_t)trash_n; char **input = get_substr(line, ' ', 1); files = tfiles; free(line); return input; } static void free_files_and_input(char ***input, struct dirent ***tfiles, const int tfiles_n) { size_t i; for (i = 0; (*input)[i]; i++) free((*input)[i]); free(*input); for (i = 0; i < (size_t)tfiles_n; i++) free((*tfiles)[i]); free(*tfiles); } static int remove_from_trash_all(struct dirent ***tfiles, const int tfiles_n, int *status) { int n = 0; size_t i; if (tfiles_n > 0 && confirm_removal((size_t)tfiles_n) == 0) { if (conf.autols == 1) reload_dirlist(); return (-1); } for (i = 0; i < (size_t)tfiles_n; i++) { int ret = remove_file_from_trash((*tfiles)[i]->d_name); if (ret != FUNC_SUCCESS) *status = FUNC_FAILURE; else n++; } if (*status != FUNC_SUCCESS && conf.autols == 1) press_any_key_to_continue(0); print_removal_result((size_t)n); return n; } static struct dirent ** load_trashed_files(int *n, int *status) { *status = FUNC_SUCCESS; struct dirent **tfiles = (struct dirent **)NULL; *n = scandir(trash_files_dir, &tfiles, skip_files, conf.case_sens_list == 1 ? xalphasort : alphasort_insensitive); if (*n <= -1) { *status = errno; xerror("trash: '%s': %s\n", trash_files_dir, strerror(errno)); } else if (*n == 0) { puts(_("trash: No trashed files")); } return tfiles; } /* 'trash del' screen. */ static int remove_from_trash(char **args) { if (trash_n == 0) { puts(_("trash: No trashed files")); return FUNC_SUCCESS; } /* Remove from trash files passed as parameters */ if (args[2]) return remove_from_trash_params(args + 2); /* No parameters: list, take input, and remove */ int files_n = 0; int exit_status = 0; struct dirent **trash_files = load_trashed_files(&files_n, &exit_status); if (files_n <= 0) return exit_status; exit_status = FUNC_SUCCESS; size_t i; char **input = list_and_get_input(&trash_files, files_n, 0); if (!input) { for (i = 0; i < (size_t)files_n; i++) free(trash_files[i]); free(trash_files); return FUNC_FAILURE; } /* Remove files */ /* First check for exit, wildcard, and non-number args. */ for (i = 0; input[i]; i++) { if (strcmp(input[i], "q") == 0) { free_files_and_input(&input, &trash_files, files_n); if (conf.autols == 1) reload_dirlist(); return exit_status; } if (strcmp(input[i], "*") == 0) { const int n = remove_from_trash_all(&trash_files, files_n, &exit_status); free_files_and_input(&input, &trash_files, files_n); /* n == -1: User cancelled operation. */ return (n == -1 ? FUNC_SUCCESS : exit_status); } /* Non-number or invalid ELN */ const int num = atoi(input[i]); if (!is_number(input[i]) || num <= 0 || num > files_n) { xerror(_("trash: %s: Invalid ELN\n"), input[i]); free_files_and_input(&input, &trash_files, files_n); return FUNC_FAILURE; } } /* Ask for confirmation */ for (i = 0; input[i]; i++); if (i > 0 && confirm_removal(i) == 0) { free_files_and_input(&input, &trash_files, files_n); if (conf.autols == 1) reload_dirlist(); return FUNC_SUCCESS; } /* At this point we now all input fields are valid ELNs. */ size_t removed = 0; for (i = 0; input[i]; i++) { const int num = atoi(input[i]); const int ret = remove_file_from_trash(trash_files[num - 1]->d_name); if (ret != FUNC_SUCCESS) { xerror(_("trash: '%s': Cannot remove file from the trash can\n"), trash_files[num - 1]->d_name); if (conf.autols == 1) press_any_key_to_continue(0); exit_status = ret; } else { removed++; } } free_files_and_input(&input, &trash_files, files_n); print_removal_result(removed); return exit_status; } /* Read original path from the trashinfo file FILE for the trashed file SRC. * STATUS is updated to reflect success (0) or error. */ static char * read_original_path(const char *file, const char *src, int *status) { *status = FUNC_SUCCESS; int fd = 0; FILE *fp = open_fread(file, &fd); if (!fp) { xerror(_("untrash: Info file for '%s' not found. Try restoring " "the file manually.\n"), src); *status = errno; return (char *)NULL; } char *orig_path = (char *)NULL; /* The max length for line is: Path=(5) + PATH_MAX + \n(1) */ char line[PATH_MAX + 6]; *line = '\0'; while (fgets(line, (int)sizeof(line), fp)) { if (*line == 'P' && strncmp(line, "Path=", 5) == 0) { char *p = strchr(line, '='); if (!p || !*(++p)) break; orig_path = savestring(p, strnlen(p, sizeof(line) - 1)); break; } } fclose(fp); /* If original path is NULL or empty, return error */ if (!orig_path || !*orig_path) { free(orig_path); *status = FUNC_FAILURE; return (char *)NULL; } /* Remove new line char from original path, if any */ const size_t orig_path_len = strlen(orig_path); if (orig_path_len > 0 && orig_path[orig_path_len - 1] == '\n') orig_path[orig_path_len - 1] = '\0'; /* Decode original path's URL format */ char *url_decoded = url_decode(orig_path); if (!url_decoded) { xerror(_("untrash: '%s': Error decoding original path\n"), orig_path); free(orig_path); *status = FUNC_FAILURE; return (char *)NULL; } free(orig_path); return url_decoded; } static int create_untrash_parent(char *dir) { /* NOTE: We should be using our own create_dirs() here, but it fails! */ char *cmd[] = {"mkdir", "-p", "--", dir, NULL}; return launch_execv(cmd, FOREGROUND, E_NOFLAG); } static int check_untrash_dest(char *file) { if (!file || !*file) { xerror(_("untrash: Filename is NULL or empty\n")); return FUNC_FAILURE; } char *p = strrchr(file, '/'); if (!p) { xerror(_("untrash: '%s': No directory specified\n"), file); return FUNC_FAILURE; } char c = p[1]; p[1] = '\0'; char *parent_dir = file; const int ret = access(parent_dir, F_OK | X_OK | W_OK); if (ret != 0) { if (errno == ENOENT) { if (create_untrash_parent(parent_dir) != FUNC_SUCCESS) { p[1] = c; return FUNC_FAILURE; } } else { xerror("untrash: '%s': %s\n", parent_dir, strerror(errno)); p[1] = c; return errno; } } p[1] = c; struct stat a; if (stat(file, &a) != -1) { xerror(_("untrash: '%s': Destination file exists\n"), file); return EEXIST; } return FUNC_SUCCESS; } static int untrash_file(char *file) { if (!file) return FUNC_FAILURE; char untrash_file[PATH_MAX + 1]; char untrash_info[PATH_MAX + 1]; snprintf(untrash_file, sizeof(untrash_file), "%s/%s", trash_files_dir, file); snprintf(untrash_info, sizeof(untrash_info), "%s/%s.trashinfo", trash_info_dir, file); int ret = FUNC_SUCCESS; char *orig_path = read_original_path(untrash_info, file, &ret); if (!orig_path) return ret; ret = check_untrash_dest(orig_path); if (ret != FUNC_SUCCESS) { if (conf.autols == 1) press_any_key_to_continue(0); free(orig_path); return ret; } ret = renameat(XAT_FDCWD, untrash_file, XAT_FDCWD, orig_path); if (ret == -1) { if (errno == EXDEV) { /* Destination file is on a different filesystem, which is why * rename(3) doesn't work: let's try with mv(1). */ char *cmd[] = {"mv", "--", untrash_file, orig_path, NULL}; ret = launch_execv(cmd, FOREGROUND, E_NOFLAG); if (ret != FUNC_SUCCESS) { if (conf.autols == 1) press_any_key_to_continue(0); free(orig_path); return ret; } } else { xerror("untrash: '%s': %s\n", untrash_file, strerror(errno)); if (conf.autols == 1) press_any_key_to_continue(0); free(orig_path); return errno; } } free(orig_path); if (unlinkat(XAT_FDCWD, untrash_info, 0) == -1) { xerror(_("untrash: '%s': %s\n"), untrash_info, strerror(errno)); return errno; } return FUNC_SUCCESS; } /* Untrash/restore all trashed files. */ static int untrash_all(struct dirent ***tfiles, const int tfiles_n, const int free_files) { size_t i; size_t untrashed = 0; int status = FUNC_SUCCESS; for (i = 0; i < (size_t)tfiles_n; i++) { if (untrash_file((*tfiles)[i]->d_name) != 0) status = FUNC_FAILURE; else untrashed++; if (free_files == 1) free((*tfiles)[i]); } if (free_files == 1) free(*tfiles); if (status == FUNC_SUCCESS) { if (conf.autols == 1) reload_dirlist(); const size_t n = count_trashed_files(); print_reload_msg(SET_SUCCESS_PTR, xs_cb, _("%zu file(s) restored\n"), untrashed); print_reload_msg(NULL, NULL, _("%zu total trashed file(s)\n"), n); } return status; } /* Untrash files passed as parameters (ARGS). */ static int untrash_files(char **args) { int status = FUNC_SUCCESS; size_t i; size_t untrashed = 0; for (i = 0; args[i]; i++) { char *d = (char *)NULL; if (strchr(args[i], '\\')) d = unescape_str(args[i], 0); if (untrash_file(d ? d : args[i]) != FUNC_SUCCESS) status = FUNC_FAILURE; else untrashed++; free(d); } if (status == FUNC_SUCCESS) { if (conf.autols == 1) reload_dirlist(); const size_t n = count_trashed_files(); print_reload_msg(SET_SUCCESS_PTR, xs_cb, _("%zu file(s) restored\n"), untrashed); print_reload_msg(NULL, NULL, _("%zu total trashed file(s)\n"), n); } return status; } int untrash_function(char **args) { if (!args) return FUNC_FAILURE; if (trash_ok == 0 || !trash_dir || !trash_files_dir || !trash_info_dir) { xerror(_("%s: Trash function disabled\n"), PROGRAM_NAME); return FUNC_FAILURE; } int exit_status = FUNC_SUCCESS; if (args[1] && *args[1] != '*' && strcmp(args[1], "a") != 0 && strcmp(args[1], "all") != 0) return untrash_files(args + 1); /* Get trashed files */ int files_n = 0; struct dirent **trash_files = load_trashed_files(&files_n, &exit_status); if (files_n <= 0) return exit_status; /* if "untrash all" (or "u a" or "u *") */ if (args[1] && (strcmp(args[1], "*") == 0 || strcmp(args[1], "a") == 0 || strcmp(args[1], "all") == 0)) return untrash_all(&trash_files, files_n, 1); /* List files and get input */ size_t i; char **input = list_and_get_input(&trash_files, files_n, 1); if (!input) { for (i = 0; i < (size_t)files_n; i++) free(trash_files[i]); free(trash_files); return FUNC_FAILURE; } /* First check for quit, *, and non-number args */ int free_and_return = 0; int reload_files = 0; for (i = 0; input[i]; i++) { if (strcmp(input[i], "q") == 0) { free_and_return = reload_files = 1; continue; } if (strcmp(input[i], "*") == 0) { int ret = untrash_all(&trash_files, files_n, 0); free_files_and_input(&input, &trash_files, files_n); return ret; } int num = atoi(input[i]); if (!is_number(input[i]) || num <= 0 || num > files_n) { xerror(_("untrash: %s: Invalid ELN\n"), input[i]); exit_status = FUNC_FAILURE; free_and_return = 1; } } /* Free and return if any of the above conditions is true. */ if (free_and_return == 1) { free_files_and_input(&input, &trash_files, files_n); if (conf.autols == 1 && reload_files == 1) reload_dirlist(); return exit_status; } /* Untrash files */ for (i = 0; input[i]; i++) { int num = atoi(input[i]); if (untrash_file(trash_files[num - 1]->d_name) != FUNC_SUCCESS) exit_status = FUNC_FAILURE; } free_files_and_input(&input, &trash_files, files_n); /* If some trashed file still remains, reload the untrash screen */ const size_t n = count_trashed_files(); if (n > 0) { if (conf.clear_screen > 0) CLEAR; untrash_function(args); } else { if (conf.autols == 1) reload_dirlist(); print_reload_msg(NULL, NULL, _("%zu trashed file(s)\n"), n); } return exit_status; } static void print_trashdir_size(void) { int status = 0; printf(_("\n%sTotal size: "), df_c); if (term_caps.suggestions == 1) {fputs("Calculating...", stdout); fflush(stdout);} const off_t full_size = dir_size(trash_files_dir, 0, &status); char *human_size = construct_human_size(full_size); char err[sizeof(xf_cb) + 6]; *err = '\0'; if (status != 0) snprintf(err, sizeof(err), "%s%c%s", xf_cb, DU_ERR_CHAR, NC); char s[MAX_SHADE_LEN]; *s = '\0'; if (conf.colorize == 1) get_color_size(full_size, s, sizeof(s)); if (term_caps.suggestions == 1) {MOVE_CURSOR_LEFT(14); ERASE_TO_RIGHT; fflush(stdout);} printf(_("%s%s%s%s\n"), err, s, human_size, df_c); } /* List files currently in the trash can */ static int list_trashed_files(void) { if (!trash_files_dir || !*trash_files_dir) { xerror("%s\n", _("trash: The trash directory is undefined\n")); return FUNC_FAILURE; } struct dirent **trash_files = (struct dirent **)NULL; const int files_n = scandir(trash_files_dir, &trash_files, skip_files, conf.case_sens_list == 1 ? xalphasort : alphasort_insensitive); if (files_n == -1) { xerror("trash: %s\n", strerror(errno)); return FUNC_FAILURE; } if (files_n <= 0) { puts(_("trash: No trashed files")); return FUNC_SUCCESS; } if (conf.clear_screen > 0) CLEAR; HIDE_CURSOR; const int ret = print_trashfiles(&trash_files, files_n); for (int i = 0; i < files_n; i++) free(trash_files[i]); free(trash_files); UNHIDE_CURSOR; if (ret != FUNC_SUCCESS) return ret; print_trashdir_size(); return FUNC_SUCCESS; } /* Make sure we are trashing a valid (trashable) file */ static int check_trash_file(char *file) { char tmp_file[PATH_MAX + 1]; if (*file == '/') /* If absolute path */ xstrsncpy(tmp_file, file, sizeof(tmp_file)); else { /* If relative path, add path to check against TRASH_DIR */ if (*workspaces[cur_ws].path == '/' && !workspaces[cur_ws].path[1]) snprintf(tmp_file, sizeof(tmp_file), "/%s", file); else snprintf(tmp_file, sizeof(tmp_file), "%s/%s", workspaces[cur_ws].path, file); } /* Do not trash any of the parent directories of TRASH_DIR */ if (strncmp(tmp_file, trash_dir, strnlen(tmp_file, sizeof(tmp_file))) == 0) { xerror(_("trash: Cannot trash '%s'\n"), tmp_file); return FUNC_FAILURE; } /* Do no trash TRASH_DIR itself nor anything inside it (trashed files) */ const size_t tlen = strlen(trash_dir); if (strncmp(tmp_file, trash_dir, tlen) == 0 && tmp_file[tlen] == '/') { xerror(_("trash: Use 'trash del' to remove trashed files\n")); return FUNC_FAILURE; } const size_t l = strlen(file); if (l > 1 && file[l - 1] == '/') /* Do not trash (move) symlinks ending with a slash. According to 'info mv': * "_Warning_: Avoid specifying a source name with a trailing slash, when * it might be a symlink to a directory. Otherwise, 'mv' may do something * very surprising, since its behavior depends on the underlying rename * system call. On a system with a modern Linux-based kernel, it fails * with 'errno=ENOTDIR'. However, on other systems (at least FreeBSD 6.1 * and Solaris 10) it silently renames not the symlink but rather the * directory referenced by the symlink." */ file[l - 1] = '\0'; struct stat a; if (lstat(file, &a) == -1) { xerror(_("trash: Cannot trash '%s': %s\n"), file, strerror(errno)); return errno; } return FUNC_SUCCESS; } /* List successfully trashed files. */ static void list_ok_trashed_files(char **args, const int *trashed, const size_t trashed_n) { if (print_removed_files == 0) return; size_t i; for (i = 0; i < trashed_n; i++) { if (!args[trashed[i]] || !*args[trashed[i]]) continue; char *p = args[trashed[i]]; if (strchr(args[trashed[i]], '\\') && !(p = unescape_str(args[trashed[i]], 0)) ) { xerror(_("trash: '%s': Error unescaping filename\n"), args[trashed[i]]); continue; } char *tmp = abbreviate_file_name(p); if (!tmp) { xerror(_("trash: '%s': Error abbreviating filename\n"), p); if (p && p != args[trashed[i]]) free(p); continue; } char *name = (*tmp == '.' && tmp[1] == '/') ? tmp + 2 : tmp; print_file_name(name, 0); if (tmp != p) free(tmp); if (p && p != args[trashed[i]]) free(p); } } /* Print filenames in ARGS and ask for confirmation. * Return the number of files to be trashed if the answer is afirmative, * or zero otherwise. */ static size_t ask_for_confirmation(char **args) { struct stat a; size_t i = 0; fputs(_("File(s) to be trashed:\n"), stdout); for (i = 1; args[i]; i++) { char *name = unescape_str(args[i], 0); if (!name) name = savestring(args[i], strlen(args[i])); const size_t l = strlen(name); if (l > 1 && name[l - 1] == '/') name[l - 1] = '\0'; print_file_name(name, lstat(name, &a) != -1 && S_ISDIR(a.st_mode)); free(name); } if (rl_get_y_or_n(_("Continue?"), conf.default_answer.trash) == 0) return 0; return i; } /* Trash files passed as arguments to the trash command */ static int trash_files_args(char **args) { if (!args || !args[0] || !args[1]) return FUNC_FAILURE; int exit_status = FUNC_SUCCESS, cwd = 0; size_t i, trashed_files = 0, n = 0; if (conf.trash_force == 1) { for (i = 1; args[i]; i++); } else { i = ask_for_confirmation(args); if (i == 0) return FUNC_SUCCESS; } time_t rawtime = time(NULL); struct tm t; char *suffix = localtime_r(&rawtime, &t) ? gen_date_suffix(t, 0) : NULL; if (!suffix) return FUNC_FAILURE; int *successfully_trashed = xnmalloc(i + 1, sizeof(int)); for (i = 1; args[i]; i++) { if (trash_n + trashed_files >= MAX_TRASH) { xerror("%s\n", _("trash: Cannot trash any more files")); exit_status = FUNC_FAILURE; break; } char *deq_file = unescape_str(args[i], 0); if (!deq_file) { xerror(_("trash: '%s': Error unescaping filename\n"), args[i]); continue; } /* Make sure we are trashing a valid file */ if (check_trash_file(deq_file) != FUNC_SUCCESS) { exit_status = FUNC_FAILURE; free(deq_file); continue; } if (cwd == 0) cwd = is_file_in_cwd(deq_file); /* Once here, everything is fine: trash the file */ if (trash_file(suffix, &t, deq_file) == FUNC_SUCCESS) { trashed_files++; if (print_removed_files == 1) { /* Store indices of successfully trashed files */ successfully_trashed[n] = (int)i; n++; } } else { cwd = 0; exit_status = FUNC_FAILURE; } free(deq_file); } free(suffix); if (exit_status == FUNC_SUCCESS) { if (conf.autols == 1 && cwd == 1) reload_dirlist(); goto PRINT_TRASHED; } else if (trashed_files > 0) { /* An error occured, but at least one file was trashed as well. * If this file was in the current dir, the screen will be refreshed * after this function (by inotify/kqueue), hidding the error message. * So let's pause here to prevent the error from being hidden, and * then refresh the list of files ourselves. */ if (conf.autols == 1) { press_any_key_to_continue(0); reload_dirlist(); } } else { /* Error and no trashed file. */ free(successfully_trashed); return exit_status; } PRINT_TRASHED: list_ok_trashed_files(args, successfully_trashed, n); print_reload_msg(SET_SUCCESS_PTR, xs_cb, _("%zu file(s) trashed\n"), trashed_files); print_reload_msg(NULL, NULL, _("%zu total trashed file(s)\n"), trash_n + trashed_files); free(successfully_trashed); return exit_status; } int trash_function(char **args) { if (!args) return FUNC_FAILURE; if (trash_ok == 0 || !trash_dir || !trash_info_dir || !trash_files_dir) { xerror(_("%s: Trash function disabled\n"), PROGRAM_NAME); return FUNC_FAILURE; } /* List trashed files ('tr' or 'tr list') */ if (!args[1] || (*args[1] == 'l' && strcmp(args[1], "list") == 0)) return list_trashed_files(); trash_n = count_trashed_files(); if (*args[1] == 'd' && strcmp(args[1], "del") == 0) return remove_from_trash(args); if (*args[1] == 'e' && strcmp(args[1], "empty") == 0) return trash_clear(); return trash_files_args(args); } #else void *_skip_me_trash; #endif /* !_NO_TRASH */ clifm-1.26.3/src/trash.h000066400000000000000000000020211506632037700147620ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* trash.h */ #ifndef TRASH_H #define TRASH_H __BEGIN_DECLS int trash_function(char **args); int untrash_function(char **args); __END_DECLS #endif /* TRASH_H */ clifm-1.26.3/src/utf8.h000066400000000000000000000357601506632037700145470ustar00rootroot00000000000000/* utf8.h - Unicode aware string functions */ /* This library is a trimmed down version of https://github.com/sheredom/utf8.h, * released into the public domain. * Modified code is licensed GPL2+. */ /* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ #ifndef SHEREDOM_UTF8_H_INCLUDED #define SHEREDOM_UTF8_H_INCLUDED #if defined(_MSC_VER) #pragma warning(push) /* disable warning: no function prototype given: converting '()' to '(void)' */ #pragma warning(disable : 4255) /* disable warning: '__cplusplus' is not defined as a preprocessor macro, * replacing with '0' for '#if/#elif' */ #pragma warning(disable : 4668) /* disable warning: bytes padding added after construct */ #pragma warning(disable : 4820) #endif #if defined(_MSC_VER) # pragma warning(pop) #endif #if defined(_MSC_VER) && (_MSC_VER < 1920) typedef __int32 utf8_int32_t; #else #include typedef int32_t utf8_int32_t; #endif #if defined(__clang__) # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wold-style-cast" # pragma clang diagnostic ignored "-Wcast-qual" #endif #ifdef __cplusplus extern "C" { #endif #if defined(_MSC_VER) # define utf8_nonnull # define utf8_pure # define utf8_restrict __restrict # define utf8_weak __inline #elif defined(__clang__) || defined(__GNUC__) || defined(__TINYC__) # define utf8_nonnull __attribute__((nonnull)) # define utf8_pure __attribute__((pure)) # define utf8_restrict __restrict__ # define utf8_weak __attribute__((weak)) #else # error Non clang, non gcc, non MSVC compiler found! #endif #ifdef __cplusplus # define utf8_null NULL #else # define utf8_null 0 #endif #if (defined(__cplusplus) && __cplusplus >= 201402L) # define utf8_constexpr14 constexpr # define utf8_constexpr14_impl constexpr #else /* constexpr and weak are incompatible. so only enable one of them */ # define utf8_constexpr14 utf8_weak # define utf8_constexpr14_impl #endif #if defined(__cplusplus) && __cplusplus >= 202002L using utf8_int8_t = char8_t; /* Introduced in C++20 */ #else typedef char utf8_int8_t; #endif /* Find the first match of the utf8 codepoint chr in the utf8 string src. */ utf8_constexpr14 utf8_nonnull utf8_pure utf8_int8_t * utf8chr(const utf8_int8_t *src, utf8_int32_t chr); /* The position of the utf8 string needle in the utf8 string haystack. */ utf8_constexpr14 utf8_nonnull utf8_pure utf8_int8_t * utf8str(const utf8_int8_t *haystack, const utf8_int8_t *needle); /* The position of the utf8 string needle in the utf8 string haystack, case * insensitive. */ utf8_constexpr14 utf8_nonnull utf8_pure utf8_int8_t * utf8casestr(const utf8_int8_t *haystack, const utf8_int8_t *needle); /* Sets out_codepoint to the current utf8 codepoint in str, and returns the * address of the next utf8 codepoint after the current one in str. */ utf8_constexpr14 utf8_nonnull utf8_int8_t * utf8codepoint(const utf8_int8_t *utf8_restrict str, utf8_int32_t *utf8_restrict out_codepoint); /* Returns 1 if the given character is uppercase, or 0 if it is not. */ utf8_constexpr14 int utf8isupper(utf8_int32_t chr); /* Make a codepoint lower case if possible. */ utf8_constexpr14 utf8_int32_t utf8lwrcodepoint(utf8_int32_t cp); /* Make a codepoint upper case if possible. */ utf8_constexpr14 utf8_int32_t utf8uprcodepoint(utf8_int32_t cp); /* Sets out_codepoint to the current utf8 codepoint in str, and returns the * address of the previous utf8 codepoint before the current one in str. */ utf8_constexpr14 utf8_nonnull utf8_int8_t * utf8rcodepoint(const utf8_int8_t *utf8_restrict str, utf8_int32_t *utf8_restrict out_codepoint); #undef utf8_weak #undef utf8_pure #undef utf8_nonnull utf8_constexpr14_impl utf8_int8_t * utf8chr(const utf8_int8_t *src, utf8_int32_t chr) { utf8_int8_t c[5] = {'\0', '\0', '\0', '\0', '\0'}; if (0 == chr) { /* Being asked to return position of null terminating byte, so * just run s to the end, and return! */ while ('\0' != *src) src++; return (utf8_int8_t *)src; } else if (0 == ((utf8_int32_t)0xffffff80 & chr)) { /* 1-byte/7-bit ascii * (0b0xxxxxxx) */ c[0] = (utf8_int8_t)chr; } else if (0 == ((utf8_int32_t)0xfffff800 & chr)) { /* 2-byte/11-bit utf8 code point * (0b110xxxxx 0b10xxxxxx) */ c[0] = (utf8_int8_t)(0xc0 | (utf8_int8_t)(chr >> 6)); c[1] = (utf8_int8_t)(0x80 | (utf8_int8_t)(chr & 0x3f)); } else if (0 == ((utf8_int32_t)0xffff0000 & chr)) { /* 3-byte/16-bit utf8 code point * (0b1110xxxx 0b10xxxxxx 0b10xxxxxx) */ c[0] = (utf8_int8_t)(0xe0 | (utf8_int8_t)(chr >> 12)); c[1] = (utf8_int8_t)(0x80 | (utf8_int8_t)((chr >> 6) & 0x3f)); c[2] = (utf8_int8_t)(0x80 | (utf8_int8_t)(chr & 0x3f)); } else { /* ((int)0xffe00000 & chr) == 0 { */ /* 4-byte/21-bit utf8 code point * (0b11110xxx 0b10xxxxxx 0b10xxxxxx 0b10xxxxxx) */ c[0] = (utf8_int8_t)(0xf0 | (utf8_int8_t)(chr >> 18)); c[1] = (utf8_int8_t)(0x80 | (utf8_int8_t)((chr >> 12) & 0x3f)); c[2] = (utf8_int8_t)(0x80 | (utf8_int8_t)((chr >> 6) & 0x3f)); c[3] = (utf8_int8_t)(0x80 | (utf8_int8_t)(chr & 0x3f)); } /* we've made c into a 2 utf8 codepoint string, one for the chr we are * seeking, another for the null terminating byte. Now use utf8str to * search */ return utf8str(src, c); } utf8_constexpr14_impl utf8_int8_t * utf8str(const utf8_int8_t *haystack, const utf8_int8_t *needle) { utf8_int32_t throwaway_codepoint = 0; /* if needle has no utf8 codepoints before the null terminating * byte then return haystack */ if ('\0' == *needle) return (utf8_int8_t *)haystack; while ('\0' != *haystack) { const utf8_int8_t *maybeMatch = haystack; const utf8_int8_t *n = needle; while (*haystack == *n && (*haystack != '\0' && *n != '\0')) { n++; haystack++; } if ('\0' == *n) { /* we found the whole utf8 string for needle in haystack at * maybeMatch, so return it */ return (utf8_int8_t *)maybeMatch; } else { /* h could be in the middle of an unmatching utf8 codepoint, * so we need to march it on to the next character beginning * starting from the current character */ haystack = utf8codepoint(maybeMatch, &throwaway_codepoint); } } /* no match */ return utf8_null; } utf8_constexpr14_impl utf8_int8_t * utf8casestr(const utf8_int8_t *haystack, const utf8_int8_t *needle) { /* if needle has no utf8 codepoints before the null terminating * byte then return haystack */ if ('\0' == *needle) return (utf8_int8_t *)haystack; for (;;) { const utf8_int8_t *maybeMatch = haystack; const utf8_int8_t *n = needle; utf8_int32_t h_cp = 0, n_cp = 0; /* Get the next code point and track it */ const utf8_int8_t *nextH = haystack = utf8codepoint(haystack, &h_cp); n = utf8codepoint(n, &n_cp); while ((0 != h_cp) && (0 != n_cp)) { h_cp = utf8lwrcodepoint(h_cp); n_cp = utf8lwrcodepoint(n_cp); /* if we find a mismatch, bail out! */ if (h_cp != n_cp) break; haystack = utf8codepoint(haystack, &h_cp); n = utf8codepoint(n, &n_cp); } if (0 == n_cp) { /* we found the whole utf8 string for needle in haystack at * maybeMatch, so return it */ return (utf8_int8_t *)maybeMatch; } if (0 == h_cp) { /* no match */ return utf8_null; } /* Roll back to the next code point in the haystack to test */ haystack = nextH; } } utf8_constexpr14_impl utf8_int8_t * utf8codepoint(const utf8_int8_t *utf8_restrict str, utf8_int32_t *utf8_restrict out_codepoint) { if (0xf0 == (0xf8 & str[0])) { /* 4 byte utf8 codepoint */ *out_codepoint = ((0x07 & str[0]) << 18) | ((0x3f & str[1]) << 12) | ((0x3f & str[2]) << 6) | (0x3f & str[3]); str += 4; } else if (0xe0 == (0xf0 & str[0])) { /* 3 byte utf8 codepoint */ *out_codepoint = ((0x0f & str[0]) << 12) | ((0x3f & str[1]) << 6) | (0x3f & str[2]); str += 3; } else if (0xc0 == (0xe0 & str[0])) { /* 2 byte utf8 codepoint */ *out_codepoint = ((0x1f & str[0]) << 6) | (0x3f & str[1]); str += 2; } else { /* 1 byte utf8 codepoint otherwise */ *out_codepoint = str[0]; str += 1; } return (utf8_int8_t *)str; } utf8_constexpr14_impl int utf8isupper(utf8_int32_t chr) { return chr != utf8lwrcodepoint(chr); } utf8_constexpr14_impl utf8_int32_t utf8uprcodepoint(utf8_int32_t cp) { if (((0x0061 <= cp) && (0x007a >= cp)) || ((0x00e0 <= cp) && (0x00f6 >= cp)) || ((0x00f8 <= cp) && (0x00fe >= cp)) || ((0x03b1 <= cp) && (0x03c1 >= cp)) || ((0x03c3 <= cp) && (0x03cb >= cp)) || ((0x0430 <= cp) && (0x044f >= cp))) { cp -= 32; } else if ((0x0450 <= cp) && (0x045f >= cp)) { cp -= 80; } else if (((0x0100 <= cp) && (0x012f >= cp)) || ((0x0132 <= cp) && (0x0137 >= cp)) || ((0x014a <= cp) && (0x0177 >= cp)) || ((0x0182 <= cp) && (0x0185 >= cp)) || ((0x01a0 <= cp) && (0x01a5 >= cp)) || ((0x01de <= cp) && (0x01ef >= cp)) || ((0x01f8 <= cp) && (0x021f >= cp)) || ((0x0222 <= cp) && (0x0233 >= cp)) || ((0x0246 <= cp) && (0x024f >= cp)) || ((0x03d8 <= cp) && (0x03ef >= cp)) || ((0x0460 <= cp) && (0x0481 >= cp)) || ((0x048a <= cp) && (0x04ff >= cp))) { cp &= ~0x1; } else if (((0x0139 <= cp) && (0x0148 >= cp)) || ((0x0179 <= cp) && (0x017e >= cp)) || ((0x01af <= cp) && (0x01b0 >= cp)) || ((0x01b3 <= cp) && (0x01b6 >= cp)) || ((0x01cd <= cp) && (0x01dc >= cp))) { cp -= 1; cp |= 0x1; } else { switch (cp) { default: break; case 0x00ff: cp = 0x0178; break; case 0x0180: cp = 0x0243; break; case 0x01dd: cp = 0x018e; break; case 0x019a: cp = 0x023d; break; case 0x019e: cp = 0x0220; break; case 0x0292: cp = 0x01b7; break; case 0x01c6: cp = 0x01c4; break; case 0x01c9: cp = 0x01c7; break; case 0x01cc: cp = 0x01ca; break; case 0x01f3: cp = 0x01f1; break; case 0x01bf: cp = 0x01f7; break; case 0x0188: cp = 0x0187; break; case 0x018c: cp = 0x018b; break; case 0x0192: cp = 0x0191; break; case 0x0199: cp = 0x0198; break; case 0x01a8: cp = 0x01a7; break; case 0x01ad: cp = 0x01ac; break; case 0x01b0: cp = 0x01af; break; case 0x01b9: cp = 0x01b8; break; case 0x01bd: cp = 0x01bc; break; case 0x01f5: cp = 0x01f4; break; case 0x023c: cp = 0x023b; break; case 0x0242: cp = 0x0241; break; case 0x037b: cp = 0x03fd; break; case 0x037c: cp = 0x03fe; break; case 0x037d: cp = 0x03ff; break; case 0x03f3: cp = 0x037f; break; case 0x03ac: cp = 0x0386; break; case 0x03ad: cp = 0x0388; break; case 0x03ae: cp = 0x0389; break; case 0x03af: cp = 0x038a; break; case 0x03cc: cp = 0x038c; break; case 0x03cd: cp = 0x038e; break; case 0x03ce: cp = 0x038f; break; case 0x0371: cp = 0x0370; break; case 0x0373: cp = 0x0372; break; case 0x0377: cp = 0x0376; break; case 0x03d1: cp = 0x0398; break; case 0x03d7: cp = 0x03cf; break; case 0x03f2: cp = 0x03f9; break; case 0x03f8: cp = 0x03f7; break; case 0x03fb: cp = 0x03fa; break; } } return cp; } utf8_constexpr14_impl utf8_int32_t utf8lwrcodepoint(utf8_int32_t cp) { if (((0x0041 <= cp) && (0x005a >= cp)) || ((0x00c0 <= cp) && (0x00d6 >= cp)) || ((0x00d8 <= cp) && (0x00de >= cp)) || ((0x0391 <= cp) && (0x03a1 >= cp)) || ((0x03a3 <= cp) && (0x03ab >= cp)) || ((0x0410 <= cp) && (0x042f >= cp))) { cp += 32; } else if ((0x0400 <= cp) && (0x040f >= cp)) { cp += 80; } else if (((0x0100 <= cp) && (0x012f >= cp)) || ((0x0132 <= cp) && (0x0137 >= cp)) || ((0x014a <= cp) && (0x0177 >= cp)) || ((0x0182 <= cp) && (0x0185 >= cp)) || ((0x01a0 <= cp) && (0x01a5 >= cp)) || ((0x01de <= cp) && (0x01ef >= cp)) || ((0x01f8 <= cp) && (0x021f >= cp)) || ((0x0222 <= cp) && (0x0233 >= cp)) || ((0x0246 <= cp) && (0x024f >= cp)) || ((0x03d8 <= cp) && (0x03ef >= cp)) || ((0x0460 <= cp) && (0x0481 >= cp)) || ((0x048a <= cp) && (0x04ff >= cp))) { cp |= 0x1; } else if (((0x0139 <= cp) && (0x0148 >= cp)) || ((0x0179 <= cp) && (0x017e >= cp)) || ((0x01af <= cp) && (0x01b0 >= cp)) || ((0x01b3 <= cp) && (0x01b6 >= cp)) || ((0x01cd <= cp) && (0x01dc >= cp))) { cp += 1; cp &= ~0x1; } else { switch (cp) { default: break; case 0x0178: cp = 0x00ff; break; case 0x0243: cp = 0x0180; break; case 0x018e: cp = 0x01dd; break; case 0x023d: cp = 0x019a; break; case 0x0220: cp = 0x019e; break; case 0x01b7: cp = 0x0292; break; case 0x01c4: cp = 0x01c6; break; case 0x01c7: cp = 0x01c9; break; case 0x01ca: cp = 0x01cc; break; case 0x01f1: cp = 0x01f3; break; case 0x01f7: cp = 0x01bf; break; case 0x0187: cp = 0x0188; break; case 0x018b: cp = 0x018c; break; case 0x0191: cp = 0x0192; break; case 0x0198: cp = 0x0199; break; case 0x01a7: cp = 0x01a8; break; case 0x01ac: cp = 0x01ad; break; case 0x01af: cp = 0x01b0; break; case 0x01b8: cp = 0x01b9; break; case 0x01bc: cp = 0x01bd; break; case 0x01f4: cp = 0x01f5; break; case 0x023b: cp = 0x023c; break; case 0x0241: cp = 0x0242; break; case 0x03fd: cp = 0x037b; break; case 0x03fe: cp = 0x037c; break; case 0x03ff: cp = 0x037d; break; case 0x037f: cp = 0x03f3; break; case 0x0386: cp = 0x03ac; break; case 0x0388: cp = 0x03ad; break; case 0x0389: cp = 0x03ae; break; case 0x038a: cp = 0x03af; break; case 0x038c: cp = 0x03cc; break; case 0x038e: cp = 0x03cd; break; case 0x038f: cp = 0x03ce; break; case 0x0370: cp = 0x0371; break; case 0x0372: cp = 0x0373; break; case 0x0376: cp = 0x0377; break; case 0x03f4: cp = 0x03b8; break; case 0x03cf: cp = 0x03d7; break; case 0x03f9: cp = 0x03f2; break; case 0x03f7: cp = 0x03f8; break; case 0x03fa: cp = 0x03fb; break; } } return cp; } utf8_constexpr14_impl utf8_int8_t * utf8rcodepoint(const utf8_int8_t *utf8_restrict str, utf8_int32_t *utf8_restrict out_codepoint) { const utf8_int8_t *s = (const utf8_int8_t *)str; if (0xf0 == (0xf8 & s[0])) { /* 4 byte utf8 codepoint */ *out_codepoint = ((0x07 & s[0]) << 18) | ((0x3f & s[1]) << 12) | ((0x3f & s[2]) << 6) | (0x3f & s[3]); } else if (0xe0 == (0xf0 & s[0])) { /* 3 byte utf8 codepoint */ *out_codepoint = ((0x0f & s[0]) << 12) | ((0x3f & s[1]) << 6) | (0x3f & s[2]); } else if (0xc0 == (0xe0 & s[0])) { /* 2 byte utf8 codepoint */ *out_codepoint = ((0x1f & s[0]) << 6) | (0x3f & s[1]); } else { /* 1 byte utf8 codepoint otherwise */ *out_codepoint = s[0]; } do { s--; } while ((0 != (0x80 & s[0])) && (0x80 == (0xc0 & s[0]))); return (utf8_int8_t *)s; } #undef utf8_restrict #undef utf8_constexpr14 #undef utf8_null #ifdef __cplusplus } /* extern "C" */ #endif #if defined(__clang__) #pragma clang diagnostic pop #endif #endif /* SHEREDOM_UTF8_H_INCLUDED */ clifm-1.26.3/src/view.c000066400000000000000000000247101506632037700146170ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* view.c -- home of the 'view' command */ #ifndef _NO_LIRA #include "helpers.h" #include #include #include #ifdef __OpenBSD__ typedef char *rl_cpvfunc_t; # include #else # include #endif /* __OpenBSD__ */ #if defined(MAC_OS_X_RENAMEAT_SYS_STDIO_H) # include /* renameat(2) */ #endif /* MAC_OS_X_RENAMEAT_SYS_STDIO_H */ #include "aux.h" /* open_f functions, is_cmd_in_path, construct_human_size */ #include "file_operations.h" /* open_file */ #include "init.h" /* get_sel_files */ #include "listing.h" /* reload_dirlist */ #include "messages.h" /* VIEW_USAGE */ #include "misc.h" /* xerror, print_reload_msg */ #include "selection.h" /* save_sel */ #include "spawn.h" /* launch_execve */ #include "tabcomp.h" /* tab_complete */ static int preview_edit(char *app) { if (!config_dir) { xerror("view: Configuration directory not found\n"); return FUNC_FAILURE; } char *file = (char *)NULL; if (alt_preview_file && *alt_preview_file) { file = alt_preview_file; } else { const size_t len = config_dir_len + 15; file = xnmalloc(len, sizeof(char)); snprintf(file, len, "%s/preview.clifm", config_dir); } int ret = FUNC_SUCCESS; if (app) { char *cmd[] = {app, file, NULL}; ret = launch_execv(cmd, FOREGROUND, E_NOFLAG); } else { ret = open_file(file); } if (file != alt_preview_file) free(file); return ret; } static size_t remove_empty_thumbnails(void) { DIR *dir; struct dirent *ent; if ((dir = opendir(thumbnails_dir)) == NULL) return 0; struct stat a; char buf[PATH_MAX + 1]; size_t removed = 0; while ((ent = readdir(dir)) != NULL) { if (SELFORPARENT(ent->d_name)) continue; snprintf(buf, sizeof(buf), "%s/%s", thumbnails_dir, ent->d_name); if (lstat(buf, &a) == -1 || !S_ISREG(a.st_mode)) continue; if (a.st_size == 0 && unlinkat(XAT_FDCWD, buf, 0) != -1) removed++; } closedir(dir); return removed; } static off_t remove_dangling_thumb(const char *basename, const char *abs_path, const struct stat *attr) { off_t size_sum = 0; printf(_("view: '%s': Removing dangling thumbnail... "), basename); if (unlinkat(XAT_FDCWD, abs_path, 0) == -1) { printf("%s\n", strerror(errno)); return (off_t)-1; } else { puts("OK"); size_sum += conf.apparent_size == 1 ? attr->st_size : attr->st_blocks * S_BLKSIZE; } return size_sum; } static size_t remove_thumbs_not_in_db(char **thumbs, off_t *size_sum, int *errors) { char **t = thumbs; size_t rem = 0; if (!t) return rem; DIR *dir = opendir(thumbnails_dir); if (!dir) return rem; char tmp[PATH_MAX + 1]; struct dirent *ent; size_t i = 0; while ((ent = readdir(dir)) != NULL) { if (SELFORPARENT(ent->d_name) || strcmp(ent->d_name, "CACHEDIR.TAG") == 0 || strcmp(ent->d_name, THUMBNAILS_INFO_FILE) == 0) continue; int found = 0; for (i = 0; t[i]; i++) { if (*ent->d_name == *t[i] && strcmp(ent->d_name, t[i]) == 0) { found = 1; break; } } if (found == 1) continue; snprintf(tmp, sizeof(tmp), "%s/%s", thumbnails_dir, ent->d_name); struct stat a; if (lstat(tmp, &a) == -1) { xerror("view: '%s': %s\n", ent->d_name, strerror(errno)); continue; } const off_t ret = remove_dangling_thumb(ent->d_name, tmp, &a); if (ret != (off_t)-1) { rem++; (*size_sum) += ret; } else { (*errors)++; } } closedir(dir); return rem; } /* Remove dangling thumbnails from the thumbnails directory by checking the * $XDG_CACHE_HOME/clifm/thumbnails/.thumbs.info file. * * The info file is created by the 'clifmimg' script: every time a new * thumbnail is generated, a new entry is added to this file. * Each entry has this form: THUMB_FILE@FILE_URI * THUMB_FILE is the name of the thumbnail file (i.e. an MD5 hash of * FILE_URI followed by a file extension, either jpg or png). * FILE_URI is the file URI for the absolute path to the original filename. * * If THUMB_FILE does not exist, the entry is removed from the info file. * If both THUMB_FILE and FILE_URI exist, the entry is preserved. * If FILE_URI does not exist, the current entry is removed and * THUMB_FILE gets deleted. * Finally, unregistered thumbnail files (not found in the database), * get deteled as well. */ static int purge_thumbnails_cache(void) { if (!thumbnails_dir || !*thumbnails_dir) return FUNC_FAILURE; struct stat a; if (stat(thumbnails_dir, &a) == -1 || !S_ISDIR(a.st_mode)) { xerror(_("view: The thumbnails directory does not exist, is not a " "directory, or there are no thumbnails\n")); return FUNC_FAILURE; } size_t rem_files = remove_empty_thumbnails(); char thumb_file[PATH_MAX + 1]; snprintf(thumb_file, sizeof(thumb_file), "%s/%s", thumbnails_dir, THUMBNAILS_INFO_FILE); if (lstat(thumb_file, &a) == -1) { xerror(_("view: Cannot access '%s': %s\n"), thumb_file, strerror(errno)); return FUNC_FAILURE; } if (!S_ISREG(a.st_mode)) { xerror(_("view: '%s': Not a regular file\n"), thumb_file); return FUNC_FAILURE; } char tmp_file[PATH_MAX + 1]; snprintf(tmp_file, sizeof(tmp_file), "%s/%s", thumbnails_dir, TMP_FILENAME); int tmp_fd = mkstemp(tmp_file); if (tmp_fd == -1) { xerror(_("view: Cannot create temporary file '%s': %s\n"), tmp_file, strerror(errno)); return FUNC_FAILURE; } FILE *tmp_fp = fdopen(tmp_fd, "w"); if (!tmp_fp) { xerror(_("view: Cannot open temporary file '%s': %s\n"), tmp_file, strerror(errno)); unlinkat(tmp_fd, tmp_file, 0); return FUNC_FAILURE; } int fd = 0; FILE *fp = open_fread(thumb_file, &fd); if (!fp) { xerror(_("view: Cannot open '%s': %s\n"), thumb_file, strerror(errno)); unlinkat(tmp_fd, tmp_file, 0); fclose(tmp_fp); return FUNC_FAILURE; } off_t size_sum = 0; int errors = 0; char tfile[PATH_MAX + 1]; /* Bigger than line is enough. This just avoids a compiler warning. */ /* Let's keep a record of all thumbnail files in the database. * We use this list to found unregistered thumbnails (not in * the database). */ char buf[NAME_MAX + 1]; size_t thumbs_in_db_c = 0; while (fgets(buf, 2, fp) != NULL) thumbs_in_db_c++; fseek(fp, 0L, SEEK_SET); char **thumbs_in_db = xnmalloc(thumbs_in_db_c + 1, sizeof(char *)); thumbs_in_db_c = 0; char *line = (char *)NULL; size_t line_size = 0; while (getline(&line, &line_size, fp) > 0) { char *p = strchr(line, '@'); if (!p || strncmp(p + 1, "file:///", 8) != 0) /* Malformed entry: remove it. */ continue; *p = '\0'; p += 8; const size_t len = strlen(p); if (len > 1 && p[len - 1] == '\n') p[len - 1] = '\0'; snprintf(tfile, sizeof(tfile), "%s/%s", thumbnails_dir, line); struct stat b; if (lstat(tfile, &b) == -1) { /* Thumbnail file does not exist: remove this entry */ printf(_("view: '%s' does not exist. Entry removed.\n"), line); rem_files++; continue; } char *abs_path = p; if (strchr(p, '%')) abs_path = url_decode(p); const int retval = lstat(abs_path, &a); if (abs_path != p) free(abs_path); if (retval != -1) { /* Both the thumbnail file and the original file exist. */ thumbs_in_db[thumbs_in_db_c] = savestring(line, strlen(line)); thumbs_in_db_c++; fprintf(tmp_fp, "%s@file://%s\n", line, p); continue; } /* The thumbnail file exist, but the original file does not: * remove this entry and the corresponding thumbnail file. */ const off_t ret = remove_dangling_thumb(line, tfile, &b); if (ret != (off_t)-1) { rem_files++; size_sum += ret; } else { errors++; } } renameat(tmp_fd, tmp_file, fd, thumb_file); fclose(fp); fclose(tmp_fp); free(line); thumbs_in_db[thumbs_in_db_c] = (char *)NULL; rem_files += remove_thumbs_not_in_db(thumbs_in_db, &size_sum, &errors); size_t i; for (i = 0; thumbs_in_db[i]; i++) free(thumbs_in_db[i]); free(thumbs_in_db); if (rem_files > 0) { const char *human = construct_human_size(size_sum); print_reload_msg(SET_SUCCESS_PTR, xs_cb, _("Removed %zu " "thumbnail(s): %s freed\n"), rem_files, human ? human : UNKNOWN_STR); } else { if (errors == 0) puts(_("view: No dangling thumbnails")); } return errors == 0 ? FUNC_SUCCESS : FUNC_FAILURE; } int preview_function(char **args) { #ifdef _NO_FZF xerror("%s: view: fzf: %s\n", PROGRAM_NAME, _(NOT_AVAILABLE)); return FUNC_FAILURE; #endif /* _NO_FZF */ if (args && args[0]) { if (IS_HELP(args[0])) { puts(VIEW_USAGE); return FUNC_SUCCESS; } if (*args[0] == 'e' && strcmp(args[0], "edit") == 0) return preview_edit(args[1]); if (*args[0] == 'p' && strcmp(args[0], "purge") == 0) return purge_thumbnails_cache(); } const size_t seln_bk = sel_n; const int fzf_preview_bk = conf.fzf_preview; enum tab_mode tabmode_bk = tabmode; const int fzftab_bk = fzftab; if (tabmode != FZF_TAB) { if (is_cmd_in_path("fzf") == 0) { err(0, NOPRINT_PROMPT, "%s: fzf: %s\n", PROGRAM_NAME, NOTFOUND_MSG); return E_NOTFOUND; /* 127, as required by exit(1) */ } } conf.fzf_preview = 1; tabmode = FZF_TAB; fzftab = 1; rl_delete_text(0, rl_end); rl_point = rl_end = 0; rl_redisplay(); flags |= PREVIEWER; tab_complete('?'); flags &= ~PREVIEWER; tabmode = tabmode_bk; conf.fzf_preview = fzf_preview_bk; fzftab = fzftab_bk; if (sel_n > seln_bk) { save_sel(); get_sel_files(); } if (conf.autols == 1) { putchar('\n'); reload_dirlist(); } #if defined(RL_READLINE_VERSION) && RL_READLINE_VERSION >= 0x0700 else { /* Only available since readline 7.0 */ rl_clear_visible_line(); } #endif /* READLINE >= 7.0 */ if (sel_n > seln_bk) { print_reload_msg(NULL, NULL, _("%zu file(s) selected\n"), sel_n - seln_bk); print_reload_msg(NULL, NULL, _("%zu total selected file(s)\n"), sel_n); } return FUNC_SUCCESS; } #else void *_skip_me_view; #endif /* !_NO_LIRA */ clifm-1.26.3/src/view.h000066400000000000000000000017771506632037700146340ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* view.h */ #ifndef CLIFM_VIEW_H # define CLIFM_VIEW_H __BEGIN_DECLS int preview_function(char **args); __END_DECLS #endif /* CLIFM_VIEW_H */ clifm-1.26.3/src/workspaces.c000066400000000000000000000234221506632037700160250ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* workspaces.c -- handle workspaces ('ws' command) */ #include "helpers.h" #include #include /* strerror */ #include /* access */ #include "aux.h" /* xatoi */ #include "checks.h" /* is_number */ #include "colors.h" /* get_dir_color */ #include "listing.h" /* reload_dirlist */ #include "messages.h" /* WS_USAGE */ #include "misc.h" /* xerror */ #include "navigation.h" /* xchdir */ #include "history.h" /* add_to_dirhist */ #include "strings.h" /* wc_xstrlen */ static size_t get_longest_workspace_name(void) { size_t longest_ws = 0; int i = MAX_WS; while (--i >= 0) { if (!workspaces[i].name) continue; const size_t l = wc_xstrlen(workspaces[i].name); if (l > longest_ws) longest_ws = l; } return longest_ws; } static char * get_workspace_path_color(const uint8_t num) { if (conf.colorize == 0) return df_c; if (!workspaces[num].path) /* Unset. DL (dividing line) defaults to gray: let's use this */ return DEF_DL_C; struct stat a; if (lstat(workspaces[num].path, &a) == -1) return uf_c; if (S_ISLNK(a.st_mode)) { char p[PATH_MAX + 1]; *p = '\0'; char *ret = xrealpath(workspaces[num].path, p); return (ret && *p) ? ln_c : or_c; } return get_dir_color(workspaces[num].path, &a, -1); } static int list_workspaces(void) { uint8_t i; int pad = (int)get_longest_workspace_name(); const char *ptr = SET_MISC_PTR; for (i = 0; i < MAX_WS; i++) { char *path_color = get_workspace_path_color(i); if (i == cur_ws) printf("%s%s%s ", mi_c, ptr, df_c); else fputs(" ", stdout); char *ws_color = df_c; if (workspaces[i].name) { printf("%s%d%s [%s%s%s]: %*s", ws_color, i + 1, df_c, ws_color, workspaces[i].name, df_c, pad - (int)wc_xstrlen(workspaces[i].name), ""); } else { printf("%s%d%s: %*s", ws_color, i + 1, df_c, pad > 0 ? pad + 3 : 0, ""); } printf("%s%s%s\n", path_color, workspaces[i].path ? workspaces[i].path : "unset", df_c); } return FUNC_SUCCESS; } static int check_workspace_num(char *str, int *tmp_ws) { const int istr = atoi(str); if (istr <= 0 || istr > MAX_WS) { xerror(_("ws: %d: No such workspace (valid workspaces: " "1-%d)\n"), istr, MAX_WS); return FUNC_FAILURE; } *tmp_ws = istr - 1; if (*tmp_ws == cur_ws) { xerror(_("ws: %d: Is the current workspace\n"), *tmp_ws + 1); return FUNC_SUCCESS; } return 2; } static void save_workspace_opts(const int n) { free(workspace_opts[n].filter.str); workspace_opts[n].filter.str = filter.str ? savestring(filter.str, strlen(filter.str)) : (char *)NULL; workspace_opts[n].filter.rev = filter.rev; workspace_opts[n].filter.type = filter.type; workspace_opts[n].filter.env = filter.env; workspace_opts[n].color_scheme = cur_cscheme; workspace_opts[n].files_counter = conf.files_counter; workspace_opts[n].light_mode = conf.light_mode; workspace_opts[n].list_dirs_first = conf.list_dirs_first; workspace_opts[n].long_view = conf.long_view; workspace_opts[n].max_files = conf.max_files; workspace_opts[n].max_name_len = conf.max_name_len; workspace_opts[n].only_dirs = conf.only_dirs; workspace_opts[n].pager = conf.pager; workspace_opts[n].show_hidden = conf.show_hidden; workspace_opts[n].sort = conf.sort; workspace_opts[n].sort_reverse = conf.sort_reverse; } static void unset_ws_filter(void) { free(filter.str); filter.str = (char *)NULL; filter.rev = 0; filter.type = FILTER_NONE; regfree(®ex_exp); } static void set_ws_filter(const int n) { filter.type = workspace_opts[n].filter.type; filter.rev = workspace_opts[n].filter.rev; filter.env = workspace_opts[n].filter.env; free(filter.str); regfree(®ex_exp); char *p = workspace_opts[n].filter.str; filter.str = savestring(p, strlen(p)); if (filter.type != FILTER_FILE_NAME) return; if (regcomp(®ex_exp, filter.str, REG_NOSUB | REG_EXTENDED) != FUNC_SUCCESS) unset_ws_filter(); } static void set_workspace_opts(const int n) { if (workspace_opts[n].color_scheme && workspace_opts[n].color_scheme != cur_cscheme) set_colors(workspace_opts[n].color_scheme, 0); if (workspace_opts[n].filter.str && *workspace_opts[n].filter.str) { set_ws_filter(n); } else { if (filter.str) unset_ws_filter(); } conf.light_mode = workspace_opts[n].light_mode; conf.list_dirs_first = workspace_opts[n].list_dirs_first; conf.long_view = workspace_opts[n].long_view; conf.files_counter = workspace_opts[n].files_counter; conf.max_files = workspace_opts[n].max_files; conf.max_name_len = workspace_opts[n].max_name_len; conf.only_dirs = workspace_opts[n].only_dirs; conf.pager = workspace_opts[n].pager; conf.show_hidden = workspace_opts[n].show_hidden; conf.sort = workspace_opts[n].sort; conf.sort_reverse = workspace_opts[n].sort_reverse; } #define IS_VALID_WS(n) ((n) >= 0 && (n) < MAX_WS && workspaces[(n)].path) static int switch_workspace(const int tmp_ws) { /* If new workspace has no path yet, copy the path of the current workspace */ if (!workspaces[tmp_ws].path) { if (!IS_VALID_WS(cur_ws)) { xerror(_("ws: Current workspace is invalid\n")); return FUNC_FAILURE; } workspaces[tmp_ws].path = savestring(workspaces[cur_ws].path, strlen(workspaces[cur_ws].path)); } else if (tmp_ws != cur_ws) { if (access(workspaces[tmp_ws].path, R_OK | X_OK) == -1) { if (!IS_VALID_WS(cur_ws)) { xerror(_("ws: Current workspace is invalid\n")); return FUNC_FAILURE; } xerror("ws: '%s': %s\n", workspaces[tmp_ws].path, strerror(errno)); if (conf.autols == 1) press_any_key_to_continue(0); free(workspaces[tmp_ws].path); workspaces[tmp_ws].path = savestring(workspaces[cur_ws].path, strlen(workspaces[cur_ws].path)); } } else { xerror(_("ws: %d: Is the current workspace\n"), tmp_ws + 1); return FUNC_SUCCESS; } if (xchdir(workspaces[tmp_ws].path, SET_TITLE) == -1) { xerror("ws: '%s': %s\n", workspaces[tmp_ws].path, strerror(errno)); return errno; } if (conf.private_ws_settings == 1) save_workspace_opts(cur_ws); prev_ws = cur_ws; cur_ws = tmp_ws; dir_changed = 1; if (conf.colorize == 1 && xargs.eln_use_workspace_color == 1) set_eln_color(); if (conf.private_ws_settings == 1) set_workspace_opts(cur_ws); if (conf.autols == 1) reload_dirlist(); add_to_dirhist(workspaces[cur_ws].path); return FUNC_SUCCESS; } #undef IS_VALID_WS /* Return the workspace number corresponding to the workspace name NAME, * or -1 if no workspace is named NAME, if error, or if NAME is already * the current workspace */ static int get_workspace_by_name(char *name, const int check_current) { if (!name || !*name) return (-1); /* CHECK_CURRENT is zero when coming from unset_workspace(), in which * case name is already unescapeed. */ char *p = check_current == 1 ? unescape_str(name, 0) : (char *)NULL; char *q = p ? p : name; int n = MAX_WS; while (--n >= 0) { if (!workspaces[n].name || *workspaces[n].name != *q || strcmp(workspaces[n].name, q) != 0) continue; if (n == cur_ws && check_current == 1) { xerror(_("ws: %s: Is the current workspace\n"), q); free(p); return (-1); } free(p); return n; } xerror(_("ws: %s: No such workspace\n"), q); free(p); return (-1); } static int unset_workspace(char *str) { int n = -1; char *name = unescape_str(str, 0); if (!name) { xerror("ws: '%s': Error unescaping name\n", str); return FUNC_FAILURE; } if (!is_number(name)) { if ((n = get_workspace_by_name(name, 0)) == -1) goto ERROR; n++; } else { n = atoi(name); } if (n < 1 || n > MAX_WS) { xerror(_("ws: '%s': No such workspace (valid workspaces: " "1-%d)\n"), name, MAX_WS); goto ERROR; } n--; if (n == cur_ws) { xerror(_("ws: '%s': Is the current workspace\n"), name); goto ERROR; } if (!workspaces[n].path) { xerror(_("ws: '%s': Already unset\n"), name); goto ERROR; } printf(_("ws: '%s': Workspace unset\n"), name); free(name); free(workspaces[n].path); workspaces[n].path = (char *)NULL; return FUNC_SUCCESS; ERROR: free(name); return FUNC_FAILURE; } int handle_workspaces(char **args) { if (!workspaces) { /* This should never happen. */ xerror(_("ws: There are no defined workspaces\n")); return FUNC_FAILURE; } if (!args[0] || !*args[0]) return list_workspaces(); if (IS_HELP(args[0])) { puts(_(WS_USAGE)); return FUNC_SUCCESS; } if (args[1] && strcmp(args[1], "unset") == 0) return unset_workspace(args[0]); int tmp_ws = 0; if (is_number(args[0])) { const int ret = check_workspace_num(args[0], &tmp_ws); if (ret != 2) return ret; } else if (*args[0] == '+' && !args[0][1]) { if ((cur_ws + 1) >= MAX_WS) { xerror(_("ws: This is already the last workspace\n")); return FUNC_FAILURE; } tmp_ws = cur_ws + 1; } else if (*args[0] == '-' && !args[0][1]) { if ((cur_ws - 1) < 0) { xerror(_("ws: This is already the first workspace\n")); return FUNC_FAILURE; } tmp_ws = cur_ws - 1; } else { tmp_ws = get_workspace_by_name(args[0], 1); if (tmp_ws == -1) return FUNC_FAILURE; } return switch_workspace(tmp_ws); } clifm-1.26.3/src/workspaces.h000066400000000000000000000020051506632037700160240ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* workspaces.h */ #ifndef WORKSPACES_H #define WORKSPACES_H __BEGIN_DECLS int handle_workspaces(char **args); __END_DECLS #endif /* WORKSPACES_H */ clifm-1.26.3/src/xdu.c000066400000000000000000000176361506632037700144560ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* xdu.c -- Trimmed down implementation of du(1) */ #include "helpers.h" #include #ifdef USE_DU1 # include /* strchr */ # include /* close, dup, dup2, unlink, unlinkat */ #endif /* USE_DU1 */ #ifdef USE_DU1 # include "aux.h" /* xnrealloc, open_fread */ # include "spawn.h" /* launch_execv */ #else # include "mem.h" /* xnrealloc */ #endif /* USE_DU1 */ /* According to 'info du', the st_size member of a stat struct is meaningful * only: * 1. When computing disk usage (not apparent sizes). * 2. If apparent sizes, only for symlinks and regular files. * NOTE: Here we add shared memory object and typed memory object just to * match the check made by du(1). These objects are not implemented on most * systems, but this might change in the future. */ #define USABLE_ST_SIZE(s) (conf.apparent_size != 1 || S_ISLNK((s)->st_mode) \ || S_ISREG((s)->st_mode) || S_TYPEISSHM((s)) || S_TYPEISTMO((s))) struct hlink_t { dev_t dev; ino_t ino; }; static struct hlink_t *xdu_hardlinks = {0}; static size_t xdu_hardlink_n = 0; static inline int check_xdu_hardlinks(const dev_t dev, const ino_t ino) { if (!xdu_hardlinks || xdu_hardlink_n == 0) return 0; size_t i; for (i = 0; i < xdu_hardlink_n; i++) { if (dev == xdu_hardlinks[i].dev && ino == xdu_hardlinks[i].ino) return 1; } return 0; } static inline void add_xdu_hardlink(const dev_t dev, const ino_t ino) { xdu_hardlinks = xnrealloc(xdu_hardlinks, xdu_hardlink_n + 1, sizeof(struct hlink_t)); xdu_hardlinks[xdu_hardlink_n].dev = dev; xdu_hardlinks[xdu_hardlink_n].ino = ino; xdu_hardlink_n++; } static inline void free_xdu_hardlinks(void) { free(xdu_hardlinks); xdu_hardlinks = (struct hlink_t *)NULL; xdu_hardlink_n = 0; } /* Trimmed down implementation of du(1) providing only those features * required by Clifm. * * Recursively count files and directories in the directory DIR and store * values in the INFO struct. * * The total size in bytes is stored in the SIZE field of the struct, and * the total number of used blocks in the BLOCKS field. * Translate this info into apparent and physical sizes of DIR as follows: * apparent = info->size (same as 'du -s -B1 --apparent-size') * physical = info->blocks * S_BLKSIZE (same as 'du -s -B1') * * The number of directories, symbolic links, and other file types is stored * in the DIRS, LINKS, and FILES fields respectively. * FIRST_LEVEL must be always 1 when calling this function (this value will * be zero whenever the function calls itself recursively). * If a directory cannot be read, or a file cannot be stat'ed, then the * STATUS field of the INFO struct is set to the appropriate errno value. */ void dir_info(const char *dir, const int first_level, struct dir_info_t *info) { if (!dir || !*dir) { info->status = ENOENT; return; } struct stat a; DIR *p; if ((p = opendir(dir)) == NULL) { info->status = errno; return; } #ifdef POSIX_FADV_SEQUENTIAL /* A hint to the kernel to optimize the current dir for reading. */ const int fd = dirfd(p); posix_fadvise(fd, 0, 0, POSIX_FADV_SEQUENTIAL); #endif /* POSIX_FADV_SEQUENTIAL */ /* Compute the PHYSICAL size of the base directory itself. */ if (first_level == 1 && stat(dir, &a) != -1) info->blocks += a.st_blocks; struct dirent *ent; char buf[PATH_MAX + 1]; while ((ent = readdir(p)) != NULL) { if (SELFORPARENT(ent->d_name)) continue; snprintf(buf, sizeof(buf), "%s/%s", dir, ent->d_name); if (lstat(buf, &a) == -1) { info->status = errno; #ifdef _DIRENT_HAVE_D_TYPE /* We cannot extract the file type from st_mode. Let's fallback * to whatever d_type says. */ switch (ent->d_type) { case DT_LNK: info->links++; break; case DT_DIR: info->dirs++; break; default: info->files++; break; } #else info->files++; #endif /* _DIRENT_HAVE_D_TYPE */ continue; } if (S_ISLNK(a.st_mode)) { info->links++; #ifdef __CYGWIN__ /* This is because on Cygwin systems some regular files, maybe due to * some permissions issue, are otherwise taken as directories. */ } else if (S_ISREG(a.st_mode)) { info->files++; #endif /* __CYGWIN__ */ } else if (S_ISDIR(a.st_mode)) { /* Even if a subdirectory is unreadable or we can't chdir into * it, do let its PHYSICAL size contribute to the total * (provided we're not computing apparent sizes). */ info->blocks += a.st_blocks; info->dirs++; dir_info(buf, 0, info); continue; } else { info->files++; } if (!USABLE_ST_SIZE(&a)) continue; if (a.st_nlink > 1) { if (check_xdu_hardlinks(a.st_dev, a.st_ino) == 1) continue; else add_xdu_hardlink(a.st_dev, a.st_ino); } info->size += a.st_size; info->blocks += a.st_blocks; } closedir(p); if (first_level == 1) free_xdu_hardlinks(); } #ifndef USE_DU1 off_t dir_size(const char *dir, const int first_level, int *status) { struct dir_info_t info = {0}; dir_info(dir, first_level, &info); *status = info.status; return (conf.apparent_size == 1 ? info.size : (info.blocks * S_BLKSIZE)); } #else /* USE_DU1 */ /* Return the full size of the directory DIR using du(1). * The size is reported in bytes if SIZE_IN_BYTES is set to 1. * Otherwise, human format is used. * STATUS is updated to the command exit code. */ off_t dir_size(char *dir, const int size_in_bytes, int *status) { if (!dir || !*dir) return (-1); char file[PATH_MAX + 1]; snprintf(file, sizeof(file), "%s/%s", xargs.stealth_mode == 1 ? P_tmpdir : tmp_dir, TMP_FILENAME); int fd = mkstemp(file); if (fd == -1) return (-1); int stdout_bk = dup(STDOUT_FILENO); /* Save original stdout */ if (stdout_bk == -1) { unlinkat(fd, file, 0); close(fd); return (-1); } /* Redirect stdout to the desired file */ dup2(fd, STDOUT_FILENO); close(fd); if (bin_flags & (GNU_DU_BIN_DU | GNU_DU_BIN_GDU)) { char *block_size = (char *)NULL; if (size_in_bytes == 1) { block_size = "--block-size=1"; } else { if (xargs.si == 1) block_size = "--block-size=KB"; else block_size = "--block-size=K"; } char *bin = (bin_flags & GNU_DU_BIN_DU) ? "du" : "gdu"; if (conf.apparent_size != 1) { char *cmd[] = {bin, "-s", block_size, "--", dir, NULL}; *status = launch_execv(cmd, FOREGROUND, E_NOSTDERR); } else { char *cmd[] = {bin, "-s", "--apparent-size", block_size, "--", dir, NULL}; *status = launch_execv(cmd, FOREGROUND, E_NOSTDERR); } } else { char *cmd[] = {"du", "-ks", "--", dir, NULL}; *status = launch_execv(cmd, FOREGROUND, E_NOSTDERR); } dup2(stdout_bk, STDOUT_FILENO); /* Restore original stdout */ close(stdout_bk); FILE *fp = open_fread(file, &fd); if (!fp) { unlink(file); return (-1); } off_t retval = -1; /* We only need here the first field of the line, which is a file * size and usually takes only a few digits: since a yottabyte takes 26 * digits, MAX_INT_STR (32) is more than enough. */ char line[MAX_INT_STR]; *line = '\0'; if (fgets(line, (int)sizeof(line), fp) == NULL) goto END; char *p = strchr(line, '\t'); if (p && p != line) { *p = '\0'; retval = (off_t)atoll(line); } END: unlinkat(fd, file, 0); fclose(fp); return retval; } #endif /* !USE_DU1 */ clifm-1.26.3/src/xdu.h000066400000000000000000000023251506632037700144500ustar00rootroot00000000000000/* * This file is part of Clifm * * SPDX-License-Identifier: GPL-2.0-or-later * Copyright (C) 2016-2025, L. Abramovich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* xdu.h */ #ifndef CLIFM_XDU_H #define CLIFM_XDU_H __BEGIN_DECLS void dir_info(const char *dir, const int first_level, struct dir_info_t *info); #ifdef USE_DU1 off_t dir_size(char *dir, const int first_level, int *status); #else off_t dir_size(const char *dir, const int first_level, int *status); #endif /* USE_DU1 */ __END_DECLS #endif /* CLIFM_XDU_H */ clifm-1.26.3/translations/000077500000000000000000000000001506632037700154275ustar00rootroot00000000000000clifm-1.26.3/translations/chinese/000077500000000000000000000000001506632037700170455ustar00rootroot00000000000000clifm-1.26.3/translations/chinese/clifm.po000066400000000000000000001233511506632037700205040ustar00rootroot00000000000000# This file is part of CliFM # Copyright (C) 2016-2022 # This file is distributed under the same license as the clifm package. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2022-04-23 14:46-0300\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: properties.c:400 #, c-format msgid "\tBlocks: %s%ld%s" msgstr "" #: properties.c:398 #, c-format msgid "\tBlocks: %s%lld%s" msgstr "" #: properties.c:420 #, c-format msgid "\tGid: %s%u (%s)%s\n" msgstr "" #: properties.c:404 #, c-format msgid "\tIO Block: %s%d%s" msgstr "" #: properties.c:406 #, c-format msgid "\tIO Block: %s%ld%s" msgstr "" #: properties.c:409 #, c-format msgid "\tInode: %s%llu%s\n" msgstr "" #: properties.c:411 #, c-format msgid "\tInode: %s%zu%s\n" msgstr "" #: properties.c:317 #, c-format msgid "\tName: %s%s%s -> %s (broken link)\n" msgstr "" #: properties.c:418 #, c-format msgid "\tUid: %s%u (%s)%s" msgstr "" #: misc.c:1789 #, c-format msgid "" "\n" " Press any key to continue... " msgstr "" #: selection.c:786 #, c-format msgid "" "\n" "%s%sTotal size%s: %s\n" msgstr "" #: bookmarks.c:214 #, c-format msgid "" "\n" "%sEnter '%c' to quit.\n" msgstr "" #: selection.c:990 #, c-format msgid "" "\n" "%sEnter 'q' to quit or 'e' to edit the selections file\n" msgstr "" #: trash.c:559 trash.c:877 #, c-format msgid "" "\n" "%sEnter 'q' to quit.\n" msgstr "" #: archives.c:816 #, c-format msgid "" "\n" "%sNOTE%s: Zstandard does not support compression of multiple files into one " "single compressed file. Files will be compressed rather into multiple " "compressed files using the original file names\n" msgstr "" #: media.c:282 #, c-format msgid "" "\n" "%sUnmounted devices%s\n" "\n" msgstr "" #: colors.c:1831 #, c-format msgid "" "\n" "*The slash followed by a number (/xx) after directories or symbolic links to " "directories indicates the amount of files contained by the corresponding " "directory, excluding self (.) and parent (..) directories.\n" msgstr "" #: misc.c:1697 msgid "" "\n" "NOTE: Some keybindings on Haiku might differ. Take a look at your current " "keybindings via the 'kb' command" msgstr "" #: colors.c:1835 #, c-format msgid "" "\n" "The second field in this list is the code that is to be used to modify the " "color of the corresponding file type in the color scheme file (in the " "\"FiletypeColors\" line), using the same ANSI style color format used by " "dircolors. By default, %s uses only 8/16 colors, but you can use 256 and RGB/" "true colors as well.\n" "\n" msgstr "" #: colors.c:1807 #, c-format msgid " %sfile name%s: bd: Block special file\n" msgstr "" #: colors.c:1818 #, c-format msgid " %sfile name%s: ca: File with capabilities\n" msgstr "" #: colors.c:1813 #, c-format msgid " %sfile name%s: cd: Character special file\n" msgstr "" #: colors.c:1800 #, c-format msgid " %sfile name%s: di: Directory*\n" msgstr "" #: colors.c:1801 #, c-format msgid " %sfile name%s: ed: EMPTY directory\n" msgstr "" #: colors.c:1806 #, c-format msgid " %sfile name%s: ee: Empty executable file\n" msgstr "" #: colors.c:1815 #, c-format msgid " %sfile name%s: ef: Empty (zero-lenght) file\n" msgstr "" #: colors.c:1805 #, c-format msgid " %sfile name%s: ex: Executable file\n" msgstr "" #: colors.c:1814 #, c-format msgid " %sfile name%s: fi: Regular file\n" msgstr "" #: colors.c:1808 #, c-format msgid " %sfile name%s: ln: Symbolic link*\n" msgstr "" #: colors.c:1810 #, c-format msgid " %sfile name%s: mh: Multi-hardlink\n" msgstr "" #: colors.c:1796 #, c-format msgid " %sfile name%s: nd: Directory with no read permission\n" msgstr "" #: colors.c:1802 #, c-format msgid " %sfile name%s: ne: EMPTY directory with no read permission\n" msgstr "" #: colors.c:1798 #, c-format msgid " %sfile name%s: nf: File with no read permission\n" msgstr "" #: colors.c:1828 #, c-format msgid " %sfile name%s: no: Unknown file type\n" msgstr "" #: colors.c:1809 #, c-format msgid " %sfile name%s: or: Broken symbolic link\n" msgstr "" #: colors.c:1825 #, c-format msgid " %sfile name%s: ow: Other-writable and NOT sticky directory*\n" msgstr "" #: colors.c:1812 #, c-format msgid " %sfile name%s: pi: Pipe or FIFO special file\n" msgstr "" #: colors.c:1817 #, c-format msgid " %sfile name%s: sg: SGID file\n" msgstr "" #: colors.c:1811 #, c-format msgid " %sfile name%s: so: Socket file\n" msgstr "" #: colors.c:1819 #, c-format msgid " %sfile name%s: st: Sticky and NOT other-writable directory*\n" msgstr "" #: colors.c:1816 #, c-format msgid " %sfile name%s: su: SUID file\n" msgstr "" #: colors.c:1822 #, c-format msgid " %sfile name%s: tw: Sticky and other-writable directory*\n" msgstr "" #: colors.c:1829 #, c-format msgid " %sfile name%s: uf: Unaccessible (non-stat'able) file\n" msgstr "" #: remotes.c:67 #, c-format msgid " Auto-mount: %s\n" msgstr "" #: remotes.c:65 #, c-format msgid " Auto-unmount: %s\n" msgstr "" #: remotes.c:58 #, c-format msgid " Comment: %s\n" msgstr "" #: remotes.c:62 #, c-format msgid " Mount command: %s\n" msgstr "" #: remotes.c:69 #, c-format msgid " Mounted: %s\n" msgstr "" #: remotes.c:60 #, c-format msgid " Mountpoint: %s\n" msgstr "" #: remotes.c:64 #, c-format msgid " Unmount command: %s\n" msgstr "" #: config.c:1263 #, c-format msgid "" "# %s profile\n" "# Write here the commands you want to be executed at startup\n" "# Ex:\n" "#echo -e \"%s, the command line file manager\"\n" msgstr "" #: strings.c:1631 #, c-format msgid "%c%s: There are no selected files%c" msgstr "" #: selection.c:938 #, c-format msgid "%d file(s) deselected. " msgstr "" #: sort.c:364 #, c-format msgid "%s %s\n" msgstr "" #: misc.c:1757 #, c-format msgid "%s %s (%s), by %s\n" msgstr "" #: misc.c:1776 #, c-format msgid "" "%s %s (%s), by %s\n" "Contact: %s\n" "Website: %s\n" "License: %s\n" msgstr "" #: tags.c:115 #, c-format msgid "%s (error resolving link target)\n" msgstr "" #: sort.c:358 #, c-format msgid "%s (not available: using 'name') %s\n" msgstr "" #: config.c:1320 #, c-format msgid "" "%s created a new MIME list file (%s) It is recommended to edit this file " "(entering 'mm edit' or pressing F6) to add the programs you use and remove " "those you don't. This will make the process of opening files faster and " "smoother\n" msgstr "" #: bookmarks.c:89 #, c-format msgid "" "%s%s\n" "Enter '%c' to edit your bookmarks or '%c' to quit.\n" msgstr "" #: file_operations.c:1055 #, c-format msgid "%s%s%s currently pointing to " msgstr "" #: file_operations.c:1052 #, c-format msgid "%s%s%s currently pointing to nowhere (broken link)\n" msgstr "" #: file_operations.c:1167 #, c-format msgid "%s%s%s successfully relinked to " msgstr "" #: archives.c:1188 #, c-format msgid "%s%s%s: Succesfully mounted on %s\n" msgstr "" #: archives.c:1009 #, c-format msgid "%s%sFile%s: %s\n" msgstr "" #: selection.c:732 #, c-format msgid "%s%sSelection Box%s\n" msgstr "" #: selection.c:543 #, c-format msgid "%s%sTotal size%s: %s\n" msgstr "" #: main.c:759 #, c-format msgid "%s->%s Running as root%s\n" msgstr "" #: history.c:540 history.c:579 #, c-format msgid "%s: !%s: Event not found\n" msgstr "" #: history.c:494 #, c-format msgid "%s: !%s: event not found\n" msgstr "" #: mime.c:1349 #, c-format msgid "" "%s: %d MIME definition(s) imported from the system. Old MIME list file " "stored as %s\n" msgstr "" #: name_cleaner.c:649 #, c-format msgid "%s: %d file(s) bleached\n" msgstr "" #: selection.c:940 #, c-format msgid "%s: %d file(s) deselected. " msgstr "" #: navigation.c:80 #, c-format msgid "%s: %d is already the current workspace\n" msgstr "" #: strings.c:1702 #, c-format msgid "" "%s: %d: ELN-filename conflict. Bypass internal expansions to fix this issue: " "';CMD FILENAME'\n" msgstr "" #: media.c:199 #, c-format msgid "%s: %d: Invalid ELN\n" msgstr "" #: navigation.c:72 #, c-format msgid "%s: %d: Invalid workspace number\n" msgstr "" #: name_cleaner.c:408 prompt.c:462 #, c-format msgid "%s: %s\n" msgstr "" #: file_operations.c:977 #, c-format msgid "" "%s: %s (%s): Cannot open file\n" "Try 'APPLICATION FILENAME'\n" msgstr "" #: aux.c:817 aux.c:831 aux.c:845 #, c-format msgid "%s: %s failed to allocate %zu bytes\n" msgstr "" #: config.c:502 file_operations.c:108 file_operations.c:134 remotes.c:137 #, c-format msgid "%s: %s: %s\n" msgstr "" #: init.c:1692 #, c-format msgid "" "%s: %s: %s\n" "Falling back to default\n" msgstr "" #: init.c:1637 #, c-format msgid "" "%s: %s: %s\n" "Falling back to default configuration directory\n" msgstr "" #: init.c:1604 #, c-format msgid "" "%s: %s: %s\n" "Falling back to the default bookmarks file\n" msgstr "" #: init.c:1664 #, c-format msgid "" "%s: %s: %s\n" "Falling back to the default keybindings file\n" msgstr "" #: file_operations.c:953 #, c-format msgid "%s: %s: Broken symbolic link\n" msgstr "" #: init.c:1628 #, c-format msgid "" "%s: %s: Cannot create directory (error %d)\n" "Falling back to default configuration directory\n" msgstr "" #: profiles.c:302 #, c-format msgid "%s: %s: Cannot create profile: Home directory not found\n" msgstr "" #: file_operations.c:1741 #, c-format msgid "%s: %s: Cannot create symlink: %s\n" msgstr "" #: tags.c:384 #, c-format msgid "%s: %s: Cannot create tag\n" msgstr "" #: tags.c:50 #, c-format msgid "%s: %s: Cannot create tag: file already exists\n" msgstr "" #: file_operations.c:251 #, c-format msgid "%s: %s: Cannot open file\n" msgstr "" #: file_operations.c:210 #, c-format msgid "%s: %s: Directory empty\n" msgstr "" #: profiles.c:371 #, c-format msgid "%s: %s: Error creating profile\n" msgstr "" #: tags.c:277 #, c-format msgid "%s: %s: Error creating tag\n" msgstr "" #: config.c:1240 #, c-format msgid "%s: %s: Error creating tags directory. Tag function disabled\n" msgstr "" #: aux.c:143 #, c-format msgid "%s: %s: Error deescaping string\n" msgstr "" #: file_operations.c:1022 file_operations.c:1111 #, c-format msgid "%s: %s: Error dequoting file\n" msgstr "" #: bookmarks.c:794 misc.c:754 name_cleaner.c:523 properties.c:684 #: readline.c:401 search.c:145 search.c:552 #, c-format msgid "%s: %s: Error dequoting file name\n" msgstr "" #: file_operations.c:776 file_operations.c:911 #, c-format msgid "%s: %s: Error dequoting filename\n" msgstr "" #: navigation.c:281 #, c-format msgid "%s: %s: Error dequoting string\n" msgstr "" #: aux.c:159 navigation.c:288 #, c-format msgid "%s: %s: Error expanding tilde\n" msgstr "" #: remotes.c:255 trash.c:136 #, c-format msgid "%s: %s: Error getting parent directory\n" msgstr "" #: strings.c:1766 #, c-format msgid "%s: %s: Error getting variable name\n" msgstr "" #: mime.c:282 #, c-format msgid "%s: %s: Error opening file\n" msgstr "" #: strings.c:1591 strings.c:1733 strings.c:1973 strings.c:2047 #, c-format msgid "%s: %s: Error quoting file name\n" msgstr "" #: profiles.c:415 #, c-format msgid "%s: %s: Error removing profile\n" msgstr "" #: file_operations.c:814 #, c-format msgid "%s: %s: File already exists. Trying with '%s' instead\n" msgstr "" #: tags.c:48 #, c-format msgid "%s: %s: File already tagged\n" msgstr "" #: tags.c:531 #, c-format msgid "%s: %s: File not tagged as %s%s%s\n" msgstr "" #: file_operations.c:1095 #, c-format msgid "%s: %s: Invalid ELN\n" msgstr "" #: exec.c:1781 exec.c:1808 #, c-format msgid "%s: %s: Invalid argument. Try 'fz -h'\n" msgstr "" #: exec.c:628 #, c-format msgid "%s: %s: Invalid number\n" msgstr "" #: exec.c:1567 #, c-format msgid "%s: %s: Is a directory\n" msgstr "" #: misc.c:916 #, c-format msgid "%s: %s: No alias found\n" msgstr "" #: mime.c:1445 mime.c:1449 #, c-format msgid "%s: %s: No associated application found\n" msgstr "" #: navigation.c:371 #, c-format msgid "%s: %s: No matches found\n" msgstr "" #: exec.c:1056 #, c-format msgid "%s: %s: No such alias\n" msgstr "" #: colors.c:955 #, c-format msgid "%s: %s: No such color scheme. Falling back to default\n" msgstr "" #: colors.c:1064 #, c-format msgid "%s: %s: No such color scheme. Falling back to the default one\n" msgstr "" #: jump.c:432 #, c-format msgid "%s: %s: No such order number\n" msgstr "" #: profiles.c:393 #, c-format msgid "%s: %s: No such profile\n" msgstr "" #: profiles.c:132 #, c-format msgid "" "%s: %s: No such profile\n" "To add a new profile enter 'pf add PROFILE'\n" msgstr "" #: remotes.c:118 #, c-format msgid "%s: %s: No such remote\n" msgstr "" #: selection.c:888 #, c-format msgid "%s: %s: No such selected file\n" msgstr "" #: sort.c:457 #, c-format msgid "%s: %s: No such sorting method\n" msgstr "" #: tags.c:75 tags.c:158 #, c-format msgid "%s: %s: No such tag\n" msgstr "" #: misc.c:634 #, c-format msgid "%s: %s: Not a directory\n" msgstr "" #: file_operations.c:1044 #, c-format msgid "%s: %s: Not a symbolic link\n" msgstr "" #: remotes.c:225 #, c-format msgid "%s: %s: Not mounted\n" msgstr "" #: sanitize.c:368 #, c-format msgid "" "%s: %s: Only command base names are allowed. Ex: 'nano' instead of '/usr/bin/" "nano'\n" msgstr "" #: profiles.c:297 #, c-format msgid "%s: %s: Profile already exists\n" msgstr "" #: remotes.c:209 #, c-format msgid "%s: %s: Remote mounted on %s\n" msgstr "" #: tags.c:317 #, c-format msgid "%s: %s: Successfully removed tag\n" msgstr "" #: main.c:826 profiles.c:165 #, c-format msgid "" "%s: %s: System shell not found. Please edit the configuration file to " "specify a working shell.\n" msgstr "" #: tags.c:271 #, c-format msgid "%s: %s: Tag already exists\n" msgstr "" #: media.c:503 #, c-format msgid "%s: %s: This feature is not available on Haiku\n" msgstr "" #: init.c:1643 #, c-format msgid "%s: %s: Using alternative configuration directory\n" msgstr "" #: misc.c:934 #, c-format msgid "%s: %zu aliases were successfully imported\n" msgstr "" #: init.c:207 #, c-format msgid "" "%s: %zu: Invalid workspace.\n" "Falling back to workspace %zu\n" msgstr "" #: jump.c:410 #, c-format msgid "%s: '%c': Invalid option\n" msgstr "" #: search.c:114 search.c:535 selection.c:429 #, c-format msgid "%s: '%c': Unrecognized file type\n" msgstr "" #: profiles.c:141 #, c-format msgid "%s: '%s' is the current profile\n" msgstr "" #: config.c:1889 #, c-format msgid "%s: '%s': %s. Using the current working directory as starting path\n" msgstr "" #: config.c:1228 #, c-format msgid "" "%s: '%s': Directory not writable. Bookmarks, commands logs, and commands " "history are disabled. Program messages won't be persistent. Using default " "options\n" msgstr "" #: config.c:1202 #, c-format msgid "%s: '%s': Directory not writable. Trash function disabled\n" msgstr "" #: config.c:2023 misc.c:379 #, c-format msgid "%s: '%s': Invalid regular expression\n" msgstr "" #: profiles.c:363 #, c-format msgid "%s: '%s': Profile succesfully created\n" msgstr "" #: profiles.c:406 #, c-format msgid "%s: '%s': Profile successfully removed\n" msgstr "" #: exec.c:1462 #, c-format msgid "%s: '%s': Syntax error\n" msgstr "" #: checks.c:107 #, c-format msgid "" "%s: '%s': Unsupported terminal. This terminal cannot understand escape " "sequences\n" msgstr "" #: config.c:550 #, c-format msgid "" "%s: '%s': Using a temporary directory for the Selection Box. Selected files " "won't be persistent across reboots" msgstr "" #: navigation.c:338 #, c-format msgid "%s: /: No parent directory\n" msgstr "" #: misc.c:937 #, c-format msgid "%s: 1 alias was successfully imported\n" msgstr "" #: config.c:99 #, c-format msgid "%s: Access to configuration files is not allowed in stealth mode\n" msgstr "" #: misc.c:902 #, c-format msgid "%s: Alias already exists\n" msgstr "" #: misc.c:855 #, c-format msgid "%s: Alias conflicts with internal command\n" msgstr "" #: config.c:113 #, c-format msgid "%s: Cannot access the configuration file\n" msgstr "" #: init.c:149 #, c-format msgid "" "%s: Cannot access the home directory. Trash, bookmarks, commands logs, and " "commands history are disabled. Program messages and selected files won't be " "persistent. Using default options\n" msgstr "" #: tags.c:643 #, c-format msgid "%s: Cannot merge tags: error moving tagged files\n" msgstr "" #: bookmarks.c:597 #, c-format msgid "%s: Cannot open the bookmarks file\n" msgstr "" #: history.c:248 #, c-format msgid "%s: Could not save directory history: %s\n" msgstr "" #: colors.c:539 #, c-format msgid "%s: Current color scheme: %s\n" msgstr "" #: colors.c:1789 #, c-format msgid "%s: Currently running without colors\n" msgstr "" #: misc.c:607 #, c-format msgid "" "%s: Default terminal not set. Use the configuration file (F10) to set it\n" msgstr "" #: trash.c:150 #, c-format msgid "%s: Directory is immutable\n" msgstr "" #: jump.c:291 #, c-format msgid "%s: Directory jumper function disabled\n" msgstr "" #: init.c:1035 init.c:1043 selection.c:486 #, c-format msgid "%s: Error expanding path\n" msgstr "" #: init.c:1246 #, c-format msgid "%s: Error expanding tilde. Using default opener\n" msgstr "" #: mime.c:460 #, c-format msgid "%s: Error getting home directory\n" msgstr "" #: main.c:848 #, c-format msgid "%s: Error getting hostname\n" msgstr "" #: mime.c:1463 #, c-format msgid "%s: Error getting mime-type\n" msgstr "" #: remotes.c:230 #, c-format msgid "%s: Error getting mountpoint for '%s'\n" msgstr "" #: misc.c:1051 #, c-format msgid "%s: Error getting variable value\n" msgstr "" #: misc.c:777 #, c-format msgid "%s: Error lauching new instance\n" msgstr "" #: checks.c:99 #, c-format msgid "%s: Error opening terminal: unknown\n" msgstr "" #: profiles.c:217 #, c-format msgid "%s: Error opening the history file\n" msgstr "" #: checks.c:512 #, c-format msgid "%s: Error parsing aliased command\n" msgstr "" #: history.c:503 history.c:522 history.c:556 #, c-format msgid "%s: Error parsing history command\n" msgstr "" #: media.c:447 #, c-format msgid "%s: Error retrieving mountpoint\n" msgstr "" #: init.c:387 #, c-format msgid "%s: Error retrieving user data\n" msgstr "" #: misc.c:968 #, c-format msgid "%s: Error saving last visited directory\n" msgstr "" #: misc.c:1566 #, c-format msgid "%s: Error storing pinned directory\n" msgstr "" #: selection.c:572 #, c-format msgid "%s: Error writing selected files to the selections file\n" msgstr "" #: exec.c:535 #, c-format msgid "%s: External commands are not allowed. Run 'ext on' to enable them.\n" msgstr "" #: init.c:1350 #, c-format msgid "%s: FZF not found. Falling back to standard TAB completion\n" msgstr "" #: init.c:251 main.c:815 #, c-format msgid "%s: Fatal error! Failed retrieving current working directory\n" msgstr "" #: trash.c:203 #, c-format msgid "%s: File is immutable\n" msgstr "" #: misc.c:614 #, c-format msgid "%s: Function only available for graphical environments\n" msgstr "" #: history.c:428 #, c-format msgid "%s: History function disabled\n" msgstr "" #: bookmarks.c:694 bookmarks.c:775 #, c-format msgid "%s: Invalid bookmark\n" msgstr "" #: navigation.c:625 #, c-format msgid "%s: Invalid history entry\n" msgstr "" #: exec.c:1654 #, c-format msgid "%s: Lira: %s\n" msgstr "" #: init.c:1609 #, c-format msgid "%s: Loaded alternative bookmarks file\n" msgstr "" #: init.c:1698 #, c-format msgid "%s: Loaded alternative configuration file\n" msgstr "" #: init.c:1670 #, c-format msgid "%s: Loaded alternative keybindings file\n" msgstr "" #: exec.c:1100 #, c-format msgid "%s: Log function disabled\n" msgstr "" #: strings.c:645 strings.c:702 #, c-format msgid "%s: Missing '%c'\n" msgstr "" #: remotes.c:386 #, c-format msgid "%s: Mounting remote...\n" msgstr "" #: misc.c:386 #, c-format msgid "%s: New filter successfully set\n" msgstr "" #: misc.c:926 #, c-format msgid "%s: No alias imported\n" msgstr "" #: exec.c:1022 exec.c:1042 #, c-format msgid "%s: No aliases found\n" msgstr "" #: colors.c:408 #, c-format msgid "%s: No color schemes found\n" msgstr "" #: selection.c:583 #, c-format msgid "%s: No matches found\n" msgstr "" #: media.c:193 media.c:400 #, c-format msgid "%s: No mount application found. Install either udevil or udisks2\n" msgstr "" #: media.c:517 #, c-format msgid "%s: No mount command found. Install either udevil or udisks2\n" msgstr "" #: remotes.c:172 #, c-format msgid "%s: No mount command specified for '%s'\n" msgstr "" #: remotes.c:123 #, c-format msgid "%s: No mountpoint specified for '%s'\n" msgstr "" #: misc.c:717 #, c-format msgid "" "%s: No option specified for '%s'\n" "Trying '%s -e %s %s'\n" msgstr "" #: exec.c:1421 keybinds.c:1444 misc.c:1624 #, c-format msgid "%s: No pinned file\n" msgstr "" #: remotes.c:48 #, c-format msgid "%s: No remotes defined\n" msgstr "" #: bookmarks.c:678 #, c-format msgid "%s: No such ELN\n" msgstr "" #: bookmarks.c:699 bookmarks.c:780 #, c-format msgid "%s: No such bookmark\n" msgstr "" #: colors.c:496 #, c-format msgid "%s: No such color scheme\n" msgstr "" #: trash.c:122 #, c-format msgid "%s: No such file or directory\n" msgstr "" #: tags.c:455 #, c-format msgid "" "%s: No tag specified. Specify a tag via :TAG. E.g. tag FILE1 FILE2 :TAG\n" msgstr "" #: tags.c:67 #, c-format msgid "%s: No tags found, Use 'tag new' to create new tags\n" msgstr "" #: remotes.c:236 #, c-format msgid "%s: No unmount command found for '%s'\n" msgstr "" #: file_operations.c:486 name_cleaner.c:561 name_cleaner.c:611 #, c-format msgid "%s: Nothing to do\n" msgstr "" #: mime.c:531 #, c-format msgid "%s: Nothing was imported. No MIME definitions found\n" msgstr "" #: mime.c:454 #, c-format msgid "%s: Nothing was imported. No graphical environment found\n" msgstr "" #: trash.c:90 trash.c:182 trash.c:190 trash.c:210 trash.c:226 #, c-format msgid "%s: Permission denied\n" msgstr "" #: keybinds.c:96 keybinds.c:139 #, c-format msgid "%s: Restart the program for changes to take effect\n" msgstr "" #: config.c:2086 #, c-format msgid "" "%s: Running in stealth mode: trash, persistent selection and directory " "history, just as bookmarks, logs and configuration files, are disabled.\n" msgstr "" #: misc.c:1616 #, c-format msgid "%s: Succesfully pinned '%s'\n" msgstr "" #: tags.c:282 #, c-format msgid "%s: Successfully created tag\n" msgstr "" #: media.c:558 #, c-format msgid "%s: There are no available %s\n" msgstr "" #: exec.c:932 exec.c:950 #, c-format msgid "%s: There are no messages\n" msgstr "" #: exec.c:415 #, c-format msgid "%s: To gracefully quit enter 'q'\n" msgstr "" #: trash.c:797 trash.c:1085 #, c-format msgid "%s: Trash function disabled\n" msgstr "" #: misc.c:1703 #, c-format msgid "%s: Unable to find any pager\n" msgstr "" #: media.c:221 #, c-format msgid "%s: Unmounted %s\n" msgstr "" #: remotes.c:423 #, c-format msgid "%s: Unmounting remote...\n" msgstr "" #: main.c:744 #, c-format msgid "%s: Unsupported CPU architecture\n" msgstr "" #: main.c:750 #, c-format msgid "%s: Unsupported operating system\n" msgstr "" #: exec.c:2194 #, c-format msgid "%s: archiving: %s\n" msgstr "" #: exec.c:2175 #, c-format msgid "%s: bleach: %s\n" msgstr "" #: bookmarks.c:814 #, c-format msgid "%s: bookmarks: %s\n" msgstr "" #: navigation.c:444 #, c-format msgid "%s: cd: Home directory not found\n" msgstr "" #: colors.c:512 #, c-format msgid "" "%s: color schemes: %s\n" "TIP: To change the current color scheme use the following environment " "variables: CLIFM_FILE_COLORS, CLIFM_IFACE_COLORS, and CLIFM_EXT_COLORS\n" msgstr "" #: mime.c:1613 #, c-format msgid "%s: file: Command not found\n" msgstr "" #: config.c:1499 #, c-format msgid "%s: fopen: '%s': %s. Using default values.\n" msgstr "" #: checks.c:161 #, c-format msgid "%s: fzf not found. Falling back to standard TAB completion\n" msgstr "" #: init.c:1357 #, c-format msgid "%s: fzftab: %s\n" msgstr "" #: init.c:1379 #, c-format msgid "%s: fzytab: %s\n" msgstr "" #: init.c:1335 #, c-format msgid "%s: highlight: %s\n" msgstr "" #: exec.c:893 init.c:1267 #, c-format msgid "%s: icons: %s\n" msgstr "" #: jump.c:663 #, c-format msgid "%s: jump: No matches found\n" msgstr "" #: media.c:510 #, c-format msgid "%s: media: Function only available on Linux systems\n" msgstr "" #: profiles.c:315 #, c-format msgid "%s: mkdir: %s: Error creating configuration directory\n" msgstr "" #: config.c:1216 #, c-format msgid "" "%s: mkdir: '%s': Error creating configuration directory. Bookmarks, commands " "logs, and command history are disabled. Program messages won't be " "persistent. Using default options\n" msgstr "" #: config.c:1194 #, c-format msgid "" "%s: mkdir: '%s': Error creating trash directory. Trash function disabled\n" msgstr "" #: config.c:1277 #, c-format msgid "" "%s: mkdir: Error creating colors directory. Using the default color scheme\n" msgstr "" #: config.c:1289 #, c-format msgid "" "%s: mkdir: Error creating plugins directory. The actions function is " "disabled\n" msgstr "" #: init.c:1504 #, c-format msgid "" "%s: option requires an argument -- '%c'\n" "Try '%s --help' for more information.\n" msgstr "" #: selection.c:123 #, c-format msgid "%s: sel: %s: Already selected\n" msgstr "" #: selection.c:327 #, c-format msgid "%s: sel: %s: Invalid regular expression\n" msgstr "" #: trash.c:637 #, c-format msgid "%s: trash: %d: Invalid ELN\n" msgstr "" #: exec.c:1742 exec.c:1766 init.c:1290 #, c-format msgid "%s: trash: %s\n" msgstr "" #: trash.c:234 #, c-format msgid "%s: trash: %s (%s): Unsupported file type\n" msgstr "" #: trash.c:419 #, c-format msgid "" "%s: trash: %s/%s: Failed removing trash file\n" "Try removing it manually\n" msgstr "" #: trash.c:350 #, c-format msgid "%s: trash: %s: Error getting file name\n" msgstr "" #: trash.c:291 #, c-format msgid "%s: trash: %s: Error removing trashed file\n" msgstr "" #: trash.c:394 #, c-format msgid "%s: trash: %s: Failed copying file to Trash\n" msgstr "" #: trash.c:440 #, c-format msgid "%s: trash: %s: Failed encoding path\n" msgstr "" #: trash.c:615 #, c-format msgid "%s: trash: %s: Invalid ELN\n" msgstr "" #: trash.c:596 trash.c:646 #, c-format msgid "%s: trash: Error trashing %s\n" msgstr "" #: checks.c:123 #, c-format msgid "%s: udisks2 not found. Falling back to udevil\n" msgstr "" #: trash.c:933 #, c-format msgid "%s: undel: %d: Invalid ELN\n" msgstr "" #: trash.c:714 #, c-format msgid "%s: undel: %s: Error decoding original path\n" msgstr "" #: trash.c:770 #, c-format msgid "%s: undel: %s: Error removing info file\n" msgstr "" #: trash.c:777 #, c-format msgid "%s: undel: %s: Error restoring trashed file\n" msgstr "" #: trash.c:676 #, c-format msgid "" "%s: undel: Info file for '%s' not found. Try restoring the file manually\n" msgstr "" #: init.c:1525 #, c-format msgid "%s: unknown option character '\\%x'\n" msgstr "" #: init.c:1521 #, c-format msgid "" "%s: unrecognized option '%c'\n" "Try '%s --help' for more information.\n" msgstr "" #: init.c:1513 #, c-format msgid "" "%s: unrecognized option '%s'\n" "Try '%s --help' for more information.\n" msgstr "" #: bookmarks.c:609 #, c-format msgid "" "%sBookmarks Manager%s\n" "\n" msgstr "" #: bookmarks.c:208 #, c-format msgid "" "%sBookmarks%s\n" "\n" msgstr "" #: colors.c:1844 #, c-format msgid "" "%sExtension colors%s\n" "\n" msgstr "" #: colors.c:1795 #, c-format msgid "" "%sFile type colors%s\n" "\n" msgstr "" #: archives.c:1028 #, c-format msgid "%sFile%s: %s\n" msgstr "" #: media.c:526 #, c-format msgid "" "%sMountpoints%s\n" "\n" msgstr "" #: archives.c:940 #, c-format msgid "%sNOTE%s: Using Zstandard\n" msgstr "" #: selection.c:551 #, c-format msgid "%sSelection Box%s\n" msgstr "" #: trash.c:535 trash.c:862 #, c-format msgid "" "%sTrashed files%s\n" "\n" msgstr "" #: archives.c:1205 #, c-format msgid "" "%s[e]%sxtract %s[E]%sxtract-to-dir %s[l]%sist %s[m]%sount %s[r]%sepack " "%s[q]%suit\n" msgstr "" #: archives.c:321 #, c-format msgid "" "%s[e]%sxtract %s[E]%sxtract-to-dir %s[l]%sist %s[t]%sest %s[m]%sount " "%s[q]%suit\n" msgstr "" #: archives.c:757 archives.c:941 #, c-format msgid "%s[e]%sxtract %s[t]%sest %s[i]%snfo %s[q]%suit\n" msgstr "" #: selection.c:941 #, c-format msgid "%zu file(s) currently selected\n" msgstr "" #: selection.c:601 #, c-format msgid "%zu files are now in the Selection Box\n" msgstr "" #: selection.c:603 #, c-format msgid "" "%zu selected file(s):\n" "\n" msgstr "" #: search.c:634 #, c-format msgid "'%s': Invalid regular expression\n" msgstr "" #: properties.c:424 #, c-format msgid "Access: \t%s%s%s\n" msgstr "" #: bookmarks.c:292 msgid "All bookmarks succesfully removed\n" msgstr "" #: selection.c:1106 msgid "All files deselected\n" msgstr "" #: mime.c:1482 #, c-format msgid "Associated application: %s [%s]\n" msgstr "" #: mime.c:1432 msgid "Associated application: None\n" msgstr "" #: mime.c:1479 #, c-format msgid "Associated application: ad [built-in] [%s]\n" msgstr "" #: exec.c:844 #, c-format msgid "Auto-open disabled\n" msgstr "" #: exec.c:841 #, c-format msgid "Auto-open enabled\n" msgstr "" #: exec.c:846 #, c-format msgid "Auto-open is %s\n" msgstr "" #: exec.c:818 #, c-format msgid "Autocd disabled\n" msgstr "" #: exec.c:815 #, c-format msgid "Autocd enabled\n" msgstr "" #: exec.c:820 #, c-format msgid "Autocd is %s\n" msgstr "" #: properties.c:429 #, c-format msgid "Birth: \t\t%s%s%s\n" msgstr "" #: properties.c:388 #, c-format msgid "Block special file" msgstr "" #: bookmarks.c:450 msgid "Bookmark line example: [sc]name:path" msgstr "" #: bookmarks.c:217 msgid "Bookmark(s) to be deleted (ex: 1 2-6, or *): " msgstr "" #: bookmarks.c:819 #, c-format msgid "Bookmarks function disabled\n" msgstr "" #: bookmarks.c:799 #, c-format msgid "Bookmarks: %s: %s\n" msgstr "" #: properties.c:426 #, c-format msgid "Change: \t%s%s%s\n" msgstr "" #: properties.c:389 #, c-format msgid "Character special file" msgstr "" #: bookmarks.c:93 msgid "Choose a bookmark: " msgstr "" #: media.c:611 msgid "Choose a mountpoint/device: " msgstr "" #: media.c:609 media.c:613 msgid "Choose a mountpoint: " msgstr "" #: mime.c:586 msgid "Choose an application ('q' to quit): " msgstr "" #: listing.c:309 #, c-format msgid "Color scheme %s->%s %s\n" msgstr "" #: exec.c:879 msgid "Columns disabled\n" msgstr "" #: exec.c:872 msgid "Columns enabled\n" msgstr "" #: file_operations.c:1562 msgid "Continue? [y/N] " msgstr "" #: tags.c:393 #, c-format msgid "Created new tag %s%s%s\n" msgstr "" #: misc.c:396 #, c-format msgid "Current filter: %c%s\n" msgstr "" #: properties.c:414 #, c-format msgid "Device: %s%d%s" msgstr "" #: properties.c:416 #, c-format msgid "Device: %s%zu%s" msgstr "" #: properties.c:385 #, c-format msgid "Directory" msgstr "" #: selection.c:737 msgid "Empty" msgstr "" #: file_operations.c:739 msgid "End filename with a slash to create a directory" msgstr "" #: media.c:601 msgid "Enter 'iELN' for device information. Ex: i4" msgstr "" #: archives.c:1081 media.c:600 msgid "Enter 'q' to quit" msgstr "" #: file_operations.c:1716 msgid "Enter links suffix ('q' to quit): " msgstr "" #: history.c:129 msgid "Error getting command!" msgstr "" #: mime.c:344 msgid "Error opening temporary file\n" msgstr "" #: archives.c:410 archives.c:419 archives.c:523 archives.c:532 msgid "Error querying file type\n" msgstr "" #: listing.c:1670 listing.c:2218 #, c-format msgid "Excluded files: %d\n" msgstr "" #: exec.c:793 #, c-format msgid "External commands allowed\n" msgstr "" #: exec.c:789 #, c-format msgid "External commands are %s\n" msgstr "" #: exec.c:796 #, c-format msgid "External commands disallowed\n" msgstr "" #: archives.c:62 msgid "Extraction path ('q' to quit): " msgstr "" #: properties.c:390 #, c-format msgid "Fifo" msgstr "" #: archives.c:673 msgid "File name ('q' to quit): " msgstr "" #: bookmarks.c:572 #, c-format msgid "File succesfully bookmarked\n" msgstr "" #: selection.c:994 msgid "File(s) to be deselected (ex: 1 2-6, or *): " msgstr "" #: trash.c:563 msgid "File(s) to be removed (ex: 1 2-6, or *): " msgstr "" #: trash.c:881 msgid "File(s) to be undeleted (ex: 1 2-6, or *): " msgstr "" #: file_operations.c:740 msgid "Filename ('q' to quit): " msgstr "" #: exec.c:725 msgid "Files counter disabled\n" msgstr "" #: exec.c:718 msgid "Files counter enabled\n" msgstr "" #: misc.c:369 msgid "Filter unset" msgstr "" #: keybinds.c:842 #, c-format msgid "Folders first %s\n" msgstr "" #: exec.c:698 msgid "Folders first disabled\n" msgstr "" #: exec.c:694 msgid "Folders first enabled\n" msgstr "" #: exec.c:689 #, c-format msgid "Folders first is %s\n" msgstr "" #: exec.c:1803 msgid "Full directory size disabled\n" msgstr "" #: exec.c:1792 msgid "Full directory size enabled\n" msgstr "" #: exec.c:1799 msgid "Full directory size is already disabled" msgstr "" #: exec.c:1788 msgid "Full directory size is already enabled" msgstr "" #: search.c:211 msgid "Glob: No matches found. Trying regex..." msgstr "" #: keybinds.c:894 #, c-format msgid "Hidden files %s\n" msgstr "" #: exec.c:1121 msgid "Hidden files disabled\n" msgstr "" #: exec.c:1128 msgid "Hidden files enabled\n" msgstr "" #: exec.c:1113 #, c-format msgid "Hidden files is %s\n" msgstr "" #: history.c:405 #, c-format msgid "History is %s\n" msgstr "" #: archives.c:692 #, c-format msgid "Invalid file name\n" msgstr "" #: name_cleaner.c:572 msgid "Is this OK? [y/N/(e)dit] " msgstr "" #: history.c:88 #, c-format msgid "Logs %s\n" msgstr "" #: history.c:103 msgid "Logs already disabled" msgstr "" #: history.c:93 msgid "Logs already enabled" msgstr "" #: history.c:106 msgid "Logs succesfully disabled" msgstr "" #: history.c:96 msgid "Logs successfully enabled" msgstr "" #: keybinds.c:810 #, c-format msgid "Long view mode %s\n" msgstr "" #: mime.c:1472 #, c-format msgid "MIME type: %s\n" msgstr "" #: search.c:457 #, c-format msgid "Matches found: %d\n" msgstr "" #: search.c:810 #, c-format msgid "Matches found: %zu\n" msgstr "" #: exec.c:622 exec.c:634 #, c-format msgid "Max files set to %d\n" msgstr "" #: exec.c:615 msgid "Max files unset\n" msgstr "" #: exec.c:603 #, c-format msgid "Max files: %d\n" msgstr "" #: exec.c:601 msgid "Max files: unset" msgstr "" #: keybinds.c:339 #, c-format msgid "Max name length set back to %d\n" msgstr "" #: keybinds.c:337 msgid "Max name length unset\n" msgstr "" #: media.c:504 msgid "Media" msgstr "" #: properties.c:425 #, c-format msgid "Modify: \t%s%s%s\n" msgstr "" #: media.c:524 msgid "Mounted devices" msgstr "" #: media.c:504 media.c:523 msgid "Mountpoints" msgstr "" #: jump.c:313 msgid "" "NOTE 2: An asterisk next rank values means that the corresponding directory " "is bookmarked, pinned, or currently used in some workspace\n" msgstr "" #: jump.c:311 msgid "" "NOTE: First time access is displayed in days, while last time access is " "displayed in hours" msgstr "" #: mime.c:1471 remotes.c:56 #, c-format msgid "Name: %s\n" msgstr "" #: config.c:87 #, c-format msgid "New configuration file written to '%s'\n" msgstr "" #: archives.c:1085 msgid "New format (ex: .tar.xz): " msgstr "" #: file_operations.c:1068 msgid "New path ('q' to quit): " msgstr "" #: remotes.c:69 msgid "No" msgstr "" #: config.c:58 msgid "No configuration file found" msgstr "" #: tags.c:167 #, c-format msgid "No file tagged as '%s'\n" msgstr "" #: misc.c:361 msgid "No filter set" msgstr "" #: search.c:673 search.c:812 #, c-format msgid "No matches found\n" msgstr "" #: exec.c:1210 msgid "No pinned file" msgstr "" #: mime.c:1378 msgid "No such ELN" msgstr "" #: mime.c:1471 msgid "None" msgstr "" #: config.c:80 #, c-format msgid "Old configuration file stored as '%s'\n" msgstr "" #: keybinds.c:1533 #, c-format msgid "Only directories %s\n" msgstr "" #: exec.c:975 #, c-format msgid "Opener set to '%s'\n" msgstr "" #: archives.c:117 archives.c:762 archives.c:948 msgid "Operation: " msgstr "" #: jump.c:316 msgid "Order\tVisits\tFirst\tLast\tRank\tDirectory" msgstr "" #: exec.c:765 msgid "Pager disabled\n" msgstr "" #: exec.c:761 msgid "Pager enabled\n" msgstr "" #: exec.c:1208 #, c-format msgid "Pinned file: %s\n" msgstr "" #: properties.c:391 #, c-format msgid "Regular file" msgstr "" #: file_operations.c:1127 msgid "Relink as a broken symbolic link? [y/n] " msgstr "" #: properties.c:434 #, c-format msgid "Size: \t\t%s%s%s\n" msgstr "" #: properties.c:386 #, c-format msgid "Socket" msgstr "" #: listing.c:304 msgid "Sorted by: " msgstr "" #: sort.c:466 msgid "Sorting method: " msgstr "" #: misc.c:1643 #, c-format msgid "Succesfully unpinned %s\n" msgstr "" #: tags.c:656 #, c-format msgid "Successfully merged %s%s%s into %s%s%s\n" msgstr "" #: bookmarks.c:365 #, c-format msgid "Successfully removed '%s'\n" msgstr "" #: tags.c:484 #, c-format msgid "Successfully tagged %zu file(s)\n" msgstr "" #: tags.c:554 #, c-format msgid "Successfully untagged %zu file(s)\n" msgstr "" #: exec.c:991 exec.c:995 keybinds.c:870 msgid "Switched back to normal mode\n" msgstr "" #: keybinds.c:868 msgid "Switched to light mode\n" msgstr "" #: properties.c:387 #, c-format msgid "Symbolic link" msgstr "" #: exec.c:733 msgid "The files counter is disabled" msgstr "" #: exec.c:731 msgid "The files counter is enabled" msgstr "" #: exec.c:756 #, c-format msgid "The files pager is %s\n" msgstr "" #: exec.c:1188 #, c-format msgid "Toggled executable bit on %zu %s\n" msgstr "" #: exec.c:1689 #, c-format msgid "" "Total files: %zu\n" "Directories: %zu\n" "Regular files: %zu\n" "Executable files: %zu\n" "Hidden files: %zu\n" "SUID files: %zu\n" "SGID files: %zu\n" "Files w/capabilities: %zu\n" "FIFO/pipes: %zu\n" "Sockets: %zu\n" "Block devices: %zu\n" "Character devices: %zu\n" "Symbolic links: %zu\n" "Broken symbolic links: %zu\n" "Multi-link files: %zu\n" "Files w/extended attributes: %zu\n" "Other-writable files: %zu\n" "Sticky files: %zu\n" "Unknown file types: %zu\n" "Unstatable files: %zu\n" msgstr "" #: properties.c:441 msgid "Total size: \t" msgstr "" #: listing.c:1400 #, c-format msgid "" "Total size: %s%s%s\n" "Largest file: %s%s%s %c%s%s%s%c\n" msgstr "" #: mime.c:555 msgid "Try 'mm, mime edit APPLICATION'\n" msgstr "" #: exec.c:661 msgid "Unicode disabled" msgstr "" #: exec.c:658 msgid "Unicode enabled" msgstr "" #: exec.c:655 #, c-format msgid "Unicode is %s\n" msgstr "" #: archives.c:669 msgid "" "Use extension to specify archive/compression type (defaults to .tar.gz)\n" "Example: myarchive.xz" msgstr "" #: remotes.c:70 msgid "Yes" msgstr "" #: actions.c:371 msgid "actions: No actions defined. Use the 'actions edit' command to add some" msgstr "" #: exec.c:790 msgid "allowed" msgstr "" #: archives.c:713 #, c-format msgid "archiver: %s: Error dequoting file name\n" msgstr "" #: archives.c:909 #, c-format msgid "archiver: %s: Not an archive/compressed file\n" msgstr "" #: sort.c:378 #, c-format msgid "atime %s\n" msgstr "" #: bookmarks.c:200 bookmarks.c:244 #, c-format msgid "bookmarks: %s: No such bookmark\n" msgstr "" #: bookmarks.c:416 #, c-format msgid "bookmarks: %s: Path already bookmarked\n" msgstr "" #: bookmarks.c:493 #, c-format msgid "bookmarks: %s: This name is already in use\n" msgstr "" #: bookmarks.c:461 #, c-format msgid "bookmarks: %s: This shortcut is already in use\n" msgstr "" #: bookmarks.c:274 #, c-format msgid "" "bookmarks: All bookmarks were deleted\n" " However, a backup copy was created (%s)\n" msgstr "" #: bookmarks.c:279 #, c-format msgid "bookmarks: Error creating backup file. No bookmark was deleted\n" msgstr "" #: bookmarks.c:309 #, c-format msgid "bookmarks: Error creating temporary file\n" msgstr "" #: bookmarks.c:546 #, c-format msgid "bookmarks: Error generating the bookmark line\n" msgstr "" #: bookmarks.c:391 bookmarks.c:554 bookmarks.c:563 #, c-format msgid "bookmarks: Error opening the bookmarks file\n" msgstr "" #: bookmarks.c:226 #, c-format msgid "bookmarks: Error parsing input\n" msgstr "" #: bookmarks.c:162 msgid "bookmarks: There are no bookmarks" msgstr "" #: sort.c:381 #, c-format msgid "btime %s\n" msgstr "" #: sort.c:383 #, c-format msgid "btime (not available: using 'ctime') %s\n" msgstr "" #: file_operations.c:1473 #, c-format msgid "bulk: %s\n" msgstr "" #: file_operations.c:1436 #, c-format msgid "bulk: %s: Error dequoting file name\n" msgstr "" #: file_operations.c:1514 msgid "bulk: Line mismatch in renaming file\n" msgstr "" #: file_operations.c:1493 file_operations.c:1548 msgid "bulk: Nothing to do" msgstr "" #: sort.c:387 #, c-format msgid "ctime %s\n" msgstr "" #: selection.c:1053 #, c-format msgid "desel: '%s': Invalid ELN\n" msgstr "" #: selection.c:1042 #, c-format msgid "desel: '%s': Invalid entry\n" msgstr "" #: selection.c:1094 msgid "desel: There are no selected files" msgstr "" #: media.c:559 msgid "devices" msgstr "" #: exec.c:655 exec.c:690 exec.c:757 exec.c:820 exec.c:846 exec.c:1114 #: history.c:89 msgid "disabled" msgstr "" #: exec.c:655 exec.c:690 exec.c:757 exec.c:820 exec.c:846 exec.c:1114 #: history.c:88 msgid "enabled" msgstr "" #: sort.c:393 #, c-format msgid "extension %s\n" msgstr "" #: remotes.c:66 remotes.c:68 msgid "false" msgstr "" #: exec.c:1189 msgid "file" msgstr "" #: exec.c:1189 msgid "files" msgstr "" #: navigation.c:619 #, c-format msgid "history: %d: No such ELN\n" msgstr "" #: sort.c:395 #, c-format msgid "inode %s\n" msgstr "" #: media.c:559 msgid "mountpoints" msgstr "" #: media.c:561 msgid "mp: There are no available mountpoints\n" msgstr "" #: sort.c:389 #, c-format msgid "mtime %s\n" msgstr "" #: sort.c:374 #, c-format msgid "name %s\n" msgstr "" #: sort.c:372 msgid "none" msgstr "" #: exec.c:790 msgid "not allowed" msgstr "" #: sort.c:376 #, c-format msgid "size %s\n" msgstr "" #: trash.c:1028 #, c-format msgid "trash: %s: %s\n" msgstr "" #: trash.c:1034 #, c-format msgid "trash: %s: Cannot trash a %s device\n" msgstr "" #: trash.c:1016 #, c-format msgid "trash: Cannot trash '%s'\n" msgstr "" #: trash.c:541 trash.c:830 trash.c:984 msgid "trash: No trashed files" msgstr "" #: trash.c:263 msgid "trash: There are no trashed files" msgstr "" #: trash.c:1022 msgid "trash: Use 'trash del' to remove trashed files" msgstr "" #: remotes.c:66 remotes.c:68 msgid "true" msgstr "" #: trash.c:908 #, c-format msgid "undel: %s: Invalid ELN\n" msgstr "" #: properties.c:418 properties.c:420 msgid "unknown" msgstr "" #: sort.c:391 #, c-format msgid "version %s\n" msgstr "" clifm-1.26.3/translations/clifm.pot000066400000000000000000002262001506632037700172470ustar00rootroot00000000000000# Clifm File Manager. # Copyright (C) 2025 L. Abramovich # This file is distributed under the same license as the Clifm package. # L. Abramovich , 2025. msgid "" msgstr "" "Project-Id-Version: clifm\n" "Report-Msgid-Bugs-To: https://github.com/leo-arch/clifm/issues\n" "POT-Creation-Date: 2025-03-16 00:42-0300\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: properties.c:1296 #, c-format msgid "\tBlocks: %s%jd%s" msgstr "" #: properties.c:1302 #, c-format msgid "\tInode: %s%ju%s" msgstr "" #: properties.c:1094 properties.c:1103 #, c-format msgid "\tName: %s%s%s\n" msgstr "" #: properties.c:1127 #, c-format msgid "\tName: %s%s%s %s%s ???%s\n" msgstr "" #: properties.c:1089 properties.c:1119 #, c-format msgid "\tName: %s%s%s %s%s%s %s%s%s\n" msgstr "" #: properties.c:1124 #, c-format msgid "\tName: %s%s%s %s%s%s %s%s%s (broken link)\n" msgstr "" #: jump.c:452 #, c-format msgid "" "\n" " %sOrder\tVisits\tFirst\tLast\tRank\tDirectory%s\n" msgstr "" #: keybinds.c:2747 #, c-format msgid "" "\n" "%s: No pinned file\n" msgstr "" #: keybinds.c:2397 #, c-format msgid "" "\n" "%s: No selected files\n" msgstr "" #: trash.c:436 #, c-format msgid "" "\n" "%sEnter 'q' to quit\n" "File(s) to be %s (e.g.: 1 2-6, or *):\n" msgstr "" #: selection.c:1133 #, c-format msgid "" "\n" "%sEnter 'q' to quit or 'e' to edit the selections file\n" "File(s) to be deselected (e.g.: 1 2-6, or *):\n" msgstr "" #: colors.c:2885 #, c-format msgid "" "\n" "%sFile extensions%s\n" "\n" msgstr "" #: colors.c:3086 #, c-format msgid "" "\n" "%sInterface%s\n" "\n" msgstr "" #: archives.c:656 #, c-format msgid "" "\n" "%sNOTE%s: Zstandard does not support compression of multiple files into a " "single compressed file. Instead, files will be compressed into multiple " "compressed files using their original filenames.\n" msgstr "" #: colors.c:3142 #, c-format msgid "" "\n" "%sPrompt%s\n" "\n" msgstr "" #: colors.c:3046 #, c-format msgid "" "\n" "%sProperties / Long view%s\n" "\n" msgstr "" #: colors.c:3209 #, c-format msgid "" "\n" "%sSyntax highlighting%s\n" "\n" msgstr "" #: trash.c:937 #, c-format msgid "" "\n" "%sTotal size: " msgstr "" #: selection.c:922 #, c-format msgid "" "\n" "%sTotal size: %s%s%s%s\n" msgstr "" #: media.c:226 #, c-format msgid "" "\n" "%sUnmounted devices%s\n" "\n" msgstr "" #: colors.c:3119 #, c-format msgid "" "\n" "%sWorkspaces%s\n" "\n" msgstr "" #: colors.c:3108 #, c-format msgid "" "\n" "(%s1%s) Used only when ColorLinksAsTarget is enabled\n" msgstr "" #: keybinds.c:1225 msgid "" "\n" "Note: Bear in mind that clifm's keybindings take precedence over " "readline's.\n" "To modify readline's keybindings edit ~/.config/clifm/readline.clifm" msgstr "" #: keybinds.c:2413 msgid "" "\n" "Ready to archive/compress selected files." msgstr "" #: keybinds.c:2445 msgid "" "\n" "Ready to export selected filenames" msgstr "" #: colors.c:3264 msgid "" "\n" "The bracketed field is the code required to modify the color of the " "corresponding element in the color scheme file.\n" "\n" msgstr "" #: jump.c:558 #, c-format msgid "" "\n" "Total rank: %d/%d\n" "Total visits: %d\n" msgstr "" #: colors.c:1070 msgid "" "\n" "You can also edit 'settings.h' in the source code and recompile.\n" msgstr "" #: jump.c:631 #, c-format msgid "" "\n" "jump: Purged %d %s\n" msgstr "" #: jump.c:590 #, c-format msgid "" "\n" "jump: Purged %d invalid %s\n" msgstr "" #: colors.c:3004 msgid "" " (dd) Date (unset: using shades)\n" " " msgstr "" #: colors.c:2981 msgid "" " (dz) Size (unset: using shades)\n" " " msgstr "" #: properties.c:1297 #, c-format msgid " Block size: %s%d%s" msgstr "" #: properties.c:1310 #, c-format msgid " Device type: %s%ju,%ju%s\n" msgstr "" #: properties.c:1306 #, c-format msgid " Gid: %s%u (%s)%s" msgstr "" #: properties.c:1298 #, c-format msgid " IO Block: %s%jd%s\n" msgstr "" #: properties.c:1304 #, c-format msgid " Uid: %s%u (%s)%s" msgstr "" #: sort.c:372 #, c-format msgid " (not available in light mode: using %sname%s)\n" msgstr "" #: colors.c:66 msgid " (on LSCOLORS)" msgstr "" #: colors.c:65 msgid " (on LS_COLORS)" msgstr "" #: file_operations.c:2021 msgid " (recursively)" msgstr "" #: remotes.c:66 #, c-format msgid " Auto-mount: %s\n" msgstr "" #: remotes.c:64 #, c-format msgid " Auto-unmount: %s\n" msgstr "" #: remotes.c:57 #, c-format msgid " Comment: %s\n" msgstr "" #: remotes.c:61 #, c-format msgid " Mount command: %s\n" msgstr "" #: remotes.c:68 #, c-format msgid " Mounted: %s%s%s\n" msgstr "" #: remotes.c:59 #, c-format msgid " Mountpoint: %s\n" msgstr "" #: remotes.c:63 #, c-format msgid " Unmount command: %s\n" msgstr "" #: config.c:2275 #, c-format msgid "" "# This is %s's profile file\n" "#\n" "# Write here the commands you want to be executed at startup.\n" "# E.g.:\n" "#echo \"%s, the command line file manager\"; read -r\n" "#\n" "# Uncommented, non-empty lines are executed line by line. If you\n" "# want a multi-line command, just write a script for it:\n" "#sh /path/to/my/script.sh\n" msgstr "" #: mime.c:1460 #, c-format msgid "" "%d MIME association(s) imported from the system.\n" "File saved as '%s'\n" "Add these new associations to your mimelist file by running 'mm edit'.\n" msgstr "" #: selection.c:1074 #, c-format msgid "%d file(s) deselected\n" msgstr "" #: selection.c:668 #, c-format msgid "%d file(s) selected\n" msgstr "" #: name_cleaner.c:679 #, c-format msgid "%d filename(s) bleached\n" msgstr "" #: help.c:568 #, c-format msgid "%s %s (%s), by %s\n" msgstr "" #: misc.c:2150 #, c-format msgid "" "%s %s%s%s%s%s (%s)\n" "%s\n" "License %s\n" "Written by %s\n" msgstr "" #: tags.c:114 #, c-format msgid "%s (error resolving link target)\n" msgstr "" #: jump.c:439 #, c-format msgid "" "%s A plus sign next rank values means that the corresponding directory is " "marked as permanent (it will not be removed).\n" msgstr "" #: jump.c:434 #, c-format msgid "" "%s An asterisk next rank values means that the corresponding directory will " "not be removed despite its rank, either because it was visited in the last " "24 hours, or because it is bookmarked, pinned, or currently active in some " "workspace.\n" msgstr "" #: jump.c:448 #, c-format msgid "" "%s Entries ranked below MinJumpRank (currently %d) will be removed at " "program exit.\n" msgstr "" #: jump.c:432 #, c-format msgid "" "%s First time access is displayed in days, while last time access is " "displayed in hours.\n" msgstr "" #: jump.c:444 #, c-format msgid "" "%s MinJumpRank is set to %d: entries will not be removed from the database " "(no matter their rank).\n" msgstr "" #: bookmarks.c:74 #, c-format msgid "" "%s%s\n" "Enter '%c' to edit your bookmarks or '%c' to quit\n" "Choose a bookmark (by ELN, shortcut, or name):\n" msgstr "" #: properties.c:784 #, c-format msgid "%s%s%s %s: Primary group set to %d (%s%s%s)\n" msgstr "" #: properties.c:777 #, c-format msgid "%s%s%s %s: User set to %d (%s%s%s)\n" msgstr "" #: file_operations.c:1169 #, c-format msgid "%s%s%s (broken link)\n" msgstr "" #: main.c:1034 #, c-format msgid "%s%s%s Running as root%s\n" msgstr "" #: tags.c:331 #, c-format msgid "%s%s%s is tagged as:\n" msgstr "" #: trash.c:955 #, c-format msgid "%s%s%s%s\n" msgstr "" #: archives.c:1026 #, c-format msgid "%s%s%s: Succesfully mounted on %s\n" msgstr "" #: colors.c:3058 #, c-format msgid "%s%sColor%s (dg) Group ID (e.g. %s%swheel%s)\n" msgstr "" #: colors.c:3039 #, c-format msgid "%s%sColor%s (dt) Timestamp mark (e.g. %sMay 25 22:08%sm%s)\n" msgstr "" #: archives.c:851 #, c-format msgid "%s%sFile%s: %s\n" msgstr "" #: selection.c:846 #, c-format msgid "%s%sSelection Box%s\n" msgstr "" #: trash.c:399 #, c-format msgid "" "%s%sTrashed files%s\n" "\n" msgstr "" #: listing.c:446 #, c-format msgid "%s/%s (%d%% free) %s %s\n" msgstr "" #: name_cleaner.c:674 #, c-format msgid "%s: %d filenames(s) bleached\n" msgstr "" #: media.c:142 #, c-format msgid "%s: %d: Invalid ELN\n" msgstr "" #: properties.c:1560 #, c-format msgid "%s: %s %s%s%s %s: Broken symbolic link\n" msgstr "" #: mem.c:51 mem.c:68 mem.c:90 #, c-format msgid "%s: %s failed to allocate %zux%zu bytes\n" msgstr "" #: colors.c:992 #, c-format msgid "" "%s: %s.\n" "TIP: To edit the color scheme use the following environment variables: " "CLIFM_FILE_COLORS, CLIFM_IFACE_COLORS, and CLIFM_EXT_COLORS.\n" "Example:\n" "\n" "CLIFM_FILE_COLORS=\"di=31:ln=33:\" CLIFM_IFACE_COLORS=\"el=35:fc=34:\" " "CLIFM_EXT_COLORS=\"*.c=1;33:*.odt=4;35:\" clifm\n" "\n" "Consult the manpage for more information.\n" msgstr "" #: init.c:2728 #, c-format msgid "" "%s: %s: %s\n" "Invalid authentication program (falling back to '%s')\n" msgstr "" #: config.c:2327 #, c-format msgid "%s: %s: Cannot create tags directory. Tag function disabled\n" msgstr "" #: exec.c:1951 #, c-format msgid "%s: %s: Command not allowed in read-only mode\n" msgstr "" #: exec.c:359 #, c-format msgid "%s: %s: Invalid number\n" msgstr "" #: file_operations.c:1674 #, c-format msgid "%s: %s: No such ELN\n" msgstr "" #: config.c:1337 #, c-format msgid "" "%s: %s: Using a temporary directory for the Selection Box. Selected files " "will not be persistent across reboots.\n" msgstr "" #: strings.c:1977 #, c-format msgid "" "%s: '%c': Invalid file type filter. Run 'help file-filters' for more " "information\n" msgstr "" #: file_operations.c:1099 #, c-format msgid "" "%s: '%s' (%s): Cannot open file\n" "Try 'APP FILE' or 'open FILE APP'\n" msgstr "" #: init.c:756 #, c-format msgid "%s: '%s' is not a shell. Setting SHELL to '%s'.\n" msgstr "" #: args.c:950 #, c-format msgid "" "%s: '%s': %s\n" "Falling back to the default configuration directory\n" msgstr "" #: config.c:1292 #, c-format msgid "" "%s: '%s': %s.\n" "Cannot create temporary directory. Falling back to '%s'.\n" msgstr "" #: init.c:793 #, c-format msgid "" "%s: '%s': %s.\n" "Cannot validate shell. Falling back to '%s'.\n" msgstr "" #: config.c:4099 #, c-format msgid "" "%s: '%s': %s. Trash function disabled. If needed, create the directories " "manually and restart %s.\n" "E.g.: mkdir -p ~/.local/share/Trash/{files,info}\n" msgstr "" #: config.c:3334 #, c-format msgid "%s: '%s': %s. Using default values.\n" msgstr "" #: args.c:1202 #, c-format msgid "%s: '%s': Absolute path is required as argument\n" msgstr "" #: config.c:4112 #, c-format msgid "" "%s: '%s': Cannot create the trash directory (or one of its subdirectories: " "'files' and 'info').\n" "Try creating them manually and restart %s.\n" "E.g.: mkdir -p ~/.local/share/Trash/{files,info}\n" msgstr "" #: misc.c:839 #, c-format msgid "%s: '%s': Cannot escape filename\n" msgstr "" #: config.c:2299 #, c-format msgid "" "%s: '%s': Directory not writable. Bookmarks, commands logs, and commands " "history are disabled. Program messages will not be persistent. Falling back " "to default settings.\n" msgstr "" #: args.c:990 args.c:1079 aux.c:522 #, c-format msgid "%s: '%s': Error expanding tilde\n" msgstr "" #: strings.c:2174 strings.c:2248 #, c-format msgid "%s: '%s': Error quoting filename\n" msgstr "" #: checks.c:665 #, c-format msgid "%s: '%s': Error reading file\n" msgstr "" #: history.c:357 #, c-format msgid "%s: '%s': Error saving directory entry: %s\n" msgstr "" #: args.c:976 #, c-format msgid "%s: '%s': Error setting custom selections file\n" msgstr "" #: file_operations.c:739 file_operations.c:1024 file_operations.c:2117 #, c-format msgid "%s: '%s': Error unescaping filename\n" msgstr "" #: aux.c:505 #, c-format msgid "%s: '%s': Error unescaping string\n" msgstr "" #: file_operations.c:2043 #, c-format msgid "%s: '%s': File changed on disk!\n" msgstr "" #: init.c:893 #, c-format msgid "" "%s: '%s': Home directory not found\n" "Falling back to '%s'\n" msgstr "" #: exec.c:1545 exec.c:1573 #, c-format msgid "%s: '%s': Invalid argument. Try 'fz -h'\n" msgstr "" #: args.c:911 #, c-format msgid "" "%s: '%s': Invalid bell style. Valid values are 0:none, 1:audible, 2:visible " "(requires readline >= 8.1), 3:flash. Defaults to 'visible', and, if not " "possible, 'none'.\n" msgstr "" #: args.c:897 #, c-format msgid "%s: '%s': Invalid fuzzy algorithm. Valid values are either 1 or 2.\n" msgstr "" #: init.c:905 #, c-format msgid "" "%s: '%s': Invalid home directory in the password database.\n" "Something is really wrong! Exiting.\n" msgstr "" #: args.c:1188 #, c-format msgid "%s: '%s': Invalid profile name\n" msgstr "" #: config.c:3873 #, c-format msgid "%s: '%s': Invalid regular expression\n" msgstr "" #: init.c:789 #, c-format msgid "" "%s: '%s': Invalid shell. Falling back to '%s'.\n" "Check '%s' for a list of valid shells.\n" msgstr "" #: args.c:1235 #, c-format msgid "%s: '%s': Invalid workspace. Valid values are 1-8.\n" msgstr "" #: mime.c:1563 mime.c:1567 #, c-format msgid "%s: '%s': No associated application found\n" msgstr "" #: mime.c:1542 #, c-format msgid "" "%s: '%s': No associated application found\n" "Fix this in the configuration file:\n" "%s\n" "(run 'view edit' if running %s)\n" msgstr "" #: exec.c:822 #, c-format msgid "%s: '%s': No such alias\n" msgstr "" #: selection.c:994 #, c-format msgid "%s: '%s': No such selected file\n" msgstr "" #: misc.c:679 #, c-format msgid "%s: '%s': Not a directory\n" msgstr "" #: sanitize.c:408 #, c-format msgid "" "%s: '%s': Only command base names are allowed. E.g.: 'nano' instead of '/usr/" "bin/nano'\n" msgstr "" #: args.c:303 #, c-format msgid "" "%s: '%s': Option requires an argument\n" "Try '%s %s' for more information.\n" msgstr "" #: exec.c:1183 #, c-format msgid "%s: '%s': Syntax error\n" msgstr "" #: term.c:466 #, c-format msgid "" "%s: '%s': Terminal type not supported. Limited functionality is expected.\n" msgstr "" #: args.c:314 #, c-format msgid "" "%s: '%s': Unrecognized option\n" "Try '%s --help' for more information.\n" msgstr "" #: file_operations.c:923 #, c-format msgid "%s: '%s': Unsafe filename\n" msgstr "" #: args.c:957 #, c-format msgid "%s: '%s': Using an alternative configuration directory\n" msgstr "" #: args.c:1465 #, c-format msgid "%s: '%s': Valid values are 0-3\n" msgstr "" #: args.c:366 #, c-format msgid "" "%s: '%zu': Invalid workspace.\n" "Falling back to workspace %zu.\n" msgstr "" #: args.c:1423 #, c-format msgid "" "%s: '--desktop-notifications': Valid values are 'kitty','system', or " "'false'.\n" msgstr "" #: args.c:1358 #, c-format msgid "" "%s: '--show-hidden': Valid values are 'true','first', 'last', or 'false'.\n" msgstr "" #: properties.c:2012 #, c-format msgid "" "%s: '--stat': Option requires an argument\n" "Try '%s --help' for more information.\n" msgstr "" #: args.c:1361 #, c-format msgid "%s: '-a': Valid values are 'true','first', 'last', or 'false'.\n" msgstr "" #: args.c:861 #, c-format msgid "" "%s: --fzytab: We have migrated to 'fnf'.\n" "Install 'fnf' (https://github.com/leo-arch/fnf) and then use --fnftab " "instead.\n" msgstr "" #: args.c:1442 #, c-format msgid "" "%s: --pager-view: '%s': Invalid value.\n" "Valid values are 'auto', 'long', and 'short'.\n" msgstr "" #: args.c:1397 #, c-format msgid "%s: --prop-fields: 'b': Birth time is not available on this platform\n" msgstr "" #: args.c:763 #, c-format msgid "" "%s: --sort: '%s': Invalid value\n" "Valid values: atime, btime, ctime, mtime, extension, group, inode, name,\n" " none, owner, size, version, blocks, links, type.\n" msgstr "" #: args.c:781 #, c-format msgid "%s: --sort: '%s': Valid values are 0-%d\n" msgstr "" #: readline.c:4605 #, c-format msgid "" "%s: An input file must be provided via the CLIFM_TEST_INPUT_FILE environment " "variable\n" msgstr "" #: bookmarks.c:774 #, c-format msgid "%s: Bookmarks function disabled\n" msgstr "" #: config.c:642 #, c-format msgid "%s: Cannot access the configuration file\n" msgstr "" #: init.c:556 #, c-format msgid "" "%s: Cannot access the home directory. Bookmarks, commands logs, and commands " "history are disabled. Program messages, selected files, and the jump " "database will not be persistent. Using default settings.\n" msgstr "" #: config.c:2317 #, c-format msgid "" "%s: Cannot create colors directory '%s': Falling back to the default color " "scheme\n" msgstr "" #: config.c:2255 #, c-format msgid "" "%s: Cannot create configuration directory '%s': Bookmarks, commands logs, " "and command history are disabled. Program messages will not be persistent. " "Falling back to default settings.\n" msgstr "" #: args.c:941 #, c-format msgid "" "%s: Cannot create directory '%s' (error %d)\n" "Falling back to the default configuration directory.\n" msgstr "" #: config.c:2332 #, c-format msgid "" "%s: Cannot create plugins directory '%s': The actions function is disabled\n" msgstr "" #: config.c:1380 #, c-format msgid "%s: Cannot create temporary directory. Falling back to '%s'.\n" msgstr "" #: args.c:710 #, c-format msgid "%s: Cannot retrieve the home directory\n" msgstr "" #: colors.c:1102 #, c-format msgid "%s: Colors are disabled\n" msgstr "" #: colors.c:3250 #, c-format msgid "%s: Currently running without colors\n" msgstr "" #: misc.c:644 #, c-format msgid "" "%s: Default terminal not set. Use the configuration file (F10) to set it.\n" msgstr "" #: navigation.c:673 #, c-format msgid "%s: Directory history cleared\n" msgstr "" #: jump.c:781 #, c-format msgid "%s: Directory jumper function disabled\n" msgstr "" #: misc.c:1976 #, c-format msgid "%s: Empty filenames buffer. Nothing to do\n" msgstr "" #: sanitize.c:189 #, c-format msgid "%s: Error dropping group privileges. Aborting.\n" msgstr "" #: sanitize.c:204 #, c-format msgid "%s: Error dropping user privileges. Aborting.\n" msgstr "" #: args.c:1171 #, c-format msgid "%s: Error expanding tilde. Using default opener.\n" msgstr "" #: mime.c:1381 mime.c:1581 #, c-format msgid "%s: Error getting MIME type\n" msgstr "" #: aux.c:545 #, c-format msgid "%s: Error getting current directory\n" msgstr "" #: listing.c:2491 listing.c:3279 #, c-format msgid "%s: Error getting file descriptor for the current directory: %s\n" msgstr "" #: mime.c:553 #, c-format msgid "%s: Error getting home directory\n" msgstr "" #: main.c:1125 #, c-format msgid "%s: Error getting hostname\n" msgstr "" #: navigation.c:75 #, c-format msgid "%s: Error getting the current working directory\n" msgstr "" #: misc.c:1053 #, c-format msgid "%s: Error getting variable value\n" msgstr "" #: media.c:368 #, c-format msgid "%s: Error retrieving mountpoint\n" msgstr "" #: misc.c:1295 #, c-format msgid "%s: Error saving last visited directory: %s\n" msgstr "" #: colors.c:489 #, c-format msgid "" "%s: Escape sequence detected in the warning prompt string: this might cause " "a few glichtes in the prompt due to some bugs in the current readline " "library (%s). Please consider removing these escape sequences (via either " "'prompt edit' or 'cs edit') or upgrading to a newer version of the library " "(>= 7.0 is recommended).\n" msgstr "" #: exec.c:279 #, c-format msgid "" "%s: External commands are currently disabled. To enable them, run 'ext on'.\n" msgstr "" #: main.c:1099 #, c-format msgid "%s: Fatal error! Failure retrieving the current working directory\n" msgstr "" #: args.c:387 #, c-format msgid "%s: Fatal error! Failure retrieving the current working directory.\n" msgstr "" #: colors.c:1044 #, c-format msgid "" "%s: File extension conflicts found. Run 'cs check-ext' to see the details.\n" msgstr "" #: config.c:1513 #, c-format msgid "%s: File may be unsafe\n" msgstr "" #: misc.c:638 #, c-format msgid "%s: Function only available for graphical environments\n" msgstr "" #: tabcomp.c:767 #, c-format msgid "" "%s: Fzf failed. Check the FzfTabOptions line by running 'cs edit'\n" "(some option may not be supported by your fzf version).\n" msgstr "" #: colors.c:2131 #, c-format msgid "" "%s: FzfTabOptions contains unsafe characters (<>|;&$`). Falling back to " "default values.\n" msgstr "" #: history.c:549 #, c-format msgid "%s: History function disabled\n" msgstr "" #: init.c:912 #, c-format msgid "" "%s: Home directory not found.\n" "Something is really wrong! Exiting.\n" msgstr "" #: listing.c:2698 listing.c:3447 #, c-format msgid "%s: Integer overflow detected (showing only %jd files)\n" msgstr "" #: main.c:1219 #, c-format msgid "" "%s: Invalid sort value: only none, name, extension, version, and inode are " "allowed in light mode\n" msgstr "" #: config.c:1497 #, c-format msgid "%s: Is a symbolic link\n" msgstr "" #: config.c:1502 #, c-format msgid "%s: Is not a regular file\n" msgstr "" #: misc.c:1881 #, c-format msgid "%s: Light mode is not supported in virtual directories\n" msgstr "" #: main.c:1153 #, c-format msgid "" "%s: Locale is not UTF-8. To avoid encoding issues you might want to set an " "UTF-8 locale. For example: export LANG=es_AR.UTF-8\n" msgstr "" #: exec.c:1777 #, c-format msgid "%s: Log function disabled\n" msgstr "" #: config.c:3590 #, c-format msgid "" "%s: MaxPath: This option is deprecated. Use the CLIFM_PROMPT_P_MAX_PATH " "environment variable instead.\n" msgstr "" #: config.c:3602 #, c-format msgid "" "%s: MinFilenameTrim: This option is deprecated. Use MinNameTruncate " "instead.\n" msgstr "" #: strings.c:993 #, c-format msgid "%s: Missing '%c'\n" msgstr "" #: strings.c:1057 #, c-format msgid "%s: Missing closing quote: '%c'\n" msgstr "" #: exec.c:2573 #, c-format msgid "%s: Nested instances are not allowed in stealth mode\n" msgstr "" #: exec.c:786 exec.c:808 #, c-format msgid "%s: No aliases found\n" msgstr "" #: args.c:652 #, c-format msgid "" "%s: No data directory found. Data files, such as plugins and color schemes, " "may not be available.\n" "Set a custom data directory via the '--data-dir' option.\n" msgstr "" #: exec.c:658 exec.c:702 #, c-format msgid "%s: No messages\n" msgstr "" #: media.c:136 media.c:315 #, c-format msgid "%s: No mount application found. Install either udevil or udisks2\n" msgstr "" #: mime.c:1396 #, c-format msgid "" "%s: No opening application found\n" "Tip: Run 'APP FILE', or 'mm edit' to add an opening application\n" msgstr "" #: exec.c:1133 #, c-format msgid "%s: No pinned file\n" msgstr "" #: remotes.c:46 #, c-format msgid "%s: No remotes defined. Run 'net edit' to add one.\n" msgstr "" #: bookmarks.c:245 #, c-format msgid "%s: No such ELN\n" msgstr "" #: tags.c:64 #, c-format msgid "%s: No tags found. Use 'tag new' to create new tags.\n" msgstr "" #: name_cleaner.c:551 name_cleaner.c:607 #, c-format msgid "%s: Nothing to do\n" msgstr "" #: mime.c:643 #, c-format msgid "%s: Nothing was imported. No MIME association found\n" msgstr "" #: mime.c:547 #, c-format msgid "%s: Nothing was imported. No graphical environment found\n" msgstr "" #: history.c:287 #, c-format msgid "" "%s: Notification daemon error: %s\n" "Disable desktop notifications (run 'help desktop-notifications' for details) " "or %s to silence this warning (original message printed below)\n" msgstr "" #: args.c:1586 #, c-format msgid "" "%s: Option '-%c' requires an argument.\n" "Try '%s -h' for more information.\n" msgstr "" #: actions.c:169 #, c-format msgid "%s: Plugins are not allowed in secure-cmds mode\n" msgstr "" #: prompt.c:1903 #, c-format msgid "%s: Prompts successfully reloaded\n" msgstr "" #: main.c:1213 #, c-format msgid "%s: PropFields: 'b': Birth time is not allowed in light mode\n" msgstr "" #: args.c:796 #, c-format msgid "" "%s: Running in stealth mode. Access to configuration files is not allowed.\n" msgstr "" #: config.c:4207 #, c-format msgid "" "%s: Running in stealth mode: persistent selection, bookmarks, jump database " "and directory history, just as plugins, logs and configuration files, are " "disabled.\n" msgstr "" #: tags.c:396 #, c-format msgid "%s: Successfully created tag\n" msgstr "" #: term.c:503 #, c-format msgid "%s: TERM variable unset. Running in xterm compatibility mode.\n" msgstr "" #: exec.c:1155 #, c-format msgid "" "%s: The 'dh' plugin is deprecated. Use the builtin 'dh' command instead " "disabling the 'dh' plugin ('actions edit'). Once done, run 'dh --help' for " "more information about the new command.\n" msgstr "" #: media.c:637 #, c-format msgid "%s: There are no available %s\n" msgstr "" #: config.c:1507 #, c-format msgid "%s: There is another name hard linked to this file\n" msgstr "" #: media.c:578 #, c-format msgid "%s: This feature is not available on Haiku\n" msgstr "" #: exec.c:106 #, c-format msgid "%s: To gracefully quit enter 'q'\n" msgstr "" #: trash.c:845 trash.c:1225 #, c-format msgid "%s: Trash function disabled\n" msgstr "" #: config.c:3820 #, c-format msgid "%s: TrimNames: This option is deprecated. Use TruncateNames instead.\n" msgstr "" #: media.c:164 #, c-format msgid "%s: Unmounted %s\n" msgstr "" #: args.c:1591 #, c-format msgid "" "%s: Unrecognized option: '-%c'\n" "Try '%s -h' for more information.\n" msgstr "" #: bulk_rename.c:409 #, c-format msgid "%s: br: Feature not allowed in virtual directories\n" msgstr "" #: misc.c:1319 #, c-format msgid "%s: cd-on-quit: Cannot create symbolic link '%s': %s\n" msgstr "" #: exec.c:1298 #, c-format msgid "%s: cd: '%s': Is a directory\n" msgstr "" #: config.c:2954 #, c-format msgid "" "%s: chdir: '%s': %s. Using the current working directory as starting path\n" msgstr "" #: colors.c:1793 #, c-format msgid "%s: colors: %s: No such color scheme. Falling back to default\n" msgstr "" #: colors.c:2291 #, c-format msgid "%s: colors: '%s': No such color scheme. Falling back to default\n" msgstr "" #: checks.c:144 #, c-format msgid "" "%s: fnf: Command not found. Falling back to the default value (fzf, if " "found, or standard)\n" msgstr "" #: checks.c:137 #, c-format msgid "%s: fzf: Command not found. Falling back to standard tab completion\n" msgstr "" #: history.c:544 #, c-format msgid "%s: history: %s\n" msgstr "" #: exec.c:627 #, c-format msgid "%s: icons: %s\n" msgstr "" #: remotes.c:377 #, c-format msgid "%s: net: %s: Mounting remote...\n" msgstr "" #: remotes.c:422 #, c-format msgid "%s: net: %s: Unmount command failed with error code %d\n" msgstr "" #: remotes.c:419 #, c-format msgid "%s: net: %s: Unmounting remote...\n" msgstr "" #: bulk_remove.c:402 #, c-format msgid "%s: rr: Feature not allowed in virtual directories\n" msgstr "" #: checks.c:149 #, c-format msgid "" "%s: smenu: Command not found. Falling back to the default value (fzf, if " "found, or standard)\n" msgstr "" #: exec.c:1505 #, c-format msgid "%s: trash: %s\n" msgstr "" #: checks.c:114 #, c-format msgid "%s: udisks2: Command not found. Falling back to udevil\n" msgstr "" #: bookmarks.c:178 #, c-format msgid "" "%sBookmark Manager%s\n" "\n" msgstr "" #: colors.c:3241 #, c-format msgid "" "%sColor scheme: %s%s%s\n" "\n" msgstr "" #: colors.c:3148 #, c-format msgid "%sColor%s (ac) Autocommand indicator (%sA%s)\n" msgstr "" #: colors.c:2957 #, c-format msgid "%sColor%s (bd) Block device\n" msgstr "" #: colors.c:2966 #, c-format msgid "%sColor%s (ca) File with capabilities\n" msgstr "" #: colors.c:2958 #, c-format msgid "%sColor%s (cd) Character device\n" msgstr "" #: colors.c:3070 #, c-format msgid "%sColor%s (db) Used blocks (e.g. %s1576%s)\n" msgstr "" #: colors.c:3031 #, c-format msgid "%sColor%s (dd) Date (e.g. %sJul 9 08:12%s)\n" msgstr "" #: colors.c:3074 #, c-format msgid "%sColor%s (de) Inode number (e.g. %s802721%s)\n" msgstr "" #: colors.c:3106 #, c-format msgid "%sColor%s (df) Default color\n" msgstr "" #: colors.c:2942 #, c-format msgid "%sColor%s (di) Directory\n" msgstr "" #: colors.c:3072 #, c-format msgid "%sColor%s (dk) Links number (e.g. %s92%s)\n" msgstr "" #: colors.c:3100 #, c-format msgid "%sColor%s (dl) Dividing line (e.g. %s------>%s)\n" msgstr "" #: colors.c:3078 #, c-format msgid "%sColor%s (dn) Dot/dash (e.g. %sr%sw%s-.%sr%s--.--%s)\n" msgstr "" #: colors.c:3076 #, c-format msgid "%sColor%s (do) Octal permissions (e.g. %s0640%s)\n" msgstr "" #: colors.c:3054 #, c-format msgid "%sColor%s (dp) SUID/SGID bit (e.g. %ss%s)\n" msgstr "" #: colors.c:3048 #, c-format msgid "%sColor%s (dr) Read bit (%sr%s)\n" msgstr "" #: colors.c:3056 #, c-format msgid "%sColor%s (du) User ID (e.g. %sjane%s)\n" msgstr "" #: colors.c:3049 #, c-format msgid "%sColor%s (dw) Write bit (%sw%s)\n" msgstr "" #: colors.c:3050 #, c-format msgid "%sColor%s (dxd) Execute bit - directory (%sx%s)\n" msgstr "" #: colors.c:3052 #, c-format msgid "%sColor%s (dxr) Execute bit - file (%sx%s)\n" msgstr "" #: colors.c:3062 #, c-format msgid "%sColor%s (dz) Size (e.g. %s12.69k%s)\n" msgstr "" #: colors.c:2943 #, c-format msgid "%sColor%s (ed) Empty directory\n" msgstr "" #: colors.c:2953 #, c-format msgid "%sColor%s (ee) Empty executable file\n" msgstr "" #: colors.c:2948 #, c-format msgid "%sColor%s (ef) Empty file\n" msgstr "" #: colors.c:3088 #, c-format msgid "%sColor%s (el) ELN's (e.g. %s12%s filename)\n" msgstr "" #: colors.c:3168 #, c-format msgid "%sColor%s (em) Error message indicator (%sE%s)\n" msgstr "" #: colors.c:2952 #, c-format msgid "%sColor%s (ex) Executable file\n" msgstr "" #: colors.c:3090 #, c-format msgid "%sColor%s (fc) File counter (e.g. dir%s/24%s)\n" msgstr "" #: colors.c:2947 #, c-format msgid "%sColor%s (fi) Regular file\n" msgstr "" #: colors.c:3211 #, c-format msgid "%sColor%s (hb) Brackets: %s(){}[]%s\n" msgstr "" #: colors.c:3213 #, c-format msgid "%sColor%s (hc) Commented out text (e.g. some text %s#comment%s)\n" msgstr "" #: colors.c:3215 #, c-format msgid "%sColor%s (hd) Slash (e.g. dir%s/%sfile)\n" msgstr "" #: colors.c:3217 #, c-format msgid "%sColor%s (he) Expansion characters: %s~*%s\n" msgstr "" #: colors.c:3219 #, c-format msgid "%sColor%s (hn) Number (e.g. pp %s12%s)\n" msgstr "" #: colors.c:3221 #, c-format msgid "%sColor%s (hp) Command parameter (e.g. cmd %s--param%s)\n" msgstr "" #: colors.c:3223 #, c-format msgid "%sColor%s (hq) Quoted text (e.g. %s\"some text\"%s)\n" msgstr "" #: colors.c:3225 #, c-format msgid "%sColor%s (hr) Redirection characters: %s><%s\n" msgstr "" #: colors.c:3227 #, c-format msgid "%sColor%s (hs) Process separator characters: %s|;&%s \n" msgstr "" #: colors.c:3229 #, c-format msgid "%sColor%s (hv) Variable name (e.g. %s$FOO%s)\n" msgstr "" #: colors.c:3231 #, c-format msgid "%sColor%s (hw) Backslash (e.g. sel this%s\\%s file%s\\%s name)\n" msgstr "" #: colors.c:3092 #, c-format msgid "" "%sColor%s (lc) Symbolic link indicator (e.g. %s36%s%s%s%ssymlink) (%s1%s)\n" msgstr "" #: colors.c:3095 #, c-format msgid "%sColor%s (li) Selected file indicator (e.g. %s12%s%s%s%sfilename)\n" msgstr "" #: colors.c:3150 #, c-format msgid "%sColor%s (li) Selected files indicator (%s%c%s)\n" msgstr "" #: colors.c:2954 #, c-format msgid "%sColor%s (ln) Symbolic link\n" msgstr "" #: colors.c:2956 #, c-format msgid "%sColor%s (mh) Multi-hardlink\n" msgstr "" #: colors.c:3102 #, c-format msgid "%sColor%s (mi) Miscellaneous indicator (%s%s%s) (%s2%s)\n" msgstr "" #: colors.c:2945 #, c-format msgid "%sColor%s (nd) Directory with no read/exec permission\n" msgstr "" #: colors.c:2950 #, c-format msgid "%sColor%s (nf) File with no read permission\n" msgstr "" #: colors.c:3162 #, c-format msgid "%sColor%s (nm) Notice message indicator (%sN%s)\n" msgstr "" #: colors.c:2973 #, c-format msgid "%sColor%s (no) Unknown file type\n" msgstr "" #: colors.c:2962 #, c-format msgid "%sColor%s (oo) Door/Port file\n" msgstr "" #: colors.c:2955 #, c-format msgid "%sColor%s (or) Broken symbolic link\n" msgstr "" #: colors.c:2971 #, c-format msgid "%sColor%s (ow) Other-writable and NOT sticky directory\n" msgstr "" #: colors.c:2960 #, c-format msgid "%sColor%s (pi) Pipe or FIFO special file\n" msgstr "" #: colors.c:3171 #, c-format msgid "%sColor%s (ro) Read-only mode indicator (%sRO%s)\n" msgstr "" #: colors.c:2965 #, c-format msgid "%sColor%s (sg) SGID file\n" msgstr "" #: colors.c:3174 #, c-format msgid "%sColor%s (si) Stealth mode indicator (%sS%s)\n" msgstr "" #: colors.c:2959 #, c-format msgid "%sColor%s (so) Socket file\n" msgstr "" #: colors.c:2967 #, c-format msgid "%sColor%s (st) Sticky and NOT other-writable directory\n" msgstr "" #: colors.c:2964 #, c-format msgid "%sColor%s (su) SUID file\n" msgstr "" #: colors.c:3153 #, c-format msgid "%sColor%s (ti) Trashed files indicator (%sT%s)\n" msgstr "" #: colors.c:3104 #, c-format msgid "%sColor%s (ts) Matching completion prefix (e.g. %sfile%sname) (%s3%s)\n" msgstr "" #: colors.c:3098 #, c-format msgid "%sColor%s (tt) Truncated filenames mark (e.g. filenam%s%c%s.odt)\n" msgstr "" #: colors.c:2969 #, c-format msgid "%sColor%s (tw) Sticky and other-writable directory\n" msgstr "" #: colors.c:3144 #, c-format msgid "" "%sColor%s (tx) Input text (e.g. $ %sls%s %s-l%s %sfilename.zst%s)\n" msgstr "" #: colors.c:2974 #, c-format msgid "%sColor%s (uf) Unaccessible (non-stat'able) file\n" msgstr "" #: colors.c:3165 #, c-format msgid "%sColor%s (wm) Warning message indicator (%sW%s)\n" msgstr "" #: colors.c:3122 #, c-format msgid "%sColor%s (ws1) Workspace [%s1%s]\n" msgstr "" #: colors.c:3124 #, c-format msgid "%sColor%s (ws2) Workspace [%s2%s]\n" msgstr "" #: colors.c:3126 #, c-format msgid "%sColor%s (ws3) Workspace [%s3%s]\n" msgstr "" #: colors.c:3128 #, c-format msgid "%sColor%s (ws4) Workspace [%s4%s]\n" msgstr "" #: colors.c:3130 #, c-format msgid "%sColor%s (ws5) Workspace [%s5%s]\n" msgstr "" #: colors.c:3132 #, c-format msgid "%sColor%s (ws6) Workspace [%s6%s]\n" msgstr "" #: colors.c:3134 #, c-format msgid "%sColor%s (ws7) Workspace [%s7%s]\n" msgstr "" #: colors.c:3136 #, c-format msgid "%sColor%s (ws8) Workspace [%s8%s]\n" msgstr "" #: colors.c:3159 #, c-format msgid "%sColor%s (xf) Error exit code (e.g. <%s1%s>)\n" msgstr "" #: colors.c:3156 #, c-format msgid "%sColor%s (xs) Success exit code (<%s0%s>)\n" msgstr "" #: properties.c:617 #, c-format msgid "" "%sEdit file ownership (Ctrl+d to quit)\n" "Both ID numbers and names are supported\n" msgstr "" #: properties.c:439 #, c-format msgid "" "%sEdit file permissions (Ctrl+d to quit)\n" "Both symbolic and numeric notation are supported\n" msgstr "" #: colors.c:2940 #, c-format msgid "" "%sFile types%s\n" "\n" msgstr "" #: archives.c:869 #, c-format msgid "%sFile%s: %s\n" msgstr "" #: properties.c:614 #, c-format msgid "" "%sFiles with different owners\n" "Only common owners are set in the template\n" msgstr "" #: properties.c:436 #, c-format msgid "" "%sFiles with different sets of permissions\n" "Only shared permission bits are set in the template\n" msgstr "" #: media.c:603 #, c-format msgid "" "%sMountpoints%s\n" "\n" msgstr "" #: archives.c:782 #, c-format msgid "%sNOTE%s: Using Zstandard\n" msgstr "" #: aux.c:94 #, c-format msgid "%sPress any key to continue... " msgstr "" #: archives.c:1043 #, c-format msgid "" "%s[e]%sxtract %s[E]%sxtract-to-dir %s[l]%sist %s[m]%sount %s[r]%sepack %s[q]" "%suit\n" msgstr "" #: archives.c:344 #, c-format msgid "" "%s[e]%sxtract %s[E]%sxtract-to-dir %s[l]%sist %s[t]%sest %s[m]%sount %s[q]" "%suit\n" msgstr "" #: archives.c:597 archives.c:783 #, c-format msgid "%s[e]%sxtract %s[t]%sest %s[i]%snfo %s[q]%suit\n" msgstr "" #: colors.c:2998 #, c-format msgid "%sbigger%s\n" msgstr "" #: colors.c:3012 #, c-format msgid "%sday%s " msgstr "" #: colors.c:3009 #, c-format msgid "%shour%s " msgstr "" #: colors.c:3018 #, c-format msgid "%smonth%s " msgstr "" #: colors.c:3021 #, c-format msgid "%solder%s\n" msgstr "" #: colors.c:3015 #, c-format msgid "%sweek%s " msgstr "" #: file_operations.c:1643 #, c-format msgid "%zu file(s) copied\n" msgstr "" #: file_operations.c:611 #, c-format msgid "%zu file(s) created\n" msgstr "" #: selection.c:1248 selection.c:1270 #, c-format msgid "%zu file(s) deselected\n" msgstr "" #: file_operations.c:1641 #, c-format msgid "%zu file(s) moved\n" msgstr "" #: file_operations.c:2012 #, c-format msgid "%zu file(s) removed\n" msgstr "" #: trash.c:95 #, c-format msgid "%zu file(s) removed from the trash can\n" msgstr "" #: bulk_rename.c:518 #, c-format msgid "%zu file(s) renamed\n" msgstr "" #: trash.c:798 trash.c:831 #, c-format msgid "%zu file(s) restored\n" msgstr "" #: selection.c:959 view.c:416 #, c-format msgid "%zu file(s) selected\n" msgstr "" #: trash.c:1210 #, c-format msgid "%zu file(s) trashed\n" msgstr "" #: name_cleaner.c:624 #, c-format msgid "%zu filename(s) will be bleached\n" msgstr "" #: selection.c:1251 #, c-format msgid "%zu selected file(s)\n" msgstr "" #: file_operations.c:2322 #, c-format msgid "%zu symbolic link(s) created\n" msgstr "" #: selection.c:669 selection.c:1075 selection.c:1249 view.c:417 #, c-format msgid "%zu total selected file(s)\n" msgstr "" #: trash.c:96 trash.c:799 trash.c:832 trash.c:1211 #, c-format msgid "%zu total trashed file(s)\n" msgstr "" #: trash.c:926 #, c-format msgid "%zu trashed file(s)\n" msgstr "" #: colors.c:1012 #, c-format msgid "'%s' conflicts with '%s'\n" msgstr "" #: colors.c:1010 #, c-format msgid "'%s' has conflicting definitions\n" msgstr "" #: file_operations.c:1248 #, c-format msgid "'%s' relinked to " msgstr "" #: bookmarks.c:715 #, c-format msgid "" "'%s': %s\n" "bookmarks: Error creating temporary file\n" msgstr "" #: bookmarks.c:706 #, c-format msgid "" "'%s': %s\n" "bookmarks: Error reading the bookmarks file\n" msgstr "" #: misc.c:956 #, c-format msgid "'%s': Alias already exists\n" msgstr "" #: misc.c:917 #, c-format msgid "'%s': Alias conflicts with internal command\n" msgstr "" #: bookmarks.c:264 bookmarks.c:365 #, c-format msgid "'%s': Invalid bookmark\n" msgstr "" #: search.c:944 #, c-format msgid "'%s': Invalid regular expression\n" msgstr "" #: bookmarks.c:269 bookmarks.c:374 bookmarks.c:611 #, c-format msgid "'%s': No such bookmark\n" msgstr "" #: tags.c:431 #, c-format msgid "'%s': Successfully removed tag\n" msgstr "" #: properties.c:1060 #, c-format msgid "" "(%s%04o%s)%s%c%s/%s%c%s%c%s%c%s.%s%c%s%c%s%c%s.%s%c%s%c%s%c%s%s Links: " "%s%zu%s " msgstr "" #: colors.c:3110 #, c-format msgid "" "(%s2%s) Also used for miscellaneous names (like bookmarks and color schemes) " "in tab completion\n" msgstr "" #: colors.c:3112 #, c-format msgid "(%s3%s) Used only for the standard tab completion mode\n" msgstr "" #: keybinds.c:1101 msgid "(Enter:accept, Ctrl+d:abort, Ctrl+c:clear-line)" msgstr "" #: selection.c:1271 msgid "0 total selected file(s)\n" msgstr "" #: properties.c:977 msgid "" msgstr "" #: file_operations.c:1171 msgid "??? (broken link)" msgstr "" #: properties.c:1338 msgid "ACL-extended:\t" msgstr "" #: properties.c:1501 #, c-format msgid "Access: \t%s%s%s\n" msgstr "" #: listing.c:708 #, c-format msgid "Active filter: %s%s%s%s\n" msgstr "" #: properties.c:1279 msgid "Archive state 1" msgstr "" #: exec.c:1470 #, c-format msgid "Archive state 1: %zu\n" msgstr "" #: properties.c:1280 msgid "Archive state 2" msgstr "" #: exec.c:1471 #, c-format msgid "Archive state 2: %zu\n" msgstr "" #: mime.c:1550 msgid "Associated application: None\n" msgstr "" #: properties.c:1318 msgid "Attributes: \t" msgstr "" #: exec.c:577 msgid "Auto-open disabled" msgstr "" #: exec.c:574 msgid "Auto-open enabled" msgstr "" #: exec.c:579 #, c-format msgid "Auto-open is %s\n" msgstr "" #: exec.c:550 msgid "Autocd disabled" msgstr "" #: exec.c:547 msgid "Autocd enabled" msgstr "" #: exec.c:552 #, c-format msgid "Autocd is %s\n" msgstr "" #: keybinds.c:1117 msgid "Bind function to this new key?" msgstr "" #: properties.c:1548 #, c-format msgid "Birth: \t\t%s%s%s\n" msgstr "" #: properties.c:1550 #, c-format msgid "Birth: \t\t%s-%s\n" msgstr "" #: properties.c:1275 msgid "Block special file" msgstr "" #: selection.c:620 msgid "Calculating file size... " msgstr "" #: config.c:75 #, c-format msgid "Cannot rename '%s' to '%s': %s\n" msgstr "" #: properties.c:1343 msgid "Capabilities:\t" msgstr "" #: properties.c:1503 #, c-format msgid "Change: \t%s%s%s\n" msgstr "" #: properties.c:1276 msgid "Character special file" msgstr "" #: navigation.c:190 msgid "Choose a directory ('q' to quit): " msgstr "" #: media.c:476 msgid "Choose a mountpoint/device: " msgstr "" #: media.c:474 media.c:479 msgid "Choose a mountpoint: " msgstr "" #: mime.c:722 msgid "Choose an application ('q' to quit): " msgstr "" #: history.c:457 msgid "Clear history?" msgstr "" #: listing.c:697 #, c-format msgid "Color scheme %s%s%s %s\n" msgstr "" #: exec.c:596 #, c-format msgid "Columns %s\n" msgstr "" #: exec.c:613 msgid "Columns disabled\n" msgstr "" #: exec.c:609 msgid "Columns enabled\n" msgstr "" #: config.c:65 msgid "Configuration file not found" msgstr "" #: bookmarks.c:491 bulk_rename.c:382 bulk_rename.c:478 file_operations.c:844 #: file_operations.c:925 file_operations.c:2027 name_cleaner.c:625 trash.c:1113 msgid "Continue?" msgstr "" #: file_operations.c:1446 msgid "Create broken symbolic link?" msgstr "" #: file_operations.c:1548 msgid "Create it?" msgstr "" #: tags.c:469 #, c-format msgid "Created new tag %s%s%s\n" msgstr "" #: colors.c:1085 #, c-format msgid "Current color scheme: '%s'\n" msgstr "" #: misc.c:590 #, c-format msgid "Current filter: %c%s\n" msgstr "" #: file_operations.c:1163 #, c-format msgid "Current target %s%s%s " msgstr "" #: properties.c:1300 #, c-format msgid "Device: %s%ju,%ju%s" msgstr "" #: keybinds.c:2061 #, c-format msgid "Directories first %s\n" msgstr "" #: exec.c:396 msgid "Directories first disabled\n" msgstr "" #: exec.c:392 msgid "Directories first enabled\n" msgstr "" #: exec.c:387 #, c-format msgid "Directories first is %s\n" msgstr "" #: properties.c:1271 msgid "Directory" msgstr "" #: keybinds.c:3172 #, c-format msgid "Disk usage analyzer %s\n" msgstr "" #: properties.c:1283 msgid "Door " msgstr "" #: exec.c:1466 #, c-format msgid "Doors: %zu\n" msgstr "" #: file_operations.c:1131 msgid "Edit target (Ctrl+d to quit)" msgstr "" #: media.c:468 msgid "Enter 'iELN' for device information. E.g.: i4" msgstr "" #: archives.c:921 media.c:466 msgid "Enter 'q' to quit" msgstr "" #: keybinds.c:1099 #, c-format msgid "Enter a keybinding for %s%s%s (current: %s%s%s)\n" msgstr "" #: file_operations.c:257 msgid "" "Enter destination directory (Ctrl+d to quit)\n" "Tip: \".\" for the current directory" msgstr "" #: file_operations.c:832 msgid "" "Enter new filename (Ctrl+d to quit)\n" "Tip: End name with a slash to create a directory" msgstr "" #: file_operations.c:1587 #, c-format msgid "" "Enter new name (Ctrl+d to quit)\n" "%s>%s " msgstr "" #: bulk_rename.c:256 msgid "Error opening temporary file" msgstr "" #: archives.c:435 archives.c:443 archives.c:475 archives.c:481 msgid "Error querying file type" msgstr "" #: exec.c:525 msgid "External commands allowed" msgstr "" #: exec.c:521 #, c-format msgid "External commands are %s\n" msgstr "" #: exec.c:528 msgid "External commands disallowed" msgstr "" #: properties.c:1273 msgid "Fifo " msgstr "" #: actions.c:400 msgid "File modified. Actions reloaded.\n" msgstr "" #: bookmarks.c:138 msgid "File modified. Bookmarks reloaded.\n" msgstr "" #: history.c:447 msgid "File modified. History entries reloaded\n" msgstr "" #: prompt.c:1874 msgid "File modified. Prompts reloaded\n" msgstr "" #: remotes.c:307 msgid "File modified. Remotes reloaded.\n" msgstr "" #: bookmarks.c:537 msgid "File succesfully bookmarked" msgstr "" #: file_operations.c:2020 #, c-format msgid "File(s) to be removed%s:\n" msgstr "" #: trash.c:1098 msgid "File(s) to be trashed:\n" msgstr "" #: file_operations.c:123 #, c-format msgid "File-creation mask set to '%04o'\n" msgstr "" #: archives.c:513 msgid "Filename ('q' to quit): " msgstr "" #: exec.c:1013 #, c-format msgid "Filenames exported to '%s'\n" msgstr "" #: exec.c:409 #, c-format msgid "File counter %s\n" msgstr "" #: exec.c:431 msgid "File counter disabled\n" msgstr "" #: exec.c:423 msgid "File counter enabled\n" msgstr "" #: tags.c:338 #, c-format msgid "Files tagged as %s%s%s%s:\n" msgstr "" #: tags.c:279 #, c-format msgid "Files tagged as %s%s%s:\n" msgstr "" #: misc.c:523 msgid "Filter unset\n" msgstr "" #: properties.c:1325 msgid "Flags: \t\t" msgstr "" #: exec.c:1994 keybinds.c:2035 #, c-format msgid "Follow links %s\n" msgstr "" #: help.c:285 msgid "" "For more information consult the manpage and/or the Wiki:\n" "https://github.com/leo-arch/clifm/wiki" msgstr "" #: exec.c:1568 msgid "Full directory size disabled\n" msgstr "" #: exec.c:1556 msgid "Full directory size enabled\n" msgstr "" #: exec.c:1563 msgid "Full directory size is already disabled" msgstr "" #: exec.c:1551 msgid "Full directory size is already enabled" msgstr "" #: search.c:1037 msgid "Glob: No matches found. Trying regex...\n" msgstr "" #: exec.c:890 keybinds.c:2133 msgid "Hidden files: off\n" msgstr "" #: exec.c:894 keybinds.c:2131 msgid "Hidden files: on\n" msgstr "" #: exec.c:882 msgid "Hidden files: on (list first)\n" msgstr "" #: exec.c:886 msgid "Hidden files: on (list last)\n" msgstr "" #: history.c:521 #, c-format msgid "History is %s\n" msgstr "" #: exec.c:643 msgid "Icons disabled\n" msgstr "" #: exec.c:638 msgid "Icons enabled\n" msgstr "" #: archives.c:532 msgid "Invalid filename" msgstr "" #: name_cleaner.c:560 msgid "Is this OK? [y/n/(e)dit] " msgstr "" #: properties.c:1815 #, c-format msgid "Items:\t\t%s%c%s\n" msgstr "" #: properties.c:1850 #, c-format msgid "Items:\t\t%s%s%llu%s (%s%llu%s %s, %s%llu%s %s, %s%llu%s %s)\n" msgstr "" #: properties.c:2074 #, c-format msgid "Largest file: %s%s%s %s%s%s%s%s\n" msgstr "" #: keybinds.c:2088 #, c-format msgid "Light mode %s\n" msgstr "" #: exec.c:754 msgid "Light mode already off" msgstr "" #: exec.c:745 msgid "Light mode already on" msgstr "" #: exec.c:760 msgid "Light mode disabled\n" msgstr "" #: exec.c:751 msgid "Light mode enabled\n" msgstr "" #: exec.c:1741 keybinds.c:2007 #, c-format msgid "Long view %s\n" msgstr "" #: mime.c:1590 #, c-format msgid "MIME type: %s\n" msgstr "" #: search.c:553 #, c-format msgid "Matches found: %d%s\n" msgstr "" #: search.c:886 #, c-format msgid "Matches found: %zu\n" msgstr "" #: exec.c:353 exec.c:365 #, c-format msgid "Max files set to %d\n" msgstr "" #: exec.c:346 msgid "Max files unset\n" msgstr "" #: exec.c:337 #, c-format msgid "Max files: %d\n" msgstr "" #: exec.c:335 msgid "Max files: unset" msgstr "" #: keybinds.c:1461 #, c-format msgid "Max name length set to %d\n" msgstr "" #: keybinds.c:1459 msgid "Max name length unset\n" msgstr "" #: exec.c:668 msgid "Messages cleared\n" msgstr "" #: selection.c:826 msgid "Missing parameter. Try 's --help'\n" msgstr "" #: properties.c:1502 #, c-format msgid "Modify: \t%s%s%s\n" msgstr "" #: media.c:601 msgid "Mounted devices" msgstr "" #: media.c:600 msgid "Mountpoints" msgstr "" #: mime.c:1589 #, c-format msgid "Name: %s\n" msgstr "" #: remotes.c:55 #, c-format msgid "Name: %s%s%s\n" msgstr "" #: config.c:91 #, c-format msgid "New configuration file written to '%s'\n" msgstr "" #: archives.c:925 msgid "New format (e.g.: .tar.xz): " msgstr "" #: keybinds.c:1113 #, c-format msgid "New key: %s\n" msgstr "" #: properties.c:795 #, c-format msgid "New ownership set for %zu file(s)\n" msgstr "" #: remotes.c:69 msgid "No" msgstr "" #: search.c:683 msgid "No matches found\n" msgstr "" #: mime.c:1489 msgid "No such ELN" msgstr "" #: mime.c:1589 msgid "None" msgstr "" #: config.c:82 #, c-format msgid "Old configuration file saved as '%s'\n" msgstr "" #: keybinds.c:654 #, c-format msgid "Old keybindings file saved as '%s'\n" msgstr "" #: keybinds.c:2967 #, c-format msgid "Only directories %s\n" msgstr "" #: exec.c:726 #, c-format msgid "Opener set to '%s'\n" msgstr "" #: mime.c:1600 #, c-format msgid "Opening application: %s [%s]\n" msgstr "" #: mime.c:1597 #, c-format msgid "Opening application: ad [builtin] [%s]\n" msgstr "" #: archives.c:126 archives.c:602 archives.c:790 msgid "Operation: " msgstr "" #: bulk_rename.c:94 file_operations.c:1452 msgid "Overwrite this file?" msgstr "" #: exec.c:489 msgid "Pager disabled" msgstr "" #: exec.c:498 msgid "Pager enabled" msgstr "" #: exec.c:483 #, c-format msgid "Pager set to %d\n" msgstr "" #: exec.c:957 #, c-format msgid "Pinned file: '%s'\n" msgstr "" #: properties.c:1284 msgid "Port " msgstr "" #: exec.c:1467 #, c-format msgid "Ports: %zu\n" msgstr "" #: config.c:3243 #, c-format msgid "PreviewMaxSize: '%c': Invalid unit.\n" msgstr "" #: config.c:3249 #, c-format msgid "PreviewMaxSize: Value too large (max %dGiB).\n" msgstr "" #: mime.c:1613 #, c-format msgid "Previewing application: %s %s\n" msgstr "" #: strings.c:2034 msgid "Querying MIME types... " msgstr "" #: properties.c:1270 msgid "Regular file" msgstr "" #: file_operations.c:1233 msgid "Relink as broken symbolic link?" msgstr "" #: trash.c:76 #, c-format msgid "Remove %zu file(s)?" msgstr "" #: file_operations.c:2050 msgid "Remove files anyway?" msgstr "" #: bookmarks.c:750 #, c-format msgid "Removed %zu bookmark(s)\n" msgstr "" #: view.c:341 #, c-format msgid "Removed %zu thumbnail(s): %s freed\n" msgstr "" #: help.c:370 msgid "Run '?' and consult the NAVIGATION section" msgstr "" #: help.c:307 #, c-format msgid "Run '?' or 'help' to get started with %s\n" msgstr "" #: colors.c:1056 msgid "Run 'cs edit' to fix these conflicts" msgstr "" #: misc.c:770 msgid "Run command?" msgstr "" #: exec.c:1425 msgid "Running in light mode: Some files statistics are not available\n" msgstr "" #: exec.c:878 #, c-format msgid "Show-hidden-files is %s\n" msgstr "" #: listing.c:704 #, c-format msgid "Showing %jd/%jd files\n" msgstr "" #: properties.c:1778 msgid "Size:\t\t" msgstr "" #: properties.c:1635 #, c-format msgid "Size: \t\t%s%s%s" msgstr "" #: properties.c:1274 msgid "Socket " msgstr "" #: listing.c:692 sort.c:434 msgid "Sorted by " msgstr "" #: profiles.c:349 #, c-format msgid "Succesfully created profile %s%s%s\n" msgstr "" #: tags.c:743 #, c-format msgid "Successfully merged %s%s%s into %s%s%s\n" msgstr "" #: profiles.c:395 #, c-format msgid "Successfully removed profile %s%s%s\n" msgstr "" #: tags.c:563 #, c-format msgid "Successfully tagged %zu file(s)\n" msgstr "" #: tags.c:635 #, c-format msgid "Successfully untagged %zu file(s)\n" msgstr "" #: keybinds.c:3280 #, c-format msgid "Switched to %s names\n" msgstr "" #: profiles.c:267 #, c-format msgid "Switched to profile %s%s%s\n" msgstr "" #: properties.c:1272 msgid "Symbolic link" msgstr "" #: help.c:425 msgid "Take a look at the 'colorschemes', 'prompt', and 'config' commands" msgstr "" #: exec.c:439 msgid "The file counter is disabled" msgstr "" #: exec.c:437 msgid "The file counter is enabled" msgstr "" #: config.c:274 msgid "" "The following is the list of options (as defined in the configuration file) " "and their current values. Whenever a value differs from the default, the " "entry is highlighted and the default value is displayed in square brackets.\n" msgstr "" #: exec.c:468 msgid "The pager is disabled" msgstr "" #: exec.c:469 msgid "The pager is enabled" msgstr "" #: exec.c:470 #, c-format msgid "The pager is set to %d\n" msgstr "" #: actions.c:424 msgid "" "To run a plugin just enter its action name\n" "Example: enter '//' to run the rgfind plugin" msgstr "" #: keybinds.c:1102 msgid "To unset the function enter '-'" msgstr "" #: exec.c:938 #, c-format msgid "Toggled executable bit on %zu %s\n" msgstr "" #: properties.c:307 properties.c:386 msgid "Too few" msgstr "" #: properties.c:307 properties.c:386 msgid "Too many" msgstr "" #: exec.c:1438 #, c-format msgid "" "Total files: %jd\n" "Directories: %zu%s\n" "Regular files: %zu%s\n" "Executable files: %zu\n" "Hidden files: %zu\n" "SUID files: %zu\n" "SGID files: %zu\n" "Files w/capabilities: %zu\n" "FIFO/pipes: %zu\n" "Sockets: %zu\n" "Block devices: %zu\n" "Character devices: %zu\n" "Symbolic links: %zu%s\n" "Multi-link files: %zu\n" "Files w/extended attributes: %zu\n" "Other-writable files: %zu\n" "Sticky files: %zu\n" "Unknown file types: %zu\n" "Unstatable files: %zu\n" msgstr "" #: properties.c:1821 msgid "Total size:\t" msgstr "" #: properties.c:1591 msgid "Total size: \t" msgstr "" #: properties.c:1662 properties.c:1814 #, c-format msgid "Total size: \t%s%c%s\n" msgstr "" #: properties.c:2069 #, c-format msgid "Total size: %s%s%s%s\n" msgstr "" #: trash.c:92 #, c-format msgid "Trash can emptied: %zu file(s) removed\n" msgstr "" #: mime.c:683 msgid "Try 'mm edit APPLICATION'\n" msgstr "" #: properties.c:1305 properties.c:1307 msgid "UNKNOWN" msgstr "" #: keybinds.c:1116 msgid "Unset this function?" msgstr "" #: archives.c:508 msgid "" "Use extension to specify archive/compression type (defaults to .tar.gz)\n" "Example: myarchive.xz" msgstr "" #: listing.c:701 msgid "Virtual directory\n" msgstr "" #: properties.c:1287 msgid "Whiteout" msgstr "" #: exec.c:1474 #, c-format msgid "Whiteout: %zu\n" msgstr "" #: properties.c:1333 msgid "Xattributes:\t" msgstr "" #: remotes.c:69 msgid "Yes" msgstr "" #: actions.c:346 msgid "actions: Access to configuration files is not allowed in stealth mode" msgstr "" #: actions.c:439 msgid "" "actions: No actions defined. Use the 'actions edit' command to add new " "actions\n" msgstr "" #: actions.c:436 msgid "actions: Plugins are not allowed in stealth mode\n" msgstr "" #: actions.c:70 msgid "actions: Plugins directory not defined" msgstr "" #: misc.c:982 #, c-format msgid "alias: %zu alias(es) imported\n" msgstr "" #: misc.c:876 #, c-format msgid "alias: '%s': Error normalizing filename\n" msgstr "" #: misc.c:968 #, c-format msgid "alias: No alias found in '%s'\n" msgstr "" #: misc.c:976 msgid "alias: No alias imported\n" msgstr "" #: exec.c:522 msgid "allowed" msgstr "" #: properties.c:1646 properties.c:1691 properties.c:1770 properties.c:1803 msgid "apparent" msgstr "" #: archives.c:553 #, c-format msgid "archiver: '%s': Error unescaping filename\n" msgstr "" #: archives.c:424 #, c-format msgid "" "archiver: '%s': Invalid file format. File should be either a directory or a " "block device.\n" msgstr "" #: archives.c:750 #, c-format msgid "archiver: '%s': Not an archive/compressed file\n" msgstr "" #: autocmds.c:861 msgid "auto: No temporary autocommand defined for the current directory\n" msgstr "" #: autocmds.c:956 msgid "auto: The current directory is undefined\n" msgstr "" #: autocmds.c:649 #, c-format msgid "autocmd: '%s': Invalid option format (it must be 'OPTION=VALUE')\n" msgstr "" #: autocmds.c:718 #, c-format msgid "autocmd: '%s': Invalid option name\n" msgstr "" #: autocmds.c:723 #, c-format msgid "autocmd: '%s': Invalid value for '%s'\n" msgstr "" #: autocmds.c:580 #, c-format msgid "autocmd: '%s': Invalid value for 'cs'\n" msgstr "" #: autocmds.c:628 #, c-format msgid "autocmd: '%s': Invalid value for 'st'\n" msgstr "" #: navigation.c:316 #, c-format msgid "bd: %s: No matches found\n" msgstr "" #: navigation.c:233 #, c-format msgid "bd: '%s': Error expanding tilde\n" msgstr "" #: navigation.c:226 #, c-format msgid "bd: '%s': Error unescaping string\n" msgstr "" #: navigation.c:283 msgid "bd: '/': No parent directory" msgstr "" #: file_operations.c:2273 #, c-format msgid "bl: '%s': Error unescaping name\n" msgstr "" #: file_operations.c:2306 #, c-format msgid "bl: Cannot create symbolic link '%s': %s\n" msgstr "" #: name_cleaner.c:509 #, c-format msgid "bleach: '%s': Error unescaping filename\n" msgstr "" #: name_cleaner.c:660 #, c-format msgid "bleach: Cannot rename '%s' to '%s': %s\n" msgstr "" #: bookmarks.c:399 #, c-format msgid "bookmarks: '%s': Already bookmarked as '%s'\n" msgstr "" #: bookmarks.c:425 #, c-format msgid "bookmarks: '%s': Colons and square brackets are not allowed\n" msgstr "" #: bookmarks.c:575 #, c-format msgid "bookmarks: '%s': Error unescaping filename\n" msgstr "" #: bookmarks.c:454 #, c-format msgid "bookmarks: '%s': Name already in use\n" msgstr "" #: bookmarks.c:420 #, c-format msgid "bookmarks: '%s': Reserved bookmark keyword\n" msgstr "" #: bookmarks.c:478 #, c-format msgid "bookmarks: '%s': Shortcut already in use\n" msgstr "" #: bookmarks.c:569 msgid "bookmarks: Cannot add any more bookmarks" msgstr "" #: bookmarks.c:124 msgid "bookmarks: Cannot open the bookmarks file" msgstr "" #: bookmarks.c:752 #, c-format msgid "" "bookmarks: Error updating bookmarks\n" "Cannot rename temporary file '%s': %s\n" msgstr "" #: bulk_rename.c:373 #, c-format msgid "br: '%s' is duplicated\n" msgstr "" #: bulk_rename.c:87 bulk_rename.c:154 #, c-format msgid "br: '%s': Error normalizing path\n" msgstr "" #: bulk_rename.c:140 #, c-format msgid "br: '%s': Error unescaping filename\n" msgstr "" #: bulk_rename.c:107 #, c-format msgid "br: Cannot rename '%s' to '%s': %s\n" msgstr "" #: bulk_rename.c:283 msgid "br: Line mismatch in temporary file" msgstr "" #: bulk_rename.c:224 bulk_rename.c:455 msgid "br: Nothing to do" msgstr "" #: bulk_rename.c:488 msgid "br: Temporary file changed on disk! Aborting." msgstr "" #: colors.c:984 msgid "builtin (256 colors)" msgstr "" #: colors.c:986 msgid "builtin (8 colors)" msgstr "" #: navigation.c:482 #, c-format msgid "cd: '%s': Error normalizing path\n" msgstr "" #: navigation.c:440 msgid "cd: Home directory not found" msgstr "" #: navigation.c:463 msgid "cd: Path is NULL or empty" msgstr "" #: colors.c:908 colors.c:969 #, c-format msgid "cs: '%s': No such color scheme\n" msgstr "" #: colors.c:898 msgid "cs: Current color scheme is unknown" msgstr "" #: colors.c:868 colors.c:893 msgid "cs: No color scheme found" msgstr "" #: colors.c:1060 msgid "cs: No conflicts found" msgstr "" #: selection.c:1205 #, c-format msgid "desel: %s: Invalid ELN\n" msgstr "" #: selection.c:1194 #, c-format msgid "desel: '%s': Invalid entry\n" msgstr "" #: selection.c:1288 msgid "desel: No selected files" msgstr "" #: media.c:638 msgid "devices" msgstr "" #: exec.c:1703 #, c-format msgid "dh: '%d': No such entry number\n" msgstr "" #: exec.c:1709 msgid "dh: Invalid history entry" msgstr "" #: properties.c:1734 properties.c:1852 msgid "directories" msgstr "" #: properties.c:1734 properties.c:1852 msgid "directory" msgstr "" #: exec.c:388 exec.c:410 exec.c:553 exec.c:580 exec.c:597 exec.c:858 #: exec.c:1742 exec.c:1792 exec.c:1822 exec.c:1995 keybinds.c:2008 #: keybinds.c:2036 keybinds.c:2062 keybinds.c:2089 keybinds.c:2968 #: keybinds.c:3173 msgid "disabled" msgstr "" #: properties.c:1647 properties.c:1692 msgid "disk usage" msgstr "" #: file_operations.c:340 #, c-format msgid "dup: '%s': Error unescaping filename\n" msgstr "" #: exec.c:388 exec.c:410 exec.c:553 exec.c:580 exec.c:597 exec.c:862 #: exec.c:1742 exec.c:1792 exec.c:1822 exec.c:1995 keybinds.c:2008 #: keybinds.c:2036 keybinds.c:2062 keybinds.c:2089 keybinds.c:2968 #: keybinds.c:3173 msgid "enabled" msgstr "" #: exec.c:859 msgid "enabled (list first)" msgstr "" #: exec.c:860 msgid "enabled (list last)" msgstr "" #: jump.c:591 jump.c:632 msgid "entries" msgstr "" #: jump.c:591 jump.c:632 msgid "entry" msgstr "" #: exec.c:200 #, c-format msgid "export: %s: Empty assignement\n" msgstr "" #: exec.c:176 msgid "export: A parameter, in the form VAR=VALUE, is required" msgstr "" #: exec.c:193 msgid "export: Error unescaping argument" msgstr "" #: remotes.c:65 remotes.c:67 msgid "false" msgstr "" #: exec.c:939 properties.c:1735 properties.c:1853 msgid "file" msgstr "" #: exec.c:939 properties.c:1735 properties.c:1853 msgid "files" msgstr "" #: history.c:293 msgid "fix the error (consult your daemon's documentation)" msgstr "" #: misc.c:620 msgid "ft: Error removing quotes: Filter unset" msgstr "" #: misc.c:566 msgid "ft: Invalid file type filter" msgstr "" #: misc.c:570 msgid "ft: Invalid filter" msgstr "" #: misc.c:510 msgid "ft: No filter set" msgstr "" #: navigation.c:684 #, c-format msgid "history: %d: No such ELN\n" msgstr "" #: navigation.c:690 msgid "history: Invalid history entry" msgstr "" #: history.c:292 msgid "install a notification daemon" msgstr "" #: properties.c:1237 msgid "invalid ACL" msgstr "" #: jump.c:337 msgid "je: Configuration directory not found\n" msgstr "" #: jump.c:807 #, c-format msgid "jump: '%c': Invalid option\n" msgstr "" #: jump.c:650 #, c-format msgid "jump: '%s': Invalid value\n" msgstr "" #: jump.c:466 msgid "jump: Database still empty" msgstr "" #: jump.c:629 #, c-format msgid "jump: No entry ranked below %d\n" msgstr "" #: jump.c:588 msgid "jump: No invalid entries" msgstr "" #: jump.c:946 msgid "jump: No matches found" msgstr "" #: exec.c:1985 msgid "k: Feature not available in light mode" msgstr "" #: exec.c:1980 msgid "k: Not in long view" msgstr "" #: keybinds.c:780 #, c-format msgid "kb: %s: Key already in use by '%s' (readline)\n" msgstr "" #: keybinds.c:742 #, c-format msgid "kb: %s: Key already in use by '%s'.\n" msgstr "" #: keybinds.c:808 #, c-format msgid "kb: '%s' conflicts with '%s'\n" msgstr "" #: keybinds.c:735 #, c-format msgid "kb: '%s' conflicts with '%s' (readline)\n" msgstr "" #: keybinds.c:1085 #, c-format msgid "" "kb: '%s': Invalid function name\n" "Type 'kb bind ' to list available function names\n" msgstr "" #: aux.c:699 msgid "kb: Cannot generate time suffix string for the backup file\n" msgstr "" #: keybinds.c:952 keybinds.c:970 #, c-format msgid "kb: Cannot open '%s': %s\n" msgstr "" #: keybinds.c:986 #, c-format msgid "kb: Cannot open temporary file: %s\n" msgstr "" #: keybinds.c:647 keybinds.c:1007 #, c-format msgid "kb: Cannot rename '%s' to '%s': %s\n" msgstr "" #: keybinds.c:980 #, c-format msgid "kb: Error creating temporary file: %s\n" msgstr "" #: keybinds.c:1051 #, c-format msgid "kb: Invalid keybinding\n" msgstr "" #: keybinds.c:799 msgid "kb: No keybindings defined" msgstr "" #: keybinds.c:1139 msgid "kb: No keybindings defined\n" msgstr "" #: keybinds.c:669 keybinds.c:694 keybinds.c:1075 msgid "kb: No keybindings file found\n" msgstr "" #: keybinds.c:679 keybinds.c:714 keybinds.c:1128 #, c-format msgid "kb: Restart %s for changes to take effect\n" msgstr "" #: file_operations.c:1188 #, c-format msgid "le: '%s': Error unescaping filename\n" msgstr "" #: file_operations.c:1208 #, c-format msgid "le: '%s': Not a symbolic link\n" msgstr "" #: file_operations.c:1243 #, c-format msgid "le: Cannot relink symbolic link '%s': %s\n" msgstr "" #: file_operations.c:1223 msgid "le: Nothing to do" msgstr "" #: properties.c:1736 properties.c:1854 msgid "link" msgstr "" #: file_operations.c:1360 file_operations.c:1371 #, c-format msgid "link: '%s': Error normalizing path\n" msgstr "" #: file_operations.c:1478 #, c-format msgid "link: Cannot create symbolic link '%s': %s\n" msgstr "" #: file_operations.c:1458 #, c-format msgid "link: Cannot unlink '%s': %s\n" msgstr "" #: file_operations.c:1348 #, c-format msgid "link: Error generating relative path: %s\n" msgstr "" #: properties.c:1736 properties.c:1854 msgid "links" msgstr "" #: exec.c:1791 #, c-format msgid "log: Command logs are %s\n" msgstr "" #: exec.c:1811 msgid "log: Command logs cleared" msgstr "" #: exec.c:1804 msgid "log: Command logs disabled" msgstr "" #: exec.c:1798 msgid "log: Command logs enabled" msgstr "" #: exec.c:1821 #, c-format msgid "log: Message logs are %s\n" msgstr "" #: exec.c:1841 msgid "log: Message logs cleared" msgstr "" #: exec.c:1834 msgid "log: Message logs disabled" msgstr "" #: exec.c:1828 msgid "log: Message logs enabled" msgstr "" #: keybinds.c:3281 msgid "long" msgstr "" #: media.c:579 msgid "media" msgstr "" #: exec.c:2445 msgid "media: Function not available\n" msgstr "" #: media.c:585 msgid "media: Function only available on Linux systems" msgstr "" #: media.c:591 msgid "media: No mount application found. Install either udevil or udisks2" msgstr "" #: archives.c:302 msgid "mount: This feature is available for Linux only." msgstr "" #: media.c:579 media.c:638 msgid "mountpoints" msgstr "" #: exec.c:2435 msgid "mountpoints: Function not available\n" msgstr "" #: media.c:640 msgid "mp: There are no available mountpoints\n" msgstr "" #: file_operations.c:1975 msgid "name was" msgstr "" #: file_operations.c:1975 msgid "names were" msgstr "" #: remotes.c:202 #, c-format msgid "net: '%s': Changed to mountpoint (%s)\n" msgstr "" #: remotes.c:247 #, c-format msgid "net: '%s': Error getting parent directory\n" msgstr "" #: remotes.c:380 #, c-format msgid "net: '%s': Mount command failed with error code %d\n" msgstr "" #: remotes.c:116 #, c-format msgid "net: '%s': No such remote\n" msgstr "" #: remotes.c:218 #, c-format msgid "net: '%s': Not mounted\n" msgstr "" #: remotes.c:223 #, c-format msgid "net: Error getting mountpoint for '%s'\n" msgstr "" #: remotes.c:166 #, c-format msgid "net: No mount command specified for '%s'\n" msgstr "" #: remotes.c:121 #, c-format msgid "net: No mountpoint specified for '%s'\n" msgstr "" #: remotes.c:228 #, c-format msgid "net: No unmount command for '%s'\n" msgstr "" #: remotes.c:283 msgid "net: Remotes file is undefined\n" msgstr "" #: file_operations.c:486 #, c-format msgid "new: '%s': No such template\n" msgstr "" #: file_operations.c:843 #, c-format msgid "new: '%s': Unsafe filename\n" msgstr "" #: properties.c:912 properties.c:927 properties.c:1141 properties.c:1237 msgid "none" msgstr "" #: exec.c:522 msgid "not allowed" msgstr "" #: keybinds.c:420 msgid "not bound" msgstr "" #: properties.c:750 #, c-format msgid "oc: '%s': Invalid group\n" msgstr "" #: properties.c:737 #, c-format msgid "oc: '%s': Invalid user\n" msgstr "" #: properties.c:793 msgid "oc: Nothing to do" msgstr "" #: properties.c:628 msgid "oc: Nothing to do\n" msgstr "" #: properties.c:1771 properties.c:1804 msgid "on disk" msgstr "" #: file_operations.c:1001 #, c-format msgid "open: '%s': Broken symbolic link to '%s'\n" msgstr "" #: properties.c:1951 #, c-format msgid "p: '%s': Cannot unescape filename\n" msgstr "" #: properties.c:385 #, c-format msgid "pc: %s characters: 9 are expected\n" msgstr "" #: properties.c:306 #, c-format msgid "pc: %s digits. Either 3 or 4 are expected\n" msgstr "" #: properties.c:314 #, c-format msgid "" "pc: '%c': Invalid digit. Values in the range 0-7 are expected for each " "field\n" msgstr "" #: properties.c:596 #, c-format msgid "pc: Applied new permissions to %zu file(s)\n" msgstr "" #: properties.c:588 #, c-format msgid "pc: Changing permissions of '%s': %s\n" msgstr "" #: properties.c:335 #, c-format msgid "pc: Invalid character in field %zu: %s-r%s are expected\n" msgstr "" #: properties.c:345 #, c-format msgid "pc: Invalid character in field %zu: %s-w%s are expected\n" msgstr "" #: properties.c:354 #, c-format msgid "pc: Invalid character in field %zu: %s-xsS%s are expected\n" msgstr "" #: properties.c:362 #, c-format msgid "pc: Invalid character in field %zu: %s-xtT%s are expected\n" msgstr "" #: properties.c:451 msgid "pc: Nothing to do\n" msgstr "" #: profiles.c:148 #, c-format msgid "pf: '%s' is the current profile\n" msgstr "" #: profiles.c:285 #, c-format msgid "pf: '%s': Cannot create profile: Home directory not found\n" msgstr "" #: profiles.c:391 #, c-format msgid "pf: '%s': Error removing profile\n" msgstr "" #: profiles.c:447 profiles.c:492 #, c-format msgid "pf: '%s': Invalid profile name\n" msgstr "" #: profiles.c:514 #, c-format msgid "pf: '%s': Is the current profile\n" msgstr "" #: profiles.c:378 profiles.c:509 #, c-format msgid "pf: '%s': No such profile\n" msgstr "" #: profiles.c:139 #, c-format msgid "" "pf: '%s': No such profile\n" "To add a new profile enter 'pf add PROFILE'\n" msgstr "" #: profiles.c:280 #, c-format msgid "pf: '%s': Profile already exists\n" msgstr "" #: profiles.c:559 #, c-format msgid "pf: '%s': Profile successfully renamed to %s%s%s\n" msgstr "" #: profiles.c:357 msgid "pf: 's': Error creating profile\n" msgstr "" #: profiles.c:549 #, c-format msgid "pf: Cannot rename profile '%s': %s\n" msgstr "" #: profiles.c:487 msgid "pf: Configuration directory is not set\n" msgstr "" #: profiles.c:212 msgid "pf: Error opening the history file\n" msgstr "" #: profiles.c:497 msgid "pf: Nothing to do. Source and destination names are the same." msgstr "" #: profiles.c:299 #, c-format msgid "pf: mkdir: '%s': Error creating configuration directory\n" msgstr "" #: exec.c:479 msgid "pg: xatoi: Error converting to integer" msgstr "" #: misc.c:2033 #, c-format msgid "pin: Error saving pinned directory: %s\n" msgstr "" #: exec.c:959 msgid "pin: No pinned file" msgstr "" #: misc.c:2083 #, c-format msgid "pin: Succesfully pinned '%s'\n" msgstr "" #: prompt.c:1756 #, c-format msgid "prompt: %s: Error unescaping string\n" msgstr "" #: prompt.c:1769 #, c-format msgid "prompt: %s: No such prompt\n" msgstr "" #: prompt.c:1749 msgid "prompt: No extra prompts defined. Using the default prompt" msgstr "" #: prompt.c:1690 msgid "prompt: No extra prompts found. Using the default prompt" msgstr "" #: prompt.c:1846 msgid "prompt: Prompts file not found" msgstr "" #: navigation.c:62 #, c-format msgid "" "pwd: '%s': Invalid option\n" "Usage: pwd [-LP]\n" msgstr "" #: file_operations.c:1973 #, c-format msgid "" "r: '%s': File may still exist (%jd more %s linked to this file before this " "operation)\n" msgstr "" #: trash.c:438 msgid "removed" msgstr "" #: trash.c:438 msgid "restored" msgstr "" #: bulk_remove.c:232 #, c-format msgid "rr: '%s': Cannot open file\n" msgstr "" #: bulk_remove.c:213 #, c-format msgid "rr: '%s': Directory empty\n" msgstr "" #: bulk_remove.c:386 msgid "rr: Nothing to do" msgstr "" #: bulk_remove.c:452 msgid "rr: Temporary file changed on disk! Aborting." msgstr "" #: search.c:202 #, c-format msgid "search: %s: Error unescaping filename\n" msgstr "" #: search.c:188 #, c-format msgid "search: '%c': Unrecognized file type\n" msgstr "" #: search.c:681 search.c:852 search.c:1010 msgid "search: No matches found\n" msgstr "" #: selection.c:464 #, c-format msgid "sel: %s: Invalid regular expression\n" msgstr "" #: selection.c:496 #, c-format msgid "" "sel: '%c': Unrecognized file type.\n" "Try 'sel --help' for more information.\n" msgstr "" #: selection.c:148 #, c-format msgid "sel: '%s': Already selected\n" msgstr "" #: selection.c:944 msgid "sel: Cannot open the selections file" msgstr "" #: selection.c:102 msgid "sel: Cannot select any more files" msgstr "" #: selection.c:121 #, c-format msgid "sel: Cannot select file '%s': %s\n" msgstr "" #: selection.c:555 msgid "sel: Error expanding path" msgstr "" #: selection.c:642 msgid "sel: Error writing files into the selections file\n" msgstr "" #: selection.c:654 selection.c:660 msgid "sel: No matches found\n" msgstr "" #: selection.c:836 msgid "sel: No selected files" msgstr "" #: keybinds.c:3281 msgid "short" msgstr "" #: sort.c:454 #, c-format msgid "st: %d (%s): Not available in light mode\n" msgstr "" #: sort.c:425 #, c-format msgid "st: %s: No such sort order\n" msgstr "" #: sort.c:414 #, c-format msgid "st: '%s': Not available in light mode\n" msgstr "" #: sort.c:461 msgid "st: Birth time is not available on this platform" msgstr "" #: tags.c:460 #, c-format msgid "tag: '%s': Cannot create tag: %s\n" msgstr "" #: tags.c:49 #, c-format msgid "tag: '%s': Cannot create tag: file already exists\n" msgstr "" #: tags.c:390 #, c-format msgid "tag: '%s': Error creating tag: %s\n" msgstr "" #: tags.c:47 #, c-format msgid "tag: '%s': File already tagged\n" msgstr "" #: tags.c:612 #, c-format msgid "tag: '%s': File not tagged as %s%s%s\n" msgstr "" #: tags.c:72 #, c-format msgid "tag: '%s': No such tag\n" msgstr "" #: tags.c:384 #, c-format msgid "tag: '%s': Tag already exists\n" msgstr "" #: tags.c:731 msgid "tag: Cannot merge tags: error moving tagged files" msgstr "" #: tags.c:532 msgid "" "tag: No tag specified. Specify a tag via :TAG. E.g. 'tag add FILE1 " "FILE2 :TAG'" msgstr "" #: tags.c:271 msgid "tag: No tags" msgstr "" #: tags.c:724 msgid "tag: Source and destination are the same tag" msgstr "" #: file_operations.c:244 #, c-format msgid "te: Changing permissions of '%s': %s\n" msgstr "" #: trash.c:571 #, c-format msgid "trash: %s: Invalid ELN\n" msgstr "" #: trash.c:593 #, c-format msgid "trash: '%s': Cannot remove file from the trash can\n" msgstr "" #: trash.c:1072 #, c-format msgid "trash: '%s': Error abbreviating filename\n" msgstr "" #: trash.c:183 #, c-format msgid "trash: '%s': Error encoding path\n" msgstr "" #: trash.c:238 #, c-format msgid "trash: '%s': Error getting file base name\n" msgstr "" #: trash.c:1065 trash.c:1154 #, c-format msgid "trash: '%s': Error unescaping filename\n" msgstr "" #: trash.c:1019 #, c-format msgid "trash: Cannot trash '%s'\n" msgstr "" #: trash.c:289 trash.c:338 trash.c:1043 #, c-format msgid "trash: Cannot trash '%s': %s\n" msgstr "" #: trash.c:1147 msgid "trash: Cannot trash any more files" msgstr "" #: trash.c:133 trash.c:167 trash.c:511 trash.c:522 trash.c:977 msgid "trash: No trashed files" msgstr "" #: trash.c:963 msgid "trash: The trash directory is undefined\n" msgstr "" #: trash.c:1025 msgid "trash: Use 'trash del' to remove trashed files\n" msgstr "" #: remotes.c:65 remotes.c:67 msgid "true" msgstr "" #: file_operations.c:127 #, c-format msgid "umask: %s: Out of range (valid values are 000-777)\n" msgstr "" #: properties.c:137 properties.c:912 properties.c:1202 properties.c:1206 #: properties.c:1322 properties.c:1347 msgid "unavailable" msgstr "" #: trash.c:896 #, c-format msgid "undel: %s: Invalid ELN\n" msgstr "" #: trash.c:766 #, c-format msgid "undel: '%s': %s\n" msgstr "" #: trash.c:709 #, c-format msgid "undel: '%s': Destination file exists\n" msgstr "" #: trash.c:655 #, c-format msgid "undel: '%s': Error decoding original path\n" msgstr "" #: trash.c:683 #, c-format msgid "undel: '%s': No directory specified\n" msgstr "" #: trash.c:677 msgid "undel: Filename is NULL or empty\n" msgstr "" #: trash.c:617 #, c-format msgid "undel: Info file for '%s' not found. Try restoring the file manually.\n" msgstr "" #: bookmarks.c:401 msgid "unnamed" msgstr "" #: misc.c:2098 msgid "unpin: No pinned file" msgstr "" #: misc.c:2116 #, c-format msgid "unpin: Succesfully unpinned '%s'\n" msgstr "" #: exec.c:1752 msgid "unset: A variable name is required" msgstr "" #: view.c:292 #, c-format msgid "view: '%s' does not exist. Entry removed.\n" msgstr "" #: view.c:224 #, c-format msgid "view: '%s': Not a regular file\n" msgstr "" #: view.c:114 #, c-format msgid "view: '%s': Removing dangling thumbnail... " msgstr "" #: view.c:219 #, c-format msgid "view: Cannot access '%s': %s\n" msgstr "" #: view.c:232 #, c-format msgid "view: Cannot create temporary file '%s': %s\n" msgstr "" #: view.c:248 #, c-format msgid "view: Cannot open '%s': %s\n" msgstr "" #: view.c:239 #, c-format msgid "view: Cannot open temporary file '%s': %s\n" msgstr "" #: view.c:346 msgid "view: No dangling thumbnails" msgstr "" #: view.c:207 msgid "" "view: The thumbnails directory does not exist, is not a directory, or there " "are no thumbnails\n" msgstr "" #: file_operations.c:1547 #, c-format msgid "vv: '%s': directory does not exist.\n" msgstr "" #: workspaces.c:133 workspaces.c:250 #, c-format msgid "ws: %d: Is the current workspace\n" msgstr "" #: workspaces.c:125 #, c-format msgid "ws: %d: No such workspace (valid workspaces: 1-%d)\n" msgstr "" #: workspaces.c:300 #, c-format msgid "ws: %s: Is the current workspace\n" msgstr "" #: workspaces.c:308 #, c-format msgid "ws: %s: No such workspace\n" msgstr "" #: workspaces.c:345 #, c-format msgid "ws: '%s': Already unset\n" msgstr "" #: workspaces.c:340 #, c-format msgid "ws: '%s': Is the current workspace\n" msgstr "" #: workspaces.c:333 #, c-format msgid "ws: '%s': No such workspace (valid workspaces: 1-%d)\n" msgstr "" #: workspaces.c:349 #, c-format msgid "ws: '%s': Workspace unset\n" msgstr "" #: workspaces.c:228 workspaces.c:238 msgid "ws: Current workspace is invalid\n" msgstr "" #: workspaces.c:366 msgid "ws: There are no defined workspaces\n" msgstr "" #: workspaces.c:397 msgid "ws: This is already the first workspace\n" msgstr "" #: workspaces.c:390 msgid "ws: This is already the last workspace\n" msgstr "" #: file_operations.c:207 msgid "xchmod: Empty buffer for filename\n" msgstr "" #: file_operations.c:213 msgid "xchmod: Empty buffer for mode\n" msgstr "" clifm-1.26.3/translations/es.po000066400000000000000000002725041506632037700164100ustar00rootroot00000000000000# Clifm File Manager. # Copyright (C) 2025 L. Abramovich # This file is distributed under the same license as the Clifm package. # L. Abramovich , 2025. msgid "" msgstr "" "Project-Id-Version: clifm\n" "Report-Msgid-Bugs-To: https://github.com/leo-arch/clifm/issues\n" "POT-Creation-Date: 2025-03-16 00:42-0300\n" "PO-Revision-Date: 2025-03-16 19:25-0300\n" "Last-Translator: L. Abramovich \n" "Language-Team: \n" "Language: es\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "\tBlocks: %s%jd%s" msgstr "\tBloques: %s%jd%s" msgid "\tInode: %s%ju%s" msgstr "\tInodo: %s%ju%s" msgid "\tName: %s%s%s\n" msgstr "\tNombre: %s%s%s\n" msgid "\tName: %s%s%s %s%s ???%s\n" msgstr "\tNombre: %s%s%s %s%s ???%s\n" msgid "\tName: %s%s%s %s%s%s %s%s%s\n" msgstr "\tNombre: %s%s%s %s%s%s %s%s%s\n" msgid "\tName: %s%s%s %s%s%s %s%s%s (broken link)\n" msgstr "\tNombre: %s%s%s %s%s%s %s%s%s (enlace roto)\n" msgid "" "\n" " %sOrder\tVisits\tFirst\tLast\tRank\tDirectory%s\n" msgstr "" "\n" " %sOrden\tVisitas\tPrimero\tÚltimo\tRango\tDirectorio%s\n" msgid "" "\n" "%s: No pinned file\n" msgstr "" "\n" "%s: No hay archivo fijado\n" msgid "" "\n" "%s: No selected files\n" msgstr "" "\n" "%s: No hay archivos seleccionados\n" msgid "" "\n" "%sEnter 'q' to quit\n" "File(s) to be %s (e.g.: 1 2-6, or *):\n" msgstr "" "\n" "%sIntroduzca 'q' para salir\n" "Archivo(s) a ser %s (por ejemplo: 1 2-6, o *):\n" msgid "" "\n" "%sEnter 'q' to quit or 'e' to edit the selections file\n" "File(s) to be deselected (e.g.: 1 2-6, or *):\n" msgstr "" "\n" "%sIntroduzca 'q' para salir o 'e' para editar el archivo de selecciones\n" "Archivo(s) a ser deseleccionados (por ejemplo: 1 2-6, o *):\n" msgid "" "\n" "%sFile extensions%s\n" "\n" msgstr "" "\n" "%sExtensiones de archivo%s\n" "\n" msgid "" "\n" "%sInterface%s\n" "\n" msgstr "" "\n" "%sInterfaz%s\n" "\n" msgid "" "\n" "%sNOTE%s: Zstandard does not support compression of multiple files into a " "single compressed file. Instead, files will be compressed into multiple " "compressed files using their original filenames.\n" msgstr "" "\n" "%sNOTA%s: Zstandard no admite la compresión de múltiples archivos en un solo archivo comprimido. En su lugar, los archivos se comprimirán en múltiples archivos comprimidos utilizando sus nombres de archivo originales.\n" msgid "" "\n" "%sPrompt%s\n" "\n" msgstr "" "\n" "%sPrompt%s\n" "\n" msgid "" "\n" "%sProperties / Long view%s\n" "\n" msgstr "" "\n" "%sPropiedades / Vista larga%s\n" "\n" msgid "" "\n" "%sSyntax highlighting%s\n" "\n" msgstr "" "\n" "%sResaltado de sintaxis%s\n" "\n" msgid "" "\n" "%sTotal size: " msgstr "" "\n" "%sTamaño total: " msgid "" "\n" "%sTotal size: %s%s%s%s\n" msgstr "" "\n" "%sTamaño total: %s%s%s%s\n" msgid "" "\n" "%sUnmounted devices%s\n" "\n" msgstr "" "\n" "%sDispositivos sin montar%s\n" "\n" msgid "" "\n" "%sWorkspaces%s\n" "\n" msgstr "" "\n" "%sEspacios de trabajo%s\n" "\n" msgid "" "\n" "(%s1%s) Used only when ColorLinksAsTarget is enabled\n" msgstr "" "\n" "(%s1%s) Se utiliza solo cuando ColorLinksAsTarget está habilitado\n" msgid "" "\n" "Note: Bear in mind that clifm's keybindings take precedence over " "readline's.\n" "To modify readline's keybindings edit ~/.config/clifm/readline.clifm" msgstr "" "\n" "Nota: Ten en cuenta que las asignaciones de teclas de clifm tienen prioridad sobre las de readline.\n" "Para modificar las asignaciones de teclas de readline, edita ~/.config/clifm/readline.clifm" msgid "" "\n" "Ready to archive/compress selected files." msgstr "" "\n" "Listo para archivar/comprimir los archivos seleccionados." msgid "" "\n" "Ready to export selected filenames" msgstr "" "\n" "Listo para exportar los archivos seleccionados" msgid "" "\n" "The bracketed field is the code required to modify the color of the " "corresponding element in the color scheme file.\n" "\n" msgstr "" "\n" "El campo entre corchetes es el código requerido para modificar el color del elemento correspondiente en el archivo de esquema de colores.\n" "\n" msgid "" "\n" "Total rank: %d/%d\n" "Total visits: %d\n" msgstr "" "\n" "Clasificación total: %d/%d\n" "Visitas totales: %d\n" msgid "" "\n" "You can also edit 'settings.h' in the source code and recompile.\n" msgstr "" "\n" "También puedes editar 'settings.h' en el código fuente y recompilar.\n" msgid "" "\n" "jump: Purged %d %s\n" msgstr "" "\n" "jump: Purgado %d %s\n" msgid "" "\n" "jump: Purged %d invalid %s\n" msgstr "" "\n" "jump: Purgado %d %s inválido\n" msgid "" " (dd) Date (unset: using shades)\n" " " msgstr "" " (dd) Fecha (no establecida: usando sombreados)\n" " " msgid "" " (dz) Size (unset: using shades)\n" " " msgstr "" " (dz) Tamaño (no establecido: usando sombreados)\n" " " msgid " Block size: %s%d%s" msgstr " Tamaño de bloque: %s%d%s" msgid " Device type: %s%ju,%ju%s\n" msgstr " Tipo de dispositivo: %s%ju,%ju%s\n" msgid " Gid: %s%u (%s)%s" msgstr " Gid: %s%u (%s)%s" msgid " IO Block: %s%jd%s\n" msgstr " Bloque de E/S: %s%jd%s\n" msgid " Uid: %s%u (%s)%s" msgstr " Uid: %s%u (%s)%s" msgid " (not available in light mode: using %sname%s)\n" msgstr " (no disponible en modo ligero: usando %snombre%s)\n" msgid " (on LSCOLORS)" msgstr " (en LSCOLORS)" msgid " (on LS_COLORS)" msgstr " (en LS_COLORS)" msgid " (recursively)" msgstr " (de forma recursiva)" msgid " Auto-mount: %s\n" msgstr " Montaje automático: %s\n" msgid " Auto-unmount: %s\n" msgstr " Desmontaje automático: %s\n" msgid " Comment: %s\n" msgstr " Comentario: %s\n" msgid " Mount command: %s\n" msgstr " Comando de montaje: %s\n" msgid " Mounted: %s%s%s\n" msgstr " Montado: %s%s%s\n" msgid " Mountpoint: %s\n" msgstr " Punto de montaje: %s\n" msgid " Unmount command: %s\n" msgstr " Comando de desmontaje: %s\n" msgid "" "%d MIME association(s) imported from the system.\n" "File saved as '%s'\n" "Add these new associations to your mimelist file by running 'mm edit'.\n" msgstr "" "%d asociación(es) MIME importada(s) del sistema.\n" "Archivo guardado como '%s'\n" "Agrega estas nuevas asociaciones a tu archivo mimelist ejecutando 'mm edit'.\n" msgid "%d file(s) deselected\n" msgstr "%d archivo(s) deseleccionado(s)\n" msgid "%d file(s) selected\n" msgstr "%d archivo(s) seleccionado(s)\n" msgid "%d filename(s) bleached\n" msgstr "%d nombre(s) de archivo blanqueado(s)\n" msgid "%s %s (%s), by %s\n" msgstr "%s %s (%s), por %s\n" msgid "" "%s %s%s%s%s%s (%s)\n" "%s\n" "License %s\n" "Written by %s\n" msgstr "" "%s %s%s%s%s%s (%s)\n" "%s\n" "Licencia %s\n" "Escrito por %s\n" msgid "%s (error resolving link target)\n" msgstr "%s (error al resolver el objetivo del enlace)\n" msgid "" "%s A plus sign next rank values means that the corresponding directory is " "marked as permanent (it will not be removed).\n" msgstr "" "%s Un signo más junto a los valores de clasificación significa que el directorio correspondiente está marcado como permanente (no será eliminado).\n" msgid "" "%s An asterisk next rank values means that the corresponding directory will " "not be removed despite its rank, either because it was visited in the last " "24 hours, or because it is bookmarked, pinned, or currently active in some " "workspace.\n" msgstr "" "%s Un asterisco junto a los valores de clasificación significa que el directorio correspondiente no será eliminado a pesar de su clasificación, ya sea porque fue visitado en las últimas 24 horas, o porque está marcado como favorito, fijado o actualmente activo en algún espacio de trabajo.\n" msgid "" "%s Entries ranked below MinJumpRank (currently %d) will be removed at " "program exit.\n" msgstr "" "%s Las entradas con clasificación por debajo de MinJumpRank (actualmente %d) serán eliminadas al salir del programa.\n" msgid "" "%s First time access is displayed in days, while last time access is " "displayed in hours.\n" msgstr "" "%s La primera vez que se accede se muestra en días, mientras que la última vez en horas.\n" msgid "" "%s MinJumpRank is set to %d: entries will not be removed from the database " "(no matter their rank).\n" msgstr "" "%s MinJumpRank está establecido en %d: las entradas no serán eliminadas de la base de datos (sin importar su clasificación).\n" msgid "" "%s%s\n" "Enter '%c' to edit your bookmarks or '%c' to quit\n" "Choose a bookmark (by ELN, shortcut, or name):\n" msgstr "" "%s%s\n" "Introduzca '%c' para editar sus marcadores o '%c' para salir\n" "Elige un marcador (por ELN, atajo o nombre):\n" msgid "%s%s%s %s: Primary group set to %d (%s%s%s)\n" msgstr "%s%s%s %s: Grupo principal establecido en %d (%s%s%s)\n" msgid "%s%s%s %s: User set to %d (%s%s%s)\n" msgstr "%s%s%s %s: Usuario establecido en %d (%s%s%s)\n" msgid "%s%s%s (broken link)\n" msgstr "%s%s%s (enlace roto)\n" msgid "%s%s%s Running as root%s\n" msgstr "%s%s%s Ejecutando como root%s\n" msgid "%s%s%s is tagged as:\n" msgstr "%s%s%s está etiquetado como:\n" msgid "%s%s%s%s\n" msgstr "%s%s%s%s\n" msgid "%s%s%s: Succesfully mounted on %s\n" msgstr "%s%s%s: Montado con éxito en %s\n" msgid "%s%sColor%s (dg) Group ID (e.g. %s%swheel%s)\n" msgstr "%s%sColor%s (dg) ID de grupo (por ejemplo, %s%swheel%s)\n" msgid "%s%sColor%s (dt) Timestamp mark (e.g. %sMay 25 22:08%sm%s)\n" msgstr "%s%sColor%s (dt) Marca de timestamp (por ejemplo, %s25 de mayo 22:08%sm%s)\n" msgid "%s%sFile%s: %s\n" msgstr "%s%sArchivo%s: %s\n" msgid "%s%sSelection Box%s\n" msgstr "%s%sCaja de selección%s\n" msgid "" "%s%sTrashed files%s\n" "\n" msgstr "" "%s%sArchivos eliminados%s\n" "\n" msgid "%s/%s (%d%% free) %s %s\n" msgstr "%s/%s (%d%% libre) %s %s\n" msgid "%s: %d filenames(s) bleached\n" msgstr "%s: %d nombre(s) de archivo blanqueado(s)\n" msgid "%s: %d: Invalid ELN\n" msgstr "%s: %d: ELN no válido\n" msgid "%s: %s %s%s%s %s: Broken symbolic link\n" msgstr "%s: %s %s%s%s %s: Enlace simbólico roto\n" msgid "%s: %s failed to allocate %zux%zu bytes\n" msgstr "%s: %s no pudo asignar %zux%zu bytes\n" msgid "" "%s: %s.\n" "TIP: To edit the color scheme use the following environment variables: " "CLIFM_FILE_COLORS, CLIFM_IFACE_COLORS, and CLIFM_EXT_COLORS.\n" "Example:\n" "\n" "CLIFM_FILE_COLORS="di=31:ln=33:" CLIFM_IFACE_COLORS="el=35:fc=34:" " "CLIFM_EXT_COLORS=".c=1;33:.odt=4;35:" clifm\n" "\n" "Consult the manpage for more information.\n" msgstr "" "%s: %s.\n" "CONSEJO: Para editar el esquema de colores, use las siguientes variables de entorno: CLIFM_FILE_COLORS, CLIFM_IFACE_COLORS y CLIFM_EXT_COLORS.\n" "Ejemplo:\n" "\n" "CLIFM_FILE_COLORS="di=31:ln=33:" CLIFM_IFACE_COLORS="el=35:fc=34:" " "CLIFM_EXT_COLORS=".c=1;33:.odt=4;35:" clifm\n" "\n" "Consulte la página del manual para obtener más información.\n" msgid "" "%s: %s: %s\n" "Invalid authentication program (falling back to '%s')\n" msgstr "" "%s: %s: %s\n" "Programa de autenticación no válido (volviendo a '%s')\n" msgid "%s: %s: Cannot create tags directory. Tag function disabled\n" msgstr "%s: %s: No se puede crear el directorio de etiquetas. Función de etiquetas deshabilitada\n" msgid "%s: %s: Command not allowed in read-only mode\n" msgstr "%s: %s: Comando no permitido en modo de solo lectura\n" msgid "%s: %s: Invalid number\n" msgstr "%s: %s: Número no válido\n" msgid "%s: %s: No such ELN\n" msgstr "%s: %s: No existe ELN\n" msgid "" "%s: %s: Using a temporary directory for the Selection Box. Selected files " "will not be persistent across reboots.\n" msgstr "" "%s: %s: Se está utilizando un directorio temporal para la Caja de selección. Los archivos seleccionados no serán persistentes entre reinicios.\n" msgid "" "%s: '%c': Invalid file type filter. Run 'help file-filters' for more " "information\n" msgstr "" "%s: '%c': Filtro de tipo de archivo no válido. Ejecute 'help file-filters' para obtener más información\n" msgid "" "%s: '%s' (%s): Cannot open file\n" "Try 'APP FILE' or 'open FILE APP'\n" msgstr "" "%s: '%s' (%s): No se puede abrir el archivo\n" "Intente 'APP ARCHIVO' o 'open ARCHIVO APP'\n" msgid "%s: '%s' is not a shell. Setting SHELL to '%s'.\n" msgstr "%s: '%s' no es una shell. Estableciendo SHELL en '%s'.\n" msgid "" "%s: '%s': %s\n" "Falling back to the default configuration directory\n" msgstr "" "%s: '%s': %s\n" "Volviendo al directorio de configuración predeterminado\n" msgid "" "%s: '%s': %s.\n" "Cannot create temporary directory. Falling back to '%s'.\n" msgstr "" "%s: '%s': %s.\n" "No se puede crear el directorio temporal. Volviendo a '%s'.\n" msgid "" "%s: '%s': %s.\n" "Cannot validate shell. Falling back to '%s'.\n" msgstr "" "%s: '%s': %s.\n" "No se puede validar la shell. Volviendo a '%s'.\n" msgid "" "%s: '%s': %s. Trash function disabled. If needed, create the directories " "manually and restart %s.\n" "E.g.: mkdir -p ~/.local/share/Trash/{files,info}\n" msgstr "" "%s: '%s': %s. Función de papelera deshabilitada. Si es necesario, cree los directorios manualmente y reinicie %s.\n" "Ej.: mkdir -p ~/.local/share/Trash/{files,info}\n" msgid "%s: '%s': %s. Using default values.\n" msgstr "%s: '%s': %s. Utilizando valores predeterminados.\n" msgid "%s: '%s': Absolute path is required as argument\n" msgstr "%s: '%s': Se requiere la ruta absoluta como argumento\n" msgid "" "%s: '%s': Cannot create the trash directory (or one of its subdirectories: " "'files' and 'info').\n" "Try creating them manually and restart %s.\n" "E.g.: mkdir -p ~/.local/share/Trash/{files,info}\n" msgstr "" "%s: '%s': No se puede crear el directorio Trash (o uno de sus subdirectorios: 'files' y 'info').\n" "Intente crearlos manualmente y reinicie %s.\n" "Ej.: mkdir -p ~/.local/share/Trash/{files,info}\n" msgid "%s: '%s': Cannot escape filename\n" msgstr "%s: '%s': No se puede escapar el nombre del archivo\n" msgid "" "%s: '%s': Directory not writable. Bookmarks, commands logs, and commands " "history are disabled. Program messages will not be persistent. Falling back " "to default settings.\n" msgstr "" "%s: '%s': El directorio no es editable. Los marcadores, registros de comandos y el historial de comandos están deshabilitados. Los mensajes del programa no serán persistentes. Volviendo a la configuración predeterminada.\n" msgid "%s: '%s': Error expanding tilde\n" msgstr "%s: '%s': Error al expandir el tilde\n" msgid "%s: '%s': Error quoting filename\n" msgstr "%s: '%s': Error al citar el nombre del archivo\n" msgid "%s: '%s': Error reading file\n" msgstr "%s: '%s': Error al leer el archivo\n" msgid "%s: '%s': Error saving directory entry: %s\n" msgstr "%s: '%s': Error al guardar la entrada del directorio: %s\n" msgid "%s: '%s': Error setting custom selections file\n" msgstr "%s: '%s': Error al establecer el archivo de selecciones personalizado\n" msgid "%s: '%s': Error unescaping filename\n" msgstr "%s: '%s': Error al desescapar el nombre del archivo\n" msgid "%s: '%s': Error unescaping string\n" msgstr "%s: '%s': Error al desescapar el texto\n" msgid "%s: '%s': File changed on disk!\n" msgstr "%s: '%s': ¡El archivo ha cambiado en el disco!\n" msgid "" "%s: '%s': Home directory not found\n" "Falling back to '%s'\n" msgstr "" "%s: '%s': No se encontró el directorio principal\n" "Volviendo a '%s'\n" msgid "%s: '%s': Invalid argument. Try 'fz -h'\n" msgstr "%s: '%s': Argumento no válido. Intente 'fz -h'\n" msgid "" "%s: '%s': Invalid bell style. Valid values are 0:none, 1:audible, 2:visible " "(requires readline >= 8.1), 3:flash. Defaults to 'visible', and, if not " "possible, 'none'.\n" msgstr "" "%s: '%s': Estilo de timbre no válido. Los valores válidos son 0:none, 1:audible, 2:visible (requiere readline >= 8.1), 3:flash. Por defecto, 'visible', y si no es posible, 'none'.\n" msgid "%s: '%s': Invalid fuzzy algorithm. Valid values are either 1 or 2.\n" msgstr "%s: '%s': Algoritmo difuso no válido. Los valores válidos son 1 o 2.\n" msgid "" "%s: '%s': Invalid home directory in the password database.\n" "Something is really wrong! Exiting.\n" msgstr "" "%s: '%s': Directorio principal no válido en la base de datos de contraseñas.\n" "¡Algo está realmente mal! Saliendo.\n" msgid "%s: '%s': Invalid profile name\n" msgstr "%s: '%s': Nombre de perfil no válido\n" msgid "%s: '%s': Invalid regular expression\n" msgstr "%s: '%s': Expresión regular no válida\n" msgid "" "%s: '%s': Invalid shell. Falling back to '%s'.\n" "Check '%s' for a list of valid shells.\n" msgstr "" "%s: '%s': Shell no válida. Volviendo a '%s'.\n" "Verifique '%s' para obtener una lista de shells válidas.\n" msgid "%s: '%s': Invalid workspace. Valid values are 1-8.\n" msgstr "%s: '%s': Espacio de trabajo no válido. Los valores válidos son 1-8.\n" msgid "%s: '%s': No associated application found\n" msgstr "%s: '%s': No se encontró aplicación asociada\n" msgid "" "%s: '%s': No associated application found\n" "Fix this in the configuration file:\n" "%s\n" "(run 'view edit' if running %s)\n" msgstr "" "%s: '%s': No se encontró aplicación asociada\n" "Corrija esto en el archivo de configuración:\n" "%s\n" "(ejecute 'view edit' si está ejecutando %s)\n" msgid "%s: '%s': No such alias\n" msgstr "%s: '%s': No existe el alias\n" msgid "%s: '%s': No such selected file\n" msgstr "%s: '%s': No existe tal archivo seleccionado\n" msgid "%s: '%s': Not a directory\n" msgstr "%s: '%s': No es un directorio\n" msgid "" "%s: '%s': Only command base names are allowed. E.g.: 'nano' instead of '/usr/" "bin/nano'\n" msgstr "" "%s: '%s': Solo se permiten nombres base de comandos. Por ejemplo: 'nano' en lugar de '/usr/bin/nano'\n" msgid "" "%s: '%s': Option requires an argument\n" "Try '%s %s' for more information.\n" msgstr "" "%s: '%s': La opción requiere un argumento\n" "Intente '%s %s' para obtener más información.\n" msgid "%s: '%s': Syntax error\n" msgstr "%s: '%s': Error de sintaxis\n" msgid "" "%s: '%s': Terminal type not supported. Limited functionality is expected.\n" msgstr "" "%s: '%s': El tipo de terminal no es compatible. Se espera una funcionalidad limitada.\n" msgid "" "%s: '%s': Unrecognized option\n" "Try '%s --help' for more information.\n" msgstr "" "%s: '%s': Opción no reconocida\n" "Intente '%s --help' para obtener más información.\n" msgid "%s: '%s': Unsafe filename\n" msgstr "%s: '%s': Nombre de archivo no seguro\n" msgid "%s: '%s': Using an alternative configuration directory\n" msgstr "%s: '%s': Utilizando un directorio de configuración alternativo\n" msgid "%s: '%s': Valid values are 0-3\n" msgstr "%s: '%s': Los valores válidos son 0-3\n" msgid "" "%s: '%zu': Invalid workspace.\n" "Falling back to workspace %zu.\n" msgstr "" "%s: '%zu': Espacio de trabajo no válido.\n" "Volviendo al espacio de trabajo %zu.\n" msgid "" "%s: '--desktop-notifications': Valid values are 'kitty','system', or " "'false'.\n" msgstr "" "%s: '--desktop-notifications': Los valores válidos son 'kitty', 'system' o 'false'.\n" msgid "" "%s: '--show-hidden': Valid values are 'true','first', 'last', or 'false'.\n" msgstr "" "%s: '--show-hidden': Los valores válidos son 'true', 'first', 'last' o 'false'.\n" msgid "" "%s: '--stat': Option requires an argument\n" "Try '%s --help' for more information.\n" msgstr "" "%s: '--stat': La opción requiere un argumento\n" "Intente '%s --help' para obtener más información.\n" msgid "%s: '-a': Valid values are 'true','first', 'last', or 'false'.\n" msgstr "%s: '-a': Los valores válidos son 'true', 'first', 'last' o 'false'.\n" msgid "" "%s: --fzytab: We have migrated to 'fnf'.\n" "Install 'fnf' (https://github.com/leo-arch/fnf) and then use --fnftab " "instead.\n" msgstr "" "%s: --fzytab: Hemos migrado a 'fnf'.\n" "Instale 'fnf' (https://github.com/leo-arch/fnf) y luego utilice --fnftab en su lugar.\n" msgid "" "%s: --pager-view: '%s': Invalid value.\n" "Valid values are 'auto', 'long', and 'short'.\n" msgstr "" "%s: --pager-view: '%s': Valor no válido.\n" "Los valores válidos son 'auto', 'long' y 'short'. msgid "%s: --prop-fields: 'b': Birth time is not available on this platform\n" msgstr "%s: --prop-fields: 'b': La hora de creación no está disponible en esta plataforma\n" msgid "" "%s: --sort: '%s': Invalid value\n" "Valid values: atime, btime, ctime, mtime, extension, group, inode, name,\n" " none, owner, size, version, blocks, links, type.\n" msgstr "" "%s: --sort: '%s': Valor no válido\n" "Valores válidos: atime, btime, ctime, mtime, extension, group, inode, name,\n" " none, owner, size, version, blocks, links, type.\n" msgid "%s: --sort: '%s': Valid values are 0-%d\n" msgstr "%s: --sort: '%s': Los valores válidos son 0-%d\n" msgid "" "%s: An input file must be provided via the CLIFM_TEST_INPUT_FILE environment " "variable\n" msgstr "" "%s: Debe proporcionar un archivo de entrada a través de la variable de entorno CLIFM_TEST_INPUT_FILE\n" msgid "%s: Bookmarks function disabled\n" msgstr "%s: Función de marcadores deshabilitada\n" msgid "%s: Cannot access the configuration file\n" msgstr "%s: No se puede acceder al archivo de configuración\n" msgid "" "%s: Cannot access the home directory. Bookmarks, commands logs, and commands " "history are disabled. Program messages, selected files, and the jump " "database will not be persistent. Using default settings.\n" msgstr "" "%s: No se puede acceder al directorio principal. Los marcadores, registros de comandos y el historial de comandos están deshabilitados. Los mensajes del programa, los archivos seleccionados y la base de datos de saltos no serán persistentes. Utilizando la configuración predeterminada.\n" msgid "" "%s: Cannot create colors directory '%s': Falling back to the default color " "scheme\n" msgstr "" "%s: No se puede crear el directorio de colores '%s': Volviendo al esquema de colores predeterminado\n" msgid "" "%s: Cannot create configuration directory '%s': Bookmarks, commands logs, " "and command history are disabled. Program messages will not be persistent. " "Falling back to default settings.\n" msgstr "" "%s: No se puede crear el directorio de configuración '%s': Los marcadores, registros de comandos y el historial de comandos están deshabilitados. Los mensajes del programa no serán persistentes. Volviendo a la configuración predeterminada.\n" msgid "" "%s: Cannot create directory '%s' (error %d)\n" "Falling back to the default configuration directory.\n" msgstr "" "%s: No se puede crear el directorio '%s' (error %d)\n" "Volviendo al directorio de configuración predeterminado.\n" msgid "" "%s: Cannot create plugins directory '%s': The actions function is disabled\n" msgstr "" "%s: No se puede crear el directorio de plugins '%s': La función de acciones está deshabilitada\n" msgid "%s: Cannot create temporary directory. Falling back to '%s'.\n" msgstr "%s: No se puede crear el directorio temporal. Volviendo a '%s'.\n" msgid "%s: Cannot retrieve the home directory\n" msgstr "%s: No se puede determinar el directorio principal\n" msgid "%s: Colors are disabled\n" msgstr "%s: Los colores están deshabilitados\n" msgid "%s: Currently running without colors\n" msgstr "%s: Se está ejecutando sin colores\n" msgid "" "%s: Default terminal not set. Use the configuration file (F10) to set it.\n" msgstr "" "%s: La terminal predeterminada no está establecida. Utilice el archivo de configuración (F10) para establecerla.\n" msgid "%s: Directory history cleared\n" msgstr "%s: Historial de directorios borrado\n" msgid "%s: Directory jumper function disabled\n" msgstr "%s: Función de salto de directorios deshabilitada\n" msgid "%s: Empty filenames buffer. Nothing to do\n" msgstr "%s: Buffer de nombres de archivos vacío. No hay nada que hacer\n" msgid "%s: Error dropping group privileges. Aborting.\n" msgstr "%s: Error al descartar privilegios de grupo. Abortando.\n" msgid "%s: Error dropping user privileges. Aborting.\n" msgstr "%s: Error al descartar privilegios de usuario. Abortando.\n" msgid "%s: Error expanding tilde. Using default opener.\n" msgstr "%s: Error al expandir el tilde. Utilizando el abridor predeterminado.\n" msgid "%s: Error getting MIME type\n" msgstr "%s: Error al obtener el tipo MIME\n" msgid "%s: Error getting current directory\n" msgstr "%s: Error al obtener el directorio actual\n" msgid "%s: Error getting file descriptor for the current directory: %s\n" msgstr "%s: Error al obtener el descriptor de archivo para el directorio actual: %s\n" msgid "%s: Error getting home directory\n" msgstr "%s: Error al obtener el directorio principal\n" msgid "%s: Error getting hostname\n" msgstr "%s: Error al obtener el nombre del host\n" msgid "%s: Error getting the current working directory\n" msgstr "%s: Error al obtener el directorio de trabajo actual\n" msgid "%s: Error getting variable value\n" msgstr "%s: Error al obtener el valor de la variable\n" msgid "%s: Error retrieving mountpoint\n" msgstr "%s: Error al recuperar el punto de montaje\n" msgid "%s: Error saving last visited directory: %s\n" msgstr "%s: Error al guardar el último directorio visitado: %s\n" msgid "" "%s: Escape sequence detected in the warning prompt string: this might cause " "a few glichtes in the prompt due to some bugs in the current readline " "library (%s). Please consider removing these escape sequences (via either " "'prompt edit' or 'cs edit') or upgrading to a newer version of the library " "(>= 7.0 is recommended).\n" msgstr "" "%s: Secuencia de escape detectada en la cadena del prompt de advertencia: esto podría causar algunos errores en el prompt debido a algunos errores en la biblioteca readline actual (%s). Por favor, considere eliminar estas secuencias de escape (mediante 'prompt edit' o 'cs edit') o actualizar a una versión más nueva de la biblioteca (>= 7.0 se recomienda).\n" msgid "" "%s: External commands are currently disabled. To enable them, run 'ext on'.\n" msgstr "" "%s: Los comandos externos están deshabilitados. Para habilitarlos, ejecute 'ext on'.\n" msgid "%s: Fatal error! Failure retrieving the current working directory\n" msgstr "%s: ¡Error fatal! No se pudo recuperar el directorio de trabajo actual\n" msgid "%s: Fatal error! Failure retrieving the current working directory.\n" msgstr "%s: ¡Error fatal! No se pudo recuperar el directorio de trabajo actual.\n" msgid "" "%s: File extension conflicts found. Run 'cs check-ext' to see the details.\n" msgstr "" "%s: Se encontraron conflictos de extensiones de archivo. Ejecute 'cs check-ext' para ver los detalles.\n" msgid "%s: File may be unsafe\n" msgstr "%s: El archivo puede ser inseguro\n" msgid "%s: Function only available for graphical environments\n" msgstr "%s: La función solo está disponible para entornos gráficos\n" msgid "" "%s: Fzf failed. Check the FzfTabOptions line by running 'cs edit'\n" "(some option may not be supported by your fzf version).\n" msgstr "" "%s: Fzf falló. Verifique la línea FzfTabOptions ejecutando 'cs edit'\n" "(algunas opciones pueden no ser compatibles con su versión de fzf).\n" msgid "" "%s: FzfTabOptions contains unsafe characters (<>|;&$`). Falling back to " "default values.\n" msgstr "" "%s: FzfTabOptions contiene caracteres no seguros (<>|;&$`). Utilizando los valores predeterminados.\n" msgid "%s: History function disabled\n" msgstr "%s: La función de historial está deshabilitada\n" msgid "" "%s: Home directory not found.\n" "Something is really wrong! Exiting.\n" msgstr "" "%s: No se encontró el directorio principal.\n" "¡Algo está realmente mal! Salir.\n" msgid "%s: Integer overflow detected (showing only %jd files)\n" msgstr "%s: Se detectó un desbordamiento de enteros (mostrando solo %jd archivos)\n" msgid "" "%s: Invalid sort value: only none, name, extension, version, and inode are " "allowed in light mode\n" msgstr "" "%s: Valor de clasificación no válido: solo none, name, extension, version y inode están permitidos en modo ligero\n" msgid "%s: Is a symbolic link\n" msgstr "%s: Es un enlace simbólico\n" msgid "%s: Is not a regular file\n" msgstr "%s: No es un archivo regular\n" msgid "%s: Light mode is not supported in virtual directories\n" msgstr "%s: El modo ligero no es compatible con directorios virtuales\n" msgid "" "%s: Locale is not UTF-8. To avoid encoding issues you might want to set an " "UTF-8 locale. For example: export LANG=es_AR.UTF-8\n" msgstr "" "%s: La configuración regional no es UTF-8. Para evitar problemas de codificación, es posible que desee establecer una configuración regional UTF-8. Por ejemplo: export LANG=es_AR.UTF-8\n" msgid "%s: Log function disabled\n" msgstr "%s: La función de registro está deshabilitada\n" msgid "" "%s: MaxPath: This option is deprecated. Use the CLIFM_PROMPT_P_MAX_PATH " "environment variable instead.\n" msgstr "" "%s: MaxPath: Esta opción está en desuso. Utilice la variable de entorno CLIFM_PROMPT_P_MAX_PATH en su lugar.\n" msgid "" "%s: MinFilenameTrim: This option is deprecated. Use MinNameTruncate " "instead.\n" msgstr "" "%s: MinFilenameTrim: Esta opción está en desuso. Utilice MinNameTruncate en su lugar.\n" msgid "%s: Missing '%c'\n" msgstr "%s: Falta '%c'\n" msgid "%s: Missing closing quote: '%c'\n" msgstr "%s: Falta comilla de cierre: '%c'\n" msgid "%s: Nested instances are not allowed in stealth mode\n" msgstr "%s: Las instancias anidadas no están permitidas en modo sigilo\n" msgid "%s: No aliases found\n" msgstr "%s: No se encontraron aliases\n" msgid "" "%s: No data directory found. Data files, such as plugins and color schemes, " "may not be available.\n" "Set a custom data directory via the '--data-dir' option.\n" msgstr "" "%s: No se encontró el directorio de datos. Los archivos de datos, como plugins y esquemas de color, " "pueden no estar disponibles.\n" "Establezca un directorio de datos personalizado a través de la opción '--data-dir'.\n" msgid "%s: No messages\n" msgstr "%s: No hay mensajes\n" msgid "%s: No mount application found. Install either udevil or udisks2\n" msgstr "%s: No se encontró la aplicación de montaje. Instale udevil o udisks2\n" msgid "" "%s: No opening application found\n" "Tip: Run 'APP FILE', or 'mm edit' to add an opening application\n" msgstr "" "%s: No se encontró ninguna aplicación de apertura\n" "Tip: Ejecute 'APP FILE' o 'mm edit' para agregar una aplicación de apertura\n" msgid "%s: No pinned file\n" msgstr "%s: No hay archivo fijado\n" msgid "%s: No remotes defined. Run 'net edit' to add one.\n" msgstr "%s: No se han definido remotos. Ejecute 'net edit' para agregar uno.\n" msgid "%s: No such ELN\n" msgstr "%s: No existe ese ELN\n" msgid "%s: No tags found. Use 'tag new' to create new tags.\n" msgstr "%s: No se encontraron etiquetas. Use 'tag new' para crear nuevas etiquetas.\n" msgid "%s: Nothing to do\n" msgstr "%s: Nada que hacer\n" msgid "%s: Nothing was imported. No MIME association found\n" msgstr "%s: No se importó nada. No se encontró asociación MIME\n" msgid "%s: Nothing was imported. No graphical environment found\n" msgstr "%s: No se importó nada. No se encontró entorno gráfico\n" msgid "" "%s: Notification daemon error: %s\n" "Disable desktop notifications (run 'help desktop-notifications' for details) " "or %s to silence this warning (original message printed below)\n" msgstr "" "%s: Error en el daemon de notificaciones: %s\n" "Deshabilite las notificaciones de escritorio (ejecute 'help desktop-notifications' para más detalles) " "o %s para silenciar esta advertencia (mensaje original impreso a continuación)\n" msgid "" "%s: Option '-%c' requires an argument.\n" "Try '%s -h' for more information.\n" msgstr "" "%s: La opción '-%c' requiere un argumento.\n" "Intente '%s -h' para más información.\n" msgid "%s: Plugins are not allowed in secure-cmds mode\n" msgstr "%s: Los plugins no están permitidos en modo secure-cmds\n" msgid "%s: Prompts successfully reloaded\n" msgstr "%s: Prompts recargados con éxito\n" msgid "%s: PropFields: 'b': Birth time is not allowed in light mode\n" msgstr "%s: PropFields: 'b': La hora de creación no está permitida en modo ligero\n" msgid "" "%s: Running in stealth mode. Access to configuration files is not allowed.\n" msgstr "" "%s: Ejecutando en modo sigilo. No se permite el acceso a los archivos de configuración.\n" msgid "" "%s: Running in stealth mode: persistent selection, bookmarks, jump database " "and directory history, just as plugins, logs and configuration files, are " "disabled.\n" msgstr "" "%s: Ejecutando en modo sigilo: la selección persistente, los favoritos, la base de datos de saltos " "y el historial de directorios, al igual que los plugins, los registros y los archivos de configuración, están deshabilitados.\n" msgid "%s: Successfully created tag\n" msgstr "%s: Etiqueta creada con éxito\n" msgid "%s: TERM variable unset. Running in xterm compatibility mode.\n" msgstr "%s: La variable TERM no está establecida. Ejecutando en modo de compatibilidad con xterm.\n" msgid "" "%s: The 'dh' plugin is deprecated. Use the builtin 'dh' command instead " "disabling the 'dh' plugin ('actions edit'). Once done, run 'dh --help' for " "more information about the new command.\n" msgstr "" "%s: El plugin 'dh' está en desuso. Use el comando 'dh' integrado en su lugar " "deshabilitando el plugin 'dh' ('actions edit'). Una vez hecho, ejecute 'dh --help' para más información sobre el nuevo comando.\n" msgid "%s: There are no available %s\n" msgstr "%s: No hay %s disponibles\n" msgid "%s: There is another name hard linked to this file\n" msgstr "%s: Hay otro nombre enlazado a este archivo\n" msgid "%s: This feature is not available on Haiku\n" msgstr "%s: Esta función no está disponible en Haiku\n" msgid "%s: To gracefully quit enter 'q'\n" msgstr "%s: Para salir correctamente, ingrese 'q'\n" msgid "%s: Trash function disabled\n" msgstr "%s: La función de papelera de reciclaje está deshabilitada\n" msgid "%s: TrimNames: This option is deprecated. Use TruncateNames instead.\n" msgstr "%s: TrimNames: Esta opción está en desuso. Use TruncateNames en su lugar.\n" msgid "%s: Unmounted %s\n" msgstr "%s: Desmontado %s\n" msgid "" "%s: Unrecognized option: '-%c'\n" "Try '%s -h' for more information.\n" msgstr "" "%s: Opción no reconocida: '-%c'\n" "Intente '%s -h' para más información.\n" msgid "%s: br: Feature not allowed in virtual directories\n" msgstr "%s: br: La función no está permitida en directorios virtuales\n" msgid "%s: cd-on-quit: Cannot create symbolic link '%s': %s\n" msgstr "%s: cd-on-quit: No se puede crear el enlace simbólico '%s': %s\n" msgid "%s: cd: '%s': Is a directory\n" msgstr "%s: cd: '%s': Es un directorio\n" msgid "" "%s: chdir: '%s': %s. Using the current working directory as starting path\n" msgstr "" "%s: chdir: '%s': %s. Utilizando el directorio de trabajo actual como ruta de inicio\n" msgid "%s: colors: %s: No such color scheme. Falling back to default\n" msgstr "%s: colors: %s: No existe este esquema de color. Volviendo al predeterminado\n" msgid "%s: colors: '%s': No such color scheme. Falling back to default\n" msgstr "%s: colors: '%s': No existe este esquema de color. Volviendo al predeterminado\n" msgid "" "%s: fnf: Command not found. Falling back to the default value (fzf, if " "found, or standard)\n" msgstr "" "%s: fnf: Comando no encontrado. Volviendo al valor predeterminado (fzf, si se encuentra, o standard)\n" msgid "%s: fzf: Command not found. Falling back to standard tab completion\n" msgstr "%s: fzf: Comando no encontrado. Volviendo al autocompletado estándar\n" msgid "%s: history: %s\n" msgstr "%s: historial: %s\n" msgid "%s: icons: %s\n" msgstr "%s: iconos: %s\n" msgid "%s: net: %s: Mounting remote...\n" msgstr "%s: net: %s: Montando remoto...\n" msgid "%s: net: %s: Unmount command failed with error code %d\n" msgstr "%s: net: %s: El comando de desmontaje falló con el código de error %d\n" msgid "%s: net: %s: Unmounting remote...\n" msgstr "%s: net: %s: Desmontando remoto...\n" msgid "%s: rr: Feature not allowed in virtual directories\n" msgstr "%s: rr: La función no está permitida en directorios virtuales\n" msgid "" "%s: smenu: Command not found. Falling back to the default value (fzf, if " "found, or standard)\n" msgstr "" "%s: smenu: Comando no encontrado. Volviendo al valor predeterminado (fzf, si se encuentra, o standard)\n" msgid "%s: trash: %s\n" msgstr "%s: papelera: %s\n" msgid "%s: udisks2: Command not found. Falling back to udevil\n" msgstr "%s: udisks2: Comando no encontrado. Volviendo a udevil\n" msgid "" "%sBookmark Manager%s\n" "\n" msgstr "" "%sAdministrador de marcadores%s\n" "\n" msgid "" "%sColor scheme: %s%s%s\n" "\n" msgstr "" "%sEsquema de color: %s%s%s\n" "\n" msgid "%sColor%s (ac) Autocommand indicator (%sA%s)\n" msgstr "%sColor%s (ac) Indicador de autocomando (%sA%s)\n" msgid "%sColor%s (bd) Block device\n" msgstr "%sColor%s (bd) Dispositivo de bloque\n" msgid "%sColor%s (ca) File with capabilities\n" msgstr "%sColor%s (ca) Archivo con capacidades\n" msgid "%sColor%s (cd) Character device\n" msgstr "%sColor%s (cd) Dispositivo de caracter\n" msgid "%sColor%s (db) Used blocks (e.g. %s1576%s)\n" msgstr "%sColor%s (db) Bloques utilizados (p. ej. %s1576%s)\n" msgid "%sColor%s (dd) Date (e.g. %sJul 9 08:12%s)\n" msgstr "%sColor%s (dd) Fecha (p. ej. %sJul 9 08:12%s)\n" msgid "%sColor%s (de) Inode number (e.g. %s802721%s)\n" msgstr "%sColor%s (de) Número de inodo (p. ej. %s802721%s)\n" msgid "%sColor%s (df) Default color\n" msgstr "%sColor%s (df) Color predeterminado\n" msgid "%sColor%s (di) Directory\n" msgstr "%sColor%s (di) Directorio\n" msgid "%sColor%s (dk) Links number (e.g. %s92%s)\n" msgstr "%sColor%s (dk) Número de enlaces (p. ej. %s92%s)\n" msgid "%sColor%s (dl) Dividing line (e.g. %s------>%s)\n" msgstr "%sColor%s (dl) Línea divisoria (p. ej. %s------>%s)\n" msgid "%sColor%s (dn) Dot/dash (e.g. %sr%sw%s-.%sr%s--.--%s)\n" msgstr "%sColor%s (dn) Punto/guion (p. ej. %sr%sw%s-.%sr%s--.--%s)\n" msgid "%sColor%s (do) Octal permissions (e.g. %s0640%s)\n" msgstr "%sColor%s (do) Permisos octales (p. ej. %s0640%s)\n" msgid "%sColor%s (dp) SUID/SGID bit (e.g. %ss%s)\n" msgstr "%sColor%s (dp) Bit SUID/SGID (p. ej. %ss%s)\n" msgid "%sColor%s (dr) Read bit (%sr%s)\n" msgstr "%sColor%s (dr) Bit de lectura (%sr%s)\n" msgid "%sColor%s (du) User ID (e.g. %sjane%s)\n" msgstr "%sColor%s (du) ID de usuario (p. ej. %sjane%s)\n" msgid "%sColor%s (dw) Write bit (%sw%s)\n" msgstr "%sColor%s (dw) Bit de escritura (%sw%s)\n" msgid "%sColor%s (dxd) Execute bit - directory (%sx%s)\n" msgstr "%sColor%s (dxd) Bit de ejecución - directorio (%sx%s)\n" msgid "%sColor%s (dxr) Execute bit - file (%sx%s)\n" msgstr "%sColor%s (dxr) Bit de ejecución - archivo (%sx%s)\n" msgid "%sColor%s (dz) Size (e.g. %s12.69k%s)\n" msgstr "%sColor%s (dz) Tamaño (p. ej. %s12.69k%s)\n" msgid "%sColor%s (ed) Empty directory\n" msgstr "%sColor%s (ed) Directorio vacío\n" msgid "%sColor%s (ee) Empty executable file\n" msgstr "%sColor%s (ee) Archivo ejecutable vacío\n" msgid "%sColor%s (ef) Empty file\n" msgstr "%sColor%s (ef) Archivo vacío\n" msgid "%sColor%s (el) ELN's (e.g. %s12%s filename)\n" msgstr "%sColor%s (el) ELN (p. ej. %s12%s nombre de archivo)\n" msgid "%sColor%s (em) Error message indicator (%sE%s)\n" msgstr "%sColor%s (em) Indicador de mensaje de error (%sE%s)\n" msgid "%sColor%s (ex) Executable file\n" msgstr "%sColor%s (ex) Archivo ejecutable\n" msgid "%sColor%s (fc) File counter (e.g. dir%s/24%s)\n" msgstr "%sColor%s (fc) Contador de archivos (p. ej. dir%s/24%s)\n" msgid "%sColor%s (fi) Regular file\n" msgstr "%sColor%s (fi) Archivo regular\n" msgid "%sColor%s (hb) Brackets: %s(){}[]%s\n" msgstr "%sColor%s (hb) Corchetes: %s(){}[]%s\n" msgid "%sColor%s (hc) Commented out text (e.g. some text %s#comment%s)\n" msgstr "%sColor%s (hc) Texto comentado (p. ej. some text %s#comment%s)\n" msgid "%sColor%s (hd) Slash (e.g. dir%s/%sfile)\n" msgstr "%sColor%s (hd) Barra (p. ej. dir%s/%sarchivo)\n" msgid "%sColor%s (he) Expansion characters: %s~%s\n" msgstr "%sColor%s (he) Caracteres de expansión: %s~%s\n" msgid "%sColor%s (hn) Number (e.g. pp %s12%s)\n" msgstr "%sColor%s (hn) Número (p. ej. pp %s12%s)\n" msgid "%sColor%s (hp) Command parameter (e.g. cmd %s--param%s)\n" msgstr "%sColor%s (hp) Parámetro de comando (p. ej. cmd %s--param%s)\n" msgid "%sColor%s (hq) Quoted text (e.g. %s"some text"%s)\n" msgstr "%sColor%s (hq) Texto entre comillas (p. ej. %s"some text"%s)\n" msgid "%sColor%s (hr) Redirection characters: %s><%s\n" msgstr "%sColor%s (hr) Caracteres de redirección: %s><%s\n" msgid "%sColor%s (hs) Process separator characters: %s|;&%s \n" msgstr "%sColor%s (hs) Caracteres de separación de procesos: %s|;&%s \n" msgid "%sColor%s (hw) Backslash (e.g. sel this%s\%s file%s\%s name)\n" msgstr "%sColor%s (hw) Barra invertida (p. ej. sel this%s\%s archivo%s\%s nombre)\n" msgid "" "%sColor%s (lc) Symbolic link indicator (e.g. %s36%s%s%s%ssymlink) (%s1%s)\n" msgstr "" "%sColor%s (lc) Indicador de enlace simbólico (p. ej. %s36%s%s%s%senlace simbólico) (%s1%s)\n" msgid "%sColor%s (li) Selected file indicator (e.g. %s12%s%s%s%sfilename)\n" msgstr "%sColor%s (li) Indicador de archivo seleccionado (p. ej. %s12%s%s%s%snombre de archivo)\n" msgid "%sColor%s (li) Selected files indicator (%s%c%s)\n" msgstr "%sColor%s (li) Indicador de archivos seleccionados (%s%c%s)\n" msgid "%sColor%s (ln) Symbolic link\n" msgstr "%sColor%s (ln) Enlace simbólico\n" msgid "%sColor%s (mh) Multi-hardlink\n" msgstr "%sColor%s (mh) Multi-enlace\n" msgid "%sColor%s (mi) Miscellaneous indicator (%s%s%s) (%s2%s)\n" msgstr "%sColor%s (mi) Indicador misceláneo (%s%s%s) (%s2%s)\n" msgid "%sColor%s (nd) Directory with no read/exec permission\n" msgstr "%sColor%s (nd) Directorio sin permiso de lectura/ejecución\n" msgid "%sColor%s (nf) File with no read permission\n" msgstr "%sColor%s (nf) Archivo sin permiso de lectura\n" msgid "%sColor%s (nm) Notice message indicator (%sN%s)\n" msgstr "%sColor%s (nm) Indicador de mensaje de notificación (%sN%s)\n" msgid "%sColor%s (no) Unknown file type\n" msgstr "%sColor%s (no) Tipo de archivo desconocido\n" msgid "%sColor%s (oo) Door/Port file\n" msgstr "%sColor%s (oo) Archivo de puerta/puerto\n" msgid "%sColor%s (or) Broken symbolic link\n" msgstr "%sColor%s (or) Enlace simbólico roto\n" msgid "%sColor%s (ow) Other-writable and NOT sticky directory\n" msgstr "%sColor%s (ow) Directorio editable por otros y NO sticky\n" msgid "%sColor%s (pi) Pipe or FIFO special file\n" msgstr "%sColor%s (pi) Archivo especial de tubería o FIFO\n" msgid "%sColor%s (ro) Read-only mode indicator (%sRO%s)\n" msgstr "%sColor%s (ro) Indicador de modo de solo lectura (%sRO%s)\n" msgid "%sColor%s (sg) SGID file\n" msgstr "%sColor%s (sg) Archivo SGID\n" msgid "%sColor%s (si) Stealth mode indicator (%sS%s)\n" msgstr "%sColor%s (si) Indicador de modo sigilo (%sS%s)\n" msgid "%sColor%s (so) Socket file\n" msgstr "%sColor%s (so) Archivo de socket\n" msgid "%sColor%s (st) Sticky and NOT other-writable directory\n" msgstr "%sColor%s (st) Directorio sticky y NO editable por otros\n" msgid "%sColor%s (su) SUID file\n" msgstr "%sColor%s (su) Archivo SUID\n" msgid "%sColor%s (ti) Trashed files indicator (%sT%s)\n" msgstr "%sColor%s (ti) Indicador de archivos eliminados (%sT%s)\n" msgid "%sColor%s (ts) Matching completion prefix (e.g. %sfile%sname) (%s3%s)\n" msgstr "%sColor%s (ts) Prefijo de completado coincidente (p. ej. %sarchivo%snombre) (%s3%s)\n" msgid "%sColor%s (tt) Truncated filenames mark (e.g. filenam%s%c%s.odt)\n" msgstr "%sColor%s (tt) Marca de nombres de archivo truncados (p. ej. filenam%s%c%s.odt)\n" msgid "%sColor%s (tw) Sticky and other-writable directory\n" msgstr "%sColor%s (tw) Directorio sticky y editable por otros\n" msgid "" "%sColor%s (tx) Input text (e.g. [1m [0m %sls%s %s-l%s %sfilename.zst%s)\n" msgstr "" "%sColor%s (tx) Texto de entrada (p. ej. [1m [0m %sls%s %s-l%s %snombre.zst%s)\n" msgid "%sColor%s (uf) Unaccessible (non-stat'able) file\n" msgstr "%sColor%s (uf) Archivo inaccesible (no stat'able)\n" msgid "%sColor%s (wm) Warning message indicator (%sW%s)\n" msgstr "%sColor%s (wm) Indicador de mensaje de advertencia (%sW%s)\n" msgid "%sColor%s (ws1) Workspace [%s1%s]\n" msgstr "%sColor%s (ws1) Espacio de trabajo [%s1%s]\n" msgid "%sColor%s (ws2) Workspace [%s2%s]\n" msgstr "%sColor%s (ws2) Espacio de trabajo [%s2%s]\n" msgid "%sColor%s (ws3) Workspace [%s3%s]\n" msgstr "%sColor%s (ws3) Espacio de trabajo [%s3%s]\n" msgid "%sColor%s (ws4) Workspace [%s4%s]\n" msgstr "%sColor%s (ws4) Espacio de trabajo [%s4%s]\n" msgid "%sColor%s (ws5) Workspace [%s5%s]\n" msgstr "%sColor%s (ws5) Espacio de trabajo [%s5%s]\n" msgid "%sColor%s (ws6) Workspace [%s6%s]\n" msgstr "%sColor%s (ws6) Espacio de trabajo [%s6%s]\n" msgid "%sColor%s (ws6) Workspace [%s6%s]\n" msgstr "%sColor%s (ws6) Espacio de trabajo [%s6%s]\n" msgid "%sColor%s (ws7) Workspace [%s7%s]\n" msgstr "%sColor%s (ws7) Espacio de trabajo [%s7%s]\n" msgid "%sColor%s (ws8) Workspace [%s8%s]\n" msgstr "%sColor%s (ws8) Espacio de trabajo [%s8%s]\n" msgid "%sColor%s (xf) Error exit code (e.g. <%s1%s>)\n" msgstr "%sColor%s (xf) Código de salida de error (p. ej. <%s1%s>)\n" msgid "%sColor%s (xs) Success exit code (<%s0%s>)\n" msgstr "%sColor%s (xs) Código de salida de éxito (<%s0%s>)\n" msgid "" "%sEdit file ownership (Ctrl+d to quit)\n" "Both ID numbers and names are supported\n" msgstr "" "%sEditar propiedad del archivo (Ctrl+d para salir)\n" "Se admiten tanto números de ID como nombres\n" msgid "" "%sEdit file permissions (Ctrl+d to quit)\n" "Both symbolic and numeric notation are supported\n" msgstr "" "%sEditar permisos del archivo (Ctrl+d para salir)\n" "Se admiten tanto notación simbólica como numérica\n" msgid "" "%sFile types%s\n" "\n" msgstr "" "%sTipos de archivo%s\n" "\n" msgid "%sFile%s: %s\n" msgstr "%sArchivo%s: %s\n" msgid "" "%sFiles with different owners\n" "Only common owners are set in the template\n" msgstr "" "%sArchivos con diferentes propietarios\n" "Solo se muestran los propietarios comunes en la plantilla\n" msgid "" "%sFiles with different sets of permissions\n" "Only shared permission bits are set in the template\n" msgstr "" "%sArchivos con diferentes conjuntos de permisos\n" "Solo se muestran los bits de permiso compartidos en la plantilla\n" msgid "" "%sMountpoints%s\n" "\n" msgstr "" "%sPuntos de montaje%s\n" "\n" msgid "%sNOTE%s: Using Zstandard\n" msgstr "%sNOTA%s: Utilizando Zstandard\n" msgid "%sPress any key to continue... " msgstr "%sPresiona cualquier tecla para continuar... " msgid "" "%s[e]%sxtract %s[E]%sxtract-to-dir %s[l]%sist %s[m]%sount %s[r]%sepack %s[q]" "%suit\n" msgstr "" "%s[e]%sxtraer %s[E]%sxtraer-a-dir %s[l]%sista %s[m]%sontar %s[r]%seempaquetar %s[q]" "%ssalir\n" msgid "" "%s[e]%sxtract %s[E]%sxtract-to-dir %s[l]%sist %s[t]%sest %s[m]%sount %s[q]" "%suit\n" msgstr "" "%s[e]%sxtraer %s[E]%sxtraer-a-dir %s[l]%sista %s[t]%sest %s[m]%sontar %s[q]" "%ssalir\n" msgid "%s[e]%sxtract %s[t]%sest %s[i]%snfo %s[q]%suit\n" msgstr "%s[e]%sxtraer %s[t]%sest %s[i]%snformación %s[q]%ssalir\n" msgid "%sbigger%s\n" msgstr "%smás grande%s\n" msgid "%sday%s " msgstr "%sdía%s " msgid "%shour%s " msgstr "%shora%s " msgid "%smonth%s " msgstr "%smes%s " msgid "%solder%s\n" msgstr "%smás antiguo%s\n" msgid "%sweek%s " msgstr "%ssemána%s " msgid "%zu file(s) copied\n" msgstr "%zu archivo(s) copiado(s)\n" msgid "%zu file(s) created\n" msgstr "%zu archivo(s) creado(s)\n" msgid "%zu file(s) deselected\n" msgstr "%zu archivo(s) deseleccionado(s)\n" msgid "%zu file(s) moved\n" msgstr "%zu archivo(s) movido(s)\n" msgid "%zu file(s) removed\n" msgstr "%zu archivo(s) eliminado(s)\n" msgid "%zu file(s) removed from the trash can\n" msgstr "%zu archivo(s) eliminado(s) de la papelera de reciclaje\n" msgid "%zu file(s) renamed\n" msgstr "%zu archivo(s) renombrado(s)\n" msgid "%zu file(s) restored\n" msgstr "%zu archivo(s) restaurado(s)\n" msgid "%zu file(s) selected\n" msgstr "%zu archivo(s) seleccionado(s)\n" msgid "%zu file(s) trashed\n" msgstr "%zu archivo(s) eliminado(s) a la papelera de reciclaje\n" msgid "%zu filename(s) will be bleached\n" msgstr "%zu nombre(s) de archivo serán blanqueado(s)\n" msgid "%zu selected file(s)\n" msgstr "%zu archivo(s) seleccionado(s)\n" msgid "%zu symbolic link(s) created\n" msgstr "%zu enlace(s) simbólico(s) creado(s)\n" msgid "%zu total selected file(s)\n" msgstr "%zu archivo(s) seleccionado(s) total(es)\n" msgid "%zu total trashed file(s)\n" msgstr "%zu archivo(s) en la papelera\n" msgid "%zu trashed file(s)\n" msgstr "%zu archivo(s) enviado(s) a la papelera\n" msgid "'%s' conflicts with '%s'\n" msgstr "'%s' entra en conflicto con '%s'\n" msgid "'%s' has conflicting definitions\n" msgstr "'%s' tiene definiciones conflictivas\n" msgid "'%s' relinked to " msgstr "'%s' reenlazado a " msgid "" "'%s': %s\n" "bookmarks: Error creating temporary file\n" msgstr "" "'%s': %s\n" "marcadores: Error al crear archivo temporal\n" msgid "" "'%s': %s\n" "bookmarks: Error reading the bookmarks file\n" msgstr "" "'%s': %s\n" "marcadores: Error al leer el archivo de marcadores\n" msgid "'%s': Alias already exists\n" msgstr "'%s': El alias ya existe\n" msgid "'%s': Alias conflicts with internal command\n" msgstr "'%s': El alias está conflicto con un comando interno\n" msgid "'%s': Invalid bookmark\n" msgstr "'%s': Marcador no válido\n" msgid "'%s': Invalid regular expression\n" msgstr "'%s': Expresión regular no válida\n" msgid "'%s': No such bookmark\n" msgstr "'%s': No existe este marcador\n" msgid "'%s': Successfully removed tag\n" msgstr "'%s': Etiqueta eliminada con éxito\n" msgid "" "(%s%04o%s)%s%c%s/%s%c%s%c%s%c%s.%s%c%s%c%s%c%s.%s%c%s%c%s%c%s%s Links: " "%s%zu%s " msgstr "" "(%s%04o%s)%s%c%s/%s%c%s%c%s%c%s.%s%c%s%c%s%c%s.%s%c%s%c%s%c%s%s Enlaces: " "%s%zu%s " msgid "" "(%s2%s) Also used for miscellaneous names (like bookmarks and color schemes) " "in tab completion\n" msgstr "" "(%s2%s) También usada para nombres varios (como marcadores y esquemas de color) " "en el autocompletado\n" msgid "(%s3%s) Used only for the standard tab completion mode\n" msgstr "(%s3%s) Se usa solo para el modo estándar de autocompletado\n" msgid "(Enter:accept, Ctrl+d:abort, Ctrl+c:clear-line)" msgstr "(Intro:aceptar, Ctrl+d:abortar, Ctrl+c:limpiar línea)" msgid "0 total selected file(s)\n" msgstr "0 archivo(s) seleccionado(s) en total\n" msgid "" msgstr "" msgid "??? (broken link)" msgstr "??? (enlace roto)" msgid "ACL-extended:\t" msgstr "ACL-extendido:\t" msgid "Access: \t%s%s%s\n" msgstr "Acceso: \t%s%s%s\n" msgid "Active filter: %s%s%s%s\n" msgstr "Filtro activo: %s%s%s%s\n" msgid "Archive state 1" msgstr "Estado de archivo 1" msgid "Archive state 1: %zu\n" msgstr "Estado de archivo 1: %zu\n" msgid "Archive state 2" msgstr "Estado de archivo 2" msgid "Archive state 2: %zu\n" msgstr "Estado de archivo 2: %zu\n" msgid "Associated application: None\n" msgstr "Aplicación asociada: Ninguna\n" msgid "Attributes: \t" msgstr "Atributos: \t" msgid "Auto-open disabled" msgstr "Auto-apertura deshabilitada" msgid "Auto-open enabled" msgstr "Auto-apertura habilitada" msgid "Auto-open is %s\n" msgstr "La auto-apertura es %s\n" msgid "Autocd disabled" msgstr "Autocd deshabilitado" msgid "Autocd enabled" msgstr "Autocd habilitado" msgid "Autocd is %s\n" msgstr "Autocd es %s\n" msgid "Bind function to this new key?" msgstr "¿Asociar función a esta nueva tecla?" msgid "Birth: \t\t%s%s%s\n" msgstr "Creación: \t\t%s%s%s\n" msgid "Birth: \t\t%s-%s\n" msgstr "Creación: \t\t%s-%s\n" msgid "Block special file" msgstr "Archivo especial de bloque" msgid "Calculating file size... " msgstr "Calculando tamaño de archivo... " msgid "Cannot rename '%s' to '%s': %s\n" msgstr "No se puede renombrar '%s' a '%s': %s\n" msgid "Capabilities:\t" msgstr "Capacidades:\t" msgid "Change: \t%s%s%s\n" msgstr "Cambio: \t%s%s%s\n" msgid "Character special file" msgstr "Archivo especial de caracter" msgid "Choose a directory ('q' to quit): " msgstr "Elige un directorio ('q' para salir): " msgid "Choose a mountpoint/device: " msgstr "Elige un punto de montaje/dispositivo: " msgid "Choose a mountpoint: " msgstr "Elige un punto de montaje: " msgid "Choose an application ('q' to quit): " msgstr "Elige una aplicación ('q' para salir): " msgid "Clear history?" msgstr "¿Borrar historial?" msgid "Color scheme %s%s%s %s\n" msgstr "Esquema de color %s%s%s %s\n" msgid "Columns %s\n" msgstr "Columnas %s\n" msgid "Columns disabled\n" msgstr "Columnas deshabilitadas\n" msgid "Columns enabled\n" msgstr "Columnas habilitadas\n" msgid "Configuration file not found" msgstr "Archivo de configuración no encontrado" msgid "Continue?" msgstr "¿Continuar?" msgid "Create broken symbolic link?" msgstr "¿Crear enlace simbólico roto?" msgid "Create it?" msgstr "¿Crearlo?" msgid "Created new tag %s%s%s\n" msgstr "Etiqueta nueva creada %s%s%s\n" msgid "Current color scheme: '%s'\n" msgstr "Esquema de color actual: '%s'\n" msgid "Current filter: %c%s\n" msgstr "Filtro actual: %c%s\n" msgid "Current target %s%s%s " msgstr "Objetivo actual %s%s%s " msgid "Device: %s%ju,%ju%s" msgstr "Dispositivo: %s%ju,%ju%s" msgid "Directories first %s\n" msgstr "Directorios-primero %s\n" msgid "Directories first disabled\n" msgstr "Directorios-primero deshabilitado\n" msgid "Directories first enabled\n" msgstr "Directorios-primero habilitado\n" msgid "Directories first is %s\n" msgstr "Directorios-primero es %s\n" msgid "Directory" msgstr "Directorio" msgid "Disk usage analyzer %s\n" msgstr "Analizador de uso de disco %s\n" msgid "Door " msgstr "Puerta " msgid "Doors: %zu\n" msgstr "Puertas: %zu\n" msgid "Edit target (Ctrl+d to quit)" msgstr "Editar objetivo (Ctrl+d para salir)" msgid "Enter 'iELN' for device information. E.g.: i4" msgstr "Ingrese 'iELN' para obtener información del dispositivo. Ej.: i4" msgid "Enter 'q' to quit" msgstr "Ingrese 'q' para salir" msgid "Enter a keybinding for %s%s%s (current: %s%s%s)\n" msgstr "Ingrese una asociación de tecla para %s%s%s (actual: %s%s%s)\n" msgid "" "Enter destination directory (Ctrl+d to quit)\n" "Tip: "." for the current directory" msgstr "" "Ingrese el directorio de destino (Ctrl+d para salir)\n" "Consejo: "." para usar el directorio actual" msgid "" "Enter new filename (Ctrl+d to quit)\n" "Tip: End name with a slash to create a directory" msgstr "" "Ingrese el nuevo nombre (Ctrl+d para salir)\n" "Consejo: Termine el nombre con una barra para crear un directorio" msgid "" "Enter new name (Ctrl+d to quit)\n" "%s>%s " msgstr "" "Ingrese el nuevo nombre (Ctrl+d para salir)\n" "%s>%s " msgid "Error opening temporary file" msgstr "Error al abrir archivo temporal" msgid "Error querying file type" msgstr "Error al consultar el tipo de archivo" msgid "External commands allowed" msgstr "Comandos externos permitidos" msgid "External commands are %s\n" msgstr "Los comandos externos están %s\n" msgid "External commands disallowed" msgstr "Comandos externos no permitidos" msgid "Fifo " msgstr "Fifo " msgid "File modified. Actions reloaded.\n" msgstr "Archivo modificado. Acciones recargadas.\n" msgid "File modified. Bookmarks reloaded.\n" msgstr "Archivo modificado. Marcadores recargados.\n" msgid "File modified. History entries reloaded\n" msgstr "Archivo modificado. Entradas de historial recargadas\n" msgid "File modified. Prompts reloaded\n" msgstr "Archivo modificado. Prompts recargados.\n" msgid "File modified. Remotes reloaded.\n" msgstr "Archivo modificado. Remotos recargados.\n" msgid "File succesfully bookmarked" msgstr "Archivo marcado con éxito" msgid "File(s) to be removed%s:\n" msgstr "Archivo(s) a eliminar%s:\n" msgid "File(s) to be trashed:\n" msgstr "Archivo(s) a mover a la papelera:\n" msgid "File-creation mask set to '%04o'\n" msgstr "Máscara de creación de archivo establecida en '%04o'\n" msgid "Filename ('q' to quit): " msgstr "Nombre de archivo ('q' para salir): " msgid "Filenames exported to '%s'\n" msgstr "Nombres de archivo exportados a '%s'\n" msgid "File counter %s\n" msgstr "Contador de archivos %s\n" msgid "File counter disabled\n" msgstr "Contador de archivos deshabilitado\n" msgid "File counter enabled\n" msgstr "Contador de archivos habilitado\n" msgid "Files tagged as %s%s%s%s:\n" msgstr "Archivos etiquetados como %s%s%s%s:\n" msgid "Files tagged as %s%s%s:\n" msgstr "Archivos etiquetados como %s%s%s:\n" msgid "Filter unset\n" msgstr "Filtro desestablecido\n" msgid "Flags: \t\t" msgstr "Indicadores: \t\t" msgid "Follow links %s\n" msgstr "Seguir enlaces %s\n" msgid "" "For more information consult the manpage and/or the Wiki:\n" "https://github.com/leo-arch/clifm/wiki" msgstr "" "Para más información, consulte la página del manual y/o la Wiki:\n" "https://github.com/leo-arch/clifm/wiki" msgid "Full directory size disabled\n" msgstr "Tamaño de directorio completo deshabilitado\n" msgid "Full directory size enabled\n" msgstr "Tamaño de directorio completo habilitado\n" msgid "Full directory size is already disabled" msgstr "El tamaño de directorio completo ya está deshabilitado" msgid "Full directory size is already enabled" msgstr "El tamaño de directorio completo ya está habilitado" msgid "Glob: No matches found. Trying regex...\n" msgstr "Glob: No se encontraron coincidencias. Intentando regex...\n" msgid "Hidden files: off\n" msgstr "Archivos ocultos: desactivados\n" msgid "Hidden files: on\n" msgstr "Archivos ocultos: activados\n" msgid "Hidden files: on (list first)\n" msgstr "Archivos ocultos: activados (listar primero)\n" msgid "Hidden files: on (list last)\n" msgstr "Archivos ocultos: activados (listar al final)\n" msgid "History is %s\n" msgstr "Historial es %s\n" msgid "Icons disabled\n" msgstr "Iconos deshabilitados\n" msgid "Icons enabled\n" msgstr "Iconos habilitados\n" msgid "Invalid filename" msgstr "Nombre de archivo no válido" msgid "Is this OK? [y/n/(e)dit] " msgstr "¿Esto es correcto? [y/n/(e)ditar] " msgid "Items:\t\t%s%c%s\n" msgstr "Elementos:\t\t%s%c%s\n" msgid "Items:\t\t%s%s%llu%s (%s%llu%s %s, %s%llu%s %s, %s%llu%s %s)\n" msgstr "Elementos:\t\t%s%s%llu%s (%s%llu%s %s, %s%llu%s %s, %s%llu%s %s)\n" msgid "Largest file: %s%s%s %s%s%s%s%s\n" msgstr "Archivo más grande: %s%s%s %s%s%s%s%s\n" msgid "Light mode %s\n" msgstr "Modo ligero %s\n" msgid "Light mode already off" msgstr "El modo ligero ya está desactivado" msgid "Light mode already on" msgstr "El modo ligero ya está activado" msgid "Light mode disabled\n" msgstr "Modo ligero deshabilitado\n" msgid "Light mode enabled\n" msgstr "Modo ligero habilitado\n" msgid "Long view %s\n" msgstr "Vista larga %s\n" msgid "MIME type: %s\n" msgstr "Tipo MIME: %s\n" msgid "Matches found: %d%s\n" msgstr "Coincidencias encontradas: %d%s\n" msgid "Matches found: %zu\n" msgstr "Se encontraron coincidencias: %zu\n" msgid "Max files set to %d\n" msgstr "Archivos máximos establecidos en %d\n" msgid "Max files unset\n" msgstr "Archivos máximos desestablecidos\n" msgid "Max files: %d\n" msgstr "Archivos máximos: %d\n" msgid "Max files: unset" msgstr "Archivos máximos: desestablecidos" msgid "Max name length set to %d\n" msgstr "Longitud máxima de nombre establecida en %d\n" msgid "Max name length unset\n" msgstr "Longitud máxima de nombre desestablecida\n" msgid "Messages cleared\n" msgstr "Mensajes borrados\n" msgid "Missing parameter. Try 's --help'\n" msgstr "Parámetro faltante. Intenta 's --help'\n" msgid "Modify: \t%s%s%s\n" msgstr "Modificar: \t%s%s%s\n" msgid "Mounted devices" msgstr "Dispositivos montados" msgid "Mountpoints" msgstr "Puntos de montaje" msgid "Name: %s\n" msgstr "Nombre: %s\n" msgid "Name: %s%s%s\n" msgstr "Nombre: %s%s%s\n" msgid "New configuration file written to '%s'\n" msgstr "Nuevo archivo de configuración escrito en '%s'\n" msgid "New format (e.g.: .tar.xz): " msgstr "Nuevo formato (p. ej.: .tar.xz): " msgid "New key: %s\n" msgstr "Nueva clave: %s\n" msgid "New ownership set for %zu file(s)\n" msgstr "Nueva propiedad establecida para %zu archivo(s)\n" msgid "No" msgstr "No" msgid "No matches found\n" msgstr "No se encontraron coincidencias\n" msgid "No such ELN" msgstr "No existe ELN" msgid "None" msgstr "Ninguno" msgid "Old configuration file saved as '%s'\n" msgstr "Archivo de configuración antiguo guardado como '%s'\n" msgid "Old keybindings file saved as '%s'\n" msgstr "Archivo de enlaces de teclas antiguo guardado como '%s'\n" msgid "Only directories %s\n" msgstr "Solo directorios %s\n" msgid "Opener set to '%s'\n" msgstr "Aperturador establecido en '%s'\n" msgid "Opening application: %s [%s]\n" msgstr "Abriendo aplicación: %s [%s]\n" msgid "Opening application: ad [builtin] [%s]\n" msgstr "Abriendo aplicación: ad [integrado] [%s]\n" msgid "Operation: " msgstr "Operación: " msgid "Overwrite this file?" msgstr "¿Sobrescribir este archivo?" msgid "Pager disabled" msgstr "Paginador deshabilitado" msgid "Pager enabled" msgstr "Paginador habilitado" msgid "Pager set to %d\n" msgstr "Paginador establecido en %d\n" msgid "Pinned file: '%s'\n" msgstr "Archivo fijado: '%s'\n" msgid "Port " msgstr "Puerto " msgid "Ports: %zu\n" msgstr "Puertos: %zu\n" msgid "PreviewMaxSize: '%c': Invalid unit.\n" msgstr "PreviewMaxSize: '%c': Unidad inválida.\n" msgid "PreviewMaxSize: Value too large (max %dGiB).\n" msgstr "PreviewMaxSize: Valor demasiado grande (máx %dGiB).\n" msgid "Previewing application: %s %s\n" msgstr "Previsualizando aplicación: %s %s\n" msgid "Querying MIME types... " msgstr "Consultando tipos MIME... " msgid "Regular file" msgstr "Archivo regular" msgid "Relink as broken symbolic link?" msgstr "Volver a enlazar como enlace simbólico roto?" msgid "Remove %zu file(s)?" msgstr "¿Eliminar %zu archivo(s)?" msgid "Remove files anyway?" msgstr "¿Eliminar archivos de cualquier manera?" msgid "Removed %zu bookmark(s)\n" msgstr "Eliminados %zu marcador(es)\n" msgid "Removed %zu thumbnail(s): %s freed\n" msgstr "Eliminadas %zu miniatura(s): %s liberado\n" msgid "Run '?' and consult the NAVIGATION section" msgstr "Ejecuta '?' y consulta la sección de NAVEGACIÓN" msgid "Run '?' or 'help' to get started with %s\n" msgstr "Ejecuta '?' o 'help' para empezar con %s\n" msgid "Run 'cs edit' to fix these conflicts" msgstr "Ejecuta 'cs edit' para solucionar estos conflictos" msgid "Run command?" msgstr "¿Ejecutar comando?" msgid "Running in light mode: Some files statistics are not available\n" msgstr "Ejecutando en modo ligero: Algunas estadísticas de archivos no están disponibles\n" msgid "Show-hidden-files is %s\n" msgstr "Mostrar-archivos-ocultos es %s\n" msgid "Showing %jd/%jd files\n" msgstr "Mostrando %jd/%jd archivos\n" msgid "Size:\t\t" msgstr "Tamaño:\t\t" msgid "Size: \t\t%s%s%s" msgstr "Tamaño: \t\t%s%s%s" msgid "Socket " msgstr "Socket " msgid "Sorted by " msgstr "Ordenado por " msgid "Succesfully created profile %s%s%s\n" msgstr "Perfil creado con éxito %s%s%s\n" msgid "Successfully merged %s%s%s into %s%s%s\n" msgstr "Combinado con éxito %s%s%s en %s%s%s\n" msgid "Successfully removed profile %s%s%s\n" msgstr "Perfil eliminado con éxito %s%s%s\n" msgid "Successfully tagged %zu file(s)\n" msgstr "Etiquetado con éxito %zu archivo(s)\n" msgid "Successfully untagged %zu file(s)\n" msgstr "Desetiquetado con éxito %zu archivo(s)\n" msgid "Switched to %s names\n" msgstr "Cambiado a nombres %s\n" msgid "Switched to profile %s%s%s\n" msgstr "Cambiado a perfil %s%s%s\n" msgid "Symbolic link" msgstr "Enlace simbólico" msgid "Take a look at the 'colorschemes', 'prompt', and 'config' commands" msgstr "Echa un vistazo a los comandos 'colorschemes', 'prompt' y 'config'" msgid "The file counter is disabled" msgstr "El contador de archivos está deshabilitado" msgid "The file counter is enabled" msgstr "El contador de archivos está habilitado" msgid "" "The following is the list of options (as defined in the configuration file) " "and their current values. Whenever a value differs from the default, the " "entry is highlighted and the default value is displayed in square brackets.\n" msgstr "" "Lo siguiente es la lista de opciones (como se define en el archivo de configuración) " "y sus valores actuales. Siempre que un valor difiere del valor predeterminado, la " "entrada se resalta y el valor predeterminado se muestra entre corchetes.\n" msgid "The pager is disabled" msgstr "El paginador está deshabilitado" msgid "The pager is enabled" msgstr "El paginador está habilitado" msgid "The pager is set to %d\n" msgstr "El paginador está establecido en %d\n" msgid "" "To run a plugin just enter its action name\n" "Example: enter '//' to run the rgfind plugin" msgstr "" "Para ejecutar un plugin, solo ingresa su nombre de acción\n" "Ejemplo: ingresa '//' para ejecutar el plugin rgfind" msgid "To unset the function enter '-'" msgstr "Para desestablecer la función, ingresa '-'" msgid "Toggled executable bit on %zu %s\n" msgstr "Alternado el bit ejecutable en %zu %s\n" msgid "Too few" msgstr "Demasiado pocos" msgid "Too many" msgstr "Demasiados" msgid "" "Total files: %jd\n" "Directories: %zu%s\n" "Regular files: %zu%s\n" "Executable files: %zu\n" "Hidden files: %zu\n" "SUID files: %zu\n" "SGID files: %zu\n" "Files w/capabilities: %zu\n" "FIFO/pipes: %zu\n" "Sockets: %zu\n" "Block devices: %zu\n" "Character devices: %zu\n" "Symbolic links: %zu%s\n" "Multi-link files: %zu\n" "Files w/extended attributes: %zu\n" "Other-writable files: %zu\n" "Sticky files: %zu\n" "Unknown file types: %zu\n" "Unstatable files: %zu\n" msgstr "" "Archivos totales: %jd\n" "Directorios: %zu%s\n" "Archivos regulares: %zu%s\n" "Archivos ejecutables: %zu\n" "Archivos ocultos: %zu\n" "Archivos SUID: %zu\n" "Archivos SGID: %zu\n" "Archivos con capacidades: %zu\n" "FIFO/tuberías: %zu\n" "Socket: %zu\n" "Dispositivos de bloque: %zu\n" "Dispositivos de caracter: %zu\n" "Enlaces simbólicos: %zu%s\n" "Archivos de multi-enlace: %zu\n" "Archivos con atributos extendidos: %zu\n" "Archivos escribibles por otros: %zu\n" "Archivos pegajosos: %zu\n" "Tipos de archivo desconocidos: %zu\n" "Archivos no estadísticos: %zu\n" msgid "Total size:\t" msgstr "Tamaño total:\t" msgid "Total size: \t" msgstr "Tamaño total: \t" msgid "Total size: \t%s%c%s\n" msgstr "Tamaño total: \t%s%c%s\n" msgid "Total size: %s%s%s%s\n" msgstr "Tamaño total: %s%s%s%s\n" msgid "Trash can emptied: %zu file(s) removed\n" msgstr "Papelera vaciada: %zu archivo(s) eliminado(s)\n" msgid "Try 'mm edit APPLICATION'\n" msgstr "Intenta 'mm edit APLICACIÓN'\n" msgid "UNKNOWN" msgstr "DESCONOCIDO" msgid "Unset this function?" msgstr "¿Desestablecer esta función?" msgid "" "Use extension to specify archive/compression type (defaults to .tar.gz)\n" "Example: myarchive.xz" msgstr "" "Utilice la extensión para especificar el tipo de archivo/compresión (predeterminado .tar.gz)\n" "Ejemplo: myarchive.xz" msgid "Virtual directory\n" msgstr "Directorio virtual\n" msgid "Whiteout" msgstr "Borrado" msgid "Whiteout: %zu\n" msgstr "Borrado: %zu\n" msgid "Xattributes:\t" msgstr "Atributos X:\t" msgid "Yes" msgstr "Sí" msgid "actions: Access to configuration files is not allowed in stealth mode" msgstr "actions: El acceso a los archivos de configuración no está permitido en modo sigilo" msgid "" "actions: No actions defined. Use the 'actions edit' command to add new " "actions\n" msgstr "" "actions: No se han definido acciones. Utilice el comando 'actions edit' para agregar nuevas acciones\n" msgid "actions: Plugins are not allowed in stealth mode\n" msgstr "actions: Los plugins no están permitidos en modo sigilo\n" msgid "actions: Plugins directory not defined" msgstr "actions: El directorio de plugins no está definido" msgid "alias: %zu alias(es) imported\n" msgstr "alias: %zu alias(es) importado(s)\n" msgid "alias: '%s': Error normalizing filename\n" msgstr "alias: '%s': Error al normalizar el nombre del archivo\n" msgid "alias: No alias found in '%s'\n" msgstr "alias: No se encontró alias en '%s'\n" msgid "alias: No alias imported\n" msgstr "alias: No se importaron aliases\n" msgid "allowed" msgstr "permitido" msgid "apparent" msgstr "aparente" msgid "archiver: '%s': Error unescaping filename\n" msgstr "archiver: '%s': Error al desescapar el nombre del archivo\n" msgid "" "archiver: '%s': Invalid file format. File should be either a directory or a " "block device.\n" msgstr "" "archiver: '%s': Formato de archivo inválido. El archivo debe ser un directorio o un dispositivo de bloque.\n" msgid "archiver: '%s': Not an archive/compressed file\n" msgstr "archiver: '%s': No es un archivo comprimido\n" msgid "auto: No temporary autocommand defined for the current directory\n" msgstr "auto: No se ha definido un autocomando temporal para el directorio actual\n" msgid "auto: The current directory is undefined\n" msgstr "auto: El directorio actual está indefinido\n" msgid "autocmd: '%s': Invalid option format (it must be 'OPTION=VALUE')\n" msgstr "autocmd: '%s': Formato de opción inválido (debe ser 'OPCIÓN=VALOR')\n" msgid "autocmd: '%s': Invalid option name\n" msgstr "autocmd: '%s': Nombre de opción inválido\n" msgid "autocmd: '%s': Invalid value for '%s'\n" msgstr "autocmd: '%s': Valor inválido para '%s'\n" msgid "autocmd: '%s': Invalid value for 'cs'\n" msgstr "autocmd: '%s': Valor inválido para 'cs'\n" msgid "autocmd: '%s': Invalid value for 'st'\n" msgstr "autocmd: '%s': Valor inválido para 'st'\n" msgid "bd: %s: No matches found\n" msgstr "bd: %s: No se encontraron coincidencias\n" msgid "bd: '%s': Error expanding tilde\n" msgstr "bd: '%s': Error al expandir el tilde\n" msgid "bd: '%s': Error unescaping string\n" msgstr "bd: '%s': Error al desescapar la cadena\n" msgid "bd: '/': No parent directory" msgstr "bd: '/': No hay directorio padre" msgid "bl: '%s': Error unescaping name\n" msgstr "bl: '%s': Error al desescapar el nombre\n" msgid "bl: Cannot create symbolic link '%s': %s\n" msgstr "bl: No se puede crear el enlace simbólico '%s': %s\n" msgid "bleach: '%s': Error unescaping filename\n" msgstr "bleach: '%s': Error al desescapar el nombre del archivo\n" msgid "bleach: Cannot rename '%s' to '%s': %s\n" msgstr "bleach: No se puede renombrar '%s' a '%s': %s\n" msgid "bookmarks: '%s': Already bookmarked as '%s'\n" msgstr "bookmarks: '%s': Ya está marcado como '%s'\n" msgid "bookmarks: '%s': Colons and square brackets are not allowed\n" msgstr "bookmarks: '%s': No se permiten ni dos puntos ni corchetes\n" msgid "bookmarks: '%s': Error unescaping filename\n" msgstr "bookmarks: '%s': Error al desescapar el nombre del archivo\n" msgid "bookmarks: '%s': Name already in use\n" msgstr "bookmarks: '%s': El nombre ya está en uso\n" msgid "bookmarks: '%s': Reserved bookmark keyword\n" msgstr "bookmarks: '%s': Palabra clave de marcador reservada\n" msgid "bookmarks: '%s': Shortcut already in use\n" msgstr "bookmarks: '%s': El acceso directo ya está en uso\n" msgid "bookmarks: Cannot add any more bookmarks" msgstr "bookmarks: No se pueden agregar más marcadores\n" msgid "bookmarks: Cannot open the bookmarks file" msgstr "bookmarks: No se puede abrir el archivo de marcadores\n" msgid "" "bookmarks: Error updating bookmarks\n" "Cannot rename temporary file '%s': %s\n" msgstr "" "bookmarks: Error al actualizar los marcadores\n" "No se puede renombrar el archivo temporal '%s': %s\n" msgid "br: '%s' is duplicated\n" msgstr "br: '%s' está duplicado\n" msgid "br: '%s': Error normalizing path\n" msgstr "br: '%s': Error al normalizar la ruta\n" msgid "br: '%s': Error unescaping filename\n" msgstr "br: '%s': Error al desescapar el nombre del archivo\n" msgid "br: Cannot rename '%s' to '%s': %s\n" msgstr "br: No se puede renombrar '%s' a '%s': %s\n" msgid "br: Line mismatch in temporary file" msgstr "br: Error de coincidencia de línea en el archivo temporal\n" msgid "br: Nothing to do" msgstr "br: No hay nada que hacer\n" msgid "br: Temporary file changed on disk! Aborting." msgstr "br: ¡El archivo temporal ha cambiado en disco! Cancelando.\n" msgid "builtin (256 colors)" msgstr "integrado (256 colores)" msgid "builtin (8 colors)" msgstr "integrado (8 colores)" msgid "cd: '%s': Error normalizing path\n" msgstr "cd: '%s': Error al normalizar la ruta\n" msgid "cd: Home directory not found" msgstr "cd: No se encontró el directorio principal\n" msgid "cd: Path is NULL or empty" msgstr "cd: La ruta es NULL o vacía\n" msgid "cs: '%s': No such color scheme\n" msgstr "cs: '%s': No existe este esquema de colores\n" msgid "cs: Current color scheme is unknown" msgstr "cs: El esquema de colores actual es desconocido\n" msgid "cs: No color scheme found" msgstr "cs: No se halló ningún esquema de colores\n" msgid "cs: No conflicts found" msgstr "cs: No se encontraron conflictos\n" msgid "desel: %s: Invalid ELN\n" msgstr "desel: %s: ELN inválido\n" msgid "desel: '%s': Invalid entry\n" msgstr "desel: '%s': Entrada inválida\n" msgid "desel: No selected files" msgstr "desel: No hay archivos seleccionados\n" msgid "devices" msgstr "dispositivos" msgid "dh: '%d': No such entry number\n" msgstr "dh: '%d': No existe este número de entrada\n" msgid "dh: Invalid history entry" msgstr "dh: Entrada de historia inválida\n" msgid "directories" msgstr "directorios" msgid "directory" msgstr "directorio" msgid "disabled" msgstr "deshabilitado" msgid "disk usage" msgstr "uso de disco" msgid "dup: '%s': Error unescaping filename\n" msgstr "dup: '%s': Error al desescapar el nombre del archivo\n" msgid "enabled" msgstr "habilitado" msgid "enabled (list first)" msgstr "habilitado (lista primero)" msgid "enabled (list last)" msgstr "habilitado (lista último)" msgid "entries" msgstr "entradas" msgid "entry" msgstr "entrada" msgid "export: %s: Empty assignement\n" msgstr "export: %s: Asignación vacía\n" msgid "export: A parameter, in the form VAR=VALUE, is required" msgstr "export: Se requiere un parámetro en el formato VAR=VALOR" msgid "export: Error unescaping argument" msgstr "export: Error al desescapar el argumento" msgid "false" msgstr "falso" msgid "file" msgstr "archivo" msgid "files" msgstr "archivos" msgid "fix the error (consult your daemon's documentation)" msgstr "corrija el error (consulte la documentación de su daemon)" msgid "ft: Error removing quotes: Filter unset" msgstr "ft: Error al eliminar comillas: Filtro desestablecido" msgid "ft: Invalid file type filter" msgstr "ft: Filtro de tipo de archivo inválido" msgid "ft: Invalid filter" msgstr "ft: Filtro inválido" msgid "ft: No filter set" msgstr "ft: No se ha establecido ningún filtro" msgid "history: %d: No such ELN\n" msgstr "historial: %d: No existe tal ELN\n" msgid "history: Invalid history entry" msgstr "historial: Entrada de historial inválida" msgid "install a notification daemon" msgstr "instale un daemon de notificación" msgid "invalid ACL" msgstr "ACL inválido" msgid "je: Configuration directory not found\n" msgstr "je: No se encontró el directorio de configuración\n" msgid "jump: '%c': Invalid option\n" msgstr "jump: '%c': Opción inválida\n" msgid "jump: '%s': Invalid value\n" msgstr "jump: '%s': Valor inválido\n" msgid "jump: Database still empty" msgstr "jump: La base de datos está vacía" msgid "jump: No entry ranked below %d\n" msgstr "jump: No hay entrada clasificada debajo de %d\n" msgid "jump: No invalid entries" msgstr "jump: No hay entradas inválidas" msgid "jump: No matches found" msgstr "jump: No se encontraron coincidencias" msgid "k: Feature not available in light mode" msgstr "k: La función no está disponible en modo ligero" msgid "k: Not in long view" msgstr "k: No en vista larga" msgid "kb: %s: Key already in use by '%s' (readline)\n" msgstr "kb: %s: La tecla ya está en uso por '%s' (readline)\n" msgid "kb: %s: Key already in use by '%s'.\n" msgstr "kb: %s: La tecla ya está en uso por '%s'.\n" msgid "kb: '%s' conflicts with '%s'\n" msgstr "kb: '%s' entra en conflicto con '%s'\n" msgid "kb: '%s' conflicts with '%s' (readline)\n" msgstr "kb: '%s' entra en conflicto con '%s' (readline)\n" msgid "" "kb: '%s': Invalid function name\n" "Type 'kb bind ' to list available function names\n" msgstr "" "kb: '%s': Nombre de función inválido\n" "Escribe 'kb bind ' para listar los nombres de función disponibles\n" msgid "kb: Cannot generate time suffix string for the backup file\n" msgstr "kb: No se puede generar el sufijo para el archivo de respaldo\n" msgid "kb: Cannot open '%s': %s\n" msgstr "kb: No se puede abrir '%s': %s\n" msgid "kb: Cannot open temporary file: %s\n" msgstr "kb: No se puede abrir el archivo temporal: %s\n" msgid "kb: Cannot rename '%s' to '%s': %s\n" msgstr "kb: No se puede renombrar '%s' a '%s': %s\n" msgid "kb: Error creating temporary file: %s\n" msgstr "kb: Error al crear el archivo temporal: %s\n" msgid "kb: Invalid keybinding\n" msgstr "kb: Enlace de tecla inválido\n" msgid "kb: No keybindings defined" msgstr "kb: No se han definido enlaces de tecla" msgid "kb: No keybindings defined\n" msgstr "kb: No se han definido enlaces de tecla\n" msgid "kb: No keybindings file found\n" msgstr "kb: No se encontró el archivo de enlaces de tecla\n" msgid "kb: Restart %s for changes to take effect\n" msgstr "kb: Reinicie %s para que los cambios tengan efecto\n" msgid "le: '%s': Error unescaping filename\n" msgstr "le: '%s': Error al desescapar el nombre del archivo\n" msgid "le: '%s': Not a symbolic link\n" msgstr "le: '%s': No es un enlace simbólico\n" msgid "le: Cannot relink symbolic link '%s': %s\n" msgstr "le: No se puede reenlazar el enlace simbólico '%s': %s\n" msgid "le: Nothing to do" msgstr "le: No hay nada que hacer" msgid "link" msgstr "enlace" msgid "link: '%s': Error normalizing path\n" msgstr "link: '%s': Error al normalizar la ruta\n" msgid "link: Cannot create symbolic link '%s': %s\n" msgstr "link: No se puede crear el enlace simbólico '%s': %s\n" msgid "link: Cannot unlink '%s': %s\n" msgstr "link: No se puede remover '%s': %s\n" msgid "link: Error generating relative path: %s\n" msgstr "link: Error al generar la ruta relativa: %s\n" msgid "links" msgstr "enlaces" msgid "log: Command logs are %s\n" msgstr "log: Los registros de comandos están %s\n" msgid "log: Command logs cleared" msgstr "log: Los registros de comandos se han borrado" msgid "log: Command logs disabled" msgstr "log: Los registros de comandos están deshabilitados" msgid "log: Command logs enabled" msgstr "log: Los registros de comandos están habilitados" msgid "log: Message logs are %s\n" msgstr "log: Los registros de mensajes están %s\n" msgid "log: Message logs cleared" msgstr "log: Los registros de mensajes se han borrado" msgid "log: Message logs disabled" msgstr "log: Los registros de mensajes están deshabilitados" msgid "log: Message logs enabled" msgstr "log: Los registros de mensajes están habilitados" msgid "long" msgstr "largo" msgid "media" msgstr "medios" msgid "media: Function not available\n" msgstr "media: La función no está disponible\n" msgid "media: Function only available on Linux systems" msgstr "media: La función solo está disponible en sistemas Linux" msgid "media: No mount application found. Install either udevil or udisks2" msgstr "media: No se encontró aplicación de montaje. Instale udevil o udisks2" msgid "mount: This feature is available for Linux only." msgstr "montar: Esta función solo está disponible para Linux" msgid "mountpoints" msgstr "puntos de montaje" msgid "mountpoints: Function not available\n" msgstr "puntos de montaje: La función no está disponible\n" msgid "mp: There are no available mountpoints\n" msgstr "mp: No hay puntos de montaje disponibles\n" msgid "name was" msgstr "el nombre era" msgid "names were" msgstr "los nombres eran" msgid "net: '%s': Changed to mountpoint (%s)\n" msgstr "net: '%s': Cambiado a punto de montaje (%s)\n" msgid "net: '%s': Error getting parent directory\n" msgstr "net: '%s': Error al obtener el directorio padre\n" msgid "net: '%s': Mount command failed with error code %d\n" msgstr "net: '%s': El comando de montaje falló con el código de error %d\n" msgid "net: '%s': No such remote\n" msgstr "net: '%s': No existe el recurso remoto\n" msgid "net: '%s': Not mounted\n" msgstr "net: '%s': No está montado\n" msgid "net: Error getting mountpoint for '%s'\n" msgstr "net: Error al obtener el punto de montaje para '%s'\n" msgid "net: No mount command specified for '%s'\n" msgstr "net: No se especificó comando de montaje para '%s'\n" msgid "net: No mountpoint specified for '%s'\n" msgstr "net: No se especificó punto de montaje para '%s'\n" msgid "net: No unmount command for '%s'\n" msgstr "net: No se especificó comando de desmontaje para '%s'\n" msgid "net: Remotes file is undefined\n" msgstr "net: El archivo de recursos remotos no está definido\n" msgid "new: '%s': No such template\n" msgstr "new: '%s': No existe la plantilla\n" msgid "new: '%s': Unsafe filename\n" msgstr "new: '%s': Nombre de archivo no seguro\n" msgid "none" msgstr "ninguno" msgid "not allowed" msgstr "no permitido" msgid "not bound" msgstr "no enlazado" msgid "oc: '%s': Invalid group\n" msgstr "oc: '%s': Grupo inválido\n" msgid "oc: '%s': Invalid user\n" msgstr "oc: '%s': Usuario inválido\n" msgid "oc: Nothing to do" msgstr "oc: No hay nada que hacer" msgid "oc: Nothing to do\n" msgstr "oc: No hay nada que hacer\n" msgid "on disk" msgstr "en disco" msgid "open: '%s': Broken symbolic link to '%s'\n" msgstr "open: '%s': Enlace simbólico roto a '%s'\n" msgid "p: '%s': Cannot unescape filename\n" msgstr "p: '%s': No se puede desescapar el nombre del archivo\n" msgid "pc: %s characters: 9 are expected\n" msgstr "pc: %s caracteres: se esperan 9\n" msgid "pc: %s digits. Either 3 or 4 are expected\n" msgstr "pc: %s dígitos. Se esperan 3 o 4\n" msgid "" "pc: '%c': Invalid digit. Values in the range 0-7 are expected for each " "field\n" msgstr "" "pc: '%c': Dígito inválido. Se esperan valores en el rango 0-7 para cada campo\n" msgid "pc: Applied new permissions to %zu file(s)\n" msgstr "pc: Se aplicaron nuevos permisos a %zu archivo(s)\n" msgid "pc: Changing permissions of '%s': %s\n" msgstr "pc: Cambiando permisos de '%s': %s\n" msgid "pc: Invalid character in field %zu: %s-r%s are expected\n" msgstr "pc: Carácter inválido en el campo %zu: %s-r%s se esperan\n" msgid "pc: Invalid character in field %zu: %s-w%s are expected\n" msgstr "pc: Carácter inválido en el campo %zu: %s-w%s se esperan\n" msgid "pc: Invalid character in field %zu: %s-xsS%s are expected\n" msgstr "pc: Carácter inválido en el campo %zu: %s-xsS%s se esperan\n" msgid "pc: Invalid character in field %zu: %s-xtT%s are expected\n" msgstr "pc: Carácter inválido en el campo %zu: %s-xtT%s se esperan\n" msgid "pc: Nothing to do\n" msgstr "pc: No hay nada que hacer\n" msgid "pf: '%s' is the current profile\n" msgstr "pf: '%s' es el perfil actual\n" msgid "pf: '%s': Cannot create profile: Home directory not found\n" msgstr "pf: '%s': No se puede crear perfil: No se encontró el directorio principal\n" msgid "pf: '%s': Error removing profile\n" msgstr "pf: '%s': Error al eliminar perfil\n" msgid "pf: '%s': Invalid profile name\n" msgstr "pf: '%s': Nombre de perfil inválido\n" msgid "pf: '%s': Is the current profile\n" msgstr "pf: '%s': Es el perfil actual\n" msgid "pf: '%s': No such profile\n" msgstr "pf: '%s': No existe el perfil\n" msgid "" "pf: '%s': No such profile\n" "To add a new profile enter 'pf add PROFILE'\n" msgstr "" "pf: '%s': No existe el perfil\n" "Para agregar un nuevo perfil, ingrese 'pf add PROFILE'\n" msgid "pf: '%s': Profile already exists\n" msgstr "pf: '%s': El perfil ya existe\n" msgid "pf: '%s': Profile successfully renamed to %s%s%s\n" msgstr "pf: '%s': Perfil renombrado con éxito a %s%s%s\n" msgid "pf: 's': Error creating profile\n" msgstr "pf: 's': Error al crear perfil\n" msgid "pf: Cannot rename profile '%s': %s\n" msgstr "pf: No se puede renombrar el perfil '%s': %s\n" msgid "pf: Configuration directory is not set\n" msgstr "pf: El directorio de configuración no está establecido\n" msgid "pf: Error opening the history file\n" msgstr "pf: Error al abrir el archivo de historial\n" msgid "pf: Nothing to do. Source and destination names are the same." msgstr "pf: No hay nada que hacer. Los nombres de origen y destino son los mismos." msgid "pf: mkdir: '%s': Error creating configuration directory\n" msgstr "pf: mkdir: '%s': Error al crear el directorio de configuración\n" msgid "pg: xatoi: Error converting to integer" msgstr "pg: xatoi: Error al convertir a entero" msgid "pin: Error saving pinned directory: %s\n" msgstr "pin: Error al guardar el directorio fijado: %s\n" msgid "pin: No pinned file" msgstr "pin: No hay archivo fijado" msgid "pin: Succesfully pinned '%s'\n" msgstr "pin: Fijado con éxito '%s'\n" msgid "prompt: %s: Error unescaping string\n" msgstr "prompt: %s: Error al desescapar la cadena\n" msgid "prompt: %s: No such prompt\n" msgstr "prompt: %s: No existe este prompt\n" msgid "prompt: No extra prompts defined. Using the default prompt" msgstr "prompt: No se han definido prompts adicionales. Usando el prompt predeterminado" msgid "prompt: No extra prompts found. Using the default prompt" msgstr "prompt: No se encontraron prompts adicionales. Usando el prompt predeterminado" msgid "prompt: Prompts file not found" msgstr "prompt: No se encontró el archivo de prompts" msgid "" "pwd: '%s': Invalid option\n" "Usage: pwd [-LP]\n" msgstr "" "pwd: '%s': Opción inválida\n" "Uso: pwd [-LP]\n" msgid "" "r: '%s': File may still exist (%jd more %s linked to this file before this " "operation)\n" msgstr "" "r: '%s': El archivo puede seguir existiendo (%jd más %s enlazados a este archivo antes de esta operación)\n" msgid "removed" msgstr "eliminado" msgid "restored" msgstr "restaurado" msgid "rr: '%s': Cannot open file\n" msgstr "rr: '%s': No se puede abrir el archivo\n" msgid "rr: '%s': Directory empty\n" msgstr "rr: '%s': Directorio vacío\n" msgid "rr: Nothing to do" msgstr "rr: No hay nada que hacer" msgid "rr: Temporary file changed on disk! Aborting." msgstr "rr: ¡El archivo temporal ha cambiado en disco! Cancelando." msgid "search: %s: Error unescaping filename\n" msgstr "search: %s: Error al desescapar el nombre del archivo\n" msgid "search: '%c': Unrecognized file type\n" msgstr "search: '%c': Tipo de archivo no reconocido\n" msgid "search: No matches found\n" msgstr "search: No se encontraron coincidencias\n" msgid "sel: %s: Invalid regular expression\n" msgstr "sel: %s: Expresión regular inválida\n" msgid "" "sel: '%c': Unrecognized file type.\n" "Try 'sel --help' for more information.\n" msgstr "" "sel: '%c': Tipo de archivo no reconocido.\n" "Pruebe 'sel --help' para obtener más información.\n" msgid "sel: '%s': Already selected\n" msgstr "sel: '%s': Ya seleccionado\n" msgid "sel: Cannot open the selections file" msgstr "sel: No se puede abrir el archivo de selecciones" msgid "sel: Cannot select any more files" msgstr "sel: No se pueden seleccionar más archivos" msgid "sel: Cannot select file '%s': %s\n" msgstr "sel: No se puede seleccionar el archivo '%s': %s\n" msgid "sel: Error expanding path" msgstr "sel: Error al expandir la ruta" msgid "sel: Error writing files into the selections file\n" msgstr "sel: Error al escribir archivos en el archivo de selecciones\n" msgid "sel: No matches found\n" msgstr "sel: No se encontraron coincidencias\n" msgid "sel: No selected files" msgstr "sel: No hay archivos seleccionados" msgid "short" msgstr "corto" msgid "st: %d (%s): Not available in light mode\n" msgstr "st: %d (%s): No disponible en modo ligero\n" msgid "st: %s: No such sort order\n" msgstr "st: %s: No existe este orden de clasificación\n" msgid "st: '%s': Not available in light mode\n" msgstr "st: '%s': No disponible en modo ligero\n" msgid "st: Birth time is not available on this platform" msgstr "st: La hora de creación no está disponible en esta plataforma" msgid "tag: '%s': Cannot create tag: %s\n" msgstr "tag: '%s': No se puede crear la etiqueta: %s\n" msgid "tag: '%s': Cannot create tag: file already exists\n" msgstr "tag: '%s': No se puede crear la etiqueta: el archivo ya existe\n" msgid "tag: '%s': Error creating tag: %s\n" msgstr "tag: '%s': Error al crear la etiqueta: %s\n" msgid "tag: '%s': File already tagged\n" msgstr "tag: '%s': El archivo ya está etiquetado\n" msgid "tag: '%s': File not tagged as %s%s%s\n" msgstr "tag: '%s': El archivo no está etiquetado como %s%s%s\n" msgid "tag: '%s': No such tag\n" msgstr "tag: '%s': No existe esa etiqueta\n" msgid "tag: '%s': Tag already exists\n" msgstr "tag: '%s': La etiqueta ya existe\n" msgid "tag: Cannot merge tags: error moving tagged files" msgstr "tag: No se pueden fusionar etiquetas: error al mover archivos etiquetados" msgid "" "tag: No tag specified. Specify a tag via :TAG. E.g. 'tag add FILE1 " "FILE2 :TAG'" msgstr "" "tag: No se ha especificado una etiqueta. Especifique una etiqueta a través de :TAG. Ej. 'tag add FILE1 FILE2 :TAG'" msgid "tag: No tags" msgstr "tag: No hay etiquetas" msgid "tag: Source and destination are the same tag" msgstr "tag: Origen y destino son la misma etiqueta" msgid "te: Changing permissions of '%s': %s\n" msgstr "te: Cambiando permisos de '%s': %s\n" msgid "trash: %s: Invalid ELN\n" msgstr "trash: %s: ELN no válido\n" msgid "trash: '%s': Cannot remove file from the trash can\n" msgstr "trash: '%s': No se puede eliminar el archivo de la papelera\n" msgid "trash: '%s': Error abbreviating filename\n" msgstr "trash: '%s': Error al abreviar el nombre del archivo\n" msgid "trash: '%s': Error encoding path\n" msgstr "trash: '%s': Error al codificar la ruta\n" msgid "trash: '%s': Error getting file base name\n" msgstr "trash: '%s': Error al obtener el nombre base del archivo\n" msgid "trash: '%s': Error unescaping filename\n" msgstr "trash: '%s': Error al desescapar el nombre del archivo\n" msgid "trash: Cannot trash '%s'\n" msgstr "trash: No se puede enviar '%s' a la papelera\n" msgid "trash: Cannot trash '%s': %s\n" msgstr "trash: No se puede enviar '%s' a la papelera: %s\n" msgid "trash: Cannot trash any more files" msgstr "trash: No se pueden enviar más archivos a la papelera" msgid "trash: No trashed files" msgstr "trash: No hay archivos en la papelera" msgid "trash: The trash directory is undefined\n" msgstr "trash: El directorio de la papelera no está definido\n" msgid "trash: Use 'trash del' to remove trashed files\n" msgstr "trash: Use 'trash del' para eliminar archivos de la papelera\n" msgid "true" msgstr "verdadero" msgid "umask: %s: Out of range (valid values are 000-777)\n" msgstr "umask: %s: Fuera de rango (valores válidos son 000-777)\n" msgid "unavailable" msgstr "no disponible" msgid "undel: %s: Invalid ELN\n" msgstr "undel: %s: ELN no válido\n" msgid "undel: '%s': %s\n" msgstr "undel: '%s': %s\n" msgid "undel: '%s': Destination file exists\n" msgstr "undel: '%s': El archivo de destino ya existe\n" msgid "undel: '%s': Error decoding original path\n" msgstr "undel: '%s': Error al decodificar la ruta original\n" msgid "undel: '%s': No directory specified\n" msgstr "undel: '%s': No se ha especificado un directorio\n" msgid "undel: Filename is NULL or empty\n" msgstr "undel: El nombre del archivo es NULL o vacío\n" msgid "undel: Info file for '%s' not found. Try restoring the file manually.\n" msgstr "undel: No se encontró el archivo de información para '%s'. Intente restaurar el archivo manualmente.\n" msgid "unnamed" msgstr "sin nombre" msgid "unpin: No pinned file" msgstr "unpin: No hay archivo fijado" msgid "unpin: Succesfully unpinned '%s'\n" msgstr "unpin: Desfijado '%s' con éxito\n" msgid "unset: A variable name is required" msgstr "unset: Se requiere un nombre de variable" msgid "view: '%s' does not exist. Entry removed.\n" msgstr "view: '%s' no existe. Entrada eliminada.\n" msgid "view: '%s': Not a regular file\n" msgstr "view: '%s': No es un archivo regular\n" msgid "view: '%s': Removing dangling thumbnail... " msgstr "view: '%s': Eliminando miniatura huérfana... " msgid "view: Cannot access '%s': %s\n" msgstr "view: No se puede acceder a '%s': %s\n" msgid "view: Cannot create temporary file '%s': %s\n" msgstr "view: No se puede crear el archivo temporal '%s': %s\n" msgid "view: Cannot open '%s': %s\n" msgstr "view: No se puede abrir '%s': %s\n" msgid "view: Cannot open temporary file '%s': %s\n" msgstr "view: No se puede abrir el archivo temporal '%s': %s\n" msgid "view: No dangling thumbnails" msgstr "view: No hay miniaturas huérfanas" msgid "" "view: The thumbnails directory does not exist, is not a directory, or there " "are no thumbnails\n" msgstr "" "view: El directorio de miniaturas no existe, no es un directorio o no hay miniaturas\n" msgid "vv: '%s': directory does not exist.\n" msgstr "vv: '%s': el directorio no existe.\n" msgid "ws: %d: Is the current workspace\n" msgstr "ws: %d: Es el espacio de trabajo actual\n" msgid "ws: %d: No such workspace (valid workspaces: 1-%d)\n" msgstr "ws: %d: No existe este espacio de trabajo (espacios de trabajo válidos: 1-%d)\n" msgid "ws: %s: Is the current workspace\n" msgstr "ws: %s: Es el espacio de trabajo actual\n" msgid "ws: %s: No such workspace\n" msgstr "ws: %s: No existe este espacio de trabajo\n" msgid "ws: '%s': Already unset\n" msgstr "ws: '%s': Ya está desestablecido\n" msgid "ws: '%s': Is the current workspace\n" msgstr "ws: '%s': Es el espacio de trabajo actual\n" msgid "ws: '%s': No such workspace (valid workspaces: 1-%d)\n" msgstr "ws: '%s': No existe este espacio de trabajo (espacios de trabajo válidos: 1-%d)\n" msgid "ws: '%s': Workspace unset\n" msgstr "ws: '%s': Espacio de trabajo desestablecido\n" msgid "ws: Current workspace is invalid\n" msgstr "ws: El espacio de trabajo actual es inválido\n" msgid "ws: There are no defined workspaces\n" msgstr "ws: No hay espacios de trabajo definidos\n" msgid "ws: This is already the first workspace\n" msgstr "ws: Este ya es el primer espacio de trabajo\n" msgid "ws: This is already the last workspace\n" msgstr "ws: Este ya es el último espacio de trabajo\n" msgid "xchmod: Empty buffer for filename\n" msgstr "xchmod: Buffer vacío para el nombre del archivo\n" msgid "xchmod: Empty buffer for mode\n" msgstr "xchmod: Buffer vacío para el modo\n" clifm-1.26.3/translations/french/000077500000000000000000000000001506632037700166745ustar00rootroot00000000000000clifm-1.26.3/translations/french/clifm.po000066400000000000000000001233511506632037700203330ustar00rootroot00000000000000# This file is part of CliFM # Copyright (C) 2016-2022 # This file is distributed under the same license as the clifm package. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2022-04-23 14:46-0300\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: properties.c:400 #, c-format msgid "\tBlocks: %s%ld%s" msgstr "" #: properties.c:398 #, c-format msgid "\tBlocks: %s%lld%s" msgstr "" #: properties.c:420 #, c-format msgid "\tGid: %s%u (%s)%s\n" msgstr "" #: properties.c:404 #, c-format msgid "\tIO Block: %s%d%s" msgstr "" #: properties.c:406 #, c-format msgid "\tIO Block: %s%ld%s" msgstr "" #: properties.c:409 #, c-format msgid "\tInode: %s%llu%s\n" msgstr "" #: properties.c:411 #, c-format msgid "\tInode: %s%zu%s\n" msgstr "" #: properties.c:317 #, c-format msgid "\tName: %s%s%s -> %s (broken link)\n" msgstr "" #: properties.c:418 #, c-format msgid "\tUid: %s%u (%s)%s" msgstr "" #: misc.c:1789 #, c-format msgid "" "\n" " Press any key to continue... " msgstr "" #: selection.c:786 #, c-format msgid "" "\n" "%s%sTotal size%s: %s\n" msgstr "" #: bookmarks.c:214 #, c-format msgid "" "\n" "%sEnter '%c' to quit.\n" msgstr "" #: selection.c:990 #, c-format msgid "" "\n" "%sEnter 'q' to quit or 'e' to edit the selections file\n" msgstr "" #: trash.c:559 trash.c:877 #, c-format msgid "" "\n" "%sEnter 'q' to quit.\n" msgstr "" #: archives.c:816 #, c-format msgid "" "\n" "%sNOTE%s: Zstandard does not support compression of multiple files into one " "single compressed file. Files will be compressed rather into multiple " "compressed files using the original file names\n" msgstr "" #: media.c:282 #, c-format msgid "" "\n" "%sUnmounted devices%s\n" "\n" msgstr "" #: colors.c:1831 #, c-format msgid "" "\n" "*The slash followed by a number (/xx) after directories or symbolic links to " "directories indicates the amount of files contained by the corresponding " "directory, excluding self (.) and parent (..) directories.\n" msgstr "" #: misc.c:1697 msgid "" "\n" "NOTE: Some keybindings on Haiku might differ. Take a look at your current " "keybindings via the 'kb' command" msgstr "" #: colors.c:1835 #, c-format msgid "" "\n" "The second field in this list is the code that is to be used to modify the " "color of the corresponding file type in the color scheme file (in the " "\"FiletypeColors\" line), using the same ANSI style color format used by " "dircolors. By default, %s uses only 8/16 colors, but you can use 256 and RGB/" "true colors as well.\n" "\n" msgstr "" #: colors.c:1807 #, c-format msgid " %sfile name%s: bd: Block special file\n" msgstr "" #: colors.c:1818 #, c-format msgid " %sfile name%s: ca: File with capabilities\n" msgstr "" #: colors.c:1813 #, c-format msgid " %sfile name%s: cd: Character special file\n" msgstr "" #: colors.c:1800 #, c-format msgid " %sfile name%s: di: Directory*\n" msgstr "" #: colors.c:1801 #, c-format msgid " %sfile name%s: ed: EMPTY directory\n" msgstr "" #: colors.c:1806 #, c-format msgid " %sfile name%s: ee: Empty executable file\n" msgstr "" #: colors.c:1815 #, c-format msgid " %sfile name%s: ef: Empty (zero-lenght) file\n" msgstr "" #: colors.c:1805 #, c-format msgid " %sfile name%s: ex: Executable file\n" msgstr "" #: colors.c:1814 #, c-format msgid " %sfile name%s: fi: Regular file\n" msgstr "" #: colors.c:1808 #, c-format msgid " %sfile name%s: ln: Symbolic link*\n" msgstr "" #: colors.c:1810 #, c-format msgid " %sfile name%s: mh: Multi-hardlink\n" msgstr "" #: colors.c:1796 #, c-format msgid " %sfile name%s: nd: Directory with no read permission\n" msgstr "" #: colors.c:1802 #, c-format msgid " %sfile name%s: ne: EMPTY directory with no read permission\n" msgstr "" #: colors.c:1798 #, c-format msgid " %sfile name%s: nf: File with no read permission\n" msgstr "" #: colors.c:1828 #, c-format msgid " %sfile name%s: no: Unknown file type\n" msgstr "" #: colors.c:1809 #, c-format msgid " %sfile name%s: or: Broken symbolic link\n" msgstr "" #: colors.c:1825 #, c-format msgid " %sfile name%s: ow: Other-writable and NOT sticky directory*\n" msgstr "" #: colors.c:1812 #, c-format msgid " %sfile name%s: pi: Pipe or FIFO special file\n" msgstr "" #: colors.c:1817 #, c-format msgid " %sfile name%s: sg: SGID file\n" msgstr "" #: colors.c:1811 #, c-format msgid " %sfile name%s: so: Socket file\n" msgstr "" #: colors.c:1819 #, c-format msgid " %sfile name%s: st: Sticky and NOT other-writable directory*\n" msgstr "" #: colors.c:1816 #, c-format msgid " %sfile name%s: su: SUID file\n" msgstr "" #: colors.c:1822 #, c-format msgid " %sfile name%s: tw: Sticky and other-writable directory*\n" msgstr "" #: colors.c:1829 #, c-format msgid " %sfile name%s: uf: Unaccessible (non-stat'able) file\n" msgstr "" #: remotes.c:67 #, c-format msgid " Auto-mount: %s\n" msgstr "" #: remotes.c:65 #, c-format msgid " Auto-unmount: %s\n" msgstr "" #: remotes.c:58 #, c-format msgid " Comment: %s\n" msgstr "" #: remotes.c:62 #, c-format msgid " Mount command: %s\n" msgstr "" #: remotes.c:69 #, c-format msgid " Mounted: %s\n" msgstr "" #: remotes.c:60 #, c-format msgid " Mountpoint: %s\n" msgstr "" #: remotes.c:64 #, c-format msgid " Unmount command: %s\n" msgstr "" #: config.c:1263 #, c-format msgid "" "# %s profile\n" "# Write here the commands you want to be executed at startup\n" "# Ex:\n" "#echo -e \"%s, the command line file manager\"\n" msgstr "" #: strings.c:1631 #, c-format msgid "%c%s: There are no selected files%c" msgstr "" #: selection.c:938 #, c-format msgid "%d file(s) deselected. " msgstr "" #: sort.c:364 #, c-format msgid "%s %s\n" msgstr "" #: misc.c:1757 #, c-format msgid "%s %s (%s), by %s\n" msgstr "" #: misc.c:1776 #, c-format msgid "" "%s %s (%s), by %s\n" "Contact: %s\n" "Website: %s\n" "License: %s\n" msgstr "" #: tags.c:115 #, c-format msgid "%s (error resolving link target)\n" msgstr "" #: sort.c:358 #, c-format msgid "%s (not available: using 'name') %s\n" msgstr "" #: config.c:1320 #, c-format msgid "" "%s created a new MIME list file (%s) It is recommended to edit this file " "(entering 'mm edit' or pressing F6) to add the programs you use and remove " "those you don't. This will make the process of opening files faster and " "smoother\n" msgstr "" #: bookmarks.c:89 #, c-format msgid "" "%s%s\n" "Enter '%c' to edit your bookmarks or '%c' to quit.\n" msgstr "" #: file_operations.c:1055 #, c-format msgid "%s%s%s currently pointing to " msgstr "" #: file_operations.c:1052 #, c-format msgid "%s%s%s currently pointing to nowhere (broken link)\n" msgstr "" #: file_operations.c:1167 #, c-format msgid "%s%s%s successfully relinked to " msgstr "" #: archives.c:1188 #, c-format msgid "%s%s%s: Succesfully mounted on %s\n" msgstr "" #: archives.c:1009 #, c-format msgid "%s%sFile%s: %s\n" msgstr "" #: selection.c:732 #, c-format msgid "%s%sSelection Box%s\n" msgstr "" #: selection.c:543 #, c-format msgid "%s%sTotal size%s: %s\n" msgstr "" #: main.c:759 #, c-format msgid "%s->%s Running as root%s\n" msgstr "" #: history.c:540 history.c:579 #, c-format msgid "%s: !%s: Event not found\n" msgstr "" #: history.c:494 #, c-format msgid "%s: !%s: event not found\n" msgstr "" #: mime.c:1349 #, c-format msgid "" "%s: %d MIME definition(s) imported from the system. Old MIME list file " "stored as %s\n" msgstr "" #: name_cleaner.c:649 #, c-format msgid "%s: %d file(s) bleached\n" msgstr "" #: selection.c:940 #, c-format msgid "%s: %d file(s) deselected. " msgstr "" #: navigation.c:80 #, c-format msgid "%s: %d is already the current workspace\n" msgstr "" #: strings.c:1702 #, c-format msgid "" "%s: %d: ELN-filename conflict. Bypass internal expansions to fix this issue: " "';CMD FILENAME'\n" msgstr "" #: media.c:199 #, c-format msgid "%s: %d: Invalid ELN\n" msgstr "" #: navigation.c:72 #, c-format msgid "%s: %d: Invalid workspace number\n" msgstr "" #: name_cleaner.c:408 prompt.c:462 #, c-format msgid "%s: %s\n" msgstr "" #: file_operations.c:977 #, c-format msgid "" "%s: %s (%s): Cannot open file\n" "Try 'APPLICATION FILENAME'\n" msgstr "" #: aux.c:817 aux.c:831 aux.c:845 #, c-format msgid "%s: %s failed to allocate %zu bytes\n" msgstr "" #: config.c:502 file_operations.c:108 file_operations.c:134 remotes.c:137 #, c-format msgid "%s: %s: %s\n" msgstr "" #: init.c:1692 #, c-format msgid "" "%s: %s: %s\n" "Falling back to default\n" msgstr "" #: init.c:1637 #, c-format msgid "" "%s: %s: %s\n" "Falling back to default configuration directory\n" msgstr "" #: init.c:1604 #, c-format msgid "" "%s: %s: %s\n" "Falling back to the default bookmarks file\n" msgstr "" #: init.c:1664 #, c-format msgid "" "%s: %s: %s\n" "Falling back to the default keybindings file\n" msgstr "" #: file_operations.c:953 #, c-format msgid "%s: %s: Broken symbolic link\n" msgstr "" #: init.c:1628 #, c-format msgid "" "%s: %s: Cannot create directory (error %d)\n" "Falling back to default configuration directory\n" msgstr "" #: profiles.c:302 #, c-format msgid "%s: %s: Cannot create profile: Home directory not found\n" msgstr "" #: file_operations.c:1741 #, c-format msgid "%s: %s: Cannot create symlink: %s\n" msgstr "" #: tags.c:384 #, c-format msgid "%s: %s: Cannot create tag\n" msgstr "" #: tags.c:50 #, c-format msgid "%s: %s: Cannot create tag: file already exists\n" msgstr "" #: file_operations.c:251 #, c-format msgid "%s: %s: Cannot open file\n" msgstr "" #: file_operations.c:210 #, c-format msgid "%s: %s: Directory empty\n" msgstr "" #: profiles.c:371 #, c-format msgid "%s: %s: Error creating profile\n" msgstr "" #: tags.c:277 #, c-format msgid "%s: %s: Error creating tag\n" msgstr "" #: config.c:1240 #, c-format msgid "%s: %s: Error creating tags directory. Tag function disabled\n" msgstr "" #: aux.c:143 #, c-format msgid "%s: %s: Error deescaping string\n" msgstr "" #: file_operations.c:1022 file_operations.c:1111 #, c-format msgid "%s: %s: Error dequoting file\n" msgstr "" #: bookmarks.c:794 misc.c:754 name_cleaner.c:523 properties.c:684 #: readline.c:401 search.c:145 search.c:552 #, c-format msgid "%s: %s: Error dequoting file name\n" msgstr "" #: file_operations.c:776 file_operations.c:911 #, c-format msgid "%s: %s: Error dequoting filename\n" msgstr "" #: navigation.c:281 #, c-format msgid "%s: %s: Error dequoting string\n" msgstr "" #: aux.c:159 navigation.c:288 #, c-format msgid "%s: %s: Error expanding tilde\n" msgstr "" #: remotes.c:255 trash.c:136 #, c-format msgid "%s: %s: Error getting parent directory\n" msgstr "" #: strings.c:1766 #, c-format msgid "%s: %s: Error getting variable name\n" msgstr "" #: mime.c:282 #, c-format msgid "%s: %s: Error opening file\n" msgstr "" #: strings.c:1591 strings.c:1733 strings.c:1973 strings.c:2047 #, c-format msgid "%s: %s: Error quoting file name\n" msgstr "" #: profiles.c:415 #, c-format msgid "%s: %s: Error removing profile\n" msgstr "" #: file_operations.c:814 #, c-format msgid "%s: %s: File already exists. Trying with '%s' instead\n" msgstr "" #: tags.c:48 #, c-format msgid "%s: %s: File already tagged\n" msgstr "" #: tags.c:531 #, c-format msgid "%s: %s: File not tagged as %s%s%s\n" msgstr "" #: file_operations.c:1095 #, c-format msgid "%s: %s: Invalid ELN\n" msgstr "" #: exec.c:1781 exec.c:1808 #, c-format msgid "%s: %s: Invalid argument. Try 'fz -h'\n" msgstr "" #: exec.c:628 #, c-format msgid "%s: %s: Invalid number\n" msgstr "" #: exec.c:1567 #, c-format msgid "%s: %s: Is a directory\n" msgstr "" #: misc.c:916 #, c-format msgid "%s: %s: No alias found\n" msgstr "" #: mime.c:1445 mime.c:1449 #, c-format msgid "%s: %s: No associated application found\n" msgstr "" #: navigation.c:371 #, c-format msgid "%s: %s: No matches found\n" msgstr "" #: exec.c:1056 #, c-format msgid "%s: %s: No such alias\n" msgstr "" #: colors.c:955 #, c-format msgid "%s: %s: No such color scheme. Falling back to default\n" msgstr "" #: colors.c:1064 #, c-format msgid "%s: %s: No such color scheme. Falling back to the default one\n" msgstr "" #: jump.c:432 #, c-format msgid "%s: %s: No such order number\n" msgstr "" #: profiles.c:393 #, c-format msgid "%s: %s: No such profile\n" msgstr "" #: profiles.c:132 #, c-format msgid "" "%s: %s: No such profile\n" "To add a new profile enter 'pf add PROFILE'\n" msgstr "" #: remotes.c:118 #, c-format msgid "%s: %s: No such remote\n" msgstr "" #: selection.c:888 #, c-format msgid "%s: %s: No such selected file\n" msgstr "" #: sort.c:457 #, c-format msgid "%s: %s: No such sorting method\n" msgstr "" #: tags.c:75 tags.c:158 #, c-format msgid "%s: %s: No such tag\n" msgstr "" #: misc.c:634 #, c-format msgid "%s: %s: Not a directory\n" msgstr "" #: file_operations.c:1044 #, c-format msgid "%s: %s: Not a symbolic link\n" msgstr "" #: remotes.c:225 #, c-format msgid "%s: %s: Not mounted\n" msgstr "" #: sanitize.c:368 #, c-format msgid "" "%s: %s: Only command base names are allowed. Ex: 'nano' instead of '/usr/bin/" "nano'\n" msgstr "" #: profiles.c:297 #, c-format msgid "%s: %s: Profile already exists\n" msgstr "" #: remotes.c:209 #, c-format msgid "%s: %s: Remote mounted on %s\n" msgstr "" #: tags.c:317 #, c-format msgid "%s: %s: Successfully removed tag\n" msgstr "" #: main.c:826 profiles.c:165 #, c-format msgid "" "%s: %s: System shell not found. Please edit the configuration file to " "specify a working shell.\n" msgstr "" #: tags.c:271 #, c-format msgid "%s: %s: Tag already exists\n" msgstr "" #: media.c:503 #, c-format msgid "%s: %s: This feature is not available on Haiku\n" msgstr "" #: init.c:1643 #, c-format msgid "%s: %s: Using alternative configuration directory\n" msgstr "" #: misc.c:934 #, c-format msgid "%s: %zu aliases were successfully imported\n" msgstr "" #: init.c:207 #, c-format msgid "" "%s: %zu: Invalid workspace.\n" "Falling back to workspace %zu\n" msgstr "" #: jump.c:410 #, c-format msgid "%s: '%c': Invalid option\n" msgstr "" #: search.c:114 search.c:535 selection.c:429 #, c-format msgid "%s: '%c': Unrecognized file type\n" msgstr "" #: profiles.c:141 #, c-format msgid "%s: '%s' is the current profile\n" msgstr "" #: config.c:1889 #, c-format msgid "%s: '%s': %s. Using the current working directory as starting path\n" msgstr "" #: config.c:1228 #, c-format msgid "" "%s: '%s': Directory not writable. Bookmarks, commands logs, and commands " "history are disabled. Program messages won't be persistent. Using default " "options\n" msgstr "" #: config.c:1202 #, c-format msgid "%s: '%s': Directory not writable. Trash function disabled\n" msgstr "" #: config.c:2023 misc.c:379 #, c-format msgid "%s: '%s': Invalid regular expression\n" msgstr "" #: profiles.c:363 #, c-format msgid "%s: '%s': Profile succesfully created\n" msgstr "" #: profiles.c:406 #, c-format msgid "%s: '%s': Profile successfully removed\n" msgstr "" #: exec.c:1462 #, c-format msgid "%s: '%s': Syntax error\n" msgstr "" #: checks.c:107 #, c-format msgid "" "%s: '%s': Unsupported terminal. This terminal cannot understand escape " "sequences\n" msgstr "" #: config.c:550 #, c-format msgid "" "%s: '%s': Using a temporary directory for the Selection Box. Selected files " "won't be persistent across reboots" msgstr "" #: navigation.c:338 #, c-format msgid "%s: /: No parent directory\n" msgstr "" #: misc.c:937 #, c-format msgid "%s: 1 alias was successfully imported\n" msgstr "" #: config.c:99 #, c-format msgid "%s: Access to configuration files is not allowed in stealth mode\n" msgstr "" #: misc.c:902 #, c-format msgid "%s: Alias already exists\n" msgstr "" #: misc.c:855 #, c-format msgid "%s: Alias conflicts with internal command\n" msgstr "" #: config.c:113 #, c-format msgid "%s: Cannot access the configuration file\n" msgstr "" #: init.c:149 #, c-format msgid "" "%s: Cannot access the home directory. Trash, bookmarks, commands logs, and " "commands history are disabled. Program messages and selected files won't be " "persistent. Using default options\n" msgstr "" #: tags.c:643 #, c-format msgid "%s: Cannot merge tags: error moving tagged files\n" msgstr "" #: bookmarks.c:597 #, c-format msgid "%s: Cannot open the bookmarks file\n" msgstr "" #: history.c:248 #, c-format msgid "%s: Could not save directory history: %s\n" msgstr "" #: colors.c:539 #, c-format msgid "%s: Current color scheme: %s\n" msgstr "" #: colors.c:1789 #, c-format msgid "%s: Currently running without colors\n" msgstr "" #: misc.c:607 #, c-format msgid "" "%s: Default terminal not set. Use the configuration file (F10) to set it\n" msgstr "" #: trash.c:150 #, c-format msgid "%s: Directory is immutable\n" msgstr "" #: jump.c:291 #, c-format msgid "%s: Directory jumper function disabled\n" msgstr "" #: init.c:1035 init.c:1043 selection.c:486 #, c-format msgid "%s: Error expanding path\n" msgstr "" #: init.c:1246 #, c-format msgid "%s: Error expanding tilde. Using default opener\n" msgstr "" #: mime.c:460 #, c-format msgid "%s: Error getting home directory\n" msgstr "" #: main.c:848 #, c-format msgid "%s: Error getting hostname\n" msgstr "" #: mime.c:1463 #, c-format msgid "%s: Error getting mime-type\n" msgstr "" #: remotes.c:230 #, c-format msgid "%s: Error getting mountpoint for '%s'\n" msgstr "" #: misc.c:1051 #, c-format msgid "%s: Error getting variable value\n" msgstr "" #: misc.c:777 #, c-format msgid "%s: Error lauching new instance\n" msgstr "" #: checks.c:99 #, c-format msgid "%s: Error opening terminal: unknown\n" msgstr "" #: profiles.c:217 #, c-format msgid "%s: Error opening the history file\n" msgstr "" #: checks.c:512 #, c-format msgid "%s: Error parsing aliased command\n" msgstr "" #: history.c:503 history.c:522 history.c:556 #, c-format msgid "%s: Error parsing history command\n" msgstr "" #: media.c:447 #, c-format msgid "%s: Error retrieving mountpoint\n" msgstr "" #: init.c:387 #, c-format msgid "%s: Error retrieving user data\n" msgstr "" #: misc.c:968 #, c-format msgid "%s: Error saving last visited directory\n" msgstr "" #: misc.c:1566 #, c-format msgid "%s: Error storing pinned directory\n" msgstr "" #: selection.c:572 #, c-format msgid "%s: Error writing selected files to the selections file\n" msgstr "" #: exec.c:535 #, c-format msgid "%s: External commands are not allowed. Run 'ext on' to enable them.\n" msgstr "" #: init.c:1350 #, c-format msgid "%s: FZF not found. Falling back to standard TAB completion\n" msgstr "" #: init.c:251 main.c:815 #, c-format msgid "%s: Fatal error! Failed retrieving current working directory\n" msgstr "" #: trash.c:203 #, c-format msgid "%s: File is immutable\n" msgstr "" #: misc.c:614 #, c-format msgid "%s: Function only available for graphical environments\n" msgstr "" #: history.c:428 #, c-format msgid "%s: History function disabled\n" msgstr "" #: bookmarks.c:694 bookmarks.c:775 #, c-format msgid "%s: Invalid bookmark\n" msgstr "" #: navigation.c:625 #, c-format msgid "%s: Invalid history entry\n" msgstr "" #: exec.c:1654 #, c-format msgid "%s: Lira: %s\n" msgstr "" #: init.c:1609 #, c-format msgid "%s: Loaded alternative bookmarks file\n" msgstr "" #: init.c:1698 #, c-format msgid "%s: Loaded alternative configuration file\n" msgstr "" #: init.c:1670 #, c-format msgid "%s: Loaded alternative keybindings file\n" msgstr "" #: exec.c:1100 #, c-format msgid "%s: Log function disabled\n" msgstr "" #: strings.c:645 strings.c:702 #, c-format msgid "%s: Missing '%c'\n" msgstr "" #: remotes.c:386 #, c-format msgid "%s: Mounting remote...\n" msgstr "" #: misc.c:386 #, c-format msgid "%s: New filter successfully set\n" msgstr "" #: misc.c:926 #, c-format msgid "%s: No alias imported\n" msgstr "" #: exec.c:1022 exec.c:1042 #, c-format msgid "%s: No aliases found\n" msgstr "" #: colors.c:408 #, c-format msgid "%s: No color schemes found\n" msgstr "" #: selection.c:583 #, c-format msgid "%s: No matches found\n" msgstr "" #: media.c:193 media.c:400 #, c-format msgid "%s: No mount application found. Install either udevil or udisks2\n" msgstr "" #: media.c:517 #, c-format msgid "%s: No mount command found. Install either udevil or udisks2\n" msgstr "" #: remotes.c:172 #, c-format msgid "%s: No mount command specified for '%s'\n" msgstr "" #: remotes.c:123 #, c-format msgid "%s: No mountpoint specified for '%s'\n" msgstr "" #: misc.c:717 #, c-format msgid "" "%s: No option specified for '%s'\n" "Trying '%s -e %s %s'\n" msgstr "" #: exec.c:1421 keybinds.c:1444 misc.c:1624 #, c-format msgid "%s: No pinned file\n" msgstr "" #: remotes.c:48 #, c-format msgid "%s: No remotes defined\n" msgstr "" #: bookmarks.c:678 #, c-format msgid "%s: No such ELN\n" msgstr "" #: bookmarks.c:699 bookmarks.c:780 #, c-format msgid "%s: No such bookmark\n" msgstr "" #: colors.c:496 #, c-format msgid "%s: No such color scheme\n" msgstr "" #: trash.c:122 #, c-format msgid "%s: No such file or directory\n" msgstr "" #: tags.c:455 #, c-format msgid "" "%s: No tag specified. Specify a tag via :TAG. E.g. tag FILE1 FILE2 :TAG\n" msgstr "" #: tags.c:67 #, c-format msgid "%s: No tags found, Use 'tag new' to create new tags\n" msgstr "" #: remotes.c:236 #, c-format msgid "%s: No unmount command found for '%s'\n" msgstr "" #: file_operations.c:486 name_cleaner.c:561 name_cleaner.c:611 #, c-format msgid "%s: Nothing to do\n" msgstr "" #: mime.c:531 #, c-format msgid "%s: Nothing was imported. No MIME definitions found\n" msgstr "" #: mime.c:454 #, c-format msgid "%s: Nothing was imported. No graphical environment found\n" msgstr "" #: trash.c:90 trash.c:182 trash.c:190 trash.c:210 trash.c:226 #, c-format msgid "%s: Permission denied\n" msgstr "" #: keybinds.c:96 keybinds.c:139 #, c-format msgid "%s: Restart the program for changes to take effect\n" msgstr "" #: config.c:2086 #, c-format msgid "" "%s: Running in stealth mode: trash, persistent selection and directory " "history, just as bookmarks, logs and configuration files, are disabled.\n" msgstr "" #: misc.c:1616 #, c-format msgid "%s: Succesfully pinned '%s'\n" msgstr "" #: tags.c:282 #, c-format msgid "%s: Successfully created tag\n" msgstr "" #: media.c:558 #, c-format msgid "%s: There are no available %s\n" msgstr "" #: exec.c:932 exec.c:950 #, c-format msgid "%s: There are no messages\n" msgstr "" #: exec.c:415 #, c-format msgid "%s: To gracefully quit enter 'q'\n" msgstr "" #: trash.c:797 trash.c:1085 #, c-format msgid "%s: Trash function disabled\n" msgstr "" #: misc.c:1703 #, c-format msgid "%s: Unable to find any pager\n" msgstr "" #: media.c:221 #, c-format msgid "%s: Unmounted %s\n" msgstr "" #: remotes.c:423 #, c-format msgid "%s: Unmounting remote...\n" msgstr "" #: main.c:744 #, c-format msgid "%s: Unsupported CPU architecture\n" msgstr "" #: main.c:750 #, c-format msgid "%s: Unsupported operating system\n" msgstr "" #: exec.c:2194 #, c-format msgid "%s: archiving: %s\n" msgstr "" #: exec.c:2175 #, c-format msgid "%s: bleach: %s\n" msgstr "" #: bookmarks.c:814 #, c-format msgid "%s: bookmarks: %s\n" msgstr "" #: navigation.c:444 #, c-format msgid "%s: cd: Home directory not found\n" msgstr "" #: colors.c:512 #, c-format msgid "" "%s: color schemes: %s\n" "TIP: To change the current color scheme use the following environment " "variables: CLIFM_FILE_COLORS, CLIFM_IFACE_COLORS, and CLIFM_EXT_COLORS\n" msgstr "" #: mime.c:1613 #, c-format msgid "%s: file: Command not found\n" msgstr "" #: config.c:1499 #, c-format msgid "%s: fopen: '%s': %s. Using default values.\n" msgstr "" #: checks.c:161 #, c-format msgid "%s: fzf not found. Falling back to standard TAB completion\n" msgstr "" #: init.c:1357 #, c-format msgid "%s: fzftab: %s\n" msgstr "" #: init.c:1379 #, c-format msgid "%s: fzytab: %s\n" msgstr "" #: init.c:1335 #, c-format msgid "%s: highlight: %s\n" msgstr "" #: exec.c:893 init.c:1267 #, c-format msgid "%s: icons: %s\n" msgstr "" #: jump.c:663 #, c-format msgid "%s: jump: No matches found\n" msgstr "" #: media.c:510 #, c-format msgid "%s: media: Function only available on Linux systems\n" msgstr "" #: profiles.c:315 #, c-format msgid "%s: mkdir: %s: Error creating configuration directory\n" msgstr "" #: config.c:1216 #, c-format msgid "" "%s: mkdir: '%s': Error creating configuration directory. Bookmarks, commands " "logs, and command history are disabled. Program messages won't be " "persistent. Using default options\n" msgstr "" #: config.c:1194 #, c-format msgid "" "%s: mkdir: '%s': Error creating trash directory. Trash function disabled\n" msgstr "" #: config.c:1277 #, c-format msgid "" "%s: mkdir: Error creating colors directory. Using the default color scheme\n" msgstr "" #: config.c:1289 #, c-format msgid "" "%s: mkdir: Error creating plugins directory. The actions function is " "disabled\n" msgstr "" #: init.c:1504 #, c-format msgid "" "%s: option requires an argument -- '%c'\n" "Try '%s --help' for more information.\n" msgstr "" #: selection.c:123 #, c-format msgid "%s: sel: %s: Already selected\n" msgstr "" #: selection.c:327 #, c-format msgid "%s: sel: %s: Invalid regular expression\n" msgstr "" #: trash.c:637 #, c-format msgid "%s: trash: %d: Invalid ELN\n" msgstr "" #: exec.c:1742 exec.c:1766 init.c:1290 #, c-format msgid "%s: trash: %s\n" msgstr "" #: trash.c:234 #, c-format msgid "%s: trash: %s (%s): Unsupported file type\n" msgstr "" #: trash.c:419 #, c-format msgid "" "%s: trash: %s/%s: Failed removing trash file\n" "Try removing it manually\n" msgstr "" #: trash.c:350 #, c-format msgid "%s: trash: %s: Error getting file name\n" msgstr "" #: trash.c:291 #, c-format msgid "%s: trash: %s: Error removing trashed file\n" msgstr "" #: trash.c:394 #, c-format msgid "%s: trash: %s: Failed copying file to Trash\n" msgstr "" #: trash.c:440 #, c-format msgid "%s: trash: %s: Failed encoding path\n" msgstr "" #: trash.c:615 #, c-format msgid "%s: trash: %s: Invalid ELN\n" msgstr "" #: trash.c:596 trash.c:646 #, c-format msgid "%s: trash: Error trashing %s\n" msgstr "" #: checks.c:123 #, c-format msgid "%s: udisks2 not found. Falling back to udevil\n" msgstr "" #: trash.c:933 #, c-format msgid "%s: undel: %d: Invalid ELN\n" msgstr "" #: trash.c:714 #, c-format msgid "%s: undel: %s: Error decoding original path\n" msgstr "" #: trash.c:770 #, c-format msgid "%s: undel: %s: Error removing info file\n" msgstr "" #: trash.c:777 #, c-format msgid "%s: undel: %s: Error restoring trashed file\n" msgstr "" #: trash.c:676 #, c-format msgid "" "%s: undel: Info file for '%s' not found. Try restoring the file manually\n" msgstr "" #: init.c:1525 #, c-format msgid "%s: unknown option character '\\%x'\n" msgstr "" #: init.c:1521 #, c-format msgid "" "%s: unrecognized option '%c'\n" "Try '%s --help' for more information.\n" msgstr "" #: init.c:1513 #, c-format msgid "" "%s: unrecognized option '%s'\n" "Try '%s --help' for more information.\n" msgstr "" #: bookmarks.c:609 #, c-format msgid "" "%sBookmarks Manager%s\n" "\n" msgstr "" #: bookmarks.c:208 #, c-format msgid "" "%sBookmarks%s\n" "\n" msgstr "" #: colors.c:1844 #, c-format msgid "" "%sExtension colors%s\n" "\n" msgstr "" #: colors.c:1795 #, c-format msgid "" "%sFile type colors%s\n" "\n" msgstr "" #: archives.c:1028 #, c-format msgid "%sFile%s: %s\n" msgstr "" #: media.c:526 #, c-format msgid "" "%sMountpoints%s\n" "\n" msgstr "" #: archives.c:940 #, c-format msgid "%sNOTE%s: Using Zstandard\n" msgstr "" #: selection.c:551 #, c-format msgid "%sSelection Box%s\n" msgstr "" #: trash.c:535 trash.c:862 #, c-format msgid "" "%sTrashed files%s\n" "\n" msgstr "" #: archives.c:1205 #, c-format msgid "" "%s[e]%sxtract %s[E]%sxtract-to-dir %s[l]%sist %s[m]%sount %s[r]%sepack " "%s[q]%suit\n" msgstr "" #: archives.c:321 #, c-format msgid "" "%s[e]%sxtract %s[E]%sxtract-to-dir %s[l]%sist %s[t]%sest %s[m]%sount " "%s[q]%suit\n" msgstr "" #: archives.c:757 archives.c:941 #, c-format msgid "%s[e]%sxtract %s[t]%sest %s[i]%snfo %s[q]%suit\n" msgstr "" #: selection.c:941 #, c-format msgid "%zu file(s) currently selected\n" msgstr "" #: selection.c:601 #, c-format msgid "%zu files are now in the Selection Box\n" msgstr "" #: selection.c:603 #, c-format msgid "" "%zu selected file(s):\n" "\n" msgstr "" #: search.c:634 #, c-format msgid "'%s': Invalid regular expression\n" msgstr "" #: properties.c:424 #, c-format msgid "Access: \t%s%s%s\n" msgstr "" #: bookmarks.c:292 msgid "All bookmarks succesfully removed\n" msgstr "" #: selection.c:1106 msgid "All files deselected\n" msgstr "" #: mime.c:1482 #, c-format msgid "Associated application: %s [%s]\n" msgstr "" #: mime.c:1432 msgid "Associated application: None\n" msgstr "" #: mime.c:1479 #, c-format msgid "Associated application: ad [built-in] [%s]\n" msgstr "" #: exec.c:844 #, c-format msgid "Auto-open disabled\n" msgstr "" #: exec.c:841 #, c-format msgid "Auto-open enabled\n" msgstr "" #: exec.c:846 #, c-format msgid "Auto-open is %s\n" msgstr "" #: exec.c:818 #, c-format msgid "Autocd disabled\n" msgstr "" #: exec.c:815 #, c-format msgid "Autocd enabled\n" msgstr "" #: exec.c:820 #, c-format msgid "Autocd is %s\n" msgstr "" #: properties.c:429 #, c-format msgid "Birth: \t\t%s%s%s\n" msgstr "" #: properties.c:388 #, c-format msgid "Block special file" msgstr "" #: bookmarks.c:450 msgid "Bookmark line example: [sc]name:path" msgstr "" #: bookmarks.c:217 msgid "Bookmark(s) to be deleted (ex: 1 2-6, or *): " msgstr "" #: bookmarks.c:819 #, c-format msgid "Bookmarks function disabled\n" msgstr "" #: bookmarks.c:799 #, c-format msgid "Bookmarks: %s: %s\n" msgstr "" #: properties.c:426 #, c-format msgid "Change: \t%s%s%s\n" msgstr "" #: properties.c:389 #, c-format msgid "Character special file" msgstr "" #: bookmarks.c:93 msgid "Choose a bookmark: " msgstr "" #: media.c:611 msgid "Choose a mountpoint/device: " msgstr "" #: media.c:609 media.c:613 msgid "Choose a mountpoint: " msgstr "" #: mime.c:586 msgid "Choose an application ('q' to quit): " msgstr "" #: listing.c:309 #, c-format msgid "Color scheme %s->%s %s\n" msgstr "" #: exec.c:879 msgid "Columns disabled\n" msgstr "" #: exec.c:872 msgid "Columns enabled\n" msgstr "" #: file_operations.c:1562 msgid "Continue? [y/N] " msgstr "" #: tags.c:393 #, c-format msgid "Created new tag %s%s%s\n" msgstr "" #: misc.c:396 #, c-format msgid "Current filter: %c%s\n" msgstr "" #: properties.c:414 #, c-format msgid "Device: %s%d%s" msgstr "" #: properties.c:416 #, c-format msgid "Device: %s%zu%s" msgstr "" #: properties.c:385 #, c-format msgid "Directory" msgstr "" #: selection.c:737 msgid "Empty" msgstr "" #: file_operations.c:739 msgid "End filename with a slash to create a directory" msgstr "" #: media.c:601 msgid "Enter 'iELN' for device information. Ex: i4" msgstr "" #: archives.c:1081 media.c:600 msgid "Enter 'q' to quit" msgstr "" #: file_operations.c:1716 msgid "Enter links suffix ('q' to quit): " msgstr "" #: history.c:129 msgid "Error getting command!" msgstr "" #: mime.c:344 msgid "Error opening temporary file\n" msgstr "" #: archives.c:410 archives.c:419 archives.c:523 archives.c:532 msgid "Error querying file type\n" msgstr "" #: listing.c:1670 listing.c:2218 #, c-format msgid "Excluded files: %d\n" msgstr "" #: exec.c:793 #, c-format msgid "External commands allowed\n" msgstr "" #: exec.c:789 #, c-format msgid "External commands are %s\n" msgstr "" #: exec.c:796 #, c-format msgid "External commands disallowed\n" msgstr "" #: archives.c:62 msgid "Extraction path ('q' to quit): " msgstr "" #: properties.c:390 #, c-format msgid "Fifo" msgstr "" #: archives.c:673 msgid "File name ('q' to quit): " msgstr "" #: bookmarks.c:572 #, c-format msgid "File succesfully bookmarked\n" msgstr "" #: selection.c:994 msgid "File(s) to be deselected (ex: 1 2-6, or *): " msgstr "" #: trash.c:563 msgid "File(s) to be removed (ex: 1 2-6, or *): " msgstr "" #: trash.c:881 msgid "File(s) to be undeleted (ex: 1 2-6, or *): " msgstr "" #: file_operations.c:740 msgid "Filename ('q' to quit): " msgstr "" #: exec.c:725 msgid "Files counter disabled\n" msgstr "" #: exec.c:718 msgid "Files counter enabled\n" msgstr "" #: misc.c:369 msgid "Filter unset" msgstr "" #: keybinds.c:842 #, c-format msgid "Folders first %s\n" msgstr "" #: exec.c:698 msgid "Folders first disabled\n" msgstr "" #: exec.c:694 msgid "Folders first enabled\n" msgstr "" #: exec.c:689 #, c-format msgid "Folders first is %s\n" msgstr "" #: exec.c:1803 msgid "Full directory size disabled\n" msgstr "" #: exec.c:1792 msgid "Full directory size enabled\n" msgstr "" #: exec.c:1799 msgid "Full directory size is already disabled" msgstr "" #: exec.c:1788 msgid "Full directory size is already enabled" msgstr "" #: search.c:211 msgid "Glob: No matches found. Trying regex..." msgstr "" #: keybinds.c:894 #, c-format msgid "Hidden files %s\n" msgstr "" #: exec.c:1121 msgid "Hidden files disabled\n" msgstr "" #: exec.c:1128 msgid "Hidden files enabled\n" msgstr "" #: exec.c:1113 #, c-format msgid "Hidden files is %s\n" msgstr "" #: history.c:405 #, c-format msgid "History is %s\n" msgstr "" #: archives.c:692 #, c-format msgid "Invalid file name\n" msgstr "" #: name_cleaner.c:572 msgid "Is this OK? [y/N/(e)dit] " msgstr "" #: history.c:88 #, c-format msgid "Logs %s\n" msgstr "" #: history.c:103 msgid "Logs already disabled" msgstr "" #: history.c:93 msgid "Logs already enabled" msgstr "" #: history.c:106 msgid "Logs succesfully disabled" msgstr "" #: history.c:96 msgid "Logs successfully enabled" msgstr "" #: keybinds.c:810 #, c-format msgid "Long view mode %s\n" msgstr "" #: mime.c:1472 #, c-format msgid "MIME type: %s\n" msgstr "" #: search.c:457 #, c-format msgid "Matches found: %d\n" msgstr "" #: search.c:810 #, c-format msgid "Matches found: %zu\n" msgstr "" #: exec.c:622 exec.c:634 #, c-format msgid "Max files set to %d\n" msgstr "" #: exec.c:615 msgid "Max files unset\n" msgstr "" #: exec.c:603 #, c-format msgid "Max files: %d\n" msgstr "" #: exec.c:601 msgid "Max files: unset" msgstr "" #: keybinds.c:339 #, c-format msgid "Max name length set back to %d\n" msgstr "" #: keybinds.c:337 msgid "Max name length unset\n" msgstr "" #: media.c:504 msgid "Media" msgstr "" #: properties.c:425 #, c-format msgid "Modify: \t%s%s%s\n" msgstr "" #: media.c:524 msgid "Mounted devices" msgstr "" #: media.c:504 media.c:523 msgid "Mountpoints" msgstr "" #: jump.c:313 msgid "" "NOTE 2: An asterisk next rank values means that the corresponding directory " "is bookmarked, pinned, or currently used in some workspace\n" msgstr "" #: jump.c:311 msgid "" "NOTE: First time access is displayed in days, while last time access is " "displayed in hours" msgstr "" #: mime.c:1471 remotes.c:56 #, c-format msgid "Name: %s\n" msgstr "" #: config.c:87 #, c-format msgid "New configuration file written to '%s'\n" msgstr "" #: archives.c:1085 msgid "New format (ex: .tar.xz): " msgstr "" #: file_operations.c:1068 msgid "New path ('q' to quit): " msgstr "" #: remotes.c:69 msgid "No" msgstr "" #: config.c:58 msgid "No configuration file found" msgstr "" #: tags.c:167 #, c-format msgid "No file tagged as '%s'\n" msgstr "" #: misc.c:361 msgid "No filter set" msgstr "" #: search.c:673 search.c:812 #, c-format msgid "No matches found\n" msgstr "" #: exec.c:1210 msgid "No pinned file" msgstr "" #: mime.c:1378 msgid "No such ELN" msgstr "" #: mime.c:1471 msgid "None" msgstr "" #: config.c:80 #, c-format msgid "Old configuration file stored as '%s'\n" msgstr "" #: keybinds.c:1533 #, c-format msgid "Only directories %s\n" msgstr "" #: exec.c:975 #, c-format msgid "Opener set to '%s'\n" msgstr "" #: archives.c:117 archives.c:762 archives.c:948 msgid "Operation: " msgstr "" #: jump.c:316 msgid "Order\tVisits\tFirst\tLast\tRank\tDirectory" msgstr "" #: exec.c:765 msgid "Pager disabled\n" msgstr "" #: exec.c:761 msgid "Pager enabled\n" msgstr "" #: exec.c:1208 #, c-format msgid "Pinned file: %s\n" msgstr "" #: properties.c:391 #, c-format msgid "Regular file" msgstr "" #: file_operations.c:1127 msgid "Relink as a broken symbolic link? [y/n] " msgstr "" #: properties.c:434 #, c-format msgid "Size: \t\t%s%s%s\n" msgstr "" #: properties.c:386 #, c-format msgid "Socket" msgstr "" #: listing.c:304 msgid "Sorted by: " msgstr "" #: sort.c:466 msgid "Sorting method: " msgstr "" #: misc.c:1643 #, c-format msgid "Succesfully unpinned %s\n" msgstr "" #: tags.c:656 #, c-format msgid "Successfully merged %s%s%s into %s%s%s\n" msgstr "" #: bookmarks.c:365 #, c-format msgid "Successfully removed '%s'\n" msgstr "" #: tags.c:484 #, c-format msgid "Successfully tagged %zu file(s)\n" msgstr "" #: tags.c:554 #, c-format msgid "Successfully untagged %zu file(s)\n" msgstr "" #: exec.c:991 exec.c:995 keybinds.c:870 msgid "Switched back to normal mode\n" msgstr "" #: keybinds.c:868 msgid "Switched to light mode\n" msgstr "" #: properties.c:387 #, c-format msgid "Symbolic link" msgstr "" #: exec.c:733 msgid "The files counter is disabled" msgstr "" #: exec.c:731 msgid "The files counter is enabled" msgstr "" #: exec.c:756 #, c-format msgid "The files pager is %s\n" msgstr "" #: exec.c:1188 #, c-format msgid "Toggled executable bit on %zu %s\n" msgstr "" #: exec.c:1689 #, c-format msgid "" "Total files: %zu\n" "Directories: %zu\n" "Regular files: %zu\n" "Executable files: %zu\n" "Hidden files: %zu\n" "SUID files: %zu\n" "SGID files: %zu\n" "Files w/capabilities: %zu\n" "FIFO/pipes: %zu\n" "Sockets: %zu\n" "Block devices: %zu\n" "Character devices: %zu\n" "Symbolic links: %zu\n" "Broken symbolic links: %zu\n" "Multi-link files: %zu\n" "Files w/extended attributes: %zu\n" "Other-writable files: %zu\n" "Sticky files: %zu\n" "Unknown file types: %zu\n" "Unstatable files: %zu\n" msgstr "" #: properties.c:441 msgid "Total size: \t" msgstr "" #: listing.c:1400 #, c-format msgid "" "Total size: %s%s%s\n" "Largest file: %s%s%s %c%s%s%s%c\n" msgstr "" #: mime.c:555 msgid "Try 'mm, mime edit APPLICATION'\n" msgstr "" #: exec.c:661 msgid "Unicode disabled" msgstr "" #: exec.c:658 msgid "Unicode enabled" msgstr "" #: exec.c:655 #, c-format msgid "Unicode is %s\n" msgstr "" #: archives.c:669 msgid "" "Use extension to specify archive/compression type (defaults to .tar.gz)\n" "Example: myarchive.xz" msgstr "" #: remotes.c:70 msgid "Yes" msgstr "" #: actions.c:371 msgid "actions: No actions defined. Use the 'actions edit' command to add some" msgstr "" #: exec.c:790 msgid "allowed" msgstr "" #: archives.c:713 #, c-format msgid "archiver: %s: Error dequoting file name\n" msgstr "" #: archives.c:909 #, c-format msgid "archiver: %s: Not an archive/compressed file\n" msgstr "" #: sort.c:378 #, c-format msgid "atime %s\n" msgstr "" #: bookmarks.c:200 bookmarks.c:244 #, c-format msgid "bookmarks: %s: No such bookmark\n" msgstr "" #: bookmarks.c:416 #, c-format msgid "bookmarks: %s: Path already bookmarked\n" msgstr "" #: bookmarks.c:493 #, c-format msgid "bookmarks: %s: This name is already in use\n" msgstr "" #: bookmarks.c:461 #, c-format msgid "bookmarks: %s: This shortcut is already in use\n" msgstr "" #: bookmarks.c:274 #, c-format msgid "" "bookmarks: All bookmarks were deleted\n" " However, a backup copy was created (%s)\n" msgstr "" #: bookmarks.c:279 #, c-format msgid "bookmarks: Error creating backup file. No bookmark was deleted\n" msgstr "" #: bookmarks.c:309 #, c-format msgid "bookmarks: Error creating temporary file\n" msgstr "" #: bookmarks.c:546 #, c-format msgid "bookmarks: Error generating the bookmark line\n" msgstr "" #: bookmarks.c:391 bookmarks.c:554 bookmarks.c:563 #, c-format msgid "bookmarks: Error opening the bookmarks file\n" msgstr "" #: bookmarks.c:226 #, c-format msgid "bookmarks: Error parsing input\n" msgstr "" #: bookmarks.c:162 msgid "bookmarks: There are no bookmarks" msgstr "" #: sort.c:381 #, c-format msgid "btime %s\n" msgstr "" #: sort.c:383 #, c-format msgid "btime (not available: using 'ctime') %s\n" msgstr "" #: file_operations.c:1473 #, c-format msgid "bulk: %s\n" msgstr "" #: file_operations.c:1436 #, c-format msgid "bulk: %s: Error dequoting file name\n" msgstr "" #: file_operations.c:1514 msgid "bulk: Line mismatch in renaming file\n" msgstr "" #: file_operations.c:1493 file_operations.c:1548 msgid "bulk: Nothing to do" msgstr "" #: sort.c:387 #, c-format msgid "ctime %s\n" msgstr "" #: selection.c:1053 #, c-format msgid "desel: '%s': Invalid ELN\n" msgstr "" #: selection.c:1042 #, c-format msgid "desel: '%s': Invalid entry\n" msgstr "" #: selection.c:1094 msgid "desel: There are no selected files" msgstr "" #: media.c:559 msgid "devices" msgstr "" #: exec.c:655 exec.c:690 exec.c:757 exec.c:820 exec.c:846 exec.c:1114 #: history.c:89 msgid "disabled" msgstr "" #: exec.c:655 exec.c:690 exec.c:757 exec.c:820 exec.c:846 exec.c:1114 #: history.c:88 msgid "enabled" msgstr "" #: sort.c:393 #, c-format msgid "extension %s\n" msgstr "" #: remotes.c:66 remotes.c:68 msgid "false" msgstr "" #: exec.c:1189 msgid "file" msgstr "" #: exec.c:1189 msgid "files" msgstr "" #: navigation.c:619 #, c-format msgid "history: %d: No such ELN\n" msgstr "" #: sort.c:395 #, c-format msgid "inode %s\n" msgstr "" #: media.c:559 msgid "mountpoints" msgstr "" #: media.c:561 msgid "mp: There are no available mountpoints\n" msgstr "" #: sort.c:389 #, c-format msgid "mtime %s\n" msgstr "" #: sort.c:374 #, c-format msgid "name %s\n" msgstr "" #: sort.c:372 msgid "none" msgstr "" #: exec.c:790 msgid "not allowed" msgstr "" #: sort.c:376 #, c-format msgid "size %s\n" msgstr "" #: trash.c:1028 #, c-format msgid "trash: %s: %s\n" msgstr "" #: trash.c:1034 #, c-format msgid "trash: %s: Cannot trash a %s device\n" msgstr "" #: trash.c:1016 #, c-format msgid "trash: Cannot trash '%s'\n" msgstr "" #: trash.c:541 trash.c:830 trash.c:984 msgid "trash: No trashed files" msgstr "" #: trash.c:263 msgid "trash: There are no trashed files" msgstr "" #: trash.c:1022 msgid "trash: Use 'trash del' to remove trashed files" msgstr "" #: remotes.c:66 remotes.c:68 msgid "true" msgstr "" #: trash.c:908 #, c-format msgid "undel: %s: Invalid ELN\n" msgstr "" #: properties.c:418 properties.c:420 msgid "unknown" msgstr "" #: sort.c:391 #, c-format msgid "version %s\n" msgstr "" clifm-1.26.3/translations/german/000077500000000000000000000000001506632037700167005ustar00rootroot00000000000000clifm-1.26.3/translations/german/clifm.po000066400000000000000000001233511506632037700203370ustar00rootroot00000000000000# This file is part of CliFM # Copyright (C) 2016-2022 # This file is distributed under the same license as the clifm package. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2022-04-23 14:46-0300\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: properties.c:400 #, c-format msgid "\tBlocks: %s%ld%s" msgstr "" #: properties.c:398 #, c-format msgid "\tBlocks: %s%lld%s" msgstr "" #: properties.c:420 #, c-format msgid "\tGid: %s%u (%s)%s\n" msgstr "" #: properties.c:404 #, c-format msgid "\tIO Block: %s%d%s" msgstr "" #: properties.c:406 #, c-format msgid "\tIO Block: %s%ld%s" msgstr "" #: properties.c:409 #, c-format msgid "\tInode: %s%llu%s\n" msgstr "" #: properties.c:411 #, c-format msgid "\tInode: %s%zu%s\n" msgstr "" #: properties.c:317 #, c-format msgid "\tName: %s%s%s -> %s (broken link)\n" msgstr "" #: properties.c:418 #, c-format msgid "\tUid: %s%u (%s)%s" msgstr "" #: misc.c:1789 #, c-format msgid "" "\n" " Press any key to continue... " msgstr "" #: selection.c:786 #, c-format msgid "" "\n" "%s%sTotal size%s: %s\n" msgstr "" #: bookmarks.c:214 #, c-format msgid "" "\n" "%sEnter '%c' to quit.\n" msgstr "" #: selection.c:990 #, c-format msgid "" "\n" "%sEnter 'q' to quit or 'e' to edit the selections file\n" msgstr "" #: trash.c:559 trash.c:877 #, c-format msgid "" "\n" "%sEnter 'q' to quit.\n" msgstr "" #: archives.c:816 #, c-format msgid "" "\n" "%sNOTE%s: Zstandard does not support compression of multiple files into one " "single compressed file. Files will be compressed rather into multiple " "compressed files using the original file names\n" msgstr "" #: media.c:282 #, c-format msgid "" "\n" "%sUnmounted devices%s\n" "\n" msgstr "" #: colors.c:1831 #, c-format msgid "" "\n" "*The slash followed by a number (/xx) after directories or symbolic links to " "directories indicates the amount of files contained by the corresponding " "directory, excluding self (.) and parent (..) directories.\n" msgstr "" #: misc.c:1697 msgid "" "\n" "NOTE: Some keybindings on Haiku might differ. Take a look at your current " "keybindings via the 'kb' command" msgstr "" #: colors.c:1835 #, c-format msgid "" "\n" "The second field in this list is the code that is to be used to modify the " "color of the corresponding file type in the color scheme file (in the " "\"FiletypeColors\" line), using the same ANSI style color format used by " "dircolors. By default, %s uses only 8/16 colors, but you can use 256 and RGB/" "true colors as well.\n" "\n" msgstr "" #: colors.c:1807 #, c-format msgid " %sfile name%s: bd: Block special file\n" msgstr "" #: colors.c:1818 #, c-format msgid " %sfile name%s: ca: File with capabilities\n" msgstr "" #: colors.c:1813 #, c-format msgid " %sfile name%s: cd: Character special file\n" msgstr "" #: colors.c:1800 #, c-format msgid " %sfile name%s: di: Directory*\n" msgstr "" #: colors.c:1801 #, c-format msgid " %sfile name%s: ed: EMPTY directory\n" msgstr "" #: colors.c:1806 #, c-format msgid " %sfile name%s: ee: Empty executable file\n" msgstr "" #: colors.c:1815 #, c-format msgid " %sfile name%s: ef: Empty (zero-lenght) file\n" msgstr "" #: colors.c:1805 #, c-format msgid " %sfile name%s: ex: Executable file\n" msgstr "" #: colors.c:1814 #, c-format msgid " %sfile name%s: fi: Regular file\n" msgstr "" #: colors.c:1808 #, c-format msgid " %sfile name%s: ln: Symbolic link*\n" msgstr "" #: colors.c:1810 #, c-format msgid " %sfile name%s: mh: Multi-hardlink\n" msgstr "" #: colors.c:1796 #, c-format msgid " %sfile name%s: nd: Directory with no read permission\n" msgstr "" #: colors.c:1802 #, c-format msgid " %sfile name%s: ne: EMPTY directory with no read permission\n" msgstr "" #: colors.c:1798 #, c-format msgid " %sfile name%s: nf: File with no read permission\n" msgstr "" #: colors.c:1828 #, c-format msgid " %sfile name%s: no: Unknown file type\n" msgstr "" #: colors.c:1809 #, c-format msgid " %sfile name%s: or: Broken symbolic link\n" msgstr "" #: colors.c:1825 #, c-format msgid " %sfile name%s: ow: Other-writable and NOT sticky directory*\n" msgstr "" #: colors.c:1812 #, c-format msgid " %sfile name%s: pi: Pipe or FIFO special file\n" msgstr "" #: colors.c:1817 #, c-format msgid " %sfile name%s: sg: SGID file\n" msgstr "" #: colors.c:1811 #, c-format msgid " %sfile name%s: so: Socket file\n" msgstr "" #: colors.c:1819 #, c-format msgid " %sfile name%s: st: Sticky and NOT other-writable directory*\n" msgstr "" #: colors.c:1816 #, c-format msgid " %sfile name%s: su: SUID file\n" msgstr "" #: colors.c:1822 #, c-format msgid " %sfile name%s: tw: Sticky and other-writable directory*\n" msgstr "" #: colors.c:1829 #, c-format msgid " %sfile name%s: uf: Unaccessible (non-stat'able) file\n" msgstr "" #: remotes.c:67 #, c-format msgid " Auto-mount: %s\n" msgstr "" #: remotes.c:65 #, c-format msgid " Auto-unmount: %s\n" msgstr "" #: remotes.c:58 #, c-format msgid " Comment: %s\n" msgstr "" #: remotes.c:62 #, c-format msgid " Mount command: %s\n" msgstr "" #: remotes.c:69 #, c-format msgid " Mounted: %s\n" msgstr "" #: remotes.c:60 #, c-format msgid " Mountpoint: %s\n" msgstr "" #: remotes.c:64 #, c-format msgid " Unmount command: %s\n" msgstr "" #: config.c:1263 #, c-format msgid "" "# %s profile\n" "# Write here the commands you want to be executed at startup\n" "# Ex:\n" "#echo -e \"%s, the command line file manager\"\n" msgstr "" #: strings.c:1631 #, c-format msgid "%c%s: There are no selected files%c" msgstr "" #: selection.c:938 #, c-format msgid "%d file(s) deselected. " msgstr "" #: sort.c:364 #, c-format msgid "%s %s\n" msgstr "" #: misc.c:1757 #, c-format msgid "%s %s (%s), by %s\n" msgstr "" #: misc.c:1776 #, c-format msgid "" "%s %s (%s), by %s\n" "Contact: %s\n" "Website: %s\n" "License: %s\n" msgstr "" #: tags.c:115 #, c-format msgid "%s (error resolving link target)\n" msgstr "" #: sort.c:358 #, c-format msgid "%s (not available: using 'name') %s\n" msgstr "" #: config.c:1320 #, c-format msgid "" "%s created a new MIME list file (%s) It is recommended to edit this file " "(entering 'mm edit' or pressing F6) to add the programs you use and remove " "those you don't. This will make the process of opening files faster and " "smoother\n" msgstr "" #: bookmarks.c:89 #, c-format msgid "" "%s%s\n" "Enter '%c' to edit your bookmarks or '%c' to quit.\n" msgstr "" #: file_operations.c:1055 #, c-format msgid "%s%s%s currently pointing to " msgstr "" #: file_operations.c:1052 #, c-format msgid "%s%s%s currently pointing to nowhere (broken link)\n" msgstr "" #: file_operations.c:1167 #, c-format msgid "%s%s%s successfully relinked to " msgstr "" #: archives.c:1188 #, c-format msgid "%s%s%s: Succesfully mounted on %s\n" msgstr "" #: archives.c:1009 #, c-format msgid "%s%sFile%s: %s\n" msgstr "" #: selection.c:732 #, c-format msgid "%s%sSelection Box%s\n" msgstr "" #: selection.c:543 #, c-format msgid "%s%sTotal size%s: %s\n" msgstr "" #: main.c:759 #, c-format msgid "%s->%s Running as root%s\n" msgstr "" #: history.c:540 history.c:579 #, c-format msgid "%s: !%s: Event not found\n" msgstr "" #: history.c:494 #, c-format msgid "%s: !%s: event not found\n" msgstr "" #: mime.c:1349 #, c-format msgid "" "%s: %d MIME definition(s) imported from the system. Old MIME list file " "stored as %s\n" msgstr "" #: name_cleaner.c:649 #, c-format msgid "%s: %d file(s) bleached\n" msgstr "" #: selection.c:940 #, c-format msgid "%s: %d file(s) deselected. " msgstr "" #: navigation.c:80 #, c-format msgid "%s: %d is already the current workspace\n" msgstr "" #: strings.c:1702 #, c-format msgid "" "%s: %d: ELN-filename conflict. Bypass internal expansions to fix this issue: " "';CMD FILENAME'\n" msgstr "" #: media.c:199 #, c-format msgid "%s: %d: Invalid ELN\n" msgstr "" #: navigation.c:72 #, c-format msgid "%s: %d: Invalid workspace number\n" msgstr "" #: name_cleaner.c:408 prompt.c:462 #, c-format msgid "%s: %s\n" msgstr "" #: file_operations.c:977 #, c-format msgid "" "%s: %s (%s): Cannot open file\n" "Try 'APPLICATION FILENAME'\n" msgstr "" #: aux.c:817 aux.c:831 aux.c:845 #, c-format msgid "%s: %s failed to allocate %zu bytes\n" msgstr "" #: config.c:502 file_operations.c:108 file_operations.c:134 remotes.c:137 #, c-format msgid "%s: %s: %s\n" msgstr "" #: init.c:1692 #, c-format msgid "" "%s: %s: %s\n" "Falling back to default\n" msgstr "" #: init.c:1637 #, c-format msgid "" "%s: %s: %s\n" "Falling back to default configuration directory\n" msgstr "" #: init.c:1604 #, c-format msgid "" "%s: %s: %s\n" "Falling back to the default bookmarks file\n" msgstr "" #: init.c:1664 #, c-format msgid "" "%s: %s: %s\n" "Falling back to the default keybindings file\n" msgstr "" #: file_operations.c:953 #, c-format msgid "%s: %s: Broken symbolic link\n" msgstr "" #: init.c:1628 #, c-format msgid "" "%s: %s: Cannot create directory (error %d)\n" "Falling back to default configuration directory\n" msgstr "" #: profiles.c:302 #, c-format msgid "%s: %s: Cannot create profile: Home directory not found\n" msgstr "" #: file_operations.c:1741 #, c-format msgid "%s: %s: Cannot create symlink: %s\n" msgstr "" #: tags.c:384 #, c-format msgid "%s: %s: Cannot create tag\n" msgstr "" #: tags.c:50 #, c-format msgid "%s: %s: Cannot create tag: file already exists\n" msgstr "" #: file_operations.c:251 #, c-format msgid "%s: %s: Cannot open file\n" msgstr "" #: file_operations.c:210 #, c-format msgid "%s: %s: Directory empty\n" msgstr "" #: profiles.c:371 #, c-format msgid "%s: %s: Error creating profile\n" msgstr "" #: tags.c:277 #, c-format msgid "%s: %s: Error creating tag\n" msgstr "" #: config.c:1240 #, c-format msgid "%s: %s: Error creating tags directory. Tag function disabled\n" msgstr "" #: aux.c:143 #, c-format msgid "%s: %s: Error deescaping string\n" msgstr "" #: file_operations.c:1022 file_operations.c:1111 #, c-format msgid "%s: %s: Error dequoting file\n" msgstr "" #: bookmarks.c:794 misc.c:754 name_cleaner.c:523 properties.c:684 #: readline.c:401 search.c:145 search.c:552 #, c-format msgid "%s: %s: Error dequoting file name\n" msgstr "" #: file_operations.c:776 file_operations.c:911 #, c-format msgid "%s: %s: Error dequoting filename\n" msgstr "" #: navigation.c:281 #, c-format msgid "%s: %s: Error dequoting string\n" msgstr "" #: aux.c:159 navigation.c:288 #, c-format msgid "%s: %s: Error expanding tilde\n" msgstr "" #: remotes.c:255 trash.c:136 #, c-format msgid "%s: %s: Error getting parent directory\n" msgstr "" #: strings.c:1766 #, c-format msgid "%s: %s: Error getting variable name\n" msgstr "" #: mime.c:282 #, c-format msgid "%s: %s: Error opening file\n" msgstr "" #: strings.c:1591 strings.c:1733 strings.c:1973 strings.c:2047 #, c-format msgid "%s: %s: Error quoting file name\n" msgstr "" #: profiles.c:415 #, c-format msgid "%s: %s: Error removing profile\n" msgstr "" #: file_operations.c:814 #, c-format msgid "%s: %s: File already exists. Trying with '%s' instead\n" msgstr "" #: tags.c:48 #, c-format msgid "%s: %s: File already tagged\n" msgstr "" #: tags.c:531 #, c-format msgid "%s: %s: File not tagged as %s%s%s\n" msgstr "" #: file_operations.c:1095 #, c-format msgid "%s: %s: Invalid ELN\n" msgstr "" #: exec.c:1781 exec.c:1808 #, c-format msgid "%s: %s: Invalid argument. Try 'fz -h'\n" msgstr "" #: exec.c:628 #, c-format msgid "%s: %s: Invalid number\n" msgstr "" #: exec.c:1567 #, c-format msgid "%s: %s: Is a directory\n" msgstr "" #: misc.c:916 #, c-format msgid "%s: %s: No alias found\n" msgstr "" #: mime.c:1445 mime.c:1449 #, c-format msgid "%s: %s: No associated application found\n" msgstr "" #: navigation.c:371 #, c-format msgid "%s: %s: No matches found\n" msgstr "" #: exec.c:1056 #, c-format msgid "%s: %s: No such alias\n" msgstr "" #: colors.c:955 #, c-format msgid "%s: %s: No such color scheme. Falling back to default\n" msgstr "" #: colors.c:1064 #, c-format msgid "%s: %s: No such color scheme. Falling back to the default one\n" msgstr "" #: jump.c:432 #, c-format msgid "%s: %s: No such order number\n" msgstr "" #: profiles.c:393 #, c-format msgid "%s: %s: No such profile\n" msgstr "" #: profiles.c:132 #, c-format msgid "" "%s: %s: No such profile\n" "To add a new profile enter 'pf add PROFILE'\n" msgstr "" #: remotes.c:118 #, c-format msgid "%s: %s: No such remote\n" msgstr "" #: selection.c:888 #, c-format msgid "%s: %s: No such selected file\n" msgstr "" #: sort.c:457 #, c-format msgid "%s: %s: No such sorting method\n" msgstr "" #: tags.c:75 tags.c:158 #, c-format msgid "%s: %s: No such tag\n" msgstr "" #: misc.c:634 #, c-format msgid "%s: %s: Not a directory\n" msgstr "" #: file_operations.c:1044 #, c-format msgid "%s: %s: Not a symbolic link\n" msgstr "" #: remotes.c:225 #, c-format msgid "%s: %s: Not mounted\n" msgstr "" #: sanitize.c:368 #, c-format msgid "" "%s: %s: Only command base names are allowed. Ex: 'nano' instead of '/usr/bin/" "nano'\n" msgstr "" #: profiles.c:297 #, c-format msgid "%s: %s: Profile already exists\n" msgstr "" #: remotes.c:209 #, c-format msgid "%s: %s: Remote mounted on %s\n" msgstr "" #: tags.c:317 #, c-format msgid "%s: %s: Successfully removed tag\n" msgstr "" #: main.c:826 profiles.c:165 #, c-format msgid "" "%s: %s: System shell not found. Please edit the configuration file to " "specify a working shell.\n" msgstr "" #: tags.c:271 #, c-format msgid "%s: %s: Tag already exists\n" msgstr "" #: media.c:503 #, c-format msgid "%s: %s: This feature is not available on Haiku\n" msgstr "" #: init.c:1643 #, c-format msgid "%s: %s: Using alternative configuration directory\n" msgstr "" #: misc.c:934 #, c-format msgid "%s: %zu aliases were successfully imported\n" msgstr "" #: init.c:207 #, c-format msgid "" "%s: %zu: Invalid workspace.\n" "Falling back to workspace %zu\n" msgstr "" #: jump.c:410 #, c-format msgid "%s: '%c': Invalid option\n" msgstr "" #: search.c:114 search.c:535 selection.c:429 #, c-format msgid "%s: '%c': Unrecognized file type\n" msgstr "" #: profiles.c:141 #, c-format msgid "%s: '%s' is the current profile\n" msgstr "" #: config.c:1889 #, c-format msgid "%s: '%s': %s. Using the current working directory as starting path\n" msgstr "" #: config.c:1228 #, c-format msgid "" "%s: '%s': Directory not writable. Bookmarks, commands logs, and commands " "history are disabled. Program messages won't be persistent. Using default " "options\n" msgstr "" #: config.c:1202 #, c-format msgid "%s: '%s': Directory not writable. Trash function disabled\n" msgstr "" #: config.c:2023 misc.c:379 #, c-format msgid "%s: '%s': Invalid regular expression\n" msgstr "" #: profiles.c:363 #, c-format msgid "%s: '%s': Profile succesfully created\n" msgstr "" #: profiles.c:406 #, c-format msgid "%s: '%s': Profile successfully removed\n" msgstr "" #: exec.c:1462 #, c-format msgid "%s: '%s': Syntax error\n" msgstr "" #: checks.c:107 #, c-format msgid "" "%s: '%s': Unsupported terminal. This terminal cannot understand escape " "sequences\n" msgstr "" #: config.c:550 #, c-format msgid "" "%s: '%s': Using a temporary directory for the Selection Box. Selected files " "won't be persistent across reboots" msgstr "" #: navigation.c:338 #, c-format msgid "%s: /: No parent directory\n" msgstr "" #: misc.c:937 #, c-format msgid "%s: 1 alias was successfully imported\n" msgstr "" #: config.c:99 #, c-format msgid "%s: Access to configuration files is not allowed in stealth mode\n" msgstr "" #: misc.c:902 #, c-format msgid "%s: Alias already exists\n" msgstr "" #: misc.c:855 #, c-format msgid "%s: Alias conflicts with internal command\n" msgstr "" #: config.c:113 #, c-format msgid "%s: Cannot access the configuration file\n" msgstr "" #: init.c:149 #, c-format msgid "" "%s: Cannot access the home directory. Trash, bookmarks, commands logs, and " "commands history are disabled. Program messages and selected files won't be " "persistent. Using default options\n" msgstr "" #: tags.c:643 #, c-format msgid "%s: Cannot merge tags: error moving tagged files\n" msgstr "" #: bookmarks.c:597 #, c-format msgid "%s: Cannot open the bookmarks file\n" msgstr "" #: history.c:248 #, c-format msgid "%s: Could not save directory history: %s\n" msgstr "" #: colors.c:539 #, c-format msgid "%s: Current color scheme: %s\n" msgstr "" #: colors.c:1789 #, c-format msgid "%s: Currently running without colors\n" msgstr "" #: misc.c:607 #, c-format msgid "" "%s: Default terminal not set. Use the configuration file (F10) to set it\n" msgstr "" #: trash.c:150 #, c-format msgid "%s: Directory is immutable\n" msgstr "" #: jump.c:291 #, c-format msgid "%s: Directory jumper function disabled\n" msgstr "" #: init.c:1035 init.c:1043 selection.c:486 #, c-format msgid "%s: Error expanding path\n" msgstr "" #: init.c:1246 #, c-format msgid "%s: Error expanding tilde. Using default opener\n" msgstr "" #: mime.c:460 #, c-format msgid "%s: Error getting home directory\n" msgstr "" #: main.c:848 #, c-format msgid "%s: Error getting hostname\n" msgstr "" #: mime.c:1463 #, c-format msgid "%s: Error getting mime-type\n" msgstr "" #: remotes.c:230 #, c-format msgid "%s: Error getting mountpoint for '%s'\n" msgstr "" #: misc.c:1051 #, c-format msgid "%s: Error getting variable value\n" msgstr "" #: misc.c:777 #, c-format msgid "%s: Error lauching new instance\n" msgstr "" #: checks.c:99 #, c-format msgid "%s: Error opening terminal: unknown\n" msgstr "" #: profiles.c:217 #, c-format msgid "%s: Error opening the history file\n" msgstr "" #: checks.c:512 #, c-format msgid "%s: Error parsing aliased command\n" msgstr "" #: history.c:503 history.c:522 history.c:556 #, c-format msgid "%s: Error parsing history command\n" msgstr "" #: media.c:447 #, c-format msgid "%s: Error retrieving mountpoint\n" msgstr "" #: init.c:387 #, c-format msgid "%s: Error retrieving user data\n" msgstr "" #: misc.c:968 #, c-format msgid "%s: Error saving last visited directory\n" msgstr "" #: misc.c:1566 #, c-format msgid "%s: Error storing pinned directory\n" msgstr "" #: selection.c:572 #, c-format msgid "%s: Error writing selected files to the selections file\n" msgstr "" #: exec.c:535 #, c-format msgid "%s: External commands are not allowed. Run 'ext on' to enable them.\n" msgstr "" #: init.c:1350 #, c-format msgid "%s: FZF not found. Falling back to standard TAB completion\n" msgstr "" #: init.c:251 main.c:815 #, c-format msgid "%s: Fatal error! Failed retrieving current working directory\n" msgstr "" #: trash.c:203 #, c-format msgid "%s: File is immutable\n" msgstr "" #: misc.c:614 #, c-format msgid "%s: Function only available for graphical environments\n" msgstr "" #: history.c:428 #, c-format msgid "%s: History function disabled\n" msgstr "" #: bookmarks.c:694 bookmarks.c:775 #, c-format msgid "%s: Invalid bookmark\n" msgstr "" #: navigation.c:625 #, c-format msgid "%s: Invalid history entry\n" msgstr "" #: exec.c:1654 #, c-format msgid "%s: Lira: %s\n" msgstr "" #: init.c:1609 #, c-format msgid "%s: Loaded alternative bookmarks file\n" msgstr "" #: init.c:1698 #, c-format msgid "%s: Loaded alternative configuration file\n" msgstr "" #: init.c:1670 #, c-format msgid "%s: Loaded alternative keybindings file\n" msgstr "" #: exec.c:1100 #, c-format msgid "%s: Log function disabled\n" msgstr "" #: strings.c:645 strings.c:702 #, c-format msgid "%s: Missing '%c'\n" msgstr "" #: remotes.c:386 #, c-format msgid "%s: Mounting remote...\n" msgstr "" #: misc.c:386 #, c-format msgid "%s: New filter successfully set\n" msgstr "" #: misc.c:926 #, c-format msgid "%s: No alias imported\n" msgstr "" #: exec.c:1022 exec.c:1042 #, c-format msgid "%s: No aliases found\n" msgstr "" #: colors.c:408 #, c-format msgid "%s: No color schemes found\n" msgstr "" #: selection.c:583 #, c-format msgid "%s: No matches found\n" msgstr "" #: media.c:193 media.c:400 #, c-format msgid "%s: No mount application found. Install either udevil or udisks2\n" msgstr "" #: media.c:517 #, c-format msgid "%s: No mount command found. Install either udevil or udisks2\n" msgstr "" #: remotes.c:172 #, c-format msgid "%s: No mount command specified for '%s'\n" msgstr "" #: remotes.c:123 #, c-format msgid "%s: No mountpoint specified for '%s'\n" msgstr "" #: misc.c:717 #, c-format msgid "" "%s: No option specified for '%s'\n" "Trying '%s -e %s %s'\n" msgstr "" #: exec.c:1421 keybinds.c:1444 misc.c:1624 #, c-format msgid "%s: No pinned file\n" msgstr "" #: remotes.c:48 #, c-format msgid "%s: No remotes defined\n" msgstr "" #: bookmarks.c:678 #, c-format msgid "%s: No such ELN\n" msgstr "" #: bookmarks.c:699 bookmarks.c:780 #, c-format msgid "%s: No such bookmark\n" msgstr "" #: colors.c:496 #, c-format msgid "%s: No such color scheme\n" msgstr "" #: trash.c:122 #, c-format msgid "%s: No such file or directory\n" msgstr "" #: tags.c:455 #, c-format msgid "" "%s: No tag specified. Specify a tag via :TAG. E.g. tag FILE1 FILE2 :TAG\n" msgstr "" #: tags.c:67 #, c-format msgid "%s: No tags found, Use 'tag new' to create new tags\n" msgstr "" #: remotes.c:236 #, c-format msgid "%s: No unmount command found for '%s'\n" msgstr "" #: file_operations.c:486 name_cleaner.c:561 name_cleaner.c:611 #, c-format msgid "%s: Nothing to do\n" msgstr "" #: mime.c:531 #, c-format msgid "%s: Nothing was imported. No MIME definitions found\n" msgstr "" #: mime.c:454 #, c-format msgid "%s: Nothing was imported. No graphical environment found\n" msgstr "" #: trash.c:90 trash.c:182 trash.c:190 trash.c:210 trash.c:226 #, c-format msgid "%s: Permission denied\n" msgstr "" #: keybinds.c:96 keybinds.c:139 #, c-format msgid "%s: Restart the program for changes to take effect\n" msgstr "" #: config.c:2086 #, c-format msgid "" "%s: Running in stealth mode: trash, persistent selection and directory " "history, just as bookmarks, logs and configuration files, are disabled.\n" msgstr "" #: misc.c:1616 #, c-format msgid "%s: Succesfully pinned '%s'\n" msgstr "" #: tags.c:282 #, c-format msgid "%s: Successfully created tag\n" msgstr "" #: media.c:558 #, c-format msgid "%s: There are no available %s\n" msgstr "" #: exec.c:932 exec.c:950 #, c-format msgid "%s: There are no messages\n" msgstr "" #: exec.c:415 #, c-format msgid "%s: To gracefully quit enter 'q'\n" msgstr "" #: trash.c:797 trash.c:1085 #, c-format msgid "%s: Trash function disabled\n" msgstr "" #: misc.c:1703 #, c-format msgid "%s: Unable to find any pager\n" msgstr "" #: media.c:221 #, c-format msgid "%s: Unmounted %s\n" msgstr "" #: remotes.c:423 #, c-format msgid "%s: Unmounting remote...\n" msgstr "" #: main.c:744 #, c-format msgid "%s: Unsupported CPU architecture\n" msgstr "" #: main.c:750 #, c-format msgid "%s: Unsupported operating system\n" msgstr "" #: exec.c:2194 #, c-format msgid "%s: archiving: %s\n" msgstr "" #: exec.c:2175 #, c-format msgid "%s: bleach: %s\n" msgstr "" #: bookmarks.c:814 #, c-format msgid "%s: bookmarks: %s\n" msgstr "" #: navigation.c:444 #, c-format msgid "%s: cd: Home directory not found\n" msgstr "" #: colors.c:512 #, c-format msgid "" "%s: color schemes: %s\n" "TIP: To change the current color scheme use the following environment " "variables: CLIFM_FILE_COLORS, CLIFM_IFACE_COLORS, and CLIFM_EXT_COLORS\n" msgstr "" #: mime.c:1613 #, c-format msgid "%s: file: Command not found\n" msgstr "" #: config.c:1499 #, c-format msgid "%s: fopen: '%s': %s. Using default values.\n" msgstr "" #: checks.c:161 #, c-format msgid "%s: fzf not found. Falling back to standard TAB completion\n" msgstr "" #: init.c:1357 #, c-format msgid "%s: fzftab: %s\n" msgstr "" #: init.c:1379 #, c-format msgid "%s: fzytab: %s\n" msgstr "" #: init.c:1335 #, c-format msgid "%s: highlight: %s\n" msgstr "" #: exec.c:893 init.c:1267 #, c-format msgid "%s: icons: %s\n" msgstr "" #: jump.c:663 #, c-format msgid "%s: jump: No matches found\n" msgstr "" #: media.c:510 #, c-format msgid "%s: media: Function only available on Linux systems\n" msgstr "" #: profiles.c:315 #, c-format msgid "%s: mkdir: %s: Error creating configuration directory\n" msgstr "" #: config.c:1216 #, c-format msgid "" "%s: mkdir: '%s': Error creating configuration directory. Bookmarks, commands " "logs, and command history are disabled. Program messages won't be " "persistent. Using default options\n" msgstr "" #: config.c:1194 #, c-format msgid "" "%s: mkdir: '%s': Error creating trash directory. Trash function disabled\n" msgstr "" #: config.c:1277 #, c-format msgid "" "%s: mkdir: Error creating colors directory. Using the default color scheme\n" msgstr "" #: config.c:1289 #, c-format msgid "" "%s: mkdir: Error creating plugins directory. The actions function is " "disabled\n" msgstr "" #: init.c:1504 #, c-format msgid "" "%s: option requires an argument -- '%c'\n" "Try '%s --help' for more information.\n" msgstr "" #: selection.c:123 #, c-format msgid "%s: sel: %s: Already selected\n" msgstr "" #: selection.c:327 #, c-format msgid "%s: sel: %s: Invalid regular expression\n" msgstr "" #: trash.c:637 #, c-format msgid "%s: trash: %d: Invalid ELN\n" msgstr "" #: exec.c:1742 exec.c:1766 init.c:1290 #, c-format msgid "%s: trash: %s\n" msgstr "" #: trash.c:234 #, c-format msgid "%s: trash: %s (%s): Unsupported file type\n" msgstr "" #: trash.c:419 #, c-format msgid "" "%s: trash: %s/%s: Failed removing trash file\n" "Try removing it manually\n" msgstr "" #: trash.c:350 #, c-format msgid "%s: trash: %s: Error getting file name\n" msgstr "" #: trash.c:291 #, c-format msgid "%s: trash: %s: Error removing trashed file\n" msgstr "" #: trash.c:394 #, c-format msgid "%s: trash: %s: Failed copying file to Trash\n" msgstr "" #: trash.c:440 #, c-format msgid "%s: trash: %s: Failed encoding path\n" msgstr "" #: trash.c:615 #, c-format msgid "%s: trash: %s: Invalid ELN\n" msgstr "" #: trash.c:596 trash.c:646 #, c-format msgid "%s: trash: Error trashing %s\n" msgstr "" #: checks.c:123 #, c-format msgid "%s: udisks2 not found. Falling back to udevil\n" msgstr "" #: trash.c:933 #, c-format msgid "%s: undel: %d: Invalid ELN\n" msgstr "" #: trash.c:714 #, c-format msgid "%s: undel: %s: Error decoding original path\n" msgstr "" #: trash.c:770 #, c-format msgid "%s: undel: %s: Error removing info file\n" msgstr "" #: trash.c:777 #, c-format msgid "%s: undel: %s: Error restoring trashed file\n" msgstr "" #: trash.c:676 #, c-format msgid "" "%s: undel: Info file for '%s' not found. Try restoring the file manually\n" msgstr "" #: init.c:1525 #, c-format msgid "%s: unknown option character '\\%x'\n" msgstr "" #: init.c:1521 #, c-format msgid "" "%s: unrecognized option '%c'\n" "Try '%s --help' for more information.\n" msgstr "" #: init.c:1513 #, c-format msgid "" "%s: unrecognized option '%s'\n" "Try '%s --help' for more information.\n" msgstr "" #: bookmarks.c:609 #, c-format msgid "" "%sBookmarks Manager%s\n" "\n" msgstr "" #: bookmarks.c:208 #, c-format msgid "" "%sBookmarks%s\n" "\n" msgstr "" #: colors.c:1844 #, c-format msgid "" "%sExtension colors%s\n" "\n" msgstr "" #: colors.c:1795 #, c-format msgid "" "%sFile type colors%s\n" "\n" msgstr "" #: archives.c:1028 #, c-format msgid "%sFile%s: %s\n" msgstr "" #: media.c:526 #, c-format msgid "" "%sMountpoints%s\n" "\n" msgstr "" #: archives.c:940 #, c-format msgid "%sNOTE%s: Using Zstandard\n" msgstr "" #: selection.c:551 #, c-format msgid "%sSelection Box%s\n" msgstr "" #: trash.c:535 trash.c:862 #, c-format msgid "" "%sTrashed files%s\n" "\n" msgstr "" #: archives.c:1205 #, c-format msgid "" "%s[e]%sxtract %s[E]%sxtract-to-dir %s[l]%sist %s[m]%sount %s[r]%sepack " "%s[q]%suit\n" msgstr "" #: archives.c:321 #, c-format msgid "" "%s[e]%sxtract %s[E]%sxtract-to-dir %s[l]%sist %s[t]%sest %s[m]%sount " "%s[q]%suit\n" msgstr "" #: archives.c:757 archives.c:941 #, c-format msgid "%s[e]%sxtract %s[t]%sest %s[i]%snfo %s[q]%suit\n" msgstr "" #: selection.c:941 #, c-format msgid "%zu file(s) currently selected\n" msgstr "" #: selection.c:601 #, c-format msgid "%zu files are now in the Selection Box\n" msgstr "" #: selection.c:603 #, c-format msgid "" "%zu selected file(s):\n" "\n" msgstr "" #: search.c:634 #, c-format msgid "'%s': Invalid regular expression\n" msgstr "" #: properties.c:424 #, c-format msgid "Access: \t%s%s%s\n" msgstr "" #: bookmarks.c:292 msgid "All bookmarks succesfully removed\n" msgstr "" #: selection.c:1106 msgid "All files deselected\n" msgstr "" #: mime.c:1482 #, c-format msgid "Associated application: %s [%s]\n" msgstr "" #: mime.c:1432 msgid "Associated application: None\n" msgstr "" #: mime.c:1479 #, c-format msgid "Associated application: ad [built-in] [%s]\n" msgstr "" #: exec.c:844 #, c-format msgid "Auto-open disabled\n" msgstr "" #: exec.c:841 #, c-format msgid "Auto-open enabled\n" msgstr "" #: exec.c:846 #, c-format msgid "Auto-open is %s\n" msgstr "" #: exec.c:818 #, c-format msgid "Autocd disabled\n" msgstr "" #: exec.c:815 #, c-format msgid "Autocd enabled\n" msgstr "" #: exec.c:820 #, c-format msgid "Autocd is %s\n" msgstr "" #: properties.c:429 #, c-format msgid "Birth: \t\t%s%s%s\n" msgstr "" #: properties.c:388 #, c-format msgid "Block special file" msgstr "" #: bookmarks.c:450 msgid "Bookmark line example: [sc]name:path" msgstr "" #: bookmarks.c:217 msgid "Bookmark(s) to be deleted (ex: 1 2-6, or *): " msgstr "" #: bookmarks.c:819 #, c-format msgid "Bookmarks function disabled\n" msgstr "" #: bookmarks.c:799 #, c-format msgid "Bookmarks: %s: %s\n" msgstr "" #: properties.c:426 #, c-format msgid "Change: \t%s%s%s\n" msgstr "" #: properties.c:389 #, c-format msgid "Character special file" msgstr "" #: bookmarks.c:93 msgid "Choose a bookmark: " msgstr "" #: media.c:611 msgid "Choose a mountpoint/device: " msgstr "" #: media.c:609 media.c:613 msgid "Choose a mountpoint: " msgstr "" #: mime.c:586 msgid "Choose an application ('q' to quit): " msgstr "" #: listing.c:309 #, c-format msgid "Color scheme %s->%s %s\n" msgstr "" #: exec.c:879 msgid "Columns disabled\n" msgstr "" #: exec.c:872 msgid "Columns enabled\n" msgstr "" #: file_operations.c:1562 msgid "Continue? [y/N] " msgstr "" #: tags.c:393 #, c-format msgid "Created new tag %s%s%s\n" msgstr "" #: misc.c:396 #, c-format msgid "Current filter: %c%s\n" msgstr "" #: properties.c:414 #, c-format msgid "Device: %s%d%s" msgstr "" #: properties.c:416 #, c-format msgid "Device: %s%zu%s" msgstr "" #: properties.c:385 #, c-format msgid "Directory" msgstr "" #: selection.c:737 msgid "Empty" msgstr "" #: file_operations.c:739 msgid "End filename with a slash to create a directory" msgstr "" #: media.c:601 msgid "Enter 'iELN' for device information. Ex: i4" msgstr "" #: archives.c:1081 media.c:600 msgid "Enter 'q' to quit" msgstr "" #: file_operations.c:1716 msgid "Enter links suffix ('q' to quit): " msgstr "" #: history.c:129 msgid "Error getting command!" msgstr "" #: mime.c:344 msgid "Error opening temporary file\n" msgstr "" #: archives.c:410 archives.c:419 archives.c:523 archives.c:532 msgid "Error querying file type\n" msgstr "" #: listing.c:1670 listing.c:2218 #, c-format msgid "Excluded files: %d\n" msgstr "" #: exec.c:793 #, c-format msgid "External commands allowed\n" msgstr "" #: exec.c:789 #, c-format msgid "External commands are %s\n" msgstr "" #: exec.c:796 #, c-format msgid "External commands disallowed\n" msgstr "" #: archives.c:62 msgid "Extraction path ('q' to quit): " msgstr "" #: properties.c:390 #, c-format msgid "Fifo" msgstr "" #: archives.c:673 msgid "File name ('q' to quit): " msgstr "" #: bookmarks.c:572 #, c-format msgid "File succesfully bookmarked\n" msgstr "" #: selection.c:994 msgid "File(s) to be deselected (ex: 1 2-6, or *): " msgstr "" #: trash.c:563 msgid "File(s) to be removed (ex: 1 2-6, or *): " msgstr "" #: trash.c:881 msgid "File(s) to be undeleted (ex: 1 2-6, or *): " msgstr "" #: file_operations.c:740 msgid "Filename ('q' to quit): " msgstr "" #: exec.c:725 msgid "Files counter disabled\n" msgstr "" #: exec.c:718 msgid "Files counter enabled\n" msgstr "" #: misc.c:369 msgid "Filter unset" msgstr "" #: keybinds.c:842 #, c-format msgid "Folders first %s\n" msgstr "" #: exec.c:698 msgid "Folders first disabled\n" msgstr "" #: exec.c:694 msgid "Folders first enabled\n" msgstr "" #: exec.c:689 #, c-format msgid "Folders first is %s\n" msgstr "" #: exec.c:1803 msgid "Full directory size disabled\n" msgstr "" #: exec.c:1792 msgid "Full directory size enabled\n" msgstr "" #: exec.c:1799 msgid "Full directory size is already disabled" msgstr "" #: exec.c:1788 msgid "Full directory size is already enabled" msgstr "" #: search.c:211 msgid "Glob: No matches found. Trying regex..." msgstr "" #: keybinds.c:894 #, c-format msgid "Hidden files %s\n" msgstr "" #: exec.c:1121 msgid "Hidden files disabled\n" msgstr "" #: exec.c:1128 msgid "Hidden files enabled\n" msgstr "" #: exec.c:1113 #, c-format msgid "Hidden files is %s\n" msgstr "" #: history.c:405 #, c-format msgid "History is %s\n" msgstr "" #: archives.c:692 #, c-format msgid "Invalid file name\n" msgstr "" #: name_cleaner.c:572 msgid "Is this OK? [y/N/(e)dit] " msgstr "" #: history.c:88 #, c-format msgid "Logs %s\n" msgstr "" #: history.c:103 msgid "Logs already disabled" msgstr "" #: history.c:93 msgid "Logs already enabled" msgstr "" #: history.c:106 msgid "Logs succesfully disabled" msgstr "" #: history.c:96 msgid "Logs successfully enabled" msgstr "" #: keybinds.c:810 #, c-format msgid "Long view mode %s\n" msgstr "" #: mime.c:1472 #, c-format msgid "MIME type: %s\n" msgstr "" #: search.c:457 #, c-format msgid "Matches found: %d\n" msgstr "" #: search.c:810 #, c-format msgid "Matches found: %zu\n" msgstr "" #: exec.c:622 exec.c:634 #, c-format msgid "Max files set to %d\n" msgstr "" #: exec.c:615 msgid "Max files unset\n" msgstr "" #: exec.c:603 #, c-format msgid "Max files: %d\n" msgstr "" #: exec.c:601 msgid "Max files: unset" msgstr "" #: keybinds.c:339 #, c-format msgid "Max name length set back to %d\n" msgstr "" #: keybinds.c:337 msgid "Max name length unset\n" msgstr "" #: media.c:504 msgid "Media" msgstr "" #: properties.c:425 #, c-format msgid "Modify: \t%s%s%s\n" msgstr "" #: media.c:524 msgid "Mounted devices" msgstr "" #: media.c:504 media.c:523 msgid "Mountpoints" msgstr "" #: jump.c:313 msgid "" "NOTE 2: An asterisk next rank values means that the corresponding directory " "is bookmarked, pinned, or currently used in some workspace\n" msgstr "" #: jump.c:311 msgid "" "NOTE: First time access is displayed in days, while last time access is " "displayed in hours" msgstr "" #: mime.c:1471 remotes.c:56 #, c-format msgid "Name: %s\n" msgstr "" #: config.c:87 #, c-format msgid "New configuration file written to '%s'\n" msgstr "" #: archives.c:1085 msgid "New format (ex: .tar.xz): " msgstr "" #: file_operations.c:1068 msgid "New path ('q' to quit): " msgstr "" #: remotes.c:69 msgid "No" msgstr "" #: config.c:58 msgid "No configuration file found" msgstr "" #: tags.c:167 #, c-format msgid "No file tagged as '%s'\n" msgstr "" #: misc.c:361 msgid "No filter set" msgstr "" #: search.c:673 search.c:812 #, c-format msgid "No matches found\n" msgstr "" #: exec.c:1210 msgid "No pinned file" msgstr "" #: mime.c:1378 msgid "No such ELN" msgstr "" #: mime.c:1471 msgid "None" msgstr "" #: config.c:80 #, c-format msgid "Old configuration file stored as '%s'\n" msgstr "" #: keybinds.c:1533 #, c-format msgid "Only directories %s\n" msgstr "" #: exec.c:975 #, c-format msgid "Opener set to '%s'\n" msgstr "" #: archives.c:117 archives.c:762 archives.c:948 msgid "Operation: " msgstr "" #: jump.c:316 msgid "Order\tVisits\tFirst\tLast\tRank\tDirectory" msgstr "" #: exec.c:765 msgid "Pager disabled\n" msgstr "" #: exec.c:761 msgid "Pager enabled\n" msgstr "" #: exec.c:1208 #, c-format msgid "Pinned file: %s\n" msgstr "" #: properties.c:391 #, c-format msgid "Regular file" msgstr "" #: file_operations.c:1127 msgid "Relink as a broken symbolic link? [y/n] " msgstr "" #: properties.c:434 #, c-format msgid "Size: \t\t%s%s%s\n" msgstr "" #: properties.c:386 #, c-format msgid "Socket" msgstr "" #: listing.c:304 msgid "Sorted by: " msgstr "" #: sort.c:466 msgid "Sorting method: " msgstr "" #: misc.c:1643 #, c-format msgid "Succesfully unpinned %s\n" msgstr "" #: tags.c:656 #, c-format msgid "Successfully merged %s%s%s into %s%s%s\n" msgstr "" #: bookmarks.c:365 #, c-format msgid "Successfully removed '%s'\n" msgstr "" #: tags.c:484 #, c-format msgid "Successfully tagged %zu file(s)\n" msgstr "" #: tags.c:554 #, c-format msgid "Successfully untagged %zu file(s)\n" msgstr "" #: exec.c:991 exec.c:995 keybinds.c:870 msgid "Switched back to normal mode\n" msgstr "" #: keybinds.c:868 msgid "Switched to light mode\n" msgstr "" #: properties.c:387 #, c-format msgid "Symbolic link" msgstr "" #: exec.c:733 msgid "The files counter is disabled" msgstr "" #: exec.c:731 msgid "The files counter is enabled" msgstr "" #: exec.c:756 #, c-format msgid "The files pager is %s\n" msgstr "" #: exec.c:1188 #, c-format msgid "Toggled executable bit on %zu %s\n" msgstr "" #: exec.c:1689 #, c-format msgid "" "Total files: %zu\n" "Directories: %zu\n" "Regular files: %zu\n" "Executable files: %zu\n" "Hidden files: %zu\n" "SUID files: %zu\n" "SGID files: %zu\n" "Files w/capabilities: %zu\n" "FIFO/pipes: %zu\n" "Sockets: %zu\n" "Block devices: %zu\n" "Character devices: %zu\n" "Symbolic links: %zu\n" "Broken symbolic links: %zu\n" "Multi-link files: %zu\n" "Files w/extended attributes: %zu\n" "Other-writable files: %zu\n" "Sticky files: %zu\n" "Unknown file types: %zu\n" "Unstatable files: %zu\n" msgstr "" #: properties.c:441 msgid "Total size: \t" msgstr "" #: listing.c:1400 #, c-format msgid "" "Total size: %s%s%s\n" "Largest file: %s%s%s %c%s%s%s%c\n" msgstr "" #: mime.c:555 msgid "Try 'mm, mime edit APPLICATION'\n" msgstr "" #: exec.c:661 msgid "Unicode disabled" msgstr "" #: exec.c:658 msgid "Unicode enabled" msgstr "" #: exec.c:655 #, c-format msgid "Unicode is %s\n" msgstr "" #: archives.c:669 msgid "" "Use extension to specify archive/compression type (defaults to .tar.gz)\n" "Example: myarchive.xz" msgstr "" #: remotes.c:70 msgid "Yes" msgstr "" #: actions.c:371 msgid "actions: No actions defined. Use the 'actions edit' command to add some" msgstr "" #: exec.c:790 msgid "allowed" msgstr "" #: archives.c:713 #, c-format msgid "archiver: %s: Error dequoting file name\n" msgstr "" #: archives.c:909 #, c-format msgid "archiver: %s: Not an archive/compressed file\n" msgstr "" #: sort.c:378 #, c-format msgid "atime %s\n" msgstr "" #: bookmarks.c:200 bookmarks.c:244 #, c-format msgid "bookmarks: %s: No such bookmark\n" msgstr "" #: bookmarks.c:416 #, c-format msgid "bookmarks: %s: Path already bookmarked\n" msgstr "" #: bookmarks.c:493 #, c-format msgid "bookmarks: %s: This name is already in use\n" msgstr "" #: bookmarks.c:461 #, c-format msgid "bookmarks: %s: This shortcut is already in use\n" msgstr "" #: bookmarks.c:274 #, c-format msgid "" "bookmarks: All bookmarks were deleted\n" " However, a backup copy was created (%s)\n" msgstr "" #: bookmarks.c:279 #, c-format msgid "bookmarks: Error creating backup file. No bookmark was deleted\n" msgstr "" #: bookmarks.c:309 #, c-format msgid "bookmarks: Error creating temporary file\n" msgstr "" #: bookmarks.c:546 #, c-format msgid "bookmarks: Error generating the bookmark line\n" msgstr "" #: bookmarks.c:391 bookmarks.c:554 bookmarks.c:563 #, c-format msgid "bookmarks: Error opening the bookmarks file\n" msgstr "" #: bookmarks.c:226 #, c-format msgid "bookmarks: Error parsing input\n" msgstr "" #: bookmarks.c:162 msgid "bookmarks: There are no bookmarks" msgstr "" #: sort.c:381 #, c-format msgid "btime %s\n" msgstr "" #: sort.c:383 #, c-format msgid "btime (not available: using 'ctime') %s\n" msgstr "" #: file_operations.c:1473 #, c-format msgid "bulk: %s\n" msgstr "" #: file_operations.c:1436 #, c-format msgid "bulk: %s: Error dequoting file name\n" msgstr "" #: file_operations.c:1514 msgid "bulk: Line mismatch in renaming file\n" msgstr "" #: file_operations.c:1493 file_operations.c:1548 msgid "bulk: Nothing to do" msgstr "" #: sort.c:387 #, c-format msgid "ctime %s\n" msgstr "" #: selection.c:1053 #, c-format msgid "desel: '%s': Invalid ELN\n" msgstr "" #: selection.c:1042 #, c-format msgid "desel: '%s': Invalid entry\n" msgstr "" #: selection.c:1094 msgid "desel: There are no selected files" msgstr "" #: media.c:559 msgid "devices" msgstr "" #: exec.c:655 exec.c:690 exec.c:757 exec.c:820 exec.c:846 exec.c:1114 #: history.c:89 msgid "disabled" msgstr "" #: exec.c:655 exec.c:690 exec.c:757 exec.c:820 exec.c:846 exec.c:1114 #: history.c:88 msgid "enabled" msgstr "" #: sort.c:393 #, c-format msgid "extension %s\n" msgstr "" #: remotes.c:66 remotes.c:68 msgid "false" msgstr "" #: exec.c:1189 msgid "file" msgstr "" #: exec.c:1189 msgid "files" msgstr "" #: navigation.c:619 #, c-format msgid "history: %d: No such ELN\n" msgstr "" #: sort.c:395 #, c-format msgid "inode %s\n" msgstr "" #: media.c:559 msgid "mountpoints" msgstr "" #: media.c:561 msgid "mp: There are no available mountpoints\n" msgstr "" #: sort.c:389 #, c-format msgid "mtime %s\n" msgstr "" #: sort.c:374 #, c-format msgid "name %s\n" msgstr "" #: sort.c:372 msgid "none" msgstr "" #: exec.c:790 msgid "not allowed" msgstr "" #: sort.c:376 #, c-format msgid "size %s\n" msgstr "" #: trash.c:1028 #, c-format msgid "trash: %s: %s\n" msgstr "" #: trash.c:1034 #, c-format msgid "trash: %s: Cannot trash a %s device\n" msgstr "" #: trash.c:1016 #, c-format msgid "trash: Cannot trash '%s'\n" msgstr "" #: trash.c:541 trash.c:830 trash.c:984 msgid "trash: No trashed files" msgstr "" #: trash.c:263 msgid "trash: There are no trashed files" msgstr "" #: trash.c:1022 msgid "trash: Use 'trash del' to remove trashed files" msgstr "" #: remotes.c:66 remotes.c:68 msgid "true" msgstr "" #: trash.c:908 #, c-format msgid "undel: %s: Invalid ELN\n" msgstr "" #: properties.c:418 properties.c:420 msgid "unknown" msgstr "" #: sort.c:391 #, c-format msgid "version %s\n" msgstr "" clifm-1.26.3/translations/italian/000077500000000000000000000000001506632037700170505ustar00rootroot00000000000000clifm-1.26.3/translations/italian/clifm.po000066400000000000000000001233511506632037700205070ustar00rootroot00000000000000# This file is part of CliFM # Copyright (C) 2016-2022 # This file is distributed under the same license as the clifm package. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2022-04-23 14:46-0300\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: properties.c:400 #, c-format msgid "\tBlocks: %s%ld%s" msgstr "" #: properties.c:398 #, c-format msgid "\tBlocks: %s%lld%s" msgstr "" #: properties.c:420 #, c-format msgid "\tGid: %s%u (%s)%s\n" msgstr "" #: properties.c:404 #, c-format msgid "\tIO Block: %s%d%s" msgstr "" #: properties.c:406 #, c-format msgid "\tIO Block: %s%ld%s" msgstr "" #: properties.c:409 #, c-format msgid "\tInode: %s%llu%s\n" msgstr "" #: properties.c:411 #, c-format msgid "\tInode: %s%zu%s\n" msgstr "" #: properties.c:317 #, c-format msgid "\tName: %s%s%s -> %s (broken link)\n" msgstr "" #: properties.c:418 #, c-format msgid "\tUid: %s%u (%s)%s" msgstr "" #: misc.c:1789 #, c-format msgid "" "\n" " Press any key to continue... " msgstr "" #: selection.c:786 #, c-format msgid "" "\n" "%s%sTotal size%s: %s\n" msgstr "" #: bookmarks.c:214 #, c-format msgid "" "\n" "%sEnter '%c' to quit.\n" msgstr "" #: selection.c:990 #, c-format msgid "" "\n" "%sEnter 'q' to quit or 'e' to edit the selections file\n" msgstr "" #: trash.c:559 trash.c:877 #, c-format msgid "" "\n" "%sEnter 'q' to quit.\n" msgstr "" #: archives.c:816 #, c-format msgid "" "\n" "%sNOTE%s: Zstandard does not support compression of multiple files into one " "single compressed file. Files will be compressed rather into multiple " "compressed files using the original file names\n" msgstr "" #: media.c:282 #, c-format msgid "" "\n" "%sUnmounted devices%s\n" "\n" msgstr "" #: colors.c:1831 #, c-format msgid "" "\n" "*The slash followed by a number (/xx) after directories or symbolic links to " "directories indicates the amount of files contained by the corresponding " "directory, excluding self (.) and parent (..) directories.\n" msgstr "" #: misc.c:1697 msgid "" "\n" "NOTE: Some keybindings on Haiku might differ. Take a look at your current " "keybindings via the 'kb' command" msgstr "" #: colors.c:1835 #, c-format msgid "" "\n" "The second field in this list is the code that is to be used to modify the " "color of the corresponding file type in the color scheme file (in the " "\"FiletypeColors\" line), using the same ANSI style color format used by " "dircolors. By default, %s uses only 8/16 colors, but you can use 256 and RGB/" "true colors as well.\n" "\n" msgstr "" #: colors.c:1807 #, c-format msgid " %sfile name%s: bd: Block special file\n" msgstr "" #: colors.c:1818 #, c-format msgid " %sfile name%s: ca: File with capabilities\n" msgstr "" #: colors.c:1813 #, c-format msgid " %sfile name%s: cd: Character special file\n" msgstr "" #: colors.c:1800 #, c-format msgid " %sfile name%s: di: Directory*\n" msgstr "" #: colors.c:1801 #, c-format msgid " %sfile name%s: ed: EMPTY directory\n" msgstr "" #: colors.c:1806 #, c-format msgid " %sfile name%s: ee: Empty executable file\n" msgstr "" #: colors.c:1815 #, c-format msgid " %sfile name%s: ef: Empty (zero-lenght) file\n" msgstr "" #: colors.c:1805 #, c-format msgid " %sfile name%s: ex: Executable file\n" msgstr "" #: colors.c:1814 #, c-format msgid " %sfile name%s: fi: Regular file\n" msgstr "" #: colors.c:1808 #, c-format msgid " %sfile name%s: ln: Symbolic link*\n" msgstr "" #: colors.c:1810 #, c-format msgid " %sfile name%s: mh: Multi-hardlink\n" msgstr "" #: colors.c:1796 #, c-format msgid " %sfile name%s: nd: Directory with no read permission\n" msgstr "" #: colors.c:1802 #, c-format msgid " %sfile name%s: ne: EMPTY directory with no read permission\n" msgstr "" #: colors.c:1798 #, c-format msgid " %sfile name%s: nf: File with no read permission\n" msgstr "" #: colors.c:1828 #, c-format msgid " %sfile name%s: no: Unknown file type\n" msgstr "" #: colors.c:1809 #, c-format msgid " %sfile name%s: or: Broken symbolic link\n" msgstr "" #: colors.c:1825 #, c-format msgid " %sfile name%s: ow: Other-writable and NOT sticky directory*\n" msgstr "" #: colors.c:1812 #, c-format msgid " %sfile name%s: pi: Pipe or FIFO special file\n" msgstr "" #: colors.c:1817 #, c-format msgid " %sfile name%s: sg: SGID file\n" msgstr "" #: colors.c:1811 #, c-format msgid " %sfile name%s: so: Socket file\n" msgstr "" #: colors.c:1819 #, c-format msgid " %sfile name%s: st: Sticky and NOT other-writable directory*\n" msgstr "" #: colors.c:1816 #, c-format msgid " %sfile name%s: su: SUID file\n" msgstr "" #: colors.c:1822 #, c-format msgid " %sfile name%s: tw: Sticky and other-writable directory*\n" msgstr "" #: colors.c:1829 #, c-format msgid " %sfile name%s: uf: Unaccessible (non-stat'able) file\n" msgstr "" #: remotes.c:67 #, c-format msgid " Auto-mount: %s\n" msgstr "" #: remotes.c:65 #, c-format msgid " Auto-unmount: %s\n" msgstr "" #: remotes.c:58 #, c-format msgid " Comment: %s\n" msgstr "" #: remotes.c:62 #, c-format msgid " Mount command: %s\n" msgstr "" #: remotes.c:69 #, c-format msgid " Mounted: %s\n" msgstr "" #: remotes.c:60 #, c-format msgid " Mountpoint: %s\n" msgstr "" #: remotes.c:64 #, c-format msgid " Unmount command: %s\n" msgstr "" #: config.c:1263 #, c-format msgid "" "# %s profile\n" "# Write here the commands you want to be executed at startup\n" "# Ex:\n" "#echo -e \"%s, the command line file manager\"\n" msgstr "" #: strings.c:1631 #, c-format msgid "%c%s: There are no selected files%c" msgstr "" #: selection.c:938 #, c-format msgid "%d file(s) deselected. " msgstr "" #: sort.c:364 #, c-format msgid "%s %s\n" msgstr "" #: misc.c:1757 #, c-format msgid "%s %s (%s), by %s\n" msgstr "" #: misc.c:1776 #, c-format msgid "" "%s %s (%s), by %s\n" "Contact: %s\n" "Website: %s\n" "License: %s\n" msgstr "" #: tags.c:115 #, c-format msgid "%s (error resolving link target)\n" msgstr "" #: sort.c:358 #, c-format msgid "%s (not available: using 'name') %s\n" msgstr "" #: config.c:1320 #, c-format msgid "" "%s created a new MIME list file (%s) It is recommended to edit this file " "(entering 'mm edit' or pressing F6) to add the programs you use and remove " "those you don't. This will make the process of opening files faster and " "smoother\n" msgstr "" #: bookmarks.c:89 #, c-format msgid "" "%s%s\n" "Enter '%c' to edit your bookmarks or '%c' to quit.\n" msgstr "" #: file_operations.c:1055 #, c-format msgid "%s%s%s currently pointing to " msgstr "" #: file_operations.c:1052 #, c-format msgid "%s%s%s currently pointing to nowhere (broken link)\n" msgstr "" #: file_operations.c:1167 #, c-format msgid "%s%s%s successfully relinked to " msgstr "" #: archives.c:1188 #, c-format msgid "%s%s%s: Succesfully mounted on %s\n" msgstr "" #: archives.c:1009 #, c-format msgid "%s%sFile%s: %s\n" msgstr "" #: selection.c:732 #, c-format msgid "%s%sSelection Box%s\n" msgstr "" #: selection.c:543 #, c-format msgid "%s%sTotal size%s: %s\n" msgstr "" #: main.c:759 #, c-format msgid "%s->%s Running as root%s\n" msgstr "" #: history.c:540 history.c:579 #, c-format msgid "%s: !%s: Event not found\n" msgstr "" #: history.c:494 #, c-format msgid "%s: !%s: event not found\n" msgstr "" #: mime.c:1349 #, c-format msgid "" "%s: %d MIME definition(s) imported from the system. Old MIME list file " "stored as %s\n" msgstr "" #: name_cleaner.c:649 #, c-format msgid "%s: %d file(s) bleached\n" msgstr "" #: selection.c:940 #, c-format msgid "%s: %d file(s) deselected. " msgstr "" #: navigation.c:80 #, c-format msgid "%s: %d is already the current workspace\n" msgstr "" #: strings.c:1702 #, c-format msgid "" "%s: %d: ELN-filename conflict. Bypass internal expansions to fix this issue: " "';CMD FILENAME'\n" msgstr "" #: media.c:199 #, c-format msgid "%s: %d: Invalid ELN\n" msgstr "" #: navigation.c:72 #, c-format msgid "%s: %d: Invalid workspace number\n" msgstr "" #: name_cleaner.c:408 prompt.c:462 #, c-format msgid "%s: %s\n" msgstr "" #: file_operations.c:977 #, c-format msgid "" "%s: %s (%s): Cannot open file\n" "Try 'APPLICATION FILENAME'\n" msgstr "" #: aux.c:817 aux.c:831 aux.c:845 #, c-format msgid "%s: %s failed to allocate %zu bytes\n" msgstr "" #: config.c:502 file_operations.c:108 file_operations.c:134 remotes.c:137 #, c-format msgid "%s: %s: %s\n" msgstr "" #: init.c:1692 #, c-format msgid "" "%s: %s: %s\n" "Falling back to default\n" msgstr "" #: init.c:1637 #, c-format msgid "" "%s: %s: %s\n" "Falling back to default configuration directory\n" msgstr "" #: init.c:1604 #, c-format msgid "" "%s: %s: %s\n" "Falling back to the default bookmarks file\n" msgstr "" #: init.c:1664 #, c-format msgid "" "%s: %s: %s\n" "Falling back to the default keybindings file\n" msgstr "" #: file_operations.c:953 #, c-format msgid "%s: %s: Broken symbolic link\n" msgstr "" #: init.c:1628 #, c-format msgid "" "%s: %s: Cannot create directory (error %d)\n" "Falling back to default configuration directory\n" msgstr "" #: profiles.c:302 #, c-format msgid "%s: %s: Cannot create profile: Home directory not found\n" msgstr "" #: file_operations.c:1741 #, c-format msgid "%s: %s: Cannot create symlink: %s\n" msgstr "" #: tags.c:384 #, c-format msgid "%s: %s: Cannot create tag\n" msgstr "" #: tags.c:50 #, c-format msgid "%s: %s: Cannot create tag: file already exists\n" msgstr "" #: file_operations.c:251 #, c-format msgid "%s: %s: Cannot open file\n" msgstr "" #: file_operations.c:210 #, c-format msgid "%s: %s: Directory empty\n" msgstr "" #: profiles.c:371 #, c-format msgid "%s: %s: Error creating profile\n" msgstr "" #: tags.c:277 #, c-format msgid "%s: %s: Error creating tag\n" msgstr "" #: config.c:1240 #, c-format msgid "%s: %s: Error creating tags directory. Tag function disabled\n" msgstr "" #: aux.c:143 #, c-format msgid "%s: %s: Error deescaping string\n" msgstr "" #: file_operations.c:1022 file_operations.c:1111 #, c-format msgid "%s: %s: Error dequoting file\n" msgstr "" #: bookmarks.c:794 misc.c:754 name_cleaner.c:523 properties.c:684 #: readline.c:401 search.c:145 search.c:552 #, c-format msgid "%s: %s: Error dequoting file name\n" msgstr "" #: file_operations.c:776 file_operations.c:911 #, c-format msgid "%s: %s: Error dequoting filename\n" msgstr "" #: navigation.c:281 #, c-format msgid "%s: %s: Error dequoting string\n" msgstr "" #: aux.c:159 navigation.c:288 #, c-format msgid "%s: %s: Error expanding tilde\n" msgstr "" #: remotes.c:255 trash.c:136 #, c-format msgid "%s: %s: Error getting parent directory\n" msgstr "" #: strings.c:1766 #, c-format msgid "%s: %s: Error getting variable name\n" msgstr "" #: mime.c:282 #, c-format msgid "%s: %s: Error opening file\n" msgstr "" #: strings.c:1591 strings.c:1733 strings.c:1973 strings.c:2047 #, c-format msgid "%s: %s: Error quoting file name\n" msgstr "" #: profiles.c:415 #, c-format msgid "%s: %s: Error removing profile\n" msgstr "" #: file_operations.c:814 #, c-format msgid "%s: %s: File already exists. Trying with '%s' instead\n" msgstr "" #: tags.c:48 #, c-format msgid "%s: %s: File already tagged\n" msgstr "" #: tags.c:531 #, c-format msgid "%s: %s: File not tagged as %s%s%s\n" msgstr "" #: file_operations.c:1095 #, c-format msgid "%s: %s: Invalid ELN\n" msgstr "" #: exec.c:1781 exec.c:1808 #, c-format msgid "%s: %s: Invalid argument. Try 'fz -h'\n" msgstr "" #: exec.c:628 #, c-format msgid "%s: %s: Invalid number\n" msgstr "" #: exec.c:1567 #, c-format msgid "%s: %s: Is a directory\n" msgstr "" #: misc.c:916 #, c-format msgid "%s: %s: No alias found\n" msgstr "" #: mime.c:1445 mime.c:1449 #, c-format msgid "%s: %s: No associated application found\n" msgstr "" #: navigation.c:371 #, c-format msgid "%s: %s: No matches found\n" msgstr "" #: exec.c:1056 #, c-format msgid "%s: %s: No such alias\n" msgstr "" #: colors.c:955 #, c-format msgid "%s: %s: No such color scheme. Falling back to default\n" msgstr "" #: colors.c:1064 #, c-format msgid "%s: %s: No such color scheme. Falling back to the default one\n" msgstr "" #: jump.c:432 #, c-format msgid "%s: %s: No such order number\n" msgstr "" #: profiles.c:393 #, c-format msgid "%s: %s: No such profile\n" msgstr "" #: profiles.c:132 #, c-format msgid "" "%s: %s: No such profile\n" "To add a new profile enter 'pf add PROFILE'\n" msgstr "" #: remotes.c:118 #, c-format msgid "%s: %s: No such remote\n" msgstr "" #: selection.c:888 #, c-format msgid "%s: %s: No such selected file\n" msgstr "" #: sort.c:457 #, c-format msgid "%s: %s: No such sorting method\n" msgstr "" #: tags.c:75 tags.c:158 #, c-format msgid "%s: %s: No such tag\n" msgstr "" #: misc.c:634 #, c-format msgid "%s: %s: Not a directory\n" msgstr "" #: file_operations.c:1044 #, c-format msgid "%s: %s: Not a symbolic link\n" msgstr "" #: remotes.c:225 #, c-format msgid "%s: %s: Not mounted\n" msgstr "" #: sanitize.c:368 #, c-format msgid "" "%s: %s: Only command base names are allowed. Ex: 'nano' instead of '/usr/bin/" "nano'\n" msgstr "" #: profiles.c:297 #, c-format msgid "%s: %s: Profile already exists\n" msgstr "" #: remotes.c:209 #, c-format msgid "%s: %s: Remote mounted on %s\n" msgstr "" #: tags.c:317 #, c-format msgid "%s: %s: Successfully removed tag\n" msgstr "" #: main.c:826 profiles.c:165 #, c-format msgid "" "%s: %s: System shell not found. Please edit the configuration file to " "specify a working shell.\n" msgstr "" #: tags.c:271 #, c-format msgid "%s: %s: Tag already exists\n" msgstr "" #: media.c:503 #, c-format msgid "%s: %s: This feature is not available on Haiku\n" msgstr "" #: init.c:1643 #, c-format msgid "%s: %s: Using alternative configuration directory\n" msgstr "" #: misc.c:934 #, c-format msgid "%s: %zu aliases were successfully imported\n" msgstr "" #: init.c:207 #, c-format msgid "" "%s: %zu: Invalid workspace.\n" "Falling back to workspace %zu\n" msgstr "" #: jump.c:410 #, c-format msgid "%s: '%c': Invalid option\n" msgstr "" #: search.c:114 search.c:535 selection.c:429 #, c-format msgid "%s: '%c': Unrecognized file type\n" msgstr "" #: profiles.c:141 #, c-format msgid "%s: '%s' is the current profile\n" msgstr "" #: config.c:1889 #, c-format msgid "%s: '%s': %s. Using the current working directory as starting path\n" msgstr "" #: config.c:1228 #, c-format msgid "" "%s: '%s': Directory not writable. Bookmarks, commands logs, and commands " "history are disabled. Program messages won't be persistent. Using default " "options\n" msgstr "" #: config.c:1202 #, c-format msgid "%s: '%s': Directory not writable. Trash function disabled\n" msgstr "" #: config.c:2023 misc.c:379 #, c-format msgid "%s: '%s': Invalid regular expression\n" msgstr "" #: profiles.c:363 #, c-format msgid "%s: '%s': Profile succesfully created\n" msgstr "" #: profiles.c:406 #, c-format msgid "%s: '%s': Profile successfully removed\n" msgstr "" #: exec.c:1462 #, c-format msgid "%s: '%s': Syntax error\n" msgstr "" #: checks.c:107 #, c-format msgid "" "%s: '%s': Unsupported terminal. This terminal cannot understand escape " "sequences\n" msgstr "" #: config.c:550 #, c-format msgid "" "%s: '%s': Using a temporary directory for the Selection Box. Selected files " "won't be persistent across reboots" msgstr "" #: navigation.c:338 #, c-format msgid "%s: /: No parent directory\n" msgstr "" #: misc.c:937 #, c-format msgid "%s: 1 alias was successfully imported\n" msgstr "" #: config.c:99 #, c-format msgid "%s: Access to configuration files is not allowed in stealth mode\n" msgstr "" #: misc.c:902 #, c-format msgid "%s: Alias already exists\n" msgstr "" #: misc.c:855 #, c-format msgid "%s: Alias conflicts with internal command\n" msgstr "" #: config.c:113 #, c-format msgid "%s: Cannot access the configuration file\n" msgstr "" #: init.c:149 #, c-format msgid "" "%s: Cannot access the home directory. Trash, bookmarks, commands logs, and " "commands history are disabled. Program messages and selected files won't be " "persistent. Using default options\n" msgstr "" #: tags.c:643 #, c-format msgid "%s: Cannot merge tags: error moving tagged files\n" msgstr "" #: bookmarks.c:597 #, c-format msgid "%s: Cannot open the bookmarks file\n" msgstr "" #: history.c:248 #, c-format msgid "%s: Could not save directory history: %s\n" msgstr "" #: colors.c:539 #, c-format msgid "%s: Current color scheme: %s\n" msgstr "" #: colors.c:1789 #, c-format msgid "%s: Currently running without colors\n" msgstr "" #: misc.c:607 #, c-format msgid "" "%s: Default terminal not set. Use the configuration file (F10) to set it\n" msgstr "" #: trash.c:150 #, c-format msgid "%s: Directory is immutable\n" msgstr "" #: jump.c:291 #, c-format msgid "%s: Directory jumper function disabled\n" msgstr "" #: init.c:1035 init.c:1043 selection.c:486 #, c-format msgid "%s: Error expanding path\n" msgstr "" #: init.c:1246 #, c-format msgid "%s: Error expanding tilde. Using default opener\n" msgstr "" #: mime.c:460 #, c-format msgid "%s: Error getting home directory\n" msgstr "" #: main.c:848 #, c-format msgid "%s: Error getting hostname\n" msgstr "" #: mime.c:1463 #, c-format msgid "%s: Error getting mime-type\n" msgstr "" #: remotes.c:230 #, c-format msgid "%s: Error getting mountpoint for '%s'\n" msgstr "" #: misc.c:1051 #, c-format msgid "%s: Error getting variable value\n" msgstr "" #: misc.c:777 #, c-format msgid "%s: Error lauching new instance\n" msgstr "" #: checks.c:99 #, c-format msgid "%s: Error opening terminal: unknown\n" msgstr "" #: profiles.c:217 #, c-format msgid "%s: Error opening the history file\n" msgstr "" #: checks.c:512 #, c-format msgid "%s: Error parsing aliased command\n" msgstr "" #: history.c:503 history.c:522 history.c:556 #, c-format msgid "%s: Error parsing history command\n" msgstr "" #: media.c:447 #, c-format msgid "%s: Error retrieving mountpoint\n" msgstr "" #: init.c:387 #, c-format msgid "%s: Error retrieving user data\n" msgstr "" #: misc.c:968 #, c-format msgid "%s: Error saving last visited directory\n" msgstr "" #: misc.c:1566 #, c-format msgid "%s: Error storing pinned directory\n" msgstr "" #: selection.c:572 #, c-format msgid "%s: Error writing selected files to the selections file\n" msgstr "" #: exec.c:535 #, c-format msgid "%s: External commands are not allowed. Run 'ext on' to enable them.\n" msgstr "" #: init.c:1350 #, c-format msgid "%s: FZF not found. Falling back to standard TAB completion\n" msgstr "" #: init.c:251 main.c:815 #, c-format msgid "%s: Fatal error! Failed retrieving current working directory\n" msgstr "" #: trash.c:203 #, c-format msgid "%s: File is immutable\n" msgstr "" #: misc.c:614 #, c-format msgid "%s: Function only available for graphical environments\n" msgstr "" #: history.c:428 #, c-format msgid "%s: History function disabled\n" msgstr "" #: bookmarks.c:694 bookmarks.c:775 #, c-format msgid "%s: Invalid bookmark\n" msgstr "" #: navigation.c:625 #, c-format msgid "%s: Invalid history entry\n" msgstr "" #: exec.c:1654 #, c-format msgid "%s: Lira: %s\n" msgstr "" #: init.c:1609 #, c-format msgid "%s: Loaded alternative bookmarks file\n" msgstr "" #: init.c:1698 #, c-format msgid "%s: Loaded alternative configuration file\n" msgstr "" #: init.c:1670 #, c-format msgid "%s: Loaded alternative keybindings file\n" msgstr "" #: exec.c:1100 #, c-format msgid "%s: Log function disabled\n" msgstr "" #: strings.c:645 strings.c:702 #, c-format msgid "%s: Missing '%c'\n" msgstr "" #: remotes.c:386 #, c-format msgid "%s: Mounting remote...\n" msgstr "" #: misc.c:386 #, c-format msgid "%s: New filter successfully set\n" msgstr "" #: misc.c:926 #, c-format msgid "%s: No alias imported\n" msgstr "" #: exec.c:1022 exec.c:1042 #, c-format msgid "%s: No aliases found\n" msgstr "" #: colors.c:408 #, c-format msgid "%s: No color schemes found\n" msgstr "" #: selection.c:583 #, c-format msgid "%s: No matches found\n" msgstr "" #: media.c:193 media.c:400 #, c-format msgid "%s: No mount application found. Install either udevil or udisks2\n" msgstr "" #: media.c:517 #, c-format msgid "%s: No mount command found. Install either udevil or udisks2\n" msgstr "" #: remotes.c:172 #, c-format msgid "%s: No mount command specified for '%s'\n" msgstr "" #: remotes.c:123 #, c-format msgid "%s: No mountpoint specified for '%s'\n" msgstr "" #: misc.c:717 #, c-format msgid "" "%s: No option specified for '%s'\n" "Trying '%s -e %s %s'\n" msgstr "" #: exec.c:1421 keybinds.c:1444 misc.c:1624 #, c-format msgid "%s: No pinned file\n" msgstr "" #: remotes.c:48 #, c-format msgid "%s: No remotes defined\n" msgstr "" #: bookmarks.c:678 #, c-format msgid "%s: No such ELN\n" msgstr "" #: bookmarks.c:699 bookmarks.c:780 #, c-format msgid "%s: No such bookmark\n" msgstr "" #: colors.c:496 #, c-format msgid "%s: No such color scheme\n" msgstr "" #: trash.c:122 #, c-format msgid "%s: No such file or directory\n" msgstr "" #: tags.c:455 #, c-format msgid "" "%s: No tag specified. Specify a tag via :TAG. E.g. tag FILE1 FILE2 :TAG\n" msgstr "" #: tags.c:67 #, c-format msgid "%s: No tags found, Use 'tag new' to create new tags\n" msgstr "" #: remotes.c:236 #, c-format msgid "%s: No unmount command found for '%s'\n" msgstr "" #: file_operations.c:486 name_cleaner.c:561 name_cleaner.c:611 #, c-format msgid "%s: Nothing to do\n" msgstr "" #: mime.c:531 #, c-format msgid "%s: Nothing was imported. No MIME definitions found\n" msgstr "" #: mime.c:454 #, c-format msgid "%s: Nothing was imported. No graphical environment found\n" msgstr "" #: trash.c:90 trash.c:182 trash.c:190 trash.c:210 trash.c:226 #, c-format msgid "%s: Permission denied\n" msgstr "" #: keybinds.c:96 keybinds.c:139 #, c-format msgid "%s: Restart the program for changes to take effect\n" msgstr "" #: config.c:2086 #, c-format msgid "" "%s: Running in stealth mode: trash, persistent selection and directory " "history, just as bookmarks, logs and configuration files, are disabled.\n" msgstr "" #: misc.c:1616 #, c-format msgid "%s: Succesfully pinned '%s'\n" msgstr "" #: tags.c:282 #, c-format msgid "%s: Successfully created tag\n" msgstr "" #: media.c:558 #, c-format msgid "%s: There are no available %s\n" msgstr "" #: exec.c:932 exec.c:950 #, c-format msgid "%s: There are no messages\n" msgstr "" #: exec.c:415 #, c-format msgid "%s: To gracefully quit enter 'q'\n" msgstr "" #: trash.c:797 trash.c:1085 #, c-format msgid "%s: Trash function disabled\n" msgstr "" #: misc.c:1703 #, c-format msgid "%s: Unable to find any pager\n" msgstr "" #: media.c:221 #, c-format msgid "%s: Unmounted %s\n" msgstr "" #: remotes.c:423 #, c-format msgid "%s: Unmounting remote...\n" msgstr "" #: main.c:744 #, c-format msgid "%s: Unsupported CPU architecture\n" msgstr "" #: main.c:750 #, c-format msgid "%s: Unsupported operating system\n" msgstr "" #: exec.c:2194 #, c-format msgid "%s: archiving: %s\n" msgstr "" #: exec.c:2175 #, c-format msgid "%s: bleach: %s\n" msgstr "" #: bookmarks.c:814 #, c-format msgid "%s: bookmarks: %s\n" msgstr "" #: navigation.c:444 #, c-format msgid "%s: cd: Home directory not found\n" msgstr "" #: colors.c:512 #, c-format msgid "" "%s: color schemes: %s\n" "TIP: To change the current color scheme use the following environment " "variables: CLIFM_FILE_COLORS, CLIFM_IFACE_COLORS, and CLIFM_EXT_COLORS\n" msgstr "" #: mime.c:1613 #, c-format msgid "%s: file: Command not found\n" msgstr "" #: config.c:1499 #, c-format msgid "%s: fopen: '%s': %s. Using default values.\n" msgstr "" #: checks.c:161 #, c-format msgid "%s: fzf not found. Falling back to standard TAB completion\n" msgstr "" #: init.c:1357 #, c-format msgid "%s: fzftab: %s\n" msgstr "" #: init.c:1379 #, c-format msgid "%s: fzytab: %s\n" msgstr "" #: init.c:1335 #, c-format msgid "%s: highlight: %s\n" msgstr "" #: exec.c:893 init.c:1267 #, c-format msgid "%s: icons: %s\n" msgstr "" #: jump.c:663 #, c-format msgid "%s: jump: No matches found\n" msgstr "" #: media.c:510 #, c-format msgid "%s: media: Function only available on Linux systems\n" msgstr "" #: profiles.c:315 #, c-format msgid "%s: mkdir: %s: Error creating configuration directory\n" msgstr "" #: config.c:1216 #, c-format msgid "" "%s: mkdir: '%s': Error creating configuration directory. Bookmarks, commands " "logs, and command history are disabled. Program messages won't be " "persistent. Using default options\n" msgstr "" #: config.c:1194 #, c-format msgid "" "%s: mkdir: '%s': Error creating trash directory. Trash function disabled\n" msgstr "" #: config.c:1277 #, c-format msgid "" "%s: mkdir: Error creating colors directory. Using the default color scheme\n" msgstr "" #: config.c:1289 #, c-format msgid "" "%s: mkdir: Error creating plugins directory. The actions function is " "disabled\n" msgstr "" #: init.c:1504 #, c-format msgid "" "%s: option requires an argument -- '%c'\n" "Try '%s --help' for more information.\n" msgstr "" #: selection.c:123 #, c-format msgid "%s: sel: %s: Already selected\n" msgstr "" #: selection.c:327 #, c-format msgid "%s: sel: %s: Invalid regular expression\n" msgstr "" #: trash.c:637 #, c-format msgid "%s: trash: %d: Invalid ELN\n" msgstr "" #: exec.c:1742 exec.c:1766 init.c:1290 #, c-format msgid "%s: trash: %s\n" msgstr "" #: trash.c:234 #, c-format msgid "%s: trash: %s (%s): Unsupported file type\n" msgstr "" #: trash.c:419 #, c-format msgid "" "%s: trash: %s/%s: Failed removing trash file\n" "Try removing it manually\n" msgstr "" #: trash.c:350 #, c-format msgid "%s: trash: %s: Error getting file name\n" msgstr "" #: trash.c:291 #, c-format msgid "%s: trash: %s: Error removing trashed file\n" msgstr "" #: trash.c:394 #, c-format msgid "%s: trash: %s: Failed copying file to Trash\n" msgstr "" #: trash.c:440 #, c-format msgid "%s: trash: %s: Failed encoding path\n" msgstr "" #: trash.c:615 #, c-format msgid "%s: trash: %s: Invalid ELN\n" msgstr "" #: trash.c:596 trash.c:646 #, c-format msgid "%s: trash: Error trashing %s\n" msgstr "" #: checks.c:123 #, c-format msgid "%s: udisks2 not found. Falling back to udevil\n" msgstr "" #: trash.c:933 #, c-format msgid "%s: undel: %d: Invalid ELN\n" msgstr "" #: trash.c:714 #, c-format msgid "%s: undel: %s: Error decoding original path\n" msgstr "" #: trash.c:770 #, c-format msgid "%s: undel: %s: Error removing info file\n" msgstr "" #: trash.c:777 #, c-format msgid "%s: undel: %s: Error restoring trashed file\n" msgstr "" #: trash.c:676 #, c-format msgid "" "%s: undel: Info file for '%s' not found. Try restoring the file manually\n" msgstr "" #: init.c:1525 #, c-format msgid "%s: unknown option character '\\%x'\n" msgstr "" #: init.c:1521 #, c-format msgid "" "%s: unrecognized option '%c'\n" "Try '%s --help' for more information.\n" msgstr "" #: init.c:1513 #, c-format msgid "" "%s: unrecognized option '%s'\n" "Try '%s --help' for more information.\n" msgstr "" #: bookmarks.c:609 #, c-format msgid "" "%sBookmarks Manager%s\n" "\n" msgstr "" #: bookmarks.c:208 #, c-format msgid "" "%sBookmarks%s\n" "\n" msgstr "" #: colors.c:1844 #, c-format msgid "" "%sExtension colors%s\n" "\n" msgstr "" #: colors.c:1795 #, c-format msgid "" "%sFile type colors%s\n" "\n" msgstr "" #: archives.c:1028 #, c-format msgid "%sFile%s: %s\n" msgstr "" #: media.c:526 #, c-format msgid "" "%sMountpoints%s\n" "\n" msgstr "" #: archives.c:940 #, c-format msgid "%sNOTE%s: Using Zstandard\n" msgstr "" #: selection.c:551 #, c-format msgid "%sSelection Box%s\n" msgstr "" #: trash.c:535 trash.c:862 #, c-format msgid "" "%sTrashed files%s\n" "\n" msgstr "" #: archives.c:1205 #, c-format msgid "" "%s[e]%sxtract %s[E]%sxtract-to-dir %s[l]%sist %s[m]%sount %s[r]%sepack " "%s[q]%suit\n" msgstr "" #: archives.c:321 #, c-format msgid "" "%s[e]%sxtract %s[E]%sxtract-to-dir %s[l]%sist %s[t]%sest %s[m]%sount " "%s[q]%suit\n" msgstr "" #: archives.c:757 archives.c:941 #, c-format msgid "%s[e]%sxtract %s[t]%sest %s[i]%snfo %s[q]%suit\n" msgstr "" #: selection.c:941 #, c-format msgid "%zu file(s) currently selected\n" msgstr "" #: selection.c:601 #, c-format msgid "%zu files are now in the Selection Box\n" msgstr "" #: selection.c:603 #, c-format msgid "" "%zu selected file(s):\n" "\n" msgstr "" #: search.c:634 #, c-format msgid "'%s': Invalid regular expression\n" msgstr "" #: properties.c:424 #, c-format msgid "Access: \t%s%s%s\n" msgstr "" #: bookmarks.c:292 msgid "All bookmarks succesfully removed\n" msgstr "" #: selection.c:1106 msgid "All files deselected\n" msgstr "" #: mime.c:1482 #, c-format msgid "Associated application: %s [%s]\n" msgstr "" #: mime.c:1432 msgid "Associated application: None\n" msgstr "" #: mime.c:1479 #, c-format msgid "Associated application: ad [built-in] [%s]\n" msgstr "" #: exec.c:844 #, c-format msgid "Auto-open disabled\n" msgstr "" #: exec.c:841 #, c-format msgid "Auto-open enabled\n" msgstr "" #: exec.c:846 #, c-format msgid "Auto-open is %s\n" msgstr "" #: exec.c:818 #, c-format msgid "Autocd disabled\n" msgstr "" #: exec.c:815 #, c-format msgid "Autocd enabled\n" msgstr "" #: exec.c:820 #, c-format msgid "Autocd is %s\n" msgstr "" #: properties.c:429 #, c-format msgid "Birth: \t\t%s%s%s\n" msgstr "" #: properties.c:388 #, c-format msgid "Block special file" msgstr "" #: bookmarks.c:450 msgid "Bookmark line example: [sc]name:path" msgstr "" #: bookmarks.c:217 msgid "Bookmark(s) to be deleted (ex: 1 2-6, or *): " msgstr "" #: bookmarks.c:819 #, c-format msgid "Bookmarks function disabled\n" msgstr "" #: bookmarks.c:799 #, c-format msgid "Bookmarks: %s: %s\n" msgstr "" #: properties.c:426 #, c-format msgid "Change: \t%s%s%s\n" msgstr "" #: properties.c:389 #, c-format msgid "Character special file" msgstr "" #: bookmarks.c:93 msgid "Choose a bookmark: " msgstr "" #: media.c:611 msgid "Choose a mountpoint/device: " msgstr "" #: media.c:609 media.c:613 msgid "Choose a mountpoint: " msgstr "" #: mime.c:586 msgid "Choose an application ('q' to quit): " msgstr "" #: listing.c:309 #, c-format msgid "Color scheme %s->%s %s\n" msgstr "" #: exec.c:879 msgid "Columns disabled\n" msgstr "" #: exec.c:872 msgid "Columns enabled\n" msgstr "" #: file_operations.c:1562 msgid "Continue? [y/N] " msgstr "" #: tags.c:393 #, c-format msgid "Created new tag %s%s%s\n" msgstr "" #: misc.c:396 #, c-format msgid "Current filter: %c%s\n" msgstr "" #: properties.c:414 #, c-format msgid "Device: %s%d%s" msgstr "" #: properties.c:416 #, c-format msgid "Device: %s%zu%s" msgstr "" #: properties.c:385 #, c-format msgid "Directory" msgstr "" #: selection.c:737 msgid "Empty" msgstr "" #: file_operations.c:739 msgid "End filename with a slash to create a directory" msgstr "" #: media.c:601 msgid "Enter 'iELN' for device information. Ex: i4" msgstr "" #: archives.c:1081 media.c:600 msgid "Enter 'q' to quit" msgstr "" #: file_operations.c:1716 msgid "Enter links suffix ('q' to quit): " msgstr "" #: history.c:129 msgid "Error getting command!" msgstr "" #: mime.c:344 msgid "Error opening temporary file\n" msgstr "" #: archives.c:410 archives.c:419 archives.c:523 archives.c:532 msgid "Error querying file type\n" msgstr "" #: listing.c:1670 listing.c:2218 #, c-format msgid "Excluded files: %d\n" msgstr "" #: exec.c:793 #, c-format msgid "External commands allowed\n" msgstr "" #: exec.c:789 #, c-format msgid "External commands are %s\n" msgstr "" #: exec.c:796 #, c-format msgid "External commands disallowed\n" msgstr "" #: archives.c:62 msgid "Extraction path ('q' to quit): " msgstr "" #: properties.c:390 #, c-format msgid "Fifo" msgstr "" #: archives.c:673 msgid "File name ('q' to quit): " msgstr "" #: bookmarks.c:572 #, c-format msgid "File succesfully bookmarked\n" msgstr "" #: selection.c:994 msgid "File(s) to be deselected (ex: 1 2-6, or *): " msgstr "" #: trash.c:563 msgid "File(s) to be removed (ex: 1 2-6, or *): " msgstr "" #: trash.c:881 msgid "File(s) to be undeleted (ex: 1 2-6, or *): " msgstr "" #: file_operations.c:740 msgid "Filename ('q' to quit): " msgstr "" #: exec.c:725 msgid "Files counter disabled\n" msgstr "" #: exec.c:718 msgid "Files counter enabled\n" msgstr "" #: misc.c:369 msgid "Filter unset" msgstr "" #: keybinds.c:842 #, c-format msgid "Folders first %s\n" msgstr "" #: exec.c:698 msgid "Folders first disabled\n" msgstr "" #: exec.c:694 msgid "Folders first enabled\n" msgstr "" #: exec.c:689 #, c-format msgid "Folders first is %s\n" msgstr "" #: exec.c:1803 msgid "Full directory size disabled\n" msgstr "" #: exec.c:1792 msgid "Full directory size enabled\n" msgstr "" #: exec.c:1799 msgid "Full directory size is already disabled" msgstr "" #: exec.c:1788 msgid "Full directory size is already enabled" msgstr "" #: search.c:211 msgid "Glob: No matches found. Trying regex..." msgstr "" #: keybinds.c:894 #, c-format msgid "Hidden files %s\n" msgstr "" #: exec.c:1121 msgid "Hidden files disabled\n" msgstr "" #: exec.c:1128 msgid "Hidden files enabled\n" msgstr "" #: exec.c:1113 #, c-format msgid "Hidden files is %s\n" msgstr "" #: history.c:405 #, c-format msgid "History is %s\n" msgstr "" #: archives.c:692 #, c-format msgid "Invalid file name\n" msgstr "" #: name_cleaner.c:572 msgid "Is this OK? [y/N/(e)dit] " msgstr "" #: history.c:88 #, c-format msgid "Logs %s\n" msgstr "" #: history.c:103 msgid "Logs already disabled" msgstr "" #: history.c:93 msgid "Logs already enabled" msgstr "" #: history.c:106 msgid "Logs succesfully disabled" msgstr "" #: history.c:96 msgid "Logs successfully enabled" msgstr "" #: keybinds.c:810 #, c-format msgid "Long view mode %s\n" msgstr "" #: mime.c:1472 #, c-format msgid "MIME type: %s\n" msgstr "" #: search.c:457 #, c-format msgid "Matches found: %d\n" msgstr "" #: search.c:810 #, c-format msgid "Matches found: %zu\n" msgstr "" #: exec.c:622 exec.c:634 #, c-format msgid "Max files set to %d\n" msgstr "" #: exec.c:615 msgid "Max files unset\n" msgstr "" #: exec.c:603 #, c-format msgid "Max files: %d\n" msgstr "" #: exec.c:601 msgid "Max files: unset" msgstr "" #: keybinds.c:339 #, c-format msgid "Max name length set back to %d\n" msgstr "" #: keybinds.c:337 msgid "Max name length unset\n" msgstr "" #: media.c:504 msgid "Media" msgstr "" #: properties.c:425 #, c-format msgid "Modify: \t%s%s%s\n" msgstr "" #: media.c:524 msgid "Mounted devices" msgstr "" #: media.c:504 media.c:523 msgid "Mountpoints" msgstr "" #: jump.c:313 msgid "" "NOTE 2: An asterisk next rank values means that the corresponding directory " "is bookmarked, pinned, or currently used in some workspace\n" msgstr "" #: jump.c:311 msgid "" "NOTE: First time access is displayed in days, while last time access is " "displayed in hours" msgstr "" #: mime.c:1471 remotes.c:56 #, c-format msgid "Name: %s\n" msgstr "" #: config.c:87 #, c-format msgid "New configuration file written to '%s'\n" msgstr "" #: archives.c:1085 msgid "New format (ex: .tar.xz): " msgstr "" #: file_operations.c:1068 msgid "New path ('q' to quit): " msgstr "" #: remotes.c:69 msgid "No" msgstr "" #: config.c:58 msgid "No configuration file found" msgstr "" #: tags.c:167 #, c-format msgid "No file tagged as '%s'\n" msgstr "" #: misc.c:361 msgid "No filter set" msgstr "" #: search.c:673 search.c:812 #, c-format msgid "No matches found\n" msgstr "" #: exec.c:1210 msgid "No pinned file" msgstr "" #: mime.c:1378 msgid "No such ELN" msgstr "" #: mime.c:1471 msgid "None" msgstr "" #: config.c:80 #, c-format msgid "Old configuration file stored as '%s'\n" msgstr "" #: keybinds.c:1533 #, c-format msgid "Only directories %s\n" msgstr "" #: exec.c:975 #, c-format msgid "Opener set to '%s'\n" msgstr "" #: archives.c:117 archives.c:762 archives.c:948 msgid "Operation: " msgstr "" #: jump.c:316 msgid "Order\tVisits\tFirst\tLast\tRank\tDirectory" msgstr "" #: exec.c:765 msgid "Pager disabled\n" msgstr "" #: exec.c:761 msgid "Pager enabled\n" msgstr "" #: exec.c:1208 #, c-format msgid "Pinned file: %s\n" msgstr "" #: properties.c:391 #, c-format msgid "Regular file" msgstr "" #: file_operations.c:1127 msgid "Relink as a broken symbolic link? [y/n] " msgstr "" #: properties.c:434 #, c-format msgid "Size: \t\t%s%s%s\n" msgstr "" #: properties.c:386 #, c-format msgid "Socket" msgstr "" #: listing.c:304 msgid "Sorted by: " msgstr "" #: sort.c:466 msgid "Sorting method: " msgstr "" #: misc.c:1643 #, c-format msgid "Succesfully unpinned %s\n" msgstr "" #: tags.c:656 #, c-format msgid "Successfully merged %s%s%s into %s%s%s\n" msgstr "" #: bookmarks.c:365 #, c-format msgid "Successfully removed '%s'\n" msgstr "" #: tags.c:484 #, c-format msgid "Successfully tagged %zu file(s)\n" msgstr "" #: tags.c:554 #, c-format msgid "Successfully untagged %zu file(s)\n" msgstr "" #: exec.c:991 exec.c:995 keybinds.c:870 msgid "Switched back to normal mode\n" msgstr "" #: keybinds.c:868 msgid "Switched to light mode\n" msgstr "" #: properties.c:387 #, c-format msgid "Symbolic link" msgstr "" #: exec.c:733 msgid "The files counter is disabled" msgstr "" #: exec.c:731 msgid "The files counter is enabled" msgstr "" #: exec.c:756 #, c-format msgid "The files pager is %s\n" msgstr "" #: exec.c:1188 #, c-format msgid "Toggled executable bit on %zu %s\n" msgstr "" #: exec.c:1689 #, c-format msgid "" "Total files: %zu\n" "Directories: %zu\n" "Regular files: %zu\n" "Executable files: %zu\n" "Hidden files: %zu\n" "SUID files: %zu\n" "SGID files: %zu\n" "Files w/capabilities: %zu\n" "FIFO/pipes: %zu\n" "Sockets: %zu\n" "Block devices: %zu\n" "Character devices: %zu\n" "Symbolic links: %zu\n" "Broken symbolic links: %zu\n" "Multi-link files: %zu\n" "Files w/extended attributes: %zu\n" "Other-writable files: %zu\n" "Sticky files: %zu\n" "Unknown file types: %zu\n" "Unstatable files: %zu\n" msgstr "" #: properties.c:441 msgid "Total size: \t" msgstr "" #: listing.c:1400 #, c-format msgid "" "Total size: %s%s%s\n" "Largest file: %s%s%s %c%s%s%s%c\n" msgstr "" #: mime.c:555 msgid "Try 'mm, mime edit APPLICATION'\n" msgstr "" #: exec.c:661 msgid "Unicode disabled" msgstr "" #: exec.c:658 msgid "Unicode enabled" msgstr "" #: exec.c:655 #, c-format msgid "Unicode is %s\n" msgstr "" #: archives.c:669 msgid "" "Use extension to specify archive/compression type (defaults to .tar.gz)\n" "Example: myarchive.xz" msgstr "" #: remotes.c:70 msgid "Yes" msgstr "" #: actions.c:371 msgid "actions: No actions defined. Use the 'actions edit' command to add some" msgstr "" #: exec.c:790 msgid "allowed" msgstr "" #: archives.c:713 #, c-format msgid "archiver: %s: Error dequoting file name\n" msgstr "" #: archives.c:909 #, c-format msgid "archiver: %s: Not an archive/compressed file\n" msgstr "" #: sort.c:378 #, c-format msgid "atime %s\n" msgstr "" #: bookmarks.c:200 bookmarks.c:244 #, c-format msgid "bookmarks: %s: No such bookmark\n" msgstr "" #: bookmarks.c:416 #, c-format msgid "bookmarks: %s: Path already bookmarked\n" msgstr "" #: bookmarks.c:493 #, c-format msgid "bookmarks: %s: This name is already in use\n" msgstr "" #: bookmarks.c:461 #, c-format msgid "bookmarks: %s: This shortcut is already in use\n" msgstr "" #: bookmarks.c:274 #, c-format msgid "" "bookmarks: All bookmarks were deleted\n" " However, a backup copy was created (%s)\n" msgstr "" #: bookmarks.c:279 #, c-format msgid "bookmarks: Error creating backup file. No bookmark was deleted\n" msgstr "" #: bookmarks.c:309 #, c-format msgid "bookmarks: Error creating temporary file\n" msgstr "" #: bookmarks.c:546 #, c-format msgid "bookmarks: Error generating the bookmark line\n" msgstr "" #: bookmarks.c:391 bookmarks.c:554 bookmarks.c:563 #, c-format msgid "bookmarks: Error opening the bookmarks file\n" msgstr "" #: bookmarks.c:226 #, c-format msgid "bookmarks: Error parsing input\n" msgstr "" #: bookmarks.c:162 msgid "bookmarks: There are no bookmarks" msgstr "" #: sort.c:381 #, c-format msgid "btime %s\n" msgstr "" #: sort.c:383 #, c-format msgid "btime (not available: using 'ctime') %s\n" msgstr "" #: file_operations.c:1473 #, c-format msgid "bulk: %s\n" msgstr "" #: file_operations.c:1436 #, c-format msgid "bulk: %s: Error dequoting file name\n" msgstr "" #: file_operations.c:1514 msgid "bulk: Line mismatch in renaming file\n" msgstr "" #: file_operations.c:1493 file_operations.c:1548 msgid "bulk: Nothing to do" msgstr "" #: sort.c:387 #, c-format msgid "ctime %s\n" msgstr "" #: selection.c:1053 #, c-format msgid "desel: '%s': Invalid ELN\n" msgstr "" #: selection.c:1042 #, c-format msgid "desel: '%s': Invalid entry\n" msgstr "" #: selection.c:1094 msgid "desel: There are no selected files" msgstr "" #: media.c:559 msgid "devices" msgstr "" #: exec.c:655 exec.c:690 exec.c:757 exec.c:820 exec.c:846 exec.c:1114 #: history.c:89 msgid "disabled" msgstr "" #: exec.c:655 exec.c:690 exec.c:757 exec.c:820 exec.c:846 exec.c:1114 #: history.c:88 msgid "enabled" msgstr "" #: sort.c:393 #, c-format msgid "extension %s\n" msgstr "" #: remotes.c:66 remotes.c:68 msgid "false" msgstr "" #: exec.c:1189 msgid "file" msgstr "" #: exec.c:1189 msgid "files" msgstr "" #: navigation.c:619 #, c-format msgid "history: %d: No such ELN\n" msgstr "" #: sort.c:395 #, c-format msgid "inode %s\n" msgstr "" #: media.c:559 msgid "mountpoints" msgstr "" #: media.c:561 msgid "mp: There are no available mountpoints\n" msgstr "" #: sort.c:389 #, c-format msgid "mtime %s\n" msgstr "" #: sort.c:374 #, c-format msgid "name %s\n" msgstr "" #: sort.c:372 msgid "none" msgstr "" #: exec.c:790 msgid "not allowed" msgstr "" #: sort.c:376 #, c-format msgid "size %s\n" msgstr "" #: trash.c:1028 #, c-format msgid "trash: %s: %s\n" msgstr "" #: trash.c:1034 #, c-format msgid "trash: %s: Cannot trash a %s device\n" msgstr "" #: trash.c:1016 #, c-format msgid "trash: Cannot trash '%s'\n" msgstr "" #: trash.c:541 trash.c:830 trash.c:984 msgid "trash: No trashed files" msgstr "" #: trash.c:263 msgid "trash: There are no trashed files" msgstr "" #: trash.c:1022 msgid "trash: Use 'trash del' to remove trashed files" msgstr "" #: remotes.c:66 remotes.c:68 msgid "true" msgstr "" #: trash.c:908 #, c-format msgid "undel: %s: Invalid ELN\n" msgstr "" #: properties.c:418 properties.c:420 msgid "unknown" msgstr "" #: sort.c:391 #, c-format msgid "version %s\n" msgstr "" clifm-1.26.3/translations/japanese/000077500000000000000000000000001506632037700172155ustar00rootroot00000000000000clifm-1.26.3/translations/japanese/clifm.po000066400000000000000000001233511506632037700206540ustar00rootroot00000000000000# This file is part of CliFM # Copyright (C) 2016-2022 # This file is distributed under the same license as the clifm package. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2022-04-23 14:46-0300\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: properties.c:400 #, c-format msgid "\tBlocks: %s%ld%s" msgstr "" #: properties.c:398 #, c-format msgid "\tBlocks: %s%lld%s" msgstr "" #: properties.c:420 #, c-format msgid "\tGid: %s%u (%s)%s\n" msgstr "" #: properties.c:404 #, c-format msgid "\tIO Block: %s%d%s" msgstr "" #: properties.c:406 #, c-format msgid "\tIO Block: %s%ld%s" msgstr "" #: properties.c:409 #, c-format msgid "\tInode: %s%llu%s\n" msgstr "" #: properties.c:411 #, c-format msgid "\tInode: %s%zu%s\n" msgstr "" #: properties.c:317 #, c-format msgid "\tName: %s%s%s -> %s (broken link)\n" msgstr "" #: properties.c:418 #, c-format msgid "\tUid: %s%u (%s)%s" msgstr "" #: misc.c:1789 #, c-format msgid "" "\n" " Press any key to continue... " msgstr "" #: selection.c:786 #, c-format msgid "" "\n" "%s%sTotal size%s: %s\n" msgstr "" #: bookmarks.c:214 #, c-format msgid "" "\n" "%sEnter '%c' to quit.\n" msgstr "" #: selection.c:990 #, c-format msgid "" "\n" "%sEnter 'q' to quit or 'e' to edit the selections file\n" msgstr "" #: trash.c:559 trash.c:877 #, c-format msgid "" "\n" "%sEnter 'q' to quit.\n" msgstr "" #: archives.c:816 #, c-format msgid "" "\n" "%sNOTE%s: Zstandard does not support compression of multiple files into one " "single compressed file. Files will be compressed rather into multiple " "compressed files using the original file names\n" msgstr "" #: media.c:282 #, c-format msgid "" "\n" "%sUnmounted devices%s\n" "\n" msgstr "" #: colors.c:1831 #, c-format msgid "" "\n" "*The slash followed by a number (/xx) after directories or symbolic links to " "directories indicates the amount of files contained by the corresponding " "directory, excluding self (.) and parent (..) directories.\n" msgstr "" #: misc.c:1697 msgid "" "\n" "NOTE: Some keybindings on Haiku might differ. Take a look at your current " "keybindings via the 'kb' command" msgstr "" #: colors.c:1835 #, c-format msgid "" "\n" "The second field in this list is the code that is to be used to modify the " "color of the corresponding file type in the color scheme file (in the " "\"FiletypeColors\" line), using the same ANSI style color format used by " "dircolors. By default, %s uses only 8/16 colors, but you can use 256 and RGB/" "true colors as well.\n" "\n" msgstr "" #: colors.c:1807 #, c-format msgid " %sfile name%s: bd: Block special file\n" msgstr "" #: colors.c:1818 #, c-format msgid " %sfile name%s: ca: File with capabilities\n" msgstr "" #: colors.c:1813 #, c-format msgid " %sfile name%s: cd: Character special file\n" msgstr "" #: colors.c:1800 #, c-format msgid " %sfile name%s: di: Directory*\n" msgstr "" #: colors.c:1801 #, c-format msgid " %sfile name%s: ed: EMPTY directory\n" msgstr "" #: colors.c:1806 #, c-format msgid " %sfile name%s: ee: Empty executable file\n" msgstr "" #: colors.c:1815 #, c-format msgid " %sfile name%s: ef: Empty (zero-lenght) file\n" msgstr "" #: colors.c:1805 #, c-format msgid " %sfile name%s: ex: Executable file\n" msgstr "" #: colors.c:1814 #, c-format msgid " %sfile name%s: fi: Regular file\n" msgstr "" #: colors.c:1808 #, c-format msgid " %sfile name%s: ln: Symbolic link*\n" msgstr "" #: colors.c:1810 #, c-format msgid " %sfile name%s: mh: Multi-hardlink\n" msgstr "" #: colors.c:1796 #, c-format msgid " %sfile name%s: nd: Directory with no read permission\n" msgstr "" #: colors.c:1802 #, c-format msgid " %sfile name%s: ne: EMPTY directory with no read permission\n" msgstr "" #: colors.c:1798 #, c-format msgid " %sfile name%s: nf: File with no read permission\n" msgstr "" #: colors.c:1828 #, c-format msgid " %sfile name%s: no: Unknown file type\n" msgstr "" #: colors.c:1809 #, c-format msgid " %sfile name%s: or: Broken symbolic link\n" msgstr "" #: colors.c:1825 #, c-format msgid " %sfile name%s: ow: Other-writable and NOT sticky directory*\n" msgstr "" #: colors.c:1812 #, c-format msgid " %sfile name%s: pi: Pipe or FIFO special file\n" msgstr "" #: colors.c:1817 #, c-format msgid " %sfile name%s: sg: SGID file\n" msgstr "" #: colors.c:1811 #, c-format msgid " %sfile name%s: so: Socket file\n" msgstr "" #: colors.c:1819 #, c-format msgid " %sfile name%s: st: Sticky and NOT other-writable directory*\n" msgstr "" #: colors.c:1816 #, c-format msgid " %sfile name%s: su: SUID file\n" msgstr "" #: colors.c:1822 #, c-format msgid " %sfile name%s: tw: Sticky and other-writable directory*\n" msgstr "" #: colors.c:1829 #, c-format msgid " %sfile name%s: uf: Unaccessible (non-stat'able) file\n" msgstr "" #: remotes.c:67 #, c-format msgid " Auto-mount: %s\n" msgstr "" #: remotes.c:65 #, c-format msgid " Auto-unmount: %s\n" msgstr "" #: remotes.c:58 #, c-format msgid " Comment: %s\n" msgstr "" #: remotes.c:62 #, c-format msgid " Mount command: %s\n" msgstr "" #: remotes.c:69 #, c-format msgid " Mounted: %s\n" msgstr "" #: remotes.c:60 #, c-format msgid " Mountpoint: %s\n" msgstr "" #: remotes.c:64 #, c-format msgid " Unmount command: %s\n" msgstr "" #: config.c:1263 #, c-format msgid "" "# %s profile\n" "# Write here the commands you want to be executed at startup\n" "# Ex:\n" "#echo -e \"%s, the command line file manager\"\n" msgstr "" #: strings.c:1631 #, c-format msgid "%c%s: There are no selected files%c" msgstr "" #: selection.c:938 #, c-format msgid "%d file(s) deselected. " msgstr "" #: sort.c:364 #, c-format msgid "%s %s\n" msgstr "" #: misc.c:1757 #, c-format msgid "%s %s (%s), by %s\n" msgstr "" #: misc.c:1776 #, c-format msgid "" "%s %s (%s), by %s\n" "Contact: %s\n" "Website: %s\n" "License: %s\n" msgstr "" #: tags.c:115 #, c-format msgid "%s (error resolving link target)\n" msgstr "" #: sort.c:358 #, c-format msgid "%s (not available: using 'name') %s\n" msgstr "" #: config.c:1320 #, c-format msgid "" "%s created a new MIME list file (%s) It is recommended to edit this file " "(entering 'mm edit' or pressing F6) to add the programs you use and remove " "those you don't. This will make the process of opening files faster and " "smoother\n" msgstr "" #: bookmarks.c:89 #, c-format msgid "" "%s%s\n" "Enter '%c' to edit your bookmarks or '%c' to quit.\n" msgstr "" #: file_operations.c:1055 #, c-format msgid "%s%s%s currently pointing to " msgstr "" #: file_operations.c:1052 #, c-format msgid "%s%s%s currently pointing to nowhere (broken link)\n" msgstr "" #: file_operations.c:1167 #, c-format msgid "%s%s%s successfully relinked to " msgstr "" #: archives.c:1188 #, c-format msgid "%s%s%s: Succesfully mounted on %s\n" msgstr "" #: archives.c:1009 #, c-format msgid "%s%sFile%s: %s\n" msgstr "" #: selection.c:732 #, c-format msgid "%s%sSelection Box%s\n" msgstr "" #: selection.c:543 #, c-format msgid "%s%sTotal size%s: %s\n" msgstr "" #: main.c:759 #, c-format msgid "%s->%s Running as root%s\n" msgstr "" #: history.c:540 history.c:579 #, c-format msgid "%s: !%s: Event not found\n" msgstr "" #: history.c:494 #, c-format msgid "%s: !%s: event not found\n" msgstr "" #: mime.c:1349 #, c-format msgid "" "%s: %d MIME definition(s) imported from the system. Old MIME list file " "stored as %s\n" msgstr "" #: name_cleaner.c:649 #, c-format msgid "%s: %d file(s) bleached\n" msgstr "" #: selection.c:940 #, c-format msgid "%s: %d file(s) deselected. " msgstr "" #: navigation.c:80 #, c-format msgid "%s: %d is already the current workspace\n" msgstr "" #: strings.c:1702 #, c-format msgid "" "%s: %d: ELN-filename conflict. Bypass internal expansions to fix this issue: " "';CMD FILENAME'\n" msgstr "" #: media.c:199 #, c-format msgid "%s: %d: Invalid ELN\n" msgstr "" #: navigation.c:72 #, c-format msgid "%s: %d: Invalid workspace number\n" msgstr "" #: name_cleaner.c:408 prompt.c:462 #, c-format msgid "%s: %s\n" msgstr "" #: file_operations.c:977 #, c-format msgid "" "%s: %s (%s): Cannot open file\n" "Try 'APPLICATION FILENAME'\n" msgstr "" #: aux.c:817 aux.c:831 aux.c:845 #, c-format msgid "%s: %s failed to allocate %zu bytes\n" msgstr "" #: config.c:502 file_operations.c:108 file_operations.c:134 remotes.c:137 #, c-format msgid "%s: %s: %s\n" msgstr "" #: init.c:1692 #, c-format msgid "" "%s: %s: %s\n" "Falling back to default\n" msgstr "" #: init.c:1637 #, c-format msgid "" "%s: %s: %s\n" "Falling back to default configuration directory\n" msgstr "" #: init.c:1604 #, c-format msgid "" "%s: %s: %s\n" "Falling back to the default bookmarks file\n" msgstr "" #: init.c:1664 #, c-format msgid "" "%s: %s: %s\n" "Falling back to the default keybindings file\n" msgstr "" #: file_operations.c:953 #, c-format msgid "%s: %s: Broken symbolic link\n" msgstr "" #: init.c:1628 #, c-format msgid "" "%s: %s: Cannot create directory (error %d)\n" "Falling back to default configuration directory\n" msgstr "" #: profiles.c:302 #, c-format msgid "%s: %s: Cannot create profile: Home directory not found\n" msgstr "" #: file_operations.c:1741 #, c-format msgid "%s: %s: Cannot create symlink: %s\n" msgstr "" #: tags.c:384 #, c-format msgid "%s: %s: Cannot create tag\n" msgstr "" #: tags.c:50 #, c-format msgid "%s: %s: Cannot create tag: file already exists\n" msgstr "" #: file_operations.c:251 #, c-format msgid "%s: %s: Cannot open file\n" msgstr "" #: file_operations.c:210 #, c-format msgid "%s: %s: Directory empty\n" msgstr "" #: profiles.c:371 #, c-format msgid "%s: %s: Error creating profile\n" msgstr "" #: tags.c:277 #, c-format msgid "%s: %s: Error creating tag\n" msgstr "" #: config.c:1240 #, c-format msgid "%s: %s: Error creating tags directory. Tag function disabled\n" msgstr "" #: aux.c:143 #, c-format msgid "%s: %s: Error deescaping string\n" msgstr "" #: file_operations.c:1022 file_operations.c:1111 #, c-format msgid "%s: %s: Error dequoting file\n" msgstr "" #: bookmarks.c:794 misc.c:754 name_cleaner.c:523 properties.c:684 #: readline.c:401 search.c:145 search.c:552 #, c-format msgid "%s: %s: Error dequoting file name\n" msgstr "" #: file_operations.c:776 file_operations.c:911 #, c-format msgid "%s: %s: Error dequoting filename\n" msgstr "" #: navigation.c:281 #, c-format msgid "%s: %s: Error dequoting string\n" msgstr "" #: aux.c:159 navigation.c:288 #, c-format msgid "%s: %s: Error expanding tilde\n" msgstr "" #: remotes.c:255 trash.c:136 #, c-format msgid "%s: %s: Error getting parent directory\n" msgstr "" #: strings.c:1766 #, c-format msgid "%s: %s: Error getting variable name\n" msgstr "" #: mime.c:282 #, c-format msgid "%s: %s: Error opening file\n" msgstr "" #: strings.c:1591 strings.c:1733 strings.c:1973 strings.c:2047 #, c-format msgid "%s: %s: Error quoting file name\n" msgstr "" #: profiles.c:415 #, c-format msgid "%s: %s: Error removing profile\n" msgstr "" #: file_operations.c:814 #, c-format msgid "%s: %s: File already exists. Trying with '%s' instead\n" msgstr "" #: tags.c:48 #, c-format msgid "%s: %s: File already tagged\n" msgstr "" #: tags.c:531 #, c-format msgid "%s: %s: File not tagged as %s%s%s\n" msgstr "" #: file_operations.c:1095 #, c-format msgid "%s: %s: Invalid ELN\n" msgstr "" #: exec.c:1781 exec.c:1808 #, c-format msgid "%s: %s: Invalid argument. Try 'fz -h'\n" msgstr "" #: exec.c:628 #, c-format msgid "%s: %s: Invalid number\n" msgstr "" #: exec.c:1567 #, c-format msgid "%s: %s: Is a directory\n" msgstr "" #: misc.c:916 #, c-format msgid "%s: %s: No alias found\n" msgstr "" #: mime.c:1445 mime.c:1449 #, c-format msgid "%s: %s: No associated application found\n" msgstr "" #: navigation.c:371 #, c-format msgid "%s: %s: No matches found\n" msgstr "" #: exec.c:1056 #, c-format msgid "%s: %s: No such alias\n" msgstr "" #: colors.c:955 #, c-format msgid "%s: %s: No such color scheme. Falling back to default\n" msgstr "" #: colors.c:1064 #, c-format msgid "%s: %s: No such color scheme. Falling back to the default one\n" msgstr "" #: jump.c:432 #, c-format msgid "%s: %s: No such order number\n" msgstr "" #: profiles.c:393 #, c-format msgid "%s: %s: No such profile\n" msgstr "" #: profiles.c:132 #, c-format msgid "" "%s: %s: No such profile\n" "To add a new profile enter 'pf add PROFILE'\n" msgstr "" #: remotes.c:118 #, c-format msgid "%s: %s: No such remote\n" msgstr "" #: selection.c:888 #, c-format msgid "%s: %s: No such selected file\n" msgstr "" #: sort.c:457 #, c-format msgid "%s: %s: No such sorting method\n" msgstr "" #: tags.c:75 tags.c:158 #, c-format msgid "%s: %s: No such tag\n" msgstr "" #: misc.c:634 #, c-format msgid "%s: %s: Not a directory\n" msgstr "" #: file_operations.c:1044 #, c-format msgid "%s: %s: Not a symbolic link\n" msgstr "" #: remotes.c:225 #, c-format msgid "%s: %s: Not mounted\n" msgstr "" #: sanitize.c:368 #, c-format msgid "" "%s: %s: Only command base names are allowed. Ex: 'nano' instead of '/usr/bin/" "nano'\n" msgstr "" #: profiles.c:297 #, c-format msgid "%s: %s: Profile already exists\n" msgstr "" #: remotes.c:209 #, c-format msgid "%s: %s: Remote mounted on %s\n" msgstr "" #: tags.c:317 #, c-format msgid "%s: %s: Successfully removed tag\n" msgstr "" #: main.c:826 profiles.c:165 #, c-format msgid "" "%s: %s: System shell not found. Please edit the configuration file to " "specify a working shell.\n" msgstr "" #: tags.c:271 #, c-format msgid "%s: %s: Tag already exists\n" msgstr "" #: media.c:503 #, c-format msgid "%s: %s: This feature is not available on Haiku\n" msgstr "" #: init.c:1643 #, c-format msgid "%s: %s: Using alternative configuration directory\n" msgstr "" #: misc.c:934 #, c-format msgid "%s: %zu aliases were successfully imported\n" msgstr "" #: init.c:207 #, c-format msgid "" "%s: %zu: Invalid workspace.\n" "Falling back to workspace %zu\n" msgstr "" #: jump.c:410 #, c-format msgid "%s: '%c': Invalid option\n" msgstr "" #: search.c:114 search.c:535 selection.c:429 #, c-format msgid "%s: '%c': Unrecognized file type\n" msgstr "" #: profiles.c:141 #, c-format msgid "%s: '%s' is the current profile\n" msgstr "" #: config.c:1889 #, c-format msgid "%s: '%s': %s. Using the current working directory as starting path\n" msgstr "" #: config.c:1228 #, c-format msgid "" "%s: '%s': Directory not writable. Bookmarks, commands logs, and commands " "history are disabled. Program messages won't be persistent. Using default " "options\n" msgstr "" #: config.c:1202 #, c-format msgid "%s: '%s': Directory not writable. Trash function disabled\n" msgstr "" #: config.c:2023 misc.c:379 #, c-format msgid "%s: '%s': Invalid regular expression\n" msgstr "" #: profiles.c:363 #, c-format msgid "%s: '%s': Profile succesfully created\n" msgstr "" #: profiles.c:406 #, c-format msgid "%s: '%s': Profile successfully removed\n" msgstr "" #: exec.c:1462 #, c-format msgid "%s: '%s': Syntax error\n" msgstr "" #: checks.c:107 #, c-format msgid "" "%s: '%s': Unsupported terminal. This terminal cannot understand escape " "sequences\n" msgstr "" #: config.c:550 #, c-format msgid "" "%s: '%s': Using a temporary directory for the Selection Box. Selected files " "won't be persistent across reboots" msgstr "" #: navigation.c:338 #, c-format msgid "%s: /: No parent directory\n" msgstr "" #: misc.c:937 #, c-format msgid "%s: 1 alias was successfully imported\n" msgstr "" #: config.c:99 #, c-format msgid "%s: Access to configuration files is not allowed in stealth mode\n" msgstr "" #: misc.c:902 #, c-format msgid "%s: Alias already exists\n" msgstr "" #: misc.c:855 #, c-format msgid "%s: Alias conflicts with internal command\n" msgstr "" #: config.c:113 #, c-format msgid "%s: Cannot access the configuration file\n" msgstr "" #: init.c:149 #, c-format msgid "" "%s: Cannot access the home directory. Trash, bookmarks, commands logs, and " "commands history are disabled. Program messages and selected files won't be " "persistent. Using default options\n" msgstr "" #: tags.c:643 #, c-format msgid "%s: Cannot merge tags: error moving tagged files\n" msgstr "" #: bookmarks.c:597 #, c-format msgid "%s: Cannot open the bookmarks file\n" msgstr "" #: history.c:248 #, c-format msgid "%s: Could not save directory history: %s\n" msgstr "" #: colors.c:539 #, c-format msgid "%s: Current color scheme: %s\n" msgstr "" #: colors.c:1789 #, c-format msgid "%s: Currently running without colors\n" msgstr "" #: misc.c:607 #, c-format msgid "" "%s: Default terminal not set. Use the configuration file (F10) to set it\n" msgstr "" #: trash.c:150 #, c-format msgid "%s: Directory is immutable\n" msgstr "" #: jump.c:291 #, c-format msgid "%s: Directory jumper function disabled\n" msgstr "" #: init.c:1035 init.c:1043 selection.c:486 #, c-format msgid "%s: Error expanding path\n" msgstr "" #: init.c:1246 #, c-format msgid "%s: Error expanding tilde. Using default opener\n" msgstr "" #: mime.c:460 #, c-format msgid "%s: Error getting home directory\n" msgstr "" #: main.c:848 #, c-format msgid "%s: Error getting hostname\n" msgstr "" #: mime.c:1463 #, c-format msgid "%s: Error getting mime-type\n" msgstr "" #: remotes.c:230 #, c-format msgid "%s: Error getting mountpoint for '%s'\n" msgstr "" #: misc.c:1051 #, c-format msgid "%s: Error getting variable value\n" msgstr "" #: misc.c:777 #, c-format msgid "%s: Error lauching new instance\n" msgstr "" #: checks.c:99 #, c-format msgid "%s: Error opening terminal: unknown\n" msgstr "" #: profiles.c:217 #, c-format msgid "%s: Error opening the history file\n" msgstr "" #: checks.c:512 #, c-format msgid "%s: Error parsing aliased command\n" msgstr "" #: history.c:503 history.c:522 history.c:556 #, c-format msgid "%s: Error parsing history command\n" msgstr "" #: media.c:447 #, c-format msgid "%s: Error retrieving mountpoint\n" msgstr "" #: init.c:387 #, c-format msgid "%s: Error retrieving user data\n" msgstr "" #: misc.c:968 #, c-format msgid "%s: Error saving last visited directory\n" msgstr "" #: misc.c:1566 #, c-format msgid "%s: Error storing pinned directory\n" msgstr "" #: selection.c:572 #, c-format msgid "%s: Error writing selected files to the selections file\n" msgstr "" #: exec.c:535 #, c-format msgid "%s: External commands are not allowed. Run 'ext on' to enable them.\n" msgstr "" #: init.c:1350 #, c-format msgid "%s: FZF not found. Falling back to standard TAB completion\n" msgstr "" #: init.c:251 main.c:815 #, c-format msgid "%s: Fatal error! Failed retrieving current working directory\n" msgstr "" #: trash.c:203 #, c-format msgid "%s: File is immutable\n" msgstr "" #: misc.c:614 #, c-format msgid "%s: Function only available for graphical environments\n" msgstr "" #: history.c:428 #, c-format msgid "%s: History function disabled\n" msgstr "" #: bookmarks.c:694 bookmarks.c:775 #, c-format msgid "%s: Invalid bookmark\n" msgstr "" #: navigation.c:625 #, c-format msgid "%s: Invalid history entry\n" msgstr "" #: exec.c:1654 #, c-format msgid "%s: Lira: %s\n" msgstr "" #: init.c:1609 #, c-format msgid "%s: Loaded alternative bookmarks file\n" msgstr "" #: init.c:1698 #, c-format msgid "%s: Loaded alternative configuration file\n" msgstr "" #: init.c:1670 #, c-format msgid "%s: Loaded alternative keybindings file\n" msgstr "" #: exec.c:1100 #, c-format msgid "%s: Log function disabled\n" msgstr "" #: strings.c:645 strings.c:702 #, c-format msgid "%s: Missing '%c'\n" msgstr "" #: remotes.c:386 #, c-format msgid "%s: Mounting remote...\n" msgstr "" #: misc.c:386 #, c-format msgid "%s: New filter successfully set\n" msgstr "" #: misc.c:926 #, c-format msgid "%s: No alias imported\n" msgstr "" #: exec.c:1022 exec.c:1042 #, c-format msgid "%s: No aliases found\n" msgstr "" #: colors.c:408 #, c-format msgid "%s: No color schemes found\n" msgstr "" #: selection.c:583 #, c-format msgid "%s: No matches found\n" msgstr "" #: media.c:193 media.c:400 #, c-format msgid "%s: No mount application found. Install either udevil or udisks2\n" msgstr "" #: media.c:517 #, c-format msgid "%s: No mount command found. Install either udevil or udisks2\n" msgstr "" #: remotes.c:172 #, c-format msgid "%s: No mount command specified for '%s'\n" msgstr "" #: remotes.c:123 #, c-format msgid "%s: No mountpoint specified for '%s'\n" msgstr "" #: misc.c:717 #, c-format msgid "" "%s: No option specified for '%s'\n" "Trying '%s -e %s %s'\n" msgstr "" #: exec.c:1421 keybinds.c:1444 misc.c:1624 #, c-format msgid "%s: No pinned file\n" msgstr "" #: remotes.c:48 #, c-format msgid "%s: No remotes defined\n" msgstr "" #: bookmarks.c:678 #, c-format msgid "%s: No such ELN\n" msgstr "" #: bookmarks.c:699 bookmarks.c:780 #, c-format msgid "%s: No such bookmark\n" msgstr "" #: colors.c:496 #, c-format msgid "%s: No such color scheme\n" msgstr "" #: trash.c:122 #, c-format msgid "%s: No such file or directory\n" msgstr "" #: tags.c:455 #, c-format msgid "" "%s: No tag specified. Specify a tag via :TAG. E.g. tag FILE1 FILE2 :TAG\n" msgstr "" #: tags.c:67 #, c-format msgid "%s: No tags found, Use 'tag new' to create new tags\n" msgstr "" #: remotes.c:236 #, c-format msgid "%s: No unmount command found for '%s'\n" msgstr "" #: file_operations.c:486 name_cleaner.c:561 name_cleaner.c:611 #, c-format msgid "%s: Nothing to do\n" msgstr "" #: mime.c:531 #, c-format msgid "%s: Nothing was imported. No MIME definitions found\n" msgstr "" #: mime.c:454 #, c-format msgid "%s: Nothing was imported. No graphical environment found\n" msgstr "" #: trash.c:90 trash.c:182 trash.c:190 trash.c:210 trash.c:226 #, c-format msgid "%s: Permission denied\n" msgstr "" #: keybinds.c:96 keybinds.c:139 #, c-format msgid "%s: Restart the program for changes to take effect\n" msgstr "" #: config.c:2086 #, c-format msgid "" "%s: Running in stealth mode: trash, persistent selection and directory " "history, just as bookmarks, logs and configuration files, are disabled.\n" msgstr "" #: misc.c:1616 #, c-format msgid "%s: Succesfully pinned '%s'\n" msgstr "" #: tags.c:282 #, c-format msgid "%s: Successfully created tag\n" msgstr "" #: media.c:558 #, c-format msgid "%s: There are no available %s\n" msgstr "" #: exec.c:932 exec.c:950 #, c-format msgid "%s: There are no messages\n" msgstr "" #: exec.c:415 #, c-format msgid "%s: To gracefully quit enter 'q'\n" msgstr "" #: trash.c:797 trash.c:1085 #, c-format msgid "%s: Trash function disabled\n" msgstr "" #: misc.c:1703 #, c-format msgid "%s: Unable to find any pager\n" msgstr "" #: media.c:221 #, c-format msgid "%s: Unmounted %s\n" msgstr "" #: remotes.c:423 #, c-format msgid "%s: Unmounting remote...\n" msgstr "" #: main.c:744 #, c-format msgid "%s: Unsupported CPU architecture\n" msgstr "" #: main.c:750 #, c-format msgid "%s: Unsupported operating system\n" msgstr "" #: exec.c:2194 #, c-format msgid "%s: archiving: %s\n" msgstr "" #: exec.c:2175 #, c-format msgid "%s: bleach: %s\n" msgstr "" #: bookmarks.c:814 #, c-format msgid "%s: bookmarks: %s\n" msgstr "" #: navigation.c:444 #, c-format msgid "%s: cd: Home directory not found\n" msgstr "" #: colors.c:512 #, c-format msgid "" "%s: color schemes: %s\n" "TIP: To change the current color scheme use the following environment " "variables: CLIFM_FILE_COLORS, CLIFM_IFACE_COLORS, and CLIFM_EXT_COLORS\n" msgstr "" #: mime.c:1613 #, c-format msgid "%s: file: Command not found\n" msgstr "" #: config.c:1499 #, c-format msgid "%s: fopen: '%s': %s. Using default values.\n" msgstr "" #: checks.c:161 #, c-format msgid "%s: fzf not found. Falling back to standard TAB completion\n" msgstr "" #: init.c:1357 #, c-format msgid "%s: fzftab: %s\n" msgstr "" #: init.c:1379 #, c-format msgid "%s: fzytab: %s\n" msgstr "" #: init.c:1335 #, c-format msgid "%s: highlight: %s\n" msgstr "" #: exec.c:893 init.c:1267 #, c-format msgid "%s: icons: %s\n" msgstr "" #: jump.c:663 #, c-format msgid "%s: jump: No matches found\n" msgstr "" #: media.c:510 #, c-format msgid "%s: media: Function only available on Linux systems\n" msgstr "" #: profiles.c:315 #, c-format msgid "%s: mkdir: %s: Error creating configuration directory\n" msgstr "" #: config.c:1216 #, c-format msgid "" "%s: mkdir: '%s': Error creating configuration directory. Bookmarks, commands " "logs, and command history are disabled. Program messages won't be " "persistent. Using default options\n" msgstr "" #: config.c:1194 #, c-format msgid "" "%s: mkdir: '%s': Error creating trash directory. Trash function disabled\n" msgstr "" #: config.c:1277 #, c-format msgid "" "%s: mkdir: Error creating colors directory. Using the default color scheme\n" msgstr "" #: config.c:1289 #, c-format msgid "" "%s: mkdir: Error creating plugins directory. The actions function is " "disabled\n" msgstr "" #: init.c:1504 #, c-format msgid "" "%s: option requires an argument -- '%c'\n" "Try '%s --help' for more information.\n" msgstr "" #: selection.c:123 #, c-format msgid "%s: sel: %s: Already selected\n" msgstr "" #: selection.c:327 #, c-format msgid "%s: sel: %s: Invalid regular expression\n" msgstr "" #: trash.c:637 #, c-format msgid "%s: trash: %d: Invalid ELN\n" msgstr "" #: exec.c:1742 exec.c:1766 init.c:1290 #, c-format msgid "%s: trash: %s\n" msgstr "" #: trash.c:234 #, c-format msgid "%s: trash: %s (%s): Unsupported file type\n" msgstr "" #: trash.c:419 #, c-format msgid "" "%s: trash: %s/%s: Failed removing trash file\n" "Try removing it manually\n" msgstr "" #: trash.c:350 #, c-format msgid "%s: trash: %s: Error getting file name\n" msgstr "" #: trash.c:291 #, c-format msgid "%s: trash: %s: Error removing trashed file\n" msgstr "" #: trash.c:394 #, c-format msgid "%s: trash: %s: Failed copying file to Trash\n" msgstr "" #: trash.c:440 #, c-format msgid "%s: trash: %s: Failed encoding path\n" msgstr "" #: trash.c:615 #, c-format msgid "%s: trash: %s: Invalid ELN\n" msgstr "" #: trash.c:596 trash.c:646 #, c-format msgid "%s: trash: Error trashing %s\n" msgstr "" #: checks.c:123 #, c-format msgid "%s: udisks2 not found. Falling back to udevil\n" msgstr "" #: trash.c:933 #, c-format msgid "%s: undel: %d: Invalid ELN\n" msgstr "" #: trash.c:714 #, c-format msgid "%s: undel: %s: Error decoding original path\n" msgstr "" #: trash.c:770 #, c-format msgid "%s: undel: %s: Error removing info file\n" msgstr "" #: trash.c:777 #, c-format msgid "%s: undel: %s: Error restoring trashed file\n" msgstr "" #: trash.c:676 #, c-format msgid "" "%s: undel: Info file for '%s' not found. Try restoring the file manually\n" msgstr "" #: init.c:1525 #, c-format msgid "%s: unknown option character '\\%x'\n" msgstr "" #: init.c:1521 #, c-format msgid "" "%s: unrecognized option '%c'\n" "Try '%s --help' for more information.\n" msgstr "" #: init.c:1513 #, c-format msgid "" "%s: unrecognized option '%s'\n" "Try '%s --help' for more information.\n" msgstr "" #: bookmarks.c:609 #, c-format msgid "" "%sBookmarks Manager%s\n" "\n" msgstr "" #: bookmarks.c:208 #, c-format msgid "" "%sBookmarks%s\n" "\n" msgstr "" #: colors.c:1844 #, c-format msgid "" "%sExtension colors%s\n" "\n" msgstr "" #: colors.c:1795 #, c-format msgid "" "%sFile type colors%s\n" "\n" msgstr "" #: archives.c:1028 #, c-format msgid "%sFile%s: %s\n" msgstr "" #: media.c:526 #, c-format msgid "" "%sMountpoints%s\n" "\n" msgstr "" #: archives.c:940 #, c-format msgid "%sNOTE%s: Using Zstandard\n" msgstr "" #: selection.c:551 #, c-format msgid "%sSelection Box%s\n" msgstr "" #: trash.c:535 trash.c:862 #, c-format msgid "" "%sTrashed files%s\n" "\n" msgstr "" #: archives.c:1205 #, c-format msgid "" "%s[e]%sxtract %s[E]%sxtract-to-dir %s[l]%sist %s[m]%sount %s[r]%sepack " "%s[q]%suit\n" msgstr "" #: archives.c:321 #, c-format msgid "" "%s[e]%sxtract %s[E]%sxtract-to-dir %s[l]%sist %s[t]%sest %s[m]%sount " "%s[q]%suit\n" msgstr "" #: archives.c:757 archives.c:941 #, c-format msgid "%s[e]%sxtract %s[t]%sest %s[i]%snfo %s[q]%suit\n" msgstr "" #: selection.c:941 #, c-format msgid "%zu file(s) currently selected\n" msgstr "" #: selection.c:601 #, c-format msgid "%zu files are now in the Selection Box\n" msgstr "" #: selection.c:603 #, c-format msgid "" "%zu selected file(s):\n" "\n" msgstr "" #: search.c:634 #, c-format msgid "'%s': Invalid regular expression\n" msgstr "" #: properties.c:424 #, c-format msgid "Access: \t%s%s%s\n" msgstr "" #: bookmarks.c:292 msgid "All bookmarks succesfully removed\n" msgstr "" #: selection.c:1106 msgid "All files deselected\n" msgstr "" #: mime.c:1482 #, c-format msgid "Associated application: %s [%s]\n" msgstr "" #: mime.c:1432 msgid "Associated application: None\n" msgstr "" #: mime.c:1479 #, c-format msgid "Associated application: ad [built-in] [%s]\n" msgstr "" #: exec.c:844 #, c-format msgid "Auto-open disabled\n" msgstr "" #: exec.c:841 #, c-format msgid "Auto-open enabled\n" msgstr "" #: exec.c:846 #, c-format msgid "Auto-open is %s\n" msgstr "" #: exec.c:818 #, c-format msgid "Autocd disabled\n" msgstr "" #: exec.c:815 #, c-format msgid "Autocd enabled\n" msgstr "" #: exec.c:820 #, c-format msgid "Autocd is %s\n" msgstr "" #: properties.c:429 #, c-format msgid "Birth: \t\t%s%s%s\n" msgstr "" #: properties.c:388 #, c-format msgid "Block special file" msgstr "" #: bookmarks.c:450 msgid "Bookmark line example: [sc]name:path" msgstr "" #: bookmarks.c:217 msgid "Bookmark(s) to be deleted (ex: 1 2-6, or *): " msgstr "" #: bookmarks.c:819 #, c-format msgid "Bookmarks function disabled\n" msgstr "" #: bookmarks.c:799 #, c-format msgid "Bookmarks: %s: %s\n" msgstr "" #: properties.c:426 #, c-format msgid "Change: \t%s%s%s\n" msgstr "" #: properties.c:389 #, c-format msgid "Character special file" msgstr "" #: bookmarks.c:93 msgid "Choose a bookmark: " msgstr "" #: media.c:611 msgid "Choose a mountpoint/device: " msgstr "" #: media.c:609 media.c:613 msgid "Choose a mountpoint: " msgstr "" #: mime.c:586 msgid "Choose an application ('q' to quit): " msgstr "" #: listing.c:309 #, c-format msgid "Color scheme %s->%s %s\n" msgstr "" #: exec.c:879 msgid "Columns disabled\n" msgstr "" #: exec.c:872 msgid "Columns enabled\n" msgstr "" #: file_operations.c:1562 msgid "Continue? [y/N] " msgstr "" #: tags.c:393 #, c-format msgid "Created new tag %s%s%s\n" msgstr "" #: misc.c:396 #, c-format msgid "Current filter: %c%s\n" msgstr "" #: properties.c:414 #, c-format msgid "Device: %s%d%s" msgstr "" #: properties.c:416 #, c-format msgid "Device: %s%zu%s" msgstr "" #: properties.c:385 #, c-format msgid "Directory" msgstr "" #: selection.c:737 msgid "Empty" msgstr "" #: file_operations.c:739 msgid "End filename with a slash to create a directory" msgstr "" #: media.c:601 msgid "Enter 'iELN' for device information. Ex: i4" msgstr "" #: archives.c:1081 media.c:600 msgid "Enter 'q' to quit" msgstr "" #: file_operations.c:1716 msgid "Enter links suffix ('q' to quit): " msgstr "" #: history.c:129 msgid "Error getting command!" msgstr "" #: mime.c:344 msgid "Error opening temporary file\n" msgstr "" #: archives.c:410 archives.c:419 archives.c:523 archives.c:532 msgid "Error querying file type\n" msgstr "" #: listing.c:1670 listing.c:2218 #, c-format msgid "Excluded files: %d\n" msgstr "" #: exec.c:793 #, c-format msgid "External commands allowed\n" msgstr "" #: exec.c:789 #, c-format msgid "External commands are %s\n" msgstr "" #: exec.c:796 #, c-format msgid "External commands disallowed\n" msgstr "" #: archives.c:62 msgid "Extraction path ('q' to quit): " msgstr "" #: properties.c:390 #, c-format msgid "Fifo" msgstr "" #: archives.c:673 msgid "File name ('q' to quit): " msgstr "" #: bookmarks.c:572 #, c-format msgid "File succesfully bookmarked\n" msgstr "" #: selection.c:994 msgid "File(s) to be deselected (ex: 1 2-6, or *): " msgstr "" #: trash.c:563 msgid "File(s) to be removed (ex: 1 2-6, or *): " msgstr "" #: trash.c:881 msgid "File(s) to be undeleted (ex: 1 2-6, or *): " msgstr "" #: file_operations.c:740 msgid "Filename ('q' to quit): " msgstr "" #: exec.c:725 msgid "Files counter disabled\n" msgstr "" #: exec.c:718 msgid "Files counter enabled\n" msgstr "" #: misc.c:369 msgid "Filter unset" msgstr "" #: keybinds.c:842 #, c-format msgid "Folders first %s\n" msgstr "" #: exec.c:698 msgid "Folders first disabled\n" msgstr "" #: exec.c:694 msgid "Folders first enabled\n" msgstr "" #: exec.c:689 #, c-format msgid "Folders first is %s\n" msgstr "" #: exec.c:1803 msgid "Full directory size disabled\n" msgstr "" #: exec.c:1792 msgid "Full directory size enabled\n" msgstr "" #: exec.c:1799 msgid "Full directory size is already disabled" msgstr "" #: exec.c:1788 msgid "Full directory size is already enabled" msgstr "" #: search.c:211 msgid "Glob: No matches found. Trying regex..." msgstr "" #: keybinds.c:894 #, c-format msgid "Hidden files %s\n" msgstr "" #: exec.c:1121 msgid "Hidden files disabled\n" msgstr "" #: exec.c:1128 msgid "Hidden files enabled\n" msgstr "" #: exec.c:1113 #, c-format msgid "Hidden files is %s\n" msgstr "" #: history.c:405 #, c-format msgid "History is %s\n" msgstr "" #: archives.c:692 #, c-format msgid "Invalid file name\n" msgstr "" #: name_cleaner.c:572 msgid "Is this OK? [y/N/(e)dit] " msgstr "" #: history.c:88 #, c-format msgid "Logs %s\n" msgstr "" #: history.c:103 msgid "Logs already disabled" msgstr "" #: history.c:93 msgid "Logs already enabled" msgstr "" #: history.c:106 msgid "Logs succesfully disabled" msgstr "" #: history.c:96 msgid "Logs successfully enabled" msgstr "" #: keybinds.c:810 #, c-format msgid "Long view mode %s\n" msgstr "" #: mime.c:1472 #, c-format msgid "MIME type: %s\n" msgstr "" #: search.c:457 #, c-format msgid "Matches found: %d\n" msgstr "" #: search.c:810 #, c-format msgid "Matches found: %zu\n" msgstr "" #: exec.c:622 exec.c:634 #, c-format msgid "Max files set to %d\n" msgstr "" #: exec.c:615 msgid "Max files unset\n" msgstr "" #: exec.c:603 #, c-format msgid "Max files: %d\n" msgstr "" #: exec.c:601 msgid "Max files: unset" msgstr "" #: keybinds.c:339 #, c-format msgid "Max name length set back to %d\n" msgstr "" #: keybinds.c:337 msgid "Max name length unset\n" msgstr "" #: media.c:504 msgid "Media" msgstr "" #: properties.c:425 #, c-format msgid "Modify: \t%s%s%s\n" msgstr "" #: media.c:524 msgid "Mounted devices" msgstr "" #: media.c:504 media.c:523 msgid "Mountpoints" msgstr "" #: jump.c:313 msgid "" "NOTE 2: An asterisk next rank values means that the corresponding directory " "is bookmarked, pinned, or currently used in some workspace\n" msgstr "" #: jump.c:311 msgid "" "NOTE: First time access is displayed in days, while last time access is " "displayed in hours" msgstr "" #: mime.c:1471 remotes.c:56 #, c-format msgid "Name: %s\n" msgstr "" #: config.c:87 #, c-format msgid "New configuration file written to '%s'\n" msgstr "" #: archives.c:1085 msgid "New format (ex: .tar.xz): " msgstr "" #: file_operations.c:1068 msgid "New path ('q' to quit): " msgstr "" #: remotes.c:69 msgid "No" msgstr "" #: config.c:58 msgid "No configuration file found" msgstr "" #: tags.c:167 #, c-format msgid "No file tagged as '%s'\n" msgstr "" #: misc.c:361 msgid "No filter set" msgstr "" #: search.c:673 search.c:812 #, c-format msgid "No matches found\n" msgstr "" #: exec.c:1210 msgid "No pinned file" msgstr "" #: mime.c:1378 msgid "No such ELN" msgstr "" #: mime.c:1471 msgid "None" msgstr "" #: config.c:80 #, c-format msgid "Old configuration file stored as '%s'\n" msgstr "" #: keybinds.c:1533 #, c-format msgid "Only directories %s\n" msgstr "" #: exec.c:975 #, c-format msgid "Opener set to '%s'\n" msgstr "" #: archives.c:117 archives.c:762 archives.c:948 msgid "Operation: " msgstr "" #: jump.c:316 msgid "Order\tVisits\tFirst\tLast\tRank\tDirectory" msgstr "" #: exec.c:765 msgid "Pager disabled\n" msgstr "" #: exec.c:761 msgid "Pager enabled\n" msgstr "" #: exec.c:1208 #, c-format msgid "Pinned file: %s\n" msgstr "" #: properties.c:391 #, c-format msgid "Regular file" msgstr "" #: file_operations.c:1127 msgid "Relink as a broken symbolic link? [y/n] " msgstr "" #: properties.c:434 #, c-format msgid "Size: \t\t%s%s%s\n" msgstr "" #: properties.c:386 #, c-format msgid "Socket" msgstr "" #: listing.c:304 msgid "Sorted by: " msgstr "" #: sort.c:466 msgid "Sorting method: " msgstr "" #: misc.c:1643 #, c-format msgid "Succesfully unpinned %s\n" msgstr "" #: tags.c:656 #, c-format msgid "Successfully merged %s%s%s into %s%s%s\n" msgstr "" #: bookmarks.c:365 #, c-format msgid "Successfully removed '%s'\n" msgstr "" #: tags.c:484 #, c-format msgid "Successfully tagged %zu file(s)\n" msgstr "" #: tags.c:554 #, c-format msgid "Successfully untagged %zu file(s)\n" msgstr "" #: exec.c:991 exec.c:995 keybinds.c:870 msgid "Switched back to normal mode\n" msgstr "" #: keybinds.c:868 msgid "Switched to light mode\n" msgstr "" #: properties.c:387 #, c-format msgid "Symbolic link" msgstr "" #: exec.c:733 msgid "The files counter is disabled" msgstr "" #: exec.c:731 msgid "The files counter is enabled" msgstr "" #: exec.c:756 #, c-format msgid "The files pager is %s\n" msgstr "" #: exec.c:1188 #, c-format msgid "Toggled executable bit on %zu %s\n" msgstr "" #: exec.c:1689 #, c-format msgid "" "Total files: %zu\n" "Directories: %zu\n" "Regular files: %zu\n" "Executable files: %zu\n" "Hidden files: %zu\n" "SUID files: %zu\n" "SGID files: %zu\n" "Files w/capabilities: %zu\n" "FIFO/pipes: %zu\n" "Sockets: %zu\n" "Block devices: %zu\n" "Character devices: %zu\n" "Symbolic links: %zu\n" "Broken symbolic links: %zu\n" "Multi-link files: %zu\n" "Files w/extended attributes: %zu\n" "Other-writable files: %zu\n" "Sticky files: %zu\n" "Unknown file types: %zu\n" "Unstatable files: %zu\n" msgstr "" #: properties.c:441 msgid "Total size: \t" msgstr "" #: listing.c:1400 #, c-format msgid "" "Total size: %s%s%s\n" "Largest file: %s%s%s %c%s%s%s%c\n" msgstr "" #: mime.c:555 msgid "Try 'mm, mime edit APPLICATION'\n" msgstr "" #: exec.c:661 msgid "Unicode disabled" msgstr "" #: exec.c:658 msgid "Unicode enabled" msgstr "" #: exec.c:655 #, c-format msgid "Unicode is %s\n" msgstr "" #: archives.c:669 msgid "" "Use extension to specify archive/compression type (defaults to .tar.gz)\n" "Example: myarchive.xz" msgstr "" #: remotes.c:70 msgid "Yes" msgstr "" #: actions.c:371 msgid "actions: No actions defined. Use the 'actions edit' command to add some" msgstr "" #: exec.c:790 msgid "allowed" msgstr "" #: archives.c:713 #, c-format msgid "archiver: %s: Error dequoting file name\n" msgstr "" #: archives.c:909 #, c-format msgid "archiver: %s: Not an archive/compressed file\n" msgstr "" #: sort.c:378 #, c-format msgid "atime %s\n" msgstr "" #: bookmarks.c:200 bookmarks.c:244 #, c-format msgid "bookmarks: %s: No such bookmark\n" msgstr "" #: bookmarks.c:416 #, c-format msgid "bookmarks: %s: Path already bookmarked\n" msgstr "" #: bookmarks.c:493 #, c-format msgid "bookmarks: %s: This name is already in use\n" msgstr "" #: bookmarks.c:461 #, c-format msgid "bookmarks: %s: This shortcut is already in use\n" msgstr "" #: bookmarks.c:274 #, c-format msgid "" "bookmarks: All bookmarks were deleted\n" " However, a backup copy was created (%s)\n" msgstr "" #: bookmarks.c:279 #, c-format msgid "bookmarks: Error creating backup file. No bookmark was deleted\n" msgstr "" #: bookmarks.c:309 #, c-format msgid "bookmarks: Error creating temporary file\n" msgstr "" #: bookmarks.c:546 #, c-format msgid "bookmarks: Error generating the bookmark line\n" msgstr "" #: bookmarks.c:391 bookmarks.c:554 bookmarks.c:563 #, c-format msgid "bookmarks: Error opening the bookmarks file\n" msgstr "" #: bookmarks.c:226 #, c-format msgid "bookmarks: Error parsing input\n" msgstr "" #: bookmarks.c:162 msgid "bookmarks: There are no bookmarks" msgstr "" #: sort.c:381 #, c-format msgid "btime %s\n" msgstr "" #: sort.c:383 #, c-format msgid "btime (not available: using 'ctime') %s\n" msgstr "" #: file_operations.c:1473 #, c-format msgid "bulk: %s\n" msgstr "" #: file_operations.c:1436 #, c-format msgid "bulk: %s: Error dequoting file name\n" msgstr "" #: file_operations.c:1514 msgid "bulk: Line mismatch in renaming file\n" msgstr "" #: file_operations.c:1493 file_operations.c:1548 msgid "bulk: Nothing to do" msgstr "" #: sort.c:387 #, c-format msgid "ctime %s\n" msgstr "" #: selection.c:1053 #, c-format msgid "desel: '%s': Invalid ELN\n" msgstr "" #: selection.c:1042 #, c-format msgid "desel: '%s': Invalid entry\n" msgstr "" #: selection.c:1094 msgid "desel: There are no selected files" msgstr "" #: media.c:559 msgid "devices" msgstr "" #: exec.c:655 exec.c:690 exec.c:757 exec.c:820 exec.c:846 exec.c:1114 #: history.c:89 msgid "disabled" msgstr "" #: exec.c:655 exec.c:690 exec.c:757 exec.c:820 exec.c:846 exec.c:1114 #: history.c:88 msgid "enabled" msgstr "" #: sort.c:393 #, c-format msgid "extension %s\n" msgstr "" #: remotes.c:66 remotes.c:68 msgid "false" msgstr "" #: exec.c:1189 msgid "file" msgstr "" #: exec.c:1189 msgid "files" msgstr "" #: navigation.c:619 #, c-format msgid "history: %d: No such ELN\n" msgstr "" #: sort.c:395 #, c-format msgid "inode %s\n" msgstr "" #: media.c:559 msgid "mountpoints" msgstr "" #: media.c:561 msgid "mp: There are no available mountpoints\n" msgstr "" #: sort.c:389 #, c-format msgid "mtime %s\n" msgstr "" #: sort.c:374 #, c-format msgid "name %s\n" msgstr "" #: sort.c:372 msgid "none" msgstr "" #: exec.c:790 msgid "not allowed" msgstr "" #: sort.c:376 #, c-format msgid "size %s\n" msgstr "" #: trash.c:1028 #, c-format msgid "trash: %s: %s\n" msgstr "" #: trash.c:1034 #, c-format msgid "trash: %s: Cannot trash a %s device\n" msgstr "" #: trash.c:1016 #, c-format msgid "trash: Cannot trash '%s'\n" msgstr "" #: trash.c:541 trash.c:830 trash.c:984 msgid "trash: No trashed files" msgstr "" #: trash.c:263 msgid "trash: There are no trashed files" msgstr "" #: trash.c:1022 msgid "trash: Use 'trash del' to remove trashed files" msgstr "" #: remotes.c:66 remotes.c:68 msgid "true" msgstr "" #: trash.c:908 #, c-format msgid "undel: %s: Invalid ELN\n" msgstr "" #: properties.c:418 properties.c:420 msgid "unknown" msgstr "" #: sort.c:391 #, c-format msgid "version %s\n" msgstr "" clifm-1.26.3/translations/norwegian/000077500000000000000000000000001506632037700174205ustar00rootroot00000000000000clifm-1.26.3/translations/norwegian/clifm.po000066400000000000000000001233511506632037700210570ustar00rootroot00000000000000# This file is part of CliFM # Copyright (C) 2016-2022 # This file is distributed under the same license as the clifm package. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2022-04-23 14:46-0300\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: properties.c:400 #, c-format msgid "\tBlocks: %s%ld%s" msgstr "" #: properties.c:398 #, c-format msgid "\tBlocks: %s%lld%s" msgstr "" #: properties.c:420 #, c-format msgid "\tGid: %s%u (%s)%s\n" msgstr "" #: properties.c:404 #, c-format msgid "\tIO Block: %s%d%s" msgstr "" #: properties.c:406 #, c-format msgid "\tIO Block: %s%ld%s" msgstr "" #: properties.c:409 #, c-format msgid "\tInode: %s%llu%s\n" msgstr "" #: properties.c:411 #, c-format msgid "\tInode: %s%zu%s\n" msgstr "" #: properties.c:317 #, c-format msgid "\tName: %s%s%s -> %s (broken link)\n" msgstr "" #: properties.c:418 #, c-format msgid "\tUid: %s%u (%s)%s" msgstr "" #: misc.c:1789 #, c-format msgid "" "\n" " Press any key to continue... " msgstr "" #: selection.c:786 #, c-format msgid "" "\n" "%s%sTotal size%s: %s\n" msgstr "" #: bookmarks.c:214 #, c-format msgid "" "\n" "%sEnter '%c' to quit.\n" msgstr "" #: selection.c:990 #, c-format msgid "" "\n" "%sEnter 'q' to quit or 'e' to edit the selections file\n" msgstr "" #: trash.c:559 trash.c:877 #, c-format msgid "" "\n" "%sEnter 'q' to quit.\n" msgstr "" #: archives.c:816 #, c-format msgid "" "\n" "%sNOTE%s: Zstandard does not support compression of multiple files into one " "single compressed file. Files will be compressed rather into multiple " "compressed files using the original file names\n" msgstr "" #: media.c:282 #, c-format msgid "" "\n" "%sUnmounted devices%s\n" "\n" msgstr "" #: colors.c:1831 #, c-format msgid "" "\n" "*The slash followed by a number (/xx) after directories or symbolic links to " "directories indicates the amount of files contained by the corresponding " "directory, excluding self (.) and parent (..) directories.\n" msgstr "" #: misc.c:1697 msgid "" "\n" "NOTE: Some keybindings on Haiku might differ. Take a look at your current " "keybindings via the 'kb' command" msgstr "" #: colors.c:1835 #, c-format msgid "" "\n" "The second field in this list is the code that is to be used to modify the " "color of the corresponding file type in the color scheme file (in the " "\"FiletypeColors\" line), using the same ANSI style color format used by " "dircolors. By default, %s uses only 8/16 colors, but you can use 256 and RGB/" "true colors as well.\n" "\n" msgstr "" #: colors.c:1807 #, c-format msgid " %sfile name%s: bd: Block special file\n" msgstr "" #: colors.c:1818 #, c-format msgid " %sfile name%s: ca: File with capabilities\n" msgstr "" #: colors.c:1813 #, c-format msgid " %sfile name%s: cd: Character special file\n" msgstr "" #: colors.c:1800 #, c-format msgid " %sfile name%s: di: Directory*\n" msgstr "" #: colors.c:1801 #, c-format msgid " %sfile name%s: ed: EMPTY directory\n" msgstr "" #: colors.c:1806 #, c-format msgid " %sfile name%s: ee: Empty executable file\n" msgstr "" #: colors.c:1815 #, c-format msgid " %sfile name%s: ef: Empty (zero-lenght) file\n" msgstr "" #: colors.c:1805 #, c-format msgid " %sfile name%s: ex: Executable file\n" msgstr "" #: colors.c:1814 #, c-format msgid " %sfile name%s: fi: Regular file\n" msgstr "" #: colors.c:1808 #, c-format msgid " %sfile name%s: ln: Symbolic link*\n" msgstr "" #: colors.c:1810 #, c-format msgid " %sfile name%s: mh: Multi-hardlink\n" msgstr "" #: colors.c:1796 #, c-format msgid " %sfile name%s: nd: Directory with no read permission\n" msgstr "" #: colors.c:1802 #, c-format msgid " %sfile name%s: ne: EMPTY directory with no read permission\n" msgstr "" #: colors.c:1798 #, c-format msgid " %sfile name%s: nf: File with no read permission\n" msgstr "" #: colors.c:1828 #, c-format msgid " %sfile name%s: no: Unknown file type\n" msgstr "" #: colors.c:1809 #, c-format msgid " %sfile name%s: or: Broken symbolic link\n" msgstr "" #: colors.c:1825 #, c-format msgid " %sfile name%s: ow: Other-writable and NOT sticky directory*\n" msgstr "" #: colors.c:1812 #, c-format msgid " %sfile name%s: pi: Pipe or FIFO special file\n" msgstr "" #: colors.c:1817 #, c-format msgid " %sfile name%s: sg: SGID file\n" msgstr "" #: colors.c:1811 #, c-format msgid " %sfile name%s: so: Socket file\n" msgstr "" #: colors.c:1819 #, c-format msgid " %sfile name%s: st: Sticky and NOT other-writable directory*\n" msgstr "" #: colors.c:1816 #, c-format msgid " %sfile name%s: su: SUID file\n" msgstr "" #: colors.c:1822 #, c-format msgid " %sfile name%s: tw: Sticky and other-writable directory*\n" msgstr "" #: colors.c:1829 #, c-format msgid " %sfile name%s: uf: Unaccessible (non-stat'able) file\n" msgstr "" #: remotes.c:67 #, c-format msgid " Auto-mount: %s\n" msgstr "" #: remotes.c:65 #, c-format msgid " Auto-unmount: %s\n" msgstr "" #: remotes.c:58 #, c-format msgid " Comment: %s\n" msgstr "" #: remotes.c:62 #, c-format msgid " Mount command: %s\n" msgstr "" #: remotes.c:69 #, c-format msgid " Mounted: %s\n" msgstr "" #: remotes.c:60 #, c-format msgid " Mountpoint: %s\n" msgstr "" #: remotes.c:64 #, c-format msgid " Unmount command: %s\n" msgstr "" #: config.c:1263 #, c-format msgid "" "# %s profile\n" "# Write here the commands you want to be executed at startup\n" "# Ex:\n" "#echo -e \"%s, the command line file manager\"\n" msgstr "" #: strings.c:1631 #, c-format msgid "%c%s: There are no selected files%c" msgstr "" #: selection.c:938 #, c-format msgid "%d file(s) deselected. " msgstr "" #: sort.c:364 #, c-format msgid "%s %s\n" msgstr "" #: misc.c:1757 #, c-format msgid "%s %s (%s), by %s\n" msgstr "" #: misc.c:1776 #, c-format msgid "" "%s %s (%s), by %s\n" "Contact: %s\n" "Website: %s\n" "License: %s\n" msgstr "" #: tags.c:115 #, c-format msgid "%s (error resolving link target)\n" msgstr "" #: sort.c:358 #, c-format msgid "%s (not available: using 'name') %s\n" msgstr "" #: config.c:1320 #, c-format msgid "" "%s created a new MIME list file (%s) It is recommended to edit this file " "(entering 'mm edit' or pressing F6) to add the programs you use and remove " "those you don't. This will make the process of opening files faster and " "smoother\n" msgstr "" #: bookmarks.c:89 #, c-format msgid "" "%s%s\n" "Enter '%c' to edit your bookmarks or '%c' to quit.\n" msgstr "" #: file_operations.c:1055 #, c-format msgid "%s%s%s currently pointing to " msgstr "" #: file_operations.c:1052 #, c-format msgid "%s%s%s currently pointing to nowhere (broken link)\n" msgstr "" #: file_operations.c:1167 #, c-format msgid "%s%s%s successfully relinked to " msgstr "" #: archives.c:1188 #, c-format msgid "%s%s%s: Succesfully mounted on %s\n" msgstr "" #: archives.c:1009 #, c-format msgid "%s%sFile%s: %s\n" msgstr "" #: selection.c:732 #, c-format msgid "%s%sSelection Box%s\n" msgstr "" #: selection.c:543 #, c-format msgid "%s%sTotal size%s: %s\n" msgstr "" #: main.c:759 #, c-format msgid "%s->%s Running as root%s\n" msgstr "" #: history.c:540 history.c:579 #, c-format msgid "%s: !%s: Event not found\n" msgstr "" #: history.c:494 #, c-format msgid "%s: !%s: event not found\n" msgstr "" #: mime.c:1349 #, c-format msgid "" "%s: %d MIME definition(s) imported from the system. Old MIME list file " "stored as %s\n" msgstr "" #: name_cleaner.c:649 #, c-format msgid "%s: %d file(s) bleached\n" msgstr "" #: selection.c:940 #, c-format msgid "%s: %d file(s) deselected. " msgstr "" #: navigation.c:80 #, c-format msgid "%s: %d is already the current workspace\n" msgstr "" #: strings.c:1702 #, c-format msgid "" "%s: %d: ELN-filename conflict. Bypass internal expansions to fix this issue: " "';CMD FILENAME'\n" msgstr "" #: media.c:199 #, c-format msgid "%s: %d: Invalid ELN\n" msgstr "" #: navigation.c:72 #, c-format msgid "%s: %d: Invalid workspace number\n" msgstr "" #: name_cleaner.c:408 prompt.c:462 #, c-format msgid "%s: %s\n" msgstr "" #: file_operations.c:977 #, c-format msgid "" "%s: %s (%s): Cannot open file\n" "Try 'APPLICATION FILENAME'\n" msgstr "" #: aux.c:817 aux.c:831 aux.c:845 #, c-format msgid "%s: %s failed to allocate %zu bytes\n" msgstr "" #: config.c:502 file_operations.c:108 file_operations.c:134 remotes.c:137 #, c-format msgid "%s: %s: %s\n" msgstr "" #: init.c:1692 #, c-format msgid "" "%s: %s: %s\n" "Falling back to default\n" msgstr "" #: init.c:1637 #, c-format msgid "" "%s: %s: %s\n" "Falling back to default configuration directory\n" msgstr "" #: init.c:1604 #, c-format msgid "" "%s: %s: %s\n" "Falling back to the default bookmarks file\n" msgstr "" #: init.c:1664 #, c-format msgid "" "%s: %s: %s\n" "Falling back to the default keybindings file\n" msgstr "" #: file_operations.c:953 #, c-format msgid "%s: %s: Broken symbolic link\n" msgstr "" #: init.c:1628 #, c-format msgid "" "%s: %s: Cannot create directory (error %d)\n" "Falling back to default configuration directory\n" msgstr "" #: profiles.c:302 #, c-format msgid "%s: %s: Cannot create profile: Home directory not found\n" msgstr "" #: file_operations.c:1741 #, c-format msgid "%s: %s: Cannot create symlink: %s\n" msgstr "" #: tags.c:384 #, c-format msgid "%s: %s: Cannot create tag\n" msgstr "" #: tags.c:50 #, c-format msgid "%s: %s: Cannot create tag: file already exists\n" msgstr "" #: file_operations.c:251 #, c-format msgid "%s: %s: Cannot open file\n" msgstr "" #: file_operations.c:210 #, c-format msgid "%s: %s: Directory empty\n" msgstr "" #: profiles.c:371 #, c-format msgid "%s: %s: Error creating profile\n" msgstr "" #: tags.c:277 #, c-format msgid "%s: %s: Error creating tag\n" msgstr "" #: config.c:1240 #, c-format msgid "%s: %s: Error creating tags directory. Tag function disabled\n" msgstr "" #: aux.c:143 #, c-format msgid "%s: %s: Error deescaping string\n" msgstr "" #: file_operations.c:1022 file_operations.c:1111 #, c-format msgid "%s: %s: Error dequoting file\n" msgstr "" #: bookmarks.c:794 misc.c:754 name_cleaner.c:523 properties.c:684 #: readline.c:401 search.c:145 search.c:552 #, c-format msgid "%s: %s: Error dequoting file name\n" msgstr "" #: file_operations.c:776 file_operations.c:911 #, c-format msgid "%s: %s: Error dequoting filename\n" msgstr "" #: navigation.c:281 #, c-format msgid "%s: %s: Error dequoting string\n" msgstr "" #: aux.c:159 navigation.c:288 #, c-format msgid "%s: %s: Error expanding tilde\n" msgstr "" #: remotes.c:255 trash.c:136 #, c-format msgid "%s: %s: Error getting parent directory\n" msgstr "" #: strings.c:1766 #, c-format msgid "%s: %s: Error getting variable name\n" msgstr "" #: mime.c:282 #, c-format msgid "%s: %s: Error opening file\n" msgstr "" #: strings.c:1591 strings.c:1733 strings.c:1973 strings.c:2047 #, c-format msgid "%s: %s: Error quoting file name\n" msgstr "" #: profiles.c:415 #, c-format msgid "%s: %s: Error removing profile\n" msgstr "" #: file_operations.c:814 #, c-format msgid "%s: %s: File already exists. Trying with '%s' instead\n" msgstr "" #: tags.c:48 #, c-format msgid "%s: %s: File already tagged\n" msgstr "" #: tags.c:531 #, c-format msgid "%s: %s: File not tagged as %s%s%s\n" msgstr "" #: file_operations.c:1095 #, c-format msgid "%s: %s: Invalid ELN\n" msgstr "" #: exec.c:1781 exec.c:1808 #, c-format msgid "%s: %s: Invalid argument. Try 'fz -h'\n" msgstr "" #: exec.c:628 #, c-format msgid "%s: %s: Invalid number\n" msgstr "" #: exec.c:1567 #, c-format msgid "%s: %s: Is a directory\n" msgstr "" #: misc.c:916 #, c-format msgid "%s: %s: No alias found\n" msgstr "" #: mime.c:1445 mime.c:1449 #, c-format msgid "%s: %s: No associated application found\n" msgstr "" #: navigation.c:371 #, c-format msgid "%s: %s: No matches found\n" msgstr "" #: exec.c:1056 #, c-format msgid "%s: %s: No such alias\n" msgstr "" #: colors.c:955 #, c-format msgid "%s: %s: No such color scheme. Falling back to default\n" msgstr "" #: colors.c:1064 #, c-format msgid "%s: %s: No such color scheme. Falling back to the default one\n" msgstr "" #: jump.c:432 #, c-format msgid "%s: %s: No such order number\n" msgstr "" #: profiles.c:393 #, c-format msgid "%s: %s: No such profile\n" msgstr "" #: profiles.c:132 #, c-format msgid "" "%s: %s: No such profile\n" "To add a new profile enter 'pf add PROFILE'\n" msgstr "" #: remotes.c:118 #, c-format msgid "%s: %s: No such remote\n" msgstr "" #: selection.c:888 #, c-format msgid "%s: %s: No such selected file\n" msgstr "" #: sort.c:457 #, c-format msgid "%s: %s: No such sorting method\n" msgstr "" #: tags.c:75 tags.c:158 #, c-format msgid "%s: %s: No such tag\n" msgstr "" #: misc.c:634 #, c-format msgid "%s: %s: Not a directory\n" msgstr "" #: file_operations.c:1044 #, c-format msgid "%s: %s: Not a symbolic link\n" msgstr "" #: remotes.c:225 #, c-format msgid "%s: %s: Not mounted\n" msgstr "" #: sanitize.c:368 #, c-format msgid "" "%s: %s: Only command base names are allowed. Ex: 'nano' instead of '/usr/bin/" "nano'\n" msgstr "" #: profiles.c:297 #, c-format msgid "%s: %s: Profile already exists\n" msgstr "" #: remotes.c:209 #, c-format msgid "%s: %s: Remote mounted on %s\n" msgstr "" #: tags.c:317 #, c-format msgid "%s: %s: Successfully removed tag\n" msgstr "" #: main.c:826 profiles.c:165 #, c-format msgid "" "%s: %s: System shell not found. Please edit the configuration file to " "specify a working shell.\n" msgstr "" #: tags.c:271 #, c-format msgid "%s: %s: Tag already exists\n" msgstr "" #: media.c:503 #, c-format msgid "%s: %s: This feature is not available on Haiku\n" msgstr "" #: init.c:1643 #, c-format msgid "%s: %s: Using alternative configuration directory\n" msgstr "" #: misc.c:934 #, c-format msgid "%s: %zu aliases were successfully imported\n" msgstr "" #: init.c:207 #, c-format msgid "" "%s: %zu: Invalid workspace.\n" "Falling back to workspace %zu\n" msgstr "" #: jump.c:410 #, c-format msgid "%s: '%c': Invalid option\n" msgstr "" #: search.c:114 search.c:535 selection.c:429 #, c-format msgid "%s: '%c': Unrecognized file type\n" msgstr "" #: profiles.c:141 #, c-format msgid "%s: '%s' is the current profile\n" msgstr "" #: config.c:1889 #, c-format msgid "%s: '%s': %s. Using the current working directory as starting path\n" msgstr "" #: config.c:1228 #, c-format msgid "" "%s: '%s': Directory not writable. Bookmarks, commands logs, and commands " "history are disabled. Program messages won't be persistent. Using default " "options\n" msgstr "" #: config.c:1202 #, c-format msgid "%s: '%s': Directory not writable. Trash function disabled\n" msgstr "" #: config.c:2023 misc.c:379 #, c-format msgid "%s: '%s': Invalid regular expression\n" msgstr "" #: profiles.c:363 #, c-format msgid "%s: '%s': Profile succesfully created\n" msgstr "" #: profiles.c:406 #, c-format msgid "%s: '%s': Profile successfully removed\n" msgstr "" #: exec.c:1462 #, c-format msgid "%s: '%s': Syntax error\n" msgstr "" #: checks.c:107 #, c-format msgid "" "%s: '%s': Unsupported terminal. This terminal cannot understand escape " "sequences\n" msgstr "" #: config.c:550 #, c-format msgid "" "%s: '%s': Using a temporary directory for the Selection Box. Selected files " "won't be persistent across reboots" msgstr "" #: navigation.c:338 #, c-format msgid "%s: /: No parent directory\n" msgstr "" #: misc.c:937 #, c-format msgid "%s: 1 alias was successfully imported\n" msgstr "" #: config.c:99 #, c-format msgid "%s: Access to configuration files is not allowed in stealth mode\n" msgstr "" #: misc.c:902 #, c-format msgid "%s: Alias already exists\n" msgstr "" #: misc.c:855 #, c-format msgid "%s: Alias conflicts with internal command\n" msgstr "" #: config.c:113 #, c-format msgid "%s: Cannot access the configuration file\n" msgstr "" #: init.c:149 #, c-format msgid "" "%s: Cannot access the home directory. Trash, bookmarks, commands logs, and " "commands history are disabled. Program messages and selected files won't be " "persistent. Using default options\n" msgstr "" #: tags.c:643 #, c-format msgid "%s: Cannot merge tags: error moving tagged files\n" msgstr "" #: bookmarks.c:597 #, c-format msgid "%s: Cannot open the bookmarks file\n" msgstr "" #: history.c:248 #, c-format msgid "%s: Could not save directory history: %s\n" msgstr "" #: colors.c:539 #, c-format msgid "%s: Current color scheme: %s\n" msgstr "" #: colors.c:1789 #, c-format msgid "%s: Currently running without colors\n" msgstr "" #: misc.c:607 #, c-format msgid "" "%s: Default terminal not set. Use the configuration file (F10) to set it\n" msgstr "" #: trash.c:150 #, c-format msgid "%s: Directory is immutable\n" msgstr "" #: jump.c:291 #, c-format msgid "%s: Directory jumper function disabled\n" msgstr "" #: init.c:1035 init.c:1043 selection.c:486 #, c-format msgid "%s: Error expanding path\n" msgstr "" #: init.c:1246 #, c-format msgid "%s: Error expanding tilde. Using default opener\n" msgstr "" #: mime.c:460 #, c-format msgid "%s: Error getting home directory\n" msgstr "" #: main.c:848 #, c-format msgid "%s: Error getting hostname\n" msgstr "" #: mime.c:1463 #, c-format msgid "%s: Error getting mime-type\n" msgstr "" #: remotes.c:230 #, c-format msgid "%s: Error getting mountpoint for '%s'\n" msgstr "" #: misc.c:1051 #, c-format msgid "%s: Error getting variable value\n" msgstr "" #: misc.c:777 #, c-format msgid "%s: Error lauching new instance\n" msgstr "" #: checks.c:99 #, c-format msgid "%s: Error opening terminal: unknown\n" msgstr "" #: profiles.c:217 #, c-format msgid "%s: Error opening the history file\n" msgstr "" #: checks.c:512 #, c-format msgid "%s: Error parsing aliased command\n" msgstr "" #: history.c:503 history.c:522 history.c:556 #, c-format msgid "%s: Error parsing history command\n" msgstr "" #: media.c:447 #, c-format msgid "%s: Error retrieving mountpoint\n" msgstr "" #: init.c:387 #, c-format msgid "%s: Error retrieving user data\n" msgstr "" #: misc.c:968 #, c-format msgid "%s: Error saving last visited directory\n" msgstr "" #: misc.c:1566 #, c-format msgid "%s: Error storing pinned directory\n" msgstr "" #: selection.c:572 #, c-format msgid "%s: Error writing selected files to the selections file\n" msgstr "" #: exec.c:535 #, c-format msgid "%s: External commands are not allowed. Run 'ext on' to enable them.\n" msgstr "" #: init.c:1350 #, c-format msgid "%s: FZF not found. Falling back to standard TAB completion\n" msgstr "" #: init.c:251 main.c:815 #, c-format msgid "%s: Fatal error! Failed retrieving current working directory\n" msgstr "" #: trash.c:203 #, c-format msgid "%s: File is immutable\n" msgstr "" #: misc.c:614 #, c-format msgid "%s: Function only available for graphical environments\n" msgstr "" #: history.c:428 #, c-format msgid "%s: History function disabled\n" msgstr "" #: bookmarks.c:694 bookmarks.c:775 #, c-format msgid "%s: Invalid bookmark\n" msgstr "" #: navigation.c:625 #, c-format msgid "%s: Invalid history entry\n" msgstr "" #: exec.c:1654 #, c-format msgid "%s: Lira: %s\n" msgstr "" #: init.c:1609 #, c-format msgid "%s: Loaded alternative bookmarks file\n" msgstr "" #: init.c:1698 #, c-format msgid "%s: Loaded alternative configuration file\n" msgstr "" #: init.c:1670 #, c-format msgid "%s: Loaded alternative keybindings file\n" msgstr "" #: exec.c:1100 #, c-format msgid "%s: Log function disabled\n" msgstr "" #: strings.c:645 strings.c:702 #, c-format msgid "%s: Missing '%c'\n" msgstr "" #: remotes.c:386 #, c-format msgid "%s: Mounting remote...\n" msgstr "" #: misc.c:386 #, c-format msgid "%s: New filter successfully set\n" msgstr "" #: misc.c:926 #, c-format msgid "%s: No alias imported\n" msgstr "" #: exec.c:1022 exec.c:1042 #, c-format msgid "%s: No aliases found\n" msgstr "" #: colors.c:408 #, c-format msgid "%s: No color schemes found\n" msgstr "" #: selection.c:583 #, c-format msgid "%s: No matches found\n" msgstr "" #: media.c:193 media.c:400 #, c-format msgid "%s: No mount application found. Install either udevil or udisks2\n" msgstr "" #: media.c:517 #, c-format msgid "%s: No mount command found. Install either udevil or udisks2\n" msgstr "" #: remotes.c:172 #, c-format msgid "%s: No mount command specified for '%s'\n" msgstr "" #: remotes.c:123 #, c-format msgid "%s: No mountpoint specified for '%s'\n" msgstr "" #: misc.c:717 #, c-format msgid "" "%s: No option specified for '%s'\n" "Trying '%s -e %s %s'\n" msgstr "" #: exec.c:1421 keybinds.c:1444 misc.c:1624 #, c-format msgid "%s: No pinned file\n" msgstr "" #: remotes.c:48 #, c-format msgid "%s: No remotes defined\n" msgstr "" #: bookmarks.c:678 #, c-format msgid "%s: No such ELN\n" msgstr "" #: bookmarks.c:699 bookmarks.c:780 #, c-format msgid "%s: No such bookmark\n" msgstr "" #: colors.c:496 #, c-format msgid "%s: No such color scheme\n" msgstr "" #: trash.c:122 #, c-format msgid "%s: No such file or directory\n" msgstr "" #: tags.c:455 #, c-format msgid "" "%s: No tag specified. Specify a tag via :TAG. E.g. tag FILE1 FILE2 :TAG\n" msgstr "" #: tags.c:67 #, c-format msgid "%s: No tags found, Use 'tag new' to create new tags\n" msgstr "" #: remotes.c:236 #, c-format msgid "%s: No unmount command found for '%s'\n" msgstr "" #: file_operations.c:486 name_cleaner.c:561 name_cleaner.c:611 #, c-format msgid "%s: Nothing to do\n" msgstr "" #: mime.c:531 #, c-format msgid "%s: Nothing was imported. No MIME definitions found\n" msgstr "" #: mime.c:454 #, c-format msgid "%s: Nothing was imported. No graphical environment found\n" msgstr "" #: trash.c:90 trash.c:182 trash.c:190 trash.c:210 trash.c:226 #, c-format msgid "%s: Permission denied\n" msgstr "" #: keybinds.c:96 keybinds.c:139 #, c-format msgid "%s: Restart the program for changes to take effect\n" msgstr "" #: config.c:2086 #, c-format msgid "" "%s: Running in stealth mode: trash, persistent selection and directory " "history, just as bookmarks, logs and configuration files, are disabled.\n" msgstr "" #: misc.c:1616 #, c-format msgid "%s: Succesfully pinned '%s'\n" msgstr "" #: tags.c:282 #, c-format msgid "%s: Successfully created tag\n" msgstr "" #: media.c:558 #, c-format msgid "%s: There are no available %s\n" msgstr "" #: exec.c:932 exec.c:950 #, c-format msgid "%s: There are no messages\n" msgstr "" #: exec.c:415 #, c-format msgid "%s: To gracefully quit enter 'q'\n" msgstr "" #: trash.c:797 trash.c:1085 #, c-format msgid "%s: Trash function disabled\n" msgstr "" #: misc.c:1703 #, c-format msgid "%s: Unable to find any pager\n" msgstr "" #: media.c:221 #, c-format msgid "%s: Unmounted %s\n" msgstr "" #: remotes.c:423 #, c-format msgid "%s: Unmounting remote...\n" msgstr "" #: main.c:744 #, c-format msgid "%s: Unsupported CPU architecture\n" msgstr "" #: main.c:750 #, c-format msgid "%s: Unsupported operating system\n" msgstr "" #: exec.c:2194 #, c-format msgid "%s: archiving: %s\n" msgstr "" #: exec.c:2175 #, c-format msgid "%s: bleach: %s\n" msgstr "" #: bookmarks.c:814 #, c-format msgid "%s: bookmarks: %s\n" msgstr "" #: navigation.c:444 #, c-format msgid "%s: cd: Home directory not found\n" msgstr "" #: colors.c:512 #, c-format msgid "" "%s: color schemes: %s\n" "TIP: To change the current color scheme use the following environment " "variables: CLIFM_FILE_COLORS, CLIFM_IFACE_COLORS, and CLIFM_EXT_COLORS\n" msgstr "" #: mime.c:1613 #, c-format msgid "%s: file: Command not found\n" msgstr "" #: config.c:1499 #, c-format msgid "%s: fopen: '%s': %s. Using default values.\n" msgstr "" #: checks.c:161 #, c-format msgid "%s: fzf not found. Falling back to standard TAB completion\n" msgstr "" #: init.c:1357 #, c-format msgid "%s: fzftab: %s\n" msgstr "" #: init.c:1379 #, c-format msgid "%s: fzytab: %s\n" msgstr "" #: init.c:1335 #, c-format msgid "%s: highlight: %s\n" msgstr "" #: exec.c:893 init.c:1267 #, c-format msgid "%s: icons: %s\n" msgstr "" #: jump.c:663 #, c-format msgid "%s: jump: No matches found\n" msgstr "" #: media.c:510 #, c-format msgid "%s: media: Function only available on Linux systems\n" msgstr "" #: profiles.c:315 #, c-format msgid "%s: mkdir: %s: Error creating configuration directory\n" msgstr "" #: config.c:1216 #, c-format msgid "" "%s: mkdir: '%s': Error creating configuration directory. Bookmarks, commands " "logs, and command history are disabled. Program messages won't be " "persistent. Using default options\n" msgstr "" #: config.c:1194 #, c-format msgid "" "%s: mkdir: '%s': Error creating trash directory. Trash function disabled\n" msgstr "" #: config.c:1277 #, c-format msgid "" "%s: mkdir: Error creating colors directory. Using the default color scheme\n" msgstr "" #: config.c:1289 #, c-format msgid "" "%s: mkdir: Error creating plugins directory. The actions function is " "disabled\n" msgstr "" #: init.c:1504 #, c-format msgid "" "%s: option requires an argument -- '%c'\n" "Try '%s --help' for more information.\n" msgstr "" #: selection.c:123 #, c-format msgid "%s: sel: %s: Already selected\n" msgstr "" #: selection.c:327 #, c-format msgid "%s: sel: %s: Invalid regular expression\n" msgstr "" #: trash.c:637 #, c-format msgid "%s: trash: %d: Invalid ELN\n" msgstr "" #: exec.c:1742 exec.c:1766 init.c:1290 #, c-format msgid "%s: trash: %s\n" msgstr "" #: trash.c:234 #, c-format msgid "%s: trash: %s (%s): Unsupported file type\n" msgstr "" #: trash.c:419 #, c-format msgid "" "%s: trash: %s/%s: Failed removing trash file\n" "Try removing it manually\n" msgstr "" #: trash.c:350 #, c-format msgid "%s: trash: %s: Error getting file name\n" msgstr "" #: trash.c:291 #, c-format msgid "%s: trash: %s: Error removing trashed file\n" msgstr "" #: trash.c:394 #, c-format msgid "%s: trash: %s: Failed copying file to Trash\n" msgstr "" #: trash.c:440 #, c-format msgid "%s: trash: %s: Failed encoding path\n" msgstr "" #: trash.c:615 #, c-format msgid "%s: trash: %s: Invalid ELN\n" msgstr "" #: trash.c:596 trash.c:646 #, c-format msgid "%s: trash: Error trashing %s\n" msgstr "" #: checks.c:123 #, c-format msgid "%s: udisks2 not found. Falling back to udevil\n" msgstr "" #: trash.c:933 #, c-format msgid "%s: undel: %d: Invalid ELN\n" msgstr "" #: trash.c:714 #, c-format msgid "%s: undel: %s: Error decoding original path\n" msgstr "" #: trash.c:770 #, c-format msgid "%s: undel: %s: Error removing info file\n" msgstr "" #: trash.c:777 #, c-format msgid "%s: undel: %s: Error restoring trashed file\n" msgstr "" #: trash.c:676 #, c-format msgid "" "%s: undel: Info file for '%s' not found. Try restoring the file manually\n" msgstr "" #: init.c:1525 #, c-format msgid "%s: unknown option character '\\%x'\n" msgstr "" #: init.c:1521 #, c-format msgid "" "%s: unrecognized option '%c'\n" "Try '%s --help' for more information.\n" msgstr "" #: init.c:1513 #, c-format msgid "" "%s: unrecognized option '%s'\n" "Try '%s --help' for more information.\n" msgstr "" #: bookmarks.c:609 #, c-format msgid "" "%sBookmarks Manager%s\n" "\n" msgstr "" #: bookmarks.c:208 #, c-format msgid "" "%sBookmarks%s\n" "\n" msgstr "" #: colors.c:1844 #, c-format msgid "" "%sExtension colors%s\n" "\n" msgstr "" #: colors.c:1795 #, c-format msgid "" "%sFile type colors%s\n" "\n" msgstr "" #: archives.c:1028 #, c-format msgid "%sFile%s: %s\n" msgstr "" #: media.c:526 #, c-format msgid "" "%sMountpoints%s\n" "\n" msgstr "" #: archives.c:940 #, c-format msgid "%sNOTE%s: Using Zstandard\n" msgstr "" #: selection.c:551 #, c-format msgid "%sSelection Box%s\n" msgstr "" #: trash.c:535 trash.c:862 #, c-format msgid "" "%sTrashed files%s\n" "\n" msgstr "" #: archives.c:1205 #, c-format msgid "" "%s[e]%sxtract %s[E]%sxtract-to-dir %s[l]%sist %s[m]%sount %s[r]%sepack " "%s[q]%suit\n" msgstr "" #: archives.c:321 #, c-format msgid "" "%s[e]%sxtract %s[E]%sxtract-to-dir %s[l]%sist %s[t]%sest %s[m]%sount " "%s[q]%suit\n" msgstr "" #: archives.c:757 archives.c:941 #, c-format msgid "%s[e]%sxtract %s[t]%sest %s[i]%snfo %s[q]%suit\n" msgstr "" #: selection.c:941 #, c-format msgid "%zu file(s) currently selected\n" msgstr "" #: selection.c:601 #, c-format msgid "%zu files are now in the Selection Box\n" msgstr "" #: selection.c:603 #, c-format msgid "" "%zu selected file(s):\n" "\n" msgstr "" #: search.c:634 #, c-format msgid "'%s': Invalid regular expression\n" msgstr "" #: properties.c:424 #, c-format msgid "Access: \t%s%s%s\n" msgstr "" #: bookmarks.c:292 msgid "All bookmarks succesfully removed\n" msgstr "" #: selection.c:1106 msgid "All files deselected\n" msgstr "" #: mime.c:1482 #, c-format msgid "Associated application: %s [%s]\n" msgstr "" #: mime.c:1432 msgid "Associated application: None\n" msgstr "" #: mime.c:1479 #, c-format msgid "Associated application: ad [built-in] [%s]\n" msgstr "" #: exec.c:844 #, c-format msgid "Auto-open disabled\n" msgstr "" #: exec.c:841 #, c-format msgid "Auto-open enabled\n" msgstr "" #: exec.c:846 #, c-format msgid "Auto-open is %s\n" msgstr "" #: exec.c:818 #, c-format msgid "Autocd disabled\n" msgstr "" #: exec.c:815 #, c-format msgid "Autocd enabled\n" msgstr "" #: exec.c:820 #, c-format msgid "Autocd is %s\n" msgstr "" #: properties.c:429 #, c-format msgid "Birth: \t\t%s%s%s\n" msgstr "" #: properties.c:388 #, c-format msgid "Block special file" msgstr "" #: bookmarks.c:450 msgid "Bookmark line example: [sc]name:path" msgstr "" #: bookmarks.c:217 msgid "Bookmark(s) to be deleted (ex: 1 2-6, or *): " msgstr "" #: bookmarks.c:819 #, c-format msgid "Bookmarks function disabled\n" msgstr "" #: bookmarks.c:799 #, c-format msgid "Bookmarks: %s: %s\n" msgstr "" #: properties.c:426 #, c-format msgid "Change: \t%s%s%s\n" msgstr "" #: properties.c:389 #, c-format msgid "Character special file" msgstr "" #: bookmarks.c:93 msgid "Choose a bookmark: " msgstr "" #: media.c:611 msgid "Choose a mountpoint/device: " msgstr "" #: media.c:609 media.c:613 msgid "Choose a mountpoint: " msgstr "" #: mime.c:586 msgid "Choose an application ('q' to quit): " msgstr "" #: listing.c:309 #, c-format msgid "Color scheme %s->%s %s\n" msgstr "" #: exec.c:879 msgid "Columns disabled\n" msgstr "" #: exec.c:872 msgid "Columns enabled\n" msgstr "" #: file_operations.c:1562 msgid "Continue? [y/N] " msgstr "" #: tags.c:393 #, c-format msgid "Created new tag %s%s%s\n" msgstr "" #: misc.c:396 #, c-format msgid "Current filter: %c%s\n" msgstr "" #: properties.c:414 #, c-format msgid "Device: %s%d%s" msgstr "" #: properties.c:416 #, c-format msgid "Device: %s%zu%s" msgstr "" #: properties.c:385 #, c-format msgid "Directory" msgstr "" #: selection.c:737 msgid "Empty" msgstr "" #: file_operations.c:739 msgid "End filename with a slash to create a directory" msgstr "" #: media.c:601 msgid "Enter 'iELN' for device information. Ex: i4" msgstr "" #: archives.c:1081 media.c:600 msgid "Enter 'q' to quit" msgstr "" #: file_operations.c:1716 msgid "Enter links suffix ('q' to quit): " msgstr "" #: history.c:129 msgid "Error getting command!" msgstr "" #: mime.c:344 msgid "Error opening temporary file\n" msgstr "" #: archives.c:410 archives.c:419 archives.c:523 archives.c:532 msgid "Error querying file type\n" msgstr "" #: listing.c:1670 listing.c:2218 #, c-format msgid "Excluded files: %d\n" msgstr "" #: exec.c:793 #, c-format msgid "External commands allowed\n" msgstr "" #: exec.c:789 #, c-format msgid "External commands are %s\n" msgstr "" #: exec.c:796 #, c-format msgid "External commands disallowed\n" msgstr "" #: archives.c:62 msgid "Extraction path ('q' to quit): " msgstr "" #: properties.c:390 #, c-format msgid "Fifo" msgstr "" #: archives.c:673 msgid "File name ('q' to quit): " msgstr "" #: bookmarks.c:572 #, c-format msgid "File succesfully bookmarked\n" msgstr "" #: selection.c:994 msgid "File(s) to be deselected (ex: 1 2-6, or *): " msgstr "" #: trash.c:563 msgid "File(s) to be removed (ex: 1 2-6, or *): " msgstr "" #: trash.c:881 msgid "File(s) to be undeleted (ex: 1 2-6, or *): " msgstr "" #: file_operations.c:740 msgid "Filename ('q' to quit): " msgstr "" #: exec.c:725 msgid "Files counter disabled\n" msgstr "" #: exec.c:718 msgid "Files counter enabled\n" msgstr "" #: misc.c:369 msgid "Filter unset" msgstr "" #: keybinds.c:842 #, c-format msgid "Folders first %s\n" msgstr "" #: exec.c:698 msgid "Folders first disabled\n" msgstr "" #: exec.c:694 msgid "Folders first enabled\n" msgstr "" #: exec.c:689 #, c-format msgid "Folders first is %s\n" msgstr "" #: exec.c:1803 msgid "Full directory size disabled\n" msgstr "" #: exec.c:1792 msgid "Full directory size enabled\n" msgstr "" #: exec.c:1799 msgid "Full directory size is already disabled" msgstr "" #: exec.c:1788 msgid "Full directory size is already enabled" msgstr "" #: search.c:211 msgid "Glob: No matches found. Trying regex..." msgstr "" #: keybinds.c:894 #, c-format msgid "Hidden files %s\n" msgstr "" #: exec.c:1121 msgid "Hidden files disabled\n" msgstr "" #: exec.c:1128 msgid "Hidden files enabled\n" msgstr "" #: exec.c:1113 #, c-format msgid "Hidden files is %s\n" msgstr "" #: history.c:405 #, c-format msgid "History is %s\n" msgstr "" #: archives.c:692 #, c-format msgid "Invalid file name\n" msgstr "" #: name_cleaner.c:572 msgid "Is this OK? [y/N/(e)dit] " msgstr "" #: history.c:88 #, c-format msgid "Logs %s\n" msgstr "" #: history.c:103 msgid "Logs already disabled" msgstr "" #: history.c:93 msgid "Logs already enabled" msgstr "" #: history.c:106 msgid "Logs succesfully disabled" msgstr "" #: history.c:96 msgid "Logs successfully enabled" msgstr "" #: keybinds.c:810 #, c-format msgid "Long view mode %s\n" msgstr "" #: mime.c:1472 #, c-format msgid "MIME type: %s\n" msgstr "" #: search.c:457 #, c-format msgid "Matches found: %d\n" msgstr "" #: search.c:810 #, c-format msgid "Matches found: %zu\n" msgstr "" #: exec.c:622 exec.c:634 #, c-format msgid "Max files set to %d\n" msgstr "" #: exec.c:615 msgid "Max files unset\n" msgstr "" #: exec.c:603 #, c-format msgid "Max files: %d\n" msgstr "" #: exec.c:601 msgid "Max files: unset" msgstr "" #: keybinds.c:339 #, c-format msgid "Max name length set back to %d\n" msgstr "" #: keybinds.c:337 msgid "Max name length unset\n" msgstr "" #: media.c:504 msgid "Media" msgstr "" #: properties.c:425 #, c-format msgid "Modify: \t%s%s%s\n" msgstr "" #: media.c:524 msgid "Mounted devices" msgstr "" #: media.c:504 media.c:523 msgid "Mountpoints" msgstr "" #: jump.c:313 msgid "" "NOTE 2: An asterisk next rank values means that the corresponding directory " "is bookmarked, pinned, or currently used in some workspace\n" msgstr "" #: jump.c:311 msgid "" "NOTE: First time access is displayed in days, while last time access is " "displayed in hours" msgstr "" #: mime.c:1471 remotes.c:56 #, c-format msgid "Name: %s\n" msgstr "" #: config.c:87 #, c-format msgid "New configuration file written to '%s'\n" msgstr "" #: archives.c:1085 msgid "New format (ex: .tar.xz): " msgstr "" #: file_operations.c:1068 msgid "New path ('q' to quit): " msgstr "" #: remotes.c:69 msgid "No" msgstr "" #: config.c:58 msgid "No configuration file found" msgstr "" #: tags.c:167 #, c-format msgid "No file tagged as '%s'\n" msgstr "" #: misc.c:361 msgid "No filter set" msgstr "" #: search.c:673 search.c:812 #, c-format msgid "No matches found\n" msgstr "" #: exec.c:1210 msgid "No pinned file" msgstr "" #: mime.c:1378 msgid "No such ELN" msgstr "" #: mime.c:1471 msgid "None" msgstr "" #: config.c:80 #, c-format msgid "Old configuration file stored as '%s'\n" msgstr "" #: keybinds.c:1533 #, c-format msgid "Only directories %s\n" msgstr "" #: exec.c:975 #, c-format msgid "Opener set to '%s'\n" msgstr "" #: archives.c:117 archives.c:762 archives.c:948 msgid "Operation: " msgstr "" #: jump.c:316 msgid "Order\tVisits\tFirst\tLast\tRank\tDirectory" msgstr "" #: exec.c:765 msgid "Pager disabled\n" msgstr "" #: exec.c:761 msgid "Pager enabled\n" msgstr "" #: exec.c:1208 #, c-format msgid "Pinned file: %s\n" msgstr "" #: properties.c:391 #, c-format msgid "Regular file" msgstr "" #: file_operations.c:1127 msgid "Relink as a broken symbolic link? [y/n] " msgstr "" #: properties.c:434 #, c-format msgid "Size: \t\t%s%s%s\n" msgstr "" #: properties.c:386 #, c-format msgid "Socket" msgstr "" #: listing.c:304 msgid "Sorted by: " msgstr "" #: sort.c:466 msgid "Sorting method: " msgstr "" #: misc.c:1643 #, c-format msgid "Succesfully unpinned %s\n" msgstr "" #: tags.c:656 #, c-format msgid "Successfully merged %s%s%s into %s%s%s\n" msgstr "" #: bookmarks.c:365 #, c-format msgid "Successfully removed '%s'\n" msgstr "" #: tags.c:484 #, c-format msgid "Successfully tagged %zu file(s)\n" msgstr "" #: tags.c:554 #, c-format msgid "Successfully untagged %zu file(s)\n" msgstr "" #: exec.c:991 exec.c:995 keybinds.c:870 msgid "Switched back to normal mode\n" msgstr "" #: keybinds.c:868 msgid "Switched to light mode\n" msgstr "" #: properties.c:387 #, c-format msgid "Symbolic link" msgstr "" #: exec.c:733 msgid "The files counter is disabled" msgstr "" #: exec.c:731 msgid "The files counter is enabled" msgstr "" #: exec.c:756 #, c-format msgid "The files pager is %s\n" msgstr "" #: exec.c:1188 #, c-format msgid "Toggled executable bit on %zu %s\n" msgstr "" #: exec.c:1689 #, c-format msgid "" "Total files: %zu\n" "Directories: %zu\n" "Regular files: %zu\n" "Executable files: %zu\n" "Hidden files: %zu\n" "SUID files: %zu\n" "SGID files: %zu\n" "Files w/capabilities: %zu\n" "FIFO/pipes: %zu\n" "Sockets: %zu\n" "Block devices: %zu\n" "Character devices: %zu\n" "Symbolic links: %zu\n" "Broken symbolic links: %zu\n" "Multi-link files: %zu\n" "Files w/extended attributes: %zu\n" "Other-writable files: %zu\n" "Sticky files: %zu\n" "Unknown file types: %zu\n" "Unstatable files: %zu\n" msgstr "" #: properties.c:441 msgid "Total size: \t" msgstr "" #: listing.c:1400 #, c-format msgid "" "Total size: %s%s%s\n" "Largest file: %s%s%s %c%s%s%s%c\n" msgstr "" #: mime.c:555 msgid "Try 'mm, mime edit APPLICATION'\n" msgstr "" #: exec.c:661 msgid "Unicode disabled" msgstr "" #: exec.c:658 msgid "Unicode enabled" msgstr "" #: exec.c:655 #, c-format msgid "Unicode is %s\n" msgstr "" #: archives.c:669 msgid "" "Use extension to specify archive/compression type (defaults to .tar.gz)\n" "Example: myarchive.xz" msgstr "" #: remotes.c:70 msgid "Yes" msgstr "" #: actions.c:371 msgid "actions: No actions defined. Use the 'actions edit' command to add some" msgstr "" #: exec.c:790 msgid "allowed" msgstr "" #: archives.c:713 #, c-format msgid "archiver: %s: Error dequoting file name\n" msgstr "" #: archives.c:909 #, c-format msgid "archiver: %s: Not an archive/compressed file\n" msgstr "" #: sort.c:378 #, c-format msgid "atime %s\n" msgstr "" #: bookmarks.c:200 bookmarks.c:244 #, c-format msgid "bookmarks: %s: No such bookmark\n" msgstr "" #: bookmarks.c:416 #, c-format msgid "bookmarks: %s: Path already bookmarked\n" msgstr "" #: bookmarks.c:493 #, c-format msgid "bookmarks: %s: This name is already in use\n" msgstr "" #: bookmarks.c:461 #, c-format msgid "bookmarks: %s: This shortcut is already in use\n" msgstr "" #: bookmarks.c:274 #, c-format msgid "" "bookmarks: All bookmarks were deleted\n" " However, a backup copy was created (%s)\n" msgstr "" #: bookmarks.c:279 #, c-format msgid "bookmarks: Error creating backup file. No bookmark was deleted\n" msgstr "" #: bookmarks.c:309 #, c-format msgid "bookmarks: Error creating temporary file\n" msgstr "" #: bookmarks.c:546 #, c-format msgid "bookmarks: Error generating the bookmark line\n" msgstr "" #: bookmarks.c:391 bookmarks.c:554 bookmarks.c:563 #, c-format msgid "bookmarks: Error opening the bookmarks file\n" msgstr "" #: bookmarks.c:226 #, c-format msgid "bookmarks: Error parsing input\n" msgstr "" #: bookmarks.c:162 msgid "bookmarks: There are no bookmarks" msgstr "" #: sort.c:381 #, c-format msgid "btime %s\n" msgstr "" #: sort.c:383 #, c-format msgid "btime (not available: using 'ctime') %s\n" msgstr "" #: file_operations.c:1473 #, c-format msgid "bulk: %s\n" msgstr "" #: file_operations.c:1436 #, c-format msgid "bulk: %s: Error dequoting file name\n" msgstr "" #: file_operations.c:1514 msgid "bulk: Line mismatch in renaming file\n" msgstr "" #: file_operations.c:1493 file_operations.c:1548 msgid "bulk: Nothing to do" msgstr "" #: sort.c:387 #, c-format msgid "ctime %s\n" msgstr "" #: selection.c:1053 #, c-format msgid "desel: '%s': Invalid ELN\n" msgstr "" #: selection.c:1042 #, c-format msgid "desel: '%s': Invalid entry\n" msgstr "" #: selection.c:1094 msgid "desel: There are no selected files" msgstr "" #: media.c:559 msgid "devices" msgstr "" #: exec.c:655 exec.c:690 exec.c:757 exec.c:820 exec.c:846 exec.c:1114 #: history.c:89 msgid "disabled" msgstr "" #: exec.c:655 exec.c:690 exec.c:757 exec.c:820 exec.c:846 exec.c:1114 #: history.c:88 msgid "enabled" msgstr "" #: sort.c:393 #, c-format msgid "extension %s\n" msgstr "" #: remotes.c:66 remotes.c:68 msgid "false" msgstr "" #: exec.c:1189 msgid "file" msgstr "" #: exec.c:1189 msgid "files" msgstr "" #: navigation.c:619 #, c-format msgid "history: %d: No such ELN\n" msgstr "" #: sort.c:395 #, c-format msgid "inode %s\n" msgstr "" #: media.c:559 msgid "mountpoints" msgstr "" #: media.c:561 msgid "mp: There are no available mountpoints\n" msgstr "" #: sort.c:389 #, c-format msgid "mtime %s\n" msgstr "" #: sort.c:374 #, c-format msgid "name %s\n" msgstr "" #: sort.c:372 msgid "none" msgstr "" #: exec.c:790 msgid "not allowed" msgstr "" #: sort.c:376 #, c-format msgid "size %s\n" msgstr "" #: trash.c:1028 #, c-format msgid "trash: %s: %s\n" msgstr "" #: trash.c:1034 #, c-format msgid "trash: %s: Cannot trash a %s device\n" msgstr "" #: trash.c:1016 #, c-format msgid "trash: Cannot trash '%s'\n" msgstr "" #: trash.c:541 trash.c:830 trash.c:984 msgid "trash: No trashed files" msgstr "" #: trash.c:263 msgid "trash: There are no trashed files" msgstr "" #: trash.c:1022 msgid "trash: Use 'trash del' to remove trashed files" msgstr "" #: remotes.c:66 remotes.c:68 msgid "true" msgstr "" #: trash.c:908 #, c-format msgid "undel: %s: Invalid ELN\n" msgstr "" #: properties.c:418 properties.c:420 msgid "unknown" msgstr "" #: sort.c:391 #, c-format msgid "version %s\n" msgstr "" clifm-1.26.3/translations/portuguese/000077500000000000000000000000001506632037700176315ustar00rootroot00000000000000clifm-1.26.3/translations/portuguese/clifm.po000066400000000000000000001233511506632037700212700ustar00rootroot00000000000000# This file is part of CliFM # Copyright (C) 2016-2022 # This file is distributed under the same license as the clifm package. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2022-04-23 14:46-0300\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: properties.c:400 #, c-format msgid "\tBlocks: %s%ld%s" msgstr "" #: properties.c:398 #, c-format msgid "\tBlocks: %s%lld%s" msgstr "" #: properties.c:420 #, c-format msgid "\tGid: %s%u (%s)%s\n" msgstr "" #: properties.c:404 #, c-format msgid "\tIO Block: %s%d%s" msgstr "" #: properties.c:406 #, c-format msgid "\tIO Block: %s%ld%s" msgstr "" #: properties.c:409 #, c-format msgid "\tInode: %s%llu%s\n" msgstr "" #: properties.c:411 #, c-format msgid "\tInode: %s%zu%s\n" msgstr "" #: properties.c:317 #, c-format msgid "\tName: %s%s%s -> %s (broken link)\n" msgstr "" #: properties.c:418 #, c-format msgid "\tUid: %s%u (%s)%s" msgstr "" #: misc.c:1789 #, c-format msgid "" "\n" " Press any key to continue... " msgstr "" #: selection.c:786 #, c-format msgid "" "\n" "%s%sTotal size%s: %s\n" msgstr "" #: bookmarks.c:214 #, c-format msgid "" "\n" "%sEnter '%c' to quit.\n" msgstr "" #: selection.c:990 #, c-format msgid "" "\n" "%sEnter 'q' to quit or 'e' to edit the selections file\n" msgstr "" #: trash.c:559 trash.c:877 #, c-format msgid "" "\n" "%sEnter 'q' to quit.\n" msgstr "" #: archives.c:816 #, c-format msgid "" "\n" "%sNOTE%s: Zstandard does not support compression of multiple files into one " "single compressed file. Files will be compressed rather into multiple " "compressed files using the original file names\n" msgstr "" #: media.c:282 #, c-format msgid "" "\n" "%sUnmounted devices%s\n" "\n" msgstr "" #: colors.c:1831 #, c-format msgid "" "\n" "*The slash followed by a number (/xx) after directories or symbolic links to " "directories indicates the amount of files contained by the corresponding " "directory, excluding self (.) and parent (..) directories.\n" msgstr "" #: misc.c:1697 msgid "" "\n" "NOTE: Some keybindings on Haiku might differ. Take a look at your current " "keybindings via the 'kb' command" msgstr "" #: colors.c:1835 #, c-format msgid "" "\n" "The second field in this list is the code that is to be used to modify the " "color of the corresponding file type in the color scheme file (in the " "\"FiletypeColors\" line), using the same ANSI style color format used by " "dircolors. By default, %s uses only 8/16 colors, but you can use 256 and RGB/" "true colors as well.\n" "\n" msgstr "" #: colors.c:1807 #, c-format msgid " %sfile name%s: bd: Block special file\n" msgstr "" #: colors.c:1818 #, c-format msgid " %sfile name%s: ca: File with capabilities\n" msgstr "" #: colors.c:1813 #, c-format msgid " %sfile name%s: cd: Character special file\n" msgstr "" #: colors.c:1800 #, c-format msgid " %sfile name%s: di: Directory*\n" msgstr "" #: colors.c:1801 #, c-format msgid " %sfile name%s: ed: EMPTY directory\n" msgstr "" #: colors.c:1806 #, c-format msgid " %sfile name%s: ee: Empty executable file\n" msgstr "" #: colors.c:1815 #, c-format msgid " %sfile name%s: ef: Empty (zero-lenght) file\n" msgstr "" #: colors.c:1805 #, c-format msgid " %sfile name%s: ex: Executable file\n" msgstr "" #: colors.c:1814 #, c-format msgid " %sfile name%s: fi: Regular file\n" msgstr "" #: colors.c:1808 #, c-format msgid " %sfile name%s: ln: Symbolic link*\n" msgstr "" #: colors.c:1810 #, c-format msgid " %sfile name%s: mh: Multi-hardlink\n" msgstr "" #: colors.c:1796 #, c-format msgid " %sfile name%s: nd: Directory with no read permission\n" msgstr "" #: colors.c:1802 #, c-format msgid " %sfile name%s: ne: EMPTY directory with no read permission\n" msgstr "" #: colors.c:1798 #, c-format msgid " %sfile name%s: nf: File with no read permission\n" msgstr "" #: colors.c:1828 #, c-format msgid " %sfile name%s: no: Unknown file type\n" msgstr "" #: colors.c:1809 #, c-format msgid " %sfile name%s: or: Broken symbolic link\n" msgstr "" #: colors.c:1825 #, c-format msgid " %sfile name%s: ow: Other-writable and NOT sticky directory*\n" msgstr "" #: colors.c:1812 #, c-format msgid " %sfile name%s: pi: Pipe or FIFO special file\n" msgstr "" #: colors.c:1817 #, c-format msgid " %sfile name%s: sg: SGID file\n" msgstr "" #: colors.c:1811 #, c-format msgid " %sfile name%s: so: Socket file\n" msgstr "" #: colors.c:1819 #, c-format msgid " %sfile name%s: st: Sticky and NOT other-writable directory*\n" msgstr "" #: colors.c:1816 #, c-format msgid " %sfile name%s: su: SUID file\n" msgstr "" #: colors.c:1822 #, c-format msgid " %sfile name%s: tw: Sticky and other-writable directory*\n" msgstr "" #: colors.c:1829 #, c-format msgid " %sfile name%s: uf: Unaccessible (non-stat'able) file\n" msgstr "" #: remotes.c:67 #, c-format msgid " Auto-mount: %s\n" msgstr "" #: remotes.c:65 #, c-format msgid " Auto-unmount: %s\n" msgstr "" #: remotes.c:58 #, c-format msgid " Comment: %s\n" msgstr "" #: remotes.c:62 #, c-format msgid " Mount command: %s\n" msgstr "" #: remotes.c:69 #, c-format msgid " Mounted: %s\n" msgstr "" #: remotes.c:60 #, c-format msgid " Mountpoint: %s\n" msgstr "" #: remotes.c:64 #, c-format msgid " Unmount command: %s\n" msgstr "" #: config.c:1263 #, c-format msgid "" "# %s profile\n" "# Write here the commands you want to be executed at startup\n" "# Ex:\n" "#echo -e \"%s, the command line file manager\"\n" msgstr "" #: strings.c:1631 #, c-format msgid "%c%s: There are no selected files%c" msgstr "" #: selection.c:938 #, c-format msgid "%d file(s) deselected. " msgstr "" #: sort.c:364 #, c-format msgid "%s %s\n" msgstr "" #: misc.c:1757 #, c-format msgid "%s %s (%s), by %s\n" msgstr "" #: misc.c:1776 #, c-format msgid "" "%s %s (%s), by %s\n" "Contact: %s\n" "Website: %s\n" "License: %s\n" msgstr "" #: tags.c:115 #, c-format msgid "%s (error resolving link target)\n" msgstr "" #: sort.c:358 #, c-format msgid "%s (not available: using 'name') %s\n" msgstr "" #: config.c:1320 #, c-format msgid "" "%s created a new MIME list file (%s) It is recommended to edit this file " "(entering 'mm edit' or pressing F6) to add the programs you use and remove " "those you don't. This will make the process of opening files faster and " "smoother\n" msgstr "" #: bookmarks.c:89 #, c-format msgid "" "%s%s\n" "Enter '%c' to edit your bookmarks or '%c' to quit.\n" msgstr "" #: file_operations.c:1055 #, c-format msgid "%s%s%s currently pointing to " msgstr "" #: file_operations.c:1052 #, c-format msgid "%s%s%s currently pointing to nowhere (broken link)\n" msgstr "" #: file_operations.c:1167 #, c-format msgid "%s%s%s successfully relinked to " msgstr "" #: archives.c:1188 #, c-format msgid "%s%s%s: Succesfully mounted on %s\n" msgstr "" #: archives.c:1009 #, c-format msgid "%s%sFile%s: %s\n" msgstr "" #: selection.c:732 #, c-format msgid "%s%sSelection Box%s\n" msgstr "" #: selection.c:543 #, c-format msgid "%s%sTotal size%s: %s\n" msgstr "" #: main.c:759 #, c-format msgid "%s->%s Running as root%s\n" msgstr "" #: history.c:540 history.c:579 #, c-format msgid "%s: !%s: Event not found\n" msgstr "" #: history.c:494 #, c-format msgid "%s: !%s: event not found\n" msgstr "" #: mime.c:1349 #, c-format msgid "" "%s: %d MIME definition(s) imported from the system. Old MIME list file " "stored as %s\n" msgstr "" #: name_cleaner.c:649 #, c-format msgid "%s: %d file(s) bleached\n" msgstr "" #: selection.c:940 #, c-format msgid "%s: %d file(s) deselected. " msgstr "" #: navigation.c:80 #, c-format msgid "%s: %d is already the current workspace\n" msgstr "" #: strings.c:1702 #, c-format msgid "" "%s: %d: ELN-filename conflict. Bypass internal expansions to fix this issue: " "';CMD FILENAME'\n" msgstr "" #: media.c:199 #, c-format msgid "%s: %d: Invalid ELN\n" msgstr "" #: navigation.c:72 #, c-format msgid "%s: %d: Invalid workspace number\n" msgstr "" #: name_cleaner.c:408 prompt.c:462 #, c-format msgid "%s: %s\n" msgstr "" #: file_operations.c:977 #, c-format msgid "" "%s: %s (%s): Cannot open file\n" "Try 'APPLICATION FILENAME'\n" msgstr "" #: aux.c:817 aux.c:831 aux.c:845 #, c-format msgid "%s: %s failed to allocate %zu bytes\n" msgstr "" #: config.c:502 file_operations.c:108 file_operations.c:134 remotes.c:137 #, c-format msgid "%s: %s: %s\n" msgstr "" #: init.c:1692 #, c-format msgid "" "%s: %s: %s\n" "Falling back to default\n" msgstr "" #: init.c:1637 #, c-format msgid "" "%s: %s: %s\n" "Falling back to default configuration directory\n" msgstr "" #: init.c:1604 #, c-format msgid "" "%s: %s: %s\n" "Falling back to the default bookmarks file\n" msgstr "" #: init.c:1664 #, c-format msgid "" "%s: %s: %s\n" "Falling back to the default keybindings file\n" msgstr "" #: file_operations.c:953 #, c-format msgid "%s: %s: Broken symbolic link\n" msgstr "" #: init.c:1628 #, c-format msgid "" "%s: %s: Cannot create directory (error %d)\n" "Falling back to default configuration directory\n" msgstr "" #: profiles.c:302 #, c-format msgid "%s: %s: Cannot create profile: Home directory not found\n" msgstr "" #: file_operations.c:1741 #, c-format msgid "%s: %s: Cannot create symlink: %s\n" msgstr "" #: tags.c:384 #, c-format msgid "%s: %s: Cannot create tag\n" msgstr "" #: tags.c:50 #, c-format msgid "%s: %s: Cannot create tag: file already exists\n" msgstr "" #: file_operations.c:251 #, c-format msgid "%s: %s: Cannot open file\n" msgstr "" #: file_operations.c:210 #, c-format msgid "%s: %s: Directory empty\n" msgstr "" #: profiles.c:371 #, c-format msgid "%s: %s: Error creating profile\n" msgstr "" #: tags.c:277 #, c-format msgid "%s: %s: Error creating tag\n" msgstr "" #: config.c:1240 #, c-format msgid "%s: %s: Error creating tags directory. Tag function disabled\n" msgstr "" #: aux.c:143 #, c-format msgid "%s: %s: Error deescaping string\n" msgstr "" #: file_operations.c:1022 file_operations.c:1111 #, c-format msgid "%s: %s: Error dequoting file\n" msgstr "" #: bookmarks.c:794 misc.c:754 name_cleaner.c:523 properties.c:684 #: readline.c:401 search.c:145 search.c:552 #, c-format msgid "%s: %s: Error dequoting file name\n" msgstr "" #: file_operations.c:776 file_operations.c:911 #, c-format msgid "%s: %s: Error dequoting filename\n" msgstr "" #: navigation.c:281 #, c-format msgid "%s: %s: Error dequoting string\n" msgstr "" #: aux.c:159 navigation.c:288 #, c-format msgid "%s: %s: Error expanding tilde\n" msgstr "" #: remotes.c:255 trash.c:136 #, c-format msgid "%s: %s: Error getting parent directory\n" msgstr "" #: strings.c:1766 #, c-format msgid "%s: %s: Error getting variable name\n" msgstr "" #: mime.c:282 #, c-format msgid "%s: %s: Error opening file\n" msgstr "" #: strings.c:1591 strings.c:1733 strings.c:1973 strings.c:2047 #, c-format msgid "%s: %s: Error quoting file name\n" msgstr "" #: profiles.c:415 #, c-format msgid "%s: %s: Error removing profile\n" msgstr "" #: file_operations.c:814 #, c-format msgid "%s: %s: File already exists. Trying with '%s' instead\n" msgstr "" #: tags.c:48 #, c-format msgid "%s: %s: File already tagged\n" msgstr "" #: tags.c:531 #, c-format msgid "%s: %s: File not tagged as %s%s%s\n" msgstr "" #: file_operations.c:1095 #, c-format msgid "%s: %s: Invalid ELN\n" msgstr "" #: exec.c:1781 exec.c:1808 #, c-format msgid "%s: %s: Invalid argument. Try 'fz -h'\n" msgstr "" #: exec.c:628 #, c-format msgid "%s: %s: Invalid number\n" msgstr "" #: exec.c:1567 #, c-format msgid "%s: %s: Is a directory\n" msgstr "" #: misc.c:916 #, c-format msgid "%s: %s: No alias found\n" msgstr "" #: mime.c:1445 mime.c:1449 #, c-format msgid "%s: %s: No associated application found\n" msgstr "" #: navigation.c:371 #, c-format msgid "%s: %s: No matches found\n" msgstr "" #: exec.c:1056 #, c-format msgid "%s: %s: No such alias\n" msgstr "" #: colors.c:955 #, c-format msgid "%s: %s: No such color scheme. Falling back to default\n" msgstr "" #: colors.c:1064 #, c-format msgid "%s: %s: No such color scheme. Falling back to the default one\n" msgstr "" #: jump.c:432 #, c-format msgid "%s: %s: No such order number\n" msgstr "" #: profiles.c:393 #, c-format msgid "%s: %s: No such profile\n" msgstr "" #: profiles.c:132 #, c-format msgid "" "%s: %s: No such profile\n" "To add a new profile enter 'pf add PROFILE'\n" msgstr "" #: remotes.c:118 #, c-format msgid "%s: %s: No such remote\n" msgstr "" #: selection.c:888 #, c-format msgid "%s: %s: No such selected file\n" msgstr "" #: sort.c:457 #, c-format msgid "%s: %s: No such sorting method\n" msgstr "" #: tags.c:75 tags.c:158 #, c-format msgid "%s: %s: No such tag\n" msgstr "" #: misc.c:634 #, c-format msgid "%s: %s: Not a directory\n" msgstr "" #: file_operations.c:1044 #, c-format msgid "%s: %s: Not a symbolic link\n" msgstr "" #: remotes.c:225 #, c-format msgid "%s: %s: Not mounted\n" msgstr "" #: sanitize.c:368 #, c-format msgid "" "%s: %s: Only command base names are allowed. Ex: 'nano' instead of '/usr/bin/" "nano'\n" msgstr "" #: profiles.c:297 #, c-format msgid "%s: %s: Profile already exists\n" msgstr "" #: remotes.c:209 #, c-format msgid "%s: %s: Remote mounted on %s\n" msgstr "" #: tags.c:317 #, c-format msgid "%s: %s: Successfully removed tag\n" msgstr "" #: main.c:826 profiles.c:165 #, c-format msgid "" "%s: %s: System shell not found. Please edit the configuration file to " "specify a working shell.\n" msgstr "" #: tags.c:271 #, c-format msgid "%s: %s: Tag already exists\n" msgstr "" #: media.c:503 #, c-format msgid "%s: %s: This feature is not available on Haiku\n" msgstr "" #: init.c:1643 #, c-format msgid "%s: %s: Using alternative configuration directory\n" msgstr "" #: misc.c:934 #, c-format msgid "%s: %zu aliases were successfully imported\n" msgstr "" #: init.c:207 #, c-format msgid "" "%s: %zu: Invalid workspace.\n" "Falling back to workspace %zu\n" msgstr "" #: jump.c:410 #, c-format msgid "%s: '%c': Invalid option\n" msgstr "" #: search.c:114 search.c:535 selection.c:429 #, c-format msgid "%s: '%c': Unrecognized file type\n" msgstr "" #: profiles.c:141 #, c-format msgid "%s: '%s' is the current profile\n" msgstr "" #: config.c:1889 #, c-format msgid "%s: '%s': %s. Using the current working directory as starting path\n" msgstr "" #: config.c:1228 #, c-format msgid "" "%s: '%s': Directory not writable. Bookmarks, commands logs, and commands " "history are disabled. Program messages won't be persistent. Using default " "options\n" msgstr "" #: config.c:1202 #, c-format msgid "%s: '%s': Directory not writable. Trash function disabled\n" msgstr "" #: config.c:2023 misc.c:379 #, c-format msgid "%s: '%s': Invalid regular expression\n" msgstr "" #: profiles.c:363 #, c-format msgid "%s: '%s': Profile succesfully created\n" msgstr "" #: profiles.c:406 #, c-format msgid "%s: '%s': Profile successfully removed\n" msgstr "" #: exec.c:1462 #, c-format msgid "%s: '%s': Syntax error\n" msgstr "" #: checks.c:107 #, c-format msgid "" "%s: '%s': Unsupported terminal. This terminal cannot understand escape " "sequences\n" msgstr "" #: config.c:550 #, c-format msgid "" "%s: '%s': Using a temporary directory for the Selection Box. Selected files " "won't be persistent across reboots" msgstr "" #: navigation.c:338 #, c-format msgid "%s: /: No parent directory\n" msgstr "" #: misc.c:937 #, c-format msgid "%s: 1 alias was successfully imported\n" msgstr "" #: config.c:99 #, c-format msgid "%s: Access to configuration files is not allowed in stealth mode\n" msgstr "" #: misc.c:902 #, c-format msgid "%s: Alias already exists\n" msgstr "" #: misc.c:855 #, c-format msgid "%s: Alias conflicts with internal command\n" msgstr "" #: config.c:113 #, c-format msgid "%s: Cannot access the configuration file\n" msgstr "" #: init.c:149 #, c-format msgid "" "%s: Cannot access the home directory. Trash, bookmarks, commands logs, and " "commands history are disabled. Program messages and selected files won't be " "persistent. Using default options\n" msgstr "" #: tags.c:643 #, c-format msgid "%s: Cannot merge tags: error moving tagged files\n" msgstr "" #: bookmarks.c:597 #, c-format msgid "%s: Cannot open the bookmarks file\n" msgstr "" #: history.c:248 #, c-format msgid "%s: Could not save directory history: %s\n" msgstr "" #: colors.c:539 #, c-format msgid "%s: Current color scheme: %s\n" msgstr "" #: colors.c:1789 #, c-format msgid "%s: Currently running without colors\n" msgstr "" #: misc.c:607 #, c-format msgid "" "%s: Default terminal not set. Use the configuration file (F10) to set it\n" msgstr "" #: trash.c:150 #, c-format msgid "%s: Directory is immutable\n" msgstr "" #: jump.c:291 #, c-format msgid "%s: Directory jumper function disabled\n" msgstr "" #: init.c:1035 init.c:1043 selection.c:486 #, c-format msgid "%s: Error expanding path\n" msgstr "" #: init.c:1246 #, c-format msgid "%s: Error expanding tilde. Using default opener\n" msgstr "" #: mime.c:460 #, c-format msgid "%s: Error getting home directory\n" msgstr "" #: main.c:848 #, c-format msgid "%s: Error getting hostname\n" msgstr "" #: mime.c:1463 #, c-format msgid "%s: Error getting mime-type\n" msgstr "" #: remotes.c:230 #, c-format msgid "%s: Error getting mountpoint for '%s'\n" msgstr "" #: misc.c:1051 #, c-format msgid "%s: Error getting variable value\n" msgstr "" #: misc.c:777 #, c-format msgid "%s: Error lauching new instance\n" msgstr "" #: checks.c:99 #, c-format msgid "%s: Error opening terminal: unknown\n" msgstr "" #: profiles.c:217 #, c-format msgid "%s: Error opening the history file\n" msgstr "" #: checks.c:512 #, c-format msgid "%s: Error parsing aliased command\n" msgstr "" #: history.c:503 history.c:522 history.c:556 #, c-format msgid "%s: Error parsing history command\n" msgstr "" #: media.c:447 #, c-format msgid "%s: Error retrieving mountpoint\n" msgstr "" #: init.c:387 #, c-format msgid "%s: Error retrieving user data\n" msgstr "" #: misc.c:968 #, c-format msgid "%s: Error saving last visited directory\n" msgstr "" #: misc.c:1566 #, c-format msgid "%s: Error storing pinned directory\n" msgstr "" #: selection.c:572 #, c-format msgid "%s: Error writing selected files to the selections file\n" msgstr "" #: exec.c:535 #, c-format msgid "%s: External commands are not allowed. Run 'ext on' to enable them.\n" msgstr "" #: init.c:1350 #, c-format msgid "%s: FZF not found. Falling back to standard TAB completion\n" msgstr "" #: init.c:251 main.c:815 #, c-format msgid "%s: Fatal error! Failed retrieving current working directory\n" msgstr "" #: trash.c:203 #, c-format msgid "%s: File is immutable\n" msgstr "" #: misc.c:614 #, c-format msgid "%s: Function only available for graphical environments\n" msgstr "" #: history.c:428 #, c-format msgid "%s: History function disabled\n" msgstr "" #: bookmarks.c:694 bookmarks.c:775 #, c-format msgid "%s: Invalid bookmark\n" msgstr "" #: navigation.c:625 #, c-format msgid "%s: Invalid history entry\n" msgstr "" #: exec.c:1654 #, c-format msgid "%s: Lira: %s\n" msgstr "" #: init.c:1609 #, c-format msgid "%s: Loaded alternative bookmarks file\n" msgstr "" #: init.c:1698 #, c-format msgid "%s: Loaded alternative configuration file\n" msgstr "" #: init.c:1670 #, c-format msgid "%s: Loaded alternative keybindings file\n" msgstr "" #: exec.c:1100 #, c-format msgid "%s: Log function disabled\n" msgstr "" #: strings.c:645 strings.c:702 #, c-format msgid "%s: Missing '%c'\n" msgstr "" #: remotes.c:386 #, c-format msgid "%s: Mounting remote...\n" msgstr "" #: misc.c:386 #, c-format msgid "%s: New filter successfully set\n" msgstr "" #: misc.c:926 #, c-format msgid "%s: No alias imported\n" msgstr "" #: exec.c:1022 exec.c:1042 #, c-format msgid "%s: No aliases found\n" msgstr "" #: colors.c:408 #, c-format msgid "%s: No color schemes found\n" msgstr "" #: selection.c:583 #, c-format msgid "%s: No matches found\n" msgstr "" #: media.c:193 media.c:400 #, c-format msgid "%s: No mount application found. Install either udevil or udisks2\n" msgstr "" #: media.c:517 #, c-format msgid "%s: No mount command found. Install either udevil or udisks2\n" msgstr "" #: remotes.c:172 #, c-format msgid "%s: No mount command specified for '%s'\n" msgstr "" #: remotes.c:123 #, c-format msgid "%s: No mountpoint specified for '%s'\n" msgstr "" #: misc.c:717 #, c-format msgid "" "%s: No option specified for '%s'\n" "Trying '%s -e %s %s'\n" msgstr "" #: exec.c:1421 keybinds.c:1444 misc.c:1624 #, c-format msgid "%s: No pinned file\n" msgstr "" #: remotes.c:48 #, c-format msgid "%s: No remotes defined\n" msgstr "" #: bookmarks.c:678 #, c-format msgid "%s: No such ELN\n" msgstr "" #: bookmarks.c:699 bookmarks.c:780 #, c-format msgid "%s: No such bookmark\n" msgstr "" #: colors.c:496 #, c-format msgid "%s: No such color scheme\n" msgstr "" #: trash.c:122 #, c-format msgid "%s: No such file or directory\n" msgstr "" #: tags.c:455 #, c-format msgid "" "%s: No tag specified. Specify a tag via :TAG. E.g. tag FILE1 FILE2 :TAG\n" msgstr "" #: tags.c:67 #, c-format msgid "%s: No tags found, Use 'tag new' to create new tags\n" msgstr "" #: remotes.c:236 #, c-format msgid "%s: No unmount command found for '%s'\n" msgstr "" #: file_operations.c:486 name_cleaner.c:561 name_cleaner.c:611 #, c-format msgid "%s: Nothing to do\n" msgstr "" #: mime.c:531 #, c-format msgid "%s: Nothing was imported. No MIME definitions found\n" msgstr "" #: mime.c:454 #, c-format msgid "%s: Nothing was imported. No graphical environment found\n" msgstr "" #: trash.c:90 trash.c:182 trash.c:190 trash.c:210 trash.c:226 #, c-format msgid "%s: Permission denied\n" msgstr "" #: keybinds.c:96 keybinds.c:139 #, c-format msgid "%s: Restart the program for changes to take effect\n" msgstr "" #: config.c:2086 #, c-format msgid "" "%s: Running in stealth mode: trash, persistent selection and directory " "history, just as bookmarks, logs and configuration files, are disabled.\n" msgstr "" #: misc.c:1616 #, c-format msgid "%s: Succesfully pinned '%s'\n" msgstr "" #: tags.c:282 #, c-format msgid "%s: Successfully created tag\n" msgstr "" #: media.c:558 #, c-format msgid "%s: There are no available %s\n" msgstr "" #: exec.c:932 exec.c:950 #, c-format msgid "%s: There are no messages\n" msgstr "" #: exec.c:415 #, c-format msgid "%s: To gracefully quit enter 'q'\n" msgstr "" #: trash.c:797 trash.c:1085 #, c-format msgid "%s: Trash function disabled\n" msgstr "" #: misc.c:1703 #, c-format msgid "%s: Unable to find any pager\n" msgstr "" #: media.c:221 #, c-format msgid "%s: Unmounted %s\n" msgstr "" #: remotes.c:423 #, c-format msgid "%s: Unmounting remote...\n" msgstr "" #: main.c:744 #, c-format msgid "%s: Unsupported CPU architecture\n" msgstr "" #: main.c:750 #, c-format msgid "%s: Unsupported operating system\n" msgstr "" #: exec.c:2194 #, c-format msgid "%s: archiving: %s\n" msgstr "" #: exec.c:2175 #, c-format msgid "%s: bleach: %s\n" msgstr "" #: bookmarks.c:814 #, c-format msgid "%s: bookmarks: %s\n" msgstr "" #: navigation.c:444 #, c-format msgid "%s: cd: Home directory not found\n" msgstr "" #: colors.c:512 #, c-format msgid "" "%s: color schemes: %s\n" "TIP: To change the current color scheme use the following environment " "variables: CLIFM_FILE_COLORS, CLIFM_IFACE_COLORS, and CLIFM_EXT_COLORS\n" msgstr "" #: mime.c:1613 #, c-format msgid "%s: file: Command not found\n" msgstr "" #: config.c:1499 #, c-format msgid "%s: fopen: '%s': %s. Using default values.\n" msgstr "" #: checks.c:161 #, c-format msgid "%s: fzf not found. Falling back to standard TAB completion\n" msgstr "" #: init.c:1357 #, c-format msgid "%s: fzftab: %s\n" msgstr "" #: init.c:1379 #, c-format msgid "%s: fzytab: %s\n" msgstr "" #: init.c:1335 #, c-format msgid "%s: highlight: %s\n" msgstr "" #: exec.c:893 init.c:1267 #, c-format msgid "%s: icons: %s\n" msgstr "" #: jump.c:663 #, c-format msgid "%s: jump: No matches found\n" msgstr "" #: media.c:510 #, c-format msgid "%s: media: Function only available on Linux systems\n" msgstr "" #: profiles.c:315 #, c-format msgid "%s: mkdir: %s: Error creating configuration directory\n" msgstr "" #: config.c:1216 #, c-format msgid "" "%s: mkdir: '%s': Error creating configuration directory. Bookmarks, commands " "logs, and command history are disabled. Program messages won't be " "persistent. Using default options\n" msgstr "" #: config.c:1194 #, c-format msgid "" "%s: mkdir: '%s': Error creating trash directory. Trash function disabled\n" msgstr "" #: config.c:1277 #, c-format msgid "" "%s: mkdir: Error creating colors directory. Using the default color scheme\n" msgstr "" #: config.c:1289 #, c-format msgid "" "%s: mkdir: Error creating plugins directory. The actions function is " "disabled\n" msgstr "" #: init.c:1504 #, c-format msgid "" "%s: option requires an argument -- '%c'\n" "Try '%s --help' for more information.\n" msgstr "" #: selection.c:123 #, c-format msgid "%s: sel: %s: Already selected\n" msgstr "" #: selection.c:327 #, c-format msgid "%s: sel: %s: Invalid regular expression\n" msgstr "" #: trash.c:637 #, c-format msgid "%s: trash: %d: Invalid ELN\n" msgstr "" #: exec.c:1742 exec.c:1766 init.c:1290 #, c-format msgid "%s: trash: %s\n" msgstr "" #: trash.c:234 #, c-format msgid "%s: trash: %s (%s): Unsupported file type\n" msgstr "" #: trash.c:419 #, c-format msgid "" "%s: trash: %s/%s: Failed removing trash file\n" "Try removing it manually\n" msgstr "" #: trash.c:350 #, c-format msgid "%s: trash: %s: Error getting file name\n" msgstr "" #: trash.c:291 #, c-format msgid "%s: trash: %s: Error removing trashed file\n" msgstr "" #: trash.c:394 #, c-format msgid "%s: trash: %s: Failed copying file to Trash\n" msgstr "" #: trash.c:440 #, c-format msgid "%s: trash: %s: Failed encoding path\n" msgstr "" #: trash.c:615 #, c-format msgid "%s: trash: %s: Invalid ELN\n" msgstr "" #: trash.c:596 trash.c:646 #, c-format msgid "%s: trash: Error trashing %s\n" msgstr "" #: checks.c:123 #, c-format msgid "%s: udisks2 not found. Falling back to udevil\n" msgstr "" #: trash.c:933 #, c-format msgid "%s: undel: %d: Invalid ELN\n" msgstr "" #: trash.c:714 #, c-format msgid "%s: undel: %s: Error decoding original path\n" msgstr "" #: trash.c:770 #, c-format msgid "%s: undel: %s: Error removing info file\n" msgstr "" #: trash.c:777 #, c-format msgid "%s: undel: %s: Error restoring trashed file\n" msgstr "" #: trash.c:676 #, c-format msgid "" "%s: undel: Info file for '%s' not found. Try restoring the file manually\n" msgstr "" #: init.c:1525 #, c-format msgid "%s: unknown option character '\\%x'\n" msgstr "" #: init.c:1521 #, c-format msgid "" "%s: unrecognized option '%c'\n" "Try '%s --help' for more information.\n" msgstr "" #: init.c:1513 #, c-format msgid "" "%s: unrecognized option '%s'\n" "Try '%s --help' for more information.\n" msgstr "" #: bookmarks.c:609 #, c-format msgid "" "%sBookmarks Manager%s\n" "\n" msgstr "" #: bookmarks.c:208 #, c-format msgid "" "%sBookmarks%s\n" "\n" msgstr "" #: colors.c:1844 #, c-format msgid "" "%sExtension colors%s\n" "\n" msgstr "" #: colors.c:1795 #, c-format msgid "" "%sFile type colors%s\n" "\n" msgstr "" #: archives.c:1028 #, c-format msgid "%sFile%s: %s\n" msgstr "" #: media.c:526 #, c-format msgid "" "%sMountpoints%s\n" "\n" msgstr "" #: archives.c:940 #, c-format msgid "%sNOTE%s: Using Zstandard\n" msgstr "" #: selection.c:551 #, c-format msgid "%sSelection Box%s\n" msgstr "" #: trash.c:535 trash.c:862 #, c-format msgid "" "%sTrashed files%s\n" "\n" msgstr "" #: archives.c:1205 #, c-format msgid "" "%s[e]%sxtract %s[E]%sxtract-to-dir %s[l]%sist %s[m]%sount %s[r]%sepack " "%s[q]%suit\n" msgstr "" #: archives.c:321 #, c-format msgid "" "%s[e]%sxtract %s[E]%sxtract-to-dir %s[l]%sist %s[t]%sest %s[m]%sount " "%s[q]%suit\n" msgstr "" #: archives.c:757 archives.c:941 #, c-format msgid "%s[e]%sxtract %s[t]%sest %s[i]%snfo %s[q]%suit\n" msgstr "" #: selection.c:941 #, c-format msgid "%zu file(s) currently selected\n" msgstr "" #: selection.c:601 #, c-format msgid "%zu files are now in the Selection Box\n" msgstr "" #: selection.c:603 #, c-format msgid "" "%zu selected file(s):\n" "\n" msgstr "" #: search.c:634 #, c-format msgid "'%s': Invalid regular expression\n" msgstr "" #: properties.c:424 #, c-format msgid "Access: \t%s%s%s\n" msgstr "" #: bookmarks.c:292 msgid "All bookmarks succesfully removed\n" msgstr "" #: selection.c:1106 msgid "All files deselected\n" msgstr "" #: mime.c:1482 #, c-format msgid "Associated application: %s [%s]\n" msgstr "" #: mime.c:1432 msgid "Associated application: None\n" msgstr "" #: mime.c:1479 #, c-format msgid "Associated application: ad [built-in] [%s]\n" msgstr "" #: exec.c:844 #, c-format msgid "Auto-open disabled\n" msgstr "" #: exec.c:841 #, c-format msgid "Auto-open enabled\n" msgstr "" #: exec.c:846 #, c-format msgid "Auto-open is %s\n" msgstr "" #: exec.c:818 #, c-format msgid "Autocd disabled\n" msgstr "" #: exec.c:815 #, c-format msgid "Autocd enabled\n" msgstr "" #: exec.c:820 #, c-format msgid "Autocd is %s\n" msgstr "" #: properties.c:429 #, c-format msgid "Birth: \t\t%s%s%s\n" msgstr "" #: properties.c:388 #, c-format msgid "Block special file" msgstr "" #: bookmarks.c:450 msgid "Bookmark line example: [sc]name:path" msgstr "" #: bookmarks.c:217 msgid "Bookmark(s) to be deleted (ex: 1 2-6, or *): " msgstr "" #: bookmarks.c:819 #, c-format msgid "Bookmarks function disabled\n" msgstr "" #: bookmarks.c:799 #, c-format msgid "Bookmarks: %s: %s\n" msgstr "" #: properties.c:426 #, c-format msgid "Change: \t%s%s%s\n" msgstr "" #: properties.c:389 #, c-format msgid "Character special file" msgstr "" #: bookmarks.c:93 msgid "Choose a bookmark: " msgstr "" #: media.c:611 msgid "Choose a mountpoint/device: " msgstr "" #: media.c:609 media.c:613 msgid "Choose a mountpoint: " msgstr "" #: mime.c:586 msgid "Choose an application ('q' to quit): " msgstr "" #: listing.c:309 #, c-format msgid "Color scheme %s->%s %s\n" msgstr "" #: exec.c:879 msgid "Columns disabled\n" msgstr "" #: exec.c:872 msgid "Columns enabled\n" msgstr "" #: file_operations.c:1562 msgid "Continue? [y/N] " msgstr "" #: tags.c:393 #, c-format msgid "Created new tag %s%s%s\n" msgstr "" #: misc.c:396 #, c-format msgid "Current filter: %c%s\n" msgstr "" #: properties.c:414 #, c-format msgid "Device: %s%d%s" msgstr "" #: properties.c:416 #, c-format msgid "Device: %s%zu%s" msgstr "" #: properties.c:385 #, c-format msgid "Directory" msgstr "" #: selection.c:737 msgid "Empty" msgstr "" #: file_operations.c:739 msgid "End filename with a slash to create a directory" msgstr "" #: media.c:601 msgid "Enter 'iELN' for device information. Ex: i4" msgstr "" #: archives.c:1081 media.c:600 msgid "Enter 'q' to quit" msgstr "" #: file_operations.c:1716 msgid "Enter links suffix ('q' to quit): " msgstr "" #: history.c:129 msgid "Error getting command!" msgstr "" #: mime.c:344 msgid "Error opening temporary file\n" msgstr "" #: archives.c:410 archives.c:419 archives.c:523 archives.c:532 msgid "Error querying file type\n" msgstr "" #: listing.c:1670 listing.c:2218 #, c-format msgid "Excluded files: %d\n" msgstr "" #: exec.c:793 #, c-format msgid "External commands allowed\n" msgstr "" #: exec.c:789 #, c-format msgid "External commands are %s\n" msgstr "" #: exec.c:796 #, c-format msgid "External commands disallowed\n" msgstr "" #: archives.c:62 msgid "Extraction path ('q' to quit): " msgstr "" #: properties.c:390 #, c-format msgid "Fifo" msgstr "" #: archives.c:673 msgid "File name ('q' to quit): " msgstr "" #: bookmarks.c:572 #, c-format msgid "File succesfully bookmarked\n" msgstr "" #: selection.c:994 msgid "File(s) to be deselected (ex: 1 2-6, or *): " msgstr "" #: trash.c:563 msgid "File(s) to be removed (ex: 1 2-6, or *): " msgstr "" #: trash.c:881 msgid "File(s) to be undeleted (ex: 1 2-6, or *): " msgstr "" #: file_operations.c:740 msgid "Filename ('q' to quit): " msgstr "" #: exec.c:725 msgid "Files counter disabled\n" msgstr "" #: exec.c:718 msgid "Files counter enabled\n" msgstr "" #: misc.c:369 msgid "Filter unset" msgstr "" #: keybinds.c:842 #, c-format msgid "Folders first %s\n" msgstr "" #: exec.c:698 msgid "Folders first disabled\n" msgstr "" #: exec.c:694 msgid "Folders first enabled\n" msgstr "" #: exec.c:689 #, c-format msgid "Folders first is %s\n" msgstr "" #: exec.c:1803 msgid "Full directory size disabled\n" msgstr "" #: exec.c:1792 msgid "Full directory size enabled\n" msgstr "" #: exec.c:1799 msgid "Full directory size is already disabled" msgstr "" #: exec.c:1788 msgid "Full directory size is already enabled" msgstr "" #: search.c:211 msgid "Glob: No matches found. Trying regex..." msgstr "" #: keybinds.c:894 #, c-format msgid "Hidden files %s\n" msgstr "" #: exec.c:1121 msgid "Hidden files disabled\n" msgstr "" #: exec.c:1128 msgid "Hidden files enabled\n" msgstr "" #: exec.c:1113 #, c-format msgid "Hidden files is %s\n" msgstr "" #: history.c:405 #, c-format msgid "History is %s\n" msgstr "" #: archives.c:692 #, c-format msgid "Invalid file name\n" msgstr "" #: name_cleaner.c:572 msgid "Is this OK? [y/N/(e)dit] " msgstr "" #: history.c:88 #, c-format msgid "Logs %s\n" msgstr "" #: history.c:103 msgid "Logs already disabled" msgstr "" #: history.c:93 msgid "Logs already enabled" msgstr "" #: history.c:106 msgid "Logs succesfully disabled" msgstr "" #: history.c:96 msgid "Logs successfully enabled" msgstr "" #: keybinds.c:810 #, c-format msgid "Long view mode %s\n" msgstr "" #: mime.c:1472 #, c-format msgid "MIME type: %s\n" msgstr "" #: search.c:457 #, c-format msgid "Matches found: %d\n" msgstr "" #: search.c:810 #, c-format msgid "Matches found: %zu\n" msgstr "" #: exec.c:622 exec.c:634 #, c-format msgid "Max files set to %d\n" msgstr "" #: exec.c:615 msgid "Max files unset\n" msgstr "" #: exec.c:603 #, c-format msgid "Max files: %d\n" msgstr "" #: exec.c:601 msgid "Max files: unset" msgstr "" #: keybinds.c:339 #, c-format msgid "Max name length set back to %d\n" msgstr "" #: keybinds.c:337 msgid "Max name length unset\n" msgstr "" #: media.c:504 msgid "Media" msgstr "" #: properties.c:425 #, c-format msgid "Modify: \t%s%s%s\n" msgstr "" #: media.c:524 msgid "Mounted devices" msgstr "" #: media.c:504 media.c:523 msgid "Mountpoints" msgstr "" #: jump.c:313 msgid "" "NOTE 2: An asterisk next rank values means that the corresponding directory " "is bookmarked, pinned, or currently used in some workspace\n" msgstr "" #: jump.c:311 msgid "" "NOTE: First time access is displayed in days, while last time access is " "displayed in hours" msgstr "" #: mime.c:1471 remotes.c:56 #, c-format msgid "Name: %s\n" msgstr "" #: config.c:87 #, c-format msgid "New configuration file written to '%s'\n" msgstr "" #: archives.c:1085 msgid "New format (ex: .tar.xz): " msgstr "" #: file_operations.c:1068 msgid "New path ('q' to quit): " msgstr "" #: remotes.c:69 msgid "No" msgstr "" #: config.c:58 msgid "No configuration file found" msgstr "" #: tags.c:167 #, c-format msgid "No file tagged as '%s'\n" msgstr "" #: misc.c:361 msgid "No filter set" msgstr "" #: search.c:673 search.c:812 #, c-format msgid "No matches found\n" msgstr "" #: exec.c:1210 msgid "No pinned file" msgstr "" #: mime.c:1378 msgid "No such ELN" msgstr "" #: mime.c:1471 msgid "None" msgstr "" #: config.c:80 #, c-format msgid "Old configuration file stored as '%s'\n" msgstr "" #: keybinds.c:1533 #, c-format msgid "Only directories %s\n" msgstr "" #: exec.c:975 #, c-format msgid "Opener set to '%s'\n" msgstr "" #: archives.c:117 archives.c:762 archives.c:948 msgid "Operation: " msgstr "" #: jump.c:316 msgid "Order\tVisits\tFirst\tLast\tRank\tDirectory" msgstr "" #: exec.c:765 msgid "Pager disabled\n" msgstr "" #: exec.c:761 msgid "Pager enabled\n" msgstr "" #: exec.c:1208 #, c-format msgid "Pinned file: %s\n" msgstr "" #: properties.c:391 #, c-format msgid "Regular file" msgstr "" #: file_operations.c:1127 msgid "Relink as a broken symbolic link? [y/n] " msgstr "" #: properties.c:434 #, c-format msgid "Size: \t\t%s%s%s\n" msgstr "" #: properties.c:386 #, c-format msgid "Socket" msgstr "" #: listing.c:304 msgid "Sorted by: " msgstr "" #: sort.c:466 msgid "Sorting method: " msgstr "" #: misc.c:1643 #, c-format msgid "Succesfully unpinned %s\n" msgstr "" #: tags.c:656 #, c-format msgid "Successfully merged %s%s%s into %s%s%s\n" msgstr "" #: bookmarks.c:365 #, c-format msgid "Successfully removed '%s'\n" msgstr "" #: tags.c:484 #, c-format msgid "Successfully tagged %zu file(s)\n" msgstr "" #: tags.c:554 #, c-format msgid "Successfully untagged %zu file(s)\n" msgstr "" #: exec.c:991 exec.c:995 keybinds.c:870 msgid "Switched back to normal mode\n" msgstr "" #: keybinds.c:868 msgid "Switched to light mode\n" msgstr "" #: properties.c:387 #, c-format msgid "Symbolic link" msgstr "" #: exec.c:733 msgid "The files counter is disabled" msgstr "" #: exec.c:731 msgid "The files counter is enabled" msgstr "" #: exec.c:756 #, c-format msgid "The files pager is %s\n" msgstr "" #: exec.c:1188 #, c-format msgid "Toggled executable bit on %zu %s\n" msgstr "" #: exec.c:1689 #, c-format msgid "" "Total files: %zu\n" "Directories: %zu\n" "Regular files: %zu\n" "Executable files: %zu\n" "Hidden files: %zu\n" "SUID files: %zu\n" "SGID files: %zu\n" "Files w/capabilities: %zu\n" "FIFO/pipes: %zu\n" "Sockets: %zu\n" "Block devices: %zu\n" "Character devices: %zu\n" "Symbolic links: %zu\n" "Broken symbolic links: %zu\n" "Multi-link files: %zu\n" "Files w/extended attributes: %zu\n" "Other-writable files: %zu\n" "Sticky files: %zu\n" "Unknown file types: %zu\n" "Unstatable files: %zu\n" msgstr "" #: properties.c:441 msgid "Total size: \t" msgstr "" #: listing.c:1400 #, c-format msgid "" "Total size: %s%s%s\n" "Largest file: %s%s%s %c%s%s%s%c\n" msgstr "" #: mime.c:555 msgid "Try 'mm, mime edit APPLICATION'\n" msgstr "" #: exec.c:661 msgid "Unicode disabled" msgstr "" #: exec.c:658 msgid "Unicode enabled" msgstr "" #: exec.c:655 #, c-format msgid "Unicode is %s\n" msgstr "" #: archives.c:669 msgid "" "Use extension to specify archive/compression type (defaults to .tar.gz)\n" "Example: myarchive.xz" msgstr "" #: remotes.c:70 msgid "Yes" msgstr "" #: actions.c:371 msgid "actions: No actions defined. Use the 'actions edit' command to add some" msgstr "" #: exec.c:790 msgid "allowed" msgstr "" #: archives.c:713 #, c-format msgid "archiver: %s: Error dequoting file name\n" msgstr "" #: archives.c:909 #, c-format msgid "archiver: %s: Not an archive/compressed file\n" msgstr "" #: sort.c:378 #, c-format msgid "atime %s\n" msgstr "" #: bookmarks.c:200 bookmarks.c:244 #, c-format msgid "bookmarks: %s: No such bookmark\n" msgstr "" #: bookmarks.c:416 #, c-format msgid "bookmarks: %s: Path already bookmarked\n" msgstr "" #: bookmarks.c:493 #, c-format msgid "bookmarks: %s: This name is already in use\n" msgstr "" #: bookmarks.c:461 #, c-format msgid "bookmarks: %s: This shortcut is already in use\n" msgstr "" #: bookmarks.c:274 #, c-format msgid "" "bookmarks: All bookmarks were deleted\n" " However, a backup copy was created (%s)\n" msgstr "" #: bookmarks.c:279 #, c-format msgid "bookmarks: Error creating backup file. No bookmark was deleted\n" msgstr "" #: bookmarks.c:309 #, c-format msgid "bookmarks: Error creating temporary file\n" msgstr "" #: bookmarks.c:546 #, c-format msgid "bookmarks: Error generating the bookmark line\n" msgstr "" #: bookmarks.c:391 bookmarks.c:554 bookmarks.c:563 #, c-format msgid "bookmarks: Error opening the bookmarks file\n" msgstr "" #: bookmarks.c:226 #, c-format msgid "bookmarks: Error parsing input\n" msgstr "" #: bookmarks.c:162 msgid "bookmarks: There are no bookmarks" msgstr "" #: sort.c:381 #, c-format msgid "btime %s\n" msgstr "" #: sort.c:383 #, c-format msgid "btime (not available: using 'ctime') %s\n" msgstr "" #: file_operations.c:1473 #, c-format msgid "bulk: %s\n" msgstr "" #: file_operations.c:1436 #, c-format msgid "bulk: %s: Error dequoting file name\n" msgstr "" #: file_operations.c:1514 msgid "bulk: Line mismatch in renaming file\n" msgstr "" #: file_operations.c:1493 file_operations.c:1548 msgid "bulk: Nothing to do" msgstr "" #: sort.c:387 #, c-format msgid "ctime %s\n" msgstr "" #: selection.c:1053 #, c-format msgid "desel: '%s': Invalid ELN\n" msgstr "" #: selection.c:1042 #, c-format msgid "desel: '%s': Invalid entry\n" msgstr "" #: selection.c:1094 msgid "desel: There are no selected files" msgstr "" #: media.c:559 msgid "devices" msgstr "" #: exec.c:655 exec.c:690 exec.c:757 exec.c:820 exec.c:846 exec.c:1114 #: history.c:89 msgid "disabled" msgstr "" #: exec.c:655 exec.c:690 exec.c:757 exec.c:820 exec.c:846 exec.c:1114 #: history.c:88 msgid "enabled" msgstr "" #: sort.c:393 #, c-format msgid "extension %s\n" msgstr "" #: remotes.c:66 remotes.c:68 msgid "false" msgstr "" #: exec.c:1189 msgid "file" msgstr "" #: exec.c:1189 msgid "files" msgstr "" #: navigation.c:619 #, c-format msgid "history: %d: No such ELN\n" msgstr "" #: sort.c:395 #, c-format msgid "inode %s\n" msgstr "" #: media.c:559 msgid "mountpoints" msgstr "" #: media.c:561 msgid "mp: There are no available mountpoints\n" msgstr "" #: sort.c:389 #, c-format msgid "mtime %s\n" msgstr "" #: sort.c:374 #, c-format msgid "name %s\n" msgstr "" #: sort.c:372 msgid "none" msgstr "" #: exec.c:790 msgid "not allowed" msgstr "" #: sort.c:376 #, c-format msgid "size %s\n" msgstr "" #: trash.c:1028 #, c-format msgid "trash: %s: %s\n" msgstr "" #: trash.c:1034 #, c-format msgid "trash: %s: Cannot trash a %s device\n" msgstr "" #: trash.c:1016 #, c-format msgid "trash: Cannot trash '%s'\n" msgstr "" #: trash.c:541 trash.c:830 trash.c:984 msgid "trash: No trashed files" msgstr "" #: trash.c:263 msgid "trash: There are no trashed files" msgstr "" #: trash.c:1022 msgid "trash: Use 'trash del' to remove trashed files" msgstr "" #: remotes.c:66 remotes.c:68 msgid "true" msgstr "" #: trash.c:908 #, c-format msgid "undel: %s: Invalid ELN\n" msgstr "" #: properties.c:418 properties.c:420 msgid "unknown" msgstr "" #: sort.c:391 #, c-format msgid "version %s\n" msgstr "" clifm-1.26.3/translations/spanish/000077500000000000000000000000001506632037700170745ustar00rootroot00000000000000clifm-1.26.3/translations/spanish/clifm.po000066400000000000000000001233511506632037700205330ustar00rootroot00000000000000# This file is part of CliFM # Copyright (C) 2016-2022 # This file is distributed under the same license as the clifm package. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2022-04-23 14:46-0300\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: properties.c:400 #, c-format msgid "\tBlocks: %s%ld%s" msgstr "" #: properties.c:398 #, c-format msgid "\tBlocks: %s%lld%s" msgstr "" #: properties.c:420 #, c-format msgid "\tGid: %s%u (%s)%s\n" msgstr "" #: properties.c:404 #, c-format msgid "\tIO Block: %s%d%s" msgstr "" #: properties.c:406 #, c-format msgid "\tIO Block: %s%ld%s" msgstr "" #: properties.c:409 #, c-format msgid "\tInode: %s%llu%s\n" msgstr "" #: properties.c:411 #, c-format msgid "\tInode: %s%zu%s\n" msgstr "" #: properties.c:317 #, c-format msgid "\tName: %s%s%s -> %s (broken link)\n" msgstr "" #: properties.c:418 #, c-format msgid "\tUid: %s%u (%s)%s" msgstr "" #: misc.c:1789 #, c-format msgid "" "\n" " Press any key to continue... " msgstr "" #: selection.c:786 #, c-format msgid "" "\n" "%s%sTotal size%s: %s\n" msgstr "" #: bookmarks.c:214 #, c-format msgid "" "\n" "%sEnter '%c' to quit.\n" msgstr "" #: selection.c:990 #, c-format msgid "" "\n" "%sEnter 'q' to quit or 'e' to edit the selections file\n" msgstr "" #: trash.c:559 trash.c:877 #, c-format msgid "" "\n" "%sEnter 'q' to quit.\n" msgstr "" #: archives.c:816 #, c-format msgid "" "\n" "%sNOTE%s: Zstandard does not support compression of multiple files into one " "single compressed file. Files will be compressed rather into multiple " "compressed files using the original file names\n" msgstr "" #: media.c:282 #, c-format msgid "" "\n" "%sUnmounted devices%s\n" "\n" msgstr "" #: colors.c:1831 #, c-format msgid "" "\n" "*The slash followed by a number (/xx) after directories or symbolic links to " "directories indicates the amount of files contained by the corresponding " "directory, excluding self (.) and parent (..) directories.\n" msgstr "" #: misc.c:1697 msgid "" "\n" "NOTE: Some keybindings on Haiku might differ. Take a look at your current " "keybindings via the 'kb' command" msgstr "" #: colors.c:1835 #, c-format msgid "" "\n" "The second field in this list is the code that is to be used to modify the " "color of the corresponding file type in the color scheme file (in the " "\"FiletypeColors\" line), using the same ANSI style color format used by " "dircolors. By default, %s uses only 8/16 colors, but you can use 256 and RGB/" "true colors as well.\n" "\n" msgstr "" #: colors.c:1807 #, c-format msgid " %sfile name%s: bd: Block special file\n" msgstr "" #: colors.c:1818 #, c-format msgid " %sfile name%s: ca: File with capabilities\n" msgstr "" #: colors.c:1813 #, c-format msgid " %sfile name%s: cd: Character special file\n" msgstr "" #: colors.c:1800 #, c-format msgid " %sfile name%s: di: Directory*\n" msgstr "" #: colors.c:1801 #, c-format msgid " %sfile name%s: ed: EMPTY directory\n" msgstr "" #: colors.c:1806 #, c-format msgid " %sfile name%s: ee: Empty executable file\n" msgstr "" #: colors.c:1815 #, c-format msgid " %sfile name%s: ef: Empty (zero-lenght) file\n" msgstr "" #: colors.c:1805 #, c-format msgid " %sfile name%s: ex: Executable file\n" msgstr "" #: colors.c:1814 #, c-format msgid " %sfile name%s: fi: Regular file\n" msgstr "" #: colors.c:1808 #, c-format msgid " %sfile name%s: ln: Symbolic link*\n" msgstr "" #: colors.c:1810 #, c-format msgid " %sfile name%s: mh: Multi-hardlink\n" msgstr "" #: colors.c:1796 #, c-format msgid " %sfile name%s: nd: Directory with no read permission\n" msgstr "" #: colors.c:1802 #, c-format msgid " %sfile name%s: ne: EMPTY directory with no read permission\n" msgstr "" #: colors.c:1798 #, c-format msgid " %sfile name%s: nf: File with no read permission\n" msgstr "" #: colors.c:1828 #, c-format msgid " %sfile name%s: no: Unknown file type\n" msgstr "" #: colors.c:1809 #, c-format msgid " %sfile name%s: or: Broken symbolic link\n" msgstr "" #: colors.c:1825 #, c-format msgid " %sfile name%s: ow: Other-writable and NOT sticky directory*\n" msgstr "" #: colors.c:1812 #, c-format msgid " %sfile name%s: pi: Pipe or FIFO special file\n" msgstr "" #: colors.c:1817 #, c-format msgid " %sfile name%s: sg: SGID file\n" msgstr "" #: colors.c:1811 #, c-format msgid " %sfile name%s: so: Socket file\n" msgstr "" #: colors.c:1819 #, c-format msgid " %sfile name%s: st: Sticky and NOT other-writable directory*\n" msgstr "" #: colors.c:1816 #, c-format msgid " %sfile name%s: su: SUID file\n" msgstr "" #: colors.c:1822 #, c-format msgid " %sfile name%s: tw: Sticky and other-writable directory*\n" msgstr "" #: colors.c:1829 #, c-format msgid " %sfile name%s: uf: Unaccessible (non-stat'able) file\n" msgstr "" #: remotes.c:67 #, c-format msgid " Auto-mount: %s\n" msgstr "" #: remotes.c:65 #, c-format msgid " Auto-unmount: %s\n" msgstr "" #: remotes.c:58 #, c-format msgid " Comment: %s\n" msgstr "" #: remotes.c:62 #, c-format msgid " Mount command: %s\n" msgstr "" #: remotes.c:69 #, c-format msgid " Mounted: %s\n" msgstr "" #: remotes.c:60 #, c-format msgid " Mountpoint: %s\n" msgstr "" #: remotes.c:64 #, c-format msgid " Unmount command: %s\n" msgstr "" #: config.c:1263 #, c-format msgid "" "# %s profile\n" "# Write here the commands you want to be executed at startup\n" "# Ex:\n" "#echo -e \"%s, the command line file manager\"\n" msgstr "" #: strings.c:1631 #, c-format msgid "%c%s: There are no selected files%c" msgstr "" #: selection.c:938 #, c-format msgid "%d file(s) deselected. " msgstr "" #: sort.c:364 #, c-format msgid "%s %s\n" msgstr "" #: misc.c:1757 #, c-format msgid "%s %s (%s), by %s\n" msgstr "" #: misc.c:1776 #, c-format msgid "" "%s %s (%s), by %s\n" "Contact: %s\n" "Website: %s\n" "License: %s\n" msgstr "" #: tags.c:115 #, c-format msgid "%s (error resolving link target)\n" msgstr "" #: sort.c:358 #, c-format msgid "%s (not available: using 'name') %s\n" msgstr "" #: config.c:1320 #, c-format msgid "" "%s created a new MIME list file (%s) It is recommended to edit this file " "(entering 'mm edit' or pressing F6) to add the programs you use and remove " "those you don't. This will make the process of opening files faster and " "smoother\n" msgstr "" #: bookmarks.c:89 #, c-format msgid "" "%s%s\n" "Enter '%c' to edit your bookmarks or '%c' to quit.\n" msgstr "" #: file_operations.c:1055 #, c-format msgid "%s%s%s currently pointing to " msgstr "" #: file_operations.c:1052 #, c-format msgid "%s%s%s currently pointing to nowhere (broken link)\n" msgstr "" #: file_operations.c:1167 #, c-format msgid "%s%s%s successfully relinked to " msgstr "" #: archives.c:1188 #, c-format msgid "%s%s%s: Succesfully mounted on %s\n" msgstr "" #: archives.c:1009 #, c-format msgid "%s%sFile%s: %s\n" msgstr "" #: selection.c:732 #, c-format msgid "%s%sSelection Box%s\n" msgstr "" #: selection.c:543 #, c-format msgid "%s%sTotal size%s: %s\n" msgstr "" #: main.c:759 #, c-format msgid "%s->%s Running as root%s\n" msgstr "" #: history.c:540 history.c:579 #, c-format msgid "%s: !%s: Event not found\n" msgstr "" #: history.c:494 #, c-format msgid "%s: !%s: event not found\n" msgstr "" #: mime.c:1349 #, c-format msgid "" "%s: %d MIME definition(s) imported from the system. Old MIME list file " "stored as %s\n" msgstr "" #: name_cleaner.c:649 #, c-format msgid "%s: %d file(s) bleached\n" msgstr "" #: selection.c:940 #, c-format msgid "%s: %d file(s) deselected. " msgstr "" #: navigation.c:80 #, c-format msgid "%s: %d is already the current workspace\n" msgstr "" #: strings.c:1702 #, c-format msgid "" "%s: %d: ELN-filename conflict. Bypass internal expansions to fix this issue: " "';CMD FILENAME'\n" msgstr "" #: media.c:199 #, c-format msgid "%s: %d: Invalid ELN\n" msgstr "" #: navigation.c:72 #, c-format msgid "%s: %d: Invalid workspace number\n" msgstr "" #: name_cleaner.c:408 prompt.c:462 #, c-format msgid "%s: %s\n" msgstr "" #: file_operations.c:977 #, c-format msgid "" "%s: %s (%s): Cannot open file\n" "Try 'APPLICATION FILENAME'\n" msgstr "" #: aux.c:817 aux.c:831 aux.c:845 #, c-format msgid "%s: %s failed to allocate %zu bytes\n" msgstr "" #: config.c:502 file_operations.c:108 file_operations.c:134 remotes.c:137 #, c-format msgid "%s: %s: %s\n" msgstr "" #: init.c:1692 #, c-format msgid "" "%s: %s: %s\n" "Falling back to default\n" msgstr "" #: init.c:1637 #, c-format msgid "" "%s: %s: %s\n" "Falling back to default configuration directory\n" msgstr "" #: init.c:1604 #, c-format msgid "" "%s: %s: %s\n" "Falling back to the default bookmarks file\n" msgstr "" #: init.c:1664 #, c-format msgid "" "%s: %s: %s\n" "Falling back to the default keybindings file\n" msgstr "" #: file_operations.c:953 #, c-format msgid "%s: %s: Broken symbolic link\n" msgstr "" #: init.c:1628 #, c-format msgid "" "%s: %s: Cannot create directory (error %d)\n" "Falling back to default configuration directory\n" msgstr "" #: profiles.c:302 #, c-format msgid "%s: %s: Cannot create profile: Home directory not found\n" msgstr "" #: file_operations.c:1741 #, c-format msgid "%s: %s: Cannot create symlink: %s\n" msgstr "" #: tags.c:384 #, c-format msgid "%s: %s: Cannot create tag\n" msgstr "" #: tags.c:50 #, c-format msgid "%s: %s: Cannot create tag: file already exists\n" msgstr "" #: file_operations.c:251 #, c-format msgid "%s: %s: Cannot open file\n" msgstr "" #: file_operations.c:210 #, c-format msgid "%s: %s: Directory empty\n" msgstr "" #: profiles.c:371 #, c-format msgid "%s: %s: Error creating profile\n" msgstr "" #: tags.c:277 #, c-format msgid "%s: %s: Error creating tag\n" msgstr "" #: config.c:1240 #, c-format msgid "%s: %s: Error creating tags directory. Tag function disabled\n" msgstr "" #: aux.c:143 #, c-format msgid "%s: %s: Error deescaping string\n" msgstr "" #: file_operations.c:1022 file_operations.c:1111 #, c-format msgid "%s: %s: Error dequoting file\n" msgstr "" #: bookmarks.c:794 misc.c:754 name_cleaner.c:523 properties.c:684 #: readline.c:401 search.c:145 search.c:552 #, c-format msgid "%s: %s: Error dequoting file name\n" msgstr "" #: file_operations.c:776 file_operations.c:911 #, c-format msgid "%s: %s: Error dequoting filename\n" msgstr "" #: navigation.c:281 #, c-format msgid "%s: %s: Error dequoting string\n" msgstr "" #: aux.c:159 navigation.c:288 #, c-format msgid "%s: %s: Error expanding tilde\n" msgstr "" #: remotes.c:255 trash.c:136 #, c-format msgid "%s: %s: Error getting parent directory\n" msgstr "" #: strings.c:1766 #, c-format msgid "%s: %s: Error getting variable name\n" msgstr "" #: mime.c:282 #, c-format msgid "%s: %s: Error opening file\n" msgstr "" #: strings.c:1591 strings.c:1733 strings.c:1973 strings.c:2047 #, c-format msgid "%s: %s: Error quoting file name\n" msgstr "" #: profiles.c:415 #, c-format msgid "%s: %s: Error removing profile\n" msgstr "" #: file_operations.c:814 #, c-format msgid "%s: %s: File already exists. Trying with '%s' instead\n" msgstr "" #: tags.c:48 #, c-format msgid "%s: %s: File already tagged\n" msgstr "" #: tags.c:531 #, c-format msgid "%s: %s: File not tagged as %s%s%s\n" msgstr "" #: file_operations.c:1095 #, c-format msgid "%s: %s: Invalid ELN\n" msgstr "" #: exec.c:1781 exec.c:1808 #, c-format msgid "%s: %s: Invalid argument. Try 'fz -h'\n" msgstr "" #: exec.c:628 #, c-format msgid "%s: %s: Invalid number\n" msgstr "" #: exec.c:1567 #, c-format msgid "%s: %s: Is a directory\n" msgstr "" #: misc.c:916 #, c-format msgid "%s: %s: No alias found\n" msgstr "" #: mime.c:1445 mime.c:1449 #, c-format msgid "%s: %s: No associated application found\n" msgstr "" #: navigation.c:371 #, c-format msgid "%s: %s: No matches found\n" msgstr "" #: exec.c:1056 #, c-format msgid "%s: %s: No such alias\n" msgstr "" #: colors.c:955 #, c-format msgid "%s: %s: No such color scheme. Falling back to default\n" msgstr "" #: colors.c:1064 #, c-format msgid "%s: %s: No such color scheme. Falling back to the default one\n" msgstr "" #: jump.c:432 #, c-format msgid "%s: %s: No such order number\n" msgstr "" #: profiles.c:393 #, c-format msgid "%s: %s: No such profile\n" msgstr "" #: profiles.c:132 #, c-format msgid "" "%s: %s: No such profile\n" "To add a new profile enter 'pf add PROFILE'\n" msgstr "" #: remotes.c:118 #, c-format msgid "%s: %s: No such remote\n" msgstr "" #: selection.c:888 #, c-format msgid "%s: %s: No such selected file\n" msgstr "" #: sort.c:457 #, c-format msgid "%s: %s: No such sorting method\n" msgstr "" #: tags.c:75 tags.c:158 #, c-format msgid "%s: %s: No such tag\n" msgstr "" #: misc.c:634 #, c-format msgid "%s: %s: Not a directory\n" msgstr "" #: file_operations.c:1044 #, c-format msgid "%s: %s: Not a symbolic link\n" msgstr "" #: remotes.c:225 #, c-format msgid "%s: %s: Not mounted\n" msgstr "" #: sanitize.c:368 #, c-format msgid "" "%s: %s: Only command base names are allowed. Ex: 'nano' instead of '/usr/bin/" "nano'\n" msgstr "" #: profiles.c:297 #, c-format msgid "%s: %s: Profile already exists\n" msgstr "" #: remotes.c:209 #, c-format msgid "%s: %s: Remote mounted on %s\n" msgstr "" #: tags.c:317 #, c-format msgid "%s: %s: Successfully removed tag\n" msgstr "" #: main.c:826 profiles.c:165 #, c-format msgid "" "%s: %s: System shell not found. Please edit the configuration file to " "specify a working shell.\n" msgstr "" #: tags.c:271 #, c-format msgid "%s: %s: Tag already exists\n" msgstr "" #: media.c:503 #, c-format msgid "%s: %s: This feature is not available on Haiku\n" msgstr "" #: init.c:1643 #, c-format msgid "%s: %s: Using alternative configuration directory\n" msgstr "" #: misc.c:934 #, c-format msgid "%s: %zu aliases were successfully imported\n" msgstr "" #: init.c:207 #, c-format msgid "" "%s: %zu: Invalid workspace.\n" "Falling back to workspace %zu\n" msgstr "" #: jump.c:410 #, c-format msgid "%s: '%c': Invalid option\n" msgstr "" #: search.c:114 search.c:535 selection.c:429 #, c-format msgid "%s: '%c': Unrecognized file type\n" msgstr "" #: profiles.c:141 #, c-format msgid "%s: '%s' is the current profile\n" msgstr "" #: config.c:1889 #, c-format msgid "%s: '%s': %s. Using the current working directory as starting path\n" msgstr "" #: config.c:1228 #, c-format msgid "" "%s: '%s': Directory not writable. Bookmarks, commands logs, and commands " "history are disabled. Program messages won't be persistent. Using default " "options\n" msgstr "" #: config.c:1202 #, c-format msgid "%s: '%s': Directory not writable. Trash function disabled\n" msgstr "" #: config.c:2023 misc.c:379 #, c-format msgid "%s: '%s': Invalid regular expression\n" msgstr "" #: profiles.c:363 #, c-format msgid "%s: '%s': Profile succesfully created\n" msgstr "" #: profiles.c:406 #, c-format msgid "%s: '%s': Profile successfully removed\n" msgstr "" #: exec.c:1462 #, c-format msgid "%s: '%s': Syntax error\n" msgstr "" #: checks.c:107 #, c-format msgid "" "%s: '%s': Unsupported terminal. This terminal cannot understand escape " "sequences\n" msgstr "" #: config.c:550 #, c-format msgid "" "%s: '%s': Using a temporary directory for the Selection Box. Selected files " "won't be persistent across reboots" msgstr "" #: navigation.c:338 #, c-format msgid "%s: /: No parent directory\n" msgstr "" #: misc.c:937 #, c-format msgid "%s: 1 alias was successfully imported\n" msgstr "" #: config.c:99 #, c-format msgid "%s: Access to configuration files is not allowed in stealth mode\n" msgstr "" #: misc.c:902 #, c-format msgid "%s: Alias already exists\n" msgstr "" #: misc.c:855 #, c-format msgid "%s: Alias conflicts with internal command\n" msgstr "" #: config.c:113 #, c-format msgid "%s: Cannot access the configuration file\n" msgstr "" #: init.c:149 #, c-format msgid "" "%s: Cannot access the home directory. Trash, bookmarks, commands logs, and " "commands history are disabled. Program messages and selected files won't be " "persistent. Using default options\n" msgstr "" #: tags.c:643 #, c-format msgid "%s: Cannot merge tags: error moving tagged files\n" msgstr "" #: bookmarks.c:597 #, c-format msgid "%s: Cannot open the bookmarks file\n" msgstr "" #: history.c:248 #, c-format msgid "%s: Could not save directory history: %s\n" msgstr "" #: colors.c:539 #, c-format msgid "%s: Current color scheme: %s\n" msgstr "" #: colors.c:1789 #, c-format msgid "%s: Currently running without colors\n" msgstr "" #: misc.c:607 #, c-format msgid "" "%s: Default terminal not set. Use the configuration file (F10) to set it\n" msgstr "" #: trash.c:150 #, c-format msgid "%s: Directory is immutable\n" msgstr "" #: jump.c:291 #, c-format msgid "%s: Directory jumper function disabled\n" msgstr "" #: init.c:1035 init.c:1043 selection.c:486 #, c-format msgid "%s: Error expanding path\n" msgstr "" #: init.c:1246 #, c-format msgid "%s: Error expanding tilde. Using default opener\n" msgstr "" #: mime.c:460 #, c-format msgid "%s: Error getting home directory\n" msgstr "" #: main.c:848 #, c-format msgid "%s: Error getting hostname\n" msgstr "" #: mime.c:1463 #, c-format msgid "%s: Error getting mime-type\n" msgstr "" #: remotes.c:230 #, c-format msgid "%s: Error getting mountpoint for '%s'\n" msgstr "" #: misc.c:1051 #, c-format msgid "%s: Error getting variable value\n" msgstr "" #: misc.c:777 #, c-format msgid "%s: Error lauching new instance\n" msgstr "" #: checks.c:99 #, c-format msgid "%s: Error opening terminal: unknown\n" msgstr "" #: profiles.c:217 #, c-format msgid "%s: Error opening the history file\n" msgstr "" #: checks.c:512 #, c-format msgid "%s: Error parsing aliased command\n" msgstr "" #: history.c:503 history.c:522 history.c:556 #, c-format msgid "%s: Error parsing history command\n" msgstr "" #: media.c:447 #, c-format msgid "%s: Error retrieving mountpoint\n" msgstr "" #: init.c:387 #, c-format msgid "%s: Error retrieving user data\n" msgstr "" #: misc.c:968 #, c-format msgid "%s: Error saving last visited directory\n" msgstr "" #: misc.c:1566 #, c-format msgid "%s: Error storing pinned directory\n" msgstr "" #: selection.c:572 #, c-format msgid "%s: Error writing selected files to the selections file\n" msgstr "" #: exec.c:535 #, c-format msgid "%s: External commands are not allowed. Run 'ext on' to enable them.\n" msgstr "" #: init.c:1350 #, c-format msgid "%s: FZF not found. Falling back to standard TAB completion\n" msgstr "" #: init.c:251 main.c:815 #, c-format msgid "%s: Fatal error! Failed retrieving current working directory\n" msgstr "" #: trash.c:203 #, c-format msgid "%s: File is immutable\n" msgstr "" #: misc.c:614 #, c-format msgid "%s: Function only available for graphical environments\n" msgstr "" #: history.c:428 #, c-format msgid "%s: History function disabled\n" msgstr "" #: bookmarks.c:694 bookmarks.c:775 #, c-format msgid "%s: Invalid bookmark\n" msgstr "" #: navigation.c:625 #, c-format msgid "%s: Invalid history entry\n" msgstr "" #: exec.c:1654 #, c-format msgid "%s: Lira: %s\n" msgstr "" #: init.c:1609 #, c-format msgid "%s: Loaded alternative bookmarks file\n" msgstr "" #: init.c:1698 #, c-format msgid "%s: Loaded alternative configuration file\n" msgstr "" #: init.c:1670 #, c-format msgid "%s: Loaded alternative keybindings file\n" msgstr "" #: exec.c:1100 #, c-format msgid "%s: Log function disabled\n" msgstr "" #: strings.c:645 strings.c:702 #, c-format msgid "%s: Missing '%c'\n" msgstr "" #: remotes.c:386 #, c-format msgid "%s: Mounting remote...\n" msgstr "" #: misc.c:386 #, c-format msgid "%s: New filter successfully set\n" msgstr "" #: misc.c:926 #, c-format msgid "%s: No alias imported\n" msgstr "" #: exec.c:1022 exec.c:1042 #, c-format msgid "%s: No aliases found\n" msgstr "" #: colors.c:408 #, c-format msgid "%s: No color schemes found\n" msgstr "" #: selection.c:583 #, c-format msgid "%s: No matches found\n" msgstr "" #: media.c:193 media.c:400 #, c-format msgid "%s: No mount application found. Install either udevil or udisks2\n" msgstr "" #: media.c:517 #, c-format msgid "%s: No mount command found. Install either udevil or udisks2\n" msgstr "" #: remotes.c:172 #, c-format msgid "%s: No mount command specified for '%s'\n" msgstr "" #: remotes.c:123 #, c-format msgid "%s: No mountpoint specified for '%s'\n" msgstr "" #: misc.c:717 #, c-format msgid "" "%s: No option specified for '%s'\n" "Trying '%s -e %s %s'\n" msgstr "" #: exec.c:1421 keybinds.c:1444 misc.c:1624 #, c-format msgid "%s: No pinned file\n" msgstr "" #: remotes.c:48 #, c-format msgid "%s: No remotes defined\n" msgstr "" #: bookmarks.c:678 #, c-format msgid "%s: No such ELN\n" msgstr "" #: bookmarks.c:699 bookmarks.c:780 #, c-format msgid "%s: No such bookmark\n" msgstr "" #: colors.c:496 #, c-format msgid "%s: No such color scheme\n" msgstr "" #: trash.c:122 #, c-format msgid "%s: No such file or directory\n" msgstr "" #: tags.c:455 #, c-format msgid "" "%s: No tag specified. Specify a tag via :TAG. E.g. tag FILE1 FILE2 :TAG\n" msgstr "" #: tags.c:67 #, c-format msgid "%s: No tags found, Use 'tag new' to create new tags\n" msgstr "" #: remotes.c:236 #, c-format msgid "%s: No unmount command found for '%s'\n" msgstr "" #: file_operations.c:486 name_cleaner.c:561 name_cleaner.c:611 #, c-format msgid "%s: Nothing to do\n" msgstr "" #: mime.c:531 #, c-format msgid "%s: Nothing was imported. No MIME definitions found\n" msgstr "" #: mime.c:454 #, c-format msgid "%s: Nothing was imported. No graphical environment found\n" msgstr "" #: trash.c:90 trash.c:182 trash.c:190 trash.c:210 trash.c:226 #, c-format msgid "%s: Permission denied\n" msgstr "" #: keybinds.c:96 keybinds.c:139 #, c-format msgid "%s: Restart the program for changes to take effect\n" msgstr "" #: config.c:2086 #, c-format msgid "" "%s: Running in stealth mode: trash, persistent selection and directory " "history, just as bookmarks, logs and configuration files, are disabled.\n" msgstr "" #: misc.c:1616 #, c-format msgid "%s: Succesfully pinned '%s'\n" msgstr "" #: tags.c:282 #, c-format msgid "%s: Successfully created tag\n" msgstr "" #: media.c:558 #, c-format msgid "%s: There are no available %s\n" msgstr "" #: exec.c:932 exec.c:950 #, c-format msgid "%s: There are no messages\n" msgstr "" #: exec.c:415 #, c-format msgid "%s: To gracefully quit enter 'q'\n" msgstr "" #: trash.c:797 trash.c:1085 #, c-format msgid "%s: Trash function disabled\n" msgstr "" #: misc.c:1703 #, c-format msgid "%s: Unable to find any pager\n" msgstr "" #: media.c:221 #, c-format msgid "%s: Unmounted %s\n" msgstr "" #: remotes.c:423 #, c-format msgid "%s: Unmounting remote...\n" msgstr "" #: main.c:744 #, c-format msgid "%s: Unsupported CPU architecture\n" msgstr "" #: main.c:750 #, c-format msgid "%s: Unsupported operating system\n" msgstr "" #: exec.c:2194 #, c-format msgid "%s: archiving: %s\n" msgstr "" #: exec.c:2175 #, c-format msgid "%s: bleach: %s\n" msgstr "" #: bookmarks.c:814 #, c-format msgid "%s: bookmarks: %s\n" msgstr "" #: navigation.c:444 #, c-format msgid "%s: cd: Home directory not found\n" msgstr "" #: colors.c:512 #, c-format msgid "" "%s: color schemes: %s\n" "TIP: To change the current color scheme use the following environment " "variables: CLIFM_FILE_COLORS, CLIFM_IFACE_COLORS, and CLIFM_EXT_COLORS\n" msgstr "" #: mime.c:1613 #, c-format msgid "%s: file: Command not found\n" msgstr "" #: config.c:1499 #, c-format msgid "%s: fopen: '%s': %s. Using default values.\n" msgstr "" #: checks.c:161 #, c-format msgid "%s: fzf not found. Falling back to standard TAB completion\n" msgstr "" #: init.c:1357 #, c-format msgid "%s: fzftab: %s\n" msgstr "" #: init.c:1379 #, c-format msgid "%s: fzytab: %s\n" msgstr "" #: init.c:1335 #, c-format msgid "%s: highlight: %s\n" msgstr "" #: exec.c:893 init.c:1267 #, c-format msgid "%s: icons: %s\n" msgstr "" #: jump.c:663 #, c-format msgid "%s: jump: No matches found\n" msgstr "" #: media.c:510 #, c-format msgid "%s: media: Function only available on Linux systems\n" msgstr "" #: profiles.c:315 #, c-format msgid "%s: mkdir: %s: Error creating configuration directory\n" msgstr "" #: config.c:1216 #, c-format msgid "" "%s: mkdir: '%s': Error creating configuration directory. Bookmarks, commands " "logs, and command history are disabled. Program messages won't be " "persistent. Using default options\n" msgstr "" #: config.c:1194 #, c-format msgid "" "%s: mkdir: '%s': Error creating trash directory. Trash function disabled\n" msgstr "" #: config.c:1277 #, c-format msgid "" "%s: mkdir: Error creating colors directory. Using the default color scheme\n" msgstr "" #: config.c:1289 #, c-format msgid "" "%s: mkdir: Error creating plugins directory. The actions function is " "disabled\n" msgstr "" #: init.c:1504 #, c-format msgid "" "%s: option requires an argument -- '%c'\n" "Try '%s --help' for more information.\n" msgstr "" #: selection.c:123 #, c-format msgid "%s: sel: %s: Already selected\n" msgstr "" #: selection.c:327 #, c-format msgid "%s: sel: %s: Invalid regular expression\n" msgstr "" #: trash.c:637 #, c-format msgid "%s: trash: %d: Invalid ELN\n" msgstr "" #: exec.c:1742 exec.c:1766 init.c:1290 #, c-format msgid "%s: trash: %s\n" msgstr "" #: trash.c:234 #, c-format msgid "%s: trash: %s (%s): Unsupported file type\n" msgstr "" #: trash.c:419 #, c-format msgid "" "%s: trash: %s/%s: Failed removing trash file\n" "Try removing it manually\n" msgstr "" #: trash.c:350 #, c-format msgid "%s: trash: %s: Error getting file name\n" msgstr "" #: trash.c:291 #, c-format msgid "%s: trash: %s: Error removing trashed file\n" msgstr "" #: trash.c:394 #, c-format msgid "%s: trash: %s: Failed copying file to Trash\n" msgstr "" #: trash.c:440 #, c-format msgid "%s: trash: %s: Failed encoding path\n" msgstr "" #: trash.c:615 #, c-format msgid "%s: trash: %s: Invalid ELN\n" msgstr "" #: trash.c:596 trash.c:646 #, c-format msgid "%s: trash: Error trashing %s\n" msgstr "" #: checks.c:123 #, c-format msgid "%s: udisks2 not found. Falling back to udevil\n" msgstr "" #: trash.c:933 #, c-format msgid "%s: undel: %d: Invalid ELN\n" msgstr "" #: trash.c:714 #, c-format msgid "%s: undel: %s: Error decoding original path\n" msgstr "" #: trash.c:770 #, c-format msgid "%s: undel: %s: Error removing info file\n" msgstr "" #: trash.c:777 #, c-format msgid "%s: undel: %s: Error restoring trashed file\n" msgstr "" #: trash.c:676 #, c-format msgid "" "%s: undel: Info file for '%s' not found. Try restoring the file manually\n" msgstr "" #: init.c:1525 #, c-format msgid "%s: unknown option character '\\%x'\n" msgstr "" #: init.c:1521 #, c-format msgid "" "%s: unrecognized option '%c'\n" "Try '%s --help' for more information.\n" msgstr "" #: init.c:1513 #, c-format msgid "" "%s: unrecognized option '%s'\n" "Try '%s --help' for more information.\n" msgstr "" #: bookmarks.c:609 #, c-format msgid "" "%sBookmarks Manager%s\n" "\n" msgstr "" #: bookmarks.c:208 #, c-format msgid "" "%sBookmarks%s\n" "\n" msgstr "" #: colors.c:1844 #, c-format msgid "" "%sExtension colors%s\n" "\n" msgstr "" #: colors.c:1795 #, c-format msgid "" "%sFile type colors%s\n" "\n" msgstr "" #: archives.c:1028 #, c-format msgid "%sFile%s: %s\n" msgstr "" #: media.c:526 #, c-format msgid "" "%sMountpoints%s\n" "\n" msgstr "" #: archives.c:940 #, c-format msgid "%sNOTE%s: Using Zstandard\n" msgstr "" #: selection.c:551 #, c-format msgid "%sSelection Box%s\n" msgstr "" #: trash.c:535 trash.c:862 #, c-format msgid "" "%sTrashed files%s\n" "\n" msgstr "" #: archives.c:1205 #, c-format msgid "" "%s[e]%sxtract %s[E]%sxtract-to-dir %s[l]%sist %s[m]%sount %s[r]%sepack " "%s[q]%suit\n" msgstr "" #: archives.c:321 #, c-format msgid "" "%s[e]%sxtract %s[E]%sxtract-to-dir %s[l]%sist %s[t]%sest %s[m]%sount " "%s[q]%suit\n" msgstr "" #: archives.c:757 archives.c:941 #, c-format msgid "%s[e]%sxtract %s[t]%sest %s[i]%snfo %s[q]%suit\n" msgstr "" #: selection.c:941 #, c-format msgid "%zu file(s) currently selected\n" msgstr "" #: selection.c:601 #, c-format msgid "%zu files are now in the Selection Box\n" msgstr "" #: selection.c:603 #, c-format msgid "" "%zu selected file(s):\n" "\n" msgstr "" #: search.c:634 #, c-format msgid "'%s': Invalid regular expression\n" msgstr "" #: properties.c:424 #, c-format msgid "Access: \t%s%s%s\n" msgstr "" #: bookmarks.c:292 msgid "All bookmarks succesfully removed\n" msgstr "" #: selection.c:1106 msgid "All files deselected\n" msgstr "" #: mime.c:1482 #, c-format msgid "Associated application: %s [%s]\n" msgstr "" #: mime.c:1432 msgid "Associated application: None\n" msgstr "" #: mime.c:1479 #, c-format msgid "Associated application: ad [built-in] [%s]\n" msgstr "" #: exec.c:844 #, c-format msgid "Auto-open disabled\n" msgstr "" #: exec.c:841 #, c-format msgid "Auto-open enabled\n" msgstr "" #: exec.c:846 #, c-format msgid "Auto-open is %s\n" msgstr "" #: exec.c:818 #, c-format msgid "Autocd disabled\n" msgstr "" #: exec.c:815 #, c-format msgid "Autocd enabled\n" msgstr "" #: exec.c:820 #, c-format msgid "Autocd is %s\n" msgstr "" #: properties.c:429 #, c-format msgid "Birth: \t\t%s%s%s\n" msgstr "" #: properties.c:388 #, c-format msgid "Block special file" msgstr "" #: bookmarks.c:450 msgid "Bookmark line example: [sc]name:path" msgstr "" #: bookmarks.c:217 msgid "Bookmark(s) to be deleted (ex: 1 2-6, or *): " msgstr "" #: bookmarks.c:819 #, c-format msgid "Bookmarks function disabled\n" msgstr "" #: bookmarks.c:799 #, c-format msgid "Bookmarks: %s: %s\n" msgstr "" #: properties.c:426 #, c-format msgid "Change: \t%s%s%s\n" msgstr "" #: properties.c:389 #, c-format msgid "Character special file" msgstr "" #: bookmarks.c:93 msgid "Choose a bookmark: " msgstr "" #: media.c:611 msgid "Choose a mountpoint/device: " msgstr "" #: media.c:609 media.c:613 msgid "Choose a mountpoint: " msgstr "" #: mime.c:586 msgid "Choose an application ('q' to quit): " msgstr "" #: listing.c:309 #, c-format msgid "Color scheme %s->%s %s\n" msgstr "" #: exec.c:879 msgid "Columns disabled\n" msgstr "" #: exec.c:872 msgid "Columns enabled\n" msgstr "" #: file_operations.c:1562 msgid "Continue? [y/N] " msgstr "" #: tags.c:393 #, c-format msgid "Created new tag %s%s%s\n" msgstr "" #: misc.c:396 #, c-format msgid "Current filter: %c%s\n" msgstr "" #: properties.c:414 #, c-format msgid "Device: %s%d%s" msgstr "" #: properties.c:416 #, c-format msgid "Device: %s%zu%s" msgstr "" #: properties.c:385 #, c-format msgid "Directory" msgstr "" #: selection.c:737 msgid "Empty" msgstr "" #: file_operations.c:739 msgid "End filename with a slash to create a directory" msgstr "" #: media.c:601 msgid "Enter 'iELN' for device information. Ex: i4" msgstr "" #: archives.c:1081 media.c:600 msgid "Enter 'q' to quit" msgstr "" #: file_operations.c:1716 msgid "Enter links suffix ('q' to quit): " msgstr "" #: history.c:129 msgid "Error getting command!" msgstr "" #: mime.c:344 msgid "Error opening temporary file\n" msgstr "" #: archives.c:410 archives.c:419 archives.c:523 archives.c:532 msgid "Error querying file type\n" msgstr "" #: listing.c:1670 listing.c:2218 #, c-format msgid "Excluded files: %d\n" msgstr "" #: exec.c:793 #, c-format msgid "External commands allowed\n" msgstr "" #: exec.c:789 #, c-format msgid "External commands are %s\n" msgstr "" #: exec.c:796 #, c-format msgid "External commands disallowed\n" msgstr "" #: archives.c:62 msgid "Extraction path ('q' to quit): " msgstr "" #: properties.c:390 #, c-format msgid "Fifo" msgstr "" #: archives.c:673 msgid "File name ('q' to quit): " msgstr "" #: bookmarks.c:572 #, c-format msgid "File succesfully bookmarked\n" msgstr "" #: selection.c:994 msgid "File(s) to be deselected (ex: 1 2-6, or *): " msgstr "" #: trash.c:563 msgid "File(s) to be removed (ex: 1 2-6, or *): " msgstr "" #: trash.c:881 msgid "File(s) to be undeleted (ex: 1 2-6, or *): " msgstr "" #: file_operations.c:740 msgid "Filename ('q' to quit): " msgstr "" #: exec.c:725 msgid "Files counter disabled\n" msgstr "" #: exec.c:718 msgid "Files counter enabled\n" msgstr "" #: misc.c:369 msgid "Filter unset" msgstr "" #: keybinds.c:842 #, c-format msgid "Folders first %s\n" msgstr "" #: exec.c:698 msgid "Folders first disabled\n" msgstr "" #: exec.c:694 msgid "Folders first enabled\n" msgstr "" #: exec.c:689 #, c-format msgid "Folders first is %s\n" msgstr "" #: exec.c:1803 msgid "Full directory size disabled\n" msgstr "" #: exec.c:1792 msgid "Full directory size enabled\n" msgstr "" #: exec.c:1799 msgid "Full directory size is already disabled" msgstr "" #: exec.c:1788 msgid "Full directory size is already enabled" msgstr "" #: search.c:211 msgid "Glob: No matches found. Trying regex..." msgstr "" #: keybinds.c:894 #, c-format msgid "Hidden files %s\n" msgstr "" #: exec.c:1121 msgid "Hidden files disabled\n" msgstr "" #: exec.c:1128 msgid "Hidden files enabled\n" msgstr "" #: exec.c:1113 #, c-format msgid "Hidden files is %s\n" msgstr "" #: history.c:405 #, c-format msgid "History is %s\n" msgstr "" #: archives.c:692 #, c-format msgid "Invalid file name\n" msgstr "" #: name_cleaner.c:572 msgid "Is this OK? [y/N/(e)dit] " msgstr "" #: history.c:88 #, c-format msgid "Logs %s\n" msgstr "" #: history.c:103 msgid "Logs already disabled" msgstr "" #: history.c:93 msgid "Logs already enabled" msgstr "" #: history.c:106 msgid "Logs succesfully disabled" msgstr "" #: history.c:96 msgid "Logs successfully enabled" msgstr "" #: keybinds.c:810 #, c-format msgid "Long view mode %s\n" msgstr "" #: mime.c:1472 #, c-format msgid "MIME type: %s\n" msgstr "" #: search.c:457 #, c-format msgid "Matches found: %d\n" msgstr "" #: search.c:810 #, c-format msgid "Matches found: %zu\n" msgstr "" #: exec.c:622 exec.c:634 #, c-format msgid "Max files set to %d\n" msgstr "" #: exec.c:615 msgid "Max files unset\n" msgstr "" #: exec.c:603 #, c-format msgid "Max files: %d\n" msgstr "" #: exec.c:601 msgid "Max files: unset" msgstr "" #: keybinds.c:339 #, c-format msgid "Max name length set back to %d\n" msgstr "" #: keybinds.c:337 msgid "Max name length unset\n" msgstr "" #: media.c:504 msgid "Media" msgstr "" #: properties.c:425 #, c-format msgid "Modify: \t%s%s%s\n" msgstr "" #: media.c:524 msgid "Mounted devices" msgstr "" #: media.c:504 media.c:523 msgid "Mountpoints" msgstr "" #: jump.c:313 msgid "" "NOTE 2: An asterisk next rank values means that the corresponding directory " "is bookmarked, pinned, or currently used in some workspace\n" msgstr "" #: jump.c:311 msgid "" "NOTE: First time access is displayed in days, while last time access is " "displayed in hours" msgstr "" #: mime.c:1471 remotes.c:56 #, c-format msgid "Name: %s\n" msgstr "" #: config.c:87 #, c-format msgid "New configuration file written to '%s'\n" msgstr "" #: archives.c:1085 msgid "New format (ex: .tar.xz): " msgstr "" #: file_operations.c:1068 msgid "New path ('q' to quit): " msgstr "" #: remotes.c:69 msgid "No" msgstr "" #: config.c:58 msgid "No configuration file found" msgstr "" #: tags.c:167 #, c-format msgid "No file tagged as '%s'\n" msgstr "" #: misc.c:361 msgid "No filter set" msgstr "" #: search.c:673 search.c:812 #, c-format msgid "No matches found\n" msgstr "" #: exec.c:1210 msgid "No pinned file" msgstr "" #: mime.c:1378 msgid "No such ELN" msgstr "" #: mime.c:1471 msgid "None" msgstr "" #: config.c:80 #, c-format msgid "Old configuration file stored as '%s'\n" msgstr "" #: keybinds.c:1533 #, c-format msgid "Only directories %s\n" msgstr "" #: exec.c:975 #, c-format msgid "Opener set to '%s'\n" msgstr "" #: archives.c:117 archives.c:762 archives.c:948 msgid "Operation: " msgstr "" #: jump.c:316 msgid "Order\tVisits\tFirst\tLast\tRank\tDirectory" msgstr "" #: exec.c:765 msgid "Pager disabled\n" msgstr "" #: exec.c:761 msgid "Pager enabled\n" msgstr "" #: exec.c:1208 #, c-format msgid "Pinned file: %s\n" msgstr "" #: properties.c:391 #, c-format msgid "Regular file" msgstr "" #: file_operations.c:1127 msgid "Relink as a broken symbolic link? [y/n] " msgstr "" #: properties.c:434 #, c-format msgid "Size: \t\t%s%s%s\n" msgstr "" #: properties.c:386 #, c-format msgid "Socket" msgstr "" #: listing.c:304 msgid "Sorted by: " msgstr "" #: sort.c:466 msgid "Sorting method: " msgstr "" #: misc.c:1643 #, c-format msgid "Succesfully unpinned %s\n" msgstr "" #: tags.c:656 #, c-format msgid "Successfully merged %s%s%s into %s%s%s\n" msgstr "" #: bookmarks.c:365 #, c-format msgid "Successfully removed '%s'\n" msgstr "" #: tags.c:484 #, c-format msgid "Successfully tagged %zu file(s)\n" msgstr "" #: tags.c:554 #, c-format msgid "Successfully untagged %zu file(s)\n" msgstr "" #: exec.c:991 exec.c:995 keybinds.c:870 msgid "Switched back to normal mode\n" msgstr "" #: keybinds.c:868 msgid "Switched to light mode\n" msgstr "" #: properties.c:387 #, c-format msgid "Symbolic link" msgstr "" #: exec.c:733 msgid "The files counter is disabled" msgstr "" #: exec.c:731 msgid "The files counter is enabled" msgstr "" #: exec.c:756 #, c-format msgid "The files pager is %s\n" msgstr "" #: exec.c:1188 #, c-format msgid "Toggled executable bit on %zu %s\n" msgstr "" #: exec.c:1689 #, c-format msgid "" "Total files: %zu\n" "Directories: %zu\n" "Regular files: %zu\n" "Executable files: %zu\n" "Hidden files: %zu\n" "SUID files: %zu\n" "SGID files: %zu\n" "Files w/capabilities: %zu\n" "FIFO/pipes: %zu\n" "Sockets: %zu\n" "Block devices: %zu\n" "Character devices: %zu\n" "Symbolic links: %zu\n" "Broken symbolic links: %zu\n" "Multi-link files: %zu\n" "Files w/extended attributes: %zu\n" "Other-writable files: %zu\n" "Sticky files: %zu\n" "Unknown file types: %zu\n" "Unstatable files: %zu\n" msgstr "" #: properties.c:441 msgid "Total size: \t" msgstr "" #: listing.c:1400 #, c-format msgid "" "Total size: %s%s%s\n" "Largest file: %s%s%s %c%s%s%s%c\n" msgstr "" #: mime.c:555 msgid "Try 'mm, mime edit APPLICATION'\n" msgstr "" #: exec.c:661 msgid "Unicode disabled" msgstr "" #: exec.c:658 msgid "Unicode enabled" msgstr "" #: exec.c:655 #, c-format msgid "Unicode is %s\n" msgstr "" #: archives.c:669 msgid "" "Use extension to specify archive/compression type (defaults to .tar.gz)\n" "Example: myarchive.xz" msgstr "" #: remotes.c:70 msgid "Yes" msgstr "" #: actions.c:371 msgid "actions: No actions defined. Use the 'actions edit' command to add some" msgstr "" #: exec.c:790 msgid "allowed" msgstr "" #: archives.c:713 #, c-format msgid "archiver: %s: Error dequoting file name\n" msgstr "" #: archives.c:909 #, c-format msgid "archiver: %s: Not an archive/compressed file\n" msgstr "" #: sort.c:378 #, c-format msgid "atime %s\n" msgstr "" #: bookmarks.c:200 bookmarks.c:244 #, c-format msgid "bookmarks: %s: No such bookmark\n" msgstr "" #: bookmarks.c:416 #, c-format msgid "bookmarks: %s: Path already bookmarked\n" msgstr "" #: bookmarks.c:493 #, c-format msgid "bookmarks: %s: This name is already in use\n" msgstr "" #: bookmarks.c:461 #, c-format msgid "bookmarks: %s: This shortcut is already in use\n" msgstr "" #: bookmarks.c:274 #, c-format msgid "" "bookmarks: All bookmarks were deleted\n" " However, a backup copy was created (%s)\n" msgstr "" #: bookmarks.c:279 #, c-format msgid "bookmarks: Error creating backup file. No bookmark was deleted\n" msgstr "" #: bookmarks.c:309 #, c-format msgid "bookmarks: Error creating temporary file\n" msgstr "" #: bookmarks.c:546 #, c-format msgid "bookmarks: Error generating the bookmark line\n" msgstr "" #: bookmarks.c:391 bookmarks.c:554 bookmarks.c:563 #, c-format msgid "bookmarks: Error opening the bookmarks file\n" msgstr "" #: bookmarks.c:226 #, c-format msgid "bookmarks: Error parsing input\n" msgstr "" #: bookmarks.c:162 msgid "bookmarks: There are no bookmarks" msgstr "" #: sort.c:381 #, c-format msgid "btime %s\n" msgstr "" #: sort.c:383 #, c-format msgid "btime (not available: using 'ctime') %s\n" msgstr "" #: file_operations.c:1473 #, c-format msgid "bulk: %s\n" msgstr "" #: file_operations.c:1436 #, c-format msgid "bulk: %s: Error dequoting file name\n" msgstr "" #: file_operations.c:1514 msgid "bulk: Line mismatch in renaming file\n" msgstr "" #: file_operations.c:1493 file_operations.c:1548 msgid "bulk: Nothing to do" msgstr "" #: sort.c:387 #, c-format msgid "ctime %s\n" msgstr "" #: selection.c:1053 #, c-format msgid "desel: '%s': Invalid ELN\n" msgstr "" #: selection.c:1042 #, c-format msgid "desel: '%s': Invalid entry\n" msgstr "" #: selection.c:1094 msgid "desel: There are no selected files" msgstr "" #: media.c:559 msgid "devices" msgstr "" #: exec.c:655 exec.c:690 exec.c:757 exec.c:820 exec.c:846 exec.c:1114 #: history.c:89 msgid "disabled" msgstr "" #: exec.c:655 exec.c:690 exec.c:757 exec.c:820 exec.c:846 exec.c:1114 #: history.c:88 msgid "enabled" msgstr "" #: sort.c:393 #, c-format msgid "extension %s\n" msgstr "" #: remotes.c:66 remotes.c:68 msgid "false" msgstr "" #: exec.c:1189 msgid "file" msgstr "" #: exec.c:1189 msgid "files" msgstr "" #: navigation.c:619 #, c-format msgid "history: %d: No such ELN\n" msgstr "" #: sort.c:395 #, c-format msgid "inode %s\n" msgstr "" #: media.c:559 msgid "mountpoints" msgstr "" #: media.c:561 msgid "mp: There are no available mountpoints\n" msgstr "" #: sort.c:389 #, c-format msgid "mtime %s\n" msgstr "" #: sort.c:374 #, c-format msgid "name %s\n" msgstr "" #: sort.c:372 msgid "none" msgstr "" #: exec.c:790 msgid "not allowed" msgstr "" #: sort.c:376 #, c-format msgid "size %s\n" msgstr "" #: trash.c:1028 #, c-format msgid "trash: %s: %s\n" msgstr "" #: trash.c:1034 #, c-format msgid "trash: %s: Cannot trash a %s device\n" msgstr "" #: trash.c:1016 #, c-format msgid "trash: Cannot trash '%s'\n" msgstr "" #: trash.c:541 trash.c:830 trash.c:984 msgid "trash: No trashed files" msgstr "" #: trash.c:263 msgid "trash: There are no trashed files" msgstr "" #: trash.c:1022 msgid "trash: Use 'trash del' to remove trashed files" msgstr "" #: remotes.c:66 remotes.c:68 msgid "true" msgstr "" #: trash.c:908 #, c-format msgid "undel: %s: Invalid ELN\n" msgstr "" #: properties.c:418 properties.c:420 msgid "unknown" msgstr "" #: sort.c:391 #, c-format msgid "version %s\n" msgstr ""

Vifm wiki