/* ** XResource.c: ** These routines provide modules with an interface to parse all kinds of ** configuration options (X resources, command line options and configuration ** file lines) in the same way (Xrm database). */ #include "config.h" #include #include #include #include "fvwmlib.h" /*************************************************************************** * If you have a module MyModule and want to parse X resources as well as * command line options and a config file: * *** EXAMPLE ***************************************************************/ #if 0 #include void main(int argc, char **argv) { const char *MyName = "MyModule"; XrmDatabase db = NULL; char *value; char *line; /* our private options */ const XrmOptionDescRec my_opts[] = { { "-iconic", ".Iconic", XrmoptionNoArg, "any_string" }, { "-foo", "*bar", XrmoptionSepArg, NULL } }; int opt_argc = argc - 6; /* options start at 6th argument for modules */ char **opt_argv = argv + 6; /* ... (open config file, etc.) */ /* Get global X resources */ MergeXResources(NULL, &db, False); /* config file descriptor in fd; config file takes precedence over X * resources (this may not be what you want). */ for (GetConfigLine(fd, &line); line != NULL; GetConfigLine(fd, &line)) { if (!MergeConfigLineResource(&db, line, MyName, '*')) { /* Parse other lines here (e.g. "IconPath") */ } else { /* You may still have to parse the line here yourself (e.g. * FvwmButtons may have multiple lines for the same resource). */ } } /* command line takes precedence over all */ MergeCmdLineResources(&db, (XrmOptionDescList)my_opts, 2, MyName, &opt_argc, opt_argv, True /*no default options*/); /* Now parse the database values: */ if (GetResourceString(db, "iconic", MyName, &value)) { /* Just see if there is *any* string and don't mind it's value. */ /* flags |= ICONIC */ } if (GetResourceString(db, "bar", MyName, &value)) { /* ... */ } /* ... */ XrmDestroyDatabase(db); } #endif /*** END OF EXAMPLE ********************************************************/ /* Default option table */ static XrmOptionDescRec default_opts[] = { { "-fg", "*Foreground", XrmoptionSepArg, NULL }, { "-bg", "*Background", XrmoptionSepArg, NULL }, { "-fn", "*Font", XrmoptionSepArg, NULL }, { "-geometry", "*Geometry", XrmoptionSepArg, NULL }, { "-title", "*Title", XrmoptionSepArg, NULL } /* Remember to update NUM_DEFAULT_OPTIONS if you change this list! */ }; #define NUM_DEFAULT_OPTS 5 /* internal function */ static void DoMergeString(char *resource, XrmDatabase *ptarget, Bool override) { XrmDatabase db; if (!resource) return; db = XrmGetStringDatabase(resource); XrmCombineDatabase(db, ptarget, override); } /*************************************************************************** * * Merges all X resources for the display/screen into a Xrm database. * If the database does not exist (*pdb == NULL), a new database is created. * If override is True, existing entries of the same name are overwritten. * * Please remember to destroy the database with XrmDestroyDatabase(*pdb) * if you do not need it amymore. * ***************************************************************************/ void MergeXResources(Display *dpy, XrmDatabase *pdb, Bool override) { if (!*pdb) /* create new database */ XrmPutStringResource(pdb, "", ""); DoMergeString(XResourceManagerString(dpy), pdb, override); DoMergeString(XScreenResourceString(DefaultScreenOfDisplay(dpy)), pdb, override); } /*************************************************************************** * * Parses the command line given through pargc/argv and puts recognized * entries into the Xrm database *pdb (if *pdb is NULL a new database is * created). The caller may provide an option list in XrmOptionDescList * format (see XrmParseCommand manpage) and/or parse only standard options * (fg, bg, geometry, fn, title). User given options have precedence over * standard options which are disabled if fNoDefaults is True. Existing * values are overwritten. * * All recognised options are removed from the command line (*pargc and * argv are updated accordingly). * * Please remember to destroy the database with XrmDestroyDatabase(*pdb) * if you do not need it amymore. * ***************************************************************************/ void MergeCmdLineResources(XrmDatabase *pdb, XrmOptionDescList opts, int num_opts, char *name, int *pargc, char **argv, Bool fNoDefaults) { if (opts && num_opts > 0) XrmParseCommand(pdb, opts, num_opts, name, pargc, argv); if (!fNoDefaults) XrmParseCommand(pdb, default_opts, NUM_DEFAULT_OPTS, name, pargc, argv); } /*************************************************************************** * * Takes a line from a config file and puts a corresponding value into the * Xrm database *pdb (will be created if *pdb is NULL). 'prefix' is the * name of the module. A specific type of binding in the database must be * provided in bindstr (either "*" or "."). Leading unquoted whitespace are * stripped from value. Existing values in the database are overwritten. * True is returned if the line was indeed merged into the database (i.e. it * had the correct format) or False if not. * * Example: If prefix = "MyModule" and bindstr = "*", the line * * *MyModuleGeometry 80x25+0+0 * * will be put into the database as if you had this line in your .Xdefaults: * * MyModule*Geometry: 80x25+0+0 * * Please remember to destroy the database with XrmDestroyDatabase(*pdb) * if you do not need it amymore. * ***************************************************************************/ Bool MergeConfigLineResource(XrmDatabase *pdb, char *line, char *prefix, char *bindstr) { int len; char *end; char *value; char *myvalue; char *resource; size_t reslen; /* translate "*(prefix)(suffix)" to "(prefix)(binding)(suffix)", * e.g. "*FvwmPagerGeometry" to "FvwmPager.Geometry" */ if (!line || *line != '*') return False; line++; len = (prefix) ? strlen(prefix) : 0; if (!prefix || strncasecmp(line, prefix, len)) return False; line += len; end = line; while (*end && !isspace(*end)) end++; if (line == end) return False; value = end; while (*value && isspace(*value)) value++; /* prefix*suffix: value */ reslen = len + (end - line) + 2; resource = (char *)safemalloc(reslen); strlcpy(resource, prefix,reslen); strlcat(resource, bindstr,reslen); strncat(resource, line, end - line); len = strlen(value); myvalue = (char *)safemalloc(len + 1); strlcpy(myvalue, value,len+1); for (len--; len >= 0 && isspace(myvalue[len]); len--) myvalue[len] = 0; /* merge string into database */ XrmPutStringResource(pdb, resource, myvalue); free(resource); free(myvalue); return True; } /*************************************************************************** * * Reads the string-value for the pair prefix/resource from the Xrm database * db and returns a pointer to it. The string may only be read and must not * be freed by the caller. 'prefix' is the class name (usually the name of * the module). If no value is found in the database, *val will be NULL. * True is returned if a value was found, False if not. If you are only * interested if there is a string, but not it's value, you can set val to * NULL. * * Example: * * GetResourceString(db, "Geometry", "MyModule", &s) * * returns the string value of the "Geometry" resource for MyModule in s. * ***************************************************************************/ Bool GetResourceString(XrmDatabase db, const char *resource, const char *prefix, char **val) { XrmValue xval = { 0, NULL }; char *str_type; char *name; size_t len; len = strlen(resource) + strlen(prefix) + 2; name = (char *)safemalloc(len); strlcpy(name, prefix,len); strlcat(name, ".",len); strlcat(name, resource,len); if (!XrmGetResource(db, name, name, &str_type, &xval) || xval.addr == NULL) { free(name); if (val) *val = NULL; return False; } free(name); if (val) *val = xval.addr; return True; }