Commit 0bf85543 authored by Michael Long's avatar Michael Long Committed by Rob Swindell
Browse files

Improvements to linux dosemu support

The hardcoded external.bat file has been moved to a templated
/exec/external.bat which can be modified by the sysop. ENV
vars are in there to be able to customize as needed. emusetup.bat
is no longer needed, but still supported. The actual dosemu command line
is now stored in /exec/dosemulaunch.ini and can be customized for
fossil or i/o command lines. the keystroke is now only sent for i/o, and
only sent as \n instead of \r which would trigger undesired behavior in
certain programs. The above 2 files can also be placed in door dirs
to override. ansi.com has been removed as it was not needed. default
external.bat includes cmd lines for share, x00, etc. (user will still
need to provide these in xtrn/dosutils).
parent 572e4c33
$_cpu = "80486"
$_cpu_emu = "fullsim"
$_floppy_a = ""
$_cdrom = ""
$_xms = (1024)
$_ems = (1024)
$_ems_frame = (0xe000)
$_external_char_set = "cp437"
$_internal_char_set = "cp437"
$_term_updfreq = (8)
$_layout = "us"
$_rawkeyboard = (auto)
$_mouse_internal = (on)
$_mouse_dev = ""
$_joy_device = ""
$_lpt1 = ""
$_lp2 = ""
$_speaker = ""
$_sound = (off)
$_sb_dsp = ""
......@@ -98,8 +98,12 @@
; Must install install/termcap or terminfo to use the following TERM setting:
; ExternalTermANSI = ansi-bbs
ExternalTermDumb = dumb
; To change the default dosemu/doscmd path, uncomment and set:
; DOSemuPath =
; To setup the dosemu cmd path and ini:
UseDOSemu = false
DOSemuPath = /usr/bin/dosemu.bin
; leave off dir path to use ctrl dir
DOSemuConfPath = dosemu.conf
; At what size to send the current output buffer regardless of timeout
; ie: Send output whenever there are at least this many bytes waiting.
......
; This contains the command line to execute DOSEMU
;
; You can copy this file to customize for any specific external programs
; that need changes by placing a copy of this file into the external program's
; startup directory.
;
; The following substitutions will be performed on this file:
; $TERM sets 'TERM=linux' (used on events, etc.)
; $CTRLDIR = path to synchronet ctrl dir
; $NODEDIR = path to synchronet node dir
; $DOSEMUBIN = path to dosemu.bin
; $VIRTCONF = appends virtual when needed (ie fossil) (-I"serial { virtual com 1 }")
; $DOSEMUCONF = path to global dosemu conf
; $EXTBAT = batch file to execute (external.bat)
; $EXTLOG = external log (used on events)
; add -I'keystroke "\r"' if you need that behavior back
;
; for com/uart/fossil i/o external programs, put it in the global "cmd" key
; for intercept i/o programs, you can override by putting "cmd" key under [stdio] section
cmd=/usr/bin/env $TERM HOME=$CTRLDIR QUIET=1 DOSDRIVE_D=$NODEDIR NODEDIR=$NODEDIR $DOSEMUBIN -I"video { none }" $VIRTUALCONF -f$DOSEMUCONF -E$EXTBAT -o$NODEDIRdosemu_boot.log $EXTLOG
[stdio]
cmd=/usr/bin/env $TERM HOME=$CTRLDIR QUIET=1 DOSDRIVE_D=$NODEDIR NODEDIR=$NODEDIR $DOSEMUBIN -I"video { none }" -I'keystroke "\n"' $VIRTUALCONF -f$DOSEMUCONF -E$EXTBAT -o$NODEDIRdosemu_boot.log $EXTLOG
@lredir D: linux\fs$NODEDIR >NUL
@lredir E: linux\fs$XTRNDIR >NUL
@lredir F: linux\fs$CTRLDIR >NUL
@lredir G: linux\fs$DATADIR >NUL
@lredir H: linux\fs$EXECDIR >NUL
E:
REM Switch to startup dir, unless its not defined
REM If not defined, go to node dir (external editors use this)
IF "%STARTDIR%"=="" D:
IF NOT "%STARTDIR%"=="" CD %STARTDIR%
REM Optionally call emusetup.bat or put that stuff here for global (in NOEMU)
REM Looks in startup dir, then ctrl dir
IF EXIST EMUSETUP.BAT GOTO EMULOCAL
IF EXIST F:\EMUSETUP.BAT GOTO EMUGLOBAL
IF EXIST E:\DOSUTILS\NUL GOTO NOEMU
IF EXIST H:\DOSUTILS\NUL GOTO NOEMU
ECHO ERROR: No emusetup.bat in E:\%STARTDIR% or F, or DOSUTILS is missing
GOTO EXEC
:EMULOCAL
CALL EMUSETUP.BAT
GOTO EXEC
:EMUGLOBAL
CALL F:\EMUSETUP.BAT
GOTO EXEC
:NOEMU
@set PATH=%PATH%;E:\dosutils;H:\dosutils
REM fossil driver, such as x00, bnu, or dosemu fossil.com
rem IF "$RUNTYPE" == "FOSSIL" @fossil.com >NUL
rem IF "$RUNTYPE" == "FOSSIL" bnu.com /P1 /L0=11520 >NUL
IF "$RUNTYPE" == "FOSSIL" x00.exe eliminate >NUL
REM share.exe for multinode file locking
@share >NUL
GOTO EXEC
:EXEC
$CMDLINE
IF NOT "%1" == "TEST" exitemu
......@@ -28,7 +28,6 @@
# NO_X = Don't include build conio library (ciolib) for X
# NO_GTK = Don't build GTK-based sysop tools
# X_PATH = /path/to/X (if not /usr/X11R6)
# USE_DOSEMU = Set to 1 to enable Linux-DOSEMU support
# the magic bit:
MKFLAGS += MAKEFLAGS=
......@@ -131,10 +130,6 @@ ifdef X_PATH
MKFLAGS += X_PATH=$(X_PATH)
endif
ifdef USE_DOSEMU
MKFLAGS += USE_DOSEMU=$(USE_DOSEMU)
endif
# Check for GLADE
ifndef NO_GTK
ifeq ($(shell pkg-config libglade-2.0 --exists && echo YES),YES)
......
......@@ -5,11 +5,6 @@ cmake_minimum_required(VERSION 2.8.11)
INCLUDE (../build/SynchronetMacros.cmake)
INCLUDE (CheckFunctionExists)
if(UNIX)
set(SBBS_USE_DOSEMU FALSE
CACHE BOOL "Set if you intend on using dosemu on Linux"
)
endif()
set(SBBS_BUILD_JSDOCS FALSE
CACHE INTERNAL "DEVELOPER ONLY - Build only to run jsdocs.js (not a BBS)"
)
......
......@@ -11,8 +11,6 @@
# Optional build targets: dlls, utils, mono, all (default) #
#########################################################################
# $Id: GNUmakefile,v 1.248 2020/04/03 19:54:31 rswindell Exp $
PWD := $(shell pwd)
SRC_ROOT ?= ${PWD}/..
include $(SRC_ROOT)/build/Common.gmake
......@@ -43,10 +41,6 @@ ifdef PREFIX
CFLAGS += -DPREFIX=$(PREFIX)
endif
ifdef USE_DOSEMU
CFLAGS += -DUSE_DOSEMU
endif
ifdef DONT_BLAME_SYNCHRONET
CFLAGS += -DDONT_BLAME_SYNCHRONET
endif
......
......@@ -223,8 +223,11 @@ bool sbbs_t::ar_exp(const uchar **ptrptr, user_t* user, client_t* client)
result=_not;
if(startup->options&BBS_OPT_NO_DOS)
break;
#if defined(_WIN32) || (defined(__linux__) && defined(USE_DOSEMU)) || defined(__FreeBSD__)
#if defined(_WIN32) || defined(__FreeBSD__)
result=!_not;
#elif defined(__linux__)
if (startup->usedosemu)
result=!_not;
#endif
break;
case AR_WIN32:
......
......@@ -121,9 +121,6 @@ struct {
struct utsname name;
char sbbsuser[9]; /* Historical UName limit of 8 chars */
char sbbsgroup[17]; /* Can't find historical limit for group names */
#ifdef __linux__
BOOL use_dosemu;
#endif
} params; /* Build parameters */
#define MAKEFILE "/tmp/SBBSmakefile"
......@@ -230,9 +227,6 @@ int main(int argc, char **argv)
SAFECOPY(params.sbbsuser,p);
if((p=getenv("GROUP"))!=NULL)
SAFECOPY(params.sbbsgroup,p);
#ifdef __linux__
params.use_dosemu=FALSE;
#endif
sscanf("$Revision: 1.100 $", "%*s %s", revision);
umask(077);
......@@ -380,9 +374,7 @@ int main(int argc, char **argv)
sprintf(mopt[i++],"%-27.27s%s","Make Command-line",params.make_cmdline);
sprintf(mopt[i++],"%-27.27s%s","File Owner",params.sbbsuser);
sprintf(mopt[i++],"%-27.27s%s","File Group",params.sbbsgroup);
#ifdef __linux__
sprintf(mopt[i++],"%-27.27s%s","Integrate DOSEmu support",params.use_dosemu?"Yes":"No");
#endif
sprintf(mopt[i++],"%-27.27s","Start Installation...");
mopt[i][0]=0;
......@@ -488,26 +480,8 @@ int main(int argc, char **argv)
"\n";
uifc.input(WIN_MID,0,0,"",params.sbbsgroup,32,K_EDIT);
break;
#ifdef __linux__
case 11:
strcpy(opt[0],"Yes");
strcpy(opt[1],"No");
opt[2][0]=0;
i=params.use_dosemu?0:1;
uifc.helpbuf= "`Include DOSEmu Support`\n"
"\nToDo: Add help.";
i=uifc.list(WIN_MID|WIN_SAV,0,0,0,&i,0
,"Integrate DOSEmu support into Synchronet?",opt);
if(!i)
params.use_dosemu=TRUE;
else if(i==1)
params.use_dosemu=FALSE;
i=0;
break;
case 12:
#else
case 11:
#endif
install_sbbs(distlist[dist],distlist[dist]->type==LOCAL_FILE?NULL:distlist[dist]->servers[server]);
bail(0);
break;
......@@ -754,11 +728,6 @@ void install_sbbs(dist_t *dist,struct server_ent_t *server) {
sprintf(sbbsgroup,"SBBSGROUP=%s",params.sbbsgroup);
putenv(sbbsgroup);
}
#ifdef __linux__
if(params.use_dosemu==TRUE) {
putenv("USE_DOSEMU=1");
}
#endif
if(params.usebcc)
putenv("bcc=1");
......
......@@ -251,6 +251,7 @@ void sbbs_read_ini(
const char* section;
const char* default_term_ansi;
const char* default_dosemu_path;
const char* default_dosemuconf_path;
char value[INI_MAX_VALUE_LEN];
str_list_t list;
global_startup_t global_buf;
......@@ -366,10 +367,14 @@ void sbbs_read_ini(
default_dosemu_path="/usr/local/bin/doscmd";
#else
default_dosemu_path="/usr/bin/dosemu.bin";
default_dosemuconf_path="";
#endif
bbs->usedosemu=iniGetBool(list,section,"UseDOSemu",TRUE);
SAFECOPY(bbs->dosemu_path
,iniGetString(list,section,"DOSemuPath",default_dosemu_path,value));
SAFECOPY(bbs->dosemuconf_path
,iniGetString(list,section,"DOSemuConfPath",default_dosemuconf_path,value));
SAFECOPY(bbs->answer_sound
,iniGetString(list,section,strAnswerSound,nulstr,value));
......@@ -839,7 +844,10 @@ BOOL sbbs_write_ini(
break;
if(!iniSetString(lp,section,"DOSemuPath",bbs->dosemu_path,&style))
break;
if(!iniSetString(lp,section,"DOSemuConfPath",bbs->dosemuconf_path,&style))
break;
if(!iniSetBool(lp,section,"UseDOSemu",bbs->usedosemu,&style))
break;
if(!iniSetString(lp,section,strAnswerSound,bbs->answer_sound,&style))
break;
if(!iniSetString(lp,section,strHangupSound,bbs->hangup_sound,&style))
......
......@@ -113,12 +113,14 @@ typedef struct {
/* Paths */
char ctrl_dir[128];
char dosemu_path[128];
char dosemuconf_path[128];
char temp_dir[128];
char answer_sound[128];
char hangup_sound[128];
char ini_fname[128];
/* Miscellaneous */
BOOL usedosemu;
char xtrn_term_ansi[32]; /* external ANSI terminal type (e.g. "ansi-bbs") */
char xtrn_term_dumb[32]; /* external dumb terminal type (e.g. "dumb") */
char host_name[128];
......
......@@ -649,6 +649,79 @@ char* ascii_str(uchar* str)
return((char*)str);
}
char* replace_named_values(const char* src
,char* buf
,size_t buflen /* includes '\0' terminator */
,const char* escape_seq
,named_string_t* string_list
,named_int_t* int_list
,BOOL case_sensitive)
{
char val[32];
size_t i;
size_t esc_len=0;
size_t name_len;
size_t value_len;
char* p = buf;
int (*cmp)(const char*, const char*, size_t);
if(case_sensitive)
cmp=strncmp;
else
cmp=strnicmp;
if(escape_seq!=NULL)
esc_len = strlen(escape_seq);
while(*src && (size_t)(p-buf) < buflen-1) {
if(esc_len) {
if(cmp(src, escape_seq, esc_len)!=0) {
*p++ = *src++;
continue;
}
src += esc_len; /* skip the escape seq */
}
if(string_list) {
for(i=0; string_list[i].name!=NULL /* terminator */; i++) {
name_len = strlen(string_list[i].name);
if(cmp(src, string_list[i].name, name_len)==0) {
value_len = strlen(string_list[i].value);
if((p-buf)+value_len > buflen-1) /* buffer overflow? */
value_len = (buflen-1)-(p-buf); /* truncate value */
memcpy(p, string_list[i].value, value_len);
p += value_len;
src += name_len;
break;
}
}
if(string_list[i].name!=NULL) /* variable match */
continue;
}
if(int_list) {
for(i=0; int_list[i].name!=NULL /* terminator */; i++) {
name_len = strlen(int_list[i].name);
if(cmp(src, int_list[i].name, name_len)==0) {
SAFEPRINTF(val,"%d",int_list[i].value);
value_len = strlen(val);
if((p-buf)+value_len > buflen-1) /* buffer overflow? */
value_len = (buflen-1)-(p-buf); /* truncate value */
memcpy(p, val, value_len);
p += value_len;
src += name_len;
break;
}
}
if(int_list[i].name!=NULL) /* variable match */
continue;
}
*p++ = *src++;
}
*p=0; /* terminate string in destination buffer */
return(buf);
}
/****************************************************************************/
/* Condense consecutive white-space chars in a string to single spaces */
/****************************************************************************/
......
......@@ -39,6 +39,9 @@ DLLEXPORT char * remove_ctrl_a(const char* instr, char* outstr);
DLLEXPORT char ctrl_a_to_ascii_char(char code);
DLLEXPORT char * truncstr(char* str, const char* set);
DLLEXPORT char * ascii_str(uchar* str);
DLLEXPORT char * replace_named_values(const char* src ,char* buf, size_t buflen,
const char* escape_seq, named_string_t* string_list,
named_int_t* int_list, BOOL case_sensitive);
DLLEXPORT char * condense_whitespace(char* str);
DLLEXPORT char exascii_to_ascii_char(uchar ch);
DLLEXPORT BOOL findstr(const char *insearch, const char *fname);
......
......@@ -1763,7 +1763,7 @@ static BOOL ar_exp(scfg_t* cfg, uchar **ptrptr, user_t* user, client_t* client)
#endif
break;
case AR_DOS:
#if defined(_WIN32) || (defined(__linux__) && defined(USE_DOSEMU)) || defined(__FreeBSD__)
#if defined(_WIN32) || defined(__linux__) || defined(__FreeBSD__)
result=!not;
#else
result=not;
......
......@@ -1174,20 +1174,29 @@ int sbbs_t::external(const char* cmdline, long mode, const char* startup_dir)
SAFECOPY(str,fullcmdline);
sprintf(fullcmdline,"%s -F %s",startup->dosemu_path,str);
#elif defined(__linux__) && defined(USE_DOSEMU)
#elif defined(__linux__)
/* dosemu integration -- Ryan Underwood, <nemesis @ icequake.net> */
/* dosemu integration -- originally by Ryan Underwood, <nemesis @ icequake.net> */
FILE *dosemubat;
int setup_override;
FILE *dosemubatfp;
FILE *externalbatfp;
FILE *de_launch_inifp;
char tok[MAX_PATH+1];
char buf[1024];
char bufout[1024];
char cmdlinebatch[MAX_PATH+1];
char externalbatsrc[MAX_PATH+1];
char externalbat[MAX_PATH+1];
char dosemuconf[MAX_PATH+1];
char de_launch_cmd[INI_MAX_VALUE_LEN];
char dosemubinloc[MAX_PATH+1];
char virtualconf[75];
char dosterm[15];
char log_external[MAX_PATH+1];
const char* runtype;
str_list_t de_launch_ini;
/* on the Unix side. xtrndir is the parent of the door's startup dir. */
char xtrndir[MAX_PATH+1];
......@@ -1196,15 +1205,18 @@ int sbbs_t::external(const char* cmdline, long mode, const char* startup_dir)
char ctrldir_dos[MAX_PATH+1];
char datadir_dos[MAX_PATH+1];
char execdir_dos[MAX_PATH+1];
char nodedir_dos[MAX_PATH+1];
/* Default locations that can be overridden by
* the sysop in emusetup.bat */
const char nodedrive[] = DOSEMU_NODE_DRIVE;
const char xtrndrive[] = DOSEMU_XTRN_DRIVE;
const char ctrldrive[] = DOSEMU_CTRL_DRIVE;
const char datadrive[] = DOSEMU_DATA_DRIVE;
const char execdrive[] = DOSEMU_EXEC_DRIVE;
const char nodedrive[] = DOSEMU_NODE_DRIVE;
const char external_bat_fn[] = "external.bat";
const char dosemu_cnf_fn[] = "dosemu.conf";
SAFECOPY(str,startup_dir);
if(*(p=lastchar(str))=='/') /* kill trailing slash */
......@@ -1214,8 +1226,9 @@ int sbbs_t::external(const char* cmdline, long mode, const char* startup_dir)
SAFECOPY(xtrndir,str);
/* construct DOS equivalents for the unix directories */
SAFECOPY(xtrndir_dos,xtrndir);
REPLACE_CHARS(xtrndir_dos,'/','\\',p);
SAFECOPY(ctrldir_dos,cfg.ctrl_dir);
REPLACE_CHARS(ctrldir_dos,'/','\\',p);
......@@ -1234,28 +1247,52 @@ int sbbs_t::external(const char* cmdline, long mode, const char* startup_dir)
p=lastchar(execdir_dos);
if (*p=='\\') *p=0;
SAFECOPY(xtrndir_dos,xtrndir);
REPLACE_CHARS(xtrndir_dos,'/','\\',p);
SAFECOPY(nodedir_dos,cfg.node_dir);
REPLACE_CHARS(nodedir_dos,'/','\\',p);
p=lastchar(nodedir_dos);
if (*p=='\\') *p=0;
/* check for existence of a dosemu.conf in the door directory.
* It is a good idea to be able to use separate configs for each
* door. */
/* must have sbbs.ini bbs useDOSemu=1 (or empty), cannot be =0 */
if (!startup->usedosemu) {
lprintf((mode&EX_OFFLINE) ? LOG_ERR : LOG_WARNING, "DOSEMU disabled, program not run");
bprintf("Sorry, DOSEMU is not supported on this node.\r\n");
return -1;
}
sprintf(str,"%sdosemu.conf",startup_dir);
if (!fexist(str)) {
/* must have sbbs.ini bbs DOSemuPath set to valid path */
SAFECOPY(dosemubinloc,(cmdstr(startup->dosemu_path,nulstr,nulstr,tok)));
if (dosemubinloc[0] == '\0') {
lprintf((mode&EX_OFFLINE) ? LOG_ERR : LOG_WARNING, "DOSEMU invalid DOSEmuPath, program not run");
bprintf("Sorry, DOSEMU is not supported on this node.\r\n");
return -1;
}
/* If we can't find it in the door dir, look for a global one
* in the ctrl dir. */
if (!fexist(dosemubinloc)) {
lprintf((mode&EX_OFFLINE) ? LOG_ERR : LOG_WARNING, "DOSEMU not found: %s", dosemubinloc);
bprintf("Sorry, DOSEMU is not supported on this node.\r\n");
return -1;
}
sprintf(str,"%sdosemu.conf",cfg.ctrl_dir);
/* check for existence of a dosemu.conf in the door directory.
* It is a good idea to be able to use separate configs for each
* door.
*
* First check startup_dir, then check cfg.ctrl_dir
*/
SAFEPRINTF2(str,"%s%s",startup_dir, dosemu_cnf_fn);
if (!fexist(str)) {
/* If we can't find it in the door dir, look for the configured one */
SAFECOPY(str,startup->dosemuconf_path);
if (!isabspath(str)) {
SAFEPRINTF2(str,"%s%s", cfg.ctrl_dir, startup->dosemuconf_path);
}
if (!fexist(str)) {
/* If we couldn't find either, try for the system one, then
* error out. */
SAFECOPY(str,"/etc/dosemu/dosemu.conf");
/* If we couldn't find either, try for the system one, then
* error out. */
SAFEPRINTF(str,"/etc/dosemu/%s", dosemu_cnf_fn);
if (!fexist(str)) {
SAFECOPY(str,"/etc/dosemu.conf");
SAFEPRINTF(str,"/etc/%s", dosemu_cnf_fn);
if (!fexist(str)) {
errormsg(WHERE,ERR_READ,str,0);
return(-1);
......@@ -1268,144 +1305,134 @@ int sbbs_t::external(const char* cmdline, long mode, const char* startup_dir)
}
else SAFECOPY(dosemuconf,str); /* using door-specific conf */
/* same deal for emusetup.bat. */
sprintf(str,"%semusetup.bat",startup_dir);
if (!fexist(str)) {
/* If we can't find it in the door dir, look for a global one
* in the ctrl dir. */
sprintf(str,"%semusetup.bat",cfg.ctrl_dir);
if (!fexist(str)) {
/* If we couldn't find either, set an error condition. */
setup_override = -1;
}
else setup_override = 0; /* using global bat */
}
else setup_override = 1; /* using door-specific bat */
/* Create the external bat here to be placed in the node dir. */
sprintf(str,"%sexternal.bat",cfg.node_dir);
if(!(dosemubat=fopen(str,"w+"))) {
SAFEPRINTF2(str,"%s%s",cfg.node_dir,external_bat_fn);
if(!(dosemubatfp=fopen(str,"w+"))) {
errormsg(WHERE,ERR_CREATE,str,0);
return(-1);
}
fprintf(dosemubat,"@echo off\r\n");
fprintf(dosemubat,"set DSZLOG=%s\\PROTOCOL.LOG\r\n",nodedrive);
fprintf(dosemubat,"set SBBSNODE=%s\r\n",nodedrive);
fprintf(dosemubat,"set SBBSNNUM=%d\r\n",cfg.node_num);
fprintf(dosemubat,"set SBBSCTRL=%s\r\n",ctrldrive);
fprintf(dosemubat,"set SBBSDATA=%s\r\n",datadrive);
fprintf(dosemubat,"set SBBSEXEC=%s\r\n",execdrive);
fprintf(dosemubat,"set PCBNODE=%d\r\n",cfg.node_num);
fprintf(dosemubat,"set PCBDRIVE=%s\r\n",nodedrive);
fprintf(dosemubat,"set PCBDIR=\\\r\n");
// let's do this cleanly like dosemu's default autoexec.bat does -wk42
/* clear existing redirections on dos side and */
/* redirect necessary drive letters to unix paths */
fprintf(dosemubat,"unix -s DOSDRIVE_E\r\n");
fprintf(dosemubat,"if '%%DOSDRIVE_E%%' == '' goto nodriveE\r\n");
fprintf(dosemubat,"lredir del %s\r\n",xtrndrive);
fprintf(dosemubat,":nodriveE\r\n");
fprintf(dosemubat,"lredir %s linux\\fs%s\r\n",xtrndrive,xtrndir_dos);
fprintf(dosemubat,"unix -s DOSDRIVE_F\r\n");
fprintf(dosemubat,"if '%%DOSDRIVE_F%%' == '' goto nodriveF\r\n");
fprintf(dosemubat,"lredir del %s\r\n",ctrldrive);
fprintf(dosemubat,":nodriveF\r\n");
fprintf(dosemubat,"lredir %s linux\\fs%s\r\n",ctrldrive,ctrldir_dos);
fprintf(dosemubat,"unix -s DOSDRIVE_G\r\n");
fprintf(dosemubat,"if '%%DOSDRIVE_G%%' == '' goto nodriveG\r\n");
fprintf(dosemubat,"lredir del %s\r\n",datadrive);
fprintf(dosemubat,":nodriveG\r\n");
fprintf(dosemubat,"lredir %s linux\\fs%s\r\n",datadrive,datadir_dos);
fprintf(dosemubat,"unix -s DOSDRIVE_H\r\n");
fprintf(dosemubat,"if '%%DOSDRIVE_H%%' == '' goto nodriveH\r\n");
fprintf(dosemubat,"lredir del %s\r\n",execdrive);
fprintf(dosemubat,":nodriveH\r\n");
fprintf(dosemubat,"lredir %s linux\\fs%s\r\n",execdrive,execdir_dos);
/* change to the drive where the parent of the startup_dir is mounted */
fprintf(dosemubat,"%s\r\n",xtrndrive);
const char* gamedir = "";
fprintf(dosemubatfp,"@ECHO OFF\r\n");
fprintf(dosemubatfp,"SET DSZLOG=%s\\PROTOCOL.LOG\r\n",nodedrive);
fprintf(dosemubatfp,"SET SBBSNODE=%s\r\n",nodedrive);
fprintf(dosemubatfp,"SET SBBSNNUM=%d\r\n",cfg.node_num);
fprintf(dosemubatfp,"SET SBBSCTRL=%s\r\n",ctrldrive);
fprintf(dosemubatfp,"SET SBBSDATA=%s\r\n",datadrive);
fprintf(dosemubatfp,"SET SBBSEXEC=%s\r\n",execdrive);
fprintf(dosemubatfp,"SET PCBNODE=%d\r\n",cfg.node_num);