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