Skip to content

Commit

Permalink
Fix #92: Add support for option annotation/comments
Browse files Browse the repository at this point in the history
This patch adds support for option annotation.  It's a very simple
implementation, but it allows for one-liner comments to be both read
and written from/to a file both retrieved and set using the API.

A small unit test called annotate.c, with a annotate.conf, is also
included as an example.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
  • Loading branch information
troglobit committed May 24, 2017
1 parent 4290de2 commit 0285479
Show file tree
Hide file tree
Showing 4 changed files with 194 additions and 26 deletions.
65 changes: 62 additions & 3 deletions src/confuse.c
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,19 @@ DLLIMPORT unsigned int cfg_size(cfg_t *cfg, const char *name)
return cfg_opt_size(cfg_getopt(cfg, name));
}

DLLIMPORT char *cfg_opt_getcomment(cfg_opt_t *opt)
{
if (opt)
return opt->comment;

return NULL;
}

DLLIMPORT char *cfg_getcomment(cfg_t *cfg, const char *name)
{
return cfg_opt_getcomment(cfg_getopt(cfg, name));
}

DLLIMPORT signed long cfg_opt_getnint(cfg_opt_t *opt, unsigned int index)
{
if (!opt || opt->type != CFGT_INT) {
Expand Down Expand Up @@ -1029,6 +1042,7 @@ static void cfg_handle_deprecated(cfg_t *cfg, cfg_opt_t *opt)
static int cfg_parse_internal(cfg_t *cfg, int level, int force_state, cfg_opt_t *force_opt)
{
int state = 0;
char *comment = NULL;
char *opttitle = NULL;
cfg_opt_t *opt = NULL;
cfg_value_t *val = NULL;
Expand Down Expand Up @@ -1067,15 +1081,24 @@ static int cfg_parse_internal(cfg_t *cfg, int level, int force_state, cfg_opt_t
if (opt && opt->flags & CFGF_DEPRECATED)
cfg_handle_deprecated(cfg, opt);

if (tok == '}') {
switch (tok) {
case '}':
if (level == 0) {
cfg_error(cfg, _("unexpected closing brace"));
goto error;
}
return STATE_EOF;
}

if (tok != CFGT_STR) {
case CFGT_STR:
break;

case CFGT_COMMENT:
if (comment)
free(comment);
comment = strdup(cfg_yylval);
continue;

default:
cfg_error(cfg, _("unexpected token '%s'"), cfg_yylval);
goto error;
}
Expand All @@ -1090,6 +1113,10 @@ static int cfg_parse_internal(cfg_t *cfg, int level, int force_state, cfg_opt_t
goto error;
}

/* Inherit last read comment */
opt->comment = comment;
comment = NULL;

if (opt->type == CFGT_SEC) {
if (is_set(CFGF_TITLE, opt->flags))
state = 6;
Expand Down Expand Up @@ -1275,6 +1302,11 @@ static int cfg_parse_internal(cfg_t *cfg, int level, int force_state, cfg_opt_t
break;

case 10: /* unknown option, mini-discard parser states: 10-15 */
if (comment) {
free(comment);
comment = NULL;
}

if (tok == '+') {
ignore = '=';
state = 13; /* Append to list, should be followed by '=' */
Expand Down Expand Up @@ -1361,6 +1393,8 @@ static int cfg_parse_internal(cfg_t *cfg, int level, int force_state, cfg_opt_t
error:
if (opttitle)
free(opttitle);
if (comment)
free(comment);

return STATE_ERROR;
}
Expand Down Expand Up @@ -1733,6 +1767,25 @@ static cfg_value_t *cfg_opt_getval(cfg_opt_t *opt, unsigned int index)
return val;
}

DLLIMPORT int cfg_opt_setcomment(cfg_opt_t *opt, char *comment)
{
if (!opt || !comment) {
errno = EINVAL;
return CFG_FAIL;
}

if (opt->comment)
free(opt->comment);
opt->comment = strdup(comment);

return CFG_SUCCESS;
}

DLLIMPORT int cfg_setcomment(cfg_t *cfg, const char *name, char *comment)
{
return cfg_opt_setcomment(cfg_getopt(cfg, name), comment);
}

DLLIMPORT int cfg_opt_setnint(cfg_opt_t *opt, long int value, unsigned int index)
{
cfg_value_t *val;
Expand Down Expand Up @@ -2089,6 +2142,7 @@ DLLIMPORT int cfg_opt_nprint_var(cfg_opt_t *opt, unsigned int index, FILE *fp)
case CFGT_SEC:
case CFGT_FUNC:
case CFGT_PTR:
case CFGT_COMMENT:
break;
}

Expand All @@ -2108,6 +2162,11 @@ DLLIMPORT int cfg_opt_print_indent(cfg_opt_t *opt, FILE *fp, int indent)
return CFG_FAIL;
}

if (opt->comment) {
cfg_indent(fp, indent);
fprintf(fp, "/* %s */\n", opt->comment);
}

if (opt->type == CFGT_SEC) {
cfg_t *sec;
unsigned int i;
Expand Down
61 changes: 47 additions & 14 deletions src/confuse.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,8 @@ enum cfg_type_t {
CFGT_BOOL, /**< boolean value */
CFGT_SEC, /**< section */
CFGT_FUNC, /**< function */
CFGT_PTR /**< pointer to user-defined value */
CFGT_PTR, /**< pointer to user-defined value */
CFGT_COMMENT /**< comment/annotation */
};
typedef enum cfg_type_t cfg_type_t;

Expand Down Expand Up @@ -236,6 +237,7 @@ struct cfg_t {
char *name; /**< The name of this section, the root
* section returned from cfg_init() is
* always named "root" */
char *comment; /**< Optional annotation/comment */
cfg_opt_t *opts; /**< Array of options */
char *title; /**< Optional title for this section, only
* set if CFGF_TITLE flag is set */
Expand Down Expand Up @@ -288,6 +290,7 @@ struct cfg_defvalue_t {
*/
struct cfg_opt_t {
const char *name; /**< The name of the option */
char *comment; /**< Optional comment/annotation */
cfg_type_t type; /**< Type of option */
unsigned int nvalues; /**< Number of values parsed */
cfg_value_t **values; /**< Array of found values */
Expand All @@ -310,9 +313,9 @@ extern const char __export confuse_version[];
extern const char __export confuse_author[];

#define __CFG_STR(name, def, flags, svalue, cb) \
{name,CFGT_STR,0,0,flags,0,{0,0,cfg_false,def,0},0,{.string=svalue},cb,0,0,0,0}
{name,0,CFGT_STR,0,0,flags,0,{0,0,cfg_false,def,0},0,{.string=svalue},cb,0,0,0,0}
#define __CFG_STR_LIST(name, def, flags, svalue, cb) \
{name,CFGT_STR,0,0,flags | CFGF_LIST,0,{0,0,cfg_false,0,def},0,{.string=svalue},cb,0,0,0,0}
{name,0,CFGT_STR,0,0,flags | CFGF_LIST,0,{0,0,cfg_false,0,def},0,{.string=svalue},cb,0,0,0,0}

/** Initialize a string option
*/
Expand Down Expand Up @@ -391,9 +394,9 @@ extern const char __export confuse_author[];


#define __CFG_INT(name, def, flags, svalue, cb) \
{name,CFGT_INT,0,0,flags,0,{def,0,cfg_false,0,0},0,{.number=svalue},cb,0,0,0,0}
{name,0,CFGT_INT,0,0,flags,0,{def,0,cfg_false,0,0},0,{.number=svalue},cb,0,0,0,0}
#define __CFG_INT_LIST(name, def, flags, svalue, cb) \
{name,CFGT_INT,0,0,flags | CFGF_LIST,0,{0,0,cfg_false,0,def},0,{.number=svalue},cb,0,0,0,0}
{name,0,CFGT_INT,0,0,flags | CFGF_LIST,0,{0,0,cfg_false,0,def},0,{.number=svalue},cb,0,0,0,0}

/** Initialize an integer option
*/
Expand Down Expand Up @@ -427,9 +430,9 @@ extern const char __export confuse_author[];


#define __CFG_FLOAT(name, def, flags, svalue, cb) \
{name,CFGT_FLOAT,0,0,flags,0,{0,def,cfg_false,0,0},0,{.fpnumber=svalue},cb,0,0,0,0}
{name,0,CFGT_FLOAT,0,0,flags,0,{0,def,cfg_false,0,0},0,{.fpnumber=svalue},cb,0,0,0,0}
#define __CFG_FLOAT_LIST(name, def, flags, svalue, cb) \
{name,CFGT_FLOAT,0,0,flags | CFGF_LIST,0,{0,0,cfg_false,0,def},0,{.fpnumber=svalue},cb,0,0,0,0}
{name,0,CFGT_FLOAT,0,0,flags | CFGF_LIST,0,{0,0,cfg_false,0,def},0,{.fpnumber=svalue},cb,0,0,0,0}

/** Initialize a floating point option
*/
Expand Down Expand Up @@ -460,9 +463,9 @@ extern const char __export confuse_author[];


#define __CFG_BOOL(name, def, flags, svalue, cb) \
{name,CFGT_BOOL,0,0,flags,0,{0,0,def,0,0},0,{.boolean=svalue},cb,0,0,0,0}
{name,0,CFGT_BOOL,0,0,flags,0,{0,0,def,0,0},0,{.boolean=svalue},cb,0,0,0,0}
#define __CFG_BOOL_LIST(name, def, flags, svalue, cb) \
{name,CFGT_BOOL,0,0,flags | CFGF_LIST,0,{0,0,cfg_false,0,def},0,{.boolean=svalue},cb,0,0,0,0}
{name,0,CFGT_BOOL,0,0,flags | CFGF_LIST,0,{0,0,cfg_false,0,def},0,{.boolean=svalue},cb,0,0,0,0}

/** Initialize a boolean option
*/
Expand Down Expand Up @@ -504,7 +507,7 @@ extern const char __export confuse_author[];
*
*/
#define CFG_SEC(name, opts, flags) \
{name,CFGT_SEC,0,0,flags,opts,{0,0,cfg_false,0,0},0,{0},0,0,0,0,0}
{name,0,CFGT_SEC,0,0,flags,opts,{0,0,cfg_false,0,0},0,{0},0,0,0,0,0}



Expand All @@ -515,13 +518,13 @@ extern const char __export confuse_author[];
* @see cfg_func_t
*/
#define CFG_FUNC(name, func) \
{name,CFGT_FUNC,0,0,CFGF_NONE,0,{0,0,cfg_false,0,0},func,{0},0,0,0,0,0}
{name,0,CFGT_FUNC,0,0,CFGF_NONE,0,{0,0,cfg_false,0,0},func,{0},0,0,0,0,0}


#define __CFG_PTR(name, def, flags, svalue, parsecb, freecb) \
{name,CFGT_PTR,0,0,flags,0,{0,0,cfg_false,0,def},0,{.ptr=svalue},parsecb,0,0,0,freecb}
{name,0,CFGT_PTR,0,0,flags,0,{0,0,cfg_false,0,def},0,{.ptr=svalue},parsecb,0,0,0,freecb}
#define __CFG_PTR_LIST(name, def, flags, svalue, parsecb, freecb) \
{name,CFGT_PTR,0,0,flags | CFGF_LIST,0,{0,0,cfg_false,0,def},0,{.ptr=svalue},parsecb,0,0,0,freecb}
{name,0,CFGT_PTR,0,0,flags | CFGF_LIST,0,{0,0,cfg_false,0,def},0,{.ptr=svalue},parsecb,0,0,0,freecb}

/** Initialize a user-defined option
*
Expand Down Expand Up @@ -551,7 +554,7 @@ extern const char __export confuse_author[];
* the option list.
*/
#define CFG_END() \
{0,CFGT_NONE,0,0,CFGF_NONE,0,{0,0,cfg_false,0,0},0,{0},0,0,0,0,0}
{0,0,CFGT_NONE,0,0,CFGF_NONE,0,{0,0,cfg_false,0,0},0,{0},0,0,0,0,0}



Expand Down Expand Up @@ -682,6 +685,19 @@ DLLIMPORT cfg_errfunc_t __export cfg_set_error_function(cfg_t *cfg, cfg_errfunc_
*/
DLLIMPORT void __export cfg_error(cfg_t *cfg, const char *fmt, ...);

/** Returns the option comment
* @param opt The option structure (eg, as returned from cfg_getopt())
* @see cfg_getcomment
*/
DLLIMPORT char * __export cfg_opt_getcomment(cfg_opt_t *opt);

/** Returns the option comment
* @param cfg The configuration file context.
* @param name The name of the option.
* @return The comment for this option, or NULL if unset
*/
DLLIMPORT char * __export cfg_getcomment(cfg_t *cfg, const char *name);

/** Returns the value of an integer option, given a cfg_opt_t pointer.
* @param opt The option structure (eg, as returned from cfg_getopt())
* @param index Index of the value to get. Zero based.
Expand Down Expand Up @@ -937,6 +953,23 @@ DLLIMPORT cfg_opt_t *__export cfg_getopt(cfg_t *cfg, const char *name);
*/
DLLIMPORT cfg_value_t *cfg_setopt(cfg_t *cfg, cfg_opt_t *opt, const char *value);

/** Annotate an option
* @param opt The option structure (eg, as returned from cfg_getopt())
* @param comment The annotation
*
* @return POSIX OK(0), or non-zero on failure.
*/
DLLIMPORT int __export cfg_opt_setcomment(cfg_opt_t *opt, char *comment);

/** Annotate an option by its name
* @param cfg The configuration file context.
* @param name The name of the option.
* @param comment The annotation
*
* @return POSIX OK(0), or non-zero on failure.
*/
DLLIMPORT int __export cfg_setcomment(cfg_t *cfg, const char *name, char *comment);

/** Set a value of an integer option.
*
* @param opt The option structure (eg, as returned from cfg_getopt())
Expand Down

0 comments on commit 0285479

Please sign in to comment.