How to read Linux environment variables in c++ - c++

In my c++ program I want to load some environment variables from the shell into some strings. How can this be done?

Use the getenv() function - see http://en.cppreference.com/w/cpp/utility/program/getenv. I like to wrap this as follows:
std::string GetEnv( const std::string & var ) {
const char * val = std::getenv( var.c_str() );
if ( val == nullptr ) { // invalid to assign nullptr to std::string
return "";
}
else {
return val;
}
}
which avoids problems when the environment variable does not exist, and allows me to use C++ strings easily to query the environment. Of course, it does not allow me to test if an environment variable does not exist, but in general that is not a problem in my code.

Same as in C: use getenv(variablename).

You could simply use char* env[]
int main(int argc, char* argv[], char* env[]){
int i;
for(i=0;env[i]!=NULL;i++)
printf("%s\n",env[i]);
return 0;
}
here is a complete article about your problem, from my website.

Related

C++ Dynamic Variable

Sorry for not knowing much about C++. There is a problem I can't solve. I want the CONFIG_PATH variable to be dynamic, not fixed. I want it to be replaceable from the outside, but I've never been able to.
string custom_path;
custom_path= argv[i];
I want to replace CONFIG_PATH with custom_path. Or I want to set it as CONFIG_PATH + custom_path
#define CONFIG_PATH "D:/config"
int GetConfigPath(char *path, size_t size, const char *name)
{
if (!OBS_UNIX_STRUCTURE && portable_mode) {
if (name && *name) {
return snprintf(path, size, CONFIG_PATH "/%s", name);
} else {
return snprintf(path, size, CONFIG_PATH);
}
} else {
return snprintf(path, size, CONFIG_PATH "/%s", name);
}
}
I want the CONFIG_PATH variable to be dynamic
CONFIG_PATH isn't a variable in the example. It is a pre-processor macro. It isn't possible to change pre-processor macros at runtime.
You can replace the macro with a variable whose value can be changed at runtime. Example:
std::string CONFIG_PATH;
int main(int argc, char** argv)
{
CONFIG_PATH = argv[i];
As a side-note: Global variables are potentially problematic. Consider alternative designs like for example passing the value as a parameter into the function.
If you remove the #define and instead use std::getenv("CONFIG_PATH") you can export (or whatever it's called in your shell) an environment variable named CONFIG_PATH that you can then read in your program. You must export it before running the program and any changes you make to it outside of your program will not be visible.
You can not concatenate it with other strings like you currently do with the macro though.
const char* config_path = std::getenv("CONFIG_PATH");
if(config_path) {
std::string path_to_foo = std::string(config_path) + "/foo";
// use path_to_foo ...
}

C++ Wrapper to GNU Readline

I am trying to write a c++ wrapper for GNU Readline to be able to easily use custom completion but came across a small problem and can't think of a solution(I am still new to c++).
class ReadLine {
public:
ReadLine();
~ReadLine();
std::string exec ();
void enableHistory ();
private:
std::vector<std::string> keywordList;
bool history;
private:
static char** my_completion (const char*, int, int);
void* xmalloc (int);
char* generator (const char*, int);
char* dupstr (std::string);
};
cpp file:
std::string ReadLine::exec(){
rl_attempted_completion_function = my_completion;
std::string buf = "";
buf = readline("Command>>");
//enable auto-complete
rl_bind_key('\t',rl_complete);
if (buf[0]!=0)
add_history(buf.c_str());
return buf;
}
char** ReadLine::my_completion (const char* text, int start, int end) {
char** matches;
matches = NULL;
if (start == 0)
matches = rl_completion_matches(text, my_generator);
return matches;
}
My problem is the line
matches = rl_completion_matches(text, my_generator)
It obviously throws an error: call to non-static member function without an object argument but I don't want to make the generator static and I can't find what arguments it should take, because I won't be able to access class members inside of it (I need keywordlist to generate keywords).
What would you suggest?
It's not easy to solve this one in a good way, since the normal solution is to solve it by having a static wrapper function where you pass the pointer to the class in as an argument.
Someone else may be able to come up with something better, but I think the solution is to have a global variable that is a pointer to the current ReadLine class instance - this could be a stack, so you can push a new one onto it, and then pop it to get back to the old one when that's done.
In the simple case, you'd have something like this:
ReadLine *currenReadLine = 0;
....
std::string ReadLine::exec(){
...
currentReadLine = this;
}
// declared as static in the class.
char ** ReadLine::my_completion(...)
{
return currentReadLine->actual_completion(...);
}
And a similar solution for the my_generator.

How to initialize glut with fake parameters?

I'm using opengl, using the GLUT and GLEW libraries to create a plugin for a certain application.
This plugin doesn't start with a simple int main(argc, argv). So i can't pass these values to glutInit().
I tried something like this:
glutInit(0, NULL); <--- Crash
GLenum err = glewInit();
But i crashed when it tried to call the glutInit() function. Can i reconstruct those params some how, so that it won't crash and still be able to use the Glut library..??
You can do it like this :
#include <GL/freeglut.h>
int main()
{
char fakeParam[] = "fake";
char *fakeargv[] = { fakeParam, NULL };
int fakeargc = 1;
glutInit( &fakeargc, fakeargv );
//...
}
but take a note that it is an ugly hack.
You might have to call glutInit with a valid argv parameter, even if you don't have any:
char *my_argv[] = { "myprogram", NULL };
int my_argc = 1;
glutInit(&my_argc, my_argv);
Edit
It might also be that the first parameter is a pointer to an int, and it can't be NULL? Then it might be enough to only pass a valid argc parameter:
int my_argc = 0;
glutInit(&my_argc, NULL);
Note the following code from the source (freeglut_init.c:677):
void FGAPIENTRY glutInit( int* pargc, char** argv )
{
char* displayName = NULL;
char* geometry = NULL;
int i, j, argc = *pargc;
...
(Note the dereferencing.)
It seems that glutInit() does require a minimum of the process name, although the man page doesn't shed any light on this.
I propose this as a de-facto standard for initializing glut applications.
static inline void glutInstall()
{
char *glut_argv[] = {
"",
(char *)0
};
int glut_argc = 0;
glutInit(&my_argc, my_argv);
}
This function can be modified on per-application basis to provide glut with the arguments it needs(if any), while permanently solving the issue of everyone asking why you are passing command line arguments to a 3rd party library.

Interchanging const char* and std::string

I am refactoring an old C library, and am currently changing the external API so that it uses std::string instead of const char*.
ColumnType Table::getColType(const char *name) const
{
int id = getColumnId(name) ;
return getColType(id) ;
}
and
int Table::getColumnId (const char * col_name) const
{
unsigned int i = 0;
while ((i < m_table.num_cols) && (strcmp(m_table.cols[i]->name, col_name) != 0) )
i++;
if (i < m_table.num_cols)
return i;
else
return -1;
}
To:
ColumnType Table::getColType(const std::string& name_in) const
{
const char* name = name_in.c_str();
int id = getColumnId(name) ;
return getColType(id) ;
}
and
int Table::getColumnId (const std::string& col_name_in) const
{
const char* col_name = col_name_in.c_str();
unsigned int i = 0;
while ((i < m_table.num_cols) && (strcmp(m_table.cols[i]->name, col_name) != 0) )
i++;
if (i < m_table.num_cols)
return i;
else
return -1;
}
In the new code, I am passing a const char* to functions that are now expecting a reference to const std::string. I know std::string can be initialised from a const char*, and the code compiles correctly (no warnings etc).
But I just want to make sure that I am not doing anything that will come to bite me later on (I18n issues aside).
In short - is what am doing "safe"?
It's safe, in so far as, executed correctly, it shouldn't cause any harm.
Nevertheless, I don't think I would recommend going forward with this unless you can point to a substantial benefit.
What may be safer is to add a function that takes in the const string&, and does a straight pass-thru to the const char* function. That way, you're letting clients stay in terms of std::string& code without modifying the internals.
For example:
ColumnType Table::getColType(const std::string& name_in) const
{
return getColType(name_in.c_str());
}
1) No need in getColType to get the c_str() from the std::string, just pass the std::string& directly into getColumnId.
2) You should use the overridden equality operator or use std::string::compare directly instead of strcmp. See
Beware of std::strings containing NULLs. The C++ class is fine with them; NULL is not special. But C strings of course treat it as end-of-string. The The following are not the same:
if (std_string_a == std_string_b) { /* C++ way */ }
// vs.
const char *cstring_a = std_string_a.c_str(),
*cstring_b = std_string_b.c_str();
if (0 == strcmp(a, b)) { /* C way */ }
When you mix and match, you have to worry about weird bugs arising when the C++ way says false, yet the C way says true.

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.