diff --git a/src/shell/shell.cpp b/src/shell/shell.cpp index c360ef8e..1af2b57d 100644 --- a/src/shell/shell.cpp +++ b/src/shell/shell.cpp @@ -50,14 +50,13 @@ void SHELL_AddAutoexec(char * line,...) { sprintf((autoexec_data+auto_len),"%s\r\n",buf); } - DOS_Shell::DOS_Shell():Program(){ input_handle=STDIN; echo=true; exit=false; bf=0; - memset(&old.buffer,0,CMD_OLDSIZE); - old.size=0; + + completion_start = NULL; } @@ -65,11 +64,14 @@ DOS_Shell::DOS_Shell():Program(){ Bit32u DOS_Shell::GetRedirection(char *s, char **ifn, char **ofn) { + char *output = strrchr(s, '>'); + if (output) { + *output = 0; + // while (!isalnum(*output)) output++; + } return 1; -} - - +} void DOS_Shell::ParseLine(char * line) { @@ -81,7 +83,7 @@ void DOS_Shell::ParseLine(char * line) { line=trim(line); Bit32u num=0; /* Number of commands in this line */ - num = GetRedirection(line,&in, &out); + num = GetRedirection(line, &in, &out); /* TODO in and out redirection */ diff --git a/src/shell/shell_cmds.cpp b/src/shell/shell_cmds.cpp index 4095302c..601ae88d 100644 --- a/src/shell/shell_cmds.cpp +++ b/src/shell/shell_cmds.cpp @@ -24,31 +24,30 @@ static SHELL_Cmd cmd_list[]={ -{ "CD", 0, &DOS_Shell::CMD_CHDIR, "SHELL_CMD_CHDIR_HELP"}, +{ "CHDIR", 0, &DOS_Shell::CMD_CHDIR, "SHELL_CMD_CHDIR_HELP"}, +{ "CD", 1, &DOS_Shell::CMD_CHDIR, "SHELL_CMD_CHDIR_HELP"}, { "CLS", 0, &DOS_Shell::CMD_CLS, "SHELL_CMD_CLS_HELP"}, { "COPY", 0, &DOS_Shell::CMD_COPY, "SHELL_CMD_COPY_HELP"}, { "DIR", 0, &DOS_Shell::CMD_DIR, "SHELL_CMD_DIR_HELP"}, { "DEL", 1, &DOS_Shell::CMD_DELETE, "SHELL_CMD_DELETE_HELP"}, { "DELETE", 0, &DOS_Shell::CMD_DELETE, "SHELL_CMD_DELETE_HELP"}, +{ "ERASE", 1, &DOS_Shell::CMD_DELETE, "SHELL_CMD_DELETE_HELP"}, { "ECHO", 0, &DOS_Shell::CMD_ECHO, "SHELL_CMD_ECHO_HELP"}, { "ECHO.", 1, &DOS_Shell::CMD_EHCODOT, "SHELL_CMD_ECHO_HELP"}, { "EXIT", 0, &DOS_Shell::CMD_EXIT, "SHELL_CMD_EXIT_HELP"}, { "HELP", 0, &DOS_Shell::CMD_HELP, "SHELL_CMD_HELP_HELP"}, -{ "MD", 0, &DOS_Shell::CMD_MKDIR, "SHELL_CMD_MKDIR_HELP"}, -{ "RD", 0, &DOS_Shell::CMD_RMDIR, "SHELL_CMD_RMDIR_HELP"}, +{ "MKDIR", 0, &DOS_Shell::CMD_MKDIR, "SHELL_CMD_MKDIR_HELP"}, +{ "MD", 1, &DOS_Shell::CMD_MKDIR, "SHELL_CMD_MKDIR_HELP"}, +{ "RMDIR", 0, &DOS_Shell::CMD_RMDIR, "SHELL_CMD_RMDIR_HELP"}, +{ "RD", 1, &DOS_Shell::CMD_RMDIR, "SHELL_CMD_RMDIR_HELP"}, { "SET", 0, &DOS_Shell::CMD_SET, "SHELL_CMD_SET_HELP"}, -{ "IF", 0, &DOS_Shell::CMD_IF, "SHELL_CMD_IF_HELP"}, +{ "IF", 0, &DOS_Shell::CMD_IF, "SHELL_CMD_IF_HELP"}, { "GOTO", 0, &DOS_Shell::CMD_GOTO, "SHELL_CMD_GOTO_HELP"}, { "TYPE", 0, &DOS_Shell::CMD_TYPE, "SHELL_CMD_TYPE_HELP"}, { "REM", 0, &DOS_Shell::CMD_REM, "SHELL_CMD_REM_HELP"}, { "RENAME", 0, &DOS_Shell::CMD_RENAME, "SHELL_CMD_RENAME_HELP"}, { "REN", 1, &DOS_Shell::CMD_RENAME, "SHELL_CMD_RENAME_HELP"}, { "PAUSE", 0, &DOS_Shell::CMD_PAUSE, "SHELL_CMD_PAUSE_HELP"}, -/* - "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} }; @@ -235,7 +234,7 @@ void DOS_Shell::CMD_DIR(char * args) { /* Make a full path in the args */ if (!DOS_Canonicalize(args,path)) { - WriteOut(MSG_Get("SHELL_CMD_ILLEGAL_PATH")); + WriteOut(MSG_Get("SHELL_ILLEGAL_PATH")); return; } *(strrchr(path,'\\')+1)=0; @@ -332,7 +331,7 @@ void DOS_Shell::CMD_COPY(char * args) { char pathTarget[DOS_PATHLENGTH]; if (!DOS_Canonicalize(source,pathSource)) { - WriteOut(MSG_Get("SHELL_CMD_ILLEGAL_PATH")); + WriteOut(MSG_Get("SHELL_ILLEGAL_PATH")); return; } // cut search pattern @@ -340,10 +339,13 @@ void DOS_Shell::CMD_COPY(char * args) { if (pos) *(pos+1) = 0; if (!DOS_Canonicalize(target,pathTarget)) { - WriteOut(MSG_Get("SHELL_CMD_ILLEGAL_PATH")); + WriteOut(MSG_Get("SHELL_ILLEGAL_PATH")); return; } - // add '\\' if target is a directoy + char* temp = strstr(pathTarget,"*.*"); + if(temp) *temp = 0;//strip off *.* from target + + // add '\\' if target is a directoy if (pathTarget[strlen(pathTarget)-1]!='\\') { if (DOS_FindFirst(pathTarget,0xffff)) { dta.GetResult(name,size,date,time,attr); @@ -520,8 +522,8 @@ void DOS_Shell::CMD_REM(char * args) { } void DOS_Shell::CMD_PAUSE(char * args){ - WriteOut(MSG_Get("SHELL_CMD_PAUSE")); - Bit8u c;Bit16u n=1; + WriteOut(MSG_Get("SHELL_CMD_PAUSE")); + Bit8u c;Bit16u n=1; DOS_ReadFile (STDIN,&c,&n); } diff --git a/src/shell/shell_inc.h b/src/shell/shell_inc.h index 2896ff92..a50b263c 100644 --- a/src/shell/shell_inc.h +++ b/src/shell/shell_inc.h @@ -26,6 +26,9 @@ #include "callback.h" #include "setup.h" +#include +#include + #define CMD_MAXLINE 4096 #define CMD_MAXCMDS 20 #define CMD_OLDSIZE 4096 @@ -46,11 +49,19 @@ public: CommandLine * cmd; }; - - class DOS_Shell : public Program { + +private: + + std::list l_history, l_completion; + + char *completion_start; + Bit16u completion_index; + public: + DOS_Shell(); + void Run(void); void RunInternal(void); //for command /C /* A load of subfunctions */ @@ -87,12 +98,6 @@ public: BatchFile * bf; bool echo; bool exit; - struct { - char buffer[CMD_OLDSIZE]; - Bitu index; - Bitu size; - } old; - }; struct SHELL_Cmd { diff --git a/src/shell/shell_misc.cpp b/src/shell/shell_misc.cpp index e586caf9..49eb6d91 100644 --- a/src/shell/shell_misc.cpp +++ b/src/shell/shell_misc.cpp @@ -40,11 +40,14 @@ static void outs(char * str) { } 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; + Bit16u len; + + line[0] = '\0'; + + std::list::iterator it_history = l_history.begin(), it_completion = l_completion.begin(); while (size) { dos.echo=false; @@ -58,41 +61,75 @@ void DOS_Shell::InputCommand(char * line) { { 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--; + if (!l_history.size()) break; + it_history = l_history.begin(); + if (it_history != l_history.end() && it_history->length() > str_len) { + const char *reader = &(it_history->c_str())[str_len]; + while ((c = *reader++)) { + line[str_index ++] = c; DOS_WriteFile(STDOUT,&c,&n); } + str_len = str_index = it_history->length(); + size = CMD_MAXLINE - str_index - 1; } break; - default: + + case 0x4B: /* LEFT */ + if (str_index) { + outc(8); + str_index --; + } break; + case 0x4D: /* RIGHT */ + if (str_index < str_len) { + outc(line[str_index++]); + } + break; + case 0x48: /* UP */ + if (it_history == l_history.end()) break; + + for (;str_index>0; str_index--) { + // removes all characters + outc(8); outc(' '); outc(8); + } + strcpy(line, it_history->c_str()); + len = it_history->length(); + str_len = str_index = len; + size = CMD_MAXLINE - str_index - 1; + DOS_WriteFile(STDOUT, (Bit8u *)line, &len); + + it_history ++; + if (it_history == l_history.end()) it_history = l_history.begin(); + + break; + + default: + break; } }; break; case 0x08: /* BackSpace */ - if (str_index>0) { - Bit32u str_remain=str_len-str_index; + if (str_index) { + outc(8); + Bit32u str_remain=str_len - str_index; if (str_remain) { - memcpy(&line[str_index-1],&line[str_index],str_remain); - line[str_len]=0; + memmove(&line[str_index-1],&line[str_index],str_remain); + line[--str_len]=0; + str_index --; /* Go back to redraw */ - for (;str_remain>0;str_remain--) { - outc(8); - } + for (Bit16u i=str_index; i < str_len; i++) + outc(line[i]); + } else { + line[--str_index] = '\0'; + str_len--; } - str_index--;str_len--; - outc(8); - outc(' '); - outc(8); - + outc(' '); outc(8); + // moves the cursor left + while (str_remain--) outc(8); } break; case 0x0a: /* New Line not handled */ @@ -103,35 +140,85 @@ void DOS_Shell::InputCommand(char * line) { size=0; //Kill the while loop break; case'\t': - { - Bit8u c=' ';Bit16u n=1; - for(Bitu i=0; i !=4 ;i++) - { - line[str_index]=c; - str_len++;//This should depend on insert being active - str_index++; - size--; - DOS_WriteFile(STDOUT,&c,&n); + { + if (l_completion.size()) { + it_completion ++; + if (it_completion == l_completion.end()) it_completion = l_completion.begin(); + } else { + // build new completion list + + // get completion mask + char *completion_start = strrchr(line, ' '); + + if (completion_start) { + completion_start ++; + completion_index = str_index - strlen(completion_start); + } else { + completion_start = line; + completion_index = 0; + } + + // build the completion list + char mask[DOS_PATHLENGTH]; + if (completion_start) { + strcpy(mask, completion_start); + // not perfect when line already contains wildcards, but works + strcat(mask, "*.*"); + } else { + strcpy(mask, "*.*"); + } + + bool res = DOS_FindFirst(mask, 0xffff & ~DOS_ATTR_VOLUME); + if (!res) break; // TODO: beep + + DOS_DTA dta(dos.dta); + char name[DOS_NAMELENGTH_ASCII];Bit32u size;Bit16u date;Bit16u time;Bit8u attr; + + while (res) { + dta.GetResult(name,size,date,time,attr); + // add result to completion list + + if (strcmp(name, ".") && strcmp(name, "..")) + l_completion.push_back(name); + + res=DOS_FindNext(); + } + + it_completion = l_completion.begin(); + } + + if (it_completion->length()) { + for (;str_index > completion_index; str_index--) { + // removes all characters + outc(8); outc(' '); outc(8); + } + + strcpy(&line[completion_index], it_completion->c_str()); + len = it_completion->length(); + str_len = str_index = completion_index + len; + size = CMD_MAXLINE - str_index - 1; + DOS_WriteFile(STDOUT, (Bit8u *)it_completion->c_str(), &len); } } break; default: + if (l_completion.size()) l_completion.clear(); line[str_index]=c; + str_index ++; + if (str_index > str_len) line[str_index] = '\0'; 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); + + // add command line to history + l_history.push_front(line); it_history = l_history.begin(); + if (l_completion.size()) l_completion.clear(); } void DOS_Shell::Execute(char * name,char * args) {