1#!/usr/bin/perl 2 3# Copyright (c) 2018, MIPI Alliance, Inc. 4# All rights reserved. 5# 6# Redistribution and use in source and binary forms, with or without 7# modification, are permitted provided that the following conditions 8# are met: 9# 10# * Redistributions of source code must retain the above copyright 11# notice, this list of conditions and the following disclaimer. 12# 13# * Redistributions in binary form must reproduce the above copyright 14# notice, this list of conditions and the following disclaimer in 15# the documentation and/or other materials provided with the 16# distribution. 17# 18# * Neither the name of the copyright holder nor the names of its 19# contributors may be used to endorse or promote products derived 20# from this software without specific prior written permission. 21# 22# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 25# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 26# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 27# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 28# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 30# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 31# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 32# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 34# Contributors: 35# norbert.schulz@intel.com - initial API and implementation 36# 37use strict; 38use warnings; 39use File::Spec; 40use XML::Simple; 41use File::Find; 42use Getopt::Long; 43use Pod::Usage; 44use String::Escape; 45use bigint qw/hex/; 46 47use Data::Dumper; 48 49# ============================================================================= 50# Globals 51# ============================================================================= 52my ( undef, undef, $TOOL ) = File::Spec->splitpath( $0 ); 53my $INDENTATION = 2; 54my $SRCLOCATION = 1; 55my $CONFIG = (); 56my $FILE_COUNTER = 0; 57my $MSG_STRUCT = (); 58my $FILE_STRUCT = (); 59my $USED_IDS = (); 60my %OPTIONS = (); 61 62 63# ============================================================================= 64# Main functions. 65# ============================================================================= 66 67sub main { 68 read_options (); 69 70 find({ 71 wanted => \&file_handler, 72 preprocess => \&filter_file_list }, @{$OPTIONS{src}}); 73 74 sub file_handler { 75 my $file = $File::Find::name; 76 if (-f $_ && !is_file_existing ($file)) { 77 _i ("Parsing: ".$file."\n"); 78 add_file ($file); 79 my $count = parse_file ($_); 80 _i ("Parsing finished: ".$file.", found $count call(s)\n"); 81 } 82 } 83 84 # 85 # Filters the file list before the file_handler functions will be 86 # called by File::find. 87 # 88 sub filter_file_list { 89 my @filtered_list = (); 90 # Filter files with wanted extensions. 91 foreach my $pattern (@{$CONFIG->{SrcFilePatterns}->{SrcFilePattern}}) { 92 push (@filtered_list, glob($pattern->{Pattern})); 93 } 94 # Add sub directories to scan whole trees. 95 foreach my $dir (grep { -d } @_) { 96 if ($dir ne '.' && $dir ne '..') { 97 push (@filtered_list, $dir); 98 } 99 } 100 return @filtered_list; 101 } 102 103 if (!defined ($FILE_STRUCT)) { 104 _e ("No files found, which match the provided patterns!\n"); 105 } 106 107 if (!defined ($MSG_STRUCT)) { 108 _e ("No messages found!\n"); 109 } 110 111 my $xml = generate_xml ($MSG_STRUCT, $FILE_STRUCT); 112 113 _i ("Writing XML file: ".$OPTIONS{catalog}."\n"); 114 open (CATALOG, ">".$OPTIONS{catalog}) 115 or _e ("Could not open file (w): $!\n"); 116 print CATALOG $xml; 117 close (CATALOG); 118 _i ("Writing XML file finished\n"); 119} 120 121# 122# generate_xml (<msg-data-structure>, <file-data-structure>) 123# 124# Description: 125# Generate SyS-T catalog XML structure based on read message 126# calls and scanned files. 127# 128sub generate_xml { 129 my $msg_struct = $_[0]; 130 my $file_struct = $_[1]; 131 132 _i ("Generating XML structure\n"); 133 134 my $output = load_template($OPTIONS{template}); 135 136 # build sources section 137 # 138 if (defined $file_struct) { 139 if ($SRCLOCATION) { 140 my $source_list = '<syst:SourceFiles>'."\n"; 141 foreach my $file_id (sort {$a <=> $b} keys %{$file_struct}) { 142 $source_list.= ' ' x ($INDENTATION*2); 143 $source_list.= '<syst:File ID="'.$file_id.'">'; 144 $source_list.= '<![CDATA['.$file_struct->{$file_id}.']]>'; 145 $source_list.= '</syst:File>'."\n" 146 } 147 $source_list.= ' ' x $INDENTATION; 148 $source_list.= '</syst:SourceFiles>'."\n"; 149 150 $output =~ s/<syst:SourceFiles\/>/$source_list/sm; 151 } 152 153 if (defined $msg_struct->{"32"}) { 154 if (index($output, '<syst:Catalog32/>') != -1) { 155 my $section = generate_catalog_section($msg_struct, 32); 156 $output =~ s/<syst:Catalog32\/>/$section/sm; 157 } else { 158 _w('32 bit catalog messages found, but template file '. 159 'is missing the insertion pattern "<syst:Catalog32/>"'."\n"); 160 } 161 } 162 if (defined $msg_struct->{"64"}) { 163 if (index($output, '<syst:Catalog64/>') != -1) { 164 my $section = generate_catalog_section($msg_struct, 64); 165 $output =~ s/<syst:Catalog64\/>/$section/sm; 166 } else { 167 _w('64 bit catalog messages found, but template file '. 168 'is missing the insertion pattern "<Messages IdSize="64Bit"/>"'."\n"); 169 } 170 } 171 } else { 172 _w( "no source files to parse found." ); 173 } 174 175 _i ("Generating XML structure finished\n"); 176 177 return $output; 178} 179 180# 181# generate_catalog_section (<found hits>, 32|64) 182# 183# Description 184sub generate_catalog_section { 185 my $hits = $_[0]; 186 my $size = $_[1]+0; 187 188 my $data = $hits->{$size}; 189 my $output =""; 190 191 $output.= '<syst:Catalog'.$size.'>'."\n"; 192 193 foreach my $file_id (sort keys %{$data}) { 194 foreach my $line_id (sort {$a <=> $b} keys %{$data->{$file_id}}) { 195 foreach my $msg_id (sort {$a <=> $b} keys %{$data->{$file_id}->{$line_id}}) { 196 my $msg = $data->{$file_id}->{$line_id}->{$msg_id}; 197 my $idval= ""; 198 199 if ($size == 32) { 200 $idval = sprintf("0x%08x", $msg_id); 201 } else { 202 $idval = sprintf("0x%016x", $msg_id); 203 } 204 $output.= ' ' x ($INDENTATION*2); 205 $output.= '<syst:Format ID="'.$idval.'"'; 206 if ($SRCLOCATION) { 207 $output.= ' File="'.$file_id.'" Line="'.$line_id .'"'; 208 } 209 $output.= '><![CDATA['.String::Escape::unbackslash($msg).']]>'; 210 $output.= '</syst:Format>'."\n"; 211 } 212 } 213 } 214 $output.= ' ' x $INDENTATION; 215 $output.= '</syst:Catalog'.$size.'>'."\n"; 216 217 return $output; 218} 219 220# 221# add_file (<file>) 222# 223# Description: 224# Add a file to the file data structure and increment global 225# file counter. 226# 227sub add_file { 228 my $file = $_[0]; 229 230 $FILE_COUNTER++; 231 232 if ($SRCLOCATION) { 233 _i ("Add $file with file id $FILE_COUNTER to file catalog\n"); 234 } 235 236 if (defined($FILE_STRUCT->{$FILE_COUNTER})) { 237 _e ("File with file id $FILE_COUNTER already exists!\n"); 238 } 239 $FILE_STRUCT->{$FILE_COUNTER} = $file; 240} 241 242# 243# is_file_existing (<file>) 244# 245# Description: 246# Check if file is already existing in the file data structure 247# 248sub is_file_existing { 249 return (grep {$FILE_STRUCT->{$_} eq $_[0]} keys %{$FILE_STRUCT}) > 0; 250} 251 252# 253# load_template (<file>) 254# 255# Description: 256# Parse the given file as the catalog template file where the catalog 257# messages get added into. 258# 259sub load_template { 260 my $file = $_[0]; 261 local $/ = undef; 262 open (FILE, $file) or _e ("Could not open input template file ".$file.": $!\n"); 263 my $content = <FILE>; 264 close FILE; 265 266 _i("Loaded template collateral file ".$file."\n"); 267 268 return $content; 269} 270 271# 272# parse_file (<file>) 273# 274# Description: 275# Parse the given file to extract SyS-T catalog trace calls. Results will be 276# stored into global catalog data structure. 277# 278sub parse_file { 279 my $file = $_[0]; 280 281 open (FILE, $file) or _e ("Could not open file ".$file.": $!\n"); 282 my @content = <FILE>; 283 close FILE; 284 285 my $add_count = 0; 286 287 # loop over the input lines 288 # 289 for (my $i = 0; $i < $#content+1; $i++) { 290 my $calltype= undef; 291 292 for my $idsize ( "32", "64" ) { 293 294 my $calltype ="Catalog".$idsize; 295 my $callset = $CONFIG->{CatalogCalls}->{$calltype}->{CatalogCall}; 296 297 foreach my $function_name (keys %{$callset}) 298 { 299 if (!defined ($callset->{$function_name}->{IdParamIdx})) { 300 _e ("Configuration: 'IdParamIdx' is not defined for function ". 301 "call: $function_name\n"); 302 } 303 if (!defined ($callset->{$function_name}->{StringParamIdx})) { 304 _e ("Configuration: 'StringParamIdx' is not defined for ". 305 "function call: $function_name\n"); 306 } 307 308 # find the current function call 309 if ($content[$i] =~ /\b${function_name}\b/) { 310 my $call = strip_comments ($content[$i]); 311 my $line_no_start = $i+1; 312 my $line_no_end = $i+1; 313 314 if (!strip_whitespaces ($call)) { 315 _i ("Catalog instrumentation call \@ ". 316 "$file:$line_no_start will be skipped.\n"); 317 next; 318 } 319 _vi ("function call start: $function_name at line ". 320 $line_no_start."\n"); 321 322 # try to find the end of the function call, which is might 323 # not be at the same line. 324 while ($content[$i] !~ /\)(\s*|\t*);/) { 325 my $tmp = strip_comments ($content[++$i]); 326 $call.=$tmp; 327 } 328 $line_no_end = $i+1; 329 330 _vi ("functon call end: $function_name at line ". 331 $line_no_end."\n"); 332 333 # remove new line and extract arguments 334 $call =~ s/\n//g; 335 $call =~ m/${function_name}\b(\s*|\t*)\((.*)\)(\s*|\t*);/; 336 337 my $arguments = $2; 338 339 # now split the arguments by character 340 my @array = split(//, $arguments); 341 my $current_arg_no = 0; 342 my $inside_string = 0; 343 my $possible_end_of_call = 0; 344 my $bracket_count = 0; 345 my $found_quotes = 0; 346 my @function_args = (); 347 my $opening_quote = ""; 348 349 # Iterate argument list character by character 350 for (my $i = 0; $i < $#array+1; $i++) { 351 # if a closing bracket will be found not inside the format 352 # string it may be the end of the call. 353 if ($array[$i] eq ")" && !$inside_string) { 354 $possible_end_of_call ^= 1; 355 if ($bracket_count == 0) { 356 last; 357 } 358 $bracket_count--; 359 } 360 # if opening bracket was found, reset possible end marker 361 if ($array[$i] eq "(" && !$inside_string) { 362 $bracket_count++; 363 $possible_end_of_call = 0; 364 } 365 366 # if a semicolon was found, not inside the format string 367 # and one of the previous characters was a closing bracket, 368 # it's the end of the call. 369 if ($array[$i] eq ";" && !$inside_string 370 && $possible_end_of_call) { 371 _d ("End of call detected at line $line_no_start\n"); 372 last; 373 } 374 375 # Find the argument separators 376 if ($array[$i] eq "," && !$inside_string) { 377 $current_arg_no++; 378 next; 379 } 380 381 # If a format string was found, do not search 382 # for argument separators. 383 if ($array[$i] eq "\"" || $array[$i] eq "'") { 384 $found_quotes = 1; 385 # check if the previous character escaped the current 386 # one. 387 if ($i >= 0 && $array[$i-1] ne "\\") { 388 # Within a string, quotes match, so reset control variables. 389 if ($inside_string && $opening_quote eq $array[$i]) { 390 $opening_quote = ""; 391 $inside_string ^= 1; 392 next; 393 # Not within a string, start quote empty. Begin of a string. 394 } elsif (!$inside_string && $opening_quote eq "") { 395 $opening_quote = $array[$i]; 396 $inside_string ^= 1; 397 next; 398 } 399 } 400 } 401 402 # Skip spaces outside of a string 403 if (!$inside_string && $found_quotes && ($array[$i] eq " " || $array[$i] eq "\t")) { 404 next; 405 } 406 407 # Add argument to array. 408 $function_args[$current_arg_no].=$array[$i]; 409 } 410 411 # remove leading and trailing whitespaces from the arguments 412 map { 413 $_ = strip_whitespaces ($_); 414 } @function_args; 415 416 my $str_idx = $callset->{$function_name}->{StringParamIdx}; 417 my $file = (defined ($FILE_STRUCT->{$FILE_COUNTER}) ? 418 $FILE_STRUCT->{$FILE_COUNTER} : $FILE_COUNTER); 419 420 my $message_id = undef; 421 my $message_str = $function_args[$str_idx-1]; 422 423 my $algorithm = 'fromIdParam'; 424 if (defined( $callset->{$function_name}->{Algorithm})) { 425 $algorithm = $callset->{$function_name}->{Algorithm}; 426 } 427 _d("Algorithm = $algorithm\n"); 428 429 my $id_idx = $callset->{$function_name}->{IdParamIdx}; 430 _d("IdParamIdx = $id_idx\n"); 431 if ($algorithm eq 'hash65599') { 432 $message_id = hash_x65599 ($message_str, $function_args[$id_idx-1]); 433 } else { 434 $message_id = to_value($function_args[$id_idx-1]); 435 } 436 437 _d ("StringParamIdx = $str_idx\n"); 438 _d ("IdSize = $idsize\n"); 439 _d ("Found call: ".strip_whitespaces ($call)."\n"); 440 _d ("Arguments: ".strip_whitespaces ($arguments)."\n"); 441 442 if (!$found_quotes) { 443 _e ("Catalog instrumentation call \@ ". 444 "$file:$line_no_start ". 445 "could not be parsed. ". 446 "No valid format string found.\n"); 447 } 448 if (!is_dec($message_id) && !is_hex($message_id)) { 449 _e ("Catalog instrumentation call \@ ". 450 "$file:$line_no_start '$message_id' ". 451 "is not decimal or hexadecimal.\n"); 452 } 453 454 if (exists($USED_IDS->{$message_id})) { 455 if ($algorithm eq 'hash65599') { 456 _e ("Catalog instrumentation call \@ ". 457 "$file:$line_no_start hash based ID '$message_id' ". 458 "already exists. Change the offset value.\n"); 459 } else { 460 _e ("Catalog instrumentation call \@ ". 461 "$file:$line_no_start with ID '$message_id' ". 462 "also exists \@ ". 463 $FILE_STRUCT->{$USED_IDS->{$message_id}->{file}}. 464 ":". 465 $USED_IDS->{$message_id}->{line}.".\n"); 466 } 467 } 468 $MSG_STRUCT->{$idsize}->{$FILE_COUNTER}->{$line_no_start}->{$message_id} = $message_str; 469 470 $USED_IDS->{$message_id} ={ 471 file => $FILE_COUNTER, 472 line => $line_no_start 473 }; 474 $add_count++; 475 476 _d ("-" x 79 . "\n"); 477 } 478 } 479 } 480 } 481 close (FILE); 482 483 return $add_count; 484} 485 486 487# ============================================================================= 488# Helper functions. 489# ============================================================================= 490 491 492# 493# read_options_from_config_file () 494# 495# Description: 496# Read options from config file and store them into global data structure. 497# The function also checks if the resp. option was overruled by a command 498# line switch. 499# 500sub read_options_from_config_file { 501 $CONFIG = read_config ($OPTIONS{config}); 502 503 if (!defined ($CONFIG->{CatalogConfigs}) 504 || !defined ($CONFIG->{CatalogConfigs}->{CatalogConfig})) { 505 return; 506 } 507 508 my %new_options = (); 509 foreach my $config_record (@{$CONFIG->{CatalogConfigs}->{CatalogConfig}}) { 510 my $option = $config_record->{option}; 511 my $value = $config_record->{value}; 512 if (!defined($OPTIONS{$option})) { 513 if ($option eq "guid" || $option eq "src") { 514 if (!defined($new_options{$option})) { 515 @{$new_options{$option}} = (); 516 } 517 push (@{$new_options{$option}}, $value); 518 } else { 519 $new_options{$option} = $value; 520 } 521 } else { 522 _vi ("Config file option '$option' overruled by ". 523 "command line option\n"); 524 } 525 } 526 527 # Merge the two hashes. 528 @OPTIONS{keys %new_options} = values %new_options; 529} 530 531# 532# read_options () 533# 534# Description: 535# Read options from command line an store into global data structure. 536# 537sub read_options { 538 GetOptions (\%OPTIONS, 539 'verbose|v', 540 'debug|d', 541 'src=s@', 542 'catalog|cf=s', 543 'config|c=s', 544 'template|tpl=s', 545 'nolocation|nl', 546 'help|h' 547 ) or pod2usage(-exitval => 0, -verbose => 2, -noperldoc => 1); 548 549 if (defined($OPTIONS{help})) { 550 pod2usage(-exitval => 0, -verbose => 2, -noperldoc => 1); 551 } 552 553 if (!defined($OPTIONS{config})) { 554 _e ("-config option is missing\n"); 555 } elsif (!-f $OPTIONS{config}) { 556 _e ("Specified config is not a file\n"); 557 } 558 559 read_options_from_config_file (); 560 561 if (defined($OPTIONS{src})) { 562 map { 563 _e ("Not existing or not a directory: $_\n") if !-e $_ || !-d $_; 564 } @{$OPTIONS{src}}; 565 } else { 566 _e ("-src option is missing\n"); 567 } 568 569 if (!defined($OPTIONS{catalog})) { 570 _e ("-catalog option is missing\n"); 571 } 572 573 if (!defined($OPTIONS{template})) { 574 _e ("-template option is missing\n"); 575 } 576 577 if (defined($OPTIONS{indentation})) { 578 $INDENTATION = $OPTIONS{indentation}; 579 } 580 581 if (defined($OPTIONS{nolocation}) and 582 (uc($OPTIONS{nolocation}) eq "TRUE") or ($OPTIONS{nolocation} == 1) 583 ) 584 { 585 $SRCLOCATION = 0; 586 } 587} 588 589sub parse_guid { 590 my $guid_expr = $_[0]; 591 my $ret = (); 592 593 if ($guid_expr =~ /^(.*);(.*)$/) { 594 $ret->{guid} = $1; 595 $ret->{mask} = $2; 596 } else { 597 $ret->{guid} = $guid_expr; 598 } 599 600 return $ret; 601} 602 603# 604# strip_comments (<string>) 605# 606# Description: 607# Strip C-style comments. 608# 609sub strip_comments { 610 my $str = $_[0]; 611 $str =~ s/\/\/.*//; 612 $str =~ s/\/\*.*\*\///g; 613 614 return $str; 615} 616 617# 618# strip_whitespaces (<string>) 619# 620# Description: 621# Strip leading and trailing whitespaces/tabs. 622# 623sub strip_whitespaces { 624 my $str = $_[0]; 625 $str =~ s/^\s+//; 626 $str =~ s/\s+$//; 627 $str =~ s/^\t+//; 628 $str =~ s/\t+$//; 629 630 return $str; 631} 632 633# 634# read_config (<configuration-file>) 635# 636# Description: 637# Read configuration and return data structure. An error 638# message will be printed for every missing required section. 639# 640sub read_config { 641 my $config_file = $_[0]; 642 643 my $xml_ref = XMLin($config_file, 644 KeyAttr => { 645 'CatalogCall' => 'Name' 646 }, 647 ForceArray => [ 648 'CatalogCall', 649 'SrcFilePattern', 650 'CatalogConfig' 651 ] 652 ); 653 654 if (!defined ($xml_ref->{SrcFilePatterns}) 655 || !defined ($xml_ref->{SrcFilePatterns}->{SrcFilePattern})) { 656 _e ("The specified config file does not contain a correct ". 657 "SrcFilePatterns/SrcFilePattern structure\n"); 658 } 659 660 if (!defined ($xml_ref->{CatalogCalls}) || 661 (!defined ($xml_ref->{CatalogCalls}->{Catalog32}->{CatalogCall}) && 662 !defined ($xml_ref->{CatalogCalls}->{Catalog64}->{CatalogCall})) 663 ) 664 { 665 _e ("The specified config file does not contain a correct ". 666 "CatalogCalls/CatalogCall structure\n"); 667 } 668 669 return $xml_ref; 670} 671 672# 673# hash_x65599 (<string>, <offset>) 674# 675# Description: 676# Calculates a x65599 hash for the provided string and offset value. 677# 678sub hash_x65599 { 679 my $string = String::Escape::unbackslash($_[0]); 680 my $offset = int($_[1]); 681 682 my $hash = 0; 683 my $tail256 = substr($string, -256); 684 685 foreach my $char (split(//, $tail256 )) { 686 $hash = uint ($hash * 65599 + ord($char)); 687 } 688 689 return $hash + $offset; 690} 691 692# 693# uint (<number>) 694# 695# Description: 696# Mimics the unsigned int data type in Perl. Required for the x65599 hash 697# calculation. 698# 699sub uint { 700 return unpack('I', pack('I', $_[0])); 701} 702 703# 704# to_value (<hex or decimal number>) 705# 706# Description: 707# convert C-Language value to perl hex value 708# 709sub to_value { 710 my $input = $_[0]; 711 my $val=0; 712 713 # Remove possible LL or ULL from the hex number in the C file. 714 $input =~ s/u?ll$//gi; 715 if (is_hex($input)) { 716 $val = hex($input); 717 } else { 718 $val = $input+0; 719 } 720 721 return $val; 722} 723 724 725# 726# is_hex (<number>) 727# 728# Description: 729# Checks if a number is a hex value. 730# 731sub is_hex { 732 return ($_[0] =~ /^0x[0-9a-f]+$/i); 733} 734 735# 736# is_dec (<number>) 737# 738# Description: 739# Checks if a number is a decimal value. 740# 741sub is_dec { 742 return ($_[0] =~ /^\d+$/); 743} 744 745# 746# _e (<msg>) 747# 748# Description: 749# Print error message on STDERR and exit with exist status 1. 750# 751sub _e { 752 _print (*STDERR, "[ERROR]", $_[0]); 753 exit (1); 754} 755 756# 757# _w (<msg>) 758# 759# Description: 760# Print warning message on STDOUT. 761# 762sub _w { 763 _print (*STDOUT, "[WARNING]", $_[0]); 764} 765 766# 767# _i (<msg>) 768# 769# Description: 770# Print general message on STDOUT. 771# 772sub _i { 773 _print (*STDOUT, "", $_[0]); 774} 775 776# 777# _vi (<msg>) 778# 779# Description: 780# Print verbose message on STDOUT. 781# 782sub _vi { 783 _i ($_[0]) if $OPTIONS{verbose}; 784} 785 786# 787# _d (<msg>) 788# 789# Description: 790# Print debug message on STDOUT. 791# 792sub _d { 793 _print (*STDOUT, "[DEBUG]", $_[0]) if $OPTIONS{debug}; 794} 795 796# 797# _print (<msg>) 798# 799# Description: 800# General print handler. 801# 802sub _print { 803 my $handle = $_[0]; 804 my $prefix = $_[1]; 805 my $msg = $_[2]; 806 807 print $handle "$TOOL: ".($prefix ne "" ? $prefix.": " : ""). $msg; 808} 809 810main (); 811exit (0); 812 813__END__ 814=head1 NAME 815 816B<syst_cgen.pl> -- A SyS-T collateral generation script. 817 818=head1 DESCRIPTION 819 820Generate a SyS-T colleteral file with catalog call information from source 821files. The script scans for pre-configured C-style macro calls and extracts 822the message, its ID and the line number and puts it into a SyS-T collateral 823XML structure. 824 825=head1 USAGE 826 827syst_cgen.pl 828 829 -config <config file> 830 [-template <catalog template file>] 831 [-src <src-dir-1>] [-src <src-dir-2> [...]] [-o <xml-file>] 832 [-verbose] [-debug] 833 834 -src <src-dir> Search path for the sources. 835 -catalog|-cf <dest-file> Destination catalog XML file. 836 -template|-tpl <catalog-file> Catalog template to be extended with messages. 837 -config|c <config-file> Catalog generation config file. 838 -nolocation|-nl Supress source location generation 839 -verbose|v Switch on verbose messages. 840 -debug|d Switch on debug messages. 841 842 843=head1 CONFIGURATION 844 845The catalog configuration file specifies the parameters of the script, e.g. 846the macro call names, the argument structure of the calls, and file extensions, 847which should be scanned. 848 849=head2 EXAMPLE CATALOG CONFIGURATION 850 <CatalogGenerator> 851 <CatalogConfigs> 852 <CatalogConfig option="catalog" value="generated_catalog.xml" /> 853 <CatalogConfig option="template" value="template.xml" /> 854 <CatalogConfig option="indentation" value="4" /> 855 <CatalogConfig option="nolocation" value="true|false" /> 856 <CatalogConfig option="src" value="." /> 857 </CatalogConfigs> 858 <SrcFilePatterns> 859 <SrcFilePattern Pattern="*.{cpp,c,h}" /> 860 </SrcFilePatterns> 861 <CatalogCalls> 862 <Catalog32> 863 <CatalogCall Name="MIPI_SYST_HASH" Algorithm="hash65599" IdParamIdx="2" StringParamIdx="1" /> 864 865 <CatalogCall Name="MIPI_SYST_CATPRINTF32" IdParamIdx="3" StringParamIdx="4" /> 866 <CatalogCall Name="MIPI_SYST_CATPRINTF32_0" IdParamIdx="3" StringParamIdx="4" /> 867 <CatalogCall Name="MIPI_SYST_CATPRINTF32_1" IdParamIdx="3" StringParamIdx="4" /> 868 <CatalogCall Name="MIPI_SYST_CATPRINTF32_2" IdParamIdx="3" StringParamIdx="4" /> 869 <CatalogCall Name="MIPI_SYST_CATPRINTF32_3" IdParamIdx="3" StringParamIdx="4" /> 870 <CatalogCall Name="MIPI_SYST_CATPRINTF32_4" IdParamIdx="3" StringParamIdx="4" /> 871 <CatalogCall Name="MIPI_SYST_CATPRINTF32_5" IdParamIdx="3" StringParamIdx="4" /> 872 <CatalogCall Name="MIPI_SYST_CATPRINTF32_6" IdParamIdx="3" StringParamIdx="4" /> 873 </Catalog32> 874 <Catalog64> 875 <CatalogCall Name="MIPI_SYST_CATPRINTF64" IdParamIdx="3" StringParamIdx="4" /> 876 <CatalogCall Name="MIPI_SYST_CATPRINTF64_0" IdParamIdx="3" StringParamIdx="4" /> 877 <CatalogCall Name="MIPI_SYST_CATPRINTF64_1" IdParamIdx="3" StringParamIdx="4" /> 878 <CatalogCall Name="MIPI_SYST_CATPRINTF64_2" IdParamIdx="3" StringParamIdx="4" /> 879 <CatalogCall Name="MIPI_SYST_CATPRINTF64_3" IdParamIdx="3" StringParamIdx="4" /> 880 <CatalogCall Name="MIPI_SYST_CATPRINTF64_4" IdParamIdx="3" StringParamIdx="4" /> 881 <CatalogCall Name="MIPI_SYST_CATPRINTF64_5" IdParamIdx="3" StringParamIdx="4" /> 882 <CatalogCall Name="MIPI_SYST_CATPRINTF64_6" IdParamIdx="3" StringParamIdx="4" /> 883 </Catalog64> 884 </CatalogCalls> 885 </CatalogGenerator> 886 887=head2 SECTION SrcFileExtensions 888 889 <SrcFilePatterns> 890 <SrcFilePattern Pattern="<pattern>" /> 891 </SrcFilePatterns> 892 893This sections defines the file extensions, which will be scanned by the script. 894 895=head2 SECTION CatalogCalls 896 897 <CatalogCalls> 898 <Catalog64 or Catalog32> 899 <CatalogCall Name="<macro-name>" IdParamIdx="<id-argument-index>" 900 StringParamIdx="<format-string-index>" IdSize="<id-size>" /> 901 </Catalog64 or /Catalog32> 902 </CatalogCalls> 903 904This section describes the used macro calls. It describes how the macro is 905named and where the arguments of intereset can be found by the script. There 906are different sections for 32 bit and 64 bit wide catalog calls. 907 908=head2 SECTION CatalogConfigs 909 910 <CatalogConfigs> 911 <CatalogConfig option="<option-name>" value="<value>" /> 912 </CatalogConfigs> 913 914This section specifies pre-defined options for the catalog generation script. 915The options will be overruled by the respective command line options. 916 917=cut 918