/* dla2csv.c - convert dla.xex save files to CSV. Rather bloated and slow by Atari standards. */ #include #include #include #include #define HEIGHT 170 #define WIDTH 256 /* cc65 doesn't fold constants, it won't let us do this: #define INBUF_SIZE (WIDTH * HEIGHT) ...it has to be a *constant*. */ #define INBUF_SIZE 5440 /* cc65 doesn't "localize" \b to the Atari backspace character, so: */ #ifdef __ATARI__ #define BS '\x7e' #else #define BS '\b' #endif char inbuf[INBUF_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] = { { "Atari ($9B)", "\x9b" }, { "Unix (\\n)", "\x0a" }, { "MS (\\r\\n)", "\x0d\x0a" }, { NULL, NULL } }; /* read a string from stdin (E: on the Atari). exit on EOF (or Break key on the Atari). */ void readstring(void) { if(fgets(stringbuf, 256, stdin) == NULL) exit(1); } /* 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; putchar('\n'); while(f == NULL) { printf("%s file: ", name); fflush(stdout); readstring(); stringbuf[strlen(stringbuf) - 1] = '\0'; /* kill trailing \n */ if(strlen(stringbuf) == 0) continue; #ifdef __ATARI__ /* if there's no device spec (D: or D1: etc), prepend D: */ if(!strchr(stringbuf, ':')) { memmove(stringbuf+2, stringbuf, strlen(stringbuf)); stringbuf[0] = 'D'; stringbuf[1] = ':'; } #endif f = fopen(stringbuf, mode); if(!f) perror(stringbuf); } return f; } /* prompt for and read EOL type, retry if needed. will not return until a valid number was entered. */ char *prompt_eol(void) { int i; putchar('\n'); for(i = 0; eoltypes[i][0] != NULL; i++) { printf("%d:%s ", i + 1, eoltypes[i][0]); } putchar('\n'); i = -1; while(i == -1) { printf("Line ending type[1]? "); fflush(stdout); readstring(); if(stringbuf[0] == '\n') { i = 0; } else { i = stringbuf[0] - 49; /* ascii 1-3 => 0-2 */ if(i < 0 || i > 2) i = -1; } } return eoltypes[i][1]; } void backspace3(void) { putchar(BS); putchar(BS); putchar(BS); } int main(int argc, char **argv) { char *inp, *eol; int i, bytes = 0, x, y, xmask, warn; #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; /* clear the screen */ putchar(0x7d); #endif 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; /* in case of short read on 2nd or later conversion: */ memset(inbuf, 0, INBUF_SIZE); /* read whole input file into memory */ inf = prompt_filename("Input DLA", "rb"); printf("Reading..."); fflush(stdout); bytes = fread(inbuf, 1, INBUF_SIZE, inf); 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"); warn = 1; } else if(fgetc(inf) != EOF) { printf("Warning: File too long!\n"); warn = 1; } else { printf("File size is OK.\n"); } 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"); warn = 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') continue; } eol = prompt_eol(); outf = prompt_filename("Output CSV", "wb"); 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++) { backspace3(); printf("%02d%%", y * 100 / HEIGHT); /* percentage */ 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++; } } } 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') return 0; } }