#!/usr/bin/perl # # generator.pl - auto-generate code for the CSSM plugin interfaces # # Usage: # perl generator.pl input-directory h-output-dir c-output-dir # # Perry The Cynic, Fall 1999. # @API_H=("cssmapi.h"); %SPI_H=("AC" => "cssmaci.h", "CSP" => "cssmcspi.h", "DL" => "cssmdli.h", "CL" => "cssmcli.h", "TP" => "cssmtpi.h"); $SOURCEPATH=$ARGV[0]; # where all the input files are $APICFG=$ARGV[1]; # configuration file $HTARGETDIR=$ARGV[2]; # where the generated headers go $CTARGETDIR=$ARGV[3]; # where the generated sources go $tabs = "\t\t\t"; # argument indentation (noncritical) $warning = "This file was automatically generated. Do not edit on penalty of futility!"; # # Open and read the configuration file # $/=undef; # gulp file open(APICFG, $APICFG) or die "Cannot open $APICFG: $^E"; $_=; close(APICFG); %optionals = /^\s*optional\s+(\w+:\w+)\s+(.*)$/gm; # # Pre-arranged arrays for processing below # %noDataReturnError = ( CL => "CSSMERR_CL_NO_FIELD_VALUES", DL => "CSSMERR_DL_ENDOFDATA" ); # # process one SPI at a time # while (($type, $header) = each %SPI_H) { my(%functions, %methods, %actuals); ($typelower = $type) =~ tr/A-Z/a-z/; # lowercase version of type # start in on the $type header file for my $sourcedir (split (/:/, $SOURCEPATH)) { open(SPI, "$sourcedir/$header") and last; } SPI or die "cannot find $header in $SOURCEPATH: $^E"; $/=undef; # big gulp mode $_ = ; # aaaaah... close(SPI); # done # throw away leading and trailing crud (only interested in SPI structure) s/^.*struct cssm_spi.*{(.*)} CSSM_SPI.*$/$1/s or die "bad format in $SPI_H{$name}"; # break up into functions (you'd do that HOW in YOUR language? :-) @functions = /CSSM_RETURN \(CSSM${type}I \*([A-Za-z_]+)\)\s+\(([^)]+)\);/g; %functions = @functions; $MOREHEADERS=""; $MOREHEADERS .= "#include \n" if /CSSM_CONTEXT/; $MOREHEADERS .= "#include \n" if /CSSM_(ACL|ACCESS)/; $MOREHEADERS .= "#include \n" if /CSSM_QUERY/; # break function arguments into many forms: # functions => formal SPI arguments # methods => formal C++ method arguments # actuals => actual expression forms for transition layer use # and (by the way) massage them into a more palatable form... $nFunctions = 0; while (($function, $_) = each %functions) { # # Turn CSSM SPI formal into method formal # $returntype{$function} = "void"; $prefix{$function} = ""; $postfix{$function} = ";"; # reshape initial argument (the module handle, more or less) s/^CSSM_${type}_HANDLE ${type}Handle(,\s*\n\s*|$)//s; # remove own handle (-> this) s/^CSSM_DL_DB_HANDLE DLDBHandle/CSSM_DB_HANDLE DBHandle/s; # DL_DB handle -> DB handle s/CSSM_HANDLE_PTR ResultsHandle(,?)\n//m # turn ptr-to-resultshandle into fn result and do { $returntype{$function} = "CSSM_HANDLE"; $prefix{$function} = "if ((Required(ResultsHandle) = "; $postfix{$function} = ") == CSSM_INVALID_HANDLE)\n return $noDataReturnError{$type};"; }; if ($function =~ /GetNext/) { # *GetNext* returns a bool $returntype{$function} = "bool"; $prefix{$function} = "if (!"; $postfix{$function} = ")\n return $noDataReturnError{$type};"; } # reshape subsequent arguments s/([su]int32) \*(\w+,?)/$1 \&$2/gm; # int * -> int & (output integer) s/(CSSM_\w+_PTR) \*(\w+,?)/$1 \&$2/gm; # _PTR * -> _PTR & s/(CSSM_\w+)_PTR (\w+)/$1 \*$2/gm; # XYZ_PTR -> XYZ * (explicit) s/(const )?CSSM_DATA \*(\w+)Bufs/$1CssmData $2Bufs\[\]/gm; # c DATA *Bufs (plural) s/(const )?CSSM_(DATA|OID) \*/$1CssmData \&/gm; # c DATA * -> c Data & s/(const )?CSSM_FIELD \*(\w+)Fields/$1CSSM_FIELD $2Fields\[\]/gm; # c FIELD *Fields (plural) s/(const )?CSSM_FIELD \*CrlTemplate/$1CSSM_FIELD CrlTemplate\[\]/gm; # c FIELD *CrlTemplate s/const CSSM_CONTEXT \*/const Context \&/gm; # c CSSM_CONTEXT * -> c Context & s/(const )?CSSM_ACCESS_CREDENTIALS \*/$1AccessCredentials \&/gm; # ditto s/(const )?CSSM_QUERY_SIZE_DATA \*/$1QuerySizeData \&/gm; # ditto s/(const )?CSSM_CSP_OPERATIONAL_STATISTICS \*/$1CSPOperationalStatistics \&/gm; # ditto s/(const )?CSSM_(WRAP_)?KEY \*/$1CssmKey \&/gm; # CSSM[WRAP]KEY * -> CssmKey & s/const CSSM_QUERY \*/const CssmQuery \&/gm; # c QUERY * -> c Query & s/(const )?(CSSM_[A-Z_]+) \*/$1$2 \&/gm; # c CSSM_ANY * -> c CSSM_ANY & $methods{$function} = $_; # # Now turn the method formal into the transition invocation actuals # s/^CSSM_DB_HANDLE \w+(,?)/DLDBHandle.DBHandle$1/s; # matching change to DL_DB handles s/(const )?([A-Z][a-z]\w+) &(\w+)(,?)/$2::required($3)$4/gm; # BIG_ * -> Small_ & s/(const )?CssmData (\w+)Bufs\[\](,?)/\&\&CssmData::required($2Bufs)$3/gm; # c DATA *DataBufs s/(const )?CSSM_FIELD (\w+)Fields\[\](,?)/$2Fields$3/gm; # c CSSM_FIELD *Fields s/(const )?CSSM_FIELD CrlTemplate\[\](,?)/CrlTemplate$2/gm; # c CSSM_FIELD *CrlTemplate # now remove formal arguments and clean up s/^.* \&\&(\w+,?)/$tabs\&$1/gm; # && escape (to keep real &) s/^.* \&(\w+)(,?)/${tabs}Required($1)$2/gm; # dereference for ref transition s/^.* \**(\w+,?)/$tabs$1/gm; # otherwise, plain actual argument s/^$tabs//; $actuals{$function} = $_; # # Fix optional arguments # foreach $opt (split " ", $optionals{"$type:$function"}) { $methods{$function} =~ s/\&$opt\b/\*$opt/; # turn refs back into pointers $actuals{$function} =~ s/::required\($opt\)/::optional($opt)/; # optional specific $actuals{$function} =~ s/Required\($opt\)/$opt/; # optional generic }; $nFunctions++; }; # # Prepare to write header and source files # open(H, ">$HTARGETDIR/${type}abstractsession.h") or die "cannot write ${type}abstractsession.h: $^E"; open(C, ">$CTARGETDIR/${type}abstractsession.cpp") or die "cannot write ${type}abstractsession.cpp: $^E"; # # Create header file # print H < #include $MOREHEADERS namespace Security { // // A pure abstract class to define the ${type} module interface // class ${type}AbstractPluginSession { public: virtual ~${type}AbstractPluginSession(); HDRHEAD $functionCount = 0; while (($function, $arglist) = each %methods) { # generate method declaration print H " virtual $returntype{$function} $function($arglist) = 0;\n"; $functionCount++; }; print H < #include #include #include ${type}AbstractPluginSession::~${type}AbstractPluginSession() { /* virtual */ } BODY # write transition layer functions while (($function, $arglist) = each %functions) { $lookupHandle = "${type}Handle"; $lookupHandle = "DLDBHandle.DLHandle" if $arglist =~ /DL_DB_HANDLE/; print C <($lookupHandle).$function($actuals{$function})${postfix{$function}} END_API($type) } SHIM }; # generate dispatch table - in the right order, please print C "\nstatic const CSSM_SPI_${type}_FUNCS ${type}FunctionStruct = {\n"; while ($function = shift @functions) { print C " cssm_$function,\n"; shift @functions; # skip over arglist part }; print C "};\n\n"; print C <