#!/usr/perl5/bin/perl -w # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2007 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" # # auditxml [-d] # auditxml takes the audit record description (.xml file) and # generates the files needed for the C audit api. use auditxml; use Getopt::Std; use vars qw($opt_d); use strict; our $debug = 0; # normal use is to set via the file being parsed. # or or # if the set attribute is omitted, debug state is toggled # Override with appDebug, but toggle won't do what you # want. my $appDebug = 0; # used after return from "new auditxml"; my $genNotice = " DO NOT EDIT. This file is auto generated by the Solaris Audit system from adt.xml. See http://opensolaris.org/os/project/audit/ "; # trim leading/trailing newlines $genNotice =~ s/^\n//s; $genNotice =~ s/\n$//s; my $prog = $0; $prog =~ s|.*/||g; my $usage = "usage: $prog [-d] file.xml\n"; getopts('d'); $appDebug = $opt_d; my $uniLabel = "adr"; my $xlateUniLabelInc = 0; die $usage if ($#ARGV < 0); # where everything comes from and where it goes: my $bsmBuildPath = "./common"; my $xlateFile = "$bsmBuildPath/adt_xlate.c"; my $headerFile = "$bsmBuildPath/adt_event_N.h"; my $doc = new auditxml ($ARGV[0]); # input XML file $debug = $appDebug; my %xlateEventTable = (); my @xlateTypeList = (); my %xlateTypeList = (); my %eventAPI = (); my %eventExtra = (); my %headers = (); my %externalIdNo = (); my @outputState = (); my %nameTranslation = (); my @xlateDefaults = (); my %xlateDefault = (); my %msg_list = (); my $event; while ($event = $doc->getNextEvent()) { my $eventId = $event->getId(); my $eventHeader = $event->getHeader(); my $idNo = $event->getIdNo(); $externalIdNo{$eventId} = $idNo; addHeader($eventHeader) if defined ($eventHeader); my $super; my $omit = $event->getOmit(); my $eventType = ''; if ($super = $event->getSuperClass()) { $event = $super; $eventType = 'instance'; } else { $eventType = $event->getType(); } # header file for API use generateAPIFile($event, $eventId, $eventType, $eventHeader, $idNo) unless $omit eq 'always'; # c file table for translation generateTableC($event, $eventId, $eventType, $eventHeader, $omit); } my $textList; while ($textList = $doc->getNextMsgId()) { generateMsgLists($textList); # enum -> text mappings } printTableC($xlateFile); printAPIFile($headerFile, $doc); exit 0; sub printTableC { my $file = shift; unless (open(Cfile, ">$file")) { print STDERR "can't open output file ($file): $!\n"; return; } my $notice = $genNotice; $notice =~ s/\n/\n * /gs; $notice =~ s/\s+\n/\n/gs; print Cfile < #include #include EOF print Cfile "#ifndef _PRAUDIT\n"; print Cfile "/* Internal data type definitions */\n\n"; my $extDef; foreach $extDef (@xlateTypeList) { print Cfile "static $extDef\n"; } @xlateTypeList = (); print Cfile "\n/* External event structure to internal event structure */\n\n"; my @pointers = (); foreach my $eventId (sort keys %xlateEventTable) { if ($xlateEventTable{$eventId}) { my ($ref1, $eventType, $firstToken, $eventHeader) = @{$xlateEventTable{$eventId}}; my @entries = @$ref1; my $entry; my $entries = $#entries; my $count = $entries + 1; my $externalName = $nameTranslation{$eventId}; my $externalRoot = $externalName; $externalRoot =~ s/AUE_//; my $structName = "XX_$externalRoot"; my $root = $eventId; $root =~ s/AUE_//; my $externalId = $eventId; $externalId =~ s/AUE_/ADT_/; unless ($eventType eq 'generic') { print Cfile "static struct entry $structName\[$count\] = {\n"; foreach $entry (@entries) { if ($entries--) { $entry =~ s/EOL/,/; } else { $entry =~ s/EOL//; } $entry =~ s/selfReference/$structName/; print Cfile "\t$entry\n"; } print Cfile "};\n"; print Cfile "static struct translation X_$externalRoot = {\n"; push (@pointers, "X_$externalRoot"); print Cfile "\t0,\n"; # tx_offsetsCalculated = 0 print Cfile "\t$externalId,\n"; print Cfile "\t$externalName,\n"; print Cfile "\t$count,\n"; print Cfile "\t&XX_$externalRoot\[$firstToken\],\n"; print Cfile "\t&XX_$externalRoot\[0\]\n};\n"; } } else { print STDERR "expected entry for $eventId but none found\n"; } } my $count = $#pointers + 2; print Cfile "struct translation *xlate_table[$count] = {\n"; my $firstEvent = 1; foreach my $eventId (@pointers) { if ($firstEvent) { $firstEvent = 0; } else { print Cfile ",\n"; } print Cfile "\t&$eventId"; } print Cfile ",\n\tNULL\n};\n"; # generate the adt_preload() function print Cfile <$lcid.$fieldName = $default; EOF } print Cfile < 0) { $include = "adt_event.h"; $adt_event_n = "_ADT_EVENT_".$header."_H"; } print Hfile < #ifdef __cplusplus extern "C" { #endif /* * adt_put_event() status values. Positive values are for kernel-generated * failure, -1 for user-space. For ADT_SUCCESS, the adt_put_event() return_val * is not used; the convention is to set it to ADT_SUCCESS. */ #define ADT_SUCCESS 0 #define ADT_FAILURE -1 EOF } foreach my $listName (sort keys %msg_list) { my $shortName = uc $listName; $shortName =~ s/_TEXT//; my ($listRef, $headref) = @{$msg_list{$listName}}; my ($header, $start, $public, $deprecated) = @$headref; next unless $Hfile[$header]; *Hfile = $Hfile[$header]; print Hfile "/* Deprecated message list */\n" if $deprecated; print Hfile "#define\tADT_$shortName\t$start\n" if $start; my @listValue = @$listRef; next unless ($#listValue >= 0); print Hfile "enum\tadt_$listName", " {\n"; my $listValue; my $i = 0; my $j = $#listValue; my $comma = ','; foreach $listValue (@listValue) { my ($id, $text) = split(/\s*::\s*/, $listValue); $comma = '' if $i++ == $j; if ($start) { $start = " = $start$comma"; } else { $start = "$comma\t"; } $text = "(no token will be generated)" unless $text; my $line = "\tADT_$shortName"."_$id$start\t/* "; # ensure whole line does not exceed 80 chars my $eline = $line.$text; #expand tabs 1 while $eline =~ s/\t+/' ' x (length($&) * 8 - length($`) % 8)/e; if ((length($eline) > 77) && ($line =~ /\t\t/)) { # 77 = 80 - length(" */") # strip off double tab so that comment can be longer $line =~ s/\t\t/\t/; # shorten eline; don't mind where the spaces are removed, it is # only $eline length which matters $eline =~ s/ {8}//; } if (length($eline) > 77) { # 80 - length(" */") # here we use negative length in substr to leave off from the # right side; 74 = 77 - length("...") $line .= substr($text, 0, 74 - length($eline)); # strip off part of last word (already cut) $line =~ s/\s(\S+)$/ /; $line .= "..."; } else { $line .= $text; } print Hfile "$line */\n"; $start = ''; } print Hfile "};\n"; } # generate defines for ADT_* external event names foreach my $eventId (sort keys %eventAPI) { my ($header, $idNo) = @{$eventExtra{$eventId}}; unless (defined ($header)) { print STDERR "missing header selection for $eventId\n"; next; } *Hfile = $Hfile[$header]; next unless $Hfile[$header]; my $l = length($eventId) + 8; # label plus preceding #define\t $l = 5 - int(($l + 8)/8); $l = 1 if $l < 1; my $tab = "\t" x $l; print STDERR "missing id number for $eventId\n" unless $idNo; $eventId =~ s/AUE_/ADT_/; print Hfile "#define\t$eventId$tab$idNo\n"; } # generate per-event structures foreach my $eventId (sort keys %eventAPI) { my ($header, $idNo) = @{$eventExtra{$eventId}}; my $dataId = $eventId; $dataId =~ s/^AUE_/adt_/; unless(defined ($header)) { print STDERR "$eventId is missing the header assignment\n"; next; } *Hfile = $Hfile[$header]; next unless $Hfile[$header]; my $externalId = $eventId; $externalId =~ s/AUE_/ADT_/; print Hfile "\nstruct $dataId {\t/* $externalId */\n"; my @entries = @{$eventAPI{$eventId}}; my $entry; if ($#entries < 0) { print Hfile "\tint\tdummy;\t/* not used */\n"; } else { foreach $entry (@entries) { $entry =~ s/termid/adt_termid_t/; print Hfile "\t$entry\n"; } } print Hfile "};\n"; $eventId =~ s/^AUE_/adt_/; print Hfile "typedef struct $dataId $eventId","_t;\n"; } foreach my $header (sort keys %headers) { $outputState[$header] = 0; } foreach my $eventId (sort keys %eventAPI) { my ($header, $idNo) = @{$eventExtra{$eventId}}; unless(defined ($header)) { # don't print duplicate error message next; } *Hfile = $Hfile[$header]; next unless $Hfile[$header]; if ($outputState[$header] == 0) { $outputState[$header] = 1; my $suffix = ''; $suffix = "_$header" if $header; print Hfile "\nunion adt_event_data$suffix {\n"; } my $elementName = $eventId; $elementName =~ s/^AUE_/adt_/; $eventId =~ s/^AUE_/adt_/; $elementName =~ s/_t$//; print Hfile "\t\t$eventId","_t\t$elementName;\n"; } foreach my $header (sort keys %headers) { if ($outputState[$header]) { *Hfile = $Hfile[$header]; next unless $Hfile[$header]; print Hfile "};\n"; } } foreach my $header (keys %headers) { next unless $Hfile[$header]; *Hfile = $Hfile[$header]; my $adt_event_n = "_ADT_EVENT_H"; if ($header > 0) { $adt_event_n = "_ADT_EVENT_".$header."_H"; } print Hfile < 'AUT_ACL', # not defined # 'arbitrary' => 'AUT_ARBITRARY', # not defined # 'arg' => 'AUT_ARG', # not defined # 'attr' => 'AUT_ATTR', 'command' => 'AUT_CMD', 'command_1' => 'ADT_CMD_ALT', # dummy token id # 'date' => 'AUT_TEXT', # not used # 'exec_args' => 'AUT_EXEC_ARGS', # not defined # 'exec_env' => 'AUT_EXEC_ENV', # not defined # 'exit' => 'AUT_EXIT', # not defined 'fmri' => 'AUT_FMRI', # 'groups' => 'AUT_GROUPS', # not defined # 'header' => 'AUT_HEADER', # not defined 'in_peer' => 'ADT_IN_PEER', # dummy token id 'tid' => 'AUT_TID', # 'ipc' => 'AUT_IPC', # not defined # 'ipc_perm' => 'AUT_IPC_PERM', # not defined # 'iport' => 'AUT_IPORT', # not defined 'label' => 'AUT_LABEL', 'newgroups' => 'AUT_NEWGROUPS', # 'opaque' => 'AUT_OPAQUE', # not defined 'path' => 'AUT_PATH', 'path_list' => '-AUT_PATH', # dummy token id 'process' => 'AUT_PROCESS', 'priv_effective' => 'ADT_AUT_PRIV_E', # dummy token id 'priv_limit' => 'ADT_AUT_PRIV_L', # dummy token id 'priv_inherit' => 'ADT_AUT_PRIV_I', # dummy token id 'return' => 'AUT_RETURN', # 'seq' => 'AUT_SEQ', # not defined # 'socket' => 'AUT_SOCKET', # not defined # 'socket-inet' => 'AUT_SOCKET_INET', 'subject' => 'AUT_SUBJECT', 'text' => 'AUT_TEXT', # 'trailer' => 'AUT_TRAILER', # not defined 'uauth' => 'AUT_UAUTH', 'zonename' => 'AUT_ZONENAME' ); my @xlateEntryList = (); my $external = $event->getExternal(); my $internal = $event->getInternal(); unless ($external) { print STDERR "No external object captured for event $eventId\n"; return; } if ($eventType) { $nameTranslation{$eventId} = $eventId; } else { $nameTranslation{$eventId} = $external->getInternalName(); } unless ($internal) { print STDERR "No internal object captured for event $eventId\n"; return; } my @entryRef = $internal->getEntries(); my $entryRef; my @tokenOrder = (); my $firstTokenIndex = 0; # djdj not used yet, djdj BUG! # needs to be used by translate table if ($internal->isReorder()) { # prescan the entry list to get the token order my @inputOrder; foreach $entryRef (@entryRef) { my ($intEntry, $entry) = @$entryRef; push (@inputOrder, $intEntry->getAttr('order')); } my $i; # walk down the inputOrder list once my $k = 1; # discover next in line my $l = 0; # who should point to next in line for ($i = 0; $i <= $#inputOrder; $i++) { my $j; for ($j = 0; $j <= $#inputOrder; $j++) { if ($k == $inputOrder[$j]) { if ($k == 1) { $firstTokenIndex = $j; } else { $tokenOrder[$l] = "&(selfReference[$j])"; } $l = $j; last; } } $k++; } $tokenOrder[$l] = 'NULL'; } else { # default order -- input order same as output my $i; my $j; for ($i = 0; $i < $#entryRef; $i++) { my $j = $i + 1; $tokenOrder[$i] = "&(selfReference[$j])"; } $tokenOrder[$#entryRef] = 'NULL'; } my $sequence = 0; foreach $entryRef (@entryRef) { my ($intEntry, $entry) = @$entryRef; my $entryId = $entry->getAttr('id'); my ($extEntry, $unusedEntry, $tokenId) = $external->getEntry($entryId); my $opt = $extEntry->getAttr('opt'); if ($opt eq 'none') { if (defined ($doc->getToken($tokenId))) { if (defined ($tokenType{$tokenId})) { $tokenId = $tokenType{$tokenId}; } else { print STDERR "token id $tokenId not implemented\n"; } } else { print STDERR "token = $tokenId is undefined\n"; $tokenId = 'error'; } my ($xlate, $jni) = formatTableEntry ('', $tokenId, $eventId, '', 0, 0, $tokenOrder[$sequence], 'NULL', $omit); push (@xlateEntryList, $xlate); } else { my $dataType = $extEntry->getAttr('type'); $dataType =~ s/\s+//g; # remove blanks (char * => char*) my $enumGroup = ''; if ($dataType =~ /^msg/i) { $enumGroup = $dataType; $enumGroup =~ s/^msg\s*//i; $enumGroup = 'adt_' . $enumGroup; } my $required = ($opt eq 'required') ? 1 : 0; my $tsol = 0; my $tokenId = $intEntry->getAttr('token'); my $token; my $tokenName; my $tokenFormat = $intEntry->getAttr('format'); if (defined ($tokenFormat)) { $tokenFormat = "\"$tokenFormat\""; } else { $tokenFormat = 'NULL'; } if (defined ($token = $doc->getToken($tokenId))) { $tsol = (lc $token->getUsage() eq 'tsol') ? 1 : 0; if (defined ($tokenType{$tokenId})) { $tokenName = $tokenType{$tokenId}; } else { print STDERR "token id $tokenId not implemented\n"; } } else { print STDERR "$tokenId is an unimplemented token ($entryId in $eventId)\n"; $tokenName = 'AUT_TEXT'; } my ($xlate, $jni) = formatTableEntry($entryId, $tokenName, $eventId, $dataType, $required, $tsol, $tokenOrder[$sequence], $tokenFormat, $enumGroup, $omit); push (@xlateEntryList, $xlate); } $sequence++; } $xlateEventTable{$eventId} = [\@xlateEntryList, $eventType, $firstTokenIndex, $eventHeader]; } sub formatTableEntry { my ($id, $token, $eventId, $type, $required, $tsol, $sequence, $format, $enumGroup, $omitEntry) = @_; # does this map belong in the xml source? (at least the defaults?) # fill in the default value only if it is other than zero. # base type adt name, default value my %entryDef = ( 'au_asid_t' => ['ADT_UINT32', ''], 'uint_t' => ['ADT_UINT32', ''], 'int' => ['ADT_INT', ''], 'int32_t' => ['ADT_INT32', ''], 'uid_t' => ['ADT_UID', 'AU_NOAUDITID'], 'gid_t' => ['ADT_GID', 'AU_NOAUDITID'], 'uid_t*' => ['ADT_UIDSTAR', ''], 'gid_t*' => ['ADT_GIDSTAR', ''], 'char' => ['ADT_CHAR', ''], 'char*' => ['ADT_CHARSTAR', ''], 'char**' => ['ADT_CHAR2STAR', ''], 'long' => ['ADT_LONG', ''], 'pid_t' => ['ADT_PID', ''], 'priv_set_t*' => ['ADT_PRIVSTAR', ''], 'ulong_t' => ['ADT_ULONG', ''], 'uint16_t', => ['ADT_UINT16', ''], 'uint32_t' => ['ADT_UINT32', ''], 'uint32_t*' => ['ADT_UINT32STAR', ''], 'uint32_t[]' => ['ADT_UINT32ARRAY', ''], 'uint64_t' => ['ADT_UINT64', ''], 'uint64_t*' => ['ADT_UINT64STAR', ''], 'm_label_t*' => ['ADT_MLABELSTAR', ''], ); my $xlateLabel = $uniLabel.$xlateUniLabelInc; my $xlateLabelInc = 0; my $xlateLine = ''; my @jniLine = (); # the list handling should be a simple loop with a loop of one # falling out naturally. unless ($type =~ /,/) { # if list, then generate sequence of entries my $dataType; my $dataSize; my $xlateLabelRef = ''; my $arraySize = ''; $arraySize = $1 if ($type =~ s/\[(\d+)\]/[]/); my $entryType = ${$entryDef{$type}}[0]; my @xlateType = (); # for adt_xlate.c my $typeCount = 1; if ($entryType) { $dataType = $entryType; $type =~ s/([^*]+)\s*(\*+)/$1 $2/; $type =~ s/\[\]//; $dataSize = "sizeof ($type)"; if ($arraySize) { $dataSize = "$arraySize * " . $dataSize; } $xlateLine = "{{$dataType, $dataSize}}"; push (@jniLine, [$id, $dataType, $format, $enumGroup, $required]); } elsif ($type eq '') { $xlateLabelRef = 'NULL'; } elsif ($type =~ /^msg/i) { $type =~ s/^msg//i; $dataType = 'ADT_MSG'; my $dataEnum = 'ADT_LIST_' . uc $type; $xlateLine = "{{$dataType, $dataEnum}}"; push (@jniLine, [$id, $dataType, $format, $enumGroup, $required]); } elsif ($type =~ /time_t/i) { $dataType = 'ADT_DATE'; $dataSize = "sizeof (time_t)"; $xlateLine = "{{$dataType, $dataSize}}"; push (@jniLine, [$id, $dataType, $format, $enumGroup, $required]); } elsif ($type =~ /termid/i) { $dataType = 'ADT_TERMIDSTAR'; $dataSize = "sizeof (au_tid_addr_t *)"; $xlateLine = "{{$dataType, $dataSize}}"; push (@jniLine, [$id, $dataType, $format, $enumGroup, $required]); } elsif (uc $omitEntry eq 'JNI') { $xlateLabelRef = 'NULL'; } else { print STDERR "$type is not an implemented data type\n"; $xlateLabelRef = 'NULL'; } if ($xlateLine && !($xlateTypeList{$xlateLine})) { $xlateTypeList{$xlateLine} = $xlateLabel; push (@xlateTypeList, "datadef\t$xlateLabel\[1\] =\t$xlateLine;"); $xlateLabelInc = 1; } else { $xlateLabel = $xlateTypeList{$xlateLine}; } $xlateLabelRef = '&' . $xlateLabel . '[0]' unless $xlateLabelRef eq 'NULL'; # "EOL" is where a comma should go unless end of list $xlateLine = "{$token,\t1,\t$xlateLabelRef,\t$sequence,\n" . "\t\t0,\t$required,\t$tsol,\t$format}EOL"; if (uc $omitEntry ne 'ALWAYS' && ${$entryDef{$type}}[1]) { my @list = (); if ($xlateDefault{$eventId}) { @list = @{$xlateDefault{$eventId}}; } else { push (@xlateDefaults, $eventId); } push (@list, $id, ${$entryDef{$type}}[1]); $xlateDefault{$eventId} = \@list; } } else { # is a list my @type = split(/,/, $type); my @arraySize = (); my @id = split(/,/, $id); my @jniId = @id; my $dataType; my $typeCount = ($#type + 1); my @xlateType = (); my @default = (); foreach my $dtype (@type) { my $jniId = shift @jniId; my $id = shift @id; my $arraySize = ''; $arraySize = $1 if ($dtype =~ s/\[(\d+)\]/[]/); my $entryType = ${$entryDef{$dtype}}[0]; if ($entryType) { my $type = $dtype; $type =~ s/([^*]+)\s*(\*+)/$1 $2/; $type =~ s/\[\]//; my $sizeString = "sizeof"; $sizeString = "$arraySize * " . $sizeString if $arraySize; push (@xlateType, "\{$entryType, $sizeString ($type)\}"); push (@jniLine, [$jniId, $entryType, $format, $enumGroup, $required]); } elsif ($type =~ /^msg/i) { $type =~ s/^msg//i; $dataType = 'ADT_MSG'; my $dataEnum = 'ADT_LIST_' . uc $type; push (@xlateType, "\{$dataType, $dataEnum\}};"); push (@jniLine, [$jniId, $dataType, $format, $enumGroup, $required]); } elsif ($type =~ /time_t/i) { $dataType = 'ADT_DATE'; push (@xlateType, "\{$entryType, sizeof ($type)\}"); push (@jniLine, [$jniId, $entryType, $format, $enumGroup, $required]); } elsif ($type =~ /termid/i) { $dataType = 'ADT_TERMIDSTAR'; push (@xlateType, "\{$dataType, sizeof (au_tid_addr_t *)\}"); push (@jniLine, [$jniId, $dataType, $format, $enumGroup, $required]); } elsif (uc $omitEntry eq 'JNI') { # nothing to do. } else { print STDERR "$dtype is not an implemented data type\n"; } if (uc $omitEntry ne 'ALWAYS' && ${$entryDef{$dtype}}[1]) { push (@default, $id, ${$entryDef{$dtype}}[1]); } } my $xlateArray = "\[$typeCount\] =\t{" . join(",\n\t\t\t\t", @xlateType) . "};"; unless ($xlateTypeList{$xlateArray}) { $xlateTypeList{$xlateArray} = $xlateLabel; $xlateArray = "datadef\t$xlateLabel" . $xlateArray; push (@xlateTypeList, $xlateArray); $xlateLabelInc = 1; } else { $xlateLabel = $xlateTypeList{$xlateArray}; } $xlateLine = "{$token,\t$typeCount,\t&$xlateLabel\[0\],\t$sequence,\n" . "\t\t0,\t$required,\t$tsol,\t$format}EOL"; if (@default) { my @list = (); if ($xlateDefault{$eventId}) { @list = @{$xlateDefault{$eventId}}; } else { push (@xlateDefaults, $eventId); } push (@list, @default); $xlateDefault{$eventId} = \@list; } } $xlateUniLabelInc++ if $xlateLabelInc; return ($xlateLine, \@jniLine); } sub generateAPIFile { my $event = shift; my $eventId = shift; my $eventType = shift; my $eventHeader = shift; my $idNo = shift; my @entryList = (); my $external = $event->getExternal(); if ($eventType && $debug) { print STDERR "event $eventId is of type $eventType\n"; } return unless $external; my ($extEntry, $entry, $tokenId, $format); while (($extEntry, $entry, $tokenId, $format) = $external->getNextEntry()) { last unless $entry; my $entryId = $entry->getAttr('id'); unless (defined $entryId) { print STDERR "undefined entry id for external $eventId\n"; next; } my $option = $extEntry->getAttr('opt'); next if ($option eq 'none'); if (defined (my $token = $doc->getToken($tokenId))) { $option = 'Trusted Solaris only' if (lc $token->getUsage() eq 'tsol') ? 1 : 0; } $option .= " (format: $format)" if $format; my $dataType = $extEntry->getAttr('type'); unless (defined $dataType) { print STDERR "no type defined for external tag for $eventId\n"; $dataType = "error"; } my $comment = $entry->getContent(); if (($dataType =~ /,/) || ($entryId =~ /,/)) { my @type = split(/\s*,\s*/, $dataType); my @id = split(/\s*,\s*/, $entryId); if ($#type != $#id) { print STDERR "number of data types ($dataType) does not match number of ids ($entryId)", " for event $eventId\n"; if ($#type < $#id) { $#id = $#type; } else { $#type = $#id; } } my $i; my $line = ''; $line = "/* $comment */\n\t" if defined $comment; for ($i = 0; $i <= $#type; $i++) { my ($primitive, $dereference) = ($type[$i] =~ /([^\*]+)\s*(\**)/); $id[$i] .= $1 if ($primitive =~ s/(\[\d+\])//); $line .= "$primitive\t$dereference$id[$i];\t/* $option */"; push (@entryList, $line); $line = ''; } } else { my $line = ''; $line = "/* $comment */\n\t" if defined $comment; if ($dataType =~ /^msg/i) { $dataType =~ s/^msg\s*//i; $line .= "enum adt_$dataType" . "\t$entryId;\t/* $option */"; } elsif ($dataType =~ /time_t/i) { $line .= "time_t\t$entryId;\t/* $option */"; } else { my ($primitive, $dereference) = ($dataType =~ /([^\*]+)\s*(\**)/); $entryId .= $1 if ($primitive =~ s/(\[\d+\])//); $line .= "$primitive\t$dereference$entryId;\t/* $option */"; } push (@entryList, $line); } } $eventExtra{$eventId} = [$eventHeader, $idNo]; $eventAPI{$eventId} = \@entryList; } sub generateMsgLists { my $textList = shift; my $textName = $textList->getId(); my $header = $textList->getHeader(); my $start = $textList->getMsgStart(); my $public = $textList->getMsgPublic(); my $deprecated = $textList->getDeprecated(); addHeader($header); print "$textName starts at $start\n" if $debug; my $entry; my @entry; while ($entry = $textList->getNextMsg()) { if ($debug) { my ($id, $text) = split(/\s*::\s*/, $entry); print " $id = $text\n"; } unshift (@entry, $entry); } $msg_list{$textName} = [\@entry, [$header, $start, $public, $deprecated]]; } sub addHeader { my $header_index = shift; die "invalid adt_event_N.h index: $header_index\n" unless ($header_index =~ /^\d+$/); $headers{$header_index} = $header_index; } # $header = 0 is a special case; it is for adt_event.h # $header > 0 creates adt_event_N.h, where N = $header sub openHeaderFiles { my $outfile = shift; # path to an adt_event_N.h file my $header; my @Hfile = (); # potentially sparse array of file handles my @HfileName = (); # parallel array to Hfile, file name (not path) foreach $header (sort keys %headers) { my $file = $outfile; if ($header > 0) { $file =~ s/_N/_$header/; } else { $file =~ s/_N//; } unless (open($Hfile[$header], ">$file")) { print STDERR "can't open output ($file): $!\n"; $HfileName[$header] = ''; $Hfile[$header] = ''; } else { my @tmp = split(/\//, $file); $HfileName[$header] = $tmp[$#tmp]; } } return (@Hfile); } sub closeHeaderFiles { my @Hfile = @_; my $header; foreach $header (sort keys %headers) { close $Hfile[$header] if $Hfile[$header]; } }