=============================================================================== opt - Option parsing 2006-02-25 SYNOPSIS #include <libHX.h> struct HXoption { const char *ln; char sh; unsigned int type; void *ptr, *uptr; void (*cb)(const struct HXoptcb *) int val; const char *help, *htyp; }; int HX_getopt(const struct HXoption *TABLE, int *ARGC, const char ***ARGV, unsigned int FLAGS); HX_getopt() This function parses *ARGV and takes action according to TABLE. Options are "eaten" and *ARGC/*ARGV are replaced with new string arrays (located on the heap) with the remaining arguments. FLAGS is a bitmask that can consist of: HXOPT_PTHRU Pass unknown options back into the new *ARGV, instead of throwing an error. HXOPT_DESTROY_OLD free() the old *ARGV. This should be used on every call that provides an ARGV that already lives in the heap. HXOPT_QUIET Do not fprintf(stderr) any warnings. HXOPT_HELPONERR Display the help on error. HXOPT_USAGEONERR Display a short usage info on error. Negative return values of HX_getopt() or zero denote error, anything else is success. The struct members are: ->ln Long option to match, if any (NULL for none) ->sh Short option to match, if any ('\0' for none) ->type Type of ptr or type of operation ->ptr Pointer to variable where option will be stored. Might be NULL to not store anything. ->uptr User-defined pointer for this option (can be used in callbacks) ->cb Callback to execute when this option is seen (after possibly assigning the option to ->ptr) ->val Value to use if ->type is HXTYPE_VAL ->sval Value to use if ->type is HXTYPE_SVAL ->help Help text for this option ->htyp Help type for this option (see below) Because that's a lot of options for an option, the use of C99 initializers is advised, e.g.: {.sh = 'f', .type = HXTYPE_STRING, .ptr = &file, .help = "Password file (default /etc/passwd)", .htyp = "FILE"}, this is unfortunately not possible in C++ or G++, so you are stuck with the expanded version, which is subject to change anytime (which is why C99 initializers should be used!). ->type can be: HXTYPE_NONE int * Set ->ptr to 1 if the option is seen. HXTYPE_VAL none, but set ->val Set ->ptr to ->val if the option is seen. HXTYPE_SVAL none, but set ->sval Set ->ptr to ->sval if the option is seen. HXTYPE_BOOL int * Expects "yes" or "no" (or 1/0, or on/off) and puts 1/0 into ->ptr. HXTYPE_BYTE unsigned char * A single byte (any further bytes in the value are ignored) HXTYPE_STRING char ** The string is allocated and read entirely. Numbers: HXTYPE_UCHAR unsigned char * A number (range 0 to 255). It might be written in any notation strtol() understands. (This usually includes at least octal, decimal and hexadecimal. This applies to all "numbers" in this table. HXTYPE_CHAR char * -128 to 127 HXTYPE_USHORT unsigned short * 0 to 65535 HXTYPE_SHORT short * -32768 to 32767 HXTYPE_UINT unsigned int * HXTYPE_INT int * HXTYPE_ULONG unsigned long * HXTYPE_LONG long * HXTYPE_FLOAT float * HXTYPE_DOUBLE double * HXTYPE_ULLONG unsigned long long * (not MSVC) HXTYPE_LLONG long long * (not MSVC) ->cb is called when the corresponding option has been parsed and ->cb is not NULL. Since the options can be arranged in any order in the configuration file, you should take care when assuming that other keys/ptrs have already been filled. uptr can be an argument of your choice, i.e.: SHCONFIG int got_min, got_max; struct rconfig_opt table[] = { {"UID_MIN", RCONF_LONG, &uid_min, set_flag, &got_min}, {"UID_MAX", RCONF_LONG, &uid_max, set_flag, &got_max}, {NULL}, }; static int set_flag(const char *key, unsigned char fmt, void *ptr, void *uptr) { *(int *)uptr = 1; } To start parsing a file, call the HX_rconfig() function with the corresponding parameters. If you want to read configuration files from different paths, i.e. to build up on default values, you can use HX_rconfig_pv() like the next code example. (pv = path vector) struct rconfig_opt table[] = { {"UID_MIN", RCONF_LONG, &uid_min, NULL}, {"UID_MAX", RCONF_LONG, &uid_max, NULL}, {NULL}, }; const char *pv_a[] = {"/etc", "/usr/local/etc", NULL}, *pv_b[] = {".", "/etc", NULL}; // Will parse /etc/configfile HX_rconfig("/etc/configfile", table); // Will parse /etc/configfile and /usr/local/etc/configfile HX_rconfig_pv(pv_a, "configfile", table, 0); // Will only parse the first successful file HX_rconfig_pv(pv_b, "configfile", table, RCONFIG_ONE); The call to HX_rconfig() will either return 1 for success, 0 for no success (actually 0 is never returned) and -errno for an error. The next call, with pv_a will parse /etc/configfile, etc. (pv from left to right). No value is returned. The call with pv_b will only read the first successful opened file, i.e. if you have both ./configfile and /etc/configfile, only the former is read if it can be opened. ===============================================================================