/*
 * Copyright (c) Des Herriott 1993, 1994
 *
 * Permission to use, copy, modify, distribute, and sell this software and its
 * documentation for any purpose is hereby granted without fee, provided that
 * the above copyright notice appear in all copies and that both that
 * copyright notice and this permission notice appear in supporting
 * documentation, and that the name of the copyright holder not be used in
 * advertising or publicity pertaining to distribution of the software without
 * specific, written prior permission.  The copyright holder makes no
 * representations about the suitability of this software for any purpose.  It
 * is provided "as is" without express or implied warranty.
 *
 * THE COPYRIGHT HOLDER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
 * EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY SPECIAL, INDIRECT OR
 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 * PERFORMANCE OF THIS SOFTWARE.
 *
 * Author: Des Herriott
 */

/*
 * Source file resource.c - deals with the Xrm database, and initialises
 * various run-time configuration options.
 */

#include <X11/Xlib.h>
#include <X11/Intrinsic.h>

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <unistd.h>
#include <sys/param.h>

#ifdef HAS_UNAME
#include <sys/utsname.h>
#endif

#include "z80.h"
#include "version.h"
#include "xspec.h"
#include "rtcfg.h"
#include "util.h"

#ifndef USRLIBDIR
#define USRLIBDIR "/usr/lib/X11"
#endif

#ifndef LIBDIR
#define LIBDIR "/usr/local/lib/xzx"
#endif

#ifndef MAXPATHLEN
#define MAXPATHLEN 1024
#endif

#define MAX_CHARS 80
#define MAX_DISP_LEN 256

#define ZX_MIN(x,y) (x<y?x:y)
#define NELEM(a) (sizeof(a)/sizeof(a[0]))

/* Xrm parseable resources - requires Xlib.h and Intrinsic.h */
static XrmOptionDescRec opts[] = {
	{ "-help",    ".help",    XrmoptionNoArg, "True" },
	{ "-version", ".version", XrmoptionNoArg, "True" },
	{ "-visual",  ".visual",  XrmoptionSepArg, NULL },
	{ "-font",    ".font",    XrmoptionSepArg, NULL },
	{ "-emode",   ".emode",   XrmoptionSepArg, NULL },
	{ "-geometry",".geometry",XrmoptionSepArg, NULL },
	{ "-romName", ".romName", XrmoptionSepArg, NULL },
	{ "-rom1280", ".rom1280", XrmoptionSepArg, NULL },
	{ "-rom1281", ".rom1281", XrmoptionSepArg, NULL },
	{ "-rompl30", ".rompl30", XrmoptionSepArg, NULL },
	{ "-rompl31", ".rompl31", XrmoptionSepArg, NULL },
	{ "-rompl32", ".rompl32", XrmoptionSepArg, NULL },
	{ "-rompl33", ".rompl33", XrmoptionSepArg, NULL },
	{ "-fda",     ".fda",     XrmoptionSepArg, NULL },
	{ "-fdb",     ".fdb",     XrmoptionSepArg, NULL },
	{ "-mitshm",  ".mitshm",  XrmoptionSepArg, NULL },
#if 1
	{ "-pixmap",  ".pixmap",  XrmoptionSepArg, NULL },
#endif
	{ "-libDir",  ".libDir",  XrmoptionSepArg, NULL },
	{ "-display", ".display", XrmoptionSepArg, NULL },
	{ "-intStyle",".intStyle",XrmoptionSepArg, NULL },
	{ "-iFreq",   ".iFreq",   XrmoptionSepArg, NULL },
	{ "-flashing",".flashing",XrmoptionSepArg, NULL },
	{ "-rrShm",   ".rrShm",   XrmoptionSepArg, NULL },
	{ "-rrNoshm", ".rrNoshm", XrmoptionSepArg, NULL },
	{ "-private", ".private", XrmoptionIsArg, NULL },
	{ "-mono",    ".mono",    XrmoptionIsArg, NULL },
	{ "-kempstUp", ".kempstUp", XrmoptionSepArg, NULL },
	{ "-kempstDown", ".kempstDown", XrmoptionSepArg, NULL },
	{ "-kempstLeft", ".kempstLeft", XrmoptionSepArg, NULL },
	{ "-kempstRight", ".kempstRight", XrmoptionSepArg, NULL },
	{ "-kempstFire", ".kempstFire", XrmoptionSepArg, NULL },
#ifdef SLOWDOWN
	{ "-slowdown",".slowdown",XrmoptionSepArg, NULL },
	{ "-keyFaster",".keyFaster",XrmoptionSepArg, NULL },
	{ "-keySlower",".keySlower",XrmoptionSepArg, NULL },
#endif
#ifdef JOY
	{ "-joystick",".joystick",XrmoptionSepArg, NULL },
	{ "-joyDev",  ".joyDev",  XrmoptionSepArg, NULL },
	{ "-tolerance",".tolerance",XrmoptionSepArg, NULL },
#endif
#if defined(DEV_AUDIO) || defined(PCSPKR_AUDIO)
	{ "-sound",   ".sound",   XrmoptionSepArg, NULL },
#endif
#ifdef DEV_AUDIO
	{ "-audioDev",".audioDev",XrmoptionSepArg, NULL },
#endif
#ifdef NAS_AUDIO
	{ "-audioServer",".audioServer",XrmoptionSepArg, NULL },
#endif
#ifdef XBELL_AUDIO
	{ "-bellVol", ".bellVol", XrmoptionSepArg, NULL },
#endif
#ifdef XZX_IF1
	{ "-if1",     ".if1",	  XrmoptionSepArg, NULL },
	{ "-if1Rom",  ".if1Rom",  XrmoptionSepArg, NULL },
	{ "-crlf",    ".crlf",    XrmoptionSepArg, NULL },
	{ "-strcr",   ".strcr",   XrmoptionSepArg, NULL },
	{ "-m1",      ".m1",	  XrmoptionSepArg, NULL },
	{ "-m2",      ".m2",	  XrmoptionSepArg, NULL },
	{ "-m3",      ".m3",	  XrmoptionSepArg, NULL },
	{ "-m4",      ".m4",	  XrmoptionSepArg, NULL },
	{ "-m5",      ".m5",	  XrmoptionSepArg, NULL },
	{ "-m6",      ".m6",	  XrmoptionSepArg, NULL },
	{ "-m7",      ".m7",	  XrmoptionSepArg, NULL },
	{ "-m8",      ".m8",	  XrmoptionSepArg, NULL },
#endif
};


/* mappings from keysyms to spectrum actions */
static struct k_map {
	char *res_name;
	char *def_keysym;
} map_tab[NUM_KEYMAPPINGS] = {
	{ "kempstUp",    "q" }, 
	{ "kempstDown",  "a" },
	{ "kempstLeft",  "o" },
	{ "kempstRight", "p" },
	{ "kempstFire",  "space" },
#ifdef SLOWDOWN
	{ "keySlower",   "KP_Subtract" },
	{ "keyFaster",   "KP_Add" },
#endif
};


/* Try to work out whether or not xzx is on the same machine as
 * the X server - needed to know whether or not to use MIT-SHM.
 * FIXME: this probably won't work on non-Unix systems.
 */
static int
is_local_server(char *dispName)
{
#ifdef HAS_UNAME
	struct utsname un;
#else
	char sysname[MAX_DISP_LEN];
#endif

	if (dispName[0] == ':')
		return(1);
	if (strncmp(dispName, "unix", 4) == 0)
		return(1);
	if (strncmp(dispName, "localhost", 9) == 0)
		return(1);

	/* Try matching the display name to the machine name */
#ifdef HAS_UNAME
	uname(&un);
	if (strncmp(dispName, un.sysname, strlen(un.sysname)) == 0)
		return(1);
	if (strncmp(dispName, un.nodename, strlen(un.nodename)) == 0)
		return(1);
#else	/* use gethostname() instead */
	gethostname(sysname, MAX_DISP_LEN);
	if (strncmp(dispName, sysname, strlen(sysname)) == 0)
		return(1);
#endif

	return(0);
}


static void
usage(void)
{
	printf("Xzx is copyright (c) 1993,1994 Des Herriott\n");
	printf("Xzx comes with no warranty; see the file COPYRIGHT for details\n");

/* The NEC EWS C compiler claims it's ANSI, but doesn't allow string 
 * literal concatenation.  Pretty braindead and useless, if you ask me.
 */
#ifndef nec_ews
	printf("\nUsage: xzx [options] [snapshot-file]\n"
		"Available options:\n"
		"   -help\t\tdisplay this message\n"
		"   -version\t\tdisplay the current version\n"
		"   -visual <visual>\tuse the specified X visual\n"
		"   -font <fontname>\tuse the specified X font [fixed]\n"
		"   -geometry <g.spec.>\tspecify window position\n"
		"   -romName <fname>\tuse the specified file as 48K ROM image\n"
		"   -rom128{0,1} <fname>\tuse the specified file as 128K ROM image\n"
		"   -rompl3{0-3} <fname>\tuse the specified file as +3 ROM image\n"
		"   -libDir <path>\tspecify library directories\n"
		"   -mitshm <bool>\ttry to use MIT-SHM [true]\n"
		"   -flashing <bool>\tenable flashing attributes [true]\n"
		"   -rrShm <n>\t\trefresh screen every <n> interrupts (MITSHM) [2]\n"
		"   -rrNoshm <n>\t\trefresh screen every <n> interrupts (no MITSHM) [6]\n"
		"   -mono\t\tuse only black and white\n"
		"   -private\t\tforce a private colormap\n"
		"   -intStyle [signal|counter]\n\t\t\t"
		"specify how interrupts are implemented [signal]\n"
		"   -iFreq <n>\t\tcounter-style interrupts occur every n instructions\n"
	    "   -kempstUp <keysym>\tKempston Joystick up key [q]\n"
	    "   -kempstDown <keysym>\tKempston Joystick down key [a]\n"
	    "   -kempstLeft <keysym>\tKempston Joystick left key [o]\n"
	    "   -kempstRight <keysym>Kempston Joystick right key [p]\n"
	    "   -kempstFire <keysym>\tKempston Joystick fire key [space]\n"
#ifdef SLOWDOWN
		"   -slowdown <int>\t\tspecify slowdown factor\n"
		"   -keySlower <keysym>\tslow down the emulator\n"
		"   -keyFaster <keysym>\tspeed up the emulator\n"
#endif
#ifdef JOY
		"   -joystick <bool>\tenable/disable Kempston joystick [false]\n"
		"   -joyDev <path>\tspecify joystick device [/dev/js0]\n"
		"   -tolerance <int>\tspecify joystick displacement tolerance [20]\n"
#endif
#if defined(DEV_AUDIO) || defined(PCSPKR_AUDIO)
		"   -sound <bool>\tenable/disable sound [false]\n"
#endif
#ifdef DEV_AUDIO
		"   -audioDev <path>\tspecify the audio device [/dev/audio]\n"
#endif
#ifdef XBELL_AUDIO
		"   -bellVol <n>\tspecify bell volume as a percentage\n"
#endif
#ifdef XZX_IF1
		"   -if1 <bool>\t\tenable Interface 1 [true]\n"
		"   -if1Rom <path>\tspecify Interface 1 ROM image\n"
		"   -crlf <bool>\t\tenable CR/LF translation on RS232 input [false]\n"
		"   -strcr <bool>\tstrip CR on RS232 output [false]\n"
		"   -m<n> <path>\t\tput Microdrive cartridge file in drive <n>\n"
		"\nMicrodrive emulation reads and writes .MDR files."
#endif
		"\nxzx reads and writes .SNA & .Z80 format snapshots.\n");
#else /* nec_ews */
	printf("Sorry, no help available until NEC fix their C compiler.\n");
#endif

	exit(0);
}


static void
show_version(void)
{
	printf("This is xzx v%d.%d pl%d\n", ZX_Major, ZX_Minor, ZX_Patch);
#ifndef nec_ews
	printf("Compile-time options:\n"
		   " *  xzx is built for a"
#ifdef LITTLE_ENDIAN
		   " little-endian architecture.\n"
#else
		   " big-endian architecture.\n"
#endif
#ifdef MITSHM
		   " *  MIT-SHM image transfer is possible.\n"
#endif
#ifdef JOY
		   " *  Linux analogue joystick emulation is possible.\n"
#endif
#ifdef DEV_AUDIO
		   " *  Sun Sparc-style audio emulation is possible.\n"
#endif
#ifdef PCSPKR_AUDIO
		   " *  Linux PC Speaker style audio emulation is possible.\n"
#endif
#ifdef LOAD_SAVE
		   " *  LOAD/SAVE emulation is enabled.\n"
#endif
#ifdef PSEUDO_IO
		   " *  Character input/output is emulated via ports.\n"
#endif
#ifdef SLOWDOWN
           " *  Speed control is enabled\n"
#endif
#ifdef XZX_IF1
           " *  Interface 1, microdrive & RS232 emulation are enabled.\n"
#endif
		   " *  X11 pixel to Spectrum pixel scaling factor is %d:1.\n",
	SCALING);
#endif /* nec_ews */
	exit(0);
}


static void
list_visuals(void)
{
	xzx_mesg(XZX_INFO, "currently only the default visual is supported");
}


static int
is_true(char *str)
{
	return (strncasecmp(str, "true", 4) == 0
		|| strncasecmp(str, "on", 2) == 0
		|| strncasecmp(str, "yes", 3) == 0);
}


static int
get_resource(XrmDatabase db, char *myName, char *myClass,
             char *resource, char *fallback, char *result,
             unsigned size)
{
	int i, len;
	char str_name[80], str_class[80], *str_type[10];
	XrmValue rmValue;

	sprintf(str_name, "%s.%s", myName, resource);
	sprintf(str_class, "%s.%c%s", myClass,
		isupper(*resource) ? toupper(*resource) : *resource, resource + 1);

    if (XrmGetResource(db, str_name, str_class, str_type, &rmValue) == True) {
		if (rmValue.addr == NULL) {
			len = 0;
		} else {
			len = ZX_MIN(rmValue.size, size - 1);
			strncpy(result, rmValue.addr, len);
		}
		result[len] = '\0';
		for (i = 0; i < NELEM(opts); i++) {
			if (opts[i].argKind == XrmoptionIsArg
			  && (strcmp(result, opts[i].option) == 0
			  || strcmp(result, opts[i].specifier) == 0)) {
				strncpy(result, "true", size);
				result[size - 1] = '\0';
				break;
			}
		}
		return 1;
    }
	if (fallback != NULL) {
		strncpy(result, fallback, size - 1);
		result[size - 1] = '\0';
	} else {
		result[0] = '\0';
	}
	return 0;
}


static int
get_string_resource(XrmDatabase db, char *myName, char *myClass,
			       char *resource, char *fallback, char *result,
			       unsigned size)
{
    char *src, *dst;
    int val;

	val = get_resource(db, myName, myClass, resource, fallback, result, size);
    src = dst = result;
	while ((*src & 0x7f) == *src && isgraph(*src) == 0 && *src != '\0') {
		src++;
	}
	while ((*src & 0x7f) != *src || isgraph(*src) != 0) {
		*dst++ = *src++;
	}
	*dst = '\0';

	return val;
}


static void
get_bool_resource(XrmDatabase db, char *myName, char *myClass,
			      char *resource, char *fallback, int *result)
{
    char resValue[MAX_CHARS];

	get_resource(db, myName, myClass, resource, fallback, resValue,
		sizeof resValue);
	*result = (is_true(resValue) != 0);
}


static void
get_int_resource(XrmDatabase db, char *myName, char *myClass,
			     char *resource, int fallback, int *result)
{
    char resValue[MAX_CHARS];

    if (get_resource(db, myName, myClass, resource, NULL, resValue,
		     sizeof resValue) == 0 || sscanf(resValue, "%d", result) <= 0) {
		*result = fallback;
	}
}


static void
get_file_defaults(Display *dpy, XrmDatabase *rDBptr,
                  char *myName, char *myClass)
{
    int len;
    char *ptr;
	char path[MAXPATHLEN];
    XrmDatabase		tmpDB;

	char *lang = getenv("LANG"), *home = getenv("HOME");

    sprintf(path, "%s%s", LIBDIR, myClass);
    *rDBptr = XrmGetFileDatabase(path);

#ifdef VMS
	tmpDB = XrmGetFileDatabase("SYS$LOGIN:decw$xdefaults.dat");
	XrmMergeDatabases(tmpDB, rDBptr);
	tmpDB = XrmGetFileDatabase("DECW$USER_DEFAULTS:xzx.dat");
	XrmMergeDatabases(tmpDB, rDBptr);
#else
    if (lang) {
		sprintf(path, "%s/%s/app-defaults/%s", USRLIBDIR, lang, myClass);
		if (access(path, 0) == -1) {
			sprintf(path, "%s/%s", USRLIBDIR, myClass);
		}
	} else {
		sprintf(path, "%s/%s", USRLIBDIR, myClass);
	}
	tmpDB = XrmGetFileDatabase(path);
	XrmMergeDatabases(tmpDB, rDBptr);

	if ((ptr = getenv("XUSERFILESEARCHPATH")) != NULL) {
		sprintf(path, "%s/%s", ptr, myClass);
		tmpDB = XrmGetFileDatabase(path);
		XrmMergeDatabases(tmpDB, rDBptr);
	}
    else if ((ptr = getenv("XAPPLRESDIR")) != NULL) {
		if (lang) {
			sprintf(path, "%s/%s/%s", ptr, lang, myClass);
			if (access(path, 0) == -1) {
				sprintf(path, "%s/%s", ptr, myClass);
			}
		} else {
			sprintf(path, "%s/%s", ptr, myClass);
		}
		tmpDB = XrmGetFileDatabase(path);
		XrmMergeDatabases(tmpDB, rDBptr);
    }
    else if (home) {
		if (lang) {
			sprintf(path, "%s/app-defaults/%s/%s", home, lang, myClass);
			if (access(path, 0) == -1) {
				sprintf(path, "%s/app-defaults/%s", home, myClass);
			}
		} else {
			sprintf(path, "%s/app-defaults/%s", home, myClass);
		}
		tmpDB = XrmGetFileDatabase(path);
		XrmMergeDatabases(tmpDB, rDBptr);
	}

	if ((ptr = XResourceManagerString(dpy)) != NULL) {
		tmpDB = XrmGetStringDatabase(ptr);
		XrmMergeDatabases(tmpDB, rDBptr);
	} else if (home) {
		sprintf(path, "%s/.Xdefaults", home);
		tmpDB = XrmGetFileDatabase(path);
		XrmMergeDatabases(tmpDB, rDBptr);
	}

	if ((ptr = getenv("XENVIRONMENT")) != NULL) {
		tmpDB = XrmGetFileDatabase(ptr);
		XrmMergeDatabases(tmpDB, rDBptr);
	} else if (home) {
		sprintf(path, "%s/.Xdefaults-", home);
		len = strlen(path);
		gethostname(&path[len], sizeof path - len);
		path[sizeof path - 1] = '\0';
		tmpDB = XrmGetFileDatabase(path);
		XrmMergeDatabases(tmpDB, rDBptr);
	}
#endif
}


Display *
xzx_open_display(int *argcp, char **argvp, KeySym *ks_list)
{
	int	 i;
	char *ptr;
	char *myName = "xzx", *myClass = "Xzx";
	char resValue[MAX_CHARS];
	char dispName[MAX_DISP_LEN];
	XrmDatabase	 argDB, rDB;
	Display *dpy;

    XrmInitialize();

    argDB = 0;
    XrmParseCommand(&argDB, opts, NELEM(opts), myName, argcp, argvp);

    /* check for bad arguments */
    for (i = 1; i < *argcp; i++) {
		if (argvp[i][0] == '-') {
			fprintf(stderr, "Unknown option '%s'\n", argvp[i]);
			fprintf(stderr, "Type: %s -help to see a list of options\n",
				argvp[0]);
			exit(1);
		}
	}

	if (get_resource(argDB, myName, myClass, "help", NULL, resValue,
			sizeof resValue) != 0) {
		usage();
	}

	if (get_resource(argDB, myName, myClass, "version", NULL, resValue,
			sizeof resValue) != 0) {
		show_version();
	}

	if (get_string_resource(argDB, myName, myClass, "display", NULL, dispName,
			MAX_DISP_LEN) == 0 || dispName[0] == '\0') {
#ifdef VMS
		if ((ptr = getenv("DECW$DISPLAY")) != NULL) {
#else
		if ((ptr = getenv("DISPLAY")) != NULL) {
#endif
			strncpy(dispName, ptr, MAX_DISP_LEN);
			dispName[MAX_DISP_LEN - 1] = '\0';
		} else {
#ifdef VMS
			strcpy(dispName, "::0.0");
			sprintf(dispName, "%s::0.0", host);
#else
			strcpy(dispName, ":0.0");
#endif
		}
	}

	if ((dpy = XOpenDisplay(dispName)) == NULL) {
		xzx_mesg(XZX_ERR, "can't open display '%s'", dispName);
		return(NULL);
	}

	get_resource(argDB, myName, myClass, "visual", "",
		 cblock.visual, sizeof cblock.visual);
	if (strncasecmp(cblock.visual, "supported", 4) == 0) {
		list_visuals();
		exit(0);
	}

    get_file_defaults(dpy, &rDB, myName, myClass);

    XrmMergeDatabases(argDB, &rDB);

	/* now fill in the blanks in our configuration block */
	get_bool_resource(rDB, myName, myClass, "mitshm", "true",
		&cblock.use_mitshm);
	get_bool_resource(rDB, myName, myClass, "pixmap", "false",
		&cblock.pixmaps);
	get_bool_resource(rDB, myName, myClass, "mono", "false",
		&cblock.monochrome);
	get_bool_resource(rDB, myName, myClass, "private", "false",
		&cblock.priv_cmap);
	get_bool_resource(rDB, myName, myClass, "flashing", "true",
		&cblock.flashing);

	get_int_resource(rDB, myName, myClass, "emode", DEF_EMODE, &cblock.emode);
	if (cblock.emode != 48 && cblock.emode != 128 && cblock.emode != 3) {
		xzx_mesg(XZX_WARN, "invalid emulation mode %d, using %d", cblock.emode,
			DEF_EMODE);
		cblock.emode = DEF_EMODE;
	}
	
	get_string_resource(rDB, myName, myClass, "font", DEF_FONT,
		cblock.font, sizeof(cblock.font));

	get_string_resource(rDB, myName, myClass, "geometry", "",
		cblock.geometry, sizeof(cblock.geometry));

	get_string_resource(rDB, myName, myClass, "romName", "spectrum.rom",
		cblock.rom48, sizeof(cblock.rom48));

	ptr = (char *)malloc(strlen(LIBDIR) + 3);
	sprintf(ptr, ".:%s", LIBDIR);
	get_string_resource(rDB, myName, myClass, "libDir", ptr,
		cblock.lib_dir, sizeof(cblock.lib_dir));
	free(ptr);

	get_string_resource(rDB, myName, myClass, "intStyle", "signal",
		resValue, sizeof(resValue));
	if (strcasecmp(resValue, "signal") == 0)
		SetCfg(icnt, 0);
	else
		SetCfg(icnt, 1);

	get_int_resource(rDB, myName, myClass, "iFreq", 5833, &cblock.ifreq);

	get_int_resource(rDB, myName, myClass, "rrShm", 2, &cblock.rr_shm);
	get_int_resource(rDB, myName, myClass, "rrNoshm", 6, &cblock.rr_noshm);

#ifdef SLOWDOWN
	get_int_resource(rDB, myName, myClass, "slowdown", 0, &cblock.slowdown);
#endif

#ifdef JOY
	get_bool_resource(rDB, myName, myClass, "joystick", "false",
		&cblock.use_js);
	get_int_resource(rDB, myName, myClass, "tolerance", 20,
		&cblock.js_tolerance);
	get_string_resource(rDB, myName, myClass, "joyDev", "/dev/js0",
		cblock.js_device, sizeof(cblock.js_device));
#endif

#if defined(DEV_AUDIO) || defined(PCSPKR_AUDIO)
	get_bool_resource(rDB, myName, myClass, "sound", "false",
		&cblock.use_sound);
#ifdef DEV_AUDIO
	get_string_resource(rDB, myName, myClass, "audioDev", "/dev/audio",
		cblock.audio_dev, sizeof(cblock.audio_dev));
#endif
#ifdef NAS_AUDIO
	get_string_resource(rDB, myName, myClass, "audioServer", "",
		cblock.au_serv, sizeof(cblock.au_serv));
#endif
#endif
#ifdef XBELL_AUDIO
	get_int_resource(rDB, myName, myClass, "bellVol", 50, &cblock.bell_vol);
	if (cblock.bell_vol > 100 || cblock.bell_vol < 0) {
		xzx_mesg(XZX_WARN, "bell volume out of range (setting to default 50)");
		cblock.bell_vol = 50;
	}
#endif

#ifdef XZX_IF1
	get_bool_resource(rDB, myName, myClass, "if1", "true",
		&cblock.if1_active);
	get_bool_resource(rDB, myName, myClass, "crlf", "false",
		&cblock.translate_nl);
	get_bool_resource(rDB, myName, myClass, "strcr", "false",
		&cblock.strip_nl);
	get_string_resource(rDB, myName, myClass, "if1Rom", "if1.rom",
		cblock.if1_rom, sizeof(cblock.if1_rom));

	for (i = 0; i < 8; i++) {
		char resname[3]; char resvalue[5];

		sprintf(resname, "m%d", i + 1);
		sprintf(resvalue, "MDR%d", i + 1);
		get_string_resource(rDB, myName, myClass, resname, resvalue,
			cblock.cartfiles[i], sizeof(cblock.cartfiles[i]));
	}
#endif
	
	get_string_resource(rDB, myName, myClass, "rom1280", "128-0.rom",
		cblock.rom128_0, sizeof(cblock.rom128_0));
	get_string_resource(rDB, myName, myClass, "rom1281", "128-1.rom",
		cblock.rom128_1, sizeof(cblock.rom128_1));

	get_string_resource(rDB, myName, myClass, "rompl30", "pl3-0.rom",
		cblock.rompl3_0, sizeof(cblock.rompl3_0));
	get_string_resource(rDB, myName, myClass, "rompl31", "pl3-1.rom",
		cblock.rompl3_1, sizeof(cblock.rompl3_1));
	get_string_resource(rDB, myName, myClass, "rompl32", "pl3-2.rom",
		cblock.rompl3_2, sizeof(cblock.rompl3_2));
	get_string_resource(rDB, myName, myClass, "rompl33", "pl3-3.rom",
		cblock.rompl3_3, sizeof(cblock.rompl3_3));

	get_string_resource(rDB, myName, myClass, "fda", "disk-a.dsk",
		cblock.disk_a, sizeof(cblock.disk_a));
	get_string_resource(rDB, myName, myClass, "fdb", "disk-b.dsk",
		cblock.disk_b, sizeof(cblock.disk_b));

	/* Initialise the X keysym -> Spectrum action translations */
	for (i = 0; i < NUM_KEYMAPPINGS; i++) {
		get_string_resource(rDB, myName, myClass, map_tab[i].res_name,
			map_tab[i].def_keysym, resValue, sizeof(resValue));
		ks_list[i] = XStringToKeysym(resValue);
		if (ks_list[i] == NoSymbol) {
			xzx_mesg(XZX_WARN, "unknown keysym <%s> found, using <%s>",
				resValue, map_tab[i].def_keysym);
			ks_list[i] = XStringToKeysym(map_tab[i].def_keysym);
		}
	}

#ifdef XZX_IF1
	if (cblock.if1_active && cblock.emode == 3) {
		xzx_mesg(XZX_INFO,
			"Interface I not supported by the +3, disabling");
		cblock.if1_active = 0;
	}
#endif

	/* avoid getting a BadAccess error if the remote server has MIT-SHM */
	if (GetCfg(use_mitshm) && !is_local_server(dispName)) {
		xzx_mesg(XZX_INFO,
			"MIT-SHM not possible on remote X server, disabling");
		SetCfg(use_mitshm, False);
	}

	return dpy;
}
