|
|
1.1 root 1: /* 1.1.1.5 ! root 2: Hatari - gemdos.c 1.1 root 3: 1.1.1.5 ! root 4: This file is distributed under the GNU Public License, version 2 or at ! 5: your option any later version. Read the file gpl.txt for details. ! 6: ! 7: GEMDOS intercept routines. ! 8: These are used mainly for hard drive redirection of high level file routines. 1.1 root 9: 1.1.1.2 root 10: Bugs/things to fix: 11: * RS232/Printing 12: * Figure out how to handle long file names and case conflicts, 13: (eg. FOO.BAR and foo.bar is the same file in TOS but not UNIX) 14: * rmdir routine, can't remove dir with files in it. (another tos/unix difference) 15: * Fix bugs, there are probably a few lurking around in here.. 16: */ 1.1.1.5 ! root 17: static char rcsid[] = "Hatari $Id: gemdos.c,v 1.11 2003/02/28 15:31:35 thothy Exp $"; 1.1 root 18: 1.1.1.4 root 19: #include <sys/stat.h> 20: #include <time.h> 21: #include <dirent.h> 22: #include <ctype.h> 23: #include <unistd.h> 24: 1.1 root 25: #include "main.h" 26: #include "cart.h" 1.1.1.2 root 27: #include "tos.h" 1.1 root 28: #include "debug.h" 29: #include "decode.h" 30: #include "dialog.h" 31: #include "file.h" 32: #include "floppy.h" 1.1.1.3 root 33: #include "hdc.h" 1.1 root 34: #include "gemdos.h" 35: #include "m68000.h" 36: #include "memAlloc.h" 37: #include "memorySnapShot.h" 38: #include "misc.h" 39: #include "printer.h" 40: #include "rs232.h" 41: #include "stMemory.h" 42: 1.1.1.2 root 43: #include "uae-cpu/hatari-glue.h" 44: 45: 1.1.1.3 root 46: /* #define GEMDOS_VERBOSE */ 1.1 root 47: #define ENABLE_SAVING /* Turn on saving stuff */ 48: 49: #define INVALID_HANDLE_VALUE -1 50: 51: #ifndef MAX_PATH 52: #define MAX_PATH 256 53: #endif 54: 1.1.1.3 root 55: 1.1.1.2 root 56: /* structure with all the drive-specific data for our emulated drives */ 57: EMULATEDDRIVE **emudrives = NULL; 58: 1.1 root 59: typedef struct 60: { 1.1.1.3 root 61: BOOL bUsed; 62: FILE *FileHandle; 1.1.1.2 root 63: char szActualName[MAX_PATH]; /* used by F_DATIME (0x57) */ 1.1 root 64: } FILE_HANDLE; 65: 1.1.1.2 root 66: typedef struct 67: { 68: BOOL bUsed; 69: int nentries; /* number of entries in fs directory */ 70: int centry; /* current entry # */ 71: struct dirent **found; /* legal files */ 72: char path[MAX_PATH]; /* sfirst path */ 73: } INTERNAL_DTA; 74: 1.1 root 75: FILE_HANDLE FileHandles[MAX_FILE_HANDLES]; 1.1.1.2 root 76: INTERNAL_DTA InternalDTAs[MAX_DTAS_FILES]; 1.1 root 77: int DTAIndex; /* Circular index into above */ 78: BOOL bInitGemDOS; /* Have we re-directed GemDOS vector to our own routines yet? */ 79: DTA *pDTA; /* Our GEMDOS hard drive Disc Transfer Address structure */ 80: unsigned short int CurrentDrive; /* Current drive (0=A,1=B,2=C etc...) */ 81: 82: /* List of GEMDos functions... */ 83: char *pszGemDOSNames[] = { 1.1.1.2 root 84: "Term", /*0x00*/ 85: "Conin", /*0x01*/ 86: "ConOut", /*0x02*/ 87: "Auxiliary Input", /*0x03*/ 88: "Auxiliary Output", /*0x04*/ 89: "Printer Output", /*0x05*/ 90: "RawConIO", /*0x06*/ 91: "Direct Conin no echo", /*0x07*/ 92: "Conin no echo", /*0x08*/ 93: "Print line", /*0x09*/ 94: "ReadLine", /*0x0a*/ 95: "ConStat", /*0x0b*/ 96: "", /*0x0c*/ 97: "", /*0x0d*/ 98: "SetDrv", /*0x0e*/ 99: "", /*0x0f*/ 100: "Conout Stat", /*0x10*/ 101: "PrtOut Stat", /*0x11*/ 102: "Auxin Stat", /*0x12*/ 103: "AuxOut Stat", /*0x13*/ 104: "", /*0x14*/ 105: "", /*0x15*/ 106: "", /*0x16*/ 107: "", /*0x17*/ 108: "", /*0x18*/ 109: "Current Disk", /*0x19*/ 110: "Set DTA", /*0x1a*/ 1.1.1.3 root 111: "", /*0x1b*/ 112: "", /*0x1c*/ 113: "", /*0x1d*/ 114: "", /*0x1e*/ 115: "", /*0x1f*/ 116: "Super", /*0x20*/ 117: "", /*0x21*/ 118: "", /*0x22*/ 119: "", /*0x23*/ 120: "", /*0x24*/ 121: "", /*0x25*/ 122: "", /*0x26*/ 123: "", /*0x27*/ 124: "", /*0x28*/ 125: "", /*0x29*/ 126: "Get Date", /*0x2a*/ 127: "Set Date", /*0x2b*/ 128: "Get Time", /*0x2c*/ 129: "Set Time", /*0x2d*/ 130: "", /*0x2e*/ 131: "Get DTA", /*0x2f*/ 1.1.1.2 root 132: "Get Version Number", /*0x30*/ 133: "Keep Process", /*0x31*/ 1.1.1.3 root 134: "", /*0x32*/ 135: "", /*0x33*/ 136: "", /*0x34*/ 137: "", /*0x35*/ 1.1.1.2 root 138: "Get Disk Free Space", /*0x36*/ 139: "", /*0x37*/ 140: "", /*0x38*/ 141: "MkDir", /*0x39*/ 142: "RmDir", /*0x3a*/ 143: "ChDir", /*0x3b*/ 144: "Create", /*0x3c*/ 145: "Open", /*0x3d*/ 146: "Close", /*0x3e*/ 147: "Read", /*0x3f*/ 148: "Write", /*0x40*/ 149: "UnLink", /*0x41*/ 150: "LSeek", /*0x42*/ 151: "ChMod", /*0x43*/ 152: "", /*0x44*/ 153: "Dup", /*0x45*/ 154: "Force", /*0x46*/ 155: "GetDir", /*0x47*/ 156: "Malloc", /*0x48*/ 157: "MFree", /*0x49*/ 158: "SetBlock", /*0x4a*/ 159: "Exec", /*0x4b*/ 160: "Term", /*0x4c*/ 161: "", /*0x4d*/ 162: "SFirst", /*0x4e*/ 163: "SNext", /*0x4f*/ 164: "", /*0x50*/ 165: "", /*0x51*/ 166: "", /*0x52*/ 167: "", /*0x53*/ 168: "", /*0x54*/ 169: "", /*0x55*/ 170: "Rename", /*0x56*/ 171: "GSDTof" /*0x57*/ 1.1 root 172: }; 173: 1.1.1.2 root 174: unsigned char GemDOS_ConvertAttribute(mode_t mode); 175: 1.1.1.3 root 176: 177: 178: 1.1.1.2 root 179: /*-------------------------------------------------------*/ 180: /* 181: Routines to convert time and date to MSDOS format. 182: Originally from the STonX emulator. (cheers!) 183: */ 184: unsigned short time2dos (time_t t) 185: { 186: struct tm *x; 187: x = localtime (&t); 188: return (x->tm_sec>>1)|(x->tm_min<<5)|(x->tm_hour<<11); 189: } 1.1 root 190: 1.1.1.2 root 191: unsigned short date2dos (time_t t) 192: { 193: struct tm *x; 194: x = localtime (&t); 195: return x->tm_mday | ((x->tm_mon+1)<<5) | ( ((x->tm_year-80>0)?x->tm_year-80:0) << 9); 196: } 1.1 root 197: 1.1.1.3 root 198: 1.1.1.2 root 199: /* 200: Convert a string to uppercase 201: */ 1.1 root 202: void strupr(char *string) 203: { 1.1.1.4 root 204: while(*string) 205: { 206: *string = toupper(*string); 207: string++; 208: } 1.1.1.2 root 209: } 210: 1.1.1.3 root 211: 1.1.1.2 root 212: /*-----------------------------------------------------------------------*/ 213: /* 214: Populate a DATETIME structure with file info 215: */ 216: BOOL GetFileInformation(char *name, DATETIME *DateTime) 217: { 218: struct stat filestat; 219: int n; 220: struct tm *x; 221: 222: n = stat(name, &filestat); 223: if( n != 0 ) return(FALSE); 224: x = localtime( &filestat.st_mtime ); 225: 226: DateTime->word1 = 0; 227: DateTime->word2 = 0; 228: 229: DateTime->word1 |= (x->tm_mday & 0x1F); /* 5 bits */ 230: DateTime->word1 |= (x->tm_mon & 0x0F)<<5; /* 4 bits */ 231: DateTime->word1 |= (((x->tm_year-80>0)?x->tm_year-80:0) & 0x7F)<<9; /* 7 bits*/ 232: 233: DateTime->word2 |= (x->tm_sec & 0x1F); /* 5 bits */ 234: DateTime->word2 |= (x->tm_min & 0x3F)<<5; /* 6 bits */ 235: DateTime->word2 |= (x->tm_hour & 0x1F)<<11; /* 5 bits */ 236: 237: return(TRUE); 238: } 1.1.1.3 root 239: 240: 1.1.1.2 root 241: /*-----------------------------------------------------------------------*/ 242: /* 243: Populate the DTA buffer with file info 244: */ 245: int PopulateDTA(char *path, struct dirent *file) 246: { 247: char tempstr[MAX_PATH]; 248: struct stat filestat; 249: int n; 250: 251: sprintf(tempstr, "%s/%s", path, file->d_name); 252: n = stat(tempstr, &filestat); 253: if(n != 0) return(FALSE); /* return on error */ 254: 255: if(!pDTA) return(FALSE); /* no DTA pointer set */ 256: strupr(file->d_name); /* convert to atari-style uppercase */ 257: strncpy(pDTA->dta_name,file->d_name,TOS_NAMELEN); /* FIXME: better handling of long file names */ 258: STMemory_WriteLong_PCSpace(pDTA->dta_size, (long)filestat.st_size); 259: STMemory_WriteWord_PCSpace(pDTA->dta_time, time2dos(filestat.st_mtime)); 260: STMemory_WriteWord_PCSpace(pDTA->dta_date, date2dos(filestat.st_mtime)); 261: pDTA->dta_attrib = GemDOS_ConvertAttribute(filestat.st_mode); 262: 1.1.1.4 root 263: return(TRUE); 1.1.1.2 root 264: } 265: 1.1.1.3 root 266: 1.1.1.2 root 267: /*-----------------------------------------------------------------------*/ 268: /* 269: Clear a used DTA structure. 270: */ 271: void ClearInternalDTA(){ 272: int i; 273: 274: /* clear the old DTA structure */ 275: if(InternalDTAs[DTAIndex].found != NULL){ 276: for(i=0; i <InternalDTAs[DTAIndex].nentries; i++) 277: free(InternalDTAs[DTAIndex].found[i]); 278: free(InternalDTAs[DTAIndex].found); 279: } 280: InternalDTAs[DTAIndex].bUsed = FALSE; 281: } 282: 1.1.1.3 root 283: 1.1.1.2 root 284: /*-----------------------------------------------------------------------*/ 285: /* 286: Match a file to a dir mask. 287: */ 288: static int match (char *pat, char *name) 289: { 290: /* make uppercase copies */ 291: char p0[MAX_PATH], n0[MAX_PATH]; 292: strcpy(p0, pat); 293: strcpy(n0, name); 294: strupr(p0); strupr(n0); 295: 296: if(name[0] == '.') return(FALSE); /* no .* files */ 297: if (strcmp(pat,"*.*")==0) return(TRUE); 298: else if (strcasecmp(pat,name)==0) return(TRUE); 299: else 300: { 301: char *p=p0,*n=n0; 302: for(;*n;) 303: { 304: if (*p=='*') {while (*n && *n != '.') n++;p++;} 305: else if (*p=='?' && *n) {n++;p++;} 306: else if (*p++ != *n++) return(FALSE); 307: } 308: if (*p==0) 309: { 310: return(TRUE); 311: } 312: } 313: return(FALSE); 314: } 315: 316: /*-----------------------------------------------------------------------*/ 317: /* 1.1.1.4 root 318: Parse directory from sfirst mask 319: - e.g.: input: "hdemudir/auto/mask*.*" outputs: "hdemudir/auto" 1.1.1.2 root 320: */ 321: void fsfirst_dirname(char *string, char *new){ 322: int i=0; 323: 324: sprintf(new, string); 325: /* convert to front slashes. */ 326: i=0; 327: while(new[i] != '\0'){ 328: if(new[i] == '\\') new[i] = '/'; 329: i++; 330: } 331: while(string[i] != '\0'){new[i] = string[i]; i++;} /* find end of string */ 332: while(new[i] != '/') i--; /* find last slash */ 333: new[i] = '\0'; 1.1.1.3 root 334: 1.1 root 335: } 336: 1.1.1.2 root 337: /*-----------------------------------------------------------------------*/ 338: /* 339: Parse directory mask, e.g. "*.*" 340: */ 341: void fsfirst_dirmask(char *string, char *new){ 342: int i=0, j=0; 343: while(string[i] != '\0')i++; /* go to end of string */ 344: while(string[i] != '/') i--; /* find last slash */ 345: i++; 346: while(string[i] != '\0')new[j++] = string[i++]; /* go to end of string */ 347: new[j++] = '\0'; 348: } 1.1 root 349: 1.1.1.2 root 350: /*-----------------------------------------------------------------------*/ 1.1 root 351: /* 352: Initialize GemDOS/PC file system 353: */ 354: void GemDOS_Init(void) 355: { 1.1.1.2 root 356: int i; 357: bInitGemDOS = FALSE; 358: 359: /* Clear handles structure */ 1.1.1.3 root 360: Memory_Clear(FileHandles, sizeof(FILE_HANDLE)*MAX_FILE_HANDLES); 1.1.1.2 root 361: /* Clear DTAs */ 1.1.1.3 root 362: for(i=0; i<MAX_DTAS_FILES; i++) 363: { 1.1.1.2 root 364: InternalDTAs[i].bUsed = FALSE; 365: InternalDTAs[i].nentries = 0; 366: InternalDTAs[i].found = NULL; 367: } 368: DTAIndex = 0; 1.1 root 369: } 370: 1.1.1.2 root 371: /*-----------------------------------------------------------------------*/ 1.1 root 372: /* 373: Reset GemDOS file system 374: */ 1.1.1.3 root 375: void GemDOS_Reset() 1.1 root 376: { 377: int i; 378: 1.1.1.2 root 379: /* Init file handles table */ 1.1.1.3 root 380: for(i=0; i<MAX_FILE_HANDLES; i++) 381: { 1.1.1.2 root 382: /* Was file open? If so close it */ 1.1 root 383: if (FileHandles[i].bUsed) 1.1.1.2 root 384: fclose(FileHandles[i].FileHandle); 1.1 root 385: 1.1.1.2 root 386: FileHandles[i].FileHandle = NULL; 1.1 root 387: FileHandles[i].bUsed = FALSE; 388: } 389: 1.1.1.3 root 390: for(i=0; i<MAX_DTAS_FILES; i++) 391: { 1.1.1.2 root 392: InternalDTAs[i].bUsed = FALSE; 393: InternalDTAs[i].nentries = 0; 394: InternalDTAs[i].found = NULL; 395: } 396: 397: /* Reset */ 1.1 root 398: bInitGemDOS = FALSE; 399: CurrentDrive = nBootDrive; 400: pDTA = NULL; 401: DTAIndex = 0; 402: } 403: 1.1.1.3 root 404: 405: /*-----------------------------------------------------------------------*/ 406: /* 407: Initialize a GEMDOS drive. 408: Only 1 emulated drive allowed, as of yet. 409: */ 410: void GemDOS_InitDrives() 411: { 412: int i; 413: 414: /* intialize data for harddrive emulation: */ 415: if(!GEMDOS_EMU_ON) 416: { 417: emudrives = malloc( MAX_HARDDRIVES*sizeof(EMULATEDDRIVE *) ); 418: for(i=0; i<MAX_HARDDRIVES; i++) 419: emudrives[0] = malloc( sizeof(EMULATEDDRIVE) ); 420: } 421: 422: for(i=0; i<MAX_HARDDRIVES; i++) 423: { 424: /* set emulation directory string */ 425: strcpy(emudrives[i]->hd_emulation_dir, ConfigureParams.HardDisc.szHardDiscDirectories[i]); 426: 427: /* remove trailing slash, if any in the directory name */ 428: File_CleanFileName(emudrives[i]->hd_emulation_dir); 429: 430: /* set drive to 2 + number of ACSI partitions */ 431: emudrives[i]->hd_letter = 2 + nPartitions + i; 432: 433: ConfigureParams.HardDisc.nDriveList += 1; 434: 435: fprintf(stderr, "Hard drive emulation, %c: <-> %s\n", 436: emudrives[i]->hd_letter + 'A', emudrives[i]->hd_emulation_dir); 437: } 438: } 439: 440: /*-----------------------------------------------------------------------*/ 441: /* 442: Un-init the GEMDOS drive 443: */ 444: void GemDOS_UnInitDrives() 445: { 446: int i; 447: 448: GemDOS_Reset(); /* Close all open files on emulated drive*/ 449: 450: if(GEMDOS_EMU_ON) 451: { 452: for(i=0; i<MAX_HARDDRIVES; i++) 453: { 454: free(emudrives[i]); /* Release memory */ 455: ConfigureParams.HardDisc.nDriveList -= 1; 456: } 457: 458: free(emudrives); 459: emudrives = NULL; 460: } 461: } 462: 463: 1.1.1.2 root 464: /*-----------------------------------------------------------------------*/ 1.1 root 465: /* 466: Save/Restore snapshot of local variables('MemorySnapShot_Store' handles type) 467: */ 468: void GemDOS_MemorySnapShot_Capture(BOOL bSave) 469: { 470: unsigned int Addr; 471: int i; 472: 1.1.1.2 root 473: /* Save/Restore details */ 1.1 root 474: MemorySnapShot_Store(&DTAIndex,sizeof(DTAIndex)); 475: MemorySnapShot_Store(&bInitGemDOS,sizeof(bInitGemDOS)); 476: if (bSave) { 477: Addr = (unsigned int)pDTA-(unsigned int)STRam; 478: MemorySnapShot_Store(&Addr,sizeof(Addr)); 479: } 480: else { 481: MemorySnapShot_Store(&Addr,sizeof(Addr)); 482: pDTA = (DTA *)((unsigned int)STRam+(unsigned int)Addr); 483: } 484: MemorySnapShot_Store(&CurrentDrive,sizeof(CurrentDrive)); 1.1.1.2 root 485: /* Don't save file handles as files may have changed which makes 486: it impossible to get a valid handle back */ 1.1 root 487: if (!bSave) { 1.1.1.2 root 488: /* Clear file handles */ 1.1 root 489: for(i=0; i<MAX_FILE_HANDLES; i++) { 1.1.1.2 root 490: FileHandles[i].FileHandle = NULL; 1.1 root 491: FileHandles[i].bUsed = FALSE; 492: } 493: } 494: } 495: 1.1.1.2 root 496: /*-----------------------------------------------------------------------*/ 1.1 root 497: /* 498: Return free PC file handle table index, or -1 if error 499: */ 500: int GemDOS_FindFreeFileHandle(void) 501: { 502: int i; 503: 504: /* Scan our file list for free slot */ 505: for(i=0; i<MAX_FILE_HANDLES; i++) { 506: if (!FileHandles[i].bUsed) 507: return(i); 508: } 509: 510: /* Cannot open any more files, return error */ 511: return(-1); 512: } 513: 1.1.1.2 root 514: /*-----------------------------------------------------------------------*/ 1.1 root 515: /* 516: Check ST handle is within our table range, return TRUE if not 517: */ 518: BOOL GemDOS_IsInvalidFileHandle(int Handle) 519: { 520: BOOL bInvalidHandle=FALSE; 521: 522: /* Check handle was valid with our handle table */ 523: if ( (Handle<0) || (Handle>=MAX_FILE_HANDLES) ) 524: bInvalidHandle = TRUE; 525: else if (!FileHandles[Handle].bUsed) 526: bInvalidHandle = TRUE; 527: 528: return(bInvalidHandle); 529: } 530: 1.1.1.2 root 531: /*-----------------------------------------------------------------------*/ 1.1 root 532: /* 533: Find drive letter from a filename, eg C,D... and return as drive ID(C:2, D:3...) 1.1.1.3 root 534: returns the current drive number if none is specified. 1.1 root 535: */ 536: int GemDOS_FindDriveNumber(char *pszFileName) 537: { 538: /* Does have 'A:' or 'C:' etc.. at start of string? */ 539: if ( (pszFileName[0]!='\0') && (pszFileName[1]==':') ) { 540: if ( (pszFileName[0]>='a') && (pszFileName[0]<='z') ) 541: return(pszFileName[0]-'a'); 542: else if ( (pszFileName[0]>='A') && (pszFileName[0]<='Z') ) 543: return(pszFileName[0]-'A'); 544: } 545: 546: return(CurrentDrive); 547: } 548: 1.1.1.2 root 549: /*-----------------------------------------------------------------------*/ 1.1 root 550: /* 551: Return drive ID(C:2, D:3 etc...) or -1 if not one of our emulation hard-drives 552: */ 553: int GemDOS_IsFileNameAHardDrive(char *pszFileName) 554: { 555: int DriveLetter; 556: 1.1.1.3 root 557: /* Do we even have a hard-drive? */ 558: if(GEMDOS_EMU_ON) 559: { 560: DriveLetter = GemDOS_FindDriveNumber(pszFileName); 561: /* add support for multiple drives here.. */ 562: if( DriveLetter == emudrives[0]->hd_letter ) 563: return(DriveLetter); 564: } 565: /* Not a high-level redirected drive */ 566: return(-1); 567: 568: /* this code is depreciated */ 1.1 root 569: /* Do we even have a hard-drive? */ 570: if (ConfigureParams.HardDisc.nDriveList!=DRIVELIST_NONE) { 1.1.1.2 root 571: /* Find drive letter(as number) */ 1.1 root 572: DriveLetter = GemDOS_FindDriveNumber(pszFileName); 1.1.1.2 root 573: /* Does match one of our drives? */ 1.1 root 574: if ( (DriveLetter>=2) && (DriveLetter<=DRIVELIST_TO_DRIVE_INDEX(ConfigureParams.HardDisc.nDriveList)) ) 575: return(DriveLetter); 576: } 577: 1.1.1.2 root 578: /* No, let TOS handle it */ 1.1 root 579: return(-1); 580: } 581: 1.1.1.2 root 582: /*-----------------------------------------------------------------------*/ 1.1 root 583: /* 584: Use hard-drive directory, current ST directory and filename to create full path 585: */ 586: void GemDOS_CreateHardDriveFileName(int Drive,char *pszFileName,char *pszDestName) 587: { 1.1.1.3 root 588: /* int DirIndex = Misc_LimitInt(Drive-2, 0,ConfigureParams.HardDisc.nDriveList-1); */ 1.1.1.2 root 589: int i; 590: 1.1.1.3 root 591: if(pszFileName[0] == '\0') return; /* check for valid string */ 592: 1.1.1.2 root 593: /* case full filename "C:\foo\bar" */ 594: if(pszFileName[1] == ':') { 595: sprintf(pszDestName, "%s%s", emudrives[0]->hd_emulation_dir, File_RemoveFileNameDrive(pszFileName)); 1.1.1.3 root 596: } 597: /* case referenced from root: "\foo\bar" */ 1.1.1.2 root 598: else if(pszFileName[0] == '\\'){ 599: sprintf(pszDestName, "%s%s", emudrives[0]->hd_emulation_dir, pszFileName); 600: } 1.1.1.3 root 601: /* case referenced from current directory */ 1.1.1.2 root 602: else { 603: sprintf(pszDestName, "%s%s%s", emudrives[0]->hd_emulation_dir, emudrives[0]->fs_currpath, pszFileName); 604: } 605: 606: /* convert to front slashes. */ 607: i=0; 608: while(pszDestName[i] != '\0'){ 609: if(pszDestName[i] == '\\') pszDestName[i] = '/'; 610: i++; 611: } 1.1 root 612: 613: } 614: 1.1.1.2 root 615: /*-----------------------------------------------------------------------*/ 1.1 root 616: /* 617: Covert from FindFirstFile/FindNextFile attribute to GemDOS format 618: */ 1.1.1.2 root 619: unsigned char GemDOS_ConvertAttribute(mode_t mode) 1.1 root 620: { 1.1.1.2 root 621: unsigned char Attrib=0; 622: 623: /* FIXME: More attributes */ 624: if(S_ISDIR(mode)) Attrib |= GEMDOS_FILE_ATTRIB_SUBDIRECTORY; 625: 1.1 root 626: /* FIXME */ 627: /* 628: // Look up attributes 629: if (dwFileAttributes&FILE_ATTRIBUTE_READONLY) 630: Attrib |= GEMDOS_FILE_ATTRIB_READONLY; 631: if (dwFileAttributes&FILE_ATTRIBUTE_HIDDEN) 632: Attrib |= GEMDOS_FILE_ATTRIB_HIDDEN; 633: if (dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY) 634: Attrib |= GEMDOS_FILE_ATTRIB_SUBDIRECTORY; 635: */ 636: return(Attrib); 637: } 638: 1.1.1.2 root 639: /*-----------------------------------------------------------------------*/ 1.1 root 640: /* 641: GEMDOS Cauxin 642: Call 0x3 643: */ 644: BOOL GemDOS_Cauxin(unsigned long Params) 645: { 646: unsigned char Char; 647: 1.1.1.2 root 648: /* Wait here until a character is ready */ 1.1 root 649: while(!RS232_GetStatus()); 650: 1.1.1.2 root 651: /* And read character */ 1.1 root 652: RS232_ReadBytes(&Char,1); 653: Regs[REG_D0] = Char; 654: 655: return(TRUE); 656: } 657: 1.1.1.2 root 658: /*-----------------------------------------------------------------------*/ 1.1 root 659: /* 660: GEMDOS Cauxout 661: Call 0x4 662: */ 663: BOOL GemDOS_Cauxout(unsigned long Params) 664: { 665: unsigned char Char; 666: 1.1.1.2 root 667: /* Send character to RS232 */ 1.1 root 668: Char = STMemory_ReadWord(Params+SIZE_WORD); 669: RS232_TransferBytesTo(&Char,1); 670: 671: return(TRUE); 672: } 673: 1.1.1.2 root 674: /*-----------------------------------------------------------------------*/ 1.1 root 675: /* 676: GEMDOS Cprnout 677: Call 0x5 678: */ 679: BOOL GemDOS_Cprnout(unsigned long Params) 680: { 681: unsigned char Char; 682: 1.1.1.2 root 683: /* Send character to printer(or file) */ 1.1 root 684: Char = STMemory_ReadWord(Params+SIZE_WORD); 685: Printer_TransferByteTo(Char); 1.1.1.2 root 686: Regs[REG_D0] = -1; /* Printer OK */ 1.1 root 687: 688: return(TRUE); 689: } 690: 1.1.1.2 root 691: /*-----------------------------------------------------------------------*/ 1.1 root 692: /* 693: GEMDOS Set drive (0=A,1=B,2=C etc...) 694: Call 0xE 695: */ 696: BOOL GemDOS_SetDrv(unsigned long Params) 697: { 1.1.1.2 root 698: /* Read details from stack for our own use */ 1.1 root 699: CurrentDrive = STMemory_ReadWord(Params+SIZE_WORD); 700: 1.1.1.2 root 701: /* Still re-direct to TOS */ 1.1 root 702: return(FALSE); 703: } 704: 1.1.1.2 root 705: /*-----------------------------------------------------------------------*/ 1.1 root 706: /* 707: GEMDOS Cprnos 708: Call 0x11 709: */ 710: BOOL GemDOS_Cprnos(unsigned long Params) 711: { 1.1.1.2 root 712: Regs[REG_D0] = -1; /* Printer OK */ 1.1 root 713: 714: return(TRUE); 715: } 716: 1.1.1.2 root 717: /*-----------------------------------------------------------------------*/ 1.1 root 718: /* 719: GEMDOS Cauxis 720: Call 0x12 721: */ 722: BOOL GemDOS_Cauxis(unsigned long Params) 723: { 1.1.1.2 root 724: /* Read our RS232 state */ 1.1 root 725: if (RS232_GetStatus()) 1.1.1.2 root 726: Regs[REG_D0] = -1; /* Chars waiting */ 1.1 root 727: else 728: Regs[REG_D0] = 0; 729: 730: return(TRUE); 731: } 732: 1.1.1.2 root 733: /*-----------------------------------------------------------------------*/ 1.1 root 734: /* 735: GEMDOS Cauxos 736: Call 0x13 737: */ 738: BOOL GemDOS_Cauxos(unsigned long Params) 739: { 1.1.1.2 root 740: Regs[REG_D0] = -1; /* Device ready */ 1.1 root 741: 742: return(TRUE); 743: } 744: 1.1.1.2 root 745: /*-----------------------------------------------------------------------*/ 1.1 root 746: /* 747: GEMDOS Set Disc Transfer Address (DTA) 748: Call 0x1A 749: */ 750: BOOL GemDOS_SetDTA(unsigned long Params) 751: { 1.1.1.2 root 752: /* Look up on stack to find where DTA is! Store as PC pointer */ 1.1 root 753: pDTA = (DTA *)STRAM_ADDR(STMemory_ReadLong(Params+SIZE_WORD)); 754: 755: return(FALSE); 756: } 757: 1.1.1.2 root 758: /*-----------------------------------------------------------------------*/ 759: /* 760: GEMDOS Dfree Free disc space. 761: Call 0x39 762: */ 763: BOOL GemDOS_DFree(unsigned long Params) 764: { 765: int Drive; 766: unsigned long Address; 767: 768: Address = (unsigned long)STMemory_ReadLong(Params+SIZE_WORD); 769: Drive = STMemory_ReadWord(Params+SIZE_WORD+SIZE_LONG); 770: /* is it our drive? */ 771: if((Drive == 0 && CurrentDrive >= 2) || Drive >= 3){ 772: /* FIXME: Report actual free drive space */ 773: 774: STMemory_WriteLong(Address, 10*2048); /* free clusters (mock 10 Mb) */ 775: STMemory_WriteLong(Address+SIZE_LONG, 50*2048 ); /* total clusters (mock 50 Mb) */ 776: 777: STMemory_WriteLong(Address+SIZE_LONG*2, 512 ); /* bytes per sector */ 778: STMemory_WriteLong(Address+SIZE_LONG*3, 1 ); /* sectors per cluster */ 779: return (TRUE); 780: } else return(FALSE); /* redirect to TOS */ 781: } 782: 783: /*-----------------------------------------------------------------------*/ 1.1 root 784: /* 785: GEMDOS MkDir 786: Call 0x39 787: */ 788: BOOL GemDOS_MkDir(unsigned long Params) 789: { 790: char szDirPath[MAX_PATH]; 791: char *pDirName; 792: int Drive; 793: 1.1.1.2 root 794: /* Find directory to make */ 1.1 root 795: pDirName = (char *)STRAM_ADDR(STMemory_ReadLong(Params+SIZE_WORD)); 1.1.1.2 root 796: 1.1 root 797: Drive = GemDOS_IsFileNameAHardDrive(pDirName); 1.1.1.2 root 798: 1.1 root 799: if (ISHARDDRIVE(Drive)) { 1.1.1.2 root 800: /* Copy old directory, as if calls fails keep this one */ 1.1 root 801: GemDOS_CreateHardDriveFileName(Drive,pDirName,szDirPath); 802: 1.1.1.2 root 803: /* Attempt to make directory */ 1.1 root 804: if ( mkdir(szDirPath, 0755)==0 ) 805: Regs[REG_D0] = GEMDOS_EOK; 806: else 1.1.1.2 root 807: Regs[REG_D0] = GEMDOS_EACCDN; /* Access denied */ 1.1 root 808: 809: return(TRUE); 810: } 811: return(FALSE); 812: } 813: 1.1.1.2 root 814: /*-----------------------------------------------------------------------*/ 1.1 root 815: /* 816: GEMDOS RmDir 817: Call 0x3A 818: */ 819: BOOL GemDOS_RmDir(unsigned long Params) 820: { 821: char szDirPath[MAX_PATH]; 822: char *pDirName; 823: int Drive; 824: 1.1.1.2 root 825: /* Find directory to make */ 1.1 root 826: pDirName = (char *)STRAM_ADDR(STMemory_ReadLong(Params+SIZE_WORD)); 827: Drive = GemDOS_IsFileNameAHardDrive(pDirName); 828: if (ISHARDDRIVE(Drive)) { 1.1.1.2 root 829: /* Copy old directory, as if calls fails keep this one */ 1.1 root 830: GemDOS_CreateHardDriveFileName(Drive,pDirName,szDirPath); 831: 1.1.1.2 root 832: /* Attempt to make directory */ 1.1 root 833: if ( rmdir(szDirPath)==0 ) 834: Regs[REG_D0] = GEMDOS_EOK; 835: else 1.1.1.2 root 836: Regs[REG_D0] = GEMDOS_EACCDN; /* Access denied */ 1.1 root 837: 838: return(TRUE); 839: } 840: return(FALSE); 841: } 842: 1.1.1.2 root 843: /*-----------------------------------------------------------------------*/ 1.1 root 844: /* 845: GEMDOS ChDir 846: Call 0x3B 847: */ 848: BOOL GemDOS_ChDir(unsigned long Params) 849: { 850: char szDirPath[MAX_PATH]; 851: char *pDirName; 852: int Drive; 1.1.1.2 root 853: int n; 1.1 root 854: 1.1.1.2 root 855: /* Find new directory */ 1.1 root 856: pDirName = (char *)STRAM_ADDR(STMemory_ReadLong(Params+SIZE_WORD)); 1.1.1.2 root 857: 1.1 root 858: Drive = GemDOS_IsFileNameAHardDrive(pDirName); 1.1.1.3 root 859: 1.1 root 860: if (ISHARDDRIVE(Drive)) { 861: 1.1.1.3 root 862: if(pDirName[1] == ':') pDirName += 2; 863: 864: /* FIXME: Klugdy code, check path exists, else error (GEMDOS_EPTHNF) */ 865: 866: sprintf(szDirPath, "%s/", pDirName); 867: 868: /* front-slashify */ 1.1.1.2 root 869: for(n=0;n<MAX_PATH;n++) if(szDirPath[n] == '\\')szDirPath[n] = '/'; 1.1.1.3 root 870: 871: /* remove any trailing slashes */ 872: if (szDirPath[strlen(szDirPath)-1]=='/' && szDirPath[strlen(szDirPath)-2]=='/') 873: szDirPath[strlen(szDirPath)-1] = '\0'; /* then remove it! */ 874: 875: 876: strcpy(emudrives[0]->fs_currpath, szDirPath); 1.1.1.2 root 877: Regs[REG_D0] = GEMDOS_EOK; 1.1 root 878: return(TRUE); 879: } 1.1.1.2 root 880: 1.1 root 881: return(FALSE); 882: } 883: 1.1.1.2 root 884: /*-----------------------------------------------------------------------*/ 1.1 root 885: /* 886: GEMDOS Create file 887: Call 0x3C 888: */ 889: BOOL GemDOS_Create(unsigned long Params) 890: { 891: char szActualFileName[MAX_PATH]; 892: char *pszFileName; 1.1.1.2 root 893: char *rwflags[] = { "w+", /* read / write (truncate if exists) */ 894: "wb" /* write only */ 895: }; 1.1 root 896: int Drive,Index,Mode; 897: 1.1.1.2 root 898: /* Find filename */ 1.1 root 899: pszFileName = (char *)STRAM_ADDR(STMemory_ReadLong(Params+SIZE_WORD)); 900: Mode = STMemory_ReadWord(Params+SIZE_WORD+SIZE_LONG); 901: Drive = GemDOS_IsFileNameAHardDrive(pszFileName); 902: if (ISHARDDRIVE(Drive)) { 1.1.1.2 root 903: /* And convert to hard drive filename */ 1.1 root 904: GemDOS_CreateHardDriveFileName(Drive,pszFileName,szActualFileName); 905: 1.1.1.2 root 906: /* Find slot to store file handle, as need to return WORD handle for ST */ 1.1 root 907: Index = GemDOS_FindFreeFileHandle(); 908: if (Index==-1) { 1.1.1.2 root 909: /* No free handles, return error code */ 910: Regs[REG_D0] = GEMDOS_ENHNDL; /* No more handles */ 1.1 root 911: return(TRUE); 912: } 913: else { 914: #ifdef ENABLE_SAVING 915: 1.1.1.2 root 916: FileHandles[Index].FileHandle = fopen(szActualFileName, rwflags[Mode&0x01]); 917: 918: if (FileHandles[Index].FileHandle != NULL) { 1.1 root 919: /* Tag handle table entry as used and return handle */ 920: FileHandles[Index].bUsed = TRUE; 1.1.1.2 root 921: Regs[REG_D0] = Index+BASE_FILEHANDLE; /* Return valid ST file handle from range 6 to 45! (ours start from 0) */ 1.1 root 922: return(TRUE); 923: } 924: else { 1.1.1.2 root 925: Regs[REG_D0] = GEMDOS_EFILNF; /* File not found */ 1.1 root 926: return(TRUE); 927: } 928: #else 1.1.1.2 root 929: Regs[REG_D0] = GEMDOS_EFILNF; /* File not found */ 1.1 root 930: return(TRUE); 931: #endif 932: } 933: } 934: 935: return(FALSE); 936: } 937: 1.1.1.2 root 938: /*-----------------------------------------------------------------------*/ 1.1 root 939: /* 940: GEMDOS Open file 941: Call 0x3D 942: */ 943: BOOL GemDOS_Open(unsigned long Params) 944: { 945: char szActualFileName[MAX_PATH]; 946: char *pszFileName; 1.1.1.2 root 947: char *open_modes[] = { "rb", "wb", "r+" }; /* convert atari modes to stdio modes */ 1.1 root 948: int Drive,Index,Mode; 949: 1.1.1.2 root 950: /* Find filename */ 1.1 root 951: pszFileName = (char *)STRAM_ADDR(STMemory_ReadLong(Params+SIZE_WORD)); 952: Mode = STMemory_ReadWord(Params+SIZE_WORD+SIZE_LONG); 953: Drive = GemDOS_IsFileNameAHardDrive(pszFileName); 1.1.1.2 root 954: 1.1 root 955: if (ISHARDDRIVE(Drive)) { 1.1.1.2 root 956: /* And convert to hard drive filename */ 1.1 root 957: GemDOS_CreateHardDriveFileName(Drive,pszFileName,szActualFileName); 1.1.1.2 root 958: /* Find slot to store file handle, as need to return WORD handle for ST */ 1.1 root 959: Index = GemDOS_FindFreeFileHandle(); 1.1.1.2 root 960: if (Index == -1) { 961: /* No free handles, return error code */ 962: Regs[REG_D0] = GEMDOS_ENHNDL; /* No more handles */ 1.1 root 963: return(TRUE); 964: } 965: 1.1.1.2 root 966: /* Open file */ 967: FileHandles[Index].FileHandle = fopen(szActualFileName, open_modes[Mode&0x03]); 1.1 root 968: 1.1.1.2 root 969: sprintf(FileHandles[Index].szActualName,"%s",szActualFileName); 970: 971: if (FileHandles[Index].FileHandle != NULL) { 972: /* Tag handle table entry as used and return handle */ 973: FileHandles[Index].bUsed = TRUE; 974: Regs[REG_D0] = Index+BASE_FILEHANDLE; /* Return valid ST file handle from range 6 to 45! (ours start from 0) */ 975: return(TRUE); 1.1 root 976: } 1.1.1.2 root 977: Regs[REG_D0] = GEMDOS_EFILNF; /* File not found/ error opening */ 978: return(TRUE); 1.1 root 979: } 1.1.1.2 root 980: 1.1 root 981: return(FALSE); 982: } 983: 1.1.1.2 root 984: /*-----------------------------------------------------------------------*/ 1.1 root 985: /* 986: GEMDOS Close file 987: Call 0x3E 988: */ 989: BOOL GemDOS_Close(unsigned long Params) 990: { 991: int Handle; 992: 1.1.1.2 root 993: /* Find our handle - may belong to TOS */ 1.1 root 994: Handle = STMemory_ReadWord(Params+SIZE_WORD)-BASE_FILEHANDLE; 995: 1.1.1.2 root 996: /* Check handle was valid */ 1.1 root 997: if (GemDOS_IsInvalidFileHandle(Handle)) { 1.1.1.2 root 998: /* No assume was TOS */ 1.1 root 999: return(FALSE); 1000: } 1001: else { 1.1.1.2 root 1002: /* Close file and free up handle table */ 1003: fclose(FileHandles[Handle].FileHandle); 1.1 root 1004: FileHandles[Handle].bUsed = FALSE; 1.1.1.2 root 1005: /* Return no error */ 1.1 root 1006: Regs[REG_D0] = GEMDOS_EOK; 1007: return(TRUE); 1008: } 1009: } 1010: 1.1.1.2 root 1011: /*-----------------------------------------------------------------------*/ 1.1 root 1012: /* 1013: GEMDOS Read file 1014: Call 0x3F 1015: */ 1016: BOOL GemDOS_Read(unsigned long Params) 1017: { 1018: char *pBuffer; 1.1.1.3 root 1019: unsigned long nBytesRead,Size,CurrentPos,FileSize; 1020: long nBytesLeft; 1.1 root 1021: int Handle; 1022: 1.1.1.2 root 1023: /* Read details from stack */ 1.1 root 1024: Handle = STMemory_ReadWord(Params+SIZE_WORD)-BASE_FILEHANDLE; 1025: Size = STMemory_ReadLong(Params+SIZE_WORD+SIZE_WORD); 1026: pBuffer = (char *)STRAM_ADDR(STMemory_ReadLong(Params+SIZE_WORD+SIZE_WORD+SIZE_LONG)); 1027: 1.1.1.2 root 1028: /* Check handle was valid */ 1.1 root 1029: if (GemDOS_IsInvalidFileHandle(Handle)) { 1.1.1.2 root 1030: /* No - assume was TOS */ 1.1 root 1031: return(FALSE); 1032: } 1033: else { 1034: 1.1.1.2 root 1035: /* To quick check to see where our file pointer is and how large the file is */ 1036: CurrentPos = ftell(FileHandles[Handle].FileHandle); 1037: fseek(FileHandles[Handle].FileHandle, 0, SEEK_END); 1038: FileSize = ftell(FileHandles[Handle].FileHandle); 1039: fseek(FileHandles[Handle].FileHandle, CurrentPos, SEEK_SET); 1.1 root 1040: 1041: nBytesLeft = FileSize-CurrentPos; 1042: 1.1.1.2 root 1043: /* Check for End Of File */ 1.1.1.3 root 1044: if (nBytesLeft == 0) { 1045: /* FIXME: should we return zero (bytes read) or an error? */ 1046: Regs[REG_D0] = 0; 1.1 root 1047: return(TRUE); 1048: } 1049: else { 1.1.1.2 root 1050: /* Limit to size of file to prevent windows error */ 1.1 root 1051: if (Size>FileSize) 1052: Size = FileSize; 1.1.1.2 root 1053: /* And read data in */ 1054: nBytesRead = fread(pBuffer, 1, Size, FileHandles[Handle].FileHandle); 1.1 root 1055: 1.1.1.2 root 1056: /* Return number of bytes read */ 1.1 root 1057: Regs[REG_D0] = nBytesRead; 1058: 1059: return(TRUE); 1060: } 1061: } 1062: } 1063: 1.1.1.2 root 1064: /*-----------------------------------------------------------------------*/ 1.1 root 1065: /* 1066: GEMDOS Write file 1067: Call 0x40 1068: */ 1069: BOOL GemDOS_Write(unsigned long Params) 1070: { 1071: char *pBuffer; 1072: unsigned long Size,nBytesWritten; 1073: int Handle; 1074: 1075: #ifdef ENABLE_SAVING 1.1.1.2 root 1076: /* Read details from stack */ 1.1 root 1077: Handle = STMemory_ReadWord(Params+SIZE_WORD)-BASE_FILEHANDLE; 1078: Size = STMemory_ReadLong(Params+SIZE_WORD+SIZE_WORD); 1079: pBuffer = (char *)STRAM_ADDR(STMemory_ReadLong(Params+SIZE_WORD+SIZE_WORD+SIZE_LONG)); 1080: 1.1.1.2 root 1081: /* Check handle was valid */ 1.1 root 1082: if (GemDOS_IsInvalidFileHandle(Handle)) { 1.1.1.2 root 1083: /* No assume was TOS */ 1.1 root 1084: return(FALSE); 1085: } 1086: else { 1087: 1.1.1.2 root 1088: nBytesWritten = fwrite(pBuffer, 1, Size, FileHandles[Handle].FileHandle); 1.1 root 1089: if (nBytesWritten>=0) { 1090: 1.1.1.2 root 1091: Regs[REG_D0] = nBytesWritten; /* OK */ 1.1 root 1092: } 1093: else 1.1.1.2 root 1094: Regs[REG_D0] = GEMDOS_EACCDN; /* Access denied(ie read-only) */ 1.1 root 1095: 1096: return(TRUE); 1097: } 1098: #endif 1099: 1100: return(FALSE); 1101: } 1102: 1.1.1.2 root 1103: /*-----------------------------------------------------------------------*/ 1.1 root 1104: /* 1105: GEMDOS UnLink(Delete) file 1106: Call 0x41 1107: */ 1108: BOOL GemDOS_UnLink(unsigned long Params) 1109: { 1110: #ifdef ENABLE_SAVING 1111: char szActualFileName[MAX_PATH]; 1112: char *pszFileName; 1113: int Drive; 1114: 1.1.1.2 root 1115: /* Find filename */ 1.1 root 1116: pszFileName = (char *)STRAM_ADDR(STMemory_ReadLong(Params+SIZE_WORD)); 1117: Drive = GemDOS_IsFileNameAHardDrive(pszFileName); 1118: if (ISHARDDRIVE(Drive)) { 1.1.1.2 root 1119: /* And convert to hard drive filename */ 1.1 root 1120: GemDOS_CreateHardDriveFileName(Drive,pszFileName,szActualFileName); 1121: 1.1.1.2 root 1122: /* Now delete file?? */ 1.1 root 1123: if ( unlink(szActualFileName)==0 ) 1.1.1.2 root 1124: Regs[REG_D0] = GEMDOS_EOK; /* OK */ 1.1 root 1125: else 1.1.1.2 root 1126: Regs[REG_D0] = GEMDOS_EFILNF; /* File not found */ 1.1 root 1127: 1128: return(TRUE); 1129: } 1130: #endif 1131: 1132: return(FALSE); 1133: } 1134: 1.1.1.2 root 1135: /*-----------------------------------------------------------------------*/ 1.1 root 1136: /* 1137: GEMDOS File seek 1138: Call 0x42 1139: */ 1140: BOOL GemDOS_LSeek(unsigned long Params) 1141: { 1142: long Offset; 1143: int Handle,Mode; 1144: 1.1.1.2 root 1145: /* Read details from stack */ 1.1 root 1146: Offset = (long)STMemory_ReadLong(Params+SIZE_WORD); 1147: Handle = STMemory_ReadWord(Params+SIZE_WORD+SIZE_LONG)-BASE_FILEHANDLE; 1148: Mode = STMemory_ReadWord(Params+SIZE_WORD+SIZE_LONG+SIZE_WORD); 1149: 1.1.1.2 root 1150: /* Check handle was valid */ 1.1 root 1151: if (GemDOS_IsInvalidFileHandle(Handle)) { 1.1.1.2 root 1152: /* No assume was TOS */ 1.1 root 1153: return(FALSE); 1154: } 1155: else { 1.1.1.2 root 1156: /* Return offset from start of file */ 1157: fseek(FileHandles[Handle].FileHandle, Offset, Mode); 1158: Regs[REG_D0] = ftell(FileHandles[Handle].FileHandle); 1.1 root 1159: return(TRUE); 1160: } 1161: } 1162: 1.1.1.2 root 1163: /*-----------------------------------------------------------------------*/ 1164: /* 1165: GEMDOS Get Directory 1166: Call 0x47 1167: */ 1168: int GemDOS_GetDir(unsigned long Params){ 1169: unsigned long Address; 1170: unsigned short Drive; 1171: 1172: Address = (long)STMemory_ReadLong(Params+SIZE_WORD); 1173: Drive = STMemory_ReadWord(Params+SIZE_WORD+SIZE_LONG); 1174: /* is it our drive? */ 1175: if((Drive == 0 && CurrentDrive >= 2) || Drive >= 3){ 1176: STMemory_WriteByte(Address, '\0' ); 1177: Regs[REG_D0] = GEMDOS_EOK; /* OK */ 1178: return(TRUE); 1179: } else return(FALSE); 1180: } 1181: 1182: /*-----------------------------------------------------------------------*/ 1.1 root 1183: /* 1184: PExec Load And Go - Redirect to cart' routine at address 0xFA1000 1185: 1186: If loading from hard-drive(ie drive ID 2 or more) set condition codes to run own GEMDos routines 1187: */ 1.1.1.2 root 1188: int GemDOS_Pexec_LoadAndGo(unsigned long Params) 1.1 root 1189: { 1.1.1.3 root 1190: /* add multiple disk support here too */ 1.1.1.2 root 1191: /* Hard-drive? */ 1.1.1.3 root 1192: if( CurrentDrive == emudrives[0]->hd_letter ) 1193: { 1194: /* If not using A: or B:, use my own routines to load */ 1195: return(CALL_PEXEC_ROUTINE); 1196: } 1.1.1.2 root 1197: else return(FALSE); 1.1 root 1198: } 1199: 1.1.1.2 root 1200: /*-----------------------------------------------------------------------*/ 1.1 root 1201: /* 1202: PExec Load But Don't Go - Redirect to cart' routine at address 0xFA1000 1203: */ 1.1.1.2 root 1204: int GemDOS_Pexec_LoadDontGo(unsigned long Params) 1.1 root 1205: { 1.1.1.2 root 1206: /* Hard-drive? */ 1.1.1.3 root 1207: if( CurrentDrive == emudrives[0]->hd_letter ) 1208: { 1209: return(CALL_PEXEC_ROUTINE); 1210: } else return(FALSE); 1.1 root 1211: } 1212: 1.1.1.2 root 1213: /*-----------------------------------------------------------------------*/ 1.1 root 1214: /* 1215: GEMDOS PExec handler 1216: Call 0x4B 1217: */ 1.1.1.2 root 1218: int GemDOS_Pexec(unsigned long Params) 1.1 root 1219: { 1220: unsigned short int Mode; 1221: 1.1.1.2 root 1222: /* Find PExec mode */ 1.1 root 1223: Mode = STMemory_ReadWord(Params+SIZE_WORD); 1224: 1.1.1.2 root 1225: /* Re-direct as needed */ 1.1 root 1226: switch(Mode) { 1.1.1.2 root 1227: case 0: /* Load and go */ 1228: return(GemDOS_Pexec_LoadAndGo(Params)); 1229: case 3: /* Load, don't go */ 1230: return(GemDOS_Pexec_LoadDontGo(Params)); 1231: case 4: /* Just go */ 1232: return(FALSE); 1233: case 5: /* Create basepage */ 1234: return(FALSE); 1235: case 6: 1236: return(FALSE); 1.1 root 1237: 1.1.1.2 root 1238: default: 1239: return(FALSE); 1.1 root 1240: } 1241: 1.1.1.2 root 1242: /* Still re-direct to TOS */ 1.1 root 1243: return(FALSE); 1244: } 1245: 1.1.1.4 root 1246: 1247: /*-----------------------------------------------------------------------*/ 1248: /* 1249: GEMDOS Search Next 1250: Call 0x4F 1251: */ 1252: BOOL GemDOS_SNext(unsigned long Params) 1253: { 1254: struct dirent **temp; 1255: int Index; 1256: 1257: /* Was DTA ours or TOS? */ 1258: if (STMemory_ReadLong_PCSpace(pDTA->magic)==DTA_MAGIC_NUMBER) { 1259: 1260: /* Find index into our list of structures */ 1261: Index = STMemory_ReadWord_PCSpace(pDTA->index)&(MAX_DTAS_FILES-1); 1262: 1263: if(InternalDTAs[Index].centry >= InternalDTAs[Index].nentries){ 1264: Regs[REG_D0] = GEMDOS_ENMFIL; /* No more files */ 1265: return(TRUE); 1266: } 1267: 1268: temp = InternalDTAs[Index].found; 1269: if(PopulateDTA(InternalDTAs[Index].path, temp[InternalDTAs[Index].centry++]) == FALSE){ 1270: fprintf(stderr,"\tError setting DTA.\n"); 1271: return(TRUE); 1272: } 1273: 1274: Regs[REG_D0] = GEMDOS_EOK; 1275: return(TRUE); 1276: } 1277: 1278: return(FALSE); 1279: } 1280: 1281: 1.1.1.2 root 1282: /*-----------------------------------------------------------------------*/ 1.1 root 1283: /* 1284: GEMDOS Find first file 1285: Call 0x4E 1286: */ 1287: BOOL GemDOS_SFirst(unsigned long Params) 1288: { 1289: char szActualFileName[MAX_PATH]; 1.1.1.2 root 1290: char tempstr[MAX_PATH]; 1.1 root 1291: char *pszFileName; 1.1.1.2 root 1292: struct dirent **files; 1.1 root 1293: unsigned short int Attr; 1294: int Drive; 1.1.1.2 root 1295: DIR *fsdir; 1296: int i,j,k; 1.1 root 1297: 1.1.1.2 root 1298: /* Find filename to search for */ 1.1 root 1299: pszFileName = (char *)STRAM_ADDR(STMemory_ReadLong(Params+SIZE_WORD)); 1300: Attr = STMemory_ReadWord(Params+SIZE_WORD+SIZE_LONG); 1301: 1302: Drive = GemDOS_IsFileNameAHardDrive(pszFileName); 1303: if (ISHARDDRIVE(Drive)) { 1304: 1.1.1.2 root 1305: /* And convert to hard drive filename */ 1.1 root 1306: GemDOS_CreateHardDriveFileName(Drive,pszFileName,szActualFileName); 1.1.1.2 root 1307: 1308: /* Populate DTA, set index for our use */ 1.1 root 1309: STMemory_WriteWord_PCSpace(pDTA->index,DTAIndex); 1.1.1.2 root 1310: STMemory_WriteLong_PCSpace(pDTA->magic,DTA_MAGIC_NUMBER); /* set our dta magic num */ 1311: 1312: if(InternalDTAs[DTAIndex].bUsed == TRUE) ClearInternalDTA(); 1313: InternalDTAs[DTAIndex].bUsed = TRUE; 1.1 root 1314: 1.1.1.2 root 1315: /* Were we looking for the volume label? */ 1.1 root 1316: if (Attr&GEMDOS_FILE_ATTRIB_VOLUME_LABEL) { 1.1.1.2 root 1317: /* Volume name */ 1318: strcpy(pDTA->dta_name,"EMULATED.001"); 1319: Regs[REG_D0] = GEMDOS_EOK; /* Got volume */ 1.1 root 1320: return(TRUE); 1321: } 1.1.1.2 root 1322: 1323: /* open directory */ 1324: fsfirst_dirname(szActualFileName, InternalDTAs[DTAIndex].path); 1325: fsdir = opendir(InternalDTAs[DTAIndex].path); 1326: 1327: if( fsdir == NULL ){ 1328: Regs[REG_D0] = GEMDOS_EPTHNF; /* Path not found */ 1.1 root 1329: return(TRUE); 1330: } 1.1.1.2 root 1331: /* close directory */ 1332: closedir( fsdir ); 1333: 1334: InternalDTAs[DTAIndex].nentries = scandir(InternalDTAs[DTAIndex].path, &files, 0, alphasort); 1335: if( InternalDTAs[DTAIndex].nentries < 0 ){ 1336: Regs[REG_D0] = GEMDOS_EFILNF; /* File (directory actually) not found */ 1337: return(TRUE); 1338: } 1339: 1340: InternalDTAs[DTAIndex].centry = 0; /* current entry is 0 */ 1341: fsfirst_dirmask(szActualFileName, tempstr); /* get directory mask */ 1.1 root 1342: 1.1.1.2 root 1343: /* Create and populate a list of matching files. */ 1.1 root 1344: 1.1.1.3 root 1345: j = 0; /* count number of entries matching mask */ 1.1.1.2 root 1346: for(i=0;i<InternalDTAs[DTAIndex].nentries;i++) 1347: if(match(tempstr, files[i]->d_name)) j++; 1348: 1349: InternalDTAs[DTAIndex].found = (struct dirent **)malloc(sizeof(struct dirent *) * j); 1350: 1351: /* copy the dirent pointers for files matching the mask to our list */ 1352: k = 0; 1353: for(i=0;i<InternalDTAs[DTAIndex].nentries;i++) 1354: if(match(tempstr, files[i]->d_name)){ 1355: InternalDTAs[DTAIndex].found[k] = files[i]; 1356: k++; 1357: } 1.1.1.3 root 1358: 1.1.1.2 root 1359: InternalDTAs[DTAIndex].nentries = j; /* set number of legal entries */ 1.1 root 1360: 1.1.1.2 root 1361: if(InternalDTAs[DTAIndex].nentries == 0){ 1362: /* No files of that match, return error code */ 1363: Regs[REG_D0] = GEMDOS_EFILNF; /* File not found */ 1364: return(TRUE); 1.1 root 1365: } 1.1.1.2 root 1366: 1367: /* Scan for first file (SNext uses no parameters) */ 1.1.1.4 root 1368: GemDOS_SNext(0); 1.1.1.2 root 1369: /* increment DTA index */ 1370: DTAIndex++; 1371: DTAIndex&=(MAX_DTAS_FILES-1); 1372: 1.1 root 1373: return(TRUE); 1374: } 1375: return(FALSE); 1376: } 1377: 1378: 1.1.1.2 root 1379: /*-----------------------------------------------------------------------*/ 1.1 root 1380: /* 1381: GEMDOS Rename 1382: Call 0x56 1383: */ 1384: BOOL GemDOS_Rename(unsigned long Params) 1385: { 1386: char *pszNewFileName,*pszOldFileName; 1387: char szNewActualFileName[MAX_PATH],szOldActualFileName[MAX_PATH]; 1388: int NewDrive, OldDrive; 1389: 1.1.1.2 root 1390: /* Read details from stack */ 1.1 root 1391: pszOldFileName = (char *)STRAM_ADDR(STMemory_ReadLong(Params+SIZE_WORD+SIZE_WORD)); 1392: pszNewFileName = (char *)STRAM_ADDR(STMemory_ReadLong(Params+SIZE_WORD+SIZE_WORD+SIZE_LONG)); 1393: 1394: NewDrive = GemDOS_IsFileNameAHardDrive(pszNewFileName); 1395: OldDrive = GemDOS_IsFileNameAHardDrive(pszOldFileName); 1396: if (ISHARDDRIVE(NewDrive) && ISHARDDRIVE(OldDrive)) { 1.1.1.2 root 1397: /* And convert to hard drive filenames */ 1.1 root 1398: GemDOS_CreateHardDriveFileName(NewDrive,pszNewFileName,szNewActualFileName); 1399: GemDOS_CreateHardDriveFileName(OldDrive,pszOldFileName,szOldActualFileName); 1400: 1.1.1.2 root 1401: /* Rename files */ 1.1 root 1402: if ( rename(szOldActualFileName,szNewActualFileName)==0 ) 1403: Regs[REG_D0] = GEMDOS_EOK; 1404: else 1.1.1.2 root 1405: Regs[REG_D0] = GEMDOS_EACCDN; /* Access denied */ 1.1 root 1406: return(TRUE); 1407: } 1408: 1409: return(FALSE); 1410: } 1411: 1.1.1.2 root 1412: /*-----------------------------------------------------------------------*/ 1.1 root 1413: /* 1414: GEMDOS GSDToF 1415: Call 0x57 1416: */ 1417: BOOL GemDOS_GSDToF(unsigned long Params) 1418: { 1419: DATETIME DateTime; 1.1.1.2 root 1420: unsigned long pBuffer; 1.1 root 1421: int Handle,Flag; 1422: 1.1.1.2 root 1423: /* Read details from stack */ 1424: pBuffer = STMemory_ReadLong(Params+SIZE_WORD); 1.1 root 1425: Handle = STMemory_ReadWord(Params+SIZE_WORD+SIZE_LONG)-BASE_FILEHANDLE; 1426: Flag = STMemory_ReadWord(Params+SIZE_WORD+SIZE_WORD+SIZE_LONG); 1427: 1.1.1.2 root 1428: /* Check handle was valid */ 1.1 root 1429: if (GemDOS_IsInvalidFileHandle(Handle)) { 1.1.1.2 root 1430: /* No assume was TOS */ 1.1 root 1431: return(FALSE); 1432: } 1433: 1.1.1.2 root 1434: /* Set time/date stamp? Do nothing. */ 1435: if( Flag == 1 ){ 1436: Regs[REG_D0] = GEMDOS_EOK; 1437: return (TRUE); 1.1 root 1438: } 1.1.1.2 root 1439: 1440: Regs[REG_D0] = GEMDOS_ERROR; /* Invalid parameter */ 1.1 root 1441: 1.1.1.2 root 1442: if (GetFileInformation(FileHandles[Handle].szActualName, &DateTime) == TRUE){ 1443: STMemory_WriteWord(pBuffer, DateTime.word1); 1444: STMemory_WriteWord(pBuffer+2, DateTime.word2); 1445: Regs[REG_D0] = GEMDOS_EOK; 1.1 root 1446: } 1.1.1.2 root 1447: return (TRUE); 1.1 root 1448: } 1449: 1450: /*-----------------------------------------------------------------------*/ 1451: /* 1452: Run GEMDos call, and re-direct if need to. Used to handle hard-disc emulation etc... 1453: This sets the condition codes(in SR), which are used in the 'cart.s' program to decide if we 1454: need to run old GEM vector, or PExec or nothing. 1455: 1456: This method keeps the stack and other states consistant with the original ST which is very important 1457: for the PExec call and maximum compatibility through-out 1458: */ 1459: void GemDOS_OpCode(void) 1460: { 1461: unsigned short int GemDOSCall,CallingSReg; 1462: unsigned long Params; 1.1.1.2 root 1463: short RunOld; 1.1 root 1464: 1.1.1.2 root 1465: 1466: /* Read SReg from stack to see if parameters are on User or Super stack */ 1467: MakeSR(); /* update value of SR */ 1.1 root 1468: CallingSReg = STMemory_ReadWord(Regs[REG_A7]); 1469: if ((CallingSReg&SR_SUPERMODE)==0) /* Calling from user mode */ 1.1.1.2 root 1470: Params = regs.usp; 1471: else { 1472: Params = Regs[REG_A7]+SIZE_WORD+SIZE_LONG; /* super stack */ 1473: if( cpu_level>0 ) 1474: Params += SIZE_WORD; /* Skip extra word whe CPU is >=68010 */ 1475: } 1.1 root 1476: 1477: /* Default to run TOS GemDos (SR_NEG run Gemdos, SR_ZERO already done, SR_OVERFLOW run own 'Pexec' */ 1.1.1.2 root 1478: RunOld = TRUE; 1.1 root 1479: SR &= SR_CLEAR_OVERFLOW; 1480: SR &= SR_CLEAR_ZERO; 1481: SR |= SR_NEG; 1482: 1483: /* Find pointer to call parameters */ 1484: GemDOSCall = STMemory_ReadWord(Params); 1.1.1.2 root 1485: 1486: #ifdef GEMDOS_VERBOSE 1487: if(GemDOSCall <= 0x57) 1488: fprintf(stderr, "GemDOS 0x%X (%s)\n",GemDOSCall,pszGemDOSNames[GemDOSCall]); 1.1.1.3 root 1489: if(!GemDOSCall){ 1490: fprintf(stderr, "Warning!!\n"); 1491: DebugUI(); 1492: } 1.1 root 1493: #endif 1494: 1495: /* Intercept call */ 1496: switch(GemDOSCall) { 1.1.1.2 root 1497: /* case 0x3: */ 1498: /* if (GemDOS_Cauxin(Params)) */ 1499: /* RunOld = FALSE; */ 1500: /* break; */ 1501: /* case 0x4: */ 1502: /* if (GemDOS_Cauxout(Params)) */ 1503: /* RunOld = FALSE; */ 1504: /* break; */ 1505: /* case 0x5: */ 1506: /* if (GemDOS_Cprnout(Params)) */ 1507: /* RunOld = FALSE; */ 1508: /* break; */ 1509: case 0xe: 1510: if (GemDOS_SetDrv(Params)) 1511: RunOld = FALSE; 1512: break; 1513: /* case 0x11: */ 1514: /* if (GemDOS_Cprnos(Params)) */ 1515: /* RunOld = FALSE; */ 1516: /* break; */ 1517: /* case 0x12: */ 1518: /* if (GemDOS_Cauxis(Params)) */ 1519: /* RunOld = FALSE; */ 1520: /* break; */ 1521: /* case 0x13: */ 1522: /* if (GemDOS_Cauxos(Params)) */ 1523: /* RunOld = FALSE; */ 1524: /* break; */ 1.1 root 1525: case 0x1a: 1526: if (GemDOS_SetDTA(Params)) 1.1.1.2 root 1527: RunOld = FALSE; 1528: break; 1529: case 0x36: 1530: if (GemDOS_DFree(Params)) 1531: RunOld = FALSE; 1.1 root 1532: break; 1533: case 0x39: 1534: if (GemDOS_MkDir(Params)) 1.1.1.2 root 1535: RunOld = FALSE; 1.1 root 1536: break; 1537: case 0x3a: 1538: if (GemDOS_RmDir(Params)) 1.1.1.2 root 1539: RunOld = FALSE; 1.1 root 1540: break; 1541: case 0x3b: 1542: if (GemDOS_ChDir(Params)) 1.1.1.2 root 1543: RunOld = FALSE; 1.1 root 1544: break; 1545: case 0x3c: 1546: if (GemDOS_Create(Params)) 1.1.1.2 root 1547: RunOld = FALSE; 1.1 root 1548: break; 1549: case 0x3d: 1550: if (GemDOS_Open(Params)) 1.1.1.2 root 1551: RunOld = FALSE; 1.1 root 1552: break; 1553: case 0x3e: 1554: if (GemDOS_Close(Params)) 1.1.1.2 root 1555: RunOld = FALSE; 1.1 root 1556: break; 1557: case 0x3f: 1558: if (GemDOS_Read(Params)) 1.1.1.2 root 1559: RunOld = FALSE; 1.1 root 1560: break; 1561: case 0x40: 1562: if (GemDOS_Write(Params)) 1.1.1.2 root 1563: RunOld = FALSE; 1.1 root 1564: break; 1565: case 0x41: 1566: if (GemDOS_UnLink(Params)) 1.1.1.2 root 1567: RunOld = FALSE; 1.1 root 1568: break; 1569: case 0x42: 1570: if (GemDOS_LSeek(Params)) 1.1.1.2 root 1571: RunOld = FALSE; 1572: break; 1573: case 0x47: 1574: if (GemDOS_GetDir(Params)) 1575: RunOld = FALSE; 1.1 root 1576: break; 1577: case 0x4b: 1.1.1.2 root 1578: if(GemDOS_Pexec(Params) == CALL_PEXEC_ROUTINE); 1579: RunOld = CALL_PEXEC_ROUTINE; 1.1 root 1580: break; 1581: case 0x4e: 1582: if (GemDOS_SFirst(Params)) 1.1.1.2 root 1583: RunOld = FALSE; 1.1 root 1584: break; 1585: case 0x4f: 1586: if (GemDOS_SNext(Params)) 1.1.1.2 root 1587: RunOld = FALSE; 1.1 root 1588: break; 1.1.1.2 root 1589: case 0x56: 1590: if (GemDOS_Rename(Params)) 1591: RunOld = FALSE; 1592: break; 1593: case 0x57: 1594: if (GemDOS_GSDToF(Params)) 1595: RunOld = FALSE; 1596: break; 1597: } 1598: 1599: switch(RunOld){ 1600: case FALSE: /* skip over branch to pexec to RTE */ 1601: SR |= SR_ZERO; 1602: break; 1603: case CALL_PEXEC_ROUTINE: /* branch to pexec, then redirect to old gemdos. */ 1604: SR |= SR_OVERFLOW; 1605: break; 1.1 root 1606: } 1607: 1.1.1.2 root 1608: MakeFromSR(); /* update the flags from the SR register */ 1.1 root 1609: } 1610: 1.1.1.2 root 1611: /*-----------------------------------------------------------------------*/ 1.1 root 1612: /* 1.1.1.2 root 1613: GemDOS_Boot - routine called on the first occurence of the gemdos opcode. 1.1.1.3 root 1614: (this should be in the cartridge bootrom) 1615: Sets up our gemdos handler (or, if we don't need one, just turn off keyclicks) 1.1.1.2 root 1616: */ 1617: 1618: void GemDOS_Boot() 1619: { 1620: 1.1.1.3 root 1621: bInitGemDOS = TRUE; 1622: #ifdef GEMDOS_VERBOSE 1623: fprintf(stderr, "Gemdos_Boot()\n"); 1624: #endif 1.1.1.2 root 1625: /* install our gemdos handler, if -e or --harddrive option used */ 1.1.1.3 root 1626: if(GEMDOS_EMU_ON){ 1627: 1.1.1.2 root 1628: /* Patch pexec code - coded value is 4, but must be 6 for TOS > 1.00 */ 1.1.1.5 ! root 1629: if(TosVersion > 0x0100) 1.1.1.2 root 1630: STMemory_WriteByte(CART_PEXEC_TOS, 0x06); 1631: 1632: /* Save old GEMDOS handler adress */ 1633: STMemory_WriteLong(CART_OLDGEMDOS, STMemory_ReadLong(0x0084)); 1634: /* Setup new GEMDOS handler, see cartimg.c */ 1635: STMemory_WriteLong(0x0084, CART_GEMDOS); 1.1 root 1636: } 1637: } 1.1.1.2 root 1638: 1639: /* 1640: GemDOS_RunOldOpCode() 1641: Has been relocated to a routine in hatari-glue.c 1642: */ 1643: 1644:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.