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

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

unix.superglobalmegacorp.com

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