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

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

unix.superglobalmegacorp.com

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