tags:

views:

85

answers:

3

I am writing an application that has a very loosely defined config file that is read in during startup. The file is easy to parse and looks something like the following:

tag1 = value1
tag2 = value2
tag3 = value3
tag4 = value4

with tags and values being the information that a user may want to configure. As I said previously, the file is loosely defined - AKA, I don't require all (or any) of the fields, and the values don't have to be in any specific order. The only real rule is that it has to be in the format above, and any tags I don't recognize get ignored.

Is there any good way to check to make sure a file is valid while parsing with the above constraints in mind? I'm developing in C#, version 2.0.x of .NET runtime. Thank you.

+1  A: 

Why bother?

You already say you ignore anything that isn't valid.

You could search for ' = ' on each line, but it seems a bit wasteful if there is no cost to having an invalid file.

Alternatively, you can place a version at the top

#footype=1

And then just look for that (generally good practice anyway, for when you change the file layout slightly)

Noon Silk
+3  A: 

I suggest parsing the file using a regular expression into a dictionary. You can add default values for all supported keys to dictionary before reading the file. This way you get a dictionary with a consistent set of keys independent of the keys found in the file. In this case you might further consider adding a list of supported keys and checking every key against this list as you read the file reporting unsupported keys.

const String fileName = @"foo.ini";

const String entryExpression = @"^\s*(?<key>[a-zA-Z][a-zA-Z0-9]*)\s*=" + 
                               @"\s*(?<value>[a-zA-Z][a-zA-Z0-9]*)\s*$";

Dictionary<String,String> entries = new Dictionary<String, String>();

foreach (String line in File.ReadAllLines(fileName))
{
    Match match = Regex.Match(line, entryExpression);

    if (match.Success)
    {
        String key = match.Groups["key"].Value;
        String value = match.Groups["value"].Value;

        if (entries.ContainsKey(key))
        {
            Console.WriteLine("Overwriting the key '{0}'.", key);
        }

        entries[key] = value;
    }
    else
    {
        Console.WriteLine("Detected malformed entry '{0}'.", line);
    }
}
Daniel Brückner
I like your style :) Regex++!
Nick Bedford
A: 

Just a random observation; the format would pass for python - so if you wanted to use some pre-existing code and offer more flexibility, you could just embed IronPython and use that to parse (execute) the config file. This will tell you about any errors, and (upon success) should make the values available by lookup.

Probably overkill - but actually flexible configuration scripts (as a DSL) is a bit of a strong point for python.

Marc Gravell
Not completely wise if 3rd parties are writing these configs (which we can only assume, if he's validating them); embedding a compiler like that will effectively allow them to break into the context of his app and execute things.
Noon Silk
Execute the config file..... somehow that sounds like a bad idea to me.
Mark
And also not completely crazy - and certainly not unheard of; it all comes down to how much you trust the input. You can do some pretty crazy things just by abusing app.config if you want. If you can control the config you are already stronger than the system you are trying to protect...
Marc Gravell