#!/usr/bin/tclsh

# The variables below have been placed at the top of this file so that you
# may easily modify their values.

set xmame [auto_execok xmame.x11]       ;  # default xmame executable
set zip   [auto_execok zip]             ;  # location of zip command
set unzip [auto_execok unzip]           ;  # location of unzip command
set workd [file join / tmp romalizer]   ;  # working directory
set verbose no                          ;  # sets verbosity (yes/no)
set force   no                          ;  # autocreate new roms? (yes/no)
set noex    no                          ;  # do not execute commands
set logfile ""                          ;  # log file ("" == no logging)
set c_level 6                           ;  # default compression level
set cutoff  150                         ;  # cutoff value (see help file)
set check_names no                      ;  # check file names too?

##########################################################################
#
#  Please do not modify anything below this point unless you really know
#  what you are doing!
#
##########################################################################

set help "
  romalizer(1)                                               romalizer(1)


  NAME
         romalizer - analyze and fix ROMs used for xmame

  SYNOPSIS
         romalizer \[-f\] \[-h\] \[-m\] \[-n\] \[-v\] \[-V\] \[-c level] \[-d workdir\]
         \[-l logfile\] \[-r rompath\] \[-x xmame\] \[-C cutoff\] rom ...

  DESCRIPTION
         romalizer will examine the  rom(s) specified on the command line
         as well as all the  clones for each rom.  If rom is a clone then
         the   associated parent   rom is used   instead, any   resulting
         duplicate roms  will be ignored, thus using  wildcards such as *
         will not result in reexamining the same rom twice.  The rom that
         is specified  may be the short name  recognized by xmame, or the
         full path name to the zip file.

         During the examination process, romlizer compares the CRCs found
         in xmame with  those in your zip files.  If any extra  files are
         stored  in your zip files,  romalizer detects them  and issues a
         report.  romalizer is  also capable  of  building  new zip files
         from your existing zip files if any discrepancies are found.

         romalizer  assumes that   files belonging  solely to  a clone be
         placed in a  separate zip file with that clones name.  romalizer
         will  not merge two  zip files,  it only analyzes  the first zip
         file found in the rompath specified.

  OPTIONS
         -c  level
                This specifies the compression level  you want to use for
                your  zip files.  0 indicates  no compression,  1 is  the
                fastest compression,  and 9 is the  slowest.  The default
                is 6.

         -d  workdir
                This   specifies the  directory  where  romalizer  places
                temporary  working files, and backs up your old ROMs when
                building new ones.  The default, if not specified, is set
                to /tmp/romalizer.

         -l  logfile
                This will send  output which is sent to  the console when
                the -v option is used to a file specified by logfile.  If
                both the -l and -v options are used, then  output will be
                sent to both the console and the logfile specified.

         -r  rompath
                Specifies  the rompath  to use when looking  for your zip
                files.  If  not  specified,  romalizer  uses the rom path
                specified in your ~/.xmamerc file.

         -x  xmame
                Specifies the location of the xmame executable to use for
                checking  CRC values.  The default,  if not specified, is
                xmame.x11.

         -C  cutoff
                Specifies the  cutoff value for the  number of roms which
                have to be specified on the command line before romalizer
                checks all CRCs at once instead of one rom at a time. The
                default is 150.

         -f     Force  creation  of  new  roms.  With  this  option  set,
                romalizer will  automatically create new ROMs for you and
                delete  your old ROMs.  This option is useful if you want
                to automatically fix a  large number  of ROMs, and you do
                not want  to backup your old  ROMs.  This option  is also
                used frequently with the -n option.

         -h     Prints out this descriptive help file.

         -m     Check file names as well as CRC values in your zip files.

         -n     Do not  execute commands,  but  instead just  print  what
                commands romalizer would execute if -n option is not used.

         -v     Verbose mode.  This  option  will  print  all  the  shell
                commands it is trying to execute to stdout.

         -V     Prints version number and exits.

  EXAMPLES
         To verify all your roms that start with the letter `a' use:

                romalizer /usr/games/lib/xmame/mame/roms/a*

         To see what romalizer would do without doing anything use:

                romalizer -v -n pacman

         To automatically fix any roms that romalizer sees problems with:

                romalizer -f pacman galaga joust

         Here is an example I use when a new version of xmame comes out:

                romalizer -f -v -n -x ~/xmame.x11 -r ~/old:~/new ~/new/roms/*

         My  ~/old/roms  directory contains my old xmame ROMs, and the
         ~/new/roms directory contains the new ROMs

  ENVIRONMENT
         ROMPATH
                Overrides the  rompath specified  in the ~/.xmamerc file.
                If a rompath is  specified on the command line, then that
                is used instead of the environment setting.

         PATH
                Used to locate zip, unzip, and xmame commands.

  SEE ALSO
         xmame(6)

  AUTHOR
         romalizer  is written by  Christopher Stone  <tkmame@ztnet.com>.
         If you have any ideas or  suggestions on improving this software
         please let me know.

  BUGS
         NeoGeo games are not supported.
"

#parse command line
if { $argc } { 
    for { set i 0 } { $i < $argc } { incr i } {
	set opt [lindex $argv $i]
	switch -exact -- $opt {
	    -h { catch { puts $help } ; exit }
	    -V { puts "$argv0: version 0.53" ; exit }
	    -v { global verbose; set verbose yes }
	    -f { global force; set force yes }
            -m { global check_names ; set check_names yes }
	    -n { global noex; set noex yes }
	    -c { incr i ; set c_level [lindex $argv $i] }
	    -d { incr i ; set workd [lindex $argv $i] }
	    -l { incr i ; set logfile [lindex $argv $i] }
	    -r { incr i ; set path  [lindex $argv $i] }
            -x { incr i ; set xmame [lindex $argv $i] }
	    -C { incr i ; set cutoff [lindex $argv $i] }
	    default { set roms [lrange $argv $i end] ; break }
	}
    }
}
# check if any roms were specified on the command line
proc printhelp { } {
    global argv0 env
    if { [info exists env(PAGER)] } {
	set pager $env(PAGER)
    } else {
	set pager "more"
    }
    puts stderr "$argv0: Missing ROM!  Try `$argv0 -h | $pager' for more options."
    exit
}
if { ![info exists roms] || !$argc } { printhelp }
# extracts the romname from a zip file name
proc remove_zip { filename } {
    set index [string last / $filename]
    if { $index != -1 } {
	incr index
	set filename [string range $filename $index end]
    }
    set index [string first ".zip" $filename]
    if { $index != -1 } {
	incr index -1
	return [string range $filename 0 $index]
    } else {
	return $filename
    }
}
# convert any zipfiles on command line to romnames
foreach rom [split $roms] { lappend newroms [remove_zip $rom] }
set roms [lsort $newroms]
# create logfile is logging was specified
if { $logfile != "" } { set logfiled [open $logfile w] }
# logging routine
proc myputs { data } {
    global logfile logfiled verbose
    if { $logfile != "" } { puts $logfiled $data }
    if { $verbose } { puts $data }
}
# check compression level
if { $c_level < 0 || $c_level > 9 } {
    puts stderr "$argv0: Invalid compression level of $c_level specified."
    exit
}
# check to see if you have zip and unzip commands
if { $zip == "" || $unzip == "" } {
    puts stderr "$argv0: Unable to locate zip and/or unzip commands."
    exit
}
# procedure to evaluate commands which are supposed to work
proc evalcmd { command } {
    global argv0
    if { [catch { eval exec $command }] == 1 } {
	puts stderr "$argv0: Unable to execute command:\n$command"
	puts stderr "$argv0: Please send a bug report to tkmame@ztnet.com"
	exit
    }
}
# prepare to work!
puts "Obtaining game information..."
if { ![file isdirectory $workd] } { file mkdir $workd }
set tempf [file join / $workd romalizer.tmp]
if { [file isfile $tempf] } { file delete $tempf }
# get all the clones for each rom
# first find the masters for each clone
set command "$xmame -listclones -stdout-file $tempf"
myputs $command
catch { eval exec $command }
set tempfid [open $tempf r]
while { [gets $tempfid data] >= 0 } {
    # get name of the clone
    set clone [string trimright [string range $data 0 7]]
    # skip header crap
    if { [string match "Name*" $clone] } { continue }
    # get rom name
    set rom [string trimright [string range $data 9 end]]
    # make a list of non-clones that have clones (i'll call these masters)
    if { ![info exists masters] || [lsearch $masters $rom] == -1 } {
	lappend masters $rom
    }
    # make a list of clones for each master
    lappend clones($rom) $clone
    # create an associatve array of clones and masters
    set master_of($clone) $rom
}
close $tempfid
# now lets get all non-clones
set command "$xmame -list -noclones -stdout-file $tempf"
myputs $command
catch { eval exec $command }
set tempfid [open $tempf r]
while { [gets $tempfid data] >= 0 } {
    # skip header crap
    if { [string match "xmame*" $data] } { continue }
    # blank line means we are done
    if { $data == "" } { break }
    for { set indx 0 } { $indx < 64 } { incr indx 8 } {
	# get rom names
	set endindx [expr $indx + 7]
	set rom [string trimright [string range $data $indx $endindx]]
	if { $rom != "" } {
	    # create list of nonclones, check masters to weed out neogeos
	    if { ![info exists master_of($rom)] } { lappend nonclones $rom }
	}
    }
}
close $tempfid
# remove any duplicate roms specified on command line
for { set i 0 } { $i < [llength $roms] } { incr i } {
    set rom [lindex $roms $i]
    if { [lsearch -exact $nonclones $rom] == -1 } {
        set roms [lreplace $roms $i $i]
	if { [info exists master_of($rom)] && 
	     [lsearch $roms $master_of($rom)] == -1 } {
	    lappend roms $master_of($rom)
	}
        incr i -1
    }
}
if { $roms == "" } {
    puts stderr "$argv0: No valid roms specified."
    printhelp
}
# if no path was specified on command line get it from xmamerc file or
# ROMPATH enviornment variable.
if { ![info exists path] } {
    set command "$xmame -showconfig -stdout-file $tempf"
    myputs $command
    catch { eval exec $command }
    if { ![file exists $tempf] } {
	puts stderr "$argv0: Unable to execute command:\n$command"
	exit
    }
    set tempfid [open $tempf r]
    while { [gets $tempfid data] >= 0 } {
	set data [string trim $data]
	if { [string compare [string range $data 0 6] "rompath"] == 0 } {
	    set path [string trim [string range $data 7 end]]
	}
    }
    close $tempfid
}
# create lookup table for short names and long names
set command "$xmame -listfull -stdout-file $tempf"
myputs $command
catch { eval exec $command }
set tempfid [open $tempf r]
while { [gets $tempfid data] >= 0 } {
    set s_name [string trimright [string range $data 0 7]]
    if { $s_name == "Name:" || $s_name == "" || $s_name == "Total Su" } {
	continue
    }
    set l_name [string range $data 10 end]
    set index [string first ", The" $l_name]
    if { $index != -1 } {
	set index2 [expr $index + 5]
        incr index -1
	set l_name "The [string range $l_name 0 $index][string range $l_name $index2 end]"
    }
    set name_lookup("$l_name") $s_name 
}
# place CRC information into data structures
proc getcrcdata { currentrom } {
    global xmame tempf crcs name_indx name_lookup
    set command "$xmame -listcrc $currentrom -stdout-file $tempf"
    myputs $command
    catch { eval exec $command }
    set tempfid [open $tempf r]
    set old_s_name ""
    while { [gets $tempfid data] >= 0 } {
	# parse each line of text
	set name [string trimright [string range $data 9 21]]
	# ignore any header crap
	if { $name == "" || [string match "File*" $name] ||
	     [string match "ported:*" $name] } { continue }
	set crc  [string range $data 0 7]
	set l_name [string range $data 22 end]
	set rom $name_lookup("$l_name")
	# ignore roms that dont exist
	if { [string compare $crc "00000000"] == 0 } { continue }
	# make list of crcs for each rom
	if { ![info exists crcs($rom)] || [lsearch $crcs($rom) $crc] == -1 } {
	    lappend crcs($rom) $crc
	}
	# create associative array of crc's and names
	set name_indx($rom,$crc) $name
    }
    close $tempfid
}
puts "Obtaining CRC information..."
# determine if we should get CRCs one at a time or all at once
set numofroms 0
foreach rom [split $roms] {
    incr numofroms
    # we need to include clones too
    if { [info exists clones($rom)] } {
	foreach clone [split $clones($rom)] { incr numofroms }
    }
}
if { $numofroms < $cutoff } {
    set processroms [llength $roms]
} else {
    set processroms 0
}
# now lets get the necessary CRC data...
if { $processroms == 0 } {
    set currentrom ""
    getcrcdata $currentrom
} else {
    for { set i 0 } { $i < $processroms } { incr i } {
	set currentrom [lindex $roms $i]
	getcrcdata $currentrom
	if { [info exists clones($currentrom)] } {
	    foreach clone [split $clones($currentrom)] { getcrcdata $clone }
	}
    }
}
proc examine_zip { rom } {
    global path unzip tempf argv0 zip_crcs zip_name_indx zip_indx
    # take first occurance of zip file found
    foreach rompath [split $path :] {
	set zipname [file join / $rompath roms ${rom}.zip]
	if { [file exists $zipname] } { break }
    }
    # use -v option to look at contents of zip file
    set command "$unzip -v $zipname > $tempf"
    myputs "$command"
    if { [catch { eval exec $command }] } {
	puts stderr "$argv0: Unable to find ${rom}.zip, skipping..."
	return -1
    }
    set tempfid [open $tempf r]
    set linecount 0
    while { [gets $tempfid data] >= 0 } {
	# skip the first three lines of output
	if { [incr linecount] <= 3 } { continue }
	# extract the CRC
	set crc [string trim [string range $data 47 54]]
	# ignore blank lines
	if { $crc == "" } { continue }
	# extract the name
	set name [string trim [string range $data 57 end]]
	# ignore dummy files made by romalizer
	if { $name == "dummy" && [string compare $crc "00000000"] == 0 } {
	    continue
	}
	# build a list of CRCs found in zipfile for $rom
	lappend zip_crcs($rom) $crc
	# locate the zipfile which contains a file of $crc
	set zip_indx($rom,$crc) $zipname
	# zip file filenames lookup table 
	set zip_name_indx($rom,$crc) $name
    }
    close $tempfid
    return 0
}
# this procedure will remove the duplicate CRCs found in all the clones
# and add them to the required CRCs for the master
proc examine_clones { master } {
    global crcs clones
    # remove CRCs that are duplicated in clones and add them to master
    # if master doesnt already have that CRC in its list
    for { set i 0 } { $i < [llength $clones($master)] } { incr i } {
	set clone [lindex $clones($master) $i]
	# compare this one with the rest in the list
	set j [expr $i + 1]
	set other_clones [lrange $clones($master) $j end]
	if { $other_clones == $clone } { continue } ; # fail safe
	foreach other_clone [split $other_clones] {
	    foreach clone_crc [split $crcs($clone)] {
		foreach other_clone_crc [split $crcs($other_clone)] {
		    if { $clone_crc == $other_clone_crc } {
			# remove crc from crcs list for both clones
			set index [lsearch $crcs($clone) $clone_crc]
			set crcs($clone) [lreplace $crcs($clone) $index $index]
			set index [lsearch $crcs($other_clone) $clone_crc]
			set crcs($other_clone) \
			    [lreplace $crcs($other_clone) $index $index]
			# now check if crc is also in the master
			set match_found 0
			foreach crc [split $crcs($master)] {
			    if { $crc == $clone_crc } {
				set match_found 1
				break
			    }
			}
			# if crc is not found in master, then add it!
			if { !$match_found } {
			    lappend crcs($master) $clone_crc
			}
		    }
		}
	    }
	}
    }
    # remove CRCs in clones that are already in master
    foreach clone [split $clones($master)] {
	foreach clone_crc [split $crcs($clone)] {
	    foreach master_crc [split $crcs($master)] {
		if { $clone_crc == $master_crc } {
		    # remove the crc from the crcs list
		    set index [lsearch $crcs($clone) $clone_crc]
		    set crcs($clone) [lreplace $crcs($clone) $index $index]
		    break
		}
	    }
	}
    }
}
# now lets get all the CRC information in the user's zip files for each
# rom specified on the command line
puts "Obtaining zip file information..."
foreach current_rom [split $roms] {
    if { [examine_zip $current_rom] == -1 } {
	# the zip file was not found, so do not give a report for it
	set i [lsearch $roms $current_rom]
        set roms [lreplace $roms $i $i]
    }
    # if a rom has a clone we need to get the CRCs for those too
    if { [info exists clones($current_rom)] } {
	foreach clone [split $clones($current_rom)] {
	    if { [examine_zip $clone] == -1 } {
		# the zip file was not found, so do not give a report for it
		set i [lsearch $roms $clone]
		set roms [lreplace $roms $i $i]
	    }
	}
	# here we make sure that any crcs which are required for both the
	# clone and master are removed from the clone's required crc list.
	# we also removed crcs duplicated across clones and add them to the
	# required list of crcs to the master if not already present
	examine_clones $current_rom
    }
}
proc aok { rom item } {
    puts [format "%10s: ${item}s GOOD" $rom] ; flush stdout
}
proc notok { rom item } {
    puts [format "%10s: ${item}s BAD!" $rom] ; flush stdout
}
proc check_names { rom } {
    global crcs2 zip_crcs2 name_indx zip_name_indx imperfections_exist
    global clones argv0
    foreach crc [split $crcs2($rom)] {
	foreach zip_crc [split $zip_crcs2($rom)] {
	    if { $zip_crc == $crc } {
		set a ""
		if { [info exists name_indx($rom,$crc)] } {
		    set a $name_indx($rom,$crc)
		} else {
		    foreach clone [split $clones($rom)] {
			if { [info exists name_indx($clone,$crc)] } {
			    set a $name_indx($clone,$crc)
			    break
			}
		    }
		}
		set b $zip_name_indx($rom,$zip_crc)
		if { [string compare $a $b] } {
		    puts "zip name $b does not match $a"
		    set imperfections_exist 1
		}
	    }
	}
    }
    if { $imperfections_exist } { notok $rom NAME } else { aok $rom NAME }
}
proc remove_crc { rom crc zip_crc } {
    global crcs2 zip_crcs2
    set indx [lsearch $crcs2($rom) $crc]
    set crcs2($rom) [lreplace $crcs2($rom) $indx $indx]
    set indx [lsearch $zip_crcs2($rom) $zip_crc]
    set zip_crcs2($rom) [lreplace $zip_crcs2($rom) $indx $indx]
}
proc show_missing_files { rom crc inverted_crc } {
    global zip_indx name_indx zip_indx title clones
    set zname [remove_zip $zip_indx($rom,$crc)]
    if { [string compare $zname $rom] == 0 } { return }
    if { $title == 0 } {
	puts "The following files are missing in $rom"
	set title 1
    }
    if { [info exists name_indx($rom,$crc)] } {
	puts -nonewline "$name_indx($rom,$crc) "
    } else {
	foreach clone [split $clones($rom)] {
	    if { [info exists name_indx($clone,$crc)] } {
		puts -nonewline "$name_indx($clone,$crc) "
		break;
	    }
	}
    }
    if { $inverted_crc } {
	puts "(Found in: $zip_indx($rom,$inverted_crc))"
    } else {
	puts "(Found in: $zip_indx($rom,$crc))"
    }
}
set title 0
# this procedure needs comments
proc status_report { rom } {
    global crcs2 zip_crcs2 zip_name_indx zip_indx name_indx title
    global imperfections_exist clones
    if { [lsort $crcs2($rom)] == [lsort $zip_crcs2($rom)] } {
	aok $rom CRC
    } else {
	foreach crc [split $crcs2($rom)] {
	    foreach zip_crc [split $zip_crcs2($rom)] {
		set inverted_crc [format "%08x" [expr 0xffffffff - 0x$crc]]
		if { $zip_crc == $crc } {
		    remove_crc $rom $crc $crc
		    break
		}
		if { $zip_crc == $inverted_crc } {
		    remove_crc $rom $crc $zip_crc
		    break
		}
	    }
	}
	if { ![llength $crcs2($rom)] && ![llength $zip_crcs2($rom)]} {
	    aok $rom CRC
	} else {
	    if { [llength $crcs2($rom)] } {
		set imperfections_exist 1
		notok $rom CRC
		set title 0
		foreach crc [split $crcs2($rom)] {
		    set inverted_crc [format "%08x" [expr 0xffffffff - 0x$crc]]
		    if { [info exists zip_indx($rom,$crc)] } {
			show_missing_files $rom $crc 0
		    } elseif { [info exists zip_indx($rom,$inverted_crc)] } {
			show_missing_files $rom $crc $inverted_crc
		    } else {
			if { [info exists name_indx($rom,$crc)] } {
			    puts -nonewline "$name_indx($rom,$crc) "
			} else {
			    foreach clone [split $clones($rom)] {
				if { [info exists name_indx($clone,$crc)] } {
				    puts -nonewline "$name_indx($clone,$crc) "
				    break;
				}
			    }
			}
			puts "Not found in any other zips! (CRC:$crc)"
		    }
		}
	    }
	    if { [llength $zip_crcs2($rom)] } {
		set imperfections_exist 1
		notok $rom CRC
		puts "The following extranous files were found in $rom:"
		foreach crc [split $zip_crcs2($rom)] {
		    puts "$zip_name_indx($rom,$crc) (CRC = $crc)"
		}
	    }
	}
    }
}
proc unzipem { zip_filename file_to_unzip mame_name workdir } {
    global noex verbose workd check_names unzip
    set command "$unzip -j $zip_filename $file_to_unzip -d $workdir"
    if { $noex } {
	puts $command 
    } else {
	myputs $command
	evalcmd $command
	if { $verbose == "no" } { puts -nonewline . ; flush stdout }
    }
    if { $check_names } {
	set indx [string last / $file_to_unzip]
	incr indx
	set trimmed_file [string range $file_to_unzip $indx end]
	if { $mame_name != $trimmed_file } {
	    set file1 [file join / $workdir $trimmed_file]
	    set file2 [file join / $workdir $mame_name]
	    set command "mv $file1 $file2"
	    if { $noex } {
		puts $command 
	    } else {
		myputs $command
		evalcmd $command
	    }
	}
    }
}
# this procedure attempts to fix your ROMs
proc fix_roms { rom } {
    global workd path crcs zip_name_indx zip_indx unzip zip noex
    global c_level verbose name_indx clones
    # this directory should not exist, if it does it means an error occurred
    # when trying to fix the roms the last time romalizer was run.  If it 
    # does exist, just remove the contents of directory, other
    set romdir [file join / $workd $rom]
    if { [file exists $romdir] } {
	set command "rm -rf $romdir"
	if { $noex } {
	    puts $command
	} else { 
	    myputs $command
	    evalcmd $command
	}
    }
    # make a directory to place roms into
    if { $noex } {
	puts "mkdir $romdir"
    } else {
	myputs "mkdir $romdir"
	file mkdir $romdir
    }
    # find the zip file 
    foreach rompath [split $path :] {
	set zipname [file join / $rompath roms $rom.zip]
	if { [file exists $zipname] } { break }
    }
    # this foreach loop needs comments
    foreach crc [split $crcs($rom)] {
	if { [string compare $crc "00000000"] == 0 } { continue }
	set inverted_crc [format "%08x" [expr 0xffffffff - 0x$crc]]
	if { [info exists zip_indx($rom,$crc)] } {
	    set b $zip_name_indx($rom,$crc)
	    if { [info exists name_indx($rom,$crc)] } {
		set a $name_indx($rom,$crc)
	    } else {
		foreach clone [split $clones($rom)] {
		    if { [info exists name_indx($clone,$crc)] } {
			set a $name_indx($clone,$crc)
			break
		    }
		}
	    }
	    unzipem $zip_indx($rom,$crc) $b $a $romdir
	} elseif { [info exists zip_indx($rom,$inverted_crc)] } {
	    set b $zip_name_indx($rom,$inverted_crc)
	    if { [info exists name_indx($rom,$crc)] } {
		set a $name_indx($rom,$crc)
	    } else {
		foreach clone [split $clones($rom)] {
		    if { [info exists name_indx($clone,$crc)] } {
			set a $name_indx($clone,$crc)
			break
		    }
		}
	    }
	    unzipem $zip_indx($rom,$inverted_crc) $b $a $romdir
	}
    }
    set zipname [file join / $workd $rom.zip]
    set zipdir  [file join / $workd $rom]
    # this rom needs no files, so create a dummy file to build a zip with
    if { [catch { glob $zipdir/* }] } {
	set dummyfile [file join / $zipdir dummy]
	set command "touch $dummyfile"
	if { $noex == "no" } { myputs $command ; evalcmd $command }
    }
    # build the zip
    set command "$zip -mrjD -$c_level $zipname $zipdir"
    if { $noex } {
	puts $command
    } else {
	myputs $command
	evalcmd $command
    }
    # cleanup
    if { $noex } {
	puts "rmdir $zipdir"
    } else {
	myputs "rmdir $zipdir"
	file delete $zipdir
    }
}
# this makes a backup copy of your original roms and installs the new
# roms that romalizer built
proc move_zips { rom } {
    global workd path noex
    foreach rompath [split $path :] {
	set zipname [file join / $rompath roms $rom.zip]
	if { [file exists $zipname] } { break }
    }
    set oldromsdir [file join / $workd oldroms]
    if { ![file isdirectory $oldromsdir] } { file delete $oldromsdir }
    if { ![file exists $oldromsdir] } {
	if { $noex } {
	    puts "mkdir $oldromsdir"
	} else {
	    myputs "mkdir $oldromsdir"
	    file mkdir $oldromsdir
	}
    }
    set command "mv $zipname $oldromsdir"
    if { $noex } {
	puts $command
    } else {
	myputs $command
	catch { eval exec $command }
    }
    set zipname [file join / $workd $rom.zip]
    set newrompath [file join / $rompath roms]
    set command "mv $zipname $newrompath"
    if { $noex } {
	puts $command
    } else {
	myputs $command
	evalcmd $command
    }
}
# make a copy of the crcs array to use with generating a status report
# the original copy we use for fixing the roms
array set crcs2 [array get crcs]
array set zip_crcs2 [array get zip_crcs]
# generate a status report for each rom and fix them if something is wrong
foreach rom [split $roms] {
    set imperfections_exist 0
    status_report $rom
    if { [info exists clones($rom)] } {
	foreach clone [split $clones($rom)] {
	    if { [info exists zip_crcs2($clone)] } {
		status_report $clone
	    }
	}
    }
    if { $imperfections_exist == 0 && $check_names } {
	check_names $rom
	if { [info exists clones($rom)] } {
	    foreach clone [split $clones($rom)] { check_names $clone }
	}
    }
    if { $imperfections_exist } {
	if { $force == "no" } {
	    puts -nonewline "Would you like me to fix your ROMs \[Y/n\] ?"
	    flush stdout
	    if { [gets stdin resp] == 0 } { set resp y }
	} else {
	    set resp y
	}
	if { $resp == "y" || $resp == "Y" } {
	    puts -nonewline "fixing..." ; flush stdout
	    fix_roms $rom
	    if { [info exists clones($rom)] } {
		foreach clone [split $clones($rom)] { fix_roms $clone }
	    }
	    # make a backup copy of your old roms and install the new roms
	    move_zips $rom
	    if { [info exists clones($rom)] } {
		foreach clone [split $clones($rom)] { move_zips $clone }
	    }
	    set oldromsdir [file join / $workd oldroms]
	    puts "\nYour old ROMs have been moved to $oldromsdir"
	}
    }
}
# cleanup before exiting
file delete $tempf
if { $logfile != "" } { close $logfiled }
