1b4ee4795Smrg#! /usr/bin/perl 2b4ee4795Smrg# 35efbdfc3Smrg# Copyright (c) 2009, Oracle and/or its affiliates. 4b4ee4795Smrg# 5b4ee4795Smrg# Permission is hereby granted, free of charge, to any person obtaining a 6b4ee4795Smrg# copy of this software and associated documentation files (the "Software"), 7b4ee4795Smrg# to deal in the Software without restriction, including without limitation 8b4ee4795Smrg# the rights to use, copy, modify, merge, publish, distribute, sublicense, 9b4ee4795Smrg# and/or sell copies of the Software, and to permit persons to whom the 10b4ee4795Smrg# Software is furnished to do so, subject to the following conditions: 11b4ee4795Smrg# 12b4ee4795Smrg# The above copyright notice and this permission notice (including the next 13b4ee4795Smrg# paragraph) shall be included in all copies or substantial portions of the 14b4ee4795Smrg# Software. 15b4ee4795Smrg# 16b4ee4795Smrg# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17b4ee4795Smrg# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18b4ee4795Smrg# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19b4ee4795Smrg# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20b4ee4795Smrg# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21b4ee4795Smrg# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 22b4ee4795Smrg# DEALINGS IN THE SOFTWARE. 23b4ee4795Smrg# 24b4ee4795Smrg 25b4ee4795Smrg# 26b4ee4795Smrg# Check a compose file for duplicate/conflicting entries and other common errors 27b4ee4795Smrg# 28b4ee4795Smrg 29b4ee4795Smrg# Compose file grammar is defined in modules/im/ximcp/imLcPrs.c 30b4ee4795Smrg 31b4ee4795Smrguse strict; 32b4ee4795Smrguse warnings; 33b4ee4795Smrg 34b4ee4795Smrgmy $error_count = 0; 35b4ee4795Smrg 36b4ee4795Smrgif (scalar(@ARGV) == 0) { 37e9fcaa8aSmrg if ( -f 'Compose' ) { 38e9fcaa8aSmrg push @ARGV, 'Compose'; 39e9fcaa8aSmrg } else { 40e9fcaa8aSmrg push @ARGV, glob '*/Compose'; 41e9fcaa8aSmrg } 42b4ee4795Smrg} 43b4ee4795Smrg 44b4ee4795Smrgforeach my $cf (@ARGV) { 45e9fcaa8aSmrg # print "Checking $cf\n"; 46b4ee4795Smrg $error_count += check_compose_file($cf); 47b4ee4795Smrg} 48b4ee4795Smrg 49b4ee4795Smrgexit($error_count); 50b4ee4795Smrg 51b4ee4795Smrgsub check_compose_file { 52b4ee4795Smrg my ($filename) = @_; 53b4ee4795Smrg my $errors = 0; 54b4ee4795Smrg 55b4ee4795Smrg my %compose_table = (); 56b4ee4795Smrg my $line = 0; 57b4ee4795Smrg my $pre_file = ($filename =~ m{\.pre$}) ? 1 : 0; 58b4ee4795Smrg my $in_c_comment = 0; 59b4ee4795Smrg 60b4ee4795Smrg open my $COMPOSE, '<', $filename or die "Could not open $filename: $!"; 61b4ee4795Smrg 62b4ee4795Smrg COMPOSE_LINE: 63b4ee4795Smrg while (my $cl = <$COMPOSE>) { 64b4ee4795Smrg $line++; 65b4ee4795Smrg chomp($cl); 66b4ee4795Smrg my $original_line = $cl; 67b4ee4795Smrg 68b4ee4795Smrg # Special handling for changes cpp makes to .pre files 69b4ee4795Smrg if ($pre_file == 1) { 70b4ee4795Smrg if ($in_c_comment) { # Look for end of multi-line C comment 71b4ee4795Smrg if ($cl =~ m{\*/(.*)$}) { 72b4ee4795Smrg $cl = $1; 73b4ee4795Smrg $in_c_comment = 0; 74b4ee4795Smrg } else { 75b4ee4795Smrg next; 76b4ee4795Smrg } 77b4ee4795Smrg } 78b4ee4795Smrg $cl =~ s{/\*.\**/}{}; # Remove single line C comments 79b4ee4795Smrg if ($cl =~ m{^(.*)/\*}) { # Start of a multi-line C comment 80b4ee4795Smrg $cl = $1; 81b4ee4795Smrg $in_c_comment = 1; 82b4ee4795Smrg } 83b4ee4795Smrg next if $cl =~ m{^\s*XCOMM}; # Skip pre-processing comments 84b4ee4795Smrg } 85b4ee4795Smrg 86b4ee4795Smrg $cl =~ s{#.*$}{}; # Remove comments 87b4ee4795Smrg next if $cl =~ m{^\s*$}; # Skip blank (or comment-only) lines 88b4ee4795Smrg chomp($cl); 89b4ee4795Smrg 90b4ee4795Smrg if ($cl =~ m{^(STATE\s+|END_STATE)}) { # Sun extension to compose file syntax 91b4ee4795Smrg %compose_table = (); 92b4ee4795Smrg } 93b4ee4795Smrg elsif ($cl =~ m{^([^:]+)\s*:\s*(.+)$}) { 94b4ee4795Smrg my ($seq, $action) = ($1, $2); 95b4ee4795Smrg $seq =~ s{\s+$}{}; 96b4ee4795Smrg 97b4ee4795Smrg my @keys = grep { $_ !~ m/^\s*$/ } split /[\s\<\>]+/, $seq; 98b4ee4795Smrg 99b4ee4795Smrg my $final_key = pop @keys; 100b4ee4795Smrg my $keytable = \%compose_table; 101b4ee4795Smrg 102b4ee4795Smrg foreach my $k (@keys) { 103b4ee4795Smrg if ($k =~ m{^U([[:xdigit:]]+)$}) { 104b4ee4795Smrg $k = 'U' . lc($1); 105b4ee4795Smrg } 106b4ee4795Smrg if (exists $keytable->{$k}) { 107b4ee4795Smrg $keytable = $keytable->{$k}; 108b4ee4795Smrg if (ref($keytable) ne 'HASH') { 109b4ee4795Smrg print 110b4ee4795Smrg "Clash with existing sequence in $filename on line $line: $seq\n"; 111b4ee4795Smrg print_sequences([$line, $original_line]); 112b4ee4795Smrg print_sequences($keytable); 113b4ee4795Smrg $errors++; 114b4ee4795Smrg next COMPOSE_LINE; 115b4ee4795Smrg } 116b4ee4795Smrg } else { 117b4ee4795Smrg my $new_keytable = {}; 118b4ee4795Smrg $keytable->{$k} = $new_keytable; 119b4ee4795Smrg $keytable = $new_keytable; 120b4ee4795Smrg } 121b4ee4795Smrg } 122b4ee4795Smrg 123b4ee4795Smrg if (exists $keytable->{$final_key}) { 124b4ee4795Smrg print "Clash with existing sequence in $filename on line $line: $seq\n"; 125b4ee4795Smrg print_sequences([$line, $original_line]); 126b4ee4795Smrg print_sequences($keytable->{$final_key}); 127b4ee4795Smrg $errors++; 128b4ee4795Smrg } else { 129b4ee4795Smrg $keytable->{$final_key} = [$line, $original_line]; 130b4ee4795Smrg } 131b4ee4795Smrg } elsif ($cl =~ m{^(STATE_TYPE:|\@StartDeadKeyMap|\@EndDeadKeyMap)}) { 132b4ee4795Smrg # ignore 133b4ee4795Smrg } elsif ($cl =~ m{^include "(.*)"}) { 134b4ee4795Smrg my $incpath = $1; 135b4ee4795Smrg if (($pre_file == 1) && ($incpath !~ m{^X11_LOCALEDATADIR/})) { 136b4ee4795Smrg print "Include path starts with $incpath instead of X11_LOCALEDATADIR\n", 137b4ee4795Smrg " -- may not find include files when installed in alternate paths\n\n"; 138b4ee4795Smrg } 139b4ee4795Smrg } else { 140b4ee4795Smrg print 'Unrecognized pattern in ', $filename, ' on line #', $line, ":\n ", 141b4ee4795Smrg $cl, "\n"; 142b4ee4795Smrg } 143b4ee4795Smrg } 144b4ee4795Smrg close $COMPOSE; 145b4ee4795Smrg 146b4ee4795Smrg return $errors; 147b4ee4795Smrg} 148b4ee4795Smrg 149b4ee4795Smrgsub print_sequences { 150b4ee4795Smrg my ($entry_ref) = @_; 151b4ee4795Smrg 152b4ee4795Smrg if (ref($entry_ref) eq 'HASH') { 153b4ee4795Smrg foreach my $h (values %{$entry_ref}) { 154b4ee4795Smrg print_sequences($h); 155b4ee4795Smrg } 156b4ee4795Smrg } else { 157b4ee4795Smrg my ($line, $seq) = @{$entry_ref}; 158b4ee4795Smrg 159b4ee4795Smrg print " line #", $line, ": ", $seq, "\n"; 160b4ee4795Smrg } 161b4ee4795Smrg} 162