Annotation of frontvm/hardware/hostcall.c, revision 1.1.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.