Find file with wildcards on entire disk - c++

I need to find a variable extension file using wildcards (*.txt, *.jpeg, *.doc) on a disk (c:).
I tried with the following function, but I can't make it recursive, and it's not working:
void Recurse(LPCTSTR str)
{
WIN32_FIND_DATA file;
cout << "Value INPUT:" << str <<"\n";
HANDLE search_handle=FindFirstFile(str,&file);
if (search_handle) {
do {
if(file.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY &&
strcmp(file.cFileName,"..")!=0
&& strcmp(file.cFileName,".")!=0
&& strcmp(file.cFileName,"$Recycle.Bin")!=0
&& strcmp(file.cFileName,"Recovery")!=0
&& strcmp(file.cFileName,"System Volume Information")!=0
&& strcmp(file.cFileName,"PerfLogs")!=0
&& strcmp(file.cFileName,"Windows")!=0)
{
str = file.cFileName;
cout << "Directory :" << file.cFileName <<"\n";
Recurse(str); // Function to remind new directory
} else {
if (file.cFileName == "*.txt") {
std::wcout << file.cFileName << std::endl; //Print files find with estension txt
}
}
} while(FindNextFile(search_handle,&file));
CloseHandle(search_handle);
}
}
Of course I tried it with a static value (*.txt) to see if it worked, but it didn't work when I called it from in main:
Recurse("C:\\*");

I modified the code in this way. If it finds them throwing me * .txt files and me brings them correctly, but the path instead in many files shows me incorrect with several strange characters. I can not understand why such behavior.
char *my1;
char *my2;
char *my3;
char *my4;
char *cp2;
LPCTSTR ori;
std::string stringa_mia;
std::vector<std::string> listafiles;
std::vector<std::string> listapath;
void Recurse(LPCTSTR str, LPCTSTR ori)
{
WIN32_FIND_DATA file;
cp2 = strdup(str);
strcat(cp2, "\\*");
HANDLE search_handle=FindFirstFile(cp2,&file);
BOOL res = TRUE;
if (search_handle)
{
while(search_handle != INVALID_HANDLE_VALUE && res)
{
if(file.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY &&
strcmp(file.cFileName,"..")!=0
&& strcmp(file.cFileName,".")!=0
&& strcmp(file.cFileName,"$Recycle.Bin")!=0
&& strcmp(file.cFileName,"Recovery")!=0
&& strcmp(file.cFileName,"System Volume Information")!=0
&& strcmp(file.cFileName,"PerfLogs")!=0
&& strcmp(file.cFileName,"Windows")!=0
&& strcmp(file.cFileName,"Program Files")!=0
&& strcmp(file.cFileName,"Boot")!=0
&& strcmp(file.cFileName,"Program Files (x86)")!=0
&& strcmp(file.cFileName,"AppData")!=0
&& strcmp(file.cFileName,"ProgramData")!=0
&& strcmp(file.cFileName,"Cookies")!=0
&& strcmp(file.cFileName,".android")!=0
&& strcmp(file.cFileName,"Programmi")!=0
)
{
my3 = strdup(file.cFileName);
my2 = strdup(str);
my1 = strdup(ori);
strcat(my2, "\\");
strcat(my2, my3);
CloseHandle(search_handle);
Recurse(my2,ori);
}
else
{
my4 = strdup(file.cFileName);
stringa_mia = std::string(my4);
if (stringa_mia.find(".txt")!=std::string::npos) {
listafiles.push_back(stringa_mia);
listapath.push_back(str);
}
}
res = FindNextFile(search_handle,&file);
}
CloseHandle(search_handle);
}
}
i call the function in this mode:
Recurse("C:","C:");

Related

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

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 years ago.
Improve this question
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.");
}
}
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/

Generate balanced Parenthesis

The tried below logic to generate the possible set of balanced parenthesis. but each possible output is getting printed twice.
void balanced_parenthesis(vector<string>& out_vec,string out_str,int is_open,int is_close)
{
if(is_open == 0 && is_close == 0)
{
cout<<out_str<<endl;
out_vec.push_back(out_str);
return;
}
if(is_open != 0)
{
out_str += '(';
is_open = is_open-1;
balanced_parenthesis(out_vec,out_str,is_open,is_close);
}
if( is_close > is_open)
{
out_str += ')';
is_close = is_close-1;
balanced_parenthesis(out_vec,out_str,is_open,is_close);
}
}
however by decrementing is_close and is_open variables in the function call prints the output exactly once.
void balanced_parenthesis(vector<string>& out_vec,string out_str,int is_open,int is_close)
{
if(is_open == 0 && is_close == 0)
{
cout<<out_str<<endl;
out_vec.push_back(out_str);
return;
}
if(is_open != 0)
{
out_str += '(';
balanced_parenthesis(out_vec,out_str,is_open,is_close);
}
if( is_close > is_open)
{
out_str += ')';
balanced_parenthesis(out_vec,out_str,is_open,is_close-1);
}
}
Could anyone explain me behaviour of the first code ?

M_construct error when reading file contents

I'm creating a game that requires a lot of setup. I decided to add a configuration file (.ini) and a reader to get the information. My ini file is setup as follows:
-cmd arg0 arg1
I initially only had one command which worked fine until I added a second. For whatever reason, I receive an std::logic_error when my command is not the first one.
// this works
-load w "someName"
// this doesn't
-delete "someName"
Here is the code used to read the file:
InitFileReader::InitFileReader()
{
std::string ini_file_path = "";
ini_file_path += PROGRAM_FOLDER;
ini_file_path += "\\blockgame.ini";
std::ifstream ini_file(ini_file_path);
if (!ini_file.is_open()) std::cout << "Couldn't find configuration file at " << ini_file_path << std::endl;
std::string line;
while(std::getline(ini_file, line))
{
if (starts_with(line, "-load "))
{
std::string arg0 = "";
unsigned int index = 6;
for (; index < line.size(); index++)
{
char c = line[index];
if (c == ' ') break;
arg0 += c;
}
std::string arg1 = "";
bool reached_quote = false;
for (; index < line.size(); index++)
{
char c = line[index];
if (c == ' ' && !reached_quote) continue;
if (c == '\"' && !reached_quote)
{
reached_quote = true;
continue;
}
else if (c == '\"') break;
arg1 += c;
}
sfr = new SaveFolderReader(arg1);
if (arg0 == "new")
{
sfr->new_header(DEFAULT_HEADER);
}
else if (arg0 == "def")
{
sfr->restore_header(DEFAULT_HEADER);
}
}
else if (starts_with(line, "-delete "))
{
std::string arg0 = "";
unsigned int index = 8;
for (; index < line.size(); index++)
{
char c = line[index];
if (c == ' ') break;
arg0 += c;
}
std::string world_path = "";
world_path += PROGRAM_FOLDER;
world_path += "\\save\\";
world_path += arg0;
if (rmdir(world_path.c_str()) != 0)
{
std::cout << "Error deleting world \"" << arg0 << "\"" << std::endl;
}
}
}
}
inline bool starts_with(const std::string& target, const std::string& prefix)
{
if (target.size() < prefix.size())
return false;
for (unsigned int i = 0; i < prefix.size(); i++)
{
if (target[i] != prefix[i])
return false;
}
return true;
}
The PROGRAM_FOLDER constant is just the parent folder of the path returned by argv[0] in main. I can't run the debugger on this code because the path changes to something strange when I do that.
I know that this error shows up because of a nullptr initialization of std::string but I still have no idea why this is happening.
I've tried typing in random characters into the config file and get the same result. It baffles me that the first if-statement works fine but the second one doesn't (when I use the -delete command).
Any suggestions would be of great use, thanks in advance!
It turns out that the error wasn't coming from that block of code at all. What was happening was that my game tried to load data in afterwards but because I didn't write the load command there was nothing to read from. I fixed my Debugger issue (For whatever reason the char[] I allocated stored different data when the debugger ran) and just reverted to std::strings.

Recursive comparison of two strings

The function int compare(...), checks if 2 strings are equal ignoring case and any non-alphabetical characters, e.g. "a?...!b" is equivalent to "ab". Returns 1 if equal, 0 else. However, there's a bug in my code!
int compare(const char* string1, const char* string2)
{
if(string1 == NULL || string2 == NULL)
return 0;
std::cout << *string1 << " | " << *string2 << std::endl;
if((!isalpha(*string1) && *string1 != ' ') && (!isalpha(*string2) && *string2 != ' '))
{
compare(++string1,++string2);
}
else if(!isalpha(*string1) && *string1 != ' ')
{
compare(++string1,string2);
}
else if(!isalpha(*string2) && *string2 != ' ')
{
compare(string1, ++string2);
}
if(tolower(*string1) != tolower(*string2))
return 0;
if(*string1 == '\0')
return 1;
if(*string1 == *string2)
compare(++string1, ++string2);
}
If I try and run this code with for example:
compare("a !!!b", "a b");
The output really confuses me:
a | b
|
! |
! |
! |
b | b
^#| ^#
| a
^#| ^#
| a
It returns 0 (not equal). It doesn't stop running once it gets to b | b, why?
Besides needing the return statement you have a flaw in your logic. You need to check if both strings are empty and thus equal earlier in the function:
int compare(const char* string1, const char* string2)
{
if(string1 == NULL || string2 == NULL)
return 0;
// This needs to go here
if(*string1 == '\0' && *string2 == '\0') {
return 1;
}
std::cout << *string1 << " | " << *string2 << std::endl;
if((!isalpha(*string1) && *string1 != ' ') && (!isalpha(*string2) && *string2 != ' '))
{
return compare(++string1,++string2);
}
else if(!isalpha(*string1) && *string1 != ' ')
{
return compare(++string1,string2);
}
else if(!isalpha(*string2) && *string2 != ' ')
{
return compare(string1, ++string2);
}
if(tolower(*string1) != tolower(*string2))
return 0;
if(*string1 == *string2)
return compare(++string1, ++string2);
}
You can check it here: https://ideone.com/Si78Nz

"retsize <= sizeInWords" in mbstowcs in dirent.h on Windows

Background information:
I'm building a file tree in windows using dirent.h (project requirement) on VS2013. I got dirent.h from here. I crash at runtime with a debug assertion failed ("retsize <= sizeInWords") from crt\crtw32\mbstowcs.c, line 283.
To test dirent.h, I used
void printDir(std::string dir, std::string tab)
{
DIR* d = opendir(dir.c_str());
dirent* ent = nullptr;
while (ent = readdir(d)) {
if (ent->d_name[0] != '.') {
std::cout << tab << ent->d_name << std::endl;
if (ent->d_type == DT_DIR) {
printDir(dir + "/" + ent->d_name, tab + " ");
}
}
}
}
which worked (called from main as printDir(".", ""))
so to build my tree I have:
struct Dirf {
std::string getFullPath() {
if (out) {
return out->getFullPath() + "/" + ent.d_name;
}
else return ent.d_name;
}
Dirf(DIR* dir, Dirf* parent = nullptr)
: out(parent)
{
if (dir) {
dirent* d = readdir(dir);
if (d) {
ent = *d;
if (dir) {
next = std::make_shared<Dirf>(dir, parent);
}
if (ent.d_type == DT_DIR) {
DIR* inDir = opendir(getFullPath().c_str());
in = std::make_shared<Dirf>(inDir, this);
closedir(inDir);
}
}
}
}
private:
typedef std::shared_ptr<Dirf> point;
friend std::string to_string(Dirf, std::string);
dirent ent;
Dirf* out; // parent to this; in->out == this, out->in == this;
point in, // in != null iff car.d_type == DT_DIR
next; // next entry in the dir
};
std::string to_string(Dirf, std::string tab = "");
However, calling Dirf(opendir(".")) fails with the debug assertion described above
While composing the question, I figured out the answer: I forgot to check for "." and ".." in Dirf's constructor (I remembered to do it in my test case). Adding
while (d && d->d_name[0] == '.') { // skip '..' and '.'
d = readdir(dir);
}
after dirent* d = readdir(dir) made the error go away.