How to have a config file outside a CPP dll file - c++

I have a config.txt file which is in my source folder. I use it to store my baseURL. When i build the dll the config file gets capsulated into one dll.
I am trying to add a config file which will reside outside the dll, so that i can change the base url when needed.
using namespace std;
struct Config {
string baseurl;
};
void loadConfig(Config& config) {
ifstream fin("config.txt");
string line;
while (getline(fin, line)) {
istringstream sin(line.substr(line.find("=") + 1));
if (line.find("baseurl") != -1)
sin >> config.baseurl;
}
}
#and to access the values
Config config;
loadConfig(config);
Also can the dll file access an external config file when placed in the same folder.?
any solutions for this?

Related

C++ working with files and directory

I have school project and i need work with files. First of all i need open csv file which is in directory "vstupnidata" in root of my program directory.
My solution which doesn't work:
string directory= "..\\vstupnidata\\";
string file= "ucty2015.csv";
ifstream VstupniSoubor((directory+file).c_str());
if (!(VstupniSoubor.is_open())){ //I am always here
VypisChybyV1();
return 1;
}
When i change it to this and dont use directory "vstupnidata", everything is OK but i need open it from directory:
string directory= "";
string file= "ucty2015.csv";
ifstream VstupniSoubor((directory+file).c_str());
if (!(VstupniSoubor.is_open())){
VypisChybyV1();
return 1;
}

Open a file with unicode path

I'm working under windows 7 with mingw. I have encountered some weird behaviour with unicode filenames. My program needs to be portable, and I'm using boost::filesystem (v 1.53) to handle the file paths.
This has all been going well, until I needed to open files with unicode filenames.
This is not about the content of the file, but the file's name.
I tried the following: For testing I made a folder named C:\UnicodeTest\вячеслав and I tried creating a file inside of it, by appending the file name test.txt to the boost wpath.
For some reason the creation of the file fails. I'm using boost's fstreams and when I try to open the file, the failbit of the stream is set.
Now the funny thing is, that when I append a foldername to the path instead, a call to create_directories() succeeds and creates the correct directory C:\UnicodeTest\вячеслав\folder.
I really don't understand why it won't work with a file. This is the code I use:
boost::filesystem::wpath path;
// find the folder to test
boost::filesystem::wpath dirPath = "C:\\UnicodeTest";
vector<boost::filesystem::wpath> files;
copy(boost::filesystem::directory_iterator(dirPath), boost::filesystem::directory_iterator(), back_inserter(files));
for(boost::filesystem::wpath &file : files)
{
if(boost::filesystem::is_directory(file))
{
path = file;
break;
}
}
// create a path for the folder
boost::filesystem::wpath folderPath = path / "folder";
// this works just fine
boost::filesystem::create_directories(folderPath);
// create a path for the file
boost::filesystem::wpath filePath = path / "test.txt";
boost::filesystem::ofstream stream;
// this fails
stream.open(filePath);
if(!stream)
{
cout << "failed to open file " << path << endl;
}
else
{
cout << "success" << endl;
}
If I understand the issue correctly, the issue of being unable to create a file directly within C:\UnicodeTest\вячеслав occurs when you do not create the folder directory, as illustrated below.
// create a path for the folder
//boost::filesystem::wpath folderPath = path / "folder";
// this works just fine
//boost::filesystem::create_directories(folderPath);
// create a path for the file
boost::filesystem::wpath filePath = path / "test.txt";
I was able to get this to work by making the filename a wchar_t string:
// create a path for the file
boost::filesystem::wpath filePath = path / L"test.txt";

How do I change the execution PATH of a process programatically?

I am working on a mini-shell, and am trying to set the execution path dynamically.
I am using setvar() to set the PATH and when I check it with getvar() it reads the new PATH.
Here are the two things I tried to execute:
1. I change the PATH to /bin which I know contains most system functions, but no programs can work. I can also verify that the path has been set in the environment. I execute the commands using execvp()
2. I then used extern char** environ to get the environment and pass it into execvpe() but it still doesn't work.
I solved this by using istringstream to manually search the PATH and then use that to execute the process:
string dir;
string path = get_var("PATH");
istringstream search(path);
while(search.good()) {
getline(search, dir, ':');
if(dir != "") {
struct stat st;
if(dir[dir.length()] != '/') dir.append("/");
string file = dir + cmdArg[0];
//is file in dir?
if(stat(file.c_str(), &st) == 0) {
execvp(file.c_str(), cmdArg);
}
}
}

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.

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