hyperrealm / libconfig

C/C++ library for processing configuration files
https://hyperrealm.github.io/libconfig/
GNU Lesser General Public License v2.1
1.11k stars 361 forks source link

Feature request: validation file #17

Open guludo opened 9 years ago

guludo commented 9 years ago

It would be nice if there was a way to tell libconfig how the config file should be structured - the same idea as XSD for XML. This way config files validation could be done by calling an API function.

ps; Sorry if this isn't the right place to put this comment.

Regards,

hyperrealm commented 9 years ago

I agree this would be a useful feature, but this would be a lot of work to implement, and I don't think I will have the time in the foreseeable future to take on a big task like this. Though if someone else wanted to contribute such a feature I would be happy to consider it.

yrutschle commented 4 years ago

Ok, I've got this working in conf2struct.

The idea is that you have a configuration file schema, which is itself written as a libconfig file. For example for the libconfig documentation example looks like this. I have no semantics to define a list of variable objects (it would make no sense in the context of c2s).

The current strategy is that, as it traverses the schema, c2s deletes the settings. Then, it prints everything that is left. I suppose that would be not so good for integration in libconfig :-) I'm happy to refactor to keep track of the setting that we traversed, and print those that are not traversed.

One problem I see in integrating this in libconfig is that in c2s, the schema is compiled by a Perl script into description tables (as here. Then the API could be something like:

config_validate_schema(config_t* under_validation, struct config_desc* schema);

In theory of course we could read the schema directly, but that's a major refactor that I don't see myself coding any time soon, if ever...

What do you think?

yrutschle commented 4 years ago

Come to think of it, I don't think it'd be too complicated.

I realised I'm missing an output in my API proposal, so we'd have something like:

int config_validate_schema(const config_t *under_validation, const config_t* schema, config_validation_error_t** errors);

schema is passed as a config_t so the caller deals with parsing the file and its errors. The function returns CONFIG_TRUE if it performed validation, CONFIG_FALSE if it failed (on allocating memory for storing errors -- I can't think of any other failure mode, but I might be wrong).

If the configuration is valid with respect to the schema, *error is NULL. Otherwise, *error points to a list of errors:

typedef struct {
    config_error_t valerr_type;
    config_setting_t *valerr_setting;
    config_validation_error_t* valerr_next;
} config_validation_error_t;

typedef enum {
    CONFIG_TYPE, /* Setting is incorrect type */
    CONFIG_UNKNOWN,  /* Setting is not in the schema */
} config_error_t;

Using valerr_setting, it becomes easy to process all errors and give helpful messages with config_setting_source_file() and config_setting_source_line().

Does this look acceptable?