+ unsigned char *p = SDATA (Vx_resource_name);
+ int i;
+
+ len = SBYTES (Vx_resource_name);
+
+ /* Only letters, digits, - and _ are valid in resource names.
+ Count the valid characters and count the invalid ones. */
+ for (i = 0; i < len; i++)
+ {
+ int c = p[i];
+ if (! ((c >= 'a' && c <= 'z')
+ || (c >= 'A' && c <= 'Z')
+ || (c >= '0' && c <= '9')
+ || c == '-' || c == '_'))
+ bad_count++;
+ else
+ good_count++;
+ }
+ }
+ else
+ /* Not a string => completely invalid. */
+ bad_count = 5, good_count = 0;
+
+ /* If name is valid already, return. */
+ if (bad_count == 0)
+ return;
+
+ /* If name is entirely invalid, or nearly so, use `emacs'. */
+ if (good_count == 0
+ || (good_count == 1 && bad_count > 0))
+ {
+ Vx_resource_name = build_string ("emacs");
+ return;
+ }
+
+ /* Name is partly valid. Copy it and replace the invalid characters
+ with underscores. */
+
+ Vx_resource_name = new = Fcopy_sequence (Vx_resource_name);
+
+ for (i = 0; i < len; i++)
+ {
+ int c = SREF (new, i);
+ if (! ((c >= 'a' && c <= 'z')
+ || (c >= 'A' && c <= 'Z')
+ || (c >= '0' && c <= '9')
+ || c == '-' || c == '_'))
+ SSET (new, i, '_');
+ }
+}
+
+
+extern char *x_get_string_resource P_ ((XrmDatabase, char *, char *));
+extern Display_Info *check_x_display_info P_ ((Lisp_Object));
+
+
+/* Get specified attribute from resource database RDB.
+ See Fx_get_resource below for other parameters. */
+
+static Lisp_Object
+xrdb_get_resource (rdb, attribute, class, component, subclass)
+ XrmDatabase rdb;
+ Lisp_Object attribute, class, component, subclass;
+{
+ register char *value;
+ char *name_key;
+ char *class_key;
+
+ CHECK_STRING (attribute);
+ CHECK_STRING (class);
+
+ if (!NILP (component))
+ CHECK_STRING (component);
+ if (!NILP (subclass))
+ CHECK_STRING (subclass);
+ if (NILP (component) != NILP (subclass))
+ error ("x-get-resource: must specify both COMPONENT and SUBCLASS or neither");
+
+ validate_x_resource_name ();
+
+ /* Allocate space for the components, the dots which separate them,
+ and the final '\0'. Make them big enough for the worst case. */
+ name_key = (char *) alloca (SBYTES (Vx_resource_name)
+ + (STRINGP (component)
+ ? SBYTES (component) : 0)
+ + SBYTES (attribute)
+ + 3);
+
+ class_key = (char *) alloca (SBYTES (Vx_resource_class)
+ + SBYTES (class)
+ + (STRINGP (subclass)
+ ? SBYTES (subclass) : 0)
+ + 3);
+
+ /* Start with emacs.FRAMENAME for the name (the specific one)
+ and with `Emacs' for the class key (the general one). */
+ strcpy (name_key, SDATA (Vx_resource_name));
+ strcpy (class_key, SDATA (Vx_resource_class));
+
+ strcat (class_key, ".");
+ strcat (class_key, SDATA (class));
+
+ if (!NILP (component))
+ {
+ strcat (class_key, ".");
+ strcat (class_key, SDATA (subclass));
+
+ strcat (name_key, ".");
+ strcat (name_key, SDATA (component));
+ }
+
+ strcat (name_key, ".");
+ strcat (name_key, SDATA (attribute));
+
+ value = x_get_string_resource (rdb, name_key, class_key);
+
+ if (value != (char *) 0)
+ return build_string (value);
+ else
+ return Qnil;
+}
+
+
+DEFUN ("x-get-resource", Fx_get_resource, Sx_get_resource, 2, 4, 0,
+ doc: /* Return the value of ATTRIBUTE, of class CLASS, from the X defaults database.
+This uses `INSTANCE.ATTRIBUTE' as the key and `Emacs.CLASS' as the
+class, where INSTANCE is the name under which Emacs was invoked, or
+the name specified by the `-name' or `-rn' command-line arguments.
+
+The optional arguments COMPONENT and SUBCLASS add to the key and the
+class, respectively. You must specify both of them or neither.
+If you specify them, the key is `INSTANCE.COMPONENT.ATTRIBUTE'
+and the class is `Emacs.CLASS.SUBCLASS'. */)
+ (attribute, class, component, subclass)
+ Lisp_Object attribute, class, component, subclass;
+{
+#ifdef HAVE_X_WINDOWS
+ check_x ();
+#endif
+
+ return xrdb_get_resource (check_x_display_info (Qnil)->xrdb,
+ attribute, class, component, subclass);
+}
+
+/* Get an X resource, like Fx_get_resource, but for display DPYINFO. */
+
+Lisp_Object
+display_x_get_resource (dpyinfo, attribute, class, component, subclass)
+ Display_Info *dpyinfo;
+ Lisp_Object attribute, class, component, subclass;
+{
+ return xrdb_get_resource (dpyinfo->xrdb,
+ attribute, class, component, subclass);
+}
+
+/* Used when C code wants a resource value. */
+
+char *
+x_get_resource_string (attribute, class)
+ char *attribute, *class;
+{
+ char *name_key;
+ char *class_key;
+ struct frame *sf = SELECTED_FRAME ();
+
+ /* Allocate space for the components, the dots which separate them,
+ and the final '\0'. */
+ name_key = (char *) alloca (SBYTES (Vinvocation_name)
+ + strlen (attribute) + 2);
+ class_key = (char *) alloca ((sizeof (EMACS_CLASS) - 1)
+ + strlen (class) + 2);
+
+ sprintf (name_key, "%s.%s", SDATA (Vinvocation_name), attribute);
+ sprintf (class_key, "%s.%s", EMACS_CLASS, class);
+
+ return x_get_string_resource (FRAME_X_DISPLAY_INFO (sf)->xrdb,
+ name_key, class_key);
+}
+
+
+/* Return the value of parameter PARAM.
+
+ First search ALIST, then Vdefault_frame_alist, then the X defaults
+ database, using ATTRIBUTE as the attribute name and CLASS as its class.
+
+ Convert the resource to the type specified by desired_type.
+
+ If no default is specified, return Qunbound. If you call
+ x_get_arg, make sure you deal with Qunbound in a reasonable way,
+ and don't let it get stored in any Lisp-visible variables! */
+
+Lisp_Object
+x_get_arg (dpyinfo, alist, param, attribute, class, type)
+ Display_Info *dpyinfo;
+ Lisp_Object alist, param;
+ char *attribute;
+ char *class;
+ enum resource_types type;
+{
+ register Lisp_Object tem;
+
+ tem = Fassq (param, alist);
+
+ if (!NILP (tem))
+ {
+ /* If we find this parm in ALIST, clear it out
+ so that it won't be "left over" at the end. */
+#ifndef WINDOWSNT /* w32fns.c has not yet been changed to cope with this. */
+ Lisp_Object tail;
+ XSETCAR (tem, Qnil);
+ /* In case the parameter appears more than once in the alist,
+ clear it out. */
+ for (tail = alist; CONSP (tail); tail = XCDR (tail))
+ if (CONSP (XCAR (tail))
+ && EQ (XCAR (XCAR (tail)), param))
+ XSETCAR (XCAR (tail), Qnil);
+#endif
+ }
+ else
+ tem = Fassq (param, Vdefault_frame_alist);
+
+ /* If it wasn't specified in ALIST or the Lisp-level defaults,
+ look in the X resources. */
+ if (EQ (tem, Qnil))
+ {
+ if (attribute)
+ {
+ tem = display_x_get_resource (dpyinfo,
+ build_string (attribute),
+ build_string (class),
+ Qnil, Qnil);
+
+ if (NILP (tem))
+ return Qunbound;
+
+ switch (type)
+ {
+ case RES_TYPE_NUMBER:
+ return make_number (atoi (SDATA (tem)));
+
+ case RES_TYPE_FLOAT:
+ return make_float (atof (SDATA (tem)));
+
+ case RES_TYPE_BOOLEAN:
+ tem = Fdowncase (tem);
+ if (!strcmp (SDATA (tem), "on")
+ || !strcmp (SDATA (tem), "true"))
+ return Qt;
+ else
+ return Qnil;
+
+ case RES_TYPE_STRING:
+ return tem;
+
+ case RES_TYPE_SYMBOL:
+ /* As a special case, we map the values `true' and `on'
+ to Qt, and `false' and `off' to Qnil. */
+ {
+ Lisp_Object lower;
+ lower = Fdowncase (tem);
+ if (!strcmp (SDATA (lower), "on")
+ || !strcmp (SDATA (lower), "true"))
+ return Qt;
+ else if (!strcmp (SDATA (lower), "off")
+ || !strcmp (SDATA (lower), "false"))
+ return Qnil;
+ else
+ return Fintern (tem, Qnil);
+ }
+
+ default:
+ abort ();
+ }
+ }