1#
2# Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
3# Use is subject to license terms.
4#
5# CDDL HEADER START
6#
7# The contents of this file are subject to the terms of the
8# Common Development and Distribution License, Version 1.0 only
9# (the "License").  You may not use this file except in compliance
10# with the License.
11#
12# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
13# or http://www.opensolaris.org/os/licensing.
14# See the License for the specific language governing permissions
15# and limitations under the License.
16#
17# When distributing Covered Code, include this CDDL HEADER in each
18# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
19# If applicable, add the following below this CDDL HEADER, with the
20# fields enclosed by brackets "[]" replaced with your own identifying
21# information: Portions Copyright [yyyy] [name of copyright owner]
22#
23# CDDL HEADER END
24#
25#ident	"%Z%%M%	%I%	%E% SMI"
26#
27# This script scans the exacct header files and extracts the names of any
28# #defines that are to be exported by the Exacct modules.  All such #defines
29# are written out as an array of structs to a file which is subsequently
30# included into the module.  Parameters to this script are the name of the
31# module to generate for, and the output file to use.
32#
33
34use warnings;
35use strict;
36
37# Forward declarations
38sub default_typefn;
39sub catalog_typefn;
40
41#
42# Map of module names to files and lists + patterns of macros to declare.
43# Each entry in the hash is keyed by the module name, and the value of each
44# entry is a list of actions, where each action is a (keyword, param) pair.
45# The valid actions are:
46#     typefn => <fn_ptr>
47#         fn_ptr is a function which when given a constant name,
48#         returns the type - see default_typefn and catalog_typefn.
49#     declare => [ <constant>, ... ]
50#         Add the passed list of constants.
51#     scan => [ <file> <regular expression> ]
52#         Scan the specified file in /usr/include
53#         for #defines that match the passed RE.
54#
55our %ModMap = (
56	Exacct => [
57		typefn	=> \&default_typefn,
58		declare	=> [ qw(P_PID P_TASKID P_PROJID) ],
59		scan 	=> [ 'sys/exacct.h' =>
60			     qr/(?:EW|EP|EXR)_\w+/ ],
61	],
62	Catalog => [
63		typefn	=> \&catalog_typefn,
64		scan 	=> [ 'sys/exacct_catalog.h' =>
65			     qr/EX[TCD]_\w+/ ],
66	],
67	File => [
68		typefn	=> \&default_typefn,
69		# From exacct.h.
70		declare	=> [ qw(EO_HEAD EO_TAIL EO_NO_VALID_HDR
71			     EO_POSN_MSK EO_VALIDATE_MSK) ],
72	],
73	Object => [
74		typefn	=> \&default_typefn,
75		# From sys/exacct.h.
76		declare	=> [ qw(EO_ERROR EO_NONE EO_ITEM EO_GROUP) ],
77	],
78);
79
80#
81# Constants may have a 'type' associated, currently only used by ::Catalog
82# (see below).  For all other cases the type is 'other'.
83#
84sub default_typefn
85{
86	return('other');
87}
88
89#
90# ::Catalog uses the 'type' field to determine whether a given constant is a
91# type, a catalog or a data id.  This function works out what type of constant
92# has been passed and returns the appropriate type.
93#
94sub catalog_typefn
95{
96	my ($define) = @_;
97	if ($define =~ /_MASK$/) {
98		return('other');
99	} elsif ($define =~ /^EXT_/) {
100		return('type');
101	} elsif ($define =~ /^EXC_/) {
102		return('catlg');
103	} elsif ($define =~ /^EXD_/) {
104		return('id');
105	} else {
106		return('other');
107	}
108}
109
110#
111# Process a C header file, looking for #defines of interest.  Candidates are
112# saved in the $defines arrayref.  Note nested includes are not processed.
113#
114sub process_file
115{
116	my ($file, $filelist, $pattern, $typefn, $defines) = @_;
117	my $fh;
118	if ($_ = (grep(m{/$file$}, @$filelist))[0]) {
119		open($fh, '<', $_) || die("Can't open $_: $!\n");
120	} else {
121		die("Can't find $file\n");
122	}
123	my $line;
124	while (defined($line = <$fh>)) {
125		if ($line =~ /#define\s+\b($pattern)\b/) {
126			$defines->{$1} = &$typefn($1);
127		}
128	}
129	close($fh);
130}
131
132#
133# Main routine.
134#
135
136# Check arguments and open the output file.
137die("Usage is extract_defines <module> <output file> <input files...>\n")
138    unless (@ARGV >= 2);
139my ($module, $outfile, @filelist) = @ARGV;
140my $mm;
141if (! defined($mm = $ModMap{$module})) {
142	die("Don't know how to handle module $module\n")
143}
144my $out;
145if (! open($out, ">$outfile")) {
146	die("Can't open $outfile: $!\n");
147}
148
149# Perform the appropriate set of actions from ModMap for the specified module.
150my $defines = {};
151my $tfn = \&default_typefn;
152my $i = 0;
153while ($i < @$mm) {
154	my $act = $$mm[$i++];
155	my $parm = $$mm[$i++];
156	if ($act eq 'typefn') {
157		$tfn = $parm;
158	} elsif ($act eq 'declare') {
159		foreach my $d (@$parm) {
160			$defines->{$d} = &$tfn($d);
161		}
162	} elsif ($act eq 'scan') {
163		process_file($parm->[0], \@filelist, $parm->[1], $tfn,
164		    $defines);
165	} else {
166		die("Illegal action $act\n");
167	}
168}
169
170# Print the structure definition.
171print $out ("static constval_t constants[] = {\n");
172foreach my $def (sort(keys(%$defines))) {
173	my $type = $defines->{$def};
174	my $len = length($def);
175	my $t = "\t" . "\t" x (3 - int(($len + 3) / 8));
176	print $out ("\t\"$def\",$t$len,\t$type,\n\t    (unsigned int) $def,\n");
177}
178print $out ("\tNULL,\t\t\t\t0,\tother,\n\t    0,\n};\n");
179close($out);
180exit(0);
181