summaryrefslogtreecommitdiff
path: root/fonts/utilities/otftofd
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 /fonts/utilities/otftofd
Initial commit
Diffstat (limited to 'fonts/utilities/otftofd')
-rw-r--r--fonts/utilities/otftofd/COPYING340
-rw-r--r--fonts/utilities/otftofd/README94
-rw-r--r--fonts/utilities/otftofd/otftofd1037
3 files changed, 1471 insertions, 0 deletions
diff --git a/fonts/utilities/otftofd/COPYING b/fonts/utilities/otftofd/COPYING
new file mode 100644
index 0000000000..b6f92f3dbf
--- /dev/null
+++ b/fonts/utilities/otftofd/COPYING
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/fonts/utilities/otftofd/README b/fonts/utilities/otftofd/README
new file mode 100644
index 0000000000..4a1f8b1f20
--- /dev/null
+++ b/fonts/utilities/otftofd/README
@@ -0,0 +1,94 @@
+Overview
+--------
+
+otftofd is a script I wrote to help the task of generating a NFSS font
+description file and a map file from a large collection of OpenType
+fonts. In particular, when considering Adobe Pro Optical fonts, there is
+almost a combinatorial nightmare when attempting to create these files
+by hand.
+
+This software is still probably alpha quality and mostly designed
+specifically for Adobe font conventions. It currently has experimental
+support for generating swashed versions of a font and fonts consisting
+of ornaments. There is some preliminary support for selecting encodings,
+but it is far from complete. The tool has been mostly tested with the
+T1 Cork encoding. For more information about using the tool, invoke it
+with the --help option.
+
+otftofd is written in CaSH (Caml Shell) and additionally requires Eddie
+Kohler's excellent LCDF Typetools.
+
+ofttofd was originally called "adobe-font-tool", but at the suggestion
+of CTAN it was renamed to hopefully be more descriptive.
+
+otftofd is licensed under the FSF General Public License. Do not hesitate
+to send me bug reports or fixes, other improvements, or suggestions.
+Contact via e-mail at washburn@acm.org.
+
+There is a public, read-only, Subversion repository for otftofd at
+https://svn.cis.upenn.edu/svnroot/otftofd/.
+
+Installation
+------------
+
+otftofd is a script so installation only requires setting the executable
+bit ("chmod a+x otftofd") and placing it in your PATH.
+
+However, otftofd is written in the Objective Caml language with
+the CaSH library. Therefore you will need to install them before
+otftofd can be used. The latest version of OCaml can be obtained
+from http://caml.inria.fr, and the latest version of CaSH from
+http://pauillac.inria.fr/cash/.
+
+Additionally, otftofd makes use of the programs otfinfo and otftotfm.
+Therefore you will need have them installed as well. They are part of
+the LCDF Typetools package. The latest version can be obtained from
+http://www.lcdf.org/type/.
+
+Usage
+-----
+
+At its simplest, otftofd is just used as
+
+ otftofd <collection of OpenType fonts>
+
+For example, if I have a directory minion, containing a set of OpenType
+fonts for the Minion Pro font. These files will have names like
+MinionPro*.otf. Inside the minion directory I would run
+
+ otftofd *.otf
+
+Which will generate a rather large number of support files. However,
+in general you won't need to concern yourself with them. At this
+point you just need to make sure that the directory "minion" is in the
+kpathsea search path for TEXINPUTS, TEXFONTS, T1FONTS, and ENCFONTS.
+The simplest way to do this is to set the environment variables, but
+you could also edit your global TeX configuration.
+
+At this point, you just need to add the following to your LaTeX document
+(assuming you are using pdfTeX/LaTeX)
+
+ \pdfmapfile {+MinionPro.map}
+ \renewcommand{\encodingdefault}{T1}
+
+And now the MinionPro font is available. You could make it the default
+"Roman" font by adding
+
+ \renewcommand{\rmdefault}{MinionPro}
+
+or just in the current scope by
+
+ \fontencoding{T1}\fontfamily{MinionPro}\selectfont
+
+
+
+By default otftofd uses the "T1" or "Cork" font encoding, but it is
+also possible to tell otftofd to use another encoding. Returning to
+our Minion Pro example, we could have done
+
+ otftofd --enc=LY1 *.otf
+
+or if we want to use an encoding that otftofd doesn't know about, we
+could have done
+
+ otftodf --enc=LY42 --encFile=myencoding.enc *.otf
diff --git a/fonts/utilities/otftofd/otftofd b/fonts/utilities/otftofd/otftofd
new file mode 100644
index 0000000000..15a30225d6
--- /dev/null
+++ b/fonts/utilities/otftofd/otftofd
@@ -0,0 +1,1037 @@
+#!/usr/bin/env cash
+(*
+# vim:ft=ocaml
+*)
+(*
+adobe-font-tool $Id: otftofd 7 2005-09-10 21:25:47Z geoffw $
+Copyright Geoffrey Alan Washburn, 2005.
+
+You can redistribute and/or modify this software under the terms of
+the GNU General Public License as published by the Free Software
+Foundation; either version 2, or (at your option) any later version.
+
+This software is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You may obtain the GNU General Public License by writing to the Free
+Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+*)
+
+#load "str.cma";;
+open Cash;;
+open Str;;
+open List;;
+
+(******************************************************************************)
+
+(* Define this here just in case, but we'll overwrite it later *)
+let program_name : string ref = ref "otftofd"
+
+(******************************************************************************)
+
+(* Small general helper functions *)
+
+(* Print an error message and exit with an error code *)
+let error (msg : string) : 'a =
+ begin
+ print_string ((!program_name) ^ " (error) : " ^ msg ^ "\n");
+ exit 1
+ end
+
+(* Print an warning message *)
+let warning (msg : string) : unit =
+ print_string ((!program_name) ^ " (warning): " ^ msg ^ "\n")
+
+
+(******************************************************************************)
+
+(* Define these in case we need to change them later/dynamically *)
+
+let dirsep = "/"
+let pathsep = ":"
+
+(******************************************************************************)
+
+(* Check whether a programs exists in a given directory *)
+let prog_exists_dir (prog : string) (dir : string) =
+ if (is_file_directory_fn dir) then
+ is_file_executable_fn (dir ^ dirsep ^ prog)
+ else
+ (error ("Tried to check the existence of program " ^ prog ^ " in non-directory " ^ dir))
+
+(* basename *)
+let basename (fn : string) =
+ let parts = Str.split (regexp dirsep) fn in
+ let rec last (l : string list) : string =
+ (match l with
+ | [] -> (error "Argument to basename doesn't have a basecase?!")
+ | [base] -> base
+ | h::t -> last t) in
+ last (parts)
+
+(* Check whether a program exists in the users path *)
+let prog_exists_path (prog : string) : bool =
+ exists (prog_exists_dir prog) (exec_path_list ())
+
+(* Run a program and return the output as a string *)
+let system (prog : string) (args : string list) : string =
+ run_with_string (fun _ -> exec_path prog args)
+
+(******************************************************************************)
+
+(* Define the various datatypes *)
+
+(* Font encodings - not entirely implemented yet FIX *)
+type encoding =
+ | OML (* Original TeX math text encoding: ?? *)
+ | OMS (* Original TeX math symbol encoding: ?? *)
+ | OMX (* Original TeX math extended symbol encoding: ?? *)
+ | OT1 (* Original TeX encoding: ?? *)
+ | OT2 (* ??: ?? *)
+ | OT4 (* ??: ?? *)
+ | QX (* ??: ?? *)
+ | T1 (* TeX Cork encoding: cork, tex256 *)
+ | T2 (* ??: ?? *)
+ | T5 (* ??: ?? *)
+ | TS1 (* ??: ?? *)
+ | U (* Unknown encoding: ?? *)
+ | LY1 (* ??: texnansx *)
+
+(* NFSS Weights *)
+type weight =
+ | UltraLightWeight
+ | ExtraLightWeight
+ | LightWeight
+ | SemiLightWeight
+ | MediumWeight
+ | SemiBoldWeight
+ | BoldWeight
+ | ExtraBoldWeight
+ | UltraBoldWeight
+
+(* NFSS Widths *)
+type width =
+ | UltraCondensedWidth
+ | ExtraCondensedWidth
+ | CondensedWidth
+ | SemiCondensedWidth
+ | MediumWidth
+ | SemiExpandedWidth
+ | ExpandedWidth
+ | ExtraExpandedWidth
+ | UltraExpandedWidth
+
+(* NFSS Shapes *)
+type shape =
+ | UprightShape
+ | ItalicShape
+ | SlantedShape
+ | SmallCapsShape
+ | UprightItalicShape
+ | OutlineShape
+
+(* OpenType features *)
+type feature =
+ | Faalt (* access all alternates *)
+ | Fc2sc (* small captials from capitals *)
+ | Fcalt (* contextual alternatives *)
+ | Fcase (* case sensitive forms *)
+ | Fcpsp (* captial spacing *)
+ | Fcswh (* contextual swash *)
+ | Fdlig (* discrentionary ligatures *)
+ | Fdnom (* denominators *)
+ | Ffina (* terminal forms *)
+ | Ffrac (* fractions *)
+ | Fhist (* historical forms *)
+ | Fkern (* kerning *)
+ | Fliga (* standard ligatures *)
+ | Flnum (* lining figures *)
+ | Fnumr (* numerators *)
+ | Fonum (* old style numbers *)
+ | Fordn (* ordinals *)
+ | Fornm (* Ornaments *)
+ | Fpnum (* proportional figures *)
+ | Fsalt (* stylistic alternatives *)
+ | Fsinf (* scientific inferiors *)
+ | Fsize (* optical sizes *)
+ | Fsmcp (* small caps *)
+ | Fss of int (* Stylistic sets *)
+ | Fsups (* superscript *)
+ | Fswsh (* swash *)
+ | Ftnum (* tabular figures *)
+ | Fzero (* slashed zero *)
+
+(* Ranges used to describe optical coverage for a font *)
+type range =
+ | Greater of float
+ | Less of float
+ | Between of (float * float)
+ | All
+
+(******************************************************************************)
+
+(* Convert an encoding to a string *)
+let encodingToString (enc : encoding) =
+ (match enc with
+ | OML -> "OML"
+ | OMS -> "OMS"
+ | OMX -> "OMX"
+ | OT1 -> "OT1"
+ | OT2 -> "OT2"
+ | OT4 -> "OT4"
+ | QX -> "QX"
+ | T1 -> "T1"
+ | T2 -> "T2"
+ | T5 -> "T5"
+ | TS1 -> "TS1"
+ | LY1 -> "LY1"
+ | U -> "U")
+
+let parseEncoding (enc : string) : encoding =
+ (match (String.uppercase enc) with
+ | "OML" -> OML
+ | "OMS" -> OMS
+ | "OMX" -> OMX
+ | "OT1" -> OT1
+ | "OT2" -> OT2
+ | "OT4" -> OT4
+ | "QX" -> QX
+ | "T1" -> T1
+ | "T2" -> T2
+ | "T5" -> T5
+ | "TS1" -> TS1
+ | "LY1" -> LY1
+ | "U" -> U
+ | _ -> error ("Unknown font encoding " ^ enc))
+
+(* Convert an encoding name to a default encoding file, not entirely correct yet. *)
+let encodingToFile (enc : encoding) =
+ let encwarn () =
+ warning ("Presently, encoding " ^ (encodingToString enc) ^ " is not directly supported.\nTry using --encFile=file to specify an encoding file. ")
+ in
+ (match enc with
+ | OML -> (encwarn (); "-")
+ | OMS -> (encwarn (); "-")
+ | OMX -> (encwarn (); "-")
+ | OT1 -> (encwarn (); "-")
+ | OT2 -> (encwarn (); "-")
+ | OT4 -> (encwarn (); "-")
+ | QX -> (encwarn (); "-")
+ | T1 -> "cork"
+ | T2 -> (encwarn (); "-")
+ | T5 -> (encwarn (); "-")
+ | TS1 -> (encwarn (); "-")
+ | LY1 -> "texnansx"
+ | U -> (encwarn (); "-"))
+
+(* Convert a feature to a string *)
+let featureToString (feat : feature) =
+ (match feat with
+ | Faalt -> "aalt"
+ | Fc2sc -> "c2sc"
+ | Fcalt -> "calt"
+ | Fcase -> "case"
+ | Fcpsp -> "cpsp"
+ | Fcswh -> "cswh"
+ | Fdlig -> "dlig"
+ | Fdnom -> "dnom"
+ | Ffina -> "fina"
+ | Ffrac -> "frac"
+ | Fhist -> "hist"
+ | Fkern -> "kern"
+ | Fliga -> "liga"
+ | Flnum -> "lnum"
+ | Fnumr -> "numr"
+ | Fonum -> "onum"
+ | Fordn -> "ordn"
+ | Fornm -> "ornm"
+ | Fpnum -> "pnum"
+ | Fsalt -> "salt"
+ | Fsinf -> "sinf"
+ | Fsize -> "size"
+ | Fsmcp -> "smcp"
+ | Fss(n) -> if((n >= 1) || (n<=20)) then "ss" ^ (string_of_int n) else (error "Invalid style set") (* FIX -- this doesn't output leading zeros :-( *)
+ | Fsups -> "sups"
+ | Fswsh -> "swsh"
+ | Ftnum -> "tnum"
+ | Fzero -> "zero")
+
+(* Convert a weight to a string *)
+let weightToString (wght : weight) =
+ (match wght with
+ | UltraLightWeight -> "ul"
+ | ExtraLightWeight -> "el"
+ | LightWeight -> "l"
+ | SemiLightWeight -> "sl"
+ | MediumWeight -> "m"
+ | SemiBoldWeight -> "sb"
+ | BoldWeight -> "b"
+ | ExtraBoldWeight -> "eb"
+ | UltraBoldWeight -> "ub")
+
+(* Convert a width to a string *)
+let widthToString (wdth : width) =
+ (match wdth with
+ | UltraCondensedWidth -> "uc"
+ | ExtraCondensedWidth -> "ec"
+ | CondensedWidth -> "c"
+ | SemiCondensedWidth -> "sc"
+ | MediumWidth -> "m"
+ | SemiExpandedWidth -> "sx"
+ | ExpandedWidth -> "x"
+ | ExtraExpandedWidth -> "ex"
+ | UltraExpandedWidth -> "ux")
+
+(* Convert a shape to a string *)
+let shapeToString (shp : shape) =
+ (match shp with
+ | UprightShape -> "n"
+ | ItalicShape -> "it"
+ | SlantedShape -> "sl"
+ | SmallCapsShape -> "sc"
+ | UprightItalicShape -> (error "FIX")
+ | OutlineShape -> (error "FIX"))
+
+(* Convert a range to a string *)
+let rangeToString (rng : range) : string =
+ (match rng with
+ | Greater f -> "<" ^ (string_of_float f) ^ "->"
+ | Less f -> "<-" ^ (string_of_float f) ^ ">"
+ | Between (s,e) -> "<" ^ (string_of_float s) ^ "-" ^ (string_of_float e) ^ ">"
+ | All -> "<->" )
+
+(* Compare to ranges -- kind of broken, but works well enough at the moment *)
+let compareRngs (rng1 : range) (rng2 : range) : int =
+ (match (rng1, rng2) with
+ (* Slapdash comparison heurisitic *)
+ | (All, All) -> 0
+ | (_, All) -> -1
+ | (All, _) -> 1
+ | (Greater f1, Greater f2) -> compare f1 f2
+ | (Less f1, Less f2) -> compare f1 f2
+ | (Greater f1, Less f2) -> compare f1 f2
+ | (Less f1, Greater f2) -> compare f1 f2
+ | (Less f, Between (s,e)) ->
+ if (f < e) then -1
+ else
+ if (f >= e) then 1
+ else
+ 0
+ | (Between (s,e), Less f) ->
+ if (f < e) then -1
+ else
+ if (f >= e) then 1
+ else
+ 0
+ | (Greater f, Between (s,e)) ->
+ if (f < e) then -1
+ else
+ if (f >= e) then 1
+ else
+ 0
+ | (Between (s,e), Greater f) ->
+ if (f < e) then -1
+ else
+ if (f >= e) then 1
+ else
+ 0
+ | (Between (s1, e1), Between (s2, e2)) ->
+ if (e1 < s1) then -1
+ else
+ if (s1 >= e2) then 1
+ else
+ if (e1 < e2) then -1
+ else
+ if (e1 >= e2) then 1
+ else
+ 0
+ )
+
+(* Create a series string from width and weight *)
+let createSeries (wght : weight) (wdth : width) =
+ (match wght with
+ | MediumWeight ->
+ (match wdth with
+ | MediumWidth -> "m"
+ | _ -> widthToString wdth)
+ | _ ->
+ (match wdth with
+ | MediumWidth -> weightToString wght
+ | _ -> (weightToString wght) ^ (widthToString wdth)))
+
+(******************************************************************************)
+
+(* Global configuration constants *)
+
+let encoding : encoding ref = ref T1
+let encodingFile : (string option) ref = ref None
+
+(* Should we show the usage information instead of doing anything? *)
+let showUsage : bool ref = ref false
+
+(* Generate a version of the fonts with swashes *)
+let swashVersion : bool ref = ref false
+
+(* Generate a version of the fonts with just ornaments *)
+let ornamentVersion : bool ref = ref false
+
+(* Should we print more info about what we are doing? *)
+let verbose : bool ref = ref false
+
+(******************************************************************************)
+
+(* Heuristics *)
+
+(* Try to infer a weight from the attribute string in the filename *)
+let parseWeight (attr : string) =
+ if (string_match (regexp ".*\\(Black\\|Bold\\|Bd\\|Semibold\\|Regular\\|ExtraLight\\|Light\\|Lt\\).*") attr 0) then
+ (match (matched_group 1 attr) with
+ (* We assume black is ExtraBold rather than UltraBold *)
+ | "Black" -> Some (ExtraBoldWeight)
+ | ("Bold"|"Bd") -> Some (BoldWeight)
+ | "Semibold" -> Some (SemiBoldWeight)
+ | "Regular" -> Some (MediumWeight)
+ (* Disambiguate *)
+ | ("Light"|"Lt") ->
+ if (string_match (regexp ".*ExtraLight.*") attr 0) then
+ Some (ExtraLightWeight)
+ else
+ Some (LightWeight)
+ | _ -> (error "Shouldn't have matched!"))
+ else
+ None
+
+(* Try to infer a width from the attribute string in the filename *)
+let parseWidth (attr : string) =
+ if (string_match (regexp ".*\\(Regular\\|Cond\\|SemiCn\\|Cn\\|SemiExt\\).*") attr 0) then
+ (match (matched_group 1 attr) with
+ | "SemiExt" -> Some (SemiExpandedWidth)
+ | "Regular" -> Some (MediumWidth)
+ | ("Cond"|"Cn") ->
+ (* Disambiguate *)
+ if (string_match (regexp ".*SemiCn.*") attr 0) then
+ Some (SemiCondensedWidth)
+ else
+ Some (CondensedWidth)
+ | _ -> (error "Shouldn't have matched!"))
+ else
+ None
+
+(* Try to infer a shape from the attribute string in the filename *)
+let parseShape (attr : string) =
+ if (string_match (regexp ".*\\(Regular\\|It\\|Italic\\|Slanted\\).*") attr 0) then
+ (match (matched_group 1 attr) with
+ | ("Italic"|"It") -> Some (ItalicShape)
+ | "Regular" -> Some (UprightShape)
+ | "Slanted" -> Some (SlantedShape)
+ | _ -> (error "Shouldn't have matched!"))
+ else
+ None
+
+(* Try to infer a design size from the attribute string in the filename *)
+let parseDesign (attr : string) =
+ if (string_match (regexp ".*\\(Regular\\|Capt\\|Disp\\|Headline\\|Subh\\).*") attr 0) then
+ (match (matched_group 1 attr) with
+ (* otfinfo gives slightly different numbers for different fonts, so just
+ use these as an estimate if otfinfo is unavailable or doesn't provide
+ feedback *)
+ | ("Disp"|"Headline") -> Some (20.1,72.0)
+ | "Subh" -> Some (13.1, 20.0)
+ | "Regular" -> Some (9.0, 13.0)
+ | "Capt" -> Some (6.0, 8.9)
+ | _ -> (error "Shouldn't have matched!"))
+ else
+ None
+
+(* Attempt to figure out stuff about the font just from the name *)
+let parseFileName (fn : string) =
+ let parts = Str.split (regexp "[-\\.]") fn in
+ (match parts with
+ | [name; attr; ext] -> if (ext = "otf") then
+ (name,
+ parseWeight attr,
+ parseWidth attr,
+ parseShape attr,
+ parseDesign attr)
+ else
+ error ("Filename \"" ^ fn ^ "\" does not appear to be an OpenType file")
+ | [name; ext] -> if (ext = "otf") then
+ (name,
+ None,
+ None,
+ None,
+ None)
+ else
+ error ("Filename \"" ^ fn ^ "\" does not appear to be an OpenType file")
+ | _ -> error ("Error parsing filename \"" ^ fn ^ "\""))
+
+(******************************************************************************)
+
+(* Constants used when optimizing ranges *)
+let minrange = 1.0
+let maxrange = 144.0
+
+(* Optimize font ranges *)
+let optRanges (rngs : (range * (string * string list)) list) :
+ (range * (string * string list)) list =
+ (* First sort them *)
+ let sorted = sort (fun (rng1, _) (rng2, _) -> compareRngs rng1 rng2)
+ rngs in
+ (* Extend the ranges so that we have everything as small as minrange pt *)
+ let cover_bottom rngs =
+ (match rngs with
+ | [] -> (error "Font must have at least one range!")
+ | (Greater f, stf)::tl -> (Greater minrange, stf)::tl
+ | (Less f, stf)::tl -> (Less f, stf)::tl
+ | (Between (s,e), stf)::tl -> (Between (minrange, e), stf)::tl
+ | (All, stf)::tl -> (All, stf)::tl)
+ in
+ (* Extend the ranges so that we have everything as large as maxrange pt *)
+ let rec cover_top rngs =
+ (match rngs with
+ | [] -> (error "Font must have at least one range!")
+ | [(Greater f, stf)] -> [(Greater f, stf)]
+ | [(Less f, stf)] -> [(Less maxrange, stf)]
+ | [(Between (s,e), stf)] -> [(Between (s, maxrange), stf)]
+ | [(All, stf)] -> [(All, stf)]
+ | hd::tl -> hd::(cover_top tl))
+ in
+ let rec remove_gaps rngs =
+ (match rngs with
+ | [] -> (error "Font must have at least one range!")
+ | [(rng, stf)] -> [(rng, stf)]
+ | (rng1, stf1)::(rng2, stf2)::tl ->
+ (match (rng1, rng2) with
+ (* All can't have a gap *)
+ | (All, _) -> (rng1, stf1)::(remove_gaps ((rng2,stf2)::tl))
+ (* Greater can't have a gap *)
+ | (Greater _, _) -> (rng1, stf1)::(remove_gaps ((rng2,stf2)::tl))
+ (* Less followed by less or all can't have a gap *)
+ | (Less _, Less _) -> (rng1, stf1)::(remove_gaps ((rng2,stf2)::tl))
+ | (Less _, All) -> (rng1, stf1)::(remove_gaps ((rng2,stf2)::tl))
+ | (Less f1, Greater f2) -> (Less f2, stf1)::(remove_gaps ((rng2,stf2)::tl))
+ | (Less f, Between (s,e)) -> (Less s, stf1)::(remove_gaps ((rng2,stf2)::tl))
+ (* Between followed by less or all can't have a gap *)
+ | (Between (s, e), Less f) -> (rng1, stf1)::(remove_gaps ((rng2,stf2)::tl))
+ | (Between (s, e), All) -> (rng1, stf1)::(remove_gaps ((rng2,stf2)::tl))
+ | (Between (s, e), Greater f) -> (Between(s, f), stf1)::(remove_gaps ((rng2,stf2)::tl))
+ | (Between (s1,e1), Between (s2,e2)) ->
+ (Between (s1,s2), stf1)::(remove_gaps ((rng2,stf2)::tl))
+ ))
+ in
+ remove_gaps (cover_bottom (cover_top sorted))
+
+(******************************************************************************)
+
+(* Feature parsing *)
+
+(* This is a list of regexps and handler functions *)
+let featureHandlers =
+ [ ("aalt", (fun _ -> Faalt));
+ ("c2sc", (fun _ -> Fc2sc));
+ ("calt", (fun _ -> Fcalt));
+ ("case", (fun _ -> Fcase));
+ ("cpsp", (fun _ -> Fcpsp));
+ ("cswh", (fun _ -> Fcswh));
+ ("dlig", (fun _ -> Fdlig));
+ ("dnom", (fun _ -> Fdnom));
+ ("fina", (fun _ -> Ffina));
+ ("frac", (fun _ -> Ffrac));
+ ("hist", (fun _ -> Fhist));
+ ("kern", (fun _ -> Fkern));
+ ("liga", (fun _ -> Fliga));
+ ("lnum", (fun _ -> Flnum));
+ ("numr", (fun _ -> Fnumr));
+ ("onum", (fun _ -> Fonum));
+ ("ordn", (fun _ -> Fordn));
+ ("ornm", (fun _ -> Fornm));
+ ("pnum", (fun _ -> Fpnum));
+ ("salt", (fun _ -> Fsalt));
+ ("sinf", (fun _ -> Fsinf));
+ ("size", (fun _ -> Fsize));
+ ("smcp", (fun _ -> Fsmcp));
+ ("smcp", (fun _ -> Fsmcp));
+ ("ss[0-9][0-9]",
+ (fun str ->
+ let numstr = (last_chars str 2) in
+ try
+ let n = int_of_string numstr in
+ if((n >= 1) || (n<=20)) then
+ Fss(n)
+ else
+ (error "Invalid style set while parsing features")
+ with Failure msg -> (error "Invalid style set while parsing features")));
+ ("sups", (fun _ -> Fsups));
+ ("swsh", (fun _ -> Fswsh));
+ ("tnum", (fun _ -> Ftnum));
+ ("zero", (fun _ -> Fzero)) ]
+
+(* Call otfinfo to obtain a list of features for the specified filename *)
+let parseOTFFeatures (fn : string) : feature list =
+ let result = system "otfinfo" ["-f"; fn] in
+ let rec buildFeatures handlers features =
+ (match handlers with
+ | [] -> (rev features)
+ | (rx, handlerFun)::hs ->
+ if (string_match
+ (regexp ("\\(.\\|\n\\)*\\(" ^ rx ^ "\\)\\(.\\|\n\\)*")) result 0) then
+ buildFeatures hs ((handlerFun (matched_group 2 result))::features)
+ else
+ buildFeatures hs features)
+ in
+ buildFeatures featureHandlers []
+
+(******************************************************************************)
+
+(* Parsing design size *)
+
+(* See if otfinfo can give us a design size as well as a size range *)
+let parseOTFSize (fn : string) : (float * float * float) option =
+ let result = system "otfinfo" ["-z"; fn] in
+ (* Abstract out the regex for a decimal number *)
+ let dec_num = "[0-9]+\\(\\.[0-9]+\\)?" in
+ if (string_match (regexp
+ ("design size \\(" ^ dec_num ^
+ "\\) pt, size range \\((\\|\\[\\)\\(" ^ dec_num ^ "\\) pt, \\(" ^ dec_num ^
+ "\\) pt\\()\\|\\]\\), .*")) result 0)
+ then
+ Some (float_of_string (matched_group 1 result),
+ float_of_string (matched_group 4 result),
+ float_of_string (matched_group 6 result))
+ else
+ None
+
+(******************************************************************************)
+
+(* The primary datastructure that we use to construct all of the necessary output
+ familes -- table of all the font families we have encountered
+ shapes -- each family has a table of shapes that it supports
+ weights -- each shape table has a table of weights it supports
+ widths -- each weight table has a table of widths it supports
+ ranges -- each width table has a list of optical ranges,
+ should not overlap.
+ impl -- each range has an associated implementation with
+ it, that is a pair of the file that we are using to
+ get this particular instance and the options that
+ we need to pass to otftotfm to generate it
+
+*)
+(* Create one of size five, don't expect to run this on more than a couple families *)
+let families = Hashtbl.create 5
+
+
+let allocate_family (fam : string) : unit =
+ (* Check to see if this family already exists *)
+ if (not (Hashtbl.mem families fam)) then
+ (* Create seven entries for shapes, as we don't recognize any more than six
+ at this point *)
+ Hashtbl.add families fam (Hashtbl.create 7)
+ else
+ ()
+
+(* Allocate an entry in the font table *)
+let allocate_entry (fam : string)
+ (shp : shape)
+ (wght : weight)
+ (wdth : width)
+ (rng : range)
+ (fn : string)
+ (opts : string list) =
+ let shpTable =
+ (* Check to see if this family already exists *)
+ try
+ Hashtbl.find families fam
+ (* If not, create it *)
+ with Not_found ->
+ (* Create seven entries for shapes, as we don't recognize any more than six
+ at this point *)
+ let tbl = Hashtbl.create 7 in
+ (Hashtbl.add families fam tbl; tbl) in
+ let wghtTable =
+ (* Check to see if this table already exists *)
+ try
+ Hashtbl.find shpTable shp
+ (* If not, create it *)
+ with Not_found ->
+ (* Create ten entries for weights, as we don't recognize any more than nine
+ at this point *)
+ let tbl = Hashtbl.create 10 in
+ (Hashtbl.add shpTable shp tbl; tbl) in
+ let wdthTable =
+ (* Check to see if this table already exists *)
+ try
+ Hashtbl.find wghtTable wght
+ (* If not, create it *)
+ with Not_found ->
+ (* Create ten entries for widthd, as we don't recognize any more than nine
+ at this point *)
+ let tbl = Hashtbl.create 10 in
+ (Hashtbl.add wghtTable wght tbl; tbl) in
+ let rngList =
+ (* Check to see if there is already a list of ranges *)
+ try
+ Hashtbl.replace wdthTable wdth ((rng,(fn, opts))::(Hashtbl.find wdthTable wdth))
+ (* If not, create it *)
+ with Not_found ->
+ Hashtbl.add wdthTable wdth [(rng, (fn, opts))] in
+ ()
+
+(***************************************************************************)
+
+(* Check for a specified feature *)
+let rec checkFeature (feat : feature) (feats : feature list) : bool =
+ (match feats with
+ | [] -> false
+ | hd::tl ->
+ if (hd = feat) then
+ true
+ else
+ checkFeature feat tl)
+
+(* Given the fonts features and the shape we inferred from the filename,
+ figure out what shapes it supports and the options necessary to generate them *)
+let decideShapes (shpopt : shape option) (feats : feature list) :
+ (shape * string list) list =
+ (* Look at what we decided from the filename *)
+ (match shpopt with
+ (* If it is upright we might also want to check for smallcaps *)
+ | Some(UprightShape) ->
+ if (checkFeature Fsmcp feats) then
+ [(UprightShape, []); (SmallCapsShape, ["-fsmcp"])]
+ else
+ [(UprightShape, [])]
+ (* OpenType allows "other" shapes to also have smallcaps shapes,
+ but NFSS doesn't support mixing shapes like that at the moment,
+ so we will just ignore the smallcaps capabilities *)
+ | Some(shp) -> [(shp, [])]
+ (* If we didn't get a shape from the filename, assume upright, and
+ check for smallcaps *)
+ | None ->
+ if (checkFeature Fsmcp feats) then
+ [(UprightShape, []); (SmallCapsShape, ["-fsmcp"])]
+ else
+ [(UprightShape, [])])
+
+(* Decide the weight of a font, not very interesting because
+ we only rely upon what we guessed from the filename *)
+(* FIX: Should also attempt to consult otfinfo *)
+let decideWeight (wghtopt : weight option) : weight =
+ (match wghtopt with
+ (* If we inferred a weight, use it *)
+ | Some(wght) -> wght
+ (* If we didn't assume that this is a medium weight font *)
+ | None -> MediumWeight)
+
+(* Decide the width of a font, not very interesting because
+ we only rely upon what we guessed from the filename *)
+(* FIX: Should also attempt to consult otfinfo *)
+let decideWidth (wdthopt : width option) : width =
+ (match wdthopt with
+ (* If we inferred a weight, use it *)
+ | Some(wdth) -> wdth
+ (* If we didn't assume that this is a medium weight font *)
+ | None -> MediumWidth)
+
+(* See if we can determine an optical size *)
+let decideSize (dsnopt : (float * float) option)
+ (feats : feature list)
+ (otfsize : (float * float * float) option) : range =
+ (* Does this font include an optical size feature? *)
+ if (checkFeature Fsize feats) then
+ (* Yes, use it *)
+ (match otfsize with
+ | Some(_, s, e) -> Between (s, e)
+ | None -> (error "Shouldn't be possible!")
+ )
+ else
+ All
+ (* Turn this off for now, doesn't seem to really work well
+
+ (* Nope, try guessing based upon the name *)
+ (match dsnopt with
+ | Some (s, e) -> Between (s, e)
+ | None -> All)
+ *)
+
+(* Table building inner loop *)
+let build_table_inner (fn : string)
+ (family : string)
+ (wghtopt : weight option)
+ (wdthopt : width option)
+ (dsnopt : (float * float) option)
+ (shp : shape)
+ (features : feature list)
+ (opts : string list) =
+ let otfsize = parseOTFSize fn in
+ (* Always add default ligatures, kerning, and terminal forms if they are available *)
+ let opts = if (checkFeature Fliga features) then "-fliga"::opts else opts in
+ let opts = if (checkFeature Fkern features) then "-fkern"::opts else opts in
+ let opts = if (checkFeature Ffina features) then "-ffina"::"--boundary-char= "::opts else opts in
+ begin
+ (* Allocate entries in the table *)
+ allocate_entry family
+ shp
+ (decideWeight wghtopt)
+ (decideWidth wdthopt)
+ (decideSize dsnopt features otfsize)
+ fn
+ opts
+ end
+
+(* Fill in the appropriate entries in the family table for the given filename *)
+let build_table (swash : bool) (orn : bool) (fn : string) =
+ let (family, wghtopt, wdthopt, shpopt, dsnopt) = parseFileName fn in
+ let features = parseOTFFeatures fn in
+ begin
+ (* For each shape we have ... *)
+ fold_left
+ (fun _ (shp, opts) ->
+ if swash then
+ if ((checkFeature Fswsh features) && (checkFeature Fcswh features)) then
+ let opts = "-fswsh"::"-fcswh"::opts in
+ build_table_inner fn family wghtopt wdthopt dsnopt shp features opts
+ else
+ (* No swashes, so don't do anything *)
+ ()
+ else if orn then
+ if (checkFeature Fornm features) then
+ let opts = "-fornm"::opts in
+ build_table_inner fn family wghtopt wdthopt dsnopt shp features opts
+ else
+ (* No ornaments, so don't do anything *)
+ ()
+ else
+ build_table_inner fn family wghtopt wdthopt dsnopt shp features opts)
+ ()
+ (decideShapes shpopt features)
+ end
+
+(* Generate the "Texname" for a given font from the filename and options *)
+let genTexname (fn : string) (enc : encoding) (opts : string list) =
+ let rec filteropts (opts : string list) : string list =
+ (match opts with
+ | [] -> []
+ | h::t ->
+ if (string_match (regexp "-f.*") h 0) then h::(filteropts t) else (filteropts t))
+ in
+ let fopts = filteropts opts in
+ let parts = Str.split (regexp "\\.") fn in
+ (match parts with
+ | [name; ext] -> if (ext = "otf") then
+ (encodingToString enc) ^ "-" ^ name ^ (String.concat "" fopts)
+ else
+ error ("Filename \"" ^ fn ^ "\" does not appear to be an OpenType file")
+ | _ -> error ("Error parsing filename \"" ^ fn ^ "\""))
+
+(******************************************************************************)
+
+(* Generate a list of NFSS font descriptor files *)
+let genFdFile (enc : encoding) : (string * string) list =
+ Hashtbl.fold
+ (fun family shpTable files ->
+ (((encodingToString enc) ^ family ^ ".fd"),
+ "\\DeclareFontFamily{" ^ (encodingToString enc) ^ "}{" ^ family ^ "}{}\n" ^
+ (Hashtbl.fold
+ (fun shp wghtTable accum ->
+ Hashtbl.fold
+ (fun wght wdthTable accum ->
+ Hashtbl.fold
+ (fun wdth rngs accum ->
+ ("\\DeclareFontShape{" ^ (encodingToString enc) ^
+ "}{" ^ family ^ "}{" ^ (createSeries wght wdth) ^
+ "}{" ^ (shapeToString shp) ^ "}{" ^
+ (fold_left
+ (fun accum (rng, (fn, opts)) ->
+ accum ^ " " ^ (rangeToString rng) ^ " " ^
+ (genTexname fn enc opts) ^ " ")
+ ""
+ (optRanges rngs)
+ ) ^ "}{ }\n" ^ accum)
+ )
+ wdthTable
+ accum
+ )
+ wghtTable
+ accum
+ )
+ shpTable
+ "\n"
+ )
+ )::files
+ )
+ families
+ []
+
+
+(******************************************************************************)
+
+type map_special =
+ | SlantFontSpecial of float
+ | ExtendFontSpecial of float
+
+type std_psfont =
+ | TimesRomanPS
+ | TimesItalicPS
+ | TimesBoldPS
+ | TimesBoldItalicPS
+ | HelveticaPS
+ | HelveticaObliquePS
+ | HelveticaBoldPS
+ | HelveticaBoldObliquePS
+ | CourierPS
+ | CourierObliquePS
+ | CourierBoldPS
+ | CourierBoldObliquePS
+ | SymbolPS
+
+type map_embed =
+ | PartialEmbed
+ | FullEmbed
+ | NoEmbed
+
+(* tfmname, psbasename, fontflags, specials, encoding file *)
+type map_entry =
+ | MapFile of string *
+ string option *
+ (* map_fontflags option * FIX *)
+ map_special list *
+ string option *
+ map_embed *
+ string
+ | PSFile of string *
+ std_psfont *
+ (* map_fontflags option * FIX *)
+ map_special list *
+ string option
+
+
+(******************************************************************************)
+
+(* Generate a list of map files by running otftotfm*)
+let genMapFile () : (string * string) list =
+ Hashtbl.fold
+ (fun family shpTable files ->
+ ((family ^ ".map"),
+ Hashtbl.fold
+ (fun shp wghtTable accum ->
+ Hashtbl.fold
+ (fun wght wdthTable accum ->
+ Hashtbl.fold
+ (fun wdth rngs accum ->
+ (fold_left
+ (fun accum (rng, (fn, opts)) ->
+ let tname = genTexname fn (!encoding) opts in
+ (match (!encodingFile) with
+ | Some(file) ->
+ let mapline =
+ system "otftotfm" (("-e"::file::fn::opts)@[tname]) in
+ accum ^ mapline
+ | None -> error "should be impossible!")
+ )
+ ""
+ rngs
+ ) ^ accum
+ )
+ wdthTable
+ accum
+ )
+ wghtTable
+ accum
+ )
+ shpTable
+ "\n"
+ )::files
+ )
+ families
+ []
+
+(******************************************************************************)
+
+(* Print the usage information for the program *)
+let usage () : 'a =
+ print_string ("Usage: " ^ (!program_name) ^ "\n" ^
+ " [--help]\n" ^
+ " [--verbose]\n" ^
+ " [--swash]\n" ^
+ " [--ornaments]\n" ^
+ " [--enc=ENCODING]\n" ^
+ " [--encFile=FILE]\n" ^
+ " files ...\n\n" ^
+ "Construct NFSS font descriptor files and PostScript map files\n" ^
+ "for the specified OpenType fonts.\n\n" ^
+ " -h, --help print this message\n" ^
+ " --verbose print more information about what is happening\n" ^
+ " --swash generate a swashy version (experimental)\n" ^
+ " --ornaments generate ornaments (experimental)\n" ^
+ " --enc=ENCODING set the encoding type (default T1) \n" ^
+ " --encFile=FILE set the encoding definition (default cork)\n\n" ^
+ "Version $Id: otftofd 7 2005-09-10 21:25:47Z geoffw $\n" ^
+ "Report bugs to <washburn@acm.org>.\n")
+
+let rec parseArgs (args : string list) : string list =
+ (match args with
+ | [] -> []
+ | "--h"::t -> (showUsage := true); parseArgs t
+ | "--verbose"::t -> (verbose := true); parseArgs t
+ | "--help"::t -> (showUsage := true); parseArgs t
+ | "--swash"::t -> (swashVersion := true); parseArgs t
+ | "--ornaments"::t -> (ornamentVersion := true); parseArgs t
+ | (h::t)
+ when
+ (string_match (regexp "--enc=\\(.*\\)") h 0) ->
+ (encoding := parseEncoding (matched_group 1 h));
+ parseArgs t
+ | (h::t)
+ when
+ (string_match (regexp "--encfile=\\(.*\\)") h 0) ->
+ (encodingFile := Some (matched_group 1 h));
+ parseArgs t
+ | h::t -> h :: (parseArgs t))
+
+(******************************************************************************)
+
+(* Should convert to basename *)
+let _ = (program_name := basename (hd (command_line ())))
+
+let options = (tl (command_line ()))
+
+let _ = map (fun prog -> if not (prog_exists_path prog) then
+ error ("Could not find the program " ^ prog ^ " in your path!"))
+ ["otfinfo"; "otftotfm"]
+
+(******************************************************************************)
+
+(* Do the work *)
+let filtered_args = (parseArgs options) in
+ let _ = (match (!encodingFile) with
+ | None -> (encodingFile := Some (encodingToFile (!encoding)))
+ | _ -> ()) in
+ if ((length filtered_args) > 0) && not (!showUsage) then
+ begin
+ ignore (map (build_table (!swashVersion)
+ (!ornamentVersion))
+ filtered_args);
+ ignore (map
+ (fun (fn, contents) ->
+ let _ = if (!verbose) then
+ print_string ((!program_name) ^ ": creating " ^ fn ^ "\n")
+ in
+ let channel = open_out fn in
+ let _ = output_string channel contents in
+ close_out channel)
+ (genFdFile (!encoding)));
+ ignore (map
+ (fun (fn, contents) ->
+ let _ = if (!verbose) then
+ print_string ((!program_name) ^ ": creating " ^ fn ^ "\n")
+ in
+ let channel = open_out fn in
+ let _ = output_string channel contents in
+ close_out channel)
+ (genMapFile ()))
+ end
+ else
+ usage ()