151 lines
3.1 KiB
C
151 lines
3.1 KiB
C
#include "../uxn.h"
|
|
#include "file.h"
|
|
|
|
/*
|
|
Copyright (c) 2021 Devine Lu Linvega
|
|
Copyright (c) 2021 Andrew Alderwick
|
|
|
|
Permission to use, copy, modify, and distribute this software for any
|
|
purpose with or without fee is hereby granted, provided that the above
|
|
copyright notice and this permission notice appear in all copies.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
WITH REGARD TO THIS SOFTWARE.
|
|
*/
|
|
|
|
#define _POSIX_C_SOURCE 200809L
|
|
|
|
//#include <stdio.h>
|
|
//#include <dirent.h>
|
|
#include <string.h>
|
|
//#include <sys/stat.h>
|
|
//#include <unistd.h>
|
|
#include "plugin.h"
|
|
|
|
static int f = -1;
|
|
static DIR *d;
|
|
static char current_filename[4096];
|
|
static enum { IDLE,
|
|
FILE_READ,
|
|
FILE_WRITE,
|
|
DIR_READ } state;
|
|
static struct dirent *de;
|
|
|
|
void
|
|
file_cleanup(void)
|
|
{
|
|
if(f >= 0) {
|
|
rb->close(f);
|
|
f = -1;
|
|
}
|
|
if(d != NULL) {
|
|
rb->closedir(d);
|
|
d = NULL;
|
|
}
|
|
de = NULL;
|
|
state = IDLE;
|
|
}
|
|
|
|
static Uint16
|
|
get_entry(char *p, Uint16 len, const char *basename, struct dirinfo info)
|
|
{
|
|
if(len < rb->strlen(basename) + 7)
|
|
return 0;
|
|
else if(info.attribute & ATTR_DIRECTORY)
|
|
return rb->snprintf(p, len, "---- %s\n", basename);
|
|
else if(info.size < 0x10000)
|
|
return rb->snprintf(p, len, "%04x %s\n", (Uint16)info.size, basename);
|
|
else
|
|
return rb->snprintf(p, len, "???? %s\n", basename);
|
|
}
|
|
|
|
static Uint16
|
|
file_read_dir(char *dest, Uint16 len)
|
|
{
|
|
char *p = dest;
|
|
if(de == NULL) de = rb->readdir(d);
|
|
for(; de != NULL; de = rb->readdir(d)) {
|
|
Uint16 n;
|
|
if(de->d_name[0] == '.' && de->d_name[1] == '\0')
|
|
continue;
|
|
n = get_entry(p, len, de->d_name, rb->dir_get_info(d, de));
|
|
if(!n) break;
|
|
p += n;
|
|
len -= n;
|
|
}
|
|
return p - dest;
|
|
}
|
|
|
|
Uint16
|
|
file_init(const char *filename)
|
|
{
|
|
file_cleanup();
|
|
rb->snprintf(current_filename, sizeof(current_filename), "/%s", (filename[0] == '/') ? &filename[1] : filename);
|
|
return 0;
|
|
}
|
|
|
|
Uint16
|
|
file_read(void *dest, Uint16 len)
|
|
{
|
|
if(state != FILE_READ && state != DIR_READ) {
|
|
file_cleanup();
|
|
if((d = rb->opendir(current_filename)) != NULL)
|
|
state = DIR_READ;
|
|
else if((f = rb->open(current_filename, O_RDONLY)) >= 0)
|
|
state = FILE_READ;
|
|
}
|
|
if(state == FILE_READ) {
|
|
return rb->read(f, dest, len);
|
|
}
|
|
if(state == DIR_READ)
|
|
return file_read_dir(dest, len);
|
|
return 0;
|
|
}
|
|
|
|
Uint16
|
|
file_write(void *src, Uint16 len, Uint8 flags)
|
|
{
|
|
Uint16 ret = 0;
|
|
if(state != FILE_WRITE) {
|
|
file_cleanup();
|
|
if((f = rb->open(current_filename, O_WRONLY | ((flags & 0x01) ? O_APPEND : 0))) >= 0)
|
|
state = FILE_WRITE;
|
|
}
|
|
if(state == FILE_WRITE) {
|
|
ret = rb->write(f, src, len);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
Uint16
|
|
file_stat(void *dest, Uint16 len)
|
|
{
|
|
DIR *sd;
|
|
struct dirent *sde;
|
|
char *basename = rb->strrchr(current_filename, '/');
|
|
if(basename != current_filename) {
|
|
*basename = '\0';
|
|
sd = rb->opendir(current_filename);
|
|
*basename++ = '/';
|
|
} else {
|
|
sd = rb->opendir("/");
|
|
++basename;
|
|
}
|
|
if(sd == NULL) return 0;
|
|
while((sde = rb->readdir(sd)) != NULL) {
|
|
if(!rb->strcmp(sde->d_name, basename)) {
|
|
Uint16 ret = get_entry(dest, len, basename, rb->dir_get_info(sd, sde));
|
|
rb->closedir(sd);
|
|
return ret;
|
|
}
|
|
}
|
|
rb->closedir(sd);
|
|
return 0;
|
|
}
|
|
|
|
Uint16
|
|
file_delete(void)
|
|
{
|
|
return rb->remove(current_filename);
|
|
}
|