aboutsummaryrefslogtreecommitdiff
path: root/dla2csv.c
blob: 46057612d86aa180240802ada479cee66f8429a5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
/* dla2csv.c - convert dla.xex save files to CSV.
	Rather bloated and slow by Atari standards. */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#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). there could
	be error checking here, but there's not. */
void readstring(void) {
	fgets(stringbuf, 256, stdin);
}

/* 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.
	there could be code here to prepend D: if it's missing, but
	there isn't.
 */
FILE *prompt_filename(const char *name, const char *mode) {
	FILE *f = NULL;
	while(f == NULL) {
		printf("\n%s file: ", name);
		fflush(stdout);
		readstring();
		stringbuf[strlen(stringbuf) - 1] = '\0';
		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 bytes = 0, x, y, xmask;

	printf("DLA to CSV converter.\n");
	while(1) {
		/* 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;
		}
		fclose(inf);
		printf("Read %d bytes.\n", bytes);

		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;
	}
}