|
|
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.14 root 21: const char Gemdos_fileid[] = "Hatari gemdos.c : " __DATE__ " " __TIME__;
1.1.1.12 root 22:
23: #include <config.h>
1.1 root 24:
1.1.1.4 root 25: #include <sys/stat.h>
26: #include <time.h>
27: #include <ctype.h>
28: #include <unistd.h>
1.1.1.12 root 29: #include <errno.h>
30:
31: #if HAVE_GLOB_H
1.1.1.6 root 32: #include <glob.h>
1.1.1.11 root 33: #endif
1.1.1.4 root 34:
1.1 root 35: #include "main.h"
36: #include "cart.h"
1.1.1.2 root 37: #include "tos.h"
1.1.1.6 root 38: #include "configuration.h"
1.1 root 39: #include "file.h"
40: #include "floppy.h"
1.1.1.3 root 41: #include "hdc.h"
1.1 root 42: #include "gemdos.h"
1.1.1.11 root 43: #include "gemdos_defines.h"
44: #include "log.h"
1.1 root 45: #include "m68000.h"
46: #include "memorySnapShot.h"
47: #include "printer.h"
48: #include "rs232.h"
1.1.1.13 root 49: #include "statusbar.h"
1.1.1.11 root 50: #include "scandir.h"
1.1 root 51: #include "stMemory.h"
1.1.1.13 root 52: #include "str.h"
1.1.1.12 root 53: #include "hatari-glue.h"
54: #include "maccess.h"
1.1.1.7 root 55:
1.1 root 56: #define ENABLE_SAVING /* Turn on saving stuff */
57:
1.1.1.6 root 58: /* GLOB_ONLYDIR is a GNU extension for the glob() function and not defined
59: * on some systems. We should probably use something different for this
60: * case, but at the moment it we simply define it as 0... */
61: #ifndef GLOB_ONLYDIR
1.1.1.15 root 62: # define GLOB_ONLYDIR 0
1.1.1.6 root 63: #endif
64:
1.1.1.11 root 65: /* Maximum supported length of a GEMDOS path: */
66: #define MAX_GEMDOS_PATH 256
1.1.1.3 root 67:
1.1.1.11 root 68:
69: /* Have we re-directed GemDOS vector to our own routines yet? */
1.1.1.13 root 70: bool bInitGemDOS;
1.1.1.11 root 71:
72: /* structure with all the drive-specific data for our emulated drives,
73: * used by GEMDOS_EMU_ON macro
74: */
1.1.1.2 root 75: EMULATEDDRIVE **emudrives = NULL;
76:
1.1.1.11 root 77: #define ISHARDDRIVE(Drive) (Drive!=-1)
78:
79: /*
80: Disk Tranfer Address (DTA)
81: */
82: #define TOS_NAMELEN 14
83:
84: typedef struct {
85: Uint8 index[2];
86: Uint8 magic[4];
87: char dta_pat[TOS_NAMELEN];
88: char dta_sattrib;
89: char dta_attrib;
90: Uint8 dta_time[2];
91: Uint8 dta_date[2];
92: Uint8 dta_size[4];
93: char dta_name[TOS_NAMELEN];
94: } DTA;
95:
96: #define DTA_MAGIC_NUMBER 0x12983476
97: #define MAX_DTAS_FILES 256 /* Must be ^2 */
98: #define CALL_PEXEC_ROUTINE 3 /* Call our cartridge pexec routine */
99:
100: #define BASE_FILEHANDLE 64 /* Our emulation handles - MUST not be valid TOS ones, but MUST be <256 */
101: #define MAX_FILE_HANDLES 32 /* We can allow 32 files open at once */
102:
1.1.1.15 root 103: /*
104: DateTime structure used by TOS call $57 f_dattime
1.1.1.11 root 105: Changed to fix potential problem with alignment.
106: */
107: typedef struct {
108: Uint16 word1;
109: Uint16 word2;
110: } DATETIME;
111:
1.1.1.6 root 112: typedef struct
1.1 root 113: {
1.1.1.13 root 114: bool bUsed;
1.1.1.9 root 115: FILE *FileHandle;
1.1.1.11 root 116: char szActualName[MAX_GEMDOS_PATH]; /* used by F_DATIME (0x57) */
1.1 root 117: } FILE_HANDLE;
118:
1.1.1.6 root 119: typedef struct
1.1.1.2 root 120: {
1.1.1.13 root 121: bool bUsed;
1.1.1.9 root 122: int nentries; /* number of entries in fs directory */
123: int centry; /* current entry # */
124: struct dirent **found; /* legal files */
1.1.1.11 root 125: char path[MAX_GEMDOS_PATH]; /* sfirst path */
1.1.1.2 root 126: } INTERNAL_DTA;
127:
1.1.1.11 root 128: static FILE_HANDLE FileHandles[MAX_FILE_HANDLES];
129: static INTERNAL_DTA InternalDTAs[MAX_DTAS_FILES];
130: static int DTAIndex; /* Circular index into above */
131: static DTA *pDTA; /* Our GEMDOS hard drive Disk Transfer Address structure */
132: static Uint16 CurrentDrive; /* Current drive (0=A,1=B,2=C etc...) */
133: static Uint32 act_pd; /* Used to get a pointer to the current basepage */
1.1.1.13 root 134: static Uint16 nAttrSFirst; /* File attribute for SFirst/Snext */
1.1.1.6 root 135:
1.1 root 136:
1.1.1.3 root 137:
1.1.1.12 root 138: /* Poor Windows (and maybe other systems) do not have a glob() function... */
139: #if !HAVE_GLOB_H
1.1.1.11 root 140:
141: typedef struct
142: {
143: size_t gl_pathc; /* Count of paths matched so far */
144: char **gl_pathv; /* List of matched pathnames. */
145: size_t gl_offs; /* Slots to reserve in `gl_pathv'. */
146: } glob_t;
147:
1.1.1.12 root 148: static int glob(const char *pattern, int flags,
149: int errfunc(const char *epath, int eerrno),
150: glob_t *pglob)
151: {
152: /* Just a quick hack to keep Hatari happy... */
153: pglob->gl_pathv = malloc(1 * sizeof(void *));
154: pglob->gl_pathv[0] = NULL;
155: pglob->gl_pathc = 0;
1.1.1.11 root 156: return 0;
157: }
158:
1.1.1.12 root 159: static void globfree(glob_t *pglob)
1.1.1.11 root 160: {
1.1.1.12 root 161: free(pglob->gl_pathv);
1.1.1.11 root 162: }
163:
1.1.1.12 root 164: #endif /* HAVE_GLOB_H */
165:
1.1.1.11 root 166:
1.1.1.15 root 167: #if defined(WIN32) && !defined(mkdir)
1.1.1.12 root 168: #define mkdir(name,mode) mkdir(name)
1.1.1.11 root 169: #endif /* WIN32 */
170:
1.1.1.12 root 171: #ifndef S_IRGRP
172: #define S_IRGRP 0
173: #define S_IROTH 0
174: #endif
175:
1.1.1.11 root 176:
1.1.1.3 root 177:
1.1.1.2 root 178: /*-------------------------------------------------------*/
1.1.1.12 root 179: /**
180: * Routines to convert time and date to MSDOS format.
181: * Originally from the STonX emulator. (cheers!)
182: */
1.1.1.9 root 183: static Uint16 GemDOS_Time2dos(time_t t)
1.1.1.2 root 184: {
185: struct tm *x;
1.1.1.12 root 186:
187: x = localtime(&t);
1.1.1.15 root 188:
1.1.1.12 root 189: if (x == NULL)
190: return 0;
191:
1.1.1.2 root 192: return (x->tm_sec>>1)|(x->tm_min<<5)|(x->tm_hour<<11);
193: }
1.1 root 194:
1.1.1.9 root 195: static Uint16 GemDOS_Date2dos(time_t t)
1.1.1.2 root 196: {
197: struct tm *x;
1.1.1.12 root 198:
199: x = localtime(&t);
200:
201: if (x == NULL)
202: return 0;
203:
204: return x->tm_mday | ((x->tm_mon+1)<<5)
205: | (((x->tm_year-80 > 0) ? x->tm_year-80 : 0) << 9);
1.1.1.2 root 206: }
1.1 root 207:
1.1.1.3 root 208:
1.1.1.2 root 209: /*-----------------------------------------------------------------------*/
1.1.1.12 root 210: /**
211: * Populate a DATETIME structure with file info
212: */
1.1.1.13 root 213: static bool GemDOS_GetFileInformation(char *name, DATETIME *DateTime)
1.1.1.2 root 214: {
1.1.1.9 root 215: struct stat filestat;
216: int n;
217: struct tm *x;
218:
219: n = stat(name, &filestat);
220: if (n != 0)
1.1.1.15 root 221: return false;
1.1.1.12 root 222:
223: x = localtime(&filestat.st_mtime);
224: if (x == NULL)
1.1.1.15 root 225: return false;
1.1.1.9 root 226:
227: DateTime->word1 = 0;
228: DateTime->word2 = 0;
229:
230: DateTime->word1 |= (x->tm_mday & 0x1F); /* 5 bits */
231: DateTime->word1 |= (x->tm_mon & 0x0F)<<5; /* 4 bits */
232: DateTime->word1 |= (((x->tm_year-80>0)?x->tm_year-80:0) & 0x7F)<<9; /* 7 bits*/
233:
234: DateTime->word2 |= (x->tm_sec & 0x1F); /* 5 bits */
235: DateTime->word2 |= (x->tm_min & 0x3F)<<5; /* 6 bits */
236: DateTime->word2 |= (x->tm_hour & 0x1F)<<11; /* 5 bits */
1.1.1.2 root 237:
1.1.1.15 root 238: return true;
1.1.1.9 root 239: }
1.1.1.2 root 240:
241:
1.1.1.9 root 242: /*-----------------------------------------------------------------------*/
1.1.1.12 root 243: /**
1.1.1.15 root 244: * Convert from FindFirstFile/FindNextFile attribute to GemDOS format
1.1.1.12 root 245: */
1.1.1.9 root 246: static unsigned char GemDOS_ConvertAttribute(mode_t mode)
247: {
248: unsigned char Attrib = 0;
249:
250: /* Directory attribute */
251: if (S_ISDIR(mode))
252: Attrib |= GEMDOS_FILE_ATTRIB_SUBDIRECTORY;
1.1.1.2 root 253:
1.1.1.9 root 254: /* Read-only attribute */
255: if (!(mode & S_IWUSR))
256: Attrib |= GEMDOS_FILE_ATTRIB_READONLY;
1.1.1.15 root 257:
1.1.1.9 root 258: /* TODO: Other attributes like GEMDOS_FILE_ATTRIB_HIDDEN ? */
1.1.1.2 root 259:
1.1.1.9 root 260: return Attrib;
1.1.1.2 root 261: }
1.1.1.3 root 262:
263:
1.1.1.2 root 264: /*-----------------------------------------------------------------------*/
1.1.1.12 root 265: /**
1.1.1.13 root 266: * Populate the DTA buffer with file info.
267: * @return 0 if entry is ok, 1 if entry should be skipped, < 0 for errors.
1.1.1.12 root 268: */
1.1.1.13 root 269: static int PopulateDTA(char *path, struct dirent *file)
1.1.1.2 root 270: {
1.1.1.11 root 271: char tempstr[MAX_GEMDOS_PATH];
1.1.1.9 root 272: struct stat filestat;
273: int n;
1.1.1.13 root 274: int nFileAttr;
1.1.1.9 root 275:
1.1.1.12 root 276: snprintf(tempstr, sizeof(tempstr), "%s%c%s", path, PATHSEP, file->d_name);
1.1.1.9 root 277: n = stat(tempstr, &filestat);
278: if (n != 0)
1.1.1.12 root 279: {
280: perror(tempstr);
1.1.1.13 root 281: return -1; /* return on error */
1.1.1.12 root 282: }
1.1.1.9 root 283:
284: if (!pDTA)
1.1.1.13 root 285: return -2; /* no DTA pointer set */
286:
287: /* Check file attributes (check is done according to the Profibuch */
288: nFileAttr = GemDOS_ConvertAttribute(filestat.st_mode);
289: if (nFileAttr != 0 && !((nAttrSFirst|0x21) & nFileAttr))
290: return 1;
291:
292: Str_ToUpper(file->d_name); /* convert to atari-style uppercase */
1.1.1.9 root 293: strncpy(pDTA->dta_name,file->d_name,TOS_NAMELEN); /* FIXME: better handling of long file names */
294: do_put_mem_long(pDTA->dta_size, filestat.st_size);
295: do_put_mem_word(pDTA->dta_time, GemDOS_Time2dos(filestat.st_mtime));
296: do_put_mem_word(pDTA->dta_date, GemDOS_Date2dos(filestat.st_mtime));
1.1.1.13 root 297: pDTA->dta_attrib = nFileAttr;
1.1.1.2 root 298:
1.1.1.13 root 299: return 0;
1.1.1.2 root 300: }
301:
1.1.1.3 root 302:
1.1.1.2 root 303: /*-----------------------------------------------------------------------*/
1.1.1.12 root 304: /**
305: * Clear a used DTA structure.
306: */
1.1.1.7 root 307: static void ClearInternalDTA(void)
308: {
1.1.1.9 root 309: int i;
1.1.1.2 root 310:
1.1.1.9 root 311: /* clear the old DTA structure */
312: if (InternalDTAs[DTAIndex].found != NULL)
313: {
314: for (i=0; i < InternalDTAs[DTAIndex].nentries; i++)
315: free(InternalDTAs[DTAIndex].found[i]);
316: free(InternalDTAs[DTAIndex].found);
317: InternalDTAs[DTAIndex].found = NULL;
318: }
319: InternalDTAs[DTAIndex].nentries = 0;
1.1.1.15 root 320: InternalDTAs[DTAIndex].bUsed = false;
1.1.1.2 root 321: }
322:
1.1.1.3 root 323:
1.1.1.2 root 324: /*-----------------------------------------------------------------------*/
1.1.1.12 root 325: /**
326: * Match a file to a dir mask.
327: */
1.1.1.2 root 328: static int match (char *pat, char *name)
329: {
1.1.1.9 root 330: char *p=pat, *n=name;
331:
332: if (name[0] == '.')
1.1.1.15 root 333: return false; /* no .* files */
1.1.1.9 root 334: if (strcmp(pat,"*.*")==0)
1.1.1.15 root 335: return true;
1.1.1.9 root 336: if (strcasecmp(pat,name)==0)
1.1.1.15 root 337: return true;
1.1.1.9 root 338:
339: for (;*n;)
1.1.1.2 root 340: {
1.1.1.9 root 341: if (*p=='*')
342: {
343: while (*n && *n != '.')
344: n++;
345: p++;
346: }
347: else
348: {
349: if (*p=='?' && *n)
350: {
351: n++;
352: p++;
353: }
354: else
355: {
356: if (toupper(*p++) != toupper(*n++))
1.1.1.15 root 357: return false;
1.1.1.9 root 358: }
359: }
1.1.1.2 root 360: }
1.1.1.9 root 361:
362: return (*p == 0); /* The name matches the pattern if it ends here, too */
1.1.1.2 root 363: }
364:
1.1.1.9 root 365:
1.1.1.2 root 366: /*-----------------------------------------------------------------------*/
1.1.1.12 root 367: /**
368: * Parse directory from sfirst mask
369: * - e.g.: input: "hdemudir/auto/mask*.*" outputs: "hdemudir/auto"
370: */
1.1.1.15 root 371: static void fsfirst_dirname(char *string, char *newstr)
1.1.1.7 root 372: {
1.1.1.9 root 373: int i=0;
1.1.1.6 root 374:
1.1.1.15 root 375: strcpy(newstr, string);
1.1.1.11 root 376:
1.1.1.15 root 377: /* convert to front slashes and go to end of string. */
378: while (newstr[i] != '\0')
1.1.1.9 root 379: {
1.1.1.15 root 380: if (newstr[i] == '\\')
381: newstr[i] = PATHSEP;
1.1.1.9 root 382: i++;
383: }
1.1.1.15 root 384: /* find last slash and terminate string */
385: while (i && newstr[i] != PATHSEP)
386: i--;
387: newstr[i] = '\0';
1.1 root 388: }
389:
1.1.1.11 root 390:
1.1.1.2 root 391: /*-----------------------------------------------------------------------*/
1.1.1.12 root 392: /**
393: * Parse directory mask, e.g. "*.*"
394: */
1.1.1.15 root 395: static void fsfirst_dirmask(char *string, char *newstr)
1.1.1.7 root 396: {
1.1.1.15 root 397: int i=0;
1.1.1.9 root 398:
399: while (string[i] != '\0')
400: i++; /* go to end of string */
1.1.1.15 root 401: while (i && string[i] != PATHSEP)
1.1.1.9 root 402: i--; /* find last slash */
1.1.1.15 root 403: if (string[i] == PATHSEP)
404: i++;
1.1.1.9 root 405: while (string[i] != '\0')
1.1.1.15 root 406: *newstr++ = string[i++]; /* go to end of string */
407: *newstr = '\0';
1.1.1.2 root 408: }
1.1 root 409:
1.1.1.7 root 410:
1.1.1.2 root 411: /*-----------------------------------------------------------------------*/
1.1.1.12 root 412: /**
413: * Initialize GemDOS/PC file system
414: */
1.1 root 415: void GemDOS_Init(void)
416: {
1.1.1.9 root 417: int i;
1.1.1.15 root 418: bInitGemDOS = false;
1.1.1.2 root 419:
1.1.1.9 root 420: /* Clear handles structure */
421: memset(FileHandles, 0, sizeof(FILE_HANDLE)*MAX_FILE_HANDLES);
422: /* Clear DTAs */
423: for(i=0; i<MAX_DTAS_FILES; i++)
424: {
1.1.1.15 root 425: InternalDTAs[i].bUsed = false;
1.1.1.9 root 426: InternalDTAs[i].nentries = 0;
427: InternalDTAs[i].found = NULL;
428: }
429: DTAIndex = 0;
1.1 root 430: }
431:
1.1.1.9 root 432:
1.1.1.2 root 433: /*-----------------------------------------------------------------------*/
1.1.1.12 root 434: /**
435: * Reset GemDOS file system
436: */
1.1.1.7 root 437: void GemDOS_Reset(void)
1.1 root 438: {
1.1.1.9 root 439: int i;
440:
441: /* Init file handles table */
442: for (i=0; i<MAX_FILE_HANDLES; i++)
443: {
444: /* Was file open? If so close it */
445: if (FileHandles[i].bUsed)
446: fclose(FileHandles[i].FileHandle);
1.1 root 447:
1.1.1.9 root 448: FileHandles[i].FileHandle = NULL;
1.1.1.15 root 449: FileHandles[i].bUsed = false;
1.1.1.9 root 450: }
451:
452: for (DTAIndex = 0; DTAIndex < MAX_DTAS_FILES; DTAIndex++)
453: {
454: ClearInternalDTA();
455: }
456: DTAIndex = 0;
457:
458: /* Reset */
1.1.1.15 root 459: bInitGemDOS = false;
1.1.1.9 root 460: CurrentDrive = nBootDrive;
461: pDTA = NULL;
1.1 root 462: }
463:
1.1.1.15 root 464: /*-----------------------------------------------------------------------*/
465: /**
466: * Routine to check the Host OS HDD path for a Drive letter sub folder
467: */
468: static bool GEMDOS_DoesHostDriveFolderExist(char* lpstrPath, int iDrive)
469: {
470: bool bExist = false;
471:
472: if (access(lpstrPath, F_OK) != 0 )
473: {
474: /* Try lower case drive letter instead */
475: int iIndex = strlen(lpstrPath)-1;
476: lpstrPath[iIndex] = tolower(lpstrPath[iIndex]);
477: }
478:
479: /* Check the file/folder is accessible (security basis) */
480: if (access(lpstrPath, F_OK) == 0 )
481: {
482: /* If its a HDD identifier (or other emulated device) */
483: if (iDrive > 1)
484: {
485: struct stat status;
486: stat( lpstrPath, &status );
487: if ( status.st_mode & S_IFDIR )
488: bExist = true;
489: }
490: }
491:
492: return bExist;
493: }
494:
495: /*-----------------------------------------------------------------------*/
496: /**
497: * Routine to check if any emulated drive is present
498: */
499: #if 0
500: static bool GEMDOS_IsHDDPresent(int iDrive)
501: {
502: bool bPresent = false;
503:
504: if ((iDrive <= nNumDrives) && (iDrive > 1))
505: if (emudrives[iDrive-2])
506: bPresent = true;
507:
508: return bPresent;
509: }
510: #endif
511:
512:
513: /**
1.1.1.16! root 514: * Determine upper limit of partitions that should be emulated.
! 515: *
! 516: * @return true if multiple GEMDOS partitions should be emulated, false otherwise
1.1.1.15 root 517: */
1.1.1.16! root 518: static bool GemDOS_DetermineMaxPartitions(int *pnMaxDrives)
1.1.1.15 root 519: {
520: struct dirent **files;
1.1.1.16! root 521: int count, i;
! 522: bool bMultiPartitions;
! 523:
! 524: *pnMaxDrives = 0;
1.1.1.15 root 525:
526: /* Scan through the main directory to see whether there are just single
527: * letter sub-folders there (then use multi-partition mode) or if
528: * arbitrary sub-folders are there (then use single-partition mode */
529: count = scandir(ConfigureParams.HardDisk.szHardDiskDirectories[0], &files, 0, alphasort);
530: if (count < 0)
531: {
532: perror("GemDOS_DetermineMaxPartitions");
1.1.1.16! root 533: return false;
1.1.1.15 root 534: }
535: else if (count <= 2)
536: {
537: /* Empty directory Only "." and ".."), assume single partition mode */
1.1.1.16! root 538: *pnMaxDrives = 1;
! 539: bMultiPartitions = false;
1.1.1.15 root 540: }
541: else
542: {
1.1.1.16! root 543: bMultiPartitions = true;
1.1.1.15 root 544: /* Check all files in the directory */
545: for (i = 0; i < count; i++)
546: {
547: if (strcmp(files[i]->d_name, ".") == 0 || strcmp(files[i]->d_name, "..") == 0)
548: {
549: /* Ignore "." and ".." */
550: continue;
551: }
552: if (strlen(files[i]->d_name) != 1 || !isalpha(files[i]->d_name[0]))
553: {
554: /* There is a folder with more than one letter...
555: * ... so use single partition mode! */
1.1.1.16! root 556: *pnMaxDrives = 1;
! 557: bMultiPartitions = false;
1.1.1.15 root 558: break;
559: }
1.1.1.16! root 560: *pnMaxDrives = toupper(files[i]->d_name[0]) - 'C' + 1;
1.1.1.15 root 561: }
562: }
563:
1.1.1.16! root 564: if (*pnMaxDrives > MAX_HARDDRIVES)
! 565: *pnMaxDrives = MAX_HARDDRIVES;
1.1.1.15 root 566:
567: /* Free file list */
568: for (i = 0; i < count; i++)
569: free(files[i]);
570: free(files);
571:
1.1.1.16! root 572: return bMultiPartitions;
1.1.1.15 root 573: }
1.1.1.3 root 574:
575: /*-----------------------------------------------------------------------*/
1.1.1.12 root 576: /**
577: * Initialize a GEMDOS drive.
1.1.1.15 root 578: * Supports up to MAX_HARDDRIVES HDD units.
1.1.1.12 root 579: */
1.1.1.7 root 580: void GemDOS_InitDrives(void)
1.1.1.3 root 581: {
1.1.1.9 root 582: int i;
1.1.1.15 root 583: int nMaxDrives;
1.1.1.16! root 584: bool bMultiPartitions;
1.1.1.9 root 585:
586: /* intialize data for harddrive emulation: */
587: if (!GEMDOS_EMU_ON)
588: {
1.1.1.15 root 589: emudrives = malloc(MAX_HARDDRIVES * sizeof(EMULATEDDRIVE *));
590: if (!emudrives)
591: {
592: perror("GemDOS_InitDrives");
593: return;
594: }
595: memset(emudrives, 0, MAX_HARDDRIVES * sizeof(EMULATEDDRIVE *));
1.1.1.9 root 596: }
1.1.1.3 root 597:
1.1.1.16! root 598: bMultiPartitions = GemDOS_DetermineMaxPartitions(&nMaxDrives);
1.1.1.15 root 599:
600: /* Now initialize all available drives */
601: for(i = 0; i < nMaxDrives; i++)
1.1.1.9 root 602: {
1.1.1.15 root 603: // Create the letter equivilent string identifier for this drive
604: char sDriveLetter[] = { PATHSEP, (char)('C' + i), '\0' };
1.1.1.6 root 605:
1.1.1.16! root 606: /* If single partition mode, skip to the right entry */
! 607: if (!bMultiPartitions)
! 608: i += nPartitions;
! 609:
! 610: /* Allocate emudrives entry for this drive */
1.1.1.15 root 611: emudrives[i] = malloc(sizeof(EMULATEDDRIVE));
612: if (!emudrives[i])
613: {
614: perror("GemDOS_InitDrives");
615: continue;
616: }
1.1.1.9 root 617:
1.1.1.15 root 618: /* set drive number (C: = 2, D: = 3, etc.) */
1.1.1.16! root 619: emudrives[i]->hd_letter = 2 + i;
1.1.1.9 root 620:
1.1.1.15 root 621: /* set emulation directory string */
622: strcpy(emudrives[i]->hd_emulation_dir, ConfigureParams.HardDisk.szHardDiskDirectories[0]);
1.1.1.9 root 623:
1.1.1.15 root 624: /* remove trailing slash, if any in the directory name */
625: File_CleanFileName(emudrives[i]->hd_emulation_dir);
1.1.1.9 root 626:
1.1.1.15 root 627: /* Add Requisit Folder ID */
1.1.1.16! root 628: if (bMultiPartitions)
1.1.1.15 root 629: strcat(emudrives[i]->hd_emulation_dir, sDriveLetter);
630:
631: // Check host file system to see if the drive folder for THIS
632: // drive letter/number exists...
633: if (GEMDOS_DoesHostDriveFolderExist(emudrives[i]->hd_emulation_dir,emudrives[i]->hd_letter))
634: {
635: /* initialize current directory string, too (initially the same as hd_emulation_dir) */
636: strcpy(emudrives[i]->fs_currpath, emudrives[i]->hd_emulation_dir);
637: File_AddSlashToEndFileName(emudrives[i]->fs_currpath); /* Needs trailing slash! */
638: /* If the GemDos Drive letter is free then */
639: if (i >= nPartitions)
640: {
641: Log_Printf(LOG_INFO, "Hard drive emulation, %c: <-> %s.\n",
642: emudrives[i]->hd_letter + 'A', emudrives[i]->hd_emulation_dir);
643: nNumDrives = i + 3;
644: }
645: else /* This letter has allready been allocated to the one supported physical disk image */
646: {
647: Log_Printf(LOG_INFO, "Drive Letter %c is already mapped to HDD image (cannot map GEM DOS drive to %s).\n",
648: emudrives[i]->hd_letter + 'A', emudrives[i]->hd_emulation_dir);
649: free(emudrives[i]);
650: emudrives[i] = NULL;
651: }
652: }
653: else
654: {
655: free(emudrives[i]); // Deallocate Memory (save space)
656: emudrives[i] = NULL;
657: }
1.1.1.9 root 658: }
1.1.1.3 root 659: }
660:
1.1.1.6 root 661:
1.1.1.3 root 662: /*-----------------------------------------------------------------------*/
1.1.1.12 root 663: /**
664: * Un-init the GEMDOS drive
665: */
1.1.1.7 root 666: void GemDOS_UnInitDrives(void)
1.1.1.3 root 667: {
1.1.1.9 root 668: int i;
1.1.1.3 root 669:
1.1.1.9 root 670: GemDOS_Reset(); /* Close all open files on emulated drive*/
1.1.1.3 root 671:
1.1.1.9 root 672: if (GEMDOS_EMU_ON)
673: {
674: for(i=0; i<MAX_HARDDRIVES; i++)
675: {
1.1.1.15 root 676: if (emudrives[i])
677: {
678: free(emudrives[i]); /* Release memory */
679: emudrives[i] = NULL;
680: nNumDrives -= 1;
681: }
1.1.1.9 root 682: }
683:
684: free(emudrives);
685: emudrives = NULL;
686: }
1.1.1.3 root 687: }
688:
689:
1.1.1.2 root 690: /*-----------------------------------------------------------------------*/
1.1.1.12 root 691: /**
692: * Save/Restore snapshot of local variables('MemorySnapShot_Store' handles type)
693: */
1.1.1.13 root 694: void GemDOS_MemorySnapShot_Capture(bool bSave)
1.1 root 695: {
1.1.1.9 root 696: unsigned int Addr;
697: int i;
1.1.1.13 root 698: bool bEmudrivesAvailable;
699:
700: /* Save/Restore the emudrives structure */
701: bEmudrivesAvailable = (emudrives != NULL);
702: MemorySnapShot_Store(&bEmudrivesAvailable, sizeof(bEmudrivesAvailable));
703: if (bEmudrivesAvailable)
704: {
705: if (!bSave && !emudrives)
706: {
707: /* We're loading a memory snapshot, but the emudrives
708: * structure has not been malloc yet... let's do it now! */
709: GemDOS_InitDrives();
710: }
711:
712: for(i=0; i<MAX_HARDDRIVES; i++)
713: {
1.1.1.15 root 714: int bDummyDrive = false;
715: if (!emudrives[i])
716: {
717: /* Allocate a dummy drive */
718: emudrives[i] = malloc(sizeof(EMULATEDDRIVE));
719: if (!emudrives[i])
720: perror("GemDOS_MemorySnapShot_Capture");
721: memset(emudrives[i], 0, sizeof(EMULATEDDRIVE));
722: bDummyDrive = true;
723: }
1.1.1.13 root 724: MemorySnapShot_Store(emudrives[i]->hd_emulation_dir,
725: sizeof(emudrives[i]->hd_emulation_dir));
726: MemorySnapShot_Store(emudrives[i]->fs_currpath,
727: sizeof(emudrives[i]->fs_currpath));
728: MemorySnapShot_Store(&emudrives[i]->hd_letter,
729: sizeof(emudrives[i]->hd_letter));
1.1.1.15 root 730: if (bDummyDrive)
731: {
732: free(emudrives[i]);
733: emudrives[i] = NULL;
734: }
1.1.1.13 root 735: }
736: }
1.1 root 737:
1.1.1.9 root 738: /* Save/Restore details */
739: MemorySnapShot_Store(&DTAIndex,sizeof(DTAIndex));
740: MemorySnapShot_Store(&bInitGemDOS,sizeof(bInitGemDOS));
1.1.1.13 root 741: MemorySnapShot_Store(&act_pd, sizeof(act_pd));
1.1.1.9 root 742: if (bSave)
743: {
1.1.1.11 root 744: Addr = ((Uint8 *)pDTA - STRam);
1.1.1.9 root 745: MemorySnapShot_Store(&Addr,sizeof(Addr));
746: }
747: else
748: {
749: MemorySnapShot_Store(&Addr,sizeof(Addr));
750: pDTA = (DTA *)(STRam + Addr);
751: }
752: MemorySnapShot_Store(&CurrentDrive,sizeof(CurrentDrive));
753: /* Don't save file handles as files may have changed which makes
754: it impossible to get a valid handle back */
755: if (!bSave)
756: {
757: /* Clear file handles */
758: for(i=0; i<MAX_FILE_HANDLES; i++)
759: {
760: FileHandles[i].FileHandle = NULL;
1.1.1.15 root 761: FileHandles[i].bUsed = false;
1.1.1.9 root 762: }
763: }
1.1 root 764: }
765:
1.1.1.9 root 766:
1.1.1.2 root 767: /*-----------------------------------------------------------------------*/
1.1.1.12 root 768: /**
769: * Return free PC file handle table index, or -1 if error
770: */
1.1.1.7 root 771: static int GemDOS_FindFreeFileHandle(void)
1.1 root 772: {
1.1.1.9 root 773: int i;
1.1 root 774:
1.1.1.9 root 775: /* Scan our file list for free slot */
776: for(i=0; i<MAX_FILE_HANDLES; i++)
777: {
778: if (!FileHandles[i].bUsed)
779: return i;
780: }
1.1 root 781:
1.1.1.9 root 782: /* Cannot open any more files, return error */
783: return -1;
1.1 root 784: }
785:
1.1.1.2 root 786: /*-----------------------------------------------------------------------*/
1.1.1.12 root 787: /**
788: * Check ST handle is within our table range, return TRUE if not
789: */
1.1.1.13 root 790: static bool GemDOS_IsInvalidFileHandle(int Handle)
1.1 root 791: {
1.1.1.15 root 792: bool bInvalidHandle = false;
1.1 root 793:
1.1.1.9 root 794: /* Check handle was valid with our handle table */
795: if ((Handle < 0) || (Handle >= MAX_FILE_HANDLES))
1.1.1.15 root 796: bInvalidHandle = true;
1.1.1.9 root 797: else if (!FileHandles[Handle].bUsed)
1.1.1.15 root 798: bInvalidHandle = true;
1.1 root 799:
1.1.1.9 root 800: return bInvalidHandle;
1.1 root 801: }
802:
1.1.1.2 root 803: /*-----------------------------------------------------------------------*/
1.1.1.12 root 804: /**
805: * Find drive letter from a filename, eg C,D... and return as drive ID(C:2, D:3...)
806: * returns the current drive number if none is specified.
807: */
1.1.1.7 root 808: static int GemDOS_FindDriveNumber(char *pszFileName)
1.1 root 809: {
1.1.1.9 root 810: /* Does have 'A:' or 'C:' etc.. at start of string? */
811: if ((pszFileName[0] != '\0') && (pszFileName[1] == ':'))
812: {
813: if ((pszFileName[0] >= 'a') && (pszFileName[0] <= 'z'))
814: return (pszFileName[0]-'a');
815: else if ((pszFileName[0] >= 'A') && (pszFileName[0] <= 'Z'))
816: return (pszFileName[0]-'A');
817: }
1.1 root 818:
1.1.1.9 root 819: return CurrentDrive;
1.1 root 820: }
821:
1.1.1.2 root 822: /*-----------------------------------------------------------------------*/
1.1.1.12 root 823: /**
824: * Return drive ID(C:2, D:3 etc...) or -1 if not one of our emulation hard-drives
825: */
1.1.1.7 root 826: static int GemDOS_IsFileNameAHardDrive(char *pszFileName)
1.1 root 827: {
1.1.1.9 root 828: int DriveLetter;
1.1.1.11 root 829: int n;
1.1.1.9 root 830:
831: /* Do we even have a hard-drive? */
832: if (GEMDOS_EMU_ON)
833: {
1.1.1.10 root 834: /* Find drive letter (as number) */
1.1.1.9 root 835: DriveLetter = GemDOS_FindDriveNumber(pszFileName);
1.1.1.15 root 836:
837: /* We've got support for multiple drives here... */
838: if (DriveLetter > 1) // If it is not a Floppy Drive
839: {
840: for (n=0; n<MAX_HARDDRIVES; n++)
841: {
842: /* Check if drive letter matches */
843: if (emudrives[n] && DriveLetter == emudrives[n]->hd_letter)
844: return DriveLetter;
845: }
846: }
1.1.1.11 root 847: }
1.1.1.15 root 848:
1.1.1.10 root 849: /* Not a high-level redirected drive, let TOS handle it */
1.1.1.9 root 850: return -1;
1.1 root 851: }
852:
1.1.1.7 root 853:
854: /*-----------------------------------------------------------------------*/
1.1.1.12 root 855: /**
856: * Returns the length of the basename of the file passed in parameter
857: * (ie the file without extension)
858: */
1.1.1.7 root 859: static int baselen(char *s)
860: {
1.1.1.9 root 861: char *ext = strchr(s,'.');
862: if (ext)
863: return ext-s;
864: return strlen(s);
1.1.1.6 root 865: }
866:
1.1.1.2 root 867: /*-----------------------------------------------------------------------*/
1.1.1.12 root 868: /**
869: * Use hard-drive directory, current ST directory and filename to create full path
870: */
871: void GemDOS_CreateHardDriveFileName(int Drive, const char *pszFileName,
872: char *pszDestName, int nDestNameLen)
1.1 root 873: {
1.1.1.9 root 874: char *s,*start;
1.1.1.2 root 875:
1.1.1.11 root 876: /* Check for valid string */
1.1.1.9 root 877: if (pszFileName[0] == '\0')
1.1.1.11 root 878: return;
879:
880: /* Is it a valid hard drive? */
881: if (Drive < 2)
882: return;
1.1.1.3 root 883:
1.1.1.9 root 884: /* case full filename "C:\foo\bar" */
1.1.1.12 root 885: s = pszDestName;
886: start = NULL;
1.1.1.9 root 887:
888: if (pszFileName[1] == ':')
889: {
1.1.1.12 root 890: snprintf(pszDestName, nDestNameLen, "%s%s",
1.1.1.15 root 891: emudrives[Drive-2]->hd_emulation_dir, File_RemoveFileNameDrive(pszFileName));
1.1.1.9 root 892: }
893: /* case referenced from root: "\foo\bar" */
894: else if (pszFileName[0] == '\\')
895: {
1.1.1.12 root 896: snprintf(pszDestName, nDestNameLen, "%s%s",
1.1.1.15 root 897: emudrives[Drive-2]->hd_emulation_dir, pszFileName);
1.1.1.9 root 898: }
899: /* case referenced from current directory */
900: else
901: {
1.1.1.12 root 902: snprintf(pszDestName, nDestNameLen, "%s%s",
1.1.1.15 root 903: emudrives[Drive-2]->fs_currpath, pszFileName);
904: start = pszDestName + strlen(emudrives[Drive-2]->fs_currpath)-1;
1.1.1.6 root 905: }
1.1.1.9 root 906:
1.1.1.15 root 907: #ifndef _WIN32
1.1.1.9 root 908: /* convert to front slashes. */
909: while((s = strchr(s+1,'\\')))
910: {
911: if (!start)
912: {
913: start = s;
914: continue;
915: }
916: {
917: glob_t globbuf;
1.1.1.12 root 918: char old1, old2;
1.1.1.9 root 919: int len, found, base_len;
920: unsigned int j;
921:
1.1.1.12 root 922: *start++ = PATHSEP;
1.1.1.9 root 923: old1 = *start;
924: *start++ = '*';
925: old2 = *start;
926: *start = 0;
927: glob(pszDestName,GLOB_ONLYDIR,NULL,&globbuf);
928: *start-- = old2;
929: *start = old1;
930: *s = 0;
931: len = strlen(pszDestName);
932: base_len = baselen(start);
933: found = 0;
1.1.1.15 root 934: // Handle long file names
1.1.1.9 root 935: for (j=0; j<globbuf.gl_pathc; j++)
936: {
937: /* If we search for a file of at least 8 characters, then it might
938: be a longer filename since the ST can access only the first 8
939: characters. If not, then it's a precise match (with case). */
940: if (!(base_len < 8 ? strcasecmp(globbuf.gl_pathv[j],pszDestName) :
941: strncasecmp(globbuf.gl_pathv[j],pszDestName,len)))
942: {
943: /* we found a matching name... */
1.1.1.12 root 944: snprintf(pszDestName, nDestNameLen, "%s%c%s",
945: globbuf.gl_pathv[j], PATHSEP, s+1);
1.1.1.9 root 946: j = globbuf.gl_pathc;
947: found = 1;
948: }
1.1.1.13 root 949: /* Here comes a work-around for a bug in the file selector
950: * of TOS 1.02: When a folder name has exactly 8 characters,
951: * it appends a '.' at the end of the name... */
952: else if (base_len == 8 && pszDestName[len-1] == '.' &&
953: !strncasecmp(globbuf.gl_pathv[j],pszDestName,len-1))
954: {
955: /* we found a matching name... */
956: snprintf(pszDestName, nDestNameLen, "%s%c%s",
957: globbuf.gl_pathv[j], PATHSEP, s+1);
958: s -= 1;
959: j = globbuf.gl_pathc; /* break */
960: found = 1;
961: }
1.1.1.9 root 962: }
963: globfree(&globbuf);
964: if (!found)
965: {
966: /* didn't find it. Let's try normal files (it might be a symlink) */
967: *start++ = '*';
968: *start = 0;
969: glob(pszDestName,0,NULL,&globbuf);
970: *start-- = old2;
971: *start = old1;
972: for (j=0; j<globbuf.gl_pathc; j++)
973: {
974: if (!strncasecmp(globbuf.gl_pathv[j],pszDestName,len))
975: {
976: /* we found a matching name... */
1.1.1.12 root 977: snprintf(pszDestName, nDestNameLen, "%s%c%s",
978: globbuf.gl_pathv[j], PATHSEP, s+1);
1.1.1.9 root 979: j = globbuf.gl_pathc;
980: found = 1;
981: }
982: }
983: globfree(&globbuf);
984: if (!found)
985: { /* really nothing ! */
1.1.1.12 root 986: *s = PATHSEP;
1.1.1.9 root 987: fprintf(stderr,"no path for %s\n",pszDestName);
988: }
989: }
990: }
991: start = s;
992: }
1.1.1.15 root 993: #endif
1.1.1.9 root 994: if (!start)
1.1.1.12 root 995: start = strrchr(pszDestName, PATHSEP); // path already converted ?
1.1.1.9 root 996:
997: if (start)
998: {
1.1.1.12 root 999: *start++ = PATHSEP; /* in case there was only 1 anti slash */
1.1.1.9 root 1000: if (*start && !strchr(start,'?') && !strchr(start,'*'))
1001: {
1002: /* We have a complete name after the path, not a wildcard */
1003: glob_t globbuf;
1004: char old1,old2;
1005: int len, found, base_len;
1006: unsigned int j;
1007:
1008: old1 = *start;
1009: *start++ = '*';
1010: old2 = *start;
1011: *start = 0;
1012: glob(pszDestName,0,NULL,&globbuf);
1013: *start-- = old2;
1014: *start = old1;
1015: len = strlen(pszDestName);
1016: base_len = baselen(start);
1017: found = 0;
1018: for (j=0; j<globbuf.gl_pathc; j++)
1019: {
1020: /* If we search for a file of at least 8 characters, then it might
1021: be a longer filename since the ST can access only the first 8
1022: characters. If not, then it's a precise match (with case). */
1023: if (!(base_len < 8 ? strcasecmp(globbuf.gl_pathv[j],pszDestName) :
1024: strncasecmp(globbuf.gl_pathv[j],pszDestName,len)))
1025: {
1026: /* we found a matching name... */
1.1.1.12 root 1027: strncpy(pszDestName, globbuf.gl_pathv[j], nDestNameLen);
1.1.1.9 root 1028: j = globbuf.gl_pathc;
1029: found = 1;
1030: }
1031: }
1.1.1.15 root 1032: #if ENABLE_TRACING
1.1.1.9 root 1033: if (!found)
1034: {
1035: /* It's often normal, the gem uses this to test for existence */
1036: /* of desktop.inf or newdesk.inf for example. */
1.1.1.15 root 1037: LOG_TRACE(TRACE_OS_GEMDOS, "didn't find filename %s\n", pszDestName );
1.1.1.9 root 1038: }
1.1.1.6 root 1039: #endif
1.1.1.9 root 1040: globfree(&globbuf);
1041: }
1042: }
1.1.1.15 root 1043: LOG_TRACE(TRACE_OS_GEMDOS, "conv %s -> %s\n", pszFileName, pszDestName );
1.1 root 1044: }
1045:
1.1.1.6 root 1046:
1.1.1.2 root 1047: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1048: /**
1049: * GEMDOS Cauxin
1050: * Call 0x3
1051: */
1.1.1.7 root 1052: #if 0
1.1.1.13 root 1053: static bool GemDOS_Cauxin(Uint32 Params)
1.1 root 1054: {
1.1.1.11 root 1055: unsigned char c;
1.1 root 1056:
1.1.1.9 root 1057: /* Wait here until a character is ready */
1058: while(!RS232_GetStatus())
1059: ;
1.1 root 1060:
1.1.1.9 root 1061: /* And read character */
1.1.1.11 root 1062: RS232_ReadBytes(&c,1);
1063: Regs[REG_D0] = c;
1.1 root 1064:
1.1.1.15 root 1065: LOG_TRACE(TRACE_OS_GEMDOS, "GEMDOS Cauxin() = 0x%x\n", (int)c);
1066:
1067: return true;
1.1 root 1068: }
1.1.1.7 root 1069: #endif
1.1 root 1070:
1.1.1.2 root 1071: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1072: /**
1073: * GEMDOS Cauxout
1074: * Call 0x4
1075: */
1.1.1.7 root 1076: #if 0
1.1.1.13 root 1077: static bool GemDOS_Cauxout(Uint32 Params)
1.1 root 1078: {
1.1.1.11 root 1079: unsigned char c;
1.1 root 1080:
1.1.1.15 root 1081: /* Get character from the stack */
1.1.1.11 root 1082: c = STMemory_ReadWord(Params+SIZE_WORD);
1.1.1.15 root 1083:
1084: LOG_TRACE(TRACE_OS_GEMDOS, "GEMDOS Cauxout(0x%x)\n", (int)c);
1085:
1086: /* Send character to RS232 */
1.1.1.11 root 1087: RS232_TransferBytesTo(&c, 1);
1.1 root 1088:
1.1.1.15 root 1089: return true;
1.1 root 1090: }
1.1.1.7 root 1091: #endif
1.1 root 1092:
1.1.1.2 root 1093: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1094: /**
1095: * GEMDOS Cprnout
1096: * Call 0x5
1097: */
1.1.1.13 root 1098: #if 0
1099: static bool GemDOS_Cprnout(Uint32 Params)
1.1 root 1100: {
1.1.1.11 root 1101: unsigned char c;
1.1 root 1102:
1.1.1.9 root 1103: /* Send character to printer(or file) */
1.1.1.11 root 1104: c = STMemory_ReadWord(Params+SIZE_WORD);
1.1.1.15 root 1105: LOG_TRACE(TRACE_OS_GEMDOS, "GEMDOS Cprnout(0x%x)\n", (int)c);
1.1.1.11 root 1106: Printer_TransferByteTo(c);
1.1.1.9 root 1107: Regs[REG_D0] = -1; /* Printer OK */
1.1 root 1108:
1.1.1.15 root 1109: return true;
1.1 root 1110: }
1.1.1.13 root 1111: #endif
1.1 root 1112:
1.1.1.2 root 1113: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1114: /**
1115: * GEMDOS Set drive (0=A,1=B,2=C etc...)
1116: * Call 0xE
1117: */
1.1.1.13 root 1118: static bool GemDOS_SetDrv(Uint32 Params)
1.1 root 1119: {
1.1.1.9 root 1120: /* Read details from stack for our own use */
1121: CurrentDrive = STMemory_ReadWord(Params+SIZE_WORD);
1.1 root 1122:
1.1.1.15 root 1123: LOG_TRACE(TRACE_OS_GEMDOS, "GEMDOS Dsetdrv(0x%x)\n", (int)CurrentDrive);
1124:
1.1.1.9 root 1125: /* Still re-direct to TOS */
1.1.1.15 root 1126: return false;
1.1 root 1127: }
1128:
1.1.1.2 root 1129: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1130: /**
1131: * GEMDOS Cprnos
1132: * Call 0x11
1133: */
1.1.1.13 root 1134: #if 0
1135: static bool GemDOS_Cprnos(Uint32 Params)
1.1 root 1136: {
1.1.1.13 root 1137: /* printer status depends if printing is enabled or not... */
1.1.1.9 root 1138: if (ConfigureParams.Printer.bEnablePrinting)
1139: Regs[REG_D0] = -1; /* Printer OK */
1140: else
1141: Regs[REG_D0] = 0; /* printer not ready if printing disabled */
1.1 root 1142:
1.1.1.15 root 1143: LOG_TRACE(TRACE_OS_GEMDOS, "GEMDOS Cprnos() = 0x%x\n", Regs[REG_D0]);
1144:
1145: return true;
1.1 root 1146: }
1.1.1.13 root 1147: #endif
1.1 root 1148:
1.1.1.2 root 1149: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1150: /**
1151: * GEMDOS Cauxis
1152: * Call 0x12
1153: */
1.1.1.7 root 1154: #if 0
1.1.1.13 root 1155: static bool GemDOS_Cauxis(Uint32 Params)
1.1 root 1156: {
1.1.1.9 root 1157: /* Read our RS232 state */
1158: if (RS232_GetStatus())
1159: Regs[REG_D0] = -1; /* Chars waiting */
1160: else
1161: Regs[REG_D0] = 0;
1.1 root 1162:
1.1.1.15 root 1163: LOG_TRACE(TRACE_OS_GEMDOS, "GEMDOS Cauxis() = 0x%x\n", Regs[REG_D0]);
1164:
1165: return true;
1.1 root 1166: }
1.1.1.7 root 1167: #endif
1.1 root 1168:
1.1.1.2 root 1169: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1170: /**
1171: * GEMDOS Cauxos
1172: * Call 0x13
1173: */
1.1.1.7 root 1174: #if 0
1.1.1.13 root 1175: static bool GemDOS_Cauxos(Uint32 Params)
1.1 root 1176: {
1.1.1.9 root 1177: Regs[REG_D0] = -1; /* Device ready */
1.1 root 1178:
1.1.1.15 root 1179: LOG_TRACE(TRACE_OS_GEMDOS, "GEMDOS Cauxos() = 0x%x\n", Regs[REG_D0]);
1180:
1181: return true;
1.1 root 1182: }
1.1.1.7 root 1183: #endif
1.1 root 1184:
1.1.1.2 root 1185: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1186: /**
1187: * GEMDOS Set Disk Transfer Address (DTA)
1188: * Call 0x1A
1189: */
1.1.1.13 root 1190: static bool GemDOS_SetDTA(Uint32 Params)
1.1 root 1191: {
1.1.1.15 root 1192: Uint32 nDTA = STMemory_ReadLong(Params+SIZE_WORD);
1193:
1194: LOG_TRACE(TRACE_OS_GEMDOS, "GEMDOS Fsetdta(0x%x)\n", nDTA);
1195:
1.1.1.9 root 1196: /* Look up on stack to find where DTA is! Store as PC pointer */
1.1.1.15 root 1197: pDTA = (DTA *)STRAM_ADDR(nDTA);
1.1 root 1198:
1.1.1.15 root 1199: return false;
1.1 root 1200: }
1201:
1.1.1.2 root 1202: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1203: /**
1204: * GEMDOS Dfree Free disk space.
1.1.1.15 root 1205: * Call 0x36
1.1.1.12 root 1206: */
1.1.1.13 root 1207: static bool GemDOS_DFree(Uint32 Params)
1.1.1.2 root 1208: {
1.1.1.9 root 1209: int Drive;
1.1.1.10 root 1210: Uint32 Address;
1.1.1.9 root 1211:
1.1.1.10 root 1212: Address = STMemory_ReadLong(Params+SIZE_WORD);
1.1.1.9 root 1213: Drive = STMemory_ReadWord(Params+SIZE_WORD+SIZE_LONG);
1.1.1.15 root 1214:
1215: LOG_TRACE(TRACE_OS_GEMDOS, "GEMDOS Dfree(0x%x, %i)\n", Address, Drive);
1216:
1.1.1.9 root 1217: /* is it our drive? */
1218: if ((Drive == 0 && CurrentDrive >= 2) || Drive >= 3)
1219: {
1220: /* FIXME: Report actual free drive space */
1221:
1222: STMemory_WriteLong(Address, 10*2048); /* free clusters (mock 10 Mb) */
1223: STMemory_WriteLong(Address+SIZE_LONG, 50*2048 ); /* total clusters (mock 50 Mb) */
1.1.1.2 root 1224:
1.1.1.9 root 1225: STMemory_WriteLong(Address+SIZE_LONG*2, 512 ); /* bytes per sector */
1226: STMemory_WriteLong(Address+SIZE_LONG*3, 1 ); /* sectors per cluster */
1.1.1.15 root 1227: return true;
1.1.1.9 root 1228: }
1229: else
1.1.1.15 root 1230: return false; /* redirect to TOS */
1.1.1.2 root 1231: }
1232:
1233: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1234: /**
1235: * GEMDOS MkDir
1236: * Call 0x39
1237: */
1.1.1.13 root 1238: static bool GemDOS_MkDir(Uint32 Params)
1.1.1.6 root 1239: {
1.1.1.9 root 1240: char *pDirName;
1241: int Drive;
1242:
1243: /* Find directory to make */
1244: pDirName = (char *)STRAM_ADDR(STMemory_ReadLong(Params+SIZE_WORD));
1245:
1.1.1.15 root 1246: LOG_TRACE(TRACE_OS_GEMDOS, "GEMDOS Dcreate(\"%s\")\n", pDirName);
1247:
1.1.1.9 root 1248: Drive = GemDOS_IsFileNameAHardDrive(pDirName);
1249:
1250: if (ISHARDDRIVE(Drive))
1251: {
1.1.1.12 root 1252: char *psDirPath;
1253: psDirPath = malloc(FILENAME_MAX);
1254: if (!psDirPath)
1255: {
1256: perror("GemDOS_MkDir");
1257: Regs[REG_D0] = GEMDOS_ENSMEM;
1.1.1.15 root 1258: return true;
1.1.1.12 root 1259: }
1260:
1.1.1.9 root 1261: /* Copy old directory, as if calls fails keep this one */
1.1.1.12 root 1262: GemDOS_CreateHardDriveFileName(Drive, pDirName, psDirPath, FILENAME_MAX);
1.1.1.9 root 1263:
1264: /* Attempt to make directory */
1.1.1.12 root 1265: if (mkdir(psDirPath, 0755) == 0)
1.1.1.9 root 1266: Regs[REG_D0] = GEMDOS_EOK;
1267: else
1268: Regs[REG_D0] = GEMDOS_EACCDN; /* Access denied */
1269:
1.1.1.12 root 1270: free(psDirPath);
1.1.1.15 root 1271: return true;
1.1.1.9 root 1272: }
1.1.1.15 root 1273: return false;
1.1 root 1274: }
1275:
1.1.1.2 root 1276: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1277: /**
1278: * GEMDOS RmDir
1279: * Call 0x3A
1280: */
1.1.1.13 root 1281: static bool GemDOS_RmDir(Uint32 Params)
1.1.1.6 root 1282: {
1.1.1.9 root 1283: char *pDirName;
1284: int Drive;
1285:
1286: /* Find directory to make */
1287: pDirName = (char *)STRAM_ADDR(STMemory_ReadLong(Params+SIZE_WORD));
1.1.1.15 root 1288:
1289: LOG_TRACE(TRACE_OS_GEMDOS, "GEMDOS Ddelete(\"%s\")\n", pDirName);
1290:
1.1.1.9 root 1291: Drive = GemDOS_IsFileNameAHardDrive(pDirName);
1.1.1.15 root 1292:
1.1.1.9 root 1293: if (ISHARDDRIVE(Drive))
1294: {
1.1.1.12 root 1295: char *psDirPath;
1296: psDirPath = malloc(FILENAME_MAX);
1297: if (!psDirPath)
1298: {
1299: perror("GemDOS_RmDir");
1300: Regs[REG_D0] = GEMDOS_ENSMEM;
1.1.1.15 root 1301: return true;
1.1.1.12 root 1302: }
1303:
1.1.1.9 root 1304: /* Copy old directory, as if calls fails keep this one */
1.1.1.12 root 1305: GemDOS_CreateHardDriveFileName(Drive, pDirName, psDirPath, FILENAME_MAX);
1.1.1.9 root 1306:
1307: /* Attempt to make directory */
1.1.1.12 root 1308: if (rmdir(psDirPath) == 0)
1.1.1.9 root 1309: Regs[REG_D0] = GEMDOS_EOK;
1310: else
1311: Regs[REG_D0] = GEMDOS_EACCDN; /* Access denied */
1312:
1.1.1.12 root 1313: free(psDirPath);
1.1.1.15 root 1314: return true;
1.1.1.9 root 1315: }
1.1.1.15 root 1316: return false;
1.1 root 1317: }
1318:
1.1.1.11 root 1319:
1.1.1.2 root 1320: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1321: /**
1322: * GEMDOS ChDir
1323: * Call 0x3B
1324: */
1.1.1.13 root 1325: static bool GemDOS_ChDir(Uint32 Params)
1.1.1.6 root 1326: {
1.1.1.9 root 1327: char *pDirName;
1328: int Drive;
1.1 root 1329:
1.1.1.9 root 1330: /* Find new directory */
1331: pDirName = (char *)STRAM_ADDR(STMemory_ReadLong(Params+SIZE_WORD));
1.1.1.3 root 1332:
1.1.1.15 root 1333: LOG_TRACE(TRACE_OS_GEMDOS, "GEMDOS Dsetpath(\"%s\")\n", pDirName);
1.1.1.3 root 1334:
1.1.1.9 root 1335: Drive = GemDOS_IsFileNameAHardDrive(pDirName);
1.1.1.3 root 1336:
1.1.1.9 root 1337: if (ISHARDDRIVE(Drive))
1338: {
1339: struct stat buf;
1.1.1.11 root 1340: char *psTempDirPath;
1.1.1.3 root 1341:
1.1.1.11 root 1342: /* Allocate temporary memory for path name: */
1343: psTempDirPath = malloc(FILENAME_MAX);
1344: if (!psTempDirPath)
1345: {
1346: perror("GemDOS_ChDir");
1347: Regs[REG_D0] = GEMDOS_ENSMEM;
1.1.1.15 root 1348: return true;
1.1.1.11 root 1349: }
1350:
1.1.1.12 root 1351: GemDOS_CreateHardDriveFileName(Drive, pDirName, psTempDirPath, FILENAME_MAX);
1.1.1.15 root 1352:
1353: // Remove trailing slashes (stat on Windows does not like that)
1354: File_CleanFileName(psTempDirPath);
1355:
1.1.1.11 root 1356: if (stat(psTempDirPath, &buf))
1357: {
1358: /* error */
1359: free(psTempDirPath);
1.1.1.9 root 1360: Regs[REG_D0] = GEMDOS_EPTHNF;
1.1.1.15 root 1361: return true;
1.1.1.9 root 1362: }
1363:
1.1.1.11 root 1364: File_AddSlashToEndFileName(psTempDirPath);
1365: File_MakeAbsoluteName(psTempDirPath);
1.1.1.9 root 1366:
1.1.1.15 root 1367: /* Prevent '..' commands moving BELOW the root HDD folder */
1368: /* by double checking if path is valid */
1369: if (strncmp(psTempDirPath, emudrives[Drive-2]->hd_emulation_dir,
1370: strlen(emudrives[Drive-2]->hd_emulation_dir)) == 0)
1371: {
1372: strcpy(emudrives[Drive-2]->fs_currpath, psTempDirPath);
1373: Regs[REG_D0] = GEMDOS_EOK;
1374: }
1375: else
1376: {
1377: Regs[REG_D0] = GEMDOS_EPTHNF;
1378: }
1.1.1.11 root 1379: free(psTempDirPath);
1.1.1.9 root 1380:
1.1.1.15 root 1381: return true;
1.1.1.9 root 1382: }
1.1.1.6 root 1383:
1.1.1.15 root 1384: return false;
1.1 root 1385: }
1386:
1.1.1.11 root 1387:
1.1.1.2 root 1388: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1389: /**
1390: * GEMDOS Create file
1391: * Call 0x3C
1392: */
1.1.1.13 root 1393: static bool GemDOS_Create(Uint32 Params)
1.1 root 1394: {
1.1.1.11 root 1395: char szActualFileName[MAX_GEMDOS_PATH];
1.1.1.12 root 1396: char *pszFileName, *ptr;
1.1.1.9 root 1397: int Drive,Index,Mode;
1.1.1.12 root 1398: const char *rwflags;
1.1.1.9 root 1399:
1400: /* Find filename */
1401: pszFileName = (char *)STRAM_ADDR(STMemory_ReadLong(Params+SIZE_WORD));
1402: Mode = STMemory_ReadWord(Params+SIZE_WORD+SIZE_LONG);
1.1.1.15 root 1403:
1404: LOG_TRACE(TRACE_OS_GEMDOS, "GEMDOS Fcreate(\"%s\", 0x%x)\n", pszFileName, Mode);
1405:
1.1.1.9 root 1406: Drive = GemDOS_IsFileNameAHardDrive(pszFileName);
1.1.1.15 root 1407:
1.1.1.12 root 1408: if (!ISHARDDRIVE(Drive))
1.1.1.9 root 1409: {
1.1.1.15 root 1410: return false;
1.1.1.12 root 1411: }
1.1.1.9 root 1412:
1.1.1.12 root 1413: if (Mode == GEMDOS_FILE_ATTRIB_VOLUME_LABEL)
1414: {
1415: fprintf(stderr, "Warning: Hatari doesn't support GEMDOS volume"
1416: " label setting\n(for '%s')\n", pszFileName);
1417: Regs[REG_D0] = GEMDOS_EFILNF; /* File not found */
1.1.1.15 root 1418: return true;
1.1.1.12 root 1419: }
1.1 root 1420:
1.1.1.12 root 1421: /* Now convert to hard drive filename */
1422: GemDOS_CreateHardDriveFileName(Drive, pszFileName,
1423: szActualFileName, sizeof(szActualFileName));
1424:
1425: /* Find slot to store file handle, as need to return WORD handle for ST */
1426: Index = GemDOS_FindFreeFileHandle();
1427: if (Index==-1)
1428: {
1429: /* No free handles, return error code */
1430: Regs[REG_D0] = GEMDOS_ENHNDL; /* No more handles */
1.1.1.15 root 1431: return true;
1.1.1.12 root 1432: }
1433: #ifdef ENABLE_SAVING
1434: /* FIXME: implement other Mode attributes
1435: * - GEMDOS_FILE_ATTRIB_HIDDEN (FA_HIDDEN)
1436: * - GEMDOS_FILE_ATTRIB_SYSTEM_FILE (FA_SYSTEM)
1437: * - GEMDOS_FILE_ATTRIB_SUBDIRECTORY (FA_DIR)
1438: * - GEMDOS_FILE_ATTRIB_WRITECLOSE (FA_ARCHIVE)
1439: * (set automatically by GemDOS >= 0.15)
1440: */
1441: if (Mode & GEMDOS_FILE_ATTRIB_READONLY)
1442: rwflags = "wb";
1443: else
1444: rwflags = "wb+";
1445: FileHandles[Index].FileHandle = fopen(szActualFileName, rwflags);
1.1.1.15 root 1446:
1.1.1.12 root 1447: if (FileHandles[Index].FileHandle != NULL)
1448: {
1449: /* Tag handle table entry as used and return handle */
1.1.1.15 root 1450: FileHandles[Index].bUsed = true;
1.1.1.12 root 1451: Regs[REG_D0] = Index+BASE_FILEHANDLE; /* Return valid ST file handle from range 6 to 45! (ours start from 0) */
1.1.1.15 root 1452: return true;
1.1.1.12 root 1453: }
1.1.1.2 root 1454:
1.1.1.12 root 1455: /* We failed to create the file... now we have to return the right
1456: * error code: Normally we return FILE-NOT-FOUND, but in case the
1457: * directory did not exist yet, we have to return PATH-NOT-FOUND
1458: * (ST-Zip 2.6 relies on that during extraction of ZIP files). */
1459: ptr = strrchr(szActualFileName, PATHSEP);
1460: if (ptr)
1461: {
1462: *ptr = 0; /* Strip filename from string */
1463: if (!File_DirectoryExists(szActualFileName))
1464: {
1465: Regs[REG_D0] = GEMDOS_EPTHNF; /* Path not found */
1.1.1.15 root 1466: return true;
1.1.1.9 root 1467: }
1468: }
1.1.1.12 root 1469: #endif
1470: Regs[REG_D0] = GEMDOS_EFILNF; /* File not found */
1.1.1.15 root 1471: return true;
1.1 root 1472: }
1473:
1.1.1.2 root 1474: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1475: /**
1476: * GEMDOS Open file
1477: * Call 0x3D
1478: */
1.1.1.13 root 1479: static bool GemDOS_Open(Uint32 Params)
1.1 root 1480: {
1.1.1.11 root 1481: char szActualFileName[MAX_GEMDOS_PATH];
1.1.1.9 root 1482: char *pszFileName;
1483: const char *open_modes[] =
1.1.1.12 root 1484: { /* convert atari modes to stdio modes */
1485: "rb", /* read only */
1486: "rb+", /* FIXME: should be write only, but "wb" truncates */
1.1.1.15 root 1487: "rb+", /* read/write */
1.1.1.12 root 1488: "rb" /* read only */
1489: };
1.1.1.9 root 1490: int Drive,Index,Mode;
1491:
1492: /* Find filename */
1493: pszFileName = (char *)STRAM_ADDR(STMemory_ReadLong(Params+SIZE_WORD));
1494: Mode = STMemory_ReadWord(Params+SIZE_WORD+SIZE_LONG);
1.1.1.15 root 1495:
1496: LOG_TRACE(TRACE_OS_GEMDOS, "GEMDOS Fopen(\"%s\", 0x%x)\n", pszFileName, Mode);
1497:
1.1.1.9 root 1498: Drive = GemDOS_IsFileNameAHardDrive(pszFileName);
1499:
1.1.1.12 root 1500: if (!ISHARDDRIVE(Drive))
1.1.1.9 root 1501: {
1.1.1.15 root 1502: return false;
1.1.1.12 root 1503: }
1504: /* And convert to hard drive filename */
1505: GemDOS_CreateHardDriveFileName(Drive, pszFileName,
1506: szActualFileName, sizeof(szActualFileName));
1507:
1508: /* Find slot to store file handle, as need to return WORD handle for ST */
1509: Index = GemDOS_FindFreeFileHandle();
1510: if (Index == -1)
1511: {
1512: /* No free handles, return error code */
1513: Regs[REG_D0] = GEMDOS_ENHNDL; /* No more handles */
1.1.1.15 root 1514: return true;
1.1.1.9 root 1515: }
1.1.1.6 root 1516:
1.1.1.12 root 1517: /* FIXME: Open file
1518: * - fopen() modes don't allow write-only mode without truncating.
1519: * Fixing this requires using open() and file descriptors instead
1520: * of fopen() and FILE* pointers, but Windows doesn't support that
1521: */
1522: FileHandles[Index].FileHandle = fopen(szActualFileName, open_modes[Mode&0x03]);
1.1.1.15 root 1523:
1.1.1.12 root 1524: snprintf(FileHandles[Index].szActualName, sizeof(FileHandles[Index].szActualName),
1525: "%s", szActualFileName);
1.1.1.15 root 1526:
1.1.1.12 root 1527: if (FileHandles[Index].FileHandle != NULL)
1528: {
1529: /* Tag handle table entry as used and return handle */
1.1.1.15 root 1530: FileHandles[Index].bUsed = true;
1.1.1.12 root 1531: Regs[REG_D0] = Index+BASE_FILEHANDLE; /* Return valid ST file handle from range 6 to 45! (ours start from 0) */
1.1.1.15 root 1532: return true;
1.1.1.12 root 1533: }
1.1.1.15 root 1534:
1.1.1.12 root 1535: if (Mode != 1 && errno == EACCES)
1.1.1.15 root 1536: LOG_TRACE(TRACE_OS_GEMDOS, "Missing permission to read file '%s'\n", szActualFileName );
1537:
1.1.1.12 root 1538: Regs[REG_D0] = GEMDOS_EFILNF; /* File not found/ error opening */
1.1.1.15 root 1539: return true;
1.1 root 1540: }
1541:
1.1.1.2 root 1542: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1543: /**
1544: * GEMDOS Close file
1545: * Call 0x3E
1546: */
1.1.1.13 root 1547: static bool GemDOS_Close(Uint32 Params)
1.1 root 1548: {
1.1.1.9 root 1549: int Handle;
1.1 root 1550:
1.1.1.9 root 1551: /* Find our handle - may belong to TOS */
1552: Handle = STMemory_ReadWord(Params+SIZE_WORD)-BASE_FILEHANDLE;
1.1 root 1553:
1.1.1.15 root 1554: LOG_TRACE(TRACE_OS_GEMDOS, "GEMDOS Fclose(%i)\n", Handle);
1555:
1.1.1.9 root 1556: /* Check handle was valid */
1557: if (GemDOS_IsInvalidFileHandle(Handle))
1558: {
1559: /* No assume was TOS */
1.1.1.15 root 1560: return false;
1.1.1.9 root 1561: }
1562: else
1563: {
1564: /* Close file and free up handle table */
1565: fclose(FileHandles[Handle].FileHandle);
1.1.1.15 root 1566: FileHandles[Handle].bUsed = false;
1.1.1.9 root 1567: /* Return no error */
1568: Regs[REG_D0] = GEMDOS_EOK;
1.1.1.15 root 1569: return true;
1.1.1.9 root 1570: }
1.1 root 1571: }
1572:
1.1.1.2 root 1573: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1574: /**
1575: * GEMDOS Read file
1576: * Call 0x3F
1577: */
1.1.1.13 root 1578: static bool GemDOS_Read(Uint32 Params)
1.1 root 1579: {
1.1.1.9 root 1580: char *pBuffer;
1581: unsigned long nBytesRead,Size,CurrentPos,FileSize;
1582: long nBytesLeft;
1583: int Handle;
1584:
1585: /* Read details from stack */
1586: Handle = STMemory_ReadWord(Params+SIZE_WORD)-BASE_FILEHANDLE;
1587: Size = STMemory_ReadLong(Params+SIZE_WORD+SIZE_WORD);
1588: pBuffer = (char *)STRAM_ADDR(STMemory_ReadLong(Params+SIZE_WORD+SIZE_WORD+SIZE_LONG));
1589:
1.1.1.15 root 1590: LOG_TRACE(TRACE_OS_GEMDOS, "GEMDOS Fread(%i, %li, 0x%x)\n",
1591: Handle, Size, STMemory_ReadLong(Params+SIZE_WORD+SIZE_WORD+SIZE_LONG));
1592:
1.1.1.9 root 1593: /* Check handle was valid */
1594: if (GemDOS_IsInvalidFileHandle(Handle))
1595: {
1596: /* No - assume was TOS */
1.1.1.15 root 1597: return false;
1.1.1.9 root 1598: }
1599: else
1600: {
1601:
1602: /* To quick check to see where our file pointer is and how large the file is */
1603: CurrentPos = ftell(FileHandles[Handle].FileHandle);
1604: fseek(FileHandles[Handle].FileHandle, 0, SEEK_END);
1605: FileSize = ftell(FileHandles[Handle].FileHandle);
1606: fseek(FileHandles[Handle].FileHandle, CurrentPos, SEEK_SET);
1607:
1608: nBytesLeft = FileSize-CurrentPos;
1609:
1610: /* Check for End Of File */
1611: if (nBytesLeft == 0)
1612: {
1613: /* FIXME: should we return zero (bytes read) or an error? */
1614: Regs[REG_D0] = 0;
1.1.1.15 root 1615: return true;
1.1.1.9 root 1616: }
1617: else
1618: {
1619: /* Limit to size of file to prevent errors */
1620: if (Size > FileSize)
1621: Size = FileSize;
1622: /* And read data in */
1623: nBytesRead = fread(pBuffer, 1, Size, FileHandles[Handle].FileHandle);
1624:
1625: /* Return number of bytes read */
1626: Regs[REG_D0] = nBytesRead;
1627:
1.1.1.15 root 1628: return true;
1.1.1.9 root 1629: }
1630: }
1.1 root 1631: }
1632:
1.1.1.2 root 1633: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1634: /**
1635: * GEMDOS Write file
1636: * Call 0x40
1637: */
1.1.1.13 root 1638: static bool GemDOS_Write(Uint32 Params)
1.1 root 1639: {
1.1.1.9 root 1640: char *pBuffer;
1641: unsigned long Size,nBytesWritten;
1642: int Handle;
1.1 root 1643:
1.1.1.9 root 1644: /* Read details from stack */
1645: Handle = STMemory_ReadWord(Params+SIZE_WORD)-BASE_FILEHANDLE;
1646: Size = STMemory_ReadLong(Params+SIZE_WORD+SIZE_WORD);
1647: pBuffer = (char *)STRAM_ADDR(STMemory_ReadLong(Params+SIZE_WORD+SIZE_WORD+SIZE_LONG));
1648:
1.1.1.15 root 1649: LOG_TRACE(TRACE_OS_GEMDOS, "GEMDOS Fwrite(%i, %li, 0x%x)\n",
1650: Handle, Size, STMemory_ReadLong(Params+SIZE_WORD+SIZE_WORD+SIZE_LONG));
1651:
1652: #ifdef ENABLE_SAVING
1.1.1.10 root 1653: /* Check if handle was not invalid */
1654: if (!GemDOS_IsInvalidFileHandle(Handle))
1.1.1.9 root 1655: {
1656: nBytesWritten = fwrite(pBuffer, 1, Size, FileHandles[Handle].FileHandle);
1.1.1.11 root 1657: if (ferror(FileHandles[Handle].FileHandle))
1.1.1.9 root 1658: {
1.1.1.11 root 1659: Regs[REG_D0] = GEMDOS_EACCDN; /* Access denied(ie read-only) */
1.1.1.9 root 1660: }
1661: else
1.1.1.11 root 1662: {
1.1.1.9 root 1663:
1.1.1.11 root 1664: Regs[REG_D0] = nBytesWritten; /* OK */
1665: }
1.1.1.15 root 1666: return true;
1.1.1.9 root 1667: }
1.1 root 1668: #endif
1669:
1.1.1.15 root 1670: return false;
1.1 root 1671: }
1672:
1.1.1.2 root 1673: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1674: /**
1675: * GEMDOS Delete file
1676: * Call 0x41
1677: */
1.1.1.13 root 1678: static bool GemDOS_FDelete(Uint32 Params)
1.1 root 1679: {
1.1.1.9 root 1680: char *pszFileName;
1681: int Drive;
1682:
1683: /* Find filename */
1684: pszFileName = (char *)STRAM_ADDR(STMemory_ReadLong(Params+SIZE_WORD));
1.1.1.15 root 1685:
1686: LOG_TRACE(TRACE_OS_GEMDOS, "GEMDOS Fdelete(\"%s\")\n", pszFileName);
1687:
1.1.1.9 root 1688: Drive = GemDOS_IsFileNameAHardDrive(pszFileName);
1.1.1.15 root 1689:
1690: #ifdef ENABLE_SAVING
1.1.1.9 root 1691: if (ISHARDDRIVE(Drive))
1692: {
1.1.1.12 root 1693: char *psActualFileName;
1694: psActualFileName = malloc(FILENAME_MAX);
1695: if (!psActualFileName)
1696: {
1697: perror("GemDOS_FDelete");
1698: Regs[REG_D0] = GEMDOS_ENSMEM;
1.1.1.15 root 1699: return true;
1.1.1.12 root 1700: }
1701:
1.1.1.9 root 1702: /* And convert to hard drive filename */
1.1.1.12 root 1703: GemDOS_CreateHardDriveFileName(Drive, pszFileName, psActualFileName, FILENAME_MAX);
1.1 root 1704:
1.1.1.9 root 1705: /* Now delete file?? */
1.1.1.12 root 1706: if (unlink(psActualFileName) == 0)
1.1.1.9 root 1707: Regs[REG_D0] = GEMDOS_EOK; /* OK */
1708: else
1709: Regs[REG_D0] = GEMDOS_EFILNF; /* File not found */
1710:
1.1.1.12 root 1711: free(psActualFileName);
1.1.1.15 root 1712: return true;
1.1.1.9 root 1713: }
1.1 root 1714: #endif
1715:
1.1.1.15 root 1716: return false;
1.1 root 1717: }
1718:
1.1.1.2 root 1719: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1720: /**
1721: * GEMDOS File seek
1722: * Call 0x42
1723: */
1.1.1.13 root 1724: static bool GemDOS_LSeek(Uint32 Params)
1.1 root 1725: {
1.1.1.9 root 1726: long Offset;
1.1.1.15 root 1727: int Handle, Mode;
1728: long nFileSize;
1729: long nOldPos, nDestPos;
1730: FILE *fhndl;
1.1.1.9 root 1731:
1732: /* Read details from stack */
1733: Offset = (long)STMemory_ReadLong(Params+SIZE_WORD);
1734: Handle = STMemory_ReadWord(Params+SIZE_WORD+SIZE_LONG)-BASE_FILEHANDLE;
1735: Mode = STMemory_ReadWord(Params+SIZE_WORD+SIZE_LONG+SIZE_WORD);
1.1 root 1736:
1.1.1.15 root 1737: LOG_TRACE(TRACE_OS_GEMDOS, "GEMDOS Fseek(%li, %i, %i)\n", Offset, Handle, Mode);
1738:
1.1.1.9 root 1739: /* Check handle was valid */
1740: if (GemDOS_IsInvalidFileHandle(Handle))
1741: {
1742: /* No assume was TOS */
1.1.1.15 root 1743: return false;
1.1.1.9 root 1744: }
1.1.1.15 root 1745:
1746: fhndl = FileHandles[Handle].FileHandle;
1747:
1748: /* Save old position in file */
1749: nOldPos = ftell(fhndl);
1750:
1751: /* Determine the size of the file */
1752: fseek(fhndl, 0L, SEEK_END);
1753: nFileSize = ftell(fhndl);
1754:
1755: switch (Mode)
1756: {
1757: case 0: nDestPos = Offset; break;
1758: case 1: nDestPos = nOldPos + Offset; break;
1759: case 2: nDestPos = nFileSize - Offset; break;
1760: default:
1761: /* Restore old position and return error */
1762: fseek(fhndl, nOldPos, SEEK_SET);
1763: Regs[REG_D0] = GEMDOS_EINVFN;
1764: return true;
1765: }
1766:
1767: if (nDestPos < 0 || nDestPos > nFileSize)
1.1.1.9 root 1768: {
1.1.1.15 root 1769: /* Restore old position and return error */
1770: fseek(fhndl, nOldPos, SEEK_SET);
1771: Regs[REG_D0] = GEMDOS_ERANGE;
1772: return true;
1.1.1.9 root 1773: }
1.1.1.15 root 1774:
1775: /* Seek to new position and return offset from start of file */
1776: fseek(fhndl, nDestPos, SEEK_SET);
1777: Regs[REG_D0] = ftell(fhndl);
1778:
1779: return true;
1.1 root 1780: }
1781:
1.1.1.10 root 1782:
1783: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1784: /**
1785: * GEMDOS Fattrib() - get or set file attributes
1786: * Call 0x43
1787: */
1.1.1.13 root 1788: static bool GemDOS_Fattrib(Uint32 Params)
1.1.1.10 root 1789: {
1.1.1.11 root 1790: char sActualFileName[MAX_GEMDOS_PATH];
1.1.1.10 root 1791: char *psFileName;
1792: int nDrive;
1793: int nRwFlag, nAttrib;
1.1.1.12 root 1794: struct stat FileStat;
1.1.1.10 root 1795:
1796: /* Find filename */
1797: psFileName = (char *)STRAM_ADDR(STMemory_ReadLong(Params+SIZE_WORD));
1798: nDrive = GemDOS_IsFileNameAHardDrive(psFileName);
1799:
1800: nRwFlag = STMemory_ReadWord(Params+SIZE_WORD+SIZE_LONG);
1801: nAttrib = STMemory_ReadWord(Params+SIZE_WORD+SIZE_LONG+SIZE_WORD);
1802:
1.1.1.15 root 1803: LOG_TRACE(TRACE_OS_GEMDOS, "GEMDOS Fattrib(\"%s\", %d, 0x%x)\n",
1804: psFileName, nRwFlag, nAttrib);
1.1.1.10 root 1805:
1.1.1.12 root 1806: if (!ISHARDDRIVE(nDrive))
1.1.1.10 root 1807: {
1.1.1.15 root 1808: return false;
1.1.1.12 root 1809: }
1.1.1.10 root 1810:
1.1.1.12 root 1811: /* Convert to hard drive filename */
1812: GemDOS_CreateHardDriveFileName(nDrive, psFileName,
1813: sActualFileName, sizeof(sActualFileName));
1.1.1.10 root 1814:
1.1.1.12 root 1815: if (nAttrib == GEMDOS_FILE_ATTRIB_VOLUME_LABEL)
1816: {
1817: fprintf(stderr, "Warning: Hatari doesn't support GEMDOS volume label setting\n(for '%s')\n", sActualFileName);
1818: Regs[REG_D0] = GEMDOS_EFILNF; /* File not found */
1.1.1.15 root 1819: return true;
1.1.1.12 root 1820: }
1821: if (stat(sActualFileName, &FileStat) != 0)
1822: {
1823: Regs[REG_D0] = GEMDOS_EFILNF; /* File not found */
1.1.1.15 root 1824: return true;
1.1.1.12 root 1825: }
1826: if (nRwFlag == 0)
1827: {
1828: /* Read attributes */
1829: Regs[REG_D0] = GemDOS_ConvertAttribute(FileStat.st_mode);
1.1.1.15 root 1830: return true;
1.1.1.12 root 1831: }
1832: if (nAttrib & GEMDOS_FILE_ATTRIB_READONLY)
1833: {
1834: /* set read-only (readable by all) */
1835: if (chmod(sActualFileName, S_IRUSR|S_IRGRP|S_IROTH) == 0)
1.1.1.10 root 1836: {
1.1.1.12 root 1837: Regs[REG_D0] = GEMDOS_FILE_ATTRIB_READONLY;
1.1.1.15 root 1838: return true;
1.1.1.10 root 1839: }
1840: }
1.1.1.12 root 1841: /* FIXME: support hidden/system/archive flags? */
1842: Regs[REG_D0] = GEMDOS_EACCDN; /* Acces denied */
1.1.1.15 root 1843: return true;
1.1.1.10 root 1844: }
1845:
1846:
1.1.1.2 root 1847: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1848: /**
1849: * GEMDOS Get Directory
1850: * Call 0x47
1851: */
1.1.1.10 root 1852: static int GemDOS_GetDir(Uint32 Params)
1.1.1.9 root 1853: {
1.1.1.10 root 1854: Uint32 Address;
1855: Uint16 Drive;
1.1.1.9 root 1856:
1.1.1.10 root 1857: Address = STMemory_ReadLong(Params+SIZE_WORD);
1.1.1.9 root 1858: Drive = STMemory_ReadWord(Params+SIZE_WORD+SIZE_LONG);
1.1.1.15 root 1859: /* Note: Drive = 0 means current drive, 1 = A:, 2 = B:, 3 = C:, etc. */
1860:
1861: LOG_TRACE(TRACE_OS_GEMDOS, "GEMDOS Dgetpath(0x%x, %i)\n", Address, (int)Drive);
1862:
1.1.1.9 root 1863: /* is it our drive? */
1.1.1.15 root 1864: if ((Drive == 0 && CurrentDrive >= 2) || (Drive >= 3 /*&& Drive <= nNumDrives*/))
1.1.1.9 root 1865: {
1.1.1.11 root 1866: char path[MAX_GEMDOS_PATH];
1.1.1.9 root 1867: int i,len,c;
1868:
1.1.1.15 root 1869: if (Drive == 0)
1870: Drive = CurrentDrive;
1871: else
1872: Drive--;
1873:
1874: if (emudrives[Drive-2] == NULL)
1875: {
1876: return false;
1877: }
1878:
1879: strcpy(path,&emudrives[Drive-2]->fs_currpath[strlen(emudrives[Drive-2]->hd_emulation_dir)]);
1880:
1881: // convert it to ST path (DOS)
1.1.1.9 root 1882: len = strlen(path)-1;
1883: path[len] = 0;
1884: for (i = 0; i <= len; i++)
1885: {
1886: c = path[i];
1.1.1.12 root 1887: STMemory_WriteByte(Address+i, (c==PATHSEP ? '\\' : c) );
1.1.1.9 root 1888: }
1.1.1.15 root 1889: LOG_TRACE(TRACE_OS_GEMDOS, "GemDOS_GetDir (%d) = %s\n", Drive, path );
1890:
1891: Regs[REG_D0] = GEMDOS_EOK; /* OK */
1.1.1.9 root 1892:
1.1.1.15 root 1893: return true;
1.1.1.9 root 1894: }
1.1.1.15 root 1895: else return false;
1.1.1.2 root 1896: }
1897:
1898: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1899: /**
1900: * PExec Load And Go - Redirect to cart' routine at address 0xFA1000
1901: *
1902: * If loading from hard-drive(ie drive ID 2 or more) set condition codes to run own GEMDos routines
1903: */
1.1.1.10 root 1904: static int GemDOS_Pexec_LoadAndGo(Uint32 Params)
1.1 root 1905: {
1.1.1.9 root 1906: /* add multiple disk support here too */
1907: /* Hard-drive? */
1.1.1.11 root 1908: char *pszFileName = (char *)STRAM_ADDR(STMemory_ReadLong(Params+2*SIZE_WORD));
1909: int Drive = GemDOS_IsFileNameAHardDrive(pszFileName);
1910:
1911: if (ISHARDDRIVE(Drive))
1.1.1.9 root 1912: {
1913: /* If not using A: or B:, use my own routines to load */
1914: return CALL_PEXEC_ROUTINE;
1915: }
1.1.1.15 root 1916: else return false;
1.1 root 1917: }
1918:
1.1.1.2 root 1919: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1920: /**
1921: * PExec Load But Don't Go - Redirect to cart' routine at address 0xFA1000
1922: */
1.1.1.10 root 1923: static int GemDOS_Pexec_LoadDontGo(Uint32 Params)
1.1 root 1924: {
1.1.1.9 root 1925: /* Hard-drive? */
1.1.1.11 root 1926: char *pszFileName = (char *)STRAM_ADDR(STMemory_ReadLong(Params+2*SIZE_WORD));
1927: int Drive = GemDOS_IsFileNameAHardDrive(pszFileName);
1928: if (ISHARDDRIVE(Drive))
1.1.1.9 root 1929: {
1930: return CALL_PEXEC_ROUTINE;
1931: }
1.1.1.15 root 1932: else return false;
1.1 root 1933: }
1934:
1.1.1.2 root 1935: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1936: /**
1937: * GEMDOS PExec handler
1938: * Call 0x4B
1939: */
1.1.1.10 root 1940: static int GemDOS_Pexec(Uint32 Params)
1.1 root 1941: {
1.1.1.10 root 1942: Uint16 Mode;
1.1.1.11 root 1943: /*char *psFileName, *psCmdLine;*/
1.1 root 1944:
1.1.1.9 root 1945: /* Find PExec mode */
1946: Mode = STMemory_ReadWord(Params+SIZE_WORD);
1.1 root 1947:
1.1.1.11 root 1948: /*
1949: psFileName = (char *)STRAM_ADDR(STMemory_ReadLong(Params+2*SIZE_WORD));
1950: psCmdLine = (char *)STRAM_ADDR(STMemory_ReadLong(Params+2*SIZE_WORD+SIZE_LONG));
1951: */
1952:
1.1.1.15 root 1953: LOG_TRACE(TRACE_OS_GEMDOS, "GEMDOS Pexec(%i, ...)\n", Mode);
1954:
1.1.1.9 root 1955: /* Re-direct as needed */
1956: switch(Mode)
1957: {
1958: case 0: /* Load and go */
1959: return GemDOS_Pexec_LoadAndGo(Params);
1960: case 3: /* Load, don't go */
1961: return GemDOS_Pexec_LoadDontGo(Params);
1962: case 4: /* Just go */
1.1.1.15 root 1963: return false;
1.1.1.9 root 1964: case 5: /* Create basepage */
1.1.1.15 root 1965: return false;
1.1.1.9 root 1966: case 6:
1.1.1.15 root 1967: return false;
1.1.1.9 root 1968: }
1969:
1.1.1.10 root 1970: /* Default: Still re-direct to TOS */
1.1.1.15 root 1971: return false;
1.1 root 1972: }
1973:
1.1.1.4 root 1974:
1975: /*-----------------------------------------------------------------------*/
1.1.1.12 root 1976: /**
1977: * GEMDOS Search Next
1978: * Call 0x4F
1979: */
1.1.1.13 root 1980: static bool GemDOS_SNext(void)
1.1.1.4 root 1981: {
1.1.1.9 root 1982: int Index;
1.1.1.13 root 1983: int ret;
1.1.1.9 root 1984:
1.1.1.15 root 1985: LOG_TRACE(TRACE_OS_GEMDOS, "GEMDOS Fsnext()\n");
1986:
1.1.1.9 root 1987: /* Refresh pDTA pointer (from the current basepage) */
1988: pDTA = (DTA *)STRAM_ADDR(STMemory_ReadLong(STMemory_ReadLong(act_pd)+32));
1.1.1.4 root 1989:
1.1.1.9 root 1990: /* Was DTA ours or TOS? */
1991: if (do_get_mem_long(pDTA->magic) == DTA_MAGIC_NUMBER)
1992: {
1.1.1.13 root 1993: struct dirent **temp;
1.1.1.9 root 1994:
1995: /* Find index into our list of structures */
1996: Index = do_get_mem_word(pDTA->index) & (MAX_DTAS_FILES-1);
1.1.1.6 root 1997:
1.1.1.13 root 1998: if (nAttrSFirst == 8)
1.1.1.9 root 1999: {
2000: Regs[REG_D0] = GEMDOS_ENMFIL; /* No more files */
1.1.1.15 root 2001: return true;
1.1.1.9 root 2002: }
2003:
2004: temp = InternalDTAs[Index].found;
1.1.1.13 root 2005: do
1.1.1.9 root 2006: {
1.1.1.13 root 2007: if (InternalDTAs[Index].centry >= InternalDTAs[Index].nentries)
2008: {
2009: Regs[REG_D0] = GEMDOS_ENMFIL; /* No more files */
1.1.1.15 root 2010: return true;
1.1.1.13 root 2011: }
2012:
2013: ret = PopulateDTA(InternalDTAs[Index].path,
2014: temp[InternalDTAs[Index].centry++]);
2015: } while (ret == 1);
2016:
2017: if (ret < 0)
2018: {
2019: Log_Printf(LOG_WARN, "GemDOS_SNext: Error setting DTA.\n");
2020: Regs[REG_D0] = GEMDOS_EINTRN;
1.1.1.15 root 2021: return true;
1.1.1.9 root 2022: }
1.1.1.4 root 2023:
1.1.1.9 root 2024: Regs[REG_D0] = GEMDOS_EOK;
1.1.1.15 root 2025: return true;
1.1.1.9 root 2026: }
1.1.1.4 root 2027:
1.1.1.15 root 2028: return false;
1.1.1.4 root 2029: }
2030:
2031:
1.1.1.2 root 2032: /*-----------------------------------------------------------------------*/
1.1.1.12 root 2033: /**
2034: * GEMDOS Find first file
2035: * Call 0x4E
2036: */
1.1.1.13 root 2037: static bool GemDOS_SFirst(Uint32 Params)
1.1 root 2038: {
1.1.1.11 root 2039: char szActualFileName[MAX_GEMDOS_PATH];
2040: char tempstr[MAX_GEMDOS_PATH];
1.1.1.9 root 2041: char *pszFileName;
2042: struct dirent **files;
2043: int Drive;
2044: DIR *fsdir;
2045: int i,j,count;
2046:
2047: /* Find filename to search for */
2048: pszFileName = (char *)STRAM_ADDR(STMemory_ReadLong(Params+SIZE_WORD));
1.1.1.13 root 2049: nAttrSFirst = STMemory_ReadWord(Params+SIZE_WORD+SIZE_LONG);
1.1.1.9 root 2050:
1.1.1.15 root 2051: LOG_TRACE(TRACE_OS_GEMDOS, "GEMDOS Fsfirst(\"%s\", 0x%x)\n", pszFileName, nAttrSFirst);
2052:
1.1.1.9 root 2053: /* Refresh pDTA pointer (from the current basepage) */
2054: pDTA = (DTA *)STRAM_ADDR(STMemory_ReadLong(STMemory_ReadLong(act_pd)+32));
2055:
2056: Drive = GemDOS_IsFileNameAHardDrive(pszFileName);
2057: if (ISHARDDRIVE(Drive))
2058: {
2059:
2060: /* And convert to hard drive filename */
1.1.1.12 root 2061: GemDOS_CreateHardDriveFileName(Drive, pszFileName,
2062: szActualFileName, sizeof(szActualFileName));
1.1.1.9 root 2063:
2064: /* Populate DTA, set index for our use */
2065: do_put_mem_word(pDTA->index, DTAIndex);
2066: /* set our dta magic num */
2067: do_put_mem_long(pDTA->magic, DTA_MAGIC_NUMBER);
2068:
1.1.1.15 root 2069: if (InternalDTAs[DTAIndex].bUsed == true)
1.1.1.9 root 2070: ClearInternalDTA();
1.1.1.15 root 2071: InternalDTAs[DTAIndex].bUsed = true;
1.1.1.9 root 2072:
2073: /* Were we looking for the volume label? */
1.1.1.13 root 2074: if (nAttrSFirst == GEMDOS_FILE_ATTRIB_VOLUME_LABEL)
1.1.1.9 root 2075: {
2076: /* Volume name */
2077: strcpy(pDTA->dta_name,"EMULATED.001");
2078: Regs[REG_D0] = GEMDOS_EOK; /* Got volume */
1.1.1.15 root 2079: return true;
1.1.1.9 root 2080: }
2081:
2082: /* open directory */
2083: fsfirst_dirname(szActualFileName, InternalDTAs[DTAIndex].path);
2084: fsdir = opendir(InternalDTAs[DTAIndex].path);
2085:
2086: if (fsdir == NULL)
2087: {
2088: Regs[REG_D0] = GEMDOS_EPTHNF; /* Path not found */
1.1.1.15 root 2089: return true;
1.1.1.9 root 2090: }
2091: /* close directory */
2092: closedir(fsdir);
2093:
2094: count = scandir(InternalDTAs[DTAIndex].path, &files, 0, alphasort);
2095: /* File (directory actually) not found */
2096: if (count < 0)
2097: {
2098: Regs[REG_D0] = GEMDOS_EFILNF;
1.1.1.15 root 2099: return true;
1.1.1.9 root 2100: }
2101:
2102: InternalDTAs[DTAIndex].centry = 0; /* current entry is 0 */
2103: fsfirst_dirmask(szActualFileName, tempstr); /* get directory mask */
2104: InternalDTAs[DTAIndex].found = files; /* get files */
2105:
2106: /* count & copy the entries that match our mask and discard the rest */
2107: j = 0;
2108: for (i=0; i < count; i++)
1.1.1.13 root 2109: {
1.1.1.9 root 2110: if (match(tempstr, files[i]->d_name))
2111: {
2112: InternalDTAs[DTAIndex].found[j] = files[i];
2113: j++;
2114: }
2115: else
2116: {
2117: free(files[i]);
1.1.1.13 root 2118: files[i] = NULL;
1.1.1.9 root 2119: }
1.1.1.13 root 2120: }
1.1.1.9 root 2121: InternalDTAs[DTAIndex].nentries = j; /* set number of legal entries */
2122:
2123: /* No files of that match, return error code */
2124: if (j==0)
2125: {
2126: free(files);
2127: InternalDTAs[DTAIndex].found = NULL;
2128: Regs[REG_D0] = GEMDOS_EFILNF; /* File not found */
1.1.1.15 root 2129: return true;
1.1.1.9 root 2130: }
2131:
2132: /* Scan for first file (SNext uses no parameters) */
1.1.1.11 root 2133: GemDOS_SNext();
1.1.1.9 root 2134: /* increment DTA index */
2135: DTAIndex++;
2136: DTAIndex&=(MAX_DTAS_FILES-1);
2137:
1.1.1.15 root 2138: return true;
1.1.1.9 root 2139: }
1.1.1.15 root 2140: return false;
1.1 root 2141: }
2142:
2143:
1.1.1.2 root 2144: /*-----------------------------------------------------------------------*/
1.1.1.12 root 2145: /**
2146: * GEMDOS Rename
2147: * Call 0x56
2148: */
1.1.1.13 root 2149: static bool GemDOS_Rename(Uint32 Params)
1.1 root 2150: {
1.1.1.9 root 2151: char *pszNewFileName,*pszOldFileName;
1.1.1.11 root 2152: char szNewActualFileName[MAX_GEMDOS_PATH],szOldActualFileName[MAX_GEMDOS_PATH];
1.1.1.9 root 2153: int NewDrive, OldDrive;
2154:
2155: /* Read details from stack */
2156: pszOldFileName = (char *)STRAM_ADDR(STMemory_ReadLong(Params+SIZE_WORD+SIZE_WORD));
2157: pszNewFileName = (char *)STRAM_ADDR(STMemory_ReadLong(Params+SIZE_WORD+SIZE_WORD+SIZE_LONG));
2158:
1.1.1.15 root 2159: LOG_TRACE(TRACE_OS_GEMDOS, "GEMDOS Frename(\"%s\", \"%s\")\n", pszOldFileName, pszNewFileName);
2160:
1.1.1.9 root 2161: NewDrive = GemDOS_IsFileNameAHardDrive(pszNewFileName);
2162: OldDrive = GemDOS_IsFileNameAHardDrive(pszOldFileName);
2163: if (ISHARDDRIVE(NewDrive) && ISHARDDRIVE(OldDrive))
2164: {
2165: /* And convert to hard drive filenames */
1.1.1.12 root 2166: GemDOS_CreateHardDriveFileName(NewDrive, pszNewFileName,
2167: szNewActualFileName, sizeof(szNewActualFileName));
2168: GemDOS_CreateHardDriveFileName(OldDrive, pszOldFileName,
2169: szOldActualFileName, sizeof(szOldActualFileName));
1.1.1.9 root 2170:
2171: /* Rename files */
2172: if ( rename(szOldActualFileName,szNewActualFileName)==0 )
2173: Regs[REG_D0] = GEMDOS_EOK;
2174: else
2175: Regs[REG_D0] = GEMDOS_EACCDN; /* Access denied */
1.1.1.15 root 2176: return true;
1.1.1.9 root 2177: }
1.1 root 2178:
1.1.1.15 root 2179: return false;
1.1 root 2180: }
2181:
1.1.1.15 root 2182:
1.1.1.2 root 2183: /*-----------------------------------------------------------------------*/
1.1.1.12 root 2184: /**
2185: * GEMDOS GSDToF
2186: * Call 0x57
2187: */
1.1.1.13 root 2188: static bool GemDOS_GSDToF(Uint32 Params)
1.1 root 2189: {
1.1.1.9 root 2190: DATETIME DateTime;
1.1.1.10 root 2191: Uint32 pBuffer;
1.1.1.9 root 2192: int Handle,Flag;
2193:
2194: /* Read details from stack */
2195: pBuffer = STMemory_ReadLong(Params+SIZE_WORD);
2196: Handle = STMemory_ReadWord(Params+SIZE_WORD+SIZE_LONG)-BASE_FILEHANDLE;
2197: Flag = STMemory_ReadWord(Params+SIZE_WORD+SIZE_WORD+SIZE_LONG);
2198:
1.1.1.15 root 2199: LOG_TRACE(TRACE_OS_GEMDOS, "GEMDOS Fdatime(0x%x, %i, %i)\n", pBuffer,
2200: Handle, Flag);
2201:
1.1.1.9 root 2202: /* Check handle was valid */
2203: if (GemDOS_IsInvalidFileHandle(Handle))
2204: {
2205: /* No assume was TOS */
1.1.1.15 root 2206: return false;
1.1.1.9 root 2207: }
2208:
2209: /* Set time/date stamp? Do nothing. */
2210: if (Flag == 1)
2211: {
2212: Regs[REG_D0] = GEMDOS_EOK;
1.1.1.15 root 2213: return true;
1.1.1.9 root 2214: }
2215:
2216: Regs[REG_D0] = GEMDOS_ERROR; /* Invalid parameter */
2217:
1.1.1.15 root 2218: if (GemDOS_GetFileInformation(FileHandles[Handle].szActualName, &DateTime) == true)
1.1.1.9 root 2219: {
2220: STMemory_WriteWord(pBuffer, DateTime.word1);
2221: STMemory_WriteWord(pBuffer+2, DateTime.word2);
2222: Regs[REG_D0] = GEMDOS_EOK;
2223: }
1.1.1.15 root 2224: return true;
1.1 root 2225: }
2226:
1.1.1.9 root 2227:
1.1 root 2228: /*-----------------------------------------------------------------------*/
1.1.1.12 root 2229: /**
2230: * Run GEMDos call, and re-direct if need to. Used to handle hard disk emulation etc...
2231: * This sets the condition codes (in SR), which are used in the 'cart_asm.s' program to
2232: * decide if we need to run old GEM vector, or PExec or nothing.
1.1.1.15 root 2233: *
1.1.1.12 root 2234: * This method keeps the stack and other states consistant with the original ST which is very important
2235: * for the PExec call and maximum compatibility through-out
2236: */
1.1 root 2237: void GemDOS_OpCode(void)
2238: {
1.1.1.9 root 2239: unsigned short int GemDOSCall,CallingSReg;
1.1.1.10 root 2240: Uint32 Params;
1.1.1.9 root 2241: short RunOld;
1.1.1.12 root 2242: Uint16 SR;
1.1.1.9 root 2243:
1.1.1.12 root 2244: SR = M68000_GetSR();
1.1.1.9 root 2245:
2246: /* Read SReg from stack to see if parameters are on User or Super stack */
2247: CallingSReg = STMemory_ReadWord(Regs[REG_A7]);
2248: if ((CallingSReg&SR_SUPERMODE)==0) /* Calling from user mode */
2249: Params = regs.usp;
2250: else
2251: {
2252: Params = Regs[REG_A7]+SIZE_WORD+SIZE_LONG; /* super stack */
1.1.1.12 root 2253: if (currprefs.cpu_level > 0)
1.1.1.9 root 2254: Params += SIZE_WORD; /* Skip extra word whe CPU is >=68010 */
2255: }
2256:
2257: /* Default to run TOS GemDos (SR_NEG run Gemdos, SR_ZERO already done, SR_OVERFLOW run own 'Pexec' */
1.1.1.15 root 2258: RunOld = true;
1.1.1.9 root 2259: SR &= SR_CLEAR_OVERFLOW;
2260: SR &= SR_CLEAR_ZERO;
2261: SR |= SR_NEG;
1.1 root 2262:
1.1.1.9 root 2263: /* Find pointer to call parameters */
2264: GemDOSCall = STMemory_ReadWord(Params);
1.1.1.2 root 2265:
1.1.1.9 root 2266: /* Intercept call */
2267: switch(GemDOSCall)
2268: {
2269: /*
2270: case 0x3:
2271: if (GemDOS_Cauxin(Params))
1.1.1.15 root 2272: RunOld = false;
1.1.1.9 root 2273: break;
2274: */
2275: /*
2276: case 0x4:
2277: if (GemDOS_Cauxout(Params))
1.1.1.15 root 2278: RunOld = false;
1.1.1.9 root 2279: break;
2280: */
1.1.1.13 root 2281: /* direct printing via GEMDOS */
2282: /*
2283: case 0x5:
1.1.1.9 root 2284: if (GemDOS_Cprnout(Params))
1.1.1.15 root 2285: RunOld = false;
1.1.1.9 root 2286: break;
1.1.1.13 root 2287: */
1.1.1.9 root 2288: case 0xe:
2289: if (GemDOS_SetDrv(Params))
1.1.1.15 root 2290: RunOld = false;
1.1.1.9 root 2291: break;
1.1.1.13 root 2292: /* Printer status */
2293: /*
2294: case 0x11:
1.1.1.9 root 2295: if (GemDOS_Cprnos(Params))
1.1.1.15 root 2296: RunOld = false;
1.1.1.9 root 2297: break;
1.1.1.13 root 2298: */
1.1.1.9 root 2299: /*
2300: case 0x12:
2301: if (GemDOS_Cauxis(Params))
1.1.1.15 root 2302: RunOld = false;
1.1.1.9 root 2303: break;
2304: */
2305: /*
2306: case 0x13:
2307: if (GemDOS_Cauxos(Params))
1.1.1.15 root 2308: RunOld = false;
1.1.1.9 root 2309: break;
2310: */
2311: case 0x1a:
2312: if (GemDOS_SetDTA(Params))
1.1.1.15 root 2313: RunOld = false;
1.1.1.9 root 2314: break;
2315: case 0x36:
2316: if (GemDOS_DFree(Params))
1.1.1.15 root 2317: RunOld = false;
1.1.1.9 root 2318: break;
2319: case 0x39:
2320: if (GemDOS_MkDir(Params))
1.1.1.15 root 2321: RunOld = false;
1.1.1.9 root 2322: break;
2323: case 0x3a:
2324: if (GemDOS_RmDir(Params))
1.1.1.15 root 2325: RunOld = false;
1.1.1.9 root 2326: break;
2327: case 0x3b:
2328: if (GemDOS_ChDir(Params))
1.1.1.15 root 2329: RunOld = false;
1.1.1.9 root 2330: break;
2331: case 0x3c:
2332: if (GemDOS_Create(Params))
1.1.1.15 root 2333: RunOld = false;
1.1.1.9 root 2334: break;
2335: case 0x3d:
2336: if (GemDOS_Open(Params))
1.1.1.15 root 2337: RunOld = false;
1.1.1.9 root 2338: break;
2339: case 0x3e:
2340: if (GemDOS_Close(Params))
1.1.1.15 root 2341: RunOld = false;
1.1.1.9 root 2342: break;
2343: case 0x3f:
2344: if (GemDOS_Read(Params))
1.1.1.15 root 2345: RunOld = false;
1.1.1.9 root 2346: break;
2347: case 0x40:
2348: if (GemDOS_Write(Params))
1.1.1.15 root 2349: RunOld = false;
1.1.1.9 root 2350: break;
2351: case 0x41:
1.1.1.12 root 2352: if (GemDOS_FDelete(Params))
1.1.1.15 root 2353: RunOld = false;
1.1.1.9 root 2354: break;
2355: case 0x42:
2356: if (GemDOS_LSeek(Params))
1.1.1.15 root 2357: RunOld = false;
1.1.1.9 root 2358: break;
1.1.1.10 root 2359: case 0x43:
2360: if (GemDOS_Fattrib(Params))
1.1.1.15 root 2361: RunOld = false;
1.1.1.10 root 2362: break;
1.1.1.9 root 2363: case 0x47:
2364: if (GemDOS_GetDir(Params))
1.1.1.15 root 2365: RunOld = false;
1.1.1.9 root 2366: break;
2367: case 0x4b:
2368: if (GemDOS_Pexec(Params) == CALL_PEXEC_ROUTINE)
2369: RunOld = CALL_PEXEC_ROUTINE;
2370: break;
2371: case 0x4e:
2372: if (GemDOS_SFirst(Params))
1.1.1.15 root 2373: RunOld = false;
1.1.1.9 root 2374: break;
2375: case 0x4f:
1.1.1.11 root 2376: if (GemDOS_SNext())
1.1.1.15 root 2377: RunOld = false;
1.1.1.9 root 2378: break;
2379: case 0x56:
2380: if (GemDOS_Rename(Params))
1.1.1.15 root 2381: RunOld = false;
1.1.1.9 root 2382: break;
2383: case 0x57:
2384: if (GemDOS_GSDToF(Params))
1.1.1.15 root 2385: RunOld = false;
1.1.1.9 root 2386: break;
1.1.1.15 root 2387: default:
2388: LOG_TRACE(TRACE_OS_GEMDOS, "GEMDOS call 0x%X\n", GemDOSCall);
1.1.1.9 root 2389: }
1.1.1.15 root 2390:
1.1.1.9 root 2391: switch(RunOld)
2392: {
1.1.1.15 root 2393: case false:
1.1.1.13 root 2394: /* skip over branch to pexec to RTE */
1.1.1.9 root 2395: SR |= SR_ZERO;
1.1.1.13 root 2396: /* visualize GemDOS emu HD access? */
2397: switch (GemDOSCall)
2398: {
2399: case 0x36:
2400: case 0x39:
2401: case 0x3a:
2402: case 0x3b:
2403: case 0x3c:
2404: case 0x3d:
2405: case 0x3e:
2406: case 0x3f:
2407: case 0x40:
2408: case 0x41:
2409: case 0x42:
2410: case 0x43:
2411: case 0x47:
2412: case 0x4e:
2413: case 0x4f:
2414: case 0x56:
2415: Statusbar_EnableHDLed();
2416: }
1.1.1.9 root 2417: break;
1.1.1.13 root 2418: case CALL_PEXEC_ROUTINE:
2419: /* branch to pexec, then redirect to old gemdos. */
1.1.1.9 root 2420: SR |= SR_OVERFLOW;
2421: break;
2422: }
1.1 root 2423:
1.1.1.12 root 2424: M68000_SetSR(SR); /* update the flags in the SR register */
1.1 root 2425: }
2426:
1.1.1.9 root 2427:
1.1.1.2 root 2428: /*-----------------------------------------------------------------------*/
1.1.1.12 root 2429: /**
2430: * GemDOS_Boot - routine called on the first occurence of the gemdos opcode.
2431: * (this should be in the cartridge bootrom)
2432: * Sets up our gemdos handler (or, if we don't need one, just turn off keyclicks)
1.1.1.2 root 2433: */
1.1.1.7 root 2434: void GemDOS_Boot(void)
1.1.1.2 root 2435: {
1.1.1.15 root 2436: bInitGemDOS = true;
1.1.1.2 root 2437:
1.1.1.15 root 2438: LOG_TRACE(TRACE_OS_GEMDOS, "Gemdos_Boot()\n" );
1.1.1.9 root 2439:
2440: /* install our gemdos handler, if -e or --harddrive option used */
2441: if (GEMDOS_EMU_ON)
2442: {
2443: /* Get the address of the p_run variable that points to the actual basepage */
2444: if (TosVersion == 0x100)
2445: {
2446: /* We have to use fix addresses on TOS 1.00 :-( */
2447: if ((STMemory_ReadWord(TosAddress+28)>>1) == 4)
2448: act_pd = 0x873c; /* Spanish TOS is different from others! */
2449: else
2450: act_pd = 0x602c;
2451: }
2452: else
2453: {
2454: act_pd = STMemory_ReadLong(TosAddress + 0x28);
2455: }
2456:
2457: /* Save old GEMDOS handler adress */
2458: STMemory_WriteLong(CART_OLDGEMDOS, STMemory_ReadLong(0x0084));
2459: /* Setup new GEMDOS handler, see "cart_asm.s" */
2460: STMemory_WriteLong(0x0084, CART_GEMDOS);
2461: }
1.1 root 2462: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.