]> git.sur5r.net Git - cc65/blob - libsrc/atari/targetutil/w2cas.c
Merge pull request #297 from groessler/something_to_pull
[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 (! _is_cmdline_dos())
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             printf("empty filename, exiting...\n");
62             if (! _is_cmdline_dos())
63                 cgetc();
64             return 1;
65         }
66         if (*x && *(x + strlen(x) - 1) == '\n')
67             *(x + strlen(x) - 1) = 0;
68         if (! strlen(x)) {  /* empty filename */
69             printf("empty filename, exiting...\n");
70             if (! _is_cmdline_dos())
71                 cgetc();
72             return 1;
73         }
74         filename = x;
75     }
76     else {
77         filename = *(argv+1);
78     }
79
80     /* allocate buffer */
81     buffer = malloc(buflen);
82     if (! buffer) {
83         buflen = _heapmaxavail(); /* get as much as we can */
84         buffer = malloc(buflen);
85         if (! buffer) {
86             fprintf(stderr, "cannot alloc %ld bytes -- aborting...\n", (long)buflen);
87             if (! _is_cmdline_dos())
88                 cgetc();
89             return 1;
90         }
91     }
92     if (verbose)
93         printf("buffer size: %ld bytes\n", (long)buflen);
94
95     /* open file */
96     file = fopen(filename, "rb");
97     if (! file) {
98         free(buffer);
99         fprintf(stderr, "cannot open '%s': %s\n", filename, strerror(errno));
100         if (! _is_cmdline_dos())
101             cgetc();
102         return 1;
103     }
104
105     /* read file -- file length must be < 32K */
106     if (verbose)
107         printf("reading input file...\n");
108     filen = fread(buffer, 1, buflen, file);
109     if (! filen) {
110         fprintf(stderr, "read error\n");
111     file_err:
112         fclose(file);
113         free(buffer);
114         if (! _is_cmdline_dos())
115             cgetc();
116         return 1;
117     }
118     if (filen > 32767l) {
119         fprintf(stderr, "file is too large (must be < 32768)\n");
120         goto file_err;
121     }
122     if (filen == buflen) { /* we have a buffer < 32768 and the file fits into it (and is most probably larger) */
123         fprintf(stderr, "not enough memory\n");
124         goto file_err;
125     }
126     if (verbose)
127       printf("file size: %ld bytes\n", (long)filen);
128
129     /* close input file */
130     fclose(file);
131
132     /* open cassette */
133     if (verbose)
134         printf("opening cassette...\n");
135     iocb->buffer = C_dev;
136     iocb->aux1 = 8;    /* open for output */
137     iocb->aux2 = 128;  /* short breaks and no stop between data blocks */
138     iocb->command = IOCB_OPEN;
139     regs.x = iocb_num;
140     regs.pc = 0xe456;   /* CIOV */
141
142     _sys(&regs);
143     if (regs.y != 1) {
144         fprintf(stderr, "CIO call to open cassette returned %d\n", regs.y);
145         free(buffer);
146         if (! _is_cmdline_dos())
147             cgetc();
148         return 1;
149     }
150
151     /* write file */
152     if (verbose)
153         printf("writing to cassette...\n");
154     iocb->buffer = buffer;
155     iocb->buflen = filen;
156     iocb->command = IOCB_PUTCHR;
157     regs.x = iocb_num;
158     regs.pc = 0xe456;   /* CIOV */
159
160     _sys(&regs);
161     if (regs.y != 1) {
162         fprintf(stderr, "CIO call to write file returned %d\n", regs.y);
163         free(buffer);
164
165         iocb->command = IOCB_CLOSE;
166         regs.x = iocb_num;
167         regs.pc = 0xe456;   /* CIOV */
168         _sys(&regs);
169
170         if (! _is_cmdline_dos())
171             cgetc();
172         return 1;
173     }
174
175     /* free buffer */
176     free(buffer);
177
178     /* close cassette */
179     iocb->command = IOCB_CLOSE;
180     regs.x = iocb_num;
181     regs.pc = 0xe456;   /* CIOV */
182     _sys(&regs);
183
184     if (regs.y != 1) {
185         fprintf(stderr, "CIO call to close cassette returned %d\n", regs.y);
186         if (! _is_cmdline_dos())
187             cgetc();
188         return 1;
189     }
190
191     /* all is fine */
192     printf("success\n");
193     if (! _is_cmdline_dos())
194         cgetc();
195     return 0;
196 }