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