LinuxQuestions.org
Review your favorite Linux distribution.
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices



Reply
 
Search this Thread
Old 11-11-2004, 09:45 AM   #1
kadissie
LQ Newbie
 
Registered: Jul 2003
Location: UK
Distribution: Fedora 5, Knoppix, Ubuntu
Posts: 27

Rep: Reputation: 15
config file parsing in C/C++


I'm looking for a robust, flexible way of reading a configuration file into my C++ program. By "reading a configuration file" I mean taking a file with bash-like variable syntax
Code:
foo=bar
and assigning the value bar to a C++ variable associated with the string "foo".

I know about popt(3) which reads in command line parameters, and this is heart-stoppingly close to what I want - I just don't want to have to code and debug the wrapper that turns bash-like variables into a command-line string. Or write a messy script that turns the variables into a command-line string.

Thanks,
R.
 
Old 11-11-2004, 09:47 AM   #2
kadissie
LQ Newbie
 
Registered: Jul 2003
Location: UK
Distribution: Fedora 5, Knoppix, Ubuntu
Posts: 27

Original Poster
Rep: Reputation: 15
I'm not fussy about config file formats though - I'd be perfectly happy to use something like the Apache config file, but I must be able to read in all C++ builtin data types.

R.
 
Old 11-11-2004, 04:59 PM   #3
johnMG
Member
 
Registered: Jul 2003
Location: CT, USA
Distribution: Debian Sarge (server), Etch (work/home)
Posts: 601

Rep: Reputation: 31
Have you tried rolling your own using C++? I'd be curious to see just how messy it comes out to be. I wrote my own for a small program I'm working on, and it's pretty kludgey waiting for me to improve it.
 
Old 11-11-2004, 06:33 PM   #4
johnMG
Member
 
Registered: Jul 2003
Location: CT, USA
Distribution: Debian Sarge (server), Etch (work/home)
Posts: 601

Rep: Reputation: 31
Ok, well, this is probably way longer than it needs to be, but here's my program's code for parsing its config file. The file consists of lines containing one word, then a number (or three numbers) separated by spaces. Like this:

Code:
light_pos  60.0    0.0   60.0
eye_pos    50.0   10.0   11.0
looking_at  0.0   15.0    0.0
near  20.0
far   80.0
angular_view_width  45.0
Please note that this code is just a first try, and may even be the wrong approach for this. If anyone sees a better way to do this with C++, please let me know.

Code:
void Viewing_geometry::read_in_viewing_params( string file_name )
{
    ifstream config_file( file_name.c_str() );
    
    string line;              // We'll be reading in one line at a time,
    string temp_word;         // examining 1st word in that line.
    string temp_ascii_double; // This is for converting the numerical values to doubles.
    
    vector<double> vec; // We store the parameter's values in this vector.
    double temp_double;
    
    // Possible number separators are space or tab.
    const string delims( " \t" );
    
    // All the possible params that may be in the config.txt file, *in order*.
    vector<string> params;
    params.push_back( "light_pos" );
    params.push_back( "eye_pos" );
    params.push_back( "looking_at" );
    params.push_back( "near" );
    params.push_back( "far" );
    params.push_back( "angular_view_width" );
    
    while ( getline ( config_file, line ) ) // One line, 1 viewing parameter.
    {
        // Be sure to use string::size_type so we can safely compare to string:npos.
        string::size_type beg_idx, end_idx;
        
        beg_idx = line.find_first_not_of( delims ); // Starts at the beginning of the line.
        end_idx = line.find_first_of( delims, beg_idx ); // getting the first word in the line.
        if ( end_idx == string::npos ) // If we're on the last token in a line,
        {                              // set the end_idx appropriately
            end_idx = line.length();
        }
        
        // Get the name of the parameter.
        temp_word = line.substr( beg_idx, end_idx - beg_idx );
        
        // Make sure it's on our list. XXX Maybe change this to use a std algorithm.
        bool temp_word_found = false;
        // Compare temp_word to each word in our list of viable ones.
        for ( vector<string>::const_iterator it = params.begin();
              it != params.end();
              ++it )
        {
            // TODO Add ablility to have comments in the file starting with #.
            
            if ( temp_word == *it )
            {
                temp_word_found = true;
            }
        }
        
        if ( !temp_word_found )
        {
            cout << "WARNING: Couldn't find parameter " << temp_word <<
                    ". Moving on to next line in config.txt." << endl;
            continue;
        }
        
        // Go on to the first number after the descriptive word.
        beg_idx = line.find_first_not_of( delims, end_idx );
        
        // Traverse the rest of line.
        while ( beg_idx != string::npos )
        {
            end_idx = line.find_first_of( delims, beg_idx );
            if ( end_idx == string::npos )
            {
                end_idx = line.length();
            }
            
            // Ok. Now: beg_idx points to the beginning of the substring,
            // and end_idx points to one-past the end of it.
            //temp_ascii_double = string( line, beg_idx, end_idx - beg_idx ); or
            temp_ascii_double = line.substr( beg_idx, end_idx - beg_idx );
            temp_double = strtod( temp_ascii_double.c_str(), NULL );
            
            vec.push_back( temp_double );

            beg_idx = line.find_first_not_of( delims, end_idx );
        }
        // Ok, vec is full. Figure out which param it corresponds to,
        // and copy the values.
                
        
        // I don't yet see a better way to do this... (?) XXX
        if ( temp_word == "light_pos" )
        {
            //cout << "Setting light position: " <<
            //    vec[0] << " " << vec[1] << " " << vec[2] << endl;
            d_light_pos.d_x = vec[0];
            d_light_pos.d_y = vec[1];
            d_light_pos.d_z = vec[2];
        }
                        
        if ( temp_word == "eye_pos" )
        {
            //cout << "Setting eye position: " <<
            //    vec[0] << " " << vec[1] << " " << vec[2] << endl;
            d_eye_pos.d_x = vec[0];
            d_eye_pos.d_y = vec[1];
            d_eye_pos.d_z = vec[2];
        }
                        
        if ( temp_word == "looking_at" )
        {
            //cout << "Setting looking-at position: " <<
            //    vec[0] << " " << vec[1] << " " << vec[2] << endl;
            d_looking_at.d_x = vec[0];
            d_looking_at.d_y = vec[1];
            d_looking_at.d_z = vec[2];
        }
                        
        if ( temp_word == "near" )
        {
            //cout << "Setting near: " << vec[0] << endl;
            d_near = vec[0];
        }
                        
        if ( temp_word == "far" )
        {
            //cout << "Setting far: " << vec[0] << endl;
            d_far = vec[0];
        }
                        
        if ( temp_word == "angular_view_width" )
        {
            //cout << "Setting angular view width (in file): " << vec[0] << endl;
            d_angular_view_width = vec[0];
            // ...but don't forget to convert to radians, which we use
            // exclusively in the code.
            d_angular_view_width = d_angular_view_width * PI / 180.0;
            cout << "and setting d_angular_view_width: " << d_angular_view_width << endl;
        }
                        
        vec.clear();
        // Now on to the next line.
    }
}
 
Old 11-12-2004, 09:49 AM   #5
ta0kira
Senior Member
 
Registered: Sep 2004
Distribution: FreeBSD 9.1, Kubuntu 12.10
Posts: 3,078

Rep: Reputation: Disabled
If you use C++, take advantage of it and avoid the procedural style of code. I ran into the same problem with a command line analyzer (looked a lot like what you have as far as analysis), but later turned it into a parser class. This makes maintenance MUCH easier. Here is how I would go about processing:

1) declare separators (i.e. " " and "\t" general separation, "\n" statement separation, "#" comment, etc.)
2) parse the entire file into strings/statements with minimal whitespace
3) insert them into a list statement objects (a class you make up)
4) (maybe going too far...) create a list of patterns and corresponding function pointers to processing functions
5) register patterns/function pointers in an analyzer class that checks for patterns then dereferences the appropriate function pointer
6) submit the list of statements to the analyzer


This way, everything is generic with the exception of the patterns and the actions. This can be put in a single .cpp file that is nice and neat; only containing pattern strings and global functions for individual actions (all must be the same prototype though). The rest of the implementation is up to you as far as semantics, however it will be highly reusable.

It is interesting you brought that up, because I was thinking about how to implement a config file too. I think the absolute easiest way to do it is to parse and view things as objects as much as possible. I think I'll go home and try to work something out tonight and I'll post the general concept I come up with if you want.
ta0kira
 
Old 11-12-2004, 10:08 AM   #6
kadissie
LQ Newbie
 
Registered: Jul 2003
Location: UK
Distribution: Fedora 5, Knoppix, Ubuntu
Posts: 27

Original Poster
Rep: Reputation: 15
Dohh! Entering "C++ read configuration file" into google returns some nice results. For my purposes, the best appear to be

http://www-personal.engin.umich.edu/...onfigFile.html
(quite simple; uses templates which may be overkill but is nice if you want to read in user-defined types)

http://spacetown.free.fr/lib/talos/index.php
(a bunch of useful c++-like extensions; includes variable-expansion syntax)

http://www.cours.polymtl.ca/roboop/d...assConfig.html
(non-templated so only works on builtin types, and quite straightforward)

Robert.

Last edited by kadissie; 11-12-2004 at 10:14 AM.
 
Old 11-12-2004, 01:48 PM   #7
johnMG
Member
 
Registered: Jul 2003
Location: CT, USA
Distribution: Debian Sarge (server), Etch (work/home)
Posts: 601

Rep: Reputation: 31
Thanks ta0kira. Yes, I'd like to see what you come up with.
 
Old 11-12-2004, 04:07 PM   #8
Mara
Moderator
 
Registered: Feb 2002
Location: Grenoble
Distribution: Debian
Posts: 9,539

Rep: Reputation: 149Reputation: 149
When the configuration file is more complicated you may thing about using flex/bison.
 
Old 11-15-2004, 05:12 AM   #9
ta0kira
Senior Member
 
Registered: Sep 2004
Distribution: FreeBSD 9.1, Kubuntu 12.10
Posts: 3,078

Rep: Reputation: Disabled
johnMG- sorry, it will be a few days. Had some stuff come up.
ta0kira
 
Old 11-22-2004, 06:18 AM   #10
ta0kira
Senior Member
 
Registered: Sep 2004
Distribution: FreeBSD 9.1, Kubuntu 12.10
Posts: 3,078

Rep: Reputation: Disabled
I finally got started on it a few days ago. It looks like it will be too large to post here, but I can post the prototypes and descriptions when I am done.
ta0kira
 
Old 06-30-2009, 11:56 AM   #11
bcj01
LQ Newbie
 
Registered: Nov 2007
Posts: 2

Rep: Reputation: 0
Wink

Quote:
Originally Posted by ta0kira View Post
I finally got started on it a few days ago. It looks like it will be too large to post here, but I can post the prototypes and descriptions when I am done.
ta0kira
Any updates?
 
Old 06-30-2009, 12:51 PM   #12
tuxdev
Senior Member
 
Registered: Jul 2005
Distribution: Slackware
Posts: 2,014

Rep: Reputation: 115Reputation: 115
Look into Boost Program Options. It'll parse command line options and simple key-value config files, and you get a nice --help message for pretty much free.
 
Old 08-26-2009, 06:19 PM   #13
ta0kira
Senior Member
 
Registered: Sep 2004
Distribution: FreeBSD 9.1, Kubuntu 12.10
Posts: 3,078

Rep: Reputation: Disabled
Quote:
Originally Posted by bcj01 View Post
Any updates?
Wow, I don't recall exactly the context of this thread (not sure what I was working on 5 years ago); however, I did write a config parser several years ago that I use in a few projects. It works very well for me, although it might not be appropriate for your application. It isn't a stand-alone lib; however, it's contained in 1 header and one source (it would need a few minor changes to be separated from the project.) It's extremely simple in that every line is tokenized based on whitespace, command substitution is allowed, and the rest is up to the program to interpret. I treat the first token as a command and the rest of the line as its options.
http://rservr.berlios.de/user/assembly.html#UCFF
http://rservr.berlios.de/app/client-...on.html#BiT_CP
http://svn.berlios.de/wsvn/rservr/tr...onfig-parser.h
http://svn.berlios.de/wsvn/rservr/tr...fig-parser.cpp

As I said above, this isn't a stand-alone parser at the moment, but it's success as the file parser for two of my largest projects (my actual parser project not included) makes me wonder if it would be appropriate as its own project. What's nice is the actual interpreter can be painfully simple (as it is in its native project,) or it can be very complex, e.g. allowing additional syntax and sematics (as it is in a privately-funded project of mine.)
Kevin Barry
 
  


Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Need help with file parsing BrianK Programming 2 09-02-2005 06:58 PM
Error Parsing Config file for X chiefreborn Suse/Novell 5 08-31-2005 07:30 PM
Parsing config files unholy Programming 5 09-18-2004 04:59 PM
Suggestiions for config file parsing library kubicon Linux - General 0 03-01-2004 03:02 PM
can't locate parsing code for .config file coolwind Linux - General 1 12-08-2002 09:24 AM


All times are GMT -5. The time now is 01:56 AM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
identi.ca: @linuxquestions
Facebook: linuxquestions Google+: linuxquestions
Open Source Consulting | Domain Registration