home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / emacs-19.28-src.tgz / tar.out / fsf / emacs / src / xrdb.c < prev    next >
C/C++ Source or Header  |  1996-09-28  |  17KB  |  740 lines

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