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:
Kelvin Sherlock 2018-07-07 00:49:36 -04:00
parent e9fe5b8678
commit d1057c52f3
3 changed files with 327 additions and 31 deletions

View File

@ -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 },

View File

@ -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));

View File

@ -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));