xrdb.c 17.1 KB
Newer Older
Jim Blandy's avatar
Jim Blandy committed
1
/* Deal with the X Resource Manager.
Paul Eggert's avatar
Paul Eggert committed
2
   Copyright (C) 1990, 1993-1994, 2000-2019 Free Software Foundation,
3
   Inc.
Jim Blandy's avatar
Jim Blandy committed
4

5 6 7
Author: Joseph Arceneaux
Created: 4/90

8 9
This file is part of GNU Emacs.

10
GNU Emacs is free software: you can redistribute it and/or modify
Jim Blandy's avatar
Jim Blandy committed
11
it under the terms of the GNU General Public License as published by
12 13
the Free Software Foundation, either version 3 of the License, or (at
your option) any later version.
Jim Blandy's avatar
Jim Blandy committed
14

15
GNU Emacs is distributed in the hope that it will be useful,
Jim Blandy's avatar
Jim Blandy committed
16 17 18 19 20
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
21
along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.  */
Jim Blandy's avatar
Jim Blandy committed
22

23
#include <config.h>
24

Andreas Schwab's avatar
Andreas Schwab committed
25
#include <unistd.h>
26
#include <errno.h>
27
#include <epaths.h>
28
#include <stdlib.h>
29 30
#include <stdio.h>

31 32 33 34 35 36
#include "lisp.h"

/* This may include sys/types.h, and that somehow loses
   if this is not done before the other system files.  */
#include "xterm.h"

Jim Blandy's avatar
Jim Blandy committed
37 38 39 40 41
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <X11/X.h>
#include <X11/Xutil.h>
#include <X11/Xresource.h>
42
#ifdef HAVE_PWD_H
Jim Blandy's avatar
Jim Blandy committed
43
#include <pwd.h>
Jim Blandy's avatar
Jim Blandy committed
44
#endif
Jim Blandy's avatar
Jim Blandy committed
45

46 47 48 49 50
/* X file search path processing.  */


/* The string which gets substituted for the %C escape in XFILESEARCHPATH
   and friends, or zero if none was specified.  */
51
static char *x_customization_string;
52 53 54 55 56


/* Return the value of the emacs.customization (Emacs.Customization)
   resource, for later use in search path decoding.  If we find no
   such resource, return zero.  */
Andreas Schwab's avatar
Andreas Schwab committed
57 58 59
static char *
x_get_customization_string (XrmDatabase db, const char *name,
			    const char *class)
60
{
61 62
  char *full_name = alloca (strlen (name) + sizeof "customization" + 3);
  char *full_class = alloca (strlen (class) + sizeof "Customization" + 3);
63 64 65 66 67 68
  char *result;

  sprintf (full_name,  "%s.%s", name,  "customization");
  sprintf (full_class, "%s.%s", class, "Customization");

  result = x_get_string_resource (db, full_name, full_class);
69
  return result ? xstrdup (result) : NULL;
70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
}

/* Expand all the Xt-style %-escapes in STRING, whose length is given
   by STRING_LEN.  Here are the escapes we're supposed to recognize:

	%N	The value of the application's class name
	%T	The value of the type parameter ("app-defaults" in this
		context)
	%S	The value of the suffix parameter ("" in this context)
	%L	The language string associated with the specified display
		(We use the "LANG" environment variable here, if it's set.)
	%l	The language part of the display's language string
		(We treat this just like %L.  If someone can tell us what
		 we're really supposed to do, dandy.)
	%t	The territory part of the display's language string
	        (This never gets used.)
	%c	The codeset part of the display's language string
	        (This never gets used either.)
	%C	The customization string retrieved from the resource
		database associated with display.
		(This is x_customization_string.)

92
   Return the resource database if its file was read successfully, and
93 94 95
   refers to %L only when the LANG environment variable is set, or
   otherwise provided by X.

96 97
   ESCAPED_SUFFIX is postpended to STRING if it is non-zero.
   %-escapes in ESCAPED_SUFFIX are expanded.
98 99 100

   Return NULL otherwise.  */

101 102 103
static XrmDatabase
magic_db (const char *string, ptrdiff_t string_len, const char *class,
	  const char *escaped_suffix)
104
{
105
  XrmDatabase db;
106 107
  char *lang = getenv ("LANG");

108
  ptrdiff_t path_size = 100;
Dmitry Antipov's avatar
Dmitry Antipov committed
109
  char *path = xmalloc (path_size);
110
  ptrdiff_t path_len = 0;
111

112
  const char *p = string;
113 114 115 116

  while (p < string + string_len)
    {
      /* The chunk we're about to stick on the end of result.  */
Paul Eggert's avatar
Paul Eggert committed
117 118
      const char *next = p;
      ptrdiff_t next_len = 1;
119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134

      if (*p == '%')
	{
	  p++;

	  if (p >= string + string_len)
	    next_len = 0;
	  else
	    switch (*p)
	      {
	      case '%':
		next = "%";
		next_len = 1;
		break;

	      case 'C':
Paul Eggert's avatar
Paul Eggert committed
135 136 137 138 139 140 141
		if (x_customization_string)
		  {
		    next = x_customization_string;
		    next_len = strlen (next);
		  }
		else
		  next_len = 0;
142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162
		break;

	      case 'N':
		next = class;
		next_len = strlen (class);
		break;

	      case 'T':
		next = "app-defaults";
		next_len = strlen (next);
		break;

	      default:
	      case 'S':
		next_len = 0;
		break;

	      case 'L':
	      case 'l':
		if (! lang)
		  {
Dan Nicolaescu's avatar
Dan Nicolaescu committed
163
		    xfree (path);
164 165
		    return NULL;
		  }
166

167 168 169
		next = lang;
		next_len = strlen (next);
		break;
170

171 172
	      case 't':
	      case 'c':
Dan Nicolaescu's avatar
Dan Nicolaescu committed
173
		xfree (path);
174 175 176 177
		return NULL;
	      }
	}

Paul Eggert's avatar
Paul Eggert committed
178
      /* Do we have room for this component followed by a '\0'?  */
179
      if (path_size - path_len <= next_len)
180 181
	path = xpalloc (path, &path_size, path_len - path_size + next_len + 1,
			-1, sizeof *path);
182

183
      memcpy (path + path_len, next, next_len);
184 185 186 187 188 189 190 191 192 193 194 195 196 197 198
      path_len += next_len;

      p++;

      /* If we've reached the end of the string, append ESCAPED_SUFFIX.  */
      if (p >= string + string_len && escaped_suffix)
	{
	  string = escaped_suffix;
	  string_len = strlen (string);
	  p = string;
	  escaped_suffix = NULL;
	}
    }

  path[path_len] = '\0';
199 200 201
  db = XrmGetFileDatabase (path);
  xfree (path);
  return db;
202 203 204
}


Jim Blandy's avatar
Jim Blandy committed
205
static char *
206
gethomedir (void)
Jim Blandy's avatar
Jim Blandy committed
207 208 209
{
  struct passwd *pw;
  char *ptr;
210
  char *copy;
Jim Blandy's avatar
Jim Blandy committed
211 212 213

  if ((ptr = getenv ("HOME")) == NULL)
    {
214 215
      if ((ptr = getenv ("LOGNAME")) != NULL
	  || (ptr = getenv ("USER")) != NULL)
Jim Blandy's avatar
Jim Blandy committed
216 217
	pw = getpwnam (ptr);
      else
218
	pw = getpwuid (getuid ());
219

Jim Blandy's avatar
Jim Blandy committed
220 221 222 223
      if (pw)
	ptr = pw->pw_dir;
    }

224
  if (ptr == NULL)
Romain Francoise's avatar
Romain Francoise committed
225
    return xstrdup ("/");
Jim Blandy's avatar
Jim Blandy committed
226

Paul Eggert's avatar
Paul Eggert committed
227 228 229 230
  ptrdiff_t len = strlen (ptr);
  copy = xmalloc (len + 2);
  strcpy (copy + len, "/");
  return memcpy (copy, ptr, len);
Jim Blandy's avatar
Jim Blandy committed
231 232
}

233 234

/* Find the first element of SEARCH_PATH which exists and is readable,
235
   after expanding the %-escapes.  Return 0 if we didn't find any, and
236
   the path name of the one we found otherwise.  */
Jim Blandy's avatar
Jim Blandy committed
237

238
static XrmDatabase
239 240
search_magic_path (const char *search_path, const char *class,
		   const char *escaped_suffix)
Jim Blandy's avatar
Jim Blandy committed
241
{
242
  const char *s, *p;
Jim Blandy's avatar
Jim Blandy committed
243

244
  for (s = search_path; *s; s = p)
Jim Blandy's avatar
Jim Blandy committed
245
    {
246 247
      for (p = s; *p && *p != ':'; p++)
	;
248

249
      if (p > s)
Jim Blandy's avatar
Jim Blandy committed
250
	{
251 252 253
	  XrmDatabase db = magic_db (s, p - s, class, escaped_suffix);
	  if (db)
	    return db;
Jim Blandy's avatar
Jim Blandy committed
254
	}
255
      else if (*p == ':')
Jim Blandy's avatar
Jim Blandy committed
256
	{
257 258 259 260
	  static char const ns[] = "%N%S";
	  XrmDatabase db = magic_db (ns, strlen (ns), class, escaped_suffix);
	  if (db)
	    return db;
Jim Blandy's avatar
Jim Blandy committed
261 262
	}

263 264
      if (*p == ':')
	p++;
Jim Blandy's avatar
Jim Blandy committed
265 266 267 268 269
    }

  return 0;
}

270 271
/* Producing databases for individual sources.  */

Jim Blandy's avatar
Jim Blandy committed
272
static XrmDatabase
273
get_system_app (const char *class)
Jim Blandy's avatar
Jim Blandy committed
274
{
275
  const char *path;
Jim Blandy's avatar
Jim Blandy committed
276

277
  path = getenv ("XFILESEARCHPATH");
278
  if (! path) path = PATH_X_DEFAULTS;
Jim Blandy's avatar
Jim Blandy committed
279

280
  return search_magic_path (path, class, 0);
Jim Blandy's avatar
Jim Blandy committed
281 282
}

283

Jim Blandy's avatar
Jim Blandy committed
284
static XrmDatabase
285
get_fallback (Display *display)
Jim Blandy's avatar
Jim Blandy committed
286 287 288 289
{
  return NULL;
}

290

Jim Blandy's avatar
Jim Blandy committed
291
static XrmDatabase
292
get_user_app (const char *class)
Jim Blandy's avatar
Jim Blandy committed
293
{
294
  XrmDatabase db = 0;
295
  const char *path;
296 297 298

  /* Check for XUSERFILESEARCHPATH.  It is a path of complete file
     names, not directories.  */
299 300 301
  path = getenv ("XUSERFILESEARCHPATH");
  if (path)
    db = search_magic_path (path, class, 0);
302

303 304
  if (! db)
    {
305 306
      /* Check for APPLRESDIR; it is a path of directories.  In each,
	 we have to search for LANG/CLASS and then CLASS.  */
307 308 309 310 311 312 313 314
      path = getenv ("XAPPLRESDIR");
      if (path)
	{
	  db = search_magic_path (path, class, "/%L/%N");
	  if (!db)
	    db = search_magic_path (path, class, "/%N");
	}
    }
315

316 317
  if (! db)
    {
318 319
      /* Check in the home directory.  This is a bit of a hack; let's
	 hope one's home directory doesn't contain any %-escapes.  */
320 321 322 323 324
      char *home = gethomedir ();
      db = search_magic_path (home, class, "%L/%N");
      if (! db)
	db = search_magic_path (home, class, "%N");
      xfree (home);
Jim Blandy's avatar
Jim Blandy committed
325
    }
326

327
  return db;
Jim Blandy's avatar
Jim Blandy committed
328 329
}

Paul Eggert's avatar
Paul Eggert committed
330
static char const xdefaults[] = ".Xdefaults";
331

Jim Blandy's avatar
Jim Blandy committed
332
static XrmDatabase
333
get_user_db (Display *display)
Jim Blandy's avatar
Jim Blandy committed
334 335 336 337
{
  XrmDatabase db;
  char *xdefs;

338
#ifdef PBaseSize		/* Cheap way to test for X11R4 or later.  */
339 340
  xdefs = XResourceManagerString (display);
#else
341
  xdefs = display->xdefaults;
342 343
#endif

Jim Blandy's avatar
Jim Blandy committed
344 345 346 347
  if (xdefs != NULL)
    db = XrmGetStringDatabase (xdefs);
  else
    {
348
      /* Use ~/.Xdefaults.  */
Paul Eggert's avatar
Paul Eggert committed
349 350 351 352 353 354
      char *home = gethomedir ();
      ptrdiff_t homelen = strlen (home);
      char *filename = xrealloc (home, homelen + sizeof xdefaults);
      strcpy (filename + homelen, xdefaults);
      db = XrmGetFileDatabase (filename);
      xfree (filename);
Jim Blandy's avatar
Jim Blandy committed
355 356
    }

357
#ifdef HAVE_XSCREENRESOURCESTRING
358 359 360
  /* Get the screen-specific resources too.  */
  xdefs = XScreenResourceString (DefaultScreenOfDisplay (display));
  if (xdefs != NULL)
361 362 363 364
    {
      XrmMergeDatabases (XrmGetStringDatabase (xdefs), &db);
      XFree (xdefs);
    }
365 366
#endif

Jim Blandy's avatar
Jim Blandy committed
367 368 369 370
  return db;
}

static XrmDatabase
371
get_environ_db (void)
Jim Blandy's avatar
Jim Blandy committed
372 373
{
  XrmDatabase db;
Paul Eggert's avatar
Paul Eggert committed
374 375
  char *p = getenv ("XENVIRONMENT");
  char *filename = 0;
Jim Blandy's avatar
Jim Blandy committed
376

Paul Eggert's avatar
Paul Eggert committed
377
  if (!p)
Jim Blandy's avatar
Jim Blandy committed
378
    {
379
      Lisp_Object system_name = Fsystem_name ();
380 381 382 383 384 385 386 387 388 389 390
      if (STRINGP (system_name))
	{
	  /* Use ~/.Xdefaults-HOSTNAME.  */
	  char *home = gethomedir ();
	  ptrdiff_t homelen = strlen (home);
	  ptrdiff_t filenamesize = (homelen + sizeof xdefaults
				    + 1 + SBYTES (system_name));
	  p = filename = xrealloc (home, filenamesize);
	  lispstpcpy (stpcpy (stpcpy (filename + homelen, xdefaults), "-"),
		      system_name);
	}
Jim Blandy's avatar
Jim Blandy committed
391 392 393
    }

  db = XrmGetFileDatabase (p);
394

Paul Eggert's avatar
Paul Eggert committed
395
  xfree (filename);
396

Jim Blandy's avatar
Jim Blandy committed
397 398 399
  return db;
}

400 401
/* External interface.  */

Jim Blandy's avatar
Jim Blandy committed
402 403 404
/* Types of values that we can find in a database */

#define XrmStringType "String"	/* String representation */
405
static XrmRepresentation x_rm_string;	/* Quark representation */
Jim Blandy's avatar
Jim Blandy committed
406 407 408 409

/* Load X resources based on the display and a possible -xrm option. */

XrmDatabase
410 411
x_load_resources (Display *display, const char *xrm_string,
		  const char *myname, const char *myclass)
Jim Blandy's avatar
Jim Blandy committed
412
{
413
  XrmDatabase user_database;
Jim Blandy's avatar
Jim Blandy committed
414 415
  XrmDatabase rdb;
  XrmDatabase db;
416
  char line[256];
417

418
#if defined USE_MOTIF || !defined HAVE_XFT || !defined USE_LUCID
419
  const char *helv = "-*-helvetica-medium-r-*--*-120-*-*-*-*-iso8859-1";
420 421 422
#endif

#ifdef USE_MOTIF
423
  const char *courier = "-*-courier-medium-r-*-*-*-120-*-*-*-*-iso8859-1";
424
#endif
Jim Blandy's avatar
Jim Blandy committed
425 426

  x_rm_string = XrmStringToQuark (XrmStringType);
427 428 429
#ifndef USE_X_TOOLKIT
  /* pmr@osf.org says this shouldn't be done if USE_X_TOOLKIT.
     I suspect it's because the toolkit version does this elsewhere.  */
Jim Blandy's avatar
Jim Blandy committed
430
  XrmInitialize ();
431
#endif
Jim Blandy's avatar
Jim Blandy committed
432 433
  rdb = XrmGetStringDatabase ("");

434 435 436
  /* Add some font defaults.  If the font `helv' doesn't exist, widgets
     will use some other default font.  */
#ifdef USE_MOTIF
437

438
  sprintf (line, "%s.pane.background: grey75", myclass);
439
  XrmPutLineResource (&rdb, line);
440
  sprintf (line, "%s*fontList: %s", myclass, helv);
441
  XrmPutLineResource (&rdb, line);
442
  sprintf (line, "%s*menu*background: grey75", myclass);
443
  XrmPutLineResource (&rdb, line);
444
  sprintf (line, "%s*menubar*background: grey75", myclass);
445
  XrmPutLineResource (&rdb, line);
446
  sprintf (line, "%s*verticalScrollBar.background: grey75", myclass);
447
  XrmPutLineResource (&rdb, line);
448
  sprintf (line, "%s*verticalScrollBar.troughColor: grey75", myclass);
449
  XrmPutLineResource (&rdb, line);
450 451 452 453
  sprintf (line, "%s*horizontalScrollBar.background: grey75", myclass);
  XrmPutLineResource (&rdb, line);
  sprintf (line, "%s*horizontalScrollBar.troughColor: grey75", myclass);
  XrmPutLineResource (&rdb, line);
454
  sprintf (line, "%s.dialog*.background: grey75", myclass);
455
  XrmPutLineResource (&rdb, line);
456
  sprintf (line, "%s*fsb.Text.background: white", myclass);
457
  XrmPutLineResource (&rdb, line);
458
  sprintf (line, "%s*fsb.FilterText.background: white", myclass);
459
  XrmPutLineResource (&rdb, line);
460
  sprintf (line, "%s*fsb*DirList.background: white", myclass);
461
  XrmPutLineResource (&rdb, line);
462
  sprintf (line, "%s*fsb*ItemsList.background: white", myclass);
463
  XrmPutLineResource (&rdb, line);
464
  sprintf (line, "%s*fsb*background: grey75", myclass);
465
  XrmPutLineResource (&rdb, line);
466
  sprintf (line, "%s*fsb.Text.fontList: %s", myclass, courier);
467
  XrmPutLineResource (&rdb, line);
468
  sprintf (line, "%s*fsb.FilterText.fontList: %s", myclass, courier);
469
  XrmPutLineResource (&rdb, line);
470
  sprintf (line, "%s*fsb*ItemsList.fontList: %s", myclass, courier);
471
  XrmPutLineResource (&rdb, line);
472
  sprintf (line, "%s*fsb*DirList.fontList: %s", myclass, courier);
473 474 475 476 477 478
  XrmPutLineResource (&rdb, line);

  /* Set double click time of list boxes in the file selection
     dialog from `double-click-time'.  */
  if (INTEGERP (Vdouble_click_time) && XINT (Vdouble_click_time) > 0)
    {
479
      sprintf (line, "%s*fsb*DirList.doubleClickInterval: %"pI"d",
480
	       myclass, XFASTINT (Vdouble_click_time));
481
      XrmPutLineResource (&rdb, line);
482
      sprintf (line, "%s*fsb*ItemsList.doubleClickInterval: %"pI"d",
483
	       myclass, XFASTINT (Vdouble_click_time));
484 485 486 487
      XrmPutLineResource (&rdb, line);
    }

#else /* not USE_MOTIF */
488

489
  sprintf (line, "Emacs.dialog*.background: grey75");
490
  XrmPutLineResource (&rdb, line);
491 492 493
#if !defined (HAVE_XFT) || !defined (USE_LUCID)
  sprintf (line, "Emacs.dialog*.font: %s", helv);
  XrmPutLineResource (&rdb, line);
494
  sprintf (line, "*XlwMenu*font: %s", helv);
495
  XrmPutLineResource (&rdb, line);
496
#endif
497
  sprintf (line, "*XlwMenu*background: grey75");
498
  XrmPutLineResource (&rdb, line);
499
  sprintf (line, "Emacs*verticalScrollBar.background: grey75");
500
  XrmPutLineResource (&rdb, line);
501 502
  sprintf (line, "Emacs*horizontalScrollBar.background: grey75");
  XrmPutLineResource (&rdb, line);
503

504 505
#endif /* not USE_MOTIF */

506 507 508 509
  user_database = get_user_db (display);

  /* Figure out what the "customization string" is, so we can use it
     to decode paths.  */
Dan Nicolaescu's avatar
Dan Nicolaescu committed
510
  xfree (x_customization_string);
511 512 513
  x_customization_string
    = x_get_customization_string (user_database, myname, myclass);

Jim Blandy's avatar
Jim Blandy committed
514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529
  /* Get application system defaults */
  db = get_system_app (myclass);
  if (db != NULL)
    XrmMergeDatabases (db, &rdb);

  /* Get Fallback resources */
  db = get_fallback (display);
  if (db != NULL)
    XrmMergeDatabases (db, &rdb);

  /* Get application user defaults */
  db = get_user_app (myclass);
  if (db != NULL)
    XrmMergeDatabases (db, &rdb);

  /* get User defaults */
530 531
  if (user_database != NULL)
    XrmMergeDatabases (user_database, &rdb);
Jim Blandy's avatar
Jim Blandy committed
532 533 534 535 536

  /* Get Environment defaults. */
  db = get_environ_db ();
  if (db != NULL)
    XrmMergeDatabases (db, &rdb);
537

Jim Blandy's avatar
Jim Blandy committed
538 539 540 541 542 543 544 545 546 547 548
  /* Last, merge in any specification from the command line. */
  if (xrm_string != NULL)
    {
      db = XrmGetStringDatabase (xrm_string);
      if (db != NULL)
	XrmMergeDatabases (db, &rdb);
    }

  return rdb;
}

549

Jim Blandy's avatar
Jim Blandy committed
550 551 552
/* Retrieve the value of the resource specified by NAME with class CLASS
   and of type TYPE from database RDB.  The value is returned in RET_VALUE. */

Andreas Schwab's avatar
Andreas Schwab committed
553 554 555
static int
x_get_resource (XrmDatabase rdb, const char *name, const char *class,
		XrmRepresentation expected_type, XrmValue *ret_value)
Jim Blandy's avatar
Jim Blandy committed
556 557 558 559 560 561
{
  XrmValue value;
  XrmName namelist[100];
  XrmClass classlist[100];
  XrmRepresentation type;

Juanma Barranquero's avatar
Juanma Barranquero committed
562 563
  XrmStringToNameList (name, namelist);
  XrmStringToClassList (class, classlist);
Jim Blandy's avatar
Jim Blandy committed
564 565 566 567 568

  if (XrmQGetResource (rdb, namelist, classlist, &type, &value) == True
      && (type == expected_type))
    {
      if (type == x_rm_string)
569
	ret_value->addr = (char *) value.addr;
Jim Blandy's avatar
Jim Blandy committed
570
      else
571
	memcpy (ret_value->addr, value.addr, ret_value->size);
Jim Blandy's avatar
Jim Blandy committed
572 573 574 575 576 577 578 579 580 581 582

      return value.size;
    }

  return 0;
}

/* Retrieve the string resource specified by NAME with CLASS from
   database RDB. */

char *
583
x_get_string_resource (XrmDatabase rdb, const char *name, const char *class)
Jim Blandy's avatar
Jim Blandy committed
584 585 586
{
  XrmValue value;

587 588 589 590
  if (inhibit_x_resources)
    /* --quick was passed, so this is a no-op.  */
    return NULL;

Jim Blandy's avatar
Jim Blandy committed
591 592 593
  if (x_get_resource (rdb, name, class, x_rm_string, &value))
    return (char *) value.addr;

Paul Eggert's avatar
Paul Eggert committed
594
  return 0;
Jim Blandy's avatar
Jim Blandy committed
595 596
}

597 598
/* Stand-alone test facilities.  */

Jim Blandy's avatar
Jim Blandy committed
599
#ifdef TESTRM
600 601 602 603 604 605 606 607 608

typedef char **List;
#define arg_listify(len, list) (list)
#define car(list) (*(list))
#define cdr(list) (list + 1)
#define NIL(list) (! *(list))
#define free_arglist(list)

static List
Andreas Schwab's avatar
Andreas Schwab committed
609
member (char *elt, List list)
610 611 612 613 614 615 616 617 618
{
  List p;

  for (p = list; ! NIL (p); p = cdr (p))
    if (! strcmp (elt, car (p)))
      return p;

  return p;
}
Jim Blandy's avatar
Jim Blandy committed
619 620

static void
Andreas Schwab's avatar
Andreas Schwab committed
621
fatal (char *msg, char *prog)
Jim Blandy's avatar
Jim Blandy committed
622
{
623
  fprintf (stderr, msg, prog);
Andreas Schwab's avatar
Andreas Schwab committed
624
  exit (1);
Jim Blandy's avatar
Jim Blandy committed
625 626
}

Andreas Schwab's avatar
Andreas Schwab committed
627 628
int
main (int argc, char **argv)
Jim Blandy's avatar
Jim Blandy committed
629 630
{
  Display *display;
631
  char *displayname, *resource_string, *class, *name;
Jim Blandy's avatar
Jim Blandy committed
632
  XrmDatabase xdb;
633
  List arg_list, lp;
Jim Blandy's avatar
Jim Blandy committed
634 635 636 637 638 639 640 641 642 643

  arg_list = arg_listify (argc, argv);

  lp = member ("-d", arg_list);
  if (!NIL (lp))
    displayname = car (cdr (lp));
  else
    displayname = "localhost:0.0";

  lp = member ("-xrm", arg_list);
Paul Eggert's avatar
Paul Eggert committed
644
  resource_string = NIL (lp) ? 0 : car (cdr (lp));
Jim Blandy's avatar
Jim Blandy committed
645 646 647 648 649 650 651

  lp = member ("-c", arg_list);
  if (! NIL (lp))
    class = car (cdr (lp));
  else
    class = "Emacs";

652 653 654 655 656
  lp = member ("-n", arg_list);
  if (! NIL (lp))
    name = car (cdr (lp));
  else
    name = "emacs";
Jim Blandy's avatar
Jim Blandy committed
657

658
  free_arglist (arg_list);
Jim Blandy's avatar
Jim Blandy committed
659 660 661 662

  if (!(display = XOpenDisplay (displayname)))
    fatal ("Can't open display '%s'\n", XDisplayName (displayname));

663
  xdb = x_load_resources (display, resource_string, name, class);
Jim Blandy's avatar
Jim Blandy committed
664 665 666 667

  /* In a real program, you'd want to also do this: */
  display->db = xdb;

668
  while (true)
Jim Blandy's avatar
Jim Blandy committed
669
    {
670 671 672 673 674
      char query_name[90];
      char query_class[90];

      printf ("Name: ");
      gets (query_name);
Jim Blandy's avatar
Jim Blandy committed
675

676
      if (strlen (query_name))
Jim Blandy's avatar
Jim Blandy committed
677
	{
678 679 680 681 682 683
	  char *value;

	  printf ("Class: ");
	  gets (query_class);

	  value = x_get_string_resource (xdb, query_name, query_class);
Jim Blandy's avatar
Jim Blandy committed
684 685

	  if (value != NULL)
686
	    printf ("\t%s(%s):  %s\n\n", query_name, query_class, value);
Jim Blandy's avatar
Jim Blandy committed
687 688 689 690 691 692 693 694 695
	  else
	    printf ("\tNo Value.\n\n");
	}
      else
	break;
    }
  printf ("\tExit.\n\n");

  XCloseDisplay (display);
Andreas Schwab's avatar
Andreas Schwab committed
696 697

  return 0;
Jim Blandy's avatar
Jim Blandy committed
698 699
}
#endif /* TESTRM */