External Objects Across CPP files (Boost Filesystem/Variants, Libconfini) - c++

I've got a deceptively complex one for y'all.
I am attempting to make a program which makes use of an INI config file (I am using the libconfini C library), which looks like this:
[General]
output_directory = /scratch/miles/trans_assembly_pipeline/
[SRA accessions]
SRR18328591
SRR28481881
It parses the information therein into a map, index-able by section, and then by key, which looks like this (the only important bit really is the char* option in the variant object):
map<string, map<string, boost::variants<int, bool, double, string, char*>>
Since keys in INI files can have various types, I am utilizing Boost's 'Variants' library to allow for multiple value types. Finally, for convenient file management, I am using Boost's 'Filesystem' library.
I have an INI parsing implementation file, which basically just stores the INI data into that map type, defined thus (the header for which, merely containing function declarations and definition directives, can be found at the bottom):
#include "ini_parse.h"
namespace fs = boost::filesystem;
// Dispatch INI data to a map, indexable by sections, then by keys
static int ini_callback(IniDispatch * const dispatch, void * map_pt) {
#define thismap (reinterpret_cast<INI_MAP*>(map_pt))
if (dispatch->type == INI_COMMENT) {
return 0;
}
if (dispatch->type == INI_SECTION) {
INI_MAP_ENTRY newSec;
thismap->insert(std::pair<std::string, INI_MAP_ENTRY>(dispatch->data, newSec));
return 0;
}
if (dispatch->type == INI_KEY) {
(*thismap)[dispatch->append_to].insert(std::pair<std::string, BOOST_VAR>(dispatch->data, dispatch->value));
}
return 0;
}
// Given a FILE object, return a buffer containing its contents
char * make_ini_buffer(FILE * iniFile) {
char * iniBuffer;
long sz;
fseek(iniFile, 0L, SEEK_END);
sz = ftell(iniFile);
rewind(iniFile);
iniBuffer = (char*)malloc(sz + 1);
fread(iniBuffer, 1, sz, iniFile);
return iniBuffer;
}
// Given the path/name of an INI config file, return a map of its data
// which can be indexed by sections, and then by keys
INI_MAP make_ini_map(const char * configPath) {
FILE * configIni = fopen(configPath, "r");
fs::path configPathObj(configPath);
try {
if (!configIni) {
std::string fileError = "ERROR: Cannot open config file: ";
throw std::runtime_error(fileError);
}
} catch (std::runtime_error& e){
std::cerr << e.what() << configPathObj.filename() << std::endl;
return {};
}
INI_MAP iniMap;
char * iniBuffer = make_ini_buffer(configIni);
strip_ini_cache(iniBuffer, strlen(iniBuffer), INI_DEFAULT_FORMAT,
NULL, ini_callback, &iniMap);
delete [] iniBuffer;
return iniMap;
}
INI_MAP cfgIni = make_ini_map("../config.ini");
Note the final line, outside of any other function, defining 'cfgIni'. The idea is to define a global INI data storage object that can be used externally by other files -- for example, like this:
#include "ini_parse.h"
int main() {
extern INI_MAP cfgIni;
extern int size_path;
std::cout << cfgIni["General"]["output_directory"] << std::endl;
return 0;
}
Now for my problem: When declaring 'cfgIni' externally in this separate file, it appears that bits of memory are getting lost from where it is defined in my implementation file to where it is declared externally and caught here. I have no issue accessing the keys in the parent/child map, but the values are more illusive.
When printing the contents of the section "General", "output_directory" is returned, no problem.
I would expect the final line in the above code snippet to print the filepath char* array, to which "output_directory" is set in the INI file.
However, I instead get some random characters, like "�U". What is even more confusing is when I print out the size of this return value in memory using sizeof(), it returns '40', the correct number of characters in that filepath.
I have linked the documentation for the libraries I used and their functions. Apologies for the length/complexity of this question.
strip_ini_cache(): https://madmurphy.github.io/libconfini/html/confini_8c.html#a25d648d387f6e8bc36e7965accfca63b
Boost.variant: https://www.boost.org/doc/libs/1_61_0/doc/html/variant.html
Boost.filesystem: https://www.boost.org/doc/libs/1_80_0/libs/filesystem/doc/reference.html
Below is my header file:
#include <iostream>
#include <string>
#include <map>
#include <cstdio>
#include <confini.h>
#include <boost/filesystem.hpp>
#include <boost/variant.hpp>
#define BOOST_VAR boost::variant<int, bool, double, std::string, char*>
#define INI_MAP_ENTRY std::map<std::string, BOOST_VAR>
#define INI_MAP std::map<std::string, INI_MAP_ENTRY>
static int ini_callback(IniDispatch * const dispatch, void * map_pt);
char * make_ini_buffer(FILE * iniFile);
INI_MAP make_ini_map(const char * configPath);

The answer to this is really quite trivial. When passed by value, as I had done in one of my files, a shallow copy of the object was created, wherein the pointers to the char arrays were overwritten with wild addresses.
The solution was to pass by const reference.

Related

How to check char array contain any char without loop in C++?

I'm using the opendir and readdir functions to search for file names containing .txt in the given directory.
Is there any way I can test a certain extension via a function without using a loop? (currently I have to loop through de-> d_filename to check but they are quite complicated, in addition I tried de->d_type however it did not return the extension)
In addition, this function is returning the name of the file name, my desired result is to get the path name from the beginning, is there a function return wchar_t* similar to de->d_fullfilepath?
This is all I have :
DIR* dr = opendir(lpszFolder);
vector<const wchar_t*> names; //get list file with extension .txt then push to this vector
if (dr == NULL) // opendir returns NULL if couldn't open directory
{
printf("Could not open current directory");
return {};
}
// Refer http://pubs.opengroup.org/onlinepubs/7990989775/xsh/readdir.html
// for readdir()
while ((de = readdir(dr)) != NULL)
{
if (de->d_type ... 'txt') // function get just .txt file.
{
wchar_t* pwc =new wchar_t(lpszFolder); //initialize new instance file path
const size_t cSize = de->d_namlen + 1; //get file len
mbstowcs(pwc, de->d_name, cSize); //combine thisfilepath + extension
names.push_back(pwc);
}
}
Best Libc function to search reversely
You might consider strrchr
Locate last occurrence of character in string
Returns a pointer to the last occurrence of character in the C string str.
The terminating null-character is considered part of the C string. Therefore, it can also be located to retrieve a pointer to the end of a string.
Sample Program to find files with specific file extension
#include <string.h>
#include <sys/types.h>
#include <dirent.h>
#include <string>
#include <vector>
using namespace std;
const char *get_filename_ext(const char *filename) {
const char *dot = strrchr(filename, '.');
return (!dot || dot == filename) ? "" : dot + 1;
}
int main(int ac, char **av) {
if (ac != 2)
return 1;
const char *lookup = (ac==3) ? av[2] : "txt";
const char *lpszFolder = av[1];
DIR* dr = opendir(lpszFolder);
vector<const wchar_t*> names; //get list file with extension .txt then push to this vector
if (dr == NULL) // opendir returns NULL if couldn't open directory
{
printf("Could not open current directory");
return (1);
}
struct dirent *ent;
uint32_t len = sizeof(((dirent*)0)->d_name);
char ext[len];
while ((ent = readdir (dr)) != NULL) {
(void)ext;
strncpy(ext, get_filename_ext(ent->d_name), len-1);
if (!strcmp(lookup, ext))
names.push_back(reinterpret_cast < wchar_t*>(ent->d_name));
}
closedir(dr);
for (auto name : names)
printf("%s", (char *)name);
return 0;
}
Main Usage
Test with:
g++ a.cpp && ./a.out myfolder
will look for all files with ".txt" extensions
Or if you want a specific extension like ☠ :
g++ a.cpp && ./a.out myfolder ☠
In modern C++ you should use algorithms from the std::algorithm library to avoid loops. These algorithms prevent many possible problems from the wrong usage of loops, mostly out of bounds problems.
And, C++ can deal with "wide strings" with the base data type wchar_t. You can simply use std::wstring instead of std::string.
Any you should not and never use plain C-Style arrays or pointers to char or wchar_t. These are that error prone that they should really not be used.
Even if you have legacy code with "old" "char*"-strings, put them into a std::string and use those in the future.
Next: You MUST NOT use raw pointers for owned memory. You should try to avoid pointers in general and use smart pointers instead. And you should not use new in C++. There is nearly no need for it any longer. Use containers from the STL.
Now back to your original question:
How to check char array contain any char without loop in C++?
Yes, by using std::algorithmsand iterators
Is there any way I can test a certain extension via a function without using a loop?
Yes, ths std::filesystem will help you. It has all the functionality you need and is superior to all handcraftedt solutions. It can especially also deal with wchar_t and wide stringsstd::wstring
In the following code, I generated an example function that returns a std::vector filled with all fule file paths in a specified directory with a given string.
#include <iostream>
#include <string>
#include <filesystem>
#include <vector>
#include <algorithm>
// Name space alias for saving typing work
namespace fs = std::filesystem;
// A function, that gets a path to a director as wstring and returns all file paths as wstring with a given extension
std::vector<std::wstring> getFilesWithCertainExtension(const std::wstring& dirPath, const std::wstring& extension = L".txt") {
// Put the wstring with path to the the directory in a generic path variable
fs::path startPath{ dirPath };
// Here we sill store all directory entries having a given extension
std::vector<fs::directory_entry> filesInDirectory{};
// Go thorugh the directory and copy all directory entries with a given extension int our vector
std::copy_if(fs::directory_iterator(startPath), {}, std::back_inserter(filesInDirectory),
[&](const fs::directory_entry& de) { return de.path().extension().wstring() == extension; });
// The result of this function should be a vector of wstrings
std::vector<std::wstring> result(filesInDirectory.size());
// Convert directory entries to wstrings
std::transform(filesInDirectory.begin(), filesInDirectory.end(), result.begin(),
[](const fs::directory_entry& de) { return de.path().wstring(); });
return result;
}
int main() {
// Read all files from c:\\temp with the default extension ".txt"
std::vector<std::wstring> files = getFilesWithCertainExtension(L"c:\\temp");
// Show full paths to user
for (const std::wstring& ws : files) std::wcout << ws << L"\n";
return 0;
}
This is one of many possible solutions. This could even be optimized, if I would understand your requirements better.
I would explain the function in more detail. But, becuase anyway nobody will read this, I save the time.

Creating a custom iterator struct to work with cstdio

I'm trying to create a iterator to go through my file. My file is binary and have int values inside, so in my point of view, it should work like that. But I'm getting errors says "invalid use of data-member 'IntFile::file' "So i marked in code where I'm getting errors. How can I manage it?
#include <iostream>
#include <cstdio>
using namespace std;
class IntFile
{
public:
int index;
FILE* file; // Error here
IntFile() {}
~IntFile() {}
int mnumbers[10];
int mnumbers2[10];
int value;
// And this whole class does not work
class iterator
{
bool operator ++ ()
{
file = fopen ("text.txt", "r+b");
fseek (file, 4*index, SEEK_CUR);
fclose(file);
}
bool operator -- ()
{
file = fopen ("text.txt", "r+b");
fseek (file, (-4)*index, SEEK_CUR);
fclose(file);
}
/*
iterator begin()
{
return ;
}
iterator end()
{
return ;
}
*/
};
};
I'm getting errors says "invalid use of data-member 'IntFile::file'"
IntFile::iterator doesn't have a data member file, nor does it implicitly have a reference to an instance of IntFile (as would be the case in, say, Java).
IntFile::iterator needs a reference to IntFile to be able to use that data member:
class iterator
{
explicit iterator(IntFile &file) : file(file) {}
// Your other code
private:
IntFile &file;
};
Then you will be able to access file.file, file.index, etc.
However, this will break down if you create multiple iterators and expect them to point to different places in the file because with this approach they all share a single file handle, and therefore a single position within that file. You can have each iterator keep track of its own position and seek there before each operation (not thread-safe) or you can duplicate the file handle for each iterator (consumes an additional file descriptor per iterator).
Or, it may be much easier to just memory-map the file and use a pointers into the mapped address space as your iterators.

Header file refresh/update

I'm having some trouble using header files.
I would like to "refresh" a .h file, in order to update all the values of the constants in it which depend on an extern variable (defined in the main .cc file).
This is approximately the situation:
Header file (header.h)
extern int extern_value;
const int one = value;
const int two = value * 2;
const int three = value * 3;
Main program
#include "header.h"
int extern_value;
int main(){
extern_value = 10;
// Here is where I would like to refresh the header file.
// Here is where I would like to have my dependant constants
// (one, two and three) being updated.
return 0;
}
Please consider that this is an extreme approximation of the problem.
Do you guys have any idea about how to solve it?
Thanks in advance.
EDIT:
This is my actual problem:
I would like to have a header file which contains all the graphical constants that my project needs. They ALL depend on the size of the display. The first thing that the main program does is getting information about the display size; THEN, I would like the program to "export" this information on the header file, so it can calculate all the graphical constants relatively to the size of the display.
You can't do this. For a variety of reasons, but not least because your variables are const, and the expression you use to compute a value to be assigned to them is not continually re-evaluated.
What you want is to use functions:
extern int extern_value;
int one() { return extern_value; }
int two() { return extern_value * 2; }
int three() { return extern_value * 3; }
Other notes:
You probably shouldn't have an extern variable for this. Pass value to the function instead:
int one(const int value) { return value; }
int two(const int value) { return 2 * value; }
int three(const int value) { return 3 * value; }
int main() {
int value = 10;
std::cout << one(value) << " " << two(value) << "\n";
return 0;
}
You can't "refresh" a header file. The content of the file is what you typed, and this is included (effectively, pasted into) the source file when you use #include "my_header.h". You can update the value associated with non-const variables, but if you want to repeatedly evaluate an expression with different values, the best way is to turn that expression into a function as shown above, and call the function with different parameters.
You'll probably need to either move the function definitions from the header to a source file, or mark them as inline, otherwise you may be warned (or receive errors) about multiple definitions if you use the same header in multiple source files.
To address your actual problem, if you need to expose information through extern variables, you'll need to make them non-const, and have your main() function initialise them, or do so during static initialisation. There are a number of issues to be aware of when doing this, so it's much safer to provide functions that compute the geometry accordingly, and base those computations on one or two function arguments, or a small number of extern variables that are statically initialised to something safe, then set appropriately once the information becomes available. Further details can be obtained by searching for e.g. static initialisation or extern variables.
In this case, you may wish to consider creating a class to hold your geometry and perform the relevant computations. A pointer to an instance of this class can be created as an extern variable, and initialised on program initialisation (i.e. statically). You can then provide the derived "constants" as member functions which calculate their result based on a small number of encapsulated values, which can be set / updated if necessary. You can even make it such that these are const, if you're careful.
See, for instance the example below (live demo):
// ******** HEADER FILE ********
class Geometry {
public:
Geometry(const int rows, const int cols)
: rows_(rows), cols_(cols) {}
int rows() const { return rows_; }
int cols() const { return cols_; }
int pixels() const { return rows_ * cols_; }
// whatever other "constants" you need, defined as functions
// containing expressions based on rows_ and cols_.
private:
// Make copy constructor & assignment operator private to prevent copying
Geometry(const Geometry&);
Geometry& operator=(const Geometry&);
// The data from which everything else is calculated
const int rows_;
const int cols_;
};
extern const Geometry* the_geometry;
// ******** SOURCE FILE ********
#include <iostream>
int main() {
const int rows = 80; // or however you get the number of rows
const int columns = 25; // or however you get the number of columns
the_geometry = new Geometry(rows, columns);
std::cout << the_geometry->pixels() << "\n";
return 0;
}
const Geometry* the_geometry = nullptr;

Creating a global FILE* object?

I'm building a program that has several functions that need to read data from a file. Since the functions are used fairly frequently, opening and closing the file for each call would be too time consuming, so my plan was to make the FILE* object global, and have the file open the whole duration of the program. Apparently, though, it's not possible, since this:
#include <fstream>
FILE * yhtit;
yhtit = fopen("thefile.txt","r");
int main() {
return 0; }
gives error: main.cpp|54|error: expected constructor, destructor, or type conversion before ‘=’ token|
What's the best way to keep a file open the whole duration of the program, without having to separately pass the FILE* object to every function that needs it?
You almost got it right. Try this:
#include <fstream>
FILE * yhtit;
int main() {
yhtit = fopen("thefile.txt","r");
//Do your thing here.
fclose(yhtit);
return 0;
}
It'd be better to pass the FILE pointer to your functions than to create a global variable. Global variables are often code smells—signs of questionable coding. You can pass the file to your functions without having to open and close the file multiple times. For example:
#include <stdio.h>
void readData(FILE *);
void readMoreData(FILE *);
int main() {
FILE *fp = fopen("...", "r");
readData(fp);
readMoreData(fp);
fclose(fp);
return 0;
}
#include <fstream>
FILE * yhtit = fopen("thefile.txt","r");
int main() {
return 0; }
You can maintain the File * variable in a structure and make that structure accessible from any function.
typedef struct
{
FILE *fp;
//other members can also be part of this structure.
}myData;
appInit(myData *ptr)
{
ptr->fp = fopen(<>,<>);
//Initialise other variables also
return;
}
appDeInit(myData *ptr)
{
fclose(ptr->fp);
}
main()
{
myData *ptr= malloc(sizeof(myData));
appInit(ptr);
//Play with ptr in all your function calls
foo(ptr);
appDeInit(myData);
}

C++: Define simple constant for use?

In C++ I wanted to define a constant that I can use in another function, A short answer on how to do this will be fine..
Lets say at the beginning of my code I want to define this constant:
//After #includes
bool OS = 1; //1 = linux
if (OS) {
const ??? = "clear";
} else {
const ??? = "cls";
}
I don't know what type to use to define the "clear" string... I'm so confused.
Later on I want to use it within a function:
int foo() {
system(::cls); //:: for global
return 0;
}
How would I define the string up top, and use the string down below? I heard char only had one character and things... I'm not sure how to use , since it says it's converting string into const char or something.
char* isn't quite a char. char* is basically a string (it's what strings were before C++ came along).
For illustration:
int array[N]; // An array of N ints.
char str[N]; // An array of N chars, which is also (loosely) called a string.
char[] degrades to char*, so you'll often see functions take a char*.
To convert std::string to const char*, you can simply call:
std::string s;
s.c_str()
In this case, it's common to use the preprocessor to define your OS. This way you can use the compiler to do the platform specific stuff:
#ifdef OS_LINUX
const char cls[] = "clear";
#elif OS_WIN
const char cls[] = "cls";
#endif
One thing you may want to consider is making it a function. This avoids nasty dependencies of global construction order.
string GetClearCommand() {
if (OS == "LINUX") {
return "clear";
} else if (OS == "WIN") {
return "cls";
}
FAIL("No OS specified?");
return "";
}
What it looks like you're trying to do is this:
#include <iostream>
using namespace std;
#ifdef LINUX
const char cls[] = "LINUX_CLEAR";
#elif WIN
const char cls[] = "WIN_CLEAR";
#else
const char cls[] = "OTHER_CLEAR";
#endif
void fake_system(const char* arg) {
std::cout << "fake_system: " << arg << std::endl;
}
int main(int argc, char** argv) {
fake_system(cls);
return 0;
}
// Then build the program passing your OS parameter.
$ g++ -DLINUX clear.cc -o clear
$ ./clear
fake_system: LINUX_CLEAR
Here's the problem, you're suffering from going out of scope with the variables. If I declare something within brackets, it only exists within the brackets.
if( foo ){
const char* blah = "blah";
}
Once we leave the if statement, the variable blah disappears. You'll need to instantiate it non-locally to whatever brackets you write. Hence:
void Bar(){
const char* blah = "blah";
if( foo ){
//blah exists within here
}
}
However, blah will not exist outside of Bar. Get it?
Yet another option is to create a class with a bunch of static methods. Create a new method for each command. Something like:
// in sys-commands.h
class SystemCommands {
public:
static char const* clear();
static char const* remove();
};
This gives you a few nice options for the implementation. The nicest one is to have a separate implementation file for each platform that you select during compile time.
// in sys-commands-win32.cpp
#include "sys-commands.h"
char const* SystemCommands::clear() { return "cls"; }
char const* SystemCommands::remove() { return "erase /f/q"; }
// in sys-commands-macosx.cpp
#include "sys-commands.h"
char const* SystemCommands::clear() { return "/usr/bin/clear"; }
char const* SystemCommands::remove() { return "/bin/rm -fr"; }
Which file gets compiled will determine which command set will be used. Your application code will look like:
#include <cstdlib>
#include "sys-commands.h"
int main() {
std::system(SystemCommands::clear());
return 0;
}
Edit: I forgot to mention that I prefer static functions to global constants for a bunch of reasons. If nothing else, you can make them non-constant without changing their types - in other words, if you ever have to select the command set based on runtime settings, the user code does not have to change or even be aware that such a change occurred.
You can use a common header file and link to different modules depending on the systen:
// systemconstants.hpp
#ifndef SYSTEM_CONSTANTS_HPP_INCLUDED
#define SYSTEM_CONSTANTS_HPP_INCLUDED
namespace constants {
extern const char cls[]; // declaration of cls with incomplete type
}
#endif
In case of Linux, just compile and link to this one:
// linux/systemconstants.cpp
#include "systemconstants.hpp"
namespace constants {
extern const char cls[] = "clear";
}
In case of Windows, just compile and link to this one:
// windows/systemconstants.cpp
#include "systemconstants.hpp"
namespace constants {
extern const char cls[] = "cls";
}
System-specific translation units could be placed in specific subdirectories (linux/, windows/, etc) of which one could be automatically selected during the build process. This extends to many other things, not just string constants.