Code Monkey home page Code Monkey logo

cfiles's Introduction

cfiles

Latest release Arch Linux Homebrew

License

cfiles is a terminal file manager with vim like keybindings, written in C using the ncurses library. It aims to provide an interface like ranger while being lightweight, fast and minimal.

screenshot

Dependencies

  • ncursesw
  • cpand mv for copying and moving
  • fzf for searching
  • w3mimgdisplay or Überzug for image previews
  • mediainfo for viewing media info and file sizes
  • atool for archive previews
  • poppler(specifically pdftoppm) for pdf previews

Compiling and Installation

Arch Linux

Arch Linux users can use the AUR package.

macOS

macOS users can use brew or macports

Others

To compile, run

make

and then run,

sudo make install

to install.

Keybindings

Key Function
h j k l Navigation keys
G Go to end
g Go to top
H Go to top of current view
M Go to middle of current view
L Go to bottom of current view
pgup Scroll Up One Page
pgdn Scroll Down One Page
f Search using fzf
F Search using fzf in the present directory
S Open Shell in present directory
space Add/Remove to/from selection list
tab View selection list
e Edit selection list
u Empty selection list
y Copy files from selection list
v Move files from selection list
a Rename Files in selection list
dd Move files from selection list to trash
dD Remove selected files
i View mediainfo and general info
I View preview
. Toggle hidden files
b Toggle borders
' View/Goto bookmarks
m Add bookmark
E Edit bookmarks
p Run external script
r Reload
q Quit

Directories Used

cfiles uses $XDG_CONFIG_HOME/cfiles directory to store the clipboard file. This is used so that the clipboard can be shared between multiple instances of cfiles. That's why I won't be adding tabs in cfiles because multiple instances can be openend and managed by any terminal multiplexer or your window manager. Note that this also means the selection list will persist even if all instances are closed.

cfiles also uses $HOME/.local/share/Trash/files as the Trash Directory, so make sure this directory exists before you try to delete a file.

For storing bookmarks, cfiles uses $XDG_CONFIG_HOME/cfiles/bookmarks file. Bookmarks are stored in the form <key>:<path>. You can either edit this file directly or press m in cfiles to add new bookmarks.

cfiles looks for external scripts in the $XDG_CONFIG_HOME/cfiles/scripts directory. Make sure the scripts are executable before moving them to the scripts directory.

If $XDG_CONFIG_HOME is not set, then $HOME/.config is used.

Opening Files

You can set FILE_OPENER in config.h to specify your file opening program. It is set to use xdg-open by default but you can change it to anything like thunar. macOS users need to set it to open.

Image Previews

You can either go with w3mimgdisplay or Überzug (link) for image previews. Each method has it's own pros and cons.

  1. Überzug

To use Überzug for image previews, set DISPLAYIMG and CLEARIMG in config.h to the paths of displayimg_uberzug and clearimg_uberzug scripts respectively.

  • Pros
    1. Better previews when compared to w3mimgdisplay
  • Cons
    1. Can't generate previews for mp3 album arts
    2. Non functional scrolling with arrow keys

I recommend Überzug because the previews scale well with change in terminal size and don't disappear on changing workspaces.

  1. w3mimgdisplay

To use w3mimgdisplay for image previews, set DISPLAYIMG and CLEARIMG in config.h to the paths of displayimg and clearimg scripts respectively.

  • Pros
    1. Faster scrolling
    2. Can generate previews of album arts for mp3 files
  • Cons
    1. Previews are very inconsistent and may disappear on resizing the terminal or changing workspaces
    2. You may have to redraw the UI while scrolling by pressing KEY_RELOAD (defaults to R)

You may have to modify the scripts a little, about which you can read here.

Why C?

I wanted to improve my C and learn ncurses so I decided this would be an ideal project.

Apart from this, I have always wanted an alternative to ranger that is faster while still having a similar UI.

cfiles's People

Contributors

jagmeethanspal avatar mistralol avatar stephenp-al avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

cfiles's Issues

Feature request: PDF preview

It would be great if PDF preview could be added in. I liked to use ranger to skim through my documents folder (stuffed with PDFs), and I'd like to do the same with cfiles.

I've sort of got this working in a hack-y way: changing the displayimg script to check for PDFs and convert to jpg for preview using ghostscript. This means that text preview would not work if ghostscript is not available.

PDFPREV=/tmp/pdf_thumb.jpg

IMGEXT="${FILENAME##*.}"

case $IMGEXT in
  pdf|PDF)
    command -v gs &> /dev/null || exit 1
    gs -dNOPAUSE -dBATCH -sDEVICE=jpeg -sOoutputFile=$PDFPREV -dLastPage=1 "$FILENAME" &>/dev/null
    FILENAME=$PDFPREV
    ;;
esac

I dunno if there's a better way?

There are two unnecessary duplicated lines in Makefile

Hi!
Thank you for the cfile utility!

Two additional install invocations with the same args.
Here is the patch:

diff --git a/Makefile b/Makefile
index 0e565f8..a0dba6e 100644
--- a/Makefile
+++ b/Makefile
@@ -22,8 +22,6 @@ install:
 	install -Dm 755 scripts/displayimg $(DEST)/displayimg
 	install -Dm 755 scripts/displayimg_uberzug $(DEST)/displayimg_uberzug
 	install -Dm 755 scripts/clearimg_uberzug $(DEST)/clearimg_uberzug
-	install -Dm 755 scripts/clearimg_uberzug $(DEST)/clearimg_uberzug
-	install -Dm 755 scripts/clearimg_uberzug $(DEST)/clearimg_uberzug
 	install -Dm 644 LICENSE /usr/share/licenses/$(PROG)/LICENSE
 	install -Dm 644 cfiles.1 /usr/local/man/man1/cfiles.1

Hope this helps. :-)

enhancement: remove bookmark shortcut

If I am not mistaken deleting a bookmark is currently performed by deleting it from $XDG_CACHE_HOME/cfiles/bookmarks. However on my system echo $XDG_CACHE_HOME returns nothing. I am also unable to determine where the bookmark info is stored in such case. fzf -e -q cfiles or fzf -e -q bookmarks doesn't return anything that would catch my eye.
I've read through the cf.c code but my C knowledge is too limited to figure out the alternative location.

Due to this difficulty, but mostly because I think that it would make for a better user experience, I suggest adding a possibility to remove unwanted bookmarks directly from cfiles.
In Vim it's done via its command line, which is not how cfiles operates, so I think it will have to function similarly to adding a bookmark, i.e. <KEY_DELBOOKMARK><BOOKMARK> .

Screenshot

Not hugely important, but do you think it may be possible to do another screenshot? Ideally one where the windows could be side by side, and perhaps a black background (to avoid distraction from the application at hand). Again, not hugely important, so feel free to close this issue at any time - I just felt that it may be better to focus on the application itself as such. (It is comparable to screenshots of e. g. midnight commander or htop, if you ask me).

Otherwise nice job - ncurses can be very annoying to have to deal with.

Archive preview

Currently only .zip, .rar, .cbr, .cbz archives are displayed:

cfiles/cf.c

Lines 1291 to 1292 in 33f9c0a

else if(strcasecmp("zip",last) == 0 || strcasecmp("rar",last) == 0 || strcasecmp("cbr",last) == 0 || strcasecmp("cbz",last) == 0)
getArchivePreview(filepath, maxy, maxx);

Could you please add preview support for .tar.bz2, .tar.gz, .tar.xz, etc?

Image preview loads slow compared to ranger

Hi. I like cfiles. Thx. Generally the image preview is better then in ranger because it works nice with tmux. The images are always on the right place and do not disappear when changing panes. However, the images load notably slower in cfiles than in ranger. Since cfiles goal is to be fast I think this is something that should be fixed. Also it bothers me when I scroll through many images.

Code execution

The issue

There are arbitrary code execution vulnerabilities due to unproper handling of filenames.
If a filename contains a shell command it will be executed when the file is opened.

How to reproduce

Create a file with a shell command, here a command that creates another file:

$ touch '; touch test'

Navigate that directory with cfiles and try to open the file. The command will be executed.

The bug

In openFiles a string containing a shell command is built from the filename before being executed with system(). Since filenames may contain shell commands that are not escaped this results in code execution.

The risk

If user A tries to open a file created by user B that contains a shell command it will be executed by user A's rights. This is a form of privilege escalation.

Other locations

There are multiple other places where system() is used in an unsafe way. All of them appear vulnerable one way or another. Also popen() is another function that should be used with care.

The fix

  • Avoid system() whenever possible, use execl or execve instead (see https://wiki.sei.cmu.edu/confluence/pages/viewpage.action?pageId=87152177 for example). They are more secure since your are not building a string, your are passing a list of arguments to the process directly.

  • If you still want to build a string be sure to escape all arguments, so you should force single quotes and escape any single quote in the argument. Warning though, escaping is a good thing but it's hard to do right.

TODO

Todo

  • Improve Upwards Scrolling
  • Show sorted directories before files
  • Fix the G keybinding
  • Add basic operations like deleting, copying etc.
  • Add rename functionality
  • Add option to show selection list
  • Show current progress or status of copying files
  • Add functionality to open files
  • Add image previews using w3mimgdisplay
  • Preserve aspect ratio in image previews
  • Add fuzzy file search using fzf
  • Find a way to redraw windows after displaying image previews or running fzf
  • Find a way to remove cursor after running fzf
  • Select the file directly from fzf
  • Supress output from xdg-open
  • Find a way to remember selection position of parent directory
  • Add open in terminal functionality
  • Add file previews
  • Improve file previews
  • Add config file for easy user customizability
  • Add more options in config file
  • Fix random segfaults
  • Show more info in the statusbar
  • Add color support
  • Add bookmarks
  • Add ability to run external scripts
  • Remove hardcoded paths
  • Use dynamic allocation wherever static arrays are used
  • Update README section about Image previews and add about Uberzug
  • Replace system() by safer functions
  • Add build system (autotools)
  • Refactor Code

Extra Features

None planned for now. You can suggest new features by opening a new issue with enhancement ;abel

Use SHELL env variable instead of hardcoding bash

Hello,

I noticed that when I use the key mapping S to open a shell session, cfiles opens a bash shell instead of my default shell, zsh.

I suggest we change this to use the SHELL environment variable instead. Thanks!

Memory leak

Leak of temp_dir

// Line 1300
// Print all the elements and highlight the selection
int t = 0;
for( i=start; i<len; i++ )
{
    allocSize = snprintf(NULL,0,"%s/%s",dir,directories[i]);
    // Here temp_dir is not freed ; memory leak
    temp_dir = malloc(allocSize + 1);
    snprintf(temp_dir,allocSize+1,"%s/%s",dir,directories[i]);

Fix

Free its memory before reuse.

Heap read overflow

Issue

If fzf is not present on the system or returns nothing (example, calling fzf in an empty directory and hitting enter) then there is a read buffer overflow on the heap.

How to reproduce

The easiest is to hit f to start fzf then enter the name of a file that doesn't exist and hit enter.

Details

The overflow happens line 1784 (rev 276a3ef) in the snprintf statement:

fp = fopen(temp_dir, "r");
while(fgets(buf,PATH_MAX,fp) != NULL){}
fclose(fp);

// Allocate Memory to `path` to store path selected file
allocSize = snprintf(NULL,0,"%s/%s",dir,buf);

If fzf didn't return anything the file is empty, therefore nothing will be written to buf, not even a NUL char. Then when snprintf reads buf to determine its length it will read outside the buffer since it stops at the first NUL char: read overflow.

Fix

Check fread's output to determine how many characters were read and NUL terminate buf. Alternatively memset(buf, '\0', PATH_MAX); just after allocating buf might be an easier solution and should ensure that the output is always NUL-terminated.

pdf previews are broken

This line:

execlp("/usr/local/bin/pdftoppm","/usr/local/bin/pdftoppm","-l","1","-jpeg",filepath,"-singlefile", "/tmp/prev", (char *)NULL);

translates into this command:

/usr/local/bin/pdftoppm x.pdf -l 1 -jpeg . -singlefile /tmp/prev

which fails and shows the usage message:

Usage: pdftoppm [options] [PDF-file [PPM-file-prefix]]

$ which  /usr/local/bin/pdftoppm 
/usr/local/bin/pdftoppm
$ pkg which /usr/local/bin/pdftoppm
/usr/local/bin/pdftoppm was installed by package poppler-utils-0.77.0

sudo support?

Could you please add exec command like y, v in administer?

Can't preview image.

OS: Manjaro.

I install cfiles from AUR.

hmank ~/Pictures » pqs python-ueberzug-git           
local/python-ueberzug-git 18.1.5.a8ac9c3-1
    ueberzug is an python script which aims to replace w3mimgdisplay
hmank ~/Pictures » pqs cfiles             
local/cfiles 1.8-2
    A ncurses file manager written in C

image

But the preview of image not work.

Use XDG paths

For things like ~/.cache you should use $XDG_CACHE_HOME there is $XDG_CONFIG_HOME etc for different paths you could be using.

cfiles preview bash script get hex code.

As xdg-mime output application for bash script and tar file,

hmank ~/./y/cfiles master > touch tt.sh && xdg-mime query filetype tt.sh
application/x-shellscript
hmank ~/./y/cfiles master > xdg-mime query filetype tt.py
text/x-python
hmank ~/./y/cfiles master > touch tt.tar.xz && xdg-mime query filetype tt.tar.xz
application/x-xz-compressed-tar

Maybe should use application/x-executable and application/x-sharedlib to check whether file is a binary?

hmank ~/./y/cfiles master > xdg-mime query filetype /usr/bin/zsh
application/x-sharedlib
hmank ~/./y/cfiles master > xdg-mime query filetype /usr/bin/firefox
application/x-shellscript
hmank ~/./y/cfiles master > 

Multiple memory corruption bugs

tl;dr: you should protect against buffer overflows.

How to reproduce

Create a filename with length 255 characters then navigate that directory. The program will segfault.

Analysis of the issue

I didn't try to pinpoint the exact location of this bug, but the code is written in an unsafe style. Setting arbitrary length of buffers to hold file and directory names is dangerous since a user can use longer filenames.

Also, copying to these buffers without verifying that they fit isn't safe: it ends up writting past the end of the buffer, causing buffer overflows. At best it just doesn't work and the user is forced to use another program, at worst it's a security issue. For example if user A visits a directory with a file created by user B then user B can crash user A's cfiles in a specific way to get code execution, thereby taking over account A.

Recommendations

  • Decide of buffer lengths dynamically depending on the file you find by checking its properties so that it's always at the right size. Don't forget to free them once and only once.

  • If you decide to use static buffers, choose their length by looking at the filesystem max filename length, not guessing. Warning, a user routinely uses different types of filesystems even in normal linux usage.

  • Use strscpy in order to avoid writting too much to the buffer. If the filename is longer than the buffer, either extend the buffer or deal with the filename one part after the other.

don't hardcode path's

It would be nice to not hardcode path's in cf.c and let the users path do the work. At the very least make paths configurable, because most of these locations are different for us BSD users.

Memory corruption

Issue

There is an out-of-bound read from the directories buffer line 1330 (rev adf61b2).

Analysis

// Line 1253
len = getNumberofFiles(dir);                  // If len == 0

// Set temp_len to 1 if `len` is less than 0
if(len <= 0)
    temp_len = 1;
else
    temp_len = len;

// ...
// Line 1284
if(selection > len-1)                         // If selection==0, >(0-1) is true
{
    selection = len-1;                        // selection = -1;
}

// ...
// Line 1330
// Copy of directories[-1] into selected_files. That read is out of bound.
snprintf(selected_file,NAME_MAX,"%s",directories[selection]);

Local fix

Do not set selection to -1.

Global fix

  • Avoid using global variables
  • As soon as the length is known invalid, stop using it and return

Wrong allocation leads to memory corruption

Issue

The function getNumberOfFiles is used in a number of places to know how much memory should be allocated. However its return value is never checked (or incorrectly) leading to wrong memory allocations and therefore memory corruptions.

Bugs

getNumberOfFiles is defined to return -1 if opendir fails (for example due to a permission issue).

(following lines are based on 9be9889)

Line 1132:

        // Get number of files in the home directory
        len = getNumberofFiles(dir);

        // Array of all the files in the current directory
        char* directories[len];

If len is -1 then the stack allocation messes the stack up. Variable Length Array (VLA) must always have a length strictly greater than 0, otherwise you have undefined behaviour.

Line 1211:

        // Stores number of files in the child directory
        len_preview = getNumberofFiles(next_dir);
        // Stores files in the child directory
        char** next_directories;
        next_directories = (char **)malloc(len_preview * sizeof(char *));

Here we have a similar issue: len_preview may be -1. In that case it is promoted to an unsigned number (size_t) resulting in the allocation of 4294967295 bytes which is a huge value. This should not result directly in a crash since Linux "lies" to the process by making the promise to give it all that space without actually reserving it, but it is definitely a bug.

Line 1674

        len_scripts = getNumberofFiles(scripts_path);
        if(len_scripts == 0)
        {
            displayAlert("No scripts found!");
            sleep(1);
        }
        else
        {
            char* scripts[len_scripts];

Here the output value is checked but that check misses the error value resulting in a negative VLA stack allocation which is undefined behaviour.

Solution

Always check return values especially if they are meant to indicate errors.

Alternatively avoid VLA as much as possible, they should not be used for large allocations anyway.

Please use $XDG_CONFIG_HOME for scripts and bookmarks

cfiles is a great little tool, just one thing disturbes me (at the moment):
you use the $XDG_CACHE_HOME for storing bookmarks and scripts.
Cache is normally only temporarily, so on my system:
$XDG_CACHE_HOME is mounted "tmpfs" in ram to speed up some things and conserve sdd usage.
Is it possible to move bookmarks and scripts to
$XDG_CONFIG_HOME, eg ~/.config/cfiles ?
Thanks a lot,
Fliggs

Bookmark injection

The issue

It is possible to inject bookmarks without the user explicitely asking to add the bookmark.

How to reproduce

Create a filename such as test\na:/tmp/other. Since the new line character is valid in filenames on most filesystems (such as ext4) this results in two bookmarks being added at once.

The risk

Not much really, adding bookmarks doesn't seem very critical. Still, it can be annoying. One point though is that it can be stealthy by adding ANSI codes to the filename to hide any suspicious part of the filename.

The fix

Escape new line characters, by encoding them for example.

Trouble building on Ubuntu 18.10

Tried building on Ubuntu 18.10 64 bit

$ ./build.sh 
-- The C compiler identification is GNU 8.2.0
-- The CXX compiler identification is GNU 8.2.0
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Found PkgConfig: /usr/bin/pkg-config (found version "0.29.1") 
-- Checking for one of the modules 'ncurses'
-- Configuring done
-- Generating done
-- Build files have been written to: /home/stu/projects/external/cfiles
[1/2] Building C object CMakeFiles/cfiles.dir/cf.c.o
cf.c:131:6: warning: no previous declaration for ‘init’ [-Wmissing-declarations]
 void init()
      ^~~~
cf.c:168:6: warning: no previous declaration for ‘curses_init’ [-Wmissing-declarations]
 void curses_init()
      ^~~~~~~~~~~
cf.c:184:5: warning: no previous declaration for ‘is_regular_file’ [-Wmissing-declarations]
 int is_regular_file(const char *path)
     ^~~~~~~~~~~~~~~
cf.c:195:5: warning: no previous declaration for ‘fileExists’ [-Wmissing-declarations]
 int fileExists(char *file)
     ^~~~~~~~~~
cf.c:207:6: warning: no previous declaration for ‘getLastToken’ [-Wmissing-declarations]
 void getLastToken(char *tokenizer)
      ^~~~~~~~~~~~
cf.c:221:5: warning: no previous declaration for ‘getNumberOfBookmarks’ [-Wmissing-declarations]
 int getNumberOfBookmarks()
     ^~~~~~~~~~~~~~~~~~~~
cf.c:242:6: warning: no previous declaration for ‘displayBookmarks’ [-Wmissing-declarations]
 void displayBookmarks()
      ^~~~~~~~~~~~~~~~
cf.c:261:6: warning: no previous declaration for ‘openBookmarkDir’ [-Wmissing-declarations]
 void openBookmarkDir(char secondKey)
      ^~~~~~~~~~~~~~~
cf.c:285:5: warning: no previous declaration for ‘bookmarkExists’ [-Wmissing-declarations]
 int bookmarkExists(char bookmark)
     ^~~~~~~~~~~~~~
cf.c:309:6: warning: no previous declaration for ‘addBookmark’ [-Wmissing-declarations]
 void addBookmark(char bookmark, char *path)
      ^~~~~~~~~~~
cf.c:320:9: warning: no previous declaration for ‘create_newwin’ [-Wmissing-declarations]
 WINDOW *create_newwin(int height, int width, int starty, int startx)
         ^~~~~~~~~~~~~
cf.c: In function ‘create_newwin’:
cf.c:320:50: warning: declaration of ‘starty’ shadows a global declaration [-Wshadow]
 WINDOW *create_newwin(int height, int width, int starty, int startx)
                                              ~~~~^~~~~~
cf.c:120:13: note: shadowed declaration is here
 int startx, starty, maxx, maxy;
             ^~~~~~
cf.c:320:62: warning: declaration of ‘startx’ shadows a global declaration [-Wshadow]
 WINDOW *create_newwin(int height, int width, int starty, int startx)
                                                          ~~~~^~~~~~
cf.c:120:5: note: shadowed declaration is here
 int startx, starty, maxx, maxy;
     ^~~~~~
cf.c: At top level:
cf.c:331:5: warning: no previous declaration for ‘compare’ [-Wmissing-declarations]
 int compare (const void * a, const void * b )
     ^~~~~~~
cf.c:353:6: warning: no previous declaration for ‘getMIME’ [-Wmissing-declarations]
 void getMIME(char *filepath, char mime[10])
      ^~~~~~~
cf.c:373:6: warning: no previous declaration for ‘openFile’ [-Wmissing-declarations]
 void openFile(char *filepath)
      ^~~~~~~~
cf.c:398:5: warning: no previous declaration for ‘checkClipboard’ [-Wmissing-declarations]
 int checkClipboard(char *filepath)
     ^~~~~~~~~~~~~~
cf.c:423:6: warning: no previous declaration for ‘writeClipboard’ [-Wmissing-declarations]
 void writeClipboard(char *filepath)
      ^~~~~~~~~~~~~~
cf.c:440:6: warning: no previous declaration for ‘removeClipboard’ [-Wmissing-declarations]
 void removeClipboard(char *filepath)
      ^~~~~~~~~~~~~~~
cf.c:452:6: warning: no previous declaration for ‘emptyClipboard’ [-Wmissing-declarations]
 void emptyClipboard()
      ^~~~~~~~~~~~~~
cf.c:464:6: warning: no previous declaration for ‘getImgPreview’ [-Wmissing-declarations]
 void getImgPreview(char *filepath, int maxy, int maxx)
      ^~~~~~~~~~~~~
cf.c: In function ‘getImgPreview’:
cf.c:464:40: warning: declaration of ‘maxy’ shadows a global declaration [-Wshadow]
 void getImgPreview(char *filepath, int maxy, int maxx)
                                    ~~~~^~~~
cf.c:120:27: note: shadowed declaration is here
 int startx, starty, maxx, maxy;
                           ^~~~
cf.c:464:50: warning: declaration of ‘maxx’ shadows a global declaration [-Wshadow]
 void getImgPreview(char *filepath, int maxy, int maxx)
                                              ~~~~^~~~
cf.c:120:21: note: shadowed declaration is here
 int startx, starty, maxx, maxy;
                     ^~~~
cf.c: At top level:
cf.c:519:6: warning: no previous declaration for ‘getTextPreview’ [-Wmissing-declarations]
 void getTextPreview(char *filepath, int maxy, int maxx)
      ^~~~~~~~~~~~~~
cf.c: In function ‘getTextPreview’:
cf.c:519:41: warning: declaration of ‘maxy’ shadows a global declaration [-Wshadow]
 void getTextPreview(char *filepath, int maxy, int maxx)
                                     ~~~~^~~~
cf.c:120:27: note: shadowed declaration is here
 int startx, starty, maxx, maxy;
                           ^~~~
cf.c:519:51: warning: declaration of ‘maxx’ shadows a global declaration [-Wshadow]
 void getTextPreview(char *filepath, int maxy, int maxx)
                                               ~~~~^~~~
cf.c:120:21: note: shadowed declaration is here
 int startx, starty, maxx, maxy;
                     ^~~~
cf.c: At top level:
cf.c:546:6: warning: no previous declaration for ‘getVidPreview’ [-Wmissing-declarations]
 void getVidPreview(char *filepath, int maxy, int maxx)
      ^~~~~~~~~~~~~
cf.c: In function ‘getVidPreview’:
cf.c:546:40: warning: declaration of ‘maxy’ shadows a global declaration [-Wshadow]
 void getVidPreview(char *filepath, int maxy, int maxx)
                                    ~~~~^~~~
cf.c:120:27: note: shadowed declaration is here
 int startx, starty, maxx, maxy;
                           ^~~~
cf.c:546:50: warning: declaration of ‘maxx’ shadows a global declaration [-Wshadow]
 void getVidPreview(char *filepath, int maxy, int maxx)
                                              ~~~~^~~~
cf.c:120:21: note: shadowed declaration is here
 int startx, starty, maxx, maxy;
                     ^~~~
cf.c: At top level:
cf.c:562:6: warning: no previous declaration for ‘getArchivePreview’ [-Wmissing-declarations]
 void getArchivePreview(char *filepath, int maxy, int maxx)
      ^~~~~~~~~~~~~~~~~
cf.c: In function ‘getArchivePreview’:
cf.c:562:44: warning: declaration of ‘maxy’ shadows a global declaration [-Wshadow]
 void getArchivePreview(char *filepath, int maxy, int maxx)
                                        ~~~~^~~~
cf.c:120:27: note: shadowed declaration is here
 int startx, starty, maxx, maxy;
                           ^~~~
cf.c:562:54: warning: declaration of ‘maxx’ shadows a global declaration [-Wshadow]
 void getArchivePreview(char *filepath, int maxy, int maxx)
                                                  ~~~~^~~~
cf.c:120:21: note: shadowed declaration is here
 int startx, starty, maxx, maxy;
                     ^~~~
cf.c:564:10: warning: unused variable ‘buf’ [-Wunused-variable]
     char buf[250];
          ^~~
cf.c: At top level:
cf.c:575:6: warning: no previous declaration for ‘getDummyVidPreview’ [-Wmissing-declarations]
 void getDummyVidPreview(char *filepath, int maxy, int maxx)
      ^~~~~~~~~~~~~~~~~~
cf.c: In function ‘getDummyVidPreview’:
cf.c:575:45: warning: declaration of ‘maxy’ shadows a global declaration [-Wshadow]
 void getDummyVidPreview(char *filepath, int maxy, int maxx)
                                         ~~~~^~~~
cf.c:120:27: note: shadowed declaration is here
 int startx, starty, maxx, maxy;
                           ^~~~
cf.c:575:55: warning: declaration of ‘maxx’ shadows a global declaration [-Wshadow]
 void getDummyVidPreview(char *filepath, int maxy, int maxx)
                                                   ~~~~^~~~
cf.c:120:21: note: shadowed declaration is here
 int startx, starty, maxx, maxy;
                     ^~~~
cf.c: At top level:
cf.c:586:6: warning: no previous declaration for ‘getFileType’ [-Wmissing-declarations]
 void getFileType(char *filepath)
      ^~~~~~~~~~~
cf.c: In function ‘getFileType’:
cf.c:589:18: warning: passing argument 1 of ‘getLastToken’ discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers]
     getLastToken(".");
                  ^~~
cf.c:207:25: note: expected ‘char *’ but argument is of type ‘const char *’
 void getLastToken(char *tokenizer)
                   ~~~~~~^~~~~~~~~
cf.c: At top level:
cf.c:596:6: warning: no previous declaration for ‘getPreview’ [-Wmissing-declarations]
 void getPreview(char *filepath, int maxy, int maxx)
      ^~~~~~~~~~
cf.c: In function ‘getPreview’:
cf.c:596:37: warning: declaration of ‘maxy’ shadows a global declaration [-Wshadow]
 void getPreview(char *filepath, int maxy, int maxx)
                                 ~~~~^~~~
cf.c:120:27: note: shadowed declaration is here
 int startx, starty, maxx, maxy;
                           ^~~~
cf.c:596:47: warning: declaration of ‘maxx’ shadows a global declaration [-Wshadow]
 void getPreview(char *filepath, int maxy, int maxx)
                                           ~~~~^~~~
cf.c:120:21: note: shadowed declaration is here
 int startx, starty, maxx, maxy;
                     ^~~~
cf.c: At top level:
cf.c:616:6: warning: no previous declaration for ‘getParentPath’ [-Wmissing-declarations]
 void getParentPath(char *path)
      ^~~~~~~~~~~~~
cf.c:633:5: warning: no previous declaration for ‘getNumberofFiles’ [-Wmissing-declarations]
 int getNumberofFiles(char* directory)
     ^~~~~~~~~~~~~~~~
cf.c: In function ‘getNumberofFiles’:
cf.c:635:9: warning: declaration of ‘len’ shadows a global declaration [-Wshadow]
     int len=0;
         ^~~
cf.c:32:5: note: shadowed declaration is here
 int len=0;
     ^~~
cf.c: At top level:
cf.c:662:5: warning: no previous declaration for ‘getFiles’ [-Wmissing-declarations]
 int getFiles(char* directory, char* target[])
     ^~~~~~~~
cf.c: In function ‘getFiles’:
cf.c:664:9: warning: declaration of ‘i’ shadows a global declaration [-Wshadow]
     int i = 0;
         ^
cf.c:44:5: note: shadowed declaration is here
 int i = 0;
     ^
cf.c: At top level:
cf.c:692:6: warning: no previous declaration for ‘copyFiles’ [-Wmissing-declarations]
 void copyFiles(char *present_dir)
      ^~~~~~~~~
cf.c: In function ‘copyFiles’:
cf.c:697:9: warning: unused variable ‘status’ [-Wunused-variable]
     int status;
         ^~~~~~
cf.c:696:11: warning: unused variable ‘pid’ [-Wunused-variable]
     pid_t pid;
           ^~~
cf.c: At top level:
cf.c:716:6: warning: no previous declaration for ‘removeFiles’ [-Wmissing-declarations]
 void removeFiles()
      ^~~~~~~~~~~
cf.c:740:6: warning: no previous declaration for ‘renameFiles’ [-Wmissing-declarations]
 void renameFiles()
      ^~~~~~~~~~~
cf.c:798:6: warning: no previous declaration for ‘moveFiles’ [-Wmissing-declarations]
 void moveFiles(char *present_dir)
      ^~~~~~~~~
cf.c: In function ‘moveFiles’:
cf.c:802:9: warning: unused variable ‘status’ [-Wunused-variable]
     int status;
         ^~~~~~
cf.c: At top level:
cf.c:823:6: warning: no previous declaration for ‘init_windows’ [-Wmissing-declarations]
 void init_windows()
      ^~~~~~~~~~~~
cf.c:834:6: warning: no previous declaration for ‘displayStatus’ [-Wmissing-declarations]
 void displayStatus()
      ^~~~~~~~~~~~~
cf.c:851:6: warning: no previous declaration for ‘displayAlert’ [-Wmissing-declarations]
 void displayAlert(char *message)
      ^~~~~~~~~~~~
cf.c:863:6: warning: no previous declaration for ‘refreshWindows’ [-Wmissing-declarations]
 void refreshWindows()
      ^~~~~~~~~~~~~~
cf.c:878:6: warning: no previous declaration for ‘handleFlags’ [-Wmissing-declarations]
 void handleFlags(char** directories)
      ^~~~~~~~~~~
cf.c: In function ‘main’:
cf.c:1134:30: warning: passing argument 1 of ‘getLastToken’ discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers]
                 getLastToken("/");
                              ^~~
cf.c:207:25: note: expected ‘char *’ but argument is of type ‘const char *’
 void getLastToken(char *tokenizer)
                   ~~~~~~^~~~~~~~~
cf.c:1187:30: warning: passing argument 1 of ‘getLastToken’ discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers]
                 getLastToken("/");
                              ^~~
cf.c:207:25: note: expected ‘char *’ but argument is of type ‘const char *’
 void getLastToken(char *tokenizer)
                   ~~~~~~^~~~~~~~~
cf.c:1210:30: warning: passing argument 1 of ‘getLastToken’ discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers]
                 getLastToken("/");
                              ^~~
cf.c:207:25: note: expected ‘char *’ but argument is of type ‘const char *’
 void getLastToken(char *tokenizer)
                   ~~~~~~^~~~~~~~~
cf.c:1278:38: warning: passing argument 1 of ‘displayAlert’ discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers]
                         displayAlert("Confirm (y/n): ");
                                      ^~~~~~~~~~~~~~~~~
cf.c:851:25: note: expected ‘char *’ but argument is of type ‘const char *’
 void displayAlert(char *message)
                   ~~~~~~^~~~~~~
cf.c:1284:42: warning: passing argument 1 of ‘displayAlert’ discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers]
                             displayAlert("ABORTED");
                                          ^~~~~~~~~
cf.c:851:25: note: expected ‘char *’ but argument is of type ‘const char *’
 void displayAlert(char *message)
                   ~~~~~~^~~~~~~
cf.c:1291:34: warning: passing argument 1 of ‘displayAlert’ discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers]
                     displayAlert("Select some files first!");
                                  ^~~~~~~~~~~~~~~~~~~~~~~~~~
cf.c:851:25: note: expected ‘char *’ but argument is of type ‘const char *’
 void displayAlert(char *message)
                   ~~~~~~^~~~~~~
cf.c:1301:34: warning: passing argument 1 of ‘displayAlert’ discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers]
                     displayAlert("No Bookmarks Found!");
                                  ^~~~~~~~~~~~~~~~~~~~~
cf.c:851:25: note: expected ‘char *’ but argument is of type ‘const char *’
 void displayAlert(char *message)
                   ~~~~~~^~~~~~~
cf.c:1316:30: warning: passing argument 1 of ‘displayAlert’ discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers]
                 displayAlert("Enter Bookmark Key");
                              ^~~~~~~~~~~~~~~~~~~~
cf.c:851:25: note: expected ‘char *’ but argument is of type ‘const char *’
 void displayAlert(char *message)
                   ~~~~~~^~~~~~~
cf.c:1320:34: warning: passing argument 1 of ‘displayAlert’ discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers]
                     displayAlert("Bookmark Key Exists!");
                                  ^~~~~~~~~~~~~~~~~~~~~~
cf.c:851:25: note: expected ‘char *’ but argument is of type ‘const char *’
 void displayAlert(char *message)
                   ~~~~~~^~~~~~~
cf.c:1340:34: warning: passing argument 1 of ‘displayAlert’ discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers]
                     displayAlert("Selection List is Empty!");
                                  ^~~~~~~~~~~~~~~~~~~~~~~~~~
cf.c:851:25: note: expected ‘char *’ but argument is of type ‘const char *’
 void displayAlert(char *message)
                   ~~~~~~^~~~~~~
cf.c:1356:34: warning: passing argument 1 of ‘displayAlert’ discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers]
                     displayAlert("Selection List is Empty!");
                                  ^~~~~~~~~~~~~~~~~~~~~~~~~~
cf.c:851:25: note: expected ‘char *’ but argument is of type ‘const char *’
 void displayAlert(char *message)
                   ~~~~~~^~~~~~~
cf.c:1381:34: warning: passing argument 1 of ‘displayAlert’ discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers]
                     displayAlert("No scripts found!");
                                  ^~~~~~~~~~~~~~~~~~~
cf.c:851:25: note: expected ‘char *’ but argument is of type ‘const char *’
 void displayAlert(char *message)
                   ~~~~~~^~~~~~~
cf.c:1399:30: warning: declaration of ‘cmd’ shadows a previous local [-Wshadow]
                         char cmd[250];
                              ^~~
cf.c:1064:14: note: shadowed declaration is here
         char cmd[250];
              ^~~
cf.c:1400:30: warning: declaration of ‘path’ shadows a previous local [-Wshadow]
                         char path[250];
                              ^~~~
cf.c:1182:22: note: shadowed declaration is here
                 char path[250];
                      ^~~~
cf.c:950:13: warning: variable ‘status’ set but not used [-Wunused-but-set-variable]
         int status;
             ^~~~~~
cf.c: In function ‘init’:
cf.c:146:31: warning: ‘/clipboard’ directive writing 10 bytes into a region of size between 1 and 250 [-Wformat-overflow=]
     sprintf(clipboard_path,"%s/clipboard",cache_path);
                               ^~~~~~~~~~
cf.c:146:5: note: ‘sprintf’ output between 11 and 260 bytes into a destination of size 250
     sprintf(clipboard_path,"%s/clipboard",cache_path);
     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
cf.c:148:31: warning: ‘/bookmarks’ directive writing 10 bytes into a region of size between 1 and 250 [-Wformat-overflow=]
     sprintf(bookmarks_path,"%s/bookmarks",cache_path);
                               ^~~~~~~~~~
cf.c:148:5: note: ‘sprintf’ output between 11 and 260 bytes into a destination of size 250
     sprintf(bookmarks_path,"%s/bookmarks",cache_path);
     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
cf.c:150:29: warning: ‘/scripts’ directive writing 8 bytes into a region of size between 1 and 250 [-Wformat-overflow=]
     sprintf(scripts_path,"%s/scripts",cache_path);
                             ^~~~~~~~
cf.c:150:5: note: ‘sprintf’ output between 9 and 258 bytes into a destination of size 250
     sprintf(scripts_path,"%s/scripts",cache_path);
     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
cf.c:152:36: warning: ‘/clipboard.tmp’ directive writing 14 bytes into a region of size between 1 and 250 [-Wformat-overflow=]
     sprintf(temp_clipboard_path,"%s/clipboard.tmp",cache_path);
                                    ^~~~~~~~~~~~~~
cf.c:152:5: note: ‘sprintf’ output between 15 and 264 bytes into a destination of size 250
     sprintf(temp_clipboard_path,"%s/clipboard.tmp",cache_path);
     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
cf.c: In function ‘compare’:
cf.c:338:34: warning: ‘sprintf’ may write a terminating nul past the end of the destination [-Wformat-overflow=]
     sprintf(temp_filepath1,"%s/%s", sort_dir, *(char **)a);
                                  ^
cf.c:338:5: note: ‘sprintf’ output 2 or more bytes (assuming 251) into a destination of size 250
     sprintf(temp_filepath1,"%s/%s", sort_dir, *(char **)a);
     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
cf.c:339:34: warning: ‘sprintf’ may write a terminating nul past the end of the destination [-Wformat-overflow=]
     sprintf(temp_filepath2,"%s/%s", sort_dir, *(char **)b);
                                  ^
cf.c:339:5: note: ‘sprintf’ output 2 or more bytes (assuming 251) into a destination of size 250
     sprintf(temp_filepath2,"%s/%s", sort_dir, *(char **)b);
     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
cf.c: In function ‘removeClipboard’:
cf.c:444:36: warning: ‘%s’ directive writing up to 249 bytes into a region of size 235 [-Wformat-overflow=]
     sprintf(cmd,"sed -i '\\|^%s|d' %s", filepath, clipboard_path);
                                    ^~             ~~~~~~~~~~~~~~
cf.c:444:5: note: ‘sprintf’ output 16 or more bytes (assuming 265) into a destination of size 250
     sprintf(cmd,"sed -i '\\|^%s|d' %s", filepath, clipboard_path);
     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
cf.c: In function ‘getVidPreview’:
cf.c:552:25: warning: ‘/preview’ directive writing 8 bytes into a region of size between 1 and 250 [-Wformat-overflow=]
     sprintf(temp_dir,"%s/preview",cache_path);
                         ^~~~~~~~
cf.c:552:5: note: ‘sprintf’ output between 9 and 258 bytes into a destination of size 250
     sprintf(temp_dir,"%s/preview",cache_path);
     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
cf.c:553:24: warning: ‘%s’ directive writing up to 249 bytes into a region of size 245 [-Wformat-overflow=]
     sprintf(buf, "less %s", temp_dir);
                        ^~   ~~~~~~~~
cf.c:553:5: note: ‘sprintf’ output between 6 and 255 bytes into a destination of size 250
     sprintf(buf, "less %s", temp_dir);
     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
cf.c: In function ‘getArchivePreview’:
cf.c:567:25: warning: ‘/preview’ directive writing 8 bytes into a region of size between 1 and 250 [-Wformat-overflow=]
     sprintf(temp_dir,"%s/preview",cache_path);
                         ^~~~~~~~
cf.c:567:5: note: ‘sprintf’ output between 9 and 258 bytes into a destination of size 250
     sprintf(temp_dir,"%s/preview",cache_path);
     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
cf.c: In function ‘copyFiles’:
cf.c:706:38: warning: ‘%s’ directive writing up to 249 bytes into a region of size 240 [-Wformat-overflow=]
         sprintf(temp_dir,"cp -r -v \"%s\" \"%s\"",buf,present_dir);
                                      ^~           ~~~
cf.c:706:9: note: ‘sprintf’ output 15 or more bytes (assuming 264) into a destination of size 250
         sprintf(temp_dir,"cp -r -v \"%s\" \"%s\"",buf,present_dir);
         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
cf.c: In function ‘removeFiles’:
cf.c:728:38: warning: ‘%s’ directive writing up to 249 bytes into a region of size 240 [-Wformat-overflow=]
         sprintf(temp_dir,"rm -r -v \"%s\"",buf);
                                      ^~    ~~~
cf.c:728:9: note: ‘sprintf’ output between 12 and 261 bytes into a destination of size 250
         sprintf(temp_dir,"rm -r -v \"%s\"",buf);
         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
cf.c: In function ‘renameFiles’:
cf.c:758:21: warning: ‘%s’ directive writing up to 249 bytes into a region of size 247 [-Wformat-overflow=]
     sprintf(cmd,"cp %s %s",clipboard_path,temp_clipboard_path);
                     ^~     ~~~~~~~~~~~~~~
cf.c:758:5: note: ‘sprintf’ output between 5 and 503 bytes into a destination of size 250
     sprintf(cmd,"cp %s %s",clipboard_path,temp_clipboard_path);
     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
cf.c:762:22: warning: ‘%s’ directive writing up to 249 bytes into a region of size 246 [-Wformat-overflow=]
     sprintf(cmd,"vim %s",temp_clipboard_path);
                      ^~  ~~~~~~~~~~~~~~~~~~~
cf.c:762:5: note: ‘sprintf’ output between 5 and 254 bytes into a destination of size 250
     sprintf(cmd,"vim %s",temp_clipboard_path);
     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
cf.c:788:21: warning: ‘%s’ directive writing up to 249 bytes into a region of size 247 [-Wformat-overflow=]
     sprintf(cmd,"rm %s %s",temp_clipboard_path,clipboard_path);
                     ^~     ~~~~~~~~~~~~~~~~~~~
cf.c:788:5: note: ‘sprintf’ output between 5 and 503 bytes into a destination of size 250
     sprintf(cmd,"rm %s %s",temp_clipboard_path,clipboard_path);
     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
cf.c:779:35: warning: ‘%s’ directive writing up to 249 bytes into a region of size 246 [-Wformat-overflow=]
                 sprintf(cmd,"mv \"%s\" \"%s\"",buf,buf2);
                                   ^~           ~~~
cf.c:779:17: note: ‘sprintf’ output between 9 and 507 bytes into a destination of size 250
                 sprintf(cmd,"mv \"%s\" \"%s\"",buf,buf2);
                 ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
cf.c: In function ‘moveFiles’:
cf.c:811:35: warning: ‘%s’ directive writing up to 249 bytes into a region of size 243 [-Wformat-overflow=]
         sprintf(temp_dir,"mv -f \"%s\" \"%s\"",buf,present_dir);
                                   ^~           ~~~
cf.c:811:9: note: ‘sprintf’ output 12 or more bytes (assuming 261) into a destination of size 250
         sprintf(temp_dir,"mv -f \"%s\" \"%s\"",buf,present_dir);
         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
cf.c: In function ‘main’:
cf.c:1035:45: warning: ‘sprintf’ may write a terminating nul past the end of the destination [-Wformat-overflow=]
                     sprintf(temp_dir, "%s/%s", next_dir, next_directories[i]);
                                             ^
cf.c:1035:21: note: ‘sprintf’ output 2 or more bytes (assuming 251) into a destination of size 250
                     sprintf(temp_dir, "%s/%s", next_dir, next_directories[i]);
                     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
cf.c:1401:49: warning: ‘sprintf’ may write a terminating nul past the end of the destination [-Wformat-overflow=]
                         sprintf(temp_dir, "%s/%s", scripts_path, scripts[option]);
                                                 ^
cf.c:1401:25: note: ‘sprintf’ output 2 or more bytes (assuming 251) into a destination of size 250
                         sprintf(temp_dir, "%s/%s", scripts_path, scripts[option]);
                         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
cf.c:1403:42: warning: ‘%s’ directive writing up to 249 bytes into a region of size between 0 and 249 [-Wformat-overflow=]
                         sprintf(cmd, "%s %s", temp_dir, path);
                                          ^~             ~~~~
cf.c:1403:25: note: ‘sprintf’ output between 2 and 500 bytes into a destination of size 250
                         sprintf(cmd, "%s %s", temp_dir, path);
                         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
cf.c:1208:37: warning: ‘sprintf’ may write a terminating nul past the end of the destination [-Wformat-overflow=]
                 sprintf(path, "%s/%s",info->pw_dir,buf);
                                     ^
cf.c:1208:17: note: ‘sprintf’ output 2 or more bytes (assuming 251) into a destination of size 250
                 sprintf(path, "%s/%s",info->pw_dir,buf);
                 ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
cf.c:1349:43: warning: ‘%s’ directive writing up to 249 bytes into a region of size 246 [-Wformat-overflow=]
                     sprintf(temp_dir,"vim %s",clipboard_path);
                                           ^~  ~~~~~~~~~~~~~~
cf.c:1349:21: note: ‘sprintf’ output between 5 and 254 bytes into a destination of size 250
                     sprintf(temp_dir,"vim %s",clipboard_path);
                     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
cf.c:1183:37: warning: ‘sprintf’ may write a terminating nul past the end of the destination [-Wformat-overflow=]
                 sprintf(path, "%s/%s",info->pw_dir,buf);
                                     ^
cf.c:1183:17: note: ‘sprintf’ output 2 or more bytes (assuming 251) into a destination of size 250
                 sprintf(path, "%s/%s",info->pw_dir,buf);
                 ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
cf.c:1333:44: warning: ‘%s’ directive writing up to 249 bytes into a region of size 245 [-Wformat-overflow=]
                     sprintf(temp_dir,"less %s",clipboard_path);
                                            ^~  ~~~~~~~~~~~~~~
cf.c:1333:21: note: ‘sprintf’ output between 6 and 255 bytes into a destination of size 250
                     sprintf(temp_dir,"less %s",clipboard_path);
                     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[2/2] Linking C executable cfiles

error and can not install

brew tap mananapr/cfiles
brew install cfiles

Error: An exception occurred within a child process:
Utils::InreplaceError: inreplace failed
Makefile:
expected replacement of "-lncursesw" with "-lncurses"

Bug with preview

Hi,
the app crashes when I preview pdf files.
I like the approach with c. I like ranger, it has everything that you need, but it's quite too complex and overloaded with things you do not need and what its the worst, it's slow. There needs to be a more performant alternative.

Make navigation keys configurable instead of hardcoded

Users of non-qwerty keyboard layouts often want to change the keybindings to preserve the physical positions on the keyboard. In cfiles the navigation keys are hardcoded preventing this.

I use Dvorak. After changing all configurable keybindings in config.h, I get error when compiling.

me@computer:/usr/local/src/cfiles$ make  
gcc -I. -Wall cf.c -o cfiles -lncursesw
In file included from cf.c:28:
cf.c: In function ‘main’:
cf.c:2473:13: error: duplicate case value
             case KEY_MV:
             ^~~~
cf.c:2094:13: note: previously used here
             case 'k':
             ^~~~
cf.c:2630:13: error: duplicate case value
             case KEY_SCRIPT:
             ^~~~
cf.c:2106:13: note: previously used here
             case 'l':
             ^~~~
make: *** [Makefile:10: all] Error 1

I discovered that the hjkl keys are hardcoded in the cf.c file, to serve as the navigation keys. On Dvorak layout the analogous keys in the right hand home row are dhnt. In order to remap them and resolve the conflicts I edited these four lines:

        // Keybindings
        switch( ch = wgetch(current_win) )
        {
            // Go up
            case KEY_UP:
-           case 'k':
+           case 't':
                scrollUp();
                break;

            // Go down
            case KEY_DOWN:
-           case 'j':
+           case 'h':
                scrollDown();
                break;

            // Go to child directory or open file
            case KEY_RIGHT:
-           case 'l':
+           case 'n':
            case '\n':
                goForward();
                break;

            // Go up a directory
            case KEY_LEFT:
-           case 'h':
+           case 'd':
                goBack();
                break;

It is doable, but requires unnecessary effort. Exposing the nav keys to user via config file will not clutter it and will save time and effort for non-qwerty users who want to preserve the physical positions of the keys.

EDITOR (Vim) prints `Command terminated` when opening a file

When I open a file through cfiles, in my EDITOR (Vim), it prints the following message:

screenshot_2019-05-13_00:36:24

before showing the file content.

I know the issue has to do with Vim in particular (since it doesn't occur with nano for example), but is there some program/command that is run before Vim is run so that this message is printed?

unreliable variable length array allocation

do {
...
// Stores number of files in the child directory
len_preview = getNumberofFiles(next_dir);
// Stores files in the child directory
char* next_directories[len_preview];
..
} while ()

This is no guarrantee that next_directories will be allocated correctly. You may want to use malloc instead.

Use after free

Issue

Some memory is read after it's been freed.

How to reproduce

The easiest way to reproduce I could find was to go to / then try to go to the (non-existent) parent directory.

Detail

When going up a directory we have the following code:

case 'h':
    free(temp_dir);
    allocSize = snprintf(NULL,0,"%s",dir);
    temp_dir = malloc(allocSize+1);
    snprintf(temp_dir,allocSize+1,"%s",dir);

    // ...

    // Get the last token in `temp_dir` and store it in `last`
    getLastToken("/");
    break;

Where in getLastToken strtok is used to store in last a pointer to part of the memory that was allocated for temp_dir.

void getLastToken(char *tokenizer)
{
    pch = strtok(temp_dir, tokenizer);
    while (pch != NULL)
    {
        last = pch;
        pch = strtok(NULL,tokenizer);
    }
}

On the next main loop iteration temp_dir is freed line 1411.

// Print all the elements and highlight the selection
int t = 0;
for( i=start; i<len; i++ )
{
    free(temp_dir);
    allocSize = snprintf(NULL,0,"%s/%s",dir,directories[i]);
    temp_dir = malloc(allocSize + 1);

Then on the next main loop iteration, handleFlags is called line 1397.

This function uses the pointer last at two places lines 1304 and 1325 (the one that triggered for me was 1325). However by that time last is a pointer to freed memory, so that's a read-after-free bug.

Note

There are other use of getLastToken or the last pointer, I expect this issue to come back at other places.

Fix

When freeing memory, invalidate all dangling pointers that point to it.

Memory leak

Issue

Some memory allocated with malloc is never freed: this is a memory leak.

Bugs

Based on 9be9889

Line 377

    buf = malloc(PATH_MAX);
    while(fgets(buf, PATH_MAX, (FILE*) fp))
    {
        if(buf[0] == bookmark)
        {
            fclose(fp);
            return 1;

buf is allocated but the function may return without freeing it resulting in a memory leak.

Line 515

    // Allocate Memory to `temp`
    allocSize = snprintf(NULL,0,"%s", filepath);
    temp = malloc(allocSize+1);
    snprintf(temp, allocSize+1, "%s", filepath);
    temp[strlen(temp)]='\0';
    if(f == NULL)
    {
        return 0;
    }

temp is allocated but the function may return without freeing it resulting in a memory leak.

Solution

Free any allocated memory before returning from the function that defined that variable.

Pass path to cfiles

With ranger I can do ranger /path/to/some/files and it opens that directory up in ranger. It would be nice if cfiles could do this too.

Auto-reload

So how would i go about this? Im using w3m to preview images and i would want to auto reload after every image (not having to press r)

Error with preview.

Whenever, in the root directory, the lost+found or root folders are highlighted, Cfiles crashes, usually with the error with preview message, so I have to manually press r(reload) to get it to work again properly. It probably has something to do with those two directories as they are not accessible by a non-root user. Expected behaviour should be to display a not accessible message(or similar) when these directories are highlighted like in ranger, but cfiles just breaks.

Here are some screenshots.

cfilebug1
cfilebug2

OS: Pop!_OS 20.04 LTS
I compiled the app manually from source.

Strange behavior opening bash scripts (xdg-open, vim)

I have a curious problem when opening shell scripts.

The file previews fine, and on initial open displays correctly in Vim.

As soon as I attempt to navigate the file, it appears that cfiles is attempting to scroll through the current directory, overwriting the screen on top of Vim.

This doesn't happen with other files opening in Vim (c, c++, html, txt files tested), just bash scripts.

Even more curious is that I can open the files with xdg-open without any issue.
screenshot3
screenshot4
screenshot_error_sh

1.2 fails to compile on FreeBSD

gcc -I. -Wall cf.c -o cfiles -lncursesw
cf.c: In function 'main':
cf.c:1453:9: warning: implicit declaration of function 'signal'; did you mean 'strsignal'? [-Wimplicit-function-declaration]
         signal(SIGCHLD, SIG_IGN);
         ^~~~~~
         strsignal
cf.c:1453:16: error: 'SIGCHLD' undeclared (first use in this function)
         signal(SIGCHLD, SIG_IGN);
                ^~~~~~~
cf.c:1453:16: note: each undeclared identifier is reported only once for each function it appears in
cf.c:1453:25: error: 'SIG_IGN' undeclared (first use in this function)
         signal(SIGCHLD, SIG_IGN);
                         ^~~~~~~
gmake: *** [Makefile:10: all] Error 1

Use EDITOR environment variable instead of hardcoding vim

It would perhaps be best if you made a call to getenv and passed it the EDITOR environment variable for opening up text files from within this file-manager. This can provide more flexibility for end users who would prefer to use another text editor other than vim.

For example:

char cmd[250];
sprintf(cmd,"%s %s", getenv("EDITOR"), filepath);

I've just taken some of the pre-existing code from the main file, though you should most definitely revise this as it is prone to buffer-overflow errors/attacks as others have mentioned.

Nonetheless I think this is a pretty cool project, and definitely a good learning experience for someone who wants to pick up C, and familiarise themselves with the language.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.