| #include <time.h> |
| #include <fcntl.h> |
| #include <errno.h> |
| #include <malloc.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <sys/stat.h> |
| #ifdef linux |
| #include <sys/vfs.h> |
| #endif |
| #ifdef __NetBSD__ |
| #include <sys/mount.h> |
| #endif |
| #include <time.h> |
| #include <unistd.h> |
| #include <utime.h> |
| |
| #include "windows.h" |
| #include "wine.h" |
| #include "int21.h" |
| #include "files.h" |
| |
| #define MAX_DRIVES 26 |
| |
| static char Copyright[] = "int21.c, copyright Erik Bos, 1993"; |
| |
| extern struct DosDriveStruct DosDrives[]; |
| extern int CurrentDrive; |
| extern void ParseDOSFileName(); |
| |
| int ValidDrive(int); |
| |
| WORD ExtendedError, CodePage = 437; |
| BYTE ErrorClass, Action, ErrorLocus; |
| |
| void Error(int e, int class, int el) |
| { |
| ExtendedError = e; |
| ErrorClass = class; |
| Action = SA_Ask4Retry; |
| ErrorLocus = el; |
| } |
| |
| void GetFreeDiskSpace(struct sigcontext_struct *context) |
| { |
| int drive; |
| struct statfs info; |
| long size,avail; |
| |
| if (!(DX & 0xff)) |
| drive = CurrentDrive; |
| else |
| drive = (DX & 0xff) - 1; |
| |
| if (!ValidDrive(drive)) { |
| Error(InvalidDrive, EC_MediaError , EL_Disk); |
| AX = 0xffff; |
| return; |
| } |
| |
| { |
| if (statfs(DosDrives[drive].RootDirectory, &info) < 0) { |
| fprintf(stderr,"cannot do statfs(%s)\n",DosDrives[drive].RootDirectory); |
| Error(GeneralFailure, EC_MediaError , EL_Disk); |
| AX = 0xffff; |
| return; |
| } |
| |
| size = info.f_bsize * info.f_blocks / 1024; |
| avail = info.f_bavail * info.f_bsize / 1024; |
| |
| #ifdef DOSDEBUG |
| fprintf(stderr,"statfs: size: %8d avail: %8d\n",size,avail); |
| #endif |
| |
| AX = SectorsPerCluster; |
| CX = SectorSize; |
| |
| BX = (avail / (CX * AX)); |
| DX = (size / (CX * AX)); |
| Error (0,0,0); |
| } |
| } |
| |
| void SetDefaultDrive(struct sigcontext_struct *context) |
| { |
| if ((DX & 0xff) < MAX_DRIVES) { |
| CurrentDrive = DX & 0xff; |
| AX &= 0xff00; |
| AX |= MAX_DRIVES; /* # of valid drive letters */ |
| Error (0,0,0); |
| } else |
| Error (InvalidDrive, EC_MediaError, EL_Disk); |
| } |
| |
| void GetDefaultDrive(struct sigcontext_struct *context) |
| { |
| AX &= 0xff00; |
| AX |= CurrentDrive; |
| Error (0,0,0); |
| } |
| |
| void GetDriveAllocInfo(struct sigcontext_struct *context) |
| { |
| int drive; |
| long size; |
| BYTE mediaID; |
| struct statfs info; |
| |
| drive = DX & 0xff; |
| |
| if (!ValidDrive(drive)) { |
| AX = SectorsPerCluster; |
| CX = SectorSize; |
| DX = 0; |
| Error (InvalidDrive, EC_MediaError, EL_Disk); |
| return; |
| } |
| |
| { |
| if (statfs(DosDrives[drive].RootDirectory, &info) < 0) { |
| fprintf(stderr,"cannot do statfs(%s)\n",DosDrives[drive].RootDirectory); |
| Error(GeneralFailure, EC_MediaError , EL_Disk); |
| AX = 0xffff; |
| return; |
| } |
| |
| size = info.f_bsize * info.f_blocks / 1024; |
| |
| #ifdef DOSDEBUG |
| fprintf(stderr,"statfs: size: %8d\n",size); |
| #endif |
| |
| AX = SectorsPerCluster; |
| CX = SectorSize; |
| DX = (size / (CX * AX)); |
| |
| mediaID = 0xf0; |
| |
| DS = segment(mediaID); |
| BX = offset(mediaID); |
| Error (0,0,0); |
| } |
| } |
| |
| void GetDefDriveAllocInfo(struct sigcontext_struct *context) |
| { |
| DX = CurrentDrive; |
| GetDriveAllocInfo(context); |
| } |
| |
| void GetDrivePB(struct sigcontext_struct *context) |
| { |
| Error (InvalidDrive, EC_MediaError, EL_Disk); |
| AX = 0xff; /* I'm sorry but I only got networked drives :-) */ |
| } |
| |
| void ReadFile(struct sigcontext_struct *context) |
| { |
| char *ptr; |
| int size; |
| |
| /* can't read from stdout / stderr */ |
| |
| if (((BX & 0xffff) == 1) ||((BX & 0xffff) == 2)) { |
| Error (InvalidHandle, EL_Unknown, EC_Unknown); |
| AX = InvalidHandle; |
| SetCflag; |
| return; |
| } |
| |
| ptr = (char *) pointer (DS,DX); |
| |
| if ((BX & 0xffff) == 0) { |
| *ptr = EOF; |
| Error (0,0,0); |
| AX = 1; |
| ResetCflag; |
| return; |
| } else { |
| size = read(BX, ptr, CX); |
| if (size == 0) { |
| Error (ReadFault, EC_Unknown, EL_Unknown); |
| AX = ExtendedError; |
| return; |
| } |
| |
| if (size == -1) { |
| switch (errno) { |
| case EAGAIN: |
| Error (ShareViolation, EC_Temporary, EL_Unknown); |
| break; |
| case EBADF: |
| Error (InvalidHandle, EC_AppError, EL_Unknown); |
| break; |
| default: |
| Error (GeneralFailure, EC_SystemFailure, EL_Unknown); |
| break; |
| } |
| AX = ExtendedError; |
| SetCflag; |
| return; |
| } |
| Error (0,0,0); |
| AX = size; |
| ResetCflag; |
| } |
| } |
| |
| void WriteFile(struct sigcontext_struct *context) |
| { |
| char *ptr; |
| int x,size; |
| |
| ptr = (char *) pointer (DS,DX); |
| |
| if ((BX & 0xffff) == 0) { |
| Error (InvalidHandle, EC_Unknown, EL_Unknown); |
| AX = InvalidHandle; |
| SetCflag; |
| return; |
| } |
| |
| if ((BX & 0xffff) < 3) { |
| for (x = 0;x != CX;x++) { |
| fprintf(stderr, "%c", *ptr++); |
| } |
| fflush(stderr); |
| |
| Error (0,0,0); |
| AX = CX; |
| ResetCflag; |
| } else { |
| size = write(BX, ptr , CX); |
| if (size == 0) { |
| Error (WriteFault, EC_Unknown, EL_Unknown); |
| AX = ExtendedError; |
| return; |
| } |
| |
| if (size == -1) { |
| switch (errno) { |
| case EAGAIN: |
| Error (ShareViolation, EC_Temporary, EL_Unknown); |
| break; |
| case EBADF: |
| Error (InvalidHandle, EC_AppError, EL_Unknown); |
| break; |
| case ENOSPC: |
| Error (DiskFull, EC_MediaError, EL_Disk); |
| break; |
| default: |
| Error (GeneralFailure, EC_SystemFailure, EL_Unknown); |
| break; |
| } |
| AX = ExtendedError; |
| SetCflag; |
| return; |
| } |
| Error (0,0,0); |
| AX = size; |
| ResetCflag; |
| } |
| } |
| |
| void UnlinkFile(struct sigcontext_struct *context) |
| { |
| char UnixFileName[256]; |
| int drive, status; |
| |
| ParseDOSFileName(UnixFileName, (char *) pointer(DS,DX), &drive); |
| |
| { |
| status = unlink((char *) pointer(DS,DX)); |
| if (status == -1) { |
| switch (errno) { |
| case EACCES: |
| case EPERM: |
| case EROFS: |
| Error (WriteProtected, EC_AccessDenied, EL_Unknown); |
| break; |
| case EBUSY: |
| Error (LockViolation, EC_AccessDenied, EL_Unknown); |
| break; |
| case EAGAIN: |
| Error (ShareViolation, EC_Temporary, EL_Unknown); |
| break; |
| case ENOENT: |
| Error (FileNotFound, EC_NotFound, EL_Unknown); |
| break; |
| default: |
| Error (GeneralFailure, EC_SystemFailure, EL_Unknown); |
| break; |
| } |
| AX = ExtendedError; |
| SetCflag; |
| return; |
| } |
| Error (0,0,0); |
| ResetCflag; |
| } |
| } |
| |
| void SeekFile(struct sigcontext_struct *context) |
| { |
| char UnixFileName[256]; |
| int drive, handle, status, fileoffset; |
| |
| |
| ParseDOSFileName(UnixFileName, (char *) pointer(DS,DX), &drive); |
| |
| { |
| switch (AX & 0xff) { |
| case 1: fileoffset = SEEK_CUR; |
| break; |
| case 2: fileoffset = SEEK_END; |
| break; |
| default: |
| case 0: fileoffset = SEEK_SET; |
| break; |
| } |
| status = lseek(BX, (CX * 0x100) + DX, fileoffset); |
| if (status == -1) { |
| switch (errno) { |
| case EBADF: |
| Error (InvalidHandle, EC_AppError, EL_Unknown); |
| break; |
| case EINVAL: |
| Error (DataInvalid, EC_AppError, EL_Unknown); |
| break; |
| default: |
| Error (GeneralFailure, EC_SystemFailure, EL_Unknown); |
| break; |
| } |
| AX = ExtendedError; |
| SetCflag; |
| return; |
| } |
| Error (0,0,0); |
| ResetCflag; |
| } |
| } |
| |
| void GetFileAttributes(struct sigcontext_struct *context) |
| { |
| char UnixFileName[256]; |
| int drive,handle; |
| |
| ParseDOSFileName(UnixFileName, (char *) pointer(DS,DX), &drive); |
| |
| { |
| CX = 0x0; |
| ResetCflag; |
| } |
| } |
| |
| void SetFileAttributes(struct sigcontext_struct *context) |
| { |
| ResetCflag; |
| } |
| |
| void DosIOCTL(struct sigcontext_struct *context) |
| { |
| AX = UnknownUnit; |
| SetCflag; |
| } |
| |
| void DupeFileHandle(struct sigcontext_struct *context) |
| { |
| AX = dup(BX); |
| ResetCflag; |
| } |
| |
| void GetSystemDate(struct sigcontext_struct *context) |
| { |
| struct tm *now; |
| time_t ltime; |
| |
| ltime = time(NULL); |
| now = localtime(<ime); |
| |
| CX = now->tm_year + 1900; |
| DX = ((now->tm_mon + 1) << 8) | now->tm_mday; |
| AX &= 0xff00; |
| AX |= now->tm_wday; |
| } |
| |
| void GetSystemTime(struct sigcontext_struct *context) |
| { |
| struct tm *now; |
| time_t ltime; |
| |
| ltime = time(NULL); |
| now = localtime(<ime); |
| |
| CX = (now->tm_hour << 8) | now->tm_min; |
| DX = now->tm_sec << 8; |
| } |
| |
| void GetExtendedErrorInfo(struct sigcontext_struct *context) |
| { |
| AX = ExtendedError; |
| BX = (0x100 * ErrorClass) | Action; |
| CX &= 0x00ff; |
| CX |= (0x100 * ErrorLocus); |
| } |
| |
| void GetInDosFlag(struct sigcontext_struct *context) |
| { |
| const BYTE InDosFlag = 0; |
| |
| ES = segment(InDosFlag); |
| BX = offset(InDosFlag); |
| } |
| |
| void CreateFile(struct sigcontext_struct *context) |
| { |
| char UnixFileName[256]; |
| int drive,handle; |
| |
| ParseDOSFileName(UnixFileName, (char *) pointer(DS,DX), &drive); |
| |
| { |
| handle = open(UnixFileName, O_CREAT | O_TRUNC); |
| |
| if (handle == -1) { |
| switch (errno) { |
| case EACCES: |
| case EPERM: |
| case EROFS: |
| Error (WriteProtected, EC_AccessDenied, EL_Unknown); |
| break; |
| case EISDIR: |
| Error (CanNotMakeDir, EC_AccessDenied, EL_Unknown); |
| break; |
| case ENFILE: |
| case EMFILE: |
| Error (NoMoreFiles, EC_MediaError, EL_Unknown); |
| case EEXIST: |
| Error (FileExists, EC_Exists, EL_Disk); |
| break; |
| case ENOSPC: |
| Error (DiskFull, EC_MediaError, EL_Disk); |
| break; |
| default: |
| Error (GeneralFailure, EC_SystemFailure, EL_Unknown); |
| break; |
| } |
| AX = ExtendedError; |
| SetCflag; |
| return; |
| } |
| Error (0,0,0); |
| BX = handle; |
| AX = NoError; |
| ResetCflag; |
| } |
| } |
| |
| void OpenExistingFile(struct sigcontext_struct *context) |
| { |
| char UnixFileName[256]; |
| int drive, handle; |
| |
| ParseDOSFileName(UnixFileName, (char *) pointer(DS,DX), &drive); |
| |
| { |
| handle = open(UnixFileName, O_RDWR); |
| |
| if (handle == -1) { |
| switch (errno) { |
| case EACCES: |
| case EPERM: |
| case EROFS: |
| Error (WriteProtected, EC_AccessDenied, EL_Unknown); |
| break; |
| case EISDIR: |
| Error (CanNotMakeDir, EC_AccessDenied, EL_Unknown); |
| break; |
| case ENFILE: |
| case EMFILE: |
| Error (NoMoreFiles, EC_MediaError, EL_Unknown); |
| case EEXIST: |
| Error (FileExists, EC_Exists, EL_Disk); |
| break; |
| case ENOSPC: |
| Error (DiskFull, EC_MediaError, EL_Disk); |
| break; |
| case ENOENT: |
| Error (FileNotFound, EC_MediaError, EL_Disk); |
| break; |
| default: |
| Error (GeneralFailure, EC_SystemFailure, EL_Unknown); |
| break; |
| } |
| AX = ExtendedError; |
| SetCflag; |
| return; |
| } |
| Error (0,0,0); |
| BX = handle; |
| AX = NoError; |
| ResetCflag; |
| } |
| } |
| |
| void CloseFile(struct sigcontext_struct *context) |
| { |
| if (close(BX) == -1) { |
| switch (errno) { |
| case EBADF: |
| Error (InvalidHandle, EC_AppError, EL_Unknown); |
| break; |
| default: |
| Error (GeneralFailure, EC_SystemFailure, EL_Unknown); |
| break; |
| } |
| AX = ExtendedError; |
| SetCflag; |
| return; |
| } |
| Error (0,0,0); |
| AX = NoError; |
| ResetCflag; |
| } |
| |
| void RenameFile(struct sigcontext_struct *context) |
| { |
| rename((char *) pointer(DS,DX), (char *) pointer(ES,DI)); |
| ResetCflag; |
| } |
| |
| void GetTrueFileName(struct sigcontext_struct *context) |
| { |
| strncpy((char *) pointer(ES,DI), (char *) pointer(DS,SI), strlen((char *) pointer(DS,SI)) & 0x7f); |
| ResetCflag; |
| } |
| |
| void MakeDir(struct sigcontext_struct *context) |
| { |
| int drive; |
| char *dirname; |
| char unixname[256]; |
| |
| dirname = (char *) pointer(DS,DX); |
| |
| ParseDOSFileName(unixname,dirname,&drive); |
| |
| { |
| if (mkdir(unixname,0) == -1) { |
| AX = CanNotMakeDir; |
| SetCflag; |
| } |
| ResetCflag; |
| } |
| } |
| |
| void ChangeDir(struct sigcontext_struct *context) |
| { |
| int drive; |
| char *dirname; |
| char unixname[256]; |
| |
| dirname = (char *) pointer(DS,DX); |
| |
| ParseDOSFileName(unixname,dirname,&drive); |
| |
| { |
| strcpy(unixname,DosDrives[drive].CurrentDirectory); |
| ResetCflag; |
| } |
| } |
| |
| void RemoveDir(struct sigcontext_struct *context) |
| { |
| int drive; |
| char *dirname; |
| char unixname[256]; |
| |
| dirname = (char *) pointer(DS,DX); |
| |
| ParseDOSFileName(unixname,dirname,&drive); |
| |
| { |
| if (strcmp(unixname,DosDrives[drive].CurrentDirectory)) { |
| AX = CanNotRemoveCwd; |
| SetCflag; |
| } |
| |
| #ifdef DOSDEBUG |
| fprintf(stderr,"rmdir %s\n",unixname); |
| #endif |
| |
| if (rmdir(unixname) == -1) { |
| AX = CanNotMakeDir; /* HUH ?*/ |
| SetCflag; |
| } |
| ResetCflag; |
| } |
| } |
| |
| void AllocateMemory(struct sigcontext_struct *context) |
| { |
| char *ptr; |
| |
| if ((ptr = (void *) memalign((size_t) (BX * 0x10), 0x10)) == NULL) { |
| AX = OutOfMemory; |
| BX = 0x0; /* out of memory */ |
| SetCflag; |
| } |
| AX = segment((unsigned long) ptr); |
| ResetCflag; |
| } |
| |
| void FreeMemory(struct sigcontext_struct *context) |
| { |
| free((void *)(ES * 0x10)); |
| ResetCflag; |
| } |
| |
| void ResizeMemoryBlock(struct sigcontext_struct *context) |
| { |
| char *ptr; |
| |
| if ((ptr = (void *) realloc((void *)(ES * 0x10), (size_t) BX * 0x10)) == NULL) { |
| AX = OutOfMemory; |
| BX = 0x0; /* out of memory */ |
| SetCflag; |
| } |
| BX = segment((unsigned long) ptr); |
| ResetCflag; |
| } |
| |
| void ExecProgram(struct sigcontext_struct *context) |
| { |
| execl("wine",(char *) pointer(DS,DX)); |
| } |
| |
| void GetReturnCode(struct sigcontext_struct *context) |
| { |
| AX = NoError; /* normal exit */ |
| } |
| |
| void FindFirst(struct sigcontext_struct *context) |
| { |
| |
| } |
| |
| void FindNext(struct sigcontext_struct *context) |
| { |
| |
| } |
| |
| void GetSysVars(struct sigcontext_struct *context) |
| { |
| ES = 0x0; |
| BX = 0x0; |
| } |
| |
| void GetFileDateTime(struct sigcontext_struct *context) |
| { |
| int drive; |
| char *dirname; |
| char unixname[256]; |
| struct stat filestat; |
| struct tm *now; |
| |
| dirname = (char *) pointer(DS,DX); |
| ParseDOSFileName(unixname, dirname, &drive); |
| |
| { |
| stat(unixname, &filestat); |
| |
| now = localtime (&filestat.st_mtime); |
| |
| CX = (now->tm_hour * 0x2000) + (now->tm_min * 0x20) + now->tm_sec/2; |
| DX = (now->tm_year * 0x200) + (now->tm_mon * 0x20) + now->tm_mday; |
| |
| ResetCflag; |
| } |
| } |
| |
| void SetFileDateTime(struct sigcontext_struct *context) |
| { |
| int drive; |
| char *dirname; |
| char unixname[256]; |
| struct utimbuf filetime; |
| |
| dirname = (char *) pointer(DS,DX); |
| |
| ParseDOSFileName(unixname, dirname, &drive); |
| |
| { |
| filetime.actime = 0L; |
| filetime.modtime = filetime.actime; |
| |
| utime(unixname,&filetime); |
| ResetCflag; |
| } |
| } |
| |
| void CreateTempFile(struct sigcontext_struct *context) |
| { |
| char UnixFileName[256],TempString[256]; |
| int drive,handle; |
| |
| ParseDOSFileName(UnixFileName, (char *) pointer(DS,DX), &drive); |
| |
| sprintf(TempString,"%s%s%d",UnixFileName,"eb",(int) getpid()); |
| |
| { |
| handle = open(TempString, O_CREAT | O_TRUNC | O_RDWR); |
| |
| if (handle == -1) { |
| AX = WriteProtected; |
| SetCflag; |
| return; |
| } |
| |
| strcpy((char *) pointer(DS,DX), UnixFileName); |
| |
| AX = handle; |
| ResetCflag; |
| } |
| } |
| |
| void CreateNewFile(struct sigcontext_struct *context) |
| { |
| char UnixFileName[256]; |
| int drive,handle; |
| |
| ParseDOSFileName(UnixFileName, (char *) pointer(DS,DX), &drive); |
| |
| { |
| handle = open(UnixFileName, O_CREAT | O_TRUNC | O_RDWR); |
| |
| if (handle == -1) { |
| AX = WriteProtected; |
| SetCflag; |
| return; |
| } |
| |
| AX = handle; |
| ResetCflag; |
| } |
| } |
| |
| void FileLock(struct sigcontext_struct *context) |
| { |
| |
| } |
| |
| void GetExtendedCountryInfo(struct sigcontext_struct *context) |
| { |
| ResetCflag; |
| } |
| |
| int ValidDrive(int d) |
| { |
| return 1; |
| } |
| |
| void GetCurrentDirectory(struct sigcontext_struct *context) |
| { |
| int drive; |
| char *ptr; |
| |
| if ((DX & 0xff) == 0) |
| drive = CurrentDrive; |
| else |
| drive = (DX & 0xff)-1; |
| |
| if (!ValidDrive(drive)) { |
| AX = InvalidDrive; |
| SetCflag; |
| return; |
| } |
| |
| strcpy((char *) pointer(DS,SI), DosDrives[drive].CurrentDirectory); |
| ResetCflag; |
| AX = 0x0100; |
| } |
| |
| void GetCurrentPSP(struct sigcontext_struct *context) |
| { |
| |
| } |
| |
| void GetDiskSerialNumber(struct sigcontext_struct *context) |
| { |
| int drive; |
| struct diskinfo *ptr; |
| |
| if ((BX & 0xff)== 0) |
| drive = CurrentDrive; |
| else |
| drive = (BX & 0xff)-1; |
| |
| if (!ValidDrive(drive)) { |
| AX = InvalidDrive; |
| SetCflag; |
| return; |
| } |
| |
| { |
| ptr =(struct diskinfo *) pointer(DS,SI); |
| |
| ptr->infolevel = 0; |
| ptr->serialnumber = 0xEBEBEB00 | drive; |
| strcpy(ptr->label,"NO NAME "); |
| strcpy(ptr->fstype,"FAT16 "); |
| |
| AX = NoError; |
| ResetCflag; |
| } |
| } |
| |
| void SetDiskSerialNumber(struct sigcontext_struct *context) |
| { |
| AX &= 0xff00; |
| AX |= 1; |
| ResetCflag; |
| } |
| |
| void CommitFile(struct sigcontext_struct *context) |
| { |
| |
| } |
| |
| /************************************************************************/ |
| |
| int do_int21(struct sigcontext_struct * context){ |
| int ah; |
| |
| fprintf(stderr,"int21: doing AX=%4x BX=%4x CX=%4x DX=%4x\n", |
| AX & 0xffff,BX & 0xffff,CX & 0xffff,DX & 0xffff); |
| |
| ah = (AX >> 8) & 0xff; |
| |
| if (ah == 0x59) { |
| GetExtendedErrorInfo(context); |
| return 1; |
| } else { |
| |
| Error (0,0,0); |
| |
| switch(ah) { |
| |
| case 0x00: /* TERMINATE PROGRAM */ |
| exit(0); |
| |
| case 0x01: /* READ CHARACTER FROM STANDARD INPUT, WITH ECHO */ |
| case 0x02: /* WRITE CHARACTER TO STANDARD OUTPUT */ |
| case 0x03: /* READ CHARACTER FROM STDAUX */ |
| case 0x04: /* WRITE CHARACTER TO STDAUX */ |
| case 0x05: /* WRITE CHARACTER TO PRINTER */ |
| case 0x06: /* DIRECT CONSOLE IN/OUTPUT */ |
| case 0x07: /* DIRECT CHARACTER INPUT, WITHOUT ECHO */ |
| case 0x08: /* CHARACTER INPUT WITHOUT ECHO */ |
| case 0x09: /* WRITE STRING TO STANDARD OUTPUT */ |
| case 0x0a: /* BUFFERED INPUT */ |
| case 0x0b: /* GET STDIN STATUS */ |
| case 0x0c: /* FLUSH BUFFER AND READ STANDARD INPUT */ |
| case 0x0d: /* DISK BUFFER FLUSH */ |
| break; |
| |
| /* no FCB support for CP/M hackers */ |
| |
| case 0x0f: /* OPEN FILE USING FCB */ |
| case 0x10: /* CLOSE FILE USING FCB */ |
| case 0x11: /* FIND FIRST MATCHING FILE USING FCB */ |
| case 0x12: /* FIND NEXT MATCHING FILE USING FCB */ |
| case 0x13: /* DELETE FILE USING FCB */ |
| case 0x14: /* SEQUENTIAL READ FROM FCB FILE */ |
| case 0x15: /* SEQUENTIAL WRITE TO FCB FILE */ |
| case 0x16: /* CREATE OR TRUNCATE FILE USING FCB */ |
| case 0x17: /* RENAME FILE USING FCB */ |
| case 0x1a: /* SET DISK TRANSFER AREA ADDRESS */ |
| case 0x21: /* READ RANDOM RECORD FROM FCB FILE */ |
| case 0x22: /* WRITE RANDOM RECORD TO FCB FILE */ |
| case 0x23: /* GET FILE SIZE FOR FCB */ |
| case 0x24: /* SET RANDOM RECORD NUMBER FOR FCB */ |
| case 0x27: /* RANDOM BLOCK READ FROM FCB FILE */ |
| case 0x28: /* RANDOM BLOCK WRITE TO FCB FILE */ |
| case 0x29: /* PARSE FILENAME INTO FCB */ |
| case 0x2f: /* GET DISK TRANSFER AREA ADDRESS */ |
| |
| case 0x2e: /* SET VERIFY FLAG */ |
| break; |
| |
| case 0x18: /* NULL FUNCTIONS FOR CP/M COMPATIBILITY */ |
| case 0x1d: |
| case 0x1e: |
| case 0x20: |
| case 0x2b: /* SET SYSTEM DATE */ |
| case 0x2d: /* SET SYSTEM TIME */ |
| case 0x37: /* "SWITCHAR" - GET SWITCH CHARACTER |
| "SWITCHAR" - SET SWITCH CHARACTER |
| "AVAILDEV" - SPECIFY \DEV\ PREFIX USE */ |
| case 0x54: /* GET VERIFY FLAG */ |
| case 0x61: /* UNUSED */ |
| case 0x6b: /* NULL FUNCTION */ |
| AX &= 0xff00; |
| break; |
| |
| case 0x67: /* SET HANDLE COUNT */ |
| ResetCflag; |
| break; |
| |
| case 0x0e: /* SELECT DEFAULT DRIVE */ |
| SetDefaultDrive(context); |
| break; |
| |
| case 0x19: /* GET CURRENT DEFAULT DRIVE */ |
| GetDefaultDrive(context); |
| break; |
| |
| case 0x1b: /* GET ALLOCATION INFORMATION FOR DEFAULT DRIVE */ |
| GetDefDriveAllocInfo(context); |
| break; |
| |
| case 0x1c: /* GET ALLOCATION INFORMATION FOR SPECIFIC DRIVE */ |
| GetDriveAllocInfo(context); |
| break; |
| |
| case 0x1f: /* GET DRIVE PARAMETER BLOCK FOR DEFAULT DRIVE */ |
| case 0x32: /* GET DOS DRIVE PARAMETER BLOCK FOR SPECIFIC DRIVE */ |
| GetDrivePB(context); |
| break; |
| |
| case 0x25: /* SET INTERRUPT VECTOR */ |
| /* Ignore any attempt to set a segment vector */ |
| return 1; |
| |
| case 0x26: /* CREATE NEW PROGRAM SEGMENT PREFIX */ |
| break; |
| |
| case 0x2a: /* GET SYSTEM DATE */ |
| GetSystemDate(context); |
| break; |
| |
| case 0x2c: /* GET SYSTEM TIME */ |
| GetSystemTime(context); |
| break; |
| |
| case 0x30: /* GET DOS VERSION */ |
| AX = DosVersion; /* Hey folks, this is DOS V3.3! */ |
| BX = 0x0012; /* 0x123456 is Wine's serial # */ |
| CX = 0x3456; |
| break; |
| |
| case 0x31: /* TERMINATE AND STAY RESIDENT */ |
| break; |
| |
| case 0x33: /* MULTIPLEXED */ |
| switch (AX & 0xff) { |
| case 0x00: /* GET CURRENT EXTENDED BREAK STATE */ |
| if (!(AX & 0xff)) |
| DX &= 0xff00; |
| break; |
| |
| case 0x01: /* SET EXTENDED BREAK STATE */ |
| break; |
| |
| case 0x02: /* GET AND SET EXTENDED CONTROL-BREAK CHECKING STATE */ |
| DX &= 0xff00; |
| break; |
| |
| case 0x05: /* GET BOOT DRIVE */ |
| DX &= 0xff00; |
| DX |= 2; /* c: is Wine's bootdrive */ |
| break; |
| |
| case 0x06: /* GET TRUE VERSION NUMBER */ |
| BX = DosVersion; |
| DX = 0x00; |
| break; |
| default: |
| break; |
| } |
| break; |
| |
| case 0x34: /* GET ADDRESS OF INDOS FLAG */ |
| GetInDosFlag(context); |
| break; |
| |
| case 0x35: /* GET INTERRUPT VECTOR */ |
| /* Return a NULL segment selector - this will bomb, |
| if anyone ever tries to use it */ |
| ES = 0; |
| BX = 0; |
| break; |
| |
| case 0x36: /* GET FREE DISK SPACE */ |
| GetFreeDiskSpace(context); |
| break; |
| |
| case 0x38: /* GET COUNTRY-SPECIFIC INFORMATION */ |
| AX &= 0xff00; |
| AX |= 0x02; /* no country support available */ |
| SetCflag; |
| break; |
| |
| case 0x39: /* "MKDIR" - CREATE SUBDIRECTORY */ |
| MakeDir(context); |
| break; |
| |
| case 0x3a: /* "RMDIR" - REMOVE SUBDIRECTORY */ |
| RemoveDir(context); |
| break; |
| |
| case 0x3b: /* "CHDIR" - SET CURRENT DIRECTORY */ |
| ChangeDir(context); |
| break; |
| |
| case 0x3c: /* "CREAT" - CREATE OR TRUNCATE FILE */ |
| CreateFile(context); |
| break; |
| |
| case 0x3d: /* "OPEN" - OPEN EXISTING FILE */ |
| OpenExistingFile(context); |
| break; |
| |
| case 0x3e: /* "CLOSE" - CLOSE FILE */ |
| case 0x68: /* "FFLUSH" - COMMIT FILE */ |
| case 0x6a: /* COMMIT FILE */ |
| |
| CloseFile(context); |
| break; |
| |
| case 0x3f: /* "READ" - READ FROM FILE OR DEVICE */ |
| ReadFile(context); |
| break; |
| |
| case 0x40: /* "WRITE" - WRITE TO FILE OR DEVICE */ |
| WriteFile(context); |
| break; |
| |
| case 0x41: /* "UNLINK" - DELETE FILE */ |
| UnlinkFile(context); |
| break; |
| |
| case 0x42: /* "LSEEK" - SET CURRENT FILE POSITION */ |
| SeekFile(context); |
| break; |
| |
| case 0x43: /* FILE ATTRIBUTES */ |
| switch (AX & 0xff) { |
| case 0x00: |
| GetFileAttributes(context); |
| break; |
| case 0x01: |
| SetFileAttributes(context); |
| break; |
| } |
| break; |
| |
| case 0x44: /* IOCTL */ |
| DosIOCTL(context); |
| break; |
| |
| case 0x45: /* "DUP" - DUPLICATE FILE HANDLE */ |
| case 0x46: /* "DUP2", "FORCEDUP" - FORCE DUPLICATE FILE HANDLE */ |
| DupeFileHandle(context); |
| break; |
| |
| case 0x47: /* "CWD" - GET CURRENT DIRECTORY */ |
| GetCurrentDirectory(context); |
| AX = 0x0100; /* many Microsoft products for Windows rely |
| on this */ |
| break; |
| |
| case 0x48: /* ALLOCATE MEMORY */ |
| AllocateMemory(context); |
| break; |
| |
| case 0x49: /* FREE MEMORY */ |
| FreeMemory(context); |
| break; |
| |
| case 0x4a: /* RESIZE MEMORY BLOCK */ |
| ResizeMemoryBlock(context); |
| break; |
| |
| case 0x4b: /* "EXEC" - LOAD AND/OR EXECUTE PROGRAM */ |
| ExecProgram(context); |
| break; |
| |
| case 0x4c: /* "EXIT" - TERMINATE WITH RETURN CODE */ |
| exit(AX & 0xff); |
| |
| case 0x4d: /* GET RETURN CODE */ |
| GetReturnCode(context); |
| break; |
| |
| case 0x4e: /* "FINDFIRST" - FIND FIRST MATCHING FILE */ |
| FindFirst(context); |
| break; |
| |
| case 0x4f: /* "FINDNEXT" - FIND NEXT MATCHING FILE */ |
| FindNext(context); |
| break; |
| |
| case 0x52: /* "SYSVARS" - GET LIST OF LISTS */ |
| GetSysVars(context); |
| break; |
| |
| case 0x56: /* "RENAME" - RENAME FILE */ |
| RenameFile(context); |
| break; |
| |
| case 0x57: /* FILE DATE AND TIME */ |
| switch (AX & 0xff) { |
| case 0x00: |
| GetFileDateTime(context); |
| break; |
| case 0x01: |
| SetFileDateTime(context); |
| break; |
| } |
| break; |
| |
| case 0x58: /* GET OR SET MEMORY/UMB ALLOCATION STRATEGY */ |
| switch (AX & 0xff) { |
| case 0x00: |
| AX = 0x01; |
| break; |
| case 0x02: |
| AX &= 0xff00; |
| break; |
| case 0x01: |
| case 0x03: |
| break; |
| } |
| ResetCflag; |
| break; |
| |
| case 0x59: /* GET EXTENDED ERROR INFO */ |
| GetExtendedErrorInfo(context); |
| break; |
| |
| case 0x5a: /* CREATE TEMPORARY FILE */ |
| CreateTempFile(context); |
| break; |
| |
| case 0x5b: /* CREATE NEW FILE */ |
| CreateNewFile(context); |
| break; |
| |
| case 0x5c: /* "FLOCK" - RECORD LOCKING */ |
| FileLock(context); |
| break; |
| |
| case 0x5d: /* NETWORK */ |
| case 0x5e: |
| case 0x5f: |
| AX &= 0xff00; |
| AX |= NoNetwork; /* network software not installed */ |
| SetCflag; |
| break; |
| |
| case 0x60: /* "TRUENAME" - CANONICALIZE FILENAME OR PATH */ |
| GetTrueFileName(context); |
| break; |
| |
| case 0x62: /* GET CURRENT PSP ADDRESS */ |
| GetCurrentPSP(context); |
| break; |
| |
| case 0x65: /* GET EXTENDED COUNTRY INFORMATION */ |
| GetExtendedCountryInfo(context); |
| break; |
| |
| case 0x66: /* GLOBAL CODE PAGE TABLE */ |
| switch (AX & 0xff) { |
| case 0x01: |
| BX = CodePage; |
| DX = BX; |
| ResetCflag; |
| break; |
| case 0x02: |
| CodePage = BX; |
| ResetCflag; |
| break; |
| } |
| break; |
| |
| case 0x69: /* DISK SERIAL NUMBER */ |
| switch (AX & 0xff) { |
| case 0x00: |
| GetDiskSerialNumber(context); |
| break; |
| case 0x01: |
| SetDiskSerialNumber(context); |
| break; |
| } |
| break; |
| |
| default: |
| fprintf(stderr,"Unable to handle int 0x21 %x\n", context->sc_eax); |
| return 1; |
| }; |
| } |
| return 1; |
| } |