Merged in Governor-Tarkin/swg-src (pull request #17)
[swg-src.git] / tools / custTool.pl
blob00f4122f3889f8eeccdf1162bd8bdcbc06cd0991
1 # ======================================================================
3 # Customization Variable Tool
4 # Copyright 2003, Sony Online Entertainment, Inc.
6 # ======================================================================
8 use strict;
10 use File::Find;
11 use POSIX qw(strftime);
13 # ======================================================================
15 # Constants
16 my $maxAllowableVariableId = 127;
17 my $dataFormatVersionNumber = 1;
18 my $firstAssignableId = 1;
20 # Names of customization variables.
21 my %countsByVariableName;
23 # Name to id assignment.
24 my %idsByVariableName;
25 my $newVariableCount = 0;
27 # Action options.
28 my $doPrintReport = 0;
29 my $doGenerateMifMapFile = 0;
31 # Report printing options.
32 my $printTpfFileNames = 0;
33 my $printSortByCount = 0;
34 my $printSortByName = 0;
35 my $reverseSort = 0;
37 # Id map file generation options.
38 my $mifFileName = "";
39 my $mifFileMustExist = 1;
41 my $debug = 0;
43 # ======================================================================
44 # SUBROUTINES
45 # ======================================================================
47 # ======================================================================
49 sub processArgs
51 # Process args. Args must come first.
52 while (defined($ARGV[0]) && ($ARGV[0] =~ m/^-([a-zA-Z]*)$/))
54 if ($1 eq "i")
56 $doPrintReport = 1;
58 elsif ($1 eq "g")
60 $doGenerateMifMapFile = 1;
62 elsif ($1 eq "F")
64 # Support first-time mif file generation, but force it to be a flag
65 # so the default is to die if not explicity specified and the mif
66 # file doesn't exist.
67 $mifFileMustExist = 0;
69 elsif ($1 eq "o")
71 die "-o option requires a filename to be specified after it (e.g. -o customization_id_manager.mif)\n" if !defined($ARGV[1]);
72 $mifFileName = $ARGV[1];
73 shift @ARGV;
75 die "filename [$mifFileName] should end in extension \".mif\"\n" if !($mifFileName =~ m/\.mif$/);
77 elsif ($1 eq "t")
79 $printTpfFileNames = 1;
81 elsif ($1 eq "c")
83 $printSortByCount = 1;
85 elsif ($1 eq "n")
87 $printSortByName = 1;
89 elsif ($1 eq "r")
91 $reverseSort = 1;
93 elsif ($1 eq "d")
95 $debug = 1;
98 shift @ARGV;
101 #-- Ensure we do at least some activity. Assume report generation is default.
102 if (($doPrintReport == 0) && ($doGenerateMifMapFile == 0))
104 $doPrintReport = 1;
107 #-- Ensure we'll print at least some output. Default is print-by-count if no printing option is specified.
108 if (($printSortByCount == 0) && ($printSortByName == 0))
110 $printSortByCount = 1;
114 # ======================================================================
116 sub findFileHandler
118 #-- Check if this is a TPF file.
119 if (m/^.*\.tpf$/)
121 #-- Indicate file we're testing.
122 print "Processing [$File::Find::name].\n" if $printTpfFileNames;
124 #-- Open the TPF file.
125 open(FILE, $_);
127 #-- Scan all variable names within the TPF file.
128 while (<FILE>)
130 chomp();
131 if (m/variableName="([^"]*)\"/) # last double-quote escaped for Emacs font-lock mode.
133 $countsByVariableName{$1}++;
137 #-- Close the file.
138 close(FILE);
142 # ======================================================================
144 sub collectCustomizationVariableData
146 # Setup directories to check.
147 @ARGV = ('.') if !defined($ARGV[0]);
149 # Do the find to scan in all TPF filenames.
150 find (\&findFileHandler, @ARGV);
153 # ======================================================================
155 sub printReport
157 # Handle printing sorted by name.
158 if ($printSortByName)
160 my @sortedKeys = sort keys(%countsByVariableName);
161 @sortedKeys = reverse @sortedKeys if $reverseSort;
163 print "Variable names sorted by name (" . @sortedKeys . " unique variable names):\n";
164 print "variable name\tcount\n";
165 foreach my $variableName (@sortedKeys)
167 my $count = $countsByVariableName{$variableName};
168 print "$variableName\t$count\n";
170 print "\n";
173 if ($printSortByCount)
175 my @sortedKeys = sort {$countsByVariableName{$b} <=> $countsByVariableName{$a}} keys(%countsByVariableName);
176 @sortedKeys = reverse @sortedKeys if $reverseSort;
178 print "Variable names sorted by name (" . @sortedKeys . " unique variable names):\n";
179 print "count\tvariable name\n";
180 foreach my $variableName (@sortedKeys)
182 my $count = $countsByVariableName{$variableName};
183 print "$count\t$variableName\n";
185 print "\n";
189 # ======================================================================
191 sub collectExistingVariableNameAssignments
193 open(MIF_FILE, $mifFileName) or die "failed to open specified mif file [$mifFileName]: $!";
195 my $nextAssignmentId = $firstAssignableId;
196 my $expectingId = 1;
198 while (<MIF_FILE>)
200 chomp();
201 if (m/int16\s+(\d+)\s*$/)
203 # Ensure we're expecting a new id.
204 die "error: file [$mifFileName] appears malformed, out of order int16/cstring declarations.\n" if !$expectingId;
205 $expectingId = 0;
207 $nextAssignmentId = $1;
209 elsif (m/cstring\s+\"([^\"]+)\"\s*$/)
211 # Ensure we're expecting a variable name.
212 die "error: file [$mifFileName] appears malformed, out of order int16/cstring declarations.\n" if $expectingId;
213 $expectingId = 1;
215 # Add new variable name. It is associated with $nextAssignmentId collected previously.
216 $idsByVariableName{$1} = $nextAssignmentId;
217 print "<existing: mapping variable name [$1] to [$nextAssignmentId]>\n" if $debug;
221 close(MIF_FILE);
224 # ======================================================================
226 sub writeMifFile
228 open(MIF_FILE, ">$mifFileName") or die "failed to open mif file [$mifFileName] for writing: $!";
230 my $timeString = strftime "%a %b %e %H:%M:%S %Y", localtime(time());
232 print MIF_FILE "// ======================================================================\n";
233 print MIF_FILE "// Output generated by Perl script \"$0\"\n";
234 print MIF_FILE "// Generation time: $timeString\n";
235 print MIF_FILE "//\n";
236 print MIF_FILE "// Do not hand-edit this file! It is generated by the build process.\n";
237 print MIF_FILE "// Changing values from a previous run without a database update will\n";
238 print MIF_FILE "// invalidate database-stored customization data.\n";
239 print MIF_FILE "// ======================================================================\n\n";
241 print MIF_FILE "form \"CIDM\"\n";
242 print MIF_FILE "{\n";
243 print MIF_FILE "\tform \"0001\"\n";
244 print MIF_FILE "\t{\n";
245 print MIF_FILE "\t\tchunk \"DATA\"\n";
246 print MIF_FILE "\t\t{\n";
248 foreach my $variableName (sort { $idsByVariableName{$a} <=> $idsByVariableName{$b} } keys %idsByVariableName)
250 print MIF_FILE "\t\t\tint16\t$idsByVariableName{$variableName}\n";
251 print MIF_FILE "\t\t\tcstring\t\"$variableName\"\n\n";
254 print MIF_FILE "\t\t}\n";
255 print MIF_FILE "\t}\n";
256 print MIF_FILE "}\n";
258 close(MIF_FILE);
260 print "<success: wrote new customization id manager data file [$mifFileName]>\n" if $debug;
263 # ======================================================================
265 sub assignNewVariableIds
267 # Setup starting id: should be the same as # entries in assignment map.
268 my @sortedValues = sort {$b <=> $a} values %idsByVariableName;
269 my $nextAssignmentId = $firstAssignableId;
271 $nextAssignmentId = ($sortedValues[0] + 1) if defined($sortedValues[0]);
272 print "<firstNewId: $nextAssignmentId>\n" if $debug;
275 # Process new IDs sorted by frequency from most to least, causing
276 # lower ID values to be assigned to higher-frequency items. This
277 # could be useful if some of the lower frequency items are really
278 # typos and need to be shuffled around.
279 foreach my $variableName (sort {$countsByVariableName{$b} <=> $countsByVariableName{$a}} keys %countsByVariableName)
281 # Check if variable is assigned yet.
282 if (!defined($idsByVariableName{$variableName}))
284 $idsByVariableName{$variableName} = $nextAssignmentId;
285 print "<new: mapping variable name [$variableName] to [$nextAssignmentId]>\n" if $debug;
287 ++$nextAssignmentId;
288 ++$newVariableCount;
293 # ======================================================================
295 sub generateMifMapFile
297 # Collect existing mif map assignments.
298 if (-f $mifFileName)
300 collectExistingVariableNameAssignments();
302 elsif ($mifFileMustExist)
304 if (length($mifFileName) < 1)
306 die "error: must specify filename for existing and output mif file with the -o flag.\n";
308 else
310 die "error: Customization id manager file must exist to preserve existing mappings.\nerror: Failed to find [$mifFileName].\nerror: Use -F for first-time file generation, don't do this unless you know what you're doing!\n";
314 # Generate assignments for non-populated but existing customization variables.
315 assignNewVariableIds();
317 # Check if we've exceeded the max assignable id value.
318 my @sortedAssignedIds = sort {$a <=> $b} values %idsByVariableName;
319 my $idCount = @sortedAssignedIds;
320 if ($idCount > 0)
322 my $maxAssignedId = $sortedAssignedIds[$idCount - 1];
323 print "<maxAssignedId: $maxAssignedId>\n" if $debug;
325 if ($maxAssignedId > $maxAllowableVariableId)
327 die "error: new unassigned customization variable ids needed but no more room.\nerror: Either unused names must be removed with database remapping or a new data format must be implemented.\nNeed id of $maxAssignedId but max allowable is $maxAllowableVariableId for format version $dataFormatVersionNumber.\n";
331 # Write new mif file if any changes.
332 if ($newVariableCount > 0)
334 writeMifFile();
336 else
338 print "skipping file generation: no new customization variable names found.\n";
342 # ======================================================================
343 # PROGRAM STARTING POINT.
344 # ======================================================================
346 # Program starts here.
348 # Handle arguments.
349 processArgs();
351 # Collect customization variable data.
352 collectCustomizationVariableData();
354 # Handle report generation.
355 if ($doPrintReport)
357 printReport();
360 # Handle mif file generation.
361 if ($doGenerateMifMapFile)
363 generateMifMapFile();
367 # ======================================================================