c++ can't seem to filter out the dot files in my recursive directory listing program

315 Views Asked by At

I've written a program to mimic linux's ls and its options:

-a: include dot files
-d: show only this directory
-l: show long form
-h: prints utilities

All the options seem to work fine so far, however, by default when doing something like: ./a.out -d (shows all the files in the current directory) I've set it up so by default the dot files should not be showing(this is setup in function getdir). They should only show when the -a flag is input, something like ./a.out -ad . However, these dot files seem to always be present. Any ideas on what I am doing wrong? (I thought about minimizing the code but decided against it since a lot of the functions are interwined and its easier to see if everything by testing some of the other options).

Sample output:
[John@storm ~]$ ./a.out -d
.ccache
.local
.mozilla
private
public_html
.Xauthority
.bash_history
.bash_logout
.bash_profile
.bashrc
.emacs
.procmailrc
.procmailrc.orig
.config
.esd_auth
OSGradedLabs
linux.txt
OS
omp1.cpp
omp
test.cpp
test2.cpp
test3.cpp
.viminfo
a.out

While it should be:
a.out  linux.txt  omp  omp1.cpp  OS  OSGradedLabs  private  public_html  test2.cpp  test3.cpp  test.cpp



#include<iostream>
#include<string.h>
#include<fstream>
#include<dirent.h>
#include <unistd.h>
#include <getopt.h>
#include <string>
#include <vector>
#include <algorithm>
#include <sys/types.h>
#include <sys/stat.h>
#include <pwd.h>
#include <grp.h>
#include <cstring>

using namespace std;

class dirls 
{
    public:
        dirls();
        dirls(bool a, bool d, bool f, bool l, bool h);
        void print_usage(string s);
        void longlisting(string dir, vector<string>& files);
        void getdir(string dir, vector<string>& files, bool recursive);
        void initiate(string s, vector<string>& files, vector<string>& paths);
        bool ishflag() { return fflag; };
      

    private:
        bool aflag;
        bool dflag;
        bool fflag;
        bool lflag;
        bool hflag;
        
};
dirls::dirls()
{
    //this->pathQueue = pathQueue;
    aflag = false;
    dflag = false;
    fflag = false;
    lflag = false;
    hflag = false;
}

dirls::dirls(bool a, bool d, bool f, bool l, bool h) 
{
    aflag = a;
    dflag = d;
    fflag = f;
    lflag = l;
    hflag = h;
}

void dirls::print_usage(string s)
{
    cout << "Usage: ";
    cout << s;
    cout << " [(-[adflh]+) (dir)]*" << endl;
    cout << "-a: include dot files" << endl;
    cout << "-f: follow symbolic links" << endl;
    cout << "-d: only this directory" << endl;
    cout << "-l: long form" << endl;
    cout << "-h: prints this message" << endl;
}


bool isDir(string dir) // check if an argument is a directory
{
    struct stat fileInfo;
    stat(dir.c_str(), &fileInfo);
    if (S_ISDIR(fileInfo.st_mode)) 
        return true;
    else 
        return false;
    
}

void dirls::getdir(string dir, vector<string>& files, bool recursive) 
{
    DIR* dp; //create the directory object
    struct dirent* entry; //create the entry structure
    dp = opendir(dir.c_str()); //open directory by converting the string to const char*
    if (dir.at(dir.length() - 1) != '/') {
        dir = dir + "/";
    }
    if (dp != NULL) { //if the directory isn't empty
        while (entry = readdir(dp)) { //while there is something in the directory
            
            if (aflag == false && dflag == false) // if -a is not included then exclude dot files
            {
                if (strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0)
                { //and if the entry isn't "." or ".."
                    //if (isDir(dir + entry->d_name) == true && recursive == true) {//check if the new path is a directory, and if it is (and recursion is specified as true), recurse.
                    if (isDir(dir + entry->d_name) == true && isDir(dir))
                    {
                        files.push_back(string(entry->d_name)); //add entry to the list of files
                        getdir(dir + entry->d_name, files, true); //recurse
                    }
                    else
                    {
                        files.push_back(string(entry->d_name));//add the entry to the list of files
                    }
                }
            }
            else if (aflag == true && dflag == false)//if -a included and -d is not included then incude dot files and recurse
            {
                if (isDir(dir + entry->d_name) == true && isDir(dir))
                {
                    files.push_back(string(entry->d_name)); //add entry to the list of files
                    getdir(dir + entry->d_name, files, true); //recurse
                }
                else
                {
                    files.push_back(string(entry->d_name));//add the entry to the list of files
                }

            }
            else if (aflag == false && dflag == true) // if -a is not included and -d is included then don't incude dot files and remove recursion
            {
                if (strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0)
                { //and if the entry isn't "." or ".."
                    //if (isDir(dir + entry->d_name) == true && recursive == true) {//check if the new path is a directory, and if it is (and recursion is specified as true), recurse.
                    if (isDir(dir + entry->d_name) == true && isDir(dir))
                    {
                        files.push_back(string(entry->d_name)); //add entry to the list of files
                        //getdir(dir + entry->d_name, files, true); //recurse
                    }
                    else
                    {
                        files.push_back(string(entry->d_name));//add the entry to the list of files
                    }
                }
            }
            else if (aflag == true && dflag == true) // if -a is included and -d is included then inclue dot files and remov recursion
            {
                if (isDir(dir + entry->d_name) == true && isDir(dir))
                {
                    files.push_back(string(entry->d_name)); //add entry to the list of files
                    //getdir(dir + entry->d_name, files, true); //recurse
                }
                else
                {
                    files.push_back(string(entry->d_name));//add the entry to the list of files
                }
            }
            else
            { };
            
        }
        (void)closedir(dp); //close directory
    }
    else 
    {
        perror("Couldn't open the directory.");
    }
}

void dirls::longlisting(string dir, vector<string>& files)
{
    string complete;
    for (int i = 0; i < files.size(); i++)
    {
        struct stat buf;
        lstat(files[i].c_str(), &buf);

        uid_t userId = buf.st_uid;
        gid_t groupId = buf.st_gid;

        struct passwd* user = getpwuid(userId);
        struct group* group = getgrgid(groupId);

        string perms = string((S_ISDIR(buf.st_mode)) ? "d" : "-") + ((buf.st_mode & S_IRUSR) ? "r" : "-") + ((buf.st_mode & S_IWUSR) ? "w" : "-") + ((buf.st_mode & S_IXUSR) ? "x" : "-") + ((buf.st_mode & S_IRGRP) ? "r" : "-") + ((buf.st_mode & S_IWGRP) ? "w" : "-") + ((buf.st_mode & S_IXGRP) ? "x" : "-") + ((buf.st_mode & S_IROTH) ? "r" : "-") + ((buf.st_mode & S_IWOTH) ? "w" : "-") + ((buf.st_mode & S_IXOTH) ? "x" : "-");

        complete = perms + " " + to_string(buf.st_size) + " " + user->pw_name + " " + group->gr_name + " " + dir;
        files[i] = complete + files[i];
    }
}

void dirls::initiate(string s, vector<string>& files, vector<string>& paths)
{
    

    while (!paths.empty()) 
    {
       
        char* pathname = (char*)paths.front().c_str();

        getdir(paths.front(), files, true);
        
        if (paths.size() > 1) 
        {
            cout << pathname << ":" << endl;
        }

        if (hflag) 
        {
            print_usage(s);
            paths.erase(paths.begin());
            continue;
        }

        if (lflag) 
        {
            longlisting(paths.front(), files);
            paths.erase(paths.begin());
            continue;
        }

        if (aflag) 
        {
            paths.erase(paths.begin());
            continue;
        }

        if (dflag) 
        {
            paths.erase(paths.begin());
            continue;
        }

       
        paths.erase(paths.begin());
        
    }
}



int main(int argc, char* argv[]) 
{
    int opt = 0;
    string first = argv[0];
    string dir = argv[1];
    struct stat buf;
    bool a = false, d = false, f = false, l = false, h = false;

    vector<string> files = vector<string>(); // holds the files in a directory
    vector<string> paths = vector<string>(); // holds the paths

    while ((opt = getopt(argc, argv, "adflh")) != -1)
    {
        switch (opt)
        {
            case 'a':
                a = true;
                break;
            case 'd':
                d = true;
                break;
            case 'f':
                f = true;
                break;
            case 'l':
                l = true;
                break;
            case 'h':
                h = true;
                break;
            default:
                break;
        }
       
    }
    
    dirls x = dirls(a, d, f, l, h);
  
    
    for (int i = optind; i < argc; i++)
    {
        paths.push_back(argv[i]);
    }
    
    if (paths.empty()) 
    {
        paths.push_back(".");
    }

    x.initiate(first, files, paths);
 
    
    for (int i = 0; i < files.size(); i++)
    {
        if ((h == true) && (a == false) && (d == false) && (f == false) && (l == false))
            break;
        cout << files[i] << endl;
        
    }
   
    return 0; 
    
}

I am fairly sure the issue lies in getdir perhaps in my understanding of strcmp so I'll put a copy of that function below for easier viewing.

void dirls::getdir(string dir, vector<string>& files, bool recursive) 
{
    DIR* dp; //create the directory object
    struct dirent* entry; //create the entry structure
    dp = opendir(dir.c_str()); //open directory by converting the string to const char*
    if (dir.at(dir.length() - 1) != '/') {
        dir = dir + "/";
    }
    if (dp != NULL) { //if the directory isn't empty
        while (entry = readdir(dp)) { //while there is something in the directory
            
            if (aflag == false && dflag == false) // if -a is not included then exclude dot files | NOT WORKING
            {
                if (strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0)
                { //and if the entry isn't "." or ".."
                    //if (isDir(dir + entry->d_name) == true && recursive == true) {//check if the new path is a directory, and if it is (and recursion is specified as true), recurse.
                    if (isDir(dir + entry->d_name) == true && isDir(dir))
                    {
                        files.push_back(string(entry->d_name)); //add entry to the list of files
                        getdir(dir + entry->d_name, files, true); //recurse
                    }
                    else
                    {
                        files.push_back(string(entry->d_name));//add the entry to the list of files
                    }
                }
            }
            else if (aflag == true && dflag == false)//if -a included and -d is not included then incude dot files and recurse
            {
                if (isDir(dir + entry->d_name) == true && isDir(dir))
                {
                    files.push_back(string(entry->d_name)); //add entry to the list of files
                    getdir(dir + entry->d_name, files, true); //recurse
                }
                else
                {
                    files.push_back(string(entry->d_name));//add the entry to the list of files
                }

            }
            else if (aflag == false && dflag == true) // if -a is not included and -d is included then don't incude dot files and remove recursion
            {
                if (strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0)
                { //and if the entry isn't "." or ".."
                    //if (isDir(dir + entry->d_name) == true && recursive == true) {//check if the new path is a directory, and if it is (and recursion is specified as true), recurse.
                    if (isDir(dir + entry->d_name) == true && isDir(dir))
                    {
                        files.push_back(string(entry->d_name)); //add entry to the list of files
                        //getdir(dir + entry->d_name, files, true); //recurse
                    }
                    else
                    {
                        files.push_back(string(entry->d_name));//add the entry to the list of files
                    }
                }
            }
            else if (aflag == true && dflag == true) // if -a is included and -d is included then inclue dot files and remov recursion
            {
                if (isDir(dir + entry->d_name) == true && isDir(dir))
                {
                    files.push_back(string(entry->d_name)); //add entry to the list of files
                    //getdir(dir + entry->d_name, files, true); //recurse
                }
                else
                {
                    files.push_back(string(entry->d_name));//add the entry to the list of files
                }
            }
            else
            { };
            
        }
        (void)closedir(dp); //close directory
    }
    else 
    {
        perror("Couldn't open the directory.");
    }
}


1

There are 1 best solutions below

2
On BEST ANSWER

strcmp compares the whole string, so your function is filtering out exact matches to "." and "..". If you only want to check the first letter of the filename you can use array indexing in the string

entry->d_name[0] != '.'

or the strncmp function which compares only the first of a certain number of characters

strncmp(entry->d_name, ".", 1) != 0

http://www.cplusplus.com/reference/cstring/strncmp/