#!/usr/bin/perl # breaker.pl 1.6 2006-01-20 14:13:55-05 davidsen Exp # breaker.pl - break a list of num/string values to max size chunks $RevNum = '1.6'; $RevDate = '2006-01-20 14:13:55-05'; sub Usage; sub by_size(); use Getopt::Std; getopts("vdn:r:f:P:G") || Usage; Usage unless defined $opt_n; $MaxSize = $opt_n; $Prefix = ( $opt_P ? $opt_P : "bklist." ); $Graft = $opt_G+0; while (<>) { next unless m/^\s*(\d+)\s+(.+)$/; $item_size = $1 + $opt_f; $item_size = $opt_r * int(($item_size + $opt_r - 1) / $opt_r) if $opt_r; # validate the size if ($item_size > $MaxSize) { printf "Item too big, %6d %s\n", $item_size, $2; next; } *WV = \$vals[$n++]; $WV->{count} = $item_size; $WV->{text} = $2; $total += $item_size; } # get the target number of media $Nmedia = int(($total + $MaxSize - 1) / $MaxSize); print "Nmedia: $Nmedia, total: $total, n: $n\n" if $opt_d; $Target = $total / $Nmedia; if ($opt_v) { printf "Total %d items, on %d media, target size %d (%.2f%%)\n", $total, $Nmedia, $Target, 100 * $Target / $MaxSize; } # sort by value for selection @vals = sort by_size @vals; # start building files for ($file = 1; $file <= $Nmedia; ++$file) { $fname = sprintf("%s%03d", $Prefix, $file); open(OF, ">$fname") || die "Create $fname"; $Ftotal = $FileCount = $n = 0; @putfiles = (); while ($n <= $#vals && $Ftotal < $Target) { if ($ItemSize = $vals[$n]->{count}) { $TrialSize = $Ftotal + $ItemSize; if ($TrialSize <= $MaxSize) { $Ftotal = $TrialSize; $vals[$n]->{count} = 0; ++$FileCount; push(@putfiles, $vals[$n]->{text}); } } ++$n; } # sort and output foreach $file (sort @putfiles) { if ($Graft) { print OF "$file=$file\n"; } else { print OF "$file\n"; } } close OF; print " File $fname built size $Ftotal with $FileCount items\n" if $opt_v; } exit 0; #Usage - how to use this sub Usage { print "breaker - break lists by size\n" . "\n" . "Usage:\n" . " breaker [ options ] [ file1 [ file2 [ file3 ... ] ] ]\n" . "\n" . "Options\n" . " -nNN max size per media is NN\n" . " THIS IS ACTUALLY REQUIRED, NOT OPTIONAL\n" . " -rNN round up sizes to multiples on NN\n" . " -fNN add fixed value to each item size\n" . " -Pstr prefix the file number with \"str\" (def. \"bklist.\")\n" . " -G format output as \"graft points\" for mkisofs. Each name appears\n" . " as \"name=name\" in the output file.\n" . "\n" . " -v verbose output while running\n" . " -d debug output (varies with version)\n" . "\n"; print "\nThis is v$RevNum ($RevDate)\n"; exit 1; } sub by_size() { $b->{count} <=> $a->{count} || $a->{text} cmp $b->{text}; }