First at-least-slightly working version of the CP/M read/write stuff. Not as
bad as I expected, but far too big.
This commit is contained in:
		
							parent
							
								
									3131dc9915
								
							
						
					
					
						commit
						50dca8b954
					
				
					 21 changed files with 464 additions and 193 deletions
				
			
		
							
								
								
									
										32
									
								
								build.lua
									
										
									
									
									
								
							
							
						
						
									
										32
									
								
								build.lua
									
										
									
									
									
								
							|  | @ -7,24 +7,24 @@ vars.ackcflags = { | |||
| vars.ackldflags = {} | ||||
| vars.plats = { | ||||
| 	"cpm", | ||||
| 	"linux386", | ||||
| 	"linux68k", | ||||
| 	"linuxppc", | ||||
| 	"linuxmips", | ||||
| 	"osx386", | ||||
| 	"osxppc", | ||||
| 	"pc86", | ||||
| 	"rpi", | ||||
| 	"pdpv7", | ||||
| 	"em22", | ||||
| --	"linux386", | ||||
| --	"linux68k", | ||||
| --	"linuxppc", | ||||
| --	"linuxmips", | ||||
| --	"osx386", | ||||
| --	"osxppc", | ||||
| --	"pc86", | ||||
| --	"rpi", | ||||
| --	"pdpv7", | ||||
| --	"em22", | ||||
| } | ||||
| vars.plats_with_tests = { | ||||
| 	"cpm", | ||||
| 	"linux68k", | ||||
| 	"linux386", | ||||
| 	"linuxppc", | ||||
| 	"linuxmips", | ||||
| 	"pc86", | ||||
| --	"cpm", | ||||
| --	"linux68k", | ||||
| --	"linux386", | ||||
| --	"linuxppc", | ||||
| --	"linuxmips", | ||||
| --	"pc86", | ||||
| } | ||||
| 
 | ||||
| installable { | ||||
|  |  | |||
|  | @ -25,7 +25,9 @@ struct FILE { | |||
| #define _IOWRITING	0x100 | ||||
| #define	_IOAPPEND	0x200 | ||||
| 
 | ||||
| #if !defined BUFSIZ | ||||
| #define	BUFSIZ      1024 | ||||
| #endif | ||||
| 
 | ||||
| #define	FOPEN_MAX	20 | ||||
| extern FILE	*__iotab[FOPEN_MAX]; | ||||
|  |  | |||
|  | @ -77,6 +77,7 @@ name led | |||
| 		(.e:{TAIL}={PLATFORMDIR}/libem.a \ | ||||
| 		           {PLATFORMDIR}/libsys.a \ | ||||
| 				   {PLATFORMDIR}/libc.a \ | ||||
| 		           {PLATFORMDIR}/libsys.a \ | ||||
| 				   {PLATFORMDIR}/libem.a \ | ||||
| 		           {PLATFORMDIR}/libend.a) | ||||
| 	linker | ||||
|  |  | |||
|  | @ -6,17 +6,21 @@ | |||
| #ifndef _ACK_PLAT_H | ||||
| #define _ACK_PLAT_H | ||||
| 
 | ||||
| /* The 8080 code generator doesn't do floating point. */ | ||||
| 
 | ||||
| #define ACKCONF_WANT_STDIO_FLOAT 0 | ||||
| 
 | ||||
| /* We're providing a time() system call rather than wanting a wrapper around
 | ||||
|  * gettimeofday() in the libc. */ | ||||
|   | ||||
| #define ACKCONF_WANT_EMULATED_TIME 0 | ||||
| 
 | ||||
| /* CP/M's underlying file abstraction is weird and doesn't map well onto
 | ||||
|  * file descriptors. Disable the standard FILE* mechanism in favour of our | ||||
|  * own. | ||||
|  */ | ||||
| /* Processes? CP/M? Hahahaha... */ | ||||
| 
 | ||||
| #define ACKCONF_WANT_EMULATED_FILE 0 | ||||
| #define ACKCONF_WANT_EMULATED_POPEN 0 | ||||
| 
 | ||||
| /* We have a very small address space, so override the default buffer size. */ | ||||
| 
 | ||||
| #define BUFSIZ 256 | ||||
| 
 | ||||
| #endif | ||||
|  |  | |||
|  | @ -67,10 +67,19 @@ extern uint8_t* cpm_ramtop; | |||
| extern uint8_t cpm_cmdlinelen; | ||||
| extern char cpm_cmdline[0x7f]; | ||||
| 
 | ||||
| /* Special: parses a filename into an FCB. Returns the user code (if any).
 | ||||
|  * Warning: cannot fail (because CP/M filespecs are incredibly lax). */ | ||||
| 
 | ||||
| extern uint8_t cpm_parse_filename(FCB* fcb, const char* filename); | ||||
| 
 | ||||
| /* Special: if the CCP hasn't been overwritten, returns to it; otherwise does
 | ||||
|  * a warmboot. */ | ||||
| extern void cpm_exit(void); | ||||
| 
 | ||||
| /* Special: equivalent to cpm_read_random() except if you read unwritten data
 | ||||
|  * 0 is returned (and the buffer contains garbage). */ | ||||
| extern uint8_t cpm_read_random_safe(FCB* fcb); | ||||
| 
 | ||||
| /* Extends cpm_ramtop over the CCP, for a little extra space. */ | ||||
| extern void cpm_overwrite_ccp(void); | ||||
| 
 | ||||
|  | @ -114,12 +123,7 @@ extern void cpm_overwrite_ccp(void); | |||
| /* 37 */ extern uint8_t cpm_reset_drives(uint16_t drive_bitmap); | ||||
| /* 40 */ extern uint8_t cpm_write_random_filled(FCB* fcb); | ||||
| 
 | ||||
| /* File descriptor emulation */ | ||||
| 
 | ||||
| struct FCBE | ||||
| { | ||||
|     FCB fcb; /* drive 0 means the console */ | ||||
|     uint8_t user; | ||||
| }; | ||||
| #define cpm_get_user() cpm_get_set_user(0xff) | ||||
| #define cpm_set_user(u) cpm_get_set_user(u) | ||||
| 
 | ||||
| #endif | ||||
|  |  | |||
|  | @ -47,28 +47,28 @@ local bdos_calls = { | |||
| 
 | ||||
| local trap_calls = { | ||||
|     "EARRAY", | ||||
|     "EBADGTO", | ||||
|     "EBADLAE", | ||||
|     "EBADLIN", | ||||
|     "EBADMON", | ||||
|     "EBADPC", | ||||
|     "EBADPTR", | ||||
|     "ECASE", | ||||
|     "ECONV", | ||||
|     "EFDIVZ", | ||||
|     "EFOVFL", | ||||
|     "EFUND", | ||||
|     "EFUNFL", | ||||
|     "EHEAP", | ||||
|     "EIDIVZ", | ||||
|     "EILLINS", | ||||
|     "EIOVFL", | ||||
|     "EIUND", | ||||
|     "EMEMFLT", | ||||
|     "EODDZ", | ||||
|     "ERANGE", | ||||
|     "ESET", | ||||
|     "EIOVFL", | ||||
|     "EFOVFL", | ||||
|     "EFUNFL", | ||||
|     "EIDIVZ", | ||||
|     "EFDIVZ", | ||||
|     "EIUND", | ||||
|     "EFUND", | ||||
|     "ECONV", | ||||
|     "ESTACK", | ||||
|     "EHEAP", | ||||
|     "EILLINS", | ||||
|     "EODDZ", | ||||
|     "ECASE", | ||||
|     "EMEMFLT", | ||||
|     "EBADPTR", | ||||
|     "EBADPC", | ||||
|     "EBADLAE", | ||||
|     "EBADMON", | ||||
|     "EBADLIN", | ||||
|     "EBADGTO", | ||||
|     "EUNIMPL", | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,14 +1,31 @@ | |||
| /* $Source$
 | ||||
|  * $State$ | ||||
|  * $Revision$ | ||||
|  */ | ||||
| 
 | ||||
| #include <stdlib.h> | ||||
| #include <errno.h> | ||||
| #include <unistd.h> | ||||
| #include <cpm.h> | ||||
| #include "cpmsys.h" | ||||
| 
 | ||||
| int close(int fd) | ||||
| { | ||||
| 	errno = EBADF; | ||||
| 	return -1; | ||||
|     struct FCBE* fcbe = &__fd[fd]; | ||||
|     int result = 0; | ||||
|     uint8_t olduser; | ||||
| 
 | ||||
|     __init_file_descriptors(); | ||||
|     if (fcbe->fcb.f[0]) | ||||
|     { | ||||
|         /* There's an actual filename here, so assume it's an open file. */ | ||||
| 
 | ||||
|         olduser = cpm_get_user(); | ||||
|         cpm_set_user(fcbe->user); | ||||
|         if (cpm_close_file(&fcbe->fcb) == 0xff) | ||||
|         { | ||||
|             errno = EIO; | ||||
|             result = -1; | ||||
|         } | ||||
|         cpm_set_user(olduser); | ||||
|     } | ||||
| 
 | ||||
|     memset(fcbe, 0, sizeof(struct FCBE)); | ||||
|     return result; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										10
									
								
								plat/cpm/libsys/cpm_read_random_safe.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								plat/cpm/libsys/cpm_read_random_safe.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,10 @@ | |||
| #include <string.h> | ||||
| #include <cpm.h> | ||||
| 
 | ||||
| uint8_t cpm_read_random_safe(FCB* fcb) | ||||
| { | ||||
|     uint8_t r = cpm_read_random(fcb); | ||||
|     if ((r == 1) || (r == 4)) | ||||
|         r = 0; | ||||
|     return r; | ||||
| } | ||||
							
								
								
									
										22
									
								
								plat/cpm/libsys/cpmsys.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								plat/cpm/libsys/cpmsys.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,22 @@ | |||
| #ifndef CPMSYS_H | ||||
| #define CPMSYS_H | ||||
| 
 | ||||
| /* File descriptor emulation */ | ||||
| 
 | ||||
| struct FCBE | ||||
| { | ||||
|     uint16_t length; /* number of records */ | ||||
|     FCB fcb; /* drive 0 means the console, f[0] == 0 means unallocated */ | ||||
|     uint8_t user; | ||||
|     uint8_t offset; /* into current sector */ | ||||
| }; | ||||
| 
 | ||||
| #define NUM_FILE_DESCRIPTORS 8 | ||||
| extern struct FCBE __fd[NUM_FILE_DESCRIPTORS]; | ||||
| extern uint8_t __transfer_buffer[128]; | ||||
| 
 | ||||
| extern void __init_file_descriptors(void); | ||||
| 
 | ||||
| #define SECTOR_ALIGNED(s) (((s) & 0x7f) == 0) | ||||
| 
 | ||||
| #endif | ||||
|  | @ -1,3 +1,73 @@ | |||
| #include <stdio.h> | ||||
| #include <cpm.h> | ||||
| #include <string.h> | ||||
| #include <ctype.h> | ||||
| #include "cpmsys.h" | ||||
| 
 | ||||
| uint8_t cpm_parse_filename(FCB* fcb, const char* filename) | ||||
| { | ||||
|     uint8_t user = cpm_get_user(); | ||||
| 
 | ||||
|     memset(fcb, 0, sizeof(FCB)); | ||||
|     memset(fcb->f, ' ', sizeof(fcb->f)); | ||||
| 
 | ||||
|     if (strchr(filename, ':')) | ||||
|     { | ||||
|         char c = *filename++; | ||||
|         if (isdigit(c)) | ||||
|         { | ||||
|             user = c - '0'; | ||||
|             c = *filename++; | ||||
|             if (isdigit(c)) | ||||
|             { | ||||
|                 user = (user*10) + (c - '0'); | ||||
|                 c = *filename++; | ||||
|             } | ||||
|         } | ||||
|         c = toupper(c); | ||||
|         if (isalpha(c)) | ||||
|         { | ||||
|             fcb->dr = c - '@'; | ||||
|             c = *filename++; | ||||
|         } | ||||
| 
 | ||||
|         while (c != ':') | ||||
|             c = *filename++; | ||||
|     } | ||||
| 
 | ||||
|     /* Read filename part. */ | ||||
| 
 | ||||
|     { | ||||
|         uint8_t i = 8; | ||||
|         uint8_t* p = &fcb->f[0]; | ||||
|         while (i--) | ||||
|         { | ||||
|             char c = toupper(*filename++); | ||||
|             if (c == '.') | ||||
|                 break; | ||||
|             if (!c) | ||||
|                 goto exit; | ||||
|             *p++ = c; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /* Read extension part. */ | ||||
| 
 | ||||
|     { | ||||
|         uint8_t i = 3; | ||||
|         uint8_t* p = &fcb->f[8]; | ||||
|         while (i--) | ||||
|         { | ||||
|             char c = toupper(*filename++); | ||||
|             if (!c) | ||||
|                 goto exit; | ||||
|             *p++ = c; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| exit: | ||||
|     if (fcb->dr == 0) | ||||
|         fcb->dr = cpm_get_current_drive() + 1; | ||||
|     return user; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,20 +0,0 @@ | |||
| #include <stdio.h> | ||||
| #include <errno.h> | ||||
| #include <cpm.h> | ||||
| 
 | ||||
| int fclose(FILE* stream) | ||||
| { | ||||
|     if (stream == CPM_FAKE_FILE) | ||||
|         return 0; | ||||
|      | ||||
|     if (fflush(stream)) | ||||
|         return; | ||||
| 
 | ||||
|     cpm_get_set_user(stream->user); | ||||
|     if (cpm_close_file(&stream->fcb) == 0xff) | ||||
|     { | ||||
|         errno = EIO; | ||||
|         return -1; | ||||
|     } | ||||
|     return 0; | ||||
| } | ||||
							
								
								
									
										19
									
								
								plat/cpm/libsys/fd.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								plat/cpm/libsys/fd.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,19 @@ | |||
| #include <stdlib.h> | ||||
| #include <errno.h> | ||||
| #include <unistd.h> | ||||
| #include <cpm.h> | ||||
| #include "cpmsys.h" | ||||
| 
 | ||||
| struct FCBE __fd[NUM_FILE_DESCRIPTORS]; | ||||
| uint8_t __transfer_buffer[128]; | ||||
| 
 | ||||
| void __init_file_descriptors(void) | ||||
| { | ||||
|     static uint8_t initialised = 0; | ||||
|     if (!initialised) | ||||
|     { | ||||
|         /* Mark stdin, stdout, stderr as being open files. */ | ||||
|         __fd[0].fcb.f[0] = __fd[1].fcb.f[0] = __fd[2].fcb.f[0] = ' '; | ||||
|         initialised = 1; | ||||
|     } | ||||
| } | ||||
|  | @ -1,9 +0,0 @@ | |||
| #include <stdio.h> | ||||
| #include <errno.h> | ||||
| #include <cpm.h> | ||||
| 
 | ||||
| int cpm_feof(FILE* stream) | ||||
| { | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
|  | @ -1,8 +0,0 @@ | |||
| #include <stdio.h> | ||||
| #include <errno.h> | ||||
| #include <cpm.h> | ||||
| 
 | ||||
| int cpm_ferror(FILE* stream) | ||||
| { | ||||
|     return 0; | ||||
| } | ||||
|  | @ -1,12 +0,0 @@ | |||
| #include <stdio.h> | ||||
| #include <errno.h> | ||||
| #include <cpm.h> | ||||
| 
 | ||||
| int fflush(FILE* stream) | ||||
| { | ||||
|     if (stream == CPM_FAKE_FILE) | ||||
|         return 0; | ||||
|      | ||||
|     errno = EBADF; | ||||
|     return -1; | ||||
| } | ||||
|  | @ -1,36 +0,0 @@ | |||
| #include <stdio.h> | ||||
| #include <errno.h> | ||||
| #include <cpm.h> | ||||
| 
 | ||||
| struct buffer | ||||
| { | ||||
|     uint8_t mx; | ||||
|     uint8_t nc; | ||||
|     uint8_t c[128]; | ||||
| }; | ||||
| 
 | ||||
| static struct buffer buffer; | ||||
| static uint8_t pos; | ||||
| 
 | ||||
| int read_from_console(void) | ||||
| { | ||||
|     while (pos == buffer.nc) | ||||
|     { | ||||
|         /* Refill buffer. */ | ||||
|         buffer.mx = sizeof(buffer.c); | ||||
|         buffer.nc = 0; | ||||
|         cpm_readline((uint8_t*) &buffer); | ||||
|         pos = 0; | ||||
|     } | ||||
| 
 | ||||
|     return buffer.c[pos++]; | ||||
| } | ||||
| 
 | ||||
| int cpm_getc(FILE* stream) | ||||
| { | ||||
|     if (stream == CPM_FAKE_FILE) | ||||
|         return read_from_console(); | ||||
| 
 | ||||
|     errno = EBADF; | ||||
|     return -1; | ||||
| } | ||||
|  | @ -1,14 +1,28 @@ | |||
| /* $Source$
 | ||||
|  * $State$ | ||||
|  * $Revision$ | ||||
|  */ | ||||
| 
 | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <errno.h> | ||||
| #include <sys/types.h> | ||||
| #include <unistd.h> | ||||
| #include <cpm.h> | ||||
| #include "cpmsys.h" | ||||
| 
 | ||||
| off_t lseek(int fd, off_t offset, int whence) | ||||
| { | ||||
| 	errno = EINVAL; | ||||
| 	return -1; | ||||
|     struct FCBE* fcbe = &__fd[fd]; | ||||
| 
 | ||||
|     __init_file_descriptors(); | ||||
|     if (fcbe->fcb.dr == 0) | ||||
|     { | ||||
|         /* Can't seek the console. */ | ||||
|         return 0; | ||||
|     } | ||||
| 
 | ||||
|     if (whence == SEEK_END) | ||||
|         offset += fcbe->length<<7; | ||||
|     if (whence == SEEK_CUR) | ||||
|         offset += (U16(fcbe->fcb.r)<<7) | fcbe->offset; | ||||
|      | ||||
|     U16(fcbe->fcb.r) = offset>>7; | ||||
|     fcbe->offset = offset & 0x7f; | ||||
|     return 0; | ||||
| } | ||||
|  |  | |||
|  | @ -1,14 +1,61 @@ | |||
| /* $Source$
 | ||||
|  * $State$ | ||||
|  * $Revision$ | ||||
|  */ | ||||
| 
 | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <errno.h> | ||||
| #include <unistd.h> | ||||
| #include <cpm.h> | ||||
| #include "cpmsys.h" | ||||
| 
 | ||||
| int open(const char* path, int access, ...) | ||||
| { | ||||
| 	errno = EACCES; | ||||
| 	uint8_t fd = 0; | ||||
|     struct FCBE* fcbe = &__fd[0]; | ||||
| 	uint8_t olduser; | ||||
| 	 | ||||
|     __init_file_descriptors(); | ||||
| 	while (fd != NUM_FILE_DESCRIPTORS) | ||||
| 	{ | ||||
| 		if (fcbe->fcb.f[0] == 0) | ||||
| 			break; | ||||
| 		fd++; | ||||
| 		fcbe++; | ||||
| 	} | ||||
| 	if (fd == NUM_FILE_DESCRIPTORS) | ||||
| 	{ | ||||
| 		errno = EMFILE; | ||||
| 		return -1; | ||||
| 	} | ||||
| 
 | ||||
| 	fcbe->user = cpm_parse_filename(&fcbe->fcb, path); | ||||
| 
 | ||||
| 	olduser = cpm_get_user(); | ||||
| 	cpm_set_user(fcbe->user); | ||||
| 
 | ||||
| 	if (access & O_TRUNC) | ||||
| 	{ | ||||
| 		cpm_delete_file(&fcbe->fcb); | ||||
| 		access |= O_CREAT; | ||||
| 	} | ||||
| 	if (access & O_CREAT) | ||||
| 	{ | ||||
| 		if (cpm_make_file(&fcbe->fcb) == 0xff) | ||||
| 			goto eio; | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		if (cpm_open_file(&fcbe->fcb) == 0xff) | ||||
| 			goto eio; | ||||
| 	} | ||||
| 
 | ||||
| 	cpm_seek_to_end(&fcbe->fcb); | ||||
| 	fcbe->length = U16(fcbe->fcb.r); | ||||
| 	if (!(access & O_APPEND)) | ||||
| 		U16(fcbe->fcb.r) = 0; | ||||
| 	return fd; | ||||
| 
 | ||||
| eio: | ||||
| 	fcbe->fcb.f[0] = 0; | ||||
| 	errno = EIO; | ||||
| 	return -1; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,17 +0,0 @@ | |||
| #include <stdio.h> | ||||
| #include <errno.h> | ||||
| #include <cpm.h> | ||||
| 
 | ||||
| int cpm_putc(int c, FILE* stream) | ||||
| { | ||||
|     if (stream == CPM_FAKE_FILE) | ||||
|     { | ||||
|         cpm_conout(c); | ||||
|         if (c == '\n') | ||||
|             cpm_conout(c); | ||||
|         return 0; | ||||
|     } | ||||
| 
 | ||||
|     errno = EBADF; | ||||
|     return -1; | ||||
| } | ||||
|  | @ -7,18 +7,100 @@ | |||
| #include <stdlib.h> | ||||
| #include <errno.h> | ||||
| #include <unistd.h> | ||||
| #include <string.h> | ||||
| #include <cpm.h> | ||||
| #include "cpmsys.h" | ||||
| 
 | ||||
| ssize_t read(int fd, void* buffer, size_t count) | ||||
| { | ||||
| 	short save; | ||||
| 	unsigned char before_n; | ||||
| 	uint8_t* bbuffer = buffer; | ||||
| 	struct FCBE* fcbe = &__fd[fd]; | ||||
| 	uint8_t olduser; | ||||
| 	ssize_t result; | ||||
| 
 | ||||
| 	if (fd != 0) | ||||
|     __init_file_descriptors(); | ||||
| 	if (fcbe->fcb.dr == 0) | ||||
| 	{ | ||||
| 		errno = EBADF; | ||||
| 		return -1; | ||||
| 		/* Read from the console. */ | ||||
| 
 | ||||
| 		if (count == 0) | ||||
| 			return 0; | ||||
| 		*(uint8_t*)buffer = cpm_conin(); | ||||
| 		return 1; | ||||
| 	} | ||||
| 
 | ||||
| 	return fread(buffer, 1, count, stdin); | ||||
| 	olduser = cpm_get_user(); | ||||
| 	cpm_set_user(fcbe->user); | ||||
| 
 | ||||
| 	if (U16(fcbe->fcb.r) >= fcbe->length) | ||||
| 		goto done; | ||||
| 	if (fcbe->offset || !SECTOR_ALIGNED(count)) | ||||
| 	{ | ||||
| 		uint8_t delta; | ||||
| 
 | ||||
| 		/* We need to read bytes until we're at a sector boundary. */ | ||||
| 
 | ||||
| 		cpm_set_dma(__transfer_buffer); | ||||
| 		if (cpm_read_random_safe(&fcbe->fcb) != 0) | ||||
| 			goto eio; | ||||
| 
 | ||||
| 		/* Copy enough bytes to reach the end of the sector. */ | ||||
| 
 | ||||
| 		delta = 128 - fcbe->offset; | ||||
| 		if (delta > count) | ||||
| 			delta = count; | ||||
| 		memcpy(bbuffer, __transfer_buffer+fcbe->offset, delta); | ||||
| 		fcbe->offset += delta; | ||||
| 		count -= delta; | ||||
| 		bbuffer += delta; | ||||
| 
 | ||||
| 		/* If we've read enough bytes, advance to the next sector. */ | ||||
| 
 | ||||
| 		if (fcbe->offset == 128) | ||||
| 		{ | ||||
| 			U16(fcbe->fcb.r)++; | ||||
| 			fcbe->offset = 0; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	while (count >= 128) | ||||
| 	{ | ||||
| 		if (U16(fcbe->fcb.r) >= fcbe->length) | ||||
| 			goto done; | ||||
| 
 | ||||
| 		/* Read entire sectors directly into the destination buffer. */ | ||||
| 
 | ||||
| 		cpm_set_dma(bbuffer); | ||||
| 		if (cpm_read_random_safe(&fcbe->fcb) != 0) | ||||
| 			goto eio; | ||||
| 		count -= 128; | ||||
| 		bbuffer += 128; | ||||
| 		U16(fcbe->fcb.r)++; | ||||
| 	} | ||||
| 
 | ||||
| 	if (count != 0) | ||||
| 	{ | ||||
| 		if (U16(fcbe->fcb.r) >= fcbe->length) | ||||
| 			goto done; | ||||
| 
 | ||||
| 		/* There's some trailing data to read. */ | ||||
| 
 | ||||
| 		cpm_set_dma(__transfer_buffer); | ||||
| 		if (cpm_read_random_safe(&fcbe->fcb) != 0) | ||||
| 			goto eio; | ||||
| 
 | ||||
| 		memcpy(bbuffer, __transfer_buffer, count); | ||||
| 		fcbe->offset = count; | ||||
| 	} | ||||
| 
 | ||||
| done: | ||||
| 	result = bbuffer - (uint8_t*)buffer; | ||||
| exit: | ||||
| 	cpm_set_user(olduser); | ||||
| 	return result; | ||||
| 
 | ||||
| eio: | ||||
| 	errno = EIO; | ||||
| 	result = -1; | ||||
| 	goto exit; | ||||
| } | ||||
|  |  | |||
|  | @ -6,7 +6,9 @@ | |||
| #include <stdlib.h> | ||||
| #include <errno.h> | ||||
| #include <unistd.h> | ||||
| #include <string.h> | ||||
| #include <cpm.h> | ||||
| #include "cpmsys.h" | ||||
| 
 | ||||
| void _sys_write_tty(char c) | ||||
| { | ||||
|  | @ -17,24 +19,103 @@ void _sys_write_tty(char c) | |||
| 
 | ||||
| ssize_t write(int fd, void* buffer, size_t count) | ||||
| { | ||||
| 	int i; | ||||
| 	char* p = buffer; | ||||
| 	 | ||||
| 	/* We're only allowed to write to fd 0, 1 or 2. */ | ||||
| 	 | ||||
| 	if ((fd < 0) || (fd > 2)) | ||||
| 	uint8_t* bbuffer = buffer; | ||||
| 	struct FCBE* fcbe = &__fd[fd]; | ||||
| 	uint8_t olduser; | ||||
| 	uint16_t result; | ||||
| 
 | ||||
|     __init_file_descriptors(); | ||||
| 	if (fcbe->fcb.dr == 0) | ||||
| 	{ | ||||
| 		errno = EBADF; | ||||
| 		return -1; | ||||
| 		/* Write to the console. */ | ||||
| 
 | ||||
| 		size_t i = count; | ||||
| 		while (i--) | ||||
| 			_sys_write_tty(*bbuffer++); | ||||
| 		return count; | ||||
| 	} | ||||
| 	 | ||||
| 	/* Write all data. */ | ||||
| 	 | ||||
| 	i = count; | ||||
| 	while (i--) | ||||
| 		_sys_write_tty(*p++); | ||||
| 	 | ||||
| 	/* No failures. */ | ||||
| 	 | ||||
| 	return count; | ||||
| 
 | ||||
| 	olduser = cpm_get_user(); | ||||
| 	cpm_set_user(fcbe->user); | ||||
| 
 | ||||
| 	if (fcbe->offset || !SECTOR_ALIGNED(count)) | ||||
| 	{ | ||||
| 		uint8_t delta; | ||||
| 
 | ||||
| 		/* We're not at a sector boundary, so we need to do a
 | ||||
| 		 * read/modify/write of the initial fragment. */ | ||||
| 
 | ||||
| 		cpm_set_dma(__transfer_buffer); | ||||
| 		if (cpm_read_random_safe(&fcbe->fcb) != 0) | ||||
| 			goto eio; | ||||
| 
 | ||||
| 		/* Copy enough bytes to reach the end of the sector. */ | ||||
| 
 | ||||
| 		delta = 128 - fcbe->offset; | ||||
| 		if (delta > count) | ||||
| 			delta = count; | ||||
| 		memcpy(__transfer_buffer+fcbe->offset, bbuffer, delta); | ||||
| 		fcbe->offset += delta; | ||||
| 		count -= delta; | ||||
| 		bbuffer += delta; | ||||
| 
 | ||||
| 		/* Write back. */ | ||||
| 
 | ||||
| 		if (cpm_write_random(&fcbe->fcb) != 0) | ||||
| 			goto eio; | ||||
| 
 | ||||
| 		/* If we've written enough bytes, advance to the next sector. */ | ||||
| 
 | ||||
| 		if (fcbe->offset == 128) | ||||
| 		{ | ||||
| 			U16(fcbe->fcb.r)++; | ||||
| 			fcbe->offset = 0; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	while (count >= 128) | ||||
| 	{ | ||||
| 		/* Write entire sectors directly from the source buffer. */ | ||||
| 
 | ||||
| 		cpm_set_dma(bbuffer); | ||||
| 		if (cpm_write_random(&fcbe->fcb) != 0) | ||||
| 			goto eio; | ||||
| 		count -= 128; | ||||
| 		bbuffer += 128; | ||||
| 		U16(fcbe->fcb.r)++; | ||||
| 	} | ||||
| 
 | ||||
| 	if (count != 0) | ||||
| 	{ | ||||
| 		/* There's some trailing data to write. We need another
 | ||||
| 		 * read/modify/write cycle. */ | ||||
| 
 | ||||
| 		cpm_set_dma(__transfer_buffer); | ||||
| 		if (cpm_read_random_safe(&fcbe->fcb) != 0) | ||||
| 			goto eio; | ||||
| 
 | ||||
| 		memcpy(__transfer_buffer, bbuffer, count); | ||||
| 
 | ||||
| 		if (cpm_write_random(&fcbe->fcb) != 0) | ||||
| 			goto eio; | ||||
| 
 | ||||
| 		fcbe->offset = count; | ||||
| 	} | ||||
| 
 | ||||
| 	if (U16(fcbe->fcb.r) >= fcbe->length) | ||||
| 	{ | ||||
| 		fcbe->length = U16(fcbe->fcb.r); | ||||
| 		if (fcbe->offset != 0) | ||||
| 			fcbe->length++; | ||||
| 	} | ||||
| 
 | ||||
| 	result = bbuffer - (uint8_t*)buffer; | ||||
| exit: | ||||
| 	cpm_set_user(olduser); | ||||
| 	return result; | ||||
| 
 | ||||
| eio: | ||||
| 	errno = EIO; | ||||
| 	result = -1; | ||||
| 	goto exit; | ||||
| } | ||||
|  |  | |||
		Loading…
	
	Add table
		
		Reference in a new issue