125 lines
		
	
	
	
		
			2.1 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			125 lines
		
	
	
	
		
			2.1 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /* $Source$
 | |
|  * $State$
 | |
|  * $Revision$
 | |
|  */
 | |
| 
 | |
| #include <stdlib.h>
 | |
| #include <errno.h>
 | |
| #include <unistd.h>
 | |
| #include <string.h>
 | |
| #include <cpm.h>
 | |
| #include "cpmsys.h"
 | |
| 
 | |
| void _sys_write_tty(char c)
 | |
| {
 | |
| 	if (c == '\n')
 | |
| 		cpm_conout('\r');
 | |
| 	cpm_conout(c);
 | |
| }
 | |
| 
 | |
| ssize_t write(int fd, void* buffer, size_t count)
 | |
| {
 | |
| 	const uint8_t* bbuffer = buffer;
 | |
| 	struct FCBE* fcbe = &__fd[fd];
 | |
| 	uint8_t olduser;
 | |
| 	uint16_t result;
 | |
| 	uint8_t* dest;
 | |
| 
 | |
|     __init_file_descriptors();
 | |
| 	if (fcbe->fcb.dr == 0)
 | |
| 	{
 | |
| 		/* Write to the console. */
 | |
| 
 | |
| 		size_t i = count;
 | |
| 		while (i--)
 | |
| 			_sys_write_tty(*bbuffer++);
 | |
| 		return count;
 | |
| 	}
 | |
| 
 | |
| 	olduser = cpm_get_user();
 | |
| 	cpm_set_user(fcbe->user);
 | |
| 
 | |
| 	if (fcbe->offset || !SECTOR_ALIGNED(count))
 | |
| 	{
 | |
| 		/* 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. */
 | |
| 
 | |
| 		dest = __transfer_buffer + fcbe->offset;
 | |
| 		while ((count != 0) && (fcbe->offset != 128))
 | |
| 		{
 | |
| 			*dest++ = *bbuffer++;
 | |
| 			fcbe->offset++;
 | |
| 			count--;
 | |
| 		}
 | |
| 
 | |
| 		/* 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;
 | |
| 
 | |
| 		dest = __transfer_buffer;
 | |
| 		while (count != 0)
 | |
| 		{
 | |
| 			*dest++ = *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;
 | |
| }
 |