xenocara/app/fvwm/libs/XResource.c

276 lines
8.4 KiB
C

/*
** 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 <X11/Xlib.h>
#include <X11/Xresource.h>
#include <string.h>
#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 <fvwmlib.h>
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;
}