예제 #1
0
void UnMount(int i_drive) {
	if (dos_kernel_disabled)
		return;

	i_drive = toupper(i_drive);
	if(i_drive-'A' == DOS_GetDefaultDrive()) {
		DOS_MCB mcb(dos.psp()-1);
		static char name[9];
		mcb.GetFileName(name);
		if (!strlen(name)) goto umount;
		LOG_MSG("GUI:Drive %c is being used. Aborted.",i_drive);
		return;
	};
umount:
	if (i_drive-'A' < DOS_DRIVES && i_drive-'A' >= 0 && Drives[i_drive-'A']) {
		switch (DriveManager::UnmountDrive(i_drive-'A')) {
		case 0:
			Drives[i_drive-'A'] = 0;
			if(i_drive-'A' == DOS_GetDefaultDrive()) 
				DOS_SetDrive(toupper('Z') - 'A');
			LOG_MSG("GUI:Drive %c has succesfully been removed.",i_drive); break;
		case 1:
			LOG_MSG("GUI:Virtual Drives can not be unMOUNTed."); break;
		case 2:
			LOG_MSG(MSCDEX_Output(1).c_str()); break;
		}
	}
}
예제 #2
0
void DOS_Shell::ShowPrompt(void) {
	Bit8u drive=DOS_GetDefaultDrive()+'A';
	char dir[DOS_PATHLENGTH];
	dir[0] = 0; //DOS_GetCurrentDir doesn't always return something. (if drive is messed up)
	DOS_GetCurrentDir(0,dir);
	WriteOut("%c:\\%s>",drive,dir);
}
예제 #3
0
bool DOS_GetFreeDiskSpace(Bit8u drive,Bit16u * bytes,Bit8u * sectors,Bit16u * clusters,Bit16u * free) {
    if (drive==0) drive=DOS_GetDefaultDrive();
    else drive--;
    if ((drive>=DOS_DRIVES) || (!Drives[drive])) {
        DOS_SetError(DOSERR_INVALID_DRIVE);
        return false;
    }
    return Drives[drive]->AllocationInfo(bytes,sectors,clusters,free);
}
예제 #4
0
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);
			}
		}
	}
}
예제 #5
0
bool DOS_GetCurrentDir(Bit8u drive,char * const buffer) {
    if (drive==0) drive=DOS_GetDefaultDrive();
    else drive--;
    if ((drive>=DOS_DRIVES) || (!Drives[drive])) {
        DOS_SetError(DOSERR_INVALID_DRIVE);
        return false;
    }
    strcpy(buffer,Drives[drive]->curdir);
    return true;
}
예제 #6
0
파일: dos_files.cpp 프로젝트: Avin15/dospad
bool DOS_GetAllocationInfo(Bit8u drive,Bit16u * _bytes_sector,Bit8u * _sectors_cluster,Bit16u * _total_clusters) {
	if (!drive) drive =  DOS_GetDefaultDrive();
	else drive--;
	if (drive >= DOS_DRIVES || !Drives[drive]) return false;
	Bit16u _free_clusters;
	Drives[drive]->AllocationInfo(_bytes_sector,_sectors_cluster,_total_clusters,&_free_clusters);
	SegSet16(ds,RealSeg(dos.tables.mediaid));
	reg_bx=RealOff(dos.tables.mediaid+drive*2);
	return true;
}
예제 #7
0
파일: dos_files.cpp 프로젝트: rhenssel/vDos
bool DOS_MakeName(char const* const name, char* fullname, Bit8u* drive)				// Nb, returns path w/o leading '\\'!
	{

	char makename_out[MAX_PATH]; // This will make sure that the PathCanonicalize function doesn't fail.
	char makename_in[DOS_PATHLENGTH * 2];

	if (!name || *name == 0 || *name == ' ')										// Both \0 and space are seperators and empty filenames report file not found
		{
		DOS_SetError(DOSERR_FILE_NOT_FOUND);
		return false;
		}
	char const* name_ptr = name;
	if (name_ptr[1] == ':')															// First get the drive
		{
		*drive = (*name_ptr | 0x20)-'a';
		name_ptr += 2;
		}
	else
		*drive = DOS_GetDefaultDrive();
	if (*drive >= DOS_DRIVES || !Drives[*drive] || strlen(name_ptr) >= DOS_PATHLENGTH)
		{ 
		DOS_SetError(DOSERR_PATH_NOT_FOUND);
		return false; 
		}
	char * oPtr = makename_in;
	if (*name_ptr != '\\' && *name_ptr != '/' && *Drives[*drive]->curdir)
		oPtr += strlen(strcat(strcat(strcpy(oPtr, "\\"), Drives[*drive]->curdir), "\\"));
	char const * iPtr = name_ptr;
	for (int sRem = 0; *iPtr; iPtr++)												// Strip bare filenames and extensions from trailing spaces
		{
		if (*iPtr == ' ')
			sRem++;
		else
			{
			if (*iPtr != '.' && *iPtr != '\\')
				for (; sRem; sRem--)
					*oPtr++ = ' ';
			else
				sRem = 0;
			*oPtr++ = *iPtr;
			}
		}
	*oPtr = 0;
	if (!(PathCanonicalize(makename_out, makename_in) && NormalizePath(makename_out))) { 
		DOS_SetError(DOSERR_PATH_NOT_FOUND);
		return false; 
	}
	
	if ( strlen(makename_out) >= DOS_PATHLENGTH ) { // Make sure that we dont try to create a path that is longer than DOS_PATHLENGTH (80 chars)
		DOS_SetError(DOSERR_PATH_NOT_FOUND);
		return false;
	}
	strcpy(fullname, makename_out + (*makename_out =='\\' ? 1 : 0));				// Leading '\\' dropped again
	return true;	
}
예제 #8
0
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;
}
예제 #9
0
파일: shell.cpp 프로젝트: KitoHo/iDOS
void DOS_Shell::Run(void) {
	char input_line[CMD_MAXLINE] = {0};
	std::string line;
	if (cmd->FindStringRemain("/C",line)) {
		strcpy(input_line,line.c_str());
		char* sep = strpbrk(input_line,"\r\n"); //GTA installer
		if (sep) *sep = 0;
		DOS_Shell temp;
		temp.echo = echo;
		temp.ParseLine(input_line);		//for *.exe *.com  |*.bat creates the bf needed by runinternal;
		temp.RunInternal();				// exits when no bf is found.
		return;
	}
	/* Start a normal shell and check for a first command init */
	WriteOut(MSG_Get("SHELL_STARTUP_BEGIN"),VERSION);
#if C_DEBUG
	WriteOut(MSG_Get("SHELL_STARTUP_DEBUG"));
#endif
	if (machine == MCH_CGA) WriteOut(MSG_Get("SHELL_STARTUP_CGA"));
	if (machine == MCH_HERC) WriteOut(MSG_Get("SHELL_STARTUP_HERC"));
	WriteOut(MSG_Get("SHELL_STARTUP_END"));

#ifdef IPHONEOS                        
    if (automount_path[0]) {
        char *p = (char*)automount_path;
        char *endp = p;
        char disk = 'c';
        LOG_MSG("DOS_Shell::Run Auto Mount");
        
        while (endp) {
            for (p = endp; *endp && *endp != ';'; endp++)
                ;
            if (*endp == ';') {
                *endp = 0; 
                endp++;
            } else {
                endp=0;
            }
            if (strlen(p) <= 0) break;
            sprintf(input_line, "mount %c \"%s\"",disk, p);
            ParseLine(input_line);
            disk++;
        }
        if (disk > 'c') {
            sprintf(input_line, "c:");
            ParseLine(input_line);
        }
    }
#endif       
    
	if (cmd->FindString("/INIT",line,true)) {
		strcpy(input_line,line.c_str());
		line.erase();
		ParseLine(input_line);
	}
	do {
		if (bf){
			if(bf->ReadLine(input_line)) {
				if (echo) {
					if (input_line[0]!='@') {
						ShowPrompt();
						WriteOut_NoParsing(input_line);
						WriteOut_NoParsing("\n");
					};
				};
				ParseLine(input_line);
				if (echo) WriteOut("\n");
			}
#ifdef IPHONEOS                        
        } else if (automount_path[0]) {
            automount_path[0] = 0;
            if (echo && !bf) WriteOut_NoParsing("\n");
            sprintf(input_line, "cls");
            ParseLine(input_line);
#endif                    
		} else {
			if (echo) ShowPrompt();
#ifdef IPHONEOS
            dospad_command_line_ready=1;
#endif
			InputCommand(input_line);
#ifdef IPHONEOS
            dospad_add_history(input_line);
            dospad_command_line_ready=0;
            if (dospad_should_launch_game)
            {
                // Make sure we can access the new installed files
                Bit8u drive = DOS_GetDefaultDrive();
                if (Drives[drive]) {
                    Drives[drive]->EmptyCache();
                }                
                FILE *fp=fopen(dospad_launch_config, "r");
                if (fp != NULL)
                {
                    char buf[256];
                    int sectionLength = strlen(dospad_launch_section);
                    while (fgets(buf, 256, fp))
                    {
                        if (strncmp(buf, dospad_launch_section, sectionLength) == 0)
                        {
                            while (fgets(buf, 256, fp))
                            {
                                if (buf[0] == '[') break;
                                if (buf[0] == '#') continue;
                                ParseLine(buf);
                            }
                        }
                    }
                    fclose(fp);
                }
                dospad_should_launch_game = 0;
                sprintf(input_line,"cls");
                dospad_launch_done();
            }
#endif
			ParseLine(input_line);
			if (echo && !bf) WriteOut_NoParsing("\n");
		}
	} while (!exit);
}
예제 #10
0
static Bitu DOS_21Handler(void) {
	if (((reg_ah != 0x50) && (reg_ah != 0x51) && (reg_ah != 0x62) && (reg_ah != 0x64)) && (reg_ah<0x6c)) {
		DOS_PSP psp(dos.psp());
		psp.SetStack(RealMake(SegValue(ss),reg_sp-18));
	}

	char name1[DOSNAMEBUF+2+DOS_NAMELENGTH_ASCII];
	char name2[DOSNAMEBUF+2+DOS_NAMELENGTH_ASCII];
	
	static Bitu time_start = 0; //For emulating temporary time changes.

	switch (reg_ah) {
	case 0x00:		/* Terminate Program */
		DOS_Terminate(mem_readw(SegPhys(ss)+reg_sp+2),false,0);
		break;
	case 0x01:		/* Read character from STDIN, with echo */
		{	
			Bit8u c;Bit16u n=1;
			dos.echo=true;
			DOS_ReadFile(STDIN,&c,&n);
			reg_al=c;
			dos.echo=false;
		}
		break;
	case 0x02:		/* Write character to STDOUT */
		{
			Bit8u c=reg_dl;Bit16u n=1;
			DOS_WriteFile(STDOUT,&c,&n);
			//Not in the official specs, but happens nonetheless. (last written character)
			reg_al = c;// reg_al=(c==9)?0x20:c; //Officially: tab to spaces
		}
		break;
	case 0x03:		/* Read character from STDAUX */
		{
			Bit16u port = real_readw(0x40,0);
			if(port!=0 && serialports[0]) {
				Bit8u status;
				// RTS/DTR on
				IO_WriteB(port+4,0x3);
				serialports[0]->Getchar(&reg_al, &status, true, 0xFFFFFFFF);
			}
		}
		break;
	case 0x04:		/* Write Character to STDAUX */
		{
			Bit16u port = real_readw(0x40,0);
			if(port!=0 && serialports[0]) {
				// RTS/DTR on
				IO_WriteB(port+4,0x3);
				serialports[0]->Putchar(reg_dl,true,true, 0xFFFFFFFF);
				// RTS off
				IO_WriteB(port+4,0x1);
			}
		}
		break;
	case 0x05:		/* Write Character to PRINTER */
		E_Exit("DOS:Unhandled call %02X",reg_ah);
		break;
	case 0x06:		/* Direct Console Output / Input */
		switch (reg_dl) {
		case 0xFF:	/* Input */
			{	
				//Simulate DOS overhead for timing sensitive games
				//MM1
				overhead();
				//TODO Make this better according to standards
				if (!DOS_GetSTDINStatus()) {
					reg_al=0;
					CALLBACK_SZF(true);
					break;
				}
				Bit8u c;Bit16u n=1;
				DOS_ReadFile(STDIN,&c,&n);
				reg_al=c;
				CALLBACK_SZF(false);
				break;
			}
		default:
			{
				Bit8u c = reg_dl;Bit16u n = 1;
				DOS_WriteFile(STDOUT,&c,&n);
				reg_al = reg_dl;
			}
			break;
		};
		break;
	case 0x07:		/* Character Input, without echo */
		{
				Bit8u c;Bit16u n=1;
				DOS_ReadFile (STDIN,&c,&n);
				reg_al=c;
				break;
		};
	case 0x08:		/* Direct Character Input, without echo (checks for breaks officially :)*/
		{
				Bit8u c;Bit16u n=1;
				DOS_ReadFile (STDIN,&c,&n);
				reg_al=c;
				break;
		};
	case 0x09:		/* Write string to STDOUT */
		{	
			Bit8u c;Bit16u n=1;
			PhysPt buf=SegPhys(ds)+reg_dx;
			while ((c=mem_readb(buf++))!='$') {
				DOS_WriteFile(STDOUT,&c,&n);
			}
		}
		break;
	case 0x0a:		/* Buffered Input */
		{
			//TODO ADD Break checkin in STDIN but can't care that much for it
			PhysPt data=SegPhys(ds)+reg_dx;
			Bit8u free=mem_readb(data);
			Bit8u read=0;Bit8u c;Bit16u n=1;
			if (!free) break;
			free--;
			for(;;) {
				DOS_ReadFile(STDIN,&c,&n);
				if (c == 8) {			// Backspace
					if (read) {	//Something to backspace.
						// STDOUT treats backspace as non-destructive.
						         DOS_WriteFile(STDOUT,&c,&n);
						c = ' '; DOS_WriteFile(STDOUT,&c,&n);
						c = 8;   DOS_WriteFile(STDOUT,&c,&n);
						--read;
					}
					continue;
				}
				if (read == free && c != 13) {		// Keyboard buffer full
					Bit8u bell = 7;
					DOS_WriteFile(STDOUT, &bell, &n);
					continue;
				}
				DOS_WriteFile(STDOUT,&c,&n);
				mem_writeb(data+read+2,c);
				if (c==13) 
					break;
				read++;
			};
			mem_writeb(data+1,read);
			break;
		};
	case 0x0b:		/* Get STDIN Status */
		if (!DOS_GetSTDINStatus()) {reg_al=0x00;}
		else {reg_al=0xFF;}
		//Simulate some overhead for timing issues
		//Tankwar menu (needs maybe even more)
		overhead();
		break;
	case 0x0c:		/* Flush Buffer and read STDIN call */
		{
			/* flush buffer if STDIN is CON */
			Bit8u handle=RealHandle(STDIN);
			if (handle!=0xFF && Files[handle] && Files[handle]->IsName("CON")) {
				Bit8u c;Bit16u n;
				while (DOS_GetSTDINStatus()) {
					n=1;	DOS_ReadFile(STDIN,&c,&n);
				}
			}
			switch (reg_al) {
			case 0x1:
			case 0x6:
			case 0x7:
			case 0x8:
			case 0xa:
				{ 
					Bit8u oldah=reg_ah;
					reg_ah=reg_al;
					DOS_21Handler();
					reg_ah=oldah;
				}
				break;
			default:
//				LOG_ERROR("DOS:0C:Illegal Flush STDIN Buffer call %d",reg_al);
				reg_al=0;
				break;
			}
		}
		break;
//TODO Find out the values for when reg_al!=0
//TODO Hope this doesn't do anything special
	case 0x0d:		/* Disk Reset */
//Sure let's reset a virtual disk
		break;	
	case 0x0e:		/* Select Default Drive */
		DOS_SetDefaultDrive(reg_dl);
		reg_al=DOS_DRIVES;
		break;
	case 0x0f:		/* Open File using FCB */
		if(DOS_FCBOpen(SegValue(ds),reg_dx)){
			reg_al=0;
		}else{
			reg_al=0xff;
		}
		LOG(LOG_FCB,LOG_NORMAL)("DOS:0x0f FCB-fileopen used, result:al=%d",reg_al);
		break;
	case 0x10:		/* Close File using FCB */
		if(DOS_FCBClose(SegValue(ds),reg_dx)){
			reg_al=0;
		}else{
			reg_al=0xff;
		}
		LOG(LOG_FCB,LOG_NORMAL)("DOS:0x10 FCB-fileclose used, result:al=%d",reg_al);
		break;
	case 0x11:		/* Find First Matching File using FCB */
		if(DOS_FCBFindFirst(SegValue(ds),reg_dx)) reg_al = 0x00;
		else reg_al = 0xFF;
		LOG(LOG_FCB,LOG_NORMAL)("DOS:0x11 FCB-FindFirst used, result:al=%d",reg_al);
		break;
	case 0x12:		/* Find Next Matching File using FCB */
		if(DOS_FCBFindNext(SegValue(ds),reg_dx)) reg_al = 0x00;
		else reg_al = 0xFF;
		LOG(LOG_FCB,LOG_NORMAL)("DOS:0x12 FCB-FindNext used, result:al=%d",reg_al);
		break;
	case 0x13:		/* Delete File using FCB */
		if (DOS_FCBDeleteFile(SegValue(ds),reg_dx)) reg_al = 0x00;
		else reg_al = 0xFF;
		LOG(LOG_FCB,LOG_NORMAL)("DOS:0x16 FCB-Delete used, result:al=%d",reg_al);
		break;
	case 0x14:		/* Sequential read from FCB */
		reg_al = DOS_FCBRead(SegValue(ds),reg_dx,0);
		LOG(LOG_FCB,LOG_NORMAL)("DOS:0x14 FCB-Read used, result:al=%d",reg_al);
		break;
	case 0x15:		/* Sequential write to FCB */
		reg_al=DOS_FCBWrite(SegValue(ds),reg_dx,0);
		LOG(LOG_FCB,LOG_NORMAL)("DOS:0x15 FCB-Write used, result:al=%d",reg_al);
		break;
	case 0x16:		/* Create or truncate file using FCB */
		if (DOS_FCBCreate(SegValue(ds),reg_dx)) reg_al = 0x00;
		else reg_al = 0xFF;
		LOG(LOG_FCB,LOG_NORMAL)("DOS:0x16 FCB-Create used, result:al=%d",reg_al);
		break;
	case 0x17:		/* Rename file using FCB */		
		if (DOS_FCBRenameFile(SegValue(ds),reg_dx)) reg_al = 0x00;
		else reg_al = 0xFF;
		break;
	case 0x1b:		/* Get allocation info for default drive */	
		if (!DOS_GetAllocationInfo(0,&reg_cx,&reg_al,&reg_dx)) reg_al=0xff;
		break;
	case 0x1c:		/* Get allocation info for specific drive */
		if (!DOS_GetAllocationInfo(reg_dl,&reg_cx,&reg_al,&reg_dx)) reg_al=0xff;
		break;
	case 0x21:		/* Read random record from FCB */
		{
			Bit16u toread=1;
			reg_al = DOS_FCBRandomRead(SegValue(ds),reg_dx,&toread,true);
		}
		LOG(LOG_FCB,LOG_NORMAL)("DOS:0x21 FCB-Random read used, result:al=%d",reg_al);
		break;
	case 0x22:		/* Write random record to FCB */
		{
			Bit16u towrite=1;
			reg_al=DOS_FCBRandomWrite(SegValue(ds),reg_dx,&towrite,true);
		}
		LOG(LOG_FCB,LOG_NORMAL)("DOS:0x22 FCB-Random write used, result:al=%d",reg_al);
		break;
	case 0x23:		/* Get file size for FCB */
		if (DOS_FCBGetFileSize(SegValue(ds),reg_dx)) reg_al = 0x00;
		else reg_al = 0xFF;
		break;
	case 0x24:		/* Set Random Record number for FCB */
		DOS_FCBSetRandomRecord(SegValue(ds),reg_dx);
		break;
	case 0x27:		/* Random block read from FCB */
		reg_al = DOS_FCBRandomRead(SegValue(ds),reg_dx,&reg_cx,false);
		LOG(LOG_FCB,LOG_NORMAL)("DOS:0x27 FCB-Random(block) read used, result:al=%d",reg_al);
		break;
	case 0x28:		/* Random Block write to FCB */
		reg_al=DOS_FCBRandomWrite(SegValue(ds),reg_dx,&reg_cx,false);
		LOG(LOG_FCB,LOG_NORMAL)("DOS:0x28 FCB-Random(block) write used, result:al=%d",reg_al);
		break;
	case 0x29:		/* Parse filename into FCB */
		{   
			Bit8u difference;
			char string[1024];
			MEM_StrCopy(SegPhys(ds)+reg_si,string,1023); // 1024 toasts the stack
			reg_al=FCB_Parsename(SegValue(es),reg_di,reg_al ,string, &difference);
			reg_si+=difference;
		}
		LOG(LOG_FCB,LOG_NORMAL)("DOS:29:FCB Parse Filename, result:al=%d",reg_al);
		break;
	case 0x19:		/* Get current default drive */
		reg_al=DOS_GetDefaultDrive();
		break;
	case 0x1a:		/* Set Disk Transfer Area Address */
		dos.dta(RealMakeSeg(ds,reg_dx));
		break;
	case 0x25:		/* Set Interrupt Vector */
		RealSetVec(reg_al,RealMakeSeg(ds,reg_dx));
		break;
	case 0x26:		/* Create new PSP */
		DOS_NewPSP(reg_dx,DOS_PSP(dos.psp()).GetSize());
		reg_al=0xf0;	/* al destroyed */		
		break;
	case 0x2a:		/* Get System Date */
		{
			reg_ax=0; // get time
			CALLBACK_RunRealInt(0x1a);
			if(reg_al) DOS_AddDays(reg_al);
			int a = (14 - dos.date.month)/12;
			int y = dos.date.year - a;
			int m = dos.date.month + 12*a - 2;
			reg_al=(dos.date.day+y+(y/4)-(y/100)+(y/400)+(31*m)/12) % 7;
			reg_cx=dos.date.year;
			reg_dh=dos.date.month;
			reg_dl=dos.date.day;
		}
		break;
	case 0x2b:		/* Set System Date */
		if (reg_cx<1980) { reg_al=0xff;break;}
		if ((reg_dh>12) || (reg_dh==0))	{ reg_al=0xff;break;}
		if (reg_dl==0) { reg_al=0xff;break;}
 		if (reg_dl>DOS_DATE_months[reg_dh]) {
			if(!((reg_dh==2)&&(reg_cx%4 == 0)&&(reg_dl==29))) // february pass
			{ reg_al=0xff;break; }
		}
		dos.date.year=reg_cx;
		dos.date.month=reg_dh;
		dos.date.day=reg_dl;
		reg_al=0;
		break;
	case 0x2c: {	/* Get System Time */
		reg_ax=0; // get time
		CALLBACK_RunRealInt(0x1a);
		if(reg_al) DOS_AddDays(reg_al);
		reg_ah=0x2c;

		Bitu ticks=((Bitu)reg_cx<<16)|reg_dx;
		if(time_start<=ticks) ticks-=time_start;
		Bitu time=(Bitu)((100.0/((double)PIT_TICK_RATE/65536.0)) * (double)ticks);

		reg_dl=(Bit8u)((Bitu)time % 100); // 1/100 seconds
		time/=100;
		reg_dh=(Bit8u)((Bitu)time % 60); // seconds
		time/=60;
		reg_cl=(Bit8u)((Bitu)time % 60); // minutes
		time/=60;
		reg_ch=(Bit8u)((Bitu)time % 24); // hours

		//Simulate DOS overhead for timing-sensitive games
        //Robomaze 2
		overhead();
		break;
	}
	case 0x2d:		/* Set System Time */
		LOG(LOG_DOSMISC,LOG_ERROR)("DOS:Set System Time not supported");
		//Check input parameters nonetheless
		if( reg_ch > 23 || reg_cl > 59 || reg_dh > 59 || reg_dl > 99 )
			reg_al = 0xff; 
		else { //Allow time to be set to zero. Restore the orginal time for all other parameters. (QuickBasic)
			if (reg_cx == 0 && reg_dx == 0) {time_start = mem_readd(BIOS_TIMER);LOG_MSG("Warning: game messes with DOS time!");}
			else time_start = 0;
			reg_al = 0;
		}
		break;
	case 0x2e:		/* Set Verify flag */
		dos.verify=(reg_al==1);
		break;
	case 0x2f:		/* Get Disk Transfer Area */
		SegSet16(es,RealSeg(dos.dta()));
		reg_bx=RealOff(dos.dta());
		break;
	case 0x30:		/* Get DOS Version */
		if (reg_al==0) reg_bh=0xFF;		/* Fake Microsoft DOS */
		if (reg_al==1) reg_bh=0x10;		/* DOS is in HMA */
		reg_al=dos.version.major;
		reg_ah=dos.version.minor;
		/* Serialnumber */
		reg_bl=0x00;
		reg_cx=0x0000;
		break;
	case 0x31:		/* Terminate and stay resident */
		// Important: This service does not set the carry flag!
		DOS_ResizeMemory(dos.psp(),&reg_dx);
		DOS_Terminate(dos.psp(),true,reg_al);
		break;
	case 0x1f: /* Get drive parameter block for default drive */
	case 0x32: /* Get drive parameter block for specific drive */
		{	/* Officially a dpb should be returned as well. The disk detection part is implemented */
			Bit8u drive=reg_dl;
			if (!drive || reg_ah==0x1f) drive = DOS_GetDefaultDrive();
			else drive--;
			if (Drives[drive]) {
				reg_al = 0x00;
				SegSet16(ds,dos.tables.dpb);
				reg_bx = drive;//Faking only the first entry (that is the driveletter)
				LOG(LOG_DOSMISC,LOG_ERROR)("Get drive parameter block.");
			} else {
				reg_al=0xff;
			}
		}
		break;
	case 0x33:		/* Extended Break Checking */
		switch (reg_al) {
			case 0:reg_dl=dos.breakcheck;break;			/* Get the breakcheck flag */
			case 1:dos.breakcheck=(reg_dl>0);break;		/* Set the breakcheck flag */
			case 2:{bool old=dos.breakcheck;dos.breakcheck=(reg_dl>0);reg_dl=old;}break;
			case 3: /* Get cpsw */
				/* Fallthrough */
			case 4: /* Set cpsw */
				LOG(LOG_DOSMISC,LOG_ERROR)("Someone playing with cpsw %x",reg_ax);
				break;
			case 5:reg_dl=3;break;//TODO should be z						/* Always boot from c: :) */
			case 6:											/* Get true version number */
				reg_bl=dos.version.major;
				reg_bh=dos.version.minor;
				reg_dl=dos.version.revision;
				reg_dh=0x10;								/* Dos in HMA */
				break;
			default:
				LOG(LOG_DOSMISC,LOG_ERROR)("Weird 0x33 call %2X",reg_al);
				reg_al =0xff;
				break;
		}
		break;
	case 0x34:		/* Get INDos Flag */
		SegSet16(es,DOS_SDA_SEG);
		reg_bx=DOS_SDA_OFS + 0x01;
		break;
	case 0x35:		/* Get interrupt vector */
		reg_bx=real_readw(0,((Bit16u)reg_al)*4);
		SegSet16(es,real_readw(0,((Bit16u)reg_al)*4+2));
		break;
	case 0x36:		/* Get Free Disk Space */
		{
			Bit16u bytes,clusters,free;
			Bit8u sectors;
			if (DOS_GetFreeDiskSpace(reg_dl,&bytes,&sectors,&clusters,&free)) {
				reg_ax=sectors;
				reg_bx=free;
				reg_cx=bytes;
				reg_dx=clusters;
			} else {
				Bit8u drive=reg_dl;
				if (drive==0) drive=DOS_GetDefaultDrive();
				else drive--;
				if (drive<2) {
					// floppy drive, non-present drivesdisks issue floppy check through int24
					// (critical error handler); needed for Mixed up Mother Goose (hook)
//					CALLBACK_RunRealInt(0x24);
				}
				reg_ax=0xffff;	// invalid drive specified
			}
		}
		break;
	case 0x37:		/* Get/Set Switch char Get/Set Availdev thing */
//TODO	Give errors for these functions to see if anyone actually uses this shit-
		switch (reg_al) {
		case 0:
			 reg_al=0;reg_dl=0x2f;break;  /* always return '/' like dos 5.0+ */
		case 1:
			 reg_al=0;break;
		case 2:
			 reg_al=0;reg_dl=0x2f;break;
		case 3:
			 reg_al=0;break;
		};
		LOG(LOG_MISC,LOG_ERROR)("DOS:0x37:Call for not supported switchchar");
		break;
	case 0x38:					/* Set Country Code */	
		if (reg_al==0) {		/* Get country specidic information */
			PhysPt dest = SegPhys(ds)+reg_dx;
			MEM_BlockWrite(dest,dos.tables.country,0x18);
			reg_ax = reg_bx = 0x01;
			CALLBACK_SCF(false);
			break;
		} else {				/* Set country code */
			LOG(LOG_MISC,LOG_ERROR)("DOS:Setting country code not supported");
		}
		CALLBACK_SCF(true);
		break;
	case 0x39:		/* MKDIR Create directory */
		MEM_StrCopy(SegPhys(ds)+reg_dx,name1,DOSNAMEBUF);
		if (DOS_MakeDir(name1)) {
			reg_ax=0x05;	/* ax destroyed */
			CALLBACK_SCF(false);
		} else {
			reg_ax=dos.errorcode;
			CALLBACK_SCF(true);
		}
		break;
	case 0x3a:		/* RMDIR Remove directory */
		MEM_StrCopy(SegPhys(ds)+reg_dx,name1,DOSNAMEBUF);
		if  (DOS_RemoveDir(name1)) {
			reg_ax=0x05;	/* ax destroyed */
			CALLBACK_SCF(false);
		} else {
			reg_ax=dos.errorcode;
			CALLBACK_SCF(true);
			LOG(LOG_MISC,LOG_NORMAL)("Remove dir failed on %s with error %X",name1,dos.errorcode);
		}
		break;
	case 0x3b:		/* CHDIR Set current directory */
		MEM_StrCopy(SegPhys(ds)+reg_dx,name1,DOSNAMEBUF);
		if  (DOS_ChangeDir(name1)) {
			reg_ax=0x00;	/* ax destroyed */
			CALLBACK_SCF(false);
		} else {
			reg_ax=dos.errorcode;
			CALLBACK_SCF(true);
		}
		break;
	case 0x3c:		/* CREATE Create of truncate file */
		MEM_StrCopy(SegPhys(ds)+reg_dx,name1,DOSNAMEBUF);
		if (DOS_CreateFile(name1,reg_cx,&reg_ax)) {
			CALLBACK_SCF(false);
		} else {
			reg_ax=dos.errorcode;
			CALLBACK_SCF(true);
		}
		break;
	case 0x3d:		/* OPEN Open existing file */
		MEM_StrCopy(SegPhys(ds)+reg_dx,name1,DOSNAMEBUF);
		if (DOS_OpenFile(name1,reg_al,&reg_ax)) {
			CALLBACK_SCF(false);
		} else {
			reg_ax=dos.errorcode;
			CALLBACK_SCF(true);
		}
		break;
	case 0x3e:		/* CLOSE Close file */
		if (DOS_CloseFile(reg_bx)) {
//			reg_al=0x01;	/* al destroyed. Refcount */
			CALLBACK_SCF(false);
		} else {
			reg_ax=dos.errorcode;
			CALLBACK_SCF(true);
		}
		break;
	case 0x3f:		/* READ Read from file or device */
		{ 
			Bit16u toread=reg_cx;
			dos.echo=true;
			if (DOS_ReadFile(reg_bx,dos_copybuf,&toread)) {
				MEM_BlockWrite(SegPhys(ds)+reg_dx,dos_copybuf,toread);
				reg_ax=toread;
				CALLBACK_SCF(false);
			} else {
				reg_ax=dos.errorcode;
				CALLBACK_SCF(true);
			}
			modify_cycles(reg_ax);
			dos.echo=false;
			break;
		}
	case 0x40:					/* WRITE Write to file or device */
		{
			Bit16u towrite=reg_cx;
			MEM_BlockRead(SegPhys(ds)+reg_dx,dos_copybuf,towrite);
			if (DOS_WriteFile(reg_bx,dos_copybuf,&towrite)) {
				reg_ax=towrite;
	   			CALLBACK_SCF(false);
			} else {
				reg_ax=dos.errorcode;
				CALLBACK_SCF(true);
			}
			modify_cycles(reg_ax);
			break;
		};
	case 0x41:					/* UNLINK Delete file */
		MEM_StrCopy(SegPhys(ds)+reg_dx,name1,DOSNAMEBUF);
		if (DOS_UnlinkFile(name1)) {
			CALLBACK_SCF(false);
		} else {
			reg_ax=dos.errorcode;
			CALLBACK_SCF(true);
		}
		break;
	case 0x42:					/* LSEEK Set current file position */
		{
			Bit32u pos=(reg_cx<<16) + reg_dx;
			if (DOS_SeekFile(reg_bx,&pos,reg_al)) {
				reg_dx=(Bit16u)(pos >> 16);
				reg_ax=(Bit16u)(pos & 0xFFFF);
				CALLBACK_SCF(false);
			} else {
				reg_ax=dos.errorcode;
				CALLBACK_SCF(true);
			}
			break;
		}
예제 #11
0
Bit8u DOS_FCB::GetDrive(void) {
	Bit8u drive=(Bit8u)sGet(sFCB,drive);
	if (!drive) return  DOS_GetDefaultDrive();
	else return drive-1;
}
예제 #12
0
bool DOS_IOCTL(void) {
	Bitu handle=0;Bit8u drive=0;
	/* calls 0-4,6,7,10,12,16 use a file handle */
	if ((reg_al<4) || (reg_al==0x06) || (reg_al==0x07) || (reg_al==0x0a) || (reg_al==0x0c) || (reg_al==0x10)) {
		handle=RealHandle(reg_bx);
		if (handle>=DOS_FILES) {
			DOS_SetError(DOSERR_INVALID_HANDLE);
			return false;
		}
		if (!Files[handle]) {
			DOS_SetError(DOSERR_INVALID_HANDLE);
			return false;
		}
	} else if (reg_al<0x12) { 				/* those use a diskdrive except 0x0b */
		if (reg_al!=0x0b) {
			drive=reg_bl;if (!drive) drive = DOS_GetDefaultDrive();else drive--;
			if( !(( drive < DOS_DRIVES ) && Drives[drive]) ) {
				DOS_SetError(DOSERR_INVALID_DRIVE);
				return false;
			}
		}
	} else {
		LOG(LOG_DOSMISC,LOG_ERROR)("DOS:IOCTL Call %2X unhandled",reg_al);
		DOS_SetError(DOSERR_FUNCTION_NUMBER_INVALID);
		return false;
	}
	switch(reg_al) {
	case 0x00:		/* Get Device Information */
		if (Files[handle]->GetInformation() & 0x8000) {	//Check for device
			reg_dx=Files[handle]->GetInformation();
		} else {
			Bit8u hdrive=Files[handle]->GetDrive();
			if (hdrive==0xff) {
				LOG(LOG_IOCTL,LOG_NORMAL)("00:No drive set");
				hdrive=2;	// defaulting to C:
			}
			/* return drive number in lower 5 bits for block devices */
			reg_dx=(Files[handle]->GetInformation()&0xffe0)|hdrive;
		}
		reg_ax=reg_dx; //Destroyed officially
		return true;
	case 0x01:		/* Set Device Information */
		if (reg_dh != 0) {
			DOS_SetError(DOSERR_DATA_INVALID);
			return false;
		} else {
			if (Files[handle]->GetInformation() & 0x8000) {	//Check for device
				reg_al=(Bit8u)(Files[handle]->GetInformation() & 0xff);
			} else {
				DOS_SetError(DOSERR_FUNCTION_NUMBER_INVALID);
				return false;
			}
		}
		return true;
	case 0x02:		/* Read from Device Control Channel */
		if (Files[handle]->GetInformation() & 0xc000) {
			/* is character device with IOCTL support */
			PhysPt bufptr=PhysMake(SegValue(ds),reg_dx);
			Bit16u retcode=0;
			if (((DOS_Device*)(Files[handle]))->ReadFromControlChannel(bufptr,reg_cx,&retcode)) {
				reg_ax=retcode;
				return true;
			}
		}
		DOS_SetError(DOSERR_FUNCTION_NUMBER_INVALID);
		return false;
	case 0x03:		/* Write to Device Control Channel */
		if (Files[handle]->GetInformation() & 0xc000) {
			/* is character device with IOCTL support */
			PhysPt bufptr=PhysMake(SegValue(ds),reg_dx);
			Bit16u retcode=0;
			if (((DOS_Device*)(Files[handle]))->WriteToControlChannel(bufptr,reg_cx,&retcode)) {
				reg_ax=retcode;
				return true;
			}
		}
		DOS_SetError(DOSERR_FUNCTION_NUMBER_INVALID);
		return false;
	case 0x06:      /* Get Input Status */
		if (Files[handle]->GetInformation() & 0x8000) {		//Check for device
			reg_al=(Files[handle]->GetInformation() & 0x40) ? 0x0 : 0xff;
		} else { // FILE
			Bit32u oldlocation=0;
			Files[handle]->Seek(&oldlocation, DOS_SEEK_CUR);
			Bit32u endlocation=0;
			Files[handle]->Seek(&endlocation, DOS_SEEK_END);
			if(oldlocation < endlocation){//Still data available
				reg_al=0xff;
			} else {
				reg_al=0x0; //EOF or beyond
			}
			Files[handle]->Seek(&oldlocation, DOS_SEEK_SET); //restore filelocation
			LOG(LOG_IOCTL,LOG_NORMAL)("06:Used Get Input Status on regular file with handle %d",handle);
		}
		return true;
	case 0x07:		/* Get Output Status */
		LOG(LOG_IOCTL,LOG_NORMAL)("07:Fakes output status is ready for handle %d",handle);
		reg_al=0xff;
		return true;
	case 0x08:		/* Check if block device removable */
		/* cdrom drives and drive a&b are removable */
		if (drive < 2) reg_ax=0;
		else if (!Drives[drive]->isRemovable()) reg_ax=1;
		else {
			DOS_SetError(DOSERR_FUNCTION_NUMBER_INVALID);
			return false;
		}
		return true;
	case 0x09:		/* Check if block device remote */
		if (Drives[drive]->isRemote()) {
			reg_dx=0x1000;	// device is remote
			// undocumented bits always clear
		} else {
			reg_dx=0x0802;	// Open/Close supported; 32bit access supported (any use? fixes Fable installer)
			// undocumented bits from device attribute word
			// TODO Set bit 9 on drives that don't support direct I/O
		}
		reg_ax=0x300;
		return true;
	case 0x0B:		/* Set sharing retry count */
		if (reg_dx==0) {
			DOS_SetError(DOSERR_FUNCTION_NUMBER_INVALID);
			return false;
		}
		return true;
	case 0x0D:		/* Generic block device request */
		{
			if (Drives[drive]->isRemovable()) {
				DOS_SetError(DOSERR_FUNCTION_NUMBER_INVALID);
				return false;
			}
			PhysPt ptr	= SegPhys(ds)+reg_dx;
			switch (reg_cl) {
			case 0x60:		/* Get Device parameters */
				mem_writeb(ptr  ,0x03);					// special function
				mem_writeb(ptr+1,(drive>=2)?0x05:0x14);	// fixed disc(5), 1.44 floppy(14)
				mem_writew(ptr+2,drive>=2);				// nonremovable ?
				mem_writew(ptr+4,0x0000);				// num of cylinders
				mem_writeb(ptr+6,0x00);					// media type (00=other type)
				// drive parameter block following
				mem_writeb(ptr+7,drive);				// drive
				mem_writeb(ptr+8,0x00);					// unit number
				mem_writed(ptr+0x1f,0xffffffff);		// next parameter block
				break;
			case 0x46:
			case 0x66:	/* Volume label */
				{			
					char const* bufin=Drives[drive]->GetLabel();
					char buffer[11] ={' '};

					char const* find_ext=strchr(bufin,'.');
					if (find_ext) {
						Bitu size=(Bitu)(find_ext-bufin);
						if (size>8) size=8;
						memcpy(buffer,bufin,size);
						find_ext++;
						memcpy(buffer+size,find_ext,(strlen(find_ext)>3) ? 3 : strlen(find_ext)); 
					} else {
						memcpy(buffer,bufin,(strlen(bufin) > 8) ? 8 : strlen(bufin));
					}
			
					char buf2[8]={ 'F','A','T','1','6',' ',' ',' '};
					if(drive<2) buf2[4] = '2'; //FAT12 for floppies

					mem_writew(ptr+0,0);			// 0
					mem_writed(ptr+2,0x1234);		//Serial number
					MEM_BlockWrite(ptr+6,buffer,11);//volumename
					if(reg_cl == 0x66) MEM_BlockWrite(ptr+0x11, buf2,8);//filesystem
				}
				break;
			default	:	
				LOG(LOG_IOCTL,LOG_ERROR)("DOS:IOCTL Call 0D:%2X Drive %2X unhandled",reg_cl,drive);
				DOS_SetError(DOSERR_FUNCTION_NUMBER_INVALID);
				return false;
			}
			return true;
		}
	case 0x0E:			/* Get Logical Drive Map */
		if (Drives[drive]->isRemovable()) {
			DOS_SetError(DOSERR_FUNCTION_NUMBER_INVALID);
			return false;
		}
		reg_al = 0;		/* Only 1 logical drive assigned */
		return true;
	default:
		LOG(LOG_DOSMISC,LOG_ERROR)("DOS:IOCTL Call %2X unhandled",reg_al);
		DOS_SetError(DOSERR_FUNCTION_NUMBER_INVALID);
		break;
	}
	return false;
}
예제 #13
0
파일: dos_ioctl.cpp 프로젝트: rhenssel/vDos
bool DOS_IOCTL(void)
	{
	Bitu handle = 0;
	Bit8u drive = 0;
	// calls 0-4,6,7,10,12,16 use a file handle
	if ((reg_al < 4) || (reg_al == 0x06) || (reg_al == 0x07) || (reg_al == 0x0a) || (reg_al == 0x0c) || (reg_al == 0x10))
		{
		handle = RealHandle(reg_bx);
		if (handle >= DOS_FILES || !Files[handle])
			{
			DOS_SetError(DOSERR_INVALID_HANDLE);
			return false;
			}
		}
	else if (reg_al < 0x12)
		{ 				// those use a diskdrive except 0x0b
		if (reg_al != 0x0b)
			{
			drive = reg_bl;
			if (!drive)
				drive = DOS_GetDefaultDrive();
			else
				drive--;
			if (!((drive < DOS_DRIVES) && Drives[drive]))
				{
				DOS_SetError(DOSERR_INVALID_DRIVE);
				return false;
				}
			}
		}
	else
		{
		LOG(LOG_DOSMISC, LOG_ERROR)("DOS:IOCTL Call %2X unhandled", reg_al);
		DOS_SetError(DOSERR_FUNCTION_NUMBER_INVALID);
		return false;
		}
	switch (reg_al)
		{
	case 0:		// Get Device Information
		if (Files[handle]->GetInformation() & 0x8000)	// Check for device
			reg_dx = Files[handle]->GetInformation();
		else
			{
			Bit8u hdrive = Files[handle]->GetDrive();
			if (hdrive == 0xff)
				hdrive = 2;		// defaulting to C:
			// return drive number in lower 5 bits for block devices
			reg_dx = (Files[handle]->GetInformation()&0xffe0)|hdrive;
			}
		reg_ax = reg_dx;	// Destroyed officially
		return true;
	case 1:		// Set Device Information
		if (reg_dh != 0)
			{
			DOS_SetError(DOSERR_DATA_INVALID);
			return false;
			}
		if (Files[handle]->GetInformation() & 0x8000)	// Check for device
			reg_al = (Bit8u)(Files[handle]->GetInformation() & 0xff);
		else
			{
			DOS_SetError(DOSERR_FUNCTION_NUMBER_INVALID);
			return false;
			}
		return true;
	case 2:		// Read from Device Control Channel
		DOS_SetError(DOSERR_FUNCTION_NUMBER_INVALID);
		return false;
	case 3:		// Write to Device Control Channel
		DOS_SetError(DOSERR_FUNCTION_NUMBER_INVALID);
		return false;
	case 6:      // Get Input Status
		if (Files[handle]->GetInformation() & 0x8000)		// Check for device
			reg_al = (Files[handle]->GetInformation() & 0x40) ? 0 : 0xff;
		else
			{	// FILE
			Bit32u oldlocation = 0;
			Files[handle]->Seek(&oldlocation, DOS_SEEK_CUR);
			Bit32u endlocation = 0;
			Files[handle]->Seek(&endlocation, DOS_SEEK_END);
			if (oldlocation < endlocation)
				reg_al = 0xff;		// Still data available
			else
				reg_al = 0;			//EOF or beyond
			Files[handle]->Seek(&oldlocation, DOS_SEEK_SET);	// restore filelocation
			}
		return true;
	case 7:		// Get Output Status
		reg_al = 0xff;
		return true;
	case 8:		// Check if block device removable
		reg_ax = 1;
		return true;
	case 9:		// Check if block device remote
		reg_dx = 0x0802;	// Open/Close supported; 32bit access supported (any use? fixes Fable installer)
		// undocumented bits from device attribute word
		// TODO Set bit 9 on drives that don't support direct I/O
		reg_ax = 0x300;
		return true;
	case 0x0A:		// Is Device or Handle Remote?
		reg_dx = 0;			// No!
		return true;
	case 0x0B:		// Set sharing retry count
		return true;
	case 0x0D:		// Generic block device request
		{
		PhysPt ptr = SegPhys(ds)+reg_dx;
		switch (reg_cl)
			{
		case 0x60:		// Get Device parameters
			vPC_rStosb(ptr, 3);								// special function
			vPC_rStosb(ptr+1, (drive>=2) ? 0x05 : 0x14);	// fixed disc(5), 1.44 floppy(14)
			vPC_rStosw(ptr+2, drive >= 2);					// nonremovable ?
			vPC_rStosw(ptr+4, 0);							// num of cylinders
			vPC_rStosb(ptr+6, 0);							// media type (00=other type)
			// drive parameter block following
			vPC_rStosb(ptr+7, drive);						// drive
			vPC_rStosb(ptr+8, 0);							// unit number
			vPC_rStosd(ptr+0x1f, 0xffffffff);				// next parameter block
			break;
		case 0x46:
		case 0x66:	// Volume label
			{			
			char const* bufin = Drives[drive]->GetLabel();
			char buffer[11] ={' '};

			char const* find_ext = strchr(bufin,'.');
			if (find_ext)
				{
				Bitu size = (Bitu)(find_ext-bufin);
				if (size > 8)
					size = 8;
				memcpy(buffer, bufin,size);
				find_ext++;
				memcpy(buffer+size, find_ext, (strlen(find_ext)>3) ? 3 : strlen(find_ext)); 
				}
			else
				memcpy(buffer,bufin, (strlen(bufin) > 8) ? 8 : strlen(bufin));
			
			char buf2[8]={ 'F','A','T','1','6',' ',' ',' '};
			if (drive < 2)
				buf2[4] = '2';						// FAT12 for floppies
			vPC_rStosw(ptr+0, 0);					// 0
			vPC_rStosd(ptr+2, 0x1234);				// Serial number
			vPC_rBlockWrite(ptr+6, buffer,11);		// volumename
			if (reg_cl == 0x66)
				vPC_rBlockWrite(ptr+0x11, buf2, 8);	// filesystem
			}
			break;
		default	:	
			LOG(LOG_IOCTL, LOG_ERROR)("DOS:IOCTL Call 0D:%2X Drive %2X unhandled", reg_cl, drive);
			DOS_SetError(DOSERR_FUNCTION_NUMBER_INVALID);
			return false;
			}
		return true;
		}
	case 0x0E:										// Get Logical Drive Map
		reg_al = 0;									// Only 1 logical drive assigned
		return true;
	default:
		LOG(LOG_DOSMISC, LOG_ERROR)("DOS:IOCTL Call %2X unhandled", reg_al);
		DOS_SetError(DOSERR_FUNCTION_NUMBER_INVALID);
		break;
		}
	return false;
	}
예제 #14
0
bool DOS_MakeName(char const * const name,char * const fullname,Bit8u * drive) {
    if(!name || *name == 0 || *name == ' ') {
        /* Both \0 and space are seperators and
         * empty filenames report file not found */
        DOS_SetError(DOSERR_FILE_NOT_FOUND);
        return false;
    }
    const char * name_int = name;
    char tempdir[DOS_PATHLENGTH];
    char upname[DOS_PATHLENGTH];
    Bitu r,w;
    Bit8u c;
    *drive = DOS_GetDefaultDrive();
    /* First get the drive */
    if (name_int[1]==':') {
        *drive=(name_int[0] | 0x20)-'a';
        name_int+=2;
    }
    if (*drive>=DOS_DRIVES || !Drives[*drive]) {
        DOS_SetError(DOSERR_PATH_NOT_FOUND);
        return false;
    }
    r=0;
    w=0;
    while (name_int[r]!=0 && (r<DOS_PATHLENGTH)) {
        c=name_int[r++];
        if ((c>='a') && (c<='z')) c-=32;
        else if (c==' ') continue; /* should be separator */
        else if (c=='/') c='\\';
        upname[w++]=c;
    }
    while (r>0 && name_int[r-1]==' ') r--;
    if (r>=DOS_PATHLENGTH) {
        DOS_SetError(DOSERR_PATH_NOT_FOUND);
        return false;
    }
    upname[w]=0;
    /* Now parse the new file name to make the final filename */
    if (upname[0]!='\\') strcpy(fullname,Drives[*drive]->curdir);
    else fullname[0]=0;
    Bit32u lastdir=0;
    Bit32u t=0;
    while (fullname[t]!=0) {
        if ((fullname[t]=='\\') && (fullname[t+1]!=0)) lastdir=t;
        t++;
    };
    r=0;
    w=0;
    tempdir[0]=0;
    bool stop=false;
    while (!stop) {
        if (upname[r]==0) stop=true;
        if ((upname[r]=='\\') || (upname[r]==0)) {
            tempdir[w]=0;
            if (tempdir[0]==0) {
                w=0;
                r++;
                continue;
            }
            if (strcmp(tempdir,".")==0) {
                tempdir[0]=0;
                w=0;
                r++;
                continue;
            }

            Bit32s iDown;
            bool dots = true;
            Bit32s templen=(Bit32s)strlen(tempdir);
            for(iDown=0; (iDown < templen) && dots; iDown++)
                if(tempdir[iDown] != '.')
                    dots = false;

            // only dots?
            if (dots && (templen > 1)) {
                Bit32s cDots = templen - 1;
                for(iDown=(Bit32s)strlen(fullname)-1; iDown>=0; iDown--) {
                    if(fullname[iDown]=='\\' || iDown==0) {
                        lastdir = iDown;
                        cDots--;
                        if(cDots==0)
                            break;
                    }
                }
                fullname[lastdir]=0;
                t=0;
                lastdir=0;
                while (fullname[t]!=0) {
                    if ((fullname[t]=='\\') && (fullname[t+1]!=0)) lastdir=t;
                    t++;
                }
                tempdir[0]=0;
                w=0;
                r++;
                continue;
            }


            lastdir=(Bit32u)strlen(fullname);

            if (lastdir!=0) strcat(fullname,"\\");
            char * ext=strchr(tempdir,'.');
            if (ext) {
                if(strchr(ext+1,'.')) {
                    //another dot in the extension =>file not found
                    //Or path not found depending on wether
                    //we are still in dir check stage or file stage
                    if(stop)
                        DOS_SetError(DOSERR_FILE_NOT_FOUND);
                    else
                        DOS_SetError(DOSERR_PATH_NOT_FOUND);
                    return false;
                }

                ext[4] = 0;
                if((strlen(tempdir) - strlen(ext)) > 8) memmove(tempdir + 8, ext, 5);
            } else tempdir[8]=0;

            for (Bitu i=0; i<strlen(tempdir); i++) {
                c=tempdir[i];
                if ((c>='A') && (c<='Z')) continue;
                if ((c>='0') && (c<='9')) continue;
                switch (c) {
                case '$':
                case '#':
                case '@':
                case '(':
                case ')':
                case '!':
                case '%':
                case '{':
                case '}':
                case '`':
                case '~':
                case '_':
                case '-':
                case '.':
                case '*':
                case '?':
                case '&':
                case '\'':
                case '+':
                case '^':
                case 246:
                case 255:
                case 0xa0:
                case 0xe5:
                case 0xbd:
                case 0x9d:
                    break;
                default:
                    LOG(LOG_FILES,LOG_NORMAL)("Makename encountered an illegal char %c hex:%X in %s!",c,c,name);
                    DOS_SetError(DOSERR_PATH_NOT_FOUND);
                    return false;
                    break;
                }
            }

            if (strlen(fullname)+strlen(tempdir)>=DOS_PATHLENGTH) {
                DOS_SetError(DOSERR_PATH_NOT_FOUND);
                return false;
            }

            strcat(fullname,tempdir);
            tempdir[0]=0;
            w=0;
            r++;
            continue;
        }
        tempdir[w++]=upname[r++];
    }
    return true;
}
예제 #15
0
static Bitu DOS_21Handler(void)
	{
	if (((reg_ah != 0x50) && (reg_ah != 0x51) && (reg_ah != 0x62) && (reg_ah != 0x64)) && (reg_ah < 0x6c))
		if (dos.psp() != 0)															// No program loaded yet?
			{
			DOS_PSP psp(dos.psp());
			psp.SetStack(SegOff2dWord(SegValue(ss), reg_sp-18));
			psp.FindFreeFileEntry();
			}

	char name1[DOSNAMEBUF+2+DOS_NAMELENGTH_ASCII];
	char name2[DOSNAMEBUF+2+DOS_NAMELENGTH_ASCII];
	switch (reg_ah)
		{
	case 0x00:																		// Terminate Program
		DOS_Terminate(Mem_Lodsw(SegPhys(ss)+reg_sp+2), false, 0);
		break;
	case 0x01:																		// Read character from STDIN, with echo
		{
		Bit8u c;
		Bit16u n = 1;
		dos.echo = true;
		DOS_ReadFile(STDIN, &c, &n);
		reg_al = c;
		dos.echo = false;
		}
		break;
	case 0x02:																		// Write character to STDOUT
		{
		Bit8u c = reg_dl;
		Bit16u n = 1;
		DOS_WriteFile(STDOUT, &c, &n);
		// Not in the official specs, but happens nonetheless. (last written character)
		reg_al = c;																	// reg_al=(c==9)?0x20:c; //Officially: tab to spaces
		}
		break;
	case 0x03:																		// Read character from STDAUX
		{
		Bit16u port = Mem_Lodsw(0x40, 0);
		if (port != 0 && serialPorts[0])
			serialPorts[0]->Getchar(&reg_al);
		}
		break;
	case 0x04:																		// Write Character to STDAUX
		{
		Bit16u port = Mem_Lodsw(0x40, 0);
		if (port != 0 && serialPorts[0])
			serialPorts[0]->Putchar(reg_dl);
		}
		break;
	case 0x05:																		// Write Character to PRINTER
		parallelPorts[0]->Putchar(reg_dl);
		break;
	case 0x06:																		// Direct Console Output/Input
		if (reg_dl == 0xff)															// Input
			{
			// TODO Make this better according to standards
			if (!DOS_GetSTDINStatus())
				{
				reg_al = 0;
				CALLBACK_SZF(true);
				break;
				}
			Bit8u c;
			Bit16u n = 1;
			DOS_ReadFile(STDIN, &c, &n);
			reg_al = c;
			CALLBACK_SZF(false);
			}
		else																		// Ouput
			{
			Bit8u c = reg_dl;
			Bit16u n = 1;
			DOS_WriteFile(STDOUT, &c, &n);
			reg_al = reg_dl;
			}
		break;
	case 0x07:																		// Character Input, without echo
	case 0x08:																		// Direct Character Input, without echo (checks for breaks officially :)
		{
		Bit8u c;
		Bit16u n = 1;
		DOS_ReadFile (STDIN, &c, &n);
		reg_al = c;
		}
		break;
	case 0x09:																		// Write string to STDOUT
		{	
		Bit8u c;
		Bit16u n = 1;
		PhysPt buf = SegPhys(ds)+reg_dx;
		while ((c = Mem_Lodsb(buf++)) != '$')
			DOS_WriteFile(STDOUT, &c, &n);
		}
		break;
	case 0x0a:																		// Buffered Input
		{
		// TODO ADD Break checkin in STDIN but can't care that much for it
		PhysPt data = SegPhys(ds)+reg_dx;
		Bit8u free = Mem_Lodsb(data);
		if (!free)
			break;
		Bit8u read = 0;
		Bit8u c;
		Bit16u n = 1;
		for(;;)
			{
			DOS_ReadFile(STDIN, &c ,&n);
			if (c == 8)
				{																	// Backspace
				if (read)
					{																// Something to backspace.
					DOS_WriteFile(STDOUT, &c, &n);									// STDOUT treats backspace as non-destructive.
					c = ' ';
					DOS_WriteFile(STDOUT, &c, &n);
					c = 8;
					DOS_WriteFile(STDOUT, &c, &n);
					--read;
					}
				continue;
				}
			if (read >= free)														// Keyboard buffer full
				{
				Beep(1750, 300);
				continue;
				}
			DOS_WriteFile(STDOUT, &c, &n);
			Mem_Stosb(data+read+2, c);
			if (c == 13) 
				break;
			read++;
			}
		Mem_Stosb(data+1, read);
		}
		break;
	case 0x0b:																		// Get STDIN Status
		reg_al = DOS_GetSTDINStatus() ? 0xff : 0x00;
		break;
	case 0x0c:																		// Flush Buffer and read STDIN call
		{
		Bit8u handle = RealHandle(STDIN);
		if (handle != 0xFF && Files[handle] && Files[handle]->IsName("CON"))		// flush buffer if STDIN is CON
			{
			Bit8u c;
			Bit16u n;
			while (DOS_GetSTDINStatus())
				{
				n = 1;
				DOS_ReadFile(STDIN, &c, &n);
				}
			}
		if (reg_al == 0x1 || reg_al == 0x6 || reg_al == 0x7 || reg_al == 0x8 || reg_al == 0xa)
			{ 
			Bit8u oldah = reg_ah;
			reg_ah = reg_al;
			DOS_21Handler();
			reg_ah = oldah;
			}
		else
			reg_al = 0;
		}
		break;
	case 0x0d:																		// Disk Reset
		break;	
	case 0x0e:																		// Select Default Drive
		DOS_SetDefaultDrive(reg_dl);
		reg_al = DOS_DRIVES;
		break;
	case 0x0f:																		// Open File using FCB
		reg_al = DOS_FCBOpen(SegValue(ds), reg_dx) ? 0 : 0xFF;
		break;
	case 0x10:																		// Close File using FCB
		reg_al = DOS_FCBClose(SegValue(ds), reg_dx) ? 0 : 0xFF;
		break;
	case 0x11:																		// Find First Matching File using FCB
		reg_al = DOS_FCBFindFirst(SegValue(ds), reg_dx) ? 0 : 0xFF;					// No test for C:\COMMAND.COM!
		break;
	case 0x12:																		// Find Next Matching File using FCB
		reg_al = DOS_FCBFindNext(SegValue(ds), reg_dx) ? 0 : 0xFF;
		break;
	case 0x13:																		// Delete File using FCB
		reg_al = DOS_FCBDeleteFile(SegValue(ds), reg_dx) ? 0 : 0xFF;
		break;
	case 0x14:																		// Sequential read from FCB
		reg_al = DOS_FCBRead(SegValue(ds), reg_dx, 0);
		break;
	case 0x15:																		// Sequential write to FCB
		reg_al = DOS_FCBWrite(SegValue(ds), reg_dx, 0);
		break;
	case 0x16:																		// Create or truncate file using FCB
		reg_al = DOS_FCBCreate(SegValue(ds), reg_dx) ? 0 : 0xFF;
		break;
	case 0x17:																		// Rename file using FCB
		reg_al = DOS_FCBRenameFile(SegValue(ds), reg_dx) ? 0 : 0xFF;
		break;
	case 0x1b:																		// Get allocation info for default drive
		if (!DOS_GetAllocationInfo(0, &reg_cx, &reg_al, &reg_dx))
			reg_al = 0xFF;
		break;
	case 0x1c:																		// Get allocation info for specific drive
		if (!DOS_GetAllocationInfo(reg_dl, &reg_cx, &reg_al, &reg_dx))
			reg_al = 0xFF;
		break;
	case 0x21:																		// Read random record from FCB
		reg_al = DOS_FCBRandomRead(SegValue(ds), reg_dx, 1, true);
		break;
	case 0x22:																		// Write random record to FCB
		reg_al = DOS_FCBRandomWrite(SegValue(ds), reg_dx, 1, true);
		break;
	case 0x23:																		// Get file size for FCB
		reg_al = DOS_FCBGetFileSize(SegValue(ds), reg_dx) ? 0 : 0xFF;
		break;
	case 0x24:																		// Set Random Record number for FCB
		DOS_FCBSetRandomRecord(SegValue(ds), reg_dx);
		break;
	case 0x27:																		// Random block read from FCB
		reg_al = DOS_FCBRandomRead(SegValue(ds), reg_dx, reg_cx, false);
		break;
	case 0x28:																		// Random Block write to FCB
		reg_al = DOS_FCBRandomWrite(SegValue(ds), reg_dx, reg_cx, false);
		break;
	case 0x29:																		// Parse filename into FCB
		{   
		Bit8u difference;
		char string[1024];
		Mem_StrnCopyFrom(string, SegPhys(ds)+reg_si, 1023);							// 1024 toasts the stack
		reg_al = FCB_Parsename(SegValue(es), reg_di, reg_al, string, &difference);
		reg_si += difference;
		}
		break;
	case 0x19:																		// Get current default drive
		reg_al = DOS_GetDefaultDrive();
		break;
	case 0x1a:																		// Set Disk Transfer Area Address
		dos.dta(RealMakeSeg(ds, reg_dx));
		break;
	case 0x25:																		// Set Interrupt Vector
		RealSetVec(reg_al, RealMakeSeg(ds, reg_dx));
		break;
	case 0x26:																		// Create new PSP
		DOS_NewPSP(reg_dx, DOS_PSP(dos.psp()).GetSize());
		break;
	case 0x2a:																		// Get System Date
		{
		_SYSTEMTIME systime;														// Return the Windows localdate
		GetLocalTime(&systime);
		reg_al = (Bit8u)systime.wDayOfWeek;											// NB Sunday = 0, despite of MSDN documentation
		reg_cx = systime.wYear;
		reg_dx = (systime.wMonth<<8)+systime.wDay;
		}
		break;
	case 0x2b:																		// Set System Date (we don't!)
		reg_al = 0xff;
		daysInMonth[2] = reg_cx&3 ? 28 : 29;										// Year is from 1980 to 2099, it is this simple
		if (reg_cx >= 1980 && reg_cx <= 2099)
			if (reg_dh > 0 && reg_dh <= 12)
				if (reg_dl > 0 && reg_dl <= daysInMonth[reg_dh])
					reg_al = 0;														// Date is valid, fake set
		break;			
	case 0x2c:																		// Get System Time
		{
		_SYSTEMTIME systime;														// Return the Windows localtime
		GetLocalTime(&systime);
		reg_cx = (systime.wHour<<8) + systime.wMinute;
		reg_dx = (systime.wSecond<<8) + systime.wMilliseconds/10;
		}
		break;
	case 0x2d:																		// Set System Time (we don't!)
		if (reg_ch < 24 && reg_cl < 60 && reg_dh < 60 && reg_dl < 100)
			reg_al = 0;																// Time is valid, fake set
		else
			reg_al = 0xff; 
		break;
	case 0x2e:																		// Set Verify flag
		dos.verify = (reg_al == 1);
		break;
	case 0x2f:																		// Get Disk Transfer Area
		SegSet16(es, RealSeg(dos.dta()));
		reg_bx = RealOff(dos.dta());
		break;
	case 0x30:																		// Get DOS Version
		if (reg_al == 0)
			reg_bh = 0xFF;															// Fake Microsoft DOS
		else if (reg_al == 1)
			reg_bh = 0;																// DOS is NOT in HMA
		reg_al = dos.version.major;
		reg_ah = dos.version.minor;
		reg_bl = 0;																	// Serialnumber
		reg_cx = 0;
		break;
	case 0x31:																		// Terminate and stay resident
		// Important: This service does not set the carry flag!
		DOS_ResizeMemory(dos.psp(), &reg_dx);
		DOS_Terminate(dos.psp(), true, reg_al);
		break;
	case 0x1f:																		// Get drive parameter block for default drive
	case 0x32:																		// Get drive parameter block for specific drive
		{																			// Officially a dpb should be returned as well. The disk detection part is implemented
		Bit8u drive = reg_dl;
		if (!drive || reg_ah == 0x1f)
			drive = DOS_GetDefaultDrive();
		else
			drive--;
		if (Drives[drive])
			{
			reg_al = 0;
			SegSet16(ds, dos.tables.dpb);
			reg_bx = drive;															// Faking only the first entry (that is the driveletter)
			}
		else
			reg_al = 0xff;
		}
		break;
	case 0x33:																		// Extended Break Checking
		switch (reg_al)
			{
		case 0:																		// Get the breakcheck flag
			reg_dl = dos.breakcheck;
			break;
		case 1:																		// Set the breakcheck flag
			dos.breakcheck = (reg_dl > 0);
			break;
		case 2:
			{
			bool old = dos.breakcheck;
			dos.breakcheck = (reg_dl > 0);
			reg_dl = old;
			}
			break;
		case 3:																		// Get cpsw
		case 4:																		// Set cpsw, both not used really
			break;
		case 5:
			reg_dl = 3;																// Boot drive = C:
			break;
		case 6:																		// Get true version number
			reg_bx = (dos.version.minor<<8) + dos.version.major;
			reg_dx = 0x1000;														// Dos in ROM
			break;
		default:
			reg_al = 0xff;
		}
		break;
	case 0x34:																		// Get address of INDos Flag
		SegSet16(es, DOS_SDA_SEG);
		reg_bx = DOS_SDA_OFS + 0x01;
		break;
	case 0x35:																		// Get interrupt vector
		reg_bx = Mem_Lodsw(0, ((Bit16u)reg_al)*4);
		SegSet16(es, Mem_Lodsw(0, ((Bit16u)reg_al)*4+2));
		break;
	case 0x36:																		// Get Free Disk Space
		{
		Bit16u bytes, clusters, free;
		Bit8u sectors;
		if (DOS_GetFreeDiskSpace(reg_dl, &bytes, &sectors, &clusters, &free))
			{
			reg_ax = sectors;
			reg_bx = free;
			reg_cx = bytes;
			reg_dx = clusters;
			}
		else
			reg_ax = 0xffff;														// invalid drive specified
		}
		break;
	case 0x37:																		// Get/Set Switch char Get/Set Availdev thing
		switch (reg_al)
			{
		case 0:
			 reg_dl = 0x2f;															 // Always return '/' like dos 5.0+
			 break;
		case 1:
			 reg_al = 0;
			 break;
		case 2:
			 reg_al = 0;
			 reg_dl = 0x2f;
			 break;
		case 3:
			 reg_al = 0;
			 break;
			}
		break;
	case 0x38:																		// Get/set Country Code
		if (reg_al == 0)															// Get country specidic information
			{
			PhysPt dest = SegPhys(ds)+reg_dx;
			Mem_CopyTo(dest, dos.tables.country, 0x18);
			reg_ax = reg_bx = 1;
			CALLBACK_SCF(false);
			}
		else																		// Set country code
			CALLBACK_SCF(true);
		break;
	case 0x39:																		// MKDIR Create directory
		Mem_StrnCopyFrom(name1, SegPhys(ds)+reg_dx, DOSNAMEBUF);
		rSpTrim(name1);
		if (DOS_MakeDir(name1))
			{
			reg_ax = 0xffff;														// AX destroyed
			CALLBACK_SCF(false);
			}
		else
			{
			reg_ax = dos.errorcode;
			CALLBACK_SCF(true);
			}
		break;
	case 0x3a:																		// RMDIR Remove directory
		Mem_StrnCopyFrom(name1, SegPhys(ds)+reg_dx, DOSNAMEBUF);
		rSpTrim(name1);
		if (DOS_RemoveDir(name1))
			{
			reg_ax = 0xffff;														// AX destroyed
			CALLBACK_SCF(false);
			}
		else
			{
			reg_ax = dos.errorcode;
			CALLBACK_SCF(true);
			}
		break;
	case 0x3b:																		// CHDIR Set current directory
		Mem_StrnCopyFrom(name1, SegPhys(ds)+reg_dx, DOSNAMEBUF);
		rSpTrim(name1);
		if (DOS_ChangeDir(name1))
			{
			reg_ax = 0xff00;														// AX destroyed
			CALLBACK_SCF(false);
			}
		else
			{
			reg_ax = dos.errorcode;
			CALLBACK_SCF(true);
			}
		break;
	case 0x3c:																		// CREATE Create or truncate file
		Mem_StrnCopyFrom(name1, SegPhys(ds)+reg_dx, DOSNAMEBUF);
		rSpTrim(name1);
		if (DOS_CreateFile(name1, reg_cx, &reg_ax))
			CALLBACK_SCF(false);
		else
			{
			reg_ax = dos.errorcode;
			CALLBACK_SCF(true);
			}
		break;
	case 0x3d:																		// OPEN Open existing file
		{
		Mem_StrnCopyFrom(name1, SegPhys(ds)+reg_dx, DOSNAMEBUF);
		rSpTrim(name1);
		if (DOS_OpenFile(name1, reg_al, &reg_ax))
			CALLBACK_SCF(false);
		else
			{
			reg_ax = dos.errorcode;
			CALLBACK_SCF(true);
			}
		break;
		}
	case 0x3e:																		// CLOSE Close file
		if (DOS_CloseFile(reg_bx))
			CALLBACK_SCF(false);
		else
			{
			reg_ax = dos.errorcode;
			CALLBACK_SCF(true);
			}
		break;
	case 0x3f:																		// READ Read from file or device
		{
		Bit16u toread = reg_cx;
		dos.echo = true;
		if (DOS_ReadFile(reg_bx, dos_copybuf, &toread))
			{
			Mem_CopyTo(SegPhys(ds)+reg_dx, dos_copybuf, toread);
			reg_ax = toread;
			CALLBACK_SCF(false);
			}
		else
			{
			reg_ax = dos.errorcode;
			CALLBACK_SCF(true);
			}
		dos.echo = false;
		}
		break;
	case 0x40:																		// WRITE Write to file or device
		{
		Bit16u towrite = reg_cx;
		Mem_CopyFrom(SegPhys(ds)+reg_dx, dos_copybuf, towrite);
		if (DOS_WriteFile(reg_bx, dos_copybuf, &towrite))
			{
			reg_ax = towrite;
   			CALLBACK_SCF(false);
			}
		else
			{
			reg_ax = dos.errorcode;
			CALLBACK_SCF(true);
			}
		}
		break;
	case 0x41:																		// UNLINK Delete file
		Mem_StrnCopyFrom(name1, SegPhys(ds)+reg_dx, DOSNAMEBUF);
		rSpTrim(name1);
		if (DOS_UnlinkFile(name1))
			CALLBACK_SCF(false);
		else
			{
			reg_ax = dos.errorcode;
			CALLBACK_SCF(true);
			}
		break;
	case 0x42:																		// LSEEK Set current file position
		{
		Bit32u pos = (reg_cx<<16) + reg_dx;
		if (DOS_SeekFile(reg_bx, &pos, reg_al))
			{
			reg_dx = (Bit16u)(pos >> 16);
			reg_ax = (Bit16u)(pos & 0xFFFF);
			CALLBACK_SCF(false);
			}
		else
			{
			reg_ax = dos.errorcode;
			CALLBACK_SCF(true);
			}
		}