# ***** BEGIN LICENSE BLOCK ***** # Version: MPL 1.1/GPL 2.0/LGPL 2.1 # # The contents of this file are subject to the Mozilla Public License Version # 1.1 (the "License"); you may not use this file except in compliance with # the License. You may obtain a copy of the License at # http://www.mozilla.org/MPL/ # # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License # for the specific language governing rights and limitations under the # License. # # The Original Code is IDL pre-processor. # # The Initial Developer of the Original Code is # Alexander J. Vincent . # Portions created by the Initial Developer are Copyright (C) 2006 # the Initial Developer. All Rights Reserved. # # Contributor(s): # # Alternatively, the contents of this file may be used under the terms of # either the GNU General Public License Version 2 or later (the "GPL"), or # the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), # in which case the provisions of the GPL or the LGPL are applicable instead # of those above. If you wish to allow use of your version of this file only # under the terms of either the GPL or the LGPL, and not to allow others to # use your version of this file under the terms of the MPL, indicate your # decision by deleting the provisions above and replace them with the notice # and other provisions required by the GPL or the LGPL. If you do not delete # the provisions above, a recipient may use your version of this file under # the terms of any one of the MPL, the GPL or the LGPL. # # ***** END LICENSE BLOCK ***** use strict; use warnings; my %defines; my $documentation = <<"Documentation" idl-preprocess.pl -DFOO -UBAR --srcdir=path/to/directory/containing.idl.in preprocessor.defines structure: -DFOO -UBAR -DFOO means #ifdef FOO will pass, #ifndef FOO will fail -UBAR means #ifdef BAR will fail, #ifndef BAR will pass Supported preprocessing (.idl.in files) #ifdef #ifndef #endif #switchdef #casedef #casebreak #defaultcase #endswitchdef Example (IDL): #switchdef #casedef WF2_PATTERN [scriptable, uuid(99639d86-39d6-46d7-aa0d-4ba4c3d72a00)] #casebreak #default [scriptable, uuid(5a2e9790-3b72-4512-b3bf-203cec7b3379)] #casebreak #endswitchdef interface nsIDOMWF2ValidityState : nsISupports { #ifdef WF2_PATTERN /** * True if the owner control's value failed to match against its pattern attribute. */ readonly attribute boolean patternMismatch; #endif /** * True if the owner control required a value and did not have it. */ readonly attribute boolean valueMissing; /** * True if the owner control meets all constraints on it. */ readonly attribute boolean valid; }; Documentation ; my $log = 0; my $level = 0; # Diagnostic logging: called at the beginning of a function, logs the function # name and parameters, and increments the indent level. sub enterLog($@) { if ($log) { my ($f, @parms) = @_; $level++; my $format = "%" . $level * 2 . "s Enter %s"; printf ($format, " ", $f); while (@parms) { print " "; my $parm = shift (@parms); print ($parm); } print "\n\n"; } } # Diagnostic logging: called in the middle of functions, logs the data at the # current indent level. sub printLog($) { if ($log) { my ($arg) = @_; my $format = "%" . $level * 2 . "s %s\n"; printf ($format, " ", $arg); } } # Diagnostic logging: called at the end of functions, decrements the indent. sub exitLog { if ($log) { my ($f, @parms) = @_; my $format = "%" . $level * 2 . "s Exit %s"; printf ($format, " ", $f); while (@parms) { print " "; my $parm = shift (@parms); print ($parm); } print "\n\n"; $level--; } } sub checkPwd($) { my ($pwd) = @_; my $nowPwd = `pwd`; if ($pwd ne $nowPwd) { die("checkPwd failed!\n begin: $pwd\n close: $nowPwd\n"); } } sub processParameters() { enterLog("processParameters", @_); my $pwd = `pwd`; my $fileDefines = ""; my $diff = ""; my $diffFilename = ""; my $srcdir = ""; while (@ARGV) { my $param = shift (@ARGV); if ($param =~ /--srcdir=/) { if ($srcdir ne "") { die("srcdir can only be defined once!"); } $srcdir = substr($param, 9); next; } if ($param eq "--help") { print $documentation; exit; } if ($param =~ /^-[DU]/) { $fileDefines .= " $param"; } } my @arrayDefines = split(/ /, $fileDefines); for (my $i = 1; $i <= $#arrayDefines; $i++) { my $define = substr($arrayDefines[$i], 2); if ($arrayDefines[$i] =~ /^-D/) { if ($define =~ /=1$/) { $defines{substr($define, 0, -2)} = 1; next; } if ($define =~ /=0$/) { $defines{substr($define, 0, -2)} = 0; next; } if ($define =~ /=/) { next; } $defines{$define} = 1; next; } if ($arrayDefines[$i] =~ /^-U/) { $defines{$define} = 0; next; } die("Bad parameter " . $arrayDefines[$i] . "\n"); } exitLog("processParameters", @_); return ($srcdir); } sub updatePrintLine($@) { my ($newLine, @stack) = @_; chomp($newLine); enterLog("updatePrintLine", @_); my $ok = 0; my $lastLine = $stack[($#stack)]; if (($newLine =~ /^#ifdef /) || ($newLine =~ /^#ifndef /)) { $stack[$#stack + 1] = $newLine; $ok = 1; } if ($newLine eq "#switchdef") { $stack[$#stack + 1] = $newLine . " 1"; $ok = 1; } if ((($newLine eq "#defaultcase") || ($newLine =~ /^#casedef /)) && ($lastLine =~ /^#switchdef /)) { $stack[$#stack + 1] = $newLine; $ok = 1; } if (($newLine eq "#endif") && (($lastLine =~ /^#ifdef /) || ($lastLine =~ /^#ifndef /))) { $#stack --; $ok = 1; } if (($newLine eq "#casebreak") && (($lastLine =~ /^#casedef /) || ($lastLine eq "#defaultcase"))) { $#stack --; $ok = 1; } if (($newLine eq "#endswitchdef") && ($lastLine =~ /^#switchdef /)) { $#stack --; $ok = 1; } if (!$ok) { die("Stack corruption in preprocessor!\n$#stack\n$lastLine\n$newLine"); } my $retval = 1; for (my $i = 1; $i <= $#stack; $i++) { my $line = $stack[$i]; if (!$ok) { die("Stack corruption in preprocessor!\n$i\n$line;"); } $ok = 0; my $mustBeDefined; my $variableName; if ($line =~ /^#ifdef /) { $ok = 1; $mustBeDefined = 1; $variableName = substr($line, 7); $retval = ($mustBeDefined == $defines{$variableName}); if (!$retval) { last; } next; } if ($line =~ /^#ifndef /) { $ok = 1; $mustBeDefined = 0; $variableName = substr($line, 8); $retval = ($mustBeDefined == $defines{$variableName}); if (!$retval) { last; } next; } if ($line =~ /^#switchdef /) { $ok = 1; $retval = 0; # We go to next instead of break because there may be a casedef after us in the stack. next; } if ($line =~ /^#casedef /) { $lastLine = $stack[$i - 1]; if ($lastLine eq "#switchdef 0") { $ok = 1; $retval = 0; last; } if ($lastLine eq "#switchdef 1") { $ok = 1; $variableName = substr($line, 9); $retval = (1 == $defines{$variableName}); if ($retval) { $stack[$i - 1] = "#switchdef 0"; } next; } die("casedef must be child of switchdef!"); } if ($line eq "#defaultcase") { $lastLine = $stack[$i - 1]; if ($lastLine eq "#switchdef 0") { $retval = 0; $ok = 1; last; } if ($lastLine eq "#switchdef 1") { $retval = 1; $ok = 1; $stack[$i - 1] = "#switchdef 0"; next; } die("defaultcase must be child of switchdef!"); } } exitLog("updatePrintLine", @_); return ($retval, @stack); } sub preprocessIDL($) { my ($includeFile) = @_; enterLog("preprocessIDL", @_); my @stack = []; open(IDL_IN, "<$includeFile") || die("Can't open file $includeFile!"); my $outFile = substr($includeFile, 0, -3); open(IDL, ">$outFile") || die("Can't open file $includeFile!"); my $contents = ""; my $printLine = 1; while (my $line = ) { if ($line =~ /^[^#]/) { if ($printLine) { print IDL $line; } next; } if ($line =~ /^#include /) { if ($printLine) { print IDL $line; } next; } ($printLine, @stack) = updatePrintLine($line, @stack); next; # We never print #foo lines, except for #include. } close(IDL); close(IDL_IN); sleep(1); exitLog("preprocessIDL", @_); } sub main() { enterLog("main", @_); my ($srcdir) = processParameters(); my @DIR_FILES = split(/\n/, `ls $srcdir`); foreach my $i (@DIR_FILES) { chomp($i); if ($i =~ /\.idl\.in$/) { preprocessIDL("$srcdir/$i"); } } exitLog("main", @_); } main();