]> git.sur5r.net Git - cc65/blob - samples/diodemo.c
more space improvements by Daniel Serpell
[cc65] / samples / diodemo.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                 diodemo.c                                 */
4 /*                                                                           */
5 /*                       Direct Disk I/O Demo Program                        */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) Copyright 2005, Oliver Schmidt, <ol.sc@web.de>                        */
10 /*                                                                           */
11 /*                                                                           */
12 /* This software is provided 'as-is', without any expressed or implied       */
13 /* warranty.  In no event will the authors be held liable for any damages    */
14 /* arising from the use of this software.                                    */
15 /*                                                                           */
16 /* Permission is granted to anyone to use this software for any purpose,     */
17 /* including commercial applications, and to alter it and redistribute it    */
18 /* freely, subject to the following restrictions:                            */
19 /*                                                                           */
20 /* 1. The origin of this software must not be misrepresented; you must not   */
21 /*    claim that you wrote the original software. If you use this software   */
22 /*    in a product, an acknowledgment in the product documentation would be  */
23 /*    appreciated but is not required.                                       */
24 /* 2. Altered source versions must be plainly marked as such, and must not   */
25 /*    be misrepresented as being the original software.                      */
26 /* 3. This notice may not be removed or altered from any source              */
27 /*    distribution.                                                          */
28 /*                                                                           */
29 /*****************************************************************************/
30
31
32
33 #include <stddef.h>
34 #include <stdlib.h>
35 #include <limits.h>
36 #include <conio.h>
37 #include <ctype.h>
38 #include <errno.h>
39 #include <dio.h>
40
41
42 #define MAX_CHUNKS 10 /* Maximum acceptable number of chunks */
43
44
45 static unsigned char ScreenX;
46 static unsigned char ScreenY;
47
48
49 static void ClearLine (void)
50 /* Clear the screen line the cursor is on */
51 {
52     cputc ('\r');
53     cclear (ScreenX);
54 }
55
56
57 static driveid_t AskForDrive (const char* Name)
58 /* Ask for a drive id and return it */
59 {
60     driveid_t Drive = 0;
61     char      Char;
62
63     cprintf ("\r\n%s Drive ID ?", Name);
64
65     do {
66         Char = cgetc ();
67         if (isdigit (Char)) {
68             cputc (Char);
69             Drive = Drive * 10 + Char - '0';
70         }
71     } while (Char != CH_ENTER);
72
73     return Drive;
74 }
75
76
77 static void AskForDisk (const char* Name, driveid_t Drive)
78 /* Ask the user to insert a specific disk */
79 {
80     ClearLine ();
81     cprintf ("\rInsert %s Disk into Drive %d !", Name, Drive);
82
83     cgetc ();
84 }
85
86
87 static char* AllocBuffer (sectsize_t SectSize, sectnum_t SectCount, sectnum_t* ChunkCount)
88 /* Allocate a copy buffer on the heap and return a pointer to it */
89 {
90     char*         Buffer = NULL;
91     unsigned long BufferSize;
92     unsigned int  Chunks = 1;
93
94     /* Increase number of chunks resp. decrease size */
95     /* of one chunk until buffer allocation succeeds */
96     do {
97         *ChunkCount = (sectnum_t) ((SectCount + Chunks - 1) / Chunks);
98         BufferSize = *ChunkCount * (unsigned long) SectSize;
99         if (BufferSize < UINT_MAX) {
100             Buffer = malloc ((size_t) BufferSize);
101         }
102     } while (Buffer == NULL && ++Chunks <= MAX_CHUNKS);
103
104     return Buffer;
105 }
106
107
108 int main (int argc, const char* argv[])
109 {
110     driveid_t  SourceId;
111     driveid_t  TargetId;
112     dhandle_t  Source = NULL;
113     dhandle_t  Target = NULL;
114     sectsize_t SectSize;
115     sectnum_t  SectCount;
116     char*      Buffer;
117     sectnum_t  Sector;
118     sectnum_t  ChunkCount;
119     sectnum_t  ChunkOffset = 0;
120
121     clrscr ();
122     screensize (&ScreenX, &ScreenY);
123
124     cputs ("Floppy Disk Copy\r\n");
125     chline (16);
126     cputs ("\r\n");
127
128     /* Get source and target drive id (which may very well be identical) */
129     switch (argc) {
130       case 1:
131         SourceId = AskForDrive ("Source");
132         TargetId = AskForDrive ("Target");
133         cputs ("\r\n");
134         break;
135
136       case 2:
137         SourceId = TargetId = atoi (argv[1]);
138         break;
139
140       case 3:
141         SourceId = atoi (argv[1]);
142         TargetId = atoi (argv[2]);
143         break;
144
145       default:
146         cprintf ("\r\nToo many arguments\r\n");
147         return EXIT_FAILURE;
148     }
149
150     cputs ("\r\n");
151
152     do {
153         /* Check for single drive copy or inital iteration */
154         if (SourceId == TargetId || Source == NULL) {
155             AskForDisk ("Source", SourceId);
156         }
157
158         /* Check for initial iteration */
159         if (Source == NULL) {
160
161             /* Open source drive */
162             Source = dio_open (SourceId);
163             if (Source == NULL) {
164                 cprintf ("\r\n\nError %d on opening Drive %d\r\n", (int) _oserror, SourceId);
165                 return EXIT_FAILURE;
166             }
167
168             SectSize  = dio_query_sectsize (Source);
169             SectCount = dio_query_sectcount (Source);
170
171             /* Allocate buffer */
172             Buffer = AllocBuffer (SectSize, SectCount, &ChunkCount);
173             if (Buffer == NULL) {
174                 cputs ("\r\n\nError on allocating Buffer\r\n");
175                 return EXIT_FAILURE;
176             }
177         }
178
179         ClearLine ();
180
181         /* Read one chunk of sectors into buffer */
182         for (Sector = ChunkOffset; Sector < SectCount && (Sector - ChunkOffset) < ChunkCount; ++Sector) {
183             cprintf ("\rReading Sector %d of %d", Sector + 1, SectCount);
184
185             /* Read one sector */
186             if (dio_read (Source, Sector, Buffer + (Sector - ChunkOffset) * SectSize) != 0) {
187                 cprintf ("\r\n\nError %d on reading from Drive %d\r\n", (int) _oserror, SourceId);
188                 return EXIT_FAILURE;
189             }
190         }
191
192         /* Check for single drive copy or inital iteration */
193         if (TargetId == SourceId || Target == NULL) {
194             AskForDisk ("Target", TargetId);
195         }
196
197         /* Open target drive on initial iteration */
198         if (Target == NULL) {
199             Target = dio_open (TargetId);
200             if (Target == NULL) {
201                 cprintf ("\r\n\nError %d on opening Drive %d\r\n", (int) _oserror, TargetId);
202                 return EXIT_FAILURE;
203             }
204
205             /* Check for compatible drives */
206             if (dio_query_sectsize (Target)  != SectSize ||
207                 dio_query_sectcount (Target) != SectCount) {
208                 cputs ("\r\n\nFormat mismatch between Drives\r\n");
209                 return EXIT_FAILURE;
210             }
211         }
212
213         ClearLine ();
214
215         /* Write one chunk of sectors from buffer */
216         for (Sector = ChunkOffset; Sector < SectCount && (Sector - ChunkOffset) < ChunkCount; ++Sector) {
217             cprintf ("\rWriting Sector %d of %d", Sector + 1, SectCount);
218
219             /* Write one sector */
220             if (dio_write (Target, Sector, Buffer + (Sector - ChunkOffset) * SectSize) != 0) {
221                 cprintf ("\r\n\nError %d on writing to Drive %d\r\n", (int) _oserror, TargetId);
222                 return EXIT_FAILURE;
223             }
224         }
225
226         /* Advance to next chunk */
227         ChunkOffset += ChunkCount;
228
229     } while (Sector < SectCount);
230
231     ClearLine ();
232     cprintf ("\rSuccessfully copied %d Sectors\r\n", SectCount);
233
234     free (Buffer);
235     dio_close (Source);
236     dio_close (Target);
237
238     return EXIT_SUCCESS;
239 }