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