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