]> code.delx.au - gnu-emacs/blob - src/xrdb.c
* xterm.c (XTread_socket): Never treat a modifier key as a
[gnu-emacs] / src / xrdb.c
1 /* Deal with the X Resource Manager.
2 Copyright (C) 1990, 1993 Free Software Foundation.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
7 any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; see the file COPYING. If not, write to
16 the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
17
18 /* Written by jla, 4/90 */
19
20 #ifdef emacs
21 #include "config.h"
22 #endif
23
24 #if 1 /* I'd really appreciate it if this code could go away... -JimB */
25 /* this avoids lossage in the `dual-universe' headers on AT&T SysV X11 */
26 #ifdef USG5
27 #define SYSV
28 #include <unistd.h>
29 #endif /* USG5 */
30
31 #endif /* 1 */
32
33 /* This should be included before the X include files; otherwise, we get
34 warnings about redefining NULL under BSD 4.3. */
35 #include <sys/param.h>
36
37 #include <X11/Xlib.h>
38 #include <X11/Xatom.h>
39 #if 0
40 #include <X11/Xos.h>
41 #endif
42 #include <X11/X.h>
43 #include <X11/Xutil.h>
44 #include <X11/Xresource.h>
45 #ifdef VMS
46 #include "vms-pwd.h"
47 #else
48 #include <pwd.h>
49 #endif
50 #include <sys/stat.h>
51
52 #ifndef MAXPATHLEN
53 #define MAXPATHLEN 256
54 #endif
55
56 extern char *getenv ();
57
58 /* This does cause trouble on AIX. I'm going to take the comment at
59 face value. */
60 #if 0
61 extern short getuid (); /* If this causes portability problems,
62 I think we should just delete it; it'll
63 default to `int' anyway. */
64 #endif
65
66 #ifdef __bsdi__
67 extern struct passwd *getpwuid (uid_t);
68 extern struct passwd *getpwnam (const char *);
69 #else
70 extern struct passwd *getpwuid ();
71 extern struct passwd *getpwnam ();
72 #endif
73
74 static char *
75 gethomedir (dirname)
76 char *dirname;
77 {
78 int uid;
79 struct passwd *pw;
80 char *ptr;
81
82 if ((ptr = getenv ("HOME")) == NULL)
83 {
84 if ((ptr = getenv ("USER")) != NULL)
85 pw = getpwnam (ptr);
86 else
87 {
88 uid = getuid ();
89 pw = getpwuid (uid);
90 }
91 if (pw)
92 ptr = pw->pw_dir;
93 else
94 {
95 ptr = NULL;
96 *dirname = '\0';
97 }
98 }
99
100 if (ptr != NULL)
101 strcpy (dirname, ptr);
102
103 dirname += strlen (dirname);
104 *dirname = '/';
105 dirname++;
106 *dirname = '\0';
107
108 return dirname;
109 }
110
111 static int
112 file_p (path)
113 char *path;
114 {
115 struct stat status;
116
117 return (access (path, 4) == 0 /* exists and is readable */
118 && stat (path, &status) == 0 /* get the status */
119 && (status.st_mode & S_IFDIR) == 0); /* not a directory */
120 }
121
122 #if 0
123 #define X_DEFAULT_SEARCH_PATH "/usr/lib/X11/"
124 #endif
125
126 /* Isn't this just disgusting? */
127
128 #define X_DEFAULT_SEARCH_PATH "/usr/lib/X11/%L/%T/%N%S:/usr/lib/X11/%l/%T/%N%S:/usr/lib/X11/%T/%N%S"
129
130 static int
131 decode_magic (string, file, return_path)
132 char *string, *file, *return_path;
133 {
134 char *p = string;
135 char *t = return_path;
136
137 while (*p)
138 {
139 if (*p == '%')
140 switch (*++p)
141 {
142 case '%':
143 *t++ = '%';
144 p++;
145 break;
146
147 case 'N':
148 case 'T':
149 case 'S':
150 case 'L':
151 case 'l':
152 case 't':
153 case 'c':
154 default:
155 p++;
156 if (*t == '/' && *p == '/')
157 p++;
158 break;
159 }
160 else
161 *t++ = *p++;
162 }
163 *t = '\0';
164 strcat (return_path, file);
165
166 if (file_p (return_path))
167 return 1;
168
169 return_path[0] = '\0';
170 return 0;
171 }
172
173 static int
174 magic_searchpath_decoder (incantation_string, file, return_path)
175 char *incantation_string, *return_path, *file;
176 {
177 register char *s = incantation_string;
178 register char *p;
179
180 /* Must be big enough for "%N%S". */
181 register int string_size = MAXPATHLEN;
182 register char *string = (char *) alloca (string_size * sizeof (*string));
183
184 while (*s)
185 {
186 p = s;
187
188 while (*p && *p != ':')
189 p++;
190
191 if (*p == ':' && *(p + 1) == ':')
192 {
193 /* We know string is big enough for this. */
194 bcopy ("%N%S", string, 5);
195 if (decode_magic (string, file, return_path))
196 return 1;
197
198 s = p + 1;
199 continue;
200 }
201
202 if (p > s)
203 {
204 int len = p - s;
205
206 if (string_size < len+1)
207 {
208 string_size = 2 * len;
209 string = (char *) alloca (string_size * sizeof (*string));
210 }
211 bcopy (s, string, len);
212 string[len] = '\0';
213 if (decode_magic (string, file, return_path))
214 return 1;
215 }
216
217 if (p && *p != 0)
218 s = p + 1;
219 else
220 return 0;
221 }
222
223 return 0;
224 }
225 \f
226 static XrmDatabase
227 get_system_app (class)
228 char *class;
229 {
230 XrmDatabase db;
231 char path[MAXPATHLEN];
232 char *p;
233
234 if ((p = getenv ("XFILESEARCHPATH")) == NULL)
235 p = X_DEFAULT_SEARCH_PATH;
236
237 if (! magic_searchpath_decoder (p, class, path))
238 return NULL;
239
240 db = XrmGetFileDatabase (path);
241 return db;
242 }
243
244 static XrmDatabase
245 get_fallback (display)
246 Display *display;
247 {
248 XrmDatabase db;
249
250 return NULL;
251 }
252
253 static XrmDatabase
254 get_user_app (class)
255 char *class;
256 {
257 XrmDatabase db;
258 char *magic_path;
259 char path[MAXPATHLEN];
260
261 if ((magic_path = getenv ("XUSERFILESEARCHPATH")) == NULL)
262 {
263 char homedir[MAXPATHLEN];
264 char *default_magic;
265 char *p;
266
267 gethomedir (homedir);
268
269 if ((p = getenv ("XAPPLRESDIR")) == NULL)
270 {
271 default_magic = "%s/%%L/%%N:%s/%%l/%%N:%s/%%N";
272 magic_path = (char *) alloca ((3 * strlen (homedir))
273 + strlen (default_magic));
274 sprintf (magic_path, default_magic, homedir, homedir, homedir);
275 }
276 else
277 {
278 default_magic = "%s/%%L/%%N:%s/%%l/%%N:%s/%%N:%s/%%N";
279 magic_path = (char *) alloca ((3 * strlen (p))
280 + strlen (default_magic)
281 + strlen (homedir));
282 sprintf (magic_path, default_magic, p, p, p, homedir);
283 }
284 }
285
286 if (! magic_searchpath_decoder (magic_path, class, path))
287 return NULL;
288
289 db = XrmGetFileDatabase (path);
290 return db;
291 }
292
293 static XrmDatabase
294 get_user_db (display)
295 Display *display;
296 {
297 XrmDatabase db;
298 char *xdefs;
299
300 #ifdef PBaseSize /* Cheap way to test for X11R4 or later. */
301 xdefs = XResourceManagerString (display);
302 #else
303 xdefs = display->xdefaults;
304 #endif
305
306 if (xdefs != NULL)
307 db = XrmGetStringDatabase (xdefs);
308 else
309 {
310 char xdefault[MAXPATHLEN];
311
312 gethomedir (xdefault);
313 strcat (xdefault, ".Xdefaults");
314 db = XrmGetFileDatabase (xdefault);
315 }
316
317 #ifdef XlibSpecificationRelease
318 #if XlibSpecificationRelease >= 5
319 /* Get the screen-specific resources too. */
320 xdefs = XScreenResourceString (DefaultScreenOfDisplay (display));
321 if (xdefs != NULL)
322 XrmMergeDatabases (XrmGetStringDatabase (xdefs), &db);
323 #endif
324 #endif
325
326 return db;
327 }
328
329 static XrmDatabase
330 get_environ_db ()
331 {
332 XrmDatabase db;
333 char *p;
334 char path[MAXPATHLEN];
335
336 if ((p = getenv ("XENVIRONMENT")) == NULL)
337 {
338 gethomedir (path);
339 strcat (path, ".Xdefaults-");
340 gethostname (path + strlen (path), MAXPATHLEN - strlen (path));
341 p = path;
342 }
343
344 db = XrmGetFileDatabase (p);
345 return db;
346 }
347 \f
348 /* Types of values that we can find in a database */
349
350 #define XrmStringType "String" /* String representation */
351 XrmRepresentation x_rm_string; /* Quark representation */
352
353 /* Load X resources based on the display and a possible -xrm option. */
354
355 XrmDatabase
356 x_load_resources (display, xrm_string, myclass)
357 Display *display;
358 char *xrm_string, *myclass;
359 {
360 char *xdefs;
361 XrmDatabase rdb;
362 XrmDatabase db;
363
364 x_rm_string = XrmStringToQuark (XrmStringType);
365 XrmInitialize ();
366 rdb = XrmGetStringDatabase ("");
367
368 /* Get application system defaults */
369 db = get_system_app (myclass);
370 if (db != NULL)
371 XrmMergeDatabases (db, &rdb);
372
373 /* Get Fallback resources */
374 db = get_fallback (display);
375 if (db != NULL)
376 XrmMergeDatabases (db, &rdb);
377
378 /* Get application user defaults */
379 db = get_user_app (myclass);
380 if (db != NULL)
381 XrmMergeDatabases (db, &rdb);
382
383 /* get User defaults */
384 db = get_user_db (display);
385 if (db != NULL)
386 XrmMergeDatabases (db, &rdb);
387
388 /* Get Environment defaults. */
389 db = get_environ_db ();
390 if (db != NULL)
391 XrmMergeDatabases (db, &rdb);
392
393 /* Last, merge in any specification from the command line. */
394 if (xrm_string != NULL)
395 {
396 db = XrmGetStringDatabase (xrm_string);
397 if (db != NULL)
398 XrmMergeDatabases (db, &rdb);
399 }
400
401 return rdb;
402 }
403
404 /* Retrieve the value of the resource specified by NAME with class CLASS
405 and of type TYPE from database RDB. The value is returned in RET_VALUE. */
406
407 int
408 x_get_resource (rdb, name, class, expected_type, ret_value)
409 XrmDatabase rdb;
410 char *name, *class;
411 XrmRepresentation expected_type;
412 XrmValue *ret_value;
413 {
414 XrmValue value;
415 XrmName namelist[100];
416 XrmClass classlist[100];
417 XrmRepresentation type;
418
419 XrmStringToNameList(name, namelist);
420 XrmStringToClassList(class, classlist);
421
422 if (XrmQGetResource (rdb, namelist, classlist, &type, &value) == True
423 && (type == expected_type))
424 {
425 if (type == x_rm_string)
426 ret_value->addr = (char *) value.addr;
427 else
428 bcopy (value.addr, ret_value->addr, ret_value->size);
429
430 return value.size;
431 }
432
433 return 0;
434 }
435
436 /* Retrieve the string resource specified by NAME with CLASS from
437 database RDB. */
438
439 char *
440 x_get_string_resource (rdb, name, class)
441 XrmDatabase rdb;
442 char *name, *class;
443 {
444 XrmValue value;
445
446 if (x_get_resource (rdb, name, class, x_rm_string, &value))
447 return (char *) value.addr;
448
449 return (char *) 0;
450 }
451 \f
452 #ifdef TESTRM
453 #include <stdio.h>
454 #include "arg-list.h"
455
456 static void
457 fatal (msg, prog, x1, x2, x3, x4, x5)
458 char *msg, *prog;
459 int x1, x2, x3, x4, x5;
460 {
461 extern int errno;
462
463 if (errno)
464 perror (prog);
465
466 (void) fprintf (stderr, msg, prog, x1, x2, x3, x4, x5);
467 exit (1);
468 }
469
470 main (argc, argv)
471 int argc;
472 char **argv;
473 {
474 Display *display;
475 char *displayname, *resource_string, *class;
476 XrmDatabase xdb;
477 List *arg_list, *lp;
478
479 arg_list = arg_listify (argc, argv);
480
481 lp = member ("-d", arg_list);
482 if (!NIL (lp))
483 displayname = car (cdr (lp));
484 else
485 displayname = "localhost:0.0";
486
487 lp = member ("-xrm", arg_list);
488 if (! NIL (lp))
489 resource_string = car (cdr (lp));
490 else
491 resource_string = (char *) 0;
492
493 lp = member ("-c", arg_list);
494 if (! NIL (lp))
495 class = car (cdr (lp));
496 else
497 class = "Emacs";
498
499 free_arglist (arg_list);
500
501
502
503 if (!(display = XOpenDisplay (displayname)))
504 fatal ("Can't open display '%s'\n", XDisplayName (displayname));
505
506 xdb = x_load_resources (display, resource_string, class);
507
508 #if 0
509 /* In a real program, you'd want to also do this: */
510 display->db = xdb;
511 #endif
512
513 while (1)
514 {
515 char line[90];
516
517 printf ("String: ");
518 gets (line);
519 if (strlen (line))
520 {
521 char *value = x_get_string_resource (xdb, line, class);
522
523 if (value != NULL)
524 printf ("\t%s: %s\n\n", line, value);
525 else
526 printf ("\tNo Value.\n\n");
527 }
528 else
529 break;
530 }
531 printf ("\tExit.\n\n");
532
533 XCloseDisplay (display);
534 }
535 #endif /* TESTRM */