From 27f092fa8d347a31d311418bb8604cf04673bffc Mon Sep 17 00:00:00 2001 From: "B. Watson" Date: Thu, 17 Nov 2022 16:46:22 -0500 Subject: dla2csv.c: de-uglify the code some, fix minor issues. --- dla.atr | Bin 92176 -> 92176 bytes dla2csv.c | 295 ++++++++++++++++++++++++++---------------------------------- dla2csv.xex | Bin 10790 -> 10909 bytes 3 files changed, 129 insertions(+), 166 deletions(-) diff --git a/dla.atr b/dla.atr index 1af905c..7266dca 100644 Binary files a/dla.atr and b/dla.atr differ diff --git a/dla2csv.c b/dla2csv.c index d8341a8..98d1173 100644 --- a/dla2csv.c +++ b/dla2csv.c @@ -33,13 +33,37 @@ void print_id(void) { printf("DLA to CSV converter v" VERSION ".\n"); } +char inbuf[INBUF_SIZE]; +char stringbuf[STRINGBUF_SIZE]; +FILE *inf, *outf; + +/* 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)", a8eol }, + { "Unix (\\n)", uxeol }, + { "MS (\\r\\n)", mseol }, + { NULL, NULL } +}; + +char *eol; /* gets assigned one of the eoltypes */ + +/* using a table of masks instead of calculating them saves maybe 2s + on the Atari. */ +unsigned char masks[] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 }; + #ifdef __ATARI__ /* Uncomment this to see elapsed time in convert() */ #define PROFILE -/* cc65 doesn't "localize" \b to the Atari backspace character, so: */ +/* cc65 doesn't "localize" \b to the Atari backspace character, like it + does for \n. If we needed it: #define BS CH_DEL +*/ /* I like these colors. Also they match dla.xex. */ #define TEXT_COLOR 0x0e @@ -129,15 +153,20 @@ void print_id(void) { printf("\n"); } - /* Show disk directory, in a 3-column layout. - drive is an ASCII digit, e.g. 0x31 is drive 1. */ - void show_dir(char drive) { + /* if the user enters a single digit, show directory of that drive. + in a 3-column layout. this is a no-op on non-Atari. + returns true if the user asked for a directory, false if not. + */ + char show_dir(void) { static char dirspec[16]; DIR *dir; struct dirent *ent; - char device = 'D'; + char device = 'D', drive = stringbuf[0]; unsigned char column = 0; + if(!isdigit(drive)) + return 0; + if(drive == '0') { drive++; device = 'H'; @@ -148,9 +177,10 @@ void print_id(void) { if(!(dir = opendir(dirspec))) { dirspec[2] = '\0'; PERROR(dirspec); - return; + return 1; } + errno = 0; while((ent = readdir(dir))) { printf("%-13s", ent->d_name); if(++column == 3) { @@ -158,9 +188,11 @@ void print_id(void) { putchar('\n'); } } + if(errno) PERROR(dirspec); closedir(dir); if(column) putchar('\n'); + return 1; } void atari_exit(int status) { @@ -180,47 +212,104 @@ void print_id(void) { cc65's runtime, do not pass Go, do not collect $200). This seems to work reliably, but I hesistate to document "Press Ctrl-3 to exit"... - ...and it turns out that on SpartaDOS X, even this doesn't prevent - the atari from locking up if the user presses ^3. Sigh. + ...and it turns out that on SpartaDOS X and other command-line DOSes, + the display list doesn't get fixed: jmp (DOSVEC) just gives you the + prompt, which expects the screen to still be usable... Sigh. Treat it + as the Reset key instead. */ - #define exit_eof_stdin() (*(OS.dosvec))() + void exit_eof_stdin(void) { + if(_is_cmdline_dos()) + __asm__("jmp $e474"); /* cc65 doesn't define WARMSV for C */ + else + (*(OS.dosvec))(); + } + + void backspace2(void) { + OS.colcrs -= 2; + } + + void print_converting(void) { + printf("Press Ctrl-C to abort conversion.\n"); + OS.crsinh = 1; + printf("\nConverting... %%"); + putchar(0xa0); + backspace2(); + } + #define enable_cursor() OS.crsinh = 0 + + char user_abort(void) { + return OS.ch == (KEY_C | KEY_CTRL); + } + + void clear_keystroke(void) { + OS.ch = KEY_NONE; + } + + #define REGISTER register + + /* using utoa() rather than fprintf() saves ~12 sec on the Atari. */ + void writepoint(unsigned char x, unsigned char y) { + static char ubuf[10]; + static char fbuf[16]; + + utoa(x, fbuf, 10); + strcat(fbuf, ","); + strcat(fbuf, utoa(y, ubuf, 10)); + strcat(fbuf, eol); + fputs(fbuf, outf); + } + + /* if user entered a filename with no device spec (D: or D1: etc), + prepend D1:. this is a no-op on non-Atari. */ + void fix_filename(void) { + if(!strchr(stringbuf, ':')) { + memmove(stringbuf+3, stringbuf, strlen(stringbuf) + 1); + stringbuf[0] = 'D'; + stringbuf[1] = '1'; + stringbuf[2] = ':'; + } + } + + #ifdef PROFILE + #define start_profile_clock() OS.rtclok[0] = OS.rtclok[1] = OS.rtclok[2] = 0 + #define print_profile_clock() \ + printf("\nElapsed time: %ds\n", ((OS.rtclok[1] << 8) | OS.rtclok[2]) / 60) + #else + #define start_profile_clock() + #define print_profile_clock() + #endif #else /* non-Atari is assumed to be POSIX (and not something like Commodore or Apple II). */ #define BS '\b' + void backspace2(void) { + putchar(BS); + putchar(BS); + } #define PERROR(x) perror(x) #define print_banner() print_id() #define noop() #define enable_break() noop() #define disable_break() noop() + #define enable_cursor() noop() #define init_console() noop() + #define clear_keystroke() noop() + #define start_profile_clock() noop() + #define print_profile_clock() noop() + #define fix_filename() noop() + #define user_abort() 0 + #define show_dir() 0 #define EXIT(x) exit(1) #define exit_eof_stdin() exit(1) + #define print_converting() printf("\nConverting... %%") + #define REGISTER + /* since utoa() only exists on cc65, can't use it on non-Atari. */ + void writepoint(unsigned char x, unsigned char y) { + fprintf(outf, "%d,%d%s", x, y, eol); + } #endif -char inbuf[INBUF_SIZE]; -char stringbuf[STRINGBUF_SIZE]; -FILE *inf, *outf; - -/* 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)", a8eol }, - { "Unix (\\n)", uxeol }, - { "MS (\\r\\n)", mseol }, - { NULL, NULL } -}; - -char *eol; /* gets assigned one of the eoltypes */ - -/* using a table of masks instead of calculating them saves maybe 2s - on the Atari. */ -unsigned char masks[] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 }; - /* Read a string from stdin (E: on the Atari). Exit if we get EOF on stdin (e.g. ^D on Linux, ^3 on Atari). See exit_eof_stdin() comments above. @@ -273,22 +362,9 @@ FILE *prompt_filename(const char *name, const char *mode) { 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 user entered a filename with no device spec (D: or D1: etc), - prepend D: */ - if(!strchr(stringbuf, ':')) { - memmove(stringbuf+2, stringbuf, strlen(stringbuf) + 1); - stringbuf[0] = 'D'; - stringbuf[1] = ':'; - } -#endif + if(show_dir()) continue; + fix_filename(); enable_break(); f = fopen(stringbuf, mode); disable_break(); @@ -327,17 +403,6 @@ char *prompt_eol(void) { return eoltypes[i][1]; } -#ifdef __ATARI__ -void backspace2(void) { - OS.colcrs -= 2; -} -#else -void backspace2(void) { - putchar(BS); - putchar(BS); -} -#endif - /* check_dla() returns 1 if all is well, 0 if there's a problem. */ int check_dla(int bytes) { int i, ok = 1; @@ -386,82 +451,6 @@ int read_file(void) { return bytes; } -#if 0 -/* convert() returns the number of particles on success, 0 on failure. */ -int convert(char *eol) { - div_t d; - unsigned int particles; -#ifdef __ATARI__ - register -#endif - unsigned int i; - unsigned char j, x, pct = 0; - - outf = prompt_filename("Output CSV", "wb"); -#ifdef __ATARI__ - printf("Press Ctrl-C to abort conversion.\n"); -#endif - printf("\nConverting... "); - fprintf(outf, "x,y%s", eol); - - for(i = 0; i < INBUF_SIZE; ++i) { - if(i % 38 == 0) { - backspace3(); - printf("%02d%%", pct++); - fflush(stdout); - } - if(inbuf[i]) { - d = div(i, 22); - x = d.rem * 8; - for(j = 0; j < 8; ++x, ++j) { - if(inbuf[i] & masks[j]) { - if(fprintf(outf, "%d,%d%s", x, d.quot, eol) < 0) { - putchar('\n'); - PERROR(stringbuf); - fclose(outf); - remove(stringbuf); - return 0; - } - particles++; - } - } - } - } - - fclose(outf); - - - return particles; -} -#endif - -#ifdef __ATARI__ -/* using utoa() rather than fprintf() saves ~12 sec on the Atari. */ -void writepoint(unsigned char x, unsigned char y) { - static char ubuf[10]; - static char fbuf[16]; - - utoa(x, fbuf, 10); - strcat(fbuf, ","); - strcat(fbuf, utoa(y, ubuf, 10)); - strcat(fbuf, eol); - fputs(fbuf, outf); - /* - utoa(x, buf, 10); - fputs(buf, outf); - fputc(',', outf); - utoa(y, buf, 10); - fputs(buf, outf); - fputs(eol, outf); - */ -} -#else -/* since utoa() only exists on cc65, can't use it on non-Atari. */ -void writepoint(unsigned char x, unsigned char y) { - fprintf(outf, "%d,%d%s", x, y, eol); -} -#endif - /* currently, on the 800 with atariserver, convert() takes: 5s for a DLA with no points (a file of zeroes). 16s for a DLA with 1000 points. @@ -469,23 +458,12 @@ void writepoint(unsigned char x, unsigned char y) { */ int convert(void) { unsigned char x, y, j, pixx; -#ifdef __ATARI__ - register -#endif - char *inp = inbuf; + REGISTER char *inp = inbuf; int particles = 0; outf = prompt_filename("Output CSV", "wb"); -#ifdef __ATARI__ - printf("Press Ctrl-C to abort conversion.\n"); - OS.crsinh = 1; -#endif - printf("\nConverting... %%"); -#ifdef __ATARI__ - putchar(0xa0); - backspace2(); -#endif + print_converting(); /* CSV file header row (column names) */ fprintf(outf, "x,y%s", eol); @@ -494,16 +472,13 @@ int convert(void) { /* loop over all the pixels, by row, then column. this loop is rather slow. */ for(y = 0; y < HEIGHT; ++y) { -#ifdef __ATARI__ - /* check for ^C */ - if(OS.ch == (KEY_C | KEY_CTRL)) { + if(user_abort()) { printf("\nUser abort!\n"); fclose(outf); remove(stringbuf); - OS.ch = KEY_NONE; + clear_keystroke(); return 0; } -#endif backspace2(); printf("%02d", y * 100 / HEIGHT); /* percentage */ fflush(stdout); @@ -528,9 +503,7 @@ int convert(void) { } fclose(outf); -#ifdef __ATARI__ - OS.crsinh = 0; -#endif + enable_cursor(); return particles; } @@ -560,12 +533,7 @@ int main(int argc, char **argv) { without re-reading the input file. */ done = 0; while(!done) { - -#ifdef __ATARI__ - #ifdef PROFILE - OS.rtclok[0] = OS.rtclok[1] = OS.rtclok[2] = 0; - #endif -#endif + start_profile_clock(); result = convert(); @@ -573,18 +541,13 @@ int main(int argc, char **argv) { done = 1; backspace2(); printf("100%%\n%d particles.\n", result); + print_profile_clock(); } else { if(!prompt_yn("Conversion failed, try again", 1)) done = 1; } } -#ifdef __ATARI__ - #ifdef PROFILE - printf("\nElapsed time: %ds\n", ((OS.rtclok[1] << 8) | OS.rtclok[2]) / 60); - #endif -#endif - if(!prompt_yn("\nConvert another file", 1)) break; } diff --git a/dla2csv.xex b/dla2csv.xex index 41b117c..fe0eb4e 100644 Binary files a/dla2csv.xex and b/dla2csv.xex differ -- cgit v1.2.3