# HG changeset patch # User John Tsiombikas # Date 1453358731 -7200 # Node ID d9b3fba68705de5151b6e5d60156d85ede73a7db initial commit diff -r 000000000000 -r d9b3fba68705 .hgignore --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.hgignore Thu Jan 21 08:45:31 2016 +0200 @@ -0,0 +1,4 @@ +\.o$ +\.d$ +\.swp$ +^xglcomp$ diff -r 000000000000 -r d9b3fba68705 Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Makefile Thu Jan 21 08:45:31 2016 +0200 @@ -0,0 +1,44 @@ +PREFIX = /usr/local + +ccsrc = $(wildcard src/*.cc) +csrc = $(wildcard src/*.c) $(wildcard src/optcfg/*.c) +obj = $(csrc:.c=.o) $(ccsrc:.cc=.o) +dep = $(obj:.o=.d) +bin = xglcomp + +warn = -pedantic -Wall +dbg = -g +opt = -O0 +incpaths = -Isrc/optcfg + +CFLAGS = $(warn) $(dbg) $(opt) $(incpaths) +CXXFLAGS = $(warn) $(dbg) $(opt) $(incpaths) +LDFLAGS = -lGL -lGLEW -lX11 -lXext -lXcomposite -lm + +$(bin): $(obj) + $(CXX) -o $@ $(obj) $(LDFLAGS) + +-include $(dep) + +%.d: %.c + @$(CPP) $(CFLAGS) $< -MM -MT $(@:.d=.o) >$@ + +%.d: %.cc + @$(CPP) $(CXXFLAGS) $< -MM -MT $(@:.d=.o) >$@ + +.PHONY: clean +clean: + rm -f $(obj) $(bin) + +.PHONY: cleandep +cleandep: + rm -f $(dep) + +.PHONY: install +install: $(bin) + mkdir -p $(DESTDIR)$(PREFIX)/bin + cp $(bin) $(DESTDIR)$(PREFIX)/bin/$(bin) + +.PHONY: uninstall +uninstall: + rm -f $(DESTDIR)$(PREFIX)/bin/$(bin) diff -r 000000000000 -r d9b3fba68705 src/cwin.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/cwin.cc Thu Jan 21 08:45:31 2016 +0200 @@ -0,0 +1,17 @@ +#include +#include "cwin.h" +#include "logger.h" + +static std::vector cwinlist; + +void add_window(CompWindow *cwin) +{ + if(have_window(cwin)) { + log_warning("add_window trying to add duplicate, ignoring\n"); + return; + } + + cwinlist.push_back(cwin); +} + +void delete_window( diff -r 000000000000 -r d9b3fba68705 src/cwin.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/cwin.h Thu Jan 21 08:45:31 2016 +0200 @@ -0,0 +1,21 @@ +#ifndef COMP_WIN_H_ +#define COMP_WIN_H_ + +#include + +struct CompWindow { + Window xwin; + Pixmap xpixmap; + + struct CompWindow *next, *prev; +}; + +void add_window(CompWindow *cwin); +void delete_window(CompWindow *cwin); +bool have_window(CompWindow *cwin); +CompWindow *find_window_xid(Window xid); + +int get_window_count(); +CompWindow *get_window(int idx); + +#endif // COMP_WIN_H_ diff -r 000000000000 -r d9b3fba68705 src/logger.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/logger.c Thu Jan 21 08:45:31 2016 +0200 @@ -0,0 +1,351 @@ +#include +#include +#include +#include +#include +#include "logger.h" + +#if defined(unix) || defined(__unix__) || defined(__APPLE__) +#include +#include +#include +#include +#endif + +enum targ_type { TARG_STREAM, TARG_FILE, TARG_FUNC }; + +struct log_target { + unsigned int msg_type; + enum targ_type targ_type; + FILE *fp; + void (*func)(const char*, void*); + void *func_cls; + + struct log_target *next; +}; + +static struct log_target *targ_list = (void*)1; /* uninitialized */ + +static void init_once(void) +{ + if(targ_list == (void*)1) { + /* perform one-time init */ + targ_list = 0; + log_add_stream(LOG_INFO | LOG_DEBUG, stdout); + log_add_stream(LOG_WARNING | LOG_ERROR, stderr); + } +} + +static void log_string(unsigned int type, const char *str); +static int typecolor(int type); + +void log_clear_targets(void) +{ + init_once(); + + while(targ_list) { + struct log_target *tmp = targ_list; + targ_list = targ_list->next; + + if(tmp->targ_type == TARG_FILE) { + fclose(tmp->fp); + } + free(tmp); + } + targ_list = 0; +} + +int log_add_stream(unsigned int type_mask, FILE *fp) +{ + struct log_target *targ; + + init_once(); + + if(!(targ = malloc(sizeof *targ))) { + perror("failed to allocate memory for log target"); + return -1; + } + targ->msg_type = type_mask; + targ->targ_type = TARG_STREAM; + targ->fp = fp; + targ->next = targ_list; + targ_list = targ; + return 0; +} + +int log_add_file(unsigned int type_mask, const char *fname) +{ + FILE *fp; + struct log_target *targ; + + init_once(); + + if(!(fp = fopen(fname, "w"))) { + fprintf(stderr, "failed to open logfile: %s: %s\n", fname, strerror(errno)); + return -1; + } + if(type_mask & (LOG_ERROR | LOG_DEBUG)) { + /* make error and debug logs unbuffered */ + setvbuf(fp, 0, _IONBF, 0); + } + if(!(targ = malloc(sizeof *targ))) { + perror("failed to allocate memory for log target"); + fclose(fp); + return -1; + } + targ->msg_type = type_mask; + targ->targ_type = TARG_FILE; + targ->fp = fp; + targ->next = targ_list; + targ_list = targ; + return 0; +} + +int log_add_func(unsigned int type_mask, void (*func)(const char*, void*), void *cls) +{ + struct log_target *targ; + + init_once(); + + if(!(targ = malloc(sizeof *targ))) { + perror("failed to allocate memory for log target"); + return -1; + } + targ->msg_type = type_mask; + targ->targ_type = TARG_FUNC; + targ->func = func; + targ->func_cls = cls; + targ->next = targ_list; + targ_list = targ; + return 0; +} + + +void log_va_msg(unsigned int type, const char *fmt, va_list ap) +{ + char fixedbuf[256]; + char *buf = fixedbuf; + int len, sz = sizeof fixedbuf; + + init_once(); + + if(!targ_list || !*fmt) return; /* don't waste our time */ + + /* try with the fixed size buffer first which should be sufficient most of the + * time. if this fails, allocate a buffer of the correct size. + */ + while((len = vsnprintf(buf, sz, fmt, ap)) >= sz || len < 0) { + sz = len >= 0 ? len + 1 : sz * 2; + if(buf != fixedbuf) + free(buf); + if(!(buf = malloc(sz))) { + return; + } + } + + if(buf != fixedbuf) + free(buf); + + log_string(type, buf); +} + +/* helpers */ +#define LOG_VA_MSG(t) \ + do { \ + va_list ap; \ + va_start(ap, fmt); \ + log_va_msg(t, fmt, ap); \ + va_end(ap); \ + } while(0) + +void log_msg(unsigned int type, const char *fmt, ...) +{ + LOG_VA_MSG(type); +} + +void log_info(const char *fmt, ...) +{ + LOG_VA_MSG(LOG_INFO); +} + +void log_warning(const char *fmt, ...) +{ + LOG_VA_MSG(LOG_WARNING); +} + +void log_error(const char *fmt, ...) +{ + LOG_VA_MSG(LOG_ERROR); +} + +void log_debug(const char *fmt, ...) +{ + LOG_VA_MSG(LOG_DEBUG); +} + +void log_va_info(const char *fmt, va_list ap) +{ + log_va_msg(LOG_INFO, fmt, ap); +} + +void log_va_warning(const char *fmt, va_list ap) +{ + log_va_msg(LOG_WARNING, fmt, ap); +} + +void log_va_error(const char *fmt, va_list ap) +{ + log_va_msg(LOG_ERROR, fmt, ap); +} + +void log_va_debug(const char *fmt, va_list ap) +{ + log_va_msg(LOG_DEBUG, fmt, ap); +} + +static void log_string(unsigned int type, const char *str) +{ + struct log_target *targ; + + targ = targ_list; + while(targ) { + if(targ->msg_type & type) { + if(targ->targ_type == TARG_STREAM || targ->targ_type == TARG_FILE) { +#if defined(unix) || defined(__unix__) || defined(__APPLE__) + if(isatty(fileno(targ->fp)) && type != LOG_INFO) { + int c = typecolor(type); + fprintf(targ->fp, "\033[%dm%s\033[0m", c, str); + } else +#endif + { + fputs(str, targ->fp); + } + + } else if(targ->targ_type == TARG_FUNC) { + targ->func(str, targ->func_cls); + } + } + targ = targ->next; + } +} + +enum { + BLACK = 0, + RED, + GREEN, + YELLOW, + BLUE, + MAGENTA, + CYAN, + WHITE +}; + +#define ANSI_FGCOLOR(x) (30 + (x)) +#define ANSI_BGCOLOR(x) (40 + (x)) + +static int typecolor(int type) +{ + switch(type) { + case LOG_ERROR: + return ANSI_FGCOLOR(RED); + case LOG_WARNING: + return ANSI_FGCOLOR(YELLOW); + case LOG_DEBUG: + return ANSI_FGCOLOR(MAGENTA); + default: + break; + } + return 37; +} + +#if defined(unix) || defined(__unix__) || defined(__APPLE__) +static int out_pipe[2], err_pipe[2]; +static int thr_running; + +static void *thr_func(void *arg); + +static int std_intercept(void) +{ + pthread_t thr; + + if(thr_running) return 0; + + pipe(out_pipe); + pipe(err_pipe); + + fcntl(out_pipe[0], F_SETFL, fcntl(out_pipe[0], F_GETFL) | O_NONBLOCK); + fcntl(err_pipe[0], F_SETFL, fcntl(err_pipe[0], F_GETFL) | O_NONBLOCK); + + if(pthread_create(&thr, 0, thr_func, 0) == -1) { + log_error("failed to start std intercept thread\n"); + return -1; + } + thr_running = 1; + pthread_detach(thr); + return 0; +} + +static void *thr_func(void *arg) +{ + static char buf[512]; + static int bufsz = sizeof buf; + int max_fd = out_pipe[0] > err_pipe[0] ? out_pipe[0] : err_pipe[0]; + + for(;;) { + int sz, res; + fd_set rdset; + + FD_ZERO(&rdset); + FD_SET(out_pipe[0], &rdset); + FD_SET(err_pipe[0], &rdset); + + while((res = select(max_fd + 1, &rdset, 0, 0, 0)) == -1 && errno == EINTR); + if(res == -1) { + break; /* assume EPIPE or non-recoverable error */ + } + if(res == 0) continue; + + if(FD_ISSET(out_pipe[0], &rdset)) { + while((sz = read(out_pipe[0], buf, bufsz - 1)) > 0) { + buf[bufsz - 1] = 0; + log_info("%s", buf); + } + if(sz == -1 && errno == EPIPE) break; + } + if(FD_ISSET(err_pipe[0], &rdset)) { + while((sz = read(err_pipe[0], buf, bufsz - 1)) > 0) { + buf[bufsz - 1] = 0; + log_error("%s", buf); + } + if(sz == -1 && errno == EPIPE) break; + } + } + return 0; +} + +void log_grab_stdout(void) +{ + if(std_intercept() == -1) { + return; + } + dup2(out_pipe[1], 1); +} + +void log_grab_stderr(void) +{ + if(std_intercept() == -1) { + return; + } + dup2(err_pipe[1], 2); +} +#else +void log_grab_stdout(void) +{ + log_error("log_grab_stdout only works on UNIX\n"); +} + +void log_grab_stderr(void) +{ + log_error("log_grab_stderr only works on UNIX\n"); +} +#endif diff -r 000000000000 -r d9b3fba68705 src/logger.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/logger.h Thu Jan 21 08:45:31 2016 +0200 @@ -0,0 +1,54 @@ +#ifndef LOGGER_H_ +#define LOGGER_H_ + +#include +#include + +enum { + LOG_INFO = 1, + LOG_WARNING = 2, + LOG_ERROR = 4, + LOG_DEBUG = 8 +}; + +#ifdef __cplusplus +extern "C" { +#endif + +/* Clear log outputs. Initially info/debug messages go to stdout, and + * warning/error messages to stderr. + */ +void log_clear_targets(void); + +/* set logging outputs for any combination of message types. + * type_mask expects a bitmask. + */ +int log_add_stream(unsigned int type_mask, FILE *fp); +int log_add_file(unsigned int type_mask, const char *fname); +int log_add_func(unsigned int type_mask, void (*func)(const char*, void*), void *cls); + +void log_msg(unsigned int type, const char *fmt, ...); +/* log_msg helpers */ +void log_info(const char *fmt, ...); +void log_warning(const char *fmt, ...); +void log_error(const char *fmt, ...); +void log_debug(const char *fmt, ...); + +void log_va_msg(unsigned int type, const char *fmt, va_list va); +/* log_va_msg helpers */ +void log_va_info(const char *fmt, va_list ap); +void log_va_warning(const char *fmt, va_list ap); +void log_va_error(const char *fmt, va_list ap); +void log_va_debug(const char *fmt, va_list ap); + +/* Intercept stdout/stderr and handle them through the logger. stdout as an + * info log, and stderr as an error log. This only works on UNIX. + */ +void log_grab_stdout(void); +void log_grab_stderr(void); + +#ifdef __cplusplus +} +#endif + +#endif /* LOGGER_H_ */ diff -r 000000000000 -r d9b3fba68705 src/main.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main.cc Thu Jan 21 08:45:31 2016 +0200 @@ -0,0 +1,9 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include "cwin.h" diff -r 000000000000 -r d9b3fba68705 src/optcfg/optcfg.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/optcfg/optcfg.c Thu Jan 21 08:45:31 2016 +0200 @@ -0,0 +1,337 @@ +#include +#include +#include +#include +#ifdef _MSC_VER +#include +#else +#include +#endif +#include "optcfg.h" + +struct optcfg { + struct optcfg_option *optlist; + + optcfg_opt_callback opt_func; + void *opt_cls; + optcfg_arg_callback arg_func; + void *arg_cls; + + int err_abort; + + /* argument parsing state */ + char **argv; + int argidx; + + /* config file parsing state */ + const char *cfg_fname; + int cfg_nline; + char *cfg_value; +}; + +static int get_opt(struct optcfg *oc, const char *s); +static char *skip_spaces(char *s); +static void strip_comments(char *s); +static void strip_trailing_spaces(char *s); +static char *parse_keyval(char *line); + + +struct optcfg *optcfg_init(struct optcfg_option *optv) +{ + struct optcfg *oc; + + if(!(oc = calloc(1, sizeof *oc))) { + return 0; + } + oc->optlist = optv; + oc->err_abort = 1; + return oc; +} + +void optcfg_destroy(struct optcfg *oc) +{ + memset(oc, 0, sizeof *oc); + free(oc); +} + +void optcfg_set_opt_callback(struct optcfg *oc, optcfg_opt_callback func, void *cls) +{ + oc->opt_func = func; + oc->opt_cls = cls; +} + +void optcfg_set_arg_callback(struct optcfg *oc, optcfg_arg_callback func, void *cls) +{ + oc->arg_func = func; + oc->arg_cls = cls; +} + +void optcfg_set_error_action(struct optcfg *oc, int act) +{ + if(act == OPTCFG_ERROR_FAIL) { + oc->err_abort = 1; + } else if(act == OPTCFG_ERROR_IGNORE) { + oc->err_abort = 0; + } +} + +int optcfg_parse_args(struct optcfg *oc, int argc, char **argv) +{ + int i; + + oc->argv = argv; + + for(i=1; iargidx = i; + + if(argv[i][0] == '-') { + if(oc->opt_func) { + int o = get_opt(oc, argv[i]); + if(o == -1 || oc->opt_func(oc, o, oc->opt_cls) == -1) { + if(oc->err_abort) { + return -1; + } + } + } else { + fprintf(stderr, "unexpected option: %s\n", argv[i]); + if(oc->err_abort) { + return -1; + } + } + } else { + if(oc->arg_func) { + if(oc->arg_func(oc, argv[i], oc->arg_cls) == -1) { + if(oc->err_abort) { + return -1; + } + } + } else { + fprintf(stderr, "unexpected argument: %s\n", argv[i]); + if(oc->err_abort) { + return -1; + } + } + } + + i = oc->argidx; + } + + oc->argidx = 0; /* done parsing args */ + return 0; +} + +int optcfg_parse_config_file(struct optcfg *oc, const char *fname) +{ + int res; + FILE *fp = fopen(fname, "rb"); + if(!fp) { + return -1; + } + + oc->cfg_fname = fname; + res = optcfg_parse_config_stream(oc, fp); + oc->cfg_fname = 0; + fclose(fp); + return res; +} + +int optcfg_parse_config_stream(struct optcfg *oc, FILE *fp) +{ + char buf[512]; + + oc->cfg_nline = 0; + while(fgets(buf, sizeof buf, fp)) { + ++oc->cfg_nline; + + if(optcfg_parse_config_line(oc, buf) == -1) { + if(oc->err_abort) { + return -1; + } + } + } + return 0; +} + +int optcfg_parse_config_line(struct optcfg *oc, const char *line) +{ + int opt, len; + char *start, *val, *buf; + + len = strlen(line); + buf = alloca(len + 1); + memcpy(buf, line, len + 1); + + start = skip_spaces(buf); + strip_comments(start); + strip_trailing_spaces(start); + if(!*start) { + return 0; + } + + if(!(val = parse_keyval(start))) { + fprintf(stderr, "error parsing %s line %d: invalid syntax\n", oc->cfg_fname ? oc->cfg_fname : "", oc->cfg_nline); + return -1; + } + oc->cfg_value = val; + if((opt = get_opt(oc, start)) == -1) { + fprintf(stderr, "error parsing %s line %d: unknown option: %s\n", oc->cfg_fname ? oc->cfg_fname : "", + oc->cfg_nline, start); + return -1; + } + + if(oc->opt_func) { + if(oc->opt_func(oc, opt, oc->opt_cls) == -1) { + return -1; + } + } + oc->cfg_value = 0; + return 0; +} + +int optcfg_enabled_value(struct optcfg *oc, int *enabledp) +{ + if(oc->argidx) { + *enabledp = 1; /* TODO take -no- prefix into account */ + } else { + char *val = optcfg_next_value(oc); + if(optcfg_bool_value(val, enabledp) == -1) { + return -1; + } + } + return 0; +} + + +char *optcfg_next_value(struct optcfg *oc) +{ + if(oc->argidx) { /* we're in the middle of parsing arguments, so get the next one */ + return oc->argv[++oc->argidx]; + } + if(oc->cfg_value) { + char *val = oc->cfg_value; + oc->cfg_value = 0; + return val; + } + return 0; +} + +void optcfg_print_options(struct optcfg *oc) +{ + int i; + for(i=0; oc->optlist[i].opt != -1; i++) { + struct optcfg_option *opt = oc->optlist + i; + + if(opt->c) { + printf(" -%c", opt->c); + } else { + printf(" "); + } + if(opt->s) { + printf("%c-%s: ", opt->c ? ',' : ' ', opt->s); + } else { + printf(": "); + } + printf("%s\n", opt->desc ? opt->desc : "undocumented"); + } +} + +int optcfg_bool_value(char *s, int *valret) +{ + if(strcasecmp(s, "yes") == 0 || strcasecmp(s, "true") == 0 || strcmp(s, "1") == 0) { + *valret = 1; + return 0; + } + if(strcasecmp(s, "no") == 0 || strcasecmp(s, "false") == 0 || strcmp(s, "0") == 0) { + *valret = 0; + return 0; + } + return -1; +} + +int optcfg_int_value(char *str, int *valret) +{ + char *endp; + *valret = strtol(str, &endp, 0); + if(endp == str) { + return -1; + } + return 0; +} + +int optcfg_float_value(char *str, float *valret) +{ + char *endp; + *valret = strtod(str, &endp); + if(endp == str) { + return -1; + } + return 0; +} + + + +static int get_opt(struct optcfg *oc, const char *arg) +{ + int i, ndashes = 0; + + while(*arg && *arg == '-') { + ndashes++; + arg++; + } + + if(ndashes > 2) { + arg -= ndashes; + } + + if(arg[1]) { /* match long options */ + for(i=0; oc->optlist[i].opt != -1; i++) { + if(strcmp(arg, oc->optlist[i].s) == 0) { + return i; + } + } + } else { + for(i=0; oc->optlist[i].opt != -1; i++) { + if(arg[0] == oc->optlist[i].c) { + return i; + } + } + } + return -1; +} + +static char *skip_spaces(char *s) +{ + while(*s && isspace(*s)) ++s; + return s; +} + +static void strip_comments(char *s) +{ + while(*s && *s != '#') ++s; + if(*s == '#') *s = 0; +} + +static void strip_trailing_spaces(char *s) +{ + char *end = s + strlen(s) - 1; + while(end >= s && isspace(*end)) { + *end-- = 0; + } +} + +static char *parse_keyval(char *line) +{ + char *val; + char *eq = strchr(line, '='); + if(!eq) return 0; + + *eq = 0; + strip_trailing_spaces(line); + val = skip_spaces(eq + 1); + strip_trailing_spaces(val); + + if(!*line || !*val) { + return 0; + } + return val; +} diff -r 000000000000 -r d9b3fba68705 src/optcfg/optcfg.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/optcfg/optcfg.h Thu Jan 21 08:45:31 2016 +0200 @@ -0,0 +1,86 @@ +/* generic unified commandline option and config file parsing library */ +#ifndef LIBOPTCFG_H_ +#define LIBOPTCFG_H_ + +struct optcfg; + +struct optcfg_option { + char c; /* short (optional): used only for argument parsing */ + char *s; /* long: used for long options and config files */ + int opt; /* the corresponding option enumeration */ + char *desc; /* text description for printing usage information */ +}; + +typedef int (*optcfg_opt_callback)(struct optcfg *oc, int opt, void *cls); +typedef int (*optcfg_arg_callback)(struct optcfg *oc, const char *arg, void *cls); + +#ifdef __cplusplus +extern "C" { +#endif + +/* initialize the optcfg object with a valid option vector terminated by an + * entry with an opt value of -1 (other fields ignored for termination purposes) + * + * Example: + * struct optcfg_option options[] = { + * {'f', "foo", OPT_FOO, "Makes sure the foo is bar"}, + * {'h', "help", OPT_HELP, "Print usage information and exit"}, + * {0, 0, -1, 0} + * }; + * struct optcfg *oc = optcfg_init(options); + */ +struct optcfg *optcfg_init(struct optcfg_option *optv); +void optcfg_destroy(struct optcfg *oc); + +/* The parse_* functions call the option callback for each option. + * + * The option callback can then call optcfg_next_value to retrieve any + * values attached to this option. When optcfg_next_value returns 0, there + * are no more values available. + * The option callback must return 0 for success, and -1 to abort parsing. + */ +void optcfg_set_opt_callback(struct optcfg *oc, optcfg_opt_callback func, void *cls); +/* the argument callback is only called from optcfg_parse_args(), when a non-option + * argument is encountered (an argument not starting with a dash) + */ +void optcfg_set_arg_callback(struct optcfg *oc, optcfg_arg_callback func, void *cls); + +enum { OPTCFG_ERROR_FAIL, OPTCFG_ERROR_IGNORE }; +void optcfg_set_error_action(struct optcfg *oc, int act); + +int optcfg_parse_args(struct optcfg *oc, int argc, char **argv); +int optcfg_parse_config_file(struct optcfg *oc, const char *fname); +int optcfg_parse_config_stream(struct optcfg *oc, FILE *fp); +int optcfg_parse_config_line(struct optcfg *oc, const char *line); +/* TODO custom I/O callback version of config file parsing */ + +/* special value function which returns if the option is enabled or disabled + * For config files it works similar to calling optcfg_next_value, and + * optcfg_bool_value in sequence. + * For argument parsing however, it doesn't consume further arguments. Merely + * the presence of the option makes it enabled, and its presence with a -no- + * prefix disables it. (TODO the second part of this) + */ +int optcfg_enabled_value(struct optcfg *oc, int *enabledp); + +/* call optcfg_next_value in the option callback to retrieve the next value + * of the current option. returns 0 if there is no next value. + */ +char *optcfg_next_value(struct optcfg *oc); + +/* helper function which can be used to print the available options */ +void optcfg_print_options(struct optcfg *oc); + +/* helper functions to convert value strings to typed values + * returns 0 for success and value is returned through the valret pointer, + * otherwise it returns -1 for type mismatch, and valret contents are undefined + */ +int optcfg_bool_value(char *str, int *valret); /* accepts yes/no, true/false, 1/0 */ +int optcfg_int_value(char *str, int *valret); +int optcfg_float_value(char *str, float *valret); + +#ifdef __cplusplus +} +#endif + +#endif /* LIBOPTCFG_H_ */