[PATCH:libX11 2/2] Bug 19379 - Provide docs with overview of all compose key combinations

Alan Coopersmith alan.coopersmith at oracle.com
Tue Sep 14 00:44:52 PDT 2010


Adds compose-chart.pl to generate DocBook/XML documents listing compose
keys, and Makefile rules to generate HTML & PDF output from them if xmlto
is present.

https://bugs.freedesktop.org/show_bug.cgi?id=19379

Signed-off-by: Alan Coopersmith <alan.coopersmith at oracle.com>
---
 COPYING              |    2 +-
 cpprules.in          |    2 +-
 nls/Makefile.am      |   39 +++++-
 nls/compose-chart.pl |  389 ++++++++++++++++++++++++++++++++++++++++++++++++++
 specs/xmlrules.in    |   10 +-
 5 files changed, 435 insertions(+), 7 deletions(-)
 create mode 100755 nls/compose-chart.pl

Samples of the HTML charts generated by this option can be viewed at:
	http://people.freedesktop.org/~alanc/Compose/

(The .txt & .xml files are there too if you change the extension on URL's
 for individual compose table charts.)

diff --git a/COPYING b/COPYING
index fe41dc7..b065516 100644
--- a/COPYING
+++ b/COPYING
@@ -13,7 +13,7 @@ to that file.
 
 Copyright (C) 2003-2006,2008 Jamey Sharp, Josh Triplett
 Copyright © 2009 Red Hat, Inc.
-Copyright 1990-1992,1999,2000,2004,2009 Oracle and/or its affiliates.
+Copyright 1990-1992,1999,2000,2004,2009,2010 Oracle and/or its affiliates.
 All rights reserved.
 
 Permission is hereby granted, free of charge, to any person obtaining a
diff --git a/cpprules.in b/cpprules.in
index 845e242..127464d 100644
--- a/cpprules.in
+++ b/cpprules.in
@@ -4,7 +4,7 @@
 
 SED = sed
 
-SUFFIXES = .pre
+SUFFIXES += .pre
 
 WCHAR32_FLAGS = -DWCHAR32=@WCHAR32@
 
diff --git a/nls/Makefile.am b/nls/Makefile.am
index 8247207..1f40b12 100644
--- a/nls/Makefile.am
+++ b/nls/Makefile.am
@@ -1,11 +1,14 @@
 x11localedir = $(X11_LOCALEDATADIR)
+specdir = $(docdir)/Compose
+
+include $(top_srcdir)/specs/xmlrules.in
 
 EXTRA_DIST = locale.alias.pre compose.dir.pre locale.dir.pre \
-	compose-check.pl
+	compose-check.pl compose-chart.pl
 
 x11locale_DATA = locale.alias locale.dir compose.dir
 
-CLEANFILES= \
+CLEANFILES += \
 	locale.alias locale.alias.l1 locale.alias.l2 \
 	compose.dir compose.dir.l1 compose.dir.l2 \
 	locale.dir locale.dir.l1 locale.dir.l2 \
@@ -95,6 +98,22 @@ locale.dir: locale.dir.pre
         < locale.dir.l1 > locale.dir.l2
 	cat locale.dir.l2 locale.dir.l1 > locale.dir
 
+if HAVE_PERL
+doc_sources = Compose/index.xml
+
+Compose/index.xml: Compose
+	$(AM_V_GEN)$(PERL) $(srcdir)/compose-chart.pl \
+	 --index --output="$@" $(locales)
+
+Compose:
+	$(MKDIR_P) $@
+
+clean-local: clean-Compose-dir
+clean-Compose-dir:
+	-rm -rf Compose
+endif HAVE_PERL
+
+
 # Per-locale data files
 
 nobase_dist_x11locale_DATA = $(locales:%=%/XI18N_OBJS)
@@ -111,4 +130,20 @@ builddirs:
 if HAVE_PERL
 TESTS_ENVIRONMENT = $(PERL)
 TESTS = $(srcdir)/compose-check.pl
+
+COMPOSE_CHARTS = $(locales:%=%/Compose.xml)
+doc_sources += $(locales:%=Compose/%.xml)
+CLEANFILES += $(COMPOSE_CHARTS) $(doc_sources)
+
+XMLTO_FLAGS += -o $(@D)
+
+%/Compose.xml: %/Compose
+	$(AM_V_GEN)$(PERL) $(srcdir)/compose-chart.pl \
+	 --locale="$(@D)" --output="$@" $<
+
+Compose/%.xml: %/Compose.xml
+	$(AM_V_GEN)cp $< $@
+
+$(doc_sources): Compose
+
 endif HAVE_PERL
diff --git a/nls/compose-chart.pl b/nls/compose-chart.pl
new file mode 100755
index 0000000..fe56d4e
--- /dev/null
+++ b/nls/compose-chart.pl
@@ -0,0 +1,389 @@
+#! /usr/bin/perl
+#
+# Copyright 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a
+# copy of this software and associated documentation files (the "Software"),
+# to deal in the Software without restriction, including without limitation
+# the rights to use, copy, modify, merge, publish, distribute, sublicense,
+# and/or sell copies of the Software, and to permit persons to whom the
+# Software is furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice (including the next
+# paragraph) shall be included in all copies or substantial portions of the
+# Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+# DEALINGS IN THE SOFTWARE.
+#
+
+#
+# Make a DocBook chart showing compose combinations for a locale
+#
+# See perldoc at end (or run with --help or --man options) for details
+# of command-line options.
+#
+
+# Compose file grammar is defined in modules/im/ximcp/imLcPrs.c
+
+use strict;
+use warnings;
+use Getopt::Long;
+use Pod::Usage;
+
+my $error_count = 0;
+
+my $charset;
+my $locale_name;
+my $output_filename = '-';
+my $man = 0;
+my $help = 0;
+my $make_index = 0;
+
+GetOptions ('charset:s' => \$charset,
+	    'locale=s' => \$locale_name,
+	    'output=s' => \$output_filename,
+	    'index' => \$make_index,
+	    'help|?' => \$help,
+	    'man' => \$man)
+    or pod2usage(2);
+pod2usage(1) if $help;
+pod2usage(-exitstatus => 0, -verbose => 2) if $man;
+
+if (!defined($charset) || ($charset eq "")) {
+  if (defined($locale_name)) {
+    my $guessed_charset = $locale_name;
+    $guessed_charset =~ s{^.*\.}{};
+    if ($guessed_charset =~ m{^(utf-8|gbk|gb18030)$}i) {
+      $charset = $1;
+    } elsif ($guessed_charset =~ m{iso8859-(\d+)}i) {
+      $charset = "iso-8859-$1";
+    } elsif ($guessed_charset =~ m{^microsoft-cp(125\d)$}) {
+      $charset = "windows-$1";
+    }
+  }
+  if (!defined($charset) || ($charset eq "")) {
+    $charset = "utf-8";
+  }
+}
+
+if ($make_index) {
+  # Print Docbook output
+  open my $OUTPUT, '>', $output_filename
+      or die "Could not create $output_filename: $!";
+
+  print $OUTPUT
+      join ("\n",
+	    qq(<?xml version="1.0" encoding="$charset" ?>),
+	    q(<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"),
+	    q( "http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd">),
+	    q(<article id="compose-index">),
+	    q(<simplesect>),
+	    q(<title>Xlib Compose Key Charts</title>),
+	    q(<simplelist type='horiz' columns='3'>),
+	    ( map { qq(<member><ulink url="$_.html">$_</ulink></member>) }
+	      @ARGV ),
+	    q(</simplelist>),
+	    q(</simplesect>),
+	    q(</article>),
+	    "\n"
+      );
+
+  close $OUTPUT or die "Couldn't write $output_filename: $!";
+
+  exit(0);
+}
+
+foreach my $a (@ARGV) {
+  $error_count += make_compose_chart($a);
+}
+
+exit($error_count);
+
+sub make_compose_chart {
+  my ($filename) = @_;
+  my $errors = 0;
+
+  my @compose_table = ();
+  my @included_files = ();
+
+  my $line = 0;
+  my $pre_file = ($filename =~ m{\.pre$}) ? 1 : 0;
+  my $in_c_comment = 0;
+  my $in_comment = 0;
+  my $keyseq_count = 0;
+
+  open my $COMPOSE, '<', $filename or die "Could not open $filename: $!";
+
+ COMPOSE_LINE:
+  while (my $cl = <$COMPOSE>) {
+    $line++;
+    chomp($cl);
+    my $original_line = $cl;
+
+    # Special handling for changes cpp makes to .pre files
+    if ($pre_file == 1) {
+      if ($in_c_comment) {		# Look for end of multi-line C comment
+	if ($cl =~ m{\*/(.*)$}) {
+	  $cl = $1;
+	  $in_c_comment = 0;
+	} else {
+	  next;
+	}
+      }
+      $cl =~ s{/\*.\**/}{};		# Remove single line C comments
+      if ($cl =~ m{^(.*)/\*}) {		# Start of a multi-line C comment
+	$cl = $1;
+	$in_c_comment = 1;
+      }
+      $cl =~ s{^\s*XCOMM}{#};		# Translate pre-processing comments
+    }
+
+    chomp($cl);
+
+    if ($cl =~ m{^\s*#\s*(.*)$}) {	# Comment only lines
+      # Combine commment blocks
+      my $comment = $1;
+
+      if ($in_comment) {
+	my $prev_comment = pop @compose_table;
+	$comment = join(' ', $prev_comment->{-comment}, $comment);
+      } else {
+	$in_comment = 1;
+      }
+
+      push @compose_table, { -type => 'comment', -comment => $comment };
+      next COMPOSE_LINE;
+    }
+
+    $in_comment = 0;
+
+    if ($cl =~ m{^\s*$}) {		# Skip blank lines
+      next COMPOSE_LINE;
+    }
+    elsif ($cl =~ m{^(STATE\s+|END_STATE)}) {
+      # Sun extension to compose file syntax
+      next COMPOSE_LINE;
+    }
+    elsif ($cl =~ m{^([^:]+)\s*:\s*(.+)$}) {
+      my ($seq, $action) = ($1, $2);
+      $seq =~ s{\s+$}{};
+
+      my @keys = grep { $_ !~ m/^\s*$/ } split /[\s\<\>]+/, $seq;
+
+      push @compose_table, {
+	-type => 'keyseq',
+	-keys => [ @keys ],
+	-action => $action
+      };
+      $keyseq_count++;
+      next COMPOSE_LINE;
+    } elsif ($cl =~ m{^(STATE_TYPE:|\@StartDeadKeyMap|\@EndDeadKeyMap)}) {
+      # ignore
+      next COMPOSE_LINE;
+    } elsif ($cl =~ m{^include "(.*)"}) {
+      my $incpath = $1;
+      $incpath =~ s{^X11_LOCALEDATADIR/(.*)/Compose}{the $1 compose table};
+
+      push @included_files, $incpath;
+      next COMPOSE_LINE;
+    } else {
+      print STDERR ('Unrecognized pattern in ', $filename,
+		    ' on line #', $line, ":\n  ", $cl, "\n");
+    }
+  }
+  close $COMPOSE;
+
+  if ($errors > 0) {
+    return $errors;
+  }
+
+  # Print Docbook output
+  open my $OUTPUT, '>', $output_filename
+      or die "Could not create $output_filename: $!";
+
+  print $OUTPUT
+      join ("\n",
+	    qq(<?xml version="1.0" encoding="$charset" ?>),
+	    q(<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"),
+	    q( "http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd">),
+	    qq(<article id="$locale_name">),
+	    q(<simplesect>),
+	    qq(<title>Xlib Compose Keys for $locale_name</title>),
+	    q(<para>Applications using Xlib input handling should recognize),
+	    q( these compose key sequences in locales using the),
+	    qq( $locale_name compose table.</para>),
+	    "\n"
+      );
+
+  if (@included_files) {
+    print $OUTPUT
+	q(<para>This compose table includes the non-conflicting),
+	q( entries from: ),
+	join(',', @included_files),
+	q(.  Those entries are not shown here - see those charts for the),
+	q( included key sequences.</para>),
+	"\n";
+  }
+
+  my @pretable_comments = ();
+
+  if ($keyseq_count == 0) {
+    @pretable_comments = @compose_table;
+  } elsif ($compose_table[0]->{-type} eq 'comment') {
+    push @pretable_comments, shift @compose_table;
+  }
+
+  foreach my $comment_ref (@pretable_comments) {
+    print $OUTPUT
+	qq(<para>), xml_escape($comment_ref->{-comment}), qq(</para>\n);
+  }
+
+  if ($keyseq_count > 0) {
+    start_table($OUTPUT);
+    my $row_count = 0;
+
+    foreach my $cr (@compose_table) {
+
+      if ($row_count++ > 750) {
+	# Break tables every 750 rows to avoid overflowing
+	# xmlto/xsltproc limits on the largest tables
+	end_table($OUTPUT);
+	start_table($OUTPUT);
+	$row_count = 0;
+      }
+
+      if ($cr->{-type} eq 'comment') {
+	print $OUTPUT
+	    qq(<row><entry namest='seq' nameend='action'>),
+	    xml_escape($cr->{-comment}), qq(</entry></row>\n);
+      } elsif ($cr->{-type} eq 'keyseq') {
+	my $action = join(" ", xml_escape($cr->{-action}));
+	if ($action =~ m{^\s*"\\([0-7]+)"}) {
+	  my $char = oct($1);
+	  if ($char >= 32) {
+	    $action =~ s{^\s*"\\[0-7]+"}{"&#$char;"};
+	  }
+	}
+	$action =~ s{^\s*"(.+)"}{"<literal>$1</literal>"};
+
+	print $OUTPUT
+	    qq(<row><entry>),
+	    qq(<keycombo action='seq'>),
+	    (map { qq(<keysym>$_</keysym>) } xml_escape(@{$cr->{-keys}})),
+	    qq(</keycombo>),
+	    qq(</entry><entry>),
+	    $action,
+	    qq(</entry></row>\n);
+      }
+    }
+
+    end_table($OUTPUT);
+  } else {
+    print $OUTPUT
+	qq(<para><emphasis>),
+	qq(This compose table defines no sequences of its own.),
+	qq(</emphasis></para>\n);
+  }
+  print $OUTPUT "</simplesect>\n</article>\n";
+
+  close $OUTPUT or die "Couldn't write $output_filename: $!";
+
+  return $errors;
+}
+
+sub xml_escape {
+  my @output;
+
+  foreach my $l (@_) {
+      $l =~ s{\&}{&amp;}g;
+      $l =~ s{\<}{&lt;}g;
+      $l =~ s{\>}{&gt;}g;
+      push @output, $l;
+  }
+  return @output;
+}
+
+sub start_table {
+  my ($OUTPUT) = @_;
+
+  print $OUTPUT
+      join("\n",
+	   qq(<table><title>Compose Key Sequences for $locale_name</title>),
+	   qq(<tgroup cols='2'>),
+	   qq( <colspec colname='seq' /><colspec colname='action' />),
+	   qq( <thead><row>),
+	   qq(  <entry>Key Sequence</entry><entry>Action</entry>),
+	   qq( </row></thead>),
+	   qq( <tbody>\n),
+      );
+}
+
+sub end_table {
+  my ($OUTPUT) = @_;
+
+  print $OUTPUT "</tbody>\n</tgroup>\n</table>\n";
+}
+
+__END__
+
+=head1 NAME
+
+compose-chart - Make DocBook/XML charts of compose table entries
+
+=head1 SYNOPSIS
+
+compose-chart [options] [file ...]
+
+ Options:
+    --charset[=<cset>]	character set to specify in XML doctype
+    --locale=<locale>	name of locale to display in chart
+    --output=<file>	filename to output chart to
+    --index		make index of charts instead of individual chart
+    --help		brief help message
+    --man		full documentation
+
+=head1 OPTIONS
+
+=over 8
+
+=item B<--charset>[=I<cset>]
+
+Specify a character set to list in the doctype declaration in the XML output.
+If not specified, attempts to guess from the locale name, else default to
+"utf-8".
+
+=item B<--locale>=I<locale>
+
+Specify the locale name to use in the chart titles and introductory text.
+
+=item B<--output>=I<file>
+
+Specify the output file to write the DocBook output to.
+
+=item B<--index>
+
+Generate an index of the listed locale charts instead of a chart for a
+specific locale.
+
+=item B<--help>
+
+Print a brief help message and exit.
+
+=item B<--man>
+
+Print the manual page and exit.
+
+=back
+
+=head1 DESCRIPTION
+
+This program will read the given compose table file(s) and generate
+DocBook/XML charts listing the available characters for end-user reference.
+
+=cut
diff --git a/specs/xmlrules.in b/specs/xmlrules.in
index 313d9bc..2af4130 100644
--- a/specs/xmlrules.in
+++ b/specs/xmlrules.in
@@ -21,6 +21,10 @@
 # DEALINGS IN THE SOFTWARE.
 #
 
+CLEANFILES =
+SUFFIXES =
+XMLTO_FLAGS =
+
 if HAVE_XMLTO
 spec_DATA = $(doc_sources:.xml=.html)
 
@@ -33,16 +37,16 @@ spec_DATA += $(doc_sources:.xml=.txt)
 endif
 
 if HAVE_STYLESHEETS
-XMLTO_FLAGS = -m $(XSL_STYLESHEET) --stringparam img.src.path=$(abs_builddir)/
+XMLTO_FLAGS += -m $(XSL_STYLESHEET) --stringparam img.src.path=$(abs_builddir)/
 
 spec_DATA += xorg.css
 xorg.css: $(STYLESHEET_SRCDIR)/xorg.css
 	$(AM_V_GEN)cp -pf $(STYLESHEET_SRCDIR)/xorg.css $@
 endif
 
-CLEANFILES = $(spec_DATA)
+CLEANFILES += $(spec_DATA)
 
-SUFFIXES = .xml .ps .pdf .txt .html
+SUFFIXES += .xml .ps .pdf .txt .html
 
 %.txt: %.xml $(dist_spec_DATA)
 	$(AM_V_GEN)$(XMLTO) $(XMLTO_FLAGS) txt $<
-- 
1.5.6.5



More information about the xorg-devel mailing list