Release 940405
[wine/gsoc-2012-control.git] / miscemu / int21.c
blob350f9e0baf0d02d3181b22390a19e09d819c3358
1 #include <time.h>
2 #include <fcntl.h>
3 #include <errno.h>
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <string.h>
7 #include <sys/stat.h>
8 #include <unistd.h>
9 #include <utime.h>
11 #include "prototypes.h"
12 #include "regfunc.h"
13 #include "windows.h"
14 #include "wine.h"
15 #include "msdos.h"
16 #include "options.h"
18 static char Copyright[] = "copyright Erik Bos, 1993";
20 WORD ExtendedError, CodePage = 437;
21 BYTE ErrorClass, Action, ErrorLocus;
22 BYTE *dta;
24 extern char TempDirectory[];
26 static int Error(int e, int class, int el)
28 ErrorClass = class;
29 Action = SA_Ask4Retry;
30 ErrorLocus = el;
31 ExtendedError = e;
33 return e;
36 static void Barf(struct sigcontext_struct *context)
38 fprintf(stderr, "int21: unknown/not implemented parameters:\n");
39 fprintf(stderr, "int21: AX %04x, BX %04x, CX %04x, DX %04x, "
40 "SI %04x, DI %04x, DS %04x, ES %04x\n",
41 AX, BX, CX, DX, SI, DI, DS, ES);
44 void ChopOffWhiteSpace(char *string)
46 int length;
48 for (length = strlen(string) ; length ; length--)
49 if (string[length] == ' ')
50 string[length] = '\0';
53 static void CreateBPB(int drive, BYTE *data)
55 if (drive > 1) {
56 setword(data, 512);
57 data[2] = 2;
58 setword(&data[3], 0);
59 data[5] = 2;
60 setword(&data[6], 240);
61 setword(&data[8], 64000);
62 data[0x0a] = 0xf8;
63 setword(&data[0x0b], 40);
64 setword(&data[0x0d], 56);
65 setword(&data[0x0f], 2);
66 setword(&data[0x11], 0);
67 setword(&data[0x1f], 800);
68 data[0x21] = 5;
69 setword(&data[0x22], 1);
70 } else { /* 1.44mb */
71 setword(data, 512);
72 data[2] = 2;
73 setword(&data[3], 0);
74 data[5] = 2;
75 setword(&data[6], 240);
76 setword(&data[8], 2880);
77 data[0x0a] = 0xf8;
78 setword(&data[0x0b], 6);
79 setword(&data[0x0d], 18);
80 setword(&data[0x0f], 2);
81 setword(&data[0x11], 0);
82 setword(&data[0x1f], 80);
83 data[0x21] = 7;
84 setword(&data[0x22], 2);
88 static void GetFreeDiskSpace(struct sigcontext_struct *context)
90 int drive;
91 long size,available;
93 if (!(EDX & 0xffL))
94 drive = DOS_GetDefaultDrive();
95 else
96 drive = (EDX & 0xffL) - 1;
98 if (!DOS_ValidDrive(drive)) {
99 Error(InvalidDrive, EC_MediaError , EL_Disk);
100 EAX |= 0xffffL;
101 return;
104 if (!DOS_GetFreeSpace(drive, &size, &available)) {
105 Error(GeneralFailure, EC_MediaError , EL_Disk);
106 EAX |= 0xffffL;
107 return;
110 EAX = (EAX & 0xffff0000L) | 4;
111 ECX = (ECX & 0xffff0000L) | 512;
113 EBX = (EBX & 0xffff0000L) | (available / (CX * AX));
114 EDX = (EDX & 0xffff0000L) | (size / (CX * AX));
115 Error (0,0,0);
118 static void SetDefaultDrive(struct sigcontext_struct *context)
120 int drive;
122 drive = EDX & 0xffL;
124 if (!DOS_ValidDrive(drive)) {
125 Error (InvalidDrive, EC_MediaError, EL_Disk);
126 return;
127 } else {
128 DOS_SetDefaultDrive(drive);
129 EAX = (EAX &0xffffff00L) | MAX_DOS_DRIVES;
130 Error (0,0,0);
134 static void GetDefaultDrive(struct sigcontext_struct *context)
136 EAX = (EAX & 0xffffff00L) | DOS_GetDefaultDrive();
137 Error (0,0,0);
140 static void GetDriveAllocInfo(struct sigcontext_struct *context)
142 int drive;
143 long size, available;
144 BYTE mediaID;
146 drive = EDX & 0xffL;
148 if (!DOS_ValidDrive(drive)) {
149 EAX = (EAX & 0xffff0000L) | 4;
150 ECX = (ECX & 0xffff0000L) | 512;
151 EDX = (EDX & 0xffff0000L);
152 Error (InvalidDrive, EC_MediaError, EL_Disk);
153 return;
156 if (!DOS_GetFreeSpace(drive, &size, &available)) {
157 Error(GeneralFailure, EC_MediaError , EL_Disk);
158 EAX |= 0xffffL;
159 return;
162 EAX = (EAX & 0xffff0000L) | 4;
163 ECX = (ECX & 0xffff0000L) | 512;
164 EDX = (EDX & 0xffff0000L) | (size / (CX * AX));
166 mediaID = 0xf0;
168 DS = segment(mediaID);
169 EBX = offset(mediaID);
170 Error (0,0,0);
173 static void GetDefDriveAllocInfo(struct sigcontext_struct *context)
175 EDX = DOS_GetDefaultDrive();
176 GetDriveAllocInfo(context);
179 static void GetDrivePB(struct sigcontext_struct *context)
181 Error (InvalidDrive, EC_MediaError, EL_Disk);
182 EAX = (EAX & 0xffff0000L) | 0xffL;
183 /* I'm sorry but I only got networked drives :-) */
186 static void ReadFile(struct sigcontext_struct *context)
188 char *ptr;
189 int size;
191 /* can't read from stdout / stderr */
193 if ((BX == 1) || (BX == 2)) {
194 Error (InvalidHandle, EL_Unknown, EC_Unknown);
195 EAX = (EAX & 0xffff0000L) | InvalidHandle;
196 SetCflag;
197 return;
200 ptr = pointer (DS,DX);
202 if (BX == 0) {
203 *ptr = EOF;
204 Error (0,0,0);
205 EAX = (EAX & 0xffff0000L) | 1;
206 ResetCflag;
207 return;
208 } else {
209 size = read(BX, ptr, CX);
210 if (size == 0) {
211 Error (ReadFault, EC_Unknown, EL_Unknown);
212 EAX = (EAX & 0xffffff00L) | ExtendedError;
213 return;
216 if (size == -1) {
217 switch (errno) {
218 case EAGAIN:
219 Error (ShareViolation, EC_Temporary, EL_Unknown);
220 break;
221 case EBADF:
222 Error (InvalidHandle, EC_AppError, EL_Unknown);
223 break;
224 default:
225 Error (GeneralFailure, EC_SystemFailure, EL_Unknown);
226 break;
228 EAX = (EAX & 0xffffff00L) | ExtendedError;
229 SetCflag;
230 return;
232 Error (0,0,0);
233 EAX = (EAX & 0xffff0000L) | size;
234 ResetCflag;
238 static void WriteFile(struct sigcontext_struct *context)
240 char *ptr;
241 int x,size;
243 ptr = pointer (DS,DX);
245 if (BX == 0) {
246 Error (InvalidHandle, EC_Unknown, EL_Unknown);
247 EAX = InvalidHandle;
248 SetCflag;
249 return;
252 if (BX < 3) {
253 for (x = 0;x != CX;x++) {
254 fprintf(stderr, "%c", *ptr++);
256 fflush(stderr);
258 Error (0,0,0);
259 EAX = (EAX & 0xffffff00L) | CX;
260 ResetCflag;
261 } else {
262 size = write(BX, ptr , CX);
263 if (size == 0) {
264 Error (WriteFault, EC_Unknown, EL_Unknown);
265 EAX = (EAX & 0xffffff00L) | ExtendedError;
266 return;
269 if (size == -1) {
270 switch (errno) {
271 case EAGAIN:
272 Error (ShareViolation, EC_Temporary, EL_Unknown);
273 break;
274 case EBADF:
275 Error (InvalidHandle, EC_AppError, EL_Unknown);
276 break;
277 case ENOSPC:
278 Error (DiskFull, EC_MediaError, EL_Disk);
279 break;
280 default:
281 Error (GeneralFailure, EC_SystemFailure, EL_Unknown);
282 break;
284 EAX = (EAX & 0xffffff00L) | ExtendedError;
285 SetCflag;
286 return;
288 Error (0,0,0);
289 EAX = (EAX & 0xffff0000L) | size;
290 ResetCflag;
294 static void UnlinkFile(struct sigcontext_struct *context)
296 if (unlink( GetUnixFileName( pointer(DS,DX)) ) == -1) {
297 switch (errno) {
298 case EACCES:
299 case EPERM:
300 case EROFS:
301 Error (WriteProtected, EC_AccessDenied, EL_Unknown);
302 break;
303 case EBUSY:
304 Error (LockViolation, EC_AccessDenied, EL_Unknown);
305 break;
306 case EAGAIN:
307 Error (ShareViolation, EC_Temporary, EL_Unknown);
308 break;
309 case ENOENT:
310 Error (FileNotFound, EC_NotFound, EL_Unknown);
311 break;
312 default:
313 Error (GeneralFailure, EC_SystemFailure, EL_Unknown);
314 break;
316 EAX = (EAX & 0xffffff00L) | ExtendedError; SetCflag;
317 return;
319 Error (0,0,0);
320 ResetCflag;
323 static void SeekFile(struct sigcontext_struct *context)
325 int status, fileoffset;
327 switch (EAX & 0xffL) {
328 case 1: fileoffset = SEEK_CUR;
329 break;
330 case 2: fileoffset = SEEK_END;
331 break;
332 default:
333 case 0: fileoffset = SEEK_SET;
334 break;
336 status = lseek(BX, (CX * 0x100) + DX, fileoffset);
337 if (status == -1) {
338 switch (errno) {
339 case EBADF:
340 Error (InvalidHandle, EC_AppError, EL_Unknown);
341 break;
342 case EINVAL:
343 Error (DataInvalid, EC_AppError, EL_Unknown);
344 break;
345 default:
346 Error (GeneralFailure, EC_SystemFailure, EL_Unknown);
347 break;
349 EAX = (EAX & 0xffffff00L) | ExtendedError; SetCflag;
350 return;
352 Error (0,0,0);
353 ResetCflag;
356 static void GetFileAttributes(struct sigcontext_struct *context)
358 EAX &= 0xfffff00L;
359 ResetCflag;
362 static void SetFileAttributes(struct sigcontext_struct *context)
364 ResetCflag;
367 static void ioctlGetDeviceInfo(struct sigcontext_struct *context)
369 WORD handle = EBX & 0xffff;
371 switch (handle) {
372 case 0:
373 case 1:
374 case 2:
375 EDX = (EDX & 0xffff0000) | 0x80d3;
376 break;
378 default:
379 Barf(context);
380 EDX = (EDX & 0xffff0000) | 0x50;
382 ResetCflag;
385 static void ioctlGenericBlkDevReq(struct sigcontext_struct *context)
387 BYTE *dataptr = pointer(DS, DX);
388 int drive;
390 if (!(EBX & 0xffL))
391 drive = DOS_GetDefaultDrive();
392 else
393 drive = (EBX & 0xffL) - 1;
395 if ((ECX & 0xff00L) != 0x0800) {
396 Barf(context);
397 return;
399 switch (ECX & 0xffL) {
400 case 0x60: /* get device parameters */
401 /* used by w4wgrp's winfile */
402 dataptr[0] = 0x04;
403 dataptr[6] = 0; /* media type */
404 if (drive > 1)
406 dataptr[1] = 0x05; /* fixed disk */
407 setword(&dataptr[2], 0x01); /* non removable */
408 setword(&dataptr[4], 0x300); /* # of cylinders */
410 else
412 dataptr[1] = 0x07; /* block dev, floppy */
413 setword(&dataptr[2], 0x02); /* removable */
414 setword(&dataptr[4], 80); /* # of cylinders */
416 CreateBPB(drive, &dataptr[7]);
417 EAX = (EAX & 0xfffff00L);
418 ResetCflag;
419 return;
420 default:
421 Barf(context);
425 static void DupeFileHandle(struct sigcontext_struct *context)
427 EAX = (EAX & 0xffff0000L) | dup(BX);
428 ResetCflag;
431 static void GetSystemDate(struct sigcontext_struct *context)
433 struct tm *now;
434 time_t ltime;
436 ltime = time(NULL);
437 now = localtime(&ltime);
439 ECX = (ECX & 0xffff0000L) | (now->tm_year + 1900);
440 EDX = (EDX & 0xffff0000L) | ((now->tm_mon + 1) << 8) | now->tm_mday;
441 EAX = (EAX & 0xffff0000L) | now->tm_wday;
444 static void GetSystemTime(struct sigcontext_struct *context)
446 struct tm *now;
447 time_t ltime;
449 ltime = time(NULL);
450 now = localtime(&ltime);
452 ECX = (ECX & 0xffffff00L) | (now->tm_hour << 8) | now->tm_min;
453 EDX = (EDX & 0xffffff00L) | now->tm_sec << 8;
456 static void GetExtendedErrorInfo(struct sigcontext_struct *context)
458 EAX = (EAX & 0xffffff00L) | ExtendedError;
459 EBX = (EBX & 0xffff0000L) | (0x100 * ErrorClass) | Action;
460 ECX = (ECX & 0xffff00ffL) | (0x100 * ErrorLocus);
463 static void GetInDosFlag(struct sigcontext_struct *context)
465 const BYTE InDosFlag = 0;
467 ES = (ES & 0xffff0000L) | segment(InDosFlag);
468 EBX = (EBX & 0xffff0000L) | offset(InDosFlag);
471 static void CreateFile(struct sigcontext_struct *context)
473 int handle;
475 if ((handle = open(GetUnixFileName( pointer(DS,DX)), O_CREAT | O_TRUNC)) == -1) {
476 switch (errno) {
477 case EACCES:
478 case EPERM:
479 case EROFS:
480 Error (WriteProtected, EC_AccessDenied, EL_Unknown);
481 break;
482 case EISDIR:
483 Error (CanNotMakeDir, EC_AccessDenied, EL_Unknown);
484 break;
485 case ENFILE:
486 case EMFILE:
487 Error (NoMoreFiles, EC_MediaError, EL_Unknown);
488 case EEXIST:
489 Error (FileExists, EC_Exists, EL_Disk);
490 break;
491 case ENOSPC:
492 Error (DiskFull, EC_MediaError, EL_Disk);
493 break;
494 default:
495 Error (GeneralFailure, EC_SystemFailure, EL_Unknown);
496 break;
498 EAX = (EAX & 0xffffff00L) | ExtendedError;
499 SetCflag;
500 return;
502 Error (0,0,0);
503 EBX = (EBX & 0xffff0000L) | handle;
504 EAX = (EAX & 0xffffff00L) | NoError;
505 ResetCflag;
508 static void OpenExistingFile(struct sigcontext_struct *context)
510 int handle;
512 fprintf(stderr,"OpenExistingFile (%s)\n", pointer(DS,DX));
514 if ((handle = open(GetUnixFileName(pointer(DS,DX)), O_RDWR)) == -1) {
515 switch (errno) {
516 case EACCES:
517 case EPERM:
518 case EROFS:
519 Error (WriteProtected, EC_AccessDenied, EL_Unknown);
520 break;
521 case EISDIR:
522 Error (CanNotMakeDir, EC_AccessDenied, EL_Unknown);
523 break;
524 case ENFILE:
525 case EMFILE:
526 Error (NoMoreFiles, EC_MediaError, EL_Unknown);
527 case EEXIST:
528 Error (FileExists, EC_Exists, EL_Disk);
529 break;
530 case ENOSPC:
531 Error (DiskFull, EC_MediaError, EL_Disk);
532 break;
533 case ENOENT:
534 Error (FileNotFound, EC_MediaError, EL_Disk);
535 break;
536 default:
537 Error (GeneralFailure, EC_SystemFailure, EL_Unknown);
538 break;
540 EAX = (EAX & 0xffffff00L) | ExtendedError;
541 SetCflag;
542 return;
544 Error (0,0,0);
545 EBX = (EBX & 0xffff0000L) | handle;
546 EAX = (EAX & 0xffffff00L) | NoError;
547 ResetCflag;
550 static void CloseFile(struct sigcontext_struct *context)
552 if (close(BX) == -1) {
553 switch (errno) {
554 case EBADF:
555 Error (InvalidHandle, EC_AppError, EL_Unknown);
556 break;
557 default:
558 Error (GeneralFailure, EC_SystemFailure, EL_Unknown);
559 break;
561 EAX = (EAX & 0xffffff00L) | ExtendedError;
562 SetCflag;
563 return;
565 Error (0,0,0);
566 EAX = (EAX & 0xffffff00L) | NoError;
567 ResetCflag;
570 static void RenameFile(struct sigcontext_struct *context)
572 char *newname, *oldname;
574 fprintf(stderr,"int21: renaming %s to %s\n",
575 pointer(DS,DX), pointer(ES,DI) );
577 oldname = GetUnixFileName( pointer(DS,DX) );
578 newname = GetUnixFileName( pointer(ES,DI) );
580 rename( oldname, newname);
581 ResetCflag;
584 static void GetTrueFileName(struct sigcontext_struct *context)
586 fprintf(stderr,"int21: GetTrueFileName of %s\n", pointer(DS,SI) );
588 strncpy(pointer(ES,DI), pointer(DS,SI), strlen(pointer(DS,SI)) & 0x7f);
589 ResetCflag;
592 static void MakeDir(struct sigcontext_struct *context)
594 char *dirname;
596 fprintf(stderr,"int21: makedir %s\n", pointer(DS,DX) );
598 if ((dirname = GetUnixFileName( pointer(DS,DX) ))== NULL) {
599 EAX = (EAX & 0xffffff00L) | CanNotMakeDir;
600 SetCflag;
601 return;
604 if (mkdir(dirname,0) == -1) {
605 EAX = (EAX & 0xffffff00L) | CanNotMakeDir;
606 SetCflag;
607 return;
609 ResetCflag;
612 static void ChangeDir(struct sigcontext_struct *context)
614 int drive;
615 char *dirname = pointer(DS,DX);
616 drive = DOS_GetDefaultDrive();
617 fprintf(stderr,"int21: changedir %s\n", dirname);
618 if (dirname != NULL && dirname[1] == ':') {
619 drive = toupper(dirname[0]) - 'A';
620 dirname += 2;
622 DOS_ChangeDir(drive, dirname);
625 static void RemoveDir(struct sigcontext_struct *context)
627 char *dirname;
629 fprintf(stderr,"int21: removedir %s\n", pointer(DS,DX) );
631 if ((dirname = GetUnixFileName( pointer(DS,DX) ))== NULL) {
632 EAX = (EAX & 0xffffff00L) | CanNotMakeDir;
633 SetCflag;
634 return;
638 if (strcmp(unixname,DosDrives[drive].CurrentDirectory)) {
639 EAX = (EAX & 0xffffff00L) | CanNotRemoveCwd;
640 SetCflag;
643 if (rmdir(dirname) == -1) {
644 EAX = (EAX & 0xffffff00L) | CanNotMakeDir;
645 SetCflag;
647 ResetCflag;
650 static void AllocateMemory(struct sigcontext_struct *context)
652 char *ptr;
654 fprintf(stderr,"int21: malloc %d bytes\n", BX * 0x10 );
656 /* if ((ptr = (void *) memalign((size_t) (BX * 0x10), 0x10)) == NULL) {
657 EAX = (EAX & 0xffffff00L) | OutOfMemory;
658 EBX = (EBX & 0xffffff00L);
659 SetCflag;
661 fprintf(stderr,"int21: malloc (ptr = %d)\n", ptr );
663 EAX = (EAX & 0xffff0000L) | segment(ptr);
665 Barf(context);
666 SetCflag;
669 static void FreeMemory(struct sigcontext_struct *context)
671 fprintf(stderr,"int21: freemem (ptr = %d)\n", ES * 0x10 );
673 free((void *)(ES * 0x10));
674 */ Barf(context);
675 ResetCflag;
678 static void ResizeMemoryBlock(struct sigcontext_struct *context)
680 char *ptr;
682 fprintf(stderr,"int21: realloc (ptr = %d)\n", ES * 0x10 );
684 /* if ((ptr = (void *) realloc((void *)(ES * 0x10), (size_t) BX * 0x10)) == NULL) {
685 EAX = (EAX & 0xffffff00L) | OutOfMemory;
686 EBX = (EBX & 0xffffff00L);
687 SetCflag;
689 EBX = (EBX & 0xffff0000L) | segment(ptr);
690 */ Barf(context);
691 SetCflag;
694 static void ExecProgram(struct sigcontext_struct *context)
696 execl("wine", GetUnixFileName( pointer(DS,DX)) );
699 static void GetReturnCode(struct sigcontext_struct *context)
701 EAX = (EAX & 0xffffff00L) | NoError; /* normal exit */
704 static void FindNext(struct sigcontext_struct *context)
706 struct dosdirent *dp;
708 dp = (struct dosdirent *)(dta + 0x0d);
710 do {
711 if ((dp = DOS_readdir(dp)) == NULL) {
712 DOS_closedir(dp);
713 Error(NoMoreFiles, EC_MediaError , EL_Disk);
714 EAX = (EAX & 0xffffff00L) | NoMoreFiles;
715 SetCflag;
716 return;
718 } while (*(dta + 0x0c) != dp->attribute);
720 setword(&dta[0x16], 0x1234); /* time */
721 setword(&dta[0x18], 0x1234); /* date */
722 setdword(&dta[0x1a], dp->filesize);
723 strncpy(dta + 0x1e, dp->filename, 13);
725 EAX = (EAX & 0xffffff00L);
726 ResetCflag;
727 return;
730 static void FindFirst(struct sigcontext_struct *context)
732 BYTE drive, *path = pointer(DS, DX);
733 struct dosdirent *dp;
735 if (path[1] == ':') {
736 drive = (islower(*path) ? toupper(*path) : *path) - 'A';
738 if (!DOS_ValidDrive(drive)) {
739 Error(InvalidDrive, EC_MediaError , EL_Disk);
740 EAX = (EAX & 0xffffff00L) | InvalidDrive;
741 SetCflag;
742 return;
744 } else
745 drive = DOS_GetDefaultDrive();
747 *dta = drive;
748 memset(dta + 1 , '?', 11);
749 *(dta + 0x0c) = ECX & (FA_LABEL | FA_DIREC);
751 if (ECX & FA_LABEL) {
752 /* return volume label */
754 if (DOS_GetVolumeLabel(drive) != NULL)
755 strncpy(dta + 0x1e, DOS_GetVolumeLabel(drive), 8);
757 EAX = (EAX & 0xffffff00L);
758 ResetCflag;
759 return;
762 if ((dp = DOS_opendir(path)) == NULL) {
763 Error(PathNotFound, EC_MediaError, EL_Disk);
764 EAX = (EAX & 0xffffff00L) | FileNotFound;
765 SetCflag;
766 return;
768 /* strncpy(dta + 1, AsciizToFCB(dp->filemask), 11); */
770 /* *((BYTE *) ((void*)dta + 0x0d)) = (BYTE *) dp; */
772 *((struct dosdirent *)(dta + 0x0d))
774 *dp;
775 FindNext(context);
778 static void GetSysVars(struct sigcontext_struct *context)
780 /* return a null pointer, to encourage anyone who tries to
781 use the pointer */
783 ES = 0x0;
784 EBX = (EBX & 0xffff0000L);
785 Barf(context);
788 static void GetFileDateTime(struct sigcontext_struct *context)
790 char *filename;
791 struct stat filestat;
792 struct tm *now;
794 if ((filename = GetUnixFileName( pointer(DS,DX) ))== NULL) {
795 EAX = (EAX & 0xffffff00L) | FileNotFound;
796 SetCflag;
797 return;
799 stat(filename, &filestat);
801 now = localtime (&filestat.st_mtime);
803 ECX = (ECX & 0xffff0000L) | ((now->tm_hour * 0x2000) + (now->tm_min * 0x20) + now->tm_sec/2);
804 EDX = (EDX & 0xffff0000L) | ((now->tm_year * 0x200) + (now->tm_mon * 0x20) + now->tm_mday);
806 ResetCflag;
809 static void SetFileDateTime(struct sigcontext_struct *context)
811 char *filename;
812 struct utimbuf filetime;
814 filename = GetUnixFileName( pointer(DS,DX) );
816 filetime.actime = 0L;
817 filetime.modtime = filetime.actime;
819 utime(filename, &filetime);
820 ResetCflag;
823 static void CreateTempFile(struct sigcontext_struct *context)
825 char temp[256];
826 int handle;
828 sprintf(temp,"%s\\win%d.tmp",TempDirectory,(int) getpid());
830 fprintf(stderr,"CreateTempFile %s\n",temp);
832 handle = open(GetUnixFileName(temp), O_CREAT | O_TRUNC | O_RDWR);
834 if (handle == -1) {
835 EAX = (EAX & 0xffffff00L) | WriteProtected;
836 SetCflag;
837 return;
840 strcpy(pointer(DS,DX), temp);
842 EAX = (EAX & 0xffff0000L) | handle;
843 ResetCflag;
846 static void CreateNewFile(struct sigcontext_struct *context)
848 int handle;
850 if ((handle = open(GetUnixFileName( pointer(DS,DX) ), O_CREAT | O_TRUNC | O_RDWR)) == -1) {
851 EAX = (EAX & 0xffffff00L) | WriteProtected;
852 SetCflag;
853 return;
856 EAX = (EAX & 0xffff0000L) | handle;
857 ResetCflag;
860 static void FileLock(struct sigcontext_struct *context)
862 fprintf(stderr, "int21: flock()\n");
865 static void GetExtendedCountryInfo(struct sigcontext_struct *context)
867 ResetCflag;
870 static void GetCurrentDirectory(struct sigcontext_struct *context)
872 int drive;
874 if ((EDX & 0xffL) == 0)
875 drive = DOS_GetDefaultDrive();
876 else
877 drive = (EDX & 0xffL)-1;
879 if (!DOS_ValidDrive(drive)) {
880 EAX = (EAX & 0xffffff00L) | InvalidDrive;
881 SetCflag;
882 return;
885 strcpy(pointer(DS,SI), DOS_GetCurrentDir(drive) );
886 ResetCflag;
889 static void GetCurrentPSP(struct sigcontext_struct *context)
891 Barf(context);
894 static void GetDiskSerialNumber(struct sigcontext_struct *context)
896 int drive;
897 BYTE *dataptr = pointer(DS, DX);
898 DWORD serialnumber;
900 if ((EBX & 0xffL) == 0)
901 drive = DOS_GetDefaultDrive();
902 else
903 drive = (EBX & 0xffL) - 1;
905 if (!DOS_ValidDrive(drive)) {
906 EAX = (EAX & 0xffffff00L) |InvalidDrive;
907 SetCflag;
908 return;
911 DOS_GetSerialNumber(drive, &serialnumber);
913 setword(dataptr, 0);
914 setdword(&dataptr[2], serialnumber);
915 strncpy(dataptr + 6, DOS_GetVolumeLabel(drive), 8);
916 strncpy(dataptr + 0x11, "FAT16 ", 8);
918 EAX = (EAX & 0xffffff00L);
919 ResetCflag;
922 static void SetDiskSerialNumber(struct sigcontext_struct *context)
924 int drive;
925 BYTE *dataptr = pointer(DS, DX);
926 DWORD serialnumber;
928 if ((EBX & 0xffL) == 0)
929 drive = DOS_GetDefaultDrive();
930 else
931 drive = (EBX & 0xffL) - 1;
933 if (!DOS_ValidDrive(drive)) {
934 EAX = (EAX & 0xffffff00L) | InvalidDrive;
935 SetCflag;
936 return;
939 serialnumber = dataptr[1] + (dataptr[2] << 8) + (dataptr[3] << 16) +
940 (dataptr[4] << 24);
942 DOS_SetSerialNumber(drive, serialnumber);
943 EAX = (EAX & 0xffffff00L) | 1L;
944 ResetCflag;
947 static void DumpFCB(BYTE *fcb)
949 int x, y;
951 fcb -= 7;
953 for (y = 0; y !=2 ; y++) {
954 for (x = 0; x!=15;x++)
955 fprintf(stderr, "%02x ", *fcb++);
956 fprintf(stderr,"\n");
960 /* microsoft's programmers should be shot for using CP/M style int21
961 calls in Windows for Workgroup's winfile.exe */
963 static void FindFirstFCB(struct sigcontext_struct *context)
965 BYTE *fcb = pointer(DS, DX);
966 int drive;
968 DumpFCB( fcb );
970 if (*fcb)
971 drive = *fcb - 1;
972 else
973 drive = DOS_GetDefaultDrive();
975 if (*(fcb - 7) == 0xff) {
976 if (*(fcb - 1) == FA_DIREC) {
977 /* return volume label */
979 memset(dta, ' ', 11);
980 if (DOS_GetVolumeLabel(drive) != NULL)
981 strncpy(dta, DOS_GetVolumeLabel(drive), 8);
982 *(dta + 0x0b) = FA_DIREC;
984 EAX = (EAX & 0xffffff00L);
985 return;
988 Barf(context);
991 static void DeleteFileFCB(struct sigcontext_struct *context)
993 BYTE *fcb = pointer(DS, DX);
994 int drive;
995 struct dosdirent *dp;
996 char temp[256], *ptr;
998 DumpFCB( fcb );
1000 if (*fcb)
1001 drive = *fcb - 1;
1002 else
1003 drive = DOS_GetDefaultDrive();
1005 strcpy(temp, DOS_GetCurrentDir(drive));
1006 strcat(temp, "\\");
1007 strncat(temp, fcb + 1, 8);
1008 ChopOffWhiteSpace(temp);
1009 strncat(temp, fcb + 9, 3);
1010 ChopOffWhiteSpace(temp);
1012 if ((dp = DOS_opendir(temp)) == NULL) {
1013 Error(InvalidDrive, EC_MediaError , EL_Disk);
1014 EAX = (EAX & 0xffffff00L) | 0xffL;
1015 return;
1018 strcpy(temp, DOS_GetCurrentDir(drive) );
1019 strcat(temp, "\\");
1021 ptr = temp + strlen(temp);
1023 while (DOS_readdir(dp) != NULL)
1025 strcpy(ptr, dp->filename);
1026 fprintf(stderr, "int21: delete file %s\n", temp);
1027 /* unlink(GetUnixFileName(temp)); */
1030 DOS_closedir(dp);
1031 EAX = (EAX & 0xffffff00L);
1034 static void RenameFileFCB(struct sigcontext_struct *context)
1036 BYTE *fcb = pointer(DS, DX);
1037 int drive;
1038 struct dosdirent *dp;
1039 char temp[256], oldname[256], newname[256], *oldnameptr, *newnameptr;
1041 DumpFCB( fcb );
1043 if (*fcb)
1044 drive = *fcb - 1;
1045 else
1046 drive = DOS_GetDefaultDrive();
1048 strcpy(temp, DOS_GetCurrentDir(drive));
1049 strcat(temp, "\\");
1050 strncat(temp, fcb + 1, 8);
1051 ChopOffWhiteSpace(temp);
1052 strncat(temp, fcb + 9, 3);
1053 ChopOffWhiteSpace(temp);
1055 if ((dp = DOS_opendir(temp)) == NULL) {
1056 Error(InvalidDrive, EC_MediaError , EL_Disk);
1057 EAX = (EAX & 0xffffff00L) | 0xffL;
1058 return;
1061 strcpy(oldname, DOS_GetCurrentDir(drive) );
1062 strcat(oldname, "\\");
1063 oldnameptr = oldname + strlen(oldname);
1065 strcpy(newname, DOS_GetCurrentDir(drive) );
1066 strcat(newname, "\\");
1067 newnameptr = newname + strlen(newname);
1069 while (DOS_readdir(dp) != NULL)
1071 strcpy(oldnameptr, dp->filename);
1072 strcpy(newnameptr, fcb + 1);
1073 fprintf(stderr, "int21: renamefile %s -> %s\n", oldname, newname);
1076 DOS_closedir(dp);
1077 EAX = (EAX & 0xffffff00L);
1080 /************************************************************************/
1082 int do_int21(struct sigcontext_struct * context)
1084 int ah;
1086 if (Options.relay_debug)
1088 printf("int21: AX %04x, BX %04x, CX %04x, DX %04x, "
1089 "SI %04x, DI %04x, DS %04x, ES %04x\n",
1090 AX, BX, CX, DX, SI, DI, DS, ES);
1093 ah = (EAX >> 8) & 0xffL;
1095 if (ah == 0x59)
1097 GetExtendedErrorInfo(context);
1098 return 1;
1100 else
1102 Error (0,0,0);
1103 switch(ah)
1105 case 0x00: /* TERMINATE PROGRAM */
1106 exit(0);
1108 case 0x01: /* READ CHARACTER FROM STANDARD INPUT, WITH ECHO */
1109 case 0x02: /* WRITE CHARACTER TO STANDARD OUTPUT */
1110 case 0x03: /* READ CHARACTER FROM STDAUX */
1111 case 0x04: /* WRITE CHARACTER TO STDAUX */
1112 case 0x05: /* WRITE CHARACTER TO PRINTER */
1113 case 0x06: /* DIRECT CONSOLE IN/OUTPUT */
1114 case 0x07: /* DIRECT CHARACTER INPUT, WITHOUT ECHO */
1115 case 0x08: /* CHARACTER INPUT WITHOUT ECHO */
1116 case 0x09: /* WRITE STRING TO STANDARD OUTPUT */
1117 case 0x0a: /* BUFFERED INPUT */
1118 case 0x0b: /* GET STDIN STATUS */
1119 case 0x0c: /* FLUSH BUFFER AND READ STANDARD INPUT */
1120 case 0x0f: /* OPEN FILE USING FCB */
1121 case 0x10: /* CLOSE FILE USING FCB */
1122 case 0x12: /* FIND NEXT MATCHING FILE USING FCB */
1123 case 0x14: /* SEQUENTIAL READ FROM FCB FILE */
1124 case 0x15: /* SEQUENTIAL WRITE TO FCB FILE */
1125 case 0x16: /* CREATE OR TRUNCATE FILE USING FCB */
1126 case 0x21: /* READ RANDOM RECORD FROM FCB FILE */
1127 case 0x22: /* WRITE RANDOM RECORD TO FCB FILE */
1128 case 0x23: /* GET FILE SIZE FOR FCB */
1129 case 0x24: /* SET RANDOM RECORD NUMBER FOR FCB */
1130 case 0x26: /* CREATE NEW PROGRAM SEGMENT PREFIX */
1131 case 0x27: /* RANDOM BLOCK READ FROM FCB FILE */
1132 case 0x28: /* RANDOM BLOCK WRITE TO FCB FILE */
1133 case 0x29: /* PARSE FILENAME INTO FCB */
1134 case 0x2e: /* SET VERIFY FLAG */
1135 Barf(context);
1136 break;
1138 case 0x18: /* NULL FUNCTIONS FOR CP/M COMPATIBILITY */
1139 case 0x1d:
1140 case 0x1e:
1141 case 0x20:
1142 case 0x2b: /* SET SYSTEM DATE */
1143 case 0x2d: /* SET SYSTEM TIME */
1144 case 0x37: /* "SWITCHAR" - GET SWITCH CHARACTER
1145 "SWITCHAR" - SET SWITCH CHARACTER
1146 "AVAILDEV" - SPECIFY \DEV\ PREFIX USE */
1147 case 0x54: /* GET VERIFY FLAG */
1148 case 0x61: /* UNUSED */
1149 case 0x6b: /* NULL FUNCTION */
1150 Barf(context);
1151 EAX &= 0xff00;
1152 break;
1154 case 0x0d: /* DISK BUFFER FLUSH */
1155 ResetCflag; /* dos 6+ only */
1156 break;
1158 case 0x0e: /* SELECT DEFAULT DRIVE */
1159 SetDefaultDrive(context);
1160 break;
1162 case 0x11: /* FIND FIRST MATCHING FILE USING FCB */
1163 FindFirstFCB(context);
1164 break;
1166 case 0x13: /* DELETE FILE USING FCB */
1167 DeleteFileFCB(context);
1168 break;
1170 case 0x17: /* RENAME FILE USING FCB */
1171 RenameFileFCB(context);
1172 break;
1174 case 0x19: /* GET CURRENT DEFAULT DRIVE */
1175 GetDefaultDrive(context);
1176 break;
1178 case 0x1a: /* SET DISK TRANSFER AREA ADDRESS */
1179 dta = pointer(DS, DX);
1180 break;
1182 case 0x1b: /* GET ALLOCATION INFORMATION FOR DEFAULT DRIVE */
1183 GetDefDriveAllocInfo(context);
1184 break;
1186 case 0x1c: /* GET ALLOCATION INFORMATION FOR SPECIFIC DRIVE */
1187 GetDriveAllocInfo(context);
1188 break;
1190 case 0x1f: /* GET DRIVE PARAMETER BLOCK FOR DEFAULT DRIVE */
1191 GetDrivePB(context);
1192 break;
1194 case 0x25: /* SET INTERRUPT VECTOR */
1195 /* Ignore any attempt to set a segment vector */
1196 fprintf(stderr, "int21: set interrupt vector %2x (%04x:%04x)\n", AX & 0xff, DS, DX);
1197 break;
1199 case 0x2a: /* GET SYSTEM DATE */
1200 GetSystemDate(context);
1201 break;
1203 case 0x2c: /* GET SYSTEM TIME */
1204 GetSystemTime(context);
1205 break;
1207 case 0x2f: /* GET DISK TRANSFER AREA ADDRESS */
1208 ES = segment(dta);
1209 EBX = (EBX & 0xffff0000L) | offset(dta);
1210 break;
1212 case 0x30: /* GET DOS VERSION */
1213 EAX = (EAX & 0xffff0000L) | DOSVERSION;
1214 EBX = (EBX & 0xffff0000L) | 0x0012; /* 0x123456 is Wine's serial # */
1215 ECX = (ECX & 0xffff0000L) | 0x3456;
1216 break;
1218 case 0x31: /* TERMINATE AND STAY RESIDENT */
1219 Barf(context);
1220 break;
1222 case 0x32: /* GET DOS DRIVE PARAMETER BLOCK FOR SPECIFIC DRIVE */
1223 GetDrivePB(context);
1224 break;
1226 case 0x33: /* MULTIPLEXED */
1227 switch (EAX & 0xff) {
1228 case 0x00: /* GET CURRENT EXTENDED BREAK STATE */
1229 if (!(EAX & 0xffL))
1230 EDX &= 0xff00L;
1231 break;
1233 case 0x01: /* SET EXTENDED BREAK STATE */
1234 break;
1236 case 0x02: /* GET AND SET EXTENDED CONTROL-BREAK CHECKING STATE*/
1237 EDX &= 0xff00L;
1238 break;
1240 case 0x05: /* GET BOOT DRIVE */
1241 EDX = (EDX & 0xff00L) | 2;
1242 /* c: is Wine's bootdrive */
1243 break;
1245 case 0x06: /* GET TRUE VERSION NUMBER */
1246 EBX = DOSVERSION;
1247 EDX = 0x00;
1248 break;
1249 default:
1250 break;
1252 break;
1254 case 0x34: /* GET ADDRESS OF INDOS FLAG */
1255 GetInDosFlag(context);
1256 break;
1258 case 0x35: /* GET INTERRUPT VECTOR */
1259 /* Return a NULL segment selector - this will bomb,
1260 if anyone ever tries to use it */
1261 fprintf(stderr, "int21: get interrupt vector %2x\n", AX & 0xff);
1262 ES = 0;
1263 EBX = 0;
1264 break;
1266 case 0x36: /* GET FREE DISK SPACE */
1267 GetFreeDiskSpace(context);
1268 break;
1270 case 0x38: /* GET COUNTRY-SPECIFIC INFORMATION */
1271 EAX &= 0xff00;
1272 EAX |= 0x02; /* no country support available */
1273 SetCflag;
1274 break;
1276 case 0x39: /* "MKDIR" - CREATE SUBDIRECTORY */
1277 MakeDir(context);
1278 break;
1280 case 0x3a: /* "RMDIR" - REMOVE SUBDIRECTORY */
1281 RemoveDir(context);
1282 break;
1284 case 0x3b: /* "CHDIR" - SET CURRENT DIRECTORY */
1285 ChangeDir(context);
1286 break;
1288 case 0x3c: /* "CREAT" - CREATE OR TRUNCATE FILE */
1289 CreateFile(context);
1290 break;
1292 case 0x3d: /* "OPEN" - OPEN EXISTING FILE */
1293 OpenExistingFile(context);
1294 break;
1296 case 0x3e: /* "CLOSE" - CLOSE FILE */
1297 CloseFile(context);
1298 break;
1300 case 0x3f: /* "READ" - READ FROM FILE OR DEVICE */
1301 ReadFile(context);
1302 break;
1304 case 0x40: /* "WRITE" - WRITE TO FILE OR DEVICE */
1305 WriteFile(context);
1306 break;
1308 case 0x41: /* "UNLINK" - DELETE FILE */
1309 UnlinkFile(context);
1310 break;
1312 case 0x42: /* "LSEEK" - SET CURRENT FILE POSITION */
1313 SeekFile(context);
1314 break;
1316 case 0x43: /* FILE ATTRIBUTES */
1317 switch (EAX & 0xffL)
1319 case 0x00:
1320 GetFileAttributes(context);
1321 break;
1322 case 0x01:
1323 SetFileAttributes(context);
1324 break;
1326 break;
1328 case 0x44: /* IOCTL */
1329 switch (EAX & 0xff)
1331 case 0x00:
1332 ioctlGetDeviceInfo(context);
1333 break;
1335 case 0x0d:
1336 ioctlGenericBlkDevReq(context);
1337 break;
1339 default:
1340 Barf(context);
1341 break;
1343 break;
1346 case 0x45: /* "DUP" - DUPLICATE FILE HANDLE */
1347 case 0x46: /* "DUP2", "FORCEDUP" - FORCE DUPLICATE FILE HANDLE */
1348 DupeFileHandle(context);
1349 break;
1351 case 0x47: /* "CWD" - GET CURRENT DIRECTORY */
1352 GetCurrentDirectory(context);
1353 EAX = (EAX & 0xffff0000L) | 0x0100;
1354 /* intlist: many Microsoft products for Windows rely on this */
1355 break;
1357 case 0x48: /* ALLOCATE MEMORY */
1358 AllocateMemory(context);
1359 break;
1361 case 0x49: /* FREE MEMORY */
1362 FreeMemory(context);
1363 break;
1365 case 0x4a: /* RESIZE MEMORY BLOCK */
1366 ResizeMemoryBlock(context);
1367 break;
1369 case 0x4b: /* "EXEC" - LOAD AND/OR EXECUTE PROGRAM */
1370 ExecProgram(context);
1371 break;
1373 case 0x4c: /* "EXIT" - TERMINATE WITH RETURN CODE */
1374 exit(EAX & 0xffL);
1375 break;
1377 case 0x4d: /* GET RETURN CODE */
1378 GetReturnCode(context);
1379 break;
1381 case 0x4e: /* "FINDFIRST" - FIND FIRST MATCHING FILE */
1382 FindFirst(context);
1383 break;
1385 case 0x4f: /* "FINDNEXT" - FIND NEXT MATCHING FILE */
1386 FindNext(context);
1387 break;
1389 case 0x52: /* "SYSVARS" - GET LIST OF LISTS */
1390 GetSysVars(context);
1391 break;
1393 case 0x56: /* "RENAME" - RENAME FILE */
1394 RenameFile(context);
1395 break;
1397 case 0x57: /* FILE DATE AND TIME */
1398 switch (EAX & 0xffL)
1400 case 0x00:
1401 GetFileDateTime(context);
1402 break;
1403 case 0x01:
1404 SetFileDateTime(context);
1405 break;
1407 break;
1409 case 0x58: /* GET OR SET MEMORY/UMB ALLOCATION STRATEGY */
1410 switch (EAX & 0xffL)
1412 case 0x00:
1413 EAX = (EAX & 0xffffff00L) | 0x01L;
1414 break;
1415 case 0x02:
1416 EAX &= 0xff00L;
1417 break;
1418 case 0x01:
1419 case 0x03:
1420 break;
1422 ResetCflag;
1423 break;
1425 case 0x5a: /* CREATE TEMPORARY FILE */
1426 CreateTempFile(context);
1427 break;
1429 case 0x5b: /* CREATE NEW FILE */
1430 CreateNewFile(context);
1431 break;
1433 case 0x5c: /* "FLOCK" - RECORD LOCKING */
1434 FileLock(context);
1435 break;
1437 case 0x5d: /* NETWORK */
1438 case 0x5e:
1439 /* network software not installed */
1440 EAX = (EAX & 0xfffff00L) | NoNetwork;
1441 SetCflag;
1442 break;
1444 case 0x5f: /* NETWORK */
1445 switch (EAX & 0xffL)
1447 case 0x07: /* ENABLE DRIVE */
1448 if (!DOS_EnableDrive(EDX & 0xffL))
1450 Error(InvalidDrive, EC_MediaError , EL_Disk);
1451 EAX = (EAX & 0xfffff00L) | InvalidDrive;
1452 SetCflag;
1453 break;
1455 else
1457 ResetCflag;
1458 break;
1460 case 0x08: /* DISABLE DRIVE */
1461 if (!DOS_DisableDrive(EDX & 0xffL))
1463 Error(InvalidDrive, EC_MediaError , EL_Disk);
1464 EAX = (EAX & 0xfffff00L) | InvalidDrive;
1465 SetCflag;
1466 break;
1468 else
1470 ResetCflag;
1471 break;
1473 default:
1474 /* network software not installed */
1475 EAX = (EAX & 0xfffff00L) | NoNetwork;
1476 SetCflag;
1477 break;
1479 break;
1481 case 0x60: /* "TRUENAME" - CANONICALIZE FILENAME OR PATH */
1482 GetTrueFileName(context);
1483 break;
1485 case 0x62: /* GET CURRENT PSP ADDRESS */
1486 GetCurrentPSP(context);
1487 break;
1489 case 0x65: /* GET EXTENDED COUNTRY INFORMATION */
1490 GetExtendedCountryInfo(context);
1491 break;
1493 case 0x66: /* GLOBAL CODE PAGE TABLE */
1494 switch (EAX & 0xffL)
1496 case 0x01:
1497 EBX = CodePage;
1498 EDX = BX;
1499 ResetCflag;
1500 break;
1501 case 0x02:
1502 CodePage = BX;
1503 ResetCflag;
1504 break;
1506 break;
1508 case 0x68: /* "FFLUSH" - COMMIT FILE */
1509 ResetCflag;
1510 break;
1512 case 0x69: /* DISK SERIAL NUMBER */
1513 switch (EAX & 0xffL)
1515 case 0x00:
1516 GetDiskSerialNumber(context);
1517 break;
1518 case 0x01:
1519 SetDiskSerialNumber(context);
1520 break;
1522 break;
1524 case 0x6a: /* COMMIT FILE */
1525 ResetCflag;
1526 break;
1528 case 0x67: /* SET HANDLE COUNT */
1529 ResetCflag;
1530 break;
1532 default:
1533 Barf(context);
1534 return 1;
1537 return 1;
1540 /**********************************************************************
1541 * DOS3Call
1543 void DOS3Call()
1545 do_int21((struct sigcontext_struct *) _CONTEXT);
1546 ReturnFromRegisterFunc();