home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 5 Edit / 05-Edit.zip / e20313sr.zip / emacs / 20.3.1 / src / xrdb.c < prev    next >
C/C++ Source or Header  |  1999-07-31  |  17KB  |  745 lines

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