First pass at file I/O. Some things missing. Thanks, gadget!

This commit is contained in:
Scott Duensing 2024-01-23 19:16:42 -06:00
parent a73c19154d
commit ea985a42fd
8 changed files with 345 additions and 40 deletions

View file

@ -29,17 +29,13 @@ void dirtest(void) {
DIR *dir;
struct dirent *dirent;
textPrint("Starting directory test.\n");
//textPrint("Starting directory test.\n");
if ((dir = opendir("0:"))) {
textPrint("Directory opened.\n");
//textPrint("Directory opened.\n");
for (;;) {
if ((dirent = readdir(dir))) {
textPrint("dirent type=");
textPrintInt(dirent->d_type);
textPrint("\n");
if (_DE_ISREG(dirent->d_type)) {
textPrint(dirent->d_name);
textPrint(" (");
@ -63,7 +59,7 @@ void dirtest(void) {
}
break;
}
textPrint("Closing.\n");
//textPrint("Closing.\n");
closedir(dir);
} else {
textPrint("Failed to open directory.\n");
@ -74,7 +70,8 @@ void dirtest(void) {
int main(void) {
f256Init();
dirtest();
// dirtest();
printf("Int = %d\n", sizeof(int));
return 0;
}

View file

@ -13,6 +13,9 @@
#include <stdint.h>
#pragma push_macro("EOF")
#undef EOF
struct call { // Mount at $ff00
long NextEvent; // Copy the next event into user-space.
@ -85,6 +88,7 @@ struct call { // Mount at $ff00
long Reject; // Reply to a received TCP packet with a REJECT message.
long Send; // Accept some new data and send an ACK along with any unACK'd data.
long Recv; // Copy any new TCP bytes into the user's buf and update the socket state.
long Close;
} TCP;
};
@ -98,8 +102,10 @@ struct call { // Mount at $ff00
struct {
long GetTime; // Get the date+time in BCD: YY,YY,MM,DD,HH,MM,SS,cS
long SetTime; //
long GetSysInfo; //
long SetBPS; //
long vectors816_1;
long vectors816_2; // 12 bytes skipped here.
long vectors816_3;
long SetTimer; //
} Config;
};
@ -408,4 +414,8 @@ struct event_t {
struct event_dir_t directory;
};
};
#pragma pop_macro("EOF")
#endif

View file

@ -32,6 +32,8 @@ extern "C"
#include <stdlib.h>
#include <stdio.h>
#include "stddclmr.h"
#include "api.h"

View file

@ -32,9 +32,35 @@
static char _dirStream[MAX_DRIVES];
static char *pathWithoutDrive(char *path, char *drive);
static bool findName(const char *name, int16_t *offset);
static char getIn(void); // This isn't the best place for this.
static int16_t kernelRead(uint8_t fd, void *buf, uint16_t nbytes);
static int16_t kernelWrite(uint8_t fd, void *buf, uint16_t nbytes);
static char *pathWithoutDrive(char *path, char *drive);
#pragma push_macro("close")
#undef close
void fileClose(uint8_t fd) {
kernelArgs->file.close.stream = fd;
kernelCall(File.Close);
for (;;) {
kernelNextEvent();
switch (kernelEventData.type) {
case kernelEvent(file.CLOSED):
case kernelEvent(file.ERROR):
return;
default:
continue;
}
}
}
#pragma pop_macro("close")
#pragma push_macro("close")
#undef close
int16_t fileCloseDir(fileDirT *dir) {
if (!dir) return -1;
@ -54,6 +80,44 @@ int16_t fileCloseDir(fileDirT *dir) {
}
}
}
#pragma pop_macro("close")
int16_t fileOpen(char *fname, char *mode) {
int16_t ret = 0;
uint8_t m = 0; // Default to READ.
char drive;
char *c;
fname = pathWithoutDrive(fname, &drive);
c = mode;
while (*c != 0) {
if (*c == 'w') m = 1; // WRITE
if (*c == 'a') m = 2; // APPEND
c++;
}
kernelArgs->common.buf = (uint8_t *)fname;
kernelArgs->common.buflen = strlen(fname);
kernelArgs->file.open.drive = drive;
kernelArgs->file.open.mode = m;
ret = kernelCall(File.Open);
if (kernelError) return -1;
for (;;) {
kernelNextEvent();
switch (kernelEventData.type) {
case kernelEvent(file.OPENED):
return ret;
case kernelEvent(file.NOT_FOUND):
case kernelEvent(file.ERROR):
return -1;
default:
continue;
}
}
}
fileDirT *fileOpenDir(char *name) {
@ -69,21 +133,11 @@ fileDirT *fileOpenDir(char *name) {
kernelArgs->common.buf = name;
kernelArgs->common.buflen = strlen(name);
stream = kernelCall(Directory.Open);
textPrint("kernelError = "); textPrintInt(kernelError); textPrint("\n");
textPrint("kernelReturn = "); textPrintInt(kernelReturn); textPrint("\n");
textPrint("stream = "); textPrintInt(stream); textPrint("\n");
if (kernelError) return NULL;
for (;;) {
kernelNextEvent();
if (kernelEventData.type != 0) {
textPrintInt(kernelEventData.type);
textPrint(" ");
}
if (kernelEventData.type == kernelEvent(directory.OPENED)) break;
if (kernelEventData.type == kernelEvent(directory.ERROR)) return NULL;
}
@ -96,30 +150,40 @@ fileDirT *fileOpenDir(char *name) {
}
int16_t fileRead(void *buf, uint16_t nbytes, uint16_t nmemb, uint8_t fd) {
char *data = (char *)buf;
int16_t gathered = 0;
int16_t returned;
uint16_t bytes = nbytes * nmemb;
while (gathered < bytes) {
returned = kernelRead(fd, data + gathered, bytes - gathered);
if (returned <= 0) break;
gathered += returned;
}
return gathered;
}
#pragma push_macro("EOF")
#pragma push_macro("FILE")
#undef EOF
#undef FILE
fileDirEntT *fileReadDir(fileDirT *dir) {
static fileDirEntT dirent;
unsigned len;
uint16_t len;
if (!dir) return NULL;
textPrint("Calling Directory.Read.\n");
textPrint("stream = "); textPrintInt(*dir->stream); textPrint("\n");
kernelArgs->directory.read.stream = *dir->stream;
kernelCall(Directory.Read);
if (kernelError) return NULL;
textPrint("Directory.Read called.\n");
for (;;) {
kernelNextEvent();
switch (kernelEventData.type) {
textPrintInt(kernelEventData.type);
textPrint(" ");
case kernelEvent(directory.VOLUME):
dirent.d_blocks = 0;
dirent.d_type = 2;
@ -163,6 +227,49 @@ fileDirEntT *fileReadDir(fileDirT *dir) {
return &dirent;
}
}
#pragma pop_macro("FILE")
#pragma pop_macro("EOF")
int16_t fileRename(char *name, char *to) {
char drive;
char drive2;
char stream;
int16_t path1;
int16_t path2;
name = pathWithoutDrive(name, &drive);
to = pathWithoutDrive(to, &drive2);
// ensure that the paths match
if (false
|| (drive != drive2)
|| !findName(name, &path1)
|| !findName(to, &path2)
|| (path1 != path2)
|| (strncmp(name, to, path1) != 0)
) {
return -1;
}
to += path2;
kernelArgs->file.delete.drive = drive;
kernelArgs->common.buf = name;
kernelArgs->common.buflen = strlen(name);
kernelArgs->common.ext = to;
kernelArgs->common.extlen = strlen(to);
stream = kernelCall(File.Rename);
if (kernelError) return -1;
for (;;) {
kernelNextEvent();
if (kernelEventData.type == kernelEvent(file.RENAMED)) break;
if (kernelEventData.type == kernelEvent(file.ERROR)) return -1;
}
return 0;
}
void fileReset(void) {
@ -172,6 +279,152 @@ void fileReset(void) {
}
int16_t fileUnlink(char *name) {
char drive;
char stream;
name = pathWithoutDrive(name, &drive);
kernelArgs->file.delete.drive = drive;
kernelArgs->common.buf = name;
kernelArgs->common.buflen = strlen(name);
stream = kernelCall(File.Delete);
if (kernelError) return -1;
for (;;) {
kernelNextEvent();
if (kernelEventData.type == kernelEvent(file.DELETED)) break;
if (kernelEventData.type == kernelEvent(file.ERROR)) return -1;
}
return 0;
}
int16_t fileWrite(void *buf, uint16_t nbytes, uint16_t nmemb, uint8_t fd) {
uint8_t *data = (uint8_t *)buf;
int16_t total = 0;
int16_t bytes = nbytes * nmemb;
uint8_t writing;
int16_t written;
int16_t i;
char *text;
if (fd == 1) {
text = (char *)buf;
for (i = 0; i < bytes; i++) {
__putchar(text[i]);
}
return i;
}
while (bytes) {
if (bytes > 254) {
writing = 254;
} else {
writing = bytes;
}
written = kernelWrite(fd, data + total, writing);
if (written <= 0) {
return -1;
}
total += written;
bytes -= written;
}
return total;
}
static bool findName(const char *name, int16_t *offset) {
int16_t i;
int16_t pos;
for (i = pos = 0; name[i]; i++) {
if (name[i] == '/') {
pos = i+1;
if (!name[pos]) {
// No base name found!
return false;
}
}
}
*offset = pos;
return true;
}
static char getIn(void) {
while (1) {
kernelNextEvent();
if (kernelError) {
kernelCall(Yield);
continue;
}
if (kernelEventData.type != kernelEvent(key.PRESSED)) continue;
if (kernelEventData.key.flags) continue; // Meta key.
return kernelEventData.key.ascii;
}
}
#pragma push_macro("EOF")
#undef EOF
static int16_t kernelRead(uint8_t fd, void *buf, uint16_t nbytes) {
if (fd == 0) {
// stdin
*(char *)buf = getIn();
return 1;
}
if (nbytes > 256) nbytes = 256;
kernelArgs->file.read.stream = fd;
kernelArgs->file.read.buflen = nbytes;
kernelCall(File.Read);
if (kernelError) return -1;
for(;;) {
kernelNextEvent();
switch (kernelEventData.type) {
case kernelEvent(file.DATA):
kernelArgs->common.buf = buf;
kernelArgs->common.buflen = kernelEventData.file.data.delivered;
kernelCall(ReadData);
if (!kernelEventData.file.data.delivered) return 256;
return kernelEventData.file.data.delivered;
case kernelEvent(file.EOF):
return 0;
case kernelEvent(file.ERROR):
return -1;
default:
continue;
}
}
}
#pragma pop_macro("EOF")
static int16_t kernelWrite(uint8_t fd, void *buf, uint16_t nbytes) {
kernelArgs->file.read.stream = fd;
kernelArgs->common.buf = buf;
kernelArgs->common.buflen = nbytes;
kernelCall(File.Write);
if (kernelError) return -1;
for (;;) {
kernelNextEvent();
if (kernelEventData.type == kernelEvent(file.WROTE)) return kernelEventData.file.data.delivered;
if (kernelEventData.type == kernelEvent(file.ERROR)) return -1;
}
}
static char *pathWithoutDrive(char *path, char *drive) {
*drive = 0;

View file

@ -45,10 +45,16 @@ typedef struct fileDirEntS {
} fileDirEntT;
void fileClose(uint8_t fd);
int16_t fileCloseDir(fileDirT *dir);
int16_t fileOpen(char *fname, char *mode);
fileDirT *fileOpenDir(char *name);
int16_t fileRead(void *buf, uint16_t nbytes, uint16_t nmemb, uint8_t fd);
fileDirEntT *fileReadDir(fileDirT *dir);
int16_t fileRename(char *name, char *to);
void fileReset(void);
int16_t fileUnlink(char *name);
int16_t fileWrite(void *buf, uint16_t nbytes, uint16_t nmemb, uint8_t fd);
#define _DE_ISREG(t) (t == 0)
@ -59,11 +65,18 @@ void fileReset(void);
// Aliases to the standard names if they don't exist.
#ifndef DIR
#define close fileClose
#define closedir fileCloseDir
#define DIR fileDirT
#define dirent fileDirEntS
#define FILE uint8_t
#define fopen fileOpen
#define fread fileRead
#define fwrite fileWrite
#define opendir fileOpenDir
#define closedir fileCloseDir
#define readdir fileReadDir
#define rename fileRename
#define unlink fileUnlink
#endif

View file

@ -38,13 +38,33 @@ extern "C"
#define kernelEvent(member) (size_t)(&((struct events *)0)->member)
#define kernelVector(member) (size_t)(&((struct call *)0xff00)->member)
#define kernelCall(fn) \
({ asm("jsr %[addy] \n" \
"stz %[err] \n" \
"ror %[err] \n" \
"sta %[ret]" \
: [err] "+m"(kernelError), [ret] "+m"(kernelReturn) \
: [addy] "i"(kernelVector(fn)) \
: "a", "x", "y", "c", "v"); kernelReturn; })
({ asm( \
"jsr %[addy] \n" \
"sta (%[ret]) \n" \
"lda #0 \n" \
"ror a \n" \
"sta (%[err]) \n" \
: [err] "=m"(kernelError), [ret] "=m"(kernelReturn) \
: [addy] "i"(kernelVector(fn)) \
: "a", "c", "v"); \
kernelReturn; })
/*
asm (
".text\n"
".global kernelwrapper\n"
"kernelwrapper: \n"
" jsr 1f \n"
" tax \n"
" lda #0 \n"
" ror a \n"
" sta (__rs2) \n"
" txa \n"
" rts \n"
"1: jmp (__rs1) \n"
);
unsigned char kernelwrapper(void *vector, char *error);
#define kernelCall(fn) kernelwrapper((void*)kernelVector(fn), &kernelError)
*/
typedef struct event_t kernelEventT;

View file

@ -54,6 +54,14 @@ static byte _bcolor = 0;
static byte _ccolor = 240;
// printf() support.
void __putchar(char c) {
static char s[2] = { 0, 0 };
s[0] = c;
textPrint(s);
}
// Clear screen to current text attributes.
void textClear(void) {
byte mmu = PEEK(MMU_IO_CTRL); // Get current MMU state.

View file

@ -59,6 +59,8 @@ typedef enum textColorsE {
extern colorT textColors[16];
void __putchar(char c); // Allows printf().
void textClear(void);
void textDefineColor(byte slot, byte fr, byte fg, byte fb, byte br, byte bg, byte bb);
void textGetXY(byte *x, byte *y);