aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--dla2csv.c390
-rw-r--r--dla2csv.xexbin11014 -> 11150 bytes
2 files changed, 211 insertions, 179 deletions
diff --git a/dla2csv.c b/dla2csv.c
index 5c2142b..4910f7e 100644
--- a/dla2csv.c
+++ b/dla2csv.c
@@ -10,6 +10,12 @@
#include <sys/types.h>
#include <dirent.h>
+#ifdef __CC65__
+ #ifndef __ATARI__
+ #error Unsupported cc65 machine type: only "-t atari" is supported.
+ #endif
+#endif
+
#include "dlaver.h"
#define HEIGHT 170
@@ -22,90 +28,76 @@
#define STRINGBUF_SIZE 256
-/* cc65 doesn't "localize" \b to the Atari backspace character, so: */
-#ifdef __ATARI__
- #define BS '\x7e'
-#else
- #define BS '\b'
-#endif
+#define PRINT_ID printf("DLA to CSV converter v" VERSION ".\n")
-char inbuf[INBUF_SIZE];
-char stringbuf[STRINGBUF_SIZE];
-FILE *inf, *outf;
+#ifdef __ATARI__
+ #include <atari.h>
-/* 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 }
-};
+/* cc65 doesn't "localize" \b to the Atari backspace character, so: */
+ #define BS CH_DEL
/* 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__
+ On modern platforms, just use perror(). */
#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 enable_break() {
+ OS.pokmsk = POKEY_WRITE.irqen = POKEY_READ.irqst | 0x80;
}
-void set_pokmsk(char value) {
- *((char *)0x10) = *((char *)0xd20e) = value;
+void disable_break() {
+ OS.pokmsk = POKEY_WRITE.irqen = POKEY_READ.irqst & 0x7f;
}
-void enable_break() {
- set_pokmsk(get_pokmsk() | 0x80);
-}
+void init_console(void) {
+ /* cc65's startup code turns off caps lock. turn it back on,
+ since we're typing DOS filenames. in BASIC this would be:
+ POKE 702,64 */
+ OS.shflok = 0x40;
-void disable_break() {
- set_pokmsk(get_pokmsk() & 0x7f);
+ /* also, cc65 sets APPMHI to $bc1f (last byte before the GR.0
+ display list). which causes the atari to lock up when Reset
+ is pressed. I can't believe this is useful behaviour... */
+ OS.appmhi = 0;
+
+ /* clear the screen */
+ putchar(CH_CLR);
}
-#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 Linux, EOF is the ^D character, and this works.
- On the Atari, EOF is ^3... 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
- document ctrl-3 as a way to exit the program (too bad), and just
- hope the user never presses it.
- */
-void readstring(void) {
- char *result;
- memset(stringbuf, 0, STRINGBUF_SIZE);
- result = fgets(stringbuf, STRINGBUF_SIZE - 1, stdin);
- if(result == NULL) {
- enable_break();
- exit(1);
+void print_banner(void) {
+ int i;
+
+ PRINT_ID;
+
+ printf("\n"
+ "At any filename prompt, you may:\n" );
+ printf(
+ "- Press Return, to exit this program.\n");
+ printf(
+ "- Enter a number, to get a directory of\n"
+ " that drive.");
+
+ /* be nice to emulator users. */
+ for(i = 0; i < 12; i++) {
+ if(OS.hatabs[i].id == 'H') {
+ printf(" Use 0 for \"H:\".");
+ break;
+ }
}
+ printf("\n");
}
-#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) {
@@ -139,8 +131,54 @@ void show_dir(char drive) {
closedir(dir);
if(column) putchar('\n');
}
+#else
+ /* non-Atari is assumed to be POSIX (and not something like
+ Commodore or Apple II). */
+ #define BS '\b'
+ #define PERROR(x) perror(x)
+ #define enable_break() noop()
+ #define disable_break() noop()
+ #define init_console() noop()
+void noop(void) { }
+void print_banner(void) {
+ PRINT_ID;
+}
#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 }
+};
+
+/* Read a string from stdin (E: on the Atari).
+ Exit on EOF (or Break key on the Atari, except we disable it).
+ On Linux, EOF is the ^D character, and this works.
+ On the Atari, EOF is ^3... 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
+ document ctrl-3 as a way to exit the program (too bad), and just
+ hope the user never presses it.
+ */
+void readstring(void) {
+ char *result;
+ memset(stringbuf, 0, STRINGBUF_SIZE);
+ result = fgets(stringbuf, STRINGBUF_SIZE - 1, stdin);
+ if(result == NULL) {
+ enable_break();
+ exit(1);
+ }
+}
+
int prompt_yn(char *prompt, int default_y) {
char *yn = "y/N";
if(default_y) yn = "Y/n";
@@ -236,89 +274,131 @@ void backspace3(void) {
putchar(BS);
}
-int main(int argc, char **argv) {
- char *inp, *eol;
- int i, bytes = 0, x, y, xmask, err;
+/* check_dla() returns 1 if all is well, 0 if there's a problem. */
+int check_dla(int bytes) {
+ int i, ok = 1;
+
+ /* warn if the file size is wrong... */
+ if(bytes < INBUF_SIZE) {
+ printf("Warning: File too short!\n");
+ ok = 0;
+ } else if(fgetc(inf) != EOF) {
+ printf("Warning: File too long!\n");
+ ok = 0;
+ } else {
+ printf("File size is OK.\n");
+ }
+ fclose(inf);
-#ifdef __ATARI__
- /* cc65's startup code turns off caps lock. turn it back on,
- since we're typing DOS filenames. in BASIC this would be:
- POKE 702,64 */
- *((char *)0x02be) = 0x40;
+ /* a DLA file never has non-zero bytes at the beginning. */
+ for(i = 0; i < 32; i++) {
+ if(inbuf[i]) {
+ printf("Warning: File doesn't look like a DLA!\n");
+ ok = 0;
+ break;
+ }
+ }
- /* also, cc65 sets APPMHI to $bc1f (last byte before the GR.0
- display list). which causes the atari to lock up when Reset
- is pressed. I can't believe this is useful behaviour... */
- *((int *)0x0e) = 0;
+ return ok;
+}
- /* clear the screen */
- putchar(0x7d);
-#endif
+int read_file(void) {
+ int bytes;
- printf("DLA to CSV converter v" VERSION ".\n");
+ /* in case of short read on 2nd or later conversion: */
+ memset(inbuf, 0, INBUF_SIZE);
-#ifdef __ATARI__
- printf("\n"
- "At any filename prompt, you may:\n" );
- printf(
- "- Press Return, to exit this program.\n");
- printf(
- "- Enter a number, to get a directory of\n"
- " that 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;
- }
+ /* read whole input file into memory */
+ 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);
}
- printf("\n");
+
+ return bytes;
+}
+
+/* convert() returns the number of particles on success, 0 on failure. */
+int convert(char *eol) {
+ char *inp;
+ int x, y, xmask, particles;
+
+ outf = prompt_filename("Output CSV", "wb");
+
+#ifdef __ATARI__
+ printf("Press Ctrl-C to abort conversion.\n");
#endif
+ printf("\nConverting... ");
+ fflush(stdout);
- while(1) {
- disable_break();
- err = 0;
+ /* CSV file header row (column names) */
+ fprintf(outf, "x,y%s", eol);
- /* in case of short read on 2nd or later conversion: */
- memset(inbuf, 0, INBUF_SIZE);
+ inp = inbuf;
+ xmask = 0x80;
+ particles = 0;
- /* read whole input file into memory */
- 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);
- continue;
- }
- printf("Read %d bytes.\n", bytes);
-
- /* warn if the file size is wrong... */
- if(bytes < INBUF_SIZE) {
- printf("Warning: File too short!\n");
- err = 1;
- } else if(fgetc(inf) != EOF) {
- printf("Warning: File too long!\n");
- err = 1;
- } else {
- printf("File size is OK.\n");
+ /* write output file one line at a time */
+ /* 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) {
+ printf("\nUser abort!\n");
+ fclose(outf);
+ remove(stringbuf);
+ OS.ch = KEY_NONE;
+ return 0;
}
- fclose(inf);
-
- /* a DLA file never has non-zero bytes at the beginning. */
- for(i = 0; i < 32; i++) {
- if(inbuf[i]) {
- printf("Warning: File doesn't look like a DLA!\n");
- err = 1;
- 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) {
+ putchar('\n');
+ PERROR(stringbuf);
+ fclose(outf);
+ remove(stringbuf);
+ return 0;
+ }
+ particles++;
+ }
+ xmask >>= 1;
+ if(!xmask) {
+ xmask = 0x80;
+ inp++;
}
}
+ }
+ fclose(outf);
+
+ return particles;
+}
+
+int main(int argc, char **argv) {
+ char *eol;
+ int done, result = 0;
+
+ init_console();
+ print_banner();
+
+ while(1) {
+ disable_break();
+
+ result = read_file();
+ if(result <= 0) continue;
+ printf("Read %d bytes.\n", result);
/* 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(err) {
+ if(!check_dla(result)) {
if(!prompt_yn("Try to convert anyway", 0))
continue;
}
@@ -327,64 +407,16 @@ int main(int argc, char **argv) {
/* 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");
-
-#ifdef __ATARI__
- printf("Press Ctrl-C to abort conversion.\n");
-#endif
- printf("\nConverting... ");
- fflush(stdout);
-
- /* 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++) {
-#ifdef __ATARI__
- /* check for ^C */
- if( *((char *)0x2fc) == 0x92 ) {
- printf("User abort!\n");
- fclose(outf);
- remove(stringbuf);
- err = 1;
- *((char *)0x2fc) = 0xff;
- break;
- }
-#endif
+ done = 0;
+ while(!done) {
+ result = convert(eol);
+ if(result) {
+ done = 1;
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) {
- putchar('\n');
- 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;
+ printf("100%%\n%d particles.\n", result);
} else {
- i = 1;
- backspace3();
- printf("100%%\n%d particles.\n", bytes);
+ if(!prompt_yn("Conversion failed, try again", 1))
+ done = 1;
}
}
diff --git a/dla2csv.xex b/dla2csv.xex
index 8ed97ad..3d03634 100644
--- a/dla2csv.xex
+++ b/dla2csv.xex
Binary files differ