First CVS upload.
Imported-from: https://svn.code.sf.net/p/dosbox/code-0/dosbox/trunk@80
This commit is contained in:
parent
7d1ca9bdd4
commit
42e5d0b779
158 changed files with 42940 additions and 0 deletions
4
src/shell/Makefile.am
Normal file
4
src/shell/Makefile.am
Normal file
|
@ -0,0 +1,4 @@
|
|||
AM_CPPFLAGS = -I$(top_srcdir)/include
|
||||
|
||||
noinst_LIBRARIES = libshell.a
|
||||
libshell_a_SOURCES = shell.cpp shell_batch.cpp shell_cmds.cpp shell_inc.h shell_misc.cpp
|
177
src/shell/shell.cpp
Normal file
177
src/shell/shell.cpp
Normal file
|
@ -0,0 +1,177 @@
|
|||
/*
|
||||
* 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>
|
||||
#include "shell_inc.h"
|
||||
|
||||
Bitu call_shellstop;
|
||||
|
||||
static Bitu shellstop_handler(void) {
|
||||
return CBRET_STOP;
|
||||
}
|
||||
|
||||
static void SHELL_ProgramStart(PROGRAM_Info * info) {
|
||||
DOS_Shell * tempshell=new DOS_Shell(info);
|
||||
tempshell->Run();
|
||||
delete tempshell;
|
||||
}
|
||||
|
||||
#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);
|
||||
}
|
||||
|
||||
|
||||
DOS_Shell::DOS_Shell(PROGRAM_Info * info):Program(info) {
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void DOS_Shell::ParseLine(char * line) {
|
||||
|
||||
char * in=0;
|
||||
char * out=0;
|
||||
char * fname0=0;
|
||||
char * fname1=0;
|
||||
|
||||
/* Check for a leading @ */
|
||||
if (line[0]=='@') line[0]=' ';
|
||||
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) {
|
||||
/* Check for a direct Command */
|
||||
if (strncasecmp(prog_info->cmd_line,"/C ",3)==0) {
|
||||
ParseLine(prog_info->cmd_line+3);
|
||||
return;
|
||||
}
|
||||
/* Start a normal shell and check for a first command init */
|
||||
WriteOut(MSG_Get("SHELL_STARTUP"));
|
||||
char input_line[CMD_MAXLINE];
|
||||
if (strncasecmp(prog_info->cmd_line,"/INIT ",6)==0) {
|
||||
ParseLine(prog_info->cmd_line+6);
|
||||
}
|
||||
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"));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void SHELL_Init() {
|
||||
call_shellstop=CALLBACK_Allocate();
|
||||
CALLBACK_Setup(call_shellstop,shellstop_handler,CB_IRET);
|
||||
PROGRAMS_MakeFile("COMMAND.COM",SHELL_ProgramStart);
|
||||
/* Now call up the shell for the first time */
|
||||
Bit16u psp_seg=DOS_GetMemory(16);
|
||||
Bit16u env_seg=DOS_GetMemory(1+(4096/16));
|
||||
/* Setup a fake MCB for the environment */
|
||||
MCB * env_mcb=(MCB *)real_host(env_seg,0);
|
||||
env_mcb->psp_segment=psp_seg;
|
||||
env_mcb->size=4096/16;
|
||||
real_writed(env_seg+1,0,0);
|
||||
|
||||
PSP * psp=(PSP *)real_host(psp_seg,0);
|
||||
Bit32u i;
|
||||
for (i=0;i<20;i++) psp->files[i]=0xff;
|
||||
psp->files[STDIN]=DOS_FindDevice("CON");
|
||||
psp->files[STDOUT]=DOS_FindDevice("CON");
|
||||
psp->files[STDERR]=DOS_FindDevice("CON");
|
||||
psp->files[STDAUX]=DOS_FindDevice("CON");
|
||||
psp->files[STDNUL]=DOS_FindDevice("CON");
|
||||
psp->files[STDPRN]=DOS_FindDevice("CON");
|
||||
psp->max_files=20;
|
||||
psp->file_table=RealMake(psp_seg,offsetof(PSP,files));
|
||||
/* Save old DTA in psp */
|
||||
psp->dta=dos.dta;
|
||||
psp->environment=env_seg+1;
|
||||
|
||||
/* Setup internal DOS Variables */
|
||||
dos.dta=RealMake(psp_seg,0x80);
|
||||
dos.psp=psp_seg;
|
||||
PROGRAM_Info info;
|
||||
strcpy(info.full_name,"Z:\\COMMAND.COM");
|
||||
info.psp_seg=psp_seg;
|
||||
MEM_BlockRead(real_phys(dos.psp,0),&info.psp_copy,sizeof(PSP));
|
||||
char line[256];
|
||||
strcpy(line,"/INIT Z:\\AUTOEXEC.BAT");
|
||||
info.cmd_line=line;
|
||||
|
||||
/* Handle the last AUTOEXEC.BAT Setup stuff */
|
||||
VFILE_Register("AUTOEXEC.BAT",(Bit8u *)autoexec_data,strlen(autoexec_data));
|
||||
SHELL_ProgramStart(&info);
|
||||
}
|
124
src/shell/shell_batch.cpp
Normal file
124
src/shell/shell_batch.cpp
Normal file
|
@ -0,0 +1,124 @@
|
|||
/*
|
||||
* 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 <string.h>
|
||||
|
||||
#include "shell_inc.h"
|
||||
#include "cpu.h"
|
||||
|
||||
|
||||
BatchFile::BatchFile(DOS_Shell * host,char * name, char * cmd_line) {
|
||||
/* Go through the command line */
|
||||
char * cmd_write=cmd_buffer;
|
||||
prev=host->bf;
|
||||
echo=host->echo;
|
||||
shell=host;
|
||||
cmd_count=0;
|
||||
while (*cmd_line || (cmd_count<CMD_MAXCMDS)) {
|
||||
cmd_words[cmd_count]=cmd_write;
|
||||
for (;(*cmd_line!=' ' && *cmd_line!=0);*cmd_write++=*cmd_line++);
|
||||
*cmd_write++=0;
|
||||
cmd_line=trim(cmd_line);
|
||||
cmd_count++;
|
||||
}
|
||||
if (!DOS_OpenFile(name,0,&file_handle)) {
|
||||
//TODO Come up with something better
|
||||
E_Exit("SHELL:Can't open BatchFile");
|
||||
}
|
||||
line_count=0;
|
||||
};
|
||||
|
||||
BatchFile::~BatchFile() {
|
||||
DOS_CloseFile(file_handle);
|
||||
shell->bf=prev;
|
||||
shell->echo=echo;
|
||||
}
|
||||
|
||||
bool BatchFile::ReadLine(char * line) {
|
||||
Bit8u c;Bit16u n;
|
||||
char temp[CMD_MAXLINE];
|
||||
emptyline:
|
||||
char * cmd_write=temp;
|
||||
do {
|
||||
n=1;
|
||||
DOS_ReadFile(file_handle,&c,&n);
|
||||
if (n>0) {
|
||||
if (c>31)
|
||||
*cmd_write++=c;
|
||||
}
|
||||
} while (c!='\n' && n);
|
||||
*cmd_write++=0;
|
||||
if (!n) {
|
||||
delete this;
|
||||
return false;
|
||||
}
|
||||
if (!strlen(temp)) goto emptyline;
|
||||
if (temp[0]==':') goto emptyline;
|
||||
/* Now parse the line read from the bat file for % stuff */
|
||||
cmd_write=line;
|
||||
char * cmd_read=temp;
|
||||
char env_name[256];char * env_write;
|
||||
while (*cmd_read) {
|
||||
env_write=env_name;
|
||||
if (*cmd_read=='%') {
|
||||
cmd_read++;
|
||||
/* Find the fullstring of this */
|
||||
|
||||
|
||||
continue;
|
||||
|
||||
} else {
|
||||
*cmd_write++=*cmd_read++;
|
||||
}
|
||||
*cmd_write=0;
|
||||
}
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
|
||||
bool BatchFile::Goto(char * where) {
|
||||
Bit32u pos=0;
|
||||
char cmd[CMD_MAXLINE];
|
||||
char * cmd_write;
|
||||
DOS_SeekFile(file_handle,&pos,DOS_SEEK_SET);
|
||||
|
||||
/* Scan till we have a match or return false*/
|
||||
Bit8u c;Bit16u n;
|
||||
again:
|
||||
cmd_write=cmd;
|
||||
do {
|
||||
n=1;
|
||||
DOS_ReadFile(file_handle,&c,&n);
|
||||
if (n>0) {
|
||||
if (c>31)
|
||||
*cmd_write++=c;
|
||||
}
|
||||
} while (c!='\n' && n);
|
||||
*cmd_write++=0;
|
||||
if (cmd[0]==':') {
|
||||
if (strcasecmp(cmd+1,where)==0) return true;
|
||||
}
|
||||
if (!n) {
|
||||
delete this;
|
||||
return false;
|
||||
}
|
||||
goto again;
|
||||
return false;
|
||||
};
|
380
src/shell/shell_cmds.cpp
Normal file
380
src/shell/shell_cmds.cpp
Normal file
|
@ -0,0 +1,380 @@
|
|||
/*
|
||||
* 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 <string.h>
|
||||
|
||||
#include "shell_inc.h"
|
||||
#include "callback.h"
|
||||
#include "regs.h"
|
||||
|
||||
|
||||
|
||||
static SHELL_Cmd cmd_list[]={
|
||||
"CD", 0, &DOS_Shell::CMD_CHDIR, "Change Directory.",
|
||||
"CLS", 0, &DOS_Shell::CMD_CLS, "Clear screen.",
|
||||
// "COPY", 0, &DOS_Shell::CMD_COPY, "Copy Files.",
|
||||
"DIR", 0, &DOS_Shell::CMD_DIR, "Directory View.",
|
||||
"ECHO", 0, &DOS_Shell::CMD_ECHO, "Display messages and enable/disable command echoing.",
|
||||
"EXIT", 0, &DOS_Shell::CMD_EXIT, "Exit from the shell.",
|
||||
"HELP", 0, &DOS_Shell::CMD_HELP, "Show help.",
|
||||
"MD", 0, &DOS_Shell::CMD_MKDIR, "Make Directory.",
|
||||
"RD", 0, &DOS_Shell::CMD_RMDIR, "Remove Directory.",
|
||||
"SET", 0, &DOS_Shell::CMD_SET, "Change environment variables.",
|
||||
"IF", 0, &DOS_Shell::CMD_IF, "Performs conditional processing in batch programs.",
|
||||
"GOTO", 0, &DOS_Shell::CMD_GOTO, "Jump to a labeled line in a batch script.",
|
||||
"TYPE", 0, &DOS_Shell::CMD_TYPE, "Display the contents of a text-file.",
|
||||
/*
|
||||
"CHDIR", 0, &DOS_Shell::CMD_CHDIR, "Change Directory",
|
||||
"MKDIR", 0, &DOS_Shell::CMD_MKDIR, "Make Directory",
|
||||
"RMDIR", 0, &DOS_Shell::CMD_RMDIR, "Remove Directory",
|
||||
*/
|
||||
0,0,0,0
|
||||
};
|
||||
|
||||
void DOS_Shell::DoCommand(char * line) {
|
||||
/* First split the line into command and arguments */
|
||||
line=trim(line);
|
||||
char cmd[255];
|
||||
char * cmd_write=cmd;
|
||||
while (*line) {
|
||||
if (*line==32) break;
|
||||
if (*line=='/') break;
|
||||
*cmd_write++=*line++;
|
||||
}
|
||||
*cmd_write=0;
|
||||
if (strlen(cmd)==0) return;
|
||||
line=trim(line);
|
||||
/* Check the internal list */
|
||||
Bit32u cmd_index=0;
|
||||
while (cmd_list[cmd_index].name) {
|
||||
if (strcasecmp(cmd_list[cmd_index].name,cmd)==0) {
|
||||
//TODO CHECK Flags
|
||||
(this->*(cmd_list[cmd_index].handler))(line);
|
||||
return;
|
||||
}
|
||||
cmd_index++;
|
||||
}
|
||||
/* This isn't an internal command execute it */
|
||||
Execute(cmd,line);
|
||||
}
|
||||
|
||||
|
||||
void DOS_Shell::CMD_CLS(char * args) {
|
||||
reg_ax=0x0003;
|
||||
CALLBACK_RunRealInt(0x10);
|
||||
};
|
||||
|
||||
void DOS_Shell::CMD_HELP(char * args){
|
||||
/* Print the help */
|
||||
WriteOut(MSG_Get("SHELL_CMD_HELP"));
|
||||
Bit32u cmd_index=0;
|
||||
while (cmd_list[cmd_index].name) {
|
||||
if (!cmd_list[cmd_index].flags) WriteOut("%-8s %s\n",cmd_list[cmd_index].name,cmd_list[cmd_index].help);
|
||||
cmd_index++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void DOS_Shell::CMD_ECHO(char * args) {
|
||||
if (!*args) {
|
||||
if (echo) { WriteOut(MSG_Get("SHELL_CMD_ECHO_ON"));}
|
||||
else { WriteOut(MSG_Get("SHELL_CMD_ECHO_OFF"));}
|
||||
return;
|
||||
}
|
||||
if (strcasecmp(args,"OFF")==0) {
|
||||
echo=false;
|
||||
return;
|
||||
}
|
||||
if (strcasecmp(args,"ON")==0) {
|
||||
echo=true;
|
||||
return;
|
||||
}
|
||||
WriteOut("%s\n",args);
|
||||
};
|
||||
|
||||
void DOS_Shell::CMD_EXIT(char * args) {
|
||||
exit=true;
|
||||
};
|
||||
|
||||
void DOS_Shell::CMD_CHDIR(char * args) {
|
||||
if (!*args) {
|
||||
Bit8u drive=DOS_GetDefaultDrive()+'A';
|
||||
Bit8u dir[DOS_PATHLENGTH];
|
||||
DOS_GetCurrentDir(0,dir);
|
||||
WriteOut("%c:\\%s\n",drive,dir);
|
||||
}
|
||||
if (DOS_ChangeDir(args)) {
|
||||
|
||||
} else {
|
||||
WriteOut(MSG_Get("SHELL_CMD_CHDIR_ERROR"),args);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
void DOS_Shell::CMD_MKDIR(char * args) {
|
||||
char * rem=ScanCMDRemain(args);
|
||||
if (rem) {
|
||||
WriteOut(MSG_Get("SHELL_ILLEGAL_SWITCH"),rem);
|
||||
return;
|
||||
}
|
||||
if (!DOS_MakeDir(args)) {
|
||||
WriteOut(MSG_Get("SHELL_CMD_MKDIR_ERROR"),args);
|
||||
}
|
||||
};
|
||||
|
||||
void DOS_Shell::CMD_RMDIR(char * args) {
|
||||
char * rem=ScanCMDRemain(args);
|
||||
if (rem) {
|
||||
WriteOut(MSG_Get("SHELL_ILLEGAL_SWITCH"),rem);
|
||||
return;
|
||||
}
|
||||
if (!DOS_RemoveDir(args)) {
|
||||
WriteOut(MSG_Get("SHELL_CMD_RMDIR_ERROR"),args);
|
||||
}
|
||||
};
|
||||
|
||||
static void FormatNumber(Bit32u num,char * buf) {
|
||||
Bit32u numm,numk,numb;
|
||||
numb=num % 1000;
|
||||
num/=1000;
|
||||
numk=num % 1000;
|
||||
num/=1000;
|
||||
numm=num;
|
||||
if (numm) {
|
||||
sprintf(buf,"%d,%03d,%03d",numm,numk,numb);
|
||||
return;
|
||||
};
|
||||
if (numk) {
|
||||
sprintf(buf,"%d,%03d",numk,numb);
|
||||
return;
|
||||
};
|
||||
sprintf(buf,"%d",numb);
|
||||
}
|
||||
|
||||
void DOS_Shell::CMD_DIR(char * args) {
|
||||
char numformat[16];
|
||||
char path[DOS_PATHLENGTH];
|
||||
|
||||
bool optW=ScanCMDBool(args,"W");
|
||||
bool optS=ScanCMDBool(args,"S");
|
||||
bool optP=ScanCMDBool(args,"P");
|
||||
char * rem=ScanCMDRemain(args);
|
||||
if (rem) {
|
||||
WriteOut(MSG_Get("SHELL_ILLEGAL_SWITCH"),rem);
|
||||
return;
|
||||
}
|
||||
|
||||
Bit32u byte_count,file_count,dir_count;
|
||||
Bit32u w_count=0;
|
||||
byte_count=file_count=dir_count=0;
|
||||
|
||||
if (strlen(args)==0) args="*.*";
|
||||
|
||||
/* Make a full path in the args */
|
||||
if (!DOS_Canonicalize(args,(Bit8u*)path)) {
|
||||
WriteOut(MSG_Get("SHELL_CMD_DIR_PATH_ERROR"));
|
||||
return;
|
||||
}
|
||||
*(strrchr(path,'\\')+1)=0;
|
||||
WriteOut(MSG_Get("SHELL_CMD_DIR_INTRO"),path);
|
||||
|
||||
DTA_FindBlock * dta;
|
||||
dta=(DTA_FindBlock *)Real2Host(dos.dta);
|
||||
bool ret=DOS_FindFirst(args,0xffff);
|
||||
if (!ret) {
|
||||
WriteOut(MSG_Get("SHELL_CMD_FILE_NOT_FOUND"),args);
|
||||
return;
|
||||
}
|
||||
|
||||
while (ret) {
|
||||
|
||||
/* File name and extension */
|
||||
char * ext="";
|
||||
if (!optW && (*dta->name != '.')) {
|
||||
ext = strrchr(dta->name, '.');
|
||||
if (!ext) ext = "";
|
||||
else *ext++ = '\0';
|
||||
};
|
||||
|
||||
Bit8u day = dta->date & 0x001f;
|
||||
Bit8u month = (dta->date >> 5) & 0x000f;
|
||||
Bit8u hour = dta->time >> 5 >> 6;
|
||||
Bit8u minute = (dta->time >> 5) & 0x003f;
|
||||
Bit16u year = (dta->date >> 9) + 1980;
|
||||
|
||||
/* output the file */
|
||||
if (dta->attr & DOS_ATTR_DIRECTORY) {
|
||||
if (optW) {
|
||||
WriteOut("[%s]",dta->name);
|
||||
for (Bitu i=14-strlen(dta->name);i>0;i--) WriteOut(" ");
|
||||
} else {
|
||||
WriteOut("%-8s %-3s %-16s %02d-%02d-%04d %2d:%02d\n",dta->name,ext,"<DIR>",day,month,year,hour,minute);
|
||||
}
|
||||
dir_count++;
|
||||
} else {
|
||||
if (optW) {
|
||||
WriteOut("%-16s",dta->name);
|
||||
} else {
|
||||
FormatNumber(dta->size,numformat);
|
||||
WriteOut("%-8s %-3s %16s %02d-%02d-%04d %2d:%02d\n",dta->name,ext,numformat,day,month,year,hour,minute);
|
||||
}
|
||||
file_count++;
|
||||
byte_count+=dta->size;
|
||||
}
|
||||
if (optW) {
|
||||
w_count++;
|
||||
}
|
||||
ret=DOS_FindNext();
|
||||
}
|
||||
if (optW) {
|
||||
if (w_count%5) WriteOut("\n");
|
||||
}
|
||||
/* Show the summary of results */
|
||||
FormatNumber(byte_count,numformat);
|
||||
WriteOut(MSG_Get("SHELL_CMD_DIR_BYTES_USED"),file_count,numformat);
|
||||
//TODO Free Space
|
||||
FormatNumber(1024*1024*100,numformat);
|
||||
WriteOut(MSG_Get("SHELL_CMD_DIR_BYTES_FREE"),dir_count,numformat);
|
||||
}
|
||||
|
||||
void DOS_Shell::CMD_COPY(char * args) {
|
||||
char * rem=ScanCMDRemain(args);
|
||||
if (rem) {
|
||||
WriteOut(MSG_Get("SHELL_ILLEGAL_SWITCH"),rem);
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void DOS_Shell::CMD_SET(char * args) {
|
||||
if (!*args) {
|
||||
/* No command line show all environment lines */
|
||||
Bit32u count=GetEnvCount();
|
||||
for (Bit32u a=0;a<count;a++) {
|
||||
WriteOut("%s\n",GetEnvNum(a));
|
||||
}
|
||||
return;
|
||||
}
|
||||
char * p=strpbrk(args, "=");
|
||||
if (!p) {
|
||||
p=GetEnvStr(args);
|
||||
if (p) WriteOut("%s\n",p);
|
||||
else WriteOut(MSG_Get("SHELL_CMD_SET_NOT_SET"),args);
|
||||
} else {
|
||||
*p++=0;
|
||||
if (!SetEnv(args,p)) {
|
||||
WriteOut(MSG_Get("SHELL_CMD_SET_OUT_OF_SPACE"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void DOS_Shell::CMD_IF(char * args) {
|
||||
bool has_not=false;
|
||||
|
||||
char * comp=strchr(args,'=');
|
||||
if (comp) {
|
||||
if (comp[1]!='=') {SyntaxError();return;}
|
||||
*comp++=' ';
|
||||
*comp++=' ';
|
||||
};
|
||||
char * word;
|
||||
word=args;
|
||||
args=StripWord(word);
|
||||
if (strcasecmp(word,"NOT")==0) {
|
||||
word=args;
|
||||
has_not=true;
|
||||
args=StripWord(word);
|
||||
}
|
||||
if (strcasecmp(word,"EXIST")==0) {
|
||||
word=args;args=StripWord(word);
|
||||
if (!*word) {
|
||||
WriteOut(MSG_Get("SHELL_CMD_IF_EXIST_MISSING_FILENAME"));
|
||||
return;
|
||||
};
|
||||
|
||||
if (DOS_FindFirst(word,0xFFFF)==(!has_not)) DoCommand(args);
|
||||
return;
|
||||
}
|
||||
if (strcasecmp(word,"ERRORLEVEL")==0) {
|
||||
word=args;args=StripWord(word);
|
||||
if(!isdigit(*word)) {
|
||||
WriteOut(MSG_Get("SHELL_CMD_IF_ERRORLEVEL_MISSING_NUMBER"));
|
||||
return;
|
||||
}
|
||||
|
||||
Bit8u n=0;
|
||||
do n = n * 10 + (*word - '0');
|
||||
while (isdigit(*++word));
|
||||
if(*word && !isspace(*word)) {
|
||||
WriteOut(MSG_Get("SHELL_CMD_IF_ERRORLEVEL_INVALID_NUMBER"));
|
||||
return;
|
||||
}
|
||||
/* Read the error code from DOS */
|
||||
reg_ah=0x4d;
|
||||
CALLBACK_RunRealInt(0x21);
|
||||
if ((reg_al>=n) ==(!has_not)) DoCommand(args);
|
||||
return;
|
||||
}
|
||||
/* Normal if string compare */
|
||||
if (!*args) { SyntaxError();return;};
|
||||
char * word2=args;
|
||||
args=StripWord(word2);
|
||||
if ((strcmp(word,word2)==0)==(!has_not)) DoCommand(args);
|
||||
}
|
||||
|
||||
void DOS_Shell::CMD_GOTO(char * args) {
|
||||
if (!bf) return;
|
||||
if (*args==':') args++;
|
||||
if (!*args) {
|
||||
WriteOut(MSG_Get("SHELL_CMD_GOTO_MISSING_LABEL"));
|
||||
return;
|
||||
}
|
||||
if (!bf->Goto(args)) {
|
||||
WriteOut(MSG_Get("SHELL_CMD_GOTO_LABEL_NOT_FOUND"),args);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void DOS_Shell::CMD_TYPE(char * args) {
|
||||
|
||||
if (!*args) {
|
||||
WriteOut(MSG_Get("SHELL_SYNTAXERROR"));
|
||||
return;
|
||||
}
|
||||
Bit16u handle;
|
||||
char * word;
|
||||
nextfile:
|
||||
word=args;
|
||||
args=StripWord(word);
|
||||
if (!DOS_OpenFile(word,0,&handle)) {
|
||||
WriteOut(MSG_Get("SHELL_CMD_FILE_NOT_FOUND"),word);
|
||||
return;
|
||||
}
|
||||
Bit16u n;Bit8u c;
|
||||
do {
|
||||
n=1;
|
||||
DOS_ReadFile(handle,&c,&n);
|
||||
DOS_WriteFile(STDOUT,&c,&n);
|
||||
} while (n);
|
||||
DOS_CloseFile(handle);
|
||||
if (*args) goto nextfile;
|
||||
}
|
||||
|
||||
|
||||
|
102
src/shell/shell_inc.h
Normal file
102
src/shell/shell_inc.h
Normal file
|
@ -0,0 +1,102 @@
|
|||
/*
|
||||
* 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 <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include "dosbox.h"
|
||||
#include "mem.h"
|
||||
#include "programs.h"
|
||||
#include "dos_inc.h"
|
||||
#include "regs.h"
|
||||
#include "support.h"
|
||||
#include "callback.h"
|
||||
|
||||
#define CMD_MAXLINE 4096
|
||||
#define CMD_MAXCMDS 20
|
||||
#define CMD_OLDSIZE 4096
|
||||
extern Bitu call_shellstop;
|
||||
class DOS_Shell;
|
||||
|
||||
|
||||
class BatchFile {
|
||||
public:
|
||||
BatchFile(DOS_Shell * host,char * name, char * cmd_line);
|
||||
~BatchFile();
|
||||
bool ReadLine(char * line);
|
||||
bool Goto(char * where);
|
||||
Bit16u file_handle;
|
||||
Bit32u line_count;
|
||||
char * cmd_words[CMD_MAXCMDS];
|
||||
char cmd_buffer[128]; //Command line can only be 128 chars
|
||||
Bit32u cmd_count;
|
||||
bool echo;
|
||||
DOS_Shell * shell;
|
||||
BatchFile * prev;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class DOS_Shell : public Program {
|
||||
public:
|
||||
DOS_Shell(PROGRAM_Info * program_info);
|
||||
void Run(void);
|
||||
/* A load of subfunctions */
|
||||
void ParseLine(char * line);
|
||||
Bit32u GetRedirection(char *s, char **ifn, char **ofn);
|
||||
void InputCommand(char * line);
|
||||
void ShowPrompt();
|
||||
void DoCommand(char * cmd);
|
||||
void Execute(char * name,char * args);
|
||||
/* Some internal used functions */
|
||||
char * Which(char * name);
|
||||
/* Some supported commands */
|
||||
void CMD_HELP(char * args);
|
||||
void CMD_CLS(char * args);
|
||||
void CMD_COPY(char * args);
|
||||
void CMD_DIR(char * args);
|
||||
void CMD_ECHO(char * args);
|
||||
void CMD_EXIT(char * args);
|
||||
void CMD_MKDIR(char * args);
|
||||
void CMD_CHDIR(char * args);
|
||||
void CMD_RMDIR(char * args);
|
||||
void CMD_SET(char * args);
|
||||
void CMD_IF(char * args);
|
||||
void CMD_GOTO(char * args);
|
||||
void CMD_TYPE(char * args);
|
||||
void SyntaxError(void);
|
||||
|
||||
/* The shell's variables */
|
||||
Bit16u input_handle;
|
||||
BatchFile * bf;
|
||||
bool echo;
|
||||
bool exit;
|
||||
struct {
|
||||
char buffer[CMD_OLDSIZE];
|
||||
Bitu index;
|
||||
Bitu size;
|
||||
} old;
|
||||
|
||||
};
|
||||
|
||||
struct SHELL_Cmd {
|
||||
const char * name; /* Command name*/
|
||||
Bit32u flags; /* Flags about the command */
|
||||
void (DOS_Shell::*handler)(char * args); /* Handler for this command */
|
||||
const char * help; /* String with command help */
|
||||
};
|
||||
|
||||
|
248
src/shell/shell_misc.cpp
Normal file
248
src/shell/shell_misc.cpp
Normal file
|
@ -0,0 +1,248 @@
|
|||
/*
|
||||
* 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 <string.h>
|
||||
#include "shell_inc.h"
|
||||
#include "cpu.h"
|
||||
|
||||
|
||||
void DOS_Shell::ShowPrompt(void) {
|
||||
Bit8u drive=DOS_GetDefaultDrive()+'A';
|
||||
Bit8u dir[DOS_PATHLENGTH];
|
||||
DOS_GetCurrentDir(0,dir);
|
||||
WriteOut("%c:\\%s>",drive,dir);
|
||||
}
|
||||
|
||||
|
||||
static void outc(Bit8u c) {
|
||||
Bit16u n=1;
|
||||
DOS_WriteFile(STDOUT,&c,&n);
|
||||
}
|
||||
|
||||
static void outs(char * str) {
|
||||
Bit16u n=strlen(str);
|
||||
DOS_WriteFile(STDOUT,(Bit8u *)str,&n);
|
||||
}
|
||||
|
||||
void DOS_Shell::InputCommand(char * line) {
|
||||
char * prev=old.buffer;
|
||||
char * reader;
|
||||
Bitu size=CMD_MAXLINE-1;
|
||||
Bit8u c;Bit16u n=1;
|
||||
Bitu str_len=0;Bitu str_index=0;
|
||||
|
||||
while (size) {
|
||||
DOS_ReadFile(input_handle,&c,&n);
|
||||
if (!n) {
|
||||
size=0; //Kill the while loop
|
||||
continue;
|
||||
}
|
||||
switch (c) {
|
||||
case 0x00: /* Extended Keys */
|
||||
{
|
||||
DOS_ReadFile(input_handle,&c,&n);
|
||||
switch (c) {
|
||||
case 0x3d: /* F3 */
|
||||
if (strlen(old.buffer)>str_len) {
|
||||
reader=&old.buffer[str_len];
|
||||
while (c=*reader++) {
|
||||
line[str_index]=c;
|
||||
str_len++;
|
||||
str_index++;
|
||||
size--;
|
||||
DOS_WriteFile(STDOUT,&c,&n);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
|
||||
}
|
||||
};
|
||||
break;
|
||||
case 0x08: /* BackSpace */
|
||||
if (str_index>0) {
|
||||
Bit32u str_remain=str_len-str_index;
|
||||
if (str_remain) {
|
||||
memcpy(&line[str_index-1],&line[str_index],str_remain);
|
||||
line[str_len]=0;
|
||||
/* Go back to redraw */
|
||||
for (;str_remain>0;str_remain--) {
|
||||
outc(8);
|
||||
}
|
||||
}
|
||||
str_index--;str_len--;
|
||||
outc(8);
|
||||
outc(' ');
|
||||
outc(8);
|
||||
|
||||
}
|
||||
break;
|
||||
case 0x0a: /* New Line not handled */
|
||||
/* Don't care */
|
||||
break;
|
||||
case 0x0d: /* Return */
|
||||
outc('\n');
|
||||
size=0; //Kill the while loop
|
||||
break;
|
||||
default:
|
||||
line[str_index]=c;
|
||||
str_len++;//This should depend on insert being active
|
||||
str_index++;
|
||||
size--;
|
||||
DOS_WriteFile(STDOUT,&c,&n);
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* String is inputted now save it in the buffer */
|
||||
line[str_len]=0;
|
||||
if (!str_len) return;
|
||||
str_len++;
|
||||
//Not quite perfect last entries can get screwed :)
|
||||
size_t first_len=strlen(old.buffer)+1;
|
||||
memmove(&old.buffer[first_len],&old.buffer[0],CMD_OLDSIZE-first_len);
|
||||
strcpy(old.buffer,line);
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
void DOS_Shell::Execute(char * name,char * args) {
|
||||
char * fullname;
|
||||
|
||||
/* check for a drive change */
|
||||
if ((strcmp(name + 1, ":") == 0) && isalpha(*name))
|
||||
{
|
||||
if (!DOS_SetDrive(toupper(name[0])-'A')) {
|
||||
WriteOut(MSG_Get("SHELL_EXECUTE_DRIVE_NOT_FOUND"),toupper(name[0]));
|
||||
}
|
||||
return;
|
||||
}
|
||||
/* Check for a full name */
|
||||
fullname=Which(name);
|
||||
if (!fullname) {
|
||||
WriteOut(MSG_Get("SHELL_EXECUTE_ILLEGAL_COMMAND"));
|
||||
return;
|
||||
}
|
||||
if (strcasecmp(strrchr(fullname, '.'), ".bat") == 0) {
|
||||
/* Run the .bat file */
|
||||
bf=new BatchFile(this,fullname,args);
|
||||
} else {
|
||||
/* Run the .exe or .com file */
|
||||
ParamBlock block;
|
||||
/* Fill the command line */
|
||||
CommandTail cmd;
|
||||
if (strlen(args)>126) args[126]=0;
|
||||
cmd.count=strlen(args);
|
||||
memcpy(cmd.buffer,args,strlen(args));
|
||||
cmd.buffer[strlen(args)]=0xd;
|
||||
|
||||
MEM_BlockWrite(real_phys(prog_info->psp_seg,128),&cmd,128);
|
||||
block.exec.cmdtail=RealMake(prog_info->psp_seg,128);
|
||||
block.exec.envseg=0;
|
||||
block.exec.fcb1=0;
|
||||
block.exec.fcb2=0;
|
||||
/* Save CS:IP to some point where i can return them from */
|
||||
RealPt newcsip;
|
||||
newcsip=CALLBACK_RealPointer(call_shellstop);
|
||||
SetSegment_16(cs,RealSeg(newcsip));
|
||||
reg_ip=RealOff(newcsip);
|
||||
|
||||
DOS_Execute(fullname,&block,0);
|
||||
DOSBOX_RunMachine();
|
||||
Bit16u blah=0;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
static char * bat_ext=".BAT";
|
||||
static char * com_ext=".COM";
|
||||
static char * exe_ext=".EXE";
|
||||
static char which_ret[DOS_PATHLENGTH];
|
||||
|
||||
char * DOS_Shell::Which(char * name) {
|
||||
/* Parse through the Path to find the correct entry */
|
||||
|
||||
// if (which_result) free(which_result);
|
||||
/* Check for extension */
|
||||
|
||||
|
||||
|
||||
/* Check if name is already ok but just misses an extension */
|
||||
char * ext=strrchr(name,'.');
|
||||
if (ext) if (strlen(ext)>4) ext=0;
|
||||
if (ext) {
|
||||
if (DOS_FileExists(name)) return name;
|
||||
} else {
|
||||
/* try to find .exe .com .bat */
|
||||
strcpy(which_ret,name);
|
||||
strcat(which_ret,bat_ext);
|
||||
if (DOS_FileExists(which_ret)) return which_ret;
|
||||
strcpy(which_ret,name);
|
||||
strcat(which_ret,com_ext);
|
||||
if (DOS_FileExists(which_ret)) return which_ret;
|
||||
strcpy(which_ret,name);
|
||||
strcat(which_ret,exe_ext);
|
||||
if (DOS_FileExists(which_ret)) return which_ret;
|
||||
}
|
||||
|
||||
/* No Path in filename look through %path% */
|
||||
|
||||
static char path[DOS_PATHLENGTH];
|
||||
char * pathenv=GetEnvStr("PATH");
|
||||
if (!pathenv) return 0;
|
||||
pathenv=strchr(pathenv,'=');
|
||||
if (!pathenv) return 0;
|
||||
pathenv++;
|
||||
char * path_write=path;
|
||||
while (*pathenv) {
|
||||
if (*pathenv!=';') {
|
||||
*path_write++=*pathenv++;
|
||||
}
|
||||
if (*pathenv==';' || *(pathenv)==0) {
|
||||
if (*path_write!='\\') *path_write++='\\';
|
||||
*path_write++=0;
|
||||
strcat(path,name);
|
||||
strcpy(which_ret,path);
|
||||
if (ext) {
|
||||
if (DOS_FileExists(which_ret)) return which_ret;
|
||||
} else {
|
||||
strcpy(which_ret,path);
|
||||
strcat(which_ret,bat_ext);
|
||||
if (DOS_FileExists(which_ret)) return which_ret;
|
||||
strcpy(which_ret,path);
|
||||
strcat(which_ret,com_ext);
|
||||
if (DOS_FileExists(which_ret)) return which_ret;
|
||||
strcpy(which_ret,path);
|
||||
strcat(which_ret,exe_ext);
|
||||
if (DOS_FileExists(which_ret)) return which_ret;
|
||||
}
|
||||
|
||||
path_write=path;
|
||||
if (*pathenv) pathenv++;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue