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
32
build.lua
32
build.lua
|
@ -7,24 +7,24 @@ vars.ackcflags = {
|
||||||
vars.ackldflags = {}
|
vars.ackldflags = {}
|
||||||
vars.plats = {
|
vars.plats = {
|
||||||
"cpm",
|
"cpm",
|
||||||
"linux386",
|
-- "linux386",
|
||||||
"linux68k",
|
-- "linux68k",
|
||||||
"linuxppc",
|
-- "linuxppc",
|
||||||
"linuxmips",
|
-- "linuxmips",
|
||||||
"osx386",
|
-- "osx386",
|
||||||
"osxppc",
|
-- "osxppc",
|
||||||
"pc86",
|
-- "pc86",
|
||||||
"rpi",
|
-- "rpi",
|
||||||
"pdpv7",
|
-- "pdpv7",
|
||||||
"em22",
|
-- "em22",
|
||||||
}
|
}
|
||||||
vars.plats_with_tests = {
|
vars.plats_with_tests = {
|
||||||
"cpm",
|
-- "cpm",
|
||||||
"linux68k",
|
-- "linux68k",
|
||||||
"linux386",
|
-- "linux386",
|
||||||
"linuxppc",
|
-- "linuxppc",
|
||||||
"linuxmips",
|
-- "linuxmips",
|
||||||
"pc86",
|
-- "pc86",
|
||||||
}
|
}
|
||||||
|
|
||||||
installable {
|
installable {
|
||||||
|
|
|
@ -25,7 +25,9 @@ struct FILE {
|
||||||
#define _IOWRITING 0x100
|
#define _IOWRITING 0x100
|
||||||
#define _IOAPPEND 0x200
|
#define _IOAPPEND 0x200
|
||||||
|
|
||||||
|
#if !defined BUFSIZ
|
||||||
#define BUFSIZ 1024
|
#define BUFSIZ 1024
|
||||||
|
#endif
|
||||||
|
|
||||||
#define FOPEN_MAX 20
|
#define FOPEN_MAX 20
|
||||||
extern FILE *__iotab[FOPEN_MAX];
|
extern FILE *__iotab[FOPEN_MAX];
|
||||||
|
|
|
@ -77,6 +77,7 @@ name led
|
||||||
(.e:{TAIL}={PLATFORMDIR}/libem.a \
|
(.e:{TAIL}={PLATFORMDIR}/libem.a \
|
||||||
{PLATFORMDIR}/libsys.a \
|
{PLATFORMDIR}/libsys.a \
|
||||||
{PLATFORMDIR}/libc.a \
|
{PLATFORMDIR}/libc.a \
|
||||||
|
{PLATFORMDIR}/libsys.a \
|
||||||
{PLATFORMDIR}/libem.a \
|
{PLATFORMDIR}/libem.a \
|
||||||
{PLATFORMDIR}/libend.a)
|
{PLATFORMDIR}/libend.a)
|
||||||
linker
|
linker
|
||||||
|
|
|
@ -6,17 +6,21 @@
|
||||||
#ifndef _ACK_PLAT_H
|
#ifndef _ACK_PLAT_H
|
||||||
#define _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
|
/* We're providing a time() system call rather than wanting a wrapper around
|
||||||
* gettimeofday() in the libc. */
|
* gettimeofday() in the libc. */
|
||||||
|
|
||||||
#define ACKCONF_WANT_EMULATED_TIME 0
|
#define ACKCONF_WANT_EMULATED_TIME 0
|
||||||
|
|
||||||
/* CP/M's underlying file abstraction is weird and doesn't map well onto
|
/* Processes? CP/M? Hahahaha... */
|
||||||
* file descriptors. Disable the standard FILE* mechanism in favour of our
|
|
||||||
* own.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define ACKCONF_WANT_EMULATED_FILE 0
|
|
||||||
#define ACKCONF_WANT_EMULATED_POPEN 0
|
#define ACKCONF_WANT_EMULATED_POPEN 0
|
||||||
|
|
||||||
|
/* We have a very small address space, so override the default buffer size. */
|
||||||
|
|
||||||
|
#define BUFSIZ 256
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -67,10 +67,19 @@ extern uint8_t* cpm_ramtop;
|
||||||
extern uint8_t cpm_cmdlinelen;
|
extern uint8_t cpm_cmdlinelen;
|
||||||
extern char cpm_cmdline[0x7f];
|
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
|
/* Special: if the CCP hasn't been overwritten, returns to it; otherwise does
|
||||||
* a warmboot. */
|
* a warmboot. */
|
||||||
extern void cpm_exit(void);
|
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. */
|
/* Extends cpm_ramtop over the CCP, for a little extra space. */
|
||||||
extern void cpm_overwrite_ccp(void);
|
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);
|
/* 37 */ extern uint8_t cpm_reset_drives(uint16_t drive_bitmap);
|
||||||
/* 40 */ extern uint8_t cpm_write_random_filled(FCB* fcb);
|
/* 40 */ extern uint8_t cpm_write_random_filled(FCB* fcb);
|
||||||
|
|
||||||
/* File descriptor emulation */
|
#define cpm_get_user() cpm_get_set_user(0xff)
|
||||||
|
#define cpm_set_user(u) cpm_get_set_user(u)
|
||||||
struct FCBE
|
|
||||||
{
|
|
||||||
FCB fcb; /* drive 0 means the console */
|
|
||||||
uint8_t user;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -47,28 +47,28 @@ local bdos_calls = {
|
||||||
|
|
||||||
local trap_calls = {
|
local trap_calls = {
|
||||||
"EARRAY",
|
"EARRAY",
|
||||||
|
"EBADGTO",
|
||||||
|
"EBADLAE",
|
||||||
|
"EBADLIN",
|
||||||
|
"EBADMON",
|
||||||
|
"EBADPC",
|
||||||
|
"EBADPTR",
|
||||||
|
"ECASE",
|
||||||
|
"ECONV",
|
||||||
|
"EFDIVZ",
|
||||||
|
"EFOVFL",
|
||||||
|
"EFUND",
|
||||||
|
"EFUNFL",
|
||||||
|
"EHEAP",
|
||||||
|
"EIDIVZ",
|
||||||
|
"EILLINS",
|
||||||
|
"EIOVFL",
|
||||||
|
"EIUND",
|
||||||
|
"EMEMFLT",
|
||||||
|
"EODDZ",
|
||||||
"ERANGE",
|
"ERANGE",
|
||||||
"ESET",
|
"ESET",
|
||||||
"EIOVFL",
|
|
||||||
"EFOVFL",
|
|
||||||
"EFUNFL",
|
|
||||||
"EIDIVZ",
|
|
||||||
"EFDIVZ",
|
|
||||||
"EIUND",
|
|
||||||
"EFUND",
|
|
||||||
"ECONV",
|
|
||||||
"ESTACK",
|
"ESTACK",
|
||||||
"EHEAP",
|
|
||||||
"EILLINS",
|
|
||||||
"EODDZ",
|
|
||||||
"ECASE",
|
|
||||||
"EMEMFLT",
|
|
||||||
"EBADPTR",
|
|
||||||
"EBADPC",
|
|
||||||
"EBADLAE",
|
|
||||||
"EBADMON",
|
|
||||||
"EBADLIN",
|
|
||||||
"EBADGTO",
|
|
||||||
"EUNIMPL",
|
"EUNIMPL",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,14 +1,31 @@
|
||||||
/* $Source$
|
|
||||||
* $State$
|
|
||||||
* $Revision$
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <cpm.h>
|
||||||
|
#include "cpmsys.h"
|
||||||
|
|
||||||
int close(int fd)
|
int close(int fd)
|
||||||
{
|
{
|
||||||
errno = EBADF;
|
struct FCBE* fcbe = &__fd[fd];
|
||||||
return -1;
|
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 <stdio.h>
|
||||||
#include <cpm.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$
|
#include <stdio.h>
|
||||||
* $State$
|
|
||||||
* $Revision$
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <sys/types.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <cpm.h>
|
||||||
|
#include "cpmsys.h"
|
||||||
|
|
||||||
off_t lseek(int fd, off_t offset, int whence)
|
off_t lseek(int fd, off_t offset, int whence)
|
||||||
{
|
{
|
||||||
errno = EINVAL;
|
struct FCBE* fcbe = &__fd[fd];
|
||||||
return -1;
|
|
||||||
|
__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$
|
#include <stdio.h>
|
||||||
* $State$
|
|
||||||
* $Revision$
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <cpm.h>
|
||||||
|
#include "cpmsys.h"
|
||||||
|
|
||||||
int open(const char* path, int access, ...)
|
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;
|
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 <stdlib.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <string.h>
|
||||||
#include <cpm.h>
|
#include <cpm.h>
|
||||||
|
#include "cpmsys.h"
|
||||||
|
|
||||||
ssize_t read(int fd, void* buffer, size_t count)
|
ssize_t read(int fd, void* buffer, size_t count)
|
||||||
{
|
{
|
||||||
short save;
|
uint8_t* bbuffer = buffer;
|
||||||
unsigned char before_n;
|
struct FCBE* fcbe = &__fd[fd];
|
||||||
|
uint8_t olduser;
|
||||||
|
ssize_t result;
|
||||||
|
|
||||||
if (fd != 0)
|
__init_file_descriptors();
|
||||||
|
if (fcbe->fcb.dr == 0)
|
||||||
{
|
{
|
||||||
errno = EBADF;
|
/* Read from the console. */
|
||||||
return -1;
|
|
||||||
|
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 <stdlib.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <string.h>
|
||||||
#include <cpm.h>
|
#include <cpm.h>
|
||||||
|
#include "cpmsys.h"
|
||||||
|
|
||||||
void _sys_write_tty(char c)
|
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)
|
ssize_t write(int fd, void* buffer, size_t count)
|
||||||
{
|
{
|
||||||
int i;
|
uint8_t* bbuffer = buffer;
|
||||||
char* p = buffer;
|
struct FCBE* fcbe = &__fd[fd];
|
||||||
|
uint8_t olduser;
|
||||||
/* We're only allowed to write to fd 0, 1 or 2. */
|
uint16_t result;
|
||||||
|
|
||||||
if ((fd < 0) || (fd > 2))
|
__init_file_descriptors();
|
||||||
|
if (fcbe->fcb.dr == 0)
|
||||||
{
|
{
|
||||||
errno = EBADF;
|
/* Write to the console. */
|
||||||
return -1;
|
|
||||||
|
size_t i = count;
|
||||||
|
while (i--)
|
||||||
|
_sys_write_tty(*bbuffer++);
|
||||||
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Write all data. */
|
olduser = cpm_get_user();
|
||||||
|
cpm_set_user(fcbe->user);
|
||||||
i = count;
|
|
||||||
while (i--)
|
if (fcbe->offset || !SECTOR_ALIGNED(count))
|
||||||
_sys_write_tty(*p++);
|
{
|
||||||
|
uint8_t delta;
|
||||||
/* No failures. */
|
|
||||||
|
/* We're not at a sector boundary, so we need to do a
|
||||||
return count;
|
* 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…
Reference in a new issue