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]
22 # Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
25 # dictck -- Sanity check a .dict file and optionally the corresponding .po file
27 # example: dickck FMD.dict FMD.po
29 # usage: dickck [-vp] [ -b buildcode ] dictfile [ pofile ]
31 # -b specify location of "buildcode" command
33 # -p print a .po file template to stdout, based on dictfile given
35 # -v verbose, show how code is assembled
37 # Note: this program requires the "buildcode" program in your search path.
44 use vars
qw($opt_b $opt_p $opt_v);
46 my $Myname = $0; # save our name for error messages
49 $SIG{HUP} = $SIG{INT} = $SIG{TERM} = $SIG{__DIE__} = sub {
50 # although fatal, we prepend "WARNING:" to make sure the
51 # commonly-used "nightly" script flags this as lint on the .dict file
52 die "$Myname: WARNING: @_";
56 # Category 1 event classes
58 my @cat1ev = qw(fault defect upset ereport list ireport);
61 # usage -- print a usage message and exit
66 warn "$Myname: $msg\n" if defined($msg);
67 warn "usage: $Myname [-pv] [ -b buildcode ] dictfile [ pofile ]\n";
75 my $buildcode = 'buildcode';
78 # the "main" for this script...
80 getopts
('b:pv') or usage
;
84 usage
unless defined($dictfile);
86 $buildcode = $opt_b if defined($opt_b);
88 dopo
($pofile) if defined($pofile);
92 # dodict -- load up a .dict file, sanity checking it as we go
103 if ($name =~ m
,([^/]+)\
.dict
$,) {
106 die "dictname \"$name\" not something.dict as expected\n";
109 open(F
, $name) or die "$name: $!\n";
110 print "parsing \"$name\"\n" if $opt_v;
116 die "$name:$line: first non-comment line must be FMDICT line\n"
118 print "FMDICT keyword found on line $line\n" if $opt_v;
121 while ($s =~ /^\s*([^=\s]+)(.*)$/) {
125 if ($s =~ /^\s*=\s*(.*)$/) {
127 die "$name:$line: property \"$lhs\" incomplete\n"
130 if ($s =~ /^"((?:[^"]|\\")*)"(.*)$/) {
134 $s =~ /^([^\s]*)(.*)$/;
138 $rhs =~ s/\\(.)/dobs($1)/ge;
140 print "property \"$lhs\" value \"$rhs\"\n" if $opt_v;
144 # check for required headers
145 die "$name: no version property in header\n"
146 unless defined($props{'version'});
147 die "$name: no name property in header\n"
148 unless defined($props{'name'});
149 die "$name: no maxkey property in header\n"
150 unless defined($props{'maxkey'});
153 die "$name:$line: unexpected version: \"$props{'version'}\"\n"
154 unless $props{'version'} eq "1";
157 die "$name:$line: name \"$props{'name'}\" doesn't match \"$dname\" from filename\n"
158 unless $props{'name'} eq $dname;
160 # check format of maxkey (value checked later)
161 die "$name:$line: maxkey property must be a number\n"
162 unless $props{'maxkey'} =~ /^\d+$/;
164 # check for old bits property
165 die "$name: obsolete \"bits\" property found in header\n"
166 if defined($props{'bits'});
174 die "$name:$line: malformed entry\n"
175 unless /^([^=]+)=(\d+)$/;
179 # make sure keys are sorted
180 my $elhs = join(' ', sort split(/\s/, $lhs));
181 die "$name:$line: keys not in expected format of:\n" .
183 unless $elhs eq $lhs;
185 # check for duplicate or unexpected keys
187 my $cat1pat = join('|', @cat1ev);
188 foreach my $e (split(/\s/, $lhs)) {
189 die "$name:$line: unknown event type \"$e\"\n"
191 /^($cat1pat)\..*[^.]$/;
192 die "$name:$line: key repeated: \"$e\"\n"
193 if defined($keys{$e});
196 $maxkey = keys(%keys) if $maxkey < keys(%keys);
198 die "$name:$line: duplicate entry for keys\n"
199 if defined($keys2val{$lhs});
200 die "$name:$line: duplicate entry for value $rhs\n"
201 if defined($val2keys{$rhs});
202 $keys2val{$lhs} = $rhs;
203 $val2keys{$rhs} = $lhs;
205 open(B
, "$buildcode $dname $rhs|") or
206 die "can't run buildcode: $!\n";
210 print "code: $code keys: $lhs\n" if $opt_v;
211 $code2val{$code} = $rhs;
221 msgid "$code.severity"
223 msgid "$code.description"
225 msgid "$code.response"
235 print "computed maxkey: $maxkey\n" if $opt_v;
238 die "$name: maxkey too low, should be $maxkey\n"
239 if $props{'maxkey'} < $maxkey;
245 # dobs -- handle backslashed sequences
250 return "\n" if $s eq 'n';
251 return "\r" if $s eq 'r';
252 return "\t" if $s eq 't';
257 # dopo -- sanity check a po file
267 open(F
, $name) or die "$name: $!\n";
268 print "parsing \"$name\"\n" if $opt_v;
274 next unless /^msgid\s*"([^"]+)"$/;
277 /^(.*)\.(type|severity|description|response|impact|action)$/;
280 die "$name:$line: no dict entry for code \"$code\"\n"
281 unless defined($code2val{$code});
286 # above checks while reading in file ensured that node code was
287 # mentioned in .po file that didn't exist in .dict file. now
288 # check the other direction: make sure the full set of entries
289 # exist for each code in the .dict file
290 foreach $code (sort keys %code2val) {
291 die "$name: missing entry for \"$code.type\"\n"
292 unless defined($ids{"$code.type"});
293 die "$name: missing entry for \"$code.severity\"\n"
294 unless defined($ids{"$code.severity"});
295 die "$name: missing entry for \"$code.description\"\n"
296 unless defined($ids{"$code.description"});
297 die "$name: missing entry for \"$code.response\"\n"
298 unless defined($ids{"$code.response"});
299 die "$name: missing entry for \"$code.impact\"\n"
300 unless defined($ids{"$code.impact"});
301 die "$name: missing entry for \"$code.action\"\n"
302 unless defined($ids{"$code.action"});