Initial revision
[bpt/emacs.git] / src / xrdb.c
CommitLineData
f3a0bf5c
JB
1/* Deal with the X Resource Manager.
2 Copyright (C) 1990 Free Software Foundation.
3
4This program is free software; you can redistribute it and/or modify
5it under the terms of the GNU General Public License as published by
6the Free Software Foundation; either version 1, or (at your option)
7any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12GNU General Public License for more details.
13
14You should have received a copy of the GNU General Public License
15along with this program; see the file COPYING. If not, write to
16the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
17
18/* Written by jla, 4/90 */
19
20#include <X11/Xlib.h>
21#include <X11/Xatom.h>
22#include <X11/Xos.h>
23#include <X11/X.h>
24#include <X11/Xutil.h>
25#include <X11/Xresource.h>
26#include <sys/param.h>
27#include <pwd.h>
28#include <sys/stat.h>
29
30#ifdef emacs
31#include "config.h"
32#endif
33
34extern char *getenv ();
35extern int getuid ();
36extern struct passwd *getpwuid ();
37extern struct passwd *getpwnam ();
38
39static char *
40gethomedir (dirname)
41 char *dirname;
42{
43 int uid;
44 struct passwd *pw;
45 char *ptr;
46
47 if ((ptr = getenv ("HOME")) == NULL)
48 {
49 if ((ptr = getenv ("USER")) != NULL)
50 pw = getpwnam (ptr);
51 else
52 {
53 uid = getuid ();
54 pw = getpwuid (uid);
55 }
56 if (pw)
57 ptr = pw->pw_dir;
58 else
59 {
60 ptr = NULL;
61 *dirname = '\0';
62 }
63 }
64
65 if (ptr != NULL)
66 strcpy (dirname, ptr);
67
68 dirname += strlen (dirname);
69 *dirname = '/';
70 dirname++;
71 *dirname = '\0';
72
73 return dirname;
74}
75
76static int
77file_p (path)
78 char *path;
79{
80 struct stat status;
81
82 return (access (path, R_OK) == 0 /* exists and is readable */
83 && stat (path, &status) == 0 /* get the status */
84 && (status.st_mode & S_IFDIR) == 0); /* not a directory */
85}
86
87#if 0
88#define X_DEFAULT_SEARCH_PATH "/usr/lib/X11/"
89#endif
90
91/* Isn't this just disgusting? */
92
93#define X_DEFAULT_SEARCH_PATH "/usr/lib/X11/%L/%T/%N%S:/usr/lib/X11/%l/%T/%N%S:/usr/lib/X11/%T/%N%S"
94
95static int
96decode_magic (string, file, return_path)
97 char *string, *file, *return_path;
98{
99 char *p = string;
100 char *t = return_path;
101
102 while (*p)
103 {
104 if (*p == '%')
105 switch (*++p)
106 {
107 case '%':
108 *t++ = '%';
109 p++;
110 break;
111
112 case 'N':
113 case 'T':
114 case 'S':
115 case 'L':
116 case 'l':
117 case 't':
118 case 'c':
119 default:
120 p++;
121 if (*t == '/' && *p == '/')
122 p++;
123 break;
124 }
125 else
126 *t++ = *p++;
127 }
128 *t = '\0';
129 strcat (return_path, file);
130
131 if (file_p (return_path))
132 return 1;
133
134 return_path[0] = '\0';
135 return 0;
136}
137
138static int
139magic_searchpath_decoder (incantation_string, file, return_path)
140 char *incantation_string, *return_path, *file;
141{
142 register char *s = incantation_string;
143 register char *p;
144 register char string[MAXPATHLEN];
145
146 while (*s)
147 {
148 p = s;
149
150 while (*p && *p != ':')
151 p++;
152
153 if (*p == ':' && *(p + 1) == ':')
154 {
155 bcopy ("%N%S", string, 5);
156 if (decode_magic (string, file, return_path))
157 return 1;
158
159 s = p + 1;
160 continue;
161 }
162
163 if (p > s)
164 {
165 int len = p - s;
166
167 bcopy (s, string, len);
168 string[len + 1] = '\0';
169 if (decode_magic (string, file, return_path))
170 return 1;
171 }
172
173 if (p)
174 s = p + 1;
175 else
176 return 0;
177 }
178
179 return 0;
180}
181\f
182static XrmDatabase
183get_system_app (class)
184 char *class;
185{
186 XrmDatabase db;
187 char path[MAXPATHLEN];
188 char *p;
189
190 if ((p = getenv ("XFILESEARCHPATH")) == NULL)
191 p = X_DEFAULT_SEARCH_PATH;
192
193 if (! magic_searchpath_decoder (p, class, path))
194 return NULL;
195
196 db = XrmGetFileDatabase (path);
197 return db;
198}
199
200static XrmDatabase
201get_fallback (display)
202 Display *display;
203{
204 XrmDatabase db;
205
206 return NULL;
207}
208
209static XrmDatabase
210get_user_app (class)
211 char *class;
212{
213 XrmDatabase db;
214 char *magic_path;
215 char path[MAXPATHLEN];
216
217 if ((magic_path = getenv ("XUSERFILESEARCHPATH")) == NULL)
218 {
219 char homedir[MAXPATHLEN];
220 char *default_magic;
221 char *p;
222
223 gethomedir (homedir);
224
225 if ((p = getenv ("XAPPLRESDIR")) == NULL)
226 {
227 default_magic = "%s/%%L/%%N:%s/%%l/%%N:%s/%%N";
228 magic_path = (char *) alloca ((3 * strlen (homedir))
229 + strlen (default_magic));
230 sprintf (magic_path, default_magic, homedir, homedir, homedir);
231 }
232 else
233 {
234 default_magic = "%s/%%L/%%N:%s/%%l/%%N:%s/%%N:%s/%%N";
235 magic_path = (char *) alloca ((3 * strlen (p))
236 + strlen (default_magic)
237 + strlen (homedir));
238 sprintf (magic_path, default_magic, p, p, p, homedir);
239 }
240 }
241
242 if (! magic_searchpath_decoder (magic_path, class, path))
243 return NULL;
244
245 db = XrmGetFileDatabase (path);
246 return db;
247}
248
249static XrmDatabase
250get_user_db (display)
251 Display *display;
252{
253 XrmDatabase db;
254 char *xdefs;
255
256 xdefs = XResourceManagerString (display);
257 if (xdefs != NULL)
258 db = XrmGetStringDatabase (xdefs);
259 else
260 {
261 char xdefault[MAXPATHLEN];
262
263 gethomedir (xdefault);
264 strcat (xdefault, ".Xdefaults");
265 db = XrmGetFileDatabase (xdefault);
266 }
267
268 return db;
269}
270
271static XrmDatabase
272get_environ_db ()
273{
274 XrmDatabase db;
275 char *p;
276 char path[MAXPATHLEN];
277
278 if ((p = getenv ("XENVIRONMENT")) == NULL)
279 {
280 gethomedir (path);
281 strcat (path, ".Xdefaults-");
282 gethostname (path + strlen (path), MAXPATHLEN - strlen (path));
283 p = path;
284 }
285
286 db = XrmGetFileDatabase (p);
287 return db;
288}
289\f
290/* Types of values that we can find in a database */
291
292#define XrmStringType "String" /* String representation */
293XrmRepresentation x_rm_string; /* Quark representation */
294
295/* Load X resources based on the display and a possible -xrm option. */
296
297XrmDatabase
298x_load_resources (display, xrm_string, myclass)
299 Display *display;
300 char *xrm_string, *myclass;
301{
302 char *xdefs;
303 XrmDatabase rdb;
304 XrmDatabase db;
305
306 x_rm_string = XrmStringToQuark (XrmStringType);
307 XrmInitialize ();
308 rdb = XrmGetStringDatabase ("");
309
310 /* Get application system defaults */
311 db = get_system_app (myclass);
312 if (db != NULL)
313 XrmMergeDatabases (db, &rdb);
314
315 /* Get Fallback resources */
316 db = get_fallback (display);
317 if (db != NULL)
318 XrmMergeDatabases (db, &rdb);
319
320 /* Get application user defaults */
321 db = get_user_app (myclass);
322 if (db != NULL)
323 XrmMergeDatabases (db, &rdb);
324
325 /* get User defaults */
326 db = get_user_db (display);
327 if (db != NULL)
328 XrmMergeDatabases (db, &rdb);
329
330 /* Get Environment defaults. */
331 db = get_environ_db ();
332 if (db != NULL)
333 XrmMergeDatabases (db, &rdb);
334
335 /* Last, merge in any specification from the command line. */
336 if (xrm_string != NULL)
337 {
338 db = XrmGetStringDatabase (xrm_string);
339 if (db != NULL)
340 XrmMergeDatabases (db, &rdb);
341 }
342
343 return rdb;
344}
345
346/* Retrieve the value of the resource specified by NAME with class CLASS
347 and of type TYPE from database RDB. The value is returned in RET_VALUE. */
348
349int
350x_get_resource (rdb, name, class, expected_type, ret_value)
351 XrmDatabase rdb;
352 char *name, *class;
353 XrmRepresentation expected_type;
354 XrmValue *ret_value;
355{
356 XrmValue value;
357 XrmName namelist[100];
358 XrmClass classlist[100];
359 XrmRepresentation type;
360
361 XrmStringToNameList(name, namelist);
362 XrmStringToClassList(class, classlist);
363
364 if (XrmQGetResource (rdb, namelist, classlist, &type, &value) == True
365 && (type == expected_type))
366 {
367 if (type == x_rm_string)
368 (char *) ret_value->addr = value.addr;
369 else
370 bcopy (value.addr, ret_value->addr, ret_value->size);
371
372 return value.size;
373 }
374
375 return 0;
376}
377
378/* Retrieve the string resource specified by NAME with CLASS from
379 database RDB. */
380
381char *
382x_get_string_resource (rdb, name, class)
383 XrmDatabase rdb;
384 char *name, *class;
385{
386 XrmValue value;
387
388 if (x_get_resource (rdb, name, class, x_rm_string, &value))
389 return (char *) value.addr;
390
391 return (char *) 0;
392}
393\f
394#ifdef TESTRM
395#include <stdio.h>
396#include "arg-list.h"
397
398static void
399fatal (msg, prog, x1, x2, x3, x4, x5)
400 char *msg, *prog;
401 int x1, x2, x3, x4, x5;
402{
403 extern int errno;
404
405 if (errno)
406 perror (prog);
407
408 (void) fprintf (stderr, msg, prog, x1, x2, x3, x4, x5);
409 exit (1);
410}
411
412main (argc, argv)
413 int argc;
414 char **argv;
415{
416 Display *display;
417 char *displayname, *resource_string, *class;
418 XrmDatabase xdb;
419 List *arg_list, *lp;
420
421 arg_list = arg_listify (argc, argv);
422
423 lp = member ("-d", arg_list);
424 if (!NIL (lp))
425 displayname = car (cdr (lp));
426 else
427 displayname = "localhost:0.0";
428
429 lp = member ("-xrm", arg_list);
430 if (! NIL (lp))
431 resource_string = car (cdr (lp));
432 else
433 resource_string = (char *) 0;
434
435 lp = member ("-c", arg_list);
436 if (! NIL (lp))
437 class = car (cdr (lp));
438 else
439 class = "Emacs";
440
441 free_arglist (arg_list);
442
443
444
445 if (!(display = XOpenDisplay (displayname)))
446 fatal ("Can't open display '%s'\n", XDisplayName (displayname));
447
448 xdb = x_load_resources (display, resource_string, class);
449
450#if 0
451 /* In a real program, you'd want to also do this: */
452 display->db = xdb;
453#endif
454
455 while (1)
456 {
457 char line[90];
458
459 printf ("String: ");
460 gets (line);
461 if (strlen (line))
462 {
463 char *value = x_get_string_resource (xdb, line, class);
464
465 if (value != NULL)
466 printf ("\t%s: %s\n\n", line, value);
467 else
468 printf ("\tNo Value.\n\n");
469 }
470 else
471 break;
472 }
473 printf ("\tExit.\n\n");
474
475 XCloseDisplay (display);
476}
477#endif /* TESTRM */