1#!/usr/bin/perl
2#
3# generator.pl - auto-generate code for the CSSM plugin interfaces
4#
5# Usage:
6#	perl generator.pl input-directory h-output-dir c-output-dir
7#
8# Perry The Cynic, Fall 1999.
9#
10@API_H=("cssmapi.h");
11%SPI_H=("AC" => "cssmaci.h", "CSP" => "cssmcspi.h", "DL" => "cssmdli.h",
12        "CL" => "cssmcli.h", "TP"  => "cssmtpi.h");
13
14$SOURCEPATH=$ARGV[0];			# where all the input files are
15$APICFG=$ARGV[1];			# configuration file
16$HTARGETDIR=$ARGV[2];			# where the generated headers go
17$CTARGETDIR=$ARGV[3];			# where the generated sources go
18
19
20$tabs = "\t\t\t";	# argument indentation (noncritical)
21$warning = "This file was automatically generated. Do not edit on penalty of futility!";
22
23
24#
25# Open and read the configuration file
26#
27$/=undef;	# gulp file
28open(APICFG, $APICFG) or die "Cannot open $APICFG: $^E";
29$_=<APICFG>;
30close(APICFG);
31%optionals = /^\s*optional\s+(\w+:\w+)\s+(.*)$/gm;
32
33
34#
35# Pre-arranged arrays for processing below
36#
37%noDataReturnError = ( CL => "CSSMERR_CL_NO_FIELD_VALUES",
38					   DL => "CSSMERR_DL_ENDOFDATA" );
39
40
41#
42# process one SPI at a time
43#
44while (($type, $header) = each %SPI_H) {
45  my(%functions, %methods, %actuals);
46  ($typelower = $type) =~ tr/A-Z/a-z/;	# lowercase version of type
47
48  # start in on the $type header file
49  for my $sourcedir (split (/:/, $SOURCEPATH)) {
50    open(SPI, "$sourcedir/$header") and last;
51  }
52  SPI or die "cannot find $header in $SOURCEPATH: $^E";
53  $/=undef;		# big gulp mode
54  $_ = <SPI>;	# aaaaah...
55  close(SPI);	# done
56  # throw away leading and trailing crud (only interested in SPI structure)
57  s/^.*struct cssm_spi.*{(.*)} CSSM_SPI.*$/$1/s
58    or die "bad format in $SPI_H{$name}";
59
60  # break up into functions (you'd do that HOW in YOUR language? :-)
61  @functions = /CSSM_RETURN \(CSSM${type}I \*([A-Za-z_]+)\)\s+\(([^)]+)\);/g;
62  %functions = @functions;
63
64  $MOREHEADERS="";
65  $MOREHEADERS .= "#include <security_cdsa_utilities/context.h>\n" if /CSSM_CONTEXT/;
66  $MOREHEADERS .= "#include <security_cdsa_utilities/cssmacl.h>\n" if /CSSM_(ACL|ACCESS)/;
67  $MOREHEADERS .= "#include <security_cdsa_utilities/cssmdb.h>\n" if /CSSM_QUERY/;
68
69  # break function arguments into many forms:
70  #  functions => formal SPI arguments
71  #  methods => formal C++ method arguments
72  #  actuals => actual expression forms for transition layer use
73  # and (by the way) massage them into a more palatable form...
74  $nFunctions = 0;
75  while (($function, $_) = each %functions) {
76    #
77    # Turn CSSM SPI formal into method formal
78	#
79	$returntype{$function} = "void";
80    $prefix{$function} = "";
81	$postfix{$function} = ";";
82    # reshape initial argument (the module handle, more or less)
83    s/^CSSM_${type}_HANDLE ${type}Handle(,\s*\n\s*|$)//s; # remove own handle (-> this)
84    s/^CSSM_DL_DB_HANDLE DLDBHandle/CSSM_DB_HANDLE DBHandle/s; # DL_DB handle -> DB handle
85    s/CSSM_HANDLE_PTR ResultsHandle(,?)\n//m	   	# turn ptr-to-resultshandle into fn result
86      and do {
87		$returntype{$function} = "CSSM_HANDLE";
88		$prefix{$function} = "if ((Required(ResultsHandle) = ";
89		$postfix{$function} = ") == CSSM_INVALID_HANDLE)\n    return $noDataReturnError{$type};";
90	  };
91	if ($function =~ /GetNext/) {					# *GetNext* returns a bool
92	  $returntype{$function} = "bool";
93	  $prefix{$function} = "if (!";
94	  $postfix{$function} = ")\n    return $noDataReturnError{$type};";
95	}
96    # reshape subsequent arguments
97	s/([su]int32) \*(\w+,?)/$1 \&$2/gm;				# int * -> int & (output integer)
98    s/(CSSM_\w+_PTR) \*(\w+,?)/$1 \&$2/gm;			# _PTR * -> _PTR &
99	s/(CSSM_\w+)_PTR (\w+)/$1 \*$2/gm;				# XYZ_PTR -> XYZ * (explicit)
100	s/(const )?CSSM_DATA \*(\w+)Bufs/$1CssmData $2Bufs\[\]/gm; # c DATA *Bufs (plural)
101    s/(const )?CSSM_(DATA|OID) \*/$1CssmData \&/gm;	# c DATA * -> c Data &
102	s/(const )?CSSM_FIELD \*(\w+)Fields/$1CSSM_FIELD $2Fields\[\]/gm; # c FIELD *Fields (plural)
103	s/(const )?CSSM_FIELD \*CrlTemplate/$1CSSM_FIELD CrlTemplate\[\]/gm; # c FIELD *CrlTemplate
104	s/const CSSM_CONTEXT \*/const Context \&/gm;	# c CSSM_CONTEXT * -> c Context &
105	s/(const )?CSSM_ACCESS_CREDENTIALS \*/$1AccessCredentials \&/gm; # ditto
106	s/(const )?CSSM_QUERY_SIZE_DATA \*/$1QuerySizeData \&/gm; # ditto
107	s/(const )?CSSM_CSP_OPERATIONAL_STATISTICS \*/$1CSPOperationalStatistics \&/gm; # ditto
108    s/(const )?CSSM_(WRAP_)?KEY \*/$1CssmKey \&/gm;	# CSSM[WRAP]KEY * -> CssmKey &
109    s/const CSSM_QUERY \*/const CssmQuery \&/gm;		# c QUERY * -> c Query &
110	s/(const )?(CSSM_[A-Z_]+) \*/$1$2 \&/gm;		# c CSSM_ANY * -> c CSSM_ANY &
111    $methods{$function} = $_;
112
113	#
114    # Now turn the method formal into the transition invocation actuals
115	#
116    s/^CSSM_DB_HANDLE \w+(,?)/DLDBHandle.DBHandle$1/s;		# matching change to DL_DB handles
117	s/(const )?([A-Z][a-z]\w+) &(\w+)(,?)/$2::required($3)$4/gm; # BIG_ * -> Small_ &
118	s/(const )?CssmData (\w+)Bufs\[\](,?)/\&\&CssmData::required($2Bufs)$3/gm; # c DATA *DataBufs
119	s/(const )?CSSM_FIELD (\w+)Fields\[\](,?)/$2Fields$3/gm; # c CSSM_FIELD *Fields
120	s/(const )?CSSM_FIELD CrlTemplate\[\](,?)/CrlTemplate$2/gm; # c CSSM_FIELD *CrlTemplate
121    # now remove formal arguments and clean up
122	s/^.* \&\&(\w+,?)/$tabs\&$1/gm;					# && escape (to keep real &)
123	s/^.* \&(\w+)(,?)/${tabs}Required($1)$2/gm;		# dereference for ref transition
124    s/^.* \**(\w+,?)/$tabs$1/gm;					# otherwise, plain actual argument
125    s/^$tabs//;
126    $actuals{$function} = $_;
127
128	#
129	# Fix optional arguments
130	#
131	foreach $opt (split " ", $optionals{"$type:$function"}) {
132	  $methods{$function} =~ s/\&$opt\b/\*$opt/;	# turn refs back into pointers
133	  $actuals{$function} =~ s/::required\($opt\)/::optional($opt)/; # optional specific
134	  $actuals{$function} =~ s/Required\($opt\)/$opt/; # optional generic
135	};
136    $nFunctions++;
137  };
138
139  #
140  # Prepare to write header and source files
141  #
142  open(H, ">$HTARGETDIR/${type}abstractsession.h") or die "cannot write ${type}abstractsession.h: $^E";
143  open(C, ">$CTARGETDIR/${type}abstractsession.cpp") or die "cannot write ${type}abstractsession.cpp: $^E";
144
145  #
146  # Create header file
147  #
148  print H <<HDRHEAD;
149//
150// $type plugin transition layer.
151// $warning
152//
153#ifndef _H_${type}ABSTRACTSESSION
154#define _H_${type}ABSTRACTSESSION
155
156#include <security_cdsa_plugin/pluginsession.h>
157#include <security_cdsa_utilities/cssmdata.h>
158$MOREHEADERS
159
160namespace Security {
161
162
163//
164// A pure abstract class to define the ${type} module interface
165//
166class ${type}AbstractPluginSession {
167public:
168	virtual ~${type}AbstractPluginSession();
169HDRHEAD
170
171  $functionCount = 0;
172  while (($function, $arglist) = each %methods) {
173    # generate method declaration
174    print H "  virtual $returntype{$function} $function($arglist) = 0;\n";
175    $functionCount++;
176  };
177  print H <<HDREND;
178};
179
180} // end namespace Security
181
182#endif //_H_${type}ABSTRACTSESSION
183HDREND
184
185  #
186  # Create source file
187  #
188  print C <<BODY;
189//
190// $type plugin transition layer.
191// $warning
192//
193#include <security_cdsa_plugin/${type}session.h>
194#include <security_cdsa_plugin/cssmplugin.h>
195#include <security_cdsa_utilities/cssmbridge.h>
196#include <Security/cssm${typelower}i.h>
197
198
199${type}AbstractPluginSession::~${type}AbstractPluginSession()
200{ /* virtual */ }
201
202BODY
203
204  # write transition layer functions
205  while (($function, $arglist) = each %functions) {
206    $lookupHandle = "${type}Handle";
207	$lookupHandle = "DLDBHandle.DLHandle" if $arglist =~ /DL_DB_HANDLE/;
208    print C <<SHIM;
209static CSSM_RETURN CSSM${type}I cssm_$function($arglist)
210{
211  BEGIN_API
212  ${prefix{$function}}findSession<${type}PluginSession>($lookupHandle).$function($actuals{$function})${postfix{$function}}
213  END_API($type)
214}
215
216SHIM
217  };
218
219  # generate dispatch table - in the right order, please
220  print C "\nstatic const CSSM_SPI_${type}_FUNCS ${type}FunctionStruct = {\n";
221  while ($function = shift @functions) {
222    print C "  cssm_$function,\n";
223    shift @functions;	# skip over arglist part
224  };
225  print C "};\n\n";
226
227  print C <<END;
228static CSSM_MODULE_FUNCS ${type}FunctionTable = {
229  CSSM_SERVICE_$type,	// service type
230  $functionCount,	// number of functions
231  (const CSSM_PROC_ADDR *)&${type}FunctionStruct
232};
233
234CSSM_MODULE_FUNCS_PTR ${type}PluginSession::construct()
235{
236   return &${type}FunctionTable;
237}
238END
239
240  #
241  # Done with this type
242  #
243  close(H);
244  close(C);
245
246  print "$nFunctions functions generated for $type SPI transition layer.\n";
247};
248