Use shell symbols in directory path - c++

I want to open a file with my program, and I want to use shell symbols to make it easier for me to locate the file. Is there an easy way to have the shell expand out my file path before I use it on runtime. I'm looking for a function that does this.
~/.foo.bar -> /home/someuser/.foo.bar
Is there some easy way to have the shell preprocess the paths to files before opening the file?

You can use wordexp:
#include <wordexp.h>
std::string wordexp(std::string var, int flags = 0)
{
wordexp_t p;
if(!wordexp(var.c_str(), &p, flags))
{
if(p.we_wordc && p.we_wordv[0])
var = p.we_wordv[0];
wordfree(&p);
}
return var;
}
int main()
{
std::cout << wordexp("~/test") << '\n';
}

Related

opening a file in random named folder using c/c++

I'm trying to code a program where it opens and reads a file automatically. But the problem is the file is stored in a folder which name is unknown. I only know where the folder is located and the file's name. How to get to that file's path in char* ?
Edit: example: d:\files\<random folder>\data.txt
I don't know the name of random folder but I know that it exists in d:\files
Since this is tagged windows, you might as well use the Windows API functions:
FindFirstFile()
FindNextFile()
to enumerate and loop through all the files in a given directory.
To check for a directory, look at dwFileAttributes contained in the WIN32_FIND_DATA structure (filled by the calls to Find...File()). But make sure to skip . and .. directories. If needed, this can be done recursively.
You can check the links for some examples, or see Listing the Files in a Directory.
In case you are using MFC, you can use CFileFind (which is a wrapper around the API functions):
CFileFind finder;
BOOL bWorking = finder.FindFile(_T("*.*"));
while (bWorking)
{
bWorking = finder.FindNextFile();
TRACE(_T("%s\n"), (LPCTSTR)finder.GetFileName());
}
Just for fun, I implemented this using the new, experimental <filesystem> FS Technical Specification supported by GCC 5.
#include <iostream>
#include <experimental/filesystem>
// for readability
namespace fs = std::experimental::filesystem;
int main(int, char* argv[])
{
if(!argv[1])
{
std::cerr << "require 2 parameters, search directory and filename\n";
return EXIT_FAILURE;
}
fs::path search_dir = argv[1];
if(!fs::is_directory(search_dir))
{
std::cerr << "First parameter must be a directory: " << search_dir << '\n';
return EXIT_FAILURE;
}
if(!argv[2])
{
std::cerr << "Expected filename to search for\n";
return EXIT_FAILURE;
}
// file to search for
fs::path file_name = argv[2];
const fs::directory_iterator dir_end; // directory end sentinel
// used to iterate through each subdirectory of search_dir
fs::directory_iterator dir_iter(search_dir);
for(; dir_iter != dir_end; ++dir_iter)
{
// skip non directories
if(!fs::is_directory(dir_iter->path()))
continue;
// check directory for file
// iterate through files in this subdirectory dir_iter->path()
auto file_iter = fs::directory_iterator(dir_iter->path());
for(; file_iter != dir_end; ++file_iter)
{
// ignore directories and wrong filenames
if(fs::is_directory(file_iter->path())
|| file_iter->path().filename() != file_name)
continue;
// Ok we found it (the first one)
std::cout << "path: " << file_iter->path().string() << '\n';
return EXIT_SUCCESS;
}
}
// Not found
std::cout << file_name << " was not found in " << search_dir.string() << '\n';
return EXIT_FAILURE;
}
The idea is: list the directories under d:\files and try to open
the file in each directory.
There isn't (yet) a standard C++ way of getting all the existing files/directories. A crude but easy way of doing this would be
system("dir d:\\files /b /ad > tmpfile");
This lists all directories (/ad), redirected to a temporary file. Then open the file:
std::ifstream list("tmpfile");
And read it:
std::string dirname;
std::string filename;
while (std::getline(list, dirname))
{
filename = "d:\\files\\" + dirname + "\\data.txt";
if ( ... file exists ... )
break;
}
I call this method crude because it has problems that are hard/impossible to fix:
It overwrites a potentially useful file
It doesn't work if current directory is read-only
It will only work in Windows
It might be possible to use _popen and fgets instead of redirecting to file.

How can I delete a directory and all files in it with C++?

How can I delete all the files in the directory? I've used rmdir and other methods suggested in the internet but no one helped me: this is one of them: (I want to remove directory tmp in the current work directory)
removeDir()
{
char currentPath[_MAX_PATH];
GetCurrentPath(currentPath);
std::string tmp(currentPath);
string path = tmp + "\\temp";
std::string command = "del ";
std::string Path = path + "1.txt";
cout << Path << endl;
system(command.append(Path).c_str());
}
GetCurrentPath(char* buffer)
{
getcwd(buffer, _MAX_PATH);
}
Use Boost Filesystem Library
You should look into the Boost Filesystem Library, which provides a number of features that make this sort of thing a lot easier. The example code on the linked page does something very similar to what you want to accomplish (it searches a directory recursively instead of deleting contents recursively).
In case you don't wanna use Boost, you can do this
rm -r "folder name"
http://www.cplusplus.com/reference/clibrary/cstdio/remove/
int remove ( const char * filename );
#include <stdio.h>
int main ()
{
if( remove( "myfile.txt" ) != 0 )
perror( "Error deleting file" );
else
puts( "File successfully deleted" );
return 0;
}

Unable to read INI file Parsing using boost::program_options

I am a newbie in c++ and boost. I am attempting to read (later write) to INI file using boost::program_options. I even tried using boost::property_tree.
Both(program_options & property_tree) work perfectly when std::stringstream s("[test]\n""a=2\n""b=3\n") is used, BUT NOT when std::ifstream s("dimension.ini"). I have put files: dimension.ini, Rcasdim.hpp/cpp in the same folder, and also have relevant boost lib files in search directory.
INI File
[Section]
a=2
b=3
Purpose:
I need to dynamically set the "Value" (at the start ONLY) for a Particular "Key" in INI file & Later USE that Previously set "Value" for that "Key" by other project files (more, as a toggle)
#include boost/program_options/detail/config_file.hpp
#include boost/program_options/parsers.hpp
namespace pod = boost::program_options::detail;
class CRcasdim
{
public:
CRcasdim(){};
~CRcasdim(){};
std::string getrcasdim(float);
private:
std::string sd;
};
std::string CRcasdim::getrcasdim(float d)
{
//std::stringstream s("[Section]\n""a=2\n""b=3\n"); WORKS
std::ifstream s("dimension.ini"); DOESNT WORK
if(!s)
{
std::cerr<<"error"<<std::endl;
}
std::set<std::string> options;
std::map<std::string, std::string> parameters;
options.insert("Section.a");
options.insert("Section.b");
try
{
for (pod::config_file_iterator i(s, options), e ; i != e; ++i)
parameters[i->string_key] = i->value[0];
}
catch(std::exception& e)
{
std::cerr<<"Exception: ";
}
if (d==2)
sd = parameters["Section.a"];
else if (d==3)
sd = parameters["Section.b"];
return sd;
}
You don't need to put the ini file and the hpp/cpp files in the same folder.
The dimension.ini file has be in the same folder like your binary(executable on linux .exe on windows).
The location depends on your build system and your platform and most probably some things I forgot.

C++ - Determining if directory (not a file) exists in Linux [duplicate]

This question already has answers here:
Checking if a directory exists in Unix (system call)
(5 answers)
Closed 4 years ago.
How would I determine if a directory (not a file) existed using C++ in Linux? I tried using the stat() function but it returned positive when a file was found. I only want to find if the inputted string is a directory, not something else.
According to man(2) stat you can use the S_ISDIR macro on the st_mode field:
bool isdir = S_ISDIR(st.st_mode);
Side note, I would recommend using Boost and/or Qt4 to make cross-platform support easier if your software can be viable on other OSs.
how about something i found here
#include <dirent.h>
bool DirectoryExists( const char* pzPath )
{
if ( pzPath == NULL) return false;
DIR *pDir;
bool bExists = false;
pDir = opendir (pzPath);
if (pDir != NULL)
{
bExists = true;
(void) closedir (pDir);
}
return bExists;
}
Or using stat
struct stat st;
if(stat("/tmp",&st) == 0)
if(st.st_mode & S_IFDIR != 0)
printf(" /tmp is present\n");
If you can check out the boost filesystem library. It's a great way to deal with this kind of problems in a generic and portable manner.
In this case it would suffice to use:
#include "boost/filesystem.hpp"
using namespace boost::filesystem;
...
if ( !exists( "test/mydir" ) ) {bla bla}
The way I understand your question is this: you have a path, say, /foo/bar/baz (baz is a file) and you want to know whether /foo/bar exists. If so, the solution looks something like this (untested):
char *myDir = dirname(myPath);
struct stat myStat;
if ((stat(myDir, &myStat) == 0) && (((myStat.st_mode) & S_IFMT) == S_IFDIR)) {
// myDir exists and is a directory.
}
In C++17**, std::filesystem provides two variants to determine the existence of a path:
is_directory() determines, if a path is a directory and does exist in the actual filesystem
exists() just determines, if the path exists in the actual filesystem (not checking, if it is a directory)
Example (without error handling):
#include <iostream>
#include <filesystem> // C++17
//#include <experimental/filesystem> // C++14
namespace fs = std::filesystem;
//namespace fs = std::experimental::filesystem; // C++14
int main()
{
// Prepare.
const auto processWorkingDir = fs::current_path();
const auto existingDir = processWorkingDir / "existing/directory"; // Should exist in file system.
const auto notExistingDir = processWorkingDir / "fake/path";
const auto file = processWorkingDir / "file.ext"; // Should exist in file system.
// Test.
std::cout
<< "existing dir:\t" << fs::is_directory(existingDir) << "\n"
<< "fake dir:\t" << fs::is_directory(notExistingDir) << "\n"
<< "existing file:\t" << fs::is_directory(file) << "\n\n";
std::cout
<< "existing dir:\t" << fs::exists(existingDir) << "\n"
<< "fake dir:\t" << fs::exists(notExistingDir) << "\n"
<< "existing file:\t" << fs::exists(file);
}
Possible output:
existing dir: 1
fake dir: 0
existing file: 0
existing dir: 1
fake dir: 0
existing file: 1
**in C++14 std::experimental::filesystem is available
Both functions throw filesystem_error in case of errors. If you want to avoid catching exceptions, use the overloaded variants with std::error_code as second parameter.
#include <filesystem>
#include <iostream>
namespace fs = std::filesystem;
bool isExistingDir(const fs::path& p) noexcept
{
try
{
return fs::is_directory(p);
}
catch (std::exception& e)
{
// Output the error message.
const auto theError = std::string{ e.what() };
std::cerr << theError;
return false;
}
}
bool isExistingDirEC(const fs::path& p) noexcept
{
std::error_code ec;
const auto isDir = fs::is_directory(p, ec);
if (ec)
{
// Output the error message.
const auto theError = ec.message();
std::cerr << theError;
return false;
}
else
{
return isDir;
}
}
int main()
{
const auto notExistingPath = fs::path{ "\xa0\xa1" };
isExistingDir(notExistingPath);
isExistingDirEC(notExistingPath);
}
If you want to find out whether a directory exists because you want to do something with it if it does (create a file/directory inside, scan its contents, etc) you should just go ahead and do whatever you want to do, then check whether it failed, and if so, report strerror(errno) to the user. This is a general principle of programming under Unix: don't try to figure out whether the thing you want to do will work. Attempt it, then see if it failed.
If you want to behave specially if whatever-it-was failed because a directory didn't exist (for instance, if you want to create a file and all necessary containing directories) you check for errno == ENOENT after open fails.
I see that one responder has recommended the use of boost::filesystem. I would like to endorse this recommendation, but sadly I cannot, because boost::filesystem is not header-only, and all of Boost's non-header-only modules have a horrible track record of causing mysterious breakage if you upgrade the shared library without recompiling the app, or even if you just didn't manage to compile your app with exactly the same flags used to compile the shared library. The maintenance grief is just not worth it.

how to search the computer for files and folders

i need a way to search the computer for files like Windows Explorer. i want my program to search lets say hard drive c:. i need it to search C:\ for folders and files (just the ones you could see in c:\ then if the user clicks on a file on the list like the folder test (C:\test) it would search test and let the user see what files/folders are in it.
Since you mentioned windows, the most straight forward winapi way to do it is with FindFirstFile and FindNextFile functions.
edit: Here's an example that shows you how to enumerate all files/folders in a directory.
#include <Windows.h>
#include <iostream>
int main()
{
WIN32_FIND_DATA file;
HANDLE search_handle=FindFirstFile(L"C:\\*",&file);
if (search_handle)
{
do
{
std::wcout << file.cFileName << std::endl;
}while(FindNextFile(search_handle,&file));
FindClose(search_handle);
}
}
This will be OS dependent. The SO question
How can I get a list of files in a directory using C or C++?
handles this problem well. You can download DIRENT here.
Now that you have this, I'd recommend recursively searching for a file with a DFS/BFS algorithm. You can assume the whole directory structure is a tree where each file is a leaf node and each subdirectory is an internal node.
So all you have to do is,
Get the list of files/folders in a directory with a function such as:
void getFilesFolders(vector<string> & dir_list, const string & folder_name)
If it's a directory, go to 1 with the directory name
If it's a file, terminate if it's the file you're looking for, else move on to the next file.
boost::filesystem can be a cross-platform solution for that (check out for such functions in it).
You can use Directory class members to do this with C# or managed C++. See the following MSDN article:
http://support.microsoft.com/kb/307009
If you wish to use C++ with MFC you can use CFileFind
http://msdn.microsoft.com/en-us/library/f33e1618%28v=VS.80%29.aspx
You'll have to supply your own browse window to present the file system tree.
Or you can use one of the directory/file controls to do both for you.
#include <Windows.h>
#include <iostream>
int FindF(char* pDirectory)
{
char szFindPath[MAX_PATH] = {0};
strcpy(szFindPath, pDirectory);
strcat(szFindPath, "\\*");
WIN32_FIND_DATA file;
HANDLE search_handle=FindFirstFile(szFindPath,&file);
if (search_handle)
{
do
{
if(file.dwFileAttributes == FILE_ATTRIBUTE_DIRECTORY)
{
strcpy(szFindPath, pDirectory);
strcat(szFindPath, "\\");
strcat(szFindPath, file.cFileName);
FindF(szFindPath);
}
std::wcout << file.cFileName << std::endl;
}while(FindNextFile(search_handle,&file));
CloseHandle(search_handle);
}
}
There really is no need to use 3rd party library to accomplish this. This is a short, independent function which lists all files (with their paths) in a directory, including subdiretories' files. std::string folderName has to finish with \, and if you want to list all files on computer, just create a loop in calling function along with GetLogicalDriveStrings (It returns strings with \, so it couldn't be more convenient in this case).
void FindAllFiles(std::string folderName)
{
WIN32_FIND_DATA FileData;
std::string folderNameWithSt = folderName + "*";
HANDLE FirstFile = FindFirstFile(folderNameWithSt.c_str(), &FileData);
if (FirstFile != INVALID_HANDLE_VALUE) {
do {
if (strcmp(FileData.cFileName, ".") != 0 && strcmp(FileData.cFileName, "..") != 0)
{
if(FileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
std::string NewPath = folderName + FileData.cFileName;
NewPath = NewPath + "\\";
FindAllFiles(NewPath);
}
else
{
std::cout /*<< folderName*/ << FileData.cFileName << std::endl;
}
}
} while(FindNextFile(FirstFile, &FileData));
}
}
This is ASCII version, remember that files and folders can be named in Unicode