============================================================================== C-Scene Issue #3 Portable Program Configuration Files Kerry D. Mathews ==============================================================================Have you ever looked at the initialization files from other programs and said: "I wish my Linux app could read init files like that?"
Well, hold your breath no longer.
In this short article, I'll go over some code that will make it possible. I've made a single function that will perform reading the configuration file, but not write. The reason is i felt it was unneccesary overhead to launch a program just to modify its configuration file. In my approach, I can use any ordinary text editor (e.g. vim), after all why re-invent the wheel.
The code, for this function, will essentially search a file for a KEYWORD and then grab corresponding VALUE.
Requirements: A function that takes two parameters, a filename, keyword, and retrieves a corresponding value. Returning an appropriate execution status (error value) is also needed.
First ponder the reasons for having to read values from a file. (hmm..)
Well, it:
For the rest of this article, I'll refer to the parameter file as: the Config File. But please remember it fills the role of an init file and a runtime parameter file.
Minor requirements are:
Again, I do things as simple as possible. I only expect to get a string value from the Config file. You can take the code and modify it to your requirements. A single entry in the Config file cannot span more (or less) than 1 line. Entries into the Config file should look like "{keyword}={value}\n" ... in psuedo code of course.
Valid entries in a Config File should look like:
scanner1=/dev/tty3a WATERHOSE=199.200.11.31 dinner_time=11pm GMT Colonels_Secret_Ingredient=saltThat looks good. Easy enough for my seven year old daughter to maintain. :)
The returned value is a NULL terminated string containing all the characters after the first "=" and up to, but not including, the '\n'.
From the examples above we can say:
For keyword: [WATERHOSE] the value is: [199.200.11.31]
For keyword: [dinner_time] the value is: [11pm GMT]
We can conclude that spaces, tabs, and other characters will be included in the value variable.
I am satisfied with the Config File and the keyword/value synergy. Let's look at the code next.
The name and prototype of our new found functions is:
int read_config_var( char *values_file, char *keyword , char value[] );
The return values are:
The meat of our function is below. You can see that it uses fgets() to fill the variable str. (oh.. yuck, the length is hardcoded) You can make your own judgements on that call. Then a string comparison between the variables 'str' and 'keyword'. If the keyword is found in str, then sprintf() is used to firmly place that value in the variable 'value'.
for(;;) { fgets(str, 80, _file); if( ferror(_file) || feof(_file) ) return(UGLY); len = strlen(str); if( strncmp(keyword, str, strlen(keyword)) == 0 ) { if (str[len - 1] == '\n') str[--len] = 0; sprintf(value, "%s", &str[strlen(keyword)+1] ); break; } }
OK. We are nearly done. The last topic is implementation. Below is an example of how our function can be used.
int main( int argc, char *argv[] ) { char * v_file = "./Secret_Addresses"; char * keyword = "Kurt Cobain"; char value[80] ; switch( read_config_var(v_file, keyword, value) ) { case 0: printf("\nValue for %s in %s is %s\n", keyword, v_file, value); break; case -1: printf("\nFile Error for [%s] \n", v_file); break; case -2: printf("\nBad User Parm for [%s] \n", keyword); break; default: printf("\nUnknown Error Occurred \n"); break; } return 0; }
Below is a sample snippet:
struct sigaction SignalAct; SignalAct.sa_handler = SigCatch; sigemptyset( &SignalAct.sa_mask ); SignalAct.sa_flags = 0; void SigCatch(int sig) { char * funct_name = "SigCatch"; if (sig == SIGUSR1) /* re - initialize daemon */ { shutdown_gracefully(); sleep(3); init_system(); } } /* end SigCatch */
Additionally; I claim no ownership, rights, or responsibilities for this code.
Final Notes: The source code for this function and examples is in values.zip. Compile by using: cc -o main main.c values.c This was written for the 2.7.2.1 gcc compiler on the 2.0.27 Linux OS.