summaryrefslogtreecommitdiffstats
path: root/contrib/gpinyin
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--contrib/gpinyin/ChangeLog200
-rw-r--r--contrib/gpinyin/gpinyin.1.man378
-rw-r--r--contrib/gpinyin/gpinyin.am56
-rwxr-xr-xcontrib/gpinyin/gpinyin.pl725
4 files changed, 1359 insertions, 0 deletions
diff --git a/contrib/gpinyin/ChangeLog b/contrib/gpinyin/ChangeLog
new file mode 100644
index 0000000..53cc228
--- /dev/null
+++ b/contrib/gpinyin/ChangeLog
@@ -0,0 +1,200 @@
+2022-10-09 G. Branden Robinson <g.branden.robinson@gmail.com>
+
+ * gpinyin.pl: Report groff version number along with this
+ program's own when not run from source tree. Drop dead code.
+ Bump micro version number to reflect recent restructuring.
+
+2022-10-09 G. Branden Robinson <g.branden.robinson@gmail.com>
+
+ Make gpinyin script stand alone.
+
+ * subs.pl: Delete, moving its content into...
+ * gpinyin.pl: ...here.
+ (vowel_t): Use explicit list with `my`.
+ (vowel_n, vowel_t): Declare local scalar `$vowel_with_tone`
+ using `my`.
+ * gpinyin.am (dist_gpinyin_DATA): Delete.
+
+2022-05-03 G. Branden Robinson <g.branden.robinson@gmail.com>
+
+ * gpinyin.am (gpinyin): Fix missing dependency on
+ `$(SH_DEPS_SED_SCRIPT)`.
+
+2021-05-11 G. Branden Robinson <g.branden.robinson@gmail.com>
+
+ * gpinyin.1.man: Render the tone mark table only if the output
+ device might be capable.
+
+ Fixes <https://savannah.gnu.org/bugs/index.php?55215>.
+
+2021-05-10 G. Branden Robinson <g.branden.robinson@gmail.com>
+
+ * gpinyin.1.man: Work around inability of grops and gropdf to
+ construct some Unicode composite characters. Use groff
+ composite special characters for "a" with acute and grave
+ accents, and define strings for "a" with macron (overline) and
+ with háček/caron accents. Use different string definitions for
+ nroff and troff modes so we don't regress UTF-8 terminal output.
+
+2021-05-10 G. Branden Robinson <g.branden.robinson@gmail.com>
+
+ * subs.pl (vowel_t): Fix incorrect rendering of base glyph 'U',
+ which was being forced to lowercase when a dieresis and tone
+ mark were both being applied. This caused the tone mark to
+ overlap the dieresis, so decrease the font size of the base
+ glyph even more to compensate. The result is ugly but
+ comprehensible.
+
+ See <https://savannah.gnu.org/bugs/?57524>, partially mitigated
+ but not completely resolved.
+
+2021-05-09 G. Branden Robinson <g.branden.robinson@gmail.com>
+
+ * subs.pl (%tones1_Unicode): Fix copy and paste error. Emit
+ U+01D5 (Latin capital letter u with dieresis and macron) for Ü
+ with tone 1, instead of U+016A (Latin capital letter u with
+ macron).
+
+ Fixes <https://savannah.gnu.org/bugs/?60562>.
+
+2021-05-09 G. Branden Robinson <g.branden.robinson@gmail.com>
+
+ * subs.pl (handle_word): Emit \[cq] instead of \[aq] when
+ interpolating an apostrophe before a vowel.
+
+ Fixes <https://savannah.gnu.org/bugs/?60561>.
+
+2021-05-09 G. Branden Robinson <g.branden.robinson@gmail.com>
+
+ * subs.pl (%tones_glyphs, %tones4_glyphs): Fix hash keys to use
+ the groff dotless i special character into which a lowercase "i"
+ has already been transformed instead of 'i' itself.
+ (vowel_n, vowel_t): Rename variable so that tone-transformed
+ vowel is stored separately. Add "or warn" to test the result
+ and cheaply assert that we got a string back from our hash
+ lookup on the vowel.
+
+ Fixes <https://savannah.gnu.org/bugs/?60560>.
+
+2021-01-06 Colin Watson <cjwatson@debian.org>
+
+ * gpinyin.pl: Avoid Perl's unsafe "<>" operator.
+
+ The "<>" operator is implemented using the two-argument form of
+ "open", which interprets magic such as pipe characters, allowing
+ execution of arbitrary commands which is unlikely to be
+ expected. Perl >= 5.22 has a "<<>>" operator which avoids this,
+ but also forbids the use of "-" to mean the standard input,
+ which is a facility that the affected groff programs document.
+
+ ARGV::readonly would probably also fix this, but I fundamentally
+ dislike the approach of escaping data in preparation for a
+ language facility to unescape it, especially when the required
+ escaping is as non-obvious as it is here. (For the same reason,
+ I prefer to use subprocess invocation facilities that allow
+ passing the argument list as a list rather than as a string to
+ be interpreted by the shell.) So I've abandoned this dubious
+ convenience and changed the affected programs to iterate over
+ command-line arguments manually using the three-argument form of
+ open.
+
+ Fixes <https://savannah.gnu.org/bugs/?55557>.
+
+2020-04-22 G. Branden Robinson <g.branden.robinson@gmail.com>
+
+ * gpinyin.1.man: Delete references to groffer.
+
+2018-02-28 Werner LEMBERG <wl@gnu.org>
+
+ * gpinyin.am (gpinyin): Use $(AM_V_GEN) to silence file generation.
+
+2015-08-22 Bernd Warken <groff-bernd.warken-72@web.de>
+
+ * gpinyin.1.man: Rename `gpinyin.man'.
+
+ * gpinyin.am: include renaming.
+
+2015-08-05 Bernd Warken <groff-bernd.warken-72@web.de>
+
+ * gpinyin.am: Add `Last update'. Setup Emacs mode.
+
+2015-04-03 Werner LEMBERG <wl@gnu.org>
+
+ * gpinyin.man: Make it work in compatibility mode.
+ (EL): Fix typo.
+
+2014-10-11 Werner LEMBERG <wl@gnu.org>
+
+ * Makefile.sub (gpinyin): Handle `gpinyin_dir'.
+
+2014-10-11 Bernd Warken <groff-bernd.warken-72@web.de>
+
+ * gpinyin.pl: Version 1.0.4
+ Remove `use IPC::System::Simple'.
+
+2014-10-10 Bernd Warken <groff-bernd.warken-72@web.de>
+
+ * gpinyin.pl: Version 1.0.3
+ Remove beginning empty line for `pinyin' parts.
+
+2014-09-25 Bernd Warken <groff-bernd.warken-72@web.de>
+
+ * gpinyin.pl: Version 1.0.2
+
+ * Makefile.sub: Add .PHONY. Restructure install and uninstall.
+
+2014-09-03 Bernd Warken <groff-bernd.warken-72@web.de>
+
+ Version 1.0.1
+
+ * all `gpinyin' files: Copying and Emacs settings.
+
+2014-08-27 Bernd Warken <groff-bernd.warken-72@web.de>
+
+ Version 1.0.0
+
+ * gpinyin.pl, subs.pl, gpinyin.man: Make `gpinyin' runnable.
+
+2014-08-08 Bernd Warken <groff-bernd.warken-72@web.de>
+
+ * gpinyin.pl: Version 0.9.2
+
+ * subs.pl: Rename `sub.pl'.
+
+ * Makefile.sub: Change `sub.pl' to `subs.pl'.
+
+2014-08-08 Bernd Warken <groff-bernd.warken-72@web.de>
+
+ * gpinyin.pl: Version 0.9.1
+
+ * sub.pl: New file for storing subs later on.
+
+ * Makefile.sub: Add new gpinyin path for sub.pl.
+
+2014-08-01 Bernd Warken <groff-bernd.warken-72@web.de>
+
+ * gpinyin.pl, gpinyin.man, ChangeLog, Makefile.sub:
+ First version 0.9.0 of gpinyin
+
+2014-08-01 Bernd Warken <groff-bernd.warken-72@web.de>
+________________________________________________________________________
+License
+
+Copyright (C) 2014-2020 Free Software Foundation, Inc.
+Written by Bernd Warken <groff-bernd.warken-72@web.de>.
+
+Copying and distribution of this file, with or without
+modification, are permitted provided the copyright notice and this
+notice are preserved.
+
+This file is part of `gpinyin', which is part of the `groff'
+project.
+
+##### Editor settings
+
+Local Variables:
+fill-column: 72
+mode: change-log
+version-control: never
+End:
+vim:set autoindent textwidth=72:
diff --git a/contrib/gpinyin/gpinyin.1.man b/contrib/gpinyin/gpinyin.1.man
new file mode 100644
index 0000000..3c3884e
--- /dev/null
+++ b/contrib/gpinyin/gpinyin.1.man
@@ -0,0 +1,378 @@
+'\" t
+.TH gpinyin @MAN1EXT@ "@MDATE@" "groff @VERSION@"
+.SH Name
+gpinyin \- use Hanyu Pinyin Chinese in
+.I groff
+documents
+.
+.
+.\" ====================================================================
+.\" Legal Terms
+.\" ====================================================================
+.\"
+.\" Copyright (C) 2014-2020 Free Software Foundation, Inc.
+.\"
+.\" This file is part of gpinyin, which is part of groff, a free
+.\" software project.
+.\"
+.\" You can redistribute it and/or modify it under the terms of the GNU
+.\" General Public License version 2 as published by the Free Software
+.\" Foundation.
+.\"
+.\" The license text is available in the internet at
+.\" <http://www.gnu.org/licenses/gpl-2.0.html>.
+.
+.
+.\" Save and disable compatibility mode (for, e.g., Solaris 10/11).
+.do nr *groff_gpinyin_1_man_C \n[.cp]
+.cp 0
+.
+.\" Define fallback for groff 1.23's MR macro if the system lacks it.
+.nr do-fallback 0
+.if !\n(.f .nr do-fallback 1 \" mandoc
+.if \n(.g .if !d MR .nr do-fallback 1 \" older groff
+.if !\n(.g .nr do-fallback 1 \" non-groff *roff
+.if \n[do-fallback] \{\
+. de MR
+. ie \\n(.$=1 \
+. I \%\\$1
+. el \
+. IR \%\\$1 (\\$2)\\$3
+. .
+.\}
+.rr do-fallback
+.
+.
+.\" ====================================================================
+.\" Local definitions
+.\" ====================================================================
+.
+.\" Define a string for the TeX logo.
+.ie t .ds TeX T\h'-.1667m'\v'.224m'E\v'-.224m'\h'-.125m'X
+.el .ds TeX TeX
+.
+.
+.\" ====================================================================
+.SH Synopsis
+.\" ====================================================================
+.
+.SY gpinyin
+.RI [ file\~ .\|.\|.]
+.YS
+.
+.
+.SY gpinyin
+.B \-h
+.
+.SY gpinyin
+.B \-\-help
+.YS
+.
+.SY gpinyin
+.B \-v
+.
+.SY gpinyin
+.B \-\-version
+.YS
+.
+.
+.\" ====================================================================
+.SH Description
+.\" ====================================================================
+.
+.I gpinyin
+is a preprocessor for
+.MR groff @MAN1EXT@
+that facilitates use of Hanyu Pinyin in
+.MR groff @MAN7EXT@
+files.
+.
+Pinyin is a method for writing the Mandarin Chinese language with the
+Latin alphabet.
+.
+Mandarin consists of more than four hundred base syllables,
+each spoken with one of five different tones.
+.
+Changing the tone applied to the syllable generally alters the meaning
+of the word it forms.
+.
+In Pinyin,
+a syllable is written in the Latin alphabet and a numeric tone indicator
+can be appended to each syllable.
+.
+.
+.P
+Each
+.I input-file
+is a file name or the character
+.RB \[lq] \- \[rq]
+to indicate that the standard input stream should be read.
+.
+As usual,
+the argument
+.RB \[lq] \-\- \[rq]
+can be used in order to force interpretation of all remaining arguments
+as file names,
+even if an
+.I input-file
+argument begins with a
+.RB \[lq] \- \[rq].
+.
+.B \-h
+and
+.B \-\-help
+display a usage message,
+while
+.B \-v
+and
+.B \-\-version
+show version information;
+all exit afterward.
+.
+.
+.\" ====================================================================
+.SS "Pinyin sections"
+.\" ====================================================================
+.
+Pinyin sections in
+.I groff
+files are enclosed by two
+.B .pinyin
+requests with different arguments.
+.
+The starting request is
+.RS
+.EX
+\&.pinyin start
+.EE
+.RE
+or
+.RS
+.EX
+\&.pinyin begin
+.EE
+.RE
+and the ending request is
+.RS
+.EX
+\&.pinyin stop
+.EE
+.RE
+or
+.RS
+.EX
+\&.pinyin end
+.EE
+.RE
+\&.
+.
+.
+.\" ====================================================================
+.SS Syllables
+.\" ====================================================================
+.
+In Pinyin,
+each syllable is represented by one to six letters drawn from the
+fifty-two upper- and lowercase letters of the Unicode basic Latin
+character set,
+plus the letter \[lq]U\[rq] with dieresis (umlaut) in both cases\[em]in
+other words,
+the members of the set \[lq][a\[en]zA\[en]Z\[:u]\[:U]]\[rq].
+.
+.
+.P
+In
+.I groff
+input,
+all basic Latin letters are written as themselves.
+.
+The \[lq]u with dieresis\[rq] can be written as
+\[lq]\e[:u]\[rq]
+in lowercase or
+\[lq]\e[:U]\[rq]
+in uppercase.
+.
+Within
+.B .pinyin
+sections,
+.I gpinyin
+supports the form
+\[lq]ue\[rq]
+for lowercase and the forms
+\[lq]Ue\[rq]
+and
+\[lq]UE\[rq]
+for uppercase.
+.
+.
+.\" ====================================================================
+.SS Tones
+.\" ====================================================================
+.
+Each syllable has exactly one of five
+.IR tones .
+.
+The fifth tone is not explicitly written at all,
+but each of the first through fourth tones is indicated with a diacritic
+above a specific vowel within the syllable.
+.
+.
+.P
+In a
+.I gpinyin
+source file,
+these tones are written by adding a numeral in the range 0 to 5 after
+the syllable.
+.
+The tone numbers 1 to 4 are transformed into accents above vowels in the
+output.
+.
+The tone numbers 0 and 5 are synonymous.
+.
+.
+.P
+.nr gpinyin*do-table 0
+.if t .nr gpinyin*do-table 1
+.if n .if '\*[.T]'utf8' .nr gpinyin*do-table 1
+.\" XXX: One hack necessitates another; since our table is conditional,
+.\" we need to save the input line counter.
+.nr gpinyin*.c \n[.c]
+.ie \n[gpinyin*do-table] \{\
+The tones are written as follows.
+.
+.
+.P
+.\" XXX: This is so gross. Why can't grops and gropdf figure this out?
+.if t .ds a- \za\[a-]
+.if n .ds a- \[a a-]
+.if t .ds a< \za\[ah]
+.if n .ds a< \[a ah]
+.if t .ne 8 \" Try to keep the table on one page for printed output.
+.TS
+l l l l l.
+Tone Description Diacritic Example Input Example Output
+_
+first flat \[a-] ma1 m\*[a-]
+second rising \[aa] ma2 m\[a aa]
+third falling-rising \[ah] ma3 m\*[a<]
+fourth falling \[ga] ma4 m\[a ga]
+fifth neutral (none) ma0 ma
+\^ \^ \^ ma5 \^
+.TE
+.\}
+.lf (\n[gpinyin*.c] + 25) \" XXX part 2: Restore input line counter.
+.el \{\
+[The tone mark table is omitted from this rendering of the man page
+because the selected output device \[lq]\*[.T]\[rq] lacks the character
+repertoire to display it.
+.
+Try another output device.]
+.\}
+.rm a-
+.rm a<
+.rr gpinyin*do-table
+.
+.
+.P
+The neutral tone number can be omitted from a word-final syllable,
+but not otherwise.
+.
+.
+.\" ====================================================================
+.SH Authors
+.\" ====================================================================
+.
+.I gpinyin
+was written by
+.MT groff\-bernd\:.warken\-72@\:web\:.de
+Bernd Warken
+.ME .
+.
+.
+.\" ====================================================================
+.SH "See also"
+.\" ====================================================================
+.
+Useful documents on the World Wide Web related to Pinyin include
+.RS 4n
+.UR http://\:www\:.foolsworkshop\:.com/\:ptou/\:index\:.html
+.I Pinyin to Unicode
+.UE ,
+.
+.br
+.UR http://\:www\:.mandarintools\:.com/
+.I On-line Chinese Tools \" sic: On-line
+.UE ,
+.
+.br
+.\" XXX: Turning off adjustment like this is ugly; thanks to meter-long
+.\" URLs we need an escape sequence that selectively disables adjustment
+.\" at the end of a word.
+.na
+.UR http://\:www\:.pinyin\:.info/\:index\:.html
+.I Pinyin.info: a guide to the writing of Mandarin Chinese in \
+romanization
+.UE ,
+.ad \*[AD]
+.
+.br
+.UR http://\:www\:.pinyin\:.info/\:rules/\:where.html
+\[lq]Where do the tone marks go?\[rq]
+.UE ,
+.
+.br
+.UR http://\:git\:.savannah\:.gnu\:.org/\:gitweb/\:\
+?p=cjk\:.git\:;a=blob_plain\:;f=doc/\:pinyin\:.txt\:;hb=HEAD
+.I pinyin.txt
+from the CJK macro package for \*[TeX]
+.UE ,
+.br
+.RS -4n
+and
+.RE
+.
+.br
+.\" XXX: Same ugliness as before.
+.na
+.UR http://\:git\:.savannah\:.gnu\:.org/\:gitweb/\:\
+?p=cjk\:.git\:;a=blob_plain\:;f=texinput/\:pinyin\:.sty\:;hb=HEAD
+.I pinyin.sty
+from the CJK macro package for \*[TeX]
+.UE .
+.ad \*[AD]
+.
+.RE
+.
+.
+.P
+.MR groff @MAN1EXT@
+and
+.MR grog @MAN1EXT@
+explain how to view
+.I roff
+documents.
+.
+.
+.P
+.MR groff @MAN7EXT@
+and
+.MR groff_char @MAN7EXT@
+are comprehensive references covering the language elements of GNU
+.I troff \" GNU
+and the available glyph repertoire,
+respectively.
+.
+.
+.\" Clean up.
+.rm TeX
+.
+.\" Restore compatibility mode (for, e.g., Solaris 10/11).
+.cp \n[*groff_gpinyin_1_man_C]
+.do rr *groff_gpinyin_1_man_C
+.
+.
+.\" Local Variables:
+.\" fill-column: 72
+.\" mode: nroff
+.\" End:
+.\" vim: set filetype=groff textwidth=72:
diff --git a/contrib/gpinyin/gpinyin.am b/contrib/gpinyin/gpinyin.am
new file mode 100644
index 0000000..78cc35a
--- /dev/null
+++ b/contrib/gpinyin/gpinyin.am
@@ -0,0 +1,56 @@
+# Automake rules for 'gpinyin' (preprocessor for added Perl parts)
+
+# Copyright (C) 2014-2020 Free Software Foundation, Inc.
+# Written by Bernd Warken <groff-bernd.warken-72@web.de>.
+# Moved to automake by Bertrand Garrigues
+
+# This file is part of 'gpinyin' which is part of 'groff'.
+
+# 'groff' is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 2 of the License, or
+# (at your option) any later version.
+
+# 'groff' is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see
+# <http://www.gnu.org/licenses/gpl-2.0.html>.
+
+########################################################################
+
+gpinyin_srcdir = $(top_srcdir)/contrib/gpinyin
+bin_SCRIPTS += gpinyin
+gpinyindir = $(gpinyin_dir)
+man1_MANS += contrib/gpinyin/gpinyin.1
+EXTRA_DIST += \
+ contrib/gpinyin/ChangeLog \
+ contrib/gpinyin/gpinyin.1.man \
+ contrib/gpinyin/gpinyin.pl
+
+gpinyin: contrib/gpinyin/gpinyin.pl $(SH_DEPS_SED_SCRIPT)
+ $(AM_V_GEN)sed -f "$(SH_DEPS_SED_SCRIPT)" \
+ -e "s|[@]g[@]|$(g)|g" \
+ -e "s|[@]BINDIR[@]|$(DESTDIR)$(bindir)|g" \
+ -e "s|[@]gpinyin_dir[@]|$(DESTIR)$(gpinyin_dir)|" \
+ -e "s|[@]VERSION[@]|$(VERSION)|g" \
+ -e "$(SH_SCRIPT_SED_CMD)" \
+ $(gpinyin_srcdir)/gpinyin.pl \
+ >$@ \
+ && chmod +x $@
+
+uninstall_groffdirs: uninstall-gpinyin-hook
+uninstall-gpinyin-hook:
+ if test -d $(DESTDIR)$(gpinyindir); then \
+ rmdir $(DESTDIR)$(gpinyindir); \
+ fi
+
+
+# Local Variables:
+# mode: makefile-automake
+# fill-column: 72
+# End:
+# vim: set autoindent filetype=automake textwidth=72:
diff --git a/contrib/gpinyin/gpinyin.pl b/contrib/gpinyin/gpinyin.pl
new file mode 100755
index 0000000..73b3034
--- /dev/null
+++ b/contrib/gpinyin/gpinyin.pl
@@ -0,0 +1,725 @@
+#! /usr/bin/env perl
+
+# gpinyin - European-like Chinese writing 'pinyin' into 'groff'
+
+# Copyright (C) 2014-2020 Free Software Foundation, Inc.
+
+# Written by Bernd Warken <groff-bernd.warken-72@web.de>.
+
+my $version = '1.0.5';
+my $groff_version = '(groff @VERSION@) '; # with trailing space
+
+# This file is part of 'gpinyin', which is part of 'groff'.
+
+# 'groff' is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 2 of the License, or
+# (at your option) any later version.
+
+# 'groff' is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+
+# You can find a copy of the GNU General Public License in the internet
+# at <http://www.gnu.org/licenses/gpl-2.0.html>.
+
+########################################################################
+
+use strict;
+use warnings;
+#use diagnostics;
+
+# temporary dir and files
+use File::Temp qw/ tempfile tempdir /;
+
+# needed for temporary dir
+use File::Spec;
+
+# for 'copy' and 'move'
+use File::Copy;
+
+# for fileparse, dirname and basename
+use File::Basename;
+
+# current working directory
+use Cwd;
+
+# $Bin is the directory where this script is located
+use FindBin;
+
+
+########################################################################
+# system variables and exported variables
+########################################################################
+
+$\ = "\n"; # final part for print command
+
+{
+ my $at = '@';
+ $groff_version = '' if '@VERSION@' eq "${at}VERSION${at}";
+}
+
+########################################################################
+# All Pinyin syllables from wikipedia
+########################################################################
+
+my %syllables =
+ (
+ 'a' => 1, 'ai' => 1, 'an' => 1, 'ang' => 1, 'ao' => 1,
+ 'ba' => 1, 'bai' => 1, 'ban' => 1, 'bang' => 1, 'bao' => 1,
+ 'bei' => 1, 'ben' => 1, 'beng' => 1,
+ 'bi' => 1, 'bian' => 1, 'biao' => 1, 'bie' => 1, 'bin' => 1,
+ 'bing' => 1, 'bo' => 1, 'bu' => 1,
+ 'ca' => 1, 'cai' => 1, 'can' => 1, 'cang' => 1, 'cao' => 1,
+ 'ce' => 1, 'cen' => 1, 'ceng' => 1,
+ 'cha' => 1, 'chai' => 1, 'chan' => 1, 'chang' => 1, 'chao' => 1,
+ 'che' => 1, 'chen' => 1, 'cheng' => 1, 'chi' => 1,
+ 'chong' => 1, 'chou' => 1, 'chu' => 1,
+ 'chua' => 1, 'chuai' => 1, 'chuan' => 1, 'chuang' => 1,
+ 'chui' => 1, 'chun' => 1, 'chuo' => 1,
+ 'ci' => 1, 'cong' => 1, 'cou' => 1,
+ 'cu' => 1, 'cuan' => 1, 'cui' => 1, 'cun' => 1, 'cuo' => 1,
+ 'da' => 1, 'dai' => 1, 'dan' => 1, 'dang' => 1, 'dao' => 1,
+ 'de' => 1, 'dei' => 1, 'den' => 1, 'deng' => 1,
+ 'di' => 1, 'dian' => 1, 'diao' => 1, 'die' => 1,
+ 'ding' => 1, 'diu' => 1, 'dong' => 1, 'dou' => 1,
+ 'du' => 1, 'duan' => 1, 'dui' => 1, 'dun' => 1, 'duo' => 1,
+ 'e' => 1, 'ei' => 1, 'en' => 1, 'eng' => 1, 'er' => 1,
+ 'fa' => 1, 'fan' => 1, 'fang' => 1,
+ 'fei' => 1, 'fen' => 1, 'feng' => 1, 'fiao' => 1,
+ 'fo' => 1, 'fou' => 1, 'fu' => 1,
+ 'ga' => 1, 'gai' => 1, 'gan' => 1, 'gang' => 1, 'gao' => 1,
+ 'ge' => 1, 'gei' => 1, 'gen' => 1, 'geng' => 1,
+ 'gong' => 1, 'gou' => 1, 'gu' => 1,
+ 'gua' => 1, 'guai' => 1, 'guan' => 1, 'guang' => 1, 'gui' => 1,
+ 'gun' => 1, 'guo' => 1,
+ 'ha' => 1, 'hai' => 1, 'han' => 1, 'hang' => 1, 'hao' => 1,
+ 'he' => 1, 'hei' => 1, 'hen' => 1, 'heng' => 1,
+ 'hong' => 1, 'hou' => 1,
+ 'hu' => 1, 'hua' => 1, 'huai' => 1, 'huan' => 1, 'huang' => 1,
+ 'hui' => 1, 'hun' => 1, 'huo' => 1,
+ 'ji' => 1, 'jia' => 1, 'jian' => 1, 'jiang' => 1, 'jiao' => 1,
+ 'jie' => 1, 'jin' => 1, 'jing' => 1, 'jiong' => 1, 'jiu' => 1,
+ 'ju' => 1, 'juan' => 1, 'jue' => 1, 'jun' => 1,
+ 'ka' => 1, 'kai' => 1, 'kan' => 1, 'kang' => 1, 'kao' => 1,
+ 'ke' => 1, 'kei' => 1, 'ken' => 1, 'keng' => 1,
+ 'kong' => 1, 'kou' => 1, 'ku' => 1, 'kua' => 1, 'kuai' => 1,
+ 'kuan' => 1, 'kuang' => 1, 'kui' => 1, 'kun' => 1, 'kuo' => 1,
+ 'la' => 1, 'lai' => 1, 'lan' => 1, 'lang' => 1, 'lao' => 1,
+ 'le' => 1, 'lei' => 1, 'leng' => 1,
+ 'li' => 1, 'lia' => 1, 'lian' => 1, 'liang' => 1, 'liao' => 1,
+ 'lie' => 1, 'lin' => 1, 'ling' => 1, 'liu' => 1,
+ 'lo' => 1, 'long' => 1, 'lou' => 1,
+ 'lu' => 1, 'luan' => 1, 'lun' => 1, 'luo' => 1,
+ 'lü' => 1, 'lüe' => 1,
+ 'ma' => 1, 'mai' => 1, 'man' => 1, 'mang' => 1, 'mao' => 1,
+ 'me' => 1, 'mei' => 1, 'men' => 1, 'meng' => 1,
+ 'mi' => 1, 'mian' => 1, 'miao' => 1, 'mie' => 1,
+ 'min' => 1, 'ming' => 1, 'miu' => 1,
+ 'mo' => 1, 'mou' => 1, 'mu' => 1,
+ 'na' => 1, 'nai' => 1, 'nan' => 1, 'nang' => 1, 'nao' => 1,
+ 'ne' => 1, 'nei' => 1, 'nen' => 1, 'neng' => 1,
+ 'ni' => 1, 'nian' => 1, 'niang' => 1, 'niao' => 1, 'nie' => 1,
+ 'nin' => 1, 'ning' => 1, 'niu' => 1, 'nong' => 1, 'nou' => 1,
+ 'nu' => 1, 'nuan' => 1, 'nun' => 1, 'nuo' => 1,
+ 'nü' => 1, 'nüe' => 1,
+ 'o' => 1, 'ong' => 1, 'ou' => 1,
+ 'pa' => 1, 'pai' => 1, 'pan' => 1, 'pang' => 1, 'pao' => 1,
+ 'pei' => 1, 'pen' => 1, 'peng' => 1,
+ 'pi' => 1, 'pian' => 1, 'piao' => 1, 'pie' => 1, 'pin' => 1,
+ 'ping' => 1, 'po' => 1, 'pou' => 1, 'pu' => 1,
+ 'qi' => 1, 'qia' => 1, 'qian' => 1, 'qiang' => 1, 'qiao' => 1, 'qie' => 1,
+ 'qin' => 1, 'qing' => 1, 'qiong' => 1, 'qiu' => 1,
+ 'qu' => 1, 'quan' => 1, 'que' => 1, 'qun' => 1,
+ 'ran' => 1, 'rang' => 1, 'rao' => 1, 're' => 1, 'ren' => 1,
+ 'ri' => 1, 'rong' => 1, 'rou' => 1,
+ 'ru' => 1, 'ruan' => 1, 'rui' => 1, 'run' => 1, 'ruo' => 1,
+ 'sa' => 1, 'sai' => 1, 'san' => 1, 'sang' => 1, 'sao' => 1,
+ 'se' => 1, 'sen' => 1, 'seng' => 1,
+ 'sha' => 1, 'shai' => 1, 'shan' => 1, 'shang' => 1, 'shao' => 1,
+ 'she' => 1, 'shei' => 1, 'shen' => 1, 'sheng' => 1, 'shi' => 1,
+ 'shou' => 1, 'shu' => 1, 'shua' => 1, 'shuai' => 1, 'shuan' => 1,
+ 'shuang' => 1, 'shui' => 1, 'shun' => 1, 'shuo' => 1,
+ 'si' => 1, 'song' => 1, 'sou' => 1, 'su' => 1, 'suan' => 1, 'sui' => 1,
+ 'sun' => 1, 'suo' => 1,
+ 'ta' => 1, 'tai' => 1, 'tan' => 1, 'tang' => 1, 'tao' => 1,
+ 'te' => 1, 'teng' => 1,
+ 'ti' => 1, 'tian' => 1, 'tiao' => 1, 'tie' => 1, 'ting' => 1,
+ 'tong' => 1, 'tou' => 1,
+ 'tu' => 1, 'tuan' => 1, 'tui' => 1, 'tun' => 1, 'tuo' => 1,
+ 'wa' => 1, 'wai' => 1, 'wan' => 1, 'wang' => 1,
+ 'wei' => 1, 'wen' => 1, 'weng' => 1, 'wo' => 1, 'wu' => 1,
+ 'xi' => 1, 'xia' => 1, 'xian' => 1, 'xiang' => 1, 'xiao' => 1,
+ 'xie' => 1, 'xin' => 1, 'xing' => 1, 'xiong' => 1, 'xiu' => 1,
+ 'xu' => 1, 'xuan' => 1, 'xue' => 1, 'xun' => 1,
+ 'ya' => 1, 'yai' => 1, 'yan' => 1, 'yang' => 1, 'yao' => 1,
+ 'ye' => 1, 'yi' => 1, 'yin' => 1, 'ying' => 1,
+ 'yo' => 1, 'yong' => 1, 'you' => 1,
+ 'yu' => 1, 'yuan' => 1, 'yue' => 1, 'yun' => 1,
+ 'za' => 1, 'zai' => 1, 'zan' => 1, 'zang' => 1, 'zao' => 1,
+ 'ze' => 1, 'zei' => 1, 'zen' => 1, 'zeng' => 1,
+ 'zha' => 1, 'zhai' => 1, 'zhan' => 1, 'zhang' => 1, 'zhao' => 1,
+ 'zhe' => 1, 'zhei' => 1, 'zhen' => 1, 'zheng' => 1, 'zhi' => 1,
+ 'zhong' => 1, 'zhou' => 1, 'zhu' => 1, 'zhua' => 1, 'zhuai' => 1,
+ 'zhuan' => 1, 'zhuang' => 1, 'zhui' => 1, 'zhun' => 1, 'zhuo' => 1,
+ 'zi' => 1, 'zong' => 1, 'zou' => 1, 'zu' => 1, 'zuan' => 1,
+ 'zui' => 1, 'zun' => 1, 'zuo' => 1,
+ );
+
+########################################################################
+# Unicode variables for utf8 tty (nroff)
+########################################################################
+
+my %tones1_Unicode =
+ (
+ 'A' => q(\\[u0100]),
+ 'E' => q(\\[u0112]),
+ 'I' => q(\\[u012A]),
+ 'O' => q(\\[u014C]),
+ 'U' => q(\\[u016A]),
+ 'Ü' => q(\\[u01D5]),
+ 'a' => q(\\[u0101]),
+ 'e' => q(\\[u0113]),
+ 'i' => q(\\[u012B]),
+ 'o' => q(\\[u014D]),
+ 'u' => q(\\[u016B]),
+ 'ü' => q(\\[u01D6]),
+ );
+
+my %tones2_Unicode =
+ (
+ 'A' => q(\\[u00C1]),
+ 'E' => q(\\[u00C9]),
+ 'I' => q(\\[u00CD]),
+ 'O' => q(\\[u00D3]),
+ 'U' => q(\\[u00DA]),
+ 'Ü' => q(\\[u01D7]),
+ 'a' => q(\\[u00E1]),
+ 'e' => q(\\[u00E9]),
+ 'i' => q(\\[u00ED]),
+ 'o' => q(\\[u00F3]),
+ 'u' => q(\\[u00FA]),
+ 'ü' => q(\\[u01D8]),
+ );
+
+my %tones3_Unicode =
+ (
+ 'A' => q(\\[u01CD]),
+ 'E' => q(\\[u011A]),
+ 'I' => q(\\[u01CF]),
+ 'O' => q(\\[u01D1]),
+ 'U' => q(\\[u01D3]),
+ 'Ü' => q(\\[u01D9]),
+ 'a' => q(\\[u01CE]),
+ 'e' => q(\\[u011B]),
+ 'i' => q(\\[u01D0]),
+ 'o' => q(\\[u01D2]),
+ 'u' => q(\\[u01D4]),
+ 'ü' => q(\\[u01DA]),
+ );
+
+my %tones4_Unicode =
+ (
+ 'A' => q(\\[u00C0]),
+ 'E' => q(\\[u00C8]),
+ 'I' => q(\\[u00CC]),
+ 'O' => q(\\[u00D2]),
+ 'U' => q(\\[u00D9]),
+ 'Ü' => q(\\[u01DB]),
+ 'a' => q(\\[u00E0]),
+ 'e' => q(\\[u00E8]),
+ 'i' => q(\\[u00EC]),
+ 'o' => q(\\[u00F2]),
+ 'u' => q(\\[u00F9]),
+ 'ü' => q(\\[u01DC]),
+ );
+
+
+########################################################################
+# glyph variables for troff
+########################################################################
+
+#my $tone1_macron = '\\[a-]';
+#my $tone2_acute = '\\[aa]';
+#my $tone3_caron = '\\[ah]';
+#my $tone4_grave = '\\[ga]';
+my @accents = ( '', '\\[a-]', '\\[aa]', '\\[ah]', '\\[ga]', );
+
+my %tones2_glyphs =
+ (
+ 'A' => q(\\['A]),
+ 'E' => q(\\['E]),
+ 'I' => q(\\['I]),
+ 'O' => q(\\['O]),
+ 'U' => q(\\['U]),
+ 'a' => q(\\['a]),
+ 'e' => q(\\['e]),
+ '\\[.i]' => q(\\['i]),
+ 'o' => q(\\['o]),
+ 'u' => q(\\['u]),
+ );
+
+my %tones4_glyphs =
+ (
+ 'A' => q(\\[`A]),
+ 'E' => q(\\[`E]),
+ 'I' => q(\\[`I]),
+ 'O' => q(\\[`O]),
+ 'U' => q(\\[`U]),
+ 'a' => q(\\[`a]),
+ 'e' => q(\\[`e]),
+ '\\[.i]' => q(\\[`i]),
+ 'o' => q(\\[`o]),
+ 'u' => q(\\[`u]),
+ );
+
+
+
+########################################################################
+# subs
+########################################################################
+
+# Pinyin consists of syllables with a final number to be translated
+# into an accent. Such numbered syllables are combined into words.
+# Such words can have a final punctuation. A line is a collection of
+# such words.
+
+my @roffs = ( 'n',
+ 't',
+ );
+
+########################################################################
+sub err {
+ my $s = shift;
+ print STDERR $s;
+ 1;
+} # err()
+
+
+########################################################################
+sub handle_line {
+ my $starting_blanks = shift;
+ my $line = shift;
+
+#&err('handle_line start: ' . $line);
+
+ my %outline = ( 'n' => $starting_blanks, 't' => $starting_blanks, );
+
+ # transform to Ü only for inside of Perl
+ $line =~ s/\\
+ \(:U
+ /Ü/gx;
+ $line =~ s/\\
+ \[:U\]
+ /Ü/gx;
+
+# handle_line()
+
+ # transform to ü only for inside of Perl
+ $line =~ s/\\
+ \(:u
+ /ü/gx;
+ $line =~ s/\\
+ \[:u\]
+ /ü/gx;
+
+ $line =~ s/U[eE]/Ü/g;
+ $line =~ s/u[eE]/ü/g;
+
+ $line =~ s/\\\(aq/'/g; # \(aq is an apostrophe
+ $line =~ s/\\\[aq\]/'/g; # \[aq] is an apostrophe
+ $line =~ s/^[']//; # remove leading apostrophe
+ $line =~ s/[']$//; # remove final apostrophe
+ $line =~ s/['][']+/'/g; # combine apostrophe groups
+ $line =~ s/([0-4])'/$1/;
+ $line =~ s/([^0-4])'/${1}0/;
+
+ my @words = split /\s+/, $line;
+
+
+# handle_line()
+ for my $word ( @words ) {
+#&err('handle_line word: ' . $word);
+
+ next unless ( $word );
+
+ # this is a word, maybe composed of several syllables
+ my $punctuation = $1 if ( $word =~ s/([,.?!:;]*)$// );
+ # '$word' is now without punctuation
+
+ my %outword = &handle_word($word);
+ next unless ( %outword );
+
+ for my $roff ( @roffs ) {
+#&err('handle_line roff ' . $roff . ': ' . $outword{$roff});
+
+ # combine words to line
+ next unless ( $outword{$roff} );
+
+ # non-initial space
+ $outline{$roff} .= ' ' if ( $outline{$roff} );
+
+ $outline{$roff} .= $outword{$roff};
+ $outline{$roff} .= $punctuation;
+ }
+ }
+#for my $roff ( @roffs ) {
+#&err('handle_line end ' . $roff . ': ' . $outline{$roff});
+#}
+ return %outline;
+} # handle_line()
+
+
+########################################################################
+sub handle_word {
+ my $word = shift;
+#&err('handle_word start: ' . $word);
+
+ $word =~ s/5/0/g; # transform 5 to 0
+ $word =~ s/([^0-4])$/${1}0/; # add lacking final no-tone
+
+ # remove apostrophes with tone
+ $word =~ s/
+ ([0-4])
+ [']
+ /$1/gx;
+ # replace apostrophes without tone by 0
+ $word =~ s/
+ ([^0-4])
+ [']
+ /${1}0/gx;
+
+# handle_word()
+ # detect wrong tone numbers
+ if ( $word =~ s/[5-9]/0/g ) {
+ &err('word ' . $word . ': wrong tone number ' . $1);
+ return {};
+ }
+
+ $word =~ s/[']//g; # remove apostrophes
+
+ # remove starting apostrophe or number
+ $word =~ s/^(['0-4])+//;
+
+ # add 0 for final no-tone
+ $word .= '0' if ( $word =~ /[^0-4]$/ );
+
+ if ( $word =~ /^[0-9]/ ) { # word starts with number
+ print 'word: ' . $word . ' starts with tone number';
+ $word =~ s/^[0-9]+//;
+ }
+#&err('handle_word 0: ' . $word);
+
+# handle_word()
+
+ my %outword = ( 'n' => '', 't' => '', );
+
+ # split word into syllables
+ while ( $word =~ /^[a-zA-ZüÜ']/ ) {
+ $word =~ s/^([a-zA-ZüÜ']+)([0-4])//;
+ my $syll = $1;
+ my $tone = $2;
+#err('handle_word split: ' . $syll . ' ' . $tone);
+ my %outsyll = &handle_syll( $syll, $tone );
+ next unless ( %outsyll );
+ for my $roff ( @roffs ) {
+ my $out = $outsyll{$roff};
+ $out = '\\[cq]' . $out if ( $out && $out =~ /^[aeo]/ );
+ $outword{$roff} .= $out;
+#&err('handle_word ' . $roff . ': ' . $outword{$roff});
+ }
+ }
+ return %outword;
+} # handle_word()
+
+
+########################################################################
+sub handle_syll {
+ my $syll = shift;
+ my $tone = shift;
+#&err( 'handle_syll start: ' . $syll . ' ' . $tone);
+
+ my $lower_case = lc($syll);
+ $lower_case =~ s/Ü/ü/g;
+ unless ( exists($syllables{$lower_case}) ) {
+ err('The syllable ' . $syll . ' is not a Chinese syllable.');
+ return {};
+ }
+
+ my %outsyll = ( 'n' => '', 't' => '', );
+
+ if ( $tone == 0 ) { # no accent
+ # use u umlaut without accent
+ $syll =~ s/Ü/\\[:U]/g;
+ $syll =~ s/ü/\\[:u]/g;
+
+ for my $roff ( @roffs ) {
+ $outsyll{$roff} = $syll;
+#&err('handle_syll 0 outsyll ' . $roff . ': ' . $outsyll{$roff});
+ }
+ return %outsyll;
+ } # end of tone 0
+
+# handle_syll()
+
+ # split syllable
+ $syll =~
+ /^
+ ([a-zA-Z]*)
+ ([aeiouAEIOUüÜ]+)
+ ([a-zA-Z]*)
+ $/x;
+ my $initial = $1;
+ my $vowels = $2;
+ my $final = $3;
+ unless ( $vowels ) {
+ &err( 'Syllable ' . $syll . ' does not have vowels' );
+ return {};
+ }
+
+ # split vowels
+ my $vowels_before = '';
+ my $vowel = '';
+ my $vowels_after = '';
+
+# handle_syll()
+
+ # find vowel for accent
+ if ( $vowels =~ /^[aeiouAEIOU]$/ ) { # only 1 vowel
+#&err('handle_syll single vowel ' . $vowels);
+ $vowel = $vowels;
+ } elsif ( $vowels eq 'ü' ) {
+ $vowel = $vowels;
+ } elsif ( $vowels eq 'Ü' ) {
+ $vowel = $vowels;
+ } elsif ( $vowels =~ /^([^aeAE]*)([aeAE])(.*)$/ ) { # a, A, e or E
+ $vowels_before = $1;
+ $vowel = $2;
+ $vowels_after = $3;
+ } elsif ( $vowels =~ /^([^oO]*)(oO)(.*)$/ ) { # o or O
+ $vowels_before = $1;
+ $vowel = $2;
+ $vowels_after = $3;
+ } elsif ( $vowels =~ /^(\w)(\w)(.*)$/ ) { # take 2nd vowel
+ $vowels_before = $1;
+ $vowel = $2;
+ $vowels_after = $3;
+ } else {
+ &err( 'Unknown vowels: ' . $vowels . ' in syllable: ' . $syll );
+ return {};
+ }
+
+# unless ( $vowel =~ /^[aeiouAEIOU]$/ ) {
+# print STDERR q(The argument ') . $vowel . q(' is not a vowel!);
+# return {};
+# }
+
+# handle_syll()
+
+ $outsyll{'n'} = &vowel_n($vowel, $tone);
+ $outsyll{'t'} = &vowel_t($vowel, $tone);
+
+ for my $roff ( @roffs ) {
+ $outsyll{$roff} = $initial . $vowels_before .
+ $outsyll{$roff} . $vowels_after . $final;
+#&err('handle_syll out ' . $roff . ': ' . $outsyll{$roff});
+ }
+
+ return %outsyll;
+} # handle_syll()
+
+
+########################################################################
+sub vowel_n { # Unicode for nroff
+ my $vowel = shift;
+ my $tone = shift;
+#&err('vowel_n: ' . $vowel . ' ' . $tone);
+
+ return '' unless ( $vowel );
+
+ my $vowel_with_tone;
+ if ( $tone == 1 ) { # macron
+ $vowel_with_tone = $tones1_Unicode{$vowel};
+ } elsif ( $tone == 2 ) { # acute
+ $vowel_with_tone = $tones2_Unicode{$vowel};
+ } elsif ( $tone == 3 ) { # caron
+ $vowel_with_tone = $tones3_Unicode{$vowel};
+ } elsif ( $tone == 4 ) { # grave
+ $vowel_with_tone = $tones4_Unicode{$vowel};
+ }
+ $vowel_with_tone or warn "failed to apply tone $tone to vowel $vowel";
+ return $vowel_with_tone;
+} # vowel_nr()
+
+
+########################################################################
+sub vowel_t { # named glyphs for troff
+ my $vowel = shift;
+ my $tone = shift;
+#&err( 'vowel_t: ' . $vowel . ' ' . $tone);
+
+ return '' unless ( $vowel );
+
+ # \o'\s-2\[:u]\s0\[a-]'
+ if ( $vowel =~ /[üÜ]/ ) {
+ my ($ue, $smaller);
+ if ($vowel eq 'ü') {
+ $ue = q(\\[:u]);
+ $smaller = 2;
+ } else {
+ $ue = q(\\[:U]);
+ $smaller = 4;
+ }
+ $vowel = q(\\o'\\s-) . $smaller . $ue . q(\\s0) .
+ $accents[$tone] . q(');
+ return $vowel;
+ }
+
+ $vowel = q(\\[.i]) if ( $vowel eq 'i' );
+
+ my $vowel_with_tone;
+ if ( $tone == 1 ) { # macron
+ $vowel_with_tone = q(\\o') . $vowel . $accents[$tone] . q(');
+ } elsif ( $tone == 2 ) { # acute
+ $vowel_with_tone = $tones2_glyphs{$vowel};
+ } elsif ( $tone == 3 ) { # caron
+ $vowel_with_tone = q(\\o') . $vowel . $accents[$tone] . q(');
+ } elsif ( $tone == 4 ) { # grave
+ $vowel_with_tone = $tones4_glyphs{$vowel};
+ }
+ $vowel_with_tone or warn "failed to apply tone $tone to vowel $vowel";
+ return $vowel_with_tone;
+} # vowel_t()
+
+
+########################################################################
+sub finish_pinyin_mode {
+#&err( 'finish' );
+ my $n = shift;
+ my $t = shift;
+ push @$n, '\\}';
+ push @$t, '\\}';
+
+ for ( @$n ) { # Unicode for nroff
+ print;
+ }
+
+ for ( @$t ) { # glyphs for troff
+ print;
+ }
+
+ 1;
+} # finish_pinyin_mode()
+
+
+########################################################################
+# options
+########################################################################
+
+foreach (@ARGV) {
+ if ( /^(-h|--h|--he|--hel|--help)$/ ) {
+ print q(Usage for the 'gpinyin' program:);
+ print 'gpinyin [-] [--] [filespec...] normal file name arguments';
+ print 'gpinyin [-h|--help] gives usage information';
+ print 'gpinyin [-v|--version] displays the version number';
+ print q(This program is a 'groff' preprocessor that handles ) .
+ q(pinyin parts in 'roff' files.);
+ exit;
+ } elsif (/^(-v|--v|--ve|--ver|--vers|--versi|--versio|--version)$/) {
+ print "gpinyin ${groff_version}version $version";
+ exit;
+ }
+}
+
+
+########################################################################
+# input
+########################################################################
+
+my $pinyin_mode = 0; # not in Pinyin mode
+
+my @output_n = # nroff
+ (
+ '.ie n \\{\\',
+ );
+
+my @output_t = # troff
+ (
+ '.el \\{\\',
+ );
+
+unshift @ARGV, '-' unless @ARGV;
+foreach my $filename (@ARGV) {
+ my $input;
+ if ($filename eq '-') {
+ $input = \*STDIN;
+ } elsif (not open $input, '<', $filename) {
+ warn $!;
+ next;
+ }
+ while (<$input>) {
+ chomp;
+ s/\s+$//; # remove final spaces
+# &err('gpinyin: ' . $_);
+
+ my $line = $_; # with starting blanks
+
+ # .pinyin start or begin line
+ if ( $line =~ /^[.']\s*pinyin\s+(start|begin)$/ ) {
+ if ( $pinyin_mode ) {
+ # '.pinyin' was started twice, ignore
+ &err( q['.pinyin' starter was run several times] );
+ } else { # new pinyin start
+ $pinyin_mode = 1;
+ }
+ next;
+ }
+
+ # .pinyin stop or end line
+ if ( $line =~ /^[.']\s*pinyin\s+(stop|end)$/ ) {
+ if ( $pinyin_mode ) { # normal stop
+ $pinyin_mode = 0;
+ &finish_pinyin_mode( \@output_n, \@output_t );
+ } else { # ignore
+ &err( 'gpinyin: there was a .pinyin stop without ' .
+ 'being in pinyin mode' );
+ }
+ next;
+ }
+
+ # now not a .pinyin line
+
+
+ if ( $pinyin_mode ) { # within Pinyin
+ my $starting_blanks = '';
+ $starting_blanks = $1 if ( s/^(s+)// ); # handle starting spaces
+
+ my %outline = &handle_line($starting_blanks, $line);
+# &err('gpinyin outline n: ' . $outline{'n'} );
+# &err('gpinyin outline t: ' . $outline{'t'} );
+ push @output_n, $outline{'n'};
+ push @output_t, $outline{'t'};
+ } else { # normal roff line, not within Pinyin
+ print $line;
+ }
+ next;
+ } # end of input line
+}
+
+
+########################################################################
+# end of file without stopping 'pinyin' mode
+if ( $pinyin_mode ) {
+ &finish_pinyin_mode( \@output_n, \@output_t );
+}
+
+########################################################################
+
+
+1;
+# Local Variables:
+# fill-column: 72
+# mode: CPerl
+# End:
+# vim: set autoindent textwidth=72: