|
|
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:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.