diff options
author | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
---|---|---|
committer | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
commit | e0c6872cf40896c7be36b11dcc744620f10adf1d (patch) | |
tree | 60335e10d2f4354b0674ec22d7b53f0f8abee672 /fonts/utilities/otftofd |
Initial commit
Diffstat (limited to 'fonts/utilities/otftofd')
-rw-r--r-- | fonts/utilities/otftofd/COPYING | 340 | ||||
-rw-r--r-- | fonts/utilities/otftofd/README | 94 | ||||
-rw-r--r-- | fonts/utilities/otftofd/otftofd | 1037 |
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 () |