more complete fs impl
This commit is contained in:
@@ -382,6 +382,8 @@ int main(int argc, char **argv) {
|
|||||||
|
|
||||||
nn_Component *eepromCard = nn_createVEEPROM(u, "eeprom", &veeprom, &nn_defaultEEPROMs[3]);
|
nn_Component *eepromCard = nn_createVEEPROM(u, "eeprom", &veeprom, &nn_defaultEEPROMs[3]);
|
||||||
|
|
||||||
|
nn_Component *managedfs = ncl_createFilesystem(u, "mainFS", "data/OpenOS", &nn_defaultFilesystems[3], true);
|
||||||
|
|
||||||
size_t ramTotal = 0;
|
size_t ramTotal = 0;
|
||||||
ramTotal += nn_ramSizes[5];
|
ramTotal += nn_ramSizes[5];
|
||||||
|
|
||||||
@@ -426,6 +428,7 @@ restart:;
|
|||||||
|
|
||||||
nn_mountComponent(c, ocelotCard, -1);
|
nn_mountComponent(c, ocelotCard, -1);
|
||||||
nn_mountComponent(c, eepromCard, 0);
|
nn_mountComponent(c, eepromCard, 0);
|
||||||
|
nn_mountComponent(c, managedfs, 1);
|
||||||
|
|
||||||
while(true) {
|
while(true) {
|
||||||
if(WindowShouldClose()) break;
|
if(WindowShouldClose()) break;
|
||||||
|
|||||||
263
src/ncomplib.c
263
src/ncomplib.c
@@ -2,7 +2,6 @@
|
|||||||
#include "ncomplib.h"
|
#include "ncomplib.h"
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdatomic.h>
|
|
||||||
|
|
||||||
static bool ncl_defaultHandler(ncl_VFSRequest *request);
|
static bool ncl_defaultHandler(ncl_VFSRequest *request);
|
||||||
|
|
||||||
@@ -74,15 +73,19 @@ bool ncl_defaultHandler(ncl_VFSRequest *request) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if(request->action == NCL_VFS_READDIR) {
|
if(request->action == NCL_VFS_READDIR) {
|
||||||
|
while(1) {
|
||||||
DIR *d = request->readdir.dir;
|
DIR *d = request->readdir.dir;
|
||||||
struct dirent *ent = readdir(d);
|
struct dirent *ent = readdir(d);
|
||||||
if(ent == NULL) {
|
if(ent == NULL) {
|
||||||
request->readdir.name = NULL;
|
request->readdir.name = NULL;
|
||||||
|
} else if(strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0) {
|
||||||
|
continue;
|
||||||
} else {
|
} else {
|
||||||
strncpy(request->readdir.name, ent->d_name, NN_MAX_PATH-1);
|
strncpy(request->readdir.name, ent->d_name, NN_MAX_PATH-1);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if(request->action == NCL_VFS_STAT) {
|
if(request->action == NCL_VFS_STAT) {
|
||||||
struct stat s;
|
struct stat s;
|
||||||
if(stat(request->stat.path, &s) != 0) {
|
if(stat(request->stat.path, &s) != 0) {
|
||||||
@@ -358,10 +361,10 @@ typedef struct ncl_FSState {
|
|||||||
size_t spaceUsed;
|
size_t spaceUsed;
|
||||||
// if 0, needs to be recomputed
|
// if 0, needs to be recomputed
|
||||||
size_t realSpaceUsed;
|
size_t realSpaceUsed;
|
||||||
atomic_size_t usage;
|
size_t usage;
|
||||||
bool isReadonly;
|
bool isReadonly;
|
||||||
// all the arrays
|
// all the arrays
|
||||||
FILE *fds[NN_MAX_OPENFILES];
|
void *fds[NN_MAX_OPENFILES];
|
||||||
void *dirs[NN_MAX_OPENFILES];
|
void *dirs[NN_MAX_OPENFILES];
|
||||||
char label[NN_MAX_LABEL];
|
char label[NN_MAX_LABEL];
|
||||||
size_t labellen;
|
size_t labellen;
|
||||||
@@ -372,7 +375,7 @@ typedef struct ncl_DriveState {
|
|||||||
nn_Lock *lock;
|
nn_Lock *lock;
|
||||||
nn_Drive conf;
|
nn_Drive conf;
|
||||||
bool isReadonly;
|
bool isReadonly;
|
||||||
atomic_size_t usage;
|
size_t usage;
|
||||||
size_t lastSector;
|
size_t lastSector;
|
||||||
char *path;
|
char *path;
|
||||||
FILE *file;
|
FILE *file;
|
||||||
@@ -385,22 +388,18 @@ typedef struct ncl_EEState {
|
|||||||
nn_Lock *lock;
|
nn_Lock *lock;
|
||||||
nn_EEPROM conf;
|
nn_EEPROM conf;
|
||||||
bool isReadonly;
|
bool isReadonly;
|
||||||
atomic_size_t usage;
|
size_t usage;
|
||||||
char *codepath;
|
char *codepath;
|
||||||
char *datapath;
|
char *datapath;
|
||||||
char label[NN_MAX_LABEL];
|
char label[NN_MAX_LABEL];
|
||||||
size_t labellen;
|
size_t labellen;
|
||||||
} ncl_EEState;
|
} ncl_EEState;
|
||||||
|
|
||||||
static void ncl_fixPath(ncl_VFS vfs, const char *path, char buf[NN_MAX_PATH]) {
|
static void ncl_fixPath(ncl_FSState *fs, const char *path, char buf[NN_MAX_PATH]) {
|
||||||
size_t len = 0;
|
snprintf(buf, NN_MAX_PATH, "%s%c%s", fs->path, fs->vfs.pathsep, path);
|
||||||
while(path[len]) {
|
for(size_t i = 0; buf[i]; i++) {
|
||||||
if(len == NN_MAX_PATH) break;
|
if(buf[i] == '/') buf[i] = fs->vfs.pathsep;
|
||||||
if(path[len] == '/') buf[len] = vfs.pathsep;
|
|
||||||
else buf[len] = path[len];
|
|
||||||
len++;
|
|
||||||
}
|
}
|
||||||
buf[len] = '\0';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// assumes locked
|
// assumes locked
|
||||||
@@ -420,6 +419,19 @@ static size_t ncl_fsGetRealUsage(ncl_FSState *fs) {
|
|||||||
return fs->realSpaceUsed;
|
return fs->realSpaceUsed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// -1 on too many
|
||||||
|
static int ncl_findFileDesc(void *fds[NN_MAX_OPENFILES]) {
|
||||||
|
for(int i = 0; i < NN_MAX_OPENFILES; i++) {
|
||||||
|
if(fds[i] == NULL) return i;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *ncl_getFile(void *fds[NN_MAX_OPENFILES], int fd) {
|
||||||
|
if(fd < 0 || fd > NN_MAX_OPENFILES) return NULL;
|
||||||
|
return fds[fd];
|
||||||
|
}
|
||||||
|
|
||||||
static nn_Exit ncl_fsHandler(nn_FSRequest *req) {
|
static nn_Exit ncl_fsHandler(nn_FSRequest *req) {
|
||||||
ncl_FSState *state = req->state;
|
ncl_FSState *state = req->state;
|
||||||
nn_Context *ctx = req->ctx;
|
nn_Context *ctx = req->ctx;
|
||||||
@@ -431,22 +443,243 @@ static nn_Exit ncl_fsHandler(nn_FSRequest *req) {
|
|||||||
if(state->fds[i] != NULL) ncl_closefile(state->vfs, state->fds[i]);
|
if(state->fds[i] != NULL) ncl_closefile(state->vfs, state->fds[i]);
|
||||||
if(state->dirs[i] != NULL) ncl_closedir(state->vfs, state->dirs[i]);
|
if(state->dirs[i] != NULL) ncl_closedir(state->vfs, state->dirs[i]);
|
||||||
}
|
}
|
||||||
|
nn_destroyLock(ctx, state->lock);
|
||||||
nn_strfree(ctx, state->path);
|
nn_strfree(ctx, state->path);
|
||||||
nn_free(ctx, state, sizeof(*state));
|
nn_free(ctx, state, sizeof(*state));
|
||||||
return NN_OK;
|
return NN_OK;
|
||||||
}
|
}
|
||||||
if(req->action == NN_FS_SPACEUSED) {
|
if(req->action == NN_FS_SPACEUSED) {
|
||||||
nn_lock(ctx, state->lock);
|
nn_lock(ctx, state->lock);
|
||||||
|
state->usage++;
|
||||||
req->spaceUsed = ncl_fsGetUsage(state);
|
req->spaceUsed = ncl_fsGetUsage(state);
|
||||||
nn_unlock(ctx, state->lock);
|
nn_unlock(ctx, state->lock);
|
||||||
return NN_OK;
|
return NN_OK;
|
||||||
}
|
}
|
||||||
|
if(req->action == NN_FS_GETLABEL) {
|
||||||
|
nn_lock(ctx, state->lock);
|
||||||
|
state->usage++;
|
||||||
|
size_t len = state->labellen;
|
||||||
|
if(len > req->getlabel.len) len = req->getlabel.len;
|
||||||
|
memcpy(req->getlabel.buf, state->label, len);
|
||||||
|
req->getlabel.len = len;
|
||||||
|
nn_unlock(ctx, state->lock);
|
||||||
|
return NN_OK;
|
||||||
|
}
|
||||||
|
if(req->action == NN_FS_SETLABEL) {
|
||||||
|
nn_lock(ctx, state->lock);
|
||||||
|
state->usage++;
|
||||||
|
size_t len = req->setlabel.len;
|
||||||
|
if(len > NN_MAX_LABEL) len = NN_MAX_LABEL;
|
||||||
|
memcpy(state->label, req->setlabel.buf, len);
|
||||||
|
state->labellen = len;
|
||||||
|
nn_unlock(ctx, state->lock);
|
||||||
|
return NN_OK;
|
||||||
|
}
|
||||||
|
if(req->action == NN_FS_ISRO) {
|
||||||
|
req->isReadonly = state->isReadonly;
|
||||||
|
return NN_OK;
|
||||||
|
}
|
||||||
|
if(req->action == NN_FS_OPEN) {
|
||||||
|
nn_lock(ctx, state->lock);
|
||||||
|
state->usage++;
|
||||||
|
int fd = ncl_findFileDesc(state->fds);
|
||||||
|
if(fd < 0) {
|
||||||
|
nn_unlock(ctx, state->lock);
|
||||||
|
nn_setError(C, "too many files");
|
||||||
|
return NN_EBADCALL;
|
||||||
|
}
|
||||||
|
const char *mode = req->open.mode;
|
||||||
|
if(mode[0] != 'r' && state->isReadonly) {
|
||||||
|
nn_unlock(ctx, state->lock);
|
||||||
|
nn_setError(C, "is readonly");
|
||||||
|
return NN_EBADCALL;
|
||||||
|
}
|
||||||
|
char path[NN_MAX_PATH];
|
||||||
|
ncl_fixPath(state, req->open.path, path);
|
||||||
|
void *file = ncl_openfile(state->vfs, path, mode);
|
||||||
|
if(file == NULL) {
|
||||||
|
nn_unlock(ctx, state->lock);
|
||||||
|
nn_setError(C, req->open.path);
|
||||||
|
return NN_EBADCALL;
|
||||||
|
}
|
||||||
|
state->fds[fd] = file;
|
||||||
|
req->fd = fd;
|
||||||
|
nn_unlock(ctx, state->lock);
|
||||||
|
return NN_OK;
|
||||||
|
}
|
||||||
|
if(req->action == NN_FS_CLOSE) {
|
||||||
|
nn_lock(ctx, state->lock);
|
||||||
|
int fd = req->fd;
|
||||||
|
void *file = ncl_getFile(state->fds, fd);
|
||||||
|
if(file == NULL) {
|
||||||
|
nn_unlock(ctx, state->lock);
|
||||||
|
nn_setError(C, "bad file descriptor");
|
||||||
|
return NN_EBADCALL;
|
||||||
|
}
|
||||||
|
state->fds[fd] = NULL;
|
||||||
|
volatile ncl_VFS vfs = state->vfs;
|
||||||
|
nn_unlock(ctx, state->lock);
|
||||||
|
// out of lock for the most minimal of performance
|
||||||
|
ncl_closefile(vfs, file);
|
||||||
|
return NN_OK;
|
||||||
|
}
|
||||||
|
if(req->action == NN_FS_READ) {
|
||||||
|
nn_lock(ctx, state->lock);
|
||||||
|
state->usage++;
|
||||||
|
void *file = ncl_getFile(state->fds, req->fd);
|
||||||
|
if(file == NULL) {
|
||||||
|
nn_unlock(ctx, state->lock);
|
||||||
|
nn_setError(C, "bad file descriptor");
|
||||||
|
return NN_EBADCALL;
|
||||||
|
}
|
||||||
|
if(!ncl_readfile(state->vfs, file, req->read.buf, &req->read.len)) {
|
||||||
|
req->read.buf = NULL;
|
||||||
|
}
|
||||||
|
nn_unlock(ctx, state->lock);
|
||||||
|
return NN_OK;
|
||||||
|
}
|
||||||
|
if(req->action == NN_FS_WRITE) {
|
||||||
|
nn_lock(ctx, state->lock);
|
||||||
|
state->usage++;
|
||||||
|
void *file = ncl_getFile(state->fds, req->fd);
|
||||||
|
if(file == NULL) {
|
||||||
|
nn_unlock(ctx, state->lock);
|
||||||
|
nn_setError(C, "bad file descriptor");
|
||||||
|
return NN_EBADCALL;
|
||||||
|
}
|
||||||
|
size_t spaceRemaining = state->conf.spaceTotal - ncl_fsGetUsage(state);
|
||||||
|
// inaccurate...
|
||||||
|
if(spaceRemaining < req->write.len) {
|
||||||
|
nn_unlock(ctx, state->lock);
|
||||||
|
nn_setError(C, "out of space");
|
||||||
|
return NN_EBADCALL;
|
||||||
|
}
|
||||||
|
bool ok = ncl_writefile(state->vfs, file, req->write.buf, req->write.len);
|
||||||
|
nn_unlock(ctx, state->lock);
|
||||||
|
if(ok) return NN_OK;
|
||||||
|
nn_setError(C, "write failed");
|
||||||
|
return NN_EBADCALL;
|
||||||
|
}
|
||||||
|
if(req->action == NN_FS_SEEK) {
|
||||||
|
nn_lock(ctx, state->lock);
|
||||||
|
void *file = ncl_getFile(state->fds, req->fd);
|
||||||
|
if(file == NULL) {
|
||||||
|
nn_unlock(ctx, state->lock);
|
||||||
|
nn_setError(C, "bad file descriptor");
|
||||||
|
return NN_EBADCALL;
|
||||||
|
}
|
||||||
|
bool ok = ncl_seekfile(state->vfs, file, req->seek.whence, &req->seek.off);
|
||||||
|
nn_unlock(ctx, state->lock);
|
||||||
|
if(ok) return NN_OK;
|
||||||
|
nn_setError(C, "seek failed");
|
||||||
|
return NN_EBADCALL;
|
||||||
|
}
|
||||||
|
if(req->action == NN_FS_OPENDIR) {
|
||||||
|
nn_lock(ctx, state->lock);
|
||||||
|
state->usage++;
|
||||||
|
int fd = ncl_findFileDesc(state->dirs);
|
||||||
|
if(fd < 0) {
|
||||||
|
nn_unlock(ctx, state->lock);
|
||||||
|
nn_setError(C, "too many directories listed simultaneously");
|
||||||
|
return NN_EBADCALL;
|
||||||
|
}
|
||||||
|
char path[NN_MAX_PATH];
|
||||||
|
ncl_fixPath(state, req->open.path, path);
|
||||||
|
void *dir = ncl_opendir(state->vfs, path);
|
||||||
|
if(dir == NULL) {
|
||||||
|
nn_unlock(ctx, state->lock);
|
||||||
|
nn_setError(C, req->opendir);
|
||||||
|
return NN_EBADCALL;
|
||||||
|
}
|
||||||
|
state->dirs[fd] = dir;
|
||||||
|
req->fd = fd;
|
||||||
|
nn_unlock(ctx, state->lock);
|
||||||
|
return NN_OK;
|
||||||
|
}
|
||||||
|
if(req->action == NN_FS_CLOSEDIR) {
|
||||||
|
nn_lock(ctx, state->lock);
|
||||||
|
int fd = req->fd;
|
||||||
|
void *file = ncl_getFile(state->dirs, fd);
|
||||||
|
if(file == NULL) {
|
||||||
|
nn_unlock(ctx, state->lock);
|
||||||
|
nn_setError(C, "bad file descriptor");
|
||||||
|
return NN_EBADCALL;
|
||||||
|
}
|
||||||
|
state->dirs[fd] = NULL;
|
||||||
|
volatile ncl_VFS vfs = state->vfs;
|
||||||
|
nn_unlock(ctx, state->lock);
|
||||||
|
// out of lock for the most minimal of performance
|
||||||
|
ncl_closedir(vfs, file);
|
||||||
|
return NN_OK;
|
||||||
|
}
|
||||||
|
if(req->action == NN_FS_READDIR) {
|
||||||
|
nn_lock(ctx, state->lock);
|
||||||
|
int fd = req->fd;
|
||||||
|
void *dir = ncl_getFile(state->dirs, fd);
|
||||||
|
if(dir == NULL) {
|
||||||
|
nn_unlock(ctx, state->lock);
|
||||||
|
nn_setError(C, "bad file descriptor");
|
||||||
|
return NN_EBADCALL;
|
||||||
|
}
|
||||||
|
char name[NN_MAX_PATH];
|
||||||
|
if(!ncl_readdir(state->vfs, dir, name)) {
|
||||||
|
nn_unlock(ctx, state->lock);
|
||||||
|
req->readdir.buf = NULL;
|
||||||
|
return NN_OK;
|
||||||
|
}
|
||||||
|
char path[NN_MAX_PATH];
|
||||||
|
snprintf(path, NN_MAX_PATH, "%s%c%s%c%s", state->path, state->vfs.pathsep, req->readdir.dirpath, state->vfs.pathsep, name);
|
||||||
|
ncl_Stat s;
|
||||||
|
if(!ncl_stat(state->vfs, path, &s)) s.isDirectory = false;
|
||||||
|
if(s.isDirectory) snprintf(req->readdir.buf, req->readdir.len, "%s/", name);
|
||||||
|
else snprintf(req->readdir.buf, req->readdir.len, "%s", name);
|
||||||
|
req->readdir.len = strlen(req->readdir.buf);
|
||||||
|
nn_unlock(ctx, state->lock);
|
||||||
|
return NN_OK;
|
||||||
|
}
|
||||||
|
|
||||||
if(C) nn_setError(C, "not implemented yet");
|
if(C) nn_setError(C, "not implemented yet");
|
||||||
return NN_EBADCALL;
|
return NN_EBADCALL;
|
||||||
}
|
}
|
||||||
|
|
||||||
nn_Component *ncl_createFilesystem(nn_Universe *universe, const char *address, const char *path, const nn_Filesystem *fs, bool isReadonly);
|
nn_Component *ncl_createFilesystem(nn_Universe *universe, const char *address, const char *path, const nn_Filesystem *fs, bool isReadonly) {
|
||||||
|
nn_Context *ctx = nn_getUniverseContext(universe);
|
||||||
|
|
||||||
|
ncl_FSState *state = nn_alloc(ctx, sizeof(*state));
|
||||||
|
if(state == NULL) return NULL;
|
||||||
|
state->ctx = ctx;
|
||||||
|
state->lock = nn_createLock(ctx);
|
||||||
|
if(state->lock == NULL) {
|
||||||
|
nn_free(ctx, state, sizeof(*state));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
state->path = nn_strdup(ctx, path);
|
||||||
|
if(state->path == NULL) {
|
||||||
|
nn_destroyLock(ctx, state->lock);
|
||||||
|
nn_free(ctx, state, sizeof(*state));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
state->vfs = ncl_defaultFS;
|
||||||
|
state->usage = 0;
|
||||||
|
state->isReadonly = isReadonly;
|
||||||
|
state->conf = *fs;
|
||||||
|
state->labellen = 0;
|
||||||
|
state->realSpaceUsed = 0;
|
||||||
|
state->spaceUsed = 0;
|
||||||
|
for(size_t i = 0; i < NN_MAX_OPENFILES; i++) {
|
||||||
|
state->fds[i] = NULL;
|
||||||
|
state->dirs[i] = NULL;
|
||||||
|
}
|
||||||
|
nn_Component *c = nn_createFilesystem(universe, address, fs, state, ncl_fsHandler);
|
||||||
|
if(c == NULL) {
|
||||||
|
nn_strfree(ctx, state->path);
|
||||||
|
nn_destroyLock(ctx, state->lock);
|
||||||
|
nn_free(ctx, state, sizeof(*state));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
nn_Component *ncl_createDrive(nn_Universe *universe, const char *address, const char *path, const nn_Drive *drive, bool isReadonly);
|
nn_Component *ncl_createDrive(nn_Universe *universe, const char *address, const char *path, const nn_Drive *drive, bool isReadonly);
|
||||||
nn_Component *ncl_createEEPROM(nn_Universe *universe, const char *address, const char *codepath, const char *datapath, bool isReadonly);
|
nn_Component *ncl_createEEPROM(nn_Universe *universe, const char *address, const char *codepath, const char *datapath, bool isReadonly);
|
||||||
|
|
||||||
@@ -619,8 +852,10 @@ bool ncl_makeReadonly(nn_Component *component) {
|
|||||||
void *state = nn_getComponentState(component);
|
void *state = nn_getComponentState(component);
|
||||||
if(strcmp(ty, NCL_FS) == 0) {
|
if(strcmp(ty, NCL_FS) == 0) {
|
||||||
ncl_FSState *fs = state;
|
ncl_FSState *fs = state;
|
||||||
|
nn_lock(fs->ctx, fs->lock);
|
||||||
fs->isReadonly = true;
|
fs->isReadonly = true;
|
||||||
fs->usage++;
|
fs->usage++;
|
||||||
|
nn_unlock(fs->ctx, fs->lock);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if(strcmp(ty, NCL_DRIVE) == 0) {
|
if(strcmp(ty, NCL_DRIVE) == 0) {
|
||||||
|
|||||||
@@ -777,6 +777,7 @@ typedef struct nn_Component {
|
|||||||
char *type;
|
char *type;
|
||||||
char *internalID;
|
char *internalID;
|
||||||
void *state;
|
void *state;
|
||||||
|
void *classState;
|
||||||
nn_ComponentHandler *handler;
|
nn_ComponentHandler *handler;
|
||||||
nn_Arena methodArena;
|
nn_Arena methodArena;
|
||||||
nn_HashMap methodsMap;
|
nn_HashMap methodsMap;
|
||||||
@@ -1457,6 +1458,7 @@ void nn_dropComponentN(nn_Component *c, size_t n) {
|
|||||||
|
|
||||||
nn_ComponentRequest req;
|
nn_ComponentRequest req;
|
||||||
req.state = c->state;
|
req.state = c->state;
|
||||||
|
req.classState = c->classState;
|
||||||
req.ctx = ctx;
|
req.ctx = ctx;
|
||||||
req.computer = NULL;
|
req.computer = NULL;
|
||||||
req.action = NN_COMP_DROP;
|
req.action = NN_COMP_DROP;
|
||||||
@@ -1477,6 +1479,10 @@ void nn_setComponentState(nn_Component *c, void *state) {
|
|||||||
c->state = state;
|
c->state = state;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void nn_setComponentClassState(nn_Component *c, void *state) {
|
||||||
|
c->classState = state;
|
||||||
|
}
|
||||||
|
|
||||||
nn_Exit nn_setComponentMethods(nn_Component *c, const nn_Method *methods) {
|
nn_Exit nn_setComponentMethods(nn_Component *c, const nn_Method *methods) {
|
||||||
size_t len = 0;
|
size_t len = 0;
|
||||||
while(methods[len].name != NULL) len++;
|
while(methods[len].name != NULL) len++;
|
||||||
@@ -1529,6 +1535,10 @@ void *nn_getComponentState(nn_Component *c) {
|
|||||||
return c->state;
|
return c->state;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void *nn_getComponentClassState(nn_Component *c) {
|
||||||
|
return c->classState;
|
||||||
|
}
|
||||||
|
|
||||||
// counts how many methods are registered. May return too many if some of them are not enabled.
|
// counts how many methods are registered. May return too many if some of them are not enabled.
|
||||||
size_t nn_countComponentMethods(nn_Component *c) {
|
size_t nn_countComponentMethods(nn_Component *c) {
|
||||||
return c->methodCount;
|
return c->methodCount;
|
||||||
@@ -1697,11 +1707,13 @@ nn_Exit nn_invokeComponent(nn_Computer *computer, const char *compAddress, const
|
|||||||
req.ctx = &c->universe->ctx;
|
req.ctx = &c->universe->ctx;
|
||||||
req.computer = computer;
|
req.computer = computer;
|
||||||
req.state = c->state;
|
req.state = c->state;
|
||||||
|
req.classState = c->classState;
|
||||||
req.action = NN_COMP_INVOKE;
|
req.action = NN_COMP_INVOKE;
|
||||||
req.methodIdx = m->idx;
|
req.methodIdx = m->idx;
|
||||||
req.returnCount = 0;
|
req.returnCount = 0;
|
||||||
nn_Exit e = c->handler(&req);
|
nn_Exit e = c->handler(&req);
|
||||||
if(e) {
|
if(e) {
|
||||||
|
if(e != NN_EBADCALL) nn_setErrorFromExit(computer, e);
|
||||||
nn_clearstack(computer);
|
nn_clearstack(computer);
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
@@ -1723,6 +1735,7 @@ nn_Exit nn_signalComponent(nn_Component *component, nn_Computer *computer, const
|
|||||||
req.ctx = &component->universe->ctx;
|
req.ctx = &component->universe->ctx;
|
||||||
req.computer = computer;
|
req.computer = computer;
|
||||||
req.state = component->state;
|
req.state = component->state;
|
||||||
|
req.classState = component->classState;
|
||||||
req.action = NN_COMP_SIGNAL;
|
req.action = NN_COMP_SIGNAL;
|
||||||
req.signal = signal;
|
req.signal = signal;
|
||||||
return component->handler(&req);
|
return component->handler(&req);
|
||||||
@@ -3125,18 +3138,17 @@ typedef enum nn_EENum {
|
|||||||
typedef struct nn_EEState {
|
typedef struct nn_EEState {
|
||||||
nn_Context *ctx;
|
nn_Context *ctx;
|
||||||
nn_EEPROM eeprom;
|
nn_EEPROM eeprom;
|
||||||
void *state;
|
|
||||||
nn_EEPROMHandler *handler;
|
nn_EEPROMHandler *handler;
|
||||||
} nn_EEState;
|
} nn_EEState;
|
||||||
|
|
||||||
static nn_Exit nn_eepromHandler(nn_ComponentRequest *req) {
|
static nn_Exit nn_eepromHandler(nn_ComponentRequest *req) {
|
||||||
if(req->action == NN_COMP_SIGNAL) return NN_OK;
|
if(req->action == NN_COMP_SIGNAL) return NN_OK;
|
||||||
if(req->action == NN_COMP_CHECKMETHOD) return NN_OK;
|
if(req->action == NN_COMP_CHECKMETHOD) return NN_OK;
|
||||||
nn_EEState *state = req->state;
|
nn_EEState *state = req->classState;
|
||||||
nn_EEPROMRequest ereq;
|
nn_EEPROMRequest ereq;
|
||||||
ereq.ctx = req->ctx;
|
ereq.ctx = req->ctx;
|
||||||
ereq.computer = req->computer;
|
ereq.computer = req->computer;
|
||||||
ereq.state = state->state;
|
ereq.state = req->state;
|
||||||
ereq.eeprom = &state->eeprom;
|
ereq.eeprom = &state->eeprom;
|
||||||
nn_EEPROM eeprom = state->eeprom;
|
nn_EEPROM eeprom = state->eeprom;
|
||||||
if(req->action == NN_COMP_DROP) {
|
if(req->action == NN_COMP_DROP) {
|
||||||
@@ -3277,9 +3289,9 @@ nn_Component *nn_createEEPROM(nn_Universe *universe, const char *address, const
|
|||||||
}
|
}
|
||||||
eestate->ctx = ctx;
|
eestate->ctx = ctx;
|
||||||
eestate->eeprom = *eeprom;
|
eestate->eeprom = *eeprom;
|
||||||
eestate->state = state;
|
|
||||||
eestate->handler = handler;
|
eestate->handler = handler;
|
||||||
nn_setComponentState(c, eestate);
|
nn_setComponentState(c, state);
|
||||||
|
nn_setComponentClassState(c, eestate);
|
||||||
nn_setComponentHandler(c, nn_eepromHandler);
|
nn_setComponentHandler(c, nn_eepromHandler);
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
@@ -3337,8 +3349,8 @@ static nn_Exit nn_veepromHandler(nn_EEPROMRequest *request) {
|
|||||||
}
|
}
|
||||||
if(request->action == NN_EEPROM_SETLABEL) {
|
if(request->action == NN_EEPROM_SETLABEL) {
|
||||||
if(request->buflen > NN_MAX_LABEL) request->buflen = NN_MAX_LABEL;
|
if(request->buflen > NN_MAX_LABEL) request->buflen = NN_MAX_LABEL;
|
||||||
state->datalen = request->buflen;
|
state->labellen = request->buflen;
|
||||||
nn_memcpy(state->data, request->robuf, state->datalen);
|
nn_memcpy(state->label, request->robuf, state->labellen);
|
||||||
return NN_OK;
|
return NN_OK;
|
||||||
}
|
}
|
||||||
if(request->action == NN_EEPROM_SETARCH) {
|
if(request->action == NN_EEPROM_SETARCH) {
|
||||||
@@ -3370,6 +3382,8 @@ nn_Component *nn_createVEEPROM(nn_Universe *universe, const char *address, const
|
|||||||
state->data = data;
|
state->data = data;
|
||||||
nn_memcpy(data, veeprom->data, veeprom->datalen);
|
nn_memcpy(data, veeprom->data, veeprom->datalen);
|
||||||
state->datalen = veeprom->datalen;
|
state->datalen = veeprom->datalen;
|
||||||
|
nn_memcpy(state->label, veeprom->label, veeprom->labellen);
|
||||||
|
state->labellen = veeprom->labellen;
|
||||||
|
|
||||||
nn_Component *c = nn_createEEPROM(universe, address, eeprom, state, nn_veepromHandler);
|
nn_Component *c = nn_createEEPROM(universe, address, eeprom, state, nn_veepromHandler);
|
||||||
if(c == NULL) goto fail;
|
if(c == NULL) goto fail;
|
||||||
@@ -3416,7 +3430,6 @@ typedef enum nn_FSNum {
|
|||||||
typedef struct nn_FSState {
|
typedef struct nn_FSState {
|
||||||
nn_Context *ctx;
|
nn_Context *ctx;
|
||||||
nn_Filesystem fs;
|
nn_Filesystem fs;
|
||||||
void *state;
|
|
||||||
nn_FSHandler *handler;
|
nn_FSHandler *handler;
|
||||||
} nn_FSState;
|
} nn_FSState;
|
||||||
|
|
||||||
@@ -3433,11 +3446,11 @@ static nn_Exit nn_fsPathCheck(nn_Computer *C, char buf[NN_MAX_PATH], const char
|
|||||||
static nn_Exit nn_fsHandler(nn_ComponentRequest *req) {
|
static nn_Exit nn_fsHandler(nn_ComponentRequest *req) {
|
||||||
if(req->action == NN_COMP_SIGNAL) return NN_OK;
|
if(req->action == NN_COMP_SIGNAL) return NN_OK;
|
||||||
if(req->action == NN_COMP_CHECKMETHOD) return NN_OK;
|
if(req->action == NN_COMP_CHECKMETHOD) return NN_OK;
|
||||||
nn_FSState *state = req->state;
|
nn_FSState *state = req->classState;
|
||||||
nn_FSRequest freq;
|
nn_FSRequest freq;
|
||||||
freq.ctx = req->ctx;
|
freq.ctx = req->ctx;
|
||||||
freq.computer = req->computer;
|
freq.computer = req->computer;
|
||||||
freq.state = state->state;
|
freq.state = req->state;
|
||||||
freq.fs = &state->fs;
|
freq.fs = &state->fs;
|
||||||
if(req->action == NN_COMP_DROP) {
|
if(req->action == NN_COMP_DROP) {
|
||||||
freq.action = NN_FS_DROP;
|
freq.action = NN_FS_DROP;
|
||||||
@@ -3513,7 +3526,7 @@ static nn_Exit nn_fsHandler(nn_ComponentRequest *req) {
|
|||||||
if(nn_checknumber(C, 1, "bad argument #2 (number expected)")) return NN_EBADCALL;
|
if(nn_checknumber(C, 1, "bad argument #2 (number expected)")) return NN_EBADCALL;
|
||||||
double requested = nn_tonumber(C, 1);
|
double requested = nn_tonumber(C, 1);
|
||||||
if(requested > NN_MAX_READ) requested = NN_MAX_READ;
|
if(requested > NN_MAX_READ) requested = NN_MAX_READ;
|
||||||
freq.action = NN_FS_CLOSE;
|
freq.action = NN_FS_READ;
|
||||||
freq.fd = nn_tointeger(C, 0);
|
freq.fd = nn_tointeger(C, 0);
|
||||||
char buf[NN_MAX_READ];
|
char buf[NN_MAX_READ];
|
||||||
freq.read.buf = buf;
|
freq.read.buf = buf;
|
||||||
@@ -3522,7 +3535,7 @@ static nn_Exit nn_fsHandler(nn_ComponentRequest *req) {
|
|||||||
if(e) return e;
|
if(e) return e;
|
||||||
if(freq.read.buf == NULL) return NN_OK;
|
if(freq.read.buf == NULL) return NN_OK;
|
||||||
req->returnCount = 1;
|
req->returnCount = 1;
|
||||||
return nn_pushbool(C, true);
|
return nn_pushlstring(C, buf, freq.read.len);
|
||||||
}
|
}
|
||||||
if(method == NN_FSNUM_WRITE) {
|
if(method == NN_FSNUM_WRITE) {
|
||||||
if(nn_checkinteger(C, 0, "bad argument #1 (fd expected)")) return NN_EBADCALL;
|
if(nn_checkinteger(C, 0, "bad argument #1 (fd expected)")) return NN_EBADCALL;
|
||||||
@@ -3587,6 +3600,7 @@ static nn_Exit nn_fsHandler(nn_ComponentRequest *req) {
|
|||||||
char name[NN_MAX_PATH];
|
char name[NN_MAX_PATH];
|
||||||
freq.action = NN_FS_READDIR;
|
freq.action = NN_FS_READDIR;
|
||||||
freq.fd = dirfd;
|
freq.fd = dirfd;
|
||||||
|
freq.readdir.dirpath = truepath;
|
||||||
freq.readdir.buf = name;
|
freq.readdir.buf = name;
|
||||||
freq.readdir.len = NN_MAX_PATH;
|
freq.readdir.len = NN_MAX_PATH;
|
||||||
e = state->handler(&freq);
|
e = state->handler(&freq);
|
||||||
@@ -3747,9 +3761,9 @@ nn_Component *nn_createFilesystem(nn_Universe *universe, const char *address, co
|
|||||||
}
|
}
|
||||||
fsstate->ctx = ctx;
|
fsstate->ctx = ctx;
|
||||||
fsstate->fs = *fs;
|
fsstate->fs = *fs;
|
||||||
fsstate->state = state;
|
|
||||||
fsstate->handler = handler;
|
fsstate->handler = handler;
|
||||||
nn_setComponentState(c, fsstate);
|
nn_setComponentState(c, state);
|
||||||
|
nn_setComponentClassState(c, fsstate);
|
||||||
nn_setComponentHandler(c, nn_fsHandler);
|
nn_setComponentHandler(c, nn_fsHandler);
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -547,6 +547,7 @@ typedef struct nn_ComponentRequest {
|
|||||||
nn_Context *ctx;
|
nn_Context *ctx;
|
||||||
nn_Computer *computer;
|
nn_Computer *computer;
|
||||||
void *state;
|
void *state;
|
||||||
|
void *classState;
|
||||||
nn_ComponentAction action;
|
nn_ComponentAction action;
|
||||||
// method index
|
// method index
|
||||||
unsigned int methodIdx;
|
unsigned int methodIdx;
|
||||||
@@ -573,6 +574,7 @@ void nn_dropComponentN(nn_Component *c, size_t n);
|
|||||||
// configure the state
|
// configure the state
|
||||||
void nn_setComponentHandler(nn_Component *c, nn_ComponentHandler *handler);
|
void nn_setComponentHandler(nn_Component *c, nn_ComponentHandler *handler);
|
||||||
void nn_setComponentState(nn_Component *c, void *state);
|
void nn_setComponentState(nn_Component *c, void *state);
|
||||||
|
void nn_setComponentClassState(nn_Component *c, void *state);
|
||||||
// sets the methods, same implications as setComponentMethodsArray.
|
// sets the methods, same implications as setComponentMethodsArray.
|
||||||
// methods is NULL-terminated, as in, it is terminated by a method with a NULL name.
|
// methods is NULL-terminated, as in, it is terminated by a method with a NULL name.
|
||||||
nn_Exit nn_setComponentMethods(nn_Component *c, const nn_Method *methods);
|
nn_Exit nn_setComponentMethods(nn_Component *c, const nn_Method *methods);
|
||||||
@@ -587,6 +589,8 @@ nn_Exit nn_setComponentTypeID(nn_Component *c, const char *internalTypeID);
|
|||||||
|
|
||||||
// get component state
|
// get component state
|
||||||
void *nn_getComponentState(nn_Component *c);
|
void *nn_getComponentState(nn_Component *c);
|
||||||
|
// get component class state
|
||||||
|
void *nn_getComponentClassState(nn_Component *c);
|
||||||
// counts how many methods are registered. May return too many if some of them are not enabled.
|
// counts how many methods are registered. May return too many if some of them are not enabled.
|
||||||
size_t nn_countComponentMethods(nn_Component *c);
|
size_t nn_countComponentMethods(nn_Component *c);
|
||||||
// will fill the methodnames array with the names of the *enabled* methods.
|
// will fill the methodnames array with the names of the *enabled* methods.
|
||||||
@@ -934,10 +938,10 @@ typedef enum nn_FSAction {
|
|||||||
|
|
||||||
// for file I/O
|
// for file I/O
|
||||||
NN_FS_OPEN,
|
NN_FS_OPEN,
|
||||||
|
NN_FS_CLOSE,
|
||||||
NN_FS_READ,
|
NN_FS_READ,
|
||||||
NN_FS_WRITE,
|
NN_FS_WRITE,
|
||||||
NN_FS_SEEK,
|
NN_FS_SEEK,
|
||||||
NN_FS_CLOSE,
|
|
||||||
|
|
||||||
// for list
|
// for list
|
||||||
NN_FS_OPENDIR,
|
NN_FS_OPENDIR,
|
||||||
@@ -986,6 +990,8 @@ typedef struct nn_FSRequest {
|
|||||||
} seek;
|
} seek;
|
||||||
const char *opendir;
|
const char *opendir;
|
||||||
struct {
|
struct {
|
||||||
|
// directory path, as a reminder if need be
|
||||||
|
const char *dirpath;
|
||||||
char *buf;
|
char *buf;
|
||||||
// set to length of entry name
|
// set to length of entry name
|
||||||
size_t len;
|
size_t len;
|
||||||
|
|||||||
Reference in New Issue
Block a user