00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #ifdef SAVE_RCSID
00011 static char *rcsid =
00012 "@(#) $Id: main.c,v 1.16 2006/04/06 16:50:13 trikalio Exp $";
00013 #endif
00014
00015 #include "opencbm.h"
00016 #include "d64copy.h"
00017
00018 #include "arch.h"
00019
00020 #include <getopt.h>
00021 #include <stdarg.h>
00022 #include <stdio.h>
00023 #include <stdlib.h>
00024 #include <signal.h>
00025 #include <string.h>
00026
00027
00028
00029 static int verbosity = 1;
00030 static int no_progress = 0;
00031
00032
00033 static CBM_FILE fd_cbm;
00034
00035
00036 static int is_cbm(char *name)
00037 {
00038 return((strcmp(name, "8" ) == 0) || (strcmp(name, "9" ) == 0) ||
00039 (strcmp(name, "10") == 0) || (strcmp(name, "11") == 0) );
00040 }
00041
00042
00043 static void help()
00044 {
00045 printf(
00046 "Usage: d64copy [OPTION]... [SOURCE] [TARGET]\n"
00047 "Copy .d64 disk images to a CBM-1541 or compatible drive and vice versa\n"
00048 "\n"
00049 "Options:\n"
00050 " -h, --help display this help and exit\n"
00051 " -V, --version display version information and exit\n"
00052 " -q, --quiet quiet output\n"
00053 " -v, --verbose control verbosity (repeatedly, up to 3 times)\n"
00054 " -n, --no-progress do not display progress information\n"
00055 "\n"
00056 " -s, --start-track=TRACK set start track\n"
00057 " -e, --end-track=TRACK set end track (start <= end <= 42/70)\n"
00058 "\n"
00059 " -t, --transfer=TRANSFER set transfermode; valid modes:\n"
00060 " auto (default)\n"
00061 " original (slowest)\n"
00062 " serial1 or s1\n"
00063 " serial2 or s2\n"
00064 " parallel (fastest)\n"
00065 " (can be abbreviated, if unambiguous)\n"
00066 " `original' and `serial1' should work in any case;\n"
00067 " `serial2' won't work if more than one device is\n"
00068 " connected to the IEC bus;\n"
00069 " `parallel' needs a XP1541/XP1571 cable in addition\n"
00070 " to the serial one.\n"
00071 " `auto' tries to determine the best option.\n"
00072 "\n"
00073 " -i, --interleave=VALUE set interleave value; ignored when reading with\n"
00074 " warp mode; default values are:\n"
00075 "\n"
00076 " original 16\n"
00077 "\n"
00078 " turbo r/w warp write\n"
00079 " serial1 4 6\n"
00080 " serial2 13 12\n"
00081 " parallel 7 4\n"
00082 "\n"
00083 " INTERLEAVE is ignored when reading with warp mode;\n"
00084 " if data transfer is very slow, increasing this\n"
00085 " value may help.\n"
00086 "\n"
00087 " -w, --warp enable warp mode; this is not possible if\n"
00088 " TRANSFER is set to `original'\n"
00089 " This is the default if transfer is not `original`.\n"
00090 "\n"
00091 " --no-warp disable warp mode; this is the default if\n"
00092 " TRANSFER is set to `original'.\n"
00093 "\n"
00094 " -b, --bam-only BAM-only copy; only allocated blocks are copied;\n"
00095 " for extended tracks (36-40), SpeedDOS BAM format\n"
00096 " is assumed. Use with caution.\n"
00097 "\n"
00098 " -B, --bam-save save BAM-only copy; this is like the `-bī option\n"
00099 " but copies always the entire directory track.\n"
00100 "\n"
00101 " -d, --drive-type=TYPE specify drive type:\n"
00102 " 0 or 1541 = 1541\n"
00103 " 1 or 1571 = 1570/1571\n"
00104 "\n"
00105 " -r, --retry-count=COUNT set retry count\n"
00106 "\n"
00107 " -E, --error-map=WHEN control whether the error map is appended.\n"
00108 " possible values for WHEN are (abbreviations\n"
00109 " available):\n"
00110 " always\n"
00111 " on_errors (default)\n"
00112 " never\n"
00113 "\n"
00114 " -2, --two-sided two-sided disk transfer (.d71): Requires 1571.\n"
00115 " Warp mode is not available for .d71 images.\n"
00116 "\n"
00117 );
00118 }
00119
00120 static void hint(char *s)
00121 {
00122 fprintf(stderr, "Try `%s' --help for more information.\n", s);
00123 }
00124
00125 static void ARCH_SIGNALDECL reset(int dummy)
00126 {
00127 fprintf(stderr, "\nSIGINT caught X-( Resetting IEC bus...\n");
00128 arch_sleep(1);
00129 d64copy_cleanup();
00130 cbm_reset(fd_cbm);
00131 cbm_driver_close(fd_cbm);
00132 exit(1);
00133 }
00134
00135
00136 static void my_message_cb(int severity, const char *format, ...)
00137 {
00138 va_list args;
00139
00140 static const char *severities[4] =
00141 {
00142 "Fatal",
00143 "Warning",
00144 "Info",
00145 "Debug"
00146 };
00147
00148 if(verbosity >= severity)
00149 {
00150 fprintf(stderr, "[%s] ", severities[severity]);
00151 va_start(args, format);
00152 vfprintf(stderr, format, args);
00153 va_end(args);
00154 fprintf(stderr, "\n");
00155 }
00156 }
00157
00158 static int my_status_cb(d64copy_status status)
00159 {
00160 static char trackmap[MAX_SECTORS+1];
00161 static int last_track;
00162 char *s;
00163 char *d;
00164
00165 static const char bs2char[] =
00166 {
00167 ' ', '.', '-', '?', '*'
00168 };
00169
00170 if(status.track == 0)
00171 {
00172 last_track = 0;
00173 return 0;
00174 }
00175
00176 if(no_progress)
00177 {
00178 return 0;
00179 }
00180
00181 if(last_track != status.track)
00182 {
00183 if(last_track)
00184 {
00185 printf("\r%2d: %-24s \n", last_track, trackmap);
00186 }
00187
00188 for(s = status.bam[status.track-1], d = trackmap; *s; s++, d++)
00189 {
00190 *d = bs2char[(int)*s];
00191 }
00192 *d = '\0';
00193 last_track = status.track;
00194 }
00195
00196 trackmap[status.sector] =
00197 bs2char[(status.read_result ||
00198 status.write_result) ? bs_error : bs_copied];
00199
00200 printf("\r%2d: %-24s%3d%% %4d/%d", status.track, trackmap,
00201 100 * status.sectors_processed / status.total_sectors,
00202 status.sectors_processed, status.total_sectors);
00203
00204 fflush(stdout);
00205 return 0;
00206 }
00207
00208
00209 int ARCH_MAINDECL main(int argc, char *argv[])
00210 {
00211 d64copy_settings *settings = d64copy_get_default_settings();
00212
00213 char *tm = NULL;
00214 char *src_arg;
00215 char *dst_arg;
00216
00217 int c;
00218 int rv = 1;
00219 int l;
00220
00221 int src_is_cbm;
00222 int dst_is_cbm;
00223
00224 struct option longopts[] =
00225 {
00226 { "help" , no_argument , NULL, 'h' },
00227 { "version" , no_argument , NULL, 'V' },
00228 { "warp" , no_argument , NULL, 'w' },
00229 { "no-warp" , no_argument , &settings->warp, 0 },
00230 { "quiet" , no_argument , NULL, 'q' },
00231 { "verbose" , no_argument , NULL, 'v' },
00232 { "no-progress", no_argument , NULL, 'n' },
00233 { "interleave" , required_argument, NULL, 'i' },
00234 { "start-track", required_argument, NULL, 's' },
00235 { "end-track" , required_argument, NULL, 'e' },
00236 { "transfer" , required_argument, NULL, 't' },
00237 { "bam-only" , no_argument , NULL, 'b' },
00238 { "bam-save" , no_argument , NULL, 'B' },
00239 { "drive-type" , required_argument, NULL, 'd' },
00240 { "retry-count", required_argument, NULL, 'r' },
00241 { "two-sided" , no_argument , NULL, '2' },
00242 { "error-map" , required_argument, NULL, 'E' },
00243 { NULL , 0 , NULL, 0 }
00244 };
00245
00246 const char shortopts[] ="hVwqbBt:i:s:e:d:r:2vnE:";
00247
00248 while((c=getopt_long(argc, argv, shortopts, longopts, NULL)) != -1)
00249 {
00250 switch(c)
00251 {
00252 case 'h': help();
00253 return 0;
00254 case 'V': printf("d64copy %s\n", OPENCBM_VERSION);
00255 return 0;
00256 case 'w': settings->warp = 1;
00257 break;
00258 case 'q': if(verbosity > 0) verbosity--;
00259 break;
00260 case 'v': verbosity++;
00261 break;
00262 case 'n': no_progress = 1;
00263 break;
00264 case 'i': settings->interleave = arch_atoc(optarg);
00265 break;
00266 case 's': settings->start_track = atoi(optarg);
00267 break;
00268 case 'e': settings->end_track = atoi(optarg);
00269 break;
00270 case 't': tm = optarg;
00271 break;
00272 case 'b': settings->bam_mode = bm_allocated;
00273 break;
00274 case 'B': settings->bam_mode = bm_save;
00275 break;
00276 case 'd': if(strcmp(optarg, "1541") == 0)
00277 {
00278 settings->drive_type = cbm_dt_cbm1541;
00279 }
00280 else if(strcmp(optarg, "1571") == 0)
00281 {
00282 settings->drive_type = cbm_dt_cbm1571;
00283 }
00284 else if(strcmp(optarg, "1570") == 0)
00285 {
00286 settings->drive_type = cbm_dt_cbm1570;
00287 }
00288 else
00289 {
00290 settings->drive_type = atoi(optarg) != 0 ?
00291 cbm_dt_cbm1571 : cbm_dt_cbm1541;
00292 }
00293 break;
00294 case 'r': settings->retries = atoi(optarg);
00295 break;
00296 case '2': settings->two_sided = 1;
00297 break;
00298 case 'E': l = strlen(optarg);
00299 if(strncmp(optarg, "always", l) == 0)
00300 {
00301 settings->error_mode = em_always;
00302 }
00303 else if(strncmp(optarg, "on_errors", l) == 0)
00304 {
00305 settings->error_mode = em_on_error;
00306 }
00307 else if(strncmp(optarg, "never", l) == 0)
00308 {
00309 settings->error_mode = em_never;
00310 }
00311 else
00312 {
00313 hint(argv[0]);
00314 return 1;
00315 }
00316 break;
00317 case 0: break;
00318 default : hint(argv[0]);
00319 return 1;
00320 }
00321 }
00322
00323 settings->transfer_mode = d64copy_get_transfer_mode_index(tm);
00324 if(settings->transfer_mode < 0)
00325 {
00326 char *modes = d64copy_get_transfer_modes();
00327 char *m;
00328
00329 fprintf(stderr, "Unknown transfer mode: %s\nAvailable modes:\n", tm);
00330
00331 for(m = modes; *m; m+=(strlen(m)+1))
00332 {
00333 fprintf(stderr, " %s\n", m);
00334 }
00335
00336 free(modes);
00337 return 1;
00338 }
00339
00340 my_message_cb(3, "transfer mode is %d", settings->transfer_mode );
00341
00342 if(optind + 2 != argc)
00343 {
00344 fprintf(stderr, "Usage: %s [OPTION]... [SOURCE] [TARGET]\n", argv[0]);
00345 hint(argv[0]);
00346 return 1;
00347 }
00348
00349 src_arg = argv[optind];
00350 dst_arg = argv[optind+1];
00351
00352 src_is_cbm = is_cbm(src_arg);
00353 dst_is_cbm = is_cbm(dst_arg);
00354
00355 if(src_is_cbm == dst_is_cbm)
00356 {
00357 my_message_cb(0, "either source or target must be a CBM drive");
00358 return 1;
00359 }
00360
00361 if(cbm_driver_open(&fd_cbm, 0) == 0)
00362 {
00363
00364
00365
00366
00367 settings->transfer_mode =
00368 d64copy_check_auto_transfer_mode(fd_cbm,
00369 settings->transfer_mode,
00370 atoi(src_is_cbm ? src_arg : dst_arg));
00371
00372 my_message_cb(3, "decided to use transfer mode %d", settings->transfer_mode );
00373
00374 signal(SIGINT, reset);
00375
00376 if(src_is_cbm)
00377 {
00378 rv = d64copy_read_image(fd_cbm, settings, atoi(src_arg), dst_arg,
00379 my_message_cb, my_status_cb);
00380 }
00381 else
00382 {
00383 rv = d64copy_write_image(fd_cbm, settings, src_arg, atoi(dst_arg),
00384 my_message_cb, my_status_cb);
00385 }
00386
00387 if(!no_progress && rv >= 0)
00388 {
00389 printf("\n%d blocks copied.\n", rv);
00390 }
00391
00392 cbm_driver_close(fd_cbm);
00393 rv = 0;
00394 }
00395 else
00396 {
00397 arch_error(0, arch_get_errno(), "%s", cbm_get_driver_name(0));
00398 }
00399
00400 free(settings);
00401
00402 return rv;
00403 }