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