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