dotconf.h 11.2 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264
#ifndef DOTCONF_H
#define DOTCONF_H

#ifdef __cplusplus
extern "C" {
#endif

/* stdio.h should be included by the application - as the manual page says */
#ifndef _STDIO_H
#include <stdio.h>		/* needed for FILE* */
#endif

#ifdef WIN32
# ifndef R_OK
#define R_OK 0
# endif
#endif

/* some buffersize definitions */
#define CFG_BUFSIZE 4096	/* max length of one line */
#define CFG_MAX_OPTION 32	/* max length of any option name */
#define CFG_MAX_VALUE 4064	/* max length of any options value */
#define CFG_MAX_FILENAME 256	/* max length of a filename */
#define CFG_VALUES 16		/* max # of arguments an option takes */

#define CFG_INCLUDEPATH_ENV "DC_INCLUDEPATH"
#define WILDCARDS	"*?"		/* list of supported wild-card characters */

/* constants for type of option */
#define ARG_TOGGLE    0		/* TOGGLE on,off; yes,no; 1, 0; */
#define ARG_INT       1		/* callback wants an integer */
#define ARG_STR       2		/* callback expects a \0 terminated str */
#define ARG_LIST      3		/* wants list of strings */
#define ARG_NAME      4		/* wants option name plus ARG_LIST stuff */
#define ARG_RAW       5		/* wants raw argument data */
#define ARG_NONE      6		/* does not expect ANY args */

#define CTX_ALL       0		/* context: option can be used anywhere */

/* for convenience of terminating the dotconf_options list */
#define LAST_OPTION						{ "", 0, NULL, NULL    }
#define LAST_CONTEXT_OPTION				{ "", 0, NULL, NULL, 0 }

#define DOTCONF_CB(__name)     const char *__name(command_t *cmd,             \
                                                  context_t *ctx)
#define FUNC_ERRORHANDLER(_name) int _name(configfile_t * configfile,		  \
											int type, long dc_errno, const char *msg)


/* some flags that change the runtime behaviour of dotconf */
#define NONE 0
#define CASE_INSENSITIVE 1<<0			/* match option names case insensitive */
#define DONT_SUBSTITUTE 1<<1			/* do not call substitute_env after read_arg */
#define NO_INLINE_COMMENTS 1<<2			/* do not allow inline comments */
#define DUPLICATE_OPTION_NAMES 1<<3		/* allow for duplicate option names */

/* syslog style errors as suggested by Sander Steffann <sander@steffann.nl> */
#ifdef HAVE_SYSLOG
#include <syslog.h>

#define DCLOG_EMERG		LOG_EMERG			/* system is unusable */
#define DCLOG_ALERT		LOG_ALERT			/* action must be taken immediately */
#define DCLOG_CRIT		LOG_CRIT			/* critical conditions */
#define DCLOG_ERR		LOG_ERR				/* error conditions */
#define DCLOG_WARNING	LOG_WARNING			/* warning conditions */
#define DCLOG_NOTICE	LOG_NOTICE			/* normal but significant condition */
#define DCLOG_INFO		LOG_INFO			/* informational */
#define DCLOG_DEBUG		LOG_DEBUG			/* debug-level messages */

#define DCLOG_LEVELMASK	LOG_PRIMASK			/* mask off the level value */

#else /* HAVE_SYSLOG */

#define DCLOG_EMERG     0       /* system is unusable */
#define DCLOG_ALERT     1       /* action must be taken immediately */
#define DCLOG_CRIT      2       /* critical conditions */
#define DCLOG_ERR       3       /* error conditions */
#define DCLOG_WARNING   4       /* warning conditions */
#define DCLOG_NOTICE    5       /* normal but significant condition */
#define DCLOG_INFO      6       /* informational */
#define DCLOG_DEBUG     7       /* debug-level messages */

#define DCLOG_LEVELMASK 7       /* mask off the level value */

#endif /* HAVE_SYSLOG */

/* callback types for dotconf_callback */

/* error constants */
#define ERR_NOERROR                0x0000
#define ERR_PARSE_ERROR            0x0001
#define ERR_UNKNOWN_OPTION         0x0002
#define ERR_WRONG_ARG_COUNT        0x0003
#define ERR_INCLUDE_ERROR          0x0004
#define ERR_NOACCESS               0x0005
#define ERR_USER                   0x1000   /* base for userdefined errno's */

/* i needed this to check an ARG_LIST entry if it's toggled in one of my apps; maybe you do too */
#define CFG_TOGGLED(_val) ( (_val[0] == 'Y'                                \
                             || _val[0] == 'y')                            \
                             || (_val[0] == '1')                           \
                             || ((_val[0] == 'o'                           \
                                 || _val[0] == 'O')                        \
                                && (_val[1] == 'n'                         \
                                    || _val[1] == 'N')))

enum callback_types
{
	ERROR_HANDLER = 1,
	CONTEXT_CHECKER
};

typedef enum callback_types			callback_types;
typedef struct configfile_t			configfile_t;
typedef struct configoption_t       configoption_t;
typedef struct configoption_t		ConfigOption;
typedef struct command_t        	command_t;
typedef void                        context_t;
typedef void                        info_t;

typedef const char *(*dotconf_callback_t)(command_t *, context_t *);
typedef int (*dotconf_errorhandler_t)(configfile_t *, int, unsigned long, const char *);
typedef const char *(*dotconf_contextchecker_t)(command_t *, unsigned long);

struct configfile_t
{
	/* ------ the fields in configfile_t are provided to the app via command_t's ; READ ONLY! --- */

	FILE *stream;
	char eof;                       /* end of file reached ? */
	size_t size;					/* file size; cached on-demand for here-documents */

	context_t *context;

	configoption_t const **config_options;
	int config_option_count;

	/* ------ misc read-only fields ------------------------------------------------------------- */
	char *filename;         		/* name of file this option was found in */
	unsigned long line;           	/* line number we're currently at */
	unsigned long flags;			/* runtime flags given to dotconf_open */

	char *includepath;

	/* ------ some callbacks for interactivity -------------------------------------------------- */
	dotconf_errorhandler_t 		errorhandler;
	dotconf_contextchecker_t 	contextchecker;

	int (*cmp_func)(const char *, const char *, size_t);
};

struct configoption_t
{
  const char *name;								/* name of configuration option */
  int type;										/* for possible values, see above */
  dotconf_callback_t callback;					/* callback function */
  info_t *info;									/* additional info for multi-option callbacks */
  unsigned long context;						/* context sensitivity flags */
};

struct command_t
{
	const char *name;             		/* name of the command */
	configoption_t *option;		/* the option as given in the app; READ ONLY */

	/* ------ argument data filled in for each line / command ----------------------------------- */
	struct {
		long value;                   	/* ARG_INT, ARG_TOGGLE */
		char *str;                    	/* ARG_STR */
		char **list;                  	/* ARG_LIST */
	} data;
	int arg_count;                		/* number of arguments (in data.list) */

	/* ------ misc context information ---------------------------------------------------------- */
	configfile_t *configfile;
	context_t *context;
};

/* ------ dotconf_create() - create the configfile_t needed for further dot.conf fun ------------ */
configfile_t *dotconf_create(char *, const configoption_t *, context_t *, unsigned long);

/* ------ dotconf_cleanup() - tidy up behind dotconf_create and the parser dust ----------------- */
void dotconf_cleanup(configfile_t *configfile);

/* ------ dotconf_command_loop() - iterate through each line of file and handle the commands ---- */
int dotconf_command_loop(configfile_t *configfile);

/* ------ dotconf_command_loop_until_error() - like continue_line but return on the first error - */
const char *dotconf_command_loop_until_error(configfile_t *configfile);

/* ------ dotconf_continue_line() - check if line continuation is to be handled ----------------- */
int dotconf_continue_line(char *buffer, size_t length);

/* ------ dotconf_get_next_line() - read in the next line of the configfile_t ------------------- */
int dotconf_get_next_line(char *buffer, size_t bufsize, configfile_t *configfile);

/* ------ dotconf_get_here_document() - read the here document until delimit is found ----------- */
char *dotconf_get_here_document(configfile_t *configfile, const char *delimit);

/* ------ dotconf_invoke_command() - call the callback for command_t ---------------------------- */
const char *dotconf_invoke_command(configfile_t *configfile, command_t *cmd);

/* ------ dotconf_find_command() - iterate through all registered options trying to match ------- */
configoption_t *dotconf_find_command(configfile_t *configfile, const char *command);

/* ------ dotconf_read_arg() - read one argument from the line handling quoting and escaping ---- */
/*
	side effects: the char* returned by dotconf_read_arg is malloc() before, hence that pointer
                  will have to be free()ed later.
*/
char *dotconf_read_arg(configfile_t *configfile, signed char **line);

/* ------ dotconf_handle_command() - parse, substitute, find, invoke the command found in buffer  */
const char *dotconf_handle_command(configfile_t *configfile, char *buffer);

/* ------ dotconf_register_option() - add a new option table to the list of commands ------------ */
void dotconf_register_options(configfile_t *configfile, const configoption_t *options);

/* ------ dotconf_warning() - handle the dispatch of error messages of various levels ----------- */
int dotconf_warning(configfile_t *configfile, int level, unsigned long errnum, const char *, ...);

/* ------ dotconf_callback() - register a special callback -------------------------------------- */
void dotconf_callback(configfile_t *configfile, callback_types type, dotconf_callback_t);

/* ------ dotconf_substitute_env() - handle the substitution on environment variables ----------- */
char *dotconf_substitute_env(configfile_t *, char *);

/* ------ internal utility function that verifies if a character is in the WILDCARDS list -- */
int dotconf_is_wild_card(char value);

/* ------ internal utility function that calls the appropriate routine for the wildcard passed in -- */
int dotconf_handle_wild_card(command_t* cmd, char wild_card, char* path, char* pre, char* ext);

/* ------ internal utility function that frees allocated memory from dotcont_find_wild_card -- */
void dotconf_wild_card_cleanup(char* path, char* pre);

/* ------ internal utility function to check for wild cards in file path -- */
/* ------ path and pre must be freed by the developer ( dotconf_wild_card_cleanup) -- */
int dotconf_find_wild_card(char* filename, char* wildcard, char** path, char** pre, char** ext);

/* ------ internal utility function that compares two stings from back to front -- */
int dotconf_strcmp_from_back(const char* s1, const char* s2);

/* ------ internal utility function that determins if a string matches the '?' criteria -- */
int dotconf_question_mark_match(char* dir_name, char* pre, char* ext);

/* ------ internal utility function that determins if a string matches the '*' criteria -- */
int dotconf_star_match(char* dir_name, char* pre, char* ext);

/* ------ internal utility function that determins matches for filenames with   -- */
/* ------ a '?' in name and calls the Internal Include function on that filename -- */
int dotconf_handle_question_mark(command_t* cmd, char* path, char* pre, char* ext);

/* ------ internal utility function that determins matches for filenames with   -- */
/* ------ a '*' in name and calls the Internal Include function on that filename -- */
int dotconf_handle_star(command_t* cmd, char* path, char* pre, char* ext);



#ifdef __cplusplus
} /* extern "C" */
#endif

#endif /* DOTCONF_H */