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