1 #!/usr/perl5/bin/perl -w
5 # The contents of this file are subject to the terms of the
6 # Common Development and Distribution License (the "License").
7 # You may not use this file except in compliance with the License.
9 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 # or http://www.opensolaris.org/os/licensing.
11 # See the License for the specific language governing permissions
12 # and limitations under the License.
14 # When distributing Covered Code, include this CDDL HEADER in each
15 # file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 # If applicable, add the following below this CDDL HEADER, with the
17 # fields enclosed by brackets "[]" replaced with your own identifying
18 # information: Portions Copyright [yyyy] [name of copyright owner]
23 # Copyright 2010 Sun Microsystems, Inc. All rights reserved.
24 # Use is subject to license terms.
27 # auditxml takes the audit record description (.xml file) and
28 # generates the files needed for the C audit api.
30 my $prog = $0; $prog =~ s
|.*/||g
;
33 Usage: $prog [options] <xml-input-file>
35 -d Enable debug output
36 -e pfx Internal event prefix (default: AUE)
37 -i pfx Interface prefix (default: adt)
38 External event prefix is uppercase version of this string.
39 -o dir Output directory (default: current dir)
47 our $debug = 0; # normal use is to set via the file being parsed.
48 # <debug set="on"/> or <debug set="off"/> or <debug/>
49 # if the set attribute is omitted, debug state is toggled
50 # Override with appDebug, but toggle won't do what you
52 my $appDebug = 0; # used after return from "new auditxml";
54 # Process command-line options
55 our ($opt_d, $opt_e, $opt_i, $opt_o);
59 if (!getopts
('de:i:o:') || $#ARGV != 0) {
62 my $outdir = $opt_o || ".";
63 my $pfx_adt = lc($opt_i) || "adt";
64 my $pfx_ADT = uc($pfx_adt);
65 my $pfx_AUE = uc($opt_e) || "AUE";
70 my $xlateUniLabelInc = 0;
73 # where everything comes from and where it goes:
75 my $xlateFile = "$outdir/${pfx_adt}_xlate.c";
76 my $headerFile = "$outdir/${pfx_adt}_event_N.h";
78 my $filename = $ARGV[0]; # input XML file
79 my $doc = new auditxml
($filename);
80 $filename =~ s
|.*/||g
;
85 DO NOT EDIT. This file is auto generated by the Solaris Audit
86 system from $filename.
88 See http://opensolaris.org/os/project/audit/
91 # trim leading/trailing newlines
92 $genNotice =~ s/^\n//s;
93 $genNotice =~ s/\n$//s;
95 my %xlateEventTable = ();
96 my @xlateTypeList = ();
97 my %xlateTypeList = ();
101 my %externalIdNo = ();
102 my @outputState = ();
103 my %nameTranslation = ();
104 my @xlateDefaults = ();
105 my %xlateDefault = ();
109 while ($event = $doc->getNextEvent()) {
110 my $eventId = $event->getId();
111 my $eventHeader = $event->getHeader();
112 my $idNo = $event->getIdNo();
113 $externalIdNo{$eventId} = $idNo;
114 addHeader
($eventHeader) if defined ($eventHeader);
116 my $omit = $event->getOmit();
118 if ($super = $event->getSuperClass()) {
120 $eventType = 'instance';
122 $eventType = $event->getType();
125 # header file for API use
126 generateAPIFile
($event, $eventId, $eventType, $eventHeader, $idNo)
127 unless $omit eq 'always';
129 # c file table for translation
130 generateTableC
($event, $eventId, $eventType, $eventHeader, $omit);
134 while ($textList = $doc->getNextMsgId()) {
135 generateMsgLists
($textList); # enum -> text mappings
138 printTableC
($xlateFile);
139 printAPIFile
($headerFile, $doc);
147 unless (open(Cfile
, ">$file")) {
148 print STDERR
"can't open output file ($file): $!\n";
152 my $notice = $genNotice;
153 $notice =~ s/\n/\n * /gs;
154 $notice =~ s/\s+\n/\n/gs;
160 #include <bsm/libbsm.h>
161 #include <adt_xlate.h>
165 print Cfile
"#ifndef _PRAUDIT\n";
166 print Cfile
"/* Internal data type definitions */\n\n";
168 foreach $extDef (@xlateTypeList) {
169 print Cfile
"static $extDef\n";
173 print Cfile
"\n/* External event structure to internal event structure */\n\n";
177 foreach my $eventId (sort keys %xlateEventTable) {
178 if ($xlateEventTable{$eventId}) {
179 my ($ref1, $eventType, $firstToken, $eventHeader) =
180 @
{$xlateEventTable{$eventId}};
181 my @entries = @
$ref1;
183 my $entries = $#entries;
184 my $count = $entries + 1;
185 my $externalName = $nameTranslation{$eventId};
186 my $externalRoot = $externalName;
187 $externalRoot =~ s/${pfx_AUE}_//;
188 my $structName = "XX_$externalRoot";
190 $root =~ s/${pfx_AUE}_//;
191 my $externalId = $eventId;
192 $externalId =~ s/${pfx_AUE}_/${pfx_ADT}_/;
194 unless ($eventType eq 'generic') {
195 print Cfile
"static struct entry $structName\[$count\] = {\n";
196 foreach $entry (@entries) {
203 $entry =~ s/selfReference/$structName/;
204 print Cfile
"\t$entry\n";
208 print Cfile
"static struct translation X_$externalRoot = {\n";
209 push (@pointers, "X_$externalRoot");
211 print Cfile
"\t0,\n"; # tx_offsetsCalculated = 0
212 print Cfile
"\t$externalId,\n";
213 print Cfile
"\t$externalName,\n";
215 print Cfile
"\t$count,\n";
216 print Cfile
"\t&XX_$externalRoot\[$firstToken\],\n";
217 print Cfile
"\t&XX_$externalRoot\[0\]\n};\n";
220 print STDERR
"expected entry for $eventId but none found\n";
224 my $count = $#pointers + 2;
225 print Cfile
"adt_translation_t *${pfx_adt}_xlate_table[$count] = {\n";
228 foreach my $eventId (@pointers) {
235 print Cfile
"\t&$eventId";
237 print Cfile
",\n\tNULL\n};\n";
239 # generate the Event preload() function
244 ${pfx_adt}_preload(au_event_t event_id, adt_event_data_t *event_data)
249 foreach my $id (@xlateDefaults) {
251 $adtID =~ s/${pfx_AUE}/${pfx_ADT}/;
256 my @preloads = @
{$xlateDefault{$id}};
258 my $fieldName = shift @preloads;
259 my $default = shift @preloads;
260 $id =~ s/${pfx_AUE}_/${pfx_adt}_/;
263 event_data->$id.$fieldName = $default;
281 print Cfile
"/* message lists */\n\n";
284 foreach $listName (sort keys %msg_list) {
285 my ($listRef, $headref) = @
{$msg_list{$listName}};
286 my ($header, $start, $public, $deprecated) = @
$headref;
288 my @listValue = @
$listRef;
290 my $listLength = $#listValue + 1;
292 $listName = 'NULL' if ($#listValue < 0);
294 push (@listName, [$listName, $listLength - 1, $start, $public]);
296 next if ($#listValue < 0);
298 print Cfile
"/* Deprecated message list */\n" if ($deprecated);
299 print Cfile
"static char *msg_$listName\[$listLength] = {\n";
302 foreach $listValue (@listValue) {
303 print Cfile
",\n" unless $ffirst;
305 my ($id, $text) = split(/\s*::\s*/, $listValue);
307 print Cfile
"\t\"$text\"";
310 print Cfile
"\tNULL";
313 print Cfile
"\n};\n";
316 if ($#listName >= 0) {
317 print Cfile
"\nstruct msg_text ${pfx_adt}_msg_text[", $#listName + 1,
320 foreach $listName (@listName) {
321 my ($name, $max, $start) = @
$listName;
322 $start = -$start if $start;
323 print Cfile
",\n" unless $ffirst;
325 $name = "msg_$name" if ($name ne 'NULL');
326 print Cfile
"\t{0, $max, $name, $start}";
328 print Cfile
"\n};\n";
339 @Hfile = openHeaderFiles
($file);
341 my $notice = $genNotice;
342 $notice =~ s/\n/\n * /gs;
343 $notice =~ s/\s+\n/\n/gs;
345 foreach my $header (keys %headers) {
346 next unless $Hfile[$header];
347 *Hfile
= $Hfile[$header];
348 my $include = "adt.h";
349 my $adt_event_n = "_${pfx_ADT}_EVENT_H";
351 $include = "${pfx_adt}_event.h";
352 $adt_event_n = "_${pfx_ADT}_EVENT_".$header."_H";
362 #include <bsm/$include>
369 * adt_put_event() status values. Positive values are for kernel-generated
370 * failure, -1 for user-space. For ADT_SUCCESS, the adt_put_event() return_val
371 * is not used; the convention is to set it to ADT_SUCCESS.
373 #define ADT_SUCCESS 0
374 #define ADT_FAILURE -1
379 foreach my $listName (sort keys %msg_list) {
380 my $shortName = uc $listName;
381 $shortName =~ s/_TEXT//;
383 my ($listRef, $headref) = @
{$msg_list{$listName}};
384 my ($header, $start, $public, $deprecated) = @
$headref;
385 next unless $Hfile[$header];
386 *Hfile
= $Hfile[$header];
388 print Hfile
"/* Deprecated message list */\n" if $deprecated;
389 print Hfile
"#define\t${pfx_ADT}_$shortName\t$start\n" if $start;
391 my @listValue = @
$listRef;
392 next unless ($#listValue >= 0);
393 print Hfile
"enum\t${pfx_adt}_$listName", " {\n";
399 foreach $listValue (@listValue) {
400 my ($id, $text) = split(/\s*::\s*/, $listValue);
401 $comma = '' if $i++ == $j;
403 $start = " = $start$comma";
407 $text = "(no token will be generated)" unless $text;
408 my $line = "\t${pfx_ADT}_$shortName"."_$id$start\t/* ";
409 # ensure whole line does not exceed 80 chars
410 my $eline = $line.$text;
412 1 while $eline =~ s/\t+/' ' x (length($&) * 8 - length($`) % 8)/e;
413 if ((length($eline) > 77) && ($line =~ /\t\t/)) {
414 # 77 = 80 - length(" */")
415 # strip off double tab so that comment can be longer
417 # shorten eline; don't mind where the spaces are removed, it is
418 # only $eline length which matters
421 if (length($eline) > 77) { # 80 - length(" */")
422 # here we use negative length in substr to leave off from the
423 # right side; 74 = 77 - length("...")
424 $line .= substr($text, 0, 74 - length($eline));
425 # strip off part of last word (already cut)
426 $line =~ s/\s(\S+)$/ /;
431 print Hfile
"$line */\n";
437 # generate defines for external event names
439 foreach my $eventId (sort keys %eventAPI) {
440 my ($header, $idNo) = @
{$eventExtra{$eventId}};
441 unless (defined ($header)) {
442 print STDERR
"missing header selection for $eventId\n";
445 *Hfile
= $Hfile[$header];
446 next unless $Hfile[$header];
448 my $l = length($eventId) + 8; # label plus preceding #define\t
449 $l = 5 - int(($l + 8)/8);
453 print STDERR
"missing id number for $eventId\n" unless $idNo;
455 $eventId =~ s/${pfx_AUE}_/${pfx_ADT}_/;
456 print Hfile
"#define\t$eventId$tab$idNo\n";
460 # generate per-event structures
462 foreach my $eventId (sort keys %eventAPI) {
463 my ($header, $idNo) = @
{$eventExtra{$eventId}};
464 my $dataId = $eventId;
465 $dataId =~ s/^${pfx_AUE}_/${pfx_adt}_/;
466 unless(defined ($header)) {
467 print STDERR
"$eventId is missing the header assignment\n";
470 *Hfile
= $Hfile[$header];
471 next unless $Hfile[$header];
473 my $externalId = $eventId;
474 $externalId =~ s/${pfx_AUE}_/${pfx_ADT}_/;
476 print Hfile
"\nstruct $dataId {\t/* $externalId */\n";
478 my @entries = @
{$eventAPI{$eventId}};
481 print Hfile
"\tint\tdummy;\t/* not used */\n";
483 foreach $entry (@entries) {
484 $entry =~ s/termid/adt_termid_t/;
485 print Hfile
"\t$entry\n";
489 $eventId =~ s/^${pfx_AUE}_/${pfx_adt}_/;
490 print Hfile
"typedef struct $dataId $eventId","_t;\n";
493 foreach my $header (sort keys %headers) {
494 $outputState[$header] = 0;
497 foreach my $eventId (sort keys %eventAPI) {
498 my ($header, $idNo) = @
{$eventExtra{$eventId}};
499 unless(defined ($header)) {
500 # don't print duplicate error message
503 *Hfile
= $Hfile[$header];
504 next unless $Hfile[$header];
505 if ($outputState[$header] == 0) {
506 $outputState[$header] = 1;
508 $suffix = "_$header" if $header;
509 print Hfile
"\nunion adt_event_data$suffix {\n";
511 my $elementName = $eventId;
512 $elementName =~ s/^${pfx_AUE}_/${pfx_adt}_/;
513 $eventId =~ s/^${pfx_AUE}_/${pfx_adt}_/;
514 $elementName =~ s/_t$//;
516 print Hfile
"\t\t$eventId","_t\t$elementName;\n";
518 foreach my $header (sort keys %headers) {
519 if ($outputState[$header]) {
520 *Hfile
= $Hfile[$header];
521 next unless $Hfile[$header];
525 foreach my $header (keys %headers) {
526 next unless $Hfile[$header];
527 *Hfile
= $Hfile[$header];
528 my $adt_event_n = "_${pfx_ADT}_EVENT_H";
530 $adt_event_n = "_${pfx_ADT}_EVENT_".$header."_H";
535 #ifndef ${pfx_ADT}_PRIVATE
536 #define ${pfx_ADT}_PRIVATE
539 * These interfaces are project private and will change without
540 * notice as needed for the Solaris Audit project.
543 extern void adt_get_auid(const adt_session_data_t *, au_id_t *);
544 extern void adt_set_auid(const adt_session_data_t *, const au_id_t);
546 extern void adt_get_mask(const adt_session_data_t *, au_mask_t *);
547 extern void adt_set_mask(const adt_session_data_t *, const au_mask_t *);
549 extern void adt_get_termid(const adt_session_data_t *, au_tid_addr_t *);
550 extern void adt_set_termid(const adt_session_data_t *,
551 const au_tid_addr_t *);
553 extern void adt_get_asid(const adt_session_data_t *, au_asid_t *);
554 extern void adt_set_asid(const adt_session_data_t *, const au_asid_t);
555 extern au_asid_t adt_get_unique_id(au_id_t);
556 extern void adt_load_table(const adt_session_data_t *, adt_translation_t **,
557 void (*preload)(au_event_t, adt_event_data_t *));
559 extern void ${pfx_adt}_preload(au_event_t, adt_event_data_t *);
561 extern adt_translation_t *${pfx_adt}_xlate_table[];
569 #endif /* $adt_event_n */
572 closeHeaderFiles
(@Hfile);
578 my $eventType = shift;
579 my $eventHeader = shift;
584 # tokenTypes are the ones that are actually defined
585 # for use in adt.xml audit records
588 # 'acl' => 'AUT_ACL', # not defined
589 # 'arbitrary' => 'AUT_ARBITRARY', # not defined
590 # 'arg' => 'AUT_ARG', # not defined
591 # 'attr' => 'AUT_ATTR',
592 'command' => 'AUT_CMD',
593 'command_alt' => 'ADT_CMD_ALT', # dummy token id
594 # 'date' => 'AUT_TEXT', # not used
595 # 'exec_args' => 'AUT_EXEC_ARGS', # not defined
596 # 'exec_env' => 'AUT_EXEC_ENV', # not defined
597 # 'exit' => 'AUT_EXIT', # not defined
598 'fmri' => 'AUT_FMRI',
599 # 'groups' => 'AUT_GROUPS', # not defined
600 # 'header' => 'AUT_HEADER', # not defined
601 'in_peer' => 'ADT_IN_PEER', # dummy token id
602 'in_remote' => 'ADT_IN_REMOTE', # dummy token id
603 # 'ipc' => 'AUT_IPC', # not defined
604 # 'ipc_perm' => 'AUT_IPC_PERM', # not defined
605 'iport' => 'AUT_IPORT',
606 'newgroups' => 'AUT_NEWGROUPS',
607 # 'opaque' => 'AUT_OPAQUE', # not defined
608 'path' => 'AUT_PATH',
609 'path_list' => '-AUT_PATH', # dummy token id
610 'process' => 'AUT_PROCESS',
611 'priv_effective' => 'ADT_AUT_PRIV_E', # dummy token id
612 'priv_limit' => 'ADT_AUT_PRIV_L', # dummy token id
613 'priv_inherit' => 'ADT_AUT_PRIV_I', # dummy token id
614 'return' => 'AUT_RETURN',
615 'secflags' => 'AUT_SECFLAGS',
616 # 'seq' => 'AUT_SEQ', # not defined
617 # 'socket' => 'AUT_SOCKET', # not defined
618 # 'socket-inet' => 'AUT_SOCKET_INET',
619 'subject' => 'AUT_SUBJECT',
620 'text' => 'AUT_TEXT',
622 # 'trailer' => 'AUT_TRAILER', # not defined
623 'uauth' => 'AUT_UAUTH',
624 'user' => 'AUT_USER',
625 'zonename' => 'AUT_ZONENAME'
628 my @xlateEntryList = ();
630 my $external = $event->getExternal();
631 my $internal = $event->getInternal();
634 print STDERR
"No external object captured for event $eventId\n";
638 $nameTranslation{$eventId} = $eventId;
640 $nameTranslation{$eventId} = $external->getInternalName();
643 print STDERR
"No internal object captured for event $eventId\n";
646 my @entryRef = $internal->getEntries();
649 my $firstTokenIndex = 0; # djdj not used yet, djdj BUG!
650 # needs to be used by translate table
652 if ($internal->isReorder()) { # prescan the entry list to get the token order
654 foreach $entryRef (@entryRef) {
655 my ($intEntry, $entry) = @
$entryRef;
656 push (@inputOrder, $intEntry->getAttr('order'));
659 my $i; # walk down the inputOrder list once
660 my $k = 1; # discover next in line
661 my $l = 0; # who should point to next in line
662 for ($i = 0; $i <= $#inputOrder; $i++) {
664 for ($j = 0; $j <= $#inputOrder; $j++) {
665 if ($k == $inputOrder[$j]) {
667 $firstTokenIndex = $j;
669 $tokenOrder[$l] = "&(selfReference[$j])";
677 $tokenOrder[$l] = 'NULL';
679 else { # default order -- input order same as output
682 for ($i = 0; $i < $#entryRef; $i++) {
684 $tokenOrder[$i] = "&(selfReference[$j])";
686 $tokenOrder[$#entryRef] = 'NULL';
690 foreach $entryRef (@entryRef) {
691 my ($intEntry, $entry) = @
$entryRef;
692 my $entryId = $entry->getAttr('id');
694 my ($extEntry, $unusedEntry, $tokenId) =
695 $external->getEntry($entryId);
696 my $opt = $extEntry->getAttr('opt');
698 if ($opt eq 'none') {
699 if (defined ($doc->getToken($tokenId))) {
700 if (defined ($tokenType{$tokenId})) {
701 $tokenId = $tokenType{$tokenId};
704 print STDERR
"token id $tokenId not implemented\n";
708 print STDERR
"token = $tokenId is undefined\n";
712 formatTableEntry
('', $tokenId, $eventId, '', 0,
713 $tokenOrder[$sequence], 'NULL', '', $omit);
714 push (@xlateEntryList, $xlate);
717 my $dataType = $extEntry->getAttr('type');
718 $dataType =~ s/\s+//g; # remove blanks (char * => char*)
721 if ($dataType =~ /^msg/i) {
722 $enumGroup = $dataType;
723 $enumGroup =~ s/^msg\s*//i;
724 $enumGroup = "${pfx_adt}_" . $enumGroup;
726 my $required = ($opt eq 'required') ?
1 : 0;
727 my $tokenId = $intEntry->getAttr('token');
730 my $tokenFormat = $intEntry->getAttr('format');
731 if (defined ($tokenFormat)) {
732 $tokenFormat = "\"$tokenFormat\"";
735 $tokenFormat = 'NULL';
738 if (defined ($token = $doc->getToken($tokenId))) {
739 if (defined ($tokenType{$tokenId})) {
740 $tokenName = $tokenType{$tokenId};
743 print STDERR
"token id $tokenId not implemented\n";
748 "$tokenId is an unimplemented token ($entryId in $eventId)\n";
749 $tokenName = 'AUT_TEXT';
752 formatTableEntry
($entryId, $tokenName, $eventId, $dataType, $required,
753 $tokenOrder[$sequence], $tokenFormat,
755 push (@xlateEntryList, $xlate);
759 $xlateEventTable{$eventId} = [\
@xlateEntryList, $eventType, $firstTokenIndex,
763 sub formatTableEntry
{
764 my ($id, $token, $eventId, $type, $required, $sequence, $format,
765 $enumGroup, $omitEntry) = @_;
768 # does this map belong in the xml source? (at least the defaults?)
769 # fill in the default value only if it is other than zero.
770 # base type adt name, default value
771 my %entryDef = ( 'au_asid_t' => ['ADT_UINT32', ''],
772 'uint_t' => ['ADT_UINT32', ''],
773 'int' => ['ADT_INT', ''],
774 'int32_t' => ['ADT_INT32', ''],
775 'uid_t' => ['ADT_UID', 'AU_NOAUDITID'],
776 'gid_t' => ['ADT_GID', 'AU_NOAUDITID'],
777 'uid_t*' => ['ADT_UIDSTAR', ''],
778 'gid_t*' => ['ADT_GIDSTAR', ''],
779 'char' => ['ADT_CHAR', ''],
780 'char*' => ['ADT_CHARSTAR', ''],
781 'char**' => ['ADT_CHAR2STAR', ''],
782 'long' => ['ADT_LONG', ''],
783 'pid_t' => ['ADT_PID', ''],
784 'priv_set_t*' => ['ADT_PRIVSTAR', ''],
785 'ulong_t' => ['ADT_ULONG', ''],
786 'uint16_t', => ['ADT_UINT16', ''],
787 'uint32_t' => ['ADT_UINT32', ''],
788 'uint32_t*' => ['ADT_UINT32STAR', ''],
789 'uint32_t[]' => ['ADT_UINT32ARRAY', ''],
790 'uint64_t' => ['ADT_UINT64', ''],
791 'uint64_t*' => ['ADT_UINT64STAR', ''],
792 'fd_t' => ['ADT_FD', '-1'],
794 my $xlateLabel = $uniLabel.$xlateUniLabelInc;
795 my $xlateLabelInc = 0;
799 # the list handling should be a simple loop with a loop of one
800 # falling out naturally.
802 unless ($type =~ /,/) { # if list, then generate sequence of entries
805 my $xlateLabelRef = '';
808 $arraySize = $1 if ($type =~ s/\[(\d+)\]/[]/);
810 my $entryType = ${$entryDef{$type}}[0];
812 my @xlateType = (); # for adt_xlate.c
816 $dataType = $entryType;
817 $type =~ s/([^*]+)\s*(\*+)/$1 $2/;
819 $dataSize = "sizeof ($type)";
821 $dataSize = "$arraySize * " . $dataSize;
823 $xlateLine = "{{$dataType, $dataSize}}";
824 push (@jniLine, [$id, $dataType, $format, $enumGroup, $required]);
825 } elsif ($type eq '') {
826 $xlateLabelRef = 'NULL';
827 } elsif ($type =~ /^msg/i) {
829 $dataType = 'ADT_MSG';
830 my $dataEnum = 'ADT_LIST_' . uc $type;
831 $xlateLine = "{{$dataType, $dataEnum}}";
832 push (@jniLine, [$id, $dataType, $format, $enumGroup, $required]);
833 } elsif ($type =~ /time_t/i) {
834 $dataType = 'ADT_DATE';
835 $dataSize = "sizeof (time_t)";
836 $xlateLine = "{{$dataType, $dataSize}}";
837 push (@jniLine, [$id, $dataType, $format, $enumGroup, $required]);
838 } elsif ($type =~ /termid/i) {
839 $dataType = 'ADT_TERMIDSTAR';
840 $dataSize = "sizeof (au_tid_addr_t *)";
841 $xlateLine = "{{$dataType, $dataSize}}";
842 push (@jniLine, [$id, $dataType, $format, $enumGroup, $required]);
843 } elsif (uc $omitEntry eq 'JNI') {
844 $xlateLabelRef = 'NULL';
846 print STDERR
"$type is not an implemented data type\n";
847 $xlateLabelRef = 'NULL';
849 if ($xlateLine && !($xlateTypeList{$xlateLine})) {
850 $xlateTypeList{$xlateLine} = $xlateLabel;
851 push (@xlateTypeList, "datadef\t$xlateLabel\[1\] =\t$xlateLine;");
854 $xlateLabel = $xlateTypeList{$xlateLine};
856 $xlateLabelRef = '&' . $xlateLabel . '[0]'
857 unless $xlateLabelRef eq 'NULL';
859 # "EOL" is where a comma should go unless end of list
860 $xlateLine = "{$token,\t1,\t$xlateLabelRef,\t$sequence,\n" .
861 "\t\t0,\t$required,\t$format}EOL";
863 if (uc $omitEntry ne 'ALWAYS' && ${$entryDef{$type}}[1]) {
865 if ($xlateDefault{$eventId}) {
866 @list = @
{$xlateDefault{$eventId}};
868 push (@xlateDefaults, $eventId);
870 push (@list, $id, ${$entryDef{$type}}[1]);
871 $xlateDefault{$eventId} = \
@list;
874 my @type = split(/,/, $type);
876 my @id = split(/,/, $id);
879 my $typeCount = ($#type + 1);
883 foreach my $dtype (@type) {
884 my $jniId = shift @jniId;
887 $arraySize = $1 if ($dtype =~ s/\[(\d+)\]/[]/);
889 my $entryType = ${$entryDef{$dtype}}[0];
892 $type =~ s/([^*]+)\s*(\*+)/$1 $2/;
895 my $sizeString = "sizeof";
896 $sizeString = "$arraySize * " . $sizeString if $arraySize;
897 push (@xlateType, "\{$entryType, $sizeString ($type)\}");
898 push (@jniLine, [$jniId, $entryType, $format, $enumGroup, $required]);
899 } elsif ($type =~ /^msg/i) {
901 $dataType = 'ADT_MSG';
902 my $dataEnum = 'ADT_LIST_' . uc $type;
903 push (@xlateType, "\{$dataType, $dataEnum\}};");
904 push (@jniLine, [$jniId, $dataType, $format, $enumGroup, $required]);
905 } elsif ($type =~ /time_t/i) {
906 $dataType = 'ADT_DATE';
907 push (@xlateType, "\{$entryType, sizeof ($type)\}");
908 push (@jniLine, [$jniId, $entryType, $format, $enumGroup, $required]);
909 } elsif ($type =~ /termid/i) {
910 $dataType = 'ADT_TERMIDSTAR';
911 push (@xlateType, "\{$dataType, sizeof (au_tid_addr_t *)\}");
912 push (@jniLine, [$jniId, $dataType, $format, $enumGroup, $required]);
913 } elsif (uc $omitEntry eq 'JNI') {
916 print STDERR
"$dtype is not an implemented data type\n";
918 if (uc $omitEntry ne 'ALWAYS' && ${$entryDef{$dtype}}[1]) {
919 push (@default, $id, ${$entryDef{$dtype}}[1]);
922 my $xlateArray = "\[$typeCount\] =\t{" . join(",\n\t\t\t\t", @xlateType) . "};";
924 unless ($xlateTypeList{$xlateArray}) {
925 $xlateTypeList{$xlateArray} = $xlateLabel;
926 $xlateArray = "datadef\t$xlateLabel" . $xlateArray;
927 push (@xlateTypeList, $xlateArray);
930 $xlateLabel = $xlateTypeList{$xlateArray};
933 "{$token,\t$typeCount,\t&$xlateLabel\[0\],\t$sequence,\n" .
934 "\t\t0,\t$required,\t$format}EOL";
937 if ($xlateDefault{$eventId}) {
938 @list = @
{$xlateDefault{$eventId}};
940 push (@xlateDefaults, $eventId);
942 push (@list, @default);
943 $xlateDefault{$eventId} = \
@list;
946 $xlateUniLabelInc++ if $xlateLabelInc;
947 return ($xlateLine, \
@jniLine);
950 sub generateAPIFile
{
953 my $eventType = shift;
954 my $eventHeader = shift;
959 my $external = $event->getExternal();
961 if ($eventType && $debug) {
962 print STDERR
"event $eventId is of type $eventType\n";
965 return unless $external;
967 my ($extEntry, $entry, $tokenId, $format);
968 while (($extEntry, $entry, $tokenId, $format) = $external->getNextEntry()) {
970 my $entryId = $entry->getAttr('id');
972 unless (defined $entryId) {
973 print STDERR
"undefined entry id for external $eventId\n";
976 my $option = $extEntry->getAttr('opt');
977 next if ($option eq 'none');
979 $option .= " (format: $format)" if $format;
981 my $dataType = $extEntry->getAttr('type');
982 unless (defined $dataType) {
983 print STDERR
"no type defined for external tag for $eventId\n";
987 my $comment = $entry->getContent();
989 if (($dataType =~ /,/) || ($entryId =~ /,/)) {
990 my @type = split(/\s*,\s*/, $dataType);
991 my @id = split(/\s*,\s*/, $entryId);
992 if ($#type != $#id) {
994 "number of data types ($dataType) does not match number of ids ($entryId)",
995 " for event $eventId\n";
1006 $line = "/* $comment */\n\t" if defined $comment;
1007 for ($i = 0; $i <= $#type; $i++) {
1008 my ($primitive, $dereference) =
1009 ($type[$i] =~ /([^\*]+)\s*(\**)/);
1010 $id[$i] .= $1 if ($primitive =~ s/(\[\d+\])//);
1011 $line .= "$primitive\t$dereference$id[$i];\t/* $option */";
1012 push (@entryList, $line);
1018 $line = "/* $comment */\n\t" if defined $comment;
1019 if ($dataType =~ /^msg/i) {
1020 $dataType =~ s/^msg\s*//i;
1021 $line .= "enum ${pfx_adt}_$dataType" . "\t$entryId;\t/* $option */";
1023 elsif ($dataType =~ /time_t/i) {
1024 $line .= "time_t\t$entryId;\t/* $option */";
1027 my ($primitive, $dereference) =
1028 ($dataType =~ /([^\*]+)\s*(\**)/);
1029 $entryId .= $1 if ($primitive =~ s/(\[\d+\])//);
1030 $line .= "$primitive\t$dereference$entryId;\t/* $option */";
1032 push (@entryList, $line);
1035 $eventExtra{$eventId} = [$eventHeader, $idNo];
1036 $eventAPI{$eventId} = \
@entryList;
1039 sub generateMsgLists
{
1040 my $textList = shift;
1042 my $textName = $textList->getId();
1043 my $header = $textList->getHeader();
1044 my $start = $textList->getMsgStart();
1045 my $public = $textList->getMsgPublic();
1046 my $deprecated = $textList->getDeprecated();
1049 print "$textName starts at $start\n" if $debug;
1053 while ($entry = $textList->getNextMsg()) {
1055 my ($id, $text) = split(/\s*::\s*/, $entry);
1056 print " $id = $text\n";
1058 unshift (@entry, $entry);
1060 $msg_list{$textName} =
1061 [\
@entry, [$header, $start, $public, $deprecated]];
1065 my $header_index = shift;
1067 die "invalid adt_event_N.h index: $header_index\n"
1068 unless ($header_index =~ /^\d+$/);
1070 $headers{$header_index} = $header_index;
1073 # $header = 0 is a special case; it is for adt_event.h
1074 # $header > 0 creates adt_event_N.h, where N = $header
1076 sub openHeaderFiles
{
1077 my $outfile = shift; # path to an adt_event_N.h file
1080 my @Hfile = (); # potentially sparse array of file handles
1081 my @HfileName = (); # parallel array to Hfile, file name (not path)
1082 foreach $header (sort keys %headers) {
1083 my $file = $outfile;
1085 $file =~ s/_N/_$header/;
1089 unless (open($Hfile[$header], ">$file")) {
1090 print STDERR
"can't open output ($file): $!\n";
1091 $HfileName[$header] = '';
1092 $Hfile[$header] = '';
1094 my @tmp = split(/\//, $file);
1095 $HfileName[$header] = $tmp[$#tmp];
1101 sub closeHeaderFiles
{
1105 foreach $header (sort keys %headers) {
1106 close $Hfile[$header] if $Hfile[$header];