(Fexpand_abbrev): Increment plist as use count only if it is an integer.
[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
EN
17along with GNU Emacs; see the file COPYING. If not, write to
18the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19Boston, MA 02111-1307, 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>
531ff254
JB
56#ifdef VMS
57#include "vms-pwd.h"
58#else
f3a0bf5c 59#include <pwd.h>
531ff254 60#endif
f3a0bf5c
JB
61#include <sys/stat.h>
62
0f2cd61f
RS
63#if !defined(S_ISDIR) && defined(S_IFDIR)
64#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
65#endif
66
4da4f201
GM
67#include "lisp.h"
68
f3a0bf5c 69extern char *getenv ();
3d5d61ae
JB
70
71/* This does cause trouble on AIX. I'm going to take the comment at
72 face value. */
73#if 0
dfc35f5f
JB
74extern short getuid (); /* If this causes portability problems,
75 I think we should just delete it; it'll
76 default to `int' anyway. */
3d5d61ae
JB
77#endif
78
2d487ae5 79#ifdef DECLARE_GETPWUID_WITH_UID_T
3e0be4d0
RS
80extern struct passwd *getpwuid (uid_t);
81extern struct passwd *getpwnam (const char *);
82#else
f3a0bf5c
JB
83extern struct passwd *getpwuid ();
84extern struct passwd *getpwnam ();
3e0be4d0 85#endif
f3a0bf5c 86
e29ad342
KH
87extern char *get_system_name ();
88
837255fb
JB
89/* Make sure not to #include anything after these definitions. Let's
90 not step on anyone's prototypes. */
91#ifdef emacs
92#define malloc xmalloc
93#define realloc xrealloc
94#define free xfree
95#endif
96
97char *x_get_string_resource ();
98static int file_p ();
99
100\f
101/* X file search path processing. */
102
103
104/* The string which gets substituted for the %C escape in XFILESEARCHPATH
105 and friends, or zero if none was specified. */
106char *x_customization_string;
107
108
109/* Return the value of the emacs.customization (Emacs.Customization)
110 resource, for later use in search path decoding. If we find no
111 such resource, return zero. */
112char *
113x_get_customization_string (db, name, class)
114 XrmDatabase db;
115 char *name, *class;
116{
117 char *full_name
118 = (char *) alloca (strlen (name) + sizeof ("customization") + 3);
119 char *full_class
120 = (char *) alloca (strlen (class) + sizeof ("Customization") + 3);
121 char *result;
122
123 sprintf (full_name, "%s.%s", name, "customization");
124 sprintf (full_class, "%s.%s", class, "Customization");
125
126 result = x_get_string_resource (db, full_name, full_class);
127
128 if (result)
abfc2e5f
RS
129 {
130 char *copy = (char *) malloc (strlen (result) + 1);
131 strcpy (copy, result);
132 return copy;
133 }
837255fb
JB
134 else
135 return 0;
136}
137
138
139/* Expand all the Xt-style %-escapes in STRING, whose length is given
140 by STRING_LEN. Here are the escapes we're supposed to recognize:
141
142 %N The value of the application's class name
143 %T The value of the type parameter ("app-defaults" in this
144 context)
145 %S The value of the suffix parameter ("" in this context)
146 %L The language string associated with the specified display
147 (We use the "LANG" environment variable here, if it's set.)
148 %l The language part of the display's language string
149 (We treat this just like %L. If someone can tell us what
150 we're really supposed to do, dandy.)
151 %t The territory part of the display's language string
152 (This never gets used.)
153 %c The codeset part of the display's language string
154 (This never gets used either.)
155 %C The customization string retrieved from the resource
156 database associated with display.
157 (This is x_customization_string.)
158
159 Return the expanded file name if it exists and is readable, and
160 refers to %L only when the LANG environment variable is set, or
161 otherwise provided by X.
162
163 ESCAPED_SUFFIX and SUFFIX are postpended to STRING if they are
164 non-zero. %-escapes in ESCAPED_SUFFIX are expanded; STRING is left
165 alone.
166
167 Return NULL otherwise. */
168
169static char *
170magic_file_p (string, string_len, class, escaped_suffix, suffix)
171 char *string;
172 int string_len;
173 char *class, *escaped_suffix, *suffix;
174{
175 char *lang = getenv ("LANG");
176
177 int path_size = 100;
178 char *path = (char *) malloc (path_size);
179 int path_len = 0;
180
181 char *p = string;
182
183 while (p < string + string_len)
184 {
185 /* The chunk we're about to stick on the end of result. */
6bbd7a29 186 char *next = NULL;
837255fb
JB
187 int next_len;
188
189 if (*p == '%')
190 {
191 p++;
192
193 if (p >= string + string_len)
194 next_len = 0;
195 else
196 switch (*p)
197 {
198 case '%':
199 next = "%";
200 next_len = 1;
201 break;
202
203 case 'C':
204 next = (x_customization_string
205 ? x_customization_string
206 : "");
207 next_len = strlen (next);
208 break;
209
210 case 'N':
211 next = class;
212 next_len = strlen (class);
213 break;
214
215 case 'T':
216 next = "app-defaults";
217 next_len = strlen (next);
218 break;
219
220 default:
221 case 'S':
222 next_len = 0;
223 break;
224
225 case 'L':
226 case 'l':
227 if (! lang)
228 {
229 free (path);
230 return NULL;
231 }
427ec082 232
837255fb
JB
233 next = lang;
234 next_len = strlen (next);
235 break;
427ec082 236
837255fb
JB
237 case 't':
238 case 'c':
239 free (path);
240 return NULL;
241 }
242 }
243 else
244 next = p, next_len = 1;
245
246 /* Do we have room for this component followed by a '\0' ? */
247 if (path_len + next_len + 1 > path_size)
248 {
249 path_size = (path_len + next_len + 1) * 2;
250 path = (char *) realloc (path, path_size);
251 }
427ec082 252
837255fb
JB
253 bcopy (next, path + path_len, next_len);
254 path_len += next_len;
255
256 p++;
257
258 /* If we've reached the end of the string, append ESCAPED_SUFFIX. */
259 if (p >= string + string_len && escaped_suffix)
260 {
261 string = escaped_suffix;
262 string_len = strlen (string);
263 p = string;
264 escaped_suffix = NULL;
265 }
266 }
267
268 /* Perhaps we should add the SUFFIX now. */
269 if (suffix)
270 {
271 int suffix_len = strlen (suffix);
272
273 if (path_len + suffix_len + 1 > path_size)
274 {
275 path_size = (path_len + suffix_len + 1);
276 path = (char *) realloc (path, path_size);
277 }
278
279 bcopy (suffix, path + path_len, suffix_len);
280 path_len += suffix_len;
281 }
282
283 path[path_len] = '\0';
284
285 if (! file_p (path))
286 {
287 free (path);
288 return NULL;
289 }
290
291 return path;
292}
293
294
f3a0bf5c 295static char *
837255fb 296gethomedir ()
f3a0bf5c 297{
f3a0bf5c
JB
298 struct passwd *pw;
299 char *ptr;
837255fb 300 char *copy;
f3a0bf5c
JB
301
302 if ((ptr = getenv ("HOME")) == NULL)
303 {
1cac1f6f
KH
304 if ((ptr = getenv ("LOGNAME")) != NULL
305 || (ptr = getenv ("USER")) != NULL)
f3a0bf5c
JB
306 pw = getpwnam (ptr);
307 else
1cac1f6f 308 pw = getpwuid (getuid ());
837255fb 309
f3a0bf5c
JB
310 if (pw)
311 ptr = pw->pw_dir;
f3a0bf5c
JB
312 }
313
427ec082 314 if (ptr == NULL)
837255fb 315 return "/";
f3a0bf5c 316
837255fb
JB
317 copy = (char *) malloc (strlen (ptr) + 2);
318 strcpy (copy, ptr);
319 strcat (copy, "/");
f3a0bf5c 320
837255fb 321 return copy;
f3a0bf5c
JB
322}
323
837255fb 324
f3a0bf5c
JB
325static int
326file_p (path)
327 char *path;
328{
329 struct stat status;
330
dfc35f5f 331 return (access (path, 4) == 0 /* exists and is readable */
f3a0bf5c 332 && stat (path, &status) == 0 /* get the status */
0f2cd61f 333 && (S_ISDIR (status.st_mode)) == 0); /* not a directory */
f3a0bf5c
JB
334}
335
f3a0bf5c 336
837255fb 337/* Find the first element of SEARCH_PATH which exists and is readable,
427ec082 338 after expanding the %-escapes. Return 0 if we didn't find any, and
837255fb 339 the path name of the one we found otherwise. */
f3a0bf5c 340
837255fb
JB
341static char *
342search_magic_path (search_path, class, escaped_suffix, suffix)
343 char *search_path, *class, *escaped_suffix, *suffix;
f3a0bf5c 344{
837255fb 345 register char *s, *p;
d4327fec 346
837255fb 347 for (s = search_path; *s; s = p)
f3a0bf5c 348 {
837255fb
JB
349 for (p = s; *p && *p != ':'; p++)
350 ;
427ec082 351
0f2cd61f 352 if (p > s)
f3a0bf5c 353 {
0f2cd61f 354 char *path = magic_file_p (s, p - s, class, escaped_suffix, suffix);
837255fb
JB
355 if (path)
356 return path;
f3a0bf5c 357 }
0f2cd61f 358 else if (*p == ':')
f3a0bf5c 359 {
0f2cd61f
RS
360 char *path;
361
362 s = "%N%S";
363 path = magic_file_p (s, strlen (s), class, escaped_suffix, suffix);
837255fb
JB
364 if (path)
365 return path;
f3a0bf5c
JB
366 }
367
837255fb
JB
368 if (*p == ':')
369 p++;
f3a0bf5c
JB
370 }
371
372 return 0;
373}
374\f
837255fb
JB
375/* Producing databases for individual sources. */
376
f3a0bf5c
JB
377static XrmDatabase
378get_system_app (class)
379 char *class;
380{
837255fb
JB
381 XrmDatabase db = NULL;
382 char *path;
f3a0bf5c 383
837255fb 384 path = getenv ("XFILESEARCHPATH");
58c7da0c 385 if (! path) path = PATH_X_DEFAULTS;
f3a0bf5c 386
837255fb
JB
387 path = search_magic_path (path, class, 0, 0);
388 if (path)
389 {
390 db = XrmGetFileDatabase (path);
391 free (path);
392 }
f3a0bf5c 393
f3a0bf5c
JB
394 return db;
395}
396
837255fb 397
f3a0bf5c
JB
398static XrmDatabase
399get_fallback (display)
400 Display *display;
401{
f3a0bf5c
JB
402 return NULL;
403}
404
837255fb 405
f3a0bf5c
JB
406static XrmDatabase
407get_user_app (class)
408 char *class;
409{
837255fb
JB
410 char *path;
411 char *file = 0;
3fa18fb2 412 char *free_it = 0;
837255fb
JB
413
414 /* Check for XUSERFILESEARCHPATH. It is a path of complete file
415 names, not directories. */
416 if (((path = getenv ("XUSERFILESEARCHPATH"))
417 && (file = search_magic_path (path, class, 0, 0)))
418
419 /* Check for APPLRESDIR; it is a path of directories. In each,
420 we have to search for LANG/CLASS and then CLASS. */
421 || ((path = getenv ("XAPPLRESDIR"))
422 && ((file = search_magic_path (path, class, "/%L/%N", 0))
423 || (file = search_magic_path (path, class, "/%N", 0))))
427ec082 424
837255fb
JB
425 /* Check in the home directory. This is a bit of a hack; let's
426 hope one's home directory doesn't contain any %-escapes. */
3fa18fb2
RS
427 || (free_it = gethomedir (),
428 ((file = search_magic_path (free_it, class, "%L/%N", 0))
429 || (file = search_magic_path (free_it, class, "%N", 0)))))
f3a0bf5c 430 {
837255fb
JB
431 XrmDatabase db = XrmGetFileDatabase (file);
432 free (file);
3fa18fb2
RS
433 if (free_it)
434 free (free_it);
837255fb 435 return db;
f3a0bf5c 436 }
3fa18fb2
RS
437
438 if (free_it)
439 free (free_it);
440 return NULL;
f3a0bf5c
JB
441}
442
837255fb 443
f3a0bf5c
JB
444static XrmDatabase
445get_user_db (display)
446 Display *display;
447{
448 XrmDatabase db;
449 char *xdefs;
450
2c8d1900 451#ifdef PBaseSize /* Cheap way to test for X11R4 or later. */
b631f177
JB
452 xdefs = XResourceManagerString (display);
453#else
a2a4d43e 454 xdefs = display->xdefaults;
b631f177
JB
455#endif
456
f3a0bf5c
JB
457 if (xdefs != NULL)
458 db = XrmGetStringDatabase (xdefs);
459 else
460 {
837255fb
JB
461 char *home;
462 char *xdefault;
f3a0bf5c 463
837255fb
JB
464 home = gethomedir ();
465 xdefault = (char *) malloc (strlen (home) + sizeof (".Xdefaults"));
466 strcpy (xdefault, home);
f3a0bf5c
JB
467 strcat (xdefault, ".Xdefaults");
468 db = XrmGetFileDatabase (xdefault);
837255fb
JB
469 free (home);
470 free (xdefault);
f3a0bf5c
JB
471 }
472
d8717d15 473#ifdef HAVE_XSCREENRESOURCESTRING
9b37b1c2
JB
474 /* Get the screen-specific resources too. */
475 xdefs = XScreenResourceString (DefaultScreenOfDisplay (display));
476 if (xdefs != NULL)
fdce0b39
JB
477 {
478 XrmMergeDatabases (XrmGetStringDatabase (xdefs), &db);
479 XFree (xdefs);
480 }
9b37b1c2
JB
481#endif
482
f3a0bf5c
JB
483 return db;
484}
485
486static XrmDatabase
487get_environ_db ()
488{
489 XrmDatabase db;
490 char *p;
e29ad342 491 char *path = 0, *home = 0, *host;
f3a0bf5c
JB
492
493 if ((p = getenv ("XENVIRONMENT")) == NULL)
494 {
837255fb 495 home = gethomedir ();
e29ad342 496 host = get_system_name ();
837255fb
JB
497 path = (char *) malloc (strlen (home)
498 + sizeof (".Xdefaults-")
499 + strlen (host));
500 sprintf (path, "%s%s%s", home, ".Xdefaults-", host);
f3a0bf5c
JB
501 p = path;
502 }
503
504 db = XrmGetFileDatabase (p);
837255fb
JB
505
506 if (path) free (path);
507 if (home) free (home);
837255fb 508
f3a0bf5c
JB
509 return db;
510}
511\f
837255fb
JB
512/* External interface. */
513
f3a0bf5c
JB
514/* Types of values that we can find in a database */
515
516#define XrmStringType "String" /* String representation */
517XrmRepresentation x_rm_string; /* Quark representation */
518
519/* Load X resources based on the display and a possible -xrm option. */
520
521XrmDatabase
837255fb 522x_load_resources (display, xrm_string, myname, myclass)
f3a0bf5c 523 Display *display;
837255fb 524 char *xrm_string, *myname, *myclass;
f3a0bf5c 525{
837255fb 526 XrmDatabase user_database;
f3a0bf5c
JB
527 XrmDatabase rdb;
528 XrmDatabase db;
4da4f201
GM
529 char line[256];
530 char *helv = "-*-helvetica-medium-r-*--*-120-*-*-*-*-iso8859-1";
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 */