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

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.9 ! root       21: char Gemdos_rcsid[] = "Hatari $Id: gemdos.c,v 1.39 2005/04/14 13:22:46 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? */
        !            92: DTA *pDTA;                                  /* Our GEMDOS hard drive Disc Transfer Address structure */
        !            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*/
        !           168:        "ChMod",      /*0x43*/
        !           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 */
        !           480:                strcpy(emudrives[i]->hd_emulation_dir, ConfigureParams.HardDisc.szHardDiscDirectories[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: 
        !           492:                ConfigureParams.HardDisc.nDriveList += 1;
        !           493: 
        !           494:                fprintf(stderr, "Hard drive emulation, %c: <-> %s\n",
        !           495:                                emudrives[i]->hd_letter + 'A', emudrives[i]->hd_emulation_dir);
        !           496:        }
        !           497: 
        !           498:        ConfigureParams.HardDisc.bUseHardDiscDirectories = TRUE;
1.1.1.3   root      499: }
                    500: 
1.1.1.6   root      501: 
1.1.1.3   root      502: /*-----------------------------------------------------------------------*/
                    503: /*
                    504:   Un-init the GEMDOS drive
                    505: */
1.1.1.7   root      506: void GemDOS_UnInitDrives(void)
1.1.1.3   root      507: {
1.1.1.9 ! root      508:        int i;
1.1.1.3   root      509: 
1.1.1.9 ! root      510:        GemDOS_Reset();        /* Close all open files on emulated drive*/
1.1.1.3   root      511: 
1.1.1.9 ! root      512:        if (GEMDOS_EMU_ON)
        !           513:        {
        !           514:                for(i=0; i<MAX_HARDDRIVES; i++)
        !           515:                {
        !           516:                        free(emudrives[i]);    /* Release memory */
        !           517:                        ConfigureParams.HardDisc.nDriveList -= 1;
        !           518:                }
        !           519: 
        !           520:                free(emudrives);
        !           521:                emudrives = NULL;
        !           522:        }
1.1.1.6   root      523: 
1.1.1.9 ! root      524:        ConfigureParams.HardDisc.bUseHardDiscDirectories = FALSE;
1.1.1.3   root      525: }
                    526: 
                    527: 
1.1.1.2   root      528: /*-----------------------------------------------------------------------*/
1.1       root      529: /*
                    530:   Save/Restore snapshot of local variables('MemorySnapShot_Store' handles type)
                    531: */
                    532: void GemDOS_MemorySnapShot_Capture(BOOL bSave)
                    533: {
1.1.1.9 ! root      534:        unsigned int Addr;
        !           535:        int i;
1.1       root      536: 
1.1.1.9 ! root      537:        /* Save/Restore details */
        !           538:        MemorySnapShot_Store(&DTAIndex,sizeof(DTAIndex));
        !           539:        MemorySnapShot_Store(&bInitGemDOS,sizeof(bInitGemDOS));
        !           540:        if (bSave)
        !           541:        {
        !           542:                Addr = (unsigned int)((Uint8 *)pDTA - STRam);
        !           543:                MemorySnapShot_Store(&Addr,sizeof(Addr));
        !           544:        }
        !           545:        else
        !           546:        {
        !           547:                MemorySnapShot_Store(&Addr,sizeof(Addr));
        !           548:                pDTA = (DTA *)(STRam + Addr);
        !           549:        }
        !           550:        MemorySnapShot_Store(&CurrentDrive,sizeof(CurrentDrive));
        !           551:        /* Don't save file handles as files may have changed which makes
        !           552:           it impossible to get a valid handle back */
        !           553:        if (!bSave)
        !           554:        {
        !           555:                /* Clear file handles  */
        !           556:                for(i=0; i<MAX_FILE_HANDLES; i++)
        !           557:                {
        !           558:                        FileHandles[i].FileHandle = NULL;
        !           559:                        FileHandles[i].bUsed = FALSE;
        !           560:                }
        !           561:        }
1.1       root      562: }
                    563: 
1.1.1.9 ! root      564: 
1.1.1.2   root      565: /*-----------------------------------------------------------------------*/
1.1       root      566: /*
                    567:   Return free PC file handle table index, or -1 if error
                    568: */
1.1.1.7   root      569: static int GemDOS_FindFreeFileHandle(void)
1.1       root      570: {
1.1.1.9 ! root      571:        int i;
1.1       root      572: 
1.1.1.9 ! root      573:        /* Scan our file list for free slot */
        !           574:        for(i=0; i<MAX_FILE_HANDLES; i++)
        !           575:        {
        !           576:                if (!FileHandles[i].bUsed)
        !           577:                        return i;
        !           578:        }
1.1       root      579: 
1.1.1.9 ! root      580:        /* Cannot open any more files, return error */
        !           581:        return -1;
1.1       root      582: }
                    583: 
1.1.1.2   root      584: /*-----------------------------------------------------------------------*/
1.1       root      585: /*
                    586:   Check ST handle is within our table range, return TRUE if not
                    587: */
1.1.1.7   root      588: static BOOL GemDOS_IsInvalidFileHandle(int Handle)
1.1       root      589: {
1.1.1.9 ! root      590:        BOOL bInvalidHandle=FALSE;
1.1       root      591: 
1.1.1.9 ! root      592:        /* Check handle was valid with our handle table */
        !           593:        if ((Handle < 0) || (Handle >= MAX_FILE_HANDLES))
        !           594:                bInvalidHandle = TRUE;
        !           595:        else if (!FileHandles[Handle].bUsed)
        !           596:                bInvalidHandle = TRUE;
1.1       root      597: 
1.1.1.9 ! root      598:        return bInvalidHandle;
1.1       root      599: }
                    600: 
1.1.1.2   root      601: /*-----------------------------------------------------------------------*/
1.1       root      602: /*
                    603:   Find drive letter from a filename, eg C,D... and return as drive ID(C:2, D:3...)
1.1.1.3   root      604:   returns the current drive number if none is specified.
1.1       root      605: */
1.1.1.7   root      606: static int GemDOS_FindDriveNumber(char *pszFileName)
1.1       root      607: {
1.1.1.9 ! root      608:        /* Does have 'A:' or 'C:' etc.. at start of string? */
        !           609:        if ((pszFileName[0] != '\0') && (pszFileName[1] == ':'))
        !           610:        {
        !           611:                if ((pszFileName[0] >= 'a') && (pszFileName[0] <= 'z'))
        !           612:                        return (pszFileName[0]-'a');
        !           613:                else if ((pszFileName[0] >= 'A') && (pszFileName[0] <= 'Z'))
        !           614:                        return (pszFileName[0]-'A');
        !           615:        }
1.1       root      616: 
1.1.1.9 ! root      617:        return CurrentDrive;
1.1       root      618: }
                    619: 
1.1.1.2   root      620: /*-----------------------------------------------------------------------*/
1.1       root      621: /*
                    622:   Return drive ID(C:2, D:3 etc...) or -1 if not one of our emulation hard-drives
                    623: */
1.1.1.7   root      624: static int GemDOS_IsFileNameAHardDrive(char *pszFileName)
1.1       root      625: {
1.1.1.9 ! root      626:        int DriveLetter;
        !           627: 
        !           628:        /* Do we even have a hard-drive? */
        !           629:        if (GEMDOS_EMU_ON)
        !           630:        {
        !           631:                DriveLetter = GemDOS_FindDriveNumber(pszFileName);
        !           632:                /* add support for multiple drives here.. */
        !           633:                if (DriveLetter == emudrives[0]->hd_letter)
        !           634:                        return DriveLetter;
        !           635:        }
        !           636:        /* Not a high-level redirected drive */
        !           637:        return -1;
1.1       root      638: 
1.1.1.9 ! root      639:        /* this code is depreciated */
        !           640:        /* Do we even have a hard-drive? */
        !           641:        if (ConfigureParams.HardDisc.nDriveList!=DRIVELIST_NONE)
        !           642:        {
        !           643:                /* Find drive letter(as number) */
        !           644:                DriveLetter = GemDOS_FindDriveNumber(pszFileName);
        !           645:                /* Does match one of our drives? */
        !           646:                if ((DriveLetter >= 2) && (DriveLetter <= DRIVELIST_TO_DRIVE_INDEX(ConfigureParams.HardDisc.nDriveList)))
        !           647:                        return DriveLetter;
        !           648:        }
1.1       root      649: 
1.1.1.9 ! root      650:        /* No, let TOS handle it */
        !           651:        return -1;
1.1       root      652: }
                    653: 
1.1.1.7   root      654: 
                    655: /*-----------------------------------------------------------------------*/
                    656: /*
                    657:   Returns the length of the basename of the file passed in parameter
                    658:    (ie the file without extension)
                    659: */
                    660: static int baselen(char *s)
                    661: {
1.1.1.9 ! root      662:        char *ext = strchr(s,'.');
        !           663:        if (ext)
        !           664:                return ext-s;
        !           665:        return strlen(s);
1.1.1.6   root      666: }
                    667: 
1.1.1.2   root      668: /*-----------------------------------------------------------------------*/
1.1       root      669: /*
                    670:   Use hard-drive directory, current ST directory and filename to create full path
                    671: */
1.1.1.9 ! root      672: void GemDOS_CreateHardDriveFileName(int Drive, const char *pszFileName, char *pszDestName)
1.1       root      673: {
1.1.1.9 ! root      674:        char *s,*start;
1.1.1.2   root      675: 
1.1.1.9 ! root      676:        if (pszFileName[0] == '\0')
        !           677:                return; /* check for valid string */
1.1.1.3   root      678: 
1.1.1.9 ! root      679:        /* case full filename "C:\foo\bar" */
        !           680:        s=pszDestName;
        !           681:        start=NULL;
        !           682: 
        !           683:        if (pszFileName[1] == ':')
        !           684:        {
        !           685:                sprintf(pszDestName, "%s%s", emudrives[0]->hd_emulation_dir, File_RemoveFileNameDrive(pszFileName));
        !           686:        }
        !           687:        /* case referenced from root:  "\foo\bar" */
        !           688:        else if (pszFileName[0] == '\\')
        !           689:        {
        !           690:                sprintf(pszDestName, "%s%s", emudrives[0]->hd_emulation_dir, pszFileName);
        !           691:        }
        !           692:        /* case referenced from current directory */
        !           693:        else
        !           694:        {
        !           695:                sprintf(pszDestName, "%s%s",  emudrives[0]->fs_currpath, pszFileName);
        !           696:                start = pszDestName + strlen(emudrives[0]->fs_currpath)-1;
1.1.1.6   root      697:        }
1.1.1.9 ! root      698: 
        !           699:        /* convert to front slashes. */
        !           700:        while((s = strchr(s+1,'\\')))
        !           701:        {
        !           702:                if (!start)
        !           703:                {
        !           704:                        start = s;
        !           705:                        continue;
        !           706:                }
        !           707:                {
        !           708:                        glob_t globbuf;
        !           709:                        char old1,old2,dest[256];
        !           710:                        int len, found, base_len;
        !           711:                        unsigned int j;
        !           712: 
        !           713:                        *start++ = '/';
        !           714:                        old1 = *start;
        !           715:                        *start++ = '*';
        !           716:                        old2 = *start;
        !           717:                        *start = 0;
        !           718:                        glob(pszDestName,GLOB_ONLYDIR,NULL,&globbuf);
        !           719:                        *start-- = old2;
        !           720:                        *start = old1;
        !           721:                        *s = 0;
        !           722:                        len = strlen(pszDestName);
        !           723:                        base_len = baselen(start);
        !           724:                        found = 0;
        !           725:                        for (j=0; j<globbuf.gl_pathc; j++)
        !           726:                        {
        !           727:                                /* If we search for a file of at least 8 characters, then it might
        !           728:                                   be a longer filename since the ST can access only the first 8
        !           729:                                   characters. If not, then it's a precise match (with case). */
        !           730:                                if (!(base_len < 8 ? strcasecmp(globbuf.gl_pathv[j],pszDestName) :
        !           731:                                                strncasecmp(globbuf.gl_pathv[j],pszDestName,len)))
        !           732:                                {
        !           733:                                        /* we found a matching name... */
        !           734:                                        sprintf(dest,"%s%c%s",globbuf.gl_pathv[j],'/',s+1);
        !           735:                                        strcpy(pszDestName,dest);
        !           736:                                        j = globbuf.gl_pathc;
        !           737:                                        found = 1;
        !           738:                                }
        !           739:                        }
        !           740:                        globfree(&globbuf);
        !           741:                        if (!found)
        !           742:                        {
        !           743:                                /* didn't find it. Let's try normal files (it might be a symlink) */
        !           744:                                *start++ = '*';
        !           745:                                *start = 0;
        !           746:                                glob(pszDestName,0,NULL,&globbuf);
        !           747:                                *start-- = old2;
        !           748:                                *start = old1;
        !           749:                                for (j=0; j<globbuf.gl_pathc; j++)
        !           750:                                {
        !           751:                                        if (!strncasecmp(globbuf.gl_pathv[j],pszDestName,len))
        !           752:                                        {
        !           753:                                                /* we found a matching name... */
        !           754:                                                sprintf(dest,"%s%c%s",globbuf.gl_pathv[j],'/',s+1);
        !           755:                                                strcpy(pszDestName,dest);
        !           756:                                                j = globbuf.gl_pathc;
        !           757:                                                found = 1;
        !           758:                                        }
        !           759:                                }
        !           760:                                globfree(&globbuf);
        !           761:                                if (!found)
        !           762:                                {           /* really nothing ! */
        !           763:                                        *s = '/';
        !           764:                                        fprintf(stderr,"no path for %s\n",pszDestName);
        !           765:                                }
        !           766:                        }
        !           767:                }
        !           768:                start = s;
        !           769:        }
        !           770: 
        !           771:        if (!start)
        !           772:                start = strrchr(pszDestName,'/'); // path already converted ?
        !           773: 
        !           774:        if (start)
        !           775:        {
        !           776:                *start++ = '/';     /* in case there was only 1 anti slash */
        !           777:                if (*start && !strchr(start,'?') && !strchr(start,'*'))
        !           778:                {
        !           779:                        /* We have a complete name after the path, not a wildcard */
        !           780:                        glob_t globbuf;
        !           781:                        char old1,old2;
        !           782:                        int len, found, base_len;
        !           783:                        unsigned int j;
        !           784: 
        !           785:                        old1 = *start;
        !           786:                        *start++ = '*';
        !           787:                        old2 = *start;
        !           788:                        *start = 0;
        !           789:                        glob(pszDestName,0,NULL,&globbuf);
        !           790:                        *start-- = old2;
        !           791:                        *start = old1;
        !           792:                        len = strlen(pszDestName);
        !           793:                        base_len = baselen(start);
        !           794:                        found = 0;
        !           795:                        for (j=0; j<globbuf.gl_pathc; j++)
        !           796:                        {
        !           797:                                /* If we search for a file of at least 8 characters, then it might
        !           798:                                   be a longer filename since the ST can access only the first 8
        !           799:                                   characters. If not, then it's a precise match (with case). */
        !           800:                                if (!(base_len < 8 ? strcasecmp(globbuf.gl_pathv[j],pszDestName) :
        !           801:                                                strncasecmp(globbuf.gl_pathv[j],pszDestName,len)))
        !           802:                                {
        !           803:                                        /* we found a matching name... */
        !           804:                                        strcpy(pszDestName,globbuf.gl_pathv[j]);
        !           805:                                        j = globbuf.gl_pathc;
        !           806:                                        found = 1;
        !           807:                                }
        !           808:                        }
1.1.1.6   root      809: #if FILE_DEBUG
1.1.1.9 ! root      810:                        if (!found)
        !           811:                        {
        !           812:                                /* It's often normal, the gem uses this to test for existence */
        !           813:                                /* of desktop.inf or newdesk.inf for example. */
        !           814:                                fprintf(stderr,"didn't find filename %s\n",pszDestName);
        !           815:                        }
1.1.1.6   root      816: #endif
1.1.1.9 ! root      817:                        globfree(&globbuf);
        !           818:                }
        !           819:        }
1.1       root      820: 
1.1.1.6   root      821: #if FILE_DEBUG
1.1.1.9 ! root      822:        fprintf(stderr,"conv %s -> %s\n",pszFileName,pszDestName);
1.1.1.6   root      823: #endif
1.1       root      824: }
                    825: 
1.1.1.6   root      826: 
1.1.1.2   root      827: /*-----------------------------------------------------------------------*/
1.1       root      828: /*
                    829:   GEMDOS Cauxin
                    830:   Call 0x3
                    831: */
1.1.1.7   root      832: #if 0
                    833: static BOOL GemDOS_Cauxin(unsigned long Params)
1.1       root      834: {
1.1.1.9 ! root      835:        unsigned char Char;
1.1       root      836: 
1.1.1.9 ! root      837:        /* Wait here until a character is ready */
        !           838:        while(!RS232_GetStatus())
        !           839:                ;
1.1       root      840: 
1.1.1.9 ! root      841:        /* And read character */
        !           842:        RS232_ReadBytes(&Char,1);
        !           843:        Regs[REG_D0] = Char;
1.1       root      844: 
1.1.1.9 ! root      845:        return TRUE;
1.1       root      846: }
1.1.1.7   root      847: #endif
1.1       root      848: 
1.1.1.2   root      849: /*-----------------------------------------------------------------------*/
1.1       root      850: /*
                    851:   GEMDOS Cauxout
                    852:   Call 0x4
                    853: */
1.1.1.7   root      854: #if 0
                    855: static BOOL GemDOS_Cauxout(unsigned long 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 RS232 */
        !           860:        Char = STMemory_ReadWord(Params+SIZE_WORD);
        !           861:        RS232_TransferBytesTo(&Char,1);
1.1       root      862: 
1.1.1.9 ! root      863:        return TRUE;
1.1       root      864: }
1.1.1.7   root      865: #endif
1.1       root      866: 
1.1.1.2   root      867: /*-----------------------------------------------------------------------*/
1.1       root      868: /*
                    869:   GEMDOS Cprnout
                    870:   Call 0x5
                    871: */
1.1.1.7   root      872: static BOOL GemDOS_Cprnout(unsigned long Params)
1.1       root      873: {
1.1.1.9 ! root      874:        unsigned char Char;
1.1       root      875: 
1.1.1.9 ! root      876:        /* Send character to printer(or file) */
        !           877:        Char = STMemory_ReadWord(Params+SIZE_WORD);
        !           878:        Printer_TransferByteTo(Char);
        !           879:        Regs[REG_D0] = -1;                /* Printer OK */
1.1       root      880: 
1.1.1.9 ! root      881:        return TRUE;
1.1       root      882: }
                    883: 
1.1.1.2   root      884: /*-----------------------------------------------------------------------*/
1.1       root      885: /*
                    886:   GEMDOS Set drive (0=A,1=B,2=C etc...)
                    887:   Call 0xE
                    888: */
1.1.1.7   root      889: static BOOL GemDOS_SetDrv(unsigned long Params)
1.1       root      890: {
1.1.1.9 ! root      891:        /* Read details from stack for our own use */
        !           892:        CurrentDrive = STMemory_ReadWord(Params+SIZE_WORD);
1.1       root      893: 
1.1.1.9 ! root      894:        /* Still re-direct to TOS */
        !           895:        return FALSE;
1.1       root      896: }
                    897: 
1.1.1.2   root      898: /*-----------------------------------------------------------------------*/
1.1       root      899: /*
                    900:   GEMDOS Cprnos
                    901:   Call 0x11
                    902: */
1.1.1.7   root      903: static BOOL GemDOS_Cprnos(unsigned long Params)
1.1       root      904: {
1.1.1.9 ! root      905:        /* pritner status depends if printing is enabled or not... */
        !           906:        if (ConfigureParams.Printer.bEnablePrinting)
        !           907:                Regs[REG_D0] = -1;              /* Printer OK */
        !           908:        else
        !           909:                Regs[REG_D0] = 0;               /* printer not ready if printing disabled */
1.1       root      910: 
1.1.1.9 ! root      911:        return TRUE;
1.1       root      912: }
                    913: 
1.1.1.2   root      914: /*-----------------------------------------------------------------------*/
1.1       root      915: /*
                    916:   GEMDOS Cauxis
                    917:   Call 0x12
                    918: */
1.1.1.7   root      919: #if 0
                    920: static BOOL GemDOS_Cauxis(unsigned long Params)
1.1       root      921: {
1.1.1.9 ! root      922:        /* Read our RS232 state */
        !           923:        if (RS232_GetStatus())
        !           924:                Regs[REG_D0] = -1;              /* Chars waiting */
        !           925:        else
        !           926:                Regs[REG_D0] = 0;
1.1       root      927: 
1.1.1.9 ! root      928:        return TRUE;
1.1       root      929: }
1.1.1.7   root      930: #endif
1.1       root      931: 
1.1.1.2   root      932: /*-----------------------------------------------------------------------*/
1.1       root      933: /*
                    934:   GEMDOS Cauxos
                    935:   Call 0x13
                    936: */
1.1.1.7   root      937: #if 0
                    938: static BOOL GemDOS_Cauxos(unsigned long Params)
1.1       root      939: {
1.1.1.9 ! root      940:        Regs[REG_D0] = -1;                /* Device ready */
1.1       root      941: 
1.1.1.9 ! root      942:        return TRUE;
1.1       root      943: }
1.1.1.7   root      944: #endif
1.1       root      945: 
1.1.1.2   root      946: /*-----------------------------------------------------------------------*/
1.1       root      947: /*
                    948:   GEMDOS Set Disc Transfer Address (DTA)
                    949:   Call 0x1A
                    950: */
1.1.1.7   root      951: static BOOL GemDOS_SetDTA(unsigned long Params)
1.1       root      952: {
1.1.1.9 ! root      953:        /* Look up on stack to find where DTA is! Store as PC pointer */
        !           954:        pDTA = (DTA *)STRAM_ADDR(STMemory_ReadLong(Params+SIZE_WORD));
1.1       root      955: 
1.1.1.9 ! root      956:        return FALSE;
1.1       root      957: }
                    958: 
1.1.1.2   root      959: /*-----------------------------------------------------------------------*/
                    960: /*
                    961:   GEMDOS Dfree Free disc space.
                    962:   Call 0x39
                    963: */
1.1.1.7   root      964: static BOOL GemDOS_DFree(unsigned long Params)
1.1.1.2   root      965: {
1.1.1.9 ! root      966:        int Drive;
        !           967:        unsigned long Address;
        !           968: 
        !           969:        Address = (unsigned long)STMemory_ReadLong(Params+SIZE_WORD);
        !           970:        Drive = STMemory_ReadWord(Params+SIZE_WORD+SIZE_LONG);
        !           971:        /* is it our drive? */
        !           972:        if ((Drive == 0 && CurrentDrive >= 2) || Drive >= 3)
        !           973:        {
        !           974:                /* FIXME: Report actual free drive space */
        !           975: 
        !           976:                STMemory_WriteLong(Address,  10*2048);           /* free clusters (mock 10 Mb) */
        !           977:                STMemory_WriteLong(Address+SIZE_LONG, 50*2048 ); /* total clusters (mock 50 Mb) */
1.1.1.2   root      978: 
1.1.1.9 ! root      979:                STMemory_WriteLong(Address+SIZE_LONG*2, 512 );   /* bytes per sector */
        !           980:                STMemory_WriteLong(Address+SIZE_LONG*3, 1 );     /* sectors per cluster */
        !           981:                return TRUE;
        !           982:        }
        !           983:        else
        !           984:                return FALSE; /* redirect to TOS */
1.1.1.2   root      985: }
                    986: 
                    987: /*-----------------------------------------------------------------------*/
1.1       root      988: /*
                    989:   GEMDOS MkDir
                    990:   Call 0x39
                    991: */
1.1.1.7   root      992: static BOOL GemDOS_MkDir(unsigned long Params)
1.1.1.6   root      993: {
1.1.1.9 ! root      994:        char szDirPath[MAX_PATH];
        !           995:        char *pDirName;
        !           996:        int Drive;
        !           997: 
        !           998:        /* Find directory to make */
        !           999:        pDirName = (char *)STRAM_ADDR(STMemory_ReadLong(Params+SIZE_WORD));
        !          1000: 
        !          1001:        Drive = GemDOS_IsFileNameAHardDrive(pDirName);
        !          1002: 
        !          1003:        if (ISHARDDRIVE(Drive))
        !          1004:        {
        !          1005:                /* Copy old directory, as if calls fails keep this one */
        !          1006:                GemDOS_CreateHardDriveFileName(Drive,pDirName,szDirPath);
        !          1007: 
        !          1008:                /* Attempt to make directory */
        !          1009:                if ( mkdir(szDirPath, 0755)==0 )
        !          1010:                        Regs[REG_D0] = GEMDOS_EOK;
        !          1011:                else
        !          1012:                        Regs[REG_D0] = GEMDOS_EACCDN;        /* Access denied */
        !          1013: 
        !          1014:                return TRUE;
        !          1015:        }
        !          1016:        return FALSE;
1.1       root     1017: }
                   1018: 
1.1.1.2   root     1019: /*-----------------------------------------------------------------------*/
1.1       root     1020: /*
                   1021:   GEMDOS RmDir
                   1022:   Call 0x3A
                   1023: */
1.1.1.7   root     1024: static BOOL GemDOS_RmDir(unsigned long Params)
1.1.1.6   root     1025: {
1.1.1.9 ! root     1026:        char szDirPath[MAX_PATH];
        !          1027:        char *pDirName;
        !          1028:        int Drive;
        !          1029: 
        !          1030:        /* Find directory to make */
        !          1031:        pDirName = (char *)STRAM_ADDR(STMemory_ReadLong(Params+SIZE_WORD));
        !          1032:        Drive = GemDOS_IsFileNameAHardDrive(pDirName);
        !          1033:        if (ISHARDDRIVE(Drive))
        !          1034:        {
        !          1035:                /* Copy old directory, as if calls fails keep this one */
        !          1036:                GemDOS_CreateHardDriveFileName(Drive,pDirName,szDirPath);
        !          1037: 
        !          1038:                /* Attempt to make directory */
        !          1039:                if ( rmdir(szDirPath)==0 )
        !          1040:                        Regs[REG_D0] = GEMDOS_EOK;
        !          1041:                else
        !          1042:                        Regs[REG_D0] = GEMDOS_EACCDN;        /* Access denied */
        !          1043: 
        !          1044:                return TRUE;
        !          1045:        }
        !          1046:        return FALSE;
1.1       root     1047: }
                   1048: 
1.1.1.2   root     1049: /*-----------------------------------------------------------------------*/
1.1       root     1050: /*
                   1051:   GEMDOS ChDir
                   1052:   Call 0x3B
                   1053: */
1.1.1.7   root     1054: static BOOL GemDOS_ChDir(unsigned long Params)
1.1.1.6   root     1055: {
1.1.1.9 ! root     1056:        char szDirPath[MAX_PATH];
        !          1057:        char *pDirName;
        !          1058:        int Drive;
1.1       root     1059: 
1.1.1.9 ! root     1060:        /* Find new directory */
        !          1061:        pDirName = (char *)STRAM_ADDR(STMemory_ReadLong(Params+SIZE_WORD));
1.1.1.6   root     1062: #if FILE_DEBUG
1.1.1.3   root     1063: 
1.1.1.9 ! root     1064:        fprintf(stderr,"chdir %s\n",pDirName);
        !          1065: #endif
1.1.1.3   root     1066: 
1.1.1.9 ! root     1067:        Drive = GemDOS_IsFileNameAHardDrive(pDirName);
1.1.1.3   root     1068: 
1.1.1.9 ! root     1069:        if (ISHARDDRIVE(Drive))
        !          1070:        {
1.1.1.3   root     1071: 
1.1.1.9 ! root     1072:                struct stat buf;
1.1.1.3   root     1073: 
1.1.1.9 ! root     1074:                GemDOS_CreateHardDriveFileName(Drive,pDirName,szDirPath);
        !          1075:                if (stat(szDirPath,&buf))
        !          1076:                { /* error */
        !          1077:                        Regs[REG_D0] = GEMDOS_EPTHNF;
        !          1078:                        return TRUE;
        !          1079:                }
        !          1080: 
        !          1081:                strcat(szDirPath, "/");
        !          1082: 
        !          1083:                /* remove any trailing slashes */
        !          1084:                if (szDirPath[strlen(szDirPath)-2]=='/')
        !          1085:                        szDirPath[strlen(szDirPath)-1] = '\0';     /* then remove it! */
        !          1086: 
        !          1087:                strcpy(emudrives[0]->fs_currpath, szDirPath);
        !          1088:                Regs[REG_D0] = GEMDOS_EOK;
        !          1089:                return TRUE;
        !          1090:        }
1.1.1.6   root     1091: 
1.1.1.9 ! root     1092:        return FALSE;
1.1       root     1093: }
                   1094: 
1.1.1.2   root     1095: /*-----------------------------------------------------------------------*/
1.1       root     1096: /*
                   1097:   GEMDOS Create file
                   1098:   Call 0x3C
                   1099: */
1.1.1.7   root     1100: static BOOL GemDOS_Create(unsigned long Params)
1.1       root     1101: {
1.1.1.9 ! root     1102:        char szActualFileName[MAX_PATH];
        !          1103:        char *pszFileName;
        !          1104:        const char *rwflags[] =
        !          1105:                {
        !          1106:                        "w+", /* read / write (truncate if exists) */
        !          1107:                        "wb"  /* write only */
        !          1108:                };
        !          1109:        int Drive,Index,Mode;
        !          1110: 
        !          1111:        /* Find filename */
        !          1112:        pszFileName = (char *)STRAM_ADDR(STMemory_ReadLong(Params+SIZE_WORD));
        !          1113:        Mode = STMemory_ReadWord(Params+SIZE_WORD+SIZE_LONG);
        !          1114:        Drive = GemDOS_IsFileNameAHardDrive(pszFileName);
        !          1115:        if (ISHARDDRIVE(Drive))
        !          1116:        {
        !          1117:                /* And convert to hard drive filename */
        !          1118:                GemDOS_CreateHardDriveFileName(Drive,pszFileName,szActualFileName);
        !          1119: 
        !          1120:                /* Find slot to store file handle, as need to return WORD handle for ST */
        !          1121:                Index = GemDOS_FindFreeFileHandle();
        !          1122:                if (Index==-1)
        !          1123:                {
        !          1124:                        /* No free handles, return error code */
        !          1125:                        Regs[REG_D0] = GEMDOS_ENHNDL;       /* No more handles */
        !          1126:                        return TRUE;
        !          1127:                }
        !          1128:                else
        !          1129:                {
1.1       root     1130: #ifdef ENABLE_SAVING
                   1131: 
1.1.1.9 ! root     1132:                        FileHandles[Index].FileHandle = fopen(szActualFileName, rwflags[Mode&0x01]);
1.1.1.2   root     1133: 
1.1.1.9 ! root     1134:                        if (FileHandles[Index].FileHandle != NULL)
        !          1135:                        {
        !          1136:                                /* Tag handle table entry as used and return handle */
        !          1137:                                FileHandles[Index].bUsed = TRUE;
        !          1138:                                Regs[REG_D0] = Index+BASE_FILEHANDLE;  /* Return valid ST file handle from range 6 to 45! (ours start from 0) */
        !          1139:                                return TRUE;
        !          1140:                        }
        !          1141:                        else
        !          1142:                        {
        !          1143:                                Regs[REG_D0] = GEMDOS_EFILNF;     /* File not found */
        !          1144:                                return TRUE;
        !          1145:                        }
1.1       root     1146: #else
1.1.1.9 ! root     1147:                        Regs[REG_D0] = GEMDOS_EFILNF;         /* File not found */
        !          1148:                        return TRUE;
1.1       root     1149: #endif
                   1150: 
1.1.1.9 ! root     1151:                }
        !          1152:        }
        !          1153: 
        !          1154:        return FALSE;
1.1       root     1155: }
                   1156: 
1.1.1.2   root     1157: /*-----------------------------------------------------------------------*/
1.1       root     1158: /*
                   1159:   GEMDOS Open file
                   1160:   Call 0x3D
                   1161: */
1.1.1.7   root     1162: static BOOL GemDOS_Open(unsigned long Params)
1.1       root     1163: {
1.1.1.9 ! root     1164:        char szActualFileName[MAX_PATH];
        !          1165:        char *pszFileName;
        !          1166:        const char *open_modes[] =
        !          1167:                { "rb", "wb", "r+", "rb"
        !          1168:                }
        !          1169:                ;  /* convert atari modes to stdio modes */
        !          1170:        int Drive,Index,Mode;
        !          1171: 
        !          1172:        /* Find filename */
        !          1173:        pszFileName = (char *)STRAM_ADDR(STMemory_ReadLong(Params+SIZE_WORD));
        !          1174:        Mode = STMemory_ReadWord(Params+SIZE_WORD+SIZE_LONG);
        !          1175:        Drive = GemDOS_IsFileNameAHardDrive(pszFileName);
        !          1176: 
        !          1177:        if (ISHARDDRIVE(Drive))
        !          1178:        {
        !          1179:                /* And convert to hard drive filename */
        !          1180:                GemDOS_CreateHardDriveFileName(Drive,pszFileName,szActualFileName);
        !          1181:                /* Find slot to store file handle, as need to return WORD handle for ST  */
        !          1182:                Index = GemDOS_FindFreeFileHandle();
        !          1183:                if (Index == -1)
        !          1184:                {
        !          1185:                        /* No free handles, return error code */
        !          1186:                        Regs[REG_D0] = GEMDOS_ENHNDL;       /* No more handles */
        !          1187:                        return TRUE;
        !          1188:                }
        !          1189: 
        !          1190:                /* Open file */
        !          1191:                FileHandles[Index].FileHandle =  fopen(szActualFileName, open_modes[Mode&0x03]);
        !          1192: 
        !          1193:                sprintf(FileHandles[Index].szActualName,"%s",szActualFileName);
        !          1194: 
        !          1195:                if (FileHandles[Index].FileHandle != NULL)
        !          1196:                {
        !          1197:                        /* Tag handle table entry as used and return handle */
        !          1198:                        FileHandles[Index].bUsed = TRUE;
        !          1199:                        Regs[REG_D0] = Index+BASE_FILEHANDLE;  /* Return valid ST file handle from range 6 to 45! (ours start from 0) */
        !          1200:                        return TRUE;
        !          1201:                }
        !          1202:                Regs[REG_D0] = GEMDOS_EFILNF;     /* File not found/ error opening */
        !          1203:                return TRUE;
        !          1204:        }
1.1.1.6   root     1205: 
1.1.1.9 ! root     1206:        return FALSE;
1.1       root     1207: }
                   1208: 
1.1.1.2   root     1209: /*-----------------------------------------------------------------------*/
1.1       root     1210: /*
                   1211:   GEMDOS Close file
1.1.1.6   root     1212:   Call 0x3E
1.1       root     1213: */
1.1.1.7   root     1214: static BOOL GemDOS_Close(unsigned long Params)
1.1       root     1215: {
1.1.1.9 ! root     1216:        int Handle;
1.1       root     1217: 
1.1.1.9 ! root     1218:        /* Find our handle - may belong to TOS */
        !          1219:        Handle = STMemory_ReadWord(Params+SIZE_WORD)-BASE_FILEHANDLE;
1.1       root     1220: 
1.1.1.9 ! root     1221:        /* Check handle was valid */
        !          1222:        if (GemDOS_IsInvalidFileHandle(Handle))
        !          1223:        {
        !          1224:                /* No assume was TOS */
        !          1225:                return FALSE;
        !          1226:        }
        !          1227:        else
        !          1228:        {
        !          1229:                /* Close file and free up handle table */
        !          1230:                fclose(FileHandles[Handle].FileHandle);
        !          1231:                FileHandles[Handle].bUsed = FALSE;
        !          1232:                /* Return no error */
        !          1233:                Regs[REG_D0] = GEMDOS_EOK;
        !          1234:                return TRUE;
        !          1235:        }
1.1       root     1236: }
                   1237: 
1.1.1.2   root     1238: /*-----------------------------------------------------------------------*/
1.1       root     1239: /*
                   1240:   GEMDOS Read file
                   1241:   Call 0x3F
                   1242: */
1.1.1.7   root     1243: static BOOL GemDOS_Read(unsigned long Params)
1.1       root     1244: {
1.1.1.9 ! root     1245:        char *pBuffer;
        !          1246:        unsigned long nBytesRead,Size,CurrentPos,FileSize;
        !          1247:        long nBytesLeft;
        !          1248:        int Handle;
        !          1249: 
        !          1250:        /* Read details from stack */
        !          1251:        Handle = STMemory_ReadWord(Params+SIZE_WORD)-BASE_FILEHANDLE;
        !          1252:        Size = STMemory_ReadLong(Params+SIZE_WORD+SIZE_WORD);
        !          1253:        pBuffer = (char *)STRAM_ADDR(STMemory_ReadLong(Params+SIZE_WORD+SIZE_WORD+SIZE_LONG));
        !          1254: 
        !          1255:        /* Check handle was valid */
        !          1256:        if (GemDOS_IsInvalidFileHandle(Handle))
        !          1257:        {
        !          1258:                /* No -  assume was TOS */
        !          1259:                return FALSE;
        !          1260:        }
        !          1261:        else
        !          1262:        {
        !          1263: 
        !          1264:                /* To quick check to see where our file pointer is and how large the file is */
        !          1265:                CurrentPos = ftell(FileHandles[Handle].FileHandle);
        !          1266:                fseek(FileHandles[Handle].FileHandle, 0, SEEK_END);
        !          1267:                FileSize = ftell(FileHandles[Handle].FileHandle);
        !          1268:                fseek(FileHandles[Handle].FileHandle, CurrentPos, SEEK_SET);
        !          1269: 
        !          1270:                nBytesLeft = FileSize-CurrentPos;
        !          1271: 
        !          1272:                /* Check for End Of File */
        !          1273:                if (nBytesLeft == 0)
        !          1274:                {
        !          1275:                        /* FIXME: should we return zero (bytes read) or an error? */
        !          1276:                        Regs[REG_D0] = 0;
        !          1277:                        return TRUE;
        !          1278:                }
        !          1279:                else
        !          1280:                {
        !          1281:                        /* Limit to size of file to prevent errors */
        !          1282:                        if (Size > FileSize)
        !          1283:                                Size = FileSize;
        !          1284:                        /* And read data in */
        !          1285:                        nBytesRead = fread(pBuffer, 1, Size, FileHandles[Handle].FileHandle);
        !          1286: 
        !          1287:                        /* Return number of bytes read */
        !          1288:                        Regs[REG_D0] = nBytesRead;
        !          1289: 
        !          1290:                        return TRUE;
        !          1291:                }
        !          1292:        }
1.1       root     1293: }
                   1294: 
1.1.1.2   root     1295: /*-----------------------------------------------------------------------*/
1.1       root     1296: /*
                   1297:   GEMDOS Write file
                   1298:   Call 0x40
                   1299: */
1.1.1.7   root     1300: static BOOL GemDOS_Write(unsigned long Params)
1.1       root     1301: {
1.1.1.9 ! root     1302:        char *pBuffer;
        !          1303:        unsigned long Size,nBytesWritten;
        !          1304:        int Handle;
1.1       root     1305: 
                   1306: #ifdef ENABLE_SAVING
1.1.1.9 ! root     1307:        /* Read details from stack */
        !          1308:        Handle = STMemory_ReadWord(Params+SIZE_WORD)-BASE_FILEHANDLE;
        !          1309:        Size = STMemory_ReadLong(Params+SIZE_WORD+SIZE_WORD);
        !          1310:        pBuffer = (char *)STRAM_ADDR(STMemory_ReadLong(Params+SIZE_WORD+SIZE_WORD+SIZE_LONG));
        !          1311: 
        !          1312:        /* Check handle was valid */
        !          1313:        if (GemDOS_IsInvalidFileHandle(Handle))
        !          1314:        {
        !          1315:                /* No assume was TOS */
        !          1316:                return FALSE;
        !          1317:        }
        !          1318:        else
        !          1319:        {
1.1       root     1320: 
1.1.1.9 ! root     1321:                nBytesWritten = fwrite(pBuffer, 1, Size, FileHandles[Handle].FileHandle);
        !          1322:                if (nBytesWritten >= 0)
        !          1323:                {
        !          1324: 
        !          1325:                        Regs[REG_D0] = nBytesWritten;      /* OK */
        !          1326:                }
        !          1327:                else
        !          1328:                        Regs[REG_D0] = GEMDOS_EACCDN;      /* Access denied(ie read-only) */
        !          1329: 
        !          1330:                return TRUE;
        !          1331:        }
1.1       root     1332: #endif
                   1333: 
1.1.1.9 ! root     1334:        return FALSE;
1.1       root     1335: }
                   1336: 
1.1.1.2   root     1337: /*-----------------------------------------------------------------------*/
1.1       root     1338: /*
                   1339:   GEMDOS UnLink(Delete) file
                   1340:   Call 0x41
                   1341: */
1.1.1.7   root     1342: static BOOL GemDOS_UnLink(unsigned long Params)
1.1       root     1343: {
                   1344: #ifdef ENABLE_SAVING
1.1.1.9 ! root     1345:        char szActualFileName[MAX_PATH];
        !          1346:        char *pszFileName;
        !          1347:        int Drive;
        !          1348: 
        !          1349:        /* Find filename */
        !          1350:        pszFileName = (char *)STRAM_ADDR(STMemory_ReadLong(Params+SIZE_WORD));
        !          1351:        Drive = GemDOS_IsFileNameAHardDrive(pszFileName);
        !          1352:        if (ISHARDDRIVE(Drive))
        !          1353:        {
        !          1354:                /* And convert to hard drive filename */
        !          1355:                GemDOS_CreateHardDriveFileName(Drive,pszFileName,szActualFileName);
1.1       root     1356: 
1.1.1.9 ! root     1357:                /* Now delete file?? */
        !          1358:                if ( unlink(szActualFileName)==0 )
        !          1359:                        Regs[REG_D0] = GEMDOS_EOK;          /* OK */
        !          1360:                else
        !          1361:                        Regs[REG_D0] = GEMDOS_EFILNF;       /* File not found */
        !          1362: 
        !          1363:                return TRUE;
        !          1364:        }
1.1       root     1365: #endif
                   1366: 
1.1.1.9 ! root     1367:        return FALSE;
1.1       root     1368: }
                   1369: 
1.1.1.2   root     1370: /*-----------------------------------------------------------------------*/
1.1       root     1371: /*
                   1372:   GEMDOS File seek
                   1373:   Call 0x42
                   1374: */
1.1.1.7   root     1375: static BOOL GemDOS_LSeek(unsigned long Params)
1.1       root     1376: {
1.1.1.9 ! root     1377:        long Offset;
        !          1378:        int Handle,Mode;
        !          1379: 
        !          1380:        /* Read details from stack */
        !          1381:        Offset = (long)STMemory_ReadLong(Params+SIZE_WORD);
        !          1382:        Handle = STMemory_ReadWord(Params+SIZE_WORD+SIZE_LONG)-BASE_FILEHANDLE;
        !          1383:        Mode = STMemory_ReadWord(Params+SIZE_WORD+SIZE_LONG+SIZE_WORD);
1.1       root     1384: 
1.1.1.9 ! root     1385:        /* Check handle was valid */
        !          1386:        if (GemDOS_IsInvalidFileHandle(Handle))
        !          1387:        {
        !          1388:                /* No assume was TOS */
        !          1389:                return FALSE;
        !          1390:        }
        !          1391:        else
        !          1392:        {
        !          1393:                /* Return offset from start of file */
        !          1394:                fseek(FileHandles[Handle].FileHandle, Offset, Mode);
        !          1395:                Regs[REG_D0] = ftell(FileHandles[Handle].FileHandle);
        !          1396:                return TRUE;
        !          1397:        }
1.1       root     1398: }
                   1399: 
1.1.1.2   root     1400: /*-----------------------------------------------------------------------*/
                   1401: /*
                   1402:   GEMDOS Get Directory
                   1403:   Call 0x47
                   1404: */
1.1.1.9 ! root     1405: static int GemDOS_GetDir(unsigned long Params)
        !          1406: {
        !          1407:        unsigned long Address;
        !          1408:        unsigned short Drive;
        !          1409: 
        !          1410:        Address = (long)STMemory_ReadLong(Params+SIZE_WORD);
        !          1411:        Drive = STMemory_ReadWord(Params+SIZE_WORD+SIZE_LONG);
        !          1412:        /* is it our drive? */
        !          1413:        if ((Drive == 0 && CurrentDrive >= 2) || Drive >= 3)
        !          1414:        {
        !          1415:                char path[MAX_PATH];
        !          1416:                int i,len,c;
        !          1417: 
        !          1418:                Regs[REG_D0] = GEMDOS_EOK;          /* OK */
        !          1419:                strcpy(path,&emudrives[0]->fs_currpath[strlen(emudrives[0]->hd_emulation_dir)]);
        !          1420:                // convertit en path st (dos)
        !          1421:                len = strlen(path)-1;
        !          1422:                path[len] = 0;
        !          1423:                for (i = 0; i <= len; i++)
        !          1424:                {
        !          1425:                        c = path[i];
        !          1426:                        STMemory_WriteByte(Address+i, (c=='/' ? '\\' : c) );
        !          1427:                }
1.1.1.6   root     1428: #if FILE_DEBUG
1.1.1.9 ! root     1429:                fprintf(stderr,"curdir %d -> %s\n",Drive,path);
1.1.1.6   root     1430: #endif
1.1.1.9 ! root     1431: 
        !          1432:                return TRUE;
        !          1433:        }
        !          1434:        else return FALSE;
1.1.1.2   root     1435: }
                   1436: 
                   1437: /*-----------------------------------------------------------------------*/
1.1       root     1438: /*
                   1439:   PExec Load And Go - Redirect to cart' routine at address 0xFA1000
1.1.1.9 ! root     1440:  
1.1       root     1441:   If loading from hard-drive(ie drive ID 2 or more) set condition codes to run own GEMDos routines
                   1442: */
1.1.1.7   root     1443: static int GemDOS_Pexec_LoadAndGo(unsigned long Params)
1.1       root     1444: {
1.1.1.9 ! root     1445:        /* add multiple disk support here too */
        !          1446:        /* Hard-drive? */
        !          1447:        if (CurrentDrive == emudrives[0]->hd_letter)
        !          1448:        {
        !          1449:                /* If not using A: or B:, use my own routines to load */
        !          1450:                return CALL_PEXEC_ROUTINE;
        !          1451:        }
        !          1452:        else return FALSE;
1.1       root     1453: }
                   1454: 
1.1.1.2   root     1455: /*-----------------------------------------------------------------------*/
1.1       root     1456: /*
                   1457:   PExec Load But Don't Go - Redirect to cart' routine at address 0xFA1000
                   1458: */
1.1.1.7   root     1459: static int GemDOS_Pexec_LoadDontGo(unsigned long Params)
1.1       root     1460: {
1.1.1.9 ! root     1461:        /* Hard-drive? */
        !          1462:        if (CurrentDrive == emudrives[0]->hd_letter)
        !          1463:        {
        !          1464:                return CALL_PEXEC_ROUTINE;
        !          1465:        }
        !          1466:        else return FALSE;
1.1       root     1467: }
                   1468: 
1.1.1.2   root     1469: /*-----------------------------------------------------------------------*/
1.1       root     1470: /*
                   1471:   GEMDOS PExec handler
                   1472:   Call 0x4B
                   1473: */
1.1.1.7   root     1474: static int GemDOS_Pexec(unsigned long Params)
1.1       root     1475: {
1.1.1.9 ! root     1476:        unsigned short int Mode;
1.1       root     1477: 
1.1.1.9 ! root     1478:        /* Find PExec mode */
        !          1479:        Mode = STMemory_ReadWord(Params+SIZE_WORD);
1.1       root     1480: 
1.1.1.9 ! root     1481:        /* Re-direct as needed */
        !          1482:        switch(Mode)
        !          1483:        {
        !          1484:         case 0:      /* Load and go */
        !          1485:                return GemDOS_Pexec_LoadAndGo(Params);
        !          1486:         case 3:      /* Load, don't go */
        !          1487:                return GemDOS_Pexec_LoadDontGo(Params);
        !          1488:         case 4:      /* Just go */
        !          1489:                return FALSE;
        !          1490:         case 5:      /* Create basepage */
        !          1491:                return FALSE;
        !          1492:         case 6:
        !          1493:                return FALSE;
1.1       root     1494: 
1.1.1.9 ! root     1495:         default:
        !          1496:                return FALSE;
        !          1497:        }
        !          1498: 
        !          1499:        /* Still re-direct to TOS */
        !          1500:        return FALSE;
1.1       root     1501: }
                   1502: 
1.1.1.4   root     1503: 
                   1504: /*-----------------------------------------------------------------------*/
                   1505: /*
                   1506:   GEMDOS Search Next
                   1507:   Call 0x4F
                   1508: */
1.1.1.7   root     1509: static BOOL GemDOS_SNext(unsigned long Params)
1.1.1.4   root     1510: {
1.1.1.9 ! root     1511:        struct dirent **temp;
        !          1512:        int Index;
        !          1513: 
        !          1514:        /* Refresh pDTA pointer (from the current basepage) */
        !          1515:        pDTA = (DTA *)STRAM_ADDR(STMemory_ReadLong(STMemory_ReadLong(act_pd)+32));
1.1.1.4   root     1516: 
1.1.1.9 ! root     1517:        /* Was DTA ours or TOS? */
        !          1518:        if (do_get_mem_long(pDTA->magic) == DTA_MAGIC_NUMBER)
        !          1519:        {
        !          1520: 
        !          1521:                /* Find index into our list of structures */
        !          1522:                Index = do_get_mem_word(pDTA->index) & (MAX_DTAS_FILES-1);
1.1.1.6   root     1523: 
1.1.1.9 ! root     1524:                if (InternalDTAs[Index].centry >= InternalDTAs[Index].nentries)
        !          1525:                {
        !          1526:                        Regs[REG_D0] = GEMDOS_ENMFIL;    /* No more files */
        !          1527:                        return TRUE;
        !          1528:                }
        !          1529: 
        !          1530:                temp = InternalDTAs[Index].found;
        !          1531:                if (PopulateDTA(InternalDTAs[Index].path, temp[InternalDTAs[Index].centry++]) == FALSE)
        !          1532:                {
        !          1533:                        fprintf(stderr,"\tError setting DTA.\n");
        !          1534:                        return TRUE;
        !          1535:                }
1.1.1.4   root     1536: 
1.1.1.9 ! root     1537:                Regs[REG_D0] = GEMDOS_EOK;
        !          1538:                return TRUE;
        !          1539:        }
1.1.1.4   root     1540: 
1.1.1.9 ! root     1541:        return FALSE;
1.1.1.4   root     1542: }
                   1543: 
                   1544: 
1.1.1.2   root     1545: /*-----------------------------------------------------------------------*/
1.1       root     1546: /*
                   1547:   GEMDOS Find first file
                   1548:   Call 0x4E
                   1549: */
1.1.1.7   root     1550: static BOOL GemDOS_SFirst(unsigned long Params)
1.1       root     1551: {
1.1.1.9 ! root     1552:        char szActualFileName[MAX_PATH];
        !          1553:        char tempstr[MAX_PATH];
        !          1554:        char *pszFileName;
        !          1555:        struct dirent **files;
        !          1556:        unsigned short int Attr;
        !          1557:        int Drive;
        !          1558:        DIR *fsdir;
        !          1559:        int i,j,count;
        !          1560: 
        !          1561:        /* Find filename to search for */
        !          1562:        pszFileName = (char *)STRAM_ADDR(STMemory_ReadLong(Params+SIZE_WORD));
        !          1563:        Attr = STMemory_ReadWord(Params+SIZE_WORD+SIZE_LONG);
        !          1564: 
        !          1565:        /* Refresh pDTA pointer (from the current basepage) */
        !          1566:        pDTA = (DTA *)STRAM_ADDR(STMemory_ReadLong(STMemory_ReadLong(act_pd)+32));
        !          1567: 
        !          1568:        Drive = GemDOS_IsFileNameAHardDrive(pszFileName);
        !          1569:        if (ISHARDDRIVE(Drive))
        !          1570:        {
        !          1571: 
        !          1572:                /* And convert to hard drive filename */
        !          1573:                GemDOS_CreateHardDriveFileName(Drive,pszFileName,szActualFileName);
        !          1574: 
        !          1575:                /* Populate DTA, set index for our use */
        !          1576:                do_put_mem_word(pDTA->index, DTAIndex);
        !          1577:                /* set our dta magic num */
        !          1578:                do_put_mem_long(pDTA->magic, DTA_MAGIC_NUMBER);
        !          1579: 
        !          1580:                if (InternalDTAs[DTAIndex].bUsed == TRUE)
        !          1581:                        ClearInternalDTA();
        !          1582:                InternalDTAs[DTAIndex].bUsed = TRUE;
        !          1583: 
        !          1584:                /* Were we looking for the volume label? */
        !          1585:                if (Attr == GEMDOS_FILE_ATTRIB_VOLUME_LABEL)
        !          1586:                {
        !          1587:                        /* Volume name */
        !          1588:                        strcpy(pDTA->dta_name,"EMULATED.001");
        !          1589:                        Regs[REG_D0] = GEMDOS_EOK;          /* Got volume */
        !          1590:                        return TRUE;
        !          1591:                }
        !          1592: 
        !          1593:                /* open directory */
        !          1594:                fsfirst_dirname(szActualFileName, InternalDTAs[DTAIndex].path);
        !          1595:                fsdir = opendir(InternalDTAs[DTAIndex].path);
        !          1596: 
        !          1597:                if (fsdir == NULL)
        !          1598:                {
        !          1599:                        Regs[REG_D0] = GEMDOS_EPTHNF;        /* Path not found */
        !          1600:                        return TRUE;
        !          1601:                }
        !          1602:                /* close directory */
        !          1603:                closedir(fsdir);
        !          1604: 
        !          1605:                count = scandir(InternalDTAs[DTAIndex].path, &files, 0, alphasort);
        !          1606:                /* File (directory actually) not found */
        !          1607:                if (count < 0)
        !          1608:                {
        !          1609:                        Regs[REG_D0] = GEMDOS_EFILNF;
        !          1610:                        return TRUE;
        !          1611:                }
        !          1612: 
        !          1613:                InternalDTAs[DTAIndex].centry = 0;          /* current entry is 0 */
        !          1614:                fsfirst_dirmask(szActualFileName, tempstr); /* get directory mask */
        !          1615:                InternalDTAs[DTAIndex].found = files;       /* get files */
        !          1616: 
        !          1617:                /* count & copy the entries that match our mask and discard the rest */
        !          1618:                j = 0;
        !          1619:                for (i=0; i < count; i++)
        !          1620:                        if (match(tempstr, files[i]->d_name))
        !          1621:                        {
        !          1622:                                InternalDTAs[DTAIndex].found[j] = files[i];
        !          1623:                                j++;
        !          1624:                        }
        !          1625:                        else
        !          1626:                        {
        !          1627:                                free(files[i]);
        !          1628:                        }
        !          1629:                InternalDTAs[DTAIndex].nentries = j; /* set number of legal entries */
        !          1630: 
        !          1631:                /* No files of that match, return error code */
        !          1632:                if (j==0)
        !          1633:                {
        !          1634:                        free(files);
        !          1635:                        InternalDTAs[DTAIndex].found = NULL;
        !          1636:                        Regs[REG_D0] = GEMDOS_EFILNF;        /* File not found */
        !          1637:                        return TRUE;
        !          1638:                }
        !          1639: 
        !          1640:                /* Scan for first file (SNext uses no parameters) */
        !          1641:                GemDOS_SNext(0);
        !          1642:                /* increment DTA index */
        !          1643:                DTAIndex++;
        !          1644:                DTAIndex&=(MAX_DTAS_FILES-1);
        !          1645: 
        !          1646:                return TRUE;
        !          1647:        }
        !          1648:        return FALSE;
1.1       root     1649: }
                   1650: 
                   1651: 
1.1.1.2   root     1652: /*-----------------------------------------------------------------------*/
1.1       root     1653: /*
                   1654:   GEMDOS Rename
                   1655:   Call 0x56
                   1656: */
1.1.1.7   root     1657: static BOOL GemDOS_Rename(unsigned long Params)
1.1       root     1658: {
1.1.1.9 ! root     1659:        char *pszNewFileName,*pszOldFileName;
        !          1660:        char szNewActualFileName[MAX_PATH],szOldActualFileName[MAX_PATH];
        !          1661:        int NewDrive, OldDrive;
        !          1662: 
        !          1663:        /* Read details from stack */
        !          1664:        pszOldFileName = (char *)STRAM_ADDR(STMemory_ReadLong(Params+SIZE_WORD+SIZE_WORD));
        !          1665:        pszNewFileName = (char *)STRAM_ADDR(STMemory_ReadLong(Params+SIZE_WORD+SIZE_WORD+SIZE_LONG));
        !          1666: 
        !          1667:        NewDrive = GemDOS_IsFileNameAHardDrive(pszNewFileName);
        !          1668:        OldDrive = GemDOS_IsFileNameAHardDrive(pszOldFileName);
        !          1669:        if (ISHARDDRIVE(NewDrive) && ISHARDDRIVE(OldDrive))
        !          1670:        {
        !          1671:                /* And convert to hard drive filenames */
        !          1672:                GemDOS_CreateHardDriveFileName(NewDrive,pszNewFileName,szNewActualFileName);
        !          1673:                GemDOS_CreateHardDriveFileName(OldDrive,pszOldFileName,szOldActualFileName);
        !          1674: 
        !          1675:                /* Rename files */
        !          1676:                if ( rename(szOldActualFileName,szNewActualFileName)==0 )
        !          1677:                        Regs[REG_D0] = GEMDOS_EOK;
        !          1678:                else
        !          1679:                        Regs[REG_D0] = GEMDOS_EACCDN;        /* Access denied */
        !          1680:                return TRUE;
        !          1681:        }
1.1       root     1682: 
1.1.1.9 ! root     1683:        return FALSE;
1.1       root     1684: }
                   1685: 
1.1.1.2   root     1686: /*-----------------------------------------------------------------------*/
1.1       root     1687: /*
                   1688:   GEMDOS GSDToF
                   1689:   Call 0x57
                   1690: */
1.1.1.7   root     1691: static BOOL GemDOS_GSDToF(unsigned long Params)
1.1       root     1692: {
1.1.1.9 ! root     1693:        DATETIME DateTime;
        !          1694:        unsigned long pBuffer;
        !          1695:        int Handle,Flag;
        !          1696: 
        !          1697:        /* Read details from stack */
        !          1698:        pBuffer = STMemory_ReadLong(Params+SIZE_WORD);
        !          1699:        Handle = STMemory_ReadWord(Params+SIZE_WORD+SIZE_LONG)-BASE_FILEHANDLE;
        !          1700:        Flag = STMemory_ReadWord(Params+SIZE_WORD+SIZE_WORD+SIZE_LONG);
        !          1701: 
        !          1702:        /* Check handle was valid */
        !          1703:        if (GemDOS_IsInvalidFileHandle(Handle))
        !          1704:        {
        !          1705:                /* No assume was TOS */
        !          1706:                return FALSE;
        !          1707:        }
        !          1708: 
        !          1709:        /* Set time/date stamp? Do nothing. */
        !          1710:        if (Flag == 1)
        !          1711:        {
        !          1712:                Regs[REG_D0] = GEMDOS_EOK;
        !          1713:                return TRUE;
        !          1714:        }
        !          1715: 
        !          1716:        Regs[REG_D0] = GEMDOS_ERROR;  /* Invalid parameter */
        !          1717: 
        !          1718:        if (GemDOS_GetFileInformation(FileHandles[Handle].szActualName, &DateTime) == TRUE)
        !          1719:        {
        !          1720:                STMemory_WriteWord(pBuffer, DateTime.word1);
        !          1721:                STMemory_WriteWord(pBuffer+2, DateTime.word2);
        !          1722:                Regs[REG_D0] = GEMDOS_EOK;
        !          1723:        }
        !          1724:        return TRUE;
1.1       root     1725: }
                   1726: 
1.1.1.9 ! root     1727: 
1.1       root     1728: /*-----------------------------------------------------------------------*/
                   1729: /*
                   1730:   Run GEMDos call, and re-direct if need to. Used to handle hard-disc emulation etc...
1.1.1.8   root     1731:   This sets the condition codes (in SR), which are used in the 'cart_asm.s' program to
                   1732:   decide if we need to run old GEM vector, or PExec or nothing.
1.1.1.9 ! root     1733:  
1.1       root     1734:   This method keeps the stack and other states consistant with the original ST which is very important
                   1735:   for the PExec call and maximum compatibility through-out
                   1736: */
                   1737: void GemDOS_OpCode(void)
                   1738: {
1.1.1.9 ! root     1739:        unsigned short int GemDOSCall,CallingSReg;
        !          1740:        unsigned long Params;
        !          1741:        short RunOld;
        !          1742: 
        !          1743: 
        !          1744:        /* Read SReg from stack to see if parameters are on User or Super stack  */
        !          1745:        MakeSR();  /* update value of SR */
        !          1746:        CallingSReg = STMemory_ReadWord(Regs[REG_A7]);
        !          1747:        if ((CallingSReg&SR_SUPERMODE)==0)      /* Calling from user mode */
        !          1748:                Params = regs.usp;
        !          1749:        else
        !          1750:        {
        !          1751:                Params = Regs[REG_A7]+SIZE_WORD+SIZE_LONG;  /* super stack */
        !          1752:                if (cpu_level > 0)
        !          1753:                        Params += SIZE_WORD;   /* Skip extra word whe CPU is >=68010 */
        !          1754:        }
        !          1755: 
        !          1756:        /* Default to run TOS GemDos (SR_NEG run Gemdos, SR_ZERO already done, SR_OVERFLOW run own 'Pexec' */
        !          1757:        RunOld = TRUE;
        !          1758:        SR &= SR_CLEAR_OVERFLOW;
        !          1759:        SR &= SR_CLEAR_ZERO;
        !          1760:        SR |= SR_NEG;
1.1       root     1761: 
1.1.1.9 ! root     1762:        /* Find pointer to call parameters */
        !          1763:        GemDOSCall = STMemory_ReadWord(Params);
1.1.1.2   root     1764: 
                   1765: #ifdef GEMDOS_VERBOSE
1.1.1.9 ! root     1766:        if (GemDOSCall < (sizeof(pszGemDOSNames)/sizeof(pszGemDOSNames[0])))
        !          1767:                fprintf(stderr, "GemDOS 0x%X (%s)\n",GemDOSCall,pszGemDOSNames[GemDOSCall]);
        !          1768:        else
        !          1769:                fprintf(stderr, "GemDOS 0x%X\n",GemDOSCall);
1.1       root     1770: #endif
                   1771: 
1.1.1.9 ! root     1772:        /* Intercept call */
        !          1773:        switch(GemDOSCall)
        !          1774:        {
        !          1775:         /*
        !          1776:         case 0x3:
        !          1777:                if (GemDOS_Cauxin(Params))
        !          1778:                        RunOld = FALSE;
        !          1779:                break;
        !          1780:         */
        !          1781:         /*
        !          1782:         case 0x4:
        !          1783:                if (GemDOS_Cauxout(Params))
        !          1784:                        RunOld = FALSE;
        !          1785:                break;
        !          1786:         */
        !          1787:         case 0x5:          /* direct printing via GEMDOS */
        !          1788:                if (GemDOS_Cprnout(Params))
        !          1789:                        RunOld = FALSE;
        !          1790:                break;
        !          1791:         case 0xe:
        !          1792:                if (GemDOS_SetDrv(Params))
        !          1793:                        RunOld = FALSE;
        !          1794:                break;
        !          1795:         case 0x11:         /* Printer status  */
        !          1796:                if (GemDOS_Cprnos(Params))
        !          1797:                        RunOld = FALSE;
        !          1798:                break;
        !          1799:         /*
        !          1800:         case 0x12:
        !          1801:                if (GemDOS_Cauxis(Params))
        !          1802:                        RunOld = FALSE;
        !          1803:                break;
        !          1804:         */
        !          1805:         /*
        !          1806:         case 0x13:
        !          1807:                if (GemDOS_Cauxos(Params))
        !          1808:                        RunOld = FALSE;
        !          1809:                break;
        !          1810:         */
        !          1811:         case 0x1a:
        !          1812:                if (GemDOS_SetDTA(Params))
        !          1813:                        RunOld = FALSE;
        !          1814:                break;
        !          1815:         case 0x36:
        !          1816:                if (GemDOS_DFree(Params))
        !          1817:                        RunOld = FALSE;
        !          1818:                break;
        !          1819:         case 0x39:
        !          1820:                if (GemDOS_MkDir(Params))
        !          1821:                        RunOld = FALSE;
        !          1822:                break;
        !          1823:         case 0x3a:
        !          1824:                if (GemDOS_RmDir(Params))
        !          1825:                        RunOld = FALSE;
        !          1826:                break;
        !          1827:         case 0x3b:
        !          1828:                if (GemDOS_ChDir(Params))
        !          1829:                        RunOld = FALSE;
        !          1830:                break;
        !          1831:         case 0x3c:
        !          1832:                if (GemDOS_Create(Params))
        !          1833:                        RunOld = FALSE;
        !          1834:                break;
        !          1835:         case 0x3d:
        !          1836:                if (GemDOS_Open(Params))
        !          1837:                        RunOld = FALSE;
        !          1838:                break;
        !          1839:         case 0x3e:
        !          1840:                if (GemDOS_Close(Params))
        !          1841:                        RunOld = FALSE;
        !          1842:                break;
        !          1843:         case 0x3f:
        !          1844:                if (GemDOS_Read(Params))
        !          1845:                        RunOld = FALSE;
        !          1846:                break;
        !          1847:         case 0x40:
        !          1848:                if (GemDOS_Write(Params))
        !          1849:                        RunOld = FALSE;
        !          1850:                break;
        !          1851:         case 0x41:
        !          1852:                if (GemDOS_UnLink(Params))
        !          1853:                        RunOld = FALSE;
        !          1854:                break;
        !          1855:         case 0x42:
        !          1856:                if (GemDOS_LSeek(Params))
        !          1857:                        RunOld = FALSE;
        !          1858:                break;
        !          1859:         case 0x47:
        !          1860:                if (GemDOS_GetDir(Params))
        !          1861:                        RunOld = FALSE;
        !          1862:                break;
        !          1863:         case 0x4b:
        !          1864:                if (GemDOS_Pexec(Params) == CALL_PEXEC_ROUTINE)
        !          1865:                        RunOld = CALL_PEXEC_ROUTINE;
        !          1866:                break;
        !          1867:         case 0x4e:
        !          1868:                if (GemDOS_SFirst(Params))
        !          1869:                        RunOld = FALSE;
        !          1870:                break;
        !          1871:         case 0x4f:
        !          1872:                if (GemDOS_SNext(Params))
        !          1873:                        RunOld = FALSE;
        !          1874:                break;
        !          1875:         case 0x56:
        !          1876:                if (GemDOS_Rename(Params))
        !          1877:                        RunOld = FALSE;
        !          1878:                break;
        !          1879:         case 0x57:
        !          1880:                if (GemDOS_GSDToF(Params))
        !          1881:                        RunOld = FALSE;
        !          1882:                break;
        !          1883:        }
        !          1884: 
        !          1885:        switch(RunOld)
        !          1886:        {
        !          1887:         case FALSE:        /* skip over branch to pexec to RTE */
        !          1888:                SR |= SR_ZERO;
        !          1889:                break;
        !          1890:         case CALL_PEXEC_ROUTINE:   /* branch to pexec, then redirect to old gemdos. */
        !          1891:                SR |= SR_OVERFLOW;
        !          1892:                break;
        !          1893:        }
1.1       root     1894: 
1.1.1.9 ! root     1895:        MakeFromSR();  /* update the flags from the SR register */
1.1       root     1896: }
                   1897: 
1.1.1.9 ! root     1898: 
1.1.1.2   root     1899: /*-----------------------------------------------------------------------*/
1.1       root     1900: /*
1.1.1.2   root     1901:   GemDOS_Boot - routine called on the first occurence of the gemdos opcode.
1.1.1.3   root     1902:   (this should be in the cartridge bootrom)
                   1903:   Sets up our gemdos handler (or, if we don't need one, just turn off keyclicks)
1.1.1.2   root     1904:  */
1.1.1.7   root     1905: void GemDOS_Boot(void)
1.1.1.2   root     1906: {
1.1.1.9 ! root     1907:        bInitGemDOS = TRUE;
1.1.1.2   root     1908: 
1.1.1.3   root     1909: #ifdef GEMDOS_VERBOSE
1.1.1.9 ! root     1910:        fprintf(stderr, "Gemdos_Boot()\n");
1.1.1.3   root     1911: #endif
1.1.1.9 ! root     1912: 
        !          1913:        /* install our gemdos handler, if -e or --harddrive option used */
        !          1914:        if (GEMDOS_EMU_ON)
        !          1915:        {
        !          1916:                /* Get the address of the p_run variable that points to the actual basepage */
        !          1917:                if (TosVersion == 0x100)
        !          1918:                {
        !          1919:                        /* We have to use fix addresses on TOS 1.00 :-( */
        !          1920:                        if ((STMemory_ReadWord(TosAddress+28)>>1) == 4)
        !          1921:                                act_pd = 0x873c;    /* Spanish TOS is different from others! */
        !          1922:                        else
        !          1923:                                act_pd = 0x602c;
        !          1924:                }
        !          1925:                else
        !          1926:                {
        !          1927:                        act_pd = STMemory_ReadLong(TosAddress + 0x28);
        !          1928:                }
        !          1929: 
        !          1930:                /* Save old GEMDOS handler adress */
        !          1931:                STMemory_WriteLong(CART_OLDGEMDOS, STMemory_ReadLong(0x0084));
        !          1932:                /* Setup new GEMDOS handler, see "cart_asm.s" */
        !          1933:                STMemory_WriteLong(0x0084, CART_GEMDOS);
        !          1934:        }
1.1       root     1935: }
1.1.1.2   root     1936: 

unix.superglobalmegacorp.com

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