void DOS_Shell::CMD_CHDIR(char * args) { HELP("CHDIR"); StripSpaces(args); char sargs[CROSS_LEN]; if (*args && !DOS_GetSFNPath(args,sargs,false)) { WriteOut(MSG_Get("SHELL_ILLEGAL_PATH")); return; } Bit8u drive = DOS_GetDefaultDrive()+'A'; char dir[DOS_PATHLENGTH]; if (!*args) { DOS_GetCurrentDir(0,dir,true); WriteOut("%c:\\%s\n",drive,dir); } else if(strlen(args) == 2 && args[1]==':') { Bit8u targetdrive = (args[0] | 0x20)-'a' + 1; unsigned char targetdisplay = *reinterpret_cast<unsigned char*>(&args[0]); if(!DOS_GetCurrentDir(targetdrive,dir,true)) { if(drive == 'Z') { WriteOut(MSG_Get("SHELL_EXECUTE_DRIVE_NOT_FOUND"),toupper(targetdisplay)); } else { WriteOut(MSG_Get("SHELL_ILLEGAL_PATH")); } return; } WriteOut("%c:\\%s\n",toupper(targetdisplay),dir); if(drive == 'Z') WriteOut(MSG_Get("SHELL_CMD_CHDIR_HINT"),toupper(targetdisplay)); } else if (!DOS_ChangeDir(sargs)) { /* Changedir failed. Check if the filename is longer then 8 and/or contains spaces */ std::string temps(args),slashpart; std::string::size_type separator = temps.find_first_of("\\/"); if(!separator) { slashpart = temps.substr(0,1); temps.erase(0,1); } separator = temps.find_first_of("\\/"); if(separator != std::string::npos) temps.erase(separator); separator = temps.find_first_of("\""); if(separator != std::string::npos) temps.erase(separator); separator = temps.rfind('.'); if(separator != std::string::npos) temps.erase(separator); separator = temps.find(' '); if(separator != std::string::npos) {/* Contains spaces */ temps.erase(separator); if(temps.size() >6) temps.erase(6); temps += "~1"; WriteOut(MSG_Get("SHELL_CMD_CHDIR_HINT_2"),temps.insert(0,slashpart).c_str()); } else { if (drive == 'Z') { WriteOut(MSG_Get("SHELL_CMD_CHDIR_HINT_3")); } else { WriteOut(MSG_Get("SHELL_CMD_CHDIR_ERROR"),args); } } } }
bool DOS_GetCurrentDir(Bit8u drive,char * const buffer, bool LFN) { if (drive==0) drive=DOS_GetDefaultDrive(); else drive--; if ((drive>=DOS_DRIVES) || (!Drives[drive])) { DOS_SetError(DOSERR_INVALID_DRIVE); return false; } if (LFN && uselfn) { char cdir[DOS_PATHLENGTH],ldir[DOS_PATHLENGTH]; if (strchr(Drives[drive]->curdir,' ')) sprintf(cdir,"\"%c:\\%s\"",drive+'A',Drives[drive]->curdir); else sprintf(cdir,"%c:\\%s",drive+'A',Drives[drive]->curdir); if (!DOS_GetSFNPath(cdir,ldir,true)) return false; strcpy(buffer,ldir+3); if (DOS_GetSFNPath(cdir,ldir,false)) strcpy(Drives[drive]->curdir,ldir+3); } else { strcpy(buffer,Drives[drive]->curdir); } return true; }
void DOS_Shell::CMD_DELETE(char * args) { HELP("DELETE"); /* Command uses dta so set it to our internal dta */ RealPt save_dta=dos.dta(); dos.dta(dos.tables.tempdta); char * rem=ScanCMDRemain(args); if (rem) { WriteOut(MSG_Get("SHELL_ILLEGAL_SWITCH"),rem); return; } /* If delete accept switches mind the space infront of them. See the dir /p code */ char full[DOS_PATHLENGTH],sfull[DOS_PATHLENGTH+2]; char buffer[CROSS_LEN]; args = ExpandDot(args,buffer); StripSpaces(args); if (!DOS_Canonicalize(args,full)) { WriteOut(MSG_Get("SHELL_ILLEGAL_PATH"));return; } //TODO Maybe support confirmation for *.* like dos does. char spath[DOS_PATHLENGTH],sargs[DOS_PATHLENGTH]; if (!DOS_GetSFNPath(args,spath,false)) { WriteOut(MSG_Get("SHELL_CMD_DEL_ERROR"),args); return; } sprintf(sargs,"\"%s\"",spath); bool res=DOS_FindFirst(sargs,0xffff & ~DOS_ATTR_VOLUME); if (!res) { WriteOut(MSG_Get("SHELL_CMD_DEL_ERROR"),args); dos.dta(save_dta); return; } //end can't be 0, but if it is we'll get a nice crash, who cares :) char * end=strrchr(full,'\\')+1;*end=0; char name[DOS_NAMELENGTH_ASCII],lname[LFN_NAMELENGTH+1]; Bit32u size;Bit16u time,date;Bit8u attr; DOS_DTA dta(dos.dta()); while (res) { dta.GetResult(name,lname,size,date,time,attr); if (!(attr & (DOS_ATTR_DIRECTORY|DOS_ATTR_READ_ONLY))) { strcpy(end,name); strcpy(sfull,full); if (uselfn) sprintf(sfull,"\"%s\"",full); if (!DOS_UnlinkFile(sfull)) WriteOut(MSG_Get("SHELL_CMD_DEL_ERROR"),full); } res=DOS_FindNext(); } dos.dta(save_dta); }
void DOS_Shell::CMD_COPY(char * args) { HELP("COPY"); static char defaulttarget[] = "."; StripSpaces(args); /* Command uses dta so set it to our internal dta */ RealPt save_dta=dos.dta(); dos.dta(dos.tables.tempdta); DOS_DTA dta(dos.dta()); Bit32u size;Bit16u date;Bit16u time;Bit8u attr; char name[DOS_NAMELENGTH_ASCII], lname[LFN_NAMELENGTH+1]; std::vector<copysource> sources; // ignore /b and /t switches: always copy binary while(ScanCMDBool(args,"B")) ; while(ScanCMDBool(args,"T")) ; //Shouldn't this be A ? while(ScanCMDBool(args,"A")) ; ScanCMDBool(args,"Y"); ScanCMDBool(args,"-Y"); ScanCMDBool(args,"V"); char * rem=ScanCMDRemain(args); if (rem) { WriteOut(MSG_Get("SHELL_ILLEGAL_SWITCH"),rem); dos.dta(save_dta); return; } // Gather all sources (extension to copy more then 1 file specified at command line) // Concatenating files go as follows: All parts except for the last bear the concat flag. // This construction allows them to be counted (only the non concat set) char q[]="\""; char* source_p = NULL; char source_x[DOS_PATHLENGTH+CROSS_LEN]; while ( (source_p = StripArg(args)) && *source_p ) { do { char* plus = strchr(source_p,'+'); // If StripWord() previously cut at a space before a plus then // set concatenate flag on last source and remove leading plus. if (plus == source_p && sources.size()) { sources[sources.size()-1].concat = true; // If spaces also followed plus then item is only a plus. if (strlen(++source_p)==0) break; plus = strchr(source_p,'+'); } if (plus) *plus++ = 0; safe_strncpy(source_x,source_p,CROSS_LEN); bool has_drive_spec = false; size_t source_x_len = strlen(source_x); if (source_x_len>0) { if (source_x[source_x_len-1]==':') has_drive_spec = true; } if (!has_drive_spec && !strpbrk(source_p,"*?") ) { //doubt that fu*\*.* is valid char spath[DOS_PATHLENGTH]; if (DOS_GetSFNPath(source_p,spath,false) && DOS_FindFirst(spath,0xffff & ~DOS_ATTR_VOLUME)) { dta.GetResult(name,lname,size,date,time,attr); if (attr & DOS_ATTR_DIRECTORY) strcat(source_x,"\\*.*"); } } sources.push_back(copysource(source_x,(plus)?true:false)); source_p = plus; } while(source_p && *source_p); } // At least one source has to be there if (!sources.size() || !sources[0].filename.size()) { WriteOut(MSG_Get("SHELL_MISSING_PARAMETER")); dos.dta(save_dta); return; }; copysource target; // If more then one object exists and last target is not part of a // concat sequence then make it the target. if(sources.size()>1 && !sources[sources.size()-2].concat){ target = sources.back(); sources.pop_back(); } //If no target => default target with concat flag true to detect a+b+c if(target.filename.size() == 0) target = copysource(defaulttarget,true); copysource oldsource; copysource source; Bit32u count = 0; while(sources.size()) { /* Get next source item and keep track of old source for concat start end */ oldsource = source; source = sources[0]; sources.erase(sources.begin()); //Skip first file if doing a+b+c. Set target to first file if(!oldsource.concat && source.concat && target.concat) { target = source; continue; } /* Make a full path in the args */ char pathSourcePre[DOS_PATHLENGTH], pathSource[DOS_PATHLENGTH+2]; char pathTarget[DOS_PATHLENGTH]; if (!DOS_Canonicalize(const_cast<char*>(source.filename.c_str()),pathSourcePre)) { WriteOut(MSG_Get("SHELL_ILLEGAL_PATH")); dos.dta(save_dta); return; } strcpy(pathSource,pathSourcePre); if (uselfn) sprintf(pathSource,"\"%s\"",pathSourcePre); // cut search pattern char* pos = strrchr(pathSource,'\\'); if (pos) *(pos+1) = 0; if (!DOS_Canonicalize(const_cast<char*>(target.filename.c_str()),pathTarget)) { WriteOut(MSG_Get("SHELL_ILLEGAL_PATH")); dos.dta(save_dta); return; } char* temp = strstr(pathTarget,"*.*"); if(temp) *temp = 0;//strip off *.* from target // add '\\' if target is a directory bool target_is_file = true; if (pathTarget[strlen(pathTarget)-1]!='\\') { if (DOS_FindFirst(pathTarget,0xffff & ~DOS_ATTR_VOLUME)) { dta.GetResult(name,lname,size,date,time,attr); if (attr & DOS_ATTR_DIRECTORY) { strcat(pathTarget,"\\"); target_is_file = false; } } } else target_is_file = false; //Find first sourcefile char sPath[DOS_PATHLENGTH]; bool ret = DOS_GetSFNPath(source.filename.c_str(),sPath,false) && DOS_FindFirst(const_cast<char*>(sPath),0xffff & ~DOS_ATTR_VOLUME); if (!ret) { WriteOut(MSG_Get("SHELL_CMD_FILE_NOT_FOUND"),const_cast<char*>(source.filename.c_str())); dos.dta(save_dta); return; } Bit16u sourceHandle,targetHandle; char nameTarget[DOS_PATHLENGTH]; char nameSource[DOS_PATHLENGTH]; bool second_file_of_current_source = false; while (ret) { dta.GetResult(name,lname,size,date,time,attr); if ((attr & DOS_ATTR_DIRECTORY)==0) { strcpy(nameSource,pathSource); strcat(nameSource,name); // Open Source if (DOS_OpenFile(nameSource,0,&sourceHandle)) { // Create Target or open it if in concat mode strcpy(nameTarget,q); strcat(nameTarget,pathTarget); if (nameTarget[strlen(nameTarget)-1]=='\\') strcat(nameTarget,uselfn?lname:name); strcat(nameTarget,q); //Special variable to ensure that copy * a_file, where a_file is not a directory concats. bool special = second_file_of_current_source && target_is_file; second_file_of_current_source = true; if (special) oldsource.concat = true; //Don't create a new file when in concat mode if (oldsource.concat || DOS_CreateFile(nameTarget,0,&targetHandle)) { Bit32u dummy=0; //In concat mode. Open the target and seek to the eof if (!oldsource.concat || (DOS_OpenFile(nameTarget,OPEN_READWRITE,&targetHandle) && DOS_SeekFile(targetHandle,&dummy,DOS_SEEK_END))) { // Copy static Bit8u buffer[0x8000]; // static, otherwise stack overflow possible. bool failed = false; Bit16u toread = 0x8000; do { failed |= DOS_ReadFile(sourceHandle,buffer,&toread); failed |= DOS_WriteFile(targetHandle,buffer,&toread); } while (toread==0x8000); failed |= DOS_CloseFile(sourceHandle); failed |= DOS_CloseFile(targetHandle); if (strcmp(name,lname)&&uselfn) WriteOut(" %s [%s]\n",lname,name); else WriteOut(" %s\n",uselfn?lname:name); if(!source.concat && !special) count++; //Only count concat files once } else { DOS_CloseFile(sourceHandle); WriteOut(MSG_Get("SHELL_CMD_COPY_FAILURE"),const_cast<char*>(target.filename.c_str())); } } else { DOS_CloseFile(sourceHandle); WriteOut(MSG_Get("SHELL_CMD_COPY_FAILURE"),const_cast<char*>(target.filename.c_str())); } } else WriteOut(MSG_Get("SHELL_CMD_COPY_FAILURE"),const_cast<char*>(source.filename.c_str())); }; //On to the next file if the previous one wasn't a device if ((attr&DOS_ATTR_DEVICE) == 0) ret = DOS_FindNext(); else ret = false; }; } WriteOut(MSG_Get("SHELL_CMD_COPY_SUCCESS"),count); dos.dta(save_dta); }
void DOS_Shell::CMD_DIR(char * args) { HELP("DIR"); char numformat[16]; char path[DOS_PATHLENGTH]; char sargs[CROSS_LEN]; std::string line; if(GetEnvStr("DIRCMD",line)){ std::string::size_type idx = line.find('='); std::string value=line.substr(idx +1 , std::string::npos); line = std::string(args) + " " + value; args=const_cast<char*>(line.c_str()); } bool optW=ScanCMDBool(args,"W"); ScanCMDBool(args,"S"); bool optP=ScanCMDBool(args,"P"); if (ScanCMDBool(args,"WP") || ScanCMDBool(args,"PW")) { optW=optP=true; } bool optB=ScanCMDBool(args,"B"); bool optAD=ScanCMDBool(args,"AD"); char * rem=ScanCMDRemain(args); if (rem) { WriteOut(MSG_Get("SHELL_ILLEGAL_SWITCH"),rem); return; } Bit32u byte_count,file_count,dir_count; Bitu w_count=0; Bitu p_count=0; Bitu w_size = optW?5:1; byte_count=file_count=dir_count=0; char buffer[CROSS_LEN]; args = trim(args); size_t argLen = strlen(args); if (argLen == 0) { strcpy(args,"*.*"); //no arguments. } else { switch (args[argLen-1]) { case '\\': // handle \, C:\, etc. case ':' : // handle C:, etc. strcat(args,"*.*"); break; default: break; } } args = ExpandDot(args,buffer); if (!strrchr(args,'*') && !strrchr(args,'?')) { Bit16u attribute=0; if(!DOS_GetSFNPath(args,sargs,false)) { WriteOut(MSG_Get("SHELL_ILLEGAL_PATH")); return; } if(DOS_GetFileAttr(sargs,&attribute) && (attribute&DOS_ATTR_DIRECTORY) ) { DOS_FindFirst(sargs,0xffff & ~DOS_ATTR_VOLUME); DOS_DTA dta(dos.dta()); strcpy(args,sargs); strcat(args,"\\*.*"); // if no wildcard and a directory, get its files } } if (!DOS_GetSFNPath(args,sargs,false)) { WriteOut(MSG_Get("SHELL_ILLEGAL_PATH")); return; } sprintf(args,"\"%s\"",sargs); if (!strrchr(args,'.')) { strcat(args,".*"); // if no extension, get them all } /* Make a full path in the args */ if (!DOS_Canonicalize(args,path)) { WriteOut(MSG_Get("SHELL_ILLEGAL_PATH")); return; } *(strrchr(path,'\\')+1)=0; if (!DOS_GetSFNPath(path,sargs,true)) { WriteOut(MSG_Get("SHELL_ILLEGAL_PATH")); return; } if (*(sargs+strlen(sargs)-1) != '\\') strcat(sargs,"\\"); if (!optB) WriteOut(MSG_Get("SHELL_CMD_DIR_INTRO"),sargs); /* Command uses dta so set it to our internal dta */ RealPt save_dta=dos.dta(); dos.dta(dos.tables.tempdta); DOS_DTA dta(dos.dta()); bool ret=DOS_FindFirst(args,0xffff & ~DOS_ATTR_VOLUME); if (!ret) { if (!optB) WriteOut(MSG_Get("SHELL_CMD_FILE_NOT_FOUND"),args); dos.dta(save_dta); return; } do { /* File name and extension */ char name[DOS_NAMELENGTH_ASCII], lname[LFN_NAMELENGTH+1]; Bit32u size;Bit16u date;Bit16u time;Bit8u attr; dta.GetResult(name,lname,size,date,time,attr); /* Skip non-directories if option AD is present */ if(optAD && !(attr&DOS_ATTR_DIRECTORY) ) continue; /* output the file */ if (optB) { // this overrides pretty much everything if (strcmp(".",uselfn?lname:name) && strcmp("..",uselfn?lname:name)) { WriteOut("%s\n",uselfn?lname:name); } } else { char * ext = empty_string; if (!optW && (name[0] != '.')) { ext = strrchr(name, '.'); if (!ext) ext = empty_string; else *ext++ = 0; } Bit8u day = (Bit8u)(date & 0x001f); Bit8u month = (Bit8u)((date >> 5) & 0x000f); Bit16u year = (Bit16u)((date >> 9) + 1980); Bit8u hour = (Bit8u)((time >> 5 ) >> 6); Bit8u minute = (Bit8u)((time >> 5) & 0x003f); if (attr & DOS_ATTR_DIRECTORY) { if (optW) { WriteOut("[%s]",name); size_t namelen = strlen(name); if (namelen <= 14) { for (size_t i=14-namelen;i>0;i--) WriteOut(" "); } } else { WriteOut("%-8s %-3s %-16s %02d-%02d-%04d %2d:%02d %s\n",name,ext,"<DIR>",day,month,year,hour,minute,uselfn?lname:""); } dir_count++; } else { if (optW) { WriteOut("%-16s",name); } else { FormatNumber(size,numformat); WriteOut("%-8s %-3s %16s %02d-%02d-%04d %2d:%02d %s\n",name,ext,numformat,day,month,year,hour,minute,uselfn?lname:""); } file_count++; byte_count+=size; } if (optW) { w_count++; } } if (optP && !(++p_count%(22*w_size))) { CMD_PAUSE(empty_string); } } while ( (ret=DOS_FindNext()) ); if (optW) { if (w_count%5) WriteOut("\n"); } if (!optB) { /* Show the summary of results */ FormatNumber(byte_count,numformat); WriteOut(MSG_Get("SHELL_CMD_DIR_BYTES_USED"),file_count,numformat); Bit8u drive=dta.GetSearchDrive(); //TODO Free Space Bitu free_space=1024*1024*100; if (Drives[drive]) { Bit16u bytes_sector;Bit8u sectors_cluster;Bit16u total_clusters;Bit16u free_clusters; Drives[drive]->AllocationInfo(&bytes_sector,§ors_cluster,&total_clusters,&free_clusters); free_space=bytes_sector*sectors_cluster*free_clusters; } FormatNumber(free_space,numformat); WriteOut(MSG_Get("SHELL_CMD_DIR_BYTES_FREE"),dir_count,numformat); } dos.dta(save_dta); }