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

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

unix.superglobalmegacorp.com

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