| 1 | #!@PERLINTERP@ -w | 
| 2 | ######################################################################## | 
| 3 | # | 
| 4 | # filepp is free software; you can redistribute it and/or modify | 
| 5 | # it under the terms of the GNU General Public License as published by | 
| 6 | # the Free Software Foundation; either version 2 of the License, or | 
| 7 | # (at your option) any later version. | 
| 8 | # | 
| 9 | # This program is distributed in the hope that it will be useful, | 
| 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | 
| 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
| 12 | # GNU General Public License for more details. | 
| 13 | # | 
| 14 | # You should have received a copy of the GNU General Public License | 
| 15 | # along with this program; see the file COPYING.  If not, write to | 
| 16 | # the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | 
| 17 | # | 
| 18 | ######################################################################## | 
| 19 | # | 
| 20 | #  Project      :  File Preprocessor | 
| 21 | #  Filename     :  $RCSfile: filepp.in,v $ | 
| 22 | #  Author       :  $Author: gezelter $ | 
| 23 | #  Maintainer   :  Darren Miller: darren@cabaret.demon.co.uk | 
| 24 | #  File version :  $Revision: 1.1 $ | 
| 25 | #  Last changed :  $Date: 2005-04-14 21:41:56 $ | 
| 26 | #  Description  :  Main program | 
| 27 | #  Licence      :  GNU copyleft | 
| 28 | # | 
| 29 | ######################################################################## | 
| 30 |  | 
| 31 | package Filepp; | 
| 32 |  | 
| 33 | use strict "vars"; | 
| 34 | #use strict "subs"; | 
| 35 | # Used to all filepp to work with any char, not just ascii, | 
| 36 | # feel free to remove this if it causes you problems | 
| 37 | #use bytes; | 
| 38 |  | 
| 39 | # version number of program | 
| 40 | my $VERSION = '1.7.1'; | 
| 41 |  | 
| 42 | # list of paths to search for modules, normal Perl list + module dir | 
| 43 | #push(@INC, "/home/maul/gezelter/tim/code/OOPSE-2.0/scripts/filepp-1.7.1/modules/f90dpend/"); | 
| 44 |  | 
| 45 | # index of keywords supported and functions to deal with them | 
| 46 | my %Keywords = ( | 
| 47 | '#comment' => \&Comment, | 
| 48 | '#define'  => \&Define, | 
| 49 | '#elif'    => \&Elif, | 
| 50 | '#else'    => \&Else, | 
| 51 | '#endif'   => \&Endif, | 
| 52 | '#error'   => \&Error, | 
| 53 | '#if'      => \&If, | 
| 54 | '#ifdef'   => \&Ifdef, | 
| 55 | '#ifndef'  => \&Ifndef, | 
| 56 | '#include' => \&Include, | 
| 57 | '#pragma'  => \&Pragma, | 
| 58 | '#undef'   => \&Undef, | 
| 59 | '#warning' => \&Warning | 
| 60 | ); | 
| 61 |  | 
| 62 | # set of functions which process the file in the Parse routine. | 
| 63 | # Processors are functions which take in a line and return the processed line. | 
| 64 | # Note: this is done as a string rather than pointer to a function because | 
| 65 | # it makes list easier to modify/remove from/print. | 
| 66 | my @Processors = ( "Filepp::ParseKeywords", "Filepp::ReplaceDefines" ); | 
| 67 | # processor types say what the processor should be run on: choice is: | 
| 68 | # 0: Everything (default) | 
| 69 | # 1: Full lines only (lines originating from Parse function) | 
| 70 | # 2: Part lines only (lines originating from within keywords, eg: | 
| 71 | # #if "condition", "condition" is a part line) | 
| 72 | my %ProcessorTypes = ( | 
| 73 | 'Filepp::ParseKeywords'  => 1, | 
| 74 | 'Filepp::ReplaceDefines' => 0 | 
| 75 | ); | 
| 76 |  | 
| 77 | # functions to run each time a new base input file is opened or closed | 
| 78 | my @OpenInputFuncs = (); | 
| 79 | my @CloseInputFuncs = (); | 
| 80 |  | 
| 81 | # functions to run each time a new output file is opened or closed | 
| 82 | my @OpenOutputFuncs = (); | 
| 83 | my @CloseOutputFuncs = (); | 
| 84 |  | 
| 85 | # safe mode is for the paranoid, when enabled turns off #pragma filepp, | 
| 86 | # enabled by default | 
| 87 | my $safe_mode = 0; | 
| 88 |  | 
| 89 | # test for shebang mode, used for "filepp script", ie. executable file with | 
| 90 | # "#!/usr/bin/perl /usr/local/bin/filepp" at the top | 
| 91 | my $shebang = 1; | 
| 92 |  | 
| 93 | # allow $keywordchar, $contchar, $optlineendchar and $macroprefix | 
| 94 | # to be perl regexps | 
| 95 | my $charperlre = 0; | 
| 96 |  | 
| 97 | # character(s) which prefix environment variables - defaults to shell-style '$' | 
| 98 | my $envchar = "\$"; | 
| 99 |  | 
| 100 | # boolean determining whether line continuation is implicit if there are more | 
| 101 | # open brackets than close brackets on a line | 
| 102 | # disabled by default | 
| 103 | my $parselineend = \&Filepp::ParseLineEnd; | 
| 104 |  | 
| 105 | # character(s) which replace continuation char(s) - defaults to C-style nothing | 
| 106 | my $contrepchar = ""; | 
| 107 |  | 
| 108 | # character(s) which prefix keywords - defaults to C-style '#' | 
| 109 | my $keywordchar; | 
| 110 | if($charperlre) { $keywordchar = "\#"; } | 
| 111 | else            { $keywordchar = "\Q#\E"; } | 
| 112 |  | 
| 113 | # character(s) which signifies continuation of a line - defaults to C-style '\' | 
| 114 | my $contchar; | 
| 115 | if($charperlre) { $contchar = "\\\\"; } | 
| 116 | else            { $contchar = "\Q\\\E"; } | 
| 117 |  | 
| 118 | # character(s) which optionally signifies the end of a line - | 
| 119 | # defaults to empty string '' | 
| 120 | my $optlineendchar = ""; | 
| 121 |  | 
| 122 | # character(s) which prefix macros - defaults to nothing | 
| 123 | my $macroprefix = ""; | 
| 124 |  | 
| 125 | # flag to use macro prefix in keywords (on by default) | 
| 126 | my $macroprefixinkeywords = 1; | 
| 127 |  | 
| 128 | # check if macros must occur as words when replacing, set this to '\b' if | 
| 129 | # you prefer cpp style behaviour as default | 
| 130 | my $bound = ''; | 
| 131 |  | 
| 132 | # number of line currently being parsed (int) | 
| 133 | my $line = 0; | 
| 134 |  | 
| 135 | # file currently being parsed | 
| 136 | my $file = ""; | 
| 137 |  | 
| 138 | # list of input files | 
| 139 | my @Inputfiles; | 
| 140 |  | 
| 141 | # list of files to include macros from | 
| 142 | my @Imacrofiles; | 
| 143 |  | 
| 144 | # flag to control when output is written | 
| 145 | my $output = 1; | 
| 146 |  | 
| 147 | # name of outputfile - defaults to STDOUT | 
| 148 | my $outputfile = ""; | 
| 149 |  | 
| 150 | # overwrite mode - automatically overwrites old file with new file | 
| 151 | my $overwrite = 0; | 
| 152 |  | 
| 153 | # overwrite conversion mode - conversion from input filename to output filename | 
| 154 | my $overwriteconv = ""; | 
| 155 |  | 
| 156 | # list of keywords which have "if" functionality | 
| 157 | my %Ifwords = ('#if',     '', | 
| 158 | '#ifdef',  '', | 
| 159 | '#ifndef', ''); | 
| 160 |  | 
| 161 | # list of keywords which have "else" functionality | 
| 162 | my %Elsewords = ('#else', '', | 
| 163 | '#elif', ''); | 
| 164 |  | 
| 165 | # list of keywords which have "endif" functionality | 
| 166 | my %Endifwords = ('#endif', ''); | 
| 167 |  | 
| 168 | # current level of include files | 
| 169 | my $include_level = -1; | 
| 170 |  | 
| 171 | # suppress blank lines in header files (indexed by include level) | 
| 172 | my $blanksuppopt = 0; | 
| 173 | my @blanksupp; | 
| 174 | # try to keep same number lines in output file as input file | 
| 175 | my $preserveblank = 0; | 
| 176 |  | 
| 177 | # counter of recursion level for detecting recursive macros | 
| 178 | my $recurse_level = -1; | 
| 179 |  | 
| 180 | # debugging info, 1=on, 0=off | 
| 181 | my $debug = 0; | 
| 182 | # send debugging info to stdout rather than stderr | 
| 183 | my $debugstdout = 0; | 
| 184 | # debug prefix character or string | 
| 185 | my $debugprefix = ""; | 
| 186 | # debug postfix character or string | 
| 187 | my $debugpostfix = "\n"; | 
| 188 |  | 
| 189 | # hash of macros defined - standard ones already included | 
| 190 | my %Defines = ( | 
| 191 | '__BASE_FILE__'     => "", | 
| 192 | '__DATE__'          => "", | 
| 193 | '__FILEPP_INPUT__'  => "Generated automatically from __BASE_FILE__ by filepp", | 
| 194 | '__FILE__'          => $file, | 
| 195 | '__INCLUDE_LEVEL__' => $include_level, | 
| 196 | '__ISO_DATE__'      => "", | 
| 197 | '__LINE__'          => $line, | 
| 198 | '__NEWLINE__'       => "\n", | 
| 199 | '__NULL__'          => "", | 
| 200 | '__TAB__'           => "\t", | 
| 201 | '__TIME__'          => "", | 
| 202 | '__VERSION__'       => $VERSION | 
| 203 | ); | 
| 204 | # hash of first chars in each macro | 
| 205 | my %DefineLookup; | 
| 206 | # length of longest and shortest define | 
| 207 | my ($defmax, $defmin); | 
| 208 | GenerateDefinesKeys(); | 
| 209 |  | 
| 210 | # set default values for date and time | 
| 211 | { | 
| 212 | # conversions of month number into letters (0-11) | 
| 213 | my @MonthChars = ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', | 
| 214 | 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'); | 
| 215 | #prepare standard defines | 
| 216 | my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isbst) = | 
| 217 | localtime(time()); | 
| 218 | $year += 1900; | 
| 219 | $sec  = sprintf("%02d", $sec); | 
| 220 | $min  = sprintf("%02d", $min); | 
| 221 | $hour = sprintf("%02d", $hour); | 
| 222 | $mday = sprintf("%02d", $mday); | 
| 223 | $mon  = sprintf("%02d", $mon); | 
| 224 | Redefine("__TIME__", $hour.":".$min.":".$sec); | 
| 225 | Redefine("__DATE__", $MonthChars[$mon]." ".$mday." ".$year); | 
| 226 | $mon = sprintf("%02d", ++$mon); | 
| 227 | Redefine("__ISO_DATE__", $year."-".$mon."-".$mday); | 
| 228 | } | 
| 229 |  | 
| 230 | # hash table for arguments to macros which need them | 
| 231 | my %DefinesArgs = (); | 
| 232 |  | 
| 233 | # hash table for functions which macros should call (if any) | 
| 234 | my %DefinesFuncs = (); | 
| 235 |  | 
| 236 | # eat-trailing-whitespace flag for each macro | 
| 237 | my %EatTrail = (); | 
| 238 |  | 
| 239 | # list of include paths | 
| 240 | my @IncludePaths; | 
| 241 |  | 
| 242 | # help string | 
| 243 | my $usage = "filepp: generic file preprocessor, version ".$VERSION." | 
| 244 | usage: filepp [options] inputfile(s) | 
| 245 | options: | 
| 246 | -b\t\tsuppress blank lines from include files | 
| 247 | -c\t\tread input from STDIN instead of file | 
| 248 | -Dmacro[=defn]\tdefine macros (same as #define) | 
| 249 | -d\t\tprint debugging information | 
| 250 | -dd\t\tprint verbose debugging information | 
| 251 | -dl\t\tprint some (light) debugging information | 
| 252 | -dpre char\tprefix all debugging information with char | 
| 253 | -dpost char\tpostfix all debugging information with char, defaults to newline | 
| 254 | -ds\t\tsend debugging info to stdout rather than stderr | 
| 255 | -e\t\tdefine all environment variables as macros | 
| 256 | -ec char\tset environment variable prefix char to \"char\" (default \$) | 
| 257 | -ecn\t\tset environment variable prefix char to nothing (default \$) | 
| 258 | -h\t\tprint this help message | 
| 259 | -Idir\t\tdirectory to search for include files | 
| 260 | -imacros file\tread in macros from file, but discard rest of file | 
| 261 | -k\t\tturn off parsing of all keywords, just macro expansion is done | 
| 262 | -kc char\tset keyword prefix char to \"char\" (defaults to #) | 
| 263 | -lc char\tset line continuation character to \"char\" (defaults to \\) | 
| 264 | -lec char\tset optional keyword line end char to \"char\" | 
| 265 | -lr char\tset line continuation replacement character to \"char\" | 
| 266 | -lrn\t\tset line continuation replacement character to newline | 
| 267 | -m module\tload module | 
| 268 | -mp char\tprefix all macros with \"char\" (defaults to no prefix) | 
| 269 | -mpnk\t\tdo not use macro prefix char in keywords | 
| 270 | -Mdir\t\tdirectory to search for filepp modules | 
| 271 | -o output\tname of output file (defaults to stdout) | 
| 272 | -ov\t\toverwrite mode - output file will overwrite input file | 
| 273 | -ovc IN=OUT\toutput file(s) will have be input file(s) with IN conveted to OUT | 
| 274 | -pb\t\tpreseve blank lines in output that would normally be removed | 
| 275 | -s\t\trun in safe mode (turns off pragma keyword) | 
| 276 | -re\t\ttreat keyword and macro prefixes and line cont chars as reg exps | 
| 277 | -u\t\tundefine all predefined macros | 
| 278 | -v\t\tprint version and exit | 
| 279 | -w\t\tturn on word boundaries when replacing macros | 
| 280 | all other arguments are assumed to be input files | 
| 281 | "; | 
| 282 |  | 
| 283 |  | 
| 284 | # visited table | 
| 285 | my %visitedTable = (); | 
| 286 |  | 
| 287 | #object directory | 
| 288 | my $objDir =""; | 
| 289 |  | 
| 290 | # f90moduleList | 
| 291 | my %parsedModList = (); | 
| 292 |  | 
| 293 | # | 
| 294 | my %f90ModList = (); | 
| 295 |  | 
| 296 | # suffix of fortran object file | 
| 297 | my $objExt = '.o'; | 
| 298 |  | 
| 299 | # suffix of fortran 90 module | 
| 300 | my $modSuffix = "mod"; | 
| 301 |  | 
| 302 | # case of basename of fortran 90 module | 
| 303 | my $modBasenameCase = "lower"; | 
| 304 |  | 
| 305 | #flag for generating dependency, by default, it is off | 
| 306 | my $dependency = 0; | 
| 307 |  | 
| 308 | #skip system header file | 
| 309 | my $skipSysInclude = 0; | 
| 310 |  | 
| 311 | #saved command line define macro | 
| 312 | my @savedDefine; | 
| 313 |  | 
| 314 | ############################################################################## | 
| 315 | # SetDebug - controls debugging level | 
| 316 | ############################################################################## | 
| 317 | sub SetDebug | 
| 318 | { | 
| 319 | $debug = shift; | 
| 320 | Debug("Debugging level set to $debug", 1); | 
| 321 | } | 
| 322 |  | 
| 323 |  | 
| 324 | ############################################################################## | 
| 325 | # Debugging info | 
| 326 | ############################################################################## | 
| 327 | sub Debug | 
| 328 | { | 
| 329 | # print nothing if not debugging | 
| 330 | if($debug == 0) { return; } | 
| 331 | my $msg = shift; | 
| 332 | my $level = 1; | 
| 333 | # check if level has been provided | 
| 334 | if($#_ > -1) { $level = shift; } | 
| 335 | if($level <= $debug) { | 
| 336 | # if currently parsing a file show filename and line number | 
| 337 | if($file ne "" && $line > 0) { | 
| 338 | $msg = $file.":".$line.": ".$msg; | 
| 339 | } | 
| 340 | # else show program name | 
| 341 | else { $msg = "filepp: ".$msg; } | 
| 342 | if($debugstdout) { | 
| 343 | print(STDOUT $debugprefix.$msg.$debugpostfix); | 
| 344 | } | 
| 345 | else { | 
| 346 | print(STDERR $debugprefix.$msg.$debugpostfix); | 
| 347 | } | 
| 348 | } | 
| 349 | } | 
| 350 |  | 
| 351 |  | 
| 352 | ############################################################################## | 
| 353 | # Standard error handler. | 
| 354 | # #error msg  - print error message "msg" and exit | 
| 355 | ############################################################################## | 
| 356 | sub Error | 
| 357 | { | 
| 358 | my $msg = shift; | 
| 359 | # close and delete output file if created | 
| 360 | close(OUTPUT); | 
| 361 | if($outputfile ne "-") { # output is not stdout | 
| 362 | my $inputfile; | 
| 363 | my $found = 0; | 
| 364 | # do paranoid check to make sure we are not deleting an input file | 
| 365 | foreach $inputfile (@Inputfiles) { | 
| 366 | if($outputfile eq $inputfile) { $found = 1; last; } | 
| 367 | } | 
| 368 | # delete output file | 
| 369 | if($found == 0) { unlink($outputfile); } | 
| 370 | } | 
| 371 | # print error message | 
| 372 | $debug = 1; | 
| 373 | Debug($msg, 0); | 
| 374 | exit(1); | 
| 375 | } | 
| 376 |  | 
| 377 |  | 
| 378 | ############################################################################## | 
| 379 | # SafeMode - turns safe mode on | 
| 380 | ############################################################################## | 
| 381 | sub SafeMode | 
| 382 | { | 
| 383 | $safe_mode = 1; | 
| 384 | Debug("Filepp safe mode enabled", 2); | 
| 385 | } | 
| 386 |  | 
| 387 |  | 
| 388 | ############################################################################## | 
| 389 | # CleanStart($sline) - strip leading whitespace from start of $sline. | 
| 390 | ############################################################################## | 
| 391 | sub CleanStart | 
| 392 | { | 
| 393 | my $sline = shift; | 
| 394 | for($sline) { | 
| 395 | # '^' = start of line, '\s+' means all whitespace, replace with nothing | 
| 396 | s/^\s+//; | 
| 397 | } | 
| 398 | return $sline; | 
| 399 | } | 
| 400 |  | 
| 401 |  | 
| 402 | ############################################################################## | 
| 403 | # Strip($sline, $char, $level) - strip $char's from start and end of $sline | 
| 404 | # removes up to $level $char's from start and end of line, it is not an | 
| 405 | # error if $level chars do not exist at the start or end of line | 
| 406 | ############################################################################## | 
| 407 | sub Strip | 
| 408 | { | 
| 409 | my $sline = shift; | 
| 410 | my $char = shift; | 
| 411 | my $level = shift; | 
| 412 | # strip leading chars from line | 
| 413 | $sline =~ s/\A([$char]{0,$level})//g; | 
| 414 | # strip trailing chars from line | 
| 415 | $sline =~ s/([$char]{0,$level})\Z//g; | 
| 416 | return $sline; | 
| 417 | } | 
| 418 |  | 
| 419 |  | 
| 420 | ############################################################################## | 
| 421 | # SetMacroPrefix $string - prefixs all macros with $string | 
| 422 | ############################################################################## | 
| 423 | sub SetMacroPrefix | 
| 424 | { | 
| 425 | $macroprefix = shift; | 
| 426 | # make sure prefix will not be treated as a Perl regular expression | 
| 427 | if(!$charperlre) {  $macroprefix = "\Q$macroprefix\E"; } | 
| 428 | Debug("Setting macro prefix to <".$macroprefix.">", 2); | 
| 429 | } | 
| 430 |  | 
| 431 |  | 
| 432 | ############################################################################## | 
| 433 | # SetKeywordchar $string - sets the first char(s) of each keyword to | 
| 434 | # something other than "#" | 
| 435 | ############################################################################## | 
| 436 | sub SetKeywordchar | 
| 437 | { | 
| 438 | $keywordchar = shift; | 
| 439 | # make sure char will not be treated as a Perl regular expression | 
| 440 | if(!$charperlre) { $keywordchar = "\Q$keywordchar\E"; } | 
| 441 | Debug("Setting keyword prefix character to <".$keywordchar.">", 2); | 
| 442 | } | 
| 443 |  | 
| 444 | ############################################################################## | 
| 445 | # GetKeywordchar - returns the current keywordchar | 
| 446 | ############################################################################## | 
| 447 | sub GetKeywordchar | 
| 448 | { | 
| 449 | return $keywordchar; | 
| 450 | } | 
| 451 |  | 
| 452 |  | 
| 453 | ############################################################################## | 
| 454 | # SetContchar $string - sets the line continuation char to something other | 
| 455 | # than "\" | 
| 456 | ############################################################################## | 
| 457 | sub SetContchar | 
| 458 | { | 
| 459 | $contchar = shift; | 
| 460 | # make sure char will not be treated as a Perl regular expression | 
| 461 | if(!$charperlre) { $contchar = "\Q$contchar\E"; } | 
| 462 | Debug("Setting line continuation character to <".$contchar.">", 2); | 
| 463 | } | 
| 464 |  | 
| 465 |  | 
| 466 | ############################################################################## | 
| 467 | # SetContrepchar $string - sets the replace of the line continuation char to | 
| 468 | # something other than "" | 
| 469 | ############################################################################## | 
| 470 | sub SetContrepchar | 
| 471 | { | 
| 472 | $contrepchar = shift; | 
| 473 | Debug("Setting line continuation replacement character to <".$contrepchar.">", 2); | 
| 474 | } | 
| 475 |  | 
| 476 |  | 
| 477 | ############################################################################## | 
| 478 | # SetOptLineEndchar $string - sets the optional line end char to something | 
| 479 | # other than "" | 
| 480 | ############################################################################## | 
| 481 | sub SetOptLineEndchar | 
| 482 | { | 
| 483 | $optlineendchar = shift; | 
| 484 | # make sure char will not be treated as a Perl regular expression | 
| 485 | if(!$charperlre) { $optlineendchar = "\Q$optlineendchar\E"; } | 
| 486 | Debug("Setting optional line end character to <".$optlineendchar.">", 2); | 
| 487 | } | 
| 488 |  | 
| 489 |  | 
| 490 | ############################################################################## | 
| 491 | # SetEnvchar $string - sets the first char(s) of each defined environment | 
| 492 | # variable to $string - NOTE: change only takes effect when DefineEnv run | 
| 493 | ############################################################################## | 
| 494 | sub SetEnvchar | 
| 495 | { | 
| 496 | $envchar = shift; | 
| 497 | Debug("Setting environment variable prefix character to <".$envchar.">",2); | 
| 498 | } | 
| 499 |  | 
| 500 | ############################################################################## | 
| 501 | # RunProcessors $string, $calledfrom | 
| 502 | # run the current processing chain on the string | 
| 503 | # $string is the string to be processed and should be returned by the processor | 
| 504 | # $calledfrom says where the processors are called from, the choice is: | 
| 505 | # | 
| 506 | # 0 or default: Part line (from within a keyword) - if called recursively | 
| 507 | # runs all processors AFTER current processor, then continues with processing. | 
| 508 | # This is used when a keyword want to run all remaining processors on a line | 
| 509 | # before doing its keyword task. | 
| 510 | # | 
| 511 | # 1: Full line (from Parse function) - if called recursively runs all | 
| 512 | # processors BEFORE current processor, then continues with processing | 
| 513 | # | 
| 514 | # 2:  Part line (from within a keyword) - if called recursively runs all | 
| 515 | # processors BEFORE current processor, then continues with processing. | 
| 516 | # This is used when keywords are using text taken from somewhere other than | 
| 517 | # the current line,  this text needs to go through the same processors as | 
| 518 | # the current line has been through so it can "catch up" (eg: regexp.pm). | 
| 519 | # | 
| 520 | ############################################################################## | 
| 521 | my @Running; | 
| 522 | my @Currentproc; | 
| 523 | sub RunProcessors | 
| 524 | { | 
| 525 | my $string = shift; | 
| 526 | my $calledfrom = 0; | 
| 527 | if($#_ > -1) { $calledfrom = shift; } | 
| 528 | my $i; | 
| 529 |  | 
| 530 | # turn off macoprefix if in a keyword | 
| 531 | my $tmpprefix = ""; | 
| 532 | if($calledfrom != 1 && $macroprefixinkeywords == 0) { | 
| 533 | $tmpprefix = $macroprefix; | 
| 534 | $macroprefix = ""; | 
| 535 | } | 
| 536 |  | 
| 537 | # These tests are done to make RunProcessors recursion safe. | 
| 538 | # If RunProcessors is called from with a function that was itself called | 
| 539 | # by RunProcessors, then the second calling of RunProcessors will only | 
| 540 | # execute the processors before the currently running processor in the | 
| 541 | # chain. | 
| 542 | my $recursing = 0; | 
| 543 | my $firstproc = 0; | 
| 544 | my $lastproc = $#Processors; | 
| 545 | if($Running[$include_level]) { | 
| 546 | if($calledfrom == 0) { | 
| 547 | $firstproc = $Currentproc[$include_level] + 1; | 
| 548 | } | 
| 549 | else { | 
| 550 | $lastproc = $Currentproc[$include_level] - 1; | 
| 551 | } | 
| 552 | $recursing = 1; | 
| 553 | } | 
| 554 | else { $Running[$include_level] = 1; } | 
| 555 |  | 
| 556 | for($i = $firstproc; $i <= $lastproc; $i++) { | 
| 557 | if(!$recursing) { $Currentproc[$include_level] = $i; } | 
| 558 | # called from anywhere (default) | 
| 559 | if($ProcessorTypes{$Processors[$i]} == 0 || | 
| 560 | # called from keyword (part lines only - within keywords) | 
| 561 | (($calledfrom == 0 || $calledfrom == 2) && | 
| 562 | $ProcessorTypes{$Processors[$i]} == 2) || | 
| 563 | # called from Parse function (whole lines only) | 
| 564 | ($calledfrom == 1 && $ProcessorTypes{$Processors[$i]} == 1)) { | 
| 565 | # run processor | 
| 566 | #           Debug("Running processor $Processors[$i] on \"$string\"", 2); | 
| 567 | $string = $Processors[$i]->($string); | 
| 568 | } | 
| 569 | # check that no processors have been deleted (bigdef.pm) | 
| 570 | if($lastproc > $#Processors) { $lastproc = $#Processors; } | 
| 571 | } | 
| 572 |  | 
| 573 | if(!$recursing) { $Running[$include_level] = 0; } | 
| 574 |  | 
| 575 | # return macro prefix to its former glory | 
| 576 | if($calledfrom != 1 && $macroprefixinkeywords == 0) { | 
| 577 | $macroprefix = $tmpprefix; | 
| 578 | } | 
| 579 |  | 
| 580 | return $string; | 
| 581 | } | 
| 582 |  | 
| 583 | ############################################################################## | 
| 584 | # PrintProcessors | 
| 585 | # print the current processing chain | 
| 586 | ############################################################################## | 
| 587 | sub PrintProcessors | 
| 588 | { | 
| 589 | my $processor; | 
| 590 | Debug("Current processing chain:", 3); | 
| 591 | my $i = 0; | 
| 592 | foreach $processor (@Processors) { | 
| 593 | Debug($processor." type ".$ProcessorTypes{$Processors[$i]}, 3); | 
| 594 | $i++; | 
| 595 | } | 
| 596 | } | 
| 597 |  | 
| 598 | ############################################################################## | 
| 599 | # AddProcessor(function[, first[, type]]) | 
| 600 | # add a line processor to processing chain, defaults to end of chain | 
| 601 | # if "first" is set to one adds processor to start of chain | 
| 602 | ############################################################################## | 
| 603 | sub AddProcessor | 
| 604 | { | 
| 605 | my $function = shift; | 
| 606 | my $first = 0; | 
| 607 | my $type = 0; | 
| 608 | # check if flag to add processor to start of chain is set | 
| 609 | if($#_ > -1) { $first = shift; } | 
| 610 | # check if processor has a type | 
| 611 | if($#_ > -1) { $type = shift; } | 
| 612 | # adding processor to start of chasin | 
| 613 | if($first) { | 
| 614 | @Processors = reverse(@Processors); | 
| 615 | } | 
| 616 | push(@Processors, $function); | 
| 617 | if($first) { | 
| 618 | @Processors = reverse(@Processors); | 
| 619 | } | 
| 620 | $ProcessorTypes{$function} = $type; | 
| 621 | Debug("Added processor ".$function." of type ".$type, 2); | 
| 622 | if($debug > 1) { PrintProcessors(); } | 
| 623 | } | 
| 624 |  | 
| 625 | ############################################################################## | 
| 626 | # AddProcessorAfter(function, processor[, type]) | 
| 627 | # add a line processor to processing chain immediately after an existing | 
| 628 | # processor, if existing processor not found, new processor is added to | 
| 629 | # end of chain | 
| 630 | ############################################################################## | 
| 631 | sub AddProcessorAfter | 
| 632 | { | 
| 633 | my $function = shift; | 
| 634 | my $existing = shift; | 
| 635 | my $type = 0; | 
| 636 | # check if processor has a type | 
| 637 | if($#_ > -1) { $type = shift; } | 
| 638 | my $i = 0; | 
| 639 | my $found = 0; | 
| 640 | my @CurrentProcessors = @Processors; | 
| 641 | my $processor; | 
| 642 | # reset processing chain | 
| 643 | @Processors = (); | 
| 644 | foreach $processor (@CurrentProcessors) { | 
| 645 | push(@Processors, $processor); | 
| 646 | if(!$found) { | 
| 647 | # check done as regular expression for greater flexibility | 
| 648 | if($processor =~ /$existing/) { | 
| 649 | push(@Processors, $function); | 
| 650 | $found = 1; | 
| 651 | } | 
| 652 | } | 
| 653 | } | 
| 654 | if(!$found) { | 
| 655 | Warning("Did not find processor $existing in chain, processor $processor added to end of list"); | 
| 656 | AddProcessor($function, 0, $type); | 
| 657 | return; | 
| 658 | } | 
| 659 | $ProcessorTypes{$function} = $type; | 
| 660 | Debug("Added processor ".$function." of type ".$type, 2); | 
| 661 | if($debug > 1) { PrintProcessors(); } | 
| 662 | } | 
| 663 |  | 
| 664 | ############################################################################## | 
| 665 | # AddProcessorBefore(function, processor[, type]) | 
| 666 | # add a line processor to processing chain immediately after an existing | 
| 667 | # processor, if existing processor not found, new processor is added to | 
| 668 | # end of chain | 
| 669 | ############################################################################## | 
| 670 | sub AddProcessorBefore | 
| 671 | { | 
| 672 | my $function = shift; | 
| 673 | my $existing = shift; | 
| 674 | my $type = 0; | 
| 675 | # check if processor has a type | 
| 676 | if($#_ > -1) { $type = shift; } | 
| 677 | my $i = 0; | 
| 678 | my $found = 0; | 
| 679 | my @CurrentProcessors = @Processors; | 
| 680 | my $processor; | 
| 681 | # reset processing chain | 
| 682 | @Processors = (); | 
| 683 | foreach $processor (@CurrentProcessors) { | 
| 684 | if(!$found) { | 
| 685 | # check done as regular expression for greater flexibility | 
| 686 | if($processor =~ /$existing/) { | 
| 687 | push(@Processors,$function); | 
| 688 | $found = 1; | 
| 689 | } | 
| 690 | } | 
| 691 | push(@Processors, $processor); | 
| 692 | } | 
| 693 | if(!$found) { | 
| 694 | Warning("Did not find processor $existing in chain, processor $processor added to start of list"); | 
| 695 | AddProcessor($function, 1, $type); | 
| 696 | return; | 
| 697 | } | 
| 698 | $ProcessorTypes{$function} = $type; | 
| 699 | Debug("Added processor ".$function." of type ".$type, 2); | 
| 700 | if($debug > 1) { PrintProcessors(); } | 
| 701 | } | 
| 702 |  | 
| 703 | ############################################################################## | 
| 704 | # RemoveProcessor(function) | 
| 705 | # remove a processor name "function" from list | 
| 706 | ############################################################################## | 
| 707 | sub RemoveProcessor | 
| 708 | { | 
| 709 | my $function = shift; | 
| 710 | my $i = 0; | 
| 711 | # find function | 
| 712 | while($i <= $#Processors && $Processors[$i] ne $function) { $i++; } | 
| 713 | # check function found | 
| 714 | if($i > $#Processors) { | 
| 715 | Warning("Attempt to remove function ".$function. | 
| 716 | " which does not exist"); | 
| 717 | return; | 
| 718 | } | 
| 719 | # remove function | 
| 720 | for(; $i<$#Processors; $i++) { | 
| 721 | $Processors[$i] = $Processors[$i+1]; | 
| 722 | } | 
| 723 | pop(@Processors); | 
| 724 | delete($ProcessorTypes{$function}); | 
| 725 | Debug("Removed processor ".$function, 2); | 
| 726 | PrintProcessors(); | 
| 727 | } | 
| 728 |  | 
| 729 |  | 
| 730 | ############################################################################## | 
| 731 | # Add a function to run each time a base file is opened | 
| 732 | ############################################################################## | 
| 733 | sub AddOpenInputFunc | 
| 734 | { | 
| 735 | my $func = shift; | 
| 736 | push(@OpenInputFuncs, $func); | 
| 737 | } | 
| 738 |  | 
| 739 | ############################################################################## | 
| 740 | # Add a function to run each time a base file is closed | 
| 741 | ############################################################################## | 
| 742 | sub AddCloseInputFunc | 
| 743 | { | 
| 744 | my $func = shift; | 
| 745 | push(@CloseInputFuncs, $func); | 
| 746 | } | 
| 747 |  | 
| 748 | ############################################################################## | 
| 749 | # Add a function to run each time a base file is opened | 
| 750 | ############################################################################## | 
| 751 | sub AddOpenOutputFunc | 
| 752 | { | 
| 753 | my $func = shift; | 
| 754 | push(@OpenOutputFuncs, $func); | 
| 755 | } | 
| 756 |  | 
| 757 | ############################################################################## | 
| 758 | # Add a function to run each time a base file is closed | 
| 759 | ############################################################################## | 
| 760 | sub AddCloseOutputFunc | 
| 761 | { | 
| 762 | my $func = shift; | 
| 763 | push(@CloseOutputFuncs, $func); | 
| 764 | } | 
| 765 |  | 
| 766 |  | 
| 767 | ############################################################################## | 
| 768 | # AddKeyword(keyword, function) | 
| 769 | # Define a new keyword, when keyword (preceded by keyword char) is found, | 
| 770 | # function is run on the remainder of the line. | 
| 771 | ############################################################################## | 
| 772 | sub AddKeyword | 
| 773 | { | 
| 774 | my $keyword = shift; | 
| 775 | my $function = shift; | 
| 776 | $Keywords{$keyword} = $function; | 
| 777 | Debug("Added keyword ".$keyword." which runs ".$function, 2); | 
| 778 | } | 
| 779 |  | 
| 780 |  | 
| 781 | ############################################################################## | 
| 782 | # RemoveKeyword(keyword) | 
| 783 | # Keyword is deleted from list, all occurrences of keyword found in | 
| 784 | # document are ignored. | 
| 785 | ############################################################################## | 
| 786 | sub RemoveKeyword | 
| 787 | { | 
| 788 | my $keyword = shift; | 
| 789 | delete $Keywords{$keyword}; | 
| 790 | # sort keywords index into reverse order, this ensures #if[n]def comes | 
| 791 | # before #if when comparing input with keywords | 
| 792 | Debug("Removed keyword ".$keyword, 2); | 
| 793 | } | 
| 794 |  | 
| 795 |  | 
| 796 | ############################################################################## | 
| 797 | # RemoveAllKeywords - removes all current keywords. | 
| 798 | ############################################################################## | 
| 799 | sub RemoveAllKeywords | 
| 800 | { | 
| 801 | %Keywords = (); | 
| 802 | Debug("Removed all current keywords", 2); | 
| 803 | } | 
| 804 |  | 
| 805 |  | 
| 806 | ############################################################################## | 
| 807 | # AddIfword - adds a keyword to ifword hash | 
| 808 | ############################################################################## | 
| 809 | sub AddIfword | 
| 810 | { | 
| 811 | my $ifword = shift; | 
| 812 | $Ifwords{$ifword} = ''; | 
| 813 | Debug("Added Ifword: ".$ifword, 2); | 
| 814 | } | 
| 815 |  | 
| 816 | ############################################################################## | 
| 817 | # RemoveIfword - removes a keyword from ifword hash | 
| 818 | ############################################################################## | 
| 819 | sub RemoveIfword | 
| 820 | { | 
| 821 | my $ifword = shift; | 
| 822 | delete $Ifwords{$ifword}; | 
| 823 | Debug("Removed Ifword: ".$ifword, 2); | 
| 824 | } | 
| 825 |  | 
| 826 | ############################################################################## | 
| 827 | # AddElseword - adds a keyword to elseword hash | 
| 828 | ############################################################################## | 
| 829 | sub AddElseword | 
| 830 | { | 
| 831 | my $elseword = shift; | 
| 832 | $Elsewords{$elseword} = ''; | 
| 833 | Debug("Added Elseword: ".$elseword, 2); | 
| 834 | } | 
| 835 |  | 
| 836 | ############################################################################## | 
| 837 | # RemoveElseword - removes a keyword from elseword hash | 
| 838 | ############################################################################## | 
| 839 | sub RemoveElseword | 
| 840 | { | 
| 841 | my $elseword = shift; | 
| 842 | delete $Elsewords{$elseword}; | 
| 843 | Debug("Removed Elseword: ".$elseword, 2); | 
| 844 | } | 
| 845 |  | 
| 846 | ############################################################################## | 
| 847 | # AddEndifword - adds a keyword to endifword hash | 
| 848 | ############################################################################## | 
| 849 | sub AddEndifword | 
| 850 | { | 
| 851 | my $endifword = shift; | 
| 852 | $Endifwords{$endifword} = ''; | 
| 853 | Debug("Added Endifword: ".$endifword, 2); | 
| 854 | } | 
| 855 |  | 
| 856 | ############################################################################## | 
| 857 | # RemoveEndifword - removes a keyword from endifword hash | 
| 858 | ############################################################################## | 
| 859 | sub RemoveEndifword | 
| 860 | { | 
| 861 | my $endifword = shift; | 
| 862 | delete $Endifwords{$endifword}; | 
| 863 | Debug("Removed Endifword: ".$endifword, 2); | 
| 864 | } | 
| 865 |  | 
| 866 |  | 
| 867 | ############################################################################## | 
| 868 | # AddIncludePath - adds another include path to the list | 
| 869 | ############################################################################## | 
| 870 | sub AddIncludePath | 
| 871 | { | 
| 872 | my $path = shift; | 
| 873 | push(@IncludePaths, $path); | 
| 874 | Debug("Added include path: \"".$path."\"", 2); | 
| 875 | } | 
| 876 |  | 
| 877 |  | 
| 878 | ############################################################################## | 
| 879 | # AddModulePath - adds another module search path to the list | 
| 880 | ############################################################################## | 
| 881 | sub AddModulePath | 
| 882 | { | 
| 883 | my $path = shift; | 
| 884 | push(@INC, $path); | 
| 885 | Debug("Added module path: \"".$path."\"", 2); | 
| 886 | } | 
| 887 |  | 
| 888 |  | 
| 889 | # set if file being written to has same name as input file | 
| 890 | my $same_file = ""; | 
| 891 |  | 
| 892 | ############################################################################## | 
| 893 | # OpenOutputFile - opens the output file | 
| 894 | ############################################################################## | 
| 895 | sub OpenOutputFile | 
| 896 | { | 
| 897 | $outputfile = shift; | 
| 898 | Debug("Output file: ".$outputfile, 1); | 
| 899 |  | 
| 900 | # check for outputfile name, if not specified use STDOUT | 
| 901 | if($outputfile eq "") { $outputfile = "-"; } | 
| 902 |  | 
| 903 | # output is not stdout and file with that name already exists | 
| 904 | if($outputfile ne "-" && FileExists($outputfile) ) { | 
| 905 | $same_file = $outputfile; | 
| 906 | # paranoid: check file is writable and normal file | 
| 907 | if(-w $outputfile && -f $outputfile) { | 
| 908 | $outputfile = $outputfile.".fpp".$$; | 
| 909 | my $i=0; # paranoid: check temp file does not exist | 
| 910 | while(FileExists($outputfile)) { | 
| 911 | $outputfile = $outputfile.$i; | 
| 912 | $i++; | 
| 913 | if($i >= 10) { Error("Cound not get temp filename"); } | 
| 914 | } | 
| 915 | } | 
| 916 | else { | 
| 917 | Error("Cannot read or write to ".$outputfile); | 
| 918 | } | 
| 919 | } | 
| 920 | if(!open(OUTPUT, ">".$outputfile)) { | 
| 921 | Error("Cannot open output file: ".$outputfile); | 
| 922 | } | 
| 923 | # run any open functions | 
| 924 | my $func; | 
| 925 | foreach $func (@OpenOutputFuncs) { $func->(); } | 
| 926 | } | 
| 927 |  | 
| 928 |  | 
| 929 | ############################################################################## | 
| 930 | # CloseOutputFile - close the output file | 
| 931 | ############################################################################## | 
| 932 | sub CloseOutputFile | 
| 933 | { | 
| 934 | # run any close functions | 
| 935 | my $func; | 
| 936 | foreach $func (@CloseOutputFuncs) { $func->(); } | 
| 937 | close(OUTPUT); | 
| 938 |  | 
| 939 | # if input and output have same name, rename output to input now | 
| 940 | if($same_file ne "") { | 
| 941 | if(rename($same_file, $same_file."~") == -1) { | 
| 942 | Error("Could not rename ".$same_file." ".$same_file."~"); | 
| 943 | } | 
| 944 | if(rename($outputfile, $same_file) == -1) { | 
| 945 | Error("Could not rename ".$outputfile." ".$same_file); | 
| 946 | } | 
| 947 | } | 
| 948 | # reset same_file | 
| 949 | $same_file = ""; | 
| 950 | } | 
| 951 |  | 
| 952 |  | 
| 953 | ############################################################################## | 
| 954 | # ChangeOutputFile - change the output file | 
| 955 | ############################################################################## | 
| 956 | sub ChangeOutputFile | 
| 957 | { | 
| 958 | CloseOutputFile(); | 
| 959 | $outputfile = shift; | 
| 960 | OpenOutputFile($outputfile); | 
| 961 | } | 
| 962 |  | 
| 963 |  | 
| 964 | ############################################################################## | 
| 965 | # AddInputFile - adds another input file to the list | 
| 966 | ############################################################################## | 
| 967 | sub AddInputFile | 
| 968 | { | 
| 969 | my $file = shift; | 
| 970 | push(@Inputfiles, $file); | 
| 971 | Debug("Added input file: \"".$file."\"", 2); | 
| 972 | } | 
| 973 |  | 
| 974 |  | 
| 975 | ############################################################################## | 
| 976 | # UseModule(module) | 
| 977 | # Module "module.pm" is used, "module.pm" can be any perl module and can use | 
| 978 | # or replace any of the functions in this package | 
| 979 | ############################################################################## | 
| 980 | sub UseModule | 
| 981 | { | 
| 982 | my $module = shift; | 
| 983 | Debug("Loading module ".$module, 1); | 
| 984 | require $module; | 
| 985 | if($@) { Error($@); } | 
| 986 | } | 
| 987 |  | 
| 988 |  | 
| 989 | ############################################################################## | 
| 990 | # find end of next word in $sline, assumes leading whitespace removed | 
| 991 | ############################################################################## | 
| 992 | sub GetNextWordEnd | 
| 993 | { | 
| 994 | my $sline = shift; | 
| 995 | # check for whitespace in this string | 
| 996 | if($sline =~ /\s/) { | 
| 997 | # return length of everything up to first whitespace | 
| 998 | return length($`); | 
| 999 | } | 
| 1000 | # whitespace not found, return length of the whole string | 
| 1001 | return length($sline); | 
| 1002 | } | 
| 1003 |  | 
| 1004 |  | 
| 1005 | ############################################################################## | 
| 1006 | # Print current table of defines - used for debugging | 
| 1007 | ############################################################################## | 
| 1008 | sub PrintDefines | 
| 1009 | { | 
| 1010 | my $define; | 
| 1011 | Debug("Current ".$keywordchar."define's:", 3); | 
| 1012 | foreach $define (keys(%Defines)) { | 
| 1013 | Debug(" macro:\"".$define."\", definition:\"".$Defines{$define}."\"",3); | 
| 1014 | } | 
| 1015 | } | 
| 1016 |  | 
| 1017 |  | 
| 1018 | ############################################################################## | 
| 1019 | # DefineEnv - define's all environment variables to macros, each prefixed | 
| 1020 | # by $envchar | 
| 1021 | ############################################################################## | 
| 1022 | sub DefineEnv | 
| 1023 | { | 
| 1024 | my $macro; | 
| 1025 | Debug("Defining environment variables as macros", 2); | 
| 1026 | foreach $macro (keys(%ENV)) { | 
| 1027 | Define($envchar.$macro." ".$ENV{$macro}); | 
| 1028 | } | 
| 1029 | } | 
| 1030 |  | 
| 1031 |  | 
| 1032 | ############################################################################## | 
| 1033 | # Find out if arguments have been used with macro | 
| 1034 | ############################################################################## | 
| 1035 | sub DefineArgsUsed | 
| 1036 | { | 
| 1037 | my $string = shift; | 
| 1038 | # check '(' is first non-whitespace char after macro | 
| 1039 | if($string =~ /^\s*\(/) { | 
| 1040 | return 1; | 
| 1041 | } | 
| 1042 | return 0; | 
| 1043 | } | 
| 1044 |  | 
| 1045 |  | 
| 1046 | ############################################################################## | 
| 1047 | # ParseArgs($string) -  find the arguments in a string of form | 
| 1048 | # (arg1, arg2, arg3...) trailing chars | 
| 1049 | # or | 
| 1050 | # arg1, arg2, arg3... | 
| 1051 | ############################################################################## | 
| 1052 | sub ParseArgs | 
| 1053 | { | 
| 1054 | my $string = shift; | 
| 1055 | $string = CleanStart($string); | 
| 1056 | my @Chars; | 
| 1057 | my $char; | 
| 1058 | # split string into chars (can't use split coz it deletes \n at end) | 
| 1059 | for($char=0; $char<length($string); $char++) { | 
| 1060 | push(@Chars, substr($string, $char, 1)); | 
| 1061 | } | 
| 1062 | my @Args;    # list of Args | 
| 1063 | my $arg = ""; | 
| 1064 | my @Endchar; | 
| 1065 | # special characters - no processing is done between character pairs | 
| 1066 | my %SpecialChars = ('(' => ')', '"' => '"', '\'' => '\''); | 
| 1067 | my $s = -1;  # start of chars | 
| 1068 | my $backslash = 0; | 
| 1069 | # number of special char pairs to allow | 
| 1070 | my $pairs = 1; | 
| 1071 |  | 
| 1072 | # deal with first '(' if there (ie func(args) rather than func args) | 
| 1073 | if($#Chars >= 0 && $Chars[0] eq '(') { | 
| 1074 | push(@Endchar, ')'); | 
| 1075 | $Chars[0] = ''; | 
| 1076 | $s++; | 
| 1077 | $pairs++; # ignore this pair of special char pairs | 
| 1078 | } | 
| 1079 |  | 
| 1080 | # replace args with their values | 
| 1081 | foreach $char (@Chars) { | 
| 1082 | # deal with end of special chars, ),",' etc. | 
| 1083 | if($#Endchar > -1 && $char eq $Endchar[$#Endchar])  { | 
| 1084 | # if char before this was a backslash, ignore this char | 
| 1085 | if($backslash) { | 
| 1086 | chop($arg); # delete backslash from string | 
| 1087 | } | 
| 1088 | else { | 
| 1089 | # pop end char of list and reduce pairs if its a bracket | 
| 1090 | if(pop(@Endchar) eq ')') { $pairs--; } | 
| 1091 | } | 
| 1092 | } | 
| 1093 | # deal with start of special chars | 
| 1094 | elsif(exists($SpecialChars{$char}))  { | 
| 1095 | # if char before this was a backslash, ignore this char | 
| 1096 | if($backslash) { | 
| 1097 | chop($arg); # delete backslash from string | 
| 1098 | } | 
| 1099 | # only start new pair if not already in special char pair | 
| 1100 | # (not including main args brackets of course) | 
| 1101 | elsif($#Endchar < $pairs-1) { | 
| 1102 | push(@Endchar, $SpecialChars{$char}); | 
| 1103 | # need to treat brackets differently for macros within | 
| 1104 | # macros "this(that(tother)))", otherwise lose track of ()'s | 
| 1105 | if($char eq '(') { $pairs++; } | 
| 1106 | } | 
| 1107 | } | 
| 1108 | # deal with ',', add arg to list and start search for next one | 
| 1109 | elsif($#Endchar == $s && $char eq ',') { | 
| 1110 | # if char before this was a backslash, ignore this char | 
| 1111 | if($backslash) { | 
| 1112 | chop($arg); # delete backslash from string | 
| 1113 | } | 
| 1114 | else { | 
| 1115 | push(@Args, CleanStart($arg)); | 
| 1116 | $char = ''; | 
| 1117 | $arg = ""; | 
| 1118 | next; | 
| 1119 | } | 
| 1120 | } | 
| 1121 | # deal \\ with an escaping \ ie. \" or \, or \\ | 
| 1122 | if($char eq '\\') { | 
| 1123 | if($backslash) { # found \\ | 
| 1124 | $backslash = 0; # second backslash ignored | 
| 1125 | chop($arg); # delete backslash from string | 
| 1126 | } | 
| 1127 | else{$backslash = 1;} | 
| 1128 | } | 
| 1129 | elsif($backslash) { $backslash = 0; } | 
| 1130 | # check for end of args string | 
| 1131 | if($#Endchar < $s) { | 
| 1132 | push(@Args, CleanStart($arg)); | 
| 1133 | $char = ''; | 
| 1134 | # put remainder of string back together | 
| 1135 | $arg = join('', @Chars); | 
| 1136 | last; | 
| 1137 | } | 
| 1138 | $arg = $arg.$char; # add char to current arg | 
| 1139 | $char = '';        # set char to null | 
| 1140 | } | 
| 1141 |  | 
| 1142 | # deal with last arg or string following args if it exists | 
| 1143 | push(@Args, $arg); | 
| 1144 |  | 
| 1145 | return @Args; | 
| 1146 | } | 
| 1147 |  | 
| 1148 |  | 
| 1149 | ############################################################################## | 
| 1150 | # Find the arguments in a macro and replace them | 
| 1151 | ############################################################################## | 
| 1152 | sub FindDefineArgs | 
| 1153 | { | 
| 1154 | my $substring = shift; | 
| 1155 | my $macro = shift; | 
| 1156 |  | 
| 1157 | # get definition list for this macro | 
| 1158 | my @Argnames = split(/\,/, $DefinesArgs{$macro}); | 
| 1159 |  | 
| 1160 | # check to see if macro can have any number of arguments (last arg ...) | 
| 1161 | my $anyargs = ($#Argnames >= 0 && $Argnames[$#Argnames] =~ /\.\.\.\Z/o); | 
| 1162 |  | 
| 1163 | # get arguments passed to this macro | 
| 1164 | my @Argvals = ParseArgs($substring); | 
| 1165 | # everything following macro args should be returned as tail | 
| 1166 | my $tail = pop(@Argvals); | 
| 1167 |  | 
| 1168 | # check the right number of args have been passed, should be all args | 
| 1169 | # present plus string at end of args (assuming macro cannot have any number | 
| 1170 | # of arguments) | 
| 1171 | if(!$anyargs && $#Argvals != $#Argnames) { | 
| 1172 | # show warning if wrong args (unless macro should have zero args and | 
| 1173 | # 1 arg provided which is blank space | 
| 1174 | if(!($#Argnames == -1 && $#Argvals == 0 && $Argvals[0] =~ /\A\s*\Z/)) { | 
| 1175 | Warning("Macro \'".$macro."\' used with ".$#Argvals. | 
| 1176 | " args, expected ".($#Argnames+1)); | 
| 1177 | } | 
| 1178 | # delete all excess args | 
| 1179 | while($#Argvals > $#Argnames) { pop(@Argvals); } | 
| 1180 | } | 
| 1181 | # make all missing args blanks | 
| 1182 | while($#Argvals < $#Argnames) { push(@Argvals, ""); } | 
| 1183 |  | 
| 1184 | return (@Argvals, $tail); | 
| 1185 | } | 
| 1186 |  | 
| 1187 |  | 
| 1188 | ############################################################################## | 
| 1189 | # FunctionMacro: used with functions to inform a module which macro | 
| 1190 | # was being replaced when the function was called - used in bigfunc.pm | 
| 1191 | ############################################################################## | 
| 1192 | my $functionmacro = ""; | 
| 1193 | sub FunctionMacro | 
| 1194 | { | 
| 1195 | return $functionmacro; | 
| 1196 | } | 
| 1197 |  | 
| 1198 |  | 
| 1199 | ############################################################################## | 
| 1200 | # Replace all defined macro's arguments with their values | 
| 1201 | # Inputs: | 
| 1202 | # $macro  = the macro to be replaces | 
| 1203 | # $string = the string following the occurrence of macro | 
| 1204 | ############################################################################## | 
| 1205 | sub ReplaceDefineArgs | 
| 1206 | { | 
| 1207 | my ($string, $tail, %Used) = @_; | 
| 1208 | # check if args used, if not do nothing | 
| 1209 | if(DefineArgsUsed($tail)) { | 
| 1210 | my $macro = $string; | 
| 1211 | # get arguments following macro | 
| 1212 | my @Argvals = FindDefineArgs($tail, $macro); | 
| 1213 | $tail = pop(@Argvals); # tail returned as last element | 
| 1214 |  | 
| 1215 | my @Argnames = split(/\,/, $DefinesArgs{$macro}); | 
| 1216 | my ($i, $j); | 
| 1217 |  | 
| 1218 | # replace previous macro with defn + args | 
| 1219 | $string = $Defines{$macro}; | 
| 1220 |  | 
| 1221 | # check if macro should call a function | 
| 1222 | if(exists($DefinesFuncs{$macro})) { | 
| 1223 | # replace all macros in argument list | 
| 1224 | for($i=0; $i<=$#Argvals; $i++) { | 
| 1225 | $Argvals[$i] = ReplaceDefines($Argvals[$i]); | 
| 1226 | } | 
| 1227 | if($debug > 1) { | 
| 1228 | my $argstring = ""; | 
| 1229 | if($#Argvals >= 0) { $argstring = join(", ", @Argvals); } | 
| 1230 | Debug("Running function $DefinesFuncs{$macro} with args (". | 
| 1231 | $argstring.")", 2); | 
| 1232 | } | 
| 1233 | # set name of macro which is being parse (needed in bigfunc.pm) | 
| 1234 | $functionmacro = $macro; | 
| 1235 | $string = $DefinesFuncs{$macro}->(@Argvals); | 
| 1236 | # don't need do anything else, return now | 
| 1237 | return $string, $tail; | 
| 1238 | } | 
| 1239 |  | 
| 1240 | # check if last arg ends in ... (allows any number of args in macro) | 
| 1241 | if($#Argnames >= 0 && $Argnames[$#Argnames] =~ s/\.\.\.\Z//o) { | 
| 1242 | # concatanate all extra args into final arg | 
| 1243 | while($#Argvals > $#Argnames) { | 
| 1244 | my $arg1 = pop(@Argvals); | 
| 1245 | my $arg2 = pop(@Argvals); | 
| 1246 | push(@Argvals, $arg2.", ".$arg1); | 
| 1247 | } | 
| 1248 | # check for ## at start of macro name in args list | 
| 1249 | if($string =~ /\#\#$Argnames[$#Argnames]/) { | 
| 1250 | # if last argument is empty remove preciding "," | 
| 1251 | if($#Argvals == $#Argnames && $Argvals[$#Argnames] eq "") { | 
| 1252 | $string =~ s/\,\s*\#\#$Argnames[$#Argnames]//g; | 
| 1253 | } | 
| 1254 | else { | 
| 1255 | $string =~ | 
| 1256 | s/\#\#$Argnames[$#Argnames]/$Argnames[$#Argnames]/g; | 
| 1257 | } | 
| 1258 | } | 
| 1259 | } | 
| 1260 |  | 
| 1261 | # to get args passed to macro to same processed level as rest of | 
| 1262 | # macro, they need to be checked for occurrences of all used macros, | 
| 1263 | # this is a nasty hack to temporarily change defines list to %Used | 
| 1264 | { | 
| 1265 | my %RealDefines = %Defines; | 
| 1266 | my $realdefmin = $defmin; | 
| 1267 | my $realdefmax = $defmax; | 
| 1268 | my %RealDefineLookup = %DefineLookup; | 
| 1269 | %Defines = %Used; | 
| 1270 | GenerateDefinesKeys(); | 
| 1271 |  | 
| 1272 | for($i=0; $i<=$#Argvals; $i++) { | 
| 1273 | $Argvals[$i] = ReplaceDefines($Argvals[$i]); | 
| 1274 | } | 
| 1275 |  | 
| 1276 | # return defines to normal | 
| 1277 | %Defines = %RealDefines; | 
| 1278 | $defmin = $realdefmin; | 
| 1279 | $defmax = $realdefmax; | 
| 1280 | %DefineLookup = %RealDefineLookup; | 
| 1281 | } | 
| 1282 |  | 
| 1283 | # The next step replaces argnames with argvals.  Once a bit of string | 
| 1284 | # has been replaced it is removed from further processing to avoid | 
| 1285 | # unwanted recursive macro replacement. | 
| 1286 | my @InString = ( $string ); # string to be replaced | 
| 1287 | my @InDone   = ( 0 );       # flag to say if string section replaced | 
| 1288 | my @OutString;              # output of string sections after each | 
| 1289 | # macro has been replaced | 
| 1290 | my @OutDone;                # output flags | 
| 1291 | my $k = 0; | 
| 1292 | for($i=0; $i<=$#Argnames; $i++) { | 
| 1293 | for($j=0; $j<=$#InString; $j++) { | 
| 1294 | if($InDone[$j] == 0) { | 
| 1295 | # replace macros and split up string so replaced part | 
| 1296 | # is flagged as done and rest is left for further | 
| 1297 | # processing | 
| 1298 | while($InString[$j] =~ /$bound$Argnames[$i]$bound/) { | 
| 1299 | $OutString[$k] = $`;            $OutDone[$k] = 0; | 
| 1300 | $k++; | 
| 1301 | $OutString[$k] = $Argvals[$i];  $OutDone[$k] = 1; | 
| 1302 | $k++; | 
| 1303 | $InString[$j] = $';     # one more quote for emacs ' | 
| 1304 | } | 
| 1305 | } | 
| 1306 | $OutString[$k] = $InString[$j];   $OutDone[$k] = $InDone[$j]; | 
| 1307 | $k++; | 
| 1308 | } | 
| 1309 | @InString = @OutString;   @InDone = @OutDone; | 
| 1310 | $k = 0; | 
| 1311 | } | 
| 1312 | # rebuild string | 
| 1313 | $string = join('', @InString); | 
| 1314 |  | 
| 1315 | Debug("Replaced \"".$macro."\" for \"".$string."\" [".$recurse_level."]", 2); | 
| 1316 | } | 
| 1317 | else { | 
| 1318 | Debug("Macro \"".$string."\" found without args, ignored", 2); | 
| 1319 | } | 
| 1320 | return ($string, $tail); | 
| 1321 | } | 
| 1322 |  | 
| 1323 |  | 
| 1324 | ############################################################################## | 
| 1325 | # When replacing macros with args, the macro and everything following the | 
| 1326 | # macro (the tail) are passed to ReplaceDefineArgs.  The function extracts | 
| 1327 | # the args from the tail and then returns the replaced macro and the new | 
| 1328 | # tail.  This function extracts the remaining part of the real tail from | 
| 1329 | # the current input string. | 
| 1330 | ############################################################################## | 
| 1331 | sub ReclaimTail | 
| 1332 | { | 
| 1333 | my ($input, $tail) = @_; | 
| 1334 | # split strings into chars and compare each one until difference found | 
| 1335 | my @Input = split(//, $input); | 
| 1336 | my @Tail  = split(//, $tail); | 
| 1337 | $tail = $input = ""; | 
| 1338 | while($#Input >= 0 && $#Tail >= 0 && $Input[$#Input] eq $Tail[$#Tail]) { | 
| 1339 | $tail = pop(@Tail).$tail; | 
| 1340 | pop(@Input); | 
| 1341 | } | 
| 1342 | while($#Input >=0) { $input = pop(@Input).$input; } | 
| 1343 | return ($input, $tail); | 
| 1344 | } | 
| 1345 |  | 
| 1346 |  | 
| 1347 | ############################################################################## | 
| 1348 | # Replace all defined macro's in a line with their value.  Recursively run | 
| 1349 | # through macros as many times as needed (to find macros within macros). | 
| 1350 | # Inputs: | 
| 1351 | # $input = string to process | 
| 1352 | # $tail  = rest of line following $string (if any), this will only be used | 
| 1353 | #          if string contains a macro with args, the args will probably be | 
| 1354 | #          at the start of the tail | 
| 1355 | # %Used  = all macros found in $string so far, these will not be checked | 
| 1356 | #          again to avoid possible recursion | 
| 1357 | # Initially just $input is passed in, other args are added for recursive calls | 
| 1358 | ############################################################################## | 
| 1359 | sub ReplaceDefines | 
| 1360 | { | 
| 1361 | my ($input, $tail, %Used) = @_; | 
| 1362 | # check for recursive macro madness (set to same level as Perl warning) | 
| 1363 | if(++$recurse_level > 97) { | 
| 1364 | $recurse_level--; | 
| 1365 | Warning("Recursive macro detected in \"".$input."\""); | 
| 1366 | if($tail) { return ($input, $tail); } | 
| 1367 | return $input; | 
| 1368 | } | 
| 1369 |  | 
| 1370 | my $out = "";   # initialise output to empty string | 
| 1371 | OUTER : while($input =~ /\S/o) { | 
| 1372 | my ($macro, $string); | 
| 1373 | my @Words; | 
| 1374 |  | 
| 1375 |  | 
| 1376 | ###################################################################### | 
| 1377 | # if macros start with prefix, skip to next prefix | 
| 1378 | ###################################################################### | 
| 1379 | if($macroprefix ne "") { | 
| 1380 | my $found = 0; | 
| 1381 | # find next potential macro in line if any | 
| 1382 | while(!$found && $input =~ /$macroprefix\S/) { | 
| 1383 | # everything before prefix | 
| 1384 | $out = $out.$`; | 
| 1385 | # reclaim first char in macro | 
| 1386 | my $match = $&; | 
| 1387 | # everything after prefix | 
| 1388 | $input = chop($match).$';  # one more quote for emacs ' | 
| 1389 | # check if first chars are in macro | 
| 1390 | if(exists($DefineLookup{substr($input, 0, $defmin)})) { | 
| 1391 | $found = 1; | 
| 1392 | } | 
| 1393 | # put prefix back onto output and carry on searching | 
| 1394 | else { $out = $out.$match; } | 
| 1395 | } | 
| 1396 | # no more macros | 
| 1397 | if(!$found) { $out = $out.$input; $input = ""; last OUTER; } | 
| 1398 | } | 
| 1399 |  | 
| 1400 |  | 
| 1401 | ###################################################################### | 
| 1402 | # replacing macros which are "words" only - quick and easy | 
| 1403 | ###################################################################### | 
| 1404 | if($bound eq '\b') { | 
| 1405 | @Words = split(/(\w+)/, $input, 2); | 
| 1406 | $out =  $out.$Words[0]; | 
| 1407 | if($#Words == 2) { $macro = $Words[1]; $input = $Words[2]; } | 
| 1408 | else             { $input = ""; last OUTER; } | 
| 1409 | } | 
| 1410 |  | 
| 1411 | ###################################################################### | 
| 1412 | # replacing all types of macro - slow and horrid | 
| 1413 | ###################################################################### | 
| 1414 | else { | 
| 1415 | # forward string to next non-whitespace char that starts a macro | 
| 1416 | while(!exists($DefineLookup{substr($input, 0, $defmin)})) { | 
| 1417 | if($input =~ /^\s/ ) { # remove preceding whitespace | 
| 1418 | @Words = split(/^(\s+)/, $input, 2); | 
| 1419 | $out = $out.$Words[1]; | 
| 1420 | $input = $Words[2]; | 
| 1421 | } | 
| 1422 | else { # skip to next char | 
| 1423 | $out = $out.substr($input, 0, 1); | 
| 1424 | $input = substr($input, 1); | 
| 1425 | } | 
| 1426 | if($input eq "") { last OUTER; } | 
| 1427 | } | 
| 1428 | # remove the longest possible potential macro (containing no | 
| 1429 | # whitespace) from the start of input | 
| 1430 | @Words = split(/(\s+)/, $input, 2); | 
| 1431 | $macro = $Words[0]; | 
| 1432 | if($#Words == 2) {$input = $Words[1].$Words[2]; } | 
| 1433 | else             {$input = ""; } | 
| 1434 | # shorten macro if too long | 
| 1435 | if(length($macro) > $defmax) { | 
| 1436 | $input = substr($macro, $defmax).$input; | 
| 1437 | $macro = substr($macro, 0, $defmax); | 
| 1438 | } | 
| 1439 | # see if a macro exists in "macro" | 
| 1440 | while(length($macro) > $defmin && | 
| 1441 | !(exists($Defines{$macro}) && !exists($Used{$macro}))) { | 
| 1442 | # chop a char off macro and try again | 
| 1443 | $input = chop($macro).$input; | 
| 1444 | } | 
| 1445 | } | 
| 1446 |  | 
| 1447 | # check if macro is at start of string and has not been used yet | 
| 1448 | if(exists($Defines{$macro}) && !exists($Used{$macro})) { | 
| 1449 | # set macro as used | 
| 1450 | $Used{$macro} = $Defines{$macro}; | 
| 1451 | # temporarily add tail to input | 
| 1452 | if($tail) { $input = $input.$tail; } | 
| 1453 | # replace macro with defn | 
| 1454 | if(CheckDefineArgs($macro)) { | 
| 1455 | ($string, $input) = ReplaceDefineArgs($macro, $input, %Used); | 
| 1456 | } | 
| 1457 | else { | 
| 1458 | $string = $Defines{$macro}; | 
| 1459 | Debug("Replaced \"".$macro."\" for \"".$string."\" [".$recurse_level."]", 2); | 
| 1460 | } | 
| 1461 |  | 
| 1462 | ($string=~ m/\#\#/) and ($string=~ s/\s*\#\#\s*//gm); | 
| 1463 |  | 
| 1464 | @Words = ReplaceDefines($string, $input, %Used); | 
| 1465 | $out = $out.$Words[0]; | 
| 1466 | if($#Words == 0) { $input = ""; } | 
| 1467 | else { | 
| 1468 | # remove space up to start of next char | 
| 1469 | if(CheckEatTrail($macro)) { $Words[1] =~ s/^[ \t]*//o; } | 
| 1470 | $input = $Words[1]; | 
| 1471 | } | 
| 1472 | delete($Used{$macro}); | 
| 1473 | # reclaim all unparsed tail | 
| 1474 | if($tail && $tail ne "") { | 
| 1475 | ($input, $tail) = ReclaimTail($input, $tail); | 
| 1476 | } | 
| 1477 | } | 
| 1478 | # macro not matched, add to output and move swiftly on | 
| 1479 | else { | 
| 1480 | if($bound eq '\b') { $out = $out.$macro; } | 
| 1481 | else { | 
| 1482 | $out = $out.substr($macro, 0, 1); | 
| 1483 | $input = substr($macro, 1).$input; | 
| 1484 | } | 
| 1485 | } | 
| 1486 | } | 
| 1487 | $recurse_level--; | 
| 1488 | # append any whitespace left in string and return it | 
| 1489 | if($tail) { return ($out.$input, $tail); } | 
| 1490 | return $out.$input; | 
| 1491 | } | 
| 1492 |  | 
| 1493 |  | 
| 1494 | ############################################################################## | 
| 1495 | # GenerateDefinesKey creates all keys and indices needed for %Defines | 
| 1496 | ############################################################################## | 
| 1497 | sub GenerateDefinesKeys | 
| 1498 | { | 
| 1499 | # find longest and shortest macro | 
| 1500 | my ($define, $length) = each %Defines; | 
| 1501 | $defmin = $defmax = length($define); | 
| 1502 | %DefineLookup = (); | 
| 1503 | foreach $define (keys(%Defines)) { | 
| 1504 | $length = length($define); | 
| 1505 | if($length > $defmax) { $defmax = $length; } | 
| 1506 | if($length < $defmin) { $defmin = $length; } | 
| 1507 | } | 
| 1508 | # regenerate lookup table of first letters | 
| 1509 | foreach $define (keys(%Defines)) { | 
| 1510 | $DefineLookup{substr($define, 0, $defmin)} = 1; | 
| 1511 | } | 
| 1512 | } | 
| 1513 |  | 
| 1514 |  | 
| 1515 | ############################################################################## | 
| 1516 | # Set a define | 
| 1517 | ############################################################################## | 
| 1518 | sub SetDefine | 
| 1519 | { | 
| 1520 | my ($macro, $value) = @_; | 
| 1521 | # add macro and value to hash table | 
| 1522 | $Defines{$macro} = $value; | 
| 1523 | # add define to keys | 
| 1524 | my $length = length($macro); | 
| 1525 | if($length < $defmin || $defmin == 0) { GenerateDefinesKeys(); } | 
| 1526 | else { | 
| 1527 | if($length > $defmax) { $defmax = $length; } | 
| 1528 | $length = substr($macro, 0, $defmin); | 
| 1529 | $DefineLookup{$length} = 1; | 
| 1530 | } | 
| 1531 | } | 
| 1532 |  | 
| 1533 |  | 
| 1534 | ############################################################################## | 
| 1535 | # Get a define without doing any macro replacement | 
| 1536 | ############################################################################## | 
| 1537 | sub GetDefine | 
| 1538 | { | 
| 1539 | my $macro = shift; | 
| 1540 | return $Defines{$macro}; | 
| 1541 | } | 
| 1542 |  | 
| 1543 |  | 
| 1544 | ############################################################################## | 
| 1545 | # Replace a define, checks if macro defined and only redefine's if it is | 
| 1546 | ############################################################################## | 
| 1547 | sub Redefine | 
| 1548 | { | 
| 1549 | my $macro = shift; | 
| 1550 | my $value = shift; | 
| 1551 | # check if defined | 
| 1552 | if(CheckDefine($macro)) { SetDefine($macro, $value); } | 
| 1553 | } | 
| 1554 |  | 
| 1555 |  | 
| 1556 | ############################################################################## | 
| 1557 | # Set a define argument list | 
| 1558 | ############################################################################## | 
| 1559 | sub SetDefineArgs | 
| 1560 | { | 
| 1561 | my $macro = shift; | 
| 1562 | my $args = shift; | 
| 1563 | # add macro args to hash table | 
| 1564 | $DefinesArgs{$macro} = $args; | 
| 1565 | } | 
| 1566 |  | 
| 1567 |  | 
| 1568 | ############################################################################## | 
| 1569 | # Set a function which should be called when a macro is found | 
| 1570 | ############################################################################## | 
| 1571 | sub SetDefineFuncs | 
| 1572 | { | 
| 1573 | my $macro = shift; | 
| 1574 | my $func = shift; | 
| 1575 | # add macro function to hash table | 
| 1576 | $DefinesFuncs{$macro} = $func; | 
| 1577 | } | 
| 1578 |  | 
| 1579 |  | 
| 1580 | ############################################################################## | 
| 1581 | # Check if a macro is defined | 
| 1582 | ############################################################################## | 
| 1583 | sub CheckDefine | 
| 1584 | { | 
| 1585 | my $macro = shift; | 
| 1586 | return exists($Defines{$macro}); | 
| 1587 | } | 
| 1588 |  | 
| 1589 |  | 
| 1590 | ############################################################################## | 
| 1591 | # Check if a macro is defined and has arguments | 
| 1592 | ############################################################################## | 
| 1593 | sub CheckDefineArgs | 
| 1594 | { | 
| 1595 | my $macro = shift; | 
| 1596 | return exists($DefinesArgs{$macro}); | 
| 1597 | } | 
| 1598 |  | 
| 1599 |  | 
| 1600 | ############################################################################## | 
| 1601 | # Check if a macro is defined and calls a function | 
| 1602 | ############################################################################## | 
| 1603 | sub CheckDefineFuncs | 
| 1604 | { | 
| 1605 | my $macro = shift; | 
| 1606 | return exists($DefinesFuncs{$macro}); | 
| 1607 | } | 
| 1608 |  | 
| 1609 |  | 
| 1610 | ############################################################################## | 
| 1611 | # Check if a macro is defined and eats trailing whitespace | 
| 1612 | ############################################################################## | 
| 1613 | sub CheckEatTrail | 
| 1614 | { | 
| 1615 | my $macro = shift; | 
| 1616 | return exists($EatTrail{$macro}); | 
| 1617 | } | 
| 1618 |  | 
| 1619 |  | 
| 1620 | ############################################################################## | 
| 1621 | # Set eat-trailing-whitespace for a macro | 
| 1622 | ############################################################################## | 
| 1623 | sub SetEatTrail | 
| 1624 | { | 
| 1625 | my $macro = shift; | 
| 1626 | $EatTrail{$macro} = 1; | 
| 1627 | } | 
| 1628 |  | 
| 1629 |  | 
| 1630 | ############################################################################## | 
| 1631 | # Test if a file exists and is readable | 
| 1632 | ############################################################################## | 
| 1633 | sub FileExists | 
| 1634 | { | 
| 1635 | my $filename = shift; | 
| 1636 | # test if file is readable and not a directory | 
| 1637 | if( !(-r $filename) || -d $filename ) { | 
| 1638 | Debug("Checking for file: ".$filename."...not found!", 2); | 
| 1639 | return 0; | 
| 1640 | } | 
| 1641 | Debug("Checking for file: ".$filename."...found!", 2); | 
| 1642 | return 1; | 
| 1643 | } | 
| 1644 |  | 
| 1645 |  | 
| 1646 | ############################################################################## | 
| 1647 | # #comment  - rest of line ignored as a comment | 
| 1648 | ############################################################################## | 
| 1649 | sub Comment | 
| 1650 | { | 
| 1651 | # nothing to be done here | 
| 1652 | Debug("Commented line", 2); | 
| 1653 | } | 
| 1654 |  | 
| 1655 |  | 
| 1656 | ############################################################################## | 
| 1657 | # Define a variable, accepted inputs: | 
| 1658 | # $macrodefn = $macro $defn - $macro associated with $defn | 
| 1659 | #              ie: #define TEST test string | 
| 1660 | #              $macro = TEST, $defn = "test string" | 
| 1661 | #              Note: $defn = rest of line after $macro | 
| 1662 | # $macrodefn = $macro - $macro defined without a defn, rest of line ignored | 
| 1663 | #              ie: #define TEST_DEFINE | 
| 1664 | #              $macro = TEST_DEFINE, $defn = "1" | 
| 1665 | ############################################################################## | 
| 1666 | sub Define | 
| 1667 | { | 
| 1668 | my $macrodefn = shift; | 
| 1669 | my $macro; | 
| 1670 | my $defn; | 
| 1671 | my $i; | 
| 1672 |  | 
| 1673 | # check there is an argument | 
| 1674 | if($macrodefn !~ /\S/o) { | 
| 1675 | Filepp::Error("define keyword used without arguments"); | 
| 1676 | } | 
| 1677 |  | 
| 1678 | # find end of macroword - assume separated by space or tab | 
| 1679 | $i = GetNextWordEnd($macrodefn); | 
| 1680 |  | 
| 1681 | # separate macro and defn (can't use split, doesn't work with '0') | 
| 1682 | $macro = substr($macrodefn, 0, $i); | 
| 1683 | $defn  = substr($macrodefn, $i); | 
| 1684 |  | 
| 1685 | # strip leading whitespace from $defn | 
| 1686 | if($defn) { | 
| 1687 | $defn =~ s/^[ \t]*//; | 
| 1688 | } | 
| 1689 | else { | 
| 1690 | $defn = ""; | 
| 1691 | } | 
| 1692 |  | 
| 1693 | # check if macro has arguments (will be a '(' in macro) | 
| 1694 | if($macro =~ /\(/) { | 
| 1695 | # split up macro, args and defn - delimiters = space, (, ), ',' | 
| 1696 | my @arglist = split(/([\s,\(,\),\,])/, $macro." ".$defn); | 
| 1697 | my $macroargs = ""; | 
| 1698 | my $arg; | 
| 1699 |  | 
| 1700 | # macro is first element in list, remove it from list | 
| 1701 | $macro = $arglist[0]; | 
| 1702 | $arglist[0] = ""; | 
| 1703 | # loop through list until ')' and find all args | 
| 1704 | foreach $arg (@arglist) { | 
| 1705 | if($arg) { | 
| 1706 | # end of arg list, leave loop | 
| 1707 | if($arg eq ")") { | 
| 1708 | $arg = ""; | 
| 1709 | last; | 
| 1710 | } | 
| 1711 | # ignore space, ',' and '(' | 
| 1712 | elsif($arg =~ /([\s,\,,\(])/) { | 
| 1713 | $arg = ""; | 
| 1714 | } | 
| 1715 | # argument found, add to ',' separated list | 
| 1716 | else { | 
| 1717 | $macroargs = $macroargs.",".$arg; | 
| 1718 | $arg = ""; | 
| 1719 | } | 
| 1720 | } | 
| 1721 | } | 
| 1722 | $macroargs = Strip($macroargs, ",", 1); | 
| 1723 | # store args | 
| 1724 | SetDefineArgs($macro, $macroargs); | 
| 1725 |  | 
| 1726 | Debug("Define: macro ".$macro." has args (".$macroargs.")", 2); | 
| 1727 | # put rest of defn back together | 
| 1728 | $defn = join('',@arglist); | 
| 1729 | $defn = CleanStart($defn); | 
| 1730 | } | 
| 1731 | # make sure macro is not being redefined and used to have args | 
| 1732 | else { | 
| 1733 | delete($DefinesArgs{$macro}); | 
| 1734 | delete($DefinesFuncs{$macro}); | 
| 1735 | } | 
| 1736 |  | 
| 1737 | # define the macro defn pair | 
| 1738 | SetDefine($macro, $defn); | 
| 1739 |  | 
| 1740 | Debug("Defined \"".$macro."\" to be \"".$defn."\"", 2); | 
| 1741 | if($debug > 2) { PrintDefines(); } | 
| 1742 | } | 
| 1743 |  | 
| 1744 |  | 
| 1745 |  | 
| 1746 | ############################################################################## | 
| 1747 | # Else, standard if[n][def]-else-endif | 
| 1748 | # usage: #else somewhere between #if[n][def] key and #endif | 
| 1749 | ############################################################################## | 
| 1750 | sub Else | 
| 1751 | { | 
| 1752 | # else always true - only ran when all preceding 'if's have failed | 
| 1753 | return 1; | 
| 1754 | } | 
| 1755 |  | 
| 1756 |  | 
| 1757 | ############################################################################## | 
| 1758 | # Endif, standard ifdef-[else]-endif | 
| 1759 | # usage: #endif somewhere after #ifdef key and optionally #else | 
| 1760 | ############################################################################## | 
| 1761 | sub Endif | 
| 1762 | { | 
| 1763 | # this always terminates an if block | 
| 1764 | return 1; | 
| 1765 | } | 
| 1766 |  | 
| 1767 |  | 
| 1768 | ############################################################################## | 
| 1769 | # If conditionally includes or ignores parts of a file based on expr | 
| 1770 | # usage: #if expr | 
| 1771 | # expr is evaluated to true(1) or false(0) and include usual ==, !=, > etc. | 
| 1772 | # style comparisons. The "defined" keyword can also be used, ie: | 
| 1773 | # #if defined MACRO || !defined(MACRO) | 
| 1774 | ############################################################################## | 
| 1775 | sub If | 
| 1776 | { | 
| 1777 | my $expr = shift; | 
| 1778 | Debug("If: parsing: \"".$expr."\"", 2); | 
| 1779 |  | 
| 1780 | # check for any "defined MACRO" tests and evaluate them | 
| 1781 | if($expr =~ /defined/) { | 
| 1782 | my $indefined = 0; | 
| 1783 |  | 
| 1784 | # split expr up into its component parts, the split is done on the | 
| 1785 | # following list of chars and strings: '!','(',')','&&','||', space | 
| 1786 | my @Exprs = split(/([\s,\!,\(,\)]|\&\&|\|\|)/, $expr); | 
| 1787 |  | 
| 1788 | # search through parts for "defined" keyword and check if macros | 
| 1789 | # are defined | 
| 1790 | foreach $expr (@Exprs) { | 
| 1791 | if($indefined == 1) { | 
| 1792 | # previously found a defined keyword, check if next word | 
| 1793 | # could be the macro to test for (not any of the listed chars) | 
| 1794 | if($expr && $expr !~ /([\s,\!,\(,\)]|\&\&|\|\|)/) { | 
| 1795 | # replace macro with 0 or 1 depending if it is defined | 
| 1796 | Debug("If: testing if \"".$expr."\" defined...", 2); | 
| 1797 | if(CheckDefine($expr)) { | 
| 1798 | $expr = 1; | 
| 1799 | Debug("If: defined", 2); | 
| 1800 | } | 
| 1801 | else { | 
| 1802 | $expr = 0; | 
| 1803 | Debug("If: NOT defined", 2); | 
| 1804 | } | 
| 1805 | $indefined = 0; | 
| 1806 | } | 
| 1807 | } | 
| 1808 | elsif($expr eq "defined") { | 
| 1809 | # get rid of defined keyword | 
| 1810 | $expr = ""; | 
| 1811 | # search for next macro following "defined" | 
| 1812 | $indefined = 1; | 
| 1813 | } | 
| 1814 | } | 
| 1815 |  | 
| 1816 | # put full expr string back together | 
| 1817 | my $newexpr = join('',@Exprs); | 
| 1818 | $expr = $newexpr; | 
| 1819 | } | 
| 1820 |  | 
| 1821 | # pass parsed line though processors | 
| 1822 | $expr = RunProcessors($expr); | 
| 1823 |  | 
| 1824 | # evaluate line and return result (1 = true) | 
| 1825 | Debug("If: evaluating \"".$expr."\"", 2); | 
| 1826 | my $result = eval($expr); | 
| 1827 | # check if statement is valid | 
| 1828 | if(!defined($result)) { Warning($@); } | 
| 1829 | elsif($result) { | 
| 1830 | Debug("If: \"".$expr."\" true", 1); | 
| 1831 | return 1; | 
| 1832 | } | 
| 1833 | Debug("If: \"".$expr."\" false", 1); | 
| 1834 | return 0; | 
| 1835 | } | 
| 1836 |  | 
| 1837 |  | 
| 1838 | ############################################################################## | 
| 1839 | # Elif equivalent to "else if".  Placed between #if[n][def] and #endif, | 
| 1840 | # equivalent to nesting #if's | 
| 1841 | ############################################################################## | 
| 1842 | sub Elif | 
| 1843 | { | 
| 1844 | my $input = shift; | 
| 1845 | return If($input); | 
| 1846 | } | 
| 1847 |  | 
| 1848 |  | 
| 1849 | ############################################################################## | 
| 1850 | # Ifdef conditionally includes or ignores parts of a file based on macro, | 
| 1851 | # usage: #ifdef MACRO | 
| 1852 | # if macro has been previously #define'd everything following the | 
| 1853 | # #ifdef will be included, else it will be ignored until #else or #endif | 
| 1854 | ############################################################################## | 
| 1855 | sub Ifdef | 
| 1856 | { | 
| 1857 | my $macro = shift; | 
| 1858 |  | 
| 1859 | # separate macro from any trailing garbage | 
| 1860 | $macro = substr($macro, 0, GetNextWordEnd($macro)); | 
| 1861 |  | 
| 1862 | # check if macro defined - if not set to be #ifdef'ed out | 
| 1863 | if(CheckDefine($macro)) { | 
| 1864 | Debug("Ifdef: ".$macro." defined", 1); | 
| 1865 | return 1; | 
| 1866 | } | 
| 1867 | Debug("Ifdef: ".$macro." not defined", 1); | 
| 1868 | return 0; | 
| 1869 | } | 
| 1870 |  | 
| 1871 |  | 
| 1872 | ############################################################################## | 
| 1873 | # Ifndef conditionally includes or ignores parts of a file based on macro, | 
| 1874 | # usage: #ifndef MACRO | 
| 1875 | # if macro has been previously #define'd everything following the | 
| 1876 | # #ifndef will be ignored, else it will be included until #else or #endif | 
| 1877 | ############################################################################## | 
| 1878 | sub Ifndef | 
| 1879 | { | 
| 1880 | my $macro = shift; | 
| 1881 |  | 
| 1882 | # separate macro from any trailing garbage | 
| 1883 | $macro = substr($macro, 0, GetNextWordEnd($macro)); | 
| 1884 |  | 
| 1885 | # check if macro defined - if not set to be #ifdef'ed out | 
| 1886 | if(CheckDefine($macro)) { | 
| 1887 | Debug("Ifndef: ".$macro." defined", 1); | 
| 1888 | return 0; | 
| 1889 | } | 
| 1890 | Debug("Ifndef: ".$macro." not defined", 1); | 
| 1891 | return 1; | 
| 1892 | } | 
| 1893 |  | 
| 1894 |  | 
| 1895 | ############################################################################## | 
| 1896 | # Parses all macros from file, but discards all other output | 
| 1897 | ############################################################################## | 
| 1898 | sub IncludeMacros | 
| 1899 | { | 
| 1900 | my $file = shift; | 
| 1901 | my $currentoutput = $output; | 
| 1902 | SetOutput(0); | 
| 1903 | Parse($file); | 
| 1904 | SetOutput($currentoutput); | 
| 1905 | } | 
| 1906 |  | 
| 1907 |  | 
| 1908 | ############################################################################## | 
| 1909 | # Include $filename in output file, format: | 
| 1910 | # #include "filename" - local include file, ie. in same directory, try -Ipath | 
| 1911 | #                       also if not not found in current directory | 
| 1912 | # #include <filename> - system include file, use -Ipath | 
| 1913 | ############################################################################## | 
| 1914 | sub Include | 
| 1915 | { | 
| 1916 | my $input = shift; | 
| 1917 | my $filename = $input; | 
| 1918 | my $fullname; | 
| 1919 | my $sysinclude = 0; | 
| 1920 | my $found = 0; | 
| 1921 | my $i; | 
| 1922 |  | 
| 1923 |  | 
| 1924 | # check for recursive includes (level set to same as Perl recurse warn) | 
| 1925 | if($include_level >= 98) { | 
| 1926 | Warning("Include recursion too deep - skipping \"".$filename."\"\n"); | 
| 1927 | return; | 
| 1928 | } | 
| 1929 |  | 
| 1930 | # replace any defined values in the include line | 
| 1931 | $filename = RunProcessors($filename); | 
| 1932 |  | 
| 1933 | # check if it is a system include file (#include <filename>) or a local | 
| 1934 | # include file (#include "filename") | 
| 1935 | if(substr($filename, 0, 1) eq "<") { | 
| 1936 | $sysinclude = 1; | 
| 1937 | # remove <> from filename | 
| 1938 | $filename = substr($filename, 1); | 
| 1939 | ($filename) = split(/\>/, $filename, 2); | 
| 1940 | } | 
| 1941 | elsif(substr($filename, 0, 1) eq "\"") { | 
| 1942 | # remove double quotes from filename | 
| 1943 | $filename = substr($filename, 1); | 
| 1944 | ($filename) = split(/\"/, $filename, 2); | 
| 1945 | } | 
| 1946 | # else assume filename given without "" or <>, naughty but allowed | 
| 1947 |  | 
| 1948 | #if skipSysInclude option is turned on, skip current file | 
| 1949 | if ($skipSysInclude && $sysinclude) { | 
| 1950 | return; | 
| 1951 | } | 
| 1952 |  | 
| 1953 | # check for file in current directory | 
| 1954 | if($sysinclude == 0) { | 
| 1955 | # get name of directory base file is in | 
| 1956 | my $dir = ""; | 
| 1957 | if($file =~ /\//) { | 
| 1958 | my @Dirs = split(/(\/)/, $file); | 
| 1959 | for($i=0; $i<$#Dirs; $i++) { | 
| 1960 | $dir = $dir.$Dirs[$i]; | 
| 1961 | } | 
| 1962 | } | 
| 1963 | if(FileExists($dir.$filename)) { | 
| 1964 | $fullname = $dir.$filename; | 
| 1965 | $found = 1; | 
| 1966 | } | 
| 1967 | } | 
| 1968 |  | 
| 1969 | # search for file in include paths, first path on command line first | 
| 1970 | $i = 0; | 
| 1971 | while($found == 0 && $i <= $#IncludePaths) { | 
| 1972 | $fullname = $IncludePaths[$i]."/".$filename; | 
| 1973 | if(FileExists($fullname)) { $found = 1; } | 
| 1974 | $i++; | 
| 1975 | } | 
| 1976 |  | 
| 1977 | # include file if found, error if not | 
| 1978 | if($found == 1) { | 
| 1979 | Debug("Including file: \"".$fullname."\"", 1); | 
| 1980 |  | 
| 1981 | #if $filename is already visited, just return | 
| 1982 | if (IsVisited($fullname)){ | 
| 1983 | return; | 
| 1984 | } else { | 
| 1985 | # recursively call Parse | 
| 1986 | print " " . $fullname . " \\\n"; | 
| 1987 | Parse($fullname); | 
| 1988 | } | 
| 1989 | } | 
| 1990 | else { | 
| 1991 | Warning("Include file \"".$filename."\" not found", 1); | 
| 1992 | } | 
| 1993 | } | 
| 1994 |  | 
| 1995 |  | 
| 1996 |  | 
| 1997 | ############################################################################## | 
| 1998 | # Pragma filepp Function Args | 
| 1999 | # Pragma executes a filepp function, everything following the function name | 
| 2000 | # is passed as arguments to the function. | 
| 2001 | # The format is: | 
| 2002 | # #pragma filepp function args... | 
| 2003 | # If pragma is not followed by "filepp", it is ignored. | 
| 2004 | ############################################################################## | 
| 2005 | sub Pragma | 
| 2006 | { | 
| 2007 | my $input = shift; | 
| 2008 |  | 
| 2009 | # check for "filepp" in string | 
| 2010 | if($input =~ /^filepp\b/) { | 
| 2011 | my ($function, $args); | 
| 2012 | ($input, $function, $args) = split(/\s/, $input, 3); | 
| 2013 | if($function) { | 
| 2014 | if(!$args) { $args = ""; } | 
| 2015 | if($safe_mode) { | 
| 2016 | Debug("Safe mode enabled, NOT running: ".$function."(".$args.")", 1); | 
| 2017 | } | 
| 2018 | else { | 
| 2019 | my @Args = ParseArgs($args); | 
| 2020 | Debug("Running function: ".$function."(".$args.")", 1); | 
| 2021 | $function->(@Args); | 
| 2022 | } | 
| 2023 | } | 
| 2024 | } | 
| 2025 | } | 
| 2026 |  | 
| 2027 |  | 
| 2028 | ############################################################################## | 
| 2029 | # Turn normal output on/off (does not affect any output produced by keywords) | 
| 2030 | # 1 = on, 0 = off | 
| 2031 | ############################################################################## | 
| 2032 | sub SetOutput | 
| 2033 | { | 
| 2034 | $output = shift; | 
| 2035 | Debug("Output set to ".$output, 2); | 
| 2036 | } | 
| 2037 |  | 
| 2038 |  | 
| 2039 | ############################################################################## | 
| 2040 | # Turn blank suppression on and off at this include level | 
| 2041 | # 1 = on, 0 = off | 
| 2042 | ############################################################################## | 
| 2043 | sub SetBlankSupp | 
| 2044 | { | 
| 2045 | $blanksupp[$include_level] = shift; | 
| 2046 | Debug("Blank suppression set to ".$blanksupp[$include_level], 2); | 
| 2047 | } | 
| 2048 |  | 
| 2049 |  | 
| 2050 | ############################################################################## | 
| 2051 | # Reset blank suppression to command-line value (except at level 0) | 
| 2052 | ############################################################################## | 
| 2053 | sub ResetBlankSupp | 
| 2054 | { | 
| 2055 | if($include_level == 0) { | 
| 2056 | $blanksupp[$include_level] = 0; | 
| 2057 | } else { | 
| 2058 | $blanksupp[$include_level] = $blanksuppopt; | 
| 2059 | } | 
| 2060 | Debug("Blank suppression reset to ".$blanksupp[$include_level], 2); | 
| 2061 | } | 
| 2062 |  | 
| 2063 |  | 
| 2064 | ############################################################################## | 
| 2065 | # Set if macros are only replaced if the macro is a 'word' | 
| 2066 | ############################################################################## | 
| 2067 | sub SetWordBoundaries | 
| 2068 | { | 
| 2069 | my $on = shift; | 
| 2070 | if($on) { | 
| 2071 | $bound = '\b'; | 
| 2072 | Debug("Word Boundaries turned on", 2); | 
| 2073 | } | 
| 2074 | else { | 
| 2075 | $bound = ''; | 
| 2076 | Debug("Word Boundaries turned off", 2); | 
| 2077 | } | 
| 2078 | } | 
| 2079 |  | 
| 2080 | ############################################################################## | 
| 2081 | # DEPRECATED - this function will be removed in later versions, use Set | 
| 2082 | # Toggle if macros are only replaced if the macro is a 'word' | 
| 2083 | ############################################################################## | 
| 2084 | sub ToggleWordBoundaries | 
| 2085 | { | 
| 2086 | if($bound eq '\b') { SetWordBoundaries(1); } | 
| 2087 | else { SetWordBoundaries(0); } | 
| 2088 | } | 
| 2089 |  | 
| 2090 |  | 
| 2091 | ############################################################################## | 
| 2092 | # Set treating keywordchar, contchar, macroprefix and optlineendchar as | 
| 2093 | # Perl regexps | 
| 2094 | ############################################################################## | 
| 2095 | sub SetCharPerlre | 
| 2096 | { | 
| 2097 | $charperlre = shift; | 
| 2098 | Debug("Characters treated as Perl regexp's : ".$charperlre, 2); | 
| 2099 | } | 
| 2100 |  | 
| 2101 |  | 
| 2102 | ############################################################################## | 
| 2103 | # Undef a previously defined variable, usage: | 
| 2104 | # #undef $macro | 
| 2105 | ############################################################################## | 
| 2106 | sub Undef | 
| 2107 | { | 
| 2108 | my $macro = shift; | 
| 2109 | my $i; | 
| 2110 |  | 
| 2111 | # separate macro from any trailing garbage | 
| 2112 | $macro = substr($macro, 0, GetNextWordEnd($macro)); | 
| 2113 |  | 
| 2114 | # delete macro from table | 
| 2115 | delete $Defines{$macro}; | 
| 2116 | delete $DefinesArgs{$macro}; | 
| 2117 | delete $DefinesFuncs{$macro}; | 
| 2118 |  | 
| 2119 | # and remove its eat-trailing-whitespace flag | 
| 2120 | if(CheckEatTrail($macro)) { delete $EatTrail{$macro}; } | 
| 2121 |  | 
| 2122 | # regenerate keys | 
| 2123 | GenerateDefinesKeys(); | 
| 2124 |  | 
| 2125 | Debug("Undefined macro \"".$macro."\"", 2); | 
| 2126 | if($debug > 1) { PrintDefines(); } | 
| 2127 | } | 
| 2128 |  | 
| 2129 |  | 
| 2130 | ############################################################################## | 
| 2131 | # UndefAll - undefines ALL macros | 
| 2132 | ############################################################################## | 
| 2133 | sub UndefAll | 
| 2134 | { | 
| 2135 | %Defines = (); | 
| 2136 | %DefineLookup = (); | 
| 2137 | %EatTrail = (); | 
| 2138 | $defmin = $defmax = 0; | 
| 2139 | Debug("Undefined ALL macros", 2); | 
| 2140 | if($debug > 1) { PrintDefines(); } | 
| 2141 | } | 
| 2142 |  | 
| 2143 |  | 
| 2144 | ############################################################################## | 
| 2145 | # #warning msg  - print warning message "msg" | 
| 2146 | ############################################################################## | 
| 2147 | sub Warning | 
| 2148 | { | 
| 2149 | my $msg = shift; | 
| 2150 | my $lastdebug = $debug; | 
| 2151 | $debug = 1; | 
| 2152 | Debug($msg, 1); | 
| 2153 | $debug = $lastdebug; | 
| 2154 | } | 
| 2155 |  | 
| 2156 |  | 
| 2157 | ############################################################################## | 
| 2158 | # ParseLineEnd - takes in line from input most recently read and checks | 
| 2159 | # if line should be continued (ie. next line in input read and appended | 
| 2160 | # to current line). | 
| 2161 | # Returns two values: | 
| 2162 | # $more - boolean, 1 = read another line from input to append to this one | 
| 2163 | #                  0 = no line continuation | 
| 2164 | # $line - the line to be read.  If any modification needs to be done to the | 
| 2165 | #         line for line contination, it is done here. | 
| 2166 | #         Example: if line is to be continued: set $more = 1, then | 
| 2167 | #                  remove line continuation character and newline from end of | 
| 2168 | #                  $line and replace with line continuation character. | 
| 2169 | ############################################################################## | 
| 2170 | sub ParseLineEnd | 
| 2171 | { | 
| 2172 | my $thisline = shift; | 
| 2173 | my $more = 0; | 
| 2174 | # check if end of line has a continuation char, if it has get next line | 
| 2175 | if($thisline =~ /$contchar$/) { | 
| 2176 | $more = 1; | 
| 2177 | # remove backslash and newline | 
| 2178 | $thisline =~ s/$contchar\n\Z//; | 
| 2179 | # append line continuation character | 
| 2180 | $thisline = $thisline.$contrepchar; | 
| 2181 | } | 
| 2182 | return ($more, $thisline); | 
| 2183 | } | 
| 2184 |  | 
| 2185 |  | 
| 2186 | ############################################################################## | 
| 2187 | # Set name of function to take check if line shoule be continued | 
| 2188 | ############################################################################## | 
| 2189 | sub SetParseLineEnd | 
| 2190 | { | 
| 2191 | my $func = shift; | 
| 2192 | $parselineend = $func; | 
| 2193 | } | 
| 2194 |  | 
| 2195 | ############################################################################## | 
| 2196 | # Get name of function to take check if line shoule be continued | 
| 2197 | ############################################################################## | 
| 2198 | sub GetParseLineEnd | 
| 2199 | { | 
| 2200 | return $parselineend; | 
| 2201 | } | 
| 2202 |  | 
| 2203 |  | 
| 2204 | ############################################################################## | 
| 2205 | # GetNextLine - returns the next line of the current INPUT line, | 
| 2206 | # line continuation is taken care of here. | 
| 2207 | ############################################################################## | 
| 2208 | sub GetNextLine | 
| 2209 | { | 
| 2210 | my $thisline = <INPUT>; | 
| 2211 | if($thisline) { | 
| 2212 | Redefine("__LINE__", ++$line); | 
| 2213 | my $more = 0; | 
| 2214 | ($more, $thisline) = $parselineend->($thisline); | 
| 2215 | while($more) { | 
| 2216 | Debug("Line continuation", 2); | 
| 2217 | my $nextline = <INPUT>; | 
| 2218 | if(!$nextline) { return $thisline; } | 
| 2219 | # increment line count | 
| 2220 | Redefine("__LINE__", ++$line); | 
| 2221 | ($more, $thisline) = $parselineend->($thisline.$nextline); | 
| 2222 | # maintain same number of lines in input as output | 
| 2223 | if($preserveblank) { Filepp::Output("\n"); } | 
| 2224 | } | 
| 2225 | } | 
| 2226 | return $thisline; | 
| 2227 | } | 
| 2228 |  | 
| 2229 |  | 
| 2230 | ############################################################################## | 
| 2231 | # Write($string) - writes $string to OUTPUT file | 
| 2232 | ############################################################################## | 
| 2233 | sub Write | 
| 2234 | { | 
| 2235 | my $string = shift; | 
| 2236 |  | 
| 2237 | if(!$dependency){ | 
| 2238 | print(OUTPUT $string); | 
| 2239 | } | 
| 2240 | } | 
| 2241 |  | 
| 2242 |  | 
| 2243 | ############################################################################## | 
| 2244 | # Output($string) - conditionally writes $string to OUTPUT file | 
| 2245 | ############################################################################## | 
| 2246 | sub Output | 
| 2247 | { | 
| 2248 | my $string = shift; | 
| 2249 | if($output) { Write($string); } | 
| 2250 | } | 
| 2251 |  | 
| 2252 | # counter for number of #if[n][def] loops currently in | 
| 2253 | my $iflevel = 0; | 
| 2254 | # flag to control when to write output | 
| 2255 | my @Writing = (1); # initialise default to 'writing' | 
| 2256 | # flag to show if current 'if' block has passed a 'true if' | 
| 2257 | my @Ifdone = (0); # initialise first to 'not passed true if' | 
| 2258 |  | 
| 2259 | ############################################################################## | 
| 2260 | # Keyword parsing routine | 
| 2261 | ############################################################################## | 
| 2262 | sub ParseKeywords | 
| 2263 | { | 
| 2264 | # input is next line in file | 
| 2265 | my $inline = shift; | 
| 2266 | my $outline = ""; | 
| 2267 |  | 
| 2268 | my $thisline = $inline; | 
| 2269 | my $keyword; | 
| 2270 | my $found = 0; | 
| 2271 | # remove whitespace from start of line | 
| 2272 | $thisline = CleanStart($thisline); | 
| 2273 | # check if first char on line is a # | 
| 2274 |  | 
| 2275 | #if($thisline && $thisline =~ /^$keywordchar/) { | 
| 2276 | if($thisline) { | 
| 2277 | # remove "#" and any following whitespace | 
| 2278 | #$thisline =~ s/^$keywordchar\s*//g; | 
| 2279 | # remove the optional end line char | 
| 2280 | if($optlineendchar ne "") { | 
| 2281 | $thisline =~ s/$optlineendchar\Z//g; | 
| 2282 | } | 
| 2283 | # check for keyword | 
| 2284 | #if($thisline && $thisline =~ /^\w+\b/ && exists($Keywords{$&})) { | 
| 2285 | if($thisline && $thisline =~ /^#*\w+\b/ && exists($Keywords{$&})) { | 
| 2286 | $keyword = $&; | 
| 2287 | $found = 1; | 
| 2288 | # remove newline from line | 
| 2289 | chomp($thisline); | 
| 2290 | # remove leading whitespace and keyword from line | 
| 2291 | my $inline = CleanStart(substr($thisline, length($keyword))); | 
| 2292 |  | 
| 2293 | # check for 'if' style keyword | 
| 2294 | if(exists($Ifwords{$keyword})) { | 
| 2295 | # increment ifblock level and set ifdone to same | 
| 2296 | # value as previous block | 
| 2297 | $iflevel++; | 
| 2298 | $Ifdone[$iflevel] = 0; | 
| 2299 | $Writing[$iflevel] = $Writing[$iflevel - 1]; | 
| 2300 | if(!$Writing[$iflevel]) { $Ifdone[$iflevel] = 1; } | 
| 2301 | } | 
| 2302 | # check for out of place 'else' or 'endif' style keyword | 
| 2303 | elsif($iflevel <= 0 && (exists($Elsewords{$keyword}) || | 
| 2304 | exists($Endifwords{$keyword}) )) { | 
| 2305 | Warning($keywordchar.$keyword." found without preceding ". | 
| 2306 | $keywordchar."[else]ifword"); | 
| 2307 | } | 
| 2308 |  | 
| 2309 | # decide if to run 'if' or 'else' keyword | 
| 2310 | if(exists($Ifwords{$keyword}) || exists($Elsewords{$keyword})){ | 
| 2311 | if(!($Ifdone[$iflevel])) { | 
| 2312 | # check return value of 'if' | 
| 2313 | if($Keywords{$keyword}->($inline)) { | 
| 2314 | $Ifdone[$iflevel] = 1; | 
| 2315 | $Writing[$iflevel] = 1; | 
| 2316 | } | 
| 2317 | else { $Writing[$iflevel] = 0; } | 
| 2318 | } | 
| 2319 | else { $Writing[$iflevel] = 0; } | 
| 2320 | } | 
| 2321 | # check for 'endif' style keyword | 
| 2322 | elsif(exists($Endifwords{$keyword})) { | 
| 2323 | # run endif keyword and decrement iflevel if true | 
| 2324 | if($Keywords{$keyword}->($inline)) { $iflevel--; } | 
| 2325 | } | 
| 2326 | # run all other keywords | 
| 2327 | elsif($Writing[$iflevel]) { $Keywords{$keyword}->($inline); } | 
| 2328 |  | 
| 2329 | # write a blank line if preserving blank lines | 
| 2330 | # (assumes keywords have no output) | 
| 2331 | if($preserveblank) { $outline = $outline."\n"; } | 
| 2332 |  | 
| 2333 | } # keyword if statement | 
| 2334 | } | 
| 2335 | # no keywords in line - write line to file if not #ifdef'ed out | 
| 2336 | if(!$found && $Writing[$iflevel]) { | 
| 2337 | $outline = $outline.$inline; | 
| 2338 | } | 
| 2339 | # keep same number of files in output and input | 
| 2340 | elsif(!$found && $preserveblank) { $outline = $outline."\n"; } | 
| 2341 |  | 
| 2342 | return $outline; | 
| 2343 | } | 
| 2344 |  | 
| 2345 | ############################################################################## | 
| 2346 | # Main parsing routine | 
| 2347 | ############################################################################## | 
| 2348 | sub Parse | 
| 2349 | { | 
| 2350 | # change file being parsed to this file, remember last filename so | 
| 2351 | # it can be returned at the end | 
| 2352 | my $lastparse = $file; | 
| 2353 | $file = shift; | 
| 2354 |  | 
| 2355 | Debug("Parsing ".$file."...", 1); | 
| 2356 | Redefine("__FILE__", $file); | 
| 2357 |  | 
| 2358 | # reset line count, remembering previous count for future reference | 
| 2359 | my $lastcount = $line; | 
| 2360 | $line = 0; | 
| 2361 | Redefine("__LINE__", $line); | 
| 2362 |  | 
| 2363 | # increment include level | 
| 2364 | Redefine("__INCLUDE_LEVEL__", ++$include_level); | 
| 2365 |  | 
| 2366 | # set blank line suppression: | 
| 2367 | # no suppression for top level files | 
| 2368 | if($include_level == 0) { | 
| 2369 | $blanksupp[$include_level] = 0; | 
| 2370 | } | 
| 2371 | # include level 1 - set suppression to command line given value | 
| 2372 | elsif($include_level == 1) { | 
| 2373 | # inherit root value if set | 
| 2374 | if($blanksupp[0]) { $blanksupp[$include_level] = 1; } | 
| 2375 | else {$blanksupp[$include_level] = $blanksuppopt; } | 
| 2376 | } | 
| 2377 | # all other include levels - keep suppression at existing value | 
| 2378 | else { | 
| 2379 | $blanksupp[$include_level] = $blanksupp[$include_level - 1]; | 
| 2380 | } | 
| 2381 |  | 
| 2382 | # reset RunProcessors function for this file | 
| 2383 | $Running[$include_level] = 0; | 
| 2384 | $Currentproc[$include_level] = 0; | 
| 2385 |  | 
| 2386 | # open file and set its handle to INPUT | 
| 2387 | local *INPUT; | 
| 2388 | if(!open(INPUT, $file)) { | 
| 2389 | Error("Could not open file ".$file); | 
| 2390 | } | 
| 2391 |  | 
| 2392 | # change the behavior of OpenInputFuncs | 
| 2393 | # every time a file is open, the functions in @OpenInputFuncs | 
| 2394 | # are called. | 
| 2395 | # if a base file, run any initialisation functions | 
| 2396 | # if($include_level == 0) { | 
| 2397 | my $func; | 
| 2398 | foreach $func (@OpenInputFuncs) { $func->(); } | 
| 2399 | #} | 
| 2400 |  | 
| 2401 | # parse each line of file | 
| 2402 | $_ = GetNextLine(); | 
| 2403 | # if in "shebang" mode, throw away first line (the #!/blah bit) | 
| 2404 | if($shebang) { | 
| 2405 | # check for "#!...perl ...filepp..." | 
| 2406 | if($_ && $_ =~ /^\#\!.*perl.+filepp/) { | 
| 2407 | Debug("Skipping first line (shebang): ".$_, 1); | 
| 2408 | $_ = GetNextLine(); | 
| 2409 | } | 
| 2410 | } | 
| 2411 |  | 
| 2412 | while($_) { | 
| 2413 | # unless blank lines are suppressed at this include level | 
| 2414 | unless($blanksupp[$include_level] && /^\s*$/) { | 
| 2415 | # run processing chain (defaults to ReplaceDefines) | 
| 2416 | $_ = RunProcessors($_, 1); | 
| 2417 | # write output to file or STDOUT | 
| 2418 | if($output) { Write($_); } | 
| 2419 | } | 
| 2420 | $_ = GetNextLine(); | 
| 2421 | } | 
| 2422 |  | 
| 2423 | # run any close functions | 
| 2424 | #if($include_level == 0) { | 
| 2425 | #my $func; | 
| 2426 | foreach $func (@CloseInputFuncs) { $func->(); } | 
| 2427 | #} | 
| 2428 |  | 
| 2429 | # check all #if blocks have been closed at end of parsing | 
| 2430 | if($lastparse eq "" && $iflevel > 0) { Warning("Unterminated if block"); } | 
| 2431 |  | 
| 2432 | # close file | 
| 2433 | close(INPUT); | 
| 2434 | Debug("Parsing ".$file." done. (".$line." lines processed)", 1); | 
| 2435 |  | 
| 2436 | # reset $line | 
| 2437 | $line = $lastcount; | 
| 2438 | Redefine("__LINE__", $line); | 
| 2439 |  | 
| 2440 | # reset $file | 
| 2441 | $file = $lastparse; | 
| 2442 | Redefine("__FILE__", $file); | 
| 2443 | if($file ne "") { | 
| 2444 | Debug("Parsing returned to ".$file." at line ".$line, 1); | 
| 2445 | } | 
| 2446 |  | 
| 2447 | # decrement include level | 
| 2448 | Redefine("__INCLUDE_LEVEL__", --$include_level); | 
| 2449 |  | 
| 2450 | } | 
| 2451 |  | 
| 2452 | ############################################################################## | 
| 2453 | # module keyword - declare a fortran90 module | 
| 2454 | ############################################################################## | 
| 2455 | sub Module{ | 
| 2456 | my $modulename = shift; | 
| 2457 | my $modulefile; | 
| 2458 | my $file; | 
| 2459 | if ($modulename !~ /^procedure/){ | 
| 2460 |  | 
| 2461 | $modulename =~ s/\s+$//; | 
| 2462 | $parsedModList{GetModBasename($modulename) .  "." . $modSuffix} | 
| 2463 | =  Filepp::GetDefine('__FILE__'); | 
| 2464 |  | 
| 2465 | #$modulefile = Filepp::GetDefine('__BASE_FILE__'); | 
| 2466 | #print $modulefile; | 
| 2467 | #$file = Filepp::GetDefine('__FILE__'); | 
| 2468 | #print $modulefile; | 
| 2469 | } | 
| 2470 | } | 
| 2471 |  | 
| 2472 | ############################################################################## | 
| 2473 | # add use keyword | 
| 2474 | ############################################################################## | 
| 2475 | Filepp::AddKeyword("module", "Filepp::Module"); | 
| 2476 |  | 
| 2477 | ############################################################################## | 
| 2478 | # use keyword - use other fortran90 module | 
| 2479 | ############################################################################## | 
| 2480 | sub Use{ | 
| 2481 | my $line = shift; | 
| 2482 | $line =~ /^(\w+).*/; | 
| 2483 | my $f90module = $1; | 
| 2484 | $f90module =~ s/\s+$//; | 
| 2485 | $f90module = uc($f90module); | 
| 2486 |  | 
| 2487 | print " " . $objDir . GetModBasename($f90module) . "." . $modSuffix . " \\\n"; | 
| 2488 | } | 
| 2489 |  | 
| 2490 | ############################################################################## | 
| 2491 | # add use keyword | 
| 2492 | ############################################################################## | 
| 2493 | Filepp::AddKeyword("use", "Filepp::Use"); | 
| 2494 |  | 
| 2495 | ############################################################################## | 
| 2496 | # add include keyword which is the same as c's #include | 
| 2497 | ############################################################################## | 
| 2498 | Filepp::AddKeyword("include", "Filepp::Include"); | 
| 2499 |  | 
| 2500 | ############################################################################## | 
| 2501 | # test whether a file is visited or not | 
| 2502 | ############################################################################## | 
| 2503 | sub IsVisited { | 
| 2504 | my $fullfile = shift; | 
| 2505 |  | 
| 2506 | if (exists($visitedTable{$fullfile})){ | 
| 2507 | return 1; | 
| 2508 | } else { | 
| 2509 | $visitedTable{$fullfile} = 1; | 
| 2510 | return 0; | 
| 2511 | } | 
| 2512 | } | 
| 2513 |  | 
| 2514 | ############################################################################## | 
| 2515 | # Clean Visited Table | 
| 2516 | ############################################################################## | 
| 2517 | sub cleanVisited { | 
| 2518 | my $visitedFile; | 
| 2519 | foreach $visitedFile (keys %visitedTable) { | 
| 2520 | delete $visitedTable{$visitedFile}; | 
| 2521 | } | 
| 2522 |  | 
| 2523 | } | 
| 2524 |  | 
| 2525 | sub AddModule { | 
| 2526 | my $modulename = shift; | 
| 2527 |  | 
| 2528 | if (!exists($f90ModList{$modulename})){ | 
| 2529 | $f90ModList{$modulename} = 1; | 
| 2530 | } else { | 
| 2531 | $f90ModList{$modulename}++; | 
| 2532 |  | 
| 2533 | } | 
| 2534 |  | 
| 2535 | } | 
| 2536 |  | 
| 2537 | ############################################################################## | 
| 2538 | # Generate rules for fortran 90 module | 
| 2539 | ############################################################################## | 
| 2540 | sub printModule { | 
| 2541 | my $modname; | 
| 2542 | my $objname; | 
| 2543 | print "\n"; | 
| 2544 | foreach $modname (keys %parsedModList) { | 
| 2545 | $objname = GetObjFile($modname); | 
| 2546 | print $objDir . $modname  . " : " . $objDir . $objname . "\n"; | 
| 2547 | } | 
| 2548 | } | 
| 2549 |  | 
| 2550 | ############################################################################## | 
| 2551 | # Get the object file name | 
| 2552 | ############################################################################## | 
| 2553 | sub GetObjFile { | 
| 2554 | use File::Basename; | 
| 2555 | my $fullname = shift; | 
| 2556 | my $filename; | 
| 2557 | my $dir; | 
| 2558 | my $suffix; | 
| 2559 |  | 
| 2560 | ($filename, $dir, $suffix) = fileparse($fullname, '\.[^.]*'); | 
| 2561 | return $filename . $objExt; | 
| 2562 | } | 
| 2563 |  | 
| 2564 | ############################################################################## | 
| 2565 | # Get the base name of fortran 90 module | 
| 2566 | ############################################################################## | 
| 2567 | sub GetModBasename { | 
| 2568 | my $modname = shift; | 
| 2569 |  | 
| 2570 | if ($modBasenameCase eq "lower") { | 
| 2571 | $modname = lc($modname); | 
| 2572 |  | 
| 2573 | } elsif ($modBasenameCase eq "upper") { | 
| 2574 | $modname = uc($modname); | 
| 2575 | } elsif ($modBasenameCase eq "mixed") { | 
| 2576 | $modname = ucfirst(lc($modname)); | 
| 2577 | } | 
| 2578 |  | 
| 2579 | return $modname; | 
| 2580 | } | 
| 2581 |  | 
| 2582 | sub RestoreCommandLineDefine { | 
| 2583 | my $macro; | 
| 2584 |  | 
| 2585 | foreach $macro(@savedDefine) { | 
| 2586 | Define($macro); | 
| 2587 | } | 
| 2588 | } | 
| 2589 |  | 
| 2590 | sub SaveCommandLineDefine { | 
| 2591 | my $macro = shift; | 
| 2592 | push @savedDefine, $macro; | 
| 2593 | } | 
| 2594 | ############################################################################## | 
| 2595 | # Main routine | 
| 2596 | ############################################################################## | 
| 2597 |  | 
| 2598 | # parse command line | 
| 2599 | my $i=0; | 
| 2600 | my $argc=0; | 
| 2601 | while($ARGV[$argc]) { $argc++; } | 
| 2602 |  | 
| 2603 | while($ARGV[$i]) { | 
| 2604 |  | 
| 2605 | # suppress blank lines in header files | 
| 2606 | if($ARGV[$i] eq "-b") { | 
| 2607 | $blanksuppopt = 1; | 
| 2608 | } | 
| 2609 |  | 
| 2610 | # read from stdin instead of file | 
| 2611 | elsif($ARGV[$i] eq "-c") { | 
| 2612 | AddInputFile("-"); | 
| 2613 | } | 
| 2614 |  | 
| 2615 | # Defines: -Dmacro[=defn] or -D macro[=defn] | 
| 2616 | elsif(substr($ARGV[$i], 0, 2) eq "-D") { | 
| 2617 | my $macrodefn; | 
| 2618 | # -D macro[=defn] format | 
| 2619 | if(length($ARGV[$i]) == 2) { | 
| 2620 | if($i+1 >= $argc) { | 
| 2621 | Error("Argument to `-D' is missing"); | 
| 2622 | } | 
| 2623 | $macrodefn = $ARGV[++$i]; | 
| 2624 | } | 
| 2625 | # -Dmacro[=defn] format | 
| 2626 | else { | 
| 2627 | $macrodefn = substr($ARGV[$i], 2); | 
| 2628 | } | 
| 2629 | my $macro = $macrodefn; | 
| 2630 | my $defn = ""; | 
| 2631 | my $j = index($macrodefn, "="); | 
| 2632 | if($j > -1) { | 
| 2633 | $defn  = substr($macrodefn, $j+1); | 
| 2634 | $macro = substr($macrodefn, 0, $j); | 
| 2635 | } | 
| 2636 | # add macro and defn to hash table | 
| 2637 | Define($macro." ".$defn); | 
| 2638 |  | 
| 2639 | #save define macro from command line | 
| 2640 | #it will be restored when next source file is processed | 
| 2641 | SaveCommandLineDefine($macro." ".$defn); | 
| 2642 | } | 
| 2643 |  | 
| 2644 | # Debugging turned on: -d | 
| 2645 | elsif($ARGV[$i] eq "-d") { | 
| 2646 | SetDebug(2); | 
| 2647 | } | 
| 2648 |  | 
| 2649 | # Full debugging turned on: -dd | 
| 2650 | elsif($ARGV[$i] eq "-dd") { | 
| 2651 | SetDebug(3); | 
| 2652 | } | 
| 2653 |  | 
| 2654 | # Light debugging turned on: -dl | 
| 2655 | elsif($ARGV[$i] eq "-dl") { | 
| 2656 | SetDebug(1); | 
| 2657 | } | 
| 2658 |  | 
| 2659 | # Send debugging info to stdout rather than stderr | 
| 2660 | elsif($ARGV[$i] eq "-ds") { | 
| 2661 | $debugstdout = 1; | 
| 2662 | } | 
| 2663 |  | 
| 2664 | # prefix all debugging info with string | 
| 2665 | elsif($ARGV[$i] eq "-dpre") { | 
| 2666 | if($i+1 >= $argc) { | 
| 2667 | Error("Argument to `-dpre' is missing"); | 
| 2668 | } | 
| 2669 | $debugprefix = ReplaceDefines($ARGV[++$i]); | 
| 2670 | } | 
| 2671 |  | 
| 2672 | # prefix all debugging info with string | 
| 2673 | elsif($ARGV[$i] eq "-dpost") { | 
| 2674 | if($i+1 >= $argc) { | 
| 2675 | Error("Argument to `-dpost' is missing"); | 
| 2676 | } | 
| 2677 | # replace defines is called here in case a newline is required, | 
| 2678 | # this allows it to be added as __NEWLINE__ | 
| 2679 | $debugpostfix = ReplaceDefines($ARGV[++$i]); | 
| 2680 | } | 
| 2681 |  | 
| 2682 | # define environment variables as macros: -e | 
| 2683 | elsif($ARGV[$i] eq "-e") { | 
| 2684 | DefineEnv(); | 
| 2685 | } | 
| 2686 |  | 
| 2687 | # set environment variable prefix char | 
| 2688 | elsif($ARGV[$i] eq "-ec") { | 
| 2689 | if($i+1 >= $argc) { | 
| 2690 | Error("Argument to `-ec' is missing"); | 
| 2691 | } | 
| 2692 | SetEnvchar($ARGV[++$i]); | 
| 2693 | } | 
| 2694 |  | 
| 2695 | # set environment variable prefix char to nothing | 
| 2696 | elsif($ARGV[$i] eq "-ecn") { | 
| 2697 | SetEnvchar(""); | 
| 2698 | } | 
| 2699 |  | 
| 2700 | # show help | 
| 2701 | elsif($ARGV[$i] eq "-h") { | 
| 2702 | print(STDERR $usage); | 
| 2703 | exit(0); | 
| 2704 | } | 
| 2705 |  | 
| 2706 | # Include paths: -Iinclude or -I include | 
| 2707 | elsif(substr($ARGV[$i], 0, 2) eq "-I") { | 
| 2708 | # -I include format | 
| 2709 | if(length($ARGV[$i]) == 2) { | 
| 2710 | if($i+1 >= $argc) { | 
| 2711 | Error("Argument to `-I' is missing"); | 
| 2712 | } | 
| 2713 | AddIncludePath($ARGV[++$i]); | 
| 2714 | } | 
| 2715 | # -Iinclude format | 
| 2716 | else { | 
| 2717 | AddIncludePath(substr($ARGV[$i], 2)); | 
| 2718 | } | 
| 2719 | } | 
| 2720 |  | 
| 2721 | # Include macros from file: -imacros file | 
| 2722 | elsif($ARGV[$i] eq "-imacros") { | 
| 2723 | if($i+1 >= $argc) { | 
| 2724 | Error("Argument to `-imacros' is missing"); | 
| 2725 | } | 
| 2726 | push(@Imacrofiles, $ARGV[++$i]); | 
| 2727 | } | 
| 2728 |  | 
| 2729 | # turn off keywords | 
| 2730 | elsif($ARGV[$i] eq "-k") { | 
| 2731 | RemoveAllKeywords(); | 
| 2732 | } | 
| 2733 |  | 
| 2734 | # set keyword prefix char | 
| 2735 | elsif($ARGV[$i] eq "-kc") { | 
| 2736 | if($i+1 >= $argc) { | 
| 2737 | Error("Argument to `-kc' is missing"); | 
| 2738 | } | 
| 2739 | SetKeywordchar($ARGV[++$i]); | 
| 2740 | } | 
| 2741 |  | 
| 2742 | # set line continuation character | 
| 2743 | elsif($ARGV[$i] eq "-lc") { | 
| 2744 | if($i+1 >= $argc) { | 
| 2745 | Error("Argument to `-lc' is missing"); | 
| 2746 | } | 
| 2747 | SetContchar($ARGV[++$i]); | 
| 2748 | } | 
| 2749 |  | 
| 2750 | # set optional line end character | 
| 2751 | elsif($ARGV[$i] eq "-lec") { | 
| 2752 | if($i+1 >= $argc) { | 
| 2753 | Error("Argument to `-lec' is missing"); | 
| 2754 | } | 
| 2755 | SetOptLineEndchar($ARGV[++$i]); | 
| 2756 | } | 
| 2757 |  | 
| 2758 | # set line continuation replacement char to newline | 
| 2759 | elsif($ARGV[$i] eq "-lrn") { | 
| 2760 | SetContrepchar("\n"); | 
| 2761 | } | 
| 2762 |  | 
| 2763 | # set line continuation replacement character | 
| 2764 | elsif($ARGV[$i] eq "-lr") { | 
| 2765 | if($i+1 >= $argc) { | 
| 2766 | Error("Argument to `-lr' is missing"); | 
| 2767 | } | 
| 2768 | SetContrepchar($ARGV[++$i]); | 
| 2769 | } | 
| 2770 |  | 
| 2771 | # Module paths: -Minclude or -M include | 
| 2772 | #elsif(substr($ARGV[$i], 0, 2) eq "-M") { | 
| 2773 | #   # -M include format | 
| 2774 | #   if(length($ARGV[$i]) == 2) { | 
| 2775 | #       if($i+1 >= $argc) { | 
| 2776 | #           Error("Argument to `-M' is missing"); | 
| 2777 | #       } | 
| 2778 | #       AddModulePath($ARGV[++$i]); | 
| 2779 | #   } | 
| 2780 | #   # -Minclude format | 
| 2781 | #   else { | 
| 2782 | #       AddModulePath(substr($ARGV[$i], 2)); | 
| 2783 | #   } | 
| 2784 | #} | 
| 2785 |  | 
| 2786 | # use module | 
| 2787 | #elsif($ARGV[$i] eq "-m") { | 
| 2788 | #   if($i+1 >= $argc) { | 
| 2789 | #       Error("Argument to `-m' is missing"); | 
| 2790 | #   } | 
| 2791 | #   UseModule($ARGV[++$i]); | 
| 2792 | #} | 
| 2793 |  | 
| 2794 | # make dependency | 
| 2795 | elsif($ARGV[$i] eq "-M") { | 
| 2796 | $dependency = 1; | 
| 2797 | } | 
| 2798 |  | 
| 2799 | # make dependency (skip system header files) | 
| 2800 | elsif($ARGV[$i] eq "-MM") { | 
| 2801 | $dependency = 1; | 
| 2802 | $skipSysInclude = 1; | 
| 2803 | } | 
| 2804 |  | 
| 2805 | #case of basename of fortran module | 
| 2806 | elsif($ARGV[$i] eq "-mc") { | 
| 2807 | my $tempVar = lc($ARGV[++$i]); | 
| 2808 | if ($modBasenameCase ne 'lower' && $modBasenameCase ne 'upper' | 
| 2809 | && $modBasenameCase ne 'mixed'){ | 
| 2810 | Error("Valid argument for `-om' are lower, upper or mixed"); | 
| 2811 | } | 
| 2812 | $modBasenameCase = $tempVar; | 
| 2813 | } | 
| 2814 |  | 
| 2815 | #the suffix of fortran module | 
| 2816 | elsif($ARGV[$i] eq "-ms") { | 
| 2817 | $modSuffix = $ARGV[++$i]; | 
| 2818 | } | 
| 2819 |  | 
| 2820 | # set macro prefix | 
| 2821 | elsif($ARGV[$i] eq "-mp") { | 
| 2822 | if($i+1 >= $argc) { | 
| 2823 | Error("Argument to `-mp' is missing"); | 
| 2824 | } | 
| 2825 | SetMacroPrefix($ARGV[++$i]); | 
| 2826 | } | 
| 2827 |  | 
| 2828 | # turn off macro prefix within keywords | 
| 2829 | elsif($ARGV[$i] eq "-mpnk") { | 
| 2830 | $macroprefixinkeywords = 0; | 
| 2831 | } | 
| 2832 |  | 
| 2833 | # tells filepp that the object and | 
| 2834 | # module files will be built in a separate directory from the sources. | 
| 2835 | elsif($ARGV[$i] eq "-od") { | 
| 2836 | $objDir = $ARGV[++$i]; | 
| 2837 | } | 
| 2838 |  | 
| 2839 | # turn on overwrite mode | 
| 2840 | elsif($ARGV[$i] eq "-ov") { | 
| 2841 | $overwrite = 1; | 
| 2842 | } | 
| 2843 |  | 
| 2844 | # turn on overwrite conversion mode | 
| 2845 | elsif($ARGV[$i] eq "-ovc") { | 
| 2846 | if($i+1 >= $argc) { | 
| 2847 | Error("Argument to `-ovc' is missing"); | 
| 2848 | } | 
| 2849 | $overwriteconv = $ARGV[++$i]; | 
| 2850 | if($overwriteconv !~ /=/) { | 
| 2851 | Error("-ovc argument is of form IN=OUT"); | 
| 2852 | } | 
| 2853 | $overwrite = 1; | 
| 2854 | } | 
| 2855 |  | 
| 2856 | # Output filename: -o filename or -ofilename | 
| 2857 | elsif(substr($ARGV[$i], 0, 2) eq "-o") { | 
| 2858 | # -o filename | 
| 2859 | if(length($ARGV[$i]) == 2) { | 
| 2860 | if($i+1 >= $argc) { | 
| 2861 | Error("Argument to `-o' is missing"); | 
| 2862 | } | 
| 2863 | $outputfile = $ARGV[++$i]; | 
| 2864 | } | 
| 2865 | # -ofilename | 
| 2866 | else { | 
| 2867 | $outputfile = substr($ARGV[$i], 2); | 
| 2868 | } | 
| 2869 | } | 
| 2870 |  | 
| 2871 | # preserve blank lines in output file | 
| 2872 | elsif($ARGV[$i] eq "-pb") { | 
| 2873 | $preserveblank = 1; | 
| 2874 | } | 
| 2875 |  | 
| 2876 | # treat $keywordchar, $contchar and $optlineendchar as regular expressions | 
| 2877 | elsif($ARGV[$i] eq "-re") { | 
| 2878 | if($charperlre) { SetCharPerlre(0); } | 
| 2879 | else { SetCharPerlre(1); } | 
| 2880 | } | 
| 2881 |  | 
| 2882 | # Safe mode - turns off #pragma | 
| 2883 | elsif($ARGV[$i] eq "-s") { | 
| 2884 | SafeMode(); | 
| 2885 | } | 
| 2886 |  | 
| 2887 | # Undefine all macros | 
| 2888 | elsif($ARGV[$i] eq "-u") { | 
| 2889 | UndefAll(); | 
| 2890 | } | 
| 2891 |  | 
| 2892 | # print version number and exit | 
| 2893 | elsif($ARGV[$i] eq "-v") { | 
| 2894 | print(STDERR "filepp version ".$VERSION."\n"); | 
| 2895 | exit(0); | 
| 2896 | } | 
| 2897 |  | 
| 2898 | # only replace macros if they appear as 'words' | 
| 2899 | elsif($ARGV[$i] eq "-w") { | 
| 2900 | if($bound eq '') { SetWordBoundaries(1); } | 
| 2901 | else { SetWordBoundaries(0); } | 
| 2902 | } | 
| 2903 |  | 
| 2904 | # default - an input file name | 
| 2905 | else { | 
| 2906 | if(!FileExists($ARGV[$i])) { | 
| 2907 | Error("Input file \"".$ARGV[$i]."\" not readable"); | 
| 2908 | } | 
| 2909 | AddInputFile($ARGV[$i]); | 
| 2910 | } | 
| 2911 |  | 
| 2912 | $i++; | 
| 2913 | } | 
| 2914 |  | 
| 2915 | # check input files have been specified | 
| 2916 | if($#Inputfiles == -1) { | 
| 2917 | Error("No input files given"); | 
| 2918 | } | 
| 2919 |  | 
| 2920 | # import macros from file if any | 
| 2921 | if($#Imacrofiles >= 0) { | 
| 2922 | my $file; | 
| 2923 | foreach $file (@Imacrofiles) { IncludeMacros($file); } | 
| 2924 | } | 
| 2925 |  | 
| 2926 | # print initial defines if debugging | 
| 2927 | if($debug > 1) { PrintDefines(); } | 
| 2928 |  | 
| 2929 | # open the output file | 
| 2930 | if(!$overwrite) { OpenOutputFile($outputfile); } | 
| 2931 |  | 
| 2932 | # parse all input files in order given on command line | 
| 2933 | my $base_file = ""; | 
| 2934 | foreach $base_file (@Inputfiles) { | 
| 2935 | Redefine("__BASE_FILE__", $base_file); | 
| 2936 | # set open output file if in overwrite mode | 
| 2937 | if($overwrite) { | 
| 2938 | if($overwriteconv ne "") { # convert output filename if needed | 
| 2939 | my ($in,$out) = split(/=/, $overwriteconv, 2); | 
| 2940 | my $outfile = $base_file; | 
| 2941 | $outfile =~ s/\Q$in\E/$out/; | 
| 2942 | OpenOutputFile($outfile); | 
| 2943 | } | 
| 2944 | else { OpenOutputFile($base_file); } | 
| 2945 | } | 
| 2946 |  | 
| 2947 | #clean visitedTable | 
| 2948 | %visitedTable = (); | 
| 2949 |  | 
| 2950 | #clear all define | 
| 2951 | UndefAll(); | 
| 2952 |  | 
| 2953 | #restore command line define | 
| 2954 | RestoreCommandLineDefine(); | 
| 2955 |  | 
| 2956 | #print dependency rule | 
| 2957 | print "\n"; | 
| 2958 | print $objDir . GetObjFile($base_file) . " : " . $base_file . " \\"; | 
| 2959 | print "\n"; | 
| 2960 |  | 
| 2961 | Parse($base_file); | 
| 2962 | # close output file if in overwrite mode | 
| 2963 | if($overwrite) { CloseOutputFile(); } | 
| 2964 | } | 
| 2965 |  | 
| 2966 | printModule(); | 
| 2967 |  | 
| 2968 | # close output file | 
| 2969 | if(!$overwrite) { CloseOutputFile(); } | 
| 2970 |  | 
| 2971 | exit(0); | 
| 2972 |  | 
| 2973 | # Hey emacs !! | 
| 2974 | # Local Variables: | 
| 2975 | # mode: perl | 
| 2976 | # End: | 
| 2977 |  | 
| 2978 | ######################################################################## | 
| 2979 | # End of file | 
| 2980 | ######################################################################## |