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

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

unix.superglobalmegacorp.com

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