Annotation of hatari/src/gemdos.c, revision 1.1.1.16

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.