From fff4e5a818e6fe74c0d2e322a0feb447f9de722d Mon Sep 17 00:00:00 2001 From: "B. Watson" Date: Thu, 10 Nov 2022 13:11:44 -0500 Subject: Report write errors in dla2csv, add disk and disktest make targets. --- dla2csv.c | 142 ++++++++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 91 insertions(+), 51 deletions(-) (limited to 'dla2csv.c') diff --git a/dla2csv.c b/dla2csv.c index 734ec57..fea78d6 100644 --- a/dla2csv.c +++ b/dla2csv.c @@ -5,6 +5,7 @@ #include #include #include +#include #define HEIGHT 170 #define WIDTH 256 @@ -14,6 +15,8 @@ ...it has to be a *constant*. */ #define INBUF_SIZE 5440 +#define STRINGBUF_SIZE 256 + /* cc65 doesn't "localize" \b to the Atari backspace character, so: */ #ifdef __ATARI__ #define BS '\x7e' @@ -22,11 +25,9 @@ #endif char inbuf[INBUF_SIZE]; - +char stringbuf[STRINGBUF_SIZE]; FILE *inf, *outf; -char stringbuf[256]; - /* don't use "\n" or "\r\n" on the right hand side, use explicit hex codes, to avoid cc65 tampering with them. */ char *eoltypes[][2] = { @@ -37,9 +38,14 @@ char *eoltypes[][2] = { }; /* read a string from stdin (E: on the Atari). - exit on EOF (or Break key 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 + suggest using this... + */ void readstring(void) { - if(fgets(stringbuf, 256, stdin) == NULL) + memset(stringbuf, 0, STRINGBUF_SIZE); + if(fgets(stringbuf, STRINGBUF_SIZE - 1, stdin) == NULL) exit(1); } @@ -58,7 +64,7 @@ FILE *prompt_filename(const char *name, const char *mode) { #ifdef __ATARI__ /* if there's no device spec (D: or D1: etc), prepend D: */ if(!strchr(stringbuf, ':')) { - memmove(stringbuf+2, stringbuf, strlen(stringbuf)); + memmove(stringbuf+2, stringbuf, strlen(stringbuf) + 1); stringbuf[0] = 'D'; stringbuf[1] = ':'; } @@ -69,6 +75,29 @@ FILE *prompt_filename(const char *name, const char *mode) { return f; } +int prompt_yn(char *prompt, int default_y) { + char *yn = "y/N"; + if(default_y) yn = "Y/n"; + + printf("%s[%s]? ", prompt, yn); + fflush(stdout); + readstring(); + + switch(stringbuf[0]) { + case 'y': + case 'Y': + return 1; + break; + case 'n': + case 'N': + return 0; + break; + default: + break; + } + return default_y; +} + /* prompt for and read EOL type, retry if needed. will not return until a valid number was entered. */ char *prompt_eol(void) { @@ -104,7 +133,7 @@ void backspace3(void) { int main(int argc, char **argv) { char *inp, *eol; - int i, bytes = 0, x, y, xmask, warn; + int i, bytes = 0, x, y, xmask, err; #ifdef __ATARI__ /* cc65's startup code turns off caps lock. turn it back on, @@ -118,13 +147,8 @@ int main(int argc, char **argv) { printf("DLA to CSV converter.\n\n"); -#ifdef __ATARI__ - /* Atari users aren't used to typing an EOF to exit */ - printf("Note: Press Ctrl-3 or Break at any\nprompt to exit this program.\n"); -#endif - while(1) { - warn = 0; + err = 0; /* in case of short read on 2nd or later conversion: */ memset(inbuf, 0, INBUF_SIZE); @@ -143,10 +167,10 @@ int main(int argc, char **argv) { /* warn if the file size is wrong... */ if(bytes < INBUF_SIZE) { printf("Warning: File too short!\n"); - warn = 1; + err = 1; } else if(fgetc(inf) != EOF) { printf("Warning: File too long!\n"); - warn = 1; + err = 1; } else { printf("File size is OK.\n"); } @@ -156,59 +180,75 @@ int main(int argc, char **argv) { for(i = 0; i < 32; i++) { if(inbuf[i]) { printf("Warning: File doesn't look like a DLA!\n"); - warn = 1; + err = 1; break; } } /* if anything looks wrong, we shouldn't proceed... but the user is boss, so give him the choice to shoot himself in the foot. */ - if(warn) { - printf("Try to convert anyway[y/N]? "); - fflush(stdout); - readstring(); - if(stringbuf[0] != 'y' && stringbuf[0] != 'Y') + if(err) { + if(!prompt_yn("Try to convert anyway", 0)) continue; } eol = prompt_eol(); - outf = prompt_filename("Output CSV", "wb"); - - printf("\nConverting... "); - fflush(stdout); + /* convert in a loop. in case of write error, this allows retry + without re-reading the input file. */ + i = err = 0; + while(!i) { + outf = prompt_filename("Output CSV", "wb"); - /* CSV file header row (column names) */ - fprintf(outf, "x,y%s", eol); - - /* write output file one line at a time */ - inp = inbuf; - xmask = 0x80; - bytes = 0; - for(y = 0; y < HEIGHT; y++) { - backspace3(); - printf("%02d%%", y * 100 / HEIGHT); /* percentage */ + printf("\nConverting... "); fflush(stdout); - for(x = 0; x < WIDTH; x++) { - if(*inp & xmask) { - fprintf(outf, "%d,%d%s", x, y, eol); - bytes++; - } - xmask >>= 1; - if(!xmask) { - xmask = 0x80; - inp++; + + /* CSV file header row (column names) */ + fprintf(outf, "x,y%s", eol); + + /* write output file one line at a time */ + inp = inbuf; + xmask = 0x80; + bytes = 0; + for(y = 0; y < HEIGHT; y++) { + 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); + err = 1; + break; + } + bytes++; + } + xmask >>= 1; + if(!xmask) { + xmask = 0x80; + inp++; + } } + if(err) break; + } + fclose(outf); + if(err) { + if(!prompt_yn("Conversion failed, try again", 1)) + i = 1; + } else { + i = 1; + backspace3(); + printf("100%%\n%d particles.\n", bytes); } } - fclose(outf); - backspace3(); - printf("100%%\n%d particles.\n", bytes); - printf("\nConvert another file[Y/n]? "); - fflush(stdout); - readstring(); - if(stringbuf[0] == 'n' || stringbuf[0] == 'N') + if(!prompt_yn("\nConvert another file", 1)) return 0; } } -- cgit v1.2.3