Loads environment variables from.env
files for C++ projects.
C++ implementation of NodeJSdotenvproject.load_dotenv()
method API inspired by Python'sPython -dotenvport of the dotenv project.
NOTE: please take into account this is still a developing project.
NONE,for sure! 😎 If it had any, it wouldn't follow the basic dotenv principles. All the needed libraries are shipped with this repository right out of the box.
Supported build methods are:
- CMake(>=3.10)
cpp-dotenvcomes with support forCMake
right out of the box. In order to use it, simply include this repository's directory and link thecpp_dotenv
target to your own targets where needed:
add_subdirectory(cpp-dotenv)
target_link_libraries(YOUR_TARGET cpp_dotenv)
After this, you might use the library as described inusage;no extra scoping, no need to worry about the project's directory structure.
To be able to use the dotenv classes, simply include the main header file:
#include"dotenv.h"
For the sake of simplycity (and if your project namespace density allows to), you can also use thedotenv
namespace under which all definitions are placed:
usingnamespacedotenv;
In order to bring your environment variables from your configuration files, simply make as many calls to theload_dotenv()
method as needed with the appropriate paths (either relative to your executable's path or absolute) and arguments.
env.load_dotenv();
Not passing any argument to the function is equivalent to tellcpp-dotenvto search for a file named.env
at the same level as the executable that is making the call to the function.
For your convenience, there is a namespace-global reference variable to thedotenv
singleton class instance namedenv
.Simply use it as you would use a dotenv object on NodeJS, or you can define your own references:
auto& dotenv = env;//'auto' here is 'dotenv::dotenv'
Theload_dotenv()
method, part ofclass dotenv
,is declared in theinclude/dotenv.h
file. Since all of its parameters have default values, it can be called with any number of arguments.
dotenv&load_dotenv(conststd::string& dotenv_path =".env",
constbooloverwrite =false,
constboolinterpolate =true);
dotenv_path
:path string, absolute or relative to the executable calling the function, of the dotenv file to be loaded. Default is".env"
.overwrite
:boolean representing whether or not to overwrite already-defined environment variables at loading time. Default isfalse
.interpolate
:boolean representing whether or not to resolve in-value variable references. Default istrue
.
A reference to theclass dotenv
this
object being used is returned, which allows for concatenating severalload_dotenv()
calls and serially load files.
Thecpp-dotenvlibrary has the following built-in features:
cpp-dotenvreports and handles four different types of errors:
- Lexer errors:errors produced by an incorrect format of the input language, i.e. usage of language features that do not belong to the dotenv syntax. This kind of errors throw irrecoverable exceptions.
- Parsing errors:errors produced by an incorrect use of the input language, i.e. the language syntax itself is correct, but it is used in an unexpected way. This kind of errors invalidate the variable they occurr in, making it to become as if it was not defined, but allowing the loading process to recover and continue.
- Circular reference errors:errors produced by variables that define a cycle of references, which are ultimately not resolved and their references are deleted from all the corresponding values. The variables they occurr in are ultimately defined as without the cycling references.
- Undefined external reference warnings:warnings produced by references to externally-loaded variables that are not present in the host environment. This variables are ultimately assigned their value as the empty string.
Escape sequence expansion happens in all of the loaded values (both string and raw form) right at the end of the loading process, after the variable resolution has already been performed.
Typical one-character escape sequences are supported (\n
,\t
,\\
,etc.). Dotenv-spefic escape sequences are:
Character | Escape sequence |
---|---|
= |
\= |
$ |
\$ |
# |
\# |
NOTE: escape sequences on externally-loaded variablesARE NOT EXPANDED.
By default, already-defined environment variables are not overwritten even if redefined in some of the loaded files.
This behavior can be changed, however, by calling theload_dotenv()
methodwith theoverwrite
parameterset totrue
.For an example on how to use it, take a look atthis one.
cpp-dotenvby default resolves variables nested inside variable definitions in the parsed files, both with those defined in the file being loaded or already present in the hosting environment itself.
- Variable reference with variables declared in thesame fileis order-independent: there's no need to worry about the declaration order of the variables inside a same file,cpp-dotenvwill resolve all of the symbols regardless of their order of declaration.
- Variable reference with variables declared ondifferent filesis order-depdendent on the loading order of the files via the
load_dotenv()
method: variables defined in later calls toload_dotenv()
are not yet visible to files being processed at a previous load and will be treated as external variables.
Variable resolution can be explicitly turned off by setting theinterpolate
parameterof theload_dotenv()
methodtofalse
.
NOTE: variable references inside externally-loaded variablesARE NOT RESOLVED.
There are two different types of supported variable references:
- Raw-style unbounded referencesof the style
$VAR_NAME
,which only support references composed by letters, numbers and underscores. Their name must start by a letter or by an underscore, and have at least one character. - Bounded references,of the style
${VAR_NAME}
,which support a wider set of character possibilities.
Assume the following.env
file:
#DB THINGS
DB_NAME=DontDoThisAtHome
DB_PASS=such_security
#CONNECTIONS THINGS
COMMAND=ping
HOST=8.8.8.8
MESSAGE="Hey buddy!"
The following.cpp
file:
#include"dotenv.h"
#include<iostream>
usingnamespacedotenv;
usingnamespacestd;
intmain()
{
env.load_dotenv();
cout <<"DB_NAME:"<< env["DB_NAME"] << endl;
cout <<"eval\ ""<< env["COMMAND"] <<""<< env["HOST"] <<"\ ""<< endl;
}
would produce the following output:
$./main
DB_NAME: DontDoThisAtHome
eval"ping 8.8.8.8"
Assuming the same.env
file as in theprevious case,the predefinedenv
reference can be easily renamed and used just exactly as the original one. Theload_dotenv()
method also returns a reference to the object it is being applied to, so it can be easily nested in a case like this.
The following code:
#include"dotenv.h"
#include<iostream>
usingnamespacestd;
intmain()
{
auto& dotenv = dotenv::env.load_dotenv();
cout <<"DB_NAME:"<< dotenv["DB_NAME"] << endl;
cout <<"eval\ ""<< dotenv["COMMAND"] <<""<< dotenv["HOST"] <<"\ ""<< endl;
}
would produce the following output:
$./main
DB_NAME: DontDoThisAtHome
eval"ping 8.8.8.8"
The situation of having several different dotenv files is no stranger one (.env
for private configuration variables,.pubenv
for public variables, etc.). Loading several files and overwritting any variables that are redefined on the files can be done as follows:
Assume the following.env
file:
#DB THINGS
DB_NAME=DontDoThisAtHome
DB_PASS=such_security
And the following.pubenv
file:
#CONNECTIONS THINGS
COMMAND=ping
HOST=8.8.8.8
MESSAGE="Hey buddy!"
The following source file:
#include"dotenv.h"
#include<iostream>
usingnamespacedotenv;
usingnamespacestd;
intmain()
{
env.load_dotenv(".env",true).load_dotenv(".pubenv",true);
cout <<"DB_NAME:"<< env["DB_NAME"] << endl;
cout <<"eval\ ""<< env["COMMAND"] <<""<< env["HOST"] <<"\ ""<< endl;
}
would produce the following output:
$./main
DB_NAME: DontDoThisAtHome
eval"ping 8.8.8.8"
Assume an environment variable${HOST}
already defined on the host environment asmyweb
and the following.env
file:
#FULL URL
URL=${URL_PROT}://${HOST}/${URL_SUBD}
#PARTIAL DEFINITIONS
URL_PROT=https
URL_SUBD=some/sub/page.html
The following.cpp
file:
#include"dotenv.h"
#include<iostream>
usingnamespacedotenv;
usingnamespacestd;
intmain()
{
env.load_dotenv();
cout <<"URL:"<< env["URL"] << endl;
}
would produce the following output:
$./main
URL: https://myweb /some/sub/page.html
- Arbitrary octal value escape sequences are not expanded.
- Arbitrary hexadecimal value escape sequences are not expanded.
- Arbitrary unicode value escape sequences are not expanded.
For the geeks, you can check the implemented grammars and all of the ANTLR-related files on thecommon/antlr/
directory.