Annotation of frontvm/hardware/hostcall.c, revision 1.1

1.1     ! root        1: /*
        !             2:   Hatari - gemdos.c
        !             3: 
        !             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.
        !             9: 
        !            10:   Now case is handled by using glob. See the function
        !            11:   GemDOS_CreateHardDriveFileName for that. It also knows about symlinks.
        !            12:   A filename is recognized on its eight first characters, do don't try to
        !            13:   push this too far, or you'll get weirdness ! (But I can even run programs
        !            14:   directly from a mounted cd in lower cases, so I guess it's working well !).
        !            15: */
        !            16: 
        !            17: #include <sys/stat.h>
        !            18: #include <time.h>
        !            19: #include <dirent.h>
        !            20: #include <ctype.h>
        !            21: #include <unistd.h>
        !            22: #include <glob.h>
        !            23: #include <SDL/SDL.h>
        !            24: #include <SDL/SDL_endian.h>
        !            25: 
        !            26: #include "main.h"
        !            27: #include "decode.h"
        !            28: #include "configuration.h"
        !            29: #include "file.h"
        !            30: #include "hostcall.h"
        !            31: #include "m68000.h"
        !            32: #include "memAlloc.h"
        !            33: #include "misc.h"
        !            34: #include "stMemory.h"
        !            35: #include "screen.h"
        !            36: #include "video.h"
        !            37: #include "audio.h"
        !            38: #include "input.h"
        !            39: #include "fe2.h"
        !            40: 
        !            41: #include "../cpu/hatari-glue.h"
        !            42: 
        !            43: //#define GEMDOS_VERBOSE
        !            44: // uncomment the following line to debug filename lookups on hd
        !            45: // #define FILE_DEBUG 1
        !            46: 
        !            47: #define ENABLE_SAVING             /* Turn on saving stuff */
        !            48: 
        !            49: #define INVALID_HANDLE_VALUE -1
        !            50: 
        !            51: #ifndef MAX_PATH
        !            52: #define MAX_PATH 256
        !            53: #endif
        !            54: 
        !            55: /* GLOB_ONLYDIR is a GNU extension for the glob() function and not defined
        !            56:  * on some systems. We should probably use something different for this
        !            57:  * case, but at the moment it we simply define it as 0... */
        !            58: #ifndef GLOB_ONLYDIR
        !            59: #warning GLOB_ONLYDIR was not defined.
        !            60: #define GLOB_ONLYDIR 0
        !            61: #endif
        !            62: 
        !            63: 
        !            64: /* structure with all the drive-specific data for our emulated drives */
        !            65: EMULATEDDRIVE emudrive;
        !            66: 
        !            67: typedef struct
        !            68: {
        !            69:   BOOL bUsed;
        !            70:   FILE *FileHandle;
        !            71:   char szActualName[MAX_PATH];   /* used by F_DATIME (0x57) */
        !            72: } FILE_HANDLE;
        !            73: 
        !            74: typedef struct
        !            75: {
        !            76:   BOOL bUsed;
        !            77:   int  nentries;                   /* number of entries in fs directory */
        !            78:   int  centry;                     /* current entry # */
        !            79:   struct dirent **found;           /* legal files */
        !            80:   char path[MAX_PATH];             /* sfirst path */
        !            81: } INTERNAL_DTA;
        !            82: 
        !            83: FILE_HANDLE  FileHandles[MAX_FILE_HANDLES];
        !            84: INTERNAL_DTA InternalDTAs[MAX_DTAS_FILES];
        !            85: int DTAIndex;                                 /* Circular index into above */
        !            86: DTA *pDTA;                                    /* Our GEMDOS hard drive Disc Transfer Address structure */
        !            87: unsigned char GemDOS_ConvertAttribute(mode_t mode);
        !            88: 
        !            89: 
        !            90: /*-------------------------------------------------------*/
        !            91: /*
        !            92:   Routines to convert time and date to MSDOS format.
        !            93:   Originally from the STonX emulator. (cheers!)
        !            94: */
        !            95: unsigned short time2dos (time_t t)
        !            96: {
        !            97:        struct tm *x;
        !            98:        x = localtime (&t);
        !            99:        return (x->tm_sec>>1)|(x->tm_min<<5)|(x->tm_hour<<11);
        !           100: }
        !           101: 
        !           102: unsigned short date2dos (time_t t)
        !           103: {
        !           104:        struct tm *x;
        !           105:        x = localtime (&t);
        !           106:        return x->tm_mday | ((x->tm_mon+1)<<5) | ( ((x->tm_year-80>0)?x->tm_year-80:0) << 9);
        !           107: }
        !           108: 
        !           109: 
        !           110: /*-----------------------------------------------------------------------*/
        !           111: /*
        !           112:   Populate a DATETIME structure with file info
        !           113: */
        !           114: BOOL GetFileInformation(char *name, DATETIME *DateTime)
        !           115: {
        !           116:   struct stat filestat;
        !           117:   int n;
        !           118:   struct tm *x;
        !           119: 
        !           120:   n = stat(name, &filestat);
        !           121:   if( n != 0 ) return(FALSE);
        !           122:   x = localtime( &filestat.st_mtime );
        !           123: 
        !           124:   DateTime->word1 = 0;
        !           125:   DateTime->word2 = 0;
        !           126: 
        !           127:   DateTime->word1 |= (x->tm_mday & 0x1F);         /* 5 bits */
        !           128:   DateTime->word1 |= (x->tm_mon & 0x0F)<<5;       /* 4 bits */
        !           129:   DateTime->word1 |= (((x->tm_year-80>0)?x->tm_year-80:0) & 0x7F)<<9;      /* 7 bits*/
        !           130: 
        !           131:   DateTime->word2 |= (x->tm_sec & 0x1F);          /* 5 bits */
        !           132:   DateTime->word2 |= (x->tm_min & 0x3F)<<5;       /* 6 bits */
        !           133:   DateTime->word2 |= (x->tm_hour & 0x1F)<<11;     /* 5 bits */
        !           134: 
        !           135:   return(TRUE);
        !           136: }
        !           137: 
        !           138: 
        !           139: /*-----------------------------------------------------------------------*/
        !           140: /*
        !           141:   Populate the DTA buffer with file info
        !           142: */
        !           143: int PopulateDTA(char *path, struct dirent *file)
        !           144: {
        !           145:   char tempstr[MAX_PATH];
        !           146:   struct stat filestat;
        !           147:   int n;
        !           148: 
        !           149:   sprintf(tempstr, "%s/%s", path, file->d_name);
        !           150:   n = stat(tempstr, &filestat);
        !           151:   if(n != 0) return(FALSE); /* return on error */
        !           152: 
        !           153:   if(!pDTA) return(FALSE); /* no DTA pointer set */
        !           154:   Misc_strupr(file->d_name);    /* convert to atari-style uppercase */
        !           155:   strncpy(pDTA->dta_name,file->d_name,TOS_NAMELEN); /* FIXME: better handling of long file names */
        !           156:   STMemory_WriteLong_PCSpace(pDTA->dta_size, (long)filestat.st_size);
        !           157:   STMemory_WriteWord_PCSpace(pDTA->dta_time, time2dos(filestat.st_mtime));
        !           158:   STMemory_WriteWord_PCSpace(pDTA->dta_date, date2dos(filestat.st_mtime));
        !           159:   pDTA->dta_attrib = GemDOS_ConvertAttribute(filestat.st_mode);
        !           160: 
        !           161:   return(TRUE);
        !           162: }
        !           163: 
        !           164: 
        !           165: /*-----------------------------------------------------------------------*/
        !           166: /*
        !           167:   Clear a used DTA structure.
        !           168: */
        !           169: void ClearInternalDTA(){
        !           170:   int i;
        !           171: 
        !           172:   /* clear the old DTA structure */
        !           173:   if(InternalDTAs[DTAIndex].found != NULL){
        !           174:     for(i=0; i <InternalDTAs[DTAIndex].nentries; i++)
        !           175:       free(InternalDTAs[DTAIndex].found[i]);
        !           176:     free(InternalDTAs[DTAIndex].found);
        !           177:   }
        !           178:   InternalDTAs[DTAIndex].bUsed = FALSE;
        !           179: }
        !           180: 
        !           181: 
        !           182: /*-----------------------------------------------------------------------*/
        !           183: /*
        !           184:   Match a file to a dir mask.
        !           185: */
        !           186: static int match (char *pat, char *name)
        !           187: {
        !           188:   /* make uppercase copies */
        !           189:   char p0[MAX_PATH], n0[MAX_PATH];
        !           190:   strcpy(p0, pat);
        !           191:   strcpy(n0, name);
        !           192:   Misc_strupr(p0);
        !           193:   Misc_strupr(n0);
        !           194: 
        !           195:   if(name[0] == '.') return(FALSE);                   /* no .* files */
        !           196:   if (strcmp(pat,"*.*")==0) return(TRUE);
        !           197:   else if (strcasecmp(pat,name)==0) return(TRUE);
        !           198:   else
        !           199:     {
        !           200:       char *p=p0,*n=n0;
        !           201:       for(;*n;)
        !           202:        {
        !           203:          if (*p=='*') {while (*n && *n != '.') n++;p++;}
        !           204:          else if (*p=='?' && *n) {n++;p++;}
        !           205:          else if (*p++ != *n++) return(FALSE);
        !           206:        }
        !           207:       if (*p==0)
        !           208:        {
        !           209:          return(TRUE);
        !           210:        }
        !           211:     }
        !           212:   return(FALSE);
        !           213: }
        !           214: 
        !           215: /*-----------------------------------------------------------------------*/
        !           216: /*
        !           217:   Parse directory from sfirst mask
        !           218:   - e.g.: input:  "hdemudir/auto/mask*.*" outputs: "hdemudir/auto"
        !           219: */
        !           220: void fsfirst_dirname(char *string, char *new){
        !           221:   int i=0;
        !           222: 
        !           223:   sprintf(new, string);
        !           224:   /* convert to front slashes. */
        !           225:   i=0;
        !           226:   while(new[i] != '\0'){
        !           227:     if(new[i] == '\\') new[i] = '/';
        !           228:     i++;
        !           229:   }
        !           230:   while(string[i] != '\0'){new[i] = string[i]; i++;} /* find end of string */
        !           231:   while(new[i] != '/') i--; /* find last slash */
        !           232:   new[i] = '\0';
        !           233: 
        !           234: }
        !           235: 
        !           236: /*-----------------------------------------------------------------------*/
        !           237: /*
        !           238:   Parse directory mask, e.g. "*.*"
        !           239: */
        !           240: void fsfirst_dirmask(char *string, char *new){
        !           241:   int i=0, j=0;
        !           242:   while(string[i] != '\0')i++;   /* go to end of string */
        !           243:   while(string[i] != '/') i--;   /* find last slash */
        !           244:   i++;
        !           245:   while(string[i] != '\0')new[j++] = string[i++]; /* go to end of string */
        !           246:   new[j++] = '\0';
        !           247: }
        !           248: 
        !           249: /*-----------------------------------------------------------------------*/
        !           250: /*
        !           251:   Initialize GemDOS/PC file system
        !           252: */
        !           253: void GemDOS_Init(void)
        !           254: {
        !           255:   int i;
        !           256: 
        !           257:   /* Clear handles structure */
        !           258:   Memory_Clear(FileHandles, sizeof(FILE_HANDLE)*MAX_FILE_HANDLES);
        !           259:   /* Clear DTAs */
        !           260:   for(i=0; i<MAX_DTAS_FILES; i++)
        !           261:   {
        !           262:     InternalDTAs[i].bUsed = FALSE;
        !           263:     InternalDTAs[i].nentries = 0;
        !           264:     InternalDTAs[i].found = NULL;
        !           265:   }
        !           266:   DTAIndex = 0;
        !           267: }
        !           268: 
        !           269: /*-----------------------------------------------------------------------*/
        !           270: /*
        !           271:   Reset GemDOS file system
        !           272: */
        !           273: void GemDOS_Reset()
        !           274: {
        !           275:   int i;
        !           276: 
        !           277:   /* Init file handles table */
        !           278:   for(i=0; i<MAX_FILE_HANDLES; i++)
        !           279:   {
        !           280:     /* Was file open? If so close it */
        !           281:     if (FileHandles[i].bUsed)
        !           282:       fclose(FileHandles[i].FileHandle);
        !           283: 
        !           284:     FileHandles[i].FileHandle = NULL;
        !           285:     FileHandles[i].bUsed = FALSE;
        !           286:   }
        !           287: 
        !           288:   for(i=0; i<MAX_DTAS_FILES; i++)
        !           289:   {
        !           290:     InternalDTAs[i].bUsed = FALSE;
        !           291:     InternalDTAs[i].nentries = 0;
        !           292:     InternalDTAs[i].found = NULL;
        !           293:   }
        !           294: 
        !           295:   /* Reset */
        !           296:   pDTA = NULL;
        !           297:   DTAIndex = 0;
        !           298: }
        !           299: 
        !           300: 
        !           301: /*-----------------------------------------------------------------------*/
        !           302: /*
        !           303:   Initialize a GEMDOS drive.
        !           304:   Only 1 emulated drive allowed, as of yet.
        !           305: */
        !           306: void GemDOS_InitDrives()
        !           307: {
        !           308:     /* set emulation directory string */
        !           309:     strcpy(emudrive.hd_emulation_dir, "./");
        !           310: 
        !           311:     /* remove trailing slash, if any in the directory name */
        !           312:     File_CleanFileName(emudrive.hd_emulation_dir);
        !           313: 
        !           314:     emudrive.hd_letter = 2;
        !           315: }
        !           316: 
        !           317: 
        !           318: /*-----------------------------------------------------------------------*/
        !           319: /*
        !           320:   Un-init the GEMDOS drive
        !           321: */
        !           322: void GemDOS_UnInitDrives()
        !           323: {
        !           324:   GemDOS_Reset();        /* Close all open files on emulated drive*/
        !           325: }
        !           326: 
        !           327: 
        !           328: /*-----------------------------------------------------------------------*/
        !           329: /*
        !           330:   Return free PC file handle table index, or -1 if error
        !           331: */
        !           332: int GemDOS_FindFreeFileHandle(void)
        !           333: {
        !           334:   int i;
        !           335: 
        !           336:   /* Scan our file list for free slot */
        !           337:   for(i=0; i<MAX_FILE_HANDLES; i++) {
        !           338:     if (!FileHandles[i].bUsed)
        !           339:       return(i);
        !           340:   }
        !           341: 
        !           342:   /* Cannot open any more files, return error */
        !           343:   return(-1);
        !           344: }
        !           345: 
        !           346: /*-----------------------------------------------------------------------*/
        !           347: /*
        !           348:   Check ST handle is within our table range, return TRUE if not
        !           349: */
        !           350: BOOL GemDOS_IsInvalidFileHandle(int Handle)
        !           351: {
        !           352:   BOOL bInvalidHandle=FALSE;
        !           353: 
        !           354:   /* Check handle was valid with our handle table */
        !           355:   if ( (Handle<0) || (Handle>=MAX_FILE_HANDLES) )
        !           356:     bInvalidHandle = TRUE;
        !           357:   else if (!FileHandles[Handle].bUsed)
        !           358:     bInvalidHandle = TRUE;
        !           359: 
        !           360:   return(bInvalidHandle);
        !           361: }
        !           362: 
        !           363: int baselen(char *s) {
        !           364:   /* Returns the length of the basename of the file passed in parameter
        !           365:      (ie the file without extension) */
        !           366:   char *ext = strchr(s,'.');
        !           367:   if (ext) return ext-s;
        !           368:   return strlen(s);
        !           369: }
        !           370: 
        !           371: /*-----------------------------------------------------------------------*/
        !           372: /*
        !           373:   Use hard-drive directory, current ST directory and filename to create full path
        !           374: */
        !           375: void GemDOS_CreateHardDriveFileName(int Drive,char *pszFileName,char *pszDestName)
        !           376: {
        !           377:   /*  int DirIndex = Misc_LimitInt(Drive-2, 0,ConfigureParams.HardDisc.nDriveList-1); */
        !           378:   char *s,*start;
        !           379: 
        !           380:   if(pszFileName[0] == '\0') return; /* check for valid string */
        !           381: 
        !           382:   /* case full filename "C:\foo\bar" */
        !           383:   s=pszDestName; start=NULL;
        !           384: 
        !           385:   if(pszFileName[1] == ':') {
        !           386:     sprintf(pszDestName, "%s%s", emudrive.hd_emulation_dir, File_RemoveFileNameDrive(pszFileName));
        !           387:   }
        !           388:   /* case referenced from root:  "\foo\bar" */
        !           389:   else if(pszFileName[0] == '\\'){
        !           390:     sprintf(pszDestName, "%s%s", emudrive.hd_emulation_dir, pszFileName);
        !           391:   }
        !           392:   /* case referenced from current directory */
        !           393:   else {
        !           394:     sprintf(pszDestName, "%s%s",  emudrive.fs_currpath, pszFileName);
        !           395:     start = pszDestName + strlen(emudrive.fs_currpath)-1;
        !           396:   }
        !           397: 
        !           398:   /* convert to front slashes. */
        !           399:   while((s = strchr(s+1,'\\'))) {
        !           400:     if (!start) {
        !           401:       start = s;
        !           402:       continue;
        !           403:     }
        !           404:     {
        !           405:       glob_t globbuf;
        !           406:       char old1,old2,dest[256];
        !           407:       int len,j,found,base_len;
        !           408: 
        !           409:       *start++ = '/';
        !           410:       old1 = *start; *start++ = '*';
        !           411:       old2 = *start; *start = 0;
        !           412:       glob(pszDestName,GLOB_ONLYDIR,NULL,&globbuf);
        !           413:       *start-- = old2; *start = old1;
        !           414:       *s = 0;
        !           415:       len = strlen(pszDestName);
        !           416:       base_len = baselen(start);
        !           417:       found = 0;
        !           418:       for (j=0; j<globbuf.gl_pathc; j++) {
        !           419:        /* If we search for a file of at least 8 characters, then it might
        !           420:           be a longer filename since the ST can access only the first 8
        !           421:           characters. If not, then it's a precise match (with case). */
        !           422:        if (!(base_len < 8 ? strcasecmp(globbuf.gl_pathv[j],pszDestName) :
        !           423:              strncasecmp(globbuf.gl_pathv[j],pszDestName,len))) {
        !           424:          /* we found a matching name... */
        !           425:          sprintf(dest,"%s%c%s",globbuf.gl_pathv[j],'/',s+1);
        !           426:          strcpy(pszDestName,dest);
        !           427:          j = globbuf.gl_pathc;
        !           428:          found = 1;
        !           429:        }
        !           430:       }
        !           431:       globfree(&globbuf);
        !           432:       if (!found) {
        !           433:        /* didn't find it. Let's try normal files (it might be a symlink) */
        !           434:        *start++ = '*';
        !           435:        *start = 0;
        !           436:        glob(pszDestName,0,NULL,&globbuf);
        !           437:        *start-- = old2; *start = old1;
        !           438:        for (j=0; j<globbuf.gl_pathc; j++) {
        !           439:          if (!strncasecmp(globbuf.gl_pathv[j],pszDestName,len)) {
        !           440:            /* we found a matching name... */
        !           441:            sprintf(dest,"%s%c%s",globbuf.gl_pathv[j],'/',s+1);
        !           442:            strcpy(pszDestName,dest);
        !           443:            j = globbuf.gl_pathc;
        !           444:            found = 1;
        !           445:          }
        !           446:        }
        !           447:        globfree(&globbuf);
        !           448:        if (!found) {           /* really nothing ! */
        !           449:          *s = '/';
        !           450:          fprintf(stderr,"no path for %s\n",pszDestName);
        !           451:        }
        !           452:       }
        !           453:     }
        !           454:     start = s;
        !           455:   }
        !           456: 
        !           457:   if (!start) start = strrchr(pszDestName,'/'); // path already converted ?
        !           458: 
        !           459:   if (start) {
        !           460:     *start++ = '/';     /* in case there was only 1 anti slash */
        !           461:     if (*start && !strchr(start,'?') && !strchr(start,'*')) {
        !           462:       /* We have a complete name after the path, not a wildcard */
        !           463:       glob_t globbuf;
        !           464:       char old1,old2;
        !           465:       int len,j,found,base_len;
        !           466: 
        !           467:       old1 = *start; *start++ = '*';
        !           468:       old2 = *start; *start = 0;
        !           469:       glob(pszDestName,0,NULL,&globbuf);
        !           470:       *start-- = old2; *start = old1;
        !           471:       len = strlen(pszDestName);
        !           472:       base_len = baselen(start);
        !           473:       found = 0;
        !           474:       for (j=0; j<globbuf.gl_pathc; j++) {
        !           475:        /* If we search for a file of at least 8 characters, then it might
        !           476:           be a longer filename since the ST can access only the first 8
        !           477:           characters. If not, then it's a precise match (with case). */
        !           478:        if (!(base_len < 8 ? strcasecmp(globbuf.gl_pathv[j],pszDestName) :
        !           479:              strncasecmp(globbuf.gl_pathv[j],pszDestName,len))) {
        !           480:          /* we found a matching name... */
        !           481:          strcpy(pszDestName,globbuf.gl_pathv[j]);
        !           482:          j = globbuf.gl_pathc;
        !           483:          found = 1;
        !           484:        }
        !           485:       }
        !           486: #if FILE_DEBUG
        !           487:       if (!found) {
        !           488:        /* It's often normal, the gem uses this to test for existence */
        !           489:        /* of desktop.inf or newdesk.inf for example. */
        !           490:        fprintf(stderr,"didn't find filename %s\n",pszDestName);
        !           491:       }
        !           492: #endif
        !           493:       globfree(&globbuf);
        !           494:     }
        !           495:   }
        !           496: 
        !           497: #if FILE_DEBUG
        !           498:  fprintf(stderr,"conv %s -> %s\n",pszFileName,pszDestName);
        !           499: #endif
        !           500: }
        !           501: 
        !           502: /*-----------------------------------------------------------------------*/
        !           503: /*
        !           504:   Covert from FindFirstFile/FindNextFile attribute to GemDOS format
        !           505: */
        !           506: unsigned char GemDOS_ConvertAttribute(mode_t mode)
        !           507: {
        !           508:   unsigned char Attrib=0;
        !           509: 
        !           510:   /* FIXME: More attributes */
        !           511:   if(S_ISDIR(mode)) Attrib |= GEMDOS_FILE_ATTRIB_SUBDIRECTORY;
        !           512: 
        !           513: /* FIXME */
        !           514: /*
        !           515:   // Look up attributes
        !           516:   if (dwFileAttributes&FILE_ATTRIBUTE_READONLY)
        !           517:     Attrib |= GEMDOS_FILE_ATTRIB_READONLY;
        !           518:   if (dwFileAttributes&FILE_ATTRIBUTE_HIDDEN)
        !           519:     Attrib |= GEMDOS_FILE_ATTRIB_HIDDEN;
        !           520:   if (dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY)
        !           521:     Attrib |= GEMDOS_FILE_ATTRIB_SUBDIRECTORY;
        !           522: */
        !           523:   return(Attrib);
        !           524: }
        !           525: 
        !           526: 
        !           527: /*-----------------------------------------------------------------------*/
        !           528: /*
        !           529:   GEMDOS Set Disc Transfer Address (DTA)
        !           530:   Call 0x1A
        !           531: */
        !           532: void GemDOS_SetDTA(unsigned long Params)
        !           533: {
        !           534:   /* Look up on stack to find where DTA is! Store as PC pointer */
        !           535:   pDTA = (DTA *)STRAM_ADDR(STMemory_ReadLong(Params+SIZE_WORD));
        !           536: }
        !           537: 
        !           538: /*-----------------------------------------------------------------------*/
        !           539: /*
        !           540:   GEMDOS Create file
        !           541:   Call 0x3C
        !           542: */
        !           543: void GemDOS_Create(unsigned long Params)
        !           544: {
        !           545:   char szActualFileName[MAX_PATH];
        !           546:   char *pszFileName;
        !           547:   char *rwflags[] = { "w+", /* read / write (truncate if exists) */
        !           548:                      "wb"  /* write only */
        !           549:   };
        !           550:   int Drive,Index,Mode;
        !           551: 
        !           552:   /* Find filename */
        !           553:   pszFileName = (char *)STRAM_ADDR(STMemory_ReadLong(Params+SIZE_WORD));
        !           554:   Mode = STMemory_ReadWord(Params+SIZE_WORD+SIZE_LONG);
        !           555:   Drive = 2;
        !           556:     /* And convert to hard drive filename */
        !           557:     GemDOS_CreateHardDriveFileName(Drive,pszFileName,szActualFileName);
        !           558: 
        !           559:     /* Find slot to store file handle, as need to return WORD handle for ST */
        !           560:     Index = GemDOS_FindFreeFileHandle();
        !           561:     if (Index==-1) {
        !           562:       /* No free handles, return error code */
        !           563:       Regs[REG_D0] = GEMDOS_ENHNDL;       /* No more handles */
        !           564:       return;
        !           565:     }
        !           566:     else {
        !           567: #ifdef ENABLE_SAVING
        !           568: 
        !           569:       FileHandles[Index].FileHandle = fopen(szActualFileName, rwflags[Mode&0x01]);
        !           570: 
        !           571:       if (FileHandles[Index].FileHandle != NULL) {
        !           572:         /* Tag handle table entry as used and return handle */
        !           573:         FileHandles[Index].bUsed = TRUE;
        !           574:         Regs[REG_D0] = Index+BASE_FILEHANDLE;  /* Return valid ST file handle from range 6 to 45! (ours start from 0) */
        !           575:         return;
        !           576:       }
        !           577:       else {
        !           578:         Regs[REG_D0] = GEMDOS_EFILNF;     /* File not found */
        !           579:         return;
        !           580:       }
        !           581: #else
        !           582:       Regs[REG_D0] = GEMDOS_EFILNF;       /* File not found */
        !           583:       return;
        !           584: #endif
        !           585:     }
        !           586: }
        !           587: 
        !           588: /*-----------------------------------------------------------------------*/
        !           589: /*
        !           590:   GEMDOS Open file
        !           591:   Call 0x3D
        !           592: */
        !           593: void GemDOS_Open(unsigned long Params)
        !           594: {
        !           595:   char szActualFileName[MAX_PATH];
        !           596:   char *pszFileName;
        !           597:   char *open_modes[] = { "rb", "wb", "r+" };  /* convert atari modes to stdio modes */
        !           598:   int Drive,Index,Mode;
        !           599: 
        !           600:   /* Find filename */
        !           601:   pszFileName = (char *)STRAM_ADDR(STMemory_ReadLong(Params+SIZE_WORD));
        !           602:   Mode = STMemory_ReadWord(Params+SIZE_WORD+SIZE_LONG);
        !           603:   Drive = 2;
        !           604: 
        !           605:     /* And convert to hard drive filename */
        !           606:     GemDOS_CreateHardDriveFileName(Drive,pszFileName,szActualFileName);
        !           607:     /* Find slot to store file handle, as need to return WORD handle for ST  */
        !           608:     Index = GemDOS_FindFreeFileHandle();
        !           609:     if (Index == -1) {
        !           610:       /* No free handles, return error code */
        !           611:       Regs[REG_D0] = GEMDOS_ENHNDL;       /* No more handles */
        !           612:       return;
        !           613:     }
        !           614: 
        !           615:     /* Open file */
        !           616:     FileHandles[Index].FileHandle =  fopen(szActualFileName, open_modes[Mode&0x03]);
        !           617: 
        !           618:     sprintf(FileHandles[Index].szActualName,"%s",szActualFileName);
        !           619: 
        !           620:     if (FileHandles[Index].FileHandle != NULL) {
        !           621:       /* Tag handle table entry as used and return handle */
        !           622:       FileHandles[Index].bUsed = TRUE;
        !           623:       Regs[REG_D0] = Index+BASE_FILEHANDLE;  /* Return valid ST file handle from range 6 to 45! (ours start from 0) */
        !           624:       return;
        !           625:     }
        !           626:     Regs[REG_D0] = GEMDOS_EFILNF;     /* File not found/ error opening */
        !           627:     return;
        !           628: }
        !           629: 
        !           630: /*-----------------------------------------------------------------------*/
        !           631: /*
        !           632:   GEMDOS Close file
        !           633:   Call 0x3E
        !           634: */
        !           635: void GemDOS_Close(unsigned long Params)
        !           636: {
        !           637:   int Handle;
        !           638: 
        !           639:   /* Find our handle - may belong to TOS */
        !           640:   Handle = STMemory_ReadWord(Params+SIZE_WORD)-BASE_FILEHANDLE;
        !           641: 
        !           642:   /* Check handle was valid */
        !           643:   if (GemDOS_IsInvalidFileHandle(Handle)) {
        !           644:     /* No assume was TOS */
        !           645:     return;
        !           646:   }
        !           647:   else {
        !           648:     /* Close file and free up handle table */
        !           649:     fclose(FileHandles[Handle].FileHandle);
        !           650:     FileHandles[Handle].bUsed = FALSE;
        !           651:     /* Return no error */
        !           652:     Regs[REG_D0] = GEMDOS_EOK;
        !           653:     return;
        !           654:   }
        !           655: }
        !           656: 
        !           657: /*-----------------------------------------------------------------------*/
        !           658: /*
        !           659:   GEMDOS Read file
        !           660:   Call 0x3F
        !           661: */
        !           662: void GemDOS_Read(unsigned long Params)
        !           663: {
        !           664:   char *pBuffer;
        !           665:   unsigned long nBytesRead,Size,CurrentPos,FileSize;
        !           666:   long nBytesLeft;
        !           667:   int Handle;
        !           668: 
        !           669:   /* Read details from stack */
        !           670:   Handle = STMemory_ReadWord(Params+SIZE_WORD)-BASE_FILEHANDLE;
        !           671:   Size = STMemory_ReadLong(Params+SIZE_WORD+SIZE_WORD);
        !           672:   pBuffer = (char *)STRAM_ADDR(STMemory_ReadLong(Params+SIZE_WORD+SIZE_WORD+SIZE_LONG));
        !           673: 
        !           674:   /* Check handle was valid */
        !           675:   if (GemDOS_IsInvalidFileHandle(Handle)) {
        !           676:     /* No -  assume was TOS */
        !           677:     return;
        !           678:   }
        !           679:   else {
        !           680: 
        !           681:     /* To quick check to see where our file pointer is and how large the file is */
        !           682:     CurrentPos = ftell(FileHandles[Handle].FileHandle);
        !           683:     fseek(FileHandles[Handle].FileHandle, 0, SEEK_END);
        !           684:     FileSize = ftell(FileHandles[Handle].FileHandle);
        !           685:     fseek(FileHandles[Handle].FileHandle, CurrentPos, SEEK_SET);
        !           686: 
        !           687:     nBytesLeft = FileSize-CurrentPos;
        !           688: 
        !           689:     /* Check for End Of File */
        !           690:     if (nBytesLeft == 0) {
        !           691:       /* FIXME: should we return zero (bytes read) or an error? */
        !           692:        Regs[REG_D0] = 0;
        !           693:       return;
        !           694:     }
        !           695:     else {
        !           696:       /* Limit to size of file to prevent windows error */
        !           697:       if (Size>FileSize)
        !           698:         Size = FileSize;
        !           699:       /* And read data in */
        !           700:       nBytesRead = fread(pBuffer, 1, Size, FileHandles[Handle].FileHandle);
        !           701: 
        !           702:       /* Return number of bytes read */
        !           703:       Regs[REG_D0] = nBytesRead;
        !           704: 
        !           705:       return;
        !           706:     }
        !           707:   }
        !           708: }
        !           709: 
        !           710: /*-----------------------------------------------------------------------*/
        !           711: /*
        !           712:   GEMDOS Write file
        !           713:   Call 0x40
        !           714: */
        !           715: void GemDOS_Write(unsigned long Params)
        !           716: {
        !           717:   char *pBuffer;
        !           718:   unsigned long Size,nBytesWritten;
        !           719:   int Handle;
        !           720: 
        !           721: #ifdef ENABLE_SAVING
        !           722:   /* Read details from stack */
        !           723:   Handle = STMemory_ReadWord(Params+SIZE_WORD)-BASE_FILEHANDLE;
        !           724:   Size = STMemory_ReadLong(Params+SIZE_WORD+SIZE_WORD);
        !           725:   pBuffer = (char *)STRAM_ADDR(STMemory_ReadLong(Params+SIZE_WORD+SIZE_WORD+SIZE_LONG));
        !           726: 
        !           727:   /* Check handle was valid */
        !           728:   if (GemDOS_IsInvalidFileHandle(Handle)) {
        !           729:     /* No assume was TOS */
        !           730:     return;
        !           731:   }
        !           732:   else {
        !           733: 
        !           734:     nBytesWritten = fwrite(pBuffer, 1, Size, FileHandles[Handle].FileHandle);
        !           735:     if (nBytesWritten>=0) {
        !           736: 
        !           737:       Regs[REG_D0] = nBytesWritten;      /* OK */
        !           738:     }
        !           739:     else
        !           740:       Regs[REG_D0] = GEMDOS_EACCDN;      /* Access denied(ie read-only) */
        !           741: 
        !           742:     return;
        !           743:   }
        !           744: #endif
        !           745: 
        !           746:   return;
        !           747: }
        !           748: 
        !           749: /*-----------------------------------------------------------------------*/
        !           750: /*
        !           751:   GEMDOS UnLink(Delete) file
        !           752:   Call 0x41
        !           753: */
        !           754: void GemDOS_UnLink(unsigned long Params)
        !           755: {
        !           756: #ifdef ENABLE_SAVING
        !           757:   char szActualFileName[MAX_PATH];
        !           758:   char *pszFileName;
        !           759:   int Drive;
        !           760: 
        !           761:   /* Find filename */
        !           762:   pszFileName = (char *)STRAM_ADDR(STMemory_ReadLong(Params+SIZE_WORD));
        !           763:   Drive = 2;
        !           764:     /* And convert to hard drive filename */
        !           765:     GemDOS_CreateHardDriveFileName(Drive,pszFileName,szActualFileName);
        !           766: 
        !           767:     /* Now delete file?? */
        !           768:     if ( unlink(szActualFileName)==0 )
        !           769:       Regs[REG_D0] = GEMDOS_EOK;          /* OK */
        !           770:     else
        !           771:       Regs[REG_D0] = GEMDOS_EFILNF;       /* File not found */
        !           772: 
        !           773:     return;
        !           774: #endif
        !           775: 
        !           776: }
        !           777: 
        !           778: /*-----------------------------------------------------------------------*/
        !           779: /*
        !           780:   GEMDOS Search Next
        !           781:   Call 0x4F
        !           782: */
        !           783: void GemDOS_SNext(unsigned long Params)
        !           784: {
        !           785:   struct dirent **temp;
        !           786:   int Index;
        !           787: 
        !           788:   /* Was DTA ours or TOS? */
        !           789:   if (STMemory_ReadLong_PCSpace(pDTA->magic)==DTA_MAGIC_NUMBER) {
        !           790: 
        !           791:     /* Find index into our list of structures */
        !           792:     Index = STMemory_ReadWord_PCSpace(pDTA->index)&(MAX_DTAS_FILES-1);
        !           793: 
        !           794:     if(InternalDTAs[Index].centry >= InternalDTAs[Index].nentries){
        !           795:       Regs[REG_D0] = GEMDOS_ENMFIL;    /* No more files */
        !           796:       return;
        !           797:     }
        !           798: 
        !           799:     temp = InternalDTAs[Index].found;
        !           800:     if(PopulateDTA(InternalDTAs[Index].path, temp[InternalDTAs[Index].centry++]) == FALSE){
        !           801:       fprintf(stderr,"\tError setting DTA.\n");
        !           802:       return;
        !           803:     }
        !           804: 
        !           805:     Regs[REG_D0] = GEMDOS_EOK;
        !           806:     return;
        !           807:   }
        !           808: 
        !           809:   return;
        !           810: }
        !           811: 
        !           812: 
        !           813: /*-----------------------------------------------------------------------*/
        !           814: /*
        !           815:   GEMDOS Find first file
        !           816:   Call 0x4E
        !           817: */
        !           818: void GemDOS_SFirst(unsigned long Params)
        !           819: {
        !           820:   char szActualFileName[MAX_PATH];
        !           821:   char tempstr[MAX_PATH];
        !           822:   char *pszFileName;
        !           823:   struct dirent **files;
        !           824:   unsigned short int Attr;
        !           825:   int Drive;
        !           826:   DIR *fsdir;
        !           827:   int i,j,k;
        !           828: 
        !           829:   /* Find filename to search for */
        !           830:   pszFileName = (char *)STRAM_ADDR(STMemory_ReadLong(Params+SIZE_WORD));
        !           831:   Attr = STMemory_ReadWord(Params+SIZE_WORD+SIZE_LONG);
        !           832: 
        !           833:   Drive = 2;
        !           834: 
        !           835:     /* And convert to hard drive filename */
        !           836:     GemDOS_CreateHardDriveFileName(Drive,pszFileName,szActualFileName);
        !           837: 
        !           838:     /* Populate DTA, set index for our use */
        !           839:     STMemory_WriteWord_PCSpace(pDTA->index,DTAIndex);
        !           840:     STMemory_WriteLong_PCSpace(pDTA->magic,DTA_MAGIC_NUMBER); /* set our dta magic num */
        !           841: 
        !           842:     if(InternalDTAs[DTAIndex].bUsed == TRUE) ClearInternalDTA();
        !           843:     InternalDTAs[DTAIndex].bUsed = TRUE;
        !           844: 
        !           845:     /* Were we looking for the volume label? */
        !           846:     if (Attr&GEMDOS_FILE_ATTRIB_VOLUME_LABEL) {
        !           847:       /* Volume name */
        !           848:       strcpy(pDTA->dta_name,"EMULATED.001");
        !           849:       Regs[REG_D0] = GEMDOS_EOK;          /* Got volume */
        !           850:       return;
        !           851:     }
        !           852: 
        !           853:     /* open directory */
        !           854:     fsfirst_dirname(szActualFileName, InternalDTAs[DTAIndex].path);
        !           855:     fsdir = opendir(InternalDTAs[DTAIndex].path);
        !           856: 
        !           857:     if( fsdir == NULL ){
        !           858:       Regs[REG_D0] = GEMDOS_EPTHNF;        /* Path not found */
        !           859:       return;
        !           860:     }
        !           861:     /* close directory */
        !           862:     closedir( fsdir );
        !           863: 
        !           864:     InternalDTAs[DTAIndex].nentries = scandir(InternalDTAs[DTAIndex].path, &files, 0, alphasort);
        !           865:     if( InternalDTAs[DTAIndex].nentries < 0 ){
        !           866:       Regs[REG_D0] = GEMDOS_EFILNF;        /* File (directory actually) not found */
        !           867:       return;
        !           868:     }
        !           869: 
        !           870:     InternalDTAs[DTAIndex].centry = 0;        /* current entry is 0 */
        !           871:     fsfirst_dirmask(szActualFileName, tempstr); /* get directory mask */
        !           872: 
        !           873:     /* Create and populate a list of matching files. */
        !           874: 
        !           875:     j = 0;                     /* count number of entries matching mask */
        !           876:     for(i=0;i<InternalDTAs[DTAIndex].nentries;i++)
        !           877:       if(match(tempstr, files[i]->d_name)) j++;
        !           878: 
        !           879:     if (j==0) {
        !           880:       return;
        !           881:     }
        !           882: 
        !           883:     InternalDTAs[DTAIndex].found = (struct dirent **)malloc(sizeof(struct dirent *) * j);
        !           884: 
        !           885:     /* copy the dirent pointers for files matching the mask to our list */
        !           886:     k = 0;
        !           887:     for(i=0;i<InternalDTAs[DTAIndex].nentries;i++)
        !           888:       if(match(tempstr, files[i]->d_name)){
        !           889:        InternalDTAs[DTAIndex].found[k] = files[i];
        !           890:        k++;
        !           891:       }
        !           892: 
        !           893:     InternalDTAs[DTAIndex].nentries = j; /* set number of legal entries */
        !           894: 
        !           895:     if(InternalDTAs[DTAIndex].nentries == 0){
        !           896:       /* No files of that match, return error code */
        !           897:       Regs[REG_D0] = GEMDOS_EFILNF;        /* File not found */
        !           898:       return;
        !           899:     }
        !           900: 
        !           901:     /* Scan for first file (SNext uses no parameters) */
        !           902:     GemDOS_SNext(0);
        !           903:     /* increment DTA index */
        !           904:     DTAIndex++;
        !           905:     DTAIndex&=(MAX_DTAS_FILES-1);
        !           906: 
        !           907:     return;
        !           908: }
        !           909: 
        !           910: 
        !           911: void Call_Memset (unsigned long Params)
        !           912: {
        !           913:        int adr, count;
        !           914:        count = STMemory_ReadLong (Params+SIZE_WORD);
        !           915:        adr = STMemory_ReadLong (Params+SIZE_WORD+SIZE_LONG);
        !           916:        memset (STRam+adr, 0, count);
        !           917: }
        !           918: 
        !           919: void Call_MemsetBlue (unsigned long Params)
        !           920: {
        !           921:        int adr, count;
        !           922:        count = STMemory_ReadLong (Params+SIZE_WORD);
        !           923:        adr = STMemory_ReadLong (Params+SIZE_WORD+SIZE_LONG);
        !           924:        memset (STRam+adr, 0xe, count);
        !           925: }
        !           926: 
        !           927: void Call_Memcpy (unsigned long Params)
        !           928: {
        !           929:        int dest, src, count;
        !           930: 
        !           931:        dest = STMemory_ReadLong (Params + SIZE_WORD);
        !           932:        src = STMemory_ReadLong (Params + SIZE_WORD + SIZE_LONG);
        !           933:        count = STMemory_ReadLong (Params + SIZE_WORD + 2*SIZE_LONG);
        !           934: 
        !           935:        memcpy (STRam+dest, STRam+src, count);
        !           936: }
        !           937: 
        !           938: static const char mouse_bmp[256] = {
        !           939:  0, 0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
        !           940:  0,15, 0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
        !           941:  0,15,15, 0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
        !           942:  0,15,15,15, 0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
        !           943:  0,15,15,15,15, 0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
        !           944:  0,15,15,15,15,15, 0,-1,-1,-1,-1,-1,-1,-1,-1,-1,
        !           945:  0,15,15,15,15, 0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
        !           946:  0,15,15,15,15, 0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
        !           947:  0,15, 0,15,15,15, 0,-1,-1,-1,-1,-1,-1,-1,-1,-1,
        !           948:  0, 0,-1, 0,15,15, 0,-1,-1,-1,-1,-1,-1,-1,-1,-1,
        !           949: -1,-1,-1, 0,15,15,15, 0,-1,-1,-1,-1,-1,-1,-1,-1,
        !           950: -1,-1,-1,-1, 0,15,15, 0,-1,-1,-1,-1,-1,-1,-1,-1,
        !           951: -1,-1,-1,-1, 0,15,15,15, 0,-1,-1,-1,-1,-1,-1,-1,
        !           952: -1,-1,-1,-1,-1, 0,15, 0,-1,-1,-1,-1,-1,-1,-1,-1,
        !           953: -1,-1,-1,-1,-1,-1, 0,-1,-1,-1,-1,-1,-1,-1,-1,-1,
        !           954: -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
        !           955: };
        !           956: 
        !           957: Uint8 under_mouse[256];
        !           958: 
        !           959: void Call_BlitCursor (unsigned long Params)
        !           960: {
        !           961:        int x, y, adr, org_x, org_y;
        !           962:        Uint8 *pixbase, *pix;
        !           963:        const char *bmp;
        !           964:        Uint8 *save;
        !           965:        org_x = STMemory_ReadLong (Params+SIZE_WORD);
        !           966:        org_y = STMemory_ReadLong (Params+SIZE_WORD+SIZE_LONG);
        !           967:        adr = STMemory_ReadLong (Params+SIZE_WORD+2*SIZE_LONG);
        !           968: 
        !           969:        pixbase = STRam + adr + (org_y*SCREENBYTES_LINE) + org_x;
        !           970:        bmp = mouse_bmp;
        !           971:        save = under_mouse;
        !           972: 
        !           973:        for (y=0; y<16; y++) {
        !           974:                if (y + org_y > SCREEN_HEIGHT_HBL) break;
        !           975:                pix = pixbase;
        !           976:                pixbase += SCREENBYTES_LINE;
        !           977:                for (x=0; x<16; x++, pix++, bmp++, save++) {
        !           978:                        if (x+org_x >= SCREENBYTES_LINE) continue;
        !           979:                        *save = *pix;
        !           980:                        if (*bmp != -1) *pix = *bmp;
        !           981:                }
        !           982:        }
        !           983: }
        !           984: 
        !           985: void Call_RestoreUnderCursor (unsigned long Params)
        !           986: {
        !           987:        int x, y, adr, org_x, org_y;
        !           988:        Uint8 *pixbase, *pix;
        !           989:        char *bmp;
        !           990:        org_x = STMemory_ReadLong (Params+SIZE_WORD);
        !           991:        org_y = STMemory_ReadLong (Params+SIZE_WORD+SIZE_LONG);
        !           992:        adr = STMemory_ReadLong (Params+SIZE_WORD+2*SIZE_LONG);
        !           993: 
        !           994:        pixbase = STRam + adr + (org_y*SCREENBYTES_LINE) + org_x;
        !           995:        bmp = under_mouse;
        !           996: 
        !           997:        for (y=0; y<16; y++) {
        !           998:                if (y + org_y > SCREEN_HEIGHT_HBL) break;
        !           999:                pix = pixbase;
        !          1000:                pixbase += SCREENBYTES_LINE;
        !          1001:                for (x=0; x<16; x++, pix++, bmp++) {
        !          1002:                        if (x+org_x >= SCREENBYTES_LINE) continue;
        !          1003:                        if (*bmp != -1) *pix = *bmp;
        !          1004:                }
        !          1005:        }
        !          1006: }
        !          1007: 
        !          1008: void Call_PutPix (unsigned long Params)
        !          1009: {
        !          1010:        int col, org_x, scr;
        !          1011:        char *pix;
        !          1012:        col = STMemory_ReadWord (Params+SIZE_WORD)>>2;
        !          1013:        org_x = Regs[REG_D4] & 0xffff;
        !          1014:        scr = Regs[REG_A3];
        !          1015: 
        !          1016:        /* hack to fix screen line. frontier's logic still thinks
        !          1017:         * there are 160 bytes per line */
        !          1018:        /* which screen buffer it is based on */
        !          1019:        if (scr & 0x100000) {
        !          1020:                scr -= 0x100000;
        !          1021:                scr *= 2;
        !          1022:                scr += 0x100000;
        !          1023:        } else {
        !          1024:                scr -= 0xf0000;
        !          1025:                scr *= 2;
        !          1026:                scr += 0xf0000;
        !          1027:        }
        !          1028:        pix = (char *)STRam + scr + org_x;
        !          1029:        *pix = col;
        !          1030:        return;
        !          1031: }
        !          1032: 
        !          1033: void Call_FillLine (unsigned long Params)
        !          1034: {
        !          1035:        int org_x,len,scr,col;
        !          1036:        char *pix;
        !          1037: 
        !          1038:        col = STMemory_ReadWord (Params+SIZE_WORD)>>2;
        !          1039:        org_x = Regs[REG_D4] & 0xffff;
        !          1040:        len = (~Regs[REG_D5]) & 0xffff;
        !          1041:        scr = Regs[REG_A3];
        !          1042:        
        !          1043:        /* hack to fix screen line. frontier's logic still thinks
        !          1044:         * there are 160 bytes per line */
        !          1045:        /* which screen buffer it is based on */
        !          1046:        if (scr & 0x100000) {
        !          1047:                scr -= 0x100000;
        !          1048:                scr *= 2;
        !          1049:                scr += 0x100000;
        !          1050:        } else {
        !          1051:                scr -= 0xf0000;
        !          1052:                scr *= 2;
        !          1053:                scr += 0xf0000;
        !          1054:        }
        !          1055:        pix = (char *)STRam + scr;
        !          1056:        org_x = SCREENBYTES_LINE;
        !          1057:        while (org_x--) {
        !          1058:                *pix = col;
        !          1059:                pix++;
        !          1060:        }
        !          1061: }
        !          1062: 
        !          1063: /*
        !          1064:  * This is used by the scanner code to draw object stalks
        !          1065:  * which are below the plane of the scanner.
        !          1066:  * The mask d7 indicates which pixels in the plane to set,
        !          1067:  * and they are set if their current colour is zero.
        !          1068:  *
        !          1069:  * This implementation isn't the way the function is really
        !          1070:  * supposed to be implemented (colour and draw mask was
        !          1071:  * combined in d6 but the colour mask is wrong now for
        !          1072:  * non-planar screen).
        !          1073:  */
        !          1074: void Call_BackHLine (unsigned long Params)
        !          1075: {
        !          1076:        int i,scr,col,bitfield;
        !          1077:        char *pix;
        !          1078: 
        !          1079:        col = STMemory_ReadWord (Params+SIZE_WORD)>>2;
        !          1080:        scr = Regs[REG_A3];
        !          1081:        bitfield = Regs[REG_D7] & 0xffff;
        !          1082:        
        !          1083:        /* hack to fix screen line. frontier's logic still thinks
        !          1084:         * there are 160 bytes per line */
        !          1085:        /* which screen buffer it is based on */
        !          1086:        if (scr & 0x100000) {
        !          1087:                scr -= 0x100000;
        !          1088:                scr *= 2;
        !          1089:                scr += 0x100000;
        !          1090:        } else {
        !          1091:                scr -= 0xf0000;
        !          1092:                scr *= 2;
        !          1093:                scr += 0xf0000;
        !          1094:        }
        !          1095:        pix = STRam + scr;
        !          1096:        for (i=15; i>=0; i--) {
        !          1097:                if ((bitfield & (1<<i)) && (*pix == 0)) *pix = col;
        !          1098:                pix++;
        !          1099:        }
        !          1100: }
        !          1101: 
        !          1102: void Call_OldHLine (unsigned long Params)
        !          1103: {
        !          1104:        int org_x,len,scr,col;
        !          1105:        char *pix;
        !          1106: 
        !          1107:        col = STMemory_ReadWord (Params+SIZE_WORD)>>2;
        !          1108:        //printf ("col=%d, d4=%d, (idx) d5=%d, (scr_line) a3=%p\n", col, Regs[REG_D4]&0xffff, Regs[REG_D5]&0xffff, (void*)Regs[REG_A3]);
        !          1109:        org_x = Regs[REG_D4] & 0xffff;
        !          1110:        len = Regs[REG_D5] & 0xffff;
        !          1111:        scr = Regs[REG_A3];
        !          1112:        
        !          1113:        /* hack to fix screen line. frontier's logic still thinks
        !          1114:         * there are 160 bytes per line */
        !          1115:        /* which screen buffer it is based on */
        !          1116:        if (scr & 0x100000) {
        !          1117:                scr -= 0x100000;
        !          1118:                scr *= 2;
        !          1119:                scr += 0x100000;
        !          1120:        } else {
        !          1121:                scr -= 0xf0000;
        !          1122:                scr *= 2;
        !          1123:                scr += 0xf0000;
        !          1124:        }
        !          1125:        len = len/2;
        !          1126:        /* horizontal line */
        !          1127:        pix = STRam + scr + org_x;
        !          1128:        while (len--) {
        !          1129:                *pix = col;
        !          1130:                pix++;
        !          1131:        }
        !          1132: }
        !          1133: 
        !          1134: void Call_HLine (unsigned long Params)
        !          1135: {
        !          1136:        int org_x,len,scr,col;
        !          1137:        char *pix;
        !          1138: 
        !          1139:        col = (Regs[REG_D1] & 0xffff)>>2;
        !          1140:        org_x = Regs[REG_D4] & 0xffff;
        !          1141:        len = Regs[REG_D5] & 0xffff;
        !          1142:        scr = Regs[REG_A3];
        !          1143:        
        !          1144:        /* horizontal line */
        !          1145:        pix = STRam + scr + org_x;
        !          1146:        while (len--) {
        !          1147:                *pix = col;
        !          1148:                pix++;
        !          1149:        }
        !          1150: }
        !          1151: 
        !          1152: /*
        !          1153:  * Blits frontier format 4-plane thingy
        !          1154:  */
        !          1155: void Call_BlitBmp (unsigned long Params)
        !          1156: {
        !          1157:        int width, height, org_x, org_y, bmp, scr;
        !          1158:        char *bmp_pix, *scr_pix, *ybase;
        !          1159:        int xpoo, i, ypoo, plane_incr;
        !          1160:        
        !          1161:        short word0, word1, word2, word3;
        !          1162:        
        !          1163:        width = STMemory_ReadWord (Params+SIZE_WORD);
        !          1164:        height = STMemory_ReadWord (Params+SIZE_WORD*2);
        !          1165:        org_x = STMemory_ReadWord (Params+SIZE_WORD*3);
        !          1166:        org_y = STMemory_ReadWord (Params+SIZE_WORD*4);
        !          1167:        bmp = STMemory_ReadLong (Params+SIZE_WORD*5);
        !          1168:        scr = STMemory_ReadLong (Params+SIZE_WORD*5 + SIZE_LONG);
        !          1169: 
        !          1170:        /* width is in words (width/16) */
        !          1171:        //printf ("Blit %dx%d to %d,%d, bmp 0x%x, scr 0x%x.\n", width, height, org_x, org_y, bmp, scr);
        !          1172:        bmp_pix = STRam + bmp + 4;
        !          1173:        ybase = STRam + scr + (org_y*SCREENBYTES_LINE) + org_x;
        !          1174: 
        !          1175:        /* These checks were in the original blit routine */
        !          1176:        if (org_x < 0) return;
        !          1177:        if (org_y < 0) return;
        !          1178:        if (height > 200) return;
        !          1179:        if (width > 320) return;
        !          1180:        
        !          1181:        plane_incr = 2*height*width;
        !          1182:        
        !          1183:        ypoo = height;
        !          1184:        while (ypoo--) {
        !          1185:                scr_pix = (char *)ybase;
        !          1186:                ybase += SCREENBYTES_LINE;
        !          1187:                for (xpoo = width; xpoo; xpoo--) {
        !          1188:                        word0 = SDL_SwapBE16 (*((short*)bmp_pix));
        !          1189:                        bmp_pix += plane_incr;
        !          1190:                        word1 = SDL_SwapBE16 (*((short*)bmp_pix));
        !          1191:                        bmp_pix += plane_incr;
        !          1192:                        word2 = SDL_SwapBE16 (*((short*)bmp_pix));
        !          1193:                        bmp_pix += plane_incr;
        !          1194:                        word3 = SDL_SwapBE16 (*((short*)bmp_pix));
        !          1195:                        
        !          1196:                        for (i=0; i<16; i++) {
        !          1197:                                *scr_pix = (word0 >> (15-i))&0x1;
        !          1198:                                *scr_pix |= ((word1 >> (15-i))&0x1)<<1;
        !          1199:                                *scr_pix |= ((word2 >> (15-i))&0x1)<<2;
        !          1200:                                *scr_pix |= ((word3 >> (15-i))&0x1)<<3;
        !          1201:                                scr_pix++;
        !          1202:                        }
        !          1203:                        bmp_pix -= 3*plane_incr;
        !          1204:                        bmp_pix += 2;
        !          1205:                }
        !          1206:        }
        !          1207: }
        !          1208: 
        !          1209: #define SCR_W  320
        !          1210: 
        !          1211: void Call_DrawStrShadowed (Params)
        !          1212: {
        !          1213:        unsigned char *str;
        !          1214:        
        !          1215:        str = Regs[REG_A0] + STRam;
        !          1216: 
        !          1217:        Regs[REG_D1] = DrawStr (
        !          1218:                        Regs[REG_D1], Regs[REG_D2],
        !          1219:                        Regs[REG_D0], str, TRUE);
        !          1220: }
        !          1221: 
        !          1222: void Call_DrawStr (Params)
        !          1223: {
        !          1224:        unsigned char *str;
        !          1225:        
        !          1226:        str = Regs[REG_A0] + STRam;
        !          1227: 
        !          1228:        Regs[REG_D1] = DrawStr (
        !          1229:                        Regs[REG_D1], Regs[REG_D2],
        !          1230:                        Regs[REG_D0], str, FALSE);
        !          1231: }
        !          1232: 
        !          1233: void Call_SetMainPalette (unsigned long Params)
        !          1234: {
        !          1235:        Uint32 pal_ptr;
        !          1236:        int i;
        !          1237:        
        !          1238:        pal_ptr = STMemory_ReadLong (Params+SIZE_WORD);
        !          1239:        
        !          1240:        for (i=0; i<16; i++) {
        !          1241:                MainPalette[i] = STMemory_ReadWord (pal_ptr);
        !          1242:                //printf ("%hx ", MainPalette[i]);
        !          1243:                pal_ptr+=2;
        !          1244:        }
        !          1245:        //printf ("\n");
        !          1246: }
        !          1247: 
        !          1248: void Call_SetCtrlPalette (unsigned long Params)
        !          1249: {
        !          1250:        Uint32 pal_ptr;
        !          1251:        int i;
        !          1252:        
        !          1253:        pal_ptr = STMemory_ReadLong (Params+SIZE_WORD);
        !          1254:        
        !          1255:        for (i=0; i<16; i++) {
        !          1256:                CtrlPalette[i] = STMemory_ReadWord (pal_ptr);
        !          1257:                pal_ptr+=2;
        !          1258:        }
        !          1259: }
        !          1260: 
        !          1261: int len_working_ext_pal;
        !          1262: unsigned short working_ext_pal[240];
        !          1263: 
        !          1264: void Call_InformScreens (unsigned long Params)
        !          1265: {
        !          1266:        physcreen2 = STMemory_ReadLong (Params+SIZE_WORD);
        !          1267:        logscreen2 = STMemory_ReadLong (Params+SIZE_WORD+SIZE_LONG);
        !          1268:        physcreen = STMemory_ReadLong (Params+SIZE_WORD+2*SIZE_LONG);
        !          1269:        logscreen = STMemory_ReadLong (Params+SIZE_WORD+3*SIZE_LONG);
        !          1270: }
        !          1271: 
        !          1272: /* also copies the extended palette into main palette */
        !          1273: void Call_SetScreenBase (unsigned long Params)
        !          1274: {
        !          1275:        int i;
        !          1276:        VideoBase = STMemory_ReadLong (Params+SIZE_WORD);
        !          1277:        VideoRaster = STRam + VideoBase;
        !          1278: 
        !          1279:        for (i=0; i<len_working_ext_pal; i++) {
        !          1280:                MainPalette[16+i] = working_ext_pal[i];
        !          1281:        }
        !          1282:        len_main_palette = 16 + len_working_ext_pal;
        !          1283: }
        !          1284: 
        !          1285: void Call_MakeExtPalette (unsigned long Params)
        !          1286: {
        !          1287:        int col_list, len, col_idx, col_val, i;
        !          1288: 
        !          1289:        col_list = STMemory_ReadLong (Params+SIZE_WORD);
        !          1290: 
        !          1291:        len = STMemory_ReadWord (col_list) >> 2;
        !          1292:        len_working_ext_pal = len;
        !          1293:        col_list+=2;
        !          1294:        //printf ("%d colours.\n", len+2);
        !          1295:        for (i=0; i<len; i++) {
        !          1296:                col_val = STMemory_ReadWord (col_list);
        !          1297:                working_ext_pal[i] = col_val;
        !          1298:                col_list += 2;
        !          1299:                col_idx = STMemory_ReadWord (col_list);
        !          1300:                /* offset dynamic colours into extended palette
        !          1301:                 * range (colours 16+) */
        !          1302:                col_idx += 16<<2;
        !          1303:                STMemory_WriteWord (col_list, col_idx);
        !          1304:                col_list += 2;
        !          1305:        }
        !          1306: }
        !          1307: 
        !          1308: void Call_DumpRegs (unsigned long Params)
        !          1309: {
        !          1310:        printf ("0x%x d0.l=%d ", m68k_getpc(), Regs[REG_D0]);
        !          1311:        printf ("d1.l=%d ", Regs[REG_D1]);
        !          1312:        printf ("d2.l=%d ", Regs[REG_D2]);
        !          1313:        printf ("d3.l=%d ", Regs[REG_D3]);
        !          1314:        printf ("d4.l=%d ", Regs[REG_D4]);
        !          1315:        printf ("d5.l=%d ", Regs[REG_D5]);
        !          1316:        printf ("d6.l=%d ", Regs[REG_D6]);
        !          1317:        printf ("d7.l=%d ", Regs[REG_D7]);
        !          1318:        printf ("\n");
        !          1319: }
        !          1320: 
        !          1321: void Call_NotifyOfScrFlip (unsigned long Params)
        !          1322: {
        !          1323:        bScreenContentsChanged = TRUE;
        !          1324: }
        !          1325: 
        !          1326: /* mouse pos in d3,d4 */
        !          1327: void Call_NotifyMousePos (unsigned long Params)
        !          1328: {
        !          1329: #if 0
        !          1330:        int x, y;
        !          1331:        
        !          1332:        x = Regs[REG_D3] & 0xffff;
        !          1333:        y = Regs[REG_D4] & 0xffff;
        !          1334: 
        !          1335:        x *= ScreenDraw.MouseScale;
        !          1336:        y *= ScreenDraw.MouseScale;
        !          1337:        
        !          1338:        SDL_EventState (SDL_MOUSEMOTION, SDL_DISABLE);
        !          1339:        SDL_WarpMouse (x, y);
        !          1340:        SDL_EventState (SDL_MOUSEMOTION, SDL_ENABLE);
        !          1341:        SDL_ShowCursor (SDL_ENABLE);    
        !          1342: #endif /* 0 */
        !          1343: }
        !          1344: 
        !          1345: void Call_DrawQuad (unsigned long Params)
        !          1346: {
        !          1347:        int high, i, j;
        !          1348:        struct Point pts[4];
        !          1349: 
        !          1350:        pts[0].x = Regs[REG_D0];
        !          1351:        pts[0].y = Regs[REG_D1];
        !          1352:        pts[1].x = Regs[REG_D2];
        !          1353:        pts[1].y = Regs[REG_D3];
        !          1354:        pts[2].x = Regs[REG_D4];
        !          1355:        pts[2].y = Regs[REG_D5];
        !          1356:        pts[3].x = Regs[REG_D6];
        !          1357:        pts[3].y = Regs[REG_D7];
        !          1358:        
        !          1359:        /* the two points with highest y actually seem to be
        !          1360:         * drawn only to y-1 by the frontier routines. weird. */
        !          1361:        for (i=0; i<4; i++) {
        !          1362:                high = 0;
        !          1363:                for (j=0; j<4; j++) {
        !          1364:                        if (pts[i].y > pts[j].y) high++;
        !          1365:                }
        !          1366:                if (high >= 2) pts[i].y--;
        !          1367:        }
        !          1368:        DrawPoly (pts, 4, Regs[REG_A0]/4);
        !          1369: }
        !          1370: 
        !          1371: void Call_DrawTriangle (unsigned long Params)
        !          1372: {
        !          1373:        DrawTriangle (Regs[REG_D0], Regs[REG_D1],
        !          1374:                        Regs[REG_D2], Regs[REG_D3],
        !          1375:                        Regs[REG_D4], Regs[REG_D5],
        !          1376:                        Regs[REG_A0]/4);
        !          1377: }
        !          1378: 
        !          1379: void Call_L35ea2 (unsigned long Params)
        !          1380: {
        !          1381:        int d0,d1,d2,max;
        !          1382: 
        !          1383:        d0 = Regs[REG_D0];
        !          1384:        d1 = Regs[REG_D1];
        !          1385:        d2 = Regs[REG_D2];
        !          1386: 
        !          1387:        max = (d0 > d1 ? d0 : d1);
        !          1388:        
        !          1389:        if (d2 == 0) {
        !          1390:                printf ("Eeek. zero divide (for real)\n");
        !          1391:                Regs[REG_D0] = 0;
        !          1392:                Regs[REG_D1] = 0;
        !          1393:                return;
        !          1394:        }
        !          1395: 
        !          1396:                if ((d0 >= (1<<16)) || (d0 <= ((-1)<<16))) {
        !          1397:                        Regs[REG_D0] = d0/(d2>>8);
        !          1398:                } else {
        !          1399:                        Regs[REG_D0] = (d0<<8)/d2;
        !          1400:                }
        !          1401:                if ((d1 >= (1<<16)) || (d1 <= ((-1)<<16))) {
        !          1402:                        Regs[REG_D1] = d1/(d2>>8);
        !          1403:                } else {
        !          1404:                        Regs[REG_D1] = (d1<<8)/d2;
        !          1405:                }
        !          1406:        /* with d2=0x2000 the 1st BP  is 0x3e000 */
        !          1407:        /* with d2=0x4000 the 1st BP  is 0x7c010 */
        !          1408:        /* with d2=0x8000 the 1st BP  is 0xf8000 */
        !          1409:        /* with d2=0x10000 the 1st BP is 0x1f0040 */
        !          1410:        /* next cunt point at > 0xf803f */
        !          1411:        //printf ("%d, %d, %d = %d, %d\n", d0, d1, d2, Regs[REG_D0], Regs[REG_D1]);
        !          1412: }
        !          1413: 
        !          1414: typedef void (*HOSTCALL) (unsigned long);
        !          1415: 
        !          1416: HOSTCALL hostcalls [] = {
        !          1417:        NULL,
        !          1418:        &Call_Memset,           /* 0x1 */
        !          1419:        &Call_MemsetBlue,               /* 0x2 */
        !          1420:        &Call_BlitCursor,               /* 0x3 */
        !          1421:        &Call_RestoreUnderCursor,       /* 0x4 */
        !          1422:        &Call_BlitBmp,          /* 0x5 */
        !          1423:        &Call_OldHLine,         /* 0x6 */
        !          1424:        NULL,           /* 0x7 */
        !          1425:        &Call_Memcpy,           /* 0x8 */
        !          1426:        &Call_PutPix,           /* 0x9 */
        !          1427:        &Call_BackHLine,                /* 0xa */
        !          1428:        &Call_FillLine,         /* 0xb */
        !          1429:        &Call_SetMainPalette,   /* 0xc */
        !          1430:        &Call_SetCtrlPalette,   /* 0xd */
        !          1431:        &Call_SetScreenBase,            /* 0xe */
        !          1432:        &Screen_Draw,                   /* 0xf */
        !          1433:        &Call_DumpRegs,         /* 0x10 */
        !          1434:        &Call_MakeExtPalette,   /* 0x11 */
        !          1435:        &Call_PlaySFX,                  /* 0x12 */
        !          1436:        &Call_GetMouseInput,            /* 0x13 */
        !          1437:        &Call_GetKeyboardEvent,         /* 0x14 */
        !          1438:        &Call_L35ea2,                   /* 0x15 */
        !          1439:        &Call_HLine,                    /* 0x16 */
        !          1440:        &Call_NotifyOfScrFlip,          /* 0x17 */
        !          1441:        &Call_NotifyMousePos,           /* 0x18 */
        !          1442:        &Call_InformScreens,            /* 0x19 */
        !          1443:        &GemDOS_SetDTA,
        !          1444:        &Call_DrawStrShadowed,          /* 0x1b */
        !          1445:        &Call_DrawStr,                  /* 0x1c */
        !          1446:        &Call_DrawTriangle,             /* 0x1d */
        !          1447:        &Call_DrawQuad,                 /* 0x1e */
        !          1448:        NULL,
        !          1449:        NULL,                           /* 0x20 */
        !          1450:        NULL,
        !          1451:        NULL,
        !          1452:        NULL,
        !          1453:        NULL,
        !          1454:        NULL,
        !          1455:        NULL,
        !          1456:        NULL,
        !          1457:        NULL,
        !          1458:        NULL,
        !          1459:        NULL,
        !          1460:        NULL,
        !          1461:        NULL,
        !          1462:        NULL,
        !          1463:        NULL,
        !          1464:        NULL,
        !          1465:        NULL,                           /* 0x30 */
        !          1466:        NULL,
        !          1467:        NULL,
        !          1468:        NULL,
        !          1469:        NULL,
        !          1470:        NULL,
        !          1471:        NULL,
        !          1472:        NULL,
        !          1473:        NULL,
        !          1474:        NULL,
        !          1475:        NULL,
        !          1476:        NULL,
        !          1477:        &GemDOS_Create,
        !          1478:        &GemDOS_Open,
        !          1479:        &GemDOS_Close,
        !          1480:        &GemDOS_Read,
        !          1481:        &GemDOS_Write,                  /* 0x40 */
        !          1482:        &GemDOS_UnLink,
        !          1483:        NULL,
        !          1484:        NULL,
        !          1485:        NULL,
        !          1486:        NULL,
        !          1487:        NULL,
        !          1488:        NULL,
        !          1489:        NULL,
        !          1490:        NULL,
        !          1491:        NULL,
        !          1492:        NULL,
        !          1493:        NULL,
        !          1494:        NULL,
        !          1495:        &GemDOS_SFirst,
        !          1496:        &GemDOS_SNext,
        !          1497:        NULL,                           /* 0x50 */
        !          1498: };
        !          1499: 
        !          1500: /*
        !          1501:  * Yay. Calling a C function from the 68k emu.
        !          1502:  */
        !          1503: unsigned long HostCall_OpCode (uae_u32 opcode)
        !          1504: {
        !          1505:        unsigned short int GemDOSCall;
        !          1506:        unsigned long Params;
        !          1507:        
        !          1508:        Params = Regs[REG_A7];
        !          1509:        
        !          1510:        GemDOSCall = STMemory_ReadWord(Params);
        !          1511:        
        !          1512:        (*hostcalls [GemDOSCall]) (Params);
        !          1513:        
        !          1514:        m68k_incpc (2);
        !          1515:        fill_prefetch_0 ();
        !          1516:        return 4;
        !          1517: }
        !          1518: 
        !          1519: /*
        !          1520:  * Faster hostcall, which takes opcode as immediate
        !          1521:  * 16-bit value, rather than on stack.
        !          1522:  */
        !          1523: unsigned long HCall_OpCode (uae_u32 opcode)
        !          1524: {
        !          1525:        unsigned short int call_idx;
        !          1526:        unsigned long Params;
        !          1527:        
        !          1528:        Params = Regs[REG_A7];
        !          1529:        Params -= SIZE_WORD;
        !          1530:        
        !          1531:        m68k_incpc (2);
        !          1532:        call_idx = STMemory_ReadWord(m68k_getpc());
        !          1533:        
        !          1534:        (hostcalls [call_idx]) (Params);
        !          1535:        
        !          1536:        m68k_incpc (2);
        !          1537:        fill_prefetch_0 ();
        !          1538:        return 4;
        !          1539: }
        !          1540: 

unix.superglobalmegacorp.com

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