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.

4616 lines
122 KiB

  1. # /////////////////////////////////////////////////////////////////////////////////////////////
  2. # Method calling graph
  3. # --------------------
  4. # -> ParseCmdLine -> PrintHelp
  5. # -> AddTarget
  6. # -> CleanLogFiles
  7. # -> GetSysdir
  8. # -> LoadEnv
  9. # -> LoadHotFix
  10. # -> LoadCodes
  11. # -> LoadReposit -> LoadKeys -> SetField
  12. # -> IsHashKey
  13. # -> AddTargetPath
  14. # -> LoadCmd -> IsRepositKey
  15. # -> PushFieldVal
  16. # -> ReadSysfile(R) -> ReplaceVar
  17. # -> SetIfFlag -> ReplaceVar
  18. # -> SetAttribOp -> ReplaceVar
  19. # -> GetMappingType
  20. # -> ReadBlock -> SetIfFlag -> ReplaceVar
  21. # -> SetAttribOp -> ReplaceVar
  22. # -> ReplaceVar
  23. # -> ReadLine -> ReplaceVar
  24. # -> LoadRecord -> LineToRecord
  25. # -> IsLangOK
  26. # -> AddRecord(R) -> LogRecord
  27. # -> VerifyCover -> Create_Tree_Branch -> Get_Except
  28. # -> Remove_Dummy_Create_Branch
  29. # -> Remove_Root_List
  30. # -> Find_UnMapping
  31. # -> PopulateReposit -> FillFilter -> IsEmptyHash
  32. # -> AddFiles -> AddEntry -> IsEmptyHash
  33. # -> IsHashKey
  34. # -> AddFileInfo -> IsRepositKey
  35. # -> IsHashKey
  36. # -> AddTargetPath
  37. # -> SetField
  38. # -> IsEmptyHash
  39. # -> IsHashKey
  40. # -> IsFoundTarget
  41. # -> FillTokens -> IsRsrcTok
  42. # -> FillTokEntry -> IsEmptyHash
  43. # -> IsHashKey
  44. # -> FillTokInfo -> ExistsBinForTok -> IsRepositKey
  45. # -> GetFieldVal
  46. # -> IsRepositKey
  47. # -> GetFieldVal
  48. # -> SetField
  49. # -> IsBgnTok
  50. # -> fullnamevalue
  51. # -> TokToFile -> IsRsrcTok
  52. # -> IsBgnTok
  53. # -> IsCustRes
  54. # -> FillCmd -> IsEmptyHash
  55. # -> IsHashKey
  56. # -> GetFieldVal
  57. # -> RecordToCmd -> IsXcopyCmd -> GetFieldVal
  58. # -> GenXcopy -> ImageToSymbol
  59. # -> GetFieldVal
  60. # -> SetSymPaths
  61. # -> MakeXcopyCmd
  62. # -> PushFieldVal
  63. # -> IsLocCmd -> GetFieldVal
  64. # -> GenLocCmd -> IsBgnOp -> IsBgnTok
  65. # -> GetFieldVal
  66. # -> GenBgnCmd -> ImageToSymbol
  67. # -> GetFieldVal
  68. # -> SetSymPaths
  69. # -> MakeXcopyCmd
  70. # -> GetLocOpType
  71. # -> SetBgnSymSw
  72. # -> GetLangCodes
  73. # -> GetBgnCodePageSw
  74. # -> GetBgnICodesSw -> GetLangCodes
  75. # -> GetBgnMultitok -> GetFieldVal
  76. # -> DeleteKey
  77. # -> GetBgnSw
  78. # -> PushFieldVal
  79. # -> IsRsrcOp -> IsRsrcTok
  80. # -> GenRsrcCmd -> ImageToSymbol
  81. # -> GetFieldVal
  82. # -> SetSymPaths
  83. # -> MakeXcopyCmd
  84. # -> GetLocOpType
  85. # -> GetLangNlsCode -> GetLangCodes
  86. # -> SetRsrcSymSw
  87. # -> PushFieldVal
  88. # -> GetFieldVal
  89. # -> IsRepositKey
  90. # -> GenMUICmd -> GetLangNlsCode -> GetLangCodes
  91. # -> GetFieldVal
  92. # -> PushFieldVal
  93. #-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  94. # SYNTAX_CHECK_ONLY -> SumErrors -> exit
  95. #-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  96. # -> GenNmakeFiles -> UpdTargetEntries -> IsEmptyHash
  97. # -> DeleteKey
  98. # -> SetField
  99. # -> GetFieldVal
  100. # -> FillSyscmd -> IsEmptyHash
  101. # -> CmdCompare -> GetFieldVal
  102. # -> GenMakeDir -> SetField
  103. # -> PushFieldVal
  104. # -> FixRepository
  105. # -> WriteToMakefile -> WriteSysgenTarget -> IsEmptyHash
  106. # -> WriteAllTarget -> IsEmptyHash
  107. # -> GetFieldVal
  108. # -> WriteFileCmds -> IsEmptyHash
  109. # -> WriteToSyscmd -> IsEmptyHash
  110. # -> SumErrors
  111. # //////////////////////////////////////////////////////////////////////////////////////////////
  112. use Data::Dumper;
  113. my $DEBUG=0;
  114. my $DEBUG_SYMBOLCD=0;
  115. my $PARSESYMBOLCD = 0;
  116. my $SYNTAX_CHECK_ONLY = undef;
  117. my $FULLCHECK = undef;
  118. my $DLINE = "RIGHT : LEFT";
  119. # Global Constants
  120. # MAP_ERR: Errors SYSGEN recognizes
  121. # 1101 is used for ERROR instructions found in sysfiles
  122. require 5.003;
  123. use lib $ENV{ "RazzleToolPath" };
  124. use cklang;
  125. %MAP_ERR = (
  126. 1001, "sysfile not found",
  127. 1002, "file not found",
  128. 1003, "file not found: unable to run sysgen incrementally",
  129. 1004, "target file not found",
  130. 1005, "filter file not found",
  131. 1006, "unable to open file for reading",
  132. 1007, "unable to open file for writing",
  133. 1008, "/F option requires a filename",
  134. 1009, "target not found in filter file",
  135. 1101, "",
  136. 1110, "syntax error",
  137. 1111, "syntax error: ENDIF unexpected",
  138. 1112, "syntax error: IF unexpected",
  139. 1113, "syntax error: END_MAP unexpected",
  140. 1114, "syntax error: BEGIN_*_MAP unexpected",
  141. 1115, "syntax error: INCLUDE unexpected",
  142. 1116, "syntax error: unknown operator in expression",
  143. 1117, "syntax error: \")\" missing in macro invocation",
  144. 1118, "syntax error: incomplete description line",
  145. 1119, "syntax error: unknown mapping type",
  146. 1120, "syntax error: unmatched IF",
  147. 1121, "syntax error: unmatched BEGIN_*_MAP",
  148. 1210, "file format error: target not found",
  149. 1211, "file format error: target not listed in \"all\"",
  150. 1212, "file format error: no description blocks found for files",
  151. 1213, "file format error: \"sysgen\" target not found",
  152. 1214, "file format error: filename with special characters",
  153. 1215, "file format error: Similar target found",
  154. 1910, "unknown language",
  155. 1911, "missing or duplicated entry for language",
  156. 1912, "incomplete entry for language",
  157. 1913, "unknown class for language",
  158. 2011, "no binary found for token",
  159. 2012, "duplicated tokens",
  160. 2013, "unknown token type (bingen or rsrc)",
  161. 2014, "unexpected token for already localized binary",
  162. 2015, "input bingen token not found for multi",
  163. 2016, "no bingen token found for custom resource",
  164. 2017, "unknown bingen token extension in token filename",
  165. 2018, "both bingen and rsrc tokens found",
  166. 2019, "custom resource found for rsrc token",
  167. 2020, "custom resource with no token",
  168. 2051, "sysfile error: undefined source path to verify",
  169. 2052, "folder not covered in sysfiles",
  170. 2101, "binary not found",
  171. 2102, "token not found",
  172. 3011, "internal error: unknown operation type",
  173. 4001, "filename with whitespace not aggregated",
  174. ); # MAP_ERR
  175. # MAP_BINGEN_TOK_EXT: Bingen token extensions SYSGEN recognizes
  176. %MAP_BINGEN_TOK_EXT =(
  177. '.a_', '.ax',
  178. '.ac_', '.acm',
  179. '.ax_', '.ax',
  180. '.bi_', '.bin',
  181. '.cn_', '.cnv',
  182. '.co_', '.com',
  183. '.cp_', '.cpl',
  184. '.dl_', '.dll',
  185. '.dr_', '.drv',
  186. '.ds_', '.ds',
  187. '.ef_', '.efi',
  188. '.ex_', '.exe',
  189. '.fl_', '.flt',
  190. '.im_', '.ime',
  191. '.mo_', '.mod',
  192. '.ms_', '.mst',
  193. '.oc_', '.ocx',
  194. '.rs_', '.rsc',
  195. '.sc_', '.scr',
  196. '.sy_', '.sys',
  197. '.tl_', '.tlb',
  198. '.ts_', '.tsp',
  199. '.wp_', '.wpc',
  200. ); # MAP_BINGEN_TOK_EXT
  201. # MAP_RSRC_TOK_EXT: Rsrc token extensions SYSGEN recognizes
  202. %MAP_RSRC_TOK_EXT =(
  203. '.rsrc', '',
  204. ); # MAP_RSRC_TOK_EXT
  205. # CODESFNAME - the name of the file containing the language codes for all languages
  206. # SYSGEN looks for this file in %NT_BLDTOOLS%
  207. $CODESFNAME = "codes.txt";
  208. # MAPPINGS: Mapping types SYSGEN recognizes
  209. @MAPPINGS = ("FILES", "BINDIRS", "TOKENS", "TOKDIRS");
  210. # FFILES, FBINDIRS, FTOKENS, FTOKDIRS: The corresponding list of fields
  211. @FFILES = ( "DestPath", "DestFile", "DestDbg", "SrcPath", "SrcFile", "SrcDbg", "Xcopy", "Langs" );
  212. @FBINDIRS = ( "DestPath", "DestDbg", "SrcPath", "SrcDbg", "Xcopy", "R", "Langs");
  213. @FTOKENS = ( "DestPath", "DestFile", "TokPath", "TokFile", "ITokPath", "LocOp", "BgnSw", "Langs");
  214. @FTOKDIRS = ( "DestPath", "TokPath", "ITokPath", "LocOp", "BgnSw", "Langs");
  215. # Localization Tool Operation Types (append or replace)
  216. %LOCOPS = (
  217. a => '-a',
  218. r => '-r',
  219. i => '-i $opts',
  220. ai => '-i $opts -a',
  221. ri => '-i $opts -r'
  222. );
  223. # Bingen Switches
  224. @BGNSWS = ( "-b", "-c" );
  225. # Error and Log Filenames
  226. $LOGFILE = "sysgen.log";
  227. $ERRFILE = "sysgen.err";
  228. # Global Variables
  229. # in addition to the if_flag, allow for nested IFs;
  230. @IFSTACK = ();
  231. # CODES - the contents of the CODESFNAME file, change to hash at 04/03/00
  232. %CODES = ();
  233. # TFILES, TBINDIRS, TTOKENS, TTOKDIRS: Records for the corresponding mapping (one of @MAPPINGS),
  234. # in the same order as they are found in the mapping files.
  235. # One record is a hash with the keys stored by @F<mapping_type>
  236. @TFILES = ();
  237. @TBINDIRS = ();
  238. @TTOKENS = ();
  239. @TTOKDIRS = ();
  240. #
  241. %VfyPath = (
  242. Exclude_Root => 'DIR_PATHS',
  243. Exclude_Subdir => 'IGNORE_PATHS',
  244. Exclude_File_Pattern => '(\.pdb)|(\.edb)|(\.dbg)|(slm\.ini)|(symbols)'
  245. );
  246. # REPOSITORY: Info necessary to generate the appropriate xcopy or bingen command,
  247. # for every file to be aggregated.
  248. %REPOSITORY = (); # As a db table, the key is (DestPath, DestFile).
  249. # As a Perl hash:
  250. # key = $DestPath (lowercase)
  251. # value = hash with
  252. # key = $DestFile (lowercase)
  253. # value = hash with
  254. # keys = DestPath, DestFile, DestDbg,
  255. # SrcPath, SrcFile, SrcDbg,
  256. # TokPath, TokFile, ITokPath,
  257. # OpType, LocOp, BgnSw,
  258. # Cmd
  259. #
  260. # not necessarily all of them defined.
  261. my %REPOSITORY_TEMPLATE = map {$_=>1}
  262. qw( SrcFile DestFile SrcDbg DestDbg SrcPath DestPath LocOp BgnSw);
  263. # CMD_REPOSITORY: Repository as found in an existing SYSGEN-generated makefile.
  264. # For every key, only {Cmd} field is filled in.
  265. %CMD_REPOSITORY = ();
  266. # SYSCMD: Stores the contents of the syscmd (SYSGEN-generated NMAKE command file)
  267. @SYSCMD= ();
  268. # MACROS: Hash storing the names and values of the macros.
  269. # Types of macros sysgen recognizes:
  270. # - command line macros (type 1)= macros defined in the command line.
  271. # Their value can be overwritten only by another command line macro.
  272. # - sysfile macros (type 0) = macros defined by the sysfiles,
  273. # inside or outside the pair (BEGIN_*_MAP, END_MAP) (type 0).
  274. # The sysfile macros do not overwrite the command line macros, but they overwrite the environment
  275. # macros.
  276. # - environment macros (type 0 too) = variables inherited from the cmd environment.
  277. # Can be overwritten by the other types of macros.
  278. # Internally, MACROS uppercases all the macro names, so the macronames are case insesitive.
  279. %MACROS = ();
  280. # FILTER
  281. # Stores the list of files to be considered.
  282. %FILTER = ();
  283. # FILE: Filename of the current description file; LINE: the current line number
  284. $FILE = "";
  285. $LINE = 0;
  286. # ERRORS: number of non fatal errors found during running SYSGEN
  287. $ERRORS = 0;
  288. # SYSFILE: names of the starting description files
  289. # By default, SYSFILE is set to ".\\sysfile" if not specified otherwise in the command line,
  290. # /F option
  291. $HOTFIX = "hotfix";
  292. $SYSFILE = ".\\sysfile";
  293. # TARGETS: targets specified in the command line
  294. %TARGETS = (); # key = $DestFile (lowercase string))
  295. # value = hash with
  296. # keys = OldDestPath (array), NewDestPath (array)
  297. %MAKEDIR=();
  298. %hotfix = ();
  299. # CLEAN : 1 if a clean SYSGEN is invoked ( by specifying /c in the command line )
  300. $CLEAN = 0;
  301. # SECTIONS
  302. ($SECTIONNAME, $DEFAULT_SECTIONS, $SECTIONS)=("process");
  303. # main {
  304. # Flush output buffer for remote.exe
  305. select(STDOUT); $| = 1;
  306. # Parse the command line
  307. &ParseCmdLine(@ARGV);
  308. # Verify SYSFILE's existence
  309. ( -e $SYSFILE ) || &FatalError( 1001, $SYSFILE );
  310. $FULLCHECK = &GetMacro("FULLCHECK") unless $FULLCHECK;
  311. # Clean sysgen.err and sysgen.log
  312. &CleanLogFiles( &GetSysdir( $SYSFILE ) );
  313. # Load the inherited environment variables
  314. &LoadEnv();
  315. &LoadHotFix(join("\\", &GetSysdir( $SYSFILE ), $HOTFIX ));
  316. # Load codes.txt file
  317. &LoadCodes();
  318. # For incremental, load Repository-associated
  319. # commands from an existing makefile to CMD_REPOSITORY.
  320. &LoadReposit( sprintf( "%s\\makefile", &GetSysdir( $SYSFILE ) ) );
  321. # Read the description files
  322. &ReadSysfile( $SYSFILE );
  323. # Verify the whole tree covered.
  324. &VerifyCover();
  325. # Populate the repository (according to the description files)
  326. &PopulateReposit();
  327. if ($SYNTAX_CHECK_ONLY){
  328. # Exit now since
  329. # no more errors can be generated.
  330. &SumErrors();
  331. exit 0;
  332. }
  333. # &SumErrors() and exit if $SYNTAX_CHECK_ONLY;
  334. # # no more errors can be generated.
  335. &GenNmakeFiles( &GetSysdir( $SYSFILE ) );
  336. # Display errors
  337. &SumErrors();
  338. # } # main
  339. # ReadSysfile
  340. # Reads a given sysfile and all the included sysfiles;
  341. # For each mapping type found, loads data into the corresponding array of hashes
  342. # ( one of the "@T" variables )
  343. # Input
  344. # mapping filename
  345. # Output
  346. # none
  347. # Usage
  348. # &ReadSysfile( "sysgen.def" );
  349. sub ReadSysfile {
  350. my $mapfname = shift;
  351. # File contents
  352. my @mapfile = ();
  353. @IFSTACK = ();
  354. # Mapping type ( one of @MAPPINGS )
  355. my $maptype;
  356. # Included filename
  357. my $incfile;
  358. # Flags
  359. my ( $if_flag, $inside_if, $if_line ) = (1, 0, undef);
  360. # Indexes
  361. my $i;
  362. # Error text
  363. my $error;
  364. # Open the mapping file
  365. ( -e $mapfname ) || &FatalError( 1002, $mapfname );
  366. print "Loading $mapfname...\n";
  367. if ($PARSESYMBOLCD && !(%default) && &GetMacro("SYMBOLCD")){
  368. %default = parseSymbolCD(&GetMacro("SYMBOLCD"));
  369. map {print STDERR $_ , "\n"} values(%default) if $DEBUG;
  370. }
  371. # Load file contents
  372. open( FILE, $mapfname ) || &FatalError( 1006, $mapfname );
  373. @mapfile = <FILE>;
  374. close( FILE );
  375. # Parse the mapping file and load the mappings.
  376. for ( $i=0, $LINE=0, $FILE=$mapfname; $i < @mapfile; $i++, $LINE++ ) {
  377. for ( $mapfile[$i] ) {
  378. SWITCH: {
  379. # white lines
  380. if ( ! /\S/ ) { last SWITCH; }
  381. # commented lines
  382. if ( /^\s*#/ ) { last SWITCH; }
  383. # ENDIF
  384. if ( /\bENDIF\b/i ) {
  385. scalar(@IFSTACK) or &FatalError( 1111, $FILE, $LINE );
  386. pop @IFSTACK;
  387. $inside_if = scalar(@IFSTACK);
  388. $if_flag = ($inside_if) ? $IFSTACK[-1] : 1;
  389. last SWITCH;
  390. } # case
  391. # IF
  392. if ( /\bIF\b/i) {
  393. push @IFSTACK, &SetIfFlag( $_);
  394. $if_flag and
  395. $if_flag = $IFSTACK[-1];
  396. $inside_if = 1;
  397. $if_line = $i;
  398. last SWITCH;
  399. } # case
  400. if ( ! $if_flag ) { last SWITCH; }
  401. # INCLUDE
  402. if ( /\bINCLUDE\b\s+(\S+)/i ) {
  403. # Evaluate the macros of the include statement
  404. $incfile = &ReplaceVar( $1, 0 );
  405. # Read the included file
  406. &ReadSysfile($incfile);
  407. # Continue with the current file; set FILE and LINE back
  408. $FILE = $mapfname;
  409. $LINE = $i;
  410. last SWITCH;
  411. } # case
  412. # SET
  413. if ( /\bSET\b/i ) {
  414. &SetMacro( &SetAttribOp( $_ ), 0 );
  415. last SWITCH;
  416. } # case
  417. # ERROR
  418. if ( /\bERROR\b\s+(\S+)/i) {
  419. $error = &ReplaceVar( $1, 0 );
  420. &FatalError( 1101, $error );
  421. last SWITCH;
  422. } # case
  423. # END_MAP
  424. if ( /END_MAP/i ) {
  425. &FatalError( 1113, $FILE, $LINE );
  426. last SWITCH;
  427. } # case
  428. # BEGIN_MAP
  429. if ( /\bBEGIN_(\S+)_MAP/i ) {
  430. $maptype = &GetMappingType( $_ );
  431. ( $maptype ) || &FatalError( 1119, $FILE, $LINE );
  432. # Read the found map.
  433. print "Loading $MAPPINGS[$maptype-1] map from $mapfname...\n";
  434. # Read the map and return the last line index
  435. $i = &ReadBlock( \@mapfile, $i+1, $maptype-1 );
  436. last SWITCH;
  437. } # case
  438. # default
  439. &FatalError( 1110, $FILE, $LINE );
  440. } #SWITCH
  441. } #for
  442. } # for
  443. &FatalError( 1120, $FILE, $if_line ) if scalar(@IFSTACK);
  444. return;
  445. } # ReadSysfile
  446. # GetMappingType
  447. # Identifies the mapping type in a BEGIN_MAP statement
  448. # Input
  449. # BEGIN_MAP statement
  450. # Output
  451. # mapping index or 0 if the mapping type is unknown
  452. sub GetMappingType {
  453. my %REVERSE = map {$MAPPINGS[$_]=>$_+1} 0..$#MAPPINGS;
  454. my $test = shift;
  455. chomp $test;
  456. $test =~ s/\s+$//gm;
  457. $test =~ s/BEGIN_(\w+)_MAP/\U$1/;
  458. $REVERSE{$test};
  459. } # GetMappingType
  460. # ReadBlock
  461. # Reads a map from the mapping file, according to its type.
  462. # Loads data into the corresponding "table" variable ( one of the "@T" variables)
  463. # Input
  464. # sysfile contents (reference)
  465. # index of the current line
  466. # mapping type
  467. # Output
  468. # index of the END_MAP line
  469. # Usage
  470. # $index = &ReadBlock( \@mapfile, $index, $maptype );
  471. sub ReadBlock {
  472. my($mapref, $index, $maptype) = @_;
  473. my $ifstack = scalar(@IFSTACK);
  474. # Output - $index
  475. # Other indexes
  476. my $line;
  477. # IF flags
  478. my( $if_flag, $inside_if, $if_line ) = (1, 0, undef);
  479. # Error text
  480. my $error;
  481. # Parse the current mapping type
  482. for ( ; $index < @{$mapref}; $index++, $LINE++ ) {
  483. for ( $mapref->[$index] ) {
  484. SWITCH: {
  485. # white lines
  486. if ( ! /\S/ ) { last SWITCH; }
  487. # commented lines
  488. if ( /^\s*#/ ) { last SWITCH; }
  489. # ENDIF
  490. if ( /\bENDIF\b/i) {
  491. scalar(@IFSTACK) or &FatalError( 1111, $FILE, $LINE );
  492. pop @IFSTACK;
  493. $inside_if = scalar(@IFSTACK);
  494. $if_flag = ($inside_if) ? $IFSTACK[-1] : 1;
  495. last SWITCH;
  496. } # case
  497. if ( /\bIF\b/i) {
  498. push @IFSTACK, &SetIfFlag( $_);
  499. $if_flag and
  500. $if_flag = $IFSTACK[-1];
  501. $inside_if = 1;
  502. $if_line = $i;
  503. last SWITCH;
  504. } # case
  505. if ( ! $if_flag ) { last SWITCH; }
  506. # INCLUDE
  507. if ( /\bINCLUDE\b\s+(\S+)/i ) {
  508. &FatalError( 1115, $FILE, $LINE );
  509. last SWITCH;
  510. } # case
  511. # SET
  512. if ( /\bSET\b/i ) {
  513. &SetMacro( &SetAttribOp( $_ ), 0 );
  514. last SWITCH;
  515. } # case
  516. # ERROR
  517. if ( /\bERROR\b\s(\S+)/i) {
  518. $error = &ReplaceVar( $1, 0 );
  519. &FatalError( 1101, $error );
  520. last SWITCH;
  521. } # case
  522. # END_MAP
  523. if ( /END_MAP/i ) {
  524. ( $ifstack!= scalar(@IFSTACK) ) and &FatalError( 1120, $FILE, $if_line );
  525. return $index;
  526. } # case
  527. # BEGIN_MAP
  528. if ( /BEGIN_\S+_MAP/i ) {
  529. &FatalError( 1114, $FILE, $LINE );
  530. last SWITCH;
  531. } # case
  532. # default
  533. &ReadLine( $mapref, $index, $maptype );
  534. } # SWITCH
  535. } # for
  536. } # for
  537. print &FatalError( 1121, $FILE, $LINE );
  538. return -1;
  539. } # ReadBlock
  540. # SetIfFlag
  541. # Evaluates the given IF expression.
  542. # Input
  543. # IF statement
  544. # Output
  545. # 1 if the IF expression is satisfied, 0 otherwise
  546. sub SetIfFlag {
  547. my( $entry ) = @_;
  548. # Output
  549. my $ret=0;
  550. # Store entry
  551. my $line = $entry;
  552. # Operator
  553. my $operator;
  554. # Operands
  555. my($operand1, $operand2);
  556. $entry = &ReplaceVar( $entry, 0 );
  557. # Identify the operands and the operator, then evaluate the expression.
  558. $entry =~ /\s*IF\s+(\S*)\s+(\S*)\s+(\S*)\s*/i;
  559. # Set operator
  560. $operand1 = $1;
  561. $operator = $2;
  562. $operand2 = $3;
  563. SWITCH: {
  564. if ( $operator eq "==" ) {
  565. if ( $operand1 eq $operand2 ) {
  566. $ret = 1;
  567. }
  568. last SWITCH;
  569. } # if
  570. if ( $operator eq "!=" ) {
  571. if ( $operand1 ne $operand2 ) {
  572. $ret = 1;
  573. }
  574. last SWITCH;
  575. } # if
  576. &FatalError( 1116, $FILE, $LINE );
  577. } # SWITCH
  578. return $ret;
  579. } # SetIfFlag
  580. # SetAttribOp
  581. # Evaluates a SET statement.
  582. # Input
  583. # a SET statement
  584. # Output
  585. # evaluated macroname and macrovalue
  586. # Usage
  587. # ($macroname, $macrovalue) = &SetAttribOp( $mapfile[$index] ) ;
  588. sub SetAttribOp {
  589. my( $entry ) = @_;
  590. # Output
  591. my($varname, $value);
  592. $entry = &ReplaceVar( $entry, 0 );
  593. $entry =~ /SET\s*(\S*)\s*=\s*\;*(.*)\s*/i;
  594. # Set variable's name and variable's value
  595. $varname = $1;
  596. $value = $2;
  597. # Verify if a variable name is defined
  598. if ( $varname eq "" ) {
  599. return ("", "");
  600. } # if
  601. return ($varname, $value);
  602. } # SetAttribOp
  603. # ReadLine
  604. # Description
  605. # Reads one description line, evaluates it and store the records it generates
  606. # Input
  607. # sysfile contents ( reference )
  608. # line number
  609. # Output
  610. # none
  611. # Usage
  612. # &ReadLine( $mapref, $index, $maptype );
  613. # Implementation
  614. sub ReadLine {
  615. my( $mapref, $index, $maptype ) = @_;
  616. # Array of records
  617. my @records;
  618. # Indexes
  619. my $i;
  620. # Replace variables and spawn new records
  621. @records = &ReplaceVar( $mapref->[$index], 1 );
  622. for ( $i=0; $i < @records; $i++ ) {
  623. &LoadRecord( $maptype, $records[$i] );
  624. } # for
  625. return $index;
  626. } # ReadLine
  627. # LoadRecord
  628. # Description
  629. # Transforms an evaluated description line into a record,
  630. # and adds it to the appropriate table.
  631. # Input
  632. # mapping type
  633. # description line (string)
  634. # Output
  635. # <none>
  636. # Usage
  637. # &LoadRecord( $maptype, $line_contents );
  638. sub LoadRecord {
  639. my($maptype, $entry) = @_;
  640. # The hash table storring the current line (record).
  641. # The keys (field names) are given by the corresponding "@F$maptype" array.
  642. my %record;
  643. %record = &LineToRecord( $maptype, $entry );
  644. # If the current language matches the record language,
  645. # add the record to the corresponding "@T$maptype" array.
  646. if ( &IsLangOK( $record{Langs}, &GetMacro( "language" ) ) ) {
  647. &AddRecord( $maptype, %record );
  648. } elsif ((!defined $record{SrcFile}) && (defined $record{SrcPath})) {
  649. print "Ignore $record{SrcPath}\n";
  650. &SetMacro(
  651. $VfyPath{'Exclude_Subdir'},
  652. &GetMacro($VfyPath{'Exclude_Subdir'}) . "; " .
  653. $record{SrcPath},
  654. 0
  655. );
  656. }# if
  657. return;
  658. } # LoadRecord
  659. # LineToRecord
  660. # Transforms a given string into a record (hash table).
  661. # Input
  662. # mapping type
  663. # description line contents
  664. # Output
  665. # record of the mapping type
  666. # Usage
  667. # %record = &LineToRecord( $maptype, $entry );
  668. sub LineToRecord {
  669. my($maptype, $entry) = @_;
  670. # Output
  671. my %record;
  672. # Mapping name
  673. my $mapname;
  674. # Corresponding "@F$maptype" variable (reference)
  675. my $ftable;
  676. # Current line split in fields
  677. my @fields;
  678. # Storage for the current line
  679. my $line = $entry;
  680. # Indexes
  681. my($i, $j);
  682. # Get the mapping name.
  683. $mapname = "F$MAPPINGS[$maptype]";
  684. $ftable = \@$mapname;
  685. # Split the record into fields
  686. @fields = split " ", $entry;
  687. # Fill in %record variable with the field names as keys and
  688. # the field values as values.
  689. for ( $i=0; $i< @$ftable; $i++ ) {
  690. # All fields must be non-null
  691. if ( !$fields[$i] ) {
  692. &FatalError( 1118, $FILE, $LINE );
  693. } # if
  694. $record{$ftable->[$i]} = $fields[$i];
  695. } # for
  696. return %record;
  697. } # LineToRecord
  698. # AddRecord
  699. # Adds the given record to the appropriate "@T" table.
  700. # Input
  701. # mapping type
  702. # record
  703. # Output
  704. # <none>
  705. sub AddRecord {
  706. my($maptype, %record) = @_;
  707. # Table name ( name of one of the "@T" variables )
  708. my $tname;
  709. # Table (reference)
  710. my $table;
  711. # Storage for the current record
  712. my %buffer;
  713. # Subdirectories ( if "R" field defined )
  714. my @subdirs;
  715. # Source field name (one of SrcPath, TokPath )
  716. my $fname;
  717. # Indexes
  718. my $i;
  719. # Set table
  720. $tname = "T$MAPPINGS[$maptype]";
  721. $table = \@$tname;
  722. # Set the field name for the path ( TokPath or SrcPath)
  723. # according to the mapping type
  724. SWITCH: {
  725. if ( $MAPPINGS[$maptype] =~ /TOK/i ) {
  726. $fname = "TokPath";
  727. last SWITCH;
  728. } # if
  729. if ( $MAPPINGS[$maptype] =~ /BIN/i ) {
  730. $fname = "SrcPath";
  731. last SWITCH;
  732. } # if
  733. if ( $MAPPINGS[$maptype] =~ /FILES/i ) {
  734. $fname = "SrcPath";
  735. last SWITCH;
  736. } # if
  737. # default
  738. # nothing to do
  739. } # SWITCH
  740. # Verify the existence of the source path
  741. if ( ! -e $record{$fname} ) {
  742. # print "Warning: $MAPPINGS[$maptype] map: No source directory $record{$fname}\n";
  743. return;
  744. } # if
  745. # Insert record into the table
  746. push @$table, \%record;
  747. # Write the record to the log file
  748. &LogRecord($maptype, \%record);
  749. # For Bindirs, look for the value of Subdirs
  750. if ( $MAPPINGS[$maptype] ne "BINDIRS" ) {
  751. return;
  752. } # if
  753. # Return if no subdirectories to be parsed ( "R" field set to "n" ).
  754. if ( $record{R} =~ /n/i ) {
  755. return;
  756. } # if
  757. # Get the list of subdirectories
  758. @subdirs = `dir /ad /b $record{SrcPath}`;
  759. # Add one record for each subdirectory found.
  760. for ( $i=0; $i < @subdirs; $i++ ) {
  761. chomp $subdirs[$i];
  762. # Found that in NT5, the result of dir /b starts with an empty line
  763. if ( $subdirs[$i] eq "" ) {
  764. next;
  765. }
  766. # Skip the "symbols" subdirectory
  767. if ( $subdirs[$i] eq "symbols" ) {
  768. next;
  769. }
  770. # Add one record for the current subdirectory
  771. %buffer = %record;
  772. $buffer{DestPath} .= "\\$subdirs[$i]";
  773. $buffer{SrcPath} .= "\\$subdirs[$i]";
  774. &AddRecord( $maptype, %buffer );
  775. } # for
  776. return;
  777. } # AddRecord
  778. # LogRecord
  779. # Writes the record to the log file.
  780. # Input
  781. # mapping type (reference)
  782. # record (reference)
  783. # Output
  784. # <none>
  785. sub LogRecord {
  786. my( $maptype, $recref ) = @_;
  787. # String to be written to the logfile
  788. my $logstr;
  789. $logstr = "$MAPPINGS[$maptype]:";
  790. for ( sort keys %{$recref} ) {
  791. $logstr .= "$_=$recref->{$_} ";
  792. } # for
  793. $logstr .= "\n";
  794. # print "$logstr";
  795. } # LogRecord
  796. # ReplaceVar
  797. # Replaces all the macronames with their value in the given string.
  798. # Input
  799. # the string to be evaluated
  800. # the replacement type:
  801. # 0 = scalar
  802. # 1 = array
  803. # Output
  804. # array if the replacement type is 1
  805. # string if the replacement type is 0
  806. # In both cases, all the macros are evaluated.
  807. # Usage
  808. # $entry = &ReplaceVar( $entry, 0 );
  809. # @records = &ReplaceVar( $entry, 1 );
  810. sub ReplaceVar {
  811. my( $line, $type ) = @_;
  812. $line =~ s/\s{2,}/ /g;
  813. $line =~ s/^\s//;
  814. $line =~ s/\s$//;
  815. my @list = ($line);
  816. foreach $line (@list){
  817. my $epyt = 0;
  818. while ($line =~ /\$\(([^\)]+)\)/){
  819. my $macro = $1;
  820. $line =~ s/\$\(\Q$macro\E\)/__MACRO__/g;
  821. if ($macro =~ /(\w+)\[\s?\]/) {
  822. $macro = $1;
  823. $epyt = 1;
  824. }
  825. my $thevalue = &GetMacro($macro);
  826. $thevalue =~ s/\s+//g;
  827. if (!$epyt){
  828. $line =~ s/__MACRO__/$thevalue/g;
  829. }
  830. else{
  831. pop @list; # take one, give many
  832. foreach my $value (split (";" , $thevalue)){
  833. next if $value !~ /\S/;
  834. my $this = $line;
  835. $this =~ s/__MACRO__/$value/g;
  836. push @list, $this;
  837. }
  838. }
  839. }
  840. }
  841. ($type) ? @list : pop @list;
  842. } # ReplaceVar
  843. # LoadCodes
  844. # Loads $CODEFNAME's file contents in %CODES
  845. # Input & Output <none>
  846. # Usage
  847. # &LoadCodes();
  848. sub LoadCodes {
  849. # codes.txt filename
  850. my $codefile;
  851. my @items;
  852. my $code;
  853. # Get the contents of $CODESFNAME
  854. $codefile = sprintf "%s\\$CODESFNAME", &GetMacro( "RazzleToolPath" );
  855. ( -e $codefile ) || &FatalError( 1002, $codefile );
  856. ( open( FILE, $codefile ) ) || &FatalError( 1006, $codefile );
  857. # Load file contents
  858. while(<FILE>) {
  859. next if (/^;/ || /^\s+$/);
  860. @items = split( /\s+/, $_ );
  861. ( @items > 5 ) || &FatalError( 1912, $CODESFNAME );
  862. (exists $CODES{uc$items[0]})? &FatalError( 1911, $CODESFNAME ): (@{$CODES{uc$items[0]}}=@items[1..$#items]);
  863. }
  864. close( FILE );
  865. for $code (keys %CODES) {
  866. &SetMacro(
  867. $VfyPath{'Exclude_Subdir'},
  868. &GetMacro($VfyPath{'Exclude_Subdir'}) . "; " .
  869. $ENV{_NTTREE} . "\\" . lc$code . "; " .
  870. $ENV{_NTTREE} . "\\" . substr(lc$CODES{$code}->[4],1),
  871. 0
  872. );
  873. }
  874. return;
  875. } # LoadCodesFile
  876. # IsLangOK
  877. # Verifies if the current language matches the value of the Langs field.
  878. # Input
  879. # Langs field value
  880. # Output
  881. # 1 if the current language matches Langs, 0 otherwise
  882. # Usage
  883. # IsLangOK( "FE", "jpn" );
  884. sub IsLangOK {
  885. return cklang::CkLang($_[1], $_[0]);
  886. } # IsLangOK
  887. # VerifyCover
  888. # Verify the @{T$MAPPING} is covered the whole tree
  889. # Input & Output
  890. # none
  891. # Usage
  892. # &VerifyCover();
  893. sub VerifyCover {
  894. my(%tree)=();
  895. return if (&GetMacro($VfyPath{'Exclude_Root'}) eq "");
  896. SetMacro(
  897. $VfyPath{'Exclude_Subdir'},
  898. &Undefine_Exclude_Lang_Subdir(&GetMacro($VfyPath{'Exclude_Subdir'})),
  899. 0
  900. );
  901. # Create except tree from @T$Mapping array, then remove the dummy to find all branch into $tree_hashptr
  902. &Create_Tree_Branch(\%tree);
  903. # Remove Root and its parents from branch tree
  904. &Remove_Root_List(\%tree, grep {/\S/} split(/\s*;\s*/, &GetMacro($VfyPath{'Exclude_Root'})));
  905. # Find unmapping folders from branch tree, also remove the empty folders and the specified file-pattern files (such as slm.ini).
  906. &Find_UnMapping(\%tree);
  907. } # VerifyCover
  908. # Undefine_Exclude_Lang_Subdir
  909. # Include $ENV{_NTTREE}\\$lang and $ENV{_NTTREE}\\$class for cover verification
  910. # Input
  911. # $str - The string list of exclude subdir
  912. # Output
  913. # $str - The string list after remove $ENV{_NTTREE}\\$lang and $ENV{_NTTREE}\\$class
  914. # Usage
  915. # &Undefine_Exclude_Lang_Subdir(&GetMacro($VfyPath{'Exclude_Subdir'}));
  916. sub Undefine_Exclude_Lang_Subdir {
  917. my $str=shift;
  918. my $lang=&GetMacro( "language" );
  919. my $pat1=&GetMacro( "_NTTREE" ) . "\\$lang;";
  920. my $pat2=&GetMacro( "_NTTREE" ) . "\\$CODES{$lang}->[4];";
  921. $str=~s/\Q$pat1\E//i;
  922. $str=~s/\Q$pat2\E//i;
  923. return $str;
  924. }
  925. # Create_Tree_Branch
  926. # Create except tree from @T$Mapping array, then remove the dummy to find all branch into $tree_hashptr
  927. # Input
  928. # $tree_hashptr - a hash pointer for store the branch tree
  929. #
  930. # Output
  931. # none - the branch tree stored in %$tree_hashptr
  932. # Usage
  933. # &Create_Tree_Branch(\%mytree);
  934. sub Create_Tree_Branch {
  935. my($tree_hashptr)=@_;
  936. my(%except)=();
  937. # Create Exception Tree from @T$Mapping array
  938. &Get_Except(\%except);
  939. # Remove the subdir if parent defined, the remains create into hash (parent dir) - hash (current dir)
  940. &Remove_Dummy_Create_Branch(\%except,$tree_hashptr);
  941. }
  942. # Get_Except
  943. # Create Exception Tree from @T$Mapping array
  944. # Input
  945. # $except_hashptr - a hash pointer for store the exception tree
  946. #
  947. # Output
  948. # none - the exception tree stored in %$except_hashptr
  949. #
  950. # Usage
  951. # &Get_Except(\%myexcept);
  952. sub Get_Except {
  953. my($except_hashptr)=@_;
  954. my($tablename, $hashptr)=();
  955. ## Predefine except directories
  956. for (split(/\s*;\s*/, &GetMacro($VfyPath{'Exclude_Subdir'}))) {
  957. next if ($_ eq "");
  958. if (/\.\.\./) {
  959. map({$$except_hashptr{$_}=1} &Find_Dot_Dot_Dot(lc$_));
  960. } else {
  961. $$except_hashptr{lc $_}=1;
  962. }
  963. }
  964. ## According bindir or tokdir to define the sourcepath to %except
  965. for $tablename (@MAPPINGS) {
  966. for $hashptr (@{"T$tablename"}) {
  967. if (exists $$hashptr{'R'}) {
  968. if ($$hashptr{'R'} eq 'n') {
  969. $$except_hashptr{ lc$$hashptr{SrcPath} . "\\."} = 1
  970. } else {
  971. $$except_hashptr{lc$$hashptr{SrcPath}} = 1
  972. }
  973. } elsif (exists $$hashptr{SrcPath}) {
  974. if (defined $$hashptr{SrcFile}) {
  975. $$except_hashptr{lc($$hashptr{SrcPath} . "\\" . $$hashptr{SrcFile})} = 1
  976. } else {
  977. $$except_hashptr{lc$$hashptr{SrcPath}} = 1
  978. }
  979. } elsif (exists $$hashptr{TokPath}) {
  980. if (defined $$hashptr{TokFile}) {
  981. $$except_hashptr{lc($$hashptr{TokPath} . "\\" . $$hashptr{TokFile})} = 1
  982. } else {
  983. $$except_hashptr{lc$$hashptr{TokPath}} = 1
  984. }
  985. } else {&Error( 2051, $hashptr);}
  986. }
  987. }
  988. }
  989. # Find_Dot_Dot_Dot
  990. # Collect the combination of the ... folders
  991. # Input
  992. # $path - A path contains "..."
  993. #
  994. # Output
  995. # keys %regist - The array of all the combination found in the path
  996. #
  997. # Usage
  998. # &Find_Dot_Dot_Dot("$ENV{_NTTREE}\\...\\symbols.pri");
  999. sub Find_Dot_Dot_Dot {
  1000. my ($path) = @_;
  1001. my ($mymatch, $file, %regist);
  1002. my @piece=split(/\\\.{3}/, $path);
  1003. for $file ( `dir /s/b/l $piece[0]$piece[-1] 2>nul`) {
  1004. chomp $file;
  1005. $mymatch = &match_subjects($file, \@piece);
  1006. next if (!defined $mymatch);
  1007. $regist{$mymatch}=1;
  1008. }
  1009. return keys %regist;
  1010. }
  1011. # match_subjects
  1012. # The subroutine called by Find_Dot_Dot_Dot, which perform the match for
  1013. # all the pieces of the infomation of the path with the file. For example
  1014. #
  1015. # Input
  1016. # $file - The fullpath filename
  1017. # $pieceptr - The array ptr
  1018. #
  1019. # Output
  1020. # undef if not match
  1021. # $match - store the path it matched
  1022. #
  1023. # Usage
  1024. # &match_subjects(
  1025. # "D:\\ntb.binaries.x86fre\\dx8\\symbols\\retail\\dll\\migrate.pdb",
  1026. # \@{"D:\\ntb.binaries.x86fre", "symbols\\", "dll\\"} );
  1027. # Return => "D:\\ntb.binaries.x86fre\\dx8\\symbols\\retail\\dll"
  1028. #
  1029. sub match_subjects {
  1030. my ($file, $pieceptr)=@_;
  1031. my $match;
  1032. for (@$pieceptr) {
  1033. return if ($file!~/\Q$_\E/);
  1034. $match .= $` . $&;
  1035. $file = $';
  1036. }
  1037. return $match;
  1038. }
  1039. # Remove_Dummy_Create_Branch
  1040. # Remove the subdir if parent defined, the remains create into hash (parent dir) - hash (current dir)
  1041. # Input
  1042. # $except_hashptr - stored the exception hash from %T$Mapping
  1043. # $tree_hashptr - will store the covered tree in hash - hash
  1044. #
  1045. # Output
  1046. # none - the covered tree stored in %$tree_hashptr
  1047. #
  1048. # Usage
  1049. # &Remove_Dummy_Create_Branch(\%myexcept, \%mybranch);
  1050. sub Remove_Dummy_Create_Branch {
  1051. my($except_hashptr,$tree_hashptr)=@_;
  1052. next1: for (keys %$except_hashptr) {
  1053. # loop all its parent
  1054. while(/\\+([^\\]+)/g) {
  1055. # Is this folder covered by its parent?
  1056. if (exists $$except_hashptr{$`}) {
  1057. # Remove current folder
  1058. delete $$except_hashptr{$_};
  1059. next next1;
  1060. } else {
  1061. # define the $tree{$parent}->{$child}=1
  1062. $$tree_hashptr{$`}->{$&}=1;
  1063. }
  1064. }
  1065. }
  1066. }
  1067. # Remove_Root_List
  1068. # Remove Root and its parents from branch tree
  1069. # Input
  1070. # $tree_hashptr - a hash pointer, %$tree_hashptr is the branch tree
  1071. # @root_list_ptr - a array for the root list
  1072. #
  1073. # Output
  1074. # none - the root and its parent will be remove from branch tree (%$tree_hashptr)
  1075. #
  1076. # Usage
  1077. # &VerifyCover();
  1078. sub Remove_Root_List {
  1079. my($tree_hashptr, @root_list_ptr)=@_;
  1080. my $concern;
  1081. # split the $root_list by ';'
  1082. for (@root_list_ptr) {
  1083. # loop all its parents
  1084. while(/\\/g) {
  1085. # remove all the parent folder
  1086. delete $$tree_hashptr{$`} if ($` ne $_);
  1087. }
  1088. }
  1089. Next2: for (keys %$tree_hashptr) {
  1090. for $concern (@root_list_ptr) {
  1091. next Next2 if (/\Q$concern\E/i);
  1092. }
  1093. delete $$tree_hashptr{$_};
  1094. }
  1095. }
  1096. # Find_UnMapping
  1097. # Find unmapping folders from branch tree, also remove the empty folders and the specified file-pattern files (such as slm.ini).
  1098. # Input
  1099. # $tree_hashptr - a hash - hash pointer, %$tree_hashptr is the branch tree
  1100. #
  1101. # Output
  1102. # none
  1103. # Usage
  1104. # &VerifyCover();
  1105. sub Find_UnMapping {
  1106. my($tree_hashptr)=@_;
  1107. my ($parent_dir, $mykey, @myfiles);
  1108. # for each tree
  1109. for $parent_dir (keys %{$tree_hashptr}) {
  1110. # find its children
  1111. for (`dir /b/ad/l $parent_dir 2>nul`) {
  1112. chomp;
  1113. # only concern not exist in covered tree
  1114. if (!exists $$tree_hashptr{$parent_dir}->{"\\$_"}) {
  1115. $mykey="$parent_dir\\$_";
  1116. # find its all children / subidr children,
  1117. # and remove specified file pattern files, then repro the error
  1118. for (`dir /s/b/a-d/l $mykey 2>nul`) {
  1119. if ((!/$VfyPath{'Exclude_File_Pattern'}/i) && (/^(.+)\\[^\\]+$/)) {
  1120. ###
  1121. my %comment = ($ENV{"_NTBINDIR"}."\\"."LOC" => " mail localizers to ask why...",
  1122. $ENV{"_NTTREE"} => " REVIEW map in bldbins.inc, ntloc.inc..."
  1123. );
  1124. my %fixed=();
  1125. foreach $dir (keys(%comment)){
  1126. $key = $dir;
  1127. $val = $comment{$dir};
  1128. $key=~s/(\w)/\U$1/g;
  1129. $key=~s/\\/\\\\/g;
  1130. $key=~s/\./\\./g;
  1131. $fixed {$key} = $val;
  1132. }
  1133. foreach $dir (keys(%fixed)){
  1134. $mykey .= $fixed{$dir} if ($mykey =~/$dir/i);
  1135. }
  1136. ##
  1137. Error(2052, $mykey);
  1138. last;
  1139. }
  1140. }
  1141. }
  1142. }
  1143. }
  1144. }
  1145. # PopulateReposit
  1146. # Populates REPOSITORY with data from the mapping tables ( @T variables).
  1147. # Input & Output <none>
  1148. # Usage
  1149. # &PopulateReposit();
  1150. sub PopulateReposit {
  1151. # Fill filter table
  1152. &FillFilter();
  1153. # Add file entries from TFILES and TBINDIRS
  1154. &AddFiles();
  1155. # If FILTER is defined, verify if all its entries (file names)
  1156. # were loaded in Repository.
  1157. for ( keys %FILTER ) {
  1158. if ( &IsEmptyHash( \%TARGETS ) || &IsHashKey( \%TARGETS, $_ ) ) {
  1159. if ( $FILTER{$_} <= 0 ) {
  1160. &Error( 1002, sprintf( "%s (%s)", $_, &GetMacro( "FILTER" ) ) );
  1161. next;
  1162. } # if
  1163. } # if
  1164. } # for
  1165. # If TARGETS is defined, verify that all its entries (target names)
  1166. # were loaded in Repository.
  1167. for ( keys %TARGETS ) {
  1168. ( &IsFoundTarget( $_ ) ) || &FatalError( 1004, $_ );
  1169. } # for
  1170. # Fill in info about tokens from TTOKENS and TTOKDIRS
  1171. &FillTokens();
  1172. # Fill in the {Cmd} field for relevant keys
  1173. &FillCmd();
  1174. return;
  1175. } # PopulateReposit
  1176. # FillCmd
  1177. # Fill in the {Cmd} REPOSITORY field
  1178. # Input & Output
  1179. # none
  1180. # Usage
  1181. # &FillCmd();
  1182. sub FillCmd {
  1183. # Repository key
  1184. my %key;
  1185. # Situations when, for a given (DestPath, DestFile) REPOSITORY key,
  1186. # the associated NMAKE commands must be stored in REPOSITORY's {Cmd} field:
  1187. # - clean SYSGEN
  1188. # - incremental SYSGEN with no command-line targets specified (empty TARGETS)
  1189. my $all = $CLEAN || &IsEmptyHash( \%TARGETS );
  1190. # Fill in the {Cmd} field
  1191. print "Translating data to makefile commands...\n";
  1192. for $destpath ( sort keys %REPOSITORY ) {
  1193. # ( !$all ) || print "\t$destpath";
  1194. print "\t$destpath" unless !$all;
  1195. for $destfile ( sort keys %{$REPOSITORY{$destpath}} ) {
  1196. $key{DestPath} = $destpath;
  1197. $key{DestFile} = $destfile;
  1198. # Check special character to avoid nmake broken
  1199. if ( substr($destfile, -1) eq '$' ) {
  1200. delete $REPOSITORY{$destpath}->{$destfile};
  1201. delete $TARGETS{$destfile};
  1202. # &DeleteKey( \%CMD_REPOSITORY, \%key );
  1203. &Error(1214, "$destpath\\$destfile");
  1204. next;
  1205. }
  1206. # If incremental with targets, print target's full path
  1207. if ( !$all && &IsHashKey( \%TARGETS, $destfile ) ) {
  1208. printf "\t%s\\%s\n",
  1209. &GetFieldVal( \%REPOSITORY, \%key, "DestPath" ),
  1210. &GetFieldVal( \%REPOSITORY, \%key, "DestFile" );
  1211. } # if
  1212. # Translate the current REPOSITORY entry into a set of nmake commands
  1213. if ( $all || &IsHashKey( \%TARGETS, $destfile ) ) {
  1214. &RecordToCmd( \%key );
  1215. } # if
  1216. } # for
  1217. ( !$all ) || print "\n";
  1218. } # for
  1219. return;
  1220. } # FillCmd
  1221. # AddTarget
  1222. # Add a filename (given on the command line) to the TARGETS table
  1223. sub AddTarget {
  1224. $TARGETS{lc$_[0]}->{Target}=1;
  1225. } # AddTarget
  1226. # IsHashKey
  1227. # Verifies if a given string is key in a given hash
  1228. # Input
  1229. # hash (reference)
  1230. # entry (without path)
  1231. # Output
  1232. # 1 if the key exists
  1233. # 0 otherwise
  1234. sub IsHashKey {
  1235. return (exists $_[0]->{lc $_[1]});
  1236. } # IsHashKey
  1237. # IsFoundTarget
  1238. # Verifies if a filename is marked as found in TARGETS
  1239. # All targets specified in the command line must be marked in TARGETS at the moment
  1240. # REPOSITORY is fully loaded.
  1241. # Input
  1242. # filename (no path)
  1243. # Output
  1244. # 1 if the target is loaded in Repository
  1245. # 0 otherwise
  1246. sub IsFoundTarget {
  1247. if ( @{$TARGETS{lc$_[0]}->{NewDestPath}} > 0 ) { return 1; }
  1248. return 0;
  1249. } # IsFoundTarget
  1250. # AddTargetPath
  1251. # Add a DestPath value to one of the NewDestPath, OldDestPath fields of TARGETS
  1252. # Input
  1253. # target name
  1254. # field name (one of NewDestPath and OldDestPath)
  1255. # field value
  1256. # Output
  1257. # none
  1258. # Usage
  1259. # &AddTargetPath( "ntdll.dll", "OldDestPath", "f:\\nt\\relbins\\jpn");
  1260. sub AddTargetPath {
  1261. push @{$TARGETS{lc$_[0]}->{$_[1]}}, lc$_[2];
  1262. } # AddTargetPath
  1263. # IsEmptyHash
  1264. # Verifies if a hash table is empty.
  1265. # Input
  1266. # hash table (reference)
  1267. # Output
  1268. # 1 if hash is empty
  1269. # 0 otherwise
  1270. sub IsEmptyHash {
  1271. !scalar(%{$_[0]});
  1272. # return (scalar(%{$_[0]}) eq 0);
  1273. } # IsEmptyHash
  1274. # UpdTargetEntries
  1275. # In case of an incremental build, update the entries corresponding to the TARGETS
  1276. # from CMD_REPOSITORY according to data from REPOSITORY.
  1277. # Input & Output
  1278. # none
  1279. sub UpdTargetEntries {
  1280. # Target name
  1281. my $tname;
  1282. # Indexes
  1283. my $i;
  1284. # CMD_REPOSITORY key
  1285. my %key;
  1286. # OldDestPath array (reference)
  1287. my $destref;
  1288. if ( $CLEAN || &IsEmptyHash(\%TARGETS) ) { return; }
  1289. for $tname ( keys %TARGETS ) {
  1290. $key{DestFile} = $tname;
  1291. # Delete CMD_REPOSITORY entries with DestFile equals to target name
  1292. $destref = \@{$TARGETS{$tname}->{OldDestPath}};
  1293. for ( $i=0; $i < @{$destref}; $i++ ) {
  1294. $key{DestPath} = $destref->[$i];
  1295. &DeleteKey( \%CMD_REPOSITORY, \%key );
  1296. } # for
  1297. # Copy data for TARGETS from REPOSITORY to CMD_REPOSITORY
  1298. $destref = \@{$TARGETS{$tname}->{NewDestPath}};
  1299. for ( $i=0; $i < @{$destref}; $i++ ) {
  1300. $key{DestPath} = $destref->[$i];
  1301. # Use the same Cmd for CMD_REPOSITORY as for REPOSITORY
  1302. &SetField( \%CMD_REPOSITORY, \%key, "DestPath", &GetFieldVal( \%REPOSITORY, \%key, "DestPath" ) );
  1303. &SetField( \%CMD_REPOSITORY, \%key, "DestFile", &GetFieldVal( \%REPOSITORY, \%key, "DestFile" ) );
  1304. &SetField( \%CMD_REPOSITORY, \%key, "Cmd", &GetFieldVal( \%REPOSITORY, \%key, "Cmd" ) );
  1305. } # for
  1306. } # for
  1307. return;
  1308. } # UpdTargetEntries
  1309. # AddFiles
  1310. # Parses TFILES and TBINDIRS and adds entries to REPOSITORY.
  1311. # Input & Output <none>
  1312. # Usage
  1313. # &AddFiles();
  1314. sub AddFiles {
  1315. # Current element of TBINDIRS ( reference )
  1316. my $recref;
  1317. # Current directory contents
  1318. my @files;
  1319. # Indexes
  1320. my($i, $j, $dir);
  1321. print "Adding file data...\n";
  1322. # Add the files listed in TFILES to REPOSITORY
  1323. for ( $i=0; $i < @TFILES; $i++ ) {
  1324. # Call AddEntry with 1, meaning that the existence of the
  1325. # file is queried and a non fatal error fired if the file is missing.
  1326. # As the file is explicitly listed in FILES MAP, it is natural to suppose
  1327. # it should exist.
  1328. &AddEntry( $TFILES[$i], 1 );
  1329. } #for
  1330. @FILES = ();
  1331. # Add the files found in the directories stored by TBINDIRS
  1332. for ( $i=0; $i < @TBINDIRS; $i++ ) {
  1333. $recref = $TBINDIRS[$i];
  1334. # Load all files from the SrcPath directory
  1335. @files = ();
  1336. @files = `dir /a-d-h /b $recref->{SrcPath} 2\>nul`;
  1337. print "\t$recref->{SrcPath}\n";
  1338. # Add one entry in REPOSITORY for each file found at SrcPath
  1339. for ( $j=0; $j < @files; $j++ ) {
  1340. chop $files[$j];
  1341. # $_.='$' if (substr($_,-1) eq '$');
  1342. # Found that in NT5, the result of dir /b starts with an empty line
  1343. if ( "$files[$j]" eq "" ) {
  1344. next;
  1345. }
  1346. $recref->{SrcFile} = $files[$j];
  1347. $recref->{DestFile} = $recref->{SrcFile};
  1348. # Call AddEntry with 0, to inhibit the file existence checking,
  1349. # as SrcFile is a result of a dir command (see above).
  1350. &AddEntry( $recref, 0);
  1351. } # for
  1352. } # for
  1353. @TBINDIRS = ();
  1354. return;
  1355. } # AddFiles
  1356. # AddEntry
  1357. # Adds a new entry to REPOSITORY, only if REPOSITORY does not already have an
  1358. # entry with the same (DestPath, DestFile) key.
  1359. # Input
  1360. # new record (reference)
  1361. # boolean argument, saying if the file existence should be checked
  1362. # Output
  1363. # none
  1364. # Usage
  1365. # &AddEntry( $recref);
  1366. sub AddEntry {
  1367. my($recref, $e_check) = @_;
  1368. # Db key
  1369. my %key;
  1370. # Add entry to Repository based on file existence and on
  1371. # the type of the call (clean, incremental, with or without targets)
  1372. $recref->{DestFile} !~/\s/ or
  1373. &Error( 4001, "\"$recref->{SrcPath}\\$recref->{SrcFile}\"") and return;
  1374. if ( ( &IsEmptyHash( \%FILTER ) || # no filters
  1375. &IsHashKey( \%FILTER, $recref->{DestFile} ) ) # filter file
  1376. &&
  1377. ( $CLEAN || # clean sysgen
  1378. &IsEmptyHash( \%TARGETS ) || # incremental with no targets specified
  1379. &IsHashKey( \%TARGETS, $recref->{DestFile} ) ) # incremental with targets, and the current
  1380. # entry is one of the targets
  1381. ) {
  1382. if ( $e_check ) {
  1383. if ( ! -e "$recref->{SrcPath}\\$recref->{SrcFile}" ) {
  1384. &Error( 2101, "$recref->{SrcPath}\\$recref->{SrcFile}" );
  1385. return;
  1386. } # if
  1387. } # if
  1388. # Set the key
  1389. $key{DestPath} = $recref->{DestPath};
  1390. $key{DestFile} = $recref->{DestFile};
  1391. &AddFileInfo( $recref, \%key );
  1392. } # if
  1393. return;
  1394. } # AddEntry
  1395. # AddFileInfo
  1396. # Input
  1397. # record to be added
  1398. # Output
  1399. # <none>
  1400. # Usage
  1401. # &AddFileInfo( $recref, \%key );
  1402. sub AddFileInfo {
  1403. my($recref, $keyref) = @_;
  1404. # Nothing to do if the DestFile already has an entry in the Repository
  1405. ( ! &IsRepositKey( \%REPOSITORY, $keyref ) ) || return;
  1406. if ( &IsHashKey( \%TARGETS, $keyref->{DestFile} ) ) {
  1407. &AddTargetPath( $keyref->{DestFile}, "NewDestPath", $keyref->{DestPath} );
  1408. } # if
  1409. if ( &IsHashKey( \%FILTER, $recref->{DestFile} ) ) {
  1410. $FILTER{lc( $recref->{DestFile} )}++;
  1411. } # if
  1412. # Set the fields of the new entry
  1413. &SetField( \%REPOSITORY, $keyref, "DestPath", $recref->{DestPath} );
  1414. &SetField( \%REPOSITORY, $keyref, "DestFile", $recref->{DestFile} );
  1415. &SetField( \%REPOSITORY, $keyref, "SrcPath", $recref->{SrcPath} );
  1416. &SetField( \%REPOSITORY, $keyref, "SrcFile", $recref->{SrcFile} );
  1417. &SetField( \%REPOSITORY, $keyref, "SrcDbg", $recref->{SrcDbg} );
  1418. &SetField( \%REPOSITORY, $keyref, "DestDbg", $recref->{DestDbg} );
  1419. SWITCH: {
  1420. if ( $recref->{Xcopy} eq "y" ) {
  1421. &SetField( \%REPOSITORY, $keyref, "OpType", "1" );
  1422. last SWITCH;
  1423. } # case
  1424. # default
  1425. ## &SetField( \%REPOSITORY, $keyref, "OpType", "0" );
  1426. } # SWITCH
  1427. return;
  1428. } # AddFileInfo
  1429. # IsRepositKey
  1430. # Looks in REPOSITORY for the given key.
  1431. # Used to decide if a record will be added or not to REPOSITORY.
  1432. # Input
  1433. # map (reference)
  1434. # the key (reference)
  1435. # Output
  1436. # 1 if the key is found and 0 otherwise
  1437. # Usage
  1438. # $is_key_found = &IsRepositKey( \%REPOSITORY, $keyref );
  1439. sub IsRepositKey {
  1440. # my( $mapref, $keyref ) = @_;
  1441. # The key referred by keyref is modified,
  1442. # but this saves a lot of execution time
  1443. # so we prefer not to work with a copy of the key
  1444. return ( exists $_[0]->{lc$_[1]->{DestPath}}->{lc$_[1]->{DestFile}} );
  1445. } # IsRepositKey
  1446. # DeleteKey
  1447. # Input
  1448. # map name (one of REPOSITORY, CMD_REPOSITORY) (reference)
  1449. # key (reference)
  1450. # Output
  1451. # none
  1452. sub DeleteKey {
  1453. # my( $mapref, $keyref ) = @_;
  1454. # The key referred by keyref is modified,
  1455. # but this saves a lot of execution time
  1456. # so we prefer not to work with a copy of the key
  1457. delete $_[0]->{lc$_[1]->{DestPath}}->{lc$_[1]->{DestFile}};
  1458. } # DeleteKey
  1459. # FillTokens
  1460. # Adds info regarding tokens in REPOSITORY (TTOKENS and TTOKDIRS).
  1461. # Input & Output <none>
  1462. # Usage
  1463. # &FillTokens();
  1464. sub FillTokens {
  1465. # Current entry from TTOKDIRS
  1466. my $recref;
  1467. # List of files found in the current directory
  1468. my @files;
  1469. # Indexes
  1470. my( $i, $j, $k );
  1471. # Custom resource file name
  1472. my $custfile;
  1473. # Custom reosurces array
  1474. my @custres;
  1475. # Custom reosurces hash for verification
  1476. my %custres_h;
  1477. # Temporary store the file hash for special sort @files
  1478. my %hashfiles;
  1479. print "Filling token data...\n";
  1480. # Fill in TTOKENS
  1481. for ( $i=0; $i < @TTOKENS; $i++ ) {
  1482. $recref = $TTOKENS[$i];
  1483. # rsrc
  1484. if ( &IsRsrcTok( $recref->{TokFile} ) ) {
  1485. &FillTokEntry( $recref, 1 );
  1486. next;
  1487. } # if
  1488. # bingen
  1489. if ( &IsBgnTok( $recref->{TokFile} ) ) {
  1490. # Identify all the custom resources under the following assumptions:
  1491. # * the token and the custom resources of a binary are in the same directory
  1492. # * for a "<binary_name>.<token_extension>" token, a custom resource has
  1493. # the name <binary_name>_<binary_extension>_<custom_resource_name>
  1494. # * a token is always followed in lexicographic order by its custom resources
  1495. # or by another token
  1496. # Parse the token file to find embeded files
  1497. # open(F, "$recref->{TokPath}\\$recref->{TokFile}");
  1498. # my @text=<F>;
  1499. # close(F);
  1500. # for $str (@text) {
  1501. # if (($str=~/\[[^\]]+\|1\|0\|4\|\"[\w\.]*\"]+\=(\w+\.\w+)\s*$/)&&(-e $1)) {
  1502. # $custres_h{$1}=0;
  1503. # }
  1504. # }
  1505. # undef @text;
  1506. # Store it to an array for later use
  1507. # @custres=keys %custres_h;
  1508. # Verify all its names' token files are included
  1509. $custfile = $recref->{DestFile};
  1510. $custfile =~ s/\./_/g;
  1511. @custres=`dir /a-d-h /b /on $recref->{TokPath}\\$custfile\* 2\>nul`;
  1512. # map({$custres_h{$_}++} `dir /a-d-h /b /on $recref->{TokPath}\\$custfile\* 2\>nul`);
  1513. # map({&Error(2020, $_) if ($custres_h{$_} eq 0)} keys %custres_h);
  1514. $recref->{CustRc} = "";
  1515. for ( $j=0; $j < @custres; $j++ ) {
  1516. chop $custres[$j];
  1517. # $_.='$' if (substr($_,-1) eq '$');
  1518. # Found that in NT5, the result of dir /b starts with an empty line
  1519. if ( $custres[$j] eq "" ) {
  1520. next;
  1521. } # if
  1522. $recref->{CustRc} .= " \\\n\t\t\t$recref->{TokPath}\\$custres[$j]";
  1523. } # for
  1524. # Call FillTokEntry with 1, meaning that the existence of the
  1525. # token file is queried and a non fatal error fired if the file
  1526. # is missing.
  1527. # As the token is explicitly listed in TOKENS MAP, it is natural
  1528. # to suppose it should exist.
  1529. &FillTokEntry( $recref, 1 );
  1530. next;
  1531. } # if
  1532. # default
  1533. &Error( 2013, "$recref->{TokPath}\\$recref->{TokFile}" );
  1534. } #for
  1535. @TTOKENS = ();
  1536. # Fill in TTOKDIRS
  1537. for ( $i=0; $i < @TTOKDIRS; $i++ ) {
  1538. $recref = $TTOKDIRS[$i];
  1539. print "\t$recref->{TokPath}\n";
  1540. # Load all files from the TokPath directory
  1541. # @files = ();
  1542. %hashfiles=map({&fullnamevalue()} `dir /a-d-h /l /b $recref->{TokPath} 2\>nul`);
  1543. @files=sort {$hashfiles{$a} cmp $hashfiles{$b}} keys %hashfiles; # because in the same folder, so we could ignore \a\b.txt, \a\b\c.txt, \a\c.txt problem.
  1544. # Fill in the corresponding entry from REPOSITORY for each token found at TokPath
  1545. for ( $j=0; $j < @files; $j++ ) {
  1546. # Found that in NT5, the result of dir /b starts with an empty line (bug)
  1547. if ( $files[$j] eq "" ) { next; }
  1548. # bingen
  1549. if ( &IsBgnTok( $files[$j] ) ) {
  1550. $recref->{TokFile} = $files[$j];
  1551. $recref->{DestFile} = &TokToFile( $recref->{TokFile} );
  1552. # Verify if the next entry in @files is an rsrc token for the same filename
  1553. if ( $j < @files-1 && &IsRsrcTok( $files[$j+1] ) ) {
  1554. if ( &TokToFile( $files[$j]) eq &TokToFile( $files[$j+1] ) ) {
  1555. &Error( 2018, "$recref->{DestPath}\\$files[$j] and $recref->{DestPath}\\$files[$j+1]");
  1556. $j = $j+1;
  1557. } # if
  1558. } # if
  1559. # Identify file's custom resources
  1560. $custfile = $recref->{DestFile};
  1561. $custfile =~ s/\./_/g;
  1562. $recref->{CustRc} = "";
  1563. for ( $k = $j+1; $k < @files; $k++ ) {
  1564. if ( &IsCustRes( $files[$k], $custfile ) ) {
  1565. $recref->{CustRc} .= " \\\n\t\t\t$recref->{TokPath}\\$files[$k]";
  1566. } # if
  1567. else {
  1568. last;
  1569. } # else
  1570. } # for
  1571. $j = $k-1;
  1572. # Call FillTokEntry with 0, to inhibit the file existence checking,
  1573. # as TokFile is a result of a dir command (see above).
  1574. &FillTokEntry( $recref, 0, \@custres );
  1575. next;
  1576. } # if
  1577. else {
  1578. # rsrc
  1579. if ( &IsRsrcTok( $files[$j] ) ) {
  1580. $recref->{TokFile} = $files[$j];
  1581. $recref->{DestFile} = &TokToFile($recref->{TokFile});
  1582. # look for bogus custom resources
  1583. $custfile = $recref->{DestFile};
  1584. $custfile =~ s/\./_/g;
  1585. for ( $k = $j+1; $k < @files; $k++ ) {
  1586. if ( &IsCustRes( $files[$k], $custfile ) ) {
  1587. &Error( 2019, "$recref->{TokPath}\\$files[$k] for $recref->{TokPath}\\$files[$j]" );
  1588. } # if
  1589. else {
  1590. last;
  1591. } # else
  1592. } # for
  1593. $j = $k-1;
  1594. &FillTokEntry( $recref, 0, \@custres );
  1595. next;
  1596. } # if
  1597. else {
  1598. # default
  1599. &Error( 2013, "$recref->{TokPath}\\$files[$j]" );
  1600. } # else
  1601. } #else
  1602. } # for
  1603. } # for
  1604. @TTOKDIRS = ();
  1605. } # FillTokens
  1606. sub fullnamevalue {
  1607. chop;
  1608. # $_.='$' if (substr($_,-1) eq '$');
  1609. /^([^\.\_]+)/o;
  1610. my($value, $key)=($1, $_);
  1611. while (/([\.\_])([^\.\_]*)/go) {
  1612. $value .= (exists $MAP_BINGEN_TOK_EXT{".$2"})?"_" . $MAP_BINGEN_TOK_EXT{".$2"} : "_$2";
  1613. }
  1614. return ($key, $value);
  1615. }
  1616. # FillTokEntry
  1617. # Given a REPOSITORY key, adds info on tokens (@TTOKENS and @TTOKDIRS).
  1618. # Input
  1619. # a token record
  1620. # boolean argument, saying if the existence of the token needs to be verified
  1621. # Output
  1622. # <none>
  1623. sub FillTokEntry {
  1624. my($recref, $e_check) = @_;
  1625. # %key = is a hash table (as defined by the database key)
  1626. my %key;
  1627. # Token information is added to an existing Repository entry
  1628. # based on token file existance and the type of the sysgen call
  1629. # (clean, incremental with or without targets)
  1630. if ( ( &IsEmptyHash( \%FILTER ) || # no filter
  1631. &IsHashKey( \%FILTER, $recref->{DestFile} ) ) # filter file
  1632. &&
  1633. ( $CLEAN || # clean sysgen
  1634. &IsEmptyHash( \%TARGETS ) || # incremental without targets
  1635. &IsHashKey( \%TARGETS, $recref->{DestFile} ) ) # incremental with targets and the current
  1636. # entry corresponds to a target
  1637. ) {
  1638. if ( $e_check ) {
  1639. if ( ! -e "$recref->{TokPath}\\$recref->{TokFile}" ) {
  1640. &Error( 2102, "$recref->{TokPath}\\$recref->{TokFile}" );
  1641. return;
  1642. } # if
  1643. } # if
  1644. # Set REPOSITORY key
  1645. $key{DestPath} = $recref->{DestPath};
  1646. $key{DestFile} = $recref->{DestFile};
  1647. # Fill in the information needed in REPOSITORY
  1648. &FillTokInfo( $recref, \%key );
  1649. } # if
  1650. return;
  1651. } # FillTokEntry
  1652. # FillTokInfo
  1653. # Adds information for bingen switches to an existing REPOSITORY entry.
  1654. # Sets the following keys ( fields ): TokPath, TokFile, BgnSw, OpType, ITokPath.
  1655. # Input
  1656. # hash table with the @FTOKENS keys, representing one token record (reference)
  1657. # key to identify the REPOSITORY entry (reference)
  1658. # Output
  1659. # <none>
  1660. # Usage
  1661. # &FillTokInfo( $recref, \%key );
  1662. sub FillTokInfo {
  1663. my( $recref, $keyref ) = @_;
  1664. # Operation type
  1665. my $optype;
  1666. # A token record does not create new entries, just adds/updates fields of an existing entry.
  1667. if ( ! &ExistsBinForTok( $keyref, $recref ) ) {
  1668. my $notfound = 1;
  1669. my $key = lc($recref->{"TokPath"}."\\".$recref->{"TokFile"});
  1670. my $hotfix = \%hotfix;
  1671. foreach my $fix (keys(%hotfix)){
  1672. my $depend = $hotfix->{$fix}->{"depend"};
  1673. foreach $dep (@$depend){
  1674. if ($key eq $dep) {
  1675. print STDERR "found hotfix for $key\n" if $DEBUG;
  1676. $notfound = 0;
  1677. }
  1678. }
  1679. }
  1680. if ($notfound){
  1681. &Error( 2011, "$recref->{TokPath}\\$recref->{TokFile}" );
  1682. return;
  1683. }
  1684. } # if
  1685. # If no key found in REPOSITORY for this entry, then return.
  1686. # ( the token does not follow the default rule given by the TOKDIRS map;
  1687. # it might be associated with another binary via the TOKENS map )
  1688. if ( ! &IsRepositKey( \%REPOSITORY, $keyref ) ) { return; }
  1689. # Verify if the binary is locked (XCopy = y) for localization.
  1690. # If locked, the binary will not be localized via bingen or rsrc and an xcopy command
  1691. # will apply instead, even though a token exists in the token tree.
  1692. $optype = &GetFieldVal( \%REPOSITORY, $keyref, "OpType" );
  1693. SWITCH: {
  1694. if ( $optype eq "1" ) {
  1695. &Error( 2014, sprintf( "%s\\%s for %s\\%s",
  1696. $recref->{TokPath},
  1697. $recref->{TokFile},
  1698. &GetFieldVal( \%REPOSITORY, $keyref, "SrcPath" ),
  1699. &GetFieldVal( \%REPOSITORY, $keyref, "SrcFile" ) ) );
  1700. return;
  1701. } # if
  1702. if ( $optype eq "2" ) {
  1703. my($previous, $current)=(&GetFieldVal( \%REPOSITORY, $keyref, "TokPath" ) . "\\" .
  1704. &GetFieldVal( \%REPOSITORY, $keyref, "TokFile" ),
  1705. $recref->{TokPath} . "\\" . $recref->{TokFile});
  1706. &Error( 2012, sprintf( "%s and %s",
  1707. $previous, $current)) if ($previous ne $current);
  1708. return;
  1709. } # if
  1710. if ( $optype eq "-" ) {
  1711. # Set the token-related fields for the binary given by the key
  1712. &SetField( \%REPOSITORY, $keyref, "TokPath", $recref->{TokPath} );
  1713. &SetField( \%REPOSITORY, $keyref, "TokFile", $recref->{TokFile} );
  1714. &SetField( \%REPOSITORY, $keyref, "OpType", "2" );
  1715. &SetField( \%REPOSITORY, $keyref, "ITokPath", $recref->{ITokPath} );
  1716. &SetField( \%REPOSITORY, $keyref, "BgnSw", $recref->{BgnSw} );
  1717. &SetField( \%REPOSITORY, $keyref, "LocOp", $recref->{LocOp} );
  1718. &SetField( \%REPOSITORY, $keyref, "CustRc", $recref->{CustRc} );
  1719. last SWITCH;
  1720. } # if
  1721. # default
  1722. &FatalError( 3011, sprintf( "$recref->{DestPath}\\$recref->{DestFile} %s",
  1723. &GetFieldVal( \%REPOSITORY, $keyref, "OpType") ) );
  1724. } # SWITCH
  1725. return;
  1726. } # FillTokInfo
  1727. # ExistsBinForTok
  1728. # Looks in Repository for an entry corresponding to a given token
  1729. # Input
  1730. # a token record ( reference )
  1731. # a Repository key ( reference )
  1732. # Output
  1733. # 1 - entry found ( token info might be already completed )
  1734. # 0 - otherwise
  1735. # Example
  1736. # if ( &ExistsBinForTok( $recref ) ) { ... }
  1737. sub ExistsBinForTok {
  1738. my( $keyref, $recref ) = @_;
  1739. # Copy key
  1740. my %tmpkey;
  1741. # Tok info ( Repository )
  1742. my( $tokpath, $tokfile );
  1743. if ( &IsRepositKey( \%REPOSITORY, $keyref ) ) { return 1; }
  1744. $tmpkey{DestFile} = $keyref->{DestFile};
  1745. for ( keys %REPOSITORY ) {
  1746. $tmpkey{DestPath} = $_;
  1747. if ( &IsRepositKey( \%REPOSITORY, \%tmpkey ) ) {
  1748. $tokpath = &GetFieldVal( \%REPOSITORY, \%tmpkey, "TokPath" );
  1749. $tokfile = &GetFieldVal( \%REPOSITORY, \%tmpkey, "TokFile" );
  1750. if ( lc($tokfile) eq lc($recref->{TokFile}) && lc($tokpath) eq lc($recref->{TokPath}) ) {
  1751. return 1;
  1752. } # if
  1753. } # if
  1754. } # for
  1755. return 0;
  1756. } # ExistsBinForTok
  1757. # TokToFile
  1758. # Converts a given bingen token name to a binary name.
  1759. # Input
  1760. # token name
  1761. # Output
  1762. # binary name
  1763. # Usage
  1764. # $fname = &TokToFile( $tokname );
  1765. sub TokToFile {
  1766. my( $tokname ) = @_;
  1767. # Output
  1768. my $imagename;
  1769. # Token extension name
  1770. my $tokext;
  1771. chomp $tokname;
  1772. $imagename = $tokname;
  1773. # rsrc token
  1774. if ( &IsRsrcTok( $tokname ) ) {
  1775. $imagename =~ s/\.rsrc//;
  1776. return $imagename;
  1777. } # if
  1778. # bingen token
  1779. if ( &IsBgnTok( $tokname ) ) {
  1780. $tokext = $tokname;
  1781. $tokext =~ /(\.\w+_)/;
  1782. $tokext = $1;
  1783. if ( not exists $MAP_BINGEN_TOK_EXT{lc($tokext)} ) {
  1784. &Error( 2017, $tokname);
  1785. return;
  1786. } # if
  1787. $imagename =~ s/$tokext/$MAP_BINGEN_TOK_EXT{lc($tokext)}/i;
  1788. return $imagename;
  1789. } # if
  1790. # default
  1791. &Error( 2013, $tokname );
  1792. } # TokToFile
  1793. sub IsRsrcTok {
  1794. ($_[0]=~/\.rsrc\r?$/i)|0;
  1795. } # IsRsrcTok
  1796. sub IsRsrcOp {
  1797. &IsRsrcTok( shift );
  1798. } # IsRsrcOp
  1799. sub IsBgnTok {
  1800. ($_[0]=~/_\r?$/)|0;
  1801. } # IsBgnTok
  1802. sub IsBgnOp {
  1803. &IsBgnTok(shift);
  1804. } # IsBgnOp
  1805. sub IsCustRes {
  1806. my $name = shift;
  1807. $name=~ s/\./_/g;
  1808. ($name=~/$_[0]/)|0;
  1809. } # IsCustRes
  1810. # SetField
  1811. # Updates a key (field) of a given REPOSITORY entry with a given value.
  1812. # Input
  1813. # map (reference)
  1814. # key value (reference)
  1815. # field name
  1816. # field value
  1817. # Output
  1818. # none
  1819. # Usage
  1820. # &SetField( \%key, "TokPath", $TokPath );
  1821. sub SetField {
  1822. # my( $mapref, $keyref, $fname, $fval ) = @_;
  1823. # The key referred by keyref is modified,
  1824. # but this saves a lot of execution time
  1825. # so we prefer not to work with a copy of the key
  1826. # $mapref->{$keyref->{DestPath}}->{$keyref->{DestFile}}->{$fname} = $fval if ($fval ne '-');
  1827. $_[0]->{lc$_[1]->{DestPath}}->{lc$_[1]->{DestFile}}->{$_[2]} = $_[3] if ($_[3] ne '-');
  1828. return;
  1829. } # SetField
  1830. # PushFieldVal
  1831. # Add one element to a field storing an array ({Cmd} field for REPOSITORY)
  1832. # Input
  1833. # map (reference)
  1834. # key value (reference)
  1835. # field name
  1836. # field value
  1837. # Output
  1838. # none
  1839. # Usage
  1840. # &PushFieldVal();
  1841. sub PushFieldVal {
  1842. # my( $mapref, $keyref, $fname, $fval ) = @_;
  1843. # The key referred by keyref is modified,
  1844. # but this saves a lot of execution time
  1845. # so we prefer not to work with a copy of the key
  1846. push @{$_[0]->{lc$_[1]->{DestPath}}->{lc$_[1]->{DestFile}}->{$_[2]}}, $_[3] if ($_[3] ne '-');
  1847. } # PushFieldVal
  1848. # GetFieldVal
  1849. # Return the value of a particular key of a given REPOSITORY entry.
  1850. # Input
  1851. # map (reference)
  1852. # key value (reference)
  1853. # name of the searched field
  1854. # Output
  1855. # the value of the searched field
  1856. # Usage
  1857. # $srcpath = &GetFieldVal( \%REPOSITORY, \%key, "SrcPath" );
  1858. sub GetFieldVal {
  1859. defined($_[0]->{lc($_[1]->{"DestPath"})}->{lc($_[1]->{"DestFile"})}->{$_[2]})?
  1860. $_[0]->{lc($_[1]->{"DestPath"})}->{lc($_[1]->{"DestFile"})}->{$_[2]}
  1861. : "-";
  1862. } # GetFieldVal
  1863. # GenNmakeFiles
  1864. # For each entry found in the REPOSITORY, generate the NMAKE description blocks
  1865. # and write them to a makefile. Also generate a nmake command file with command-line
  1866. # parameters for nmake.
  1867. # Input
  1868. # directory where the nmake files are generated
  1869. # Output
  1870. # none
  1871. # Usage
  1872. # &GenNmakeFiles(".");
  1873. sub GenNmakeFiles {
  1874. my( $nmakedir ) = @_;
  1875. print "Generating $nmakedir\\makefile...\n";
  1876. # Update CMD_REPOSITORY for TARGETS with updated data from REPOSITORY
  1877. &UpdTargetEntries();
  1878. # Identify all targets with description block changed
  1879. # and keep them in SYSCMD
  1880. &FillSyscmd();
  1881. &GenMakeDir();
  1882. # FIX The REPOSITORY changes described in hotfix
  1883. &FixRepository();
  1884. # Write the makefile
  1885. &WriteToMakefile( "$nmakedir\\makefile", "$nmakedir\\syscmd" );
  1886. # Write the syscmd file
  1887. &WriteToSyscmd( "$nmakedir\\syscmd" );
  1888. if ( -e "$nmakedir\\makefile" ) {
  1889. print "\n$nmakedir\\makefile is ready for execution.\n";
  1890. print "Call \"nmake\" to complete aggregation (single thread).\n";
  1891. print "Call \"mtnmake sysgen\" to complete aggregation (mutiple threads).\n";
  1892. } # if
  1893. else {
  1894. print "No MAKEFILE generated. Nothing to do.\n";
  1895. } # else
  1896. return;
  1897. } # GenNmakeFiles
  1898. # FillSyscmd
  1899. # Fills in @SYSCMD global variable with the target names having their description
  1900. # block changed. It is used for incremental calls only.
  1901. # Input & Output
  1902. # none
  1903. sub FillSyscmd {
  1904. # Repository key
  1905. my %key;
  1906. # Destinationa path, destination file
  1907. my( $destpath, $destfile );
  1908. # Nothing to do in case of:
  1909. # clean sysgen
  1910. # incremental sysgen with targets
  1911. if ( $CLEAN || !&IsEmptyHash( \%TARGETS ) ) {
  1912. return;
  1913. } # if
  1914. # The call is incremental, without targets, and a previous makefile exists
  1915. # It is fine to use REPOSITORY in this case;
  1916. # the only case when we use CMD_REPOSITORY to write info to the makefile
  1917. # is an incremental sysgen with targets (when a makefile already exists).
  1918. # Compare all description blocks
  1919. for $destpath ( sort keys %REPOSITORY ) {
  1920. for $destfile ( sort keys %{$REPOSITORY{$destpath}} ) {
  1921. $key{DestPath} = $destpath;
  1922. $key{DestFile} = $destfile;
  1923. # Store in SYSCMD the keys with changed description blocks
  1924. if ( &CmdCompare( \%key ) ) {
  1925. push @SYSCMD, "$destpath\\$destfile";
  1926. } # if
  1927. } # for
  1928. } # for
  1929. return;
  1930. } # FillSyscmd
  1931. # WriteToMakefile
  1932. # Generate the makefile
  1933. # Input
  1934. # makefile name, syscmd file name
  1935. # Output
  1936. # none
  1937. sub WriteToMakefile {
  1938. my( $makefname, $sysfname ) = @_;
  1939. # Open the makefile
  1940. ( open MAKEFILE, ">"."$makefname" ) || &FatalError( 1007, $makefname );
  1941. select( MAKEFILE );
  1942. # Write "sysgen" target
  1943. &WriteSysgenTarget($sysfname );
  1944. # Write "all" target
  1945. &WriteAllTarget();
  1946. # Write file-by-file description blocks
  1947. &WriteFileCmds();
  1948. close(MAKEFILE);
  1949. select( STDOUT );
  1950. return;
  1951. } # WriteToMakefile
  1952. # WriteSysgenTarget
  1953. # Write "sysgen" target in the generated makefile
  1954. # It invokes nmake recursively.
  1955. # Input
  1956. # filename (including path) of the generated syscmd file
  1957. # Output
  1958. # none
  1959. # Usage
  1960. # &WriteSysgenTarget("$nmakedir\\syscmd");
  1961. sub WriteSysgenTarget {
  1962. my($cmdfile) = @_;
  1963. printf "sysgen: \n";
  1964. # Call nmake @syscmd in the following cases:
  1965. # sysgen with targets (clean or incremental)
  1966. # incremental sysgen without targets, but with changes in the description blocks
  1967. if ( !&IsEmptyHash( \%TARGETS ) || ( !$CLEAN && ( @SYSCMD > 0 ) ) ) {
  1968. printf "\t\@nmake \@$cmdfile /K /NOLOGO\n";
  1969. } # if
  1970. # Call nmake all in the following cases:
  1971. # sysgen without targets (clean or incremental)
  1972. if ( &IsEmptyHash( \%TARGETS ) ) {
  1973. if ( $CLEAN ) {
  1974. printf "\t\@nmake /A all /K /NOLOGO\n";
  1975. } # if
  1976. else {
  1977. printf "\t\@nmake all /K /NOLOGO\n";
  1978. } # else
  1979. } # if
  1980. printf "\n";
  1981. return;
  1982. } # WriteSysgenTarget
  1983. # WriteAllTarget
  1984. # Writes "all"'s target dependency line in the makefile.
  1985. # Input & Output
  1986. # none
  1987. # Usage
  1988. # &WriteAllTarget();
  1989. sub WriteAllTarget {
  1990. # Table (reference): REPOSITORY or CMD_REPOSITORY
  1991. my $mapref;
  1992. # Destination path, destination file
  1993. my( $destpath, $destfile );
  1994. my $chars;
  1995. my $steps;
  1996. my @alltargets;
  1997. my $i;
  1998. my $j;
  1999. my $k;
  2000. my $total=0;
  2001. # Use data from CMD_REPOSITORY or REPOSITORY,
  2002. # depending if SYSGEN is called or not incrementally,
  2003. # with or without targets.
  2004. $mapref = \%CMD_REPOSITORY;
  2005. if ( $CLEAN || &IsEmptyHash( \%TARGETS ) ) {
  2006. $mapref = \%REPOSITORY;
  2007. } # if
  2008. # MAKEFILE file handler is the default.
  2009. print "all : \\\n\t" ;
  2010. $i = 0;
  2011. @alltargets = map({$total+=scalar(keys %{$mapref->{$_}});$_;} sort keys %{$mapref});
  2012. if ($alltargets[$i]=~/\\\\\\makedir/) {
  2013. print "\\\\\\Makedir\\Makedir ";
  2014. $i++;
  2015. }
  2016. $SECTIONS = $DEFAULT_SECTIONS if ($SECTIONS!~/\d+/);
  2017. $SECTIONS = 1 if ($#alltargets < $SECTIONS);
  2018. $chars=length($SECTIONS);
  2019. $steps=$total / $SECTIONS;
  2020. for ($j = 1; $j <= $SECTIONS; $j++) {
  2021. printf("${SECTIONNAME}\%0${chars}d\%0${chars}d ", $SECTIONS, $j);
  2022. }
  2023. for ($j = 0, $k = 0;$i <= $#alltargets; $i++) {
  2024. for $destfile ( sort keys %{$mapref->{$alltargets[$i]}} ) {
  2025. if ($j <= $k++) {
  2026. $j += $steps;
  2027. printf("\n\n${SECTIONNAME}\%0${chars}d\%0${chars}d : ", $SECTIONS, $j / $steps);
  2028. }
  2029. $key{DestPath} = $alltargets[$i];
  2030. $key{DestFile} = $destfile;
  2031. my $quot_ = $destfile =~ /\s/ ? "\"":"";
  2032. printf( " \\\n\t${quot_}%s\\%s${quot_}",
  2033. &GetFieldVal( $mapref, \%key, "DestPath" ),
  2034. &GetFieldVal( $mapref, \%key, "DestFile" ) );
  2035. } # for
  2036. } # for
  2037. print " \n\n";
  2038. return;
  2039. } # WriteAllTarget
  2040. # WriteFileCmds
  2041. # For every file, write its dependency block in the makefile.
  2042. # Input & Output
  2043. # none
  2044. # Usage
  2045. # &WriteFileCmds();
  2046. sub WriteFileCmds {
  2047. # Table (reference): REPOSITORY or CMD_REPOSITORY
  2048. my $mapref;
  2049. # Counter
  2050. my $i;
  2051. # Reference to the Cmd field
  2052. my $cmdref;
  2053. # Destinationa path, destination file
  2054. my( $destpath, $destfile );
  2055. # Use data from CMD_REPOSITORY or REPOSITORY,
  2056. # depending if SYSGEN is called or not incrementally,
  2057. # with or without targets.
  2058. $mapref = \%CMD_REPOSITORY;
  2059. if ( $CLEAN || &IsEmptyHash( \%TARGETS ) ) {
  2060. $mapref = \%REPOSITORY;
  2061. } # if
  2062. # Write file-by-file description blocks
  2063. for $destpath ( sort keys %{$mapref} ) {
  2064. for $destfile ( sort keys %{$mapref->{$destpath}} ) {
  2065. # Print {Cmd} field
  2066. $cmdref = \@{$mapref->{$destpath}->{$destfile}->{Cmd}};
  2067. for ( $i=0; $i < @{$cmdref}; $i++ ) {
  2068. print $cmdref->[$i];
  2069. } # for
  2070. print "\n";
  2071. } # for
  2072. } # for
  2073. return;
  2074. } # WriteFileCmds
  2075. # CmdCompare
  2076. # Given a key, compare the {Cmd} field from REPOSITORY to the {Cmd} CMD_REPOSITORY field.
  2077. # Input
  2078. # repository type key (reference)
  2079. # Output
  2080. # 0 if commands compare OK
  2081. # 1 if commands are different
  2082. # Usage
  2083. # $is_different = &CmdCompare( \%key );
  2084. sub CmdCompare {
  2085. my( $keyref ) = @_;
  2086. # Cmd fields
  2087. my( $repref, $cmdref );
  2088. # Indexes
  2089. my $i;
  2090. $repref = &GetFieldVal( \%REPOSITORY, $keyref, "Cmd" );
  2091. $cmdref = &GetFieldVal( \%CMD_REPOSITORY, $keyref, "Cmd" );
  2092. if ( scalar( @{$repref} ) != scalar( @{$cmdref} ) ) { return 1; }
  2093. for ( $i = 0; $i < @{$repref}; $i++ ) {
  2094. if ( lc( $repref->[$i] ) ne lc( $cmdref->[$i] ) ) { return 1; }
  2095. } # for
  2096. return 0;
  2097. } # CmdCompare
  2098. # RecordToCmd
  2099. # Converts one entry from REPOSITORY to a set of cmd instructions,
  2100. # stored in the REPOSITORY as well
  2101. # Input
  2102. # key identifying the REPOSITORY entry (reference)
  2103. # Output
  2104. # none
  2105. # Usage
  2106. # &RecordToCmd( $keyref );
  2107. sub RecordToCmd {
  2108. #Input
  2109. my( $keyref ) = @_;
  2110. # Build the command array according to the operation type (xcopy or bingen)
  2111. SWITCH: {
  2112. if ( &IsXcopyCmd( $keyref ) ) {
  2113. &GenXcopy( $keyref );
  2114. last SWITCH;
  2115. } # if
  2116. if ( &IsLocCmd( $keyref ) ) {
  2117. &GenLocCmd( $keyref );
  2118. last SWITCH;
  2119. } # if
  2120. # default
  2121. &FatalError( 3011,
  2122. sprintf "$keyref->{DestPath}\\$keyref->{DestFile} %s",
  2123. &GetFieldVal( \%REPOSITORY, $keyref, "OpType") );
  2124. } # SWITCH
  2125. # Now generate the muibld command line
  2126. # No more processing if the entry is not anymore in Repository
  2127. # (for ex. because DeleteKey was called by GenBgnCmd)
  2128. if ( ! &IsRepositKey( \%REPOSITORY, $keyref ) ) {
  2129. return;
  2130. } # if
  2131. if ( ! &GetMacro( "ntdebug" ) && # only retail builds
  2132. &GetMacro( "GENERATE_MUI_DLLS" ) # and only when requested
  2133. ) {
  2134. &GenMUICmd( $keyref );
  2135. } # if
  2136. } # RecordToCmd
  2137. # IsXcopyCmd
  2138. # Verifies if one entry from REPOSITORY corresponds to an xcopy command.
  2139. # Input
  2140. # key identifying the REPOSITORY entry (reference)
  2141. # Output
  2142. # 1 for xcopy, 0 otherwise
  2143. # Usage
  2144. # $bxcopy = &IsXcopyCmd( $keyref );
  2145. sub IsXcopyCmd {
  2146. my( $keyref ) = @_;
  2147. # Output
  2148. $bxcopy = 0;
  2149. # Operation Type
  2150. my $optype;
  2151. # Look for the value of OpType
  2152. # "0" or "1" indicates that an xcopy command corresponds to this record
  2153. $optype = &GetFieldVal( \%REPOSITORY, $keyref, "OpType" );
  2154. SWITCH: {
  2155. if ( $optype eq "-" ) {
  2156. $bxcopy = 1;
  2157. last SWITCH;
  2158. } #if
  2159. if ( $optype eq "1" ) {
  2160. $bxcopy = 1;
  2161. last SWITCH;
  2162. } #if
  2163. # default
  2164. # nothing to do
  2165. } # SWITCH
  2166. return $bxcopy;
  2167. } # IsXcopyCmd
  2168. # IsLocCmd
  2169. # Verifies if one entry from REPOSITORY corresponds to a bingen command.
  2170. # Input
  2171. # key identifying the REPOSITORY entry (reference)
  2172. # Output
  2173. # 1 for bingen or rsrc, 0 otherwise
  2174. # Usage
  2175. # $bbgn = &IsLocCmd( $keyref );
  2176. sub IsLocCmd {
  2177. my( $keyref ) = @_;
  2178. # Output
  2179. my $bbgn = 0;
  2180. # Operation type
  2181. my $optype;
  2182. $optype = &GetFieldVal( \%REPOSITORY, $keyref, "OpType" );
  2183. # Look for the value of OpType.
  2184. # "-a" or "-r" indicates that a localization command (bingen, rsrc, ...)
  2185. # corresponds to this record.
  2186. SWITCH: {
  2187. if ( $optype == 2 ) {
  2188. $bbgn = 1;
  2189. last SWITCH;
  2190. } #if
  2191. # default
  2192. # nothing to do
  2193. } # SWITCH
  2194. return $bbgn;
  2195. } # IsLocCmd
  2196. sub GetDynData {
  2197. my $repository = shift;
  2198. my $keyref = shift;
  2199. my $dyndata = $repository->{lc($keyref->{"DestPath"})}->{lc($keyref->{"DestFile"})};
  2200. map {$dyndata->{$_} = "-" unless $dyndata->{$_}}
  2201. keys(%REPOSITORY_TEMPLATE);
  2202. # cannot use "keys (%$dyndata);"!
  2203. $dyndata;
  2204. }
  2205. # GenXcopy
  2206. # For the given entry from REPOSITORY, generates the xcopy commands.
  2207. # Input
  2208. # key identifying the REPOSITORY entry
  2209. # Output
  2210. # none
  2211. # Usage
  2212. # &GetXcopy( $keyref );
  2213. sub GenXcopy {
  2214. return if $SYNTAX_CHECK_ONLY;
  2215. my( $keyref ) = @_;
  2216. # dbgline, pdbline, file line, dependency line
  2217. my( $dbgline, $pdbline, $symline, $fline, $dline );
  2218. # Paths and filenames for the symbols
  2219. my $dyndata = &GetDynData(\%REPOSITORY, $keyref);
  2220. my ($srcext, $srcpdb, $srcdbg, $srcsym, $dstext, $dstpdb, $dstdbg, $dstsym) =
  2221. &NewImageToSymbol($dyndata->{"SrcFile"} ,
  2222. $dyndata->{"DestFile"},
  2223. $dyndata->{"SrcPath"} ,
  2224. $dyndata->{"SrcDbg" } );
  2225. my( $srcsymfull, $dstsymfull ) = &SetSymPaths(
  2226. $dyndata->{"SrcDbg"} ,
  2227. $srcext,
  2228. $srcpdb,
  2229. $srcdbg,
  2230. $srcsym,
  2231. $dyndata->{"DestDbg"},
  2232. $dstext );
  2233. # Dependency line
  2234. $dline = $DLINE;
  2235. my $quot_ = $dyndata->{"SrcFile"} =~ /\s/ ? "\"" : "";
  2236. my $qquot_ = "\\\"" if $quot_;
  2237. $dline =~ s/RIGHT/${quot_}$dyndata->{"DestPath"}\\$dyndata->{"DestFile"}${quot_}/;
  2238. $dline =~ s/LEFT/${quot_}$dyndata->{"SrcPath"}\\$dyndata->{"SrcFile"}${quot_}/;
  2239. # Generate the copy commands for the symbols files (dbg, pdb, and sym)
  2240. $pdbline = &MakeXcopyCmd( $dyndata->{"SrcFile"},
  2241. $srcsymfull,
  2242. $srcpdb,
  2243. $dstsymfull,
  2244. $dstpdb );
  2245. $dbgline = &MakeXcopyCmd( $dyndata->{"SrcFile"},
  2246. $srcsymfull,
  2247. $srcdbg,
  2248. $dstsymfull,
  2249. $dstdbg );
  2250. $symline = &MakeXcopyCmd( $dyndata->{"SrcFile"},
  2251. $srcsymfull,
  2252. $srcsym,
  2253. $dstsymfull,
  2254. $dstsym );
  2255. # Generate binary's xcopy command
  2256. $fline = &MakeXcopyCmd( $dyndata->{"SrcFile" } ,
  2257. $dyndata->{"SrcPath" } ,
  2258. $dyndata->{"SrcFile" } ,
  2259. $dyndata->{"DestPath"} ,
  2260. $dyndata->{"DestFile"} ,
  2261. $qquot_ );
  2262. # Write the dependency line
  2263. &PushFieldVal( \%REPOSITORY, $keyref, "Cmd", "$dline\n" );
  2264. $MAKEDIR{$dyndata->{"DestPath"}} = 1;
  2265. &PushFieldVal( \%REPOSITORY, $keyref, "Cmd", "\t$fline\n" );
  2266. if ( $dbgline || $pdbline || $symline ) {
  2267. if ( $dstsymfull ne $dyndata->{"DestDbg"}) {
  2268. $MAKEDIR{$dstsymfull} = 1;
  2269. } # if
  2270. } # if
  2271. if ( $dbgline ) {
  2272. &PushFieldVal( \%REPOSITORY, $keyref, "Cmd", "\t$dbgline\n" );
  2273. } # if
  2274. if ( $pdbline ) {
  2275. &PushFieldVal( \%REPOSITORY, $keyref, "Cmd", "\t$pdbline\n" );
  2276. } # if
  2277. if ( $symline ) {
  2278. &PushFieldVal( \%REPOSITORY, $keyref, "Cmd", "\t$symline\n" );
  2279. } # if
  2280. return;
  2281. } # GenXcopy
  2282. # SetSymPaths
  2283. # Set the source and destination paths for the symbols
  2284. # Can be the same as set in the sysfile (BBT case)
  2285. # or can be the subdir with the the filename externsion.
  2286. # The decision is made based on the pdb file existence.
  2287. # Input
  2288. # SrcDbg field value
  2289. # source file extension
  2290. # source pdb file
  2291. # source dbg file
  2292. # source sym file
  2293. # DestDbg field value
  2294. # destination file extension
  2295. # Output
  2296. # path to the source symbol file
  2297. # path to the destination symbols file
  2298. sub SetSymPaths {
  2299. my( $srcpath, $srcext, $srcpdb, $srcdbg, $srcsym, $dstpath, $dstext ) = @_;
  2300. # Output
  2301. my( $srcsymfull, $dstsymfull) = ( $srcpath, $dstpath );
  2302. # Verify if the file exists in extension subdir
  2303. if ( $srcpath ne "-" &&
  2304. $dstpath ne "-" &&
  2305. ( -e "$srcpath\\$srcext\\$srcpdb" || -e "$srcpath\\$srcext\\$srcdbg" || -e "$srcpath\\$srcext\\$srcsym" ) ) {
  2306. $srcsymfull .= "\\$srcext";
  2307. $dstsymfull .= "\\$dstext";
  2308. }
  2309. return ( $srcsymfull, $dstsymfull );
  2310. } # SetSymPaths
  2311. # MakeXcopyCmd
  2312. # Generates an xcopy command for copying a given file.
  2313. # Input
  2314. # source path
  2315. # source file
  2316. # dest path
  2317. # dest file
  2318. # Output
  2319. # xcopy command
  2320. # Usage
  2321. # $xcopy = &MakeXcopyCmd( "f:\\nt\\usa\\\binaries", "advapi.dll",
  2322. # "f:\\nt\\jpn\\relbins", "advapi.dll" );
  2323. sub MakeXcopyCmd {
  2324. my( $binary, $srcpath, $srcfile, $dstpath, $dstfile, $qquot_ ) = @_;
  2325. # last argument : optional
  2326. my $result;
  2327. if (( $dstpath eq "-") || ($srcpath eq "-" ) || !(-e "$srcpath\\$srcfile")){
  2328. $result = "";
  2329. if ($PARSESYMBOLCD && defined($default{$binary})){
  2330. my %hints = %{$default{$binary}};
  2331. my $ext = $1 if ($dstfile=~/\.(\w+)$/);
  2332. if ($ext && $hints{$ext}){
  2333. my ($sympath, $symname ) =
  2334. ($hints{$ext}=~/^(.*)\\([^\\]+)$/);
  2335. my $srchead= &GetMacro("_nttree");
  2336. my $dsthead= &GetMacro("dst");
  2337. $result =
  2338. "logerr \"copy /v ${qquot_}$srchead\\$sympath\\$symname${qquot_} ".
  2339. "${qquot_}$dsthead\\$sympath\\$symname${qquot_}\"";
  2340. print STDERR " added default for $binary: \"", $ext ,"\"\n" if $DEBUG;
  2341. }
  2342. }
  2343. }
  2344. else{
  2345. $result = "logerr \"copy /v ${qquot_}$srcpath\\$srcfile${qquot_} $dstpath\"";
  2346. }
  2347. $result;
  2348. } # MakeXcopyCmd
  2349. # GenLocCmd
  2350. # For the given entry from REPOSITORY, generates the bingen commands.
  2351. # Input
  2352. # key identifying the REPOSITORY entry (reference
  2353. # array of commands where the output is added (reference)
  2354. # Output
  2355. # none
  2356. # Usage
  2357. # &GenLocCmd( $keyref );
  2358. sub GenLocCmd {
  2359. return if $SYNTAX_CHECK_ONLY;
  2360. my $keyref = shift;
  2361. my $op = &GetFieldVal( \%REPOSITORY, $keyref, "TokFile" );
  2362. &GenBgnCmd( $keyref ) and return if &IsBgnOp($op);
  2363. &GenRsrcCmd($keyref) and return if &IsRsrcOp($op);
  2364. } # GenLocCmd
  2365. sub GenBgnCmd {
  2366. my( $keyref ) = @_;
  2367. # pdb line, bingen line, dependency line
  2368. my( $pdbline, $bgnline, $symline, $dline ) = ("", "", "", "");
  2369. my $symcmd = "";
  2370. # Symbol paths and filenames
  2371. my ($srcext, $srcpdb, $srcdbg, $srcsym, $dstext, $dstpdb, $dstdbg, $dstsym) =
  2372. &NewImageToSymbol(&GetFieldVal( \%REPOSITORY, $keyref, "SrcFile"),
  2373. &GetFieldVal( \%REPOSITORY, $keyref, "DestFile"),
  2374. &GetFieldVal( \%REPOSITORY, $keyref, "SrcPath"),
  2375. &GetFieldVal( \%REPOSITORY, $keyref, "SrcDbg" ));
  2376. my( $symsrcfull, $symdstfull ) =
  2377. &SetSymPaths( &GetFieldVal( \%REPOSITORY, $keyref, "SrcDbg" ),
  2378. $srcext,
  2379. $srcpdb,
  2380. $srcdbg,
  2381. $srcsym,
  2382. &GetFieldVal( \%REPOSITORY, $keyref, "DestDbg"),
  2383. $dstext );
  2384. $pdbline = &MakeXcopyCmd( &GetFieldVal( \%REPOSITORY, $keyref, "SrcFile"), $symsrcfull, $srcpdb, $symdstfull, $dstpdb);
  2385. $symline = &MakeXcopyCmd( &GetFieldVal( \%REPOSITORY, $keyref, "SrcFile"), $symsrcfull, $srcsym, $symdstfull, $dstsym);
  2386. $dbgline = &MakeXcopyCmd( &GetFieldVal( \%REPOSITORY, $keyref, "SrcFile"), $symsrcfull, $srcdbg, $symdstfull, $dstdbg);
  2387. # -a | -r | -ai | -ir switch
  2388. # localization operation type ( append or replace )
  2389. my $bgntype = &GetLocOpType( &GetFieldVal( \%REPOSITORY, $keyref, "LocOp" ) );
  2390. # -m switch (specific to bingen; different for rsrc)
  2391. $symcmd = &SetBgnSymSw( $symsrcfull, $srcdbg, $symdstfull, $dstdbg );
  2392. # Code page, secondary language id, primary language id (specific for bingen)
  2393. my( $cpage, $lcid, $prilang, $seclang ) = @{&GetLangCodes( &GetMacro( "language" ) )};
  2394. # -p switch (specific for bingen)
  2395. $cpage = &GetBgnCodePageSw( $cpage );
  2396. # -i switch (specific for bingen)
  2397. my $icodes = &GetBgnICodesSw( $bgntype, &GetMacro( "ILANGUAGE" ) );
  2398. # multitoken (bingen)
  2399. my $multitok = ""; # &GetBgnMultitok( $keyref, $bgntype );
  2400. # the unlocalized version of the token must exist as well
  2401. # if ( substr($bgntype,-2) eq "-a" ) {
  2402. # if ( ! -e $multitok ) {
  2403. # &Error( 2015, sprintf( "\n%s\\%s",
  2404. # &GetFieldVal( \%REPOSITORY, $keyref, "TokPath" ),
  2405. # &GetFieldVal( \%REPOSITORY, $keyref, "TokFile" ) ) );
  2406. # &DeleteKey( \%REPOSITORY, $keyref );
  2407. # return;
  2408. # } # if
  2409. # } # if
  2410. # Sets the bingen command
  2411. $bgnline = sprintf "logerr \"bingen -n -w -v -f %s %s -o %s %s %s %s %s %s\\%s %s %s\\%s %s\\%s\"",
  2412. $symcmd,
  2413. $cpage,
  2414. $prilang,
  2415. $seclang,
  2416. &GetBgnSw( &GetFieldVal( \%REPOSITORY, $keyref, "BgnSw" ) ),
  2417. $icodes,
  2418. $bgntype,
  2419. &GetFieldVal( \%REPOSITORY, $keyref, "SrcPath" ),
  2420. &GetFieldVal( \%REPOSITORY, $keyref, "SrcFile" ),
  2421. $multitok,
  2422. &GetFieldVal( \%REPOSITORY, $keyref, "TokPath" ),
  2423. &GetFieldVal( \%REPOSITORY, $keyref, "TokFile" ),
  2424. &GetFieldVal( \%REPOSITORY, $keyref, "DestPath" ),
  2425. &GetFieldVal( \%REPOSITORY, $keyref, "DestFile" );
  2426. # Dependency line
  2427. $dline = sprintf "%s\\%s : %s\\%s %s\\%s %s%s\n",
  2428. &GetFieldVal( \%REPOSITORY, $keyref, "DestPath" ),
  2429. &GetFieldVal( \%REPOSITORY, $keyref, "DestFile" ),
  2430. &GetFieldVal( \%REPOSITORY, $keyref, "SrcPath" ),
  2431. &GetFieldVal( \%REPOSITORY, $keyref, "SrcFile" ),
  2432. &GetFieldVal( \%REPOSITORY, $keyref, "TokPath" ),
  2433. &GetFieldVal( \%REPOSITORY, $keyref, "TokFile" ),
  2434. &GetFieldVal( \%REPOSITORY, $keyref, "CustRc" );
  2435. $multitok;
  2436. &PushFieldVal( \%REPOSITORY, $keyref, "Cmd", "$dline" );
  2437. # Dependency line done
  2438. # Description block
  2439. $MAKEDIR{&GetFieldVal( \%REPOSITORY, $keyref, "DestPath" )} = 1;
  2440. if ( $multitok || $pdbline || $symline ) {
  2441. if ( $symdstfull ne &GetFieldVal( \%REPOSITORY, $keyref, "DestDbg" ) ) {
  2442. $MAKEDIR{$symdstfull}=1;
  2443. } # if
  2444. } # if
  2445. &PushFieldVal( \%REPOSITORY, $keyref, "Cmd", sprintf( "\t$bgnline\n" ) );
  2446. if ( $pdbline ) {
  2447. &PushFieldVal( \%REPOSITORY, $keyref, "Cmd", sprintf( "\t$pdbline\n" ) );
  2448. } # if
  2449. if ( $symline ) {
  2450. &PushFieldVal( \%REPOSITORY, $keyref, "Cmd", sprintf( "\t$symline\n" ) );
  2451. } # if
  2452. if ( $dbgline && $symcmd!~/\W/) {
  2453. &PushFieldVal( \%REPOSITORY, $keyref, "Cmd", sprintf( "\t$dbgline\n" ) );
  2454. } # if
  2455. # Optional resource-only DLL generation
  2456. # Description block done
  2457. return;
  2458. } # GenBgnCmd
  2459. sub GenRsrcCmd {
  2460. return if $SYNTAX_CHECK_ONLY;
  2461. my( $keyref ) = @_;
  2462. my $pdbline = ""; # copy pdb line
  2463. my $dbgline = ""; # copy dbg line
  2464. my $symline = ""; # copy sym line
  2465. my $binline = ""; # copy binary line
  2466. my $rsrcline= ""; # rsrc command line
  2467. my ($srcext, $srcpdb, $srcdbg, $srcsym, $dstext, $dstpdb, $dstdbg, $dstsym) =
  2468. &NewImageToSymbol(&GetFieldVal( \%REPOSITORY, $keyref, "SrcFile"),
  2469. &GetFieldVal( \%REPOSITORY, $keyref, "DestFile"),
  2470. &GetFieldVal( \%REPOSITORY, $keyref, "SrcPath"),
  2471. &GetFieldVal( \%REPOSITORY, $keyref, "SrcDbg" ));
  2472. my( $symsrcfull, $symdstfull ) =
  2473. &SetSymPaths( &GetFieldVal( \%REPOSITORY, $keyref, "SrcDbg" ),
  2474. $srcext,
  2475. $srcpdb,
  2476. $srcdbg,
  2477. $srcsym,
  2478. &GetFieldVal( \%REPOSITORY, $keyref, "DestDbg" ),
  2479. $dstext );
  2480. $pdbline = &MakeXcopyCmd( &GetFieldVal( \%REPOSITORY, $keyref, "SrcFile"), $symsrcfull, $srcpdb, $symdstfull, $dstpdb);
  2481. $dbgline = &MakeXcopyCmd( &GetFieldVal( \%REPOSITORY, $keyref, "SrcFile"), $symsrcfull, $srcdbg, $symdstfull, $srcdbg);
  2482. $symline = &MakeXcopyCmd( &GetFieldVal( \%REPOSITORY, $keyref, "SrcFile"), $symsrcfull, $srcsym, $symdstfull, $srcsym);
  2483. # in fact, it is necessary to fix the makexcopycmd
  2484. $binline = &MakeXcopyCmd( &GetFieldVal( \%REPOSITORY, $keyref, "SrcFile"),
  2485. &GetFieldVal( \%REPOSITORY, $keyref, "SrcPath" ),
  2486. &GetFieldVal( \%REPOSITORY, $keyref, "SrcFile" ),
  2487. &GetFieldVal( \%REPOSITORY, $keyref, "DestPath" ),
  2488. &GetFieldVal( \%REPOSITORY, $keyref, "DestFile" ) );
  2489. # -a or -r switch
  2490. # localization operation type ( append or replace )
  2491. my $rsrctype = &GetLocOpType( &GetFieldVal( \%REPOSITORY, $keyref, "LocOp" ) );
  2492. # -l switch
  2493. my $langsw = &GetLangNlsCode( &GetMacro( "language" ) );
  2494. $langsw =~ s/0x0//;
  2495. $langsw =~ s/0x//;
  2496. $langsw = sprintf "-l %s", $langsw;
  2497. # -s switch
  2498. my $symsw = &SetRsrcSymSw( $symsrcfull, $srcdbg, $symdstfull, $dstdbg );
  2499. # rsrc command line
  2500. $rsrcline = sprintf "logerr \"rsrc %s\\%s %s %s\\%s %s %s \"",
  2501. &GetFieldVal( \%REPOSITORY, $keyref, "DestPath" ),
  2502. &GetFieldVal( \%REPOSITORY, $keyref, "DestFile" ),
  2503. $rsrctype,
  2504. &GetFieldVal( \%REPOSITORY, $keyref, "TokPath" ),
  2505. &GetFieldVal( \%REPOSITORY, $keyref, "TokFile" ),
  2506. $langsw,
  2507. $symsw;
  2508. # Dependency line
  2509. $dline = sprintf "%s\\%s : %s\\%s %s\\%s\n",
  2510. &GetFieldVal( \%REPOSITORY, $keyref, "DestPath" ),
  2511. &GetFieldVal( \%REPOSITORY, $keyref, "DestFile" ),
  2512. &GetFieldVal( \%REPOSITORY, $keyref, "SrcPath" ),
  2513. &GetFieldVal( \%REPOSITORY, $keyref, "SrcFile" ),
  2514. &GetFieldVal( \%REPOSITORY, $keyref, "TokPath" ),
  2515. &GetFieldVal( \%REPOSITORY, $keyref, "TokFile" );
  2516. &PushFieldVal( \%REPOSITORY, $keyref, "Cmd", "$dline" );
  2517. # Dependency line done
  2518. # Description block
  2519. $MAKEDIR{&GetFieldVal( \%REPOSITORY, $keyref, "DestPath" )} = 1;
  2520. if ( $dbgline || $pdbline || $symline) {
  2521. if ( $symdstfull ne &GetFieldVal( \%REPOSITORY, $keyref, "DestDbg" ) ) {
  2522. $MAKEDIR{$symdstfull}=1;
  2523. } # if
  2524. } # if
  2525. if ( $pdbline ) {
  2526. &PushFieldVal( \%REPOSITORY, $keyref, "Cmd", sprintf( "\t$pdbline\n" ) );
  2527. } # if
  2528. if ( $dbgline ) {
  2529. &PushFieldVal( \%REPOSITORY, $keyref, "Cmd", sprintf( "\t$dbgline\n" ) );
  2530. } # if
  2531. if ( $symline ) {
  2532. &PushFieldVal( \%REPOSITORY, $keyref, "Cmd", sprintf( "\t$symline\n" ) );
  2533. } # if
  2534. &PushFieldVal( \%REPOSITORY, $keyref, "Cmd", sprintf( "\t$binline\n" ) );
  2535. &PushFieldVal( \%REPOSITORY, $keyref, "Cmd", sprintf( "\t$rsrcline\n" ) );
  2536. return;
  2537. } # GenRsrcCmd
  2538. sub GenMUICmd {
  2539. return if $SYNTAX_CHECK_ONLY;
  2540. # Optional resource-only DLL generation
  2541. my( $keyref ) = @_;
  2542. my $lcid = &GetLangNlsCode( &GetMacro( "language" ) );
  2543. my( $muiline, $lnkline ) = ( "", "" );
  2544. my $_target = &GetMacro( "_target" ),
  2545. # Sets the muibld command
  2546. $muiline = sprintf "logerr \"muibld.exe -l %s -i 4 5 6 9 10 11 16 HTML 23 1024 2110 %s\\%s %s\\mui\\%s\\res\\%s.res\"",
  2547. $lcid,
  2548. &GetFieldVal( \%REPOSITORY, $keyref, "DestPath" ),
  2549. &GetFieldVal( \%REPOSITORY, $keyref, "DestFile" ),
  2550. &GetMacro( "_NTBINDIR" ),
  2551. &GetMacro( "Language" ),
  2552. &GetFieldVal( \%REPOSITORY, $keyref, "DestFile" );
  2553. # Sets the link command
  2554. $lnkline = sprintf "logerr \"link /noentry /dll /nologo /nodefaultlib /out:%s\\mui\\%s\\$_target\\%s.mui %s\\mui\\%s\\res\\%s.res\"",
  2555. &GetMacro( "_NTBINDIR" ),
  2556. &GetMacro( "Language" ),
  2557. &GetFieldVal( \%REPOSITORY, $keyref, "DestFile" ),
  2558. &GetMacro( "_NTBINDIR" ),
  2559. &GetMacro( "Language" ),
  2560. &GetFieldVal( \%REPOSITORY, $keyref, "DestFile" );
  2561. $MAKEDIR{sprintf("%s\\mui\\%s\\res",
  2562. &GetMacro("_NTBINDIR"),
  2563. &GetMacro("Language"))} = 1;
  2564. $MAKEDIR{sprintf("%s\\mui\\%s\\$_target",
  2565. &GetMacro("_NTBINDIR"),
  2566. &GetMacro("Language"))} = 1;
  2567. &PushFieldVal( \%REPOSITORY, $keyref, "Cmd", sprintf( "\t$muiline\n" ) );
  2568. &PushFieldVal( \%REPOSITORY, $keyref, "Cmd", sprintf( "\t$lnkline\n" ) );
  2569. return;
  2570. } # GenMUICmd
  2571. # GetBgnCodePageSw
  2572. # Sets the code path bingen switch (-p)
  2573. # Input: code page value
  2574. # Output: bingen -p switch
  2575. sub GetBgnCodePageSw {
  2576. return "-p $_[0]" unless $_[0]=~/^\-$/;
  2577. } # GetBgnCodePageSw
  2578. # GetBgnICodesSw
  2579. # Sets the -i bingen switch, if needed
  2580. # ( primary language id and secondary language id for the input language )
  2581. # Input: bingen opetation type (-r or -a)
  2582. # the input language
  2583. # Output: -i <pri lang code> <sec lang code> in any of the following cases:
  2584. # * append token operation (bingen -a)
  2585. # * the input language is different from USA
  2586. # (another way of saying that ILANGUAGE is defined and is
  2587. # different from USA)
  2588. # Otherwise, return ""
  2589. sub GetBgnICodesSw {
  2590. my( $bgntype, $ilang ) = @_;
  2591. # Input language codes
  2592. my( $cpage, $lcid, $prilang, $seclang );
  2593. # Append operation => set -i
  2594. # Replace operation and the input language is not USA => -i
  2595. if ( $bgntype eq "-a" || ( $ilang && lc($ilang) ne "usa" ) ) {
  2596. if ( !$ilang ) {
  2597. $ilang = "USA";
  2598. } # if
  2599. ( $cpage, $lcid, $prilang, $seclang ) = @{&GetLangCodes( $ilang )};
  2600. return "-i $prilang $seclang";
  2601. } # if
  2602. return "";
  2603. } # GetBgnICodesSw
  2604. # SetBgnSymSw
  2605. # Generates the -m bingen switch
  2606. # Input: dbg source path, dbg file, dbg destination path, dbg file
  2607. # Output: string containing the -m bingen switch
  2608. sub SetBgnSymSw {
  2609. return " -m $_[0] $_[2]" if ($_[0] !~ /^\-$/ && $_[2] !~ /^\-$/ && -e "$_[0]\\$_[1]");
  2610. } # SetBgnSymSw
  2611. # SetRsrcSymSw
  2612. # Input
  2613. # dbg source path, dbg file, dbg destination path, dbg file
  2614. # Output
  2615. # the -s rsrc switch
  2616. sub SetRsrcSymSw {
  2617. return " -s $_[2]\\$_[3]" if ($_[0] !~/^\-$/ && $_[1] !~/^\-$/ && -e "$_[0]\\$_[1]");
  2618. } # SetRsrcSymSw
  2619. # GetLocOpType
  2620. # Sets the localization operation type ( replace or append )
  2621. # Input
  2622. # loc op type as found in the mapping file
  2623. # Output
  2624. # loc op type ( -a or -r )
  2625. sub GetLocOpType {
  2626. my $loctype = shift;
  2627. $loctype |= &GetMacro( "LOC_OP_TYPE" );
  2628. if ($loctype){
  2629. ($locmatch,$locargs)=($loctype=~/^-([A-z]+)([^A-r]*)/);
  2630. $locargs=~s/,/ /g;
  2631. if (exists $LOCOPS{$locmatch}) {
  2632. ($retstr=$LOCOPS{$locmatch})=~s/\$opts/$locargs/e;
  2633. return $retstr;
  2634. }
  2635. }
  2636. "-r";
  2637. } # GetLocOpType
  2638. # GetBgnSw
  2639. # Returns the bingen switch
  2640. # Input: bingen op type as found in the mapping file
  2641. # Output: bingen switch
  2642. sub GetBgnSw {
  2643. $_[0] =~tr/A-Z/a-z/;
  2644. #here, the BGNSW @contains dash<blah blah blah>.
  2645. map {return $_[0] if $_[0] eq $_} @BGNSWS;
  2646. "";
  2647. } # GetBgnSw
  2648. # GetBgnMultitok
  2649. # Sets the multitoken input parameter (bingen)
  2650. # Input: operation type and path to the input token files
  2651. sub GetBgnMultitok {
  2652. my( $keyref, $bgntype ) = @_;
  2653. # Language itokens
  2654. my $langpath;
  2655. # Tok path, tok file
  2656. my( $itokpath, $itokfile );
  2657. $itokpath = &GetFieldVal( \%REPOSITORY, $keyref, "ITokPath" );
  2658. $itokfile = &GetFieldVal( \%REPOSITORY, $keyref, "TokFile" );
  2659. if ( substr($bgntype,-2) ne "-a" ) { return ""; }
  2660. $langpath = sprintf "%s\\%s", $itokpath, &GetMacro( "LANGUAGE" );
  2661. if ( -e "$langpath\\$itokfile" ) {
  2662. return "$langpath\\$itokfile";
  2663. }
  2664. return "$itokpath\\$itokfile";
  2665. } # GetBgnMultitok
  2666. # GetBgnMultitok
  2667. # Returns the filenames for symbol files and the extension for directory
  2668. #
  2669. # Input: ($srcfile,$destfile,$srcpath)
  2670. # source file name,
  2671. # destination file name,
  2672. # source file path,
  2673. # source file symbol path.
  2674. #
  2675. # Output: ($srcext, $srcpdb, $srcdbg, $srcsym, $dstext, $dstpdb, $dstdbg, $dstsym)
  2676. # source file extension,
  2677. # source pdb file name,
  2678. # source dbg file name,
  2679. # source sym file name
  2680. # destination file extension,
  2681. # destination pdb file name,
  2682. # destination dbg file name,
  2683. # destination sym file name.
  2684. #
  2685. # Example: ($srcext, $srcpdb, $srcdbg, $srcsym, $dstext, $dstpdb, $dstdbg, $dstsym) =
  2686. # &NewImageToSymbol($SrcFile, $DestFile, $SrcPath, $srcDbg);
  2687. sub NewImageToSymbol {
  2688. my ($srcfile,$destfile,$srcpath, $srcdbg) = @_;
  2689. my @known=qw(exe dll sys ocx drv);
  2690. my $checkext = qq(pdb);
  2691. my $valid = 0;
  2692. my @ext = qw (pdb dbg sym);
  2693. map {$valid = 1 if ($srcfile =~/\.$_\b/i)} @known;
  2694. my @sym = ();
  2695. foreach $name (($srcfile, $destfile)){
  2696. $ext=$1 if ($name=~/\.(\w+)$/);
  2697. push @sym, $ext;
  2698. foreach $newext (@ext){
  2699. my $sym = $name;
  2700. $sym =~ s/$ext$/$newext/;
  2701. if ($valid && $sym =~ /$checkext$/) {
  2702. # >link /dump /headers <binary> |(
  2703. # more? perl -ne "{print $1 if /\s(\S+\.pdb) *$/im}" )
  2704. # >blah-blah-blah.pdb
  2705. my $testname = join "\\",($srcdbg, $ext, $sym);
  2706. if (! -e $testname){
  2707. # we must get the correct directory to check -e!
  2708. #
  2709. if ($FULLCHECK and $srcdbg ne "-"){
  2710. print STDERR "LINK /DUMP ... $srcpath\\$srcfile => replace $sym " if $DEBUG;
  2711. $result = qx ("LINK /DUMP /HEADERS $srcpath\\$srcfile");
  2712. # $sym = $1 if ($result =~/\s\b(\S+\.$checkext) *$/im);
  2713. # $sym =~s/[^\\]+\\//g;
  2714. $sym = $3 if $result =~/\s\b(([^\\]+\\)+)?(\S+.$checkext) *$/im;
  2715. print STDERR "with $sym\n" if $DEBUG;
  2716. # _namematch($srcpdb,$pdb); use it still?
  2717. }
  2718. }
  2719. }
  2720. push @sym, $sym;
  2721. }
  2722. }
  2723. print STDERR join("\n", @sym), "\n----\n" if $DEBUG;
  2724. @sym;
  2725. } # NewImageToSymbol
  2726. # GetLangCodes
  2727. # Read the language codes from codes.txt
  2728. # Input: language
  2729. # Output: the language codes ( codepage, primary language id, secondary language id )
  2730. # Ex. ($CodePage, $lcid, $PriLangId, $SecLangId) = &GetLangCodes($language);
  2731. sub GetLangCodes {
  2732. return (exists $CODES{uc$_[0]})?$CODES{uc$_[0]}: &FatalError( 1910, $language );
  2733. } # GetLangCodes
  2734. # GetLangNlsCode
  2735. #
  2736. sub GetLangNlsCode {
  2737. my @langcodes = @{&GetLangCodes(shift)};
  2738. return $langcodes[1];
  2739. } # GetLangNlsCode
  2740. sub _GetLangNlsCode {
  2741. # my($language) = @_;
  2742. #
  2743. my @langcodes = @{&GetLangCodes(shift)};
  2744. return $langcodes[1];
  2745. } # GetLangNlsCode
  2746. # GenMakeDir
  2747. # Write the whole tree to create the target structure.
  2748. # Input & Output
  2749. # none
  2750. # Usage
  2751. # &GenMakeDir();
  2752. sub GenMakeDir {
  2753. # Remove the parent folder
  2754. my $curdir;
  2755. my @directories;
  2756. for $curdir (keys %MAKEDIR) {
  2757. if (exists $MAKEDIR{$curdir}) {
  2758. while ($curdir=~/\\/g) {
  2759. if (($` ne $curdir) && (exists $MAKEDIR{$`})) {
  2760. delete $MAKEDIR{$`};
  2761. }
  2762. }
  2763. }
  2764. }
  2765. # Create the record into REPOSITORY
  2766. $key{DestPath} = "\\\\\\makedir";
  2767. $key{DestFile} = "makedir";
  2768. &SetField( \%REPOSITORY, \%key, "DestPath", "\\\\\\makedir" );
  2769. &SetField( \%REPOSITORY, \%key, "DestFile", "makedir" );
  2770. &PushFieldVal( \%REPOSITORY, \%key, "Cmd", "\\\\\\Makedir\\Makedir : \n");
  2771. map({&PushFieldVal( \%REPOSITORY, \%key, "Cmd", "\t\@-md $_ 2\>\>nul\n")} sort keys %MAKEDIR);
  2772. return;
  2773. } # GenMakeDir
  2774. # WriteToSyscmd
  2775. # Creates the SYSCMD nmake command file.
  2776. # Input
  2777. # syscmd file name
  2778. # Output
  2779. # none
  2780. sub WriteToSyscmd {
  2781. my( $syscmd ) = @_;
  2782. # Target name, as specified in the command line
  2783. my $tname;
  2784. # Indexes
  2785. my $i;
  2786. # Write to syscmd in the following cases:
  2787. # - sysgen with targets (clean or incremental)
  2788. # - sysgen incremental without targets, but with changes detected in the description blocks
  2789. if ( &IsEmptyHash( \%TARGETS ) && ( $CLEAN || ( @SYSCMD == 0 ) ) ) {
  2790. return;
  2791. } # if
  2792. print "Generating $syscmd...\n";
  2793. ( open( SYSCMD, ">"."$syscmd" ) ) || &FatalError( 1007, $syscmd );
  2794. print SYSCMD "/A \n";
  2795. # Always run \\\Makedir\Makedir
  2796. print SYSCMD "\\\\\\Makedir\\Makedir ";
  2797. # Write targets to syscmd
  2798. for $tname ( sort keys %TARGETS ) {
  2799. for ( $i=0; $i < @{$TARGETS{$tname}->{NewDestPath}}; $i++ ) {
  2800. print SYSCMD " \\\n $TARGETS{$tname}->{NewDestPath}->[$i]\\$tname";
  2801. } # for
  2802. } # for
  2803. # For incremental without TARGETS, print targets stored in @SYSCMD
  2804. # ( tbd - add an assert here: SYSCMD can be non-empty only for incremental without targets)
  2805. for ( $i=0; $i < @SYSCMD; $i++ ) {
  2806. print SYSCMD " \\\n $SYSCMD[$i]";
  2807. } # for
  2808. close( SYSCMD );
  2809. return;
  2810. } # WriteToSyscmd
  2811. # LoadReposit
  2812. # Populate CMD_REPOSITORY according to an existing SYSGEN generated makefile.
  2813. # For each found key, fill in the {Cmd} field.
  2814. # Input
  2815. # makefile name
  2816. # Output
  2817. # none
  2818. # Usage
  2819. # &LoadReposit();
  2820. sub LoadReposit {
  2821. my( $makefname ) = @_;
  2822. # Contents of an existing makefile
  2823. my @makefile;
  2824. # Line number where the "all" target description line finishes
  2825. my $line;
  2826. # Nothing to do in case of a clean SYSGEN
  2827. ( !$CLEAN ) || return;
  2828. # Nothing to do if the makefile does not exist
  2829. ( -e $makefname ) || &FatalError( 1003, $makefname );
  2830. # Open the makefile
  2831. ( open( MAKEFILE, $makefname ) ) || &FatalError( 1006, $makefname );
  2832. print "Loading $makefname...\n";
  2833. # Load makefile's contents
  2834. @makefile = <MAKEFILE>;
  2835. close( MAKEFILE );
  2836. # Fill in keys according to "all" target found in the makefile
  2837. $line = &LoadKeys( $makefname, \@makefile );
  2838. # Load makefile's description blocks into CMD_REPOSITORY's {Cmd} field.
  2839. &LoadCmd( $makefname, $line, \@makefile );
  2840. return;
  2841. } # LoadReposit
  2842. # LoadKeys
  2843. # Loads keys according to the "all" target from the given
  2844. # SYSGEN-generated makefile.
  2845. # Input
  2846. # makefile's name
  2847. # makefile's contents (reference)
  2848. # Output
  2849. # line number following "all" target or
  2850. # -1 if "all" target was not found
  2851. # Usage
  2852. # &LoadKeys( \@makefile );
  2853. sub LoadKeys {
  2854. my( $makefname, $makefref ) = @_;
  2855. # Repository key
  2856. my %key;
  2857. # Indexes
  2858. my $i;
  2859. my %alltarget=();
  2860. my $cursection=0;
  2861. my $makeflines = $#$makefref;
  2862. my ($targetname, $errortarget);
  2863. # Skip white lines in the beginnig of makefile
  2864. for ( $i=0; $i < $makeflines; $i++ ) {
  2865. if ( $makefref->[$i] =~ /\S/ ) { last; }
  2866. } # for
  2867. # First non empty line from MAKEFILE must contain "sysgen" target
  2868. ( ( $i < @{$makefref} && $makefref->[$i] =~ /sysgen\s*:/i ) ) || &FatalError( 1213, $makefname);
  2869. # ignore nmake line
  2870. $i++;
  2871. $alltarget{'all'} = 1;
  2872. $makeflines = $#$makefref;
  2873. while (scalar(%alltarget) ne 0) {
  2874. # Error if target was not solved.
  2875. ( ++$i < $makeflines ) || &FatalError( 1210, "${makefname}(" . join(",", keys %alltarget) . ")" );
  2876. # Find the target, such as all
  2877. for ( ; $i < $makefref ; $i++) {
  2878. $errortarget=$targetname = '';
  2879. # Suppose only find one item matched
  2880. ($targetname, $errortarget) = map({($makefref->[$i]=~/^\Q$_\E\ :/)?$_:()} keys %alltarget) if($makefref->[$i] =~ / :/);
  2881. # Go to next line if not found
  2882. next if ($targetname eq '');
  2883. # Two target found in same line
  2884. ($errortarget eq '') || &FatalError( 1215, "${makefname}($targetname, $errortarget, ...)");
  2885. # Target was found, move to next line and exit for loop
  2886. $i++;
  2887. last;
  2888. } # for
  2889. # Lookfor its belongs
  2890. for ( ; $i < $makeflines ; $i++ ) {
  2891. last if ($makefref->[$i] !~ /\S/);
  2892. # lookfor item(s) in one line
  2893. for (split(/\s+/, $makefref->[$i])) {
  2894. next if ($_ eq '');
  2895. last if ($_ eq '\\');
  2896. # $_=$makefref->[$i];
  2897. # If it is a section name, push it into alltarget hash
  2898. if ( /\Q$SECTIONNAME\E\d+$/) {
  2899. $alltarget{$_} = 1;
  2900. # Match the last one of $SECTIONAME, with (\d+)\1 => such as 88 => 8, 1616 => 16, 6464 => 64
  2901. $SECTIONS = $1 if (($SECTIONS !~/^\d+$/) && (/\Q$SECTIONNAME\E(\d+)\1/));
  2902. # Create it into REPOSITORY
  2903. } elsif (/(\S*)\\(\S*)/) {
  2904. ($key{DestPath}, $key{DestFile})=($1, $2);
  2905. &SetField( \%CMD_REPOSITORY, \%key, "DestPath", $1 );
  2906. &SetField( \%CMD_REPOSITORY, \%key, "DestFile", $2 );
  2907. # If DestFile is part of TARGETS, store DestPath in TARGETS.
  2908. if ( &IsHashKey( \%TARGETS, $key{DestFile} ) ) {
  2909. &AddTargetPath( $key{DestFile}, "OldDestPath", $key{DestPath} );
  2910. } # if
  2911. } # if
  2912. } # for
  2913. } # for
  2914. delete $alltarget{$targetname};
  2915. } # while
  2916. return $i;
  2917. } # LoadKeys
  2918. # LoadCmd
  2919. # Load the body of the makefile.
  2920. # Fill in the {Cmd} field for each CMD_REPOSITORY key
  2921. # Input
  2922. # makefile name
  2923. # makefile line following the all target dependency lines
  2924. # make file contents (reference)
  2925. # Output
  2926. # none
  2927. # Usage
  2928. # &LoadCmd( 2543, \@makefile );
  2929. sub LoadCmd {
  2930. my( $makefname, $line, $makefref ) = @_;
  2931. # Counters
  2932. my($i, $j);
  2933. # Repository key
  2934. my %key;
  2935. # Description line (one or more file lines,
  2936. # depending on the existence of custom resources)
  2937. my $dline;
  2938. # Buffer for one line
  2939. my $buffer;
  2940. ( $line > @makefile ) || &FatalError( 1212, $makefname);
  2941. for ( $i = $line; $i < @{$makefref}; $i++ ) {
  2942. # Skip white lines
  2943. if ( $makefref->[$i] !~ /\S/ ) { next; }
  2944. # Identify dependency line and key
  2945. $makefref->[$i] =~ /(\S*)\\(\S*)\s*: /;
  2946. $key{DestPath} = $1;
  2947. $key{DestFile} = $2;
  2948. # The key must exist in CMD_REPOSITORY
  2949. &IsRepositKey( \%CMD_REPOSITORY, \%key ) ||
  2950. &FatalError( 1211, "$key{DestPath}\\$key{DestFile}" );
  2951. # Load the description block into the {Cmd} field
  2952. $dline = "";
  2953. # Read first the dependency line.
  2954. # It might be spread over several lines in the makefile,
  2955. # but we will make a single line from it.
  2956. for ( $j=$i; $j < @{$makefref}; $j++ ) {
  2957. $dline .= $makefref->[$j];
  2958. # Description line ends if the last character is not a continuation line mark
  2959. $buffer = $makefref->[$j];
  2960. $buffer =~ s/\s*//g;
  2961. if ( substr ( $buffer, -1, 1 ) ne "\\" ) { last; }
  2962. } # for
  2963. &PushFieldVal( \%CMD_REPOSITORY, \%key, "Cmd", $dline );
  2964. $i=$j+1;
  2965. # Read then the command block.
  2966. for ( $j=$i; $j < @{$makefref}; $j++ ) {
  2967. # Description block ends at the first white line encountered
  2968. if ( $makefref->[$j] !~ /\S/ ) { last; }
  2969. # Load the current command line
  2970. &PushFieldVal( \%CMD_REPOSITORY, \%key, "Cmd", $makefref->[$j] );
  2971. } # for
  2972. $i = $j;
  2973. } # for
  2974. return;
  2975. } # LoadCmd
  2976. # LoadEnv
  2977. # Loads the environment variables into MACROS (hash).
  2978. # Uppercases all the macroname.
  2979. # Input & Output: none
  2980. # Usage
  2981. # &LoadEnv();
  2982. sub LoadEnv {
  2983. for ( keys %ENV ) {
  2984. &SetMacro( $_, $ENV{$_}, 0 );
  2985. } #for
  2986. return;
  2987. } # LoadEnv
  2988. # GetMacro
  2989. # Returns the value of a macro.
  2990. # Input
  2991. # macroname
  2992. # Output
  2993. # macrovalue ( empty string if not defined )
  2994. # Usage
  2995. # $language = &GetMacro("Language");
  2996. sub GetMacro {
  2997. return $MACROS{uc$_[0]}->{Value};
  2998. } # GetMacro
  2999. # SetMacro
  3000. # Sets the value of a macro.
  3001. # Input
  3002. # macroname
  3003. # macrovalue
  3004. # macrotype (see %MACROS in the beginning of the file
  3005. # for more details on the types of macros.
  3006. # Output
  3007. # none
  3008. # Usage
  3009. # &SetMacro( "_BuildArch", "nec_98", 0);
  3010. sub SetMacro {
  3011. my $varname=uc shift;
  3012. # Do not overwrite a macro defined in the command line unless
  3013. # the same macro is redefined in the command line
  3014. if ( (!exists $MACROS{$varname}) || ($MACROS{$varname}->{Type} == 0) || ($_[1] == 1)) {
  3015. ($MACROS{$varname}->{Value}, $MACROS{$varname}->{Type})=@_;
  3016. }
  3017. return;
  3018. } # SetMacro
  3019. # FatalError
  3020. # Prints the error and exits.
  3021. # Input
  3022. # error code
  3023. # name of the sysfile where the error occured or any other text
  3024. # line number on the description file where the error occured or 0 if not the case
  3025. # Ouput
  3026. # none
  3027. # Usage
  3028. # &FatalError( 1111, "sysfile", 12 );
  3029. # &FatalError( 1002, $CODESFNAME, 0 );
  3030. sub FatalError {
  3031. &PrintError( "fatal error", @_);
  3032. print "Stop.\n";
  3033. exit;
  3034. } # FatalError
  3035. # Error
  3036. # Prints the error and returns.
  3037. # Input
  3038. # error code
  3039. # name of the sysfile where the error occured or any other text
  3040. # line number on the description file where the error occured or 0 if not the case
  3041. # Output
  3042. # none
  3043. # Usage
  3044. # &Error( 2011, $recref->{TokPath}\\$recref->{TokFile});
  3045. sub Error {
  3046. # Errors from IGNORE macro are not counted
  3047. if ( &PrintError( "error", @_ ) ) {
  3048. $ERRORS++;
  3049. } # if
  3050. return;
  3051. } # Error
  3052. # PrintError
  3053. # Prints the encountered error with the format
  3054. # <description filename>(<line>): <fatal error | error> <error_code>: <error_text>
  3055. # Input
  3056. # error type ( fatal error or error )
  3057. # error code
  3058. # filename where the error was encountered or other text
  3059. # line number or 0
  3060. # Output
  3061. # 1 if the error is counted
  3062. # 0 otherwise
  3063. # Usage
  3064. # &PrintError( 1002, $CODESFNAME, 0);
  3065. sub PrintError {
  3066. my( $errtype, $errno, $file, $line ) = @_;
  3067. # Error text
  3068. my $errtxt;
  3069. # Ignore errors
  3070. my $ignore;
  3071. my @ivalues;
  3072. # Counter
  3073. my $i;
  3074. my $fileline;
  3075. # Do not print anything if errno is listed in IGNORE macro
  3076. $ignore = &GetMacro( "IGNORE" );
  3077. $ignore =~ s/\s*//g;
  3078. @ivalues = split ";", $ignore;
  3079. for ( $i=0; $i < @ivalues; $i++ ) {
  3080. if ( $errno == $ivalues[$i] ) {
  3081. return 0;
  3082. } # if
  3083. } # for
  3084. $errtxt = "SYSGEN:";
  3085. $fileline="";
  3086. if ( $file ) {
  3087. if ( $line ) { $fileline=" $file($line)"; }
  3088. else { $fileline=" $file"; }
  3089. } # if
  3090. if ( $MAP_ERR{$errno} ) { $fileline .= ": ".$MAP_ERR{$errno}; }
  3091. $errtxt .= " $errtype $errno:$fileline";
  3092. ( open LOGFILE, ">>$LOGFILE" ) || &FatalError( 1007, $LOGFILE );
  3093. printf LOGFILE "$errtxt\n";
  3094. close LOGFILE;
  3095. ( open ERRFILE, ">>$ERRFILE" ) || &FatalError( 1007, $ERRFILE );
  3096. printf ERRFILE "$errtxt\n";
  3097. close ERRFILE ;
  3098. select(STDERR); $| = 1;
  3099. printf "$errtxt\n";
  3100. select(STDOUT); $| = 1;
  3101. return 1;
  3102. } # PrintError
  3103. # SumErrors
  3104. # Displays the number of non-fatal errors found while running SYSGEN.
  3105. # Runs at the end of sysgen.
  3106. # Input & Output: none
  3107. # Usage
  3108. # &SumErrors();
  3109. sub SumErrors {
  3110. if ( ! $ERRORS ) {
  3111. print "\nSYSGEN: No errors found during execution.\n";
  3112. } # if
  3113. else {
  3114. print "\nSYSGEN: Total Errors: $ERRORS\n";
  3115. } # else
  3116. return;
  3117. } # SumErrors
  3118. # CleanLogFiles
  3119. # For a clean SYSGEN, delete sysgen.log and sysgen.err files.
  3120. # For an incremental SYSGEN, delete only sysgen.err.
  3121. # Input
  3122. # sysfile's directory
  3123. # Output
  3124. # none
  3125. # Usage
  3126. # &CleanLogFiles();
  3127. sub CleanLogFiles {
  3128. my( $sysdir ) = @_;
  3129. # Set LOGFILE and ERRFILE
  3130. $LOGFILE = "${sysdir}\\sysgen.log";
  3131. $ERRFILE = "${sysdir}\\sysgen.err";
  3132. # Delete files
  3133. if ( $CLEAN && -e $LOGFILE ) { unlink $LOGFILE; }
  3134. if ( -e $ERRFILE ) { unlink $ERRFILE; }
  3135. # Delete existing makefile and syscmd
  3136. if ( $CLEAN && !$SYNTAX_CHECK_ONLY && -e "$sysdir\\makefile" ) { unlink "$sysdir\\makefile"; }
  3137. if ( -e "$sysdir\\syscmd" ) { unlink "$sysdir\\syscmd"; }
  3138. return;
  3139. } # CleanLogFiles
  3140. # ////////////////////////////////////////////////////////////////////////////////////////
  3141. # PrintHelp
  3142. # Print usage
  3143. sub PrintHelp {
  3144. print STDERR <<EOT;
  3145. Usage
  3146. sysgen [<options>] [<macros>] [<targets>]
  3147. where
  3148. <options> are used for controlling the sysgen session.
  3149. Options are not case sensitive and can be preceded by
  3150. either a slash (/) or a dash (-).
  3151. Sysgen recognizes the following options:
  3152. /c generate the makefile from scratch, overwriting existing one.
  3153. By running nmake, all the targets will be generated.
  3154. /s limit sysgen to syntax check - makefile not (re)generated.
  3155. /f <filename> takes <filename> as the sysfile.
  3156. If this option is omitted, sysgen searches the current
  3157. directory for a file called sysfile and uses it as a
  3158. description (mapping) file.
  3159. <macros> list the command line macro definitions in the format
  3160. "<macroname>=<macrovalue>". Use them if you need to
  3161. overwrite macros defined in the sysfiles or in the razzle.
  3162. <targets> list files (name only, without path) to localize/aggregate.
  3163. By running nmake, only the specified targets will be
  3164. generated.
  3165. EOT
  3166. } #PrintHelp
  3167. # FillFilter
  3168. # Fills in the FILTER variable
  3169. # Input & Output
  3170. # none
  3171. sub FillFilter {
  3172. # List of filtered files
  3173. my @farray;
  3174. # Index
  3175. my $i;
  3176. $file = &GetMacro( "FILTER" );
  3177. ( $file ) || return;
  3178. ( -e $file ) || &FatalError( 1005, $file );
  3179. # Open the mapping file
  3180. ( open( FILE, $file ) ) || &FatalError( 1006, $file );
  3181. # Load file contents
  3182. @farray = <FILE>;
  3183. close( FILE );
  3184. print "Loading filter $file...\n";
  3185. for ( $i = 0; $i < @farray; $i++ ) {
  3186. chop $farray[$i];
  3187. $farray[$i] =~ s/^\s*//g;
  3188. $farray[$i] =~ s/\s*=\s*/=/g;
  3189. next if (($farray[$i]=~/^\;/)||($farray[$i]=~/^\s*$/));
  3190. $FILTER{lc( $farray[$i] )} = 0;
  3191. } # for
  3192. # In case targets were specified in the command line,
  3193. # verify FILTER contains them.
  3194. if ( ! &IsEmptyHash( \%TARGETS ) ) {
  3195. for ( keys %TARGETS ) {
  3196. if ( ! exists $FILTER{lc( $_ )} ) {
  3197. &FatalError( 1009, $_ );
  3198. } # if
  3199. } # for
  3200. } # if
  3201. return;
  3202. } # FillFilter
  3203. # GetSysdir
  3204. # Returns the directory name from a sysfile path.
  3205. # Sysfile's directory is the place where SYSGEN generates the following files:
  3206. # makefile (used by nmake to execute the aggregation)
  3207. # syscmd (is the nmake command-line file used for incremental builds)
  3208. # sysgen.log (the output of SYSGEN and NMAKE)
  3209. # sysgen.err (the errors found while running SYSGEN and NMAKE)
  3210. # Input
  3211. # full path to a sysfile
  3212. # Output
  3213. # directory name of the given sysfile
  3214. sub GetSysdir {
  3215. my( $sysfile ) = @_;
  3216. # Output
  3217. my $sysdir;
  3218. # Indexes
  3219. my $i;
  3220. # Buffer
  3221. my @array;
  3222. $sysdir = ".";
  3223. @array = split /\\/, $sysfile;
  3224. if ( @array > 1 ) {
  3225. $sysdir = "";
  3226. for ( $i = 0; $i < (@array-1)-1; $i++ ) { $sysdir .= "$array[$i]\\"; }
  3227. $sysdir .= $array[$i];
  3228. } # if
  3229. return $sysdir;
  3230. } # GetSysdir
  3231. # ParseCmdLine
  3232. # Parses the command line.
  3233. # SYSGEN's command-line syntax is:
  3234. # SYSGEN [<options>] [<macros>] [<targets>]
  3235. # Input
  3236. # command-line array
  3237. # Output
  3238. # none
  3239. # Usage
  3240. # &ParseCmdline(@ARGV);
  3241. sub ParseCmdLine {
  3242. my @cmdline = @_;
  3243. # Indexes
  3244. my( $i );
  3245. my( $optname );
  3246. my( @text );
  3247. # read makefile.mak if exists
  3248. if (-e "makefile.mak") {
  3249. open(F, "makefile.mak");
  3250. @text=<F>;
  3251. close(F);
  3252. ## $#text + 1 // The lines of the makefile.mak is
  3253. ## = 1 + 2 + 4 + ... + $total * 2 // the first 1 is the all: target in makefile.mak
  3254. ## // the remains are the total of process(n)'s line, ex: process04 has 8 lines
  3255. ## <Mathmetic calculate>
  3256. ## => $#text = 2 + 4 + ... + $total * 2 // remove + 1 in two side
  3257. ## => $#text = 2 * (1 + 2 + ... + $total) // take 2 out of the sum serious
  3258. ## => $#text = 2 * ((1 + $total) * $total) / 2 // the formula of the sum serious
  3259. ## => $#text = (1 + $total) * $total // remove *2 & /2
  3260. ## => $#text = $total^2 + $total // expand
  3261. ## => $total^2 + $total - $#text = 0 // get =0 equation
  3262. ## => $total = (-1 + sqrt(1^2 - 4 * 1 * (-$#text)) / (2 * 1) // the roots is (-b + sqrt(b^2 - 4*a*c) / 2a. ignore the negative one
  3263. ## => $total = (sqrt(4 * $#text + 1) -1) / 2
  3264. $DEFAULT_SECTIONS= (sqrt(4 * $#text + 1) - 1) / 2;
  3265. } else {
  3266. $DEFAULT_SECTIONS = 16;
  3267. }
  3268. print "\n";
  3269. for ( $i=0; $i < @cmdline; $i++ ) {
  3270. $_ = $cmdline[$i];
  3271. ($optname)=m/[-\/]([\?cnfs])/i;
  3272. # Check Option
  3273. if ( $optname ) {
  3274. $SYNTAX_CHECK_ONLY = 1 and next if $optname eq 's'; # -s for syntax check only
  3275. if ($optname eq '?') { # -? for help
  3276. &PrintHelp();
  3277. exit;
  3278. } elsif ($optname eq 'c') { # -c for CLEAN
  3279. $CLEAN = 1;
  3280. $SECTIONS = $DEFAULT_SECTIONS if ($SECTIONS !~/^\d+$/);
  3281. next;
  3282. } elsif ($optname eq 'n') { # -n for Section Number
  3283. # Set SECTIONS value
  3284. $i++;
  3285. ( $i < @cmdline ) || &FatalError( 1008 );
  3286. $SECTIONS = $cmdline[$i];
  3287. next;
  3288. } elsif ($optname eq 'f') { # -f for specified SYSFILE
  3289. # Set SYSFILE value
  3290. $i++;
  3291. ( $i < @cmdline ) || &FatalError( 1008 );
  3292. push @SYSFILES, $cmdline[$i];
  3293. next;
  3294. } # if
  3295. } # if
  3296. # macro definition
  3297. if ( /(\S+)\s*\=\s*(\S+)/ ) {
  3298. &SetMacro( $1, $2, 1 );
  3299. next;
  3300. } # if
  3301. # default (target name)
  3302. &AddTarget($_);
  3303. } # for
  3304. return;
  3305. } # ParseCmdLine
  3306. # parseSymbolCD
  3307. # create the mapping for some binaries listed in symbolcd.txt
  3308. # Input
  3309. # filename [path to symbolcd.txt]
  3310. # Output
  3311. # REF TO ARRAY OF HASH REF [{BIN => SYMBOL}, ... ]
  3312. # Sample usage:
  3313. # print join "\n", @{&parseSymbolCD("symbolcd.txt")};
  3314. #
  3315. sub parseSymbolCD{
  3316. my $fname = shift;
  3317. print "Loading $fname... ";
  3318. open (F, "<". $fname);
  3319. my %o;
  3320. my $o = \%o;
  3321. while(<F>){
  3322. chomp;
  3323. my @s = split ",", $_;
  3324. $s[0] =~ s/^.*\\//g;
  3325. next if ($s[0] eq $s[1]);
  3326. $s[1] =~ s/^.*\.//g;
  3327. $o->{$s[0]} = {} unless defined ($o->{$s[0]});
  3328. $o->{$s[0]}->{$s[1]} = $s[2];
  3329. # there are more lines
  3330. }
  3331. close(F);
  3332. print scalar(keys(%o)), " symbols\n";
  3333. if ($DEBUG){
  3334. foreach $lib (keys(%o)){
  3335. my %hint = %{$o{$lib}};
  3336. print STDERR join("\t", keys(%hint)), "\n";
  3337. }
  3338. }
  3339. %o;
  3340. }
  3341. # LoadHotFix
  3342. # Reads and loads the makefile style hotfix, using the two parts
  3343. # of the dependancy rule for:
  3344. #
  3345. # * check for token->binary depenancy during repository generation
  3346. # * repository modification
  3347. #
  3348. # Input
  3349. # HOTFIX filename
  3350. # Output
  3351. # <none>
  3352. # LoadHotFix can be called any time,
  3353. # since it expands symbols without relying on
  3354. # that vars are defined.
  3355. # Input
  3356. # filename [path to hotfix file]
  3357. # Output
  3358. # <unused>
  3359. sub LoadHotFix{
  3360. my $filename = shift;
  3361. return unless -e $filename;
  3362. open (HOTFIX, $filename);
  3363. # makefile style hot fix.
  3364. my ($target, $build, $depend);
  3365. my $hotfix = \%hotfix;
  3366. while(<HOTFIX>){
  3367. chomp;
  3368. next if /^\#/; # comment
  3369. if (/^\S*SET/i){
  3370. &SetMacro( &SetAttribOp( $_ ), 0 );
  3371. next;
  3372. }
  3373. if ($_=~/^(.*) *\:[^\\](.*)$/){
  3374. $target = $1;#target: source list
  3375. my @depend = ();
  3376. $depend = $2;
  3377. map {push @depend, lc(&ReplaceVar($_))} split( /\s+/, $depend);
  3378. $target =~s/ +$//g;
  3379. $target = lc(&ReplaceVar($target));
  3380. $hotfix{$target} = {"build" => [],
  3381. "depend" => [@depend]};
  3382. print STDERR join("\n", map {"'$_'"} @depend), "\n---\n" if $DEBUG;
  3383. $build = $hotfix->{$target}->{"build"};
  3384. }
  3385. push @$build, "\t".&ReplaceVar($_)."\n" if (/\S/ && /^\t/ );# instructions
  3386. }
  3387. print "Loading $filename ... ",
  3388. scalar (keys(%hotfix)), " hotfix rules\n";
  3389. print STDERR join("\n", map {"'$_'"} keys(%hotfix)), "\n" if $DEBUG;
  3390. close(HOTFIX);
  3391. map {print STDERR $_, "\n",join("\n",
  3392. @{$hotfix->{$_}->{"build"}}), "\n---\n"}
  3393. keys(%hotfix)
  3394. and exit if $DEBUG;
  3395. 1;
  3396. }
  3397. # FixRepository
  3398. # Merges contents of Repository with the commands from the HOTFIX file
  3399. # on the same target without introducing new targets.
  3400. # Must be called as late as possible but before the
  3401. # writing the nmake Makefile
  3402. # Input
  3403. # <none>
  3404. # Output
  3405. # <unused>
  3406. sub FixRepository{
  3407. my $mapref = \%REPOSITORY;
  3408. return unless scalar(keys(%hotfix));
  3409. for $destpath ( sort keys %{$mapref} ) {
  3410. for $destfile ( sort keys %{$mapref->{$destpath}} ) {
  3411. $fullname=lc(join("\\",$destpath, $destfile));
  3412. if ($hotfix{lc($fullname)}){
  3413. print STDERR "Applying hotfix rule for $fullname\n" if $DEBUG;
  3414. my $cmdref = $mapref->{$destpath}->{$destfile}->{"Cmd"};
  3415. my @cmd = map {$_} @{$cmdref};
  3416. my $hotfix = \%hotfix;
  3417. my $depend = $hotfix->{$fullname}->{"depend"};
  3418. my $dep = join(" ", "", @$depend);
  3419. $cmd[0] =~ s/$/$dep/;# append the dep list
  3420. $#cmd=0 if &GetMacro("OVERWRITE_DEFAULT_RULE");
  3421. my $newcmd = $hotfix->{$fullname}->{"build"};
  3422. if (&GetMacro("APPEND")){
  3423. # append:
  3424. push @cmd, @{$newcmd};
  3425. }
  3426. else{
  3427. # prepend:
  3428. my $line0 = shift @cmd;
  3429. unshift @cmd, @{$newcmd};
  3430. unshift @cmd, $line0;
  3431. }
  3432. $mapref->{$destpath}->{$destfile}->{"Cmd"} = \@cmd;
  3433. map {print STDERR "$_\n"} @cmd if $DEBUG;
  3434. }
  3435. }
  3436. }
  3437. 1;
  3438. }