Source code of Windows XP (NT5)
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.

691 lines
21 KiB

  1. @REM -----------------------------------------------------------------
  2. @REM
  3. @REM findinfdata - jtolman
  4. @REM Go through inf files and find install data for each file.
  5. @REM
  6. @REM Copyright (c) Microsoft Corporation. All rights reserved.
  7. @REM
  8. @REM -----------------------------------------------------------------
  9. @perl -x "%~f0" %*
  10. @goto :EOF
  11. #!perl
  12. use strict;
  13. use lib $ENV{RAZZLETOOLPATH} . "\\PostBuildScripts";
  14. use lib $ENV{RAZZLETOOLPATH} . "\\sp";
  15. use lib $ENV{RAZZLETOOLPATH};
  16. use Logmsg;
  17. use ParseArgs;
  18. use InfData;
  19. use InfParse;
  20. use CanonDir qw(%misses addPrefix removePrefix);
  21. sub Usage { print<<USAGE; exit(1) }
  22. Usage: findinfdata [options] <bin_dir> /f <out_file>
  23. /f: File to output the results to.
  24. /c: Use information from a change file.
  25. /w Include WOW files.
  26. /xs Ignore server skus.
  27. /xc Ignore client skus.
  28. /i Remake infscan.lst using infscan before reading it.
  29. /o Write using original directory structure.
  30. /s Read infs from service pack directory structure.
  31. /b Read infs from the binaries directory.
  32. /l Language to run for.
  33. USAGE
  34. my ($outfile, $dir, $infscan, $altpath, $template, $newfile, $wow, $binaries, $lang, $servpack);
  35. my @changes;
  36. my ($xserver, $xclient);
  37. parseargs('?' => \&Usage,
  38. 'f:'=> \$outfile,
  39. 'c:'=> \@changes,
  40. 'w' => \$wow,
  41. 'xs'=> \$xserver,
  42. 'xc'=> \$xclient,
  43. 'i' => \$infscan,
  44. 'o' => \$altpath,
  45. 's' => \$servpack,
  46. 'b' => \$binaries,
  47. 'l:'=> \$lang,
  48. \$dir
  49. );
  50. undef $wow if $binaries and lc$ENV{_BUILDARCH} ne "ia64";
  51. $wow = 1 if $binaries and lc$ENV{_BUILDARCH} eq "ia64";
  52. if ($altpath) { undef $altpath; }
  53. else { $altpath = 1; }
  54. my $arch = $wow ? "ia64":"i386";
  55. my $barch = $wow ? "ia64":"x86";
  56. my $archd = $wow ? "ia64":"w32x86";
  57. $lang = $ENV{LANG} if !defined $lang;
  58. $lang = "usa" if !defined $lang or $lang eq "";
  59. my $slp = "";
  60. my $slpdir;
  61. my $bindir;
  62. my $wowdir;
  63. if ( $binaries ) {
  64. $bindir = "$dir";
  65. $wowdir = "$dir\\wowbins";
  66. }
  67. elsif ( $servpack ) {
  68. $bindir = "$dir\\bin";
  69. $slpdir = "$dir\\slp";
  70. $wowdir = "$dir\\bin\\wowbins";
  71. }
  72. else {
  73. $bindir = "$dir\\bin";
  74. $slpdir = "$dir";
  75. $wowdir = "$dir\\bin\\wowbins_uncomp";
  76. }
  77. ######################################################################
  78. # Define main data structures.
  79. my %files; # Main table of files and directories.
  80. my %relfiles; # All files with multiple versions.
  81. # List of skus to examine: BitMask SkuName CongealScriptsName
  82. my $skumax = 7; # Max # of bits in the this list. Change as needed.
  83. my @skus = ();
  84. my @skuletters = ();
  85. if ( !$xclient ) {
  86. push @skus, "1, pro, wks";
  87. push @skus, "2, per, per" if $arch ne "ia64";
  88. push @skuletters, ("p", "c");
  89. }
  90. if ( !$xserver ) {
  91. push @skus, "4, srv, srv" if $arch ne "ia64";
  92. push @skus, "8, ads, ent";
  93. push @skus, "16, dtc, dtc";
  94. # push @skus, "32, sbs, sbs" if $arch ne "ia64";
  95. # push @skus, "64, bla, bla" if $arch ne "ia64";
  96. push @skuletters, ("s", "a", "d");
  97. # push @skuletters, ("l", "b");
  98. }
  99. my $skumask = 0;
  100. my $skucount = 0;
  101. my $type;
  102. my $prod;
  103. my $boot;
  104. CanonDir::setup( $archd, $arch );
  105. # List of info on relative paths to use with /r.
  106. my %relpath;
  107. if ( $altpath ) {
  108. %relpath = (
  109. 0x1 => "ip\\",
  110. 0x2 => "ic\\",
  111. 0x4 => "is\\",
  112. 0x8 => "ia\\",
  113. 0x1c => "is\\", # Remove when il and ib are used.
  114. 0x7c => "is\\",
  115. 0x18 => "ia\\",
  116. 0x10 => "id\\",
  117. 0x20 => "il\\",
  118. 0x40 => "ib\\",
  119. );
  120. } else {
  121. %relpath = (
  122. 0x2 => "perinf\\",
  123. 0x7c => "srvinf\\",
  124. 0x18 => "entinf\\",
  125. 0x10 => "dtcinf\\",
  126. 0x20 => "sbsinf\\",
  127. 0x40 => "blainf\\",
  128. );
  129. }
  130. my %infpath = (
  131. "proinf" => 0x1,
  132. "perinf" => 0x2,
  133. "srvinf" => 0x7c,
  134. "entinf" => 0x18,
  135. "dtcinf" => 0x10,
  136. "blainf" => 0x20,
  137. "sbsinf" => 0x40
  138. );
  139. my @pathorder = ("sbsinf","blainf","dtcinf","perinf","entinf","srvinf", "");
  140. my %buildorder = (
  141. "pro" => "\\",
  142. "per" => "\\ \\perinf\\",
  143. "srv" => "\\ \\srvinf\\",
  144. "bla" => "\\ \\srvinf\\ \\blainf\\",
  145. "sbs" => "\\ \\srvinf\\ \\sbsinf\\",
  146. "ads" => "\\ \\srvinf\\ \\entinf\\",
  147. "dtc" => "\\ \\srvinf\\ \\entinf\\ \\dtcinf\\",
  148. );
  149. # Format: ANSI_Codepage LCID
  150. my %langinfo = (
  151. "ara" => 1256,
  152. "br" => 1252,
  153. "chh" => 950,
  154. "chs" => 936,
  155. "cht" => 950,
  156. "cs" => 1250,
  157. "da" => 1252,
  158. "el" => 1253,
  159. "es" => 1252,
  160. "fi" => 1252,
  161. "fr" => 1252,
  162. "ger" => 1252,
  163. "heb" => 1255,
  164. "hu" => 1250,
  165. "it" => 1252,
  166. "jpn" => 932,
  167. "kor" => 949,
  168. "nl" => 1252,
  169. "no" => 1252,
  170. "pl" => 1250,
  171. "psu" => 1253,
  172. "pt" => 1252,
  173. "ru" => 1251,
  174. "sv" => 1252,
  175. "tr" => 1254,
  176. "usa" => 1252
  177. );
  178. my $cpage = 1252;
  179. $cpage = $langinfo{$lang} if exists $langinfo{$lang};
  180. my %layids; # List of dirid definitions for layout.inf.
  181. my %unknowns; # Used to keep track of warnings.
  182. ######################################################################
  183. # Subroutines used for managing data in the %files data structure.
  184. # Add an installation directory to a file's list.
  185. sub addEntry {
  186. my ($source, $dirid, $path, $name, $bit) = @_;
  187. $source = lc $source;
  188. $name = lc $name;
  189. my $src = $source;
  190. $src = "$3$1" if $source =~ /^([^\\]*)(\\(.*\\))?/;
  191. my $entry = InfData->new($src, $dirid, $path, $name, $bit);
  192. foreach my $ent ( @{ $files{$source} } ) {
  193. return if $ent->addBit($entry);
  194. }
  195. if ( !exists $files{$source} ) {
  196. if ($dirid != 65619) {
  197. $files{$source} = [ () ];
  198. } else {
  199. $unknowns{"$source\t$name"} = "";
  200. return;
  201. }
  202. }
  203. push @{ $files{$source} }, $entry;
  204. }
  205. # Get a list of a file's installation directories.
  206. sub getEntries {
  207. my ($source) = @_;
  208. if ( !exists $files{$source} ) {
  209. print LOG "Unknown file: $source\n";
  210. return ();
  211. }
  212. return @{ $files{$source} };
  213. }
  214. ######################################################################
  215. # Start processing.
  216. # Create a log file.
  217. $outfile =~ /^(.*\\)?([^\\]*)$/;
  218. my $outdir = $1;
  219. my $logfile;
  220. $logfile = "$outdir\Efindinfdata.$arch.$lang.log" if !defined $binaries;
  221. $logfile = "$ENV{TEMP}\\findinfdata.$arch$ENV{_BuildType}.$lang.out" if defined $binaries;
  222. if ( !open LOG, ">$logfile" ) {
  223. errmsg( "Unable to open logfile: $logfile" );
  224. die;
  225. }
  226. # Run infscan for each sku, as needed.
  227. my $curbuild = "";
  228. my $tmp = "$ENV{TEMP}\\infscan.$arch$ENV{_BuildType}.$lang";
  229. foreach my $skudata ( @skus ) {
  230. my ($bit, $sku, $cgsku) = split(/\s*,\s*/, $skudata);
  231. my $infscanfile;
  232. $infscanfile = "$outdir\Einfscan.$arch.$lang.$sku.lst" if !defined $binaries;
  233. $infscanfile = "$ENV{TEMP}\\infscan.$arch$ENV{_BuildType}.$lang.$cgsku.lst" if defined $binaries;
  234. my $infdir;
  235. $infdir = "$slpdir\\$sku\\$arch";
  236. if ( $infscan or !-f $infscanfile ) {
  237. logmsg( "Scanning infs for $sku..." );
  238. my $lg;
  239. $lg = "$outdir\Escan.$arch.$lang.$sku.log" if !defined $binaries;
  240. $lg = "$ENV{TEMP}\\infscan.$arch$ENV{_BuildType}.$lang.$cgsku.log" if defined $binaries;
  241. my $filt;
  242. $filt = "$outdir\Efilter.$arch.$lang.$sku.inf" if !defined $binaries;
  243. $filt = "$ENV{TEMP}\\filter.$arch$ENV{_BuildType}.$lang.$cgsku.inf" if defined $binaries;
  244. if ( !$binaries ) {
  245. system "rmdir /s /q $tmp >nul 2>&1";
  246. system "mkdir $tmp >nul 2>&1";
  247. system "copy $infdir\\*.inf $tmp > $lg 2>nul";
  248. system "copy $infdir\\*.in_ $tmp >> $lg 2>nul";
  249. system "copy $infdir\\lang\\*.inf $tmp >> $lg 2>nul";
  250. system "copy $infdir\\lang\\*.in_ $tmp >> $lg 2>nul";
  251. system "expand -r $tmp\\*.in_ >nul 2>nul";
  252. system "del /q $tmp\\*.in_ >nul 2>nul";
  253. } else {
  254. my $build = $buildorder{$sku};
  255. my $temp = $build;
  256. $build =~ s/^\Q$curbuild \E//i;
  257. $curbuild = $temp;
  258. my @build = split(" ", $build);
  259. foreach my $loc ( @build ) {
  260. logmsg "Copying from $loc.";
  261. if ( $loc eq "\\" ) {
  262. system "rmdir /s /q $tmp >nul 2>&1";
  263. system "mkdir $tmp >nul 2>&1";
  264. system "copy $bindir\\lang\\*.inf $tmp >> $lg 2>nul";
  265. }
  266. my $infdir = "$bindir$loc";
  267. system "copy $infdir*.inf $tmp > $lg 2>nul";
  268. }
  269. }
  270. if ( $cpage ) {
  271. foreach my $file ( `dir /b /s $tmp\\*.inf` ) {
  272. chomp $file;
  273. system "unitext -u -$cpage -z $file $file\.2 >nul 2>nul";
  274. system "move /y $file\.2 $file >nul 2>nul";
  275. }
  276. }
  277. logmsg( "Generating filter.inf..." );
  278. system "infscan /R /G /V ntx86 /D /C $filt $tmp >> $lg 2>&1";
  279. logmsg( "Running infscan..." );
  280. system "infscan /G /F $filt /Q $infscanfile $tmp >> $lg 2>&1";
  281. }
  282. }
  283. system "rmdir /s /q $tmp >nul 2>nul";
  284. # Do infscan and layout.inf parse for each sku.
  285. foreach my $skudata ( @skus ) {
  286. my ($bit, $sku, $cgsku) = split(/\s*,\s*/, $skudata);
  287. logmsg( "Processing sku $sku:" );
  288. $skumask |= $bit;
  289. $skucount++;
  290. # Read in the infscan information.
  291. logmsg( "Reading infscan information..." );
  292. my $infscanfile;
  293. $infscanfile = "$outdir\Einfscan.$arch.$lang.$sku.lst" if !defined $binaries;
  294. $infscanfile = "$ENV{TEMP}\\infscan.$arch$ENV{_BuildType}.$lang.$cgsku.lst" if defined $binaries;
  295. if ( !open INFSCAN, $infscanfile ) {
  296. errmsg( "Couldn't find $infscanfile" );
  297. die;
  298. }
  299. while ( <INFSCAN> ) {
  300. if ( /^\"([^\"]*)\",(\d*),(\"([^\"]*)\")?,\"([^\"]*)\",(\d),\"([^\"]*)\"(,\"([^\"]*)\")?\s*$/ ) { # "
  301. my ($source, $dirid, $subdir, $target, $flag, $inf, $sect) = ($1,$2,$4,$5,$6,$7,$9);
  302. if ( $dirid eq "" ) {
  303. $unknowns{"$source\t$target"} = "";
  304. next;
  305. }
  306. $source = "$2\\$1" if $source =~ /^(.*\\)([^\\]*)$/;
  307. $subdir = addPrefix($dirid, lc $subdir, %CanonDir::scanids);
  308. ($dirid, $subdir) = removePrefix($subdir, %CanonDir::revids);
  309. addEntry($source, $dirid, $subdir, $target, $bit);
  310. } else {
  311. chomp;
  312. print LOG "Line omitted: $_\n"
  313. }
  314. }
  315. close INFSCAN;
  316. # Read in the layout.inf information.
  317. logmsg( "Reading layout.inf information..." );
  318. my $infdir;
  319. $infdir = "$bindir" if $sku eq "pro";
  320. $infdir = "$bindir\\$cgsku\Einf" if $sku ne "pro";
  321. my %layf;
  322. if ( open INF, "$infdir\\layout.inf" ) {
  323. $_ = parseSect(sub { return; });
  324. while ( /^\[/ ) {
  325. if ( /^\s*\[SourceDisksFiles(\.\w*)?\]\s*$/i and ($1 eq "" or lc$1 eq ".$barch") ) {
  326. # Process a list of files and data.
  327. $_ = parseSect(sub {
  328. my ($layf, $data) = split(/\s*=\s*/,$_[0]);
  329. my @fields = split(/\s*,\s*/, $data);
  330. $layf{lc $layf} = [ @fields ];
  331. } );
  332. }
  333. elsif ( /^\s*\[WinntDirectories\]\s*$/i ) {
  334. # Process a list of directories and their numbers.
  335. $_ = parseSect(sub {
  336. my ($num, $dest) = split(/\s*=\s*/);
  337. $dest = $1 if $dest=~/^\"\\?([^\"]*)\"$/; # "
  338. $layids{$num} = lc $dest;
  339. } );
  340. }
  341. elsif ( /^\s*\[Strings\]\s*$/i ) {
  342. # Process a list of localization strings.
  343. $_ = parseSect( \&parseStr );
  344. }
  345. else {
  346. $_ = parseSect(sub { return; });
  347. }
  348. }
  349. close INF;
  350. # Insert strings into directory names.
  351. foreach my $num (keys %layids) {
  352. $layids{$num} = strSub($layids{$num});
  353. }
  354. # Figure out where the files go.
  355. foreach my $file (keys %layf) {
  356. my @data = @{ $layf{$file} };
  357. my $target = strSub($data[10]);
  358. $target = $file if $target eq "";
  359. if ( $file =~ /\.cat$/i ) {
  360. addEntry($file, 65619, "", $target, $bit);
  361. addEntry($file, 65535, ".cat", $target, $bit);
  362. next;
  363. }
  364. my $ofile = $file;
  365. $file = "$2\\$1" if $file =~ /^(.*\\)([^\\]*)$/;
  366. my $dirid = $data[7];
  367. if ( $dirid ne "" ) {
  368. my $path = addPrefix($dirid, "", %layids);
  369. ($dirid, $path) = removePrefix($path, %CanonDir::revids);
  370. addEntry($file, $dirid, $path, $target, $bit);
  371. } else {
  372. $unknowns{"$ofile\t$target"} = "";
  373. }
  374. }
  375. undef %InfParse::strings;
  376. undef %layids;
  377. }
  378. # Determine what entries go in Cache.files.
  379. logmsg( "Reading cache file information..." );
  380. my $cachedir = "$bindir\\congeal_scripts\\autogen\\";
  381. if ( open CACHE, "$cachedir$barch\_$cgsku.h" ) {
  382. while ( <CACHE> ) {
  383. next if !/^\s*{\s*(NULL|L\"([^\"]*)\"\s*),\s*L\".*\\\\([^\\\"]*)\"\s*,.*},?\s*$/; # "
  384. my $src = $3;
  385. $src = $2 if defined $2 and $2 ne "";
  386. $src =~ /^(.*\\)?([^\\]*)$/;
  387. my $dest = $2;
  388. $src = "$2\\$1" if defined $1;
  389. addEntry($src, 65619, "", $dest, $bit);
  390. }
  391. close CACHE;
  392. }
  393. }
  394. # Print various warnings.
  395. foreach my $key (keys %misses) {
  396. my $count = $misses{$key} / $skucount;
  397. print LOG "Unknown dirID ($count+ files affected): $key\n";
  398. }
  399. undef %misses;
  400. foreach my $file (sort keys %unknowns) {
  401. $file = lc $file;
  402. my ($source, $target) = split(/\t/, $file);
  403. if ( !defined $files{$source} ) {
  404. print LOG "Directory not known: $source\n";
  405. next;
  406. }
  407. next if $target eq $source;
  408. my $test = 0;
  409. foreach my $entry (getEntries($source)) {
  410. $test = 1 if lc $entry->{NAME} eq $target;
  411. }
  412. print LOG "Lost target name for $source: $target\n" if !$test;
  413. }
  414. undef %unknowns;
  415. # Handle WOW files.
  416. if ( $arch eq "ia64" ) {
  417. # Get a list of wow files to generate.
  418. logmsg( "Examining WOW files..." );
  419. if ( !-d $wowdir ) {
  420. errmsg( "Unable to find wow directory." );
  421. die;
  422. }
  423. foreach my $wow (`dir /b /s /a-d $wowdir\\w*`) {
  424. $wow =~ s/^\Q$wowdir\E\\//;
  425. if ( $wow =~ /^\s*(.*\\)?w([^\\]*[^\\\s])\s*$/ ) {
  426. my $file = $2;
  427. my $wfile = "w$2";
  428. my $dir = $altpath ? "wow\\$1":"wowbins_uncomp\\$1";
  429. my $key = $wfile;
  430. $key = "$wfile\\$dir" if exists $files{"$wfile\\$dir"};
  431. if ( exists $files{$key} ) {
  432. foreach my $entry ( @{ $files{$key} } ) {
  433. $entry->setSrcDir($dir);
  434. }
  435. my $entries = $files{$key};
  436. delete $files{$key};
  437. $files{"$wfile\\$dir"} = $entries;
  438. }
  439. }
  440. }
  441. }
  442. # Put appropriate stuff in the lang directory.
  443. my %temp;
  444. if ( !$binaries ) {
  445. my $prodir = "$slpdir\\pro\\$arch";
  446. foreach my $file ( `dir /a-d /b $prodir` ) {
  447. $file =~ s/^\Q$prodir\E\\//i;
  448. $file =~ s/\s*$//;
  449. $temp{lc $file} = "";
  450. }
  451. }
  452. my $langdir = "$bindir\\lang";
  453. foreach my $file ( `dir /a-d /b $langdir` ) {
  454. $file =~ s/^\Q$langdir\\//i;
  455. $file =~ s/\s*$//;
  456. $file = lc $file;
  457. next if $file =~ /\\/;
  458. next if !exists $files{$file};
  459. $file =~ /^([^\.]*(\..?.?)).?$/;
  460. next if exists $temp{$file} or exists $temp{"$1_"};
  461. my $list = $files{$file};
  462. delete $files{$file};
  463. foreach my $entry ( @$list ) {
  464. $entry->setSrcDir("lang");
  465. }
  466. $files{"$file\\lang\\"} = $list;
  467. }
  468. undef %temp;
  469. if ( $altpath ) {
  470. foreach my $val ( keys %relpath ) {
  471. delete $relpath{$val} if $val == $skumask;
  472. }
  473. }
  474. # Parse a command file, if specified.
  475. logmsg( "Processing change files..." );
  476. @changes = () if !defined @changes;
  477. foreach my $changefile ( @changes ) {
  478. if ( !open CHANGE, $changefile ) {
  479. errmsg( "Unable to open $changefile." );
  480. die;
  481. }
  482. while ( <CHANGE> ) {
  483. next if /^\s*(\#.*)?$/;
  484. if ( /^\s*([^\=]*\S)\s*=\s*(.*\S)\s*$/ ) {
  485. my $filename = lc $1;
  486. my $file = $filename;
  487. my $cmd = lc $2;
  488. $file = "$2\\$1\\" if $file =~ /^(.*)\\([^\\]*)$/;
  489. if ( defined $files{$file} ) {
  490. if ( $cmd eq "dontwait" ) {
  491. # This file should be copied before reboot.
  492. foreach my $entry ( @{ $files{$file} } ) {
  493. $entry->{WHEN} = "dontdelayuntilreboot";
  494. }
  495. }
  496. elsif ( $cmd =~ /^type\s*:\s*(.*\S)\s*$/ ) {
  497. # This file belongs to a non-obvious inf section group.
  498. my $spec = lc $1;
  499. foreach my $entry ( @{ $files{$file} } ) {
  500. $entry->{SPEC} = $spec;
  501. }
  502. }
  503. elsif ( $cmd =~ /^dir\s*:\s*(.*)$/ ) {
  504. # This file goes in an unusual source directory.
  505. my $newdir = lc $1;
  506. $newdir = "" if !defined $newdir;
  507. my $entries = $files{$file};
  508. foreach my $entry ( @$entries ) {
  509. $entry->setSrcDir($newdir);
  510. }
  511. delete $files{$file};
  512. $file =~ /^([^\\]*)(\\.*)?$/;
  513. $file = $1;
  514. $files{"$file\\$newdir\\"} = $entries;
  515. }
  516. elsif ( $cmd =~ /^flag\s*:\s*(.*)$/ ) {
  517. my $flag = lc $1;
  518. foreach my $entry ( @{ $files{$file} } ) {
  519. next if $entry->{DIRID} == 65619;
  520. $entry->{FLAG} = $flag;
  521. }
  522. }
  523. elsif ( $cmd =~ /^temp\s*:\s*(.*)$/ ) {
  524. my $temp = lc $1;
  525. foreach my $entry ( @{ $files{$file} } ) {
  526. $entry->{TEMP} = $temp;
  527. }
  528. }
  529. else {
  530. wrnmsg "Unknown change file command: $cmd";
  531. }
  532. } else {
  533. wrnmsg "Unknown entry in change file: $filename";
  534. next;
  535. }
  536. }
  537. elsif ( /^\s*ADD\s*/ ) {
  538. while ( <CHANGE> ) {
  539. last if /^\s*END\s*$/;
  540. next if /^\s*(\#.*)?$/;
  541. chomp;
  542. my $entry = InfData->new();
  543. if ( !$entry->readLine($_,\@skuletters) ) {
  544. wrnmsg "Line omitted:\n$_";
  545. next;
  546. }
  547. my $file = $entry->getSrcDir();
  548. $file = $entry->getSrc() . "\\$file" if defined $file;
  549. $file = $entry->getSrc() if !defined $file;
  550. my $test = 0;
  551. foreach my $ent ( @{ $files{$file} } ) {
  552. $test = 1 if $ent->addBit($entry);
  553. }
  554. next if $test;
  555. $files{$file} = [ () ] if !exists $files{$file};
  556. push @{ $files{$file} }, $entry;
  557. }
  558. }
  559. elsif ( /^\s*DELETE\s*/ ) {
  560. while ( <CHANGE> ) {
  561. last if /^\s*END\s*$/;
  562. next if /^\s*(\#.*)?$/;
  563. chomp;
  564. my $entry = InfData->new();
  565. if ( !$entry->readLine($_,\@skuletters) ) {
  566. wrnmsg "Line omitted:\n$_";
  567. next;
  568. }
  569. my $file = $entry->getSrcDir();
  570. if ($file ne "") { $file = $entry->getSrc() . "\\$file"; }
  571. else { $file = $entry->getSrc(); }
  572. next if !exists $files{$file};
  573. my @newlist = ();
  574. foreach my $ent ( @{ $files{$file} } ) {
  575. my $newent = $ent->delBit($entry);
  576. push @newlist, $newent if defined $newent;
  577. }
  578. if ($#newlist >= 0) { $files{$file} = [ @newlist ]; }
  579. else { delete $files{$file}; }
  580. }
  581. }
  582. }
  583. close CHANGE;
  584. }
  585. # If need relative paths, need to find all of the affected files.
  586. logmsg( "Finding different file versions..." );
  587. foreach my $sku ( @pathorder ) {
  588. next if ($infpath{$sku} & $skumask) == 0;
  589. foreach my $file ( `dir /a-d /b /s $bindir\\$sku` ) {
  590. $file =~ s/^\Q$bindir\E\\//i;
  591. chomp $file;
  592. $file =~ /\\([^\\]*)$/;
  593. next if !exists $files{lc $1} and !exists $files{lc $file};
  594. $relfiles{lc $file} = "";
  595. }
  596. }
  597. # Generate the table.
  598. logmsg( "Generating the table..." );
  599. if ( !open OUT, ">$outfile" ) {
  600. errmsg( "Unable to open $outfile." );
  601. die;
  602. }
  603. # Step through the files.
  604. foreach my $file (sort keys %files) {
  605. # Figure out what versions of the file exist.
  606. my @vers = ();
  607. foreach my $entry ( getEntries($file) ) {
  608. my @list = ();
  609. my $mask = $entry->{MASK};
  610. foreach my $ver (@vers) {
  611. $ver = $mask if ($ver|$mask) == $mask;
  612. $mask = 0 if ($ver|$mask) == $ver;
  613. push @list, $ver;
  614. }
  615. push @list, $mask if $mask != 0;
  616. @vers = @list;
  617. }
  618. # Process each entry for each file.
  619. foreach my $entry ( getEntries($file) ) {
  620. my $fullmask;
  621. my $mask = $entry->{MASK};
  622. foreach my $ver (@vers) {
  623. $fullmask = $ver if ($ver|$mask) == $ver;
  624. }
  625. my $fullpath = $entry->getFullPath();
  626. my $myfile = $entry->getSrc();
  627. my $mypath = $entry->getSrcDir();
  628. # Break up by directory if more than one version exists.
  629. foreach my $skudir ( @pathorder ) {
  630. my $pathmask = 0;
  631. my $subdir;
  632. if ( exists $infpath{$skudir} ) {
  633. $pathmask = $infpath{$skudir};
  634. } else {
  635. $pathmask = $fullmask;
  636. }
  637. $subdir = $relpath{$pathmask};
  638. $subdir = "" if !$subdir or (!$altpath and $skudir eq "") or $mypath ne "";
  639. $subdir = "$mypath$subdir" if $mypath ne "\\";
  640. my $filename = "$subdir$myfile";
  641. $pathmask &= $skumask;
  642. $pathmask &= $fullmask;
  643. next if ($pathmask & $mask) == 0;
  644. next if $skudir ne "" and !exists $relfiles{lc "$skudir\\$myfile"};
  645. $fullmask &= ~$pathmask;
  646. # Add the entry needed for this version.
  647. $entry->{MASK} = $pathmask & $mask;
  648. $entry->{NAME} = $filename;
  649. print OUT $entry->getLine(\@skuletters);
  650. print OUT "\n";
  651. }
  652. }
  653. }
  654. close OUT;