1 /* -*-c-*- */
2 /* Copyright (C) 1999 Dominik Vogt */
3 /* This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, see: <http://www.gnu.org/licenses/>
15 */
16
17 /*
18 ** XResource.c:
19 ** These routines provide modules with an interface to parse all kinds of
20 ** configuration options (X resources, command line options and configuration
21 ** file lines) in the same way (Xrm database).
22 */
23
24 #include "config.h"
25
26 #include <X11/Xlib.h>
27 #include <X11/Xresource.h>
28
29 #include "fvwmlib.h"
30 #include "XResource.h"
31
32
33
34 /*
35 * If you have a module MyModule and want to parse X resources as well as
36 * command line options and a config file:
37 *
38 *** EXAMPLE */
39 #if 0
40 #include <fvwmlib.h>
41
42 void main(int argc, char **argv)
43 {
44 const char *MyName = "MyModule";
45 XrmDatabase db = NULL;
46 XrmValue *rm_value;
47 char *line;
48
49 /* our private options */
50 const XrmOptionDescRec my_opts[] = {
51 { "-iconic", ".Iconic", XrmoptionNoArg, "any_string" },
52 { "-foo", "*bar", XrmoptionSepArg, NULL }
53 };
54 int opt_argc = argc - 6; /* options start at 6th argument for modules */
55 char **opt_argv = argv + 6;
56
57 /* ... (open config file, etc.) */
58
59 /* Get global X resources */
60 MergeXResources(NULL, &db, False);
61
62 /* config file descriptor in fd; config file takes precedence over X
63 * resources (this may not be what you want). */
64 for (GetConfigLine(fd, &line); line != NULL; GetConfigLine(fd, &line))
65 {
66 if (!MergeConfigLineResource(&db, line, MyName, '*'))
67 {
68 /* Parse other lines here (e.g. "ImagePath") */
69 }
70 else
71 {
72 /* You may still have to parse the line here yourself (e.g.
73 * FvwmButtons may have multiple lines for the same resource). */
74 }
75 }
76
77 /* command line takes precedence over all */
78 MergeCmdLineResources(&db, (XrmOptionDescList)my_opts, 2, MyName,
79 &opt_argc, opt_argv, True /*no default options*/);
80
81 /* Now parse the database values: */
82 if (GetResourceString(db, "iconic", MyName, &rm_value))
83 {
84 /* Just see if there is *any* string and don't mind it's value. */
85 /* flags |= ICONIC */
86 }
87 if (GetResourceString(db, "bar", MyName, &rm_value))
88 {
89 /* ... */
90 }
91
92 /* ... */
93 XrmDestroyDatabase(db);
94 }
95 #endif
96
97 /*** END OF EXAMPLE ***/
98
99
100
101
102 /* Default option table */
103 static XrmOptionDescRec default_opts[] =
104 {
105 { "-fg", "*Foreground", XrmoptionSepArg, NULL },
106 { "-bg", "*Background", XrmoptionSepArg, NULL },
107 { "-fn", "*Font", XrmoptionSepArg, NULL },
108 { "-geometry", "*Geometry", XrmoptionSepArg, NULL },
109 { "-title", "*Title", XrmoptionSepArg, NULL }
110 /* Remember to update NUM_DEFAULT_OPTIONS if you change this list! */
111 };
112 #define NUM_DEFAULT_OPTS 5
113
114
115
116 /* internal function */
DoMergeString(char * resource,XrmDatabase * ptarget,Bool override)117 static void DoMergeString(char *resource, XrmDatabase *ptarget, Bool override)
118 {
119 XrmDatabase db;
120
121 if (!resource)
122 return;
123 db = XrmGetStringDatabase(resource);
124 XrmCombineDatabase(db, ptarget, override);
125 }
126
127 /*
128 *
129 * Merges all X resources for the display/screen into a Xrm database.
130 * If the database does not exist (*pdb == NULL), a new database is created.
131 * If override is True, existing entries of the same name are overwritten.
132 *
133 * Please remember to destroy the database with XrmDestroyDatabase(*pdb)
134 * if you do not need it amymore.
135 *
136 */
MergeXResources(Display * dpy,XrmDatabase * pdb,Bool override)137 void MergeXResources(Display *dpy, XrmDatabase *pdb, Bool override)
138 {
139 if (!*pdb)
140 /* create new database */
141 XrmPutStringResource(pdb, "", "");
142 DoMergeString(XResourceManagerString(dpy), pdb, override);
143 DoMergeString(XScreenResourceString(DefaultScreenOfDisplay(dpy)), pdb,
144 override);
145 }
146
147 /*
148 *
149 * Parses the command line given through pargc/argv and puts recognized
150 * entries into the Xrm database *pdb (if *pdb is NULL a new database is
151 * created). The caller may provide an option list in XrmOptionDescList
152 * format (see XrmParseCommand manpage) and/or parse only standard options
153 * (fg, bg, geometry, fn, title). User given options have precedence over
154 * standard options which are disabled if fNoDefaults is True. Existing
155 * values are overwritten.
156 *
157 * All recognised options are removed from the command line (*pargc and
158 * argv are updated accordingly).
159 *
160 * Please remember to destroy the database with XrmDestroyDatabase(*pdb)
161 * if you do not need it amymore.
162 *
163 */
MergeCmdLineResources(XrmDatabase * pdb,XrmOptionDescList opts,int num_opts,char * name,int * pargc,char ** argv,Bool fNoDefaults)164 void MergeCmdLineResources(XrmDatabase *pdb, XrmOptionDescList opts,
165 int num_opts, char *name, int *pargc, char **argv,
166 Bool fNoDefaults)
167 {
168 if (!name)
169 return;
170 if (opts && num_opts > 0)
171 XrmParseCommand(pdb, opts, num_opts, name, pargc, argv);
172 if (!fNoDefaults)
173 XrmParseCommand(pdb, default_opts, NUM_DEFAULT_OPTS,
174 name, pargc, argv);
175 }
176
177 /*
178 *
179 * Takes a line from a config file and puts a corresponding value into the
180 * Xrm database *pdb (will be created if *pdb is NULL). 'prefix' is the
181 * name of the module. A specific type of binding in the database must be
182 * provided in bindstr (either "*" or "."). Leading unquoted whitespace are
183 * stripped from value. Existing values in the database are overwritten.
184 * True is returned if the line was indeed merged into the database (i.e. it
185 * had the correct format) or False if not.
186 *
187 * Example: If prefix = "MyModule" and bindstr = "*", the line
188 *
189 * *MyModuleGeometry 80x25+0+0
190 *
191 * will be put into the database as if you had this line in your .Xdefaults:
192 *
193 * MyModule*Geometry: 80x25+0+0
194 *
195 * Please remember to destroy the database with XrmDestroyDatabase(*pdb)
196 * if you do not need it amymore.
197 *
198 */
MergeConfigLineResource(XrmDatabase * pdb,char * line,char * prefix,char * bindstr)199 Bool MergeConfigLineResource(XrmDatabase *pdb, char *line, char *prefix,
200 char *bindstr)
201 {
202 int len;
203 char *end;
204 char *value;
205 char *myvalue;
206 char *resource;
207
208 /* translate "*(prefix)(suffix)" to "(prefix)(binding)(suffix)",
209 * e.g. "*FvwmPagerGeometry" to "FvwmPager.Geometry" */
210 if (!line || *line != '*')
211 return False;
212
213 line++;
214 len = (prefix) ? strlen(prefix) : 0;
215 if (!prefix || strncasecmp(line, prefix, len))
216 return False;
217
218 line += len;
219 end = line;
220 while (*end && !isspace((unsigned char)*end))
221 end++;
222 if (line == end)
223 return False;
224 value = end;
225 while (*value && isspace((unsigned char)*value))
226 value++;
227
228 /* prefix*suffix: value */
229 /* TA: FIXME! xasprintf() */
230 resource = fxmalloc(len + (end - line) + 2);
231 strcpy(resource, prefix);
232 strcat(resource, bindstr);
233 strncat(resource, line, end - line);
234
235 len = strlen(value);
236 myvalue = fxmalloc(len + 1);
237 strcpy(myvalue, value);
238 for (len--; len >= 0 && isspace((unsigned char)myvalue[len]); len--)
239 myvalue[len] = 0;
240
241 /* merge string into database */
242 XrmPutStringResource(pdb, resource, myvalue);
243
244 free(resource);
245 free(myvalue);
246 return True;
247 }
248
249 /*
250 *
251 * Reads the string-value for the pair prefix/resource from the Xrm database
252 * db and returns a pointer to it. The string may only be read and must not
253 * be freed by the caller. 'prefix' is the class name (usually the name of
254 * the module). If no value is found in the database, *val will be NULL.
255 * True is returned if a value was found, False if not. If you are only
256 * interested if there is a string, but not it's value, you can set val to
257 * NULL.
258 *
259 * Example:
260 *
261 * GetResourceString(db, "Geometry", "MyModule", &r)
262 *
263 * returns the resource value of the "Geometry" resource for MyModule in r.
264 *
265 */
GetResourceString(XrmDatabase db,const char * resource,const char * prefix,XrmValue * xval)266 Bool GetResourceString(
267 XrmDatabase db, const char *resource, const char *prefix, XrmValue *xval)
268 {
269 char *str_type;
270 char *name;
271 char *Name;
272 int i;
273
274 /* TA: FIXME! xasprintf() */
275 name = fxmalloc(strlen(resource) + strlen(prefix) + 2);
276 Name = fxmalloc(strlen(resource) + strlen(prefix) + 2);
277 strcpy(name, prefix);
278 strcat(name, ".");
279 strcat(name, resource);
280 strcpy(Name, name);
281 if (isupper(name[0]))
282 name[0] = tolower(name[0]);
283 if (islower(Name[0]))
284 Name[0] = toupper(Name[0]);
285 i = strlen(prefix) + 1;
286 if (isupper(name[i]))
287 name[i] = tolower(name[i]);
288 if (islower(Name[i]))
289 Name[i] = toupper(Name[i]);
290 if (!XrmGetResource(db, name, Name, &str_type, xval) ||
291 xval->addr == NULL || xval->size == 0)
292 {
293 free(name);
294 free(Name);
295 xval->size = 0;
296 xval->addr = NULL;
297
298 return False;
299 }
300 free(name);
301 free(Name);
302
303 return True;
304 }
305