Working on file operations.
This commit is contained in:
parent
496ef13a94
commit
03046dcf11
8 changed files with 332 additions and 39 deletions
|
@ -24,33 +24,57 @@
|
||||||
#include "f256.h"
|
#include "f256.h"
|
||||||
|
|
||||||
|
|
||||||
int main(void) {
|
void dirtest(void) {
|
||||||
byte x;
|
|
||||||
byte y;
|
|
||||||
|
|
||||||
|
DIR *dir;
|
||||||
|
struct dirent *dirent;
|
||||||
|
|
||||||
|
textPrint("Starting directory test.\n");
|
||||||
|
|
||||||
|
if ((dir = opendir("0:"))) {
|
||||||
|
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(" (");
|
||||||
|
textPrintInt(dirent->d_blocks);
|
||||||
|
textPrint(")\n");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_DE_ISDIR(dirent->d_type)) {
|
||||||
|
textPrint(dirent->d_name);
|
||||||
|
textPrint("/\n");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_DE_ISLBL(dirent->d_type)) {
|
||||||
|
textPrint("Directory of ");
|
||||||
|
textPrint(dirent->d_name);
|
||||||
|
textPrint(":\n");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
textPrint("Closing.\n");
|
||||||
|
closedir(dir);
|
||||||
|
} else {
|
||||||
|
textPrint("Failed to open directory.\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
f256Init();
|
f256Init();
|
||||||
|
|
||||||
textPrint("F256 LIVES!\n");
|
dirtest();
|
||||||
textSetColor(LIGHT_GREEN, BLACK);
|
|
||||||
textPrint("Green!\n\n");
|
|
||||||
textSetColor(ORANGE, BLACK);
|
|
||||||
textPrint("byte is "); textPrintInt(sizeof(byte));
|
|
||||||
textPrint("\nint is "); textPrintInt(sizeof(int));
|
|
||||||
textPrint("\nint16_t is "); textPrintInt(sizeof(int16_t));
|
|
||||||
textPrint("\nint32_t is "); textPrintInt(sizeof(int32_t));
|
|
||||||
textPrint("\n");
|
|
||||||
|
|
||||||
textPrint("\nEvent Size: "); textPrintInt(sizeof(kernelEvent(key.PRESSED)));
|
|
||||||
textPrint("\n\n");
|
|
||||||
textGetXY(&x, &y);
|
|
||||||
|
|
||||||
while(1) {
|
|
||||||
//kernelCall(NextEvent);
|
|
||||||
textGotoXY(x, y);
|
|
||||||
textPrint("Pending: ");
|
|
||||||
textPrintInt(kernelGetPending());
|
|
||||||
textPrint(" ");
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
#include "tile.c"
|
#include "tile.c"
|
||||||
#include "graphics.c"
|
#include "graphics.c"
|
||||||
#include "sprite.c"
|
#include "sprite.c"
|
||||||
|
#include "file.c"
|
||||||
|
|
||||||
|
|
||||||
void f256Init(void) {
|
void f256Init(void) {
|
||||||
|
@ -58,6 +59,7 @@ void f256Init(void) {
|
||||||
bitmapReset();
|
bitmapReset();
|
||||||
tileReset();
|
tileReset();
|
||||||
spriteReset();
|
spriteReset();
|
||||||
|
fileReset();
|
||||||
|
|
||||||
randomSeed(0); //***TODO*** Use clock or something.
|
randomSeed(0); //***TODO*** Use clock or something.
|
||||||
}
|
}
|
||||||
|
|
|
@ -163,6 +163,7 @@ void FAR_POKE(uint32_t address, byte value);
|
||||||
#include "tile.h"
|
#include "tile.h"
|
||||||
#include "graphics.h"
|
#include "graphics.h"
|
||||||
#include "sprite.h"
|
#include "sprite.h"
|
||||||
|
#include "file.h"
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|
185
f256lib/file.c
Normal file
185
f256lib/file.c
Normal file
|
@ -0,0 +1,185 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2024 Scott Duensing, scott@kangaroopunch.com
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "file.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define MAX_DRIVES 8
|
||||||
|
|
||||||
|
|
||||||
|
static char _dirStream[MAX_DRIVES];
|
||||||
|
|
||||||
|
|
||||||
|
static char *pathWithoutDrive(char *path, char *drive);
|
||||||
|
|
||||||
|
|
||||||
|
int16_t fileCloseDir(fileDirT *dir) {
|
||||||
|
if (!dir) return -1;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
if (*dir->stream) {
|
||||||
|
kernelArgs->directory.close.stream = *dir->stream;
|
||||||
|
kernelCall(Directory.Close);
|
||||||
|
if (!kernelError) {
|
||||||
|
*dir->stream = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
kernelNextEvent();
|
||||||
|
if (kernelEventData.type == kernelEvent(directory.CLOSED)) {
|
||||||
|
free(dir);
|
||||||
|
dir = NULL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fileDirT *fileOpenDir(char *name) {
|
||||||
|
char drive;
|
||||||
|
char stream;
|
||||||
|
fileDirT *dir;
|
||||||
|
|
||||||
|
name = pathWithoutDrive(name, &drive);
|
||||||
|
|
||||||
|
if (_dirStream[drive]) return NULL; // Only one at a time.
|
||||||
|
|
||||||
|
kernelArgs->directory.open.drive = drive;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
_dirStream[drive] = stream;
|
||||||
|
dir = (fileDirT *)malloc(sizeof(fileDirT));
|
||||||
|
dir->stream = &_dirStream[drive];
|
||||||
|
|
||||||
|
return dir;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fileDirEntT *fileReadDir(fileDirT *dir) {
|
||||||
|
static fileDirEntT dirent;
|
||||||
|
unsigned len;
|
||||||
|
|
||||||
|
if (!dir) return NULL;
|
||||||
|
|
||||||
|
textPrint("Calling Directory.Read.\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;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case kernelEvent(directory.FILE):
|
||||||
|
kernelArgs->common.buf = &dirent.d_blocks;
|
||||||
|
kernelArgs->common.buflen = sizeof(dirent.d_blocks);
|
||||||
|
kernelCall(ReadExt);
|
||||||
|
dirent.d_type = (dirent.d_blocks == 0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case kernelEvent(directory.FREE):
|
||||||
|
// dirent doesn't care about these types of records.
|
||||||
|
kernelArgs->directory.read.stream = *dir->stream;
|
||||||
|
kernelCall(Directory.Read);
|
||||||
|
if (!kernelError) continue;
|
||||||
|
// Fall through.
|
||||||
|
|
||||||
|
case kernelEvent(directory.EOF):
|
||||||
|
case kernelEvent(directory.ERROR):
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
default:
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy the name.
|
||||||
|
len = kernelEventData.directory.file.len;
|
||||||
|
if (len >= sizeof(dirent.d_name)) {
|
||||||
|
len = sizeof(dirent.d_name) - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len > 0) {
|
||||||
|
kernelArgs->common.buf = &dirent.d_name;
|
||||||
|
kernelArgs->common.buflen = len;
|
||||||
|
kernelCall(ReadData);
|
||||||
|
}
|
||||||
|
dirent.d_name[len] = '\0';
|
||||||
|
|
||||||
|
return &dirent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void fileReset(void) {
|
||||||
|
byte x;
|
||||||
|
|
||||||
|
for (x=0; x<MAX_DRIVES; x++) _dirStream[x] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static char *pathWithoutDrive(char *path, char *drive) {
|
||||||
|
*drive = 0;
|
||||||
|
|
||||||
|
if (strlen(path) < 2) return path;
|
||||||
|
if (path[1] != ':') return path;
|
||||||
|
if ((*path >= '0') && (*path <= '7')) *drive = *path - '0';
|
||||||
|
|
||||||
|
return (path + 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
75
f256lib/file.h
Normal file
75
f256lib/file.h
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2024 Scott Duensing, scott@kangaroopunch.com
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef FILE_H
|
||||||
|
#define FILE_H
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#include "f256.h"
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct fileDirS {
|
||||||
|
char *stream;
|
||||||
|
} fileDirT;
|
||||||
|
|
||||||
|
typedef struct fileDirEntS {
|
||||||
|
unsigned char d_blocks;
|
||||||
|
unsigned char d_type;
|
||||||
|
char d_name[256];
|
||||||
|
} fileDirEntT;
|
||||||
|
|
||||||
|
|
||||||
|
int16_t fileCloseDir(fileDirT *dir);
|
||||||
|
fileDirT *fileOpenDir(char *name);
|
||||||
|
fileDirEntT *fileReadDir(fileDirT *dir);
|
||||||
|
void fileReset(void);
|
||||||
|
|
||||||
|
|
||||||
|
#define _DE_ISREG(t) (t == 0)
|
||||||
|
#define _DE_ISDIR(t) (t == 1)
|
||||||
|
#define _DE_ISLBL(t) (t == 2)
|
||||||
|
#define _DE_ISLNK(t) (0)
|
||||||
|
|
||||||
|
|
||||||
|
// Aliases to the standard names if they don't exist.
|
||||||
|
#ifndef DIR
|
||||||
|
#define DIR fileDirT
|
||||||
|
#define dirent fileDirEntS
|
||||||
|
#define opendir fileOpenDir
|
||||||
|
#define closedir fileCloseDir
|
||||||
|
#define readdir fileReadDir
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#endif // FILE_H
|
|
@ -26,6 +26,7 @@
|
||||||
|
|
||||||
kernelEventT kernelEventData; // Allocate some RAM to hold event data.
|
kernelEventT kernelEventData; // Allocate some RAM to hold event data.
|
||||||
kernelArgsT *kernelArgs; // Create an alias for the kernel args.
|
kernelArgsT *kernelArgs; // Create an alias for the kernel args.
|
||||||
|
char kernelReturn;
|
||||||
char kernelError;
|
char kernelError;
|
||||||
|
|
||||||
|
|
||||||
|
@ -43,7 +44,7 @@ void kernelReset(void) {
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
case EVENT(JOYSTICK):
|
case EVENT(GAME):
|
||||||
// Joystick
|
// Joystick
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
|
@ -34,24 +34,27 @@ extern "C"
|
||||||
#include "f256.h"
|
#include "f256.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define kernelNextEvent() ({ kernelEventData.type = 0; kernelCall(NextEvent); })
|
||||||
#define kernelEvent(member) (size_t)(&((struct events *)0)->member)
|
#define kernelEvent(member) (size_t)(&((struct events *)0)->member)
|
||||||
#define kernelVector(member) (size_t)(&((struct call *)0xff00)->member)
|
#define kernelVector(member) (size_t)(&((struct call *)0xff00)->member)
|
||||||
#define kernelCall(fn) \
|
#define kernelCall(fn) \
|
||||||
asm("jsr %[addy] \n" \
|
({ asm("jsr %[addy] \n" \
|
||||||
"stz %[err] \n" \
|
"stz %[err] \n" \
|
||||||
"ror %[err]" \
|
"ror %[err] \n" \
|
||||||
: [err] "+m"(kernelError) \
|
"sta %[ret]" \
|
||||||
|
: [err] "+m"(kernelError), [ret] "+m"(kernelReturn) \
|
||||||
: [addy] "i"(kernelVector(fn)) \
|
: [addy] "i"(kernelVector(fn)) \
|
||||||
: "a", "x", "y", "c", "v");
|
: "a", "x", "y", "c", "v"); kernelReturn; })
|
||||||
|
|
||||||
|
|
||||||
typedef struct event_t kernelEventT;
|
typedef struct event_t kernelEventT;
|
||||||
typedef struct call_args kernelArgsT;
|
typedef struct call_args kernelArgsT;
|
||||||
|
|
||||||
|
|
||||||
extern char kernelError;
|
|
||||||
extern kernelArgsT *kernelArgs;
|
|
||||||
extern kernelEventT kernelEventData;
|
extern kernelEventT kernelEventData;
|
||||||
|
extern kernelArgsT *kernelArgs;
|
||||||
|
extern char kernelReturn;
|
||||||
|
extern char kernelError;
|
||||||
|
|
||||||
|
|
||||||
byte kernelGetPending(void);
|
byte kernelGetPending(void);
|
||||||
|
|
|
@ -112,10 +112,11 @@ void textGotoXY(byte x, byte y) {
|
||||||
|
|
||||||
// Print a string to the screen.
|
// Print a string to the screen.
|
||||||
void textPrint(char *message) {
|
void textPrint(char *message) {
|
||||||
int x = 0;
|
int16_t x = 0;
|
||||||
int i = 0;
|
int16_t i = 0;
|
||||||
int j = 0;
|
int16_t j = 0;
|
||||||
byte mmu = PEEK(MMU_IO_CTRL); // Get current MMU state.
|
int16_t m = 0;
|
||||||
|
byte mmu = PEEK(MMU_IO_CTRL); // Get current MMU state.
|
||||||
volatile byte *vram = (byte *)mathUnsignedAddition(TEXT_MATRIX, mathUnsignedMultiply(_MAX_COL, _row));
|
volatile byte *vram = (byte *)mathUnsignedAddition(TEXT_MATRIX, mathUnsignedMultiply(_MAX_COL, _row));
|
||||||
volatile byte *save = 0;
|
volatile byte *save = 0;
|
||||||
|
|
||||||
|
@ -136,9 +137,12 @@ void textPrint(char *message) {
|
||||||
if (_row == _MAX_ROW) {
|
if (_row == _MAX_ROW) {
|
||||||
// Scroll contents up one line.
|
// Scroll contents up one line.
|
||||||
vram = (byte *)TEXT_MATRIX;
|
vram = (byte *)TEXT_MATRIX;
|
||||||
|
m = _MAX_COL * (_MAX_ROW - 1); // mathUnsignedMultiply(_MAX_COL, (_MAX_ROW - 1)); // It REALLY doesn't like using the copro for this.
|
||||||
POKE(MMU_IO_CTRL, MMU_IO_COLOR); // Swap I/O page 3 into bank 6.
|
POKE(MMU_IO_CTRL, MMU_IO_COLOR); // Swap I/O page 3 into bank 6.
|
||||||
for (j=0; j<2; j++) {
|
for (j=0; j<2; j++) { // Twice - first is the text, second is color.
|
||||||
for (i = 0; i < mathUnsignedMultiply(_MAX_COL, (_MAX_ROW - 1)); i++) vram[i] = vram[i+_MAX_COL];
|
for (i = 0; i < m; i++) {
|
||||||
|
vram[i] = vram[i + _MAX_COL];
|
||||||
|
}
|
||||||
POKE(MMU_IO_CTRL, MMU_IO_TEXT); // Swap I/O page 2 into bank 6.
|
POKE(MMU_IO_CTRL, MMU_IO_TEXT); // Swap I/O page 2 into bank 6.
|
||||||
}
|
}
|
||||||
// Clear bottom line.
|
// Clear bottom line.
|
||||||
|
@ -238,8 +242,6 @@ void textSetCursor(byte c) {
|
||||||
|
|
||||||
|
|
||||||
void textSetDouble(bool x, bool y) {
|
void textSetDouble(bool x, bool y) {
|
||||||
//***TODO*** Adding this function seems to have screwed up scrolling.
|
|
||||||
|
|
||||||
POKE(VKY_MSTR_CTRL_1, (PEEK(VKY_MSTR_CTRL_1) & 0xf9) | (x << 1) | (y << 2));
|
POKE(VKY_MSTR_CTRL_1, (PEEK(VKY_MSTR_CTRL_1) & 0xf9) | (x << 1) | (y << 2));
|
||||||
|
|
||||||
_MAX_COL = x ? 40 : 80;
|
_MAX_COL = x ? 40 : 80;
|
||||||
|
|
Loading…
Add table
Reference in a new issue