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