Thursday, April 18, 2013

Run your C program using configuration files


Main idea

Instead of using command parameters for your application you can setup a config file or even multiple config files. This is the kind of code that is most useful in console application. It allows to test or run your software in various ways. In this manner you can configure strings, numbers and enable/disable flags to your application using a file you can edit in any text editor. You can change the way your application behaves without recompiling it and it can be very helpful for testing purposes. It is a very easy code to understand, and add configuration variables into.

The config file

For example use the following text in a file called configuration_1.cfg The separator character in this example is the equal sign, but it can also be colon, tab or space.
# This is a comment
# Configuration file number 1
MyFlag=Enabled
MyString=config file is useful
MyNumber=43

The coding part

First we should define the maximum length of lines we want to work with. I also like to to work with booleans as ints with values of 1 for true and 0 for false. so i will define the following.
#define MAX_LINE_LENGTH         256
#define TRUE  1
#define FALSE 0
A global configuration structure of type config_st can be used to store the parameters after they are parsed from the file. extend your application by adding additional variables that it needs to this structure.
typedef struct config_s
{
 char configFileName[60];
 int b_Flag;
 int myNumber;
 char myString[MAX_LINE_LENGTH];
}config_st;

To use this structure as a global variables add the following to your c file.

config_st g_config;

parsing the config file

The parseConfigFile function iterates over the config file line by line reading the parameters into a global config state. On each line the first word is read into the param variable and the text after the separator character is read into the value variable. the if-else if logic that comes after that handles each variable according to it's type.
void parseConfigFile()
{
 // parsing configuration file
 char next_line[MAX_LINE_LENGTH];
 char* value, *param; 
 int line = 0;
 FILE * fd = fopen(g_config.configFileName, "r");
 if (!fd) {
  //could not open the file
  return;
 }
 while (fgets(next_line, MAX_LINE_LENGTH, fd)) {
  line++;
  if ((next_line[0] == '#') || (next_line[0] == '\n')) {
   // skip
  } else {
   //read from the line into param until the first separator
   param = strtok(next_line," :=\t");
   // continue tokenizing next_line until end of line is reached
   value = strtok(NULL,"\n");
   if ( (param == NULL) || (value == NULL) ) {
    continue;
   }
   else if ( strcmp(param, "MyFlag") == 0 ) {
    setTrueIfEnabled(value, &g_config.b_Flag);
   }
   else if ( strcmp(param, "MyString") == 0 ) {
    strcpy(g_config.myString, value);
   }
   else if( strcmp(param, "MyNumber") == 0 ) {
    g_config.myNumber = atoi(value);
   }
  }
 }
 //close the file
 fclose(fd);
}

Helper functions

the setTrueIfEnabled helper function is used to set boolean flags
void setTrueIfEnabled(const char * key,int * result)
{
 if (strcmp(key, "Enabled") == 0)
  *result = TRUE;
 else
  *result = FALSE;
}

Required headers

Add the needed include files to your program.

#include <string.h>
#include <stdlib.h>

Main program example

Here is a simple main example that uses the config file parser, I hard code the file name here but it can be a command parameter if you use several configuration files.
int main(int argc, char **argv)
{
 sprintf(g_config.configFileName ,"%s", "configuration_1.cfg");
 parseConfigFile();
 printf("myNumber is %d\n",g_config.myNumber);
 printf("myString is %s\n",g_config.myString);
 printf("MyFlag is %d\n",g_config.b_Flag);
 return 0;
}

Program output

myNumber is 43
myString is config file is useful
MyFlag is 1

No comments:

Post a Comment