From 17bba1ebffb8bb37299c0a2d3a57b3a4c51ab0fe Mon Sep 17 00:00:00 2001 From: "B. Watson" Date: Fri, 11 Nov 2022 15:41:40 -0500 Subject: dla2csv.xex: disk directory support, disable break key, ^C to abort conversion. --- dla2csv.c | 167 +++++++++++++++++++++++++++++++++++++++++++++++++++--------- dla2csv.xex | Bin 8774 -> 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 #include #include +#include +#include +#include #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 Binary files a/dla2csv.xex and b/dla2csv.xex differ -- cgit v1.2.3