Config files in NeL provide you with a powerful way to set up your programs at runtime. There are two parts to working with config files: the config file format and the CConfigFile class. There is a fantastic sample for this, so feel free to look in the samples directory for more hands on information. NeL makes working with config files a breeze so we'll cover the code portion first.
Most of the work done on a config file will be done through the CConfigFile class.
CConfigFile cf;
cf.load("myconfig.cfg");
int var1 = cf.getVar("var1").asInt();
Retrieving variables from the config file is almost that simple. The config file system allows you to convert config file values to a variety of types:
Type | Conversion Method |
---|---|
int | asInt() |
double | asDouble() |
float | asFloat() |
string | asString() |
bool | asBool() |
This covers the essentials of working with config files but there's a whole lot more to config files. You can work with arrays in config files as well. When a parameter in the config file is declared as an array you can access it using the size method and then the asInt(int) method. You're not locked in to asInt, though, you can use all of the type conversion methods - the int parameter is what is important. Here is an example of accessing an array from the config file:
for (int i = 0; i < cf.getVar("myArray").size(); ++i)
{
nlinfo("this is member %d of the array: %s", i, cf.getVar("myArray").asString(i).c_str());
}
You can see above that I was able to get the "myArray" variable and convert a specific member of it to the string type.
Something that is important to note: if you try to get a variable that doesn't exist or convert it to a type that NeL cannot convert it to (such as trying to convert a string to an integer) the config file system will throw the exception EConfigFile. If you are loading config files that may be changed or accessing variables that may not be in the config file it is highly recommended that you place you getVar calls within a try/catch block to compensate for potential config file errors.
The config file system allows you to update existing config files. The benefit to this is that you can update or fix config files from within your code automatically. There is only one downside to writing a config file from code: any formatting that you have in the config file and any comments you have are completely lost. With that said, here is a quick example of how you can set a config file variable and save it:
// Set a variable with an integer value.
cf.getVar("myVariable").setAsInt(65536);
// Create an array or strings.
std::vector<std::string> foo;
foo.push_back("test");
foo.push_back("bar");
cf.getVar("myArray").setAsString(foo);
// Call this method to save the config file:
cf.save();
One last thing that config files allow you to do is monitor whether a file or variable has changed. This is useful if you want to drive runtime activity from the file or automatically adopt changes from the config file. The config file system provides two ways of monitoring changes to the config file system - by config file or by config file variable. To implement these you will need to create a function that can be called by the config file system in the event of a change.
By Config File
void myCallbackName()
By Config File Variable
void myVariableCallbackName(CConfigFile::CVar &var)
Once you have defined the methods you are interested in you simply need to register the callback with the config file system:
// For config file wide changes
cf.setCallback(myCallbackName);
// For config file variable specific changes
cf.setCallback("myVariable", myVariableCallbackName);
The config file class also has a few options to help you out. One of the handiest ones is the UnknownVariables
public member. This vector of strings lists all of the variables that were requested but not found in the config file. You can use this method during troubleshooting to see if you have a misconfigured config file or to see what variables your code is calling that are not found. This can be extremely handy for finding typos within your code.
Also handy for troubleshooting is the display()
public method. Call this method to make the config file system print out all of the variables that it loaded to to the InfoLog.
The config file format uses C++ style comments:
// This is a comment in the config file.
/*
* And so is this!
*/
Really the format for a config file is pretty straight forward. Here is a good example:
var1 = 123; // var1 type:int, value:123
var2 = "456.25"; // var2 type:string, value:"456.25"
var3 = 123.123; // var3 type:real, value:123.123
// the resulting type is type of the first left value
var4 = 123.123 + 2; // var4 type:real, value:125.123
var5 = 123 + 2.1; // var5 type:int, value:125
var6 = (-112+1) * 3 - 14; // var6 type:int, value:-347
var7 = var1 + 1; // var7 type:int, value:124
var8 = var2 + 10; // var8 type:string, value:456.2510 (convert 10 into a string and concat it)
var9 = 10.15 + var2; // var9 type:real, value:466.40 (convert var2 into a real and add it)
var10 = { 10.0, 51.1 }; // var10 type:realarray, values:{10.0,51.1}
var11 = { "str1", "str2", "str3" }; // var11 type:stringarray, values:{"str1", "str2", "str3"}
var12 = { 133, -1 }; // var12 type:intarray, values:{133,-1}
var13 = { 1, 0.5, -1 };