+ char *p, *q, *key;
+ struct skeyval *xrms, *ret;
+
+ p = q = strchr(string, ':');
+ if (!q) {
+ fprintf(stderr, "pterm: expected a colon in resource string"
+ " \"%s\"\n", string);
+ return;
+ }
+ q++;
+ while (p > string && p[-1] != '.' && p[-1] != '*')
+ p--;
+ xrms = snew(struct skeyval);
+ key = snewn(q-p, char);
+ memcpy(key, p, q-p);
+ key[q-p-1] = '\0';
+ xrms->key = key;
+ while (*q && isspace((unsigned char)*q))
+ q++;
+ xrms->value = dupstr(q);
+
+ if (!xrmtree)
+ xrmtree = newtree234(keycmp);
+
+ ret = add234(xrmtree, xrms);
+ if (ret) {
+ /* Override an existing string. */
+ del234(xrmtree, ret);
+ add234(xrmtree, xrms);
+ }
+}
+
+const char *get_setting(const char *key)
+{
+ struct skeyval tmp, *ret;
+ tmp.key = key;
+ if (xrmtree) {
+ ret = find234(xrmtree, &tmp, NULL);
+ if (ret)
+ return ret->value;
+ }
+ return x_get_default(key);
+}
+
+void *open_settings_r(const char *sessionname)
+{
+ char *filename;
+ FILE *fp;
+ char *line;
+ tree234 *ret;
+
+ filename = make_filename(INDEX_SESSION, sessionname);
+ fp = fopen(filename, "r");
+ sfree(filename);
+ if (!fp)
+ return NULL; /* can't open */
+
+ ret = newtree234(keycmp);
+
+ while ( (line = fgetline(fp)) ) {
+ char *value = strchr(line, '=');
+ struct skeyval *kv;
+
+ if (!value) {
+ sfree(line);
+ continue;
+ }
+ *value++ = '\0';
+ value[strcspn(value, "\r\n")] = '\0'; /* trim trailing NL */
+
+ kv = snew(struct skeyval);
+ kv->key = dupstr(line);
+ kv->value = dupstr(value);
+ add234(ret, kv);
+
+ sfree(line);
+ }
+
+ fclose(fp);
+
+ return ret;
+}
+
+char *read_setting_s(void *handle, const char *key)
+{
+ tree234 *tree = (tree234 *)handle;
+ const char *val;
+ struct skeyval tmp, *kv;
+
+ tmp.key = key;
+ if (tree != NULL &&
+ (kv = find234(tree, &tmp, NULL)) != NULL) {
+ val = kv->value;
+ assert(val != NULL);
+ } else
+ val = get_setting(key);
+
+ if (!val)
+ return NULL;
+ else
+ return dupstr(val);
+}
+
+int read_setting_i(void *handle, const char *key, int defvalue)
+{
+ tree234 *tree = (tree234 *)handle;
+ const char *val;
+ struct skeyval tmp, *kv;
+
+ tmp.key = key;
+ if (tree != NULL &&
+ (kv = find234(tree, &tmp, NULL)) != NULL) {
+ val = kv->value;
+ assert(val != NULL);
+ } else
+ val = get_setting(key);
+
+ if (!val)
+ return defvalue;
+ else
+ return atoi(val);
+}
+
+FontSpec *read_setting_fontspec(void *handle, const char *name)
+{
+ /*
+ * In GTK1-only PuTTY, we used to store font names simply as a
+ * valid X font description string (logical or alias), under a
+ * bare key such as "Font".
+ *
+ * In GTK2 PuTTY, we have a prefix system where "client:"
+ * indicates a Pango font and "server:" an X one; existing
+ * configuration needs to be reinterpreted as having the
+ * "server:" prefix, so we change the storage key from the
+ * provided name string (e.g. "Font") to a suffixed one
+ * ("FontName").
+ */
+ char *suffname = dupcat(name, "Name", NULL);
+ char *tmp;
+
+ if ((tmp = read_setting_s(handle, suffname)) != NULL) {
+ FontSpec *fs = fontspec_new(tmp);
+ sfree(suffname);
+ sfree(tmp);
+ return fs; /* got new-style name */
+ }
+ sfree(suffname);
+
+ /* Fall back to old-style name. */
+ tmp = read_setting_s(handle, name);
+ if (tmp && *tmp) {
+ char *tmp2 = dupcat("server:", tmp, NULL);
+ FontSpec *fs = fontspec_new(tmp2);
+ sfree(tmp2);
+ sfree(tmp);
+ return fs;
+ } else {
+ sfree(tmp);
+ return NULL;
+ }
+}
+Filename *read_setting_filename(void *handle, const char *name)
+{
+ char *tmp = read_setting_s(handle, name);
+ if (tmp) {
+ Filename *ret = filename_from_str(tmp);
+ sfree(tmp);
+ return ret;
+ } else
+ return NULL;