|
|
1.1 root 1: /*
2: Hatari
3:
4: GEMDos intercept routines. These are used mainly for Hard Drive redirection of high level
5: file routines.
6: */
7:
8: #include <sys/types.h>
9: #include <sys/stat.h>
10: #include <fcntl.h>
11:
12: #include "main.h"
13: #include "cart.h"
14: #include "debug.h"
15: #include "decode.h"
16: #include "dialog.h"
17: #include "file.h"
18: #include "floppy.h"
19: #include "gemdos.h"
20: #include "m68000.h"
21: #include "memAlloc.h"
22: #include "memorySnapShot.h"
23: #include "misc.h"
24: #include "printer.h"
25: #include "rs232.h"
26: #include "statusBar.h"
27: #include "stMemory.h"
28: #include "view.h"
29:
30: #define ENABLE_SAVING /* Turn on saving stuff */
31:
32: #define INVALID_HANDLE_VALUE -1
33:
34: #ifndef MAX_PATH
35: #define MAX_PATH 256
36: #endif
37:
38: typedef struct
39: {
40: BOOL bUsed;
41: int FileHandle;
42: } FILE_HANDLE;
43:
44: FILE_HANDLE FileHandles[MAX_FILE_HANDLES];
45: //INTERNAL_DTA InternalDTAs[MAX_DTAS_FILES];
46: int DTAIndex; /* Circular index into above */
47: BOOL bInitGemDOS; /* Have we re-directed GemDOS vector to our own routines yet? */
48: DTA *pDTA; /* Our GEMDOS hard drive Disc Transfer Address structure */
49: unsigned short int CurrentDrive; /* Current drive (0=A,1=B,2=C etc...) */
50:
51: #ifdef DEBUG_TO_FILE
52: /* List of GEMDos functions... */
53: char *pszGemDOSNames[] = {
54: "Term", //0x00
55: "Conin", //0x01
56: "ConOut", //0x02
57: "Auxiliary Input", //0x03
58: "Auxiliary Output", //0x04
59: "Printer Output", //0x05
60: "RawConIO", //0x06
61: "Direct Conin no echo", //0x07
62: "Conin no echo", //0x08
63: "Print line", //0x09
64: "ReadLine", //0x0a
65: "ConStat", //0x0b
66: "", //0x0c
67: "", //0x0d
68: "SetDrv", //0x0e
69: "", //0x0f
70: "Conout Stat", //0x10
71: "PrtOut Stat", //0x11
72: "Auxin Stat", //0x12
73: "AuxOut Stat", //0x13
74: "", //0x14
75: "", //0x15
76: "", //0x16
77: "", //0x17
78: "", //0x18
79: "Current Disk", //0x19
80: "Set DTA", //0x1a
81: "", //0x1b
82: "", //0x1c
83: "", //0x1d
84: "", //0x1e
85: "", //0x1f
86: "Super", //0x20
87: "", //0x21
88: "", //0x22
89: "", //0x23
90: "", //0x24
91: "", //0x25
92: "", //0x26
93: "", //0x27
94: "", //0x28
95: "", //0x29
96: "Get Date", //0x2a
97: "Set Date", //0x2b
98: "Get Time", //0x2c
99: "Set Time", //0x2d
100: "", //0x2e
101: "Get DTA", //0x2f
102: "Get Version Number", //0x30
103: "Keep Process", //0x31
104: "", //0x32
105: "", //0x33
106: "", //0x34
107: "", //0x35
108: "Get Disk Free Space", //0x36
109: "", //0x37
110: "", //0x38
111: "MkDir", //0x39
112: "RmDir", //0x3a
113: "ChDir", //0x3b
114: "Create", //0x3c
115: "Open", //0x3d
116: "Close", //0x3e
117: "Read", //0x3f
118: "Write", //0x40
119: "UnLink", //0x41
120: "LSeek", //0x42
121: "ChMod", //0x43
122: "", //0x44
123: "Dup", //0x45
124: "Force", //0x46
125: "GetDir", //0x47
126: "Malloc", //0x48
127: "MFree", //0x49
128: "SetBlock", //0x4a
129: "Exec", //0x4b
130: "Term", //0x4c
131: "", //0x4d
132: "SFirst", //0x4e
133: "SNext", //0x4f
134: "", //0x50
135: "", //0x51
136: "", //0x52
137: "", //0x53
138: "", //0x54
139: "", //0x55
140: "Rename", //0x56
141: "GSDTof" //0x57
142: };
143: #endif
144:
145:
146:
147: /* Convert a string to uppercase */
148: void strupr(char *string)
149: {
150: int i;
151: for(i=0; i<strlen(string); i++)
152: string[i] = toupper(string[i]);
153: }
154:
155:
156: //-----------------------------------------------------------------------
157: /*
158: Initialize GemDOS/PC file system
159: */
160: void GemDOS_Init(void)
161: {
162: // Clear handles structure
163: Memory_Clear(FileHandles,sizeof(FILE_HANDLE)*MAX_FILE_HANDLES);
164: }
165:
166: //-----------------------------------------------------------------------
167: /*
168: Reset GemDOS file system
169: */
170: void GemDOS_Reset(void)
171: {
172: int i;
173:
174: // Init file handles table
175: for(i=0; i<MAX_FILE_HANDLES; i++) {
176: // Was file open? If so close it
177: if (FileHandles[i].bUsed)
178: close(FileHandles[i].FileHandle);
179:
180: FileHandles[i].FileHandle = INVALID_HANDLE_VALUE;
181: FileHandles[i].bUsed = FALSE;
182: }
183:
184: // Reset
185: bInitGemDOS = FALSE;
186: CurrentDrive = nBootDrive;
187: pDTA = NULL;
188: DTAIndex = 0;
189: }
190:
191: //-----------------------------------------------------------------------
192: /*
193: Save/Restore snapshot of local variables('MemorySnapShot_Store' handles type)
194: */
195: void GemDOS_MemorySnapShot_Capture(BOOL bSave)
196: {
197: unsigned int Addr;
198: int i;
199:
200: // Save/Restore details
201: MemorySnapShot_Store(&DTAIndex,sizeof(DTAIndex));
202: MemorySnapShot_Store(&bInitGemDOS,sizeof(bInitGemDOS));
203: if (bSave) {
204: Addr = (unsigned int)pDTA-(unsigned int)STRam;
205: MemorySnapShot_Store(&Addr,sizeof(Addr));
206: }
207: else {
208: MemorySnapShot_Store(&Addr,sizeof(Addr));
209: pDTA = (DTA *)((unsigned int)STRam+(unsigned int)Addr);
210: }
211: MemorySnapShot_Store(&CurrentDrive,sizeof(CurrentDrive));
212: // Don't save file handles as files may have changed which makes
213: // it impossible to get a valid handle back
214: if (!bSave) {
215: // Clear file handles
216: for(i=0; i<MAX_FILE_HANDLES; i++) {
217: FileHandles[i].FileHandle = INVALID_HANDLE_VALUE;
218: FileHandles[i].bUsed = FALSE;
219: }
220: // And DTAs
221: /*FIXME*/
222: /* for(i=0; i<MAX_DTAS_FILES; i++) {
223: InternalDTAs[i].FileHandle = INVALID_HANDLE_VALUE;
224: memset(&InternalDTAs[i].FindFileData,0x0,sizeof(WIN32_FIND_DATA));
225: }
226: */
227: }
228: }
229:
230: //-----------------------------------------------------------------------
231: /*
232: Return free PC file handle table index, or -1 if error
233: */
234: int GemDOS_FindFreeFileHandle(void)
235: {
236: int i;
237:
238: /* Scan our file list for free slot */
239: for(i=0; i<MAX_FILE_HANDLES; i++) {
240: if (!FileHandles[i].bUsed)
241: return(i);
242: }
243:
244: /* Cannot open any more files, return error */
245: return(-1);
246: }
247:
248: //-----------------------------------------------------------------------
249: /*
250: Check ST handle is within our table range, return TRUE if not
251: */
252: BOOL GemDOS_IsInvalidFileHandle(int Handle)
253: {
254: BOOL bInvalidHandle=FALSE;
255:
256: /* Check handle was valid with our handle table */
257: if ( (Handle<0) || (Handle>=MAX_FILE_HANDLES) )
258: bInvalidHandle = TRUE;
259: else if (!FileHandles[Handle].bUsed)
260: bInvalidHandle = TRUE;
261:
262: return(bInvalidHandle);
263: }
264:
265: //-----------------------------------------------------------------------
266: /*
267: Find drive letter from a filename, eg C,D... and return as drive ID(C:2, D:3...)
268: */
269: int GemDOS_FindDriveNumber(char *pszFileName)
270: {
271: /* Does have 'A:' or 'C:' etc.. at start of string? */
272: if ( (pszFileName[0]!='\0') && (pszFileName[1]==':') ) {
273: if ( (pszFileName[0]>='a') && (pszFileName[0]<='z') )
274: return(pszFileName[0]-'a');
275: else if ( (pszFileName[0]>='A') && (pszFileName[0]<='Z') )
276: return(pszFileName[0]-'A');
277: }
278:
279: return(CurrentDrive);
280: }
281:
282: //-----------------------------------------------------------------------
283: /*
284: Return drive ID(C:2, D:3 etc...) or -1 if not one of our emulation hard-drives
285: */
286: int GemDOS_IsFileNameAHardDrive(char *pszFileName)
287: {
288: int DriveLetter;
289:
290: /* Do we even have a hard-drive? */
291: if (ConfigureParams.HardDisc.nDriveList!=DRIVELIST_NONE) {
292: // Find drive letter(as number)
293: DriveLetter = GemDOS_FindDriveNumber(pszFileName);
294: // Does match one of our drives?
295: if ( (DriveLetter>=2) && (DriveLetter<=DRIVELIST_TO_DRIVE_INDEX(ConfigureParams.HardDisc.nDriveList)) )
296: return(DriveLetter);
297: }
298:
299: // No, let TOS handle it
300: return(-1);
301: }
302:
303: //-----------------------------------------------------------------------
304: /*
305: Use hard-drive directory, current ST directory and filename to create full path
306: */
307: void GemDOS_CreateHardDriveFileName(int Drive,char *pszFileName,char *pszDestName)
308: {
309: int DirIndex = Misc_LimitInt(Drive-2, 0,ConfigureParams.HardDisc.nDriveList-1);
310: // debug << "::" << pszFileName << endl;
311: /* Combine names */
312: if (File_IsRootFileName(pszFileName))
313: sprintf(pszDestName,"%s%s",ConfigureParams.HardDisc.szHardDiscDirectories[DirIndex],File_RemoveFileNameDrive(pszFileName));
314: else {
315: if (File_DoesFileNameEndWithSlash(szCurrentDir))
316: sprintf(pszDestName,"%s%s%s",ConfigureParams.HardDisc.szHardDiscDirectories[DirIndex],File_RemoveFileNameDrive(szCurrentDir),File_RemoveFileNameDrive(pszFileName));
317: else
318: sprintf(pszDestName,"%s%s/%s",ConfigureParams.HardDisc.szHardDiscDirectories[DirIndex],File_RemoveFileNameDrive(szCurrentDir),File_RemoveFileNameDrive(pszFileName));
319: }
320: // Remove any '/'s at end of filenames
321: File_RemoveFileNameTrailingSlashes(pszDestName);
322:
323: // And make all upper case, as original ST
324: strupr(pszDestName);
325: // debug << "\t" << pszDestName << endl;
326: }
327:
328: //-----------------------------------------------------------------------
329: /*
330: Covert from FindFirstFile/FindNextFile attribute to GemDOS format
331: */
332: char GemDOS_ConvertAttribute(int dwFileAttributes)
333: {
334: char Attrib=0;
335: /* FIXME */
336: /*
337: // Look up attributes
338: if (dwFileAttributes&FILE_ATTRIBUTE_READONLY)
339: Attrib |= GEMDOS_FILE_ATTRIB_READONLY;
340: if (dwFileAttributes&FILE_ATTRIBUTE_HIDDEN)
341: Attrib |= GEMDOS_FILE_ATTRIB_HIDDEN;
342: if (dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY)
343: Attrib |= GEMDOS_FILE_ATTRIB_SUBDIRECTORY;
344: */
345: return(Attrib);
346: }
347:
348: //-----------------------------------------------------------------------
349: /*
350: GEMDOS Cauxin
351: Call 0x3
352: */
353: BOOL GemDOS_Cauxin(unsigned long Params)
354: {
355: unsigned char Char;
356:
357: // Wait here until a character is ready
358: while(!RS232_GetStatus());
359:
360: // And read character
361: RS232_ReadBytes(&Char,1);
362: Regs[REG_D0] = Char;
363:
364: return(TRUE);
365: }
366:
367: //-----------------------------------------------------------------------
368: /*
369: GEMDOS Cauxout
370: Call 0x4
371: */
372: BOOL GemDOS_Cauxout(unsigned long Params)
373: {
374: unsigned char Char;
375:
376: // Send character to RS232
377: Char = STMemory_ReadWord(Params+SIZE_WORD);
378: RS232_TransferBytesTo(&Char,1);
379:
380: return(TRUE);
381: }
382:
383: //-----------------------------------------------------------------------
384: /*
385: GEMDOS Cprnout
386: Call 0x5
387: */
388: BOOL GemDOS_Cprnout(unsigned long Params)
389: {
390: unsigned char Char;
391:
392: // Send character to printer(or file)
393: Char = STMemory_ReadWord(Params+SIZE_WORD);
394: Printer_TransferByteTo(Char);
395: Regs[REG_D0] = -1; // Printer OK
396:
397: return(TRUE);
398: }
399:
400: //-----------------------------------------------------------------------
401: /*
402: GEMDOS Set drive (0=A,1=B,2=C etc...)
403: Call 0xE
404: */
405: BOOL GemDOS_SetDrv(unsigned long Params)
406: {
407: // Read details from stack for our own use
408: CurrentDrive = STMemory_ReadWord(Params+SIZE_WORD);
409: // debug << "CurrentDrive: " << CurrentDrive << endl;
410:
411: // Still re-direct to TOS
412: return(FALSE);
413: }
414:
415: //-----------------------------------------------------------------------
416: /*
417: GEMDOS Cprnos
418: Call 0x11
419: */
420: BOOL GemDOS_Cprnos(unsigned long Params)
421: {
422: Regs[REG_D0] = -1; // Printer OK
423:
424: return(TRUE);
425: }
426:
427: //-----------------------------------------------------------------------
428: /*
429: GEMDOS Cauxis
430: Call 0x12
431: */
432: BOOL GemDOS_Cauxis(unsigned long Params)
433: {
434: // Read our RS232 state
435: if (RS232_GetStatus())
436: Regs[REG_D0] = -1; // Chars waiting
437: else
438: Regs[REG_D0] = 0;
439:
440: return(TRUE);
441: }
442:
443: //-----------------------------------------------------------------------
444: /*
445: GEMDOS Cauxos
446: Call 0x13
447: */
448: BOOL GemDOS_Cauxos(unsigned long Params)
449: {
450: Regs[REG_D0] = -1; // Device ready
451:
452: return(TRUE);
453: }
454:
455: //-----------------------------------------------------------------------
456: /*
457: GEMDOS Set Disc Transfer Address (DTA)
458: Call 0x1A
459: */
460: BOOL GemDOS_SetDTA(unsigned long Params)
461: {
462: // Look up on stack to find where DTA is! Store as PC pointer
463: pDTA = (DTA *)STRAM_ADDR(STMemory_ReadLong(Params+SIZE_WORD));
464:
465: // char szString[256];
466: // sprintf(szString,"0x%X",STMemory_ReadLong(Params+SIZE_WORD));
467: // debug << " to " << szString << endl;
468:
469: // Still re-direct to TOS
470: return(FALSE);
471: }
472:
473: //-----------------------------------------------------------------------
474: /*
475: GEMDOS MkDir
476: Call 0x39
477: */
478: BOOL GemDOS_MkDir(unsigned long Params)
479: {
480: char szDirPath[MAX_PATH];
481: char *pDirName;
482: int Drive;
483:
484: // Find directory to make
485: pDirName = (char *)STRAM_ADDR(STMemory_ReadLong(Params+SIZE_WORD));
486: // debug << pDirName << endl;
487: Drive = GemDOS_IsFileNameAHardDrive(pDirName);
488: // debug << Drive << endl;
489: if (ISHARDDRIVE(Drive)) {
490: // Copy old directory, as if calls fails keep this one
491: GemDOS_CreateHardDriveFileName(Drive,pDirName,szDirPath);
492:
493: // Attempt to make directory
494: if ( mkdir(szDirPath, 0755)==0 )
495: Regs[REG_D0] = GEMDOS_EOK;
496: else
497: Regs[REG_D0] = GEMDOS_EACCDN; // Access denied
498:
499: return(TRUE);
500: }
501: return(FALSE);
502: }
503:
504: //-----------------------------------------------------------------------
505: /*
506: GEMDOS RmDir
507: Call 0x3A
508: */
509: BOOL GemDOS_RmDir(unsigned long Params)
510: {
511: char szDirPath[MAX_PATH];
512: char *pDirName;
513: int Drive;
514:
515: // Find directory to make
516: pDirName = (char *)STRAM_ADDR(STMemory_ReadLong(Params+SIZE_WORD));
517: Drive = GemDOS_IsFileNameAHardDrive(pDirName);
518: if (ISHARDDRIVE(Drive)) {
519: // Copy old directory, as if calls fails keep this one
520: GemDOS_CreateHardDriveFileName(Drive,pDirName,szDirPath);
521:
522: // Attempt to make directory
523: if ( rmdir(szDirPath)==0 )
524: Regs[REG_D0] = GEMDOS_EOK;
525: else
526: Regs[REG_D0] = GEMDOS_EACCDN; // Access denied
527:
528: return(TRUE);
529: }
530: return(FALSE);
531: }
532:
533: //-----------------------------------------------------------------------
534: /*
535: GEMDOS ChDir
536: Call 0x3B
537: */
538: BOOL GemDOS_ChDir(unsigned long Params)
539: {
540: char szDirPath[MAX_PATH];
541: char *pDirName;
542: int Drive;
543:
544: // Find new directory
545: pDirName = (char *)STRAM_ADDR(STMemory_ReadLong(Params+SIZE_WORD));
546: // debug << pDirName << endl;
547: Drive = GemDOS_IsFileNameAHardDrive(pDirName);
548: if (ISHARDDRIVE(Drive)) {
549: // Check path exists, else error
550: GemDOS_CreateHardDriveFileName(Drive,"",szDirPath);
551:
552: if ( chdir(szDirPath)==0 ) {
553: strcpy(szCurrentDir,pDirName);
554: Regs[REG_D0] = GEMDOS_EOK;
555: }
556: else
557: Regs[REG_D0] = GEMDOS_EPTHNF; // Path not found
558:
559: return(TRUE);
560: }
561:
562: return(FALSE);
563: }
564:
565: //-----------------------------------------------------------------------
566: /*
567: GEMDOS Create file
568: Call 0x3C
569: */
570: BOOL GemDOS_Create(unsigned long Params)
571: {
572: char szActualFileName[MAX_PATH];
573: char *pszFileName;
574: unsigned int Access;
575: int Drive,Index,Mode;
576:
577: // Find filename
578: pszFileName = (char *)STRAM_ADDR(STMemory_ReadLong(Params+SIZE_WORD));
579: Mode = STMemory_ReadWord(Params+SIZE_WORD+SIZE_LONG);
580: Drive = GemDOS_IsFileNameAHardDrive(pszFileName);
581: if (ISHARDDRIVE(Drive)) {
582: // And convert to hard drive filename
583: GemDOS_CreateHardDriveFileName(Drive,pszFileName,szActualFileName);
584:
585: // Find slot to store file handle, as need to return WORD handle for ST (NOTE PC's Window handles are all LONGS)
586: Index = GemDOS_FindFreeFileHandle();
587: if (Index==-1) {
588: // No free handles, return error code
589: Regs[REG_D0] = GEMDOS_ENHNDL; // No more handles
590: return(TRUE);
591: }
592: else {
593: #ifdef ENABLE_SAVING
594: // Select mode
595: switch(Mode&0x01) { // Top bits used in some TOSes
596: case 0: // Read/Write
597: //FIXME Access = GENERIC_READ|GENERIC_WRITE;
598: break;
599: case 1: // Write only
600: //FIXME Access = GENERIC_WRITE;
601: break;
602: }
603:
604: //FIXME FileHandles[Index].FileHandle = CreateFile(szActualFileName,Access,0,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
605: if (FileHandles[Index].FileHandle!=INVALID_HANDLE_VALUE) {
606: /* Tag handle table entry as used and return handle */
607: FileHandles[Index].bUsed = TRUE;
608: Regs[REG_D0] = Index+BASE_FILEHANDLE; // Return valid ST file handle from range 6 to 45! (ours start from 0)
609:
610: return(TRUE);
611: }
612: else {
613: Regs[REG_D0] = GEMDOS_EFILNF; // File not found
614: return(TRUE);
615: }
616: #else
617: Regs[REG_D0] = GEMDOS_EFILNF; // File not found
618: return(TRUE);
619: #endif
620: }
621: }
622:
623: return(FALSE);
624: }
625:
626: //-----------------------------------------------------------------------
627: /*
628: GEMDOS Open file
629: Call 0x3D
630: */
631: BOOL GemDOS_Open(unsigned long Params)
632: {
633: char szActualFileName[MAX_PATH];
634: char *pszFileName;
635: unsigned int Access;
636: int Drive,Index,Mode;
637:
638: // Find filename
639: pszFileName = (char *)STRAM_ADDR(STMemory_ReadLong(Params+SIZE_WORD));
640: Mode = STMemory_ReadWord(Params+SIZE_WORD+SIZE_LONG);
641: Drive = GemDOS_IsFileNameAHardDrive(pszFileName);
642: // Debug_File("Open %s\n",pszFileName);
643: if (ISHARDDRIVE(Drive)) {
644: // And convert to hard drive filename
645: GemDOS_CreateHardDriveFileName(Drive,pszFileName,szActualFileName);
646:
647: // Find slot to store file handle, as need to return WORD handle for ST (NOTE PC's Window handles are all LONGS)
648: Index = GemDOS_FindFreeFileHandle();
649: if (Index==-1) {
650: // No free handles, return error code
651: Regs[REG_D0] = GEMDOS_ENHNDL; // No more handles
652: return(TRUE);
653: }
654: else {
655: // Select mode
656: switch(Mode&0x03) { // Top bits used in some TOSes
657: case 0: // Read only
658: //FIXME Access = GENERIC_READ;
659: break;
660: case 1: // Write only
661: //FIXME Access = GENERIC_WRITE;
662: break;
663: case 2: // Read/Write
664: //FIXME Access = GENERIC_READ|GENERIC_WRITE;
665: break;
666: }
667:
668: // Open file
669: //FIXME FileHandles[Index].FileHandle = CreateFile(szActualFileName,Access,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
670: if (FileHandles[Index].FileHandle!=INVALID_HANDLE_VALUE) {
671: // Tag handle table entry as used and return handle
672: FileHandles[Index].bUsed = TRUE;
673: Regs[REG_D0] = Index+BASE_FILEHANDLE; // Return valid ST file handle from range 6 to 45! (ours start from 0)
674:
675: return(TRUE);
676: }
677: else {
678: Regs[REG_D0] = GEMDOS_EFILNF; // File not found
679: return(TRUE);
680: }
681: }
682: }
683:
684: return(FALSE);
685: }
686:
687: //-----------------------------------------------------------------------
688: /*
689: GEMDOS Close file
690: Call 0x3E
691: */
692: BOOL GemDOS_Close(unsigned long Params)
693: {
694: int Handle;
695:
696: // Find our handle - may belong to TOS
697: Handle = STMemory_ReadWord(Params+SIZE_WORD)-BASE_FILEHANDLE;
698:
699: // Check handle was valid
700: if (GemDOS_IsInvalidFileHandle(Handle)) {
701: // No assume was TOS
702: return(FALSE);
703: }
704: else {
705: // Close file and free up handle table
706: close(FileHandles[Handle].FileHandle);
707: FileHandles[Handle].bUsed = FALSE;
708: // Return no error
709: Regs[REG_D0] = GEMDOS_EOK;
710: return(TRUE);
711: }
712: }
713:
714: //-----------------------------------------------------------------------
715: /*
716: GEMDOS Read file
717: Call 0x3F
718: */
719: BOOL GemDOS_Read(unsigned long Params)
720: {
721: char *pBuffer;
722: unsigned long nBytesRead,Size,CurrentPos,FileSize,nBytesLeft;
723: int Handle;
724:
725: // Read details from stack
726: Handle = STMemory_ReadWord(Params+SIZE_WORD)-BASE_FILEHANDLE;
727: Size = STMemory_ReadLong(Params+SIZE_WORD+SIZE_WORD);
728: pBuffer = (char *)STRAM_ADDR(STMemory_ReadLong(Params+SIZE_WORD+SIZE_WORD+SIZE_LONG));
729:
730: // Check handle was valid
731: if (GemDOS_IsInvalidFileHandle(Handle)) {
732: // No assume was TOS
733: return(FALSE);
734: }
735: else {
736: StatusBar_SetIcon(STATUS_ICON_HARDDRIVE,ICONSTATE_UPDATE);
737:
738: // To quick check to see where our file pointer is and how large the file is
739: CurrentPos = lseek(FileHandles[Handle].FileHandle, 0, SEEK_CUR);
740: FileSize = lseek(FileHandles[Handle].FileHandle, 0, SEEK_END);
741: lseek(FileHandles[Handle].FileHandle, CurrentPos, SEEK_SET);
742:
743: nBytesLeft = FileSize-CurrentPos;
744:
745: // Check for End Of File
746: if (nBytesLeft<0) {
747: Regs[REG_D0] = GEMDOS_ERROR;
748:
749: return(TRUE);
750: }
751: else {
752: // Limit to size of file to prevent windows error
753: if (Size>FileSize)
754: Size = FileSize;
755: // And read data in
756: nBytesRead = read(FileHandles[Handle].FileHandle, pBuffer, Size);
757: //??? FlushFileBuffers(FileHandles[Handle].FileHandle);
758:
759: // Return number of bytes read
760: Regs[REG_D0] = nBytesRead;
761:
762: return(TRUE);
763: }
764: }
765: }
766:
767: //-----------------------------------------------------------------------
768: /*
769: GEMDOS Write file
770: Call 0x40
771: */
772: BOOL GemDOS_Write(unsigned long Params)
773: {
774: char *pBuffer;
775: unsigned long Size,nBytesWritten;
776: int Handle;
777:
778: #ifdef ENABLE_SAVING
779: // Read details from stack
780: Handle = STMemory_ReadWord(Params+SIZE_WORD)-BASE_FILEHANDLE;
781: Size = STMemory_ReadLong(Params+SIZE_WORD+SIZE_WORD);
782: pBuffer = (char *)STRAM_ADDR(STMemory_ReadLong(Params+SIZE_WORD+SIZE_WORD+SIZE_LONG));
783:
784: // Check handle was valid
785: if (GemDOS_IsInvalidFileHandle(Handle)) {
786: // No assume was TOS
787: return(FALSE);
788: }
789: else {
790: StatusBar_SetIcon(STATUS_ICON_HARDDRIVE,ICONSTATE_UPDATE);
791:
792: nBytesWritten = write(FileHandles[Handle].FileHandle, pBuffer, Size);
793: if (nBytesWritten>=0) {
794: //??? FlushFileBuffers(FileHandles[Handle].FileHandle);
795:
796: Regs[REG_D0] = nBytesWritten; // OK
797: }
798: else
799: Regs[REG_D0] = GEMDOS_EACCDN; // Access denied(ie read-only)
800:
801: return(TRUE);
802: }
803: #endif
804:
805: return(FALSE);
806: }
807:
808: //-----------------------------------------------------------------------
809: /*
810: GEMDOS UnLink(Delete) file
811: Call 0x41
812: */
813: BOOL GemDOS_UnLink(unsigned long Params)
814: {
815: #ifdef ENABLE_SAVING
816: char szActualFileName[MAX_PATH];
817: char *pszFileName;
818: int Drive;
819:
820: // Find filename
821: pszFileName = (char *)STRAM_ADDR(STMemory_ReadLong(Params+SIZE_WORD));
822: Drive = GemDOS_IsFileNameAHardDrive(pszFileName);
823: if (ISHARDDRIVE(Drive)) {
824: // And convert to hard drive filename
825: GemDOS_CreateHardDriveFileName(Drive,pszFileName,szActualFileName);
826:
827: // Now delete file??
828: if ( unlink(szActualFileName)==0 )
829: Regs[REG_D0] = GEMDOS_EOK; // OK
830: else
831: Regs[REG_D0] = GEMDOS_EFILNF; // File not found
832:
833: return(TRUE);
834: }
835: #endif
836:
837: return(FALSE);
838: }
839:
840: //-----------------------------------------------------------------------
841: /*
842: GEMDOS File seek
843: Call 0x42
844: */
845: BOOL GemDOS_LSeek(unsigned long Params)
846: {
847: long Offset;
848: int Handle,Mode;
849:
850: // Read details from stack
851: Offset = (long)STMemory_ReadLong(Params+SIZE_WORD);
852: Handle = STMemory_ReadWord(Params+SIZE_WORD+SIZE_LONG)-BASE_FILEHANDLE;
853: Mode = STMemory_ReadWord(Params+SIZE_WORD+SIZE_LONG+SIZE_WORD);
854:
855: // Check handle was valid
856: if (GemDOS_IsInvalidFileHandle(Handle)) {
857: // No assume was TOS
858: return(FALSE);
859: }
860: else {
861: // Return offset from start of file
862: Regs[REG_D0] = lseek(FileHandles[Handle].FileHandle, Offset, Mode);
863: return(TRUE);
864: }
865: }
866:
867: //-----------------------------------------------------------------------
868: /*
869: PExec Load And Go - Redirect to cart' routine at address 0xFA1000
870:
871: If loading from hard-drive(ie drive ID 2 or more) set condition codes to run own GEMDos routines
872: */
873: void GemDOS_Pexec_LoadAndGo(unsigned long Params)
874: {
875: // Hard-drive?
876: if (CurrentDrive>=2) // If not using A: or B:, use my own routines to load
877: SR = (SR&0xff00) | SR_OVERFLOW;
878: }
879:
880: //-----------------------------------------------------------------------
881: /*
882: PExec Load But Don't Go - Redirect to cart' routine at address 0xFA1000
883: */
884: void GemDOS_Pexec_LoadDontGo(unsigned long Params)
885: {
886: // Hard-drive?
887: if (CurrentDrive>=2)
888: SR = (SR&0xff00) | SR_OVERFLOW;
889: }
890:
891: //-----------------------------------------------------------------------
892: /*
893: GEMDOS PExec handler
894: Call 0x4B
895: */
896: BOOL GemDOS_Pexec(unsigned long Params)
897: {
898: unsigned short int Mode;
899:
900: // Find PExec mode
901: Mode = STMemory_ReadWord(Params+SIZE_WORD);
902: // Debug_File("Pexec %d (Drv:%d)\n",Mode,CurrentDrive);
903:
904: // Re-direct as needed
905: switch(Mode) {
906: case 0: // Load and go
907: GemDOS_Pexec_LoadAndGo(Params);
908: return(FALSE);
909: case 3: // Load, don't go
910: GemDOS_Pexec_LoadDontGo(Params);
911: return(FALSE);
912: case 4: // Just go
913: return(FALSE);
914: case 5: // Create basepage
915: return(FALSE);
916: case 6:
917: return(FALSE);
918:
919: default:
920: return(FALSE);
921: }
922:
923: // Still re-direct to TOS
924: return(FALSE);
925: }
926:
927: //-----------------------------------------------------------------------
928: /*
929: GEMDOS Find first file
930: Call 0x4E
931: */
932: BOOL GemDOS_SFirst(unsigned long Params)
933: {
934: int FatDate, FatTime;
935: char szActualFileName[MAX_PATH];
936: char *pszFileName;
937: unsigned short int Attr;
938: int Drive;
939:
940: // Find filename to search for
941: pszFileName = (char *)STRAM_ADDR(STMemory_ReadLong(Params+SIZE_WORD));
942: Attr = STMemory_ReadWord(Params+SIZE_WORD+SIZE_LONG);
943: // debug << "SFirst: " << pszFileName << endl;
944: // M68000_OutputHistory();
945:
946: Drive = GemDOS_IsFileNameAHardDrive(pszFileName);
947: if (ISHARDDRIVE(Drive)) {
948: StatusBar_SetIcon(STATUS_ICON_HARDDRIVE,ICONSTATE_UPDATE);
949:
950: // And convert to hard drive filename
951: GemDOS_CreateHardDriveFileName(Drive,pszFileName,szActualFileName);
952:
953: // Populate DTA, set index for our use
954: STMemory_WriteWord_PCSpace(pDTA->index,DTAIndex);
955: STMemory_WriteLong_PCSpace(pDTA->magic,DTA_MAGIC_NUMBER);
956: strcpy(pDTA->dta_pat,"");
957: pDTA->dta_sattrib = 0;
958: pDTA->dta_attrib = 0;
959:
960: // Were we looking for the volume label? Read directly from drive
961: if (Attr&GEMDOS_FILE_ATTRIB_VOLUME_LABEL) {
962: // Default and find drive from filename
963: strcpy(pDTA->dta_name,"");
964: File_GetFileNameDrive(pszFileName);
965: //FIXME if (GetVolumeInformation(pszFileName,pDTA->dta_name,TOS_NAMELEN,NULL,NULL,NULL,NULL,0))
966: // strupr(pDTA->dta_name);
967: Regs[REG_D0] = GEMDOS_EOK; // Got volume
968: return(TRUE);
969: }
970:
971: // Scan for first file
972: /* FIXME */
973: /*
974: InternalDTAs[DTAIndex].FileHandle = FindFirstFile(szActualFileName,&InternalDTAs[DTAIndex].FindFileData);
975: if (InternalDTAs[DTAIndex].FileHandle==INVALID_HANDLE_VALUE) {
976: // No files of that match, return error code
977: Regs[REG_D0] = GEMDOS_EFILNF; // File not found
978: return(TRUE);
979: }
980: else {
981: // Repeat find until have useable filename! The PC returns '.' and '..' - ignore '.'!
982: while( !stricmp(InternalDTAs[DTAIndex].FindFileData.cFileName,".") ) {
983: if (FindNextFile(InternalDTAs[DTAIndex].FileHandle,&InternalDTAs[DTAIndex].FindFileData)==0) {
984: // If this is all there is, then error
985: Regs[REG_D0] = GEMDOS_ENMFIL; // No more files
986: return(TRUE);
987: }
988: }
989:
990: // And make all upper case, as original ST
991: strupr(InternalDTAs[DTAIndex].FindFileData.cFileName);
992: strcpy(pDTA->dta_name,InternalDTAs[DTAIndex].FindFileData.cFileName);
993:
994: // Fill remaining details, as PC
995: //FIXME STMemory_WriteLong_PCSpace(pDTA->dta_size,InternalDTAs[DTAIndex].FindFileData.nFileSizeLow);
996: //FIXME Misc_TimeDataToDos(&InternalDTAs[DTAIndex].FindFileData.ftLastWriteTime,&FatDate,&FatTime);
997: STMemory_WriteWord_PCSpace(pDTA->dta_time,FatTime);
998: STMemory_WriteWord_PCSpace(pDTA->dta_date,FatDate);
999: //FIXME pDTA->dta_attrib = GemDOS_ConvertAttribute(InternalDTAs[DTAIndex].FindFileData.dwFileAttributes);
1000:
1001: Regs[REG_D0] = GEMDOS_EOK;
1002:
1003: DTAIndex++;
1004: DTAIndex&=(MAX_DTAS_FILES-1);
1005: }
1006: return(TRUE);
1007: */
1008: }
1009: return(FALSE);
1010: }
1011:
1012: //-----------------------------------------------------------------------
1013: /*
1014: GEMDOS Search Next
1015: Call 0x4F
1016: */
1017: BOOL GemDOS_SNext(unsigned long Params)
1018: {
1019: int FatDate, FatTime;
1020: int DTAIndex;
1021:
1022: // Was DTA ours or TOS?
1023: if (STMemory_ReadLong_PCSpace(pDTA->magic)==DTA_MAGIC_NUMBER) {
1024: StatusBar_SetIcon(STATUS_ICON_HARDDRIVE,ICONSTATE_UPDATE);
1025:
1026: // Find index into our list of structures
1027: DTAIndex = STMemory_ReadWord_PCSpace(pDTA->index)&(MAX_DTAS_FILES-1);
1028: /*FIXME
1029: if (FindNextFile(InternalDTAs[DTAIndex].FileHandle,&InternalDTAs[DTAIndex].FindFileData)==0) {
1030: Regs[REG_D0] = GEMDOS_ENMFIL; // No more files
1031: return(TRUE);
1032: }
1033: // Find next file on hard drive
1034: else {
1035: // And make all upper case, as original ST
1036: strupr(InternalDTAs[DTAIndex].FindFileData.cFileName);
1037: strcpy(pDTA->dta_name,InternalDTAs[DTAIndex].FindFileData.cFileName);
1038: // Fill remaining details, as PC
1039: STMemory_WriteLong_PCSpace(pDTA->dta_size,InternalDTAs[DTAIndex].FindFileData.nFileSizeLow);
1040: Misc_TimeDataToDos(&InternalDTAs[DTAIndex].FindFileData.ftLastWriteTime,&FatDate,&FatTime);
1041: STMemory_WriteWord_PCSpace(pDTA->dta_time,FatTime);
1042: STMemory_WriteWord_PCSpace(pDTA->dta_date,FatDate);
1043: pDTA->dta_attrib = GemDOS_ConvertAttribute(InternalDTAs[DTAIndex].FindFileData.dwFileAttributes);
1044:
1045: Regs[REG_D0] = GEMDOS_EOK;
1046: return(TRUE);
1047: }
1048: */
1049: }
1050:
1051: return(FALSE);
1052: }
1053:
1054: //-----------------------------------------------------------------------
1055: /*
1056: GEMDOS Rename
1057: Call 0x56
1058: */
1059: BOOL GemDOS_Rename(unsigned long Params)
1060: {
1061: char *pszNewFileName,*pszOldFileName;
1062: char szNewActualFileName[MAX_PATH],szOldActualFileName[MAX_PATH];
1063: int NewDrive, OldDrive;
1064:
1065: // Read details from stack
1066: pszOldFileName = (char *)STRAM_ADDR(STMemory_ReadLong(Params+SIZE_WORD+SIZE_WORD));
1067: pszNewFileName = (char *)STRAM_ADDR(STMemory_ReadLong(Params+SIZE_WORD+SIZE_WORD+SIZE_LONG));
1068:
1069: NewDrive = GemDOS_IsFileNameAHardDrive(pszNewFileName);
1070: OldDrive = GemDOS_IsFileNameAHardDrive(pszOldFileName);
1071: if (ISHARDDRIVE(NewDrive) && ISHARDDRIVE(OldDrive)) {
1072: // And convert to hard drive filenames
1073: GemDOS_CreateHardDriveFileName(NewDrive,pszNewFileName,szNewActualFileName);
1074: GemDOS_CreateHardDriveFileName(OldDrive,pszOldFileName,szOldActualFileName);
1075:
1076: // Rename files
1077: if ( rename(szOldActualFileName,szNewActualFileName)==0 )
1078: Regs[REG_D0] = GEMDOS_EOK;
1079: else
1080: Regs[REG_D0] = GEMDOS_EACCDN; // Access denied
1081: return(TRUE);
1082: }
1083:
1084: return(FALSE);
1085: }
1086:
1087: //-----------------------------------------------------------------------
1088: /*
1089: GEMDOS GSDToF
1090: Call 0x57
1091: */
1092: BOOL GemDOS_GSDToF(unsigned long Params)
1093: {
1094: /*FIXME*/
1095: /*
1096: BY_HANDLE_FILE_INFORMATION FileInfo;
1097: WORD FatDate,FatTime;
1098: DATETIME DateTime;
1099: char *pBuffer;
1100: int Handle,Flag;
1101:
1102: // Read details from stack
1103: pBuffer = (char *)STRAM_ADDR(STMemory_ReadLong(Params+SIZE_WORD));
1104: Handle = STMemory_ReadWord(Params+SIZE_WORD+SIZE_LONG)-BASE_FILEHANDLE;
1105: Flag = STMemory_ReadWord(Params+SIZE_WORD+SIZE_WORD+SIZE_LONG);
1106:
1107: // Check handle was valid
1108: if (GemDOS_IsInvalidFileHandle(Handle)) {
1109: // No assume was TOS
1110: return(FALSE);
1111: }
1112: else {
1113: Regs[REG_D0] = GEMDOS_ERROR; // Invalid parameter
1114:
1115: if (Flag==0) { // Read time
1116: if (GetFileInformationByHandle(FileHandles[Handle].FileHandle,&FileInfo)) {
1117: if (FileTimeToDosDateTime(&FileInfo.ftCreationTime,&FatDate,&FatTime)) {
1118: DateTime.hour = FatTime>>11;
1119: DateTime.minute = FatTime>>5;
1120: DateTime.second = FatTime;
1121: DateTime.year = FatDate>>9;
1122: DateTime.month = FatDate>>5;
1123: DateTime.day = FatDate;
1124:
1125: Regs[REG_D0] = GEMDOS_EOK;
1126: }
1127: }
1128: }
1129: else if (Flag==1) {
1130: Regs[REG_D0] = GEMDOS_EOK;
1131: }
1132:
1133: return(TRUE);
1134: }
1135: */
1136: return(FALSE);
1137: }
1138:
1139: //-----------------------------------------------------------------------
1140: /*
1141: This is called when we get a GemDOS exception. We then re-direct vector to our
1142: own routine. This forces execution through TOS which sets up the stack etc... and
1143: then calls our own routine in the cart' space which has the illegal instruction
1144: 'GEMDOS_OPCODE'.
1145: */
1146: BOOL GemDOS(void)
1147: {
1148: unsigned long OldGemDOSVector;
1149:
1150: // Init Gemdos if not already
1151: if (!bInitGemDOS) {
1152: OldGemDOSVector = STMemory_ReadLong(0x84);
1153: STMemory_WriteLong(CART_OLDGEMDOS,OldGemDOSVector); // Store original gemdos handler
1154: STMemory_WriteLong(0x84,CART_GEMDOS); // And redirect to new one (see cart.s)
1155:
1156: bInitGemDOS = TRUE;
1157: }
1158:
1159: // Now execute as normal, we may intercept it again later (see cart.s)
1160: return(FALSE);
1161: }
1162:
1163:
1164: /*-----------------------------------------------------------------------*/
1165: /*
1166: Run GEMDos call, and re-direct if need to. Used to handle hard-disc emulation etc...
1167: This sets the condition codes(in SR), which are used in the 'cart.s' program to decide if we
1168: need to run old GEM vector, or PExec or nothing.
1169:
1170: This method keeps the stack and other states consistant with the original ST which is very important
1171: for the PExec call and maximum compatibility through-out
1172: */
1173: void GemDOS_OpCode(void)
1174: {
1175: unsigned short int GemDOSCall,CallingSReg;
1176: unsigned long Params;
1177:
1178: /* Read SReg from stack to see if parameters are on User or Super stack (We enter here ALWAYS in super mode) */
1179: CallingSReg = STMemory_ReadWord(Regs[REG_A7]);
1180: if ((CallingSReg&SR_SUPERMODE)==0) /* Calling from user mode */
1181: Params = Regs[REG_A8];
1182: else /* Calling from super mode */
1183: Params = Regs[REG_A7]+SIZE_WORD+SIZE_LONG;
1184:
1185: /* Default to run TOS GemDos (SR_NEG run Gemdos, SR_ZERO already done, SR_OVERFLOW run own 'Pexec' */
1186: SR &= SR_CLEAR_OVERFLOW;
1187: SR &= SR_CLEAR_ZERO;
1188: SR |= SR_NEG;
1189:
1190: /* Find pointer to call parameters */
1191: GemDOSCall = STMemory_ReadWord(Params);
1192: #ifdef DEBUG_TO_FILE
1193: Debug_File("GemDOS 0x%X (%s)\n",GemDOSCall,pszGemDOSNames[GemDOSCall]);
1194: #endif
1195:
1196: /* Intercept call */
1197: switch(GemDOSCall) {
1198: case 0x3:
1199: if (GemDOS_Cauxin(Params))
1200: SR |= SR_ZERO;
1201: break;
1202: case 0x4:
1203: if (GemDOS_Cauxout(Params))
1204: SR |= SR_ZERO;
1205: break;
1206: case 0x5:
1207: if (GemDOS_Cprnout(Params))
1208: SR |= SR_ZERO;
1209: break;
1210: case 0xe:
1211: if (GemDOS_SetDrv(Params))
1212: SR |= SR_ZERO;
1213: break;
1214: case 0x11:
1215: if (GemDOS_Cprnos(Params))
1216: SR |= SR_ZERO;
1217: break;
1218: case 0x12:
1219: if (GemDOS_Cauxis(Params))
1220: SR |= SR_ZERO;
1221: break;
1222: case 0x13:
1223: if (GemDOS_Cauxos(Params))
1224: SR |= SR_ZERO;
1225: break;
1226: case 0x1a:
1227: if (GemDOS_SetDTA(Params))
1228: SR |= SR_ZERO;
1229: break;
1230: case 0x39:
1231: if (GemDOS_MkDir(Params))
1232: SR |= SR_ZERO;
1233: break;
1234: case 0x3a:
1235: if (GemDOS_RmDir(Params))
1236: SR |= SR_ZERO;
1237: break;
1238: case 0x3b:
1239: if (GemDOS_ChDir(Params))
1240: SR |= SR_ZERO;
1241: break;
1242: case 0x3c:
1243: if (GemDOS_Create(Params))
1244: SR |= SR_ZERO;
1245: break;
1246: case 0x3d:
1247: if (GemDOS_Open(Params))
1248: SR |= SR_ZERO;
1249: break;
1250: case 0x3e:
1251: if (GemDOS_Close(Params))
1252: SR |= SR_ZERO;
1253: break;
1254: case 0x3f:
1255: if (GemDOS_Read(Params))
1256: SR |= SR_ZERO;
1257: break;
1258: case 0x40:
1259: if (GemDOS_Write(Params))
1260: SR |= SR_ZERO;
1261: break;
1262: case 0x41:
1263: if (GemDOS_UnLink(Params))
1264: SR |= SR_ZERO;
1265: break;
1266: case 0x42:
1267: if (GemDOS_LSeek(Params))
1268: SR |= SR_ZERO;
1269: break;
1270: case 0x4b:
1271: if (GemDOS_Pexec(Params))
1272: SR |= SR_ZERO;
1273: break;
1274: case 0x4e:
1275: if (GemDOS_SFirst(Params))
1276: SR |= SR_ZERO;
1277: break;
1278: case 0x4f:
1279: if (GemDOS_SNext(Params))
1280: SR |= SR_ZERO;
1281: break;
1282: case 0x56:
1283: if (GemDOS_Rename(Params))
1284: SR |= SR_ZERO;
1285: break;
1286: case 0x57:
1287: if (GemDOS_GSDToF(Params))
1288: SR |= SR_ZERO;
1289: break;
1290: }
1291:
1292: /* Write back to emulation condition codes, used for code re-direction */
1293: EmuCCode = SR<<4;
1294: }
1295:
1296:
1297: //-----------------------------------------------------------------------
1298: /*
1299: Re-direct execution to old GEM calls, used in 'cart.s'
1300: */
1301: void GemDOS_RunOldOpCode(void)
1302: {
1303: /* Set 'PC' to that of old GemDOS routines (see 'old_gemdos' in cart.s) */
1304: m68k_setpc( STMemory_ReadLong(0xfa1004) ); /* Address of 'old_gemdos' in cart.s */
1305: /* __asm {
1306: mov ecx,[STRAM_OFFSET+0xfa1004] // Address of 'old_gemdos' in cart.s
1307: bswap ecx
1308: and ecx,0x00ffffff
1309: mov esi,ecx
1310: add esi,STRAM_OFFSET // New PC
1311: RET
1312: }
1313: */
1314: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.