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

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

unix.superglobalmegacorp.com

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