diff options
author | H. Peter Anvin <hpa@zytor.com> | 2012-08-07 22:56:33 -0700 |
---|---|---|
committer | H. Peter Anvin <hpa@zytor.com> | 2012-08-07 22:56:33 -0700 |
commit | 040a718eca78e6b6a745c55963f83cafaa830ca6 (patch) | |
tree | e9530d196694687d2ed8a1dad79d181c4433384b | |
parent | 4e38eb13133ba2eaf35ff9421dac5251bdbb01e7 (diff) | |
download | abc80-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.txt | 1 | ||||
-rw-r--r-- | tools/fileop.c | 184 |
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; } |