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 <cc65.h>
40 #include <dio.h>
41
42
43 #define MAX_CHUNKS 10 /* Maximum acceptable number of chunks */
44
45
46 static unsigned char ScreenX;
47 static unsigned char ScreenY;
48
49
ClearLine(void)50 static void ClearLine (void)
51 /* Clear the screen line the cursor is on */
52 {
53 cputc ('\r');
54 cclear (ScreenX);
55 }
56
57
AskForDrive(const char * Name)58 static unsigned char AskForDrive (const char* Name)
59 /* Ask for a drive id and return it */
60 {
61 unsigned char Drive = 0;
62 char Char;
63
64 cprintf ("\r\n%s Drive ID ? ", Name);
65
66 cursor (1);
67 do {
68 Char = cgetc ();
69 if (isdigit (Char)) {
70 cputc (Char);
71 Drive = Drive * 10 + Char - '0';
72 }
73 } while (Char != CH_ENTER);
74 cursor (0);
75
76 return Drive;
77 }
78
79
AskForDisk(const char * Name,unsigned char Drive)80 static void AskForDisk (const char* Name, unsigned char Drive)
81 /* Ask the user to insert a specific disk */
82 {
83 ClearLine ();
84 cprintf ("\rInsert %s Disk into Drive %d !", Name, Drive);
85
86 cgetc ();
87 }
88
89
AllocBuffer(unsigned int SectSize,unsigned int SectCount,unsigned int * ChunkCount)90 static char* AllocBuffer (unsigned int SectSize, unsigned int SectCount, unsigned int* ChunkCount)
91 /* Allocate a copy buffer on the heap and return a pointer to it */
92 {
93 char* Buffer = NULL;
94 unsigned long BufferSize;
95 unsigned int Chunks = 1;
96
97 /* Increase number of chunks resp. decrease size */
98 /* of one chunk until buffer allocation succeeds */
99 do {
100 *ChunkCount = (unsigned int) ((SectCount + Chunks - 1) / Chunks);
101 BufferSize = *ChunkCount * (unsigned long) SectSize;
102 if (BufferSize < UINT_MAX) {
103 Buffer = malloc ((size_t) BufferSize);
104 }
105 } while (Buffer == NULL && ++Chunks <= MAX_CHUNKS);
106
107 return Buffer;
108 }
109
110
main(int argc,const char * argv[])111 int main (int argc, const char* argv[])
112 {
113 unsigned char SourceId;
114 unsigned char TargetId;
115 dhandle_t Source = NULL;
116 dhandle_t Target = NULL;
117 unsigned int SectSize;
118 unsigned int SectCount;
119 char* Buffer;
120 unsigned int Sector;
121 unsigned int ChunkCount;
122 unsigned int ChunkOffset = 0;
123
124 clrscr ();
125 screensize (&ScreenX, &ScreenY);
126
127 /* Allow user to read exit messages */
128 if (doesclrscrafterexit ()) {
129 atexit ((void (*)) cgetc);
130 }
131
132 cputs ("Floppy Disk Copy\r\n");
133 chline (16);
134 cputs ("\r\n");
135
136 /* Get source and target drive id (which may very well be identical) */
137 switch (argc) {
138 case 1:
139 SourceId = AskForDrive ("Source");
140 TargetId = AskForDrive ("Target");
141 cputs ("\r\n");
142 break;
143
144 case 2:
145 SourceId = TargetId = atoi (argv[1]);
146 break;
147
148 case 3:
149 SourceId = atoi (argv[1]);
150 TargetId = atoi (argv[2]);
151 break;
152
153 default:
154 cprintf ("\r\nToo many arguments\r\n");
155 return EXIT_FAILURE;
156 }
157
158 cputs ("\r\n");
159
160 do {
161 /* Check for single drive copy or inital iteration */
162 if (SourceId == TargetId || Source == NULL) {
163 AskForDisk ("Source", SourceId);
164 }
165
166 /* Check for initial iteration */
167 if (Source == NULL) {
168
169 /* Open source drive */
170 Source = dio_open (SourceId);
171 if (Source == NULL) {
172 cprintf ("\r\n\nError %d on opening Drive %d\r\n", (int) _oserror, SourceId);
173 return EXIT_FAILURE;
174 }
175
176 SectSize = dio_query_sectsize (Source);
177 SectCount = dio_query_sectcount (Source);
178
179 /* Allocate buffer */
180 Buffer = AllocBuffer (SectSize, SectCount, &ChunkCount);
181 if (Buffer == NULL) {
182 cputs ("\r\n\nError on allocating Buffer\r\n");
183 return EXIT_FAILURE;
184 }
185 }
186
187 ClearLine ();
188
189 /* Read one chunk of sectors into buffer */
190 for (Sector = ChunkOffset; Sector < SectCount && (Sector - ChunkOffset) < ChunkCount; ++Sector) {
191 cprintf ("\rReading Sector %d of %d", Sector + 1, SectCount);
192
193 /* Read one sector */
194 if (dio_read (Source, Sector, Buffer + (Sector - ChunkOffset) * SectSize) != 0) {
195 cprintf ("\r\n\nError %d on reading from Drive %d\r\n", (int) _oserror, SourceId);
196 return EXIT_FAILURE;
197 }
198 }
199
200 /* Check for single drive copy or inital iteration */
201 if (TargetId == SourceId || Target == NULL) {
202 AskForDisk ("Target", TargetId);
203 }
204
205 /* Open target drive on initial iteration */
206 if (Target == NULL) {
207 Target = dio_open (TargetId);
208 if (Target == NULL) {
209 cprintf ("\r\n\nError %d on opening Drive %d\r\n", (int) _oserror, TargetId);
210 return EXIT_FAILURE;
211 }
212
213 /* Check for compatible drives */
214 if (dio_query_sectsize (Target) != SectSize ||
215 dio_query_sectcount (Target) != SectCount) {
216 cputs ("\r\n\nFormat mismatch between Drives\r\n");
217 return EXIT_FAILURE;
218 }
219 }
220
221 ClearLine ();
222
223 /* Write one chunk of sectors from buffer */
224 for (Sector = ChunkOffset; Sector < SectCount && (Sector - ChunkOffset) < ChunkCount; ++Sector) {
225 cprintf ("\rWriting Sector %d of %d", Sector + 1, SectCount);
226
227 /* Write one sector */
228 if (dio_write (Target, Sector, Buffer + (Sector - ChunkOffset) * SectSize) != 0) {
229 cprintf ("\r\n\nError %d on writing to Drive %d\r\n", (int) _oserror, TargetId);
230 return EXIT_FAILURE;
231 }
232 }
233
234 /* Advance to next chunk */
235 ChunkOffset += ChunkCount;
236
237 } while (Sector < SectCount);
238
239 ClearLine ();
240 cprintf ("\rSuccessfully copied %d Sectors\r\n", SectCount);
241
242 free (Buffer);
243 dio_close (Source);
244 dio_close (Target);
245
246 return EXIT_SUCCESS;
247 }
248