-lbrttutil #include "BUConfigure.h"
The basic concept with this utility is for an application programmer to define a parameter structure that gets filled in from either parameter file input or from variable argument list key-value pairs using the configure methods (see below). The parameter structure can be as complex as needed. The BUConfigure class is already set up to parse out simple scalar int, double and char * parameters. The application programmer can extend this for other more complex and custom parameter parsing through callback procedures. Care has been taken to make it easy to subclass BUConfigure to extend the parsing capabilities. Custom parsers can even be used to initiate program actions.
The basic configuration "switchboard" is a structure, BU_ConfigureSpec, that the application programmer must provide that relates locations in the application parameter data structure to key names and data types.
typedef struct BU_ConfigureSpec { const char *type; const char *name; const char *defValue; int offset; int specFlags; struct BU_CustomOption *customPtr; } BU_ConfigureSpec;
The type element is a data type string. BUConfigure comes with a set of predefined data types it can parse, "boolean", for boolean parameters (yes, no, on, off, etc.), "int", for 32-bit integer data, "double", for double foating data, "string", for string data that will be allocated and copied to char * parameter pointers, and I"ptr" for generic pointers. The name element is a parameter name string and is arbitrary. Parameter name strings should be unique across a single instance of BUConfigure and any subclasses. The defValue element is a default value string that will be parsed when the BUConfigure object method setConfigureSpecs is called. The offset element is a byte offset into the application program parameter data structure corresponding to the parameter value. The specFlags element are processing flags that are defined below. The customPtr element points to an application programmer defined callback procedure for doing custom processing of this parameter, as described below.
The application programmer must first specify a set of these structures through a call to the setConfigureSpecs method before processing any configuration parameter files or specifications through variable argument lists using the configure methods.
BUConfigure();METHODS
typedef int (BU_TypeParserProc) (BU_ConfigureSpec *spec, char *value, char *paramRec);
typedef int (BU_OptionParseProc) (BU_ConfigureSpec *spec, BU_ClientData clientData, char *value, char *paramRec, int offset); typedef char *(BU_OptionPrintProc) (BU_ConfigureSpec *spec, BU_ClientData clientData, char *paramRec, int offset); typedef struct BU_CustomOption { BU_OptionParseProc *parseProc; BU_OptionPrintProc *printProc; BU_ClientData clientData; } BU_CustomOption;
#include "BUConfigure.h" /* define main class parameter data structure */ typedef struct MyClassStruct { int x, y, spc_w, spc_h, wtran; double latr, lonr, opacity; } MyClassStruct; /* prototypes for main class custom parsers */ static int myclass_parse_tran (BU_ConfigureSpec *spec, BU_ClientData clientData, char *value, char *paramRec, int offset); static char *myclass_print_tran (BU_ConfigureSpec *spec, BU_ClientData clientData, char *paramRec, int offset); static BU_CustomOption tranOption = {myclass_parse_tran, myclass_print_tran, (BU_ClientData) NULL }; /* define configure specs for main class */ static BU_ConfigureSpec configureSpecs[] = { {"int", "x", "0", BU_Offset (MyClassStruct, x), 0, NULL}, {"int", "y", "0", BU_Offset (MyClassStruct, y), 0, NULL}, {"int", "width", "0", BU_Offset (MyClassStruct, spc_w), 0, NULL}, {"int", "height", "0", BU_Offset (MyClassStruct, spc_h), 0, NULL}, {"custom", "wtran", "none", BU_Offset (MyClassStruct, wtran), 0, &tranOption}, {"double", "latr", "0.0", BU_Offset (MyClassStruct, latr), 0, NULL}, {"double", "lonr", "0.0", BU_Offset (MyClassStruct, lonr), 0, NULL}, {"double", "opacity", "1.0", BU_Offset (MyClassStruct, opacity), 0, NULL}, {"end", NULL, NULL, 0, 0, NULL} }; /* custom parsers for main class */ static int myclass_parse_tran (BU_ConfigureSpec *spec, BU_ClientData clientData, char *value, char *paramRec, int offset) { int tran_old, tran; memcpy (&tran_old, paramRec+offset, sizeof(int)); if (!strcmp(value, "none")) { tran = 0; } else if (!strcmp(value, "edp")) { tran = 1; } else if (!strcmp(value, "merc")) { tran = 2; } else if (!strcmp(value, "geog")) { tran = 3; } else { bu_register_error(0, "myclass_parse_tran: illegal value for tran: '%s'\n", value); return (-1); } memcpy (paramRec+offset, &tran, sizeof(int)); if (tran != tran_old) spec->specFlags |= BU_CONFIGURE_OPTION_SET; return (0); } static char * myclass_print_tran (BU_ConfigureSpec *spec, BU_ClientData clientData, char *paramRec, int offset) { int tran; char string[8]; memcpy (&tran, paramRec+offset, sizeof(int)); switch (tran) { case 0: strcpy(string, "none"); break; case 1: strcpy(string, "edp"); break; case 2: strcpy(string, "merc"); break; case 3: strcpy(string, "geog"); break; default: strcpy(string, "NULL"); break; } return(strdup(string)); } /* main class subclassed from BUConfigure */ class MyClass : public BUConfigure { public: MyClass () { memset (&(this->myclass), 0, sizeof(MyClassStruct)); this->setConfigureSpecs (configureSpecs, (char *) &(this->myclass), "MyClass"); }; MyClassStruct myclass; /* main class parameter structure */ }; /* define subclass parameter data structure */ typedef struct MySubClassStruct { int ymode; int preserve_yscale; double constant_aspect; double spc_ytop; char *fill; } MySubClassStruct; /* prototypes for subclass custom parsers */ static int mysubclass_parse_ybb (BU_ConfigureSpec *spec, BU_ClientData clientData, char *value, char *paramRec, int offset); static char *mysubclass_print_ybb (BU_ConfigureSpec *spec, BU_ClientData clientData, char *paramRec, int offset); static BU_CustomOption ybbOption = {mysubclass_parse_ybb, mysubclass_print_ybb, (BU_ClientData) NULL }; /* define configure specs for subclass - note new "color" type */ static BU_ConfigureSpec configuresubSpecs[] = { {"custom", "ytop", NULL, BU_Offset (MySubClassStruct, spc_ytop), BU_CONFIGURE_NULL_OK, &ybbOption}, {"boolean", "preserve_yscale", "0", BU_Offset (MySubClassStruct, preserve_yscale), 0, NULL}, {"double", "constant_aspect", "1.5", BU_Offset (MySubClassStruct, constant_aspect), 0, NULL}, {"color", "fill", "black", BU_Offset (MySubClassStruct, fill), BU_CONFIGURE_NULL_OK, NULL}, {"end", NULL, NULL, 0, 0, NULL} }; /* custom parsers for subclass */ static int mysubclass_parse_ybb (BU_ConfigureSpec *spec, BU_ClientData clientData, char *value, char *paramRec, int offset) { MySubClassStruct *sc = (MySubClassStruct *) paramRec; double bb_old, bb; memcpy (&bb_old, paramRec+offset, sizeof(double)); if (value == NULL || *value == '\0') { bb = 1.e30; } else { if (sc->ymode == 1) { bb = str2epoch (value); } else { bb = atof(value); } } memcpy (paramRec+offset, &bb, sizeof(double)); if (bb != bb_old) spec->specFlags |= BU_CONFIGURE_OPTION_SET; return (0); } static char * mysubclass_print_ybb (BU_ConfigureSpec *spec, BU_ClientData clientData, char *paramRec, int offset) { MySubClassStruct *sc = (MySubClassStruct *) paramRec; double bb; char string[32]; memcpy (&bb, paramRec+offset, sizeof(double)); sprintf (string, "%.15e", bb); return(strdup(string)); } /* custom new data type parser for "color" data types */ static int MyTypeParserProc (BU_ConfigureSpec *spec, char *value, char *paramRec) { char *ptr; char **str_ptr; int ret; if (!strcmp(spec->type, "color")) { if (!(spec->specFlags & BU_CONFIGURE_NULL_OK) && value == NULL) { bu_register_error (0, "BU_ParseConfigValue: Cannot set NULL value if not BU_CONFIGURE_NULL_OK for %s.\n", spec->name); return (BU_CONFIGURE_ERROR); } str_ptr = (char **) (paramRec+spec->offset); ptr = NULL; if (value) ptr = strdup(value); if (BU_Strcmp(*str_ptr, ptr)) spec->specFlags |= BU_CONFIGURE_OPTION_SET; if (*str_ptr) free (*str_ptr); *str_ptr = ptr; return (BU_CONFIGURE_OK); } return (BU_CONFIGURE_UNRECOGNIZED_TYPE); } /* subclass subclassed from main class which inherits BUConfigure */ class MySubClass : public MyClass { public: MySubClass () { memset (&(this->mysubclass), 0, sizeof(MySubClassStruct)); this->addTypeParser ("color", MyTypeParserProc); /* add new data type parser */ this->setConfigureSpecs (configuresubSpecs, (char *) &(this->mysubclass), "MySubClass"); }; MySubClassStruct mysubclass; /* subclass parameter structure */ }; int main (int argc, char **argv) { MyClass *myclass = new MyClass (); /* configure main class */ int ret = myclass->configure ( "x", "0", "y", "1", "width", "100", "height", "200", "wtran", "edp", "opacity", "0.5", NULL ); if (ret != BU_CONFIGURE_OK) { bu_complain (0, "myclass->configure() error.\n"); } MySubClass *mysubclass = new MySubClass (); /* configure subclass - inherits parameters from main class as well */ ret = mysubclass->configure ( "x", "1", "y", "2", "width", "300", "height", "400", "wtran", "merc", "opacity", "2.5", "ytop", "-500.0", "preserve_yscale", "yes", "constant_aspect", "0.5", "fill", "blue", NULL ); if (ret != BU_CONFIGURE_OK) { bu_complain (0, "myclass->configure() error.\n"); } exit (0); }