1#!/usr/bin/perl
2#
3# Copyright (c) 2001-2004 Apple Computer, Inc. All Rights Reserved.
4#
5# @APPLE_LICENSE_HEADER_START@
6#
7# This file contains Original Code and/or Modifications of Original Code
8# as defined in and that are subject to the Apple Public Source License
9# Version 2.0 (the 'License'). You may not use this file except in
10# compliance with the License. Please obtain a copy of the License at
11# http://www.opensource.apple.com/apsl/ and read it before using this
12# file.
13#
14# The Original Code and all software distributed under the License are
15# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
19# Please see the License for the specific language governing rights and
20# limitations under the License.
21#
22# @APPLE_LICENSE_HEADER_END@
23#
24# generator.pl - derive various and sundry C++ code from the CDSA header files
25#
26# Usage:
27#	perl generator.pl input-directory config-file output-directory
28#
29# Perry The Cynic, Fall 1999.
30#
31@API_H=("cssmapi.h");
32%SPI_H=("AC" => "cssmaci.h", "CSP" => "cssmcspi.h", "DL" => "cssmdli.h",
33        "CL" => "cssmcli.h", "TP"  => "cssmtpi.h");
34@OIDS_H=("oidscert.h", "oidscrl.h");
35@OIDS_H2=("oidsattr.h", "oidsalg.h");
36
37$SOURCEDIR=$ARGV[0];			# directory with inputs
38$APICFG=$ARGV[1];				# configuration file
39$TARGETDIR=$ARGV[2];			# directory for outputs
40
41
42$TRANSITION="$TARGETDIR/transition.gen"; # C++ code for transition layer
43$TABLES="$TARGETDIR/funcnames.gen";		# function name tables
44$REPORT="$TARGETDIR/generator.rpt";		# report file
45$EXPORTS="$TARGETDIR/cssmexports.gen";	# Exports file
46
47$tabs = "\t\t\t";	# argument indentation (noncritical)
48$warning = "This file was automatically generated. Do not edit on penalty of futility!";
49
50
51#
52# Parse API headers and extract function names and argument lists
53#
54# Jim Muprhy I added [^;]* to the end of the %formals variable to
55# allow for deprecation macros.
56#
57$/=undef;	# big gulp mode
58foreach $_ (@API_H) {
59  open(API_H, "$SOURCEDIR/$_") or die "Cannot open $SOURCEDIR/$_: $^E";
60  $_ = <API_H>;		# glglgl... aaaaah
61  %formals = /CSSM_RETURN CSSMAPI\s*([A-Za-z_]+)\s+\(([^)]*)\)[^;]*;/gs;
62  while (($name, $args) = each %formals) {
63    $args =~ s/^.*[ *]([A-Za-z_]+,?)$/$tabs$1/gm;	# remove type declarators
64    $args =~ s/^$tabs//o;	# chop intial tabs		# so now we have...
65    $actuals{$name} = $args;						# ...an actual argument list
66  };
67};
68close(API_H);
69
70
71#
72# Slurp SPI headers into memory for future use
73#
74$/=undef;	# slurp files
75while (($key, $file) = each %SPI_H) {
76  open(SPI_H, "$SOURCEDIR/$file") or die "Cannot open $SOURCEDIR/$file: $^E";
77  $spi{$key} = <SPI_H>;
78};
79close(SPI_H);
80
81
82#
83# Open and read the configuration file
84#
85$/=undef;	# gulp yet again
86open(APICFG, $APICFG) or die "Cannot open $APICFG: $^E";
87$_=<APICFG>;
88close(APICFG);
89%config = /^\s*(\w+)\s+(.*)$/gm;
90
91
92#
93# Now we will generate the API transition layer.
94# The idea here is that for each function in the API, we try to
95# figure out what type of plugin it belongs to, and then look up
96# its evil twin in that type's header. If that works, we generate
97# a function for the transition, taking care of various oddities
98# and endities in the process.
99#
100open(OUT, ">$TRANSITION") or die "Cannot write $TRANSITION: $^E";
101select OUT;
102open(REPORT, ">$REPORT") or die "Cannot write $REPORT: $^E";
103
104sub ignored {
105  my ($reason) = @_;
106  $ignored++;
107  print REPORT "$name $reason\n";
108};
109
110print "//
111// $warning
112//";
113
114for $name (sort keys %formals) {
115  $config = $config{$name};
116  do { ignored "has custom implementation"; next; } if $config =~ /custom/;
117
118  ($barename) = $name =~ /^CSSM.*_([A-Za-z]+$)/;
119  die "Can't fathom SPI name for $name" unless $barename;
120  $actuals = $actuals{$name};
121
122  # key off the type code in the first argument: CSSM_type_HANDLE
123  ($type, $handle) = $formals{$name} =~ /CSSM_([A-Z_]+)_HANDLE\s+([A-Za-z0-9_]+)/;
124  $type = "CSP" if $type eq "CC";	# CSP methods may have CC (context) handles
125  $type = "DL" if $type eq "DL_DB";	# DL methods may have DL_DB handles
126  $type = "KR" if $type eq "KRSP";	# KR methods have KRSP handles
127  $Type = $type . "Attachment";
128  do { ignored "has no module type"; next; } unless defined $SPI_H{$type};
129
130  # $prefix will hold code to be generated before the actual call
131  $prefix = "";
132
133  # match the SPI; take care of the Privilege variants of some calls
134  # Jim Murphy Added [^;]* before the ; to allow for deprecation macros
135  ($args) = $spi{$type} =~ /CSSM_RETURN \(CSSM${type}I \*$barename\)\s+\(([^)]*)\)[^;]*;/s
136    or $barename =~ s/P$// &&	# second chance for FooBarP() API functions
137      (($args) = $spi{$type} =~ /CSSM_RETURN \(CSSM${type}I \*$barename\)\s+\(([^)]*)\)[^;]*;/s)
138    or do { ignored "not in $SPI_H{$type}"; next; };
139
140  # take care of CSP calls taking context handles
141  $handletype = $type;
142  $type eq "CSP" && $actuals =~ /CCHandle/ && do {
143    $actuals =~ s/CCHandle/context.CSPHandle, CCHandle/;
144    $args =~ /CSSM_CONTEXT/ &&
145      $actuals =~ s/CCHandle/CCHandle, &context/;
146    $handletype = "CC";
147  };
148
149  # add the default privilege argument to non-P functions taking privileges
150  $args =~ /CSSM_PRIVILEGE/ && ! ($name =~ /P$/) &&			# add privilege argument (last)
151    ($actuals .= ",\n${tabs}attachment.module.cssm.getPrivilege()");
152
153  # finally translate DLDBHandles into their DL component
154  $handle =~ s/DLDBHandle/DLDBHandle.DLHandle/;
155
156  # payoff time
157  print "
158CSSM_RETURN CSSMAPI
159$name ($formals{$name})
160{
161  BEGIN_API";
162  if ($handletype eq "CC") {
163    print "
164  HandleContext &context = enterContext($handle);
165  CSPAttachment &attachment = context.attachment;";
166  } else {
167    print "
168  $Type &attachment = enterAttachment<$Type>($handle);";
169  };
170  print "
171  TransitLock _(attachment);
172  ${prefix}return attachment.downcalls.$barename($actuals);
173  END_API($type)
174}
175";
176  $written++;
177};
178close(OUT);
179select(STDOUT);
180
181
182#
183# Now peruse the SPI headers for a list of function names
184# and build in-memory translation tables for runtime.
185#
186open(OUT, ">$TABLES") or die "Cannot write $TABLES: $^E";
187select OUT;
188
189print "//
190// Standard plugin name tables
191// $warning
192//
193";
194while (($name, $_) = each %spi) {
195  print "extern const char *const ${name}NameTable[] = {";
196  s/^.*struct cssm_spi.*{(.*)} CSSM_SPI.*$/$1/s
197    or die "bad format in $SPI_H{$name}";
198  s/CSSM_RETURN \(CSSM[A-Z]*I \*([A-Za-z_]+)\)\s+\([^)]+\)[^;]*;/\t"$1",/g;
199  print;
200  print "};\n\n";
201};
202close(OUT);
203select(STDOUT);
204
205#
206# Finally, generate linker export file to avoid leaking internal symbols
207#
208open(OUT, ">$EXPORTS") or die "Cannot write $EXPORTS: $^E";
209select(OUT);
210
211# entry point names (functions)
212for $name (keys %formals) {
213  $symbols{$name} = 1;
214};
215
216# OID-related data symbols
217$/=undef;
218foreach $_ (@OIDS_H) {
219  open(OIDS_H, "$SOURCEDIR/$_") or die "Cannot open $SOURCEDIR/$_: $^E";
220  $_ = <OIDS_H>;		# glglgl... aaaaah
221  s/\/\*.*\*\///gm;	# remove comments
222
223  foreach $name (/\s+(CSSMOID_[A-Za-z0-9_]+)/gs) {
224    $symbols{$name} = 1;
225  };
226};
227close(OIDS_H);
228
229foreach $_ (@OIDS_H2) {
230    open(OIDS_H2, "$SOURCEDIR/../../libsecurity_asn1/lib/$_") or die "Cannot open $SOURCEDIR/$_: $^E";
231    $_ = <OIDS_H2>;		# glglgl... aaaaah
232    s/\/\*.*\*\///gm;	# remove comments
233
234    foreach $name (/\s+(CSSMOID_[A-Za-z0-9_]+)/gs) {
235        $symbols{$name} = 1;
236    };
237};
238close(OIDS_H2);
239
240foreach $name (keys %symbols) {
241  print "_$name\n";
242};
243
244close(OUT);
245select(STDOUT);
246
247
248close(EXPORTS);
249close(REPORT);
250print "$written API functions generated; $ignored ignored (see $REPORT)\n";
251