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