1 /*
2 ucon64_opts.c - switches for all uCON64 options
3 
4 Copyright (c) 2002 - 2005              NoisyB
5 Copyright (c) 2002 - 2005, 2015 - 2021 dbjh
6 Copyright (c) 2005                     Jan-Erik Karlsson (Amiga)
7 
8 
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
13 
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 GNU General Public License for more details.
18 
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23 #ifdef  HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26 #ifdef  _MSC_VER
27 #pragma warning(push)
28 #pragma warning(disable: 4668) // 'symbol' is not defined as a preprocessor macro, replacing with '0' for 'directives'
29 #endif
30 #include <ctype.h>
31 #ifdef  _MSC_VER
32 #pragma warning(pop)
33 #endif
34 #include <errno.h>
35 #ifdef  _MSC_VER
36 #pragma warning(push)
37 #pragma warning(disable: 4820) // 'bytes' bytes padding added after construct 'member_name'
38 #include <io.h>
39 #pragma warning(pop)
40 #endif
41 #include <stdlib.h>
42 #ifdef  HAVE_UNISTD_H
43 #include <unistd.h>
44 #endif
45 #ifdef  _MSC_VER
46 #pragma warning(push)
47 #pragma warning(disable: 4820) // 'bytes' bytes padding added after construct 'member_name'
48 #endif
49 #include <sys/stat.h>
50 #ifdef  _MSC_VER
51 #pragma warning(pop)
52 #endif
53 #include "misc/archive.h"
54 #include "misc/file.h"
55 #include "misc/misc.h"
56 #include "misc/parallel.h"
57 #include "misc/string.h"
58 #include "misc/term.h" // to avoid MinGW warning about using ll prefix in fprintf()
59 #include "ucon64_dat.h"
60 #include "ucon64_misc.h"
61 #include "ucon64_opts.h"
62 #include "console/dc.h"
63 #include "console/gb.h"
64 #include "console/gba.h"
65 #include "console/genesis.h"
66 #include "console/lynx.h"
67 #include "console/n64.h"
68 #include "console/nds.h"
69 #include "console/neogeo.h"
70 #include "console/nes.h"
71 #include "console/pce.h"
72 #include "console/sms.h"
73 #include "console/snes.h"
74 #include "console/swan.h"
75 #include "backup/backup.h"
76 #include "backup/cd64.h"
77 #include "backup/cmc.h"
78 #include "backup/doctor64.h"
79 #include "backup/doctor64jr.h"
80 #include "backup/f2a.h"
81 #include "backup/fal.h"
82 #include "backup/gbx.h"
83 #include "backup/gd.h"
84 #include "backup/lynxit.h"
85 #include "backup/mccl.h"
86 #include "backup/mcd.h"
87 #include "backup/md-pro.h"
88 #include "backup/msg.h"
89 #include "backup/pce-pro.h"
90 #include "backup/pl.h"
91 #include "backup/quickdev16.h"
92 #include "backup/sflash.h"
93 #include "backup/smc.h"
94 #include "backup/smcic2.h"
95 #include "backup/smd.h"
96 #include "backup/smsgg-pro.h"
97 #include "backup/swc.h"
98 #include "backup/ufosd.h"
99 #include "patch/aps.h"
100 #include "patch/bsl.h"
101 #include "patch/gg.h"
102 #include "patch/ips.h"
103 #include "patch/ppf.h"
104 
105 
106 static int
strtoint(const char * str,int base,void * var,size_t var_size)107 strtoint (const char *str, int base, void *var, size_t var_size)
108 {
109   char *endptr;
110   int64_t value = 0;
111 
112   if (var_size > sizeof value)
113     var_size = sizeof value;
114   errno = 0;
115   value = strtoll (str, &endptr, base);
116   if (errno || *endptr)
117     return -1;
118   else
119 #ifndef WORDS_BIGENDIAN
120     memcpy (var, &value, var_size);
121 #else
122     memcpy (var, ((uint8_t *) &value) + sizeof value - var_size, var_size);
123 #endif
124 
125   return 0;
126 }
127 
128 
129 int
ucon64_switches(st_ucon64_t * p)130 ucon64_switches (st_ucon64_t *p)
131 {
132   int x = 0;
133   const char *option_arg = p->optarg;
134 
135   /*
136     Handle options or switches that cause other _options_ to be ignored except
137     other options of the same class (so the order in which they were specified
138     matters).
139     We have to do this here (not in ucon64_options()) or else other options
140     might be executed before these.
141   */
142   switch (p->option)
143     {
144     /*
145       Many tools ignore other options if --help has been specified. We do the
146       same (compare with GNU tools).
147     */
148     case UCON64_HELP:
149       x = USAGE_VIEW_LONG;
150       if (option_arg)
151         {
152           if (!strcmp (option_arg, "pad"))
153             x = USAGE_VIEW_PAD;
154           else if (!strcmp (option_arg, "dat"))
155             x = USAGE_VIEW_DAT;
156           else if (!strcmp (option_arg, "patch"))
157             x = USAGE_VIEW_PATCH;
158           else if (!strcmp (option_arg, "backup"))
159             x = USAGE_VIEW_BACKUP;
160           else if (!strcmp (option_arg, "disc"))
161             x = USAGE_VIEW_DISC;
162         }
163       ucon64_usage (ucon64.argc, ucon64.argv, x);
164       exit (0);
165 
166     /*
167       It's also common to exit after displaying version information.
168       On some configurations printf is a macro (Red Hat Linux 6.2 + GCC 3.2),
169       so we can't use preprocessor directives in the argument list.
170     */
171     case UCON64_VER:
172       printf ("version:                           %s (%s)\n"
173               "platform:                          %s\n",
174               UCON64_VERSION_S, __DATE__, CURRENT_OS_S);
175 
176 #ifdef  USE_PARALLEL
177 #ifdef  USE_PPDEV
178       puts ("parallel port backup unit support: yes (ppdev)");
179 #else
180       puts ("parallel port backup unit support: yes");
181 #endif // USE_PPDEV
182 #else
183       puts ("parallel port backup unit support: no");
184 #endif
185 
186 #ifdef  USE_USB
187       puts ("USB port backup unit support:      yes");
188 #else
189       puts ("USB port backup unit support:      no");
190 #endif
191 
192 
193 #ifdef  USE_ANSI_COLOR
194       puts ("ANSI colors enabled:               yes");
195 #else
196       puts ("ANSI colors enabled:               no");
197 #endif
198 
199 #ifdef  USE_ZLIB
200       printf ("gzip and zip support:              yes, zlib %s\n",
201               ZLIB_VERSION);
202 #else
203       puts ("gzip and zip support:              no");
204 #endif
205 
206       printf ("configuration file %s  %s\n",
207               // display the existence only for the config file (really helps solving problems)
208               access (ucon64.configfile, F_OK) ? "(not present):" : "(present):    ",
209               ucon64.configfile);
210 
211 #ifdef  USE_DISCMAGE
212       fputs ("discmage DLL:                      ", stdout);
213 
214 #ifdef  DLOPEN
215       puts (ucon64.discmage_path);
216 #else
217 #if     defined __MSDOS__
218       fputs ("discmage.dxe", stdout);
219 #elif   defined __CYGWIN__ || defined _WIN32
220       fputs ("discmage.dll", stdout);
221 #elif   defined __APPLE__                       // Mac OS X actually
222       fputs ("libdiscmage.dylib", stdout);
223 #elif   defined __unix__ || defined __BEOS__
224       fputs ("libdiscmage.so", stdout);
225 #else
226       fputs ("unknown", stdout);
227 #endif
228       puts (", dynamically linked");
229 #endif // DLOPEN
230 
231       if (ucon64.discmage_enabled)
232         {
233           x = dm_get_version ();
234           printf ("discmage enabled:                  yes, %d.%d.%d (%s)\n",
235                   (x >> 16) & 0xff, (x >> 8) & 0xff, x & 0xff,
236                   dm_get_version_s ());
237         }
238       else
239         puts ("discmage enabled:                  no");
240 #endif // USE_DISCMAGE
241 
242       printf ("configuration directory:           %s\n"
243               "DAT file directory:                %s\n"
244               "entries in DATabase:               %u\n"
245               "DATabase enabled:                  %s\n",
246               ucon64.configdir,
247               ucon64.datdir,
248               ucon64_dat_total_entries (),
249               ucon64.dat_enabled ? "yes" : "no");
250       exit (0);
251       break;
252 
253     case UCON64_FRONTEND:
254       ucon64.frontend = 1;                      // used by (for example) ucon64_gauge()
255       break;
256 
257     case UCON64_NBAK:
258       ucon64.backup = 0;
259       break;
260 
261     case UCON64_R:
262       ucon64.recursive = 1;
263       break;
264 
265 #ifdef  USE_ANSI_COLOR
266     case UCON64_NCOL:
267       ucon64.ansi_color = 0;
268       break;
269 #endif
270 
271     case UCON64_RIP:
272     case UCON64_MKTOC:
273     case UCON64_MKCUE:
274     case UCON64_MKSHEET:
275     case UCON64_BIN2ISO:
276     case UCON64_ISOFIX:
277     case UCON64_XCDRW:
278     case UCON64_DISC:
279     case UCON64_CDMAGE:
280       ucon64.force_disc = 1;
281       break;
282 
283     case UCON64_NS:
284       ucon64.org_split = ucon64.split = 0;
285       break;
286 
287     case UCON64_HD:
288       ucon64.backup_header_len = UNKNOWN_BACKUP_HEADER_LEN;
289       break;
290 
291     case UCON64_HDN:
292       ucon64.backup_header_len = strtol (option_arg, NULL, 10);
293       break;
294 
295     case UCON64_NHD:
296       ucon64.backup_header_len = 0;
297       break;
298 
299     case UCON64_SWP:                            // deprecated
300     case UCON64_INT:
301       ucon64.interleaved = 1;
302       break;
303 
304     case UCON64_INT2:
305       ucon64.interleaved = 2;
306       break;
307 
308     case UCON64_NSWP:                           // deprecated
309     case UCON64_NINT:
310       ucon64.interleaved = 0;
311       break;
312 
313     case UCON64_PORT:
314 #ifdef  USE_USB
315       if (!strnicmp (option_arg, "usb", 3))
316         {
317           if (strlen (option_arg) >= 4)
318             ucon64.usbport = strtol (option_arg + 3, NULL, 10) + 1; // usb0 => ucon64.usbport = 1
319           else                                  // we automatically detect the
320             ucon64.usbport = 1;                 //  USB port in the F2A & Quickdev16 code
321 
322           /*
323             We don't want to make uCON64 behave differently if --port=USB{n} is
324             specified *after* a transfer option (instead of before one), so we
325             have to reset ucon64.parport_needed here.
326           */
327           ucon64.parport_needed = 0;
328         }
329       else
330 #endif
331         ucon64.parport = (uint16_t) strtol (option_arg, NULL, 16);
332       break;
333 
334 #ifdef  USE_PARALLEL
335     /*
336       We detect the presence of these options here so that we can drop
337       privileges ASAP.
338       Note that the libcd64 options are not listed here. We cannot drop
339       privileges before libcd64 is initialised (after cd64_t.devopen() has been
340       called).
341     */
342     case UCON64_XFIG:
343     case UCON64_XFIGC:
344     case UCON64_XFIGS:
345     case UCON64_XIC2:
346     case UCON64_XLIT:
347     case UCON64_XMSG:
348     case UCON64_XRESET:
349     case UCON64_XSMC:
350     case UCON64_XSMCR:
351     case UCON64_XSMD:
352     case UCON64_XSMDS:
353     case UCON64_XSWC:
354     case UCON64_XSWC2:
355     case UCON64_XSWCC:
356     case UCON64_XSWCR:
357     case UCON64_XSWCS:
358     case UCON64_XV64:
359       if (!UCON64_ISSET2 (ucon64.parport_mode, parport_mode_t))
360         ucon64.parport_mode = PPMODE_SPP;
361     case UCON64_XCMC:
362     case UCON64_XCMCT:
363     case UCON64_XGD3:
364     case UCON64_XGD3R:
365     case UCON64_XGD3S:
366     case UCON64_XGD6:
367     case UCON64_XGD6R:
368     case UCON64_XGD6S:
369     case UCON64_XMCCL:
370     case UCON64_XMCD:
371       if (!UCON64_ISSET2 (ucon64.parport_mode, parport_mode_t))
372         ucon64.parport_mode = PPMODE_SPP_BIDIR;
373     case UCON64_XDJR:
374     case UCON64_XF2A:                           // could be for USB version
375     case UCON64_XF2AMULTI:                      // idem
376     case UCON64_XF2AB:                          // idem
377     case UCON64_XF2AC:                          // idem
378     case UCON64_XF2AS:                          // idem
379     case UCON64_XFAL:
380     case UCON64_XFALMULTI:
381     case UCON64_XFALB:
382     case UCON64_XFALC:
383     case UCON64_XFALS:
384     case UCON64_XGBX:
385     case UCON64_XGBXB:
386     case UCON64_XGBXS:
387     case UCON64_XGG:
388     case UCON64_XGGB:
389     case UCON64_XGGS:
390     case UCON64_XMD:
391     case UCON64_XMDB:
392     case UCON64_XMDS:
393     case UCON64_XPCE:
394     case UCON64_XPL:
395     case UCON64_XPLI:
396     case UCON64_XSF:
397     case UCON64_XSFS:
398       if (!UCON64_ISSET2 (ucon64.parport_mode, parport_mode_t))
399         ucon64.parport_mode = PPMODE_EPP;
400 #ifdef  USE_USB
401       if (!ucon64.usbport)                      // no pport I/O if F2A option and USB F2A
402 #endif
403       ucon64.parport_needed = 1;
404       break;
405 #endif // USE_PARALLEL
406 
407 #ifdef  USE_LIBCD64
408     case UCON64_XCD64:
409     case UCON64_XCD64B:
410     case UCON64_XCD64C:
411     case UCON64_XCD64E:
412     case UCON64_XCD64F:
413     case UCON64_XCD64M:
414     case UCON64_XCD64S:
415 #ifdef  USE_PARALLEL
416       if (!UCON64_ISSET2 (ucon64.parport_mode, parport_mode_t))
417         ucon64.parport_mode = PPMODE_SPP_BIDIR;
418 #endif
419       // We don't really need the parallel port. We just have to make sure that
420       //  privileges aren't dropped.
421       ucon64.parport_needed = 2;
422       break;
423 
424     case UCON64_XCD64P:
425       ucon64.io_mode = strtol (option_arg, NULL, 10);
426       break;
427 #endif // USE_LIBCD64
428 
429 #ifdef  USE_PARALLEL
430     case UCON64_XCMCM:
431       ucon64.io_mode = strtol (option_arg, NULL, 10);
432       break;
433 
434     case UCON64_XFALM:
435     case UCON64_XGBXM:
436     case UCON64_XPLM:
437       ucon64.parport_mode = PPMODE_SPP_BIDIR;
438       break;
439 
440     case UCON64_XSWC_IO:
441       ucon64.io_mode = strtol (option_arg, NULL, 16);
442 
443       if (ucon64.io_mode & SWC_IO_ALT_ROM_SIZE)
444         puts ("WARNING: I/O mode not yet implemented");
445 #if 0 // all these constants are defined by default
446       if (ucon64.io_mode & (SWC_IO_SPC7110 | SWC_IO_SDD1 | SWC_IO_SA1 | SWC_IO_MMX2))
447         puts ("WARNING: Be sure to compile swc.c with the appropriate constants defined");
448 #endif
449 
450       if (ucon64.io_mode > SWC_IO_MAX)
451         {
452           printf ("WARNING: Invalid value for MODE (0x%x), using 0\n", ucon64.io_mode);
453           ucon64.io_mode = 0;
454         }
455       else
456         {
457           printf ("I/O mode: 0x%03x", ucon64.io_mode);
458           if (ucon64.io_mode)
459             {
460               char flagstr[160];
461 
462               flagstr[0] = '\0';
463               if (ucon64.io_mode & SWC_IO_FORCE_32MBIT)
464                 strcat (flagstr, "force 32 Mbit dump, ");
465               if (ucon64.io_mode & SWC_IO_ALT_ROM_SIZE)
466                 strcat (flagstr, "alternative ROM size method, ");
467               if (ucon64.io_mode & SWC_IO_SUPER_FX)
468                 strcat (flagstr, "Super FX, ");
469               if (ucon64.io_mode & SWC_IO_SDD1)
470                 strcat (flagstr, "S-DD1, ");
471               if (ucon64.io_mode & SWC_IO_SA1)
472                 strcat (flagstr, "SA-1, ");
473               if (ucon64.io_mode & SWC_IO_SPC7110)
474                 strcat (flagstr, "SPC7110, ");
475               if (ucon64.io_mode & SWC_IO_DX2_TRICK)
476                 strcat (flagstr, "DX2 trick, ");
477               if (ucon64.io_mode & SWC_IO_MMX2)
478                 strcat (flagstr, "Mega Man X 2, ");
479               if (ucon64.io_mode & SWC_IO_DUMP_BIOS)
480                 strcat (flagstr, "dump BIOS, ");
481 
482               if (flagstr[0])
483                 flagstr[strlen (flagstr) - 2] = '\0';
484               printf (" (%s)", flagstr);
485             }
486           fputc ('\n', stdout);
487         }
488       break;
489 #endif // USE_PARALLEL
490 
491 #ifdef  USE_USB
492     case UCON64_XQD16:
493     case UCON64_XUFOSD:
494       /*
495         It is possible to perform USB I/O without being root. However, without
496         any configuration root privileges are required. By default uCON64 will
497         be installed setuid root (on UNIX), so we just have to make sure
498         privileges will not be dropped. One way to do that is assigning 2 to
499         ucon64.parport_needed. A more appropriate way for USB devices is using
500         ucon64.usbport.
501       */
502       if (!ucon64.usbport)
503         ucon64.usbport = 1;
504       break;
505 #endif // USE_USB
506 
507     case UCON64_PATCH: // --patch and --file are the same
508     case UCON64_FILE:
509       ucon64.file = option_arg;
510       break;
511 
512     case UCON64_I:
513     case UCON64_B:
514     case UCON64_A:
515     case UCON64_NA:
516     case UCON64_PPF:
517     case UCON64_NPPF:
518     case UCON64_IDPPF:
519       if (!ucon64.file || !ucon64.file[0])
520         ucon64.file = ucon64.argv[ucon64.argc - 1];
521       break;
522 
523 #if 0
524     case UCON64_ROM:
525       if (option_arg)
526         ucon64.fname = option_arg;
527       break;
528 #endif
529 
530     case UCON64_O:
531       {
532         char path[FILENAME_MAX];
533         int dir = 0;
534 
535         if (realpath2 (option_arg, path))
536           {
537             char dir_name[FILENAME_MAX];
538             struct stat fstate;
539 
540             /*
541               MinGW's stat() does not accept a trailing slash or backslash, but
542               dirname2() only recognizes a path as directory if it ends with a
543               slash or backslash.
544             */
545             strcat (path, DIR_SEPARATOR_S);
546             dirname2 (path, dir_name);
547             if (!stat (dir_name, &fstate) && S_ISDIR (fstate.st_mode))
548               {
549                 // dirname2() strips trailing slashes and/or backslashes (if not
550                 //  the root directory of a drive).
551                 snprintf (ucon64.output_path, FILENAME_MAX, "%s%s", dir_name,
552                           dir_name[strlen (dir_name) - 1] != DIR_SEPARATOR ?
553                             DIR_SEPARATOR_S : "");
554                 ucon64.output_path[FILENAME_MAX - 1] = '\0';
555                 dir = 1;
556               }
557           }
558 
559         if (!dir)
560           puts ("WARNING: Argument for " OPTION_S "o must be a directory. Using current directory instead");
561       }
562       break;
563 
564     case UCON64_NHI:
565       ucon64.snes_hirom = 0;
566       break;
567 
568     case UCON64_HI:
569       ucon64.snes_hirom = SNES_HIROM;
570       break;
571 
572     case UCON64_EROM:
573       ucon64.snes_header_base = SNES_EROM;
574       break;
575 
576     case UCON64_BS:
577       ucon64.bs_dump = 1;
578       break;
579 
580     case UCON64_NBS:
581       ucon64.bs_dump = 0;
582       break;
583 
584     case UCON64_CTRL:
585       if (UCON64_ISSET (ucon64.controller))
586         ucon64.controller |= 1 << strtol (option_arg, NULL, 10);
587       else
588         ucon64.controller = 1 << strtol (option_arg, NULL, 10);
589       break;
590 
591     case UCON64_CTRL2:
592       if (UCON64_ISSET (ucon64.controller2))
593         ucon64.controller2 |= 1 << strtol (option_arg, NULL, 10);
594       else
595         ucon64.controller2 = 1 << strtol (option_arg, NULL, 10);
596       break;
597 
598     case UCON64_NTSC:
599       if (!UCON64_ISSET (ucon64.tv_standard))
600         ucon64.tv_standard = 0;
601       else if (ucon64.tv_standard == 1)
602         ucon64.tv_standard = 2;                 // code for NTSC/PAL (NES UNIF/iNES)
603       break;
604 
605     case UCON64_PAL:
606       if (!UCON64_ISSET (ucon64.tv_standard))
607         ucon64.tv_standard = 1;
608       else if (ucon64.tv_standard == 0)
609         ucon64.tv_standard = 2;                 // code for NTSC/PAL (NES UNIF/iNES)
610       break;
611 
612     case UCON64_BAT:
613       ucon64.battery = 1;
614       break;
615 
616     case UCON64_NBAT:
617       ucon64.battery = 0;
618       break;
619 
620     case UCON64_VRAM:
621       ucon64.vram = 1;
622       break;
623 
624     case UCON64_NVRAM:
625       ucon64.vram = 0;
626       break;
627 
628     case UCON64_MIRR:
629       ucon64.mirror = strtol (option_arg, NULL, 10);
630       break;
631 
632     case UCON64_MAPR:
633       ucon64.mapr = option_arg;                 // pass the _string_, it can be a
634       break;                                    //  board name
635 
636     case UCON64_CMNT:
637       ucon64.comment = option_arg;
638       break;
639 
640     case UCON64_DUMPINFO:
641       ucon64.use_dump_info = 1;
642       ucon64.dump_info = option_arg;
643       break;
644 
645     case UCON64_RANGE:
646       {
647         char buf[80], *token;
648         size_t len = strnlen (option_arg, sizeof buf - 1);
649         unsigned int offset1, offset2;
650 
651         strncpy (buf, option_arg, len)[len] = '\0';
652 
653         token = strtok (buf, ":");
654         if (!token)
655           {
656             fputs ("ERROR: No O1 (offset 1) specified. Specify one before a colon\n", stderr);
657             break;
658           }
659         if (strtoint (token, 16, &offset1, sizeof offset1))
660           {
661             fprintf (stderr, "ERROR: Invalid O1 (offset 1): %s\n", token);
662             break;
663           }
664 
665         token = strtok (NULL, "");
666         if (!token)
667           {
668             fputs ("ERROR: No O2 (offset 2) specified. Specify one after a colon\n", stderr);
669             break;
670           }
671         if (strtoint (token, 16, &offset2, sizeof offset2))
672           {
673             fprintf (stderr, "ERROR: Invalid O2 (offset 2): %s\n", token);
674             break;
675           }
676 
677         if (offset1 >= offset2)
678           {
679             fputs ("ERROR: When specifying a range O2 (offset 2) must be larger than O1 (offset 1)\n",
680                    stderr);
681             break;
682           }
683 
684         ucon64.range_start = offset1;
685         ucon64.range_length = offset2 - offset1 + 1;
686       }
687       break;
688 
689     case UCON64_Q:
690     case UCON64_QQ:                             // for now -qq is equivalent to -q
691       ucon64.quiet = 1;
692       cm_verbose = 0;
693       break;
694 
695     case UCON64_V:
696       ucon64.quiet = -1;
697       cm_verbose = 1;
698       break;
699 
700     case UCON64_SSIZE:
701       ucon64.part_size = strtol (option_arg, NULL, 10) * MBIT;
702       break;
703 
704     case UCON64_ID:
705       ucon64.id = -2;                           // just a value other than
706       break;                                    //  UCON64_UNKNOWN and smaller than 0
707 
708     case UCON64_IDNUM:
709       ucon64.id = strtol (option_arg, NULL, 10);
710       if (ucon64.id < 0)
711         ucon64.id = 0;
712       else if (ucon64.id > 999)
713         {
714           fputs ("ERROR: NUM must be smaller than or equal to 999\n", stderr);
715           exit (1);
716         }
717       break;
718 
719     case UCON64_REGION:
720       if (option_arg[1] == '\0' && toupper ((int) option_arg[0]) == 'X') // be insensitive to case
721         ucon64.region = 256;
722       else
723         ucon64.region = strtol (option_arg, NULL, 10);
724       break;
725 
726     default:
727       break;
728     }
729 
730   return 0;
731 }
732 
733 
734 static inline char *
tofunc(char * s,size_t len,int (* func)(int))735 tofunc (char *s, size_t len, int (*func) (int))
736 {
737   char *p = s;
738 
739   for (; len > 0; p++, len--)
740     *p = (char) func (*p);
741 
742   return s;
743 }
744 
745 
746 static inline int
ls_toprint(int c)747 ls_toprint (int c)
748 {
749   return isprint (c) ? c : '.';
750 }
751 
752 
753 static int
hexstring_to_ints(char * src,int wildcard)754 hexstring_to_ints (char *src, int wildcard)
755 {
756   int retval = 0, i = 0;
757   char *dest = src;
758   uint8_t value = 0;
759 
760   for (; *src; ++src)
761     {
762       uint8_t digit;
763 
764       if (*src == ' ' || *src == '\t')
765         continue;
766       else if (*src >= '0' && *src <= '9')
767         digit = *src - '0';
768       else if (*src >= 'A' && *src <= 'F')
769         digit = *src - 'A' + 10;
770       else if (*src >= 'a' && *src <= 'f')
771         digit = *src - 'a' + 10;
772       else if (wildcard && *src == '?')
773         {
774           *dest++ = *src;
775           i += i & 1 ? 1 : 2;
776           continue;
777         }
778       else
779         {
780           retval = -1;
781           break;
782         }
783       value = value << 4 | digit;
784       if (i & 1)
785         *dest++ = value;
786       i++;
787     }
788   *dest = '\0';
789 
790   if (!retval)
791     retval = i / 2;
792 
793   return retval;
794 }
795 
796 
797 static int64_t
strtoll2(const char * str)798 strtoll2 (const char *str)
799 {
800   char *endptr;
801   int64_t value = 0;
802 
803   errno = 0;
804   value = strtoll (str, &endptr, 10);
805   if (errno || *endptr)
806     value = strtoll (str, NULL, 16);
807 
808   return value;
809 }
810 
811 
812 static void
set_dump_args(const char * str,uint64_t * start,uint64_t * len)813 set_dump_args (const char *str, uint64_t *start, uint64_t *len)
814 {
815   char buf[80], *token;
816   size_t l;
817   uint64_t end;
818 
819   if (!str)
820     {
821       *start = 0;
822       *len = ucon64.fsize;
823       return;
824     }
825 
826   l = strnlen (str, sizeof buf - 1);
827   strncpy (buf, str, l)[l] = '\0';
828 
829   token = strtok (buf, ":");
830   if (!token)
831     {
832       *start = 0;
833       *len = ucon64.fsize;
834       return;
835     }
836   *start = strtoll2 (token);
837   if (*start >= ucon64.fsize)
838     {
839       fprintf (stderr,
840                "ERROR: O1 (start) must be smaller than the file size (0x%llx)\n",
841                (long long unsigned int) ucon64.fsize);
842       exit (1);
843     }
844 
845   token = strtok (NULL, "");
846   if (!token)
847     {
848       *len = ucon64.fsize - *start;
849       return;
850     }
851   end = strtoll2 (token);
852   if (end >= ucon64.fsize)
853     {
854       fprintf (stderr,
855                "ERROR: O2 (end) must be smaller than the file size (0x%llx)\n",
856                (long long unsigned int) ucon64.fsize);
857       exit (1);
858     }
859   if (*start > end)
860     {
861       fputs ("ERROR: O2 (end) must be larger than or equal to O1 (start)\n", stderr);
862       exit (1);
863     }
864   *len = end - *start + 1;
865 }
866 
867 
868 int
ucon64_options(st_ucon64_t * p)869 ucon64_options (st_ucon64_t *p)
870 {
871 #ifdef  USE_PARALLEL
872   unsigned short enableRTS = (unsigned short) -1; // for UCON64_XSWC & UCON64_XSWC2
873 #endif
874   int value = 0, x = 0;
875   unsigned int checksum;
876   char buf[MAXBUFSIZE], src_name[FILENAME_MAX], dest_name[FILENAME_MAX],
877        *ptr = NULL, *values[UCON64_MAX_ARGS];
878   const char *option_arg = p->optarg;
879 
880   strcpy (src_name, ucon64.fname);
881   strcpy (dest_name, ucon64.fname);
882 
883   switch (p->option)
884     {
885     case UCON64_CRCHD:                          // deprecated
886       value = UNKNOWN_BACKUP_HEADER_LEN;
887     case UCON64_CRC:
888       if (!value)
889         value = ucon64.nfo ? ucon64.nfo->backup_header_len :
890                   UCON64_ISSET2 (ucon64.backup_header_len, unsigned int) ?
891                     ucon64.backup_header_len : 0;
892       fputs (ucon64.fname, stdout);
893       if (ucon64.fname_arch[0])
894         printf (" (%s)\n", ucon64.fname_arch);
895       else
896         fputc ('\n', stdout);
897       checksum = 0;
898       ucon64_chksum (NULL, NULL, &checksum, ucon64.fname, ucon64.fsize, value);
899       printf ("Checksum (CRC32): 0x%08x\n", checksum);
900       break;
901 
902     case UCON64_SHA1:
903       value = ucon64.nfo ? ucon64.nfo->backup_header_len :
904                 UCON64_ISSET2 (ucon64.backup_header_len, unsigned int) ?
905                   ucon64.backup_header_len : 0;
906       fputs (ucon64.fname, stdout);
907       if (ucon64.fname_arch[0])
908         printf (" (%s)\n", ucon64.fname_arch);
909       else
910         fputc ('\n', stdout);
911       ucon64_chksum (buf, NULL, NULL, ucon64.fname, ucon64.fsize, value);
912       printf ("Checksum (SHA1): 0x%s\n", buf);
913       break;
914 
915     case UCON64_MD5:
916       value = ucon64.nfo ? ucon64.nfo->backup_header_len :
917                 UCON64_ISSET2 (ucon64.backup_header_len, unsigned int) ?
918                   ucon64.backup_header_len : 0;
919       fputs (ucon64.fname, stdout);
920       if (ucon64.fname_arch[0])
921         printf (" (%s)\n", ucon64.fname_arch);
922       else
923         fputc ('\n', stdout);
924       ucon64_chksum (NULL, buf, NULL, ucon64.fname, ucon64.fsize, value);
925       printf ("Checksum (MD5): 0x%s\n", buf);
926       break;
927 
928     case UCON64_HEX:
929       {
930         uint64_t start, len;
931         set_dump_args (option_arg, &start, &len);
932         ucon64_dump (stdout, ucon64.fname, start, len, DUMPER_HEX);
933       }
934       break;
935 
936     case UCON64_BIT:
937       {
938         uint64_t start, len;
939         set_dump_args (option_arg, &start, &len);
940         ucon64_dump (stdout, ucon64.fname, start, len, DUMPER_BIT);
941       }
942       break;
943 
944     case UCON64_CODE:
945       {
946         uint64_t start, len;
947         set_dump_args (option_arg, &start, &len);
948         ucon64_dump (stdout, ucon64.fname, start, len, DUMPER_CODE);
949       }
950       break;
951 
952     case UCON64_PRINT:
953       {
954         uint64_t start, len;
955         set_dump_args (option_arg, &start, &len);
956         ucon64_dump (stdout, ucon64.fname, start, len, DUMPER_PRINT);
957       }
958       break;
959 
960     case UCON64_C:
961       ucon64_filefile (option_arg, 0, 0, FALSE);
962       break;
963 
964     case UCON64_CS:
965       ucon64_filefile (option_arg, 0, 0, TRUE);
966       break;
967 
968     case UCON64_FIND:
969       ucon64_find (ucon64.fname, 0, ucon64.fsize, option_arg,
970                    strlen (option_arg), MEMCMP2_WCARD ('?'));
971       break;
972 
973     case UCON64_FINDR:
974       ucon64_find (ucon64.fname, 0, ucon64.fsize, option_arg,
975                    strlen (option_arg), MEMCMP2_REL);
976       break;
977 
978     case UCON64_FINDI:
979       ucon64_find (ucon64.fname, 0, ucon64.fsize, option_arg,
980                    strlen (option_arg), MEMCMP2_WCARD ('?') | MEMCMP2_CASE);
981       break;
982 
983     case UCON64_HFIND:
984       strcpy (buf, option_arg);
985       value = hexstring_to_ints (buf, 1);
986       if (value < 0)
987         {
988           fprintf (stderr, "ERROR: Invalid search string: %s\n", option_arg);
989           break;
990         }
991       ucon64_find (ucon64.fname, 0, ucon64.fsize, buf, value, MEMCMP2_WCARD ('?'));
992       break;
993 
994     case UCON64_HFINDR:
995       strcpy (buf, option_arg);
996       value = hexstring_to_ints (buf, 0);
997       if (value < 0)
998         {
999           fprintf (stderr, "ERROR: Invalid search string: %s\n", option_arg);
1000           break;
1001         }
1002       ucon64_find (ucon64.fname, 0, ucon64.fsize, buf, value, MEMCMP2_REL);
1003       break;
1004 
1005     case UCON64_DFIND:
1006       strcpy (buf, option_arg);
1007       value = strarg (values, buf, " ", UCON64_MAX_ARGS);
1008       for (x = 0; x < value; x++)
1009         buf[x] = values[x][0] == '?' && values[x][1] == '\0' ?
1010                    '?' : (char) strtol (values[x], NULL, 10);
1011       buf[x] = '\0';
1012       ucon64_find (ucon64.fname, 0, ucon64.fsize, buf, value, MEMCMP2_WCARD ('?'));
1013       break;
1014 
1015     case UCON64_DFINDR:
1016       strcpy (buf, option_arg);
1017       value = strarg (values, buf, " ", UCON64_MAX_ARGS);
1018       for (x = 0; x < value; x++)
1019         buf[x] = (char) strtol (values[x], NULL, 10);
1020       buf[x] = '\0';
1021       ucon64_find (ucon64.fname, 0, ucon64.fsize, buf, value, MEMCMP2_REL);
1022       break;
1023 
1024     case UCON64_HREPLACE:
1025       {
1026         size_t len = strnlen (option_arg, sizeof buf - 1);
1027         int searchlen, replacelen;
1028         char *token, *search, *replace;
1029 
1030         strncpy (buf, option_arg, len)[len] = '\0';
1031 
1032         token = strtok (buf, ":");
1033         if (!token)
1034           {
1035             fputs ("ERROR: No search string specified. Specify one before a colon\n",
1036                    stderr);
1037             break;
1038           }
1039         if ((search = strdup (token)) == NULL)
1040           {
1041             fprintf (stderr, ucon64_msg[BUFFER_ERROR], strlen (token) + 1);
1042             break;
1043           }
1044         searchlen = hexstring_to_ints (search, 1);
1045         if (searchlen < 0)
1046           {
1047             fprintf (stderr, "ERROR: S (search string) is invalid: %s\n", token);
1048             free (search);
1049             break;
1050           }
1051 
1052         token = strtok (NULL, "");
1053         if (!token)
1054           {
1055             fputs ("ERROR: No replacement string specified. Specify one after a colon\n",
1056                    stderr);
1057             free (search);
1058             break;
1059           }
1060         if ((replace = strdup (token)) == NULL)
1061           {
1062             fprintf (stderr, ucon64_msg[BUFFER_ERROR], strlen (token) + 1);
1063             free (search);
1064             break;
1065           }
1066         replacelen = hexstring_to_ints (replace, 0);
1067         if (replacelen < 0)
1068           {
1069             fprintf (stderr, "ERROR: R (replacement string) is invalid: %s\n", token);
1070             free (search);
1071             free (replace);
1072             break;
1073           }
1074 
1075         ucon64_replace (ucon64.fname, 0, ucon64.fsize, search, searchlen,
1076                         replace, replacelen, MEMCMP2_WCARD ('?'));
1077 
1078         free (search);
1079         free (replace);
1080       }
1081       break;
1082 
1083     case UCON64_PADHD:                          // deprecated
1084       value = UNKNOWN_BACKUP_HEADER_LEN;
1085     case UCON64_P:
1086     case UCON64_PAD:
1087       if (!value && ucon64.nfo)
1088         value = ucon64.nfo->backup_header_len;
1089       ucon64_file_handler (dest_name, src_name, 0);
1090 
1091       fcopy (src_name, 0, ucon64.fsize, dest_name, "wb");
1092       if (truncate2 (dest_name, ucon64.fsize +
1093                        (MBIT - ((ucon64.fsize - value) % MBIT))) == -1)
1094         {
1095           fprintf (stderr, ucon64_msg[OPEN_WRITE_ERROR], dest_name); // msg is not a typo
1096           exit (1);
1097         }
1098 
1099       printf (ucon64_msg[WROTE], dest_name);
1100       remove_temp_file ();
1101       break;
1102 
1103     case UCON64_PADN:
1104       ucon64_file_handler (dest_name, src_name, 0);
1105 
1106       fcopy (src_name, 0, ucon64.fsize, dest_name, "wb");
1107       if (truncate2 (dest_name, strtoll (option_arg, NULL, 10) +
1108                        (ucon64.nfo ? ucon64.nfo->backup_header_len : 0)) == -1)
1109         {
1110           fprintf (stderr, ucon64_msg[OPEN_WRITE_ERROR], dest_name); // msg is not a typo
1111           exit (1);
1112         }
1113 
1114       printf (ucon64_msg[WROTE], dest_name);
1115       remove_temp_file ();
1116       break;
1117 
1118     case UCON64_ISPAD:
1119       {
1120         int64_t padded = ucon64_testpad (ucon64.fname);
1121 
1122         if (padded != -1)
1123           {
1124             if (!padded)
1125               puts ("Padded: No");
1126             else
1127               printf ("Padded: Maybe, %lld Byte%s (%.4f Mb)\n",
1128                       (long long int) padded, padded != 1 ? "s" : "",
1129                       TOMBIT_F (padded));
1130           }
1131       }
1132       break;
1133 
1134     case UCON64_STRIP:
1135       ucon64_file_handler (dest_name, src_name, 0);
1136       fcopy (src_name, 0, ucon64.fsize - strtoll (option_arg, NULL, 10),
1137              dest_name, "wb");
1138       printf (ucon64_msg[WROTE], dest_name);
1139       remove_temp_file ();
1140       break;
1141 
1142     case UCON64_STP:
1143       ucon64_file_handler (dest_name, src_name, 0);
1144       fcopy (src_name, 512, ucon64.fsize, dest_name, "wb");
1145       printf (ucon64_msg[WROTE], dest_name);
1146       remove_temp_file ();
1147       break;
1148 
1149     case UCON64_STPN:
1150       ucon64_file_handler (dest_name, src_name, 0);
1151       fcopy (src_name, strtoll (option_arg, NULL, 10), ucon64.fsize,
1152              dest_name, "wb");
1153       printf (ucon64_msg[WROTE], dest_name);
1154       remove_temp_file ();
1155       break;
1156 
1157     case UCON64_INS:
1158       ucon64_file_handler (dest_name, src_name, 0);
1159       memset (buf, 0, 512);
1160       ucon64_fwrite (buf, 0, 512, dest_name, "wb");
1161       fcopy (src_name, 0, ucon64.fsize, dest_name, "ab");
1162       printf (ucon64_msg[WROTE], dest_name);
1163       remove_temp_file ();
1164       break;
1165 
1166     case UCON64_INSN:
1167       ucon64_file_handler (dest_name, src_name, 0);
1168       {
1169         FILE *file;
1170         uint64_t bytesleft = strtoll (option_arg, NULL, 10);
1171 
1172         if ((file = fopen (dest_name, "wb")) == NULL)
1173           {
1174             fprintf (stderr, ucon64_msg[OPEN_WRITE_ERROR], dest_name);
1175             break;
1176           }
1177         memset (buf, 0, (size_t) MIN (bytesleft, MAXBUFSIZE));
1178         while (bytesleft > 0)
1179           bytesleft -= fwrite (buf, 1, (size_t) MIN (bytesleft, MAXBUFSIZE), file);
1180         fclose (file);
1181       }
1182       fcopy (src_name, 0, ucon64.fsize, dest_name, "ab");
1183       printf (ucon64_msg[WROTE], dest_name);
1184       remove_temp_file ();
1185       break;
1186 
1187     case UCON64_SPLIT:
1188       ucon64_split (strtoll (option_arg, NULL, 10));
1189       break;
1190 
1191     case UCON64_A:
1192       aps_apply (ucon64.fname, ucon64.file);
1193       break;
1194 
1195     case UCON64_B:
1196       bsl_apply (ucon64.fname, ucon64.file);
1197       break;
1198 
1199     case UCON64_I:
1200       ips_apply (ucon64.fname, ucon64.file);
1201       break;
1202 
1203     case UCON64_PPF:
1204       ppf_apply (ucon64.fname, ucon64.file);
1205       break;
1206 
1207     case UCON64_MKA:
1208       aps_create (option_arg, ucon64.fname);    // original, modified
1209       break;
1210 
1211     case UCON64_MKI:
1212       ips_create (option_arg, ucon64.fname);    // original, modified
1213       break;
1214 
1215     case UCON64_MKPPF:
1216       ppf_create (option_arg, ucon64.fname);    // original, modified
1217       break;
1218 
1219     case UCON64_NA:
1220       aps_set_desc (ucon64.fname, option_arg);
1221       break;
1222 
1223     case UCON64_NPPF:
1224       ppf_set_desc (ucon64.fname, option_arg);
1225       break;
1226 
1227     case UCON64_IDPPF:
1228       ppf_set_fid (ucon64.fname, option_arg);
1229       break;
1230 
1231     case UCON64_SCAN:
1232     case UCON64_LSD:
1233       if (ucon64.dat_enabled)
1234         {
1235           if (ucon64.crc32)
1236             {
1237               fputs (ucon64.fname, stdout);
1238               if (ucon64.fname_arch[0])
1239                 printf (" (%s)\n", ucon64.fname_arch);
1240               else
1241                 fputc ('\n', stdout);
1242               // use ucon64.fcrc32 for SNES & Genesis interleaved/N64 non-interleaved
1243               printf ("Checksum (CRC32): 0x%08x\n", ucon64.fcrc32 ?
1244                         ucon64.fcrc32 : ucon64.crc32);
1245               ucon64_dat_nfo ((st_ucon64_dat_t *) ucon64.dat, 1);
1246             }
1247         }
1248       else
1249         fputs (ucon64_msg[DAT_NOT_ENABLED], stdout);
1250       break;
1251 
1252     case UCON64_LSV:
1253       if (ucon64.nfo)
1254         ucon64_nfo ();
1255       break;
1256 
1257     case UCON64_LS:
1258       ucon64.newline_before_rom = 0;
1259 
1260       if (ucon64.nfo)
1261         ptr = ucon64.nfo->name;
1262 
1263       if (ucon64.dat)
1264         {
1265           if (!ptr)
1266             ptr = ((st_ucon64_dat_t *) ucon64.dat)->name;
1267           else if (!ptr[0])
1268             ptr = ((st_ucon64_dat_t *) ucon64.dat)->name;
1269         }
1270 
1271       if (ptr && ptr[0])
1272         {
1273           struct stat fstate;
1274 
1275           if (stat (ucon64.fname, &fstate))
1276             break;
1277           strftime (buf, 13, "%b %d %Y", localtime (&fstate.st_mtime));
1278           printf ("%-31.31s %10u %s %s", tofunc (ptr, strlen (ptr), ls_toprint),
1279                   (unsigned int) ucon64.fsize, buf, basename2 (ucon64.fname));
1280           if (ucon64.fname_arch[0])
1281             printf (" (%s)\n", ucon64.fname_arch);
1282           else
1283             fputc ('\n', stdout);
1284         }
1285       break;
1286 
1287     case UCON64_RDAT:
1288       ucon64.newline_before_rom = 0;
1289       ucon64_rename (UCON64_RDAT);
1290       break;
1291 
1292     case UCON64_RROM:
1293       ucon64.newline_before_rom = 0;
1294       ucon64_rename (UCON64_RROM);
1295       break;
1296 
1297     case UCON64_R83:
1298       ucon64.newline_before_rom = 0;
1299       ucon64_rename (UCON64_R83);
1300       break;
1301 
1302     case UCON64_RJOLIET:
1303       ucon64.newline_before_rom = 0;
1304       ucon64_rename (UCON64_RJOLIET);
1305       break;
1306 
1307     case UCON64_RL:
1308       ucon64.newline_before_rom = 0;
1309       ucon64_rename (UCON64_RL);
1310       break;
1311 
1312     case UCON64_RU:
1313       ucon64.newline_before_rom = 0;
1314       ucon64_rename (UCON64_RU);
1315       break;
1316 
1317 #ifdef  USE_DISCMAGE
1318     case UCON64_BIN2ISO:
1319     case UCON64_ISOFIX:
1320     case UCON64_RIP:
1321     case UCON64_CDMAGE:
1322       if (ucon64.discmage_enabled)
1323         {
1324           uint32_t flags = 0;
1325 
1326           switch (p->option)
1327             {
1328             case UCON64_BIN2ISO:
1329               flags |= DM_2048; // DM_2048 read sectors and convert to 2048 Bytes
1330               break;
1331 
1332             case UCON64_ISOFIX:
1333               flags |= DM_FIX; // DM_FIX read sectors and fix (if needed/possible)
1334               break;
1335 
1336             case UCON64_CDMAGE:
1337 //              flags |= DM_CDMAGE;
1338               break;
1339             }
1340 
1341           ucon64.image = dm_reopen (ucon64.fname, 0, (dm_image_t *) ucon64.image);
1342           if (ucon64.image)
1343             {
1344               int track = strtol (option_arg, NULL, 10);
1345               if (track < 1)
1346                 track = 1;
1347               track--; // decrement for dm_rip()
1348 
1349               printf ("Writing track: %d\n\n", track + 1);
1350 
1351               dm_set_gauge (&discmage_gauge);
1352               dm_rip ((dm_image_t *) ucon64.image, track, flags);
1353               fputc ('\n', stdout);
1354             }
1355         }
1356       else
1357         printf (ucon64_msg[NO_LIB], ucon64.discmage_path);
1358       break;
1359 
1360     case UCON64_MKTOC:
1361     case UCON64_MKCUE:
1362     case UCON64_MKSHEET:
1363       if (ucon64.discmage_enabled && ucon64.image)
1364         {
1365           char fname[FILENAME_MAX];
1366           strcpy (fname, ((dm_image_t *) ucon64.image)->fname);
1367 
1368           if (p->option == UCON64_MKTOC || p->option == UCON64_MKSHEET)
1369             {
1370               set_suffix (fname, ".toc");
1371               ucon64_file_handler (fname, NULL, 0);
1372 
1373               if (!dm_toc_write ((dm_image_t *) ucon64.image))
1374                 printf (ucon64_msg[WROTE], basename2 (fname));
1375               else
1376                 fputs ("ERROR: Could not generate toc sheet\n", stderr);
1377             }
1378 
1379           if (p->option == UCON64_MKCUE || p->option == UCON64_MKSHEET)
1380             {
1381               set_suffix (fname, ".cue");
1382               ucon64_file_handler (fname, NULL, 0);
1383 
1384               if (!dm_cue_write ((dm_image_t *) ucon64.image))
1385                 printf (ucon64_msg[WROTE], basename2 (fname));
1386               else
1387                 fputs ("ERROR: Could not generate cue sheet\n", stderr);
1388             }
1389         }
1390       else
1391         printf (ucon64_msg[NO_LIB], ucon64.discmage_path);
1392       break;
1393 
1394     case UCON64_XCDRW:
1395       if (ucon64.discmage_enabled)
1396         {
1397 //          dm_set_gauge (&discmage_gauge);
1398           if (!access (ucon64.fname, F_OK))
1399             dm_disc_write ((dm_image_t *) ucon64.image);
1400           else
1401             dm_disc_read ((dm_image_t *) ucon64.image);
1402         }
1403       else
1404         printf (ucon64_msg[NO_LIB], ucon64.discmage_path);
1405       break;
1406 #endif // USE_DISCMAGE
1407 
1408     case UCON64_DB:
1409       if (ucon64.quiet > -1)
1410         {
1411           if (ucon64.dat_enabled)
1412             {
1413               ucon64_dat_view (ucon64.console, 0);
1414               printf ("TIP: %s " OPTION_LONG_S "db " OPTION_LONG_S "nes"
1415                       " would show only information about known NES ROMs\n",
1416                       basename2 (ucon64.argv[0]));
1417             }
1418           else
1419             fputs (ucon64_msg[DAT_NOT_ENABLED], stdout);
1420           break;
1421         }
1422 
1423     case UCON64_DBV:
1424       if (ucon64.dat_enabled)
1425         {
1426           ucon64_dat_view (ucon64.console, 1);
1427           printf ("TIP: %s " OPTION_LONG_S "dbv " OPTION_LONG_S "nes"
1428                   " would show only information about known NES ROMs\n",
1429                   basename2 (ucon64.argv[0]));
1430         }
1431       else
1432         fputs (ucon64_msg[DAT_NOT_ENABLED], stdout);
1433       break;
1434 
1435     case UCON64_DBS:
1436       if (ucon64.dat_enabled)
1437         {
1438           ucon64.crc32 = 0;
1439           sscanf (option_arg, "%x", &ucon64.crc32);
1440 
1441           if ((ucon64.dat = ucon64_dat_search (ucon64.crc32)) == NULL)
1442             {
1443               printf (ucon64_msg[DAT_NOT_FOUND], ucon64.crc32);
1444               printf ("TIP: Be sure to install the right DAT files in %s\n",
1445                       ucon64.datdir);
1446             }
1447           else
1448             {
1449               ucon64_dat_nfo ((st_ucon64_dat_t *) ucon64.dat, 1);
1450               printf ("\n"
1451                       "TIP: %s " OPTION_LONG_S "dbs" OPTARG_S "0x%08x " OPTION_LONG_S
1452                       "nes would search only for a NES ROM\n",
1453                       basename2 (ucon64.argv[0]), ucon64.crc32);
1454             }
1455         }
1456       else
1457         fputs (ucon64_msg[DAT_NOT_ENABLED], stdout);
1458       break;
1459 
1460     case UCON64_MKDAT:
1461       ucon64.newline_before_rom = 0;
1462       ucon64_create_dat (option_arg, ucon64.fname,
1463                          ucon64.nfo ? ucon64.nfo->backup_header_len : 0);
1464       break;
1465 
1466     case UCON64_MULTI:
1467       switch (ucon64.console)
1468         {
1469         case UCON64_GBA:
1470           gba_multi (strtol (option_arg, NULL, 10) * MBIT, NULL);
1471           break;
1472         case UCON64_GEN:
1473           genesis_multi (strtol (option_arg, NULL, 10) * MBIT);
1474           break;
1475         case UCON64_PCE:
1476           pce_multi (strtol (option_arg, NULL, 10) * MBIT);
1477           break;
1478         case UCON64_SMS:                        // Sega Master System *and* Game Gear
1479           sms_multi (strtol (option_arg, NULL, 10) * MBIT);
1480           break;
1481         case UCON64_SNES:
1482           snes_multi (strtol (option_arg, NULL, 10) * MBIT);
1483           break;
1484         default:
1485           return -1;
1486         }
1487       break;
1488 
1489     case UCON64_E:
1490       ucon64_e ();
1491       break;
1492 
1493     case UCON64_1991:
1494       genesis_1991 (ucon64.nfo);
1495       break;
1496 
1497     case UCON64_B0:
1498       lynx_b0 (ucon64.nfo, option_arg);
1499       break;
1500 
1501     case UCON64_B1:
1502       lynx_b1 (ucon64.nfo, option_arg);
1503       break;
1504 
1505     case UCON64_BIN:
1506       genesis_bin (ucon64.nfo);
1507       break;
1508 
1509     case UCON64_BIOS:
1510       neogeo_bios (option_arg);
1511       break;
1512 
1513     case UCON64_BOT:
1514       n64_bot (ucon64.nfo, option_arg);
1515       break;
1516 
1517     case UCON64_CHK:
1518       switch (ucon64.console)
1519         {
1520         case UCON64_GB:
1521           gb_chk (ucon64.nfo);
1522           break;
1523         case UCON64_GBA:
1524           gba_chk (ucon64.nfo);
1525           break;
1526         case UCON64_GEN:
1527           genesis_chk (ucon64.nfo);
1528           break;
1529         case UCON64_N64:
1530           n64_chk (ucon64.nfo);
1531           break;
1532         case UCON64_SMS:
1533           sms_chk (ucon64.nfo);
1534           break;
1535         case UCON64_SNES:
1536           snes_chk (ucon64.nfo);
1537           break;
1538         case UCON64_SWAN:
1539           swan_chk (ucon64.nfo);
1540           break;
1541         case UCON64_NDS:
1542           nds_chk (ucon64.nfo);
1543           break;
1544         default:
1545 // the next msg has already been printed
1546 //          fputs (ucon64_msg[CONSOLE_ERROR], stderr);
1547           return -1;
1548         }
1549       break;
1550 
1551     case UCON64_COL:
1552       snes_col (option_arg);
1553       break;
1554 
1555     case UCON64_CRP:
1556       gba_crp (ucon64.nfo, option_arg);
1557       break;
1558 
1559     case UCON64_DBUH:
1560       snes_backup_header_info (ucon64.nfo);
1561       break;
1562 
1563     case UCON64_SWAP:
1564     case UCON64_DINT:
1565       switch (ucon64.console)
1566         {
1567         case UCON64_NES:
1568           nes_dint ();
1569           break;
1570         case UCON64_PCE:
1571           pce_swap (ucon64.nfo);
1572           break;
1573         case UCON64_SNES:
1574           snes_dint (ucon64.nfo);
1575           break;
1576         default:                                // Nintendo 64
1577           puts ("Converting file...");
1578           ucon64_file_handler (dest_name, NULL, 0);
1579           fcopy (src_name, 0, ucon64.fsize, dest_name, "wb");
1580           ucon64_fbswap16 (dest_name, 0, ucon64.fsize);
1581           printf (ucon64_msg[WROTE], dest_name);
1582           break;
1583         }
1584       break;
1585 
1586     case UCON64_SWAP2:
1587       // --swap2 is currently used only for Nintendo 64
1588       puts ("Converting file...");
1589       ucon64_file_handler (dest_name, NULL, 0);
1590       fcopy (src_name, 0, ucon64.fsize, dest_name, "wb");
1591       ucon64_fwswap32 (dest_name, 0, ucon64.fsize);
1592       printf (ucon64_msg[WROTE], dest_name);
1593       break;
1594 
1595     case UCON64_DMIRR:
1596       snes_demirror (ucon64.nfo);
1597       break;
1598 
1599     case UCON64_DNSRT:
1600       snes_densrt (ucon64.nfo);
1601       break;
1602 
1603     case UCON64_F:
1604       switch (ucon64.console)
1605         {
1606         case UCON64_GEN:
1607           genesis_f (ucon64.nfo);
1608           break;
1609         case UCON64_N64:
1610           n64_f (ucon64.nfo);
1611           break;
1612         case UCON64_PCE:
1613           pce_f (ucon64.nfo);
1614           break;
1615         case UCON64_SNES:
1616           snes_f (ucon64.nfo);
1617           break;
1618         default:
1619 // the next msg has already been printed
1620 //          fputs (ucon64_msg[CONSOLE_ERROR], stderr);
1621           return -1;
1622         }
1623       break;
1624 
1625     case UCON64_FDS:
1626       nes_fds ();
1627       break;
1628 
1629     case UCON64_FDSL:
1630       nes_fdsl (ucon64.nfo, NULL);
1631       break;
1632 
1633     case UCON64_FFE:
1634       nes_ffe (ucon64.nfo);
1635       break;
1636 
1637     case UCON64_FIG:
1638       snes_fig (ucon64.nfo);
1639       break;
1640 
1641     case UCON64_FIGS:
1642       snes_figs (ucon64.nfo);
1643       break;
1644 
1645     case UCON64_GBX:
1646       gb_gbx (ucon64.nfo);
1647       break;
1648 
1649     case UCON64_GD3:
1650       snes_gd3 (ucon64.nfo);
1651       break;
1652 
1653     case UCON64_GD3S:
1654       snes_gd3s (ucon64.nfo);
1655       break;
1656 
1657     case UCON64_GG:
1658       switch (ucon64.console)
1659         {
1660         case UCON64_GB:
1661         case UCON64_GEN:
1662         case UCON64_NES:
1663         case UCON64_SMS:
1664         case UCON64_SNES:
1665           // ROM images for SNES (GD3) and Genesis (SMD) can be interleaved
1666           if (ucon64.nfo->interleaved)
1667             fputs ("ERROR: This ROM seems to be interleaved, but uCON64 will only apply a Game\n"
1668                    "       Genie patch to non-interleaved ROMs. Convert to a non-interleaved\n"
1669                    "       format\n", stderr);
1670           else if (ucon64.console == UCON64_NES &&
1671                    nes_get_file_type () != INES && nes_get_file_type () != FFE)
1672             fputs ("ERROR: This NES ROM is in a format that uCON64 cannot apply a Game Genie patch\n"
1673                    "       to. Convert to iNES\n", stderr);
1674           else
1675             gg_apply (ucon64.nfo, option_arg);
1676           break;
1677         default:
1678           fputs ("ERROR: Cannot apply Game Genie code for this ROM/console\n", stderr);
1679 // the next msg has already been printed
1680 //          fputs (ucon64_msg[CONSOLE_ERROR], stderr);
1681           return -1;
1682         }
1683       break;
1684 
1685     case UCON64_GGD:
1686       gg_display (ucon64.nfo, option_arg);
1687       break;
1688 
1689     case UCON64_GGE:
1690       gg_display (ucon64.nfo, option_arg);
1691       break;
1692 
1693     case UCON64_GP2BMP:
1694       gb_gp2bmp ();
1695       break;
1696 
1697     case UCON64_IC2:
1698       snes_ic2 (ucon64.nfo);
1699       break;
1700 
1701     case UCON64_INES:
1702       nes_ines ();
1703       break;
1704 
1705     case UCON64_INESHD:
1706       nes_ineshd (ucon64.nfo);
1707       break;
1708 
1709     case UCON64_PARSE:
1710       dc_parse (option_arg);
1711       break;
1712 
1713     case UCON64_MKIP:
1714       dc_mkip ();
1715       break;
1716 
1717     case UCON64_J:
1718       switch (ucon64.console)
1719         {
1720         case UCON64_GEN:
1721           genesis_j (ucon64.nfo);
1722           break;
1723         case UCON64_NES:
1724           nes_j (NULL);
1725           break;
1726         case UCON64_SNES:
1727           snes_j (ucon64.nfo);
1728           break;
1729         default:
1730 // the next msg has already been printed
1731 //          fputs (ucon64_msg[CONSOLE_ERROR], stderr);
1732           return -1;
1733         }
1734       break;
1735 
1736     case UCON64_K:
1737       snes_k (ucon64.nfo);
1738       break;
1739 
1740     case UCON64_L:
1741       snes_l (ucon64.nfo);
1742       break;
1743 
1744     case UCON64_LNX:
1745       lynx_lnx (ucon64.nfo);
1746       break;
1747 
1748     case UCON64_LOGO:
1749       switch (ucon64.console)
1750         {
1751         case UCON64_GB:
1752           gb_logo (ucon64.nfo);
1753           break;
1754         case UCON64_GBA:
1755           gba_logo (ucon64.nfo);
1756           break;
1757         case UCON64_NDS:
1758           nds_logo (ucon64.nfo);
1759           break;
1760         default:
1761 // the next msg has already been printed
1762 //          fputs (ucon64_msg[CONSOLE_ERROR], stderr);
1763           return -1;
1764         }
1765       break;
1766 
1767     case UCON64_LSRAM:
1768       n64_sram (ucon64.nfo, option_arg);
1769       break;
1770 
1771     case UCON64_LYX:
1772       lynx_lyx (ucon64.nfo);
1773       break;
1774 
1775     case UCON64_MGD:
1776       switch (ucon64.console)
1777         {
1778         case UCON64_GB:
1779           gb_mgd (ucon64.nfo);
1780           break;
1781         case UCON64_GEN:
1782           genesis_mgd (ucon64.nfo);
1783           break;
1784         case UCON64_NG:
1785           neogeo_mgd ();
1786           break;
1787         case UCON64_PCE:
1788           pce_mgd (ucon64.nfo);
1789           break;
1790         case UCON64_SMS:
1791           sms_mgd (ucon64.nfo, UCON64_SMS);
1792           break;
1793         case UCON64_SNES:
1794           snes_mgd (ucon64.nfo);
1795           break;
1796         default:
1797 // the next msg has already been printed
1798 //          fputs (ucon64_msg[CONSOLE_ERROR], stderr);
1799           return -1;
1800         }
1801       break;
1802 
1803     case UCON64_MGDGG:
1804       sms_mgd (ucon64.nfo, UCON64_GAMEGEAR);
1805       break;
1806 
1807     case UCON64_MGH:
1808       switch (ucon64.console)
1809         {
1810         case UCON64_GEN:
1811           genesis_mgh (ucon64.nfo);
1812           break;
1813         case UCON64_SNES:
1814           snes_mgh (ucon64.nfo);
1815           break;
1816         default:
1817 // the next msg has already been printed
1818 //          fputs (ucon64_msg[CONSOLE_ERROR], stderr);
1819           return -1;
1820         }
1821       break;
1822 
1823     case UCON64_MKSRM:
1824       snes_create_sram ();
1825       break;
1826 
1827     case UCON64_MSG:
1828       pce_msg (ucon64.nfo);
1829       break;
1830 
1831     case UCON64_N:
1832       switch (ucon64.console)
1833         {
1834         case UCON64_GB:
1835           gb_n (ucon64.nfo, option_arg);
1836           break;
1837         case UCON64_GBA:
1838           gba_n (ucon64.nfo, option_arg);
1839           break;
1840         case UCON64_GEN:
1841           genesis_n (ucon64.nfo, option_arg);
1842           break;
1843         case UCON64_LYNX:
1844           lynx_n (ucon64.nfo, option_arg);
1845           break;
1846         case UCON64_N64:
1847           n64_n (ucon64.nfo, option_arg);
1848           break;
1849         case UCON64_NES:
1850           nes_n (option_arg);
1851           break;
1852         case UCON64_SNES:
1853           snes_n (ucon64.nfo, option_arg);
1854           break;
1855         case UCON64_NDS:
1856           nds_n (ucon64.nfo, option_arg);
1857           break;
1858         default:
1859 // the next msg has already been printed
1860 //          fputs (ucon64_msg[CONSOLE_ERROR], stderr);
1861           return -1;
1862         }
1863       break;
1864 
1865     case UCON64_N2:
1866       genesis_n2 (ucon64.nfo, option_arg);
1867       break;
1868 
1869     case UCON64_N2GB:
1870       gb_n2gb (ucon64.nfo, option_arg);
1871       break;
1872 
1873     case UCON64_NROT:
1874       lynx_nrot (ucon64.nfo);
1875       break;
1876 
1877     case UCON64_PASOFAMI:
1878       nes_pasofami ();
1879       break;
1880 
1881     case UCON64_PATTERN:
1882       ucon64_pattern (option_arg);
1883       break;
1884 
1885     case UCON64_POKE:
1886       {
1887         size_t len = strnlen (option_arg, sizeof buf - 1);
1888         char *token;
1889         uint64_t offset;
1890 
1891         strncpy (buf, option_arg, len)[len] = '\0';
1892 
1893         token = strtok (buf, ":");
1894         if (!token)
1895           {
1896             fputs ("ERROR: No offset specified. Specify one before a colon\n", stderr);
1897             break;
1898           }
1899         if (strtoint (token, 16, &offset, sizeof offset))
1900           {
1901             fprintf (stderr, "ERROR: Invalid offset: %s\n", token);
1902             break;
1903           }
1904 
1905         token = strtok (NULL, "");
1906         if (!token)
1907           {
1908             fputs ("ERROR: No value specified. Specify one after a colon\n", stderr);
1909             break;
1910           }
1911         if (strtoint (token, 16, &value, sizeof value) ||
1912             (unsigned int) value > 255)
1913           {
1914             fprintf (stderr, "ERROR: Invalid value: %s\n", token);
1915             break;
1916           }
1917 
1918         if (offset >= ucon64.fsize)
1919           {
1920             fprintf (stderr, "ERROR: Offset 0x%016llx is too large for file size\n",
1921                      (long long unsigned int) offset);
1922             break;
1923           }
1924 
1925         ucon64_file_handler (dest_name, src_name, 0);
1926         fcopy (src_name, 0, ucon64.fsize, dest_name, "wb");
1927 
1928         fputc ('\n', stdout);
1929         buf[0] = (char) ucon64_fgetc (dest_name, offset);
1930         dumper (stdout, buf, 1, offset, DUMPER_HEX);
1931 
1932         ucon64_fputc (dest_name, offset, value, "r+b");
1933 
1934         buf[0] = (char) value;
1935         dumper (stdout, buf, 1, offset, DUMPER_HEX);
1936         fputc ('\n', stdout);
1937 
1938         printf (ucon64_msg[WROTE], dest_name);
1939         remove_temp_file ();
1940       }
1941       break;
1942 
1943     case UCON64_ROTL:
1944       lynx_rotl (ucon64.nfo);
1945       break;
1946 
1947     case UCON64_ROTR:
1948       lynx_rotr (ucon64.nfo);
1949       break;
1950 
1951     case UCON64_S:
1952       switch (ucon64.console)
1953         {
1954         case UCON64_GEN:
1955           genesis_s (ucon64.nfo);
1956           break;
1957         case UCON64_NES:
1958           nes_s ();
1959           break;
1960         case UCON64_NG:
1961           neogeo_s ();
1962           break;
1963         case UCON64_SNES:
1964           snes_s (ucon64.nfo);
1965           break;
1966         default:
1967 // the next msg has already been printed
1968 //          fputs (ucon64_msg[CONSOLE_ERROR], stderr);
1969           return -1;
1970         }
1971       break;
1972 
1973     case UCON64_SAM:
1974       neogeo_sam (option_arg);
1975       break;
1976 
1977     case UCON64_SCR:
1978       dc_scramble ();
1979       break;
1980 
1981     case UCON64_SGB:
1982       gb_sgb (ucon64.nfo);
1983       break;
1984 
1985     case UCON64_SMC:
1986       snes_smc (ucon64.nfo);
1987       break;
1988 
1989     case UCON64_SMD:
1990       switch (ucon64.console)
1991         {
1992         case UCON64_GEN:
1993           genesis_smd (ucon64.nfo);
1994           break;
1995         case UCON64_SMS:
1996           sms_smd (ucon64.nfo);
1997           break;
1998         default:
1999           return -1;
2000         }
2001       break;
2002 
2003     case UCON64_SMDS:
2004       switch (ucon64.console)
2005         {
2006         case UCON64_GEN:
2007           genesis_smds ();
2008           break;
2009         case UCON64_SMS:
2010           sms_smds ();
2011           break;
2012         default:
2013           return -1;
2014         }
2015       break;
2016 
2017     case UCON64_SMGH:
2018       switch (ucon64.console)
2019         {
2020         case UCON64_GEN:
2021           genesis_smgh (ucon64.nfo);
2022           break;
2023         case UCON64_SNES:
2024           snes_smgh (ucon64.nfo);
2025           break;
2026         default:
2027 // the next msg has already been printed
2028 //          fputs (ucon64_msg[CONSOLE_ERROR], stderr);
2029           return -1;
2030         }
2031       break;
2032 
2033     case UCON64_SMINI2SRM:
2034       snes_smini2srm ();
2035       break;
2036 
2037 #ifdef  USE_ZLIB
2038     case UCON64_SMINIS:
2039       snes_sminis (ucon64.nfo, option_arg);
2040       break;
2041 #endif
2042 
2043     case UCON64_SRAM:
2044       gba_sram ();
2045       break;
2046 
2047     case UCON64_SC:
2048       gba_sc ();
2049       break;
2050 
2051     case UCON64_SSC:
2052       gb_ssc (ucon64.nfo);
2053       break;
2054 
2055     case UCON64_SWC:
2056       snes_swc (ucon64.nfo);
2057       break;
2058 
2059     case UCON64_SWCS:
2060       snes_swcs (ucon64.nfo);
2061       break;
2062 
2063     case UCON64_UFO:
2064       snes_ufo (ucon64.nfo);
2065       break;
2066 
2067     case UCON64_UFOS:
2068       snes_ufos (ucon64.nfo);
2069       break;
2070 
2071     case UCON64_UFOSD:
2072       snes_ufosd (ucon64.nfo);
2073       break;
2074 
2075     case UCON64_UFOSDS:
2076       snes_ufosds (ucon64.nfo);
2077       break;
2078 
2079     case UCON64_UNIF:
2080       nes_unif ();
2081       break;
2082 
2083     case UCON64_UNSCR:
2084       dc_unscramble ();
2085       break;
2086 
2087     case UCON64_USMS:
2088       n64_usms (ucon64.nfo, option_arg);
2089       break;
2090 
2091     case UCON64_V64:
2092       n64_v64 (ucon64.nfo);
2093       break;
2094 
2095     /*
2096       It doesn't make sense to continue after executing a (send) backup option
2097       ("multizip"). Don't return, but use break instead. ucon64_execute_options()
2098       checks if an option was used that should stop uCON64.
2099     */
2100 #ifdef  USE_LIBCD64
2101     case UCON64_XCD64:
2102       if (access (ucon64.fname, F_OK) != 0)
2103         cd64_read_rom (ucon64.fname, 64);
2104       else
2105         cd64_write_rom (ucon64.fname);
2106       fputc ('\n', stdout);
2107       break;
2108 
2109     case UCON64_XCD64C:
2110       if (!access (ucon64.fname, F_OK) && ucon64.backup)
2111         printf ("Wrote backup to %s\n", mkbak (ucon64.fname, BAK_MOVE));
2112       cd64_read_rom (ucon64.fname, strtol (option_arg, NULL, 10));
2113       fputc ('\n', stdout);
2114       break;
2115 
2116     case UCON64_XCD64B:
2117       cd64_write_bootemu (ucon64.fname);
2118       fputc ('\n', stdout);
2119       break;
2120 
2121     case UCON64_XCD64S:
2122       if (access (ucon64.fname, F_OK) != 0)
2123         cd64_read_sram (ucon64.fname);
2124       else
2125         cd64_write_sram (ucon64.fname);
2126       fputc ('\n', stdout);
2127       break;
2128 
2129     case UCON64_XCD64F:
2130       if (access (ucon64.fname, F_OK) != 0)
2131         cd64_read_flashram (ucon64.fname);
2132       else
2133         cd64_write_flashram (ucon64.fname);
2134       fputc ('\n', stdout);
2135       break;
2136 
2137     case UCON64_XCD64E:
2138       if (access (ucon64.fname, F_OK) != 0)
2139         cd64_read_eeprom (ucon64.fname);
2140       else
2141         cd64_write_eeprom (ucon64.fname);
2142       fputc ('\n', stdout);
2143       break;
2144 
2145     case UCON64_XCD64M:
2146       if (access (ucon64.fname, F_OK) != 0)
2147         cd64_read_mempack (ucon64.fname, strtol (option_arg, NULL, 10));
2148       else
2149         cd64_write_mempack (ucon64.fname, strtol (option_arg, NULL, 10));
2150       fputc ('\n', stdout);
2151       break;
2152 #endif // USE_LIBCD64
2153 
2154 #ifdef  USE_PARALLEL
2155     case UCON64_XRESET:
2156       parport_print_info ();
2157       fputs ("Resetting parallel port...", stdout);
2158       outportb (ucon64.parport + PARPORT_DATA, 0);
2159       // Strobe, Auto Linefeed and Select Printer are hardware inverted, so we
2160       //  have to write a 1 to bring the associated pins in a low state (0V).
2161       outportb (ucon64.parport + PARPORT_CONTROL,
2162                 (inportb (ucon64.parport + PARPORT_CONTROL) & 0xf0) | 0x0b);
2163       puts ("done");
2164       break;
2165 
2166     case UCON64_XCMC:
2167       if (!access (ucon64.fname, F_OK) && ucon64.backup)
2168         printf ("Wrote backup to %s\n", mkbak (ucon64.fname, BAK_MOVE));
2169       cmc_read_rom (ucon64.fname, ucon64.parport, ucon64.io_mode); // ucon64.io_mode contains speed value
2170       fputc ('\n', stdout);
2171       break;
2172 
2173     case UCON64_XCMCT:
2174       cmc_test (strtol (option_arg, NULL, 10), ucon64.parport, ucon64.io_mode);
2175       fputc ('\n', stdout);
2176       break;
2177 
2178     case UCON64_XDJR:
2179       if (access (ucon64.fname, F_OK) != 0)
2180         {
2181           doctor64jr_read (ucon64.fname, ucon64.parport);
2182           fputc ('\n', stdout);
2183         }
2184       else
2185         {
2186           if (!ucon64.nfo->interleaved)
2187             fputs ("ERROR: This ROM does not seem to be interleaved, but the Doctor V64 Junior only\n"
2188                    "       supports interleaved ROMs. Convert to a Doctor V64 compatible format\n",
2189                    stderr);
2190           else
2191             {
2192               doctor64jr_write (ucon64.fname, ucon64.parport);
2193               fputc ('\n', stdout);
2194             }
2195         }
2196       break;
2197 
2198     case UCON64_XFAL:
2199       if (access (ucon64.fname, F_OK) != 0)
2200         fal_read_rom (ucon64.fname, ucon64.parport, 32);
2201       else
2202         fal_write_rom (ucon64.fname, ucon64.parport);
2203       fputc ('\n', stdout);
2204       break;
2205 
2206     case UCON64_XFALMULTI:
2207       tmpnam2 (src_name, NULL);
2208       ucon64.temp_file = src_name;
2209       register_func (remove_temp_file);
2210       // gba_multi() calls ucon64_file_handler() so the directory part will be
2211       //  stripped from src_name. The directory should be used though.
2212       if (!ucon64.output_path[0])
2213         {
2214           dirname2 (src_name, ucon64.output_path);
2215           if (ucon64.output_path[strlen (ucon64.output_path) - 1] != DIR_SEPARATOR)
2216             strcat (ucon64.output_path, DIR_SEPARATOR_S);
2217         }
2218       if (gba_multi (strtol (option_arg, NULL, 10) * MBIT, src_name) == 0)
2219         { // don't try to start a transfer if there was a problem
2220           fputc ('\n', stdout);
2221           ucon64.fsize = fsizeof (src_name);
2222           fal_write_rom (src_name, ucon64.parport);
2223         }
2224 
2225       unregister_func (remove_temp_file);
2226       remove_temp_file ();
2227       fputc ('\n', stdout);
2228       break;
2229 
2230     case UCON64_XFALC:
2231       if (!access (ucon64.fname, F_OK) && ucon64.backup)
2232         printf ("Wrote backup to %s\n", mkbak (ucon64.fname, BAK_MOVE));
2233       fal_read_rom (ucon64.fname, ucon64.parport,
2234                     strtol (option_arg, NULL, 10));
2235       fputc ('\n', stdout);
2236       break;
2237 
2238     case UCON64_XFALS:
2239       if (access (ucon64.fname, F_OK) != 0)
2240         fal_read_sram (ucon64.fname, ucon64.parport, UCON64_UNKNOWN);
2241       else
2242         fal_write_sram (ucon64.fname, ucon64.parport, UCON64_UNKNOWN);
2243       fputc ('\n', stdout);
2244       break;
2245 
2246     case UCON64_XFALB:
2247       if (access (ucon64.fname, F_OK) != 0)
2248         fal_read_sram (ucon64.fname, ucon64.parport,
2249                        strtol (option_arg, NULL, 10));
2250       else
2251         fal_write_sram (ucon64.fname, ucon64.parport,
2252                         strtol (option_arg, NULL, 10));
2253       fputc ('\n', stdout);
2254       break;
2255 
2256     case UCON64_XFIG:
2257       if (access (ucon64.fname, F_OK) != 0)       // file does not exist => dump cartridge
2258         {
2259           fig_read_rom (ucon64.fname, ucon64.parport);
2260           fputc ('\n', stdout);
2261         }
2262       else
2263         {
2264           if (!ucon64.nfo->backup_header_len)
2265             fputs ("ERROR: This ROM has no header. Convert to a FIG compatible format\n",
2266                    stderr);
2267           else if (ucon64.nfo->interleaved)
2268             fputs ("ERROR: This ROM seems to be interleaved, but the FIG does not support\n"
2269                    "       interleaved ROMs. Convert to a FIG compatible format\n",
2270                    stderr);
2271           else // file exists => send it to the copier
2272             {
2273               fig_write_rom (ucon64.fname, ucon64.parport);
2274               fputc ('\n', stdout);
2275             }
2276         }
2277       break;
2278 
2279     case UCON64_XFIGS:
2280       if (access (ucon64.fname, F_OK) != 0)     // file does not exist => dump SRAM contents
2281         fig_read_sram (ucon64.fname, ucon64.parport);
2282       else                                      // file exists => restore SRAM
2283         fig_write_sram (ucon64.fname, ucon64.parport);
2284       fputc ('\n', stdout);
2285       break;
2286 
2287     case UCON64_XFIGC:
2288       if (access (ucon64.fname, F_OK) != 0)     // file does not exist => dump cart SRAM contents
2289         fig_read_cart_sram (ucon64.fname, ucon64.parport);
2290       else                                      // file exists => restore SRAM
2291         fig_write_cart_sram (ucon64.fname, ucon64.parport);
2292       fputc ('\n', stdout);
2293       break;
2294 
2295     case UCON64_XGBX:
2296       if (access (ucon64.fname, F_OK) != 0)     // file does not exist => dump cartridge/flash card
2297         gbx_read_rom (ucon64.fname, ucon64.parport);
2298       else                                      // file exists => send it to the programmer
2299         gbx_write_rom (ucon64.fname, ucon64.parport);
2300       fputc ('\n', stdout);
2301       break;
2302 
2303     case UCON64_XGBXS:
2304       if (access (ucon64.fname, F_OK) != 0)
2305         gbx_read_sram (ucon64.fname, ucon64.parport, -1);
2306       else
2307         gbx_write_sram (ucon64.fname, ucon64.parport, -1);
2308       fputc ('\n', stdout);
2309       break;
2310 
2311     case UCON64_XGBXB:
2312       if (access (ucon64.fname, F_OK) != 0)
2313         gbx_read_sram (ucon64.fname, ucon64.parport,
2314                        strtol (option_arg, NULL, 10));
2315       else
2316         gbx_write_sram (ucon64.fname, ucon64.parport,
2317                         strtol (option_arg, NULL, 10));
2318       fputc ('\n', stdout);
2319       break;
2320 
2321     case UCON64_XGD3:
2322       if (access (ucon64.fname, F_OK) != 0)     // file does not exist => dump cartridge
2323         {
2324           gd3_read_rom (ucon64.fname, ucon64.parport); // dumping is not yet supported
2325           fputc ('\n', stdout);
2326         }
2327       else
2328         {
2329           if (!ucon64.nfo->backup_header_len)
2330             fputs ("ERROR: This ROM has no header. Convert to a Game Doctor compatible format\n",
2331                    stderr);
2332           else                                  // file exists => send it to the copier
2333             {
2334               gd3_write_rom (ucon64.fname, ucon64.parport, ucon64.nfo);
2335               fputc ('\n', stdout);
2336             }
2337         }
2338       break;
2339 
2340     case UCON64_XGD3S:
2341       if (access (ucon64.fname, F_OK) != 0)     // file does not exist => dump SRAM contents
2342         gd3_read_sram (ucon64.fname, ucon64.parport); // dumping is not yet supported
2343       else                                      // file exists => restore SRAM
2344         gd3_write_sram (ucon64.fname, ucon64.parport);
2345       fputc ('\n', stdout);
2346       break;
2347 
2348     case UCON64_XGD3R:
2349       if (access (ucon64.fname, F_OK) != 0)
2350         gd3_read_saver (ucon64.fname, ucon64.parport);
2351       else
2352         gd3_write_saver (ucon64.fname, ucon64.parport);
2353       fputc ('\n', stdout);
2354       break;
2355 
2356     case UCON64_XGD6:
2357       if (access (ucon64.fname, F_OK) != 0)
2358         {
2359           gd6_read_rom (ucon64.fname, ucon64.parport);
2360           fputc ('\n', stdout);
2361         }
2362       else
2363         {
2364           if (!ucon64.nfo->backup_header_len)
2365             fputs ("ERROR: This ROM has no header. Convert to a Game Doctor compatible format\n",
2366                    stderr);
2367           else
2368             {
2369               gd6_write_rom (ucon64.fname, ucon64.parport, ucon64.nfo);
2370               fputc ('\n', stdout);
2371             }
2372         }
2373       break;
2374 
2375     case UCON64_XGD6S:
2376       if (access (ucon64.fname, F_OK) != 0)
2377         gd6_read_sram (ucon64.fname, ucon64.parport);
2378       else
2379         gd6_write_sram (ucon64.fname, ucon64.parport);
2380       fputc ('\n', stdout);
2381       break;
2382 
2383     case UCON64_XGD6R:
2384       if (access (ucon64.fname, F_OK) != 0)
2385         gd6_read_saver (ucon64.fname, ucon64.parport);
2386       else
2387         gd6_write_saver (ucon64.fname, ucon64.parport);
2388       fputc ('\n', stdout);
2389       break;
2390 
2391     case UCON64_XGG:
2392       if (access (ucon64.fname, F_OK) != 0)
2393         {
2394           smsgg_read_rom (ucon64.fname, ucon64.parport, 32 * MBIT);
2395           fputc ('\n', stdout);
2396         }
2397       else
2398         {
2399           if (ucon64.nfo->backup_header_len)
2400             fputs ("ERROR: This ROM has a header. Remove it with " OPTION_LONG_S "stp or " OPTION_LONG_S "mgd\n",
2401                    stderr);
2402           else if (ucon64.nfo->interleaved)
2403             fputs ("ERROR: This ROM seems to be interleaved, but uCON64 does not support\n"
2404                    "       sending interleaved ROMs to the SMS-PRO/GG-PRO. Convert ROM with " OPTION_LONG_S "mgd\n",
2405                    stderr);
2406           else
2407             {
2408               smsgg_write_rom (ucon64.fname, ucon64.parport);
2409               fputc ('\n', stdout);
2410             }
2411         }
2412       break;
2413 
2414     case UCON64_XGGS:
2415       if (access (ucon64.fname, F_OK) != 0)
2416         smsgg_read_sram (ucon64.fname, ucon64.parport, -1);
2417       else
2418         smsgg_write_sram (ucon64.fname, ucon64.parport, -1);
2419       fputc ('\n', stdout);
2420       break;
2421 
2422     case UCON64_XGGB:
2423       if (access (ucon64.fname, F_OK) != 0)
2424         smsgg_read_sram (ucon64.fname, ucon64.parport,
2425                          strtol (option_arg, NULL, 10));
2426       else
2427         smsgg_write_sram (ucon64.fname, ucon64.parport,
2428                           strtol (option_arg, NULL, 10));
2429       fputc ('\n', stdout);
2430       break;
2431 
2432     case UCON64_XIC2:
2433       smcic2_write_rom (ucon64.fname, ucon64.parport);
2434       fputc ('\n', stdout);
2435       break;
2436 
2437     case UCON64_XLIT:
2438       if (!access (ucon64.fname, F_OK) && ucon64.backup)
2439         printf ("Wrote backup to %s\n", mkbak (ucon64.fname, BAK_MOVE));
2440       lynxit_read_rom (ucon64.fname, ucon64.parport);
2441       break;
2442 
2443     case UCON64_XMCCL:
2444       if (!access (ucon64.fname, F_OK) && ucon64.backup)
2445         printf ("Wrote backup to %s\n", mkbak (ucon64.fname, BAK_MOVE));
2446       mccl_read (ucon64.fname, ucon64.parport);
2447       break;
2448 
2449     case UCON64_XMCD:
2450       if (!access (ucon64.fname, F_OK) && ucon64.backup)
2451         printf ("Wrote backup to %s\n", mkbak (ucon64.fname, BAK_MOVE));
2452       mcd_read_rom (ucon64.fname, ucon64.parport);
2453       fputc ('\n', stdout);
2454       break;
2455 
2456     case UCON64_XMD:
2457       if (access (ucon64.fname, F_OK) != 0)     // file does not exist => dump flash card
2458         {
2459           md_read_rom (ucon64.fname, ucon64.parport, 64 * MBIT); // reads 32 Mbit if Sharp card
2460           fputc ('\n', stdout);
2461         }
2462       else                                      // file exists => send it to the MD-PRO
2463         {
2464           if (ucon64.nfo->backup_header_len)    // binary with header is possible
2465             fputs ("ERROR: This ROM has a header. Remove it with " OPTION_LONG_S "stp or " OPTION_LONG_S "bin\n",
2466                    stderr);
2467           else if (genesis_get_copier_type () != BIN)
2468             fputs ("ERROR: This ROM is not in binary/BIN/RAW format. uCON64 only supports sending\n"
2469                    "       binary files to the MD-PRO. Convert ROM with " OPTION_LONG_S "bin\n",
2470                    stderr);
2471           else
2472             {
2473               md_write_rom (ucon64.fname, ucon64.parport);
2474               fputc ('\n', stdout);
2475             }
2476         }
2477       break;
2478 
2479     case UCON64_XMDS:
2480       if (access (ucon64.fname, F_OK) != 0)     // file does not exist => dump SRAM contents
2481         md_read_sram (ucon64.fname, ucon64.parport, -1);
2482       else                                      // file exists => restore SRAM
2483         md_write_sram (ucon64.fname, ucon64.parport, -1);
2484       fputc ('\n', stdout);
2485       break;
2486 
2487     case UCON64_XMDB:
2488       if (access (ucon64.fname, F_OK) != 0)
2489         md_read_sram (ucon64.fname, ucon64.parport,
2490                       strtol (option_arg, NULL, 10));
2491       else
2492         md_write_sram (ucon64.fname, ucon64.parport,
2493                        strtol (option_arg, NULL, 10));
2494       fputc ('\n', stdout);
2495       break;
2496 
2497     case UCON64_XMSG:
2498       if (access (ucon64.fname, F_OK) != 0)
2499         {
2500           msg_read_rom (ucon64.fname, ucon64.parport);
2501           fputc ('\n', stdout);
2502         }
2503       else
2504         {
2505           if (!ucon64.nfo->backup_header_len)
2506             fputs ("ERROR: This ROM has no header. Convert to an MSG compatible format\n",
2507                    stderr);
2508           else if (ucon64.nfo->interleaved)
2509             fputs ("ERROR: This ROM seems to be bit-swapped, but the MSG does not support\n"
2510                    "       bit-swapped ROMs. Convert to an MSG compatible format\n",
2511                    stderr);
2512           else
2513             {
2514               msg_write_rom (ucon64.fname, ucon64.parport);
2515               fputc ('\n', stdout);
2516             }
2517         }
2518       break;
2519 
2520     case UCON64_XPCE:
2521       if (access (ucon64.fname, F_OK) != 0)
2522         pce_read_rom (ucon64.fname, ucon64.parport, 32 * MBIT);
2523       else
2524         pce_write_rom (ucon64.fname, ucon64.parport);
2525       fputc ('\n', stdout);
2526       break;
2527 
2528     case UCON64_XPL:
2529       if (access (ucon64.fname, F_OK) != 0)
2530         pl_read_rom (ucon64.fname, ucon64.parport);
2531       else
2532         pl_write_rom (ucon64.fname, ucon64.parport);
2533       fputc ('\n', stdout);
2534       break;
2535 
2536     case UCON64_XPLI:
2537       pl_info (ucon64.parport);
2538       fputc ('\n', stdout);
2539       break;
2540 
2541     case UCON64_XSF:
2542       if (access (ucon64.fname, F_OK) != 0)     // file does not exist => dump flash card
2543         sf_read_rom (ucon64.fname, ucon64.parport, 64 * MBIT);
2544       else                                      // file exists => send it to the Super Flash
2545         sf_write_rom (ucon64.fname, ucon64.parport);
2546       fputc ('\n', stdout);
2547       break;
2548 
2549     case UCON64_XSFS:
2550       if (access (ucon64.fname, F_OK) != 0)     // file does not exist => dump SRAM contents
2551         sf_read_sram (ucon64.fname, ucon64.parport);
2552       else                                      // file exists => restore SRAM
2553         sf_write_sram (ucon64.fname, ucon64.parport);
2554       fputc ('\n', stdout);
2555       break;
2556 
2557     case UCON64_XSMC: // we don't use WF_NO_ROM => no need to check for file
2558       if (!ucon64.nfo->backup_header_len)
2559         fputs ("ERROR: This ROM has no header. Convert to an SMC compatible format with " OPTION_LONG_S "ffe\n",
2560                stderr);
2561       else
2562         {
2563           smc_write_rom (ucon64.fname, ucon64.parport);
2564           fputc ('\n', stdout);
2565         }
2566       break;
2567 
2568     case UCON64_XSMCR:
2569       if (access (ucon64.fname, F_OK) != 0)
2570         smc_read_rts (ucon64.fname, ucon64.parport);
2571       else
2572         smc_write_rts (ucon64.fname, ucon64.parport);
2573       fputc ('\n', stdout);
2574       break;
2575 
2576     case UCON64_XSMD:
2577       if (access (ucon64.fname, F_OK) != 0)     // file does not exist => dump cartridge
2578         {
2579           smd_read_rom (ucon64.fname, ucon64.parport);
2580           fputc ('\n', stdout);
2581         }
2582       else                                      // file exists => send it to the copier
2583         {
2584           if (!ucon64.nfo->backup_header_len)
2585             fputs ("ERROR: This ROM has no header. Convert to an SMD compatible format\n",
2586                    stderr);
2587           else if (!ucon64.nfo->interleaved)
2588             fputs ("ERROR: This ROM does not seem to be interleaved, but the SMD only supports\n"
2589                    "       interleaved ROMs. Convert to an SMD compatible format\n",
2590                    stderr);
2591           else
2592             {
2593               smd_write_rom (ucon64.fname, ucon64.parport);
2594               fputc ('\n', stdout);
2595             }
2596         }
2597       break;
2598 
2599     case UCON64_XSMDS:
2600       if (access (ucon64.fname, F_OK) != 0)     // file does not exist => dump SRAM contents
2601         smd_read_sram (ucon64.fname, ucon64.parport);
2602       else                                      // file exists => restore SRAM
2603         smd_write_sram (ucon64.fname, ucon64.parport);
2604       fputc ('\n', stdout);
2605       break;
2606 
2607     case UCON64_XSWC:
2608       enableRTS = 0;                            // falling through
2609     case UCON64_XSWC2:
2610       if (access (ucon64.fname, F_OK) != 0)     // file does not exist => dump cartridge
2611         {
2612           swc_read_rom (ucon64.fname, ucon64.parport, ucon64.io_mode);
2613           fputc ('\n', stdout);
2614         }
2615       else
2616         {
2617           if (!ucon64.nfo->backup_header_len)
2618             fputs ("ERROR: This ROM has no header. Convert to an SWC compatible format\n",
2619                    stderr);
2620           else if (ucon64.nfo->interleaved)
2621             fputs ("ERROR: This ROM seems to be interleaved, but the SWC does not support\n"
2622                    "       interleaved ROMs. Convert to an SWC compatible format\n",
2623                    stderr);
2624           else
2625             {
2626               if (enableRTS != 0)
2627                 enableRTS = 1;
2628               // file exists => send it to the copier
2629               swc_write_rom (ucon64.fname, ucon64.parport, enableRTS);
2630               fputc ('\n', stdout);
2631             }
2632         }
2633       break;
2634 
2635     case UCON64_XSWCS:
2636       if (access (ucon64.fname, F_OK) != 0)     // file does not exist => dump SRAM contents
2637         swc_read_sram (ucon64.fname, ucon64.parport);
2638       else                                      // file exists => restore SRAM
2639         swc_write_sram (ucon64.fname, ucon64.parport);
2640       fputc ('\n', stdout);
2641       break;
2642 
2643     case UCON64_XSWCC:
2644       if (access (ucon64.fname, F_OK) != 0)     // file does not exist => dump SRAM contents
2645         swc_read_cart_sram (ucon64.fname, ucon64.parport, ucon64.io_mode);
2646       else                                      // file exists => restore SRAM
2647         swc_write_cart_sram (ucon64.fname, ucon64.parport, ucon64.io_mode);
2648       fputc ('\n', stdout);
2649       break;
2650 
2651     case UCON64_XSWCR:
2652       if (access (ucon64.fname, F_OK) != 0)
2653         swc_read_rts (ucon64.fname, ucon64.parport);
2654       else
2655         swc_write_rts (ucon64.fname, ucon64.parport);
2656       fputc ('\n', stdout);
2657       break;
2658 
2659     case UCON64_XV64:
2660       if (access (ucon64.fname, F_OK) != 0)
2661         {
2662           doctor64_read (ucon64.fname, ucon64.parport);
2663           fputc ('\n', stdout);
2664         }
2665       else
2666         {
2667           if (!ucon64.nfo->interleaved)
2668             fputs ("ERROR: This ROM does not seem to be interleaved, but the Doctor V64 only\n"
2669                    "       supports interleaved ROMs. Convert to a Doctor V64 compatible format\n",
2670                    stderr);
2671           else
2672             {
2673               doctor64_write (ucon64.fname, ucon64.nfo->backup_header_len,
2674                               (int) ucon64.fsize, ucon64.parport);
2675               fputc ('\n', stdout);
2676             }
2677         }
2678       break;
2679 #endif // USE_PARALLEL
2680 
2681 #if     defined USE_PARALLEL || defined USE_USB
2682     case UCON64_XF2A:
2683       if (access (ucon64.fname, F_OK) != 0)
2684         f2a_read_rom (ucon64.fname, 32);
2685       else
2686         f2a_write_rom (ucon64.fname, UCON64_UNKNOWN);
2687       fputc ('\n', stdout);
2688       break;
2689 
2690     case UCON64_XF2AMULTI:
2691       f2a_write_rom (NULL, strtol (option_arg, NULL, 10) * MBIT);
2692       fputc ('\n', stdout);
2693       break;
2694 
2695     case UCON64_XF2AC:
2696       if (!access (ucon64.fname, F_OK) && ucon64.backup)
2697         printf ("Wrote backup to %s\n", mkbak (ucon64.fname, BAK_MOVE));
2698       f2a_read_rom (ucon64.fname, strtol (option_arg, NULL, 10));
2699       fputc ('\n', stdout);
2700       break;
2701 
2702     case UCON64_XF2AS:
2703       if (access (ucon64.fname, F_OK) != 0)
2704         f2a_read_sram (ucon64.fname, UCON64_UNKNOWN);
2705       else
2706         f2a_write_sram (ucon64.fname, UCON64_UNKNOWN);
2707       fputc ('\n', stdout);
2708       break;
2709 
2710     case UCON64_XF2AB:
2711       if (access (ucon64.fname, F_OK) != 0)
2712         f2a_read_sram (ucon64.fname, strtol (option_arg, NULL, 10));
2713       else
2714         f2a_write_sram (ucon64.fname, strtol (option_arg, NULL, 10));
2715       fputc ('\n', stdout);
2716       break;
2717 #endif // USE_PARALLEL || USE_USB
2718 
2719 #ifdef  USE_USB
2720     case UCON64_XQD16:
2721       if (ucon64.nfo->interleaved)
2722         fputs ("ERROR: This ROM seems to be interleaved, but the Quickdev16 does not support\n"
2723                "       interleaved ROMs. Convert to an SWC compatible format\n",
2724                stderr);
2725       else
2726         {
2727           quickdev16_write_rom (ucon64.fname);
2728           fputc ('\n', stdout);
2729         }
2730       break;
2731 
2732     case UCON64_XUFOSD:
2733       if (snes_get_copier_type () != UFOSD)
2734         fputs ("ERROR: This ROM is not in Super UFO Pro 8 SD format. Convert with " OPTION_LONG_S "ufosd\n",
2735                stderr);
2736       else if (ucon64.nfo->interleaved)
2737         fputs ("ERROR: This ROM seems to be interleaved, but the Super UFO Pro 8 SD does not\n"
2738                "       support interleaved ROMs. Convert with " OPTION_LONG_S "ufosd\n",
2739                stderr);
2740       else
2741         {
2742           ufosd_write_rom (ucon64.fname);
2743           fputc ('\n', stdout);
2744         }
2745       break;
2746 #endif // USE_USB
2747 
2748     case UCON64_Z64:
2749       n64_z64 (ucon64.nfo);
2750       break;
2751 
2752     default:
2753       break;
2754     }
2755 
2756   return 0;
2757 }
2758