2009-05-02 23:03:37 +02:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2002 The DOSBox Team
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU Library General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdarg.h>
|
2009-05-02 23:20:05 +02:00
|
|
|
#include "setup.h"
|
2009-05-02 23:03:37 +02:00
|
|
|
#include "shell_inc.h"
|
|
|
|
|
|
|
|
Bitu call_shellstop;
|
|
|
|
|
|
|
|
static Bitu shellstop_handler(void) {
|
|
|
|
return CBRET_STOP;
|
|
|
|
}
|
|
|
|
|
2009-05-02 23:20:05 +02:00
|
|
|
static void SHELL_ProgramStart(Program * * make) {
|
|
|
|
*make=new DOS_Shell;
|
2009-05-02 23:03:37 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
#define AUTOEXEC_SIZE 4096
|
|
|
|
static char autoexec_data[AUTOEXEC_SIZE]={0};
|
|
|
|
|
|
|
|
void SHELL_AddAutoexec(char * line,...) {
|
|
|
|
char buf[2048];
|
|
|
|
va_list msg;
|
|
|
|
|
|
|
|
va_start(msg,line);
|
|
|
|
vsprintf(buf,line,msg);
|
|
|
|
va_end(msg);
|
|
|
|
|
|
|
|
size_t auto_len=strlen(autoexec_data);
|
|
|
|
if ((auto_len+strlen(line)+3)>AUTOEXEC_SIZE) {
|
|
|
|
E_Exit("SYSTEM:Autoexec.bat file overlow");
|
|
|
|
}
|
|
|
|
sprintf((autoexec_data+auto_len),"%s\r\n",buf);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-05-02 23:20:05 +02:00
|
|
|
DOS_Shell::DOS_Shell():Program(){
|
2009-05-02 23:03:37 +02:00
|
|
|
input_handle=STDIN;
|
|
|
|
echo=true;
|
|
|
|
exit=false;
|
|
|
|
bf=0;
|
|
|
|
memset(&old.buffer,0,CMD_OLDSIZE);
|
|
|
|
old.size=0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Bit32u DOS_Shell::GetRedirection(char *s, char **ifn, char **ofn) {
|
|
|
|
|
|
|
|
|
|
|
|
return 1;
|
2009-05-02 23:35:44 +02:00
|
|
|
}
|
2009-05-02 23:03:37 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void DOS_Shell::ParseLine(char * line) {
|
|
|
|
|
|
|
|
char * in=0;
|
|
|
|
char * out=0;
|
|
|
|
char * fname0=0;
|
|
|
|
char * fname1=0;
|
|
|
|
|
|
|
|
/* Check for a leading @ */
|
2009-05-02 23:27:47 +02:00
|
|
|
if (line[0]=='@') line[0]=' ';
|
2009-05-02 23:03:37 +02:00
|
|
|
line=trim(line);
|
|
|
|
Bit32u num=0; /* Number of commands in this line */
|
|
|
|
|
|
|
|
num = GetRedirection(line,&in, &out);
|
|
|
|
|
|
|
|
/* TODO in and out redirection */
|
|
|
|
|
|
|
|
DoCommand(line);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void DOS_Shell::Run(void) {
|
2009-05-02 23:20:05 +02:00
|
|
|
char input_line[CMD_MAXLINE];
|
|
|
|
std::string line;
|
2009-05-02 23:27:47 +02:00
|
|
|
|
|
|
|
if (cmd->FindStringRemain("/C",line)) {
|
2009-05-02 23:20:05 +02:00
|
|
|
strcpy(input_line,line.c_str());
|
2009-05-02 23:27:47 +02:00
|
|
|
ParseLine(input_line);
|
2009-05-02 23:03:37 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
/* Start a normal shell and check for a first command init */
|
|
|
|
WriteOut(MSG_Get("SHELL_STARTUP"));
|
2009-05-02 23:20:05 +02:00
|
|
|
if (cmd->FindString("/INIT",line,true)) {
|
|
|
|
strcpy(input_line,line.c_str());
|
|
|
|
line.erase();
|
|
|
|
ParseLine(input_line);
|
2009-05-02 23:03:37 +02:00
|
|
|
}
|
|
|
|
do {
|
|
|
|
if (bf && bf->ReadLine(input_line)) {
|
|
|
|
if (echo) {
|
|
|
|
if (input_line[0]!='@') {
|
|
|
|
ShowPrompt();
|
|
|
|
WriteOut(input_line);
|
|
|
|
WriteOut("\n");
|
|
|
|
};
|
|
|
|
};
|
|
|
|
} else {
|
|
|
|
if (echo) ShowPrompt();
|
|
|
|
InputCommand(input_line);
|
|
|
|
|
|
|
|
}
|
|
|
|
ParseLine(input_line);
|
|
|
|
if (echo) WriteOut("\n");
|
|
|
|
} while (!exit);
|
|
|
|
}
|
|
|
|
|
|
|
|
void DOS_Shell::SyntaxError(void) {
|
|
|
|
WriteOut(MSG_Get("SHELL_SYNTAXERROR"));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2009-05-02 23:20:05 +02:00
|
|
|
void AUTOEXEC_Init(Section * sec) {
|
|
|
|
MSG_Add("AUTOEXEC_CONFIGFILE_HELP","Add here the lines you want to execute on startup.\n");
|
|
|
|
/* Register a virtual AUOEXEC.BAT file */
|
|
|
|
|
|
|
|
Section_line * section=static_cast<Section_line *>(sec);
|
|
|
|
char * extra=(char *)section->data.c_str();
|
|
|
|
if (extra) SHELL_AddAutoexec(extra);
|
|
|
|
/* Check to see for extra command line options to be added */
|
|
|
|
std::string line;
|
|
|
|
while (control->cmdline->FindString("-c",line,true)) {
|
|
|
|
SHELL_AddAutoexec((char *)line.c_str());
|
|
|
|
}
|
|
|
|
/* Check for first command being a directory or file */
|
|
|
|
char buffer[CROSS_LEN];
|
|
|
|
if (control->cmdline->FindCommand(1,line)) {
|
|
|
|
struct stat test;
|
|
|
|
strcpy(buffer,line.c_str());
|
|
|
|
if (stat(buffer,&test)) {
|
|
|
|
getcwd(buffer,CROSS_LEN);
|
|
|
|
strcat(buffer,line.c_str());
|
|
|
|
if (stat(buffer,&test)) goto nomount;
|
|
|
|
}
|
|
|
|
if (test.st_mode & S_IFDIR) {
|
2009-05-02 23:35:44 +02:00
|
|
|
SHELL_AddAutoexec("MOUNT C \"%s\"",buffer);
|
2009-05-02 23:20:05 +02:00
|
|
|
SHELL_AddAutoexec("C:");
|
|
|
|
} else {
|
|
|
|
char * name=strrchr(buffer,CROSS_FILESPLIT);
|
|
|
|
if (!name) goto nomount;
|
|
|
|
*name++=0;
|
|
|
|
if (access(buffer,F_OK)) goto nomount;
|
2009-05-02 23:35:44 +02:00
|
|
|
SHELL_AddAutoexec("MOUNT C \"%s\"",buffer);
|
2009-05-02 23:20:05 +02:00
|
|
|
SHELL_AddAutoexec("C:");
|
|
|
|
SHELL_AddAutoexec(name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
nomount:
|
|
|
|
VFILE_Register("AUTOEXEC.BAT",(Bit8u *)autoexec_data,strlen(autoexec_data));
|
|
|
|
}
|
|
|
|
|
|
|
|
static char * path_string="PATH=Z:\\";
|
|
|
|
static char * comspec_string="COMSPEC=Z:\\COMMAND.COM";
|
|
|
|
static char * full_name="Z:\\COMMAND.COM";
|
|
|
|
static char * init_line="/INIT AUTOEXEC.BAT";
|
2009-05-02 23:03:37 +02:00
|
|
|
|
|
|
|
void SHELL_Init() {
|
2009-05-02 23:20:05 +02:00
|
|
|
/* Add messages */
|
2009-05-02 23:27:47 +02:00
|
|
|
MSG_Add("SHELL_ILLEGAL_PATH","Illegal Path\n");
|
2009-05-02 23:20:05 +02:00
|
|
|
MSG_Add("SHELL_CMD_HELP","supported commands are:\n");
|
|
|
|
MSG_Add("SHELL_CMD_ECHO_ON","ECHO is on\n");
|
|
|
|
MSG_Add("SHELL_CMD_ECHO_OFF","ECHO is off\n");
|
|
|
|
MSG_Add("SHELL_ILLEGAL_SWITCH","Illegal switch: %s\n");
|
|
|
|
MSG_Add("SHELL_CMD_CHDIR_ERROR","Unable to change to: %s\n");
|
|
|
|
MSG_Add("SHELL_CMD_MKDIR_ERROR","Unable to make: %s\n");
|
2009-05-02 23:27:47 +02:00
|
|
|
MSG_Add("SHELL_CMD_RMDIR_ERROR","Unable to remove: %s\n");
|
2009-05-02 23:35:44 +02:00
|
|
|
MSG_Add("SHELL_CMD_DEL_ERROR","Unable to delete: %s\n");
|
2009-05-02 23:20:05 +02:00
|
|
|
MSG_Add("SHELL_SYNTAXERROR","The syntax of the command is incorrect.\n");
|
|
|
|
MSG_Add("SHELL_CMD_SET_NOT_SET","Environment variable %s not defined\n");
|
|
|
|
MSG_Add("SHELL_CMD_SET_OUT_OF_SPACE","Not enough environment space left.\n");
|
|
|
|
MSG_Add("SHELL_CMD_IF_EXIST_MISSING_FILENAME","IF EXIST: Missing filename.\n");
|
|
|
|
MSG_Add("SHELL_CMD_IF_ERRORLEVEL_MISSING_NUMBER","IF ERRORLEVEL: Missing number.\n");
|
|
|
|
MSG_Add("SHELL_CMD_IF_ERRORLEVEL_INVALID_NUMBER","IF ERRORLEVEL: Invalid number.\n");
|
|
|
|
MSG_Add("SHELL_CMD_GOTO_MISSING_LABEL","No label supplied to GOTO command.\n");
|
|
|
|
MSG_Add("SHELL_CMD_GOTO_LABEL_NOT_FOUND","GOTO: Label %s not found.\n");
|
|
|
|
MSG_Add("SHELL_CMD_FILE_NOT_FOUND","File %s not found.\n");
|
|
|
|
MSG_Add("SHELL_CMD_FILE_EXISTS","File %s already exists.\n");
|
|
|
|
MSG_Add("SHELL_CMD_DIR_INTRO","Directory of %s.\n");
|
|
|
|
MSG_Add("SHELL_CMD_DIR_BYTES_USED","%5d File(s) %17s Bytes\n");
|
|
|
|
MSG_Add("SHELL_CMD_DIR_BYTES_FREE","%5d Dir(s) %17s Bytes free\n");
|
|
|
|
MSG_Add("SHELL_EXECUTE_DRIVE_NOT_FOUND","Drive %c does not exist!\n");
|
|
|
|
MSG_Add("SHELL_EXECUTE_ILLEGAL_COMMAND","Illegal command: %s.\n");
|
2009-05-02 23:35:44 +02:00
|
|
|
MSG_Add("SHELL_CMD_PAUSE","Press any key to continue.\n");
|
|
|
|
MSG_Add("SHELL_CMD_PAUSE_HELP","Waits for 1 keystroke to continue.\n");
|
|
|
|
MSG_Add("SHELL_CMD_COPY_FAILURE","Copy failure : %s.\n");
|
|
|
|
MSG_Add("SHELL_CMD_COPY_SUCCESS"," %d File(s) copied.\n");
|
2009-05-02 23:27:47 +02:00
|
|
|
|
|
|
|
MSG_Add("SHELL_STARTUP","DOSBox Shell v" VERSION "\n"
|
2009-05-02 23:35:44 +02:00
|
|
|
"DOSBox does not run protected mode games!\n"
|
2009-05-02 23:27:47 +02:00
|
|
|
"For supported shell commands type: HELP\n"
|
2009-05-02 23:35:44 +02:00
|
|
|
"For a short introduction type: INTRO\n\n"
|
2009-05-02 23:27:47 +02:00
|
|
|
"For more information read the README file in DOSBox directory.\n"
|
|
|
|
"\nHAVE FUN!\nThe DOSBox Team\n\n"
|
|
|
|
);
|
|
|
|
|
2009-05-02 23:20:05 +02:00
|
|
|
MSG_Add("SHELL_CMD_CHDIR_HELP","Change Directory.\n");
|
|
|
|
MSG_Add("SHELL_CMD_CLS_HELP","Clear screen.\n");
|
|
|
|
MSG_Add("SHELL_CMD_DIR_HELP","Directory View.\n");
|
|
|
|
MSG_Add("SHELL_CMD_ECHO_HELP","Display messages and enable/disable command echoing.\n");
|
|
|
|
MSG_Add("SHELL_CMD_EXIT_HELP","Exit from the shell.\n");
|
|
|
|
MSG_Add("SHELL_CMD_HELP_HELP","Show help.\n");
|
|
|
|
MSG_Add("SHELL_CMD_MKDIR_HELP","Make Directory.\n");
|
|
|
|
MSG_Add("SHELL_CMD_RMDIR_HELP","Remove Directory.\n");
|
|
|
|
MSG_Add("SHELL_CMD_SET_HELP","Change environment variables.\n");
|
|
|
|
MSG_Add("SHELL_CMD_IF_HELP","Performs conditional processing in batch programs.\n");
|
|
|
|
MSG_Add("SHELL_CMD_GOTO_HELP","Jump to a labeled line in a batch script.\n");
|
|
|
|
MSG_Add("SHELL_CMD_TYPE_HELP","Display the contents of a text-file.\n");
|
|
|
|
MSG_Add("SHELL_CMD_REM_HELP","Add comments in a batch file.\n");
|
2009-05-02 23:27:47 +02:00
|
|
|
MSG_Add("SHELL_CMD_NO_WILD","This is a simple version of the command, no wildcards allowed!\n");
|
|
|
|
MSG_Add("SHELL_CMD_RENAME_HELP","Renames files.\n");
|
|
|
|
MSG_Add("SHELL_CMD_DELETE_HELP","Removes files.\n");
|
2009-05-02 23:35:44 +02:00
|
|
|
MSG_Add("SHELL_CMD_COPY_HELP","Copy files.\n");
|
|
|
|
MSG_Add("SHELL_CMD_INTRO_HELP","Gives an introduction into dosbox\n");
|
2009-05-02 23:20:05 +02:00
|
|
|
/* Regular startup */
|
2009-05-02 23:03:37 +02:00
|
|
|
call_shellstop=CALLBACK_Allocate();
|
2009-05-02 23:27:47 +02:00
|
|
|
/* Setup the startup CS:IP to kill the last running machine when exitted */
|
|
|
|
RealPt newcsip=CALLBACK_RealPointer(call_shellstop);
|
|
|
|
SegSet16(cs,RealSeg(newcsip));
|
|
|
|
reg_ip=RealOff(newcsip);
|
2009-05-02 23:20:05 +02:00
|
|
|
|
2009-05-02 23:03:37 +02:00
|
|
|
CALLBACK_Setup(call_shellstop,shellstop_handler,CB_IRET);
|
|
|
|
PROGRAMS_MakeFile("COMMAND.COM",SHELL_ProgramStart);
|
2009-05-02 23:20:05 +02:00
|
|
|
|
2009-05-02 23:03:37 +02:00
|
|
|
/* Now call up the shell for the first time */
|
2009-05-02 23:20:05 +02:00
|
|
|
Bit16u psp_seg=DOS_GetMemory(16+1)+1;
|
|
|
|
Bit16u env_seg=DOS_GetMemory(1+(4096/16))+1;
|
2009-05-02 23:12:18 +02:00
|
|
|
Bit16u stack_seg=DOS_GetMemory(2048/16);
|
|
|
|
SegSet16(ss,stack_seg);
|
|
|
|
reg_sp=2046;
|
2009-05-02 23:20:05 +02:00
|
|
|
/* Setup MCB and the environment */
|
2009-05-02 23:35:44 +02:00
|
|
|
DOS_MCB envmcb((Bit16u)(env_seg-1));
|
|
|
|
envmcb.SetPSPSeg(psp_seg);
|
|
|
|
envmcb.SetSize(4096/16);
|
|
|
|
|
2009-05-02 23:20:05 +02:00
|
|
|
PhysPt env_write=PhysMake(env_seg,0);
|
|
|
|
MEM_BlockWrite(env_write,path_string,strlen(path_string)+1);
|
|
|
|
env_write+=strlen(path_string)+1;
|
|
|
|
MEM_BlockWrite(env_write,comspec_string,strlen(comspec_string)+1);
|
|
|
|
env_write+=strlen(comspec_string)+1;
|
|
|
|
mem_writeb(env_write++,0);
|
|
|
|
mem_writew(env_write,1);
|
|
|
|
env_write+=2;
|
|
|
|
MEM_BlockWrite(env_write,full_name,strlen(full_name)+1);
|
|
|
|
|
|
|
|
DOS_PSP psp(psp_seg);
|
|
|
|
psp.MakeNew(0);
|
|
|
|
psp.SetFileHandle(STDIN ,DOS_FindDevice("CON"));
|
|
|
|
psp.SetFileHandle(STDOUT,DOS_FindDevice("CON"));
|
|
|
|
psp.SetFileHandle(STDERR,DOS_FindDevice("CON"));
|
|
|
|
psp.SetFileHandle(STDAUX,DOS_FindDevice("CON"));
|
|
|
|
psp.SetFileHandle(STDNUL,DOS_FindDevice("CON"));
|
|
|
|
psp.SetFileHandle(STDPRN,DOS_FindDevice("CON"));
|
|
|
|
psp.SetParent(psp_seg);
|
|
|
|
/* Set the environment */
|
|
|
|
psp.SetEnvironment(env_seg);
|
|
|
|
/* Set the command line for the shell start up */
|
|
|
|
CommandTail tail;
|
|
|
|
tail.count=strlen(init_line);
|
|
|
|
strcpy(tail.buffer,init_line);
|
|
|
|
MEM_BlockWrite(PhysMake(psp_seg,128),&tail,128);
|
2009-05-02 23:03:37 +02:00
|
|
|
/* Setup internal DOS Variables */
|
2009-05-02 23:20:05 +02:00
|
|
|
dos.dta=psp.GetDTA();
|
2009-05-02 23:03:37 +02:00
|
|
|
dos.psp=psp_seg;
|
2009-05-02 23:20:05 +02:00
|
|
|
|
|
|
|
Program * new_program;
|
|
|
|
SHELL_ProgramStart(&new_program);
|
|
|
|
new_program->Run();
|
|
|
|
delete new_program;
|
2009-05-02 23:03:37 +02:00
|
|
|
}
|