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

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

unix.superglobalmegacorp.com

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