First pass at file I/O. Some things missing. Thanks, gadget!
This commit is contained in:
parent
a73c19154d
commit
ea985a42fd
8 changed files with 345 additions and 40 deletions
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -32,6 +32,8 @@ extern "C"
|
|||
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "stddclmr.h"
|
||||
|
||||
#include "api.h"
|
||||
|
|
297
f256lib/file.c
297
f256lib/file.c
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Add table
Reference in a new issue