2 * (c) 1993, 1994 Erik Bos
14 #include "prototypes.h"
21 WORD ExtendedError
, CodePage
= 437;
22 BYTE ErrorClass
, Action
, ErrorLocus
;
30 static struct DosHeap
*heap
;
32 extern char TempDirectory
[];
34 static int Error(int e
, int class, int el
)
37 Action
= SA_Ask4Retry
;
44 static void errno_to_doserr(void)
48 Error (ShareViolation
, EC_Temporary
, EL_Unknown
);
51 Error (InvalidHandle
, EC_AppError
, EL_Unknown
);
54 Error (DiskFull
, EC_MediaError
, EL_Disk
);
59 Error (WriteProtected
, EC_AccessDenied
, EL_Unknown
);
62 Error (LockViolation
, EC_AccessDenied
, EL_Unknown
);
65 Error (FileNotFound
, EC_NotFound
, EL_Unknown
);
68 Error (CanNotMakeDir
, EC_AccessDenied
, EL_Unknown
);
72 Error (NoMoreFiles
, EC_MediaError
, EL_Unknown
);
75 Error (FileExists
, EC_Exists
, EL_Disk
);
78 fprintf(stderr
, "int21: unknown errno %d!\n", errno
);
79 Error (GeneralFailure
, EC_SystemFailure
, EL_Unknown
);
84 static void Barf(struct sigcontext_struct
*context
)
86 fprintf(stderr
, "int21: unknown/not implemented parameters:\n");
87 fprintf(stderr
, "int21: AX %04x, BX %04x, CX %04x, DX %04x, "
88 "SI %04x, DI %04x, DS %04x, ES %04x\n",
89 AX
, BX
, CX
, DX
, SI
, DI
, DS
, ES
);
92 void ChopOffWhiteSpace(char *string
)
96 for (length
= strlen(string
) ; length
; length
--)
97 if (string
[length
] == ' ')
98 string
[length
] = '\0';
101 static void CreateBPB(int drive
, BYTE
*data
)
106 setword(&data
[3], 0);
108 setword(&data
[6], 240);
109 setword(&data
[8], 64000);
111 setword(&data
[0x0b], 40);
112 setword(&data
[0x0d], 56);
113 setword(&data
[0x0f], 2);
114 setword(&data
[0x11], 0);
115 setword(&data
[0x1f], 800);
117 setword(&data
[0x22], 1);
118 } else { /* 1.44mb */
121 setword(&data
[3], 0);
123 setword(&data
[6], 240);
124 setword(&data
[8], 2880);
126 setword(&data
[0x0b], 6);
127 setword(&data
[0x0d], 18);
128 setword(&data
[0x0f], 2);
129 setword(&data
[0x11], 0);
130 setword(&data
[0x1f], 80);
132 setword(&data
[0x22], 2);
136 static void GetFreeDiskSpace(struct sigcontext_struct
*context
)
142 drive
= DOS_GetDefaultDrive();
144 drive
= (EDX
& 0xff) - 1;
146 if (!DOS_ValidDrive(drive
)) {
147 Error(InvalidDrive
, EC_MediaError
, EL_Disk
);
152 if (!DOS_GetFreeSpace(drive
, &size
, &available
)) {
153 Error(GeneralFailure
, EC_MediaError
, EL_Disk
);
158 EAX
= (EAX
& 0xffff0000) | 4;
159 ECX
= (ECX
& 0xffff0000) | 512;
161 EBX
= (EBX
& 0xffff0000) | (available
/ (CX
* AX
));
162 EDX
= (EDX
& 0xffff0000) | (size
/ (CX
* AX
));
166 static void GetDriveAllocInfo(struct sigcontext_struct
*context
)
169 long size
, available
;
174 if (!DOS_ValidDrive(drive
)) {
175 EAX
= (EAX
& 0xffff0000) | 4;
176 ECX
= (ECX
& 0xffff0000) | 512;
177 EDX
= (EDX
& 0xffff0000);
178 Error (InvalidDrive
, EC_MediaError
, EL_Disk
);
182 if (!DOS_GetFreeSpace(drive
, &size
, &available
)) {
183 Error(GeneralFailure
, EC_MediaError
, EL_Disk
);
188 EAX
= (EAX
& 0xffff0000) | 4;
189 ECX
= (ECX
& 0xffff0000) | 512;
190 EDX
= (EDX
& 0xffff0000) | (size
/ (CX
* AX
));
194 DS
= segment(mediaID
);
195 EBX
= offset(mediaID
);
199 static void GetDefDriveAllocInfo(struct sigcontext_struct
*context
)
201 EDX
= DOS_GetDefaultDrive();
202 GetDriveAllocInfo(context
);
205 static void GetDrivePB(struct sigcontext_struct
*context
)
207 Error (InvalidDrive
, EC_MediaError
, EL_Disk
);
208 EAX
= (EAX
& 0xffff0000) | 0xffL
;
209 /* I'm sorry but I only got networked drives :-) */
212 static void ReadFile(struct sigcontext_struct
*context
)
217 /* can't read from stdout / stderr */
218 if ((BX
== 1) || (BX
== 2)) {
219 Error (InvalidHandle
, EL_Unknown
, EC_Unknown
);
220 EAX
= (EAX
& 0xffff0000) | InvalidHandle
;
225 ptr
= pointer (DS
,DX
);
229 EAX
= (EAX
& 0xffff0000) | 1;
233 size
= read(BX
, ptr
, CX
);
236 EAX
= (EAX
& 0xffffff00) | ExtendedError
;
241 EAX
= (EAX
& 0xffff0000) | size
;
246 static void WriteFile(struct sigcontext_struct
*context
)
251 ptr
= pointer (DS
,DX
);
254 Error (InvalidHandle
, EC_Unknown
, EL_Unknown
);
261 for (x
= 0;x
!= CX
;x
++) {
262 fprintf(stderr
, "%c", *ptr
++);
267 EAX
= (EAX
& 0xffffff00) | CX
;
270 size
= write(BX
, ptr
, CX
);
272 Error (WriteFault
, EC_Unknown
, EL_Unknown
);
273 EAX
= (EAX
& 0xffffff00) | ExtendedError
;
279 EAX
= (EAX
& 0xffffff00) | ExtendedError
;
284 EAX
= (EAX
& 0xffff0000) | size
;
289 static void SeekFile(struct sigcontext_struct
*context
)
291 off_t status
, fileoffset
;
293 switch (EAX
& 0xff) {
294 case 1: fileoffset
= SEEK_CUR
;
296 case 2: fileoffset
= SEEK_END
;
299 case 0: fileoffset
= SEEK_SET
;
302 status
= lseek(BX
, (CX
* 0x100) + DX
, fileoffset
);
305 EAX
= (EAX
& 0xffffff00) | ExtendedError
; SetCflag
;
309 EAX
= (EAX
& 0xffff0000L
) | (status
& 0xffff);
310 EDX
= (EDX
& 0xffff0000L
) | ((status
>> 16) & 0xffff);
315 static void ioctlGetDeviceInfo(struct sigcontext_struct
*context
)
317 WORD handle
= EBX
& 0xffff;
323 EDX
= (EDX
& 0xffff0000) | 0x80d3;
330 if (fstat(handle
, &sbuf
) < 0)
332 IntBarf(0x21, context
);
333 EDX
= (EDX
& 0xffff0000) | 0x50;
338 /* This isn't the right answer, but should be close enough. */
339 EDX
= (EDX
& 0xffff0000) | 0x0943;
345 static void ioctlGenericBlkDevReq(struct sigcontext_struct
*context
)
347 BYTE
*dataptr
= pointer(DS
, DX
);
351 drive
= DOS_GetDefaultDrive();
353 drive
= (EBX
& 0xff) - 1;
355 if ((ECX
& 0xff00) != 0x0800) {
356 IntBarf(0x21, context
);
359 switch (ECX
& 0xff) {
360 case 0x60: /* get device parameters */
361 /* used by w4wgrp's winfile */
363 dataptr
[6] = 0; /* media type */
366 dataptr
[1] = 0x05; /* fixed disk */
367 setword(&dataptr
[2], 0x01); /* non removable */
368 setword(&dataptr
[4], 0x300); /* # of cylinders */
372 dataptr
[1] = 0x07; /* block dev, floppy */
373 setword(&dataptr
[2], 0x02); /* removable */
374 setword(&dataptr
[4], 80); /* # of cylinders */
376 CreateBPB(drive
, &dataptr
[7]);
377 EAX
= (EAX
& 0xfffff00);
381 IntBarf(0x21, context
);
385 static void GetSystemDate(struct sigcontext_struct
*context
)
391 now
= localtime(<ime
);
393 ECX
= (ECX
& 0xffff0000) | (now
->tm_year
+ 1900);
394 EDX
= (EDX
& 0xffff0000) | ((now
->tm_mon
+ 1) << 8) | now
->tm_mday
;
395 EAX
= (EAX
& 0xffff0000) | now
->tm_wday
;
398 static void GetSystemTime(struct sigcontext_struct
*context
)
404 now
= localtime(<ime
);
406 ECX
= (ECX
& 0xffffff00) | (now
->tm_hour
<< 8) | now
->tm_min
;
407 EDX
= (EDX
& 0xffffff00) | now
->tm_sec
<< 8;
410 static void GetExtendedErrorInfo(struct sigcontext_struct
*context
)
412 EAX
= (EAX
& 0xffffff00) | ExtendedError
;
413 EBX
= (EBX
& 0xffff0000) | (ErrorClass
<< 8) | Action
;
414 ECX
= (ECX
& 0xffff00ff) | (ErrorLocus
<< 8);
417 static void CreateFile(struct sigcontext_struct
*context
)
421 if ((handle
= open(GetUnixFileName( pointer(DS
,DX
)), O_CREAT
| O_TRUNC
)) == -1) {
423 EAX
= (EAX
& 0xffffff00) | ExtendedError
;
428 EBX
= (EBX
& 0xffff0000) | handle
;
429 EAX
= (EAX
& 0xffffff00) | NoError
;
433 static void OpenExistingFile(struct sigcontext_struct
*context
)
453 fprintf(stderr
,"OpenExistingFile (%s)\n", pointer(DS
,DX
));
455 if ((handle
= open(GetUnixFileName(pointer(DS
,DX
)), mode
)) == -1) {
457 EAX
= (EAX
& 0xffffff00) | ExtendedError
;
462 EAX
= (EBX
& 0xffff0000) | handle
;
466 static void CloseFile(struct sigcontext_struct
*context
)
468 if (close(BX
) == -1) {
470 EAX
= (EAX
& 0xffffff00) | ExtendedError
;
475 EAX
= (EAX
& 0xffffff00) | NoError
;
479 static void RenameFile(struct sigcontext_struct
*context
)
481 char *newname
, *oldname
;
483 fprintf(stderr
,"int21: renaming %s to %s\n",
484 pointer(DS
,DX
), pointer(ES
,DI
) );
486 oldname
= GetUnixFileName( pointer(DS
,DX
) );
487 newname
= GetUnixFileName( pointer(ES
,DI
) );
489 rename( oldname
, newname
);
494 static void MakeDir(struct sigcontext_struct
*context
)
498 fprintf(stderr
,"int21: makedir %s\n", pointer(DS
,DX
) );
500 if ((dirname
= GetUnixFileName( pointer(DS
,DX
) ))== NULL
) {
501 EAX
= (EAX
& 0xffffff00) | CanNotMakeDir
;
506 if (mkdir(dirname
,0) == -1) {
507 EAX
= (EAX
& 0xffffff00) | CanNotMakeDir
;
514 static void ChangeDir(struct sigcontext_struct
*context
)
517 char *dirname
= pointer(DS
,DX
);
518 drive
= DOS_GetDefaultDrive();
519 fprintf(stderr
,"int21: changedir %s\n", dirname
);
520 if (dirname
!= NULL
&& dirname
[1] == ':') {
521 drive
= toupper(dirname
[0]) - 'A';
524 DOS_ChangeDir(drive
, dirname
);
527 static void RemoveDir(struct sigcontext_struct
*context
)
531 fprintf(stderr
,"int21: removedir %s\n", pointer(DS
,DX
) );
533 if ((dirname
= GetUnixFileName( pointer(DS
,DX
) ))== NULL
) {
534 EAX
= (EAX
& 0xffffff00) | CanNotMakeDir
;
540 if (strcmp(unixname,DosDrives[drive].CurrentDirectory)) {
541 EAX = (EAX & 0xffffff00) | CanNotRemoveCwd;
545 if (rmdir(dirname
) == -1) {
546 EAX
= (EAX
& 0xffffff00) | CanNotMakeDir
;
552 static void ExecProgram(struct sigcontext_struct
*context
)
554 execl("wine", GetUnixFileName( pointer(DS
,DX
)) );
557 static void FindNext(struct sigcontext_struct
*context
)
559 struct dosdirent
*dp
;
561 dp
= (struct dosdirent
*)(dta
+ 0x0d);
564 if ((dp
= DOS_readdir(dp
)) == NULL
) {
565 Error(NoMoreFiles
, EC_MediaError
, EL_Disk
);
566 EAX
= (EAX
& 0xffffff00) | NoMoreFiles
;
570 } while (*(dta
+ 0x0c) != dp
->attribute
);
572 setword(&dta
[0x16], 0x1234); /* time */
573 setword(&dta
[0x18], 0x1234); /* date */
574 setdword(&dta
[0x1a], dp
->filesize
);
575 strncpy(dta
+ 0x1e, dp
->filename
, 13);
577 EAX
= (EAX
& 0xffffff00);
582 static void FindFirst(struct sigcontext_struct
*context
)
584 BYTE drive
, *path
= pointer(DS
, DX
);
585 struct dosdirent
*dp
;
587 if (path
[1] == ':') {
588 drive
= (islower(*path
) ? toupper(*path
) : *path
) - 'A';
590 if (!DOS_ValidDrive(drive
)) {
591 Error(InvalidDrive
, EC_MediaError
, EL_Disk
);
592 EAX
= (EAX
& 0xffffff00L
) | InvalidDrive
;
597 drive
= DOS_GetDefaultDrive();
600 memset(dta
+ 1 , '?', 11);
601 *(dta
+ 0x0c) = ECX
& (FA_LABEL
| FA_DIREC
);
603 if (ECX
& FA_LABEL
) {
604 /* return volume label */
606 if (DOS_GetVolumeLabel(drive
) != NULL
)
607 strncpy(dta
+ 0x1e, DOS_GetVolumeLabel(drive
), 8);
609 EAX
= (EAX
& 0xffffff00L
);
614 if ((dp
= DOS_opendir(path
)) == NULL
) {
615 Error(PathNotFound
, EC_MediaError
, EL_Disk
);
616 EAX
= (EAX
& 0xffffff00L
) | FileNotFound
;
621 memcpy(dta
+ 0x0d, &dp
, sizeof(dp
));
625 static void GetFileDateTime(struct sigcontext_struct
*context
)
628 struct stat filestat
;
631 if ((filename
= GetUnixFileName( pointer(DS
,DX
) ))== NULL
) {
632 EAX
= (EAX
& 0xffffff00) | FileNotFound
;
636 stat(filename
, &filestat
);
638 now
= localtime (&filestat
.st_mtime
);
640 ECX
= (ECX
& 0xffff0000) | ((now
->tm_hour
* 0x2000) + (now
->tm_min
* 0x20) + now
->tm_sec
/2);
641 EDX
= (EDX
& 0xffff0000) | ((now
->tm_year
* 0x200) + (now
->tm_mon
* 0x20) + now
->tm_mday
);
646 static void SetFileDateTime(struct sigcontext_struct
*context
)
649 struct utimbuf filetime
;
651 filename
= GetUnixFileName( pointer(DS
,DX
) );
653 filetime
.actime
= 0L;
654 filetime
.modtime
= filetime
.actime
;
656 utime(filename
, &filetime
);
660 static void CreateTempFile(struct sigcontext_struct
*context
)
665 sprintf(temp
,"%s\\win%d.tmp",TempDirectory
,(int) getpid());
667 fprintf(stderr
,"CreateTempFile %s\n",temp
);
669 handle
= open(GetUnixFileName(temp
), O_CREAT
| O_TRUNC
| O_RDWR
);
672 EAX
= (EAX
& 0xffffff00) | WriteProtected
;
677 strcpy(pointer(DS
,DX
), temp
);
679 EAX
= (EAX
& 0xffff0000) | handle
;
683 static void CreateNewFile(struct sigcontext_struct
*context
)
687 if ((handle
= open(GetUnixFileName( pointer(DS
,DX
) ), O_CREAT
| O_TRUNC
| O_RDWR
)) == -1) {
688 EAX
= (EAX
& 0xffffff00) | WriteProtected
;
693 EAX
= (EAX
& 0xffff0000) | handle
;
697 static void GetCurrentDirectory(struct sigcontext_struct
*context
)
701 if ((EDX
& 0xff) == 0)
702 drive
= DOS_GetDefaultDrive();
704 drive
= (EDX
& 0xff)-1;
706 if (!DOS_ValidDrive(drive
)) {
707 EAX
= (EAX
& 0xffffff00) | InvalidDrive
;
712 strcpy(pointer(DS
,SI
), DOS_GetCurrentDir(drive
) );
716 static void GetDiskSerialNumber(struct sigcontext_struct
*context
)
719 BYTE
*dataptr
= pointer(DS
, DX
);
722 if ((EBX
& 0xff) == 0)
723 drive
= DOS_GetDefaultDrive();
725 drive
= (EBX
& 0xff) - 1;
727 if (!DOS_ValidDrive(drive
)) {
728 EAX
= (EAX
& 0xffffff00) |InvalidDrive
;
733 DOS_GetSerialNumber(drive
, &serialnumber
);
736 setdword(&dataptr
[2], serialnumber
);
737 strncpy(dataptr
+ 6, DOS_GetVolumeLabel(drive
), 8);
738 strncpy(dataptr
+ 0x11, "FAT16 ", 8);
740 EAX
= (EAX
& 0xffffff00);
744 static void SetDiskSerialNumber(struct sigcontext_struct
*context
)
747 BYTE
*dataptr
= pointer(DS
, DX
);
750 if ((EBX
& 0xff) == 0)
751 drive
= DOS_GetDefaultDrive();
753 drive
= (EBX
& 0xff) - 1;
755 if (!DOS_ValidDrive(drive
)) {
756 EAX
= (EAX
& 0xffffff00) | InvalidDrive
;
761 serialnumber
= dataptr
[1] + (dataptr
[2] << 8) + (dataptr
[3] << 16) +
764 DOS_SetSerialNumber(drive
, serialnumber
);
765 EAX
= (EAX
& 0xffffff00) | 1L;
769 static void DumpFCB(BYTE
*fcb
)
775 for (y
= 0; y
!=2 ; y
++) {
776 for (x
= 0; x
!=15;x
++)
777 fprintf(stderr
, "%02x ", *fcb
++);
778 fprintf(stderr
,"\n");
782 /* microsoft's programmers should be shot for using CP/M style int21
783 calls in Windows for Workgroup's winfile.exe */
785 static void FindFirstFCB(struct sigcontext_struct
*context
)
787 BYTE
*fcb
= pointer(DS
, DX
);
795 drive
= DOS_GetDefaultDrive();
797 if (*(fcb
- 7) == 0xff) {
798 if (*(fcb
- 1) == FA_DIREC
) {
799 /* return volume label */
801 memset(dta
, ' ', 11);
802 if (DOS_GetVolumeLabel(drive
) != NULL
)
803 strncpy(dta
, DOS_GetVolumeLabel(drive
), 8);
804 *(dta
+ 0x0b) = FA_DIREC
;
806 EAX
= (EAX
& 0xffffff00);
810 IntBarf(0x21, context
);
813 static void DeleteFileFCB(struct sigcontext_struct
*context
)
815 BYTE
*fcb
= pointer(DS
, DX
);
817 struct dosdirent
*dp
;
818 char temp
[256], *ptr
;
825 drive
= DOS_GetDefaultDrive();
827 strcpy(temp
, DOS_GetCurrentDir(drive
));
829 strncat(temp
, fcb
+ 1, 8);
830 ChopOffWhiteSpace(temp
);
831 strncat(temp
, fcb
+ 9, 3);
832 ChopOffWhiteSpace(temp
);
834 if ((dp
= DOS_opendir(temp
)) == NULL
) {
835 Error(InvalidDrive
, EC_MediaError
, EL_Disk
);
836 EAX
= (EAX
& 0xffffff00) | 0xffL
;
840 strcpy(temp
, DOS_GetCurrentDir(drive
) );
843 ptr
= temp
+ strlen(temp
);
845 while (DOS_readdir(dp
) != NULL
)
847 strcpy(ptr
, dp
->filename
);
848 fprintf(stderr
, "int21: delete file %s\n", temp
);
849 /* unlink(GetUnixFileName(temp)); */
852 EAX
= (EAX
& 0xffffff00);
855 static void RenameFileFCB(struct sigcontext_struct
*context
)
857 BYTE
*fcb
= pointer(DS
, DX
);
859 struct dosdirent
*dp
;
860 char temp
[256], oldname
[256], newname
[256], *oldnameptr
, *newnameptr
;
867 drive
= DOS_GetDefaultDrive();
869 strcpy(temp
, DOS_GetCurrentDir(drive
));
871 strncat(temp
, fcb
+ 1, 8);
872 ChopOffWhiteSpace(temp
);
873 strncat(temp
, fcb
+ 9, 3);
874 ChopOffWhiteSpace(temp
);
876 if ((dp
= DOS_opendir(temp
)) == NULL
) {
877 Error(InvalidDrive
, EC_MediaError
, EL_Disk
);
878 EAX
= (EAX
& 0xffffff00) | 0xffL
;
882 strcpy(oldname
, DOS_GetCurrentDir(drive
) );
883 strcat(oldname
, "\\");
884 oldnameptr
= oldname
+ strlen(oldname
);
886 strcpy(newname
, DOS_GetCurrentDir(drive
) );
887 strcat(newname
, "\\");
888 newnameptr
= newname
+ strlen(newname
);
890 while (DOS_readdir(dp
) != NULL
)
892 strcpy(oldnameptr
, dp
->filename
);
893 strcpy(newnameptr
, fcb
+ 1);
894 fprintf(stderr
, "int21: renamefile %s -> %s\n", oldname
, newname
);
897 EAX
= (EAX
& 0xffffff00);
900 /************************************************************************/
902 int do_int21(struct sigcontext_struct
* context
)
906 if (Options
.relay_debug
)
908 printf("int21: AX %04x, BX %04x, CX %04x, DX %04x, "
909 "SI %04x, DI %04x, DS %04x, ES %04x\n",
910 AX
, BX
, CX
, DX
, SI
, DI
, DS
, ES
);
913 ah
= (EAX
>> 8) & 0xffL
;
917 GetExtendedErrorInfo(context
);
925 case 0x00: /* TERMINATE PROGRAM */
928 case 0x01: /* READ CHARACTER FROM STANDARD INPUT, WITH ECHO */
929 case 0x02: /* WRITE CHARACTER TO STANDARD OUTPUT */
930 case 0x03: /* READ CHARACTER FROM STDAUX */
931 case 0x04: /* WRITE CHARACTER TO STDAUX */
932 case 0x05: /* WRITE CHARACTER TO PRINTER */
933 case 0x06: /* DIRECT CONSOLE IN/OUTPUT */
934 case 0x07: /* DIRECT CHARACTER INPUT, WITHOUT ECHO */
935 case 0x08: /* CHARACTER INPUT WITHOUT ECHO */
936 case 0x09: /* WRITE STRING TO STANDARD OUTPUT */
937 case 0x0a: /* BUFFERED INPUT */
938 case 0x0b: /* GET STDIN STATUS */
939 case 0x0c: /* FLUSH BUFFER AND READ STANDARD INPUT */
940 case 0x0f: /* OPEN FILE USING FCB */
941 case 0x10: /* CLOSE FILE USING FCB */
942 case 0x12: /* FIND NEXT MATCHING FILE USING FCB */
943 case 0x14: /* SEQUENTIAL READ FROM FCB FILE */
944 case 0x15: /* SEQUENTIAL WRITE TO FCB FILE */
945 case 0x16: /* CREATE OR TRUNCATE FILE USING FCB */
946 case 0x21: /* READ RANDOM RECORD FROM FCB FILE */
947 case 0x22: /* WRITE RANDOM RECORD TO FCB FILE */
948 case 0x23: /* GET FILE SIZE FOR FCB */
949 case 0x24: /* SET RANDOM RECORD NUMBER FOR FCB */
950 case 0x26: /* CREATE NEW PROGRAM SEGMENT PREFIX */
951 case 0x27: /* RANDOM BLOCK READ FROM FCB FILE */
952 case 0x28: /* RANDOM BLOCK WRITE TO FCB FILE */
953 case 0x29: /* PARSE FILENAME INTO FCB */
954 case 0x2e: /* SET VERIFY FLAG */
955 IntBarf(0x21, context
);
958 case 0x18: /* NULL FUNCTIONS FOR CP/M COMPATIBILITY */
962 case 0x2b: /* SET SYSTEM DATE */
963 case 0x2d: /* SET SYSTEM TIME */
964 case 0x37: /* "SWITCHAR" - GET SWITCH CHARACTER
965 "SWITCHAR" - SET SWITCH CHARACTER
966 "AVAILDEV" - SPECIFY \DEV\ PREFIX USE */
967 case 0x54: /* GET VERIFY FLAG */
968 case 0x6b: /* NULL FUNCTION */
969 IntBarf(0x21, context
);
973 case 0x0d: /* DISK BUFFER FLUSH */
974 ResetCflag
; /* dos 6+ only */
977 case 0x0e: /* SELECT DEFAULT DRIVE */
978 if (!DOS_ValidDrive(EDX
& 0xff)) {
979 Error (InvalidDrive
, EC_MediaError
, EL_Disk
);
982 DOS_SetDefaultDrive(EDX
& 0xff);
983 EAX
= (EAX
&0xffffff00) | MAX_DOS_DRIVES
;
988 case 0x11: /* FIND FIRST MATCHING FILE USING FCB */
989 FindFirstFCB(context
);
992 case 0x13: /* DELETE FILE USING FCB */
993 DeleteFileFCB(context
);
996 case 0x17: /* RENAME FILE USING FCB */
997 RenameFileFCB(context
);
1000 case 0x19: /* GET CURRENT DEFAULT DRIVE */
1001 EAX
= (EAX
& 0xffffff00) | DOS_GetDefaultDrive();
1005 case 0x1a: /* SET DISK TRANSFER AREA ADDRESS */
1006 dta
= pointer(DS
, DX
);
1009 case 0x1b: /* GET ALLOCATION INFORMATION FOR DEFAULT DRIVE */
1010 GetDefDriveAllocInfo(context
);
1013 case 0x1c: /* GET ALLOCATION INFORMATION FOR SPECIFIC DRIVE */
1014 GetDriveAllocInfo(context
);
1017 case 0x1f: /* GET DRIVE PARAMETER BLOCK FOR DEFAULT DRIVE */
1018 GetDrivePB(context
);
1021 case 0x25: /* SET INTERRUPT VECTOR */
1022 /* Ignore any attempt to set a segment vector */
1023 fprintf(stderr
, "int21: set interrupt vector %2x (%04x:%04x)\n", AX
& 0xff, DS
, DX
);
1026 case 0x2a: /* GET SYSTEM DATE */
1027 GetSystemDate(context
);
1030 case 0x2c: /* GET SYSTEM TIME */
1031 GetSystemTime(context
);
1034 case 0x2f: /* GET DISK TRANSFER AREA ADDRESS */
1036 EBX
= (EBX
& 0xffff0000) | offset(dta
);
1039 case 0x30: /* GET DOS VERSION */
1040 EAX
= (EAX
& 0xffff0000) | DOSVERSION
;
1041 EBX
= (EBX
& 0xffff0000) | 0x0012; /* 0x123456 is Wine's serial # */
1042 ECX
= (ECX
& 0xffff0000) | 0x3456;
1045 case 0x31: /* TERMINATE AND STAY RESIDENT */
1046 IntBarf(0x21, context
);
1049 case 0x32: /* GET DOS DRIVE PARAMETER BLOCK FOR SPECIFIC DRIVE */
1050 GetDrivePB(context
);
1053 case 0x33: /* MULTIPLEXED */
1054 switch (EAX
& 0xff) {
1055 case 0x00: /* GET CURRENT EXTENDED BREAK STATE */
1060 case 0x01: /* SET EXTENDED BREAK STATE */
1063 case 0x02: /* GET AND SET EXTENDED CONTROL-BREAK CHECKING STATE*/
1067 case 0x05: /* GET BOOT DRIVE */
1068 EDX
= (EDX
& 0xff00) | 2;
1069 /* c: is Wine's bootdrive */
1072 case 0x06: /* GET TRUE VERSION NUMBER */
1078 IntBarf(0x21, context
);
1083 case 0x34: /* GET ADDRESS OF INDOS FLAG */
1084 ES
= (ES
& 0xffff0000) | segment(heap
->InDosFlag
);
1085 EBX
= (EBX
& 0xffff0000) | offset(heap
->InDosFlag
);
1088 case 0x35: /* GET INTERRUPT VECTOR */
1089 /* Return a NULL segment selector - this will bomb,
1090 if anyone ever tries to use it */
1091 fprintf(stderr
, "int21: get interrupt vector %2x\n", AX
& 0xff);
1096 case 0x36: /* GET FREE DISK SPACE */
1097 GetFreeDiskSpace(context
);
1100 case 0x38: /* GET COUNTRY-SPECIFIC INFORMATION */
1102 EAX
|= 0x02; /* no country support available */
1106 case 0x39: /* "MKDIR" - CREATE SUBDIRECTORY */
1110 case 0x3a: /* "RMDIR" - REMOVE SUBDIRECTORY */
1114 case 0x3b: /* "CHDIR" - SET CURRENT DIRECTORY */
1118 case 0x3c: /* "CREAT" - CREATE OR TRUNCATE FILE */
1119 CreateFile(context
);
1122 case 0x3d: /* "OPEN" - OPEN EXISTING FILE */
1123 OpenExistingFile(context
);
1126 case 0x3e: /* "CLOSE" - CLOSE FILE */
1130 case 0x3f: /* "READ" - READ FROM FILE OR DEVICE */
1134 case 0x40: /* "WRITE" - WRITE TO FILE OR DEVICE */
1138 case 0x41: /* "UNLINK" - DELETE FILE */
1139 if (unlink( GetUnixFileName( pointer(DS
,DX
)) ) == -1) {
1141 EAX
= (EAX
& 0xffffff00) | ExtendedError
;
1149 case 0x42: /* "LSEEK" - SET CURRENT FILE POSITION */
1153 case 0x43: /* FILE ATTRIBUTES */
1166 case 0x44: /* IOCTL */
1170 ioctlGetDeviceInfo(context
);
1173 case 0x09: /* CHECK IF BLOCK DEVICE REMOTE */
1174 EDX
= (EDX
& 0xffff0000) | (1<<9) | (1<<12);
1178 case 0x0b: /* SET SHARING RETRY COUNT */
1183 ioctlGenericBlkDevReq(context
);
1187 IntBarf(0x21, context
);
1192 case 0x45: /* "DUP" - DUPLICATE FILE HANDLE */
1193 case 0x46: /* "DUP2", "FORCEDUP" - FORCE DUPLICATE FILE HANDLE */
1194 EAX
= (EAX
& 0xffff0000) | dup(BX
);
1198 case 0x47: /* "CWD" - GET CURRENT DIRECTORY */
1199 GetCurrentDirectory(context
);
1200 EAX
= (EAX
& 0xffff0000) | 0x0100;
1201 /* intlist: many Microsoft products for Windows rely on this */
1204 case 0x48: /* ALLOCATE MEMORY */
1205 case 0x49: /* FREE MEMORY */
1206 case 0x4a: /* RESIZE MEMORY BLOCK */
1207 IntBarf(0x21, context
);
1210 case 0x4b: /* "EXEC" - LOAD AND/OR EXECUTE PROGRAM */
1211 ExecProgram(context
);
1214 case 0x4c: /* "EXIT" - TERMINATE WITH RETURN CODE */
1218 case 0x4d: /* GET RETURN CODE */
1219 EAX
= (EAX
& 0xffffff00) | NoError
; /* normal exit */
1222 case 0x4e: /* "FINDFIRST" - FIND FIRST MATCHING FILE */
1226 case 0x4f: /* "FINDNEXT" - FIND NEXT MATCHING FILE */
1230 case 0x52: /* "SYSVARS" - GET LIST OF LISTS */
1232 EBX
= (EBX
& 0xffff0000);
1233 IntBarf(0x21, context
);
1236 case 0x56: /* "RENAME" - RENAME FILE */
1237 RenameFile(context
);
1240 case 0x57: /* FILE DATE AND TIME */
1244 GetFileDateTime(context
);
1247 SetFileDateTime(context
);
1252 case 0x58: /* GET OR SET MEMORY/UMB ALLOCATION STRATEGY */
1256 EAX
= (EAX
& 0xffffff00) | 0x01L
;
1268 case 0x5a: /* CREATE TEMPORARY FILE */
1269 CreateTempFile(context
);
1272 case 0x5b: /* CREATE NEW FILE */
1273 CreateNewFile(context
);
1276 case 0x5c: /* "FLOCK" - RECORD LOCKING */
1277 IntBarf(0x21, context
);
1280 case 0x5d: /* NETWORK */
1282 /* network software not installed */
1283 EAX
= (EAX
& 0xfffff00) | NoNetwork
;
1287 case 0x5f: /* NETWORK */
1290 case 0x07: /* ENABLE DRIVE */
1291 if (!DOS_EnableDrive(EDX
& 0xff))
1293 Error(InvalidDrive
, EC_MediaError
, EL_Disk
);
1294 EAX
= (EAX
& 0xfffff00) | InvalidDrive
;
1303 case 0x08: /* DISABLE DRIVE */
1304 if (!DOS_DisableDrive(EDX
& 0xff))
1306 Error(InvalidDrive
, EC_MediaError
, EL_Disk
);
1307 EAX
= (EAX
& 0xfffff00) | InvalidDrive
;
1317 /* network software not installed */
1318 EAX
= (EAX
& 0xfffff00) | NoNetwork
;
1324 case 0x60: /* "TRUENAME" - CANONICALIZE FILENAME OR PATH */
1325 strncpy(pointer(ES
,DI
), pointer(DS
,SI
), strlen(pointer(DS
,SI
)) & 0x7f);
1329 case 0x61: /* UNUSED */
1330 case 0x62: /* GET CURRENT PSP ADDRESS */
1331 case 0x63: /* UNUSED */
1332 case 0x64: /* OS/2 DOS BOX */
1333 case 0x65: /* GET EXTENDED COUNTRY INFORMATION */
1334 IntBarf(0x21, context
);
1337 case 0x66: /* GLOBAL CODE PAGE TABLE */
1352 case 0x67: /* SET HANDLE COUNT */
1356 case 0x68: /* "FFLUSH" - COMMIT FILE */
1360 case 0x69: /* DISK SERIAL NUMBER */
1364 GetDiskSerialNumber(context
);
1367 SetDiskSerialNumber(context
);
1372 case 0x6a: /* COMMIT FILE */
1376 case 0xea: /* NOVELL NETWARE - RETURN SHELL VERSION */
1380 IntBarf(0x21, context
);
1387 /**********************************************************************
1392 do_int21((struct sigcontext_struct
*) _CONTEXT
);
1393 ReturnFromRegisterFunc();
1396 void INT21_Init(void)
1401 if ((handle
= GlobalAlloc(GMEM_FIXED
,sizeof(struct DosHeap
))) == 0)
1402 myerror("out of memory");
1404 heap
= (struct DosHeap
*) GlobalLock(handle
);
1405 HEAP_Init(&DosHeapDesc
, heap
, sizeof(struct DosHeap
));
1408 heap
->InDosFlag
= 0;
1409 strcpy(heap
->biosdate
, "01/01/80");