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