aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorB. Watson <urchlay@slackware.uk>2022-11-11 15:41:40 -0500
committerB. Watson <urchlay@slackware.uk>2022-11-11 15:41:40 -0500
commit17bba1ebffb8bb37299c0a2d3a57b3a4c51ab0fe (patch)
tree8e76efc7b4b43c9a7ce81c653562f10905585b77
parentba54f1aedcc6e7228c4233dcb1ff35151415b064 (diff)
downloaddla-asm-17bba1ebffb8bb37299c0a2d3a57b3a4c51ab0fe.tar.gz
dla2csv.xex: disk directory support, disable break key, ^C to abort conversion.
-rw-r--r--dla2csv.c167
-rw-r--r--dla2csv.xexbin8774 -> 10885 bytes
2 files changed, 143 insertions, 24 deletions
diff --git a/dla2csv.c b/dla2csv.c
index ca46fc1..0172f9b 100644
--- a/dla2csv.c
+++ b/dla2csv.c
@@ -6,6 +6,9 @@
#include <string.h>
#include <unistd.h>
#include <errno.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <dirent.h>
#include "dlaver.h"
@@ -30,29 +33,111 @@ char inbuf[INBUF_SIZE];
char stringbuf[STRINGBUF_SIZE];
FILE *inf, *outf;
-/* don't use "\n" or "\r\n" on the right hand side, use explicit
- hex codes, to avoid cc65 tampering with them. */
+/* We can't use string literal syntax, cc65 "helpfully" turns "\x0a"
+ into an Atari 0x9b EOL character. Numeric constants are left alone. */
+char a8eol[] = { 0x9b, 0x00, 0x00 };
+char uxeol[] = { 0x0a, 0x00, 0x00 };
+char mseol[] = { 0x0d, 0x0a, 0x00 };
char *eoltypes[][2] = {
- { "Atari ($9B)", "\x9b" },
- { "Unix (\\n)", "\x0a" },
- { "MS (\\r\\n)", "\x0d\x0a" },
+ { "Atari ($9B)", a8eol },
+ { "Unix (\\n)", uxeol },
+ { "MS (\\r\\n)", mseol },
{ NULL, NULL }
};
-/* read a string from stdin (E: on the Atari).
- exit on EOF (or Break key on the Atari).
- on DOS 2.0S, we end up back at the DUP menu... but
- SpartaDOS 3.2d locks up with a black screen. so don't
+/* On the Atari, we should show Atari-style error messages, including
+ the familiar error number.
+ Another reason to do this: on the Atari, perror() says "Bad file number"
+ instead of "No space left on device", if the disk fills up due
+ to fprintf().
+ On modern platforms, just use perror().
+ */
+#ifdef __ATARI__
+ #define PERROR(x) atari_perror(x)
+void atari_perror(char *msg) {
+ printf("%s: Error %d: %s\n", msg, _oserror, _stroserror(_oserror));
+}
+#else
+ #define PERROR(x) perror(x)
+#endif
+
+/* cc65 doesn't play nice with the Break key on the Atari. It
+ works as expected during disk I/O, but if you press it while
+ printing to stdout or reading from stdin, the program freezes.
+ so call disable_break() at startup, then wrap disk I/O in
+ enable_break() and disable_break(). */
+#ifdef __ATARI__
+char get_pokmsk(void) {
+ return *((char *)0x10);
+}
+
+void set_pokmsk(char value) {
+ *((char *)0x10) = *((char *)0xd20e) = value;
+}
+
+void enable_break() {
+ set_pokmsk(get_pokmsk() | 0x80);
+}
+
+void disable_break() {
+ set_pokmsk(get_pokmsk() & 0x7f);
+}
+#else
+void enable_break() { } /* no-op */
+void disable_break() { } /* no-op */
+#endif
+
+/* Read a string from stdin (E: on the Atari).
+ Exit on EOF (or Break key on the Atari, except we disable it).
+ On DOS 2.0S, we end up back at the DUP menu... but
+ SpartaDOS 3.2d locks up with a black screen. So don't
suggest using this...
*/
void readstring(void) {
+ char *result;
memset(stringbuf, 0, STRINGBUF_SIZE);
- if(fgets(stringbuf, STRINGBUF_SIZE - 1, stdin) == NULL)
- exit(1);
+ result = fgets(stringbuf, STRINGBUF_SIZE - 1, stdin);
+ if(result == NULL) exit(1);
+}
+
+#ifdef __ATARI__
+/* Show disk directory, in a 3-column layout.
+ drive is an ASCII digit, e.g. 0x31 is drive 1. */
+void show_dir(char drive) {
+ static char dirspec[16];
+ char device = 'D';
+ DIR *dir;
+ struct dirent *ent;
+ int column = 0;
+
+ if(drive == '0') {
+ drive++;
+ device = 'H';
+ }
+
+ sprintf(dirspec, "%c%c:*.*", device, drive);
+
+ if(!(dir = opendir(dirspec))) {
+ dirspec[2] = '\0';
+ PERROR(dirspec);
+ return;
+ }
+
+ while((ent = readdir(dir))) {
+ printf("%-13s", ent->d_name);
+ if(++column == 3) {
+ column = 0;
+ putchar('\n');
+ }
+ }
+
+ closedir(dir);
+ if(column) putchar('\n');
}
+#endif
-/* prompt for a filename, try to open it. if there's an error,
- show error message and retry. will not return until it
+/* Prompt for a filename, try to open it. If there's an error,
+ show error message and retry. Will not return until it
opens the file. */
FILE *prompt_filename(const char *name, const char *mode) {
FILE *f = NULL;
@@ -64,6 +149,11 @@ FILE *prompt_filename(const char *name, const char *mode) {
stringbuf[strlen(stringbuf) - 1] = '\0'; /* kill trailing \n */
if(strlen(stringbuf) == 0) continue;
#ifdef __ATARI__
+ /* if the user enters a single digit, show directory of that drive. */
+ if(isdigit(stringbuf[0])) {
+ show_dir(stringbuf[0]);
+ continue;
+ }
/* if there's no device spec (D: or D1: etc), prepend D: */
if(!strchr(stringbuf, ':')) {
memmove(stringbuf+2, stringbuf, strlen(stringbuf) + 1);
@@ -71,8 +161,10 @@ FILE *prompt_filename(const char *name, const char *mode) {
stringbuf[1] = ':';
}
#endif
+ enable_break();
f = fopen(stringbuf, mode);
- if(!f) perror(stringbuf);
+ disable_break();
+ if(!f) PERROR(stringbuf);
}
return f;
}
@@ -100,7 +192,7 @@ int prompt_yn(char *prompt, int default_y) {
return default_y;
}
-/* prompt for and read EOL type, retry if needed. will not return
+/* Prompt for and read EOL type, retry if needed. Will not return
until a valid number was entered. */
char *prompt_eol(void) {
int i;
@@ -119,7 +211,7 @@ char *prompt_eol(void) {
if(stringbuf[0] == '\n') {
i = 0;
} else {
- i = stringbuf[0] - 49; /* ascii 1-3 => 0-2 */
+ i = stringbuf[0] - 49; /* ASCII 1-3 => 0-2 */
if(i < 0 || i > 2)
i = -1;
}
@@ -149,7 +241,23 @@ int main(int argc, char **argv) {
printf("DLA to CSV converter v" VERSION ".\n");
+#ifdef __ATARI__
+ printf("\n"
+ "At any filename prompt, you may enter\n"
+ "a number, to get a directory of that\n"
+ "drive.");
+ /* be nice to emulator users. 0x31a is HATABS. */
+ for(i = 0x31a; i < 0x340; i += 3) {
+ if(*((char *)i) == 'H') {
+ printf(" Use 0 for \"H:\".");
+ break;
+ }
+ }
+ printf("\n\n");
+#endif
+
while(1) {
+ disable_break();
err = 0;
/* in case of short read on 2nd or later conversion: */
@@ -159,9 +267,11 @@ int main(int argc, char **argv) {
inf = prompt_filename("Input DLA", "rb");
printf("Reading...");
fflush(stdout);
+ enable_break();
bytes = fread(inbuf, 1, INBUF_SIZE, inf);
+ disable_break();
if(bytes <= 0) {
- perror(stringbuf);
+ PERROR(stringbuf);
continue;
}
printf("Read %d bytes.\n", bytes);
@@ -202,6 +312,9 @@ int main(int argc, char **argv) {
while(!i) {
outf = prompt_filename("Output CSV", "wb");
+#ifdef __ATARI__
+ printf("Press Ctrl-C to abort conversion.\n");
+#endif
printf("\nConverting... ");
fflush(stdout);
@@ -213,19 +326,25 @@ int main(int argc, char **argv) {
xmask = 0x80;
bytes = 0;
for(y = 0; y < HEIGHT; y++) {
+#ifdef __ATARI__
+ /* check for ^C */
+ if( *((char *)0x2fc) == 0x92 ) {
+ printf("User abort!\n");
+ fclose(outf);
+ remove(stringbuf);
+ err = 1;
+ *((char *)0x2fc) = 0xff;
+ break;
+ }
+#endif
backspace3();
printf("%02d%%", y * 100 / HEIGHT); /* percentage */
fflush(stdout);
for(x = 0; x < WIDTH; x++) {
if(*inp & xmask) {
if(fprintf(outf, "%d,%d%s", x, y, eol) < 0) {
- #ifdef __ATARI__
- /* dirty hack alert: cc65 gives us the
- wrong error here, when the disk fills up. */
- if(errno == EBADF) errno = ENOSPC;
- #endif
- printf("errno is %d\n", errno);
- perror(stringbuf);
+ putchar('\n');
+ PERROR(stringbuf);
err = 1;
break;
}
diff --git a/dla2csv.xex b/dla2csv.xex
index 9e551ec..60fccce 100644
--- a/dla2csv.xex
+++ b/dla2csv.xex
Binary files differ