mirror of
https://github.com/digarok/gsplus.git
synced 2025-01-14 03:30:41 +00:00
Host FST updates:
1. slightly improved logging 2. option to automatically translate cr/lf in text/source files 3. option to merlin encode text .S files 4. default file type for common source code files extensions.
This commit is contained in:
parent
e9fe5b8678
commit
d1057c52f3
@ -118,6 +118,8 @@ extern int g_win_status_debug_request;
|
||||
|
||||
extern char *g_cfg_host_path;
|
||||
extern int g_cfg_host_read_only;
|
||||
extern int g_cfg_host_crlf;
|
||||
extern int g_cfg_host_merlin;
|
||||
|
||||
extern int g_screen_index[];
|
||||
extern word32 g_full_refresh_needed;
|
||||
@ -244,6 +246,8 @@ Cfg_menu g_cfg_host_menu[] = {
|
||||
{ "Host FST Configuration", g_cfg_host_menu, 0, 0, CFGTYPE_MENU },
|
||||
{ "Shared Host Folder", KNMP(g_cfg_host_path), CFGTYPE_DIR },
|
||||
{ "Read Only,0,No,1,Yes", KNMP(g_cfg_host_read_only), CFGTYPE_INT },
|
||||
{ "CR/LF conversion,0,No,1,Yes", KNMP(g_cfg_host_crlf), CFGTYPE_INT },
|
||||
{ "Merlin conversion,0,No,1,Yes", KNMP(g_cfg_host_merlin), CFGTYPE_INT },
|
||||
{ "", 0, 0, 0, 0 },
|
||||
{ "Back to Main Config", g_cfg_main_menu, 0, 0, CFGTYPE_MENU },
|
||||
{ 0, 0, 0, 0, 0 },
|
||||
|
185
src/host_fst.c
185
src/host_fst.c
@ -74,6 +74,12 @@ enum {
|
||||
directory_file,
|
||||
};
|
||||
|
||||
enum {
|
||||
translate_none,
|
||||
translate_crlf,
|
||||
translate_merlin,
|
||||
};
|
||||
|
||||
|
||||
struct directory {
|
||||
int displacement;
|
||||
@ -88,6 +94,7 @@ struct fd_entry {
|
||||
int type;
|
||||
int access;
|
||||
int fd;
|
||||
int translate;
|
||||
struct directory *dir;
|
||||
};
|
||||
|
||||
@ -137,7 +144,8 @@ static int read_only = 0;
|
||||
|
||||
char *g_cfg_host_path = ""; // must not be null.
|
||||
int g_cfg_host_read_only = 0;
|
||||
|
||||
int g_cfg_host_crlf = 1;
|
||||
int g_cfg_host_merlin = 0;
|
||||
|
||||
/*
|
||||
* simple malloc pool to simplify code. Should never need > 4 allocations.
|
||||
@ -296,16 +304,92 @@ static word32 remove_fd(int cookie) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
static ssize_t safe_read(int fd, void *buffer, size_t count) {
|
||||
static void cr_to_lf(byte *buffer, size_t size) {
|
||||
size_t i;
|
||||
for (i = 0; i < size; ++i) {
|
||||
if (buffer[i] == '\r') buffer[i] = '\n';
|
||||
}
|
||||
}
|
||||
|
||||
static void lf_to_cr(byte *buffer, size_t size) {
|
||||
size_t i;
|
||||
for (i = 0; i < size; ++i) {
|
||||
if (buffer[i] == '\n') buffer[i] = '\r';
|
||||
}
|
||||
}
|
||||
|
||||
static void merlin_to_text(byte *buffer, size_t size) {
|
||||
size_t i;
|
||||
for (i = 0; i < size; ++i) {
|
||||
byte b = buffer[i];
|
||||
if (b == 0xa0) b = '\t';
|
||||
b &= 0x7f;
|
||||
if (b == '\r') b = '\n';
|
||||
buffer[i] = b;
|
||||
}
|
||||
}
|
||||
|
||||
static void text_to_merlin(byte *buffer, size_t size) {
|
||||
size_t i;
|
||||
for (i = 0; i < size; ++i) {
|
||||
byte b = buffer[i];
|
||||
if (b == '\t') b = 0xa0;
|
||||
if (b == '\n') b = '\r';
|
||||
if (b != ' ') b |= 0x80;
|
||||
buffer[i] = b;
|
||||
}
|
||||
}
|
||||
|
||||
static ssize_t safe_read(struct fd_entry *e, byte *buffer, size_t count) {
|
||||
int fd = e->fd;
|
||||
int tr = e->translate;
|
||||
|
||||
for (;;) {
|
||||
ssize_t ok = read(fd, buffer, count);
|
||||
if (ok >= 0) return ok;
|
||||
if (ok >= 0) {
|
||||
size_t i;
|
||||
if (tr == translate_crlf) {
|
||||
for (i = 0; i < ok; ++i) {
|
||||
if (buffer[i] == '\n') buffer[i] = '\r';
|
||||
}
|
||||
}
|
||||
if (tr == translate_merlin) {
|
||||
for (i = 0; i < ok; ++i) {
|
||||
unsigned char c = buffer[i];
|
||||
if (c == '\t') c = 0xa0;
|
||||
if (c == '\n') c = '\r';
|
||||
if (c != ' ') c |= 0x80;
|
||||
buffer[i] = c;
|
||||
}
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
if (ok < 0 && errno == EINTR) continue;
|
||||
return ok;
|
||||
}
|
||||
}
|
||||
|
||||
static ssize_t safe_write(int fd, const void *buffer, size_t count) {
|
||||
static ssize_t safe_write(struct fd_entry *e, byte *buffer, size_t count) {
|
||||
int fd = e->fd;
|
||||
int tr = e->translate;
|
||||
|
||||
if (tr == translate_crlf) {
|
||||
size_t i;
|
||||
for (i = 0; i < count; ++i) {
|
||||
if (buffer[i] == '\r') buffer[i] = '\n';
|
||||
}
|
||||
}
|
||||
if (tr == translate_merlin) {
|
||||
size_t i;
|
||||
for (i = 0; i < count; ++i) {
|
||||
unsigned char c = buffer[i];
|
||||
if (c == 0xa0) c = '\t';
|
||||
c &= 0x7f;
|
||||
if (c == '\r') c = '\n';
|
||||
buffer[i] = c;
|
||||
}
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
ssize_t ok = write(fd, buffer, count);
|
||||
if (ok >= 0) return ok;
|
||||
@ -517,6 +601,37 @@ static void get_file_xinfo(const char *path, struct file_info *fi) {
|
||||
}
|
||||
#endif
|
||||
|
||||
#undef _
|
||||
#define _(a, b, c) { a, sizeof(a) - 1, b, c }
|
||||
struct ftype_entry {
|
||||
char *ext;
|
||||
unsigned length;
|
||||
unsigned file_type;
|
||||
unsigned aux_type;
|
||||
};
|
||||
|
||||
static struct ftype_entry suffixes[] = {
|
||||
_("c", 0xb0, 0x0008),
|
||||
_("cc", 0xb0, 0x0008),
|
||||
_("h", 0xb0, 0x0008),
|
||||
_("rez", 0xb0, 0x0015),
|
||||
_("asm", 0xb0, 0x0003),
|
||||
_("mac", 0xb0, 0x0003),
|
||||
_("pas", 0xb0, 0x0005),
|
||||
_("txt", 0x04, 0x0000),
|
||||
_("text", 0x04, 0x0000),
|
||||
_("s", 0x04, 0x0000),
|
||||
{ 0, 0, 0, 0}
|
||||
};
|
||||
|
||||
static struct ftype_entry prefixes[] = {
|
||||
_("m16.", 0xb0, 0x0003),
|
||||
_("e16.", 0xb0, 0x0003),
|
||||
{ 0, 0, 0, 0}
|
||||
};
|
||||
|
||||
#undef _
|
||||
|
||||
static word32 get_file_info(const char *path, struct file_info *fi) {
|
||||
struct stat st;
|
||||
memset(fi, 0, sizeof(*fi));
|
||||
@ -564,6 +679,31 @@ static word32 get_file_info(const char *path, struct file_info *fi) {
|
||||
|
||||
if (S_ISREG(st.st_mode)) {
|
||||
get_file_xinfo(path, fi);
|
||||
|
||||
if (!fi->has_fi) {
|
||||
/* guess the file type / auxtype based on extension */
|
||||
int n;
|
||||
const char *dot = NULL;
|
||||
const char *slash = NULL;
|
||||
|
||||
for(n = 0; ; ++n) {
|
||||
char c = path[n];
|
||||
if (c == 0) break;
|
||||
else if (c == '/') { slash = path + n + 1; dot = NULL; }
|
||||
else if (c == '.') dot = path + n + 1;
|
||||
}
|
||||
|
||||
if (dot && *dot) {
|
||||
for (n = 0; n < sizeof(suffixes) / sizeof(suffixes[0]); ++n) {
|
||||
if (!suffixes[n].ext) break;
|
||||
if (!strcasecmp(dot, suffixes[n].ext)) {
|
||||
fi->file_type = suffixes[n].file_type;
|
||||
fi->aux_type = suffixes[n].aux_type;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// get file type/aux type
|
||||
@ -1551,6 +1691,20 @@ static word32 fst_open(int class, const char *path) {
|
||||
return tooManyFilesOpen;
|
||||
}
|
||||
|
||||
if (type == regular_file){
|
||||
|
||||
if (g_cfg_host_crlf) {
|
||||
if (fi.file_type == 0x04 || fi.file_type == 0xb0)
|
||||
e->translate = translate_crlf;
|
||||
}
|
||||
|
||||
if (g_cfg_host_merlin && fi.file_type == 0x04) {
|
||||
int n = strlen(path);
|
||||
if (n >= 3 && path[n-1] == 'S' && path[n-2] == '.')
|
||||
e->translate = translate_merlin;
|
||||
}
|
||||
}
|
||||
|
||||
e->access = access;
|
||||
e->path = strdup(path);
|
||||
e->type = type;
|
||||
@ -1610,7 +1764,7 @@ static word32 fst_read(int class) {
|
||||
|
||||
for (word32 i = 0 ; i < request_count; ++i) {
|
||||
byte b;
|
||||
ok = safe_read(e->fd, &b, 1);
|
||||
ok = safe_read(e, &b, 1);
|
||||
if (ok < 0) return map_errno();
|
||||
if (ok == 0) break;
|
||||
transfer_count++;
|
||||
@ -1623,7 +1777,8 @@ static word32 fst_read(int class) {
|
||||
byte *data = gc_malloc(request_count);
|
||||
if (!data) return outOfMem;
|
||||
|
||||
ok = safe_read(e->fd, data, request_count);
|
||||
|
||||
ok = safe_read(e, data, request_count);
|
||||
if (ok < 0) rv = map_errno();
|
||||
if (ok == 0) rv = eofEncountered;
|
||||
if (ok > 0) {
|
||||
@ -1685,7 +1840,7 @@ static word32 fst_write(int class) {
|
||||
}
|
||||
|
||||
word32 rv = 0;
|
||||
ssize_t ok = safe_write(e->fd, data, request_count);
|
||||
ssize_t ok = safe_write(e, data, request_count);
|
||||
if (ok < 0) rv = map_errno();
|
||||
if (ok > 0) {
|
||||
if (class)
|
||||
@ -2026,7 +2181,7 @@ static word32 fst_get_dir_entry(int class) {
|
||||
struct file_info fi;
|
||||
rv = get_file_info(fullpath, &fi);
|
||||
|
||||
|
||||
if (dname) fprintf(stderr, " - %s", dname);
|
||||
|
||||
// p16 and gs/os both use truncating c1 output string.
|
||||
rv = set_gsstr_truncate(name, dname);
|
||||
@ -2403,7 +2558,6 @@ void host_fst(void) {
|
||||
|
||||
fprintf(stderr, "Host FST: %04x %s", call, call_name(call));
|
||||
|
||||
|
||||
if (call & 0x8000) {
|
||||
fputs("\n", stderr);
|
||||
// system level.
|
||||
@ -2444,16 +2598,14 @@ void host_fst(void) {
|
||||
case 0x10:
|
||||
path1 = get_path1();
|
||||
break;
|
||||
case 0x04:
|
||||
path1 = get_path1();
|
||||
path2 = get_path2();
|
||||
break;
|
||||
|
||||
case 0x04:
|
||||
path1 = get_path1();
|
||||
path2 = get_path2();
|
||||
break;
|
||||
}
|
||||
|
||||
if (path1) fprintf(stderr, " - %s", path1);
|
||||
if (path2) fprintf(stderr, " - %s", path2);
|
||||
fputs("\n", stderr);
|
||||
|
||||
switch(call & 0xff) {
|
||||
case 0x01:
|
||||
@ -2551,8 +2703,7 @@ void host_fst(void) {
|
||||
acc = invalidFSTop;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
fputs("\n", stderr);
|
||||
}
|
||||
|
||||
if (acc) fprintf(stderr, " %02x %s\n", acc, error_name(acc));
|
||||
|
@ -36,6 +36,11 @@ enum {
|
||||
directory_file,
|
||||
};
|
||||
|
||||
enum {
|
||||
translate_none,
|
||||
translate_crlf,
|
||||
translate_merlin,
|
||||
};
|
||||
|
||||
struct directory {
|
||||
int displacement;
|
||||
@ -50,6 +55,7 @@ struct fd_entry {
|
||||
int type;
|
||||
int access;
|
||||
HANDLE handle;
|
||||
int translate;
|
||||
struct directory *dir;
|
||||
};
|
||||
|
||||
@ -171,6 +177,8 @@ static int read_only = 0;
|
||||
|
||||
char *g_cfg_host_path = ""; // must not be null.
|
||||
int g_cfg_host_read_only = 0;
|
||||
int g_cfg_host_crlf = 1;
|
||||
int g_cfg_host_merlin = 0;
|
||||
|
||||
|
||||
/*
|
||||
@ -342,6 +350,42 @@ static word32 remove_fd(int cookie) {
|
||||
}
|
||||
|
||||
|
||||
static void cr_to_lf(byte *buffer, size_t size) {
|
||||
size_t i;
|
||||
for (i = 0; i < size; ++i) {
|
||||
if (buffer[i] == '\r') buffer[i] = '\n';
|
||||
}
|
||||
}
|
||||
|
||||
static void lf_to_cr(byte *buffer, size_t size) {
|
||||
size_t i;
|
||||
for (i = 0; i < size; ++i) {
|
||||
if (buffer[i] == '\n') buffer[i] = '\r';
|
||||
}
|
||||
}
|
||||
|
||||
static void merlin_to_text(byte *buffer, size_t size) {
|
||||
size_t i;
|
||||
for (i = 0; i < size; ++i) {
|
||||
byte b = buffer[i];
|
||||
if (b == 0xa0) b = '\t';
|
||||
b &= 0x7f;
|
||||
if (b == '\r') b = '\n';
|
||||
buffer[i] = b;
|
||||
}
|
||||
}
|
||||
|
||||
static void text_to_merlin(byte *buffer, size_t size) {
|
||||
size_t i;
|
||||
for (i = 0; i < size; ++i) {
|
||||
byte b = buffer[i];
|
||||
if (b == '\t') b = 0xa0;
|
||||
if (b == '\n') b = '\r';
|
||||
if (b != ' ') b |= 0x80;
|
||||
buffer[i] = b;
|
||||
}
|
||||
}
|
||||
|
||||
struct file_info {
|
||||
|
||||
FILETIME create_date;
|
||||
@ -542,6 +586,39 @@ static word16 map_attributes(DWORD dwFileAttributes) {
|
||||
return access;
|
||||
}
|
||||
|
||||
#undef _
|
||||
#define _(a, b, c) { a, sizeof(a) - 1, b, c }
|
||||
struct ftype_entry {
|
||||
char *ext;
|
||||
unsigned length;
|
||||
unsigned file_type;
|
||||
unsigned aux_type;
|
||||
};
|
||||
|
||||
static struct ftype_entry suffixes[] = {
|
||||
_("c", 0xb0, 0x0008),
|
||||
_("cc", 0xb0, 0x0008),
|
||||
_("h", 0xb0, 0x0008),
|
||||
_("rez", 0xb0, 0x0015),
|
||||
_("asm", 0xb0, 0x0003),
|
||||
_("mac", 0xb0, 0x0003),
|
||||
_("pas", 0xb0, 0x0005),
|
||||
_("txt", 0x04, 0x0000),
|
||||
_("text", 0x04, 0x0000),
|
||||
_("s", 0x04, 0x0000),
|
||||
{ 0, 0, 0, 0}
|
||||
};
|
||||
|
||||
static struct ftype_entry prefixes[] = {
|
||||
_("m16.", 0xb0, 0x0003),
|
||||
_("e16.", 0xb0, 0x0003),
|
||||
{ 0, 0, 0, 0}
|
||||
};
|
||||
|
||||
#undef _
|
||||
|
||||
|
||||
|
||||
static word32 get_file_info(const char *path, struct file_info *fi) {
|
||||
|
||||
|
||||
@ -587,7 +664,33 @@ static word32 get_file_info(const char *path, struct file_info *fi) {
|
||||
|
||||
get_file_xinfo(path, fi);
|
||||
if (fi->resource_eof) fi->storage_type = extendedFile;
|
||||
|
||||
if (!fi->has_fi) {
|
||||
/* guess the file type / auxtype based on extension */
|
||||
int n;
|
||||
const char *dot = NULL;
|
||||
const char *slash = NULL;
|
||||
|
||||
for(n = 0; ; ++n) {
|
||||
char c = path[n];
|
||||
if (c == 0) break;
|
||||
else if (c == '/') { slash = path + n + 1; dot = NULL; }
|
||||
else if (c == '.') dot = path + n + 1;
|
||||
}
|
||||
|
||||
if (dot && *dot) {
|
||||
for (n = 0; n < sizeof(suffixes) / sizeof(suffixes[0]); ++n) {
|
||||
if (!suffixes[n].ext) break;
|
||||
if (!strcasecmp(dot, suffixes[n].ext)) {
|
||||
fi->file_type = suffixes[n].file_type;
|
||||
fi->aux_type = suffixes[n].aux_type;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 0x01 = read enable
|
||||
// 0x02 = write enable
|
||||
// 0x04 = invisible
|
||||
@ -1092,8 +1195,7 @@ static word32 fst_create(int class, const char *path) {
|
||||
|
||||
|
||||
if (pcount >= 4) {
|
||||
afp_init
|
||||
(&fi.afp, fi.file_type, fi.aux_type);
|
||||
afp_init(&fi.afp, fi.file_type, fi.aux_type);
|
||||
fi.has_fi = 1;
|
||||
}
|
||||
|
||||
@ -1105,8 +1207,7 @@ static word32 fst_create(int class, const char *path) {
|
||||
fi.storage_type = get_memory16_c(pb + CreateRec_storageType, 0);
|
||||
fi.create_date = get_date_time(pb + CreateRec_createDate);
|
||||
|
||||
afp_init
|
||||
(&fi.afp, fi.file_type, fi.aux_type);
|
||||
afp_init(&fi.afp, fi.file_type, fi.aux_type);
|
||||
fi.has_fi = 1;
|
||||
}
|
||||
int ok;
|
||||
@ -1114,7 +1215,7 @@ static word32 fst_create(int class, const char *path) {
|
||||
if (fi.storage_type == 0 && fi.file_type == 0x0f)
|
||||
fi.storage_type = 0x0d;
|
||||
|
||||
if (fi.storage_type == 0x0d || fi.storage_type == 0x0f) {
|
||||
if (fi.storage_type == 0x0d) {
|
||||
ok = CreateDirectory(path, NULL);
|
||||
if (!ok) return map_last_error();
|
||||
|
||||
@ -1720,6 +1821,22 @@ static word32 fst_open(int class, const char *path) {
|
||||
return tooManyFilesOpen;
|
||||
}
|
||||
|
||||
if (type == regular_file){
|
||||
|
||||
if (g_cfg_host_crlf) {
|
||||
if (fi.file_type == 0x04 || fi.file_type == 0xb0)
|
||||
e->translate = translate_crlf;
|
||||
}
|
||||
|
||||
if (g_cfg_host_merlin && fi.file_type == 0x04) {
|
||||
int n = strlen(path);
|
||||
if (n >= 3 && path[n-1] == 'S' && path[n-2] == '.')
|
||||
e->translate = translate_merlin;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
e->access = access;
|
||||
e->path = strdup(path);
|
||||
e->type = type;
|
||||
@ -1787,6 +1904,16 @@ static word32 fst_read(int class) {
|
||||
if (!ok) return map_last_error();
|
||||
if (read_count == 0) break;
|
||||
transfer_count++;
|
||||
|
||||
switch(e->translate) {
|
||||
case translate_crlf:
|
||||
lf_to_cr(&b, 1);
|
||||
break;
|
||||
case translate_merlin:
|
||||
text_to_merlin(&b, 1);
|
||||
break;
|
||||
}
|
||||
|
||||
set_memory_c(data_buffer++, b, 0);
|
||||
if (newline_table[b & newline_mask]) break;
|
||||
}
|
||||
@ -1802,6 +1929,14 @@ static word32 fst_read(int class) {
|
||||
else if (read_count == 0) rv = eofEncountered;
|
||||
if (read_count > 0) {
|
||||
transfer_count = read_count;
|
||||
switch(e->translate) {
|
||||
case translate_crlf:
|
||||
lf_to_cr(data, transfer_count);
|
||||
break;
|
||||
case translate_merlin:
|
||||
text_to_merlin(data, transfer_count);
|
||||
break;
|
||||
}
|
||||
for (size_t i = 0; i < transfer_count; ++i) {
|
||||
set_memory_c(data_buffer + i, data[i], 0);
|
||||
}
|
||||
@ -1858,6 +1993,14 @@ static word32 fst_write(int class) {
|
||||
data[i] = get_memory_c(data_buffer + i,0);
|
||||
}
|
||||
|
||||
switch (e->translate) {
|
||||
case translate_crlf:
|
||||
cr_to_lf(data, request_count);
|
||||
break;
|
||||
case translate_merlin:
|
||||
merlin_to_text(data, request_count);
|
||||
break;
|
||||
}
|
||||
word32 rv = 0;
|
||||
DWORD write_count = 0;
|
||||
int ok = WriteFile(e->handle, data, request_count, &write_count, NULL);
|
||||
@ -2128,6 +2271,7 @@ static word32 fst_get_dir_entry(int class) {
|
||||
struct file_info fi;
|
||||
rv = get_file_info(fullpath, &fi);
|
||||
|
||||
if (dname) fprintf(stderr, " - %s", dname);
|
||||
|
||||
// p16 and gs/os both use truncating c1 output string.
|
||||
rv = set_gsstr_truncate(name, dname);
|
||||
@ -2527,9 +2671,7 @@ void host_fst(void) {
|
||||
|
||||
fprintf(stderr, "Host FST: %04x %s", call, call_name(call));
|
||||
|
||||
|
||||
if (call & 0x8000) {
|
||||
fputs("\n", stderr);
|
||||
// system level.
|
||||
switch(call) {
|
||||
case 0x8001:
|
||||
@ -2568,15 +2710,15 @@ void host_fst(void) {
|
||||
case 0x10:
|
||||
path1 = get_path1();
|
||||
break;
|
||||
case 0x04:
|
||||
path1 = get_path1();
|
||||
path2 = get_path2();
|
||||
break;
|
||||
case 0x04:
|
||||
path1 = get_path1();
|
||||
path2 = get_path2();
|
||||
break;
|
||||
}
|
||||
|
||||
if (path1) fprintf(stderr, " - %s", path1);
|
||||
if (path2) fprintf(stderr, " - %s", path2);
|
||||
fputs("\n", stderr);
|
||||
|
||||
|
||||
switch(call & 0xff) {
|
||||
case 0x01:
|
||||
@ -2693,8 +2835,7 @@ void host_fst(void) {
|
||||
acc = invalidFSTop;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
fputs("\n", stderr);
|
||||
}
|
||||
|
||||
if (acc) fprintf(stderr, " %02x %s\n", acc, error_name(acc));
|
||||
|
Loading…
x
Reference in New Issue
Block a user