summaryrefslogtreecommitdiff
path: root/support/pydocstrip
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
committerNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
commite0c6872cf40896c7be36b11dcc744620f10adf1d (patch)
tree60335e10d2f4354b0674ec22d7b53f0f8abee672 /support/pydocstrip
Initial commit
Diffstat (limited to 'support/pydocstrip')
-rw-r--r--support/pydocstrip/COPYING280
-rw-r--r--support/pydocstrip/FILELIST22
-rw-r--r--support/pydocstrip/README39
-rw-r--r--support/pydocstrip/README_samples19
-rw-r--r--support/pydocstrip/docstrip.py629
-rw-r--r--support/pydocstrip/vnbase.dtx1600
-rw-r--r--support/pydocstrip/vndriver.dtx390
-rw-r--r--support/pydocstrip/vnparam.dtx105
-rw-r--r--support/pydocstrip/vnr.kins80
-rw-r--r--support/pydocstrip/vnr_cm.kins19
-rw-r--r--support/pydocstrip/vnr_ec.kins17
-rw-r--r--support/pydocstrip/vnr_pp.kins40
12 files changed, 3240 insertions, 0 deletions
diff --git a/support/pydocstrip/COPYING b/support/pydocstrip/COPYING
new file mode 100644
index 0000000000..3a39732cc8
--- /dev/null
+++ b/support/pydocstrip/COPYING
@@ -0,0 +1,280 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
diff --git a/support/pydocstrip/FILELIST b/support/pydocstrip/FILELIST
new file mode 100644
index 0000000000..dc35a37a57
--- /dev/null
+++ b/support/pydocstrip/FILELIST
@@ -0,0 +1,22 @@
+/////////////////////////////////
+
+You should open one of these files in an Editor
+and learn about the KINS file syntax
+
+vnr.kins Sample KINS file
+vnr_pp.kins Default Preamble/Postamble; this file is imported by vnr.kins
+vnr_ec.kins KINS file imported by vnr.kins
+vnr_cm.kins KINS file imported by vnr.kins
+
+//////////////////////////////////
+
+Below the DTX files used for test.
+Please see the DTX's documentation in the standard TeX distribution.
+
+vnbase.dtx | Sample DTX source files. These files are used by vnr.kins.
+vnparam.dtx | These files are part of VNR (Vietnamese Fonts for TeX)
+vndriver.dtx | and can be found at http://vnr.sarovar.org/menu=download
+
+//////////////////////////////////
+
+tempdir TempDir that is used for storing the output of TEST routine
diff --git a/support/pydocstrip/README b/support/pydocstrip/README
new file mode 100644
index 0000000000..2cf141eb49
--- /dev/null
+++ b/support/pydocstrip/README
@@ -0,0 +1,39 @@
+Please visit
+ http://docstrip.sarovar.org/
+for the full description on `docstrip.py`.
+
+docstrip.py
+
+* is the Python version of TeX's `docstrip` utility
+* but it use KINS files instead of TeX's INS file.
+
+* some advance functions of `docstrip.py`:
+ ----------------------------------------
+
+ a) Support the switches at the command line, for e.g,
+ docstrip.py -e "test=0;foo=1"
+ or
+ docstrip.py -e "test=1;foo=1"
+
+ With this features,
+ we can easily create a quite sophisticated generation.
+
+ b) Support the source-file-time checking:
+
+ If the (DTX) source file havenot changes, the `docstrip.py`
+ knows this and skips the generation. So if we have many DTX
+ files, or the DTX files have quite big size, we may save
+ very much time of generation.
+
+ (The behavior can be overwritten by using `--force` option.)
+
+ c) Can generate only files whose names match a regular expression:
+ for example:
+ docstrip.py [...] -g "foo[0-9]\.tex"
+ will generate "foo1.tex", "foo2.tex" but "foo100.tex"
+
+ d) Can run in DEBUG mode:
+
+ The DEBUG mode is turned on by the `--debug` option.
+ No file is generated; but we will know what `docstrip.py`
+ would do in the real mode.
diff --git a/support/pydocstrip/README_samples b/support/pydocstrip/README_samples
new file mode 100644
index 0000000000..865ca6fd55
--- /dev/null
+++ b/support/pydocstrip/README_samples
@@ -0,0 +1,19 @@
+This directory contains the samples for `docstrip.py`
+See FILELIST for the details.
+
+Please try one of following codes.
+(Watch for the results saved in ./tempdir before try any other code!)
+
+ docstrip.py -f -j vnr -e "test=0;nopre=1;destdir=./tempdir"
+ docstrip.py -f -j vnr -e "test=1;nopre=1;destdir=./tempdir"
+ docstrip.py -f -j vnr -e "test=0;nopre=1;destdir=./tempdir"
+ docstrip.py -f -j vnr -e "test=0;nopre=0;destdir=./tempdir"
+
+Because we are running a test, we should use the -f option;
+otherwise, the generation occurs only once!
+
+Under LINUX, you may firstly try
+ chmod +x docstrip.py
+
+If you are using Python for WIN32, you may try, for e.g.,
+ "your_python.exe" docstrip.py [...]
diff --git a/support/pydocstrip/docstrip.py b/support/pydocstrip/docstrip.py
new file mode 100644
index 0000000000..99a985967b
--- /dev/null
+++ b/support/pydocstrip/docstrip.py
@@ -0,0 +1,629 @@
+#!/usr/bin/env python
+import string,re,sys,stat,os,getopt,time
+
+## <VERSION
+SELF_VER = 1796
+## VERSION>
+
+SELF_INFOR = "ktv-docstrip (version Python.%d)" % SELF_VER
+GEN_DATE = "%d/%02d/%02d" % time.localtime()[:3]
+
+## :: Regular Expression
+
+## file DTX
+re_begin = re.compile("%<\*([!a-zA-Z(][()a-zA-Z0-9_|&!]*)>") # begin block
+re_end = re.compile("%</([!a-zA-Z(][()a-zA-Z0-9_|&!]*)>") # end block
+re_sblock = re.compile("%<([!a-zA-Z(][()a-zA-Z0-9_|&!]*)>(.+\n)")# inline block
+re_code = re.compile("^[^%]") # code
+
+## file KINS
+re_from = re.compile("\$from\(([^)]+)\)")
+re_gen = re.compile("\$gen\(([^)]+)\)[ ]*\(([^)]+)\)[ ]*(.*)")
+re_asg = re.compile("\$([a-z][a-z0-9_]*)[ ]*=[ ]*(.*)")
+## re_asg = re.compile("\$([a-z][a-z0-9_]*)[ ]*=[ ]*(.*)")
+re_kasg = re.compile("([a-z][a-zA-Z0-9_]*)[ ]*=[ ]*(.*)")
+re_com = re.compile("#.*") ## comment line
+re_isnum = re.compile("[+|-]*[0-9]+")
+re_local = re.compile("\$local\(([^)]+)\)")
+re_eof = re.compile("\$eof=([01])")
+## re_eoj = re.compile("\$eoj=([01])")
+re_import = re.compile("\$import\(([^)]+)\)") ## add, Ky Anh, 2003/12/25
+re_if = re.compile("\$if\(([^)]+)\)")
+re_elif = re.compile("\$elif\(([^)]+)\)")
+re_exec = re.compile("\$<<<(.*)")
+## re_expand = re.compile("\$\([a-z][a-z0-9_]*\)")
+
+def _xsplit(st):
+ """Tao list cac terminal/guard, bo qua &,|,!,(,)
+ Chi tra ve cac list chua co trong danh sach __guards ma thoi
+ """
+ ## last modify: Ky Anh, 2003/12/27
+ ## : use global __guards
+ global __guards
+ for ops in ['&', '(', ')', '!', '|', ',', ' ']:
+ st = string.replace(st, ops, ':')
+ tmp = []
+ for ops in string.split(st, ':'):
+ if (ops != '') and (not ops in __guards):
+ tmp.append(ops)
+ __guards.extend(tmp)
+ __use(tmp,0)
+
+def _translate(st): #
+ """Dich mot bieu thuc logic thanh loi chuan cua PYTHON"""
+ st = "(%s)" % st
+ idx = 0
+ tmpst = ""
+ find_next_op = 0
+ group_level = 0
+ while idx < len(st):
+ if st[idx] == '!':
+ tmpst = tmpst + "(not "
+ find_next_op = 1
+ elif st[idx] == '(':
+ tmpst = tmpst + '('
+ group_level = group_level + 1
+ elif st[idx] == ')':
+ tmpst = tmpst + ')'
+ group_level = group_level - 1
+ else: # !
+ if find_next_op:
+ while (find_next_op > 0) and (idx < len(st)):
+ if (st[idx] in __block_ops) or (group_level == 0):
+ tmpst = tmpst + ')' + st[idx]
+ find_next_op = 0
+ else:
+ tmpst = tmpst + st[idx]
+ idx = idx + 1
+ else:
+ tmpst = tmpst + st[idx]
+ idx = idx +1
+
+ idx = string.count(tmpst,'(') - string.count(tmpst,')')
+ while idx > 0 :
+ tmpst = tmpst + ')'
+ idx = idx - 1
+ return tmpst[1:-1]
+
+def __setval(guard, value=1):
+ ## add, Ky Anh, 2003/12/27
+ exec("global %s\n%s=%d" % (guard,guard,value))
+
+def __use(options, value=1):
+ ## add, Ky Anh, 2003/12/27
+ ## mod, Ky Anh, 2003/12/30, v1792, remove __alpha/__beta option check
+ for weapon in options:
+ tmpst = string.strip(weapon)
+ if tmpst: __setval(tmpst,value)
+## if tmpst in __alpha_options:
+## __setval(tmpst,1)
+## elif tmpst in __beta_options:
+## __setval(tmpst,0)
+## else:
+
+def _use(opts_string, value=1):
+ __use(string.split(opts_string, ","), value)
+
+def _do_global():
+ ## add, Ky Anh, 2003/12/27
+## _force_
+## _gonly_
+## _kins_nopre
+## _kins_nopost
+## _kins_debug
+## _kins_destdir
+## jobnames ## list of job (<kins> files)
+## __guards ## list of guard in DTX files
+## add, Ky Anh, 2003/12/27
+## NO ## list of NO-equivalent (0, No, NO, etc.)
+## __block_ops ## list of operators in a DTX guard (block)
+## __kins_vars ## list of global kins variables
+## __global_kins_vars ## kins variables that are also the global
+## variables in this program
+## __no_skip_vars ## variables appear in the third part of |$gen|
+## command; these variables arenot the <test>
+## __alpha_options ## this DTX options will always be set to 1
+## __beta_options ## - 0
+## _tex_ ## output as the INS file
+ global\
+ _force_,\
+ _gonly_,\
+ _kins_nopre,\
+ _kins_nopost,\
+ _kins_debug,\
+ _kins_destdir,\
+ jobnames,\
+ __guards,\
+ NO,\
+ __block_ops,\
+ __kins_vars,\
+ __global_kins_vars,\
+ __no_skip_vars,\
+ _tex_,\
+ _kins_pre_def,\
+ _kins_pos_def
+## __alpha_options,\
+## __beta_options
+
+ NO = ['0','no']
+
+ __block_ops = ['&','|'] ## donot accept the !. See the _translate()
+ __global_kins_vars = ["pre", "post"]
+ __no_skip_vars = ["append", "nopost", "nopre",\
+ "destdir", "source", "debug"]
+## __alpha_options = ["alpha", "com"]
+## __beta_options = []
+
+ jobnames = []
+ __guards = []
+
+ _force_ = 0
+ _gonly_ = 0
+ _tex_ = 0
+
+ ## initialize the global variables
+ ## these variable can be exported, i.e.,
+ ## we can use `--exec cmd' at command line.
+ _kins_nopre = '0'
+ _kins_nopost = '0'
+ _kins_debug = '0'
+ _kins_destdir = '.'
+ __kins_vars = ["nopre", "nopost", "destdir", "debug"]
+ _kins_pre_def = "%% This file was generate\n\
+%% \tfrom the file `$source'\n\
+%% \twith option `$option'\n\
+%% GenDate: $date\n\
+%% Generator: $generator\n"
+ _kins_pos_def = "%% End of file `$dest'"
+
+ ## init the <special> guards
+ ## we neednot do this, because if a guard appears in a DTX file
+ ## it is recognize by _xsplit and then set the value by __use
+ ## see the defintionof _xplist for more details
+ ## __use(__alpha_options + __beta_options)
+
+def _xstrip(options, debug=0):
+ """Tach ma tu file DTX voi options"""
+ global __ilines, __output
+ _use(options, 1)
+ __output = []
+ __level = 0
+ __prints = [1]
+ if debug: print "%s" % ("=" * 72),
+ for weapon in __ilines:
+ print_code = 0
+ if re_begin.match(weapon):
+ __level = __level + 1
+ if __prints[__level - 1]: # previous block
+ current_bblock = re_begin.match(weapon).group(1)
+ exec("print_code=%s" % _translate(current_bblock))
+ __prints.append(int(print_code))
+ if debug: print "\nlevel%2d %s *%s -> "\
+ % (__level,__prints,re_begin.match(weapon).group(1)),
+ elif re_end.match(weapon):
+ __level = __level - 1
+ if __level < 0: break
+ __prints.pop()
+ if debug: print "\nlevel%2d %s /%s -> "\
+ % (__level,__prints,re_end.match(weapon).group(1)),
+ elif re_sblock.match(weapon): #
+ if __prints[__level]:
+ current_bblock = re_sblock.match(weapon).group(1)
+ exec("print_code=%s" % _translate(current_bblock))
+ if debug: print "\nlevel%2d %s %s -> "\
+ % (__level,__prints,re_sblock.match(weapon).group(1)),
+ if print_code:
+ if debug: sys.stdout.write('s')
+ else: __output.append(re_sblock.match(weapon).group(2))
+ if debug:
+ print "\nlevel%2d %s -> " % (__level,__prints),
+ elif re_code.match(weapon):
+ if __prints[__level]:
+ if debug: sys.stdout.write('n')
+ else: __output.append(weapon)
+ if __level:
+ print \
+"\nThe blocks of your DTX file donot balance.\n\
+To debug, use <docstrip> with `--debug' option."
+ if debug: print "\n%s" % ("=" * 72)
+
+ _use(options, 0) # reset options' value to 0
+
+def _readkins(filename):
+ ## add, Ky Anh, 2003/12/25
+ """Read a KINS file, remove the comment line, and strip the lines.
+ This function returns a LIST of KINS lines."""
+ mykinslines = []
+ f = open(filename, 'r')
+ iline = f.readline()
+ while iline:
+ iline = re_com.split(iline)[0]
+ iline = string.strip(iline)
+ if re_eof.match(iline):
+ if re_eof.match(iline).group(1) == '1':
+ break ## reach END OF FILE
+ elif iline:
+ mykinslines.append(iline)
+ iline = f.readline()
+ f.close()
+ return mykinslines
+
+def _dokins(filename):
+ """Excute the KINS code. The original name is |_readkins|; this version
+ wasnot support |$import|. To do |$import|, a new function |_readkins| was
+ added, and this function is now named |_dokins|."""
+ global _kins_pre, _kins_post, kins_lines, _kins_pre_def, _kins_pos_def
+ kins_lines = []
+ __imported = [] # list of imported files
+
+ _kins_pre = _kins_pre_def # default preamble/
+ _kins_post = _kins_pos_def # default /postamble
+ _kins_source= ''
+
+ in_pre = in_post = 0
+ in_if = [1]
+ __iflevel = 0
+ __ifcont = []
+
+ kins_lines = _readkins(filename)
+
+ while kins_lines:
+ iline = kins_lines.pop(0)
+## :: = $if
+ if re_if.match(iline):
+ if_value = 0
+ __iflevel = __iflevel + 1
+ if in_if[__iflevel - 1]:
+ var_name = re_if.match(iline).group(1)
+ if re_kasg.match(var_name):
+ var_value = re_kasg.match(var_name).group(2)
+ var_name = re_kasg.match(var_name).group(1)
+ try:
+ if var_name in __kins_vars:
+ exec("tmp_value=_kins_%s" % var_name)
+ else:
+ exec("tmp_value=_gen_%s" % var_name)
+ if var_value == tmp_value:
+ if_value = 1
+ except NameError: pass
+ in_if.append(if_value)
+## :: = $elif
+ elif re_elif.match(iline):
+ __iflevel = __iflevel - 1
+ iline = "$if%s" % iline[5:]
+ kins_lines.insert(0, iline)
+## :: = $else
+ elif iline == "$else":
+ in_if[__iflevel] = 1 - in_if[__iflevel]
+## :: = $enif
+ elif iline == "$enif":
+ __iflevel = __iflevel - 1
+ if __iflevel < 0:
+ sys.stderr.write(\
+ "\nerror: to much $enif. The program is going to stop.\n")
+ sys.exit(1)
+ else:
+ in_if.pop()
+ if __iflevel == 0:
+ kins_lines[0:0], __ifcont = __ifcont, []
+ elif __iflevel:
+ if in_if[__iflevel]:
+ __ifcont.append(iline)
+## :: = pre, post
+ elif iline == "$pre": _kins_pre, in_pre = "", 1
+ elif iline == "$post": _kins_post, in_post = "", 1
+ elif iline == "$enpre": in_pre = 0
+ elif iline == "$enpost": in_post = 0
+## ## :: = $(.+)
+## elif re_expand.match(iline):
+## var_name = re_expand.match(iline).group(1)
+## :: = $<<<<
+ elif re_exec.match(iline):
+ try:
+ exec(re_exec.match(iline).group(1))
+ except:
+ sys.stderr.write("E")
+## :: = if in_pre, in_post
+ ## hai do`ng sau pha?i dde^? sau bo^'n do`ng tre^n
+ elif in_pre: _kins_pre = _kins_pre + iline + '\n'
+ elif in_post: _kins_post = _kins_post + iline + '\n'
+## :: = $from
+ elif re_from.match(iline): # from macro
+ _kins_source = re_from.search(iline).group(1)
+ _readsource(_kins_source)
+ sys.stderr.write('_')
+## :: = $import
+ elif re_import.match(iline):
+ _i_file = re_import.match(iline).group(1)
+ if not _i_file in __imported:
+ __imported.append(_i_file)
+ if not string.lower(_i_file[-5:]) == ".kins":
+ _i_file = _i_file + ".kins"
+ kins_lines[0:0] = _readkins(_i_file)
+ sys.stderr.write('=')
+ else:
+ sys.stderr.write('*')
+## :: = assign
+ elif re_asg.match(iline):
+ var_name = re_asg.match(iline).group(1)
+ var_value= re_asg.match(iline).group(2)
+## :: = = $docstrip
+ if var_name == 'docstrip': #
+ if SELF_VER < int(var_value):
+ sys.stderr.write(\
+"need docstrip %d or higher. Current docstrip's version: %d.\n"\
+ % (int(var_value), SELF_VER))
+ return
+## :: = = global kins variables
+ elif var_name in __global_kins_vars:
+ exec('global _kins_%s\n_kins_%s="""%s"""'\
+ % (var_name, var_name, var_value))
+## :: = = other kins variables
+ else:
+ if not var_name in __kins_vars:
+ __kins_vars.append(var_name)
+ exec('_kins_%s="""%s"""' % (var_name,var_value))
+ if var_name == 'source': _readsource(_kins_source)
+## :: = $local
+ elif re_local.match(iline):
+ zzz = re_local.match(iline).group(1)
+ if re_kasg.match(zzz):
+ var_name = re_kasg.match(zzz).group(1)
+ var_value = re_kasg.match(zzz).group(2)
+ exec('_gen_%s="""%s"""' % (var_name,var_value))
+## :: = $gen
+ elif re_gen.match(iline): # gen macro
+ gen_des = re_gen.match(iline).group(1)
+ if (not _gonly_) or (only_files.search(gen_des)):
+ gen_opt = re_gen.match(iline).group(2)
+ ## neu $gen co them tham so thu ba
+ ## tham so nay phai de trong ngoac: (.+)
+ kins_skip = 0
+ _gen_append = '0' # <initial value must be '0'>
+ _gen_nopre = _kins_nopre # get the global value
+ _gen_nopost = _kins_nopost # as the initialization
+ _gen_destdir = _kins_destdir# add 2003/12/10
+ _gen_debug = _kins_debug #
+ if re_gen.search(iline).group(3) != "":
+ gen_optlist = string.split(\
+ re_gen.search(iline).group(3)[1:-1],',')
+ for item in gen_optlist:
+ item = string.strip(item)
+ if item == "append": _gen_append = '1'
+ elif item == "nopost": _gen_nopost = '1'
+ elif item == "nopre" : _gen_nopre = '1'
+ else:
+ zzz = re_kasg.match(item)
+ if zzz:
+ var_name = zzz.group(1)
+ var_value= str(zzz.group(2))
+ if var_name in __no_skip_vars:
+ exec('_gen_%s="""%s"""' % (var_name,var_value))
+ else:
+ try:
+ if var_name in __kins_vars:
+ exec("tmp_value=_kins_%s" % var_name)
+ else:
+ exec("tmp_value=_gen_%s" % var_name)
+ if not var_value == tmp_value:
+ kins_skip = 1
+ break # break the FOR loop
+ ## donot mention other check
+ except NameError:
+ exec('_gen_%s="""%s"""' % (var_name,var_value))
+ if kins_skip:
+ sys.stderr.write('o')
+ else:
+ gen_des = "%s/%s" % (_gen_destdir, gen_des)
+ _gen(gen_des,gen_opt,\
+ _gen_append,\
+ _gen_nopre,_gen_nopost,\
+ _kins_source, _gen_debug)
+ else:
+ sys.stderr.write('o')
+## :: = anything else
+ else: pass
+ if __iflevel != 0:
+ sys.stderr.write("\nerror: missing $if or $enif\n")
+
+def _readsource(source):
+ ## last modify: Ky Anh, 2003/12/27
+ ## : according to changes of _xsplit
+ global __ilines,\
+ src_time
+ __ilines = []
+ src_time = os.stat(source)[stat.ST_MTIME]
+ f = open(source, 'r')
+ iline = f.readline() #
+ while iline:
+ if re_code.match(iline): # code
+ __ilines.append(iline)
+ elif re_begin.match(iline): # begin block
+ __ilines.append(iline)
+ _xsplit(re_begin.match(iline).group(1))
+ elif re_sblock.match(iline):# single block
+ __ilines.append(iline)
+ _xsplit(re_sblock.match(iline).group(1))
+ elif re_end.match(iline): # end block
+ __ilines.append(iline)
+ iline = f.readline()
+ f.close()
+
+def _gen(filename, opt,\
+ _gen_append='0',\
+ _gen_nopre='0', _gen_nopost='0',\
+ source_name='', _gen_debug='0'):
+
+ if not _gen_debug in NO: #yes, debug is ON
+ sys.stderr.write('-')
+ print "f(%s)s(%s)o(%s)a(%s)npre(%s)npos(%s)bug(%s)"\
+ % (filename, source_name, opt,\
+ _gen_append, _gen_nopre, _gen_nopost, _gen_debug)
+ _xstrip(opt, 1)
+ else:
+ des = string.split(filename, '/')[-1:][0]
+ try:
+ dest_time = os.stat(filename)[stat.ST_MTIME]
+ except os.error:
+ dest_time = 0
+
+ if _force_ or (src_time > dest_time):
+ try:
+ if _gen_append in NO:
+ g = open(filename, 'w')
+ sys.stderr.write('.')
+ else:
+ g = open(filename, 'a')
+ g.write('\n')
+ sys.stderr.write('+')
+ except IOError:
+ sys.stderr.write('X')
+ return
+
+ if _gen_nopre in NO:
+ global _kins_pre
+ ## expand |preample|
+ tmp__pre = string.replace(_kins_pre,"$date", GEN_DATE)
+ tmp__pre = string.replace(tmp__pre, "$c", '#')
+ tmp__pre = string.replace(tmp__pre, "$generator", SELF_INFOR)
+ tmp__pre = string.replace(tmp__pre, "$option", opt)
+ tmp__pre = string.replace(tmp__pre, "$dest", des)
+ tmp__pre = string.replace(tmp__pre, "$source", source_name)
+ g.write(tmp__pre)
+## if _tex_:
+## if tmp__pre[-1:] == '\n':
+## tmp__pre = tmp__pre[:-1]
+## print "\def\ktvpre{^^A"
+## print string.replace(tmp__pre, "\n", "^^J^^A\n"),
+## print "}\usepreamble\ktvpre"
+ _xstrip(opt, 0)
+ g.writelines(__output)
+ if _tex_:
+ print "\\generate{\\file{%s}{\\from{%s}{%s}}}"\
+ % (filename, source_name, opt)
+
+ if _gen_nopost in NO:
+ global _kins_post
+ tmp__pre = _kins_post
+ ## expand |posamble|. Only macro "$dest" is allowed.
+ tmp__pre = string.replace(_kins_post,"$dest", des)
+ tmp__pre = string.replace(tmp__pre, "$c", "#")
+ g.write(tmp__pre)# the tail
+
+ g.close()
+ os.utime(filename, (src_time, src_time))
+ else:
+ sys.stderr.write('|')
+
+def usage():
+ sys.stdout.write(\
+"""Usage: docstrip [options] file1 file2...
+ -e --exec code excute <code> before any job
+ (only the assignments are accepted)
+ -g --gen expr generate only files whose names
+ match the regular expression <expr>
+ -j --job job specify the kins file named <job>
+ (the extension `.kins' can be omitted)
+ -t --tex print the (TeX) INS code
+ -d --debug print debug information (donot generate any file)
+ -f --force force generatation (skip time check)
+ -h --help show this message
+ -v --version print version information and exit
+Report:
+ . generate sucessfully
+ + generate in `append' mode
+ o skip file (specified by <kins> file)
+ ? some things wrong occur
+ _ opening new source file
+ = importing a kins file
+ * file is already imported. Inogre it!
+ X cannot open file for writting
+ E failed on excuting embeded python code
+ | skip file (the source time <= the destination time)
+Within the `--debug' option:
+ - debugging
+ n normal code
+ s single block code
+""")
+
+if __name__ == '__main__':
+ try:
+ opts, args\
+ = getopt.getopt(sys.argv[1:],\
+ "vdhftg:e:j:",\
+ ["debug","tex","job=","version", "gen=","force","help","exec="])
+ except:
+ sys.stderr.write("Please try |docstrip.py --help|\n")
+ sys.exit(1)
+
+ _do_global()
+
+ for o, a in opts:
+ if o in ("-h", "--help"):
+ usage()
+ sys.exit(0)
+ elif o in ("-v", "--version"):
+ sys.stdout.write("%s\n" % SELF_INFOR)
+ sys.exit(0)
+ elif o in ("-f", "--force"):
+ _force_ = 1
+ elif o in ("-t", "--tex"):
+ _tex_ = 1
+ elif o in ("-d", "--debug"):
+ _kins_debug = '1'
+ elif o in ("-g", "--gen"):
+ _gonly_ = 1
+ only_files = re.compile(a)
+ sys.stderr.write(" genonly = %s\n" % a)
+ elif o in ("-j", "--job"):
+ if not string.lower(a[-5:]) == ".kins":
+ a = a + ".kins"
+ jobnames.append(a)
+ elif o in ("-e", "--exec"):
+ a = string.split(a, ';')
+ for code in a:
+ zzz = re_kasg.match(string.strip(code))
+ if zzz:
+ var_name = zzz.group(1)
+ var_value= zzz.group(2)
+ exec('_kins_%s="""%s"""' % (var_name,var_value))
+ if not var_name in __kins_vars:
+ __kins_vars.append(var_name)
+ sys.stderr.write(" %s = %s\n" % (var_name,var_value))
+ else:
+ sys.stderr.write(" ?code: %s\n" % code)
+
+ for item in args:
+ if not string.lower(item[-5:]) == ".kins":
+ item = item + ".kins"
+ jobnames.append(item)
+
+ if jobnames == []:
+ sys.stderr.write("Please try |docstrip.py --help|\n")
+ sys.exit(1)
+
+ if _tex_:
+ print\
+"%%%% This file was generated by `%s'\n\
+%%%% from the source(s) %s\n\
+\\input docstrip.tex" % (SELF_INFOR, jobnames)
+
+ for jobname in jobnames:
+ if os.path.isfile(jobname):
+ sys.stderr.write("\n<<%s>>\n" % jobname)
+ _dokins(jobname)
+ else:
+ sys.stderr.write("\n<<%s>>: cannot open this file\n" % jobname)
+ if _tex_:
+ print "\\endbatchfile\n\\endinput\n%% End of file."
+
+ sys.stderr.write("(ok)\n")
+
+####################
+## END OF PROGRAM ##
+####################
+
+## TO DO:
+
+## 2003/12/27:
+## $if, $fi, $else, $elif
diff --git a/support/pydocstrip/vnbase.dtx b/support/pydocstrip/vnbase.dtx
new file mode 100644
index 0000000000..080ade8f52
--- /dev/null
+++ b/support/pydocstrip/vnbase.dtx
@@ -0,0 +1,1600 @@
+% \iffalse
+%<dtx>\ProvidesFile{vnbase.dtx}[2003/11/01 v01.01 VNR.KTV.DTX.Base]
+% \fi
+%
+% \section{Basic macros}
+%
+% \begin{macrocode}
+%<*vnbase>
+% \end{macrocode}
+%
+% §Þnh nghÜa tÊt c¶ c¸c macro ®­îc dïng bëi |VNR|.
+%
+% \subsection{Generic Macros}
+%
+% \danger
+% V× |mfplain.mp| kh«ng ®­îc cËp nhËt cïng víi |plain.mf|,
+% nªn ®Ó |MetaPost| cã thÓ lµm viÖc víi |ec| fonts,
+% ta ph¶i cÇn c¸c dßng sau (chÐp tõ |plain.mf|).
+% \endanger
+%
+% \begin{macrocode}
+%<*test>
+vardef whatever = save ?; ? enddef;
+def killtext text t = enddef;
+%</test>
+% \end{macrocode}
+%
+% \begin{macrocode}
+if unknown exbase:
+ input exbase;
+fi;
+% \end{macrocode}
+%
+% \begin{macrocode}
+if unknown displaying:
+ displaying := 0;
+fi
+% \end{macrocode}
+% Trong *exbase.mf*, macro *ecchar* ®­îc ®Þnh nghÜa bëi *|let ecchar=\;|*.
+% \begin{macrocode}
+let vnchar = ecchar;
+let cmchar = ecchar;
+% \end{macrocode}
+%
+% Load |T5| |encoding| vµ c¸c macro ®Þnh nghÜa c¸c hä ch÷ c¸i, hä dÊu.
+% \begin{macrocode}
+input vncode;
+% \end{macrocode}
+%
+% \subsection{Test: Parameters}
+%
+% Parameter for |t5supp-encoding|.
+% \begin{macrocode}
+%<*t5supp>
+% get_acc_pos := 1;
+% gen_t5_supp := 1;
+% if known get_acc_pos or known gen_t5_supp:
+ mag := 100.375;
+% fi
+%</t5supp>
+% \end{macrocode}
+%
+% *(KTV,2003/11/02):*
+% ViÖc ®Æt *|defaultfont:="Times-Roman"|* sÏ sinh ra lçi
+% (kh«ng t×m thÊy font |tfm|) t­¬ng øng.
+% Xem thªm trong \href{../doc/vnr_bug_fix.dvi}{vnr_bug_fix}.
+%
+% *(KTV,2003/11/13):*
+% Ph¶i dïng *|prologues:=1|* míi cã thÓ |merge| c¸c output t¹o bëi
+% |MetaPost| b»ng |mpmergeps.py|.
+% (Ch­a kiÓm tra ®iÒu nµy víi |mergemps.py|.)
+% \begin{macrocode}
+%<*test>
+% show_labels := 1; % value passed in the `makefile'
+% makeXbox := 0; % value passed in the `makefile'
+defaultscale := 1;
+prologues := 1;
+%defaultfont := "Times-Roman";
+if known black_proof:
+ proofcolor := .9999[white, black];
+else:
+ proofcolor := .3[white, black];
+fi
+if known gensize:
+ mag := 20/gensize;
+else: mag := 2; fi
+if known no_labels:
+ def penlabels(text _list) = enddef;
+fi
+%</test>
+% \end{macrocode}
+%
+% \subsection{Test: Letters}
+%
+% Danh s¸ch c¸c ch÷ c¸i ®­îc vÏ khi trong \tstmode.
+% Muèn |test| ch÷ c¸i nµo th× chØ viÖc bá dÊu |%| ë tr­íc ch÷ ®ã.
+% Cã thÓ thùc hiÖn c¸c phÐp g¸n, vÝ dô: *|test_grave:=1|*.
+% \emph{L­u ý:} nh÷ng ch÷ c¸i ®­îc test sÏ gåm c¶ ch÷ hoa lÉn ch÷ th­êng.
+% (Xem ®Þnh nghÜa cña *grave_fam*, *acute_fam*,... ë \lref{def:accent_fam},
+% ®Þnh nghÜa cña *a_fam*, *d_fam*,... ë \lref{def:letter_fam}.)
+%
+% \begin{multicols}3
+% \begin{macrocode}
+%<*test>
+def testchars =
+%<=def:testchars>
+if known test_grave:
+ grave_fam(,)
+fi if known test_acute:
+ acute_fam(,)
+fi if known test_tilde:
+ tilde_fam(,)
+fi if known test_hook:
+ hook_fam(,)
+fi if known test_dot:
+ dot_fam(,)
+fi if known test_a:
+ a_fam(,)
+fi if known test_e:
+ e_fam(,)
+fi if known test_i:
+ i_fam(,)
+fi if known test_o:
+ o_fam(,)
+fi if known test_u:
+ u_fam(,)
+fi if known test_uhorn:
+ uhorn_fam(,)
+fi if known test_y:
+ y_fam(,)
+fi if known test_d:
+ d_fam(,)
+fi if known test_all_chars:
+ full_fam(,)
+fi
+% a.acute_,
+% a.dot_,
+% a.grave_,
+% a.hook_,
+% a.tilde_,
+% a.breve_,
+% a.breve_.acute_,
+% a.breve_.dot_,
+% a.breve_.grave_,
+% a.breve_.hook_,
+% a.breve_.tilde_,
+% a.circumflex_,
+% a.circumflex_.acute_,
+% a.circumflex_.dot_,
+% a.circumflex_.grave_,
+% a.circumflex_.hook_,
+% a.circumflex_.tilde_,
+% d.bar_,
+% e.acute_,
+% e.dot_,
+% e.grave_,
+% e.hook_,
+% e.tilde_,
+% e.circumflex_,
+% e.circumflex_.acute_,
+% e.circumflex_.dot_,
+% e.circumflex_.grave_,
+% e.circumflex_.hook_,
+% e.circumflex_.tilde_,
+% i.acute_,
+% i.dot_,
+% i.grave_,
+% i.hook_,
+% i.tilde_,
+% o.acute_,
+% o.dot_,
+% o.grave_,
+% o.hook_,
+% o.tilde_,
+% o.circumflex_,
+% o.circumflex_.acute_,
+% o.circumflex_.dot_,
+% o.circumflex_.grave_,
+% o.circumflex_.hook_,
+% o.circumflex_.tilde_,
+% o.horn_,
+% o.horn_.acute_,
+% o.horn_.dot_,
+% o.horn_.grave_,
+% o.horn_.hook_,
+% o.horn_.tilde_,
+% u.acute_,
+% u.dot_,
+% u.grave_,
+% u.hook_,
+% u.tilde_,
+% u.horn_,
+% u.horn_.acute_,
+% u.horn_.dot_,
+% u.horn_.grave_,
+% u.horn_.hook_,
+% u.horn_.tilde_,
+% y.acute_,
+% y.dot_,
+% y.grave_,
+% y.hook_,
+% y.tilde_,
+last
+enddef;
+%</test>
+% \end{macrocode}
+% \end{multicols}
+%
+% \danger
+% Ta thªm vµo danh s¸ch trªn ch÷ c¸i ¶o |last|. \emph{Môc ®Ých:}
+% Khi dïng vßng lÆp |for| ®Ó duyÖt qua danh s¸ch
+% |testchars|, ta ph¶i biÕt lóc nµo th× kÕt thóc danh s¸ch.
+% Ch÷ c¸i ¶o |last| t¹o ®iÒu kiÖn ®Ó kiÓm tra.
+% Nh­ vËy, |last| ph¶i lu«n ®­îc |test|:
+% ta kh«ng ®­îc phÐp bá ®i |last| trong danh s¸ch nãi trªn.
+% \endanger
+%
+% \begin{macrocode}
+%<test> C.l.last := C.u.last := 256;
+% \end{macrocode}
+%
+% \subsection{Test: Macros}
+%
+% \begin{macro}{used_char}
+% Macro nµy kiÓm tra xem \meta{char} víi m· |_code| cã n»m trong
+% danh s¸ch |testchars| hay kh«ng. NÕu cã, \meta{char} nµy sÏ ®­îc vÏ.
+% ChØ trong \tstmode\ míi cã sù kiÓm tra nµy, cßn trong b¶n
+% \meta{publish} cña |VNR-METAFONT| th× macro |used_char| ®­îc bá qua.
+% Xem ®Þnh nghÜa cña macro |define_vnchar| (\lref{def:define_vnchar}).
+% \begin{macrocode}
+%<*test>
+vardef used_char(expr _code) =
+%<=def:used_char>
+ boolean _is_used;
+ if not known test_all_chars:
+ _is_used := false;
+ forsuffixes $ = testchars:
+ if _code = vn_code($):
+ _is_used := true;
+ fi;
+ endfor;
+ else:
+ _is_used := true;
+ fi;
+ _is_used
+enddef;
+%</test>
+% \end{macrocode}
+% \end{macro}
+%
+% Khai b¸o 14 biÕn kiÓu |BOOLEAN|.
+% C¸c biÕn nµy ®­îc g¸n gi¸ trÞ ban ®Çu |FALSE|.
+%
+% \emph{VÝ dô:} biÕn |a_fam_used| cã gi¸ trÞ |TRUE| nÕu mét trong c¸c
+% ch÷ c¸i |a|, |¸|, |µ|, |¶|, |·|, |¹| ®­îc |test|. L­u ý r»ng,
+% c¸c ch÷ c¸i |a|, |¸|, |µ|, |¶|, |·|, |¹| ®­îc vÏ theo c¸ch \emph{t­¬ng
+% tù} nhau, nªn ta chØ cÇn \emph{dïng mét biÕn} lµ |a_fam_used|:
+% nÕu |a_fam_used| b»ng |TRUE|, th× ta sÏ |load| m· |MF| ®Ó vÏ c¸c
+% ch÷ |a|, m· nµy ®Æt trong |vnlar|.
+%
+% Xem thªm ®Þnh nghÜa cña |input_lr_fam|, |input_ur_fam| bªn d­íi.
+%
+% \begin{macrocode}
+%<*test>
+forsuffixes _u =
+ A_fam_used, D_fam_used, E_fam_used, I_fam_used,
+ O_fam_used, U_fam_used, Y_fam_used,
+ a_fam_used, d_fam_used, e_fam_used, i_fam_used,
+ o_fam_used, u_fam_used, y_fam_used:
+ boolean _u;
+ _u := false;
+endfor;
+%</test>
+% \end{macrocode}
+%
+% Gi¶ sö trong |test_char|, \meta{char} cã m· |_c| ®­îc \meta{test}.
+% Khi ®ã, ta sÏ t×m xem \meta{char} nµy n»m trong hä nµo (|A_fam|,
+% |e_fam|, v.v...). NÕu (vÝ dô) nã n»m trong hä |a_fam|, th× ta sÏ g¸n
+% biÕn |a_fam_used| gi¸ trÞ |TRUE|.
+%
+% \begin{macro}{test_fam}
+%
+% Macro |test_fam| d­íi ®©y cã nhiÖm
+% vô tr¶ lêi xem \meta{char} víi m· |_c| cã n»m trong hä |_f| hay kh«ng;
+% nÕu cã th× g¸n |_u| b»ng |TRUE|. \emph{L­u ý:} c¸c \meta{char} (tiÕng
+% ViÖt) chØ cã m· hoÆc nhá h¬n |32|, hoÆc lín h¬n |127|.
+%
+% \begin{macrocode}
+%<*test>
+def test_fam(text _f, _u, _c) =
+ n_ := 0;
+ if not _u:
+ forsuffixes $ = _f(,) 257:
+ n_ := n_ + 1;
+ if (($ < 32) or ($ > 127)) and ($ = C.u._c) or ($ = C.l._c):
+ _u := true;
+ fi
+ endfor
+ fi
+enddef;
+%</test>
+% \end{macrocode}
+% \end{macro}
+%
+% B©y giê, ta duyÖt qua tÊt c¶ c¸c hä (ch÷ hoa) ®Ó xem |_c| thuéc hä nµo.
+% Râ rµng, mçi \meta{char} chØ thuéc mét vµ chØ mét hä mµ th«i, nªn ta cã
+% thÓ c¶i thiÖn viÖc duyÖt b»ng c¸ch dïng |if...elif...if|. (Nh­ng viÖc
+% nµy kh«ng \emph{kinh tÕ}l¾m.)
+%
+% \begin{multicols}2
+% \begin{macrocode}
+%<*test>
+forsuffixes _c = testchars:
+ test_fam(A_fam)(A_fam_used)(_c);
+ test_fam(D_fam)(D_fam_used)(_c);
+ test_fam(E_fam)(E_fam_used)(_c);
+ test_fam(I_fam)(I_fam_used)(_c);
+ test_fam(O_fam)(O_fam_used)(_c);
+ test_fam(U_fam)(U_fam_used)(_c);
+ test_fam(Y_fam)(Y_fam_used)(_c);
+ test_fam(a_fam)(a_fam_used)(_c);
+ test_fam(d_fam)(d_fam_used)(_c);
+ test_fam(e_fam)(e_fam_used)(_c);
+ test_fam(i_fam)(i_fam_used)(_c);
+ test_fam(o_fam)(o_fam_used)(_c);
+ test_fam(u_fam)(u_fam_used)(_c);
+ test_fam(y_fam)(y_fam_used)(_c);
+ test_fam(U_horn_fam)(U_fam_used)(_c);
+ test_fam(u_horn_fam)(u_fam_used)(_c);
+endfor
+%</test>
+% \end{macrocode}
+% \end{multicols}
+%
+% BiÕn |inpustr| ®­îc dïng trong 4 macro s¾p tíi.
+%
+% \begin{macrocode}
+%<test>string inputstr;
+% \end{macrocode}
+%
+% \begin{macro}{input_ur_fam}
+% Xem hä ch÷ nµo ®­îc dïng th× |load| m· |MF| ®Ó vÏ hä t­¬ng øng.
+% \up ë ®©y lµ hä c¸c ch÷ hoa.
+% \begin{macrocode}
+%<*test>
+def input_ur_fam =
+ inputstr := "";
+ if A_fam_used: inputstr := inputstr & "input vnuar; "; fi
+ if D_fam_used: inputstr := inputstr & "input vnudr; "; fi
+ if E_fam_used: inputstr := inputstr & "input vnuer; "; fi
+ if I_fam_used: inputstr := inputstr & "input vnuir; "; fi
+ if O_fam_used: inputstr := inputstr & "input vnuor; "; fi
+ if U_fam_used: inputstr := inputstr & "input vnuur; "; fi
+ if Y_fam_used: inputstr := inputstr & "input vnuyr; "; fi
+ scantokens(inputstr);
+enddef;
+%</test>
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{input_lr_fam}
+% |Load| m· vÏ c¸c ch÷ th­êng.
+% \begin{macrocode}
+%<*test>
+def input_lr_fam =
+ inputstr := "";
+ if a_fam_used: inputstr := inputstr & "input vnlar; "; fi
+ if d_fam_used: inputstr := inputstr & "input vnldr; "; fi
+ if e_fam_used: inputstr := inputstr & "input vnler; "; fi
+ if i_fam_used: inputstr := inputstr & "input vnlir; "; fi
+ if o_fam_used: inputstr := inputstr & "input vnlor; "; fi
+ if u_fam_used: inputstr := inputstr & "input vnlur; "; fi
+ if y_fam_used: inputstr := inputstr & "input vnlyr; "; fi
+ scantokens(inputstr);
+enddef;
+%</test>
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{input_sc_fam}
+% |Load| m· vÏ c¸c ch÷ |small-cap|.
+% \begin{macrocode}
+%<*test>
+def input_sc_fam =
+ inputstr := "";
+ if a_fam_used: inputstr := inputstr & "input vnuar; "; fi
+ if d_fam_used: inputstr := inputstr & "input vnudr; "; fi
+ if e_fam_used: inputstr := inputstr & "input vnuer; "; fi
+ if i_fam_used: inputstr := inputstr & "input vnuir; "; fi
+ if o_fam_used: inputstr := inputstr & "input vnuor; "; fi
+ if u_fam_used: inputstr := inputstr & "input vnuur; "; fi
+ if y_fam_used: inputstr := inputstr & "input vnuyr; "; fi
+ scantokens(inputstr);
+enddef;
+%</test>
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{input_li_fam}
+% |Load| m· vÏ c¸c ch÷ nghiªng.
+% \begin{macrocode}
+%<*test>
+def input_li_fam =
+ inputstr := "";
+ if a_fam_used: inputstr := inputstr & "input vnlai; "; fi
+ if d_fam_used: inputstr := inputstr & "input vnldi; "; fi
+ if e_fam_used: inputstr := inputstr & "input vnlei; "; fi
+ if i_fam_used: inputstr := inputstr & "input vnlii; "; fi
+ if o_fam_used: inputstr := inputstr & "input vnloi; "; fi
+ if u_fam_used: inputstr := inputstr & "input vnlui; "; fi
+ if y_fam_used: inputstr := inputstr & "input vnlyi; "; fi
+ scantokens(inputstr);
+enddef;
+%</test>
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{bboxcolor}
+% \begin{macro}{bbxorule}
+% Macro |bboxrule| dïng ®Ó vÏ ®o¹n th¼ng nèi hai ®iÓm |w| vµ |z|,
+% víi mµu lµ |bboxcolor| vµ kiÓu ®­êng th¼ng lµ |linecap|.
+% \emph{L­u ý:} |linecap| lµ biÕn |internal| cña |MetaPOST|.
+%
+% \danger
+% NÕu ta muèn t¹m thêi quªn ®i gi¸ trÞ cña mét biÕn |internal|, ë ®©y lµ
+% biÕn |linecap|, th× dïng |interim| trong mét |group|. Sau |group| ®ã,
+% gi¸ trÞ cò cña biÕn |internal| sÏ ®­îc phôc håi. §èi víi biÕn |external|,
+% ta dïng hµm |save| thay v× |interim|.
+% \endanger
+% \begin{macrocode}
+%<*test>
+def bboxcolor = red enddef;
+def bboxrule(expr w,z) =
+ begingroup
+ interim linecap := squared;
+ draw w..z
+ withpen pencircle scaled (.4/bp_per_pixel)
+ withcolor bboxcolor;
+ endgroup
+enddef;
+%</test>
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{makebbox}
+% VÏ bèn c¹nh cña h×nh ch÷ nhËt bao quanh \meta{h×nh vÏ}
+% víi kÝch th­íc cña h×nh ch÷ nhËt b»ng kÝch th­íc cña \meta{h×nh vÏ}.
+% \meta{H×nh vÏ} ë ®©y lµ \meta{char} hoÆc \meta{accent}.
+% \begin{macrocode}
+%<*test>
+def makebbox(text rule) =
+ if known makeXbox:
+ for x = 0,w:
+ bboxrule((x,-d),(x,h)); endfor
+ for y = 0,h,-d:
+ bboxrule((0,y),(w,y)); endfor
+ fi
+enddef;
+%</test>
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{makebox}
+% VÏ l­íi gåm c¸c ®o¹n th¼ng ®i qua c¸c ®iÓm ®Æc biÖt.
+% \danger
+% Macro nµy dïng ®Ó kÕt thóc viÖc vÏ \meta{char},
+% kh«ng dïng ®Ó kÕt thóc viÖc vÏ \meta{accent}.\\
+% Cã thÓ xem chó thÝch vÒ macro nµy trong \mfb E/309/.
+% \endanger
+% \begin{macrocode}
+%<*test>
+def makebox(text rule) =
+% \end{macrocode}
+% VÏ b¶y (7) ®­êng th¼ng n»m ngang: mét ®­êng ®i qua gèc täa ®é;
+% mét ®­êng ®i ë ®é s©u |body_depth| -- ®­êng nµy kh«ng thÓ thÊy ®­îc
+% nÕu ta xem kÕt qu¶ do viÖc |merge| c¸c file "PS" t¹o bëi "MetaPost".
+% \begin{macrocode}
+ for y = 0, (cap_height+acc_height),
+ asc_height, body_height, x_height,
+ bar_height, desc_depth ,-body_depth:
+ rule((l,y),(r,y));
+ endfor
+% \end{macrocode}
+% \begin{macrocode}
+ for y = -3.5pt, 8.5pt, (x_height + acc_height):
+ rule((l-4pt,y),(l-2pt,y));
+ endfor
+% \end{macrocode}
+% VÏ c¸c ®­êng th¼ng ®øng.
+% \begin{macrocode}
+ for x=l,r:
+ rule((x,-body_depth),(x,body_height));
+ endfor
+% \end{macrocode}
+% VÏ c¸c ®­êng th¼ng ®øng phô.
+% \begin{macrocode}
+ for x = u*(1 + floor(l/u)) step u until r-1:
+ rule((x,-body_depth),(x,body_height));
+ endfor
+ for x = 0.5w:
+ rule((x,-body_depth - 1pt),
+ (x,-body_depth - 1.5pt));
+ rule((x, cap_height + acc_height + 1pt),
+ (x, cap_height + acc_height + 1.5pt));
+ endfor
+% \end{macrocode}
+% VÏ thªm ®­êng th¼ng ®øng nÕu |charic <> 0|.
+% \begin{macrocode}
+ if charic <> 0:
+ rule((r + charic*pt, h.o_),
+ (r + charic*pt,.5h.o_));
+ fi
+enddef;
+%</test>
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{Test: enchar}
+%
+% \begin{macro}{endchar}
+% Sau khi kÕt thóc viÖc vÏ mét \meta{char},
+% ta vÏ h×nh ch÷ nhËt bao quanh \meta{char} ®ã (b»ng |makebbox|),
+% vµ vÏ l­íi gåm c¸c ®­êng th¼ng ®Æc biÖt (b»ng |makebox|).
+%
+% \danger
+% Xem trong |METAFONTBook| vÒ |proofrule|.
+% \endanger
+% \begin{macrocode}
+%<*test>
+def endchar =
+ scantokens extra_endchar;
+% if proofing > 0:
+ if known makeXbox:
+ makebox(proofrule);
+ makebbox(proofrule);
+ fi
+ shipit;
+ endgroup
+enddef;
+%</test>
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{Writting Shifting Information}
+%
+% \begin{macro}{abs_round}
+% \begin{macrocode}
+%<*t5supp>
+def abs_round(expr _e) =
+ if _e < 0: ceiling(_e - .5)
+ else: floor(_e + .5)
+ fi
+enddef;
+%</t5supp>
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{write_shift_xy}
+% Ghi ra *log* file th«ng tin vÒ |shift|; c¸c th«ng tin nµy ®­îc sö dông
+% trong qu¸ tr×nh chuyÓn font *VNR* sang *type1* format.
+% Xem \href{../doc/vnr_type1.pdf}{vnr_type1.pdf} (appendix {\bf A})
+% ®Ó biÕt thªm vai trß cña macro nµy.
+% \begin{macrocode}
+%<*t5supp>
+def write_shift_xy(suffix _l, _a)(expr _sx, _sy) =
+ if known bp_per_pixel:
+ message "CC " &
+ if case_ = capital: "capital"
+ elseif case_ = small: "small"
+ else: "smallcap"
+ fi & " " & str _l & " " & str _a & " " &
+ decimal(abs_round(_sx*bp_per_pixel*10/designsize)) & " " &
+ decimal(abs_round(_sy*bp_per_pixel*10/designsize));
+ fi
+enddef;
+%</t5supp>
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{Miscellanea}
+%
+% BiÕn |case_| dïng lµm |switch| ®Ó x¸c ®Þnh kiÓu ch÷ hoa/th­êng/...
+% \begin{macrocode}
+numeric case_;
+small := 0;
+capital := 1;
+smallcap := 2;
+def set_lowercase =
+ case_ := small;
+ def vncase = l enddef;
+enddef;
+def set_uppercase =
+ case_ := capital;
+ def vncase = u enddef;
+enddef;
+def set_smallcap =
+ case_ := smallcap;
+ def vncase = l enddef;
+enddef;
+% \end{macrocode}
+%
+% \begin{macro}{casename}
+% Tªn ®Çy ®ñ cña ch÷ c¸i ®ang ®­îc
+% |METAFONT| vÏ (chØ khi |testing| lµ \emph{unknown}).
+% Cã thÓ thÊy c¸c tªn nµy trªn |terminal| vµ trong file |log|
+% nÕu ch¹y |mf| víi |mode := proof|.
+% \begin{macrocode}
+def casename expr _name =
+%<*!test>
+ "The " &
+ if case_ = capital: "capital"
+ elseif case_ = small: "small"
+ else: "smallcap" fi
+ & " letter " & _name
+%</!test>
+enddef;
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{ifknown}
+% This macro expands to |_b| if the suffix |_a| is \emph{unknown},
+% and to |_a| itself in the other case.
+% Macro nµy ®­îc dïng nhiÒu, khi ph¶i lùa chän c¸c biÕn t­¬ng øng
+% víi c¸c dÊu. Xem mét vÝ dô ë \lref{use:ifknown}.
+% \begin{macrocode}
+def ifknown(suffix _a)(expr _b) =
+ if known _a: _a else: _b fi
+enddef;
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{tand}
+% Hµm tÝnh |tangent| cña gãc |d| (tÝnh b»ng ®é, |d = degree|).
+% \begin{macrocode}
+def tand(expr _d) =
+ (sind(_d)/cosd(_d))
+enddef;
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{hp}
+% Lµm trßn theo chiÒu ngang (|horizontal|).
+% \begin{macrocode}
+def hp(expr _x) =
+ hround(_x*hppp)
+enddef;
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{vp}
+% Lµm trßn theo chiÒu ®øng (|vertical|).
+% \begin{macrocode}
+def vp(expr _y) =
+ vround(_y*vppp)
+enddef;
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{Macro: begin, end}
+%
+% \begin{macro}{begin_pic}
+% \begin{macrocode}
+def begin_pic(suffix _n) =
+ begingroup
+ clearxy;
+ clearit;
+ clearpen;
+ picture vn.vncase._n.pic;
+ vn.vncase._n.pic :=
+ begingroup
+enddef;
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{end_pic}
+% \begin{macrocode}
+def end_pic =
+% \end{macrocode}
+%
+% \danger
+% Ta chØ cã thÓ dïng |makebbox| ë ®©y mµ th«i!
+% \endanger
+%
+% \begin{macrocode}
+%<test> makebbox(proofrule);
+% \end{macrocode}
+%
+% \begin{macrocode}
+ currentpicture
+ endgroup;
+ endgroup
+enddef;
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macrocode}
+let end_accent = end_pic;
+let begin_letter = begin_pic;
+let end_letter = end_pic;
+% \end{macrocode}
+%
+% \begin{macro}{begin_accent}
+% \begin{macrocode}
+def begin_accent(suffix _a) =
+ begin_pic(_a);
+ set_char_dimens(vn_width(_a), vn_height(_a), 0)
+enddef;
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{Picture's Properties}
+%
+% Tõ \meta{h×nh vÏ} dïng ®Ó chØ \meta{picture} do |METAFONT|
+% t¹o ra khi vÏ ch÷ c¸i \meta{char}, hoÆc dÊu \meta{accent}.
+% Mçi \meta{h×nh vÏ} cã c¸c thuéc tÝnh sau ®©y:
+% \begin{verbatim}
+% code, pic, width, height, top, bot, depth,
+% ic, left, right, gap, join_xp, join_x
+% \end{verbatim}
+%
+% \begin{multicols}2
+% \begin{macrocode}
+def vn_code(suffix _n) =
+ C.vncase._n
+enddef;
+def vn_pic(suffix _n) =
+ vn.vncase._n.pic
+enddef;
+def vn_width(suffix _n) =
+ vn.vncase._n.w#
+enddef;
+def vn_height(suffix _n) =
+ vn.vncase._n.h#
+enddef;
+def vn_top(suffix _n) =
+ vn.vncase._n.top#
+enddef;
+def vn_depth(suffix _n) =
+ vn.vncase._n.d#
+enddef;
+def vn_bot(suffix _n) =
+ vn.vncase._n.bot#
+enddef;
+def vn_ic(suffix _n) =
+ vn.vncase._n.ic#
+enddef;
+def vn_left_adj(suffix _n) =
+ vn.vncase._n.left_adj#
+enddef;
+def vn_right_adj(suffix _n) =
+ vn.vncase._n.right_adj#
+enddef;
+def vn_gap(suffix _n) =
+ vn.vncase._n.gap#
+enddef;
+def vn_join_xp(suffix _n) =
+ vn.vncase._n.join.x
+enddef;
+def vn_join_x(suffix _n) =
+ vn.vncase._n.join.x#
+enddef;
+def vn_rt(suffix _n) =
+ vn.vncase._n.rt#
+enddef;
+def vn_dot_shift_y(suffix _n) =
+ vn.vncase._n.dot_shift.y#
+enddef;
+def vn_ac_top =
+ vn.vncase.accent_top#
+enddef;
+def vn_double_ac_top =
+ vn.vncase.double_accent_top#
+enddef;
+let vn_left_side = vn_join_x;
+def vn_right_side(suffix _a) =
+ (vn_width(_a) - vn_left_side(_a))
+enddef;
+def align_left(suffix _a, _b) =
+ 0
+enddef;
+def vn_align_join(suffix _a, _b) =
+ (vn_join_x(_a) - vn_join_x(_b))
+enddef;
+def vn_align_right(suffix _a, _b) =
+ (vn_width(_a) - vn_width(_b))
+enddef;
+% \end{macrocode}
+% \end{multicols}
+%
+% \subsection{Setting Macros}
+%
+% \begin{macro}{define_accent_dimens}
+% X¸c ®Þnh c¸c kÝch th­íc cña mét dÊu (gåm cã |width|, |height|, |top|).
+% \begin{macrocode}
+def define_accent_dimens(suffix _a)(expr _w, _h) =
+ vn_width(_a) := _w;
+ vn_height(_a) := _h;
+ vn_top(_a) := vn_height(_a) + vn_letter_height# + vn_accent_gap#;
+% \end{macrocode}
+% TÝnh l¹i gi¸ trÞ lín nhÊt cña |vn_max_ac_top#|.
+% \begin{macrocode}
+ vn_max_ac_top# := max(vn_max_ac_top#, vn_top(_a));
+enddef;
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{set_char_dimens}
+% \begin{macrocode}
+def set_char_dimens(expr _w, _h, _d) =
+ charwd := _w;
+ charht := _h;
+ chardp := _d;
+ w := hp(charwd);
+ h := vp(charht);
+ d := vp(chardp);
+ charic := 0;
+enddef;
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{set_letter_dimens}
+% \begin{macrocode}
+def set_letter_dimens(suffix _l)(expr _w, _h, _d, _ic, _lft, _rt) =
+ set_char_dimens(_w, _h, _d);
+ vn_width(_l) := _w;
+ vn_height(_l) := _h;
+ vn_depth(_l) := _d;
+ vn_ic(_l) := _ic;
+ vn_left_adj(_l) := _lft;
+ vn_right_adj(_l) := _rt;
+ adjust_fit(_lft, _rt);
+enddef;
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{set_ac_join}
+% \begin{macrocode}
+def set_ac_join(suffix _a)(expr _xp, _x, _rt) =
+ vn_join_xp(_a) := _xp;
+ vn_join_x(_a) := _x;
+ vn_rt(_a) := _rt;
+%<*test>
+ if known show_labels:
+ makelabel("j", (vn_join_xp(_a), 0));
+ makelabel("J", (hp(vn_join_x(_a)), 0));
+ makelabel("r", (hp(vn_width(_a)), vp(vn_rt(_a))));
+ makelabel("o", (0,0));
+ fi;
+%</test>
+enddef;
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{set_letter_join}
+% \begin{macrocode}
+def set_letter_join(suffix _l)(expr _xp, _x) =
+ vn_join_xp(_l) := _xp;
+ vn_join_x(_l) := _x;
+%<*test>
+ if known show_labels:
+ makelabel("X", (vn_join_xp(_l), vp(vn_height(_l))));
+ makelabel("Y", (hp(vn_join_x(_l)), vp(vn_height(_l))));
+ fi;
+%</test>
+enddef;
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{set_adj_gap}
+% \begin{macrocode}
+def set_adj_gap(suffix _l, _a) =
+%<=use:ifknown>
+ adj_gap# := ifknown(vn_gap(_l._a),
+ ifknown(vn_gap(_a), 0));
+enddef;
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{set_shift}
+% \begin{macrocode}
+def set_shift(suffix _l, _a) =
+ shift.y := vp(vn_top(_a) - vn_height(_a))
+ + ifknown(hook_shift.y._l._a,0)*u;
+ shift.x := get_join_xp(_l, _a) - vn_join_xp(_a)
+ + slant*shift.y
+ + ifknown(hook_shift.x.vncase._l._a,0)*u;
+% \end{macrocode}
+%
+% \begin{macrocode}
+ shift.y# := vn_top(_a) - vn_height(_a)
+ + ifknown(hook_shift.y._l._a#,0)*u#;
+ shift.x# := get_join_x(_l, _a) - vn_join_x(_a)
+ + slant*shift.y#
+ + ifknown(hook_shift.x.vncase._l._a#,0)*u#;
+enddef;
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{set_ic}
+% \begin{macrocode}
+def set_ic(suffix _l, _a) =
+ italcorr max(vn_ic(_l),
+ vn_width(_a) + shift.x#
+ + slant*(vn_rt(_a) + shift.y#)
+ - w# + .5u#);
+enddef;
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{set_lic}
+% \begin{macrocode}
+def set_lic(suffix _l) =
+ italcorr vn_ic(_l);
+enddef;
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{set_fit}
+% \begin{macrocode}
+def set_fit(suffix _l) =
+ adjust_fit(vn_left_adj(_l), vn_right_adj(_l));
+enddef;
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{set_dot_shift}
+% to avoid error when calling |set_dot_shift(idot)|
+% \begin{macrocode}
+C.l.idot.dot_ = C.u.idot.dot_ = 256;
+% \end{macrocode}
+%
+% \begin{macrocode}
+def set_dot_shift(suffix _l) =
+ shift.y := - vp(ifknown(vn_dot_shift_y(_l), vn_bot(dot_)));
+ shift.x := get_join_xp(_l, dot_) - vn_join_xp(dot_) + slant*shift.y;
+enddef;
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{Getting Macros}
+%
+% \begin{macro}{get_join_xp}
+% \begin{macrocode}
+def get_join_xp(suffix _l, _a) =
+ ifknown(vn_join_xp(_l._a), vn_join_xp(_l))
+enddef;
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{get_join_x}
+% \begin{macrocode}
+def get_join_x(suffix _l, _a) =
+ ifknown(vn_join_x(_l._a), vn_join_x(_l))
+enddef;
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{get_top}
+% \begin{macrocode}
+def get_top(suffix _a) =
+%<=def:get_top>
+ max(vn_top(_a) + adj_gap#,
+ if vn_top(_a) <= vn_ac_top:
+ vn_ac_top
+ else:
+ vn_double_ac_top
+ fi)
+enddef;
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{Pos Function}
+%
+% \begin{macro}{pos}
+% Xem chó thÝch trong \mfb E/310/.
+% \begin{macrocode}
+vardef pos@#(expr b,d) =
+ if known b:
+ if b <= currentbreadth:
+ (x@#r - x@#l, y@#r - y@#l) = (eps,0) rotated d;
+ else: (x@#r - x@#l, y@#r - y@#l) = (b - currentbreadth, 0) rotated d;
+ fi
+ else: (x@#r - x@#l, y@#r - y@#l) = (b - currentbreadth, 0) rotated d;
+ fi
+% \end{macrocode}
+% H×nh nh­ anh Thµnh nhÇm lÉn, khi dïng *|if known b ... else|*?
+% Kh«ng! Quan s¸t file *log* (sau khi thªm *message ...* vµo trong *else:*)
+% ta thÊy cã nhiÒu lÇn tr­êng hîp "else" x¶y ra... Xem xÐt mét sè tr­êng hîp
+% gäi *pos*, ta thÊy: cã khi *|expr b|* lµ mét biÓu thøc,
+% cã khi nã lµ mét biÕn. VÝ dô, khi vÏ *tilde* trong *vnaccent*,
+% anh Thµnh ®· dïng\\\centerline{"pos1(vn_tilde_vair, theta + 90)"}
+% Nh­ vËy lµ, hµm *pos* ®­îc ®Þnh nghÜa ë ®©y \emph{rÊt m¹nh}.
+% Mét c©u hái ®Æt ra lµ, liÖu cã cÇn ph©n biÖt hai tr­êng hîp nh­ trªn?
+% C©u tr¶ lêi lµ \emph{kh¼ng ®Þnh}.
+% \up ý cña anh Thµnh lµ: nÕu *|expr b|* ®­îc dïng lµ mét biÕn, th× cÇn
+% ph¶i khèng chÕ tr­êng hîp gi¸ trÞ cña biÕn ®ã ë d­íi ng­ìng cho phÐp!
+% \begin{macrocode}
+ x@# = .5(x@#l + x@#r);
+ y@# = .5(y@#l + y@#r)
+enddef;
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{vn_sl_shift}
+% \begin{macrocode}
+def vn_sl_shift(suffix _a) =
+% .5slant*(adj_y# + vn_height(_a))
+ 0
+enddef;
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{Drawing Letters and Accents}
+%
+% \begin{macro}{define_vnchar}
+% \label{def:define_vnchar}
+%
+% Macro nµy nèi dÊu |_c| víi ch÷ |_c|, t¹o thµnh mét ch÷ c¸i
+% tiÕng ViÖt. VÝ dô, nèi dÊu huyÒn víi ch÷ "a".
+%
+% \begin{macrocode}
+def define_vnchar(suffix _l, _a) =
+%<=def:define_vnchar>
+%<test> if used_char(vn_code(_l._a)):
+ set_adj_gap(_l, _a);
+ beginchar(vn_code(_l._a),
+ vn_width(_l),
+ get_top(_a),
+ vn_depth(_l));
+ set_shift(_l, _a);
+ set_ic(_l, _a);
+ set_fit(_l);
+ currentpicture := vn_pic(_l);
+ addto currentpicture also vn_pic(_a)
+ shifted (shift.x, shift.y + vp(adj_gap#));
+%<*t5supp>
+ write_shift_xy(_l, _a)
+ (shift.x + hp(vn_left_adj(_l)) + letter_fit,
+ shift.y + vp(adj_gap#));
+%</t5supp>
+ endchar
+%<test> fi
+enddef;
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{define_double_accent}
+% \begin{macrocode}
+def define_double_accent(suffix _a, _b)(expr _adj_x, _adj_y) =
+ shift.y# := _adj_y + vn_height(_a);
+ shift.x# := _adj_x + slant*shift.y#;
+ define_accent_dimens(_a._b, vn_width(_a), vn_height(_b) + shift.y#);
+ begin_accent(_a._b);
+ currentpicture := vn_pic(_a);
+ addto currentpicture
+ also vn_pic(_b) shifted (hp(shift.x#), vp(shift.y#));
+%<*t5supp>
+ write_shift_xy(_a, _b)(hp(shift.x#), vp(shift.y#));
+%</t5supp>
+ set_ac_join(
+ _a._b,
+ vn_join_xp(_a),
+ vn_join_x(_a),
+ if vn_width(_a) + slant*vn_rt(_a)
+ > vn_width(_b) + shift.x#
+ + slant*(vn_rt(_b) + shift.y#):
+ vn_rt(_a)
+ else:
+ vn_rt(_b) + shift.y#
+ fi);
+ end_accent;
+enddef;
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{define_vnaccent}
+%
+% VÏ \meta{accent} |_a| víi m· |_c|.
+% ChØ dïng víi |T5supp|.
+% Xem c¸ch dïng trong *vnuacc* \lref{use:define_vnaccent}.
+%
+% \begin{macrocode}
+%<*t5supp>
+def define_vnaccent(expr _c)(suffix _a) =
+%<=def:define_vnaccent>
+ beginchar(_c, vn_width(_a), vn_height(_a), 0);
+ currentpicture := vn_pic(_a);
+ endchar
+enddef;
+%</t5supp>
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{define_vnchar_dot}
+%
+% Thªm dÊu nÆng vµo mét ch÷
+%
+% \begin{macrocode}
+def define_vnchar_dot(suffix _l) =
+%<test> if used_char(vn_code(_l.dot_)):
+% \end{macrocode}
+% Ta ph©n biÖt hai tr­êng hîp: ch÷ |Þ| (th­êng)
+% vµ c¸c ch÷ kh¸c (víi dÊu nÆng).
+% \begin{macrocode}
+ if (case_ = small) and (vn_code(_l.dot_) = vn_code(i.dot_)):
+ beginchar(vn_code(i.dot_),
+ vn_width(idot),
+ vn_height(idot),
+ vn_bot(dot_));
+ set_dot_shift(idot);
+ set_lic(idot);
+ set_fit(idot);
+ currentpicture := vn_pic(idot);
+ else:
+ beginchar(vn_code(_l.dot_),
+ vn_width(_l),
+ vn_height(_l),
+ ifknown(vn_depth(_l.dot_),
+ max(vn_bot(dot_), vn_depth(_l))));
+ set_dot_shift(_l);
+ set_lic(_l);
+ set_fit(_l);
+ currentpicture := vn_pic(_l);
+ fi
+ addto currentpicture
+ also vn_pic(dot_) shifted (shift.x, shift.y);
+%<*t5supp>
+ write_shift_xy(_l, dot_)
+ (shift.x + hp(vn_left_adj(_l)) + letter_fit,
+ shift.y);
+%</t5supp>
+ endchar
+%<test> fi
+enddef;
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{define_vnchar_dot_ac}
+%
+% Thªm dÊu vµ dÊu nÆng vµo mét ch÷ cã dÊu.
+%
+% \begin{macrocode}
+def define_vnchar_dot_ac(suffix _l, _a) =
+%<test> if used_char(vn_code(_l._a.dot_)):
+ set_adj_gap(_l, _a);
+ beginchar(vn_code(_l._a.dot_),
+ vn_width(_l),
+ get_top(_a),
+ max(vn_bot(dot_), vn_depth(_l)));
+ set_shift(_l, _a);
+ set_ic(_l, _a);
+ set_fit(_l);
+ currentpicture := vn_pic(_l);
+ addto currentpicture
+ also vn_pic(_a) shifted (shift.x, shift.y + vp(adj_gap#));
+ set_dot_shift(_l);
+ addto currentpicture
+ also vn_pic(dot_) shifted (shift.x, shift.y);
+%<*t5supp>
+ write_shift_xy(_l._a, dot_)
+ (shift.x + hp(vn_left_adj(_l)) + letter_fit, shift.y);
+%</t5supp>
+ endchar
+%<test> fi
+enddef;
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{define_vnchar_horn}
+%
+% VÏ r©u cho ch÷ |u| hoÆc |o|.
+%
+% \begin{macrocode}
+def define_vnchar_horn(suffix _l) =
+%<test> if used_char(vn_code(_l.horn_)):
+ select_horn(_l);
+ set_shift_horn(_l);
+ update_horn_width(_l);
+ beginchar(vn_code(_l.horn_),
+ updated_width#,
+ vn_top(cur_horn_),
+ vn_depth(_l));
+ set_ic(_l, cur_horn_);
+ set_fit(_l);
+ select_letter_u(_l);
+ addto currentpicture
+ also vn_pic(cur_horn_) shifted (shift.x, shift.y);
+ endchar
+%<test> fi
+enddef;
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{select_horn}
+%
+% Chän r©u cña ch÷ |u| hay ch÷ |o|.
+%
+% \begin{macrocode}
+def select_horn(suffix _l) =
+ if vn_code(_l.horn_) = vn_code(u.horn_):
+ def cur_horn_ = uhorn_ enddef;
+ else: def cur_horn_ = ohorn_ enddef;
+ fi
+enddef;
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{update_horn_width}
+% \begin{macrocode}
+def update_horn_width(suffix _l) =
+ _du := (shift.x + hp(vn_width(cur_horn_)))
+ - (hp(vn_width(_l) + vn_left_adj(_l)
+ + vn_right_adj(_l)) + 2letter_fit)
+ - slant*(shift.y + vp(vn_height(cur_horn_)));
+ updated_width# :=
+ vn_width(_l)
+ if _du > .5u:
+ + .5u#*floor(_du/.5u)
+ fi
+enddef;
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{set_shift_horn}
+% \begin{macrocode}
+def set_shift_horn(suffix _l) =
+ shift.y := vp(vn_bot(cur_horn_));
+ shift.x := vn_join_xp(_l.horn_join)
+ - vn_join_xp(cur_horn_) + slant*(shift.y);
+enddef;
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{select_letter_u}
+% \begin{macrocode}
+def select_letter_u(suffix _l) =
+% test for the serif capital u letter with horn
+ if serifs and (case_ <> small) and (vn_code(_l.horn_) = vn_code(u.horn_)):
+% use the modified "U" (without right part of the right serif)
+ currentpicture := vn_pic(Uhorn)
+ else:
+ currentpicture := vn_pic(_l)
+ fi
+enddef;
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{define_vnchar_horn_ac}
+% set |cur_horn_| to |uhorn_| or |ohorn_| according to |_l|.
+% \begin{macrocode}
+def define_vnchar_horn_ac(suffix _l, _a) =
+%<test> if used_char(vn_code(_l.horn_._a)):
+ select_horn(_l);
+ set_adj_gap(_l, _a);
+ set_shift_horn(_l);
+ update_horn_width(_l);
+ beginchar(vn_code(_l.horn_._a),
+ updated_width#,
+ get_top(_a),
+ vn_depth(_l));
+ set_ic(_l, cur_horn_);
+ set_fit(_l);
+ select_letter_u(_l);
+ addto currentpicture also vn_pic(cur_horn_)
+ shifted (shift.x, shift.y);
+ set_shift(_l.horn_, _a);
+% if serifs and (vn_code(_l.horn_._a) = vn_code(o.horn_.grave_)):
+% shift.x := shift.x + max(0, u - .3stem);
+% fi
+ set_ic(_l, _a);
+ addto currentpicture also vn_pic(_a)
+ shifted (shift.x, shift.y + vp(adj_gap#));
+%<*t5supp>
+ write_shift_xy(_l.horn_, _a)
+ (shift.x + hp(vn_left_adj(_l)) + letter_fit,
+ shift.y + vp(adj_gap#));
+%</t5supp>
+ endchar
+%<test> fi
+enddef;
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{define_vnchar_horn}
+% \begin{macrocode}
+def define_vnchar_horn_dot(suffix _l) =
+%<test> if used_char(vn_code(_l.horn_.dot_)):
+ select_horn(_l); % set cur_horn_ to uhorn_ or ohorn_ according to _l
+ set_shift_horn(_l);
+ update_horn_width(_l);
+ beginchar(vn_code(_l.horn_.dot_),
+ updated_width#,
+ vn_top(cur_horn_),
+ max(vn_bot(dot_), vn_depth(_l)));
+ set_ic(_l, cur_horn_);
+ set_fit(_l);
+ select_letter_u(_l);
+ addto currentpicture also vn_pic(cur_horn_)
+ shifted (shift.x, shift.y);
+ set_dot_shift(_l);
+ addto currentpicture also vn_pic(dot_)
+ shifted (shift.x, shift.y);
+%<*t5supp>
+ write_shift_xy(_l.horn_, dot_)
+ (shift.x + hp(vn_left_adj(_l)) + letter_fit,
+ shift.y);
+%</t5supp>
+ endchar
+%<test> fi
+enddef;
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{hook_arck.r}
+% |hook_arc| is based on |super_arc| from exbase.mf
+% \begin{macrocode}
+vardef hook_arc.r(suffix $, $$)(expr _superness, _swap) =
+ pair center, corner;
+ if (y$ = y$r) or _swap:
+ center = (x$$r, y$r);
+ corner = (x$r, y$$r);
+ else:
+ center = (x$r, y$$r);
+ corner = (x$$r, y$r);
+ fi
+ z$.r{corner - z$.r}
+ ... _superness[center, corner]{z$$.r - z$.r}
+ ... {z$$.r - corner}z$$.r
+enddef;
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{hook_arc.l}
+% \begin{macrocode}
+vardef hook_arc.l(suffix $, $$)(expr _superness, _swap) =
+ pair center, corner;
+ if (y$ = y$r) or _swap:
+ center = (x$$l, y$l);
+ corner = (x$l, y$$l);
+ else:
+ center = (x$l, y$$l);
+ corner = (x$$l, y$l);
+ fi
+ z$l{corner - z$l}
+ ... _superness[center, corner]{z$$l - z$l}
+ ... {z$$l - corner}z$$l
+enddef;
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{vn_hook_bulb}
+% |vn_hook_bulb| is based on bulb from |exbase.mf|
+% \begin{macrocode}
+def vn_hook_bulb(suffix $, $$, $$$) =
+ z$$$r = z$$r;
+ path_.l := z$l{x$$r - x$r, 0} ... {0, y$$r - y$r}z$$l;
+ filldraw
+ path.l -- z$$r{0, y$r - y$$r}
+ ... {x$r - x$$r, 0}z$r -- cycle; % link
+ path_.r := z$$$l{0, y$r - y$$r} .. z$$$r{0, y$$r - y$r}; % near - circle
+ filldraw
+ subpath(0, xpart(path_.r intersectiontimes path_.l))
+ of path_.r
+ -- z$$r{0, y$$r - y$r} .. cycle; % bulb
+enddef;
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{vn_draw_horn}
+% \begin{verbatim}
+% ====4r===
+% = 1 = z1r = z4r
+% = = y2 = 1/3[y1, y3]
+% = 4 22l
+% = =
+% = =
+% ===4l====
+% ==
+% ==
+% 3===
+% \end{verbatim}
+%
+% \begin{macrocode}
+def vn_draw_horn(suffix _a)(expr _dotsize, _horn_stem, _horn_bot_theta) =
+ cur_dotsize# := _dotsize;
+ cur_stem# := _horn_stem;
+ define_blacker_pixels(cur_dotsize, cur_stem);
+% \end{macrocode}
+% \begin{macrocode}
+ if not square_dots:
+ pickup crisp.nib;
+ pos4(cur_dotsize, 90);
+ top y4r = h;
+ x4 = w - .5cur_dotsize;
+ pos1(cur_stem, 90);
+ pos2(cur_stem, 0);
+ pos3(cur_stem, _horn_bot_theta - 90);
+ z1r = z4r;
+ rt x2r = hround(x4 + .5cur_dotsize) + 2eps;
+ lft x3l = 0;
+ bot y3r = 0;
+ y2 = 1/3[y1, y3];
+ y_ := ypart( (z1{right} ... z2{down} ... z3 )
+ intersectiontimes (z4l{right} .. {left}z4r) );
+ if y_ < 0:
+ y_ := 1;
+ fi
+% \end{macrocode}
+% Víi ®o¹n m· d­íi ®©y, ta t« ®­îc mét nöa h×nh trßn vµ mét tam gi¸c cong
+% cã mét c¹nh lµ ®­êng kÝnh cña nöa h×nh trßn. Tam gi¸c nµy ®­îc chän
+% dùa trªn tham sè |y_| ë trªn.
+% {\ttfamily
+% \begin{verbatim}
+% ooooo
+% ooooooox
+% ooooooooxx
+% oooooooooxxx
+% oooooooooxxxx
+% oooooooooxxxxx
+% ooooooooxxxxxxx
+% oooooooxxxxxx
+% ooooooxxxxx
+% ooooxxx
+% \end{verbatim}
+% }
+% \begin{macrocode}
+ filldraw z4r{left}
+ .. subpath (0, y_) of (z4l{right}.. {left}z4r)
+ -- cycle;
+% \end{macrocode}
+% \danger
+% Tuy nhiªn, víi phÇn h×nh trßn ë trªn, khi ®­îc phãng to, c¸i r©u sÏ
+% bÞ khuyÕt mét m¶nh.
+%
+% §Ó kh¾c phôc lçi nµy, anh Thµnh ®· thªm vµo mét chót,
+% |--z2--cycle|, trong ®o¹n m· trªn. M¶nh khuyÕt b©y giê kh«ng cßn.
+% Tuy nhiªn, c¸c font |typewriter| khi ®ã ®Òu bÞ lçi <<|strange path|>>.
+% \emph{Lçi nµy xuÊt hiÖn trong bé |VNR| ngµy 2003/03/03
+% (\href{http://vinux.sourceforge.net/vntex}{vinux.sourceforge.net/vntex}).}
+% \endanger
+%
+% TiÕp theo, ta vÏ dÊu phÈy, thªm vµo h×nh ë trªn ®Ó t¹o r©u.
+% \begin{macrocode}
+ filldraw stroke
+ z1e{right} ... z2e{down} ... {left}z3e;
+% \end{macrocode}
+% §Ó che ®i m¶nh khuyÕt ®ång thêi tr¸nh lçi ë trªn,
+% ta cã thÓ viÕt m· riªng... ®Ó t¹o mét tam gi¸c ®ñ lín.
+% C¸c ®Ønh cña tam gi¸c nµy lµ c¸c ®iÓm \meta{ngoµi cïng} cña r©u.
+% Cho ®Õn ngµy "2003/11/30", miÕng v¸ nµy ch­a thÓ hiÖn thiÕu sãt nµo.
+% C¸c font |typewriter| ®Òu tèt, nh­ng c¸c font |csc| th× vÉn\footnote{%
+% §· kh¾c phôc lçi sau ®ã mét ngµy, còng víi viÖc viÕt l¹i |docstrip|.
+% \emph{Nguyªn nh©n:} c¸c |guard| trong file
+% *|vndriver.dtx|* lµ c¸c |nested| |guard|, vµ |docstrip.py| khi ®ã
+% kh«ng thÓ hiÓu ®iÒu nµy.}...
+% \danger
+% CÇn xem l¹i |METAFONTbook|, xem thö tam gi¸c nµy liÖu cã ®Ønh *rÊt nhän*
+% hay lµ *trßn* (nh­ khi dïng |draw|)? (\emph{Tr¶ lêi:} dïng |filldraw|
+% th× chuyÖn nµy khái ph¶i lo....)
+% \endanger
+% \begin{macrocode}
+ filldraw z1r--z2r--z4l--cycle;
+% \end{macrocode}
+% \begin{macrocode}
+%<test> penlabels(0, 1, 2, 3, 4);
+ set_ac_join(_a, x3,
+ .5cur_stem*sind(_horn_bot_theta),
+ h# - .5cur_dotsize#);
+% \end{macrocode}
+% \begin{macrocode}
+ else:
+ pickup fine.nib;
+ pos4(cur_dotsize, 90);
+ top y4r = h;
+ x4 = w - .5cur_dotsize;
+ pos4'(cur_dotsize, 0);
+ z4' = z4;
+ dot(4', 4); % squarish dot
+ horn_join := max(fine.breadth, floor cur_stem);
+ horn_bot := max(fine.breadth, floor .8cur_stem);
+ pos0(horn_join, 0);
+ pos1(horn_join, 0);
+ pos2(horn_bot, 0);
+ y0 = y4;
+ y1 = y4l;
+ x0r = x1r = x4'r;
+ lft x2l = 0;
+ bot y2r = 0;
+ z2' = whatever[z1, z2];
+ numeric _vn_bot_width;
+ pos2'(_vn_bot_width, -90 + _horn_bot_theta);
+ z2l = z2'l;
+ filldraw stroke z0e -- z1e .. z2'e; % tail
+%<test> penlabels(0, 1, 2', 3, 4);
+ set_ac_join(_a, x2', 0, h#);
+ fi
+ vn_bot(_a) := vn_top(_a) - vn_height(_a);
+enddef;
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{set_horn_join}
+% \begin{macrocode}
+def set_horn_join(suffix _l)(expr _pl, _pr) =
+ select_horn(_l); % set cur_horn_ to uhorn_ or ohorn_ according to _l
+ path bot_line;
+ pair L, R;
+ bot_line := (.5w, vp(vn_bot(cur_horn_))) -- (w, vp(vn_bot(cur_horn_)));
+ L := point xpart(bot_line intersectiontimes _pl) of bot_line;
+ R := point xpart(bot_line intersectiontimes _pr) of bot_line;
+ set_ac_join(_l.horn_join, xpart .5[L, R], 0, 0);
+enddef;
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{Oct031 Character}
+%
+% \begin{macro}{lig_CGQ_table}
+% \begin{macrocode}
+def lig_CGQ_table(expr k) =
+ "C" kern k, "G" kern k, "Q" kern k
+enddef;
+% \end{macrocode}
+%
+% \begin{macrocode}
+def end_ligtable = 0 kern 0 enddef;
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{input_lig}
+% define input_lig to generate only char oct"031" from excspl.mf
+% \begin{macrocode}
+def input_lig suffix @# =
+ let save_endchar = endchar;
+ let endchar = lig_endchar;
+ scantokens("input " & str @#);
+ relax;
+ let endchar = save_endchar;
+enddef;
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{lig_endchar}
+% \begin{macrocode}
+def lig_endchar =
+ if charcode = oct"031":
+ save_endchar
+ else:
+ endgroup
+ fi
+enddef;
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{Macro: generate}
+%
+% \begin{macro}{generate}
+% File |vnr10.mf| sÏ |input| c¸c file |vnbase.mf| vµ |ecrm.mf|.
+% §Õn l­ît m×nh, |ecrm| sÏ |input| driver lµ |exroman| b»ng c¸ch gäi
+% *|generate exroman|* (®èi víi |ec|, |generate| chÝnh lµ |input|).
+% {\tiny
+% \begin{verbatim}
+% 0: 0 *
+% 1: 1 +- vnr10.mf
+% 2: 2 | +- vnbase.mf
+% 3: 3 | | +- exbase.mf
+% 4: 3 | | +- vncode.mf
+% 5: 2 | +- ecrm.mf
+% 6: 3 | | +- null.mf
+% 7: 3 | | +- vnroman.mf
+%
+% (See |doc/vnr10_tree_*.txt| for full detail)
+% \end{verbatim}
+% }
+% §Ó thay thÕ |exroman| b»ng |driver| cña |VNR|, ta sÏ ®Þnh nghÜa l¹i
+% |generate|, nhê vµo ®Æc ®iÓm: c¸c |driver| cña |ec| ®Òu b¾t ®Çu b»ng
+% hai ký tù |ec|, vµ c¸c |driver| cña |VNR| (bao gåm \emph{vnroman},
+% \emph{vncsc}, \emph{vntextit}) ®­îc b¾t ®Çu bëi |vn|.
+%
+% \danger
+% Kh«ng thÓ hiÓu t¹i sao ph¶i dïng |scantokens("input null")|.
+% NÕu kh«ng cã dßng nµy, th× tÊt c¶ c¸c file ®Òu ®­îc |input| mét
+% c¸ch \emph{b×nh th­êng}, nh­ng kh«ng cã ch÷ nµo ®­îc vÏ c¶.
+%
+% T¹i sao anh Thµnh l¹i cã thÓ nghÜ ra chuyÖn thªm dßng nµy vµo?
+% \emph{Qu¸ siªu!}
+% \endanger
+% \begin{macrocode}
+vardef generate @# =
+ scantokens("input null");
+ scantokens("input vn" & substring(2, length(str @#)) of str @#);
+enddef;
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macrocode}
+%</vnbase>
+% \end{macrocode}
+% \endinput
diff --git a/support/pydocstrip/vndriver.dtx b/support/pydocstrip/vndriver.dtx
new file mode 100644
index 0000000000..01f24a8af0
--- /dev/null
+++ b/support/pydocstrip/vndriver.dtx
@@ -0,0 +1,390 @@
+% \iffalse
+%<dtx>\ProvidesFile{vndriver.dtx}[2003/11/01 v01.01 VNR.KTV.DTX.driver]
+% \fi
+%
+% \section{Driver}
+%
+% \subsection{Common Part}
+%
+% \begin{macrocode}
+%<*test|rm|it|csc>
+% \end{macrocode}
+%
+% |version_check| was introduced in |dc1.3|.
+% \begin{macrocode}
+version_check(1,0);
+% \end{macrocode}
+%
+% Accessories for polish special letters. Pseudoparameters.
+%
+% \begin{macrocode}
+input exaccess;
+input expseudo;
+% \end{macrocode}
+% \begin{macrocode}
+mode_setup;
+font_setup;
+pseudo_setup;
+% \end{macrocode}
+%
+% \begin{macrocode}
+%</test|rm|it|csc>
+% \end{macrocode}
+%
+% \subsection{Test Mode}
+%
+% \begin{macrocode}
+%<test&(rm|it)> set_lowercase;
+%<test&(rm|it)> input vnaccent;
+%<test&rm> input_lr_fam;
+%<test&it> input_li_fam;
+% \end{macrocode}
+% \begin{macrocode}
+%<*test>
+set_uppercase;
+input vnaccent;
+input_ur_fam;
+%</test>
+% \end{macrocode}
+%
+%
+% \subsection{Only for T5supp}
+%
+% \subsubsection{Common Part}
+%
+% \begin{macrocode}
+%<*t5supp>
+input exbraces;
+input expunct;
+%<!csc> input exaccent;
+input exsign;
+%</t5supp>
+% \end{macrocode}
+%
+% \subsubsection{Roman}
+%
+% \begin{macrocode}
+%<*!test&rm&t5supp>
+set_lowercase;
+input vnaccent;
+input vndothook;
+input vnminus;
+input vnlacc;
+input vnclr;
+set_uppercase;
+input vnaccent;
+input vnuacc;
+input vncur;
+%</!test&rm&t5supp>
+% \end{macrocode}
+%
+% \subsubsection{Italic}
+%
+% \begin{macrocode}
+%<*!test&it&t5supp>
+set_lowercase;
+input vnaccent;
+input vndothook;
+input vnminus;
+input vnlacc;
+input vncli;
+set_uppercase;
+input vnaccent;
+input vnuacc;
+input vncur;
+%</!test&it&t5supp>
+% \end{macrocode}
+%
+% \subsubsection{CSC}
+%
+% \begin{macrocode}
+%<*!test&csc&t5supp>
+set_uppercase;
+input vnaccent;
+input vnuacc;
+input vncur;
+%</!test&csc&t5supp>
+% \end{macrocode}
+%
+% If the variable |gen_t5supp_supp| is already known,
+% the |next| equals |endinput| and the driver stops here;
+% otherwise, the |next| is |relax| and nothing happens.
+%
+% \begin{macrocode}
+%<*!test&!t5supp&csc>
+input exrulett;
+input exbraces;
+input expunct;
+input exsign;
+input exromp;
+input exrdigit;
+set_uppercase;
+input vnaccent;
+input vncur;
+%</!test&!t5supp&csc>
+% \end{macrocode}
+%
+% \subsection{Something from EC font}
+%
+% Letters from |EC| font.
+% \begin{macrocode}
+%<*!test&!t5supp&(rm|it)>
+input exbraces;
+input expunct;
+input exaccent;
+input exsign;
+input exrlig;
+input exromp;
+input exrulett;
+input exrllett;
+input exrdigit;
+%</!test&!t5supp&(rm|it)>
+% \end{macrocode}
+%
+% \subsection{Lowercase Letters}
+%
+% \begin{macrocode}
+%<*!test&!t5supp&(rm|it)>
+set_lowercase;
+input vnaccent;
+%</!test&!t5supp&(rm|it)>
+% \end{macrocode}
+%
+% \subsubsection{Roman fonts}
+%
+% \begin{macrocode}
+%<*!test&!t5supp&rm>
+input vnclr;
+input vndothook;
+input vnminus;
+%</!test&!t5supp&rm>
+% \end{macrocode}
+%
+% \subsubsection{Italic fonts}
+%
+% \begin{macrocode}
+%<*!test&!t5supp&it>
+input vncli;
+input vndothook;
+input vnminus;
+%</!test&!t5supp&it>
+% \end{macrocode}
+%
+% \subsection{Uppercase Letters}
+%
+% \begin{macrocode}
+%<*!test&!t5supp&(rm|it)>
+set_uppercase;
+input vnaccent;
+input vncur;
+%</!test&!t5supp&(rm|it)>
+% \end{macrocode}
+%
+% \subsection{Only for CSC}
+%
+% \begin{macrocode}
+%<*csc>
+% \end{macrocode}
+%
+% \begin{macrocode}
+boolean is_small_cap;
+is_small_cap:=true;
+% \end{macrocode}
+%%% fine higher
+% the `higher' values are used while putting accents and attaching ogoneks
+% \begin{macrocode}
+forsuffixes $ =
+ u,o, letter_fit,
+ x_height, bar_height,
+ body_height,stem:
+ higher.$.#:=$.#; higher.$:=$;
+endfor
+% \end{macrocode}
+%%% fine lower
+% \begin{macrocode}
+begingroup
+% \end{macrocode}
+% \begin{macrocode}
+ forsuffixes $ =
+ u, width_adj, cap_serif_fit, letter_fit,
+ body_height, cap_height, x_height, bar_height, comma_depth,
+ flare, dot_size, cap_hair, stem, cap_stem, cap_curve, cap_ess,
+ cap_jut, beak_jut, beak, slab, cap_bar, cap_band, cap_notch_cut,
+ o, apex_o:
+ save $; $.#:=lower.$.#; endfor
+ fudge:=lower.fudge;
+% \end{macrocode}
+% optional part:
+% \begin{macrocode}
+ forsuffixes $ =
+ depth_corr, left_corr, top_breadth_corr,
+ tip_breadth_corr, tip_xcorr, tip_ycorr, pre_angle,
+ post_angle, pre_limit, post_limit, pre_lightness,
+ post_lightness, pre_deflexion, post_deflexion, cap_flat,
+ ogonek_pen#:
+ if known lower.$: $:=lower.$; fi
+ endfor
+% \end{macrocode}
+% \begin{macrocode}
+ input expseudo;
+% \end{macrocode}
+% \begin{macrocode}
+ font_setup;
+ pseudo_setup;
+% \end{macrocode}
+% \begin{macrocode}
+%<*!test&!t5supp>
+ input_lig excspl;
+%</!test&!t5supp>
+% \end{macrocode}
+% \begin{macrocode}
+%<*test>
+ set_smallcap;
+ input vnaccent;
+ input_sc_fam;
+endgroup
+%</test>
+% \end{macrocode}
+%
+% \begin{macrocode}
+%<*!test&t5supp>
+ set_smallcap;
+ input vnaccent;
+ input vnlacc;
+ input vncur;
+ input txpseudo;
+ font_setup;
+ pseudo_setup;
+ input txaccent;
+ input vndothook;
+ input vnminus;
+% \end{macrocode}
+%
+% \begin{macrocode}
+endgroup
+%</!test&t5supp>
+% \end{macrocode}
+%
+% \begin{macrocode}
+%<*!test&!t5supp>
+ extra_endchar := extra_endchar & "charcode:=charcode+code_offset";
+ code_offset := ASCII"a" - ASCII"A";
+ input exrulett; % upper case (majuscules)
+ suppress_i_dot := true;
+ code_offset := 0;
+% \end{macrocode}
+% \begin{macrocode}
+ set_smallcap;
+ input vnaccent;
+ input vncur;
+% \end{macrocode}
+% \begin{macrocode}
+ input txpseudo;
+ font_setup;
+ pseudo_setup;
+ input txaccent;
+ input vndothook;
+ input vnminus;
+% \end{macrocode}
+%
+% \begin{macrocode}
+endgroup;
+% \end{macrocode}
+%
+% \begin{macrocode}
+%</!test&!t5supp>
+% \end{macrocode}
+% \begin{macrocode}
+%</csc>
+% \end{macrocode}
+%
+% \subsection{Font Parameters}
+%
+% \subsubsection{Common Part}
+%
+% \begin{macrocode}
+%<*!test&!t5supp&(rm|it|csc)>
+font_coding_scheme := "Vietnamese TeX Font Encoding";
+boundarychar := oct"027";
+font_slant slant;
+font_x_height x_height#;
+font_cap_height cap_height#;
+font_asc_height asc_height#;
+%</!test&!t5supp&(rm|it|csc)>
+% \end{macrocode}
+%
+% \begin{macrocode}
+%<*!test&!t5supp&(rm|it|csc)>
+font_acc_cap_height (cap_height#+acc_height#);
+font_desc_depth desc_depth#;
+font_max_height (max(asc_height#,body_height#, cap_height#+acc_height#));
+font_max_depth (max(desc_depth#,paren_depth#,the_ogonek_depth#));
+font_baselineskip max(1.2*designsize,body_height#+paren_depth#);
+% font_digit_width % set inside the digits file
+% font_cap_stem % set after the programme of the capital I
+%</!test&!t5supp&(rm|it|csc)>
+% \end{macrocode}
+%
+% \subsubsection{Roman}
+%
+% \begin{macrocode}
+%<*!test&!t5supp&rm>
+if monospace:
+ font_normal_space 9u#; % no stretching or shrinking
+ font_quad 18u#;
+ font_extra_space 9u#;
+ input vnmligtb; % ligature := monospaced fonts
+else:
+ font_normal_space 6u# + 2letter_fit#;
+ font_normal_stretch 3u#;
+ font_normal_shrink 2u#;
+ font_quad 18u# + 4letter_fit#;
+ font_extra_space 2u#;
+ input vnrligtb; % ligature := not monospaced fonts
+fi
+%</!test&!t5supp&rm>
+% \end{macrocode}
+%
+% \subsubsection{Italic}
+%
+% \begin{macrocode}
+%<*!test&!t5supp&it>
+if monospace:
+ font_normal_space 9u#; % no stretching or shrinking
+ font_quad 18u#;
+ font_extra_space 9u#;
+ letter_fit# := letter_fit
+ := 0;
+ input vnmligtb; % ligature := monospaced
+else:
+ font_normal_space 6u#+2letter_fit#;
+ font_normal_stretch 3u#;
+ font_normal_shrink 2u#;
+ font_quad 18u#+4letter_fit#;
+ font_extra_space 2u#;
+ input vniligtb; % ligature := proportionally spaced
+fi
+%</!test&!t5supp&it>
+% \end{macrocode}
+%
+% \subsubsection{CSC}
+%
+% \begin{macrocode}
+%<*!test&csc&!t5supp>
+if monospace:
+ font_normal_space 9u#; % no stretching or shrinking
+ font_quad 18u#;
+ font_extra_space 9u#;
+ input vnmligtb; % do the monospace ligature programs
+else:
+ font_normal_space 6u# + 2letter_fit#;
+ font_normal_stretch 3u#;
+ font_normal_shrink 2u#;
+ font_quad 18u# + 4letter_fit#;
+ font_extra_space 2u#;
+ input vncligtb; % do the ligature programs, not for monospaced fonts
+fi
+%</!test&csc&!t5supp>
+% \end{macrocode}
+%
+% \endinput
diff --git a/support/pydocstrip/vnparam.dtx b/support/pydocstrip/vnparam.dtx
new file mode 100644
index 0000000000..8c0c93fc9e
--- /dev/null
+++ b/support/pydocstrip/vnparam.dtx
@@ -0,0 +1,105 @@
+% \iffalse
+%<dtx>\ProvidesFile{vnparam.dtx}[2003/11/01 v02.02 VNR.KTV.DTX.Parameter]
+% \fi
+%
+% \section{Parameter Files}
+%
+% Tr­íc ngµy |2003/11/30|, c¸c |parameter| |file| ®­îc thÓ hiÖn rÊt
+% r¾c rèi, vµ file |vnparam.dtx| dµi lª thª. B»ng c¸ch sö dông <<|kins|>>
+% file vµ <<|docstrip|>> ®Ó t¹o file |MF| tõ file |DTX|, mäi viÖc cã
+% vÎ ®¬n gi¶n h¬n nhiÒu. Bï l¹i, ph¶i khai b¸o c¸c |postamble| trong
+% <<|kins|>> file.
+%
+% \subsection{Generation Sizes}
+%
+% \begin{macrocode}
+gensize:=
+% \end{macrocode}
+%
+% \begin{multicols}4
+% \begin{macrocode}
+%<sz1|sz0100>1
+%<sz2|sz0200>2
+%<sz3|sz0300>3
+%<sz4|sz0400>4
+%<sz5|sz0500>5
+%<sz6|sz0600>6
+%<sz7|sz0700>7
+%<sz8|sz0800>8
+%<sz9|sz0900>9
+%<sz10|sz1000>10
+%<sz1095>10.95
+%<sz11|sz1100>11
+%<sz12|sz1200>12
+%<sz13|sz1300>13
+%<sz14|sz1400>14
+%<sz1440>14.40
+%<sz15|sz1500>15
+%<sz16|sz1600>16
+%<sz17|sz1700>17
+%<sz1728>17.28
+%<sz18|sz1800>18
+%<sz19|sz1900>19
+%<sz20|sz2000>20
+%<sz2074>20.74
+%<sz21|sz2100>21
+%<sz22|sz2200>22
+%<sz23|sz2300>23
+%<sz24|sz2400>24
+%<sz2488>24.88
+%<sz25|sz2500>25
+%<sz26|sz2600>26
+%<sz27|sz2700>27
+%<sz28|sz2800>28
+%<sz29|sz2900>29
+%<sz2986>29.86
+%<sz30|sz3000>30
+%<sz31|sz3100>31
+%<sz32|sz3200>32
+%<sz33|sz3300>33
+%<sz34|sz3400>34
+%<sz35|sz3500>35
+%<sz3583>35.83
+%<sz36|sz3600>36
+%<sz37|sz3700>37
+%<sz38|sz3800>38
+%<sz39|sz3900>39
+% \end{macrocode}
+% Chóng ta muèn xem ®iÒu kú diÖu...
+% \begin{macrocode}
+%<sz50|sz5000>50
+%<sz60|sz6000>60
+%<sz70|sz7000>70
+%<sz80|sz8000>80
+%<sz90|sz9000>90
+%<sz100|sz10000>100
+% \end{macrocode}
+% \end{multicols}
+%
+% \subsection{Common Hooks}
+%
+% \begin{macrocode}
+;input vnhook;
+hook_acc_wh(u.acute_,1.2,1.2);
+% \end{macrocode}
+%
+% \subsection{Private Hooks}
+%
+% \begin{macrocode}
+%<csc> hook_acc_wh(l.acute_,1.3,1.3);
+%<ff> hook_acc_wh(l.acute_,1.2,.6);
+%<ff> hook_acc_wh(u.acute_,1.2,.6);
+% \end{macrocode}
+%
+% \begin{macrocode}
+input vnbase;
+% \end{macrocode}
+%
+% \danger
+% ViÖc "load" c¸c "driver" cña font "ec" kh«ng xuÊt hiÖn ë ®©y...
+% bëi v× <<"docstrip">> sÏ thªm c¸c m· thÝch hîp
+% khi t¹o file "mf" tõ file "dtx".
+% Xem (ch¼ng h¹n) file \href{vnr_ec.kins}{vnr_ec.kins} ®Ó biÕt t¹i sao.
+% \endanger
+%
+% \endinput
diff --git a/support/pydocstrip/vnr.kins b/support/pydocstrip/vnr.kins
new file mode 100644
index 0000000000..f3f248ac32
--- /dev/null
+++ b/support/pydocstrip/vnr.kins
@@ -0,0 +1,80 @@
+## VNR-METAFONT program
+## Line start with a sharp (#) is the comment line
+
+$docstrip=1793
+
+## require docstrip version 1793 or higher
+## TRY: `docstrip --version`
+
+## default local variables
+
+## If these variables arenot specified from the command line
+## they accept the default value given.
+
+$local(t5supp=0)
+$local(test=1)
+$local(nopre=1)
+$local(cm=1)
+$local(ec=0)
+$local(param=1)
+
+## The following code arenot valuable
+$local(destdir=tempdir)
+
+## default destination
+$destdir=tempdir
+
+$if(t5supp=1)
+ $test=0
+$enif
+
+$import(vnr_pp)
+## import file vnr_pp.kins
+
+$from(vnbase.dtx)
+## the source file is vnbase.dtx
+
+ $gen(vnbase.mf)(vnbase,test)(test=1)
+ $gen(vnbase.mf)(vnbase)(test=0,t5supp=0)
+ $gen(vnbase.mf)(vnbase,t5supp)(test=0,t5supp=1)
+
+$from(vndriver.dtx)
+## the source file now is vndriver.dtx
+
+ $if(test=1)
+ $gen(vncsc.mf)(csc,test)
+ $gen(vntextit.mf)(it,test)
+ $gen(vnroman.mf)(rm,test)
+ $else
+ $gen(vncsc.mf)(csc)
+ $gen(vnroman.mf)(rm)
+ $gen(vntextit.mf)(it)
+ $enif
+
+ $if(t5supp=1)
+ $if(test=0)
+ $gen(vncsc.mf)(csc,t5supp)
+ $gen(vnroman.mf)(rm,t5supp)
+ $gen(vntextit.mf)(it,t5supp)
+ $enif
+ $enif
+
+########################################################################
+
+$if(param=1)
+ $pre
+ %% This file is a part of VNR-METAFONT program.
+ $enpre
+
+ $if(ec=1)
+ $import(vnr_ec)
+ $enif
+
+ $if(cm=1)
+ $import(vnr_cm)
+ $enif
+$enif
+
+$eof=1
+
+########################################################################
diff --git a/support/pydocstrip/vnr_cm.kins b/support/pydocstrip/vnr_cm.kins
new file mode 100644
index 0000000000..b13a0e586b
--- /dev/null
+++ b/support/pydocstrip/vnr_cm.kins
@@ -0,0 +1,19 @@
+## VNR-METAFONT program
+
+## Parameter files -- names base on CMR font
+
+$docstrip=1792
+
+$if(cm=1)
+ $nopost=0
+ $from(vnparam.dtx)
+
+ $post=input ecbi;bye.\n
+ $gen(vnbxti7.mf)(bxti,sz7)
+ $gen(vnbxti8.mf)(bxti,sz8)
+
+ $post=input ecbx;bye.\n
+ $gen(vnbx5.mf)(bx,sz5)
+$enif
+
+$eof=1
diff --git a/support/pydocstrip/vnr_ec.kins b/support/pydocstrip/vnr_ec.kins
new file mode 100644
index 0000000000..ed6800a06f
--- /dev/null
+++ b/support/pydocstrip/vnr_ec.kins
@@ -0,0 +1,17 @@
+## VNR-METAFONT program
+
+## Parameter files -- names base on EC font
+
+$docstrip=1792
+
+$if(ec=1)
+ $nopost=0
+ $from(vnparam.dtx)
+
+ $post=input ecbi;bye.\n
+ $gen(vnbi0500.mf)(sz0500)
+ $gen(vnbi0600.mf)(sz0600)
+ $post=input
+$enif
+
+$eof=1
diff --git a/support/pydocstrip/vnr_pp.kins b/support/pydocstrip/vnr_pp.kins
new file mode 100644
index 0000000000..bb98a49e68
--- /dev/null
+++ b/support/pydocstrip/vnr_pp.kins
@@ -0,0 +1,40 @@
+## VNR-METAFONT program
+
+## Default Preamble, Postamble
+
+$if(nopre=0)
+ $pre
+ %%
+ %% This is file `$dest' which was generated from
+ %% the source `$source'
+ %% with option `$option'.
+ %%
+ %% The generator was `$generator'
+ %% and the generation date was `$date'.
+ %%
+ %% This is a test preamble. In the preabmle
+ %% you have five expandanable macros:
+ %%
+ %% ${c} : the sharp ($c)
+ %% ${dest} : the destination
+ %% ${source} : the source file
+ %% ${option} : list of options used
+ %% ${generator} : print information about the generator
+ %% ${date} : print the generation date
+ %%
+ %% Please see the usage in the file `vnr_pp.kins'.
+ $c$c
+ $c$c This line will start with two sharp
+ $c$c
+ %%
+ $enpre
+$enif
+
+$if(nopost=0)
+ $post
+ endinput;
+ %% End of file `$dest'.
+ $enpost
+$enif
+
+$eof=1