Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

388 lines
12 KiB

  1. #!perl -w
  2. #
  3. # reorder_layout.pl -- A tool to reorganize the layout.inx file based on usage
  4. #
  5. # Author: Scott Mackowski (ScottMa)
  6. #
  7. ##############################################################################
  8. ##############################################################################
  9. # Globals
  10. ##############################################################################
  11. my %desiredoutputorder; # Hash to map: number -> {FN, DN}
  12. my %orderedfiles; # Hash to map: {FN, DN} -> number
  13. my %datalines; # Layout.inx lines associated with FN, DN
  14. my $currentfilenumber = 0; # Index of the current file into the sort
  15. # order hashtables.
  16. ##############################################################################
  17. # Functions
  18. ##############################################################################
  19. #
  20. # This sort routine is for numeric sorting...
  21. #
  22. sub numerically { $a <=> $b; }
  23. #
  24. # Displays usage info for this script and then aborts.
  25. #
  26. sub ShowUsageInformation
  27. {
  28. printf STDERR "Usage: $0 (layout.inx) (usage_file)\n";
  29. die "\n";
  30. } # ShowUsageInformation
  31. #
  32. # Flushes all lines for the current section of the INX file, using the
  33. # desired output order.
  34. #
  35. sub FlushFileSection
  36. {
  37. #
  38. # Walk through the data hash in the desired output order.
  39. # If the file has been seen in the current section (has data),
  40. # write out each of its associated lines in order, then remove
  41. # the entry from all hashes.
  42. #
  43. foreach $recordnumber (sort numerically keys %desiredoutputorder)
  44. {
  45. my $filename = $desiredoutputorder{$recordnumber}{FN};
  46. my $dirnum = $desiredoutputorder{$recordnumber}{DN};
  47. if ( (exists ($datalines{$filename}) )
  48. && (exists ($datalines{$filename}{$dirnum}) ) )
  49. {
  50. foreach $linenumber (sort numerically keys %{ $datalines{$filename}{$dirnum} })
  51. {
  52. printf OUTPUTFILE ("%s\n", $datalines{$filename}{$dirnum}{$linenumber} );
  53. }
  54. delete $datalines{$filename}{$dirnum};
  55. delete $desiredoutputorder{$recordnumber};
  56. delete $orderedfiles{$filename}{$dirnum};
  57. }
  58. }
  59. #
  60. # Flush the extra lines from the end of the section that
  61. # were read but not associated with any entry.
  62. #
  63. if ($archivedlinecount > 0)
  64. {
  65. foreach $archivedlinecount (sort numerically keys %archivedlines)
  66. {
  67. printf OUTPUTFILE ("%s\n", $archivedlines{$archivedlinecount});
  68. delete $archivedlines{$archivedlinecount};
  69. }
  70. $archivedlinecount = 0;
  71. $lastarchiveassocdirnum = "";
  72. $lastarchiveassocfile = "";
  73. }
  74. }
  75. ##############################################################################
  76. # Main
  77. ##############################################################################
  78. #
  79. # If we have no commandline arguments, abort with usage
  80. #
  81. if ($#ARGV < 0)
  82. {
  83. &ShowUsageInformation();
  84. }
  85. #
  86. # First, we read the current layout.inx file and extract the list of
  87. # directories and their associated numbers.
  88. #
  89. $currentinputfile = $ARGV[0];
  90. open(INPUTFILE, $currentinputfile)
  91. or die "\nCan't open input file $currentinputfile\n";
  92. $inDirectorySection = 0; # This variable will be set when we are
  93. # in the section of the file that has the
  94. # directory number -> directory mappings.
  95. LINE: while( $line = <INPUTFILE> )
  96. {
  97. # Chomp the trailing newline off; lowercase the line.
  98. chomp $line;
  99. $line = lc $line;
  100. #
  101. # If this line starts with a bracket, we are entering a new section.
  102. # Reset the "inDirectorySection" variable, and only set it if the
  103. # section name matches.
  104. #
  105. if ($line =~ /^\[/)
  106. {
  107. $inDirectorySection = 0;
  108. }
  109. if ($line eq "[winntdirectories]")
  110. {
  111. $inDirectorySection = 1;
  112. next LINE;
  113. }
  114. #
  115. # Skip lines outside of the targetted section and comment lines.
  116. #
  117. next LINE if (! $inDirectorySection);
  118. next LINE if ($line =~ /^@\*/);
  119. #
  120. # Extract the directory name from the line as everything on the
  121. # right side of the = sign, removing leading whitespace.
  122. # Also extract the directory number as the string of digits
  123. # immediately preceding the = sign, removing trailing whitespace.
  124. #
  125. ($directory = $line) =~ s/.*=\s*(.*)/$1/;
  126. ($dirnum = $line) =~ s/(.*:)?(\d*)\s*=.*/$2/;
  127. #
  128. # If this is a good line, the directory number will have been
  129. # extracted, save this directory into the masterdirectoryhash.
  130. #
  131. if ($dirnum)
  132. {
  133. $directory =~ s/^\"(.*)\"$/$1/;
  134. $directory =~ s/^(.*)\\$/$1/;
  135. $masterdirectoryhash{$directory} = $dirnum;
  136. }
  137. } # while (there is still data in this inputfile)
  138. close (INPUTFILE); # Close the input file...
  139. #
  140. # Now, we read the desired output order file and create the ordering
  141. # for this set of files.
  142. #
  143. $currentinputfile = $ARGV[1];
  144. open(INPUTFILE, $currentinputfile)
  145. or die "\nCan't open input file $currentinputfile\n";
  146. LINE: while( $line = <INPUTFILE> )
  147. {
  148. # Chomp the trailing newline off; lowercase the line.
  149. chomp $line;
  150. $line = lc $line;
  151. #
  152. # Extract the directory name from the line as everything to the
  153. # left of the last backslash (excluding the backslash itself).
  154. # Also extract the filename as everything to the right of the
  155. # last backslash (excluding the backslash itself).
  156. #
  157. ($directory = $line) =~ s/(.*)\\.*/$1/;
  158. ($filename = $line) =~ s/.*\\(.*)/$1/;
  159. #
  160. # Remove any leading backslash from the directory name.
  161. #
  162. $directory =~ s/^\\(.*)/$1/;
  163. #
  164. # If this is one of the directories we saw in the original layout.inx
  165. # file, add this filename/pathname combonation as the next file to
  166. # place. We save both a forward lookup: {FN, DN} -> number, and a
  167. # ordering lookup: number -> {FN, DN}.
  168. #
  169. if (exists($masterdirectoryhash{$directory}))
  170. {
  171. if ( (! exists($orderedfiles{$filename}))
  172. || (! exists($orderedfiles{$filename}{$masterdirectoryhash{$directory}})) )
  173. {
  174. $desiredoutputorder{$currentfilenumber}{FN} = $filename;
  175. $desiredoutputorder{$currentfilenumber}{DN} = $masterdirectoryhash{$directory};
  176. $orderedfiles{$filename}{$masterdirectoryhash{$directory}} = $currentfilenumber;
  177. $currentfilenumber++;
  178. }
  179. }
  180. } # while (there is still data in this inputfile)
  181. close (INPUTFILE); # Close the input file...
  182. #
  183. # Finally, we re-read the supplied layout.inx file, and simulataneously
  184. # create the output file. This file has the same name as the input file,
  185. # with ".new" appended to it.
  186. #
  187. $currentinputfile = $ARGV[0];
  188. open(INPUTFILE, $currentinputfile)
  189. or die "\nCan't open input file $currentinputfile\n";
  190. open(OUTPUTFILE, ">" . $currentinputfile . ".new")
  191. or die "\nCan't open output file $currentinputfile.new\n";
  192. $inFileSection = 0; # This variable will be set when we are
  193. # in any section of the file that has the
  194. # actual files' lines to be reordered.
  195. $archivedlinecount = 0; # These variables hold lines that are to
  196. $lastarchiveassocfile = ""; # be associated with the next real line
  197. $lastarchiveassocdirnum = ""; # such as comments, etc.
  198. LINE: while( $line = <INPUTFILE> )
  199. {
  200. # Chomp the trailing newline off.
  201. chomp $line;
  202. #
  203. # If this line starts with a bracket, we are entering a new section.
  204. # Reset the "inFileSection" variable, flush the file section's data,
  205. # and only set it if the section name matches.
  206. #
  207. if ($line =~ /^\[/)
  208. {
  209. $inFileSection = 0;
  210. &FlushFileSection();
  211. }
  212. if ($line =~ /^\[SourceDisksFiles/)
  213. {
  214. $inFileSection = 1;
  215. printf OUTPUTFILE ("%s\n", $line);
  216. next LINE;
  217. }
  218. #
  219. # Skip lines outside of the targetted section, simply copying them
  220. # into the output file.
  221. #
  222. if (! $inFileSection)
  223. {
  224. printf OUTPUTFILE ("%s\n", $line);
  225. next LINE;
  226. }
  227. #
  228. # If the line does not contain an equals sign, assume it is a comment.
  229. #
  230. if ($line !~ /=/)
  231. {
  232. #
  233. # If we are currently associated with an entry (it had comment lines
  234. # above it), add these new lines to the corresponding data hash.
  235. # Otherwise, archive these new lines to be associated later.
  236. #
  237. if ($lastarchiveassocdirnum)
  238. {
  239. $datalines{$lastarchiveassocfile}{$lastarchiveassocdirnum}{scalar(keys %{ $datalines{$lastarchiveassocfile}{$lastarchiveassocdirnum} })} = $line;
  240. }
  241. else
  242. {
  243. $archivedlines{$archivedlinecount} = $line;
  244. $archivedlinecount++;
  245. }
  246. }
  247. else
  248. {
  249. #
  250. # Extract the filename as everything to the left of the equals
  251. # sign (except the prodfilt tags), removing trailing whitespace.
  252. # Also, extract everything to the right of the equals as a set
  253. # of comma-delimited fields.
  254. #
  255. ($filename = $line) =~ s/(.*:)?(\S*.?\S*)\s*=.*/$2/;
  256. ($fields = $line) =~ s/.*=\s*(.*)/$1/;
  257. #
  258. # Split the fields along the commas and examine the eighth field.
  259. # Extract it as a number that represents the directory entry.
  260. #
  261. my @linefields = split(',', $fields);
  262. $dirnum = $linefields[7];
  263. $dirnum =~ s/\D*//g;
  264. #
  265. # Check the eleventh field. If it exists, use the contents of it,
  266. # stripping any trailing comments, as the real filename.
  267. #
  268. if ($#linefields > 9)
  269. {
  270. if ($linefields[10] ne "")
  271. {
  272. $filename = $linefields[10];
  273. $filename =~ s/;.*//;
  274. }
  275. }
  276. #
  277. # Strip any trailing whitespace from the filename.
  278. #
  279. $filename =~ s/ *$//g;
  280. #
  281. # If there were lines read before this one that need to be
  282. # associated with a data line (such as comments), add those
  283. # to the data hash for this entry now, removing them from
  284. # the temporary archived lines variable.
  285. # Now, set the lastarchiveassoc* variables so trailing
  286. # comments are mapped with this set.
  287. #
  288. if ($archivedlinecount > 0)
  289. {
  290. foreach $archivedlinecount (sort numerically keys %archivedlines)
  291. {
  292. $datalines{$filename}{$dirnum}{scalar(keys %{ $datalines{$filename}{$dirnum} })} = $archivedlines{$archivedlinecount};
  293. delete $archivedlines{$archivedlinecount};
  294. }
  295. $archivedlinecount = 0;
  296. $lastarchiveassocdirnum = $dirnum;
  297. $lastarchiveassocfile = $filename;
  298. }
  299. #
  300. # Reset the lastarchiveassoc* variables so the next comment
  301. # lines are not mapped with this entry, but are instead
  302. # archived for their successor.
  303. #
  304. else
  305. {
  306. $lastarchiveassocdirnum = 0;
  307. $lastarchiveassocfile = "";
  308. }
  309. #
  310. # Add the current line to the data hash for this entry.
  311. #
  312. $datalines{$filename}{$dirnum}{scalar(keys %{ $datalines{$filename}{$dirnum} })} = $line;
  313. #
  314. # If this file has not already been ordered (wasn't in the
  315. # supplied order file and hasn't already been seen), assign
  316. # it the next available slot and record the file as seen.
  317. #
  318. if ( (! exists($orderedfiles{$filename}))
  319. || (! exists($orderedfiles{$filename}{$dirnum})) )
  320. {
  321. $desiredoutputorder{$currentfilenumber}{FN} = $filename;
  322. $desiredoutputorder{$currentfilenumber}{DN} = $dirnum;
  323. $orderedfiles{$filename}{$dirnum} = $currentfilenumber;
  324. $currentfilenumber++;
  325. }
  326. }
  327. } # while (there is still data in this inputfile)
  328. close (INPUTFILE); # Close the input file...
  329. &FlushFileSection(); # Flush any data from the last section here
  330. close (OUTPUTFILE); # Close the output file...