(syms_of_ntproc) <w32-get-true-file-attributes>: Doc fix.
[bpt/emacs.git] / src / xrdb.c
CommitLineData
f3a0bf5c 1/* Deal with the X Resource Manager.
0b5538bd 2 Copyright (C) 1990, 1993, 1994, 2000, 2001, 2002, 2003, 2004,
8cabe764 3 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
f3a0bf5c 4
3b7ad313
EN
5This file is part of GNU Emacs.
6
7GNU Emacs is free software; you can redistribute it and/or modify
f3a0bf5c 8it under the terms of the GNU General Public License as published by
684d6f5b 9the Free Software Foundation; either version 3, or (at your option)
f3a0bf5c
JB
10any later version.
11
3b7ad313 12GNU Emacs is distributed in the hope that it will be useful,
f3a0bf5c
JB
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
3b7ad313 18along with GNU Emacs; see the file COPYING. If not, write to
4fc5845f
LK
19the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20Boston, MA 02110-1301, USA. */
f3a0bf5c
JB
21
22/* Written by jla, 4/90 */
23
a2a4d43e 24#ifdef emacs
18160b98 25#include <config.h>
a2a4d43e
JB
26#endif
27
dfcf069d
AS
28#ifdef HAVE_UNISTD_H
29#include <unistd.h>
30#endif
31
57bda87a 32#include <epaths.h>
012c3e71 33
837255fb
JB
34#include <stdio.h>
35
a2a4d43e 36#if 1 /* I'd really appreciate it if this code could go away... -JimB */
cca1b1d7
GM
37/* This avoids lossage in the `dual-universe' headers on AT&T SysV
38 X11. Don't do it on Solaris, because it breaks compilation with
39 XFree86 4.0.3 (and probably many other X11R6 releases) on Solaris
40 2 */
41#if defined(USG5) && !defined(SOLARIS2)
8f510a71 42#ifndef SYSV
a2a4d43e 43#define SYSV
8f510a71 44#endif
cca1b1d7 45#endif /* USG5 && !SOLARIS2 */
a2a4d43e
JB
46
47#endif /* 1 */
54c908b5 48
f3a0bf5c
JB
49#include <X11/Xlib.h>
50#include <X11/Xatom.h>
dfc35f5f 51#if 0
f3a0bf5c 52#include <X11/Xos.h>
dfc35f5f 53#endif
f3a0bf5c
JB
54#include <X11/X.h>
55#include <X11/Xutil.h>
56#include <X11/Xresource.h>
5b9c0a1d 57#ifdef HAVE_PWD_H
f3a0bf5c 58#include <pwd.h>
531ff254 59#endif
f3a0bf5c
JB
60#include <sys/stat.h>
61
0f2cd61f
RS
62#if !defined(S_ISDIR) && defined(S_IFDIR)
63#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
64#endif
65
4da4f201
GM
66#include "lisp.h"
67
f3a0bf5c 68extern char *getenv ();
3d5d61ae
JB
69
70/* This does cause trouble on AIX. I'm going to take the comment at
71 face value. */
72#if 0
dfc35f5f
JB
73extern short getuid (); /* If this causes portability problems,
74 I think we should just delete it; it'll
75 default to `int' anyway. */
3d5d61ae
JB
76#endif
77
2d487ae5 78#ifdef DECLARE_GETPWUID_WITH_UID_T
3e0be4d0
RS
79extern struct passwd *getpwuid (uid_t);
80extern struct passwd *getpwnam (const char *);
81#else
f3a0bf5c
JB
82extern struct passwd *getpwuid ();
83extern struct passwd *getpwnam ();
3e0be4d0 84#endif
f3a0bf5c 85
e29ad342
KH
86extern char *get_system_name ();
87
837255fb
JB
88/* Make sure not to #include anything after these definitions. Let's
89 not step on anyone's prototypes. */
90#ifdef emacs
0cf36656
KR
91/* darwin.h may have already defined these. */
92#undef malloc
93#undef realloc
94#undef free
837255fb
JB
95#define malloc xmalloc
96#define realloc xrealloc
97#define free xfree
98#endif
99
100char *x_get_string_resource ();
101static int file_p ();
102
103\f
104/* X file search path processing. */
105
106
107/* The string which gets substituted for the %C escape in XFILESEARCHPATH
108 and friends, or zero if none was specified. */
109char *x_customization_string;
110
111
112/* Return the value of the emacs.customization (Emacs.Customization)
113 resource, for later use in search path decoding. If we find no
114 such resource, return zero. */
115char *
116x_get_customization_string (db, name, class)
117 XrmDatabase db;
118 char *name, *class;
119{
120 char *full_name
121 = (char *) alloca (strlen (name) + sizeof ("customization") + 3);
122 char *full_class
123 = (char *) alloca (strlen (class) + sizeof ("Customization") + 3);
124 char *result;
125
126 sprintf (full_name, "%s.%s", name, "customization");
127 sprintf (full_class, "%s.%s", class, "Customization");
128
129 result = x_get_string_resource (db, full_name, full_class);
130
131 if (result)
abfc2e5f
RS
132 {
133 char *copy = (char *) malloc (strlen (result) + 1);
134 strcpy (copy, result);
135 return copy;
136 }
837255fb
JB
137 else
138 return 0;
139}
140
141
142/* Expand all the Xt-style %-escapes in STRING, whose length is given
143 by STRING_LEN. Here are the escapes we're supposed to recognize:
144
145 %N The value of the application's class name
146 %T The value of the type parameter ("app-defaults" in this
147 context)
148 %S The value of the suffix parameter ("" in this context)
149 %L The language string associated with the specified display
150 (We use the "LANG" environment variable here, if it's set.)
151 %l The language part of the display's language string
152 (We treat this just like %L. If someone can tell us what
153 we're really supposed to do, dandy.)
154 %t The territory part of the display's language string
155 (This never gets used.)
156 %c The codeset part of the display's language string
157 (This never gets used either.)
158 %C The customization string retrieved from the resource
159 database associated with display.
160 (This is x_customization_string.)
161
162 Return the expanded file name if it exists and is readable, and
163 refers to %L only when the LANG environment variable is set, or
164 otherwise provided by X.
165
166 ESCAPED_SUFFIX and SUFFIX are postpended to STRING if they are
167 non-zero. %-escapes in ESCAPED_SUFFIX are expanded; STRING is left
168 alone.
169
170 Return NULL otherwise. */
171
172static char *
173magic_file_p (string, string_len, class, escaped_suffix, suffix)
174 char *string;
175 int string_len;
176 char *class, *escaped_suffix, *suffix;
177{
178 char *lang = getenv ("LANG");
179
180 int path_size = 100;
181 char *path = (char *) malloc (path_size);
182 int path_len = 0;
183
184 char *p = string;
185
186 while (p < string + string_len)
187 {
188 /* The chunk we're about to stick on the end of result. */
6bbd7a29 189 char *next = NULL;
837255fb
JB
190 int next_len;
191
192 if (*p == '%')
193 {
194 p++;
195
196 if (p >= string + string_len)
197 next_len = 0;
198 else
199 switch (*p)
200 {
201 case '%':
202 next = "%";
203 next_len = 1;
204 break;
205
206 case 'C':
207 next = (x_customization_string
208 ? x_customization_string
209 : "");
210 next_len = strlen (next);
211 break;
212
213 case 'N':
214 next = class;
215 next_len = strlen (class);
216 break;
217
218 case 'T':
219 next = "app-defaults";
220 next_len = strlen (next);
221 break;
222
223 default:
224 case 'S':
225 next_len = 0;
226 break;
227
228 case 'L':
229 case 'l':
230 if (! lang)
231 {
232 free (path);
233 return NULL;
234 }
427ec082 235
837255fb
JB
236 next = lang;
237 next_len = strlen (next);
238 break;
427ec082 239
837255fb
JB
240 case 't':
241 case 'c':
242 free (path);
243 return NULL;
244 }
245 }
246 else
247 next = p, next_len = 1;
248
249 /* Do we have room for this component followed by a '\0' ? */
250 if (path_len + next_len + 1 > path_size)
251 {
252 path_size = (path_len + next_len + 1) * 2;
253 path = (char *) realloc (path, path_size);
254 }
427ec082 255
837255fb
JB
256 bcopy (next, path + path_len, next_len);
257 path_len += next_len;
258
259 p++;
260
261 /* If we've reached the end of the string, append ESCAPED_SUFFIX. */
262 if (p >= string + string_len && escaped_suffix)
263 {
264 string = escaped_suffix;
265 string_len = strlen (string);
266 p = string;
267 escaped_suffix = NULL;
268 }
269 }
270
271 /* Perhaps we should add the SUFFIX now. */
272 if (suffix)
273 {
274 int suffix_len = strlen (suffix);
275
276 if (path_len + suffix_len + 1 > path_size)
277 {
278 path_size = (path_len + suffix_len + 1);
279 path = (char *) realloc (path, path_size);
280 }
281
282 bcopy (suffix, path + path_len, suffix_len);
283 path_len += suffix_len;
284 }
285
286 path[path_len] = '\0';
287
288 if (! file_p (path))
289 {
290 free (path);
291 return NULL;
292 }
293
294 return path;
295}
296
297
f3a0bf5c 298static char *
837255fb 299gethomedir ()
f3a0bf5c 300{
f3a0bf5c
JB
301 struct passwd *pw;
302 char *ptr;
837255fb 303 char *copy;
f3a0bf5c
JB
304
305 if ((ptr = getenv ("HOME")) == NULL)
306 {
1cac1f6f
KH
307 if ((ptr = getenv ("LOGNAME")) != NULL
308 || (ptr = getenv ("USER")) != NULL)
f3a0bf5c
JB
309 pw = getpwnam (ptr);
310 else
1cac1f6f 311 pw = getpwuid (getuid ());
837255fb 312
f3a0bf5c
JB
313 if (pw)
314 ptr = pw->pw_dir;
f3a0bf5c
JB
315 }
316
427ec082 317 if (ptr == NULL)
8fd0f424 318 return xstrdup ("/");
f3a0bf5c 319
837255fb
JB
320 copy = (char *) malloc (strlen (ptr) + 2);
321 strcpy (copy, ptr);
322 strcat (copy, "/");
f3a0bf5c 323
837255fb 324 return copy;
f3a0bf5c
JB
325}
326
837255fb 327
f3a0bf5c 328static int
aa7e4660
RS
329file_p (filename)
330 char *filename;
f3a0bf5c
JB
331{
332 struct stat status;
333
aa7e4660
RS
334 return (access (filename, 4) == 0 /* exists and is readable */
335 && stat (filename, &status) == 0 /* get the status */
0f2cd61f 336 && (S_ISDIR (status.st_mode)) == 0); /* not a directory */
f3a0bf5c
JB
337}
338
f3a0bf5c 339
837255fb 340/* Find the first element of SEARCH_PATH which exists and is readable,
427ec082 341 after expanding the %-escapes. Return 0 if we didn't find any, and
837255fb 342 the path name of the one we found otherwise. */
f3a0bf5c 343
837255fb
JB
344static char *
345search_magic_path (search_path, class, escaped_suffix, suffix)
346 char *search_path, *class, *escaped_suffix, *suffix;
f3a0bf5c 347{
837255fb 348 register char *s, *p;
d4327fec 349
837255fb 350 for (s = search_path; *s; s = p)
f3a0bf5c 351 {
837255fb
JB
352 for (p = s; *p && *p != ':'; p++)
353 ;
427ec082 354
0f2cd61f 355 if (p > s)
f3a0bf5c 356 {
0f2cd61f 357 char *path = magic_file_p (s, p - s, class, escaped_suffix, suffix);
837255fb
JB
358 if (path)
359 return path;
f3a0bf5c 360 }
0f2cd61f 361 else if (*p == ':')
f3a0bf5c 362 {
0f2cd61f
RS
363 char *path;
364
365 s = "%N%S";
366 path = magic_file_p (s, strlen (s), class, escaped_suffix, suffix);
837255fb
JB
367 if (path)
368 return path;
f3a0bf5c
JB
369 }
370
837255fb
JB
371 if (*p == ':')
372 p++;
f3a0bf5c
JB
373 }
374
375 return 0;
376}
377\f
837255fb
JB
378/* Producing databases for individual sources. */
379
f3a0bf5c
JB
380static XrmDatabase
381get_system_app (class)
382 char *class;
383{
837255fb
JB
384 XrmDatabase db = NULL;
385 char *path;
f3a0bf5c 386
837255fb 387 path = getenv ("XFILESEARCHPATH");
58c7da0c 388 if (! path) path = PATH_X_DEFAULTS;
f3a0bf5c 389
837255fb
JB
390 path = search_magic_path (path, class, 0, 0);
391 if (path)
392 {
393 db = XrmGetFileDatabase (path);
394 free (path);
395 }
f3a0bf5c 396
f3a0bf5c
JB
397 return db;
398}
399
837255fb 400
f3a0bf5c
JB
401static XrmDatabase
402get_fallback (display)
403 Display *display;
404{
f3a0bf5c
JB
405 return NULL;
406}
407
837255fb 408
f3a0bf5c
JB
409static XrmDatabase
410get_user_app (class)
411 char *class;
412{
837255fb
JB
413 char *path;
414 char *file = 0;
3fa18fb2 415 char *free_it = 0;
837255fb
JB
416
417 /* Check for XUSERFILESEARCHPATH. It is a path of complete file
418 names, not directories. */
419 if (((path = getenv ("XUSERFILESEARCHPATH"))
420 && (file = search_magic_path (path, class, 0, 0)))
421
422 /* Check for APPLRESDIR; it is a path of directories. In each,
423 we have to search for LANG/CLASS and then CLASS. */
424 || ((path = getenv ("XAPPLRESDIR"))
425 && ((file = search_magic_path (path, class, "/%L/%N", 0))
426 || (file = search_magic_path (path, class, "/%N", 0))))
427ec082 427
837255fb
JB
428 /* Check in the home directory. This is a bit of a hack; let's
429 hope one's home directory doesn't contain any %-escapes. */
3fa18fb2
RS
430 || (free_it = gethomedir (),
431 ((file = search_magic_path (free_it, class, "%L/%N", 0))
432 || (file = search_magic_path (free_it, class, "%N", 0)))))
f3a0bf5c 433 {
837255fb
JB
434 XrmDatabase db = XrmGetFileDatabase (file);
435 free (file);
3fa18fb2
RS
436 if (free_it)
437 free (free_it);
837255fb 438 return db;
f3a0bf5c 439 }
3fa18fb2
RS
440
441 if (free_it)
442 free (free_it);
443 return NULL;
f3a0bf5c
JB
444}
445
837255fb 446
f3a0bf5c
JB
447static XrmDatabase
448get_user_db (display)
449 Display *display;
450{
451 XrmDatabase db;
452 char *xdefs;
453
2c8d1900 454#ifdef PBaseSize /* Cheap way to test for X11R4 or later. */
b631f177
JB
455 xdefs = XResourceManagerString (display);
456#else
a2a4d43e 457 xdefs = display->xdefaults;
b631f177
JB
458#endif
459
f3a0bf5c
JB
460 if (xdefs != NULL)
461 db = XrmGetStringDatabase (xdefs);
462 else
463 {
837255fb
JB
464 char *home;
465 char *xdefault;
f3a0bf5c 466
837255fb
JB
467 home = gethomedir ();
468 xdefault = (char *) malloc (strlen (home) + sizeof (".Xdefaults"));
469 strcpy (xdefault, home);
f3a0bf5c
JB
470 strcat (xdefault, ".Xdefaults");
471 db = XrmGetFileDatabase (xdefault);
837255fb
JB
472 free (home);
473 free (xdefault);
f3a0bf5c
JB
474 }
475
d8717d15 476#ifdef HAVE_XSCREENRESOURCESTRING
9b37b1c2
JB
477 /* Get the screen-specific resources too. */
478 xdefs = XScreenResourceString (DefaultScreenOfDisplay (display));
479 if (xdefs != NULL)
fdce0b39
JB
480 {
481 XrmMergeDatabases (XrmGetStringDatabase (xdefs), &db);
482 XFree (xdefs);
483 }
9b37b1c2
JB
484#endif
485
f3a0bf5c
JB
486 return db;
487}
488
489static XrmDatabase
490get_environ_db ()
491{
492 XrmDatabase db;
493 char *p;
e29ad342 494 char *path = 0, *home = 0, *host;
f3a0bf5c
JB
495
496 if ((p = getenv ("XENVIRONMENT")) == NULL)
497 {
837255fb 498 home = gethomedir ();
e29ad342 499 host = get_system_name ();
837255fb
JB
500 path = (char *) malloc (strlen (home)
501 + sizeof (".Xdefaults-")
502 + strlen (host));
503 sprintf (path, "%s%s%s", home, ".Xdefaults-", host);
f3a0bf5c
JB
504 p = path;
505 }
506
507 db = XrmGetFileDatabase (p);
837255fb
JB
508
509 if (path) free (path);
510 if (home) free (home);
837255fb 511
f3a0bf5c
JB
512 return db;
513}
514\f
837255fb
JB
515/* External interface. */
516
f3a0bf5c
JB
517/* Types of values that we can find in a database */
518
519#define XrmStringType "String" /* String representation */
520XrmRepresentation x_rm_string; /* Quark representation */
521
522/* Load X resources based on the display and a possible -xrm option. */
523
524XrmDatabase
837255fb 525x_load_resources (display, xrm_string, myname, myclass)
f3a0bf5c 526 Display *display;
837255fb 527 char *xrm_string, *myname, *myclass;
f3a0bf5c 528{
837255fb 529 XrmDatabase user_database;
f3a0bf5c
JB
530 XrmDatabase rdb;
531 XrmDatabase db;
4da4f201 532 char line[256];
6ca30ba4 533
4da4f201 534 char *helv = "-*-helvetica-medium-r-*--*-120-*-*-*-*-iso8859-1";
6ca30ba4 535
8d56e206 536#ifdef USE_MOTIF
4da4f201
GM
537 char *courier = "-*-courier-medium-r-*-*-*-120-*-*-*-*-iso8859-1";
538 extern Lisp_Object Vdouble_click_time;
8d56e206 539#endif
f3a0bf5c
JB
540
541 x_rm_string = XrmStringToQuark (XrmStringType);
082dc211
RS
542#ifndef USE_X_TOOLKIT
543 /* pmr@osf.org says this shouldn't be done if USE_X_TOOLKIT.
544 I suspect it's because the toolkit version does this elsewhere. */
f3a0bf5c 545 XrmInitialize ();
082dc211 546#endif
f3a0bf5c
JB
547 rdb = XrmGetStringDatabase ("");
548
4da4f201
GM
549 /* Add some font defaults. If the font `helv' doesn't exist, widgets
550 will use some other default font. */
551#ifdef USE_MOTIF
427ec082 552
cf9b4b0b 553 sprintf (line, "%s.pane.background: grey75", myclass);
06bbf618 554 XrmPutLineResource (&rdb, line);
cf9b4b0b 555 sprintf (line, "%s*fontList: %s", myclass, helv);
4da4f201 556 XrmPutLineResource (&rdb, line);
cf9b4b0b 557 sprintf (line, "%s*menu*background: grey75", myclass);
4da4f201 558 XrmPutLineResource (&rdb, line);
b6a15240 559 sprintf (line, "%s*menubar*background: grey75", myclass);
4da4f201 560 XrmPutLineResource (&rdb, line);
cf9b4b0b 561 sprintf (line, "%s*verticalScrollBar.background: grey75", myclass);
4da4f201 562 XrmPutLineResource (&rdb, line);
cf9b4b0b 563 sprintf (line, "%s*verticalScrollBar.troughColor: grey75", myclass);
06bbf618 564 XrmPutLineResource (&rdb, line);
cf9b4b0b 565 sprintf (line, "%s.dialog*.background: grey75", myclass);
4da4f201 566 XrmPutLineResource (&rdb, line);
cf9b4b0b 567 sprintf (line, "%s*fsb.Text.background: white", myclass);
4da4f201 568 XrmPutLineResource (&rdb, line);
cf9b4b0b 569 sprintf (line, "%s*fsb.FilterText.background: white", myclass);
4da4f201 570 XrmPutLineResource (&rdb, line);
cf9b4b0b 571 sprintf (line, "%s*fsb*DirList.background: white", myclass);
4da4f201 572 XrmPutLineResource (&rdb, line);
cf9b4b0b 573 sprintf (line, "%s*fsb*ItemsList.background: white", myclass);
4da4f201 574 XrmPutLineResource (&rdb, line);
cf9b4b0b 575 sprintf (line, "%s*fsb*background: grey75", myclass);
4da4f201 576 XrmPutLineResource (&rdb, line);
cf9b4b0b 577 sprintf (line, "%s*fsb.Text.fontList: %s", myclass, courier);
4da4f201 578 XrmPutLineResource (&rdb, line);
cf9b4b0b 579 sprintf (line, "%s*fsb.FilterText.fontList: %s", myclass, courier);
4da4f201 580 XrmPutLineResource (&rdb, line);
cf9b4b0b 581 sprintf (line, "%s*fsb*ItemsList.fontList: %s", myclass, courier);
4da4f201 582 XrmPutLineResource (&rdb, line);
cf9b4b0b 583 sprintf (line, "%s*fsb*DirList.fontList: %s", myclass, courier);
4da4f201
GM
584 XrmPutLineResource (&rdb, line);
585
586 /* Set double click time of list boxes in the file selection
587 dialog from `double-click-time'. */
588 if (INTEGERP (Vdouble_click_time) && XINT (Vdouble_click_time) > 0)
589 {
590 sprintf (line, "%s*fsb*DirList.doubleClickInterval: %d",
cf9b4b0b 591 myclass, XFASTINT (Vdouble_click_time));
4da4f201
GM
592 XrmPutLineResource (&rdb, line);
593 sprintf (line, "%s*fsb*ItemsList.doubleClickInterval: %d",
cf9b4b0b 594 myclass, XFASTINT (Vdouble_click_time));
4da4f201
GM
595 XrmPutLineResource (&rdb, line);
596 }
597
598#else /* not USE_MOTIF */
427ec082 599
fc6c5dfe 600 sprintf (line, "Emacs.dialog*.font: %s", helv);
4da4f201 601 XrmPutLineResource (&rdb, line);
fc6c5dfe 602 sprintf (line, "Emacs.dialog*.background: grey75");
4da4f201 603 XrmPutLineResource (&rdb, line);
fc6c5dfe 604 sprintf (line, "*XlwMenu*font: %s", helv);
4da4f201 605 XrmPutLineResource (&rdb, line);
fc6c5dfe 606 sprintf (line, "*XlwMenu*background: grey75");
4da4f201 607 XrmPutLineResource (&rdb, line);
fc6c5dfe 608 sprintf (line, "Emacs*verticalScrollBar.background: grey75");
4da4f201 609 XrmPutLineResource (&rdb, line);
427ec082 610
4da4f201
GM
611#endif /* not USE_MOTIF */
612
a8986f4c
KH
613#ifdef HAVE_X_I18N
614 {
615#ifdef USE_MOTIF
616 Bool motif = True;
617#else /* not USE_MOTIF */
618 Bool motif = False;
619#endif /* not USE_MOTIF */
620 /* Setup the default fontSet resource. */
621 extern char *xic_create_fontsetname P_ ((char *base_fontname, Bool motif));
622 char *fontsetname = xic_create_fontsetname (helv, motif);
623 int len = strlen (fontsetname);
624 char *buf = line;
625
626 /* fontsetname may be very long. */
627 if (len + 16 > 256)
628 buf = alloca (len + 16);
629 sprintf (buf, "Emacs*fontSet: %s", fontsetname);
630 XrmPutLineResource (&rdb, buf);
631 if (fontsetname != helv)
632 xfree (fontsetname);
633 }
634#endif /* HAVE_X_I18N */
635
837255fb
JB
636 user_database = get_user_db (display);
637
638 /* Figure out what the "customization string" is, so we can use it
639 to decode paths. */
640 if (x_customization_string)
641 free (x_customization_string);
642 x_customization_string
643 = x_get_customization_string (user_database, myname, myclass);
644
f3a0bf5c
JB
645 /* Get application system defaults */
646 db = get_system_app (myclass);
647 if (db != NULL)
648 XrmMergeDatabases (db, &rdb);
649
650 /* Get Fallback resources */
651 db = get_fallback (display);
652 if (db != NULL)
653 XrmMergeDatabases (db, &rdb);
654
655 /* Get application user defaults */
656 db = get_user_app (myclass);
657 if (db != NULL)
658 XrmMergeDatabases (db, &rdb);
659
660 /* get User defaults */
837255fb
JB
661 if (user_database != NULL)
662 XrmMergeDatabases (user_database, &rdb);
f3a0bf5c
JB
663
664 /* Get Environment defaults. */
665 db = get_environ_db ();
666 if (db != NULL)
667 XrmMergeDatabases (db, &rdb);
427ec082 668
f3a0bf5c
JB
669 /* Last, merge in any specification from the command line. */
670 if (xrm_string != NULL)
671 {
672 db = XrmGetStringDatabase (xrm_string);
673 if (db != NULL)
674 XrmMergeDatabases (db, &rdb);
675 }
676
677 return rdb;
678}
679
837255fb 680
f3a0bf5c
JB
681/* Retrieve the value of the resource specified by NAME with class CLASS
682 and of type TYPE from database RDB. The value is returned in RET_VALUE. */
683
684int
685x_get_resource (rdb, name, class, expected_type, ret_value)
686 XrmDatabase rdb;
687 char *name, *class;
688 XrmRepresentation expected_type;
689 XrmValue *ret_value;
690{
691 XrmValue value;
692 XrmName namelist[100];
693 XrmClass classlist[100];
694 XrmRepresentation type;
695
696 XrmStringToNameList(name, namelist);
697 XrmStringToClassList(class, classlist);
698
699 if (XrmQGetResource (rdb, namelist, classlist, &type, &value) == True
700 && (type == expected_type))
701 {
702 if (type == x_rm_string)
41ab0754 703 ret_value->addr = (char *) value.addr;
f3a0bf5c
JB
704 else
705 bcopy (value.addr, ret_value->addr, ret_value->size);
706
707 return value.size;
708 }
709
710 return 0;
711}
712
713/* Retrieve the string resource specified by NAME with CLASS from
714 database RDB. */
715
716char *
717x_get_string_resource (rdb, name, class)
718 XrmDatabase rdb;
719 char *name, *class;
720{
721 XrmValue value;
722
723 if (x_get_resource (rdb, name, class, x_rm_string, &value))
724 return (char *) value.addr;
725
726 return (char *) 0;
727}
728\f
837255fb
JB
729/* Stand-alone test facilities. */
730
f3a0bf5c 731#ifdef TESTRM
837255fb
JB
732
733typedef char **List;
734#define arg_listify(len, list) (list)
735#define car(list) (*(list))
736#define cdr(list) (list + 1)
737#define NIL(list) (! *(list))
738#define free_arglist(list)
739
740static List
741member (elt, list)
742 char *elt;
743 List list;
744{
745 List p;
746
747 for (p = list; ! NIL (p); p = cdr (p))
748 if (! strcmp (elt, car (p)))
749 return p;
750
751 return p;
752}
f3a0bf5c
JB
753
754static void
755fatal (msg, prog, x1, x2, x3, x4, x5)
756 char *msg, *prog;
757 int x1, x2, x3, x4, x5;
758{
759 extern int errno;
760
761 if (errno)
762 perror (prog);
763
764 (void) fprintf (stderr, msg, prog, x1, x2, x3, x4, x5);
765 exit (1);
766}
767
768main (argc, argv)
769 int argc;
770 char **argv;
771{
772 Display *display;
837255fb 773 char *displayname, *resource_string, *class, *name;
f3a0bf5c 774 XrmDatabase xdb;
837255fb 775 List arg_list, lp;
f3a0bf5c
JB
776
777 arg_list = arg_listify (argc, argv);
778
779 lp = member ("-d", arg_list);
780 if (!NIL (lp))
781 displayname = car (cdr (lp));
782 else
783 displayname = "localhost:0.0";
784
785 lp = member ("-xrm", arg_list);
786 if (! NIL (lp))
787 resource_string = car (cdr (lp));
788 else
789 resource_string = (char *) 0;
790
791 lp = member ("-c", arg_list);
792 if (! NIL (lp))
793 class = car (cdr (lp));
794 else
795 class = "Emacs";
796
837255fb
JB
797 lp = member ("-n", arg_list);
798 if (! NIL (lp))
799 name = car (cdr (lp));
800 else
801 name = "emacs";
f3a0bf5c 802
837255fb 803 free_arglist (arg_list);
f3a0bf5c
JB
804
805 if (!(display = XOpenDisplay (displayname)))
806 fatal ("Can't open display '%s'\n", XDisplayName (displayname));
807
837255fb 808 xdb = x_load_resources (display, resource_string, name, class);
f3a0bf5c 809
f3a0bf5c
JB
810 /* In a real program, you'd want to also do this: */
811 display->db = xdb;
f3a0bf5c
JB
812
813 while (1)
814 {
837255fb
JB
815 char query_name[90];
816 char query_class[90];
817
818 printf ("Name: ");
819 gets (query_name);
f3a0bf5c 820
837255fb 821 if (strlen (query_name))
f3a0bf5c 822 {
837255fb
JB
823 char *value;
824
825 printf ("Class: ");
826 gets (query_class);
827
828 value = x_get_string_resource (xdb, query_name, query_class);
f3a0bf5c
JB
829
830 if (value != NULL)
837255fb 831 printf ("\t%s(%s): %s\n\n", query_name, query_class, value);
f3a0bf5c
JB
832 else
833 printf ("\tNo Value.\n\n");
834 }
835 else
836 break;
837 }
838 printf ("\tExit.\n\n");
839
840 XCloseDisplay (display);
841}
842#endif /* TESTRM */
ab5796a9
MB
843
844/* arch-tag: 37e6fbab-ed05-4363-9e76-6c4109ed511f
845 (do not change this comment) */