aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@zytor.com>2012-08-07 22:56:33 -0700
committerH. Peter Anvin <hpa@zytor.com>2012-08-07 22:56:33 -0700
commit040a718eca78e6b6a745c55963f83cafaa830ca6 (patch)
treee9530d196694687d2ed8a1dad79d181c4433384b
parent4e38eb13133ba2eaf35ff9421dac5251bdbb01e7 (diff)
downloadabc80-040a718eca78e6b6a745c55963f83cafaa830ca6.tar.gz
abc80-040a718eca78e6b6a745c55963f83cafaa830ca6.tar.xz
abc80-040a718eca78e6b6a745c55963f83cafaa830ca6.zip
abcprintd: make it possible to read a directory via PRA:
Make it possible to read a directory by opening PRA: without a filename.
-rw-r--r--tools/abcprint.txt1
-rw-r--r--tools/fileop.c184
2 files changed, 134 insertions, 51 deletions
diff --git a/tools/abcprint.txt b/tools/abcprint.txt
index ca2e9b3..acd64d3 100644
--- a/tools/abcprint.txt
+++ b/tools/abcprint.txt
@@ -19,6 +19,7 @@ FF A0 ss ixix NNNNNNNNEEE OPEN TEXT
ixix = Address of IX-map (used as a handle)
Open an existing file for reading in text mode
+ If the filename is empty (all spaces), read the directory
FF A1 ss ixix NNNNNNNNEEE OPEN BINARY
diff --git a/tools/fileop.c b/tools/fileop.c
index e597f4a..c0e4ff6 100644
--- a/tools/fileop.c
+++ b/tools/fileop.c
@@ -7,6 +7,9 @@
#include <inttypes.h>
#include <stdbool.h>
#include <wchar.h>
+#include <dirent.h>
+#include <sys/types.h>
+#include <sys/stat.h>
#ifndef O_TEXT
# define O_TEXT 0
@@ -54,6 +57,7 @@ static struct file_data *filemap[65536];
struct file_data {
FILE *f;
+ DIR *d;
};
static void send_reply(int fd, int status)
@@ -75,7 +79,10 @@ static void do_close(int fd, uint16_t ix)
struct file_data *fm = filemap[ix];
if (fm) {
- fclose(fm->f);
+ if (fm->f)
+ fclose(fm->f);
+ if (fm->d)
+ closedir(fm->d);
free(fm);
filemap[ix] = NULL;
send_reply(fd, 0);
@@ -96,7 +103,7 @@ static void do_closeall(int fd)
send_reply(fd, 0);
}
-static void unmangle_filename(char *out, const unsigned char *in)
+static void unmangle_filename(char *out, const char *in)
{
static const wchar_t my_tolower[256] =
L"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017"
@@ -118,7 +125,7 @@ static void unmangle_filename(char *out, const unsigned char *in)
for (i = 0; i < 8; i++) {
if (*in != ' ')
- out += wctomb(out, my_tolower[*in]);
+ out += wctomb(out, my_tolower[(unsigned char)*in]);
in++;
}
@@ -126,7 +133,7 @@ static void unmangle_filename(char *out, const unsigned char *in)
out += wctomb(out, L'.');
for (i = 0; i < 3; i++) {
if (*in != ' ')
- out += wctomb(out, my_tolower[*in]);
+ out += wctomb(out, my_tolower[(unsigned char)*in]);
in++;
}
}
@@ -148,25 +155,31 @@ static void do_open(int fd, uint16_t ix, char *name)
do_close(-1, ix);
- unmangle_filename(path, (const unsigned char *)name);
+ unmangle_filename(path, name);
- if (!path[0]) {
- /* Empty filename */
- send_reply(fd, 128+21); /* File not found */
- return;
- }
-
fm = calloc(1, sizeof(struct file_info *));
if (!fm) {
send_reply(fd, 128+42);
return;
}
- fm->f = fopen(path, modes[cmd[0] & 3]);
- if (!fm->f && errno == EACCES && !(cmd[0] & 2)) {
- fm->f = fopen(path, modes[(cmd[0] & 1)+4]);
+ if (!path[0]) {
+ /* Empty filename */
+
+ if ((cmd[0] & 3) == 0)
+ fm->d = opendir(".");
+ else
+ errno = ENOENT; /* File not found */
+ } else {
+ /* Actual filename */
+
+ fm->f = fopen(path, modes[cmd[0] & 3]);
+ if (!fm->f && errno == EACCES && !(cmd[0] & 2)) {
+ fm->f = fopen(path, modes[(cmd[0] & 1)+4]);
+ }
}
- if (!fm->f) {
+
+ if (!fm->f && !fm->d) {
free(fm);
switch (errno) {
#if 0 /* Enable this? */
@@ -201,7 +214,7 @@ static void do_read_block(int fd, uint16_t ix, uint16_t len)
unsigned char *data;
int dlen;
- if (!fm) {
+ if (!fm || !fm->f) {
send_reply(fd, 128+45);
return;
}
@@ -244,6 +257,54 @@ static void do_read_block(int fd, uint16_t ix, uint16_t len)
free(data);
}
+/*
+ * Returns 0 for OK, -1 for failure
+ */
+static int mangle_name(char *dst, const char *src)
+{
+ static const wchar_t srcset[] =
+ L"0123456789_."
+ L"ÉABCDEFGHIJKLMNOPQRSTUVWXYZÄÖÅÜÆØ"
+ L"éabcdefghijklmnopqrstuvwxyzäöåüæø";
+ static const char dstset[] =
+ "0123456789_."
+ "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^[\\"
+ "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^[\\";
+ char *d = dst;
+ const char *s;
+ wchar_t sc;
+ const wchar_t *scp;
+ char dc;
+ int n;
+ char unmangle_buf[64];
+
+ s = src;
+
+ memset(dst, ' ', 11);
+ dst[11] = '\0';
+
+ mbtowc(NULL, NULL, 0); /* Reset the shift state */
+
+ while (d < dst+11 && (n = mbtowc(&sc, s, (size_t)~0)) > 0) {
+ s += n;
+
+ if ( (scp = wcschr(srcset, sc)) ) {
+ dc = dstset[scp - srcset];
+ } else {
+ dc = '_';
+ }
+
+ if ( dc == '.' )
+ d = dst+8;
+ else
+ *d++ = dc;
+ }
+
+ unmangle_filename(unmangle_buf, dst);
+ return strcmp(unmangle_buf, src) ? 0 : -1;
+}
+
+
#define BUF_SIZE 256
static void do_input(int fd, uint16_t ix)
@@ -253,52 +314,73 @@ static void do_input(int fd, uint16_t ix)
char data[BUF_SIZE], data1[2*BUF_SIZE];
char *p, *q, c;
int dlen;
+ struct dirent *de;
+ struct stat st;
if (!fm) {
send_reply(fd, 128+45);
return;
}
- clearerr(fm->f);
- if (!fgets(data, sizeof data, fm->f)) {
- if (ferror(fm->f)) {
- switch (errno) {
- case EBADF:
- err = 128+44; /* Logisk fil ej öppen */
- break;
- case EIO:
- err = 128+35; /* Checksummafel vid läsning */
- break;
- default:
- err = 128+48; /* Fel i biblioteket */
- break;
+ if (fm->f) {
+ clearerr(fm->f);
+ if (!fgets(data, sizeof data, fm->f)) {
+ if (ferror(fm->f)) {
+ switch (errno) {
+ case EBADF:
+ err = 128+44; /* Logisk fil ej öppen */
+ break;
+ case EIO:
+ err = 128+35; /* Checksummafel vid läsning */
+ break;
+ default:
+ err = 128+48; /* Fel i biblioteket */
+ break;
+ }
+ } else {
+ /* EOF */
+ err = 128+34; /* Slut på filen */
}
} else {
- /* EOF */
- err = 128+34; /* Slut på filen */
+ /* Strip CR and change LF -> CR LF */
+ for (p = data, q = data1+2 ; (c = *p) ; p++) {
+ switch (c) {
+ case '\r':
+ break;
+ case '\n':
+ *q++ = '\r';
+ /* fall through */
+ default:
+ *q++ = c;
+ break;
+ }
+ }
+ dlen = q - (data1+2);
+ err = 0;
}
- send_reply(fd, err);
- return;
+ } else if (fm->d) {
+ while ( (de = readdir(fm->d)) ) {
+ if (de->d_name[0] != '.' && !mangle_name(data1+2, de->d_name) &&
+ !stat(de->d_name, &st) && S_ISREG(st.st_mode))
+ break;
+ }
+ if (de) {
+ dlen = 11 + sprintf(data1+2+11, ",%lu\r\n",
+ ((unsigned long)st.st_size + 252)/253);
+ err = 0;
+ } else {
+ err = 128+34;
+ }
+ } else {
+ err = 128+44;
}
- /* Strip CR and change LF -> CR LF */
- for (p = data, q = data1+2 ; (c = *p) ; p++) {
- switch (c) {
- case '\r':
- break;
- case '\n':
- *q++ = '\r';
- /* fall through */
- default:
- *q++ = c;
- break;
- }
+ send_reply(fd, err);
+ if (!err) {
+ data1[0] = dlen;
+ data1[1] = dlen >> 8;
+ xwrite(fd, data1, dlen+2);
}
- dlen = q - (data1+2);
- data1[0] = dlen;
- data1[1] = dlen >> 8;
- send_reply(fd, 0);
- xwrite(fd, data1, dlen+2);
}
static void do_print(int fd, uint16_t ix, uint16_t len, void *data)
@@ -306,7 +388,7 @@ static void do_print(int fd, uint16_t ix, uint16_t len, void *data)
struct file_data *fm = filemap[ix];
int err;
- if (!fm) {
+ if (!fm || !fm->f) {
send_reply(fd, 128+45);
return;
}