]> git.sur5r.net Git - cc65/blob - libsrc/atari/targetutil/w2cas.c
Merge remote-tracking branch 'upstream/master' into a5200
[cc65] / libsrc / atari / targetutil / w2cas.c
1 /* w2cas.c -- write file to cassette
2  *
3  * This program writes a boot file (typically linked with
4  * 'atari-cassette.cfg') to the cassette.
5  * Only files < 32K are supported, since the loading of
6  * larger files requires a special loader inside the program.
7  *
8  * Christian Groessler, chris@groessler.org, 2014
9  */
10
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <errno.h>
15 #include <6502.h>
16 #include <atari.h>
17 #include <conio.h>
18
19 static int verbose = 1;
20 static char C_dev[] = "C:";
21
22 static struct __iocb *findfreeiocb(void)
23 {
24     struct __iocb *iocb = &IOCB;  /* first IOCB (#0) */
25     int i;
26
27     for (i = 0; i < 8; i++) {
28         if (iocb->handler == 0xff)
29             return iocb;
30         iocb++;
31     }
32     return NULL;
33 }
34
35 int main(int argc, char **argv)
36 {
37     char *filename, *x;
38     char buf[20];
39     FILE *file;
40     unsigned char *buffer;
41     size_t filen, buflen = 32768l + 1;
42     struct regs regs;
43     struct __iocb *iocb = findfreeiocb();
44     int iocb_num;
45
46     if (! iocb) {
47         fprintf(stderr, "couldn't find a free iocb\n");
48         if (_dos_type != 1)
49             cgetc();
50         return 1;
51     }
52     iocb_num = (iocb - &IOCB) * 16;
53     if (verbose)
54         printf("using iocb index $%02X ($%04X)\n", iocb_num, iocb);
55
56     if (argc < 2) {
57         printf("\nfilename: ");
58         x = fgets(buf, 19, stdin);
59         printf("\n");
60         if (! x)
61             return 1;
62         if (*x && *(x + strlen(x) - 1) == '\n')
63             *(x + strlen(x) - 1) = 0;
64         filename = x;
65     }
66     else {
67         filename = *(argv+1);
68     }
69
70     /* allocate buffer */
71     buffer = malloc(buflen);
72     if (! buffer) {
73         buflen = _heapmaxavail(); /* get as much as we can */
74         buffer = malloc(buflen);
75         if (! buffer) {
76             fprintf(stderr, "cannot alloc %ld bytes -- aborting...\n", (long)buflen);
77             if (_dos_type != 1)
78                 cgetc();
79             return 1;
80         }
81     }
82     if (verbose)
83         printf("buffer size: %ld bytes\n", (long)buflen);
84
85     /* open file */
86     file = fopen(filename, "rb");
87     if (! file) {
88         free(buffer);
89         fprintf(stderr, "cannot open '%s': %s\n", filename, strerror(errno));
90         if (_dos_type != 1)
91             cgetc();
92         return 1;
93     }
94
95     /* read file -- file length must be < 32K */
96     if (verbose)
97         printf("reading input file...\n");
98     filen = fread(buffer, 1, buflen, file);
99     if (! filen) {
100         fprintf(stderr, "read error\n");
101     file_err:
102         fclose(file);
103         free(buffer);
104         if (_dos_type != 1)
105             cgetc();
106         return 1;
107     }
108     if (filen > 32767l) {
109         fprintf(stderr, "file is too large (must be < 32768)\n");
110         goto file_err;
111     }
112     if (filen == buflen) { /* we have a buffer < 32768 and the file fits into it (and is most probably larger) */
113         fprintf(stderr, "not enough memory\n");
114         goto file_err;
115     }
116     if (verbose)
117       printf("file size: %ld bytes\n", (long)filen);
118
119     /* close input file */
120     fclose(file);
121
122     /* open cassette */
123     if (verbose)
124         printf("opening cassette...\n");
125     iocb->buffer = C_dev;
126     iocb->aux1 = 8;    /* open for output */
127     iocb->aux2 = 128;  /* short breaks and no stop between data blocks */
128     iocb->command = IOCB_OPEN;
129     regs.x = iocb_num;
130     regs.pc = 0xe456;   /* CIOV */
131
132     _sys(&regs);
133     if (regs.y != 1) {
134         fprintf(stderr, "CIO call to open cassette returned %d\n", regs.y);
135         free(buffer);
136         if (_dos_type != 1)
137             cgetc();
138         return 1;
139     }
140
141     /* write file */
142     if (verbose)
143         printf("writing to cassette...\n");
144     iocb->buffer = buffer;
145     iocb->buflen = filen;
146     iocb->command = IOCB_PUTCHR;
147     regs.x = iocb_num;
148     regs.pc = 0xe456;   /* CIOV */
149
150     _sys(&regs);
151     if (regs.y != 1) {
152         fprintf(stderr, "CIO call to write file returned %d\n", regs.y);
153         free(buffer);
154
155         iocb->command = IOCB_CLOSE;
156         regs.x = iocb_num;
157         regs.pc = 0xe456;   /* CIOV */
158         _sys(&regs);
159
160         if (_dos_type != 1)
161             cgetc();
162         return 1;
163     }
164
165     /* free buffer */
166     free(buffer);
167
168     /* close cassette */
169     iocb->command = IOCB_CLOSE;
170     regs.x = iocb_num;
171     regs.pc = 0xe456;   /* CIOV */
172     _sys(&regs);
173
174     if (regs.y != 1) {
175         fprintf(stderr, "CIO call to close cassette returned %d\n", regs.y);
176         if (_dos_type != 1)
177             cgetc();
178         return 1;
179     }
180
181     /* all is fine */
182     printf("success\n");
183     if (_dos_type != 1)
184         cgetc();
185     return 0;
186 }