pax_global_header00006660000000000000000000000064124737022640014521gustar00rootroot0000000000000052 comment=7677e7d7b4e0f455418813437f6d2dae296c4715 t1utils-1.39/000077500000000000000000000000001247370226400130625ustar00rootroot00000000000000t1utils-1.39/.gitignore000066400000000000000000000004271247370226400150550ustar00rootroot00000000000000*.o .deps Makefile Makefile.in aclocal.m4 autom4te* config.cache config.guess config.h config.h.in config.h.in~ config.log config.status config.sub configure depcomp include install-sh missing stamp-h* t1ascii t1asm t1binary t1disasm t1mac t1unmac t1utils-*.rpm t1utils-*.tar.gz t1utils-1.39/INSTALL000066400000000000000000000164461247370226400141260ustar00rootroot00000000000000Basic Installation ================== These are generic installation instructions. The `configure' shell script attempts to guess correct values for various system-dependent variables used during compilation. It uses those values to create a `Makefile' in each directory of the package. It may also create one or more `.h' files containing system-dependent definitions. Finally, it creates a shell script `config.status' that you can run in the future to recreate the current configuration, a file `config.cache' that saves the results of its tests to speed up reconfiguring, and a file `config.log' containing compiler output (useful mainly for debugging `configure'). If you need to do unusual things to compile the package, please try to figure out how `configure' could check whether to do them, and mail diffs or instructions to the address given in the `README' so they can be considered for the next release. If at some point `config.cache' contains results you don't want to keep, you may remove or edit it. The file `configure.in' is used to create `configure' by a program called `autoconf'. You only need `configure.in' if you want to change it or regenerate `configure' using a newer version of `autoconf'. The simplest way to compile this package is: 1. `cd' to the directory containing the package's source code and type `./configure' to configure the package for your system. If you're using `csh' on an old version of System V, you might need to type `sh ./configure' instead to prevent `csh' from trying to execute `configure' itself. Running `configure' takes awhile. While running, it prints some messages telling which features it is checking for. 2. Type `make' to compile the package. 3. Optionally, type `make check' to run any self-tests that come with the package. 4. Type `make install' to install the programs and any data files and documentation. 5. You can remove the program binaries and object files from the source code directory by typing `make clean'. To also remove the files that `configure' created (so you can compile the package for a different kind of computer), type `make distclean'. There is also a `make maintainer-clean' target, but that is intended mainly for the package's developers. If you use it, you may have to get all sorts of other programs in order to regenerate files that came with the distribution. Compilers and Options ===================== Some systems require unusual options for compilation or linking that the `configure' script does not know about. You can give `configure' initial values for variables by setting them in the environment. Using a Bourne-compatible shell, you can do that on the command line like this: CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure Or on systems that have the `env' program, you can do it like this: env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure Compiling For Multiple Architectures ==================================== You can compile the package for more than one kind of computer at the same time, by placing the object files for each architecture in their own directory. To do this, you must use a version of `make' that supports the `VPATH' variable, such as GNU `make'. `cd' to the directory where you want the object files and executables to go and run the `configure' script. `configure' automatically checks for the source code in the directory that `configure' is in and in `..'. If you have to use a `make' that does not supports the `VPATH' variable, you have to compile the package for one architecture at a time in the source code directory. After you have installed the package for one architecture, use `make distclean' before reconfiguring for another architecture. Installation Names ================== By default, `make install' will install the package's files in `/usr/local/bin', `/usr/local/man', etc. You can specify an installation prefix other than `/usr/local' by giving `configure' the option `--prefix=PATH'. You can specify separate installation prefixes for architecture-specific files and architecture-independent files. If you give `configure' the option `--exec-prefix=PATH', the package will use PATH as the prefix for installing programs and libraries. Documentation and other data files will still use the regular prefix. If the package supports it, you can cause programs to be installed with an extra prefix or suffix on their names by giving `configure' the option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. Optional Features ================= Some packages pay attention to `--enable-FEATURE' options to `configure', where FEATURE indicates an optional part of the package. They may also pay attention to `--with-PACKAGE' options, where PACKAGE is something like `gnu-as' or `x' (for the X Window System). The `README' should mention any `--enable-' and `--with-' options that the package recognizes. For packages that use the X Window System, `configure' can usually find the X include and library files automatically, but if it doesn't, you can use the `configure' options `--x-includes=DIR' and `--x-libraries=DIR' to specify their locations. Specifying the System Type ========================== There may be some features `configure' can not figure out automatically, but needs to determine by the type of host the package will run on. Usually `configure' can figure that out, but if it prints a message saying it can not guess the host type, give it the `--host=TYPE' option. TYPE can either be a short name for the system type, such as `sun4', or a canonical name with three fields: CPU-COMPANY-SYSTEM See the file `config.sub' for the possible values of each field. If `config.sub' isn't included in this package, then this package doesn't need to know the host type. If you are building compiler tools for cross-compiling, you can also use the `--target=TYPE' option to select the type of system they will produce code for and the `--build=TYPE' option to select the type of system on which you are compiling the package. Sharing Defaults ================ If you want to set default values for `configure' scripts to share, you can create a site shell script called `config.site' that gives default values for variables like `CC', `cache_file', and `prefix'. `configure' looks for `PREFIX/share/config.site' if it exists, then `PREFIX/etc/config.site' if it exists. Or, you can set the `CONFIG_SITE' environment variable to the location of the site script. A warning: not all `configure' scripts look for a site script. Operation Controls ================== `configure' recognizes the following options to control how it operates. `--cache-file=FILE' Use and save the results of the tests in FILE instead of `./config.cache'. Set FILE to `/dev/null' to disable caching, for debugging `configure'. `--help' Print a summary of the options to `configure', and exit. `--quiet' `--silent' `-q' Do not print messages saying which checks are being made. `--srcdir=DIR' Look for the package's source code in directory DIR. Usually `configure' can determine that directory automatically. `--version' Print the version of Autoconf used to generate the `configure' script, and exit. `configure' also accepts some other, not widely useful, options. t1utils-1.39/LICENSE000066400000000000000000000032371247370226400140740ustar00rootroot00000000000000Portions of this software are subject to the license below. The relevant source files are clearly marked; they refer to this file using the phrase "the Click LICENSE file". This license is an MIT license, plus a clause (taken from the W3C license) requiring prior written permission to use our names in publicity. =========================================================================== Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. The name and trademarks of copyright holders may NOT be used in advertising or publicity pertaining to the Software without specific, written prior permission. Title to copyright in this Software and any associated documentation will at all times remain with copyright holders. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. t1utils-1.39/Makefile.am000066400000000000000000000034151247370226400151210ustar00rootroot00000000000000## Process this file with automake to produce Makefile.in AUTOMAKE_OPTIONS = foreign check-news bin_PROGRAMS = t1ascii t1binary t1asm t1disasm t1unmac t1mac man_MANS = t1ascii.1 t1binary.1 t1asm.1 t1disasm.1 t1unmac.1 t1mac.1 t1ascii_SOURCES = include/lcdf/clp.h include/lcdf/inttypes.h \ clp.c t1lib.h t1lib.c t1ascii.c t1binary_SOURCES = include/lcdf/clp.h include/lcdf/inttypes.h \ clp.c t1lib.h t1lib.c t1binary.c t1asm_SOURCES = include/lcdf/clp.h include/lcdf/inttypes.h \ clp.c t1lib.h t1asmhelp.h t1lib.c t1asm.c t1disasm_SOURCES = include/lcdf/clp.h include/lcdf/inttypes.h \ clp.c t1lib.h t1asmhelp.h t1lib.c t1disasm.c t1unmac_SOURCES = include/lcdf/clp.h include/lcdf/inttypes.h \ clp.c t1lib.h t1lib.c t1unmac.c t1mac_SOURCES = include/lcdf/clp.h include/lcdf/inttypes.h \ clp.c t1lib.h t1lib.c t1mac.c AM_CPPFLAGS = -I$(top_srcdir)/include LDADD = @LIBOBJS@ EXTRA_DIST = $(man_MANS) t1utils.spec versionize: perl -pi -e "s/^\\.ds V.*/.ds V $(VERSION)/;" t1ascii.1 t1binary.1 t1disasm.1 t1asm.1 t1unmac.1 t1mac.1 perl -pi -e 's/^Version:(\s*).*/Version:$${1}$(VERSION)/; s/$(PACKAGE)-[\w.]+\.tar\.gz/$(PACKAGE)-$(VERSION).tar.gz/;' t1utils.spec perl -pi -e 's/VERSION [\d.ab]+/VERSION $(VERSION)/;' README rpm: dist buildarch=`rpm --showrc | awk '/^build arch/ { print $$4; }'` ; \ mkdir -p /tmp/rpm-t1u/SOURCES /tmp/rpm-t1u/RPMS/$$buildarch \ /tmp/rpm-t1u/BUILD ; \ echo 'include: /usr/lib/rpm/rpmrc' > /tmp/rpm-t1u/rc ; \ echo 'macrofiles: /usr/lib/rpm/macros:/tmp/rpm-t1u/macros' >> /tmp/rpm-t1u/rc ; \ echo '%_topdir /tmp/rpm-t1u' > /tmp/rpm-t1u/macros ; \ cp $(PACKAGE)-$(VERSION).tar.gz /tmp/rpm-t1u/SOURCES ; \ rpmbuild --rcfile /tmp/rpm-t1u/rc -bb t1utils.spec ; \ cp /tmp/rpm-t1u/RPMS/$$buildarch/*.rpm . rm -rf /tmp/rpm-t1u .PHONY: srclinks versionize rpm t1utils-1.39/NEWS000066400000000000000000000224761247370226400135740ustar00rootroot00000000000000T1utils NEWS Version 1.39 26.Feb.2015 * t1disasm: Security fixes for buffer overrun reported by Jakub Wilk and Niels Thykier. Version 1.38 29.Sep.2013 * t1disasm: Fix an infinite loop on some fonts reported by Niels Thykier. Version 1.37 29.Jun.2011 * t1asm: Use a dynamically allocated buffer to handle huge characters (reported by Werner Lemberg). Version 1.36 29.May.2010 * Several minor cleanups. Version 1.35 22.Oct.2009 * Don't use "getline" as a symbol (reported by Karl Berry and C.M. Connelly). Version 1.34 1.Mar.2008 * Add '--enable-multiplatform' (requested by Karl Berry). Version 1.33 8.Jan.2008 * Several minor cleanups. Version 1.32 23.Feb.2004 * t1disasm: Avoid memory corruption bug (strings passed to eexec_line are not null terminated). Reported by Werner Lemberg. Version 1.31 8.Feb.2004 * All: Support fonts where the eexec-encrypted portion is binary, and the first ciphertext byte is 0. Reported by Werner Lemberg. Version 1.30 6.Jan.2004 * All: Support fonts, such as those in PostScript files printed by acroread, where "currentfile eexec" is not followed by a newline. Version 1.29 6.Oct.2003 * t1disasm: Support odd fonts where a character is defined on the "/CharStrings" line. Reported by Werner Lemberg. Version 1.28 7.Aug.2003 * Address build problems reported by Nelson H.F. Beebe. Version 1.27 26.Mar.2003 * t1ascii: Add optional warning when output lines are longer than 255 characters. Requested by Werner Lemberg . Version 1.26 16.Apr.2002 * t1mac: Fix buglet (C++ comment, and temporary file left behind). Reported by Vladimir Volovich . Version 1.25 3.Jan.2002 * t1asm: Beware extra characters after `currentfile closefile'. Reported by Luc Devroye . Version 1.24 6.Sep.2001 * Fixed compilation bugs on various platforms reported by Nelson H. F. Beebe . Version 1.23 18.Jun.2001 * Fixed Macintosh file bugs: the MacBinary CRC was calculated incorrectly, and extended finder flags were set to random values in BinHex output. Reported, and patch provided, by Tom Kacvinsky . Version 1.22 6.Mar.2001 * Fixed bug on processing PFA fonts with DOS line endings. The symptom was t1binary producing strange/unusable fonts. Problem: the all-zeros line, which signals the end of the font's binary section, was not being recognized because of an extra '\r'. This has been a bug since version 1.13 -- chagrin! Problem reported by Han The Thanh . Version 1.21 9.Feb.2001 * t1ascii, t1asm, t1unmac: Raised minimum PFA line length to 8. The Adobe spec may imply that there cannot be whitespace within the first 8 bytes of an ASCII-encoded eexec section; it's somewhat ambiguous. Reported by Rainer Menzner . Version 1.20 22.Jun.2000 * t1asm: Fixed bug where `t1asm -a' would give a `warning: line length raised to 4' error message. Reported by Tom Kacvinsky . Version 1.19 3.May.2000 * t1mac: Generated Macintosh fonts now use a custom-drawn icon set, rather than Adobe's default. They also have a t1utils-specific creator signature (T1UT), and their file information mentions t1utils. * t1mac: Added the `--filename' option. Version 1.18 2.May.2000 * t1mac: Fixed bug where generated files appeared corrupted to Macintoshes. Reported by Marten Thavenius . Version 1.17 27.Apr.2000 * Added new program, `t1mac', which translates PFA or PFB fonts into Macintosh-style fonts. T1mac can output in MacBinary, AppleSingle, AppleDouble, or BinHex format. Suggested by Marten Thavenius . * t1unmac: Added support for BinHex. * t1unmac: Fixed bugs in manual page and program options. Version 1.16 25.Apr.2000 * t1unmac: Supports AppleSingle and AppleDouble files with the `--applesingle/double' option. Requested by Kent Boortz . Version 1.15 4.Apr.2000 * t1ascii, t1binary, and t1disasm: Fixed bad error message. * t1unmac: Generates PFB fonts by default. Version 1.14 25.Aug.1999 * t1asm: Version 1.13 produced complete crap output. My test cases were too limited to catch this. Found by Rainer Menzner . Version 1.13 2.Aug.1999 * t1disasm: Complete rewrite. It now uses t1lib.c functions; the goal is to handle PFA and PFB fonts consistently. This has been extensively tested, but there may be bugs. * t1disasm, t1asm: Fixed to support fonts with multiple Subrs and CharStrings sections, like some old Oblique fonts. * PFA minimum line length raised to 4. * t1ascii, t1binary, t1disasm: Changes in t1lib.c to support reading binary PFA fonts. Requested by Tom Kacvinsky . Version 1.12 1.Aug.1999 * t1ascii, t1binary, t1asm, t1disasm: Support fonts with whitespace following the "currentfile eexec" line. Embedded fonts in PostScript generated by Acrobat Reader have this property. Reported by Tom Kacvinsky . * t1ascii, t1asm, t1unmac: Use lowercase hex digits instead of uppercase. * t1unmac: Added `--line-length' option for PFA output. Version 1.11 29.May.1999 * Bug fix in t1asm/t1disasm: if a `readhexstring' procedure was defined, we got confused. Reported by Luc Devroye . * t1binary now has a maximum block length of 2^32 - 1. "Feature" requested by Werner Lemberg . * t1ascii and t1binary each accept both PFA and PFB fonts. If you pass an ASCII font (PFA) to t1ascii, it will output it mostly unchanged, and similarly for PFB fonts and t1binary. The `-l' options will still take effect, so you can use `t1ascii -l 60' to shorten the encrypted line lengths of a PFA font. t1ascii also does some newline translation (changes carriage returns to newlines). Version 1.10.1 12.Apr.1999 * t1asm: Fixed bug when `-l' option wasn't provided. Caught by Giuseppe Ghibò . Version 1.10 11.Apr.1999 * t1asm/t1disasm: Provide support for Type1C (Compact Font Format) font files. These fonts have unencrypted character strings, signalled by a negative lenIV value. Suggestion and patch thanks to Tom Kacvinsky . * t1ascii/t1asm: Added `-l/--line-length' option to control maximum encrypted line length. Suggestion thanks to Giuseppe Ghibò . Version 1.9 14.Feb.1999 * t1asm/t1disasm: Be more robust on fonts that don't end in `mark currentfile closefile'. John Vromans provided a font that ended with `mark' on one line and `currentfile closefile' on another; t1asm and t1disasm did not recognize the encrypted section of the font had ended, and generated some garbage. Version 1.8 2.Jan.1999 * Added some more Type 2 commands (flex, flex1, hflex, hflex1) from a revision of the Type 2 spec. (I wouldn't have known about this except for CurveSoft's revised t1utils package, available at http://www.curvesoft.com. These t1utils are more up-to-date than theirs, however.) * t1asm: Fixed one Type 2 command's translation (cntrmask was incorrectly mapped to 18, not 20). Version 1.7.2 11.Dec.1998 * Integrated patches from Jan-Jaap van der Heijden to support building t1utils under 32-bit Windows. Version 1.7.1 5.Dec.1998 * The t1utils package now uses automake. Version 1.7 27.Nov.1998 * t1asm: Should now work with fonts that have no /Subrs sections. Previously, assembling such a font would silently fail; all the character definitions would be mistaken for procedures and t1asm wouldn't translate them. Problem noticed and fix suggested by Tom Kacvinsky . * t1disasm: Removed spurious debugging output and improved warning message about unknown charstring commands. * Changed fgetc/fputc into getc/putc. Version 1.6 27.Sep.1998 * `--help' now prints to stdout, following the GNU Coding Standards. * Makefiles: Added `make uninstall' target, enabled `./configure's program name transformations, made VPATH builds possible. Version 1.5.2 6.Aug.1998 * t1asm/t1disasm: Changed unknown charstring commands at the request of Werner Lemberg and LEE Chun-Yu. An unknown escape in the charstring, like 12 X, is translated to "escape_X" rather than "UNKNOWN_12_X". Version 1.5.1 31.May.1998 * t1unmac did not actually understand the -r and -b options. Fixed. * t1unmac: Added better diagnostics to help you diagnose seeking problems. Version 1.5 5.Mar.1998 * Initial release with Eddie Kohler as maintainer. * All: Updated to the GNU program behavior standards (long options, --help, --version). Banners removed. Added more error messages. * t1binary: Removed fixed limit on line length. * t1binary: Supports Macintosh files, whose lines end in `\r'. * t1binary: Supports an odd number of hex digits in a line. * t1asm/t1disasm: Added support for Type 2 commands like `blend' and `add', which also appear in some multiple master fonts like Adobe Jenson. * t1asm/t1disasm: Added support for unknown charstring commands. t1disasm translates an unknown command #X to "UNKNOWN_X", and t1asm does the reverse. * t1asm/t1unmac: Changed default output to PFB. * t1unmac: Used to be called `unpost'. `t1unmac' is a much better name. t1utils-1.39/README000066400000000000000000000047451247370226400137540ustar00rootroot00000000000000T1UTILS ======= t1utils is a collection of simple type-1 font manipulation programs. Together, they allow you to convert between PFA (ASCII) and PFB (binary) formats, disassemble PFA or PFB files into human-readable form, reassemble them into PFA or PFB format. Additionally you can extract font resources from a Macintosh font file or create a Macintosh Type 1 font file from a PFA or PFB font. There are currently six programs: t1ascii converts PFB files to PFA format. t1binary converts PFA files to PFB format. t1disasm disassembles a type-1 font (PFA or PFB format) into a raw, human-readable text form for subsequent hand editing, tweaking, hint fixing, etc... t1asm assembles type-1 font into PFA or PFB format from human-readable form produced by t1disasm. t1unmac extracts POST resources from a Macintosh type-1 file (ATM/Laserwriter) into PFA or PFB format for use outside the Macintosh environment. The Macintosh file should be stored in MacBinary, AppleSingle, AppleDouble, or BinHex format, or as a raw resource fork. Note that t1unmac does not have to run on a Macintosh, but makes Macintosh type-1 fonts available to Unix machines and PCs. t1mac creates a Macintosh Type 1 file from a PFA or PFB-format Type 1 font. Writes the Macintosh file in MacBinary, AppleSingle, AppleDouble, or BinHex format, or as a raw resource fork. WARNING: This will not suffice to use the new font on a Macintosh, as Macintoshes cannot read raw Type 1 fonts. You will need to create a font suitcase containing bitmap fonts if you do not have such a suitcase for the font already. T1utils cannot help you do this. Installation ------------ You need an ANSI C compiler, such as gcc. Just type `./configure', then `make'. `make install' will build and install the utilities and their manual pages. `./configure' accepts the usual options. See `INSTALL' for more details. The most commonly used option is `--prefix', which can be used to install the utilities in a place other than /usr/local. Copyright and license --------------------- The original t1utils were (c) 1992 I. Lee Hetherington. Changes since version 1.2 are (c) 1998-2013 Eddie Kohler. Distribution is under the Click LICENSE, a BSD-like license described in the LICENSE file in this directory. Note that these tools should not be used to illegally copy type-1 font programs. Typeface design is an intricate art that should be rewarded. Eddie Kohler ekohler@gmail.com I. Lee Hetherington ilh@lcs.mit.edu t1utils-1.39/bootstrap.sh000077500000000000000000000000321247370226400154310ustar00rootroot00000000000000#! /bin/sh autoreconf -i t1utils-1.39/clp.c000066400000000000000000002051621247370226400140120ustar00rootroot00000000000000/* -*- related-file-name: "../include/lcdf/clp.h" -*- */ /* clp.c - Complete source code for CLP. * This file is part of CLP, the command line parser package. * * Copyright (c) 1997-2012 Eddie Kohler, ekohler@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, subject to the conditions * listed in the Click LICENSE file, which is available in full at * http://www.pdos.lcs.mit.edu/click/license.html. The conditions include: you * must preserve this copyright notice, and you cannot mention the copyright * holders in advertising related to the Software without their permission. * The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This * notice is a summary of the Click LICENSE file; the license in that file is * legally binding. */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include #include #include #include #include /* By default, assume we have strtoul. */ #if !defined(HAVE_STRTOUL) && !defined(HAVE_CONFIG_H) # define HAVE_STRTOUL 1 #endif #ifdef __cplusplus extern "C" { #endif /** @file clp.h * @brief Functions for parsing command line options. * * The CLP functions are used to parse command line arugments into options. * It automatically handles value parsing, error messages, long options with * minimum prefix matching, short options, and negated options. * * The CLP model works like this. * *
    *
  1. The user declares an array of Clp_Option structures that define the * options their program accepts.
  2. *
  3. The user creates a Clp_Parser object using Clp_NewParser(), passing in * the command line arguments to parse and the Clp_Option structures.
  4. *
  5. A loop repeatedly calls Clp_Next() to parse the arguments.
  6. *
* * Unlike many command line parsing libraries, CLP steps through all arguments * one at a time, rather than slurping up all options at once. This makes it * meaningful to give an option more than once. * * Here's an example. * * @code * #define ANIMAL_OPT 1 * #define VEGETABLE_OPT 2 * #define MINERALS_OPT 3 * #define USAGE_OPT 4 * * static const Clp_Option options[] = { * { "animal", 'a', ANIMAL_OPT, Clp_ValString, 0 }, * { "vegetable", 'v', VEGETABLE_OPT, Clp_ValString, Clp_Negate | Clp_Optional }, * { "minerals", 'm', MINERALS_OPT, Clp_ValInt, 0 }, * { "usage", 0, USAGE_OPT, 0, 0 } * }; * * int main(int argc, char *argv[]) { * Clp_Parser *clp = Clp_NewParser(argc, argv, * sizeof(options) / sizeof(options[0]), options); * int opt; * while ((opt = Clp_Next(clp)) != Clp_Done) * switch (opt) { * case ANIMAL_OPT: * fprintf(stderr, "animal is %s\n", clp->val.s); * break; * case VEGETABLE_OPT: * if (clp->negated) * fprintf(stderr, "no vegetables!\n"); * else if (clp->have_val) * fprintf(stderr, "vegetable is %s\n", clp->val.s); * else * fprintf(stderr, "vegetables OK\n"); * break; * case MINERALS_OPT: * fprintf(stderr, "%d minerals\n", clp->val.i); * break; * case USAGE_OPT: * fprintf(stderr, "Usage: 20q [--animal=ANIMAL] [--vegetable[=VEGETABLE]] [--minerals=N]\n"); * break; * case Clp_NotOption: * fprintf(stderr, "non-option %s\n", clp->vstr); * break; * } * } * } * @endcode * * Here are a couple of executions. * *
 * % ./20q --animal=cat
 * animal is cat
 * % ./20q --animal=cat -a dog -afish --animal bird --an=snake
 * animal is cat
 * animal is dog
 * animal is fish
 * animal is bird
 * animal is snake
 * % ./20q --no-vegetables
 * no vegetables!
 * % ./20q -v
 * vegetables OK
 * % ./20q -vkale
 * vegetable is kale
 * % ./20q -m10
 * 10 minerals
 * % ./20q -m foo
 * '-m' expects an integer, not 'foo'
 * 
*/ /* Option types for Clp_SetOptionChar */ #define Clp_DoubledLong (Clp_LongImplicit * 2) #define Clp_InitialValType 8 #define MAX_AMBIGUOUS_VALUES 4 typedef struct { int val_type; Clp_ValParseFunc func; int flags; void *user_data; } Clp_ValType; typedef struct { unsigned ilong : 1; unsigned ishort : 1; unsigned imandatory : 1; unsigned ioptional : 1; unsigned ipos : 1; unsigned ineg : 1; unsigned iprefmatch : 1; unsigned lmmpos_short : 1; unsigned lmmneg_short : 1; unsigned char ilongoff; int lmmpos; int lmmneg; } Clp_InternOption; #define Clp_OptionCharsSize 5 typedef struct { int c; int type; } Clp_Oclass; #define Clp_OclassSize 10 typedef struct Clp_Internal { const Clp_Option *opt; Clp_InternOption *iopt; int nopt; unsigned opt_generation; Clp_ValType *valtype; int nvaltype; const char * const *argv; int argc; Clp_Oclass oclass[Clp_OclassSize]; int noclass; int long1pos; int long1neg; int utf8; char option_chars[Clp_OptionCharsSize]; const char *xtext; const char *program_name; void (*error_handler)(Clp_Parser *, const char *); int option_processing; int current_option; unsigned char is_short; unsigned char whole_negated; /* true if negated by an option character */ unsigned char could_be_short; unsigned char current_short; unsigned char negated_by_no; int ambiguous; int ambiguous_values[MAX_AMBIGUOUS_VALUES]; } Clp_Internal; struct Clp_ParserState { const char * const *argv; int argc; char option_chars[Clp_OptionCharsSize]; const char *xtext; int option_processing; unsigned opt_generation; int current_option; unsigned char is_short; unsigned char whole_negated; unsigned char current_short; unsigned char negated_by_no; }; typedef struct Clp_StringList { Clp_Option *items; Clp_InternOption *iopt; int nitems; int allow_int; int nitems_invalid_report; } Clp_StringList; static int parse_string(Clp_Parser *, const char *, int, void *); static int parse_int(Clp_Parser *, const char *, int, void *); static int parse_bool(Clp_Parser *, const char *, int, void *); static int parse_double(Clp_Parser *, const char *, int, void *); static int parse_string_list(Clp_Parser *, const char *, int, void *); static int ambiguity_error(Clp_Parser *, int, int *, const Clp_Option *, const Clp_InternOption *, const char *, const char *, ...); /******* * utf8 **/ #define U_REPLACEMENT 0xFFFD static char * encode_utf8(char *s, int n, int c) { if (c < 0 || c >= 0x110000 || (c >= 0xD800 && c <= 0xDFFF)) c = U_REPLACEMENT; if (c <= 0x7F && n >= 1) *s++ = c; else if (c <= 0x7FF && n >= 2) { *s++ = 0xC0 | (c >> 6); goto char1; } else if (c <= 0xFFFF && n >= 3) { *s++ = 0xE0 | (c >> 12); goto char2; } else if (n >= 4) { *s++ = 0xF0 | (c >> 18); *s++ = 0x80 | ((c >> 12) & 0x3F); char2: *s++ = 0x80 | ((c >> 6) & 0x3F); char1: *s++ = 0x80 | (c & 0x3F); } return s; } static int decode_utf8(const char *s, const char **cp) { int c; if ((unsigned char) *s <= 0x7F) /* 1 byte: 0x000000-0x00007F */ c = *s++; else if ((unsigned char) *s <= 0xC1) /* bad/overlong encoding */ goto replacement; else if ((unsigned char) *s <= 0xDF) { /* 2 bytes: 0x000080-0x0007FF */ if ((s[1] & 0xC0) != 0x80) /* bad encoding */ goto replacement; c = (*s++ & 0x1F) << 6; goto char1; } else if ((unsigned char) *s <= 0xEF) { /* 3 bytes: 0x000800-0x00FFFF */ if ((s[1] & 0xC0) != 0x80 /* bad encoding */ || (s[2] & 0xC0) != 0x80 /* bad encoding */ || ((unsigned char) *s == 0xE0 /* overlong encoding */ && (s[1] & 0xE0) == 0x80) || ((unsigned char) *s == 0xED /* encoded surrogate */ && (s[1] & 0xE0) == 0xA0)) goto replacement; c = (*s++ & 0x0F) << 12; goto char2; } else if ((unsigned char) *s <= 0xF4) { /* 4 bytes: 0x010000-0x10FFFF */ if ((s[1] & 0xC0) != 0x80 /* bad encoding */ || (s[2] & 0xC0) != 0x80 /* bad encoding */ || (s[3] & 0xC0) != 0x80 /* bad encoding */ || ((unsigned char) *s == 0xF0 /* overlong encoding */ && (s[1] & 0xF0) == 0x80) || ((unsigned char) *s == 0xF4 /* encoded value > 0x10FFFF */ && (unsigned char) s[1] >= 0x90)) goto replacement; c = (*s++ & 0x07) << 18; c += (*s++ & 0x3F) << 12; char2: c += (*s++ & 0x3F) << 6; char1: c += (*s++ & 0x3F); } else { replacement: c = U_REPLACEMENT; for (s++; (*s & 0xC0) == 0x80; s++) /* nothing */; } if (cp) *cp = s; return c; } static int utf8_charlen(const char *s) { const char *sout; (void) decode_utf8(s, &sout); return sout - s; } static int clp_utf8_charlen(const Clp_Internal *cli, const char *s) { return (cli->utf8 ? utf8_charlen(s) : 1); } /******* * Clp_NewParser, etc. **/ static int min_different_chars(const char *s, const char *t) /* Returns the minimum number of bytes required to distinguish s from t. If s is shorter than t, returns strlen(s). */ { const char *sfirst = s; while (*s && *t && *s == *t) s++, t++; if (!*s) return s - sfirst; else return s - sfirst + 1; } static int long_as_short(const Clp_Internal *cli, const Clp_Option *o, Clp_InternOption *io, int failure) { if ((cli->long1pos || cli->long1neg) && io->ilong) { const char *name = o->long_name + io->ilongoff; if (cli->utf8) { int c = decode_utf8(name, &name); if (!*name && c && c != U_REPLACEMENT) return c; } else if (name[0] && !name[1]) return (unsigned char) name[0]; } return failure; } static void compare_options(Clp_Parser *clp, const Clp_Option *o1, Clp_InternOption *io1, const Clp_Option *o2, Clp_InternOption *io2) { Clp_Internal *cli = clp->internal; int short1, shortx1; /* ignore meaningless combinations */ if ((!io1->ishort && !io1->ilong) || (!io2->ishort && !io2->ilong) || !((io1->ipos && io2->ipos) || (io1->ineg && io2->ineg)) || o1->option_id == o2->option_id) return; /* look for duplication of short options */ short1 = (io1->ishort ? o1->short_name : -1); shortx1 = long_as_short(cli, o1, io1, -2); if (short1 >= 0 || shortx1 >= 0) { int short2 = (io2->ishort ? o2->short_name : -3); int shortx2 = long_as_short(cli, o2, io2, -4); if (short1 == short2) Clp_OptionError(clp, "CLP internal error: more than 1 option has short name %<%c%>", short1); else if ((short1 == shortx2 || shortx1 == short2 || shortx1 == shortx2) && ((io1->ipos && io2->ipos && cli->long1pos) || (io1->ineg && io2->ineg && cli->long1neg))) Clp_OptionError(clp, "CLP internal error: 1-char long name conflicts with short name %<%c%>", (short1 == shortx2 ? shortx2 : shortx1)); } /* analyze longest minimum match */ if (io1->ilong) { const char *name1 = o1->long_name + io1->ilongoff; /* long name's first character matches short name */ if (io2->ishort && !io1->iprefmatch) { int name1char = (cli->utf8 ? decode_utf8(name1, 0) : (unsigned char) *name1); if (name1char == o2->short_name) { if (io1->ipos && io2->ipos) io1->lmmpos_short = 1; if (io1->ineg && io2->ineg) io1->lmmneg_short = 1; } } /* match long name to long name */ if (io2->ilong) { const char *name2 = o2->long_name + io2->ilongoff; if (strcmp(name1, name2) == 0) Clp_OptionError(clp, "CLP internal error: duplicate long name %<%s%>", name1); if (io1->ipos && io2->ipos && !strncmp(name1, name2, io1->lmmpos) && (!io1->iprefmatch || strncmp(name1, name2, strlen(name1)))) io1->lmmpos = min_different_chars(name1, name2); if (io1->ineg && io2->ineg && !strncmp(name1, name2, io1->lmmneg) && (!io1->iprefmatch || strncmp(name1, name2, strlen(name1)))) io1->lmmneg = min_different_chars(name1, name2); } } } /** @param argc number of arguments * @param argv argument array * @param nopt number of option definitions * @param opt option definition array * @return the parser * * The new Clp_Parser that will parse the arguments in @a argv according to * the option definitions in @a opt. * * The Clp_Parser is created with the following characteristics: * *
    *
  • The "-" character introduces short options (Clp_SetOptionChar(clp, * '-', Clp_Short)).
  • *
  • Clp_ProgramName is set from the first argument in @a argv, if any. The * first argument returned by Clp_Next() will be the second argument in @a * argv. Note that this behavior differs from Clp_SetArguments.
  • *
  • UTF-8 support is on iff the LANG environment variable contains * one of the substrings "UTF-8", "UTF8", or "utf8". Override this with * Clp_SetUTF8().
  • *
  • The Clp_ValString, Clp_ValStringNotOption, Clp_ValInt, Clp_ValUnsigned, * Clp_ValBool, and Clp_ValDouble types are installed.
  • *
  • Errors are reported to standard error.
  • *
* * You may also create a Clp_Parser with no arguments or options * (Clp_NewParser(0, 0, 0, 0)) and set the arguments and options * later. * * Returns NULL if there isn't enough memory to construct the parser. * * @note The CLP library will not modify the contents of @a argv or @a opt. * The calling program must not modify @a opt. It may modify @a argv in * limited cases. */ Clp_Parser * Clp_NewParser(int argc, const char * const *argv, int nopt, const Clp_Option *opt) { Clp_Parser *clp = (Clp_Parser *)malloc(sizeof(Clp_Parser)); Clp_Internal *cli = (Clp_Internal *)malloc(sizeof(Clp_Internal)); Clp_InternOption *iopt = (Clp_InternOption *)malloc(sizeof(Clp_InternOption) * nopt); if (cli) cli->valtype = (Clp_ValType *)malloc(sizeof(Clp_ValType) * Clp_InitialValType); if (!clp || !cli || !iopt || !cli->valtype) goto failed; clp->opt = -1; clp->negated = 0; clp->have_val = 0; clp->vstr = 0; clp->user_data = 0; clp->internal = cli; cli->opt = opt; cli->nopt = nopt; cli->iopt = iopt; cli->opt_generation = 0; cli->error_handler = 0; /* Assign program name (now so we can call Clp_OptionError) */ if (argc > 0) { const char *slash = strrchr(argv[0], '/'); cli->program_name = slash ? slash + 1 : argv[0]; } else cli->program_name = 0; /* Assign arguments, skipping program name */ Clp_SetArguments(clp, argc - 1, argv + 1); /* Initialize UTF-8 status and option classes */ { char *s = getenv("LANG"); cli->utf8 = (s && (strstr(s, "UTF-8") != 0 || strstr(s, "UTF8") != 0 || strstr(s, "utf8") != 0)); } cli->oclass[0].c = '-'; cli->oclass[0].type = Clp_Short; cli->noclass = 1; cli->long1pos = cli->long1neg = 0; /* Add default type parsers */ cli->nvaltype = 0; Clp_AddType(clp, Clp_ValString, 0, parse_string, 0); Clp_AddType(clp, Clp_ValStringNotOption, Clp_DisallowOptions, parse_string, 0); Clp_AddType(clp, Clp_ValInt, 0, parse_int, 0); Clp_AddType(clp, Clp_ValUnsigned, 0, parse_int, (void *)cli); Clp_AddType(clp, Clp_ValBool, 0, parse_bool, 0); Clp_AddType(clp, Clp_ValDouble, 0, parse_double, 0); /* Set options */ Clp_SetOptions(clp, nopt, opt); return clp; failed: if (cli && cli->valtype) free(cli->valtype); if (cli) free(cli); if (clp) free(clp); if (iopt) free(iopt); return 0; } /** @param clp the parser * * All memory associated with @a clp is freed. */ void Clp_DeleteParser(Clp_Parser *clp) { int i; Clp_Internal *cli; if (!clp) return; cli = clp->internal; /* get rid of any string list types */ for (i = 0; i < cli->nvaltype; i++) if (cli->valtype[i].func == parse_string_list) { Clp_StringList *clsl = (Clp_StringList *)cli->valtype[i].user_data; free(clsl->items); free(clsl->iopt); free(clsl); } free(cli->valtype); free(cli->iopt); free(cli); free(clp); } /** @param clp the parser * @param errh error handler function * @return previous error handler function * * The error handler function is called when CLP encounters an error while * parsing the command line. It is called with the arguments "(*errh)(@a * clp, s)", where s is a description of the error terminated by * a newline. The s descriptions produced by CLP itself are prefixed * by the program name, if any. */ Clp_ErrorHandler Clp_SetErrorHandler(Clp_Parser *clp, void (*errh)(Clp_Parser *, const char *)) { Clp_Internal *cli = clp->internal; Clp_ErrorHandler old = cli->error_handler; cli->error_handler = errh; return old; } /** @param clp the parser * @param utf8 does the parser support UTF-8? * @return previous UTF-8 mode * * In UTF-8 mode, all input strings (arguments and long names for options) are * assumed to be encoded via UTF-8, and all character names * (Clp_SetOptionChar() and short names for options) may cover the whole * Unicode range. Out of UTF-8 mode, all input strings are treated as binary, * and all character names must be unsigned char values. * * Furthermore, error messages in UTF-8 mode may contain Unicode quote * characters. */ int Clp_SetUTF8(Clp_Parser *clp, int utf8) { Clp_Internal *cli = clp->internal; int i, j, old_utf8 = cli->utf8; cli->utf8 = utf8; for (i = 0; i < cli->nopt; ++i) { cli->iopt[i].lmmpos = cli->iopt[i].lmmneg = 1; cli->iopt[i].lmmpos_short = cli->iopt[i].lmmneg_short = 0; for (j = 0; j < cli->nopt; ++j) compare_options(clp, &cli->opt[i], &cli->iopt[i], &cli->opt[j], &cli->iopt[j]); } return old_utf8; } /** @param clp the parser * @param c character * @return option character treatment * * Returns an integer specifying how CLP treats arguments that begin * with character @a c. See Clp_SetOptionChar for possibilities. */ int Clp_OptionChar(Clp_Parser *clp, int c) { Clp_Internal *cli = clp->internal; int i, oclass = 0; if (cli->noclass > 0 && cli->oclass[0].c == 0) oclass = cli->oclass[0].type; for (i = 0; i < cli->noclass; ++i) if (cli->oclass[i].c == c) oclass = cli->oclass[i].type; return oclass; } /** @param clp the parser * @param c character * @param type option character treatment * @return previous option character treatment, or -1 on error * * @a type specifies how CLP treats arguments that begin with character @a c. * Possibilities are: * *
*
Clp_NotOption (or 0)
*
The argument cannot be an option.
*
Clp_Long
*
The argument is a long option.
*
Clp_Short
*
The argument is a set of short options.
*
Clp_Short|Clp_Long
*
The argument is either a long option or, if no matching long option is * found, a set of short options.
*
Clp_LongNegated
*
The argument is a negated long option. For example, after * Clp_SetOptionChar(@a clp, '^', Clp_LongNegated), the argument "^foo" is * equivalent to "--no-foo".
*
Clp_ShortNegated
*
The argument is a set of negated short options.
*
Clp_ShortNegated|Clp_LongNegated
*
The argument is either a negated long option or, if no matching long * option is found, a set of negated short options.
*
Clp_LongImplicit
*
The argument may be a long option, where the character @a c is actually * part of the long option name. For example, after Clp_SetOptionChar(@a clp, * 'f', Clp_LongImplicit), the argument "foo" may be equivalent to * "--foo".
*
* * In UTF-8 mode, @a c may be any Unicode character. Otherwise, @a c must be * an unsigned char value. The special character 0 assigns @a type to @em * every character. * * It is an error if @a c is out of range, @a type is illegal, or there are * too many character definitions stored in @a clp already. The function * returns -1 on error. * * A double hyphen "--" always introduces a long option. This behavior cannot * currently be changed with Clp_SetOptionChar(). */ int Clp_SetOptionChar(Clp_Parser *clp, int c, int type) { int i, j, long1pos, long1neg; int old = Clp_OptionChar(clp, c); Clp_Internal *cli = clp->internal; if (type != Clp_NotOption && type != Clp_Short && type != Clp_Long && type != Clp_ShortNegated && type != Clp_LongNegated && type != Clp_LongImplicit && type != (Clp_Short | Clp_Long) && type != (Clp_ShortNegated | Clp_LongNegated)) return -1; if (c < 0 || c >= (cli->utf8 ? 0x110000 : 256)) return -1; if (c == 0) cli->noclass = 0; for (i = 0; i < cli->noclass; ++i) if (cli->oclass[i].c == c) break; if (i == Clp_OclassSize) return -1; cli->oclass[i].c = c; cli->oclass[i].type = type; if (cli->noclass == i) cli->noclass = i + 1; long1pos = long1neg = 0; for (i = 0; i < cli->noclass; ++i) { if ((cli->oclass[i].type & Clp_Short) && (cli->oclass[i].type & Clp_Long)) long1pos = 1; if ((cli->oclass[i].type & Clp_ShortNegated) && (cli->oclass[i].type & Clp_LongNegated)) long1neg = 1; } if (long1pos != cli->long1pos || long1neg != cli->long1neg) { /* Must recheck option set */ cli->long1pos = long1pos; cli->long1neg = long1neg; for (i = 0; i < cli->nopt; ++i) { cli->iopt[i].lmmpos = cli->iopt[i].lmmneg = 1; cli->iopt[i].lmmpos_short = cli->iopt[i].lmmneg_short = 0; for (j = 0; j < cli->nopt; ++j) compare_options(clp, &cli->opt[i], &cli->iopt[i], &cli->opt[j], &cli->iopt[j]); } } return old; } /** @param clp the parser * @param nopt number of option definitions * @param opt option definition array * @return 0 on success, -1 on failure * * Installs the option definitions in @a opt. Future option parsing will * use @a opt to search for options. * * Also checks @a opt's option definitions for validity. "CLP internal * errors" are reported via Clp_OptionError() if: * *
    *
  • An option has a negative ID.
  • *
  • Two different short options have the same name.
  • *
  • Two different long options have the same name.
  • *
  • A short and a long option are ambiguous, in that some option character * might introduce either a short or a long option (e.g., Clp_SetOptionChar(@a * clp, '-', Clp_Long|Clp_Short)), and a short name equals a long name.
  • *
* * If necessary memory cannot be allocated, this function returns -1 without * modifying the parser. * * @note The CLP library will not modify the contents of @a argv or @a opt. * The calling program must not modify @a opt either until another call to * Clp_SetOptions() or the parser is destroyed. */ int Clp_SetOptions(Clp_Parser *clp, int nopt, const Clp_Option *opt) { Clp_Internal *cli = clp->internal; Clp_InternOption *iopt; int i, j; static unsigned opt_generation = 0; if (nopt > cli->nopt) { iopt = (Clp_InternOption *)malloc(sizeof(Clp_InternOption) * nopt); if (!iopt) return -1; free(cli->iopt); cli->iopt = iopt; } cli->opt = opt; cli->nopt = nopt; cli->opt_generation = ++opt_generation; iopt = cli->iopt; cli->current_option = -1; /* Massage the options to make them usable */ for (i = 0; i < nopt; i++) { /* Ignore negative option_ids, which are internal to CLP */ if (opt[i].option_id < 0) { Clp_OptionError(clp, "CLP internal error: option %d has negative option_id", i); iopt[i].ilong = iopt[i].ishort = iopt[i].ipos = iopt[i].ineg = 0; continue; } /* Set flags based on input flags */ iopt[i].ilong = (opt[i].long_name != 0 && opt[i].long_name[0] != 0); iopt[i].ishort = (opt[i].short_name > 0 && opt[i].short_name < (cli->utf8 ? 0x110000 : 256)); iopt[i].ipos = 1; iopt[i].ineg = (opt[i].flags & Clp_Negate) != 0; iopt[i].imandatory = (opt[i].flags & Clp_Mandatory) != 0; iopt[i].ioptional = (opt[i].flags & Clp_Optional) != 0; iopt[i].iprefmatch = (opt[i].flags & Clp_PreferredMatch) != 0; iopt[i].ilongoff = 0; /* Enforce invariants */ if (opt[i].val_type <= 0) iopt[i].imandatory = iopt[i].ioptional = 0; if (opt[i].val_type > 0 && !iopt[i].ioptional) iopt[i].imandatory = 1; /* Options that start with 'no-' should be changed to OnlyNegated */ if (iopt[i].ilong && strncmp(opt[i].long_name, "no-", 3) == 0) { iopt[i].ipos = 0; iopt[i].ineg = 1; iopt[i].ilongoff = 3; if (strncmp(opt[i].long_name + 3, "no-", 3) == 0) Clp_OptionError(clp, "CLP internal error: option %d begins with \"no-no-\"", i); } else if (opt[i].flags & Clp_OnlyNegated) { iopt[i].ipos = 0; iopt[i].ineg = 1; } } /* Check option set */ for (i = 0; i < nopt; ++i) { iopt[i].lmmpos = iopt[i].lmmneg = 1; iopt[i].lmmpos_short = iopt[i].lmmneg_short = 0; for (j = 0; j < nopt; ++j) compare_options(clp, &opt[i], &iopt[i], &opt[j], &iopt[j]); } return 0; } /** @param clp the parser * @param argc number of arguments * @param argv argument array * * Installs the arguments in @a argv for parsing. Future option parsing will * analyze @a argv. * * Unlike Clp_NewParser(), this function does not treat @a argv[0] specially. * The first subsequent call to Clp_Next() will analyze @a argv[0]. * * This function also sets option processing to on, as by * Clp_SetOptionProcessing(@a clp, 1). * * @note The CLP library will not modify the contents of @a argv. The calling * program should not generally modify the element of @a argv that CLP is * currently analyzing. */ void Clp_SetArguments(Clp_Parser *clp, int argc, const char * const *argv) { Clp_Internal *cli = clp->internal; cli->argc = argc + 1; cli->argv = argv - 1; cli->is_short = 0; cli->whole_negated = 0; cli->option_processing = 1; cli->current_option = -1; } /** @param clp the parser * @param on whether to search for options * @return previous option processing setting * * When option processing is off, every call to Clp_Next() returns * Clp_NotOption. By default the option "--" turns off option * processing and is otherwise ignored. */ int Clp_SetOptionProcessing(Clp_Parser *clp, int on) { Clp_Internal *cli = clp->internal; int old = cli->option_processing; cli->option_processing = on; return old; } /******* * functions for Clp_Option lists **/ /* the ever-glorious argcmp */ static int argcmp(const char *ref, const char *arg, int min_match, int fewer_dashes) /* Returns 0 if ref and arg don't match. Returns -1 if ref and arg match, but fewer than min_match characters. Returns len if ref and arg match min_match or more characters; len is the number of characters that matched in arg. Allows arg to contain fewer dashes than ref iff fewer_dashes != 0. Examples: argcmp("x", "y", 1, 0) --> 0 / just plain wrong argcmp("a", "ax", 1, 0) --> 0 / ...even though min_match == 1 and the 1st chars match argcmp("box", "bo", 3, 0) --> -1 / ambiguous argcmp("cat", "c=3", 1, 0) --> 1 / handles = arguments */ { const char *refstart = ref; const char *argstart = arg; assert(min_match > 0); compare: while (*ref && *arg && *arg != '=' && *ref == *arg) ref++, arg++; /* Allow arg to contain fewer dashes than ref */ if (fewer_dashes && *ref == '-' && ref[1] && ref[1] == *arg) { ref++; goto compare; } if (*arg && *arg != '=') return 0; else if (ref - refstart < min_match) return -1; else return arg - argstart; } static int find_prefix_opt(Clp_Parser *clp, const char *arg, int nopt, const Clp_Option *opt, const Clp_InternOption *iopt, int *ambiguous, int *ambiguous_values) /* Looks for an unambiguous match of 'arg' against one of the long options in 'opt'. Returns positive if it finds one; otherwise, returns -1 and possibly changes 'ambiguous' and 'ambiguous_values' to keep track of at most MAX_AMBIGUOUS_VALUES possibilities. */ { int i, fewer_dashes = 0, first_ambiguous = *ambiguous; int negated = clp && clp->negated; int first_charlen = (clp ? clp_utf8_charlen(clp->internal, arg) : 1); retry: for (i = 0; i < nopt; i++) { int len, lmm; if (!iopt[i].ilong || (negated ? !iopt[i].ineg : !iopt[i].ipos)) continue; lmm = (negated ? iopt[i].lmmneg : iopt[i].lmmpos); if (clp && clp->internal->could_be_short && (negated ? iopt[i].lmmneg_short : iopt[i].lmmpos_short)) lmm = (first_charlen >= lmm ? first_charlen + 1 : lmm); len = argcmp(opt[i].long_name + iopt[i].ilongoff, arg, lmm, fewer_dashes); if (len > 0) return i; else if (len < 0) { if (*ambiguous < MAX_AMBIGUOUS_VALUES) ambiguous_values[*ambiguous] = i; (*ambiguous)++; } } /* If there were no partial matches, try again with fewer_dashes true */ if (*ambiguous == first_ambiguous && !fewer_dashes) { fewer_dashes = 1; goto retry; } return -1; } /***** * Argument parsing **/ static int val_type_binsearch(Clp_Internal *cli, int val_type) { unsigned l = 0, r = cli->nvaltype; while (l < r) { unsigned m = l + (r - l) / 2; if (cli->valtype[m].val_type == val_type) return m; else if (cli->valtype[m].val_type < val_type) l = m + 1; else r = m; } return l; } /** @param clp the parser * @param val_type value type ID * @param flags value type flags * @param parser parser function * @param user_data user data for @a parser function * @return 0 on success, -1 on failure * * Defines argument type @a val_type in parser @a clp. The parsing function * @a parser will be passed argument values for type @a val_type. It should * parse the argument into values (usually in @a clp->val, but sometimes * elsewhere), report errors if necessary, and return whether the parse was * successful. * * Any prior argument parser match @a val_type is removed. @a val_type must * be greater than zero. * * @a flags specifies additional parsing flags. At the moment the only * relevant flag is Clp_DisallowOptions, which means that separated values * must not look like options. For example, assume argument * --a/-a has mandatory value type Clp_ValStringNotOption * (which has Clp_DisallowOptions). Then: * *
    *
  • --a=--b will parse with value --b.
  • *
  • -a--b will parse with value --b.
  • *
  • --a --b will not parse, since the mandatory value looks like * an option.
  • *
  • -a --b will not parse, since the mandatory value looks like * an option.
  • *
*/ int Clp_AddType(Clp_Parser *clp, int val_type, int flags, Clp_ValParseFunc parser, void *user_data) { Clp_Internal *cli = clp->internal; int vtpos; if (val_type <= 0 || !parser) return -1; vtpos = val_type_binsearch(cli, val_type); if (vtpos == cli->nvaltype || cli->valtype[vtpos].val_type != val_type) { if (cli->nvaltype != 0 && (cli->nvaltype % Clp_InitialValType) == 0) { Clp_ValType *new_valtype = (Clp_ValType *) realloc(cli->valtype, sizeof(Clp_ValType) * (cli->nvaltype + Clp_InitialValType)); if (!new_valtype) return -1; cli->valtype = new_valtype; } memmove(&cli->valtype[vtpos + 1], &cli->valtype[vtpos], sizeof(Clp_ValType) * (cli->nvaltype - vtpos)); cli->nvaltype++; cli->valtype[vtpos].func = 0; } if (cli->valtype[vtpos].func == parse_string_list) { Clp_StringList *clsl = (Clp_StringList *) cli->valtype[vtpos].user_data; free(clsl->items); free(clsl->iopt); free(clsl); } cli->valtype[vtpos].val_type = val_type; cli->valtype[vtpos].func = parser; cli->valtype[vtpos].flags = flags; cli->valtype[vtpos].user_data = user_data; return 0; } /******* * Default argument parsers **/ static int parse_string(Clp_Parser *clp, const char *arg, int complain, void *user_data) { (void)complain, (void)user_data; clp->val.s = arg; return 1; } static int parse_int(Clp_Parser *clp, const char *arg, int complain, void *user_data) { const char *val; if (*arg == 0 || isspace((unsigned char) *arg) || (user_data != 0 && *arg == '-')) val = arg; else if (user_data != 0) { /* unsigned */ #if HAVE_STRTOUL clp->val.u = strtoul(arg, (char **) &val, 0); #else /* don't bother really trying to do it right */ if (arg[0] == '-') val = arg; else clp->val.u = strtol(arg, (char **) &val, 0); #endif } else clp->val.i = strtol(arg, (char **) &val, 0); if (*arg != 0 && *val == 0) return 1; else if (complain) { const char *message = user_data != 0 ? "%<%O%> expects a nonnegative integer, not %<%s%>" : "%<%O%> expects an integer, not %<%s%>"; return Clp_OptionError(clp, message, arg); } else return 0; } static int parse_double(Clp_Parser *clp, const char *arg, int complain, void *user_data) { const char *val; (void)user_data; if (*arg == 0 || isspace((unsigned char) *arg)) val = arg; else clp->val.d = strtod(arg, (char **) &val); if (*arg != 0 && *val == 0) return 1; else if (complain) return Clp_OptionError(clp, "%<%O%> expects a real number, not %<%s%>", arg); else return 0; } static int parse_bool(Clp_Parser *clp, const char *arg, int complain, void *user_data) { int i; char lcarg[6]; (void)user_data; if (strlen(arg) > 5 || strchr(arg, '=') != 0) goto error; for (i = 0; arg[i] != 0; i++) lcarg[i] = tolower((unsigned char) arg[i]); lcarg[i] = 0; if (argcmp("yes", lcarg, 1, 0) > 0 || argcmp("true", lcarg, 1, 0) > 0 || argcmp("1", lcarg, 1, 0) > 0) { clp->val.i = 1; return 1; } else if (argcmp("no", lcarg, 1, 0) > 0 || argcmp("false", lcarg, 1, 0) > 0 || argcmp("1", lcarg, 1, 0) > 0) { clp->val.i = 0; return 1; } error: if (complain) Clp_OptionError(clp, "%<%O%> expects a true-or-false value, not %<%s%>", arg); return 0; } /***** * Clp_AddStringListType **/ static int parse_string_list(Clp_Parser *clp, const char *arg, int complain, void *user_data) { Clp_StringList *sl = (Clp_StringList *)user_data; int idx, ambiguous = 0; int ambiguous_values[MAX_AMBIGUOUS_VALUES + 1]; /* actually look for a string value */ idx = find_prefix_opt (0, arg, sl->nitems, sl->items, sl->iopt, &ambiguous, ambiguous_values); if (idx >= 0) { clp->val.i = sl->items[idx].option_id; return 1; } if (sl->allow_int) { if (parse_int(clp, arg, 0, 0)) return 1; } if (complain) { const char *complaint; if (ambiguous) complaint = "ambiguous value %<%s%> for option %<%O%>"; else { complaint = "unknown value %<%s%> for option %<%O%>"; ambiguous = sl->nitems_invalid_report; for (idx = 0; idx < ambiguous; idx++) ambiguous_values[idx] = idx; } return ambiguity_error (clp, ambiguous, ambiguous_values, sl->items, sl->iopt, "", complaint, arg); } else return 0; } static int finish_string_list(Clp_Parser *clp, int val_type, int flags, Clp_Option *items, int nitems, int itemscap) { int i, j; Clp_StringList *clsl = (Clp_StringList *)malloc(sizeof(Clp_StringList)); Clp_InternOption *iopt = (Clp_InternOption *)malloc(sizeof(Clp_InternOption) * nitems); if (!clsl || !iopt) goto error; clsl->items = items; clsl->iopt = iopt; clsl->nitems = nitems; clsl->allow_int = (flags & Clp_AllowNumbers) != 0; if (nitems < MAX_AMBIGUOUS_VALUES && nitems < itemscap && clsl->allow_int) { items[nitems].long_name = "any integer"; clsl->nitems_invalid_report = nitems + 1; } else if (nitems > MAX_AMBIGUOUS_VALUES + 1) clsl->nitems_invalid_report = MAX_AMBIGUOUS_VALUES + 1; else clsl->nitems_invalid_report = nitems; for (i = 0; i < nitems; i++) { iopt[i].ilong = iopt[i].ipos = 1; iopt[i].ishort = iopt[i].ineg = iopt[i].ilongoff = iopt[i].iprefmatch = 0; iopt[i].lmmpos = 1; iopt[i].lmmpos_short = 0; } for (i = 0; i < nitems; i++) for (j = 0; j < nitems; j++) compare_options(clp, &items[i], &iopt[i], &items[j], &iopt[j]); if (Clp_AddType(clp, val_type, 0, parse_string_list, clsl) >= 0) return 0; error: if (clsl) free(clsl); if (iopt) free(iopt); return -1; } /** @param clp the parser * @param val_type value type ID * @param flags string list flags * @return 0 on success, -1 on failure * * Defines argument type @a val_type in parser @a clp. The parsing function * sets @a clp->val.i to an integer. The value string is matched against * strings provided in the ellipsis arguments. For example, the * Clp_AddStringListType() call below has the same effect as the * Clp_AddStringListTypeVec() call: * * For example: * @code * Clp_AddStringListType(clp, 100, Clp_AllowNumbers, "cat", 1, * "cattle", 2, "dog", 3, (const char *) NULL); * * const char * const strs[] = { "cat", "cattle", "dog" }; * const int vals[] = { 1, 2, 3 }; * Clp_AddStringListTypeVec(clp, 100, Clp_AllowNumbers, 3, strs, vals); * @endcode * * @note The CLP library will not modify any of the passed-in strings. The * calling program must not modify or free them either until the parser is * destroyed. */ int Clp_AddStringListType(Clp_Parser *clp, int val_type, int flags, ...) { int nitems = 0; int itemscap = 5; Clp_Option *items = (Clp_Option *)malloc(sizeof(Clp_Option) * itemscap); va_list val; va_start(val, flags); if (!items) goto error; /* slurp up the arguments */ while (1) { int value; char *name = va_arg(val, char *); if (!name) break; value = va_arg(val, int); if (nitems >= itemscap) { Clp_Option *new_items; itemscap *= 2; new_items = (Clp_Option *)realloc(items, sizeof(Clp_Option) * itemscap); if (!new_items) goto error; items = new_items; } items[nitems].long_name = name; items[nitems].option_id = value; items[nitems].flags = 0; nitems++; } va_end(val); if (finish_string_list(clp, val_type, flags, items, nitems, itemscap) >= 0) return 0; error: va_end(val); if (items) free(items); return -1; } /** @param clp the parser * @param val_type value type ID * @param flags string list flags * @param nstrs number of strings in list * @param strs array of strings * @param vals array of values * @return 0 on success, -1 on failure * * Defines argument type @a val_type in parser @a clp. The parsing function * sets @a clp->val.i to an integer. The value string is matched against the * @a strs. If there's a unique match, the corresponding entry from @a vals * is returned. Unique prefix matches also work. Finally, if @a flags * contains the Clp_AllowNumbers flag, then integers are also accepted. * * For example: * @code * const char * const strs[] = { "cat", "cattle", "dog" }; * const int vals[] = { 1, 2, 3 }; * Clp_AddStringListTypeVec(clp, 100, Clp_AllowNumbers, 3, strs, vals); * @endcode * * Say that option --animal takes value type 100. Then: * *
    *
  • --animal=cat will succeed and set @a clp->val.i = 1.
  • *
  • --animal=cattle will succeed and set @a clp->val.i = 2.
  • *
  • --animal=dog will succeed and set @a clp->val.i = 3.
  • *
  • --animal=d will succeed and set @a clp->val.i = 3.
  • *
  • --animal=c will fail, since c is ambiguous.
  • *
  • --animal=4 will succeed and set @a clp->val.i = 4.
  • *
* * @note The CLP library will not modify the contents of @a strs or @a vals. * The calling program can modify the @a strs array, but the actual strings * (for instance, @a strs[0] and @a strs[1]) must not be modified or freed * until the parser is destroyed. */ int Clp_AddStringListTypeVec(Clp_Parser *clp, int val_type, int flags, int nstrs, const char * const *strs, const int *vals) /* An alternate way to make a string list type. See Clp_AddStringListType for the basics; this coalesces the strings and values into two arrays, rather than spreading them out into a variable argument list. */ { int i; int itemscap = (nstrs < 5 ? 5 : nstrs); Clp_Option *items = (Clp_Option *)malloc(sizeof(Clp_Option) * itemscap); if (!items) return -1; /* copy over items */ for (i = 0; i < nstrs; i++) { items[i].long_name = strs[i]; items[i].option_id = vals[i]; items[i].flags = 0; } if (finish_string_list(clp, val_type, flags, items, nstrs, itemscap) >= 0) return 0; else { free(items); return -1; } } /******* * Returning information **/ const char * Clp_ProgramName(Clp_Parser *clp) { return clp->internal->program_name; } /** @param clp the parser * @param name new program name * @return previous program name * * The calling program should not modify or free @a name until @a clp itself * is destroyed. */ const char * Clp_SetProgramName(Clp_Parser *clp, const char *name) { const char *old = clp->internal->program_name; clp->internal->program_name = name; return old; } /****** * Clp_ParserStates **/ /** @return the parser state * * A Clp_ParserState object can store a parsing state of a Clp_Parser object. * This state specifies exactly how far the Clp_Parser has gotten in parsing * an argument list. The Clp_SaveParser() and Clp_RestoreParser() functions * can be used to save this state and then restore it later, allowing a * Clp_Parser to switch among argument lists. * * The initial state is empty, in that after Clp_RestoreParser(clp, state), * Clp_Next(clp) would return Clp_Done. * * Parser states can be saved and restored among different parser objects. * * @sa Clp_DeleteParserState, Clp_SaveParser, Clp_RestoreParser */ Clp_ParserState * Clp_NewParserState(void) { Clp_ParserState *state = (Clp_ParserState *)malloc(sizeof(Clp_ParserState)); if (state) { state->argv = 0; state->argc = 0; state->option_chars[0] = 0; state->xtext = 0; state->option_processing = 0; state->opt_generation = 0; state->current_option = -1; state->is_short = 0; state->whole_negated = 0; state->current_short = 0; state->negated_by_no = 0; } return state; } /** @param state parser state * * The memory associated with @a state is freed. */ void Clp_DeleteParserState(Clp_ParserState *state) { free(state); } /** @param clp the parser * @param state parser state * @sa Clp_NewParserState, Clp_RestoreParser */ void Clp_SaveParser(const Clp_Parser *clp, Clp_ParserState *state) { Clp_Internal *cli = clp->internal; state->argv = cli->argv; state->argc = cli->argc; memcpy(state->option_chars, cli->option_chars, Clp_OptionCharsSize); state->xtext = cli->xtext; state->option_processing = cli->option_processing; state->opt_generation = cli->opt_generation; state->current_option = cli->current_option; state->is_short = cli->is_short; state->whole_negated = cli->whole_negated; state->current_short = cli->current_short; state->negated_by_no = cli->negated_by_no; } /** @param clp the parser * @param state parser state * * The parser state in @a state is restored into @a clp. The next call to * Clp_Next() will return the same result as it would have at the time @a * state was saved (probably by Clp_SaveParser(@a clp, @a state)). * * A parser state contains information about arguments (argc and argv; see * Clp_SetArguments()) and option processing (Clp_SetOptionProcessing()), but * not about options (Clp_SetOptions()). Changes to options and value types * are preserved across Clp_RestoreParser(). * * @sa Clp_NewParserState, Clp_SaveParser */ void Clp_RestoreParser(Clp_Parser *clp, const Clp_ParserState *state) { Clp_Internal *cli = clp->internal; cli->argv = state->argv; cli->argc = state->argc; memcpy(cli->option_chars, state->option_chars, Clp_OptionCharsSize); cli->xtext = state->xtext; cli->option_processing = state->option_processing; cli->is_short = state->is_short; cli->whole_negated = state->whole_negated; cli->current_short = state->current_short; cli->negated_by_no = state->negated_by_no; if (cli->opt_generation == state->opt_generation) cli->current_option = state->current_option; else cli->current_option = -1; } /******* * Clp_Next and its helpers **/ static void set_option_text(Clp_Internal *cli, const char *text, int n_option_chars) { assert(n_option_chars < Clp_OptionCharsSize); memcpy(cli->option_chars, text, n_option_chars); cli->option_chars[n_option_chars] = 0; cli->xtext = text + n_option_chars; } static int get_oclass(Clp_Parser *clp, const char *text, int *ocharskip) { int c; if (clp->internal->utf8) { const char *s; c = decode_utf8(text, &s); *ocharskip = s - text; } else { c = (unsigned char) text[0]; *ocharskip = 1; } return Clp_OptionChar(clp, c); } static int next_argument(Clp_Parser *clp, int want_argument) /* Moves clp to the next argument. Returns 1 if it finds another option. Returns 0 if there aren't any more arguments. Returns 0, sets clp->have_val = 1, and sets clp->vstr to the argument if the next argument isn't an option. If want_argument > 0, it'll look for an argument. want_argument == 1: Accept arguments that start with Clp_NotOption or Clp_LongImplicit. want_argument == 2: Accept ALL arguments. Where is the option stored when this returns? Well, cli->argv[0] holds the whole of the next command line argument. cli->option_chars holds a string: what characters began the option? It is generally "-" or "--". cli->text holds the text of the option: for short options, cli->text[0] is the relevant character; for long options, cli->text holds the rest of the option. */ { Clp_Internal *cli = clp->internal; const char *text; int oclass, ocharskip; /* clear relevant flags */ clp->have_val = 0; clp->vstr = 0; cli->could_be_short = 0; /* if we're in a string of short options, move up one char in the string */ if (cli->is_short) { cli->xtext += clp_utf8_charlen(cli, cli->xtext); if (cli->xtext[0] == 0) cli->is_short = 0; else if (want_argument > 0) { /* handle -O[=]argument case */ clp->have_val = 1; if (cli->xtext[0] == '=') clp->vstr = cli->xtext + 1; else clp->vstr = cli->xtext; cli->is_short = 0; return 0; } } /* if in short options, we're all set */ if (cli->is_short) return 1; /** if not in short options, move to the next argument **/ cli->whole_negated = 0; cli->xtext = 0; if (cli->argc <= 1) return 0; cli->argc--; cli->argv++; text = cli->argv[0]; if (want_argument > 1) goto not_option; if (text[0] == '-' && text[1] == '-') { oclass = Clp_DoubledLong; ocharskip = 2; } else oclass = get_oclass(clp, text, &ocharskip); /* If this character could introduce either a short or a long option, try a long option first, but remember that short's a possibility for later. */ if ((oclass & (Clp_Short | Clp_ShortNegated)) && (oclass & (Clp_Long | Clp_LongNegated))) { oclass &= ~(Clp_Short | Clp_ShortNegated); if (text[ocharskip]) cli->could_be_short = 1; } switch (oclass) { case Clp_Short: cli->is_short = 1; goto check_singleton; case Clp_ShortNegated: cli->is_short = 1; cli->whole_negated = 1; goto check_singleton; case Clp_Long: goto check_singleton; case Clp_LongNegated: cli->whole_negated = 1; goto check_singleton; check_singleton: /* For options introduced with one character, option-char, '[option-char]' alone is NOT an option. */ if (!text[ocharskip]) goto not_option; set_option_text(cli, text, ocharskip); break; case Clp_LongImplicit: /* LongImplict: option_chars == "" (since all chars are part of the option); restore head -> text of option */ if (want_argument > 0) goto not_option; set_option_text(cli, text, 0); break; case Clp_DoubledLong: set_option_text(cli, text, ocharskip); break; not_option: case Clp_NotOption: cli->is_short = 0; clp->have_val = 1; clp->vstr = text; return 0; default: assert(0 /* CLP misconfiguration: bad option type */); } return 1; } static void switch_to_short_argument(Clp_Parser *clp) { Clp_Internal *cli = clp->internal; const char *text = cli->argv[0]; int ocharskip, oclass = get_oclass(clp, text, &ocharskip); assert(cli->could_be_short); cli->is_short = 1; cli->whole_negated = (oclass & Clp_ShortNegated ? 1 : 0); set_option_text(cli, cli->argv[0], ocharskip); } static int find_long(Clp_Parser *clp, const char *arg) /* If arg corresponds to one of clp's options, finds that option & returns it. If any argument is given after an = sign in arg, sets clp->have_val = 1 and clp->vstr to that argument. Sets cli->ambiguous to 1 iff there was no match because the argument was ambiguous. */ { Clp_Internal *cli = clp->internal; int optno, len, lmm; const Clp_Option *opt = cli->opt; const Clp_InternOption *iopt; int first_negative_ambiguous; /* Look for a normal option. */ optno = find_prefix_opt (clp, arg, cli->nopt, opt, cli->iopt, &cli->ambiguous, cli->ambiguous_values); if (optno >= 0) goto worked; /* If we can't find it, look for a negated option. */ /* I know this is silly, but it makes me happy to accept --no-no-option as a double negative synonym for --option. :) */ first_negative_ambiguous = cli->ambiguous; while (arg[0] == 'n' && arg[1] == 'o' && arg[2] == '-') { arg += 3; clp->negated = !clp->negated; optno = find_prefix_opt (clp, arg, cli->nopt, opt, cli->iopt, &cli->ambiguous, cli->ambiguous_values); if (optno >= 0) goto worked; } /* No valid option was found; return 0. Mark the ambiguous values found through '--no' by making them negative. */ { int i, max = cli->ambiguous; if (max > MAX_AMBIGUOUS_VALUES) max = MAX_AMBIGUOUS_VALUES; for (i = first_negative_ambiguous; i < max; i++) cli->ambiguous_values[i] = -cli->ambiguous_values[i] - 1; } return -1; worked: iopt = &cli->iopt[optno]; lmm = (clp->negated ? iopt->lmmneg : iopt->lmmpos); if (cli->could_be_short && (clp->negated ? iopt->lmmneg_short : iopt->lmmpos_short)) { int first_charlen = clp_utf8_charlen(cli, arg); lmm = (first_charlen >= lmm ? first_charlen + 1 : lmm); } len = argcmp(opt[optno].long_name + iopt->ilongoff, arg, lmm, 1); assert(len > 0); if (arg[len] == '=') { clp->have_val = 1; clp->vstr = arg + len + 1; } return optno; } static int find_short(Clp_Parser *clp, const char *text) /* If short_name corresponds to one of clp's options, returns it. */ { Clp_Internal *cli = clp->internal; const Clp_Option *opt = cli->opt; const Clp_InternOption *iopt = cli->iopt; int i, c; if (clp->internal->utf8) c = decode_utf8(text, 0); else c = (unsigned char) *text; for (i = 0; i < cli->nopt; i++) if (iopt[i].ishort && opt[i].short_name == c && (clp->negated ? iopt[i].ineg : iopt[i].ipos)) return i; return -1; } /** @param clp the parser * @return option ID of next option * * Parse the next argument from the argument list, store information about * that argument in the fields of @a clp, and return the option's ID. * * If an argument was successfully parsed, that option's ID is returned. * Other possible return values are: * *
*
Clp_Done
*
There are no more arguments.
*
Clp_NotOption
*
The next argument was not an option. The argument's text is @a * clp->vstr (and @a clp->val.s).
*
Clp_BadOption
*
The next argument was a bad option: either an option that wasn't * understood, or an option lacking a required value, or an option whose value * couldn't be parsed. The option has been skipped.
*
Clp_Error
*
There was an internal error. This should never occur unless a user * messes with, for example, a Clp_Option array.
*
* * The fields of @a clp are set as follows. * *
*
negated
*
1 if the option was negated, 0 if it wasn't.
*
have_val
*
1 if the option had a value, 0 if it didn't. Note that negated options * are not allowed to have values.
*
vstr
*
The value string, if any. NULL if there was no value.
*
val
*
An option's value type will parse the value string into this * union.
*
* * The parsed argument is shifted off the argument list, so that sequential * calls to Clp_Next() step through the arugment list. */ int Clp_Next(Clp_Parser *clp) { Clp_Internal *cli = clp->internal; int optno; const Clp_Option *opt; Clp_ParserState clpsave; int vtpos, complain; /* Set up clp */ cli->current_option = -1; cli->ambiguous = 0; /* Get the next argument or option */ if (!next_argument(clp, cli->option_processing ? 0 : 2)) { clp->val.s = clp->vstr; clp->opt = clp->have_val ? Clp_NotOption : Clp_Done; return clp->opt; } clp->negated = cli->whole_negated; if (cli->is_short) optno = find_short(clp, cli->xtext); else optno = find_long(clp, cli->xtext); /* If there's ambiguity between long & short options, and we couldn't find a long option, look for a short option */ if (optno < 0 && cli->could_be_short) { switch_to_short_argument(clp); optno = find_short(clp, cli->xtext); } /* If we didn't find an option... */ if (optno < 0 || (clp->negated && !cli->iopt[optno].ineg)) { /* default processing for the "--" option: turn off option processing and return the next argument */ if (strcmp(cli->argv[0], "--") == 0) { Clp_SetOptionProcessing(clp, 0); return Clp_Next(clp); } /* otherwise, report some error or other */ if (cli->ambiguous) ambiguity_error(clp, cli->ambiguous, cli->ambiguous_values, cli->opt, cli->iopt, cli->option_chars, "option %<%s%s%> is ambiguous", cli->option_chars, cli->xtext); else if (cli->is_short && !cli->could_be_short) Clp_OptionError(clp, "unrecognized option %<%s%C%>", cli->option_chars, cli->xtext); else Clp_OptionError(clp, "unrecognized option %<%s%s%>", cli->option_chars, cli->xtext); return (clp->opt = Clp_BadOption); } /* Set the current option */ cli->current_option = optno; cli->current_short = cli->is_short; cli->negated_by_no = clp->negated && !cli->whole_negated; /* The no-argument (or should-have-no-argument) case */ if (clp->negated || (!cli->iopt[optno].imandatory && !cli->iopt[optno].ioptional)) { if (clp->have_val) { Clp_OptionError(clp, "%<%O%> can%,t take an argument"); clp->opt = Clp_BadOption; } else clp->opt = cli->opt[optno].option_id; return clp->opt; } /* Get an argument if we need one, or if it's optional */ /* Sanity-check the argument type. */ opt = &cli->opt[optno]; if (opt->val_type <= 0) return (clp->opt = Clp_Error); vtpos = val_type_binsearch(cli, opt->val_type); if (vtpos == cli->nvaltype || cli->valtype[vtpos].val_type != opt->val_type) return (clp->opt = Clp_Error); /* complain == 1 only if the argument was explicitly given, or it is mandatory. */ complain = (clp->have_val != 0) || cli->iopt[optno].imandatory; Clp_SaveParser(clp, &clpsave); if (cli->iopt[optno].imandatory && !clp->have_val) { /* Mandatory argument case */ /* Allow arguments to options to start with a dash, but only if the argument type allows it by not setting Clp_DisallowOptions */ int disallow = (cli->valtype[vtpos].flags & Clp_DisallowOptions) != 0; next_argument(clp, disallow ? 1 : 2); if (!clp->have_val) { int got_option = cli->xtext != 0; Clp_RestoreParser(clp, &clpsave); if (got_option) Clp_OptionError(clp, "%<%O%> requires a non-option argument"); else Clp_OptionError(clp, "%<%O%> requires an argument"); return (clp->opt = Clp_BadOption); } } else if (cli->is_short && !clp->have_val && cli->xtext[clp_utf8_charlen(cli, cli->xtext)]) { /* The -[option]argument case: Assume that the rest of the current string is the argument. */ next_argument(clp, 1); complain = 1; } /* Parse the argument */ if (clp->have_val) { Clp_ValType *atr = &cli->valtype[vtpos]; if (atr->func(clp, clp->vstr, complain, atr->user_data) <= 0) { /* parser failed */ clp->have_val = 0; if (complain) return (clp->opt = Clp_BadOption); else Clp_RestoreParser(clp, &clpsave); } } return (clp->opt = opt->option_id); } /** @param clp the parser * @param allow_options whether options will be allowed * * Remove and return the next argument from @a clp's argument array. If there * are no arguments left, or if the next argument is an option and @a * allow_options != 0, then returns null. */ const char * Clp_Shift(Clp_Parser *clp, int allow_options) /* Returns the next argument from the argument list without parsing it. If there are no more arguments, returns 0. */ { Clp_ParserState clpsave; Clp_SaveParser(clp, &clpsave); next_argument(clp, allow_options ? 2 : 1); if (!clp->have_val) Clp_RestoreParser(clp, &clpsave); return clp->vstr; } /******* * Clp_OptionError **/ typedef struct Clp_BuildString { char *text; char *pos; int capacity; int bad; } Clp_BuildString; static Clp_BuildString * new_build_string(void) { Clp_BuildString *bs = (Clp_BuildString *)malloc(sizeof(Clp_BuildString)); if (!bs) goto bad; bs->text = (char *)malloc(256); if (!bs->text) goto bad; bs->pos = bs->text; bs->capacity = 256; bs->bad = 0; return bs; bad: if (bs) free(bs); return 0; } static void free_build_string(Clp_BuildString *bs) { if (bs) free(bs->text); free(bs); } static int grow_build_string(Clp_BuildString *bs, int want) { char *new_text; int ipos = bs->pos - bs->text; int new_capacity = bs->capacity; while (want >= new_capacity) new_capacity *= 2; new_text = (char *)realloc(bs->text, new_capacity); if (!new_text) { bs->bad = 1; return 0; } else { bs->text = new_text; bs->pos = bs->text + ipos; bs->capacity = new_capacity; return 1; } } #define ENSURE_BUILD_STRING(bs, space) \ ((((bs)->pos - (bs)->text) + (space) >= (bs)->capacity) \ || grow_build_string((bs), ((bs)->pos - (bs)->text) + (space))) static void append_build_string(Clp_BuildString *bs, const char *s, int l) { if (l < 0) l = strlen(s); if (ENSURE_BUILD_STRING(bs, l)) { memcpy(bs->pos, s, l); bs->pos += l; } } static Clp_BuildString * Clp_VaOptionError(Clp_Parser *clp, Clp_BuildString *bs, const char *fmt, va_list val) { Clp_Internal *cli = clp->internal; const char *percent; int c; if (!bs) bs = new_build_string(); if (!bs) return 0; if (cli->program_name && cli->program_name[0]) { append_build_string(bs, cli->program_name, -1); append_build_string(bs, ": ", 2); } for (percent = strchr(fmt, '%'); percent; percent = strchr(fmt, '%')) { append_build_string(bs, fmt, percent - fmt); switch (*++percent) { case 's': { const char *s = va_arg(val, const char *); if (s) append_build_string(bs, s, -1); else append_build_string(bs, "(null)", 6); break; } case 'C': { const char *s = va_arg(val, const char *); if (cli->utf8) c = decode_utf8(s, 0); else c = (unsigned char) *s; goto char_c; } case 'c': c = va_arg(val, int); goto char_c; char_c: if (ENSURE_BUILD_STRING(bs, 4)) { if (c >= 32 && c <= 126) *bs->pos++ = c; else if (c < 32) { *bs->pos++ = '^'; *bs->pos++ = c + 64; } else if (cli->utf8 && c >= 127 && c < 0x110000) { bs->pos = encode_utf8(bs->pos, 4, c); } else if (c >= 127 && c <= 255) { sprintf(bs->pos, "\\%03o", c & 0xFF); bs->pos += 4; } else { *bs->pos++ = '\\'; *bs->pos++ = '?'; } } break; case 'd': { int d = va_arg(val, int); if (ENSURE_BUILD_STRING(bs, 32)) { sprintf(bs->pos, "%d", d); bs->pos = strchr(bs->pos, 0); } break; } case 'O': { int optno = cli->current_option; const Clp_Option *opt = &cli->opt[optno]; if (optno < 0) append_build_string(bs, "(no current option!)", -1); else if (cli->current_short) { append_build_string(bs, cli->option_chars, -1); if (ENSURE_BUILD_STRING(bs, 5)) { if (cli->utf8) bs->pos = encode_utf8(bs->pos, 5, opt->short_name); else *bs->pos++ = opt->short_name; } } else if (cli->negated_by_no) { append_build_string(bs, cli->option_chars, -1); append_build_string(bs, "no-", 3); append_build_string(bs, opt->long_name + cli->iopt[optno].ilongoff, -1); } else { append_build_string(bs, cli->option_chars, -1); append_build_string(bs, opt->long_name + cli->iopt[optno].ilongoff, -1); } break; } case '%': if (ENSURE_BUILD_STRING(bs, 1)) *bs->pos++ = '%'; break; case '`': /* backwards compatibility */ case '<': append_build_string(bs, (cli->utf8 ? "\342\200\230" : "'"), -1); break; case '\'': /* backwards compatibility */ case ',': case '>': append_build_string(bs, (cli->utf8 ? "\342\200\231" : "'"), -1); break; default: if (ENSURE_BUILD_STRING(bs, 2)) { *bs->pos++ = '%'; *bs->pos++ = *percent; } break; } fmt = ++percent; } append_build_string(bs, fmt, -1); append_build_string(bs, "\n", 1); return bs; } static void do_error(Clp_Parser *clp, Clp_BuildString *bs) { const char *text; if (bs && !bs->bad) { *bs->pos = 0; text = bs->text; } else text = "out of memory\n"; if (clp->internal->error_handler != 0) (*clp->internal->error_handler)(clp, text); else fputs(text, stderr); } /** @param clp the parser * @param format error format * * Format an error message from @a format and any additional arguments in the * ellipsis. The resulting error string by printing it to standard error or * passing it to Clp_SetErrorHandler. * * The following format characters are accepted: * *
*
%c
*
A character (type int). Control characters are printed in * caret notation. If the parser is in UTF-8 mode, the character is formatted * in UTF-8. Otherwise, special characters are printed with backslashes and * octal notation.
*
%s
*
A string (type const char *).
*
%C
*
The argument is a string (type const char *). The first * character in this string is printed. If the parser is in UTF-8 mode, this * may involve multiple bytes.
*
%d
*
An integer (type int). Printed in decimal.
*
%O
*
The current option. No values are read from the argument list; the * current option is defined in the Clp_Parser object itself.
*
%%
*
Prints a percent character.
*
%<
*
Prints an open quote string. In UTF-8 mode, prints a left single * quote. Otherwise prints a single quote.
*
%>
*
Prints a closing quote string. In UTF-8 mode, prints a right single * quote. Otherwise prints a single quote.
*
%,
*
Prints an apostrophe. In UTF-8 mode, prints a right single quote. * Otherwise prints a single quote.
*
* * Note that no flag characters, precision, or field width characters are * currently supported. * * @sa Clp_SetErrorHandler */ int Clp_OptionError(Clp_Parser *clp, const char *format, ...) { Clp_BuildString *bs; va_list val; va_start(val, format); bs = Clp_VaOptionError(clp, 0, format, val); va_end(val); do_error(clp, bs); free_build_string(bs); return 0; } static int ambiguity_error(Clp_Parser *clp, int ambiguous, int *ambiguous_values, const Clp_Option *opt, const Clp_InternOption *iopt, const char *prefix, const char *fmt, ...) { Clp_Internal *cli = clp->internal; Clp_BuildString *bs; int i; va_list val; va_start(val, fmt); bs = Clp_VaOptionError(clp, 0, fmt, val); if (!bs) goto done; if (clp->internal->program_name && clp->internal->program_name[0]) { append_build_string(bs, clp->internal->program_name, -1); append_build_string(bs, ": ", 2); } append_build_string(bs, "(Possibilities are", -1); for (i = 0; i < ambiguous && i < MAX_AMBIGUOUS_VALUES; i++) { int value = ambiguous_values[i]; const char *no_dash = ""; if (value < 0) value = -(value + 1), no_dash = "no-"; if (i == 0) append_build_string(bs, " ", 1); else if (i == ambiguous - 1) append_build_string(bs, (i == 1 ? " and " : ", and "), -1); else append_build_string(bs, ", ", 2); append_build_string(bs, (cli->utf8 ? "\342\200\230" : "'"), -1); append_build_string(bs, prefix, -1); append_build_string(bs, no_dash, -1); append_build_string(bs, opt[value].long_name + iopt[value].ilongoff, -1); append_build_string(bs, (cli->utf8 ? "\342\200\231" : "'"), -1); } if (ambiguous > MAX_AMBIGUOUS_VALUES) append_build_string(bs, ", and others", -1); append_build_string(bs, ".)\n", -1); va_end(val); done: do_error(clp, bs); free_build_string(bs); return 0; } static int copy_string(char *buf, int buflen, int bufpos, const char *what) { int l = strlen(what); if (l > buflen - bufpos - 1) l = buflen - bufpos - 1; memcpy(buf + bufpos, what, l); return l; } /** @param clp the parser * @param buf output buffer * @param len length of output buffer * @return number of characters written to the buffer, not including the terminating NUL * * A string that looks like the last option parsed by @a clp is extracted into * @a buf. The correct option characters are put into the string first, * followed by the option text. The output buffer is null-terminated unless * @a len == 0. * * @sa Clp_CurOptionName */ int Clp_CurOptionNameBuf(Clp_Parser *clp, char *buf, int len) { Clp_Internal *cli = clp->internal; int optno = cli->current_option; int pos = 0; if (optno < 0) pos += copy_string(buf, len, pos, "(no current option!)"); else if (cli->current_short) { pos += copy_string(buf, len, pos, cli->option_chars); if (cli->utf8) pos = (encode_utf8(buf + pos, len - pos - 1, cli->opt[optno].short_name) - buf); else if (pos < len - 1) buf[pos++] = cli->opt[optno].short_name; } else if (cli->negated_by_no) { pos += copy_string(buf, len, pos, cli->option_chars); pos += copy_string(buf, len, pos, "no-"); pos += copy_string(buf, len, pos, cli->opt[optno].long_name + cli->iopt[optno].ilongoff); } else { pos += copy_string(buf, len, pos, cli->option_chars); pos += copy_string(buf, len, pos, cli->opt[optno].long_name + cli->iopt[optno].ilongoff); } if (pos < len) buf[pos] = 0; return pos; } /** @param clp the parser * @return string describing the current option * * This function acts like Clp_CurOptionNameBuf(), but returns a pointer into * a static buffer that will be rewritten on the next call to * Clp_CurOptionName(). * * @note This function is not thread safe. * * @sa Clp_CurOptionName */ const char * Clp_CurOptionName(Clp_Parser *clp) { static char buf[256]; Clp_CurOptionNameBuf(clp, buf, 256); return buf; } #ifdef __cplusplus } #endif t1utils-1.39/configure.ac000066400000000000000000000054611247370226400153560ustar00rootroot00000000000000dnl Process this file with autoconf to produce a configure script. AC_INIT([t1utils], [1.39]) AC_CONFIG_SRCDIR([t1ascii.c]) AM_INIT_AUTOMAKE AC_CONFIG_HEADERS([config.h]) AM_MAINTAINER_MODE AC_PROG_CC AC_C_CONST AC_ARG_ENABLE([warnings], [AS_HELP_STRING([--enable-warnings], [compile with -W -Wall])], [if test "$enableval" = yes; then CFLAGS="$CFLAGS -W -Wall" fi]) dnl dnl strerror()? dnl AC_REPLACE_FUNCS([strerror]) dnl dnl integer types dnl AC_CHECK_HEADERS(inttypes.h, have_inttypes_h=yes, have_inttypes_h=no) AC_CHECK_HEADERS(sys/types.h, have_sys_types_h=yes, have_sys_types_h=no) if test $have_inttypes_h = no -a $have_sys_types_h = yes; then AC_CACHE_CHECK([for uintXX_t typedefs], ac_cv_uint_t, [AC_EGREP_HEADER(dnl changequote(<<,>>)<<(^|[^a-zA-Z_0-9])uint32_t[^a-zA-Z_0-9]>>changequote([,]), sys/types.h, ac_cv_uint_t=yes, ac_cv_uint_t=no)]) fi if test $have_inttypes_h = no -a $have_sys_types_h = yes -a "$ac_cv_uint_t" = no; then AC_CACHE_CHECK([for u_intXX_t typedefs], ac_cv_u_int_t, [AC_EGREP_HEADER(dnl changequote(<<,>>)<<(^|[^a-zA-Z_0-9])u_int32_t[^a-zA-Z_0-9]>>changequote([,]), sys/types.h, ac_cv_u_int_t=yes, ac_cv_u_int_t=no)]) fi if test $have_inttypes_h = yes -o "$ac_cv_uint_t" = yes; then : elif test "$ac_cv_u_int_t" = yes; then AC_DEFINE(HAVE_U_INT_TYPES, 1, [Define if you have u_intXX_t types but not uintXX_t types.]) else AC_MSG_WARN([ ========================================= Neither uint32_t nor u_int32_t defined by or ! Assuming "short" has 16 bits and "int" has 32 bits. =========================================]) AC_DEFINE(HAVE_FAKE_INT_TYPES, 1, [Define if intXX_t types are not available.]) fi AC_CHECK_TYPES(uintptr_t, [], [], [#if HAVE_INTTYPES_H # include #endif #if HAVE_SYS_TYPES_H # include #endif ]) AC_CHECK_SIZEOF(void *) AC_CHECK_SIZEOF(unsigned long) AC_CHECK_SIZEOF(unsigned int) dnl dnl verbatim portions of the header dnl AH_TOP([#ifndef T1UTILS_CONFIG_H #define T1UTILS_CONFIG_H]) AH_BOTTOM([#include #ifdef __cplusplus extern "C" { #endif /* Prototype strerror if we don't have it. */ #if !HAVE_STRERROR char *strerror(int errno); #endif #ifdef __cplusplus } /* Get rid of a possible inline macro under C++. */ # define inline inline #endif #endif /* T1UTILS_CONFIG_H */]) dnl dnl Multiplatform output directories (for teTeX and TeX Live) dnl AC_CANONICAL_HOST AC_ARG_ENABLE([multiplatform], [AS_HELP_STRING([--enable-multiplatform], [put executables into bin/PLATFORM and libraries into lib/PLATFORM])]) if test "x$enable_multiplatform" = xyes; then test "x$bindir" = 'x${exec_prefix}/bin' && bindir="$bindir/$host" test "x$libdir" = 'x${exec_prefix}/lib' && libdir="$libdir/$host" fi dnl dnl Output dnl AC_CONFIG_FILES([Makefile]) AC_OUTPUT t1utils-1.39/include/000077500000000000000000000000001247370226400145055ustar00rootroot00000000000000t1utils-1.39/include/lcdf/000077500000000000000000000000001247370226400154155ustar00rootroot00000000000000t1utils-1.39/include/lcdf/clp.h000066400000000000000000000241461247370226400163530ustar00rootroot00000000000000/* -*- related-file-name: "../../liblcdf/clp.c" -*- */ #ifndef LCDF_CLP_H #define LCDF_CLP_H #ifdef __cplusplus extern "C" { #endif /* clp.h - Public interface to CLP. * This file is part of CLP, the command line parser package. * * Copyright (c) 1997-2012 Eddie Kohler, ekohler@gmail.com * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, subject to the conditions * listed in the Click LICENSE file, which is available in full at * http://www.pdos.lcs.mit.edu/click/license.html. The conditions include: you * must preserve this copyright notice, and you cannot mention the copyright * holders in advertising related to the Software without their permission. * The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This * notice is a summary of the Click LICENSE file; the license in that file is * legally binding. */ typedef struct Clp_Option Clp_Option; typedef struct Clp_Parser Clp_Parser; typedef struct Clp_ParserState Clp_ParserState; /** @brief Option description. * * CLP users declare arrays of Clp_Option structures to specify what options * should be parsed. * @sa Clp_NewParser, Clp_SetOptions */ struct Clp_Option { const char *long_name; /**< Name of long option, or NULL if the option has no long name. */ int short_name; /**< Character defining short option, or 0 if the option has no short name. */ int option_id; /**< User-specified ID defining option, returned by Clp_Next. */ int val_type; /**< ID of option's value type, or 0 if option takes no value. */ int flags; /**< Option parsing flags. */ }; /** @name Value types * These values describe the type of an option's argument and are used in * the Clp_Option val_type field. For example, if an option took integers, its * Clp_Option structure would have val_type set to Clp_ValInt. */ /**@{*/ #define Clp_NoVal 0 /**< @brief Option takes no value. */ #define Clp_ValString 1 /**< @brief Option value is an arbitrary string. */ #define Clp_ValStringNotOption 2 /**< @brief Option value is a non-option string. See Clp_DisallowOptions. */ #define Clp_ValBool 3 /**< @brief Option value is a boolean. Accepts "true", "false", "yes", "no", "1", and "0", or any prefixes thereof. The match is case-insensitive. */ #define Clp_ValInt 4 /**< @brief Option value is a signed int. Accepts an optional "+" or "-" sign, followed by one or more digits. The digits may be include a "0x" or "0X" prefix, for a hexidecimal number, or a "0" prefix, for an octal number; otherwise it is decimal. */ #define Clp_ValUnsigned 5 /**< @brief Option value is an unsigned int. Accepts an optional "+" sign, followed by one or more digits. The digits may be include a "0x" or "0X" prefix, for a hexidecimal number, or a "0" prefix, for an octal number; otherwise it is decimal. */ #define Clp_ValDouble 6 /**< @brief Option value is a double. Accepts a real number as defined by strtod(). */ #define Clp_ValFirstUser 10 /**< @brief Value types >= Clp_ValFirstUser are available for user types. */ /**@}*/ /** @name Option flags * These flags are used in the Clp_Option flags field. */ /**@{*/ #define Clp_Mandatory (1<<0) /**< @brief Option flag: value is mandatory. It is an error if the option has no value. This is the default if an option has arg_type != 0 and the Clp_Optional flag is not provided. */ #define Clp_Optional (1<<1) /**< @brief Option flag: value is optional. */ #define Clp_Negate (1<<2) /**< @brief Option flag: option may be negated. --no-[long_name] will be accepted in argument lists. */ #define Clp_OnlyNegated (1<<3) /**< @brief Option flag: option must be negated. --no-[long_name] will be accepted in argument lists, but --[long_name] will not. This is the default if long_name begins with "no-". */ #define Clp_PreferredMatch (1<<4) /**< @brief Option flag: prefer this option when matching. Prefixes of --[long_name] should map to this option, even if other options begin with --[long_name]. */ /**@}*/ /** @name Option character types * These flags are used in to define character types in Clp_SetOptionChar(). */ /**@{*/ /* Clp_NotOption 0 */ #define Clp_Short (1<<0) /**< @brief Option character begins a set of short options. */ #define Clp_Long (1<<1) /**< @brief Option character begins a long option. */ #define Clp_ShortNegated (1<<2) /**< @brief Option character begins a set of negated short options. */ #define Clp_LongNegated (1<<3) /**< @brief Option character begins a negated long option. */ #define Clp_LongImplicit (1<<4) /**< @brief Option character can begin a long option, and is part of that long option. */ /**@}*/ #define Clp_NotOption 0 /**< @brief Clp_Next value: argument was not an option. */ #define Clp_Done -1 /**< @brief Clp_Next value: there are no more arguments. */ #define Clp_BadOption -2 /**< @brief Clp_Next value: argument was an erroneous option. */ #define Clp_Error -3 /**< @brief Clp_Next value: internal CLP error. */ #define Clp_ValSize 40 /**< @brief Minimum size of the Clp_Parser val.cs field. */ #define Clp_ValIntSize 10 /**< @brief Minimum size of the Clp_Parser val.is field. */ /** @brief A value parsing function. * @param clp the parser * @param vstr the value to be parsed * @param complain if nonzero, report error messages via Clp_OptionError * @param user_data user data passed to Clp_AddType() * @return 1 if parsing succeeded, 0 otherwise */ typedef int (*Clp_ValParseFunc)(Clp_Parser *clp, const char *vstr, int complain, void *user_data); /** @brief A function for reporting option errors. * @param clp the parser * @param message error message */ typedef void (*Clp_ErrorHandler)(Clp_Parser *clp, const char *message); /** @brief Command line parser. * * A Clp_Parser object defines an instance of CLP, including allowed options, * value types, and current arguments. * @sa Clp_NewParser, Clp_SetOptions, Clp_SetArguments */ struct Clp_Parser { int opt; /**< The last option. */ int negated; /**< Whether the last option was negated. */ int have_val; /**< Whether the last option had a value. */ const char *vstr; /**< The string value provided with the last option. */ union { int i; unsigned u; double d; const char *s; void *pv; #ifdef HAVE_INT64_TYPES int64_t i64; uint64_t u64; #endif char cs[Clp_ValSize]; unsigned char ucs[Clp_ValSize]; int is[Clp_ValIntSize]; unsigned us[Clp_ValIntSize]; } val; /**< The parsed value provided with the last option. */ void *user_data; /**< Uninterpreted by CLP; users can set arbitrarily. */ struct Clp_Internal *internal; }; /** @cond never */ #if __GNUC__ >= 4 # define CLP_SENTINEL __attribute__((sentinel)) #else # define CLP_SENTINEL /* nothing */ #endif /** @endcond never */ /** @brief Create a new Clp_Parser. */ Clp_Parser *Clp_NewParser(int argc, const char * const *argv, int nopt, const Clp_Option *opt); /** @brief Destroy a Clp_Parser object. */ void Clp_DeleteParser(Clp_Parser *clp); /** @brief Return @a clp's program name. */ const char *Clp_ProgramName(Clp_Parser *clp); /** @brief Set @a clp's program name. */ const char *Clp_SetProgramName(Clp_Parser *clp, const char *name); /** @brief Set @a clp's error handler function. */ Clp_ErrorHandler Clp_SetErrorHandler(Clp_Parser *clp, Clp_ErrorHandler errh); /** @brief Set @a clp's UTF-8 mode. */ int Clp_SetUTF8(Clp_Parser *clp, int utf8); /** @brief Return @a clp's treatment of character @a c. */ int Clp_OptionChar(Clp_Parser *clp, int c); /** @brief Set @a clp's treatment of character @a c. */ int Clp_SetOptionChar(Clp_Parser *clp, int c, int type); /** @brief Set @a clp's option definitions. */ int Clp_SetOptions(Clp_Parser *clp, int nopt, const Clp_Option *opt); /** @brief Set @a clp's arguments. */ void Clp_SetArguments(Clp_Parser *clp, int argc, const char * const *argv); /** @brief Set whether @a clp is searching for options. */ int Clp_SetOptionProcessing(Clp_Parser *clp, int on); #define Clp_DisallowOptions (1<<0) /**< @brief Value type flag: value can't be an option string. See Clp_AddType(). */ /** @brief Define a new value type for @a clp. */ int Clp_AddType(Clp_Parser *clp, int val_type, int flags, Clp_ValParseFunc parser, void *user_data); #define Clp_AllowNumbers (1<<0) /**< @brief String list flag: allow explicit numbers. See Clp_AddStringListType() and Clp_AddStringListTypeVec(). */ /** @brief Define a new string list value type for @a clp. */ int Clp_AddStringListTypeVec(Clp_Parser *clp, int val_type, int flags, int nstrs, const char * const *strs, const int *vals); /** @brief Define a new string list value type for @a clp. */ int Clp_AddStringListType(Clp_Parser *clp, int val_type, int flags, ...) CLP_SENTINEL; /** @brief Parse and return the next argument from @a clp. */ int Clp_Next(Clp_Parser *clp); /** @brief Return the next argument from @a clp without option parsing. */ const char *Clp_Shift(Clp_Parser *clp, int allow_options); /** @brief Create a new Clp_ParserState. */ Clp_ParserState *Clp_NewParserState(void); /** @brief Destroy a Clp_ParserState object. */ void Clp_DeleteParserState(Clp_ParserState *state); /** @brief Save @a clp's current state in @a state. */ void Clp_SaveParser(const Clp_Parser *clp, Clp_ParserState *state); /** @brief Restore parser state from @a state into @a clp. */ void Clp_RestoreParser(Clp_Parser *clp, const Clp_ParserState *state); /** @brief Report a parser error. */ int Clp_OptionError(Clp_Parser *clp, const char *format, ...); /** @brief Extract the current option as a string. */ int Clp_CurOptionNameBuf(Clp_Parser *clp, char *buf, int len); /** @brief Extract the current option as a string. */ const char *Clp_CurOptionName(Clp_Parser *clp); #undef CLP_SENTINEL #ifdef __cplusplus } #endif #endif t1utils-1.39/include/lcdf/inttypes.h000066400000000000000000000014411247370226400174450ustar00rootroot00000000000000#ifndef LCDF_INTTYPES_H #define LCDF_INTTYPES_H /* Define known-width integer types. */ #ifdef HAVE_INTTYPES_H # include #elif defined(HAVE_SYS_TYPES_H) # include # ifdef HAVE_U_INT_TYPES typedef u_int8_t uint8_t; typedef u_int16_t uint16_t; typedef u_int32_t uint32_t; # endif #endif #ifdef HAVE_FAKE_INT_TYPES typedef signed char int8_t; typedef unsigned char uint8_t; typedef signed short int16_t; typedef unsigned short uint16_t; typedef signed int int32_t; typedef unsigned int uint32_t; #endif #ifndef HAVE_UINTPTR_T # if SIZEOF_VOID_P == SIZEOF_UNSIGNED_INT typedef unsigned int uintptr_t; # elif SIZEOF_VOID_P == SIZEOF_UNSIGNED_LONG typedef unsigned long uintptr_t; # endif #endif /* Note: Windows compilers call these types '[un]signed __int8', etc. */ #endif t1utils-1.39/strerror.c000066400000000000000000000007161247370226400151140ustar00rootroot00000000000000/* Some operating systems don't have strerror. This file provides a definition which David Mazieres assures me works. */ #ifdef HAVE_CONFIG_H # include #endif #ifdef __cplusplus extern "C" { #endif char * strerror(int errno) { extern int sys_nerr; extern char *sys_errlist[]; if (errno < 0 || errno >= sys_nerr) return (char *)"bad error number"; else return sys_errlist[errno]; } #ifdef __cplusplus } #endif t1utils-1.39/t1ascii.1000066400000000000000000000023511247370226400145020ustar00rootroot00000000000000.ds V 1.39 .de M .BR "\\$1" "(\\$2)\\$3" .. .TH T1ASCII 1 "" "Version \*V" .SH NAME t1ascii \- convert PostScript Type 1 font from binary to ASCII .SH SYNOPSIS .B t1ascii \%[\fB\-l\fR \fIlength\fR] \%[\fIinput\fR [\fIoutput\fR]] .SH DESCRIPTION .BR t1ascii converts Adobe Type 1 font programs in PFB (binary) format to PFA (hexadecimal) format. If the file .I output is not specified output goes to the standard output. If the file .I input is not specified input comes from the standard input. ' .SH OPTIONS .TP 5 .BI \-\-line\-length= "num\fR, " \-l " num" Set the maximum length of encrypted lines in the output to .I num. (These are the lines consisting wholly of hexadecimal digits.) The default is 64. ' .TP 5 .BR \-\-warnings ", " \-w Warn when the input font contains lines longer than 255 characters. Long lines don't strictly conform to Adobe's Document Structuring Conventions, and may cause problems with older software. ' .SH "SEE ALSO" .LP .M t1binary 1 , .M t1unmac 1 , .M t1mac 1 , .M t1asm 1 , .M t1disasm 1 .LP .I "Adobe Type 1 Font Format" .SH AUTHORS Lee Hetherington (ilh@lcs.mit.edu) .br Eddie Kohler (ekohler@gmail.com) .PP Ported to Microsoft C/C++ Compiler and MS-DOS operating system by Kai-Uwe Herbing (herbing@netmbx.netmbx.de). t1utils-1.39/t1ascii.c000066400000000000000000000170111247370226400145630ustar00rootroot00000000000000/* t1ascii * * This program takes an Adobe Type-1 font program in binary (PFB) format and * converts it to ASCII (PFA) format. * * Copyright (c) 1992 by I. Lee Hetherington, all rights reserved. * Copyright (c) 1998-2013 Eddie Kohler * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, subject to the * conditions listed in the Click LICENSE file, which is available in full at * http://github.com/kohler/click/blob/master/LICENSE. The conditions * include: you must preserve this copyright notice, and you cannot mention * the copyright holders in advertising related to the Software without * their permission. The Software is provided WITHOUT ANY WARRANTY, EXPRESS * OR IMPLIED. This notice is a summary of the Click LICENSE file; the * license in that file is binding. * * New change log in `NEWS'. Old change log: * * Revision 1.2 92/06/23 10:58:43 ilh * MSDOS porting by Kai-Uwe Herbing (herbing@netmbx.netmbx.de) * incoporated. * * Revision 1.1 92/05/22 11:47:24 ilh * initial version * * Ported to Microsoft C/C++ Compiler and MS-DOS operating system by * Kai-Uwe Herbing (herbing@netmbx.netmbx.de) on June 12, 1992. Code * specific to the MS-DOS version is encapsulated with #ifdef _MSDOS * ... #endif, where _MSDOS is an identifier, which is automatically * defined, if you compile with the Microsoft C/C++ Compiler. * */ /* Note: this is ANSI C. */ #ifdef HAVE_CONFIG_H # include #endif #if defined(_MSDOS) || defined(_WIN32) # include # include #endif #include #include #include #include #include #include #include #include #include "t1lib.h" #ifdef __cplusplus extern "C" { #endif static FILE *ofp; static int line_length = 64; /***** * Command line **/ #define OUTPUT_OPT 301 #define VERSION_OPT 302 #define HELP_OPT 303 #define LINE_LEN_OPT 304 #define WARNINGS_OPT 305 static Clp_Option options[] = { { "help", 0, HELP_OPT, 0, 0 }, { "line-length", 'l', LINE_LEN_OPT, Clp_ValInt, 0 }, { "output", 'o', OUTPUT_OPT, Clp_ValString, 0 }, { "version", 0, VERSION_OPT, 0, 0 }, { "warnings", 'w', WARNINGS_OPT, 0, Clp_Negate } }; static const char *program_name; static const char *ifp_filename = ""; static int line_length_warning = -1; void fatal_error(const char *message, ...) { va_list val; va_start(val, message); fprintf(stderr, "%s: ", program_name); vfprintf(stderr, message, val); putc('\n', stderr); va_end(val); exit(1); } void error(const char *message, ...) { va_list val; va_start(val, message); fprintf(stderr, "%s: ", program_name); vfprintf(stderr, message, val); putc('\n', stderr); va_end(val); } static void short_usage(void) { fprintf(stderr, "Usage: %s [OPTION]... [INPUT [OUTPUT]]\n\ Try `%s --help' for more information.\n", program_name, program_name); } static void usage(void) { printf("\ `T1ascii' translates a PostScript Type 1 font from compact binary (PFB) to\n\ ASCII (PFA) format. The result is written to the standard output unless an\n\ OUTPUT file is given.\n\ \n\ Usage: %s [OPTION]... [INPUT [OUTPUT]]\n\ \n\ Options:\n\ -l, --line-length=NUM Set max encrypted line length (default 64).\n\ -o, --output=FILE Write output to FILE.\n\ -w, --warnings Warn on too-long lines.\n\ -h, --help Print this message and exit.\n\ --version Print version number and warranty and exit.\n\ \n\ Report bugs to .\n", program_name); } /***** * PFA font_reader functions **/ static int hexcol = 0; static void pfa_output_ascii(char *data, int len) { if (hexcol) { putc('\n', ofp); hexcol = 0; } if (line_length_warning == 0 && len > 256) { line_length_warning = 1; fprintf(stderr, "%s: warning: %s has lines longer than 255 characters\n%s: (This may cause problems with older printers.)\n", program_name, ifp_filename, program_name); } fputs(data, ofp); if (len && data[len - 1] != '\n') { int p = len - 2; while (p > 0 && data[p] != '\n') p--; hexcol = (p ? len - p - 1 : hexcol + len); } } static void pfa_output_binary(unsigned char *data, int len) { static const char *hexchar = "0123456789abcdef"; for (; len > 0; len--, data++) { /* trim hexadecimal lines to line_length columns */ if (hexcol >= line_length) { putc('\n', ofp); hexcol = 0; } putc(hexchar[(*data >> 4) & 0xf], ofp); putc(hexchar[*data & 0xf], ofp); hexcol += 2; } } static void pfa_output_end(void) { } #ifdef __cplusplus } #endif /***** * main() **/ int main(int argc, char *argv[]) { struct font_reader fr; int c; FILE *ifp = 0; Clp_Parser *clp = Clp_NewParser(argc, (const char * const *)argv, sizeof(options) / sizeof(options[0]), options); program_name = Clp_ProgramName(clp); /* interpret command line arguments using CLP */ while (1) { int opt = Clp_Next(clp); switch (opt) { case LINE_LEN_OPT: line_length = clp->val.i; if (line_length < 8) { line_length = 8; error("warning: line length raised to %d", line_length); } else if (line_length > 1024) { line_length = 1024; error("warning: line length lowered to %d", line_length); } break; output_file: case OUTPUT_OPT: if (ofp) fatal_error("output file already specified"); if (strcmp(clp->vstr, "-") == 0) ofp = stdout; else { ofp = fopen(clp->vstr, "w"); if (!ofp) fatal_error("%s: %s", clp->vstr, strerror(errno)); } break; case WARNINGS_OPT: line_length_warning = (clp->negated ? -1 : 0); break; case HELP_OPT: usage(); exit(0); break; case VERSION_OPT: printf("t1ascii (LCDF t1utils) %s\n", VERSION); printf("Copyright (C) 1992-2010 I. Lee Hetherington, Eddie Kohler et al.\n\ This is free software; see the source for copying conditions.\n\ There is NO warranty, not even for merchantability or fitness for a\n\ particular purpose.\n"); exit(0); break; case Clp_NotOption: if (ifp && ofp) fatal_error("too many arguments"); else if (ifp) goto output_file; if (strcmp(clp->vstr, "-") == 0) { ifp_filename = ""; ifp = stdin; } else { ifp_filename = clp->vstr; ifp = fopen(clp->vstr, "rb"); if (!ifp) fatal_error("%s: %s", clp->vstr, strerror(errno)); } break; case Clp_Done: goto done; case Clp_BadOption: short_usage(); exit(1); break; } } done: if (!ifp) ifp = stdin; if (!ofp) ofp = stdout; if (line_length > 255 && line_length_warning == 0) fprintf(stderr, "%s: warning: selected --line-length is greater than 255\n", program_name); #if defined(_MSDOS) || defined(_WIN32) /* As we are processing a PFB (binary) input */ /* file, we must set its file mode to binary. */ _setmode(_fileno(ifp), _O_BINARY); #endif /* prepare font reader */ fr.output_ascii = pfa_output_ascii; fr.output_binary = pfa_output_binary; fr.output_end = pfa_output_end; /* peek at first byte to see if it is the PFB marker 0x80 */ c = getc(ifp); ungetc(c, ifp); /* do the file */ if (c == PFB_MARKER) process_pfb(ifp, ifp_filename, &fr); else if (c == '%') process_pfa(ifp, ifp_filename, &fr); else fatal_error("%s does not start with font marker (`%%' or 0x80)", ifp_filename); fclose(ifp); fclose(ofp); return 0; } t1utils-1.39/t1asm.1000066400000000000000000000054321247370226400141750ustar00rootroot00000000000000.ds V 1.39 .de M .BR "\\$1" "(\\$2)\\$3" .. .TH T1ASM 1 "" "Version \*V" .SH NAME t1asm \- assemble PostScript Type 1 font .SH SYNOPSIS .B t1asm \%[\fB\-a\fR|\fB\-b\fR] \%[\fB\-l\fR \fIlength\fR] \%[\fIinput\fR [\fIoutput\fR]] .SH DESCRIPTION .B t1asm assembles Adobe Type 1 font programs into either PFA (hexadecimal) or PFB (binary) formats from a human-readable form. If the file .I output is not specified output goes to the standard output. If the file .I input is not specified input comes from the standard input. .B t1asm tokenizes the charstring data and performs eexec and charstring encryption as specified in the ``black book,'' .I "Adobe Type 1 Font Format." The input must have a line of the form .RS .nf .ft B /-|{string currentfile exch readstring pop}executeonly def .ft R .fi .RE which defines the command, in this case `\-|', that is to start charstring data. It is an error not to define such a command. Another common name for this command is `RD'. After the start of the .B Subrs array in the input, all open braces `{' not in a comment begin a charstring. Such a charstring is terminated by the next non-comment close brace `}'. Within such a charstring, only comments, integers, and valid charstring commands are allowed. Valid charstring command names can be found in .I "Adobe Type 1 Font Format" and other documents describing the newer Type 2 opcodes. The format within a charstring is unimportant as long as integers and commands are separated by at least a one whitespace (space, tab, newline) character. Note that within charstrings, comments are discarded because they cannot be encoded. .SH OPTIONS .TP 5 .BR \-\-pfa ", " \-a Output in PFA (ASCII) format. .TP 5 .BR \-\-pfb ", " \-b Output in PFB (binary) format. This is the default. .TP .BI \-\-block\-length= "num\fR, " \-l " num" PFB only: Set the maximum output block length to .I num. The default length is as large as memory allows. .TP .BI \-\-line\-length= "num\fR, " \-l " num" PFA only: Set the maximum length of encrypted lines in the output to .I num. (These are the lines consisting wholly of hexadecimal digits.) The default is 64. .SH EXAMPLES .LP .nf % t1asm Utopia-Regular.raw > Utopia-Regular.pfb % t1asm -a Utopia-Regular.raw > Utopia-Regular.pfa .fi .SH "SEE ALSO" .LP .M t1disasm 1 , .M t1ascii 1 , .M t1binary 1 , .M t1unmac 1 , .M t1mac 1 .LP .I "Adobe Type 1 Font Format" is available free from Adobe as a PDF file. http://partners.adobe.com/asn/developer/PDFS/TN/T1_SPEC.PDF .LP .I "The Type 2 Charstring Format," also available from Adobe as a PDF file, describes the newer Type 2 operators, which are also used in some multiple-master Type 1 fonts like Adobe Jenson and Kepler. http://partners.adobe.com/asn/developer/PDFS/TN/5177.Type2.pdf ' .SH AUTHORS Lee Hetherington (ilh@lcs.mit.edu) .br Eddie Kohler (ekohler@gmail.com) t1utils-1.39/t1asm.c000066400000000000000000000522221247370226400142560ustar00rootroot00000000000000/* t1asm -*- c-basic-offset: 2 -*- * * This program `assembles' Adobe Type-1 font programs in pseudo-PostScript * form into either PFB or PFA format. The human readable/editable input is * charstring- and eexec-encrypted as specified in the `Adobe Type 1 Font * Format' version 1.1 (the `black book'). There is a companion program, * t1disasm, which `disassembles' PFB and PFA files into a pseudo-PostScript * file. * * Copyright (c) 1992 by I. Lee Hetherington, all rights reserved. * Copyright (c) 1998-2013 Eddie Kohler * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, subject to the * conditions listed in the Click LICENSE file, which is available in full at * http://github.com/kohler/click/blob/master/LICENSE. The conditions * include: you must preserve this copyright notice, and you cannot mention * the copyright holders in advertising related to the Software without * their permission. The Software is provided WITHOUT ANY WARRANTY, EXPRESS * OR IMPLIED. This notice is a summary of the Click LICENSE file; the * license in that file is binding. * * New change log in `NEWS'. Old change log: * * Revision 1.4 92/07/10 10:53:09 ilh * Added support for additional PostScript after the closefile command * (ie., some fonts have {restore}if after the cleartomark). * * Revision 1.3 92/06/23 10:58:25 ilh * MSDOS porting by Kai-Uwe Herbing (herbing@netmbx.netmbx.de) * incoporated. * * Revision 1.2 92/05/22 11:54:45 ilh * Fixed bug where integers larger than 32000 could not be encoded in * charstrings. Now integer range is correct for four-byte * twos-complement integers: -(1<<31) <= i <= (1<<31)-1. Bug detected by * Piet Tutelaers (rcpt@urc.tue.nl). * * Revision 1.1 92/05/22 11:48:46 ilh * initial version * * Ported to Microsoft C/C++ Compiler and MS-DOS operating system by * Kai-Uwe Herbing (herbing@netmbx.netmbx.de) on June 12, 1992. Code * specific to the MS-DOS version is encapsulated with #ifdef _MSDOS * ... #endif, where _MSDOS is an identifier, which is automatically * defined, if you compile with the Microsoft C/C++ Compiler. * */ /* Note: this is ANSI C. */ #ifdef HAVE_CONFIG_H # include #endif #if defined(_MSDOS) || defined(_WIN32) # include # include #endif #include #include #include #include #include #include #include #include #include "t1lib.h" #include "t1asmhelp.h" #define LINESIZE 512 #ifdef __cplusplus extern "C" { #endif typedef unsigned char byte; static FILE *ifp; static FILE *ofp; static struct pfb_writer w; static int blocklen = -1; /* flags */ static int pfb = 1; static int active = 0; static int ever_active = 0; static int start_charstring = 0; static int in_eexec = 0; /* need to add 1 as space for \0 */ static char line[LINESIZE + 1]; /* for charstring buffering */ static byte *charstring_buf, *charstring_bp; static int charstring_bufsiz; /* decryption stuff */ static uint16_t er, cr; static uint16_t c1 = 52845, c2 = 22719; /* table of charstring commands */ static struct command { const char *name; int one, two; } command_table[] = { { "abs", 12, 9 }, /* Type 2 */ { "add", 12, 10 }, /* Type 2 */ { "and", 12, 3 }, /* Type 2 */ { "blend", 16, -1 }, /* Type 2 */ { "callgsubr", 29, -1 }, /* Type 2 */ { "callother", 12, 16 }, /* Type 1 ONLY */ { "callothersubr", 12, 16 }, /* Type 1 ONLY */ { "callsubr", 10, -1 }, { "closepath", 9, -1 }, /* Type 1 ONLY */ { "cntrmask", 20, -1 }, /* Type 2 */ { "div", 12, 12 }, { "dotsection", 12, 0 }, /* Type 1 ONLY */ { "drop", 12, 18 }, /* Type 2 */ { "dup", 12, 27 }, /* Type 2 */ { "endchar", 14, -1 }, { "eq", 12, 15 }, /* Type 2 */ { "error", 0, -1 }, /* special */ { "escape", 12, -1 }, /* special */ { "exch", 12, 28 }, /* Type 2 */ { "flex", 12, 35 }, /* Type 2 */ { "flex1", 12, 37 }, /* Type 2 */ { "get", 12, 21 }, /* Type 2 */ { "hflex", 12, 34 }, /* Type 2 */ { "hflex1", 12, 36 }, /* Type 2 */ { "hhcurveto", 27, -1 }, /* Type 2 */ { "hintmask", 19, -1 }, /* Type 2 */ { "hlineto", 6, -1 }, { "hmoveto", 22, -1 }, { "hsbw", 13, -1 }, /* Type 1 ONLY */ { "hstem", 1, -1 }, { "hstem3", 12, 2 }, /* Type 1 ONLY */ { "hstemhm", 18, -1 }, /* Type 2 */ { "hvcurveto", 31, -1 }, { "ifelse", 12, 22 }, /* Type 2 */ { "index", 12, 29 }, /* Type 2 */ { "load", 12, 13 }, /* Type 2 */ { "mul", 12, 24 }, /* Type 2 */ { "neg", 12, 14 }, /* Type 2 */ { "not", 12, 5 }, /* Type 2 */ { "or", 12, 4 }, /* Type 2 */ { "pop", 12, 17 }, /* Type 1 ONLY */ { "put", 12, 20 }, /* Type 2 */ { "random", 12, 23 }, /* Type 2 */ { "rcurveline", 24, -1 }, /* Type 2 */ { "return", 11, -1 }, { "rlinecurve", 25, -1 }, /* Type 2 */ { "rlineto", 5, -1 }, { "rmoveto", 21, -1 }, { "roll", 12, 30 }, /* Type 2 */ { "rrcurveto", 8, -1 }, { "sbw", 12, 7 }, /* Type 1 ONLY */ { "seac", 12, 6 }, /* Type 1 ONLY */ { "setcurrentpoint", 12, 33 }, /* Type 1 ONLY */ { "sqrt", 12, 26 }, /* Type 2 */ { "store", 12, 8 }, /* Type 2 */ { "sub", 12, 11 }, /* Type 2 */ { "vhcurveto", 30, -1 }, { "vlineto", 7, -1 }, { "vmoveto", 4, -1 }, { "vstem", 3, -1 }, { "vstem3", 12, 1 }, /* Type 1 ONLY */ { "vstemhm", 23, -1 }, /* Type 2 */ { "vvcurveto", 26, -1 }, /* Type 2 */ }; /* alphabetical */ /* Two separate encryption functions because eexec and charstring encryption must proceed in parallel. */ static byte eencrypt(byte plain) { byte cipher; cipher = (byte)(plain ^ (er >> 8)); er = (uint16_t)((cipher + er) * c1 + c2); return cipher; } static byte cencrypt(byte plain) { byte cipher; /* Thanks to Tom Kacvinsky who reported that lenIV == -1 means unencrypted charstrings. */ if (lenIV < 0) return plain; cipher = (byte)(plain ^ (cr >> 8)); cr = (uint16_t)((cipher + cr) * c1 + c2); return cipher; } /* This function outputs a single byte. If output is in PFB format then output is buffered through blockbuf[]. If output is in PFA format, then output will be hexadecimal if in_eexec is set, ASCII otherwise. */ static void output_byte(byte b) { static const char *hexchar = "0123456789abcdef"; static int hexcol = 0; if (pfb) { /* PFB */ PFB_OUTPUT_BYTE(&w, b); } else { /* PFA */ if (in_eexec) { /* trim hexadecimal lines to `blocklen' columns */ if (hexcol >= blocklen) { putc('\n', ofp); hexcol = 0; } putc(hexchar[(b >> 4) & 0xf], ofp); putc(hexchar[b & 0xf], ofp); hexcol += 2; } else { putc(b, ofp); } } } /* This function outputs a byte through possible eexec encryption. */ static void eexec_byte(byte b) { if (in_eexec) output_byte(eencrypt(b)); else output_byte(b); } /* This function outputs a null-terminated string through possible eexec encryption. */ static void eexec_string(const char *string) { while (*string) eexec_byte(*string++); } /* This function gets ready for the eexec-encrypted data. If output is in PFB format then flush current ASCII block and get ready for binary block. We start encryption with four random (zero) bytes. */ static void eexec_start(char *string) { eexec_string("currentfile eexec\n"); if (pfb && w.blocktyp != PFB_BINARY) { pfb_writer_output_block(&w); w.blocktyp = PFB_BINARY; } in_eexec = 1; er = 55665; eexec_byte(0); eexec_byte(0); eexec_byte(0); eexec_byte(0); eexec_string(string); } /* 25.Aug.1999 -- Return 1 if this line actually looks like the start of a charstring. We use the heuristic that it should start with `/' (a name) or `dup' (a subroutine). Previous heuristic caused killa bad output. */ static int check_line_charstring(void) { char *p = line; while (isspace((unsigned char) *p)) p++; return (*p == '/' || (p[0] == 'd' && p[1] == 'u' && p[2] == 'p')); } /* This function returns an input line of characters. A line is terminated by length (including terminating null) greater than LINESIZE, \r, \n, \r\n, or when active (looking for charstrings) by '{'. When terminated by a newline the newline is put into line[]. When terminated by '{', the '{' is not put into line[], and the flag start_charstring is set to 1. */ static void t1utils_getline(void) { int c; char *p = line; int comment = 0; start_charstring = 0; while (p < line + LINESIZE) { c = getc(ifp); if (c == EOF) break; else if (c == '%') comment = 1; else if (active && !comment && c == '{') { /* 25.Aug.1999 -- new check for whether we should stop be active */ if (check_line_charstring()) { start_charstring = 1; break; } else active = 0; } *p++ = (char) c; /* end of line processing: change CR or CRLF into LF, and exit */ if (c == '\r') { c = getc(ifp); if (c != '\n') ungetc(c, ifp); p[-1] = '\n'; break; } else if (c == '\n') break; } *p = '\0'; } /* This function wraps-up the eexec-encrypted data and writes ASCII trailer. If output is in PFB format then this entails flushing binary block and starting an ASCII block. */ static void eexec_end(void) { int i, j; if (!pfb) putc('\n', ofp); else if (w.blocktyp != PFB_ASCII) { pfb_writer_output_block(&w); w.blocktyp = PFB_ASCII; } in_eexec = active = 0; for (i = 0; i < 8; i++) { for (j = 0; j < 64; j++) eexec_byte('0'); eexec_byte('\n'); } } /* This function is used by the binary search, bsearch(), for command names in the command table. */ static int CDECL command_compare(const void *key, const void *item) { return strcmp((const char *) key, ((const struct command *) item)->name); } /* This function returns 1 if the string is an integer and 0 otherwise. */ static int is_integer(char *string) { if (isdigit((unsigned char) string[0]) || string[0] == '-' || string[0] == '+') { while (*++string && isdigit((unsigned char) *string)) ; /* deliberately empty */ if (!*string) return 1; } return 0; } /* This function initializes charstring encryption. Note that this is called at the beginning of every charstring. */ static void charstring_start(void) { int i; if (!charstring_buf) { charstring_bufsiz = 65536; if (!(charstring_buf = (byte *) malloc(charstring_bufsiz))) fatal_error("out of memory"); } charstring_bp = charstring_buf; cr = 4330; for (i = 0; i < lenIV; i++) *charstring_bp++ = cencrypt((byte) 0); } /* This function encrypts and buffers a single byte of charstring data. */ static void charstring_byte(int v) { byte b = (byte)(v & 0xff); if (charstring_bp - charstring_buf == charstring_bufsiz) { charstring_bufsiz *= 2; if (!(charstring_buf = (byte *) realloc(charstring_buf, charstring_bufsiz))) fatal_error("out of memory"); charstring_bp = charstring_buf + charstring_bufsiz / 2; } *charstring_bp++ = cencrypt(b); } /* This function outputs buffered, encrypted charstring data through possible eexec encryption. */ static void charstring_end(void) { byte *bp; sprintf(line, "%d ", (int) (charstring_bp - charstring_buf)); eexec_string(line); sprintf(line, "%s ", cs_start); eexec_string(line); for (bp = charstring_buf; bp < charstring_bp; bp++) eexec_byte(*bp); } /* This function generates the charstring representation of an integer. */ static void charstring_int(int num) { int x; if (num >= -107 && num <= 107) { charstring_byte(num + 139); } else if (num >= 108 && num <= 1131) { x = num - 108; charstring_byte(x / 256 + 247); charstring_byte(x % 256); } else if (num >= -1131 && num <= -108) { x = abs(num) - 108; charstring_byte(x / 256 + 251); charstring_byte(x % 256); } else if (num >= (-2147483647-1) && num <= 2147483647) { charstring_byte(255); charstring_byte(num >> 24); charstring_byte(num >> 16); charstring_byte(num >> 8); charstring_byte(num); } else { error("can't format huge number `%d'", num); /* output 0 instead */ charstring_byte(139); } } /* This function returns one charstring token. It ignores comments. */ static void get_charstring_token(void) { int c = getc(ifp); while (isspace(c)) c = getc(ifp); if (c == '%') { while (c != EOF && c != '\r' && c != '\n') c = getc(ifp); get_charstring_token(); } else if (c == '}') { line[0] = '}'; line[1] = 0; } else { char *p = line; while (p < line + LINESIZE) { *p++ = c; c = getc(ifp); if (c == EOF || isspace(c) || c == '%' || c == '}') { ungetc(c, ifp); break; } } *p = 0; } } /* This function parses an entire charstring into integers and commands, outputting bytes through the charstring buffer. */ static void parse_charstring(void) { struct command *cp; charstring_start(); while (!feof(ifp)) { get_charstring_token(); if (line[0] == '}') break; if (is_integer(line)) { charstring_int(atoi(line)); } else { int one; int two; int ok = 0; cp = (struct command *) bsearch((void *) line, (void *) command_table, sizeof(command_table) / sizeof(struct command), sizeof(struct command), command_compare); if (cp) { one = cp->one; two = cp->two; ok = 1; } else if (strncmp(line, "escape_", 7) == 0) { /* Parse the `escape' keyword requested by Lee Chun-Yu and Werner Lemberg */ one = 12; if (sscanf(line + 7, "%d", &two) == 1) ok = 1; } else if (strncmp(line, "UNKNOWN_", 8) == 0) { /* Allow unanticipated UNKNOWN commands. */ one = 12; if (sscanf(line + 8, "12_%d", &two) == 1) ok = 1; else if (sscanf(line + 8, "%d", &one) == 1) { two = -1; ok = 1; } } if (!ok) error("unknown charstring command `%s'", line); else if (one < 0 || one > 255) error("bad charstring command number `%d'", one); else if (two > 255) error("bad charstring command number `%d'", two); else if (two < 0) charstring_byte(one); else { charstring_byte(one); charstring_byte(two); } } } charstring_end(); } /***** * Command line **/ #define BLOCK_LEN_OPT 300 #define OUTPUT_OPT 301 #define VERSION_OPT 302 #define HELP_OPT 303 #define PFB_OPT 304 #define PFA_OPT 305 static Clp_Option options[] = { { "block-length", 'l', BLOCK_LEN_OPT, Clp_ValInt, 0 }, { "help", 0, HELP_OPT, 0, 0 }, { "line-length", 0, BLOCK_LEN_OPT, Clp_ValInt, 0 }, { "output", 'o', OUTPUT_OPT, Clp_ValString, 0 }, { "pfa", 'a', PFA_OPT, 0, 0 }, { "pfb", 'b', PFB_OPT, 0, 0 }, { "version", 0, VERSION_OPT, 0, 0 }, }; static const char *program_name; void fatal_error(const char *message, ...) { va_list val; va_start(val, message); fprintf(stderr, "%s: ", program_name); vfprintf(stderr, message, val); putc('\n', stderr); va_end(val); exit(1); } void error(const char *message, ...) { va_list val; va_start(val, message); fprintf(stderr, "%s: ", program_name); vfprintf(stderr, message, val); putc('\n', stderr); va_end(val); } static void short_usage(void) { fprintf(stderr, "Usage: %s [OPTION]... [INPUT [OUTPUT]]\n\ Try `%s --help' for more information.\n", program_name, program_name); } static void usage(void) { printf("\ `T1asm' translates a human-readable version of a PostScript Type 1 font into\n\ standard PFB or PFA format. The result is written to the standard output\n\ unless an OUTPUT file is given.\n\ \n\ Usage: %s [OPTION]... [INPUT [OUTPUT]]\n\ \n\ Options:\n\ -a, --pfa Output font in ASCII (PFA) format.\n\ -b, --pfb Output font in binary (PFB) format. This is\n\ the default.\n\ -l, --block-length NUM Set max block length for PFB output.\n\ -l, --line-length NUM Set max encrypted line length for PFA output.\n\ -o, --output=FILE Write output to FILE.\n\ -h, --help Print this message and exit.\n\ --version Print version number and warranty and exit.\n\ \n\ Report bugs to .\n", program_name); } #ifdef __cplusplus } #endif int main(int argc, char *argv[]) { char *p, *q; Clp_Parser *clp = Clp_NewParser(argc, (const char * const *)argv, sizeof(options) / sizeof(options[0]), options); program_name = Clp_ProgramName(clp); /* interpret command line arguments using CLP */ while (1) { int opt = Clp_Next(clp); switch (opt) { case BLOCK_LEN_OPT: blocklen = clp->val.i; break; output_file: case OUTPUT_OPT: if (ofp) fatal_error("output file already specified"); if (strcmp(clp->vstr, "-") == 0) ofp = stdout; else if (!(ofp = fopen(clp->vstr, "w"))) fatal_error("%s: %s", clp->vstr, strerror(errno)); break; case PFB_OPT: pfb = 1; break; case PFA_OPT: pfb = 0; break; case HELP_OPT: usage(); exit(0); break; case VERSION_OPT: printf("t1asm (LCDF t1utils) %s\n", VERSION); printf("Copyright (C) 1992-2010 I. Lee Hetherington, Eddie Kohler et al.\n\ This is free software; see the source for copying conditions.\n\ There is NO warranty, not even for merchantability or fitness for a\n\ particular purpose.\n"); exit(0); break; case Clp_NotOption: if (ifp && ofp) fatal_error("too many arguments"); else if (ifp) goto output_file; if (strcmp(clp->vstr, "-") == 0) ifp = stdin; else if (!(ifp = fopen(clp->vstr, "r"))) fatal_error("%s: %s", clp->vstr, strerror(errno)); break; case Clp_Done: goto done; case Clp_BadOption: short_usage(); exit(1); break; } } done: if (!pfb) { if (blocklen == -1) blocklen = 64; else if (blocklen < 8) { blocklen = 8; error("warning: line length raised to %d", blocklen); } else if (blocklen > 1024) { blocklen = 1024; error("warning: line length lowered to %d", blocklen); } } if (!ifp) ifp = stdin; if (!ofp) ofp = stdout; if (pfb) init_pfb_writer(&w, blocklen, ofp); #if defined(_MSDOS) || defined(_WIN32) /* If we are processing a PFB (binary) output */ /* file, we must set its file mode to binary. */ if (pfb) _setmode(_fileno(ofp), _O_BINARY); #endif /* Finally, we loop until no more input. Some special things to look for are the `currentfile eexec' line, the beginning of the `/Subrs' or `/CharStrings' definition, the definition of `/lenIV', and the definition of the charstring start command which has `...string currentfile...' in it. Being careful: Check with `/Subrs' and `/CharStrings' to see that a number follows the token -- otherwise, the token is probably nested in a subroutine a la Adobe Jenson, and we shouldn't pay attention to it. Bugs: Occurrence of `/Subrs 9' in a comment will fool t1asm. Thanks to Tom Kacvinsky who reported that some fonts come without /Subrs sections and provided a patch. */ while (!feof(ifp) && !ferror(ifp)) { t1utils_getline(); if (!ever_active) { if (strncmp(line, "currentfile eexec", 17) == 0 && isspace((unsigned char) line[17])) { /* Allow arbitrary whitespace after "currentfile eexec". Thanks to Tom Kacvinsky for reporting this. Note: strlen("currentfile eexec") == 17. */ for (p = line + 18; isspace((unsigned char) *p); p++) ; eexec_start(p); continue; } else if (strncmp(line, "/lenIV", 6) == 0) { set_lenIV(line); } else if ((p = strstr(line, "string currentfile"))) { set_cs_start(line); } } if (!active) { if ((p = strstr(line, "/Subrs")) && isdigit((unsigned char) p[7])) ever_active = active = 1; else if ((p = strstr(line, "/CharStrings")) && isdigit((unsigned char) p[13])) ever_active = active = 1; } if ((p = strstr(line, "currentfile closefile"))) { /* 2/14/99 -- happy Valentine's day! -- don't look for `mark currentfile closefile'; the `mark' might be on a different line */ /* 1/3/2002 -- happy new year! -- Luc Devroye reports a failure with some printers when `currentfile closefile' is followed by space */ p += sizeof("currentfile closefile") - 1; for (q = p; isspace((unsigned char) *q) && *q != '\n'; q++) /* nada */; if (q == p && !*q) error("warning: `currentfile closefile' line too long"); else if (q != p) { if (*q != '\n') error("text after `currentfile closefile' ignored"); *p++ = '\n'; *p++ = '\0'; } eexec_string(line); break; } eexec_string(line); /* output line data */ if (start_charstring) { if (!cs_start[0]) fatal_error("couldn't find charstring start command"); parse_charstring(); } } /* Handle remaining PostScript after the eexec section */ if (in_eexec) eexec_end(); /* There may be additional code. */ while (!feof(ifp) && !ferror(ifp)) { t1utils_getline(); eexec_string(line); } if (pfb) pfb_writer_end(&w); /* the end! */ if (!ever_active) error("warning: no charstrings found in input file"); fclose(ifp); fclose(ofp); return 0; } t1utils-1.39/t1asmhelp.h000066400000000000000000000023321247370226400151310ustar00rootroot00000000000000#ifndef T1ASMHELP_H #define T1ASMHELP_H static int lenIV = 4; /* If the line contains an entry of the form `/lenIV ' then set the global lenIV to . This indicates the number of random bytes at the beginning of each charstring. */ static void set_lenIV(const char* line) { char *p = strstr(line, "/lenIV "); /* Allow lenIV to be negative. Thanks to Tom Kacvinsky */ if (p && (isdigit((unsigned char) p[7]) || p[7] == '+' || p[7] == '-')) { lenIV = atoi(p + 7); } } static const char* cs_start = ""; static void set_cs_start(const char* line) { static int cs_start_set = 0; char *p, *q, *r; if ((p = strstr(line, "string currentfile")) && strstr(line, "readstring")) { /* locate the name of the charstring start command */ for (q = p; q != line && q[-1] != '/'; --q) /* nada */; if (q != line) { for (r = q; r != p && !isspace((unsigned char) *r) && *r != '{'; ++r) /* nada */; if (cs_start_set) free((char*) cs_start); cs_start = p = malloc(r - q + 1); memcpy(p, q, r - q); p[r - q] = 0; cs_start_set = 1; } } } #endif t1utils-1.39/t1binary.1000066400000000000000000000017511247370226400147010ustar00rootroot00000000000000.ds V 1.39 .de M .BR "\\$1" "(\\$2)\\$3" .. .TH T1BINARY 1 "" "Version \*V" .SH NAME t1binary \- convert PostScript Type 1 font from ASCII to binary .SH SYNOPSIS .B t1binary \%[\fB\-l\fR \fIlength\fR] \%[\fIinput\fR [\fIoutput\fR]] .SH DESCRIPTION .B t1binary converts Adobe Type 1 font programs in PFA (hexadecimal) format to PFB (binary) format. If the file .I output is not specified output goes to the standard output. If the file .I input is not specified input comes from the standard input. .SH OPTIONS .TP 5 .BI \-\-block\-length= "length\fR, " \-l " length" Set the maximum length of sections in PFB output to .I length. The default length is as large as memory allows. .SH "SEE ALSO" .LP .M t1ascii 1 , .M t1unmac 1 , .M t1mac 1 , .M t1disasm 1 , .M t1asm 1 .LP .I "Adobe Type 1 Font Format" .SH AUTHORS Lee Hetherington (ilh@lcs.mit.edu) .br Eddie Kohler (ekohler@gmail.com) .PP Ported to Microsoft C/C++ Compiler and MS-DOS operating system by Kai-Uwe Herbing (herbing@netmbx.netmbx.de). t1utils-1.39/t1binary.c000066400000000000000000000153251247370226400147650ustar00rootroot00000000000000/* t1binary * * This program takes an Adobe Type-1 font program in ASCII (PFA) format and * converts it to binary (PFB) format. * * Copyright (c) 1992 by I. Lee Hetherington, all rights reserved. * Copyright (c) 1998-2013 Eddie Kohler * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, subject to the * conditions listed in the Click LICENSE file, which is available in full at * http://github.com/kohler/click/blob/master/LICENSE. The conditions * include: you must preserve this copyright notice, and you cannot mention * the copyright holders in advertising related to the Software without * their permission. The Software is provided WITHOUT ANY WARRANTY, EXPRESS * OR IMPLIED. This notice is a summary of the Click LICENSE file; the * license in that file is binding. * * New change log in `NEWS'. Old change log: * * Revision 1.2 92/06/23 10:58:08 ilh * MSDOS porting by Kai-Uwe Herbing (herbing@netmbx.netmbx.de) * incoporated. * * Revision 1.1 92/05/22 11:58:17 ilh * initial version * * Ported to Microsoft C/C++ Compiler and MS-DOS operating system by * Kai-Uwe Herbing (herbing@netmbx.netmbx.de) on June 12, 1992. Code * specific to the MS-DOS version is encapsulated with #ifdef _MSDOS * ... #endif, where _MSDOS is an identifier, which is automatically * defined, if you compile with the Microsoft C/C++ Compiler. * */ /* Note: this is ANSI C. */ #ifdef HAVE_CONFIG_H # include #endif #if defined(_MSDOS) || defined(_WIN32) # include # include #endif #include #include #include #include #include #include #include #include #include "t1lib.h" #ifdef __cplusplus extern "C" { #endif typedef unsigned char byte; /* for PFB block buffering */ static struct pfb_writer w; /* PFB font_reader functions */ static void pfb_output_ascii(char *s, int len) { if (w.blocktyp == PFB_BINARY) { pfb_writer_output_block(&w); w.blocktyp = PFB_ASCII; } for (; len > 0; len--, s++) PFB_OUTPUT_BYTE(&w, (byte)*s); } static void pfb_output_binary(unsigned char *s, int len) { if (w.blocktyp == PFB_ASCII) { pfb_writer_output_block(&w); w.blocktyp = PFB_BINARY; } for (; len > 0; len--, s++) PFB_OUTPUT_BYTE(&w, *s); } static void pfb_output_end(void) { pfb_writer_end(&w); } /***** * Command line **/ #define BLOCK_LEN_OPT 300 #define OUTPUT_OPT 301 #define VERSION_OPT 302 #define HELP_OPT 303 static Clp_Option options[] = { { "block-length", 'l', BLOCK_LEN_OPT, Clp_ValInt, 0 }, { "help", 0, HELP_OPT, 0, 0 }, { "length", 0, BLOCK_LEN_OPT, Clp_ValInt, 0 }, { "output", 'o', OUTPUT_OPT, Clp_ValString, 0 }, { "version", 0, VERSION_OPT, 0, 0 }, }; static const char *program_name; void fatal_error(const char *message, ...) { va_list val; va_start(val, message); fprintf(stderr, "%s: ", program_name); vfprintf(stderr, message, val); putc('\n', stderr); va_end(val); exit(1); } void error(const char *message, ...) { va_list val; va_start(val, message); fprintf(stderr, "%s: ", program_name); vfprintf(stderr, message, val); putc('\n', stderr); va_end(val); } static void short_usage(void) { fprintf(stderr, "Usage: %s [OPTION]... [INPUT [OUTPUT]]\n\ Try `%s --help' for more information.\n", program_name, program_name); } static void usage(void) { printf("\ `T1binary' translates a PostScript Type 1 font from ASCII (PFA) to compact\n\ binary (PFB) format. The result is written to the standard output unless an\n\ OUTPUT file is given.\n\ \n\ Usage: %s [OPTION]... [INPUT [OUTPUT]]\n\ \n\ Options:\n\ -l, --block-length=NUM Set max output block length.\n\ -o, --output=FILE Write output to FILE.\n\ -h, --help Print this message and exit.\n\ --version Print version number and warranty and exit.\n\ \n\ Report bugs to .\n", program_name); } #ifdef __cplusplus } #endif int main(int argc, char *argv[]) { int c; FILE *ifp = 0, *ofp = 0; const char *ifp_filename = ""; struct font_reader fr; int max_blocklen = -1; Clp_Parser *clp = Clp_NewParser(argc, (const char * const *)argv, sizeof(options) / sizeof(options[0]), options); program_name = Clp_ProgramName(clp); /* interpret command line arguments using CLP */ while (1) { int opt = Clp_Next(clp); switch (opt) { case BLOCK_LEN_OPT: max_blocklen = clp->val.i; if (max_blocklen <= 0) { max_blocklen = 1; error("warning: block length raised to %d", max_blocklen); } break; output_file: case OUTPUT_OPT: if (ofp) fatal_error("output file already specified"); if (strcmp(clp->vstr, "-") == 0) ofp = stdout; else { ofp = fopen(clp->vstr, "wb"); if (!ofp) fatal_error("%s: %s", clp->vstr, strerror(errno)); } break; case HELP_OPT: usage(); exit(0); break; case VERSION_OPT: printf("t1binary (LCDF t1utils) %s\n", VERSION); printf("Copyright (C) 1992-2010 I. Lee Hetherington, Eddie Kohler et al.\n\ This is free software; see the source for copying conditions.\n\ There is NO warranty, not even for merchantability or fitness for a\n\ particular purpose.\n"); exit(0); break; case Clp_NotOption: if (ifp && ofp) fatal_error("too many arguments"); else if (ifp) goto output_file; if (strcmp(clp->vstr, "-") == 0) ifp = stdin; else { ifp_filename = clp->vstr; ifp = fopen(clp->vstr, "r"); if (!ifp) fatal_error("%s: %s", clp->vstr, strerror(errno)); } break; case Clp_Done: goto done; case Clp_BadOption: short_usage(); exit(1); break; } } done: if (!ifp) ifp = stdin; if (!ofp) ofp = stdout; #if defined(_MSDOS) || defined(_WIN32) /* As we are processing a PFB (binary) output */ /* file, we must set its file mode to binary. */ _setmode(_fileno(ofp), _O_BINARY); #endif /* prepare font reader and pfb writer */ fr.output_ascii = pfb_output_ascii; fr.output_binary = pfb_output_binary; fr.output_end = pfb_output_end; init_pfb_writer(&w, max_blocklen, ofp); /* peek at first byte to see if it is the PFB marker 0x80 */ c = getc(ifp); ungetc(c, ifp); /* do the file */ if (c == PFB_MARKER) process_pfb(ifp, ifp_filename, &fr); else if (c == '%') process_pfa(ifp, ifp_filename, &fr); else fatal_error("%s does not start with font marker (`%%' or 0x80)", ifp_filename); fclose(ifp); fclose(ofp); if (!w.binary_blocks_written) fatal_error("no binary blocks written! Are you sure this was a font?"); return 0; } t1utils-1.39/t1disasm.1000066400000000000000000000040451247370226400146740ustar00rootroot00000000000000.ds V 1.39 .de M .BR "\\$1" "(\\$2)\\$3" .. .TH T1DISASM 1 "" "Version \*V" .SH NAME t1disasm \- disassemble PostScript Type 1 font .SH SYNOPSIS .B t1disasm \%[\fIinput\fR [\fIoutput\fR]] .SH DESCRIPTION .B t1disasm disassembles Adobe Type 1 font programs in either PFA (hexadecimal) or PFB (binary) formats into human-readable form. If the file .I output is not specified output goes to the standard output. If the file .I input is not specified input comes from the standard input. .B t1disasm performs eexec and charstring decryption as specified in the ``black book'', .I "Adobe Type 1 Font Format." Additionally, the charstring binary tokens are expanded into human-readable text form, using the names given in the black book and later documents describing Type 2 opcodes. .SH EXAMPLES .LP .nf % t1disasm Utopia-Regular.pfb Utopia-Regular.raw % t1disasm Utopia-Regular.pfa Utopia-Regular.raw .fi In .B Subrs entries in Utopia-Regular.raw will look like .RS .nf .ft B dup 5 { 8 111 vstem \-12 128 hstem 707 \-20 hstem return } | .ft R .fi .RE and the .B CharStrings entries like .RS .nf .ft B /exclam { 58 242 hsbw 6 callsubr 5 4 callsubr 63 707 rmoveto \-54 0 \-5 \-22 4 \-45 rrcurveto 40 \-431 rlineto 29 hlineto 42 431 rlineto 4 45 \-5 22 \-55 0 rrcurveto closepath 6 4 callsubr \-719 vmoveto 243 callsubr endchar } |\- .ft R .fi .RE .SH "SEE ALSO" .LP .M t1asm 1 , .M t1ascii 1 , .M t1binary 1 , .M t1unmac 1 , .M t1mac 1 .LP .I "Adobe Type 1 Font Format" is available free from Adobe as a PDF file: http://partners.adobe.com/asn/developer/PDFS/TN/T1_SPEC.PDF .LP .I "The Type 2 Charstring Format," also available from Adobe as a PDF file, describes the newer Type 2 operators, which are also used in some multiple-master Type 1 fonts like Adobe Jenson and Kepler: http://partners.adobe.com/asn/developer/PDFS/TN/5177.Type2.pdf ' .SH AUTHORS Lee Hetherington (ilh@lcs.mit.edu) .br Eddie Kohler (ekohler@gmail.com) t1utils-1.39/t1disasm.c000066400000000000000000000477011247370226400147640ustar00rootroot00000000000000/* t1disasm * * This program `disassembles' Adobe Type-1 font programs in either PFB or PFA * format. It produces a human readable/editable pseudo-PostScript file by * performing eexec and charstring decryption as specified in the `Adobe Type 1 * Font Format' version 1.1 (the `black book'). There is a companion program, * t1asm, which `assembles' such a pseudo-PostScript file into either PFB or * PFA format. * * Copyright (c) 1992 by I. Lee Hetherington, all rights reserved. * Copyright (c) 1998-2013 Eddie Kohler * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, subject to the * conditions listed in the Click LICENSE file, which is available in full at * http://github.com/kohler/click/blob/master/LICENSE. The conditions * include: you must preserve this copyright notice, and you cannot mention * the copyright holders in advertising related to the Software without * their permission. The Software is provided WITHOUT ANY WARRANTY, EXPRESS * OR IMPLIED. This notice is a summary of the Click LICENSE file; the * license in that file is binding. * * New change log in `NEWS'. Old change log: * * Revision 1.4 92/07/10 10:55:08 ilh * Added support for additional PostScript after the closefile command * (ie., some fonts have {restore}if' after the cleartomark). Also, * removed hardwired charstring start command (-| or RD) in favor of * automatically determining it. * * Revision 1.3 92/06/23 10:57:53 ilh * MSDOS porting by Kai-Uwe Herbing (herbing@netmbx.netmbx.de) * incoporated. * * Revision 1.2 92/05/22 12:05:33 ilh * Fixed bug where we were counting on sprintf to return its first * argument---not true in ANSI C. This bug was detected by Piet * Tutelaers (rcpt@urc.tue.nl). Also, fixed (signed) integer overflow * error when testing high-order bit of integer for possible * sign-extension by making comparison between unsigned integers. * * Revision 1.1 92/05/22 12:04:07 ilh * initial version * * Ported to Microsoft C/C++ Compiler and MS-DOS operating system by * Kai-Uwe Herbing (herbing@netmbx.netmbx.de) on June 12, 1992. Code * specific to the MS-DOS version is encapsulated with #ifdef _MSDOS * ... #endif, where _MSDOS is an identifier, which is automatically * defined, if you compile with the Microsoft C/C++ Compiler. * */ /* Note: this is ANSI C. */ #ifdef HAVE_CONFIG_H # include #endif #if defined(_MSDOS) || defined(_WIN32) # include # include #endif #include #include #include #include #include #include #include #include #include #include "t1lib.h" #include "t1asmhelp.h" #ifdef __cplusplus extern "C" { #endif typedef unsigned char byte; static FILE *ofp; static int unknown = 0; /* decryption stuff */ static uint16_t c1 = 52845, c2 = 22719; static uint16_t cr_default = 4330; static uint16_t er_default = 55665; static int error_count = 0; /* Subroutine to output strings. */ static void output(const char *string) { fprintf(ofp, "%s", string); } /* Subroutine to neatly format output of charstring tokens. If token = "\n", then a newline is output. If at start of line (start == 1), prefix token with tab, otherwise a space. */ static void output_token(const char *token) { static int start = 1; if (strcmp(token, "\n") == 0) { fprintf(ofp, "\n"); start = 1; } else { fprintf(ofp, "%s%s", start ? "\t" : " ", token); start = 0; } } /* Subroutine to decrypt and ASCII-ify tokens in charstring data. The charstring decryption machinery is fired up, skipping the first lenIV bytes, and the decrypted tokens are expanded into human-readable form. */ static void decrypt_charstring(unsigned char *line, int len) { int i; int32_t val; char buf[20]; /* decrypt charstring */ if (lenIV >= 0) { /* only decrypt if lenIV >= 0 -- negative lenIV means unencrypted charstring. Thanks to Tom Kacvinsky */ uint16_t cr = cr_default; byte plain; for (i = 0; i < len; i++) { byte cipher = line[i]; plain = (byte)(cipher ^ (cr >> 8)); cr = (uint16_t)((cipher + cr) * c1 + c2); line[i] = plain; } line += lenIV; len -= lenIV; } /* handle each charstring command */ for (i = 0; i < len; i++) { byte b = line[i]; if (b >= 32) { if (b >= 32 && b <= 246) val = b - 139; else if (b >= 247 && b <= 250) { i++; val = (b - 247)*256 + 108 + line[i]; } else if (b >= 251 && b <= 254) { i++; val = -(b - 251)*256 - 108 - line[i]; } else { val = (line[i+1] & 0xff) << 24; val |= (line[i+2] & 0xff) << 16; val |= (line[i+3] & 0xff) << 8; val |= (line[i+4] & 0xff) << 0; /* in case an int32 is larger than four bytes---sign extend */ #if INT_MAX > 0x7FFFFFFFUL if (val & 0x80000000) val |= ~0x7FFFFFFF; #endif i += 4; } sprintf(buf, "%d", val); output_token(buf); } else { switch (b) { case 0: output_token("error"); break; /* special */ case 1: output_token("hstem"); break; case 3: output_token("vstem"); break; case 4: output_token("vmoveto"); break; case 5: output_token("rlineto"); break; case 6: output_token("hlineto"); break; case 7: output_token("vlineto"); break; case 8: output_token("rrcurveto"); break; case 9: output_token("closepath"); break; /* Type 1 ONLY */ case 10: output_token("callsubr"); break; case 11: output_token("return"); break; case 13: output_token("hsbw"); break; /* Type 1 ONLY */ case 14: output_token("endchar"); break; case 16: output_token("blend"); break; /* Type 2 */ case 18: output_token("hstemhm"); break; /* Type 2 */ case 19: output_token("hintmask"); break; /* Type 2 */ case 20: output_token("cntrmask"); break; /* Type 2 */ case 21: output_token("rmoveto"); break; case 22: output_token("hmoveto"); break; case 23: output_token("vstemhm"); break; /* Type 2 */ case 24: output_token("rcurveline"); break; /* Type 2 */ case 25: output_token("rlinecurve"); break; /* Type 2 */ case 26: output_token("vvcurveto"); break; /* Type 2 */ case 27: output_token("hhcurveto"); break; /* Type 2 */ case 28: { /* Type 2 */ /* short integer */ val = (line[i+1] & 0xff) << 8; val |= (line[i+2] & 0xff); i += 2; if (val & 0x8000) val |= ~0x7FFF; sprintf(buf, "%d", val); output_token(buf); } case 29: output_token("callgsubr"); break; /* Type 2 */ case 30: output_token("vhcurveto"); break; case 31: output_token("hvcurveto"); break; case 12: i++; b = line[i]; switch (b) { case 0: output_token("dotsection"); break; /* Type 1 ONLY */ case 1: output_token("vstem3"); break; /* Type 1 ONLY */ case 2: output_token("hstem3"); break; /* Type 1 ONLY */ case 3: output_token("and"); break; /* Type 2 */ case 4: output_token("or"); break; /* Type 2 */ case 5: output_token("not"); break; /* Type 2 */ case 6: output_token("seac"); break; /* Type 1 ONLY */ case 7: output_token("sbw"); break; /* Type 1 ONLY */ case 8: output_token("store"); break; /* Type 2 */ case 9: output_token("abs"); break; /* Type 2 */ case 10: output_token("add"); break; /* Type 2 */ case 11: output_token("sub"); break; /* Type 2 */ case 12: output_token("div"); break; case 13: output_token("load"); break; /* Type 2 */ case 14: output_token("neg"); break; /* Type 2 */ case 15: output_token("eq"); break; /* Type 2 */ case 16: output_token("callothersubr"); break; /* Type 1 ONLY */ case 17: output_token("pop"); break; /* Type 1 ONLY */ case 18: output_token("drop"); break; /* Type 2 */ case 20: output_token("put"); break; /* Type 2 */ case 21: output_token("get"); break; /* Type 2 */ case 22: output_token("ifelse"); break; /* Type 2 */ case 23: output_token("random"); break; /* Type 2 */ case 24: output_token("mul"); break; /* Type 2 */ case 26: output_token("sqrt"); break; /* Type 2 */ case 27: output_token("dup"); break; /* Type 2 */ case 28: output_token("exch"); break; /* Type 2 */ case 29: output_token("index"); break; /* Type 2 */ case 30: output_token("roll"); break; /* Type 2 */ case 33: output_token("setcurrentpoint"); break;/* Type 1 ONLY */ case 34: output_token("hflex"); break; /* Type 2 */ case 35: output_token("flex"); break; /* Type 2 */ case 36: output_token("hflex1"); break; /* Type 2 */ case 37: output_token("flex1"); break; /* Type 2 */ default: sprintf(buf, "escape_%d", b); unknown++; output_token(buf); break; } break; default: sprintf(buf, "UNKNOWN_%d", b); unknown++; output_token(buf); break; } output_token("\n"); } } if (i > len) { output("\terror\n"); error("disassembly error: charstring too short"); } } /* Disassembly font_reader functions */ static int in_eexec = 0; static unsigned char *save = 0; static int save_len = 0; static int save_cap = 0; static void append_save(const unsigned char *line, int len) { if (line == save) { assert(len <= save_cap); save_len = len; return; } if (save_len + len >= save_cap) { unsigned char *new_save; if (!save_cap) save_cap = 1024; while (save_len + len >= save_cap) save_cap *= 2; new_save = (unsigned char *)malloc(save_cap); if (!new_save) fatal_error("out of memory"); memcpy(new_save, save, save_len); free(save); save = new_save; } memcpy(save + save_len, line, len); save_len += len; } /* 23.Feb.2004 - use 'memstr', not strstr, because the strings input to eexec_line aren't null terminated! Reported by Werner Lemberg. */ static const unsigned char * oog_memstr(const unsigned char *line, int line_len, const char *pattern, int pattern_len) { const unsigned char *try; const unsigned char *last = line + line_len - pattern_len + 1; while (line < last && (try = memchr(line, (unsigned char)*pattern, last - line))) { if (memcmp(try, pattern, pattern_len) == 0) return try; else line = try + 1; } return 0; } /* returns 1 if next \n should be deleted */ static int eexec_line(unsigned char *line, int line_len) { int cs_start_len = strlen(cs_start); int pos; int first_space; int digits; int cut_newline = 0; /* append this data to the end of `save' if necessary */ if (save_len) { append_save(line, line_len); line = save; line_len = save_len; save_len = 0; } if (!line_len) return 0; /* Look for charstring start */ /* skip first word */ for (pos = 0; pos < line_len && isspace(line[pos]); pos++) ; while (pos < line_len && !isspace(line[pos])) pos++; if (pos >= line_len) goto not_charstring; /* skip spaces */ first_space = pos; while (pos < line_len && isspace(line[pos])) pos++; if (pos >= line_len || !isdigit(line[pos])) goto not_charstring; /* skip number */ digits = pos; while (pos < line_len && isdigit(line[pos])) pos++; /* check for subr (another number) */ if (pos < line_len - 1 && isspace(line[pos]) && isdigit(line[pos+1])) { first_space = pos; digits = pos + 1; for (pos = digits; pos < line_len && isdigit(line[pos]); pos++) ; } /* check for charstring start */ if (pos + 2 + cs_start_len < line_len && pos > digits && line[pos] == ' ' && strncmp((const char *)(line + pos + 1), cs_start, cs_start_len) == 0 && line[pos + 1 + cs_start_len] == ' ') { /* check if charstring is long enough */ int cs_len = atoi((const char *)(line + digits)); if (pos + 2 + cs_start_len + cs_len < line_len) { /* long enough! */ if (line[line_len - 1] == '\r') { line[line_len - 1] = '\n'; cut_newline = 1; } fprintf(ofp, "%.*s {\n", first_space, line); decrypt_charstring(line + pos + 2 + cs_start_len, cs_len); pos += 2 + cs_start_len + cs_len; fprintf(ofp, "\t}%.*s", line_len - pos, line + pos); return cut_newline; } else { /* not long enough! */ append_save(line, line_len); return 0; } } /* otherwise, just output the line */ not_charstring: /* 6.Oct.2003 - Werner Lemberg reports a stupid Omega font that behaves badly: a charstring definition follows "/Charstrings ... begin", ON THE SAME LINE. */ { const char *CharStrings = (const char *) oog_memstr(line, line_len, "/CharStrings ", 13); int crap, n; char should_be_slash = 0; if (CharStrings && sscanf(CharStrings + 12, " %d dict dup begin %c%n", &crap, &should_be_slash, &n) >= 2 && should_be_slash == '/') { int len = (CharStrings + 12 + n - 1) - (char *) line; fprintf(ofp, "%.*s\n", len, line); return eexec_line((unsigned char *) (CharStrings + 12 + n - 1), line_len - len); } } if (line[line_len - 1] == '\r') { line[line_len - 1] = '\n'; cut_newline = 1; } set_lenIV((char *)line); set_cs_start((char *)line); fprintf(ofp, "%.*s", line_len, line); /* look for `currentfile closefile' to see if we should stop decrypting */ if (oog_memstr(line, line_len, "currentfile closefile", 21) != 0) in_eexec = -1; return cut_newline; } static int all_zeroes(const char *string) { if (*string != '0') return 0; while (*string == '0') string++; return *string == '\0' || *string == '\n'; } static void disasm_output_ascii(char *line, int len) { int was_in_eexec = in_eexec; (void) len; /* avoid warning */ in_eexec = 0; /* if we came from a binary section, we need to process that too */ if (was_in_eexec > 0) { unsigned char zero = 0; eexec_line(&zero, 0); } /* if we just came from the "ASCII part" of an eexec section, we need to process the saved lines */ if (was_in_eexec < 0) { int i = 0; int save_char = 0; /* note: save[] is unsigned char * */ while (i < save_len) { /* grab a line */ int start = i; while (i < save_len && save[i] != '\r' && save[i] != '\n') i++; if (i < save_len) { if (i < save_len - 1 && save[i] == '\r' && save[i+1] == '\n') save_char = -1; else save_char = save[i+1]; save[i] = '\n'; save[i+1] = 0; } else save[i] = 0; /* output it */ disasm_output_ascii((char *)(save + start), -1); /* repair damage */ if (i < save_len) { if (save_char >= 0) { save[i+1] = save_char; i++; } else i += 2; } } save_len = 0; } if (!all_zeroes(line)) output(line); } /* collect until '\n' or end of binary section */ static void disasm_output_binary(unsigned char *data, int len) { static int ignore_newline; static uint16_t er; byte plain; int i; /* in the ASCII portion of a binary section, just save this data */ if (in_eexec < 0) { append_save(data, len); return; } /* eexec initialization */ if (in_eexec == 0) { er = er_default; ignore_newline = 0; in_eexec = 0; } if (in_eexec < 4) { for (i = 0; i < len && in_eexec < 4; i++, in_eexec++) { byte cipher = data[i]; plain = (byte)(cipher ^ (er >> 8)); er = (uint16_t)((cipher + er) * c1 + c2); data[i] = plain; } data += i; len -= i; } /* now make lines: collect until '\n' or '\r' and pass them off to eexec_line. */ i = 0; while (in_eexec > 0) { int start = i; for (; i < len; i++) { byte cipher = data[i]; plain = (byte)(cipher ^ (er >> 8)); er = (uint16_t)((cipher + er) * c1 + c2); data[i] = plain; if (plain == '\r' || plain == '\n') break; } if (ignore_newline && start < i && data[start] == '\n') { ignore_newline = 0; continue; } if (i >= len) { if (start < len) append_save(data + start, i - start); break; } i++; ignore_newline = eexec_line(data + start, i - start); } /* if in_eexec < 0, we have some plaintext lines sitting around in a binary section of the PFB. save them for later */ if (in_eexec < 0 && i < len) append_save(data + i, len - i); } static void disasm_output_end(void) { /* take care of leftover saved data */ static char crap[1] = ""; disasm_output_ascii(crap, 0); } /***** * Command line **/ #define OUTPUT_OPT 301 #define VERSION_OPT 302 #define HELP_OPT 303 static Clp_Option options[] = { { "help", 0, HELP_OPT, 0, 0 }, { "output", 'o', OUTPUT_OPT, Clp_ValString, 0 }, { "version", 0, VERSION_OPT, 0, 0 }, }; static const char *program_name; void fatal_error(const char *message, ...) { va_list val; va_start(val, message); fprintf(stderr, "%s: ", program_name); vfprintf(stderr, message, val); fputc('\n', stderr); va_end(val); exit(1); } void error(const char *message, ...) { va_list val; va_start(val, message); fprintf(stderr, "%s: ", program_name); vfprintf(stderr, message, val); fputc('\n', stderr); error_count++; va_end(val); } static void short_usage(void) { fprintf(stderr, "Usage: %s [INPUT [OUTPUT]]\n\ Try `%s --help' for more information.\n", program_name, program_name); } static void usage(void) { printf("\ `T1disasm' translates a PostScript Type 1 font in PFB or PFA format into a\n\ human-readable, human-editable form. The result is written to the standard\n\ output unless an OUTPUT file is given.\n\ \n\ Usage: %s [OPTION]... [INPUT [OUTPUT]]\n\ \n\ Options:\n\ -o, --output=FILE Write output to FILE.\n\ -h, --help Print this message and exit.\n\ --version Print version number and warranty and exit.\n\ \n\ Report bugs to .\n", program_name); } #ifdef __cplusplus } #endif int main(int argc, char *argv[]) { struct font_reader fr; int c; FILE *ifp = 0; const char *ifp_filename = ""; Clp_Parser *clp = Clp_NewParser(argc, (const char * const *)argv, sizeof(options) / sizeof(options[0]), options); program_name = Clp_ProgramName(clp); /* interpret command line arguments using CLP */ while (1) { int opt = Clp_Next(clp); switch (opt) { output_file: case OUTPUT_OPT: if (ofp) fatal_error("output file already specified"); if (strcmp(clp->vstr, "-") == 0) ofp = stdout; else { ofp = fopen(clp->vstr, "w"); if (!ofp) fatal_error("%s: %s", clp->vstr, strerror(errno)); } break; case HELP_OPT: usage(); exit(0); break; case VERSION_OPT: printf("t1disasm (LCDF t1utils) %s\n", VERSION); printf("Copyright (C) 1992-2010 I. Lee Hetherington, Eddie Kohler et al.\n\ This is free software; see the source for copying conditions.\n\ There is NO warranty, not even for merchantability or fitness for a\n\ particular purpose.\n"); exit(0); break; case Clp_NotOption: if (ifp && ofp) fatal_error("too many arguments"); else if (ifp) goto output_file; if (strcmp(clp->vstr, "-") == 0) ifp = stdin; else { ifp_filename = clp->vstr; ifp = fopen(clp->vstr, "rb"); if (!ifp) fatal_error("%s: %s", clp->vstr, strerror(errno)); } break; case Clp_Done: goto done; case Clp_BadOption: short_usage(); exit(1); break; } } done: if (!ifp) ifp = stdin; if (!ofp) ofp = stdout; #if defined(_MSDOS) || defined(_WIN32) /* As we might be processing a PFB (binary) input file, we must set its file mode to binary. */ _setmode(_fileno(ifp), _O_BINARY); #endif /* prepare font reader */ fr.output_ascii = disasm_output_ascii; fr.output_binary = disasm_output_binary; fr.output_end = disasm_output_end; /* peek at first byte to see if it is the PFB marker 0x80 */ c = getc(ifp); ungetc(c, ifp); /* do the file */ if (c == PFB_MARKER) process_pfb(ifp, ifp_filename, &fr); else if (c == '%') process_pfa(ifp, ifp_filename, &fr); else fatal_error("%s does not start with font marker (`%%' or 0x80)", ifp_filename); fclose(ifp); fclose(ofp); if (unknown) error((unknown > 1 ? "encountered %d unknown charstring commands" : "encountered %d unknown charstring command"), unknown); return (error_count ? 1 : 0); } t1utils-1.39/t1lib.c000066400000000000000000000307051247370226400142460ustar00rootroot00000000000000/* t1lib * * This file contains functions for reading PFA and PFB files. * * Copyright (c) 1998-2013 Eddie Kohler * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, subject to the * conditions listed in the Click LICENSE file, which is available in full at * http://github.com/kohler/click/blob/master/LICENSE. The conditions * include: you must preserve this copyright notice, and you cannot mention * the copyright holders in advertising related to the Software without * their permission. The Software is provided WITHOUT ANY WARRANTY, EXPRESS * OR IMPLIED. This notice is a summary of the Click LICENSE file; the * license in that file is binding. */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include #include #include "t1lib.h" #ifdef __cplusplus extern "C" { #endif #define PFA_ASCII 1 #define PFA_EEXEC_TEST 2 #define PFA_HEX 3 #define PFA_BINARY 4 /* This function returns the value (0-15) of a single hex digit. It returns 0 for an invalid hex digit. */ static int hexval(char c) { if (c >= 'A' && c <= 'F') return c - 'A' + 10; else if (c >= 'a' && c <= 'f') return c - 'a' + 10; else if (c >= '0' && c <= '9') return c - '0'; else return 0; } /* This function translates a string of hexadecimal digits into binary data. We allow an odd number of digits. Returns length of binary data. */ static int translate_hex_string(char *s, char *saved_orphan) { int c1 = *saved_orphan; char *start = s; char *t = s; for (; *s; s++) { if (isspace((unsigned char) *s)) continue; if (c1) { *t++ = (hexval(c1) << 4) + hexval(*s); c1 = 0; } else c1 = *s; } *saved_orphan = c1; return t - start; } /* This function returns 1 if the string contains all '0's. */ static int all_zeroes(char *s) { if (*s == '\0' || *s == '\n') return 0; while (*s == '0') s++; return *s == '\0' || *s == '\n'; } /* This function handles the entire file. */ #define LINESIZE 1024 void process_pfa(FILE *ifp, const char *ifp_filename, struct font_reader *fr) { /* Loop until no more input. We need to look for `currentfile eexec' to start eexec section (hex to binary conversion) and line of all zeros to switch back to ASCII. */ /* Don't use fgets() in case line-endings are indicated by bare \r's, as occurs in Macintosh fonts. */ /* 2.Aug.1999 - At the behest of Tom Kacvinsky , support binary PFA fonts. */ char buffer[LINESIZE]; int c = 0; int blocktyp = PFA_ASCII; char saved_orphan = 0; (void)ifp_filename; while (c != EOF) { char *line = buffer, *last = buffer; int crlf = 0; c = getc(ifp); while (c != EOF && c != '\r' && c != '\n' && last < buffer + LINESIZE - 1) { *last++ = c; c = getc(ifp); } /* handle the end of the line */ if (last == buffer + LINESIZE - 1) /* buffer overrun: don't append newline even if we have it */ ungetc(c, ifp); else if (c == '\r' && blocktyp != PFA_BINARY) { /* change CR or CR/LF into LF, unless reading binary data! (This condition was wrong before, caused Thanh problems - 6.Mar.2001) */ c = getc(ifp); if (c != '\n') ungetc(c, ifp), crlf = 1; else crlf = 2; *last++ = '\n'; } else if (c != EOF) *last++ = c; *last = 0; /* now that we have the line, handle it */ if (blocktyp == PFA_ASCII) { if (strncmp(line, "currentfile eexec", 17) == 0 && isspace((unsigned char) line[17])) { char saved_p; /* assert(line == buffer); */ for (line += 18; isspace((unsigned char) *line); line++) /* nada */; saved_p = *line; *line = 0; fr->output_ascii(buffer, line - buffer); *line = saved_p; blocktyp = PFA_EEXEC_TEST; if (!*line) continue; } else { fr->output_ascii(line, last - line); continue; } } /* check immediately after "currentfile eexec" for ASCII or binary */ if (blocktyp == PFA_EEXEC_TEST) { /* 8.Feb.2004: fix bug if first character in a binary eexec block is 0, reported by Werner Lemberg */ for (; line < last && isspace((unsigned char) *line); line++) /* nada */; if (line == last) continue; else if (last >= line + 4 && isxdigit((unsigned char) line[0]) && isxdigit((unsigned char) line[1]) && isxdigit((unsigned char) line[2]) && isxdigit((unsigned char) line[3])) blocktyp = PFA_HEX; else blocktyp = PFA_BINARY; memmove(buffer, line, last - line + 1); last = buffer + (last - line); line = buffer; /* patch up crlf fix */ if (blocktyp == PFA_BINARY && crlf) { last[-1] = '\r'; if (crlf == 2) *last++ = '\n'; } } /* blocktyp == PFA_HEX || blocktyp == PFA_BINARY */ if (all_zeroes(line)) { /* XXX not safe */ fr->output_ascii(line, last - line); blocktyp = PFA_ASCII; } else if (blocktyp == PFA_HEX) { int len = translate_hex_string(line, &saved_orphan); if (len) fr->output_binary((unsigned char *)line, len); } else fr->output_binary((unsigned char *)line, last - line); } fr->output_end(); } /* Process a PFB file. */ /* XXX Doesn't handle "currentfile eexec" as intelligently as process_pfa does. */ static int handle_pfb_ascii(struct font_reader *fr, char *line, int len) { /* Divide PFB_ASCII blocks into lines */ int start = 0; while (1) { int pos = start; while (pos < len && line[pos] != '\n' && line[pos] != '\r') pos++; if (pos >= len) { if (pos == start) return 0; else if (start == 0 && pos == LINESIZE - 1) { line[pos] = 0; fr->output_ascii(line, pos); return 0; } else { memmove(line, line + start, pos - start); return pos - start; } } else if (pos < len - 1 && line[pos] == '\r' && line[pos+1] == '\n') { line[pos] = '\n'; line[pos+1] = 0; fr->output_ascii(line + start, pos + 1 - start); start = pos + 2; } else { char save = line[pos+1]; line[pos] = '\n'; line[pos+1] = 0; fr->output_ascii(line + start, pos + 1 - start); line[pos+1] = save; start = pos + 1; } } } void process_pfb(FILE *ifp, const char *ifp_filename, struct font_reader *fr) { int blocktyp = 0; unsigned block_len = 0; int c = 0; unsigned filepos = 0; int linepos = 0; char line[LINESIZE]; while (1) { while (block_len == 0) { c = getc(ifp); blocktyp = getc(ifp); if (c != PFB_MARKER || (blocktyp != PFB_ASCII && blocktyp != PFB_BINARY && blocktyp != PFB_DONE)) { if (c == EOF || blocktyp == EOF) error("%s corrupted: no end-of-file marker", ifp_filename); else error("%s corrupted: bad block marker at position %u", ifp_filename, filepos); blocktyp = PFB_DONE; } if (blocktyp == PFB_DONE) goto done; block_len = getc(ifp) & 0xFF; block_len |= (getc(ifp) & 0xFF) << 8; block_len |= (getc(ifp) & 0xFF) << 16; block_len |= (unsigned) (getc(ifp) & 0xFF) << 24; if (feof(ifp)) { error("%s corrupted: bad block length at position %u", ifp_filename, filepos); blocktyp = PFB_DONE; goto done; } filepos += 6; } /* read the block in its entirety, in LINESIZE chunks */ while (block_len > 0) { unsigned rest = LINESIZE - 1 - linepos; /* leave space for '\0' */ unsigned n = (block_len > rest ? rest : block_len); int actual = fread(line + linepos, 1, n, ifp); if (actual != (int) n) { error("%s corrupted: block short by %u bytes at position %u", ifp_filename, block_len - actual, filepos); block_len = actual; } if (blocktyp == PFB_BINARY) fr->output_binary((unsigned char *)line, actual); else linepos = handle_pfb_ascii(fr, line, linepos + actual); block_len -= actual; filepos += actual; } /* handle any leftover line */ if (linepos > 0) { line[linepos] = 0; fr->output_ascii(line, linepos); linepos = 0; } } done: c = getc(ifp); if (c != EOF) error("%s corrupted: data after PFB end marker at position %u", ifp_filename, filepos - 2); fr->output_end(); } #define DEFAULT_BLOCKLEN (1L<<12) void init_pfb_writer(struct pfb_writer *w, int blocklen, FILE *f) { w->len = DEFAULT_BLOCKLEN; w->buf = (unsigned char *)malloc(w->len); if (!w->buf) fatal_error("out of memory"); w->max_len = (blocklen <= 0 ? 0xFFFFFFFFU : (unsigned)blocklen); w->pos = 0; w->blocktyp = PFB_ASCII; w->binary_blocks_written = 0; w->f = f; } void pfb_writer_output_block(struct pfb_writer *w) { /* do nothing if nothing in block */ if (w->pos == 0) return; /* output four-byte block length */ putc(PFB_MARKER, w->f); putc(w->blocktyp, w->f); putc((int)(w->pos & 0xff), w->f); putc((int)((w->pos >> 8) & 0xff), w->f); putc((int)((w->pos >> 16) & 0xff), w->f); putc((int)((w->pos >> 24) & 0xff), w->f); /* output block data */ fwrite(w->buf, 1, w->pos, w->f); /* mark block buffer empty and uninitialized */ w->pos = 0; if (w->blocktyp == PFB_BINARY) w->binary_blocks_written++; } void pfb_writer_grow_buf(struct pfb_writer *w) { if (w->len < w->max_len) { /* grow w->buf */ unsigned new_len = w->len * 2; unsigned char *new_buf; if (new_len > w->max_len) new_len = w->max_len; new_buf = (unsigned char *)malloc(new_len); if (!new_buf) { error("out of memory; continuing with a smaller block size"); w->max_len = w->len; pfb_writer_output_block(w); } else { memcpy(new_buf, w->buf, w->len); free(w->buf); w->buf = new_buf; w->len = new_len; } } else /* buf already the right size, just output the block */ pfb_writer_output_block(w); } void pfb_writer_end(struct pfb_writer *w) { if (w->pos) pfb_writer_output_block(w); putc(PFB_MARKER, w->f); putc(PFB_DONE, w->f); } /* This CRC table and routine were borrowed from macutils-2.0b3 */ static unsigned short crctab[256] = { 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7, 0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF, 0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6, 0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE, 0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485, 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D, 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4, 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC, 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823, 0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B, 0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12, 0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A, 0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41, 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49, 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70, 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78, 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F, 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067, 0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E, 0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256, 0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D, 0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, 0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C, 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634, 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB, 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3, 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A, 0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92, 0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9, 0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1, 0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8, 0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0, }; /* * Update a CRC check on the given buffer. */ int crcbuf(int crc, unsigned int len, const char *buf) { const unsigned char *ubuf = (const unsigned char *)buf; while (len--) crc = ((crc << 8) & 0xFF00) ^ crctab[((crc >> 8) & 0xFF) ^ *ubuf++]; return crc; } #ifdef __cplusplus } #endif t1utils-1.39/t1lib.h000066400000000000000000000023711247370226400142510ustar00rootroot00000000000000#ifndef T1LIB_H #define T1LIB_H #ifdef __cplusplus extern "C" { #endif #ifdef WIN32 # pragma warning (disable: 4007 4096) # define CDECL __cdecl #else # define CDECL #endif #define PFB_MARKER 128 #define PFB_ASCII 1 #define PFB_BINARY 2 #define PFB_DONE 3 struct font_reader { void (*output_ascii)(char *, int); void (*output_binary)(unsigned char *, int); void (*output_end)(); }; void process_pfa(FILE *, const char *filename, struct font_reader *); void process_pfb(FILE *, const char *filename, struct font_reader *); struct pfb_writer { unsigned char *buf; unsigned len; unsigned max_len; unsigned pos; int blocktyp; int binary_blocks_written; FILE *f; }; void init_pfb_writer(struct pfb_writer *, int, FILE *); void pfb_writer_output_block(struct pfb_writer *); void pfb_writer_grow_buf(struct pfb_writer *); void pfb_writer_end(struct pfb_writer *); #define PFB_OUTPUT_BYTE(w, b) do { \ if ((w)->pos >= (w)->len) pfb_writer_grow_buf(w); \ (w)->buf[(w)->pos++] = (b); \ } while (0) int crcbuf(int crc, unsigned int len, const char *buf); /* whoever uses this code must provide a definition for these functions */ extern void error(const char *, ...); extern void fatal_error(const char *, ...); #ifdef __cplusplus } #endif #endif t1utils-1.39/t1mac.1000066400000000000000000000035531247370226400141570ustar00rootroot00000000000000.ds V 1.39 .de M .BR "\\$1" "(\\$2)\\$3" .. .TH T1MAC 1 "" "Version \*V" .SH NAME t1mac \- translate a PFA or PFB PostScript Type 1 font into Macintosh format .SH SYNOPSIS .B t1mac \%[\fB\-\-macbinary\fR | \fB\-\-applesingle\fR | \fB\-\-appledouble\fR | \fB\-\-binhex\fR | \fB\-\-raw\fR] \%[\fB\-\-filename\fR \fIname\fR] \%[\fIinput\fR [\fIoutput\fR]] .SH DESCRIPTION .B t1mac reads a PFA (hexadecimal) or PFB (binary) PostScript Type 1 font file and generates an equivalent Macintosh Type 1 font file. The output file can be in MacBinary II, AppleSingle, AppleDouble, or BinHex format, or it can be a raw resource fork. The default is MacBinary II; use an option to choose a different format. If the .I output file is not specified output goes to the standard output. .PP WARNING: The output of .B t1mac is not sufficient to use the font, since Macintoshes can't read raw Type 1 fonts. You will need to create a font suitcase containing bitmap fonts if you do not have such a suitcase for the font already. .B t1mac cannot help you do this. .SH OPTIONS .TP 5 .BR \-\-raw ", " \-r Indicates that output should be a raw resource fork. .TP 5 .BR \-\-macbinary Indicates that output should be in MacBinary I or II format. This is the default. .TP 5 .BR \-\-applesingle Indicates that output should be in AppleSingle format. .TP 5 .BR \-\-appledouble Indicates that output should be in AppleDouble format. .TP 5 .BR \-\-binhex Indicates that output should be in BinHex 4.0 format. .TP 5 .BR \-\-filename "=\fIname\fR, " \-n " \fIname\fR" Sets the Macintosh filename of the output font to \fIname\fR. The default is to construct the filename from the font's name using established Macintosh conventions. This option is not useful when output is a raw resource fork. .SH "SEE ALSO" .LP .M t1unmac 1 , .M t1ascii 1 , .M t1binary 1 , .M t1asm 1 , .M t1disasm 1 .SH AUTHORS Eddie Kohler (ekohler@gmail.com) t1utils-1.39/t1mac.c000066400000000000000000000743001247370226400142370ustar00rootroot00000000000000/* t1mac * * This program converts Type 1 fonts in PFA or PFB format into Macintosh Type * 1 fonts stored in MacBinary (I or II), AppleSingle, AppleDouble, BinHex, or * raw resource fork format. * * Copyright (c) 2000-2013 Eddie Kohler * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, subject to the * conditions listed in the Click LICENSE file, which is available in full at * http://github.com/kohler/click/blob/master/LICENSE. The conditions * include: you must preserve this copyright notice, and you cannot mention * the copyright holders in advertising related to the Software without * their permission. The Software is provided WITHOUT ANY WARRANTY, EXPRESS * OR IMPLIED. This notice is a summary of the Click LICENSE file; the * license in that file is binding. */ #ifdef HAVE_CONFIG_H # include #endif #if defined(_MSDOS) || defined(_WIN32) # include # include #endif #include #include #include #include #include #include #include #include #include #include "t1lib.h" #ifdef __cplusplus extern "C" { #endif typedef unsigned char byte; /* resource fork layout */ #define RFORK_HEADERLEN 256 #define RFORK_MAP_RESERVEDLEN 22 #define RFORK_MAP_HEADERLEN 28 #define RFORK_RTYPE_LEN 8 #define RFORK_RSRC_LEN 12 /* Macintosh times are # seconds since 1/1/1904, not 1/1/1970 */ #define MAC_TIME_DELTA 2082844800 /* POST resource information */ #define POST_ASCII 1 #define POST_BINARY 2 #define POST_END 5 /* Adobe font file information */ #define T1_FILETYPE 0x4C57464E /* LWFN */ #define T1_FILECREATOR 0x54315554 /* T1UT */ #define T1_FINDERFLAGS 33 /* Bundle + Inited */ #define MAX_RSRC_LEN 2048 static byte rbuf[MAX_RSRC_LEN]; static int rbufpos; static int blocktyp; static char *font_name; /* information about the resources being built */ typedef struct Rsrc { int32_t type; int id; int attrs; int data_offset; uint32_t data_len; int next_in_type; int next_type; } Rsrc; static Rsrc *rsrc = 0; static int nrsrc = 0; static int rsrc_cap = 0; static int cur_post_id = 0; /* output resource fork */ static FILE *rfork_f = 0; /* ICN# data */ static const unsigned char icon_bw_data[] = { 0,0,0,0,255,255,255,255,128,0,0,1,128,0,0,1,128,0,0,1, 128,0,0,1,128,0,0,1,128,0,0,1,128,0,0,1,128,0,0,33, 128,0,0,97,128,0,0,225,128,0,1,225,128,0,3,225,128,0,7,225, 128,0,15,225,128,0,31,225,128,0,55,225,159,128,103,249,144,128,199,9, 240,129,135,15,0,131,7,0,0,134,7,0,15,140,7,240,8,31,255,240, 8,63,255,240,8,96,7,240,8,192,7,240,9,192,15,240,11,224,31,240, 15,240,63,240,15,255,255,240,0,0,0,0,255,255,255,255,255,255,255,255, 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 255,255,255,255,240,255,255,15,240,255,255,15,0,255,255,0,0,255,255,0, 15,255,255,240,15,255,255,240,15,255,255,240,15,255,255,240,15,255,255,240, 15,255,255,240,15,255,255,240,15,255,255,240,15,255,255,240,}; static const unsigned char small_icon_bw_data[] = { 255,255,128,1,128,1,128,1,128,5,128,13,128,29,128,61,128,125,184,253, 201,179,59,60,39,252,44,60,60,124,63,252,255,255,255,255,255,255,255,255, 255,255,255,255,255,255,255,255,255,255,255,255,207,243,63,252,63,252,63,252, 63,252,63,252,}; static const unsigned char icon_8_data[] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,92,92,92,92,92,92,92,92, 92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92, 92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92, 92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,105,92,92,92,92, 92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92, 92,92,92,92,92,92,92,105,92,92,92,92,92,92,92,92,92,92,92,92, 92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,105, 92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92, 92,92,92,92,92,92,92,92,92,92,92,105,92,92,92,92,92,92,92,92, 92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92, 92,92,92,105,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92, 92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,105,92,92,92,92, 92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92, 92,92,92,92,92,92,92,105,92,92,92,92,92,92,92,92,92,92,92,92, 92,92,92,92,92,92,92,92,92,92,92,92,92,92,5,92,92,92,92,105, 92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92, 92,92,92,92,92,5,5,92,92,92,92,105,92,92,92,92,92,92,92,92, 92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,5,5,5,92, 92,92,92,105,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92, 92,92,92,92,92,92,92,5,5,5,5,92,92,92,92,105,92,92,92,92, 92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,5,5, 5,5,5,92,92,92,92,105,92,92,92,92,92,92,92,92,92,92,92,92, 92,92,92,92,92,92,92,92,92,5,5,5,5,5,5,92,92,92,92,105, 92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92, 5,5,5,5,5,5,5,92,92,92,92,105,92,92,92,92,92,92,92,92, 92,92,92,92,92,92,92,92,92,92,92,5,5,5,5,5,5,5,5,92, 92,92,92,105,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92, 92,92,5,5,92,5,5,5,5,5,5,92,92,92,92,105,92,92,92,105, 105,105,105,105,92,92,92,92,92,92,92,92,92,5,5,92,92,5,5,105, 105,105,105,105,92,92,92,105,92,92,92,105,0,0,0,0,92,92,92,92, 92,92,92,92,5,5,92,92,92,5,5,105,0,0,0,0,92,92,92,105, 105,105,105,105,0,0,0,0,92,92,92,92,92,92,92,5,5,92,92,92, 92,5,5,105,0,0,0,0,105,105,105,105,0,0,0,0,0,0,0,0, 92,92,92,92,92,92,5,5,92,92,92,92,92,5,5,105,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,92,92,92,92,92,5,5,92, 92,92,92,92,92,5,5,105,0,0,0,0,0,0,0,0,0,0,0,0, 92,92,92,92,92,92,92,92,5,5,92,92,92,92,92,92,92,5,5,5, 5,5,5,92,0,0,0,0,0,0,0,0,92,92,92,92,92,92,92,5, 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,105,0,0,0,0, 0,0,0,0,92,92,92,92,92,92,5,5,5,5,5,5,5,5,5,5, 5,5,5,5,5,5,5,105,0,0,0,0,0,0,0,0,92,92,92,92, 92,5,5,92,92,92,92,92,92,92,92,92,92,5,5,5,5,5,5,105, 0,0,0,0,0,0,0,0,92,92,92,92,5,5,92,92,92,92,92,92, 92,92,92,92,92,5,5,5,5,5,5,105,0,0,0,0,0,0,0,0, 92,92,92,5,5,5,92,92,92,92,92,92,92,92,92,92,5,5,5,5, 5,5,5,105,0,0,0,0,0,0,0,0,92,92,5,5,5,5,5,92, 92,92,92,92,92,92,92,5,5,5,5,5,5,5,5,105,0,0,0,0, 0,0,0,0,92,5,5,5,5,5,5,5,92,92,92,92,92,92,5,5, 5,5,5,5,5,5,5,105,0,0,0,0,0,0,0,0,92,105,105,105, 105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105, 0,0,0,0,}; static const unsigned char small_icon_8_data[] = { 92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92, 92,92,92,92,92,92,92,92,92,92,92,105,92,92,92,92,92,92,92,92, 92,92,92,92,92,92,92,105,92,92,92,92,92,92,92,92,92,92,92,92, 92,92,92,105,92,92,92,92,92,92,92,92,92,92,92,92,92,5,92,105, 92,92,92,92,92,92,92,92,92,92,92,92,5,5,92,105,92,92,92,92, 92,92,92,92,92,92,92,5,5,5,92,105,92,92,92,92,92,92,92,92, 92,92,5,5,5,5,92,105,92,92,92,92,92,92,92,92,92,5,92,5, 5,5,92,105,92,105,105,105,92,92,92,92,5,92,92,5,105,105,92,105, 92,105,0,0,92,92,92,5,92,92,92,5,0,0,105,105,0,0,92,92, 92,92,5,92,92,92,92,5,5,5,0,0,0,0,92,92,92,5,5,5, 5,5,5,5,5,5,0,0,0,0,92,92,5,92,92,92,92,92,92,5, 5,5,0,0,0,0,92,5,5,92,92,92,92,92,5,5,5,5,0,0, 0,0,5,5,5,5,105,105,105,5,5,5,5,5,0,0,}; static const unsigned char icon_4_data[] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,69,69,69,69, 69,69,69,69,69,69,69,69,69,69,69,69,84,84,84,84,84,84,84,84, 84,84,84,84,84,84,84,85,69,69,69,69,69,69,69,69,69,69,69,69, 69,69,69,69,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,85, 69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,84,84,84,84, 84,84,84,84,84,84,84,84,84,84,84,85,69,69,69,69,69,69,69,69, 69,69,69,69,69,69,69,69,84,84,84,84,84,84,84,84,84,84,84,84, 84,84,84,85,69,69,69,69,69,69,69,69,69,69,69,69,69,21,69,69, 84,84,84,84,84,84,84,84,84,84,84,84,81,20,84,85,69,69,69,69, 69,69,69,69,69,69,69,69,17,21,69,69,84,84,84,84,84,84,84,84, 84,84,84,81,17,20,84,85,69,69,69,69,69,69,69,69,69,69,69,17, 17,21,69,69,84,84,84,84,84,84,84,84,84,84,81,17,17,20,84,85, 69,69,69,69,69,69,69,69,69,69,17,17,17,21,69,69,84,84,84,84, 84,84,84,84,84,81,17,17,17,20,84,85,69,69,69,69,69,69,69,69, 69,17,65,17,17,21,69,69,84,85,85,85,84,84,84,84,81,20,81,21, 85,85,84,85,69,69,0,0,69,69,69,69,17,69,65,21,0,0,69,69, 85,85,0,0,84,84,84,81,20,84,81,21,0,0,85,85,0,0,0,0, 69,69,69,17,69,69,65,21,0,0,0,0,0,0,0,0,84,84,81,20, 84,84,81,21,0,0,0,0,0,0,69,69,69,69,17,69,69,69,65,17, 17,30,0,0,0,0,84,84,84,81,17,17,17,17,17,17,17,21,0,0, 0,0,69,69,69,17,17,17,17,17,17,17,17,21,0,0,0,0,84,84, 81,20,84,84,84,84,81,17,17,21,0,0,0,0,69,69,17,69,69,69, 69,69,65,17,17,21,0,0,0,0,84,81,17,84,84,84,84,84,17,17, 17,21,0,0,0,0,69,17,17,21,69,69,69,65,17,17,17,21,0,0, 0,0,81,17,17,17,84,84,84,17,17,17,17,21,0,0,0,0,229,85, 85,85,85,85,85,85,85,85,85,85,0,0,}; static const unsigned char small_icon_4_data[] = { 84,84,84,84,84,84,84,85,69,69,69,69,69,69,69,69,84,84,84,84, 84,84,84,85,69,69,69,69,69,69,69,69,84,84,84,84,84,84,81,85, 69,69,69,69,69,69,17,69,84,84,84,84,84,81,17,85,69,69,69,69, 69,17,17,69,84,84,84,84,81,81,17,85,69,85,69,69,21,65,85,69, 85,0,84,81,84,81,0,85,0,69,69,21,69,65,17,0,0,84,81,17, 17,17,17,0,0,69,21,69,69,65,17,0,0,81,20,84,84,17,17,0, 0,17,17,85,81,17,17,0,}; /* fseek with fatal_error */ static void reposition(FILE *fi, int32_t absolute) { if (fseek(fi, absolute, 0) == -1) fatal_error("can't seek to position %d", absolute); } /* Some functions to write one, two, three, and four byte integers in 68000 byte order (most significant byte first). */ static void write_one(int c, FILE *f) { putc(c, f); } static void write_two(int c, FILE *f) { putc((c >> 8) & 255, f); putc(c & 255, f); } static void write_three(int32_t c, FILE *f) { putc((c >> 16) & 255, f); putc((c >> 8) & 255, f); putc(c & 255, f); } static void write_four(int32_t c, FILE *f) { putc((c >> 24) & 255, f); putc((c >> 16) & 255, f); putc((c >> 8) & 255, f); putc(c & 255, f); } /* Some functions to store one, two, three, and four byte integers in 68000 byte order (most significant byte first). */ static void store_one(int c, char *s) { s[0] = (char)(c & 255); } static void store_two(int c, char *s) { s[0] = (char)((c >> 8) & 255); s[1] = (char)(c & 255); } static void store_four(int32_t c, char *s) { s[0] = (char)((c >> 24) & 255); s[1] = (char)((c >> 16) & 255); s[2] = (char)((c >> 8) & 255); s[3] = (char)(c & 255); } static void output_new_rsrc(const char *rtype, int rid, int attrs, const char *data, uint32_t len) { Rsrc *r; if (nrsrc >= rsrc_cap) { rsrc_cap = (rsrc_cap ? rsrc_cap * 2 : 256); r = (Rsrc *)malloc(sizeof(Rsrc) * rsrc_cap); if (!r) fatal_error("out of memory"); memcpy(r, rsrc, sizeof(Rsrc) * nrsrc); free(rsrc); rsrc = r; } r = &rsrc[nrsrc]; nrsrc++; /* prepare resource record */ { const unsigned char *b = (const unsigned char *)rtype; r->type = (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3]; } r->id = rid; r->attrs = attrs; if (nrsrc == 1) r->data_offset = 0; else r->data_offset = rsrc[nrsrc-2].data_offset + rsrc[nrsrc-2].data_len + 4; r->data_len = len; r->next_in_type = r->next_type = -2; /* resource consists of length, then data */ write_four(r->data_len, rfork_f); fwrite(data, 1, len, rfork_f); } static void init_current_post(void) { rbufpos = 2; cur_post_id = 501; blocktyp = POST_ASCII; } static void output_current_post(void) { if (blocktyp != POST_END && rbufpos <= 2) return; rbuf[0] = blocktyp; rbuf[1] = 0; output_new_rsrc("POST", cur_post_id, 0, (char *)rbuf, rbufpos); rbufpos = 2; cur_post_id++; } /* font_reader functions */ static void t1mac_output_data(byte *s, int len) { while (len > 0) { int n; /* In some Mac fonts, the ASCII sections terminate with a line-end */ if (rbufpos >= MAX_RSRC_LEN || (blocktyp == POST_ASCII && len + rbufpos > MAX_RSRC_LEN && rbufpos)) output_current_post(); n = (len + rbufpos <= MAX_RSRC_LEN ? len : MAX_RSRC_LEN - rbufpos); memcpy(rbuf + rbufpos, s, n); rbufpos += n; s += n; len -= n; } } static void t1mac_output_ascii(char *s, int len) { if (blocktyp == POST_BINARY) { output_current_post(); blocktyp = POST_ASCII; } /* Mac line endings */ if (len > 0 && s[len-1] == '\n') s[len-1] = '\r'; t1mac_output_data((byte *)s, len); if (strncmp(s, "/FontName", 9) == 0) { for (s += 9; isspace((unsigned char) *s); s++) /* skip */; if (*s == '/') { const char *t = ++s; while (*t && !isspace((unsigned char) *t)) t++; free(font_name); font_name = (char *)malloc(t - s + 1); memcpy(font_name, s, t - s); font_name[t - s] = 0; } } } static void t1mac_output_binary(unsigned char *s, int len) { if (blocktyp == POST_ASCII) { output_current_post(); blocktyp = POST_BINARY; } t1mac_output_data(s, len); } static void t1mac_output_end(void) { output_current_post(); blocktyp = POST_END; output_current_post(); } /* finish off the resource fork */ static uint32_t complete_rfork(void) { uint32_t reflist_offset, total_data_len; uint32_t typelist_len; int i, j, ntypes; /* analyze resources */ { int last_type = -1; ntypes = 0; for (i = 0; i < nrsrc; i++) if (rsrc[i].next_in_type == -2) { int last = -1; if (last_type >= 0) rsrc[last_type].next_type = i; for (j = i; j < nrsrc; j++) if (rsrc[j].type == rsrc[i].type) { if (last >= 0) rsrc[last].next_in_type = j; last = j; } rsrc[last].next_in_type = -1; last_type = i; ntypes++; } } /* have just finished writing data */ /* now write resource map */ for (i = 0; i < RFORK_MAP_RESERVEDLEN; i++) putc(0, rfork_f); /* reserved */ write_two(0, rfork_f); /* resource fork attributes */ typelist_len = ntypes * RFORK_RTYPE_LEN + 2; write_two(RFORK_MAP_HEADERLEN, rfork_f); /* offset from start of map to typelist */ write_two(RFORK_MAP_HEADERLEN + typelist_len + nrsrc * RFORK_RSRC_LEN, rfork_f); /* offset from start of map to namelist */ /* output type map */ write_two(ntypes - 1, rfork_f);/* number of types - 1 */ reflist_offset = typelist_len; for (i = 0; i >= 0; i = rsrc[i].next_type) { int n_in_type = 0; for (j = i; j >= 0; j = rsrc[j].next_in_type) n_in_type++; write_four(rsrc[i].type, rfork_f); /* resource type */ write_two(n_in_type - 1, rfork_f); /* number in type - 1 */ write_two(reflist_offset, rfork_f); /* offset to reflist from start of typelist */ reflist_offset += n_in_type * RFORK_RSRC_LEN; } /* output reference list */ for (i = 0; i >= 0; i = rsrc[i].next_type) for (j = i; j >= 0; j = rsrc[j].next_in_type) { write_two(rsrc[j].id, rfork_f); /* ID */ write_two(-1, rfork_f); /* offset to name */ write_one(rsrc[j].attrs, rfork_f); /* attributes */ write_three(rsrc[j].data_offset, rfork_f); /* offset to data from start of data */ write_four(0, rfork_f); /* reserved */ } /* finally, patch up resource fork header */ { total_data_len = rsrc[nrsrc-1].data_offset + rsrc[nrsrc-1].data_len + 4; reposition(rfork_f, 0); write_four(RFORK_HEADERLEN, rfork_f); /* offset from rfork to data */ write_four(RFORK_HEADERLEN + total_data_len, rfork_f); /* offset from rfork to map */ write_four(total_data_len, rfork_f); /* length of data */ write_four(RFORK_MAP_HEADERLEN + reflist_offset, rfork_f); /* length of map */ } return RFORK_HEADERLEN + total_data_len + RFORK_MAP_HEADERLEN + reflist_offset; } /* write a MacBinary II file */ static void output_raw(FILE *rf, int32_t len, FILE *f) { char buf[2048]; reposition(rf, 0); while (len > 0) { int n = (len < 2048 ? len : 2048); fread(buf, 1, n, rf); fwrite(buf, 1, n, f); len -= n; } } static void output_macbinary(FILE *rf, int32_t rf_len, const char *filename, FILE *f) { int i, len = strlen(filename); char buf[128]; if (len < 1 || len > 63) fatal_error("filename length must be between 1 and 63"); store_one(0, buf+0); /* old version number */ store_one(len, buf+1); /* filename length */ memset(buf+2, 0, 63); /* filename padding */ memcpy(buf+2, filename, len); /* filename */ store_four(T1_FILETYPE, buf+65); /* file type */ store_four(T1_FILECREATOR, buf+69); /* file creator */ store_one(T1_FINDERFLAGS, buf+73); /* finder flags */ store_one(0, buf+74); /* zero byte */ store_two(0, buf+75); /* vertical position in window */ store_two(0, buf+77); /* horizontal position in window */ store_two(0, buf+79); /* window or folder ID */ store_one(0, buf+81); /* protected flag */ store_one(0, buf+82); /* zero byte */ store_four(0, buf+83); /* data fork length */ store_four(rf_len, buf+87); /* resource fork length */ { time_t t = time(0) + MAC_TIME_DELTA; store_four(t, buf+91); /* creation date */ store_four(t, buf+95); /* modification date */ } store_two(0, buf+99); /* GetInfo comment length */ store_one(0, buf+101); /* finder flags part 2 */ memset(buf+102, 0, 116 - 102); /* padding */ store_four(0, buf+116); /* total length when unpacked */ store_two(0, buf+120); /* length of secondary header */ store_one(129, buf+122); /* version number */ store_one(129, buf+123); /* minimum acceptable version number */ store_two(crcbuf(0, 124, buf), buf+124); /* CRC */ store_two(0, buf+126); /* padding to 128 bytes */ /* write out the header */ fwrite(buf, 1, 128, f); /* now write resource fork */ output_raw(rf, rf_len, f); for (i = rf_len % 128; i && i < 128; i++) putc(0, f); } /* write an AppleSingle file */ #define APPLESINGLE_MAGIC 0x00051600 #define APPLEDOUBLE_MAGIC 0x00051607 #define APPLESINGLE_VERSION 0x00020000 #define APPLESINGLE_TIME_DELTA 883612800 #define APPLESINGLE_HEADERLEN 26 #define APPLESINGLE_ENTRYLEN 12 #define APPLESINGLE_DFORK_ENTRY 1 #define APPLESINGLE_RFORK_ENTRY 2 #define APPLESINGLE_DATES_ENTRY 8 #define APPLESINGLE_DATES_LEN 16 #define APPLESINGLE_FINDERINFO_ENTRY 9 #define APPLESINGLE_FINDERINFO_LEN 32 #define APPLESINGLE_REALNAME_ENTRY 3 static void output_applesingle(FILE *rf, int32_t rf_len, const char *filename, FILE *f, int appledouble) { uint32_t offset; int i, nentries, len = strlen(filename); if (appledouble) /* magic number */ write_four(APPLEDOUBLE_MAGIC, f); else write_four(APPLESINGLE_MAGIC, f); write_four(APPLESINGLE_VERSION, f); /* version number */ for (i = 0; i < 4; i++) write_four(0, f); /* filler */ nentries = (appledouble ? 4 : 5); write_two(nentries, f); /* number of entries */ /* real name entry */ offset = APPLESINGLE_HEADERLEN + nentries * APPLESINGLE_ENTRYLEN; write_four(APPLESINGLE_REALNAME_ENTRY, f); write_four(offset, f); write_four(len, f); offset += len; /* time entry */ write_four(APPLESINGLE_DATES_ENTRY, f); write_four(offset, f); write_four(APPLESINGLE_DATES_LEN, f); offset += APPLESINGLE_DATES_LEN; /* finder info entry */ write_four(APPLESINGLE_FINDERINFO_ENTRY, f); write_four(offset, f); write_four(APPLESINGLE_FINDERINFO_LEN, f); offset += APPLESINGLE_FINDERINFO_LEN; /* resource fork entry */ write_four(APPLESINGLE_RFORK_ENTRY, f); write_four(offset, f); write_four(rf_len, f); offset += rf_len; /* data fork entry */ if (!appledouble) { write_four(APPLESINGLE_DFORK_ENTRY, f); write_four(offset, f); write_four(0, f); } /* real name data */ fwrite(filename, 1, len, f); /* time data */ i = time(0) - APPLESINGLE_TIME_DELTA; write_four(i, f); /* creation date */ write_four(i, f); /* modification date */ write_four(0x80000000, f); /* backup date */ write_four(0, f); /* access date */ /* finder info data */ write_four(T1_FILETYPE, f); /* file type */ write_four(T1_FILECREATOR, f); /* file creator */ write_one(T1_FINDERFLAGS, f); /* finder flags */ write_one(0, f); /* extended finder flags */ write_two(0, f); /* vertical position in window */ write_two(0, f); /* horizontal position in window */ write_two(0, f); /* window or folder ID */ write_four(0, f); /* icon ID and reserved */ write_four(0, f); /* reserved */ write_one(0, f); /* script flag */ write_one(0, f); /* reserved */ write_two(0, f); /* comment ID */ write_four(0, f); /* put away */ /* resource fork data */ output_raw(rf, rf_len, f); } /* write a BinHex file */ static void binhex_buffer(const byte *s, int len, FILE *f) { static int col = 1; static int bits = 0; static int bitspos = 2; static const char *table = "!\"#$%&'()*+,-012345689@ABCDEFGHIJKLMNPQRSTUVXYZ[`abcdefhijklmpqr"; byte buf[5]; int c, i, left; if (!s && bitspos > 2) { /* output the remaining bits */ s = (const byte *)"\0"; len = 1; } for (left = len; left > 0; left--, s++) { int pos; if (s[0] == 0x90) { buf[0] = 0x90; buf[1] = 0x00; pos = 2; } else { buf[0] = s[0]; pos = 1; } /* find a run */ if (left > 2 && s[0] == s[1] && s[0] == s[2]) { for (i = 3; i < left && i < 255; i++) if (s[i] != s[0]) break; buf[pos] = 0x90; buf[pos+1] = i; pos += 2; s += i - 1; left -= i - 1; } /* store those characters */ for (i = 0; i < pos; i++) { bits |= buf[i]; while (bitspos >= 0) { c = (bits >> bitspos) & 0x3F; putc(table[c], f); if (++col == 63) { putc('\n', f); col = 0; } bitspos -= 6; } bits <<= 8; bitspos += 8; } } } static void output_binhex(FILE *rf, int32_t rf_len, const char *filename, FILE *f) { int crc, len = strlen(filename); char buf[2048]; if (len < 1 || len > 63) fatal_error("filename length must be between 1 and 63"); store_one(len, buf+0); /* filename length */ memcpy(buf+1, filename, len); /* filename */ store_one(0, buf+1+len); /* version */ store_four(T1_FILETYPE, buf+2+len); /* file type */ store_four(T1_FILECREATOR, buf+6+len); /* file creator */ store_one(T1_FINDERFLAGS, buf+10+len); /* finder flags */ store_one(0, buf+11+len); /* extended finder flags */ store_four(0, buf+12+len); /* length of data fork */ store_four(rf_len, buf+16+len); /* length of resource fork */ store_two(crcbuf(0, 20+len, buf), buf+20+len); /* CRC */ store_two(0, buf+22+len); /* data fork CRC */ /* output BinHex comment */ fputs("(This file must be converted with BinHex 4.0)\n:", f); /* BinHex the header */ binhex_buffer((const byte *)buf, 24+len, f); /* resource fork data */ reposition(rf, 0); crc = 0; while (rf_len > 0) { int n = (rf_len < 2048 ? rf_len : 2048); fread(buf, 1, n, rf); crc = crcbuf(crc, n, buf); /* update CRC */ binhex_buffer((const byte *)buf, n, f); rf_len -= n; } store_two(crc, buf); /* resource fork CRC */ binhex_buffer((const byte *)buf, 2, f); binhex_buffer(0, 0, f); /* get rid of any remaining bits */ fputs(":\n", f); /* trailer */ } /***** * command line **/ #define OUTPUT_OPT 301 #define VERSION_OPT 302 #define HELP_OPT 303 #define MACBINARY_OPT 304 #define RAW_OPT 305 #define APPLESINGLE_OPT 306 #define APPLEDOUBLE_OPT 307 #define BINHEX_OPT 308 #define FILENAME_OPT 309 static Clp_Option options[] = { { "appledouble", 0, APPLEDOUBLE_OPT, 0, 0 }, { "applesingle", 0, APPLESINGLE_OPT, 0, 0 }, { "binhex", 0, BINHEX_OPT, 0, 0 }, { "help", 0, HELP_OPT, 0, 0 }, { "macbinary", 0, MACBINARY_OPT, 0, 0 }, { "filename", 'n', FILENAME_OPT, Clp_ValString, 0 }, { "output", 'o', OUTPUT_OPT, Clp_ValString, 0 }, { "raw", 'r', RAW_OPT, 0, 0 }, { "version", 0, VERSION_OPT, 0, 0 }, }; static const char *program_name; void fatal_error(const char *message, ...) { va_list val; va_start(val, message); fprintf(stderr, "%s: ", program_name); vfprintf(stderr, message, val); putc('\n', stderr); va_end(val); exit(1); } void error(const char *message, ...) { va_list val; va_start(val, message); fprintf(stderr, "%s: ", program_name); vfprintf(stderr, message, val); putc('\n', stderr); va_end(val); } static void short_usage(void) { fprintf(stderr, "Usage: %s [OPTION]... [INPUT [OUTPUT]]\n\ Try `%s --help' for more information.\n", program_name, program_name); } static void usage(void) { printf("\ `T1mac' translates a PostScript Type 1 font from PFA or PFB format into\n\ Macintosh Type 1 format. The result can be written in MacBinary II format (the\n\ default), AppleSingle format, AppleDouble format, or BinHex format, or as a\n\ raw resource fork. It is sent to the standard output unless an OUTPUT file is\n\ given.\n\ \n\ Usage: %s [OPTION]... [INPUT [OUTPUT]]\n\ \n\ Options:\n\ -r, --raw Output is a raw Macintosh resource fork.\n\ --macbinary Output is in MacBinary format (default).\n\ --applesingle Output is in AppleSingle format.\n\ --appledouble Output is in AppleDouble format.\n\ --binhex Output is in BinHex format.\n\ -n, --filename NAME Macintosh font filename will be NAME.\n\ -o, --output FILE Write output to FILE.\n\ -h, --help Print this message and exit.\n\ --version Print version number and warranty and exit.\n\ \n\ Report bugs to .\n", program_name); } #ifdef __cplusplus } #endif int main(int argc, char *argv[]) { int i, c; FILE *ifp = 0, *ofp = 0; const char *ifp_filename = ""; const char *ofp_filename = ""; const char *set_font_name = 0; struct font_reader fr; uint32_t rfork_len; int raw = 0, macbinary = 1, applesingle = 0, appledouble = 0, binhex = 0; Clp_Parser *clp = Clp_NewParser(argc, (const char * const *)argv, sizeof(options) / sizeof(options[0]), options); program_name = Clp_ProgramName(clp); /* interpret command line arguments using CLP */ while (1) { int opt = Clp_Next(clp); switch (opt) { case RAW_OPT: raw = 1; macbinary = applesingle = appledouble = binhex = 0; break; case MACBINARY_OPT: macbinary = 1; raw = applesingle = appledouble = binhex = 0; break; case APPLESINGLE_OPT: applesingle = 1; raw = macbinary = appledouble = binhex = 0; break; case APPLEDOUBLE_OPT: appledouble = 1; raw = macbinary = applesingle = binhex = 0; break; case BINHEX_OPT: binhex = 1; raw = macbinary = applesingle = appledouble = 0; break; output_file: case OUTPUT_OPT: if (ofp) fatal_error("output file already specified"); if (strcmp(clp->vstr, "-") == 0) ofp = stdout; else { ofp_filename = clp->vstr; ofp = fopen(ofp_filename, "wb"); if (!ofp) fatal_error("%s: %s", ofp_filename, strerror(errno)); } break; case FILENAME_OPT: if (set_font_name) fatal_error("Macintosh font filename already specified"); set_font_name = clp->vstr; break; case HELP_OPT: usage(); exit(0); break; case VERSION_OPT: printf("t1mac (LCDF t1utils) %s\n", VERSION); printf("Copyright (C) 2000-2010 Eddie Kohler et al.\n\ This is free software; see the source for copying conditions.\n\ There is NO warranty, not even for merchantability or fitness for a\n\ particular purpose.\n"); exit(0); break; case Clp_NotOption: if (ifp && ofp) fatal_error("too many arguments"); else if (ifp) goto output_file; if (strcmp(clp->vstr, "-") == 0) ifp = stdin; else { ifp_filename = clp->vstr; ifp = fopen(clp->vstr, "r"); if (!ifp) fatal_error("%s: %s", clp->vstr, strerror(errno)); } break; case Clp_Done: goto done; case Clp_BadOption: short_usage(); exit(1); break; } } done: if (!ifp) ifp = stdin; if (!ofp) ofp = stdout; #if defined(_MSDOS) || defined(_WIN32) /* As we are processing a PFB (binary) output */ /* file, we must set its file mode to binary. */ _setmode(_fileno(ofp), _O_BINARY); #endif /* prepare font reader */ fr.output_ascii = t1mac_output_ascii; fr.output_binary = t1mac_output_binary; fr.output_end = t1mac_output_end; /* prepare resource fork file */ rfork_f = tmpfile(); if (!rfork_f) fatal_error("cannot open temorary file: %s", strerror(errno)); for (i = 0; i < RFORK_HEADERLEN; i++) putc(0, rfork_f); init_current_post(); /* peek at first byte to see if it is the PFB marker 0x80 */ c = getc(ifp); ungetc(c, ifp); /* do the file */ if (c == PFB_MARKER) process_pfb(ifp, ifp_filename, &fr); else if (c == '%') process_pfa(ifp, ifp_filename, &fr); else fatal_error("%s does not start with font marker (`%%' or 0x80)", ifp_filename); if (ifp != stdin) fclose(ifp); /* check if anything was read */ if (nrsrc == 0) error("no POST resources written -- are you sure this was a font?"); /* output large B/W icon */ output_new_rsrc("ICN#", 256, 32, (const char *)icon_bw_data, 256); /* output FREF */ output_new_rsrc("FREF", 256, 32, "LWFN\0\0\0", 7); /* output BNDL */ output_new_rsrc("BNDL", 256, 32, "T1UT\0\0\0\1FREF\0\0\0\0\1\0ICN#\0\0\0\0\1\0", 28); /* output other icons */ output_new_rsrc("icl8", 256, 32, (const char *)icon_8_data, 1024); output_new_rsrc("icl4", 256, 32, (const char *)icon_4_data, 512); output_new_rsrc("ics#", 256, 32, (const char *)small_icon_bw_data, 64); output_new_rsrc("ics8", 256, 32, (const char *)small_icon_8_data, 256); output_new_rsrc("ics4", 256, 32, (const char *)small_icon_4_data, 128); /* output T1UT (signature) */ output_new_rsrc("T1UT", 0, 0, "DConverted by t1mac (t1utils) \251Eddie Kohler http://www.lcdf.org/type/", 69); /* finish off resource file */ rfork_len = complete_rfork(); /* prepare font name */ if (!set_font_name && font_name) { int part = 0, len = 0; char *x, *s; for (x = s = font_name; *s; s++) if (isupper((unsigned char) *s) || isdigit((unsigned char) *s)) { *x++ = *s; part++; len = 1; } else if (islower((unsigned char) *s)) { if (len < (part <= 1 ? 5 : 3)) *x++ = *s; len++; } *x++ = 0; set_font_name = font_name; } else if (!set_font_name) set_font_name = "Unknown Font"; /* now, output the file */ if (macbinary) output_macbinary(rfork_f, rfork_len, set_font_name, ofp); else if (raw) output_raw(rfork_f, rfork_len, ofp); else if (applesingle || appledouble) output_applesingle(rfork_f, rfork_len, set_font_name, ofp, appledouble); else if (binhex) output_binhex(rfork_f, rfork_len, set_font_name, ofp); else fatal_error("strange output format"); fclose(rfork_f); if (ofp != stdout) fclose(ofp); return 0; } t1utils-1.39/t1unmac.1000066400000000000000000000041051247370226400145140ustar00rootroot00000000000000.ds V 1.39 .de M .BR "\\$1" "(\\$2)\\$3" .. .TH T1UNMAC 1 "" "Version \*V" .SH NAME t1unmac \- translate a Mac PostScript Type 1 font into PFA or PFB format .SH SYNOPSIS .B t1unmac \%[\fB\-a\fR|\fB\-b\fR] \%[\fB\-r\fR] \%[\fIinput\fR [\fIoutput\fR]] .SH DESCRIPTION .B t1unmac extracts POST resources from a Macintosh PostScript font file and creates a PFA (hexadecimal) or PFB (binary) font file. The file .I input should be in MacBinary I or II, AppleSingle, AppleDouble, or BinHex format, or it can be a raw resource fork. If the file is a raw resource fork, you need to give the `\-\-raw' option; otherwise .B t1unmac should automatically figure out what kind of file you have. If the file .I output is not specified output goes to the standard output. .SH OPTIONS .TP 5 .BR \-\-pfa ", " \-a Output in PFA (ASCII) format. .TP 5 .BR \-\-pfb ", " \-b Output in PFB (binary) format. This is the default. .TP 5 .BR \-\-raw ", " \-r Indicates that the input is a raw resource fork. .TP 5 .BR \-\-macbinary Indicates that the input is in MacBinary I or II format. .TP 5 .BR \-\-applesingle Indicates that the input is in AppleSingle format. .TP 5 .BR \-\-appledouble Indicates that the input is in AppleDouble format. .TP 5 .BR \-\-binhex Indicates that the input is in BinHex 4.0 format. .TP .BI \-\-block\-length= "num\fR, " \-l " num" PFB only: Set the maximum output block length to .I num. The default length is as large as memory allows. .TP .BI \-\-line\-length= "num\fR, " \-l " num" PFA only: Set the maximum length of encrypted lines in the output to .I num. (These are the lines consisting wholly of hexadecimal digits.) The default is 64. .SH EXAMPLES .LP On Mac OS X, you can use .B t1unmac to translate a font into PFA or PFB format as follows: .nf % \fBt1unmac\fR \-\-raw FONTFILENAME/..namedfork/rsrc > OUTPUT .fi .SH "SEE ALSO" .LP .M t1mac 1 , .M t1ascii 1 , .M t1binary 1 , .M t1asm 1 , .M t1disasm 1 .SH AUTHORS Lee Hetherington (ilh@lcs.mit.edu) .br Eddie Kohler (ekohler@gmail.com) .PP Ported to Microsoft C/C++ Compiler and MS-DOS operating system by Kai-Uwe Herbing (herbing@netmbx.netmbx.de). t1utils-1.39/t1unmac.c000066400000000000000000000545321247370226400146070ustar00rootroot00000000000000/* t1unmac/unpost * * This program converts Macintosh Type 1 fonts stored in MacBinary (I or II), * AppleSingle, AppleDouble, BinHex, or raw resource fork format to PFA and * PFB formats. * * Copyright (c) 1992 by I. Lee Hetherington, all rights reserved. * Copyright (c) 1998-2013 Eddie Kohler * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, subject to the * conditions listed in the Click LICENSE file, which is available in full at * http://github.com/kohler/click/blob/master/LICENSE. The conditions * include: you must preserve this copyright notice, and you cannot mention * the copyright holders in advertising related to the Software without * their permission. The Software is provided WITHOUT ANY WARRANTY, EXPRESS * OR IMPLIED. This notice is a summary of the Click LICENSE file; the * license in that file is binding. * * New change log in `NEWS'. Old change log: * * Revision 1.2 92/06/23 10:57:33 ilh * MSDOS porting by Kai-Uwe Herbing (herbing@netmbx.netmbx.de) * incoporated. * * Revision 1.1 92/05/22 12:07:49 ilh * initial version * * Ported to Microsoft C/C++ Compiler and MS-DOS operating system by * Kai-Uwe Herbing (herbing@netmbx.netmbx.de) on June 12, 1992. Code * specific to the MS-DOS version is encapsulated with #ifdef _MSDOS * ... #endif, where _MSDOS is an identifier, which is automatically * defined, if you compile with the Microsoft C/C++ Compiler. * */ /* Note: this is ANSI C. */ #ifdef HAVE_CONFIG_H # include #endif #if defined(_MSDOS) || defined(_WIN32) # include # include # include #endif #include #include #include #include #include #include #include #include #include "t1lib.h" #ifdef __cplusplus extern "C" { #endif /* Some functions to read one, two, three, and four byte integers in 68000 byte order (most significant byte first). */ static int read_one(FILE *fi) { return getc(fi); } static int read_two(FILE *fi) { int val; val = getc(fi); val = (val << 8) | getc(fi); return val; } static int32_t read_three(FILE *fi) { int32_t val; val = getc(fi); val = (val << 8) | getc(fi); val = (val << 8) | getc(fi); return val; } static int32_t read_four(FILE *fi) { int32_t val; val = getc(fi); val = (val << 8) | getc(fi); val = (val << 8) | getc(fi); val = (val << 8) | getc(fi); return val; } /* reposition a file with error messages */ static void reposition(FILE *fi, int32_t absolute) { if (fseek(fi, absolute, 0) == -1) fatal_error("can't seek to position %d\n\ (The Mac file may be corrupted, or you may need the `-r' option.)", absolute); } static int blocklen = -1; static int hex_column = 0; /* current column of hex ASCII output */ static void output_hex_byte(FILE *fo, int b) { static const char *hex = "0123456789abcdef"; if (hex_column >= blocklen) { putc('\n', fo); hex_column = 0; } putc(hex[b >> 4], fo); putc(hex[b & 0xf], fo); hex_column += 2; } /* Function to extract a particular POST resource. Offset points to the four byte length which is followed by the data. The first byte of the POST data specifies resource type: 1 for ASCII, 2 for binary, and 5 for end. The second byte is always zero. */ /* Function to write four byte length to PFB file: least significant byte first. */ static int extract_data(FILE *fi, FILE *fo, struct pfb_writer *w, int32_t offset, int pfb) { enum PS_type { PS_ascii = 1, PS_binary = 2, PS_end = 5 }; static int last_type = -1; static int skip_newline = 0; int32_t len; int more = 1; int i, c; reposition(fi, offset); len = read_four(fi) - 2; /* subtract type field */ switch ((enum PS_type)read_one(fi)) { case PS_ascii: { (void) read_one(fi); if (last_type != PFB_ASCII && pfb) { pfb_writer_output_block(w); w->blocktyp = PFB_ASCII; } for (i = 0; i < len; i++) { c = read_one(fi); if (c == '\n' && skip_newline) { skip_newline = 0; continue; } if (c == '\r') { c = '\n'; skip_newline = 1; } else skip_newline = 0; if (pfb) PFB_OUTPUT_BYTE(w, c); else putc(c, fo); } last_type = PFB_ASCII; break; } case PS_binary: { (void) read_one(fi); if (last_type != PFB_BINARY && pfb) { pfb_writer_output_block(w); w->blocktyp = PFB_BINARY; } else if (last_type != PFB_BINARY) hex_column = 0; if (pfb) { while (len--) PFB_OUTPUT_BYTE(w, read_one(fi)); } else { while (len--) output_hex_byte(fo, read_one(fi)); } last_type = PFB_BINARY; break; } case PS_end: more = 0; break; } return more; } /***** * Command line **/ #define OUTPUT_OPT 301 #define VERSION_OPT 302 #define HELP_OPT 303 #define PFB_OPT 304 #define PFA_OPT 305 #define MACBINARY_OPT 306 #define RAW_OPT 307 #define LINE_LEN_OPT 308 #define APPLEDOUBLE_OPT 309 #define BINHEX_OPT 310 static Clp_Option options[] = { { "applesingle", 0, APPLEDOUBLE_OPT, 0, 0 }, { "appledouble", 0, APPLEDOUBLE_OPT, 0, 0 }, { "binhex", 0, BINHEX_OPT, 0, 0 }, { "block-length", 0, LINE_LEN_OPT, Clp_ValUnsigned, 0 }, { "help", 0, HELP_OPT, 0, 0 }, { "line-length", 'l', LINE_LEN_OPT, Clp_ValUnsigned, 0 }, { "macbinary", 0, MACBINARY_OPT, 0, 0 }, { "output", 'o', OUTPUT_OPT, Clp_ValString, 0 }, { "pfa", 'a', PFA_OPT, 0, 0 }, { "pfb", 'b', PFB_OPT, 0, 0 }, { "raw", 'r', RAW_OPT, 0, 0 }, { "version", 0, VERSION_OPT, 0, 0 }, }; static const char *program_name; void fatal_error(const char *message, ...) { va_list val; va_start(val, message); fprintf(stderr, "%s: ", program_name); vfprintf(stderr, message, val); putc('\n', stderr); va_end(val); exit(1); } void error(const char *message, ...) { va_list val; va_start(val, message); fprintf(stderr, "%s: ", program_name); vfprintf(stderr, message, val); putc('\n', stderr); va_end(val); } static void short_usage(void) { fprintf(stderr, "Usage: %s [OPTION]... INPUT [OUTPUT]\n\ Try `%s --help' for more information.\n", program_name, program_name); } static void usage(void) { printf("\ `T1unmac' extracts a PostScript Type 1 font from a Macintosh font file. It can\n\ read MacBinary, AppleSingle, AppleDouble, or BinHex files, or raw Macintosh\n\ resource forks. The result is written to the standard output unless an OUTPUT\n\ file is given.\n\ \n\ Usage: %s [OPTION]... INPUT [OUTPUT]\n\ \n\ Options:\n\ -r, --raw Input is a raw Macintosh resource fork.\n\ --macbinary Input is in MacBinary format.\n\ --applesingle Input is in AppleSingle format.\n\ --appledouble Input is in AppleDouble format.\n\ --binhex Input is in BinHex format.\n\ -a, --pfa Output font in ASCII (PFA) format.\n\ -b, --pfb Output font in binary (PFB) format. This is\n\ the default.\n\ -l, --block-length NUM Set max block length for PFB output.\n\ -l, --line-length NUM Set max encrypted line length for PFA output.\n\ -o, --output FILE Write output to FILE.\n\ -h, --help Print this message and exit.\n\ --version Print version number and warranty and exit.\n\ \n\ Report bugs to .\n", program_name); } static const char * check_macbinary(FILE *ifp) { int i, j; char buf[124]; /* check "version" bytes at offsets 0 and 74 */ reposition(ifp, 0); if (read_one(ifp) != 0) return "bad version byte"; reposition(ifp, 74); if (read_one(ifp) != 0) return "bad version byte"; #if 0 /* write out bullshit */ {int t; reposition(ifp, 65); t = read_four(ifp); fprintf(stderr, "Type %c%c%c%c\n", (t>>24)&255, (t>>16)&255, (t>>8)&255, t&255); t = read_four(ifp); fprintf(stderr, "Creator %c%c%c%c\n", (t>>24)&255, (t>>16)&255, (t>>8)&255, t&255); t = read_one(ifp); fprintf(stderr, "Finder flags 1 %02x\n", t); read_one(ifp); t = read_two(ifp); fprintf(stderr, "horizpos %04x\n", t); t = read_two(ifp); fprintf(stderr, "vertpos %04x\n", t); t = read_two(ifp); fprintf(stderr, "folder id %d\n", t); t = read_one(ifp); fprintf(stderr, "protected? %x\n", t); t = read_one(ifp); t = read_four(ifp); fprintf(stderr, "data len %d\n", t); t = read_four(ifp); fprintf(stderr, "rsrc len %d\n", t); t = read_four(ifp); { struct tm *crap; fprintf(stderr, "creation date %x\n", t); t -= 2082844800; fprintf(stderr, " %s\n", ctime(&t)); t = read_four(ifp); fprintf(stderr, "modification date %x\n", t); t -= 2082844800; fprintf(stderr, " %s\n", ctime(&t)); t = read_two(ifp); } fprintf(stderr, "getinfo len %d\n", t); t = read_one(ifp); fprintf(stderr, "finderflags 2 %02x\n", t); reposition(ifp, 116); t = read_four(ifp); fprintf(stderr, "total len %d\n", t); t = read_two(ifp); fprintf(stderr, "secondary header len %d\n", t); t = read_one(ifp); fprintf(stderr, "version %d\n", t); t = read_one(ifp); fprintf(stderr, "version %d\n", t); } #endif /* check file length */ reposition(ifp, 1); i = read_one(ifp); if (i > 63) return "bad length"; reposition(ifp, 83); i = read_four(ifp); j = read_four(ifp); if (i < 0 || j < 0 || i >= 0x800000 || j >= 0x800000) return "bad length"; /* check CRC */ reposition(ifp, 0); fread(buf, 1, 124, ifp); if (crcbuf(0, 124, buf) != read_two(ifp)) { reposition(ifp, 82); if (read_one(ifp) != 0) return "bad checksum"; } return 0; } #define APPLESINGLE_MAGIC 0x00051600 #define APPLEDOUBLE_MAGIC 0x00051607 static const char * check_appledouble(FILE *ifp) { int i; reposition(ifp, 0); i = read_four(ifp); if (i != APPLEDOUBLE_MAGIC && i != APPLESINGLE_MAGIC) return "bad magic number"; return 0; } static const char * translate_binhex(FILE *f, FILE *tmpf) { int i, c = 0, last_char, after_x90, bits, bitpos; unsigned char value_table[256]; /* prepare value table */ { const char *table = "!\"#$%&'()*+,-012345689@ABCDEFGHIJKLMNPQRSTUVXYZ[`abcdefhijklmpqr"; for (i = 0; i < 256; i++) value_table[i] = 255; for (i = 0; *table; i++, table++) value_table[(unsigned char)*table] = i; } /* skip to comment */ { const char *comment = "(This file must be converted with BinHex"; while (!feof(f)) { const char *s; for (s = comment; *s; s++) { c = getc(f); if (c != *s) break; } /* skip to end of line */ while (c >= 0 && c != '\n' && c != '\r') c = getc(f); /* stop if read comment */ if (!*s) goto found_comment; } /* failed */ return "no comment"; } found_comment: /* skip spaces, look for ':' */ for (c = ' '; isspace(c); c = getc(f)) ; if (c != ':') return "no file-start character"; /* found ':', process until you find another ':' */ last_char = -1; after_x90 = bits = 0; bitpos = 10; for (c = getc(f); c >= 0; c = getc(f)) if (!isspace(c)) { /* add 6 bits to bits */ if (value_table[c] == 255) break; bits |= (value_table[c] << bitpos); bitpos -= 6; /* output character(s) */ if (bitpos <= 2) { int d = bits >> 8; bits = (bits << 8) & 0xFF00; bitpos += 8; if (after_x90) { /* handle compression */ if (d == 0) { last_char = 0x90; putc(0x90, tmpf); } else for (i = 1; i < d; i++) putc(last_char, tmpf); after_x90 = 0; } else if (d == 0x90) after_x90 = 1; else { last_char = d; putc(d, tmpf); } } } if (c < 0) return "unexpected EOF"; else if (c != ':') return "bad character"; fflush(tmpf); return 0; } static int check_binhex_crc(FILE *f, int offset, int length) { int crc = 0; char buf[2048]; reposition(f, offset); while (length > 0) { int n = (length < 2048 ? length : 2048); fread(buf, 1, n, f); crc = crcbuf(crc, n, buf); length -= n; } return crc == 0; } static const char * check_binhex(FILE *f) { int fname_len, data_len, rsrc_len, off; /* check lengths */ reposition(f, 0); fname_len = read_one(f); if (fname_len < 1 || fname_len > 63) return "bad length"; reposition(f, 1 + fname_len + 11); data_len = read_four(f); rsrc_len = read_four(f); if (data_len < 0 || rsrc_len < 0 || data_len >= 0x800000 || rsrc_len >= 0x800000) return "bad length"; /* check version */ reposition(f, 1 + fname_len); if (read_one(f) != 0) return "bad version"; /* check CRC */ off = 1 + fname_len + 21; if (!check_binhex_crc(f, 0, off)) return "bad header CRC"; if (!check_binhex_crc(f, off, data_len + 2)) return "bad data CRC"; if (!check_binhex_crc(f, off + data_len + 2, rsrc_len + 2)) return "bad resource fork CRC"; return 0; } #ifdef __cplusplus } #endif int main(int argc, char *argv[]) { FILE *ifp = 0; FILE *ofp = 0; struct pfb_writer w; const char *ifp_name = ""; int32_t res_offset, res_data_offset, res_map_offset, type_list_offset; int32_t post_type; int num_types, num_extracted = 0, pfb = 1; int raw = 0, appledouble = 0, binhex = 0, macbinary = 0; Clp_Parser *clp = Clp_NewParser(argc, (const char * const *)argv, sizeof(options) / sizeof(options[0]), options); program_name = Clp_ProgramName(clp); /* interpret command line arguments using CLP */ while (1) { int opt = Clp_Next(clp); switch (opt) { case RAW_OPT: raw = 1; appledouble = binhex = macbinary = 0; break; case MACBINARY_OPT: macbinary = 1; raw = appledouble = binhex = 0; break; case APPLEDOUBLE_OPT: appledouble = 1; raw = binhex = macbinary = 0; break; case BINHEX_OPT: binhex = 1; raw = appledouble = macbinary = 0; break; output_file: case OUTPUT_OPT: if (ofp) fatal_error("output file already specified"); if (strcmp(clp->vstr, "-") == 0) ofp = stdout; else { ofp = fopen(clp->vstr, "w"); if (!ofp) fatal_error("%s: %s", clp->vstr, strerror(errno)); } break; case PFB_OPT: pfb = 1; break; case PFA_OPT: pfb = 0; break; case LINE_LEN_OPT: blocklen = clp->val.i; break; case HELP_OPT: usage(); exit(0); break; case VERSION_OPT: printf("t1unmac (LCDF t1utils) %s\n", VERSION); printf("Copyright (C) 1992-2010 I. Lee Hetherington, Eddie Kohler et al.\n\ This is free software; see the source for copying conditions.\n\ There is NO warranty, not even for merchantability or fitness for a\n\ particular purpose.\n"); exit(0); break; case Clp_NotOption: if (ifp && ofp) fatal_error("too many arguments"); else if (ifp) goto output_file; if (strcmp(clp->vstr, "-") == 0) ifp = stdin; else { ifp_name = clp->vstr; ifp = fopen(clp->vstr, "rb"); if (!ifp) fatal_error("%s: %s", clp->vstr, strerror(errno)); } break; case Clp_Done: goto done; case Clp_BadOption: short_usage(); exit(1); break; } } done: if (!ifp) ifp = stdin; if (!ofp) ofp = stdout; #if defined(_MSDOS) || defined(_WIN32) _setmode(_fileno(ifp), _O_BINARY); /* If we are processing a PFB (binary) output */ /* file, we must set its file mode to binary. */ if (pfb) _setmode(_fileno(ofp), _O_BINARY); #endif if (pfb) init_pfb_writer(&w, blocklen, ofp); else { if (blocklen == -1) blocklen = 64; else if (blocklen < 8) { blocklen = 8; error("warning: line length raised to %d", blocklen); } else if (blocklen > 1024) { blocklen = 1024; error("warning: line length lowered to %d", blocklen); } } /* check for non-seekable input */ if (fseek(ifp, 0, 0)) { char buf[2048]; FILE *tmp = tmpfile(); if (!tmp) fatal_error("cannot open temporary file: %s", strerror(errno)); while (!feof(ifp)) { int i = fread(buf, 1, 2048, ifp); if (i > 0) fwrite(buf, 1, i, tmp); } if (ferror(ifp)) fatal_error("%s: %s", ifp_name, strerror(errno)); reposition(tmp, 0); fflush(tmp); if (ifp != stdin) fclose(ifp); ifp = tmp; } /* check for empty file */ fseek(ifp, 0, 2); if (ftell(ifp) == 0) fatal_error("%s: empty file\n\ (Try re-transferring the files using MacBinary format.)", ifp_name); reposition(ifp, 0); if (!raw && !appledouble && !binhex && !macbinary) { /* check magic number, try to figure out what it is */ int i, magic; magic = read_four(ifp); reposition(ifp, 0); if (magic == APPLESINGLE_MAGIC || magic == APPLEDOUBLE_MAGIC) appledouble = 1; else if ((magic & 0xFF000000) == 0) macbinary = 1; else { binhex = 1; for (i = 0; i < 4; i++, magic >>= 8) if (!isprint(magic & 0xFF) && !isspace(magic & 0xFF)) /* not an ASCII character, assume not BinHex */ binhex = 0; } if (!appledouble && !macbinary && !binhex) fatal_error("%s: unknown file type", ifp_name); } if (raw) { /* raw resource file */ res_offset = 0; } else if (macbinary) { /* MacBinary (I or II) file */ const char *check; int32_t data_fork_size; /* check integrity of file */ check = check_macbinary(ifp); if (check) fatal_error("%s: not a MacBinary file (%s)", ifp_name, check); /* read data and resource fork sizes in MacBinary header */ reposition(ifp, 83); data_fork_size = read_four(ifp); (void) read_four(ifp); /* round data_fork_size up to multiple of 128 */ if (data_fork_size % 128) data_fork_size += 128 - data_fork_size % 128; res_offset = 128 + data_fork_size; } else if (appledouble) { /* AppleDouble file */ const char *check; const char *applewhat; int i, n; /* check integrity */ check = check_appledouble(ifp); if (check) fatal_error("%s: not an AppleDouble file (%s)", ifp_name, check); reposition(ifp, 0); if (read_four(ifp) == APPLESINGLE_MAGIC) applewhat = "AppleSingle"; else applewhat = "AppleDouble"; /* find offset to resource and/or data fork */ reposition(ifp, 24); n = read_two(ifp); res_offset = -1; for (i = 0; i < n; i++) { int type = read_four(ifp); if (type == 0) fatal_error("%s: bad %s file (bad entry descriptor)", ifp_name, applewhat); if (type == 2) /* resource fork entry */ res_offset = read_four(ifp); else (void) read_four(ifp); (void) read_four(ifp); } if (res_offset < 0) fatal_error("%s: bad %s file (no resource fork)", ifp_name, applewhat); } else if (binhex) { /* BinHex file */ const char *check; FILE *tmpf = tmpfile(); if (!tmpf) fatal_error("cannot open temporary file: %s", strerror(errno)); /* check integrity */ check = translate_binhex(ifp, tmpf); if (check) fatal_error("%s: not a BinHex file (%s)", ifp_name, check); check = check_binhex(tmpf); if (check) fatal_error("%s: bad BinHex file (%s)", ifp_name, check); /* find resource offset */ reposition(tmpf, 0); res_offset = read_one(tmpf); reposition(tmpf, 1 + res_offset + 11); res_offset += 22 + read_four(tmpf) + 2; if (ifp != stdin) fclose(ifp); ifp = tmpf; } else { fatal_error("%s: strange format", ifp_name); exit(1); } /* read offsets from resource fork header */ reposition(ifp, res_offset); res_data_offset = res_offset + read_four(ifp); res_map_offset = res_offset + read_four(ifp); /* read type list offset from resource map header */ reposition(ifp, res_map_offset + 24); type_list_offset = res_map_offset + read_two(ifp); /* read type list */ reposition(ifp, type_list_offset); num_types = read_two(ifp) + 1; /* find POST type */ post_type = (int32_t)('P' & 0xff) << 24; post_type |= (int32_t)('O' & 0xff) << 16; post_type |= (int32_t)('S' & 0xff) << 8; post_type |= (int32_t)('T' & 0xff); while (num_types--) { if (read_four(ifp) == post_type) { int nrsrc = 1 + read_two(ifp); int list_offset = type_list_offset + read_two(ifp); int rsrc_pos = 0; int want_id = 501; int second_time = 1; reposition(ifp, list_offset); /* read resources sequentially, starting with ID 501, until we encounter an "end" resource or we can't find the next resource */ while (rsrc_pos < nrsrc) { int offset = ftell(ifp); int id = read_two(ifp); if (id == want_id) { (void) read_two(ifp); (void) read_one(ifp); num_extracted++; if (!extract_data(ifp, ofp, &w, res_data_offset + read_three(ifp), pfb)) break; second_time = 0; want_id++; } reposition(ifp, offset + 12); rsrc_pos++; if (rsrc_pos >= nrsrc && !second_time) { reposition(ifp, list_offset); rsrc_pos = 0; } } break; } else { (void) read_two(ifp); (void) read_two(ifp); } } #if 0 system("/bin/rm -f /tmp/x.*"); { FILE *f; int i; reposition(ifp, res_offset + 16); if ((f = fopen("/tmp/x.systemarea", "wb"))) { for (i = res_offset + 16; i < res_data_offset; i++) { putc(getc(ifp), f); } fclose(f); } } reposition(ifp, type_list_offset); num_types = read_two(ifp) + 1; while (num_types--) { int t = read_four(ifp); int num_of_type = 1 + read_two(ifp); int32_t save_offset = ftell(ifp) + 2; reposition(ifp, type_list_offset + read_two(ifp)); while (num_of_type--) { FILE *f; char buf[2048]; int x, i, attrs; x = ftell(ifp); i = read_two(ifp); /* ID */ read_two(ifp); attrs = read_one(ifp); sprintf(buf, "/tmp/x.%c%c%c%c.%d", (t>>24)&255, (t>>16)&255, (t>>8)&255, t&255, i); fprintf(stderr, "%c%c%c%c.%d %d", (t>>24)&255, (t>>16)&255, (t>>8)&255, t&255, i, attrs); if ((f = fopen(buf, "wb"))) { int l; reposition(ifp, res_data_offset + read_three(ifp)); l = read_four(ifp); fprintf(stderr, " %d\n", l); while (l > 0) { int n = (l < 2048 ? l : 2048); fread(buf, 1, n, ifp); fwrite(buf, 1, n, f); l -= n; } fclose(f); } reposition(ifp, x + 12); } reposition(ifp, save_offset); } #endif if (pfb) pfb_writer_end(&w); if (num_extracted == 0) error("%s: not a Type 1 font (no POST resources)", ifp_name); fclose(ifp); fclose(ofp); return 0; } t1utils-1.39/t1utils.spec000066400000000000000000000027541247370226400153530ustar00rootroot00000000000000Summary: Programs for manipulating PostScript Type 1 fonts Name: t1utils Version: 1.39 Release: 1 Source: http://www.lcdf.org/type/t1utils-1.39.tar.gz URL: http://www.lcdf.org/type/ Group: Utilities/Printing Vendor: Little Cambridgeport Design Factory Packager: Eddie Kohler License: freely modifiable and distributable BuildRoot: /tmp/t1utils-build %description The t1utils package is a set of programs for manipulating PostScript Type 1 fonts. It contains programs to change between binary PFB format (for storage), ASCII PFA format (for printing), a human-readable and -editable ASCII format, and Macintosh resource forks. %prep %setup %build %configure make %install [ "$RPM_BUILD_ROOT" != "/" ] && [ -d $RPM_BUILD_ROOT ] && rm -rf $RPM_BUILD_ROOT mkdir -p $RPM_BUILD_ROOT make DESTDIR=$RPM_BUILD_ROOT install %clean [ "$RPM_BUILD_ROOT" != "/" ] && [ -d $RPM_BUILD_ROOT ] && rm -rf $RPM_BUILD_ROOT %files %attr(-,root,root) %doc NEWS README %attr(0755,root,root) %{_bindir}/t1ascii %attr(0755,root,root) %{_bindir}/t1binary %attr(0755,root,root) %{_bindir}/t1asm %attr(0755,root,root) %{_bindir}/t1disasm %attr(0755,root,root) %{_bindir}/t1unmac %attr(0755,root,root) %{_bindir}/t1mac %attr(0644,root,root) %{_mandir}/man1/t1ascii.1* %attr(0644,root,root) %{_mandir}/man1/t1binary.1* %attr(0644,root,root) %{_mandir}/man1/t1asm.1* %attr(0644,root,root) %{_mandir}/man1/t1disasm.1* %attr(0644,root,root) %{_mandir}/man1/t1unmac.1* %attr(0644,root,root) %{_mandir}/man1/t1mac.1*